[
  {
    "path": ".azure/pipelines/build.yaml",
    "content": "trigger:\n  branches:\n    include:\n    - main\n    - 3.x\n  paths:\n    exclude:\n    - samples\n\nschedules:\n- cron: \"0 0 * * *\"\n  displayName: 'Daily midnight build (including CodeQL)'\n  branches:\n    include:\n    - main\n    - 3.x\n  always: true\n\nparameters:\n  - name: build_configuration\n    displayName: Build configuration\n    type: string\n    default: Release\n    values:\n    - Release\n    - Debug\n  - name: version_prefix\n    displayName: Version prefix\n    type: string\n    default: 10.0.0\n  - name: include_suffix\n    displayName: Append version suffix\n    type: boolean\n    default: true\n  - name: version_suffix\n    displayName: Version suffix\n    type: string\n    default: ci.$(Build.BuildNumber)\n  - name: skip_test\n    displayName: Skip tests\n    type: boolean\n    default: false\n  - name: frameworks\n    displayName: Frameworks\n    type: object\n    default:\n    - net8.0\n    - net10.0\n  - name: tests_categories\n    displayName: Test categories\n    type: object\n    default:\n    - BVT\n    - SlowBVT\n    - Functional\n  - name: runCodeQL3000\n    default: false\n    displayName: Run CodeQL3000 tasks\n    type: boolean\n\nvariables:\n- template: templates/vars.yaml\n\nresources:\n  repositories:\n  - repository: 1ESPipelineTemplates\n    type: git\n    name: 1ESPipelineTemplates/1ESPipelineTemplates\n    ref: refs/tags/release\n\nextends:\n  ${{ if eq(variables['System.TeamProject'], 'GitHub - PR Builds') }}:\n    template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates\n  ${{ else }}:\n    template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates\n  parameters:\n    settings:\n      skipBuildTagsForGitHubPullRequests: true\n    sdl:\n      autobaseline:\n        enableForGitHub: true\n    pool:\n      name: $(pool_name)\n      image: $(pool_image)\n      os: windows\n    stages:\n    - stage: build_test\n      displayName: Build and Tests\n      jobs:\n      - template: /.azure/pipelines/templates/build.yaml@self\n        parameters:\n          build_configuration: ${{ parameters.build_configuration }}\n          version_prefix: ${{ parameters.version_prefix }}\n          include_suffix: ${{ parameters.include_suffix }}\n          version_suffix: ${{ parameters.version_suffix }}\n          codesign: false\n          skip_test: ${{ parameters.skip_test }}\n          publish_nightly: false\n          publish_nuget: false\n          frameworks: ${{ parameters.frameworks }}\n          tests_categories: ${{ parameters.tests_categories }}\n          runCodeQL3000: ${{ parameters.runCodeQL3000 }}\n"
  },
  {
    "path": ".azure/pipelines/github-mirror.yaml",
    "content": "trigger:\n  branches:\n    include:\n    - '*'\n\npr: none\n\nschedules:\n- cron: '0 */2 * * *'\n  displayName: Scheduled sync\n  branches:\n    include:\n    - main\n\nresources:\n  repositories:\n  - repository: 1ESPipelineTemplates\n    type: git\n    name: 1ESPipelineTemplates/1ESPipelineTemplates\n    ref: refs/tags/release\n\nextends:\n  template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates\n  parameters:\n    pool: \n      name: orleans-build-hosted-pool\n      image: orleans-build-image\n      os: windows\n    stages:\n    - stage: clone\n      displayName: Mirror GitHub repo\n      jobs:\n      - job:\n        steps:\n        - checkout: self\n          displayName: Clone GitHub repo\n          fetchDepth: 0\n          fetchTags: true\n        - task: Powershell@2\n          displayName: Set git config\n          inputs:\n            targetType: 'inline'\n            script: |\n              git config --global user.email \"${env:GIT_USEREMAIL}\"\n              git config --global user.name \"${env:GIT_USERNAME}\"\n        - task: PowerShell@2\n          displayName: Push to remote repo\n          inputs:\n            targetType: 'inline'\n            script: |\n              foreach ($ref in ${env:REFS_MIRROR}.Split(' '))\n              {\n                git config --add remote.origin.fetch \"$ref\"\n              }\n              git fetch --all\n              git remote add --mirror=fetch mirror https://${Env:SYSTEM_ACCESSTOKEN}@${env:REMOTE_REPOSITORY}\n              git push --force --all --progress mirror\n          env:\n            SYSTEM_ACCESSTOKEN: $(System.AccessToken)"
  },
  {
    "path": ".azure/pipelines/nightly-main.yaml",
    "content": "trigger: none\npr: none\n\nschedules:\n- cron: \"0 0 * * *\"\n  displayName: Publish nightly packages\n  branches:\n    include:\n    - main\n  always: false\n\nparameters:\n  - name: publish_nuget\n    displayName: Publish to nuget.org\n    type: boolean\n    default: false\n  - name: publish_nightly\n    displayName: Publish to orleans-nightly\n    type: boolean\n    default: true\n  - name: version_prefix\n    displayName: Version prefix\n    type: string\n    default: 10.0.0\n  - name: version_suffix\n    displayName: Version suffix\n    type: string\n    default: nightly.$(Build.BuildNumber)\n  - name: include_suffix\n    displayName: Append version suffix\n    type: boolean\n    default: true\n\nvariables:\n- template: templates/vars.yaml\n\nresources:\n  repositories:\n  - repository: 1ESPipelineTemplates\n    type: git\n    name: 1ESPipelineTemplates/1ESPipelineTemplates\n    ref: refs/tags/release\n\nextends:\n  ${{ if eq(variables['System.TeamProject'], 'GitHub - PR Builds') }}:\n    template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates\n  ${{ else }}:\n    template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates\n  parameters:\n    sdl:\n      policheck:\n        enabled: true\n      tsa:\n        enabled: true\n    settings:\n      skipBuildTagsForGitHubPullRequests: true\n    pool:\n      name: $(pool_name)\n      image: $(pool_image)\n      os: windows\n    stages:\n    - stage: build_test\n      displayName: Build and Tests\n      jobs:\n      - template: /.azure/pipelines/templates/build.yaml@self\n        parameters:\n          build_configuration: Release\n          version_prefix: ${{ parameters.version_prefix }}\n          include_suffix: ${{ parameters.include_suffix }}\n          version_suffix: ${{ parameters.version_suffix }}\n          codesign: true\n          publish_nightly: ${{ parameters.publish_nightly }}\n          publish_nuget: ${{ parameters.publish_nuget }}\n          skip_test: true\n"
  },
  {
    "path": ".azure/pipelines/templates/build.yaml",
    "content": "parameters:\n  - name: build_configuration\n    displayName: Build configuration\n    type: string\n    default: Release\n    values:\n    - Release\n    - Debug\n  - name: version_prefix\n    displayName: Version prefix\n    type: string\n    default: 9.0.0\n  - name: include_suffix\n    displayName: Append version suffix\n    type: boolean\n    default: true\n  - name: version_suffix\n    displayName: Version suffix\n    type: string\n    default: ci.$(Build.BuildNumber)\n  - name: codesign\n    displayName: Enable code signing\n    type: boolean\n    default: false\n  - name: skip_test\n    displayName: Skip tests\n    type: boolean\n    default: false\n  - name: publish_nightly\n    displayName: Publish to orleans-nightly\n    type: boolean\n    default: false\n  - name: publish_nuget\n    displayName: Publish to nuget.org\n    type: boolean\n    default: false\n  - name: frameworks\n    displayName: Frameworks\n    type: object\n    default:\n    - net8.0\n    - net10.0\n  - name: tests_categories\n    displayName: Test categories\n    type: object\n    default:\n    - BVT\n    - SlowBVT\n    - Functional\n  - name: runCodeQL3000\n    default: false\n    displayName: Run CodeQL3000 tasks\n    type: boolean\n\njobs:\n\n# Approval needed for publishing to nuget.org\n- job: PreDeploymentApprovalJob\n  displayName: Pre-Deployment Approval\n  timeoutInMinutes: 2880\n  ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nuget, true)) }}:\n    pool: server\n  steps:\n    - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nuget, true)) }}:\n      - task: ManualValidation@1\n        inputs:\n          notifyUsers: ${{ variables.notifyUsers }}\n          approvers: ${{ variables.approvers }}\n    - ${{ if not(and(eq(parameters.codesign, true), eq(parameters.publish_nuget, true))) }}:\n      - script: echo \"Skipping pre-deployment approval\"\n\n# Build, sign dlls, build nuget pkgs, then sign them\n- job: Build\n  displayName: Build and create NuGet packages\n  dependsOn: PreDeploymentApprovalJob\n  variables:\n    ${{ if eq(parameters.codesign, true) }}:\n      microbuild_signing: true\n      publishVstsFeed: 'public/orleans-nightly'\n    ${{ else }}:\n      microbuild_signing: false\n  ${{ if ne(variables['System.TeamProject'], 'GitHub - PR Builds') }}:\n    templateContext:\n      outputs:\n      - output: pipelineArtifact\n        targetPath: '$(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}'\n        artifactName: nuget\n      # Publish packages to nightly\n      - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nightly, true)) }}:\n        - output: nuget\n          useDotNetTask: false\n          packageParentPath: $(Pipeline.Workspace)\n          packagesToPush: $(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}/**/*.nupkg\n          nuGetFeedType: internal\n          publishVstsFeed: $(publishVstsFeed)\n          allowPackageConflicts: true\n      - ${{ if and(eq(parameters.codesign, true), eq(parameters.publish_nuget, true)) }}:\n        - output: nuget\n          condition: succeeded()\n          useDotNetTask: false\n          packageParentPath: $(Pipeline.Workspace)\n          packagesToPush: $(build.sourcesdirectory)/Artifacts/${{parameters.build_configuration}}/**/*.nupkg\n          nuGetFeedType: external\n          publishFeedCredentials: dotnet-orleans-nuget\n          publishPackageMetadata: true\n          allowPackageConflicts: true\n  steps:\n  - ${{ if eq(variables.microbuild_signing, true) }}:\n    - task: MicroBuildSigningPlugin@4\n      displayName: Install MicroBuild plugin\n      inputs:\n        signType: real\n        zipSources: false\n        feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json\n        ConnectedServiceName: 'MicroBuild Signing Task (DevDiv)'\n        ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca\n      env:\n        TeamName: Orleans\n        MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)'\n  - checkout: self\n  - task: NodeTool@0\n    displayName: 'Use Node.js'\n    inputs:\n      versionSpec: '20.x'\n  - task: npmAuthenticate@0\n    displayName: 'Authenticate npm feeds'\n    inputs:\n      workingFile: '$(Build.SourcesDirectory)/src/Dashboard/Orleans.Dashboard/.azdo/.npmrc'\n  - task: UseDotNet@2\n    displayName: 'Use .NET Core sdk'\n    inputs:\n      useGlobalJson: true\n  - ${{ if eq(variables.runCodeQL3000, 'true') }}:\n    - task: CodeQL3000Init@0\n      displayName: CodeQL Initialize\n    # This task only tags a build if it actually does CodeQL3000 work.\n    # Those tasks no-op while the analysis is considered up to date i.e. for runs w/in a few days of each other.\n    - script: \"echo ##vso[build.addbuildtag]CodeQL3000\"\n      displayName: 'Set CI CodeQL3000 tag'\n      condition: ne(variables.CODEQL_DIST,'')\n  - task: DotNetCoreCLI@2\n    displayName: Build\n    inputs:\n      command: build\n      arguments: '$(build_flags) /bl:${{parameters.build_configuration}}-Build.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)'\n    env:\n      VersionPrefix: ${{parameters.version_prefix}}\n      ${{ if eq(parameters.include_suffix, true) }}:\n        VersionSuffix: ${{parameters.version_suffix}}\n      OfficialBuild: $(official_build)\n  - ${{ if eq(variables.runCodeQL3000, 'true') }}:\n    - task: CodeQL3000Finalize@0\n      displayName: CodeQL Finalize\n  - task: CmdLine@2\n    displayName: Pack\n    inputs:\n      script: 'dotnet pack --no-build --no-restore $(build_flags) /bl:${{parameters.build_configuration}}-Pack.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)'\n    env:\n      VersionPrefix: ${{parameters.version_prefix}}\n      ${{ if eq(parameters.include_suffix, true) }}:\n        VersionSuffix: ${{parameters.version_suffix}}\n      OfficialBuild: $(official_build)\n  # Signing\n  - ${{ if eq(variables.microbuild_signing, true) }}:\n    - task: NuGetCommand@2\n      displayName: \"Install packages for signing\"\n      inputs:\n        command: 'custom'\n        arguments: 'install sign/packages.config -ConfigFile sign/Nuget.Config'\n    - task: MSBuild@1\n      displayName: \"Sign binaries and packages\"\n      inputs:\n        solution: sign/sign.proj\n        msbuildArguments: -t:sign -p:Configuration=${{parameters.build_configuration}}\n\n# Tests\n- ${{ if and(eq(parameters.skip_test, false), ne(variables.runCodeQL3000, 'true')) }}:\n  - ${{ each category in parameters.tests_categories }}:\n    - ${{ each framework in parameters.frameworks }}:\n      - job:\n        displayName: ${{category}} on ${{framework}}\n        timeoutInMinutes: 120\n        dependsOn: Build\n        templateContext:\n          outputs:\n          - output: pipelineArtifact\n            targetPath: '$(Build.ArtifactStagingDirectory)/test_outputs_${{category}}_${{framework}}_$(Build.BuildId)'\n            artifactName: 'test_outputs_${{category}}_${{framework}}_$(System.JobAttempt)'\n            condition: succeededOrFailed()\n        variables:\n          # Transform \"net8.0\" to \"8.0.x\" for the second DotNetCoreCLI@2\n          testFrameworkToInstall: ${{format('{0}.x', replace(upper(framework), 'NET', ''))}}\n        steps:\n        - checkout: self\n        - task: NodeTool@0\n          displayName: 'Use Node.js'\n          inputs:\n            versionSpec: '20.x'\n        - task: npmAuthenticate@0\n          displayName: 'Authenticate npm feeds'\n          inputs:\n            workingFile: '$(Build.SourcesDirectory)/src/Dashboard/Orleans.Dashboard/.azdo/.npmrc'\n        - task: UseDotNet@2\n          inputs:\n            useGlobalJson: true\n          displayName: 'Use .NET Core sdk'\n        - task: DotNetCoreCLI@2\n          displayName: Build\n          inputs:\n            command: build\n            arguments: '$(build_flags) /bl:${{parameters.build_configuration}}-Build.binlog /p:Configuration=${{parameters.build_configuration}} $(solution)'\n        - ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n          - task: AzureCLI@2\n            displayName: Azure Login\n            env:\n              SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n              AZURE_CORE_USE_MSAL_HTTP_CACHE: \"false\"\n            inputs:\n              azureSubscription: 'dotnet-orleans-test'\n              useGlobalConfig: true\n              addSpnToEnvironment: true\n              scriptType: pscore\n              scriptLocation: inlineScript\n              inlineScript: |\n                # Extract TenantId and ServicePrincipalId from the connection\n                Write-Host \"##vso[task.setvariable variable=tenantId]$($env:tenantId)\"\n                Write-Host \"##vso[task.setvariable variable=servicePrincipalId;issecret=true]$($env:servicePrincipalId)\"\n                # AzurePipelinesCredential expect the GUID of the connection, not the name, so let's get it here\n                Write-Host \"##vso[task.setvariable variable=serviceConnectionId]$($env:SERVICE_CONNECTION_ID)\"\n                Get-ChildItem env:\n        - task: UseDotNet@2\n          # We need this step because the tested framework can be different from the build framework\n          inputs:\n            version: ${{variables.testFrameworkToInstall}}\n          displayName: 'Install .NET Core sdk used in tests'\n        - task: DotNetCoreCLI@2\n          displayName: Test\n          env:\n            ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n              AZURE_TENANT_ID: $(tenantId)\n              AZURE_CLIENT_ID: $(servicePrincipalId)\n              SERVICE_CONNECTION_ID: $(serviceConnectionId)\n              SYSTEM_ACCESSTOKEN: $(System.AccessToken)\n          inputs:\n            command: 'test'\n            testRunTitle: ${{category}} on ${{framework}}\n            arguments: '--no-build --logger \"trx;LogFilePrefix=testresults-${{framework}}-${{category}}\" --framework ${{framework}} --configuration \"${{parameters.build_configuration}}\" --filter Category=${{category}} --blame-crash-dump-type full --blame-hang-timeout 10m --blame-hang-dump-type full -- -parallel none -noshadow'\n            publishTestResults: false # Doesn't merge correctly, use the explicit PublishTestResults task instead\n        - task: PublishTestResults@2\n          displayName: Publishing test results\n          condition: succeededOrFailed()\n          inputs:\n            testResultsFormat: VSTest\n            testResultsFiles: '**/testresults-*.trx'\n            mergeTestResults: true\n            testRunTitle: ${{category}} on ${{framework}}\n        - task: CopyFiles@2\n          displayName: 'Copy test logs'\n          condition: succeededOrFailed()\n          inputs:\n            Contents: '**\\*.log'\n            TargetFolder: '$(Build.ArtifactStagingDirectory)/test_outputs_${{category}}_${{framework}}_$(Build.BuildId)'\n            OverWrite: true\n        - task: CopyFiles@2\n          displayName: 'Copy crash dumps'\n          condition: succeededOrFailed()\n          inputs:\n            Contents: '**\\*.dmp'\n            TargetFolder: '$(Build.ArtifactStagingDirectory)/test_outputs_${{category}}_${{framework}}_$(Build.BuildId)'\n            OverWrite: true\n"
  },
  {
    "path": ".azure/pipelines/templates/vars.yaml",
    "content": "# It seems that variables must be defined in their own file when using templates\n\nvariables:\n  build_flags: ' /m /v:m'\n  solution: 'Orleans.slnx'\n  codesign_runtime: '2.1.x'\n  GDN_SUPPRESS_FORKED_BUILD_WARNING: true # Avoid warning \"Guardian is not supported for builds from forked GitHub repositories\"\n  MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)'\n  # Auto-injection is not necessary because the tasks are explicitly included where they're enabled.\n  Codeql.SkipTaskAutoInjection: true\n  ${{ if eq(variables['System.TeamProject'], 'GitHub - PR Builds') }}:\n    pool_name: 'orleans-pr-hosted-pool'\n    pool_image: 'orleans-build-image'\n    official_build: false\n  ${{ else }}:\n    ${{ if eq(variables['System.TeamProject'], 'internal') }}:\n      pool_name: 'NetCore1ESPool-Internal'\n      pool_image: '1es-windows-2022'\n    ${{ else }}:\n      pool_name: 'orleans-build-hosted-pool'\n      pool_image: 'orleans-build-image'\n    official_build: true\n    # Do not let CodeQL3000 Extension gate scan frequency.\n    Codeql.Cadence: 0\n    # Enable CodeQL3000 unconditionally so it may be run on any branch.\n    Codeql.Enabled: true\n    # Ignore test and infrastructure code.\n    Codeql.SourceRoot: src\n    # CodeQL3000 needs this plumbed along as a variable to enable TSA. Don't use TSA in manual builds.\n    Codeql.TSAEnabled: ${{ eq(variables['Build.Reason'], 'Schedule') }}\n    # Default expects tsaoptions.json under SourceRoot.\n    Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json'\n    # Do not slow builds down w/ the CodeQL3000 tasks unless this is a nightly build or it's requested.\n    runCodeQL3000: ${{ or(eq(variables['Build.Reason'], 'Schedule'), and(eq(variables['Build.Reason'], 'Manual'), eq(parameters.runCodeQL3000, 'true'))) }}\n"
  },
  {
    "path": ".azuredevops/dependabot.yml",
    "content": "version: 2\r\n\r\n# Disabling dependabot on Azure DevOps as this is a mirrored repo. Updates should go through github.\r\nenable-campaigned-updates: false\r\nenable-security-updates: false\r\n"
  },
  {
    "path": ".config/1espt/PipelineAutobaseliningConfig.yml",
    "content": "## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details.\r\n\r\npipelines:\r\n  128:\r\n    retail:\r\n      source:\r\n        credscan:\r\n          lastModifiedDate: 2024-09-11\r\n        eslint:\r\n          lastModifiedDate: 2024-09-11\r\n        armory:\r\n          lastModifiedDate: 2024-09-11\r\n      binary:\r\n        credscan:\r\n          lastModifiedDate: 2024-10-16\r\n        binskim:\r\n          lastModifiedDate: 2024-10-16\r\n  1152:\r\n    retail:\r\n      source:\r\n        credscan:\r\n          lastModifiedDate: 2024-07-30\r\n        eslint:\r\n          lastModifiedDate: 2024-07-30\r\n        psscriptanalyzer:\r\n          lastModifiedDate: 2024-07-30\r\n        armory:\r\n          lastModifiedDate: 2024-07-30\r\n      binary:\r\n        credscan:\r\n          lastModifiedDate: 2024-07-30\r\n        binskim:\r\n          lastModifiedDate: 2024-07-30\r\n        spotbugs:\r\n          lastModifiedDate: 2024-07-30\r\n  1397:\r\n    retail:\r\n      source:\r\n        credscan:\r\n          lastModifiedDate: 2024-08-02\r\n        eslint:\r\n          lastModifiedDate: 2024-08-02\r\n        psscriptanalyzer:\r\n          lastModifiedDate: 2024-08-02\r\n        armory:\r\n          lastModifiedDate: 2024-08-02\r\n      binary:\r\n        credscan:\r\n          lastModifiedDate: 2024-08-02\r\n        binskim:\r\n          lastModifiedDate: 2024-08-02\r\n        spotbugs:\r\n          lastModifiedDate: 2024-08-02"
  },
  {
    "path": ".config/guardian/.gdnbaselines",
    "content": "{\r\n  \"properties\": {\r\n    \"helpUri\": \"https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/baselines\"\r\n  },\r\n  \"version\": \"1.0.0\",\r\n  \"baselines\": {\r\n    \"default\": {\r\n      \"name\": \"default\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"lastUpdatedDate\": \"2024-08-02 00:42:13Z\"\r\n    }\r\n  },\r\n  \"results\": {\r\n    \"492bb9459285aa02a23f6a6779e5be2eb5abf65a32cc613280b7ed722cd4a98e\": {\r\n      \"signature\": \"492bb9459285aa02a23f6a6779e5be2eb5abf65a32cc613280b7ed722cd4a98e\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/nuget.config\",\r\n      \"line\": 9,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0060\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"caaa03f03b1c7c073308d50dd596413120a75aa9f7188f1747597683f6e3b436\": {\r\n      \"signature\": \"caaa03f03b1c7c073308d50dd596413120a75aa9f7188f1747597683f6e3b436\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/dlabnugetcert.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"37bf0118bbd656e6d30e7e3f731bac3e88caa0067868f32526cba611de7fb34a\": {\r\n      \"signature\": \"37bf0118bbd656e6d30e7e3f731bac3e88caa0067868f32526cba611de7fb34a\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/dynamicsha1.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"0df13d5b0e02d27610c5d26fbf8ada8c29161046087a88e59971d1fdea20c88d\": {\r\n      \"signature\": \"0df13d5b0e02d27610c5d26fbf8ada8c29161046087a88e59971d1fdea20c88d\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/dynamicsha2.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"709b4fdd6d0142712f9f69b3192563e149ccc7cb8762be291bbb567bb2d42d86\": {\r\n      \"signature\": \"709b4fdd6d0142712f9f69b3192563e149ccc7cb8762be291bbb567bb2d42d86\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/testdlab.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"4eaff6af7a166277db7356b713f44571532010adcfa3b81e77d34370f054a692\": {\r\n      \"signature\": \"4eaff6af7a166277db7356b713f44571532010adcfa3b81e77d34370f054a692\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/testdlabsha2.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"bf291646a1ae462fe07d1e4fe7cf682ececdbac480c9242a9fe60b5607842dbc\": {\r\n      \"signature\": \"bf291646a1ae462fe07d1e4fe7cf682ececdbac480c9242a9fe60b5607842dbc\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/vsmsappx.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"f85ca33e9ffc2662390548a77947fa9c1c0a66aa194a61d381fdbce391769435\": {\r\n      \"signature\": \"f85ca33e9ffc2662390548a77947fa9c1c0a66aa194a61d381fdbce391769435\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/WinBlue.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"f64a177dcdd266dfecc33e3a55c01c58ec6c097f3453a70cf7b9be0bb40ea30c\": {\r\n      \"signature\": \"f64a177dcdd266dfecc33e3a55c01c58ec6c097f3453a70cf7b9be0bb40ea30c\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/WP223.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    },\r\n    \"26564b328f56f22a3050e620db0d9bc693ba20720e04e99e76625da1bacc92b8\": {\r\n      \"signature\": \"26564b328f56f22a3050e620db0d9bc693ba20720e04e99e76625da1bacc92b8\",\r\n      \"alternativeSignatures\": [],\r\n      \"target\": \"MicroBuild/Plugins/MicroBuild.Plugins.Signing.1.1.950/build/tools/MobileTools/7Sign/tcb.pfx\",\r\n      \"line\": 1,\r\n      \"memberOf\": [\r\n        \"default\"\r\n      ],\r\n      \"tool\": \"credscan\",\r\n      \"ruleId\": \"CSCAN-GENERAL0020\",\r\n      \"createdDate\": \"2024-08-02 00:42:13Z\",\r\n      \"expirationDate\": \"2025-01-19 00:45:11Z\",\r\n      \"justification\": \"This error is baselined with an expiration date of 180 days from 2024-08-02 00:45:11Z\"\r\n    }\r\n  }\r\n}"
  },
  {
    "path": ".config/tsaoptions.json",
    "content": "{\n  \"areaPath\": \"DevDiv\\\\ASP.NET Core\\\\Orleans\",\n  \"codebaseName\": \"Orleans\",\n  \"instanceUrl\": \"https://devdiv.visualstudio.com/\",\n  \"iterationPath\": \"DevDiv\",\n  \"notificationAliases\": [\n    \"bpetit@microsoft.com\",\n    \"reuben.bond@microsoft.com\"\n  ],\n  \"projectName\": \"DEVDIV\",\n  \"repositoryName\": \"Orleans\",\n  \"template\": \"TFSDEVDIV\"\n}\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:\n// https://github.com/devcontainers/images/tree/main/src/dotnet\n{\n\t\"name\": \"Orleans\",\n\t\"image\": \"mcr.microsoft.com/devcontainers/dotnet:latest\",\n\n\t// Features to add to the dev container. More info: https://containers.dev/features\n\t\"features\": {\n\t\t\"ghcr.io/devcontainers/features/docker-in-docker\": {},\n\t\t\"ghcr.io/devcontainers/features/github-cli:1\": {}\n\t},\n\n\t\"hostRequirements\": {\n\t\t\"cpus\": 4,\n\t\t\"memory\": \"8gb\",\n\t\t\"storage\": \"32gb\"\n\t},\n\n\t\"customizations\": {\n\t\t\"vscode\": {\n\t\t\t\"extensions\": [\n\t\t\t\t\"ms-dotnettools.csdevkit\",\n\t\t\t\t\"GitHub.copilot\"\n\t\t\t],\n\t\t\t\"settings\": {\n\t\t\t\t\"remote.autoForwardPorts\": true,\n\t\t\t\t\"remote.autoForwardPortsSource\": \"hybrid\",\n\t\t\t\t\"remote.otherPortsAttributes\": {\n\t\t\t\t\t\"onAutoForward\": \"ignore\"\n\t\t\t\t},\n\t\t\t\t\"dotnet.defaultSolution\": \"Orleans.slnx\"\n\t\t\t}\n\t\t}\n\t},\n\n\t\"onCreateCommand\": \"dotnet restore\",\n\t\"postStartCommand\": \"dotnet dev-certs https --trust || true\"\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "; EditorConfig to support per-solution formatting.\n; Use the EditorConfig VS add-in to make this work.\n; http://editorconfig.org/\n;\n; Here are some resources for what's supported for .NET/C#\n; https://kent-boogaart.com/blog/editorconfig-reference-for-c-developers\n; https://learn.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference\n;\n; Be **careful** editing this because some of the rules don't support adding a severity level\n; For instance if you change to `dotnet_sort_system_directives_first = true:suggestion` (adding `:warning`)\n; then the rule will be silently ignored.\n\n; This is the default for the codeline.\nroot = true\n\n[*]\nindent_style = space\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nspelling_exclusion_path = spelling.dic\n\n# Verify settings\n[*.{received,verified}.{cs}]\ncharset = \"utf-8-bom\"\nend_of_line = lf\nindent_size = unset\nindent_style = unset\ninsert_final_newline = false\ntab_width = unset\ntrim_trailing_whitespace = false\n\n[*.{cs,csx,cake}]\nindent_size = 4\ndotnet_sort_system_directives_first = true\n\n# Don't use this. qualifier\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\n\n# use int x = .. over Int32\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\n\n# use int.MaxValue over Int32.MaxValue\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\n# Require var all the time.\ncsharp_style_var_for_built_in_types = true:suggestion\ncsharp_style_var_when_type_is_apparent = true:suggestion\ncsharp_style_var_elsewhere = true:suggestion\n\n# Disallow throw expressions.\ncsharp_style_throw_expression = false:suggestion\n\n# Newline settings\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_before_else = true\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_members_in_anonymous_types = true\n\n# Namespace settings\ncsharp_style_namespace_declarations = file_scoped\n\n# Brace settings\ncsharp_prefer_braces = true # Prefer curly braces even for one line of code\n\ndotnet_sort_system_directives_first = true\ndotnet_style_coalesce_expression = true : suggestion\ndotnet_style_collection_initializer = true : suggestion\ndotnet_style_explicit_tuple_names = true : suggestion\ndotnet_style_null_propagation = true : suggestion\ndotnet_style_object_initializer = true : suggestion\ndotnet_style_parentheses_in_arithmetic_binary_operators =never_if_unnecessary:suggestion\ndotnet_style_parentheses_in_other_binary_operators =never_if_unnecessary:suggestion\ndotnet_style_parentheses_in_other_operators =never_if_unnecessary:suggestion\ndotnet_style_parentheses_in_relational_binary_operators =never_if_unnecessary:suggestion\ndotnet_style_predefined_type_for_locals_parameters_members = true : suggestion\ndotnet_style_predefined_type_for_member_access = true : suggestion\ndotnet_style_prefer_auto_properties = true : suggestion\ndotnet_style_prefer_compound_assignment = true : suggestion\ndotnet_style_prefer_conditional_expression_over_assignment = true : suggestion\ndotnet_style_prefer_conditional_expression_over_return = true : suggestion\ndotnet_style_prefer_inferred_anonymous_type_member_names = true : suggestion\ndotnet_style_prefer_inferred_tuple_names = true : suggestion\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true : suggestion\ndotnet_style_qualification_for_event =false:suggestion\ndotnet_style_qualification_for_field =false:suggestion\ndotnet_style_qualification_for_method =false:suggestion\ndotnet_style_qualification_for_property =false:suggestion\ndotnet_style_require_accessibility_modifiers = always : suggestion\n\n# Naming Symbols\n# constant_fields - Define constant fields\ndotnet_naming_symbols.constant_fields.applicable_kinds = field\ndotnet_naming_symbols.constant_fields.required_modifiers = const\n# non_private_readonly_fields - Define public, internal and protected readonly fields\ndotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, internal, protected\ndotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field\ndotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly\n# static_readonly_fields - Define static and readonly fields\ndotnet_naming_symbols.static_readonly_fields.applicable_kinds = field\ndotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly\n# private_readonly_fields - Define private readonly fields\ndotnet_naming_symbols.private_readonly_fields.applicable_accessibilities = private\ndotnet_naming_symbols.private_readonly_fields.applicable_kinds = field\ndotnet_naming_symbols.private_readonly_fields.required_modifiers = readonly\n# public_internal_fields - Define public and internal fields\ndotnet_naming_symbols.public_internal_fields.applicable_accessibilities = public, internal\ndotnet_naming_symbols.public_internal_fields.applicable_kinds = field\n# private_protected_fields - Define private and protected fields\ndotnet_naming_symbols.private_protected_fields.applicable_accessibilities = private, protected\ndotnet_naming_symbols.private_protected_fields.applicable_kinds = field\n# public_symbols - Define any public symbol\ndotnet_naming_symbols.public_symbols.applicable_accessibilities = public, internal, protected, protected_internal\ndotnet_naming_symbols.public_symbols.applicable_kinds = method, property, event, delegate\n# parameters - Defines any parameter\ndotnet_naming_symbols.parameters.applicable_kinds = parameter\n# non_interface_types - Defines class, struct, enum and delegate types\ndotnet_naming_symbols.non_interface_types.applicable_kinds = class, struct, enum, delegate\n# interface_types - Defines interfaces\ndotnet_naming_symbols.interface_types.applicable_kinds = interface\n# private_fields - Defines private fields\ndotnet_naming_symbols.private_fields.applicable_kinds = field\ndotnet_naming_symbols.private_fields.applicable_accessibilities = private\n\n# Naming Styles\n# camel_case - Define the camelCase style\ndotnet_naming_style.camel_case.capitalization = camel_case\n# pascal_case - Define the Pascal_case style\ndotnet_naming_style.pascal_case.capitalization = pascal_case\n# first_upper - The first character must start with an upper-case character\ndotnet_naming_style.first_upper.capitalization = first_word_upper\n# prefix_interface_interface_with_i - Interfaces must be PascalCase and the first character of an interface must be an 'I'\ndotnet_naming_style.prefix_interface_interface_with_i.capitalization = pascal_case\ndotnet_naming_style.prefix_interface_interface_with_i.required_prefix = I\n# prefix_underscore_camel_case - Private fields must be prefixed with an '_'\ndotnet_naming_style.prefix_underscore_camel_case.capitalization = camel_case\ndotnet_naming_style.prefix_underscore_camel_case.required_prefix = _\n\n# Naming Rules\n# Constant fields must be PascalCase\ndotnet_naming_rule.constant_fields_must_be_pascal_case.severity = suggestion\ndotnet_naming_rule.constant_fields_must_be_pascal_case.symbols = constant_fields\ndotnet_naming_rule.constant_fields_must_be_pascal_case.style = pascal_case\n# Public, internal and protected readonly fields must be PascalCase\ndotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.severity = suggestion\ndotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.symbols = non_private_readonly_fields\ndotnet_naming_rule.non_private_readonly_fields_must_be_pascal_case.style = pascal_case\n# Static readonly fields must be PascalCase\ndotnet_naming_rule.static_readonly_fields_must_be_pascal_case.severity = suggestion\ndotnet_naming_rule.static_readonly_fields_must_be_pascal_case.symbols = static_readonly_fields\ndotnet_naming_rule.static_readonly_fields_must_be_pascal_case.style = pascal_case\n# Private readonly fields must be camelCase\ndotnet_naming_rule.private_readonly_fields_must_be_camel_case.severity = suggestion\ndotnet_naming_rule.private_readonly_fields_must_be_camel_case.symbols = private_readonly_fields\ndotnet_naming_rule.private_readonly_fields_must_be_camel_case.style = prefix_underscore_camel_case\n# Public and internal fields must be PascalCase\ndotnet_naming_rule.public_internal_fields_must_be_pascal_case.severity = suggestion\ndotnet_naming_rule.public_internal_fields_must_be_pascal_case.symbols = public_internal_fields\ndotnet_naming_rule.public_internal_fields_must_be_pascal_case.style = pascal_case\n# Private and protected fields must be camelCase\ndotnet_naming_rule.private_protected_fields_must_be_camel_case.severity = suggestion\ndotnet_naming_rule.private_protected_fields_must_be_camel_case.symbols = private_protected_fields\ndotnet_naming_rule.private_protected_fields_must_be_camel_case.style = camel_case\n# Public members must be capitalized\ndotnet_naming_rule.public_members_must_be_capitalized.severity = suggestion\ndotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols\ndotnet_naming_rule.public_members_must_be_capitalized.style = first_upper\n# Parameters must be camelCase\ndotnet_naming_rule.parameters_must_be_camel_case.severity = suggestion\ndotnet_naming_rule.parameters_must_be_camel_case.symbols = parameters\ndotnet_naming_rule.parameters_must_be_camel_case.style = camel_case\n# Class, struct, enum and delegates must be PascalCase\ndotnet_naming_rule.non_interface_types_must_be_pascal_case.severity = suggestion\ndotnet_naming_rule.non_interface_types_must_be_pascal_case.symbols = non_interface_types\ndotnet_naming_rule.non_interface_types_must_be_pascal_case.style = pascal_case\n# Interfaces must be PascalCase and start with an 'I'\ndotnet_naming_rule.interface_types_must_be_prefixed_with_i.severity = suggestion\ndotnet_naming_rule.interface_types_must_be_prefixed_with_i.symbols = interface_types\ndotnet_naming_rule.interface_types_must_be_prefixed_with_i.style = prefix_interface_interface_with_i\n# Private fields must begin with an '_'\ndotnet_naming_rule.private_members_with_underscore.symbols = private_fields\ndotnet_naming_rule.private_members_with_underscore.style = prefix_underscore_camel_case\ndotnet_naming_rule.private_members_with_underscore.severity = suggestion\n\n# Indentation Options\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_labels = flush_left\ncsharp_indent_switch_labels = true\n# Style Options\ncsharp_style_conditional_delegate_call = true : suggestion\ncsharp_style_deconstructed_variable_declaration = true : suggestion\ncsharp_style_expression_bodied_accessors = true : suggestion\ncsharp_style_expression_bodied_constructors = false : silent\ncsharp_style_expression_bodied_indexers = true : suggestion\ncsharp_style_expression_bodied_methods = when_on_single_line : suggestion\ncsharp_style_expression_bodied_operators = when_on_single_line : suggestion\ncsharp_style_expression_bodied_properties = true : suggestion\ncsharp_style_expression_bodied_lambdas = true : suggestion\ncsharp_style_expression_bodied_local_functions = when_on_single_line : suggestion\ncsharp_style_inlined_variable_declaration = true : suggestion\ncsharp_style_pattern_local_over_anonymous_function = true : suggestion\ncsharp_style_pattern_matching_over_as_with_null_check = true : suggestion\ncsharp_style_pattern_matching_over_is_with_cast_check = true : suggestion\ncsharp_style_throw_expression = true : suggestion\ncsharp_style_var_elsewhere = true : suggestion\ncsharp_style_var_for_built_in_types = true : suggestion\ncsharp_style_var_when_type_is_apparent = true : suggestion\ncsharp_style_namespace_declarations = file_scoped\n\n# New Line Options\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_else = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_between_query_expression_clauses = true\n# Spacing Options\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = do_not_ignore\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n# Wrapping Options\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = true\n# Blocks\ncsharp_prefer_braces = true:none\n# Expressions\ncsharp_prefer_simple_default_expression = true:suggestion\n\n[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]\nindent_size = 2\n\n# Xml config files\n[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]\nindent_size = 2\n\n[*.json]\nindent_size = 2\n\n[*.{ps1,psm1}]\nindent_size = 4\n\n[*.sh]\nindent_size = 4\nend_of_line = lf\n\n[*.{razor,cshtml}]\ncharset = utf-8-bom\n\n[*.{cs,vb}]\n\n# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time\ndotnet_diagnostic.SYSLIB1054.severity = suggestion\n\n# CA1018: Mark attributes with AttributeUsageAttribute\ndotnet_diagnostic.CA1018.severity = suggestion\n\n# CA1047: Do not declare protected member in sealed type\ndotnet_diagnostic.CA1047.severity = suggestion\n\n# CA1305: Specify IFormatProvider\ndotnet_diagnostic.CA1305.severity = suggestion\n\n# CA1507: Use nameof to express symbol names\ndotnet_diagnostic.CA1507.severity = suggestion\n\n# CA1510: Use ArgumentNullException throw helper\ndotnet_diagnostic.CA1510.severity = suggestion\n\n# CA1511: Use ArgumentException throw helper\ndotnet_diagnostic.CA1511.severity = suggestion\n\n# CA1512: Use ArgumentOutOfRangeException throw helper\ndotnet_diagnostic.CA1512.severity = suggestion\n\n# CA1513: Use ObjectDisposedException throw helper\ndotnet_diagnostic.CA1513.severity = suggestion\n\n# CA1725: Parameter names should match base declaration\ndotnet_diagnostic.CA1725.severity = suggestion\n\n# CA1802: Use literals where appropriate\ndotnet_diagnostic.CA1802.severity = suggestion\n\n# CA1805: Do not initialize unnecessarily\ndotnet_diagnostic.CA1805.severity = suggestion\n\n# CA1810: Do not initialize unnecessarily\ndotnet_diagnostic.CA1810.severity = suggestion\n\n# CA1821: Remove empty Finalizers\ndotnet_diagnostic.CA1821.severity = suggestion\n\n# CA1822: Make member static\ndotnet_diagnostic.CA1822.severity = suggestion\ndotnet_code_quality.CA1822.api_surface = private, internal\n\n# CA1823: Avoid unused private fields\ndotnet_diagnostic.CA1823.severity = suggestion\n\n# CA1825: Avoid zero-length array allocations\ndotnet_diagnostic.CA1825.severity = suggestion\n\n# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly\ndotnet_diagnostic.CA1826.severity = suggestion\n\n# CA1827: Do not use Count() or LongCount() when Any() can be used\ndotnet_diagnostic.CA1827.severity = suggestion\n\n# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used\ndotnet_diagnostic.CA1828.severity = suggestion\n\n# CA1829: Use Length/Count property instead of Count() when available\ndotnet_diagnostic.CA1829.severity = suggestion\n\n# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder\ndotnet_diagnostic.CA1830.severity = suggestion\n\n# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1831.severity = suggestion\n\n# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1832.severity = suggestion\n\n# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1833.severity = suggestion\n\n# CA1834: Consider using 'StringBuilder.Append(char)' when applicable\ndotnet_diagnostic.CA1834.severity = suggestion\n\n# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'\ndotnet_diagnostic.CA1835.severity = suggestion\n\n# CA1836: Prefer IsEmpty over Count\ndotnet_diagnostic.CA1836.severity = suggestion\n\n# CA1837: Use 'Environment.ProcessId'\ndotnet_diagnostic.CA1837.severity = suggestion\n\n# CA1838: Avoid 'StringBuilder' parameters for P/Invokes\ndotnet_diagnostic.CA1838.severity = suggestion\n\n# CA1839: Use 'Environment.ProcessPath'\ndotnet_diagnostic.CA1839.severity = suggestion\n\n# CA1840: Use 'Environment.CurrentManagedThreadId'\ndotnet_diagnostic.CA1840.severity = suggestion\n\n# CA1841: Prefer Dictionary.Contains methods\ndotnet_diagnostic.CA1841.severity = suggestion\n\n# CA1842: Do not use 'WhenAll' with a single task\ndotnet_diagnostic.CA1842.severity = suggestion\n\n# CA1843: Do not use 'WaitAll' with a single task\ndotnet_diagnostic.CA1843.severity = suggestion\n\n# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'\ndotnet_diagnostic.CA1844.severity = suggestion\n\n# CA1845: Use span-based 'string.Concat'\ndotnet_diagnostic.CA1845.severity = suggestion\n\n# CA1846: Prefer AsSpan over Substring\ndotnet_diagnostic.CA1846.severity = suggestion\n\n# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters\ndotnet_diagnostic.CA1847.severity = suggestion\n\n# CA1852: Seal internal types\ndotnet_diagnostic.CA1852.severity = suggestion\n\n# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method\ndotnet_diagnostic.CA1854.severity = suggestion\n\n# CA1855: Prefer 'Clear' over 'Fill'\ndotnet_diagnostic.CA1855.severity = suggestion\n\n# CA1856: Incorrect usage of ConstantExpected attribute\ndotnet_diagnostic.CA1856.severity = error\n\n# CA1857: A constant is expected for the parameter\ndotnet_diagnostic.CA1857.severity = suggestion\n\n# CA1858: Use 'StartsWith' instead of 'IndexOf'\ndotnet_diagnostic.CA1858.severity = suggestion\n\n# CA2007: Consider calling ConfigureAwait on the awaited task\ndotnet_diagnostic.CA2007.severity = silent\n\n# CA2008: Do not create tasks without passing a TaskScheduler\ndotnet_diagnostic.CA2008.severity = suggestion\n\n# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value\ndotnet_diagnostic.CA2009.severity = suggestion\n\n# CA2011: Avoid infinite recursion\ndotnet_diagnostic.CA2011.severity = suggestion\n\n# CA2012: Use ValueTask correctly\ndotnet_diagnostic.CA2012.severity = suggestion\n\n# CA2013: Do not use ReferenceEquals with value types\ndotnet_diagnostic.CA2013.severity = suggestion\n\n# CA2014: Do not use stackalloc in loops.\ndotnet_diagnostic.CA2014.severity = suggestion\n\n# CA2016: Forward the 'CancellationToken' parameter to methods that take one\ndotnet_diagnostic.CA2016.severity = suggestion\n\n# CA2200: Rethrow to preserve stack details\ndotnet_diagnostic.CA2200.severity = suggestion\n\n# CA2201: Do not raise reserved exception types\ndotnet_diagnostic.CA2201.severity = suggestion\n\n# CA2208: Instantiate argument exceptions correctly\ndotnet_diagnostic.CA2208.severity = suggestion\n\n# CA2245: Do not assign a property to itself\ndotnet_diagnostic.CA2245.severity = suggestion\n\n# CA2246: Assigning symbol and its member in the same statement\ndotnet_diagnostic.CA2246.severity = suggestion\n\n# CA2249: Use string.Contains instead of string.IndexOf to improve readability.\ndotnet_diagnostic.CA2249.severity = suggestion\n\n# IDE0005: Remove unnecessary usings\ndotnet_diagnostic.IDE0005.severity = suggestion\n\n# IDE0011: Curly braces to surround blocks of code\ndotnet_diagnostic.IDE0011.severity = suggestion\n\n# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)\ndotnet_diagnostic.IDE0020.severity = suggestion\n\n# IDE0029: Use coalesce expression (non-nullable types)\ndotnet_diagnostic.IDE0029.severity = suggestion\n\n# IDE0030: Use coalesce expression (nullable types)\ndotnet_diagnostic.IDE0030.severity = suggestion\n\n# IDE0031: Use null propagation\ndotnet_diagnostic.IDE0031.severity = suggestion\n\n# IDE0035: Remove unreachable code\ndotnet_diagnostic.IDE0035.severity = suggestion\n\n# IDE0036: Order modifiers\ncsharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion\ndotnet_diagnostic.IDE0036.severity = suggestion\n\n# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)\ndotnet_diagnostic.IDE0038.severity = suggestion\n\n# IDE0043: Format string contains invalid placeholder\ndotnet_diagnostic.IDE0043.severity = suggestion\n\n# IDE0044: Make field readonly\ndotnet_diagnostic.IDE0044.severity = suggestion\n\n# IDE0051: Remove unused private members\ndotnet_diagnostic.IDE0051.severity = suggestion\n\n# IDE0055: All formatting rules\ndotnet_diagnostic.IDE0055.severity = suggestion\n\n# IDE0059: Unnecessary assignment to a value\ndotnet_diagnostic.IDE0059.severity = suggestion\n\n# IDE0060: Remove unused parameter\ndotnet_code_quality_unused_parameters = non_public\ndotnet_diagnostic.IDE0060.severity = suggestion\n\n# IDE0062: Make local function static\ndotnet_diagnostic.IDE0062.severity = suggestion\n\n# IDE0073: File header\n#dotnet_diagnostic.IDE0073.severity = silent\n#file_header_template = Licensed to the .NET Foundation under one or more agreements.\\nThe .NET Foundation licenses this file to you under the MIT license.\n\n# IDE1006: Required naming style\ndotnet_diagnostic.IDE1006.severity = suggestion\n\n# IDE0161: Convert to file-scoped namespace\ndotnet_diagnostic.IDE0161.severity = suggestion\n\n# IDE0200: Lambda expression can be removed\ndotnet_diagnostic.IDE0200.severity = suggestion\n\n# IDE2000: Disallow multiple blank lines\ndotnet_style_allow_multiple_blank_lines_experimental = false\ndotnet_diagnostic.IDE2000.severity = suggestion\n\n# CA1018: Mark attributes with AttributeUsageAttribute\ndotnet_diagnostic.CA1018.severity = suggestion\n# CA1507: Use nameof to express symbol names\ndotnet_diagnostic.CA1507.severity = suggestion\n# CA1510: Use ArgumentNullException throw helper\ndotnet_diagnostic.CA1510.severity = suggestion\n# CA1511: Use ArgumentException throw helper\ndotnet_diagnostic.CA1511.severity = suggestion\n# CA1512: Use ArgumentOutOfRangeException throw helper\ndotnet_diagnostic.CA1512.severity = suggestion\n# CA1513: Use ObjectDisposedException throw helper\ndotnet_diagnostic.CA1513.severity = suggestion\n# CA1802: Use literals where appropriate\ndotnet_diagnostic.CA1802.severity = suggestion\n# CA1805: Do not initialize unnecessarily\ndotnet_diagnostic.CA1805.severity = suggestion\n# CA1810: Do not initialize unnecessarily\ndotnet_diagnostic.CA1810.severity = suggestion\n# CA1822: Make member static\ndotnet_diagnostic.CA1822.severity = suggestion\n# CA1823: Avoid zero-length array allocations\ndotnet_diagnostic.CA1825.severity = suggestion\n# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly\ndotnet_diagnostic.CA1826.severity = suggestion\n# CA1827: Do not use Count() or LongCount() when Any() can be used\ndotnet_diagnostic.CA1827.severity = suggestion\n# CA1829: Use Length/Count property instead of Count() when available\ndotnet_diagnostic.CA1829.severity = suggestion\n# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1831.severity = suggestion\n# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1832.severity = suggestion\n# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate\ndotnet_diagnostic.CA1833.severity = suggestion\n# CA1834: Consider using 'StringBuilder.Append(char)' when applicable\ndotnet_diagnostic.CA1834.severity = suggestion\n# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'\ndotnet_diagnostic.CA1835.severity = suggestion\n# CA1837: Use 'Environment.ProcessId'\ndotnet_diagnostic.CA1837.severity = suggestion\n# CA1838: Avoid 'StringBuilder' parameters for P/Invokes\ndotnet_diagnostic.CA1838.severity = suggestion\n# CA1841: Prefer Dictionary.Contains methods\ndotnet_diagnostic.CA1841.severity = suggestion\n# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'\ndotnet_diagnostic.CA1844.severity = suggestion\n# CA1845: Use span-based 'string.Concat'\ndotnet_diagnostic.CA1845.severity = suggestion\n# CA1846: Prefer AsSpan over Substring\ndotnet_diagnostic.CA1846.severity = suggestion\n# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters\ndotnet_diagnostic.CA1847.severity = suggestion\n# CA1852: Seal internal types\ndotnet_diagnostic.CA1852.severity = suggestion\n# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method\ndotnet_diagnostic.CA1854.severity = suggestion\n# CA1855: Prefer 'Clear' over 'Fill'\ndotnet_diagnostic.CA1855.severity = suggestion\n# CA1856: Incorrect usage of ConstantExpected attribute\ndotnet_diagnostic.CA1856.severity = suggestion\n# CA1857: A constant is expected for the parameter\ndotnet_diagnostic.CA1857.severity = suggestion\n# CA1858: Use 'StartsWith' instead of 'IndexOf'\ndotnet_diagnostic.CA1858.severity = suggestion\n# CA2007: Consider calling ConfigureAwait on the awaited task\ndotnet_diagnostic.CA2007.severity = suggestion\n# CA2008: Do not create tasks without passing a TaskScheduler\ndotnet_diagnostic.CA2008.severity = suggestion\n# CA2012: Use ValueTask correctly\ndotnet_diagnostic.CA2012.severity = suggestion\n# CA2201: Do not raise reserved exception types\ndotnet_diagnostic.CA2201.severity = suggestion\n# CA2249: Use string.Contains instead of string.IndexOf to improve readability.\ndotnet_diagnostic.CA2249.severity = suggestion\n# IDE0005: Remove unnecessary usings\ndotnet_diagnostic.IDE0005.severity = suggestion\n# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)\ndotnet_diagnostic.IDE0020.severity = suggestion\n# IDE0029: Use coalesce expression (non-nullable types)\ndotnet_diagnostic.IDE0029.severity = suggestion\n# IDE0030: Use coalesce expression (nullable types)\ndotnet_diagnostic.IDE0030.severity = suggestion\n# IDE0031: Use null propagation\ndotnet_diagnostic.IDE0031.severity = suggestion\n# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)\ndotnet_diagnostic.IDE0038.severity = suggestion\n# IDE0044: Make field readonly\ndotnet_diagnostic.IDE0044.severity = suggestion\n# IDE0051: Remove unused private members\ndotnet_diagnostic.IDE0051.severity = suggestion\n# IDE0059: Unnecessary assignment to a value\ndotnet_diagnostic.IDE0059.severity = suggestion\n# IDE0060: Remove unused parameters\ndotnet_diagnostic.IDE0060.severity = suggestion\n# IDE0062: Make local function static\ndotnet_diagnostic.IDE0062.severity = suggestion\n# IDE0200: Lambda expression can be removed\ndotnet_diagnostic.IDE0200.severity = suggestion\n# CA2016: Forward the 'CancellationToken' parameter to methods that take one\ndotnet_diagnostic.CA2016.severity = suggestion\n\n# RS0041: Public members should not use oblivious types\ndotnet_diagnostic.RS0041.severity = suggestion\n\n# RS0026: Do not add multiple public overloads with optional parameters\ndotnet_diagnostic.RS0026.severity = suggestion\n\n# RS0027: API with optional parameter(s) should have the most parameters amongst its public overloads\ndotnet_diagnostic.RS0027.severity = suggestion\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n\n# Verify.Xunit\n*.verified.cs text eol=lf working-tree-encoding=UTF-8\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "## General\n\n* Make only high confidence suggestions when reviewing code changes.\n* Always use the latest version C#, currently C# 13 features.\n* Never change global.json unless explicitly asked to.\n* Orleans is a distributed actor framework for .NET - understand the grain-based programming model when making changes.\n\n## Build and Test\n\n### Building the Project\n\n* Use `dotnet build` to build the solution (Orleans.slnx).\n* The solution uses .NET SDK 9.0.306 as specified in global.json.\n* Build scripts are available: `Build.cmd` (Windows) or `build.ps1` (PowerShell).\n* Debug builds include a date suffix in version numbers.\n\n### Running Tests\n\n* Use `dotnet test` to run tests.\n* Test.cmd provides a convenient way to run all tests on Windows.\n* Tests are organized by category: BVT, SlowBVT, Functional, and provider-specific categories.\n* Some tests require external dependencies (Redis, Cassandra, Azure, AWS, etc.) - check the CI workflow for setup examples.\n* Use `--filter` to run specific test categories, e.g., `dotnet test --filter \"Category=BVT\"`.\n\n## Formatting\n\n* Apply code-formatting style defined in `.editorconfig`.\n* Prefer file-scoped namespace declarations and single-line using directives.\n* Insert a newline before the opening curly brace of any code block (e.g., after `if`, `for`, `while`, `foreach`, `using`, `try`, etc.).\n* Ensure that the final return statement of a method is on its own line.\n* Use pattern matching and switch expressions wherever possible.\n* Use `nameof` instead of string literals when referring to member names.\n* Ensure that XML doc comments are created for any public APIs. When applicable, include `<example>` and `<code>` documentation in the comments.\n\n### Nullable Reference Types\n\n* Declare variables non-nullable, and check for `null` at entry points.\n* Always use `is null` or `is not null` instead of `== null` or `!= null`.\n* Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.\n\n## Testing\n\n* We use xUnit SDK v3 for tests.\n* Do not emit \"Act\", \"Arrange\" or \"Assert\" comments.\n* Use NSubstitute for mocking in tests.\n* Copy existing style in nearby files for test method names and capitalization.\n* Tests are located in the `test/` directory, organized by functionality (e.g., DefaultCluster.Tests, NonSilo.Tests, Extensions/).\n\n## Repository Structure\n\n* **src/** - Core Orleans runtime, serialization, client, hosting, and provider implementations.\n  * Orleans.Core - Core runtime abstractions and implementations\n  * Orleans.Serialization - High-performance serialization framework\n  * Orleans.Client - Client-side grain communication\n  * Orleans.Runtime - Server-side runtime implementation\n  * Orleans.Hosting.Kubernetes - Kubernetes hosting support\n  * Provider subdirectories: AWS/, Azure/, AdoNet/, Cassandra/, Redis/ for various storage and clustering providers\n* **test/** - All test projects, mirroring the src/ structure.\n* **samples/** - Example applications demonstrating Orleans usage.\n* **playground/** - Experimental code and development workspace.\n\n## Common Patterns\n\n* Grains are the fundamental building blocks - they have stable identity, behavior, and state.\n* Grain interfaces inherit from IGrain or IGrainWithGuidKey/IGrainWithStringKey/etc.\n* Use async/await consistently - Orleans is built on asynchronous patterns.\n* Follow the Virtual Actor Model - grains are automatically activated/deactivated by the runtime.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\r\nupdates:\r\n  - package-ecosystem: \"dotnet-sdk\"\r\n    directory: \"/\"\r\n    schedule:\r\n      interval: \"weekly\"\r\n      day: \"wednesday\"\r\n    ignore:\r\n      - dependency-name: \"*\"\r\n        update-types:\r\n          - \"version-update:semver-major\"\r\n"
  },
  {
    "path": ".github/eventhubs-emulator/Config.json",
    "content": "{\n  \"UserConfig\": {\n    \"NamespaceConfig\": [\n      {\n        \"Type\": \"EventHub\",\n        \"Name\": \"emulatorNs1\",\n        \"Entities\": [\n          {\n            \"Name\": \"ehorleanstest\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest2\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest3\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest4\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest5\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest6\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest7\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest8\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          },\n          {\n            \"Name\": \"ehorleanstest9\",\n            \"PartitionCount\": \"4\",\n            \"ConsumerGroups\": [\n              {\n                \"Name\": \"orleansnightly\"\n              }\n            ]\n          }\n        ]\n      }\n    ],\n    \"LoggingConfig\": {\n      \"Type\": \"File\"\n    }\n  }\n}\n"
  },
  {
    "path": ".github/policies/resourceManagement.yml",
    "content": "id: \r\nname: GitOps.PullRequestIssueManagement\r\ndescription: GitOps.PullRequestIssueManagement primitive\r\nowner: \r\nresource: repository\r\ndisabled: false\r\nwhere: \r\nconfiguration:\r\n  resourceManagementConfiguration:\r\n    scheduledSearches:\r\n    - description: Close stale issues\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasLabel:\r\n          label: 'Needs: author feedback'\r\n      - hasLabel:\r\n          label: 'Status: no recent activity'\r\n      - noActivitySince:\r\n          days: 3\r\n      actions:\r\n      - closeIssue\r\n    - description: Add no recent activity label to issues\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasLabel:\r\n          label: 'Needs: author feedback'\r\n      - noActivitySince:\r\n          days: 4\r\n      - isNotLabeledWith:\r\n          label: 'Status: no recent activity'\r\n      actions:\r\n      - addLabel:\r\n          label: 'Status: no recent activity'\r\n      - addReply:\r\n          reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**.\r\n    - description: Close duplicate issues\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasLabel:\r\n          label: duplicate\r\n      actions:\r\n      - addReply:\r\n          reply: This issue has been marked as duplicate. It will be closed for housekeeping purposes.\r\n      - closeIssue\r\n    - description: Close stale pull requests\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isPullRequest\r\n      - isOpen\r\n      - hasLabel:\r\n          label: 'Needs: author feedback'\r\n      - hasLabel:\r\n          label: 'Status: no recent activity'\r\n      - noActivitySince:\r\n          days: 7\r\n      actions:\r\n      - closeIssue\r\n    - description: Add no recent activity label to pull requests\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isPullRequest\r\n      - isOpen\r\n      - hasLabel:\r\n          label: 'Needs: author feedback'\r\n      - noActivitySince:\r\n          days: 7\r\n      - isNotLabeledWith:\r\n          label: 'Status: no recent activity'\r\n      actions:\r\n      - addLabel:\r\n          label: 'Status: no recent activity'\r\n      - addReply:\r\n          reply: This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within 7 days of this comment**.\r\n    - description: Close Answered questions\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasLabel:\r\n          label: ':heavy_check_mark: Resolution: Answered'\r\n      actions:\r\n      - addReply:\r\n          reply: Thanks for contacting us. We believe that the question you've raised has been answered. If you still feel a need to continue the discussion, feel free to reopen the issue and add your comments.\r\n      - addLabel:\r\n          label: 'Status: Resolved'\r\n      - closeIssue\r\n    - description: Close by Design\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isOpen\r\n      - isIssue\r\n      - hasLabel:\r\n          label: ':heavy_check_mark: Resolution: By Design'\r\n      actions:\r\n      - addReply:\r\n          reply: Thank you for your feedback. We're closing this issue as the behavior discussed is by design.\r\n      - addLabel:\r\n          label: 'Status: Resolved'\r\n      - closeIssue\r\n    - description: Close duplicates\r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isOpen\r\n      - isIssue\r\n      - hasLabel:\r\n          label: ':heavy_check_mark: Resolution: Duplicate'\r\n      actions:\r\n      - addReply:\r\n          reply: >+\r\n            This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes.\r\n\r\n      - addLabel:\r\n          label: 'Status: Resolved'\r\n      - closeIssue\r\n    - description: 'Label issues as Stale '\r\n      frequencies:\r\n      - daily:\r\n          time: 16:0\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasNoLabel\r\n      - isNotAssigned\r\n      - isPartOfMilestone:\r\n          milestone: Triage\r\n      - created:\r\n          before: 365\r\n      actions:\r\n      - addLabel:\r\n          label: stale\r\n      - addReply:\r\n          reply: 'We are marking this issue as stale due to the lack of activity in the past six months. If there is no further activity within two weeks, this issue will be closed. You can always create a new issue based on the guidelines provided in our pinned announcement. '\r\n    - description: Mark old issues in the backlog as stale\r\n      frequencies:\r\n      - daily:\r\n          time: 17:0\r\n      filters:\r\n      - isOpen\r\n      - hasNoLabel\r\n      - isNotAssigned\r\n      - isPartOfMilestone:\r\n          milestone: Backlog\r\n      - created:\r\n          before: 365\r\n      - isIssue\r\n      actions:\r\n      - addLabel:\r\n          label: stale\r\n      - addReply:\r\n          reply: 'We are marking this issue as stale due to the lack of activity in the past six months. If there is no further activity within two weeks, this issue will be closed. You can always create a new issue based on the guidelines provided in our pinned announcement. '\r\n    - description: Close Stale Issues\r\n      frequencies:\r\n      - daily:\r\n          time: 15:0\r\n      - daily:\r\n          time: 18:0\r\n      filters:\r\n      - isIssue\r\n      - isOpen\r\n      - hasLabel:\r\n          label: stale\r\n      - noActivitySince:\r\n          days: 10\r\n      actions:\r\n      - addReply:\r\n          reply: 'This issue has been marked stale for the past 30 and is being closed due to lack of activity. '\r\n      - closeIssue\r\n    eventResponderTasks:\r\n    - if:\r\n      - payloadType: Pull_Request\r\n      - isAction:\r\n          action: Opened\r\n      then:\r\n      - addCodeFlowLink\r\n      description: Add a CodeFlow link to new pull requests\r\nonFailure: \r\nonSuccess: \r\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: .NET CI\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n  merge_group:\n    types:\n      - checks_requested\nenv:\n  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1\n  DOTNET_NOLOGO: true\njobs:\n  build:\n    name: Build\n    runs-on: ${{ matrix.os }}\n    continue-on-error: true\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest, macos-latest]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup Node.js\n      uses: actions/setup-node@v4\n      with:\n        node-version: '20.x'\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Build\n      run: dotnet build -bl\n    - uses: actions/upload-artifact@v4\n      with:\n        name: build_log_${{ matrix.os }}\n        retention-days: 1\n        path: |\n          **/*.binlog\n  test-redis:\n    name: Redis provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"Redis\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      redis:\n        image: redis\n        ports:\n        - 6379:6379\n        options: >-\n          --health-cmd \"redis-cli ping\"\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n        ORLEANSREDISCONNECTIONSTRING: \"localhost:6379,ssl=False,abortConnect=False\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-cassandra:\n    name: Cassandra provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"Cassandra\"]\n        dbversion: [\"4.0\", \"4.1\", \"5.0\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Clustering)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.dbversion }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n        CASSANDRAVERSION: ${{ matrix.dbversion }}\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.dbversion }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-postgres:\n    name: PostgreSQL provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"PostgreSql\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      postgres:\n        image: postgres\n        env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"False positive\")]\n          POSTGRES_PASSWORD: postgres\n        ports:\n        - 5432:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"False positive\")]\n        ORLEANSPOSTGRESCONNECTIONSTRING: \"Server=127.0.0.1;Port=5432;Pooling=false;User Id=postgres;Password=postgres;SSL Mode=Disable\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-mariadb:\n    name: MariaDB/MySQL provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"MySql\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      mariadb:\n        image: mariadb:10.6\n        ports:\n          - 3306:3306\n        env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"False positive\")]\n          MARIADB_ROOT_PASSWORD: \"mariadb\"\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSMYSQLCONNECTIONSTRING: \"Server=127.0.0.1;Port=3306;UId=root;Pwd=mariadb;\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-sqlserver:\n    name: Microsoft SQL Server provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"SqlServer\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      mssql:\n        image: mcr.microsoft.com/mssql/server:latest\n        ports:\n          - 1433:1433\n        env:\n          ACCEPT_EULA: \"Y\"\n          MSSQL_PID: \"Developer\"\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"False positive\")]\n          SA_PASSWORD: \"yourWeak(!)Password\"\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSMSSQLCONNECTIONSTRING: \"Server=127.0.0.1,1433;User Id=SA;Password=yourWeak(!)Password;TrustServerCertificate=True;\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-azure-storage:\n    name: Azure Storage provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        framework: [\"net8.0\", \"net10.0\"]\n        provider: [\"AzureStorage\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Start Azurite\n      run: |\n        docker run -d --name azurite \\\n          -p 10000:10000 \\\n          -p 10001:10001 \\\n          -p 10002:10002 \\\n          mcr.microsoft.com/azure-storage/azurite:latest \\\n          azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck\n    - name: Wait for Azurite\n      run: |\n        echo \"Waiting for Azurite to be ready...\"\n        timeout 60 bash -c 'until nc -z localhost 10000 && nc -z localhost 10001 && nc -z localhost 10002; do sleep 1; done'\n        echo \"Azurite is ready\"\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --framework ${{ matrix.framework }}\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n# [SuppressMessage(\"Microsoft.Security\", \"CSCAN0090:ConfigFile\", Justification=\"Not a secret\")]\n# [SuppressMessage(\"Microsoft.Security\", \"CSCAN0220:DefaultPasswordContexts\", Justification=\"Not a secret\")]\n        ORLEANSDATACONNECTIONSTRING: \"DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;\"\n    - name: Clean up Azurite\n      if: always()\n      run: docker rm -f azurite\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-azure-eventhubs:\n    name: Azure Event Hubs provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        framework: [\"net8.0\", \"net10.0\"]\n        provider: [\"EventHub\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Start Azurite\n      run: |\n        docker run -d --name azurite \\\n          -p 10000:10000 \\\n          -p 10001:10001 \\\n          -p 10002:10002 \\\n          mcr.microsoft.com/azure-storage/azurite:latest \\\n          azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck\n    - name: Wait for Azurite\n      run: |\n        echo \"Waiting for Azurite to be ready...\"\n        timeout 60 bash -c 'until nc -z localhost 10000 && nc -z localhost 10001 && nc -z localhost 10002; do sleep 1; done'\n        echo \"Azurite is ready\"\n    - name: Start Event Hubs emulator\n      run: |\n        docker run -d --name eventhubs-emulator \\\n          -v ${{ github.workspace }}/.github/eventhubs-emulator/Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json \\\n          -p 5672:5672 \\\n          -e BLOB_SERVER=host.docker.internal \\\n          -e METADATA_SERVER=host.docker.internal \\\n          -e ACCEPT_EULA=Y \\\n          --add-host=host.docker.internal:host-gateway \\\n          mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest\n    - name: Wait for Event Hubs emulator\n      run: |\n        echo \"Waiting for Event Hubs emulator to be ready...\"\n        timeout 60 bash -c 'until nc -z localhost 5672; do sleep 1; done'\n        echo \"Event Hubs emulator is ready\"\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional|Category=Streaming)\"\n        --framework ${{ matrix.framework }}\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n# [SuppressMessage(\"Microsoft.Security\", \"CSCAN0090:ConfigFile\", Justification=\"Not a secret\")]\n# [SuppressMessage(\"Microsoft.Security\", \"CSCAN0220:DefaultPasswordContexts\", Justification=\"Not a secret\")]\n        ORLEANSEVENTHUBCONNECTIONSTRING: \"Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;\"\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSDATACONNECTIONSTRING: \"DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;\"\n    - name: Clean up Event Hubs emulator\n      if: always()\n      run: docker rm -f eventhubs-emulator\n    - name: Clean up Azurite\n      if: always()\n      run: docker rm -f azurite\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-azure-cosmosdb:\n    if: ${{ false }}\n    name: Azure Cosmos DB provider tests\n    runs-on: windows-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        framework: [\"net8.0\", \"net10.0\"]\n        provider: [\"Cosmos\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    # - name: Install emulator certificate\n    #   run: |\n    #     sleep 90s\n    #     mkdir /tmp/emulatorcerts\n    #     sudo sh -c \"curl -k https://127.0.0.1:${{ job.services.cosmosdb-emulator.ports[8081] }}/_explorer/emulator.pem > /tmp/emulatorcert.crt\"\n    #     cat /tmp/emulatorcert.crt\n    #     awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > \"emulatorcert.\" c \".crt\"}' < /tmp/emulatorcert.crt\n    #     sudo cp emulatorcert.*.crt /usr/local/share/ca-certificates/\n    #     sudo update-ca-certificates\n    - name: Start Azure Cosmos DB emulator\n      run: |\n        Write-Host \"Launching Azure Cosmos DB Emulator\"\n        Import-Module \"$env:ProgramFiles\\Azure Cosmos DB Emulator\\PSModules\\Microsoft.Azure.CosmosDB.Emulator\"\n        Start-CosmosDbEmulator -NoUI -Consistency Strong -PartitionCount 2 -DefaultPartitionCount 2\n        $IPAddress = \"127.0.0.1\" #(Get-NetIPAddress -AddressFamily IPV4 -AddressState Preferred -PrefixOrigin Manual | Select-Object IPAddress -First 1).IPAddress ?? \"127.0.0.1\"\n        Add-Content -Path $env:GITHUB_ENV -Value \"ORLEANSCOSMOSDBACCOUNTENDPOINT=https://$($IPAddress):8081/\"\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        #ORLEANSCOSMOSDBACCOUNTENDPOINT: \"https://127.0.0.1:8081/\"\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSCOSMOSDBACCOUNTKEY: \"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-consul:\n    name: Consul provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"Consul\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-zookeeper:\n    name: ZooKeeper provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"ZooKeeper\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      zookeeper:\n        image: zookeeper:3.9\n        ports:\n          - 2181:2181\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n        ORLEANSZOOKEEPERCONNECTIONSTRING: \"localhost:2181\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-dynamodb:\n    name: AWS DynamoDB provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"DynamoDB\"]\n        framework: [\"net8.0\", \"net10.0\"]\n    services:\n      dynamodb:\n        image: amazon/dynamodb-local:latest\n        ports:\n        - 8000:8000\n        env:\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n          AWS_ACCESS_KEY_ID: root\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n          AWS_SECRET_ACCESS_KEY: pass\n          AWS_REGION: us-east-1\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n      env:\n        ORLEANSDYNAMODBSERVICE: \"http://127.0.0.1:8000\"\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSDYNAMODBACCESSKEY: \"root\"\n# [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n        ORLEANSDYNAMODBSECRETKEY: \"pass\"\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-nats:\n    name: NATS stream provider tests\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    strategy:\n      matrix:\n        provider: [\"NATS\"]\n        framework: [\"net8.0\", \"net10.0\"]\n#    services:\n#      nats:\n#        image: nats:latest\n#        ports:\n#        - 4222:4222\n#        - 8222:8222\n#        env:\n#          HTTP_PORT: 8222\n    steps:\n    - name: Start NATS\n      run: docker run -d --name nats -p 4222:4222 -p 8222:8222 nats:latest --js --http-port=8222\n    - name: Wait for NATS\n      run: sleep 5\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.provider }}&(Category=BVT|Category=SlowBVT|Category=Functional)\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.provider }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n    - name: Clean up container\n      if: always()\n      run: docker rm -f nats\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test:\n    name: Test\n    runs-on: ${{ matrix.os }}\n    continue-on-error: true\n    strategy:\n      matrix:\n        suite: [BVT, SlowBVT, Functional]\n        os: [ubuntu-latest, windows-latest, macos-latest]\n        framework: [\"net8.0\", \"net10.0\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup Node.js\n      uses: actions/setup-node@v4\n      with:\n        node-version: '20.x'\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Build\n      run: dotnet build\n    - name: Test\n      run: dotnet test\n        --framework ${{ matrix.framework }}\n        --filter \"Category=${{ matrix.suite }}&Category!=Consul\"\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.suite }}_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.suite }}_${{ matrix.os }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n  test-codegenerator:\n    name: Test Code Generator\n    runs-on: ${{ matrix.os }}\n    continue-on-error: true\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest, macos-latest]\n        framework: [\"net8.0\", \"net10.0\"]\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Test Code Generator\n      run: dotnet test\n        test/Orleans.CodeGenerator.Tests/Orleans.CodeGenerator.Tests.csproj\n        --framework ${{ matrix.framework }}\n        --blame-hang-timeout 10m\n        --blame-crash-dump-type full\n        --blame-hang-dump-type full\n        --logger \"trx;LogFileName=test_results_${{ matrix.framework }}.trx\"\n        --\n        -parallel none -noshadow\n    - name: Archive Test Results\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: test_output_${{ github.job }}_${{ matrix.os }}_${{ matrix.framework }}\n        retention-days: 1\n        path: |\n          **/TestResults/*\n          **/logs/*\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: CodeQL\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n  merge_group:\n    types:\n      - checks_requested\n  schedule:\n    - cron: '0 6 * * 1'  # Run weekly on Monday at 6:00 UTC\n\njobs:\n  analyze:\n    name: Analyze (${{ matrix.language }})\n    runs-on: ubuntu-latest\n    timeout-minutes: 360\n    permissions:\n      security-events: write\n      packages: read\n      actions: read\n      contents: read\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - language: csharp\n            build-mode: none\n          - language: javascript-typescript\n            build-mode: none\n          - language: actions\n            build-mode: none\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: ${{ matrix.language }}\n          build-mode: ${{ matrix.build-mode }}\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n        with:\n          category: \"/language:${{ matrix.language }}\"\n"
  },
  {
    "path": ".github/workflows/generate-api-diffs.yml",
    "content": "name: Generate API Diffs\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '0 16 * * *' # 8am PST (16:00 UTC)\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  generate-and-pr:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v4\n        with:\n          global-json-file: global.json\n\n      - name: Restore and build\n        run: |\n          set +e\n\n          # Find all csproj files excluding specific paths\n          find src -name '*.csproj' | egrep -v 'Orleans.Analyzers|Orleans.CodeGenerator' | while read proj; do\n            export CI=false && dotnet build \"$proj\" -f net8.0 --configuration Release --no-incremental /t:\"Build;GenAPIGenerateReferenceAssemblySource\"\n          done\n        continue-on-error: true\n\n      - name: Create or update pull request\n        uses: dotnet/actions-create-pull-request@e8d799aa1f8b17f324f9513832811b0a62f1e0b1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          branch: update-api-diffs\n          base: main\n          title: \"[Automated] Update API Surface Area\"\n          body: \"Auto-generated update to the API surface to compare current surface vs latest release. This should only be merged once this surface area ships in a new release.\"\n"
  },
  {
    "path": ".github/workflows/locker.yml",
    "content": "name: Locker - Lock stale issues and PRs\non:\n  schedule:\n    - cron: '0 9 * * *' # Once per day, early morning PT\n\n  workflow_dispatch:\n    # Manual triggering through the GitHub UI, API, or CLI\n    inputs:\n      daysSinceClose:\n        required: true\n        default: \"30\"\n      daysSinceUpdate:\n        required: true\n        default: \"30\"\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  main:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Actions\n        uses: actions/checkout@v4\n        with:\n          repository: \"microsoft/vscode-github-triage-actions\"\n          path: ./actions\n          ref: cd16cd2aad6ba2da74bb6c6f7293adddd579a90e # locker action commit sha\n      - name: Install Actions\n        run: npm install --production --prefix ./actions\n      - name: Run Locker\n        uses: ./actions/locker\n        with:\n          daysSinceClose:  ${{ fromJson(inputs.daysSinceClose  || 30) }}\n          daysSinceUpdate: ${{ fromJson(inputs.daysSinceUpdate || 30) }}\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# Tool Runtime Dir\n/[Tt]ools/\n/src/[Bb]ootstrap/\n\n# Orleans code-gen files\norleans.codegen.cs\norleans.codegen.fs\norleans.codegen.vb\nsrc/SDK/VSIX/\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n.vscode/\n.vs/\n.idea/\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nBinaries/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\nArtifacts/\n\n# Roslyn cache directories\n*.ide/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n#NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding addin-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# If using the old MSBuild-Integrated Package Restore, uncomment this:\n#!**/packages/repositories.config\n# Auto-downloaded nuget.exe\n**/[Nn]u[Gg]et.exe\n*.lock.json\n*.nuget.props\n*.nuget.targets\n\n# Windows Azure Build Output\ncsx/\n*.build.csdef\n\n# Windows Store app package directory\nAppPackages/\n\n# Others\nsql/\n*.Cache\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\npatch.diff\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# Temporary working files\n**/pingme.txt\n.vs/\nsrc/SetupTestScriptOutput.txt\n\n\\.DS_Store\n\n# Binary MSBuild Log files\n*.binlog\n\n# VS Code\n.ionide/\n\n# Verify.Xunit\n*.received.*\n\n# code coverage\n*.cobertura.xml\n"
  },
  {
    "path": "Build.cmd",
    "content": "powershell -NoProfile -ExecutionPolicy unrestricted -Command \"./build.ps1 %1\"\n"
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "content": "# Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant\nto clarify expected behavior in our community.\n\nFor more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Orleans\n\nSome notes and guidelines for developers who want to contribute to Orleans.\n\n## Contributing to this project\n\nHere are some pointers for anyone looking for mini-features and work items that would make a positive contribution to Orleans.\n\nThese are just a few ideas, so if you think of something else that would be useful, then spin up a [discussion thread](https://github.com/dotnet/orleans/issues) on GitHub to discuss the proposal, and go for it.\n\n* **[Orleans GitHub Repository](https://github.com/dotnet/orleans)**\n\nPull requests are always welcome.\n\n* **[Intern and Student Projects](https://docs.microsoft.com/dotnet/orleans/resources/student-projects)**\n\nSome suggestions for possible intern / student projects.\n\n* **[Documentation Guidelines](https://docs.microsoft.com/contribute/dotnet/dotnet-contribute)**\n\nA style guide for writing documentation for this site.\n\n## Code contributions\n\nThis project uses the same contribution process as the other **[.NET projects](https://github.com/dotnet)** on GitHub.\n\n* **[.NET Project Contribution Guidelines](https://github.com/dotnet/runtime/blob/main/CONTRIBUTING.md)**\n\nGuidelines and workflow for contributing to .NET projects on GitHub.\n\n* **[.NET CLA](https://cla.dotnetfoundation.org/)**\n\nContribution License Agreement for .NET projects on GitHub.\n\n* **[.NET Framework Design Guidelines](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/framework-design-guidelines-digest.md)**\n\nSome basic API design rules, coding standards, and style guide for .NET Framework APIs.\n\n## Coding Standards and Conventions\n\nWe try not to be too OCD about coding style wars, but in case of disputes we do fall back to the core principles in the two \".NET Coding Standards\" books used by the other .NET OSS projects on GitHub:\n\n* [C# Coding Style Guide](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/coding-style.md)\n\n* [.NET Framework Design Guidelines](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/framework-design-guidelines-digest.md)\n\nThere are lots of other useful documents on the [.NET](https://github.com/dotnet/runtime/tree/main/docs#coding-guidelines) documentation sites which are worth reading, although most experienced C# developers will probably have picked up many of those best-practices by osmosis, particularly around performance and memory management.\n\n## Source code organization\n\nOrleans has not religiously followed a \"One Class Per File\" rule, but instead we have tried to use pragmatic judgment to maximize the change of \"code understand-ability\" for developers on the team. If lots of small-ish classes share a \"common theme\" and/or are always dealt with together, then it is OK to place those into one source code file in most cases. See for example the various \"log consumer\" classes were originally placed in single source file, as they represented a single unit of code comprehension.\n\nAs a corollary, it is much easier to find the source code for a class if it is in a file with the same name as the class [similar to Java file naming rules], so there is a tension and value judgment here between code find-ability and minimizing / constraining the number of projects in a solution and files within a project [which both have direct impact on the Visual Studio \"Opening\" and \"Building\" times for large projects].\n\nCode search tools in VS and ReSharper definitely help here.\n\n## Dependencies and Inter-Project References\n\nOne topic that we are very strict about is around dependency references between components and sub-systems.\n\n### Component / Project References\n\nReferences between projects in a solution must always use \"**Project References**\" rather than \"_DLL References_\" to ensure that component build relationships are known to the build tools.\n\n**Right**:\n\n```xml\n<ProjectReference Include=\"..\\Orleans\\Orleans.csproj\">\n    <Project>{BC1BD60C-E7D8-4452-A21C-290AEC8E2E74}</Project>\n    <Name>Orleans</Name>\n</ProjectReference>\n```\n\n_Wrong_:\n\n```xml\n<Reference Include=\"Orleans\" >\n    <HintPath>..\\Orleans\\bin\\Debug\\Orleans.dll</HintPath>\n</Reference>\n```\n\nIn order to help ensure we keep inter-project references clean, then on the build servers [and local `Build.cmd` script] we deliberately use side-by-side input `.\\src` and output `.\\Binaries` directories rather than the more normal in-place build directory structure (eg. `[PROJ]\\bin\\Release`) used by VS on local dev machines.\n\n### Unified component versions\n\nWe use the same unified versions of external component throughout the Orleans code base, and so should never need to add `bindingRedirect` entries in `App.config` files.\n\nAlso, in general it should almost never be necessary to have `Private=True` elements in Orleans project files, except to override a conflict with a Windows / VS \"system\" component.\nSome package management tools can occasionally get confused when making version changes, and sometimes think that we are using multiple versions of the same assembly within a solution, which of course we never do.\n\nWe long for the day when package management tools for .NET can make version changes transactionally. Until then, it is occasionally necessary to \"fix\" the misguided actions of some .NET package management tools by hand-editing the .csproj files (they are just XML text files) back to sanity and/or using the \"Discard Edited Line\" functions that most good Git tools such as [Atlassian SourceTree](https://www.sourcetreeapp.com/) provide.\n\nUsing \"sort\" references and unified component versions avoids creating brittle links between Orleans run-time and/or external components, and has proved highly effective in the last several years at reducing stress levels for the Orleans Team during important deployment milestones. :)\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "<Project>\n  <!-- Set the repository root into a variable -->\n  <PropertyGroup>\n    <SourceRoot>$(MSBuildThisFileDirectory)</SourceRoot>\n  </PropertyGroup>\n\n  <!-- Set common properties regarding assembly information and nuget packages -->\n  <PropertyGroup>\n    <Authors>Microsoft</Authors>\n    <Product>Microsoft Orleans</Product>\n    <Copyright>© Microsoft Corporation. All rights reserved.</Copyright>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <PackageProjectUrl>https://github.com/dotnet/orleans</PackageProjectUrl>\n    <PackageIcon>logo_128.png</PackageIcon>\n    <PackageTags>Orleans Cloud-Computing Actor-Model Actors Distributed-Systems C# .NET</PackageTags>\n    <PackageReleaseNotes></PackageReleaseNotes>\n    <PublicRepositoryUrl>https://github.com/dotnet/orleans</PublicRepositoryUrl>\n    <PrivateRepositoryUrl>$(RepositoryUrl)</PrivateRepositoryUrl>\n    <RepositoryUrl>$(RepositoryUrl)</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\n    <LangVersion>preview</LangVersion>\n    <Features>strict</Features>\n    <WarningLevel>3</WarningLevel>\n    <AnalysisLevel>preview</AnalysisLevel>\n    <!-- TODO: Uncomment this and fix errors -->\n    <!-- <AnalysisMode>All</AnalysisMode> -->\n    <!-- TODO: Uncomment this and fix errors -->\n    <!-- <Nullable>enable</Nullable> -->\n    <EmbedUntrackedSources>true</EmbedUntrackedSources>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n    <DebugType>embedded</DebugType>\n    <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>\n    <IncludeSymbols>false</IncludeSymbols>\n    <IncludeSource>false</IncludeSource>\n    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <!--<NoWarn>$(NoWarn);2003</NoWarn>-->\n    <!-- TODO: Disable and ensure all public members are documented: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs1591 -->\n    <NoWarn>$(NoWarn);1591</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TF_BUILD)' == 'true' or '$(GITHUB_ACTIONS)' == 'true'\">\n    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"$(SourceRoot)assets/logo_128.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"/\" />\n  </ItemGroup>\n\n  <!-- FSharp SDK overrides -->\n  <PropertyGroup>\n    <DisableImplicitSystemValueTupleReference>true</DisableImplicitSystemValueTupleReference>\n    <DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>\n  </PropertyGroup>\n\n  <!-- Versioning properties -->\n  <PropertyGroup>\n    <AssemblyVersion>10.0.0.0</AssemblyVersion>\n    <VersionPrefix Condition=\" '$(VersionPrefix)'=='' \">10.0.0</VersionPrefix>\n  </PropertyGroup>\n\n  <!-- For Debug builds generated a date/time dependent version suffix -->\n  <PropertyGroup Condition=\" '$(Configuration)'=='Debug' \">\n    <VersionSuffix Condition=\" '$(VersionSuffix)'=='' \">dev</VersionSuffix>\n    <VersionSuffix Condition=\" '$(VersionDateSuffix)'!='' \">$(VersionSuffix)-$(VersionDateSuffix)</VersionSuffix>\n  </PropertyGroup>\n\n  <Import Condition=\" '$(OrleansBuildTimeCodeGen)' == 'true' \" Project=\"$(MSBuildThisFileDirectory)src/Orleans.CodeGenerator/build/Microsoft.Orleans.CodeGenerator.props\" />\n\n  <!-- Set output folder for created NuGet packages -->\n  <PropertyGroup>\n    <PackageOutputPath Condition=\" '$(PackageOutputPath)'=='' \">$(SourceRoot)/Artifacts/$(Configuration)</PackageOutputPath>\n  </PropertyGroup>\n\n  <!-- Set output folder for distributed test apps -->\n  <PropertyGroup>\n    <DistributedTestsOutputPath Condition=\" '$(DistributedODistributedTestsOutputPathutputPath)'=='' \">$(SourceRoot)/Artifacts/DistributedTests</DistributedTestsOutputPath>\n  </PropertyGroup>\n\n  <Choose>\n    <When Condition=\"'$(OfficialBuild)' != 'true'\">\n      <!-- On non-official builds we don't burn in a git sha.  In large part because it\n           hurts our determinism efforts as binaries which should be the same between\n           builds will not (due to developers building against different HEAD\n           values -->\n      <PropertyGroup>\n        <GitHeadSha>&lt;developer build&gt;</GitHeadSha>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(BUILD_SOURCEVERSION)' != ''\">\n      <PropertyGroup>\n        <GitHeadSha>$(BUILD_SOURCEVERSION)</GitHeadSha>\n      </PropertyGroup>\n    </When>\n    <When Condition=\"'$(BUILD_SOURCEVERSION)' == '' AND '$(GIT_COMMIT)' != ''\">\n      <PropertyGroup>\n        <GitHeadSha>$(GIT_COMMIT)</GitHeadSha>\n      </PropertyGroup>\n    </When>\n    <Otherwise>\n      <PropertyGroup>\n        <GitHeadSha>Not found</GitHeadSha>\n        <DotGitDir>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory).git'))</DotGitDir>\n        <HeadFileContent Condition=\"Exists('$(DotGitDir)/HEAD')\">$([System.IO.File]::ReadAllText('$(DotGitDir)/HEAD').Trim())</HeadFileContent>\n        <RefPath Condition=\"$(HeadFileContent.StartsWith('ref: '))\">$(DotGitDir)/$(HeadFileContent.Substring(5))</RefPath>\n        <GitHeadSha Condition=\"'$(RefPath)' != '' AND Exists('$(RefPath)')\">$([System.IO.File]::ReadAllText('$(RefPath)').Trim())</GitHeadSha>\n        <GitHeadSha Condition=\"'$(HeadFileContent)' != '' AND '$(RefPath)' == ''\">$(HeadFileContent)</GitHeadSha>\n      </PropertyGroup>\n    </Otherwise>\n  </Choose>\n</Project>\n"
  },
  {
    "path": "Directory.Build.targets",
    "content": "<Project>\n  <!-- Set InformationVersion here, since $(Version) is already set at this point. -->\n  <PropertyGroup>\n    <InformationalVersion>$(Version). Commit Hash: $(GitHeadSha)</InformationalVersion>\n  </PropertyGroup>\n\n  <Import Condition=\" '$(OrleansBuildTimeCodeGen)' == 'true' \" Project=\"$(MSBuildThisFileDirectory)src/Orleans.CodeGenerator/build/Microsoft.Orleans.CodeGenerator.props\" />\n  <Import\n    Condition=\" '$(OrleansBuildTimeCodeGen)' == 'true' and '$(IsOrleansFrameworkPart)' != 'false' and '$(PackageId)' != 'Microsoft.Orleans.Core.Abstractions' \"\n    Project=\"$(MSBuildThisFileDirectory)src/Orleans.Core/build/Microsoft.Orleans.Core.targets\" />\n\n  <ItemGroup>\n    <!-- Enable code generator -->\n    <ProjectReference\n      Include=\"$(SourceRoot)src/Orleans.CodeGenerator/Orleans.CodeGenerator.csproj\"\n      OutputItemType=\"Analyzer\"\n      PrivateAssets=\"None\"\n      Condition=\" '$(OrleansBuildTimeCodeGen)' == 'true' \"/>\n    <ProjectReference\n      Include=\"$(SourceRoot)src/Orleans.Analyzers/Orleans.Analyzers.csproj\"\n      AssetTargetFallback=\"netstandard2.0\"\n      UndefineProperties=\"TargetFramework\"\n      SkipGetTargetFrameworkProperties=\"true\"\n      OutputItemType=\"Analyzer\"\n      PrivateAssets=\"None\"\n      Condition=\" '$(OrleansBuildTimeCodeGen)' == 'true' \"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Directory.Packages.props",
    "content": "<Project>\n  <PropertyGroup>\n    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>\n    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageVersion Include=\"Aspire.Azure.Storage.Queues\" Version=\"13.0.0\" />\n    <PackageVersion Include=\"Aspire.Hosting.AppHost\" Version=\"13.1.1\" />\n    <PackageVersion Include=\"Aspire.Hosting.Orleans\" Version=\"13.1.1\" />\n    <PackageVersion Include=\"Aspire.Hosting.Redis\" Version=\"13.1.1\" />\n    <PackageVersion Include=\"Aspire.StackExchange.Redis\" Version=\"13.1.1\" />\n    <PackageVersion Include=\"Autofac.Extensions.DependencyInjection\" Version=\"10.0.0\" />\n    <PackageVersion Include=\"AwesomeAssertions\" Version=\"9.3.0\" />\n    <PackageVersion Include=\"AWSSDK.DynamoDBv2\" Version=\"4.0.14\" />\n    <PackageVersion Include=\"AWSSDK.SQS\" Version=\"4.0.2.14\" />\n    <PackageVersion Include=\"Azure.Core\" Version=\"1.50.0\" />\n    <PackageVersion Include=\"Azure.Data.Tables\" Version=\"12.11.0\" />\n    <PackageVersion Include=\"Azure.Identity\" Version=\"1.17.1\" />\n    <PackageVersion Include=\"Azure.Messaging.EventHubs\" Version=\"5.12.2\" />\n    <PackageVersion Include=\"Azure.Security.KeyVault.Secrets\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Azure.Storage.Blobs\" Version=\"12.27.0\" />\n    <PackageVersion Include=\"Azure.Storage.Queues\" Version=\"12.25.0\" />\n    <PackageVersion Include=\"BenchmarkDotNet.Diagnostics.Windows\" Version=\"0.13.12\" />\n    <PackageVersion Include=\"BenchmarkDotNet\" Version=\"0.13.12\" />\n    <PackageVersion Include=\"CassandraCSharpDriver\" Version=\"3.22.0\" />\n    <PackageVersion Include=\"Consul\" Version=\"1.7.14.10\" />\n    <PackageVersion Include=\"coverlet.collector\" Version=\"6.0.4\" />\n    <PackageVersion Include=\"coverlet.msbuild\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"CsCheck\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"FSharp.Core\" Version=\"9.0.303\" />\n    <PackageVersion Include=\"Google.Cloud.PubSub.V1\" Version=\"1.0.0-beta13\" />\n    <PackageVersion Include=\"Google.Protobuf\" Version=\"3.33.5\" />\n    <PackageVersion Include=\"Grpc.Tools\" Version=\"2.78.0\" />\n    <PackageVersion Include=\"Hyperion\" Version=\"0.12.2\" />\n    <PackageVersion Include=\"KubernetesClient\" Version=\"18.0.13\" />\n    <PackageVersion Include=\"MemoryPack\" Version=\"1.21.4\" />\n    <PackageVersion Include=\"MessagePack\" Version=\"3.1.4\" />\n    <PackageVersion Include=\"Microsoft.AspNetCore.Connections.Abstractions\" Version=\"8.0.24\" />\n    <PackageVersion Include=\"Microsoft.Azure.Cosmos\" Version=\"3.57.0\" />\n    <PackageVersion Include=\"Microsoft.Build\" Version=\"17.10.4\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.Analyzers\" Version=\"3.11.0\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.Common\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing\" Version=\"1.1.2\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis.Workspaces.Common\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Microsoft.CodeAnalysis\" Version=\"4.5.0\" />\n    <PackageVersion Include=\"Microsoft.Crank.EventSources\" Version=\"0.2.0-alpha.23422.5\" />\n    <PackageVersion Include=\"Microsoft.CSharp\" Version=\"4.7.0\" />\n    <PackageVersion Include=\"Microsoft.Data.SqlClient\" Version=\"6.1.4\" />\n    <PackageVersion Include=\"Microsoft.Data.Sqlite\" Version=\"8.0.24\" />\n    <PackageVersion Include=\"Microsoft.DotNet.GenAPI.Task\" Version=\"9.0.103-servicing.25065.25\" />\n    <PackageVersion Include=\"Microsoft.DotNet.PlatformAbstractions\" Version=\"3.1.6\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.Abstractions\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.AzureKeyVault\" Version=\"3.1.24\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration.Json\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Configuration\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"8.0.2\" />\n    <PackageVersion Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.DependencyModel\" Version=\"8.0.2\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Diagnostics.Testing\" Version=\"8.10.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Hosting.Abstractions\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Hosting\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Http.Resilience\" Version=\"9.0.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Http\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"8.0.3\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging.Console\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging.Debug\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"Microsoft.Extensions.ObjectPool\" Version=\"8.0.24\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Options.ConfigurationExtensions\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.Options\" Version=\"8.0.2\" />\n    <PackageVersion Include=\"Microsoft.Extensions.ServiceDiscovery\" Version=\"10.3.0\" />\n    <PackageVersion Include=\"Microsoft.Extensions.TimeProvider.Testing\" Version=\"9.10.0\" />\n    <PackageVersion Include=\"Microsoft.NET.Test.Sdk\" Version=\"18.0.1\" />\n    <PackageVersion Include=\"Microsoft.NETFramework.ReferenceAssemblies\" Version=\"1.0.3\" />\n    <PackageVersion Include=\"Microsoft.SourceLink.AzureRepos.Git\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"Microsoft.SourceLink.GitHub\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"MySql.Data\" Version=\"8.0.31\" />\n    <PackageVersion Include=\"NATS.Net\" Version=\"2.7.2\" />\n    <PackageVersion Include=\"Newtonsoft.Json\" Version=\"13.0.4\" />\n    <PackageVersion Include=\"NodaTime\" Version=\"3.3.0\" />\n    <PackageVersion Include=\"Npgsql\" Version=\"8.0.8\" />\n    <PackageVersion Include=\"NSubstitute.Analyzers.CSharp\" Version=\"1.0.17\" />\n    <PackageVersion Include=\"NSubstitute\" Version=\"5.3.0\" />\n    <PackageVersion Include=\"OpenTelemetry\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"OpenTelemetry.Exporter.OpenTelemetryProtocol\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"OpenTelemetry.Extensions.Hosting\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"OpenTelemetry.Instrumentation.AspNetCore\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"OpenTelemetry.Instrumentation.Http\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"OpenTelemetry.Instrumentation.Runtime\" Version=\"1.9.0\" />\n    <PackageVersion Include=\"protobuf-net\" Version=\"3.2.56\" />\n    <PackageVersion Include=\"SpanJson\" Version=\"4.2.1\" />\n    <PackageVersion Include=\"SQLitePCLRaw.bundle_e_sqlite3\" Version=\"2.1.11\" />\n    <PackageVersion Include=\"StackExchange.Redis\" Version=\"2.11.0\" />\n    <PackageVersion Include=\"StructureMap.Microsoft.DependencyInjection\" Version=\"2.0.0\" />\n    <PackageVersion Include=\"System.CodeDom\" Version=\"10.0.3\" />\n    <PackageVersion Include=\"System.Collections.Immutable\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"System.CommandLine\" Version=\"2.0.0-beta1.21308.1\" />\n    <PackageVersion Include=\"System.Diagnostics.PerformanceCounter\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"System.Drawing.Common\" Version=\"8.0.24\" />\n    <PackageVersion Include=\"System.IO.Hashing\" Version=\"10.0.3\" NoWarn=\"NU5104\" />\n    <PackageVersion Include=\"System.IO.Pipelines\" Version=\"8.0.0\" />\n    <PackageVersion Include=\"System.Memory.Data\" Version=\"8.0.1\" />\n    <PackageVersion Include=\"System.Text.Json\" Version=\"8.0.5\" />\n    <PackageVersion Include=\"Testcontainers\" Version=\"4.10.0\" />\n    <PackageVersion Include=\"Testcontainers.Consul\" Version=\"4.10.0\" />\n    <PackageVersion Include=\"Utf8Json\" Version=\"1.3.7\" />\n    <PackageVersion Include=\"Verify.Xunit\" Version=\"29.5.0\" />\n    <PackageVersion Include=\"xunit.assert\" Version=\"2.9.3\" />\n    <PackageVersion Include=\"xunit.core\" Version=\"2.9.3\" />\n    <PackageVersion Include=\"xunit.extensibility.core\" Version=\"2.9.3\" />\n    <PackageVersion Include=\"xunit.extensibility.execution\" Version=\"2.9.3\" />\n    <PackageVersion Include=\"xunit.runner.visualstudio\" Version=\"3.1.5\" />\n    <PackageVersion Include=\"Xunit.SkippableFact\" Version=\"1.5.61\" />\n    <PackageVersion Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageVersion Include=\"ZeroFormatter\" Version=\"1.6.4\" />\n    <PackageVersion Include=\"ZooKeeperNetEx\" Version=\"3.4.12.4\" />\n  </ItemGroup>\n  <!-- Updates for later TFMs -->\n  <ItemGroup Condition=\" '$(TargetFramework)' == 'net10.0' \">\n    <PackageVersion Update=\"Aspire.Azure.Storage.Queues\" Version=\"13.1.1\" />\n    <PackageVersion Update=\"BenchmarkDotNet\" Version=\"0.15.6\" />\n    <PackageVersion Update=\"FSharp.Core\" Version=\"10.0.103\" />\n    <PackageVersion Update=\"Microsoft.AspNetCore.Connections.Abstractions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.CodeAnalysis.Common\" Version=\"5.0.0\" />\n    <PackageVersion Update=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"5.0.0\" />\n    <PackageVersion Update=\"Microsoft.CodeAnalysis.CSharp\" Version=\"5.0.0\" />\n    <PackageVersion Update=\"Microsoft.CodeAnalysis.Workspaces.Common\" Version=\"5.0.0\" />\n    <PackageVersion Update=\"Microsoft.CodeAnalysis\" Version=\"5.0.0\" />\n    <PackageVersion Update=\"Azure.Core\" Version=\"1.51.1\" />\n    <PackageVersion Update=\"Microsoft.Data.Sqlite\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Configuration.Abstractions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Configuration.Binder\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Configuration.Json\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Configuration\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.DependencyInjection\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.DependencyModel\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Diagnostics.Testing\" Version=\"10.3.0\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Hosting.Abstractions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Hosting\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Http\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Http.Resilience\" Version=\"10.3.0\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Logging.Console\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Logging.Debug\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Logging\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.ObjectPool\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Options.ConfigurationExtensions\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.Options\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"Microsoft.Extensions.TimeProvider.Testing\" Version=\"10.3.0\" />\n    <PackageVersion Update=\"OpenTelemetry\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"OpenTelemetry.Exporter.OpenTelemetryProtocol\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"OpenTelemetry.Extensions.Hosting\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"OpenTelemetry.Instrumentation.AspNetCore\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"OpenTelemetry.Instrumentation.Http\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"OpenTelemetry.Instrumentation.Runtime\" Version=\"1.15.0\" />\n    <PackageVersion Update=\"System.Collections.Immutable\" Version=\"10.0.0\" />\n    <PackageVersion Update=\"System.CommandLine\" Version=\"2.0.0-beta1.21308.1\" />\n    <PackageVersion Update=\"System.Diagnostics.PerformanceCounter\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"System.Drawing.Common\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"System.IO.Pipelines\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"System.Memory.Data\" Version=\"10.0.3\" />\n    <PackageVersion Update=\"System.Text.Json\" Version=\"10.0.0\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) .NET Foundation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "NuGet.Config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <!-- Feeds to use to restore dependent packages from -->\n    <add key=\"dotnet-public\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json\" />\n    <add key=\"dotnet-eng\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json\" />\n    <add key=\"dotnet9\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json\" />\n    <add key=\"dotnet9-transport\" value=\"https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet9-transport/nuget/v3/index.json\" />\n  </packageSources>\n  <packageSourceMapping>\n    <packageSource key=\"dotnet9-transport\">\n      <package pattern=\"*WorkloadBuildTasks*\" />\n    </packageSource>\n    <packageSource key=\"dotnet-public\">\n      <package pattern=\"*\" />\n    </packageSource>\n    <packageSource key=\"dotnet9\">\n      <package pattern=\"*\" />\n    </packageSource>\n    <packageSource key=\"dotnet-eng\">\n      <package pattern=\"*\" />\n    </packageSource>\n  </packageSourceMapping>\n  <disabledPackageSources>\n    <clear />\n  </disabledPackageSources>\n</configuration>\n"
  },
  {
    "path": "Orleans.slnx",
    "content": "<Solution>\n  <Folder Name=\"/playground/\">\n    <Project Path=\"playground/ActivationSheddingToy/ActivationSheddingToy.csproj\" />\n  </Folder>\n  <Folder Name=\"/playground/ActivationRebalancing/\">\n    <Project Path=\"playground/ActivationRebalancing/ActivationRebalancing.AppHost/ActivationRebalancing.AppHost.csproj\" />\n    <Project Path=\"playground/ActivationRebalancing/ActivationRebalancing.Cluster/ActivationRebalancing.Cluster.csproj\" />\n    <Project Path=\"playground/ActivationRebalancing/ActivationRebalancing.Frontend/ActivationRebalancing.Frontend.csproj\" />\n  </Folder>\n  <Folder Name=\"/playground/ActivationRepartitioning/\">\n    <Project Path=\"playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/ActivationRepartitioning.AppHost.csproj\" />\n    <Project Path=\"playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/ActivationRepartitioning.Frontend.csproj\" />\n  </Folder>\n  <Folder Name=\"/playground/ChaoticCluster/\">\n    <Project Path=\"playground/ChaoticCluster/ChaoticCluster.AppHost/ChaoticCluster.AppHost.csproj\" />\n    <Project Path=\"playground/ChaoticCluster/ChaoticCluster.ServiceDefaults/ChaoticCluster.ServiceDefaults.csproj\" />\n    <Project Path=\"playground/ChaoticCluster/ChaoticCluster.Silo/ChaoticCluster.Silo.csproj\" />\n  </Folder>\n  <Folder Name=\"/playground/Dashboard/\">\n    <Project Path=\"playground/DashboardCohosted/DashboardCohosted.csproj\" />\n    <Project Path=\"playground/DashboardSeparateHost/DashboardSeparateHost.csproj\" />\n  </Folder>\n  <Folder Name=\"/Solution Items/\">\n    <File Path=\".editorconfig\" />\n    <File Path=\"Directory.Build.props\" />\n    <File Path=\"Directory.Build.targets\" />\n    <File Path=\"Directory.Packages.props\" />\n  </Folder>\n  <Folder Name=\"/src/\">\n    <Project Path=\"src/Orleans.Analyzers/Orleans.Analyzers.csproj\" />\n    <Project Path=\"src/Orleans.BroadcastChannel/Orleans.BroadcastChannel.csproj\" />\n    <Project Path=\"src/Orleans.Client/Orleans.Client.csproj\" />\n    <Project Path=\"src/Orleans.CodeGenerator/Orleans.CodeGenerator.csproj\" />\n    <Project Path=\"src/Orleans.Core.Abstractions/Orleans.Core.Abstractions.csproj\" />\n    <Project Path=\"src/Orleans.Core/Orleans.Core.csproj\" />\n    <Project Path=\"src/Orleans.EventSourcing/Orleans.EventSourcing.csproj\" />\n    <Project Path=\"src/Orleans.Journaling/Orleans.Journaling.csproj\" />\n    <Project Path=\"src/Orleans.Persistence.Memory/Orleans.Persistence.Memory.csproj\" />\n    <Project Path=\"src/Orleans.Reminders/Orleans.Reminders.csproj\" />\n    <Project Path=\"src/Orleans.Runtime/Orleans.Runtime.csproj\" />\n    <Project Path=\"src/Orleans.DurableJobs/Orleans.DurableJobs.csproj\" Id=\"ab4cc723-b3cf-4c32-be4c-1a180a49797c\" />\n    <Project Path=\"src/Orleans.Sdk/Orleans.Sdk.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.FSharp/Orleans.Serialization.FSharp.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.MessagePack/Orleans.Serialization.MessagePack.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.NewtonsoftJson/Orleans.Serialization.NewtonsoftJson.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.SystemTextJson/Orleans.Serialization.SystemTextJson.csproj\" />\n    <Project Path=\"src/Orleans.Serialization.TestKit/Orleans.Serialization.TestKit.csproj\" />\n    <Project Path=\"src/Orleans.Serialization/Orleans.Serialization.csproj\" />\n    <Project Path=\"src/Orleans.Server/Orleans.Server.csproj\" />\n    <Project Path=\"src/Orleans.Streaming/Orleans.Streaming.csproj\" />\n    <Project Path=\"src/Orleans.TestingHost/Orleans.TestingHost.csproj\" />\n    <Project Path=\"src/Serializers/Orleans.Serialization.Protobuf/Orleans.Serialization.Protobuf.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Dashboard/\">\n    <Project Path=\"src/Dashboard/Orleans.Dashboard.Abstractions/Orleans.Dashboard.Abstractions.csproj\" />\n    <Project Path=\"src/Dashboard/Orleans.Dashboard/Orleans.Dashboard.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/\">\n    <Project Path=\"src/Orleans.Clustering.Consul/Orleans.Clustering.Consul.csproj\" />\n    <Project Path=\"src/Orleans.Clustering.ZooKeeper/Orleans.Clustering.ZooKeeper.csproj\" />\n    <Project Path=\"src/Orleans.Connections.Security/Orleans.Connections.Security.csproj\" />\n    <Project Path=\"src/Orleans.Hosting.Kubernetes/Orleans.Hosting.Kubernetes.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/AdoNet/\">\n    <Project Path=\"src/AdoNet/Orleans.Clustering.AdoNet/Orleans.Clustering.AdoNet.csproj\" />\n    <Project Path=\"src/AdoNet/Orleans.GrainDirectory.AdoNet/Orleans.GrainDirectory.AdoNet.csproj\" />\n    <Project Path=\"src/AdoNet/Orleans.Persistence.AdoNet/Orleans.Persistence.AdoNet.csproj\" />\n    <Project Path=\"src/AdoNet/Orleans.Reminders.AdoNet/Orleans.Reminders.AdoNet.csproj\" />\n    <Project Path=\"src/AdoNet/Orleans.Streaming.AdoNet/Orleans.Streaming.AdoNet.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/AWS/\">\n    <Project Path=\"src/AWS/Orleans.Clustering.DynamoDB/Orleans.Clustering.DynamoDB.csproj\" />\n    <Project Path=\"src/AWS/Orleans.Persistence.DynamoDB/Orleans.Persistence.DynamoDB.csproj\" />\n    <Project Path=\"src/AWS/Orleans.Reminders.DynamoDB/Orleans.Reminders.DynamoDB.csproj\" />\n    <Project Path=\"src/AWS/Orleans.Streaming.SQS/Orleans.Streaming.SQS.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/Azure/\">\n    <Project Path=\"src/Azure/Orleans.Clustering.AzureStorage/Orleans.Clustering.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Clustering.Cosmos/Orleans.Clustering.Cosmos.csproj\" />\n    <Project Path=\"src/Azure/Orleans.GrainDirectory.AzureStorage/Orleans.GrainDirectory.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Journaling.AzureStorage/Orleans.Journaling.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Persistence.AzureStorage/Orleans.Persistence.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Persistence.Cosmos/Orleans.Persistence.Cosmos.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Reminders.AzureStorage/Orleans.Reminders.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Reminders.Cosmos/Orleans.Reminders.Cosmos.csproj\" />\n    <Project Path=\"src/Azure/Orleans.DurableJobs.AzureStorage/Orleans.DurableJobs.AzureStorage.csproj\" Id=\"5bbb1058-9ab2-44e9-b237-49f5b6bee151\" />\n    <Project Path=\"src/Azure/Orleans.Streaming.AzureStorage/Orleans.Streaming.AzureStorage.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Streaming.EventHubs/Orleans.Streaming.EventHubs.csproj\" />\n    <Project Path=\"src/Azure/Orleans.Transactions.AzureStorage/Orleans.Transactions.AzureStorage.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/Cassandra/\">\n    <Project Path=\"src/Cassandra/Orleans.Clustering.Cassandra/Orleans.Clustering.Cassandra.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/NATS/\">\n    <Project Path=\"src\\Orleans.Streaming.NATS\\Orleans.Streaming.NATS.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Extensions/Redis/\">\n    <Project Path=\"src/Redis/Orleans.Clustering.Redis/Orleans.Clustering.Redis.csproj\" />\n    <Project Path=\"src/Redis/Orleans.GrainDirectory.Redis/Orleans.GrainDirectory.Redis.csproj\" />\n    <Project Path=\"src/Redis/Orleans.Persistence.Redis/Orleans.Persistence.Redis.csproj\" />\n    <Project Path=\"src/Redis/Orleans.Reminders.Redis/Orleans.Reminders.Redis.csproj\" />\n  </Folder>\n  <Folder Name=\"/src/Transactions/\">\n    <Project Path=\"src/Orleans.Transactions.TestKit.Base/Orleans.Transactions.TestKit.Base.csproj\" />\n    <Project Path=\"src/Orleans.Transactions.TestKit.xUnit/Orleans.Transactions.TestKit.xUnit.csproj\" />\n    <Project Path=\"src/Orleans.Transactions/Orleans.Transactions.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/\">\n    <Project Path=\"test/Orleans.Analyzers.Tests/Orleans.Analyzers.Tests.csproj\" />\n    <Project Path=\"test/Orleans.DefaultCluster.Tests/Orleans.DefaultCluster.Tests.csproj\" />\n    <Project Path=\"test/Orleans.DependencyInjection.Tests/Orleans.DependencyInjection.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Core.Tests/Orleans.Core.Tests.csproj\" />\n    <Project Path=\"test/Orleans.CodeGenerator.Tests/Orleans.CodeGenerator.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Connections.Security.Tests/Orleans.Connections.Security.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Journaling.Tests/Orleans.Journaling.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj\" />\n    <Project Path=\"test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj\" />\n    <Project Path=\"test/Orleans.Runtime.Tests/Orleans.Runtime.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Runtime.Internal.Tests/Orleans.Runtime.Internal.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Placement.Tests/Orleans.Placement.Tests.csproj\" />\n    <Project Path=\"test/Orleans.GrainDirectory.Tests/Orleans.GrainDirectory.Tests.csproj\" />\n    <Project Path=\"test/Orleans.Streaming.Tests/Orleans.Streaming.Tests.csproj\" />\n    <Project Path=\"test/Orleans.EventSourcing.Tests/Orleans.EventSourcing.Tests.csproj\" />\n    <Project Path=\"test/Orleans.DurableJobs.Tests/Orleans.DurableJobs.Tests.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Dashboard/\">\n    <Project Path=\"test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/Orleans.Dashboard.TestGrains.csproj\" />\n    <Project Path=\"test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/Orleans.Dashboard.UnitTests.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Benchmarks/\">\n    <Project Path=\"test/Benchmarks.AdoNet/Benchmarks.AdoNet.csproj\" />\n    <Project Path=\"test/Benchmarks/Benchmarks.csproj\" />\n    <Project Path=\"test/Grains/BenchmarkGrainInterfaces/BenchmarkGrainInterfaces.csproj\" />\n    <Project Path=\"test/Grains/BenchmarkGrains/BenchmarkGrains.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/DistributedTests/\">\n    <File Path=\"test/DistributedTests/README.md\" />\n    <Project Path=\"test/DistributedTests/DistributedTests.Client/DistributedTests.Client.csproj\" />\n    <Project Path=\"test/DistributedTests/DistributedTests.Common/DistributedTests.Common.csproj\" />\n    <Project Path=\"test/DistributedTests/DistributedTests.Grains/DistributedTests.Grains.csproj\" />\n    <Project Path=\"test/DistributedTests/DistributedTests.Server/DistributedTests.Server.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Extensions/\">\n    <Project Path=\"test/Extensions/Orleans.AWS.Tests/Orleans.AWS.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Clustering.Consul.Tests/Orleans.Clustering.Consul.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Streaming.EventHubs.Tests/Orleans.Streaming.EventHubs.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Clustering.Cassandra.Tests/Orleans.Clustering.Cassandra.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Cosmos.Tests/Orleans.Cosmos.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Redis.Tests/Orleans.Redis.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.AdoNet.Tests/Orleans.AdoNet.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Azure.Tests/Orleans.Azure.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Clustering.ZooKeeper.Tests/Orleans.Clustering.ZooKeeper.Tests.csproj\" />\n    <Project Path=\"test/Extensions/Orleans.Streaming.NATS.Tests/Orleans.Streaming.NATS.Tests.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Grains/\">\n    <Project Path=\"test/Grains/TestFSharp/TestFSharp.fsproj\" />\n    <Project Path=\"test/Grains/TestFSharpGrainInterfaces/TestFSharpGrainInterfaces.csproj\" />\n    <Project Path=\"test/Grains/TestFSharpGrainInterfaces/FSharpInterfaces/TestFSharpInterfaces.fsproj\" />\n    <Project Path=\"test/Grains/TestGrainInterfaces/TestGrainInterfaces.csproj\" />\n    <Project Path=\"test/Grains/TestGrains/TestGrains.csproj\" />\n    <Project Path=\"test/Grains/TestInternalGrainInterfaces/TestInternalGrainInterfaces.csproj\" />\n    <Project Path=\"test/Grains/TestInternalGrains/TestInternalGrains.csproj\" />\n    <Project Path=\"test/Grains/TestVersionGrains/TestVersionGrains.csproj\" />\n    <Project Path=\"test/Grains/TestVersionGrains2/TestVersionGrains2.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Misc/\">\n    <Project Path=\"test/Misc/TestSerializerExternalModels/TestSerializerExternalModels.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/TestInfrastructure/\">\n    <Project Path=\"test/TestInfrastructure/Orleans.TestingHost.Tests/Orleans.TestingHost.Tests.csproj\" />\n    <Project Path=\"test/TestInfrastructure/TestExtensions/TestExtensions.csproj\" />\n  </Folder>\n  <Folder Name=\"/test/Transactions/\">\n    <Project Path=\"test/Transactions/Orleans.Transactions.Azure.Test/Orleans.Transactions.Azure.Test.csproj\" />\n    <Project Path=\"test/Transactions/Orleans.Transactions.Tests/Orleans.Transactions.Tests.csproj\" />\n  </Folder>\n</Solution>\n"
  },
  {
    "path": "Parallel-Tests.ps1",
    "content": "param(\n    [string[]] $directories,\n    [string] $testFilter = $null)\n\n. .\\common.ps1\n\nInstall-Dotnet\n\n$maxDegreeOfParallelism = [math]::min($env:NUMBER_OF_PROCESSORS, 4)\nWrite-Host \"Max Job Parallelism = $maxDegreeOfParallelism\"\n\n$failed = $false\n\nif(\n    [Console]::InputEncoding -is [Text.UTF8Encoding] -and\n    [Console]::InputEncoding.GetPreamble().Length -ne 0\n) {\n    Write-Host Setting [Console]::InputEncoding\n    [Console]::InputEncoding = New-Object Text.UTF8Encoding $false\n}\nelse\n{\n    Write-Host Not changing [Console]::InputEncoding\n}\n\nif ([string]::IsNullOrWhiteSpace($testFilter)) {\n    $testFilter = $env:TEST_FILTERS;\n}\n\nif ([string]::IsNullOrWhiteSpace($testFilter)) {\n    $testFilter = \"Category=BVT|Category=SlowBVT\";\n}\n\nWrite-Host \"Test filters: `\"$testFilter`\"\";\n\nfunction Receive-CompletedJobs {\n    $succeeded = $true\n    foreach($job in (Get-Job | Where-Object { $_.State -ne 'Running' }))\n    {\n        Receive-Job $job -AutoRemoveJob -Wait | Write-Host\n\n        if ($job.State -eq 'Failed') {\n            $succeeded = $false\n            Write-Host -ForegroundColor Red 'Failed: ' $job.Name '('$job.State')'\n        }\n        Write-Host ''\n    }\n    return $succeeded\n}\n\n$ExecuteCmd =\n{\n    param([string] $args1, [string] $path)\n\n    Set-Location -Path \"$path\"\n\n    $cmdline = \"& dotnet \" + $args1\n\n    Invoke-Expression $cmdline;\n    $cmdExitCode = $LASTEXITCODE;\n    if ($cmdExitCode -ne 0)\n    {\n        Throw \"Error when running tests. Command: `\"$cmdline`\". Exit Code: $cmdExitCode\"\n    }\n    else\n    {\n        Write-Host \"Tests completed. Command: `\"$cmdline`\"\"\n    }\n}\n\nforeach ($d in $directories)\n{\n    $running = @(Get-Job | Where-Object { $_.State -eq 'Running' })\n    if ($running.Count -ge $maxDegreeOfParallelism) {\n        $running | Wait-Job -Any | Out-Null\n    }\n\n    if (-not (Receive-CompletedJobs)) { $failed = $true }\n\n    if (-not $testFilter.StartsWith('\"')) { $testFilter = \"`\"$testFilter\"; }\n    if (-not $testFilter.EndsWith('\"')) { $testFilter = \"$testFilter`\"\"; }\n\n    $jobName = $([System.IO.Path]::GetFileName($d))\n    $cmdLine = 'test --blame-hang-timeout 10m --no-build --configuration \"' + $env:BuildConfiguration + '\" --filter ' + $testFilter + ' --logger \"trx\" -- -parallel none -noshadow'\n    Write-Host $jobName dotnet $cmdLine\n    Start-Job $ExecuteCmd -ArgumentList @($cmdLine, \"$d\") -Name $jobName | Out-Null\n    Write-Host ''\n}\n\n# Wait for all jobs to complete and results ready to be received\nWait-Job * | Out-Null\n\nif (-not (Receive-CompletedJobs)) { $failed = $true }\n\nif ($failed)\n{\n    Write-Host 'Test run failed'\n    Exit 1\n}\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <image src=\"https://raw.githubusercontent.com/dotnet/orleans/gh-pages/assets/logo_full.png\" alt=\"Orleans logo\" width=\"600px\">\n</p>\n\n[![NuGet](https://img.shields.io/nuget/v/Microsoft.Orleans.Core.svg?style=flat)](http://www.nuget.org/profiles/Orleans)\n[![Follow on Twitter](https://img.shields.io/twitter/follow/msftorleans.svg?style=social&logo=twitter)](https://twitter.com/intent/follow?screen_name=msftorleans)\n\n[![Discord](https://discordapp.com/api/guilds/333727978460676096/widget.png?style=banner2)](https://aka.ms/orleans-discord)\n\n### Orleans is a cross-platform framework for building robust, scalable distributed applications\n\nOrleans builds on the developer productivity of .NET and brings it to the world of distributed applications, such as cloud services. Orleans scales from a single on-premises server to globally distributed, highly-available applications in the cloud.\n\nOrleans takes familiar concepts like objects, interfaces, async/await, and try/catch and extends them to multi-server environments. As such, it helps developers experienced with single-server applications transition to building resilient, scalable cloud services and other distributed applications. For this reason, Orleans has often been referred to as \"Distributed .NET\".\n\nIt was created by [Microsoft Research](http://research.microsoft.com/projects/orleans/) and introduced the [Virtual Actor Model](https://www.microsoft.com/en-us/research/publication/orleans-distributed-virtual-actors-for-programmability-and-scalability/) as a novel approach to building a new generation of distributed systems for the Cloud era. The core contribution of Orleans is its programming model which tames the complexity inherent to highly-parallel distributed systems without restricting capabilities or imposing onerous constraints on the developer.\n\n## Grains\n\n![A grain is composed of a stable identity, behavior, and state](assets/grain_formulation.svg)\n\nThe fundamental building block in any Orleans application is a *grain*. Grains are entities comprising user-defined identity, behavior, and state. Grain identities are user-defined keys which make Grains always available for invocation. Grains can be invoked by other grains or by external clients such as Web frontends, via strongly-typed communication interfaces (contracts). Each grain is an instance of a class which implements one or more of these interfaces.\n\nGrains can have volatile and/or persistent state that can be stored in any storage system. As such, grains implicitly partition application state, enabling automatic scalability and simplifying recovery from failures. Grain state is kept in memory while the grain is active, leading to lower latency and less load on data stores.\n\n<p align=\"center\">\n  <image src=\"assets/managed_lifecycle.svg\" alt=\"A diagram showing the managed lifecycle of a grain\">\n</p>\n\nInstantiation of grains is automatically performed on demand by the Orleans runtime. Grains which are not used for a while are automatically removed from memory to free up resources. This is possible because of their stable identity, which allows invoking grains whether they are already loaded into memory or not. This also allows for transparent recovery from failure because the caller does not need to know on which server a grain is instantiated on at any point in time. Grains have a managed lifecycle, with the Orleans runtime responsible for activating/deactivating, and placing/locating grains as needed. This allows the developer to write code as if all grains were always in-memory.\n\nTaken together, the stable identity, statefulness, and managed lifecycle of Grains are core factors that make systems built on Orleans scalable, performant, &amp; reliable without forcing developers to write complex distributed systems code.\n\n### Example: IoT cloud backend\n\nConsider a cloud backend for an [Internet of Things](https://en.wikipedia.org/wiki/Internet_of_things) system. This application needs to process incoming device data, filter, aggregate, and process this information, and enable sending commands to devices. In Orleans, it is natural to model each device with a grain which becomes a *digital twin* of the physical device it corresponds to. These grains keep the latest device data in memory, so that they can be quickly queried and processed without the need to communicate with the physical device directly. By observing streams of time-series data from the device, the grain can detect changes in conditions, such as measurements exceeding a threshold, and trigger an action.\n\nA simple thermostat could be modeled as follows:\n\n```csharp\npublic interface IThermostat : IGrainWithStringKey\n{\n    Task<List<Command>> OnUpdate(ThermostatStatus update);\n}\n```\n\nEvents arriving from the thermostat from a Web frontend can be sent to its grain by invoking the `OnUpdate` method which optionally returns a command back to the device.\n\n```csharp\nvar thermostat = client.GetGrain<IThermostat>(id);\nreturn await thermostat.OnUpdate(update);\n```\n\nThe same thermostat grain can implement a separate interface for control systems to interact with:\n\n```csharp\npublic interface IThermostatControl : IGrainWithStringKey\n{\n    Task<ThermostatStatus> GetStatus();\n\n    Task UpdateConfiguration(ThermostatConfiguration config);\n}\n```\n\nThese two interfaces (`IThermostat` and `IThermostatControl`) are implemented by a single implementation class:\n\n```csharp\npublic class ThermostatGrain : Grain, IThermostat, IThermostatControl\n{\n    private ThermostatStatus _status;\n    private List<Command> _commands;\n\n    public Task<List<Command>> OnUpdate(ThermostatStatus status)\n    {\n        _status = status;\n        var result = _commands;\n        _commands = new List<Command>();\n        return Task.FromResult(result);\n    }\n    \n    public Task<ThermostatStatus> GetStatus() => Task.FromResult(_status);\n    \n    public Task UpdateConfiguration(ThermostatConfiguration config)\n    {\n        _commands.Add(new ConfigUpdateCommand(config));\n        return Task.CompletedTask;\n    }\n}\n```\n\nThe `Grain` class above does not persist its state. A more thorough example demonstrating state persistence is available in the docs, for more information see [Microsoft Orleans: Grain Persistence](https://docs.microsoft.com/dotnet/orleans/grains/grain-persistence).\n\n## Orleans runtime\n\nThe Orleans runtime is what implements the programming model for applications. The main component of the runtime is the *silo*, which is responsible for hosting grains. Typically, a group of silos run as a cluster for scalability and fault-tolerance. When run as a cluster, silos coordinate with each other to distribute work, detect and recover from failures. The runtime enables grains hosted in the cluster to communicate with each other as if they are within a single process.\n\nIn addition to the core programming model, the silo provides grains with a set of runtime services, such as timers, reminders (persistent timers), persistence, transactions, streams, and more. See the [features section](#features) below for more detail.\n\nWeb frontends and other external clients call grains in the cluster using the client library which automatically manages network communication. Clients can also be co-hosted in the same process with silos for simplicity.\n\nOrleans is compatible with .NET Standard 2.0 and above, running on Windows, Linux, and macOS, in full .NET Framework or .NET Core.\n\n## Features\n\nOrleans is a feature-rich framework. It provides a set of services that enable the development of distributed systems. The following sections describe the features of Orleans.\n\n### Persistence\n\nOrleans provides a simple persistence model which ensures that state is available to a grain before requests are processed and that consistency is maintained. Grains can have multiple named persistent data objects, for example, one called \"profile\" for a user's profile and one called \"inventory\" for their inventory. This state can be stored in any storage system. For example, profile data may be stored in one database and inventory in another. While a grain is running, this state is kept in memory so that read requests can be served without accessing storage. When the grain updates its state, a `state.WriteStateAsync()` call ensures that the backing store is updated for durability and consistency. For more information see [Microsoft Orleans: Grain Persistence](https://docs.microsoft.com/dotnet/orleans/grains/grain-persistence).\n\n### Distributed ACID transactions\n\nIn addition to the simple persistence model described above, grains can have *transactional state*. Multiple grains can participate in [ACID](https://en.wikipedia.org/wiki/ACID) transactions together regardless of where their state is ultimately stored. Transactions in Orleans are distributed and decentralized (there is no central transaction manager or transaction coordinator) and have [serializable isolation](https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels). For more information, see the [Microsoft Orleans: Transactions](https://docs.microsoft.com/dotnet/orleans/grains/transactions).\n\n### Streams\n\nStreams help developers to process series of data items in near-real time. Streams in Orleans are *managed*: streams do not need to be created or registered before a grain or client publishes to a stream or subscribes to a stream. This allows for greater decoupling of stream producers and consumers from each other and from the infrastructure. Stream processing is reliable: grains can store checkpoints (cursors) and reset to a stored checkpoint during activation or at any point afterwards.\n\nStreams supports batch delivery of messages to consumers to improve efficiency and recovery performance.\nStreams are backed by queueing services such as Azure Event Hubs, Amazon Kinesis, and others. An arbitrary number of streams can be multiplexed onto a smaller number of queues and the responsibility for processing these queues is balanced evenly across the cluster.\n\n### Timers &amp; reminders\n\nReminders are a durable scheduling mechanism for grains. They can be used to ensure that some action is completed at a future point even if the grain is not currently activated at that time. Timers are the non-durable counterpart to reminders and can be used for high-frequency events which do not require reliability. For more information, see [Microsoft Orleans: Timers and reminders](https://docs.microsoft.com/dotnet/orleans/grains/timers-and-reminders).\n\n### Flexible grain placement\n\nWhen a grain is activated in Orleans, the runtime decides which server (silo) to activate that grain on. This is called grain placement. The placement process in Orleans is fully configurable: developers can choose from a set of out-of-the-box placement policies such as random, prefer-local, and load-based, or custom logic can be configured. This allows for full flexibility in deciding where grains are created. For example, grains can be placed on a server close to resources which they need to operate on or other grains which they communicate with.\n\n### Grain versioning &amp; heterogeneous clusters\n\nApplication code evolves over time and upgrading live, production systems in a manner which safely accounts for these changes can be challenging, particularly in stateful systems. Grain interfaces in Orleans can be optionally versioned. The cluster maintains a mapping of which grain implementations are available on which silos in the cluster and the versions of those implementations. This version information is used by the runtime in conjunction with placement strategies to make placement decisions when routing calls to grains. In addition to safe update of versioned grains, this also enables heterogeneous clusters, where different silos have different sets of grain implementations available. For more information, see [Microsoft Orleans: Grain interface versioning](https://docs.microsoft.com/dotnet/orleans/grains/grain-versioning/grain-versioning).\n\n### Elastic scalability &amp; fault tolerance\n\nOrleans is designed to scale elastically. When a silo joins a cluster it is able to accept new activations and when a silo leaves the cluster (either because of scale down or a machine failure) the grains which were activated on that silo will be re-activated on remaining silos as needed. An Orleans cluster can be scaled down to a single silo. The same properties which enable elastic scalability also enable fault tolerance: the cluster automatically detects and quickly recovers from failures.\n\n### Run anywhere\n\nOrleans runs anywhere that .NET Core or .NET Framework are supported. This includes hosting on Linux, Windows, and macOS and deploying to Kubernetes, virtual or physical machines, on premises or in the cloud, and PaaS services such as Azure Container Apps, Azure App Service, and Azure Kubernetes Service.\n\n### Stateless workers\n\nStateless workers are specially marked grains which do not have any associated state and can be activated on multiple silos simultaneously. This enables increased parallelism for stateless functions. For more information, see [Microsoft Orleans: Stateless worker grains](https://docs.microsoft.com/dotnet/orleans/grains/stateless-worker-grains) documentation.\n\n### Grain call filters\n\nLogic which is common to many grains can be expressed as [an interceptor, or Grain call filter](https://docs.microsoft.com/dotnet/orleans/grains/interceptors). Orleans supports filters for both incoming and outgoing calls. Some common use-cases of filters are: authorization, logging and telemetry, and error handling.\n\n### Request context\n\nMetadata and other information can be passed along a series of requests using [request context](https://docs.microsoft.com/dotnet/orleans/grains/request-context). Request context can be used for holding distributed tracing information or any other user-defined values.\n\n## Documentation\n\nThe official documentation for Microsoft Orleans is available at <https://docs.microsoft.com/dotnet/orleans>.\n\n## [Samples](./samples/#readme)\n\nA variety of samples are available in the official [.NET Samples Browser](https://docs.microsoft.com/samples/browse/?terms=orleans).\n\n## Get started\n\nPlease see the [getting started tutorial](https://docs.microsoft.com/dotnet/orleans/tutorials-and-samples/tutorial-1).\n\n### Building\n\nOn Windows, run the `build.cmd` script to build the NuGet packages locally, then reference the required NuGet packages from `/Artifacts/Release/*`.\nYou can run `Test.cmd` to run all BVT tests, and `TestAll.cmd` to also run Functional tests.\n\nOn Linux and macOS, run `dotnet build` to build Orleans.\n\n## Official builds\n\nThe latest stable, production-quality release is located [here](https://github.com/dotnet/orleans/releases/latest).\n\nNightly builds are published to [a NuGet feed](https://pkgs.dev.azure.com/dnceng/public/_packaging/orleans-nightly/nuget/v3/index.json). These builds pass all functional tests, but are not thoroughly tested as the stable builds or pre-release builds published to NuGet.\n\n<details>\n<summary>\nUsing the nightly build packages in your project\n</summary>\n\nTo use nightly builds in your project, add the MyGet feed using either of the following methods:\n\n1. Changing the .csproj file to include this section:\n\n```xml\n<ItemGroup>\n  <RestoreSources>\n    $(RestoreSources);\n    https://pkgs.dev.azure.com/dnceng/public/_packaging/orleans-nightly/nuget/v3/index.json\n  </RestoreSources>\n</ItemGroup>\n```\n\nor\n\n1. Creating a `NuGet.config` file in the solution directory with the following contents:\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear /> \n    <add key=\"orleans-nightly\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/orleans-nightly/nuget/v3/index.json\" />\n    <add key=\"nuget\" value=\"https://api.nuget.org/v3/index.json\" />\n  </packageSources>\n</configuration>\n```\n\n</details>\n\n## Community\n\n[![Discord](https://discordapp.com/api/guilds/333727978460676096/widget.png?style=banner4)](https://aka.ms/orleans-discord)\n    \n* Ask questions by [opening an issue on GitHub](https://github.com/dotnet/orleans/issues) or on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=orleans)\n* [Chat on Discord](https://aka.ms/orleans-discord)\n* Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements.\n* [OrleansContrib - GitHub organization for community add-ons to Orleans](https://github.com/OrleansContrib/) Various community projects, including Monitoring, Design Patterns, Storage Providers, etc.\n* Guidelines for developers wanting to [contribute code changes to Orleans](CONTRIBUTING.md).\n* You are also encouraged to report bugs or start a technical discussion by starting a new [thread](https://github.com/dotnet/orleans/issues) on GitHub.\n\n## License\n\nThis project is licensed under the [MIT license](LICENSE).\n\n## Quick links\n\n* [Microsoft Research project home](http://research.microsoft.com/projects/orleans/)\n* Technical Report: [Distributed Virtual Actors for Programmability and Scalability](http://research.microsoft.com/apps/pubs/default.aspx?id=210931)\n* [Microsoft Orleans: Documentation](https://docs.microsoft.com/dotnet/orleans/)\n* [Contributing](CONTRIBUTING.md)\n"
  },
  {
    "path": "SUPPORT.md",
    "content": "# Support\n\n## How to file issues and get help  \n\nThis project uses GitHub [Issues](https://github.com/dotnet/orleans/issues) to track bugs and feature requests. Please search the existing \nissues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a [new Issue](https://github.com/dotnet/orleans/issues/new).\n\n## Community\n\nThe Orleans community enjoys a lively discussion on our [Discord server](https://aka.ms/orleans-discord), and in the Issues customers file here on GitHub. If you would like to engage with our active, friendly community, use one of the links below to find someone who can help. \n\n[![Discord](https://discordapp.com/api/guilds/333727978460676096/widget.png?style=banner4)](https://aka.ms/orleans-discord)\n    \n* Ask questions by [opening an issue on GitHub](https://github.com/dotnet/orleans/issues) or on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=orleans)\n* [Chat on Discord](https://aka.ms/orleans-discord)\n* Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements.\n* [OrleansContrib - GitHub organization for community add-ons to Orleans](https://github.com/OrleansContrib/) Various community projects, including Monitoring, Design Patterns, Storage Providers, etc.\n* Guidelines for developers wanting to [contribute code changes to Orleans](CONTRIBUTING.md).\n* You are also encouraged to report bugs or start a technical discussion by starting a new [thread](https://github.com/dotnet/orleans/issues) on GitHub.\n\n## Microsoft Support Policy  \n\nOrleans is officially supported by Microsoft. Customers with support contracts can create support tickets via https://aka.ms/orleanssupport. Orleans is listed under ASP.NET Core:\n![image](https://github.com/dotnet/orleans/assets/203839/30b02291-06a1-4364-9e1c-9a06209c386d)\n"
  },
  {
    "path": "Test.cmd",
    "content": "@if not defined _echo @echo off\nsetlocal\n\nif not defined BuildConfiguration SET BuildConfiguration=Debug\n\nSET CMDHOME=%~dp0\n@REM Remove trailing backslash \\\nset CMDHOME=%CMDHOME:~0,-1%\n\n:: Clear the 'Platform' env variable for this session, as it's a per-project setting within the build, and\n:: misleading value (such as 'MCD' in HP PCs) may lead to build breakage (issue: #69).\nset Platform=\n\n:: Disable multilevel lookup https://github.com/dotnet/core-setup/blob/main/Documentation/design-docs/multilevel-sharedfx-lookup.md\nset DOTNET_MULTILEVEL_LOOKUP=0\n\npushd \"%CMDHOME%\"\n@cd\n\nSET TestResultDir=%CMDHOME%\\Binaries\\%BuildConfiguration%\\TestResults\n\nif not exist %TestResultDir% md %TestResultDir%\n\nSET _Directory=bin\\%BuildConfiguration%\\net461\\win10-x64\n\nset TESTS=^\n'%CMDHOME%\\test\\Extensions\\TesterAzureUtils',^\n'%CMDHOME%\\test\\TesterInternal',^\n'%CMDHOME%\\test\\Tester',^\n'%CMDHOME%\\test\\DefaultCluster.Tests',^\n'%CMDHOME%\\test\\NonSilo.Tests',^\n'%CMDHOME%\\test\\Extensions\\AWSUtils.Tests',^\n'%CMDHOME%\\test\\Extensions\\Consul.Tests',^\n'%CMDHOME%\\test\\Extensions\\ServiceBus.Tests',^\n'%CMDHOME%\\test\\Extensions\\TesterAdoNet',^\n'%CMDHOME%\\test\\Extensions\\TesterZooKeeperUtils',^\n'%CMDHOME%\\test\\Transactions\\Orleans.Transactions.Tests',^\n'%CMDHOME%\\test\\Transactions\\Orleans.Transactions.Azure.Test',^\n'%CMDHOME%\\test\\TestInfrastructure\\Orleans.TestingHost.Tests',^\n'%CMDHOME%\\test\\DependencyInjection.Tests',^\n'%CMDHOME%\\test\\Orleans.Connections.Security.Tests',^\n'%CMDHOME%\\test\\Analyzers.Tests'\"\n\n@Echo Test assemblies = %TESTS%\n\nPowerShell -NoProfile -ExecutionPolicy Bypass -Command \"& ./Parallel-Tests.ps1 -directories %TESTS% -dotnet '%_dotnet%'\"\nset testresult=%errorlevel%\npopd\nendlocal&set testresult=%testresult%\nexit /B %testresult%\n"
  },
  {
    "path": "TestAll.cmd",
    "content": "@setlocal\n@ECHO off\n\nSET CMDHOME=%~dp0\n@REM Remove trailing backslash \\\nset CMDHOME=%CMDHOME:~0,-1%\n\n@REM Due to more of Windows .cmd script parameter passing quirks, we can't pass this value as cmdline argument, \n@REM  so we need to pass it in through the back door as environment variable, scoped by setlocal\nset TEST_FILTERS=Category=BVT^|Category=SlowBVT^|Category=Functional\n\n@REM Note: We transfer _complete_ control to the Test.cmd script here because we don't use CALL.\n\n\"%CMDHOME%\\Test.cmd\" %1\n\n@REM Note: Execution will NOT return here, and the exit code returned to the caller will be whatever the other script returned.\n"
  },
  {
    "path": "build.ps1",
    "content": "# --------------------\n# Orleans build script\n# --------------------\n\n. ./common.ps1\n\n$scriptDir = Split-Path $script:MyInvocation.MyCommand.Path\n$solution = Join-Path $scriptDir \"Orleans.slnx\"\n\n# Define build flags & config\nif ($null -eq $env:BUILD_FLAGS)\n{\n    $env:BUILD_FLAGS = \"/m /v:m\"\n}\nif ($null -eq $env:BuildConfiguration)\n{\n    $env:BuildConfiguration = \"Debug\"\n}\n\n# Clear the 'Platform' env variable for this session, as it's a per-project setting within the build, and\n# misleading value (such as 'MCD' in HP PCs) may lead to build breakage (issue: #69).\n$Platform = $null\n\n# Disable multilevel lookup https://github.com/dotnet/core-setup/blob/main/Documentation/design-docs/multilevel-sharedfx-lookup.md\n $DOTNET_MULTILEVEL_LOOKUP = 0\n\n$BuildProperties = \"/p:Configuration=$env:BuildConfiguration\";\n\n # Set DateTime suffix for debug builds\n if ($env:BuildConfiguration -eq \"Debug\")\n {\n    $dateSuffix = Get-Date -Format \"yyyyMMddHHmm\"\n    $BuildProperties = $BuildProperties + \" /p:VersionDateSuffix=$dateSuffix\"\n }\n\nWrite-Output \"===== Building $solution =====\"\n\nInstall-Dotnet\n\nif ($args[0] -ne \"Pack\")\n{\n    Write-Output \"Build $env:BuildConfiguration ==============================\"\n    Invoke-Dotnet -Command \"restore\" -Arguments \"$env:BUILD_FLAGS /bl:${env:BuildConfiguration}-Restore.binlog ${BuildProperties} `\"$solution`\"\"\n    Invoke-Dotnet -Command \"build\" -Arguments \"$env:BUILD_FLAGS /bl:${env:BuildConfiguration}-Build.binlog ${BuildProperties} `\"$solution`\"\"\n}\n\nWrite-Output \"Package $env:BuildConfiguration ============================\"\nInvoke-Dotnet -Command \"pack\" -Arguments \"--no-build --no-restore $BUILD_FLAGS /bl:${env:BuildConfiguration}-Pack.binlog ${BuildProperties} `\"$solution`\"\"\n\nWrite-Output \"===== Build succeeded for $solution =====\"\n"
  },
  {
    "path": "common.ps1",
    "content": "function Install-Dotnet \n{\n   $installDotnet = $true\n   try \n   {\n       # Check that the dotnet.exe command exists\n       Get-Command dotnet.exe 2>&1 | Out-Null\n       # Read the version from global.json\n       $globalJson = Get-Content .\\global.json | ConvertFrom-Json\n       $requiredVersion = $globalJson.sdk.version\n       # Check versions already installed\n       $localVersions = dotnet --list-sdks |% {  $_.Split(\" \")[0] }\n       Write-Output \"Required SDK: $requiredVersion\"\n       Write-Output \"Installed SDKs: $localversions\"\n       # If the required version is not installed, we will call the installation script\n       $installDotnet = !$localVersions.Contains($globalJson.sdk.version)\n   }\n   catch\n   {\n       Write-Output \"dotnet not found\"\n       # do nothing, we will install dotnet\n   }\n\n   if ($installDotnet)\n   {\n       Write-Output \"Installing dotnet ${requiredVersion}\"\n\n       New-Item -ItemType Directory -Force -Path .\\Tools | Out-Null\n\n       [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n       Invoke-WebRequest `\n           -Uri \"https://dot.net/v1/dotnet-install.ps1\" `\n           -OutFile \".\\Tools\\dotnet-install.ps1\"\n\n       & .\\Tools\\dotnet-install.ps1 -InstallDir Tools\\dotnetcli\\ -JSonFile .\\global.json\n   }\n}\n\nfunction Invoke-Dotnet \n{\n   param \n   (\n       $Command,\n       $Arguments\n   )\n   $cmdArgs = @()\n   $cmdArgs = $cmdArgs + $Command\n   $cmdArgs = $cmdArgs + ($Arguments -split \"\\s+\")\n   Write-Output \"dotnet $cmdArgs\"\n   & dotnet $cmdArgs\n   if ($LASTEXITCODE -ne 0)\n   {\n       Write-Error \"===== Build FAILED -- $Command with error $LASTEXITCODE - CANNOT CONTINUE =====\"\n       Exit $LASTEXITCODE\n   }\n}"
  },
  {
    "path": "distributed-tests.yml",
    "content": "variables:\n  clusterId: '{{ \"now\" | date: \"%s\" }}'\n  serviceId: '{{ \"now\" | date: \"%s\" }}'\n  framework: net8.0\n\njobs:\n  server:\n    source:\n      localFolder: Artifacts/DistributedTests/DistributedTests.Server/{{framework}}\n    executable: DistributedTests.Server.exe\n    readyStateText: Orleans Silo started.\n    framework: net8.0\n    arguments: \"{{configurator}} --clusterId {{clusterId}} --serviceId {{serviceId}} --azureQueueUri {{azureQueueUri}} --azureTableUri {{azureTableUri}} {{configuratorOptions}}\"\n    onConfigure:\n      - if (job.endpoints.Count > 0) {\n          job.endpoints.RemoveRange(job.variables.instances, job.endpoints.Count - job.variables.instances);\n        }\n  client:\n    source:\n      localFolder: Artifacts/DistributedTests/DistributedTests.Client/{{framework}}\n    executable: DistributedTests.Client.exe\n    waitForExit: true\n    framework: net8.0\n    arguments: \"{{command}} --clusterId {{clusterId}} --serviceId {{serviceId}} --azureQueueUri {{azureQueueUri}} --azureTableUri {{azureTableUri}} {{commandOptions}}\"\n    onConfigure:\n      - if (job.endpoints.Count > 0) {\n          job.endpoints.Reverse();\n          job.endpoints.RemoveRange(job.variables.instances, job.endpoints.Count - job.variables.instances);\n        }\n\nscenarios:\n  ping:\n    server:\n      job: server\n      variables:\n        instances: 10\n        configurator: SimpleSilo\n    client:\n      job: client\n      variables:\n        command: ping\n        instances: 1\n        numWorkers: 250\n        blocksPerWorker: 0\n        requestsPerBlock: 500\n        duration: 120\n        commandOptions: \"--numWorkers {{numWorkers}} --blocksPerWorker {{blocksPerWorker}} --requestsPerBlock {{requestsPerBlock}} --duration {{duration}}\"\n  fanout:\n    server:\n      job: server\n      variables:\n        instances: 10\n        configurator: SimpleSilo\n    client:\n      job: client\n      variables:\n        command: fan-out\n        instances: 1\n        numWorkers: 1\n        blocksPerWorker: 0\n        requestsPerBlock: 50\n        duration: 240\n        commandOptions: \"--numWorkers {{numWorkers}} --blocksPerWorker {{blocksPerWorker}} --requestsPerBlock {{requestsPerBlock}} --duration {{duration}}\"\n  streaming:\n    server:\n      job: server\n      variables:\n        instances: 10\n        configurator: EventGeneratorStreamingSilo\n        duration: 300\n        type: ExplicitGrainBasedAndImplicit\n        streamsPerQueue: 1000\n        queueCount: 8\n        wait: 20\n        configuratorOptions: \"--type {{type}} --streamsPerQueue {{streamsPerQueue}} --queueCount {{queueCount}} --wait {{wait}} --duration {{duration}}\"\n    client:\n      job: client\n      variables:\n        command: counter\n        instances: 1\n        commandOptions: \"requests errors\"\n  reliability:\n    server:\n      job: server\n      variables:\n        instances: 10\n        configurator: SimpleSilo\n    chaosagent:\n      job: client\n      waitForExit: false\n      variables:\n        command: chaosagent\n        instances: 1\n        wait: 30\n        serversPerRound: 1\n        rounds: 4\n        roundDelay: 30\n        graceful: false\n        restart: true\n        commandOptions: \"--wait {{wait}} --serversPerRound {{serversPerRound}} --rounds {{rounds}} --roundDelay {{roundDelay}} --graceful {{graceful}} --restart {{restart}}\"\n    client:\n      job: client\n      waitForExit: true\n      variables:\n        command: ping\n        instances: 1\n        numWorkers: 250\n        blocksPerWorker: 0\n        requestsPerBlock: 500\n        duration: 180\n        commandOptions: \"--numWorkers {{numWorkers}} --blocksPerWorker {{blocksPerWorker}} --requestsPerBlock {{requestsPerBlock}} --duration {{duration}}\"\n  rolling:\n    server:\n      job: server\n      variables:\n        instances: 10\n        configurator: SimpleSilo\n    chaosagent:\n      job: client\n      waitForExit: false\n      variables:\n        command: chaosagent\n        instances: 1\n        wait: 30\n        serversPerRound: 1\n        rounds: 4\n        roundDelay: 30\n        graceful: true\n        restart: true\n        commandOptions: \"--wait {{wait}} --serversPerRound {{serversPerRound}} --rounds {{rounds}} --roundDelay {{roundDelay}} --graceful {{graceful}} --restart {{restart}}\"\n    client:\n      job: client\n      waitForExit: true\n      variables:\n        command: ping\n        instances: 1\n        numWorkers: 250\n        blocksPerWorker: 0\n        requestsPerBlock: 500\n        duration: 180\n        commandOptions: \"--numWorkers {{numWorkers}} --blocksPerWorker {{blocksPerWorker}} --requestsPerBlock {{requestsPerBlock}} --duration {{duration}}\"\n\ncounters:\n- provider: Microsoft.Orleans\n  values:\n  - name: app-requests\n    measurement: orleans-counter/requests-per-second\n    description: Request rate\n\n  - name: activation-count\n    measurement: orleans-counter/grain-activation-count\n    description: Total number of grains\n\nresults:\n# Microsoft.Orleans counters\n- name: orleans-counter/requests-per-second\n  measurement: orleans-counter/requests-per-second\n  description: Request rate\n  format: \"n0\"\n  aggregate: max\n  reduce: max\n- name: orleans-counter/requests-per-second/95\n  measurement: orleans-counter/requests-per-second\n  description: Request rate\n  format: \"n0\"\n  aggregate: percentile95\n  reduce: max\n- name: activation-count\n  measurement: orleans-counter/grain-activation-count\n  description: Active grains\n\nprofiles:\n  local:\n    variables:\n      azureQueueUri: \"http://127.0.0.1:10001\"\n      azureTableUri: \"http://127.0.0.1:10002\"\n    jobs:\n      server:\n        endpoints:\n          - http://localhost:5010\n        variables:\n          instances: 1\n      client:\n        endpoints:\n          - http://localhost:5010\n      chaosagent:\n        endpoints:\n          - http://localhost:5010"
  },
  {
    "path": "es-metadata.yml",
    "content": "schemaVersion: 0.0.1\nisProduction: true\naccountableOwners:\n  service: 29f743e3-3a8f-4955-89e1-dcd58905919a\nrouting:\n  defaultAreaPath:\n    org: devdiv\n    path: DevDiv\\ASP.NET Core\n"
  },
  {
    "path": "global.json",
    "content": "{\n  \"sdk\": {\n    \"rollForward\": \"major\",\n    \"version\": \"10.0.103\"\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.AppHost/ActivationRebalancing.AppHost.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"13.0.0\" />\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsAspireHost>true</IsAspireHost>\n    <UserSecretsId>6e52d7b6-4f1f-4e1c-abef-df2fe839e7f2</UserSecretsId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.AppHost\" />\n    <PackageReference Include=\"Aspire.Hosting.Orleans\" />\n    <PackageReference Include=\"Aspire.Hosting.Redis\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ActivationRebalancing.Cluster\\ActivationRebalancing.Cluster.csproj\" />\n    <ProjectReference Include=\"..\\ActivationRebalancing.Frontend\\ActivationRebalancing.Frontend.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.AppHost/Program.cs",
    "content": "using Aspire.Hosting;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"orleans-redis\");\n\nvar orleans = builder.AddOrleans(\"cluster\")\n    .WithClustering(redis);\n\nvar backend = builder.AddProject<Projects.ActivationRebalancing_Cluster>(\"backend\")\n    .WithReference(orleans)\n    .WaitFor(redis)\n    .WithReplicas(5);\n\nbuilder.AddProject<Projects.ActivationRebalancing_Frontend>(\"frontend\")\n    .WithReference(orleans.AsClient())\n    .WaitFor(backend)\n    .WithReplicas(1);\n\nbuilder.Build().Run();\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.AppHost/Properties/launchSettings.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"https\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:17267;http://localhost:15094\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"https://localhost:21125\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"https://localhost:22078\"\n      }\n    },\n    \"http\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"http://localhost:15094\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"http://localhost:19108\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"http://localhost:20187\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.AppHost/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.AppHost/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\",\n      \"Aspire.Hosting.Dcp\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Cluster/ActivationRebalancing.Cluster.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.StackExchange.Redis\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Server\\Orleans.Server.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Redis\\Orleans.Clustering.Redis\\Orleans.Clustering.Redis.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Cluster/Program.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\n\nvar builder = Host.CreateApplicationBuilder(args);\nbuilder.AddKeyedRedisClient(\"orleans-redis\");\nbuilder.Logging.AddFilter(\"Orleans.Runtime.Placement.Rebalancing\", LogLevel.Trace);\n#pragma warning disable ORLEANSEXP002\nbuilder.UseOrleans(builder => builder\n    .Configure<GrainCollectionOptions>(o =>\n    {\n        o.CollectionQuantum = TimeSpan.FromSeconds(15);\n    })\n    .Configure<ResourceOptimizedPlacementOptions>(o =>\n    {\n        o.LocalSiloPreferenceMargin = 0;\n    })\n    .Configure<ActivationRebalancerOptions>(o =>\n    {\n        o.RebalancerDueTime = TimeSpan.FromSeconds(5);\n        o.SessionCyclePeriod = TimeSpan.FromSeconds(5);\n        // uncomment these below, if you want higher migration rate\n        //o.CycleNumberWeight = 1;\n        //o.SiloNumberWeight = 0; \n    })\n    .AddActivationRebalancer());\n#pragma warning restore ORLEANSEXP002\n\nbuilder.Services.AddHostedService<LoadDriverBackgroundService>();\nvar app = builder.Build();\n\nawait app.RunAsync();\n\ninternal class LoadDriverBackgroundService(IGrainFactory client) : BackgroundService\n{\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            for (var i = 0; i < 5 * Random.Shared.Next(1, 1000); i++)\n            {\n                await client.GetGrain<IRebalancingTestGrain>(Guid.NewGuid()).Ping();\n            }\n\n            await Task.Delay(Random.Shared.Next(500, 1_000), stoppingToken);\n        }\n    }\n}\n\npublic interface IRebalancingTestGrain : IGrainWithGuidKey\n{\n    Task Ping();\n}\n\n[CollectionAgeLimit(Minutes = 0.5)]\npublic class RebalancingTestGrain : Grain, IRebalancingTestGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/ActivationRebalancing.Frontend.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.StackExchange.Redis\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Server\\Orleans.Server.csproj\" />\n    <ProjectReference Include=\"..\\ActivationRebalancing.Cluster\\ActivationRebalancing.Cluster.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Redis\\Orleans.Clustering.Redis\\Orleans.Clustering.Redis.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/Controllers/StatsController.cs",
    "content": "using Microsoft.AspNetCore.Mvc;\nusing Orleans.Runtime;\nusing Orleans;\n\nnamespace ActivationRebalancing.Frontend.Controllers;\n\n[ApiController]\n[Route(\"api/[controller]\")]\npublic class StatsController(IClusterClient clusterClient) : ControllerBase\n{\n    [HttpGet(\"silos\")]\n    public async Task<IActionResult> GetStats()\n    {\n        var grainStats = await clusterClient\n            .GetGrain<IManagementGrain>(0)\n            .GetDetailedGrainStatistics();\n\n        var siloData = grainStats.GroupBy(stat => stat.SiloAddress)\n            .Select(g => new SiloData(g.Key.ToString(), g.Count()))\n            .ToList();\n\n        if (siloData.Count == 4)\n        {\n            siloData = [.. siloData, new SiloData(\"x\", 0)];\n        }\n\n        if (siloData.Count > 5)\n        {\n            throw new NotSupportedException(\"The frontend cant support more than 6 silos\");\n        }\n\n        return Ok(siloData);\n    }\n}\n\npublic record SiloData(string Host, int Activations);"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/Program.cs",
    "content": "using Orleans.Hosting;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.AddKeyedRedisClient(\"orleans-redis\");\nbuilder.UseOrleansClient();\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\nvar options = new DefaultFilesOptions();\noptions.DefaultFileNames.Clear();\noptions.DefaultFileNames.Add(\"index.html\");\n\napp.UseDefaultFiles(options);\napp.UseStaticFiles();\napp.MapControllers();\napp.Run();\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"http\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"launchUrl\": \"index.html\",\n      \"applicationUrl\": \"http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/wwwroot/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Orleans Activation Load Balancing</title>\n  <script src=\"https://d3js.org/d3.v7.min.js\"></script>\n  <style>\n    :root {\n      --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n      --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n      --card-bg: rgba(255, 255, 255, 0.95);\n      --card-dark-bg: rgba(44, 62, 80, 0.95);\n      --text-primary: #2c3e50;\n      --text-secondary: #7f8c8d;\n      --text-light: #ecf0f1;\n      --border-radius: 16px;\n      --shadow-soft: 0 10px 40px rgba(0, 0, 0, 0.1);\n      --shadow-strong: 0 20px 60px rgba(0, 0, 0, 0.15);\n      --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n    }\n\n    * {\n      margin: 0;\n      padding: 0;\n      box-sizing: border-box;\n    }\n\n    body {\n      font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;\n      background: var(--primary-gradient);\n      height: 100vh;\n      color: var(--text-primary);\n      padding: 12px;\n      line-height: 1.6;\n      overflow: hidden;\n      display: flex;\n      flex-direction: column;\n    }\n\n    .container {\n      height: 100%;\n      display: flex;\n      flex-direction: column;\n    }\n\n    .header {\n      text-align: center;\n      margin-bottom: 16px;\n      flex-shrink: 0;\n    }\n\n    h1 {\n      color: white;\n      font-size: clamp(1.5rem, 3vw, 2.5rem);\n      font-weight: 700;\n      margin-bottom: 6px;\n      text-shadow: 0 4px 8px rgba(0,0,0,0.2);\n      letter-spacing: -0.02em;\n    }\n\n    .subtitle {\n      color: rgba(255, 255, 255, 0.9);\n      font-size: clamp(0.9rem, 1.5vw, 1.1rem);\n      font-weight: 400;\n      margin-bottom: 12px;\n    }\n\n    .dashboard-grid {\n      display: flex;\n      flex-direction: column;\n      gap: 16px;\n      flex: 1;\n      min-height: 0;\n    }\n\n    .unified-chart-section {\n      background: var(--card-dark-bg);\n      border-radius: 12px;\n      padding: 20px;\n      -webkit-backdrop-filter: blur(10px);\n      backdrop-filter: blur(10px);\n      display: flex;\n      flex-direction: column;\n      flex: 1;\n      min-height: 0;\n    }\n\n    .charts-container {\n      display: grid;\n      grid-template-columns: 4fr 1fr;\n      gap: 20px;\n      flex: 1;\n      min-height: 0;\n    }\n\n    .line-chart-area {\n      grid-column: 1;\n      display: flex;\n      flex-direction: column;\n      min-height: 0;\n    }\n\n    .bar-chart-area {\n      grid-column: 2;\n      display: flex;\n      flex-direction: column;\n      min-height: 0;\n    }\n\n    .chart-subtitle {\n      font-size: 0.9rem;\n      font-weight: 500;\n      color: rgba(236, 240, 241, 0.8);\n      margin-bottom: 12px;\n      display: flex;\n      align-items: center;\n      gap: 6px;\n      flex-shrink: 0;\n    }\n\n    .bar {\n      fill-opacity: 0.9;\n      transition: var(--transition);\n      filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.2));\n    }\n\n    .bar:hover {\n      fill-opacity: 1;\n      transform: scaleY(1.02);\n    }\n\n    .bar-label {\n      text-anchor: middle;\n      font-size: 13px;\n      fill: var(--text-light);\n      font-weight: 600;\n      text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\n    }\n\n    .max-scale-label {\n      font-weight: 500;\n      fill: #bdc3c7;\n      font-size: 11px;\n    }\n\n    .bar-chart {\n      display: flex;\n      justify-content: space-between;\n      align-items: flex-end;\n      flex: 1;\n      gap: 8px;\n      min-height: 0;\n    }\n\n    .line-chart {\n      flex: 1;\n      min-height: 0;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    }\n\n    .line {\n      filter: drop-shadow(0 3px 6px rgba(0,0,0,0.15));\n      stroke-width: 3;\n      transition: var(--transition);\n    }\n\n    .line:hover {\n      stroke-width: 4;\n      filter: drop-shadow(0 4px 12px rgba(0,0,0,0.25));\n    }\n\n    .legend {\n      display: flex;\n      justify-content: center;\n      gap: 16px;\n      margin-top: 12px;\n      flex-wrap: wrap;\n      flex-shrink: 0;\n    }\n\n    .legend-item {\n      display: flex;\n      align-items: center;\n      gap: 6px;\n      padding: 6px 10px;\n      background: rgba(255, 255, 255, 0.1);\n      border-radius: 20px;\n      font-size: 0.8rem;\n      color: var(--text-light);\n      -webkit-backdrop-filter: blur(10px);\n      backdrop-filter: blur(10px);\n    }\n\n    .legend-color {\n      width: 10px;\n      height: 10px;\n      border-radius: 50%;\n      border: 2px solid rgba(255, 255, 255, 0.3);\n    }\n\n    .legend-color-1 { background-color: #ff6b6b; }\n    .legend-color-2 { background-color: #4ecdc4; }\n    .legend-color-3 { background-color: #45b7d1; }\n    .legend-color-4 { background-color: #f9ca24; }\n    .legend-color-5 { background-color: #dda0dd; }\n    /* Grid styling for the density matrix */\n    rect {\n      transition: var(--transition);\n      stroke: rgba(255, 255, 255, 0.1);\n      stroke-width: 0.5;\n    }\n\n    rect:hover {\n      stroke-width: 2;\n      stroke: rgba(255, 255, 255, 0.6);\n      filter: brightness(1.1);\n    }\n\n    /* Axis styling */\n    .axis text {\n      font-size: 12px;\n      fill: var(--text-light);\n      font-family: 'Inter', sans-serif;\n    }\n\n    .axis path,\n    .axis line {\n      fill: none;\n      stroke: rgba(236, 240, 241, 0.3);\n      shape-rendering: crispEdges;\n      stroke-width: 1;\n    }\n\n    .axis-title {\n      font-size: 14px;\n      font-weight: 500;\n      fill: var(--text-light);\n    }\n\n    /* Modern scrollbar */\n    ::-webkit-scrollbar {\n      width: 8px;\n      height: 8px;\n    }\n\n    ::-webkit-scrollbar-track {\n      background: rgba(255, 255, 255, 0.1);\n      border-radius: 4px;\n    }\n\n    ::-webkit-scrollbar-thumb {\n      background: rgba(255, 255, 255, 0.3);\n      border-radius: 4px;\n      transition: var(--transition);\n    }\n\n    ::-webkit-scrollbar-thumb:hover {\n      background: rgba(255, 255, 255, 0.5);\n    }\n\n    /* Loading animation */\n    @keyframes pulse {\n      0%, 100% { opacity: 1; transform: scale(1); }\n      50% { opacity: 0.7; transform: scale(1.1); }\n    }\n\n    @keyframes fadeIn {\n      from { opacity: 0; transform: translateY(20px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    .loading {\n      animation: pulse 2s infinite;\n    }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"header\">\n      <h1>Orleans Activation Load Balancing</h1>\n      <p class=\"subtitle\">Real-time monitoring and visualization of grain activation distribution across silos</p>\n    </div>\n\n    <div class=\"dashboard-grid\">\n      <div class=\"unified-chart-section\">\n        <div class=\"charts-container\">\n          <div class=\"line-chart-area\">\n            <div class=\"chart-subtitle\">Timeline</div>\n            <div id=\"line-chart\" class=\"line-chart\"></div>\n          </div>\n\n          <div class=\"bar-chart-area\">\n            <div class=\"chart-subtitle\">Current Distribution</div>\n            <div id=\"bar-charts\" class=\"bar-chart\"></div>\n          </div>\n        </div>\n\n        <div class=\"legend\">\n          <div class=\"legend-item\">\n            <div class=\"legend-color legend-color-1\"></div>\n            <span>Silo 1</span>\n          </div>\n          <div class=\"legend-item\">\n            <div class=\"legend-color legend-color-2\"></div>\n            <span>Silo 2</span>\n          </div>\n          <div class=\"legend-item\">\n            <div class=\"legend-color legend-color-3\"></div>\n            <span>Silo 3</span>\n          </div>\n          <div class=\"legend-item\">\n            <div class=\"legend-color legend-color-4\"></div>\n            <span>Silo 4</span>\n          </div>\n          <div class=\"legend-item\">\n            <div class=\"legend-color legend-color-5\"></div>\n            <span>Silo 5</span>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <script>\n    // Calculate dimensions based on available space\n    const headerHeight = document.querySelector('.header').offsetHeight;\n    const availableHeight = window.innerHeight - headerHeight - 60; // Account for padding and margins\n    const availableWidth = window.innerWidth - 60; // Account for padding\n\n    // For the line chart (takes up 80% of width)\n    const lineChartWidth = availableWidth * 0.75; // Accounting for grid gap\n    const lineChartHeight = availableHeight * 0.85;\n\n    // For the bar charts (20% of width)\n    const barChartWidth = 50;\n    const barChartContainerHeight = availableHeight * 0.85;\n\n    const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#dda0dd'];\n    const numColors = colors.length;\n    const maxDataPoints = 100;\n\n    const svgBarCharts = d3.select(\"#bar-charts\")\n      .selectAll(\"svg\")\n      .data(colors)\n      .enter()\n      .append(\"svg\")\n      .attr(\"width\", barChartWidth)\n      .attr(\"height\", barChartContainerHeight)\n      .append(\"g\")\n      .attr(\"transform\", `translate(${barChartWidth / 2}, 0)`);\n\n    svgBarCharts.append(\"line\")\n      .attr(\"x1\", 0)\n      .attr(\"y1\", barChartContainerHeight)\n      .attr(\"x2\", 0)\n      .attr(\"y2\", 0)\n      .attr(\"stroke\", \"#ecf0f1\")\n      .attr(\"stroke-width\", 1);\n\n    svgBarCharts.append(\"line\")\n      .attr(\"x1\", -barChartWidth / 2)\n      .attr(\"y1\", barChartContainerHeight)\n      .attr(\"x2\", barChartWidth / 2)\n      .attr(\"y2\", barChartContainerHeight)\n      .attr(\"stroke\", \"#ecf0f1\")\n      .attr(\"stroke-width\", 1);\n\n    svgBarCharts.append(\"text\")\n      .attr(\"class\", \"bar-label\")\n      .attr(\"x\", 0)\n      .attr(\"y\", barChartContainerHeight + 20)\n      .text(d => \"0\");\n\n    // Add max scale label at the top\n    svgBarCharts.append(\"text\")\n      .attr(\"class\", \"max-scale-label\")\n      .attr(\"x\", 0)\n      .attr(\"y\", -5)\n      .attr(\"text-anchor\", \"middle\")\n      .attr(\"font-size\", \"10px\")\n      .attr(\"fill\", \"#666\")\n      .text(\"0\");\n\n    const svgLineChart = d3.select(\"#line-chart\")\n      .append(\"svg\")\n      .attr(\"width\", lineChartWidth)\n      .attr(\"height\", lineChartHeight)\n      .style(\"border-radius\", \"8px\");\n\n    const xScale = d3.scaleLinear()\n      .domain([0, maxDataPoints - 1])\n      .range([0, lineChartWidth - 50]);\n\n    let yScale = d3.scaleLinear()\n      .domain([0, 750])\n      .range([lineChartHeight, 0]);\n\n    const xAxis = d3.axisBottom(xScale).ticks(5);\n    let yAxis = d3.axisLeft(yScale).ticks(5);\n\n    svgLineChart.append(\"g\")\n      .attr(\"class\", \"x-axis axis\")\n      .attr(\"transform\", `translate(50, ${lineChartHeight - 30})`)\n      .call(xAxis);\n\n    svgLineChart.append(\"g\")\n      .attr(\"class\", \"y-axis axis\")\n      .attr(\"transform\", `translate(50, 0)`)\n      .call(yAxis);\n\n    // Add axis labels\n    svgLineChart.append(\"text\")\n      .attr(\"class\", \"axis-title\")\n      .attr(\"transform\", \"rotate(-90)\")\n      .attr(\"y\", 15)\n      .attr(\"x\", -lineChartHeight / 2)\n      .style(\"text-anchor\", \"middle\")\n      .text(\"Activation Count\");\n\n    svgLineChart.append(\"text\")\n      .attr(\"class\", \"axis-title\")\n      .attr(\"x\", lineChartWidth / 2 + 25)\n      .attr(\"y\", lineChartHeight - 5)\n      .style(\"text-anchor\", \"middle\")\n      .text(\"Time (Data Points)\");\n\n    // Create a clipping path to constrain the line chart area\n    svgLineChart.append(\"defs\")\n      .append(\"clipPath\")\n      .attr(\"id\", \"chart-clip\")\n      .append(\"rect\")\n      .attr(\"width\", lineChartWidth - 50)\n      .attr(\"height\", lineChartHeight)\n      .attr(\"x\", 0)\n      .attr(\"y\", 0);\n\n    // Create a container group for the lines that will be clipped\n    const linesContainer = svgLineChart.append(\"g\")\n      .attr(\"transform\", \"translate(50, 0)\")\n      .attr(\"clip-path\", \"url(#chart-clip)\");\n\n    const lineGenerators = colors.map(() => d3.line()\n      .x((d, i) => xScale(i))\n      .y(d => yScale(d)));\n\n    const linePaths = linesContainer.selectAll(\".line\")\n      .data(colors)\n      .enter()\n      .append(\"path\")\n      .attr(\"class\", \"line\")\n      .attr(\"stroke\", (d, i) => colors[i])\n      .attr(\"fill\", \"none\")\n      .attr(\"stroke-width\", 3)\n      .attr(\"stroke-linecap\", \"round\")\n      .attr(\"stroke-linejoin\", \"round\");\n\n    const activationsHistory = colors.map(() => []);\n\n    const worker = new Worker('worker.js');\n\n    function updateChart(data) {\n      worker.postMessage(data);\n\n      worker.onmessage = function (event) {\n        const { densityMatrix, error } = event.data;\n\n        if (error) {\n          console.error('Error from worker:', error);\n          return;\n        }\n\n        // Calculate the maximum activation count across all silos for scaling\n        const maxActivations = Math.max(...data.map(silo => silo.activations));\n        const barScale = d3.scaleLinear()\n          .domain([0, maxActivations])\n          .range([0, barChartContainerHeight - 30]); // Leave some space for labels\n\n        svgBarCharts.each(function (d, i) {\n          const barChart = d3.select(this);\n\n          const bars = barChart.selectAll(\".bar\")\n            .data([data[i].activations]);\n\n          bars.enter()\n            .append(\"rect\")\n            .attr(\"class\", \"bar\")\n            .merge(bars)\n            .attr(\"x\", -barChartWidth / 2 + 5)\n            .attr(\"y\", d => barChartContainerHeight - barScale(d))\n            .attr(\"width\", barChartWidth - 20)\n            .attr(\"height\", d => barScale(d))\n            .attr(\"fill\", colors[i])\n            .attr(\"rx\", 4) // Rounded corners\n            .attr(\"ry\", 4);\n\n          bars.exit().remove();\n\n          barChart.select(\".bar-label\")\n            .text(data[i].activations);\n\n          // Update the max scale label\n          barChart.select(\".max-scale-label\")\n            .text(maxActivations);\n        });\n\n        data.forEach((silo, i) => {\n          activationsHistory[i].push(silo.activations);\n\n          // Keep only the most recent maxDataPoints for smooth scrolling\n          if (activationsHistory[i].length > maxDataPoints) {\n            activationsHistory[i].shift();\n          }\n        });\n\n        // Update line chart scale based on current maximum across all visible history\n        const allHistoryValues = activationsHistory.flat();\n        const maxHistoryValue = allHistoryValues.length > 0 ? Math.max(...allHistoryValues) : 750;\n        const rawMaxValue = Math.max(maxHistoryValue, maxActivations);\n\n        // Add 20% buffer above the maximum value for comfortable spacing\n        const newMaxValue = rawMaxValue * 1.2;\n\n        // Update Y scale domain if needed\n        yScale.domain([0, newMaxValue]);\n        yAxis = d3.axisLeft(yScale).ticks(5);\n\n        // Update Y axis\n        svgLineChart.select(\".y-axis\")\n          .transition()\n          .duration(300)\n          .call(yAxis);\n\n        // Update line generators with new scale\n        const updatedLineGenerators = colors.map(() => d3.line()\n          .x((d, i) => xScale(i))\n          .y(d => yScale(d)));\n\n        linePaths.each(function (d, i) {\n          d3.select(this)\n            .datum(activationsHistory[i])\n            .attr(\"d\", updatedLineGenerators[i]);\n        });\n      };\n    }\n\n    function fetchData() {\n      fetch('/api/stats/silos')\n        .then(response => {\n          if (!response.ok) {\n            throw new Error(`HTTP error! status: ${response.status}`);\n          }\n          return response.json();\n        })\n        .then(newData => {\n          console.log('Fetched Data:', newData);\n          updateChart(newData);\n        })\n        .catch(error => {\n          console.error('Error fetching grain stats:', error);\n        });\n    }\n\n    setInterval(fetchData, 500);\n    fetchData();\n\n    // Handle window resize for responsiveness\n    let resizeTimeout;\n    window.addEventListener('resize', () => {\n      clearTimeout(resizeTimeout);\n      resizeTimeout = setTimeout(() => {\n        // Reload on any significant resize since we're using viewport-based dimensions\n        location.reload();\n      }, 250);\n    });\n\n    // Add keyboard shortcuts for better UX\n    document.addEventListener('keydown', (e) => {\n      if (e.key === 'r' || e.key === 'R') {\n        if (e.ctrlKey || e.metaKey) {\n          e.preventDefault();\n          fetchData();\n        }\n      }\n    });\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "playground/ActivationRebalancing/ActivationRebalancing.Frontend/wwwroot/worker.js",
    "content": "self.onmessage = function (e) {\n  try {\n    const data = e.data;\n    const totalActivations = data.reduce((sum, d) => sum + d.activations, 0);\n    const densityMatrix = Array.from({ length: 20 }, () => Array(20).fill('white'));\n\n    data.forEach((d, i) => {\n      const numCells = Math.round(d.activations / totalActivations * 400);\n      const color = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff'][i % 5];\n\n      let cellsFilled = 0;\n      const maxFillWhiteCellAttempts = 500;\n\n      for (let attempt = 0; attempt < maxFillWhiteCellAttempts && cellsFilled < numCells; attempt++) {\n        const x = Math.floor(Math.random() * 20);\n        const y = Math.floor(Math.random() * 20);\n        if (densityMatrix[y][x] === 'white') {\n          densityMatrix[y][x] = color;\n          cellsFilled++;\n        }\n      }\n\n    });\n\n    postMessage({ densityMatrix });\n  } catch (error) {\n    postMessage({ error: error.message });\n  }\n};\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/ActivationRepartitioning.AppHost.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"13.0.0\" />\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsAspireHost>true</IsAspireHost>\n    <UserSecretsId>6a521b87-2bf9-4af8-b7c7-4947536e1d50</UserSecretsId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.AppHost\" />\n    <PackageReference Include=\"Aspire.Hosting.Orleans\" />\n    <PackageReference Include=\"Aspire.Hosting.Redis\" />\n    <PackageReference Include=\"Aspire.StackExchange.Redis\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ActivationRepartitioning.Frontend\\ActivationRepartitioning.Frontend.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/Program.cs",
    "content": "using Aspire.Hosting;\nusing Projects;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"orleans-redis\");\n\nvar orleans = builder.AddOrleans(\"cluster\")\n    .WithClustering(redis);\n\nbuilder.AddProject<ActivationRepartitioning_Frontend>(\"frontend\")\n    .WithReference(orleans)\n    .WaitFor(redis)\n    .WithReplicas(5);\n\nbuilder.Build().Run();\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/Properties/launchSettings.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"https\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:17234;http://localhost:15087\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"https://localhost:21284\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"https://localhost:22143\"\n      }\n    },\n    \"http\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"http://localhost:15087\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"http://localhost:19030\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"http://localhost:20232\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.AppHost/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\",\n      \"Aspire.Hosting.Dcp\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/ActivationRepartitioning.Frontend.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.StackExchange.Redis\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Redis\\Orleans.Clustering.Redis\\Orleans.Clustering.Redis.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/Data/ClusterDiagnosticsService.cs",
    "content": "using System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing Orleans.Core.Internal;\n\nnamespace ActivationRepartitioning.Frontend.Data;\n\npublic class ClusterDiagnosticsService(IGrainFactory grainFactory)\n{\n    private readonly Dictionary<SiloAddress, int> _hostKeys = [];\n    private readonly Dictionary<SiloAddress, HostDetails> _hostDetails = [];\n    private readonly Dictionary<GrainId, GrainDetails> _grainDetails = []; // Grain to host id\n    private readonly Dictionary<Key, ulong> _edges = [];\n    private readonly IManagementGrain _managementGrain = grainFactory.GetGrain<IManagementGrain>(0);\n    private readonly record struct GrainDetails(int GrainKey, int HostKey);\n    private readonly record struct HostDetails(int HostKey, int ActivationCount);\n    private int _version;\n\n    public async ValueTask<CallGraph> GetGrainCallFrequencies()\n    {\n        var loaderGrain = grainFactory.GetGrain<ILoaderGrain>(\"root\");\n        var loaderGrainType = loaderGrain.GetGrainId().Type;\n        var resetCount = await loaderGrain.GetResetCount();\n        if (resetCount > _version)\n        {\n            _version = resetCount;\n            await ResetAsync();\n        }\n\n        lock (this)\n        {\n            _edges.Clear();\n        }\n\n        var maxEdgeValue = 0;\n        var maxActivationCount = 0;\n\n        var silos = (await _managementGrain.GetHosts(onlyActive: true)).Keys.Order();\n        foreach (var silo in silos)\n        {\n            var hostKey = GetHostVertex(silo);\n            var activationCount = 0;\n            foreach (var activation in await _managementGrain.GetDetailedGrainStatistics(hostsIds: [silo]))\n            {\n                if (activation.GrainId.Type.Equals(loaderGrainType)) continue;\n                if (activation.GrainId.IsSystemTarget()) continue;\n\n                lock (this)\n                {\n                    var details = GetGrainVertex(activation.GrainId, hostKey);\n                    _grainDetails[activation.GrainId] = new(details.GrainKey, hostKey);\n                    ++activationCount;\n                }\n            }\n\n            lock (this)\n            {\n                maxActivationCount = Math.Max(maxActivationCount, activationCount);\n                _hostDetails[silo] = new(hostKey, activationCount);\n            }\n        }\n\n        foreach (var edge in await _managementGrain.GetGrainCallFrequencies())\n        {\n            if (edge.TargetGrain.IsSystemTarget() || edge.SourceGrain.IsSystemTarget()) continue;\n            lock (this)\n            {\n                var sourceHostId = GetHostVertex(edge.SourceHost);\n                var targetHostId = GetHostVertex(edge.TargetHost);\n                var sourceVertex = GetGrainVertex(edge.SourceGrain, sourceHostId);\n                var targetVertex = GetGrainVertex(edge.TargetGrain, targetHostId);\n                maxEdgeValue = Math.Max(maxEdgeValue, (int)edge.CallCount);\n                UpdateEdge(new(sourceVertex.GrainKey, targetVertex.GrainKey), edge.CallCount);\n            }\n        }\n\n        lock (this)\n        {\n            var grainIds = new List<GraphNode>(_grainDetails.Count);\n            CollectionsMarshal.SetCount(grainIds, _grainDetails.Count);\n            foreach ((var grainId, var (grainKey, hostKey)) in _grainDetails)\n            {\n                grainIds[grainKey] = new(grainId.ToString(), grainId.Key.ToString()!, hostKey, 1.0);\n            }\n\n            var hostIds = new List<HostNode>(_hostKeys.Count);\n            CollectionsMarshal.SetCount(hostIds, _hostKeys.Count);\n            foreach ((var hostId, var key) in _hostKeys)\n            {\n                if (_hostDetails.TryGetValue(hostId, out var details))\n                {\n                    hostIds[key] = new(hostId.ToString(), details.ActivationCount);\n                }\n            }\n\n            var edges = new List<GraphEdge>();\n\n            foreach (var edge in _edges)\n            {\n                edges.Add(new(edge.Key.Source, edge.Key.Target, edge.Value));\n            }\n\n            return new(grainIds, hostIds, edges, maxEdgeValue, maxActivationCount);\n        }\n    }\n\n    internal async ValueTask ResetAsync()\n    {\n        var fanoutType = grainFactory.GetGrain<IFanOutGrain>(0, \"0\").GetGrainId().Type;\n        foreach (var activation in await _managementGrain.GetDetailedGrainStatistics())\n        {\n            if (!activation.GrainId.Type.Equals(fanoutType)) continue;\n            await grainFactory.GetGrain<IGrainManagementExtension>(activation.GrainId).DeactivateOnIdle();\n        }\n\n        Reset();\n    }\n\n    internal void Reset()\n    {\n        lock (this)\n        {\n            _hostKeys.Clear();\n            _hostDetails.Clear();\n            _grainDetails.Clear();\n            _edges.Clear();\n        }\n    }\n\n    private GrainDetails GetGrainVertex(GrainId grainId, int hostKey)\n    {\n        lock (this)\n        {\n            ref var key = ref CollectionsMarshal.GetValueRefOrAddDefault(_grainDetails, grainId, out var exists);\n            if (!exists)\n            {\n                key = new(_grainDetails.Count - 1, hostKey);\n            }\n\n            return key;\n        }\n    }\n\n    private int GetHostVertex(SiloAddress silo)\n    {\n        lock (this)\n        {\n            ref var key = ref CollectionsMarshal.GetValueRefOrAddDefault(_hostKeys, silo, out var exists);\n            if (!exists)\n            {\n                key = _hostKeys.Count - 1;\n            }\n\n            return key;\n        }\n    }\n\n    private void UpdateEdge(Key key, ulong increment)\n    {\n        lock (this)\n        {\n            ref var count = ref CollectionsMarshal.GetValueRefOrAddDefault(_edges, key, out var exists);\n            count += increment;\n        }\n    }\n}\n\npublic record class CallGraph(List<GraphNode> GrainIds, List<HostNode> HostIds, List<GraphEdge> Edges, int MaxEdgeValue, int MaxActivationCount);\n\npublic record struct HostNode(string Name, int ActivationCount);\npublic record struct GraphNode(string Name, string Key, int Host, double Weight);\npublic record struct Key(int Source, int Target);\npublic record struct GraphEdge(int Source, int Target, double Weight);\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/Program.cs",
    "content": "using ActivationRepartitioning.Frontend.Data;\nusing Microsoft.AspNetCore.Mvc;\nusing Orleans.Configuration;\nusing Orleans.Placement.Repartitioning;\n\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.AddKeyedRedisClient(\"orleans-redis\");\nbuilder.UseOrleans(orleans =>\n{\n#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n    orleans.AddActivationRepartitioner();\n    orleans.Configure<ActivationRepartitionerOptions>(o =>\n    {\n        o.MinRoundPeriod = TimeSpan.FromSeconds(5);\n        o.MaxRoundPeriod = TimeSpan.FromSeconds(15);\n        o.RecoveryPeriod = TimeSpan.FromSeconds(5);\n        o.AnchoringFilterEnabled = false;\n    });\n#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n#pragma warning disable ORLEANSEXP002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n    orleans.AddActivationRebalancer();\n    orleans.Configure<ActivationRebalancerOptions>(o =>\n    {\n        o.RebalancerDueTime = TimeSpan.FromSeconds(10);\n        o.SessionCyclePeriod = TimeSpan.FromSeconds(5);\n        o.CycleNumberWeight = 0.7;\n    });\n#pragma warning restore ORLEANSEXP002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n});\n\n// Add services to the container.\nbuilder.Services.AddSingleton<ClusterDiagnosticsService>();\n\nvar app = builder.Build();\n\nvar clusterDiagnosticsService = app.Services.GetRequiredService<ClusterDiagnosticsService>();\napp.MapGet(\"/data.json\", ([FromServices] ClusterDiagnosticsService clusterDiagnosticsService) => clusterDiagnosticsService.GetGrainCallFrequencies());\napp.MapPost(\"/reset\", async ([FromServices] IGrainFactory grainFactory) =>\n{\n    await grainFactory.GetGrain<ILoaderGrain>(\"root\").Reset();\n});\napp.MapPost(\"/add\", async ([FromServices] IGrainFactory grainFactory) =>\n{\n    await grainFactory.GetGrain<ILoaderGrain>(\"root\").AddForest();\n});\n\n// Configure the HTTP request pipeline.\nif (!app.Environment.IsDevelopment())\n{\n    app.UseExceptionHandler(\"/Error\");\n    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n    app.UseHsts();\n}\n\napp.UseHttpsRedirection();\n\napp.UseDefaultFiles();\napp.UseStaticFiles();\n\napp.UseRouting();\n\nawait app.StartAsync();\n\nvar loadGrain = app.Services.GetRequiredService<IGrainFactory>().GetGrain<ILoaderGrain>(\"root\");\nfor (var i = 0; i < 5; i++)\n{\n    for (var j = 0; j < 3; j++)\n    {\n        await loadGrain.AddForest();\n    }\n\n    await Task.Delay(TimeSpan.FromSeconds(2));\n}\n\nawait app.WaitForShutdownAsync();\n\npublic interface ILoaderGrain : IGrainWithStringKey\n{\n    ValueTask AddForest();\n    ValueTask Reset();\n    ValueTask<int> GetResetCount();\n}\n\npublic class LoaderGrain : Grain, ILoaderGrain\n{\n    private int _numForests = 0;\n    private int _resetCount;\n\n    public async ValueTask AddForest()\n    {\n        var forest = _numForests++;\n        var loadGrain = GrainFactory.GetGrain<IFanOutGrain>(0, forest.ToString());\n        await loadGrain.Ping();\n    }\n\n    public async ValueTask Reset()\n    {\n        ++_resetCount;\n        _numForests = 0;\n        await ServiceProvider.GetRequiredService<ClusterDiagnosticsService>().ResetAsync();\n        await GrainFactory.GetGrain<IManagementGrain>(0).ResetGrainCallFrequencies();\n    }\n\n    public ValueTask<int> GetResetCount() => new(_resetCount);\n}\n\npublic interface IFanOutGrain : IGrainWithIntegerCompoundKey\n{\n    public ValueTask Ping();\n}\n\npublic class FanOutGrain : Grain, IFanOutGrain\n{\n    public const int FanOutFactor = 4;\n    public const int MaxLevel = 2;\n    private readonly List<IFanOutGrain> _children;\n\n    public FanOutGrain()\n    {\n        var id = this.GetPrimaryKeyLong(out var forest);\n        if (forest is null)\n        {\n            throw new InvalidOperationException(\"FanOutGrain must be created with a forest identifier (i.e, a grain key extension).\");\n        }\n\n        var level = id == 0 ? 0 : (int)Math.Log(id, FanOutFactor);\n        var numChildren = level < MaxLevel ? FanOutFactor : 0;\n        _children = new List<IFanOutGrain>(numChildren);\n        var childBase = (id + 1) * FanOutFactor;\n        for (var i = 1; i <= numChildren; i++)\n        {\n            var child = GrainFactory.GetGrain<IFanOutGrain>(childBase + i, forest);\n            _children.Add(child);\n        }\n\n        this.RegisterGrainTimer(() => Ping().AsTask(), TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5));\n    }\n\n    public async ValueTask Ping()\n    {\n        var tasks = new List<ValueTask>(_children.Count);\n        foreach (var child in _children)\n        {\n            tasks.Add(child.Ping());\n        }\n\n        // Wait for the tasks to complete.\n        foreach (var task in tasks)\n        {\n            await task;\n        }\n    }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/Properties/launchSettings.json",
    "content": "{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:14770\",\n      \"sslPort\": 44343\n    }\n  },\n  \"profiles\": {\n    \"http\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"http://localhost:5022\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"https\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:7000;http://localhost:5022\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    },\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/appsettings.Development.json",
    "content": "{\n  \"DetailedErrors\": true,\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/wwwroot/css/open-iconic/FONT-LICENSE",
    "content": "SIL OPEN FONT LICENSE Version 1.1\n\nCopyright (c) 2014 Waybury\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/wwwroot/css/open-iconic/ICON-LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Waybury\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/wwwroot/css/open-iconic/README.md",
    "content": "[Open Iconic v1.1.1](https://github.com/iconic/open-iconic)\n===========\n\n### Open Iconic is the open source sibling of [Iconic](https://github.com/iconic/open-iconic). It is a hyper-legible collection of 223 icons with a tiny footprint&mdash;ready to use with Bootstrap and Foundation. [View the collection](https://github.com/iconic/open-iconic)\n\n\n\n## What's in Open Iconic?\n\n* 223 icons designed to be legible down to 8 pixels\n* Super-light SVG files - 61.8 for the entire set\n* SVG sprite&mdash;the modern replacement for icon fonts\n* Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats\n* Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats\n* PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.\n\n\n## Getting Started\n\n#### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](https://github.com/iconic/open-iconic) and [Reference](https://github.com/iconic/open-iconic) sections.\n\n### General Usage\n\n#### Using Open Iconic's SVGs\n\nWe like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).\n\n```\n<img src=\"/open-iconic/svg/icon-name.svg\" alt=\"icon name\">\n```\n\n#### Using Open Iconic's SVG Sprite\n\nOpen Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.\n\nAdding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `<svg>` *tag and a unique class name for each different icon in the* `<use>` *tag.*\n\n```\n<svg class=\"icon\">\n  <use xlink:href=\"open-iconic.svg#account-login\" class=\"icon-account-login\"></use>\n</svg>\n```\n\nSizing icons only needs basic CSS. All the icons are in a square format, so just set the `<svg>` tag with equal width and height dimensions.\n\n```\n.icon {\n  width: 16px;\n  height: 16px;\n}\n```\n\nColoring icons is even easier. All you need to do is set the `fill` rule on the `<use>` tag.\n\n```\n.icon-account-login {\n  fill: #f00;\n}\n```\n\nTo learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).\n\n#### Using Open Iconic's Icon Font...\n\n\n##### …with Bootstrap\n\nYou can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`\n\n\n```\n<link href=\"/open-iconic/font/css/open-iconic-bootstrap.css\" rel=\"stylesheet\">\n```\n\n\n```\n<span class=\"oi oi-icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n##### …with Foundation\n\nYou can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`\n\n```\n<link href=\"/open-iconic/font/css/open-iconic-foundation.css\" rel=\"stylesheet\">\n```\n\n\n```\n<span class=\"fi-icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n##### …on its own\n\nYou can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`\n\n```\n<link href=\"/open-iconic/font/css/open-iconic.css\" rel=\"stylesheet\">\n```\n\n```\n<span class=\"oi\" data-glyph=\"icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n\n## License\n\n### Icons\n\nAll code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).\n\n### Fonts\n\nAll fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/wwwroot/css/site.css",
    "content": "@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');\n\nhtml, body {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\nh1:focus {\n    outline: none;\n}\n\na, .btn-link {\n    color: #0071c1;\n}\n\n.btn-primary {\n    color: #fff;\n    background-color: #1b6ec2;\n    border-color: #1861ac;\n}\n\n.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {\n  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;\n}\n\n.content {\n    padding-top: 1.1rem;\n}\n\n.valid.modified:not([type=checkbox]) {\n    outline: 1px solid #26b050;\n}\n\n.invalid {\n    outline: 1px solid red;\n}\n\n.validation-message {\n    color: red;\n}\n\n#blazor-error-ui {\n    background: lightyellow;\n    bottom: 0;\n    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);\n    display: none;\n    left: 0;\n    padding: 0.6rem 1.25rem 0.7rem 1.25rem;\n    position: fixed;\n    width: 100%;\n    z-index: 1000;\n}\n\n    #blazor-error-ui .dismiss {\n        cursor: pointer;\n        position: absolute;\n        right: 0.75rem;\n        top: 0.5rem;\n    }\n\n.blazor-error-boundary {\n    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;\n    padding: 1rem 1rem 1rem 3.7rem;\n    color: white;\n}\n\n    .blazor-error-boundary::after {\n        content: \"An error has occurred.\"\n    }\n"
  },
  {
    "path": "playground/ActivationRepartitioning/ActivationRepartitioning.Frontend/wwwroot/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Orleans Activation Rebalancing</title>\n    <link rel=\"stylesheet\" href=\"css/bootstrap/bootstrap.min.css\" />\n    <link href=\"css/site.css\" rel=\"stylesheet\" />\n    <link rel=\"icon\" type=\"image/png\" href=\"favicon.png\" />\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js\"></script>\n    <style>\n      body,\n      html {\n        margin: 0;\n        padding: 0;\n        width: 100%;\n        height: 100%;\n      }\n      #callGraphContainer {\n        width: 100%;\n        height: 100%;\n      }\n      svg {\n        width: 100%;\n        height: 100%;\n      }\n      text {\n        text-anchor: middle;\n        font-family: \"Helvetica Neue\", Helvetica, sans-serif;\n        font-size: 16px;\n      }\n      .absolute-button {\n        position: absolute;\n        padding: 10px 20px;\n        font-size: 20px;\n        border: none;\n        color: white;\n        background-color: #007bff;\n        cursor: pointer;\n      }\n      #addGrainsButton {\n        top: 10px;\n        left: 10px;\n      }\n      #resetButton {\n        top: 10px;\n        left: 200px;\n      }\n    </style>\n  </head>\n  <body>\n    <div id=\"callGraphContainer\">\n      <svg>\n        <g class=\"graph-container\">\n          <g class=\"links\"></g>\n          <g class=\"nodes\"></g>\n        </g>\n      </svg>\n    </div>\n    <button id=\"addGrainsButton\" class=\"absolute-button\">Add grains</button>\n    <button id=\"resetButton\" class=\"absolute-button\">Reset</button>\n    <script type=\"text/javascript\">\n      const state = { nodes: [], links: [], isUpdate: false };\n\n      const svg = d3.select(\"svg\");\n      let width = svg.node().clientWidth;\n      let height = svg.node().clientHeight;\n\n      function mergeObjects(updated, existing) {\n        for (let key in existing) {\n          if (existing.hasOwnProperty(key) && !updated.hasOwnProperty(key)) {\n            updated[key] = existing[key];\n          }\n        }\n      }\n\n      async function loadData() {\n        try {\n          const data = await fetch(\"/data.json\");\n          const jsonData = await data.json();\n          mergeData(jsonData);\n          renderGraph();\n        } catch (error) {\n          console.error(\"Error fetching or parsing data:\", error);\n        }\n      }\n\n      window.onload = async function () {\n        await loadData();\n      };\n\n      setInterval(async function () {\n        state.isUpdate = true;\n        await loadData();\n      }, 5000);\n\n      function mergeData(jsonData) {\n        const newHostNodes = jsonData.hostIds.map((d, i) => ({\n          id: \"host-\" + i,\n          name: d.name,\n          isHost: true,\n          index: i,\n          activationCount: d.activationCount,\n        }));\n\n        const newGrainNodes = jsonData.grainIds.map((d, i) => ({\n          id: \"grain-\" + d.name,\n          host: d.host,\n          name: d.name,\n          key: d.key,\n          type: 'grain',\n        }));\n        const newNodes = newHostNodes.concat(newGrainNodes);\n\n        const newGrainLinks = jsonData.edges.map((d) => {\n          var source = jsonData.grainIds[d.source];\n          var target = jsonData.grainIds[d.target];\n          return {\n            id: \"edge(\" + source.name + \",\" + target.name + \")\",\n            source: \"grain-\" + source.name,\n            target: \"grain-\" + target.name,\n            sourceHost: source.host,\n            targetHost: target.host,\n            weight: d.weight,\n            isHostLink: false,\n          };\n        });\n\n        const newHostLinks = jsonData.grainIds.map((d, i) => ({\n          id: \"host-edge(\" + d.name + \",\" + d.host + \")\",\n          source: \"grain-\" + d.name,\n          target: \"host-\" + d.host,\n          distance: 100,\n          isHostLink: true,\n          host: d.host,\n        }));\n\n        const hostToHostLinks = [];\n        for (let i = 0; i < newHostNodes.length; i++) {\n        for (let j = 0; j < newHostNodes.length; j++) {\n          if (i == j) continue;\n          hostToHostLinks.push({\n            id:\n              \"host-link(\" +\n              newHostNodes[i].id +\n              \",\" +\n              newHostNodes[j].id +\n              \")\",\n            source: newHostNodes[i].id,\n            target: newHostNodes[j].id,\n            isHostToHostLink: true,\n          });\n        }\n      }\n\n        const newLinks = newGrainLinks\n          .concat(newHostLinks)\n          .concat(hostToHostLinks);\n\n        // Merge new nodes and links into the existing state\n        const nodeMap = new Map(state.nodes.map((d) => [d.id, d]));\n        newNodes.forEach((node) => {\n          if (nodeMap.has(node.id)) {\n            mergeObjects(node, nodeMap.get(node.id));\n          } else {\n            node.x = width / 2;\n            node.y = height / 2;\n          }\n        });\n        state.nodes = Array.from(newNodes);\n        state.links = Array.from(newLinks);\n\n        state.maxEdgeValue = jsonData.maxEdgeValue;\n        state.maxActivationCount = jsonData.maxActivationCount;\n      }\n\n      function renderGraph() {\n        const graphContainer = svg.select(\".graph-container\");\n\n        var colorScheme = [...d3.schemeTableau10];\n        colorScheme.splice(2, 1); // Remove red since we use that for badness (inter-host links)\n        const color = d3.scaleOrdinal(colorScheme);\n        const linkColor = d3\n          .scaleSequential(d3.interpolateOrRd)\n          .domain([0, state.maxEdgeValue]);\n\n        const nodeData = graphContainer\n          .select(\".nodes\")\n          .selectAll(\"g\")\n          .data(state.nodes, (d) => d.id)\n          .join(\n            (enter) => {\n              var g = enter.append(\"g\");\n              g.append(\"circle\");\n              g.append(\"text\").attr(\"class\", \"label\");\n              g.filter((d) => d.isHost)\n                .append(\"text\")\n                .attr(\"class\", \"info\");\n              return g;\n            },\n            (update) => update,\n            (exit) => exit.remove()\n          );\n\n        // Grain label\n        nodeData\n          .select(\".label\")\n          .filter((d) => false /*d.type === 'grain'*/)\n          .text((d) => (d.key.includes(\"hosted-\") ? \"client\" : d.key))\n          .attr(\"dy\", -10);\n\n        // Host label\n        nodeData\n          .select(\".label\")\n          .filter((d) => d.isHost)\n          .text((d) => \"[\" + d.index + \"]\")\n          .attr(\"font-weight\", \"bold\")\n          .attr(\"dy\", -5);\n\n        // Host info\n        nodeData\n          .select(\".info\")\n          .filter((d) => d.isHost)\n          .attr(\"dy\", 15)\n          .text((d) => d.activationCount);\n\n        // Circle\n        nodeData\n          .select(\"circle\")\n          .attr(\"r\", (d) =>\n            d.isHost\n              ? 10 + (15 * d.activationCount) / state.maxActivationCount\n              : 8\n          )\n          .attr(\"stroke\", \"#222\")\n          .attr(\"stroke-width\", (d) => (d.isHost ? 2 : 1))\n          .attr(\"class\", (d) => (d.isHost ? \"host-circle\" : \"\"))\n          .attr(\"fill\", (d) => (d.isHost ? color(d.index) : color(d.host)));\n\n        // Links\n        const linkData = graphContainer\n          .select(\".links\")\n          .selectAll(\"line\")\n          .data(state.links, (d) => d.id)\n          .join(\n            (enter) => enter.append(\"line\"),\n            (update) => update,\n            (exit) => exit.remove()\n          )\n          .filter((d) => !d.isHostToHostLink)\n          .attr(\"stroke-width\", (d) =>\n            d.isHostLink ? 0.25 : 1 + d.weight / state.maxEdgeValue\n          )\n          .attr(\"stroke\", (d) =>\n            d.isHostLink\n              ? color(d.host)\n              : d.sourceHost == d.targetHost\n              ? color(d.sourceHost)\n              : \"red\"\n          );\n\n        if (state.simulation === undefined) {\n          state.simulation = d3\n            .forceSimulation(state.nodes)\n            .force(\n              \"center\",\n              d3.forceCenter(width / 2, height / 2).strength(0.05)\n            )\n            .force(\n              \"link\",\n              d3\n                .forceLink(state.links)\n                .id((d) => d.id)\n                .strength((d) =>\n                  d.isHostToHostLink ? 2 : d.isHostLink ? 1 : d.source.host == d.target.host ? 0.2 : 0.10 * (d.weight / state.maxEdgeValue)\n                )\n                .distance((d) =>\n                  d.isHostToHostLink ? 600 : d.isHostLink ? 150 : d.source.host == d.target.host ? 15 : 30 * (1 - (d.weight / state.maxEdgeValue))\n                )\n            )\n            .force(\n              \"charge\",\n              d3.forceManyBody().strength((d) => (d.isHost ? -150 : -50))\n            )\n            .alphaDecay(0.01) // Reduce alpha decay rate for gradual settling\n            .velocityDecay(0.3) // Reduce velocity decay rate for gradual settling\n            .on(\"tick\", ticked);\n\n          svg.call(\n            d3\n              .zoom()\n              .scaleExtent([0.1, 10])\n              .on(\"zoom\", (event) => {\n                graphContainer.attr(\"transform\", event.transform);\n              })\n          );\n        } else {\n          state.simulation.nodes(state.nodes);\n          state.simulation.force(\"link\").links(state.links);\n          state.simulation.on(\"tick\", ticked);\n          state.simulation.alpha(0.02).restart();\n        }\n\n        function ticked() {\n          linkData\n            .attr(\"x1\", (d) => d.source.x)\n            .attr(\"y1\", (d) => d.source.y)\n            .attr(\"x2\", (d) => d.target.x)\n            .attr(\"y2\", (d) => d.target.y);\n\n          nodeData.attr(\"transform\", (d) => `translate(${d.x},${d.y})`);\n        }\n\n        window.addEventListener(\"resize\", () => {\n          width = svg.node().clientWidth;\n          height = svg.node().clientHeight;\n          state.simulation.force(\n            \"center\",\n            d3.forceCenter(width / 2, height / 2)\n          );\n          state.simulation.alpha(1).restart();\n        });\n      }\n\n      async function postRequest(url) {\n        try {\n          const response = await fetch(url, {\n            method: \"POST\",\n            headers: {\n              \"Content-Type\": \"application/json\",\n            },\n          });\n          if (!response.ok) {\n            throw new Error(\"Network response was not ok\");\n          }\n          await loadData();\n        } catch (error) {\n          console.error(\"Error with the fetch operation:\", error);\n        }\n      }\n\n      document\n        .getElementById(\"addGrainsButton\")\n        .addEventListener(\"click\", () => {\n          postRequest(\"/add\");\n        });\n\n      document.getElementById(\"resetButton\").addEventListener(\"click\", () => {\n        postRequest(\"/reset\");\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "playground/ActivationSheddingToy/ActivationSheddingToy.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ServerGarbageCollection>true</ServerGarbageCollection>\n    <AssemblyName>ActivationSheddingToy</AssemblyName>\n    <RootNamespace>ActivationSheddingToy</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Server\\Orleans.Server.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ActivationSheddingToy/ActivationSheddingToyHostedService.cs",
    "content": "using Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Runtime;\nusing Orleans.Statistics;\n\ninternal sealed class ActivationSheddingToyHostedService(IGrainFactory grainFactory, IEnvironmentStatisticsProvider environmentStatisticsProvider) : BackgroundService\n{\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        var i = 0;\n        var tasks = new List<Task>();\n        var stats = new List<(int GrainCount, long UsageBytes)>();\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            while (tasks.Count < 10_000)\n            {\n                var grain = grainFactory.GetGrain<IActivationSheddingToyGrain>(++i);\n                tasks.Add(grain.Ping());\n            }\n\n            await Task.WhenAll(tasks);\n            tasks.Clear();\n\n            if (i % 100_000 == 0)\n            {\n                var activationCount = await grainFactory.GetGrain<IManagementGrain>(0).GetTotalActivationCount();\n                var envStats = environmentStatisticsProvider.GetEnvironmentStatistics();\n                while (envStats.MemoryUsagePercentage > 80)\n                {\n                    Console.WriteLine($\"Memory usage is high ({envStats.MemoryUsagePercentage:N2}%) with {activationCount} activations.\");\n                    GC.Collect();\n                    await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);\n                    envStats = environmentStatisticsProvider.GetEnvironmentStatistics();\n                    activationCount = await grainFactory.GetGrain<IManagementGrain>(0).GetTotalActivationCount();\n                }\n\n                PrintUsage(i, stats, envStats, activationCount);\n            }\n\n            if (stats.Count == 50)\n            {\n                using var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));\n                while (await timer.WaitForNextTickAsync(stoppingToken))\n                {\n                    var activationCount = await grainFactory.GetGrain<IManagementGrain>(0).GetTotalActivationCount();\n                    var envStats = environmentStatisticsProvider.GetEnvironmentStatistics();\n                    PrintUsage(i, stats, envStats, activationCount);\n                    if (stats.Count == 10)\n                    {\n                        break;\n                    }\n                }\n\n                break;\n            }\n        }\n\n        PlotAndPrintStats(stats);\n    }\n\n    private void PrintUsage(int i, List<(int GrainCount, long UsageBytes)> stats, EnvironmentStatistics envStats, int activationCount)\n    {\n        GC.Collect();\n        var usage = GC.GetTotalMemory(forceFullCollection: true);\n        stats.Add((i, usage));\n        Console.WriteLine($\"{i:N0} active grains. {usage:N0}bytes used. {usage / i:N0}bytes/grain (approx)\");\n        Console.WriteLine($\"\\t{envStats}\");\n        Console.WriteLine($\"\\tActivations: {activationCount}\");\n    }\n\n    private static void PlotAndPrintStats(List<(int GrainCount, long UsageBytes)> stats)\n    {\n        if (stats.Count < 2)\n        {\n            Console.WriteLine(\"Not enough data points to plot or calculate marginal usage.\");\n            return;\n        }\n\n        // Calculate and print marginal memory usage per grain\n        Console.WriteLine(\"Marginal memory usage per grain (bytes) between points:\");\n        for (int j = 1; j < stats.Count; j++)\n        {\n            int deltaGrains = stats[j].GrainCount - stats[j - 1].GrainCount;\n            long deltaBytes = stats[j].UsageBytes - stats[j - 1].UsageBytes;\n            double marginal = deltaGrains != 0 ? (double)deltaBytes / deltaGrains : double.NaN;\n            Console.WriteLine($\"{stats[j - 1].GrainCount:N0} -> {stats[j].GrainCount:N0}: {marginal:N2} bytes/grain\");\n        }\n    }\n}\n\ninternal sealed class ActivationSheddingToyGrain : Grain, IActivationSheddingToyGrain\n{\n    private byte[] _buffer = new byte[100_000];\n    public Task Ping()\n    {\n        _ = _buffer;\n        return Task.CompletedTask;\n    }\n}\n\ninternal interface IActivationSheddingToyGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n"
  },
  {
    "path": "playground/ActivationSheddingToy/Program.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args);\nbuilder.UseOrleans(orleans =>\n{\n    orleans.UseLocalhostClustering();\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n    orleans.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n});\n\nbuilder.Services.Configure<GrainCollectionOptions>(options =>\n{\n    options.EnableActivationSheddingOnMemoryPressure = true;\n    options.MemoryUsageLimitPercentage = 80;\n    options.MemoryUsageTargetPercentage = 50;\n});\n\nbuilder.Services.AddHostedService<ActivationSheddingToyHostedService>();\nawait builder.Build().RunAsync();\n\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.AppHost/ChaoticCluster.AppHost.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Sdk Name=\"Aspire.AppHost.Sdk\" Version=\"13.0.0\" />\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsAspireHost>true</IsAspireHost>\n    <UserSecretsId>8cceaca4-1c1f-473f-ac3a-6f220c8791cf</UserSecretsId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Hosting.AppHost\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ChaoticCluster.Silo\\ChaoticCluster.Silo.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.AppHost/Program.cs",
    "content": "using Projects;\n\nvar builder = DistributedApplication.CreateBuilder(args);\n\nbuilder.AddProject<ChaoticCluster_Silo>(\"silo\");\n\nbuilder.Build().Run();\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.AppHost/Properties/launchSettings.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n  \"profiles\": {\n    \"https\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:17213;http://localhost:15139\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"https://localhost:21045\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"https://localhost:22043\"\n      }\n    },\n    \"http\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"http://localhost:15139\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"DOTNET_ENVIRONMENT\": \"Development\",\n        \"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL\": \"http://localhost:19150\",\n        \"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL\": \"http://localhost:20085\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.AppHost/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.AppHost/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\",\n      \"Aspire.Hosting.Dcp\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.ServiceDefaults/ChaoticCluster.ServiceDefaults.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsAspireSharedProject>true</IsAspireSharedProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n\n    <PackageReference Include=\"Microsoft.Extensions.Http.Resilience\" />\n    <PackageReference Include=\"Microsoft.Extensions.ServiceDiscovery\" />\n    <PackageReference Include=\"OpenTelemetry.Exporter.OpenTelemetryProtocol\" />\n    <PackageReference Include=\"OpenTelemetry.Extensions.Hosting\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.AspNetCore\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Http\" />\n    <PackageReference Include=\"OpenTelemetry.Instrumentation.Runtime\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.ServiceDefaults/Extensions.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Diagnostics.HealthChecks;\nusing Microsoft.Extensions.Logging;\nusing OpenTelemetry;\nusing OpenTelemetry.Metrics;\nusing OpenTelemetry.Trace;\n\nnamespace Microsoft.Extensions.Hosting;\n// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.\n// This project should be referenced by each service project in your solution.\n// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults\npublic static class Extensions\n{\n    public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)\n    {\n        builder.ConfigureOpenTelemetry();\n\n        builder.AddDefaultHealthChecks();\n\n        builder.Services.AddServiceDiscovery();\n\n        builder.Services.ConfigureHttpClientDefaults(http =>\n        {\n            // Turn on resilience by default\n            http.AddStandardResilienceHandler();\n\n            // Turn on service discovery by default\n            http.AddServiceDiscovery();\n        });\n\n        // Uncomment the following to restrict the allowed schemes for service discovery.\n        // builder.Services.Configure<ServiceDiscoveryOptions>(options =>\n        // {\n        //     options.AllowedSchemes = [\"https\"];\n        // });\n\n        return builder;\n    }\n\n    public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)\n    {\n        builder.Logging.AddOpenTelemetry(logging =>\n        {\n            logging.IncludeFormattedMessage = true;\n            logging.IncludeScopes = true;\n        });\n\n        builder.Services.AddOpenTelemetry()\n            .WithMetrics(metrics =>\n            {\n                metrics.AddAspNetCoreInstrumentation()\n                    .AddHttpClientInstrumentation()\n                    .AddRuntimeInstrumentation()\n                    .AddMeter(\"System.Runtime\")\n                    .AddMeter(\"Microsoft.Orleans\");\n            });\n\n        builder.AddOpenTelemetryExporters();\n\n        return builder;\n    }\n\n    private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)\n    {\n        var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration[\"OTEL_EXPORTER_OTLP_ENDPOINT\"]);\n\n        if (useOtlpExporter)\n        {\n            builder.Services.AddOpenTelemetry().UseOtlpExporter();\n        }\n\n        // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)\n        //if (!string.IsNullOrEmpty(builder.Configuration[\"APPLICATIONINSIGHTS_CONNECTION_STRING\"]))\n        //{\n        //    builder.Services.AddOpenTelemetry()\n        //       .UseAzureMonitor();\n        //}\n\n        return builder;\n    }\n\n    public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)\n    {\n        builder.Services.AddHealthChecks()\n            // Add a default liveness check to ensure app is responsive\n            .AddCheck(\"self\", () => HealthCheckResult.Healthy(), [\"live\"]);\n\n        return builder;\n    }\n\n    public static WebApplication MapDefaultEndpoints(this WebApplication app)\n    {\n        // Adding health checks endpoints to applications in non-development environments has security implications.\n        // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.\n        if (app.Environment.IsDevelopment())\n        {\n            // All health checks must pass for app to be considered ready to accept traffic after starting\n            app.MapHealthChecks(\"/health\");\n\n            // Only health checks tagged with the \"live\" tag must pass for app to be considered alive\n            app.MapHealthChecks(\"/alive\", new HealthCheckOptions\n            {\n                Predicate = r => r.Tags.Contains(\"live\")\n            });\n        }\n\n        return app;\n    }\n}\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.Silo/ChaoticCluster.Silo.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net10.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ServerGarbageCollection>true</ServerGarbageCollection>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Azure\\Orleans.Clustering.AzureStorage\\Orleans.Clustering.AzureStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Server\\Orleans.Server.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"..\\ChaoticCluster.ServiceDefaults\\ChaoticCluster.ServiceDefaults.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.Silo/Program.cs",
    "content": "using System.Diagnostics;\nusing ChaoticCluster.Silo;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\n\nvar builder = Host.CreateApplicationBuilder(args);\nbuilder.AddServiceDefaults(); // Configure OTel\nusing var app = builder.Build();\nawait app.StartAsync();\n\nvar testClusterBuilder = new InProcessTestClusterBuilder(1);\ntestClusterBuilder.ConfigureSilo((options, siloBuilder) => new SiloBuilderConfigurator().Configure(siloBuilder));\ntestClusterBuilder.ConfigureSiloHost((options, hostBuilder) =>\n{\n    foreach (var provider in app.Services.GetServices<ILoggerProvider>())\n    {\n        hostBuilder.Logging.AddProvider(provider);\n    }\n});\n\ntestClusterBuilder.ConfigureClientHost(hostBuilder =>\n{\n    foreach (var provider in app.Services.GetServices<ILoggerProvider>())\n    {\n        hostBuilder.Logging.AddProvider(provider);\n    }\n});\n\nvar testCluster = testClusterBuilder.Build();\nawait testCluster.DeployAsync();\nvar log = testCluster.Client.ServiceProvider.GetRequiredService<ILogger<Program>>();\nlog.LogInformation($\"ServiceId: {testCluster.Options.ServiceId}\");\nlog.LogInformation($\"ClusterId: {testCluster.Options.ClusterId}\");\n\nvar cts = new CancellationTokenSource(TimeSpan.FromMinutes(15));\nvar reconfigurationTimer = Stopwatch.StartNew();\nvar upperLimit = 10;\nvar lowerLimit = 1; // Membership is kept on the primary, so we can't go below 1\nvar target = upperLimit;\nvar idBase = 0L;\nvar client = testCluster.Silos[0].ServiceProvider.GetRequiredService<IGrainFactory>();\nconst int CallsPerIteration = 100;\nconst int MaxGrains = 524_288; // 2**19;\n\nvar loadTask = Task.Run(async () =>\n{\n    while (!cts.IsCancellationRequested)\n    {\n        var time = Stopwatch.StartNew();\n        var tasks = Enumerable.Range(0, CallsPerIteration).Select(i => client.GetGrain<IMyTestGrain>((idBase + i) % MaxGrains).Ping().AsTask()).ToList();\n        var workTask = Task.WhenAll(tasks);\n        using var delayCancellation = new CancellationTokenSource();\n        var delay = TimeSpan.FromMilliseconds(90_000);\n        var delayTask = Task.Delay(delay, delayCancellation.Token);\n        await Task.WhenAny(workTask, delayTask);\n\n        try\n        {\n            await workTask;\n        }\n        catch (SiloUnavailableException sue)\n        {\n            log.LogInformation(sue, \"Swallowed transient exception.\");\n        }\n        catch (OrleansMessageRejectionException omre)\n        {\n           log.LogInformation(omre, \"Swallowed rejection.\");\n        }\n        catch (Exception exception)\n        {\n            log.LogError(exception, \"Unhandled exception.\");\n            throw;\n        }\n\n        delayCancellation.Cancel();\n        idBase += CallsPerIteration;\n    }\n});\n\nvar chaosTask = Task.Run(async () =>\n{\n    var clusterOperation = Task.CompletedTask;\n    while (!cts.IsCancellationRequested)\n    {\n        try\n        {\n            var remaining = TimeSpan.FromSeconds(10) - reconfigurationTimer.Elapsed;\n            if (remaining <= TimeSpan.Zero)\n            {\n                reconfigurationTimer.Restart();\n                await clusterOperation;\n\n                clusterOperation = Task.Run(async () =>\n                {\n                    var currentCount = testCluster.Silos.Count;\n\n                    if (currentCount > target)\n                    {\n                        // Stop or kill a random silo, but not the primary (since that hosts cluster membership)\n                        var victim = testCluster.Silos[Random.Shared.Next(1, testCluster.Silos.Count - 1)];\n                        if (currentCount % 2 == 0)\n                        {\n                            log.LogInformation($\"Stopping '{victim.SiloAddress}'.\");\n                            await testCluster.StopSiloAsync(victim);\n                            log.LogInformation($\"Stopped '{victim.SiloAddress}'.\");\n                        }\n                        else\n                        {\n                            log.LogInformation($\"Killing '{victim.SiloAddress}'.\");\n                            await testCluster.KillSiloAsync(victim);\n                            log.LogInformation($\"Killed '{victim.SiloAddress}'.\");\n                        }\n                    }\n                    else if (currentCount < target)\n                    {\n                        log.LogInformation(\"Starting new silo.\");\n                        var result = await testCluster.StartAdditionalSiloAsync();\n                        log.LogInformation($\"Started '{result.SiloAddress}'.\");\n                    }\n\n                    if (currentCount <= lowerLimit)\n                    {\n                        target = upperLimit;\n                    }\n                    else if (currentCount >= upperLimit)\n                    {\n                        target = lowerLimit;\n                    }\n                });\n            }\n            else\n            {\n                await Task.Delay(remaining);\n            }\n        }\n        catch (Exception exception)\n        {\n            log.LogInformation(exception, \"Ignoring chaos exception.\");\n        }\n    }\n});\n\nawait await Task.WhenAny(loadTask, chaosTask);\ncts.Cancel();\nawait Task.WhenAll(loadTask, chaosTask);\nawait testCluster.StopAllSilosAsync();\nawait testCluster.DisposeAsync();\n\nawait app.StopAsync();"
  },
  {
    "path": "playground/ChaoticCluster/ChaoticCluster.Silo/SiloBuilderConfigurator.cs",
    "content": "using Orleans.TestingHost;\n\nnamespace ChaoticCluster.Silo;\n\nclass SiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n            siloBuilder.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n        }\n    }\n\ninternal interface IMyTestGrain : IGrainWithIntegerKey\n{\n    ValueTask Ping();\n}\n\n[CollectionAgeLimit(Minutes = 1.01)]\ninternal class MyTestGrain : Grain, IMyTestGrain\n{\n    public ValueTask Ping() => default;\n}\n"
  },
  {
    "path": "playground/DashboardCohosted/DashboardCohosted.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <IsPackable>false</IsPackable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Dashboard\\Orleans.Dashboard\\Orleans.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\test\\Orleans.Dashboard.Tests\\Orleans.Dashboard.TestGrains\\Orleans.Dashboard.TestGrains.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Client\\Orleans.Client.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Persistence.Memory\\Orleans.Persistence.Memory.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/DashboardCohosted/Program.cs",
    "content": "using Orleans.Dashboard;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder.UseLocalhostClustering();\n    siloBuilder.UseInMemoryReminderService();\n    siloBuilder.AddMemoryGrainStorageAsDefault();\n\n    // Add the dashboard\n    siloBuilder.AddDashboard();\n});\n\nvar app = builder.Build();\n\n// Map dashboard endpoints at the root\napp.MapOrleansDashboard();\n\napp.Run();\n"
  },
  {
    "path": "playground/DashboardCohosted/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"DashboardCohosted\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"https://localhost:55355;http://localhost:55356\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/DashboardCohosted/README.md",
    "content": "# Orleans Dashboard - Cohosted Example\n\nThis example demonstrates how to cohost the Orleans Dashboard within the same web application that runs your Orleans silo.\n\n## Overview\n\nThis is the simplest way to add the Orleans Dashboard to your application. The dashboard is hosted within the same process as your silo, using ASP.NET Core minimal APIs.\n\n## Key Features\n\n- **Single Process**: Both Orleans and the dashboard run in the same web application\n- **Minimal Configuration**: Simple setup with just a few lines of code\n- **ASP.NET Core Integration**: Uses `WebApplication.CreateBuilder()` and minimal APIs\n\n## How It Works\n\nThe example shows:\n\n1. Creating a web application with `WebApplication.CreateBuilder()`\n2. Configuring Orleans using `builder.UseOrleans()`\n3. Adding the dashboard with `siloBuilder.AddDashboard()`\n4. Mapping dashboard endpoints with `app.MapOrleansDashboard()`\n\n## Running the Example\n\n```bash\ndotnet run\n```\n\nOnce running, open your browser to:\n- **Dashboard**: https://localhost:55355/ (or http://localhost:55356/)\n\n## Code Walkthrough\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder.UseLocalhostClustering();\n    siloBuilder.UseInMemoryReminderService();\n    siloBuilder.AddMemoryGrainStorageAsDefault();\n\n    // Add the dashboard\n    siloBuilder.AddDashboard();\n});\n\nvar app = builder.Build();\n\n// Map dashboard endpoints\napp.MapOrleansDashboard();\n\napp.Run();\n```\n\n## When to Use This Approach\n\nUse this cohosted approach when:\n- You want the simplest setup\n- You're building a web application that also hosts Orleans\n- You want dashboard access on the same port as your web app\n- You're running a single silo or don't need a centralized dashboard\n\n## Customization\n\n### Custom Route Prefix\n\n```csharp\napp.MapOrleansDashboard(routePrefix: \"/dashboard\");\n```\n\n### Add Authentication\n\n```csharp\napp.MapOrleansDashboard().RequireAuthorization();\n```\n\n### Configure Update Interval\n\n```csharp\nsiloBuilder.AddDashboard(options =>\n{\n    options.CounterUpdateIntervalMs = 2000; // Update every 2 seconds\n});\n```\n\n## Important Notes\n\n> [!WARNING]\n> The Orleans Dashboard is designed for **development and testing scenarios only**. It is not recommended for production deployments as it can have a significant performance impact on your cluster.\n\n## Related Examples\n\n- **DashboardSeparateHost**: Shows how to host the dashboard in a separate application\n- **DashboardToy**: Advanced example with .NET Aspire integration\n\n## Learn More\n\n- [Orleans Dashboard Documentation](../../../src/Dashboard/Orleans.Dashboard/README.md)\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n"
  },
  {
    "path": "playground/DashboardSeparateHost/DashboardSeparateHost.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <IsPackable>false</IsPackable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Dashboard\\Orleans.Dashboard\\Orleans.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\test\\Orleans.Dashboard.Tests\\Orleans.Dashboard.TestGrains\\Orleans.Dashboard.TestGrains.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Client\\Orleans.Client.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Persistence.Memory\\Orleans.Persistence.Memory.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "playground/DashboardSeparateHost/Program.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.Dashboard;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\nusing System.Net;\nusing TestGrains;\n\n//\n// In this sample we integrate the Dashboard Minimal APIs into the client application.\n//\nvar siloHostBuilder = Host.CreateApplicationBuilder(args);\nsiloHostBuilder.UseOrleans(builder =>\n{\n    builder.UseDevelopmentClustering(options => options.PrimarySiloEndpoint = new IPEndPoint(IPAddress.Loopback, 11111));\n    builder.UseInMemoryReminderService();\n    builder.AddMemoryGrainStorageAsDefault();\n    builder.ConfigureEndpoints(IPAddress.Loopback, 11111, 30000);\n    builder.AddDashboard();\n});\nsiloHostBuilder.Services.AddSingleton<IHostedService, TestGrainsHostedService>();\nusing var siloHost = siloHostBuilder.Build();\n\nawait siloHost.StartAsync();\n\nawait Task.Delay(1000);\n\n// Create a WebApplication for hosting the dashboard\nvar dashboardBuilder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans client\ndashboardBuilder.UseOrleansClient(clientBuilder =>\n{\n    clientBuilder.UseStaticClustering(options => options.Gateways.Add(new IPEndPoint(IPAddress.Loopback, 30000).ToGatewayUri()));\n\n    // Add dashboard services\n    clientBuilder.AddDashboard();\n});\n\nvar dashboardApp = dashboardBuilder.Build();\n\n// Map dashboard endpoints\ndashboardApp.MapOrleansDashboard();\n\nawait dashboardApp.RunAsync();\n\nawait siloHost.StopAsync();\n"
  },
  {
    "path": "playground/DashboardSeparateHost/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"DashboardSeparateHost\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"https://localhost:55355;http://localhost:55356\"\n    }\n  }\n}\n"
  },
  {
    "path": "playground/DashboardSeparateHost/README.md",
    "content": "# Orleans Dashboard - Separate Host Example\n\nThis example demonstrates how to host the Orleans Dashboard in a separate web application that connects to an Orleans cluster as a client.\n\n## Overview\n\nThis approach separates the dashboard web service from your silos.\n\n## Key Features\n\n- **Separate Process**: Dashboard web service runs independently from Orleans silos\n- **Client Connection**: Connects to the Orleans cluster as an Orleans client\n- **Standalone Silo**: Includes a separate silo host for demonstration\n- **Test Grains**: Includes test grains to generate activity for the dashboard\n\n## How It Works\n\nThe example consists of two components:\n\n1. **Silo Host**: A standalone Orleans silo that runs independently\n2. **Dashboard Web App**: A web application that connects as an Orleans client and hosts the dashboard\n\n## Running the Example\n\n```bash\ndotnet run\n```\n\nThe application will:\n1. Start an Orleans silo on ports 11111 (silo) and 30000 (gateway)\n2. Start the dashboard web application\n3. Generate test grain activity automatically\n\nOnce running, open your browser to the default ports (typically https://localhost:5001 or http://localhost:5000).\n\n## Code Walkthrough\n\n### Silo Host\n\n```csharp\nvar siloHost = Host.CreateDefaultBuilder(args)\n    .UseOrleans((_, builder) =>\n    {\n        builder.UseDevelopmentClustering(options =>\n            options.PrimarySiloEndpoint = new IPEndPoint(IPAddress.Loopback, 11111));\n        builder.ConfigureEndpoints(IPAddress.Loopback, 11111, 30000);\n        builder.AddDashboard();\n        // ... other configuration\n    })\n    .Build();\n```\n\n### Dashboard Client\n\n```csharp\nvar dashboardBuilder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans client\ndashboardBuilder.UseOrleansClient(clientBuilder =>\n{\n    clientBuilder.UseStaticClustering(options =>\n        options.Gateways.Add(new IPEndPoint(IPAddress.Loopback, 30000).ToGatewayUri()));\n\n    // Add dashboard services\n    clientBuilder.AddDashboard();\n});\n\nvar app = dashboardBuilder.Build();\n\n// Map dashboard endpoints\napp.MapOrleansDashboard();\n\nawait app.RunAsync();\n```\n\n\n## Architecture\n\n```\n┌─────────────────┐\n│  Silo Host      │\n│  (Port 11111)   │\n│  Gateway: 30000 │\n└────────▲────────┘\n         │\n         │ Orleans Client Connection\n         │\n┌────────┴────────┐\n│  Dashboard      │\n│  Web App        │\n│  (Port 5000)    │\n└─────────────────┘\n```\n\n## Customization\n\n### Connect to Remote Cluster\n\n```csharp\ndashboardBuilder.UseOrleansClient(clientBuilder =>\n{\n    clientBuilder.UseStaticClustering(options =>\n    {\n        options.Gateways.Add(new IPEndPoint(IPAddress.Parse(\"10.0.0.1\"), 30000).ToGatewayUri());\n        options.Gateways.Add(new IPEndPoint(IPAddress.Parse(\"10.0.0.2\"), 30000).ToGatewayUri());\n    });\n\n    clientBuilder.AddDashboard();\n});\n```\n\n### Custom Route Prefix\n\n```csharp\napp.MapOrleansDashboard(routePrefix: \"/dashboard\");\n```\n\n### Add Authentication\n\n```csharp\napp.MapOrleansDashboard().RequireAuthorization();\n```\n\n## Important Notes\n\n> [!WARNING]\n> The Orleans Dashboard is designed for **development and testing scenarios only**. It is not recommended for production deployments as it can have a significant performance impact on your cluster.\n\n## Related Examples\n\n- **DashboardCohosted**: Shows how to host the dashboard within a silo\n- **DashboardToy**: Advanced example with .NET Aspire integration\n\n## Learn More\n\n- [Orleans Dashboard Documentation](../../../src/Dashboard/Orleans.Dashboard/README.md)\n- [Orleans Client Configuration](https://learn.microsoft.com/dotnet/orleans/host/configuration-guide/client-configuration)\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n"
  },
  {
    "path": "playground/Directory.Build.props",
    "content": "<Project>\n  <PropertyGroup>\n    <_ParentDirectoryBuildPropsPath Condition=\"'$(_DirectoryBuildPropsFile)' != ''\">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildPropsFile)'))</_ParentDirectoryBuildPropsPath>\n  </PropertyGroup>\n\n  <Import Project=\"$(_ParentDirectoryBuildPropsPath)\" Condition=\"Exists('$(_ParentDirectoryBuildPropsPath)')\"/>\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <GenerateDocumentationFile>false</GenerateDocumentationFile>\n    <ServerGarbageCollection>true</ServerGarbageCollection>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/README.md",
    "content": "# Orleans Samples\n\n> [!IMPORTANT]\n> 📢 This collection of samples has been moved to the official [`dotnet/samples` repository](https://github.com/dotnet/samples/tree/main/orleans) and is part of the [Samples browser experience](https://learn.microsoft.com/en-us/samples/browse/?expanded=dotnet&products=dotnet-orleans).\n\n- :octocat: [dotnet/samples](https://github.com/dotnet/samples/tree/main/orleans)\n- :eyes: [Samples browser](https://learn.microsoft.com/samples/browse/?expanded=dotnet&products=dotnet-orleans)\n\n## [Hello, World!](https://learn.microsoft.com/samples/dotnet/samples/orleans-hello-world-sample-app)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/HelloWorld/code.png\" />\n</p>\n\nA *Hello, World!* application which demonstrates how to create and use your first grains.\n\n### Demonstrates\n\n- How to get started with Orleans\n- How to define and implement grain interface\n- How to get a reference to a grain and call a grain\n\n## [Adventure](https://learn.microsoft.com/samples/dotnet/samples/orleans-text-adventure-game)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Adventure/assets/BoxArt.jpg\" />\n</p>\n\nBefore there were graphical user interfaces, before the era of game consoles and massive-multiplayer games, there were VT100 terminals and there was [Colossal Cave Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), [Zork](https://en.wikipedia.org/wiki/Zork), and [Microsoft Adventure](https://en.wikipedia.org/wiki/Microsoft_Adventure).\nPossibly lame by today's standards, back then it was a magical world of monsters, chirping birds, and things you could pick up.\nIt's the inspiration for this sample.\n\n### Demonstrates\n\n- How to structure an application (in this case, a game) using grains\n- How to connect an external client to an Orleans cluster (`ClientBuilder`)\n\n## [Chirper](https://learn.microsoft.com/samples/dotnet/samples/orleans-chirper-social-media-sample-app)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Chirper/screenshot.png\" />\n</p>\n\nA social network pub/sub system, with short text messages being sent between users.\nPublishers send out short *\"Chirp\"* messages (not to be confused with *\"Tweets\"*, for a variety of legal reasons) to any other users that are following them.\n\n### Demonstrates\n\n- How to build a simplified social media / social network application using Orleans\n- How to store state within a grain using grain persistence (`IPersistentState<T>`)\n- Grains which implement multiple grain interfaces\n- Reentrant grains, which allow for multiple grain calls to be executed concurrently, in a single-threaded, interleaving fashion\n- Using a *grain observer* (`IGrainObserver`) to receive push notifications from grains\n\n## [GPS Tracker](https://learn.microsoft.com/samples/dotnet/samples/orleans-gps-device-tracker-sample)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/GPSTracker/screenshot.jpeg\" />\n</p>\n\nA service for tracking GPS-equipped [IoT](https://en.wikipedia.org/wiki/Internet_of_Things) devices on a map.\nDevice locations are updated in near-real-time using SignalR and hence this sample demonstrates one approach to integrating Orleans with SignalR.\nThe device updates originate from a *device gateway*, which is implemented using a separate process which connects to the main service and simulates a number of devices moving in a pseudorandom fashion around an area of San Francisco.\n\n### Demonstrates\n\n- How to use Orleans to build an [Internet of Things](https://en.wikipedia.org/wiki/Internet_of_Things) application\n- How Orleans can be co-hosted and integrated with [ASP.NET Core SignalR](https://docs.microsoft.com/aspnet/core/signalr/introduction)\n- How to broadcast real-time updates from a grain to a set of clients using Orleans and SignalR\n\n## [HanBaoBao](https://github.com/ReubenBond/hanbaobao-web)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/ReubenBond/hanbaobao-web/main/assets/demo-1.png\" />\n</p>\n\nAn English-Mandarin dictionary Web application demonstrating deployment to Kubernetes, fan-out grain calls, and request throttling.\n\n### Demonstrates\n\n- How to build a realistic application using Orleans\n- How to deploy an Orleans-based application to Kubernetes\n- How to integrate Orleans with ASP.NET Core and a [*Single-page Application*](https://en.wikipedia.org/wiki/Single-page_application) JavaScript framework ([Vue.js](https://vuejs.org/))\n- How to implement leaky-bucket request throttling\n- How to load and query data from a database\n- How to cache results lazily and temporarily\n- How to fan-out requests to many grains and collect the results\n\n## [Presence Service](https://learn.microsoft.com/samples/dotnet/samples/orleans-gaming-presence-service-sample)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Presence/screenshot.png\" />\n</p>\n\nA gaming presence service, similar to one of the Orleans-based services built for [Halo](https://www.xbox.com/games/halo).\nA presence service tracks players and game sessions in near-real-time.\n\n### Demonstrates\n\n- A simplified version of a real-world use of Orleans\n- Using a *grain observer* (`IGrainObserver`) to receive push notifications from grains\n\n## [Tic Tac Toe](https://learn.microsoft.com/samples/dotnet/samples/orleans-tictactoe-web-based-game)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/TicTacToe/logo.png\"/>\n</p>\n\nA Web-based [Tic-tac-toe](https://en.wikipedia.org/wiki/Tic-tac-toe) game using ASP.NET MVC, JavaScript, and Orleans.\n\n### Demonstrates\n\n- How to build an online game using Orleans\n- How to build a basic game lobby system\n- How to access Orleans grains from an ASP.NET Core MVC application\n\n## [Voting](https://learn.microsoft.com/samples/dotnet/samples/orleans-voting-sample-app-on-kubernetes)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Voting/screenshot.png\"/>\n</p>\n\nA Web application for voting on a set of choices. This sample demonstrates deployment to Kubernetes.\nThe application uses [.NET Generic Host](https://docs.microsoft.com/dotnet/core/extensions/generic-host) to co-host [ASP.NET Core](https://docs.microsoft.com/aspnet/core) and Orleans as well as the [Orleans Dashboard](https://www.nuget.org/packages/Microsoft.Orleans.Dashboard) together in the same process.\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Voting/dashboard.png\"/>\n</p>\n\n### Demonstrates\n\n- How to deploy an Orleans-based application to Kubernetes\n- How to configure the [Orleans Dashboard](https://www.nuget.org/packages/Microsoft.Orleans.Dashboard)\n\n## [Chat Room](https://learn.microsoft.com/samples/dotnet/samples/orleans-chat-room-sample)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/ChatRoom/screenshot.png\" />\n</p>\n\nA terminal-based chat application built using [Orleans Streams](https://docs.microsoft.com/dotnet/orleans/streaming).\n\n### Demonstrates\n\n- How to build a chat application using Orleans\n- How to use [Orleans Streams](https://docs.microsoft.com/dotnet/orleans/streaming)\n\n## [Bank Account](https://learn.microsoft.com/samples/dotnet/samples/orleans-bank-account-acid-transactions)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/BankAccount/assets/BankClient.png\"/>\n</p>\n\nSimulates bank accounts, using ACID transactions to transfer random amounts between a set of accounts.\n\n### Demonstrates\n\n- How to use Orleans Transactions to safely perform operations involving multiple stateful grains with ACID guarantees and serializable isolation.\n\n## [Blazor Server](https://learn.microsoft.com/samples/dotnet/samples/orleans-aspnet-core-blazor-server-sample) and [Blazor WebAssembly](https://learn.microsoft.com/samples/dotnet/samples/orleans-aspnet-core-blazor-wasm-sample)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Blazor/BlazorServer/screenshot.jpeg\"/>\n</p>\n\nThese two Blazor samples are based on the [Blazor introductory tutorials](https://dotnet.microsoft.com/learn/aspnet/blazor-tutorial/intro), adapted for use with Orleans.\nThe [Blazor WebAssembly](./Blazor/BlazorWasm/#readme) sample uses the [Blazor WebAssembly hosting model](https://docs.microsoft.com/aspnet/core/blazor/hosting-models#blazor-webassembly).\nThe [Blazor Server](./Blazor/BlazorServer/#readme) sample uses the [Blazor Server hosting model](https://docs.microsoft.com/aspnet/core/blazor/hosting-models#blazor-server).\nThey include an interactive counter, a TODO list, and a Weather service.\n\n### Demonstrates\n\n- How to integrate ASP.NET Core Blazor Server with Orleans\n- How to integrate ASP.NET Core Blazor WebAssembly (WASM) with Orleans\n\n## [Stocks](https://learn.microsoft.com/samples/dotnet/samples/orleans-stocks-sample-app)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/Stocks/screenshot.png\" />\n</p>\n\nA stock price application which fetches prices from a remote service using an HTTP call and caches prices temporarily in a grain.\nA [`BackgroundService`](https://docs.microsoft.com/aspnet/core/fundamentals/host/hosted-services#backgroundservice-base-class) periodically polls for updates stock prices from various `StockGrain` grains which correspond to a set of stock symbols.\n\n### Demonstrates\n\n- How to use Orleans from within a [`BackgroundService`](https://docs.microsoft.com/aspnet/core/fundamentals/host/hosted-services#backgroundservice-base-class).\n- How to use timers within a grain\n- How to make external service calls using .NET's `HttpClient` and cache the results within a grain.\n\n## [Transport Layer Security](https://learn.microsoft.com/samples/dotnet/samples/orleans-transport-layer-security-tls)\n\n<p align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/dotnet/samples/main/orleans/TransportLayerSecurity/screenshot.png\" />\n</p>\n\nA *Hello, World!* application configured to use mutual [*Transport Layer Security*](https://en.wikipedia.org/wiki/Transport_Layer_Security) to secure network communication between every server.\n\n### Demonstrates\n\n- How to configure mutual-TLS (mTLS) authentication for Orleans\n\n## [General Examples - Road to Orleans](https://github.com/PiotrJustyna/road-to-orleans/)\n\nA compiled list of examples varying in difficulty.\n\n### Demonstrates\n\n- How to develop Orleans-based applications\n\n## [Visual Basic Hello World](https://github.com/dotnet/samples/tree/main/orleans/VBHelloWorld/README.md)\n\nA *Hello, World!* application using Visual Basic.\n\n### Demonstrates\n\n- How to develop Orleans-based applications using Visual Basic\n\n## [F# Hello World](https://github.com/dotnet/samples/tree/main/orleans/FSharpHelloWorld/README.md)\n\nA *Hello, World!* application using F#.\n\n### Demonstrates\n\n- How to develop Orleans-based applications using F#\n\n## [F# Hello World written in F# end to end](https://github.com/PiotrJustyna/road-to-orleans/tree/main/5a#readme)\n\nIn-memory clustering example where everything is written in F#:\n\n- Clustered Silos\n- Concurrent Clients\n- Grains\n- Interfaces\n\n### Demonstrates\n\n- How to develop Orleans-based applications using F# end to end\n\n## [F# Reminder](https://github.com/PiotrJustyna/road-to-orleans/tree/main/1b#readme)\n\n- How to use grain reminders in an F# grain\n\n### Demonstrates\n\n- How to develop a reminder grain in F#\n\n## [F# Grain Service](https://github.com/PiotrJustyna/road-to-orleans/tree/main/1c#readme)\n\n- How to use grain service from other grains in F#\n\n### Demonstrates\n\n- How to develop grain service and grain service client in F#\n\n## [Streaming: Pub/Sub Streams over Azure Event Hubs](https://learn.microsoft.com/samples/dotnet/samples/orleans-streaming-pubsub-with-azure-event-hub)\n\nAn application using Orleans Streams with [Azure Event Hubs](https://azure.microsoft.com/services/event-hubs/) as the provider and implicit subscribers.\n\n### Demonstrates\n\n- How to use [Orleans Streams](https://docs.microsoft.com/dotnet/orleans/streaming)\n- How to use the `[ImplicitStreamSubscription(namespace)]` attribute to implicitly subscribe a grain to the stream with the corresponding id\n- How to configure Orleans Streams for use with [Azure Event Hubs](https://azure.microsoft.com/services/event-hubs/)\n\n## [Streaming: Custom Data Adapter](https://learn.microsoft.com/samples/dotnet/samples/orleans-streaming-custom-data-adapter)\n\nAn application using Orleans Streams with a non-Orleans publisher pushing to a stream which a grain consumes via a *custom data adapter* which tells Orleans how to interpret stream messages.\n\n### Demonstrates\n\n- How to use [Orleans Streams](https://docs.microsoft.com/dotnet/orleans/streaming)\n- How to use the `[ImplicitStreamSubscription(namespace)]` attribute to implicitly subscribe a grain to the stream with the corresponding id\n- How to configure Orleans Streams for use with [Azure Event Hubs](https://azure.microsoft.com/services/event-hubs/)\n- How to consume stream messages published by non-Orleans publishers by providing a custom `EventHubDataAdapter` implementation (a custom data adapter)\n"
  },
  {
    "path": "sign/NuGet.Config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <add key=\"dotnet-eng\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json\" />\n    <add key=\"dotnet-public\" value=\"https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json\" />\n  </packageSources>\n  <packageSourceMapping>\n    <packageSource key=\"dotnet-public\">\n      <package pattern=\"vswhere\" />\n      <package pattern=\"MicroBuild.Core\" />\n    </packageSource>\n    <packageSource key=\"dotnet-eng\">\n      <package pattern=\"*\" />\n    </packageSource>\n  </packageSourceMapping>\n  <disabledPackageSources>\n    <clear />\n  </disabledPackageSources>\n</configuration>\n"
  },
  {
    "path": "sign/Sign.proj",
    "content": "<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->\n<Project DefaultTargets=\"Sign\">\n\n  <PropertyGroup>\n    <!-- Respect environment variable for the NuGet Packages Root if set; otherwise, use the current default location -->\n    <NuGetPackageRoot Condition=\"'$(NuGetPackageRoot)' != ''\">$([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)'))</NuGetPackageRoot>\n    <NuGetPackageRoot Condition=\"'$(NuGetPackageRoot)' == '' and '$(NUGET_PACKAGES)' != ''\">$([MSBuild]::NormalizeDirectory('$(NUGET_PACKAGES)'))</NuGetPackageRoot>\n    <NuGetPackageRoot Condition=\"'$(NuGetPackageRoot)' == '' and '$(OS)' == 'Windows_NT'\">$([MSBuild]::NormalizeDirectory('$(UserProfile)', '.nuget', 'packages'))</NuGetPackageRoot>\n    <NuGetPackageRoot Condition=\"'$(NuGetPackageRoot)' == '' and '$(OS)' != 'Windows_NT'\">$([MSBuild]::NormalizeDirectory('$(HOME)', '.nuget', 'packages'))</NuGetPackageRoot>\n    <ArtifactsTmpDir>$(MSBuildProjectDirectory)\\..\\bin\\tmp\\</ArtifactsTmpDir>\n    <ArtifactsLogDir>$(MSBuildProjectDirectory)\\..\\bin\\logs\\</ArtifactsLogDir>\n  </PropertyGroup>\n\n  <Import Project=\"$(NuGetPackageRoot)microsoft.dotnet.signtool\\6.0.0-beta.20630.2\\build\\Microsoft.DotNet.SignTool.props\" />\n\n  <Import Project=\"Sign.props\" />\n\n  <Target Name=\"Sign\">\n    <Error Text=\"The value of DotNetSignType is invalid: '$(DotNetSignType)'\"\n           Condition=\"'$(DotNetSignType)' != 'real' and '$(DotNetSignType)' != 'test' and '$(DotNetSignType)' != ''\" />\n\n    <PropertyGroup>\n      <_DryRun>false</_DryRun>\n      <_TestSign>false</_TestSign>\n      <_DesktopMSBuildRequired>false</_DesktopMSBuildRequired>\n      <_DesktopMSBuildRequired>true</_DesktopMSBuildRequired>\n      <DoStrongNameCheck>false</DoStrongNameCheck>\n    </PropertyGroup>\n\n    <Error Condition=\"'$(AllowEmptySignList)' != 'true' AND '@(ItemsToSign)' == ''\" \n           Text=\"List of files to sign is empty. Make sure that ItemsToSign is configured correctly.\" />\n\n    <!-- We only need this if we are going to use the executable version. -->\n    <Exec Command='\"$(NuGetPackageRoot)vswhere\\2.6.7\\tools\\vswhere.exe\" -latest -prerelease -property installationPath -requires Microsoft.Component.MSBuild'\n          ConsoleToMsBuild=\"true\"\n          StandardErrorImportance=\"high\"\n          Condition=\"$(_DesktopMSBuildRequired)\">\n      <Output TaskParameter=\"ConsoleOutput\" PropertyName=\"_VSInstallDir\" />\n    </Exec>\n\n    <Message Text=\"Signing files\" Importance=\"High\"/>\n\n    <PropertyGroup Condition=\"$(_DesktopMSBuildRequired)\">\n      <_DesktopMSBuildPath>$(_VSInstallDir)\\MSBuild\\Current\\Bin\\msbuild.exe</_DesktopMSBuildPath>\n      <_DesktopMSBuildPath Condition=\"!Exists('$(_DesktopMSBuildPath)')\">$(_VSInstallDir)\\MSBuild\\15.0\\Bin\\msbuild.exe</_DesktopMSBuildPath>\n    </PropertyGroup>\n\n    <Microsoft.DotNet.SignTool.SignToolTask\n        DryRun=\"$(_DryRun)\"\n        TestSign=\"$(_TestSign)\"\n        DoStrongNameCheck=\"$(DoStrongNameCheck)\"\n        AllowEmptySignList=\"$(AllowEmptySignList)\"\n        CertificatesSignInfo=\"@(CertificatesSignInfo)\"\n        ItemsToSign=\"@(ItemsToSign)\"\n        StrongNameSignInfo=\"@(StrongNameSignInfo)\"\n        FileSignInfo=\"@(FileSignInfo)\"\n        FileExtensionSignInfo=\"@(FileExtensionSignInfo)\"\n        TempDir=\"$(ArtifactsTmpDir)\"\n        LogDir=\"$(ArtifactsLogDir)\"\n        MSBuildPath=\"$(_DesktopMSBuildPath)\"\n        SNBinaryPath=\"$(NuGetPackageRoot)sn\\1.0.0\\sn.exe\"\n        MicroBuildCorePath=\"$(NuGetPackageRoot)microbuild.core\\0.2.0\"/>\n  </Target>\n</Project>"
  },
  {
    "path": "sign/Sign.props",
    "content": "<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->\n<Project>\n\n  <PropertyGroup>\n    <!-- By default, search for sign aritfacts under the list of known directories. -->\n    <EnableDefaultArtifacts>true</EnableDefaultArtifacts>\n  </PropertyGroup>\n\n  <Import Project=\"..\\Directory.Build.props\" />\n\n  <!-- Repo extension point to sign and/or publish. Artifacts are shipping and blobs by default. -->\n  <ItemDefinitionGroup>\n    <Artifact>\n      <PublishFlatContainer>true</PublishFlatContainer>\n      <IsShipping>true</IsShipping>\n    </Artifact>\n  </ItemDefinitionGroup>\n\n  <ItemGroup>\n    <!--\n      This is intended to hold information about the certificates used for signing.\n      For now the only information required is whether or not the certificate can be\n      used for signing already signed files - DualSigningAllowed==true.\n    -->\n    <CertificatesSignInfo Include=\"3PartyDual\" DualSigningAllowed=\"true\" />\n    <CertificatesSignInfo Include=\"3PartySHA2\" DualSigningAllowed=\"true\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(EnableDefaultArtifacts)' == 'true'\">\n    <ItemsToSign Include=\"$(PackageOutputPath)\\*.nupkg\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <!-- Default certificate/strong-name to be used for all files with PKT==\"31bf3856ad364e35\". -->\n    <StrongNameSignInfo Include=\"MsSharedLib72\" PublicKeyToken=\"31bf3856ad364e35\" CertificateName=\"Microsoft400\" />\n    <StrongNameSignInfo Include=\"SilverlightCert121\" PublicKeyToken=\"7cec85d7bea7798e\" CertificateName=\"Microsoft400\" />\n    <StrongNameSignInfo Include=\"StrongName\" PublicKeyToken=\"b77a5c561934e089\" CertificateName=\"Microsoft400\" />\n    <StrongNameSignInfo Include=\"StrongName\" PublicKeyToken=\"b03f5f7f11d50a3a\" CertificateName=\"Microsoft400\" />\n    <StrongNameSignInfo Include=\"$(MSBuildThisFileDirectory)snk\\Open.snk\" PublicKeyToken=\"cc7b13ffcd2ddd51\" CertificateName=\"Microsoft400\" />\n\n    <!--\n      Map of file extensions to default certificate name. Files with these extensions are\n      signed with the specified certificate. Particularly useful for files that don't have\n      a public key token.\n      The certificate can be overriden using the StrongNameSignInfo or the FileSignInfo item group.\n    -->\n    <FileExtensionSignInfo Include=\".jar\" CertificateName=\"MicrosoftJARSHA2\" />\n    <FileExtensionSignInfo Include=\".js;.ps1;.psd1;.psm1;.psc1;.py\" CertificateName=\"Microsoft400\" />\n    <FileExtensionSignInfo Include=\".dll;.exe;.mibc\" CertificateName=\"Microsoft400\" />\n    <FileExtensionSignInfo Include=\".nupkg\" CertificateName=\"NuGet\" />\n    <FileExtensionSignInfo Include=\".vsix\" CertificateName=\"VsixSHA2\" />\n    <FileExtensionSignInfo Include=\".zip\" CertificateName=\"None\" />\n    <FileExtensionSignInfo Include=\".tgz\" CertificateName=\"None\" />\n  </ItemGroup>\n\n  <!-- The name of the .NET specific certificate, which is a general replacement for Microsoft400\n       If UseDotNetCert is specific in a repo's eng/Signing.props, all usage of Microsoft400 is replaced\n       with MicrosoftDotNet500 -->\n  <PropertyGroup>\n    <DotNetCertificateName>MicrosoftDotNet500</DotNetCertificateName>\n    <UseDotNetCertificate>false</UseDotNetCertificate>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <!-- Flags for controlling whether empty signing lists are detected for in build and post-build signing.\n         These flags are split (rather than just a single check based on PostBuildSign == true/false because\n         some repos may do both in-build and post-build signing. -->\n    <!-- Control whether an empty ItemsToSign item group is allowed when calling SignToolTask. -->\n    <AllowEmptySignList Condition=\"'$(PostBuildSign)' != 'true'\">false</AllowEmptySignList>\n    <AllowEmptySignList Condition=\"'$(PostBuildSign)' == 'true'\">true</AllowEmptySignList>\n    <!-- Control whether an empty ItemsToSignPostBuild item group is allowed during publishing -->\n    <AllowEmptySignPostBuildList Condition=\"'$(PostBuildSign)' != 'true'\">true</AllowEmptySignPostBuildList>\n    <AllowEmptySignPostBuildList Condition=\"'$(PostBuildSign)' == 'true'\">false</AllowEmptySignPostBuildList>\n\n    <NETCORE_ENGINEERING_TELEMETRY>Signing</NETCORE_ENGINEERING_TELEMETRY>\n  </PropertyGroup>\n\n  <!-- Sign tool parallelism limits. These may be overridden by a repo. -->\n  <PropertyGroup>\n    <!-- Number of containers to repack in parallel -->\n    <SignToolRepackParallelism>16</SignToolRepackParallelism>\n    <!-- Maximum size in MB that a file may be before it is repacked serially -->\n    <SignToolRepackMaximumParallelFileSize>128</SignToolRepackMaximumParallelFileSize>\n  </PropertyGroup>\n\n  <!-- Allow repository to customize signing configuration -->\n  <Import Project=\"$(RepositoryEngineeringDir)Signing.props\" Condition=\"Exists('$(RepositoryEngineeringDir)Signing.props')\" />\n\n  <!-- Respect Artifact item repo extension point -->\n  <ItemGroup Condition=\"'@(Artifact)' != ''\">\n    <!-- If PostBuildSign == true, these are added to ItemsToSignPostBuild, otherwise these are added to ItemsToSign -->\n    <ItemsToSign Include=\"@(Artifact)\" Condition=\"'$(PostBuildSign)' != 'true'\" />\n    <ItemsToSignPostBuild Include=\"@(Artifact->'%(Filename)%(Extension)')\" Condition=\"'$(PostBuildSign)' == 'true'\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "sign/packages.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<packages>\n  <package id=\"Microsoft.DotNet.SignTool\" version=\"6.0.0-beta.20630.2\"/>\n  <package id=\"vswhere\" version=\"2.6.7\"/>\n  <package id=\"sn\" version=\"1.0.0\"/>\n  <package id=\"MicroBuild.Core\" version=\"0.2.0\"/>\n</packages>"
  },
  {
    "path": "spelling.dic",
    "content": "Parsable\nstackalloc\nImpl\naddr\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/AWSUtilsHostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Clustering.DynamoDB;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing System;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Hosting\n{\n    public static class AwsUtilsHostingExtensions\n    {\n        /// <summary>\n        /// Configures the silo to use DynamoDB for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseDynamoDBClustering(\n            this ISiloBuilder builder,\n            Action<DynamoDBClusteringOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IMembershipTable, DynamoDBMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the silo to use DynamoDB for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseDynamoDBClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<DynamoDBClusteringOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<DynamoDBClusteringOptions>());\n                    services.AddSingleton<IMembershipTable, DynamoDBMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use DynamoDB for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseDynamoDBClustering(\n            this IClientBuilder builder,\n            Action<DynamoDBGatewayOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IGatewayListProvider, DynamoDBGatewayListProvider>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use DynamoDB for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseDynamoDBClustering(\n            this IClientBuilder builder,\n            Action<OptionsBuilder<DynamoDBGatewayOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<DynamoDBGatewayOptions>());\n                    services.AddSingleton<IGatewayListProvider, DynamoDBGatewayListProvider>();\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/DynamoDBClusteringProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"DynamoDB\", \"Clustering\", \"Silo\", typeof(DynamoDBClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"DynamoDB\", \"Clustering\", \"Client\", typeof(DynamoDBClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class DynamoDBClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseDynamoDBClustering(options =>\n            {\n                var accessKey = configurationSection[nameof(options.AccessKey)];\n                if (!string.IsNullOrEmpty(accessKey))\n                {\n                    options.AccessKey = accessKey;\n                }\n\n                var secretKey = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(secretKey))\n                {\n                    options.SecretKey = secretKey;\n                }\n\n                var region = configurationSection[nameof(options.Service)] ?? configurationSection[\"Region\"];\n                if (!string.IsNullOrEmpty(region))\n                {\n                    options.Service = region;\n                }\n\n                var token = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(token))\n                {\n                    options.Token = token;\n                }\n\n                var profileName = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(profileName))\n                {\n                    options.ProfileName = profileName;\n                }\n\n                var tableName = configurationSection[nameof(options.TableName)];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.ReadCapacityUnits)], out var rcu))\n                {\n                    options.ReadCapacityUnits = rcu;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.WriteCapacityUnits)], out var wcu))\n                {\n                    options.WriteCapacityUnits = wcu;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UseProvisionedThroughput)], out var upt))\n                {\n                    options.UseProvisionedThroughput = upt;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.CreateIfNotExists)], out var cine))\n                {\n                    options.CreateIfNotExists = cine;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UpdateIfExists)], out var uie))\n                {\n                    options.UpdateIfExists = uie;\n                }\n            });\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseDynamoDBClustering(options =>\n            {\n                var accessKey = configurationSection[nameof(options.AccessKey)];\n                if (!string.IsNullOrEmpty(accessKey))\n                {\n                    options.AccessKey = accessKey;\n                }\n\n                var secretKey = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(secretKey))\n                {\n                    options.SecretKey = secretKey;\n                }\n\n                var region = configurationSection[nameof(options.Service)] ?? configurationSection[\"Region\"];\n                if (!string.IsNullOrEmpty(region))\n                {\n                    options.Service = region;\n                }\n\n                var token = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(token))\n                {\n                    options.Token = token;\n                }\n\n                var profileName = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(profileName))\n                {\n                    options.ProfileName = profileName;\n                }\n\n                var tableName = configurationSection[nameof(options.TableName)];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.ReadCapacityUnits)], out var rcu))\n                {\n                    options.ReadCapacityUnits = rcu;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.WriteCapacityUnits)], out var wcu))\n                {\n                    options.WriteCapacityUnits = wcu;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UseProvisionedThroughput)], out var upt))\n                {\n                    options.UseProvisionedThroughput = upt;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.CreateIfNotExists)], out var cine))\n                {\n                    options.CreateIfNotExists = cine;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UpdateIfExists)], out var uie))\n                {\n                    options.UpdateIfExists = uie;\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Membership/DynamoDBGatewayListProvider.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Clustering.DynamoDB\n{\n    internal class DynamoDBGatewayListProvider : IGatewayListProvider\n    {\n        private DynamoDBStorage storage;\n        private readonly string clusterId;\n        private readonly string INSTANCE_STATUS_ACTIVE = ((int)SiloStatus.Active).ToString();\n        private readonly ILogger logger;\n        private readonly DynamoDBGatewayOptions options;\n\n        public DynamoDBGatewayListProvider(\n            ILogger<DynamoDBGatewayListProvider> logger,\n            IOptions<DynamoDBGatewayOptions> options,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<GatewayOptions> gatewayOptions)\n        {\n            this.logger = logger;\n            this.options = options.Value;\n            this.clusterId = clusterOptions.Value.ClusterId;\n            this.MaxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n        }\n\n        public Task InitializeGatewayListProvider()\n        {\n            this.storage = new DynamoDBStorage(\n                this.logger,\n                this.options.Service,\n                this.options.AccessKey,\n                this.options.SecretKey,\n                this.options.Token,\n                this.options.ProfileName,\n                this.options.ReadCapacityUnits,\n                this.options.WriteCapacityUnits,\n                this.options.UseProvisionedThroughput,\n                this.options.CreateIfNotExists,\n                this.options.UpdateIfExists);\n\n            return this.storage.InitializeTable(this.options.TableName,\n                new List<KeySchemaElement>\n                {\n                    new KeySchemaElement { AttributeName = SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME, KeyType = KeyType.HASH },\n                    new KeySchemaElement { AttributeName = SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                },\n                new List<AttributeDefinition>\n                {\n                    new AttributeDefinition { AttributeName = SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME, AttributeType = ScalarAttributeType.S },\n                    new AttributeDefinition { AttributeName = SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME, AttributeType = ScalarAttributeType.S }\n                });\n        }\n\n        public async Task<IList<Uri>> GetGateways()\n        {\n            var expressionValues = new Dictionary<string, AttributeValue>\n            {\n                { $\":{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                { $\":{SiloInstanceRecord.STATUS_PROPERTY_NAME}\", new AttributeValue { N = INSTANCE_STATUS_ACTIVE } },\n                { $\":{SiloInstanceRecord.PROXY_PORT_PROPERTY_NAME}\", new AttributeValue { N = \"0\"} }\n            };\n\n            var expression =\n                $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME} = :{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME} \" +\n                $\"AND {SiloInstanceRecord.STATUS_PROPERTY_NAME} = :{SiloInstanceRecord.STATUS_PROPERTY_NAME} \" +\n                $\"AND {SiloInstanceRecord.PROXY_PORT_PROPERTY_NAME} > :{SiloInstanceRecord.PROXY_PORT_PROPERTY_NAME}\";\n\n            var records = await storage.ScanAsync<Uri>(this.options.TableName, expressionValues,\n                expression, gateway =>\n                {\n                    return SiloAddress.New(\n                            IPAddress.Parse(gateway[SiloInstanceRecord.ADDRESS_PROPERTY_NAME].S),\n                            int.Parse(gateway[SiloInstanceRecord.PROXY_PORT_PROPERTY_NAME].N),\n                            int.Parse(gateway[SiloInstanceRecord.GENERATION_PROPERTY_NAME].N)).ToGatewayUri();\n                });\n\n            return records;\n        }\n\n        public TimeSpan MaxStaleness { get; }\n\n        public bool IsUpdatable\n        {\n            get { return true; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Membership/DynamoDBGatewayListProviderHelper.cs",
    "content": "using System;\nusing System.Linq;\nusing Orleans.Configuration;\n\nnamespace Orleans.Clustering.DynamoDB\n{\n    /// <inheritdoc/>\n    public class DynamoDBGatewayListProviderHelper\n    {\n        private const string AccessKeyPropertyName = \"AccessKey\";\n        private const string SecretKeyPropertyName = \"SecretKey\";\n        private const string ServicePropertyName = \"Service\";\n        private const string ReadCapacityUnitsPropertyName = \"ReadCapacityUnits\";\n        private const string WriteCapacityUnitsPropertyName = \"WriteCapacityUnits\";\n\n        /// <summary>\n        /// Parse data connection string to fill in fields in <paramref name=\"options\"/>\n        /// </summary>\n        /// <param name=\"dataConnectionString\"></param>\n        /// <param name=\"options\"></param>\n        internal static void ParseDataConnectionString(string dataConnectionString, DynamoDBGatewayOptions options)\n        {\n            var parameters = dataConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);\n\n            var serviceConfig = Array.Find(parameters, p => p.Contains(ServicePropertyName));\n            if (!string.IsNullOrWhiteSpace(serviceConfig))\n            {\n                var value = serviceConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.Service = value[1];\n            }\n\n            var secretKeyConfig = Array.Find(parameters, p => p.Contains(SecretKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(secretKeyConfig))\n            {\n                var value = secretKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.SecretKey = value[1];\n            }\n\n            var accessKeyConfig = Array.Find(parameters, p => p.Contains(AccessKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(accessKeyConfig))\n            {\n                var value = accessKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.AccessKey = value[1];\n            }\n\n            var readCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(ReadCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(readCapacityUnitsConfig))\n            {\n                var value = readCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.ReadCapacityUnits = int.Parse(value[1]);\n            }\n\n            var writeCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(WriteCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(writeCapacityUnitsConfig))\n            {\n                var value = writeCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.WriteCapacityUnits = int.Parse(value[1]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Membership/DynamoDBMembershipHelper.cs",
    "content": "using Orleans.Configuration;\nusing System;\nusing System.Linq;\n\nnamespace Orleans.Clustering.DynamoDB\n{\n    /// <inheritdoc />\n    public class DynamoDBMembershipHelper\n    {\n        private const string AccessKeyPropertyName = \"AccessKey\";\n        private const string SecretKeyPropertyName = \"SecretKey\";\n        private const string ServicePropertyName = \"Service\";\n        private const string TableNamePropertyName = \"TableName\";\n        private const string ReadCapacityUnitsPropertyName = \"ReadCapacityUnits\";\n        private const string WriteCapacityUnitsPropertyName = \"WriteCapacityUnits\";\n        \n        /// <summary>\n        /// Parse data connection string to fill in fields in <paramref name=\"options\"/>\n        /// </summary>\n        /// <param name=\"dataConnectionString\"></param>\n        /// <param name=\"options\"></param>\n        public static void ParseDataConnectionString(string dataConnectionString, DynamoDBClusteringOptions options)\n        {\n            var parameters = dataConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);\n\n            var serviceConfig = Array.Find(parameters, p => p.Contains(ServicePropertyName));\n            if (!string.IsNullOrWhiteSpace(serviceConfig))\n            {\n                var value = serviceConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.Service = value[1];\n            }\n\n            var tableNameConfig = Array.Find(parameters, p => p.Contains(TableNamePropertyName));\n            if (!string.IsNullOrWhiteSpace(tableNameConfig))\n            {\n                var value = tableNameConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.TableName = value[1];\n            }\n\n            var secretKeyConfig = Array.Find(parameters, p => p.Contains(SecretKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(secretKeyConfig))\n            {\n                var value = secretKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.SecretKey = value[1];\n            }\n\n            var accessKeyConfig = Array.Find(parameters, p => p.Contains(AccessKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(accessKeyConfig))\n            {\n                var value = accessKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.AccessKey = value[1];\n            }\n\n            var readCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(ReadCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(readCapacityUnitsConfig))\n            {\n                var value = readCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.ReadCapacityUnits = int.Parse(value[1]);\n            }\n\n            var writeCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(WriteCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(writeCapacityUnitsConfig))\n            {\n                var value = writeCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.WriteCapacityUnits = int.Parse(value[1]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Membership/DynamoDBMembershipTable.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Clustering.DynamoDB\n{\n    internal partial class DynamoDBMembershipTable : IMembershipTable\n    {\n        private static readonly TableVersion NotFoundTableVersion = new TableVersion(0, \"0\");\n\n        private const string CURRENT_ETAG_ALIAS = \":currentETag\";\n        private const int MAX_BATCH_SIZE = 25;\n\n        private readonly ILogger logger;\n        private DynamoDBStorage storage;\n        private readonly DynamoDBClusteringOptions options;\n        private readonly string clusterId;\n\n        public DynamoDBMembershipTable(\n            ILoggerFactory loggerFactory,\n            IOptions<DynamoDBClusteringOptions> clusteringOptions,\n            IOptions<ClusterOptions> clusterOptions)\n        {\n            logger = loggerFactory.CreateLogger<DynamoDBMembershipTable>();\n            this.options = clusteringOptions.Value;\n            this.clusterId = clusterOptions.Value.ClusterId;\n        }\n\n        public async Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            this.storage = new DynamoDBStorage(\n                this.logger,\n                this.options.Service,\n                this.options.AccessKey,\n                this.options.SecretKey,\n                this.options.Token,\n                this.options.ProfileName,\n                this.options.ReadCapacityUnits,\n                this.options.WriteCapacityUnits,\n                this.options.UseProvisionedThroughput,\n                this.options.CreateIfNotExists,\n                this.options.UpdateIfExists);\n\n            LogInformationInitializingMembershipTable();\n            await storage.InitializeTable(this.options.TableName,\n                new List<KeySchemaElement>\n                {\n                    new KeySchemaElement { AttributeName = SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME, KeyType = KeyType.HASH },\n                    new KeySchemaElement { AttributeName = SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                },\n                new List<AttributeDefinition>\n                {\n                    new AttributeDefinition { AttributeName = SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME, AttributeType = ScalarAttributeType.S },\n                    new AttributeDefinition { AttributeName = SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME, AttributeType = ScalarAttributeType.S }\n                });\n\n            // even if I am not the one who created the table,\n            // try to insert an initial table version if it is not already there,\n            // so we always have a first table version row, before this silo starts working.\n            if (tryInitTableVersion)\n            {\n                // ignore return value, since we don't care if I inserted it or not, as long as it is in there.\n                bool created = await TryCreateTableVersionEntryAsync();\n                if (created) LogInformationCreatedNewTableVersionRow();\n            }\n        }\n\n        private async Task<bool> TryCreateTableVersionEntryAsync()\n        {\n            var keys = new Dictionary<string, AttributeValue>\n            {\n                { $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                { $\"{SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME}\", new AttributeValue(SiloInstanceRecord.TABLE_VERSION_ROW) }\n            };\n\n            var versionRow = await storage.ReadSingleEntryAsync(this.options.TableName, keys, fields => new SiloInstanceRecord(fields));\n            if (versionRow != null)\n            {\n                return false;\n            }\n\n            if (!TryCreateTableVersionRecord(0, null, out var entry))\n            {\n                return false;\n            }\n\n            var notExistConditionExpression =\n                $\"attribute_not_exists({SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}) AND attribute_not_exists({SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME})\";\n            try\n            {\n                await storage.PutEntryAsync(this.options.TableName, entry.GetFields(true), notExistConditionExpression);\n            }\n            catch (ConditionalCheckFailedException)\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        private bool TryCreateTableVersionRecord(int version, string etag, out SiloInstanceRecord entry)\n        {\n            int etagInt;\n            if (etag is null)\n            {\n                etagInt = 0;\n            }\n            else\n            {\n                if (!int.TryParse(etag, out etagInt))\n                {\n                    entry = default;\n                    return false;\n                }\n            }\n\n            entry = new SiloInstanceRecord\n            {\n                DeploymentId = clusterId,\n                SiloIdentity = SiloInstanceRecord.TABLE_VERSION_ROW,\n                MembershipVersion = version,\n                ETag = etagInt\n            };\n\n            return true;\n        }\n\n        public async Task DeleteMembershipTableEntries(string clusterId)\n        {\n            try\n            {\n                var keys = new Dictionary<string, AttributeValue> { { $\":{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(clusterId) } };\n                var records = await storage.QueryAsync(this.options.TableName, keys, $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME} = :{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", item => new SiloInstanceRecord(item));\n\n                var toDelete = new List<Dictionary<string, AttributeValue>>();\n                foreach (var record in records.results)\n                {\n                    toDelete.Add(record.GetKeys());\n                }\n\n                List<Task> tasks = new List<Task>();\n                foreach (var batch in toDelete.BatchIEnumerable(MAX_BATCH_SIZE))\n                {\n                    tasks.Add(storage.DeleteEntriesAsync(this.options.TableName, batch));\n                }\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception exc)\n            {\n                LogErrorUnableToDeleteMembershipRecords(exc, this.options.TableName, clusterId);\n                throw;\n            }\n        }\n\n        public async Task<MembershipTableData> ReadRow(SiloAddress siloAddress)\n        {\n            try\n            {\n                var siloEntryKeys = new Dictionary<string, AttributeValue>\n                {\n                    { $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                    { $\"{SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME}\", new AttributeValue(SiloInstanceRecord.ConstructSiloIdentity(siloAddress)) }\n                };\n\n                var versionEntryKeys = new Dictionary<string, AttributeValue>\n                {\n                    { $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                    { $\"{SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME}\", new AttributeValue(SiloInstanceRecord.TABLE_VERSION_ROW) }\n                };\n\n                var entries = await storage.GetEntriesTxAsync(this.options.TableName,\n                    new[] {siloEntryKeys, versionEntryKeys}, fields => new SiloInstanceRecord(fields));\n\n                MembershipTableData data = Convert(entries.ToList());\n                LogTraceReadMyEntry(siloAddress, data);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorReadingSiloEntry(exc, siloAddress, this.options.TableName);\n                throw;\n            }\n        }\n\n        public async Task<MembershipTableData> ReadAll()\n        {\n            try\n            {\n                //first read just the version row so that we can check for version consistency\n                var versionEntryKeys = new Dictionary<string, AttributeValue>\n                {\n                    { $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                    { $\"{SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME}\", new AttributeValue(SiloInstanceRecord.TABLE_VERSION_ROW) }\n                };\n                var versionRow = await this.storage.ReadSingleEntryAsync(this.options.TableName, versionEntryKeys,\n                    fields => new SiloInstanceRecord(fields));\n                if (versionRow == null)\n                {\n                    throw new KeyNotFoundException(\"No version row found for membership table\");\n                }\n\n                var keys = new Dictionary<string, AttributeValue> { { $\":{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) } };\n                var records = await this.storage.QueryAllAsync(this.options.TableName, keys, $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME} = :{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", item => new SiloInstanceRecord(item));\n\n                if (records.Exists(record => record.MembershipVersion > versionRow.MembershipVersion))\n                {\n                    LogWarningFoundInconsistencyReadingAllSiloEntries();\n                    //not expecting this to hit often, but if it does, should put in a limit\n                    return await this.ReadAll();\n                }\n\n                MembershipTableData data = Convert(records);\n                LogTraceReadAllTable(data);\n\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorReadingAllSiloEntries(exc, options.TableName);\n                throw;\n            }\n        }\n\n        public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            try\n            {\n                LogDebugInsertRow(entry);\n                var tableEntry = Convert(entry, tableVersion);\n\n                if (!TryCreateTableVersionRecord(tableVersion.Version, tableVersion.VersionEtag, out var versionEntry))\n                {\n                    LogWarningInsertFailedInvalidETag(entry, tableVersion.VersionEtag);\n                    return false;\n                }\n\n                versionEntry.ETag++;\n\n                bool result;\n\n                try\n                {\n                    var notExistConditionExpression =\n                        $\"attribute_not_exists({SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}) AND attribute_not_exists({SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME})\";\n                    var tableEntryInsert = new Put\n                    {\n                        Item = tableEntry.GetFields(true),\n                        ConditionExpression = notExistConditionExpression,\n                        TableName = this.options.TableName\n                    };\n\n                    var conditionalValues = new Dictionary<string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = tableVersion.VersionEtag } } };\n                    var etagConditionalExpression = $\"{SiloInstanceRecord.ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}\";\n                    var versionEntryUpdate = new Update\n                    {\n                        TableName = this.options.TableName,\n                        Key = versionEntry.GetKeys(),\n                        ConditionExpression = etagConditionalExpression\n                    };\n                    (versionEntryUpdate.UpdateExpression, versionEntryUpdate.ExpressionAttributeValues) =\n                        this.storage.ConvertUpdate(versionEntry.GetFields(), conditionalValues);\n\n                    await this.storage.WriteTxAsync(new[] {tableEntryInsert}, new[] {versionEntryUpdate});\n\n                    result = true;\n                }\n                catch (TransactionCanceledException canceledException)\n                {\n                    if (canceledException.Message.Contains(\"ConditionalCheckFailed\")) //not a good way to check for this currently\n                    {\n                        result = false;\n                        LogWarningInsertFailedDueToContention(entry);\n                    }\n                    else\n                    {\n                        throw;\n                    }\n                }\n\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorInsertingEntry(exc, entry, this.options.TableName);\n                throw;\n            }\n        }\n\n        public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            try\n            {\n                LogDebugUpdateRow(entry, etag);\n                var siloEntry = Convert(entry, tableVersion);\n                if (!int.TryParse(etag, out var currentEtag))\n                {\n                    LogWarningUpdateFailedInvalidETag(entry, etag);\n                    return false;\n                }\n\n                siloEntry.ETag = currentEtag + 1;\n\n                if (!TryCreateTableVersionRecord(tableVersion.Version, tableVersion.VersionEtag, out var versionEntry))\n                {\n                    LogWarningUpdateFailedInvalidETag(entry, tableVersion.VersionEtag);\n                    return false;\n                }\n\n                versionEntry.ETag++;\n\n                bool result;\n\n                try\n                {\n                    var etagConditionalExpression = $\"{SiloInstanceRecord.ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}\";\n\n                    var siloConditionalValues = new Dictionary<string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = etag } } };\n                    var siloEntryUpdate = new Update\n                    {\n                        TableName = this.options.TableName,\n                        Key = siloEntry.GetKeys(),\n                        ConditionExpression = etagConditionalExpression\n                    };\n                    (siloEntryUpdate.UpdateExpression, siloEntryUpdate.ExpressionAttributeValues) =\n                        this.storage.ConvertUpdate(siloEntry.GetFields(), siloConditionalValues);\n\n\n                    var versionConditionalValues = new Dictionary<string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = tableVersion.VersionEtag } } };\n                    var versionEntryUpdate = new Update\n                    {\n                        TableName = this.options.TableName,\n                        Key = versionEntry.GetKeys(),\n                        ConditionExpression = etagConditionalExpression\n                    };\n                    (versionEntryUpdate.UpdateExpression, versionEntryUpdate.ExpressionAttributeValues) =\n                        this.storage.ConvertUpdate(versionEntry.GetFields(), versionConditionalValues);\n\n                    await this.storage.WriteTxAsync(updates: new[] {siloEntryUpdate, versionEntryUpdate});\n                    result = true;\n                }\n                catch (TransactionCanceledException canceledException)\n                {\n                    if (canceledException.Message.Contains(\"ConditionalCheckFailed\")) //not a good way to check for this currently\n                    {\n                        result = false;\n                        LogWarningUpdateFailedDueToContention(canceledException, entry, etag);\n                    }\n                    else\n                    {\n                        throw;\n                    }\n                }\n\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorUpdatingEntry(exc, entry, this.options.TableName);\n                throw;\n            }\n        }\n\n        public async Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            try\n            {\n                LogDebugMergeEntry(entry);\n                var siloEntry = ConvertPartial(entry);\n                var fields = new Dictionary<string, AttributeValue> { { SiloInstanceRecord.I_AM_ALIVE_TIME_PROPERTY_NAME, new AttributeValue(siloEntry.IAmAliveTime) } };\n                var expression = $\"attribute_exists({SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}) AND attribute_exists({SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME})\";\n                await this.storage.UpsertEntryAsync(this.options.TableName, siloEntry.GetKeys(),fields, expression);\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorUpdatingIAmAlive(exc, entry, this.options.TableName);\n                throw;\n            }\n        }\n\n        private MembershipTableData Convert(List<SiloInstanceRecord> entries)\n        {\n            try\n            {\n                var memEntries = new List<Tuple<MembershipEntry, string>>();\n                var tableVersion = NotFoundTableVersion;\n                foreach (var tableEntry in entries)\n                {\n                    if (tableEntry.SiloIdentity == SiloInstanceRecord.TABLE_VERSION_ROW)\n                    {\n                        tableVersion = new TableVersion(tableEntry.MembershipVersion, tableEntry.ETag.ToString(CultureInfo.InvariantCulture));\n                    }\n                    else\n                    {\n                        try\n                        {\n                            MembershipEntry membershipEntry = Parse(tableEntry);\n                            memEntries.Add(new Tuple<MembershipEntry, string>(membershipEntry,\n                                tableEntry.ETag.ToString(CultureInfo.InvariantCulture)));\n                        }\n                        catch (Exception exc)\n                        {\n                            LogErrorIntermediateErrorParsingSiloInstanceTableEntry(exc, tableEntry);\n                        }\n                    }\n                }\n                var data = new MembershipTableData(memEntries, tableVersion);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogErrorIntermediateErrorParsingSiloInstanceTableEntries(exc, entries);\n                throw;\n            }\n        }\n\n        private static MembershipEntry Parse(SiloInstanceRecord tableEntry)\n        {\n            var parse = new MembershipEntry\n            {\n                HostName = tableEntry.HostName,\n                Status = (SiloStatus)tableEntry.Status\n            };\n\n            parse.ProxyPort = tableEntry.ProxyPort;\n\n            parse.SiloAddress = SiloAddress.New(IPAddress.Parse(tableEntry.Address), tableEntry.Port, tableEntry.Generation);\n\n            if (!string.IsNullOrEmpty(tableEntry.SiloName))\n            {\n                parse.SiloName = tableEntry.SiloName;\n            }\n\n            parse.StartTime = !string.IsNullOrEmpty(tableEntry.StartTime) ?\n                LogFormatter.ParseDate(tableEntry.StartTime) : default;\n\n            parse.IAmAliveTime = !string.IsNullOrEmpty(tableEntry.IAmAliveTime) ?\n                LogFormatter.ParseDate(tableEntry.IAmAliveTime) : default;\n\n            var suspectingSilos = new List<SiloAddress>();\n            var suspectingTimes = new List<DateTime>();\n\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingSilos))\n            {\n                string[] silos = tableEntry.SuspectingSilos.Split('|');\n                foreach (string silo in silos)\n                {\n                    suspectingSilos.Add(SiloAddress.FromParsableString(silo));\n                }\n            }\n\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingTimes))\n            {\n                string[] times = tableEntry.SuspectingTimes.Split('|');\n                foreach (string time in times)\n                    suspectingTimes.Add(LogFormatter.ParseDate(time));\n            }\n\n            if (suspectingSilos.Count != suspectingTimes.Count)\n                throw new OrleansException($\"SuspectingSilos.Length of {suspectingSilos.Count} as read from Azure table is not equal to SuspectingTimes.Length of {suspectingTimes.Count}\");\n\n            for (int i = 0; i < suspectingSilos.Count; i++)\n                parse.AddSuspector(suspectingSilos[i], suspectingTimes[i]);\n\n            return parse;\n        }\n\n        private SiloInstanceRecord Convert(MembershipEntry memEntry, TableVersion tableVersion)\n        {\n            var tableEntry = new SiloInstanceRecord\n            {\n                DeploymentId = this.clusterId,\n                Address = memEntry.SiloAddress.Endpoint.Address.ToString(),\n                Port = memEntry.SiloAddress.Endpoint.Port,\n                Generation = memEntry.SiloAddress.Generation,\n                HostName = memEntry.HostName,\n                Status = (int)memEntry.Status,\n                ProxyPort = memEntry.ProxyPort,\n                SiloName = memEntry.SiloName,\n                StartTime = LogFormatter.PrintDate(memEntry.StartTime),\n                IAmAliveTime = LogFormatter.PrintDate(memEntry.IAmAliveTime),\n                SiloIdentity = SiloInstanceRecord.ConstructSiloIdentity(memEntry.SiloAddress),\n                MembershipVersion = tableVersion.Version\n            };\n\n            if (memEntry.SuspectTimes != null)\n            {\n                var siloList = new StringBuilder();\n                var timeList = new StringBuilder();\n                bool first = true;\n                foreach (var tuple in memEntry.SuspectTimes)\n                {\n                    if (!first)\n                    {\n                        siloList.Append('|');\n                        timeList.Append('|');\n                    }\n                    siloList.Append(tuple.Item1.ToParsableString());\n                    timeList.Append(LogFormatter.PrintDate(tuple.Item2));\n                    first = false;\n                }\n\n                tableEntry.SuspectingSilos = siloList.ToString();\n                tableEntry.SuspectingTimes = timeList.ToString();\n            }\n            else\n            {\n                tableEntry.SuspectingSilos = string.Empty;\n                tableEntry.SuspectingTimes = string.Empty;\n            }\n\n            return tableEntry;\n        }\n\n        private SiloInstanceRecord ConvertPartial(MembershipEntry memEntry)\n        {\n            return new SiloInstanceRecord\n            {\n                DeploymentId = this.clusterId,\n                IAmAliveTime = LogFormatter.PrintDate(memEntry.IAmAliveTime),\n                SiloIdentity = SiloInstanceRecord.ConstructSiloIdentity(memEntry.SiloAddress)\n            };\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            try\n            {\n                var keys = new Dictionary<string, AttributeValue>\n                {\n                    { $\":{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\", new AttributeValue(this.clusterId) },\n                };\n                var filter = $\"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME} = :{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}\";\n\n                var records = await this.storage.QueryAllAsync(this.options.TableName, keys, filter, item => new SiloInstanceRecord(item));\n                var defunctRecordKeys = records.Where(r => SiloIsDefunct(r, beforeDate)).Select(r => r.GetKeys());\n\n                var tasks = new List<Task>();\n                foreach (var batch in defunctRecordKeys.BatchIEnumerable(MAX_BATCH_SIZE))\n                {\n                    tasks.Add(this.storage.DeleteEntriesAsync(this.options.TableName, batch));\n                }\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception exc)\n            {\n                LogErrorUnableToCleanUpDefunctMembershipRecords(exc, this.options.TableName, this.clusterId);\n                throw;\n            }\n        }\n\n        private static bool SiloIsDefunct(SiloInstanceRecord silo, DateTimeOffset beforeDate)\n        {\n            return DateTimeOffset.TryParse(silo.IAmAliveTime, out var iAmAliveTime)\n                    && iAmAliveTime < beforeDate\n                    && silo.Status != (int)SiloStatus.Active;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Initializing AWS DynamoDB Membership Table\"\n        )]\n        private partial void LogInformationInitializingMembershipTable();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Created new table version row.\"\n        )]\n        private partial void LogInformationCreatedNewTableVersionRow();\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unable to delete membership records on table {TableName} for ClusterId {ClusterId}\"\n        )]\n        private partial void LogErrorUnableToDeleteMembershipRecords(Exception exception, string tableName, string clusterId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Read my entry {SiloAddress} Table: {TableData}\"\n        )]\n        private partial void LogTraceReadMyEntry(SiloAddress siloAddress, MembershipTableData tableData);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading silo entry for key {SiloAddress} from the table {TableName}\"\n        )]\n        private partial void LogWarningIntermediateErrorReadingSiloEntry(Exception exception, SiloAddress siloAddress, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Found an inconsistency while reading all silo entries\"\n        )]\n        private partial void LogWarningFoundInconsistencyReadingAllSiloEntries();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"ReadAll Table {Table}\"\n        )]\n        private partial void LogTraceReadAllTable(MembershipTableData table);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading all silo entries {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorReadingAllSiloEntries(Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"InsertRow entry = {Entry}\"\n        )]\n        private partial void LogDebugInsertRow(MembershipEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Insert failed. Invalid ETag value. Will retry. Entry {Entry}, eTag {ETag}\"\n        )]\n        private partial void LogWarningInsertFailedInvalidETag(MembershipEntry entry, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Insert failed due to contention on the table. Will retry. Entry {Entry}\"\n        )]\n        private partial void LogWarningInsertFailedDueToContention(MembershipEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error inserting entry {Entry} to the table {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorInsertingEntry(Exception exception, MembershipEntry entry, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpdateRow entry = {Entry}, etag = {Etag}\"\n        )]\n        private partial void LogDebugUpdateRow(MembershipEntry entry, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Update failed. Invalid ETag value. Will retry. Entry {Entry}, eTag {ETag}\"\n        )]\n        private partial void LogWarningUpdateFailedInvalidETag(MembershipEntry entry, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Update failed due to contention on the table. Will retry. Entry {Entry}, eTag {ETag}\"\n        )]\n        private partial void LogWarningUpdateFailedDueToContention(Exception exception, MembershipEntry entry, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error updating entry {Entry} to the table {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorUpdatingEntry(Exception exception, MembershipEntry entry, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Merge entry = {Entry}\"\n        )]\n        private partial void LogDebugMergeEntry(MembershipEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error updating IAmAlive field for entry {Entry} to the table {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorUpdatingIAmAlive(Exception exception, MembershipEntry entry, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Intermediate error parsing SiloInstanceTableEntry to MembershipTableData: {TableEntry}. Ignoring this entry.\"\n        )]\n        private partial void LogErrorIntermediateErrorParsingSiloInstanceTableEntry(Exception exception, SiloInstanceRecord tableEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Intermediate error parsing SiloInstanceTableEntry to MembershipTableData: {Entries}.\"\n        )]\n        private partial void LogErrorIntermediateErrorParsingSiloInstanceTableEntries(Exception exception, IEnumerable<SiloInstanceRecord> entries);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unable to clean up defunct membership records on table {TableName} for ClusterId {ClusterId}\"\n        )]\n        private partial void LogErrorUnableToCleanUpDefunctMembershipRecords(Exception exception, string tableName, string clusterId);\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Membership/SiloInstanceRecord.cs",
    "content": "using Amazon.DynamoDBv2.Model;\nusing System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Text;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal class SiloInstanceRecord\n    {\n        public const string DEPLOYMENT_ID_PROPERTY_NAME = \"DeploymentId\";\n        public const string SILO_IDENTITY_PROPERTY_NAME = \"SiloIdentity\";\n        public const string ETAG_PROPERTY_NAME = \"ETag\";\n        public const string ADDRESS_PROPERTY_NAME = \"Address\";\n        public const string PORT_PROPERTY_NAME = \"Port\";\n        public const string GENERATION_PROPERTY_NAME = \"Generation\";\n        public const string HOSTNAME_PROPERTY_NAME = \"HostName\";\n        public const string STATUS_PROPERTY_NAME = \"SiloStatus\";\n        public const string PROXY_PORT_PROPERTY_NAME = \"ProxyPort\";\n        public const string SILO_NAME_PROPERTY_NAME = \"SiloName\";\n        public const string INSTANCE_NAME_PROPERTY_NAME = \"InstanceName\";\n        public const string SUSPECTING_SILOS_PROPERTY_NAME = \"SuspectingSilos\";\n        public const string SUSPECTING_TIMES_PROPERTY_NAME = \"SuspectingTimes\";\n        public const string START_TIME_PROPERTY_NAME = \"StartTime\";\n        public const string I_AM_ALIVE_TIME_PROPERTY_NAME = \"IAmAliveTime\";\n        internal const char Seperator = '-';\n        internal const string TABLE_VERSION_ROW = \"VersionRow\"; // Range key for version row.\n        public const string MEMBERSHIP_VERSION_PROPERTY_NAME = \"MembershipVersion\";\n\n        public string DeploymentId { get; set; }\n        public string SiloIdentity { get; set; }\n        public string Address { get; set; }\n        public int Port { get; set; }\n        public int Generation { get; set; }\n        public string HostName { get; set; }\n        public int Status { get; set; }\n        public int ProxyPort { get; set; }\n        public string SiloName { get; set; }\n        public string SuspectingSilos { get; set; }\n        public string SuspectingTimes { get; set; }\n        public string StartTime { get; set; }\n        public string IAmAliveTime { get; set; }\n        public int ETag { get; set; }\n\n        public int MembershipVersion { get; set; }\n\n        public SiloInstanceRecord() { }\n\n        public SiloInstanceRecord(Dictionary<string, AttributeValue> fields)\n        {\n            if (fields.TryGetValue(DEPLOYMENT_ID_PROPERTY_NAME, out var deploymentId))\n                DeploymentId = deploymentId.S;\n\n            if (fields.TryGetValue(SILO_IDENTITY_PROPERTY_NAME, out var siloIdentity))\n                SiloIdentity = siloIdentity.S;\n\n            if (fields.TryGetValue(ADDRESS_PROPERTY_NAME, out var address))\n                Address = address.S;\n\n            if (fields.TryGetValue(PORT_PROPERTY_NAME, out var sPort) &&\n                int.TryParse(sPort.N, out var port))\n                Port = port;\n\n            if (fields.TryGetValue(GENERATION_PROPERTY_NAME, out var sGeneration) &&\n                int.TryParse(sGeneration.N, out var generation))\n                Generation = generation;\n\n            if (fields.TryGetValue(HOSTNAME_PROPERTY_NAME, out var hostName))\n                HostName = hostName.S;\n\n            if (fields.TryGetValue(STATUS_PROPERTY_NAME, out var sStatus) &&\n                int.TryParse(sStatus.N, out var status))\n                Status = status;\n\n            if (fields.TryGetValue(PROXY_PORT_PROPERTY_NAME, out var sProxyPort) &&\n                int.TryParse(sProxyPort.N, out var proxyPort))\n                ProxyPort = proxyPort;\n\n            if (fields.TryGetValue(SILO_NAME_PROPERTY_NAME, out var siloName))\n                SiloName = siloName.S;\n\n            if (fields.TryGetValue(SUSPECTING_SILOS_PROPERTY_NAME, out var suspectingSilos))\n                SuspectingSilos = suspectingSilos.S;\n\n            if (fields.TryGetValue(SUSPECTING_TIMES_PROPERTY_NAME, out var suspectingTimes))\n                SuspectingTimes = suspectingTimes.S;\n\n            if (fields.TryGetValue(START_TIME_PROPERTY_NAME, out var startTime))\n                StartTime = startTime.S;\n\n            if (fields.TryGetValue(I_AM_ALIVE_TIME_PROPERTY_NAME, out var aliveTime))\n                IAmAliveTime = aliveTime.S;\n\n            if (fields.TryGetValue(ETAG_PROPERTY_NAME, out var sETag) &&\n                int.TryParse(sETag.N, out var etag))\n                ETag = etag;\n\n            if (fields.TryGetValue(MEMBERSHIP_VERSION_PROPERTY_NAME, out var value) &&\n                int.TryParse(value.N, out var version))\n                MembershipVersion = version;\n        }\n\n        internal static SiloAddress UnpackRowKey(string rowKey)\n        {\n            try\n            {\n                int idx1 = rowKey.IndexOf(Seperator);\n                int idx2 = rowKey.LastIndexOf(Seperator);\n                ReadOnlySpan<char> rowKeySpan = rowKey.AsSpan();\n                ReadOnlySpan<char> addressStr = rowKeySpan[..idx1];\n                ReadOnlySpan<char> portStr = rowKeySpan.Slice(idx1 + 1, idx2 - idx1 - 1);\n                ReadOnlySpan<char> genStr = rowKeySpan[(idx2 + 1)..];\n                IPAddress address = IPAddress.Parse(addressStr);\n                int port = int.Parse(portStr);\n                int generation = int.Parse(genStr);\n                return SiloAddress.New(address, port, generation);\n            }\n            catch (Exception exc)\n            {\n                throw new AggregateException(\"Error from UnpackRowKey\", exc);\n            }\n        }\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n            sb.Append(\"OrleansSilo [\");\n            sb.Append(\" Deployment=\").Append(DeploymentId);\n            sb.Append(\" LocalEndpoint=\").Append(Address);\n            sb.Append(\" LocalPort=\").Append(Port);\n            sb.Append(\" Generation=\").Append(Generation);\n\n            sb.Append(\" Host=\").Append(HostName);\n            sb.Append(\" Status=\").Append(Status);\n            sb.Append(\" ProxyPort=\").Append(ProxyPort);\n\n            sb.Append(\" SiloName=\").Append(SiloName);\n\n            if (!string.IsNullOrEmpty(SuspectingSilos)) sb.Append(\" SuspectingSilos=\").Append(SuspectingSilos);\n            if (!string.IsNullOrEmpty(SuspectingTimes)) sb.Append(\" SuspectingTimes=\").Append(SuspectingTimes);\n            sb.Append(\" StartTime=\").Append(StartTime);\n            sb.Append(\" IAmAliveTime=\").Append(IAmAliveTime);\n            sb.Append(\"]\");\n            return sb.ToString();\n        }\n\n        public static string ConstructSiloIdentity(SiloAddress silo)\n        {\n            return string.Format(\"{0}-{1}-{2}\", silo.Endpoint.Address, silo.Endpoint.Port, silo.Generation);\n        }\n\n        public Dictionary<string, AttributeValue> GetKeys()\n        {\n            var keys = new Dictionary<string, AttributeValue>();\n            keys.Add(DEPLOYMENT_ID_PROPERTY_NAME, new AttributeValue(DeploymentId));\n            keys.Add(SILO_IDENTITY_PROPERTY_NAME, new AttributeValue(SiloIdentity));\n            return keys;\n        }\n\n        public Dictionary<string, AttributeValue> GetFields(bool includeKeys = false)\n        {\n            var fields = new Dictionary<string, AttributeValue>();\n\n            if (includeKeys)\n            {\n                fields.Add(DEPLOYMENT_ID_PROPERTY_NAME, new AttributeValue(DeploymentId));\n                fields.Add(SILO_IDENTITY_PROPERTY_NAME, new AttributeValue(SiloIdentity));\n            }\n\n            if (!string.IsNullOrWhiteSpace(Address))\n                fields.Add(ADDRESS_PROPERTY_NAME, new AttributeValue(Address));\n\n            fields.Add(PORT_PROPERTY_NAME, new AttributeValue { N = Port.ToString() });\n            fields.Add(GENERATION_PROPERTY_NAME, new AttributeValue { N = Generation.ToString() });\n\n            if (!string.IsNullOrWhiteSpace(HostName))\n                fields.Add(HOSTNAME_PROPERTY_NAME, new AttributeValue(HostName));\n\n            fields.Add(STATUS_PROPERTY_NAME, new AttributeValue { N = Status.ToString() });\n            fields.Add(PROXY_PORT_PROPERTY_NAME, new AttributeValue { N = ProxyPort.ToString() });\n\n            if (!string.IsNullOrWhiteSpace(SiloName))\n                fields.Add(SILO_NAME_PROPERTY_NAME, new AttributeValue(SiloName));\n\n            if (!string.IsNullOrWhiteSpace(SuspectingSilos))\n                fields.Add(SUSPECTING_SILOS_PROPERTY_NAME, new AttributeValue(SuspectingSilos));\n\n            if (!string.IsNullOrWhiteSpace(SuspectingTimes))\n                fields.Add(SUSPECTING_TIMES_PROPERTY_NAME, new AttributeValue(SuspectingTimes));\n\n            if (!string.IsNullOrWhiteSpace(StartTime))\n                fields.Add(START_TIME_PROPERTY_NAME, new AttributeValue(StartTime));\n\n            if (!string.IsNullOrWhiteSpace(IAmAliveTime))\n                fields.Add(I_AM_ALIVE_TIME_PROPERTY_NAME, new AttributeValue(IAmAliveTime));\n\n            fields.Add(MEMBERSHIP_VERSION_PROPERTY_NAME, new AttributeValue { N = MembershipVersion.ToString() });\n\n            fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = ETag.ToString() });\n            return fields;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Options/DynamoDBClusteringOptions.cs",
    "content": "using Orleans.Clustering.DynamoDB;\n\nnamespace Orleans.Configuration\n{\n    public class DynamoDBClusteringOptions : DynamoDBClientOptions\n    {\n        /// <summary>\n        /// Read capacity unit for DynamoDB storage\n        /// </summary>\n        public int ReadCapacityUnits { get; set; } = DynamoDBStorage.DefaultReadCapacityUnits;\n\n        /// <summary>\n        /// Write capacity unit for DynamoDB storage\n        /// </summary>\n        public int WriteCapacityUnits { get; set; } = DynamoDBStorage.DefaultWriteCapacityUnits;\n\n        /// <summary>\n        /// Use Provisioned Throughput for tables\n        /// </summary>\n        public bool UseProvisionedThroughput { get; set; } = true;\n\n        /// <summary>\n        /// Create the table if it doesn't exist\n        /// </summary>\n        public bool CreateIfNotExists { get; set; } = true;\n\n        /// <summary>\n        /// Update the table if it exists\n        /// </summary>\n        public bool UpdateIfExists { get; set; } = true;\n\n        /// <summary>\n        /// DynamoDB table name.\n        /// Defaults to 'OrleansSilos'.\n        /// </summary>\n        public string TableName { get; set; } = \"OrleansSilos\";\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Options/DynamoDBClusteringSiloOptions.cs",
    "content": "﻿namespace Orleans.Configuration\n{\n    public class DynamoDBClusteringSiloOptions\n    {\n        /// <summary>\n        /// Connection string for DynamoDB Storage\n        /// </summary>\n        [RedactConnectionString]\n        public string ConnectionString { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Options/DynamoDBGatewayOptions.cs",
    "content": "using Orleans.Clustering.DynamoDB;\n\nnamespace Orleans.Configuration\n{\n    public class DynamoDBGatewayOptions : DynamoDBClientOptions\n    {\n        /// <summary>\n        /// Read capacity unit for DynamoDB storage\n        /// </summary>\n        public int ReadCapacityUnits { get; set; } = DynamoDBStorage.DefaultReadCapacityUnits;\n\n        /// <summary>\n        /// Write capacity unit for DynamoDB storage\n        /// </summary>\n        public int WriteCapacityUnits { get; set; } = DynamoDBStorage.DefaultWriteCapacityUnits;\n\n        /// <summary>\n        /// Use Provisioned Throughput for tables\n        /// </summary>\n        public bool UseProvisionedThroughput { get; set; } = true;\n\n        /// <summary>\n        /// Create the table if it doesn't exist\n        /// </summary>\n        public bool CreateIfNotExists { get; set; } = true;\n\n        /// <summary>\n        /// Update the table if it exists\n        /// </summary>\n        public bool UpdateIfExists { get; set; } = true;\n\n        /// <summary>\n        /// DynamoDB table name.\n        /// Defaults to 'OrleansSilos'.\n        /// </summary>\n        public string TableName { get; set; } = \"OrleansSilos\";\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/Orleans.Clustering.DynamoDB.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Clustering.DynamoDB</PackageId>\n    <Title>Microsoft Orleans AWS DynamoDB Clustering Provider</Title>\n    <Description>Microsoft Orleans clustering provider backed by AWS DynamoDB</Description>\n    <PackageTags>$(PackageTags) AWS DynamoDB</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Clustering.DynamoDB</AssemblyName>\n    <RootNamespace>Orleans.Clustering.DynamoDB</RootNamespace>\n    <DefineConstants>$(DefineConstants);CLUSTERING_DYNAMODB</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBStorage.cs\" Link=\"Storage\\DynamoDBStorage.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBClientOptions.cs\" Link=\"Storage\\DynamoDBClientOptions.cs\" />\n    <Compile Include=\"..\\Shared\\AWSUtils.cs\" Link=\"AWSUtils.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"AWSSDK.DynamoDBv2\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AWS/Orleans.Clustering.DynamoDB/README.md",
    "content": "# Microsoft Orleans Clustering for DynamoDB\n\n## Introduction\nMicrosoft Orleans Clustering for DynamoDB provides cluster membership functionality for Microsoft Orleans using Amazon's DynamoDB. This allows Orleans silos to coordinate and form a cluster using DynamoDB as the backing store.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Clustering.DynamoDB\n```\n\n## Example - Configuring DynamoDB Membership\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace ExampleGrains;\n\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\n// Implement the grain interface\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"Hello, {greeting}!\");\n    }\n}\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            // Configure DynamoDB clustering\n            .UseDynamoDBClustering(options =>\n            {\n                options.AccessKey = \"YOUR_AWS_ACCESS_KEY\";\n                options.SecretKey = \"YOUR_AWS_SECRET_KEY\";\n                options.Region = \"us-east-1\";\n                options.TableName = \"OrleansClusteringTable\";\n                options.CreateIfNotExists = true;\n            });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"DynamoDB\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Configuration Guide](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/)\n- [Orleans Clustering](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n- [AWS SDK for .NET Documentation](https://docs.aws.amazon.com/sdk-for-net/index.html)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Hosting/DynamoDBGrainStorageProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"DynamoDB\", \"GrainStorage\", \"Silo\", typeof(DynamoDBGrainStorageProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class DynamoDBGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddDynamoDBGrainStorage(\n            name,\n            (OptionsBuilder<DynamoDBStorageOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var accessKey = configurationSection[nameof(options.AccessKey)];\n                if (!string.IsNullOrEmpty(accessKey))\n                {\n                    options.AccessKey = accessKey;\n                }\n\n                var secretKey = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(secretKey))\n                {\n                    options.SecretKey = secretKey;\n                }\n\n                var region = configurationSection[nameof(options.Service)] ?? configurationSection[\"Region\"];\n                if (!string.IsNullOrEmpty(region))\n                {\n                    options.Service = region;\n                }\n\n                var token = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(token))\n                {\n                    options.Token = token;\n                }\n\n                var profileName = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(profileName))\n                {\n                    options.ProfileName = profileName;\n                }\n\n                var serviceId = configurationSection[nameof(options.ServiceId)];\n                if (!string.IsNullOrEmpty(serviceId))\n                {\n                    options.ServiceId = serviceId;\n                }\n\n                var tableName = configurationSection[nameof(options.TableName)];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.ReadCapacityUnits)], out var rcu))\n                {\n                    options.ReadCapacityUnits = rcu;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.WriteCapacityUnits)], out var wcu))\n                {\n                    options.WriteCapacityUnits = wcu;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UseProvisionedThroughput)], out var upt))\n                {\n                    options.UseProvisionedThroughput = upt;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.CreateIfNotExists)], out var cine))\n                {\n                    options.CreateIfNotExists = cine;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UpdateIfExists)], out var uie))\n                {\n                    options.UpdateIfExists = uie;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.DeleteStateOnClear)], out var dsoc))\n                {\n                    options.DeleteStateOnClear = dsoc;\n                }\n\n                if (TimeSpan.TryParse(configurationSection[nameof(options.TimeToLive)], out var ttl))\n                {\n                    options.TimeToLive = ttl;\n                }\n\n                var serializerKey = configurationSection[\"SerializerKey\"];\n                if (!string.IsNullOrEmpty(serializerKey))\n                {\n                    options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Hosting/DynamoDBGrainStorageServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime.Hosting;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class DynamoDBGrainStorageServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage as the default grain storage.\n        /// </summary>\n        public static IServiceCollection AddDynamoDBGrainStorageAsDefault(this IServiceCollection services, Action<DynamoDBStorageOptions> configureOptions)\n        {\n            return services.AddDynamoDBGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage for grain storage.\n        /// </summary>\n        public static IServiceCollection AddDynamoDBGrainStorage(this IServiceCollection services, string name, Action<DynamoDBStorageOptions> configureOptions)\n        {\n            return services.AddDynamoDBGrainStorage(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage as the default grain storage.\n        /// </summary>\n        public static IServiceCollection AddDynamoDBGrainStorageAsDefault(this IServiceCollection services, Action<OptionsBuilder<DynamoDBStorageOptions>> configureOptions = null)\n        {\n            return services.AddDynamoDBGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage for grain storage.\n        /// </summary>\n        public static IServiceCollection AddDynamoDBGrainStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<DynamoDBStorageOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<DynamoDBStorageOptions>(name));\n            services.AddTransient<IConfigurationValidator>(sp => new DynamoDBGrainStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<DynamoDBStorageOptions>>().Get(name), name));\n            services.ConfigureNamedOptionForLogging<DynamoDBStorageOptions>(name);\n            services.AddTransient<IPostConfigureOptions<DynamoDBStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<DynamoDBStorageOptions>>();\n            return services.AddGrainStorage(name, DynamoDBGrainStorageFactory.Create);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Hosting/DynamoDBGrainStorageSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    public static class DynamoDBGrainStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddDynamoDBGrainStorageAsDefault(this ISiloBuilder builder, Action<DynamoDBStorageOptions> configureOptions)\n        {\n            return builder.AddDynamoDBGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddDynamoDBGrainStorage(this ISiloBuilder builder, string name, Action<DynamoDBStorageOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddDynamoDBGrainStorage(name, configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddDynamoDBGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<DynamoDBStorageOptions>> configureOptions = null)\n        {\n            return builder.AddDynamoDBGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use AWS DynamoDB storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddDynamoDBGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<DynamoDBStorageOptions>> configureOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddDynamoDBGrainStorage(name, configureOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Options/DynamoDBStorageOptions.cs",
    "content": "using System;\nusing Orleans.Persistence.DynamoDB;\nusing Orleans.Runtime;\nusing Orleans.Storage;\n\nnamespace Orleans.Configuration\n{\n    public class DynamoDBStorageOptions : DynamoDBClientOptions, IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Gets or sets a unique identifier for this service, which should survive deployment and redeployment.\n        /// </summary>\n        public string ServiceId { get; set; } = string.Empty;\n\n        /// <summary>\n        /// Use Provisioned Throughput for tables\n        /// </summary>\n        public bool UseProvisionedThroughput { get; set; } = true;\n\n        /// <summary>\n        /// Create the table if it doesn't exist\n        /// </summary>\n        public bool CreateIfNotExists { get; set; } = true;\n\n        /// <summary>\n        /// Update the table if it exists\n        /// </summary>\n        public bool UpdateIfExists { get; set; } = true;\n\n        /// <summary>\n        /// Read capacity unit for DynamoDB storage\n        /// </summary>\n        public int ReadCapacityUnits { get; set; } = DynamoDBStorage.DefaultReadCapacityUnits;\n\n        /// <summary>\n        /// Write capacity unit for DynamoDB storage\n        /// </summary>\n        public int WriteCapacityUnits { get; set; } = DynamoDBStorage.DefaultWriteCapacityUnits;\n\n        /// <summary>\n        /// DynamoDB table name.\n        /// Defaults to 'OrleansGrainState'.\n        /// </summary>\n        public string TableName { get; set; } = \"OrleansGrainState\";\n\n        /// <summary>\n        /// Indicates if grain data should be deleted or reset to defaults when a grain clears it's state.\n        /// </summary>\n        public bool DeleteStateOnClear { get; set; } = false;\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n        /// <summary>\n        /// Specifies a time span in which the item would be expired in the future\n        /// every StateWrite will increase the TTL of the grain\n        /// </summary>\n        public TimeSpan? TimeToLive { get; set; }\n        public IGrainStorageSerializer GrainStorageSerializer { get; set; }\n    }\n\n    /// <summary>\n    /// Configuration validator for DynamoDBStorageOptions\n    /// </summary>\n    public class DynamoDBGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        private readonly DynamoDBStorageOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        public DynamoDBGrainStorageOptionsValidator(DynamoDBStorageOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.TableName))\n                throw new OrleansConfigurationException(\n                    $\"Configuration for DynamoDBGrainStorage {this.name} is invalid. {nameof(this.options.TableName)} is not valid.\");\n\n            if (this.options.UseProvisionedThroughput)\n            {\n                if (this.options.ReadCapacityUnits == 0)\n                    throw new OrleansConfigurationException(\n                        $\"Configuration for DynamoDBGrainStorage {this.name} is invalid. {nameof(this.options.ReadCapacityUnits)} is not valid.\");\n\n                if (this.options.WriteCapacityUnits == 0)\n                    throw new OrleansConfigurationException(\n                        $\"Configuration for DynamoDBGrainStorage {this.name} is invalid. {nameof(this.options.WriteCapacityUnits)} is not valid.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Orleans.Persistence.DynamoDB.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Persistence.DynamoDB</PackageId>\n    <Title>Microsoft Orleans AWS DynamoDB Persistence Provider</Title>\n    <Description>Microsoft Orleans persistence providers backed by AWS DynamoDB</Description>\n    <PackageTags>$(PackageTags) AWS DynamoDB</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Persistence.DynamoDB</AssemblyName>\n    <RootNamespace>Orleans.Persistence.DynamoDB</RootNamespace>\n    <DefineConstants>$(DefineConstants);PERSISTENCE_DYNAMODB</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\AWSUtils.cs\" Link=\"AWSUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBStorage.cs\" Link=\"Storage\\DynamoDBStorage.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBClientOptions.cs\" Link=\"Storage\\DynamoDBClientOptions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"AWSSDK.DynamoDBv2\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/Provider/DynamoDBGrainStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Orleans.Configuration;\nusing Orleans.Persistence.DynamoDB;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Dynamo DB storage Provider.\n    /// Persist Grain State in a DynamoDB table either in Json or Binary format.\n    /// </summary>\n    public partial class DynamoDBGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private const int MAX_DATA_SIZE = 400 * 1024;\n        private const string GRAIN_REFERENCE_PROPERTY_NAME = \"GrainReference\";\n        private const string BINARY_STATE_PROPERTY_NAME = \"GrainState\";\n        private const string GRAIN_TYPE_PROPERTY_NAME = \"GrainType\";\n        private const string ETAG_PROPERTY_NAME = \"ETag\";\n        private const string GRAIN_TTL_PROPERTY_NAME = \"GrainTtl\";\n        private const string CURRENT_ETAG_ALIAS = \":currentETag\";\n\n        private readonly DynamoDBStorageOptions options;\n        private readonly IActivatorProvider _activatorProvider;\n        private readonly ILogger logger;\n        private readonly string name;\n\n        private DynamoDBStorage storage;\n\n        /// <summary>\n        /// Default Constructor\n        /// </summary>\n        public DynamoDBGrainStorage(\n            string name,\n            DynamoDBStorageOptions options,\n            IActivatorProvider activatorProvider,\n            ILogger<DynamoDBGrainStorage> logger)\n        {\n            this.name = name;\n            this.logger = logger;\n            this.options = options;\n            _activatorProvider = activatorProvider;\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<DynamoDBGrainStorage>(this.name), this.options.InitStage, Init, Close);\n        }\n\n        /// <summary> Initialization function for this storage provider. </summary>\n        public async Task Init(CancellationToken ct)\n        {\n            var stopWatch = Stopwatch.StartNew();\n\n            try\n            {\n                var initMsg = string.Format(\"Init: Name={0} ServiceId={1} Table={2} DeleteStateOnClear={3}\",\n                        this.name, this.options.ServiceId, this.options.TableName, this.options.DeleteStateOnClear);\n\n                LogInformationInitializingDynamoDBGrainStorage(logger, this.name, initMsg);\n\n                this.storage = new DynamoDBStorage(\n                    this.logger,\n                    this.options.Service,\n                    this.options.AccessKey,\n                    this.options.SecretKey,\n                    this.options.Token,\n                    this.options.ProfileName,\n                    this.options.ReadCapacityUnits,\n                    this.options.WriteCapacityUnits,\n                    this.options.UseProvisionedThroughput,\n                    this.options.CreateIfNotExists,\n                    this.options.UpdateIfExists);\n\n                await storage.InitializeTable(this.options.TableName,\n                    new List<KeySchemaElement>\n                    {\n                        new KeySchemaElement { AttributeName = GRAIN_REFERENCE_PROPERTY_NAME, KeyType = KeyType.HASH },\n                        new KeySchemaElement { AttributeName = GRAIN_TYPE_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                    },\n                    new List<AttributeDefinition>\n                    {\n                        new AttributeDefinition { AttributeName = GRAIN_REFERENCE_PROPERTY_NAME, AttributeType = ScalarAttributeType.S },\n                        new AttributeDefinition { AttributeName = GRAIN_TYPE_PROPERTY_NAME, AttributeType = ScalarAttributeType.S }\n                    },\n                    secondaryIndexes: null,\n                    ttlAttributeName: this.options.TimeToLive.HasValue ? GRAIN_TTL_PROPERTY_NAME : null);\n                stopWatch.Stop();\n                LogInformationProviderInitialized(logger, this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds);\n            }\n            catch (Exception exc)\n            {\n                stopWatch.Stop();\n                LogErrorProviderInitFailed(logger, this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds, exc);\n                throw;\n            }\n        }\n\n        /// <summary> Shutdown this storage provider. </summary>\n        public Task Close(CancellationToken ct) => Task.CompletedTask;\n\n        /// <summary> Read state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ReadStateAsync{T}\"/>\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (this.storage == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string partitionKey = GetKeyString(grainId);\n            LogTraceReadingGrainState(logger, grainType, partitionKey, grainId, this.options.TableName);\n\n            string rowKey = AWSUtils.ValidateDynamoDBRowKey(grainType);\n\n            var record = await this.storage.ReadSingleEntryAsync(this.options.TableName,\n                new Dictionary<string, AttributeValue>\n                {\n                    { GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(partitionKey) },\n                    { GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(rowKey) }\n                },\n                (fields) =>\n                {\n                    return new GrainStateRecord\n                    {\n                        GrainType = fields[GRAIN_TYPE_PROPERTY_NAME].S,\n                        GrainReference = fields[GRAIN_REFERENCE_PROPERTY_NAME].S,\n                        ETag = int.Parse(fields[ETAG_PROPERTY_NAME].N),\n                        State = fields.TryGetValue(BINARY_STATE_PROPERTY_NAME, out var propertyName) ? propertyName.B?.ToArray() : null,\n                    };\n                }).ConfigureAwait(false);\n\n            if (record != null)\n            {\n                var loadedState = ConvertFromStorageFormat<T>(record);\n                grainState.RecordExists = loadedState != null;\n                grainState.State = loadedState ?? CreateInstance<T>();\n                grainState.ETag = record.ETag.ToString();\n            }\n            else\n            {\n                ResetGrainState(grainState);\n            }\n        }\n\n        /// <summary> Write state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.WriteStateAsync{T}\"/>\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (this.storage == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string partitionKey = GetKeyString(grainId);\n            string rowKey = AWSUtils.ValidateDynamoDBRowKey(grainType);\n\n            var record = new GrainStateRecord { GrainReference = partitionKey, GrainType = rowKey };\n\n            try\n            {\n                ConvertToStorageFormat(grainState.State, record);\n                await WriteStateInternal(grainState, record);\n            }\n            catch (ConditionalCheckFailedException exc)\n            {\n                throw new InconsistentStateException($\"Inconsistent grain state: {exc}\");\n            }\n            catch (Exception exc)\n            {\n                LogErrorWritingGrainState(logger, exc, grainType, grainId, grainState.ETag, this.options.TableName);\n                throw;\n            }\n        }\n\n        private async Task WriteStateInternal<T>(IGrainState<T> grainState, GrainStateRecord record, bool clear = false)\n        {\n            var fields = new Dictionary<string, AttributeValue>();\n            if (this.options.TimeToLive.HasValue)\n            {\n                fields.Add(GRAIN_TTL_PROPERTY_NAME, new AttributeValue { N = ((DateTimeOffset)DateTime.UtcNow.Add(this.options.TimeToLive.Value)).ToUnixTimeSeconds().ToString() });\n            }\n\n            if (record.State != null && record.State.Length > 0)\n            {\n                fields.Add(BINARY_STATE_PROPERTY_NAME, new AttributeValue { B = new MemoryStream(record.State) });\n            }\n            else\n            {\n                fields.Add(BINARY_STATE_PROPERTY_NAME, new AttributeValue { NULL = true });\n            }\n\n            int newEtag = 0;\n            if (clear)\n            {\n                fields.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference));\n                fields.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType));\n\n                int currentEtag;\n                int.TryParse(grainState.ETag, out currentEtag);\n                newEtag = currentEtag;\n                newEtag++;\n                fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = newEtag.ToString() });\n\n                await this.storage.PutEntryAsync(this.options.TableName, fields).ConfigureAwait(false);\n            }\n            else if (string.IsNullOrWhiteSpace(grainState.ETag))\n            {\n                fields.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference));\n                fields.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType));\n                fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = \"0\" });\n\n                var expression = $\"attribute_not_exists({GRAIN_REFERENCE_PROPERTY_NAME}) AND attribute_not_exists({GRAIN_TYPE_PROPERTY_NAME})\";\n                await this.storage.PutEntryAsync(this.options.TableName, fields, expression).ConfigureAwait(false);\n            }\n            else\n            {\n                var keys = new Dictionary<string, AttributeValue>();\n                keys.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference));\n                keys.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType));\n\n                int currentEtag;\n                int.TryParse(grainState.ETag, out currentEtag);\n                newEtag = currentEtag;\n                newEtag++;\n                fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = newEtag.ToString() });\n\n                var conditionalValues = new Dictionary<string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = currentEtag.ToString() } } };\n                var expression = $\"{ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}\";\n                await this.storage.UpsertEntryAsync(this.options.TableName, keys, fields, expression, conditionalValues).ConfigureAwait(false);\n            }\n\n            grainState.ETag = newEtag.ToString();\n            grainState.RecordExists = !clear;\n        }\n\n        /// <summary> Clear / Delete state data function for this storage provider. </summary>\n        /// <remarks>\n        /// If the <c>DeleteStateOnClear</c> is set to <c>true</c> then the table row\n        /// for this grain will be deleted / removed, otherwise the table row will be\n        /// cleared by overwriting with default / null values.\n        /// </remarks>\n        /// <see cref=\"IGrainStorage.ClearStateAsync{T}\"/>\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (this.storage == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string partitionKey = GetKeyString(grainId);\n            LogTraceClearingGrainState(logger, grainType, partitionKey, grainId, grainState.ETag, this.options.DeleteStateOnClear, this.options.TableName);\n\n            string rowKey = AWSUtils.ValidateDynamoDBRowKey(grainType);\n            var record = new GrainStateRecord { GrainReference = partitionKey, ETag = string.IsNullOrWhiteSpace(grainState.ETag) ? 0 : int.Parse(grainState.ETag), GrainType = rowKey };\n\n            var operation = \"Clearing\";\n            try\n            {\n                if (this.options.DeleteStateOnClear)\n                {\n                    operation = \"Deleting\";\n                    var keys = new Dictionary<string, AttributeValue>();\n                    keys.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference));\n                    keys.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType));\n\n                    await this.storage.DeleteEntryAsync(this.options.TableName, keys).ConfigureAwait(false);\n                    ResetGrainState(grainState);\n                }\n                else\n                {\n                    await WriteStateInternal(grainState, record, true);\n                    grainState.State = CreateInstance<T>();\n                    grainState.RecordExists = false;\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorClearingGrainState(logger, exc, operation, grainType, grainId, grainState.ETag, this.options.TableName);\n                throw;\n            }\n        }\n\n        internal class GrainStateRecord\n        {\n            public string GrainReference { get; set; } = \"\";\n            public string GrainType { get; set; } = \"\";\n            public byte[] State { get; set; }\n            public int ETag { get; set; }\n        }\n\n        private string GetKeyString(GrainId grainId)\n        {\n            var key = $\"{options.ServiceId}_{grainId}\";\n            return AWSUtils.ValidateDynamoDBPartitionKey(key);\n        }\n\n        internal T ConvertFromStorageFormat<T>(GrainStateRecord entity)\n        {\n            T dataValue = default;\n            try\n            {\n                if (entity.State is { Length: > 0 })\n                    dataValue = this.options.GrainStorageSerializer.Deserialize<T>(entity.State);\n            }\n            catch (Exception exc)\n            {\n                var sb = new StringBuilder();\n                sb.AppendFormat(\"Unable to convert from storage format GrainStateEntity.Data={0}\", entity.State);\n\n                if (dataValue != null)\n                {\n                    sb.Append($\"Data Value={dataValue} Type={dataValue.GetType()}\");\n                }\n\n                var message = sb.ToString();\n                LogError(logger, message);\n                throw new AggregateException(message, exc);\n            }\n\n            return dataValue;\n        }\n\n        internal void ConvertToStorageFormat(object grainState, GrainStateRecord entity)\n        {\n            int dataSize;\n            // Convert to binary format\n            entity.State = this.options.GrainStorageSerializer.Serialize(grainState).ToArray();\n            dataSize = BINARY_STATE_PROPERTY_NAME.Length + entity.State.Length;\n\n            LogTraceWritingBinaryData(logger, dataSize, entity.GrainReference, entity.GrainType);\n\n            var pkSize = GRAIN_REFERENCE_PROPERTY_NAME.Length + entity.GrainReference.Length;\n            var rkSize = GRAIN_TYPE_PROPERTY_NAME.Length + entity.GrainType.Length;\n            var versionSize = ETAG_PROPERTY_NAME.Length + entity.ETag.ToString().Length;\n\n            if ((pkSize + rkSize + versionSize + dataSize) > MAX_DATA_SIZE)\n            {\n                var msg = $\"Data too large to write to DynamoDB table. Size={dataSize} MaxSize={MAX_DATA_SIZE}\";\n                throw new ArgumentOutOfRangeException(\"GrainState.Size\", msg);\n            }\n        }\n\n        private void ResetGrainState<T>(IGrainState<T> grainState)\n        {\n            grainState.RecordExists = false;\n            grainState.ETag = null;\n            grainState.State = CreateInstance<T>();\n        }\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"AWS DynamoDB Grain Storage {Name} is initializing: {InitMsg}\"\n        )]\n        private static partial void LogInformationInitializingDynamoDBGrainStorage(ILogger logger, string name, string initMsg);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Initializing provider {Name} of type {Type} in stage {Stage} took {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private static partial void LogInformationProviderInitialized(ILogger logger, string name, string type, int stage, long elapsedMilliseconds);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Provider_ErrorFromInit,\n            Level = LogLevel.Error,\n            Message = \"Initialization failed for provider {Name} of type {Type} in stage {Stage} in {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private static partial void LogErrorProviderInitFailed(ILogger logger, string name, string type, int stage, long elapsedMilliseconds, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Reading: GrainType={GrainType} Pk={PartitionKey} GrainId={GrainId} from Table={TableName}\"\n        )]\n        private static partial void LogTraceReadingGrainState(ILogger logger, string grainType, string partitionKey, GrainId grainId, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error Writing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to Table={TableName}\"\n        )]\n        private static partial void LogErrorWritingGrainState(ILogger logger, Exception exception, string grainType, GrainId grainId, string eTag, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Clearing: GrainType={GrainType} Pk={PartitionKey} GrainId={GrainId} ETag={ETag} DeleteStateOnClear={DeleteStateOnClear} from Table={TableName}\"\n        )]\n        private static partial void LogTraceClearingGrainState(ILogger logger, string grainType, string partitionKey, GrainId grainId, string eTag, bool deleteStateOnClear, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error {Operation}: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from Table={TableName}\"\n        )]\n        private static partial void LogErrorClearingGrainState(ILogger logger, Exception exception, string operation, string grainType, GrainId grainId, string eTag, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"{Message}\"\n        )]\n        private static partial void LogError(ILogger logger, string message);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Writing binary data size = {DataSize} for grain id = Partition={Partition} / Row={Row}\"\n        )]\n        private static partial void LogTraceWritingBinaryData(ILogger logger, int dataSize, string partition, string row);\n    }\n\n    public static class DynamoDBGrainStorageFactory\n    {\n        public static DynamoDBGrainStorage Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<DynamoDBStorageOptions>>();\n            return ActivatorUtilities.CreateInstance<DynamoDBGrainStorage>(services, optionsMonitor.Get(name), name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Persistence.DynamoDB/README.md",
    "content": "# Microsoft Orleans Persistence for DynamoDB\n\n## Introduction\nMicrosoft Orleans Persistence for DynamoDB provides grain persistence for Microsoft Orleans using Amazon's DynamoDB. This allows your grains to persist their state in DynamoDB and reload it when they are reactivated.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Persistence.DynamoDB\n```\n\n## Example - Configuring DynamoDB Persistence\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure DynamoDB as grain storage\n            .AddDynamoDBGrainStorage(\n                name: \"dynamoStore\",\n                configureOptions: options =>\n                {\n                    options.AccessKey = \"YOUR_AWS_ACCESS_KEY\";\n                    options.SecretKey = \"YOUR_AWS_SECRET_KEY\";\n                    options.Region = \"us-east-1\";\n                    options.TableName = \"OrleansGrainState\";\n                    options.CreateIfNotExists = true;\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Grain Storage in a Grain\n```csharp\n// Define grain state class\n\npublic class MyGrainState\n{\n    public string Data { get; set; }\n    public int Version { get; set; }\n}\n\n// Grain implementation that uses the DynamoDB storage\npublic class MyGrain : Grain, IMyGrain, IGrainWithStringKey\n{\n    private readonly IPersistentState<MyGrainState> _state;\n\n    public MyGrain([PersistentState(\"state\", \"dynamoStore\")] IPersistentState<MyGrainState> state)\n    {\n        _state = state;\n    }\n\n    public async Task SetData(string data)\n    {\n        _state.State.Data = data;\n        _state.State.Version++;\n        await _state.WriteStateAsync();\n    }\n\n    public Task<string> GetData()\n    {\n        return Task.FromResult(_state.State.Data);\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n- [AWS SDK for .NET Documentation](https://docs.aws.amazon.com/sdk-for-net/index.html)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/DynamoDBRemindersProviderBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"DynamoDB\", \"Reminders\", \"Silo\", typeof(DynamoDBRemindersProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class DynamoDBRemindersProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseDynamoDBReminderService(options =>\n            {\n                var accessKey = configurationSection[nameof(options.AccessKey)];\n                if (!string.IsNullOrEmpty(accessKey))\n                {\n                    options.AccessKey = accessKey;\n                }\n\n                var secretKey = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(secretKey))\n                {\n                    options.SecretKey = secretKey;\n                }\n\n                var region = configurationSection[nameof(options.Service)] ?? configurationSection[\"Region\"];\n                if (!string.IsNullOrEmpty(region))\n                {\n                    options.Service = region;\n                }\n\n                var token = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(token))\n                {\n                    options.Token = token;\n                }\n\n                var profileName = configurationSection[nameof(options.SecretKey)];\n                if (!string.IsNullOrEmpty(profileName))\n                {\n                    options.ProfileName = profileName;\n                }\n\n                var tableName = configurationSection[nameof(options.TableName)];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.ReadCapacityUnits)], out var rcu))\n                {\n                    options.ReadCapacityUnits = rcu;\n                }\n\n                if (int.TryParse(configurationSection[nameof(options.WriteCapacityUnits)], out var wcu))\n                {\n                    options.WriteCapacityUnits = wcu;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UseProvisionedThroughput)], out var upt))\n                {\n                    options.UseProvisionedThroughput = upt;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.CreateIfNotExists)], out var cine))\n                {\n                    options.CreateIfNotExists = cine;\n                }\n\n                if (bool.TryParse(configurationSection[nameof(options.UpdateIfExists)], out var uie))\n                {\n                    options.UpdateIfExists = uie;\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/DynamoDBServiceCollectionReminderExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Reminders.DynamoDB;\nusing System;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class DynamoDBServiceCollectionReminderExtensions\n    {\n        /// <summary>\n        /// Adds reminder storage backed by Amazon DynamoDB.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n        /// </returns>\n        public static IServiceCollection UseDynamoDBReminderService(this IServiceCollection services, Action<DynamoDBReminderStorageOptions> configure)\n        {\n            services.AddReminders();\n            services.AddSingleton<IReminderTable, DynamoDBReminderTable>();\n            services.Configure<DynamoDBReminderStorageOptions>(configure);\n            services.ConfigureFormatter<DynamoDBReminderStorageOptions>();\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/DynamoDBSiloBuilderReminderExtensions.cs",
    "content": "using Orleans.Configuration;\nusing System;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo host builder extensions.\n    /// </summary>\n    public static class DynamoDBSiloBuilderReminderExtensions\n    {\n        /// <summary>\n        /// Adds reminder storage backed by Amazon DynamoDB.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n        /// </returns>\n        public static ISiloBuilder UseDynamoDBReminderService(this ISiloBuilder builder, Action<DynamoDBReminderStorageOptions> configure)\n        {\n            builder.ConfigureServices(services => services.UseDynamoDBReminderService(configure));\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/Orleans.Reminders.DynamoDB.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Reminders.DynamoDB</PackageId>\n    <Title>Microsoft Orleans AWS DynamoDB Reminders Provider</Title>\n    <Description>Microsoft Orleans reminders provider backed by AWS DynamoDB</Description>\n    <PackageTags>$(PackageTags) AWS DynamoDB</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Reminders.DynamoDB</AssemblyName>\n    <RootNamespace>Orleans.Reminders.DynamoDB</RootNamespace>\n    <DefineConstants>$(DefineConstants);REMINDERS_DYNAMODB</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBStorage.cs\" Link=\"Storage\\DynamoDBStorage.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\DynamoDBClientOptions.cs\" Link=\"Storage\\DynamoDBClientOptions.cs\" />\n    <Compile Include=\"..\\Shared\\AWSUtils.cs\" Link=\"AWSUtils.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <PackageReference Include=\"AWSSDK.DynamoDBv2\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/README.md",
    "content": "# Microsoft Orleans Reminders for DynamoDB\n\n## Introduction\nMicrosoft Orleans Reminders for DynamoDB provides persistence for Orleans reminders using Amazon's DynamoDB. This allows your Orleans applications to schedule persistent reminders that will be triggered even after silo restarts or grain deactivation.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Reminders.DynamoDB\n```\n\n## Example - Configuring DynamoDB Reminders\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure DynamoDB as reminder storage\n            .UseDynamoDBReminderService(options =>\n            {\n                options.AccessKey = \"YOUR_AWS_ACCESS_KEY\";\n                options.SecretKey = \"YOUR_AWS_SECRET_KEY\";\n                options.Region = \"us-east-1\";\n                options.TableName = \"OrleansReminders\";\n                options.CreateIfNotExists = true;\n            });\n    });\n\n// Run the host\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to the grain\nvar reminderGrain = host.Services.GetRequiredService<IGrainFactory>()\n    .GetGrain<IReminderGrain>(\"my-reminder-grain\");\n\n// Start the reminder\nawait reminderGrain.StartReminder(\"ExampleReminder\");\nConsole.WriteLine(\"Reminder started!\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Using Reminders in a Grain\n```csharp\nusing System;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\n\nnamespace ReminderExample;\n\npublic interface IReminderGrain : IGrainWithStringKey\n{\n    Task StartReminder(string reminderName);\n    Task StopReminder();\n}\n\npublic class ReminderGrain : Grain, IReminderGrain, IRemindable\n{\n    private string _reminderName = \"MyReminder\";\n\n    public async Task StartReminder(string reminderName)\n    {\n        _reminderName = reminderName;\n        \n        // Register a persistent reminder\n        await RegisterOrUpdateReminder(\n            reminderName,\n            TimeSpan.FromMinutes(2),  // Time to delay before the first tick (must be > 1 minute)\n            TimeSpan.FromMinutes(5)); // Period of the reminder (must be > 1 minute)\n    }\n\n    public async Task StopReminder()\n    {\n        // Find and unregister the reminder\n        var reminder = await GetReminder(_reminderName);\n        if (reminder != null)\n        {\n            await UnregisterReminder(reminder);\n        }\n    }\n\n    public Task ReceiveReminder(string reminderName, TickStatus status)\n    {\n        // This method is called when the reminder ticks\n        Console.WriteLine($\"Reminder {reminderName} triggered at {DateTime.UtcNow}. Status: {status}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Reminders and Timers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n- [Reminder Services](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/reminder-services)\n- [AWS SDK for .NET Documentation](https://docs.aws.amazon.com/sdk-for-net/index.html)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/Reminders/DynamoDBReminderTable.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Reminders.DynamoDB\n{\n    /// <summary>\n    /// Implementation for IReminderTable using DynamoDB as underlying storage.\n    /// </summary>\n    internal sealed partial class DynamoDBReminderTable : IReminderTable\n    {\n        private const string GRAIN_REFERENCE_PROPERTY_NAME = \"GrainReference\";\n        private const string REMINDER_NAME_PROPERTY_NAME = \"ReminderName\";\n        private const string SERVICE_ID_PROPERTY_NAME = \"ServiceId\";\n        private const string START_TIME_PROPERTY_NAME = \"StartTime\";\n        private const string PERIOD_PROPERTY_NAME = \"Period\";\n        private const string GRAIN_HASH_PROPERTY_NAME = \"GrainHash\";\n        private const string REMINDER_ID_PROPERTY_NAME = \"ReminderId\";\n        private const string ETAG_PROPERTY_NAME = \"ETag\";\n        private const string CURRENT_ETAG_ALIAS = \":currentETag\";\n        private const string SERVICE_ID_GRAIN_HASH_INDEX = \"ServiceIdIndex\";\n        private const string SERVICE_ID_GRAIN_REFERENCE_INDEX = \"ServiceIdGrainReferenceIndex\";\n\n        private readonly ILogger logger;\n        private readonly DynamoDBReminderStorageOptions options;\n        private readonly string serviceId;\n\n        private DynamoDBStorage storage;\n\n        /// <summary>Initializes a new instance of the <see cref=\"DynamoDBReminderTable\"/> class.</summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"clusterOptions\"></param>\n        /// <param name=\"storageOptions\"></param>\n        public DynamoDBReminderTable(\n            ILoggerFactory loggerFactory,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<DynamoDBReminderStorageOptions> storageOptions)\n        {\n            this.logger = loggerFactory.CreateLogger<DynamoDBReminderTable>();\n            this.serviceId = clusterOptions.Value.ServiceId;\n            this.options = storageOptions.Value;\n        }\n\n        /// <summary>Initialize current instance with specific global configuration and logger</summary>\n        public Task Init()\n        {\n            this.storage = new DynamoDBStorage(\n                this.logger,\n                this.options.Service,\n                this.options.AccessKey,\n                this.options.SecretKey,\n                this.options.Token,\n                this.options.ProfileName,\n                this.options.ReadCapacityUnits,\n                this.options.WriteCapacityUnits,\n                this.options.UseProvisionedThroughput,\n                this.options.CreateIfNotExists,\n                this.options.UpdateIfExists);\n\n            LogInformationInitializingDynamoDBRemindersTable(logger);\n\n            var serviceIdGrainHashGlobalSecondaryIndex = new GlobalSecondaryIndex\n            {\n                IndexName = SERVICE_ID_GRAIN_HASH_INDEX,\n                Projection = new Projection { ProjectionType = ProjectionType.ALL },\n                KeySchema = new List<KeySchemaElement>\n                {\n                    new KeySchemaElement { AttributeName = SERVICE_ID_PROPERTY_NAME, KeyType = KeyType.HASH},\n                    new KeySchemaElement { AttributeName = GRAIN_HASH_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                }\n            };\n\n            var serviceIdGrainReferenceGlobalSecondaryIndex = new GlobalSecondaryIndex\n            {\n                IndexName = SERVICE_ID_GRAIN_REFERENCE_INDEX,\n                Projection = new Projection { ProjectionType = ProjectionType.ALL },\n                KeySchema = new List<KeySchemaElement>\n                {\n                    new KeySchemaElement { AttributeName = SERVICE_ID_PROPERTY_NAME, KeyType = KeyType.HASH},\n                    new KeySchemaElement { AttributeName = GRAIN_REFERENCE_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                }\n            };\n\n            return this.storage.InitializeTable(this.options.TableName,\n                new List<KeySchemaElement>\n                {\n                    new KeySchemaElement { AttributeName = REMINDER_ID_PROPERTY_NAME, KeyType = KeyType.HASH },\n                    new KeySchemaElement { AttributeName = GRAIN_HASH_PROPERTY_NAME, KeyType = KeyType.RANGE }\n                },\n                new List<AttributeDefinition>\n                {\n                    new AttributeDefinition { AttributeName = REMINDER_ID_PROPERTY_NAME, AttributeType = ScalarAttributeType.S },\n                    new AttributeDefinition { AttributeName = GRAIN_HASH_PROPERTY_NAME, AttributeType = ScalarAttributeType.N },\n                    new AttributeDefinition { AttributeName = SERVICE_ID_PROPERTY_NAME, AttributeType = ScalarAttributeType.S },\n                    new AttributeDefinition { AttributeName = GRAIN_REFERENCE_PROPERTY_NAME, AttributeType = ScalarAttributeType.S }\n                },\n                new List<GlobalSecondaryIndex> { serviceIdGrainHashGlobalSecondaryIndex, serviceIdGrainReferenceGlobalSecondaryIndex });\n        }\n\n        /// <summary>\n        /// Reads a reminder for a grain reference by reminder name.\n        /// Read a row from the reminder table\n        /// </summary>\n        /// <param name=\"grainId\"> grain ref to locate the row </param>\n        /// <param name=\"reminderName\"> reminder name to locate the row </param>\n        /// <returns> Return the ReminderTableData if the rows were read successfully </returns>\n        public async Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            var reminderId = ConstructReminderId(this.serviceId, grainId, reminderName);\n\n            var keys = new Dictionary<string, AttributeValue>\n                {\n                    { $\"{REMINDER_ID_PROPERTY_NAME}\", new AttributeValue(reminderId) },\n                    { $\"{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = grainId.GetUniformHashCode().ToString() } }\n                };\n\n            try\n            {\n                return await this.storage.ReadSingleEntryAsync(this.options.TableName, keys, this.Resolve).ConfigureAwait(false);\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadReminderEntry(logger, exc, new(keys), this.options.TableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Read one row from the reminder table\n        /// </summary>\n        /// <param name=\"grainId\">grain ref to locate the row </param>\n        /// <returns> Return the ReminderTableData if the rows were read successfully </returns>\n        public async Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            var expressionValues = new Dictionary<string, AttributeValue>\n                {\n                    { $\":{SERVICE_ID_PROPERTY_NAME}\", new AttributeValue(this.serviceId) },\n                    { $\":{GRAIN_REFERENCE_PROPERTY_NAME}\", new AttributeValue(grainId.ToString()) }\n                };\n\n            try\n            {\n                var expression = $\"{SERVICE_ID_PROPERTY_NAME} = :{SERVICE_ID_PROPERTY_NAME} AND {GRAIN_REFERENCE_PROPERTY_NAME} = :{GRAIN_REFERENCE_PROPERTY_NAME}\";\n                var records = await this.storage.QueryAllAsync(this.options.TableName, expressionValues, expression, this.Resolve, SERVICE_ID_GRAIN_REFERENCE_INDEX, consistentRead: false).ConfigureAwait(false);\n\n                return new ReminderTableData(records);\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadReminderEntries(logger, exc, new(expressionValues), this.options.TableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Reads reminder table data for a given hash range.\n        /// </summary>\n        /// <param name=\"begin\"></param>\n        /// <param name=\"end\"></param>\n        /// <returns> Return the RemiderTableData if the rows were read successfully </returns>\n        public async Task<ReminderTableData> ReadRows(uint begin, uint end)\n        {\n            Dictionary<string, AttributeValue> expressionValues = null;\n\n            try\n            {\n                string expression = string.Empty;\n                List<ReminderEntry> records;\n\n                if (begin < end)\n                {\n                    expressionValues = new Dictionary<string, AttributeValue>\n                    {\n                        { $\":{SERVICE_ID_PROPERTY_NAME}\", new AttributeValue(this.serviceId) },\n                        { $\":Begin{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = (begin + 1).ToString() } },\n                        { $\":End{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = end.ToString() } }\n                    };\n                    expression = $\"{SERVICE_ID_PROPERTY_NAME} = :{SERVICE_ID_PROPERTY_NAME} AND {GRAIN_HASH_PROPERTY_NAME} BETWEEN :Begin{GRAIN_HASH_PROPERTY_NAME} AND :End{GRAIN_HASH_PROPERTY_NAME}\";\n                    records = await this.storage.QueryAllAsync(this.options.TableName, expressionValues, expression, this.Resolve, SERVICE_ID_GRAIN_HASH_INDEX, consistentRead: false).ConfigureAwait(false);\n                }\n                else\n                {\n                    expressionValues = new Dictionary<string, AttributeValue>\n                    {\n                        { $\":{SERVICE_ID_PROPERTY_NAME}\", new AttributeValue(this.serviceId) },\n                        { $\":End{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = end.ToString() } }\n                    };\n                    expression = $\"{SERVICE_ID_PROPERTY_NAME} = :{SERVICE_ID_PROPERTY_NAME} AND {GRAIN_HASH_PROPERTY_NAME} <= :End{GRAIN_HASH_PROPERTY_NAME}\";\n                    records = await this.storage.QueryAllAsync(this.options.TableName, expressionValues, expression, this.Resolve, SERVICE_ID_GRAIN_HASH_INDEX, consistentRead: false).ConfigureAwait(false);\n\n                    expressionValues = new Dictionary<string, AttributeValue>\n                    {\n                        { $\":{SERVICE_ID_PROPERTY_NAME}\", new AttributeValue(this.serviceId) },\n                        { $\":Begin{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = begin.ToString() } }\n                    };\n                    expression = $\"{SERVICE_ID_PROPERTY_NAME} = :{SERVICE_ID_PROPERTY_NAME} AND {GRAIN_HASH_PROPERTY_NAME} > :Begin{GRAIN_HASH_PROPERTY_NAME}\";\n                    records.AddRange(await this.storage.QueryAllAsync(this.options.TableName, expressionValues, expression, this.Resolve, SERVICE_ID_GRAIN_HASH_INDEX, consistentRead: false).ConfigureAwait(false));\n\n                }\n\n                return new ReminderTableData(records);\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadReminderEntryRange(logger, exc, new(expressionValues), this.options.TableName);\n                throw;\n            }\n        }\n\n        private ReminderEntry Resolve(Dictionary<string, AttributeValue> item)\n        {\n            return new ReminderEntry\n            {\n                ETag = item[ETAG_PROPERTY_NAME].N,\n                GrainId = GrainId.Parse(item[GRAIN_REFERENCE_PROPERTY_NAME].S),\n                Period = TimeSpan.Parse(item[PERIOD_PROPERTY_NAME].S),\n                ReminderName = item[REMINDER_NAME_PROPERTY_NAME].S,\n                StartAt = DateTime.Parse(item[START_TIME_PROPERTY_NAME].S)\n            };\n        }\n\n        /// <summary>\n        /// Remove one row from the reminder table\n        /// </summary>\n        /// <param name=\"grainId\"> specific grain ref to locate the row </param>\n        /// <param name=\"reminderName\"> reminder name to locate the row </param>\n        /// <param name=\"eTag\"> e tag </param>\n        /// <returns> Return true if the row was removed </returns>\n        public async Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            var reminderId = ConstructReminderId(this.serviceId, grainId, reminderName);\n\n            var keys = new Dictionary<string, AttributeValue>\n                {\n                    { $\"{REMINDER_ID_PROPERTY_NAME}\", new AttributeValue(reminderId) },\n                    { $\"{GRAIN_HASH_PROPERTY_NAME}\", new AttributeValue { N = grainId.GetUniformHashCode().ToString() } }\n                };\n\n            try\n            {\n                var conditionalValues = new Dictionary<string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = eTag } } };\n                var expression = $\"{ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}\";\n\n                await this.storage.DeleteEntryAsync(this.options.TableName, keys, expression, conditionalValues).ConfigureAwait(false);\n                return true;\n            }\n            catch (ConditionalCheckFailedException)\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Test hook to clear reminder table data.\n        /// </summary>\n        /// <returns></returns>\n        public async Task TestOnlyClearTable()\n        {\n            var expressionValues = new Dictionary<string, AttributeValue>\n                {\n                    { $\":{SERVICE_ID_PROPERTY_NAME}\", new AttributeValue(this.serviceId) }\n                };\n\n            try\n            {\n                var expression = $\"{SERVICE_ID_PROPERTY_NAME} = :{SERVICE_ID_PROPERTY_NAME}\";\n                var records = await this.storage.ScanAsync(this.options.TableName, expressionValues, expression,\n                    item => new Dictionary<string, AttributeValue>\n                    {\n                        { REMINDER_ID_PROPERTY_NAME, item[REMINDER_ID_PROPERTY_NAME] },\n                        { GRAIN_HASH_PROPERTY_NAME, item[GRAIN_HASH_PROPERTY_NAME] }\n                    }).ConfigureAwait(false);\n\n                if (records.Count <= 25)\n                {\n                    await this.storage.DeleteEntriesAsync(this.options.TableName, records);\n                }\n                else\n                {\n                    List<Task> tasks = new List<Task>();\n                    foreach (var batch in records.BatchIEnumerable(25))\n                    {\n                        tasks.Add(this.storage.DeleteEntriesAsync(this.options.TableName, batch));\n                    }\n                    await Task.WhenAll(tasks);\n                }\n            }\n            catch (Exception exc)\n            {\n                LogWarningRemoveReminderEntries(logger, exc, new(expressionValues), this.options.TableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Async method to put an entry into the reminder table\n        /// </summary>\n        /// <param name=\"entry\"> The entry to put </param>\n        /// <returns> Return the entry ETag if entry was upsert successfully </returns>\n        public async Task<string> UpsertRow(ReminderEntry entry)\n        {\n            var reminderId = ConstructReminderId(this.serviceId, entry.GrainId, entry.ReminderName);\n\n            var fields = new Dictionary<string, AttributeValue>\n                {\n                    { REMINDER_ID_PROPERTY_NAME, new AttributeValue(reminderId) },\n                    { GRAIN_HASH_PROPERTY_NAME, new AttributeValue { N = entry.GrainId.GetUniformHashCode().ToString() } },\n                    { SERVICE_ID_PROPERTY_NAME, new AttributeValue(this.serviceId) },\n                    { GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue( entry.GrainId.ToString()) },\n                    { PERIOD_PROPERTY_NAME, new AttributeValue(entry.Period.ToString()) },\n                    { START_TIME_PROPERTY_NAME, new AttributeValue(entry.StartAt.ToString()) },\n                    { REMINDER_NAME_PROPERTY_NAME, new AttributeValue(entry.ReminderName) },\n                    { ETAG_PROPERTY_NAME, new AttributeValue { N = Random.Shared.Next().ToString() } }\n                };\n\n            try\n            {\n                LogDebugUpsertRow(logger, entry, entry.ETag);\n\n                await this.storage.PutEntryAsync(this.options.TableName, fields);\n\n                entry.ETag = fields[ETAG_PROPERTY_NAME].N;\n                return entry.ETag;\n            }\n            catch (Exception exc)\n            {\n                LogWarningUpdateReminderEntry(logger, exc, entry, options.TableName);\n                throw;\n            }\n        }\n\n        private static string ConstructReminderId(string serviceId, GrainId grainId, string reminderName) => $\"{serviceId}_{grainId}_{reminderName}\";\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Information,\n            Message = \"Initializing AWS DynamoDB Reminders Table\"\n        )]\n        private static partial void LogInformationInitializingDynamoDBRemindersTable(ILogger logger);\n\n        private readonly struct DictionaryLogRecord(Dictionary<string, AttributeValue> keys)\n        {\n            public override string ToString() => Utils.DictionaryToString(keys);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading reminder entry {Keys} from table {TableName}.\"\n        )]\n        private static partial void LogWarningReadReminderEntry(ILogger logger, Exception exception, DictionaryLogRecord keys, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading reminder entry {Entries} from table {TableName}.\"\n        )]\n        private static partial void LogWarningReadReminderEntries(ILogger logger, Exception exception, DictionaryLogRecord entries, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading reminder entry {ExpressionValues} from table {TableName}.\"\n        )]\n        private static partial void LogWarningReadReminderEntryRange(ILogger logger, Exception exception, DictionaryLogRecord expressionValues, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error removing reminder entries {Entries} from table {TableName}.\"\n        )]\n        private static partial void LogWarningRemoveReminderEntries(ILogger logger, Exception exception, DictionaryLogRecord entries, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpsertRow entry = {Entry}, etag = {ETag}\"\n        )]\n        private static partial void LogDebugUpsertRow(ILogger logger, ReminderEntry entry, string eTag);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ReminderServiceBase,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error updating entry {Entry} to the table {TableName}.\"\n        )]\n        private static partial void LogWarningUpdateReminderEntry(ILogger logger, Exception exception, ReminderEntry entry, string tableName);\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/Reminders/DynamoDbReminderServiceOptions.cs",
    "content": "namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration for Amazon DynamoDB reminder storage.\n    /// </summary>\n    public class DynamoDBReminderTableOptions\n    {\n        /// <summary>\n        /// Gets or sets the connection string.\n        /// </summary>\n        [RedactConnectionString]\n        public string ConnectionString { get; set; }\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/Reminders/DynamoDbReminderStorageOptions.cs",
    "content": "using Orleans.Reminders.DynamoDB;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration for Amazon DynamoDB reminder storage.\n    /// </summary>\n    public class DynamoDBReminderStorageOptions : DynamoDBClientOptions\n    {\n        /// <summary>\n        /// Read capacity unit for DynamoDB storage\n        /// </summary>\n        public int ReadCapacityUnits { get; set; } = DynamoDBStorage.DefaultReadCapacityUnits;\n\n        /// <summary>\n        /// Write capacity unit for DynamoDB storage\n        /// </summary>\n        public int WriteCapacityUnits { get; set; } = DynamoDBStorage.DefaultWriteCapacityUnits;\n\n        /// <summary>\n        /// Use Provisioned Throughput for tables\n        /// </summary>\n        public bool UseProvisionedThroughput { get; set; } = true;\n\n        /// <summary>\n        /// Create the table if it doesn't exist\n        /// </summary>\n        public bool CreateIfNotExists { get; set; } = true;\n\n        /// <summary>\n        /// Update the table if it exists\n        /// </summary>\n        public bool UpdateIfExists { get; set; } = true;\n\n        /// <summary>\n        /// DynamoDB table name.\n        /// Defaults to 'OrleansReminders'.\n        /// </summary>\n        public string TableName { get; set; } = \"OrleansReminders\";\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Reminders.DynamoDB/Reminders/DynamoDbReminderStorageOptionsExtensions.cs",
    "content": "using System;\nusing System.Linq;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration for Amazon DynamoDB reminder storage.\n    /// </summary>\n    public static class DynamoDBReminderStorageOptionsExtensions\n    {\n        private const string AccessKeyPropertyName = \"AccessKey\";\n        private const string SecretKeyPropertyName = \"SecretKey\";\n        private const string ServicePropertyName = \"Service\";\n        private const string ReadCapacityUnitsPropertyName = \"ReadCapacityUnits\";\n        private const string WriteCapacityUnitsPropertyName = \"WriteCapacityUnits\";\n        private const string UseProvisionedThroughputPropertyName = \"UseProvisionedThroughput\";\n        private const string CreateIfNotExistsPropertyName = \"CreateIfNotExists\";\n        private const string UpdateIfExistsPropertyName = \"UpdateIfExists\";\n\n        /// <summary>\n        /// Configures this instance using the provided connection string.\n        /// </summary>\n        public static void ParseConnectionString(this DynamoDBReminderStorageOptions options, string connectionString)\n        {\n            var parameters = connectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);\n\n            var serviceConfig = Array.Find(parameters, p => p.Contains(ServicePropertyName));\n            if (!string.IsNullOrWhiteSpace(serviceConfig))\n            {\n                var value = serviceConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.Service = value[1];\n            }\n\n            var secretKeyConfig = Array.Find(parameters, p => p.Contains(SecretKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(secretKeyConfig))\n            {\n                var value = secretKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.SecretKey = value[1];\n            }\n\n            var accessKeyConfig = Array.Find(parameters, p => p.Contains(AccessKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(accessKeyConfig))\n            {\n                var value = accessKeyConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.AccessKey = value[1];\n            }\n\n            var readCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(ReadCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(readCapacityUnitsConfig))\n            {\n                var value = readCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.ReadCapacityUnits = int.Parse(value[1]);\n            }\n\n            var writeCapacityUnitsConfig = Array.Find(parameters, p => p.Contains(WriteCapacityUnitsPropertyName));\n            if (!string.IsNullOrWhiteSpace(writeCapacityUnitsConfig))\n            {\n                var value = writeCapacityUnitsConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.WriteCapacityUnits = int.Parse(value[1]);\n            }\n\n            var useProvisionedThroughputConfig = Array.Find(parameters, p => p.Contains(UseProvisionedThroughputPropertyName));\n            if (!string.IsNullOrWhiteSpace(useProvisionedThroughputConfig))\n            {\n                var value = useProvisionedThroughputConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.UseProvisionedThroughput = bool.Parse(value[1]);\n            }\n\n            var createIfNotExistsPropertyNameConfig = Array.Find(parameters, p => p.Contains(CreateIfNotExistsPropertyName));\n            if (!string.IsNullOrWhiteSpace(createIfNotExistsPropertyNameConfig))\n            {\n                var value = createIfNotExistsPropertyNameConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.CreateIfNotExists = bool.Parse(value[1]);\n            }\n\n            var updateIfExistsPropertyNameConfig = Array.Find(parameters, p => p.Contains(UpdateIfExistsPropertyName));\n            if (!string.IsNullOrWhiteSpace(updateIfExistsPropertyNameConfig))\n            {\n                var value = updateIfExistsPropertyNameConfig.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    options.UpdateIfExists = bool.Parse(value[1]);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Hosting/ClientBuilderExtensions.cs",
    "content": "﻿using System;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class ClientBuilderExtensions\n    {   /// <summary>\n        /// Configure cluster client to use SQS persistent streams with default settings\n        /// </summary>\n        public static IClientBuilder AddSqsStreams(this IClientBuilder builder, string name, Action<SqsOptions> configureOptions)\n        {\n            builder.AddSqsStreams(name, b=>\n                b.ConfigureSqs(ob=>ob.Configure(configureOptions)));\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure cluster client to use SQS persistent streams.\n        /// </summary>\n        public static IClientBuilder AddSqsStreams(this IClientBuilder builder, string name, Action<ClusterClientSqsStreamConfigurator> configure)\n        {\n            var configurator = new ClusterClientSqsStreamConfigurator(name, builder);\n            configure?.Invoke(configurator);\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Hosting/SiloBuilderExtensions.cs",
    "content": "using System;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use SQS persistent streams.\n        /// </summary>\n        public static ISiloBuilder AddSqsStreams(this ISiloBuilder builder, string name, Action<SqsOptions> configureOptions)\n        {\n            builder.AddSqsStreams(name, b =>\n                b.ConfigureSqs(ob => ob.Configure(configureOptions)));\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure silo to use SQS persistent streams.\n        /// </summary>\n        public static ISiloBuilder AddSqsStreams(this ISiloBuilder builder, string name, Action<SiloSqsStreamConfigurator> configure)\n        {\n            var configurator = new SiloSqsStreamConfigurator(name,\n                configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n            configure?.Invoke(configurator);\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Orleans.Streaming.SQS.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Streaming.SQS</PackageId>\n    <Title>Microsoft Orleans AWS SQS Streaming Provider</Title>\n    <Description>Microsoft Orleans streaming provider backed by AWS SQS</Description>\n    <PackageTags>$(PackageTags) AWS SQS</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <DefineConstants>$(DefineConstants);STREAMING_SQS</DefineConstants>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\AWSUtils.cs\" Link=\"AWSUtils.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <PackageReference Include=\"AWSSDK.SQS\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/README.md",
    "content": "# Microsoft Orleans Streaming for Amazon SQS\n\n## Introduction\nMicrosoft Orleans Streaming for Amazon SQS provides a stream provider implementation for Orleans using Amazon Simple Queue Service (SQS). This allows for publishing and subscribing to streams of events with SQS as the underlying messaging infrastructure.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Streaming.SQS\n```\n\n## Example - Configuring SQS Streaming\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Streams;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure SQS as a stream provider\n            .AddSqsStreams(\n                name: \"SQSStreamProvider\",\n                configureOptions: options =>\n                {\n                    options.AccessKey = \"YOUR_AWS_ACCESS_KEY\";\n                    options.SecretKey = \"YOUR_AWS_SECRET_KEY\";\n                    options.Region = \"us-east-1\";\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using SQS Streams in a Grain\n```csharp\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Streams;\n\n// Producer grain\npublic class ProducerGrain : Grain, IProducerGrain\n{\n    private IAsyncStream<string> _stream;\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"SQSStreamProvider\");\n        _stream = streamProvider.GetStream<string>(Guid.NewGuid(), \"MyStreamNamespace\");\n        \n        return base.OnActivateAsync(cancellationToken);\n    }\n\n    public async Task SendMessage(string message)\n    {\n        // Send a message to the stream\n        await _stream.OnNextAsync(message);\n    }\n}\n\n// Consumer grain\npublic class ConsumerGrain : Grain, IConsumerGrain, IAsyncObserver<string>\n{\n    private StreamSubscriptionHandle<string> _subscription;\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"SQSStreamProvider\");\n        var stream = streamProvider.GetStream<string>(this.GetPrimaryKey(), \"MyStreamNamespace\");\n        \n        // Subscribe to the stream\n        _subscription = await stream.SubscribeAsync(this);\n        \n        await base.OnActivateAsync(cancellationToken);\n    }\n\n    public Task OnNextAsync(string item, StreamSequenceToken token = null)\n    {\n        Console.WriteLine($\"Received message: {item}\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnCompletedAsync()\n    {\n        Console.WriteLine(\"Stream completed\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnErrorAsync(Exception ex)\n    {\n        Console.WriteLine($\"Stream error: {ex.Message}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Streams](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/index)\n- [Stream Providers](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/stream-providers)\n- [AWS SDK for .NET Documentation](https://docs.aws.amazon.com/sdk-for-net/index.html)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Storage/SQSStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Amazon.Runtime;\nusing Amazon.SQS;\nusing Amazon.SQS.Model;\nusing Microsoft.Extensions.Logging;\nusing Orleans;\nusing Orleans.Streaming.SQS;\nusing SQSMessage = Amazon.SQS.Model.Message;\n\nnamespace OrleansAWSUtils.Storage\n{\n    /// <summary>\n    /// Wrapper/Helper class around AWS SQS queue service\n    /// </summary>\n    internal partial class SQSStorage\n    {\n        /// <summary>\n        /// Maximum number of messages allowed by SQS to peak per request\n        /// </summary>\n        public const int MAX_NUMBER_OF_MESSAGE_TO_PEEK = 10;\n        private const string AccessKeyPropertyName = \"AccessKey\";\n        private const string SecretKeyPropertyName = \"SecretKey\";\n        private const string ServicePropertyName = \"Service\";\n        private readonly ILogger Logger;\n        private string accessKey;\n        private string secretKey;\n        private string service;\n        private string queueUrl;\n        private AmazonSQSClient sqsClient;\n\n        /// <summary>\n        /// The queue Name\n        /// </summary>\n        public string QueueName { get; private set; }\n\n        /// <summary>\n        /// Default Ctor\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"queueName\">The name of the queue</param>\n        /// <param name=\"connectionString\">The connection string</param>\n        /// <param name=\"serviceId\">The service ID</param>\n        public SQSStorage(ILoggerFactory loggerFactory, string queueName, string connectionString, string serviceId = \"\")\n        {\n            QueueName = string.IsNullOrWhiteSpace(serviceId) ? queueName : $\"{serviceId}-{queueName}\";\n            ParseDataConnectionString(connectionString);\n            Logger = loggerFactory.CreateLogger<SQSStorage>();\n            CreateClient();\n        }\n\n        private void ParseDataConnectionString(string dataConnectionString)\n        {\n            var parameters = dataConnectionString.Split(';', StringSplitOptions.RemoveEmptyEntries);\n\n            var serviceConfig = Array.Find(parameters, p => p.Contains(ServicePropertyName));\n            if (!string.IsNullOrWhiteSpace(serviceConfig))\n            {\n                var value = serviceConfig.Split('=', StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    service = value[1];\n            }\n\n            var secretKeyConfig = Array.Find(parameters, p => p.Contains(SecretKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(secretKeyConfig))\n            {\n                var value = secretKeyConfig.Split('=', StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    secretKey = value[1];\n            }\n\n            var accessKeyConfig = Array.Find(parameters, p => p.Contains(AccessKeyPropertyName));\n            if (!string.IsNullOrWhiteSpace(accessKeyConfig))\n            {\n                var value = accessKeyConfig.Split('=', StringSplitOptions.RemoveEmptyEntries);\n                if (value.Length == 2 && !string.IsNullOrWhiteSpace(value[1]))\n                    accessKey = value[1];\n            }\n        }\n\n        private void CreateClient()\n        {\n            if (service.StartsWith(\"http://\", StringComparison.OrdinalIgnoreCase) ||\n                service.StartsWith(\"https://\", StringComparison.OrdinalIgnoreCase))\n            {\n                // Local SQS instance (for testing)\n                var credentials = new BasicAWSCredentials(\"dummy\", \"dummyKey\");\n                sqsClient = new AmazonSQSClient(credentials, new AmazonSQSConfig { ServiceURL = service });\n            }\n            else if (!string.IsNullOrEmpty(accessKey) && !string.IsNullOrEmpty(secretKey))\n            {\n                // AWS SQS instance (auth via explicit credentials)\n                var credentials = new BasicAWSCredentials(accessKey, secretKey);\n                sqsClient = new AmazonSQSClient(credentials, new AmazonSQSConfig { RegionEndpoint = AWSUtils.GetRegionEndpoint(service) });\n            }\n            else\n            {\n                // AWS SQS instance (implicit auth - EC2 IAM Roles etc)\n                sqsClient = new AmazonSQSClient(new AmazonSQSConfig { RegionEndpoint = AWSUtils.GetRegionEndpoint(service) });\n            }\n        }\n\n        private async Task<string> GetQueueUrl()\n        {\n            try\n            {\n                var response = await sqsClient.GetQueueUrlAsync(QueueName);\n                if (!string.IsNullOrWhiteSpace(response.QueueUrl))\n                    queueUrl = response.QueueUrl;\n\n                return queueUrl;\n            }\n            catch (QueueDoesNotExistException)\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Initialize SQSStorage by creating or connecting to an existent queue\n        /// </summary>\n        /// <returns></returns>\n        public async Task InitQueueAsync()\n        {\n            try\n            {\n                if (string.IsNullOrWhiteSpace(await GetQueueUrl()))\n                {\n                    var response = await sqsClient.CreateQueueAsync(QueueName);\n                    queueUrl = response.QueueUrl;\n                }\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"InitQueueAsync\");\n            }\n        }\n\n        /// <summary>\n        /// Delete the queue\n        /// </summary>\n        /// <returns></returns>\n        public async Task DeleteQueue()\n        {\n            try\n            {\n                if (string.IsNullOrWhiteSpace(queueUrl))\n                    throw new InvalidOperationException(\"Queue not initialized\");\n                await sqsClient.DeleteQueueAsync(queueUrl);\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"DeleteQueue\");\n            }\n        }\n\n        /// <summary>\n        /// Add a message to the SQS queue\n        /// </summary>\n        /// <param name=\"message\">Message request</param>\n        /// <returns></returns>\n        public async Task AddMessage(SendMessageRequest message)\n        {\n            try\n            {\n                if (string.IsNullOrWhiteSpace(queueUrl))\n                    throw new InvalidOperationException(\"Queue not initialized\");\n\n                message.QueueUrl = queueUrl;\n                await sqsClient.SendMessageAsync(message);\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"AddMessage\");\n            }\n        }\n\n        /// <summary>\n        /// Get Messages from SQS Queue.\n        /// </summary>\n        /// <param name=\"count\">The number of messages to peak. Min 1 and max 10</param>\n        /// <returns>Collection with messages from the queue</returns>\n        public async Task<IEnumerable<SQSMessage>> GetMessages(int count = 1)\n        {\n            try\n            {\n                if (string.IsNullOrWhiteSpace(queueUrl))\n                    throw new InvalidOperationException(\"Queue not initialized\");\n\n                if (count < 1)\n                    throw new ArgumentOutOfRangeException(nameof(count));\n\n                var request = new ReceiveMessageRequest { QueueUrl = queueUrl, MaxNumberOfMessages = count <= MAX_NUMBER_OF_MESSAGE_TO_PEEK ? count : MAX_NUMBER_OF_MESSAGE_TO_PEEK };\n                var response = await sqsClient.ReceiveMessageAsync(request);\n                return response.Messages;\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"GetMessages\");\n            }\n            return null;\n        }\n\n        /// <summary>\n        /// Delete a message from SQS queue\n        /// </summary>\n        /// <param name=\"message\">The message to be deleted</param>\n        /// <returns></returns>\n        public async Task DeleteMessage(SQSMessage message)\n        {\n            try\n            {\n                if (message == null)\n                    throw new ArgumentNullException(nameof(message));\n\n                if (string.IsNullOrWhiteSpace(message.ReceiptHandle))\n                    throw new ArgumentNullException(nameof(message.ReceiptHandle));\n\n                if (string.IsNullOrWhiteSpace(queueUrl))\n                    throw new InvalidOperationException(\"Queue not initialized\");\n\n                await sqsClient.DeleteMessageAsync(\n                    new DeleteMessageRequest { QueueUrl = queueUrl, ReceiptHandle = message.ReceiptHandle });\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"DeleteMessage\");\n            }\n        }\n\n        private void ReportErrorAndRethrow(Exception exc, string operation)\n        {\n            LogErrorSQSOperation(exc, operation, QueueName);\n            throw new AggregateException($\"Error doing {operation} for SQS queue {QueueName}\", exc);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.StreamProviderManagerBase,\n            Level = LogLevel.Error,\n            Message = \"Error doing {Operation} for SQS queue {QueueName}\"\n        )]\n        private partial void LogErrorSQSOperation(Exception exception, string operation, string queueName);\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSAdapter.cs",
    "content": "using Orleans.Streams;\nusing OrleansAWSUtils.Storage;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\n\nnamespace OrleansAWSUtils.Streams\n{\n    internal class SQSAdapter : IQueueAdapter\n    {\n        protected readonly string ServiceId;\n        private readonly Serializer<SQSBatchContainer> serializer;\n        protected readonly string DataConnectionString;\n        private readonly IConsistentRingStreamQueueMapper streamQueueMapper;\n        protected readonly ConcurrentDictionary<QueueId, SQSStorage> Queues = new ConcurrentDictionary<QueueId, SQSStorage>();\n        private readonly ILoggerFactory loggerFactory;\n        public string Name { get; private set; }\n        public bool IsRewindable { get { return false; } }\n\n        public StreamProviderDirection Direction { get { return StreamProviderDirection.ReadWrite; } }\n\n        public SQSAdapter(Serializer<SQSBatchContainer> serializer, IConsistentRingStreamQueueMapper streamQueueMapper, ILoggerFactory loggerFactory, string dataConnectionString, string serviceId, string providerName)\n        {\n            if (string.IsNullOrEmpty(dataConnectionString)) throw new ArgumentNullException(nameof(dataConnectionString));\n            if (string.IsNullOrEmpty(serviceId)) throw new ArgumentNullException(nameof(serviceId));\n            this.loggerFactory = loggerFactory;\n            this.serializer = serializer;\n            DataConnectionString = dataConnectionString;\n            this.ServiceId = serviceId;\n            Name = providerName;\n            this.streamQueueMapper = streamQueueMapper;\n        }\n\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n        {\n            return SQSAdapterReceiver.Create(this.serializer, this.loggerFactory, queueId, DataConnectionString, this.ServiceId);\n        }\n\n        public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            if (token != null)\n            {\n                throw new ArgumentException(\"SQSStream stream provider currently does not support non-null StreamSequenceToken.\", nameof(token));\n            }\n            var queueId = streamQueueMapper.GetQueueForStream(streamId);\n            SQSStorage queue;\n            if (!Queues.TryGetValue(queueId, out queue))\n            {\n                var tmpQueue = new SQSStorage(this.loggerFactory, queueId.ToString(), DataConnectionString, this.ServiceId);\n                await tmpQueue.InitQueueAsync();\n                queue = Queues.GetOrAdd(queueId, tmpQueue);\n            }\n            var msg = SQSBatchContainer.ToSQSMessage(this.serializer, streamId, events, requestContext);\n            await queue.AddMessage(msg);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSAdapterFactory.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\nusing Orleans.Configuration;\nusing Orleans;\nusing Orleans.Configuration.Overrides;\nusing Orleans.Serialization;\n\nnamespace OrleansAWSUtils.Streams\n{\n    /// <summary> Factory class for Azure Queue based stream provider.</summary>\n    public class SQSAdapterFactory : IQueueAdapterFactory\n    {\n        private readonly string providerName;\n        private readonly SqsOptions sqsOptions;\n        private readonly ClusterOptions clusterOptions;\n        private readonly Serializer<SQSBatchContainer> serializer;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly HashRingBasedStreamQueueMapper streamQueueMapper;\n        private readonly IQueueAdapterCache adapterCache;\n\n        /// <summary>\n        /// Application level failure handler override.\n        /// </summary>\n        protected Func<QueueId, Task<IStreamFailureHandler>> StreamFailureHandlerFactory { private get; set; }\n\n        public SQSAdapterFactory(\n            string name, \n            SqsOptions sqsOptions,\n            HashRingStreamQueueMapperOptions queueMapperOptions,\n            SimpleQueueCacheOptions cacheOptions,\n            IOptions<ClusterOptions> clusterOptions, \n            Orleans.Serialization.Serializer serializer, \n            ILoggerFactory loggerFactory)\n        {\n            ArgumentNullException.ThrowIfNull(serializer);\n\n            this.providerName = name;\n            this.sqsOptions = sqsOptions;\n            this.clusterOptions = clusterOptions.Value;\n            this.serializer = serializer.GetSerializer<SQSBatchContainer>();\n            this.loggerFactory = loggerFactory;\n            streamQueueMapper = new HashRingBasedStreamQueueMapper(queueMapperOptions, this.providerName);\n            adapterCache = new SimpleQueueAdapterCache(cacheOptions, this.providerName, this.loggerFactory);\n        }\n\n\n        /// <summary> Init the factory.</summary>\n        public virtual void Init()\n        {\n            if (StreamFailureHandlerFactory == null)\n            {\n                StreamFailureHandlerFactory =\n                    qid => Task.FromResult<IStreamFailureHandler>(new NoOpStreamDeliveryFailureHandler());\n            }\n        }\n\n        /// <summary>Creates the Azure Queue based adapter.</summary>\n        public virtual Task<IQueueAdapter> CreateAdapter()\n        {\n            var adapter = new SQSAdapter(this.serializer, this.streamQueueMapper, this.loggerFactory, this.sqsOptions.ConnectionString, this.clusterOptions.ServiceId, this.providerName);\n            return Task.FromResult<IQueueAdapter>(adapter);\n        }\n\n        /// <summary>Creates the adapter cache.</summary>\n        public virtual IQueueAdapterCache GetQueueAdapterCache()\n        {\n            return adapterCache;\n        }\n\n        /// <summary>Creates the factory stream queue mapper.</summary>\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            return streamQueueMapper;\n        }\n\n        /// <summary>\n        /// Creates a delivery failure handler for the specified queue.\n        /// </summary>\n        /// <param name=\"queueId\"></param>\n        /// <returns></returns>\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            return StreamFailureHandlerFactory(queueId);\n        }\n\n        public static SQSAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var sqsOptions = services.GetOptionsByName<SqsOptions>(name);\n            var cacheOptions = services.GetOptionsByName<SimpleQueueCacheOptions>(name);\n            var queueMapperOptions = services.GetOptionsByName<HashRingStreamQueueMapperOptions>(name);\n            IOptions<ClusterOptions> clusterOptions = services.GetProviderClusterOptions(name);\n            var factory = ActivatorUtilities.CreateInstance<SQSAdapterFactory>(services, name, sqsOptions, cacheOptions, queueMapperOptions, clusterOptions);\n            factory.Init();\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSAdapterReceiver.cs",
    "content": "using Orleans;\nusing Orleans.Streams;\nusing OrleansAWSUtils.Storage;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Serialization;\nusing SQSMessage = Amazon.SQS.Model.Message;\n\nnamespace OrleansAWSUtils.Streams\n{\n    /// <summary>\n    /// Receives batches of messages from a single partition of a message queue.\n    /// </summary>\n    internal partial class SQSAdapterReceiver : IQueueAdapterReceiver\n    {\n        private SQSStorage queue;\n        private long lastReadMessage;\n        private Task outstandingTask;\n        private readonly ILogger logger;\n        private readonly Serializer<SQSBatchContainer> serializer;\n\n\n        public QueueId Id { get; private set; }\n\n        public static IQueueAdapterReceiver Create(Serializer<SQSBatchContainer> serializer, ILoggerFactory loggerFactory, QueueId queueId, string dataConnectionString, string serviceId)\n        {\n            if (queueId.IsDefault) throw new ArgumentNullException(nameof(queueId));\n            if (string.IsNullOrEmpty(dataConnectionString)) throw new ArgumentNullException(nameof(dataConnectionString));\n            if (string.IsNullOrEmpty(serviceId)) throw new ArgumentNullException(nameof(serviceId));\n\n            var queue = new SQSStorage(loggerFactory, queueId.ToString(), dataConnectionString, serviceId);\n            return new SQSAdapterReceiver(serializer, loggerFactory, queueId, queue);\n        }\n\n        private SQSAdapterReceiver(Serializer<SQSBatchContainer> serializer, ILoggerFactory loggerFactory, QueueId queueId, SQSStorage queue)\n        {\n            if (queueId.IsDefault) throw new ArgumentNullException(nameof(queueId));\n            if (queue == null) throw new ArgumentNullException(nameof(queue));\n\n            Id = queueId;\n            this.queue = queue;\n            logger = loggerFactory.CreateLogger<SQSAdapterReceiver>();\n            this.serializer = serializer;\n        }\n\n        public Task Initialize(TimeSpan timeout)\n        {\n            if (queue != null) // check in case we already shut it down.\n            {\n                return queue.InitQueueAsync();\n            }\n            return Task.CompletedTask;\n        }\n\n        public async Task Shutdown(TimeSpan timeout)\n        {\n            try\n            {\n                // await the last storage operation, so after we shutdown and stop this receiver we don't get async operation completions from pending storage operations.\n                if (outstandingTask != null)\n                    await outstandingTask;\n            }\n            finally\n            {\n                // remember that we shut down so we never try to read from the queue again.\n                queue = null;\n            }\n        }\n\n        public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n        {\n            try\n            {\n                var queueRef = queue; // store direct ref, in case we are somehow asked to shutdown while we are receiving.\n                if (queueRef == null) return new List<IBatchContainer>();\n\n                int count = maxCount < 0 || maxCount == QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG ?\n                    SQSStorage.MAX_NUMBER_OF_MESSAGE_TO_PEEK : Math.Min(maxCount, SQSStorage.MAX_NUMBER_OF_MESSAGE_TO_PEEK);\n\n                var task = queueRef.GetMessages(count);\n                outstandingTask = task;\n                IEnumerable<SQSMessage> messages = await task;\n                if (messages == null || !messages.Any())\n                    return Array.Empty<IBatchContainer>();\n\n                List<IBatchContainer> messageBatch = messages\n                    .Select(msg => (IBatchContainer)SQSBatchContainer.FromSQSMessage(this.serializer, msg, lastReadMessage++)).ToList();\n\n                return messageBatch;\n            }\n            finally\n            {\n                outstandingTask = null;\n            }\n        }\n\n        public async Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n        {\n            try\n            {\n                var queueRef = queue; // store direct ref, in case we are somehow asked to shutdown while we are receiving.\n                if (messages.Count == 0 || queueRef == null) return;\n                List<SQSMessage> cloudQueueMessages = messages.Cast<SQSBatchContainer>().Select(b => b.Message).ToList();\n                outstandingTask = Task.WhenAll(cloudQueueMessages.Select(queueRef.DeleteMessage));\n                try\n                {\n                    await outstandingTask;\n                }\n                catch (Exception exc)\n                {\n                    LogWarningDeleteMessageException(logger, exc, Id);\n                }\n            }\n            finally\n            {\n                outstandingTask = null;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception upon DeleteMessage on queue {Id}. Ignoring.\"\n        )]\n        private static partial void LogWarningDeleteMessageException(ILogger logger, Exception exception, QueueId id);\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSBatchContainer.cs",
    "content": "using Amazon.SQS.Model;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing SQSMessage = Amazon.SQS.Model.Message;\n\nnamespace OrleansAWSUtils.Streams\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    internal class SQSBatchContainer : IBatchContainer\n    {\n        [JsonProperty]\n        [Orleans.Id(0)]\n        private EventSequenceTokenV2 sequenceToken;\n\n        [JsonProperty]\n        [Orleans.Id(1)]\n        private readonly List<object> events;\n\n        [JsonProperty]\n        [Orleans.Id(2)]\n        private readonly Dictionary<string, object> requestContext;\n\n        [NonSerialized]\n        // Need to store reference to the original SQS Message to be able to delete it later on.\n        // Don't need to serialize it, since we are never interested in sending it to stream consumers.\n        internal SQSMessage Message;\n\n        [Orleans.Id(3)]\n        public StreamId StreamId { get; private set; }\n\n        public StreamSequenceToken SequenceToken\n        {\n            get { return sequenceToken; }\n        }\n\n        [JsonConstructor]\n        private SQSBatchContainer(\n            StreamId streamId,\n            List<object> events,\n            Dictionary<string, object> requestContext,\n            EventSequenceTokenV2 sequenceToken)\n            : this(streamId, events, requestContext)\n        {\n            this.sequenceToken = sequenceToken;\n        }\n\n        private SQSBatchContainer(StreamId streamId, List<object> events, Dictionary<string, object> requestContext)\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events), \"Message contains no events\");\n\n            StreamId = streamId;\n            this.events = events;\n            this.requestContext = requestContext;\n        }\n\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return events.OfType<T>().Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, sequenceToken.CreateSequenceTokenForEvent(i)));\n        }\n\n        internal static SendMessageRequest ToSQSMessage<T>(\n            Serializer<SQSBatchContainer> serializer,\n            StreamId streamId,\n            IEnumerable<T> events,\n            Dictionary<string, object> requestContext)\n        {\n            var sqsBatchMessage = new SQSBatchContainer(streamId, events.Cast<object>().ToList(), requestContext);\n            var rawBytes = serializer.SerializeToArray(sqsBatchMessage);\n            var payload = new JObject\n            {\n                { \"payload\", JToken.FromObject(rawBytes) }\n            };\n            return new SendMessageRequest\n            {\n                MessageBody = payload.ToString()\n            };\n        }\n\n        internal static SQSBatchContainer FromSQSMessage(Serializer<SQSBatchContainer> serializer, SQSMessage msg, long sequenceId)\n        {\n            var json = JObject.Parse(msg.Body);\n            var sqsBatch = serializer.Deserialize(json[\"payload\"].ToObject<byte[]>());\n            sqsBatch.Message = msg;\n            sqsBatch.sequenceToken = new EventSequenceTokenV2(sequenceId);\n            return sqsBatch;\n        }\n\n        public bool ImportRequestContext()\n        {\n            if (requestContext != null)\n            {\n                RequestContextExtensions.Import(requestContext);\n                return true;\n            }\n            return false;\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"[SQSBatchContainer:Stream={0},#Items={1}]\", StreamId, events.Count);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSStreamBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing OrleansAWSUtils.Streams;\n\nnamespace Orleans.Hosting\n{\n    public class SiloSqsStreamConfigurator : SiloPersistentStreamConfigurator\n    {\n        public SiloSqsStreamConfigurator(string name, Action<Action<IServiceCollection>> configureServicesDelegate)\n            : base(name, configureServicesDelegate, SQSAdapterFactory.Create)\n        {\n            this.ConfigureDelegate(services =>\n            {\n                services.ConfigureNamedOptionForLogging<SqsOptions>(name)\n                    .ConfigureNamedOptionForLogging<SimpleQueueCacheOptions>(name)\n                    .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name);\n            });\n        }\n\n        public SiloSqsStreamConfigurator ConfigureSqs(Action<OptionsBuilder<SqsOptions>> configureOptions)\n        {\n            this.Configure(configureOptions);\n            return this;\n        }\n\n        public SiloSqsStreamConfigurator ConfigureCache(int cacheSize = SimpleQueueCacheOptions.DEFAULT_CACHE_SIZE)\n        {\n            this.Configure<SimpleQueueCacheOptions>(ob => ob.Configure(options => options.CacheSize = cacheSize));\n            return this;\n        }\n\n        public SiloSqsStreamConfigurator ConfigurePartitioning(int numOfparitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n        {\n            this.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = numOfparitions));\n            return this;\n        }\n    }\n\n    public class ClusterClientSqsStreamConfigurator : ClusterClientPersistentStreamConfigurator\n    {\n        public ClusterClientSqsStreamConfigurator(string name, IClientBuilder builder)\n            : base(name, builder, SQSAdapterFactory.Create)\n        {\n            builder\n                .ConfigureServices(services =>\n                {\n                    services.ConfigureNamedOptionForLogging<SqsOptions>(name)\n                    .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name);\n                });\n        }\n\n        public ClusterClientSqsStreamConfigurator ConfigureSqs(Action<OptionsBuilder<SqsOptions>> configureOptions)\n        {\n            this.Configure(configureOptions);\n            return this;\n\n        }\n\n        public ClusterClientSqsStreamConfigurator ConfigurePartitioning(int numOfparitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n        {\n            this.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = numOfparitions));\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SQSStreamProviderUtils.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing OrleansAWSUtils.Storage;\nusing Orleans.Configuration;\n\nnamespace OrleansAWSUtils.Streams\n{\n    /// <summary>\n    /// SQS utility functions\n    /// </summary>\n    public class SQSStreamProviderUtils\n    {\n        /// <summary>\n        /// Async method to delete all used queues, for specific provider and clusterId\n        /// </summary>\n        /// <returns> Task object for this async method </returns>\n        public static async Task DeleteAllUsedQueues(string providerName, string clusterId, string storageConnectionString, ILoggerFactory loggerFactory)\n        {\n            if (clusterId != null)\n            {\n                var queueMapper = new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions(), providerName);\n                List<QueueId> allQueues = queueMapper.GetAllQueues().ToList();\n\n                var deleteTasks = new List<Task>();\n                foreach (var queueId in allQueues)\n                {\n                    var manager = new SQSStorage(loggerFactory, queueId.ToString(), storageConnectionString, clusterId);\n                    manager.InitQueueAsync().Wait();\n                    deleteTasks.Add(manager.DeleteQueue());\n                }\n\n                await Task.WhenAll(deleteTasks);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Orleans.Streaming.SQS/Streams/SqsStreamOptions.cs",
    "content": "﻿\nnamespace Orleans.Configuration\n{\n    public class SqsOptions\n    {\n        [Redact]\n        public string ConnectionString { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Shared/AWSUtils.cs",
    "content": "using Amazon;\nusing System;\n\n#if CLUSTERING_DYNAMODB\nnamespace Orleans.Clustering.DynamoDB\n#elif PERSISTENCE_DYNAMODB\nnamespace Orleans.Persistence.DynamoDB\n#elif REMINDERS_DYNAMODB\nnamespace Orleans.Reminders.DynamoDB\n#elif STREAMING_SQS\nnamespace Orleans.Streaming.SQS\n#elif AWSUTILS_TESTS\nnamespace Orleans.AWSUtils.Tests\n#elif TRANSACTIONS_DYNAMODB\nnamespace Orleans.Transactions.DynamoDB\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Some basic utilities methods for AWS SDK\n    /// </summary>\n    internal static class AWSUtils\n    {\n        internal static RegionEndpoint GetRegionEndpoint(string zone = \"\")\n        {\n            //\n            // Keep the order from RegionEndpoint so it is easier to maintain.\n            // us-west-2 is the default\n            //\n\n            return RegionEndpoint.GetBySystemName(zone) ?? RegionEndpoint.USWest2;\n        }\n\n        /// <summary>\n        /// Validate DynamoDB PartitionKey.\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <returns></returns>\n        public static string ValidateDynamoDBPartitionKey(string key)\n        {\n            if (key.Length >= 2048)\n                throw new ArgumentException(string.Format(\"Key length {0} is too long to be an DynamoDB partition key. Key={1}\", key.Length, key));\n\n            return key;\n        }\n\n        /// <summary>\n        /// Validate DynamoDB RowKey.\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <returns></returns>\n        public static string ValidateDynamoDBRowKey(string key)\n        {\n            if (key.Length >= 1024)\n                throw new ArgumentException(string.Format(\"Key length {0} is too long to be an DynamoDB row key. Key={1}\", key.Length, key));\n\n            return key;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AWS/Shared/Storage/DynamoDBClientOptions.cs",
    "content": "#if CLUSTERING_DYNAMODB\nnamespace Orleans.Clustering.DynamoDB\n#elif PERSISTENCE_DYNAMODB\nnamespace Orleans.Persistence.DynamoDB\n#elif REMINDERS_DYNAMODB\nnamespace Orleans.Reminders.DynamoDB\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    public class DynamoDBClientOptions\n    {\n        /// <summary>\n        /// AccessKey string for DynamoDB Storage\n        /// </summary>\n        [Redact]\n        public string AccessKey { get; set; }\n\n        /// <summary>\n        /// Secret key for DynamoDB storage\n        /// </summary>\n        [Redact]\n        public string SecretKey { get; set; }\n\n        /// <summary>\n        /// DynamoDB region name, such as \"us-west-2\"\n        /// </summary>\n        public string Service { get; set; }\n\n        /// <summary>\n        /// Token for DynamoDB storage\n        /// </summary>\n        public string Token { get; set; }\n\n        /// <summary>\n        /// AWS profile name.\n        /// </summary>\n        public string ProfileName { get; set; }\n    }\n}"
  },
  {
    "path": "src/AWS/Shared/Storage/DynamoDBStorage.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Amazon.Runtime;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Amazon.Runtime.CredentialManagement;\n\n#if CLUSTERING_DYNAMODB\nnamespace Orleans.Clustering.DynamoDB\n#elif PERSISTENCE_DYNAMODB\nnamespace Orleans.Persistence.DynamoDB\n#elif REMINDERS_DYNAMODB\nnamespace Orleans.Reminders.DynamoDB\n#elif AWSUTILS_TESTS\nnamespace Orleans.AWSUtils.Tests\n#elif TRANSACTIONS_DYNAMODB\nnamespace Orleans.Transactions.DynamoDB\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Wrapper around AWS DynamoDB SDK.\n    /// </summary>\n    internal partial class DynamoDBStorage\n    {\n        private readonly string _accessKey;\n        private readonly string _token;\n        private readonly string _profileName;\n        /// <summary> Secret key for this dynamoDB table </summary>\n        protected string secretKey;\n        private readonly string _service;\n        public const int DefaultReadCapacityUnits = 10;\n        public const int DefaultWriteCapacityUnits = 5;\n        private readonly ProvisionedThroughput _provisionedThroughput;\n        private readonly bool _createIfNotExists;\n        private readonly bool _updateIfExists;\n        private readonly bool _useProvisionedThroughput;\n        private readonly ReadOnlyCollection<TableStatus> _updateTableValidTableStatuses = new ReadOnlyCollection<TableStatus>(new List<TableStatus>()\n            {\n                TableStatus.CREATING, TableStatus.UPDATING, TableStatus.ACTIVE\n            });\n        private AmazonDynamoDBClient _ddbClient;\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Create a DynamoDBStorage instance\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"accessKey\"></param>\n        /// <param name=\"secretKey\"></param>\n        /// <param name=\"token\"></param>\n        /// <param name=\"profileName\"></param>\n        /// <param name=\"service\"></param>\n        /// <param name=\"readCapacityUnits\"></param>\n        /// <param name=\"writeCapacityUnits\"></param>\n        /// <param name=\"useProvisionedThroughput\"></param>\n        /// <param name=\"createIfNotExists\"></param>\n        /// <param name=\"updateIfExists\"></param>\n        public DynamoDBStorage(\n            ILogger logger,\n            string service,\n            string accessKey = \"\",\n            string secretKey = \"\",\n            string token = \"\",\n            string profileName = \"\",\n            int readCapacityUnits = DefaultReadCapacityUnits,\n            int writeCapacityUnits = DefaultWriteCapacityUnits,\n            bool useProvisionedThroughput = true,\n            bool createIfNotExists = true,\n            bool updateIfExists = true)\n        {\n            if (service == null) throw new ArgumentNullException(nameof(service));\n            this._accessKey = accessKey;\n            this.secretKey = secretKey;\n            this._token = token;\n            this._profileName = profileName;\n            this._service = service;\n            this._useProvisionedThroughput = useProvisionedThroughput;\n            this._provisionedThroughput = this._useProvisionedThroughput\n                ? new ProvisionedThroughput(readCapacityUnits, writeCapacityUnits)\n                : null;\n            this._createIfNotExists = createIfNotExists;\n            this._updateIfExists = updateIfExists;\n            _logger = logger;\n            CreateClient();\n        }\n\n        /// <summary>\n        /// Create a DynamoDB table if it doesn't exist\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table</param>\n        /// <param name=\"keys\">The keys definitions</param>\n        /// <param name=\"attributes\">The attributes used on the key definition</param>\n        /// <param name=\"secondaryIndexes\">(optional) The secondary index definitions</param>\n        /// <param name=\"ttlAttributeName\">(optional) The name of the item attribute that indicates the item TTL (if null, ttl won't be enabled)</param>\n        /// <returns></returns>\n        public async Task InitializeTable(string tableName, List<KeySchemaElement> keys, List<AttributeDefinition> attributes, List<GlobalSecondaryIndex> secondaryIndexes = null, string ttlAttributeName = null)\n        {\n            if (!this._createIfNotExists && !this._updateIfExists)\n            {\n                LogInformationTableNotCreatedOrUpdated(_logger, tableName);\n                return;\n            }\n\n            try\n            {\n                TableDescription tableDescription = await GetTableDescription(tableName);\n                await (tableDescription == null\n                    ? CreateTableAsync(tableName, keys, attributes, secondaryIndexes, ttlAttributeName)\n                    : UpdateTableAsync(tableDescription, attributes, secondaryIndexes, ttlAttributeName));\n            }\n            catch (Exception exc)\n            {\n                LogErrorCouldNotInitializeTable(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        private void CreateClient()\n        {\n            if (this._service.StartsWith(\"http://\", StringComparison.OrdinalIgnoreCase) ||\n                this._service.StartsWith(\"https://\", StringComparison.OrdinalIgnoreCase))\n            {\n                // Local DynamoDB instance (for testing)\n                var credentials = new BasicAWSCredentials(\"dummy\", \"dummyKey\");\n                this._ddbClient = new AmazonDynamoDBClient(credentials, new AmazonDynamoDBConfig { ServiceURL = this._service });\n            }\n            else if (!string.IsNullOrEmpty(this._accessKey) && !string.IsNullOrEmpty(this.secretKey) && !string.IsNullOrEmpty(this._token))\n            {\n                // AWS DynamoDB instance (auth via explicit credentials and token)\n                var credentials = new SessionAWSCredentials(this._accessKey, this.secretKey, this._token);\n                this._ddbClient = new AmazonDynamoDBClient(credentials, new AmazonDynamoDBConfig { RegionEndpoint = AWSUtils.GetRegionEndpoint(this._service) });\n            }\n            else if (!string.IsNullOrEmpty(this._accessKey) && !string.IsNullOrEmpty(this.secretKey))\n            {\n                // AWS DynamoDB instance (auth via explicit credentials)\n                var credentials = new BasicAWSCredentials(this._accessKey, this.secretKey);\n                this._ddbClient = new AmazonDynamoDBClient(credentials, new AmazonDynamoDBConfig { RegionEndpoint = AWSUtils.GetRegionEndpoint(this._service) });\n            }\n            else if (!string.IsNullOrEmpty(this._profileName))\n            {\n                // AWS DynamoDB instance (auth via explicit credentials and token found in a named profile)\n                var chain = new CredentialProfileStoreChain();\n                if (chain.TryGetAWSCredentials(this._profileName, out var credentials))\n                {\n                    this._ddbClient = new AmazonDynamoDBClient(\n                        credentials,\n                        new AmazonDynamoDBConfig\n                        {\n                            RegionEndpoint = AWSUtils.GetRegionEndpoint(this._service)\n                        });\n                }\n                else\n                {\n                    throw new InvalidOperationException(\n                        $\"AWS named profile '{this._profileName}' provided, but credentials could not be retrieved\");\n                }\n            }\n            else\n            {\n                // AWS DynamoDB instance (implicit auth - EC2 IAM Roles etc)\n                this._ddbClient = new AmazonDynamoDBClient(new AmazonDynamoDBConfig { RegionEndpoint = AWSUtils.GetRegionEndpoint(this._service) });\n            }\n        }\n\n        private async Task<TableDescription> GetTableDescription(string tableName)\n        {\n            try\n            {\n                var description = await _ddbClient.DescribeTableAsync(tableName);\n                if (description.Table != null)\n                    return description.Table;\n            }\n            catch (ResourceNotFoundException)\n            {\n                return null;\n            }\n            return null;\n        }\n\n        private async ValueTask CreateTableAsync(string tableName, List<KeySchemaElement> keys, List<AttributeDefinition> attributes, List<GlobalSecondaryIndex> secondaryIndexes = null, string ttlAttributeName = null)\n        {\n            if (!_createIfNotExists)\n            {\n                LogWarningTableNotCreated(_logger, tableName);\n                return;\n            }\n\n            var request = new CreateTableRequest\n            {\n                TableName = tableName,\n                AttributeDefinitions = attributes,\n                KeySchema = keys,\n                BillingMode = this._useProvisionedThroughput ? BillingMode.PROVISIONED : BillingMode.PAY_PER_REQUEST,\n                ProvisionedThroughput = _provisionedThroughput\n            };\n\n            if (secondaryIndexes != null && secondaryIndexes.Count > 0)\n            {\n                if (this._useProvisionedThroughput)\n                {\n                    secondaryIndexes.ForEach(i =>\n                    {\n                        i.ProvisionedThroughput = _provisionedThroughput;\n                    });\n                }\n\n                request.GlobalSecondaryIndexes = secondaryIndexes;\n            }\n\n            try\n            {\n                try\n                {\n                    await _ddbClient.CreateTableAsync(request);\n                }\n                catch (ResourceInUseException)\n                {\n                    // The table has already been created.\n                }\n\n                TableDescription tableDescription = await TableWaitOnStatusAsync(tableName, TableStatus.CREATING, TableStatus.ACTIVE);\n                tableDescription = await TableUpdateTtlAsync(tableDescription, ttlAttributeName);\n            }\n            catch (Exception exc)\n            {\n                LogErrorCouldNotCreateTable(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        private async ValueTask UpdateTableAsync(TableDescription tableDescription, List<AttributeDefinition> attributes, List<GlobalSecondaryIndex> secondaryIndexes = null, string ttlAttributeName = null)\n        {\n            if (!this._updateIfExists)\n            {\n                LogWarningTableNotUpdated(_logger, tableDescription.TableName);\n                return;\n            }\n\n            if (!_updateTableValidTableStatuses.Contains(tableDescription.TableStatus))\n            {\n                throw new InvalidOperationException($\"Table {tableDescription.TableName} has a status of {tableDescription.TableStatus} and can't be updated automatically.\");\n            }\n\n            if (tableDescription.TableStatus == TableStatus.CREATING\n                || tableDescription.TableStatus == TableStatus.UPDATING)\n            {\n                tableDescription = await TableWaitOnStatusAsync(tableDescription.TableName, tableDescription.TableStatus, TableStatus.ACTIVE);\n            }\n\n            var request = new UpdateTableRequest\n            {\n                TableName = tableDescription.TableName,\n                AttributeDefinitions = attributes,\n                BillingMode = this._useProvisionedThroughput ? BillingMode.PROVISIONED : BillingMode.PAY_PER_REQUEST,\n                ProvisionedThroughput = _provisionedThroughput,\n                GlobalSecondaryIndexUpdates = this._useProvisionedThroughput\n                    ? tableDescription.GlobalSecondaryIndexes?.Select(gsi => new GlobalSecondaryIndexUpdate\n                    {\n                        Update = new UpdateGlobalSecondaryIndexAction\n                        {\n                            IndexName = gsi.IndexName,\n                            ProvisionedThroughput = _provisionedThroughput\n                        }\n                    }).ToList()\n                    : null\n            };\n\n            try\n            {\n                if ((request.ProvisionedThroughput?.ReadCapacityUnits ?? 0) != tableDescription.ProvisionedThroughput?.ReadCapacityUnits        // PROVISIONED Throughput read capacity change\n                    || (request.ProvisionedThroughput?.WriteCapacityUnits ?? 0) != tableDescription.ProvisionedThroughput?.WriteCapacityUnits   // PROVISIONED Throughput write capacity change\n                    || (tableDescription.ProvisionedThroughput?.ReadCapacityUnits != 0 && tableDescription.ProvisionedThroughput?.WriteCapacityUnits != 0 && this._useProvisionedThroughput == false /* from PROVISIONED to PAY_PER_REQUEST */))\n                {\n                    await _ddbClient.UpdateTableAsync(request);\n                    tableDescription = await TableWaitOnStatusAsync(tableDescription.TableName, TableStatus.UPDATING, TableStatus.ACTIVE);\n                }\n\n                tableDescription = await TableUpdateTtlAsync(tableDescription, ttlAttributeName);\n\n                // Wait for all table indexes to become ACTIVE.\n                // We can only have one GSI in CREATING state at one time.\n                // We also wait for all indexes to finish UPDATING as the table is not ready to receive queries from Orleans until all indexes are created.\n                List<GlobalSecondaryIndexDescription> globalSecondaryIndexes = tableDescription.GlobalSecondaryIndexes;\n                if (globalSecondaryIndexes != null)\n                {\n                    foreach (var globalSecondaryIndex in globalSecondaryIndexes)\n                    {\n                        if (globalSecondaryIndex.IndexStatus == IndexStatus.CREATING\n                            || globalSecondaryIndex.IndexStatus == IndexStatus.UPDATING)\n                        {\n                            tableDescription = await TableIndexWaitOnStatusAsync(tableDescription.TableName, globalSecondaryIndex.IndexName, globalSecondaryIndex.IndexStatus, IndexStatus.ACTIVE);\n                        }\n                    }\n                }\n\n                var existingGlobalSecondaryIndexes = tableDescription.GlobalSecondaryIndexes?.Select(globalSecondaryIndex => globalSecondaryIndex.IndexName).ToArray() ?? Array.Empty<string>();\n                var secondaryIndexesToCreate = (secondaryIndexes ?? Enumerable.Empty<GlobalSecondaryIndex>()).Where(secondaryIndex => !existingGlobalSecondaryIndexes.Contains(secondaryIndex.IndexName));\n\n                foreach (var secondaryIndex in secondaryIndexesToCreate)\n                {\n                    await TableCreateSecondaryIndex(tableDescription.TableName, attributes, secondaryIndex);\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorCouldNotUpdateTable(_logger, exc, tableDescription.TableName);\n                throw;\n            }\n        }\n\n        private async Task TableCreateSecondaryIndex(string tableName, List<AttributeDefinition> attributes, GlobalSecondaryIndex secondaryIndex)\n        {\n            await _ddbClient.UpdateTableAsync(new UpdateTableRequest\n            {\n                TableName = tableName,\n                GlobalSecondaryIndexUpdates = new List<GlobalSecondaryIndexUpdate>\n                {\n                    new GlobalSecondaryIndexUpdate\n                    {\n                        Create = new CreateGlobalSecondaryIndexAction()\n                        {\n                            IndexName = secondaryIndex.IndexName,\n                            Projection = secondaryIndex.Projection,\n                            ProvisionedThroughput = _provisionedThroughput,\n                            KeySchema = secondaryIndex.KeySchema\n                        }\n                    }\n                },\n                AttributeDefinitions = attributes\n            });\n\n            // Adding a GSI to a table is an eventually consistent operation and we might miss the table UPDATING status if we query the table status imediatelly after the table update call.\n            // Creating a GSI takes significantly longer than 1 second and therefore this delay does not add time to the total duration of this method.\n            await Task.Delay(1000);\n\n            // When adding a GSI, the table briefly changes its status to UPDATING. The GSI creation process usually takes longer.\n            // For this reason, we will wait for both the table and the index to become ACTIVE before marking the operation as complete.\n            await TableWaitOnStatusAsync(tableName, TableStatus.UPDATING, TableStatus.ACTIVE);\n            await TableIndexWaitOnStatusAsync(tableName, secondaryIndex.IndexName, IndexStatus.CREATING, IndexStatus.ACTIVE);\n        }\n\n        private async ValueTask<TableDescription> TableUpdateTtlAsync(TableDescription tableDescription, string ttlAttributeName)\n        {\n            var describeTimeToLive = (await _ddbClient.DescribeTimeToLiveAsync(tableDescription.TableName)).TimeToLiveDescription;\n\n            // We can only handle updates to the table TTL from DISABLED to ENABLED.\n            // This is because updating the TTL attribute requires (1) disabling the table TTL and (2) re-enabling it with the new TTL attribute.\n            // As per the below details page for this API: \"It can take up to one hour for the change to fully process. Any additional UpdateTimeToLive calls for the same table during this one hour duration result in a ValidationException.\"\n            // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html\n            // However if the TTL is already set on the correct attribute, the attribute value is updated every time a record is written, thus the configuration is already correct and warning doesn't need to be logged.\n            if (describeTimeToLive.TimeToLiveStatus != TimeToLiveStatus.DISABLED && describeTimeToLive.AttributeName != ttlAttributeName)\n            {\n                LogWarningTtlNotDisabled(_logger, tableDescription.TableName);\n                return tableDescription;\n            }\n\n            if (string.IsNullOrEmpty(ttlAttributeName) || describeTimeToLive.AttributeName == ttlAttributeName)\n            {\n                return tableDescription;\n            }\n\n            try\n            {\n                await _ddbClient.UpdateTimeToLiveAsync(new UpdateTimeToLiveRequest\n                {\n                    TableName = tableDescription.TableName,\n                    TimeToLiveSpecification = new TimeToLiveSpecification { AttributeName = ttlAttributeName, Enabled = true }\n                });\n\n                return await TableWaitOnStatusAsync(tableDescription.TableName, TableStatus.UPDATING, TableStatus.ACTIVE);\n            }\n            catch (AmazonDynamoDBException ddbEx)\n            {\n                // We need to swallow this exception as there is no API exposed to determine if the below issue will occur before calling UpdateTimeToLive(Async)\n                // \"Time to live has been modified multiple times within a fixed interval\".\n                // We can arrive at this situation if the TTL feature was recently disabled on the target table.\n                LogErrorUpdateTtlException(_logger, ddbEx, tableDescription.TableName, ttlAttributeName);\n                return tableDescription;\n            }\n        }\n\n        private async Task<TableDescription> TableWaitOnStatusAsync(string tableName, TableStatus whileStatus, TableStatus desiredStatus, int delay = 2000)\n        {\n            TableDescription ret = null;\n\n            do\n            {\n                if (ret != null)\n                {\n                    await Task.Delay(delay);\n                }\n\n                ret = await GetTableDescription(tableName);\n            } while (ret.TableStatus == whileStatus);\n\n            if (ret.TableStatus != desiredStatus)\n            {\n                throw new InvalidOperationException($\"Table {tableName} has failed to reach the desired status of {desiredStatus}\");\n            }\n\n            return ret;\n        }\n\n        private async Task<TableDescription> TableIndexWaitOnStatusAsync(string tableName, string indexName, IndexStatus whileStatus, IndexStatus desiredStatus = null, int delay = 2000)\n        {\n            TableDescription ret;\n            GlobalSecondaryIndexDescription index = null;\n\n            do\n            {\n                if (index != null)\n                {\n                    await Task.Delay(delay);\n                }\n\n                ret = await GetTableDescription(tableName);\n                index = ret.GlobalSecondaryIndexes?.Find(index => index.IndexName == indexName);\n            } while (index != null && index.IndexStatus == whileStatus);\n\n            if (desiredStatus != null && (index == null || index.IndexStatus != desiredStatus))\n            {\n                throw new InvalidOperationException($\"Index {indexName} in table {tableName} has failed to reach the desired status of {desiredStatus}\");\n            }\n\n            return ret;\n        }\n\n        /// <summary>\n        /// Delete a table from DynamoDB\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to delete</param>\n        /// <returns></returns>\n        public Task DeleTableAsync(string tableName)\n        {\n            try\n            {\n                return _ddbClient.DeleteTableAsync(new DeleteTableRequest { TableName = tableName });\n            }\n            catch (Exception exc)\n            {\n                LogErrorCouldNotDeleteTable(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Create or Replace an entry in a DynamoDB Table\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to put an entry</param>\n        /// <param name=\"fields\">The fields/attributes to add or replace in the table</param>\n        /// <param name=\"conditionExpression\">Optional conditional expression</param>\n        /// <param name=\"conditionValues\">Optional field/attribute values used in the conditional expression</param>\n        /// <returns></returns>\n        public Task PutEntryAsync(string tableName, Dictionary<string, AttributeValue> fields, string conditionExpression = \"\", Dictionary<string, AttributeValue> conditionValues = null)\n        {\n            LogTraceCreatingTableEntry(_logger, tableName, new(fields));\n\n            try\n            {\n                var request = new PutItemRequest(tableName, fields, ReturnValue.NONE);\n                if (!string.IsNullOrWhiteSpace(conditionExpression))\n                    request.ConditionExpression = conditionExpression;\n\n                if (conditionValues != null && conditionValues.Keys.Count > 0)\n                    request.ExpressionAttributeValues = conditionValues;\n\n                return _ddbClient.PutItemAsync(request);\n            }\n            catch (Exception exc)\n            {\n                LogErrorUnableToCreateItem(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Create or update an entry in a DynamoDB Table\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to upsert an entry</param>\n        /// <param name=\"keys\">The table entry keys for the entry</param>\n        /// <param name=\"fields\">The fields/attributes to add or updated in the table</param>\n        /// <param name=\"conditionExpression\">Optional conditional expression</param>\n        /// <param name=\"conditionValues\">Optional field/attribute values used in the conditional expression</param>\n        /// <param name=\"extraExpression\">Additional expression that will be added in the end of the upsert expression</param>\n        /// <param name=\"extraExpressionValues\">Additional field/attribute that will be used in the extraExpression</param>\n        /// <remarks>The fields dictionary item values will be updated with the values returned from DynamoDB</remarks>\n        /// <returns></returns>\n        public async Task UpsertEntryAsync(string tableName, Dictionary<string, AttributeValue> keys, Dictionary<string, AttributeValue> fields,\n            string conditionExpression = \"\", Dictionary<string, AttributeValue> conditionValues = null, string extraExpression = \"\",\n            Dictionary<string, AttributeValue> extraExpressionValues = null)\n        {\n            LogTraceUpsertingEntry(_logger, new(fields), new(keys), tableName);\n\n            try\n            {\n                var request = new UpdateItemRequest\n                {\n                    TableName = tableName,\n                    Key = keys,\n                    ReturnValues = ReturnValue.UPDATED_NEW\n                };\n\n                (request.UpdateExpression, request.ExpressionAttributeValues) = ConvertUpdate(fields, conditionValues,\n                    extraExpression, extraExpressionValues);\n\n                if (!string.IsNullOrWhiteSpace(conditionExpression))\n                    request.ConditionExpression = conditionExpression;\n\n                var result = await _ddbClient.UpdateItemAsync(request);\n\n                foreach (var key in result.Attributes.Keys)\n                {\n                    if (fields.ContainsKey(key))\n                    {\n                        fields[key] = result.Attributes[key];\n                    }\n                    else\n                    {\n                        fields.Add(key, result.Attributes[key]);\n                    }\n                }\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateUpsert(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        public (string updateExpression, Dictionary<string, AttributeValue> expressionAttributeValues)\n            ConvertUpdate(Dictionary<string, AttributeValue> fields,\n                Dictionary<string, AttributeValue> conditionValues = null,\n                string extraExpression = \"\", Dictionary<string, AttributeValue> extraExpressionValues = null)\n        {\n            var expressionAttributeValues = new Dictionary<string, AttributeValue>();\n\n            var updateExpression = new StringBuilder();\n            foreach (var field in fields.Keys)\n            {\n                var valueKey = \":\" + field;\n                expressionAttributeValues.Add(valueKey, fields[field]);\n                updateExpression.Append($\" {field} = {valueKey},\");\n            }\n            updateExpression.Insert(0, \"SET\");\n\n            if (string.IsNullOrWhiteSpace(extraExpression))\n            {\n                updateExpression.Remove(updateExpression.Length - 1, 1);\n            }\n            else\n            {\n                updateExpression.Append($\" {extraExpression}\");\n                if (extraExpressionValues != null && extraExpressionValues.Count > 0)\n                {\n                    foreach (var key in extraExpressionValues.Keys)\n                    {\n                        expressionAttributeValues.Add(key, extraExpressionValues[key]);\n                    }\n                }\n            }\n\n            if (conditionValues != null && conditionValues.Keys.Count > 0)\n            {\n                foreach (var item in conditionValues)\n                {\n                    expressionAttributeValues.Add(item.Key, item.Value);\n                }\n            }\n\n            return (updateExpression.ToString(), expressionAttributeValues);\n        }\n\n        /// <summary>\n        /// Delete an entry from a DynamoDB table\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to delete an entry</param>\n        /// <param name=\"keys\">The table entry keys for the entry to be deleted</param>\n        /// <param name=\"conditionExpression\">Optional conditional expression</param>\n        /// <param name=\"conditionValues\">Optional field/attribute values used in the conditional expression</param>\n        /// <returns></returns>\n        public Task DeleteEntryAsync(string tableName, Dictionary<string, AttributeValue> keys, string conditionExpression = \"\", Dictionary<string, AttributeValue> conditionValues = null)\n        {\n            LogTraceDeletingTableEntry(_logger, tableName, new(keys));\n\n            try\n            {\n                var request = new DeleteItemRequest\n                {\n                    TableName = tableName,\n                    Key = keys\n                };\n\n                if (!string.IsNullOrWhiteSpace(conditionExpression))\n                    request.ConditionExpression = conditionExpression;\n\n                if (conditionValues != null && conditionValues.Keys.Count > 0)\n                    request.ExpressionAttributeValues = conditionValues;\n\n                return _ddbClient.DeleteItemAsync(request);\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateDelete(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Delete multiple entries from a DynamoDB table (Batch delete)\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to delete entries</param>\n        /// <param name=\"toDelete\">List of key values for each entry that must be deleted in the batch</param>\n        /// <returns></returns>\n        public Task DeleteEntriesAsync(string tableName, IReadOnlyCollection<Dictionary<string, AttributeValue>> toDelete)\n        {\n            LogTraceDeletingTableEntries(_logger, tableName);\n\n            if (toDelete == null) throw new ArgumentNullException(nameof(toDelete));\n\n            if (toDelete.Count == 0)\n                return Task.CompletedTask;\n\n            try\n            {\n                var request = new BatchWriteItemRequest();\n                request.RequestItems = new Dictionary<string, List<WriteRequest>>();\n                var batch = new List<WriteRequest>();\n\n                foreach (var keys in toDelete)\n                {\n                    var writeRequest = new WriteRequest();\n                    writeRequest.DeleteRequest = new DeleteRequest();\n                    writeRequest.DeleteRequest.Key = keys;\n                    batch.Add(writeRequest);\n                }\n                request.RequestItems.Add(tableName, batch);\n                return _ddbClient.BatchWriteItemAsync(request);\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateDeleteEntries(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Read an entry from a DynamoDB table\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type</typeparam>\n        /// <param name=\"tableName\">The name of the table to search for the entry</param>\n        /// <param name=\"keys\">The table entry keys to search for</param>\n        /// <param name=\"resolver\">Function that will be called to translate the returned fields into a concrete type. This Function is only called if the result is != null</param>\n        /// <returns>The object translated by the resolver function</returns>\n        public async Task<TResult> ReadSingleEntryAsync<TResult>(string tableName, Dictionary<string, AttributeValue> keys, Func<Dictionary<string, AttributeValue>, TResult> resolver) where TResult : class\n        {\n            try\n            {\n                var request = new GetItemRequest\n                {\n                    TableName = tableName,\n                    Key = keys,\n                    ConsistentRead = true\n                };\n\n                var response = await _ddbClient.GetItemAsync(request);\n\n                if (response.IsItemSet)\n                {\n                    return resolver(response.Item);\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            catch (Exception)\n            {\n                LogDebugUnableToFindTableEntry(_logger, new(keys));\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Query for multiple entries in a DynamoDB table by filtering its keys\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type</typeparam>\n        /// <param name=\"tableName\">The name of the table to search for the entries</param>\n        /// <param name=\"keys\">The table entry keys to search for</param>\n        /// <param name=\"keyConditionExpression\">the expression that will filter the keys</param>\n        /// <param name=\"resolver\">Function that will be called to translate the returned fields into a concrete type. This Function is only called if the result is != null and will be called for each entry that match the query and added to the results list</param>\n        /// <param name=\"indexName\">In case a secondary index is used in the keyConditionExpression</param>\n        /// <param name=\"scanIndexForward\">In case an index is used, show if the seek order is ascending (true) or descending (false)</param>\n        /// <param name=\"lastEvaluatedKey\">The primary key of the first item that this operation will evaluate. Use the value that was returned for LastEvaluatedKey in the previous operation</param>\n        /// <param name=\"consistentRead\">Determines the read consistency model. Note that if a GSI is used, this must be false.</param>\n        /// <returns>The collection containing a list of objects translated by the resolver function and the LastEvaluatedKey for paged results</returns>\n        public async Task<(List<TResult> results, Dictionary<string, AttributeValue> lastEvaluatedKey)> QueryAsync<TResult>(string tableName, Dictionary<string, AttributeValue> keys, string keyConditionExpression, Func<Dictionary<string, AttributeValue>, TResult> resolver, string indexName = \"\", bool scanIndexForward = true, Dictionary<string, AttributeValue> lastEvaluatedKey = null, bool consistentRead = true) where TResult : class\n        {\n            try\n            {\n                var request = new QueryRequest\n                {\n                    TableName = tableName,\n                    ExpressionAttributeValues = keys,\n                    ConsistentRead = consistentRead,\n                    KeyConditionExpression = keyConditionExpression,\n                    Select = Select.ALL_ATTRIBUTES\n                };\n\n                if (lastEvaluatedKey != null && lastEvaluatedKey.Count > 0)\n                {\n                    request.ExclusiveStartKey = lastEvaluatedKey;\n                }\n\n                if (!string.IsNullOrWhiteSpace(indexName))\n                {\n                    request.ScanIndexForward = scanIndexForward;\n                    request.IndexName = indexName;\n                }\n\n                var response = await _ddbClient.QueryAsync(request);\n\n                var resultList = new List<TResult>();\n                foreach (var item in response.Items)\n                {\n                    resultList.Add(resolver(item));\n                }\n                return (resultList, response.LastEvaluatedKey);\n            }\n            catch (Exception)\n            {\n                LogDebugUnableToFindTableEntry(_logger, new(keys));\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Query for multiple entries in a DynamoDB table by filtering its keys\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type</typeparam>\n        /// <param name=\"tableName\">The name of the table to search for the entries</param>\n        /// <param name=\"keys\">The table entry keys to search for</param>\n        /// <param name=\"keyConditionExpression\">the expression that will filter the keys</param>\n        /// <param name=\"resolver\">Function that will be called to translate the returned fields into a concrete type. This Function is only called if the result is != null and will be called for each entry that match the query and added to the results list</param>\n        /// <param name=\"indexName\">In case a secondary index is used in the keyConditionExpression</param>\n        /// <param name=\"scanIndexForward\">In case an index is used, show if the seek order is ascending (true) or descending (false)</param>\n        /// <param name=\"consistentRead\">Determines the read consistency model. Note that if a GSI is used, this must be false.</param>\n        /// <returns>The collection containing a list of objects translated by the resolver function</returns>\n        public async Task<List<TResult>> QueryAllAsync<TResult>(string tableName, Dictionary<string, AttributeValue> keys,\n                string keyConditionExpression, Func<Dictionary<string, AttributeValue>, TResult> resolver,\n                string indexName = \"\", bool scanIndexForward = true, bool consistentRead = true) where TResult : class\n        {\n            List<TResult> resultList = null;\n            Dictionary<string, AttributeValue> lastEvaluatedKey = null;\n            do\n            {\n                List<TResult> results;\n                (results, lastEvaluatedKey) = await QueryAsync(tableName, keys, keyConditionExpression, resolver,\n                    indexName, scanIndexForward, lastEvaluatedKey, consistentRead);\n                if (resultList == null)\n                {\n                    resultList = results;\n                }\n                else\n                {\n                    resultList.AddRange(results);\n                }\n            } while (lastEvaluatedKey != null && lastEvaluatedKey.Count != 0);\n\n            return resultList;\n        }\n\n        /// <summary>\n        /// Scan a DynamoDB table by querying the entry fields.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type</typeparam>\n        /// <param name=\"tableName\">The name of the table to search for the entries</param>\n        /// <param name=\"attributes\">The attributes used on the expression</param>\n        /// <param name=\"expression\">The filter expression</param>\n        /// <param name=\"resolver\">Function that will be called to translate the returned fields into a concrete type. This Function is only called if the result is != null and will be called for each entry that match the query and added to the results list</param>\n        /// <returns>The collection containing a list of objects translated by the resolver function</returns>\n        public async Task<List<TResult>> ScanAsync<TResult>(string tableName, Dictionary<string, AttributeValue> attributes, string expression, Func<Dictionary<string, AttributeValue>, TResult> resolver) where TResult : class\n        {\n            // From the Amazon documentation:\n            // \"A single Scan operation will read up to the maximum number of items set\n            // (if using the Limit parameter) or a maximum of 1 MB of data and then apply\n            // any filtering to the results using FilterExpression.\"\n            // https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/MDynamoDBScanAsyncStringDictionary!String,%20Condition!CancellationToken.html\n\n            try\n            {\n                var resultList = new List<TResult>();\n\n                Dictionary<string, AttributeValue> exclusiveStartKey = null;\n\n                while (true)\n                {\n                    var request = new ScanRequest\n                    {\n                        TableName = tableName,\n                        ConsistentRead = true,\n                        FilterExpression = expression,\n                        ExpressionAttributeValues = attributes,\n                        Select = Select.ALL_ATTRIBUTES\n                    };\n\n                    if (exclusiveStartKey is not null && exclusiveStartKey.Count > 0)\n                    {\n                        request.ExclusiveStartKey = exclusiveStartKey;\n                    }\n\n                    var response = await _ddbClient.ScanAsync(request);\n\n                    if (response.Items != null)\n                    {\n                        foreach (var item in response.Items)\n                        {\n                            resultList.Add(resolver(item));\n                        }\n                    }\n\n                    if (response.LastEvaluatedKey == null || response.LastEvaluatedKey.Count == 0)\n                    {\n                        break;\n                    }\n                    else\n                    {\n                        exclusiveStartKey = response.LastEvaluatedKey;\n                    }\n                }\n\n                return resultList;\n            }\n            catch (Exception exc)\n            {\n                LogWarningFailedToReadTable(_logger, exc, tableName);\n                throw new OrleansException($\"Failed to read table {tableName}: {exc.Message}\", exc);\n            }\n        }\n\n        /// <summary>\n        /// Crete or replace multiple entries in a DynamoDB table (Batch put)\n        /// </summary>\n        /// <param name=\"tableName\">The name of the table to search for the entry</param>\n        /// <param name=\"toCreate\">List of key values for each entry that must be created or replaced in the batch</param>\n        /// <returns></returns>\n        public Task PutEntriesAsync(string tableName, IReadOnlyCollection<Dictionary<string, AttributeValue>> toCreate)\n        {\n            LogTracePutEntries(_logger, tableName);\n\n            if (toCreate == null) throw new ArgumentNullException(nameof(toCreate));\n\n            if (toCreate.Count == 0)\n                return Task.CompletedTask;\n\n            try\n            {\n                var request = new BatchWriteItemRequest();\n                request.RequestItems = new Dictionary<string, List<WriteRequest>>();\n                var batch = new List<WriteRequest>();\n\n                foreach (var item in toCreate)\n                {\n                    var writeRequest = new WriteRequest();\n                    writeRequest.PutRequest = new PutRequest();\n                    writeRequest.PutRequest.Item = item;\n                    batch.Add(writeRequest);\n                }\n                request.RequestItems.Add(tableName, batch);\n                return _ddbClient.BatchWriteItemAsync(request);\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateBulkInsert(_logger, exc, tableName);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Transactionally reads entries from a DynamoDB table\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type</typeparam>\n        /// <param name=\"tableName\">The name of the table to search for the entry</param>\n        /// <param name=\"keys\">The table entry keys to search for</param>\n        /// <param name=\"resolver\">Function that will be called to translate the returned fields into a concrete type. This Function is only called if the result is != null</param>\n        /// <returns>The object translated by the resolver function</returns>\n        public async Task<IEnumerable<TResult>> GetEntriesTxAsync<TResult>(string tableName, IEnumerable<Dictionary<string, AttributeValue>> keys, Func<Dictionary<string, AttributeValue>, TResult> resolver) where TResult : class\n        {\n            try\n            {\n                var request = new TransactGetItemsRequest\n                {\n                    TransactItems = keys.Select(key => new TransactGetItem\n                    {\n                        Get = new Get\n                        {\n                            TableName = tableName,\n                            Key = key\n                        }\n                    }).ToList()\n                };\n\n                var response = await _ddbClient.TransactGetItemsAsync(request);\n\n                return response.Responses.Where(r => r?.Item?.Count > 0).Select(r => resolver(r.Item));\n            }\n            catch (Exception)\n            {\n                LogDebugUnableToFindTableEntries(_logger, new(keys));\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Transactionally performs write requests\n        /// </summary>\n        /// <param name=\"puts\">Any puts to be performed</param>\n        /// <param name=\"updates\">Any updated to be performed</param>\n        /// <param name=\"deletes\">Any deletes to be performed</param>\n        /// <param name=\"conditionChecks\">Any condition checks to be performed</param>\n        /// <returns></returns>\n        public Task WriteTxAsync(IEnumerable<Put> puts = null, IEnumerable<Update> updates = null, IEnumerable<Delete> deletes = null, IEnumerable<ConditionCheck> conditionChecks = null)\n        {\n            try\n            {\n                var transactItems = new List<TransactWriteItem>();\n                if (puts != null)\n                {\n                    transactItems.AddRange(puts.Select(p => new TransactWriteItem { Put = p }));\n                }\n                if (updates != null)\n                {\n                    transactItems.AddRange(updates.Select(u => new TransactWriteItem { Update = u }));\n                }\n                if (deletes != null)\n                {\n                    transactItems.AddRange(deletes.Select(d => new TransactWriteItem { Delete = d }));\n                }\n                if (conditionChecks != null)\n                {\n                    transactItems.AddRange(conditionChecks.Select(c => new TransactWriteItem { ConditionCheck = c }));\n                }\n\n                var request = new TransactWriteItemsRequest\n                {\n                    TransactItems = transactItems\n                };\n\n                return _ddbClient.TransactWriteItemsAsync(request);\n            }\n            catch (Exception exc)\n            {\n                LogDebugUnableToWrite(_logger, exc);\n                throw;\n            }\n        }\n\n        private readonly struct DictionaryLogRecord(Dictionary<string, AttributeValue> dictionary)\n        {\n            public override string ToString() => Utils.DictionaryToString(dictionary);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"The config values for 'createIfNotExists' and 'updateIfExists' are false. The table '{TableName}' will not be created or updated.\"\n        )]\n        private static partial void LogInformationTableNotCreatedOrUpdated(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not initialize connection to storage table {TableName}\"\n        )]\n        private static partial void LogErrorCouldNotInitializeTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"The config value 'createIfNotExists' is false. The table '{TableName}' does not exist and it will not get created.\"\n        )]\n        private static partial void LogWarningTableNotCreated(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not create table {TableName}\"\n        )]\n        private static partial void LogErrorCouldNotCreateTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"The config value 'updateIfExists' is false. The table structure for table '{TableName}' will not be updated.\"\n        )]\n        private static partial void LogWarningTableNotUpdated(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not update table {TableName}\"\n        )]\n        private static partial void LogErrorCouldNotUpdateTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"TTL is not DISABLED. Cannot update table TTL for table {TableName}. Please update manually.\"\n        )]\n        private static partial void LogWarningTtlNotDisabled(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception occured while updating table {TableName} TTL attribute to {TtlAttributeName}. Please update manually.\"\n        )]\n        private static partial void LogErrorUpdateTtlException(ILogger logger, Exception exception, string tableName, string ttlAttributeName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not delete table {TableName}\"\n        )]\n        private static partial void LogErrorCouldNotDeleteTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Creating {TableName} table entry: {TableEntry}\"\n        )]\n        private static partial void LogTraceCreatingTableEntry(ILogger logger, string tableName, DictionaryLogRecord tableEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unable to create item to table {TableName}\"\n        )]\n        private static partial void LogErrorUnableToCreateItem(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Upserting entry {Entry} with key(s) {Keys} into table {TableName}\"\n        )]\n        private static partial void LogTraceUpsertingEntry(ILogger logger, DictionaryLogRecord entry, DictionaryLogRecord keys, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error upserting to the table {TableName}\"\n        )]\n        private static partial void LogWarningIntermediateUpsert(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Deleting table {TableName} entry with key(s) {Keys}\"\n        )]\n        private static partial void LogTraceDeletingTableEntry(ILogger logger, string tableName, DictionaryLogRecord keys);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error deleting entry from the table {TableName}.\"\n        )]\n        private static partial void LogWarningIntermediateDelete(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Deleting {TableName} table entries\"\n        )]\n        private static partial void LogTraceDeletingTableEntries(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error deleting entries from the table {TableName}.\"\n        )]\n        private static partial void LogWarningIntermediateDeleteEntries(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Put entries {TableName} table\"\n        )]\n        private static partial void LogTracePutEntries(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error bulk inserting entries to table {TableName}.\"\n        )]\n        private static partial void LogWarningIntermediateBulkInsert(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unable to find table entry for Keys = {Keys}\"\n        )]\n        private static partial void LogDebugUnableToFindTableEntry(ILogger logger, DictionaryLogRecord keys);\n\n        private readonly struct DictionariesLogRecord(IEnumerable<Dictionary<string, AttributeValue>> keys)\n        {\n            public override string ToString() => Utils.EnumerableToString(keys, d => Utils.DictionaryToString(d));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unable to find table entry for Keys = {Keys}\"\n        )]\n        private static partial void LogDebugUnableToFindTableEntries(ILogger logger, DictionariesLogRecord keys);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to read table {TableName}\"\n        )]\n        private static partial void LogWarningFailedToReadTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unable to write\"\n        )]\n        private static partial void LogDebugUnableToWrite(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/AdoNetClusteringProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AdoNet\", \"Clustering\", \"Silo\", typeof(AdoNetClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"AdoNet\", \"Clustering\", \"Client\", typeof(AdoNetClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AdoNetClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAdoNetClustering((OptionsBuilder<AdoNetClusteringSiloOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var invariant = configurationSection[nameof(options.Invariant)];\n                if (!string.IsNullOrEmpty(invariant))\n                {\n                    options.Invariant = invariant;\n                }\n\n                var connectionString = configurationSection[nameof(options.ConnectionString)];\n                var connectionName = configurationSection[\"ConnectionName\"];\n                if (string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(connectionName))\n                {\n                    connectionString = services.GetRequiredService<IConfiguration>().GetConnectionString(connectionName);\n                }\n\n                if (!string.IsNullOrEmpty(connectionString))\n                {\n                    options.ConnectionString = connectionString;\n                }\n            }));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAdoNetClustering((OptionsBuilder<AdoNetClusteringClientOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var invariant = configurationSection[nameof(options.Invariant)];\n                if (!string.IsNullOrEmpty(invariant))\n                {\n                    options.Invariant = invariant;\n                }\n\n                var connectionString = configurationSection[nameof(options.ConnectionString)];\n                var connectionName = configurationSection[\"ConnectionName\"];\n                if (string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(connectionName))\n                {\n                    connectionString = services.GetRequiredService<IConfiguration>().GetConnectionString(connectionName);\n                }\n\n                if (!string.IsNullOrEmpty(connectionString))\n                {\n                    options.ConnectionString = connectionString;\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/AdoNetHostingExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for configuring ADO.NET for clustering.\n    /// </summary>\n    public static class AdoNetHostingExtensions\n    {\n        /// <summary>\n        /// Configures this silo to use ADO.NET for clustering. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder UseAdoNetClustering(\n            this ISiloBuilder builder,\n            Action<AdoNetClusteringSiloOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IMembershipTable, AdoNetClusteringTable>();\n                    services.AddSingleton<IConfigurationValidator, AdoNetClusteringSiloOptionsValidator>();\n                });\n        }\n\n        /// <summary>\n        /// Configures this silo to use ADO.NET for clustering. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder UseAdoNetClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<AdoNetClusteringSiloOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<AdoNetClusteringSiloOptions>());\n                    services.AddSingleton<IMembershipTable, AdoNetClusteringTable>();\n                    services.AddSingleton<IConfigurationValidator, AdoNetClusteringSiloOptionsValidator>();\n                });\n        }\n\n        /// <summary>\n        /// Configures this client to use ADO.NET for clustering. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IClientBuilder UseAdoNetClustering(\n            this IClientBuilder builder,\n            Action<AdoNetClusteringClientOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IGatewayListProvider, AdoNetGatewayListProvider>();\n                    services.AddSingleton<IConfigurationValidator, AdoNetClusteringClientOptionsValidator>();\n                });\n        }\n\n        /// <summary>\n        /// Configures this client to use ADO.NET for clustering. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IClientBuilder UseAdoNetClustering(\n            this IClientBuilder builder,\n            Action<OptionsBuilder<AdoNetClusteringClientOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<AdoNetClusteringClientOptions>());\n                    services.AddSingleton<IGatewayListProvider, AdoNetGatewayListProvider>();\n                    services.AddSingleton<IConfigurationValidator, AdoNetClusteringClientOptionsValidator>();\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Messaging/AdoNetClusteringTable.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.AdoNet.Storage;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    public partial class AdoNetClusteringTable : IMembershipTable\n    {\n        private readonly string clusterId;\n        private readonly IServiceProvider serviceProvider;\n        private readonly ILogger logger;\n        private RelationalOrleansQueries orleansQueries;\n        private readonly AdoNetClusteringSiloOptions clusteringTableOptions;\n\n        public AdoNetClusteringTable(\n            IServiceProvider serviceProvider,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<AdoNetClusteringSiloOptions> clusteringOptions,\n            ILogger<AdoNetClusteringTable> logger)\n        {\n            this.serviceProvider = serviceProvider;\n            this.logger = logger;\n            this.clusteringTableOptions = clusteringOptions.Value;\n            this.clusterId = clusterOptions.Value.ClusterId;\n        }\n\n        public async Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            LogTraceInitializeMembershipTable();\n\n            //This initializes all of Orleans operational queries from the database using a well known view\n            //and assumes the database with appropriate definitions exists already.\n            orleansQueries = await RelationalOrleansQueries.CreateInstance(\n                clusteringTableOptions.Invariant,\n                clusteringTableOptions.ConnectionString);\n\n            // even if I am not the one who created the table,\n            // try to insert an initial table version if it is not already there,\n            // so we always have a first table version row, before this silo starts working.\n            if (tryInitTableVersion)\n            {\n                var wasCreated = await InitTableAsync();\n                if (wasCreated)\n                {\n                    LogInfoCreatedNewTableVersionRow();\n                }\n            }\n        }\n\n        public async Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            LogTraceReadRow(key);\n            try\n            {\n                return await orleansQueries.MembershipReadRowAsync(this.clusterId, key);\n            }\n            catch (Exception ex)\n            {\n                LogDebugReadRowFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task<MembershipTableData> ReadAll()\n        {\n            LogTraceReadAll();\n            try\n            {\n                return await orleansQueries.MembershipReadAllAsync(this.clusterId);\n            }\n            catch (Exception ex)\n            {\n                LogDebugReadAllFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            LogTraceInsertRow(entry, tableVersion);\n\n            //The \"tableVersion\" parameter should always exist when inserting a row as Init should\n            //have been called and membership version created and read. This is an optimization to\n            //not to go through all the way to database to fail a conditional check on etag (which does\n            //exist for the sake of robustness) as mandated by Orleans membership protocol.\n            //Likewise, no update can be done without membership entry.\n            if (entry == null)\n            {\n                LogDebugInsertRowAbortedNullEntry();\n                throw new ArgumentNullException(nameof(entry));\n            }\n            if (tableVersion is null)\n            {\n                LogDebugInsertRowAbortedNullTableVersion();\n                throw new ArgumentNullException(nameof(tableVersion));\n            }\n\n            try\n            {\n                return await orleansQueries.InsertMembershipRowAsync(this.clusterId, entry, tableVersion.VersionEtag);\n            }\n            catch (Exception ex)\n            {\n                LogDebugInsertRowFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            LogTraceUpdateRow(entry, etag, tableVersion);\n\n            //The \"tableVersion\" parameter should always exist when updating a row as Init should\n            //have been called and membership version created and read. This is an optimization to\n            //not to go through all the way to database to fail a conditional check (which does\n            //exist for the sake of robustness) as mandated by Orleans membership protocol.\n            //Likewise, no update can be done without membership entry or an etag.\n            if (entry == null)\n            {\n                LogDebugUpdateRowAbortedNullEntry();\n                throw new ArgumentNullException(nameof(entry));\n            }\n            if (tableVersion is null)\n            {\n                LogDebugUpdateRowAbortedNullTableVersion();\n                throw new ArgumentNullException(nameof(tableVersion));\n            }\n\n            try\n            {\n                return await orleansQueries.UpdateMembershipRowAsync(this.clusterId, entry, tableVersion.VersionEtag);\n            }\n            catch (Exception ex)\n            {\n                LogDebugUpdateRowFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            LogTraceUpdateIAmAlive(entry);\n            if (entry == null)\n            {\n                LogDebugUpdateIAmAliveAbortedNullEntry();\n                throw new ArgumentNullException(nameof(entry));\n            }\n            try\n            {\n                await orleansQueries.UpdateIAmAliveTimeAsync(this.clusterId, entry.SiloAddress, entry.IAmAliveTime);\n            }\n            catch (Exception ex)\n            {\n                LogDebugUpdateIAmAliveFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task DeleteMembershipTableEntries(string clusterId)\n        {\n            LogTraceDeleteMembershipTableEntries(clusterId);\n            try\n            {\n                await orleansQueries.DeleteMembershipTableEntriesAsync(clusterId);\n            }\n            catch (Exception ex)\n            {\n                LogDebugDeleteMembershipTableEntriesFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            LogTraceCleanupDefunctSiloEntries(beforeDate, clusterId);\n            try\n            {\n                await orleansQueries.CleanupDefunctSiloEntriesAsync(beforeDate, this.clusterId);\n            }\n            catch (Exception ex)\n            {\n                LogDebugCleanupDefunctSiloEntriesFailed(ex);\n                throw;\n            }\n        }\n\n        private async Task<bool> InitTableAsync()\n        {\n            try\n            {\n                return await orleansQueries.InsertMembershipVersionRowAsync(this.clusterId);\n            }\n            catch (Exception ex)\n            {\n                LogTraceInsertSiloMembershipVersionFailed(ex);\n                throw;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(InitializeMembershipTable)} called.\"\n        )]\n        private partial void LogTraceInitializeMembershipTable();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Created new table version row.\"\n        )]\n        private partial void LogInfoCreatedNewTableVersionRow();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(ReadRow)} called with key: {{Key}}.\"\n        )]\n        private partial void LogTraceReadRow(SiloAddress key);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(ReadRow)} failed\"\n        )]\n        private partial void LogDebugReadRowFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(ReadAll)} called.\"\n        )]\n        private partial void LogTraceReadAll();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(ReadAll)} failed\"\n        )]\n        private partial void LogDebugReadAllFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(InsertRow)} called with entry {{Entry}} and tableVersion {{TableVersion}}.\"\n        )]\n        private partial void LogTraceInsertRow(MembershipEntry entry, TableVersion tableVersion);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(InsertRow)} aborted due to null check. MembershipEntry is null.\"\n        )]\n        private partial void LogDebugInsertRowAbortedNullEntry();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(InsertRow)} aborted due to null check. TableVersion is null \"\n        )]\n        private partial void LogDebugInsertRowAbortedNullTableVersion();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(InsertRow)} failed\"\n        )]\n        private partial void LogDebugInsertRowFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(IMembershipTable)}.{nameof(UpdateRow)} called with entry {{Entry}}, etag {{ETag}} and tableVersion {{TableVersion}}.\"\n        )]\n        private partial void LogTraceUpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(UpdateRow)} aborted due to null check. MembershipEntry is null.\"\n        )]\n        private partial void LogDebugUpdateRowAbortedNullEntry();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(UpdateRow)} aborted due to null check. TableVersion is null\"\n        )]\n        private partial void LogDebugUpdateRowAbortedNullTableVersion();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(UpdateRow)} failed\"\n        )]\n        private partial void LogDebugUpdateRowFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(IMembershipTable)}.{nameof(UpdateIAmAlive)} called with entry {{Entry}}.\"\n        )]\n        private partial void LogTraceUpdateIAmAlive(MembershipEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(UpdateIAmAlive)} aborted due to null check. MembershipEntry is null.\"\n        )]\n        private partial void LogDebugUpdateIAmAliveAbortedNullEntry();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(UpdateIAmAlive)} failed\"\n        )]\n        private partial void LogDebugUpdateIAmAliveFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(IMembershipTable)}.{nameof(DeleteMembershipTableEntries)} called with clusterId {{ClusterId}}.\"\n        )]\n        private partial void LogTraceDeleteMembershipTableEntries(string clusterId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(DeleteMembershipTableEntries)} failed\"\n        )]\n        private partial void LogDebugDeleteMembershipTableEntriesFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(IMembershipTable)}.{nameof(CleanupDefunctSiloEntries)} called with beforeDate {{beforeDate}} and clusterId {{ClusterId}}.\"\n        )]\n        private partial void LogTraceCleanupDefunctSiloEntries(DateTimeOffset beforeDate, string clusterId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetClusteringTable)}.{nameof(CleanupDefunctSiloEntries)} failed\"\n        )]\n        private partial void LogDebugCleanupDefunctSiloEntriesFailed(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Insert silo membership version failed\"\n        )]\n        private partial void LogTraceInsertSiloMembershipVersionFailed(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Messaging/AdoNetGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.AdoNet.Storage;\nusing Orleans.Messaging;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Membership\n{\n    public partial class AdoNetGatewayListProvider : IGatewayListProvider\n    {\n        private readonly ILogger _logger;\n        private readonly string _clusterId;\n        private readonly AdoNetClusteringClientOptions _options;\n        private RelationalOrleansQueries _orleansQueries;\n        private readonly IServiceProvider _serviceProvider;\n        private readonly TimeSpan _maxStaleness;\n\n        public AdoNetGatewayListProvider(\n            ILogger<AdoNetGatewayListProvider> logger,\n            IServiceProvider serviceProvider,\n            IOptions<AdoNetClusteringClientOptions> options,\n            IOptions<GatewayOptions> gatewayOptions,\n            IOptions<ClusterOptions> clusterOptions)\n        {\n            this._logger = logger;\n            this._serviceProvider = serviceProvider;\n            this._options = options.Value;\n            this._clusterId = clusterOptions.Value.ClusterId;\n            this._maxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n        }\n\n        public TimeSpan MaxStaleness\n        {\n            get { return this._maxStaleness; }\n        }\n\n        public bool IsUpdatable\n        {\n            get { return true; }\n        }\n\n        public async Task InitializeGatewayListProvider()\n        {\n            LogTraceInitializeGatewayListProvider();\n            _orleansQueries = await RelationalOrleansQueries.CreateInstance(_options.Invariant, _options.ConnectionString);\n        }\n\n        public async Task<IList<Uri>> GetGateways()\n        {\n            LogTraceGetGateways();\n            try\n            {\n                return await _orleansQueries.ActiveGatewaysAsync(this._clusterId);\n            }\n            catch (Exception ex)\n            {\n                LogDebugGatewaysFailed(ex);\n                throw;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetGatewayListProvider)}.{nameof(InitializeGatewayListProvider)} called.\"\n        )]\n        private partial void LogTraceInitializeGatewayListProvider();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = $\"{nameof(AdoNetGatewayListProvider)}.{nameof(GetGateways)} called.\"\n        )]\n        private partial void LogTraceGetGateways();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AdoNetGatewayListProvider)}.{nameof(GetGateways)} failed\"\n        )]\n        private partial void LogDebugGatewaysFailed(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Migrations/MySQL-Clustering-3.7.0.sql",
    "content": "INSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'CleanupDefunctSiloEntriesKey','\n    DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = @DeploymentId\n        AND @DeploymentId IS NOT NULL\n        AND IAmAliveTime < @IAmAliveTime\n        AND Status !=3;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Migrations/Oracle-Clustering-3.7.0.sql",
    "content": "INSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n  'DeleteMembershipTableEntriesKey','\n  BEGIN\n    DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = :DeploymentId\n        AND :DeploymentId IS NOT NULL\n        AND IAmAliveTime < :IAmAliveTime\n        AND Status != 3;\n  END;\n');\n/"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Migrations/PostgreSQL-Clustering-3.6.0.sql",
    "content": "-- Run this migration for upgrading the PostgreSQL clustering table and routines for deployments created before 3.6.0\n\nBEGIN;\n\n-- Change date type\n\nALTER TABLE OrleansMembershipVersionTable\nALTER COLUMN Timestamp TYPE TIMESTAMPTZ(3) USING Timestamp AT TIME ZONE 'UTC';\n\nALTER TABLE OrleansMembershipTable\nALTER COLUMN StartTime TYPE TIMESTAMPTZ(3) USING StartTime AT TIME ZONE 'UTC',\nALTER COLUMN IAmAliveTime TYPE TIMESTAMPTZ(3) USING IAmAliveTime AT TIME ZONE 'UTC';\n\n-- Recreate routines\n\nCREATE OR REPLACE FUNCTION update_i_am_alive_time(\n    deployment_id OrleansMembershipTable.DeploymentId%TYPE,\n    address_arg OrleansMembershipTable.Address%TYPE,\n    port_arg OrleansMembershipTable.Port%TYPE,\n    generation_arg OrleansMembershipTable.Generation%TYPE,\n    i_am_alive_time OrleansMembershipTable.IAmAliveTime%TYPE)\n  RETURNS void AS\n$func$\nBEGIN\n    -- This is expected to never fail by Orleans, so return value\n    -- is not needed nor is it checked.\n    UPDATE OrleansMembershipTable as d\n    SET\n        IAmAliveTime = i_am_alive_time\n    WHERE\n        d.DeploymentId = deployment_id AND deployment_id IS NOT NULL\n        AND d.Address = address_arg AND address_arg IS NOT NULL\n        AND d.Port = port_arg AND port_arg IS NOT NULL\n        AND d.Generation = generation_arg AND generation_arg IS NOT NULL;\nEND\n$func$ LANGUAGE plpgsql;\n\n\nCREATE OR REPLACE FUNCTION insert_membership(\n    DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,\n    AddressArg      OrleansMembershipTable.Address%TYPE,\n    PortArg         OrleansMembershipTable.Port%TYPE,\n    GenerationArg   OrleansMembershipTable.Generation%TYPE,\n    SiloNameArg     OrleansMembershipTable.SiloName%TYPE,\n    HostNameArg     OrleansMembershipTable.HostName%TYPE,\n    StatusArg       OrleansMembershipTable.Status%TYPE,\n    ProxyPortArg    OrleansMembershipTable.ProxyPort%TYPE,\n    StartTimeArg    OrleansMembershipTable.StartTime%TYPE,\n    IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,\n    VersionArg      OrleansMembershipVersionTable.Version%TYPE)\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n    BEGIN\n        INSERT INTO OrleansMembershipTable\n        (\n            DeploymentId,\n            Address,\n            Port,\n            Generation,\n            SiloName,\n            HostName,\n            Status,\n            ProxyPort,\n            StartTime,\n            IAmAliveTime\n        )\n        SELECT\n            DeploymentIdArg,\n            AddressArg,\n            PortArg,\n            GenerationArg,\n            SiloNameArg,\n            HostNameArg,\n            StatusArg,\n            ProxyPortArg,\n            StartTimeArg,\n            IAmAliveTimeArg\n        ON CONFLICT (DeploymentId, Address, Port, Generation) DO\n            NOTHING;\n\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        UPDATE OrleansMembershipVersionTable\n        SET\n            Timestamp = now(),\n            Version = Version + 1\n        WHERE\n            DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n            AND Version = VersionArg AND VersionArg IS NOT NULL\n            AND RowCountVar > 0;\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        ASSERT RowCountVar <> 0, 'no rows affected, rollback';\n\n\n        RETURN QUERY SELECT RowCountVar;\n    EXCEPTION\n    WHEN assert_failure THEN\n        RETURN QUERY SELECT RowCountVar;\n    END;\n\nEND\n$func$ LANGUAGE plpgsql;\n\n\nCREATE OR REPLACE FUNCTION update_membership(\n    DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,\n    AddressArg      OrleansMembershipTable.Address%TYPE,\n    PortArg         OrleansMembershipTable.Port%TYPE,\n    GenerationArg   OrleansMembershipTable.Generation%TYPE,\n    StatusArg       OrleansMembershipTable.Status%TYPE,\n    SuspectTimesArg OrleansMembershipTable.SuspectTimes%TYPE,\n    IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,\n    VersionArg      OrleansMembershipVersionTable.Version%TYPE\n  )\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n    BEGIN\n\n    UPDATE OrleansMembershipVersionTable\n    SET\n        Timestamp = now(),\n        Version = Version + 1\n    WHERE\n        DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n        AND Version = VersionArg AND VersionArg IS NOT NULL;\n\n\n    GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n    UPDATE OrleansMembershipTable\n    SET\n        Status = StatusArg,\n        SuspectTimes = SuspectTimesArg,\n        IAmAliveTime = IAmAliveTimeArg\n    WHERE\n        DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n        AND Address = AddressArg AND AddressArg IS NOT NULL\n        AND Port = PortArg AND PortArg IS NOT NULL\n        AND Generation = GenerationArg AND GenerationArg IS NOT NULL\n        AND RowCountVar > 0;\n\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        ASSERT RowCountVar <> 0, 'no rows affected, rollback';\n\n\n        RETURN QUERY SELECT RowCountVar;\n    EXCEPTION\n    WHEN assert_failure THEN\n        RETURN QUERY SELECT RowCountVar;\n    END;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Migrations/PostgreSQL-Clustering-3.7.0.sql",
    "content": "INSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'CleanupDefunctSiloEntriesKey','\n    DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = @DeploymentId\n        AND @DeploymentId IS NOT NULL\n        AND IAmAliveTime < @IAmAliveTime\n        AND Status != 3;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Migrations/SQLServer-Clustering-3.7.0.sql",
    "content": "INSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n    'CleanupDefunctSiloEntriesKey',\n    'DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = @DeploymentId\n        AND @DeploymentId IS NOT NULL\n        AND IAmAliveTime < @IAmAliveTime\n        AND Status != 3;\n    '\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'CleanupDefunctSiloEntriesKey'\n);\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/MySQL-Clustering.sql",
    "content": "-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically.\nCREATE TABLE OrleansMembershipVersionTable\n(\n    DeploymentId NVARCHAR(150) NOT NULL,\n    Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n    Version INT NOT NULL DEFAULT 0,\n\n    CONSTRAINT PK_OrleansMembershipVersionTable_DeploymentId PRIMARY KEY(DeploymentId)\n);\n\n-- Every silo instance has a row in the membership table.\nCREATE TABLE OrleansMembershipTable\n(\n    DeploymentId NVARCHAR(150) NOT NULL,\n    Address VARCHAR(45) NOT NULL,\n    Port INT NOT NULL,\n    Generation INT NOT NULL,\n    SiloName NVARCHAR(150) NOT NULL,\n    HostName NVARCHAR(150) NOT NULL,\n    Status INT NOT NULL,\n    ProxyPort INT NULL,\n    SuspectTimes VARCHAR(8000) NULL,\n    StartTime DATETIME NOT NULL,\n    IAmAliveTime DATETIME NOT NULL,\n\n    CONSTRAINT PK_MembershipTable_DeploymentId PRIMARY KEY(DeploymentId, Address, Port, Generation),\n    CONSTRAINT FK_MembershipTable_MembershipVersionTable_DeploymentId FOREIGN KEY (DeploymentId) REFERENCES OrleansMembershipVersionTable (DeploymentId)\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateIAmAlivetimeKey','\n    -- This is expected to never fail by Orleans, so return value\n    -- is not needed nor is it checked.\n    UPDATE OrleansMembershipTable\n    SET\n        IAmAliveTime = @IAmAliveTime\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n        AND Address = @Address AND @Address IS NOT NULL\n        AND Port = @Port AND @Port IS NOT NULL\n        AND Generation = @Generation AND @Generation IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipVersionKey','\n    INSERT INTO OrleansMembershipVersionTable\n    (\n        DeploymentId\n    )\n    SELECT * FROM ( SELECT @DeploymentId ) AS TMP\n    WHERE NOT EXISTS\n    (\n    SELECT 1\n    FROM\n        OrleansMembershipVersionTable\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n    );\n\n    SELECT ROW_COUNT();\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipKey','\n    call InsertMembershipKey(@DeploymentId, @Address, @Port, @Generation,\n    @Version, @SiloName, @HostName, @Status, @ProxyPort, @StartTime, @IAmAliveTime);'\n);\n\nDELIMITER $$\n\nCREATE PROCEDURE InsertMembershipKey(\n    in    _DeploymentId NVARCHAR(150),\n    in    _Address VARCHAR(45),\n    in    _Port INT,\n    in    _Generation INT,\n    in    _Version INT,\n    in    _SiloName NVARCHAR(150),\n    in    _HostName NVARCHAR(150),\n    in    _Status INT,\n    in    _ProxyPort INT,\n    in    _StartTime DATETIME,\n    in    _IAmAliveTime DATETIME\n)\nBEGIN\n    DECLARE _ROWCOUNT INT;\n    START TRANSACTION;\n    INSERT INTO OrleansMembershipTable\n    (\n        DeploymentId,\n        Address,\n        Port,\n        Generation,\n        SiloName,\n        HostName,\n        Status,\n        ProxyPort,\n        StartTime,\n        IAmAliveTime\n    )\n    SELECT * FROM ( SELECT\n        _DeploymentId,\n        _Address,\n        _Port,\n        _Generation,\n        _SiloName,\n        _HostName,\n        _Status,\n        _ProxyPort,\n        _StartTime,\n        _IAmAliveTime) AS TMP\n    WHERE NOT EXISTS\n    (\n    SELECT 1\n    FROM\n        OrleansMembershipTable\n    WHERE\n        DeploymentId = _DeploymentId AND _DeploymentId IS NOT NULL\n        AND Address = _Address AND _Address IS NOT NULL\n        AND Port = _Port AND _Port IS NOT NULL\n        AND Generation = _Generation AND _Generation IS NOT NULL\n    );\n\n    UPDATE OrleansMembershipVersionTable\n    SET\n        Version = Version + 1\n    WHERE\n        DeploymentId = _DeploymentId AND _DeploymentId IS NOT NULL\n        AND Version = _Version AND _Version IS NOT NULL\n        AND ROW_COUNT() > 0;\n\n    SET _ROWCOUNT = ROW_COUNT();\n\n    IF _ROWCOUNT = 0\n    THEN\n        ROLLBACK;\n    ELSE\n        COMMIT;\n    END IF;\n    SELECT _ROWCOUNT;\nEND$$\n\nDELIMITER ;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateMembershipKey','\n    START TRANSACTION;\n\n    UPDATE OrleansMembershipVersionTable\n    SET\n        Version = Version + 1\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n        AND Version = @Version AND @Version IS NOT NULL;\n\n    UPDATE OrleansMembershipTable\n    SET\n        Status = @Status,\n        SuspectTimes = @SuspectTimes,\n        IAmAliveTime = @IAmAliveTime\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n        AND Address = @Address AND @Address IS NOT NULL\n        AND Port = @Port AND @Port IS NOT NULL\n        AND Generation = @Generation AND @Generation IS NOT NULL\n        AND ROW_COUNT() > 0;\n\n    SELECT ROW_COUNT();\n    COMMIT;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'GatewaysQueryKey','\n    SELECT\n        Address,\n        ProxyPort,\n        Generation\n    FROM\n        OrleansMembershipTable\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n        AND Status = @Status AND @Status IS NOT NULL\n        AND ProxyPort > 0;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadRowKey','\n    SELECT\n        v.DeploymentId,\n        m.Address,\n        m.Port,\n        m.Generation,\n        m.SiloName,\n        m.HostName,\n        m.Status,\n        m.ProxyPort,\n        m.SuspectTimes,\n        m.StartTime,\n        m.IAmAliveTime,\n        v.Version\n    FROM\n        OrleansMembershipVersionTable v\n        -- This ensures the version table will returned even if there is no matching membership row.\n        LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId\n        AND Address = @Address AND @Address IS NOT NULL\n        AND Port = @Port AND @Port IS NOT NULL\n        AND Generation = @Generation AND @Generation IS NOT NULL\n    WHERE\n        v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadAllKey','\n    SELECT\n        v.DeploymentId,\n        m.Address,\n        m.Port,\n        m.Generation,\n        m.SiloName,\n        m.HostName,\n        m.Status,\n        m.ProxyPort,\n        m.SuspectTimes,\n        m.StartTime,\n        m.IAmAliveTime,\n        v.Version\n    FROM\n        OrleansMembershipVersionTable v LEFT OUTER JOIN OrleansMembershipTable m\n        ON v.DeploymentId = m.DeploymentId\n    WHERE\n        v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteMembershipTableEntriesKey','\n    DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n    DELETE FROM OrleansMembershipVersionTable\n    WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Options/AdoNetClusteringClientOptions.cs",
    "content": "﻿namespace Orleans.Configuration\n{\n    public class AdoNetClusteringClientOptions\n    {\n        /// <summary>\n        /// Connection string for Sql\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// The invariant name of the connector for gatewayProvider's database.\n        /// </summary>\n        public string Invariant { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Options/AdoNetClusteringClientOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Validates <see cref=\"AdoNetClusteringClientOptions\"/> configuration.\n    /// </summary>\n    public class AdoNetClusteringClientOptionsValidator : IConfigurationValidator\n    {\n        private readonly AdoNetClusteringClientOptions options;\n\n        public AdoNetClusteringClientOptionsValidator(IOptions<AdoNetClusteringClientOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.Invariant))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetClusteringClientOptions)} values for {nameof(AdoNetClusteringTable)}. {nameof(options.Invariant)} is required.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ConnectionString))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetClusteringClientOptions)} values for {nameof(AdoNetClusteringTable)}. {nameof(options.ConnectionString)} is required.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Options/AdoNetClusteringSiloOptions.cs",
    "content": "﻿namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for ADO.NET clustering\n    /// </summary>\n    public class AdoNetClusteringSiloOptions\n    {\n        /// <summary>\n        /// Connection string for AdoNet Storage\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// The invariant name of the connector for membership's database.\n        /// </summary>\n        public string Invariant { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Options/AdoNetReminderTableOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Validates <see cref=\"AdoNetClusteringSiloOptions\"/> configuration.\n    /// </summary>\n    public class AdoNetClusteringSiloOptionsValidator : IConfigurationValidator\n    {\n        private readonly AdoNetClusteringSiloOptions options;\n\n        public AdoNetClusteringSiloOptionsValidator(IOptions<AdoNetClusteringSiloOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.Invariant))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetClusteringSiloOptions)} values for {nameof(AdoNetClusteringTable)}. {nameof(options.Invariant)} is required.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ConnectionString))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetClusteringSiloOptions)} values for {nameof(AdoNetClusteringTable)}. {nameof(options.ConnectionString)} is required.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Oracle-Clustering.sql",
    "content": "-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically.\nCREATE TABLE \"ORLEANSMEMBERSHIPVERSIONTABLE\"\n(\n    \"DEPLOYMENTID\" NVARCHAR2(150) NOT NULL ENABLE,\n    \"TIMESTAMP\" TIMESTAMP (6) DEFAULT sys_extract_utc(systimestamp) NOT NULL ENABLE,\n    \"VERSION\" NUMBER(*,0) DEFAULT 0,\n\n    CONSTRAINT \"ORLEANSMEMBERSHIPVERSIONTA_PK\" PRIMARY KEY (\"DEPLOYMENTID\")\n);\n/\n\n-- Every silo instance has a row in the membership table.\nCREATE TABLE \"ORLEANSMEMBERSHIPTABLE\"\n(\n    \"DEPLOYMENTID\" NVARCHAR2(150) NOT NULL ENABLE,\n    \"ADDRESS\" VARCHAR2(45 BYTE) NOT NULL ENABLE,\n    \"PORT\" NUMBER(*,0) NOT NULL ENABLE,\n    \"GENERATION\" NUMBER(*,0) NOT NULL ENABLE,\n    \"SILONAME\" NVARCHAR2(150) NOT NULL ENABLE,\n    \"HOSTNAME\" NVARCHAR2(150) NOT NULL ENABLE,\n    \"STATUS\" NUMBER(*,0) NOT NULL ENABLE,\n    \"PROXYPORT\" NUMBER(*,0),\n    \"SUSPECTTIMES\" VARCHAR2(4000 BYTE),\n    \"STARTTIME\" TIMESTAMP (6) NOT NULL ENABLE,\n    \"IAMALIVETIME\" TIMESTAMP (6) NOT NULL ENABLE,\n\n    CONSTRAINT \"ORLEANSMEMBERSHIPTABLE_PK\" PRIMARY KEY (\"DEPLOYMENTID\", \"ADDRESS\", \"PORT\", \"GENERATION\"),\n    CONSTRAINT \"ORLEANSMEMBERSHIPTABLE_FK1\" FOREIGN KEY (\"DEPLOYMENTID\")\n\t  REFERENCES \"ORLEANSMEMBERSHIPVERSIONTABLE\" (\"DEPLOYMENTID\") ENABLE\n);\n/\n\nCREATE OR REPLACE FUNCTION InsertMembership(PARAM_DEPLOYMENTID IN NVARCHAR2, PARAM_IAMALIVETIME IN TIMESTAMP, PARAM_SILONAME IN NVARCHAR2, PARAM_HOSTNAME IN NVARCHAR2, PARAM_ADDRESS IN VARCHAR2,\n                                    PARAM_PORT IN NUMBER, PARAM_GENERATION IN NUMBER, PARAM_STARTTIME IN TIMESTAMP, PARAM_STATUS IN NUMBER, PARAM_PROXYPORT IN NUMBER, PARAM_VERSION IN NUMBER)\n  RETURN NUMBER IS\n  rowcount NUMBER;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    INSERT INTO OrleansMembershipTable\n    (\n      DeploymentId,\n      Address,\n      Port,\n      Generation,\n      SiloName,\n      HostName,\n      Status,\n      ProxyPort,\n      StartTime,\n      IAmAliveTime\n    )\n    SELECT\n      PARAM_DEPLOYMENTID,\n      PARAM_ADDRESS,\n      PARAM_PORT,\n      PARAM_GENERATION,\n      PARAM_SILONAME,\n      PARAM_HOSTNAME,\n      PARAM_STATUS,\n      PARAM_PROXYPORT,\n      PARAM_STARTTIME,\n      PARAM_IAMALIVETIME\n    FROM DUAL WHERE NOT EXISTS\n    (\n      SELECT 1 FROM OrleansMembershipTable WHERE\n        DeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n        AND Address = PARAM_ADDRESS AND PARAM_ADDRESS IS NOT NULL\n        AND Port = PARAM_PORT AND PARAM_PORT IS NOT NULL\n        AND Generation = PARAM_GENERATION AND PARAM_GENERATION IS NOT NULL\n    );\n    rowcount :=\tSQL%ROWCOUNT;\n    UPDATE OrleansMembershipVersionTable\n    SET Timestamp = sys_extract_utc(systimestamp),\n        Version = Version + 1\n    WHERE\n  \t\tDeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n    \tAND Version = PARAM_VERSION AND PARAM_VERSION IS NOT NULL\n      AND rowcount > 0;\n    rowcount :=\tSQL%ROWCOUNT;\n    IF rowcount = 0 THEN\n      ROLLBACK;\n    ELSE\n      COMMIT;\n    END IF;\n\n    IF rowcount > 0 THEN\n      RETURN(1);\n    ELSE\n      RETURN(0);\n    END IF;\n  END;\n/\n\nCREATE OR REPLACE FUNCTION UpdateMembership(PARAM_DEPLOYMENTID IN NVARCHAR2, PARAM_ADDRESS IN VARCHAR2, PARAM_PORT IN NUMBER, PARAM_GENERATION IN NUMBER,\n                                               PARAM_IAMALIVETIME IN TIMESTAMP, PARAM_STATUS IN NUMBER, PARAM_SUSPECTTIMES IN VARCHAR2, PARAM_VERSION IN NUMBER\n                                              )\n  RETURN NUMBER IS\n  rowcount NUMBER;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    UPDATE OrleansMembershipVersionTable\n      SET\n        Timestamp = sys_extract_utc(systimestamp),\n        Version = Version + 1\n    WHERE\n\t\tDeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n\t\tAND Version = PARAM_VERSION AND PARAM_VERSION IS NOT NULL;\n    rowcount := SQL%ROWCOUNT;\n    UPDATE OrleansMembershipTable\n      SET\n        Status = PARAM_STATUS,\n        SuspectTimes = PARAM_SUSPECTTIMES,\n        IAmAliveTime = PARAM_IAMALIVETIME\n      WHERE DeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n        AND Address = PARAM_ADDRESS AND PARAM_ADDRESS IS NOT NULL\n        AND Port = PARAM_PORT AND PARAM_PORT IS NOT NULL\n        AND Generation = PARAM_GENERATION AND PARAM_GENERATION IS NOT NULL\n        AND rowcount > 0;\n    rowcount := SQL%ROWCOUNT;\n    COMMIT;\n    RETURN(rowcount);\n  END;\n/\n\nCREATE OR REPLACE FUNCTION InsertMembershipVersion(PARAM_DEPLOYMENTID IN NVARCHAR2)\nRETURN NUMBER IS\nrowcount NUMBER;\nPRAGMA AUTONOMOUS_TRANSACTION;\nBEGIN\n  INSERT INTO OrleansMembershipVersionTable\n      (\n        DeploymentId\n      )\n      SELECT PARAM_DEPLOYMENTID FROM DUAL WHERE NOT EXISTS\n      (\n        SELECT 1 FROM OrleansMembershipVersionTable WHERE\n        DeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n      );\n      rowCount := SQL%ROWCOUNT;\n\n      COMMIT;\n      RETURN(rowCount);\nEND;\n/\n\nCREATE OR REPLACE FUNCTION UpdateIAmAlivetime(PARAM_DEPLOYMENTID IN NVARCHAR2, PARAM_ADDRESS in VARCHAR2, PARAM_PORT IN NUMBER,\n                                                 PARAM_GENERATION IN NUMBER, PARAM_IAMALIVE IN TIMESTAMP)\nRETURN NUMBER IS\nrowcount NUMBER;\nPRAGMA AUTONOMOUS_TRANSACTION;\nBEGIN\n    UPDATE OrleansMembershipTable\n        SET\n            IAmAliveTime = PARAM_IAMALIVE\n        WHERE\n            DeploymentId = PARAM_DEPLOYMENTID AND PARAM_DEPLOYMENTID IS NOT NULL\n            AND Address = PARAM_ADDRESS AND PARAM_ADDRESS IS NOT NULL\n            AND Port = PARAM_PORT AND PARAM_PORT IS NOT NULL\n            AND Generation = PARAM_GENERATION AND PARAM_GENERATION IS NOT NULL;\n      COMMIT;\n      RETURN(0);\nEND;\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateIAmAlivetimeKey','\n    SELECT UpdateIAmAlivetime(:DeploymentId, :Address, :Port, :Generation, :IAmAliveTime) AS RESULT FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipVersionKey','\n    SELECT InsertMembershipVersion(:DeploymentId) AS RESULT FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipKey','\n    SELECT INSERTMEMBERSHIP(:DeploymentId,:IAmAliveTime,:SiloName,:Hostname,:Address,:Port,:Generation,:StartTime,:Status,:ProxyPort,:Version) FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateMembershipKey','\n    SELECT UpdateMembership(:DeploymentId, :Address, :Port, :Generation, :IAmAliveTime, :Status, :SuspectTimes, :Version) AS RESULT FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadRowKey','\n    SELECT v.DeploymentId, m.Address, m.Port, m.Generation, m.SiloName, m.HostName,\n       m.Status, m.ProxyPort, m.SuspectTimes, m.StartTime, m.IAmAliveTime, v.Version\n    FROM\n        OrleansMembershipVersionTable v\n        LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId\n        AND Address = :Address AND :Address IS NOT NULL\n        AND Port = :Port AND :Port IS NOT NULL\n        AND Generation = :Generation AND :Generation IS NOT NULL\n    WHERE\n        v.DeploymentId = :DeploymentId AND :DeploymentId IS NOT NULL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadAllKey','\n    SELECT v.DeploymentId, m.Address, m.Port, m.Generation, m.SiloName, m.HostName, m.Status,\n       m.ProxyPort, m.SuspectTimes, m.StartTime, m.IAmAliveTime, v.Version\n    FROM\n        OrleansMembershipVersionTable v\n        LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId\n    WHERE\n        v.DeploymentId = :DeploymentId AND :DeploymentId IS NOT NULL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteMembershipTableEntriesKey','\n  BEGIN\n    DELETE FROM OrleansMembershipTable\n      WHERE DeploymentId = :DeploymentId AND :DeploymentId IS NOT NULL;\n    DELETE FROM OrleansMembershipVersionTable\n      WHERE DeploymentId = :DeploymentId AND :DeploymentId IS NOT NULL;\n  END;\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'GatewaysQueryKey','\n    SELECT Address, ProxyPort, Generation\n    FROM OrleansMembershipTable\n    WHERE DeploymentId = :DeploymentId AND :DeploymentId IS NOT NULL\n      AND Status = :Status AND :Status IS NOT NULL\n      AND ProxyPort > 0\n');\n/\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/Orleans.Clustering.AdoNet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.AdoNet</PackageId>\n    <Title>Microsoft Orleans ADO.NET Clustering Provider</Title>\n    <Description>Microsoft Orleans clustering provider backed by ADO.NET</Description>\n    <PackageTags>$(PackageTags) ADO.NET SQL MySQL PostgreSQL Oracle</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Clustering.AdoNet</AssemblyName>\n    <RootNamespace>Orleans.Clustering.AdoNet</RootNamespace>\n    <DefineConstants>$(DefineConstants);CLUSTERING_ADONET</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/PostgreSQL-Clustering.sql",
    "content": "-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically.\nCREATE TABLE OrleansMembershipVersionTable\n(\n    DeploymentId varchar(150) NOT NULL,\n    Timestamp timestamptz(3) NOT NULL DEFAULT now(),\n    Version integer NOT NULL DEFAULT 0,\n\n    CONSTRAINT PK_OrleansMembershipVersionTable_DeploymentId PRIMARY KEY(DeploymentId)\n);\n\n-- Every silo instance has a row in the membership table.\nCREATE TABLE OrleansMembershipTable\n(\n    DeploymentId varchar(150) NOT NULL,\n    Address varchar(45) NOT NULL,\n    Port integer NOT NULL,\n    Generation integer NOT NULL,\n    SiloName varchar(150) NOT NULL,\n    HostName varchar(150) NOT NULL,\n    Status integer NOT NULL,\n    ProxyPort integer NULL,\n    SuspectTimes varchar(8000) NULL,\n    StartTime timestamptz(3) NOT NULL,\n    IAmAliveTime timestamptz(3) NOT NULL,\n\n    CONSTRAINT PK_MembershipTable_DeploymentId PRIMARY KEY(DeploymentId, Address, Port, Generation),\n    CONSTRAINT FK_MembershipTable_MembershipVersionTable_DeploymentId FOREIGN KEY (DeploymentId) REFERENCES OrleansMembershipVersionTable (DeploymentId)\n);\n\nCREATE FUNCTION update_i_am_alive_time(\n    deployment_id OrleansMembershipTable.DeploymentId%TYPE,\n    address_arg OrleansMembershipTable.Address%TYPE,\n    port_arg OrleansMembershipTable.Port%TYPE,\n    generation_arg OrleansMembershipTable.Generation%TYPE,\n    i_am_alive_time OrleansMembershipTable.IAmAliveTime%TYPE)\n  RETURNS void AS\n$func$\nBEGIN\n    -- This is expected to never fail by Orleans, so return value\n    -- is not needed nor is it checked.\n    UPDATE OrleansMembershipTable as d\n    SET\n        IAmAliveTime = i_am_alive_time\n    WHERE\n        d.DeploymentId = deployment_id AND deployment_id IS NOT NULL\n        AND d.Address = address_arg AND address_arg IS NOT NULL\n        AND d.Port = port_arg AND port_arg IS NOT NULL\n        AND d.Generation = generation_arg AND generation_arg IS NOT NULL;\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateIAmAlivetimeKey','\n    -- This is expected to never fail by Orleans, so return value\n    -- is not needed nor is it checked.\n    SELECT * from update_i_am_alive_time(\n        @DeploymentId,\n        @Address,\n        @Port,\n        @Generation,\n        @IAmAliveTime\n    );\n');\n\nCREATE FUNCTION insert_membership_version(\n    DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE\n)\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n    BEGIN\n\n        INSERT INTO OrleansMembershipVersionTable\n        (\n            DeploymentId\n        )\n        SELECT DeploymentIdArg\n        ON CONFLICT (DeploymentId) DO NOTHING;\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        ASSERT RowCountVar <> 0, 'no rows affected, rollback';\n\n        RETURN QUERY SELECT RowCountVar;\n    EXCEPTION\n    WHEN assert_failure THEN\n        RETURN QUERY SELECT RowCountVar;\n    END;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipVersionKey','\n    SELECT * FROM insert_membership_version(\n        @DeploymentId\n    );\n');\n\nCREATE FUNCTION insert_membership(\n    DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,\n    AddressArg      OrleansMembershipTable.Address%TYPE,\n    PortArg         OrleansMembershipTable.Port%TYPE,\n    GenerationArg   OrleansMembershipTable.Generation%TYPE,\n    SiloNameArg     OrleansMembershipTable.SiloName%TYPE,\n    HostNameArg     OrleansMembershipTable.HostName%TYPE,\n    StatusArg       OrleansMembershipTable.Status%TYPE,\n    ProxyPortArg    OrleansMembershipTable.ProxyPort%TYPE,\n    StartTimeArg    OrleansMembershipTable.StartTime%TYPE,\n    IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,\n    VersionArg      OrleansMembershipVersionTable.Version%TYPE)\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n    BEGIN\n        INSERT INTO OrleansMembershipTable\n        (\n            DeploymentId,\n            Address,\n            Port,\n            Generation,\n            SiloName,\n            HostName,\n            Status,\n            ProxyPort,\n            StartTime,\n            IAmAliveTime\n        )\n        SELECT\n            DeploymentIdArg,\n            AddressArg,\n            PortArg,\n            GenerationArg,\n            SiloNameArg,\n            HostNameArg,\n            StatusArg,\n            ProxyPortArg,\n            StartTimeArg,\n            IAmAliveTimeArg\n        ON CONFLICT (DeploymentId, Address, Port, Generation) DO\n            NOTHING;\n\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        UPDATE OrleansMembershipVersionTable\n        SET\n            Timestamp = now(),\n            Version = Version + 1\n        WHERE\n            DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n            AND Version = VersionArg AND VersionArg IS NOT NULL\n            AND RowCountVar > 0;\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        ASSERT RowCountVar <> 0, 'no rows affected, rollback';\n\n\n        RETURN QUERY SELECT RowCountVar;\n    EXCEPTION\n    WHEN assert_failure THEN\n        RETURN QUERY SELECT RowCountVar;\n    END;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'InsertMembershipKey','\n    SELECT * FROM insert_membership(\n        @DeploymentId,\n        @Address,\n        @Port,\n        @Generation,\n        @SiloName,\n        @HostName,\n        @Status,\n        @ProxyPort,\n        @StartTime,\n        @IAmAliveTime,\n        @Version\n    );\n');\n\nCREATE FUNCTION update_membership(\n    DeploymentIdArg OrleansMembershipTable.DeploymentId%TYPE,\n    AddressArg      OrleansMembershipTable.Address%TYPE,\n    PortArg         OrleansMembershipTable.Port%TYPE,\n    GenerationArg   OrleansMembershipTable.Generation%TYPE,\n    StatusArg       OrleansMembershipTable.Status%TYPE,\n    SuspectTimesArg OrleansMembershipTable.SuspectTimes%TYPE,\n    IAmAliveTimeArg OrleansMembershipTable.IAmAliveTime%TYPE,\n    VersionArg      OrleansMembershipVersionTable.Version%TYPE\n  )\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n    BEGIN\n\n    UPDATE OrleansMembershipVersionTable\n    SET\n        Timestamp = now(),\n        Version = Version + 1\n    WHERE\n        DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n        AND Version = VersionArg AND VersionArg IS NOT NULL;\n\n\n    GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n    UPDATE OrleansMembershipTable\n    SET\n        Status = StatusArg,\n        SuspectTimes = SuspectTimesArg,\n        IAmAliveTime = IAmAliveTimeArg\n    WHERE\n        DeploymentId = DeploymentIdArg AND DeploymentIdArg IS NOT NULL\n        AND Address = AddressArg AND AddressArg IS NOT NULL\n        AND Port = PortArg AND PortArg IS NOT NULL\n        AND Generation = GenerationArg AND GenerationArg IS NOT NULL\n        AND RowCountVar > 0;\n\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n        ASSERT RowCountVar <> 0, 'no rows affected, rollback';\n\n\n        RETURN QUERY SELECT RowCountVar;\n    EXCEPTION\n    WHEN assert_failure THEN\n        RETURN QUERY SELECT RowCountVar;\n    END;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpdateMembershipKey','\n    SELECT * FROM update_membership(\n        @DeploymentId,\n        @Address,\n        @Port,\n        @Generation,\n        @Status,\n        @SuspectTimes,\n        @IAmAliveTime,\n        @Version\n    );\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadRowKey','\n    SELECT\n        v.DeploymentId,\n        m.Address,\n        m.Port,\n        m.Generation,\n        m.SiloName,\n        m.HostName,\n        m.Status,\n        m.ProxyPort,\n        m.SuspectTimes,\n        m.StartTime,\n        m.IAmAliveTime,\n        v.Version\n    FROM\n        OrleansMembershipVersionTable v\n        -- This ensures the version table will returned even if there is no matching membership row.\n        LEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId\n        AND Address = @Address AND @Address IS NOT NULL\n        AND Port = @Port AND @Port IS NOT NULL\n        AND Generation = @Generation AND @Generation IS NOT NULL\n    WHERE\n        v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'MembershipReadAllKey','\n    SELECT\n        v.DeploymentId,\n        m.Address,\n        m.Port,\n        m.Generation,\n        m.SiloName,\n        m.HostName,\n        m.Status,\n        m.ProxyPort,\n        m.SuspectTimes,\n        m.StartTime,\n        m.IAmAliveTime,\n        v.Version\n    FROM\n        OrleansMembershipVersionTable v LEFT OUTER JOIN OrleansMembershipTable m\n        ON v.DeploymentId = m.DeploymentId\n    WHERE\n        v.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteMembershipTableEntriesKey','\n    DELETE FROM OrleansMembershipTable\n    WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n    DELETE FROM OrleansMembershipVersionTable\n    WHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'GatewaysQueryKey','\n    SELECT\n        Address,\n        ProxyPort,\n        Generation\n    FROM\n        OrleansMembershipTable\n    WHERE\n        DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n        AND Status = @Status AND @Status IS NOT NULL\n        AND ProxyPort > 0;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/README.md",
    "content": "# Microsoft Orleans Clustering Provider for ADO.NET\n\n## Introduction\nMicrosoft Orleans Clustering Provider for ADO.NET allows Orleans silos to organize themselves as a cluster using relational databases through ADO.NET. This provider enables silos to discover each other, maintain cluster membership, and detect and handle failures.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Clustering.AdoNet\n```\n\nYou will also need to install the appropriate database driver package for your database system:\n\n- SQL Server: `Microsoft.Data.SqlClient`\n- MySQL: `MySql.Data` or `MySqlConnector`\n- PostgreSQL: `Npgsql`\n- Oracle: `Oracle.ManagedDataAccess.Core`\n- SQLite: `Microsoft.Data.Sqlite`\n\n## Example - Configuring ADO.NET Clustering\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\n// Implement the grain interface\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"Hello, {greeting}!\");\n    }\n}\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            // Configure ADO.NET for clustering\n            .UseAdoNetClustering(options =>\n            {\n                options.Invariant = \"System.Data.SqlClient\";  // Or other providers like \"MySql.Data.MySqlClient\", \"Npgsql\", etc.\n                options.ConnectionString = \"Server=localhost;Database=OrleansCluster;User Id=myUsername;******;\";\n            });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"World\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Configuring Client to Connect to Cluster\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\nvar clientBuilder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(clientBuilder =>\n    {\n        clientBuilder\n            // Configure the client to use ADO.NET for clustering\n            .UseAdoNetClustering(options =>\n            {\n                options.Invariant = \"Microsoft.Data.SqlClient\";  // Or other providers like \"MySql.Data.MySqlClient\", \"Npgsql\", etc.\n                options.ConnectionString = \"Server=localhost;Database=OrleansCluster;User Id=myUsername;******;\";\n            });\n    });\n\nvar host = clientBuilder.Build();\nawait host.StartAsync();\nvar client = host.Services.GetRequiredService<IClusterClient>();\n\n// Get a reference to a grain and call it\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"World\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Database Setup\n\nBefore using the ADO.NET clustering provider, you need to set up the necessary database tables. Scripts for different database systems are available in the Orleans source repository:\nnamespace ExampleGrains;\n\n- [SQL Server Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Clustering.AdoNet/SQLServer-Clustering.sql)\n- [MySQL Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Clustering.AdoNet/MySQL-Clustering.sql)\n- [PostgreSQL Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Clustering.AdoNet/PostgreSQL-Clustering.sql)\n- [Oracle Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Clustering.AdoNet/Oracle-Clustering.sql)\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Clustering providers](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n- [Relational Database Provider](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/relational-storage-providers)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/AdoNet/Orleans.Clustering.AdoNet/SQLServer-Clustering.sql",
    "content": "-- For each deployment, there will be only one (active) membership version table version column which will be updated periodically.\nIF OBJECT_ID(N'[OrleansMembershipVersionTable]', 'U') IS NULL\nCREATE TABLE OrleansMembershipVersionTable\n(\n\tDeploymentId NVARCHAR(150) NOT NULL,\n\tTimestamp DATETIME2(3) NOT NULL DEFAULT GETUTCDATE(),\n\tVersion INT NOT NULL DEFAULT 0,\n\n\tCONSTRAINT PK_OrleansMembershipVersionTable_DeploymentId PRIMARY KEY(DeploymentId)\n);\n\n-- Every silo instance has a row in the membership table.\nIF OBJECT_ID(N'[OrleansMembershipTable]', 'U') IS NULL\nCREATE TABLE OrleansMembershipTable\n(\n\tDeploymentId NVARCHAR(150) NOT NULL,\n\tAddress VARCHAR(45) NOT NULL,\n\tPort INT NOT NULL,\n\tGeneration INT NOT NULL,\n\tSiloName NVARCHAR(150) NOT NULL,\n\tHostName NVARCHAR(150) NOT NULL,\n\tStatus INT NOT NULL,\n\tProxyPort INT NULL,\n\tSuspectTimes VARCHAR(8000) NULL,\n\tStartTime DATETIME2(3) NOT NULL,\n\tIAmAliveTime DATETIME2(3) NOT NULL,\n\n\tCONSTRAINT PK_MembershipTable_DeploymentId PRIMARY KEY(DeploymentId, Address, Port, Generation),\n\tCONSTRAINT FK_MembershipTable_MembershipVersionTable_DeploymentId FOREIGN KEY (DeploymentId) REFERENCES OrleansMembershipVersionTable (DeploymentId)\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'UpdateIAmAlivetimeKey',\n\t'-- This is expected to never fail by Orleans, so return value\n\t-- is not needed nor is it checked.\n\tSET NOCOUNT ON;\n\tUPDATE OrleansMembershipTable\n\tSET\n\t\tIAmAliveTime = @IAmAliveTime\n\tWHERE\n\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\tAND Address = @Address AND @Address IS NOT NULL\n\t\tAND Port = @Port AND @Port IS NOT NULL\n\t\tAND Generation = @Generation AND @Generation IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'UpdateIAmAlivetimeKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT \n\t'InsertMembershipVersionKey',\n\t'SET NOCOUNT ON;\n\tINSERT INTO OrleansMembershipVersionTable\n\t(\n\t\tDeploymentId\n\t)\n\tSELECT @DeploymentId\n\tWHERE NOT EXISTS\n\t(\n\t\tSELECT 1\n\t\tFROM\n\t\t\tOrleansMembershipVersionTable WITH(HOLDLOCK, XLOCK, ROWLOCK)\n\t\tWHERE\n\t\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t);\n\t\n\tSELECT @@ROWCOUNT;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'InsertMembershipVersionKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'InsertMembershipKey',\n\t'SET XACT_ABORT, NOCOUNT ON;\n\tDECLARE @ROWCOUNT AS INT;\n\tBEGIN TRANSACTION;\n\tINSERT INTO OrleansMembershipTable\n\t(\n\t\tDeploymentId,\n\t\tAddress,\n\t\tPort,\n\t\tGeneration,\n\t\tSiloName,\n\t\tHostName,\n\t\tStatus,\n\t\tProxyPort,\n\t\tStartTime,\n\t\tIAmAliveTime\n\t)\n\tSELECT\n\t\t@DeploymentId,\n\t\t@Address,\n\t\t@Port,\n\t\t@Generation,\n\t\t@SiloName,\n\t\t@HostName,\n\t\t@Status,\n\t\t@ProxyPort,\n\t\t@StartTime,\n\t\t@IAmAliveTime\n\tWHERE NOT EXISTS\n\t(\n\t\tSELECT 1\n\t\tFROM\n\t\t\tOrleansMembershipTable WITH(HOLDLOCK, XLOCK, ROWLOCK)\n\t\tWHERE\n\t\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\t\tAND Address = @Address AND @Address IS NOT NULL\n\t\t\tAND Port = @Port AND @Port IS NOT NULL\n\t\t\tAND Generation = @Generation AND @Generation IS NOT NULL\n\t);\n\n\tUPDATE OrleansMembershipVersionTable\n\tSET\n\t\tTimestamp = GETUTCDATE(),\n\t\tVersion = Version + 1\n\tWHERE\n\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\tAND Version = @Version AND @Version IS NOT NULL\n\t\tAND @@ROWCOUNT > 0;\n\t\n\tSET @ROWCOUNT = @@ROWCOUNT;\n\t\n\tIF @ROWCOUNT = 0\n\t\tROLLBACK TRANSACTION\n\tELSE\n\t\tCOMMIT TRANSACTION\n\tSELECT @ROWCOUNT;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'InsertMembershipKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'UpdateMembershipKey',\n\t'SET XACT_ABORT, NOCOUNT ON;\n\tBEGIN TRANSACTION;\n\t\n\tUPDATE OrleansMembershipVersionTable\n\tSET\n\t\tTimestamp = GETUTCDATE(),\n\t\tVersion = Version + 1\n\tWHERE\n\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\tAND Version = @Version AND @Version IS NOT NULL;\n\t\n\tUPDATE OrleansMembershipTable\n\tSET\n\t\tStatus = @Status,\n\t\tSuspectTimes = @SuspectTimes,\n\t\tIAmAliveTime = @IAmAliveTime\n\tWHERE\n\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\tAND Address = @Address AND @Address IS NOT NULL\n\t\tAND Port = @Port AND @Port IS NOT NULL\n\t\tAND Generation = @Generation AND @Generation IS NOT NULL\n\t\tAND @@ROWCOUNT > 0;\n\t\n\tSELECT @@ROWCOUNT;\n\tCOMMIT TRANSACTION;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'UpdateMembershipKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'GatewaysQueryKey',\n\t'SELECT\n\t\tAddress,\n\t\tProxyPort,\n\t\tGeneration\n\tFROM\n\t\tOrleansMembershipTable\n\tWHERE\n\t\tDeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL\n\t\tAND Status = @Status AND @Status IS NOT NULL\n\t\tAND ProxyPort > 0;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'GatewaysQueryKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'MembershipReadRowKey',\n\t'SELECT\n\t\tv.DeploymentId,\n\t\tm.Address,\n\t\tm.Port,\n\t\tm.Generation,\n\t\tm.SiloName,\n\t\tm.HostName,\n\t\tm.Status,\n\t\tm.ProxyPort,\n\t\tm.SuspectTimes,\n\t\tm.StartTime,\n\t\tm.IAmAliveTime,\n\t\tv.Version\n\tFROM\n\t\tOrleansMembershipVersionTable v\n\t\t-- This ensures the version table will returned even if there is no matching membership row.\n\t\tLEFT OUTER JOIN OrleansMembershipTable m ON v.DeploymentId = m.DeploymentId\n\t\tAND Address = @Address AND @Address IS NOT NULL\n\t\tAND Port = @Port AND @Port IS NOT NULL\n\t\tAND Generation = @Generation AND @Generation IS NOT NULL\n\tWHERE\n\t\tv.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'MembershipReadRowKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'MembershipReadAllKey',\n\t'SELECT\n\t\tv.DeploymentId,\n\t\tm.Address,\n\t\tm.Port,\n\t\tm.Generation,\n\t\tm.SiloName,\n\t\tm.HostName,\n\t\tm.Status,\n\t\tm.ProxyPort,\n\t\tm.SuspectTimes,\n\t\tm.StartTime,\n\t\tm.IAmAliveTime,\n\t\tv.Version\n\tFROM\n\t\tOrleansMembershipVersionTable v LEFT OUTER JOIN OrleansMembershipTable m\n\t\tON v.DeploymentId = m.DeploymentId\n\tWHERE\n\t\tv.DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'MembershipReadAllKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'DeleteMembershipTableEntriesKey',\n\t'DELETE FROM OrleansMembershipTable\n\tWHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n\tDELETE FROM OrleansMembershipVersionTable\n\tWHERE DeploymentId = @DeploymentId AND @DeploymentId IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'DeleteMembershipTableEntriesKey'\n);\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/AdoNetGrainDirectory.cs",
    "content": "namespace Orleans.GrainDirectory.AdoNet;\n\ninternal sealed partial class AdoNetGrainDirectory(string name, AdoNetGrainDirectoryOptions options, ILogger<AdoNetGrainDirectory> logger, IOptions<ClusterOptions> clusterOptions, IHostApplicationLifetime lifetime) : IGrainDirectory\n{\n    private readonly ILogger _logger = logger;\n    private readonly string _clusterId = clusterOptions.Value.ClusterId;\n    private RelationalOrleansQueries? _queries;\n\n    /// <summary>\n    /// Looks up a grain activation.\n    /// </summary>\n    /// <param name=\"grainId\">The grain identifier.</param>\n    /// <returns>The grain address if found or null if not found.</returns>\n    public async Task<GrainAddress?> Lookup(GrainId grainId)\n    {\n        try\n        {\n            var queries = await GetQueriesAsync();\n\n            var entry = await queries\n                .LookupGrainActivationAsync(_clusterId, name, grainId.ToString())\n                .WaitAsync(lifetime.ApplicationStopping);\n\n            return entry?.ToGrainAddress();\n        }\n        catch (Exception ex)\n        {\n            LogFailedToLookup(ex, _clusterId, grainId);\n            throw;\n        }\n    }\n\n    /// <summary>\n    /// Registers a new grain activation.\n    /// </summary>\n    /// <param name=\"address\">The grain address.</param>\n    /// <returns>The new or current grain address.</returns>\n    public async Task<GrainAddress?> Register(GrainAddress address)\n    {\n        ArgumentNullException.ThrowIfNull(address);\n        ArgumentNullException.ThrowIfNull(address.SiloAddress);\n\n        try\n        {\n            var queries = await GetQueriesAsync();\n\n            // this call is expected to register a new entry or return the existing one if found in a thread safe manner\n            var entry = await queries\n                .RegisterGrainActivationAsync(_clusterId, name, address.GrainId.ToString(), address.SiloAddress.ToParsableString(), address.ActivationId.ToParsableString())\n                .WaitAsync(lifetime.ApplicationStopping);\n\n            LogRegistered(_clusterId, address.GrainId, address.SiloAddress, address.ActivationId);\n\n            return entry.ToGrainAddress();\n        }\n        catch (Exception ex)\n        {\n            LogFailedToRegister(ex, _clusterId, address.GrainId, address.SiloAddress, address.ActivationId);\n            throw;\n        }\n    }\n\n    /// <summary>\n    /// Unregister an existing grain activation.\n    /// </summary>\n    /// <param name=\"address\">The grain address.</param>\n    public async Task Unregister(GrainAddress address)\n    {\n        ArgumentNullException.ThrowIfNull(address);\n        ArgumentNullException.ThrowIfNull(address.SiloAddress);\n\n        try\n        {\n            var queries = await GetQueriesAsync();\n\n            var count = await queries\n                .UnregisterGrainActivationAsync(_clusterId, name, address.GrainId.ToString(), address.ActivationId.ToParsableString())\n                .WaitAsync(lifetime.ApplicationStopping);\n\n            if (count > 0)\n            {\n                LogUnregistered(_clusterId, address.GrainId, address.SiloAddress, address.ActivationId);\n            }\n        }\n        catch (Exception ex)\n        {\n            LogFailedToUnregister(ex, _clusterId, address.GrainId, address.SiloAddress, address.ActivationId);\n            throw;\n        }\n    }\n\n    /// <summary>\n    /// Unregisters all grain activations in the specified set of silos.\n    /// </summary>\n    /// <param name=\"siloAddresses\">The set of silos.</param>\n    public async Task UnregisterSilos(List<SiloAddress> siloAddresses)\n    {\n        ArgumentNullException.ThrowIfNull(siloAddresses);\n\n        if (siloAddresses.Count == 0)\n        {\n            return;\n        }\n\n        try\n        {\n            var queries = await GetQueriesAsync();\n\n            var count = await queries\n                .UnregisterGrainActivationsAsync(_clusterId, name, GetSilosAddressesAsString(siloAddresses))\n                .WaitAsync(lifetime.ApplicationStopping);\n\n            if (count > 0)\n            {\n                LogUnregisteredSilos(count, _clusterId, siloAddresses);\n            }\n        }\n        catch (Exception ex)\n        {\n            LogFailedToUnregisterSilos(ex, _clusterId, siloAddresses);\n            throw;\n        }\n\n        static string GetSilosAddressesAsString(IEnumerable<SiloAddress> siloAddresses) => string.Join('|', siloAddresses.Select(x => x.ToParsableString()));\n    }\n\n    /// <summary>\n    /// Unfortunate implementation detail to account for lack of async lifetime.\n    /// Ideally this concern will be moved upstream so this won't be needed.\n    /// </summary>\n    private readonly SemaphoreSlim _semaphore = new(1);\n\n    /// <summary>\n    /// Ensures queries are loaded only once while allowing for recovery if the load fails.\n    /// </summary>\n    private ValueTask<RelationalOrleansQueries> GetQueriesAsync()\n    {\n        // attempt fast path\n        return _queries is not null ? new(_queries) : new(CoreAsync());\n\n        // slow path\n        async Task<RelationalOrleansQueries> CoreAsync()\n        {\n            await _semaphore.WaitAsync(lifetime.ApplicationStopping);\n            try\n            {\n                // attempt fast path again\n                if (_queries is not null)\n                {\n                    return _queries;\n                }\n\n                // slow path - the member variable will only be set if the call succeeds\n                return _queries = await RelationalOrleansQueries\n                    .CreateInstance(options.Invariant, options.ConnectionString)\n                    .WaitAsync(lifetime.ApplicationStopping);\n            }\n            finally\n            {\n                _semaphore.Release();\n            }\n        }\n    }\n\n    #region Logging\n\n    [LoggerMessage(1, LogLevel.Error, \"Failed to lookup({ClusterId}, {GrainId})\")]\n    private partial void LogFailedToLookup(Exception ex, string clusterId, GrainId grainId);\n\n    [LoggerMessage(2, LogLevel.Debug, \"Registered ({ClusterId}, {GrainId}, {SiloAddress}, {ActivationId})\")]\n    private partial void LogRegistered(string clusterId, GrainId grainId, SiloAddress siloAddress, ActivationId activationId);\n\n    [LoggerMessage(3, LogLevel.Error, \"Failed to register ({ClusterId}, {GrainId}, {SiloAddress}, {ActivationId})\")]\n    private partial void LogFailedToRegister(Exception ex, string clusterId, GrainId grainId, SiloAddress siloAddress, ActivationId activationId);\n\n    [LoggerMessage(4, LogLevel.Debug, \"Unregistered ({ClusterId}, {GrainId}, {SiloAddress}, {ActivationId})\")]\n    private partial void LogUnregistered(string clusterId, GrainId grainId, SiloAddress siloAddress, ActivationId activationId);\n\n    [LoggerMessage(5, LogLevel.Error, \"Failed to unregister ({ClusterId}, {GrainId}, {SiloAddress}, {ActivationId})\")]\n    private partial void LogFailedToUnregister(Exception ex, string clusterId, GrainId grainId, SiloAddress siloAddress, ActivationId activationId);\n\n    [LoggerMessage(6, LogLevel.Debug, \"Unregistered {Count} activations from silos {SiloAddresses} in cluster {ClusterId}\")]\n    private partial void LogUnregisteredSilos(int count, string clusterId, IEnumerable<SiloAddress> siloAddresses);\n\n    [LoggerMessage(7, LogLevel.Error, \"Failed to unregister silos {SiloAddresses} in cluster {ClusterId}\")]\n    private partial void LogFailedToUnregisterSilos(Exception ex, string clusterId, IEnumerable<SiloAddress> siloAddresses);\n\n    #endregion Logging\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/AdoNetGrainDirectoryEntry.cs",
    "content": "namespace Orleans.GrainDirectory.AdoNet;\n\n/// <summary>\n/// The model that represents a grain activation in an ADONET grain directory.\n/// </summary>\ninternal sealed record AdoNetGrainDirectoryEntry(\n    string ClusterId,\n    string ProviderId,\n    string GrainId,\n    string SiloAddress,\n    string ActivationId)\n{\n    public AdoNetGrainDirectoryEntry() : this(\"\", \"\", \"\", \"\", \"\")\n    {\n    }\n\n    public GrainAddress ToGrainAddress() => new()\n    {\n        GrainId = Runtime.GrainId.Parse(GrainId, CultureInfo.InvariantCulture),\n        SiloAddress = Runtime.SiloAddress.FromParsableString(SiloAddress),\n        ActivationId = Runtime.ActivationId.FromParsableString(ActivationId)\n    };\n\n    public static AdoNetGrainDirectoryEntry FromGrainAddress(string clusterId, string providerId, GrainAddress address)\n    {\n        ArgumentNullException.ThrowIfNull(clusterId);\n        ArgumentNullException.ThrowIfNull(address);\n        ArgumentNullException.ThrowIfNull(address.SiloAddress);\n\n        return new AdoNetGrainDirectoryEntry(\n            clusterId,\n            providerId,\n            address.GrainId.ToString(),\n            address.SiloAddress.ToParsableString(),\n            address.ActivationId.ToParsableString());\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/AdoNetGrainDirectoryOptions.cs",
    "content": "namespace Orleans.GrainDirectory.AdoNet;\n\n/// <summary>\n/// Options for the ADO.NET Grain Directory.\n/// </summary>\npublic class AdoNetGrainDirectoryOptions\n{\n    /// <summary>\n    /// Gets or sets the ADO.NET invariant.\n    /// </summary>\n    [Required]\n    public string Invariant { get; set; } = \"\";\n\n    /// <summary>\n    /// Gets or sets the connection string.\n    /// </summary>\n    [Redact]\n    [Required]\n    public string ConnectionString { get; set; } = \"\";\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/GlobalSuppressions.cs",
    "content": "// This file is used by Code Analysis to maintain SuppressMessage\n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given\n// a specific target and scoped to a namespace, type, member, etc.\n\nusing System.Diagnostics.CodeAnalysis;\n\n[assembly: SuppressMessage(\"Style\", \"IDE0130:Namespace does not match folder structure\", Justification = \"N/A\", Scope = \"namespace\", Target = \"~N:Orleans.Configuration\")]\n[assembly: SuppressMessage(\"Style\", \"IDE0130:Namespace does not match folder structure\", Justification = \"N/A\", Scope = \"namespace\", Target = \"~N:Orleans.Hosting\")]\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Hosting/AdoNetGrainDirectoryProviderBuilder.cs",
    "content": "using static System.String;\n\n[assembly: RegisterProvider(\"AdoNet\", \"GrainDirectory\", \"Silo\", typeof(AdoNetGrainDirectoryProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AdoNetGrainDirectoryProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string? name, IConfigurationSection configurationSection)\n    {\n        builder.AddAdoNetGrainDirectory(name ?? \"Default\", optionsBuilder => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n        {\n            var invariant = configurationSection[\"Invariant\"];\n            if (!IsNullOrWhiteSpace(invariant))\n            {\n                options.Invariant = invariant;\n            }\n\n            var connectionString = configurationSection[\"ConnectionString\"];\n            var connectionName = configurationSection[\"ConnectionName\"];\n            if (!IsNullOrWhiteSpace(connectionString))\n            {\n                options.ConnectionString = connectionString;\n            }\n            else if (!IsNullOrWhiteSpace(connectionName))\n            {\n                connectionString = services.GetRequiredService<IConfiguration>().GetConnectionString(connectionName);\n                if (!IsNullOrWhiteSpace(connectionString))\n                {\n                    options.ConnectionString = connectionString;\n                }\n            }\n        }));\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Hosting/AdoNetGrainDirectoryServiceCollectionExtensions.cs",
    "content": "using Orleans.Runtime.Hosting;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// <see cref=\"IServiceCollection\"/> extensions.\n/// </summary>\ninternal static class AdoNetGrainDirectoryServiceCollectionExtensions\n{\n    internal static IServiceCollection AddAdoNetGrainDirectory(\n        this IServiceCollection services,\n        string name,\n        Action<OptionsBuilder<AdoNetGrainDirectoryOptions>> configureOptions)\n    {\n        configureOptions.Invoke(services.AddOptions<AdoNetGrainDirectoryOptions>(name));\n\n        return services\n            .AddTransient<IConfigurationValidator>(sp => new AdoNetGrainDirectoryOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AdoNetGrainDirectoryOptions>>().Get(name), name))\n            .ConfigureNamedOptionForLogging<AdoNetGrainDirectoryOptions>(name)\n            .AddGrainDirectory(name, (sp, name) =>\n            {\n                var options = sp.GetOptionsByName<AdoNetGrainDirectoryOptions>(name);\n\n                return ActivatorUtilities.CreateInstance<AdoNetGrainDirectory>(sp, name, options);\n            });\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Hosting/AdoNetGrainDirectorySiloBuilderExtensions.cs",
    "content": "namespace Orleans.Hosting;\n\npublic static class AdoNetGrainDirectorySiloBuilderExtensions\n{\n    public static ISiloBuilder UseAdoNetGrainDirectoryAsDefault(\n        this ISiloBuilder builder,\n        Action<AdoNetGrainDirectoryOptions> configureOptions) =>\n        builder.UseAdoNetGrainDirectoryAsDefault(ob => ob.Configure(configureOptions));\n\n    public static ISiloBuilder UseAdoNetGrainDirectoryAsDefault(\n        this ISiloBuilder builder,\n        Action<OptionsBuilder<AdoNetGrainDirectoryOptions>> configureOptions) =>\n        builder.ConfigureServices(services => services.AddAdoNetGrainDirectory(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, configureOptions));\n\n    public static ISiloBuilder AddAdoNetGrainDirectory(\n        this ISiloBuilder builder,\n        string name,\n        Action<AdoNetGrainDirectoryOptions> configureOptions) =>\n        builder.AddAdoNetGrainDirectory(name, ob => ob.Configure(configureOptions));\n\n    public static ISiloBuilder AddAdoNetGrainDirectory(\n        this ISiloBuilder builder,\n        string name,\n        Action<OptionsBuilder<AdoNetGrainDirectoryOptions>> configureOptions) =>\n        builder.ConfigureServices(services => services.AddAdoNetGrainDirectory(name, configureOptions));\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/MySQL-GrainDirectory.sql",
    "content": "/*\nOrleans Grain Directory.\nThis table stores the location of all grains in the cluster.\n\nNOTE:\nThe combination of ClusterId, ProviderId, and GrainId forms the primary key for the OrleansGrainDirectory table.\nTogether, these columns reach the maximum allowed key size for MariaDB/MySQL indexes (768 bytes).\nCare should be taken not to increase the length of these columns, as it may exceed MariaDB/MySQL's key size limitation.\n\n*/\nCREATE TABLE OrleansGrainDirectory\n(\n    /* Identifies the cluster instance */\n    ClusterId VARCHAR(150) NOT NULL,\n\n    /* Identifies the grain directory provider */\n    ProviderId VARCHAR(150) NOT NULL,\n\n    /* Holds the grain id in text form */\n    GrainId VARCHAR(468) NOT NULL,\n\n    /* Holds the silo address where the grain is located */\n    SiloAddress VARCHAR(100) NOT NULL,\n\n    /* Holds the activation id in the silo where it is located */\n    ActivationId VARCHAR(100) NOT NULL,\n\n    /* Holds the time at which the grain was added to the directory */\n    CreatedOn DATETIME(3) NOT NULL,\n\n    /* Primary key ensures uniqueness of grain identity */\n    PRIMARY KEY (ClusterId, ProviderId, GrainId)\n);\n\nDELIMITER $$\n\nCREATE PROCEDURE RegisterGrainActivation\n(\n    IN _ClusterId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n    IN _GrainId NVARCHAR(468),\n    IN _SiloAddress NVARCHAR(100),\n    IN _ActivationId NVARCHAR(100)\n)\nBEGIN\n\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION\n    BEGIN\n        ROLLBACK;\n        RESIGNAL;\n    END;\n\n    START TRANSACTION;\n\n    INSERT INTO OrleansGrainDirectory\n    (\n        ClusterId,\n        ProviderId,\n        GrainId,\n        SiloAddress,\n        ActivationId,\n        CreatedOn\n    )\n    VALUES\n    (\n        _ClusterId,\n        _ProviderId,\n        _GrainId,\n        _SiloAddress,\n        _ActivationId,\n        UTC_TIMESTAMP(3)\n    )\n    ON DUPLICATE KEY UPDATE\n        ClusterId = ClusterId;\n\n    -- Return the current registration\n    SELECT\n        ClusterId,\n        ProviderId,\n        GrainId,\n        SiloAddress,\n        ActivationId\n    FROM\n        OrleansGrainDirectory\n    WHERE\n        ClusterId = _ClusterId\n        AND ProviderId = _ProviderId\n        AND GrainId = _GrainId;\n\n    COMMIT;\n\nEND;\n\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n    'RegisterGrainActivationKey',\n    'CALL RegisterGrainActivation(@ClusterId, @ProviderId, @GrainId, @SiloAddress, @ActivationId);';\n\nDELIMITER $$\n\nCREATE PROCEDURE UnregisterGrainActivation\n(\n    IN _ClusterId VARCHAR(150),\n    IN _ProviderId VARCHAR(150),\n    IN _GrainId VARCHAR(468),\n    IN _ActivationId VARCHAR(100)\n)\nBEGIN\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION\n    BEGIN\n        ROLLBACK;\n        RESIGNAL;\n    END;\n\n    START TRANSACTION;\n\n    DELETE FROM OrleansGrainDirectory\n    WHERE\n        ClusterId = _ClusterId\n        AND ProviderId = _ProviderId\n        AND GrainId = _GrainId\n        AND ActivationId = _ActivationId;\n\n    SELECT ROW_COUNT() AS DeletedRows;\n\n    COMMIT;\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n    'UnregisterGrainActivationKey',\n\t'CALL UnregisterGrainActivation(@ClusterId, @ProviderId, @GrainId, @ActivationId);';\n\nDELIMITER $$\n\nCREATE PROCEDURE LookupGrainActivation\n(\n    IN _ClusterId VARCHAR(150),\n    IN _ProviderId VARCHAR(150),\n    IN _GrainId VARCHAR(468)\n)\nBEGIN\n    SELECT\n        ClusterId,\n        ProviderId,\n        GrainId,\n        SiloAddress,\n        ActivationId\n    FROM\n        OrleansGrainDirectory\n    WHERE\n        ClusterId = _ClusterId\n        AND ProviderId = _ProviderId\n        AND GrainId = _GrainId;\nEND\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n    QueryKey,\n    QueryText\n)\nSELECT\n    'LookupGrainActivationKey',\n    'CALL LookupGrainActivation(@ClusterId, @ProviderId, @GrainId);';\n\nDELIMITER $$\n\nCREATE PROCEDURE UnregisterGrainActivations\n(\n    IN _ClusterId VARCHAR(150),\n    IN _ProviderId VARCHAR(150),\n    IN _SiloAddresses TEXT\n)\nBEGIN\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION\n    BEGIN\n        ROLLBACK;\n        RESIGNAL;\n    END;\n\n    START TRANSACTION;\n\n    -- Parse silo addresses into temporary table for batch operation\n    CREATE TEMPORARY TABLE TempSiloAddresses\n    (\n        SiloAddress VARCHAR(100) NOT NULL,\n        Level INT NOT NULL\n    );\n\n    INSERT INTO TempSiloAddresses (SiloAddress, Level)\n    WITH RECURSIVE SiloAddressesCTE AS\n    (\n        SELECT\n            SUBSTRING_INDEX(_SiloAddresses, '|', 1) AS Value,\n            SUBSTRING(_SiloAddresses, CHAR_LENGTH(SUBSTRING_INDEX(_SiloAddresses, '|', 1)) + 2, CHAR_LENGTH(_SiloAddresses)) AS Others,\n            1 AS Level\n        UNION ALL\n        SELECT\n            SUBSTRING_INDEX(Others, '|', 1) AS Value,\n            SUBSTRING(Others, CHAR_LENGTH(SUBSTRING_INDEX(Others, '|', 1)) + 2, CHAR_LENGTH(Others)) AS Others,\n            Level + 1\n        FROM SiloAddressesCTE\n        WHERE Others != ''\n    )\n    SELECT Value, Level FROM SiloAddressesCTE;\n\n    DELETE FROM OrleansGrainDirectory\n    WHERE\n        ClusterId = _ClusterId\n        AND ProviderId = _ProviderId\n        AND SiloAddress IN (SELECT SiloAddress FROM TempSiloAddresses);\n\n    SELECT ROW_COUNT() AS DeletedRows;\n\n    DROP TEMPORARY TABLE TempSiloAddresses;\n\n    COMMIT;\nEND\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n    'UnregisterGrainActivationsKey',\n    'CALL UnregisterGrainActivations(@ClusterId, @ProviderId, @SiloAddresses);';\n\nDELIMITER ;\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Options/AdoNetGrainDirectoryOptionsValidator.cs",
    "content": "using static System.String;\n\nnamespace Orleans.Configuration;\n\n/// <summary>\n/// Validates <see cref=\"AdoNetGrainDirectoryOptions\"/> configuration.\n/// </summary>\npublic class AdoNetGrainDirectoryOptionsValidator(AdoNetGrainDirectoryOptions options, string name) : IConfigurationValidator\n{\n    /// <inheritdoc />\n    public void ValidateConfiguration()\n    {\n        if (options is null)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainDirectoryOptions)} values for {nameof(AdoNetGrainDirectory)}|{name}. {nameof(options)} is required.\");\n        }\n\n        if (IsNullOrWhiteSpace(options.Invariant))\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainDirectoryOptions)} values for {nameof(AdoNetGrainDirectory)}|{name}. {nameof(options.Invariant)} is required.\");\n        }\n\n        if (IsNullOrWhiteSpace(options.ConnectionString))\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainDirectoryOptions)} values for {nameof(AdoNetGrainDirectory)}|{name}. {nameof(options.ConnectionString)} is required.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Orleans.GrainDirectory.AdoNet.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.GrainDirectory.AdoNet</PackageId>\n    <Title>Microsoft Orleans ADO.NET Grain Directory Provider</Title>\n    <Description>Microsoft Orleans grain directory provider backed by ADO.NET</Description>\n    <PackageTags>$(PackageTags) ADO.NET SQL</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n    <Nullable>Enable</Nullable>\n    <ImplicitUsings>Enable</ImplicitUsings>\n    <NoWarn>CA2007</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.GrainDirectory.AdoNet</AssemblyName>\n    <RootNamespace>Orleans.GrainDirectory.AdoNet</RootNamespace>\n    <DefineConstants>$(DefineConstants);GRAINDIRECTORY_ADONET</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Benchmarks.AdoNet\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/PostgreSQL-GrainDirectory.sql",
    "content": "/*\nOrleans Grain Directory.\nThis table stores the location of all grains in the cluster.\n\nNOTE:\nThe combination of ClusterId, ProviderId, and GrainId forms the primary key for the OrleansGrainDirectory table.\nTogether, these columns reach the maximum allowed key size for PostgreSQL indexes (2704 bytes).\nCare should be taken not to increase the length of these columns, as it may exceed PostgreSQL's key size limitation.\n\n*/\nCREATE TABLE OrleansGrainDirectory\n(\n    /* Identifies the cluster instance */\n    ClusterId VARCHAR(150) NOT NULL,\n\n    /* Identifies the grain directory provider */\n    ProviderId VARCHAR(150) NOT NULL,\n\n    /* Holds the grain id in text form */\n    GrainId VARCHAR(2404) NOT NULL,\n\n    /* Holds the silo address where the grain is located */\n    SiloAddress VARCHAR(100) NOT NULL,\n\n    /* Holds the activation id in the silo where it is located */\n    ActivationId VARCHAR(100) NOT NULL,\n\n    /* Holds the time at which the grain was added to the directory */\n    CreatedOn TIMESTAMPTZ NOT NULL,\n\n    /* Identifies a unique grain activation */\n    CONSTRAINT PK_OrleansGrainDirectory PRIMARY KEY\n    (\n        ClusterId,\n        ProviderId,\n        GrainId\n    )\n);\n\n/* Registers a new grain activation */\nCREATE OR REPLACE FUNCTION RegisterGrainActivation(\n    _ClusterId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _GrainId VARCHAR(600),\n    _SiloAddress VARCHAR(100),\n    _ActivationId VARCHAR(100)\n)\nRETURNS TABLE\n(\n    ClusterId VARCHAR(150),\n    ProviderId VARCHAR(150),\n    GrainId VARCHAR(600),\n    SiloAddress VARCHAR(100),\n    ActivationId VARCHAR(100)\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n    _Now TIMESTAMPTZ := NOW();\nBEGIN\n\nRETURN QUERY\nINSERT INTO OrleansGrainDirectory\n(\n    ClusterId,\n    ProviderId,\n    GrainId,\n    SiloAddress,\n    ActivationId,\n    CreatedOn\n)\nSELECT\n    _ClusterId,\n    _ProviderId,\n    _GrainId,\n    _SiloAddress,\n    _ActivationId,\n    _Now\nON CONFLICT (ClusterId, ProviderId, GrainId)\nDO UPDATE SET\n    ClusterId = _ClusterId,\n    ProviderId = _ProviderId,\n    GrainId = _GrainId\nRETURNING\n    ClusterId,\n    ProviderId,\n    GrainId,\n    SiloAddress,\n    ActivationId;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'RegisterGrainActivationKey',\n\t'START TRANSACTION; SELECT * FROM RegisterGrainActivation (@ClusterId, @ProviderId, @GrainId, @SiloAddress, @ActivationId); COMMIT;'\n;\n\n/* Unregisters an existing grain activation */\nCREATE OR REPLACE FUNCTION UnregisterGrainActivation(\n    _ClusterId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _GrainId VARCHAR(600),\n    _ActivationId VARCHAR(100)\n)\nRETURNS INT\nLANGUAGE plpgsql\nAS $$\nDECLARE\n    _RowCount INT;\nBEGIN\n\nDELETE FROM OrleansGrainDirectory\nWHERE ClusterId = _ClusterId\n    AND ProviderId = _ProviderId\n    AND GrainId = _GrainId\n    AND ActivationId = _ActivationId;\n\nGET DIAGNOSTICS _RowCount = ROW_COUNT;\n\nRETURN _RowCount;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'UnregisterGrainActivationKey',\n\t'SELECT * FROM UnregisterGrainActivation (@ClusterId, @ProviderId, @GrainId, @ActivationId)'\n;\n\n/* Looks up an existing grain activation */\nCREATE OR REPLACE FUNCTION LookupGrainActivation(\n    _ClusterId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _GrainId VARCHAR(600)\n)\nRETURNS TABLE\n(\n    ClusterId VARCHAR(150),\n    ProviderId VARCHAR(150),\n    GrainId VARCHAR(600),\n    SiloAddress VARCHAR(100),\n    ActivationId VARCHAR(100)\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nBEGIN\n\nRETURN QUERY\nSELECT\n    ClusterId,\n    ProviderId,\n    GrainId,\n    SiloAddress,\n    ActivationId\nFROM\n    OrleansGrainDirectory\nWHERE\n    ClusterId = _ClusterId\n    AND ProviderId = _ProviderId\n    AND GrainId = _GrainId;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n    QueryKey,\n    QueryText\n)\nSELECT\n    'LookupGrainActivationKey',\n    'SELECT * FROM LookupGrainActivation(@ClusterId, @ProviderId, @GrainId)'\n;\n\n/* Unregisters all grain activations in the specified silos */\nCREATE OR REPLACE FUNCTION UnregisterGrainActivations(\n    _ClusterId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _SiloAddresses TEXT\n)\nRETURNS INT\nLANGUAGE plpgsql\nAS $$\nDECLARE\n    _RowCount INT;\nBEGIN\n\nDELETE FROM OrleansGrainDirectory\nWHERE\n    ClusterId = _ClusterId\n    AND ProviderId = _ProviderId\n    AND SiloAddress = ANY (string_to_array(_SiloAddresses, '|'));\n\nGET DIAGNOSTICS _RowCount = ROW_COUNT;\n\nRETURN _RowCount;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'UnregisterGrainActivationsKey',\n\t'SELECT * FROM UnregisterGrainActivations (@ClusterId, @ProviderId, @SiloAddresses)'\n;\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/Properties/Usings.cs",
    "content": "global using System;\nglobal using System.Collections.Generic;\nglobal using System.ComponentModel.DataAnnotations;\nglobal using System.Globalization;\nglobal using System.Linq;\nglobal using System.Threading;\nglobal using System.Threading.Tasks;\nglobal using Microsoft.Extensions.Configuration;\nglobal using Microsoft.Extensions.DependencyInjection;\nglobal using Microsoft.Extensions.Hosting;\nglobal using Microsoft.Extensions.Logging;\nglobal using Microsoft.Extensions.Options;\nglobal using Orleans.Configuration;\nglobal using Orleans.GrainDirectory;\nglobal using Orleans.GrainDirectory.AdoNet;\nglobal using Orleans.GrainDirectory.AdoNet.Storage;\nglobal using Orleans.Providers;\nglobal using Orleans.Runtime;\n"
  },
  {
    "path": "src/AdoNet/Orleans.GrainDirectory.AdoNet/SQLServer-GrainDirectory.sql",
    "content": "/*\nOrleans Grain Directory.\nThis table stores the location of all grains in the cluster.\n\nNOTE:\nThe combination of ClusterId, ProviderId, and GrainId forms the primary key for the OrleansGrainDirectory table.\nTogether, these columns reach the maximum allowed key size for SQL Server indexes (900 bytes).\nCare should be taken not to increase the length of these columns, as it may exceed SQL Server's key size limitation.\n\n*/\nCREATE TABLE OrleansGrainDirectory\n(\n    /* Identifies the cluster instance */\n    ClusterId VARCHAR(150) NOT NULL,\n\n    /* Identifies the grain directory provider */\n    ProviderId VARCHAR(150) NOT NULL,\n\n    /* Holds the grain id in text form */\n    GrainId VARCHAR(600) NOT NULL,\n\n    /* Holds the silo address where the grain is located */\n    SiloAddress VARCHAR(100) NOT NULL,\n\n    /* Holds the activation id in the silo where it is located */\n    ActivationId VARCHAR(100) NOT NULL,\n\n    /* Holds the time at which the grain was added to the directory */\n    CreatedOn DATETIMEOFFSET(3) NOT NULL,\n\n    /* Identifies a unique grain activation */\n    CONSTRAINT PK_OrleansGrainDirectory PRIMARY KEY CLUSTERED\n    (\n        ClusterId ASC,\n        ProviderId ASC,\n        GrainId ASC\n    )\n)\nGO\n\n/* Registers a new grain activation */\nCREATE PROCEDURE RegisterGrainActivation\n    @ClusterId VARCHAR(150),\n    @ProviderId VARCHAR(150),\n    @GrainId VARCHAR(600),\n    @SiloAddress VARCHAR(100),\n    @ActivationId VARCHAR(100)\nAS\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @Now DATETIMEOFFSET(3) = CAST(SYSUTCDATETIME() AS DATETIMEOFFSET(3));\n\nBEGIN TRANSACTION;\n\n/* Get the existing entry if it exists. */\n/* This also places a lock on the range upfront in case we need to add a new entry. */\n/* This lock is required to prevent deadlocks. */\nDECLARE @Exists INT =\n(\n    SELECT\n        1\n    FROM\n        OrleansGrainDirectory WITH (UPDLOCK, HOLDLOCK)\n    WHERE\n        ClusterId = @ClusterId\n        AND ProviderId = @ProviderId\n        AND GrainId = @GrainId\n);\n\nIF @Exists = 1\nBEGIN\n\n    /* If the entry already exists, we can return it. */\n    SELECT\n        ClusterId,\n        ProviderId,\n        GrainId,\n        SiloAddress,\n        ActivationId\n    FROM\n        OrleansGrainDirectory\n    WHERE\n        ClusterId = @ClusterId\n        AND ProviderId = @ProviderId\n        AND GrainId = @GrainId;\n\nEND\nELSE\nBEGIN\n\n    /* If the entry does not yet exist, we will add it now. */\n    INSERT INTO OrleansGrainDirectory\n    (\n        ClusterId,\n        ProviderId,\n        GrainId,\n        SiloAddress,\n        ActivationId,\n        CreatedOn\n    )\n    OUTPUT\n        INSERTED.ClusterId,\n        INSERTED.ProviderId,\n        INSERTED.GrainId,\n        INSERTED.SiloAddress,\n        INSERTED.ActivationId\n    VALUES\n    (\n        @ClusterId,\n        @ProviderId,\n        @GrainId,\n        @SiloAddress,\n        @ActivationId,\n        @Now\n    );\n\nEND\n\nCOMMIT;\n\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'RegisterGrainActivationKey',\n\t'EXECUTE RegisterGrainActivation @ClusterId = @ClusterId, @ProviderId = @ProviderId, @GrainId = @GrainId, @SiloAddress = @SiloAddress, @ActivationId = @ActivationId'\nGO\n\n/* Unregisters an existing grain activation */\nCREATE PROCEDURE UnregisterGrainActivation\n    @ClusterId VARCHAR(150),\n    @ProviderId VARCHAR(150),\n    @GrainId VARCHAR(600),\n    @ActivationId VARCHAR(100)\nAS\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\n/* Delete the entry if it exists. */\n/* This places a lock on the hash index pages upfront to prevent deadlocks. */\nDELETE OrleansGrainDirectory\nFROM OrleansGrainDirectory\nWHERE\n    ClusterId = @ClusterId\n    AND ProviderId = @ProviderId\n    AND GrainId = @GrainId\n    AND ActivationId = @ActivationId;\n\nSELECT @@ROWCOUNT;\n\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'UnregisterGrainActivationKey',\n\t'EXECUTE UnregisterGrainActivation @ClusterId = @ClusterId, @ProviderId = @ProviderId, @GrainId = @GrainId, @ActivationId = @ActivationId'\nGO\n\n\n/* Looks up an existing grain activation */\nCREATE PROCEDURE LookupGrainActivation\n    @ClusterId VARCHAR(150),\n    @ProviderId VARCHAR(150),\n    @GrainId VARCHAR(600)\nAS\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\n/* Get the existing entry if it exists. */\n/* This also places a lock on the hash index pages upfront to prevent deadlocks with registration. */\nSELECT\n    ClusterId,\n    ProviderId,\n    GrainId,\n    SiloAddress,\n    ActivationId\nFROM\n    OrleansGrainDirectory\nWHERE\n    ClusterId = @ClusterId\n    AND ProviderId = @ProviderId\n    AND GrainId = @GrainId;\n\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'LookupGrainActivationKey',\n\t'EXECUTE LookupGrainActivation @ClusterId = @ClusterId, @ProviderId = @ProviderId, @GrainId = @GrainId'\nGO\n\n\n/* Unregisters all grain activations in the specified silos */\nCREATE PROCEDURE UnregisterGrainActivations\n    @ClusterId VARCHAR(150),\n    @ProviderId VARCHAR(150),\n    @SiloAddresses VARCHAR(MAX)\nAS\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nBEGIN TRANSACTION;\n\n/* Delete the entries if they exist. */\n/* This places a exclusive lock on the entire table to prevent deadlocks with registration. */\nDELETE OrleansGrainDirectory\nFROM OrleansGrainDirectory WITH (TABLOCKX)\nWHERE\n    ClusterId = @ClusterId\n    AND ProviderId = @ProviderId\n    AND SiloAddress IN (SELECT Value FROM STRING_SPLIT(@SiloAddresses, '|'));\n\nSELECT @@ROWCOUNT;\n\nCOMMIT TRANSACTION;\n\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'UnregisterGrainActivationsKey',\n\t'EXECUTE UnregisterGrainActivations @ClusterId = @ClusterId, @ProviderId = @ProviderId, @SiloAddresses = @SiloAddresses'\nGO\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/AdoNetGrainStorageProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"AdoNet\", \"GrainStorage\", \"Silo\", typeof(AdoNetGrainStorageProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AdoNetGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAdoNetGrainStorage(name, (OptionsBuilder<AdoNetGrainStorageOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var invariant = configurationSection[nameof(options.Invariant)];\n                if (!string.IsNullOrEmpty(invariant))\n                {\n                    options.Invariant = invariant;\n                }\n\n                var connectionString = configurationSection[nameof(options.ConnectionString)];\n                var connectionName = configurationSection[\"ConnectionName\"];\n                if (string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(connectionName))\n                {\n                    connectionString = services.GetRequiredService<IConfiguration>().GetConnectionString(connectionName);\n                }\n\n                if (!string.IsNullOrEmpty(connectionString))\n                {\n                    options.ConnectionString = connectionString;\n                }\n\n                var serializerKey = configurationSection[\"SerializerKey\"];\n                if (!string.IsNullOrEmpty(serializerKey))\n                {\n                    options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Migrations/PostgreSQL-Persistence-3.6.0.sql",
    "content": "-- Run this migration for upgrading the PostgreSQL persistence table and routines for deployments created before 3.6.0\n\nBEGIN;\n\n-- Change date type\n\nALTER TABLE OrleansStorage\nALTER COLUMN modifiedon TYPE TIMESTAMPTZ USING modifiedon AT TIME ZONE 'UTC';\n\n-- Recreate routines\n\nCREATE OR REPLACE FUNCTION writetostorage(\n    _grainidhash integer,\n    _grainidn0 bigint,\n    _grainidn1 bigint,\n    _graintypehash integer,\n    _graintypestring character varying,\n    _grainidextensionstring character varying,\n    _serviceid character varying,\n    _grainstateversion integer,\n    _payloadbinary bytea)\n    RETURNS TABLE(newgrainstateversion integer)\n    LANGUAGE 'plpgsql'\nAS $function$\n    DECLARE\n     _newGrainStateVersion integer := _GrainStateVersion;\n     RowCountVar integer := 0;\n\n    BEGIN\n\n    -- Grain state is not null, so the state must have been read from the storage before.\n    -- Let's try to update it.\n    --\n    -- When Orleans is running in normal, non-split state, there will\n    -- be only one grain with the given ID and type combination only. This\n    -- grain saves states mostly serially if Orleans guarantees are upheld. Even\n    -- if not, the updates should work correctly due to version number.\n    --\n    -- In split brain situations there can be a situation where there are two or more\n    -- grains with the given ID and type combination. When they try to INSERT\n    -- concurrently, the table needs to be locked pessimistically before one of\n    -- the grains gets @GrainStateVersion = 1 in return and the other grains will fail\n    -- to update storage. The following arrangement is made to reduce locking in normal operation.\n    --\n    -- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed\n    -- and throws an InconsistentStateException.\n    --\n    -- See further information at https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence.\n    IF _GrainStateVersion IS NOT NULL\n    THEN\n        UPDATE OrleansStorage\n        SET\n            PayloadBinary = _PayloadBinary,\n            ModifiedOn = (now() at time zone 'utc'),\n            Version = Version + 1\n\n        WHERE\n            GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n            AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n            AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n            AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n            AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n            AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n            AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n            AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL;\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n        IF RowCountVar > 0\n        THEN\n            _newGrainStateVersion := _GrainStateVersion + 1;\n        END IF;\n    END IF;\n\n    -- The grain state has not been read. The following locks rather pessimistically\n    -- to ensure only one INSERT succeeds.\n    IF _GrainStateVersion IS NULL\n    THEN\n        INSERT INTO OrleansStorage\n        (\n            GrainIdHash,\n            GrainIdN0,\n            GrainIdN1,\n            GrainTypeHash,\n            GrainTypeString,\n            GrainIdExtensionString,\n            ServiceId,\n            PayloadBinary,\n            ModifiedOn,\n            Version\n        )\n        SELECT\n            _GrainIdHash,\n            _GrainIdN0,\n            _GrainIdN1,\n            _GrainTypeHash,\n            _GrainTypeString,\n            _GrainIdExtensionString,\n            _ServiceId,\n            _PayloadBinary,\n           now(),\n            1\n        WHERE NOT EXISTS\n         (\n            -- There should not be any version of this grain state.\n            SELECT 1\n            FROM OrleansStorage\n            WHERE\n                GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n                AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n                AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n                AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n                AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n                AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n                AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n         );\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n        IF RowCountVar > 0\n        THEN\n            _newGrainStateVersion := 1;\n        END IF;\n    END IF;\n\n    RETURN QUERY SELECT _newGrainStateVersion AS NewGrainStateVersion;\nEND\n\n$function$;\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/MySQL-Persistence.sql",
    "content": "-- The design criteria for this table are:\n--\n-- 1. It can contain arbitrary content serialized as binary, XML or JSON. These formats\n-- are supported to allow one to take advantage of in-storage processing capabilities for\n-- these types if required. This should not incur extra cost on storage.\n--\n-- 2. The table design should scale with the idea of tens or hundreds (or even more) types\n-- of grains that may operate with even hundreds of thousands of grain IDs within each\n-- type of a grain.\n--\n-- 3. The table and its associated operations should remain stable. There should not be\n-- structural reason for unexpected delays in operations. It should be possible to also\n-- insert data reasonably fast without resource contention.\n--\n-- 4. For reasons in 2. and 3., the index should be as narrow as possible so it fits well in\n-- memory and should it require maintenance, isn't resource intensive. For this\n-- reason the index is narrow by design (ideally non-clustered). Currently the entity\n-- is recognized in the storage by the grain type and its ID, which are unique in Orleans silo.\n-- The ID is the grain ID bytes (if string type UTF-8 bytes) and possible extension key as UTF-8\n-- bytes concatenated with the ID and then hashed.\n--\n-- Reason for hashing: Database engines usually limit the length of the column sizes, which\n-- would artificially limit the length of IDs or types. Even when within limitations, the\n-- index would be thick and consume more memory.\n--\n-- In the current setup the ID and the type are hashed into two INT type instances, which\n-- are made a compound index. When there are no collisions, the index can quickly locate\n-- the unique row. Along with the hashed index values, the NVARCHAR(nnn) values are also\n-- stored and they are used to prune hash collisions down to only one result row.\n--\n-- 5. The design leads to duplication in the storage. It is reasonable to assume there will\n-- a low number of services with a given service ID operational at any given time. Or that\n-- compared to the number of grain IDs, there are a fairly low number of different types of\n-- grain. The catch is that were these data separated to another table, it would make INSERT\n-- and UPDATE operations complicated and would require joins, temporary variables and additional\n-- indexes or some combinations of them to make it work. It looks like fitting strategy\n-- could be to use table compression.\n--\n-- 6. For the aforementioned reasons, grain state DELETE will set NULL to the data fields\n-- and updates the Version number normally. This should alleviate the need for index or\n-- statistics maintenance with the loss of some bytes of storage space. The table can be scrubbed\n-- in a separate maintenance operation.\n--\n-- 7. In the storage operations queries the columns need to be in the exact same order\n-- since the storage table operations support optionally streaming.\nCREATE TABLE OrleansStorage\n(\n    -- These are for the book keeping. Orleans calculates\n    -- these hashes (see RelationalStorageProvide implementation),\n    -- which are signed 32 bit integers mapped to the *Hash fields.\n    -- The mapping is done in the code. The\n    -- *String columns contain the corresponding clear name fields.\n    --\n    -- If there are duplicates, they are resolved by using GrainIdN0,\n    -- GrainIdN1, GrainIdExtensionString and GrainTypeString fields.\n    -- It is assumed these would be rarely needed.\n    GrainIdHash                INT NOT NULL,\n    GrainIdN0                BIGINT NOT NULL,\n    GrainIdN1                BIGINT NOT NULL,\n    GrainTypeHash            INT NOT NULL,\n    GrainTypeString            NVARCHAR(512) NOT NULL,\n    GrainIdExtensionString    NVARCHAR(512) NULL,\n    ServiceId                NVARCHAR(150) NOT NULL,\n\n    -- Payload\n    PayloadBinary    BLOB NULL,\n\n    -- Informational field, no other use.\n    ModifiedOn DATETIME NOT NULL,\n\n    -- The version of the stored payload.\n    Version INT NULL\n\n    -- The following would in principle be the primary key, but it would be too thick\n    -- to be indexed, so the values are hashed and only collisions will be solved\n    -- by using the fields. That is, after the indexed queries have pinpointed the right\n    -- rows down to [0, n] relevant ones, n being the number of collided value pairs.\n) ROW_FORMAT = COMPRESSED KEY_BLOCK_SIZE = 16;\nALTER TABLE OrleansStorage ADD INDEX IX_OrleansStorage (GrainIdHash, GrainTypeHash);\n\nDELIMITER $$\n\nCREATE PROCEDURE ClearStorage\n(\n    in _GrainIdHash INT,\n    in _GrainIdN0 BIGINT,\n    in _GrainIdN1 BIGINT,\n    in _GrainTypeHash INT,\n    in _GrainTypeString NVARCHAR(512),\n    in _GrainIdExtensionString NVARCHAR(512),\n    in _ServiceId NVARCHAR(150),\n    in _GrainStateVersion INT\n)\nBEGIN\n    DECLARE _newGrainStateVersion INT;\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;\n    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN ROLLBACK; RESIGNAL; END;\n\n    SET _newGrainStateVersion = _GrainStateVersion;\n\n    -- Default level is REPEATABLE READ and may cause Gap Lock issues\n    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n    START TRANSACTION;\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = NULL,\n        Version = Version + 1\n    WHERE\n        GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n        AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n        AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n        AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL\n        LIMIT 1;\n\n    IF ROW_COUNT() > 0\n    THEN\n        SET _newGrainStateVersion = _GrainStateVersion + 1;\n    END IF;\n\n    SELECT _newGrainStateVersion AS NewGrainStateVersion;\n    COMMIT;\nEND$$\n\nCREATE PROCEDURE DeleteStorage\n(\n    in _GrainIdHash INT,\n    in _GrainIdN0 BIGINT,\n    in _GrainIdN1 BIGINT,\n    in _GrainTypeHash INT,\n    in _GrainTypeString NVARCHAR(512),\n    in _GrainIdExtensionString NVARCHAR(512),\n    in _ServiceId NVARCHAR(150),\n    in _GrainStateVersion INT\n)\nBEGIN\n    DECLARE _newGrainStateVersion INT;\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;\n    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN ROLLBACK; RESIGNAL; END;\n\n    SET _newGrainStateVersion = _GrainStateVersion;\n\n    -- Default level is REPEATABLE READ and may cause Gap Lock issues\n    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n    START TRANSACTION;\n    DELETE FROM OrleansStorage\n    WHERE\n        GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n        AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n        AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n        AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL\n        LIMIT 1;\n\n    IF ROW_COUNT() > 0\n    THEN\n        SET _newGrainStateVersion = _GrainStateVersion + 1;\n    END IF;\n\n    SELECT _newGrainStateVersion AS NewGrainStateVersion;\n    COMMIT;\nEND$$\n\nDELIMITER $$\nCREATE PROCEDURE WriteToStorage\n(\n    in _GrainIdHash INT,\n    in _GrainIdN0 BIGINT,\n    in _GrainIdN1 BIGINT,\n    in _GrainTypeHash INT,\n    in _GrainTypeString NVARCHAR(512),\n    in _GrainIdExtensionString NVARCHAR(512),\n    in _ServiceId NVARCHAR(150),\n    in _GrainStateVersion INT,\n    in _PayloadBinary BLOB\n)\nBEGIN\n    DECLARE _newGrainStateVersion INT;\n    DECLARE _rowCount INT;\n    DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;\n    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN ROLLBACK; RESIGNAL; END;\n\n    SET _newGrainStateVersion = _GrainStateVersion;\n\n    -- Default level is REPEATABLE READ and may cause Gap Lock issues\n    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n    START TRANSACTION;\n\n    -- Grain state is not null, so the state must have been read from the storage before.\n    -- Let's try to update it.\n    --\n    -- When Orleans is running in normal, non-split state, there will\n    -- be only one grain with the given ID and type combination only. This\n    -- grain saves states mostly serially if Orleans guarantees are upheld. Even\n    -- if not, the updates should work correctly due to version number.\n    --\n    -- In split brain situations there can be a situation where there are two or more\n    -- grains with the given ID and type combination. When they try to INSERT\n    -- concurrently, the table needs to be locked pessimistically before one of\n    -- the grains gets @GrainStateVersion = 1 in return and the other grains will fail\n    -- to update storage. The following arrangement is made to reduce locking in normal operation.\n    --\n    -- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed\n    -- and throws an InconsistentStateException.\n    --\n    -- See further information at https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence.\n    IF _GrainStateVersion IS NOT NULL\n    THEN\n        UPDATE OrleansStorage\n        SET\n            PayloadBinary = _PayloadBinary,\n            ModifiedOn = UTC_TIMESTAMP(),\n            Version = Version + 1\n        WHERE\n            GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n            AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n            AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n            AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n            AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n            AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n            AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n            AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL\n            LIMIT 1;\n\n        IF ROW_COUNT() > 0\n        THEN\n            SET _newGrainStateVersion = _GrainStateVersion + 1;\n            SET _GrainStateVersion = _newGrainStateVersion;\n        END IF;\n    END IF;\n\n    -- The grain state has not been read. The following locks rather pessimistically\n    -- to ensure only on INSERT succeeds.\n    IF _GrainStateVersion IS NULL\n    THEN\n        INSERT INTO OrleansStorage\n        (\n            GrainIdHash,\n            GrainIdN0,\n            GrainIdN1,\n            GrainTypeHash,\n            GrainTypeString,\n            GrainIdExtensionString,\n            ServiceId,\n            PayloadBinary,\n            ModifiedOn,\n            Version\n        )\n        SELECT * FROM ( SELECT\n            _GrainIdHash,\n            _GrainIdN0,\n            _GrainIdN1,\n            _GrainTypeHash,\n            _GrainTypeString,\n            _GrainIdExtensionString,\n            _ServiceId,\n            _PayloadBinary,\n            UTC_TIMESTAMP(),\n            1) AS TMP\n        WHERE NOT EXISTS\n        (\n            -- There should not be any version of this grain state.\n            SELECT 1\n            FROM OrleansStorage\n            WHERE\n                GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n                AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n                AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n                AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n                AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n                AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n                AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n        ) LIMIT 1;\n\n        IF ROW_COUNT() > 0\n        THEN\n            SET _newGrainStateVersion = 1;\n        END IF;\n    END IF;\n\n    SELECT _newGrainStateVersion AS NewGrainStateVersion;\n    COMMIT;\nEND$$\n\nDELIMITER ;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadFromStorageKey',\n    'SELECT\n        PayloadBinary,\n        UTC_TIMESTAMP(),\n        Version\n    FROM\n        OrleansStorage\n    WHERE\n        GrainIdHash = @GrainIdHash\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = @GrainIdN0 AND @GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = @GrainIdN1 AND @GrainIdN1 IS NOT NULL\n        AND GrainTypeString = @GrainTypeString AND GrainTypeString IS NOT NULL\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        LIMIT 1;'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'WriteToStorageKey','\n    call WriteToStorage(@GrainIdHash, @GrainIdN0, @GrainIdN1, @GrainTypeHash, @GrainTypeString, @GrainIdExtensionString, @ServiceId, @GrainStateVersion, @PayloadBinary);'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ClearStorageKey','\n    call ClearStorage(@GrainIdHash, @GrainIdN0, @GrainIdN1, @GrainTypeHash, @GrainTypeString, @GrainIdExtensionString, @ServiceId, @GrainStateVersion);'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteStorageKey','\n    call DeleteStorage(@GrainIdHash, @GrainIdN0, @GrainIdN1, @GrainTypeHash, @GrainTypeString, @GrainIdExtensionString, @ServiceId, @GrainStateVersion);'\n);\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Options/AdoNetGrainStorageOptions.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Persistence.AdoNet.Storage;\nusing Orleans.Runtime;\nusing Orleans.Storage;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for ADO.NET grain storage.\n    /// </summary>\n    public class AdoNetGrainStorageOptions : IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Connection string for AdoNet storage.\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n\n        /// <summary>\n        /// Default init stage in silo lifecycle.\n        /// </summary>\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n        /// <summary>\n        /// The default ADO.NET invariant used for storage if none is given. \n        /// </summary>\n        public const string DEFAULT_ADONET_INVARIANT = AdoNetInvariants.InvariantNameSqlServer;\n\n        /// <summary>\n        /// The invariant name for storage.\n        /// </summary>\n        public string Invariant { get; set; } = DEFAULT_ADONET_INVARIANT;\n\n        /// <inheritdoc/>\n        public IGrainStorageSerializer GrainStorageSerializer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the hasher picker to use for this storage provider. \n        /// </summary>\n        public IStorageHasherPicker HashPicker { get; set; }\n\n        /// <summary>\n        /// Sets legacy Orleans v3-compatible hash picker to use for this storage provider. Invoke this method if you need to run\n        /// Orleans v7+ silo against existing Orleans v3-initialized database and keep existing grain state.\n        /// </summary>\n        public void UseOrleans3CompatibleHasher()\n        {\n            // content-aware hashing with different pickers, unable to use standard StorageHasherPicker\n            this.HashPicker = new Orleans3CompatibleStorageHashPicker();\n        }\n\n        /// <summary>\n        /// Delete record row from db when state is cleared.\n        /// </summary>\n        public bool DeleteStateOnClear { get; set; }\n    }\n\n    /// <summary>\n    /// ConfigurationValidator for AdoNetGrainStorageOptions\n    /// </summary>\n    public class AdoNetGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        private readonly AdoNetGrainStorageOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"configurationOptions\">The option to be validated.</param>\n        /// <param name=\"name\">The name of the option to be validated.</param>\n        public AdoNetGrainStorageOptionsValidator(AdoNetGrainStorageOptions configurationOptions, string name)\n        {\n            this.options = configurationOptions ?? throw new OrleansConfigurationException($\"Invalid AdoNetGrainStorageOptions for AdoNetGrainStorage {name}. Options is required.\");\n            this.name = name;\n        }\n\n        /// <inheritdoc cref=\"IConfigurationValidator\"/>\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.Invariant))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \\\"{name}\\\". {nameof(options.Invariant)} is required.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ConnectionString))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \\\"{name}\\\". {nameof(options.ConnectionString)} is required.\");\n            }\n\n            if (this.options.HashPicker == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} {name}. {nameof(options.HashPicker)} is required.\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Provides default configuration HashPicker for AdoNetGrainStorageOptions.\n    /// </summary>\n    public class DefaultAdoNetGrainStorageOptionsHashPickerConfigurator : IPostConfigureOptions<AdoNetGrainStorageOptions>\n    {\n        public void PostConfigure(string name, AdoNetGrainStorageOptions options)\n        {\n            // preserving explicitly configured HashPicker\n            if (options.HashPicker != null)\n                return;\n\n            // set default IHashPicker if not configured yet\n            options.HashPicker = new StorageHasherPicker(new[] { new OrleansDefaultHasher() });\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Oracle-Persistence.sql",
    "content": "-- The design criteria for this table are:\n--\n-- 1. It can contain arbitrary content serialized as binary, XML or JSON. These formats\n-- are supported to allow one to take advantage of in-storage processing capabilities for\n-- these types if required. This should not incur extra cost on storage.\n--\n-- 2. The table design should scale with the idea of tens or hundreds (or even more) types\n-- of grains that may operate with even hundreds of thousands of grain IDs within each\n-- type of a grain.\n--\n-- 3. The table and its associated operations should remain stable. There should not be\n-- structural reason for unexpected delays in operations. It should be possible to also\n-- insert data reasonably fast without resource contention.\n--\n-- 4. For reasons in 2. and 3., the index should be as narrow as possible so it fits well in\n-- memory and should it require maintenance, isn't resource intensive. For this\n-- reason the index is narrow by design (ideally non-clustered). Currently the entity\n-- is recognized in the storage by the grain type and its ID, which are unique in Orleans silo.\n-- The ID is the grain ID bytes (if string type UTF-8 bytes) and possible extension key as UTF-8\n-- bytes concatenated with the ID and then hashed.\n--\n-- Reason for hashing: Database engines usually limit the length of the column sizes, which\n-- would artificially limit the length of IDs or types. Even when within limitations, the\n-- index would be thick and consume more memory.\n--\n-- In the current setup the ID and the type are hashed into two INT type instances, which\n-- are made a compound index. When there are no collisions, the index can quickly locate\n-- the unique row. Along with the hashed index values, the NVARCHAR(nnn) values are also\n-- stored and they are used to prune hash collisions down to only one result row.\n--\n-- 5. The design leads to duplication in the storage. It is reasonable to assume there will\n-- a low number of services with a given service ID operational at any given time. Or that\n-- compared to the number of grain IDs, there are a fairly low number of different types of\n-- grain. The catch is that were these data separated to another table, it would make INSERT\n-- and UPDATE operations complicated and would require joins, temporary variables and additional\n-- indexes or some combinations of them to make it work. It looks like fitting strategy\n-- could be to use table compression.\n--\n-- 6. For the aforementioned reasons, grain state DELETE will set NULL to the data fields\n-- and updates the Version number normally. This should alleviate the need for index or\n-- statistics maintenance with the loss of some bytes of storage space. The table can be scrubbed\n-- in a separate maintenance operation.\n--\n-- 7. In the storage operations queries the columns need to be in the exact same order\n-- since the storage table operations support optionally streaming.\nCREATE TABLE \"ORLEANSSTORAGE\"\n(\n\n    -- These are for the book keeping. Orleans calculates\n    -- these hashes (see RelationalStorageProvide implementation),\n    -- which are signed 32 bit integers mapped to the *Hash fields.\n    -- The mapping is done in the code. The\n    -- *String columns contain the corresponding clear name fields.\n    --\n    -- If there are duplicates, they are resolved by using GrainIdN0,\n    -- GrainIdN1, GrainIdExtensionString and GrainTypeString fields.\n    -- It is assumed these would be rarely needed.\n    \"GRAINIDHASH\" NUMBER(*,0) NOT NULL ENABLE,\n    \"GRAINIDN0\" NUMBER(19,0) NOT NULL ENABLE,\n    \"GRAINIDN1\" NUMBER(19,0) NOT NULL ENABLE,\n    \"GRAINTYPEHASH\" NUMBER(*,0) NOT NULL ENABLE,\n    \"GRAINTYPESTRING\" NVARCHAR2(512) NOT NULL ENABLE,\n    \"GRAINIDEXTENSIONSTRING\" NVARCHAR2(512),\n    \"SERVICEID\" NVARCHAR2(150) NOT NULL ENABLE,\n\n    -- Payload\n    \"PAYLOADBINARY\" BLOB,\n\n    -- Informational field, no other use.\n    \"MODIFIEDON\" TIMESTAMP (6) NOT NULL ENABLE,\n    -- The version of the stored payload.\n    \"VERSION\" NUMBER(*,0)\n\n    -- The following would in principle be the primary key, but it would be too thick\n    -- to be indexed, so the values are hashed and only collisions will be solved\n    -- by using the fields. That is, after the indexed queries have pinpointed the right\n    -- rows down to [0, n] relevant ones, n being the number of collided value pairs.\n);\nCREATE INDEX \"IX_ORLEANSSTORAGE\" ON \"ORLEANSSTORAGE\" (\"GRAINIDHASH\", \"GRAINTYPEHASH\") PARALLEL\nCOMPRESS;\n/\n\nCREATE OR REPLACE FUNCTION WriteToStorage(PARAM_GRAINIDHASH IN NUMBER, PARAM_GRAINIDN0 IN NUMBER, PARAM_GRAINIDN1 IN NUMBER, PARAM_GRAINTYPEHASH IN NUMBER, PARAM_GRAINTYPESTRING IN NVARCHAR2,\n                                             PARAM_GRAINIDEXTENSIONSTRING IN NVARCHAR2, PARAM_SERVICEID IN VARCHAR2, PARAM_GRAINSTATEVERSION IN NUMBER, PARAM_PAYLOADBINARY IN BLOB)\n  RETURN NUMBER IS\n  rowcount NUMBER;\n  newGrainStateVersion NUMBER := PARAM_GRAINSTATEVERSION;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    -- When Orleans is running in normal, non-split state, there will\n    -- be only one grain with the given ID and type combination only. This\n    -- grain saves states mostly serially if Orleans guarantees are upheld. Even\n    -- if not, the updates should work correctly due to version number.\n    --\n    -- In split brain situations there can be a situation where there are two or more\n    -- grains with the given ID and type combination. When they try to INSERT\n    -- concurrently, the table needs to be locked pessimistically before one of\n    -- the grains gets @GrainStateVersion = 1 in return and the other grains will fail\n    -- to update storage. The following arrangement is made to reduce locking in normal operation.\n    --\n    -- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed\n    -- and throws an InconsistentStateException.\n    --\n    -- See further information at https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence.\n\n\n    -- If the @GrainStateVersion is not zero, this branch assumes it exists in this database.\n    -- The NULL value is supplied by Orleans when the state is new.\n    IF newGrainStateVersion IS NOT NULL THEN\n        UPDATE OrleansStorage\n        SET\n            PayloadBinary = PARAM_PAYLOADBINARY,\n            ModifiedOn = sys_extract_utc(systimestamp),\n            Version = Version + 1\n        WHERE\n            GrainIdHash = PARAM_GRAINIDHASH AND PARAM_GRAINIDHASH IS NOT NULL\n            AND GrainTypeHash = PARAM_GRAINTYPEHASH AND PARAM_GRAINTYPEHASH IS NOT NULL\n            AND (GrainIdN0 = PARAM_GRAINIDN0 OR PARAM_GRAINIDN0 IS NULL)\n            AND (GrainIdN1 = PARAM_GRAINIDN1 OR PARAM_GRAINIDN1 IS NULL)\n            AND (GrainTypeString = PARAM_GRAINTYPESTRING OR PARAM_GRAINTYPESTRING IS NULL)\n            AND ((PARAM_GRAINIDEXTENSIONSTRING IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = PARAM_GRAINIDEXTENSIONSTRING) OR PARAM_GRAINIDEXTENSIONSTRING IS NULL AND GrainIdExtensionString IS NULL)\n            AND ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n            AND Version IS NOT NULL AND Version = PARAM_GRAINSTATEVERSION AND PARAM_GRAINSTATEVERSION IS NOT NULL\n    RETURNING Version INTO newGrainStateVersion;\n\n    rowcount := SQL%ROWCOUNT;\n\n    IF rowcount = 1 THEN\n      COMMIT;\n      RETURN(newGrainStateVersion);\n    END IF;\n    END IF;\n\n    -- The grain state has not been read. The following locks rather pessimistically\n    -- to ensure only one INSERT succeeds.\n    IF PARAM_GRAINSTATEVERSION IS NULL THEN\n        INSERT INTO OrleansStorage\n        (\n            GrainIdHash,\n            GrainIdN0,\n            GrainIdN1,\n            GrainTypeHash,\n            GrainTypeString,\n            GrainIdExtensionString,\n            ServiceId,\n            PayloadBinary,\n            ModifiedOn,\n            Version\n        )\n        SELECT\n            PARAM_GRAINIDHASH,\n            PARAM_GRAINIDN0,\n            PARAM_GRAINIDN1,\n            PARAM_GRAINTYPEHASH,\n            PARAM_GRAINTYPESTRING,\n            PARAM_GRAINIDEXTENSIONSTRING,\n            PARAM_SERVICEID,\n            PARAM_PAYLOADBINARY,\n            sys_extract_utc(systimestamp),\n            1 FROM DUAL\n         WHERE NOT EXISTS\n         (\n            -- There should not be any version of this grain state.\n            SELECT 1\n            FROM OrleansStorage\n            WHERE\n                GrainIdHash = PARAM_GRAINIDHASH AND PARAM_GRAINIDHASH IS NOT NULL\n                AND GrainTypeHash = PARAM_GRAINTYPEHASH AND PARAM_GRAINTYPEHASH IS NOT NULL\n                AND (GrainIdN0 = PARAM_GRAINIDN0 OR PARAM_GRAINIDN0 IS NULL)\n                AND (GrainIdN1 = PARAM_GRAINIDN1 OR PARAM_GRAINIDN1 IS NULL)\n                AND (GrainTypeString = PARAM_GRAINTYPESTRING OR PARAM_GRAINTYPESTRING IS NULL)\n                AND ((PARAM_GRAINIDEXTENSIONSTRING IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = PARAM_GRAINIDEXTENSIONSTRING) OR PARAM_GRAINIDEXTENSIONSTRING IS NULL AND GrainIdExtensionString IS NULL)\n                AND ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n         );\n\n     rowCount := SQL%ROWCOUNT;\n\n        IF rowCount > 0 THEN\n            newGrainStateVersion := 1;\n        END IF;\n    END IF;\n  COMMIT;\n    RETURN(newGrainStateVersion);\n  END;\n/\n\nCREATE OR REPLACE FUNCTION ClearStorage(PARAM_GRAINIDHASH IN NUMBER, PARAM_GRAINIDN0 IN NUMBER, PARAM_GRAINIDN1 IN NUMBER, PARAM_GRAINTYPEHASH IN NUMBER, PARAM_GRAINTYPESTRING IN NVARCHAR2,\n                                             PARAM_GRAINIDEXTENSIONSTRING IN NVARCHAR2, PARAM_SERVICEID IN VARCHAR2, PARAM_GRAINSTATEVERSION IN NUMBER)\n  RETURN NUMBER IS\n  rowcount NUMBER;\n  newGrainStateVersion NUMBER := PARAM_GRAINSTATEVERSION;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = NULL,\n        ModifiedOn = sys_extract_utc(systimestamp),\n        Version = Version + 1\n    WHERE GrainIdHash = PARAM_GRAINIDHASH AND PARAM_GRAINIDHASH IS NOT NULL\n      AND GrainTypeHash = PARAM_GRAINTYPEHASH AND PARAM_GRAINTYPEHASH IS NOT NULL\n      AND (GrainIdN0 = PARAM_GRAINIDN0 OR PARAM_GRAINIDN0 IS NULL)\n      AND (GrainIdN1  = PARAM_GRAINIDN1 OR PARAM_GRAINIDN1 IS NULL)\n      AND (GrainTypeString = PARAM_GRAINTYPESTRING OR PARAM_GRAINTYPESTRING IS NULL)\n      AND ((PARAM_GRAINIDEXTENSIONSTRING IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = PARAM_GRAINIDEXTENSIONSTRING) OR PARAM_GRAINIDEXTENSIONSTRING IS NULL AND GrainIdExtensionString IS NULL)\n      AND ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n      AND Version IS NOT NULL AND Version = PARAM_GRAINSTATEVERSION AND PARAM_GRAINSTATEVERSION IS NOT NULL\n    RETURNING Version INTO newGrainStateVersion;\n\n    COMMIT;\n    RETURN(newGrainStateVersion);\n  END;\n/\n\nCREATE OR REPLACE FUNCTION DeleteStorage(PARAM_GRAINIDHASH IN NUMBER, PARAM_GRAINIDN0 IN NUMBER, PARAM_GRAINIDN1 IN NUMBER, PARAM_GRAINTYPEHASH IN NUMBER, PARAM_GRAINTYPESTRING IN NVARCHAR2,\n                                             PARAM_GRAINIDEXTENSIONSTRING IN NVARCHAR2, PARAM_SERVICEID IN VARCHAR2, PARAM_GRAINSTATEVERSION IN NUMBER)\n  RETURN NUMBER IS\n  rowcount NUMBER;\n  newGrainStateVersion NUMBER := PARAM_GRAINSTATEVERSION;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    DELETE FROM OrleansStorage\n    WHERE GrainIdHash = PARAM_GRAINIDHASH AND PARAM_GRAINIDHASH IS NOT NULL\n      AND GrainTypeHash = PARAM_GRAINTYPEHASH AND PARAM_GRAINTYPEHASH IS NOT NULL\n      AND (GrainIdN0 = PARAM_GRAINIDN0 OR PARAM_GRAINIDN0 IS NULL)\n      AND (GrainIdN1  = PARAM_GRAINIDN1 OR PARAM_GRAINIDN1 IS NULL)\n      AND (GrainTypeString = PARAM_GRAINTYPESTRING OR PARAM_GRAINTYPESTRING IS NULL)\n      AND ((PARAM_GRAINIDEXTENSIONSTRING IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = PARAM_GRAINIDEXTENSIONSTRING) OR PARAM_GRAINIDEXTENSIONSTRING IS NULL AND GrainIdExtensionString IS NULL)\n      AND ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n      AND Version IS NOT NULL AND Version = PARAM_GRAINSTATEVERSION AND PARAM_GRAINSTATEVERSION IS NOT NULL;\n\n    rowCount := SQL%ROWCOUNT;\n\n    IF rowCount > 0 THEN\n        newGrainStateVersion := PARAM_GRAINSTATEVERSION + 1;\n    END IF;\n\n    COMMIT;\n    RETURN(newGrainStateVersion);\n  END;\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'WriteToStorageKey','\n  SELECT WriteToStorage(:GrainIdHash, :GrainIdN0, :GrainIdN1, :GrainTypeHash, :GrainTypeString,\n                                             :GrainIdExtensionString, :ServiceId, :GrainStateVersion, :PayloadBinary)\n                                             AS NewGrainStateVersion FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ClearStorageKey',\n    'SELECT ClearStorage(:GrainIdHash, :GrainIdN0, :GrainIdN1, :GrainTypeHash, :GrainTypeString,\n                                             :GrainIdExtensionString, :ServiceId, :GrainStateVersion) AS Version FROM DUAL'\n);\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteStorageKey',\n    'SELECT DeleteStorage(:GrainIdHash, :GrainIdN0, :GrainIdN1, :GrainTypeHash, :GrainTypeString,\n                                             :GrainIdExtensionString, :ServiceId, :GrainStateVersion) AS Version FROM DUAL'\n);\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadFromStorageKey',\n    '\n     SELECT PayloadBinary, Version\n     FROM OrleansStorage\n     WHERE GrainIdHash = :GrainIdHash AND :GrainIdHash IS NOT NULL\n       AND (GrainIdN0 = :GrainIdN0 OR :GrainIdN0 IS NULL)\n       AND (GrainIdN1 = :GrainIdN1 OR :GrainIdN1 IS NULL)\n       AND GrainTypeHash = :GrainTypeHash AND :GrainTypeHash IS NOT NULL\n       AND (GrainTypeString = :GrainTypeString OR :GrainTypeString IS NULL)\n       AND ((:GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = :GrainIdExtensionString) OR :GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n       AND ServiceId = :ServiceId AND :ServiceId IS NOT NULL'\n);\n/\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Orleans.Persistence.AdoNet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Persistence.AdoNet</PackageId>\n    <Title>Microsoft Orleans ADO.NET Persistence Provider</Title>\n    <Description>Microsoft Orleans persistence providers backed by ADO.NET</Description>\n    <PackageTags>$(PackageTags) ADO.NET SQL MySQL PostgreSQL Oracle</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Persistence.AdoNet</AssemblyName>\n    <RootNamespace>Orleans.Persistence.AdoNet</RootNamespace>\n    <DefineConstants>$(DefineConstants);PERSISTENCE_ADONET</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/PostgreSQL-Persistence.sql",
    "content": "CREATE TABLE OrleansStorage\n(\n    grainidhash integer NOT NULL,\n    grainidn0 bigint NOT NULL,\n    grainidn1 bigint NOT NULL,\n    graintypehash integer NOT NULL,\n    graintypestring character varying(512)  NOT NULL,\n    grainidextensionstring character varying(512) ,\n    serviceid character varying(150)  NOT NULL,\n    payloadbinary bytea,\n    modifiedon timestamp without time zone NOT NULL,\n    version integer\n);\n\nCREATE INDEX ix_orleansstorage\n    ON orleansstorage USING btree\n    (grainidhash, graintypehash);\n\nCREATE OR REPLACE FUNCTION writetostorage(\n    _grainidhash integer,\n    _grainidn0 bigint,\n    _grainidn1 bigint,\n    _graintypehash integer,\n    _graintypestring character varying,\n    _grainidextensionstring character varying,\n    _serviceid character varying,\n    _grainstateversion integer,\n    _payloadbinary bytea)\n    RETURNS TABLE(newgrainstateversion integer)\n    LANGUAGE 'plpgsql'\nAS $function$\n    DECLARE\n     _newGrainStateVersion integer := _GrainStateVersion;\n     RowCountVar integer := 0;\n\n    BEGIN\n\n    -- Grain state is not null, so the state must have been read from the storage before.\n    -- Let's try to update it.\n    --\n    -- When Orleans is running in normal, non-split state, there will\n    -- be only one grain with the given ID and type combination only. This\n    -- grain saves states mostly serially if Orleans guarantees are upheld. Even\n    -- if not, the updates should work correctly due to version number.\n    --\n    -- In split brain situations there can be a situation where there are two or more\n    -- grains with the given ID and type combination. When they try to INSERT\n    -- concurrently, the table needs to be locked pessimistically before one of\n    -- the grains gets @GrainStateVersion = 1 in return and the other grains will fail\n    -- to update storage. The following arrangement is made to reduce locking in normal operation.\n    --\n    -- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed\n    -- and throws an InconsistentStateException.\n    --\n    -- See further information at https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence.\n    IF _GrainStateVersion IS NOT NULL\n    THEN\n        UPDATE OrleansStorage\n        SET\n            PayloadBinary = _PayloadBinary,\n            ModifiedOn = (now() at time zone 'utc'),\n            Version = Version + 1\n\n        WHERE\n            GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n            AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n            AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n            AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n            AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n            AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n            AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n            AND Version IS NOT NULL AND Version = _GrainStateVersion AND _GrainStateVersion IS NOT NULL;\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n        IF RowCountVar > 0\n        THEN\n            _newGrainStateVersion := _GrainStateVersion + 1;\n        END IF;\n    END IF;\n\n    -- The grain state has not been read. The following locks rather pessimistically\n    -- to ensure only one INSERT succeeds.\n    IF _GrainStateVersion IS NULL\n    THEN\n        INSERT INTO OrleansStorage\n        (\n            GrainIdHash,\n            GrainIdN0,\n            GrainIdN1,\n            GrainTypeHash,\n            GrainTypeString,\n            GrainIdExtensionString,\n            ServiceId,\n            PayloadBinary,\n            ModifiedOn,\n            Version\n        )\n        SELECT\n            _GrainIdHash,\n            _GrainIdN0,\n            _GrainIdN1,\n            _GrainTypeHash,\n            _GrainTypeString,\n            _GrainIdExtensionString,\n            _ServiceId,\n            _PayloadBinary,\n           (now() at time zone 'utc'),\n            1\n        WHERE NOT EXISTS\n         (\n            -- There should not be any version of this grain state.\n            SELECT 1\n            FROM OrleansStorage\n            WHERE\n                GrainIdHash = _GrainIdHash AND _GrainIdHash IS NOT NULL\n                AND GrainTypeHash = _GrainTypeHash AND _GrainTypeHash IS NOT NULL\n                AND GrainIdN0 = _GrainIdN0 AND _GrainIdN0 IS NOT NULL\n                AND GrainIdN1 = _GrainIdN1 AND _GrainIdN1 IS NOT NULL\n                AND GrainTypeString = _GrainTypeString AND _GrainTypeString IS NOT NULL\n                AND ((_GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = _GrainIdExtensionString) OR _GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n                AND ServiceId = _ServiceId AND _ServiceId IS NOT NULL\n         );\n\n        GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n        IF RowCountVar > 0\n        THEN\n            _newGrainStateVersion := 1;\n        END IF;\n    END IF;\n\n    RETURN QUERY SELECT _newGrainStateVersion AS NewGrainStateVersion;\nEND\n\n$function$;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'WriteToStorageKey','\n\n        select * from WriteToStorage(@GrainIdHash, @GrainIdN0, @GrainIdN1, @GrainTypeHash, @GrainTypeString, @GrainIdExtensionString, @ServiceId, @GrainStateVersion, @PayloadBinary);\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadFromStorageKey','\n    SELECT\n        PayloadBinary,\n        (now() at time zone ''utc''),\n        Version\n    FROM\n        OrleansStorage\n    WHERE\n        GrainIdHash = @GrainIdHash\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = @GrainIdN0 AND @GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = @GrainIdN1 AND @GrainIdN1 IS NOT NULL\n        AND GrainTypeString = @GrainTypeString AND GrainTypeString IS NOT NULL\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ClearStorageKey','\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = NULL,\n        Version = Version + 1\n    WHERE\n        GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = @GrainIdN0 AND @GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = @GrainIdN1 AND @GrainIdN1 IS NOT NULL\n        AND GrainTypeString = @GrainTypeString AND @GrainTypeString IS NOT NULL\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = @GrainStateVersion AND @GrainStateVersion IS NOT NULL\n    Returning Version as NewGrainStateVersion\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteStorageKey','\n    DELETE FROM OrleansStorage\n    WHERE\n        GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND GrainIdN0 = @GrainIdN0 AND @GrainIdN0 IS NOT NULL\n        AND GrainIdN1 = @GrainIdN1 AND @GrainIdN1 IS NOT NULL\n        AND GrainTypeString = @GrainTypeString AND @GrainTypeString IS NOT NULL\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = @GrainStateVersion AND @GrainStateVersion IS NOT NULL\n    Returning Version + 1 as NewGrainStateVersion\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/README.md",
    "content": "# Microsoft Orleans Persistence for ADO.NET\n\n## Introduction\nMicrosoft Orleans Persistence for ADO.NET provides grain persistence for Microsoft Orleans using relational databases through ADO.NET. This provider allows your grains to persist their state in various relational databases including SQL Server, MySQL, PostgreSQL, and Oracle.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Persistence.AdoNet\n```\n\nYou will also need to install the appropriate database driver package for your database system:\n\n- SQL Server: `Microsoft.Data.SqlClient`\n- MySQL: `MySql.Data` or `MySqlConnector`\n- PostgreSQL: `Npgsql`\n- Oracle: `Oracle.ManagedDataAccess.Core`\n- SQLite: `Microsoft.Data.Sqlite`\n\n## Example - Configuring ADO.NET Persistence\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure ADO.NET as grain storage\n            .AddAdoNetGrainStorage(\n                name: \"AdoNetStore\",\n                configureOptions: options =>\n                {\n                    options.Invariant = \"Microsoft.Data.SqlClient\";  // Or other providers like \"MySql.Data.MySqlClient\", \"Npgsql\", etc.\n                    options.ConnectionString = \"Server=localhost;Database=OrleansStorage;User Id=myUsername;******;\";\n                    // Optional: Configure custom queries\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Grain Storage in a Grain\n\n```csharp\nusing System;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\n\n// Define grain state class\npublic class MyGrainState\n{\n    public string Data { get; set; }\n    public int Version { get; set; }\n}\n\n// Grain implementation that uses the ADO.NET storage\npublic class MyGrain : Grain, IMyGrain, IGrainWithStringKey\n{\n    private readonly IPersistentState<MyGrainState> _state;\n\n    public MyGrain([PersistentState(\"state\", \"AdoNetStore\")] IPersistentState<MyGrainState> state)\n    {\n        _state = state;\n    }\n\n    public async Task SetData(string data)\n    {\n        _state.State.Data = data;\n        _state.State.Version++;\n        await _state.WriteStateAsync();\n    }\n\n    public Task<string> GetData()\n    {\n        return Task.FromResult(_state.State.Data);\n    }\n}\n```\n\n## Database Setup\n\nBefore using the ADO.NET provider, you need to set up the necessary database tables. Scripts for different database systems are available in the Orleans source repository:\n\n- [SQL Server Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Persistence.AdoNet/SQLServer-Persistence.sql)\n- [MySQL Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Persistence.AdoNet/MySQL-Persistence.sql)\n- [PostgreSQL Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Persistence.AdoNet/PostgreSQL-Persistence.sql)\n- [Oracle Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Persistence.AdoNet/Oracle-Persistence.sql)\n- [SQLite Scripts](https://github.com/dotnet/orleans/tree/main/src/AdoNet/Orleans.Persistence.AdoNet/Sqlite-Persistence.sql)\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n- [Relational Database Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence/relational-storage)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/SQLServer-Persistence.sql",
    "content": "-- The design criteria for this table are:\n--\n-- 1. It can contain arbitrary content serialized as binary, XML or JSON. These formats\n-- are supported to allow one to take advantage of in-storage processing capabilities for\n-- these types if required. This should not incur extra cost on storage.\n--\n-- 2. The table design should scale with the idea of tens or hundreds (or even more) types\n-- of grains that may operate with even hundreds of thousands of grain IDs within each\n-- type of a grain.\n--\n-- 3. The table and its associated operations should remain stable. There should not be\n-- structural reason for unexpected delays in operations. It should be possible to also\n-- insert data reasonably fast without resource contention.\n--\n-- 4. For reasons in 2. and 3., the index should be as narrow as possible so it fits well in\n-- memory and should it require maintenance, isn't resource intensive. For this\n-- reason the index is narrow by design (ideally non-clustered). Currently the entity\n-- is recognized in the storage by the grain type and its ID, which are unique in Orleans silo.\n-- The ID is the grain ID bytes (if string type UTF-8 bytes) and possible extension key as UTF-8\n-- bytes concatenated with the ID and then hashed.\n--\n-- Reason for hashing: Database engines usually limit the length of the column sizes, which\n-- would artificially limit the length of IDs or types. Even when within limitations, the\n-- index would be thick and consume more memory.\n--\n-- In the current setup the ID and the type are hashed into two INT type instances, which\n-- are made a compound index. When there are no collisions, the index can quickly locate\n-- the unique row. Along with the hashed index values, the NVARCHAR(nnn) values are also\n-- stored and they are used to prune hash collisions down to only one result row.\n--\n-- 5. The design leads to duplication in the storage. It is reasonable to assume there will\n-- a low number of services with a given service ID operational at any given time. Or that\n-- compared to the number of grain IDs, there are a fairly low number of different types of\n-- grain. The catch is that were these data separated to another table, it would make INSERT\n-- and UPDATE operations complicated and would require joins, temporary variables and additional\n-- indexes or some combinations of them to make it work. It looks like fitting strategy\n-- could be to use table compression.\n--\n-- 6. For the aforementioned reasons, grain state DELETE will set NULL to the data fields\n-- and updates the Version number normally. This should alleviate the need for index or\n-- statistics maintenance with the loss of some bytes of storage space. The table can be scrubbed\n-- in a separate maintenance operation.\n--\n-- 7. In the storage operations queries the columns need to be in the exact same order\n-- since the storage table operations support optionally streaming.\nIF OBJECT_ID(N'[OrleansStorage]', 'U') IS NULL\nCREATE TABLE OrleansStorage\n(\n    -- These are for the book keeping. Orleans calculates\n    -- these hashes (see RelationalStorageProvide implementation),\n    -- which are signed 32 bit integers mapped to the *Hash fields.\n    -- The mapping is done in the code. The\n    -- *String columns contain the corresponding clear name fields.\n    --\n    -- If there are duplicates, they are resolved by using GrainIdN0,\n    -- GrainIdN1, GrainIdExtensionString and GrainTypeString fields.\n    -- It is assumed these would be rarely needed.\n    GrainIdHash                INT NOT NULL,\n    GrainIdN0                BIGINT NOT NULL,\n    GrainIdN1                BIGINT NOT NULL,\n    GrainTypeHash            INT NOT NULL,\n    GrainTypeString            NVARCHAR(512) NOT NULL,\n    GrainIdExtensionString    NVARCHAR(512) NULL,\n    ServiceId                NVARCHAR(150) NOT NULL,\n\n    -- Payload\n    PayloadBinary    VARBINARY(MAX) NULL,\n\n    -- Informational field, no other use.\n    ModifiedOn DATETIME2(3) NOT NULL,\n\n    -- The version of the stored payload.\n    Version INT NULL\n\n    -- The following would in principle be the primary key, but it would be too thick\n    -- to be indexed, so the values are hashed and only collisions will be solved\n    -- by using the fields. That is, after the indexed queries have pinpointed the right\n    -- rows down to [0, n] relevant ones, n being the number of collided value pairs.\n);\n\nIF NOT EXISTS(SELECT * FROM sys.indexes WHERE name = 'IX_OrleansStorage' AND object_id = OBJECT_ID('OrleansStorage'))\nBEGIN\n\tCREATE NONCLUSTERED INDEX IX_OrleansStorage ON OrleansStorage(GrainIdHash, GrainTypeHash);\nEND\n\n-- This ensures lock escalation will not lock the whole table, which can potentially be enormous.\n-- See more information at https://www.littlekendra.com/2016/02/04/why-rowlock-hints-can-make-queries-slower-and-blocking-worse-in-sql-server/.\nALTER TABLE OrleansStorage SET(LOCK_ESCALATION = DISABLE);\n\n-- A feature with ID is compression. If it is supported, it is used for OrleansStorage table. This is an Enterprise feature.\n-- This consumes more processor cycles, but should save on space on GrainIdString, GrainTypeString and ServiceId, which\n-- contain mainly the same values. Also the payloads will be compressed.\nIF EXISTS (SELECT 1 FROM sys.dm_db_persisted_sku_features WHERE feature_id = 100)\nBEGIN\n    ALTER TABLE OrleansStorage REBUILD PARTITION = ALL WITH(DATA_COMPRESSION = PAGE);\nEND\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n    'WriteToStorageKey',\n    '-- When Orleans is running in normal, non-split state, there will\n    -- be only one grain with the given ID and type combination only. This\n    -- grain saves states mostly serially if Orleans guarantees are upheld. Even\n    -- if not, the updates should work correctly due to version number.\n    --\n    -- In split brain situations there can be a situation where there are two or more\n    -- grains with the given ID and type combination. When they try to INSERT\n    -- concurrently, the table needs to be locked pessimistically before one of\n    -- the grains gets @GrainStateVersion = 1 in return and the other grains will fail\n    -- to update storage. The following arrangement is made to reduce locking in normal operation.\n    --\n    -- If the version number explicitly returned is still the same, Orleans interprets it so the update did not succeed\n    -- and throws an InconsistentStateException.\n    --\n    -- See further information at https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence.\n    BEGIN TRANSACTION;\n    SET XACT_ABORT, NOCOUNT ON;\n\n    DECLARE @NewGrainStateVersion AS INT = @GrainStateVersion;\n\n\n    -- If the @GrainStateVersion is not zero, this branch assumes it exists in this database.\n    -- The NULL value is supplied by Orleans when the state is new.\n    IF @GrainStateVersion IS NOT NULL\n    BEGIN\n        UPDATE OrleansStorage\n        SET\n            PayloadBinary = @PayloadBinary,\n            ModifiedOn = GETUTCDATE(),\n            Version = Version + 1,\n            @NewGrainStateVersion = Version + 1,\n            @GrainStateVersion = Version + 1\n        WHERE\n            GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n            AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n            AND (GrainIdN0 = @GrainIdN0 OR @GrainIdN0 IS NULL)\n            AND (GrainIdN1 = @GrainIdN1 OR @GrainIdN1 IS NULL)\n            AND (GrainTypeString = @GrainTypeString OR @GrainTypeString IS NULL)\n            AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n            AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n            AND Version IS NOT NULL AND Version = @GrainStateVersion AND @GrainStateVersion IS NOT NULL\n            OPTION(FAST 1, OPTIMIZE FOR(@GrainIdHash UNKNOWN, @GrainTypeHash UNKNOWN));\n    END\n\n    -- The grain state has not been read. The following locks rather pessimistically\n    -- to ensure only one INSERT succeeds.\n    IF @GrainStateVersion IS NULL\n    BEGIN\n        INSERT INTO OrleansStorage\n        (\n            GrainIdHash,\n            GrainIdN0,\n            GrainIdN1,\n            GrainTypeHash,\n            GrainTypeString,\n            GrainIdExtensionString,\n            ServiceId,\n            PayloadBinary,\n            ModifiedOn,\n            Version\n        )\n        SELECT\n            @GrainIdHash,\n            @GrainIdN0,\n            @GrainIdN1,\n            @GrainTypeHash,\n            @GrainTypeString,\n            @GrainIdExtensionString,\n            @ServiceId,\n            @PayloadBinary,\n            GETUTCDATE(),\n            1\n         WHERE NOT EXISTS\n         (\n            -- There should not be any version of this grain state.\n            SELECT 1\n            FROM OrleansStorage WITH(XLOCK, ROWLOCK, HOLDLOCK, INDEX(IX_OrleansStorage))\n            WHERE\n                GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n                AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n                AND (GrainIdN0 = @GrainIdN0 OR @GrainIdN0 IS NULL)\n                AND (GrainIdN1 = @GrainIdN1 OR @GrainIdN1 IS NULL)\n                AND (GrainTypeString = @GrainTypeString OR @GrainTypeString IS NULL)\n                AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n                AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n         ) OPTION(FAST 1, OPTIMIZE FOR(@GrainIdHash UNKNOWN, @GrainTypeHash UNKNOWN));\n\n        IF @@ROWCOUNT > 0\n        BEGIN\n            SET @NewGrainStateVersion = 1;\n        END\n    END\n\n    SELECT @NewGrainStateVersion AS NewGrainStateVersion;\n    COMMIT TRANSACTION;'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'WriteToStorageKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n    'ClearStorageKey',\n    'BEGIN TRANSACTION;\n    SET XACT_ABORT, NOCOUNT ON;\n    DECLARE @NewGrainStateVersion AS INT = @GrainStateVersion;\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = NULL,\n        ModifiedOn = GETUTCDATE(),\n        Version = Version + 1,\n        @NewGrainStateVersion = Version + 1\n    WHERE\n        GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND (GrainIdN0 = @GrainIdN0 OR @GrainIdN0 IS NULL)\n        AND (GrainIdN1 = @GrainIdN1 OR @GrainIdN1 IS NULL)\n        AND (GrainTypeString = @GrainTypeString OR @GrainTypeString IS NULL)\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = @GrainStateVersion AND @GrainStateVersion IS NOT NULL\n        OPTION(FAST 1, OPTIMIZE FOR(@GrainIdHash UNKNOWN, @GrainTypeHash UNKNOWN));\n\n    SELECT @NewGrainStateVersion;\n    COMMIT TRANSACTION;'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ClearStorageKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n    'ReadFromStorageKey',\n    '-- The application code will deserialize the relevant result. Not that the query optimizer\n    -- estimates the result of rows based on its knowledge on the index. It does not know there\n    -- will be only one row returned. Forcing the optimizer to process the first found row quickly\n    -- creates an estimate for a one-row result and makes a difference on multi-million row tables.\n    -- Also the optimizer is instructed to always use the same plan via index using the OPTIMIZE\n    -- FOR UNKNOWN flags. These hints are only available in SQL Server 2008 and later. They\n    -- should guarantee the execution time is robustly basically the same from query-to-query.\n    SELECT\n        PayloadBinary,\n        Version\n    FROM\n        OrleansStorage\n    WHERE\n        GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND (GrainIdN0 = @GrainIdN0 OR @GrainIdN0 IS NULL)\n        AND (GrainIdN1 = @GrainIdN1 OR @GrainIdN1 IS NULL)\n        AND (GrainTypeString = @GrainTypeString OR @GrainTypeString IS NULL)\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        OPTION(FAST 1, OPTIMIZE FOR(@GrainIdHash UNKNOWN, @GrainTypeHash UNKNOWN));'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ReadFromStorageKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n    'DeleteStorageKey',\n    'BEGIN TRANSACTION;\n    SET XACT_ABORT, NOCOUNT ON;\n    DELETE FROM OrleansStorage OUTPUT DELETED.Version + 1\n    WHERE\n        GrainIdHash = @GrainIdHash AND @GrainIdHash IS NOT NULL\n        AND GrainTypeHash = @GrainTypeHash AND @GrainTypeHash IS NOT NULL\n        AND (GrainIdN0 = @GrainIdN0 OR @GrainIdN0 IS NULL)\n        AND (GrainIdN1 = @GrainIdN1 OR @GrainIdN1 IS NULL)\n        AND (GrainTypeString = @GrainTypeString OR @GrainTypeString IS NULL)\n        AND ((@GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString IS NOT NULL AND GrainIdExtensionString = @GrainIdExtensionString) OR @GrainIdExtensionString IS NULL AND GrainIdExtensionString IS NULL)\n        AND ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND Version IS NOT NULL AND Version = @GrainStateVersion AND @GrainStateVersion IS NOT NULL\n        OPTION(FAST 1, OPTIMIZE FOR(@GrainIdHash UNKNOWN, @GrainTypeHash UNKNOWN));\n\n    COMMIT TRANSACTION;'\nWHERE NOT EXISTS\n(\n    SELECT 1\n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'DeleteStorageKey'\n);\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Sqlite-Persistence.sql",
    "content": "-- The design criteria for this table are:\n--\n-- 1. It can contain arbitrary content serialized as binary, XML or JSON. These formats\n-- are supported to allow one to take advantage of in-storage processing capabilities for\n-- these types if required. This should not incur extra cost on storage.\n--\n-- 2. The table design should scale with the idea of tens or hundreds (or even more) types\n-- of grains that may operate with even hundreds of thousands of grain IDs within each\n-- type of a grain.\n--\n-- 3. The table and its associated operations should remain stable. There should not be\n-- structural reason for unexpected delays in operations. It should be possible to also\n-- insert data reasonably fast without resource contention.\n--\n-- 4. For reasons in 2. and 3., the index should be as narrow as possible so it fits well in\n-- memory and should it require maintenance, isn't resource intensive. For this\n-- reason the index is narrow by design (ideally non-clustered). Currently the entity\n-- is recognized in the storage by the grain type and its ID, which are unique in Orleans silo.\n-- The ID is the grain ID bytes (if string type UTF-8 bytes) and possible extension key as UTF-8\n-- bytes concatenated with the ID and then hashed.\n--\n-- Reason for hashing: Database engines usually limit the length of the column sizes, which\n-- would artificially limit the length of IDs or types. Even when within limitations, the\n-- index would be thick and consume more memory.\n--\n-- In the current setup the ID and the type are hashed into two INT type instances, which\n-- are made a compound index. When there are no collisions, the index can quickly locate\n-- the unique row. Along with the hashed index values, the NVARCHAR(nnn) values are also\n-- stored and they are used to prune hash collisions down to only one result row.\n--\n-- 5. The design leads to duplication in the storage. It is reasonable to assume there will\n-- a low number of services with a given service ID operational at any given time. Or that\n-- compared to the number of grain IDs, there are a fairly low number of different types of\n-- grain. The catch is that were these data separated to another table, it would make INSERT\n-- and UPDATE operations complicated and would require joins, temporary variables and additional\n-- indexes or some combinations of them to make it work. It looks like fitting strategy\n-- could be to use table compression.\n--\n-- 6. For the aforementioned reasons, grain state DELETE will set NULL to the data fields\n-- and updates the Version number normally. This should alleviate the need for index or\n-- statistics maintenance with the loss of some bytes of storage space. The table can be scrubbed\n-- in a separate maintenance operation.\n--\n-- 7. In the storage operations queries the columns need to be in the exact same order\n-- since the storage table operations support optionally streaming.\nCREATE TABLE OrleansStorage\n(\n    -- These are for the book keeping. Orleans calculates\n    -- these hashes (see RelationalStorageProvide implementation),\n    -- which are signed 32 bit integers mapped to the *Hash fields.\n    -- The mapping is done in the code. The\n    -- *String columns contain the corresponding clear name fields.\n    --\n    -- If there are duplicates, they are resolved by using GrainIdN0,\n    -- GrainIdN1, GrainIdExtensionString and GrainTypeString fields.\n    -- It is assumed these would be rarely needed.\n    GrainIdHash                INT NOT NULL,\n    GrainIdN0                BIGINT NOT NULL,\n    GrainIdN1                BIGINT NOT NULL,\n    GrainTypeHash            INT NOT NULL,\n    GrainTypeString            NVARCHAR(512) NOT NULL,\n    GrainIdExtensionString    NVARCHAR(512) NULL,\n    ServiceId                NVARCHAR(150) NOT NULL,\n    -- Payload\n    PayloadBinary    BLOB NULL,\n    -- Informational field, no other use.\n    ModifiedOn DATETIME NOT NULL,\n    -- The version of the stored payload.\n    Version INT NULL\n    -- The following would in principle be the primary key, but it would be too thick\n    -- to be indexed, so the values are hashed and only collisions will be solved\n    -- by using the fields. That is, after the indexed queries have pinpointed the right\n    -- rows down to [0, n] relevant ones, n being the number of collided value pairs.\n);\n\nCREATE INDEX IX_OrleansStorage ON OrleansStorage(GrainIdHash, GrainTypeHash);\n\n\n-- Updates an existing grain state with optimistic concurrency control or inserts it if it does not exist.\nINSERT INTO OrleansQuery (QueryKey, QueryText) VALUES \n('WriteToStorageKey', '\n    BEGIN TRANSACTION;\n\n    CREATE TEMP TABLE IF NOT EXISTS OrleansStorageWriteState\n    (\n        TotalChangesBefore INT NOT NULL\n    );\n    DELETE FROM OrleansStorageWriteState;\n    INSERT INTO OrleansStorageWriteState (TotalChangesBefore) VALUES (total_changes() + 1);\n\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = @PayloadBinary,\n        ModifiedOn = datetime(''now''),\n        Version = Version + 1\n    WHERE\n        GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId\n        AND Version = @GrainStateVersion;\n\n    INSERT INTO OrleansStorage (GrainIdHash, GrainIdN0, GrainIdN1, GrainTypeHash, GrainTypeString, GrainIdExtensionString, ServiceId, PayloadBinary, ModifiedOn, Version)\n    SELECT @GrainIdHash, @GrainIdN0, @GrainIdN1, @GrainTypeHash, @GrainTypeString, @GrainIdExtensionString, @ServiceId, @PayloadBinary, datetime(''now''), 1\n    WHERE changes() = 0\n      AND @GrainStateVersion IS NULL\n      AND NOT EXISTS (\n        SELECT 1 FROM OrleansStorage\n        WHERE GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId\n    );\n\n    SELECT Version AS NewGrainStateVersion FROM OrleansStorage\n    WHERE total_changes() > (SELECT TotalChangesBefore FROM OrleansStorageWriteState LIMIT 1)\n        AND GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId;\n\n    SELECT @GrainStateVersion AS NewGrainStateVersion\n    WHERE total_changes() = (SELECT TotalChangesBefore FROM OrleansStorageWriteState LIMIT 1)\n        AND @GrainStateVersion IS NOT NULL;\n\n    COMMIT;\n');\n\n-- Retrieves the binary payload and the current version of a specific grain state.\nINSERT INTO OrleansQuery (QueryKey, QueryText) VALUES \n('ReadFromStorageKey', '\n    SELECT\n        PayloadBinary,\n        Version AS Version\n    FROM\n        OrleansStorage\n    WHERE\n        GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId\n    LIMIT 1;\n');\n\n-- Clears the grain state by setting the payload to null and incrementing the version for consistency.\nINSERT INTO OrleansQuery (QueryKey, QueryText) VALUES \n('ClearStorageKey', '\n    UPDATE OrleansStorage\n    SET\n        PayloadBinary = NULL,\n        ModifiedOn = datetime(''now''),\n        Version = Version + 1\n    WHERE\n        GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId\n        AND Version = @GrainStateVersion;\n\n    SELECT Version AS NewGrainStateVersion FROM OrleansStorage\n    WHERE changes() > 0\n        AND GrainIdHash = @GrainIdHash AND GrainTypeHash = @GrainTypeHash\n        AND GrainIdN0 = @GrainIdN0 AND GrainIdN1 = @GrainIdN1\n        AND GrainTypeString = @GrainTypeString\n        AND (GrainIdExtensionString = @GrainIdExtensionString OR (GrainIdExtensionString IS NULL AND @GrainIdExtensionString IS NULL))\n        AND ServiceId = @ServiceId;\n\n    SELECT @GrainStateVersion AS NewGrainStateVersion\n    WHERE changes() = 0\n        AND @GrainStateVersion IS NOT NULL;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/AdoGrainKey.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Text;\n\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// This is an internal helper class that collects grain key information\n    /// so that's easier to manage during database operations.\n    /// </summary>\n    internal class AdoGrainKey\n    {\n        public long N0Key { get; }\n\n        public long N1Key { get; }\n\n        public string StringKey { get; }\n\n        public bool IsLongKey { get; }\n\n        public bool IsGuidKey { get; }\n\n        public bool IsStringKey { get; }\n\n        public AdoGrainKey(long key, string keyExtension)\n        {\n            N0Key = 0;\n            N1Key = key;\n            StringKey = keyExtension;\n\n            IsLongKey = true;\n            IsGuidKey = false;\n            IsStringKey = false;\n        }\n\n        public AdoGrainKey(Guid key, string keyExtension)\n        {\n            var guidKeyBytes = key.ToByteArray();\n            N0Key = BitConverter.ToInt64(guidKeyBytes, 0);\n            N1Key = BitConverter.ToInt64(guidKeyBytes, 8);\n            StringKey = keyExtension;\n\n            IsLongKey = false;\n            IsGuidKey = true;\n            IsStringKey = false;\n        }\n\n        public AdoGrainKey(string key)\n        {\n            StringKey = key;\n            N0Key = 0;\n            N1Key = 0;\n\n            IsLongKey = false;\n            IsGuidKey = false;\n            IsStringKey = true;\n        }\n\n        public byte[] GetHashBytes()\n        {\n            byte[] bytes = null;\n            if(IsLongKey)\n            {\n                bytes = BitConverter.GetBytes(N1Key);\n            }\n            else if(IsGuidKey)\n            {\n                bytes = ToGuidKey(N0Key, N1Key).ToByteArray();\n            }\n\n            if(bytes != null && StringKey != null)\n            {\n                int oldLen = bytes.Length;\n                var stringBytes = Encoding.UTF8.GetBytes(StringKey);\n                Array.Resize(ref bytes, bytes.Length + stringBytes.Length);\n                Array.Copy(stringBytes, 0, bytes, oldLen, stringBytes.Length);\n            }\n\n            if(bytes == null)\n            {\n                bytes = Encoding.UTF8.GetBytes(StringKey);\n            }\n\n            if(BitConverter.IsLittleEndian)\n            {\n                Array.Reverse(bytes);\n            }\n\n            return bytes;\n        }\n\n        public override string ToString()\n        {\n            string primaryKey;\n            string keyExtension = null;\n            if(IsLongKey)\n            {\n                primaryKey = N1Key.ToString(CultureInfo.InvariantCulture);\n                keyExtension = StringKey;\n            }\n            else if(IsGuidKey)\n            {\n                primaryKey = ToGuidKey(N0Key, N1Key).ToString();\n                keyExtension = StringKey;\n            }\n            else\n            {\n                primaryKey = StringKey;\n            }\n\n            const string GrainIdAndExtensionSeparator = \"#\";\n            return string.Format($\"{primaryKey}{(keyExtension != null ? GrainIdAndExtensionSeparator + keyExtension : string.Empty)}\");\n        }\n\n        private static Guid ToGuidKey(long n0Key, long n1Key)\n        {\n            return new Guid((uint)(n0Key & 0xffffffff), (ushort)(n0Key >> 32), (ushort)(n0Key >> 48), (byte)n1Key, (byte)(n1Key >> 8), (byte)(n1Key >> 16), (byte)(n1Key >> 24), (byte)(n1Key >> 32), (byte)(n1Key >> 40), (byte)(n1Key >> 48), (byte)(n1Key >> 56));\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/AdoNetGrainStorage.cs",
    "content": "using Orleans.Persistence.AdoNet.Storage;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration.Overrides;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Configuration;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Logging codes used by <see cref=\"AdoNetGrainStorage\"/>.\n    /// </summary>\n    /// <remarks> These are taken from <em>Orleans.Providers.ProviderErrorCode</em> and <em>Orleans.Providers.AzureProviderErrorCode</em>.</remarks>\n    internal enum RelationalStorageProviderCodes\n    {\n        //These is from Orleans.Providers.ProviderErrorCode and Orleans.Providers.AzureProviderErrorCode.\n        ProvidersBase = 200000,\n\n        RelationalProviderBase = ProvidersBase + 400,\n        RelationalProviderDeleteError = RelationalProviderBase + 8,\n        RelationalProviderInitProvider = RelationalProviderBase + 9,\n        RelationalProviderNoDeserializer = RelationalProviderBase + 10,\n        RelationalProviderNoStateFound = RelationalProviderBase + 11,\n        RelationalProviderClearing = RelationalProviderBase + 12,\n        RelationalProviderCleared = RelationalProviderBase + 13,\n        RelationalProviderReading = RelationalProviderBase + 14,\n        RelationalProviderRead = RelationalProviderBase + 15,\n        RelationalProviderReadError = RelationalProviderBase + 16,\n        RelationalProviderWriting = RelationalProviderBase + 17,\n        RelationalProviderWrote = RelationalProviderBase + 18,\n        RelationalProviderWriteError = RelationalProviderBase + 19\n    }\n\n    public static class AdoNetGrainStorageFactory\n    {\n        public static AdoNetGrainStorage Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<AdoNetGrainStorageOptions>>();\n            var clusterOptions = services.GetProviderClusterOptions(name);\n            return ActivatorUtilities.CreateInstance<AdoNetGrainStorage>(services, Options.Create(optionsMonitor.Get(name)), name, clusterOptions);\n        }\n    }\n\n    /// <summary>\n    /// A storage provider for writing grain state data to relational storage.\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// Configuration is provided through <see cref=\"AdoNetGrainStorageOptions\"/>.\n    /// </para>\n    /// <para>\n    /// Required configuration: <c>ConnectionString</c> - The database connection string.\n    /// </para>\n    /// <para>\n    /// Optional configuration: <c>Invariant</c> - The ADO.NET provider invariant name (defaults to <c>Microsoft.Data.SqlClient</c>).\n    /// </para>\n    /// </remarks>\n    [DebuggerDisplay(\"Name = {Name}, ConnectionString = {Storage.ConnectionString}\")]\n    public partial class AdoNetGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n    {\n        public IGrainStorageSerializer Serializer { get; set; }\n\n        /// <summary>\n        /// Tag for BinaryFormatSerializer\n        /// </summary>\n        public const string BinaryFormatSerializerTag = \"BinaryFormatSerializer\";\n        /// <summary>\n        /// Tag for JsonFormatSerializer\n        /// </summary>\n        public const string JsonFormatSerializerTag = \"JsonFormatSerializer\";\n        /// <summary>\n        /// Tag for XmlFormatSerializer\n        /// </summary>\n        public const string XmlFormatSerializerTag = \"XmlFormatSerializer\";\n\n        /// <summary>\n        /// The Service ID for which this relational provider is used.\n        /// </summary>\n        private readonly string serviceId;\n        private readonly IActivatorProvider _activatorProvider;\n        private readonly ILogger logger;\n\n        /// <summary>\n        /// The storage used for back-end operations.\n        /// </summary>\n        private IRelationalStorage Storage { get; set; }\n\n        /// <summary>\n        /// These chars are delimiters when used to extract a class base type from a class\n        /// that is either <see cref=\"Type.AssemblyQualifiedName\"/> or <see cref=\"Type.FullName\"/>.\n        /// <see cref=\"ExtractBaseClass(string)\"/>.\n        /// </summary>\n        private static char[] BaseClassExtractionSplitDelimeters { get; } = new[] { '[', ']' };\n\n        /// <summary>\n        /// The default query to initialize this structure from the Orleans database.\n        /// </summary>\n        public const string DefaultInitializationQuery = \"SELECT QueryKey, QueryText FROM OrleansQuery WHERE QueryKey = 'WriteToStorageKey' OR QueryKey = 'ReadFromStorageKey' OR QueryKey = 'ClearStorageKey' OR QueryKey = 'DeleteStorageKey'\";\n\n        /// <summary>\n        /// The queries currently used. When this is updated, the new queries will take effect immediately.\n        /// </summary>\n        public RelationalStorageProviderQueries CurrentOperationalQueries { get; set; }\n\n        /// <summary>\n        /// The hash generator used to hash natural keys, grain ID and grain type to a more narrow index.\n        /// </summary>\n        public IStorageHasherPicker HashPicker { get; set; }\n\n        private readonly AdoNetGrainStorageOptions options;\n        private readonly string name;\n\n        public AdoNetGrainStorage(\n            IActivatorProvider activatorProvider,\n            ILogger<AdoNetGrainStorage> logger,\n            IOptions<AdoNetGrainStorageOptions> options,\n            IOptions<ClusterOptions> clusterOptions,\n            string name)\n        {\n            this.options = options.Value;\n            this.name = name;\n            _activatorProvider = activatorProvider;\n            this.logger = logger;\n            this.serviceId = clusterOptions.Value.ServiceId;\n            this.Serializer = options.Value.GrainStorageSerializer;\n            this.HashPicker = options.Value.HashPicker ?? new StorageHasherPicker(new[] { new OrleansDefaultHasher() });\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<AdoNetGrainStorage>(this.name), this.options.InitStage, Init, Close);\n        }\n\n        /// <summary>Clear state data function for this storage provider.</summary>\n        /// <see cref=\"IGrainStorage.ClearStateAsync{T}\"/>.\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainReference, IGrainState<T> grainState)\n        {\n            //It assumed these parameters are always valid. If not, an exception will be thrown,\n            //even if not as clear as when using explicitly checked parameters.\n            var grainId = GrainIdAndExtensionAsString(grainReference);\n            var baseGrainType = ExtractBaseClass(grainType);\n            LogTraceClearingGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n\n            if (!grainState.RecordExists)\n            {\n                await ReadStateAsync(grainType, grainReference, grainState).ConfigureAwait(false);\n                if (!grainState.RecordExists)\n                {\n                    return;\n                }\n            }\n\n            string storageVersion = null;\n            try\n            {\n                var grainIdHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());\n                var grainTypeHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));\n\n                var queryText = options.DeleteStateOnClear ? CurrentOperationalQueries.DeleteState : CurrentOperationalQueries.ClearState;\n\n                // Backward compatibility checks in Init should handle this case and throw prior to reaching this state.\n                if (queryText is null)\n                {\n                    throw new UnreachableException($\"QueryText is null for {nameof(options.DeleteStateOnClear)}={options.DeleteStateOnClear}\");\n                }\n                var clearRecord = (await Storage.ReadAsync(queryText, command =>\n                {\n                    command.AddParameter(\"GrainIdHash\", grainIdHash);\n                    command.AddParameter(\"GrainIdN0\", grainId.N0Key);\n                    command.AddParameter(\"GrainIdN1\", grainId.N1Key);\n                    command.AddParameter(\"GrainTypeHash\", grainTypeHash);\n                    command.AddParameter(\"GrainTypeString\", baseGrainType);\n                    command.AddParameter(\"GrainIdExtensionString\", grainId.StringKey);\n                    command.AddParameter(\"ServiceId\", serviceId);\n                    command.AddParameter(\"GrainStateVersion\", !string.IsNullOrWhiteSpace(grainState.ETag) ? int.Parse(grainState.ETag, CultureInfo.InvariantCulture) : default(int?));\n                }, (selector, resultSetCount, token) => Task.FromResult(selector.GetValue(0).ToString()), cancellationToken: CancellationToken.None).ConfigureAwait(false));\n                storageVersion = clearRecord.SingleOrDefault();\n            }\n            catch (Exception ex)\n            {\n                LogErrorClearingGrainState(ex, serviceId, name, baseGrainType, grainId, grainState.ETag);\n                throw;\n            }\n\n            const string OperationString = \"ClearState\";\n            var inconsistentStateException = CheckVersionInconsistency(OperationString, serviceId, this.name, storageVersion, grainState.ETag, baseGrainType, grainId.ToString());\n            if (inconsistentStateException != null)\n            {\n                throw inconsistentStateException;\n            }\n\n            // When delete on clear is set, ETag should be null since the record was deleted.\n            // The DB script returns deleted record version + 1 as storageVersion for the CheckVersionInconsistency check above.\n            //No errors found, the version of the state held by the grain can be updated and also the state.\n            grainState.ETag = options.DeleteStateOnClear ? null : storageVersion;\n            grainState.RecordExists = false;\n            grainState.State = CreateInstance<T>();\n            LogTraceClearedGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n        }\n\n\n        /// <summary> Read state data function for this storage provider.</summary>\n        /// <see cref=\"IGrainStorage.ReadStateAsync{T}\"/>.\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainReference, IGrainState<T> grainState)\n        {\n            //It assumed these parameters are always valid. If not, an exception will be thrown, even if not as clear\n            //as with explicitly checked parameters.\n            var grainId = GrainIdAndExtensionAsString(grainReference);\n            var baseGrainType = ExtractBaseClass(grainType);\n            LogTraceReadingGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n\n            try\n            {\n                var commandBehavior = CommandBehavior.Default;\n                var grainIdHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());\n                var grainTypeHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));\n                var readRecords = (await Storage.ReadAsync(\n                    CurrentOperationalQueries.ReadFromStorage,\n                    command =>\n                    {\n                        command.AddParameter(\"GrainIdHash\", grainIdHash);\n                        command.AddParameter(\"GrainIdN0\", grainId.N0Key);\n                        command.AddParameter(\"GrainIdN1\", grainId.N1Key);\n                        command.AddParameter(\"GrainTypeHash\", grainTypeHash);\n                        command.AddParameter(\"GrainTypeString\", baseGrainType);\n                        command.AddParameter(\"GrainIdExtensionString\", grainId.StringKey);\n                        command.AddParameter(\"ServiceId\", serviceId);\n                    },\n                    (selector, resultSetCount, token) =>\n                    {\n                        object storageState = null;\n                        int? version;\n                        byte[] payload;\n                        payload = selector.GetValueOrDefault<byte[]>(\"PayloadBinary\");\n                        if (payload != null)\n                        {\n                            storageState = Serializer.Deserialize<T>(new BinaryData(payload));\n                        }\n                        version = selector.GetNullableInt32(\"Version\");\n                        var result = Tuple.Create(storageState, version?.ToString(CultureInfo.InvariantCulture));\n                        return Task.FromResult(result);\n                    },\n                    commandBehavior, CancellationToken.None).ConfigureAwait(false)).SingleOrDefault();\n\n                T state = readRecords != null ? (T)readRecords.Item1 : default;\n                string etag = readRecords != null ? readRecords.Item2 : null;\n                bool recordExists = readRecords != null;\n                if (state == null)\n                {\n                    LogTraceNullGrainStateRead(serviceId, name, baseGrainType, grainId, grainState.ETag);\n                    state = CreateInstance<T>();\n                }\n\n                grainState.State = state;\n                grainState.ETag = etag;\n                grainState.RecordExists = recordExists;\n                LogTraceReadGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n            }\n            catch (Exception ex)\n            {\n                LogErrorReadingGrainState(ex, serviceId, name, baseGrainType, grainId, grainState.ETag);\n                throw;\n            }\n        }\n\n\n        /// <summary> Write state data function for this storage provider.</summary>\n        /// <see cref=\"IGrainStorage.WriteStateAsync{T}\"/>\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainReference, IGrainState<T> grainState)\n        {\n            //It assumed these parameters are always valid. If not, an exception will be thrown, even if not as clear\n            //as with explicitly checked parameters.\n            var data = grainState.State;\n            var grainId = GrainIdAndExtensionAsString(grainReference);\n            var baseGrainType = ExtractBaseClass(grainType);\n            LogTraceWritingGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n\n            string storageVersion = null;\n            try\n            {\n                var grainIdHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());\n                var grainTypeHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));\n                var writeRecord = await Storage.ReadAsync(CurrentOperationalQueries.WriteToStorage, command =>\n                {\n                    var serialized = this.Serializer.Serialize<T>(grainState.State);\n\n                    command.AddParameter(\"GrainIdHash\", grainIdHash);\n                    command.AddParameter(\"GrainIdN0\", grainId.N0Key);\n                    command.AddParameter(\"GrainIdN1\", grainId.N1Key);\n                    command.AddParameter(\"GrainTypeHash\", grainTypeHash);\n                    command.AddParameter(\"GrainTypeString\", baseGrainType);\n                    command.AddParameter(\"GrainIdExtensionString\", grainId.StringKey);\n                    command.AddParameter(\"ServiceId\", serviceId);\n                    command.AddParameter(\"GrainStateVersion\", !string.IsNullOrWhiteSpace(grainState.ETag) ? int.Parse(grainState.ETag, CultureInfo.InvariantCulture) : default(int?));\n                    command.AddParameter(\"PayloadBinary\", serialized.ToArray());\n                }, (selector, resultSetCount, token) =>\n                { return Task.FromResult(selector.GetNullableInt32(\"NewGrainStateVersion\").ToString()); }, cancellationToken: CancellationToken.None).ConfigureAwait(false);\n                storageVersion = writeRecord.SingleOrDefault();\n            }\n            catch (Exception ex)\n            {\n                LogErrorWritingGrainState(ex, serviceId, name, baseGrainType, grainId, grainState.ETag);\n                throw;\n            }\n\n            const string OperationString = \"WriteState\";\n            var inconsistentStateException = CheckVersionInconsistency(OperationString, serviceId, this.name, storageVersion, grainState.ETag, baseGrainType, grainId.ToString());\n            if (inconsistentStateException != null)\n            {\n                throw inconsistentStateException;\n            }\n\n            //No errors found, the version of the state held by the grain can be updated.\n            grainState.ETag = storageVersion;\n            grainState.RecordExists = true;\n\n            LogTraceWroteGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);\n        }\n\n        /// <summary> Initialization function for this storage provider. </summary>\n        private async Task Init(CancellationToken cancellationToken)\n        {\n            Storage = RelationalStorage.CreateInstance(options.Invariant, options.ConnectionString);\n            var queries = await Storage.ReadAsync(DefaultInitializationQuery, command => { }, (selector, resultSetCount, token) =>\n            {\n                return Task.FromResult(Tuple.Create(selector.GetValue<string>(\"QueryKey\"), selector.GetValue<string>(\"QueryText\")));\n            }).ConfigureAwait(false);\n\n            // This check is for backward compatibility:\n            // 1. Some AdoNet storage invariants may not support delete on clear.\n            // 2. AdoNet invariant supports delete on clear but updated persistence scripts have not been deployed to management db.\n            var deleteStateQuery = queries.SingleOrDefault(i => i.Item1 == \"DeleteStorageKey\")?.Item2;\n            if (options.DeleteStateOnClear && deleteStateQuery is null)\n            {\n                throw new ArgumentException($\"{nameof(options.DeleteStateOnClear)}=true is not supported. Use {nameof(options.DeleteStateOnClear)}=false instead or check persistence scripts.\");\n            }\n            CurrentOperationalQueries = new RelationalStorageProviderQueries(\n                queries.Single(i => i.Item1 == \"WriteToStorageKey\").Item2,\n                queries.Single(i => i.Item1 == \"ReadFromStorageKey\").Item2,\n                queries.Single(i => i.Item1 == \"ClearStorageKey\").Item2,\n                deleteStateQuery);\n\n            LogInfoInitializedStorageProvider(\n                serviceId,\n                name,\n                Storage.InvariantName,\n                new(Storage.ConnectionString));\n        }\n\n        /// <summary>\n        /// Close this provider\n        /// </summary>\n        private Task Close(CancellationToken token)\n        {\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Checks for version inconsistency as defined in the database scripts.\n        /// </summary>\n        /// <param name=\"serviceId\">Service Id.</param>\n        /// <param name=\"providerName\">The name of this storage provider.</param>\n        /// <param name=\"operation\">The operation attempted.</param>\n        /// <param name=\"storageVersion\">The version from storage.</param>\n        /// <param name=\"grainVersion\">The grain version.</param>\n        /// <param name=\"normalizedGrainType\">Grain type without generics information.</param>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <returns>An exception for throwing or <em>null</em> if no violation was detected.</returns>\n        /// <remarks>This means that the version was not updated in the database or the version storage version was something else than null\n        /// when the grain version was null, meaning effectively a double activation and save.</remarks>\n        private static InconsistentStateException CheckVersionInconsistency(string operation, string serviceId, string providerName, string storageVersion, string grainVersion, string normalizedGrainType, string grainId)\n        {\n            //If these are the same, it means no row was inserted or updated in the storage.\n            //Effectively it means the UPDATE or INSERT conditions failed due to ETag violation.\n            //Also if grainState.ETag storageVersion is null and storage comes back as null,\n            //it means two grains were activated an the other one succeeded in writing its state.\n            //\n            //NOTE: the storage could return also the new and old ETag (Version), but currently it doesn't.\n            if (storageVersion == grainVersion || storageVersion == string.Empty || (storageVersion is null && grainVersion is not null))\n            {\n                //TODO: Note that this error message should be canonical across back-ends.\n                return new InconsistentStateException($\"Version conflict ({operation}): ServiceId={serviceId} ProviderName={providerName} GrainType={normalizedGrainType} GrainId={grainId} ETag={grainVersion}.\");\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Extracts a grain ID as a string and appends the key extension with '#' infix is present.\n        /// </summary>\n        /// <returns>The grain ID as a string.</returns>\n        /// <remarks>This likely should exist in Orleans core in more optimized form.</remarks>\n        private static AdoGrainKey GrainIdAndExtensionAsString(GrainId grainId)\n        {\n            string keyExt;\n            if (grainId.TryGetGuidKey(out var guid, out keyExt))\n            {\n                return new AdoGrainKey(guid, keyExt);\n            }\n\n            if (grainId.TryGetIntegerKey(out var integer, out keyExt))\n            {\n                return new AdoGrainKey(integer, keyExt);\n            }\n\n            return new AdoGrainKey(grainId.Key.ToString());\n        }\n\n        /// <summary>\n        /// Extracts a base class from a string that is either <see cref=\"Type.AssemblyQualifiedName\"/> or\n        /// <see cref=\"Type.FullName\"/> or returns the one given as a parameter if no type is given.\n        /// </summary>\n        /// <param name=\"typeName\">The base class name to give.</param>\n        /// <returns>The extracted base class or the one given as a parameter if it didn't have a generic part.</returns>\n        private static string ExtractBaseClass(string typeName)\n        {\n            var genericPosition = typeName.IndexOf(\"`\", StringComparison.OrdinalIgnoreCase);\n            if (genericPosition != -1)\n            {\n                //The following relies the generic argument list to be in form as described\n                //at https://msdn.microsoft.com/en-us/library/w3f99sx1.aspx.\n                var split = typeName.Split(BaseClassExtractionSplitDelimeters, StringSplitOptions.RemoveEmptyEntries);\n                var stripped = new Queue<string>(split.Where(i => i.Length > 1 && i[0] != ',').Select(WithoutAssemblyVersion));\n\n                return ReformatClassName(stripped);\n            }\n\n            return typeName;\n\n            string WithoutAssemblyVersion(string input)\n            {\n                var asmNameIndex = input.IndexOf(',');\n                if (asmNameIndex >= 0)\n                {\n                    var asmVersionIndex = input.IndexOf(',', asmNameIndex + 1);\n                    if (asmVersionIndex >= 0) return input[..asmVersionIndex];\n                    return input[..asmNameIndex];\n                }\n\n                return input;\n            }\n\n            string ReformatClassName(Queue<string> segments)\n            {\n                var simpleTypeName = segments.Dequeue();\n                var arity = GetGenericArity(simpleTypeName);\n                if (arity <= 0) return simpleTypeName;\n\n                var args = new List<string>(arity);\n                for (var i = 0; i < arity; i++)\n                {\n                    args.Add(ReformatClassName(segments));\n                }\n\n                return $\"{simpleTypeName}[{string.Join(\",\", args.Select(arg => $\"[{arg}]\"))}]\";\n            }\n\n            int GetGenericArity(string input)\n            {\n                var arityIndex = input.IndexOf(\"`\", StringComparison.OrdinalIgnoreCase);\n                if (arityIndex != -1)\n                {\n                    return int.Parse(input.AsSpan()[(arityIndex + 1)..]);\n                }\n\n                return 0;\n            }\n        }\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderClearing,\n            Level = LogLevel.Trace,\n            Message = \"Clearing grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceClearingGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderDeleteError,\n            Level = LogLevel.Error,\n            Message = \"Error clearing grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogErrorClearingGrainState(Exception exception, string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderCleared,\n            Level = LogLevel.Trace,\n            Message = \"Cleared grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceClearedGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderReading,\n            Level = LogLevel.Trace,\n            Message = \"Reading grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceReadingGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderNoStateFound,\n            Level = LogLevel.Trace,\n            Message = \"Null grain state read (default will be instantiated): ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceNullGrainStateRead(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderRead,\n            Level = LogLevel.Trace,\n            Message = \"Read grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceReadGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderReadError,\n            Level = LogLevel.Error,\n            Message = \"Error reading grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogErrorReadingGrainState(Exception exception, string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderWriting,\n            Level = LogLevel.Trace,\n            Message = \"Writing grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceWritingGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderWriteError,\n            Level = LogLevel.Error,\n            Message = \"Error writing grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogErrorWritingGrainState(Exception exception, string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderWrote,\n            Level = LogLevel.Trace,\n            Message = \"Wrote grain state: ServiceId={ServiceId} ProviderName={Name} GrainType={BaseGrainType} GrainId={GrainId} ETag={ETag}.\"\n        )]\n        private partial void LogTraceWroteGrainState(string serviceId, string name, string baseGrainType, AdoGrainKey grainId, string etag);\n\n        private readonly struct ConnectionStringLogRecord(string connectionString)\n        {\n            public override string ToString() => ConfigUtilities.RedactConnectionStringInfo(connectionString);\n        }\n\n        [LoggerMessage(\n            EventId = (int)RelationalStorageProviderCodes.RelationalProviderInitProvider,\n            Level = LogLevel.Information,\n            Message = \"Initialized storage provider: ServiceId={ServiceId} ProviderName={Name} Invariant={InvariantName} ConnectionString={ConnectionString}.\"\n        )]\n        private partial void LogInfoInitializedStorageProvider(string serviceId, string name, string invariantName, ConnectionStringLogRecord connectionString);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/AdoNetGrainStorageServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class AdoNetGrainStorageServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configure silo to use  AdoNet grain storage as the default grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IServiceCollection AddAdoNetGrainStorage(this IServiceCollection services, Action<AdoNetGrainStorageOptions> configureOptions)\n        {\n            return services.AddAdoNetGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use AdoNet grain storage for grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IServiceCollection AddAdoNetGrainStorage(this IServiceCollection services, string name, Action<AdoNetGrainStorageOptions> configureOptions)\n        {\n            return services.AddAdoNetGrainStorage(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use AdoNet grain storage as the default grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IServiceCollection AddAdoNetGrainStorageAsDefault(this IServiceCollection services, Action<OptionsBuilder<AdoNetGrainStorageOptions>> configureOptions = null)\n        {\n            return services.AddAdoNetGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use AdoNet grain storage for grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IServiceCollection AddAdoNetGrainStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<AdoNetGrainStorageOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<AdoNetGrainStorageOptions>(name));\n            services.ConfigureNamedOptionForLogging<AdoNetGrainStorageOptions>(name);\n            services.AddTransient<IPostConfigureOptions<AdoNetGrainStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<AdoNetGrainStorageOptions>>();\n            services.AddTransient<IPostConfigureOptions<AdoNetGrainStorageOptions>, DefaultAdoNetGrainStorageOptionsHashPickerConfigurator>();\n            services.AddTransient<IConfigurationValidator>(sp => new AdoNetGrainStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AdoNetGrainStorageOptions>>().Get(name), name));\n            return services.AddGrainStorage(name, AdoNetGrainStorageFactory.Create);\n        }\n    } \n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/AdoNetGrainStorageSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    public static class AdoNetGrainStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use AdoNet grain storage as the default grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder AddAdoNetGrainStorageAsDefault(this ISiloBuilder builder, Action<AdoNetGrainStorageOptions> configureOptions)\n        {\n            return builder.AddAdoNetGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use  AdoNet grain storage for grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder AddAdoNetGrainStorage(this ISiloBuilder builder, string name, Action<AdoNetGrainStorageOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAdoNetGrainStorage(name, configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use  AdoNet grain storage as the default grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder AddAdoNetGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<AdoNetGrainStorageOptions>> configureOptions = null)\n        {\n            return builder.AddAdoNetGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use AdoNet grain storage for grain storage. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder AddAdoNetGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<AdoNetGrainStorageOptions>> configureOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddAdoNetGrainStorage(name, configureOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/IHasher.cs",
    "content": "﻿namespace Orleans.Storage\n{\n    /// <summary>\n    /// An interface for all the hashing operations currently in Orleans Storage operations.\n    /// </summary>\n    /// <remarks>Implement this to provide a hasher for database key with specific properties.\n    /// As for an example: collision resistance on out-of-control ID providers.</remarks>\n    public interface IHasher\n    {\n        /// <summary>\n        /// Description of the hashing functionality.\n        /// </summary>\n        string Description { get; }\n\n        /// <summary>\n        /// The hash.\n        /// </summary>\n        /// <param name=\"data\">The data to hash.</param>\n        /// <returns>The given bytes hashed.</returns>\n        int Hash(byte[] data);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/IStorageHashPicker.cs",
    "content": "using Orleans.Runtime;\nusing System.Collections.Generic;\n\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// A picker to choose from provided hash functions. Provides agility to update or change hashing functionality for both built-in and custom operations.\n    /// </summary>\n    /// <remarks>The returned hash needs to be thread safe or a unique instance.</remarks>\n    public interface IStorageHasherPicker\n    {\n        /// <summary>\n        /// The hash functions saved to this picker.\n        /// </summary>\n        ICollection<IHasher> HashProviders { get; }\n\n        /// <summary>Picks a hasher using the given parameters.</summary>\n        /// <param name=\"serviceId\">The ID of the current service.</param>\n        /// <param name=\"storageProviderInstanceName\">The requesting storage provider.</param>\n        /// <param name=\"grainType\">The type of grain.</param>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <param name=\"grainState\">The grain state.</param>\n        /// <param name=\"tag\">An optional tag parameter that might be used by the storage parameter for \"out-of-band\" contracts.</param>\n        /// <returns>A serializer or <em>null</em> if not match was found.</returns>\n        IHasher PickHasher<T>(string serviceId, string storageProviderInstanceName, string grainType, GrainId grainId, IGrainState<T> grainState, string tag = null);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/JenkinsHash.cs",
    "content": "using System;\n\nnamespace Orleans.Storage\n{\n    // Based on the version in http://home.comcast.net/~bretm/hash/7.html, which is based on that\n    // in http://burtleburtle.net/bob/hash/evahash.html.\n    // Note that we only use the version that takes three ulongs, which was written by the Orleans team.\n    // implementation restored from Orleans v3.7.2: https://github.com/dotnet/orleans/blob/b24e446abfd883f0e4ed614f5267eaa3331548dc/src/Orleans.Core.Abstractions/IDs/JenkinsHash.cs,\n    // trimmed and slightly optimized\n    internal static class JenkinsHash\n    {\n        private static void Mix(ref uint aa, ref uint bb, ref uint cc)\n        {\n            uint a = aa;\n            uint b = bb;\n            uint c = cc;\n\n            a -= b; a -= c; a ^= (c >> 13);\n            b -= c; b -= a; b ^= (a << 8);\n            c -= a; c -= b; c ^= (b >> 13);\n            a -= b; a -= c; a ^= (c >> 12);\n            b -= c; b -= a; b ^= (a << 16);\n            c -= a; c -= b; c ^= (b >> 5);\n            a -= b; a -= c; a ^= (c >> 3);\n            b -= c; b -= a; b ^= (a << 10);\n            c -= a; c -= b; c ^= (b >> 15);\n\n            aa = a;\n            bb = b;\n            cc = c;\n        }\n\n        // This is the reference implementation of the Jenkins hash.\n        public static uint ComputeHash(ReadOnlySpan<byte> data)\n        {\n            int len = data.Length;\n            uint a = 0x9e3779b9;\n            uint b = a;\n            uint c = 0;\n            int i = 0;\n\n            while (i <= len - 12)\n            {\n                a += (uint)data[i++] |\n                    ((uint)data[i++] << 8) |\n                    ((uint)data[i++] << 16) |\n                    ((uint)data[i++] << 24);\n                b += (uint)data[i++] |\n                    ((uint)data[i++] << 8) |\n                    ((uint)data[i++] << 16) |\n                    ((uint)data[i++] << 24);\n                c += (uint)data[i++] |\n                    ((uint)data[i++] << 8) |\n                    ((uint)data[i++] << 16) |\n                    ((uint)data[i++] << 24);\n                Mix(ref a, ref b, ref c);\n            }\n            c += (uint)len;\n            if (i < len)\n                a += data[i++];\n            if (i < len)\n                a += (uint)data[i++] << 8;\n            if (i < len)\n                a += (uint)data[i++] << 16;\n            if (i < len)\n                a += (uint)data[i++] << 24;\n            if (i < len)\n                b += (uint)data[i++];\n            if (i < len)\n                b += (uint)data[i++] << 8;\n            if (i < len)\n                b += (uint)data[i++] << 16;\n            if (i < len)\n                b += (uint)data[i++] << 24;\n            if (i < len)\n                c += (uint)data[i++] << 8;\n            if (i < len)\n                c += (uint)data[i++] << 16;\n            if (i < len)\n                c += (uint)data[i++] << 24;\n            Mix(ref a, ref b, ref c);\n            return c;\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/Orleans3CompatibleHasher.cs",
    "content": "using System;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Orleans v3-compatible hasher implementation for non-string-only grain key ids.\n    /// </summary>\n    internal class Orleans3CompatibleHasher : IHasher\n    {\n        /// <summary>\n        /// <see cref=\"IHasher.Description\"/>\n        /// </summary>\n        public string Description { get; } = $\"Orleans v3 hash function ({nameof(JenkinsHash)}).\";\n\n        /// <summary>\n        /// <see cref=\"IHasher.Hash(byte[])\"/>.\n        /// </summary>\n        public int Hash(byte[] data) => Hash(data.AsSpan());\n\n        /// <summary>\n        /// <see cref=\"IHasher.Hash(byte[])\"/>.\n        /// </summary>\n        public int Hash(ReadOnlySpan<byte> data)\n        {\n            // implementation restored from Orleans v3.7.2: https://github.com/dotnet/orleans/blob/b24e446abfd883f0e4ed614f5267eaa3331548dc/src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/OrleansDefaultHasher.cs\n            return unchecked((int)JenkinsHash.ComputeHash(data));\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/Orleans3CompatibleStorageHashPicker.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Orleans v3-compatible hash picker implementation for Orleans v3 -> v7+ migration scenarios.\n    /// </summary>\n    public class Orleans3CompatibleStorageHashPicker : IStorageHasherPicker\n    {\n        private readonly Orleans3CompatibleHasher _nonStringHasher;\n\n        /// <summary>\n        /// <see cref=\"IStorageHasherPicker.HashProviders\"/>.\n        /// </summary>\n        public ICollection<IHasher> HashProviders { get; }\n\n        /// <summary>\n        /// A constructor.\n        /// </summary>\n        public Orleans3CompatibleStorageHashPicker()\n        {\n            _nonStringHasher = new();\n            HashProviders = [_nonStringHasher];\n        }\n\n        /// <summary>\n        /// <see cref=\"IStorageHasherPicker.PickHasher{T}\"/>.\n        /// </summary>\n        public IHasher PickHasher<T>(\n            string serviceId,\n            string storageProviderInstanceName,\n            string grainType,\n            GrainId grainId,\n            IGrainState<T> grainState,\n            string tag = null)\n        {\n            // string-only grain keys had special behaviour in Orleans v3\n            if (grainId.TryGetIntegerKey(out _, out _) || grainId.TryGetGuidKey(out _, out _))\n                return _nonStringHasher;\n\n            // unable to cache hasher instances: content-aware behaviour, see hasher implementation for details\n            return new Orleans3CompatibleStringKeyHasher(_nonStringHasher, grainType);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/Orleans3CompatibleStringKeyHasher.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Text;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Orleans v3-compatible hasher implementation for string-only grain key ids.\n    /// </summary>\n    internal class Orleans3CompatibleStringKeyHasher : IHasher\n    {\n        private readonly Orleans3CompatibleHasher _innerHasher;\n        private readonly string _grainType;\n\n        public Orleans3CompatibleStringKeyHasher(Orleans3CompatibleHasher innerHasher, string grainType)\n        {\n            _innerHasher = innerHasher;\n            _grainType = grainType;\n        }\n\n        /// <summary>\n        /// <see cref=\"IHasher.Description\"/>\n        /// </summary>\n        public string Description { get; } = $\"Orleans v3 hash function ({nameof(JenkinsHash)}).\";\n\n        /// <summary>\n        /// <see cref=\"IHasher.Hash(byte[])\"/>.\n        /// </summary>\n        public int Hash(byte[] data)\n        {\n            // Orleans v3 treats string-only keys as integer keys with extension (AdoGrainKey.IsLongKey == true),\n            // so data must be extended for string-only grain keys.\n            // But AdoNetGrainStorage implementation also uses such code:\n            //    ...\n            //    var grainIdHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());\n            //    var grainTypeHash = HashPicker.PickHasher(serviceId, this.name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));\n            //    ...\n            // PickHasher parameters are the same for both calls so we need to analyze data content to distinguish these cases.\n            // It doesn't word if string key is equal to grain type name, but we consider this edge case to be negligibly rare.\n\n            if (IsGrainTypeName(data))\n                return _innerHasher.Hash(data);\n\n            var extendedLength = data.Length + 8;\n\n            const int maxOnStack = 256;\n            byte[] rentedBuffer = null;\n\n            // assuming code below never throws, so calling ArrayPool.Return without try/finally block for JIT optimization\n\n            var buffer = extendedLength > maxOnStack\n                ? (rentedBuffer = ArrayPool<byte>.Shared.Rent(extendedLength)).AsSpan()\n                : stackalloc byte[maxOnStack];\n\n            buffer = buffer[..extendedLength];\n\n            data.AsSpan().CopyTo(buffer);\n            // buffer may contain arbitrary data, setting zeros in 'extension' segment\n            buffer[data.Length..].Clear();\n\n            var hash = _innerHasher.Hash(buffer);\n\n            if (rentedBuffer is not null)\n                ArrayPool<byte>.Shared.Return(rentedBuffer);\n\n            return hash;\n        }\n\n        private bool IsGrainTypeName(byte[] data)\n        {\n            // at least 1 byte per char\n            if (data.Length < _grainType.Length)\n                return false;\n\n            var grainTypeByteCount = Encoding.UTF8.GetByteCount(_grainType);\n            if (grainTypeByteCount != data.Length)\n                return false;\n\n            const int maxOnStack = 256;\n            byte[] rentedBuffer = null;\n\n            // assuming code below never throws, so calling ArrayPool.Return without try/finally block for JIT optimization\n\n            var buffer = grainTypeByteCount > maxOnStack\n                ? (rentedBuffer = ArrayPool<byte>.Shared.Rent(grainTypeByteCount)).AsSpan()\n                : stackalloc byte[maxOnStack];\n\n            buffer = buffer[..grainTypeByteCount];\n\n            var bytesWritten = Encoding.UTF8.GetBytes(_grainType, buffer);\n            var isGrainType = buffer[..bytesWritten].SequenceEqual(data);\n            if (rentedBuffer is not null)\n                ArrayPool<byte>.Shared.Return(rentedBuffer);\n\n            return isGrainType;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/OrleansDefaultHasher.cs",
    "content": "namespace Orleans.Storage\n{\n    /// <summary>\n    /// A default implementation uses the same hash as Orleans in grains placement.\n    /// </summary>\n    public sealed class OrleansDefaultHasher: IHasher\n    {\n        /// <summary>\n        /// <see cref=\"IHasher.Description\"/>\n        /// </summary>\n        public string Description => $\"The default Orleans hash function ({nameof(StableHash)}).\";\n\n        /// <summary>\n        /// <see cref=\"IHasher.Hash(byte[])\"/>.\n        /// </summary>\n        public int Hash(byte[] data) => (int)StableHash.ComputeHash(data);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/RelationalStorageProviderQueries.cs",
    "content": "namespace Orleans.Storage;\n\n/// <summary>\n/// A container class for the queries currently used by the <see cref=\"AdoNetGrainStorage\"/>.\n/// </summary>\n/// <remarks>This is provided as a separate entity in order to make these dynamically updatable.</remarks>\npublic class RelationalStorageProviderQueries\n{\n    /// <summary>\n    /// The clause to write to the storage.\n    /// </summary>\n    public string WriteToStorage { get; }\n\n    /// <summary>\n    /// The clause to read from the storage.\n    /// </summary>\n    public string ReadFromStorage { get; set; }\n\n    /// <summary>\n    /// The clause to clear the storage.\n    /// </summary>\n    public string ClearState { get; set; }\n\n    /// <summary>\n    /// The clause to delete the row from storage when clearing state.\n    /// </summary>\n    public string DeleteState { get; set; }\n\n    /// <summary>\n    /// Constructor.\n    /// </summary>\n    /// <param name=\"writeToStorage\">The clause to write to a storage.</param>\n    /// <param name=\"readFromStorage\">The clause to read from a storage.</param>\n    /// <param name=\"clearState\">The clause to clear the storage.</param>\n    /// <param name=\"deleteState\">The clause to delete the row from storage. May be <see langword=\"null\"/> for backward compatibility.</param>\n    public RelationalStorageProviderQueries(string writeToStorage, string readFromStorage, string clearState, string deleteState)\n    {\n        ArgumentNullException.ThrowIfNull(writeToStorage);\n        ArgumentNullException.ThrowIfNull(readFromStorage);\n        ArgumentNullException.ThrowIfNull(clearState);\n\n        // No null check on deleteState for backward compatibility.\n\n        WriteToStorage = writeToStorage;\n        ReadFromStorage = readFromStorage;\n        ClearState = clearState;\n        DeleteState = deleteState;\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/StorageHasherPicker.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\n\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// <see cref=\"IStorageHasherPicker\"/>.\n    /// </summary>\n    public class StorageHasherPicker: IStorageHasherPicker\n    {\n        /// <summary>\n        /// <see cref=\"IStorageHasherPicker.HashProviders\"/>.\n        /// </summary>\n        public ICollection<IHasher> HashProviders { get; }\n\n\n        /// <summary>\n        /// A constructor.\n        /// </summary>\n        /// <param name=\"hashProviders\">The hash providers this picker uses.</param>\n        public StorageHasherPicker(IEnumerable<IHasher> hashProviders)\n        {\n            if(hashProviders == null)\n            {\n                throw new ArgumentNullException(nameof(hashProviders));\n            }\n\n            HashProviders = new Collection<IHasher>(new List<IHasher>(hashProviders));\n        }\n\n\n        /// <summary>\n        /// <see cref=\"IStorageHasherPicker.PickHasher{T}\"/>.\n        /// </summary>\n        public IHasher PickHasher<T>(string serviceId, string storageProviderInstanceName, string grainType, GrainId grainId, IGrainState<T> grainState, string tag = null)\n        {\n            return HashProviders.FirstOrDefault();\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/AdoNetRemindersProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AdoNet\", \"Reminders\", \"Silo\", typeof(AdoNetRemindersProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AdoNetRemindersProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAdoNetReminderService((OptionsBuilder<AdoNetReminderTableOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var invariant = configurationSection[nameof(options.Invariant)];\n                if (!string.IsNullOrEmpty(invariant))\n                {\n                    options.Invariant = invariant;\n                }\n\n                var connectionString = configurationSection[nameof(options.ConnectionString)];\n                var connectionName = configurationSection[\"ConnectionName\"];\n                if (string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(connectionName))\n                {\n                    connectionString = services.GetRequiredService<IConfiguration>().GetConnectionString(connectionName);\n                }\n\n                if (!string.IsNullOrEmpty(connectionString))\n                {\n                    options.ConnectionString = connectionString;\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/Migrations/PostgreSQL-Reminders-3.6.0.sql",
    "content": "-- Run this migration for upgrading the PostgreSQL reminder table and routines for deployments created before 3.6.0\n\nBEGIN;\n\n-- Change date type\n\nALTER TABLE OrleansRemindersTable\nALTER COLUMN StartTime TYPE TIMESTAMPTZ(3) USING StartTime AT TIME ZONE 'UTC';\n\n-- Recreate routines\n\nCREATE OR REPLACE FUNCTION upsert_reminder_row(\n    ServiceIdArg    OrleansRemindersTable.ServiceId%TYPE,\n    GrainIdArg      OrleansRemindersTable.GrainId%TYPE,\n    ReminderNameArg OrleansRemindersTable.ReminderName%TYPE,\n    StartTimeArg    OrleansRemindersTable.StartTime%TYPE,\n    PeriodArg       OrleansRemindersTable.Period%TYPE,\n    GrainHashArg    OrleansRemindersTable.GrainHash%TYPE\n  )\n  RETURNS TABLE(version integer) AS\n$func$\nDECLARE\n    VersionVar int := 0;\nBEGIN\n\n    INSERT INTO OrleansRemindersTable\n    (\n        ServiceId,\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        GrainHash,\n        Version\n    )\n    SELECT\n        ServiceIdArg,\n        GrainIdArg,\n        ReminderNameArg,\n        StartTimeArg,\n        PeriodArg,\n        GrainHashArg,\n        0\n    ON CONFLICT (ServiceId, GrainId, ReminderName)\n        DO UPDATE SET\n            StartTime = excluded.StartTime,\n            Period = excluded.Period,\n            GrainHash = excluded.GrainHash,\n            Version = OrleansRemindersTable.Version + 1\n    RETURNING\n        OrleansRemindersTable.Version INTO STRICT VersionVar;\n\n    RETURN QUERY SELECT VersionVar AS versionr;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/MySQL-Reminders.sql",
    "content": "-- Orleans Reminders table - https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders\nCREATE TABLE OrleansRemindersTable\n(\n    ServiceId NVARCHAR(150) NOT NULL,\n    GrainId VARCHAR(150) NOT NULL,\n    ReminderName NVARCHAR(150) NOT NULL,\n    StartTime DATETIME NOT NULL,\n    Period BIGINT NOT NULL,\n    GrainHash INT NOT NULL,\n    Version INT NOT NULL,\n\n    CONSTRAINT PK_RemindersTable_ServiceId_GrainId_ReminderName PRIMARY KEY(ServiceId, GrainId, ReminderName)\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpsertReminderRowKey','\n    INSERT INTO OrleansRemindersTable\n    (\n        ServiceId,\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        GrainHash,\n        Version\n    )\n    VALUES\n    (\n        @ServiceId,\n        @GrainId,\n        @ReminderName,\n        @StartTime,\n        @Period,\n        @GrainHash,\n        last_insert_id(0)\n    )\n    ON DUPLICATE KEY\n    UPDATE\n        StartTime = @StartTime,\n        Period = @Period,\n        GrainHash = @GrainHash,\n        Version = last_insert_id(Version+1);\n\n\n    SELECT last_insert_id() AS Version;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowsKey','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainId = @GrainId AND @GrainId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowKey','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainId = @GrainId AND @GrainId IS NOT NULL\n        AND ReminderName = @ReminderName AND @ReminderName IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows1Key','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainHash > @BeginHash AND @BeginHash IS NOT NULL\n        AND GrainHash <= @EndHash AND @EndHash IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows2Key','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND ((GrainHash > @BeginHash AND @BeginHash IS NOT NULL)\n        OR (GrainHash <= @EndHash AND @EndHash IS NOT NULL));\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowKey','\n    DELETE FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainId = @GrainId AND @GrainId IS NOT NULL\n        AND ReminderName = @ReminderName AND @ReminderName IS NOT NULL\n        AND Version = @Version AND @Version IS NOT NULL;\n    SELECT ROW_COUNT();\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowsKey','\n    DELETE FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/Oracle-Reminders.sql",
    "content": "-- Orleans Reminders table - https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders\nCREATE TABLE \"ORLEANSREMINDERSTABLE\"\n(\n    \"SERVICEID\" NVARCHAR2(150) NOT NULL ENABLE,\n    \"GRAINID\" VARCHAR2(150) NOT NULL,\n    \"REMINDERNAME\" NVARCHAR2(150) NOT NULL,\n    \"STARTTIME\" TIMESTAMP(6) NOT NULL ENABLE,\n    \"PERIOD\" NUMBER(19,0) NULL,\n    \"GRAINHASH\" INT NOT NULL,\n    \"VERSION\" INT NOT NULL,\n\n    CONSTRAINT PK_REMINDERSTABLE PRIMARY KEY(SERVICEID, GRAINID, REMINDERNAME)\n);\n/\n\nCREATE OR REPLACE FUNCTION UpsertReminderRow(PARAM_SERVICEID IN NVARCHAR2, PARAM_GRAINHASH IN INT, PARAM_GRAINID IN VARCHAR2, PARAM_REMINDERNAME IN NVARCHAR2,\n                                                PARAM_STARTTIME IN TIMESTAMP, PARAM_PERIOD IN NUMBER)\nRETURN NUMBER IS\n  rowcount NUMBER;\n  currentVersion NUMBER := 0;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    MERGE INTO OrleansRemindersTable ort\n    USING (\n      SELECT PARAM_SERVICEID as SERVICEID,\n        PARAM_GRAINID as GRAINID,\n        PARAM_REMINDERNAME as REMINDERNAME,\n        PARAM_STARTTIME as STARTTIME,\n        PARAM_PERIOD as PERIOD,\n        PARAM_GRAINHASH GRAINHASH\n      FROM dual\n    ) n_ort\n    ON (ort.ServiceId = n_ort.SERVICEID AND\n        ort.GrainId = n_ort.GRAINID AND\n        ort.ReminderName = n_ort.REMINDERNAME\n    )\n    WHEN MATCHED THEN\n    UPDATE SET\n      ort.StartTime = n_ort.STARTTIME,\n      ort.Period = n_ort.PERIOD,\n      ort.GrainHash = n_ort.GRAINHASH,\n      ort.Version = ort.Version+1\n    WHEN NOT MATCHED THEN\n    INSERT (ort.ServiceId, ort.GrainId, ort.ReminderName, ort.StartTime, ort.Period, ort.GrainHash, ort.Version)\n    VALUES (n_ort.SERVICEID, n_ort.GRAINID, n_ort.REMINDERNAME, n_ort.STARTTIME, n_ort.PERIOD, n_ort.GRAINHASH, 0);\n\n    SELECT Version INTO currentVersion FROM OrleansRemindersTable\n        WHERE ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n        AND GrainId = PARAM_GRAINID AND PARAM_GRAINID IS NOT NULL\n        AND ReminderName = PARAM_REMINDERNAME AND PARAM_REMINDERNAME IS NOT NULL;\n    COMMIT;\n    RETURN(currentVersion);\n  END;\n/\n\nCREATE OR REPLACE FUNCTION DeleteReminderRow(PARAM_SERVICEID IN NVARCHAR2, PARAM_GRAINID IN VARCHAR2, PARAM_REMINDERNAME IN NVARCHAR2,\n                                                PARAM_VERSION IN NUMBER)\nRETURN NUMBER IS\n  rowcount NUMBER;\n  PRAGMA AUTONOMOUS_TRANSACTION;\n  BEGIN\n    DELETE FROM OrleansRemindersTable\n      WHERE ServiceId = PARAM_SERVICEID AND PARAM_SERVICEID IS NOT NULL\n        AND GrainId = PARAM_GRAINID AND PARAM_GRAINID IS NOT NULL\n        AND ReminderName = PARAM_REMINDERNAME AND PARAM_REMINDERNAME IS NOT NULL\n        AND Version = PARAM_VERSION AND PARAM_VERSION IS NOT NULL;\n\n    rowcount := SQL%ROWCOUNT;\n\n    COMMIT;\n    RETURN(rowcount);\n  END;\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpsertReminderRowKey','\n    SELECT UpsertReminderRow(:ServiceId, :GrainHash, :GrainId, :ReminderName, :StartTime, :Period) AS Version FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowsKey','\n    SELECT GrainId, ReminderName, StartTime, Period, Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = :ServiceId AND :ServiceId IS NOT NULL\n        AND GrainId = :GrainId AND :GrainId IS NOT NULL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowKey','\n    SELECT GrainId, ReminderName, StartTime, Period, Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = :ServiceId AND :ServiceId IS NOT NULL\n        AND GrainId = :GrainId AND :GrainId IS NOT NULL\n        AND ReminderName = :ReminderName AND :ReminderName IS NOT NULL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows1Key','\n    SELECT GrainId, ReminderName, StartTime, Period, Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = :ServiceId AND :ServiceId IS NOT NULL\n        AND GrainHash > :BeginHash AND :BeginHash IS NOT NULL\n        AND GrainHash <= :EndHash AND :EndHash IS NOT NULL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows2Key','\n    SELECT GrainId, ReminderName, StartTime, Period,Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = :ServiceId AND :ServiceId IS NOT NULL\n        AND ((GrainHash > :BeginHash AND :BeginHash IS NOT NULL)\n        OR (GrainHash <= :EndHash AND :EndHash IS NOT NULL))\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowKey','\n    SELECT DeleteReminderRow(:ServiceId, :GrainId, :ReminderName, :Version) AS RESULT FROM DUAL\n');\n/\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowsKey','\n    DELETE FROM OrleansRemindersTable\n    WHERE ServiceId = :ServiceId AND :ServiceId IS NOT NULL\n');\n/\n\nCOMMIT;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/Orleans.Reminders.AdoNet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Reminders.AdoNet</PackageId>\n    <Title>Microsoft Orleans ADO.NET Reminders Provider</Title>\n    <Description>Microsoft Orleans reminders provider backed by ADO.NET</Description>\n    <PackageTags>$(PackageTags) ADO.NET SQL MySQL PostgreSQL Oracle</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Reminders.AdoNet</AssemblyName>\n    <RootNamespace>Orleans.Reminders.AdoNet</RootNamespace>\n    <DefineConstants>$(DefineConstants);REMINDERS_ADONET</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/PostgreSQL-Reminders.sql",
    "content": "-- Orleans Reminders table - https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders\nCREATE TABLE OrleansRemindersTable\n(\n    ServiceId varchar(150) NOT NULL,\n    GrainId varchar(150) NOT NULL,\n    ReminderName varchar(150) NOT NULL,\n    StartTime timestamptz(3) NOT NULL,\n    Period bigint NOT NULL,\n    GrainHash integer NOT NULL,\n    Version integer NOT NULL,\n\n    CONSTRAINT PK_RemindersTable_ServiceId_GrainId_ReminderName PRIMARY KEY(ServiceId, GrainId, ReminderName)\n);\n\nCREATE FUNCTION upsert_reminder_row(\n    ServiceIdArg    OrleansRemindersTable.ServiceId%TYPE,\n    GrainIdArg      OrleansRemindersTable.GrainId%TYPE,\n    ReminderNameArg OrleansRemindersTable.ReminderName%TYPE,\n    StartTimeArg    OrleansRemindersTable.StartTime%TYPE,\n    PeriodArg       OrleansRemindersTable.Period%TYPE,\n    GrainHashArg    OrleansRemindersTable.GrainHash%TYPE\n  )\n  RETURNS TABLE(version integer) AS\n$func$\nDECLARE\n    VersionVar int := 0;\nBEGIN\n\n    INSERT INTO OrleansRemindersTable\n    (\n        ServiceId,\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        GrainHash,\n        Version\n    )\n    SELECT\n        ServiceIdArg,\n        GrainIdArg,\n        ReminderNameArg,\n        StartTimeArg,\n        PeriodArg,\n        GrainHashArg,\n        0\n    ON CONFLICT (ServiceId, GrainId, ReminderName)\n        DO UPDATE SET\n            StartTime = excluded.StartTime,\n            Period = excluded.Period,\n            GrainHash = excluded.GrainHash,\n            Version = OrleansRemindersTable.Version + 1\n    RETURNING\n        OrleansRemindersTable.Version INTO STRICT VersionVar;\n\n    RETURN QUERY SELECT VersionVar AS versionr;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'UpsertReminderRowKey','\n    SELECT * FROM upsert_reminder_row(\n        @ServiceId,\n        @GrainId,\n        @ReminderName,\n        @StartTime,\n        @Period,\n        @GrainHash\n    );\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowsKey','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainId = @GrainId AND @GrainId IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadReminderRowKey','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainId = @GrainId AND @GrainId IS NOT NULL\n        AND ReminderName = @ReminderName AND @ReminderName IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows1Key','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND GrainHash > @BeginHash AND @BeginHash IS NOT NULL\n        AND GrainHash <= @EndHash AND @EndHash IS NOT NULL;\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'ReadRangeRows2Key','\n    SELECT\n        GrainId,\n        ReminderName,\n        StartTime,\n        Period,\n        Version\n    FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL\n        AND ((GrainHash > @BeginHash AND @BeginHash IS NOT NULL)\n        OR (GrainHash <= @EndHash AND @EndHash IS NOT NULL));\n');\n\nCREATE FUNCTION delete_reminder_row(\n    ServiceIdArg    OrleansRemindersTable.ServiceId%TYPE,\n    GrainIdArg      OrleansRemindersTable.GrainId%TYPE,\n    ReminderNameArg OrleansRemindersTable.ReminderName%TYPE,\n    VersionArg      OrleansRemindersTable.Version%TYPE\n)\n  RETURNS TABLE(row_count integer) AS\n$func$\nDECLARE\n    RowCountVar int := 0;\nBEGIN\n\n\n    DELETE FROM OrleansRemindersTable\n    WHERE\n        ServiceId = ServiceIdArg AND ServiceIdArg IS NOT NULL\n        AND GrainId = GrainIdArg AND GrainIdArg IS NOT NULL\n        AND ReminderName = ReminderNameArg AND ReminderNameArg IS NOT NULL\n        AND Version = VersionArg AND VersionArg IS NOT NULL;\n\n    GET DIAGNOSTICS RowCountVar = ROW_COUNT;\n\n    RETURN QUERY SELECT RowCountVar;\n\nEND\n$func$ LANGUAGE plpgsql;\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowKey','\n    SELECT * FROM delete_reminder_row(\n        @ServiceId,\n        @GrainId,\n        @ReminderName,\n        @Version\n    );\n');\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nVALUES\n(\n    'DeleteReminderRowsKey','\n    DELETE FROM OrleansRemindersTable\n    WHERE\n        ServiceId = @ServiceId AND @ServiceId IS NOT NULL;\n');\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/README.md",
    "content": "# Microsoft Orleans Reminders for ADO.NET\n\n## Introduction\nMicrosoft Orleans Reminders for ADO.NET provides persistence for Orleans reminders using ADO.NET-compatible databases (SQL Server, MySQL, PostgreSQL, etc.). This allows your Orleans applications to schedule persistent reminders that will be triggered even after silo restarts or grain deactivation.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Reminders.AdoNet\n```\n\nYou will also need to install the appropriate ADO.NET provider for your database:\n\n```shell\n# For SQL Server\ndotnet add package Microsoft.Data.SqlClient\n\n# For MySQL\ndotnet add package MySql.Data\n\n# For PostgreSQL\ndotnet add package Npgsql\n```\n\n## Example - Configuring ADO.NET Reminders\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Example;\n\n// Create a host builder\nvar builder = Host.CreateApplicationBuilder(args);\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseLocalhostClustering()\n        // Configure ADO.NET as reminder storage\n        .UseAdoNetReminderService(options =>\n        {\n            options.Invariant = \"Microsoft.Data.SqlClient\";  // For SQL Server\n            options.ConnectionString = \"Server=localhost;Database=OrleansReminders;User ID=orleans;******;\";\n        });\n});\n\n// Build and start the host\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a grain reference and use it\nvar grain = host.Services.GetRequiredService<IGrainFactory>().GetGrain<IReminderGrain>(\"my-reminder-grain\");\nawait grain.StartReminder(\"DailyReport\");\nConsole.WriteLine(\"Reminder started successfully!\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Using Reminders in a Grain\n```csharp\nusing System;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\n\nnamespace Example;\n\npublic interface IReminderGrain : IGrainWithStringKey\n{\n    Task StartReminder(string reminderName);\n    Task StopReminder();\n}\n\npublic class ReminderGrain : Grain, IReminderGrain, IRemindable\n{\n    private string _reminderName = \"MyReminder\";\n\n    public async Task StartReminder(string reminderName)\n    {\n        _reminderName = reminderName;\n\n        // Register a persistent reminder\n        await RegisterOrUpdateReminder(\n            reminderName,\n            TimeSpan.FromMinutes(2),  // Time to delay before the first tick (must be > 1 minute)\n            TimeSpan.FromMinutes(5)); // Period of the reminder (must be > 1 minute)\n    }\n\n    public async Task StopReminder()\n    {\n        // Find and unregister the reminder\n        var reminder = await GetReminder(_reminderName);\n        if (reminder != null)\n        {\n            await UnregisterReminder(reminder);\n        }\n    }\n\n    public Task ReceiveReminder(string reminderName, TickStatus status)\n    {\n        // This method is called when the reminder ticks\n        Console.WriteLine($\"Reminder {reminderName} triggered at {DateTime.UtcNow}. Status: {status}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Reminders and Timers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n- [Reminder Services](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/reminder-services)\n- [ADO.NET Database Setup](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/adonet-configuration)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/ReminderService/AdoNetReminderTable.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Reminders.AdoNet.Storage;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    internal sealed class AdoNetReminderTable : IReminderTable\n    {\n        private readonly AdoNetReminderTableOptions options;\n        private readonly string serviceId;\n        private RelationalOrleansQueries orleansQueries;\n\n        public AdoNetReminderTable(\n            IOptions<ClusterOptions> clusterOptions, \n            IOptions<AdoNetReminderTableOptions> storageOptions)\n        {\n            this.serviceId = clusterOptions.Value.ServiceId;\n            this.options = storageOptions.Value;\n        }\n\n        public async Task Init()\n        {\n            this.orleansQueries = await RelationalOrleansQueries.CreateInstance(this.options.Invariant, this.options.ConnectionString);\n        }\n\n        public Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            return this.orleansQueries.ReadReminderRowsAsync(this.serviceId, grainId);\n        }\n\n        public Task<ReminderTableData> ReadRows(uint beginHash, uint endHash)\n        {\n            return this.orleansQueries.ReadReminderRowsAsync(this.serviceId, beginHash, endHash);\n        }\n\n        public Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            return this.orleansQueries.ReadReminderRowAsync(this.serviceId, grainId, reminderName);\n        }   \n        \n        public Task<string> UpsertRow(ReminderEntry entry)\n        {\n            if (entry.StartAt.Kind is DateTimeKind.Unspecified)\n            {\n                entry.StartAt = new DateTime(entry.StartAt.Ticks, DateTimeKind.Utc);\n            }\n\n            return this.orleansQueries.UpsertReminderRowAsync(this.serviceId, entry.GrainId, entry.ReminderName, entry.StartAt, entry.Period);            \n        }\n\n        public Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            return this.orleansQueries.DeleteReminderRowAsync(this.serviceId, grainId, reminderName, eTag);            \n        }\n\n        public Task TestOnlyClearTable()\n        {\n            return this.orleansQueries.DeleteReminderRowsAsync(this.serviceId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/ReminderService/AdoNetReminderTableOptions.cs",
    "content": "namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for ADO.NET reminder storage.\n    /// </summary>\n    public class AdoNetReminderTableOptions\n    {\n        /// <summary>\n        /// Gets or sets the ADO.NET invariant.\n        /// </summary>\n        public string Invariant { get; set; }\n\n        /// <summary>\n        /// Gets or sets the connection string.\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/ReminderService/AdoNetReminderTableOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.ReminderService;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Validates <see cref=\"AdoNetReminderTableOptions\"/> configuration.\n    /// </summary>\n    public class AdoNetReminderTableOptionsValidator : IConfigurationValidator\n    {\n        private readonly AdoNetReminderTableOptions options;\n        \n        public AdoNetReminderTableOptionsValidator(IOptions<AdoNetReminderTableOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.Invariant))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetReminderTableOptions)} values for {nameof(AdoNetReminderTable)}. {nameof(options.Invariant)} is required.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ConnectionString))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetReminderTableOptions)} values for {nameof(AdoNetReminderTable)}. {nameof(options.ConnectionString)} is required.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/SQLServer-Reminders.sql",
    "content": "-- Orleans Reminders table - https://learn.microsoft.com/dotnet/orleans/grains/timers-and-reminders\nIF OBJECT_ID(N'[OrleansRemindersTable]', 'U') IS NULL\nCREATE TABLE OrleansRemindersTable\n(\n\tServiceId NVARCHAR(150) NOT NULL,\n\tGrainId VARCHAR(150) NOT NULL,\n\tReminderName NVARCHAR(150) NOT NULL,\n\tStartTime DATETIME2(3) NOT NULL,\n\tPeriod BIGINT NOT NULL,\n\tGrainHash INT NOT NULL,\n\tVersion INT NOT NULL,\n\n\tCONSTRAINT PK_RemindersTable_ServiceId_GrainId_ReminderName PRIMARY KEY(ServiceId, GrainId, ReminderName)\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'UpsertReminderRowKey',\n\t'DECLARE @Version AS INT = 0;\n\tSET XACT_ABORT, NOCOUNT ON;\n\tBEGIN TRANSACTION;\n\tUPDATE OrleansRemindersTable WITH(UPDLOCK, ROWLOCK, HOLDLOCK)\n\tSET\n\t\tStartTime = @StartTime,\n\t\tPeriod = @Period,\n\t\tGrainHash = @GrainHash,\n\t\t@Version = Version = Version + 1\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND GrainId = @GrainId AND @GrainId IS NOT NULL\n\t\tAND ReminderName = @ReminderName AND @ReminderName IS NOT NULL;\n\n\tINSERT INTO OrleansRemindersTable\n\t(\n\t\tServiceId,\n\t\tGrainId,\n\t\tReminderName,\n\t\tStartTime,\n\t\tPeriod,\n\t\tGrainHash,\n\t\tVersion\n\t)\n\tSELECT\n\t\t@ServiceId,\n\t\t@GrainId,\n\t\t@ReminderName,\n\t\t@StartTime,\n\t\t@Period,\n\t\t@GrainHash,\n\t\t0\n\tWHERE\n\t\t@@ROWCOUNT=0;\n\tSELECT @Version AS Version;\n\tCOMMIT TRANSACTION;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'UpsertReminderRowKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'ReadReminderRowsKey',\n\t'SELECT\n\t\tGrainId,\n\t\tReminderName,\n\t\tStartTime,\n\t\tPeriod,\n\t\tVersion\n\tFROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND GrainId = @GrainId AND @GrainId IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ReadReminderRowsKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'ReadReminderRowKey',\n\t'SELECT\n\t\tGrainId,\n\t\tReminderName,\n\t\tStartTime,\n\t\tPeriod,\n\t\tVersion\n\tFROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND GrainId = @GrainId AND @GrainId IS NOT NULL\n\t\tAND ReminderName = @ReminderName AND @ReminderName IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ReadReminderRowKey'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'ReadRangeRows1Key',\n\t'SELECT\n\t\tGrainId,\n\t\tReminderName,\n\t\tStartTime,\n\t\tPeriod,\n\t\tVersion\n\tFROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND GrainHash > @BeginHash AND @BeginHash IS NOT NULL\n\t\tAND GrainHash <= @EndHash AND @EndHash IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ReadRangeRows1Key'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'ReadRangeRows2Key',\n\t'SELECT\n\t\tGrainId,\n\t\tReminderName,\n\t\tStartTime,\n\t\tPeriod,\n\t\tVersion\n\tFROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND ((GrainHash > @BeginHash AND @BeginHash IS NOT NULL)\n\t\tOR (GrainHash <= @EndHash AND @EndHash IS NOT NULL));\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'ReadRangeRows2Key'\n);\n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'DeleteReminderRowKey',\n\t'DELETE FROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL\n\t\tAND GrainId = @GrainId AND @GrainId IS NOT NULL\n\t\tAND ReminderName = @ReminderName AND @ReminderName IS NOT NULL\n\t\tAND Version = @Version AND @Version IS NOT NULL;\n\tSELECT @@ROWCOUNT;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'DeleteReminderRowKey'\n);    \n\nINSERT INTO OrleansQuery(QueryKey, QueryText)\nSELECT\n\t'DeleteReminderRowsKey',\n\t'DELETE FROM OrleansRemindersTable\n\tWHERE\n\t\tServiceId = @ServiceId AND @ServiceId IS NOT NULL;\n\t'\nWHERE NOT EXISTS \n( \n    SELECT 1 \n    FROM OrleansQuery oqt\n    WHERE oqt.[QueryKey] = 'DeleteReminderRowsKey'\n);  \n"
  },
  {
    "path": "src/AdoNet/Orleans.Reminders.AdoNet/SiloBuilderReminderExtensions.cs",
    "content": "using System;\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Runtime.ReminderService;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo host builder extensions.\n    /// </summary>\n    public static class SiloBuilderReminderExtensions\n    {\n        /// <summary>Adds reminder storage using ADO.NET. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.</summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configureOptions\">Configuration delegate.</param>\n        /// <returns>The provided <see cref=\"ISiloBuilder\"/>, for chaining.</returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder UseAdoNetReminderService(\n            this ISiloBuilder builder,\n            Action<AdoNetReminderTableOptions> configureOptions)\n        {\n            return builder.UseAdoNetReminderService(ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>Adds reminder storage using ADO.NET. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.</summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configureOptions\">Configuration delegate.</param>\n        /// <returns>The provided <see cref=\"ISiloBuilder\"/>, for chaining.</returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static ISiloBuilder UseAdoNetReminderService(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<AdoNetReminderTableOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.UseAdoNetReminderService(configureOptions));\n        }\n\n        /// <summary>Adds reminder storage using ADO.NET. Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.</summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"configureOptions\">Configuration delegate.</param>\n        /// <returns>The provided <see cref=\"IServiceCollection\"/>, for chaining.</returns>\n        /// <remarks>\n        /// Instructions on configuring your database are available at <see href=\"http://aka.ms/orleans-sql-scripts\"/>.\n        /// </remarks>\n        public static IServiceCollection UseAdoNetReminderService(this IServiceCollection services, Action<OptionsBuilder<AdoNetReminderTableOptions>> configureOptions)\n        {\n            services.AddReminders();\n            services.AddSingleton<IReminderTable, AdoNetReminderTable>();\n            services.ConfigureFormatter<AdoNetReminderTableOptions>();\n            services.AddSingleton<IConfigurationValidator, AdoNetReminderTableOptionsValidator>();\n            configureOptions(services.AddOptions<AdoNetReminderTableOptions>());\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetBatchContainer.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// The <see cref=\"IBatchContainer\"/> implementation for the ADONET provider.\n/// </summary>\n/// <remarks>\n/// 1. This class only supports binary serialization as performance and data size is the priority for database storage.\n/// 2. Though the <see cref=\"SequenceToken\"/> is supported here, it is not yet used, as the ADO.NET provider is not rewindable.\n/// </remarks>\n[GenerateSerializer]\n[Alias(\"Orleans.Streaming.AdoNet.AdoNetBatchContainer\")]\ninternal class AdoNetBatchContainer : IBatchContainer\n{\n    public AdoNetBatchContainer(StreamId streamId, List<object> events, Dictionary<string, object> requestContext)\n    {\n        ArgumentNullException.ThrowIfNull(events);\n\n        StreamId = streamId;\n        Events = events;\n        RequestContext = requestContext;\n    }\n\n    #region Serialized State\n\n    [Id(0)]\n    public StreamId StreamId { get; }\n\n    [Id(1)]\n    public List<object> Events { get; }\n\n    [Id(2)]\n    public Dictionary<string, object> RequestContext { get; }\n\n    [Id(3)]\n    public EventSequenceTokenV2 SequenceToken { get; internal set; } = null!;\n\n    /// <summary>\n    /// Holds the receipt for message confirmation.\n    /// </summary>\n    [Id(4)]\n    public int Dequeued { get; internal set; }\n\n    #endregion Serialized State\n\n    #region Interface\n\n    StreamSequenceToken IBatchContainer.SequenceToken => SequenceToken;\n\n    public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n    {\n        return SequenceToken is null\n            ? throw new InvalidOperationException($\"Cannot get events from a half-baked {nameof(AdoNetBatchContainer)}\")\n            : Events\n                .OfType<T>()\n                .Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, SequenceToken.CreateSequenceTokenForEvent(i)));\n    }\n\n    public bool ImportRequestContext()\n    {\n        if (RequestContext is not null)\n        {\n            RequestContextExtensions.Import(RequestContext);\n            return true;\n        }\n\n        return false;\n    }\n\n    #endregion Interface\n\n    #region Conversion\n\n    /// <summary>\n    /// Creates a new <see cref=\"AdoNetBatchContainer\"/> from the specified <see cref=\"AdoNetStreamMessage\"/>.\n    /// </summary>\n    public static AdoNetBatchContainer FromMessage(Serializer<AdoNetBatchContainer> serializer, AdoNetStreamMessage message)\n    {\n        ArgumentNullException.ThrowIfNull(serializer);\n        ArgumentNullException.ThrowIfNull(message);\n\n        var container = serializer.Deserialize(message.Payload);\n        container.SequenceToken = new(message.MessageId);\n        container.Dequeued = message.Dequeued;\n\n        return container;\n    }\n\n    /// <summary>\n    /// Converts the specified <see cref=\"AdoNetBatchContainer\"/> to a message payload.\n    /// </summary>\n    public static byte[] ToMessagePayload(Serializer<AdoNetBatchContainer> serializer, StreamId streamId, List<object> events, Dictionary<string, object> requestContext)\n    {\n        ArgumentNullException.ThrowIfNull(serializer);\n        ArgumentNullException.ThrowIfNull(events);\n\n        var container = new AdoNetBatchContainer(streamId, events, requestContext);\n        var payload = serializer.SerializeToArray(container);\n\n        return payload;\n    }\n\n    #endregion Conversion\n\n    public override string ToString() => $\"[{nameof(AdoNetBatchContainer)}:Stream={StreamId},#Items={Events.Count}]\";\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetQueueAdapter.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// Stream queue storage adapter for ADO.NET providers.\n/// </summary>\ninternal partial class AdoNetQueueAdapter(string name, AdoNetStreamOptions streamOptions, ClusterOptions clusterOptions, SimpleQueueCacheOptions cacheOptions, AdoNetStreamQueueMapper mapper, RelationalOrleansQueries queries, Serializer<AdoNetBatchContainer> serializer, ILogger<AdoNetQueueAdapter> logger, IServiceProvider serviceProvider) : IQueueAdapter\n{\n    private readonly ILogger<AdoNetQueueAdapter> _logger = logger;\n\n    /// <summary>\n    /// Maps to the ProviderId in the database.\n    /// </summary>\n    public string Name { get; } = name;\n\n    /// <summary>\n    /// The ADO.NET provider is not yet rewindable.\n    /// </summary>\n    public bool IsRewindable => false;\n\n    /// <summary>\n    /// The ADO.NET provider works both ways.\n    /// </summary>\n    public StreamProviderDirection Direction => StreamProviderDirection.ReadWrite;\n\n    public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n    {\n        // map the queue id\n        var adoNetQueueId = mapper.GetAdoNetQueueId(queueId);\n\n        // create the receiver\n        return ReceiverFactory(serviceProvider, [Name, adoNetQueueId, streamOptions, clusterOptions, cacheOptions, queries]);\n    }\n\n    public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n    {\n        // the ADO.NET provider is not rewindable so we do not support user supplied tokens\n        if (token is not null)\n        {\n            throw new ArgumentException($\"{nameof(AdoNetQueueAdapter)} does not support a user supplied {nameof(StreamSequenceToken)}.\");\n        }\n\n        // map the Orleans stream id to the corresponding queue id\n        var queueId = mapper.GetAdoNetQueueId(streamId);\n\n        // create the payload from the events\n        var payload = AdoNetBatchContainer.ToMessagePayload(serializer, streamId, events.Cast<object>().ToList(), requestContext);\n\n        // we can enqueue the message now\n        try\n        {\n            await queries.QueueStreamMessageAsync(clusterOptions.ServiceId, Name, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());\n        }\n        catch (Exception ex)\n        {\n            LogFailedToQueueStreamMessage(ex, clusterOptions.ServiceId, Name, queueId);\n            throw;\n        }\n    }\n\n    /// <summary>\n    /// The receiver factory.\n    /// </summary>\n    private static readonly ObjectFactory<AdoNetQueueAdapterReceiver> ReceiverFactory = ActivatorUtilities.CreateFactory<AdoNetQueueAdapterReceiver>([typeof(string), typeof(string), typeof(AdoNetStreamOptions), typeof(ClusterOptions), typeof(SimpleQueueCacheOptions), typeof(RelationalOrleansQueries)]);\n\n    #region Logging\n\n    [LoggerMessage(1, LogLevel.Error, \"Failed to queue stream message with ({ServiceId}, {ProviderId}, {QueueId})\")]\n    private partial void LogFailedToQueueStreamMessage(Exception ex, string serviceId, string providerId, string queueId);\n\n    #endregion Logging\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetQueueAdapterFactory.cs",
    "content": "using System.Threading;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Orleans.Streaming.AdoNet;\n\ninternal class AdoNetQueueAdapterFactory : IQueueAdapterFactory\n{\n    public AdoNetQueueAdapterFactory(string name, AdoNetStreamOptions streamOptions, ClusterOptions clusterOptions, SimpleQueueCacheOptions cacheOptions, HashRingStreamQueueMapperOptions hashOptions, ILoggerFactory loggerFactory, IHostApplicationLifetime lifetime, IServiceProvider serviceProvider)\n    {\n        _name = name;\n        _streamOptions = streamOptions;\n        _clusterOptions = clusterOptions;\n        _cacheOptions = cacheOptions;\n        _lifetime = lifetime;\n        _serviceProvider = serviceProvider;\n\n        _streamQueueMapper = new HashRingBasedStreamQueueMapper(hashOptions, name);\n        _cache = new SimpleQueueAdapterCache(cacheOptions, name, loggerFactory);\n        _adoNetQueueMapper = new AdoNetStreamQueueMapper(_streamQueueMapper);\n    }\n\n    private readonly string _name;\n    private readonly AdoNetStreamOptions _streamOptions;\n    private readonly ClusterOptions _clusterOptions;\n    private readonly SimpleQueueCacheOptions _cacheOptions;\n    private readonly IHostApplicationLifetime _lifetime;\n    private readonly IServiceProvider _serviceProvider;\n\n    private readonly HashRingBasedStreamQueueMapper _streamQueueMapper;\n    private readonly SimpleQueueAdapterCache _cache;\n    private readonly AdoNetStreamQueueMapper _adoNetQueueMapper;\n\n    private RelationalOrleansQueries _queries;\n\n    /// <summary>\n    /// Unfortunate implementation detail to account for lack of async lifetime.\n    /// Ideally this concern will be moved upstream so this won't be needed.\n    /// </summary>\n    private readonly SemaphoreSlim _semaphore = new(1);\n\n    /// <summary>\n    /// Ensures queries are loaded only once while allowing for recovery if the load fails.\n    /// </summary>\n    private ValueTask<RelationalOrleansQueries> GetQueriesAsync()\n    {\n        // attempt fast path\n        return _queries is not null ? new(_queries) : new(CoreAsync());\n\n        // slow path\n        async Task<RelationalOrleansQueries> CoreAsync()\n        {\n            await _semaphore.WaitAsync(_streamOptions.InitializationTimeout, _lifetime.ApplicationStopping);\n            try\n            {\n                // attempt fast path again\n                if (_queries is not null)\n                {\n                    return _queries;\n                }\n\n                // slow path - the member variable will only be set if the call succeeds\n                return _queries = await RelationalOrleansQueries\n                    .CreateInstance(_streamOptions.Invariant, _streamOptions.ConnectionString)\n                    .WaitAsync(_streamOptions.InitializationTimeout);\n            }\n            finally\n            {\n                _semaphore.Release();\n            }\n        }\n    }\n\n    public async Task<IQueueAdapter> CreateAdapter()\n    {\n        var queries = await GetQueriesAsync();\n\n        return AdapterFactory(_serviceProvider, [_name, _streamOptions, _clusterOptions, _cacheOptions, _adoNetQueueMapper, queries]);\n    }\n\n    public async Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n    {\n        var queries = await GetQueriesAsync();\n\n        return HandlerFactory(_serviceProvider, [false, _streamOptions, _clusterOptions, _adoNetQueueMapper, queries]);\n    }\n\n    public IQueueAdapterCache GetQueueAdapterCache() => _cache;\n\n    public IStreamQueueMapper GetStreamQueueMapper() => _streamQueueMapper;\n\n    /// <summary>\n    /// Used by the silo and client configurators as an entry point to set up a stream.\n    /// </summary>\n    public static IQueueAdapterFactory Create(IServiceProvider serviceProvider, string name)\n    {\n        ArgumentNullException.ThrowIfNull(serviceProvider);\n        ArgumentNullException.ThrowIfNull(name);\n\n        var streamOptions = serviceProvider.GetOptionsByName<AdoNetStreamOptions>(name);\n        var clusterOptions = serviceProvider.GetProviderClusterOptions(name).Value;\n        var cacheOptions = serviceProvider.GetOptionsByName<SimpleQueueCacheOptions>(name);\n        var hashOptions = serviceProvider.GetOptionsByName<HashRingStreamQueueMapperOptions>(name);\n\n        return QueueAdapterFactoryFactory(serviceProvider, [name, streamOptions, clusterOptions, cacheOptions, hashOptions]);\n    }\n\n    /// <summary>\n    /// Factory of <see cref=\"AdoNetQueueAdapterFactory\"/> instances.\n    /// </summary>\n    private static readonly ObjectFactory<AdoNetQueueAdapterFactory> QueueAdapterFactoryFactory = ActivatorUtilities.CreateFactory<AdoNetQueueAdapterFactory>([typeof(string), typeof(AdoNetStreamOptions), typeof(ClusterOptions), typeof(SimpleQueueCacheOptions), typeof(HashRingStreamQueueMapperOptions)]);\n\n    /// <summary>\n    /// Factory of <see cref=\"AdoNetQueueAdapter\"/> instances.\n    /// </summary>\n    private static readonly ObjectFactory<AdoNetQueueAdapter> AdapterFactory = ActivatorUtilities.CreateFactory<AdoNetQueueAdapter>([typeof(string), typeof(AdoNetStreamOptions), typeof(ClusterOptions), typeof(SimpleQueueCacheOptions), typeof(AdoNetStreamQueueMapper), typeof(RelationalOrleansQueries)]);\n\n    /// <summary>\n    /// Factory of <see cref=\"AdoNetStreamFailureHandler\"/> instances.\n    /// </summary>\n    private static readonly ObjectFactory<AdoNetStreamFailureHandler> HandlerFactory = ActivatorUtilities.CreateFactory<AdoNetStreamFailureHandler>([typeof(bool), typeof(AdoNetStreamOptions), typeof(ClusterOptions), typeof(AdoNetStreamQueueMapper), typeof(RelationalOrleansQueries)]);\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetQueueAdapterReceiver.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// Receives message batches from an individual queue of an ADO.NET provider.\n/// </summary>\ninternal partial class AdoNetQueueAdapterReceiver(string providerId, string queueId, AdoNetStreamOptions streamOptions, ClusterOptions clusterOptions, SimpleQueueCacheOptions cacheOptions, RelationalOrleansQueries queries, Serializer<AdoNetBatchContainer> serializer, ILogger<AdoNetQueueAdapterReceiver> logger) : IQueueAdapterReceiver\n{\n    private readonly ILogger<AdoNetQueueAdapterReceiver> _logger = logger;\n\n    /// <summary>\n    /// Flags that no further work should be attempted.\n    /// </summary>\n    private bool _shutdown;\n\n    /// <summary>\n    /// Helps shutdown wait for any outstanding storage operation.\n    /// </summary>\n    private Task _outstandingTask;\n\n    /// <summary>\n    /// This receiver does not require initialization.\n    /// </summary>\n    public Task Initialize(TimeSpan timeout) => Task.CompletedTask;\n\n    /// <summary>\n    /// Waits for any outstanding work before shutting down.\n    /// </summary>\n    public async Task Shutdown(TimeSpan timeout)\n    {\n        // disable any further attempts to access storage\n        _shutdown = true;\n\n        // wait for any outstanding storage operation to complete.\n        var outstandingTask = _outstandingTask;\n        if (outstandingTask is not null)\n        {\n            try\n            {\n                await outstandingTask.WaitAsync(timeout);\n            }\n            catch (Exception ex)\n            {\n                LogShutdownFault(ex, clusterOptions.ServiceId, providerId, queueId);\n            }\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n    {\n        // if shutdown has been called then we refuse further requests gracefully\n        if (_shutdown)\n        {\n            return [];\n        }\n\n        // cap max count as appropriate\n        maxCount = Math.Min(maxCount, cacheOptions.CacheSize);\n\n        try\n        {\n            // grab a message batch from storage while pinning the task so shutdown can wait for it\n            var task = queries.GetStreamMessagesAsync(\n                clusterOptions.ServiceId,\n                providerId,\n                queueId,\n                maxCount,\n                streamOptions.MaxAttempts,\n                streamOptions.VisibilityTimeout.TotalSecondsCeiling(),\n                streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling(),\n                streamOptions.EvictionInterval.TotalSecondsCeiling(),\n                streamOptions.EvictionBatchSize);\n\n            _outstandingTask = task;\n\n            var messages = await task;\n\n            // convert the messages into standard batch containers\n            return messages.Select(x => AdoNetBatchContainer.FromMessage(serializer, x)).Cast<IBatchContainer>().ToList();\n        }\n        catch (Exception ex)\n        {\n            LogDequeueFailed(ex, clusterOptions.ServiceId, providerId, queueId);\n            throw;\n        }\n        finally\n        {\n            _outstandingTask = null;\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n    {\n        // skip work if there are no messages to deliver\n        if (messages.Count == 0)\n        {\n            return;\n        }\n\n        // get the identifiers for the messages to confirm\n        var items = messages.Cast<AdoNetBatchContainer>().Select(x => new AdoNetStreamConfirmation(x.SequenceToken.SequenceNumber, x.Dequeued)).ToList();\n\n        try\n        {\n            // execute the confirmation while pinning the task so shutdown can wait for it\n            var task = queries.ConfirmStreamMessagesAsync(clusterOptions.ServiceId, providerId, queueId, items);\n            _outstandingTask = task;\n\n            try\n            {\n                await task;\n            }\n            catch (Exception ex)\n            {\n                LogConfirmationFailed(ex, clusterOptions.ClusterId, providerId, queueId, items);\n                throw;\n            }\n        }\n        finally\n        {\n            _outstandingTask = null;\n        }\n    }\n\n    #region Logging\n\n    [LoggerMessage(1, LogLevel.Error, \"Failed to get messages from ({ServiceId}, {ProviderId}, {QueueId})\")]\n    private partial void LogDequeueFailed(Exception exception, string serviceId, string providerId, string queueId);\n\n    [LoggerMessage(2, LogLevel.Error, \"Failed to confirm messages for ({ServiceId}, {ProviderId}, {QueueId}, {@Items})\")]\n    private partial void LogConfirmationFailed(Exception exception, string serviceId, string providerId, string queueId, List<AdoNetStreamConfirmation> items);\n\n    [LoggerMessage(3, LogLevel.Warning, \"Handled fault while shutting down receiver for ({ServiceId}, {ProviderId}, {QueueId})\")]\n    private partial void LogShutdownFault(Exception exception, string serviceId, string providerId, string queueId);\n\n    #endregion Logging\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamConfirmation.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// The model that represents a message that can be confirmed.\n/// </summary>\ninternal record AdoNetStreamConfirmation(\n    long MessageId,\n    int Dequeued)\n{\n    public AdoNetStreamConfirmation() : this(0, 0)\n    {\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamConfirmationAck.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// The model that represents a message that was successfully confirmed.\n/// </summary>\ninternal record AdoNetStreamConfirmationAck(\n    string ServiceId,\n    string ProviderId,\n    string QueueId,\n    long MessageId)\n{\n    public AdoNetStreamConfirmationAck() : this(\"\", \"\", \"\", 0)\n    {\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamDeadLetter.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// The model that represents a dead letter in an ADONET streaming provider.\n/// </summary>\ninternal record AdoNetStreamDeadLetter(\n    string ServiceId,\n    string ProviderId,\n    string QueueId,\n    long MessageId,\n    int Dequeued,\n    DateTime VisibleOn,\n    DateTime ExpiresOn,\n    DateTime CreatedOn,\n    DateTime ModifiedOn,\n    DateTime DeadOn,\n    DateTime RemoveOn,\n    byte[] Payload)\n{\n    public AdoNetStreamDeadLetter() : this(\"\", \"\", \"\", 0, 0, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, [])\n    {\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamFailureHandler.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// An <see cref=\"IStreamFailureHandler\"/> that attempts to move the message to dead letters.\n/// </summary>\ninternal partial class AdoNetStreamFailureHandler(bool faultOnFailure, AdoNetStreamOptions streamOptions, ClusterOptions clusterOptions, AdoNetStreamQueueMapper mapper, RelationalOrleansQueries queries, ILogger<AdoNetStreamFailureHandler> logger) : IStreamFailureHandler\n{\n    private readonly ILogger<AdoNetStreamFailureHandler> _logger = logger;\n\n    /// <summary>\n    /// Gets a value indicating whether the subscription should fault when there is an error.\n    /// </summary>\n    public bool ShouldFaultSubsriptionOnError { get; } = faultOnFailure;\n\n    /// <summary>\n    /// Attempts to move the message to dead letters on delivery failure.\n    /// </summary>\n    public Task OnDeliveryFailure(GuidId subscriptionId, string streamProviderName, StreamId streamIdentity, StreamSequenceToken sequenceToken) => OnFailureAsync(streamProviderName, streamIdentity, sequenceToken);\n\n    /// <summary>\n    /// Attempts to move the message to dead letters on delivery failure.\n    /// </summary>\n    public Task OnSubscriptionFailure(GuidId subscriptionId, string streamProviderName, StreamId streamIdentity, StreamSequenceToken sequenceToken) => OnFailureAsync(streamProviderName, streamIdentity, sequenceToken);\n\n    /// <summary>\n    /// Attempts to move the message to dead letters on delivery failure.\n    /// </summary>\n    private async Task OnFailureAsync(string streamProviderName, StreamId streamIdentity, StreamSequenceToken sequenceToken)\n    {\n        ArgumentNullException.ThrowIfNull(streamProviderName);\n        ArgumentNullException.ThrowIfNull(sequenceToken);\n\n        var queueId = mapper.GetAdoNetQueueId(streamIdentity);\n\n        try\n        {\n            await queries.FailStreamMessageAsync(clusterOptions.ServiceId, streamProviderName, queueId, sequenceToken.SequenceNumber, streamOptions.MaxAttempts, streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling());\n\n            LogMovedMessage(clusterOptions.ServiceId, streamProviderName, queueId, sequenceToken.SequenceNumber);\n        }\n        catch (Exception ex)\n        {\n            LogFailedToMoveMessage(ex, clusterOptions.ServiceId, streamProviderName, queueId, sequenceToken.SequenceNumber);\n            throw;\n        }\n    }\n\n    #region Logging\n\n    [LoggerMessage(1, LogLevel.Warning, \"Moved failed delivery to dead letters: ({ServiceId}, {ProviderId}, {QueueId}, {MessageId})\")]\n    private partial void LogMovedMessage(string serviceId, string providerId, string queueId, long messageId);\n\n    [LoggerMessage(2, LogLevel.Error, \"Failed to move failed delivery to dead letters: ({ServiceId}, {ProviderId}, {QueueId}, {MessageId}\")]\n    private partial void LogFailedToMoveMessage(Exception ex, string serviceId, string providerId, string queueId, long messageId);\n\n    #endregion Logging\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamMessage.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// The model that represents a stored message in an ADONET streaming provider.\n/// </summary>\ninternal record AdoNetStreamMessage(\n    string ServiceId,\n    string ProviderId,\n    string QueueId,\n    long MessageId,\n    int Dequeued,\n    DateTime VisibleOn,\n    DateTime ExpiresOn,\n    DateTime CreatedOn,\n    DateTime ModifiedOn,\n    byte[] Payload)\n{\n    public AdoNetStreamMessage() : this(\"\", \"\", \"\", 0, 0, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, [])\n    {\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamMessageAck.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// Represents an acknowledgement from storage that a message was enqueued.\n/// This is used to surface any generated identifiers for testing.\n/// </summary>\ninternal record AdoNetStreamMessageAck(\n    string ServiceId,\n    string ProviderId,\n    string QueueId,\n    long MessageId)\n{\n    public AdoNetStreamMessageAck() : this(\"\", \"\", \"\", 0)\n    {\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamOptions.cs",
    "content": "namespace Orleans.Configuration;\n\n/// <summary>\n/// Options for ADO.NET Streaming.\n/// </summary>\npublic class AdoNetStreamOptions\n{\n    /// <summary>\n    /// Gets or sets the ADO.NET invariant.\n    /// </summary>\n    public string Invariant { get; set; }\n\n    /// <summary>\n    /// Gets or sets the connection string.\n    /// </summary>\n    [Redact]\n    public string ConnectionString { get; set; }\n\n    /// <summary>\n    /// The maximum number of attempts to deliver a message.\n    /// The message is eventually moved to dead letters if these many attempts are made without success.\n    /// </summary>\n    public int MaxAttempts { get; set; } = 5;\n\n    /// <summary>\n    /// The timeout until a message is allowed to be dequeued again if not yet confirmed.\n    /// </summary>\n    public TimeSpan VisibilityTimeout { get; set; } = TimeSpan.FromMinutes(1);\n\n    /// <summary>\n    /// The expiry timeout until a message is considered expired and moved to dead letters regardless of attempts.\n    /// The message is only moved if the current attempt is also past its visibility timeout.\n    /// </summary>\n    public TimeSpan ExpiryTimeout { get; set; } = TimeSpan.FromMinutes(10);\n\n    /// <summary>\n    /// The removal timeout until a failed message is deleted from the dead letters table.\n    /// </summary>\n    public TimeSpan DeadLetterEvictionTimeout { get; set; } = TimeSpan.FromDays(7);\n\n    /// <summary>\n    /// The period of time between eviction activities.\n    /// These include moving expired messages to dead letters and removing dead letters after their own lifetime.\n    /// This period is cluster wide and will not change with the number of silos.\n    /// </summary>\n    public TimeSpan EvictionInterval { get; set; } = TimeSpan.FromSeconds(10);\n\n    /// <summary>\n    /// The maximum number of messages affected by an eviction batch.\n    /// </summary>\n    public int EvictionBatchSize { get; set; } = 1000;\n\n    /// <summary>\n    /// A safety timeout for underlying database initialization.\n    /// </summary>\n    public TimeSpan InitializationTimeout { get; set; } = TimeSpan.FromSeconds(30);\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamOptionsValidator.cs",
    "content": "using static System.String;\n\nnamespace Orleans.Configuration;\n\n/// <summary>\n/// Validates <see cref=\"AdoNetStreamOptions\"/> configuration.\n/// </summary>\npublic class AdoNetStreamOptionsValidator(AdoNetStreamOptions options, string name) : IConfigurationValidator\n{\n    /// <inheritdoc />\n    public void ValidateConfiguration()\n    {\n        if (IsNullOrWhiteSpace(options.Invariant))\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.Invariant)} is required.\");\n        }\n\n        if (IsNullOrWhiteSpace(options.ConnectionString))\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.ConnectionString)} is required.\");\n        }\n\n        if (options.MaxAttempts < 0)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.MaxAttempts)} must be greater than zero.\");\n        }\n\n        if (options.VisibilityTimeout < TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.VisibilityTimeout)} must be greater than zero.\");\n        }\n\n        if (options.EvictionInterval < TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.EvictionInterval)} must be greater than zero.\");\n        }\n\n        if (options.ExpiryTimeout < TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.ExpiryTimeout)} must be greater than zero.\");\n        }\n\n        if (options.DeadLetterEvictionTimeout < TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.DeadLetterEvictionTimeout)} must be greater than zero.\");\n        }\n\n        if (options.EvictionBatchSize < 0)\n        {\n            throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetStreamOptions)} values for ADO.NET Streaming Provider '{name}': {nameof(options.EvictionBatchSize)} must be greater than zero.\");\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/AdoNetStreamQueueMapper.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// Maps Orleans streams and queues identifiers to ADO.NET queue identifiers.\n/// </summary>\ninternal class AdoNetStreamQueueMapper(IConsistentRingStreamQueueMapper mapper)\n{\n    /// <summary>\n    /// Caches the lookup of Orleans stream identifiers to ADO.NET queue identifiers.\n    /// </summary>\n    private readonly ConcurrentDictionary<StreamId, string> _byStreamLookup = new();\n\n    /// <summary>\n    /// Caches the lookup of Orleans queue identifiers to ADO.NET queue identifiers.\n    /// </summary>\n    private readonly ConcurrentDictionary<QueueId, string> _byQueueLookup = new();\n\n    /// <summary>\n    /// Caches the mapping factory of Orleans stream identifiers to ADO.NET queue identifiers.\n    /// </summary>\n    private readonly Func<StreamId, string> _fromStreamFactory = (StreamId streamId) => mapper.GetQueueForStream(streamId).ToString();\n\n    /// <summary>\n    /// Cache the mapping factory of Orleans queue identifiers to ADO.NET queue identifiers.\n    /// </summary>\n    private readonly Func<QueueId, string> _fromQueueFactory = (QueueId queueId) => queueId.ToString();\n\n    /// <summary>\n    /// Gets the ADO.NET QueueId for the specified Orleans StreamId.\n    /// </summary>\n    public string GetAdoNetQueueId(StreamId streamId) => _byStreamLookup.GetOrAdd(streamId, _fromStreamFactory);\n\n    /// <summary>\n    /// Gets the ADO.NET QueueId for the specified Orleans QueueId.\n    /// </summary>\n    public string GetAdoNetQueueId(QueueId queueId) => _byQueueLookup.GetOrAdd(queueId, _fromQueueFactory);\n\n    /// <summary>\n    /// Gets all ADO.NET QueueIds in the current space.\n    /// </summary>\n    public IEnumerable<string> GetAllAdoNetQueueIds()\n    {\n        foreach (var queueId in mapper.GetAllQueues())\n        {\n            yield return _byQueueLookup.GetOrAdd(queueId, _fromQueueFactory);\n        }\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Extensions.cs",
    "content": "namespace Orleans.Streaming.AdoNet;\n\n/// <summary>\n/// Internal syntax sugar.\n/// </summary>\ninternal static class Extensions\n{\n    /// <inheritdoc cref=\"Math.Ceiling(double)\"/>\n    public static int Int32Ceiling(this double value) => (int)Math.Ceiling(value);\n\n    /// <summary>\n    /// Rounds up the specified time span to the nearest upper second and returns the total number of seconds as an integer.\n    /// </summary>\n    public static int TotalSecondsCeiling(this TimeSpan value) => value.TotalSeconds.Int32Ceiling();\n\n    /// <summary>\n    /// Rounds up the specified time span to the nearest upper second and returns the total number of seconds as an integer.\n    /// </summary>\n    public static TimeSpan SecondsCeiling(this TimeSpan value) => TimeSpan.FromSeconds(value.TotalSecondsCeiling());\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/GlobalSuppressions.cs",
    "content": "// This file is used by Code Analysis to maintain SuppressMessage\n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given\n// a specific target and scoped to a namespace, type, member, etc.\n\n[assembly: SuppressMessage(\"Style\", \"IDE0053:Use expression body for lambda expression\", Justification = \"N/A\")]"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Hosting/ClusterClientAdoNetStreamConfigurator.cs",
    "content": "using Orleans.Streaming.AdoNet;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Helps set up an individual stream provider on a silo.\n/// </summary>\npublic class ClusterClientAdoNetStreamConfigurator : ClusterClientPersistentStreamConfigurator\n{\n    public ClusterClientAdoNetStreamConfigurator(string name, IClientBuilder clientBuilder) : base(name, clientBuilder, AdoNetQueueAdapterFactory.Create)\n    {\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(clientBuilder);\n\n        clientBuilder.ConfigureServices(services =>\n        {\n            services\n                .ConfigureNamedOptionForLogging<AdoNetStreamOptions>(name)\n                .ConfigureNamedOptionForLogging<SimpleQueueCacheOptions>(name)\n                .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new AdoNetStreamOptionsValidator(sp.GetOptionsByName<AdoNetStreamOptions>(name), name));\n        });\n\n        // in a typical i/o bound shared database there is little benefit to more than one queue per provider\n        // however multiple queues are fully supported if the user wants to fine tune throughput for their own system\n        ConfigurePartitioning(1);\n    }\n\n    public ClusterClientAdoNetStreamConfigurator ConfigureAdoNet(Action<OptionsBuilder<AdoNetStreamOptions>> configureOptions)\n    {\n        ArgumentNullException.ThrowIfNull(configureOptions);\n\n        this.Configure(configureOptions);\n\n        return this;\n    }\n\n    public ClusterClientAdoNetStreamConfigurator ConfigureCache(int cacheSize = SimpleQueueCacheOptions.DEFAULT_CACHE_SIZE)\n    {\n        this.Configure<SimpleQueueCacheOptions>(ob => ob.Configure(options => options.CacheSize = cacheSize));\n\n        return this;\n    }\n\n    public ClusterClientAdoNetStreamConfigurator ConfigurePartitioning(int partitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n    {\n        this.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = partitions));\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Hosting/ClusterClientAdoNetStreamExtensions.cs",
    "content": "namespace Orleans.Hosting;\n\n/// <summary>\n/// Allows configuration of individual ADO.NET streams in a cluster client.\n/// </summary>\npublic static class ClusterClientAdoNetStreamExtensions\n{\n    /// <summary>\n    /// Configure cluster client to use ADO.NET persistent streams with default settings.\n    /// </summary>\n    public static IClientBuilder AddAdoNetStreams(this IClientBuilder builder, string name, Action<AdoNetStreamOptions> configureOptions)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(configureOptions);\n\n        return builder.AddAdoNetStreams(name, b =>\n        {\n            b.ConfigureAdoNet(ob => ob.Configure(configureOptions));\n        });\n    }\n\n    /// <summary>\n    /// Configure cluster client to use ADO.NET persistent streams.\n    /// </summary>\n    public static IClientBuilder AddAdoNetStreams(this IClientBuilder builder, string name, Action<ClusterClientAdoNetStreamConfigurator> configure)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(configure);\n\n        var configurator = new ClusterClientAdoNetStreamConfigurator(name, builder);\n\n        configure.Invoke(configurator);\n\n        return builder;\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Hosting/SiloAdoNetStreamConfigurator.cs",
    "content": "using Orleans.Streaming.AdoNet;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Helps set up an individual stream provider on a silo.\n/// </summary>\npublic class SiloAdoNetStreamConfigurator : SiloPersistentStreamConfigurator\n{\n    public SiloAdoNetStreamConfigurator(string name, Action<Action<IServiceCollection>> configureDelegate) : base(name, configureDelegate, AdoNetQueueAdapterFactory.Create)\n    {\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(configureDelegate);\n\n        ConfigureDelegate(services =>\n        {\n            services\n                .ConfigureNamedOptionForLogging<AdoNetStreamOptions>(name)\n                .ConfigureNamedOptionForLogging<SimpleQueueCacheOptions>(name)\n                .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new AdoNetStreamOptionsValidator(sp.GetOptionsByName<AdoNetStreamOptions>(name), name));\n        });\n\n        // in a typical i/o bound shared database there is little benefit to more than one queue per provider\n        // however multiple queues are fully supported if the user wants to fine tune throughput for their own system\n        ConfigurePartitioning(1);\n    }\n\n    public SiloAdoNetStreamConfigurator ConfigureAdoNet(Action<OptionsBuilder<AdoNetStreamOptions>> configureOptions)\n    {\n        ArgumentNullException.ThrowIfNull(configureOptions);\n\n        this.Configure(configureOptions);\n\n        return this;\n    }\n\n    public SiloAdoNetStreamConfigurator ConfigureCache(int cacheSize = SimpleQueueCacheOptions.DEFAULT_CACHE_SIZE)\n    {\n        this.Configure<SimpleQueueCacheOptions>(ob => ob.Configure(options => options.CacheSize = cacheSize));\n\n        return this;\n    }\n\n    public SiloAdoNetStreamConfigurator ConfigurePartitioning(int partitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n    {\n        this.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = partitions));\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Hosting/SiloBuilderAdoNetStreamExtensions.cs",
    "content": "namespace Orleans.Hosting;\n\n/// <summary>\n/// Allows configuration of individual ADO.NET streams in a silo.\n/// </summary>\npublic static class SiloBuilderAdoNetStreamExtensions\n{\n    /// <summary>\n    /// Configure silo to use ADO.NET persistent streams.\n    /// </summary>\n    public static ISiloBuilder AddAdoNetStreams(this ISiloBuilder builder, string name, Action<AdoNetStreamOptions> configureOptions)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(configureOptions);\n\n        return builder.AddAdoNetStreams(name, b =>\n        {\n            b.ConfigureAdoNet(ob => ob.Configure(configureOptions));\n        });\n    }\n\n    /// <summary>\n    /// Configure silo to use ADO.NET persistent streams.\n    /// </summary>\n    public static ISiloBuilder AddAdoNetStreams(this ISiloBuilder builder, string name, Action<SiloAdoNetStreamConfigurator> configure)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n        ArgumentNullException.ThrowIfNull(configure);\n\n        var configurator = new SiloAdoNetStreamConfigurator(name, configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n\n        configure.Invoke(configurator);\n\n        return builder;\n    }\n}"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/MySQL-Streaming.sql",
    "content": "CREATE TABLE OrleansStreamMessageSequence\n(\n    MessageId BIGINT NOT NULL\n);\nINSERT INTO OrleansStreamMessageSequence\nSELECT 0\nWHERE NOT EXISTS (SELECT * FROM OrleansStreamMessageSequence);\n\nDELIMITER $$\n\nCREATE TABLE OrleansStreamMessage\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider*/\n\tQueueId NVARCHAR(150) NOT NULL,\n\n\t/* The unique ascending number of the queued message */\n\tMessageId BIGINT NOT NULL,\n\n\t/* The number of times the event was dequeued */\n\tDequeued INT NOT NULL,\n\n\t/* The UTC time at which the event will become visible */\n\tVisibleOn DATETIME(6) NOT NULL,\n\n\t/* The UTC time at which the event will expire */\n\tExpiresOn DATETIME(6) NOT NULL,\n\n    /* The UTC time at which the event was created - troubleshooting only */\n\tCreatedOn DATETIME(6) NOT NULL,\n\n    /* The UTC time at which the event was updated - troubleshooting only */\n\tModifiedOn DATETIME(6) NOT NULL,\n\n\t/* The arbitrarily large payload of the event */\n\tPayload LONGBLOB NOT NULL,\n\n\t/* This PK supports the various ordered scanning queries. */\n\tPRIMARY KEY (ServiceId, ProviderId, QueueId, MessageId)\n);\n\nDELIMITER $$\n\nCREATE TABLE OrleansStreamDeadLetter\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider*/\n\tQueueId NVARCHAR(150) NOT NULL,\n\n\t/* The unique ascending number of the queued message */\n\tMessageId BIGINT NOT NULL,\n\n\t/* The number of times the event was dequeued */\n\tDequeued INT NOT NULL,\n\n\t/* The UTC time at which the event will become visible */\n\tVisibleOn DATETIME(6) NOT NULL,\n\n\t/* The UTC time at which the event will expire */\n\tExpiresOn DATETIME(6) NOT NULL,\n\n    /* The UTC time at which the event was created - troubleshooting only */\n\tCreatedOn DATETIME(6) NOT NULL,\n\n    /* The UTC time at which the event was updated - troubleshooting only */\n\tModifiedOn DATETIME(6) NOT NULL,\n\n    /* The UTC time at which the event was given up on - troubleshooting only */\n\tDeadOn DATETIME(6) NOT NULL,\n\n\t/* The UTC time at which the event is scheduled to be removed from dead letters */\n\tRemoveOn DATETIME(6) NOT NULL,\n\n\t/* The arbitrarily large payload of the event */\n\tPayload LONGBLOB NULL,\n\n\t/* This PK supports the various ordered scanning queries. */\n\tPRIMARY KEY (ServiceId, ProviderId, QueueId, MessageId)\n);\n\nDELIMITER $$\n\nCREATE TABLE OrleansStreamControl\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider */\n\tQueueId NVARCHAR(150) NOT NULL,\n\n    /* The next due schedule for messages to be evicted */\n    EvictOn DATETIME(6) NOT NULL,\n\n    /* Each row represents a flat configuration object for an individual queue */\n\tPRIMARY KEY (ServiceId, ProviderId, QueueId)\n);\n\nDELIMITER $$\n\nCREATE PROCEDURE QueueStreamMessage\n(\n    IN _ServiceId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n    IN _QueueId NVARCHAR(150),\n    IN _Payload LONGBLOB,\n    IN _ExpiryTimeout INT\n)\nBEGIN\n\nDECLARE _Now DATETIME(6) DEFAULT UTC_TIMESTAMP(6);\nDECLARE _ExpiresOn DATETIME(6) DEFAULT DATE_ADD(_Now, INTERVAL _ExpiryTimeout SECOND);\nDECLARE _MessageId BIGINT;\n\nUPDATE OrleansStreamMessageSequence\nSET MessageId = LAST_INSERT_ID(MessageId + 1);\n\nSET _MessageId = LAST_INSERT_ID();\n\nINSERT INTO OrleansStreamMessage\n(\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    Payload\n)\nVALUES\n(\n    _ServiceId,\n    _ProviderId,\n    _QueueId,\n    _MessageId,\n    0,\n    _Now,\n    _ExpiresOn,\n    _Now,\n    _Now,\n    _Payload\n);\n\nSELECT\n    _ServiceId AS ServiceId,\n    _ProviderId AS ProviderId,\n    _QueueId AS QueueId,\n    _MessageId AS MessageId;\n\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'QueueStreamMessageKey',\n\t'CALL QueueStreamMessage(@ServiceId, @ProviderId, @QueueId, @Payload, @ExpiryTimeout)'\n\nDELIMITER $$\n\nCREATE PROCEDURE GetStreamMessages\n(\n    IN _ServiceId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n\tIN _QueueId NVARCHAR(150),\n    IN _MaxCount INT,\n\tIN _MaxAttempts INT,\n\tIN _VisibilityTimeout INT,\n    IN _RemovalTimeout INT,\n    IN _EvictionInterval INT,\n    IN _EvictionBatchSize INT\n)\nBEGIN\n\nDECLARE _Now DATETIME(6) DEFAULT UTC_TIMESTAMP(6);\nDECLARE _VisibleOn DATETIME(6) DEFAULT DATE_ADD(_Now, INTERVAL _VisibilityTimeout SECOND);\nDECLARE _NextEvictOn TIMESTAMP(6) DEFAULT DATE_ADD(_Now, INTERVAL _EvictionInterval SECOND);\nDECLARE _EvictOn DATETIME(6);\nDECLARE _Count INT;\n\n-- get the next eviction schedule\nSET _EvictOn =\n(\n    SELECT EvictOn\n    FROM OrleansStreamControl\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n);\n\n-- initialize the control row as necessary\nIF _EvictOn IS NULL THEN\n\n    -- race to initialize the control row\n    INSERT OrleansStreamControl\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        EvictOn\n    )\n    VALUES\n    (\n        _ServiceId,\n        _ProviderId,\n        _QueueId,\n        _NextEvictOn\n    )\n    ON DUPLICATE KEY\n    UPDATE\n        EvictOn = EvictOn;\n\n    -- read the winning update\n    SET _EvictOn =\n    (\n        SELECT EvictOn\n        FROM OrleansStreamControl\n        WHERE\n            ServiceId = _ServiceId\n            AND ProviderId = _ProviderId\n            AND QueueId = _QueueId\n    );\n\nEND IF;\n\nIF _EvictOn <= _Now THEN\n\n    -- race to update the control row\n    UPDATE OrleansStreamControl\n    SET EvictOn = _NextEvictOn\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n        AND EvictOn <= _Now;\n\n    -- if we won the race then we also run eviction\n    IF ROW_COUNT() > 0 THEN\n        CALL EvictStreamMessages(_ServiceId, _ProviderId, _QueueId, _MaxAttempts, _RemovalTimeout, _EvictionBatchSize);\n        CALL EvictStreamDeadLetters(_ServiceId, _ProviderId, _QueueId, _EvictionBatchSize);\n    END IF;\n\nEND IF;\n\nSTART TRANSACTION;\n\n/* elect the batch of messages to dequeue and lock them in order */\nCREATE TEMPORARY TABLE _Batch AS\nSELECT\n\tServiceId,\n    ProviderId,\n\tQueueId,\n\tMessageId\nFROM\n    OrleansStreamMessage\nWHERE\n    ServiceId = _ServiceId\n    AND ProviderId = _ProviderId\n    AND QueueId = _QueueId\n    AND Dequeued < _MaxAttempts\n    AND VisibleOn <= _Now\n    AND ExpiresOn > _Now\nORDER BY\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nLIMIT _MaxCount\nFOR UPDATE SKIP LOCKED;\n\n/* update the message batch */\nUPDATE OrleansStreamMessage AS M\nINNER JOIN _Batch AS B\n    ON M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId\nSET\n    M.Dequeued = M.Dequeued + 1,\n    M.VisibleOn = _VisibleOn,\n    M.ModifiedOn = _Now;\n\n/* return the updated batch */\nSELECT\n\tM.ServiceId,\n    M.ProviderId,\n\tM.QueueId,\n\tM.MessageId,\n\tM.Dequeued,\n\tM.VisibleOn,\n\tM.ExpiresOn,\n\tM.CreatedOn,\n\tM.ModifiedOn,\n\tM.Payload\nFROM\n    OrleansStreamMessage AS M\n    INNER JOIN _Batch AS B\n        ON M.ServiceId = B.ServiceId\n        AND M.ProviderId = B.ProviderId\n        AND M.QueueId = B.QueueId\n        AND M.MessageId = B.MessageId;\n\nDROP TEMPORARY TABLE _Batch;\n\nCOMMIT;\n\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'GetStreamMessagesKey',\n\t'CALL GetStreamMessages(@ServiceId, @ProviderId, @QueueId, @MaxCount, @MaxAttempts, @VisibilityTimeout, @RemovalTimeout, @EvictionInterval, @EvictionBatchSize)';\n\nDELIMITER $$\n\nCREATE PROCEDURE ConfirmStreamMessages\n(\n    IN _ServiceId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n    IN _QueueId NVARCHAR(150),\n    IN _Items LONGTEXT\n)\nBEGIN\n\nDECLARE _Delimiter1 NVARCHAR(1) DEFAULT '|';\nDECLARE _Delimiter2 NVARCHAR(1) DEFAULT ':';\nDECLARE _Value LONGTEXT;\nDECLARE _MessageId BIGINT;\nDECLARE _Dequeued INT;\n\nSET _Items = CONCAT(_Items, _Delimiter1);\n\n/* parse the message identifiers to be deleted */\nDROP TEMPORARY TABLE IF EXISTS _ItemsTable;\nCREATE TEMPORARY TABLE _ItemsTable\n(\n    ServiceId NVARCHAR(150) NOT NULL,\n    ProviderId NVARCHAR(150) NOT NULL,\n    QueueId NVARCHAR(150) NOT NULL,\n    MessageId BIGINT NOT NULL,\n    Dequeued INT NOT NULL,\n\n    PRIMARY KEY (ServiceId, ProviderId, QueueId, MessageId)\n);\n\nWHILE LOCATE(_Delimiter1, _Items) > 0 DO\n\n    SET _Value = SUBSTRING_INDEX(_Items, _Delimiter1, 1);\n    SET _MessageId = CAST(SUBSTRING_INDEX(_Value, _Delimiter2, 1) AS UNSIGNED);\n    SET _Dequeued = CAST(SUBSTRING_INDEX(_Value, _Delimiter2, -1) AS UNSIGNED);\n    \n    INSERT INTO _ItemsTable\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId,\n        Dequeued\n    )\n    VALUES\n    (\n        _ServiceId,\n        _ProviderId,\n        _QueueId,\n        _MessageId,\n        _Dequeued\n    );\n\n    SET _Items = SUBSTRING(_Items, LOCATE(_Delimiter1, _Items) + 1);\n\nEND WHILE;\n\nSTART TRANSACTION;\n\n/* elect the batch of messages to confirm and lock them in order */\nCREATE TEMPORARY TABLE _Batch AS\nSELECT\n\tM.ServiceId,\n    M.ProviderId,\n    M.QueueId,\n    M.MessageId\nFROM\n\tOrleansStreamMessage AS M\n    INNER JOIN _ItemsTable AS I\n        ON M.ServiceId = I.ServiceId\n        AND M.ProviderId = I.ProviderId\n        AND M.QueueId = I.QueueId\n        AND M.MessageId = I.MessageId\n        AND M.Dequeued = I.Dequeued\nORDER BY\n    M.ServiceId,\n    M.ProviderId,\n    M.QueueId,\n\tM.MessageId\nFOR UPDATE;\n\n/* delete the elected batch */\nDELETE M\nFROM OrleansStreamMessage AS M\nINNER JOIN _Batch AS B\n    ON M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId;\n\n/* return the ack */\nSELECT\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nFROM\n    _Batch;\n\nDROP TEMPORARY TABLE _Batch;\nDROP TEMPORARY TABLE _ItemsTable;\n\nCOMMIT;\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'ConfirmStreamMessagesKey',\n\t'CALL ConfirmStreamMessages(@ServiceId, @ProviderId, @QueueId, @Items)';\n\nDELIMITER $$\n\nCREATE PROCEDURE FailStreamMessage\n(\n    IN _ServiceId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n    IN _QueueId NVARCHAR(150),\n    IN _MessageId BIGINT,\n    IN _MaxAttempts INT,\n    IN _RemovalTimeout INT\n)\nBEGIN\n\nDECLARE _Now DATETIME(6) DEFAULT UTC_TIMESTAMP(6);\nDECLARE _RemoveOn DATETIME(6) DEFAULT DATE_ADD(_Now, INTERVAL _RemovalTimeout SECOND);\n\n/* if the message can still be dequeued then attempt to mark it visible again */\nUPDATE OrleansStreamMessage\nSET\n    VisibleOn = _Now,\n    ModifiedOn = _Now\nWHERE\n    ServiceId = _ServiceId\n    AND ProviderId = _ProviderId\n    AND QueueId = _QueueId\n    AND MessageId = _MessageId\n    AND Dequeued < _MaxAttempts;\n\nIF ROW_COUNT() = 0 THEN\n\n    START TRANSACTION;\n\n    /* otherwise attempt to move the message to dead letters */\n    CREATE TEMPORARY TABLE Deleted AS\n    SELECT\n        *\n    FROM\n        OrleansStreamMessage\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n        AND MessageId = _MessageId;\n\n    DELETE FROM OrleansStreamMessage\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n        AND MessageId = _MessageId;\n\n    INSERT INTO OrleansStreamDeadLetter\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId,\n        Dequeued,\n        VisibleOn,\n        ExpiresOn,\n        CreatedOn,\n        ModifiedOn,\n        DeadOn,\n        RemoveOn,\n        Payload\n    )\n    SELECT\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId,\n        Dequeued,\n        VisibleOn,\n        ExpiresOn,\n        CreatedOn,\n        ModifiedOn,\n        _Now AS DeadOn,\n        _RemoveOn AS RemoveOn,\n        Payload\n    FROM\n        Deleted;\n\n    COMMIT;\n\nEND IF;\n\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'FailStreamMessageKey',\n\t'CALL FailStreamMessage(@ServiceId, @ProviderId, @QueueId, @MessageId, @MaxAttempts, @RemovalTimeout)'\n\nDELIMITER $$\n\nCREATE PROCEDURE EvictStreamMessages\n(\n\tIN _ServiceId NVARCHAR(150),\n    IN _ProviderId NVARCHAR(150),\n\tIN _QueueId NVARCHAR(150),\n\tIN _BatchSize INT,\n\tIN _MaxAttempts INT,\n\tIN _RemovalTimeout INT\n)\nBEGIN\n\nDECLARE _Now DATETIME(6) DEFAULT UTC_TIMESTAMP();\nDECLARE _RemoveOn DATETIME(6) DEFAULT DATE_ADD(_Now, INTERVAL _RemovalTimeout SECOND);\n\nSTART TRANSACTION;\n\n/* elect the batch of messages to move and lock them in order */\nCREATE TEMPORARY TABLE _Batch AS\nSELECT\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nFROM\n    OrleansStreamMessage\nWHERE\n    ServiceId = _ServiceId\n    AND ProviderId = _ProviderId\n    AND QueueId = _QueueId\n    AND\n\t(\n\t\t-- a message is no longer dequeueable if the last attempt timed out\n\t\t(Dequeued >= _MaxAttempts AND VisibleOn <= _Now)\n\t\tOR\n\t\t-- a message is no longer dequeueable if it has expired regardless\n\t\t(ExpiresOn <= _Now)\n\t)\nORDER BY\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nLIMIT _BatchSize\nFOR UPDATE SKIP LOCKED;\n\n/* copy the messages to dead letters */\nINSERT INTO OrleansStreamDeadLetter\n(\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    DeadOn,\n    RemoveOn,\n    Payload\n)\nSELECT\n    M.ServiceId,\n    M.ProviderId,\n    M.QueueId,\n    M.MessageId,\n    M.Dequeued,\n    M.VisibleOn,\n    M.ExpiresOn,\n    M.CreatedOn,\n    M.ModifiedOn,\n    _Now,\n    _RemoveOn,\n    M.Payload\nFROM\n    OrleansStreamMessage AS M\n    INNER JOIN _Batch AS B\n        ON M.ServiceId = B.ServiceId\n        AND M.ProviderId = B.ProviderId\n        AND M.QueueId = B.QueueId\n        AND M.MessageId = B.MessageId;\n\n/* delete elected messages from the source now */\nDELETE M\nFROM OrleansStreamMessage AS M\nINNER JOIN _Batch AS B\n    ON M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId;\n\nDROP TEMPORARY TABLE _Batch;\n\nCOMMIT;\n\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamMessagesKey',\n\t'CALL EvictStreamMessages(@ServiceId, @ProviderId, @QueueId, @BatchSize, @MaxAttempts, @RemovalTimeout)'\n;\n\nDELIMITER $$\n\nCREATE PROCEDURE EvictStreamDeadLetters\n(\n\t_ServiceId NVARCHAR(150),\n    _ProviderId NVARCHAR(150),\n\t_QueueId NVARCHAR(150),\n\t_BatchSize INT\n)\nBEGIN\n\nDECLARE _Now DATETIME(6) DEFAULT UTC_TIMESTAMP();\n\n/* elect the batch of messages to remove */\nCREATE TEMPORARY TABLE _Batch AS\nSELECT\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nFROM\n    OrleansStreamDeadLetter\nWHERE\n    ServiceId = _ServiceId\n    AND ProviderId = _ProviderId\n    AND QueueId = _QueueId\n    AND RemoveOn <= _Now\nORDER BY\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId\nLIMIT _BatchSize\nFOR UPDATE SKIP LOCKED;\n\n/* now delete the locked messages */\nDELETE M\nFROM OrleansStreamDeadLetter AS M\nINNER JOIN _Batch AS B\n    ON M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId;\n\nDROP TEMPORARY TABLE _Batch;\n\nEND;\n\nDELIMITER $$\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamDeadLettersKey',\n\t'CALL EvictStreamDeadLetters(@ServiceId, @ProviderId, @QueueId, @BatchSize)'\n;\n\nDELIMITER $$"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Orleans.Streaming.AdoNet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Streaming.AdoNet</PackageId>\n    <Title>Microsoft Orleans ADO.NET Streaming Provider</Title>\n    <Description>Microsoft Orleans streaming provider backed by ADO.NET</Description>\n    <PackageTags>$(PackageTags) ADO.NET SQL</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Streaming.AdoNet</AssemblyName>\n    <RootNamespace>Orleans.Streaming.AdoNet</RootNamespace>\n    <DefineConstants>$(DefineConstants);STREAMING_ADONET</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Benchmarks.AdoNet\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/PostgreSQL-Streaming.sql",
    "content": "CREATE SEQUENCE OrleansStreamMessageSequence\nAS BIGINT\nSTART WITH 1\nINCREMENT BY 1\nNO MAXVALUE\nNO CYCLE;\n\nCREATE TABLE OrleansStreamMessage\n(\n\tServiceId VARCHAR(150) NOT NULL,\n    ProviderId VARCHAR(150) NOT NULL,\n\tQueueId VARCHAR(150) NOT NULL,\n\tMessageId BIGINT NOT NULL,\n\tDequeued INT NOT NULL,\n\tVisibleOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tExpiresOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tCreatedOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tModifiedOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tPayload BYTEA NOT NULL,\n\n\tCONSTRAINT PK_OrleansStreamMessage PRIMARY KEY\n\t(\n\t\tServiceId,\n        ProviderId,\n\t\tQueueId,\n\t\tMessageId\n\t)\n);\n\nCREATE TABLE OrleansStreamDeadLetter\n(\n\tServiceId VARCHAR(150) NOT NULL,\n    ProviderId VARCHAR(150) NOT NULL,\n\tQueueId VARCHAR(150) NOT NULL,\n\tMessageId BIGINT NOT NULL,\n\tDequeued INT NOT NULL,\n\tVisibleOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tExpiresOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tCreatedOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tModifiedOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tDeadOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tRemoveOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\tPayload BYTEA,\n\n\tCONSTRAINT PK_OrleansStreamDeadLetter PRIMARY KEY\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    )\n);\n\nCREATE TABLE OrleansStreamControl\n(\n\tServiceId VARCHAR(150) NOT NULL,\n    ProviderId VARCHAR(150) NOT NULL,\n\tQueueId VARCHAR(150) NOT NULL,\n\tEvictOn TIMESTAMP(6) WITHOUT TIME ZONE NOT NULL,\n\n\tCONSTRAINT PK_OrleansStreamControl PRIMARY KEY\n    (\n        ServiceId,\n        ProviderId,\n        QueueId\n    )\n);\n\nCREATE OR REPLACE FUNCTION QueueStreamMessage\n(\n\t_ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n\t_QueueId VARCHAR(150),\n\t_Payload BYTEA,\n\t_ExpiryTimeout INT\n)\nRETURNS TABLE\n(\n\tServiceId VARCHAR(150),\n    ProviderId VARCHAR(150),\n\tQueueId VARCHAR(150),\n\tMessageId BIGINT\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n\t_MessageId BIGINT := nextval('OrleansStreamMessageSequence');\n\t_Now TIMESTAMP(6) WITHOUT TIME ZONE := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';\n\t_ExpiresOn TIMESTAMP(6) WITHOUT TIME ZONE := _Now + INTERVAL '1 SECOND' * _ExpiryTimeout;\nBEGIN\n\nRETURN QUERY\nINSERT INTO OrleansStreamMessage\n(\n\tServiceId,\n\tProviderId,\n\tQueueId,\n\tMessageId,\n\tDequeued,\n\tVisibleOn,\n\tExpiresOn,\n\tCreatedOn,\n\tModifiedOn,\n\tPayload\n)\nVALUES\n(\n\t_ServiceId,\n\t_ProviderId,\n\t_QueueId,\n\t_MessageId,\n\t0,\n\t_Now,\n\t_ExpiresOn,\n\t_Now,\n\t_Now,\n\t_Payload\n)\nRETURNING\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'QueueStreamMessageKey',\n\t'SELECT * FROM QueueStreamMessage(@ServiceId, @ProviderId, @QueueId, @Payload, @ExpiryTimeout)'\n;\n\nCREATE OR REPLACE FUNCTION GetStreamMessages\n(\n\t_ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n\t_QueueId VARCHAR(150),\n    _MaxCount INT,\n\t_MaxAttempts INT,\n\t_VisibilityTimeout INT,\n    _RemovalTimeout INT,\n    _EvictionInterval INT,\n    _EvictionBatchSize INT\n)\nRETURNS TABLE\n(\n\tServiceId VARCHAR(150),\n    ProviderId VARCHAR(150),\n\tQueueId VARCHAR(150),\n\tMessageId BIGINT,\n\tDequeued INT,\n\tVisibleOn TIMESTAMP(6) WITHOUT TIME ZONE,\n\tExpiresOn TIMESTAMP(6) WITHOUT TIME ZONE,\n\tCreatedOn TIMESTAMP(6) WITHOUT TIME ZONE,\n\tModifiedOn TIMESTAMP(6) WITHOUT TIME ZONE,\n\tPayload BYTEA\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n\t_Now TIMESTAMP(6) WITHOUT TIME ZONE := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';\n\t_VisibleOn TIMESTAMP(6) WITHOUT TIME ZONE := _Now + INTERVAL '1 SECOND' * _VisibilityTimeout;\n\t_EvictOn TIMESTAMP(6) WITHOUT TIME ZONE;\n    _NextEvictOn TIMESTAMP(6) WITHOUT TIME ZONE := _Now + INTERVAL '1 SECOND' * _EvictionInterval;\nBEGIN\n\n/* get the next eviction schedule */\nSELECT EvictOn\nINTO _EvictOn\nFROM OrleansStreamControl\nWHERE\n\tServiceId = _ServiceId\n\tAND ProviderId = _ProviderId\n\tAND QueueId = _QueueId;\n\n/* initialize the control row if necessary */\nIF _EvictOn IS NULL THEN\n\n    /* initialize with a past date so eviction runs immediately */\n    INSERT INTO OrleansStreamControl\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        EvictOn\n    )\n    VALUES\n    (\n        _ServiceId,\n        _ProviderId,\n        _QueueId,\n        _Now - INTERVAL '1 SECOND'\n    )\n    ON CONFLICT (ServiceId, ProviderId, QueueId)\n    DO NOTHING;\n\n    /* get the next eviction schedule again */\n    SELECT EvictOn\n    INTO _EvictOn\n    FROM OrleansStreamControl\n    WHERE\n\t    ServiceId = _ServiceId\n\t    AND ProviderId = _ProviderId\n\t    AND QueueId = _QueueId;\n\nEND IF;\n\n/* evict messages if necessary */\nIF _EvictOn <= _Now THEN\n\n    /* race to set the next schedule */\n\tUPDATE OrleansStreamControl\n\tSET EvictOn = _NextEvictOn\n    WHERE\n\t    ServiceId = _ServiceId\n\t\tAND ProviderId = _ProviderId\n\t\tAND QueueId = _QueueId\n\t\tAND EvictOn <= _Now;\n\n    /* if we won the race then we also run the due eviction */\n\tIF (FOUND) THEN\n\t\tCALL EvictStreamMessages(_ServiceId, _ProviderId, _QueueId, _EvictionBatchSize, _MaxAttempts, _RemovalTimeout);\n\t\tCALL EvictStreamDeadLetters(_ServiceId, _ProviderId, _QueueId, _EvictionBatchSize);\n\tEND IF;\n\nEND IF;\n\nRETURN QUERY\nWITH Batch AS\n(\n    /* elect the next batch of visible messages */\n\tSELECT\n\t\tServiceId,\n\t\tProviderId,\n\t\tQueueId,\n\t\tMessageId\n\tFROM\n\t\tOrleansStreamMessage\n\tWHERE\n\t\tServiceId = _ServiceId\n\t\tAND ProviderId = _ProviderId\n\t\tAND QueueId = _QueueId\n\t\tAND Dequeued < _MaxAttempts\n\t\tAND VisibleOn <= _Now\n\t\tAND ExpiresOn > _Now\n\n    /* the criteria below helps prevent deadlocks while improving queue-like throughput */\n\tORDER BY\n\t\tServiceId,\n\t\tProviderId,\n\t\tQueueId,\n\t\tMessageId\n    FOR UPDATE\n\tLIMIT _MaxCount\n)\nUPDATE OrleansStreamMessage AS M\nSET\n\tDequeued = Dequeued + 1,\n\tVisibleOn = _VisibleOn,\n\tModifiedOn = _Now\nFROM\n    Batch AS B\nWHERE\n\tM.ServiceId = B.ServiceId\n\tAND M.ProviderId = B.ProviderId\n\tAND M.QueueId = B.QueueId\n\tAND M.MessageId = B.MessageId\nRETURNING\n    M.ServiceId,\n    M.ProviderId,\n    M.QueueId,\n    M.MessageId,\n    M.Dequeued,\n    M.VisibleOn,\n    M.ExpiresOn,\n    M.CreatedOn,\n    M.ModifiedOn,\n    M.Payload;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'GetStreamMessagesKey',\n\t'SELECT * FROM GetStreamMessages(@ServiceId, @ProviderId, @QueueId, @MaxCount, @MaxAttempts, @VisibilityTimeout, @RemovalTimeout, @EvictionInterval, @EvictionBatchSize)'\n;\n\nCREATE OR REPLACE FUNCTION ConfirmStreamMessages\n(\n\t_ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n\t_QueueId VARCHAR(150),\n    _Items TEXT\n)\nRETURNS TABLE\n(\n\tServiceId VARCHAR(150),\n    ProviderId VARCHAR(150),\n\tQueueId VARCHAR(150),\n\tMessageId BIGINT\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n\t_Count INT;\nBEGIN\n\nCREATE TEMP TABLE _ItemsTable\n(\n\tMessageId BIGINT PRIMARY KEY NOT NULL,\n\tDequeued INT NOT NULL\n) ON COMMIT DROP;\n\nINSERT INTO _ItemsTable\n(\n\tMessageId,\n\tDequeued\n)\nSELECT\n\tCAST(split_part(Value, ':', 1) AS BIGINT) AS MessageId,\n\tCAST(split_part(Value, ':', 2) AS INT) AS Dequeued\nFROM\n\tUNNEST(string_to_array(_Items, '|')) AS Value;\n\nRETURN QUERY\nWITH Batch AS\n(\n\tSELECT\n\t\tM.*\n\tFROM\n\t\tOrleansStreamMessage AS M\n        INNER JOIN _ItemsTable AS I\n            ON I.MessageId = M.MessageId\n            AND I.Dequeued = M.Dequeued\n\tWHERE\n\t\tServiceId = _ServiceId\n\t    AND ProviderId = _ProviderId\n\t\tAND QueueId = _QueueId\n\n    /* the criteria below helps prevent deadlocks */\n\tORDER BY\n\t    ServiceId,\n\t    ProviderId,\n\t    QueueId,\n\t\tMessageId\n    FOR UPDATE\n)\nDELETE FROM OrleansStreamMessage AS M\nUSING Batch AS B\nWHERE\n    M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId\nRETURNING\n    M.ServiceId,\n    M.ProviderId,\n    M.QueueId,\n    M.MessageId;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'ConfirmStreamMessagesKey',\n\t'SELECT * FROM ConfirmStreamMessages(@ServiceId, @ProviderId, @QueueId, @Items)'\n;\n\nCREATE OR REPLACE PROCEDURE FailStreamMessage\n(\n    _ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _QueueId VARCHAR(150),\n    _MessageId BIGINT,\n    _MaxAttempts INT,\n    _RemovalTimeout INT\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n    _Now TIMESTAMP(6) WITHOUT TIME ZONE := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';\n    _RemoveOn TIMESTAMP(6) WITHOUT TIME ZONE := _Now + INTERVAL '1 SECOND' * _RemovalTimeout;\nBEGIN\n\n/* if the message can still be dequeued then attempt to mark it visible again */\nUPDATE OrleansStreamMessage\nSET\n    VisibleOn = _Now,\n    ModifiedOn = _Now\nWHERE\n    ServiceId = _ServiceId\n    AND ProviderId = _ProviderId\n    AND QueueId = _QueueId\n    AND MessageId = _MessageId\n    AND Dequeued < _MaxAttempts;\n\nIF FOUND THEN\n    RETURN;\nEND IF;\n\n/* otherwise attempt to move the message to dead letters */\nWITH Deleted AS\n(\n    DELETE FROM OrleansStreamMessage\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n        AND MessageId = _MessageId\n    RETURNING\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId,\n        Dequeued,\n        VisibleOn,\n        ExpiresOn,\n        CreatedOn,\n        ModifiedOn,\n        Payload\n)\nINSERT INTO OrleansStreamDeadLetter\n(\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    DeadOn,\n    RemoveOn,\n    Payload\n)\nSELECT\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    _Now AS DeadOn,\n    _RemoveOn AS RemoveOn,\n    Payload\nFROM\n    Deleted;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'FailStreamMessageKey',\n\t'CALL FailStreamMessage(@ServiceId, @ProviderId, @QueueId, @MessageId, @MaxAttempts, @RemovalTimeout)'\n;\n\nCREATE OR REPLACE PROCEDURE EvictStreamMessages\n(\n    _ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _QueueId VARCHAR(150),\n    _BatchSize INT,\n    _MaxAttempts INT,\n    _RemovalTimeout INT\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n    _Now TIMESTAMP(6) WITHOUT TIME ZONE := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';\n    _RemoveOn TIMESTAMP(6) WITHOUT TIME ZONE := _Now + INTERVAL '1 second' * _RemovalTimeout;\nBEGIN\n\n/* elect the next batch of messages to evict */\nWITH Batch AS\n(\n    SELECT\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    FROM\n        OrleansStreamMessage\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n\n        -- the message was given the opportunity to complete\n        AND VisibleOn <= _Now\n\t\tAND\n\t\t(\n\t\t\t-- the message was dequeued too many times\n\t\t\tDequeued >= _MaxAttempts\n\t\t\tOR\n\t\t\t-- the message expired\n\t\t\tExpiresOn <= _Now\n\t\t)\n\n    /* the criteria below helps prevent deadlocks while improving queue-like throughput */\n    ORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    FOR UPDATE\n    LIMIT _BatchSize\n),\n\n/* delete the messages locked in the batch */\nDeleted AS\n(\n    DELETE FROM OrleansStreamMessage AS M\n    USING Batch AS B\n    WHERE\n        M.ServiceId = B.ServiceId\n        AND M.ProviderId = B.ProviderId\n        AND M.QueueId = B.QueueId\n        AND M.MessageId = B.MessageId\n    RETURNING\n        M.ServiceId,\n        M.ProviderId,\n        M.QueueId,\n        M.MessageId,\n        M.Dequeued,\n        M.VisibleOn,\n        M.ExpiresOn,\n        M.CreatedOn,\n        M.ModifiedOn,\n        M.Payload\n)\n\n/* copy the deleted messages to the dead-letter table */\nINSERT INTO OrleansStreamDeadLetter\n(\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    DeadOn,\n    RemoveOn,\n    Payload\n)\nSELECT\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    _Now,\n    _RemoveOn,\n    Payload\nFROM\n    Deleted AS D;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamMessagesKey',\n\t'CALL EvictStreamMessages(@ServiceId, @ProviderId, @QueueId, @BatchSize, @MaxAttempts, @RemovalTimeout)'\n;\n\nCREATE OR REPLACE PROCEDURE EvictStreamDeadLetters\n(\n    _ServiceId VARCHAR(150),\n    _ProviderId VARCHAR(150),\n    _QueueId VARCHAR(150),\n    _BatchSize INT\n)\nLANGUAGE plpgsql\nAS $$\n#VARIABLE_CONFLICT USE_COLUMN\nDECLARE\n    _Now TIMESTAMP(6) WITHOUT TIME ZONE := CURRENT_TIMESTAMP AT TIME ZONE 'UTC';\nBEGIN\n\n/* elect the next batch of dead letters to evict */\nWITH Batch AS\n(\n    SELECT\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    FROM\n        OrleansStreamDeadLetter\n    WHERE\n        ServiceId = _ServiceId\n        AND ProviderId = _ProviderId\n        AND QueueId = _QueueId\n        AND RemoveOn <= _Now\n\n    /* the criteria below helps prevent deadlocks while improving queue-like throughput */\n    ORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    FOR UPDATE\n    LIMIT _BatchSize\n)\nDELETE FROM OrleansStreamDeadLetter AS M\nUSING Batch AS B\nWHERE\n    M.ServiceId = B.ServiceId\n    AND M.ProviderId = B.ProviderId\n    AND M.QueueId = B.QueueId\n    AND M.MessageId = B.MessageId;\n\nEND;\n$$;\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamDeadLettersKey',\n\t'CALL EvictStreamDeadLetters(@ServiceId, @ProviderId, @QueueId, @BatchSize)'\n;"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/Properties/Usings.cs",
    "content": "global using System;\nglobal using System.Collections.Concurrent;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using System.Threading.Tasks;\nglobal using Microsoft.Extensions.DependencyInjection;\nglobal using Microsoft.Extensions.Logging;\nglobal using Microsoft.Extensions.Options;\nglobal using Orleans.Configuration;\nglobal using Orleans.Configuration.Overrides;\nglobal using Orleans.Hosting;\nglobal using Orleans.Providers.Streams.Common;\nglobal using Orleans.Runtime;\nglobal using Orleans.Serialization;\nglobal using Orleans.Streaming.AdoNet.Storage;\nglobal using Orleans.Streams;\n"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/README.md",
    "content": "# Microsoft Orleans Streaming for ADO.NET\n\n## Introduction\nMicrosoft Orleans Streaming for ADO.NET provides a stream provider implementation for Orleans using ADO.NET-compatible databases (SQL Server, MySQL, PostgreSQL, etc.). This allows for publishing and subscribing to streams of events with relational databases as the underlying infrastructure.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Streaming.AdoNet\n```\n\nYou will also need to install the appropriate ADO.NET provider for your database:\n\n```shell\n# For SQL Server\ndotnet add package Microsoft.Data.SqlClient\n\n# For MySQL\ndotnet add package MySql.Data\n\n# For PostgreSQL\ndotnet add package Npgsql\n```\n\n## Example - Configuring ADO.NET Streaming\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Streams;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure ADO.NET as a stream provider\n            .AddAdoNetStreams(\n                name: \"AdoNetStreamProvider\",\n                configureOptions: options =>\n                {\n                    options.Invariant = \"Microsoft.Data.SqlClient\";  // For SQL Server\n                    options.ConnectionString = \"Server=localhost;Database=OrleansStreaming;User ID=orleans;******;\";\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using ADO.NET Streams in a Grain\n```csharp\n// Producer grain\npublic class ProducerGrain : Grain, IProducerGrain\n{\n    private IAsyncStream<string> _stream;\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"AdoNetStreamProvider\");\n        _stream = streamProvider.GetStream<string>(Guid.NewGuid(), \"MyStreamNamespace\");\n\n        return base.OnActivateAsync(cancellationToken);\n    }\n\n    public async Task SendMessage(string message)\n    {\n        // Send a message to the stream\n        await _stream.OnNextAsync(message);\n    }\n}\n\n// Consumer grain\npublic class ConsumerGrain : Grain, IConsumerGrain, IAsyncObserver<string>\n{\n    private StreamSubscriptionHandle<string> _subscription;\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"AdoNetStreamProvider\");\n        var stream = streamProvider.GetStream<string>(this.GetPrimaryKey(), \"MyStreamNamespace\");\n\n        // Subscribe to the stream\n        _subscription = await stream.SubscribeAsync(this);\n\n        await base.OnActivateAsync(cancellationToken);\n    }\n\n    public Task OnNextAsync(string item, StreamSequenceToken token = null)\n    {\n        Console.WriteLine($\"Received message: {item}\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnCompletedAsync()\n    {\n        Console.WriteLine(\"Stream completed\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnErrorAsync(Exception ex)\n    {\n        Console.WriteLine($\"Stream error: {ex.Message}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Streams](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/index)\n- [Stream Providers](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/stream-providers)\n- [ADO.NET Database Setup](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/adonet-configuration)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/AdoNet/Orleans.Streaming.AdoNet/SQLServer-Streaming.sql",
    "content": "/*\nOrleans Stream Message Sequence.\nThis sequence reduces contention on generation of [MessageId] values vs an identity column.\nThe CACHE parameter can be increased to further reduce contention.\n*/\nCREATE SEQUENCE OrleansStreamMessageSequence\nAS BIGINT\nSTART WITH 1\nINCREMENT BY 1\nNO MAXVALUE\nNO CYCLE\nCACHE 1000;\nGO\n\n/*\nOrleans Streaming Message Queue.\n\nThis table stores queued messages awaiting processing by Orleans.\n\nThe demands for this table are as follows:\n\n1. The table will see inserts only at the tail, as new rows are added.\n2. The table will be polled with high frequency to reserve the first batch of rows that matches a well-known criteria (\"visible\" and \"not expired\" and \"under max attempts\").\n3. The table will see rows being removed at the head as messages are confirmed.\n4. The table will see rows being removed at the head as expired messages are moved to dead letters.\n5. Due to the above queries touching more than one row at a time, there is a possibility of deadlocks.\n6. A few faulted or poisoned messages can linger for some time at the head before being moved to dead letters.\n7. The table will occasionaly become empty or at least sparse as the cluster succeeds to catch up to all messages.\n\nWhile [1-6] all cause page fragmentation over time, [7] self resolves this degradation by allowing sql server to eventually remove all pages.\nTherefore the design attempts to optimise for [2] while assuming the resulting degradation eventually resolves itself.\n\nThe design also attempts to minimize the possibility of deadlocks at the expense of higher locking contention.\nThis happens by forcing all queries to touch data in the exact same order of the clustered index.\nThis induces ordered resource lock acquisition while avoiding the cost of ordering itself.\n\n*/\nCREATE TABLE OrleansStreamMessage\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider*/\n\tQueueId NVARCHAR(150) NOT NULL,\n\n\t/* The unique ascending number of the queued message */\n\tMessageId BIGINT NOT NULL,\n\n\t/* The number of times the event was dequeued */\n\tDequeued INT NOT NULL,\n\n\t/* The UTC time at which the event will become visible */\n\tVisibleOn DATETIME2(7) NOT NULL,\n\n\t/* The UTC time at which the event will expire */\n\tExpiresOn DATETIME2(7) NOT NULL,\n\n    /* The UTC time at which the event was created - troubleshooting only */\n\tCreatedOn DATETIME2(7) NOT NULL,\n\n    /* The UTC time at which the event was updated - troubleshooting only */\n\tModifiedOn DATETIME2(7) NOT NULL,\n\n\t/* The arbitrarily large payload of the event */\n\tPayload VARBINARY(MAX) NOT NULL,\n\n\t/* This Clustered PK supports the various ordered scanning queries. */\n\tCONSTRAINT PK_OrleansStreamMessage PRIMARY KEY CLUSTERED\n\t(\n\t\tServiceId ASC,\n        ProviderId ASC,\n\t\tQueueId ASC,\n\t\tMessageId ASC\n\t)\n);\nGO\n\n/*\nOrleans Streaming Dead Letters.\n\nThis table holds events that could not be processed within the allowed number of attempts or that have expired.\n*/\nCREATE TABLE OrleansStreamDeadLetter\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider*/\n\tQueueId NVARCHAR(150) NOT NULL,\n\n\t/* The unique ascending number of the queued message */\n\tMessageId BIGINT NOT NULL,\n\n\t/* The number of times the event was dequeued */\n\tDequeued INT NOT NULL,\n\n\t/* The UTC time at which the event will become visible */\n\tVisibleOn DATETIME2(7) NOT NULL,\n\n\t/* The UTC time at which the event will expire */\n\tExpiresOn DATETIME2(7) NOT NULL,\n\n    /* The UTC time at which the event was created - troubleshooting only */\n\tCreatedOn DATETIME2(7) NOT NULL,\n\n    /* The UTC time at which the event was updated - troubleshooting only */\n\tModifiedOn DATETIME2(7) NOT NULL,\n\n    /* The UTC time at which the event was given up on - troubleshooting only */\n\tDeadOn DATETIME2(7) NOT NULL,\n\n\t/* The UTC time at which the event is scheduled to be removed from dead letters */\n\tRemoveOn DATETIME2(7) NOT NULL,\n\n\t/* The arbitrarily large payload of the event */\n\tPayload VARBINARY(MAX) NULL,\n\n\t/* This Clustered PK supports the various ordered scanning queries. */\n    /* Its main purpose is to help partition the update row locks as to minimize dequeing contention. */\n\tCONSTRAINT PK_OrleansStreamDeadLetter PRIMARY KEY CLUSTERED\n\t(\n\t\tServiceId ASC,\n        ProviderId ASC,\n\t\tQueueId ASC,\n\t\tMessageId ASC\n\t)\n);\nGO\n\n/*\nOrleans Streaming Control Table.\nThis table holds schedule variables to help providers self manage their own work.\n*/\nCREATE TABLE OrleansStreamControl\n(\n\t/* Identifies the application */\n\tServiceId NVARCHAR(150) NOT NULL,\n\n    /* Identifies the provider within the application */\n    ProviderId NVARCHAR(150) NOT NULL,\n\n\t/* Identifies the individual queue shard as configured in the provider */\n\tQueueId NVARCHAR(150) NOT NULL,\n\n    /* The next due schedule for messages to be evicted */\n    EvictOn DATETIME2(7) NOT NULL,\n\n    /* Each row represents a flat configuration object for an individual queue */\n\tCONSTRAINT PK_OrleansStreamControl PRIMARY KEY CLUSTERED\n\t(\n\t\tServiceId ASC,\n        ProviderId ASC,\n\t\tQueueId ASC\n\t)\n);\nGO\n\n/* Queues a message to the Orleans Streaming Message Queue */\nCREATE PROCEDURE QueueStreamMessage\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n\t@Payload VARBINARY(MAX),\n\t@ExpiryTimeout INT\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @MessageId BIGINT = NEXT VALUE FOR OrleansStreamMessageSequence;\nDECLARE @Now DATETIME2(7) = SYSUTCDATETIME();\nDECLARE @ExpiresOn DATETIME2(7) = DATEADD(SECOND, @ExpiryTimeout, @Now);\n\nINSERT INTO OrleansStreamMessage\n(\n\tServiceId,\n    ProviderId,\n\tQueueId,\n\tMessageId,\n\tDequeued,\n\tVisibleOn,\n\tExpiresOn,\n\tCreatedOn,\n\tModifiedOn,\n\tPayload\n)\nOUTPUT\n    Inserted.ServiceId,\n    Inserted.ProviderId,\n    Inserted.QueueId,\n    Inserted.MessageId\nVALUES\n(\n\t@ServiceId,\n    @ProviderId,\n\t@QueueId,\n\t@MessageId,\n\t0,\n\t@Now,\n\t@ExpiresOn,\n\t@Now,\n\t@Now,\n\t@Payload\n);\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'QueueStreamMessageKey',\n\t'EXECUTE QueueStreamMessage @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @Payload = @Payload, @ExpiryTimeout = @ExpiryTimeout'\nGO\n\n/* Gets message batches from the Orleans Streaming Message Queue */\n/* Also opportunistically performs eviction activities when they are due */\nCREATE PROCEDURE GetStreamMessages\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n    @MaxCount INT,\n\t@MaxAttempts INT,\n\t@VisibilityTimeout INT,\n    @RemovalTimeout INT,\n    @EvictionInterval INT,\n    @EvictionBatchSize INT\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @Now DATETIME2(7) = SYSUTCDATETIME();\nDECLARE @VisibleOn DATETIME2(7) = DATEADD(SECOND, @VisibilityTimeout, @Now);\n\n/* lightweight check to see if an eviction activity is due */\nDECLARE @EvictOn DATETIME2(7) =\n(\n    SELECT EvictOn\n    FROM OrleansStreamControl\n    WHERE\n        ServiceId = @ServiceId\n        AND ProviderId = @ProviderId\n        AND QueueId = @QueueId\n);\n\n/* escalate to a eviction attempt only if an activity is due */\nIF @EvictOn IS NULL OR @EvictOn < @Now\nBEGIN\n\n    /* attempt to win a race to update the schedule */\n    /* this will also initialize the table if necessary */\n    WITH Candidate AS\n    (\n        SELECT\n            ServiceId = @ServiceId,\n            ProviderId = @ProviderId,\n            QueueId = @QueueId,\n            Now = @Now,\n            EvictOn = DATEADD(SECOND, @EvictionInterval, @Now)\n    )\n    MERGE OrleansStreamControl WITH (UPDLOCK, HOLDLOCK) AS T\n    USING Candidate AS S\n    ON T.ServiceId = S.ServiceId\n    AND T.ProviderId = S.ProviderId\n    AND T.QueueId = S.QueueId\n    WHEN MATCHED AND T.EvictOn < S.Now THEN\n    UPDATE SET T.EvictOn = S.EvictOn\n    WHEN NOT MATCHED BY TARGET THEN\n    INSERT\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        EvictOn\n    )\n    VALUES\n    (\n        ServiceId,\n        ProviderId,\n        QueueId,\n        EvictOn\n    );\n\n    /* if the above statement won the race then we also get to run the eviction */\n    /* other concurrent queries will continue running as normal until the next due time */\n    IF (@@ROWCOUNT > 0)\n    BEGIN\n\n        /* evict messages */\n        EXECUTE EvictStreamMessages\n            @ServiceId = @ServiceId,\n            @ProviderId = @ProviderId,\n            @QueueId = @QueueId,\n            @MaxAttempts = @MaxAttempts,\n            @RemovalTimeout = @RemovalTimeout,\n            @BatchSize = @EvictionBatchSize\n\n        /* evict dead letters */\n        EXECUTE EvictStreamDeadLetters\n            @ServiceId = @ServiceId,\n            @ProviderId = @ProviderId,\n            @QueueId = @QueueId,\n            @BatchSize = @EvictionBatchSize;\n            \n    END;\n\nEND;\n\n/* update messages in the exact same order as the clustered index to avoid deadlocks with other queries */\nWITH Batch AS\n(\n\tSELECT TOP (@MaxCount)\n\t\tServiceId,\n        ProviderId,\n\t\tQueueId,\n\t\tMessageId,\n\t\tDequeued,\n\t\tVisibleOn,\n\t\tExpiresOn,\n\t\tCreatedOn,\n\t\tModifiedOn,\n\t\tPayload\n\tFROM\n\t\tOrleansStreamMessage WITH (UPDLOCK)\n\tWHERE\n\t\tServiceId = @ServiceId\n        AND ProviderId = @ProviderId\n\t\tAND QueueId = @QueueId\n\t\tAND Dequeued < @MaxAttempts\n\t\tAND VisibleOn <= @Now\n\t\tAND ExpiresOn > @Now\n\tORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n\t\tMessageId\n)\nUPDATE Batch\nSET\n\tDequeued += 1,\n\tVisibleOn = @VisibleOn,\n\tModifiedOn = @Now\nOUTPUT\n\tInserted.ServiceId,\n    Inserted.ProviderId,\n\tInserted.QueueId,\n\tInserted.MessageId,\n\tInserted.Dequeued,\n\tInserted.VisibleOn,\n\tInserted.ExpiresOn,\n\tInserted.CreatedOn,\n\tInserted.ModifiedOn,\n\tInserted.Payload\nFROM\n\tBatch;\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'GetStreamMessagesKey',\n\t'EXECUTE GetStreamMessages @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @MaxCount = @MaxCount, @MaxAttempts = @MaxAttempts, @VisibilityTimeout = @VisibilityTimeout, @RemovalTimeout = @RemovalTimeout, @EvictionInterval = @EvictionInterval, @EvictionBatchSize = @EvictionBatchSize'\nGO\n\n/* Confirms delivery of a stream message. */\nCREATE PROCEDURE ConfirmStreamMessages\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n    @Items NVARCHAR(MAX)\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\n/* parse the message identifiers to be deleted */\nDECLARE @ItemsTable TABLE\n(\n    MessageId BIGINT PRIMARY KEY NOT NULL,\n    Dequeued INT NOT NULL\n);\nWITH Items AS\n(\n\tSELECT Value FROM STRING_SPLIT(@Items, '|')\n)\nINSERT INTO @ItemsTable\n(\n    MessageId,\n    Dequeued\n)\nSELECT\n\tCAST(SUBSTRING(Value, 1, CHARINDEX(':', Value, 1) - 1) AS BIGINT) AS MessageId,\n\tCAST(SUBSTRING(Value, CHARINDEX(':', Value, 1) + 1, LEN(Value)) AS INT) AS Dequeued\nFROM\n\tItems;\n\n/* count the number of messages to delete so we can use order by in the next query */\nDECLARE @Count INT = (SELECT COUNT(*) FROM @ItemsTable);\n\n/* delete messages in the exact same order as the clustered index to avoid deadlocks with other queries */\nWITH Batch AS\n(\n\tSELECT TOP (@Count)\n\t\t*\n\tFROM\n\t\tOrleansStreamMessage AS M WITH (UPDLOCK, HOLDLOCK)\n\tWHERE\n\t\tServiceId = @ServiceId\n        AND ProviderId = @ProviderId\n\t\tAND QueueId = @QueueId\n        AND EXISTS\n        (\n            SELECT *\n            FROM @ItemsTable AS I\n            WHERE I.MessageId = M.MessageId\n            AND I.Dequeued = M.Dequeued\n        )\n\tORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n\t\tMessageId\n)\nDELETE FROM Batch\nOUTPUT\n    Deleted.ServiceId,\n    Deleted.ProviderId,\n    Deleted.QueueId,\n    Deleted.MessageId;\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'ConfirmStreamMessagesKey',\n\t'EXECUTE ConfirmStreamMessages @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @Items = @Items'\nGO\n\n/* Applies delivery failure rules to the specified message. */\n/* If the message has been dequeued too many times, we move it to the dead letter table. */\n/* If the message has expired, we move to the dead letter table. */\n/* If the message is still eligible for delivery, it is made visible again. */\nCREATE PROCEDURE FailStreamMessage\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n    @MessageId BIGINT,\n\t@MaxAttempts INT,\n\t@RemovalTimeout INT\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @Now DATETIME2(7) = SYSUTCDATETIME();\nDECLARE @RemoveOn DATETIME2(7) = DATEADD(SECOND, @RemovalTimeout, @Now);\n\n/* if the message can still be dequeued then attempt to mark it visible again */\nUPDATE OrleansStreamMessage\nSET\n    VisibleOn = @Now,\n    ModifiedOn = @Now\nWHERE\n    ServiceId = @ServiceId\n    AND ProviderId = @ProviderId\n    AND QueueId = @QueueId\n    AND MessageId = @MessageId\n    AND Dequeued < @MaxAttempts;\n\nIF @@ROWCOUNT > 0 RETURN;\n\n/* otherwise attempt to move the message to dead letters */\nDELETE FROM OrleansStreamMessage\nOUTPUT\n    Deleted.ServiceId,\n    Deleted.ProviderId,\n    Deleted.QueueId,\n    Deleted.MessageId,\n    Deleted.Dequeued,\n    Deleted.VisibleOn,\n    Deleted.ExpiresOn,\n    Deleted.CreatedOn,\n    Deleted.ModifiedOn,\n    @Now AS DeadOn,\n    @RemoveOn AS RemoveOn,\n    Deleted.Payload\nINTO OrleansStreamDeadLetter\n(\n    ServiceId,\n    ProviderId,\n    QueueId,\n    MessageId,\n    Dequeued,\n    VisibleOn,\n    ExpiresOn,\n    CreatedOn,\n    ModifiedOn,\n    DeadOn,\n    RemoveOn,\n    Payload\n)\nWHERE\n    ServiceId = @ServiceId\n    AND ProviderId = @ProviderId\n    AND QueueId = @QueueId\n    AND MessageId = @MessageId;\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'FailStreamMessageKey',\n\t'EXECUTE FailStreamMessage @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @MessageId = @MessageId, @MaxAttempts = @MaxAttempts, @RemovalTimeout = @RemovalTimeout'\nGO\n\n/* Moves non-delivered messages from the message table to the dead letter table for human troubleshooting. */\nCREATE PROCEDURE EvictStreamMessages\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n\t@BatchSize INT,\n\t@MaxAttempts INT,\n\t@RemovalTimeout INT\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @Now DATETIME2(7) = SYSUTCDATETIME();\nDECLARE @RemoveOn DATETIME2(7) = DATEADD(SECOND, @RemovalTimeout, @Now);\n\n/* delete messages in the exact same order as the clustered index to avoid deadlocks with other queries */\nWITH Batch AS\n(\n\tSELECT TOP (@BatchSize)\n\t\tServiceId,\n        ProviderId,\n\t\tQueueId,\n\t\tMessageId,\n\t\tDequeued,\n\t\tVisibleOn,\n\t\tExpiresOn,\n\t\tCreatedOn,\n\t\tModifiedOn,\n\t\tDeadOn = @Now,\n\t\tRemoveOn = @RemoveOn,\n\t\tPayload\n\tFROM\n\t\tOrleansStreamMessage WITH (UPDLOCK)\n\tWHERE\n\t\tServiceId = @ServiceId\n        AND ProviderId = @ProviderId\n\t\tAND QueueId = @QueueId\n\n        -- the message was given the opportunity to complete\n        AND VisibleOn <= @Now\n\t\tAND\n\t\t(\n\t\t\t-- the message was dequeued too many times\n\t\t\tDequeued >= @MaxAttempts\n\t\t\tOR\n\t\t\t-- the message expired\n\t\t\tExpiresOn <= @Now\n\t\t)\n\tORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n\t\tMessageId\n)\nDELETE FROM Batch\nOUTPUT\n\tDeleted.ServiceId,\n    Deleted.ProviderId,\n\tDeleted.QueueId,\n\tDeleted.MessageId,\n\tDeleted.Dequeued,\n\tDeleted.VisibleOn,\n\tDeleted.ExpiresOn,\n\tDeleted.CreatedOn,\n\tDeleted.ModifiedOn,\n\tDeleted.DeadOn,\n\tDeleted.RemoveOn,\n\tDeleted.Payload\nINTO OrleansStreamDeadLetter\n(\n\tServiceId,\n    ProviderId,\n\tQueueId,\n\tMessageId,\n\tDequeued,\n\tVisibleOn,\n\tExpiresOn,\n\tCreatedOn,\n\tModifiedOn,\n\tDeadOn,\n\tRemoveOn,\n\tPayload\n);\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamMessagesKey',\n\t'EXECUTE EvictStreamMessages @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @BatchSize = @BatchSize, @MaxAttempts = @MaxAttempts, @RemovalTimeout = @RemovalTimeout'\nGO\n\n/* Removes messages from the dead letters table. */\nCREATE PROCEDURE EvictStreamDeadLetters\n\t@ServiceId NVARCHAR(150),\n    @ProviderId NVARCHAR(150),\n\t@QueueId NVARCHAR(150),\n\t@BatchSize INT\nAS\nBEGIN\n\nSET NOCOUNT ON;\nSET XACT_ABORT ON;\n\nDECLARE @Now DATETIME2(7) = SYSUTCDATETIME();\n\n/* delete messages in the exact same order as the clustered index to avoid deadlocks with other queries */\nWITH Batch AS\n(\n    SELECT TOP (@BatchSize)\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n    FROM\n        OrleansStreamDeadLetter WITH (UPDLOCK)\n    WHERE\n        ServiceId = @ServiceId\n        AND ProviderId = @ProviderId\n        AND QueueId = @QueueId\n        AND RemoveOn <= @Now\n    ORDER BY\n        ServiceId,\n        ProviderId,\n        QueueId,\n        MessageId\n)\nDELETE FROM Batch;\n\nEND\nGO\n\nINSERT INTO OrleansQuery\n(\n\tQueryKey,\n\tQueryText\n)\nSELECT\n\t'EvictStreamDeadLettersKey',\n\t'EXECUTE EvictStreamDeadLetters @ServiceId = @ServiceId, @ProviderId = @ProviderId, @QueueId = @QueueId, @BatchSize = @BatchSize'\nGO\n"
  },
  {
    "path": "src/AdoNet/Shared/MySQL-Main.sql",
    "content": "/*\nImplementation notes:\n\n1) The general idea is that data is read and written through Orleans specific queries.\n   Orleans operates on column names and types when reading and on parameter names and types when writing.\n\n2) The implementations *must* preserve input and output names and types. Orleans uses these parameters to reads query results by name and type.\n   Vendor and deployment specific tuning is allowed and contributions are encouraged as long as the interface contract\n   is maintained.\n\n3) The implementation across vendor specific scripts *should* preserve the constraint names. This simplifies troubleshooting\n   by virtue of uniform naming across concrete implementations.\n\n5) ETag for Orleans is an opaque column that represents a unique version. The type of its actual implementation\n   is not important as long as it represents a unique version. In this implementation we use integers for versioning\n\n6) For the sake of being explicit and removing ambiguity, Orleans expects some queries to return either TRUE as >0 value\n   or FALSE as =0 value. That is, affected rows or such does not matter. If an error is raised or an exception is thrown\n   the query *must* ensure the entire transaction is rolled back and may either return FALSE or propagate the exception.\n   Orleans handles exception as a failure and will retry.\n\n7) The implementation follows the Extended Orleans membership protocol. For more information, see at:\n        https://learn.microsoft.com/dotnet/orleans/implementation/cluster-management\n        https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs\n*/\n-- This table defines Orleans operational queries. Orleans uses these to manage its operations,\n-- these are the only queries Orleans issues to the database.\n-- These can be redefined (e.g. to provide non-destructive updates) provided the stated interface principles hold.\nCREATE TABLE OrleansQuery\n(\n    QueryKey VARCHAR(64) NOT NULL,\n    QueryText VARCHAR(8000) NOT NULL,\n\n    CONSTRAINT OrleansQuery_Key PRIMARY KEY(QueryKey)\n);\n"
  },
  {
    "path": "src/AdoNet/Shared/Oracle-Main.sql",
    "content": "/*\nImplementation notes:\n\n1) The general idea is that data is read and written through Orleans specific queries.\n   Orleans operates on column names and types when reading and on parameter names and types when writing.\n\n2) The implementations *must* preserve input and output names and types. Orleans uses these parameters to reads query results by name and type.\n   Vendor and deployment specific tuning is allowed and contributions are encouraged as long as the interface contract\n   is maintained.\n\n3) The implementation across vendor specific scripts *should* preserve the constraint names. This simplifies troubleshooting\n   by virtue of uniform naming across concrete implementations.\n\n5) ETag for Orleans is an opaque column that represents a unique version. The type of its actual implementation\n   is not important as long as it represents a unique version. In this implementation we use integers for versioning\n\n6) For the sake of being explicit and removing ambiguity, Orleans expects some queries to return either TRUE as >0 value\n   or FALSE as =0 value. That is, affected rows or such does not matter. If an error is raised or an exception is thrown\n   the query *must* ensure the entire transaction is rolled back and may either return FALSE or propagate the exception.\n   Orleans handles exception as a failure and will retry.\n\n7) The implementation follows the Extended Orleans membership protocol. For more information, see at:\n        https://learn.microsoft.com/dotnet/orleans/implementation/cluster-management\n        https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs\n*/\n\n-- This table defines Orleans operational queries. Orleans uses these to manage its operations,\n-- these are the only queries Orleans issues to the database.\n-- These can be redefined (e.g. to provide non-destructive updates) provided the stated interface principles hold.\nCREATE TABLE \"ORLEANSQUERY\"\n(\n    \"QUERYKEY\" VARCHAR2(64 BYTE) NOT NULL ENABLE,\n    \"QUERYTEXT\" VARCHAR2(4000 BYTE),\n\n    CONSTRAINT \"ORLEANSQUERY_PK\" PRIMARY KEY (\"QUERYKEY\")\n);\n/\n\nCOMMIT;\n\n-- Oracle specific implementation note:\n-- Some OrleansQueries are implemented as functions and differ from the scripts of other databases.\n-- The main reason for this is the fact, that oracle doesn't support returning variables from queries\n-- directly. So in the case that a variable value is needed as output of a OrleansQuery (e.g. version)\n-- a function is used.\n"
  },
  {
    "path": "src/AdoNet/Shared/PostgreSQL-Main.sql",
    "content": "-- requires Postgres 9.5 (or perhaps higher)\n\n/*\nImplementation notes:\n\n1) The general idea is that data is read and written through Orleans specific queries.\n   Orleans operates on column names and types when reading and on parameter names and types when writing.\n\n2) The implementations *must* preserve input and output names and types. Orleans uses these parameters to reads query results by name and type.\n   Vendor and deployment specific tuning is allowed and contributions are encouraged as long as the interface contract\n   is maintained.\n\n3) The implementation across vendor specific scripts *should* preserve the constraint names. This simplifies troubleshooting\n   by virtue of uniform naming across concrete implementations.\n\n5) ETag for Orleans is an opaque column that represents a unique version. The type of its actual implementation\n   is not important as long as it represents a unique version. In this implementation we use integers for versioning\n\n6) For the sake of being explicit and removing ambiguity, Orleans expects some queries to return either TRUE as >0 value\n   or FALSE as =0 value. That is, affected rows or such does not matter. If an error is raised or an exception is thrown\n   the query *must* ensure the entire transaction is rolled back and may either return FALSE or propagate the exception.\n   Orleans handles exception as a failure and will retry.\n\n7) The implementation follows the Extended Orleans membership protocol. For more information, see at:\n        https://learn.microsoft.com/dotnet/orleans/implementation/cluster-management\n        https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs\n*/\n\n\n\n-- This table defines Orleans operational queries. Orleans uses these to manage its operations,\n-- these are the only queries Orleans issues to the database.\n-- These can be redefined (e.g. to provide non-destructive updates) provided the stated interface principles hold.\nCREATE TABLE OrleansQuery\n(\n    QueryKey varchar(64) NOT NULL,\n    QueryText varchar(8000) NOT NULL,\n\n    CONSTRAINT OrleansQuery_Key PRIMARY KEY(QueryKey)\n);\n"
  },
  {
    "path": "src/AdoNet/Shared/SQLServer-Main.sql",
    "content": "/*\nImplementation notes:\n\n1) The general idea is that data is read and written through Orleans specific queries.\n   Orleans operates on column names and types when reading and on parameter names and types when writing.\n\n2) The implementations *must* preserve input and output names and types. Orleans uses these parameters to reads query results by name and type.\n   Vendor and deployment specific tuning is allowed and contributions are encouraged as long as the interface contract\n   is maintained.\n\n3) The implementation across vendor specific scripts *should* preserve the constraint names. This simplifies troubleshooting\n   by virtue of uniform naming across concrete implementations.\n\n5) ETag for Orleans is an opaque column that represents a unique version. The type of its actual implementation\n   is not important as long as it represents a unique version. In this implementation we use integers for versioning\n\n6) For the sake of being explicit and removing ambiguity, Orleans expects some queries to return either TRUE as >0 value\n   or FALSE as =0 value. That is, affected rows or such does not matter. If an error is raised or an exception is thrown\n   the query *must* ensure the entire transaction is rolled back and may either return FALSE or propagate the exception.\n   Orleans handles exception as a failure and will retry.\n\n7) The implementation follows the Extended Orleans membership protocol. For more information, see at:\n        https://learn.microsoft.com/dotnet/orleans/implementation/cluster-management\n        https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs\n*/\n\n-- These settings improves throughput of the database by reducing locking by better separating readers from writers.\n-- SQL Server 2012 and newer can refer to itself as CURRENT. Older ones need a workaround.\nDECLARE @current NVARCHAR(256);\nDECLARE @snapshotSettings NVARCHAR(612);\n\nSELECT @current = N'[' + (SELECT DB_NAME()) + N']';\nSET @snapshotSettings = N'ALTER DATABASE ' + @current + N' SET READ_COMMITTED_SNAPSHOT ON; ALTER DATABASE ' + @current + N' SET ALLOW_SNAPSHOT_ISOLATION ON;';\n\nEXECUTE sp_executesql @snapshotSettings;\n\n-- This table defines Orleans operational queries. Orleans uses these to manage its operations,\n-- these are the only queries Orleans issues to the database.\n-- These can be redefined (e.g. to provide non-destructive updates) provided the stated interface principles hold.\nIF OBJECT_ID(N'[OrleansQuery]', 'U') IS NULL\nCREATE TABLE OrleansQuery\n(\n\tQueryKey VARCHAR(64) NOT NULL,\n\tQueryText VARCHAR(8000) NOT NULL,\n\n\tCONSTRAINT OrleansQuery_Key PRIMARY KEY(QueryKey)\n);\n"
  },
  {
    "path": "src/AdoNet/Shared/Sqlite-Main.sql",
    "content": "/*\nImplementation notes:\n\n1) The general idea is that data is read and written through Orleans specific queries.\n   Orleans operates on column names and types when reading and on parameter names and types when writing.\n\n2) The implementations *must* preserve input and output names and types. Orleans uses these parameters to reads query results by name and type.\n   Vendor and deployment specific tuning is allowed and contributions are encouraged as long as the interface contract\n   is maintained.\n\n3) The implementation across vendor specific scripts *should* preserve the constraint names. This simplifies troubleshooting\n   by virtue of uniform naming across concrete implementations.\n\n5) ETag for Orleans is an opaque column that represents a unique version. The type of its actual implementation\n   is not important as long as it represents a unique version. In this implementation we use integers for versioning\n\n6) For the sake of being explicit and removing ambiguity, Orleans expects some queries to return either TRUE as >0 value\n\n   or FALSE as =0 value. That is, affected rows or such does not matter. If an error is raised or an exception is thrown\n   the query *must* ensure the entire transaction is rolled back and may either return FALSE or propagate the exception.\n   Orleans handles exception as a failure and will retry.\n\n7) The implementation follows the Extended Orleans membership protocol. For more information, see at:\n        https://learn.microsoft.com/dotnet/orleans/implementation/cluster-management\n        https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs\n*/\n\n-- These settings improves throughput of the database by reducing locking by better separating readers from writers.\n-- SQL Server 2012 and newer can refer to itself as CURRENT. Older ones need a workaround.\nCREATE TABLE OrleansQuery\n(\n    QueryKey  TEXT PRIMARY KEY,\n    QueryText TEXT NOT NULL\n);\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/AdoNetFormatProvider.cs",
    "content": "using System;\nusing System.Globalization;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Formats .NET types appropriately for database consumption in non-parameterized queries.\n    /// </summary>\n    internal class AdoNetFormatProvider: IFormatProvider\n    {\n        private readonly AdoNetFormatter formatter = new AdoNetFormatter();\n\n        /// <summary>\n        /// Returns an instance of the formatter\n        /// </summary>\n        /// <param name=\"formatType\">Requested format type</param>\n        /// <returns></returns>\n        public object GetFormat(Type formatType)\n        {\n            return formatType == typeof(ICustomFormatter) ? formatter : null;\n        }\n\n\n        private class AdoNetFormatter: ICustomFormatter\n        {\n            public string Format(string format, object arg, IFormatProvider formatProvider)\n            {\n                //This null check applies also to Nullable<T> when T does not have value defined.\n                if(arg == null)\n                {\n                    return \"NULL\";\n                }\n\n                if(arg is string)\n                {\n                    return \"N'\" + ((string)arg).Replace(\"'\", \"''\", StringComparison.Ordinal) + \"'\";\n                }\n\n                if(arg is DateTime)\n                {\n                    return \"'\" + ((DateTime)arg).ToString(\"O\") + \"'\";\n                }\n\n                if(arg is DateTimeOffset)\n                {\n                    return \"'\" + ((DateTimeOffset)arg).ToString(\"O\") + \"'\";\n                }\n\n                if(arg is IFormattable)\n                {\n                    return ((IFormattable)arg).ToString(format, CultureInfo.InvariantCulture);\n                }\n\n                return arg.ToString();\n            }\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/AdoNetInvariants.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// A holder for well known, vendor specific connector class invariant names.\n    /// </summary>\n    internal static class AdoNetInvariants\n    {\n        /// <summary>\n        /// A list of the supported invariants.\n        /// </summary>\n        /// <remarks>The invariant names here do not match the namespaces as is often the convention.\n        /// Current exception is MySQL Connector library that uses the same invariant as MySQL compared\n        /// to the official Oracle distribution.</remarks>\n        public static ICollection<string> Invariants { get; } = new Collection<string>(new List<string>(new[]\n        {\n            InvariantNameMySql,\n            InvariantNameOracleDatabase,\n            InvariantNamePostgreSql,\n            InvariantNameSqlLite,\n            InvariantNameSqlServer,\n            InvariantNameMySqlConnector\n        }));\n\n        /// <summary>\n        /// Microsoft SQL Server invariant name string.\n        /// </summary>\n        public const string InvariantNameSqlServer = \"Microsoft.Data.SqlClient\";\n\n        /// <summary>\n        /// Oracle Database server invariant name string.\n        /// </summary>\n        public const string InvariantNameOracleDatabase = \"Oracle.DataAccess.Client\";\n\n        /// <summary>\n        /// SQLite invariant name string.\n        /// </summary>\n        public const string InvariantNameSqlLite = \"System.Data.SQLite\";\n\n        /// <summary>\n        /// MySql invariant name string.\n        /// </summary>\n        public const string InvariantNameMySql = \"MySql.Data.MySqlClient\";\n\n        /// <summary>\n        /// PostgreSQL invariant name string.\n        /// </summary>\n        public const string InvariantNamePostgreSql = \"Npgsql\";\n\n        /// <summary>\n        /// Dotnet core Microsoft SQL Server invariant name string.\n        /// </summary>\n        [Obsolete(\"Use InvariantNameSqlServer instead.\")]\n        public const string InvariantNameSqlServerDotnetCore = InvariantNameSqlServer;\n\n        /// <summary>\n        /// An open source implementation of the MySQL connector library.\n        /// </summary>\n        public const string InvariantNameMySqlConnector = \"MySql.Data.MySqlConnector\";\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/DbConnectionFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Data.Common;\nusing System.Linq;\nusing System.Reflection;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// This class caches the references to all loaded factories\n    internal static class DbConnectionFactory\n    {\n        private static readonly ConcurrentDictionary<string, CachedFactory> factoryCache =\n            new ConcurrentDictionary<string, CachedFactory>();\n\n        private static readonly Dictionary<string, List<Tuple<string, string>>> providerFactoryTypeMap =\n            new Dictionary<string, List<Tuple<string, string>>>\n            {\n                { AdoNetInvariants.InvariantNameSqlServer, new List<Tuple<string, string>>{ new Tuple<string, string>(\"Microsoft.Data.SqlClient\", \"Microsoft.Data.SqlClient.SqlClientFactory\") } },\n                { AdoNetInvariants.InvariantNameMySql, new List<Tuple<string, string>>{ new Tuple<string, string>(\"MySql.Data\", \"MySql.Data.MySqlClient.MySqlClientFactory\") } },\n                { AdoNetInvariants.InvariantNameOracleDatabase, new List<Tuple<string, string>>{ new Tuple<string, string>(\"Oracle.ManagedDataAccess\", \"Oracle.ManagedDataAccess.Client.OracleClientFactory\") } },\n                { AdoNetInvariants.InvariantNamePostgreSql, new List<Tuple<string, string>>{ new Tuple<string, string>(\"Npgsql\", \"Npgsql.NpgsqlFactory\") } },\n                { AdoNetInvariants.InvariantNameSqlLite, new List<Tuple<string, string>>{ new Tuple<string, string>(\"Microsoft.Data.Sqlite\", \"Microsoft.Data.Sqlite.SqliteFactory\") } },\n                { AdoNetInvariants.InvariantNameMySqlConnector, new List<Tuple<string, string>>{ new Tuple<string, string>(\"MySqlConnector\", \"MySqlConnector.MySqlConnectorFactory\") , new Tuple<string, string>(\"MySqlConnector\", \"MySql.Data.MySqlClient.MySqlClientFactory\") } },\n            };\n\n        private static CachedFactory GetFactory(string invariantName)\n        {\n            if (string.IsNullOrWhiteSpace(invariantName))\n            {\n                throw new ArgumentNullException(nameof(invariantName));\n            }\n\n            List<Tuple<string, string>> providerFactoryDefinitions;\n            if (!providerFactoryTypeMap.TryGetValue(invariantName, out providerFactoryDefinitions) || providerFactoryDefinitions.Count == 0)\n                throw new InvalidOperationException($\"Database provider factory with '{invariantName}' invariant name not supported.\");\n\n            List<Exception> exceptions = null;\n            foreach (var providerFactoryDefinition in providerFactoryDefinitions)\n            {\n                Assembly asm = null;\n                try\n                {\n                    var asmName = new AssemblyName(providerFactoryDefinition.Item1);\n                    asm = Assembly.Load(asmName);\n                }\n                catch (Exception exc)\n                {\n                    AddException(new InvalidOperationException($\"Unable to find and/or load a candidate assembly '{providerFactoryDefinition.Item1}' for '{invariantName}' invariant name.\", exc));\n                    continue;\n                }\n\n                if (asm == null)\n                {\n                    AddException(new InvalidOperationException($\"Can't find database provider factory with '{invariantName}' invariant name. Please make sure that your ADO.Net provider package library is deployed with your application.\"));\n                    continue;\n                }\n\n                var providerFactoryType = asm.GetType(providerFactoryDefinition.Item2);\n                if (providerFactoryType == null)\n                {\n                    AddException(new InvalidOperationException($\"Unable to load type '{providerFactoryDefinition.Item2}' for '{invariantName}' invariant name.\"));\n                    continue;\n                }\n\n                var prop = providerFactoryType.GetFields().SingleOrDefault(p => string.Equals(p.Name, \"Instance\", StringComparison.OrdinalIgnoreCase) && p.IsStatic);\n                if (prop == null)\n                {\n                    AddException(new InvalidOperationException($\"Invalid provider type '{providerFactoryDefinition.Item2}' for '{invariantName}' invariant name.\"));\n                    continue;\n                }\n\n                var factory = (DbProviderFactory)prop.GetValue(null);\n                return new CachedFactory(factory, providerFactoryType.Name, \"\", providerFactoryType.AssemblyQualifiedName);\n            }\n\n            throw new AggregateException(exceptions);\n\n            void AddException(Exception ex)\n            {\n                if (exceptions == null)\n                {\n                    exceptions = new List<Exception>();\n                }\n                exceptions.Add(ex);\n            }\n        }\n\n        public static DbConnection CreateConnection(string invariantName, string connectionString)\n        {\n            if (string.IsNullOrWhiteSpace(invariantName))\n            {\n                throw new ArgumentNullException(nameof(invariantName));\n            }\n\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                throw new ArgumentNullException(nameof(connectionString));\n            }\n\n            var factory = factoryCache.GetOrAdd(invariantName, GetFactory).Factory;\n            var connection = factory.CreateConnection();\n\n            if (connection == null)\n            {\n                throw new InvalidOperationException($\"Database provider factory: '{invariantName}' did not return a connection object.\");\n            }\n\n            connection.ConnectionString = connectionString;\n            return connection;\n        }\n\n        private class CachedFactory\n        {\n            public CachedFactory(DbProviderFactory factory, string factoryName, string factoryDescription, string factoryAssemblyQualifiedNameKey)\n            {\n                Factory = factory;\n                FactoryName = factoryName;\n                FactoryDescription = factoryDescription;\n                FactoryAssemblyQualifiedNameKey = factoryAssemblyQualifiedNameKey;\n            }\n\n            /// <summary>\n            /// The factory to provide vendor specific functionality.\n            /// </summary>\n            /// <remarks>For more about <see href=\"http://florianreischl.blogspot.fi/2011/08/adonet-connection-pooling-internals-and.html\">ConnectionPool</see>\n            /// and issues with using this factory. Take these notes into account when considering robustness of Orleans!</remarks>\n            public readonly DbProviderFactory Factory;\n\n            /// <summary>\n            /// The name of the loaded factory, set by a database connector vendor.\n            /// </summary>\n            public readonly string FactoryName;\n\n            /// <summary>\n            /// The description of the loaded factory, set by a database connector vendor.\n            /// </summary>\n            public readonly string FactoryDescription;\n\n            /// <summary>\n            /// The description of the loaded factory, set by a database connector vendor.\n            /// </summary>\n            public readonly string FactoryAssemblyQualifiedNameKey;\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/DbConstantsStore.cs",
    "content": "using System.Collections.Generic;\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    internal static class DbConstantsStore\n    {\n        private static readonly Dictionary<string, DbConstants> invariantNameToConsts =\n            new Dictionary<string, DbConstants>\n            {\n                {\n                    AdoNetInvariants.InvariantNameSqlServer,\n                    new DbConstants(startEscapeIndicator: '[',\n                                    endEscapeIndicator: ']',\n                                    unionAllSelectTemplate: \" UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: false,\n                                    supportsStreamNatively: true,\n                                    supportsCommandCancellation: true,\n                                    commandInterceptor: NoOpCommandInterceptor.Instance)\n                },\n                {AdoNetInvariants.InvariantNameMySql, new DbConstants(\n                                    startEscapeIndicator: '`',\n                                    endEscapeIndicator: '`',\n                                    unionAllSelectTemplate: \" UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: true,\n                                    supportsStreamNatively: false,\n                                    supportsCommandCancellation: false,\n                                    commandInterceptor: NoOpCommandInterceptor.Instance)\n                },\n                {AdoNetInvariants.InvariantNamePostgreSql, new DbConstants(\n                                    startEscapeIndicator: '\"',\n                                    endEscapeIndicator: '\"',\n                                    unionAllSelectTemplate: \" UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: false,\n                                    supportsStreamNatively: true,\n                                    supportsCommandCancellation: true, // See https://dev.mysql.com/doc/connector-net/en/connector-net-ref-mysqlclient-mysqlcommandmembers.html.\n                                    commandInterceptor: NoOpCommandInterceptor.Instance)\n\n                },\n                {AdoNetInvariants.InvariantNameOracleDatabase, new DbConstants(\n                                    startEscapeIndicator: '\\\"',\n                                    endEscapeIndicator: '\\\"',\n                                    unionAllSelectTemplate: \" FROM DUAL UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: true,\n                                    supportsStreamNatively: false,\n                                    supportsCommandCancellation: false, // Is supported but the remarks sound scary: https://docs.oracle.com/cd/E11882_01/win.112/e23174/OracleCommandClass.htm#DAFIEHHG.\n                                    commandInterceptor: OracleCommandInterceptor.Instance)\n\n                },\n                {\n                    AdoNetInvariants.InvariantNameMySqlConnector,\n                    new DbConstants(startEscapeIndicator: '[',\n                                    endEscapeIndicator: ']',\n                                    unionAllSelectTemplate: \" UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: false,\n                                    supportsStreamNatively: true,\n                                    supportsCommandCancellation: true,\n                                    commandInterceptor: NoOpCommandInterceptor.Instance)\n                },\n                {\n                    AdoNetInvariants.InvariantNameSqlLite,\n                    new DbConstants(startEscapeIndicator: '\\\"',\n                                    endEscapeIndicator: '\\\"',\n                                    unionAllSelectTemplate: \" UNION ALL SELECT \",\n                                    isSynchronousAdoNetImplementation: false,\n                                    supportsStreamNatively: false,\n                                    supportsCommandCancellation: true,\n                                    commandInterceptor: NoOpCommandInterceptor.Instance)\n            }\n            };\n\n        public static DbConstants GetDbConstants(string invariantName)\n        {\n            return invariantNameToConsts[invariantName];\n        }\n\n        /// <summary>\n        /// If the underlying storage supports cancellation or not.\n        /// </summary>\n        /// <param name=\"storage\">The storage used.</param>\n        /// <returns><em>TRUE</em> if cancellation is supported. <em>FALSE</em> otherwise.</returns>\n        public static bool SupportsCommandCancellation(this IRelationalStorage storage)\n        {\n            return SupportsCommandCancellation(storage.InvariantName);\n        }\n\n\n        /// <summary>\n        /// If the provider supports cancellation or not.\n        /// </summary>\n        /// <param name=\"adoNetProvider\">The ADO.NET provider invariant string.</param>\n        /// <returns><em>TRUE</em> if cancellation is supported. <em>FALSE</em> otherwise.</returns>\n        public static bool SupportsCommandCancellation(string adoNetProvider)\n        {\n            return GetDbConstants(adoNetProvider).SupportsCommandCancellation;\n        }\n\n\n        /// <summary>\n        /// If the underlying storage supports streaming natively.\n        /// </summary>\n        /// <param name=\"storage\">The storage used.</param>\n        /// <returns><em>TRUE</em> if streaming is supported natively. <em>FALSE</em> otherwise.</returns>\n        public static bool SupportsStreamNatively(this IRelationalStorage storage)\n        {\n            return SupportsStreamNatively(storage.InvariantName);\n        }\n\n\n        /// <summary>\n        /// If the provider supports streaming natively.\n        /// </summary>\n        /// <param name=\"adoNetProvider\">The ADO.NET provider invariant string.</param>\n        /// <returns><em>TRUE</em> if streaming is supported natively. <em>FALSE</em> otherwise.</returns>\n        public static bool SupportsStreamNatively(string adoNetProvider)\n        {\n            return GetDbConstants(adoNetProvider).SupportsStreamNatively;\n        }\n\n\n        /// <summary>\n        /// If the underlying ADO.NET implementation is known to be synchronous.\n        /// </summary>\n        /// <param name=\"storage\">The storage used.</param>\n        /// <returns></returns>\n        public static bool IsSynchronousAdoNetImplementation(this IRelationalStorage storage)\n        {\n            //Currently the assumption is all but MySQL are asynchronous.\n            return IsSynchronousAdoNetImplementation(storage.InvariantName);\n        }\n\n\n        /// <summary>\n        /// If the provider supports cancellation or not.\n        /// </summary>\n        /// <param name=\"adoNetProvider\">The ADO.NET provider invariant string.</param>\n        /// <returns></returns>\n        public static bool IsSynchronousAdoNetImplementation(string adoNetProvider)\n        {\n            return GetDbConstants(adoNetProvider).IsSynchronousAdoNetImplementation;\n        }\n\n        public static ICommandInterceptor GetDatabaseCommandInterceptor(string invariantName)\n        {\n            return GetDbConstants(invariantName).DatabaseCommandInterceptor;\n        }\n    }\n\n    internal class DbConstants\n    {\n        /// <summary>\n        /// A query template for union all select\n        /// </summary>\n        public readonly string UnionAllSelectTemplate;\n\n        /// <summary>\n        /// Indicates whether the ADO.net provider does only support synchronous operations.\n        /// </summary>\n        public readonly bool IsSynchronousAdoNetImplementation;\n\n        /// <summary>\n        /// Indicates whether the ADO.net provider does streaming operations natively.\n        /// </summary>\n        public readonly bool SupportsStreamNatively;\n\n        /// <summary>\n        /// Indicates whether the ADO.net provider supports cancellation of commands.\n        /// </summary>\n        public readonly bool SupportsCommandCancellation;\n\n        /// <summary>\n        /// The character that indicates a start escape key for columns and tables that are reserved words.\n        /// </summary>\n        public readonly char StartEscapeIndicator;\n\n        /// <summary>\n        /// The character that indicates an end escape key for columns and tables that are reserved words.\n        /// </summary>\n        public readonly char EndEscapeIndicator;\n\n        public readonly ICommandInterceptor DatabaseCommandInterceptor;\n\n\n        public DbConstants(char startEscapeIndicator, char endEscapeIndicator, string unionAllSelectTemplate,\n                           bool isSynchronousAdoNetImplementation, bool supportsStreamNatively, bool supportsCommandCancellation, ICommandInterceptor commandInterceptor)\n        {\n            StartEscapeIndicator = startEscapeIndicator;\n            EndEscapeIndicator = endEscapeIndicator;\n            UnionAllSelectTemplate = unionAllSelectTemplate;\n            IsSynchronousAdoNetImplementation = isSynchronousAdoNetImplementation;\n            SupportsStreamNatively = supportsStreamNatively;\n            SupportsCommandCancellation = supportsCommandCancellation;\n            DatabaseCommandInterceptor = commandInterceptor;\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/DbExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Data;\nusing System.Data.Common;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Contains some convenience methods to use in conjunction with <see cref=\"IRelationalStorage\">IRelationalStorage</see> and <see cref=\"RelationalStorage\">GenericRelationalStorage</see>.\n    /// </summary>\n    internal static class DbExtensions\n    {\n        /// <summary>\n        /// An explicit map of type CLR viz database type conversions.\n        /// </summary>\n        private static readonly ReadOnlyDictionary<Type, DbType> typeMap = new ReadOnlyDictionary<Type, DbType>(new Dictionary<Type, DbType>\n        {\n            { typeof(object),   DbType.Object },\n            { typeof(int),      DbType.Int32 },\n            { typeof(int?),     DbType.Int32 },\n            { typeof(uint),     DbType.UInt32 },\n            { typeof(uint?),    DbType.UInt32 },\n            { typeof(long),     DbType.Int64 },\n            { typeof(long?),    DbType.Int64 },\n            { typeof(ulong),    DbType.UInt64 },\n            { typeof(ulong?),   DbType.UInt64 },\n            { typeof(float),    DbType.Single },\n            { typeof(float?),   DbType.Single },\n            { typeof(double),   DbType.Double },\n            { typeof(double?),  DbType.Double },\n            { typeof(decimal),  DbType.Decimal },\n            { typeof(decimal?), DbType.Decimal },\n            { typeof(short),    DbType.Int16 },\n            { typeof(short?),   DbType.Int16 },\n            { typeof(ushort),   DbType.UInt16 },\n            { typeof(ushort?),  DbType.UInt16 },\n            { typeof(byte),     DbType.Byte },\n            { typeof(byte?),    DbType.Byte },\n            { typeof(sbyte),    DbType.SByte },\n            { typeof(sbyte?),   DbType.SByte },\n            { typeof(bool),     DbType.Boolean },\n            { typeof(bool?),    DbType.Boolean },\n            { typeof(string),   DbType.String },\n            { typeof(char),     DbType.StringFixedLength },\n            { typeof(char?),    DbType.StringFixedLength },\n            { typeof(Guid),     DbType.Guid },\n            { typeof(Guid?),    DbType.Guid },\n            //Using DateTime for cross DB compatibility. The underlying DB table column type can be DateTime or DateTime2\n            { typeof(DateTime),     DbType.DateTime },\n            { typeof(DateTime?),    DbType.DateTime },\n            { typeof(TimeSpan),     DbType.Time },\n            { typeof(byte[]),       DbType.Binary },\n            { typeof(TimeSpan?),        DbType.Time },\n            { typeof(DateTimeOffset),   DbType.DateTimeOffset },\n            { typeof(DateTimeOffset?),  DbType.DateTimeOffset },\n        });\n\n        /// <summary>\n        /// Creates a new SQL parameter using the given arguments.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the parameter.</typeparam>\n        /// <param name=\"command\">The command to use to create the parameter.</param>\n        /// <param name=\"direction\">The direction of the parameter.</param>\n        /// <param name=\"parameterName\">The name of the parameter.</param>\n        /// <param name=\"value\">The value of the parameter.</param>\n        /// <param name=\"size\">The size of the parameter value.</param>\n        /// <param name=\"dbType\">the <see cref=\"DbType\"/> of the parameter.</param>\n        /// <returns>A parameter created using the given arguments.</returns>\n        public static IDbDataParameter CreateParameter<T>(this IDbCommand command, ParameterDirection direction, string parameterName, T value, int? size = null, DbType? dbType = null)\n        {\n            //There should be no boxing for value types. See at:\n            //http://stackoverflow.com/questions/8823239/comparing-a-generic-against-null-that-could-be-a-value-or-reference-type\n            var parameter = command.CreateParameter();\n            parameter.ParameterName = parameterName;\n            parameter.Value = (object)value ?? DBNull.Value;\n            parameter.DbType = dbType ?? typeMap[typeof(T)];\n            parameter.Direction = direction;\n            if (size != null) { parameter.Size = size.Value; }\n\n            return parameter;\n        }\n\n        /// <summary>\n        /// Creates and adds a new SQL parameter to the command.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the parameter.</typeparam>\n        /// <param name=\"command\">The command to use to create the parameter.</param>\n        /// <param name=\"parameterName\">The name of the parameter.</param>\n        /// <param name=\"value\">The value of the parameter.</param>\n        /// <param name=\"direction\">The direction of the parameter.</param>\n        /// <param name=\"size\">The size of the parameter value.</param>\n        /// <param name=\"dbType\">the <see cref=\"DbType\"/> of the parameter.</param>\n        public static void AddParameter<T>(this IDbCommand command, string parameterName, T value, ParameterDirection direction = ParameterDirection.Input, int? size = null, DbType? dbType = null)\n        {\n            command.Parameters.Add(command.CreateParameter(direction, parameterName, value, size));\n        }\n\n        /// <summary>\n        /// Returns a value if it is not <see cref=\"System.DBNull\"/>, <em>default(TValue)</em> otherwise.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of the value to request.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field to retrieve.</param>\n        /// <param name=\"default\">The default value if value in position is <see cref=\"System.DBNull\"/>.</param>\n        /// <returns>Either the given value or the default for the requested type.</returns>\n        /// <remarks>This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>\n        public static TValue GetValueOrDefault<TValue>(this IDataRecord record, string fieldName, TValue @default = default)\n        {\n\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return record.IsDBNull(ordinal) ? @default : (TValue)record.GetValue(ordinal);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n        /// <summary>\n        /// Returns a value if it is not <see cref=\"System.DBNull\"/>, <em>default</em>  otherwise.\n        /// </summary>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field to retrieve.</param>\n        /// <param name=\"default\">The default value if value in position is <see cref=\"System.DBNull\"/>.</param>\n        /// <returns>Either the given value or the default for <see cref=\"System.DateTime\"/>?.</returns>\n        /// <exception cref=\"DataException\"/>\n        /// <remarks>An explicit function like this is needed in cases where to connector infers a type that is undesirable.\n        /// An example here is Npgsql.NodaTime, which makes Npgsql return Noda type and consequently Orleans is not able to\n        /// use it since it expects .NET <see cref=\"System.DateTime\"/>. This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>\n        public static DateTime? GetDateTimeValueOrDefault(this IDataRecord record, string fieldName, DateTime? @default = default)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return record.IsDBNull(ordinal) ? @default : DateTime.SpecifyKind(record.GetDateTime(ordinal), DateTimeKind.Utc);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n        /// <summary>\n        /// Returns a value if it is not <see cref=\"System.DBNull\"/>, <em>default(TValue)</em> otherwise.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of the value to request.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field to retrieve.</param>\n        /// <param name=\"default\">The default value if value in position is <see cref=\"System.DBNull\"/>.</param>\n        /// <returns>Either the given value or the default for the requested type.</returns>\n        /// <exception cref=\"DataException\"/>\n        /// <remarks>This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>\n        public static async Task<TValue> GetValueOrDefaultAsync<TValue>(this DbDataReader record, string fieldName, TValue @default = default)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return (await record.IsDBNullAsync(ordinal).ConfigureAwait(false))\n                    ? @default\n                    : (await record.GetFieldValueAsync<TValue>(ordinal).ConfigureAwait(false));\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n\n        /// <summary>\n        /// Returns a value if it is not <see cref=\"System.DBNull\"/>, <em>default(TValue)</em> otherwise.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of the value to request.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"ordinal\">The ordinal of the fieldname.</param>\n        /// <param name=\"default\">The default value if value in position is <see cref=\"System.DBNull\"/>.</param>\n        /// <returns>Either the given value or the default for the requested type.</returns>\n        /// <exception cref=\"IndexOutOfRangeException\"/>                \n        public static TValue GetValueOrDefault<TValue>(this IDataRecord record, int ordinal, TValue @default = default)\n        {\n            return record.IsDBNull(ordinal) ? @default : (TValue)record.GetValue(ordinal);\n        }\n\n\n        /// <summary>\n        /// Returns a value if it is not <see cref=\"System.DBNull\"/>, <em>default(TValue)</em> otherwise.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of the value to request.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"ordinal\">The ordinal of the fieldname.</param>\n        /// <param name=\"default\">The default value if value in position is <see cref=\"System.DBNull\"/>.</param>\n        /// <returns>Either the given value or the default for the requested type.</returns>\n        /// <exception cref=\"IndexOutOfRangeException\"/>                \n        public static async Task<TValue> GetValueOrDefaultAsync<TValue>(this DbDataReader record, int ordinal, TValue @default = default)\n        {\n\n            return (await record.IsDBNullAsync(ordinal).ConfigureAwait(false)) ? @default : (await record.GetFieldValueAsync<TValue>(ordinal).ConfigureAwait(false));\n        }\n\n\n        /// <summary>\n        /// Returns a value with the given <see paramref=\"fieldName\"/>.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of value to retrieve.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <returns>Value in the given field indicated by <see paramref=\"fieldName\"/>.</returns>\n        /// <exception cref=\"DataException\"/>\n        /// <remarks>This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>        \n        public static TValue GetValue<TValue>(this IDataRecord record, string fieldName)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return (TValue)record.GetValue(ordinal);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n        /// <summary>\n        /// Returns a <see cref=\"System.DateTime\"/> value with the given <see paramref=\"fieldName\"/>.\n        /// </summary>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <returns>DateTime Value in the given field.</returns>\n        /// <exception cref=\"DataException\"/>\n        /// <remarks>An explicit function like this is needed in cases where to connector infers a type that is undesirable.\n        /// An example here is Npgsql.NodaTime, which makes Npgsql return Noda type and consequently Orleans is not able to\n        /// use it since it expects .NET <see cref=\"System.DateTime\"/>. This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>\n        public static DateTime GetDateTimeValue(this IDataRecord record, string fieldName)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return DateTime.SpecifyKind(record.GetDateTime(ordinal), DateTimeKind.Utc);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n        /// <summary>\n        /// Returns a value with the given <see paramref=\"fieldName\"/> as int.\n        /// </summary>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <exception cref=\"DataException\"/>\n        /// <returns>Integer value in the given field indicated by <see paramref=\"fieldName\"/>.</returns>\n        public static int GetInt32(this IDataRecord record, string fieldName)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return record.GetInt32(ordinal);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n        /// <summary>\n        /// Returns a value with the given <see paramref=\"fieldName\"/> as long.\n        /// </summary>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <exception cref=\"DataException\"/>\n        /// <returns>Integer value in the given field indicated by <see paramref=\"fieldName\"/>.</returns>\n        public static long GetInt64(this IDataRecord record, string fieldName)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                // Original casting when old schema is used.  Here to maintain backwards compatibility\n                return record.GetFieldType(ordinal) == typeof(int) ? record.GetInt32(ordinal) : record.GetInt64(ordinal);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n        /// <summary>\n        /// Returns a value with the given <see paramref=\"fieldName\"/> as nullable int.\n        /// </summary>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <exception cref=\"DataException\"/>\n        /// <returns>Nullable int value in the given field indicated by <see paramref=\"fieldName\"/>.</returns>\n        public static int? GetNullableInt32(this IDataRecord record, string fieldName)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                var value = record.GetValue(ordinal);\n                if (value == DBNull.Value)\n                    return null;\n\n                return Convert.ToInt32(value);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n        /// <summary>\n        /// Returns a value with the given <see paramref=\"fieldName\"/>.\n        /// </summary>\n        /// <typeparam name=\"TValue\">The type of value to retrieve.</typeparam>\n        /// <param name=\"record\">The record from which to retrieve the value.</param>\n        /// <param name=\"fieldName\">The name of the field.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Value in the given field indicated by <see paramref=\"fieldName\"/>.</returns>\n        /// <exception cref=\"DataException\"/>\n        /// <remarks>This function throws if the given <see paramref=\"fieldName\"/> does not exist.</remarks>        \n        public static async Task<TValue> GetValueAsync<TValue>(this DbDataReader record, string fieldName, CancellationToken cancellationToken = default)\n        {\n            try\n            {\n                var ordinal = record.GetOrdinal(fieldName);\n                return await record.GetFieldValueAsync<TValue>(ordinal, cancellationToken).ConfigureAwait(false);\n            }\n            catch (IndexOutOfRangeException e)\n            {\n                throw new DataException($\"Field '{fieldName}' not found in data record.\", e);\n            }\n        }\n\n\n\n        /// <summary>\n        /// Adds given parameters to a command using reflection.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the parameters.</typeparam>\n        /// <param name=\"command\">The command.</param>\n        /// <param name=\"parameters\">The parameters.</param>\n        /// <param name=\"nameMap\">Maps a given property name to another one defined in the map.</param>\n        /// <remarks>Does not support collection parameters currently. Does not cache reflection results.</remarks>\n        public static void ReflectionParameterProvider<T>(this IDbCommand command, T parameters, IReadOnlyDictionary<string, string> nameMap = null)\n        {\n            if (!EqualityComparer<T>.Default.Equals(parameters, default))\n            {\n                var properties = parameters.GetType().GetProperties();\n                for (int i = 0; i < properties.Length; ++i)\n                {\n                    var property = properties[i];\n                    var value = property.GetValue(parameters, null);\n                    var parameter = command.CreateParameter();\n                    parameter.Value = value ?? DBNull.Value;\n                    parameter.Direction = ParameterDirection.Input;\n                    parameter.ParameterName = nameMap != null && nameMap.ContainsKey(properties[i].Name) ? nameMap[property.Name] : properties[i].Name;\n                    parameter.DbType = typeMap[property.PropertyType];\n\n                    command.Parameters.Add(parameter);\n                }\n            }\n        }\n\n\n        /// <summary>\n        /// Creates object of the given type from the results of a query.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type to construct.</typeparam>\n        /// <param name=\"record\">The record from which to read the results.</param>\n        /// <returns>And object of type <see typeparam=\"TResult\"/>.</returns>\n        /// <remarks>Does not support <see typeparam=\"TResult\"/> of type <em>dynamic</em>.</remarks>\n        public static TResult ReflectionSelector<TResult>(this IDataRecord record)\n        {\n            //This is done like this in order to box value types.\n            //Otherwise property.SetValue() would have a copy of the struct, which would\n            //get garbage collected. Consequently the original struct value would not be set.            \n            object obj = Activator.CreateInstance<TResult>();\n            var properties = obj.GetType().GetProperties();\n            for (int i = 0; i < properties.Length; ++i)\n            {\n                var rp = record[properties[i].Name];\n                if (!Equals(rp, DBNull.Value))\n                {\n                    properties[i].SetValue(obj, rp, null);\n                }\n            }\n\n            return (TResult)obj;\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/DbStoredQueries.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing Orleans.Runtime;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif ORLEANS_REMINDERS_PROVIDER\nusing Orleans.Reminders.AdoNet.Converters;\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// This class implements the expected contract between Orleans and the underlying relational storage.\n    /// It makes sure all the stored queries are present and \n    /// </summary>\n    internal class DbStoredQueries\n    {\n        private readonly Dictionary<string, string> queries;\n\n        internal DbStoredQueries(Dictionary<string, string> queries)\n        {\n            var fields = typeof(DbStoredQueries).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)\n                .Select(p => p.Name);\n            var missingQueryKeys = fields.Except(queries.Keys).ToArray();\n            if (missingQueryKeys.Length > 0)\n            {\n                throw new ArgumentException(\n                    $\"Not all required queries found. Missing are: {string.Join(\",\", missingQueryKeys)}\");\n            }\n            this.queries = queries;\n        }\n\n        /// <summary>\n        /// The query that's used to get all the stored queries.\n        /// this will probably be the same for all relational dbs.\n        /// </summary>\n        internal const string GetQueriesKey = \"SELECT QueryKey, QueryText FROM OrleansQuery\";\n\n#if CLUSTERING_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// A query template to retrieve gateway URIs.\n        /// </summary>        \n        internal string GatewaysQueryKey => queries[nameof(GatewaysQueryKey)];\n\n        /// <summary>\n        /// A query template to retrieve a single row of membership data.\n        /// </summary>        \n        internal string MembershipReadRowKey => queries[nameof(MembershipReadRowKey)];\n\n        /// <summary>\n        /// A query template to retrieve all membership data.\n        /// </summary>        \n        internal string MembershipReadAllKey => queries[nameof(MembershipReadAllKey)];\n\n        /// <summary>\n        /// A query template to insert a membership version row.\n        /// </summary>\n        internal string InsertMembershipVersionKey => queries[nameof(InsertMembershipVersionKey)];\n\n        /// <summary>\n        /// A query template to update \"I Am Alive Time\".\n        /// </summary>\n        internal string UpdateIAmAlivetimeKey => queries[nameof(UpdateIAmAlivetimeKey)];\n\n        /// <summary>\n        /// A query template to insert a membership row.\n        /// </summary>\n        internal string InsertMembershipKey => queries[nameof(InsertMembershipKey)];\n\n        /// <summary>\n        /// A query template to update a membership row.\n        /// </summary>\n        internal string UpdateMembershipKey => queries[nameof(UpdateMembershipKey)];\n\n        /// <summary>\n        /// A query template to delete membership entries.\n        /// </summary>\n        internal string DeleteMembershipTableEntriesKey => queries[nameof(DeleteMembershipTableEntriesKey)];\n\n        /// <summary>\n        /// A query template to cleanup defunct silo entries.\n        /// </summary>\n        internal string CleanupDefunctSiloEntriesKey => queries[nameof(CleanupDefunctSiloEntriesKey)];\n\n#endif\n\n#if REMINDERS_ADONET || TESTER_SQLUTILS || ORLEANS_REMINDERS_PROVIDER\n\n        /// <summary>\n        /// A query template to read reminder entries.\n        /// </summary>\n        internal string ReadReminderRowsKey => queries[nameof(ReadReminderRowsKey)];\n\n        /// <summary>\n        /// A query template to read reminder entries with ranges.\n        /// </summary>\n        internal string ReadRangeRows1Key => queries[nameof(ReadRangeRows1Key)];\n\n        /// <summary>\n        /// A query template to read reminder entries with ranges.\n        /// </summary>\n        internal string ReadRangeRows2Key => queries[nameof(ReadRangeRows2Key)];\n\n        /// <summary>\n        /// A query template to read a reminder entry with ranges.\n        /// </summary>\n        internal string ReadReminderRowKey => queries[nameof(ReadReminderRowKey)];\n\n        /// <summary>\n        /// A query template to upsert a reminder row.\n        /// </summary>\n        internal string UpsertReminderRowKey => queries[nameof(UpsertReminderRowKey)];\n\n        /// <summary>\n        /// A query template to delete a reminder row.\n        /// </summary>\n        internal string DeleteReminderRowKey => queries[nameof(DeleteReminderRowKey)];\n\n        /// <summary>\n        /// A query template to delete all reminder rows.\n        /// </summary>\n        internal string DeleteReminderRowsKey => queries[nameof(DeleteReminderRowsKey)];\n\n#endif\n\n#if STREAMING_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// A query template to enqueue a message into the stream table.\n        /// </summary>\n        internal string QueueStreamMessageKey => queries[nameof(QueueStreamMessageKey)];\n\n        /// <summary>\n        /// A query template to dequeue messages from the stream table.\n        /// </summary>\n        internal string GetStreamMessagesKey => queries[nameof(GetStreamMessagesKey)];\n\n        /// <summary>\n        /// A query template to confirm message delivery from the stream table.\n        /// </summary>\n        internal string ConfirmStreamMessagesKey => queries[nameof(ConfirmStreamMessagesKey)];\n\n        /// <summary>\n        /// A query template to evict a single message (by moving it to dead letters).\n        /// </summary>\n        internal string FailStreamMessageKey => queries[nameof(FailStreamMessageKey)];\n\n        /// <summary>\n        /// A query template to batch evict messages (by moving them to dead letters).\n        /// </summary>\n        internal string EvictStreamMessagesKey => queries[nameof(EvictStreamMessagesKey)];\n\n        /// <summary>\n        /// A query template to evict expired dead letters (by deleting them).\n        /// </summary>\n        internal string EvictStreamDeadLettersKey => queries[nameof(EvictStreamDeadLettersKey)];\n\n#endif\n\n#if GRAINDIRECTORY_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// A query template to register a grain activation.\n        /// </summary>\n        internal string RegisterGrainActivationKey => queries[nameof(RegisterGrainActivationKey)];\n\n        /// <summary>\n        /// A query template to unregister a grain activation.\n        /// </summary>\n        internal string UnregisterGrainActivationKey => queries[nameof(UnregisterGrainActivationKey)];\n\n        /// <summary>\n        /// A query template to lookup a grain activation.\n        /// </summary>\n        internal string LookupGrainActivationKey => queries[nameof(LookupGrainActivationKey)];\n\n        /// <summary>\n        /// A query template to unregister all grain activations for a set of silos.\n        /// </summary>\n        internal string UnregisterGrainActivationsKey => queries[nameof(UnregisterGrainActivationsKey)];\n\n#endif\n\n        internal static class Converters\n        {\n            internal static KeyValuePair<string, string> GetQueryKeyAndValue(IDataRecord record)\n            {\n                return new KeyValuePair<string, string>(record.GetValue<string>(\"QueryKey\"),\n                    record.GetValue<string>(\"QueryText\"));\n            }\n\n\n            internal static Tuple<MembershipEntry, int> GetMembershipEntry(IDataRecord record)\n            {\n                //TODO: This is a bit of hack way to check in the current version if there's membership data or not, but if there's a start time, there's member.            \n                DateTime? startTime = record.GetDateTimeValueOrDefault(nameof(Columns.StartTime));\n                MembershipEntry entry = null;\n                if (startTime.HasValue)\n                {\n                    entry = new MembershipEntry\n                    {\n                        SiloAddress = GetSiloAddress(record, nameof(Columns.Port)),\n                        SiloName = TryGetSiloName(record),\n                        HostName = record.GetValue<string>(nameof(Columns.HostName)),\n                        Status = (SiloStatus)Enum.Parse(typeof(SiloStatus), record.GetInt32(nameof(Columns.Status)).ToString()),\n                        ProxyPort = record.GetInt32(nameof(Columns.ProxyPort)),\n                        StartTime = startTime.Value,\n                        IAmAliveTime = record.GetDateTimeValue(nameof(Columns.IAmAliveTime))\n                    };\n\n                    string suspectingSilos = record.GetValueOrDefault<string>(nameof(Columns.SuspectTimes));\n                    if (!string.IsNullOrWhiteSpace(suspectingSilos))\n                    {\n                        entry.SuspectTimes = new List<Tuple<SiloAddress, DateTime>>();\n                        entry.SuspectTimes.AddRange(suspectingSilos.Split('|').Select(s =>\n                        {\n                            var split = s.Split(',');\n                            return new Tuple<SiloAddress, DateTime>(SiloAddress.FromParsableString(split[0]),\n                                LogFormatter.ParseDate(split[1]));\n                        }));\n                    }\n                }\n\n                return Tuple.Create(entry, GetVersion(record));\n            }\n\n            /// <summary>\n            /// This method is for compatibility with membership tables that\n            /// do not contain a SiloName field\n            /// </summary>\n            private static string TryGetSiloName(IDataRecord record)\n            {\n                int pos;\n                try\n                {\n                    pos = record.GetOrdinal(nameof(Columns.SiloName));\n                }\n                catch (IndexOutOfRangeException)\n                {\n                    return null;\n                }\n\n                return (string)record.GetValue(pos);\n\n            }\n\n            internal static int GetVersion(IDataRecord record)\n            {\n                return Convert.ToInt32(record.GetValue<object>(nameof(Version)));\n            }\n\n            internal static Uri GetGatewayUri(IDataRecord record)\n            {\n                return GetSiloAddress(record, nameof(Columns.ProxyPort)).ToGatewayUri();\n            }\n\n            private static SiloAddress GetSiloAddress(IDataRecord record, string portName)\n            {\n                //Use the GetInt32 method instead of the generic GetValue<TValue> version to retrieve the value from the data record\n                //GetValue<int> causes an InvalidCastException with orcale data provider. See https://github.com/dotnet/orleans/issues/3561\n                int port = record.GetInt32(portName);\n                int generation = record.GetInt32(nameof(Columns.Generation));\n                string address = record.GetValue<string>(nameof(Columns.Address));\n                var siloAddress = SiloAddress.New(IPAddress.Parse(address), port, generation);\n                return siloAddress;\n            }\n\n            internal static bool GetSingleBooleanValue(IDataRecord record)\n            {\n                if (record.FieldCount != 1) throw new InvalidOperationException(\"Expected a single column\");\n                return Convert.ToBoolean(record.GetValue(0));\n            }\n        }\n\n        internal class Columns\n        {\n            private readonly IDbCommand command;\n\n            internal Columns(IDbCommand cmd)\n            {\n                command = cmd;\n\n            }\n\n            private void Add<T>(string paramName, T paramValue, DbType? dbType = null)\n            {\n                command.AddParameter(paramName, paramValue, dbType: dbType);\n            }\n\n            private void AddAddress(string name, IPAddress address)\n            {\n                Add(name, address.ToString(), dbType: DbType.AnsiString);\n            }\n\n            private void AddGrainHash(string name, uint grainHash)\n            {\n                Add(name, (int)grainHash);\n            }\n\n            internal string ClientId\n            {\n                set { Add(nameof(ClientId), value); }\n            }\n\n            internal int GatewayPort\n            {\n                set { Add(nameof(GatewayPort), value); }\n            }\n\n            internal IPAddress GatewayAddress\n            {\n                set { AddAddress(nameof(GatewayAddress), value); }\n            }\n\n            internal string SiloId\n            {\n                set { Add(nameof(SiloId), value); }\n            }\n\n            internal string Id\n            {\n                set { Add(nameof(Id), value); }\n            }\n\n            internal string Name\n            {\n                set { Add(nameof(Name), value); }\n            }\n\n            internal const string IsValueDelta = nameof(IsValueDelta);\n            internal const string StatValue = nameof(StatValue);\n            internal const string Statistic = nameof(Statistic);\n\n            internal SiloAddress SiloAddress\n            {\n                set\n                {\n                    Address = value.Endpoint.Address;\n                    Port = value.Endpoint.Port;\n                    Generation = value.Generation;\n                }\n            }\n\n            /// <summary>\n            /// Workaround for SiloAddress in the Grain Directory clashing with the existing property.\n            /// </summary>\n            internal string SiloAddressAsString\n            {\n                set => Add(\"SiloAddress\", value);\n            }\n\n            internal string SiloAddresses\n            {\n                set => Add(nameof(SiloAddresses), value);\n            }\n\n            internal int Generation\n            {\n                set { Add(nameof(Generation), value); }\n            }\n\n            internal int Port\n            {\n                set { Add(nameof(Port), value); }\n            }\n\n            internal uint BeginHash\n            {\n                set { AddGrainHash(nameof(BeginHash), value); }\n            }\n\n            internal uint EndHash\n            {\n                set { AddGrainHash(nameof(EndHash), value); }\n            }\n\n            internal uint GrainHash\n            {\n                set { AddGrainHash(nameof(GrainHash), value); }\n            }\n\n            internal DateTime StartTime\n            {\n                set { Add(nameof(StartTime), value); }\n            }\n\n            internal IPAddress Address\n            {\n                set { AddAddress(nameof(Address), value); }\n            }\n\n            internal string ServiceId\n            {\n                set { Add(nameof(ServiceId), value); }\n            }\n\n            internal string ClusterId\n            {\n                set { Add(nameof(ClusterId), value); }\n            }\n\n            internal string DeploymentId\n            {\n                set { Add(nameof(DeploymentId), value); }\n            }\n\n            internal string SiloName\n            {\n                set { Add(nameof(SiloName), value); }\n            }\n\n            internal string HostName\n            {\n                set { Add(nameof(HostName), value); }\n            }\n\n            internal string Version\n            {\n                set { Add(nameof(Version), int.Parse(value)); }\n            }\n\n            internal DateTime IAmAliveTime\n            {\n                set { Add(nameof(IAmAliveTime), value); }\n            }\n\n            internal string GrainId\n            {\n                set { Add(nameof(GrainId), value, dbType: DbType.AnsiString); }\n            }\n\n            internal int GrainIdHash\n            {\n                set => Add(nameof(GrainIdHash), value);\n            }\n\n            internal string ReminderName\n            {\n                set { Add(nameof(ReminderName), value); }\n            }\n\n            internal TimeSpan Period\n            {\n                set\n                {\n                    if (value.TotalMilliseconds <= int.MaxValue)\n                    {\n                        // Original casting when old schema is used.  Here to maintain backwards compatibility\n                        Add(nameof(Period), (int)value.TotalMilliseconds);\n                    }\n                    else\n                    {\n                        Add(nameof(Period), (long)value.TotalMilliseconds);\n                    }\n                }\n            }\n\n            internal SiloStatus Status\n            {\n                set { Add(nameof(Status), (int)value); }\n            }\n\n            internal int ProxyPort\n            {\n                set { Add(nameof(ProxyPort), value); }\n            }\n\n            internal List<Tuple<SiloAddress, DateTime>> SuspectTimes\n            {\n                set\n                {\n                    Add(nameof(SuspectTimes), value == null\n                        ? null\n                        : string.Join(\"|\", value.Select(\n                            s => $\"{s.Item1.ToParsableString()},{LogFormatter.PrintDate(s.Item2)}\")));\n                }\n            }\n\n            internal string QueueId\n            {\n                set => Add(nameof(QueueId), value);\n            }\n\n            internal long MessageId\n            {\n                set => Add(nameof(MessageId), value);\n            }\n\n            internal byte[] Payload\n            {\n                set => Add(nameof(Payload), value);\n            }\n\n            internal int ExpiryTimeout\n            {\n                set => Add(nameof(ExpiryTimeout), value);\n            }\n\n            internal int MaxCount\n            {\n                set => Add(nameof(MaxCount), value);\n            }\n\n            internal int MaxAttempts\n            {\n                set => Add(nameof(MaxAttempts), value);\n            }\n\n            internal int RemovalTimeout\n            {\n                set => Add(nameof(RemovalTimeout), value);\n            }\n\n            internal int VisibilityTimeout\n            {\n                set => Add(nameof(VisibilityTimeout), value);\n            }\n\n            internal int EvictionInterval\n            {\n                set => Add(nameof(EvictionInterval), value);\n            }\n\n            internal int EvictionBatchSize\n            {\n                set => Add(nameof(EvictionBatchSize), value);\n            }\n\n            internal string EventIds\n            {\n                set => Add(nameof(EventIds), value);\n            }\n\n            internal string ProviderId\n            {\n                set => Add(nameof(ProviderId), value);\n            }\n\n            internal string Items\n            {\n                set => Add(nameof(Items), value);\n            }\n\n            internal string ActivationId\n            {\n                set => Add(nameof(ActivationId), value);\n            }\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/ICommandInterceptor.cs",
    "content": "using System.Data;\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    internal interface ICommandInterceptor\n    {\n        void Intercept(IDbCommand command);\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/IRelationalStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// A common interface for all relational databases.\n    /// </summary>\n#if TESTER_SQLUTILS\n    public interface IRelationalStorage\n#else\n    internal interface IRelationalStorage\n#endif\n    {\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>SELECT</em> statement.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type.</typeparam>\n        /// <param name=\"query\">The query to execute.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. The parameters must be in the same order with same names as defined in the query.</param>\n        /// <param name=\"selector\">This function transforms the raw <see cref=\"IDataRecord\"/> results to type <see paramref=\"TResult\"/> the <see cref=\"int\"/> parameter being the resultset number.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>A list of objects as a result of the <see paramref=\"query\"/>.</returns>\n        /// <example>This sample shows how to make a hand-tuned database call.\n        /// <code>\n        /// //This struct holds the return value in this example.\n        /// public struct Information\n        /// {\n        ///     public string TABLE_CATALOG { get; set; }\n        ///     public string TABLE_NAME { get; set; }\n        /// }\n        ///\n        /// //Here are defined two queries. There can be more than two queries, in which case\n        /// //the result sets are differentiated by a count parameter. Here the queries are\n        /// //SELECT clauses, but they can be whatever, even mixed ones.\n        /// IEnumerable&lt;Information&gt; ret =\n        ///     await storage.ReadAsync&lt;Information&gt;(\"SELECT * FROM INFORMATION_SCHEMA.TABLES; SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tp1\", command =>\n        /// {\n        ///     //Parameters are added and created like this.\n        ///     //They are database vendor agnostic.\n        ///     var tp1 = command.CreateParameter();\n        ///     tp1.ParameterName = \"tp1\";\n        ///     tp1.Value = \"some test value\";\n        ///     tp1.DbType = DbType.String;\n        ///     tp1.Direction = ParameterDirection.Input;\n        ///     command.Parameters.Add(tp1);\n        ///\n        ///     //The selector is used to select the results within the result set. In this case there are two homogenous\n        ///     //result sets, so there is actually no need to check which result set the selector holds and it could\n        ///     //marked with by convention by underscore (_).\n        /// }, (selector, resultSetCount) =>\n        ///    {\n        ///        //This function is called once for each row returned, so the final result will be an\n        ///        //IEnumerable&lt;Information&gt;.\n        ///        return new Information\n        ///        {\n        ///            TABLE_CATALOG = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_CATALOG\"),\n        ///            TABLE_NAME = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_NAME\")\n        ///        }\n        ///}).ConfigureAwait(continueOnCapturedContext: false);\n        /// </code>\n        /// </example>\n        Task<IEnumerable<TResult>> ReadAsync<TResult>(string query, Action<IDbCommand> parameterProvider, Func<IDataRecord, int, CancellationToken, Task<TResult>> selector, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.\n        /// </summary>\n        /// <param name=\"query\">The query to execute.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Affected rows count.</returns>\n        /// <example>This sample shows how to make a hand-tuned database call.\n        /// <code>\n        /// //In contract to reading, execute queries are simpler as they return only\n        /// //the affected rows count if it is available.\n        /// var query = \"\"IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'Test') CREATE TABLE Test(Id INT PRIMARY KEY IDENTITY(1, 1) NOT NULL);\"\n        /// int affectedRowsCount = await storage.ExecuteAsync(query, command =>\n        /// {\n        ///     //There aren't parameters here, but they'd be added like when reading.\n        ///     //As the affected rows count is the only thing returned, there isn't\n        ///     //facilities to read anything.\n        /// }).ConfigureAwait(continueOnCapturedContext: false);\n        /// </code>\n        /// </example>\n        Task<int> ExecuteAsync(string query, Action<IDbCommand> parameterProvider, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// The well known invariant name of the underlying database.\n        /// </summary>\n        string InvariantName { get; }\n\n        /// <summary>\n        /// The connection string used to connect to the database.\n        /// </summary>\n        string ConnectionString { get; }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/NoOpDatabaseCommandInterceptor.cs",
    "content": "using System.Data;\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    internal class NoOpCommandInterceptor : ICommandInterceptor\n    {\n        public static readonly ICommandInterceptor Instance = new NoOpCommandInterceptor();\n\n        private NoOpCommandInterceptor()\n        {\n            \n        }\n\n        public void Intercept(IDbCommand command)\n        {\n            //NOP\n        }\n    }\n}\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/OracleDatabaseCommandInterceptor.cs",
    "content": "using System;\nusing System.Data;\nusing System.Linq.Expressions;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// This interceptor bypasses some Oracle specifics.\n    /// </summary>\n    internal class OracleCommandInterceptor : ICommandInterceptor\n    {\n        public static readonly ICommandInterceptor Instance = new OracleCommandInterceptor();\n\n        private readonly Lazy<Action<IDbDataParameter>> setClobOracleDbTypeAction;\n        private readonly Lazy<Action<IDbDataParameter>> setBlobOracleDbTypeAction;\n        private readonly Lazy<Action<IDbCommand>> setCommandBindByNameAction;\n\n\n        private OracleCommandInterceptor()\n        {\n            setClobOracleDbTypeAction = new Lazy<Action<IDbDataParameter>>(() => BuildSetOracleDbTypeAction(\"Clob\"));\n            setBlobOracleDbTypeAction = new Lazy<Action<IDbDataParameter>>(() => BuildSetOracleDbTypeAction(\"Blob\"));\n            setCommandBindByNameAction = new Lazy<Action<IDbCommand>>(BuildSetBindByNameAction);\n        }\n\n        /// <summary>\n        /// Creates a compiled lambda which sets the BindByName property on OracleCommand to true.\n        /// </summary>\n        /// <returns>An action which takes a OracleCommand as IDbCommand </returns>\n        private Action<IDbCommand> BuildSetBindByNameAction()\n        {\n            var type = Type.GetType(\"Oracle.ManagedDataAccess.Client.OracleCommand, Oracle.ManagedDataAccess\");\n\n            var parameterExpression = Expression.Parameter(typeof(IDbCommand), \"command\");\n\n            var castExpression = Expression.Convert(parameterExpression, type);\n\n            var booleanConstantExpression = Expression.Constant(true);\n\n            var setMethod = type.GetProperty(\"BindByName\").GetSetMethod();\n\n            var callExpression = Expression.Call(castExpression, setMethod, booleanConstantExpression);\n\n            return Expression.Lambda<Action<IDbCommand>>(callExpression, parameterExpression).Compile();\n        }\n\n        /// <summary>\n        /// Creates a compiled lambda which sets the OracleDbType property to the specified <paramref name=\"enumName\"/>\n        /// </summary>\n        /// <param name=\"enumName\">String value of a OracleDbType enum value.</param>\n        /// <returns>An action which takes a OracleParameter as IDbDataParameter.</returns>\n        private static Action<IDbDataParameter> BuildSetOracleDbTypeAction(string enumName)\n        {\n            var type = Type.GetType(\"Oracle.ManagedDataAccess.Client.OracleParameter, Oracle.ManagedDataAccess\");\n\n            var parameterExpression = Expression.Parameter(typeof(IDbDataParameter), \"dbparameter\");\n\n            var castExpression = Expression.Convert(parameterExpression, type);\n\n            var enumType = Type.GetType(\"Oracle.ManagedDataAccess.Client.OracleDbType, Oracle.ManagedDataAccess\");\n\n            var clob = Enum.Parse(enumType, enumName);\n\n            var enumConstantExpression = Expression.Constant(clob, enumType);\n\n            var setMethod = type.GetProperty(\"OracleDbType\").GetSetMethod();\n\n            var callExpression = Expression.Call(castExpression, setMethod, enumConstantExpression);\n\n            return Expression.Lambda<Action<IDbDataParameter>>(callExpression, parameterExpression).Compile();\n        }\n\n\n        public void Intercept(IDbCommand command)\n        {\n            foreach (IDbDataParameter commandParameter in command.Parameters)\n            {\n                //By default oracle binds parameters by index not name\n                //The property BindByName must be set to true to change the default behaviour\n                setCommandBindByNameAction.Value(command);\n\n                //String parameters are mapped to NVarChar2 OracleDbType which is limited to 4000 bytes\n                //This sets the OracleType explicitly to CLOB\n                if (commandParameter.ParameterName == \"PayloadJson\")\n                { \n                    setClobOracleDbTypeAction.Value(commandParameter);\n                    continue;\n                }\n\n                //Same like above\n                if (commandParameter.ParameterName == \"PayloadXml\")\n                { \n                    setClobOracleDbTypeAction.Value(commandParameter);\n                    continue;\n                }\n\n                //Byte arrays are mapped as RAW which causes problems\n                //This sets the OracleDbType explicitly to BLOB\n                if (commandParameter.ParameterName == \"PayloadBinary\")\n                {\n                    setBlobOracleDbTypeAction.Value(commandParameter);\n                    continue;\n                }\n\n                //Oracle doesn´t support DbType.Boolean, instead\n                //we map these to DbType.Int32\n                if (commandParameter.DbType == DbType.Boolean)\n                {\n                    commandParameter.Value = commandParameter.ToString() == bool.TrueString ? 1 : 0;\n                    commandParameter.DbType = DbType.Int32;\n                }\n            }\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/OrleansRelationalDownloadStream.cs",
    "content": "using System;\nusing System.Data.Common;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// This is a chunked read implementation for ADO.NET providers which do\n    /// not otherwise implement <see cref=\"DbDataReader.GetStream(int)\"/> natively.\n    /// </summary>\n    internal class OrleansRelationalDownloadStream : Stream\n    {\n        /// <summary>\n        /// A cached task as if there are multiple rounds of reads, it is likely\n        /// the bytes read is the same. This saves one allocation.\n        /// </summary>\n        private Task<int> _lastTask;\n\n        /// <summary>\n        /// The reader to use to read from the database.\n        /// </summary>\n        private DbDataReader _reader;\n\n        /// <summary>\n        /// The position in the overall stream.\n        /// </summary>\n        private long _position;\n\n        /// <summary>\n        /// The column ordinal to read from.\n        /// </summary>\n        private readonly int _ordinal;\n\n        /// <summary>\n        /// The total number of bytes in the column.\n        /// </summary>\n        private readonly long _totalBytes;\n\n        /// <summary>\n        /// The internal byte array buffer size used in .CopyToAsync.\n        /// This size is just a guess and is likely dependent on the database\n        /// tuning settings (e.g. read_buffer_size in case of MySQL).\n        /// </summary>\n        private const int InternalReadBufferLength = 4092;\n\n        /// <summary>\n        /// Initializes a new <see cref=\"OrleansRelationalDownloadStream\"/> instance.\n        /// </summary>\n        /// <param name=\"reader\">The reader to use to read from the database.</param>\n        /// <param name=\"ordinal\">The column ordinal to read from.</param>\n        public OrleansRelationalDownloadStream(DbDataReader reader, int ordinal)\n        {\n            _reader = reader;\n            _ordinal = ordinal;\n\n            //This return the total length of the column pointed by the ordinal.\n            _totalBytes = reader.GetBytes(ordinal, 0, null, 0, 0);\n        }\n\n        /// <inheritdoc/>\n        public override bool CanRead => _reader != null && (!_reader.IsClosed);\n\n        /// <inheritdoc/>\n        public override bool CanSeek => false;\n\n        /// <inheritdoc/>\n        public override bool CanTimeout => true;\n\n        /// <inheritdoc/>\n        public override bool CanWrite => false;\n\n        /// <inheritdoc/>\n        public override long Length => _totalBytes;\n\n        /// <inheritdoc/>\n        public override long Position\n        {\n            get => _position;\n            set => throw new NotSupportedException();\n        }\n\n        /// <inheritdoc/>\n        public override void Flush() => throw new NotSupportedException();\n\n        /// <inheritdoc/>\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n            //This will throw with the same parameter names if the parameters are not valid.\n            ValidateReadParameters(buffer, offset, count);\n\n            try\n            {\n                int length = Math.Min(count, (int)(_totalBytes - _position));\n                long bytesRead = 0;\n                if (length > 0)\n                {\n                    bytesRead = _reader.GetBytes(_ordinal, _position, buffer, offset, length);\n                    _position += bytesRead;\n                }\n\n                return (int)bytesRead;\n            }\n            catch (DbException dex)\n            {\n                //It's not OK to throw non-IOExceptions from a Stream.\n                throw new IOException(dex.Message, dex);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)\n        {\n            //This will throw with the same parameter names if the parameters are not valid.\n            ValidateReadParameters(buffer, offset, count);\n\n            if (cancellationToken.IsCancellationRequested)\n            {\n                var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);\n                tcs.SetCanceled(cancellationToken);\n                return tcs.Task;\n            }\n\n            try\n            {\n                //The last used task is saved in order to avoid one allocation when the number of bytes read\n                //will likely be the same multiple times.\n                int bytesRead = Read(buffer, offset, count);\n                var ret = _lastTask != null && bytesRead == _lastTask.Result ? _lastTask : (_lastTask = Task.FromResult(bytesRead));\n\n                return ret;\n            }\n            catch (Exception e)\n            {\n                //Due to call to Read, this is for sure a IOException and can be thrown out.\n                var tcs = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);\n                tcs.SetException(e);\n\n                return tcs.Task;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)\n        {\n            if (!cancellationToken.IsCancellationRequested)\n            {\n                byte[] buffer = new byte[InternalReadBufferLength];\n                int bytesRead;\n                while ((bytesRead = Read(buffer, 0, buffer.Length)) > 0)\n                {\n                    if (cancellationToken.IsCancellationRequested)\n                    {\n                        break;\n                    }\n\n                    await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();\n\n        /// <inheritdoc/>\n        public override void SetLength(long value) => throw new NotSupportedException();\n\n        /// <inheritdoc/>\n        public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();\n\n        /// <inheritdoc/>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                _reader = null;\n            }\n\n            base.Dispose(disposing);\n        }\n\n        /// <summary>\n        /// Checks the parameters passed into a ReadAsync() or Read() are valid.\n        /// </summary>\n        /// <param name=\"buffer\"></param>\n        /// <param name=\"offset\"></param>\n        /// <param name=\"count\"></param>\n        private static void ValidateReadParameters(byte[] buffer, long offset, long count)\n        {\n            ArgumentNullException.ThrowIfNull(buffer);\n            ArgumentOutOfRangeException.ThrowIfNegative(offset);\n            ArgumentOutOfRangeException.ThrowIfNegative(count);\n\n            if (checked(offset + count) > buffer.Length)\n            {\n                throw new ArgumentException(\"Invalid offset length\");\n            }\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/RelationalOrleansQueries.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nusing Orleans.Streaming.AdoNet;\nusing Orleans.GrainDirectory.AdoNet;\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// A class for all relational storages that support all systems stores : membership, reminders and statistics\n    /// </summary>\n    internal class RelationalOrleansQueries\n    {\n        /// <summary>\n        /// the underlying storage\n        /// </summary>\n        private readonly IRelationalStorage storage;\n\n        /// <summary>\n        /// When inserting statistics and generating a batch insert clause, these are the columns in the statistics\n        /// table that will be updated with multiple values. The other ones are updated with one value only.\n        /// </summary>\n        private static readonly string[] InsertStatisticsMultiupdateColumns = {\n            DbStoredQueries.Columns.IsValueDelta,\n            DbStoredQueries.Columns.StatValue,\n            DbStoredQueries.Columns.Statistic\n        };\n\n        /// <summary>\n        /// the orleans functional queries\n        /// </summary>\n        private readonly DbStoredQueries dbStoredQueries;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"storage\">the underlying relational storage</param>\n        /// <param name=\"dbStoredQueries\">Orleans functional queries</param>\n        private RelationalOrleansQueries(IRelationalStorage storage, DbStoredQueries dbStoredQueries)\n        {\n            this.storage = storage;\n            this.dbStoredQueries = dbStoredQueries;\n        }\n\n        /// <summary>\n        /// Creates an instance of a database of type <see cref=\"RelationalOrleansQueries\"/> and Initializes Orleans queries from the database.\n        /// Orleans uses only these queries and the variables therein, nothing more.\n        /// </summary>\n        /// <param name=\"invariantName\">The invariant name of the connector for this database.</param>\n        /// <param name=\"connectionString\">The connection string this database should use for database operations.</param>\n        internal static async Task<RelationalOrleansQueries> CreateInstance(string invariantName, string connectionString)\n        {\n            var storage = RelationalStorage.CreateInstance(invariantName, connectionString);\n\n            var queries = await storage.ReadAsync(DbStoredQueries.GetQueriesKey, DbStoredQueries.Converters.GetQueryKeyAndValue, null);\n\n            return new RelationalOrleansQueries(storage, new DbStoredQueries(queries.ToDictionary(q => q.Key, q => q.Value)));\n        }\n\n        private Task ExecuteAsync(string query, Func<IDbCommand, DbStoredQueries.Columns> parameterProvider)\n        {\n            return storage.ExecuteAsync(query, command => parameterProvider(command));\n        }\n\n        private async Task<TAggregate> ReadAsync<TResult, TAggregate>(string query,\n            Func<IDataRecord, TResult> selector,\n            Func<IDbCommand, DbStoredQueries.Columns> parameterProvider,\n            Func<IEnumerable<TResult>, TAggregate> aggregator)\n        {\n            var ret = await storage.ReadAsync(query, selector, command => parameterProvider(command));\n            return aggregator(ret);\n        }\n\n#if REMINDERS_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// Reads Orleans reminder data from the tables.\n        /// </summary>\n        /// <param name=\"serviceId\">The service ID.</param>\n        /// <param name=\"grainId\">The grain reference (ID).</param>\n        /// <returns>Reminder table data.</returns>\n        internal Task<ReminderTableData> ReadReminderRowsAsync(string serviceId, GrainId grainId)\n        {\n            return ReadAsync(dbStoredQueries.ReadReminderRowsKey, GetReminderEntry, command =>\n                new DbStoredQueries.Columns(command) { ServiceId = serviceId, GrainId = grainId.ToString() },\n                ret => new ReminderTableData(ret.ToList()));\n        }\n\n        /// <summary>\n        /// Reads Orleans reminder data from the tables.\n        /// </summary>\n        /// <param name=\"serviceId\">The service ID.</param>\n        /// <param name=\"beginHash\">The begin hash.</param>\n        /// <param name=\"endHash\">The end hash.</param>\n        /// <returns>Reminder table data.</returns>\n        internal Task<ReminderTableData> ReadReminderRowsAsync(string serviceId, uint beginHash, uint endHash)\n        {\n            var query = (int)beginHash < (int)endHash ? dbStoredQueries.ReadRangeRows1Key : dbStoredQueries.ReadRangeRows2Key;\n\n            return ReadAsync(query, GetReminderEntry, command =>\n                new DbStoredQueries.Columns(command) { ServiceId = serviceId, BeginHash = beginHash, EndHash = endHash },\n                ret => new ReminderTableData(ret.ToList()));\n        }\n\n        internal static KeyValuePair<string, string> GetQueryKeyAndValue(IDataRecord record)\n        {\n            return new KeyValuePair<string, string>(record.GetValue<string>(\"QueryKey\"),\n                record.GetValue<string>(\"QueryText\"));\n        }\n\n        internal static ReminderEntry GetReminderEntry(IDataRecord record)\n        {\n            //Having non-null field, GrainId, means with the query filter options, an entry was found.\n            string grainId = record.GetValueOrDefault<string>(nameof(DbStoredQueries.Columns.GrainId));\n            if (grainId != null)\n            {\n                return new ReminderEntry\n                {\n                    GrainId = GrainId.Parse(grainId),\n                    ReminderName = record.GetValue<string>(nameof(DbStoredQueries.Columns.ReminderName)),\n                    StartAt = record.GetDateTimeValue(nameof(DbStoredQueries.Columns.StartTime)),\n\n                    //Use the GetInt64 method instead of the generic GetValue<TValue> version to retrieve the value from the data record\n                    //GetValue<int> causes an InvalidCastException with oracle data provider. See https://github.com/dotnet/orleans/issues/3561\n                    Period = TimeSpan.FromMilliseconds(record.GetInt64(nameof(DbStoredQueries.Columns.Period))),\n                    ETag = DbStoredQueries.Converters.GetVersion(record).ToString()\n                };\n            }\n            return null;\n        }\n        /// <summary>\n        /// Reads one row of reminder data.\n        /// </summary>\n        /// <param name=\"serviceId\">Service ID.</param>\n        /// <param name=\"grainId\">The grain reference (ID).</param>\n        /// <param name=\"reminderName\">The reminder name to retrieve.</param>\n        /// <returns>A remainder entry.</returns>\n        internal Task<ReminderEntry> ReadReminderRowAsync(string serviceId, GrainId grainId,\n            string reminderName)\n        {\n            return ReadAsync(dbStoredQueries.ReadReminderRowKey, GetReminderEntry, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    GrainId = grainId.ToString(),\n                    ReminderName = reminderName\n                }, ret => ret.FirstOrDefault());\n        }\n\n        /// <summary>\n        /// Either inserts or updates a reminder row.\n        /// </summary>\n        /// <param name=\"serviceId\">The service ID.</param>\n        /// <param name=\"grainId\">The grain reference (ID).</param>\n        /// <param name=\"reminderName\">The reminder name to retrieve.</param>\n        /// <param name=\"startTime\">Start time of the reminder.</param>\n        /// <param name=\"period\">Period of the reminder.</param>\n        /// <returns>The new etag of the either or updated or inserted reminder row.</returns>\n        internal Task<string> UpsertReminderRowAsync(string serviceId, GrainId grainId,\n            string reminderName, DateTime startTime, TimeSpan period)\n        {\n            return ReadAsync(dbStoredQueries.UpsertReminderRowKey, DbStoredQueries.Converters.GetVersion, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    GrainHash = grainId.GetUniformHashCode(),\n                    GrainId = grainId.ToString(),\n                    ReminderName = reminderName,\n                    StartTime = startTime,\n                    Period = period\n                }, ret => ret.First().ToString());\n        }\n\n        /// <summary>\n        /// Deletes a reminder\n        /// </summary>\n        /// <param name=\"serviceId\">Service ID.</param>\n        /// <param name=\"grainId\"></param>\n        /// <param name=\"reminderName\"></param>\n        /// <param name=\"etag\"></param>\n        /// <returns></returns>\n        internal Task<bool> DeleteReminderRowAsync(string serviceId, GrainId grainId, string reminderName,\n            string etag)\n        {\n            return ReadAsync(dbStoredQueries.DeleteReminderRowKey, DbStoredQueries.Converters.GetSingleBooleanValue, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    GrainId = grainId.ToString(),\n                    ReminderName = reminderName,\n                    Version = etag\n                }, ret => ret.First());\n        }\n\n        /// <summary>\n        /// Deletes all reminders rows of a service id.\n        /// </summary>\n        /// <param name=\"serviceId\"></param>\n        /// <returns></returns>\n        internal Task DeleteReminderRowsAsync(string serviceId)\n        {\n            return ExecuteAsync(dbStoredQueries.DeleteReminderRowsKey, command =>\n                new DbStoredQueries.Columns(command) { ServiceId = serviceId });\n        }\n\n#endif\n\n#if CLUSTERING_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// Lists active gateways. Used mainly by Orleans clients.\n        /// </summary>\n        /// <param name=\"deploymentId\">The deployment for which to query the gateways.</param>\n        /// <returns>The gateways for the silo.</returns>\n        internal Task<List<Uri>> ActiveGatewaysAsync(string deploymentId)\n        {\n            return ReadAsync(dbStoredQueries.GatewaysQueryKey, DbStoredQueries.Converters.GetGatewayUri, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId, Status = SiloStatus.Active },\n                ret => ret.ToList());\n        }\n\n        /// <summary>\n        /// Queries Orleans membership data.\n        /// </summary>\n        /// <param name=\"deploymentId\">The deployment for which to query data.</param>\n        /// <param name=\"siloAddress\">Silo data used as parameters in the query.</param>\n        /// <returns>Membership table data.</returns>\n        internal Task<MembershipTableData> MembershipReadRowAsync(string deploymentId, SiloAddress siloAddress)\n        {\n            return ReadAsync(dbStoredQueries.MembershipReadRowKey, DbStoredQueries.Converters.GetMembershipEntry, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId, SiloAddress = siloAddress },\n                ConvertToMembershipTableData);\n        }\n\n        /// <summary>\n        /// returns all membership data for a deployment id\n        /// </summary>\n        /// <param name=\"deploymentId\"></param>\n        /// <returns></returns>\n        internal Task<MembershipTableData> MembershipReadAllAsync(string deploymentId)\n        {\n            return ReadAsync(dbStoredQueries.MembershipReadAllKey, DbStoredQueries.Converters.GetMembershipEntry, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId }, ConvertToMembershipTableData);\n        }\n\n        /// <summary>\n        /// deletes all membership entries for a deployment id\n        /// </summary>\n        /// <param name=\"deploymentId\"></param>\n        /// <returns></returns>\n        internal Task DeleteMembershipTableEntriesAsync(string deploymentId)\n        {\n            return ExecuteAsync(dbStoredQueries.DeleteMembershipTableEntriesKey, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId });\n        }\n\n        /// <summary>\n        /// deletes all membership entries for inactive silos where the IAmAliveTime is before the beforeDate parameter\n        /// and the silo status is <seealso cref=\"SiloStatus.Dead\"/>.\n        /// </summary>\n        /// <param name=\"beforeDate\"></param>\n        /// <param name=\"deploymentId\"></param>\n        /// <returns></returns>\n        internal Task CleanupDefunctSiloEntriesAsync(DateTimeOffset beforeDate, string deploymentId)\n        {\n            return ExecuteAsync(dbStoredQueries.CleanupDefunctSiloEntriesKey, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId, IAmAliveTime = beforeDate.UtcDateTime });\n        }\n\n        /// <summary>\n        /// Updates IAmAlive for a silo\n        /// </summary>\n        /// <param name=\"deploymentId\"></param>\n        /// <param name=\"siloAddress\"></param>\n        /// <param name=\"iAmAliveTime\"></param>\n        /// <returns></returns>\n        internal Task UpdateIAmAliveTimeAsync(string deploymentId, SiloAddress siloAddress, DateTime iAmAliveTime)\n        {\n            return ExecuteAsync(dbStoredQueries.UpdateIAmAlivetimeKey, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    DeploymentId = deploymentId,\n                    SiloAddress = siloAddress,\n                    IAmAliveTime = iAmAliveTime\n                });\n        }\n\n        /// <summary>\n        /// Inserts a version row if one does not already exist.\n        /// </summary>\n        /// <param name=\"deploymentId\">The deployment for which to query data.</param>\n        /// <returns><em>TRUE</em> if a row was inserted. <em>FALSE</em> otherwise.</returns>\n        internal Task<bool> InsertMembershipVersionRowAsync(string deploymentId)\n        {\n            return ReadAsync(dbStoredQueries.InsertMembershipVersionKey, DbStoredQueries.Converters.GetSingleBooleanValue, command =>\n                new DbStoredQueries.Columns(command) { DeploymentId = deploymentId }, ret => ret.First());\n        }\n\n        /// <summary>\n        /// Inserts a membership row if one does not already exist.\n        /// </summary>\n        /// <param name=\"deploymentId\">The deployment with which to insert row.</param>\n        /// <param name=\"membershipEntry\">The membership entry data to insert.</param>\n        /// <param name=\"etag\">The table expected version etag.</param>\n        /// <returns><em>TRUE</em> if insert succeeds. <em>FALSE</em> otherwise.</returns>\n        internal Task<bool> InsertMembershipRowAsync(string deploymentId, MembershipEntry membershipEntry,\n            string etag)\n        {\n            return ReadAsync(dbStoredQueries.InsertMembershipKey, DbStoredQueries.Converters.GetSingleBooleanValue, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    DeploymentId = deploymentId,\n                    IAmAliveTime = membershipEntry.IAmAliveTime,\n                    SiloName = membershipEntry.SiloName,\n                    HostName = membershipEntry.HostName,\n                    SiloAddress = membershipEntry.SiloAddress,\n                    StartTime = membershipEntry.StartTime,\n                    Status = membershipEntry.Status,\n                    ProxyPort = membershipEntry.ProxyPort,\n                    Version = etag\n                }, ret => ret.First());\n        }\n\n        /// <summary>\n        /// Updates membership row data.\n        /// </summary>\n        /// <param name=\"deploymentId\">The deployment with which to insert row.</param>\n        /// <param name=\"membershipEntry\">The membership data to used to update database.</param>\n        /// <param name=\"etag\">The table expected version etag.</param>\n        /// <returns><em>TRUE</em> if update SUCCEEDS. <em>FALSE</em> ot</returns>\n        internal Task<bool> UpdateMembershipRowAsync(string deploymentId, MembershipEntry membershipEntry,\n            string etag)\n        {\n            return ReadAsync(dbStoredQueries.UpdateMembershipKey, DbStoredQueries.Converters.GetSingleBooleanValue, command =>\n                new DbStoredQueries.Columns(command)\n                {\n                    DeploymentId = deploymentId,\n                    SiloAddress = membershipEntry.SiloAddress,\n                    IAmAliveTime = membershipEntry.IAmAliveTime,\n                    Status = membershipEntry.Status,\n                    SuspectTimes = membershipEntry.SuspectTimes,\n                    Version = etag\n                }, ret => ret.First());\n        }\n\n        private static MembershipTableData ConvertToMembershipTableData(IEnumerable<Tuple<MembershipEntry, int>> ret)\n        {\n            var retList = ret.ToList();\n            var tableVersionEtag = retList[0].Item2;\n            var membershipEntries = new List<Tuple<MembershipEntry, string>>();\n            if (retList[0].Item1 != null)\n            {\n                membershipEntries.AddRange(retList.Select(i => new Tuple<MembershipEntry, string>(i.Item1, string.Empty)));\n            }\n            return new MembershipTableData(membershipEntries, new TableVersion(tableVersionEtag, tableVersionEtag.ToString()));\n        }\n\n#endif\n\n#if STREAMING_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// Queues a stream message to the stream message table.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"payload\">The serialized event payload.</param>\n        /// <param name=\"expiryTimeout\">The expiry timeout for this event batch.</param>\n        /// <returns>An acknowledgement that the message was queued.</returns>\n        internal Task<AdoNetStreamMessageAck> QueueStreamMessageAsync(string serviceId, string providerId, string queueId, byte[] payload, int expiryTimeout)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n\n            return ReadAsync(\n                dbStoredQueries.QueueStreamMessageKey,\n                record => new AdoNetStreamMessageAck(\n                    (string)record[nameof(AdoNetStreamMessageAck.ServiceId)],\n                    (string)record[nameof(AdoNetStreamMessageAck.ProviderId)],\n                    (string)record[nameof(AdoNetStreamMessageAck.QueueId)],\n                    (long)record[nameof(AdoNetStreamMessageAck.MessageId)]),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    Payload = payload,\n                    ExpiryTimeout = expiryTimeout,\n                },\n                result => result.Single());\n        }\n\n        /// <summary>\n        /// Gets stream messages from the stream message table.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"maxCount\">The maximum count of event batches to get.</param>\n        /// <param name=\"maxAttempts\">The maximum attempts to lock an unprocessed event batch.</param>\n        /// <param name=\"visibilityTimeout\">The visibility timeout for the retrieved event batches.</param>\n        /// <param name=\"removalTimeout\">The timeout before the message is to be deleted from dead letters.</param>\n        /// <param name=\"evictionInterval\">The interval between opportunistic data eviction.</param>\n        /// <param name=\"evictionBatchSize\">The number of messages to evict in each batch.</param>\n        /// <returns>A list of dequeued payloads.</returns>\n        internal Task<IList<AdoNetStreamMessage>> GetStreamMessagesAsync(string serviceId, string providerId, string queueId, int maxCount, int maxAttempts, int visibilityTimeout, int removalTimeout, int evictionInterval, int evictionBatchSize)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n\n            return ReadAsync<AdoNetStreamMessage, IList<AdoNetStreamMessage>>(\n                dbStoredQueries.GetStreamMessagesKey,\n                record => new AdoNetStreamMessage(\n                    (string)record[nameof(AdoNetStreamMessage.ServiceId)],\n                    (string)record[nameof(AdoNetStreamMessage.ProviderId)],\n                    (string)record[nameof(AdoNetStreamMessage.QueueId)],\n                    (long)record[nameof(AdoNetStreamMessage.MessageId)],\n                    (int)record[nameof(AdoNetStreamMessage.Dequeued)],\n                    (DateTime)record[nameof(AdoNetStreamMessage.VisibleOn)],\n                    (DateTime)record[nameof(AdoNetStreamMessage.ExpiresOn)],\n                    (DateTime)record[nameof(AdoNetStreamMessage.CreatedOn)],\n                    (DateTime)record[nameof(AdoNetStreamMessage.ModifiedOn)],\n                    (byte[])record[nameof(AdoNetStreamMessage.Payload)]),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    MaxCount = maxCount,\n                    MaxAttempts = maxAttempts,\n                    VisibilityTimeout = visibilityTimeout,\n                    RemovalTimeout = removalTimeout,\n                    EvictionInterval = evictionInterval,\n                    EvictionBatchSize = evictionBatchSize\n                },\n                result => result.ToList());\n        }\n\n        /// <summary>\n        /// Confirms delivery of messages from the stream message table.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"messages\">The messages to confirm.</param>\n        /// <returns>A list of confirmations.</returns>\n        /// <remarks>\n        /// If <paramref name=\"messages\"/> is empty then an empty confirmation list is returned.\n        /// </remarks>\n        internal Task<IList<AdoNetStreamConfirmationAck>> ConfirmStreamMessagesAsync(string serviceId, string providerId, string queueId, IList<AdoNetStreamConfirmation> messages)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n            ArgumentNullException.ThrowIfNull(messages);\n\n            if (messages.Count == 0)\n            {\n                return Task.FromResult<IList<AdoNetStreamConfirmationAck>>([]);\n            }\n\n            // this builds a string in the form \"1:2|3:4|5:6\" where the first number is the message id and the second is the dequeue counter which acts as a receipt\n            // while we have more efficient ways of passing this data per RDMS, we use a string here to ensure call compatibility across ADONET providers\n            // it is the responsibility of the RDMS implementation to parse this string and apply it correctly\n            var items = messages.Aggregate(new StringBuilder(), (b, m) => b.Append(b.Length > 0 ? \"|\" : \"\").Append(m.MessageId).Append(':').Append(m.Dequeued), b => b.ToString());\n\n            return ReadAsync<AdoNetStreamConfirmationAck, IList<AdoNetStreamConfirmationAck>>(\n                dbStoredQueries.ConfirmStreamMessagesKey,\n                record => new AdoNetStreamConfirmationAck(\n                    (string)record[nameof(AdoNetStreamConfirmationAck.ServiceId)],\n                    (string)record[nameof(AdoNetStreamConfirmationAck.ProviderId)],\n                    (string)record[nameof(AdoNetStreamConfirmationAck.QueueId)],\n                    (long)record[nameof(AdoNetStreamConfirmationAck.MessageId)]),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    Items = items\n                },\n                result => result.ToList());\n        }\n\n        /// <summary>\n        /// Applies delivery failure logic to a stream message, such as making the message visible again or moving it to dead letters.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"messageId\">The message identifier.</param>\n        internal Task FailStreamMessageAsync(string serviceId, string providerId, string queueId, long messageId, int maxAttempts, int removalTimeout)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n\n            return ExecuteAsync(\n                dbStoredQueries.FailStreamMessageKey,\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    MessageId = messageId,\n                    MaxAttempts = maxAttempts,\n                    RemovalTimeout = removalTimeout\n                });\n        }\n\n        /// <summary>\n        /// Moves eligible messages from the stream message table to the dead letter table.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"maxCount\">The max number of messages to move in this batch.</param>\n        /// <param name=\"maxAttempts\">The max number of times a message can be dequeued.</param>\n        /// <param name=\"removalTimeout\">The timeout before the message is to be deleted from dead letters.</param>\n        internal Task EvictStreamMessagesAsync(string serviceId, string providerId, string queueId, int maxCount, int maxAttempts, int removalTimeout)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n\n            return ExecuteAsync(\n                dbStoredQueries.EvictStreamMessagesKey,\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    MaxCount = maxCount,\n                    MaxAttempts = maxAttempts,\n                    RemovalTimeout = removalTimeout\n                });\n        }\n\n        /// <summary>\n        /// Removes messages from the dead letter after their removal timeout expires.\n        /// </summary>\n        /// <param name=\"serviceId\">The service identifier.</param>\n        /// <param name=\"providerId\">The provider identifier.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"maxCount\">The max number of messages to move in this batch.</param>\n        internal Task EvictStreamDeadLettersAsync(string serviceId, string providerId, string queueId, int maxCount)\n        {\n            ArgumentNullException.ThrowIfNull(serviceId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(queueId);\n\n            return ExecuteAsync(\n                dbStoredQueries.EvictStreamDeadLettersKey,\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ServiceId = serviceId,\n                    ProviderId = providerId,\n                    QueueId = queueId,\n                    MaxCount = maxCount\n                });\n        }\n\n#endif\n\n#if GRAINDIRECTORY_ADONET || TESTER_SQLUTILS\n\n        /// <summary>\n        /// Registers a new grain activation.\n        /// </summary>\n        /// <param name=\"clusterId\">The cluster identifier.</param>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        /// <param name=\"siloAddress\">The silo address.</param>\n        /// <param name=\"activationId\">The activation identifier.</param>\n        /// <returns>The count of rows affected.</returns>\n        internal Task<AdoNetGrainDirectoryEntry> RegisterGrainActivationAsync(string clusterId, string providerId, string grainId, string siloAddress, string activationId)\n        {\n            ArgumentNullException.ThrowIfNull(clusterId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(grainId);\n            ArgumentNullException.ThrowIfNull(siloAddress);\n            ArgumentNullException.ThrowIfNull(activationId);\n\n            return ReadAsync(\n                dbStoredQueries.RegisterGrainActivationKey,\n                record => new AdoNetGrainDirectoryEntry(\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ClusterId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ProviderId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.GrainId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.SiloAddress)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ActivationId)]),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ClusterId = clusterId,\n                    ProviderId = providerId,\n                    GrainId = grainId,\n                    SiloAddressAsString = siloAddress,\n                    ActivationId = activationId\n                },\n                result => result.Single());\n        }\n\n        /// <summary>\n        /// Unregisters a grain activation.\n        /// </summary>\n        /// <param name=\"clusterId\">The cluster identifier.</param>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        /// <param name=\"activationId\">The activation identifier.</param>\n        /// <returns>The count of rows affected.</returns>\n        internal Task<int> UnregisterGrainActivationAsync(string clusterId, string providerId, string grainId, string activationId)\n        {\n            ArgumentNullException.ThrowIfNull(clusterId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(grainId);\n            ArgumentNullException.ThrowIfNull(activationId);\n\n            return ReadAsync(\n                dbStoredQueries.UnregisterGrainActivationKey,\n                record => record.GetInt32(0),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ClusterId = clusterId,\n                    ProviderId = providerId,\n                    GrainId = grainId,\n                    ActivationId = activationId\n                },\n                result => result.Single());\n        }\n\n        /// <summary>\n        /// Looks up a grain activation.\n        /// </summary>\n        /// <param name=\"clusterId\">The cluster identifier.</param>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        /// <returns>The grain activation if found or null if not.</returns>\n        internal Task<AdoNetGrainDirectoryEntry> LookupGrainActivationAsync(string clusterId, string providerId, string grainId)\n        {\n            ArgumentNullException.ThrowIfNull(clusterId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(grainId);\n\n            return ReadAsync(\n                dbStoredQueries.LookupGrainActivationKey,\n                record => new AdoNetGrainDirectoryEntry(\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ClusterId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ProviderId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.GrainId)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.SiloAddress)],\n                    (string)record[nameof(AdoNetGrainDirectoryEntry.ActivationId)]),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ClusterId = clusterId,\n                    ProviderId = providerId,\n                    GrainId = grainId,\n                },\n                result => result.SingleOrDefault());\n        }\n\n        /// <summary>\n        /// Unregisters all grain activations for a set of silos.\n        /// </summary>\n        /// <param name=\"clusterId\">The cluster identifier.</param>\n        /// <param name=\"siloAddresses\">The pipe separated set of silos.</param>\n        /// <returns>The count of rows affected.</returns>\n        internal Task<int> UnregisterGrainActivationsAsync(string clusterId, string providerId, string siloAddresses)\n        {\n            ArgumentNullException.ThrowIfNull(clusterId);\n            ArgumentNullException.ThrowIfNull(providerId);\n            ArgumentNullException.ThrowIfNull(siloAddresses);\n\n            return ReadAsync(\n                dbStoredQueries.UnregisterGrainActivationsKey,\n                record => record.GetInt32(0),\n                command => new DbStoredQueries.Columns(command)\n                {\n                    ClusterId = clusterId,\n                    ProviderId = providerId,\n                    SiloAddresses = siloAddresses\n                },\n                result => result.Single());\n        }\n\n#endif\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/RelationalStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.Common;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// A general purpose class to work with a given relational database and ADO.NET provider.\n    /// </summary>\n    [DebuggerDisplay(\"InvariantName = {InvariantName}, ConnectionString = {ConnectionString}\")]\n    internal class RelationalStorage : IRelationalStorage\n    {\n        /// <summary>\n        /// The connection string to use.\n        /// </summary>\n        private readonly string _connectionString;\n\n        /// <summary>\n        /// The invariant name of the connector for this database.\n        /// </summary>\n        private readonly string _invariantName;\n\n        /// <summary>\n        /// If the ADO.NET provider of this storage supports cancellation or not. This\n        /// capability is queried and the result is cached here.\n        /// </summary>\n        private readonly bool _supportsCommandCancellation;\n\n        /// <summary>\n        /// If the underlying ADO.NET implementation is natively asynchronous\n        /// (the ADO.NET Db*.XXXAsync classes are overridden) or not.\n        /// </summary>\n        private readonly bool _isSynchronousAdoNetImplementation;\n\n        /// <summary>\n        /// Command interceptor for the given data provider.\n        /// </summary>\n        private readonly ICommandInterceptor _databaseCommandInterceptor;\n\n        /// <summary>\n        /// The invariant name of the connector for this database.\n        /// </summary>\n        public string InvariantName\n        {\n            get\n            {\n                return _invariantName;\n            }\n        }\n\n\n        /// <summary>\n        /// The connection string used to connect to the database.\n        /// </summary>\n        public string ConnectionString\n        {\n            get\n            {\n                return _connectionString;\n            }\n        }\n\n\n        /// <summary>\n        /// Creates an instance of a database of type <see cref=\"IRelationalStorage\"/>.\n        /// </summary>\n        /// <param name=\"invariantName\">The invariant name of the connector for this database.</param>\n        /// <param name=\"connectionString\">The connection string this database should use for database operations.</param>\n        /// <returns></returns>\n        public static IRelationalStorage CreateInstance(string invariantName, string connectionString)\n        {\n            if (string.IsNullOrWhiteSpace(invariantName))\n            {\n                throw new ArgumentException(\"The name of invariant must contain characters\", nameof(invariantName));\n            }\n\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                throw new ArgumentException(\"Connection string must contain characters\", nameof(connectionString));\n            }\n\n            return new RelationalStorage(invariantName, connectionString);\n        }\n\n\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>SELECT</em> statement.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type.</typeparam>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>SELECT</em> statement.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"selector\">This function transforms the raw <see cref=\"IDataRecord\"/> results to type <see paramref=\"TResult\"/> the <see cref=\"int\"/> parameter being the resultset number.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>A list of objects as a result of the <see paramref=\"query\"/>.</returns>\n        /// <example>This sample shows how to make a hand-tuned database call.\n        /// <code>\n        /// //This struct holds the return value in this example.\n        /// public struct Information\n        /// {\n        ///     public string TABLE_CATALOG { get; set; }\n        ///     public string TABLE_NAME { get; set; }\n        /// }\n        ///\n        /// //Here are defined two queries. There can be more than two queries, in which case\n        /// //the result sets are differentiated by a count parameter. Here the queries are\n        /// //SELECT clauses, but they can be whatever, even mixed ones.\n        /// IEnumerable&lt;Information&gt; ret =\n        ///     await storage.ReadAsync&lt;Information&gt;(\"SELECT * FROM INFORMATION_SCHEMA.TABLES; SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tp1\", command =>\n        /// {\n        ///     //Parameters are added and created like this.\n        ///     //They are database vendor agnostic.\n        ///     var tp1 = command.CreateParameter();\n        ///     tp1.ParameterName = \"tp1\";\n        ///     tp1.Value = \"some test value\";\n        ///     tp1.DbType = DbType.String;\n        ///     tp1.Direction = ParameterDirection.Input;\n        ///     command.Parameters.Add(tp1);\n        ///\n        ///     //The selector is used to select the results within the result set. In this case there are two homogenous\n        ///     //result sets, so there is actually no need to check which result set the selector holds and it could\n        ///     //marked with by convention by underscore (_).\n        /// }, (selector, resultSetCount) =>\n        ///    {\n        ///        //This function is called once for each row returned, so the final result will be an\n        ///        //IEnumerable&lt;Information&gt;.\n        ///        return new Information\n        ///        {\n        ///            TABLE_CATALOG = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_CATALOG\"),\n        ///            TABLE_NAME = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_NAME\")\n        ///        }\n        ///}).ConfigureAwait(continueOnCapturedContext: false);\n        /// </code>\n        /// </example>\n        public async Task<IEnumerable<TResult>> ReadAsync<TResult>(string query, Action<IDbCommand> parameterProvider, Func<IDataRecord, int, CancellationToken, Task<TResult>> selector, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default)\n        {\n            //If the query is something else that is not acceptable (e.g. an empty string), there will an appropriate database exception.\n            if (query == null)\n            {\n                throw new ArgumentNullException(nameof(query));\n            }\n\n            if (selector == null)\n            {\n                throw new ArgumentNullException(nameof(selector));\n            }\n\n            return (await ExecuteAsync(query, parameterProvider, ExecuteReaderAsync, selector, commandBehavior, cancellationToken).ConfigureAwait(false)).Item1;\n        }\n\n\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.\n        /// </summary>\n        /// <param name=\"query\">The query to execute.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Affected rows count.</returns>\n        /// <example>This sample shows how to make a hand-tuned database call.\n        /// <code>\n        /// //In contract to reading, execute queries are simpler as they return only\n        /// //the affected rows count if it is available.\n        /// var query = \"\"IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Test') CREATE TABLE Test(Id INT PRIMARY KEY IDENTITY(1, 1) NOT NULL);\"\n        /// int affectedRowsCount = await storage.ExecuteAsync(query, command =>\n        /// {\n        ///     //There aren't parameters here, but they'd be added like when reading.\n        ///     //As the affected rows count is the only thing returned, there isn't\n        ///     //facilities to read anything.\n        /// }).ConfigureAwait(continueOnCapturedContext: false);\n        /// </code>\n        /// </example>\n        public async Task<int> ExecuteAsync(string query, Action<IDbCommand> parameterProvider, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default)\n        {\n            //If the query is something else that is not acceptable (e.g. an empty string), there will an appropriate database exception.\n            if (query == null)\n            {\n                throw new ArgumentNullException(nameof(query));\n            }\n\n            return (await ExecuteAsync(query, parameterProvider, ExecuteReaderAsync, (unit, id, c) => Task.FromResult(unit), commandBehavior, cancellationToken).ConfigureAwait(false)).Item2;\n        }\n\n        /// <summary>\n        /// Creates an instance of a database of type <see cref=\"RelationalStorage\"/>.\n        /// </summary>\n        /// <param name=\"invariantName\">The invariant name of the connector for this database.</param>\n        /// <param name=\"connectionString\">The connection string this database should use for database operations.</param>\n        private RelationalStorage(string invariantName, string connectionString)\n        {\n            this._connectionString = connectionString;\n            this._invariantName = invariantName;\n            _supportsCommandCancellation = DbConstantsStore.SupportsCommandCancellation(InvariantName);\n            _isSynchronousAdoNetImplementation = DbConstantsStore.IsSynchronousAdoNetImplementation(InvariantName);\n            this._databaseCommandInterceptor = DbConstantsStore.GetDatabaseCommandInterceptor(InvariantName);\n        }\n\n        private static async Task<Tuple<IEnumerable<TResult>, int>> SelectAsync<TResult>(DbDataReader reader, Func<IDataReader, int, CancellationToken, Task<TResult>> selector, CancellationToken cancellationToken)\n        {\n            var results = new List<TResult>();\n            var resultSetCount = 0;\n\n            do\n            {\n                while (await reader.ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))\n                {\n                    var obj = await selector(reader, resultSetCount, cancellationToken).ConfigureAwait(false);\n                    results.Add(obj);\n                }\n\n                ++resultSetCount;\n\n            } while (await reader.NextResultAsync(cancellationToken).ConfigureAwait(false));\n\n            return Tuple.Create(results.AsEnumerable(), reader.RecordsAffected);\n        }\n\n        private async Task<Tuple<IEnumerable<TResult>, int>> ExecuteReaderAsync<TResult>(DbCommand command, Func<IDataRecord, int, CancellationToken, Task<TResult>> selector, CommandBehavior commandBehavior, CancellationToken cancellationToken)\n        {\n            using (var reader = await command.ExecuteReaderAsync(commandBehavior, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))\n            {\n                CancellationTokenRegistration cancellationRegistration = default;\n                try\n                {\n                    if (cancellationToken.CanBeCanceled && _supportsCommandCancellation)\n                    {\n                        cancellationRegistration = cancellationToken.Register(CommandCancellation, Tuple.Create(reader, command), useSynchronizationContext: false);\n                    }\n                    return await SelectAsync(reader, selector, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);\n                }\n                finally\n                {\n                    cancellationRegistration.Dispose();\n                }\n            }\n        }\n\n\n        private async Task<Tuple<IEnumerable<TResult>, int>> ExecuteAsync<TResult>(\n            string query,\n            Action<DbCommand> parameterProvider,\n            Func<DbCommand, Func<IDataRecord, int, CancellationToken, Task<TResult>>, CommandBehavior, CancellationToken, Task<Tuple<IEnumerable<TResult>, int>>> executor,\n            Func<IDataRecord, int, CancellationToken, Task<TResult>> selector,\n            CommandBehavior commandBehavior,\n            CancellationToken cancellationToken)\n        {\n            using (var connection = DbConnectionFactory.CreateConnection(_invariantName, _connectionString))\n            {\n                await connection.OpenAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);\n                using (var command = connection.CreateCommand())\n                {\n                    parameterProvider?.Invoke(command);\n                    command.CommandText = query;\n\n                    _databaseCommandInterceptor.Intercept(command);\n\n                    Task<Tuple<IEnumerable<TResult>, int>> ret;\n                    if (_isSynchronousAdoNetImplementation)\n                    {\n                        ret = Task.Run(() => executor(command, selector, commandBehavior, cancellationToken), cancellationToken);\n                    }\n                    else\n                    {\n                        ret = executor(command, selector, commandBehavior, cancellationToken);\n                    }\n\n                    return await ret.ConfigureAwait(continueOnCapturedContext: false);\n                }\n            }\n        }\n\n\n        private static void CommandCancellation(object state)\n        {\n            //The MSDN documentation tells that DbCommand.Cancel() should not be called for SqlCommand if the reader has been closed\n            //in order to avoid a race condition that would cause the SQL Server to stream the result set\n            //despite the connection already closed. Source: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.cancel(v=vs.110).aspx.\n            //Enforcing this behavior across all providers does not seem to hurt.\n            var stateTuple = (Tuple<DbDataReader, DbCommand>)state;\n            if (!stateTuple.Item1.IsClosed)\n            {\n                stateTuple.Item2.Cancel();\n            }\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/AdoNet/Shared/Storage/RelationalStorageExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Data.Common;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\n#nullable disable\n\n#if CLUSTERING_ADONET\nnamespace Orleans.Clustering.AdoNet.Storage\n#elif PERSISTENCE_ADONET\nnamespace Orleans.Persistence.AdoNet.Storage\n#elif REMINDERS_ADONET\nnamespace Orleans.Reminders.AdoNet.Storage\n#elif STREAMING_ADONET\nnamespace Orleans.Streaming.AdoNet.Storage\n#elif GRAINDIRECTORY_ADONET\nnamespace Orleans.GrainDirectory.AdoNet.Storage\n#elif TESTER_SQLUTILS\nnamespace Orleans.Tests.SqlUtils\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Convenience functions to work with objects of type <see cref=\"IRelationalStorage\"/>.\n    /// </summary>\n    internal static class RelationalStorageExtensions\n    {\n        /// <summary>\n        /// Used to format .NET objects suitable to relational database format.\n        /// </summary>\n        private static readonly AdoNetFormatProvider adoNetFormatProvider = new AdoNetFormatProvider();\n\n        /// <summary>\n        /// This is a template to produce query parameters that are indexed.\n        /// </summary>\n        private const string indexedParameterTemplate = \"@p{0}\";\n\n        /// <summary>\n        /// Executes a multi-record insert query clause with <em>SELECT UNION ALL</em>.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"storage\">The storage to use.</param>\n        /// <param name=\"tableName\">The table name to against which to execute the query.</param>\n        /// <param name=\"parameters\">The parameters to insert.</param>\n        /// <param name=\"nameMap\">If provided, maps property names from <typeparamref name=\"T\"/> to ones provided in the map.</param>\n        /// <param name=\"onlyOnceColumns\">If given, SQL parameter values for the given <typeparamref name=\"T\"/> property types are generated only once. Effective only when <paramref name=\"useSqlParams\"/> is <em>TRUE</em>.</param>\n        /// <param name=\"useSqlParams\"><em>TRUE</em> if the query should be in parameterized form. <em>FALSE</em> otherwise.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>The rows affected.</returns>\n        public static Task<int> ExecuteMultipleInsertIntoAsync<T>(this IRelationalStorage storage, string tableName, IEnumerable<T> parameters, IReadOnlyDictionary<string, string> nameMap = null, IEnumerable<string> onlyOnceColumns = null, bool useSqlParams = true, CancellationToken cancellationToken = default)\n        {\n            if(string.IsNullOrWhiteSpace(tableName))\n            {\n                throw new ArgumentException(\"The name must be a legal SQL table name\", nameof(tableName));\n            }\n\n            if(parameters == null)\n            {\n                throw new ArgumentNullException(nameof(parameters));\n            }\n\n            var storageConsts = DbConstantsStore.GetDbConstants(storage.InvariantName);\n\n            var startEscapeIndicator = storageConsts.StartEscapeIndicator;\n            var endEscapeIndicator = storageConsts.EndEscapeIndicator;\n\n            //SqlParameters map is needed in case the query needs to be parameterized in order to avoid two\n            //reflection passes as first a query needs to be constructed and after that when a database\n            //command object has been created, parameters need to be provided to them.\n            var sqlParameters = new Dictionary<string, object>();\n            const string insertIntoValuesTemplate = \"INSERT INTO {0} ({1}) SELECT {2};\";\n            var columns = string.Empty;\n            var values = new List<string>();\n            if(parameters.Any())\n            {\n                //Type and property information are the same for all of the objects.\n                //The following assumes the property names will be retrieved in the same\n                //order as is the index iteration done.\n                var onlyOnceRow = new List<string>();\n                var properties = parameters.First().GetType().GetProperties();\n                columns = string.Join(\",\", nameMap == null ? properties.Select(pn => string.Format(\"{0}{1}{2}\", startEscapeIndicator, pn.Name, endEscapeIndicator)) : properties.Select(pn => string.Format(\"{0}{1}{2}\", startEscapeIndicator, (nameMap.TryGetValue(pn.Name, out var pnName) ? pnName : pn.Name), endEscapeIndicator)));\n                if (onlyOnceColumns != null && onlyOnceColumns.Any())\n                {\n                    var onlyOnceProperties = properties.Where(pn => onlyOnceColumns.Contains(pn.Name)).Select(pn => pn).ToArray();\n                    var onlyOnceData = parameters.First();\n                    for(int i = 0; i < onlyOnceProperties.Length; ++i)\n                    {\n                        var currentProperty = onlyOnceProperties[i];\n                        var parameterValue = currentProperty.GetValue(onlyOnceData, null);\n                        if(useSqlParams)\n                        {\n                            var parameterName = string.Format(\"@{0}\", (nameMap.TryGetValue(onlyOnceProperties[i].Name, out var parameter) ? parameter : onlyOnceProperties[i].Name));\n                            onlyOnceRow.Add(parameterName);\n                            sqlParameters.Add(parameterName, parameterValue);\n                        }\n                        else\n                        {\n                            onlyOnceRow.Add(string.Format(adoNetFormatProvider, \"{0}\", parameterValue));\n                        }\n                    }\n                }\n\n                var dataRows = new List<string>();\n                var multiProperties = onlyOnceColumns == null ? properties : properties.Where(pn => !onlyOnceColumns.Contains(pn.Name)).Select(pn => pn).ToArray();\n                int parameterCount = 0;\n                foreach(var row in parameters)\n                {\n                    for(int i = 0; i < multiProperties.Length; ++i)\n                    {\n                        var currentProperty = multiProperties[i];\n                        var parameterValue = currentProperty.GetValue(row, null);\n                        if(useSqlParams)\n                        {\n                            var parameterName = string.Format(indexedParameterTemplate, parameterCount);\n                            dataRows.Add(parameterName);\n                            sqlParameters.Add(parameterName, parameterValue);\n                            ++parameterCount;\n                        }\n                        else\n                        {\n                            dataRows.Add(string.Format(adoNetFormatProvider, \"{0}\", parameterValue));\n                        }\n                    }\n\n                    values.Add(string.Format(\"{0}\", string.Join(\",\", onlyOnceRow.Concat(dataRows))));\n                    dataRows.Clear();\n                }\n            }\n\n            var query = string.Format(insertIntoValuesTemplate, tableName, columns, string.Join(storageConsts.UnionAllSelectTemplate, values));\n            return storage.ExecuteAsync(query, command =>\n            {\n                if (useSqlParams)\n                {\n                    foreach (var sp in sqlParameters)\n                    {\n                        var p = command.CreateParameter();\n                        p.ParameterName = sp.Key;\n                        p.Value = sp.Value ?? DBNull.Value;\n                        p.Direction = ParameterDirection.Input;\n                        command.Parameters.Add(p);\n                    }\n                }\n            }, cancellationToken: cancellationToken);\n        }\n\n\n        /// <summary>\n        /// A simplified version of <see cref=\"IRelationalStorage.ReadAsync{TResult}\"/>\n        /// </summary>\n        /// <param name=\"storage\"></param>\n        /// <param name=\"query\"></param>\n        /// <param name=\"selector\"></param>\n        /// <param name=\"parameterProvider\"></param>\n        /// <typeparam name=\"TResult\"></typeparam>\n        /// <returns></returns>\n        public static Task<IEnumerable<TResult>> ReadAsync<TResult>(this IRelationalStorage storage, string query, Func<IDataRecord, TResult> selector, Action<IDbCommand> parameterProvider)\n        {\n            return storage.ReadAsync(query, parameterProvider, (record, i, cancellationToken) => Task.FromResult(selector(record)));\n        }\n\n        /// <summary>\n        /// Uses <see cref=\"IRelationalStorage\"/> with <see cref=\"DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})\"/>.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type of the result.</typeparam>\n        /// <param name=\"storage\">The storage to use.</param>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>SELECT</em> statement, but works with other queries too.</param>\n        /// <param name=\"parameters\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>A list of objects as a result of the <see paramref=\"query\"/>.</returns>\n        /// <example>This uses reflection to read results and match the parameters.\n        /// <code>\n        /// //This struct holds the return value in this example.\n        /// public struct Information\n        /// {\n        ///     public string TABLE_CATALOG { get; set; }\n        ///     public string TABLE_NAME { get; set; }\n        /// }\n        ///\n        /// //Here reflection (<seealso cref=\"DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})\"/>)\n        /// is used to match parameter names as well as to read back the results (<seealso cref=\"DbExtensions.ReflectionSelector{TResult}(IDataRecord)\"/>).\n        /// var query = \"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tname;\";\n        /// IEnumerable&lt;Information&gt; informationData = await db.ReadAsync&lt;Information&gt;(query, new { tname = 200000 });\n        /// </code>\n        /// </example>\n        public static Task<IEnumerable<TResult>> ReadAsync<TResult>(this IRelationalStorage storage, string query, object parameters, CancellationToken cancellationToken = default)\n        {\n            return storage.ReadAsync(query, command =>\n            {\n                if (parameters != null)\n                {\n                    command.ReflectionParameterProvider(parameters);\n                }\n            }, (selector, resultSetCount, token) => Task.FromResult(selector.ReflectionSelector<TResult>()), cancellationToken: cancellationToken);\n        }\n\n\n        /// <summary>\n        /// Uses <see cref=\"IRelationalStorage\"/> with <see cref=\"DbExtensions.ReflectionParameterProvider{T}(System.Data.IDbCommand, T, IReadOnlyDictionary{string, string})\">DbExtensions.ReflectionParameterProvider</see>.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type of the result.</typeparam>\n        /// <param name=\"storage\">The storage to use.</param>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>SELECT</em> statement, but works with other queries too.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>A list of objects as a result of the <see paramref=\"query\"/>.</returns>\n        public static Task<IEnumerable<TResult>> ReadAsync<TResult>(this IRelationalStorage storage, string query, CancellationToken cancellationToken = default)\n        {\n            return ReadAsync<TResult>(storage, query, null, cancellationToken);\n        }\n\n\n        /// <summary>\n        /// Uses <see cref=\"IRelationalStorage\"/> with <see cref=\"DbExtensions.ReflectionSelector{TResult}(System.Data.IDataRecord)\"/>.\n        /// </summary>\n        /// <param name=\"storage\">The storage to use.</param>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.</param>\n        /// <param name=\"parameters\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Affected rows count.</returns>\n        /// <example>This uses reflection to provide parameters to an execute\n        /// query that reads only affected rows count if available.\n        /// <code>\n        /// //Here reflection (<seealso cref=\"DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})\"/>)\n        /// is used to match parameter names as well as to read back the results (<seealso cref=\"DbExtensions.ReflectionSelector{TResult}(IDataRecord)\"/>).\n        /// var query = \"IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tname) CREATE TABLE Test(Id INT PRIMARY KEY IDENTITY(1, 1) NOT NULL);\"\n        /// await db.ExecuteAsync(query, new { tname = \"test_table\" });\n        /// </code>\n        /// </example>\n        public static Task<int> ExecuteAsync(this IRelationalStorage storage, string query, object parameters, CancellationToken cancellationToken = default)\n        {\n            return storage.ExecuteAsync(query, command =>\n            {\n                if (parameters != null)\n                {\n                    command.ReflectionParameterProvider(parameters);\n                }\n            }, cancellationToken: cancellationToken);\n        }\n\n\n        /// <summary>\n        /// Uses <see cref=\"IRelationalStorage\"/> with <see cref=\"DbExtensions.ReflectionSelector{TResult}(System.Data.IDataRecord)\"/>.\n        /// </summary>\n        /// <param name=\"storage\">The storage to use.</param>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Affected rows count.</returns>\n        public static Task<int> ExecuteAsync(this IRelationalStorage storage, string query, CancellationToken cancellationToken = default)\n        {\n            return ExecuteAsync(storage, query, null, cancellationToken);\n        }\n\n\n        /// <summary>\n        /// Returns a native implementation of <see cref=\"DbDataReader.GetStream(int)\"/> for those providers\n        /// which support it. Otherwise returns a chunked read using <see cref=\"DbDataReader.GetBytes(int, long, byte[], int, int)\"/>.\n        /// </summary>\n        /// <param name=\"reader\">The reader from which to return the stream.</param>\n        /// <param name=\"ordinal\">The ordinal column for which to return the stream.</param>\n        /// <param name=\"storage\">The storage that gives the invariant.</param>\n        /// <returns></returns>\n        public static Stream GetStream(this DbDataReader reader, int ordinal, IRelationalStorage storage)\n        {\n            if(storage.SupportsStreamNatively())\n            {\n                return reader.GetStream(ordinal);\n            }\n\n            return new OrleansRelationalDownloadStream(reader, ordinal);\n        }\n    }\n}\n\n#nullable restore\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/AzureBasedMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Azure;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.AzureUtils;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Clustering.AzureStorage.Utilities;\nusing Orleans.Configuration;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal partial class AzureBasedMembershipTable : IMembershipTable\n    {\n        private readonly ILogger logger;\n        private readonly ILoggerFactory loggerFactory;\n        private OrleansSiloInstanceManager tableManager;\n        private readonly AzureStorageClusteringOptions options;\n        private readonly string clusterId;\n\n        public AzureBasedMembershipTable(\n            ILoggerFactory loggerFactory,\n            IOptions<AzureStorageClusteringOptions> clusteringOptions,\n            IOptions<ClusterOptions> clusterOptions)\n        {\n            this.loggerFactory = loggerFactory;\n            this.logger = loggerFactory.CreateLogger<AzureBasedMembershipTable>();\n            this.options = clusteringOptions.Value;\n            this.clusterId = clusterOptions.Value.ClusterId;\n        }\n\n        public async Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            LogFormatter.SetExceptionDecoder(typeof(RequestFailedException), AzureTableUtils.PrintStorageException);\n\n            this.tableManager = await OrleansSiloInstanceManager.GetManager(\n                this.clusterId,\n                this.loggerFactory,\n                this.options);\n\n            // even if I am not the one who created the table,\n            // try to insert an initial table version if it is not already there,\n            // so we always have a first table version row, before this silo starts working.\n            if (tryInitTableVersion)\n            {\n                // ignore return value, since we don't care if I inserted it or not, as long as it is in there.\n                bool created = await tableManager.TryCreateTableVersionEntryAsync();\n                if (created) LogInformationCreatedNewTableVersionRow();\n            }\n        }\n\n        public Task DeleteMembershipTableEntries(string clusterId)\n        {\n            return tableManager.DeleteTableEntries(clusterId);\n        }\n\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            return tableManager.CleanupDefunctSiloEntries(beforeDate);\n        }\n\n        public async Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            try\n            {\n                var entries = await tableManager.FindSiloEntryAndTableVersionRow(key);\n                MembershipTableData data = Convert(entries);\n                LogDebugReadMyEntry(key, data);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorReadingSiloEntry(exc, key, tableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<MembershipTableData> ReadAll()\n        {\n            try\n            {\n                var entries = await tableManager.FindAllSiloEntries();\n                MembershipTableData data = Convert(entries);\n                LogTraceReadAllTable(data);\n\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningIntermediateErrorReadingAllSiloEntries(exc, tableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            try\n            {\n                LogDebugInsertRow(entry, tableVersion);\n                var tableEntry = Convert(entry, tableManager.DeploymentId);\n                var versionEntry = tableManager.CreateTableVersionEntry(tableVersion.Version);\n\n                bool result = await tableManager.InsertSiloEntryConditionally(\n                    tableEntry, versionEntry, tableVersion.VersionEtag);\n\n                if (result == false)\n                    LogWarningTableContention(entry, tableVersion);\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningInsertingMembershipEntry(exc,\n                    entry,\n                    tableVersion is null ? \"null\" : tableVersion.ToString(),\n                    tableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            try\n            {\n                LogDebugUpdateRow(entry, etag, tableVersion);\n                var siloEntry = Convert(entry, tableManager.DeploymentId);\n                var versionEntry = tableManager.CreateTableVersionEntry(tableVersion.Version);\n\n                bool result = await tableManager.UpdateSiloEntryConditionally(siloEntry, etag, versionEntry, tableVersion.VersionEtag);\n                if (result == false)\n                    LogWarningTableContentionEtag(entry, etag, tableVersion);\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningUpdatingMembershipEntry(exc,\n                    entry,\n                    tableVersion is null ? \"null\" : tableVersion.ToString(),\n                    tableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            try\n            {\n                LogDebugMergeEntry(entry);\n                var siloEntry = ConvertPartial(entry, tableManager.DeploymentId);\n                await tableManager.MergeTableEntryAsync(siloEntry);\n            }\n            catch (Exception exc)\n            {\n                LogWarningUpdatingMembershipEntry(exc,\n                    entry,\n                    tableManager.TableName);\n                throw;\n            }\n        }\n\n        private MembershipTableData Convert(List<(SiloInstanceTableEntry Entity, string ETag)> entries)\n        {\n            try\n            {\n                var memEntries = new List<Tuple<MembershipEntry, string>>();\n                TableVersion tableVersion = null;\n                foreach (var tuple in entries)\n                {\n                    var tableEntry = tuple.Entity;\n                    if (tableEntry.RowKey.Equals(SiloInstanceTableEntry.TABLE_VERSION_ROW))\n                    {\n                        tableVersion = new TableVersion(int.Parse(tableEntry.MembershipVersion), tuple.ETag);\n                    }\n                    else\n                    {\n                        try\n                        {\n\n                            MembershipEntry membershipEntry = Parse(tableEntry);\n                            memEntries.Add(new Tuple<MembershipEntry, string>(membershipEntry, tuple.ETag));\n                        }\n                        catch (Exception exc)\n                        {\n                            LogErrorParsingMembershipTableDataIgnoring(exc, tableEntry);\n                        }\n                    }\n                }\n                var data = new MembershipTableData(memEntries, tableVersion);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogErrorParsingMembershipTableData(exc, new(entries));\n                throw;\n            }\n        }\n\n        private static MembershipEntry Parse(SiloInstanceTableEntry tableEntry)\n        {\n            var parse = new MembershipEntry\n            {\n                HostName = tableEntry.HostName,\n                Status = (SiloStatus)Enum.Parse(typeof(SiloStatus), tableEntry.Status)\n            };\n\n            if (!string.IsNullOrEmpty(tableEntry.ProxyPort))\n                parse.ProxyPort = int.Parse(tableEntry.ProxyPort);\n\n            int port = 0;\n            if (!string.IsNullOrEmpty(tableEntry.Port))\n                int.TryParse(tableEntry.Port, out port);\n\n            int gen = 0;\n            if (!string.IsNullOrEmpty(tableEntry.Generation))\n                int.TryParse(tableEntry.Generation, out gen);\n\n            parse.SiloAddress = SiloAddress.New(IPAddress.Parse(tableEntry.Address), port, gen);\n\n            parse.RoleName = tableEntry.RoleName;\n            if (!string.IsNullOrEmpty(tableEntry.SiloName))\n            {\n                parse.SiloName = tableEntry.SiloName;\n            }\n            else if (!string.IsNullOrEmpty(tableEntry.InstanceName))\n            {\n                // this is for backward compatability: in a mixed cluster of old and new version,\n                // some entries will have the old InstanceName column.\n                parse.SiloName = tableEntry.InstanceName;\n            }\n            if (!string.IsNullOrEmpty(tableEntry.UpdateZone))\n                parse.UpdateZone = int.Parse(tableEntry.UpdateZone);\n\n            if (!string.IsNullOrEmpty(tableEntry.FaultZone))\n                parse.FaultZone = int.Parse(tableEntry.FaultZone);\n\n            parse.StartTime = !string.IsNullOrEmpty(tableEntry.StartTime) ?\n                LogFormatter.ParseDate(tableEntry.StartTime) : default;\n\n            parse.IAmAliveTime = !string.IsNullOrEmpty(tableEntry.IAmAliveTime) ?\n                LogFormatter.ParseDate(tableEntry.IAmAliveTime) : default;\n\n            var suspectingSilos = new List<SiloAddress>();\n            var suspectingTimes = new List<DateTime>();\n\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingSilos))\n            {\n                string[] silos = tableEntry.SuspectingSilos.Split('|');\n                foreach (string silo in silos)\n                {\n                    suspectingSilos.Add(SiloAddress.FromParsableString(silo));\n                }\n            }\n\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingTimes))\n            {\n                string[] times = tableEntry.SuspectingTimes.Split('|');\n                foreach (string time in times)\n                    suspectingTimes.Add(LogFormatter.ParseDate(time));\n            }\n\n            if (suspectingSilos.Count != suspectingTimes.Count)\n                throw new OrleansException(string.Format(\"SuspectingSilos.Length of {0} as read from Azure table is not equal to SuspectingTimes.Length of {1}\", suspectingSilos.Count, suspectingTimes.Count));\n\n            for (int i = 0; i < suspectingSilos.Count; i++)\n                parse.AddSuspector(suspectingSilos[i], suspectingTimes[i]);\n\n            return parse;\n        }\n\n        private static SiloInstanceTableEntry Convert(MembershipEntry memEntry, string deploymentId)\n        {\n            var tableEntry = new SiloInstanceTableEntry\n            {\n                DeploymentId = deploymentId,\n                Address = memEntry.SiloAddress.Endpoint.Address.ToString(),\n                Port = memEntry.SiloAddress.Endpoint.Port.ToString(CultureInfo.InvariantCulture),\n                Generation = memEntry.SiloAddress.Generation.ToString(CultureInfo.InvariantCulture),\n                HostName = memEntry.HostName,\n                Status = memEntry.Status.ToString(),\n                ProxyPort = memEntry.ProxyPort.ToString(CultureInfo.InvariantCulture),\n                RoleName = memEntry.RoleName,\n                SiloName = memEntry.SiloName,\n                // this is for backward compatability: in a mixed cluster of old and new version,\n                // we need to populate both columns.\n                InstanceName = memEntry.SiloName,\n                UpdateZone = memEntry.UpdateZone.ToString(CultureInfo.InvariantCulture),\n                FaultZone = memEntry.FaultZone.ToString(CultureInfo.InvariantCulture),\n                StartTime = LogFormatter.PrintDate(memEntry.StartTime),\n                IAmAliveTime = LogFormatter.PrintDate(memEntry.IAmAliveTime)\n            };\n\n            if (memEntry.SuspectTimes != null)\n            {\n                var siloList = new StringBuilder();\n                var timeList = new StringBuilder();\n                bool first = true;\n                foreach (var tuple in memEntry.SuspectTimes)\n                {\n                    if (!first)\n                    {\n                        siloList.Append('|');\n                        timeList.Append('|');\n                    }\n                    siloList.Append(tuple.Item1.ToParsableString());\n                    timeList.Append(LogFormatter.PrintDate(tuple.Item2));\n                    first = false;\n                }\n\n                tableEntry.SuspectingSilos = siloList.ToString();\n                tableEntry.SuspectingTimes = timeList.ToString();\n            }\n            else\n            {\n                tableEntry.SuspectingSilos = string.Empty;\n                tableEntry.SuspectingTimes = string.Empty;\n            }\n            tableEntry.PartitionKey = deploymentId;\n            tableEntry.RowKey = SiloInstanceTableEntry.ConstructRowKey(memEntry.SiloAddress);\n\n            return tableEntry;\n        }\n\n        private static SiloInstanceTableEntry ConvertPartial(MembershipEntry memEntry, string deploymentId)\n        {\n            return new SiloInstanceTableEntry\n            {\n                DeploymentId = deploymentId,\n                IAmAliveTime = LogFormatter.PrintDate(memEntry.IAmAliveTime),\n                PartitionKey = deploymentId,\n                RowKey = SiloInstanceTableEntry.ConstructRowKey(memEntry.SiloAddress)\n            };\n        }\n\n        private readonly struct UtilsEnumerableToStringLogValue(IEnumerable<(SiloInstanceTableEntry Entity, string ETag)> entries)\n        {\n            public override string ToString() => Utils.EnumerableToString(entries, tuple => tuple.Entity.ToString());\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Created new table version row.\"\n        )]\n        private partial void LogInformationCreatedNewTableVersionRow();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Read my entry {SiloAddress} Table=\\n{Data}\"\n        )]\n        private partial void LogDebugReadMyEntry(SiloAddress siloAddress, MembershipTableData data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading silo entry for key {SiloAddress} from the table {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorReadingSiloEntry(Exception exception, SiloAddress siloAddress, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"ReadAll Table={Data}\"\n        )]\n        private partial void LogTraceReadAllTable(MembershipTableData data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error reading all silo entries {TableName}.\"\n        )]\n        private partial void LogWarningIntermediateErrorReadingAllSiloEntries(Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"InsertRow entry = {Data}, table version = {TableVersion}\"\n        )]\n        private partial void LogDebugInsertRow(MembershipEntry data, TableVersion tableVersion);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_22,\n            Level = LogLevel.Warning,\n            Message = \"Insert failed due to contention on the table. Will retry. Entry {Data}, table version = {TableVersion}\"\n        )]\n        private partial void LogWarningTableContention(MembershipEntry data, TableVersion tableVersion);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_23,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error inserting entry {Data} tableVersion {TableVersion} to the table {TableName}\"\n        )]\n        private partial void LogWarningInsertingMembershipEntry(Exception ex, MembershipEntry data, string tableVersion, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpdateRow entry = {Data}, etag = {ETag}, table version = {TableVersion}\"\n        )]\n        private partial void LogDebugUpdateRow(MembershipEntry data, string eTag, TableVersion tableVersion);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_24,\n            Level = LogLevel.Warning,\n            Message = \"Update failed due to contention on the table. Will retry. Entry {Data}, eTag {ETag}, table version = {TableVersion}\"\n        )]\n        private partial void LogWarningTableContentionEtag(MembershipEntry data, string eTag, TableVersion tableVersion);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_25,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error updating entry {Data} tableVersion {TableVersion} to the table {TableName}\"\n        )]\n        private partial void LogWarningUpdatingMembershipEntry(Exception ex, MembershipEntry data, string tableVersion, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Merge entry = {Data}\"\n        )]\n        private partial void LogDebugMergeEntry(MembershipEntry data);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_26,\n            Level = LogLevel.Warning,\n            Message = \"Intermediate error updating IAmAlive field for entry {Data} to the table {TableName}.\"\n        )]\n        private partial void LogWarningUpdatingMembershipEntry(Exception ex, MembershipEntry data, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_61,\n            Level = LogLevel.Error,\n            Message = \"Intermediate error parsing SiloInstanceTableEntry to MembershipTableData: {Data}. Ignoring this entry.\"\n        )]\n        private partial void LogErrorParsingMembershipTableDataIgnoring(Exception ex, SiloInstanceTableEntry data);\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_60,\n            Level = LogLevel.Error,\n            Message = \"Intermediate error parsing SiloInstanceTableEntry to MembershipTableData: {Data}.\"\n        )]\n        private partial void LogErrorParsingMembershipTableData(Exception ex, UtilsEnumerableToStringLogValue data);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/AzureGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\n\nnamespace Orleans.AzureUtils\n{\n    internal class AzureGatewayListProvider : IGatewayListProvider\n    {\n        private OrleansSiloInstanceManager siloInstanceManager;\n        private readonly string clusterId;\n        private readonly AzureStorageGatewayOptions options;\n        private readonly ILoggerFactory loggerFactory;\n\n        public AzureGatewayListProvider(ILoggerFactory loggerFactory, IOptions<AzureStorageGatewayOptions> options, IOptions<ClusterOptions> clusterOptions, IOptions<GatewayOptions> gatewayOptions)\n        {\n            this.loggerFactory = loggerFactory;\n            this.clusterId = clusterOptions.Value.ClusterId;\n            this.MaxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n            this.options = options.Value;\n        }\n\n        public async Task InitializeGatewayListProvider()\n        {\n            this.siloInstanceManager = await OrleansSiloInstanceManager.GetManager(\n                this.clusterId,\n                this.loggerFactory,\n                this.options);\n        }\n        // no caching\n        public Task<IList<Uri>> GetGateways()\n        {\n            // FindAllGatewayProxyEndpoints already returns a deep copied List<Uri>.\n            return this.siloInstanceManager.FindAllGatewayProxyEndpoints();\n        }\n\n        public TimeSpan MaxStaleness { get; }\n\n        public bool IsUpdatable => true;\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/AzureTableClusteringExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.AzureUtils;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Hosting\n{\n    public static class AzureTableClusteringExtensions\n    {\n        /// <summary>\n        /// Configures the silo to use Azure Storage for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The silo builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseAzureStorageClustering(\n            this ISiloBuilder builder,\n            Action<AzureStorageClusteringOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IMembershipTable, AzureBasedMembershipTable>()\n                    .ConfigureFormatter<AzureStorageClusteringOptions>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the silo to use Azure Storage for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The silo builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseAzureStorageClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<AzureStorageClusteringOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<AzureStorageClusteringOptions>());\n                    services.AddTransient<IConfigurationValidator>(sp => new AzureStorageClusteringOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureStorageClusteringOptions>>().Get(Options.DefaultName), Options.DefaultName));\n                    services.AddSingleton<IMembershipTable, AzureBasedMembershipTable>()\n                    .ConfigureFormatter<AzureStorageClusteringOptions>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use Azure Storage for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseAzureStorageClustering(\n            this IClientBuilder builder,\n            Action<AzureStorageGatewayOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IGatewayListProvider, AzureGatewayListProvider>()\n                    .ConfigureFormatter<AzureStorageGatewayOptions>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use Azure Storage for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseAzureStorageClustering(\n            this IClientBuilder builder,\n            Action<OptionsBuilder<AzureStorageGatewayOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<AzureStorageGatewayOptions>());\n                    services.AddTransient<IConfigurationValidator>(sp => new AzureStorageGatewayOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureStorageGatewayOptions>>().Get(Options.DefaultName), Options.DefaultName));\n                    services.AddSingleton<IGatewayListProvider, AzureGatewayListProvider>()\n                    .ConfigureFormatter<AzureStorageGatewayOptions>();\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/AzureTableStorageClusteringProviderBuilder.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AzureTableStorage\", \"Clustering\", \"Silo\", typeof(AzureTableStorageClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"AzureTableStorage\", \"Clustering\", \"Client\", typeof(AzureTableStorageClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureTableStorageClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAzureStorageClustering((OptionsBuilder<AzureStorageClusteringOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var tableName = configurationSection[\"TableName\"];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.TableServiceClient = services.GetRequiredKeyedService<TableServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.TableServiceClient = new TableServiceClient(uri);\n                        }\n                        else\n                        {\n                            options.TableServiceClient = new TableServiceClient(connectionString);\n                        }\n                    }\n                }\n            }));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAzureStorageClustering((OptionsBuilder<AzureStorageGatewayOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var tableName = configurationSection[\"TableName\"];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.TableServiceClient = services.GetRequiredKeyedService<TableServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.TableServiceClient = new TableServiceClient(uri);\n                        }\n                        else\n                        {\n                            options.TableServiceClient = new TableServiceClient(connectionString);\n                        }\n                    }\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/Options/AzureStorageClusteringOptions.cs",
    "content": "namespace Orleans.Clustering.AzureStorage;\n\n/// <summary>\n/// Specify options used for AzureTableBasedMembership\n/// </summary>\npublic class AzureStorageClusteringOptions : AzureStorageOperationOptions\n{\n    public override string TableName { get; set; } = DEFAULT_TABLE_NAME;\n    public const string DEFAULT_TABLE_NAME = \"OrleansSiloInstances\";\n}\n\n/// <summary>\n/// Configuration validator for <see cref=\"AzureStorageClusteringOptions\"/>.\n/// </summary>\npublic class AzureStorageClusteringOptionsValidator : AzureStorageOperationOptionsValidator<AzureStorageClusteringOptions>\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AzureStorageClusteringOptionsValidator\"/> class.\n    /// </summary>\n    /// <param name=\"options\">The option to be validated.</param>\n    /// <param name=\"name\">The option name to be validated.</param>\n    public AzureStorageClusteringOptionsValidator(AzureStorageClusteringOptions options, string name) : base(options, name)\n    {\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/Options/AzureStorageGatewayOptions.cs",
    "content": "namespace Orleans.Clustering.AzureStorage;\n\npublic class AzureStorageGatewayOptions : AzureStorageOperationOptions\n{\n    public override string TableName { get; set; } = AzureStorageClusteringOptions.DEFAULT_TABLE_NAME;\n}\n\n/// <summary>\n/// Configuration validator for <see cref=\"AzureStorageGatewayOptions\"/>.\n/// </summary>\npublic class AzureStorageGatewayOptionsValidator : AzureStorageOperationOptionsValidator<AzureStorageGatewayOptions>\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AzureStorageGatewayOptionsValidator\"/> class.\n    /// </summary>\n    /// <param name=\"options\">The option to be validated.</param>\n    /// <param name=\"name\">The option name to be validated.</param>\n    public AzureStorageGatewayOptionsValidator(AzureStorageGatewayOptions options, string name) : base(options, name)\n    {\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/Orleans.Clustering.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Table Storage Clustering Provider</Title>\n    <Description>Microsoft Orleans clustering provider backed by Azure Table Storage</Description>\n    <PackageTags>$(PackageTags) Azure Table Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Clustering.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.Clustering.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_CLUSTERING</DefineConstants>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/OrleansSiloInstanceManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Clustering.AzureStorage.Utilities;\nusing Orleans.Runtime;\n\nnamespace Orleans.AzureUtils\n{\n    internal partial class OrleansSiloInstanceManager\n    {\n        public string TableName { get; }\n\n        private const string INSTANCE_STATUS_CREATED = nameof(SiloStatus.Created);  //\"Created\";\n        private const string INSTANCE_STATUS_ACTIVE = nameof(SiloStatus.Active);    //\"Active\";\n        private const string INSTANCE_STATUS_DEAD = nameof(SiloStatus.Dead);        //\"Dead\";\n\n        private readonly AzureTableDataManager<SiloInstanceTableEntry> storage;\n        private readonly ILogger logger;\n        private readonly AzureStoragePolicyOptions storagePolicyOptions;\n\n        public string DeploymentId { get; private set; }\n\n        private OrleansSiloInstanceManager(\n            string clusterId,\n            ILoggerFactory loggerFactory,\n            AzureStorageOperationOptions options)\n        {\n            DeploymentId = clusterId;\n            TableName = options.TableName;\n            logger = loggerFactory.CreateLogger<OrleansSiloInstanceManager>();\n            storage = new AzureTableDataManager<SiloInstanceTableEntry>(\n                options,\n                loggerFactory.CreateLogger<AzureTableDataManager<SiloInstanceTableEntry>>());\n            this.storagePolicyOptions = options.StoragePolicyOptions;\n        }\n\n        public static async Task<OrleansSiloInstanceManager> GetManager(\n            string clusterId,\n            ILoggerFactory loggerFactory,\n            AzureStorageOperationOptions options)\n        {\n            var instance = new OrleansSiloInstanceManager(clusterId, loggerFactory, options);\n            try\n            {\n                await instance.storage.InitTableAsync();\n            }\n            catch (Exception ex)\n            {\n                instance.LogErrorConnectingToAzureTable(ex, instance.storage.TableName);\n                throw;\n            }\n            return instance;\n        }\n\n        public SiloInstanceTableEntry CreateTableVersionEntry(int tableVersion)\n        {\n            return new SiloInstanceTableEntry\n            {\n                DeploymentId = DeploymentId,\n                PartitionKey = DeploymentId,\n                RowKey = SiloInstanceTableEntry.TABLE_VERSION_ROW,\n                MembershipVersion = tableVersion.ToString(CultureInfo.InvariantCulture)\n            };\n        }\n\n        public void RegisterSiloInstance(SiloInstanceTableEntry entry)\n        {\n            entry.Status = INSTANCE_STATUS_CREATED;\n            LogRegisterSiloInstance(entry);\n            Task.WaitAll(new Task[] { storage.UpsertTableEntryAsync(entry) });\n        }\n\n        public Task<string> UnregisterSiloInstance(SiloInstanceTableEntry entry)\n        {\n            entry.Status = INSTANCE_STATUS_DEAD;\n            LogUnregisterSiloInstance(entry);\n            return storage.UpsertTableEntryAsync(entry);\n        }\n\n        public Task<string> ActivateSiloInstance(SiloInstanceTableEntry entry)\n        {\n            LogActivateSiloInstance(entry);\n            entry.Status = INSTANCE_STATUS_ACTIVE;\n            return storage.UpsertTableEntryAsync(entry);\n        }\n\n        /// <summary>\n        /// Represent a silo instance entry in the gateway URI format.\n        /// </summary>\n        /// <param name=\"gateway\">The input silo instance</param>\n        /// <returns></returns>\n        private static Uri ConvertToGatewayUri(SiloInstanceTableEntry gateway)\n        {\n            int proxyPort = 0;\n            if (!string.IsNullOrEmpty(gateway.ProxyPort))\n                int.TryParse(gateway.ProxyPort, out proxyPort);\n\n            int gen = 0;\n            if (!string.IsNullOrEmpty(gateway.Generation))\n                int.TryParse(gateway.Generation, out gen);\n\n            SiloAddress address = SiloAddress.New(IPAddress.Parse(gateway.Address), proxyPort, gen);\n            return address.ToGatewayUri();\n        }\n\n        public async Task<IList<Uri>> FindAllGatewayProxyEndpoints()\n        {\n            LogDebugSearchingGateway(this.DeploymentId);\n\n            try\n            {\n                const string Zero = \"0\";\n                var queryResults = await storage.ReadTableEntriesAndEtagsAsync(TableClient.CreateQueryFilter($\"PartitionKey eq {DeploymentId} and Status eq {INSTANCE_STATUS_ACTIVE} and ProxyPort ne {Zero}\"));\n\n                var gatewaySiloInstances = queryResults.Select(entity => ConvertToGatewayUri(entity.Item1)).ToList();\n\n                LogFoundGateway(gatewaySiloInstances.Count, this.DeploymentId);\n                return gatewaySiloInstances;\n            }catch(Exception exc)\n            {\n                LogErrorSearchingGateway(exc, this.DeploymentId);\n                throw;\n            }\n        }\n\n        public async Task<string> DumpSiloInstanceTable()\n        {\n            var queryResults = await storage.ReadAllTableEntriesForPartitionAsync(this.DeploymentId);\n\n            SiloInstanceTableEntry[] entries = queryResults.Select(entry => entry.Item1).ToArray();\n\n            var sb = new StringBuilder();\n            sb.Append(string.Format(\"Deployment {0}. Silos: \", DeploymentId));\n\n            // Loop through the results, displaying information about the entity\n            Array.Sort(entries,\n                (e1, e2) =>\n                {\n                    if (e1 == null) return (e2 == null) ? 0 : -1;\n                    if (e2 == null) return (e1 == null) ? 0 : 1;\n                    if (e1.SiloName == null) return (e2.SiloName == null) ? 0 : -1;\n                    if (e2.SiloName == null) return (e1.SiloName == null) ? 0 : 1;\n                    return string.CompareOrdinal(e1.SiloName, e2.SiloName);\n                });\n            foreach (SiloInstanceTableEntry entry in entries)\n            {\n                sb.AppendLine(string.Format(\"[IP {0}:{1}:{2}, {3}, Instance={4}, Status={5}]\", entry.Address, entry.Port, entry.Generation,\n                    entry.HostName, entry.SiloName, entry.Status));\n            }\n            return sb.ToString();\n        }\n\n        internal Task<string> MergeTableEntryAsync(SiloInstanceTableEntry data)\n        {\n            return storage.MergeTableEntryAsync(data, AzureTableUtils.ANY_ETAG); // we merge this without checking eTags.\n        }\n\n        internal Task<(SiloInstanceTableEntry, string)> ReadSingleTableEntryAsync(string partitionKey, string rowKey)\n        {\n            return storage.ReadSingleTableEntryAsync(partitionKey, rowKey);\n        }\n\n        internal async Task<int> DeleteTableEntries(string clusterId)\n        {\n            if (clusterId == null) throw new ArgumentNullException(nameof(clusterId));\n\n            var entries = await storage.ReadAllTableEntriesForPartitionAsync(clusterId);\n\n            await DeleteEntriesBatch(entries);\n\n            return entries.Count;\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            var entriesList = (await FindAllSiloEntries())\n                .Where(entry => !string.Equals(SiloInstanceTableEntry.TABLE_VERSION_ROW, entry.Item1.RowKey)\n                    && entry.Item1.Status != INSTANCE_STATUS_ACTIVE\n                    && entry.Item1.Timestamp < beforeDate)\n                .ToList();\n\n            await DeleteEntriesBatch(entriesList);\n        }\n\n        private async Task DeleteEntriesBatch(List<(SiloInstanceTableEntry, string)> entriesList)\n        {\n            if (entriesList.Count <= this.storagePolicyOptions.MaxBulkUpdateRows)\n            {\n                await storage.DeleteTableEntriesAsync(entriesList);\n            }\n            else\n            {\n                var tasks = new List<Task>();\n                foreach (var batch in entriesList.BatchIEnumerable(this.storagePolicyOptions.MaxBulkUpdateRows))\n                {\n                    tasks.Add(storage.DeleteTableEntriesAsync(batch));\n                }\n                await Task.WhenAll(tasks);\n            }\n        }\n\n        internal async Task<List<(SiloInstanceTableEntry, string)>> FindSiloEntryAndTableVersionRow(SiloAddress siloAddress)\n        {\n            string rowKey = SiloInstanceTableEntry.ConstructRowKey(siloAddress);\n\n            var filter = TableClient.CreateQueryFilter($\"(PartitionKey eq {DeploymentId}) and ((RowKey eq {rowKey}) or (RowKey eq {SiloInstanceTableEntry.TABLE_VERSION_ROW}))\");\n            var queryResults = await storage.ReadTableEntriesAndEtagsAsync(filter);\n            if (queryResults.Count < 1 || queryResults.Count > 2)\n                throw new KeyNotFoundException(string.Format(\"Could not find table version row or found too many entries. Was looking for key {0}, found = {1}\", siloAddress, Utils.EnumerableToString(queryResults)));\n\n            int numTableVersionRows = queryResults.Count(tuple => tuple.Item1.RowKey == SiloInstanceTableEntry.TABLE_VERSION_ROW);\n            if (numTableVersionRows < 1)\n                throw new KeyNotFoundException(string.Format(\"Did not read table version row. Read = {0}\", Utils.EnumerableToString(queryResults)));\n\n            if (numTableVersionRows > 1)\n                throw new KeyNotFoundException(string.Format(\"Read {0} table version rows, while was expecting only 1. Read = {1}\", numTableVersionRows, Utils.EnumerableToString(queryResults)));\n\n            return queryResults;\n        }\n\n        internal async Task<List<(SiloInstanceTableEntry, string)>> FindAllSiloEntries()\n        {\n            var queryResults = await storage.ReadAllTableEntriesForPartitionAsync(this.DeploymentId);\n            if (queryResults.Count < 1)\n                throw new KeyNotFoundException(string.Format(\"Could not find enough rows in the FindAllSiloEntries call. Found = {0}\", Utils.EnumerableToString(queryResults)));\n\n            int numTableVersionRows = queryResults.Count(tuple => tuple.Item1.RowKey == SiloInstanceTableEntry.TABLE_VERSION_ROW);\n            if (numTableVersionRows < 1)\n                throw new KeyNotFoundException(string.Format(\"Did not find table version row. Read = {0}\", Utils.EnumerableToString(queryResults)));\n            if (numTableVersionRows > 1)\n                throw new KeyNotFoundException(string.Format(\"Read {0} table version rows, while was expecting only 1. Read = {1}\", numTableVersionRows, Utils.EnumerableToString(queryResults)));\n\n            return queryResults;\n        }\n\n        /// <summary>\n        /// Insert (create new) row entry\n        /// </summary>\n        internal async Task<bool> TryCreateTableVersionEntryAsync()\n        {\n            try\n            {\n                var versionRow = await storage.ReadSingleTableEntryAsync(DeploymentId, SiloInstanceTableEntry.TABLE_VERSION_ROW);\n                if (versionRow.Entity != null)\n                {\n                    return false;\n                }\n\n                SiloInstanceTableEntry entry = CreateTableVersionEntry(0);\n                await storage.CreateTableEntryAsync(entry);\n                return true;\n            }\n            catch (Exception exc)\n            {\n                if (!AzureTableUtils.EvaluateException(exc, out var httpStatusCode, out var restStatus)) throw;\n\n                LogTraceInsertSiloEntryConditionallyFailed(httpStatusCode, restStatus);\n                if (AzureTableUtils.IsContentionError(httpStatusCode)) return false;\n\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Insert (create new) row entry\n        /// </summary>\n        /// <param name=\"siloEntry\">Silo Entry to be written</param>\n        /// <param name=\"tableVersionEntry\">Version row to update</param>\n        /// <param name=\"tableVersionEtag\">Version row eTag</param>\n        internal async Task<bool> InsertSiloEntryConditionally(SiloInstanceTableEntry siloEntry, SiloInstanceTableEntry tableVersionEntry, string tableVersionEtag)\n        {\n            try\n            {\n                await storage.InsertTwoTableEntriesConditionallyAsync(siloEntry, tableVersionEntry, tableVersionEtag);\n                return true;\n            }\n            catch (Exception exc)\n            {\n                if (!AzureTableUtils.EvaluateException(exc, out var httpStatusCode, out var restStatus)) throw;\n\n                LogTraceInsertSiloEntryConditionallyFailed(httpStatusCode, restStatus);\n                if (AzureTableUtils.IsContentionError(httpStatusCode)) return false;\n\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Conditionally update the row for this entry, but only if the eTag matches with the current record in data store\n        /// </summary>\n        /// <param name=\"siloEntry\">Silo Entry to be written</param>\n        /// <param name=\"entryEtag\">ETag value for the entry being updated</param>\n        /// <param name=\"tableVersionEntry\">Version row to update</param>\n        /// <param name=\"versionEtag\">ETag value for the version row</param>\n        /// <returns></returns>\n        internal async Task<bool> UpdateSiloEntryConditionally(SiloInstanceTableEntry siloEntry, string entryEtag, SiloInstanceTableEntry tableVersionEntry, string versionEtag)\n        {\n            try\n            {\n                await storage.UpdateTwoTableEntriesConditionallyAsync(siloEntry, entryEtag, tableVersionEntry, versionEtag);\n                return true;\n            }\n            catch (Exception exc)\n            {\n                if (!AzureTableUtils.EvaluateException(exc, out var httpStatusCode, out var restStatus)) throw;\n\n                LogTraceUpdateSiloEntryConditionallyFailed(httpStatusCode, restStatus);\n                if (AzureTableUtils.IsContentionError(httpStatusCode)) return false;\n\n                throw;\n            }\n        }\n\n        [LoggerMessage(\n            EventId = (int)TableStorageErrorCode.AzureTable_33,\n            Level = LogLevel.Error,\n            Message = \"Exception trying to create or connect to the Azure table {TableName}\"\n        )]\n        private partial void LogErrorConnectingToAzureTable(Exception exception, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100270,\n            Level = LogLevel.Information,\n            Message = \"Registering silo instance: {Data}\"\n        )]\n        private partial void LogRegisterSiloInstance(SiloInstanceTableEntry data);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100271,\n            Level = LogLevel.Information,\n            Message = \"Unregistering silo instance: {Data}\"\n        )]\n        private partial void LogUnregisterSiloInstance(SiloInstanceTableEntry data);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100272,\n            Level = LogLevel.Information,\n            Message = \"Activating silo instance: {Data}\"\n        )]\n        private partial void LogActivateSiloInstance(SiloInstanceTableEntry data);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100277,\n            Level = LogLevel.Debug,\n            Message = \"Searching for active gateway silos for deployment {DeploymentId}.\"\n        )]\n        private partial void LogDebugSearchingGateway(string deploymentId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100278,\n            Level = LogLevel.Information,\n            Message = \"Found {GatewaySiloCount} active Gateway Silos for deployment {DeploymentId}.\"\n        )]\n        private partial void LogFoundGateway(int gatewaySiloCount, string deploymentId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100331,\n            Level = LogLevel.Error,\n            Message = \"Error searching for active gateway silos for deployment {DeploymentId} \"\n        )]\n        private partial void LogErrorSearchingGateway(Exception exception, string deploymentId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"InsertSiloEntryConditionally failed with httpStatusCode={HttpStatusCode}, restStatus={RestStatus}\"\n        )]\n        private partial void LogTraceInsertSiloEntryConditionallyFailed(HttpStatusCode httpStatusCode, string restStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"UpdateSiloEntryConditionally failed with httpStatusCode={HttpStatusCode}, restStatus={RestStatus}\"\n        )]\n        private partial void LogTraceUpdateSiloEntryConditionallyFailed(HttpStatusCode httpStatusCode, string restStatus);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/README.md",
    "content": "# Microsoft Orleans Clustering Provider for Azure Storage\n\n## Introduction\nMicrosoft Orleans Clustering Provider for Azure Storage allows Orleans silos to organize themselves as a cluster using Azure Table Storage. This provider enables silos to discover each other, maintain cluster membership, and detect and handle failures.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Clustering.AzureStorage\n```\n\n## Example - Configuring Azure Storage Clustering\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\n// Implement the grain interface\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"Hello, {greeting}!\");\n    }\n}\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            // Configure Azure Table Storage for clustering\n            .UseAzureStorageClustering(options =>\n            {\n                options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                options.TableName = \"OrleansClustering\"; // Optional: defaults to \"OrleansClustering\"\n            });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"World\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Configuring Client to Connect to Cluster\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\nnamespace ExampleGrains;\n\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\nvar clientBuilder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(clientBuilder =>\n    {\n        clientBuilder\n            // Configure the client to use Azure Storage for clustering\n            .UseAzureStorageClustering(options =>\n            {\n                options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                options.TableName = \"OrleansClustering\"; // Optional: defaults to \"OrleansClustering\"\n            });\n    });\n\nvar host = clientBuilder.Build();\nawait host.StartAsync();\nvar client = host.Services.GetRequiredService<IClusterClient>();\n\n// Get a reference to a grain and call it\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"World\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Clustering providers](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n- [Azure Storage provider](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/azure-storage-providers)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/SiloInstanceTableEntry.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Text;\nusing Azure;\nusing Azure.Data.Tables;\nusing Orleans.Runtime;\n\nnamespace Orleans.AzureUtils\n{\n    internal class SiloInstanceTableEntry : ITableEntity\n    {\n        public string DeploymentId { get; set; }    // PartitionKey\n        public string Address { get; set; }         // RowKey\n        public string Port { get; set; }            // RowKey\n        public string Generation { get; set; }      // RowKey\n\n        public string HostName { get; set; }        // Mandatory\n        public string Status { get; set; }          // Mandatory\n        public string ProxyPort { get; set; }       // Optional\n\n        public string RoleName { get; set; }        // Optional - only for Azure role\n        public string SiloName { get; set; }\n        public string InstanceName { get; set; }    // For backward compatability we leave the old column, untill all clients update the code to new version.\n        public string UpdateZone { get; set; }         // Optional - only for Azure role\n        public string FaultZone { get; set; }          // Optional - only for Azure role\n\n        public string SuspectingSilos { get; set; }          // For liveness\n        public string SuspectingTimes { get; set; }          // For liveness\n\n        public string StartTime       { get; set; }          // Time this silo was started. For diagnostics.\n        public string IAmAliveTime    { get; set; }           // Time this silo updated it was alive. For diagnostics.\n        public string MembershipVersion      { get; set; }               // Special version row (for serializing table updates). // We'll have a designated row with only MembershipVersion column.\n\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n\n        internal const string TABLE_VERSION_ROW = \"VersionRow\"; // Row key for version row.\n        internal const char Seperator = '-';\n\n        public static string ConstructRowKey(SiloAddress silo)\n        {\n            return string.Format(\"{0}-{1}-{2}\", silo.Endpoint.Address, silo.Endpoint.Port, silo.Generation);\n        }\n        internal static SiloAddress UnpackRowKey(string rowKey)\n        {\n            var debugInfo = \"UnpackRowKey\";\n            try\n            {\n#if DEBUG\n                debugInfo = string.Format(\"UnpackRowKey: RowKey={0}\", rowKey);\n                Trace.TraceInformation(debugInfo);\n#endif\n                int idx1 = rowKey.IndexOf(Seperator);\n                int idx2 = rowKey.LastIndexOf(Seperator);\n#if DEBUG\n                debugInfo = string.Format(\"UnpackRowKey: RowKey={0} Idx1={1} Idx2={2}\", rowKey, idx1, idx2);\n#endif\n                ReadOnlySpan<char> rowKeySpan = rowKey.AsSpan();\n                ReadOnlySpan<char> addressStr = rowKeySpan[..idx1];\n                ReadOnlySpan<char> portStr = rowKeySpan.Slice(idx1 + 1, idx2 - idx1 - 1);\n                ReadOnlySpan<char> genStr = rowKeySpan[(idx2 + 1)..];\n#if DEBUG\n                debugInfo = string.Format(\"UnpackRowKey: RowKey={0} -> Address={1} Port={2} Generation={3}\",\n                    rowKey, addressStr.ToString(), portStr.ToString(), genStr.ToString());\n\n                Trace.TraceInformation(debugInfo);\n#endif\n                IPAddress address = IPAddress.Parse(addressStr);\n                int port = int.Parse(portStr);\n                int generation = int.Parse(genStr);\n                return SiloAddress.New(address, port, generation);\n            }\n            catch (Exception exc)\n            {\n                throw new AggregateException(\"Error from \" + debugInfo, exc);\n            }\n        }\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n            if (RowKey.Equals(TABLE_VERSION_ROW))\n            {\n                sb.Append(\"VersionRow [\").Append(DeploymentId);\n                sb.Append(\" Deployment=\").Append(DeploymentId);\n                sb.Append(\" MembershipVersion=\").Append(MembershipVersion);\n                sb.Append(\"]\");\n            }\n            else\n            {\n                sb.Append(\"OrleansSilo [\");\n                sb.Append(\" Deployment=\").Append(DeploymentId);\n                sb.Append(\" LocalEndpoint=\").Append(Address);\n                sb.Append(\" LocalPort=\").Append(Port);\n                sb.Append(\" Generation=\").Append(Generation);\n\n                sb.Append(\" Host=\").Append(HostName);\n                sb.Append(\" Status=\").Append(Status);\n                sb.Append(\" ProxyPort=\").Append(ProxyPort);\n\n                if (!string.IsNullOrEmpty(RoleName)) sb.Append(\" RoleName=\").Append(RoleName);\n                sb.Append(\" SiloName=\").Append(SiloName);\n                sb.Append(\" UpgradeZone=\").Append(UpdateZone);\n                sb.Append(\" FaultZone=\").Append(FaultZone);\n\n                if (!string.IsNullOrEmpty(SuspectingSilos)) sb.Append(\" SuspectingSilos=\").Append(SuspectingSilos);\n                if (!string.IsNullOrEmpty(SuspectingTimes)) sb.Append(\" SuspectingTimes=\").Append(SuspectingTimes);\n                sb.Append(\" StartTime=\").Append(StartTime);\n                sb.Append(\" IAmAliveTime=\").Append(IAmAliveTime);\n                sb.Append(\"]\");\n            }\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.AzureStorage/Utilities/TableStorageErrorCode.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Clustering.AzureStorage.Utilities\n{\n    [SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n    internal enum TableStorageErrorCode\n    {\n        Runtime = 100000,\n        AzureTableBase = Runtime + 800,\n\n        AzureTable_20 = AzureTableBase + 20,\n        AzureTable_21 = AzureTableBase + 21,\n        AzureTable_22 = AzureTableBase + 22,\n        AzureTable_23 = AzureTableBase + 23,\n        AzureTable_24 = AzureTableBase + 24,\n        AzureTable_25 = AzureTableBase + 25,\n        AzureTable_26 = AzureTableBase + 26,\n\n        AzureTable_32 = AzureTableBase + 32,\n        AzureTable_33 = AzureTableBase + 33,\n\n        AzureTable_60 = AzureTableBase + 60,\n        AzureTable_61 = AzureTableBase + 61,\n\n        AzureTable_65 = AzureTableBase + 65,\n        AzureTable_66 = AzureTableBase + 66,\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringProviderBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Clustering.Cosmos;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AzureCosmosDB\", \"Clustering\", \"Silo\", typeof(CosmosClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"AzureCosmosDB\", \"Clustering\", \"Client\", typeof(CosmosClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class CosmosClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string? name, IConfigurationSection configurationSection) =>\n        builder.UseCosmosClustering(optionsBuilder =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var databaseName = configurationSection[nameof(options.DatabaseName)];\n                if (!string.IsNullOrEmpty(databaseName))\n                {\n                    options.DatabaseName = databaseName;\n                }\n                var containerName = configurationSection[nameof(options.ContainerName)];\n                if (!string.IsNullOrEmpty(containerName))\n                {\n                    options.ContainerName = containerName;\n                }\n                if (bool.TryParse(configurationSection[nameof(options.IsResourceCreationEnabled)], out var irce))\n                {\n                    options.IsResourceCreationEnabled = irce;\n                }\n                if(int.TryParse(configurationSection[nameof(options.DatabaseThroughput)], out var dt))\n                {\n                    options.DatabaseThroughput = dt;\n                }\n                if(bool.TryParse(configurationSection[nameof(options.CleanResourcesOnInitialization)], out var croi))\n                {\n                    options.CleanResourcesOnInitialization = croi;\n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if(!string.IsNullOrEmpty(serviceKey))\n                {\n                    options.ConfigureCosmosClient(sp=>\n                        new ValueTask<CosmosClient>(sp.GetRequiredKeyedService<CosmosClient>(serviceKey)));\n                }\n                else\n                {\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigureCosmosClient(connectionString);\n                    }\n                }\n            }));\n\n    public void Configure(IClientBuilder builder, string? name, IConfigurationSection configurationSection) =>\n        builder.UseCosmosGatewayListProvider(optionsBuilder =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var databaseName = configurationSection[nameof(options.DatabaseName)];\n                if (!string.IsNullOrEmpty(databaseName))\n                {\n                    options.DatabaseName = databaseName;\n                }\n                var containerName = configurationSection[nameof(options.ContainerName)];\n                if (!string.IsNullOrEmpty(containerName))\n                {\n                    options.ContainerName = containerName;\n                }\n                if (bool.TryParse(configurationSection[nameof(options.IsResourceCreationEnabled)], out var irce))\n                {\n                    options.IsResourceCreationEnabled = irce;\n                }\n                if (int.TryParse(configurationSection[nameof(options.DatabaseThroughput)], out var dt))\n                {\n                    options.DatabaseThroughput = dt;\n                }\n                if (bool.TryParse(configurationSection[nameof(options.CleanResourcesOnInitialization)], out var croi))\n                {\n                    options.CleanResourcesOnInitialization = croi;\n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    options.ConfigureCosmosClient(sp =>\n                        new ValueTask<CosmosClient>(sp.GetRequiredKeyedService<CosmosClient>(serviceKey)));\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigureCosmosClient(connectionString);\n                    }\n                }\n            }));\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/HostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Messaging;\nusing Orleans.Clustering.Cosmos;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Extension methods for configuring Azure Cosmos DB clustering.\n/// </summary>\npublic static class HostingExtensions\n{\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static ISiloBuilder UseCosmosClustering(\n        this ISiloBuilder builder,\n        Action<CosmosClusteringOptions> configureOptions)\n    {\n        builder.Services.UseCosmosClustering(configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static ISiloBuilder UseCosmosClustering(\n        this ISiloBuilder builder,\n        Action<OptionsBuilder<CosmosClusteringOptions>> configureOptions)\n    {\n        builder.Services.UseCosmosClustering(configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static ISiloBuilder UseCosmosClustering(this ISiloBuilder builder)\n    {\n        builder.Services.AddOptions<CosmosClusteringOptions>();\n        builder.Services.AddSingleton<IMembershipTable, CosmosMembershipTable>();\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static IClientBuilder UseCosmosGatewayListProvider(\n        this IClientBuilder builder,\n        Action<CosmosClusteringOptions> configureOptions)\n    {\n        builder.Services.UseCosmosGatewayListProvider(configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static IClientBuilder UseCosmosGatewayListProvider(this IClientBuilder builder)\n    {\n        builder.Services.AddOptions<CosmosClusteringOptions>();\n        builder.Services.AddSingleton<IGatewayListProvider, CosmosGatewayListProvider>();\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"builder\"/>.</returns>\n    public static IClientBuilder UseCosmosGatewayListProvider(\n        this IClientBuilder builder,\n        Action<OptionsBuilder<CosmosClusteringOptions>> configureOptions)\n    {\n        builder.Services.UseCosmosGatewayListProvider(configureOptions);\n        return builder;\n    }\n\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"services\"/>.</returns>\n    public static IServiceCollection UseCosmosClustering(\n        this IServiceCollection services,\n        Action<CosmosClusteringOptions> configureOptions)\n    {\n        return services.UseCosmosClustering(ob => ob.Configure(configureOptions));\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"services\"/>.</returns>\n    public static IServiceCollection UseCosmosClustering(\n        this IServiceCollection services,\n        Action<OptionsBuilder<CosmosClusteringOptions>> configureOptions)\n    {\n        configureOptions?.Invoke(services.AddOptions<CosmosClusteringOptions>());\n        return services.AddSingleton<IMembershipTable, CosmosMembershipTable>();\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"services\"/>.</returns>\n    public static IServiceCollection UseCosmosGatewayListProvider(\n        this IServiceCollection services,\n        Action<CosmosClusteringOptions> configureOptions)\n    {\n        return services.UseCosmosGatewayListProvider(ob => ob.Configure(configureOptions));\n    }\n\n    /// <summary>\n    /// Adds clustering backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <returns>The provided <paramref name=\"services\"/>.</returns>\n    public static IServiceCollection UseCosmosGatewayListProvider(\n        this IServiceCollection services,\n        Action<OptionsBuilder<CosmosClusteringOptions>> configureOptions)\n    {\n        configureOptions?.Invoke(services.AddOptions<CosmosClusteringOptions>());\n        services.AddTransient<IConfigurationValidator>(\n            sp => new CosmosOptionsValidator<CosmosClusteringOptions>(\n                sp.GetRequiredService<IOptionsMonitor<CosmosClusteringOptions>>().CurrentValue,\n                nameof(CosmosClusteringOptions)));\n        return services.AddSingleton<IGatewayListProvider, CosmosGatewayListProvider>();\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosGatewayListProvider.cs",
    "content": "using System.Net;\nusing Orleans.Messaging;\nusing Orleans.Clustering.Cosmos.Models;\n\nnamespace Orleans.Clustering.Cosmos;\n\ninternal partial class CosmosGatewayListProvider : IGatewayListProvider\n{\n    private readonly ILogger _logger;\n    private readonly string _clusterId;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly CosmosClusteringOptions _options;\n    private readonly QueryRequestOptions _queryRequestOptions;\n    private Container _container = default!;\n\n    public TimeSpan MaxStaleness { get; }\n\n    public bool IsUpdatable => true;\n\n    public CosmosGatewayListProvider(\n        ILoggerFactory loggerFactory,\n        IServiceProvider serviceProvider,\n        IOptions<CosmosClusteringOptions> options,\n        IOptions<ClusterOptions> clusterOptions,\n        IOptions<GatewayOptions> gatewayOptions\n    )\n    {\n        _logger = loggerFactory.CreateLogger<CosmosGatewayListProvider>();\n        _serviceProvider = serviceProvider;\n        _clusterId = clusterOptions.Value.ClusterId;\n        _options = options.Value;\n        _queryRequestOptions = new QueryRequestOptions { PartitionKey = new(_clusterId) };\n        MaxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n    }\n\n    public async Task InitializeGatewayListProvider()\n    {\n        try\n        {\n            var client = await _options.CreateClient!(_serviceProvider).ConfigureAwait(false);\n            _container = client.GetContainer(_options.DatabaseName, _options.ContainerName);\n        }\n        catch (Exception ex)\n        {\n            LogErrorInitializingGatewayListProvider(ex);\n            throw;\n        }\n    }\n\n    public async Task<IList<Uri>> GetGateways()\n    {\n        try\n        {\n            var query = _container\n                .GetItemLinqQueryable<SiloEntity>(requestOptions: _queryRequestOptions)\n                .Where(g => g.EntityType == nameof(SiloEntity) &&\n                    g.Status == (int)SiloStatus.Active &&\n                    g.ProxyPort.HasValue && g.ProxyPort.Value != 0)\n                .ToFeedIterator();\n\n            var entities = new List<SiloEntity>();\n            do\n            {\n                var items = await query.ReadNextAsync();\n                entities.AddRange(items);\n            } while (query.HasMoreResults);\n\n            var uris = entities.Select(ConvertToGatewayUri).ToArray();\n            return uris;\n        }\n        catch (Exception ex)\n        {\n            LogErrorReadingGatewayListFromCosmosDb(ex);\n            throw;\n        }\n    }\n\n    private static Uri ConvertToGatewayUri(SiloEntity gateway) =>\n        SiloAddress.New(new IPEndPoint(IPAddress.Parse(gateway.Address), gateway.ProxyPort!.Value), gateway.Generation).ToGatewayUri();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error initializing Azure Cosmos DB gateway list provider\"\n    )]\n    private partial void LogErrorInitializingGatewayListProvider(Exception ex);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error reading gateway list from Azure Cosmos DB\"\n    )]\n    private partial void LogErrorReadingGatewayListFromCosmosDb(Exception ex);\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosMembershipTable.cs",
    "content": "using System.Net;\nusing Orleans.Clustering.Cosmos.Models;\n\nnamespace Orleans.Clustering.Cosmos;\n\ninternal partial class CosmosMembershipTable : IMembershipTable\n{\n    private const string PARTITION_KEY = \"/ClusterId\";\n    private const string CLUSTER_VERSION_ID = \"ClusterVersion\";\n    private readonly ILogger _logger;\n    private readonly CosmosClusteringOptions _options;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly string _clusterId;\n    private readonly PartitionKey _partitionKey;\n    private readonly QueryRequestOptions _queryRequestOptions;\n    private CosmosClient _client = default!;\n    private Container _container = default!;\n    private SiloEntity? _self = null;\n\n    public CosmosMembershipTable(\n        ILoggerFactory loggerFactory,\n        IServiceProvider serviceProvider,\n        IOptions<CosmosClusteringOptions> options,\n        IOptions<ClusterOptions> clusterOptions)\n    {\n        _logger = loggerFactory.CreateLogger<CosmosMembershipTable>();\n        _serviceProvider = serviceProvider;\n        _options = options.Value;\n        _clusterId = clusterOptions.Value.ClusterId;\n        _partitionKey = new(_clusterId);\n\n        _queryRequestOptions = new() { PartitionKey = _partitionKey };\n    }\n\n    public async Task InitializeMembershipTable(bool tryInitTableVersion)\n    {\n        await InitializeCosmosClient().ConfigureAwait(false);\n\n        if (_options.IsResourceCreationEnabled)\n        {\n            if (_options.CleanResourcesOnInitialization)\n            {\n                await TryDeleteDatabase().ConfigureAwait(false);\n            }\n\n            await TryCreateCosmosResources().ConfigureAwait(false);\n        }\n\n        _container = _client.GetContainer(_options.DatabaseName, _options.ContainerName);\n\n        ClusterVersionEntity? versionEntity = null;\n\n        try\n        {\n            versionEntity = (await _container.ReadItemAsync<ClusterVersionEntity>(CLUSTER_VERSION_ID, _partitionKey).ConfigureAwait(false)).Resource;\n        }\n        catch (CosmosException ce) when (ce.StatusCode == HttpStatusCode.NotFound)\n        {\n            if (versionEntity is null)\n            {\n                versionEntity = new ClusterVersionEntity\n                {\n                    ClusterId = _clusterId,\n                    ClusterVersion = 0,\n                    Id = CLUSTER_VERSION_ID\n                };\n\n                var response = await _container.CreateItemAsync(versionEntity, _partitionKey).ConfigureAwait(false);\n\n                if (response.StatusCode == HttpStatusCode.Created)\n                {\n                    LogDebugCreatedNewClusterVersionEntity();\n                }\n            }\n        }\n    }\n\n    public async Task DeleteMembershipTableEntries(string clusterId)\n    {\n        try\n        {\n            var silos = await ReadSilos().ConfigureAwait(false);\n\n            var batch = _container.CreateTransactionalBatch(_partitionKey);\n\n            foreach (var silo in silos)\n            {\n                batch = batch.DeleteItem(silo.Id);\n            }\n\n            batch = batch.DeleteItem(CLUSTER_VERSION_ID);\n\n            await batch.ExecuteAsync().ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            LogErrorDeletingMembershipTableEntries(ex);\n            WrappedException.CreateAndRethrow(ex);\n        }\n    }\n\n    public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n    {\n        try\n        {\n            var silos = (await ReadSilos(SiloStatus.Dead).ConfigureAwait(false)).Where(s => s.IAmAliveTime < beforeDate).ToList();\n            if (silos.Count == 0)\n            {\n                return;\n            }\n\n            var batch = _container.CreateTransactionalBatch(_partitionKey);\n\n            foreach (var silo in silos)\n            {\n                batch = batch.DeleteItem(silo.Id);\n            }\n\n            await batch.ExecuteAsync().ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            LogErrorCleaningUpDefunctSiloEntries(ex);\n            WrappedException.CreateAndRethrow(ex);\n        }\n    }\n\n    public async Task<MembershipTableData> ReadRow(SiloAddress key)\n    {\n        var id = ConstructSiloEntityId(key);\n\n        try\n        {\n            var readClusterVersionTask = ReadClusterVersion();\n            var readSiloTask = _container.ReadItemAsync<SiloEntity>(id, _partitionKey);\n\n            await Task.WhenAll(readClusterVersionTask, readSiloTask).ConfigureAwait(false);\n\n            var clusterVersion = await readClusterVersionTask;\n            var silo = await readSiloTask;\n\n            TableVersion? version = null;\n            if (clusterVersion is not null)\n            {\n                version = new TableVersion(clusterVersion.ClusterVersion, clusterVersion.ETag);\n            }\n            else\n            {\n                LogErrorClusterVersionEntityDoesNotExist();\n            }\n\n            var memEntries = new List<Tuple<MembershipEntry, string>>\n            {\n                Tuple.Create(ParseEntity(silo.Resource), silo.Resource.ETag)\n            };\n\n            return new MembershipTableData(memEntries, version);\n        }\n        catch (Exception exc)\n        {\n            LogWarningFailureReadingSiloEntry(exc, key, _clusterId);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<MembershipTableData> ReadAll()\n    {\n        try\n        {\n            var readClusterVersionTask = ReadClusterVersion();\n            var readSilosTask = ReadSilos();\n\n            await Task.WhenAll(readClusterVersionTask, readSilosTask).ConfigureAwait(false);\n\n            var clusterVersion = await readClusterVersionTask;\n            var silos = await readSilosTask;\n\n            TableVersion? version = null;\n            if (clusterVersion is not null)\n            {\n                version = new TableVersion(clusterVersion.ClusterVersion, clusterVersion.ETag);\n            }\n            else\n            {\n                LogErrorClusterVersionEntityDoesNotExist();\n            }\n\n            var memEntries = new List<Tuple<MembershipEntry, string>>();\n            foreach (var entity in silos)\n            {\n                try\n                {\n                    var membershipEntry = ParseEntity(entity);\n                    memEntries.Add(new Tuple<MembershipEntry, string>(membershipEntry, entity.ETag));\n                }\n                catch (Exception exc)\n                {\n                    LogErrorReadingAllMembershipRecords(exc);\n                    WrappedException.CreateAndRethrow(exc);\n                    throw;\n                }\n            }\n\n            return new MembershipTableData(memEntries, version);\n        }\n        catch (Exception exc)\n        {\n            LogWarningReadingEntries(exc, _clusterId);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n    {\n        try\n        {\n            var siloEntity = ConvertToEntity(entry, _clusterId);\n            var versionEntity = BuildVersionEntity(tableVersion);\n\n            var response = await _container.CreateTransactionalBatch(_partitionKey)\n                .ReplaceItem(versionEntity.Id, versionEntity, new TransactionalBatchItemRequestOptions { IfMatchEtag = tableVersion.VersionEtag })\n                .CreateItem(siloEntity)\n                .ExecuteAsync().ConfigureAwait(false);\n\n            return response.IsSuccessStatusCode;\n        }\n        catch (CosmosException exc)\n        {\n            if (exc.StatusCode == HttpStatusCode.PreconditionFailed) return false;\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n    {\n        try\n        {\n            var siloEntity = ConvertToEntity(entry, _clusterId);\n            siloEntity.ETag = etag;\n\n            var versionEntity = BuildVersionEntity(tableVersion);\n\n            var response = await _container.CreateTransactionalBatch(_partitionKey)\n                .ReplaceItem(versionEntity.Id, versionEntity, new TransactionalBatchItemRequestOptions { IfMatchEtag = tableVersion.VersionEtag })\n                .ReplaceItem(siloEntity.Id, siloEntity, new TransactionalBatchItemRequestOptions { IfMatchEtag = siloEntity.ETag })\n                .ExecuteAsync().ConfigureAwait(false);\n\n            return response.IsSuccessStatusCode;\n        }\n        catch (CosmosException exc)\n        {\n            if (exc.StatusCode == HttpStatusCode.PreconditionFailed) return false;\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task UpdateIAmAlive(MembershipEntry entry)\n    {\n        var siloEntityId = ConstructSiloEntityId(entry.SiloAddress);\n\n        if (_self is not { } selfRow)\n        {\n            var response = await _container.ReadItemAsync<SiloEntity>(siloEntityId, _partitionKey).ConfigureAwait(false);\n\n            if (response.StatusCode != HttpStatusCode.OK)\n            {\n                LogWarningUnableToQueryEntry(new(entry));\n                throw new OrleansException($\"Unable to query for SiloEntity {entry.ToFullString()}\");\n            }\n\n            _self = selfRow = response.Resource;\n        }\n\n        selfRow.IAmAliveTime = entry.IAmAliveTime;\n\n        try\n        {\n            var replaceResponse = await _container.ReplaceItemAsync(\n                selfRow,\n                siloEntityId,\n                _partitionKey,\n                new ItemRequestOptions { IfMatchEtag = selfRow.ETag }).ConfigureAwait(false);\n            _self = replaceResponse.Resource;\n        }\n        catch (Exception exc)\n        {\n            _self = null;\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    private async Task InitializeCosmosClient()\n    {\n        try\n        {\n            _client = await _options.CreateClient!(_serviceProvider).ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            LogErrorInitializingCosmosClient(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task TryDeleteDatabase()\n    {\n        try\n        {\n            await _client.GetDatabase(_options.DatabaseName).DeleteAsync().ConfigureAwait(false);\n        }\n        catch (CosmosException dce) when (dce.StatusCode == HttpStatusCode.NotFound)\n        {\n            return;\n        }\n        catch (Exception ex)\n        {\n            LogErrorDeletingCosmosDBDatabase(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task TryCreateCosmosResources()\n    {\n        var dbResponse = await _client.CreateDatabaseIfNotExistsAsync(_options.DatabaseName, _options.DatabaseThroughput).ConfigureAwait(false);\n        var db = dbResponse.Database;\n\n        var containerProperties = new ContainerProperties(_options.ContainerName, PARTITION_KEY);\n        containerProperties.IndexingPolicy.IndexingMode = IndexingMode.Consistent;\n        containerProperties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = \"/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/Address/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/Port/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/Generation/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/Hostname/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/SiloName/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/\\\"SuspectingSilos\\\"/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/\\\"SuspectingTimes\\\"/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/StartTime/*\" });\n        containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/IAmAliveTime/*\" });\n\n        const int maxRetries = 3;\n        for (var retry = 0; retry <= maxRetries; ++retry)\n        {\n            var containerResponse = await db.CreateContainerIfNotExistsAsync(\n                containerProperties,\n                _options.ContainerThroughputProperties).ConfigureAwait(false);\n\n            if (retry == maxRetries || dbResponse.StatusCode != HttpStatusCode.Created || containerResponse.StatusCode == HttpStatusCode.Created)\n            {\n                break;  // Apparently some throttling logic returns HttpStatusCode.OK (not 429) when the collection wasn't created in a new DB.\n            }\n            await Task.Delay(1000);\n        }\n    }\n\n    private async Task<ClusterVersionEntity?> ReadClusterVersion()\n    {\n        try\n        {\n            var response = await _container.ReadItemAsync<ClusterVersionEntity>(\n                CLUSTER_VERSION_ID,\n                _partitionKey).ConfigureAwait(false);\n\n            return response.StatusCode == HttpStatusCode.OK\n                ? response.Resource\n                : response.StatusCode == HttpStatusCode.NotFound\n                    ? null\n                    : throw new Exception($\"Error reading Cluster Version entity. Status code: {response.StatusCode}\");\n        }\n        catch (Exception ex)\n        {\n            LogErrorReadingClusterVersionEntity(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task<IReadOnlyList<SiloEntity>> ReadSilos(SiloStatus? status = null)\n    {\n        try\n        {\n            var query = _container\n                .GetItemLinqQueryable<SiloEntity>(requestOptions: _queryRequestOptions)\n                .Where(g => g.EntityType == nameof(SiloEntity));\n\n            if (status is not null)\n            {\n                query = query.Where(g => (SiloStatus)g.Status == status);\n            }\n\n            var iterator = query.ToFeedIterator();\n\n            var silos = new List<SiloEntity>();\n            do\n            {\n                var items = await iterator.ReadNextAsync().ConfigureAwait(false);\n                silos.AddRange(items);\n            } while (iterator.HasMoreResults);\n\n            return silos;\n        }\n        catch (Exception exc)\n        {\n            LogErrorReadingSiloEntities(exc);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    private static string ConstructSiloEntityId(SiloAddress silo) => $\"{silo.Endpoint.Address}-{silo.Endpoint.Port}-{silo.Generation}\";\n\n    private static MembershipEntry ParseEntity(SiloEntity entity)\n    {\n        var entry = new MembershipEntry\n        {\n            HostName = entity.Hostname,\n            Status = (SiloStatus)entity.Status\n        };\n\n        if (entity.ProxyPort.HasValue)\n            entry.ProxyPort = entity.ProxyPort.Value;\n\n        entry.SiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Parse(entity.Address), entity.Port), entity.Generation);\n\n        entry.SiloName = entity.SiloName;\n\n        entry.StartTime = entity.StartTime.UtcDateTime;\n\n        entry.IAmAliveTime = entity.IAmAliveTime.UtcDateTime;\n\n        var suspectingSilos = new List<SiloAddress>();\n        var suspectingTimes = new List<DateTime>();\n\n        foreach (var silo in entity.SuspectingSilos)\n        {\n            suspectingSilos.Add(SiloAddress.FromParsableString(silo));\n        }\n\n        foreach (var time in entity.SuspectingTimes)\n        {\n            suspectingTimes.Add(LogFormatter.ParseDate(time));\n        }\n\n        if (suspectingSilos.Count != suspectingTimes.Count)\n        {\n            throw new OrleansException($\"SuspectingSilos.Length of {suspectingSilos.Count} as read from Azure Cosmos DB is not equal to SuspectingTimes.Length of {suspectingTimes.Count}\");\n        }\n\n        for (var i = 0; i < suspectingSilos.Count; i++)\n        {\n            entry.AddSuspector(suspectingSilos[i], suspectingTimes[i]);\n        }\n\n        return entry;\n    }\n\n    private static SiloEntity ConvertToEntity(MembershipEntry memEntry, string clusterId)\n    {\n        var tableEntry = new SiloEntity\n        {\n            Id = ConstructSiloEntityId(memEntry.SiloAddress),\n            ClusterId = clusterId,\n            Address = memEntry.SiloAddress.Endpoint.Address.ToString(),\n            Port = memEntry.SiloAddress.Endpoint.Port,\n            Generation = memEntry.SiloAddress.Generation,\n            Hostname = memEntry.HostName,\n            Status = (int)memEntry.Status,\n            ProxyPort = memEntry.ProxyPort,\n            SiloName = memEntry.SiloName,\n            StartTime = memEntry.StartTime,\n            IAmAliveTime = memEntry.IAmAliveTime\n        };\n\n        if (memEntry.SuspectTimes != null)\n        {\n            foreach (var tuple in memEntry.SuspectTimes)\n            {\n                tableEntry.SuspectingSilos.Add(tuple.Item1.ToParsableString());\n                tableEntry.SuspectingTimes.Add(LogFormatter.PrintDate(tuple.Item2));\n            }\n        }\n\n        return tableEntry;\n    }\n\n    private ClusterVersionEntity BuildVersionEntity(TableVersion tableVersion)\n    {\n        return new ClusterVersionEntity\n        {\n            ClusterId = _clusterId,\n            ClusterVersion = tableVersion.Version,\n            Id = CLUSTER_VERSION_ID,\n            ETag = tableVersion.VersionEtag\n        };\n    }\n\n    private readonly struct MembershipEntryLogValue(MembershipEntry membershipEntry)\n    {\n        public override string ToString() => membershipEntry.ToFullString();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Created new Cluster Version entity.\"\n    )]\n    private partial void LogDebugCreatedNewClusterVersionEntity();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error deleting membership table entries.\"\n    )]\n    private partial void LogErrorDeletingMembershipTableEntries(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error cleaning up defunct silo entries.\"\n    )]\n    private partial void LogErrorCleaningUpDefunctSiloEntries(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failure reading silo entry {Key} for cluster {Cluster}\"\n    )]\n    private partial void LogWarningFailureReadingSiloEntry(Exception exception, SiloAddress key, string cluster);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Initial ClusterVersionEntity entity does not exist.\"\n    )]\n    private partial void LogErrorClusterVersionEntityDoesNotExist();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure reading all membership records.\"\n    )]\n    private partial void LogErrorReadingAllMembershipRecords(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failure reading entries for cluster {Cluster}\"\n    )]\n    private partial void LogWarningReadingEntries(Exception exception, string cluster);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error initializing Azure Cosmos DB Client for membership table provider.\"\n    )]\n    private partial void LogErrorInitializingCosmosClient(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error deleting Azure Cosmos DB database.\"\n    )]\n    private partial void LogErrorDeletingCosmosDBDatabase(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error reading Cluster Version entity.\"\n    )]\n    private partial void LogErrorReadingClusterVersionEntity(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error reading Silo entities.\"\n    )]\n    private partial void LogErrorReadingSiloEntities(Exception exception);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.MembershipBase,\n        Level = LogLevel.Warning,\n        Message = \"Unable to query entry {Entry}\"\n    )]\n    private partial void LogWarningUnableToQueryEntry(MembershipEntryLogValue entry);\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Models/BaseClusterEntity.cs",
    "content": "using Newtonsoft.Json;\n\nnamespace Orleans.Clustering.Cosmos;\n\ninternal abstract class BaseClusterEntity : BaseEntity\n{\n    [JsonProperty(nameof(ClusterId))]\n    [JsonPropertyName(nameof(ClusterId))]\n    public string ClusterId { get; set; } = default!;\n\n    [JsonProperty(nameof(EntityType))]\n    [JsonPropertyName(nameof(EntityType))]\n    public abstract string EntityType { get; }\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Models/ClusterVersionEntity.cs",
    "content": "using Newtonsoft.Json;\n\nnamespace Orleans.Clustering.Cosmos;\n\ninternal class ClusterVersionEntity : BaseClusterEntity\n{\n    public override string EntityType => nameof(ClusterVersionEntity);\n\n    [JsonProperty(nameof(ClusterVersion))]\n    [JsonPropertyName(nameof(ClusterVersion))]\n    public int ClusterVersion { get; set; } = 0;\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Models/SiloEntity.cs",
    "content": "using Newtonsoft.Json;\n\nnamespace Orleans.Clustering.Cosmos.Models;\n\ninternal class SiloEntity : BaseClusterEntity\n{\n    public override string EntityType => nameof(SiloEntity);\n\n    [JsonProperty(nameof(Address))]\n    [JsonPropertyName(nameof(Address))]\n    public string Address { get; set; } = default!;\n\n    [JsonProperty(nameof(Port))]\n    [JsonPropertyName(nameof(Port))]\n    public int Port { get; set; }\n\n    [JsonProperty(nameof(Generation))]\n    [JsonPropertyName(nameof(Generation))]\n    public int Generation { get; set; }\n\n    [JsonProperty(nameof(Hostname))]\n    [JsonPropertyName(nameof(Hostname))]\n    public string Hostname { get; set; } = default!;\n\n    [JsonProperty(nameof(Status))]\n    [JsonPropertyName(nameof(Status))]\n    public int Status { get; set; }\n\n    [JsonProperty(nameof(ProxyPort))]\n    [JsonPropertyName(nameof(ProxyPort))]\n    public int? ProxyPort { get; set; }\n\n    [JsonProperty(nameof(SiloName))]\n    [JsonPropertyName(nameof(SiloName))]\n    public string SiloName { get; set; } = default!;\n\n    [JsonProperty(nameof(SuspectingSilos))]\n    [JsonPropertyName(nameof(SuspectingSilos))]\n    public List<string> SuspectingSilos { get; set; } = new();\n\n    [JsonProperty(nameof(SuspectingTimes))]\n    [JsonPropertyName(nameof(SuspectingTimes))]\n    public List<string> SuspectingTimes { get; set; } = new();\n\n    [JsonProperty(nameof(StartTime))]\n    [JsonPropertyName(nameof(StartTime))]\n    public DateTimeOffset StartTime { get; set; }\n\n    [JsonProperty(nameof(IAmAliveTime))]\n    [JsonPropertyName(nameof(IAmAliveTime))]\n    public DateTimeOffset IAmAliveTime { get; set; }\n\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Options/CosmosClusteringOptions.cs",
    "content": "namespace Orleans.Clustering.Cosmos;\n\n/// <summary>\n/// Options for configuring Azure Cosmos DB clustering.\n/// </summary>\npublic class CosmosClusteringOptions : CosmosOptions\n{\n    private const string ORLEANS_CLUSTER_CONTAINER = \"OrleansCluster\";\n\n    /// <summary>\n    /// Initializes a new <see cref=\"CosmosClusteringOptions\"/> instance.\n    /// </summary>\n    public CosmosClusteringOptions()\n    {\n        ContainerName = ORLEANS_CLUSTER_CONTAINER;\n    }\n}\n\n/// <summary>\n/// Configuration validator for <see cref=\"CosmosClusteringOptions\"/>.\n/// </summary>\npublic class CosmosClusteringOptionsValidator : CosmosOptionsValidator<CosmosClusteringOptions>\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CosmosClusteringOptionsValidator\"/> class.\n    /// </summary>\n    /// <param name=\"options\">The option to be validated.</param>\n    /// <param name=\"name\">The option name to be validated.</param>\n    public CosmosClusteringOptionsValidator(CosmosClusteringOptions options, string name) : base(options, name)\n    {\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/Orleans.Clustering.Cosmos.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.Cosmos</PackageId>\n    <Title>Microsoft Orleans clustering provider for Azure Cosmos DB</Title>\n    <Description>Microsoft Orleans clustering provider backed by Azure Cosmos DB</Description>\n    <PackageTags>$(PackageTags) Azure Cosmos DB</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Clustering.Cosmos</AssemblyName>\n    <RootNamespace>Orleans.Clustering.Cosmos</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_CLUSTERING</DefineConstants>\n    <Nullable>enable</Nullable>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptions.cs\" Link=\"Storage\\CosmosOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptionsValidator.cs\" Link=\"Storage\\CosmosOptionsValidator.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\BaseEntity.cs\" Link=\"Storage\\BaseEntity.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\Usings.cs\" Link=\"Storage\\Usings.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosIdSanitizer.cs\" Link=\"Storage\\CosmosIdSanitizer.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Microsoft.Azure.Cosmos\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Include=\"System.Runtime.CompilerServices.InternalsVisibleToAttribute\">\n      <_Parameter1>Orleans.Cosmos.Tests</_Parameter1>\n    </AssemblyAttribute>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Azure/Orleans.Clustering.Cosmos/README.md",
    "content": "# Microsoft Orleans Clustering for Azure Cosmos DB\n\n## Introduction\nMicrosoft Orleans Clustering for Azure Cosmos DB provides cluster membership functionality for Microsoft Orleans using Azure Cosmos DB. This allows Orleans silos to coordinate and form a cluster using Azure Cosmos DB as the backing store.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Clustering.Cosmos\n```\n\n## Example - Configuring Azure Cosmos DB Membership\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseCosmosClustering(options =>\n            {\n                options.AccountEndpoint = \"https://YOUR_COSMOS_ENDPOINT\";\n                options.AccountKey = \"YOUR_COSMOS_KEY\";\n                options.DB = \"YOUR_DATABASE_NAME\";\n                options.CanCreateResources = true;\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Configuration Guide](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/)\n- [Orleans Clustering](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/AzureStorageJobShard.Log.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.DurableJobs.AzureStorage;\n\ninternal sealed partial class AzureStorageJobShard\n{\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Initializing shard '{ShardId}' from Azure Storage blob\"\n    )]\n    private static partial void LogInitializingShard(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Shard '{ShardId}' initialized successfully. Loaded {JobCount} job(s) in {ElapsedMilliseconds}ms\"\n    )]\n    private static partial void LogShardInitialized(ILogger logger, string shardId, int jobCount, long elapsedMilliseconds);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Adding job '{JobId}' (Name: '{JobName}') to shard '{ShardId}' with due time {DueTime}\"\n    )]\n    private static partial void LogAddingJob(ILogger logger, string jobId, string jobName, string shardId, DateTimeOffset dueTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Removing job '{JobId}' from shard '{ShardId}'\"\n    )]\n    private static partial void LogRemovingJob(ILogger logger, string jobId, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Retrying job '{JobId}' in shard '{ShardId}' with new due time {NewDueTime}\"\n    )]\n    private static partial void LogRetryingJob(ILogger logger, string jobId, string shardId, DateTimeOffset newDueTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Flushing batch of {OperationCount} job operation(s) to shard '{ShardId}'\"\n    )]\n    private static partial void LogFlushingBatch(ILogger logger, int operationCount, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Batch of {OperationCount} job operation(s) written to shard '{ShardId}' in {ElapsedMilliseconds}ms. Total committed blocks: {CommittedBlockCount}\"\n    )]\n    private static partial void LogBatchWritten(ILogger logger, int operationCount, string shardId, long elapsedMilliseconds, int committedBlockCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Updating metadata for shard '{ShardId}'\"\n    )]\n    private static partial void LogUpdatingMetadata(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Metadata updated for shard '{ShardId}'\"\n    )]\n    private static partial void LogMetadataUpdated(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Shard '{ShardId}' has {CommittedBlockCount} committed blocks, approaching Azure Blob append limit of 50,000\"\n    )]\n    private static partial void LogApproachingBlockLimit(ILogger logger, string shardId, int committedBlockCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Large batch detected for shard '{ShardId}': {OperationCount} operations (max configured: {MaxBatchSize})\"\n    )]\n    private static partial void LogLargeBatch(ILogger logger, string shardId, int operationCount, int maxBatchSize);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error writing batch of {OperationCount} operation(s) to shard '{ShardId}'\"\n    )]\n    private static partial void LogErrorWritingBatch(ILogger logger, Exception exception, int operationCount, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error updating metadata for shard '{ShardId}'\"\n    )]\n    private static partial void LogErrorUpdatingMetadata(ILogger logger, Exception exception, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Stopping storage processor for shard '{ShardId}'\"\n    )]\n    private static partial void LogStoppingProcessor(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Storage processor stopped for shard '{ShardId}'\"\n    )]\n    private static partial void LogProcessorStopped(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Processing storage operation queue for shard '{ShardId}'\"\n    )]\n    private static partial void LogProcessingStorageQueue(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Waiting for additional operations to batch (current size: {CurrentSize}, min size: {MinSize}) for shard '{ShardId}'\"\n    )]\n    private static partial void LogWaitingForBatch(ILogger logger, int currentSize, int minSize, string shardId);\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/AzureStorageJobShard.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing System.Transactions;\nusing Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Models;\nusing Azure.Storage.Blobs.Specialized;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Buffers.Adaptors;\n\nnamespace Orleans.DurableJobs.AzureStorage;\n\ninternal sealed partial class AzureStorageJobShard : JobShard\n{\n    private readonly Channel<StorageOperation> _storageOperationChannel;\n    private readonly Task _storageProcessorTask;\n    private readonly CancellationTokenSource _shutdownCts = new();\n    private readonly AzureStorageJobShardOptions _options;\n    private readonly ILogger<AzureStorageJobShard> _logger;\n\n    internal AppendBlobClient BlobClient { get; init; }\n    internal ETag? ETag { get; private set; }\n    internal int CommitedBlockCount { get; private set; }\n\n    public AzureStorageJobShard(string id, DateTimeOffset startTime, DateTimeOffset endTime, AppendBlobClient blobClient, IDictionary<string, string>? metadata, ETag? eTag, AzureStorageJobShardOptions options, ILogger<AzureStorageJobShard> logger)\n        : base(id, startTime, endTime)\n    {\n        BlobClient = blobClient;\n        ETag = eTag;\n        Metadata = metadata;\n        _options = options;\n        _logger = logger;\n        \n        // Create unbounded channel for storage operations\n        _storageOperationChannel = Channel.CreateUnbounded<StorageOperation>(new UnboundedChannelOptions\n        {\n            SingleReader = true,\n            SingleWriter = false\n        });\n        \n        // Start the background task that processes storage operations\n        _storageProcessorTask = ProcessStorageOperationsAsync();\n    }\n\n    protected override async Task PersistAddJobAsync(string jobId, string jobName, DateTimeOffset dueTime, GrainId target, IReadOnlyDictionary<string, string>? metadata, CancellationToken cancellationToken)\n    {\n        LogAddingJob(_logger, jobId, jobName, Id, dueTime);\n        var operation = JobOperation.CreateAddOperation(jobId, jobName, dueTime, target, metadata);\n        await EnqueueStorageOperationAsync(StorageOperation.CreateAppendOperation(operation), cancellationToken);\n    }\n\n    protected override async Task PersistRemoveJobAsync(string jobId, CancellationToken cancellationToken)\n    {\n        LogRemovingJob(_logger, jobId, Id);\n        var operation = JobOperation.CreateRemoveOperation(jobId);\n        await EnqueueStorageOperationAsync(StorageOperation.CreateAppendOperation(operation), cancellationToken);\n    }\n\n    protected override async Task PersistRetryJobAsync(string jobId, DateTimeOffset newDueTime, CancellationToken cancellationToken)\n    {\n        LogRetryingJob(_logger, jobId, Id, newDueTime);\n        var operation = JobOperation.CreateRetryOperation(jobId, newDueTime);\n        await EnqueueStorageOperationAsync(StorageOperation.CreateAppendOperation(operation), cancellationToken);\n    }\n\n    public async Task UpdateBlobMetadata(IDictionary<string, string> metadata, CancellationToken cancellationToken)\n    {\n        LogUpdatingMetadata(_logger, Id);\n        await EnqueueStorageOperationAsync(StorageOperation.CreateMetadataOperation(metadata), cancellationToken);\n    }\n\n    public async ValueTask InitializeAsync(CancellationToken cancellationToken)\n    {\n        LogInitializingShard(_logger, Id);\n        var sw = Stopwatch.StartNew();\n        \n        // Load existing blob\n        var response = await BlobClient.DownloadAsync(cancellationToken: cancellationToken);\n        using var stream = response.Value.Content;\n\n        // Rebuild state by replaying operations\n        var addedJobs = new Dictionary<string, JobOperation>();\n        var deletedJobs = new HashSet<string>();\n        var jobRetryCounters = new Dictionary<string, (int dequeueCount, DateTimeOffset? newDueTime)>();\n\n        await foreach (var operation in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, cancellationToken))\n        {\n            switch (operation.Type)\n            {\n                case JobOperation.OperationType.Add:\n                    if (!deletedJobs.Contains(operation.Id))\n                    {\n                        addedJobs[operation.Id] = operation;\n                    }\n                    break;\n                case JobOperation.OperationType.Remove:\n                    deletedJobs.Add(operation.Id);\n                    addedJobs.Remove(operation.Id);\n                    jobRetryCounters.Remove(operation.Id);\n                    break;\n                case JobOperation.OperationType.Retry:\n                    if (!deletedJobs.Contains(operation.Id))\n                    {\n                        if (!jobRetryCounters.ContainsKey(operation.Id))\n                        {\n                            jobRetryCounters[operation.Id] = (1, operation.DueTime);\n                        }\n                        else\n                        {\n                            var entry = jobRetryCounters[operation.Id];\n                            jobRetryCounters[operation.Id] = (entry.dequeueCount + 1, operation.DueTime);\n                        }\n                    }\n                    break;\n            }\n        }\n\n        // Rebuild the priority queue\n        foreach (var op in addedJobs.Values)\n        {\n            var retryCounter = 0;\n            var dueTime = op.DueTime!.Value;\n            if (jobRetryCounters.TryGetValue(op.Id, out var retryEntries))\n            {\n                retryCounter = retryEntries.dequeueCount;\n                dueTime = retryEntries.newDueTime ?? dueTime;\n            }\n\n            EnqueueJob(new DurableJob\n            {\n                Id = op.Id,\n                Name = op.Name!,\n                DueTime = dueTime,\n                TargetGrainId = op.TargetGrainId!.Value,\n                ShardId = Id,\n                Metadata = op.Metadata,\n            },\n            retryCounter);\n        }\n\n        ETag = response.Value.Details.ETag;\n        \n        sw.Stop();\n        LogShardInitialized(_logger, Id, addedJobs.Count, sw.ElapsedMilliseconds);\n    }\n\n    private async Task EnqueueStorageOperationAsync(StorageOperation operation, CancellationToken cancellationToken)\n    {\n        await _storageOperationChannel.Writer.WriteAsync(operation, cancellationToken);\n        await operation.CompletionSource.Task;\n    }\n\n    private async Task ProcessStorageOperationsAsync()\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding);\n\n        var cancellationToken = _shutdownCts.Token;\n        // TODO: AppendBlob has a limit of 50,000 blocks. Implement blob rotation when this limit is approached.\n        var batchOperations = new List<StorageOperation>(_options.MaxBatchSize);\n        \n        try\n        {\n            while (await _storageOperationChannel.Reader.WaitToReadAsync(cancellationToken))\n            {\n                // Read first operation\n                if (!_storageOperationChannel.Reader.TryRead(out var firstOperation))\n                {\n                    continue;\n                }\n\n                // Handle metadata operations immediately (cannot be batched)\n                if (firstOperation.Type is StorageOperationType.UpdateMetadata)\n                {\n                    try\n                    {\n                        await UpdateMetadataAsync(firstOperation.Metadata!, cancellationToken);\n                        LogMetadataUpdated(_logger, Id);\n                        firstOperation.CompletionSource.TrySetResult();\n                    }\n                    catch (Exception ex)\n                    {\n                        LogErrorUpdatingMetadata(_logger, ex, Id);\n                        firstOperation.CompletionSource?.TrySetException(ex);\n                    }\n                    continue;\n                }\n\n                // Collect job operations for batching\n                batchOperations.Add(firstOperation);\n\n                // Try to collect more operations up to the maximum batch size\n                if (TryCollectJobOperationsForBatch(batchOperations))\n                {\n                    // Not enough operations to meet the minimum batch size, wait for more or timeout\n                    if (batchOperations.Count < _options.MinBatchSize)\n                    {\n                        LogWaitingForBatch(_logger, batchOperations.Count, _options.MinBatchSize, Id);\n                    }\n                    await Task.Delay(_options.BatchFlushInterval, cancellationToken);\n                    TryCollectJobOperationsForBatch(batchOperations);\n                }\n\n                // Process the batch of job operations\n                if (batchOperations.Count > 0)\n                {\n                    try\n                    {\n                        LogFlushingBatch(_logger, batchOperations.Count, Id);\n                        await AppendJobOperationBatchAsync(batchOperations, cancellationToken);\n\n                        // Mark all operations as completed\n                        foreach (var op in batchOperations)\n                        {\n                            op.CompletionSource.TrySetResult();\n                        }\n                    }\n                    catch (Exception ex)\n                    {\n                        LogErrorWritingBatch(_logger, ex, batchOperations.Count, Id);\n                        \n                        // Mark all operations as failed\n                        foreach (var op in batchOperations)\n                        {\n                            op.CompletionSource?.TrySetException(ex);\n                        }\n                    }\n                    finally\n                    {\n                        batchOperations.Clear();\n                    }\n                }\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            // Ignore\n        }\n        finally\n        {\n            // Expected during shutdown - cancel all pending operations\n            while (_storageOperationChannel.Reader.TryRead(out var operation))\n            {\n                operation.CompletionSource?.TrySetCanceled(cancellationToken);\n            }\n        }\n\n        // Local function to collect job operations for batching. Returns true if more operations can be collected.\n        bool TryCollectJobOperationsForBatch(List<StorageOperation> batchOperations)\n        {\n            // Collect more jobs, up to a maximum batch size\n            while (batchOperations.Count < _options.MaxBatchSize && _storageOperationChannel.Reader.TryPeek(out var nextOperation))\n            {\n                if (nextOperation.Type is StorageOperationType.UpdateMetadata)\n                {\n                    // Stop batching if we encounter a metadata operation\n                    return false;\n                }\n                _storageOperationChannel.Reader.TryRead(out var operation);\n                Debug.Assert(operation != null);\n                batchOperations.Add(operation!);\n            }\n            return batchOperations.Count != _options.MaxBatchSize;\n        }\n    }\n\n    private async Task AppendJobOperationBatchAsync(List<StorageOperation> operations, CancellationToken cancellationToken)\n    {\n        var sw = Stopwatch.StartNew();\n        using var stream = PooledBufferStream.Rent();\n        try\n        {\n            stream.Position = 0; // TODO Remove that once PooledBufferStream fixed\n            \n            // Encode all job operations into a single stream\n            foreach (var operation in operations)\n            {\n                NetstringJsonSerializer<JobOperation>.Encode(operation.JobOperation!.Value, stream, JobOperationJsonContext.Default.JobOperation);\n            }\n            stream.Position = 0;\n            var result = await BlobClient.AppendBlockAsync(\n                stream,\n                new AppendBlobAppendBlockOptions { Conditions = new AppendBlobRequestConditions { IfMatch = ETag } },\n                cancellationToken);\n            ETag = result.Value.ETag;\n            CommitedBlockCount = result.Value.BlobCommittedBlockCount;\n            \n            sw.Stop();\n            LogBatchWritten(_logger, operations.Count, Id, sw.ElapsedMilliseconds, CommitedBlockCount);\n            \n            // Warn if approaching the 50,000 block limit (warn at 80%)\n            if (CommitedBlockCount > 40000)\n            {\n                LogApproachingBlockLimit(_logger, Id, CommitedBlockCount);\n            }\n            \n            // Warn if batch is unusually large\n            if (operations.Count > _options.MaxBatchSize * 0.8)\n            {\n                LogLargeBatch(_logger, Id, operations.Count, _options.MaxBatchSize);\n            }\n        }\n        finally\n        {\n            PooledBufferStream.Return(stream);\n        }\n    }\n\n    private async Task UpdateMetadataAsync(IDictionary<string, string> metadata, CancellationToken cancellationToken)\n    {\n        var result = await BlobClient.SetMetadataAsync(\n            metadata,\n            new BlobRequestConditions { IfMatch = ETag },\n            cancellationToken);\n        ETag = result.Value.ETag;\n        Metadata = metadata;\n    }\n\n    /// <summary>\n    /// Stops the background storage processor and waits for all pending operations to complete.\n    /// After calling this method, no new storage operations can be enqueued.\n    /// This method is idempotent and can be called multiple times safely.\n    /// </summary>\n    internal async Task StopProcessorAsync(CancellationToken cancellationToken)\n    {\n        LogStoppingProcessor(_logger, Id);\n        \n        // Complete the channel to stop accepting new operations (idempotent operation)\n        if (_storageOperationChannel.Writer.TryComplete())\n        {\n            _shutdownCts.Cancel();\n        }\n\n        // Wait for the background processor to finish all pending operations\n        try\n        {\n            await _storageProcessorTask.WaitAsync(cancellationToken);\n            LogProcessorStopped(_logger, Id);\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected during normal shutdown\n            LogProcessorStopped(_logger, Id);\n        }\n    }\n\n    public override async ValueTask DisposeAsync()\n    {\n        await StopProcessorAsync(CancellationToken.None);\n        _shutdownCts.Dispose();\n        await base.DisposeAsync();\n    }\n}\n\ninternal enum StorageOperationType\n{\n    AppendJobOperation,\n    UpdateMetadata\n}\n\ninternal sealed class StorageOperation\n{\n    public required StorageOperationType Type { get; init; }\n    public JobOperation? JobOperation { get; init; }\n    public IDictionary<string, string>? Metadata { get; init; }\n    public TaskCompletionSource CompletionSource { get; init; } = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n    public static StorageOperation CreateAppendOperation(JobOperation jobOperation)\n    {\n        return new StorageOperation\n        {\n            Type = StorageOperationType.AppendJobOperation,\n            JobOperation = jobOperation\n        };\n    }\n\n    public static StorageOperation CreateMetadataOperation(IDictionary<string, string> metadata)\n    {\n        return new StorageOperation\n        {\n            Type = StorageOperationType.UpdateMetadata,\n            Metadata = metadata\n        };\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/AzureStorageJobShardManager.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Models;\nusing Azure.Storage.Blobs.Specialized;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs.AzureStorage;\n\npublic sealed partial class AzureStorageJobShardManager : JobShardManager\n{\n    private readonly BlobServiceClient _blobServiceClient;\n    private readonly string _containerName;\n    private readonly string _blobPrefix;\n    private BlobContainerClient _client = null!;\n    private readonly IClusterMembershipService _clusterMembership;\n    private readonly ConcurrentDictionary<string, AzureStorageJobShard> _jobShardCache = new();\n    private readonly ILogger<AzureStorageJobShardManager> _logger;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly AzureStorageJobShardOptions _options;\n    private readonly DurableJobsOptions _durableJobsOptions;\n    private long _shardCounter = 0; // For generating unique shard IDs\n\n    private const string AdoptedCountKey = \"AdoptedCount\";\n    private const string LastAdoptedTimeKey = \"LastAdoptedTime\";\n    private const string LegacyStolenCountKey = \"StolenCount\";\n    private const string LegacyLastStolenTimeKey = \"LastStolenTime\";\n\n    public AzureStorageJobShardManager(\n        SiloAddress siloAddress,\n        BlobServiceClient client,\n        string containerName,\n        string blobPrefix,\n        AzureStorageJobShardOptions options,\n        IOptions<DurableJobsOptions> durableJobsOptions,\n        IClusterMembershipService clusterMembership,\n        ILoggerFactory loggerFactory)\n        : base(siloAddress)\n    {\n        _blobServiceClient = client;\n        _containerName = containerName;\n        _blobPrefix = blobPrefix;\n        _clusterMembership = clusterMembership;\n        _logger = loggerFactory.CreateLogger<AzureStorageJobShardManager>();\n        _loggerFactory = loggerFactory;\n        _options = options;\n        _durableJobsOptions = durableJobsOptions.Value;\n    }\n\n    public AzureStorageJobShardManager(\n        ILocalSiloDetails localSiloDetails,\n        IOptions<AzureStorageJobShardOptions> options,\n        IOptions<DurableJobsOptions> durableJobsOptions,\n        IClusterMembershipService clusterMembership,\n        ILoggerFactory loggerFactory)\n        : this(localSiloDetails.SiloAddress, options.Value.BlobServiceClient, options.Value.ContainerName, localSiloDetails.ClusterId, options.Value, durableJobsOptions, clusterMembership, loggerFactory)\n    {\n    }\n\n    public override async Task<List<Orleans.DurableJobs.IJobShard>> AssignJobShardsAsync(DateTimeOffset maxShardStartTime, CancellationToken cancellationToken)\n    {\n        await InitializeIfNeeded(cancellationToken);\n        LogAssigningShards(_logger, SiloAddress, maxShardStartTime, _containerName);\n\n        var result = new List<Orleans.DurableJobs.IJobShard>();\n        await foreach (var blob in _client.GetBlobsAsync(traits: BlobTraits.Metadata, states: BlobStates.None, cancellationToken: cancellationToken, prefix: _blobPrefix))\n        {\n            // Get the owner and creator of the shard\n            var (owner, membershipVersion, shardStartTime, maxDueTime) = ParseMetadata(blob.Metadata);\n\n            // Check if the membership version is more recent than our current version\n            if (membershipVersion > _clusterMembership.CurrentSnapshot.Version)\n            {\n                // Refresh membership to at least that version\n                await _clusterMembership.Refresh(membershipVersion, cancellationToken);\n            }\n\n            if (shardStartTime > maxShardStartTime)\n            {\n                // This shard is too new. Since blobs are returned in alphabetical order and our blob names\n                // contain timestamps (yyyyMMddHHmm format), all subsequent blobs will also be too new.\n                LogShardTooNew(_logger, blob.Name, shardStartTime, maxShardStartTime);\n                break;\n            }\n\n            // If I am the owner, the shard must be in cache - always return it\n            if (owner is not null && owner.Equals(SiloAddress))\n            {\n                if (_jobShardCache.TryGetValue(blob.Name, out var shard))\n                {\n                    LogShardAssigned(_logger, blob.Name, SiloAddress);\n                    result.Add(shard);\n                }\n                else\n                {\n                    // Shard is owned by us but not in cache - this is unexpected, release ownership\n                    Debug.Assert(false, $\"Shard '{blob.Name}' is owned by this silo but not in cache - releasing ownership\");\n                    await ReleaseOwnership(blob.Name);\n                }\n                continue;\n            }\n\n            // In debug, verify that if we're not the owner, the shard should not be in our cache\n            Debug.Assert(!_jobShardCache.ContainsKey(blob.Name), $\"Shard '{blob.Name}' is in cache but we are not the owner (owner: {owner?.ToParsableString() ?? \"none\"})\");\n\n            // Check if the owner is valid\n            var ownerStatus = owner is not null ? _clusterMembership.CurrentSnapshot.GetSiloStatus(owner) : SiloStatus.None;\n\n            if (ownerStatus is not SiloStatus.Dead and not SiloStatus.None)\n            {\n                // Owner is still active and it's not me, skip this shard\n                LogShardStillOwned(_logger, blob.Name, owner!);\n                continue;\n            }\n\n            // Determine if this is an adopted shard (taken from dead owner) vs orphaned (gracefully released)\n            var isAdopted = owner is not null && ownerStatus == SiloStatus.Dead;\n\n            // Try to claim orphaned or adopted shard\n            LogClaimingShard(_logger, blob.Name, SiloAddress, owner);\n            var blobClient = _client.GetAppendBlobClient(blob.Name);\n            var metadata = blob.Metadata;\n            var orphanedShard = new AzureStorageJobShard(blob.Name, shardStartTime, maxDueTime, blobClient, metadata, blob.Properties.ETag, _options, _loggerFactory.CreateLogger<AzureStorageJobShard>());\n            if (!await TryTakeOwnership(orphanedShard, metadata, SiloAddress, isAdopted, cancellationToken))\n            {\n                // Either poisoned shard or someone else took ownership - dispose and continue\n                await orphanedShard.DisposeAsync();\n                continue;\n            }\n            await orphanedShard.InitializeAsync(cancellationToken);\n            // We don't want to add new jobs to shards that we just took ownership of\n            await orphanedShard.MarkAsCompleteAsync(cancellationToken);\n            _jobShardCache[blob.Name] = orphanedShard;\n            LogShardAssigned(_logger, blob.Name, SiloAddress);\n            result.Add(orphanedShard);\n        }\n        \n        LogAssignmentCompleted(_logger, result.Count, SiloAddress);\n        return result;\n\n        async Task ReleaseOwnership(string blobName)\n        {\n            try\n            {\n                var blobClient = _client.GetAppendBlobClient(blobName);\n                var properties = await blobClient.GetPropertiesAsync(cancellationToken: cancellationToken);\n                var metadata = properties.Value.Metadata;\n                metadata.Remove(\"Owner\");\n                // Reset adopted count since we're gracefully releasing\n                metadata.Remove(AdoptedCountKey);\n                metadata.Remove(LastAdoptedTimeKey);\n                metadata.Remove(LegacyStolenCountKey);\n                metadata.Remove(LegacyLastStolenTimeKey);\n                await blobClient.SetMetadataAsync(metadata, new BlobRequestConditions { IfMatch = properties.Value.ETag }, cancellationToken);\n            }\n            catch (Exception ex)\n            {\n                // Log but continue - we'll let another silo claim it\n                _logger.LogWarning(ex, \"Failed to release ownership of shard '{ShardId}' that was not in cache\", blobName);\n            }\n        }\n\n        async Task<bool> TryTakeOwnership(AzureStorageJobShard shard, IDictionary<string, string> metadata, SiloAddress newOwner, bool isAdopted, CancellationToken ct)\n        {\n            if (isAdopted)\n            {\n                var existingAdoptedCount = GetAdoptedCount(metadata);\n                if (existingAdoptedCount > _durableJobsOptions.MaxAdoptedCount)\n                {\n                    // Already marked as poisoned.\n                    return false;\n                }\n\n                // Increment adopted count for shards taken from dead owners.\n                var adoptedCount = existingAdoptedCount + 1;\n                if (adoptedCount > _durableJobsOptions.MaxAdoptedCount)\n                {\n                    // Persist poisoned marker so this shard is not repeatedly re-evaluated as newly poisoned.\n                    SetAdoptedMetadata(metadata, adoptedCount, DateTimeOffset.UtcNow);\n                    try\n                    {\n                        await shard.UpdateBlobMetadata(metadata, ct);\n                    }\n                    catch (RequestFailedException ex)\n                    {\n                        LogOwnershipFailed(_logger, ex, shard.Id, newOwner);\n                    }\n\n                    LogPoisonedShardDetected(_logger, shard.Id, adoptedCount, _durableJobsOptions.MaxAdoptedCount);\n                    return false;\n                }\n\n                SetAdoptedMetadata(metadata, adoptedCount, DateTimeOffset.UtcNow);\n                LogShardAdopted(_logger, shard.Id, newOwner, adoptedCount);\n            }\n\n            metadata[\"Owner\"] = newOwner.ToParsableString();\n            metadata[\"MembershipVersion\"] = _clusterMembership.CurrentSnapshot.Version.Value.ToString();\n\n            try\n            {\n                await shard.UpdateBlobMetadata(metadata, ct);\n                LogOwnershipTaken(_logger, shard.Id, newOwner);\n                return true;\n            }\n            catch (RequestFailedException ex)\n            {\n                // Someone else took over the shard\n                LogOwnershipFailed(_logger, ex, shard.Id, newOwner);\n                return false;\n            }\n        }\n\n        static int GetAdoptedCount(IDictionary<string, string> metadata)\n        {\n            if (metadata.TryGetValue(AdoptedCountKey, out var countStr)\n                   && int.TryParse(countStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out var adoptedCount))\n            {\n                return adoptedCount;\n            }\n\n            return metadata.TryGetValue(LegacyStolenCountKey, out countStr)\n                   && int.TryParse(countStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out var legacyCount)\n                ? legacyCount\n                : 0;\n        }\n\n        static void SetAdoptedMetadata(IDictionary<string, string> metadata, int adoptedCount, DateTimeOffset adoptedTime)\n        {\n            metadata[AdoptedCountKey] = adoptedCount.ToString(CultureInfo.InvariantCulture);\n            metadata[LastAdoptedTimeKey] = adoptedTime.ToString(\"o\", CultureInfo.InvariantCulture);\n            metadata.Remove(LegacyStolenCountKey);\n            metadata.Remove(LegacyLastStolenTimeKey);\n        }\n    }\n\n    public override async Task<Orleans.DurableJobs.IJobShard> CreateShardAsync(DateTimeOffset minDueTime, DateTimeOffset maxDueTime, IDictionary<string, string> metadata, CancellationToken cancellationToken)\n    {\n        await InitializeIfNeeded(cancellationToken);\n        LogRegisteringShard(_logger, SiloAddress, minDueTime, maxDueTime, _containerName);\n        \n        var i = 0;\n        while (true)\n        {\n            var counter = Interlocked.Increment(ref _shardCounter);\n            var shardId = $\"{_blobPrefix}-{minDueTime:yyyyMMddHHmm}-{SiloAddress.ToParsableString()}-{counter}\";\n            var blobClient = _client.GetAppendBlobClient(shardId);\n            var metadataInfo = CreateMetadata(metadata, SiloAddress, _clusterMembership.CurrentSnapshot.Version, minDueTime, maxDueTime);\n            metadataInfo[\"Owner\"] = SiloAddress.ToParsableString();\n            try\n            {\n                var response = await blobClient.CreateIfNotExistsAsync(metadata: metadataInfo, cancellationToken: cancellationToken);\n                if (response == null)\n                {\n                    // Blob already exists, try again with a different name\n                    LogShardIdCollision(_logger, shardId, i);\n                    continue;\n                }\n            }\n            catch (RequestFailedException ex)\n            {\n                i++;\n                if (i > _options.MaxBlobCreationRetries)\n                {\n                    throw new InvalidOperationException($\"Failed to create shard blob '{shardId}' after {i} attempts\", ex);\n                }\n                // Blob already exists, try again with a different name\n                LogShardRegistrationRetry(_logger, ex, shardId, i);\n                continue;\n            }\n            \n            var shard = new AzureStorageJobShard(shardId, minDueTime, maxDueTime, blobClient, metadataInfo, null, _options, _loggerFactory.CreateLogger<AzureStorageJobShard>());\n            await shard.InitializeAsync(cancellationToken);\n            _jobShardCache[shardId] = shard;\n            LogShardRegistered(_logger, shardId, SiloAddress);\n            return shard;\n        }\n    }\n\n    public override async Task UnregisterShardAsync(Orleans.DurableJobs.IJobShard shard, CancellationToken cancellationToken)\n    {\n        var azureShard = shard as AzureStorageJobShard ?? throw new ArgumentException(\"Shard is not an AzureStorageJobShard\", nameof(shard));\n        LogUnregisteringShard(_logger, shard.Id, SiloAddress);\n        \n        // Stop the background storage processor to ensure no more changes can happen\n        await azureShard.StopProcessorAsync(cancellationToken);\n        \n        // Now we can safely get a consistent view of the state\n        var count = await shard.GetJobCountAsync();\n        // We want to make sure to get the latest properties\n        var properties = await azureShard.BlobClient.GetPropertiesAsync(cancellationToken: cancellationToken);\n\n        // But we don't want to update the metadata if the ETag has changed\n        var currentETag = properties.Value.ETag;\n        var conditions = new BlobRequestConditions { IfMatch = currentETag };\n        var metadata = properties.Value.Metadata;\n        var (owner, _, _, _) = ParseMetadata(metadata);\n\n        if (owner != SiloAddress)\n        {\n            LogUnregisterWrongOwner(_logger, shard.Id, SiloAddress, owner);\n            throw new InvalidOperationException(\"Cannot unregister a shard owned by another silo\");\n        }\n\n        if (count > 0)\n        {\n            // There are still jobs in the shard, release ownership gracefully.\n            metadata.Remove(\"Owner\");\n            // Reset adopted count since we're gracefully releasing (not crashing)\n            metadata.Remove(AdoptedCountKey);\n            metadata.Remove(LastAdoptedTimeKey);\n            metadata.Remove(LegacyStolenCountKey);\n            metadata.Remove(LegacyLastStolenTimeKey);\n            await azureShard.BlobClient.SetMetadataAsync(metadata, conditions, cancellationToken);\n            _jobShardCache.TryRemove(shard.Id, out _);\n            LogShardOwnershipReleased(_logger, shard.Id, SiloAddress, count);\n        }\n        else\n        {\n            // No jobs left, we can delete the shard\n            await azureShard.BlobClient.DeleteIfExistsAsync(conditions: conditions, cancellationToken: cancellationToken);\n            _jobShardCache.TryRemove(shard.Id, out _);\n            LogShardDeleted(_logger, shard.Id, SiloAddress);\n        }\n\n        // Dispose the shard's resources\n        await azureShard.DisposeAsync();\n    }\n\n    private async ValueTask InitializeIfNeeded(CancellationToken cancellationToken = default)\n    {\n        if (_client != null) return;\n\n        LogInitializing(_logger, _containerName);\n        _client = _blobServiceClient.GetBlobContainerClient(_containerName);\n        await _client.CreateIfNotExistsAsync(cancellationToken: cancellationToken);\n        LogInitialized(_logger, _containerName);\n    }\n\n    private static Dictionary<string, string> CreateMetadata(IDictionary<string, string> existingMetadata, SiloAddress siloAddress, MembershipVersion membershipVersion, DateTimeOffset minDueTime, DateTimeOffset maxDueTime)\n    {\n        var metadata = new Dictionary<string, string>(existingMetadata)\n        {\n            { \"MinDueTime\", minDueTime.ToString(\"o\") },\n            { \"MaxDueTime\", maxDueTime.ToString(\"o\") },\n            { \"MembershipVersion\", membershipVersion.Value.ToString(CultureInfo.InvariantCulture) }\n        };\n\n        return metadata;\n    }\n\n    private static (SiloAddress? owner, MembershipVersion membershipVersion, DateTimeOffset minDueTime, DateTimeOffset maxDueTime) ParseMetadata(IDictionary<string, string> metadata)\n    {\n        var owner = metadata.TryGetValue(\"Owner\", out var ownerStr) ? SiloAddress.FromParsableString(ownerStr) : null;\n        var membershipVersion = metadata.TryGetValue(\"MembershipVersion\", out var membershipVersionStr) && long.TryParse(membershipVersionStr, out var versionValue)\n            ? new MembershipVersion(versionValue)\n            : MembershipVersion.MinValue;\n        var minDueTime = metadata.TryGetValue(\"MinDueTime\", out var minDueTimeStr) && DateTimeOffset.TryParse(minDueTimeStr, out var minDt) ? minDt : DateTimeOffset.MinValue;\n        var maxDueTime = metadata.TryGetValue(\"MaxDueTime\", out var maxDueTimeStr) && DateTimeOffset.TryParse(maxDueTimeStr, out var maxDt) ? maxDt : DateTimeOffset.MaxValue;\n        return (owner, membershipVersion, minDueTime, maxDueTime);\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Initializing Azure Storage Job Shard Manager with container '{ContainerName}'\"\n    )]\n    private static partial void LogInitializing(ILogger logger, string containerName);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Azure Storage Job Shard Manager initialized successfully for container '{ContainerName}'\"\n    )]\n    private static partial void LogInitialized(ILogger logger, string containerName);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Assigning job shards for silo {SiloAddress} with max time {MaxDateTime} from container '{ContainerName}'\"\n    )]\n    private static partial void LogAssigningShards(ILogger logger, SiloAddress siloAddress, DateTimeOffset maxDateTime, string containerName);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Ignoring shard '{ShardId}' since its start time is greater than specified maximum (MinDueTime={MinDueTime}, MaxDateTime={MaxDateTime})\"\n    )]\n    private static partial void LogShardTooNew(ILogger logger, string shardId, DateTimeOffset minDueTime, DateTimeOffset maxDateTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Shard '{ShardId}' is still owned by active silo {Owner}\"\n    )]\n    private static partial void LogShardStillOwned(ILogger logger, string shardId, SiloAddress owner);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Reclaiming shard '{ShardId}' from cache for silo {SiloAddress}\"\n    )]\n    private static partial void LogReclaimingShardFromCache(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Claiming shard '{ShardId}' for silo {SiloAddress} (Previous Owner={PreviousOwner})\"\n    )]\n    private static partial void LogClaimingShard(ILogger logger, string shardId, SiloAddress siloAddress, SiloAddress? previousOwner);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to take ownership of shard '{ShardId}' for silo {SiloAddress} due to conflict\"\n    )]\n    private static partial void LogShardOwnershipConflict(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Shard '{ShardId}' assigned to silo {SiloAddress}\"\n    )]\n    private static partial void LogShardAssigned(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Assigned {ShardCount} shard(s) to silo {SiloAddress}\"\n    )]\n    private static partial void LogAssignmentCompleted(ILogger logger, int shardCount, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Took ownership of shard '{ShardId}' for silo {SiloAddress}\"\n    )]\n    private static partial void LogOwnershipTaken(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to take ownership of shard '{ShardId}' for silo {SiloAddress}\"\n    )]\n    private static partial void LogOwnershipFailed(ILogger logger, Exception exception, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Creating new shard for silo {SiloAddress} (MinDueTime={MinDueTime}, MaxDueTime={MaxDueTime}) in container '{ContainerName}'\"\n    )]\n    private static partial void LogRegisteringShard(ILogger logger, SiloAddress siloAddress, DateTimeOffset minDueTime, DateTimeOffset maxDueTime, string containerName);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Shard ID collision for '{ShardId}' (attempt {Attempt}), retrying with new ID\"\n    )]\n    private static partial void LogShardIdCollision(ILogger logger, string shardId, int attempt);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to register shard '{ShardId}' (attempt {Attempt}), retrying\"\n    )]\n    private static partial void LogShardRegistrationRetry(ILogger logger, Exception exception, string shardId, int attempt);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Shard '{ShardId}' created successfully for silo {SiloAddress}\"\n    )]\n    private static partial void LogShardRegistered(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Unregistering shard '{ShardId}' for silo {SiloAddress}\"\n    )]\n    private static partial void LogUnregisteringShard(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Cannot unregister shard '{ShardId}' - silo {SiloAddress} is not the owner (Owner={Owner})\"\n    )]\n    private static partial void LogUnregisterWrongOwner(ILogger logger, string shardId, SiloAddress siloAddress, SiloAddress? owner);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Released ownership of shard '{ShardId}' by silo {SiloAddress} ({JobCount} jobs remaining)\"\n    )]\n    private static partial void LogShardOwnershipReleased(ILogger logger, string shardId, SiloAddress siloAddress, int jobCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Deleted shard '{ShardId}' by silo {SiloAddress} (no jobs remaining)\"\n    )]\n    private static partial void LogShardDeleted(ILogger logger, string shardId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Poisoned shard detected: '{ShardId}' has been adopted {AdoptedCount} times (max allowed: {MaxAdoptedCount}). Shard will not be assigned.\"\n    )]\n    private static partial void LogPoisonedShardDetected(ILogger logger, string shardId, int adoptedCount, int maxAdoptedCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Shard '{ShardId}' adopted by silo {SiloAddress} (adopted count: {AdoptedCount})\"\n    )]\n    private static partial void LogShardAdopted(ILogger logger, string shardId, SiloAddress siloAddress, int adoptedCount);\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/Hosting/AzureStorageDurableJobsExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.DurableJobs;\nusing Orleans.DurableJobs.AzureStorage;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Extensions for configuring Azure Blob Storage durable jobs.\n/// </summary>\npublic static class AzureStorageDurableJobsExtensions\n{\n    /// <summary>\n    /// Adds durable jobs storage backed by Azure Blob Storage.\n    /// </summary>\n    /// <param name=\"builder\">\n    /// The builder.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the durable jobs storage.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n    /// </returns>\n    public static ISiloBuilder UseAzureBlobDurableJobs(this ISiloBuilder builder, Action<AzureStorageJobShardOptions> configure)\n    {\n        builder.ConfigureServices(services => services.UseAzureBlobDurableJobs(configure));\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds durable jobs storage backed by Azure Blob Storage.\n    /// </summary>\n    /// <param name=\"builder\">\n    /// The builder.\n    /// </param>\n    /// <param name=\"configureOptions\">\n    /// The configuration delegate.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n    /// </returns>\n    public static ISiloBuilder UseAzureBlobDurableJobs(this ISiloBuilder builder, Action<OptionsBuilder<AzureStorageJobShardOptions>> configureOptions)\n    {\n        builder.ConfigureServices(services => services.UseAzureBlobDurableJobs(configureOptions));\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds durable jobs storage backed by Azure Blob Storage.\n    /// </summary>\n    /// <param name=\"services\">\n    /// The service collection.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the durable jobs storage.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n    /// </returns>\n    public static IServiceCollection UseAzureBlobDurableJobs(this IServiceCollection services, Action<AzureStorageJobShardOptions> configure)\n    {\n        services.AddDurableJobs();\n        services.AddSingleton<AzureStorageJobShardManager>();\n        services.AddFromExisting<Orleans.DurableJobs.JobShardManager, AzureStorageJobShardManager>();\n        services.Configure<AzureStorageJobShardOptions>(configure);\n        services.ConfigureFormatter<AzureStorageJobShardOptions>();\n        return services;\n    }\n\n    /// <summary>\n    /// Adds durable jobs storage backed by Azure Blob Storage.\n    /// </summary>\n    /// <param name=\"services\">\n    /// The service collection.\n    /// </param>\n    /// <param name=\"configureOptions\">\n    /// The configuration delegate.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n    /// </returns>\n    public static IServiceCollection UseAzureBlobDurableJobs(this IServiceCollection services, Action<OptionsBuilder<AzureStorageJobShardOptions>> configureOptions)\n    {\n        services.AddDurableJobs();\n        services.AddSingleton<AzureStorageJobShardManager>();\n        services.AddFromExisting<Orleans.DurableJobs.JobShardManager, AzureStorageJobShardManager>();\n        configureOptions?.Invoke(services.AddOptions<AzureStorageJobShardOptions>());\n        services.ConfigureFormatter<AzureStorageJobShardOptions>();\n        services.AddTransient<IConfigurationValidator>(sp => new AzureStorageJobShardOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureStorageJobShardOptions>>().Get(Options.DefaultName), Options.DefaultName));\n        return services;\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/Hosting/AzureStorageJobShardOptions.cs",
    "content": "using System;\nusing Azure.Storage.Blobs;\n\nnamespace Orleans.Hosting;\n\npublic class AzureStorageJobShardOptions\n{\n    /// <summary>\n    /// Gets or sets the <see cref=\"BlobServiceClient\"/> instance used to store job shards.\n    /// </summary>\n    public BlobServiceClient BlobServiceClient { get; set; } = null!;\n\n    /// <summary>\n    /// Gets or sets the name of the container used to store durable jobs.\n    /// </summary>\n    public string ContainerName { get; set; } = \"jobs\";\n\n    /// <summary>\n    /// Gets or sets the maximum number of job operations to batch together in a single blob write.\n    /// Default is 50 operations.\n    /// </summary>\n    public int MaxBatchSize { get; set; } = 50;\n\n    /// <summary>\n    /// Gets or sets the minimum number of job operations to batch together before flushing.\n    /// If more than 1 then the we will wait <see cref=\"BatchFlushInterval\"/> for additional operations.\n    /// Default is 1 operation (immediate flush, optimized for latency).\n    /// </summary>\n    public int MinBatchSize { get; set; } = 1;\n\n    /// <summary>\n    /// Gets or sets the maximum time to wait for additional operations if the minimum batch size isn't reached \n    /// before flushing a batch.\n    /// Default is 50 milliseconds.\n    /// </summary>\n    public TimeSpan BatchFlushInterval { get; set; } = TimeSpan.FromMilliseconds(50);\n    \n    /// <summary>\n    /// Gets or sets the maximum number of retries for creating a blob for a job shard in case of name collisions.\n    /// </summary>\n    public int MaxBlobCreationRetries { get; internal set; } = 3;\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/Hosting/AzureStorageJobShardOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Validates <see cref=\"AzureStorageJobShardOptions\"/>.\n/// </summary>\npublic class AzureStorageJobShardOptionsValidator : IConfigurationValidator\n{\n    private readonly AzureStorageJobShardOptions _options;\n    private readonly string _name;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AzureStorageJobShardOptionsValidator\"/> class.\n    /// </summary>\n    /// <param name=\"options\">The options.</param>\n    /// <param name=\"name\">The name.</param>\n    public AzureStorageJobShardOptionsValidator(AzureStorageJobShardOptions options, string name)\n    {\n        _options = options;\n        _name = name;\n    }\n\n    /// <inheritdoc/>\n    public void ValidateConfiguration()\n    {\n        if (_options.BlobServiceClient is null)\n        {\n            throw new OrleansConfigurationException($\"Invalid configuration for {nameof(AzureStorageJobShardOptions)} with name '{_name}'. {nameof(_options.BlobServiceClient)} is required.\");\n        }\n\n        if (string.IsNullOrWhiteSpace(_options.ContainerName))\n        {\n            throw new OrleansConfigurationException($\"Invalid configuration for {nameof(AzureStorageJobShardOptions)} with name '{_name}'. {nameof(_options.ContainerName)} is required.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/JobOperation.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs.AzureStorage;\n\n/// <summary>\n/// Represents an operation to be performed on a durable job.\n/// </summary>\ninternal struct JobOperation\n{\n    /// <summary>\n    /// The type of operation to perform.\n    /// </summary>\n    public enum OperationType\n    {\n        Add,\n        Remove,\n        Retry,\n    }\n\n    /// <summary>\n    /// Gets or sets the type of operation.\n    /// </summary>\n    public OperationType Type { get; init; }\n\n    /// <summary>\n    /// Gets or sets the job identifier.\n    /// </summary>\n    public string Id { get; init; }\n\n    /// <summary>\n    /// Gets or sets the job name (only used for Add operations).\n    /// </summary>\n    public string? Name { get; init; }\n\n    /// <summary>\n    /// Gets or sets the due time (used for Add and Retry operations).\n    /// </summary>\n    public DateTimeOffset? DueTime { get; init; }\n\n    /// <summary>\n    /// Gets or sets the target grain ID (only used for Add operations).\n    /// </summary>\n    public GrainId? TargetGrainId { get; init; }\n\n    /// <summary>\n    /// Gets or sets the job metadata (only used for Add operations).\n    /// </summary>\n    public IReadOnlyDictionary<string, string>? Metadata { get; init; }\n\n    /// <summary>\n    /// Creates an Add operation for scheduling a new job.\n    /// </summary>\n    /// <param name=\"id\">The job identifier.</param>\n    /// <param name=\"name\">The job name.</param>\n    /// <param name=\"dueTime\">The job due time.</param>\n    /// <param name=\"targetGrainId\">The target grain ID.</param>\n    /// <param name=\"metadata\">The job metadata.</param>\n    /// <returns>A new JobOperation for adding a job.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"id\"/> or <paramref name=\"name\"/> is null or empty.</exception>\n    public static JobOperation CreateAddOperation(string id, string name, DateTimeOffset dueTime, GrainId targetGrainId, IReadOnlyDictionary<string, string>? metadata)\n    {\n        ArgumentException.ThrowIfNullOrEmpty(id);\n        ArgumentException.ThrowIfNullOrEmpty(name);\n\n        return new() { Type = OperationType.Add, Id = id, Name = name, DueTime = dueTime, TargetGrainId = targetGrainId, Metadata = metadata };\n    }\n\n    /// <summary>\n    /// Creates a Remove operation for canceling a job.\n    /// </summary>\n    /// <param name=\"id\">The job identifier.</param>\n    /// <returns>A new JobOperation for removing a job.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"id\"/> is null or empty.</exception>\n    public static JobOperation CreateRemoveOperation(string id)\n    {\n        ArgumentException.ThrowIfNullOrEmpty(id);\n\n        return new() { Type = OperationType.Remove, Id = id };\n    }\n\n    /// <summary>\n    /// Creates a Retry operation for rescheduling a job.\n    /// </summary>\n    /// <param name=\"id\">The job identifier.</param>\n    /// <param name=\"dueTime\">The new due time.</param>\n    /// <returns>A new JobOperation for retrying a job.</returns>\n    /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"id\"/> is null or empty.</exception>\n    public static JobOperation CreateRetryOperation(string id, DateTimeOffset dueTime)\n    {\n        ArgumentException.ThrowIfNullOrEmpty(id);\n\n        return new() { Type = OperationType.Retry, Id = id, DueTime = dueTime };\n    }\n}\n\n/// <summary>\n/// JSON serialization context for JobOperation with compile-time source generation.\n/// </summary>\n[JsonSerializable(typeof(JobOperation))]\n[JsonSourceGenerationOptions(\n    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,\n    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,\n    WriteIndented = false)]\ninternal partial class JobOperationJsonContext : JsonSerializerContext\n{\n}"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/NetstringJsonSerializer.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Text;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.CompilerServices;\nusing System.Text.Json;\nusing System.Text.Json.Serialization.Metadata;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Serialization.Buffers.Adaptors;\n\nnamespace Orleans.DurableJobs.AzureStorage;\n\n/// <summary>\n/// Provides methods for serializing and deserializing JSON data using the netstring format.\n/// Netstrings are a simple, self-delimiting way to encode data with length prefixes.\n/// Format: [6 hex digits]:[data]\\n\n/// Maximum data size is 10MB (0xA00000 bytes).\n/// </summary>\npublic static class NetstringJsonSerializer<T>\n{\n    private const int MaxLength = 0xA00000; // 10MB\n\n    /// <summary>\n    /// Encodes an object as a netstring by serializing it to JSON and writing directly to a stream.\n    /// </summary>\n    /// <param name=\"value\">The object to encode.</param>\n    /// <param name=\"stream\">The stream to write the netstring-encoded data to.</param>\n    /// <param name=\"jsonTypeInfo\">The JSON type info for serialization.</param>\n    /// <exception cref=\"InvalidOperationException\">Thrown when the serialized data exceeds the maximum length.</exception>\n    public static void Encode(T value, Stream stream, JsonTypeInfo<T> jsonTypeInfo)\n    {\n        // Remember starting position\n        var startPosition = stream.Position;\n\n        // Skip past where the length prefix will go (6 hex digits + colon)\n        Span<byte> lengthBytes = stackalloc byte[7];\n        stream.Write(lengthBytes);\n\n        // Remember position where data starts\n        var dataStartPosition = stream.Position;\n        \n        // Serialize JSON directly to stream\n        using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { SkipValidation = false }))\n        {\n            JsonSerializer.Serialize(writer, value, jsonTypeInfo);\n        }\n\n        stream.Flush();\n        \n        // Calculate JSON length\n        var jsonLength = (int)(stream.Position - dataStartPosition);\n        \n        if (jsonLength > MaxLength)\n        {\n            throw new InvalidOperationException($\"Serialized data exceeds maximum length of {MaxLength} bytes\");\n        }\n\n        // Write trailing newline\n        stream.WriteByte((byte)'\\n');\n        \n        // Remember end position\n        var endPosition = stream.Position;\n        \n        // Seek back to write the length prefix\n        stream.Position = startPosition;\n        \n        // Format length as 6-digit hex and write directly\n        if (!Utf8Formatter.TryFormat(jsonLength, lengthBytes, out _, new StandardFormat('X', 6)))\n        {\n            throw new InvalidOperationException(\"Failed to format length prefix\");\n        }\n\n        lengthBytes[6] = (byte)':';\n        \n        stream.Write(lengthBytes);\n        \n        // Restore position to end\n        stream.Position = endPosition;\n    }\n\n    /// <summary>\n    /// Reads netstring-encoded JSON objects from a stream and deserializes them.\n    /// </summary>\n    /// <param name=\"stream\">The stream to read from.</param>\n    /// <param name=\"jsonTypeInfo\">The JSON type info for deserialization.</param>\n    /// <param name=\"cancellationToken\">The cancellation token to cancel the operation.</param>\n    /// <returns>An async enumerable of deserialized objects.</returns>\n    /// <exception cref=\"InvalidDataException\">Thrown when the stream contains invalid netstring data.</exception>\n    public static async IAsyncEnumerable<T> DecodeAsync(Stream stream, JsonTypeInfo<T> jsonTypeInfo, [EnumeratorCancellation] CancellationToken cancellationToken)\n    {\n        const int TypicalBufferSize = 4096; // 4KB \n        var buffer = ArrayPool<byte>.Shared.Rent(TypicalBufferSize);\n\n        try\n        {\n            while (true)\n            {\n                \n                // Try to read length prefix (6 hex digits + colon)\n                try\n                {\n                    await stream.ReadExactlyAsync(buffer, 0, 7, cancellationToken);\n                }\n                catch (EndOfStreamException)\n                {\n                    // We are done\n                    yield break;\n                }\n\n                // Verify colon\n                if (buffer[6] != ':')\n                {\n                    throw new InvalidDataException($\"Expected colon at position 6, got byte value {buffer[6]}\");\n                }\n\n                // Parse length as hex\n                if (!Utf8Parser.TryParse(buffer.AsSpan(0, 6), out int length, out _, 'X'))\n                {\n                    throw new InvalidDataException($\"Invalid netstring length: {System.Text.Encoding.UTF8.GetString(buffer, 0, 6)}\");\n                }\n\n                if (length < 0 || length > MaxLength)\n                {\n                    throw new InvalidDataException($\"Netstring length out of valid range: {length}\");\n                }\n\n                // Ensure buffer is large enough for the data + newline\n                var totalLength = length + 1;\n                if (buffer.Length < totalLength)\n                {\n                    ArrayPool<byte>.Shared.Return(buffer);\n                    buffer = ArrayPool<byte>.Shared.Rent(totalLength);\n                }\n\n                // Read data + trailing newline\n                try\n                {\n                    await stream.ReadExactlyAsync(buffer.AsMemory(0, totalLength), cancellationToken);\n                }\n                catch (EndOfStreamException ex)\n                {\n                    throw new InvalidDataException(\"Unexpected end of stream while reading netstring data\", ex);\n                }\n\n                // Verify trailing newline\n                if (buffer[length] != '\\n')\n                {\n                    throw new InvalidDataException($\"Expected newline at end of netstring, got byte value {buffer[length]}\");\n                }\n\n                // Deserialize JSON directly from UTF-8 bytes\n                var result = JsonSerializer.Deserialize(buffer.AsSpan(0, length), jsonTypeInfo);\n                if (result is null)\n                {\n                    throw new JsonException(\"Deserialized JSON resulted in null value\");\n                }\n\n                yield return result;\n            }\n        }\n        finally\n        {\n            ArrayPool<byte>.Shared.Return(buffer);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/Orleans.DurableJobs.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.DurableJobs.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Storage Durable Jobs Provider</Title>\n    <Description>Microsoft Orleans durable jobs provider backed by Azure Blob Storage</Description>\n    <PackageTags>$(PackageTags) Azure Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.DurableJobs.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.DurableJobs.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants)</DefineConstants>\n    <Nullable>enable</Nullable>\n    <VersionSuffix Condition=\"$(VersionSuffix) != ''\">$(VersionSuffix).alpha.1</VersionSuffix>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.DurableJobs\\Orleans.DurableJobs.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Storage.Blobs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.DurableJobs.AzureStorage/README.md",
    "content": "# Microsoft Orleans Durable Jobs for Azure Storage\n\n## Introduction\nMicrosoft Orleans Durable Jobs for Azure Storage provides persistent storage for Orleans Durable Jobs using Azure Blob Storage. This allows your Orleans applications to schedule jobs that survive silo restarts, grain deactivation, and cluster reconfigurations. Jobs are stored in append blobs, providing efficient storage and retrieval for time-based job scheduling.\n\n## Getting Started\n\n### Installation\nTo use this package, install it via NuGet along with the core package:\n\n```shell\ndotnet add package Microsoft.Orleans.DurableJobs\ndotnet add package Microsoft.Orleans.DurableJobs.AzureStorage\n```\n\n### Configuration\n\n#### Using Connection String\n```csharp\nusing Azure.Storage.Blobs;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseAzureStorageClustering(options => options.ConfigureTableServiceClient(\"YOUR_STORAGE_ACCOUNT_URI\"))\n        .UseAzureStorageDurableJobs(options =>\n        {\n            options.Configure(o =>\n            {\n                o.BlobServiceClient = new BlobServiceClient(\"YOUR_AZURE_STORAGE_CONNECTION_STRING\");\n                o.ContainerName = \"durable-jobs\";\n            });\n        });\n});\n\nawait builder.Build().RunAsync();\n```\n\n#### Using Managed Identity (Recommended for Production)\n```csharp\nusing Azure.Identity;\nusing Azure.Storage.Blobs;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseAzureStorageClustering(options => options.ConfigureTableServiceClient(\"YOUR_STORAGE_ACCOUNT_URI\"))\n        .UseAzureStorageDurableJobs(options =>\n        {\n            options.Configure(o =>\n            {\n                var credential = new DefaultAzureCredential();\n                o.BlobServiceClient = new BlobServiceClient(\n                    new Uri(\"https://youraccount.blob.core.windows.net\"),\n                    credential);\n                o.ContainerName = \"durable-jobs\";\n            });\n        });\n});\n\nawait builder.Build().RunAsync();\n```\n\n#### With Advanced Options\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\n\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseAzureStorageClustering(options => options.ConfigureTableServiceClient(connectionString))\n        .UseAzureStorageDurableJobs(options =>\n        {\n            options.Configure(o =>\n            {\n                o.BlobServiceClient = new BlobServiceClient(connectionString);\n                // Use different containers for different environments\n                o.ContainerName = $\"durable-jobs-{Environment.GetEnvironmentVariable(\"ASPNETCORE_ENVIRONMENT\")?.ToLowerInvariant()}\";\n            });\n        })\n        .ConfigureServices(services =>\n        {\n            services.Configure<DurableJobsOptions>(options =>\n            {\n                // Shard duration: balance between latency and storage overhead\n                options.ShardDuration = TimeSpan.FromMinutes(5);\n                \n                // Control concurrency to prevent overwhelming the system\n                options.MaxConcurrentJobsPerSilo = 50;\n                \n                // Custom retry policy with exponential backoff\n                options.ShouldRetry = (context, exception) =>\n                {\n                    // Don't retry on permanent failures\n                    if (exception is ArgumentException or InvalidOperationException)\n                        return null;\n                    \n                    // Exponential backoff with max 3 retries\n                    if (context.DequeueCount < 3)\n                    {\n                        var delay = TimeSpan.FromSeconds(Math.Pow(2, context.DequeueCount));\n                        return DateTimeOffset.UtcNow.Add(delay);\n                    }\n                    \n                    return null;\n                };\n            });\n        });\n});\n```\n\n## Usage Example\n\n### Email Scheduling with Cancellation\n```csharp\nusing Orleans;\nusing Orleans.DurableJobs;\n\npublic interface IEmailGrain : IGrainWithStringKey\n{\n    Task ScheduleEmail(string subject, string body, DateTimeOffset sendTime);\n    Task CancelScheduledEmail();\n}\n\npublic class EmailGrain : Grain, IEmailGrain, IDurableJobHandler\n{\n    private readonly ILocalDurableJobManager _jobManager;\n    private readonly IEmailService _emailService;\n    private readonly ILogger<EmailGrain> _logger;\n    private IDurableJob? _durableEmailJob;\n\n    public EmailGrain(\n        ILocalDurableJobManager jobManager,\n        IEmailService emailService,\n        ILogger<EmailGrain> logger)\n    {\n        _jobManager = jobManager;\n        _emailService = emailService;\n        _logger = logger;\n    }\n\n    public async Task ScheduleEmail(string subject, string body, DateTimeOffset sendTime)\n    {\n        var emailAddress = this.GetPrimaryKeyString();\n        var metadata = new Dictionary<string, string>\n        {\n            [\"Subject\"] = subject,\n            [\"Body\"] = body\n        };\n\n        _durableEmailJob = await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"SendEmail\",\n                DueTime = sendTime,\n                Metadata = metadata\n            },\n            CancellationToken.None);\n\n        _logger.LogInformation(\n            \"Scheduled email to {EmailAddress} for {SendTime} (JobId: {JobId})\",\n            emailAddress, sendTime, _durableEmailJob.Id);\n    }\n\n    public async Task CancelScheduledEmail()\n    {\n        if (_durableEmailJob is null)\n        {\n            _logger.LogWarning(\"No scheduled email to cancel\");\n            return;\n        }\n\n        var canceled = await _jobManager.TryCancelDurableJobAsync(_durableEmailJob);\n        if (canceled)\n        {\n            _logger.LogInformation(\"Email job {JobId} canceled successfully\", _durableEmailJob.Id);\n            _durableEmailJob = null;\n        }\n        else\n        {\n            _logger.LogWarning(\"Failed to cancel email job {JobId} (may have already executed)\", _durableEmailJob.Id);\n        }\n    }\n\n    public async Task ExecuteJobAsync(IDurableJobContext context, CancellationToken cancellationToken)\n    {\n        var emailAddress = this.GetPrimaryKeyString();\n        var subject = context.Job.Metadata?[\"Subject\"];\n        var body = context.Job.Metadata?[\"Body\"];\n\n        _logger.LogInformation(\n            \"Sending email to {EmailAddress} (Job: {JobId}, Attempt: {Attempt})\",\n            emailAddress, context.Job.Id, context.DequeueCount);\n\n        try\n        {\n            await _emailService.SendEmailAsync(emailAddress, subject, body, cancellationToken);\n            _logger.LogInformation(\"Email sent successfully to {EmailAddress}\", emailAddress);\n            _durableEmailJob = null;\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Failed to send email to {EmailAddress}\", emailAddress);\n            throw; // Let the retry policy handle it\n        }\n    }\n}\n```\n\n### Order Workflow with Multiple Scheduled Steps\n```csharp\npublic interface IOrderGrain : IGrainWithGuidKey\n{\n    Task PlaceOrder(OrderDetails order);\n    Task CancelOrder();\n}\n\npublic class OrderGrain : Grain, IOrderGrain, IDurableJobHandler\n{\n    private readonly ILocalDurableJobManager _jobManager;\n    private readonly IOrderService _orderService;\n    private readonly IGrainFactory _grainFactory;\n    private readonly ILogger<OrderGrain> _logger;\n    private OrderDetails? _orderDetails;\n\n    public OrderGrain(\n        ILocalDurableJobManager jobManager,\n        IOrderService orderService,\n        IGrainFactory grainFactory,\n        ILogger<OrderGrain> logger)\n    {\n        _jobManager = jobManager;\n        _orderService = orderService;\n        _grainFactory = grainFactory;\n        _logger = logger;\n    }\n\n    public async Task PlaceOrder(OrderDetails order)\n    {\n        _orderDetails = order;\n        var orderId = this.GetPrimaryKey();\n\n        // Create the order\n        await _orderService.CreateOrderAsync(orderId, order);\n        _logger.LogInformation(\"Order {OrderId} created for customer {CustomerId}\", orderId, order.CustomerId);\n\n        // Schedule payment reminder after 1 hour\n        var paymentReminderTime = DateTimeOffset.UtcNow.AddHours(1);\n        await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"PaymentReminder\",\n                DueTime = paymentReminderTime,\n                Metadata = new Dictionary<string, string>\n                {\n                    [\"Step\"] = \"PaymentReminder\",\n                    [\"CustomerEmail\"] = order.CustomerEmail\n                }\n            },\n            CancellationToken.None);\n\n        // Schedule order expiration after 24 hours\n        var expirationTime = DateTimeOffset.UtcNow.AddHours(24);\n        await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"OrderExpiration\",\n                DueTime = expirationTime,\n                Metadata = new Dictionary<string, string>\n                {\n                    [\"Step\"] = \"OrderExpiration\"\n                }\n            },\n            CancellationToken.None);\n\n        _logger.LogInformation(\n            \"Scheduled payment reminder for {ReminderTime} and expiration for {ExpirationTime}\",\n            paymentReminderTime, expirationTime);\n    }\n\n    public async Task CancelOrder()\n    {\n        var orderId = this.GetPrimaryKey();\n        await _orderService.CancelOrderAsync(orderId);\n        _orderDetails = null;\n        _logger.LogInformation(\"Order {OrderId} canceled\", orderId);\n    }\n\n    public async Task ExecuteJobAsync(IDurableJobContext context, CancellationToken cancellationToken)\n    {\n        var step = context.Job.Metadata![\"Step\"];\n        var orderId = this.GetPrimaryKey();\n\n        _logger.LogInformation(\n            \"Executing workflow step {Step} for order {OrderId} (Attempt: {Attempt})\",\n            step, orderId, context.DequeueCount);\n\n        switch (step)\n        {\n            case \"PaymentReminder\":\n                await HandlePaymentReminder(context, cancellationToken);\n                break;\n\n            case \"OrderExpiration\":\n                await HandleOrderExpiration(cancellationToken);\n                break;\n\n            default:\n                _logger.LogWarning(\"Unknown workflow step: {Step}\", step);\n                break;\n        }\n    }\n\n    private async Task HandlePaymentReminder(IDurableJobContext context, CancellationToken ct)\n    {\n        var orderId = this.GetPrimaryKey();\n        var order = await _orderService.GetOrderAsync(orderId, ct);\n        \n        if (order?.Status == OrderStatus.Pending)\n        {\n            var customerEmail = context.Job.Metadata![\"CustomerEmail\"];\n            var emailGrain = _grainFactory.GetGrain<IEmailGrain>(customerEmail);\n            \n            await emailGrain.ScheduleEmail(\n                \"Payment Reminder\",\n                $\"Your order {orderId} is awaiting payment. Please complete your purchase within 23 hours.\",\n                DateTimeOffset.UtcNow);\n\n            _logger.LogInformation(\"Payment reminder sent for order {OrderId}\", orderId);\n        }\n        else\n        {\n            _logger.LogInformation(\n                \"Skipping payment reminder for order {OrderId} - status is {Status}\",\n                orderId, order?.Status);\n        }\n    }\n\n    private async Task HandleOrderExpiration(CancellationToken ct)\n    {\n        var orderId = this.GetPrimaryKey();\n        var order = await _orderService.GetOrderAsync(orderId, ct);\n        \n        if (order?.Status == OrderStatus.Pending)\n        {\n            await _orderService.CancelOrderAsync(orderId, ct);\n            _logger.LogInformation(\"Order {OrderId} expired and canceled\", orderId);\n\n            // Notify customer\n            var emailGrain = _grainFactory.GetGrain<IEmailGrain>(order.CustomerEmail);\n            await emailGrain.ScheduleEmail(\n                \"Order Expired\",\n                $\"Your order {orderId} has expired due to pending payment.\",\n                DateTimeOffset.UtcNow);\n        }\n        else\n        {\n            _logger.LogInformation(\n                \"Order {OrderId} did not expire - status is {Status}\",\n                orderId, order?.Status);\n        }\n    }\n}\n\n// Supporting types\npublic class OrderDetails\n{\n    public string CustomerId { get; set; } = \"\";\n    public string CustomerEmail { get; set; } = \"\";\n    public decimal Amount { get; set; }\n    public List<OrderItem> Items { get; set; } = new();\n}\n\npublic enum OrderStatus\n{\n    Pending,\n    Paid,\n    Shipped,\n    Delivered,\n    Cancelled\n}\n```\n\n## How It Works\n\n### Storage Architecture\n1. **Blob Container**: All jobs are stored in a single Azure Blob Storage container\n2. **Append Blobs**: Each job shard is stored as an append blob, providing efficient sequential writes\n3. **Blob Naming**: Blobs are named with the pattern: `{ShardStartTime:yyyyMMddHHmm}-{SiloAddress}-{Index}`\n4. **Metadata**: Blob metadata stores ownership and time range information:\n   - `Owner`: The silo currently processing this shard\n   - `Creator`: The silo that created this shard\n   - `MinDueTime`: Start of the time range for jobs in this shard\n   - `MaxDueTime`: End of the time range for jobs in this shard\n\n### Shard Ownership and High Availability\n1. **Optimistic Concurrency**: ETags prevent conflicting updates when multiple silos try to claim a shard\n2. **Ownership Transfer**: When a silo fails, other silos detect the failure and claim orphaned shards\n3. **Creator Priority**: The silo that created a shard gets priority to reclaim it if it loses ownership\n4. **Automatic Cleanup**: Empty shards are deleted automatically after processing\n\n### Job Lifecycle with Azure Storage\n```\n┌─────────────────────┐\n│  Job Scheduled      │ ──▶ Written to append blob\n└─────────────────────┘\n         │\n         ▼\n┌─────────────────────┐\n│  Waiting in Shard   │ ──▶ Persisted in Azure Blob Storage\n└─────────────────────┘\n         │\n         ▼\n┌─────────────────────┐\n│  Shard Owned        │ ──▶ Silo acquires ownership via metadata update\n└─────────────────────┘\n         │\n         ▼\n┌─────────────────────┐\n│  Job Executed       │ ──▶ Handler invoked on target grain\n└─────────────────────┘\n         │\n         ├──▶ Success ──▶ Job entry removed from blob\n         │\n         └──▶ Failure ──▶ Retry: Updated due time in blob\n                          No Retry: Job entry removed\n```\n\n## Performance Considerations\n\n### Concurrency Settings\n```csharp\nservices.Configure<DurableJobsOptions>(options =>\n{\n    // Adjust based on your workload and Azure Storage limits\n    options.MaxConcurrentJobsPerSilo = 50;\n});\n```\n\n### Storage Costs\n- **Container**: One container per cluster\n- **Blobs**: One blob per active time shard\n- **Operations**: \n  - Schedule job: 1-2 append operations\n  - Execute job: 1 read + 1 delete operation\n  - Shard ownership transfer: 1 metadata update\n\n## Monitoring and Troubleshooting\n\n### Enable Logging\n```csharp\nbuilder.Logging.AddFilter(\"Orleans.DurableJobs\", LogLevel.Information);\nbuilder.Logging.AddFilter(\"Orleans.DurableJobs.AzureStorage\", LogLevel.Information);\n```\n\n### Key Metrics to Monitor\n- **Shard Assignment Time**: Time to claim ownership of unassigned shards\n- **Job Execution Latency**: Time between due time and actual execution\n- **Retry Rate**: Percentage of jobs requiring retry\n- **Blob Operations**: Number of read/write/delete operations per minute\n\n## Security Best Practices\n\n### Use Managed Identity\n```csharp\nvar credential = new DefaultAzureCredential();\nvar blobServiceClient = new BlobServiceClient(storageAccountUri, credential);\n```\n\n### Network Security\n- Enable firewall rules to restrict access\n- Use private endpoints for enhanced security\n- Consider Azure Virtual Network integration\n\n### Access Control\n```csharp\n// Minimum required permissions:\n// - Storage Blob Data Contributor (for read/write/delete operations)\n// - Or custom role with:\n//   - Microsoft.Storage/storageAccounts/blobServices/containers/read\n//   - Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read\n//   - Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write\n//   - Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Azure Blob Storage Documentation](https://learn.microsoft.com/azure/storage/blobs/)\n- [Orleans Durable Jobs Core Package](../../../Orleans.DurableJobs/README.md)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/AzureTableGrainDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Web;\nusing Azure;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.GrainDirectory.AzureStorage\n{\n    public class AzureTableGrainDirectory : IGrainDirectory, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly AzureTableDataManager<GrainDirectoryEntity> tableDataManager;\n        private readonly string clusterId;\n\n        internal class GrainDirectoryEntity : ITableEntity\n        {\n            public required string SiloAddress { get; set; }\n            public required string ActivationId { get; set; }\n            public required long MembershipVersion { get; set; }\n            public required string PartitionKey { get; set; }\n            public required string RowKey { get; set; }\n            public DateTimeOffset? Timestamp { get; set; }\n            public ETag ETag { get; set; }\n\n            public GrainAddress ToGrainAddress()\n            {\n                return new GrainAddress\n                {\n                    GrainId = RowKeyToGrainId(this.RowKey),\n                    SiloAddress = Runtime.SiloAddress.FromParsableString(this.SiloAddress),\n                    ActivationId = Runtime.ActivationId.FromParsableString(this.ActivationId),\n                    MembershipVersion = new MembershipVersion(this.MembershipVersion)\n                };\n            }\n\n            public static GrainDirectoryEntity FromGrainAddress(string clusterId, GrainAddress address)\n            {\n                ArgumentNullException.ThrowIfNull(address.SiloAddress);\n\n                return new GrainDirectoryEntity\n                {\n                    PartitionKey = clusterId,\n                    RowKey = GrainIdToRowKey(address.GrainId),\n                    SiloAddress = address.SiloAddress.ToParsableString(),\n                    ActivationId = address.ActivationId.ToParsableString(),\n                    MembershipVersion = address.MembershipVersion.Value,\n                };\n            }\n\n            internal static string GrainIdToRowKey(GrainId grainId) => HttpUtility.UrlEncode(grainId.ToString(), Encoding.UTF8);\n\n            internal static GrainId RowKeyToGrainId(string rowKey) => GrainId.Parse(HttpUtility.UrlDecode(rowKey, Encoding.UTF8));\n        }\n\n        public AzureTableGrainDirectory(\n            AzureTableGrainDirectoryOptions directoryOptions,\n            IOptions<ClusterOptions> clusterOptions,\n            ILoggerFactory loggerFactory)\n        {\n            this.tableDataManager = new AzureTableDataManager<GrainDirectoryEntity>(\n                directoryOptions,\n                loggerFactory.CreateLogger<AzureTableDataManager<GrainDirectoryEntity>>());\n            this.clusterId = clusterOptions.Value.ClusterId;\n        }\n\n        public async Task<GrainAddress?> Lookup(GrainId grainId)\n        {\n            var result = await this.tableDataManager.ReadSingleTableEntryAsync(this.clusterId, GrainDirectoryEntity.GrainIdToRowKey(grainId));\n\n            if (result.Entity is null)\n            {\n                return null;\n            }\n\n            return result.Item1.ToGrainAddress();\n        }\n\n        public Task<GrainAddress?> Register(GrainAddress address) => Register(address, null);\n\n        public async Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress)\n        {\n            (bool isSuccess, string eTag) result;\n            if (previousAddress is not null)\n            {\n                var entry = GrainDirectoryEntity.FromGrainAddress(this.clusterId, address);\n                var previousEntry = GrainDirectoryEntity.FromGrainAddress(this.clusterId, previousAddress);\n                var (storedEntry, eTag) = await tableDataManager.ReadSingleTableEntryAsync(entry.PartitionKey, entry.RowKey);\n                if (storedEntry is null)\n                {\n                    result = await this.tableDataManager.InsertTableEntryAsync(entry);\n                }\n                else if (storedEntry.ActivationId != previousEntry.ActivationId || storedEntry.SiloAddress != previousEntry.SiloAddress)\n                {\n                    return await Lookup(address.GrainId);\n                }\n                else\n                {\n                    _ = await tableDataManager.UpdateTableEntryAsync(entry, eTag);\n                    return address;\n                }\n            }\n            else\n            {\n                var entry = GrainDirectoryEntity.FromGrainAddress(this.clusterId, address);\n                result = await this.tableDataManager.InsertTableEntryAsync(entry);\n            }\n\n            // Possible race condition?\n            return result.isSuccess ? address : await Lookup(address.GrainId);\n        }\n\n        public async Task Unregister(GrainAddress address)\n        {\n            var result = await this.tableDataManager.ReadSingleTableEntryAsync(this.clusterId, GrainDirectoryEntity.GrainIdToRowKey(address.GrainId));\n\n            // No entry found\n            if (result.Entity is null)\n            {\n                return;\n            }\n\n            // Check if the entry in storage match the one we were asked to delete\n            var entity = result.Item1;\n            if (entity.ActivationId == address.ActivationId.ToParsableString())\n                await this.tableDataManager.DeleteTableEntryAsync(GrainDirectoryEntity.FromGrainAddress(this.clusterId, address), entity.ETag.ToString());\n        }\n\n        public async Task UnregisterMany(List<GrainAddress> addresses)\n        {\n            if (addresses.Count <= this.tableDataManager.StoragePolicyOptions.MaxBulkUpdateRows)\n            {\n                await UnregisterManyBlock(addresses);\n            }\n            else\n            {\n                var tasks = new List<Task>();\n                foreach (var subList in addresses.BatchIEnumerable(this.tableDataManager.StoragePolicyOptions.MaxBulkUpdateRows))\n                {\n                    tasks.Add(UnregisterManyBlock(subList));\n                }\n                await Task.WhenAll(tasks);\n            }\n        }\n\n        public Task UnregisterSilos(List<SiloAddress> siloAddresses)\n        {\n            // Too costly to implement using Azure Table\n            return Task.CompletedTask;\n        }\n\n        private async Task UnregisterManyBlock(List<GrainAddress> addresses)\n        {\n            var queryBuilder = new StringBuilder();\n            queryBuilder.Append(TableClient.CreateQueryFilter($\"(PartitionKey eq {clusterId}) and (\"));\n            var first = true;\n            foreach (var addr in addresses)\n            {\n                if (!first)\n                {\n                    queryBuilder.Append(\" or \");\n                }\n                else\n                {\n                    first = false;\n                }\n\n                var rowKey = GrainDirectoryEntity.GrainIdToRowKey(addr.GrainId);\n                var queryClause = TableClient.CreateQueryFilter($\"((RowKey eq {rowKey}) and (ActivationId eq {addr.ActivationId.ToString()}))\");\n                queryBuilder.Append(queryClause);\n            }\n\n            queryBuilder.Append(')');\n            var entities = await this.tableDataManager.ReadTableEntriesAndEtagsAsync(queryBuilder.ToString());\n            await this.tableDataManager.DeleteTableEntriesAsync(entities);\n        }\n\n        // Called by lifecycle, should not be called explicitely, except for tests\n        public async Task InitializeIfNeeded(CancellationToken ct = default)\n        {\n            await this.tableDataManager.InitTableAsync();\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n\n            lifecycle.Subscribe(nameof(AzureTableGrainDirectory), ServiceLifecycleStage.RuntimeInitialize, InitializeIfNeeded);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/Hosting/AzureTableGrainDirectoryExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Hosting\n{\n    public static class AzureTableGrainDirectorySiloBuilderExtensions\n    {\n        public static ISiloBuilder UseAzureTableGrainDirectoryAsDefault(\n            this ISiloBuilder builder,\n            Action<AzureTableGrainDirectoryOptions> configureOptions)\n        {\n            return builder.UseAzureTableGrainDirectoryAsDefault(ob => ob.Configure(configureOptions));\n        }\n\n        public static ISiloBuilder UseAzureTableGrainDirectoryAsDefault(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<AzureTableGrainDirectoryOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableGrainDirectory(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, configureOptions));\n        }\n\n        public static ISiloBuilder AddAzureTableGrainDirectory(\n            this ISiloBuilder builder,\n            string name,\n            Action<AzureTableGrainDirectoryOptions> configureOptions)\n        {\n            return builder.AddAzureTableGrainDirectory(name, ob => ob.Configure(configureOptions));\n        }\n\n        public static ISiloBuilder AddAzureTableGrainDirectory(\n            this ISiloBuilder builder,\n            string name,\n            Action<OptionsBuilder<AzureTableGrainDirectoryOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableGrainDirectory(name, configureOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/Hosting/AzureTableGrainDirectoryServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.GrainDirectory.AzureStorage;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class AzureTableGrainDirectoryServiceCollectionExtensions\n    {\n        internal static IServiceCollection AddAzureTableGrainDirectory(\n            this IServiceCollection services,\n            string name,\n            Action<OptionsBuilder<AzureTableGrainDirectoryOptions>> configureOptions)\n        {\n            configureOptions.Invoke(services.AddOptions<AzureTableGrainDirectoryOptions>(name));\n            services\n                .AddTransient<IConfigurationValidator>(sp => new AzureTableGrainDirectoryOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureTableGrainDirectoryOptions>>().Get(name), name))\n                .ConfigureNamedOptionForLogging<AzureTableGrainDirectoryOptions>(name)\n                .AddGrainDirectory(name, (sp, name) => ActivatorUtilities.CreateInstance<AzureTableGrainDirectory>(sp, sp.GetOptionsByName<AzureTableGrainDirectoryOptions>(name)));\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/Hosting/AzureTableStorageGrainDirectoryProviderBuilder.cs",
    "content": "using System;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AzureTableStorage\", \"GrainDirectory\", \"Silo\", typeof(AzureTableStorageGrainDirectoryProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureTableStorageGrainDirectoryProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureTableGrainDirectory(name, (OptionsBuilder<AzureTableGrainDirectoryOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var tableName = configurationSection[\"TableName\"];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.TableServiceClient = services.GetRequiredKeyedService<TableServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.TableServiceClient = new TableServiceClient(uri);\n                        }\n                        else\n                        {\n                            options.TableServiceClient = new TableServiceClient(connectionString);\n                        }\n                    }\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/Options/AzureTableGrainDirectoryOptions.cs",
    "content": "using Orleans.GrainDirectory.AzureStorage;\n\nnamespace Orleans.Configuration\n{\n    public class AzureTableGrainDirectoryOptions : AzureStorageOperationOptions\n    {\n        /// <summary>\n        /// Table name for Azure Storage\n        /// </summary>\n        public override string TableName { get; set; } = DEFAULT_TABLE_NAME;\n        public const string DEFAULT_TABLE_NAME = \"GrainDirectory\";\n    }\n\n    public class AzureTableGrainDirectoryOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableGrainDirectoryOptions>\n    {\n        public AzureTableGrainDirectoryOptionsValidator(AzureTableGrainDirectoryOptions options, string name) : base(options, name)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/Orleans.GrainDirectory.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.GrainDirectory.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Storage Grain Directory Provider</Title>\n    <Description>Microsoft Orleans Grain Directory provider backed by Azure Storage</Description>\n    <PackageTags>$(PackageTags) Azure Grain Directory</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.GrainDirectory.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.GrainDirectory.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_DIRECTORY</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.GrainDirectory.AzureStorage/README.md",
    "content": "# Microsoft Orleans Grain Directory for Azure Storage\n\n## Introduction\nMicrosoft Orleans Grain Directory for Azure Storage provides a grain directory implementation using Azure Storage. The grain directory is used to locate active grain instances across the cluster, and this package allows Orleans to store that information in Azure Storage.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.GrainDirectory.AzureStorage\n```\n\n## Example - Configuring Azure Storage Grain Directory\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Storage as grain directory\n            .UseAzureStorageGrainDirectoryAsDefault(options =>\n            {\n                options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                options.TableName = \"GrainDirectory\";\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Configuration Guide](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/)\n- [Implementation Details](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/index)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/AzureAppendBlobLogStorage.cs",
    "content": "using Azure;\nusing Azure.Storage.Blobs.Specialized;\nusing Azure.Storage.Blobs.Models;\nusing System.Runtime.CompilerServices;\nusing Azure.Storage.Sas;\nusing Orleans.Serialization.Buffers;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Journaling;\n\ninternal sealed partial class AzureAppendBlobLogStorage : IStateMachineStorage\n{\n    private static readonly AppendBlobCreateOptions CreateOptions = new() { Conditions = new() { IfNoneMatch = ETag.All } };\n    private readonly AppendBlobClient _client;\n    private readonly ILogger<AzureAppendBlobLogStorage> _logger;\n    private readonly LogExtentBuilder.ReadOnlyStream _stream;\n    private readonly AppendBlobAppendBlockOptions _appendOptions;\n    private bool _exists;\n    private int _numBlocks;\n\n    public bool IsCompactionRequested => _numBlocks > 10;\n\n    public AzureAppendBlobLogStorage(AppendBlobClient client, ILogger<AzureAppendBlobLogStorage> logger)\n    {\n        _client = client;\n        _logger = logger;\n        _stream = new();\n\n        // For the first request, if we have not performed a read yet, we want to guard against clobbering an existing blob.\n        _appendOptions = new AppendBlobAppendBlockOptions() { Conditions = new AppendBlobRequestConditions { IfNoneMatch = ETag.All } };\n    }\n\n    public async ValueTask AppendAsync(LogExtentBuilder value, CancellationToken cancellationToken)\n    {\n        if (!_exists)\n        {\n            var response = await _client.CreateAsync(CreateOptions, cancellationToken);\n            _appendOptions.Conditions.IfNoneMatch = default;\n            _appendOptions.Conditions.IfMatch = response.Value.ETag;\n            _exists = true;\n        }\n\n        _stream.SetBuilder(value);\n        var result = await _client.AppendBlockAsync(_stream, _appendOptions, cancellationToken).ConfigureAwait(false);\n        LogAppend(_logger, value.Length, _client.BlobContainerName, _client.Name);\n\n        _stream.Reset();\n        _appendOptions.Conditions.IfNoneMatch = default;\n        _appendOptions.Conditions.IfMatch = result.Value.ETag;\n        _numBlocks = result.Value.BlobCommittedBlockCount;\n    }\n\n    public async ValueTask DeleteAsync(CancellationToken cancellationToken)\n    {\n        var conditions = new BlobRequestConditions { IfMatch = _appendOptions.Conditions.IfMatch };\n        await _client.DeleteAsync(conditions: conditions, cancellationToken: cancellationToken).ConfigureAwait(false);\n\n        // Expect no blob to have been created when we append to it.\n        _appendOptions.Conditions.IfNoneMatch = ETag.All;\n        _appendOptions.Conditions.IfMatch = default;\n        _numBlocks = 0;\n    }\n\n    public async IAsyncEnumerable<LogExtent> ReadAsync([EnumeratorCancellation] CancellationToken cancellationToken)\n    {\n        Response<BlobDownloadStreamingResult> result;\n        try\n        {\n            // If the blob was not newly created, then download the blob.\n            result = await _client.DownloadStreamingAsync(cancellationToken: cancellationToken).ConfigureAwait(false);\n        }\n        catch (RequestFailedException exception) when (exception.Status is 404)\n        {\n            _exists = false;\n            yield break;\n        }\n\n        // If the blob has a size of zero, check for a snapshot and restore the blob from the snapshot if one exists.\n        if (result.Value.Details.ContentLength == 0)\n        {\n            if (result.Value.Details.Metadata.TryGetValue(\"snapshot\", out var snapshot) && snapshot is { Length: > 0 })\n            {\n                result = await CopyFromSnapshotAsync(result.Value.Details.ETag, snapshot, cancellationToken).ConfigureAwait(false);\n            }\n        }\n\n        _numBlocks = result.Value.Details.BlobCommittedBlockCount;\n        _appendOptions.Conditions.IfNoneMatch = default;\n        _appendOptions.Conditions.IfMatch = result.Value.Details.ETag;\n        _exists = true;\n\n        // Read everything into a single log segment. We could change this to read in chunks,\n        // yielding when the stream does not return synchronously, if we wanted to support larger state machines.\n        var rawStream = result.Value.Content;\n        using var buffer = new ArcBufferWriter();\n        while (true)\n        {\n            var mem = buffer.GetMemory();\n            var bytesRead = await rawStream.ReadAsync(mem, cancellationToken);\n            if (bytesRead == 0)\n            {\n                if (buffer.Length > 0)\n                {\n                    LogRead(_logger, buffer.Length, _client.BlobContainerName, _client.Name);\n                    yield return new LogExtent(buffer.ConsumeSlice(buffer.Length));\n                }\n\n                yield break;\n            }\n\n            buffer.AdvanceWriter(bytesRead);\n        }\n    }\n\n    private async Task<Response<BlobDownloadStreamingResult>> CopyFromSnapshotAsync(ETag eTag, string snapshotDetail, CancellationToken cancellationToken)\n    {\n        // Read snapshot and append it to the blob.\n        var snapshot = _client.WithSnapshot(snapshotDetail);\n        var uri = snapshot.GenerateSasUri(permissions: BlobSasPermissions.Read, expiresOn: DateTimeOffset.UtcNow.AddHours(1));\n        var copyResult = await _client.SyncCopyFromUriAsync(\n            uri,\n            new BlobCopyFromUriOptions { DestinationConditions = new BlobRequestConditions { IfNoneMatch = eTag } },\n            cancellationToken).ConfigureAwait(false);\n        if (copyResult.Value.CopyStatus is not CopyStatus.Success)\n        {\n            throw new InvalidOperationException($\"Copy did not complete successfully. Status: {copyResult.Value.CopyStatus}\");\n        }\n\n        var result = await _client.DownloadStreamingAsync(cancellationToken: cancellationToken).ConfigureAwait(false);\n        _exists = true;\n        return result;\n    }\n\n    public async ValueTask ReplaceAsync(LogExtentBuilder value, CancellationToken cancellationToken)\n    {\n        // Create a snapshot of the blob for recovery purposes.\n        var blobSnapshot = await _client.CreateSnapshotAsync(conditions: _appendOptions.Conditions, cancellationToken: cancellationToken).ConfigureAwait(false);\n\n        // Open the blob for writing, overwriting existing contents.\n        var createOptions = new AppendBlobCreateOptions()\n        {\n            Conditions = _appendOptions.Conditions,\n            Metadata = new Dictionary<string, string> { [\"snapshot\"] = blobSnapshot.Value.Snapshot },\n        };\n        var createResult = await _client.CreateAsync(createOptions, cancellationToken).ConfigureAwait(false);\n        _appendOptions.Conditions.IfMatch = createResult.Value.ETag;\n        _appendOptions.Conditions.IfNoneMatch = default;\n\n        // Write the state machine snapshot.\n        _stream.SetBuilder(value);\n        var result = await _client.AppendBlockAsync(_stream, _appendOptions, cancellationToken).ConfigureAwait(false);\n        LogReplace(_logger, _client.BlobContainerName, _client.Name, value.Length);\n\n        _stream.Reset();\n        _appendOptions.Conditions.IfNoneMatch = default;\n        _appendOptions.Conditions.IfMatch = result.Value.ETag;\n        _numBlocks = result.Value.BlobCommittedBlockCount;\n\n        // Delete the blob snapshot.\n        await _client.WithSnapshot(blobSnapshot.Value.Snapshot).DeleteAsync(cancellationToken: cancellationToken).ConfigureAwait(false);\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Appended {Length} bytes to blob \\\"{ContainerName}/{BlobName}\\\"\")]\n    private static partial void LogAppend(ILogger logger, long length, string containerName, string blobName);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Read {Length} bytes from blob \\\"{ContainerName}/{BlobName}\\\"\")]\n    private static partial void LogRead(ILogger logger, long length, string containerName, string blobName);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Replaced blob \\\"{ContainerName}/{BlobName}\\\", writing {Length} bytes\")]\n    private static partial void LogReplace(ILogger logger, string containerName, string blobName, long length);\n\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/AzureAppendBlobStateMachineStorageOptions.cs",
    "content": "using Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage;\nusing Azure.Core;\nusing Orleans.Runtime;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// Options for configuring the Azure Append Blob state machine storage provider.\n/// </summary>\npublic sealed class AzureAppendBlobStateMachineStorageOptions\n{\n    private BlobServiceClient? _blobServiceClient;\n\n    /// <summary>\n    /// Container name where state machine state is stored.\n    /// </summary>\n    public string ContainerName { get; set; } = DEFAULT_CONTAINER_NAME;\n    public const string DEFAULT_CONTAINER_NAME = \"state\";\n\n    /// <summary>\n    /// Gets or sets the delegate used to generate the blob name for a given grain.\n    /// </summary>\n    public Func<GrainId, string> GetBlobName { get; set; } = DefaultGetBlobName;\n\n    private static readonly Func<GrainId, string> DefaultGetBlobName = static (GrainId grainId) => $\"{grainId}.bin\";\n\n    /// <summary>\n    /// Options to be used when configuring the blob storage client, or <see langword=\"null\"/> to use the default options.\n    /// </summary>\n    public BlobClientOptions? ClientOptions { get; set; }\n\n    /// <summary>\n    /// Gets or sets the client used to access the Azure Blob Service.\n    /// </summary>\n    public BlobServiceClient? BlobServiceClient\n    {\n        get => _blobServiceClient;\n        set\n        {\n            ArgumentNullException.ThrowIfNull(value);\n            _blobServiceClient = value;\n            CreateClient = ct => Task.FromResult(value);\n        }\n    }\n\n    /// <summary>\n    /// The optional delegate used to create a <see cref=\"BlobServiceClient\"/> instance.\n    /// </summary>\n    internal Func<CancellationToken, Task<BlobServiceClient>>? CreateClient { get; private set; }\n\n    /// <summary>\n    /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n    /// </summary>\n    public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n    public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n    /// <summary>\n    /// A function for building container factory instances.\n    /// </summary>\n    public Func<IServiceProvider, AzureAppendBlobStateMachineStorageOptions, IBlobContainerFactory> BuildContainerFactory { get; set; }\n        = static (provider, options) => new DefaultBlobContainerFactory(options);\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using a connection string.\n    /// </summary>\n    public void ConfigureBlobServiceClient(string connectionString)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(connectionString);\n        CreateClient = ct => Task.FromResult(new BlobServiceClient(connectionString, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI.\n    /// </summary>\n    public void ConfigureBlobServiceClient(Uri serviceUri)\n    {\n        ArgumentNullException.ThrowIfNull(serviceUri);\n        CreateClient = ct => Task.FromResult(new BlobServiceClient(serviceUri, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using the provided callback.\n    /// </summary>\n    public void ConfigureBlobServiceClient(Func<CancellationToken, Task<BlobServiceClient>> createClientCallback)\n    {\n        CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n    }\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"TokenCredential\"/>.\n    /// </summary>\n    public void ConfigureBlobServiceClient(Uri serviceUri, TokenCredential tokenCredential)\n    {\n        ArgumentNullException.ThrowIfNull(serviceUri);\n        ArgumentNullException.ThrowIfNull(tokenCredential);\n        CreateClient = ct => Task.FromResult(new BlobServiceClient(serviceUri, tokenCredential, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"AzureSasCredential\"/>.\n    /// </summary>\n    public void ConfigureBlobServiceClient(Uri serviceUri, AzureSasCredential azureSasCredential)\n    {\n        ArgumentNullException.ThrowIfNull(serviceUri);\n        ArgumentNullException.ThrowIfNull(azureSasCredential);\n        CreateClient = ct => Task.FromResult(new BlobServiceClient(serviceUri, azureSasCredential, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"StorageSharedKeyCredential\"/>.\n    /// </summary>\n    public void ConfigureBlobServiceClient(Uri serviceUri, StorageSharedKeyCredential sharedKeyCredential)\n    {\n        ArgumentNullException.ThrowIfNull(serviceUri);\n        ArgumentNullException.ThrowIfNull(sharedKeyCredential);\n        CreateClient = ct => Task.FromResult(new BlobServiceClient(serviceUri, sharedKeyCredential, ClientOptions));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/AzureAppendBlobStateMachineStorageProvider.cs",
    "content": "using Azure.Storage.Blobs.Specialized;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Journaling;\n\ninternal sealed class AzureAppendBlobStateMachineStorageProvider(\n    IOptions<AzureAppendBlobStateMachineStorageOptions> options,\n    IServiceProvider serviceProvider,\n    ILogger<AzureAppendBlobLogStorage> logger) : IStateMachineStorageProvider, ILifecycleParticipant<ISiloLifecycle>\n{\n    private readonly IBlobContainerFactory _containerFactory = options.Value.BuildContainerFactory(serviceProvider, options.Value);\n    private readonly AzureAppendBlobStateMachineStorageOptions _options = options.Value;\n\n    private async Task Initialize(CancellationToken cancellationToken)\n    {\n        var client = await _options.CreateClient!(cancellationToken);\n        await _containerFactory.InitializeAsync(client, cancellationToken).ConfigureAwait(false);\n    }\n\n    public IStateMachineStorage Create(IGrainContext grainContext)\n    {\n        var container = _containerFactory.GetBlobContainerClient(grainContext.GrainId);\n        var blobName = _options.GetBlobName(grainContext.GrainId);\n        var blobClient = container.GetAppendBlobClient(blobName);\n        return new AzureAppendBlobLogStorage(blobClient, logger);\n    }\n\n    public void Participate(ISiloLifecycle observer)\n    {\n        observer.Subscribe(\n            nameof(AzureAppendBlobStateMachineStorageProvider),\n            ServiceLifecycleStage.RuntimeInitialize,\n            onStart: Initialize);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/AzureBlobStorageGrainJournalingProviderBuilder.cs",
    "content": "using Azure.Storage.Blobs;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Journaling;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AzureBlobStorage\", \"GrainJournaling\", \"Silo\", typeof(AzureBlobStorageGrainJournalingProviderBuilder))]\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureBlobStorageGrainJournalingProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string? name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureAppendBlobStateMachineStorage();\n        var optionsBuilder = builder.Services.AddOptions<AzureAppendBlobStateMachineStorageOptions>();\n        optionsBuilder.Configure<IServiceProvider>((options, services) =>\n        {\n            var containerName = configurationSection[\"ContainerName\"];\n            if (!string.IsNullOrEmpty(containerName))\n            {\n                options.ContainerName = containerName;\n            }\n\n            var serviceKey = configurationSection[\"ServiceKey\"];\n            if (!string.IsNullOrEmpty(serviceKey))\n            {\n                // Get a client by name.\n                options.BlobServiceClient = services.GetRequiredKeyedService<BlobServiceClient>(serviceKey);\n            }\n            else\n            {\n                // Construct a connection multiplexer from a connection string.\n                var connectionName = configurationSection[\"ConnectionName\"];\n                var connectionString = configurationSection[\"ConnectionString\"];\n                if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                {\n                    var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                    connectionString = rootConfiguration.GetConnectionString(connectionName);\n                }\n\n                if (!string.IsNullOrEmpty(connectionString))\n                {\n                    if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                    {\n                        options.BlobServiceClient = new(uri);\n                    }\n                    else\n                    {\n                        options.BlobServiceClient = new(connectionString);\n                    }\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/AzureBlobStorageHostingExtensions.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\nusing Orleans.Hosting;\n\nnamespace Orleans.Journaling;\n\npublic static class AzureBlobStorageHostingExtensions\n{\n    public static ISiloBuilder AddAzureAppendBlobStateMachineStorage(this ISiloBuilder builder) => builder.AddAzureAppendBlobStateMachineStorage(configure: null);\n    public static ISiloBuilder AddAzureAppendBlobStateMachineStorage(this ISiloBuilder builder, Action<AzureAppendBlobStateMachineStorageOptions>? configure)\n    {\n        builder.AddStateMachineStorage();\n\n        var services = builder.Services;\n\n        var options = builder.Services.AddOptions<AzureAppendBlobStateMachineStorageOptions>();\n        if (configure is not null)\n        {\n            options.Configure(configure);\n        }\n\n        if (services.Any(service => service.ServiceType.Equals(typeof(AzureAppendBlobStateMachineStorageProvider))))\n        {\n            return builder;\n        }\n\n        builder.Services.AddSingleton<AzureAppendBlobStateMachineStorageProvider>();\n        builder.Services.AddFromExisting<IStateMachineStorageProvider, AzureAppendBlobStateMachineStorageProvider>();\n        builder.Services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, AzureAppendBlobStateMachineStorageProvider>();\n        return builder;\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/DefaultBlobContainerFactory.cs",
    "content": "﻿using Azure.Storage.Blobs;\nusing Orleans.Runtime;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// A default blob container factory that uses the default container name.\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"DefaultBlobContainerFactory\"/> class.\n/// </remarks>\n/// <param name=\"options\">The blob storage options</param>\ninternal sealed class DefaultBlobContainerFactory(AzureAppendBlobStateMachineStorageOptions options) : IBlobContainerFactory\n{\n    private BlobContainerClient _defaultContainer = null!;\n\n    /// <inheritdoc/>\n    public BlobContainerClient GetBlobContainerClient(GrainId grainId) => _defaultContainer;\n\n    /// <inheritdoc/>\n    public async Task InitializeAsync(BlobServiceClient client, CancellationToken cancellationToken)\n    {\n        _defaultContainer = client.GetBlobContainerClient(options.ContainerName);\n        await _defaultContainer.CreateIfNotExistsAsync(cancellationToken: cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/IBlobContainerFactory.cs",
    "content": "﻿using Azure.Storage.Blobs;\nusing Orleans.Runtime;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// A factory for building container clients for blob storage using GrainId\n/// </summary>\npublic interface IBlobContainerFactory\n{\n    /// <summary>\n    /// Gets the container which should be used for the specified grain.\n    /// </summary>\n    /// <param name=\"grainId\">The grain id</param>\n    /// <returns>A configured blob client</returns>\n    public BlobContainerClient GetBlobContainerClient(GrainId grainId);\n\n    /// <summary>\n    /// Initialize any required dependencies using the provided client and options.\n    /// </summary>\n    /// <param name=\"client\">The connected blob client</param>\n    /// <param name=\"cancellationToken\">A token used to cancel the request.</param>\n    /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation.</returns>\n    public Task InitializeAsync(BlobServiceClient client, CancellationToken cancellationToken);\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/Orleans.Journaling.AzureStorage.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Journaling.AzureStorage</PackageId>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <VersionSuffix Condition=\"$(VersionSuffix) != ''\">$(VersionSuffix).alpha.1</VersionSuffix>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Storage.Blobs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Journaling\\Orleans.Journaling.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Journaling.Tests\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/Properties/AssemblyInfo.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\n[assembly: Experimental(\"ORLEANSEXP005\")]\n"
  },
  {
    "path": "src/Azure/Orleans.Journaling.AzureStorage/README.md",
    "content": "# Microsoft Orleans Journaling for Azure Storage\n\n## Introduction\nMicrosoft Orleans Journaling for Azure Storage provides an Azure Storage implementation of the Orleans Journaling provider. This allows logging and tracking of grain operations using Azure Storage as a backing store.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Journaling.AzureStorage\n```\n\n## Example - Configuring Azure Storage Journaling\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Configuration;\nusing System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing MyGrainNamespace;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Storage as a journaling provider\n            .AddAzureAppendBlobStateMachineStorage(optionsBuilder =>\n            {\n                optionsBuilder.Configure((options, serviceProvider) => options.BlobServiceClient = serviceProvider.GetRequiredService<BlobServiceClient>());\n            });\n    });\n\nvar host = await builder.StartAsync();\n\n// Get a reference to the grain\nvar shoppingCart = host.Services.GetRequiredService<IGrainFactory>()\n    .GetGrain<IShoppingCartGrain>(\"user1-cart\");\n\n// Use the grain\nawait shoppingCart.UpdateItem(\"apple\", 5, 0);\nawait shoppingCart.UpdateItem(\"banana\", 3, 1);\n\n// Get and print the cart contents\nvar (contents, version) = await shoppingCart.GetCart();\nConsole.WriteLine($\"Shopping cart (version {version}):\");\nforeach (var item in contents)\n{\n    Console.WriteLine($\"- {item.Key}: {item.Value}\");\n}\n\n// Wait for the application to terminate\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Using Journaling in a Grain\n```csharp\nusing Orleans.Runtime;\n\nnamespace MyGrainNamespace;\n\npublic interface IShoppingCartGrain : IGrain\n{\n    ValueTask<(bool success, long version)> UpdateItem(string itemId, int quantity, long version);\n    ValueTask<(Dictionary<string, int> Contents, long Version)> GetCart();\n    ValueTask<long> GetVersion();\n    ValueTask<(bool success, long version)> Clear(long version);\n}\n\npublic class ShoppingCartGrain(\n    [FromKeyedServices(\"shopping-cart\")] IDurableDictionary cart,\n    [FromKeyedServices(\"version\")] IDurableValue<long> version) : DurableGrain, IShoppingCartGrain\n{\n    private readonly IDurableValue<long> _version = version;\n\n    public async ValueTask<(bool success, long version)> UpdateItem(string itemId, int quantity, long version)\n    {\n        if (_version.Value != version)\n        {\n            // Conflict\n            return (false, _version.Value);\n        }\n\n        if (quantity == 0)\n        {\n            cart.Remove(itemId);\n        }\n        else\n        {\n            cart[itemId] = quantity;\n        }\n\n        _version.Value++;\n        await WriteStateAsync();\n        return (true, _version.Value);\n    }\n\n    public ValueTask<(Dictionary<string, int> Contents, long Version)> GetCart() => new((cart.ToDictionary(), _version.Value));\n    public ValueTask<long> GetVersion() => new(_version.Value);\n\n    public async ValueTask<(bool success, long version)> Clear(long version)\n    {\n        if (_version.Value != version)\n        {\n            // Conflict\n            return (false, _version.Value);\n        }\n\n        cart.Clear();\n        _version.Value++;\n        await WriteStateAsync();\n        return (true, _version.Value);\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Journaling](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/event-sourcing)\n- [Event Sourcing Grains](https://learn.microsoft.com/en-us/dotnet/orleans/grains/event-sourcing)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Hosting/AzureBlobGrainStorageServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class AzureBlobGrainStorageServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configure silo to use azure blob storage as the default grain storage.\n        /// </summary>\n        public static IServiceCollection AddAzureBlobGrainStorageAsDefault(this IServiceCollection services, Action<AzureBlobStorageOptions> configureOptions)\n        {\n            return services.AddAzureBlobGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage for grain storage.\n        /// </summary>\n        public static IServiceCollection AddAzureBlobGrainStorage(this IServiceCollection services, string name, Action<AzureBlobStorageOptions> configureOptions)\n        {\n            return services.AddAzureBlobGrainStorage(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage as the default grain storage.\n        /// </summary>\n        public static IServiceCollection AddAzureBlobGrainStorageAsDefault(this IServiceCollection services, Action<OptionsBuilder<AzureBlobStorageOptions>> configureOptions = null)\n        {\n            return services.AddAzureBlobGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage for grain storage.\n        /// </summary>\n        public static IServiceCollection AddAzureBlobGrainStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<AzureBlobStorageOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<AzureBlobStorageOptions>(name));\n            services.AddTransient<IConfigurationValidator>(sp => new AzureBlobStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureBlobStorageOptions>>().Get(name), name));\n            services.AddTransient<IPostConfigureOptions<AzureBlobStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<AzureBlobStorageOptions>>();\n            services.ConfigureNamedOptionForLogging<AzureBlobStorageOptions>(name);\n            return services.AddGrainStorage(name, AzureBlobGrainStorageFactory.Create);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Hosting/AzureBlobSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    public static class AzureBlobSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use azure blob storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureBlobGrainStorageAsDefault(this ISiloBuilder builder, Action<AzureBlobStorageOptions> configureOptions)\n        {\n            return builder.AddAzureBlobGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureBlobGrainStorage(this ISiloBuilder builder, string name, Action<AzureBlobStorageOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAzureBlobGrainStorage(name, configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureBlobGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<AzureBlobStorageOptions>> configureOptions = null)\n        {\n            return builder.AddAzureBlobGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureBlobGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<AzureBlobStorageOptions>> configureOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddAzureBlobGrainStorage(name, configureOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Hosting/AzureBlobStorageGrainStorageProviderBuilder.cs",
    "content": "using System;\nusing Azure.Storage.Blobs;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"AzureBlobStorage\", \"GrainStorage\", \"Silo\", typeof(AzureBlobStorageGrainStorageProviderBuilder))]\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureBlobStorageGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureBlobGrainStorage(name, (OptionsBuilder<AzureBlobStorageOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var containerName = configurationSection[\"ContainerName\"];\n                if (!string.IsNullOrEmpty(containerName))\n                {\n                    options.ContainerName = containerName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.BlobServiceClient = services.GetRequiredKeyedService<BlobServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.BlobServiceClient = new(uri);\n                        }\n                        else\n                        {\n                            options.BlobServiceClient = new(connectionString);\n                        }\n                    }\n                }\n\n                var serializerKey = configurationSection[\"SerializerKey\"];\n                if (!string.IsNullOrEmpty(serializerKey))\n                {\n                    options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Hosting/AzureTableSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\n\nnamespace Orleans.Hosting\n{\n    public static class AzureTableSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use azure table storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableGrainStorageAsDefault(this ISiloBuilder builder, Action<AzureTableStorageOptions> configureOptions)\n        {\n            return builder.AddAzureTableGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableGrainStorage(this ISiloBuilder builder, string name, Action<AzureTableStorageOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableGrainStorage(name, ob => ob.Configure(configureOptions)));\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage as the default grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<AzureTableStorageOptions>> configureOptions = null)\n        {\n            return builder.AddAzureTableGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage for grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<AzureTableStorageOptions>> configureOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableGrainStorage(name, configureOptions));\n        }\n\n        internal static IServiceCollection AddAzureTableGrainStorage(\n            this IServiceCollection services,\n            string name,\n            Action<OptionsBuilder<AzureTableStorageOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<AzureTableStorageOptions>(name));\n            services.AddTransient<IConfigurationValidator>(sp => new AzureTableGrainStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureTableStorageOptions>>().Get(name), name));\n            services.AddTransient<IPostConfigureOptions<AzureTableStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<AzureTableStorageOptions>>();\n            services.ConfigureNamedOptionForLogging<AzureTableStorageOptions>(name);\n            return services.AddGrainStorage(name, AzureTableGrainStorageFactory.Create);\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Hosting/AzureTableStorageGrainStorageProviderBuilder.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"AzureTableStorage\", \"GrainStorage\", \"Silo\", typeof(AzureTableStorageGrainStorageProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureTableStorageGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureTableGrainStorage(name, (OptionsBuilder<AzureTableStorageOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var tableName = configurationSection[\"TableName\"];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.TableServiceClient = services.GetRequiredKeyedService<TableServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.TableServiceClient = new TableServiceClient(uri);\n                        }\n                        else\n                        {\n                            options.TableServiceClient = new TableServiceClient(connectionString);\n                        }\n                    }\n                }\n\n                var serializerKey = configurationSection[\"SerializerKey\"];\n                if (!string.IsNullOrEmpty(serializerKey))\n                {\n                    options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Orleans.Persistence.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Persistence.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Storage Persistence Provider</Title>\n    <Description>Microsoft Orleans persistence providers backed by Azure Storage</Description>\n    <PackageTags>$(PackageTags) Azure Table Blob Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Persistence.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.Persistence.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_PERSISTENCE</DefineConstants>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureBlobUtils.cs\" Link=\"Storage\\AzureBlobUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Storage.Blobs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/AzureProviderErrorCode.cs",
    "content": "namespace Orleans.Providers.Azure\n{\n    internal enum AzureProviderErrorCode\n    {\n        ProvidersBase = 200000,\n\n        // Azure storage provider related\n        AzureTableProviderBase                      = ProvidersBase + 100,\n        AzureTableProvider_DataNotFound             = AzureTableProviderBase + 1,\n        AzureTableProvider_ReadingData              = AzureTableProviderBase + 2,\n        AzureTableProvider_WritingData              = AzureTableProviderBase + 3,\n        AzureTableProvider_Storage_Reading          = AzureTableProviderBase + 4,\n        AzureTableProvider_Storage_Writing          = AzureTableProviderBase + 5,\n        AzureTableProvider_Storage_DataRead         = AzureTableProviderBase + 6,\n        AzureTableProvider_WriteError               = AzureTableProviderBase + 7,\n        AzureTableProvider_DeleteError              = AzureTableProviderBase + 8,\n        AzureTableProvider_InitProvider             = AzureTableProviderBase + 9,\n        AzureTableProvider_ParamConnectionString    = AzureTableProviderBase + 10,\n\n        AzureBlobProviderBase                       = ProvidersBase + 300,\n        AzureBlobProvider_BlobNotFound              = AzureBlobProviderBase + 1,\n        AzureBlobProvider_ContainerNotFound         = AzureBlobProviderBase + 2,\n        AzureBlobProvider_BlobEmpty                 = AzureBlobProviderBase + 3,\n        AzureBlobProvider_ReadingData               = AzureBlobProviderBase + 4,\n        AzureBlobProvider_WritingData               = AzureBlobProviderBase + 5,\n        AzureBlobProvider_Storage_Reading           = AzureBlobProviderBase + 6,\n        AzureBlobProvider_Storage_Writing           = AzureBlobProviderBase + 7,\n        AzureBlobProvider_Storage_DataRead          = AzureBlobProviderBase + 8,\n        AzureBlobProvider_WriteError                = AzureBlobProviderBase + 9,\n        AzureBlobProvider_DeleteError               = AzureBlobProviderBase + 10,\n        AzureBlobProvider_InitProvider              = AzureBlobProviderBase + 11,\n        AzureBlobProvider_ParamConnectionString     = AzureBlobProviderBase + 12,\n        AzureBlobProvider_ReadError                 = AzureBlobProviderBase + 13,\n        AzureBlobProvider_ClearError                = AzureBlobProviderBase + 14,\n        AzureBlobProvider_ClearingData              = AzureBlobProviderBase + 15,\n        AzureBlobProvider_Cleared                   = AzureBlobProviderBase + 16,\n\n\n\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/AzureBlobStorage.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Models;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Azure;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Simple storage provider for writing grain state data to Azure blob storage in JSON format.\n    /// </summary>\n    public partial class AzureBlobGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly ILogger logger;\n        private readonly string name;\n        private readonly IBlobContainerFactory blobContainerFactory;\n        private readonly IActivatorProvider _activatorProvider;\n        private readonly AzureBlobStorageOptions options;\n        private readonly IGrainStorageSerializer grainStorageSerializer;\n\n        /// <summary> Default constructor </summary>\n        public AzureBlobGrainStorage(\n            string name,\n            AzureBlobStorageOptions options,\n            IBlobContainerFactory blobContainerFactory,\n            IActivatorProvider activatorProvider,\n            ILogger<AzureBlobGrainStorage> logger)\n        {\n            this.name = name;\n            this.options = options;\n            this.blobContainerFactory = blobContainerFactory;\n            _activatorProvider = activatorProvider;\n            this.grainStorageSerializer = options.GrainStorageSerializer;\n            this.logger = logger;\n        }\n\n        /// <summary> Read state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ReadStateAsync{T}\"/>\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var blobName = GetBlobName(grainType, grainId);\n            var container = this.blobContainerFactory.GetBlobContainerClient(grainId);\n\n            LogTraceReading(grainType, grainId, grainState.ETag, blobName, container.Name);\n\n            try\n            {\n                var blob = container.GetBlobClient(blobName);\n\n                var response = await blob.DownloadContentAsync();\n                grainState.ETag = response.Value.Details.ETag.ToString();\n                var contents = response.Value.Content;\n                T? loadedState;\n                if (contents is null || contents.IsEmpty)\n                {\n                    loadedState = default;\n                    LogTraceBlobEmptyReading(grainType, grainId, grainState.ETag, blobName, container.Name);\n                }\n                else\n                {\n                    loadedState = this.ConvertFromStorageFormat<T>(contents);\n                    LogTraceDataRead(grainType, grainId, grainState.ETag, blobName, container.Name);\n                }\n\n                grainState.State = loadedState ?? CreateInstance<T>();\n                grainState.RecordExists = loadedState is not null;\n            }\n            catch (RequestFailedException ex) when (ex.IsNotFound())\n            {\n                ResetGrainState(grainState);\n                if (ex.IsBlobNotFound())\n                {\n                    LogTraceBlobNotFoundReading(grainType, grainId, grainState.ETag, blobName, container.Name);\n                }\n                else if (ex.IsContainerNotFound())\n                {\n                    LogTraceContainerNotFoundReading(grainType, grainId, grainState.ETag, blobName, container.Name);\n                }\n            }\n            catch (Exception ex)\n            {\n                LogErrorReading(ex, grainType, grainId, grainState.ETag, blobName, container.Name);\n                throw;\n            }\n        }\n\n        private void ResetGrainState<T>(IGrainState<T> grainState)\n        {\n            grainState.ETag = null;\n            grainState.RecordExists = false;\n            grainState.State = CreateInstance<T>();\n        }\n\n        private static string GetBlobName(string grainType, GrainId grainId) => $\"{grainType}-{grainId}.json\";\n\n        /// <summary> Write state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.WriteStateAsync{T}\"/>\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var blobName = GetBlobName(grainType, grainId);\n            var container = this.blobContainerFactory.GetBlobContainerClient(grainId);\n\n            try\n            {\n                LogTraceWriting(grainType, grainId, grainState.ETag, blobName, container.Name);\n\n                var contents = ConvertToStorageFormat(grainState.State);\n\n                var blob = container.GetBlobClient(blobName);\n\n                await WriteStateAndCreateContainerIfNotExists(grainType, grainId, grainState, contents, \"application/octet-stream\", blob);\n\n                LogTraceDataWritten(grainType, grainId, grainState.ETag, blobName, container.Name);\n            }\n            catch (Exception ex)\n            {\n                LogErrorWriting(ex, grainType, grainId, grainState.ETag, blobName, container.Name);\n\n                throw;\n            }\n        }\n\n        /// <summary> Clear / Delete state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ClearStateAsync{T}\"/>\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var blobName = GetBlobName(grainType, grainId);\n            var container = this.blobContainerFactory.GetBlobContainerClient(grainId);\n\n            try\n            {\n                LogTraceClearing(grainType, grainId, grainState.ETag, blobName, container.Name);\n\n                var blob = container.GetBlobClient(blobName);\n\n                var conditions = string.IsNullOrEmpty(grainState.ETag)\n                    ? new BlobRequestConditions { IfNoneMatch = ETag.All }\n                    : new BlobRequestConditions { IfMatch = new ETag(grainState.ETag) };\n\n                if (options.DeleteStateOnClear)\n                {\n                    await DoOptimisticUpdate(\n                        static state => state.blob.DeleteIfExistsAsync(DeleteSnapshotsOption.None, conditions: state.conditions),\n                        (blob, conditions),\n                        blob,\n                        grainState.ETag).ConfigureAwait(false);\n                    grainState.ETag = null;\n                }\n                else\n                {\n                    var options = new BlobUploadOptions { Conditions = conditions };\n                    var response = await DoOptimisticUpdate(\n                        static state => state.blob.UploadAsync(BinaryData.Empty, state.options),\n                        (blob, options, conditions),\n                        blob,\n                        grainState.ETag).ConfigureAwait(false);\n                    grainState.ETag = response.Value.ETag.ToString();\n                }\n\n                grainState.RecordExists = false;\n                grainState.State = CreateInstance<T>();\n                LogTraceCleared(grainType, grainId, grainState.ETag, blobName, container.Name);\n            }\n            catch (Exception ex)\n            {\n                LogErrorClearing(ex, grainType, grainId, grainState.ETag, blobName, container.Name);\n\n                throw;\n            }\n        }\n\n        private async Task WriteStateAndCreateContainerIfNotExists<T>(string grainType, GrainId grainId, IGrainState<T> grainState, BinaryData contents, string mimeType, BlobClient blob)\n        {\n            var container = this.blobContainerFactory.GetBlobContainerClient(grainId);\n\n            try\n            {\n                var conditions = string.IsNullOrEmpty(grainState.ETag)\n                    ? new BlobRequestConditions { IfNoneMatch = ETag.All }\n                    : new BlobRequestConditions { IfMatch = new ETag(grainState.ETag) };\n\n                var options = new BlobUploadOptions\n                {\n                    HttpHeaders = new BlobHttpHeaders { ContentType = mimeType },\n                    Conditions = conditions,\n                };\n\n                var result = await DoOptimisticUpdate(\n                    static state => state.blob.UploadAsync(state.contents, state.options),\n                    (blob, contents, options),\n                    blob,\n                    grainState.ETag)\n                        .ConfigureAwait(false);\n\n                grainState.ETag = result.Value.ETag.ToString();\n                grainState.RecordExists = true;\n            }\n            catch (RequestFailedException exception) when (exception.IsContainerNotFound())\n            {\n                // if the container does not exist, create it, and make another attempt\n                LogTraceContainerNotFound(grainType, grainId, grainState.ETag, blob.Name, container.Name);\n                await container.CreateIfNotExistsAsync().ConfigureAwait(false);\n\n                await WriteStateAndCreateContainerIfNotExists(grainType, grainId, grainState, contents, mimeType, blob).ConfigureAwait(false);\n            }\n        }\n\n        private static async Task<TResult> DoOptimisticUpdate<TState, TResult>(Func<TState, Task<TResult>> updateOperation, TState state, BlobClient blob, string currentETag)\n        {\n            try\n            {\n                return await updateOperation(state).ConfigureAwait(false);\n            }\n            catch (RequestFailedException ex) when (ex.IsPreconditionFailed() || ex.IsConflict() || ex.IsNotFound() && !ex.IsContainerNotFound())\n            {\n                throw new InconsistentStateException($\"Blob storage condition not Satisfied. BlobName: {blob.Name}, Container: {blob.BlobContainerName}, CurrentETag: {currentETag}\", \"Unknown\", currentETag, ex);\n            }\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<AzureBlobGrainStorage>(this.name), this.options.InitStage, Init);\n        }\n\n        /// <summary> Initialization function for this storage provider. </summary>\n        private async Task Init(CancellationToken ct)\n        {\n            var stopWatch = Stopwatch.StartNew();\n\n            try\n            {\n                LogDebugInitializing(this.name, this.options.ContainerName);\n                if (options.CreateClient is not { } createClient)\n                {\n                    throw new OrleansConfigurationException($\"No credentials specified. Use the {options.GetType().Name}.{nameof(AzureBlobStorageOptions.ConfigureBlobServiceClient)} method to configure the Azure Blob Service client.\");\n                }\n\n                var client = await createClient();\n                await this.blobContainerFactory.InitializeAsync(client);\n                stopWatch.Stop();\n                LogInformationInitProvider(this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds);\n            }\n            catch (Exception ex)\n            {\n                stopWatch.Stop();\n                LogErrorFromInit(ex, this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Serialize to the configured storage format\n        /// </summary>\n        /// <param name=\"grainState\">The grain state data to be serialized</param>\n        private BinaryData ConvertToStorageFormat<T>(T grainState) => this.grainStorageSerializer.Serialize(grainState);\n\n        /// <summary>\n        /// Deserialize from the configured storage format\n        /// </summary>\n        /// <param name=\"contents\">The serialized contents.</param>\n        private T? ConvertFromStorageFormat<T>(BinaryData contents) => this.grainStorageSerializer.Deserialize<T>(contents);\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_Storage_Reading,\n            Message = \"Reading: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceReading(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_BlobEmpty,\n            Message = \"BlobEmpty reading: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceBlobEmptyReading(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_Storage_DataRead,\n            Message = \"Read: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceDataRead(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_ReadError,\n            Message = \"Error reading: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogErrorReading(Exception exception, string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_BlobNotFound,\n            Message = \"BlobNotFound reading: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceBlobNotFoundReading(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_ContainerNotFound,\n            Message = \"ContainerNotFound reading: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceContainerNotFoundReading(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_Storage_Writing,\n            Message = \"Writing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceWriting(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_Storage_DataRead,\n            Message = \"Written: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceDataWritten(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_WriteError,\n            Message = \"Error writing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogErrorWriting(Exception exception, string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_ClearingData,\n            Message = \"Clearing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceClearing(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_Cleared,\n            Message = \"Cleared: GrainType={GrainType} GrainId={GrainId} ETag={ETag} BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceCleared(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_ClearError,\n            Message = \"Error clearing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogErrorClearing(Exception exception, string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_ContainerNotFound,\n            Message = \"Creating container: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to BlobName={BlobName} in Container={ContainerName}\"\n        )]\n        private partial void LogTraceContainerNotFound(string grainType, GrainId grainId, string? eTag, string blobName, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_InitProvider,\n            Message = \"AzureBlobGrainStorage {Name} is initializing: ContainerName={ContainerName}\"\n        )]\n        private partial void LogDebugInitializing(string name, string containerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)AzureProviderErrorCode.AzureBlobProvider_InitProvider,\n            Message = \"Initializing provider {ProviderName} of type {ProviderType} in stage {Stage} took {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private partial void LogInformationInitProvider(string providerName, string providerType, int stage, long elapsedMilliseconds);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Provider_ErrorFromInit, Message = \"Initialization failed for provider {ProviderName} of type {ProviderType} in stage {Stage} in {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private partial void LogErrorFromInit(Exception exception, string providerName, string providerType, int stage, long elapsedMilliseconds);\n    }\n\n    public static class AzureBlobGrainStorageFactory\n    {\n        public static AzureBlobGrainStorage Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<AzureBlobStorageOptions>>();\n            var options = optionsMonitor.Get(name);\n\n            var containerFactory = options.BuildContainerFactory(services, options);\n\n            return ActivatorUtilities.CreateInstance<AzureBlobGrainStorage>(services, name, options, containerFactory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/AzureBlobStorageOptions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Core;\nusing Azure.Storage;\nusing Azure.Storage.Blobs;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Persistence.AzureStorage;\nusing Orleans.Runtime;\nusing Orleans.Storage;\n\nnamespace Orleans.Configuration\n{\n    public class AzureBlobStorageOptions : IStorageProviderSerializerOptions\n    {\n        private BlobServiceClient _blobServiceClient;\n\n        /// <summary>\n        /// Container name where grain stage is stored\n        /// </summary>\n        public string ContainerName { get; set; } = DEFAULT_CONTAINER_NAME;\n        public const string DEFAULT_CONTAINER_NAME = \"grainstate\";\n\n        /// <summary>\n        /// Options to be used when configuring the blob storage client, or <see langword=\"null\"/> to use the default options.\n        /// </summary>\n        public BlobClientOptions ClientOptions { get; set; }\n\n        /// <summary>\n        /// The optional delegate used to create a <see cref=\"BlobServiceClient\"/> instance.\n        /// </summary>\n        internal Func<Task<BlobServiceClient>> CreateClient { get; private set; }\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n        /// <inheritdoc/>\n        public IGrainStorageSerializer GrainStorageSerializer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the client used to access the Azure Blob Service.\n        /// </summary>\n        public BlobServiceClient BlobServiceClient\n        {\n            get => _blobServiceClient; set\n            {\n                _blobServiceClient = value;\n                CreateClient = () => Task.FromResult(value);\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to delete the state when <see cref=\"IGrainStorage.ClearStateAsync\"/> is called.  Defaults to true.\n        /// </summary>\n        public bool DeleteStateOnClear { get; set; } = true;\n\n        /// <summary>\n        /// A function for building container factory instances\n        /// </summary>\n        public Func<IServiceProvider, AzureBlobStorageOptions, IBlobContainerFactory> BuildContainerFactory { get; set; }\n            = static (provider, options) => ActivatorUtilities.CreateInstance<DefaultBlobContainerFactory>(provider, options);\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using a connection string.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(string connectionString)\n        {\n            BlobServiceClient = new BlobServiceClient(connectionString, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using the provided callback.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Func<Task<BlobServiceClient>> createClientCallback)\n        {\n            CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.Core.TokenCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, TokenCredential tokenCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, tokenCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.AzureSasCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, AzureSasCredential azureSasCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, azureSasCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"StorageSharedKeyCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, StorageSharedKeyCredential sharedKeyCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, sharedKeyCredential, ClientOptions);\n        }\n    }\n\n    /// <summary>\n    /// Configuration validator for AzureBlobStorageOptions\n    /// </summary>\n    public class AzureBlobStorageOptionsValidator : IConfigurationValidator\n    {\n        private readonly AzureBlobStorageOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        public AzureBlobStorageOptionsValidator(AzureBlobStorageOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (this.options.CreateClient is null)\n            {\n                throw new OrleansConfigurationException($\"No credentials specified. Use the {options.GetType().Name}.{nameof(AzureBlobStorageOptions.ConfigureBlobServiceClient)} method to configure the Azure Blob Service client.\");\n            }\n\n            try\n            {\n                AzureBlobUtils.ValidateContainerName(options.ContainerName);\n                AzureBlobUtils.ValidateBlobName(this.name);\n            }\n            catch(ArgumentException e)\n            {\n                throw new OrleansConfigurationException(\n                    $\"Configuration for AzureBlobStorageOptions {name} is invalid. {nameof(this.options.ContainerName)} is not valid\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/AzureTableStorage.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Overrides;\nusing Orleans.Persistence.AzureStorage;\nusing Orleans.Providers.Azure;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Simple storage for writing grain state data to Azure table storage.\n    /// </summary>\n    public partial class AzureTableGrainStorage : IGrainStorage, IRestExceptionDecoder, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly AzureTableStorageOptions options;\n        private readonly ClusterOptions clusterOptions;\n        private readonly IGrainStorageSerializer storageSerializer;\n        private readonly ILogger logger;\n        private readonly IActivatorProvider _activatorProvider;\n        private GrainStateTableDataManager? tableDataManager;\n\n        // each property can hold 64KB of data and each entity can take 1MB in total, so 15 full properties take\n        // 15 * 64 = 960 KB leaving room for the primary key, timestamp etc\n        private const int MAX_DATA_CHUNK_SIZE = 64 * 1024;\n        private const int MAX_STRING_PROPERTY_LENGTH = 32 * 1024;\n        private const int MAX_DATA_CHUNKS_COUNT = 15;\n\n        private const string BINARY_DATA_PROPERTY_NAME = \"Data\";\n        private const string STRING_DATA_PROPERTY_NAME = \"StringData\";\n\n        private readonly string name;\n\n        /// <summary> Default constructor </summary>\n        public AzureTableGrainStorage(\n            string name,\n            AzureTableStorageOptions options,\n            IOptions<ClusterOptions> clusterOptions,\n            ILogger<AzureTableGrainStorage> logger,\n            IActivatorProvider activatorProvider)\n        {\n            this.options = options;\n            this.clusterOptions = clusterOptions.Value;\n            this.name = name;\n            this.storageSerializer = options.GrainStorageSerializer;\n            this.logger = logger;\n            _activatorProvider = activatorProvider;\n        }\n\n        /// <summary> Read state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ReadStateAsync{T}\"/>\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (tableDataManager == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string pk = GetKeyString(grainId);\n            LogTraceReadingGrainState(grainType, pk, grainId, this.options.TableName);\n            string partitionKey = pk;\n            string rowKey = AzureTableUtils.SanitizeTableProperty(grainType);\n            var entity = await tableDataManager.Read(partitionKey, rowKey).ConfigureAwait(false);\n            if (entity is not null)\n            {\n                var loadedState = ConvertFromStorageFormat<T>(entity);\n                grainState.RecordExists = loadedState != null;\n                grainState.State = loadedState ?? CreateInstance<T>();\n                grainState.ETag = entity.ETag.ToString();\n            }\n            else\n            {\n                grainState.RecordExists = false;\n                grainState.ETag = null;\n                grainState.State = CreateInstance<T>();\n            }\n        }\n\n        /// <summary> Write state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.WriteStateAsync{T}\"/>\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (tableDataManager == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string pk = GetKeyString(grainId);\n            LogTraceWritingGrainState(grainType, pk, grainId, grainState.ETag, this.options.TableName);\n\n            var rowKey = AzureTableUtils.SanitizeTableProperty(grainType);\n            var entity = new TableEntity(pk, rowKey)\n            {\n                ETag = new ETag(grainState.ETag)\n            };\n            ConvertToStorageFormat(grainState.State, entity);\n            try\n            {\n                await DoOptimisticUpdate(() => tableDataManager.Write(entity), grainType, grainId, this.options.TableName, grainState.ETag).ConfigureAwait(false);\n                grainState.ETag = entity.ETag.ToString();\n                grainState.RecordExists = true;\n            }\n            catch (Exception exc)\n            {\n                LogErrorWriteGrainState(grainType, grainId, grainState.ETag, this.options.TableName, exc);\n                throw;\n            }\n        }\n\n        /// <summary> Clear / Delete state data function for this storage provider. </summary>\n        /// <remarks>\n        /// If the <c>DeleteStateOnClear</c> is set to <c>true</c> then the table row\n        /// for this grain will be deleted / removed, otherwise the table row will be\n        /// cleared by overwriting with default / null values.\n        /// </remarks>\n        /// <see cref=\"IGrainStorage.ClearStateAsync{T}\"/>\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (tableDataManager == null) throw new ArgumentException(\"GrainState-Table property not initialized\");\n\n            string pk = GetKeyString(grainId);\n            LogTraceClearingGrainState(grainType, pk, grainId, grainState.ETag, this.options.DeleteStateOnClear, this.options.TableName);\n            var rowKey = AzureTableUtils.SanitizeTableProperty(grainType);\n            var entity = new TableEntity(pk, rowKey)\n            {\n                ETag = new ETag(grainState.ETag)\n            };\n            string operation = \"Clearing\";\n            try\n            {\n                if (this.options.DeleteStateOnClear)\n                {\n                    operation = \"Deleting\";\n                    await DoOptimisticUpdate(() => tableDataManager.Delete(entity), grainType, grainId, this.options.TableName, grainState.ETag).ConfigureAwait(false);\n                    grainState.ETag = null;\n                }\n                else\n                {\n                    await DoOptimisticUpdate(() => tableDataManager.Write(entity), grainType, grainId, this.options.TableName, grainState.ETag).ConfigureAwait(false);\n                    grainState.ETag = entity.ETag.ToString(); // Update in-memory data to the new ETag\n                }\n\n                grainState.RecordExists = false;\n                grainState.State = CreateInstance<T>();\n            }\n            catch (Exception exc)\n            {\n                LogErrorClearingGrainState(operation, grainType, grainId, grainState.ETag!, this.options.TableName, exc);\n                throw;\n            }\n        }\n\n        private static async Task DoOptimisticUpdate(Func<Task> updateOperation, string grainType, GrainId grainId, string tableName, string currentETag)\n        {\n            try\n            {\n                await updateOperation.Invoke().ConfigureAwait(false);\n            }\n            catch (RequestFailedException ex) when (ex.IsPreconditionFailed() || ex.IsConflict() || ex.IsNotFound())\n            {\n                throw new TableStorageUpdateConditionNotSatisfiedException(grainType, grainId.ToString(), tableName, \"Unknown\", currentETag, ex);\n            }\n        }\n\n        /// <summary>\n        /// Serialize to Azure storage format in either binary or JSON format.\n        /// </summary>\n        /// <param name=\"grainState\">The grain state data to be serialized</param>\n        /// <param name=\"entity\">The Azure table entity the data should be stored in</param>\n        /// <remarks>\n        /// See:\n        /// http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx\n        /// for more on the JSON serializer.\n        /// </remarks>\n        internal void ConvertToStorageFormat<T>(T grainState, TableEntity entity)\n        {\n            var binaryData = storageSerializer.Serialize<T>(grainState);\n\n            CheckMaxDataSize(binaryData.ToMemory().Length, MAX_DATA_CHUNK_SIZE * MAX_DATA_CHUNKS_COUNT);\n\n            if (options.UseStringFormat)\n            {\n                var properties = SplitStringData(binaryData.ToString().AsMemory());\n\n                foreach (var keyValuePair in properties.Zip(GetPropertyNames(STRING_DATA_PROPERTY_NAME),\n                (property, name) => new KeyValuePair<string, object>(name, property.ToString())))\n                {\n                    entity[keyValuePair.Key] = keyValuePair.Value;\n                }\n            }\n            else\n            {\n                var properties = SplitBinaryData(binaryData);\n\n                foreach (var keyValuePair in properties.Zip(GetPropertyNames(BINARY_DATA_PROPERTY_NAME),\n                (property, name) => new KeyValuePair<string, object>(name, property.ToArray())))\n                {\n                    entity[keyValuePair.Key] = keyValuePair.Value;\n                }\n            }\n        }\n\n        private void CheckMaxDataSize(int dataSize, int maxDataSize)\n        {\n            if (dataSize > maxDataSize)\n            {\n                var msg = string.Format(\"Data too large to write to Azure table. Size={0} MaxSize={1}\", dataSize, maxDataSize);\n                LogErrorDataTooLarge(dataSize, maxDataSize);\n                throw new ArgumentOutOfRangeException(\"GrainState.Size\", msg);\n            }\n        }\n\n        private static IEnumerable<ReadOnlyMemory<char>> SplitStringData(ReadOnlyMemory<char> stringData)\n        {\n            var startIndex = 0;\n            while (startIndex < stringData.Length)\n            {\n                var chunkSize = Math.Min(MAX_STRING_PROPERTY_LENGTH, stringData.Length - startIndex);\n\n                yield return stringData.Slice(startIndex, chunkSize);\n\n                startIndex += chunkSize;\n            }\n        }\n\n        private static IEnumerable<ReadOnlyMemory<byte>> SplitBinaryData(ReadOnlyMemory<byte> binaryData)\n        {\n            var startIndex = 0;\n            while (startIndex < binaryData.Length)\n            {\n                var chunkSize = Math.Min(MAX_DATA_CHUNK_SIZE, binaryData.Length - startIndex);\n\n                yield return binaryData.Slice(startIndex, chunkSize);\n\n                startIndex += chunkSize;\n            }\n        }\n\n        private static IEnumerable<string> GetPropertyNames(string basePropertyName)\n        {\n            yield return basePropertyName;\n            for (var i = 1; i < MAX_DATA_CHUNKS_COUNT; ++i)\n            {\n                yield return basePropertyName + i;\n            }\n        }\n\n        private static IEnumerable<byte[]> ReadBinaryDataChunks(TableEntity entity)\n        {\n            foreach (var binaryDataPropertyName in GetPropertyNames(BINARY_DATA_PROPERTY_NAME))\n            {\n                if (entity.TryGetValue(binaryDataPropertyName, out var dataProperty))\n                {\n                    switch (dataProperty)\n                    {\n                        // if TablePayloadFormat.JsonNoMetadata is used\n                        case string stringValue:\n                            if (!string.IsNullOrEmpty(stringValue))\n                            {\n                                yield return Convert.FromBase64String(stringValue);\n                            }\n                            break;\n\n                        // if any payload type providing metadata is used\n                        case byte[] binaryValue:\n                            if (binaryValue != null && binaryValue.Length > 0)\n                            {\n                                yield return binaryValue;\n                            }\n                            break;\n                    }\n                }\n            }\n        }\n\n        private static byte[] ReadBinaryData(TableEntity entity)\n        {\n            var dataChunks = ReadBinaryDataChunks(entity).ToArray();\n            var dataSize = dataChunks.Select(d => d.Length).Sum();\n            var result = new byte[dataSize];\n            var startIndex = 0;\n            foreach (var dataChunk in dataChunks)\n            {\n                Array.Copy(dataChunk, 0, result, startIndex, dataChunk.Length);\n                startIndex += dataChunk.Length;\n            }\n            return result;\n        }\n\n        private static IEnumerable<string> ReadStringDataChunks(TableEntity entity)\n        {\n            foreach (var stringDataPropertyName in GetPropertyNames(STRING_DATA_PROPERTY_NAME))\n            {\n                if (entity.TryGetValue(stringDataPropertyName, out var dataProperty))\n                {\n                    if (dataProperty is string { Length: > 0 } data)\n                    {\n                        yield return data;\n                    }\n                }\n            }\n        }\n\n        private static string ReadStringData(TableEntity entity)\n        {\n            return string.Join(string.Empty, ReadStringDataChunks(entity));\n        }\n\n        /// <summary>\n        /// Deserialize from Azure storage format\n        /// </summary>\n        /// <param name=\"entity\">The Azure table entity the stored data</param>\n        internal T? ConvertFromStorageFormat<T>(TableEntity entity)\n        {\n            // Read from both column type for backward compatibility\n            var binaryData = ReadBinaryData(entity);\n            var stringData = ReadStringData(entity);\n\n            T? dataValue = default;\n            try\n            {\n                var input = binaryData.Length > 0\n                    ? new BinaryData(binaryData)\n                    : new BinaryData(stringData);\n                if (input.Length > 0)\n                    dataValue = this.storageSerializer.Deserialize<T>(input);\n            }\n            catch (Exception exc)\n            {\n                var sb = new StringBuilder();\n                if (binaryData.Length > 0)\n                {\n                    sb.AppendFormat(\"Unable to convert from storage format GrainStateEntity.Data={0}\", binaryData);\n                }\n                else if (!string.IsNullOrEmpty(stringData))\n                {\n                    sb.AppendFormat(\"Unable to convert from storage format GrainStateEntity.StringData={0}\", stringData);\n                }\n\n                if (dataValue != null)\n                {\n                    sb.AppendFormat(\"Data Value={0} Type={1}\", dataValue, dataValue.GetType());\n                }\n\n                LogErrorSimpleMessage(sb, exc);\n                throw new AggregateException(sb.ToString(), exc);\n            }\n\n            return dataValue;\n        }\n\n        private string GetKeyString(GrainId grainId)\n        {\n            var key = $\"{clusterOptions.ServiceId}_{grainId}\";\n            return AzureTableUtils.SanitizeTableProperty(key);\n        }\n\n        private partial class GrainStateTableDataManager\n        {\n            public string TableName { get; private set; }\n            private readonly AzureTableDataManager<TableEntity> tableManager;\n            private readonly ILogger logger;\n\n            public GrainStateTableDataManager(AzureStorageOperationOptions options, ILogger logger)\n            {\n                this.logger = logger;\n                TableName = options.TableName;\n                tableManager = new AzureTableDataManager<TableEntity>(options, logger);\n            }\n\n            public Task InitTableAsync()\n            {\n                return tableManager.InitTableAsync();\n            }\n\n            public async Task<TableEntity?> Read(string partitionKey, string rowKey)\n            {\n                LogTraceReadingPartitionKeyRowKey(partitionKey, rowKey, TableName);\n                try\n                {\n                    var data = await tableManager.ReadSingleTableEntryAsync(partitionKey, rowKey).ConfigureAwait(false);\n                    if (data.Entity == null)\n                    {\n                        LogTraceDataNotFoundReading(partitionKey, rowKey, TableName);\n                        return default;\n                    }\n\n                    var record = data.Entity;\n                    record.ETag = new ETag(data.ETag);\n                    LogTraceDataRead(record.PartitionKey, record.RowKey, TableName, record.ETag.ToString());\n\n                    return record;\n                }\n                catch (Exception exc)\n                {\n                    if (AzureTableUtils.TableStorageDataNotFound(exc))\n                    {\n                        LogTraceDataNotFoundReadingException(partitionKey, rowKey, TableName, exc);\n\n                        return default;  // No data\n                    }\n                    throw;\n                }\n            }\n\n            public async Task Write(TableEntity entity)\n            {\n                LogTraceWritingPartitionKeyRowKey(entity.PartitionKey, entity.RowKey, TableName, entity.ETag.ToString());\n\n                string eTag = string.IsNullOrEmpty(entity.ETag.ToString()) ?\n                    await tableManager.CreateTableEntryAsync(entity).ConfigureAwait(false) :\n                    await tableManager.UpdateTableEntryAsync(entity, entity.ETag).ConfigureAwait(false);\n                entity.ETag = new ETag(eTag);\n            }\n\n            public async Task Delete(TableEntity entity)\n            {\n                if (string.IsNullOrWhiteSpace(entity.ETag.ToString()))\n                {\n                    LogTraceNotAttemptingDelete(entity.PartitionKey, entity.RowKey, TableName, entity.ETag.ToString());\n                    return;\n                }\n\n                LogTraceWritingPartitionKeyRowKey(entity.PartitionKey, entity.RowKey, TableName, entity.ETag.ToString());\n                await tableManager.DeleteTableEntryAsync(entity, entity.ETag).ConfigureAwait(false);\n                entity.ETag = default;\n            }\n\n            // Partial log methods for GrainStateTableDataManager\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_Storage_Reading,\n                Level = LogLevel.Trace,\n                Message = \"Reading: PartitionKey={PartitionKey} RowKey={RowKey} from Table={TableName}\"\n            )]\n            private partial void LogTraceReadingPartitionKeyRowKey(string partitionKey, string rowKey, string tableName);\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_DataNotFound,\n                Level = LogLevel.Trace,\n                Message = \"DataNotFound reading: PartitionKey={PartitionKey} RowKey={RowKey} from Table={TableName}\"\n            )]\n            private partial void LogTraceDataNotFoundReading(string partitionKey, string rowKey, string tableName);\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_Storage_DataRead,\n                Level = LogLevel.Trace,\n                Message = \"Read: PartitionKey={PartitionKey} RowKey={RowKey} from Table={TableName} with ETag={ETag}\"\n            )]\n            private partial void LogTraceDataRead(string partitionKey, string rowKey, string tableName, string eTag);\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_DataNotFound,\n                Level = LogLevel.Trace,\n                Message = \"DataNotFound reading (exception): PartitionKey={PartitionKey} RowKey={RowKey} from Table={TableName}\"\n            )]\n            private partial void LogTraceDataNotFoundReadingException(string partitionKey, string rowKey, string tableName, Exception exception);\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_Storage_Writing,\n                Level = LogLevel.Trace,\n                Message = \"Writing: PartitionKey={PartitionKey} RowKey={RowKey} to Table={TableName} with ETag={ETag}\"\n            )]\n            private partial void LogTraceWritingPartitionKeyRowKey(string partitionKey, string rowKey, string tableName, string eTag);\n\n            [LoggerMessage(\n                EventId = (int)AzureProviderErrorCode.AzureTableProvider_DataNotFound,\n                Level = LogLevel.Trace,\n                Message = \"Not attempting to delete non-existent persistent state: PartitionKey={PartitionKey} RowKey={RowKey} from Table={TableName} with ETag={ETag}\"\n            )]\n            private partial void LogTraceNotAttemptingDelete(string partitionKey, string rowKey, string tableName, string eTag);\n        }\n\n        /// <summary> Decodes Storage exceptions.</summary>\n        public bool DecodeException(Exception e, out HttpStatusCode httpStatusCode, out string restStatus, bool getRESTErrors = false)\n        {\n            return AzureTableUtils.EvaluateException(e, out httpStatusCode, out restStatus, getRESTErrors);\n        }\n\n        private async Task Init(CancellationToken ct)\n        {\n            var stopWatch = Stopwatch.StartNew();\n            try\n            {\n                LogDebugStorageInitializing(name, this.options.TableName);\n                this.tableDataManager = new GrainStateTableDataManager(this.options, this.logger);\n                await this.tableDataManager.InitTableAsync();\n                stopWatch.Stop();\n                LogInfoInitializingProvider(this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds);\n            }\n            catch (Exception ex)\n            {\n                stopWatch.Stop();\n                LogErrorInitializationFailed(this.name, this.GetType().Name, this.options.InitStage, stopWatch.ElapsedMilliseconds, ex);\n                throw;\n            }\n        }\n\n        private Task Close(CancellationToken ct)\n        {\n            this.tableDataManager = null;\n            return Task.CompletedTask;\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<AzureTableGrainStorage>(this.name), this.options.InitStage, Init, Close);\n        }\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_ReadingData,\n            Level = LogLevel.Trace,\n            Message = \"Reading: GrainType={GrainType} Pk={PartitionKey} GrainId={GrainId} from Table={TableName}\"\n        )]\n        private partial void LogTraceReadingGrainState(string grainType, string partitionKey, GrainId grainId, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_WritingData,\n            Level = LogLevel.Trace,\n            Message = \"Writing: GrainType={GrainType} Pk={PartitionKey} GrainId={GrainId} ETag={ETag} to Table={TableName}\"\n        )]\n        private partial void LogTraceWritingGrainState(string grainType, string partitionKey, GrainId grainId, string eTag, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_WriteError,\n            Level = LogLevel.Error,\n            Message = \"Error Writing: GrainType={GrainType} GrainId={GrainId} ETag={ETag} to Table={TableName}\"\n        )]\n        private partial void LogErrorWriteGrainState(string grainType, GrainId grainId, string eTag, string tableName, Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_WritingData,\n            Level = LogLevel.Trace,\n            Message = \"Clearing: GrainType={GrainType} Pk={PartitionKey} GrainId={GrainId} ETag={ETag} DeleteStateOnClear={DeleteStateOnClear} from Table={TableName}\"\n        )]\n        private partial void LogTraceClearingGrainState(string grainType, string partitionKey, GrainId grainId, string eTag, bool deleteStateOnClear, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_DeleteError,\n            Level = LogLevel.Error,\n            Message = \"Error {Operation}: GrainType={GrainType} GrainId={GrainId} ETag={ETag} from Table={TableName}\"\n        )]\n        private partial void LogErrorClearingGrainState(string operation, string grainType, GrainId grainId, string eTag, string tableName, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Data too large to write to Azure table. Size={Size} MaxSize={MaxSize}\"\n        )]\n        private partial void LogErrorDataTooLarge(int size, int maxSize);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"{Message}\"\n        )]\n        private partial void LogErrorSimpleMessage(StringBuilder message, Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_InitProvider,\n            Level = LogLevel.Debug,\n            Message = \"AzureTableGrainStorage {ProviderName} is initializing: TableName={TableName}\"\n        )]\n        private partial void LogDebugStorageInitializing(string providerName, string tableName);\n\n        [LoggerMessage(\n            EventId = (int)AzureProviderErrorCode.AzureTableProvider_InitProvider,\n            Level = LogLevel.Information,\n            Message = \"Initializing provider {ProviderName} of type {ProviderType} in stage {Stage} took {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private partial void LogInfoInitializingProvider(string providerName, string providerType, int stage, long elapsedMilliseconds);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Provider_ErrorFromInit,\n            Level = LogLevel.Error,\n            Message = \"Initialization failed for provider {ProviderName} of type {ProviderType} in stage {Stage} in {ElapsedMilliseconds} Milliseconds.\"\n        )]\n        private partial void LogErrorInitializationFailed(string providerName, string providerType, int stage, long elapsedMilliseconds, Exception exception);\n    }\n\n    public static class AzureTableGrainStorageFactory\n    {\n        public static AzureTableGrainStorage Create(IServiceProvider services, string name)\n        {\n            var optionsSnapshot = services.GetRequiredService<IOptionsMonitor<AzureTableStorageOptions>>();\n            var clusterOptions = services.GetProviderClusterOptions(name);\n            return ActivatorUtilities.CreateInstance<AzureTableGrainStorage>(services, name, optionsSnapshot.Get(name), clusterOptions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/AzureTableStorageOptions.cs",
    "content": "using Orleans.Persistence.AzureStorage;\nusing Orleans.Storage;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration for AzureTableGrainStorage\n    /// </summary>\n    public class AzureTableStorageOptions : AzureStorageOperationOptions, IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Table name where grain stage is stored\n        /// </summary>\n        public override string TableName { get; set; } = DEFAULT_TABLE_NAME;\n        public const string DEFAULT_TABLE_NAME = \"OrleansGrainState\";\n\n        /// <summary>\n        /// Indicates if grain data should be deleted or reset to defaults when a grain clears it's state.\n        /// </summary>\n        public bool DeleteStateOnClear { get; set; } = false;\n\n        /// <summary>\n        /// Indicates if grain data should be stored in string or in binary format.\n        /// </summary>\n        public bool UseStringFormat { get; set; }\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n        /// <inheritdoc/>\n        public IGrainStorageSerializer GrainStorageSerializer { get; set; }\n    }\n\n    /// <summary>\n    /// Configuration validator for AzureTableStorageOptions\n    /// </summary>\n    public class AzureTableGrainStorageOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableStorageOptions>\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        public AzureTableGrainStorageOptionsValidator(AzureTableStorageOptions options, string name) : base(options, name)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/IBlobContainerFactory.cs",
    "content": "using System.Threading.Tasks;\nusing Azure.Storage.Blobs;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.Storage;\n\n/// <summary>\n/// A factory for building container clients for blob storage using grainType and grainId\n/// </summary>\npublic interface IBlobContainerFactory\n{\n    /// <summary>\n    /// Gets the container which should be used for the specified grain.\n    /// </summary>\n    /// <param name=\"grainId\">The grain id</param>\n    /// <returns>A configured blob client</returns>\n    public BlobContainerClient GetBlobContainerClient(GrainId grainId);\n\n    /// <summary>\n    /// Initialize any required dependencies using the provided client and options.\n    /// </summary>\n    /// <param name=\"client\">The connected blob client</param>\n    /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation.</returns>\n    public Task InitializeAsync(BlobServiceClient client);\n}\n\n/// <summary>\n/// A default blob container factory that uses the default container name.\n/// </summary>\ninternal class DefaultBlobContainerFactory : IBlobContainerFactory\n{\n    private readonly AzureBlobStorageOptions _options;\n    private BlobContainerClient _defaultContainer = null!;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DefaultBlobContainerFactory\"/> class.\n    /// </summary>\n    /// <param name=\"options\">The blob storage options</param>\n    public DefaultBlobContainerFactory(AzureBlobStorageOptions options)\n    {\n        _options = options;\n    }\n\n    /// <inheritdoc/>\n    public BlobContainerClient GetBlobContainerClient(GrainId grainId)\n        => _defaultContainer;\n\n    /// <inheritdoc/>\n    public async Task InitializeAsync(BlobServiceClient client)\n    {\n        _defaultContainer = client.GetBlobContainerClient(_options.ContainerName);\n        await _defaultContainer.CreateIfNotExistsAsync();\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/README.md",
    "content": "# Microsoft Orleans Persistence for Azure Storage\n\n## Introduction\nMicrosoft Orleans Persistence for Azure Storage provides grain persistence for Microsoft Orleans using Azure Storage (Blob and Table). This allows your grains to persist their state in Azure Storage and reload it when they are reactivated.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Persistence.AzureStorage\n```\n\n## Example - Configuring Azure Storage Persistence\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n// Define grain interface\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task SetData(string data);\n    Task<string> GetData();\n}\n\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Table Storage as grain storage\n            .AddAzureTableGrainStorage(\n                name: \"tableStore\",\n                configureOptions: options =>\n                {\n                    options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                })\n            // Configure Azure Blob Storage as grain storage\n            .AddAzureBlobGrainStorage(\n                name: \"blobStore\",\n                configureOptions: options =>\n                {\n                    options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IMyGrain>(\"user123\");\nawait grain.SetData(\"Hello from Azure Storage!\");\nvar response = await grain.GetData();\n\n// Print the result\nConsole.WriteLine($\"Grain data: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Using Grain Storage in a Grain\n```csharp\nusing System;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\nnamespace ExampleGrains;\n\n// Define grain state class\n\npublic class MyGrainState\n{\n    public string Data { get; set; }\n    public int Version { get; set; }\n}\n\n// Grain implementation that uses the Azure storage\npublic class MyGrain : Grain, IMyGrain, IGrainWithStringKey\n{\n    private readonly IPersistentState<MyGrainState> _state;\n\n    public MyGrain([PersistentState(\"state\", \"tableStore\")] IPersistentState<MyGrainState> state)\n    {\n        _state = state;\n    }\n\n    public async Task SetData(string data)\n    {\n        _state.State.Data = data;\n        _state.State.Version++;\n        await _state.WriteStateAsync();\n    }\n\n    public Task<string> GetData()\n    {\n        return Task.FromResult(_state.State.Data);\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n- [Azure Storage Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence/azure-storage)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Storage/StorageExceptionExtensions.cs",
    "content": "using System.Net;\nusing Azure;\nusing Azure.Storage.Blobs.Models;\n\nnamespace Orleans.Storage\n{\n    internal static class StorageExceptionExtensions\n    {\n        public static bool IsNotFound(this RequestFailedException requestFailedException)\n        {\n            return requestFailedException?.Status == (int)HttpStatusCode.NotFound;\n        }\n\n        public static bool IsPreconditionFailed(this RequestFailedException requestFailedException)\n        {\n            return requestFailedException?.Status == (int)HttpStatusCode.PreconditionFailed;\n        }\n\n        public static bool IsConflict(this RequestFailedException requestFailedException)\n        {\n            return requestFailedException?.Status == (int)HttpStatusCode.Conflict;\n        }\n\n        public static bool IsContainerNotFound(this RequestFailedException requestFailedException)\n        {\n            return requestFailedException?.Status == (int)HttpStatusCode.NotFound\n                && requestFailedException.ErrorCode == BlobErrorCode.ContainerNotFound;\n        }\n\n        public static bool IsBlobNotFound(this RequestFailedException requestFailedException)\n        {\n            return requestFailedException?.Status == (int)HttpStatusCode.NotFound\n                && requestFailedException.ErrorCode == BlobErrorCode.BlobNotFound;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.AzureStorage/Storage/TableStorageUpdateConditionNotSatisfiedException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Exception thrown when a storage provider detects an Etag inconsistency when attempting to perform a WriteStateAsync operation.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class TableStorageUpdateConditionNotSatisfiedException : InconsistentStateException\n    {\n        private const string DefaultMessageFormat = \"Table storage condition not Satisfied.  GrainType: {0}, GrainId: {1}, TableName: {2}, StoredETag: {3}, CurrentETag: {4}\";\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        public TableStorageUpdateConditionNotSatisfiedException(\n            string errorMsg,\n            string grainType,\n            string grainId,\n            string tableName,\n            string storedEtag,\n            string currentEtag,\n            Exception storageException)\n            : base(errorMsg, storedEtag, currentEtag, storageException)\n        {\n            this.GrainType = grainType;\n            this.GrainId = grainId;\n            this.TableName = tableName;\n        }\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        public TableStorageUpdateConditionNotSatisfiedException(\n            string grainType,\n            string grainId,\n            string tableName,\n            string storedEtag,\n            string currentEtag,\n            Exception storageException)\n            : this(CreateDefaultMessage(grainType, grainId, tableName, storedEtag, currentEtag), grainType, grainId, tableName, storedEtag, currentEtag, storageException)\n        {\n        }\n\n        /// <summary>\n        /// Id of grain\n        /// </summary>\n        [Id(0)]\n        public string GrainId { get; }\n\n        /// <summary>\n        /// Type of grain that throw this exception\n        /// </summary>\n        [Id(1)]\n        public string GrainType { get; }\n\n        /// <summary>\n        /// Azure table name\n        /// </summary>\n        [Id(2)]\n        public string TableName { get; }\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        public TableStorageUpdateConditionNotSatisfiedException()\n        {\n        }\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        public TableStorageUpdateConditionNotSatisfiedException(string msg)\n            : base(msg)\n        {\n        }\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        public TableStorageUpdateConditionNotSatisfiedException(string msg, Exception exc)\n            : base(msg, exc)\n        {\n        }\n\n        private static string CreateDefaultMessage(\n            string grainType,\n            string grainId,\n            string tableName,\n            string storedEtag,\n            string currentEtag)\n        {\n            return string.Format(DefaultMessageFormat, grainType, grainId, tableName, storedEtag, currentEtag);\n        }\n\n        /// <summary>\n        /// Exception thrown when an azure table storage exception is thrown due to update conditions not being satisfied.\n        /// </summary>\n        [Obsolete]\n        protected TableStorageUpdateConditionNotSatisfiedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.GrainType = info.GetString(\"GrainType\");\n            this.GrainId = info.GetString(\"GrainId\");\n            this.TableName = info.GetString(\"TableName\");\n        }\n\n        /// <inheritdoc />   \n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            if (info == null) throw new ArgumentNullException(nameof(info));\n\n            info.AddValue(\"GrainType\", this.GrainType);\n            info.AddValue(\"GrainId\", this.GrainId);\n            info.AddValue(\"TableName\", this.TableName);\n            base.GetObjectData(info, context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/CosmosConditionNotSatisfiedException.cs",
    "content": "using System.Runtime.Serialization;\nusing Orleans.Storage;\n\nnamespace Orleans.Persistence.Cosmos;\n\n/// <summary>\n/// Exception thrown when a storage provider detects an Etag inconsistency when attempting to perform a WriteStateAsync operation.\n/// </summary>\n[Serializable]\n[GenerateSerializer]\npublic class CosmosConditionNotSatisfiedException : InconsistentStateException\n{\n    private const string DefaultMessageFormat = \"Cosmos DB condition not satisfied. GrainType: {0}, GrainId: {1}, TableName: {2}, StoredETag: {3}, CurrentETag: {4}\";\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    public CosmosConditionNotSatisfiedException(\n        string errorMsg,\n        string grainType,\n        GrainId grainId,\n        string collection,\n        string storedEtag,\n        string currentEtag)\n        : base(errorMsg, storedEtag, currentEtag)\n    {\n        GrainType = grainType;\n        GrainId = grainId.ToString();\n        Collection = collection;\n    }\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    public CosmosConditionNotSatisfiedException(\n        string grainType,\n        GrainId grainId,\n        string collection,\n        string storedEtag,\n        string currentEtag)\n        : this(CreateDefaultMessage(grainType, grainId, collection, storedEtag, currentEtag), grainType, grainId, collection, storedEtag, currentEtag)\n    {\n    }\n\n    /// <summary>\n    /// Gets the id of the affected grain.\n    /// </summary>\n    [Id(0)]\n    public string GrainId { get; } = default!;\n\n    /// <summary>\n    /// Gets the grain type of the affected grain.\n    /// </summary>\n    [Id(1)]\n    public string GrainType { get; } = default!;\n\n    /// <summary>\n    /// Gets the collection name\n    /// </summary>\n    [Id(2)]\n    public string Collection { get; } = default!;\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    public CosmosConditionNotSatisfiedException()\n    {\n    }\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    public CosmosConditionNotSatisfiedException(string msg)\n        : base(msg)\n    {\n    }\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    public CosmosConditionNotSatisfiedException(string msg, Exception exc)\n        : base(msg, exc)\n    {\n    }\n\n    private static string CreateDefaultMessage(\n        string grainType,\n        GrainId grainId,\n        string collection,\n        string storedEtag,\n        string currentEtag) => string.Format(DefaultMessageFormat, grainType, grainId, collection, storedEtag, currentEtag);\n\n    /// <summary>\n    /// Exception thrown when a Cosmos DB exception is thrown due to update conditions not being satisfied.\n    /// </summary>\n    [Obsolete]\n    protected CosmosConditionNotSatisfiedException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    {\n        GrainType = info.GetString(\"GrainType\")!;\n        GrainId = info.GetString(\"GrainId\")!;\n        Collection = info.GetString(\"Collection\")!;\n    }\n\n    /// <inheritdoc />\n    [Obsolete]\n    public override void GetObjectData(SerializationInfo info, StreamingContext context)\n    {\n        if (info == null) throw new ArgumentNullException(nameof(info));\n\n        info.AddValue(\"GrainType\", GrainType);\n        info.AddValue(\"GrainId\", GrainId);\n        info.AddValue(\"Collection\", Collection);\n        base.GetObjectData(info, context);\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/CosmosGrainStorage.cs",
    "content": "using System.Net;\nusing System.Threading;\nusing System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Storage;\nusing static Orleans.Persistence.Cosmos.CosmosIdSanitizer;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Persistence.Cosmos;\n\npublic sealed partial class CosmosGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n{\n    private const string ANY_ETAG = \"*\";\n    private const string KEY_STRING_SEPARATOR = \"__\";\n    private const string GRAINTYPE_PARTITION_KEY_PATH = \"/GrainType\";\n    private readonly ILogger _logger;\n    private readonly CosmosGrainStorageOptions _options;\n    private readonly string _name;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly string _serviceId;\n    private string _partitionKeyPath;\n    private readonly IPartitionKeyProvider _partitionKeyProvider;\n    private readonly IActivatorProvider _activatorProvider;\n    private readonly ICosmosOperationExecutor _executor;\n    private CosmosClient _client = default!;\n    private Container _container = default!;\n\n    public CosmosGrainStorage(\n        string name,\n        CosmosGrainStorageOptions options,\n        ILoggerFactory loggerFactory,\n        IServiceProvider serviceProvider,\n        IOptions<ClusterOptions> clusterOptions,\n        IPartitionKeyProvider partitionKeyProvider,\n        IActivatorProvider activatorProvider)\n    {\n        _logger = loggerFactory.CreateLogger<CosmosGrainStorage>();\n        _options = options;\n        _name = name;\n        _serviceProvider = serviceProvider;\n        _serviceId = clusterOptions.Value.ServiceId;\n        _partitionKeyProvider = partitionKeyProvider;\n        _activatorProvider = activatorProvider;\n        _executor = options.OperationExecutor;\n        _partitionKeyPath = _options.PartitionKeyPath;\n    }\n\n    public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n    {\n        var id = GetKeyString(grainId);\n        var partitionKey = await BuildPartitionKey(grainType, grainId);\n\n        LogTraceReadingState(grainType, id, grainId, _options.ContainerName, partitionKey);\n\n        try\n        {\n            var pk = new PartitionKey(partitionKey);\n            var entity = await _executor.ExecuteOperation(static args =>\n            {\n                var (self, id, pk) = args;\n                return self._container.ReadItemAsync<GrainStateEntity<T>>(id, pk);\n            },\n            (this, id, pk)).ConfigureAwait(false);\n\n            if (entity.Resource.State != null)\n            {\n                grainState.State = entity.Resource.State;\n                grainState.RecordExists = true;\n            }\n            else\n            {\n                grainState.State = CreateInstance<T>();\n                grainState.RecordExists = false;\n            }\n\n            grainState.ETag = entity.Resource.ETag;\n        }\n        catch (CosmosException dce)\n        {\n            if (dce.StatusCode == HttpStatusCode.NotFound)\n            {\n                // State is new, just activate a default and return.\n                ResetGrainState(grainState);\n                return;\n            }\n\n            LogErrorReadingState(dce, grainType, id);\n            WrappedException.CreateAndRethrow(dce);\n            throw;\n        }\n        catch (Exception exc)\n        {\n            LogErrorReadingState(exc, grainType, id);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n    {\n        var id = GetKeyString(grainId);\n\n        var partitionKey = await BuildPartitionKey(grainType, grainId);\n\n        LogTraceWritingState(grainType, id, grainId, grainState.ETag, _options.ContainerName, partitionKey);\n\n        ItemResponse<GrainStateEntity<T>>? response = null;\n\n        try\n        {\n            var entity = new GrainStateEntity<T>\n            {\n                ETag = grainState.ETag,\n                Id = id,\n                GrainType = grainType,\n                State = grainState.State,\n                PartitionKey = partitionKey\n            };\n\n            var pk = new PartitionKey(partitionKey);\n            if (string.IsNullOrWhiteSpace(grainState.ETag))\n            {\n                response = await _executor.ExecuteOperation(\n                    static args =>\n                    {\n                        var (self, entity, pk) = args;\n                        return self._container.CreateItemAsync(entity, pk);\n                    },\n                    (this, entity, pk)).ConfigureAwait(false);\n            }\n            else if (grainState.ETag == ANY_ETAG)\n            {\n                var requestOptions = new ItemRequestOptions { IfMatchEtag = grainState.ETag };\n                response = await _executor.ExecuteOperation(\n                    static args =>\n                    {\n                        var (self, entity, pk, requestOptions) = args;\n                        return self._container.UpsertItemAsync(entity, pk, requestOptions);\n                    },\n                    (this, entity, pk, requestOptions)).ConfigureAwait(false);\n            }\n            else\n            {\n                var requestOptions = new ItemRequestOptions { IfMatchEtag = grainState.ETag };\n                response = await _executor.ExecuteOperation(\n                    static args =>\n                    {\n                        var (self, entity, pk, requestOptions) = args;\n                        return self._container.ReplaceItemAsync(entity, entity.Id, pk, requestOptions);\n                    },\n                    (this, entity, pk, requestOptions)).ConfigureAwait(false);\n            }\n\n            grainState.ETag = response.Resource.ETag;\n            grainState.RecordExists = true;\n        }\n        catch (CosmosException ex) when (ex.StatusCode is HttpStatusCode.PreconditionFailed or HttpStatusCode.Conflict or HttpStatusCode.NotFound)\n        {\n            throw new CosmosConditionNotSatisfiedException(grainType, grainId, _options.ContainerName, \"Unknown\", grainState.ETag);\n        }\n        catch (Exception exc)\n        {\n            LogErrorWritingState(exc, grainType, id);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n    {\n        var id = GetKeyString(grainId);\n        var partitionKey = await BuildPartitionKey(grainType, grainId);\n\n        LogTraceClearingState(grainType, id, grainId, grainState.ETag, _options.DeleteStateOnClear, _options.ContainerName, partitionKey);\n\n        var pk = new PartitionKey(partitionKey);\n        var requestOptions = new ItemRequestOptions { IfMatchEtag = grainState.ETag };\n        try\n        {\n            if (_options.DeleteStateOnClear)\n            {\n                if (string.IsNullOrWhiteSpace(grainState.ETag))\n                {\n                    try\n                    {\n                        var entity = await _executor.ExecuteOperation(static args =>\n                        {\n                            var (self, id, pk) = args;\n                            return self._container.ReadItemAsync<GrainStateEntity<T>>(id, pk);\n                        },\n                        (this, id, pk)).ConfigureAwait(false);\n\n                        // State exists but the current activation has not observed state creation. Therefore, we have inconsistent\n                        // state and should throw to give the grain a chance to deactivate and recover.\n                        throw new CosmosConditionNotSatisfiedException(grainType, grainId, _options.ContainerName, \"None\", entity.ETag);\n                    }\n                    catch (CosmosException dce) when (dce.StatusCode == HttpStatusCode.NotFound)\n                    {\n                        // Ignore, since this is the expected outcome.\n                        // All other exceptions will be handled by the outer catch blocks.\n                    }\n                }\n                else\n                {\n                    await _executor.ExecuteOperation(static args =>\n                    {\n                        var (self, id, pk, requestOptions) = args;\n                        return self._container.DeleteItemAsync<GrainStateEntity<T>>(id, pk, requestOptions);\n                    },\n                    (this, id, pk, requestOptions));\n                }\n\n                ResetGrainState(grainState);\n            }\n            else\n            {\n                var entity = new GrainStateEntity<T>\n                {\n                    ETag = grainState.ETag,\n                    Id = id,\n                    GrainType = grainType,\n                    State = default!,\n                    PartitionKey = partitionKey\n                };\n\n                var response = await _executor.ExecuteOperation(static args =>\n                {\n                    var (self, grainState, entity, pk, requestOptions) = args;\n                    return grainState.ETag switch\n                    {\n                        null or { Length: 0 } => self._container.CreateItemAsync(entity, pk),\n                        ANY_ETAG => self._container.ReplaceItemAsync(entity, entity.Id, pk, requestOptions),\n                        _ => self._container.ReplaceItemAsync(entity, entity.Id, pk, requestOptions),\n                    };\n                },\n                (this, grainState, entity, pk, requestOptions)).ConfigureAwait(false);\n\n                grainState.ETag = response.Resource.ETag;\n                grainState.RecordExists = false;\n                grainState.State = CreateInstance<T>();\n            }\n        }\n        catch (CosmosException ex) when (ex.StatusCode is HttpStatusCode.PreconditionFailed or HttpStatusCode.Conflict or HttpStatusCode.NotFound)\n        {\n            throw new CosmosConditionNotSatisfiedException(grainType, grainId, _options.ContainerName, \"Unknown\", grainState?.ETag ?? \"Unknown\");\n        }\n        catch (Exception exc)\n        {\n            LogErrorClearingState(exc, grainType, id);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public void Participate(ISiloLifecycle lifecycle)\n    {\n        lifecycle.Subscribe(OptionFormattingUtilities.Name<CosmosGrainStorage>(_name), _options.InitStage, Init);\n    }\n\n    private string GetKeyString(GrainId grainId) => $\"{Sanitize(_serviceId)}{KEY_STRING_SEPARATOR}{Sanitize(grainId.Type.ToString()!)}{SeparatorChar}{Sanitize(grainId.Key.ToString()!)}\";\n\n    private ValueTask<string> BuildPartitionKey(string grainType, GrainId grainId) =>\n        _partitionKeyProvider.GetPartitionKey(grainType, grainId);\n\n    private async Task Init(CancellationToken ct)\n    {\n        var stopWatch = Stopwatch.StartNew();\n\n        try\n        {\n            LogDebugInit(_name, _serviceId, _options.ContainerName, _options.DeleteStateOnClear);\n\n            await InitializeCosmosClient().ConfigureAwait(false);\n\n            if (_options.IsResourceCreationEnabled)\n            {\n                if (_options.CleanResourcesOnInitialization)\n                {\n                    await TryDeleteDatabase().ConfigureAwait(false);\n                }\n\n                await TryCreateResources().ConfigureAwait(false);\n            }\n\n            _container = _client.GetContainer(_options.DatabaseName, _options.ContainerName);\n\n            stopWatch.Stop();\n            LogDebugInitializingProvider(_name, GetType().Name, _options.InitStage, stopWatch.ElapsedMilliseconds);\n        }\n        catch (Exception ex)\n        {\n            stopWatch.Stop();\n            LogErrorInitializationFailed(ex, _name, GetType().Name, _options.InitStage, stopWatch.ElapsedMilliseconds);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task InitializeCosmosClient()\n    {\n        try\n        {\n            _client = await _options.CreateClient(_serviceProvider).ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            LogErrorInitializingClient(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task TryCreateResources()\n    {\n        var dbResponse = await _client.CreateDatabaseIfNotExistsAsync(_options.DatabaseName, _options.DatabaseThroughput);\n        var db = dbResponse.Database;\n\n        var stateContainer = new ContainerProperties(_options.ContainerName, _options.PartitionKeyPath);\n        stateContainer.IndexingPolicy.IndexingMode = IndexingMode.Consistent;\n        stateContainer.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = \"/*\" });\n        stateContainer.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/\\\"State\\\"/*\" });\n\n        if (_options.StateFieldsToIndex != null)\n        {\n            foreach (var idx in _options.StateFieldsToIndex)\n            {\n                var path = idx.StartsWith(\"/\") ? idx[1..] : idx;\n                stateContainer.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = $\"/\\\"State\\\"/\\\"{path}\\\"/?\" });\n            }\n        }\n\n        const int maxRetries = 3;\n        for (var retry = 0; retry <= maxRetries; ++retry)\n        {\n            var containerResponse = await db.CreateContainerIfNotExistsAsync(stateContainer, _options.ContainerThroughputProperties);\n\n            if (containerResponse.StatusCode == HttpStatusCode.OK || containerResponse.StatusCode == HttpStatusCode.Created)\n            {\n                var container = containerResponse.Resource;\n                _partitionKeyPath = container.PartitionKeyPath;\n                if (_partitionKeyPath == GRAINTYPE_PARTITION_KEY_PATH &&\n                    _partitionKeyProvider is not DefaultPartitionKeyProvider)\n                    throw new OrleansConfigurationException(\"Custom partition key provider is not compatible with partition key path set to /GrainType\");\n            }\n\n            if (retry == maxRetries || dbResponse.StatusCode != HttpStatusCode.Created || containerResponse.StatusCode == HttpStatusCode.Created)\n            {\n                break;  // Apparently some throttling logic returns HttpStatusCode.OK (not 429) when the collection wasn't created in a new DB.\n            }\n            await Task.Delay(1000);\n        }\n    }\n\n    private async Task TryDeleteDatabase()\n    {\n        try\n        {\n            await _client.GetDatabase(_options.DatabaseName).DeleteAsync().ConfigureAwait(false);\n        }\n        catch (CosmosException dce) when (dce.StatusCode == HttpStatusCode.NotFound)\n        {\n            return;\n        }\n        catch (Exception ex)\n        {\n            LogErrorDeletingDatabase(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private void ResetGrainState<T>(IGrainState<T> grainState)\n    {\n        grainState.State = CreateInstance<T>();\n        grainState.ETag = null;\n        grainState.RecordExists = false;\n    }\n\n    private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Reading: GrainType={GrainType} Key={Id} GrainId={GrainId} from Container={Container} with PartitionKey={PartitionKey}\"\n    )]\n    private partial void LogTraceReadingState(string grainType, string id, GrainId grainId, string container, string partitionKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure reading state for Grain Type {GrainType} with Id {Id}\"\n    )]\n    private partial void LogErrorReadingState(Exception exception, string grainType, string id);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Writing: GrainType={GrainType} Key={Id} GrainId={GrainId} ETag={ETag} from Container={Container} with PartitionKey={PartitionKey}\"\n    )]\n    private partial void LogTraceWritingState(string grainType, string id, GrainId grainId, string eTag, string container, string partitionKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure writing state for Grain Type {GrainType} with Id {Id}\"\n    )]\n    private partial void LogErrorWritingState(Exception exception, string grainType, string id);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Clearing: GrainType={GrainType} Key={Id} GrainId={GrainId} ETag={ETag} DeleteStateOnClear={DeleteStateOnClear} from Container={Container} with PartitionKey {PartitionKey}\"\n    )]\n    private partial void LogTraceClearingState(string grainType, string id, GrainId grainId, string eTag, bool deleteStateOnClear, string container, string partitionKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure clearing state for Grain Type {GrainType} with Id {Id}\"\n    )]\n    private partial void LogErrorClearingState(Exception exception, string grainType, string id);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Initializing: Name={Name} ServiceId={ServiceId} Collection={Collection} DeleteStateOnClear={DeleteStateOnClear}\"\n    )]\n    private partial void LogDebugInit(string name, string serviceId, string collection, bool deleteStateOnClear);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Initializing provider {ProviderName} of type {ProviderType} in stage {Stage} took {ElapsedMilliseconds} milliseconds\"\n    )]\n    private partial void LogDebugInitializingProvider(string providerName, string providerType, int stage, long elapsedMilliseconds);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Provider_ErrorFromInit,\n        Level = LogLevel.Error,\n        Message = \"Initialization failed for provider {ProviderName} of type {ProviderType} in stage {Stage} in {ElapsedMilliseconds} milliseconds\"\n    )]\n    private partial void LogErrorInitializationFailed(Exception exception, string providerName, string providerType, int stage, long elapsedMilliseconds);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error initializing Azure Cosmos DB client for grain storage provider\"\n    )]\n    private partial void LogErrorInitializingClient(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error deleting Azure Cosmos DB database\"\n    )]\n    private partial void LogErrorDeletingDatabase(Exception exception);\n}\n\npublic static class CosmosStorageFactory\n{\n    public static CosmosGrainStorage Create(IServiceProvider services, string name)\n    {\n        var optionsMonitor = services.GetRequiredService<IOptionsMonitor<CosmosGrainStorageOptions>>();\n        var partitionKeyProvider = services.GetKeyedService<IPartitionKeyProvider>(name)\n            ?? services.GetRequiredService<IPartitionKeyProvider>();\n        var loggerFactory = services.GetRequiredService<ILoggerFactory>();\n        var clusterOptions = services.GetRequiredService<IOptions<ClusterOptions>>();\n        var activatorProvider = services.GetRequiredService<IActivatorProvider>();\n        return new CosmosGrainStorage(\n            name,\n            optionsMonitor.Get(name),\n            loggerFactory,\n            services,\n            clusterOptions,\n            partitionKeyProvider,\n            activatorProvider);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/CosmosStorageOptions.cs",
    "content": "using Orleans.Core;\n\nnamespace Orleans.Persistence.Cosmos;\n\n/// <summary>\n/// Options for Azure Cosmos DB grain persistence.\n/// </summary>\npublic class CosmosGrainStorageOptions : CosmosOptions\n{\n    private const string ORLEANS_STORAGE_CONTAINER = \"OrleansStorage\";\n    public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n    private const string DEFAULT_PARTITION_KEY_PATH = \"/PartitionKey\";\n\n    /// <summary>\n    /// Stage of silo lifecycle where storage should be initialized. Storage must be initialized prior to use.\n    /// </summary>\n    public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n\n    /// <summary>\n    /// Gets or sets a value indicating whether state should be deleted when <see cref=\"IStorage.ClearStateAsync()\"/> is called.\n    /// </summary>\n    public bool DeleteStateOnClear { get; set; }\n\n    /// <summary>\n    /// List of JSON path strings.\n    /// Each entry on this list represents a property in the State Object that will be included in the document index.\n    /// The default is to not add any property in the State object.\n    /// </summary>\n    public List<string> StateFieldsToIndex { get; set; } = new();\n\n    public string PartitionKeyPath { get; set; } = DEFAULT_PARTITION_KEY_PATH;\n\n    /// <summary>\n    /// Initializes a new <see cref=\"CosmosGrainStorageOptions\"/> instance.\n    /// </summary>\n    public CosmosGrainStorageOptions()\n    {\n        ContainerName = ORLEANS_STORAGE_CONTAINER;\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/HostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.Storage;\nusing Orleans.Providers;\nusing Orleans.Persistence.Cosmos;\nusing Orleans.Runtime.Hosting;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Extension methods for configuring Azure Cosmos DB persistence.\n/// </summary>\npublic static class HostingExtensions\n{\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <typeparam name=\"TPartitionKeyProvider\">The custom partition key provider type.</typeparam>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault<TPartitionKeyProvider>(\n        this ISiloBuilder builder,\n        Action<CosmosGrainStorageOptions> configureOptions) where TPartitionKeyProvider : class, IPartitionKeyProvider\n    {\n        return builder.AddCosmosGrainStorage<TPartitionKeyProvider>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <typeparam name=\"TPartitionKeyProvider\">The custom partition key provider type.</typeparam>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorage<TPartitionKeyProvider>(\n        this ISiloBuilder builder,\n        string name,\n        Action<CosmosGrainStorageOptions> configureOptions) where TPartitionKeyProvider : class, IPartitionKeyProvider\n    {\n        builder.Services.AddKeyedSingleton<IPartitionKeyProvider, TPartitionKeyProvider>(name);\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <param name=\"customPartitionKeyProviderType\">The custom partition key provider type.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault(\n        this ISiloBuilder builder,\n        Action<CosmosGrainStorageOptions> configureOptions,\n        Type customPartitionKeyProviderType)\n    {\n        return builder.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions, customPartitionKeyProviderType);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    /// <param name=\"customPartitionKeyProviderType\">The custom partition key provider type.</param>\n    public static ISiloBuilder AddCosmosGrainStorage(\n        this ISiloBuilder builder,\n        string name,\n        Action<CosmosGrainStorageOptions> configureOptions,\n        Type customPartitionKeyProviderType)\n    {\n        if (customPartitionKeyProviderType != null)\n        {\n            builder.Services.TryAddSingleton(typeof(IPartitionKeyProvider), customPartitionKeyProviderType);\n        }\n\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault(\n        this ISiloBuilder builder,\n        Action<CosmosGrainStorageOptions> configureOptions)\n    {\n        return builder.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorage(\n        this ISiloBuilder builder,\n        string name,\n        Action<CosmosGrainStorageOptions> configureOptions)\n    {\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <typeparam name=\"TPartitionKeyProvider\">The custom partition key provider type.</typeparam>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault<TPartitionKeyProvider>(\n        this ISiloBuilder builder,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null) where TPartitionKeyProvider : class, IPartitionKeyProvider\n    {\n        return builder.AddCosmosGrainStorage<TPartitionKeyProvider>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <typeparam name=\"TPartitionKeyProvider\">The custom partition key provider type.</typeparam>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorage<TPartitionKeyProvider>(\n        this ISiloBuilder builder,\n        string name,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null) where TPartitionKeyProvider : class, IPartitionKeyProvider\n    {\n        builder.Services.AddKeyedSingleton<IPartitionKeyProvider, TPartitionKeyProvider>(name);\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"customPartitionKeyProviderType\">The custom partition key provider type.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault(\n        this ISiloBuilder builder,\n        Type customPartitionKeyProviderType,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        return builder.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, customPartitionKeyProviderType, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage using a custom Partition Key Provider.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorage(\n        this ISiloBuilder builder,\n        string name,\n        Type customPartitionKeyProviderType,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        if (customPartitionKeyProviderType != null)\n        {\n            builder.Services.AddKeyedSingleton(typeof(IPartitionKeyProvider), name, customPartitionKeyProviderType);\n        }\n\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorageAsDefault(\n        this ISiloBuilder builder,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        return builder.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static ISiloBuilder AddCosmosGrainStorage(\n        this ISiloBuilder builder,\n        string name,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        builder.Services.AddCosmosGrainStorage(name, configureOptions);\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static IServiceCollection AddCosmosGrainStorageAsDefault(\n        this IServiceCollection services,\n        Action<CosmosGrainStorageOptions> configureOptions)\n    {\n        return services.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, ob => ob.Configure(configureOptions));\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static IServiceCollection AddCosmosGrainStorage(\n        this IServiceCollection services,\n        string name,\n        Action<CosmosGrainStorageOptions> configureOptions)\n    {\n        return services.AddCosmosGrainStorage(name, ob => ob.Configure(configureOptions));\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage as the default grain storage.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static IServiceCollection AddCosmosGrainStorageAsDefault(\n        this IServiceCollection services,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        return services.AddCosmosGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n    }\n\n    /// <summary>\n    /// Configure silo to use Azure Cosmos DB storage for grain storage.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"name\">The storage provider name.</param>\n    /// <param name=\"configureOptions\">The delegate used to configure the provider.</param>\n    public static IServiceCollection AddCosmosGrainStorage(\n        this IServiceCollection services,\n        string name,\n        Action<OptionsBuilder<CosmosGrainStorageOptions>>? configureOptions = null)\n    {\n        configureOptions?.Invoke(services.AddOptions<CosmosGrainStorageOptions>(name));\n        services.AddTransient<IConfigurationValidator>(\n            sp => new CosmosOptionsValidator<CosmosGrainStorageOptions>(\n                sp.GetService<IOptionsMonitor<CosmosGrainStorageOptions>>()!.Get(name),\n                name));\n        services.ConfigureNamedOptionForLogging<CosmosGrainStorageOptions>(name);\n        services.TryAddSingleton<IPartitionKeyProvider, DefaultPartitionKeyProvider>();\n        return services.AddGrainStorage(name, CosmosStorageFactory.Create);\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/IPartitionKeyProvider.cs",
    "content": "namespace Orleans.Persistence.Cosmos;\n\n/// <summary>\n/// Creates a partition key for the provided grain.\n/// </summary>\npublic interface IPartitionKeyProvider\n{\n    /// <summary>\n    /// Creates a partition key for the provided grain.\n    /// </summary>\n    /// <param name=\"grainType\">The grain type.</param>\n    /// <param name=\"grainId\">The grain identifier.</param>\n    /// <returns>The partition key.</returns>\n    ValueTask<string> GetPartitionKey(string grainType, GrainId grainId);\n}\n\ninternal class DefaultPartitionKeyProvider : IPartitionKeyProvider\n{\n    public ValueTask<string> GetPartitionKey(string grainType, GrainId grainId) => new(CosmosIdSanitizer.Sanitize(grainType));\n}"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/Models/GrainStateEntity.cs",
    "content": "using Newtonsoft.Json;\n\nnamespace Orleans.Persistence.Cosmos;\n\ninternal class GrainStateEntity<TState> : BaseEntity\n{\n    [JsonProperty(nameof(GrainType))]\n    [JsonPropertyName(nameof(GrainType))]\n    public string GrainType { get; set; } = default!;\n\n    [JsonProperty(nameof(State))]\n    [JsonPropertyName(nameof(State))]\n    public TState State { get; set; } = default!;\n\n    [JsonProperty(nameof(PartitionKey))]\n    [JsonPropertyName(nameof(PartitionKey))]\n    public string PartitionKey { get; set; } = default!;\n}"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/Orleans.Persistence.Cosmos.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Persistence.Cosmos</PackageId>\n    <Title>Microsoft Orleans Grain Storage for Azure Cosmos DB</Title>\n    <Description>Microsoft Orleans persistence providers for Azure Cosmos DB</Description>\n    <PackageTags>$(PackageTags) Azure Cosmos DB Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Persistence.Cosmos</AssemblyName>\n    <RootNamespace>Orleans.Persistence.Cosmos</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_PERSISTENCE</DefineConstants>\n    <Nullable>enable</Nullable>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptions.cs\" Link=\"Storage\\CosmosOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptionsValidator.cs\" Link=\"Storage\\CosmosOptionsValidator.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\BaseEntity.cs\" Link=\"Storage\\BaseEntity.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\Usings.cs\" Link=\"Storage\\Usings.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosIdSanitizer.cs\" Link=\"Storage\\CosmosIdSanitizer.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Microsoft.Azure.Cosmos\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Include=\"System.Runtime.CompilerServices.InternalsVisibleToAttribute\">\n      <_Parameter1>Orleans.Cosmos.Tests</_Parameter1>\n    </AssemblyAttribute>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Azure/Orleans.Persistence.Cosmos/README.md",
    "content": "# Microsoft Orleans Persistence for Azure Cosmos DB\n\n## Introduction\nMicrosoft Orleans Persistence for Azure Cosmos DB provides grain persistence for Microsoft Orleans using Azure Cosmos DB. This allows your grains to persist their state in Azure Cosmos DB and reload it when they are reactivated, offering a globally distributed, multi-model database service for your Orleans applications.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Persistence.Cosmos\n```\n\n## Example - Configuring Azure Cosmos DB Persistence\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Cosmos DB as grain storage\n            .AddCosmosGrainStorage(\n                name: \"cosmosStore\",\n                configureOptions: options =>\n                {\n                    options.AccountEndpoint = \"https://YOUR_COSMOS_ENDPOINT\";\n                    options.AccountKey = \"YOUR_COSMOS_KEY\";\n                    options.DB = \"YOUR_DATABASE_NAME\";\n                    options.CanCreateResources = true;\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Grain Storage in a Grain\n```csharp\n// Define grain state class\n\npublic class MyGrainState\n{\n    public string Data { get; set; }\n    public int Version { get; set; }\n}\n\n// Grain implementation that uses the Cosmos DB storage\npublic class MyGrain : Grain, IMyGrain, IGrainWithStringKey\n{\n    private readonly IPersistentState<MyGrainState> _state;\n\n    public MyGrain([PersistentState(\"state\", \"cosmosStore\")] IPersistentState<MyGrainState> state)\n    {\n        _state = state;\n    }\n\n    public async Task SetData(string data)\n    {\n        _state.State.Data = data;\n        _state.State.Version++;\n        await _state.WriteStateAsync();\n    }\n\n    public Task<string> GetData()\n    {\n        return Task.FromResult(_state.State.Data);\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n- [Azure Storage Providers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence/azure-storage)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/AzureStorageReminderServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Reminders.AzureStorage;\nusing Orleans.Runtime.ReminderService;\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class AzureStorageReminderServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n        /// </returns>\n        public static IServiceCollection UseAzureTableReminderService(this IServiceCollection services, Action<AzureTableReminderStorageOptions> configure)\n        {\n            services.AddReminders();\n            services.AddSingleton<IReminderTable, AzureBasedReminderTable>();\n            services.Configure<AzureTableReminderStorageOptions>(configure);\n            services.ConfigureFormatter<AzureTableReminderStorageOptions>();\n            return services;\n        }\n\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n        /// </returns>\n        public static IServiceCollection UseAzureTableReminderService(this IServiceCollection services, Action<OptionsBuilder<AzureTableReminderStorageOptions>> configureOptions)\n        {\n            services.AddReminders();\n            services.AddSingleton<IReminderTable, AzureBasedReminderTable>();\n            configureOptions?.Invoke(services.AddOptions<AzureTableReminderStorageOptions>());\n            services.ConfigureFormatter<AzureTableReminderStorageOptions>();\n            services.AddTransient<IConfigurationValidator>(sp => new AzureTableReminderStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureTableReminderStorageOptions>>().Get(Options.DefaultName), Options.DefaultName));\n            return services;\n        }\n\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        /// <param name=\"connectionString\">\n        /// The storage connection string.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n        /// </returns>\n        public static IServiceCollection UseAzureTableReminderService(this IServiceCollection services, string connectionString)\n        {\n            services.UseAzureTableReminderService(options =>\n            {\n                if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                {\n                    options.TableServiceClient = new(uri);\n                }\n                else\n                {\n                    options.TableServiceClient = new(connectionString);\n                }\n            });\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/AzureStorageReminderSiloBuilderReminderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Reminders.AzureStorage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo host builder extensions.\n    /// </summary>\n    public static class AzureStorageReminderSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n        /// </returns>\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, Action<AzureTableReminderStorageOptions> configure)\n        {\n            builder.ConfigureServices(services => services.UseAzureTableReminderService(configure));\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n        /// </returns>\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, Action<OptionsBuilder<AzureTableReminderStorageOptions>> configureOptions)\n        {\n            builder.ConfigureServices(services => services.UseAzureTableReminderService(configureOptions));\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds reminder storage backed by Azure Table Storage.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"connectionString\">\n        /// The storage connection string.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n        /// </returns>\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, string connectionString)\n        {\n            builder.UseAzureTableReminderService(options =>\n            {\n                if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                {\n                    options.TableServiceClient = new(uri);\n                }\n                else\n                {\n                    options.TableServiceClient = new(connectionString);\n                }\n            });\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/AzureTableStorageRemindersProviderBuilder.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Reminders.AzureStorage;\n\n[assembly: RegisterProvider(\"AzureTableStorage\", \"Reminders\", \"Silo\", typeof(AzureTableStorageRemindersProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class AzureTableStorageRemindersProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseAzureTableReminderService((OptionsBuilder<AzureTableReminderStorageOptions> optionsBuilder) =>\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var tableName = configurationSection[\"TableName\"];\n                if (!string.IsNullOrEmpty(tableName))\n                {\n                    options.TableName = tableName; \n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.TableServiceClient = services.GetRequiredKeyedService<TableServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            options.TableServiceClient = new(uri);\n                        }\n                        else\n                        {\n                            options.TableServiceClient = new(connectionString);\n                        }\n                    }\n                }\n            }));\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/Orleans.Reminders.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Reminders.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Table Storage Reminders Provider</Title>\n    <Description>Microsoft Orleans reminders provider backed by Azure Table Storage</Description>\n    <PackageTags>$(PackageTags) Azure Table Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Reminders.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.Reminders.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_REMINDERS</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/README.md",
    "content": "# Microsoft Orleans Reminders for Azure Storage\n\n## Introduction\nMicrosoft Orleans Reminders for Azure Storage provides persistence for Orleans reminders using Azure Table Storage. This allows your Orleans applications to schedule persistent reminders that will be triggered even after silo restarts or grain deactivation.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Reminders.AzureStorage\n```\n\n## Example - Configuring Azure Storage Reminders\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Table Storage as reminder storage\n            .UseAzureTableReminderService(options =>\n            {\n                options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                options.TableName = \"OrleansReminders\";\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Reminders in a Grain\n```csharp\npublic interface IReminderGrain\n{\n    Task StartReminder(string reminderName);\n    Task StopReminder();\n}\n\npublic class ReminderGrain : Grain, IReminderGrain, IRemindable\n{\n    private string _reminderName = \"MyReminder\";\n\n    public async Task StartReminder(string reminderName)\n    {\n        _reminderName = reminderName;\n        \n        // Register a persistent reminder\n        await RegisterOrUpdateReminder(\n            reminderName,\n            TimeSpan.FromMinutes(2),  // Time to delay before the first tick (must be > 1 minute)\n            TimeSpan.FromMinutes(5)); // Period of the reminder (must be > 1 minute)\n    }\n\n    public async Task StopReminder()\n    {\n        // Find and unregister the reminder\n        var reminder = await GetReminder(_reminderName);\n        if (reminder != null)\n        {\n            await UnregisterReminder(reminder);\n        }\n    }\n\n    public Task ReceiveReminder(string reminderName, TickStatus status)\n    {\n        // This method is called when the reminder ticks\n        Console.WriteLine($\"Reminder {reminderName} triggered at {DateTime.UtcNow}. Status: {status}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Reminders and Timers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n- [Reminder Services](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/reminder-services)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/Storage/AzureBasedReminderTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.AzureUtils.Utilities;\nusing Orleans.Configuration;\nusing Orleans.Reminders.AzureStorage;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    public sealed partial class AzureBasedReminderTable : IReminderTable\n    {\n        private readonly ILogger logger;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ClusterOptions clusterOptions;\n        private readonly AzureTableReminderStorageOptions storageOptions;\n        private readonly RemindersTableManager remTableManager;\n        private readonly TaskCompletionSource _initializationTask = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        public AzureBasedReminderTable(\n            ILoggerFactory loggerFactory,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<AzureTableReminderStorageOptions> storageOptions)\n        {\n            this.logger = loggerFactory.CreateLogger<AzureBasedReminderTable>();\n            this.loggerFactory = loggerFactory;\n            this.clusterOptions = clusterOptions.Value;\n            this.storageOptions = storageOptions.Value;\n            this.remTableManager = new RemindersTableManager(\n                this.clusterOptions.ServiceId,\n                this.clusterOptions.ClusterId,\n                this.storageOptions,\n                this.loggerFactory);\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                while (true)\n                {\n                    try\n                    {\n                        await remTableManager.InitTableAsync();\n                        _initializationTask.TrySetResult();\n                        return;\n                    }\n                    catch (Exception ex) when (!cancellationToken.IsCancellationRequested)\n                    {\n                        LogErrorCreatingAzureTable(ex);\n                        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);\n                    }\n                }\n            }\n            catch (OperationCanceledException ex)\n            {\n                LogErrorReminderTableInitializationCanceled(ex);\n                _initializationTask.TrySetCanceled(ex.CancellationToken);\n                throw;\n            }\n            catch (Exception ex)\n            {\n                LogErrorInitializingReminderTable(ex);\n                _initializationTask.TrySetException(ex);\n                throw;\n            }\n        }\n\n        public Task StopAsync(CancellationToken cancellationToken)\n        {\n            _initializationTask.TrySetCanceled(CancellationToken.None);\n            return Task.CompletedTask;\n        }\n\n        private ReminderTableData ConvertFromTableEntryList(List<(ReminderTableEntry Entity, string ETag)> entries)\n        {\n            var remEntries = new List<ReminderEntry>();\n            foreach (var entry in entries)\n            {\n#pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception.\n                try\n                {\n                    ReminderEntry converted = ConvertFromTableEntry(entry.Entity, entry.ETag);\n                    remEntries.Add(converted);\n                }\n                catch (Exception)\n                {\n                    // Ignoring...\n                }\n#pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception.\n            }\n            return new ReminderTableData(remEntries);\n        }\n\n        private ReminderEntry ConvertFromTableEntry(ReminderTableEntry tableEntry, string eTag)\n        {\n            try\n            {\n                return new ReminderEntry\n                {\n                    GrainId = GrainId.Parse(tableEntry.GrainReference),\n                    ReminderName = tableEntry.ReminderName,\n                    StartAt = LogFormatter.ParseDate(tableEntry.StartAt),\n                    Period = TimeSpan.Parse(tableEntry.Period),\n                    ETag = eTag,\n                };\n            }\n            catch (Exception exc)\n            {\n                LogErrorParsingReminderEntry(exc, tableEntry);\n                throw;\n            }\n            finally\n            {\n                string serviceIdStr = this.clusterOptions.ServiceId;\n                if (!tableEntry.ServiceId.Equals(serviceIdStr))\n                {\n                    LogWarningAzureTable_ReadWrongReminder(tableEntry, serviceIdStr);\n                    throw new OrleansException($\"Read a reminder entry for wrong Service id. Read {tableEntry}, but my service id is {serviceIdStr}. Going to discard it.\");\n                }\n            }\n        }\n\n        private static ReminderTableEntry ConvertToTableEntry(ReminderEntry remEntry, string serviceId, string deploymentId)\n        {\n            string partitionKey = ReminderTableEntry.ConstructPartitionKey(serviceId, remEntry.GrainId);\n            string rowKey = ReminderTableEntry.ConstructRowKey(remEntry.GrainId, remEntry.ReminderName);\n\n            var consistentHash = remEntry.GrainId.GetUniformHashCode();\n\n            return new ReminderTableEntry\n            {\n                PartitionKey = partitionKey,\n                RowKey = rowKey,\n\n                ServiceId = serviceId,\n                DeploymentId = deploymentId,\n                GrainReference = remEntry.GrainId.ToString(),\n                ReminderName = remEntry.ReminderName,\n\n                StartAt = LogFormatter.PrintDate(remEntry.StartAt),\n                Period = remEntry.Period.ToString(),\n\n                GrainRefConsistentHash = consistentHash.ToString(\"X8\"),\n                ETag = new ETag(remEntry.ETag),\n            };\n        }\n\n        public async Task TestOnlyClearTable()\n        {\n            await _initializationTask.Task;\n\n            await this.remTableManager.DeleteTableEntries();\n        }\n\n        public async Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            try\n            {\n                await _initializationTask.Task;\n\n                var entries = await this.remTableManager.FindReminderEntries(grainId);\n                ReminderTableData data = ConvertFromTableEntryList(entries);\n                LogTraceReadForGrain(grainId, data);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadingReminders(exc, grainId, this.remTableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<ReminderTableData> ReadRows(uint begin, uint end)\n        {\n            try\n            {\n                await _initializationTask.Task;\n\n                var entries = await this.remTableManager.FindReminderEntries(begin, end);\n                ReminderTableData data = ConvertFromTableEntryList(entries);\n                LogTraceReadInRange(new(begin, end), data);\n                return data;\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadingReminderRange(exc, new(begin, end), this.remTableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            try\n            {\n                await _initializationTask.Task;\n\n                LogDebugReadRow(grainId, reminderName);\n                var result = await this.remTableManager.FindReminderEntry(grainId, reminderName);\n                return result.Entity is null ? null : ConvertFromTableEntry(result.Entity, result.ETag);\n            }\n            catch (Exception exc)\n            {\n                LogWarningReadingReminderRow(exc, grainId, reminderName, this.remTableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<string> UpsertRow(ReminderEntry entry)\n        {\n            try\n            {\n                await _initializationTask.Task;\n\n                LogDebugUpsertRow(entry);\n                ReminderTableEntry remTableEntry = ConvertToTableEntry(entry, this.clusterOptions.ServiceId, this.clusterOptions.ClusterId);\n\n                string result = await this.remTableManager.UpsertRow(remTableEntry);\n                if (result == null)\n                {\n                    LogWarningReminderUpsertFailed(entry);\n                }\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningUpsertReminderEntry(exc, entry, this.remTableManager.TableName);\n                throw;\n            }\n        }\n\n        public async Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            var entry = new ReminderTableEntry\n            {\n                PartitionKey = ReminderTableEntry.ConstructPartitionKey(this.clusterOptions.ServiceId, grainId),\n                RowKey = ReminderTableEntry.ConstructRowKey(grainId, reminderName),\n                ETag = new ETag(eTag),\n            };\n\n            try\n            {\n                await _initializationTask.Task;\n\n                LogTraceRemoveRow(entry);\n\n                bool result = await this.remTableManager.DeleteReminderEntryConditionally(entry, eTag);\n                if (result == false)\n                {\n                    LogWarningOnReminderDeleteRetry(entry);\n                }\n                return result;\n            }\n            catch (Exception exc)\n            {\n                LogWarningWhenDeletingReminder(exc, entry, this.remTableManager.TableName);\n                throw;\n            }\n        }\n\n        private readonly struct RingRangeLogValue(uint Begin, uint End)\n        {\n            public override string ToString() => RangeFactory.CreateRange(Begin, End).ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)AzureReminderErrorCode.AzureTable_39,\n            Message = \"Exception trying to create or connect to the Azure table\"\n        )]\n        private partial void LogErrorCreatingAzureTable(Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Reminder table initialization canceled.\"\n        )]\n        private partial void LogErrorReminderTableInitializationCanceled(Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error initializing reminder table.\"\n        )]\n        private partial void LogErrorInitializingReminderTable(Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)AzureReminderErrorCode.AzureTable_49,\n            Message = \"Failed to parse ReminderTableEntry: {TableEntry}. This entry is corrupt, going to ignore it.\"\n        )]\n        private partial void LogErrorParsingReminderEntry(Exception ex, object tableEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_ReadWrongReminder,\n            Message = \"Read a reminder entry for wrong Service id. Read {TableEntry}, but my service id is {ServiceId}. Going to discard it.\"\n        )]\n        private partial void LogWarningAzureTable_ReadWrongReminder(ReminderTableEntry tableEntry, string serviceId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Read for grain {GrainId} Table={Data}\"\n        )]\n        private partial void LogTraceReadForGrain(GrainId grainId, ReminderTableData data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_47,\n            Message = \"Intermediate error reading reminders for grain {GrainId} in table {TableName}.\"\n        )]\n        private partial void LogWarningReadingReminders(Exception ex, GrainId grainId, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Read in {RingRange} Table={Data}\"\n        )]\n        private partial void LogTraceReadInRange(RingRangeLogValue ringRange, ReminderTableData data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_40,\n            Message = \"Intermediate error reading reminders in range {RingRange} for table {TableName}.\"\n        )]\n        private partial void LogWarningReadingReminderRange(Exception ex, RingRangeLogValue ringRange, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"ReadRow grainRef = {GrainId} reminderName = {ReminderName}\"\n        )]\n        private partial void LogDebugReadRow(GrainId grainId, string reminderName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_46,\n            Message = \"Intermediate error reading row with grainId = {GrainId} reminderName = {ReminderName} from table {TableName}.\"\n        )]\n        private partial void LogWarningReadingReminderRow(Exception ex, GrainId grainId, string reminderName, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpsertRow entry = {Data}\"\n        )]\n        private partial void LogDebugUpsertRow(ReminderEntry data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_45,\n            Message = \"Upsert failed on the reminder table. Will retry. Entry = {Data}\"\n        )]\n        private partial void LogWarningReminderUpsertFailed(ReminderEntry data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_42,\n            Message = \"Intermediate error upserting reminder entry {Data} to the table {TableName}.\"\n        )]\n        private partial void LogWarningUpsertReminderEntry(Exception ex, ReminderEntry data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"RemoveRow entry = {Data}\"\n        )]\n        private partial void LogTraceRemoveRow(ReminderTableEntry data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_43,\n            Message = \"Delete failed on the reminder table. Will retry. Entry = {Data}\"\n        )]\n        private partial void LogWarningOnReminderDeleteRetry(ReminderTableEntry data);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureReminderErrorCode.AzureTable_44,\n            Message = \"Intermediate error when deleting reminder entry {Data} to the table {TableName}.\"\n        )]\n        private partial void LogWarningWhenDeletingReminder(Exception ex, ReminderTableEntry data, string tableName);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/Storage/AzureTableReminderStorageOptions.cs",
    "content": "namespace Orleans.Reminders.AzureStorage\n{\n    /// <summary>Options for Azure Table based reminder table.</summary>\n    public class AzureTableReminderStorageOptions : AzureStorageOperationOptions\n    {\n        /// <summary>\n        /// Table name for Azure Storage\n        /// </summary>\n        public override string TableName { get; set; } = DEFAULT_TABLE_NAME;\n        public const string DEFAULT_TABLE_NAME = \"OrleansReminders\";\n    }\n\n    /// <summary>\n    /// Configuration validator for <see cref=\"AzureTableReminderStorageOptions\"/>.\n    /// </summary>\n    public class AzureTableReminderStorageOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableReminderStorageOptions>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AzureTableReminderStorageOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        public AzureTableReminderStorageOptionsValidator(AzureTableReminderStorageOptions options, string name) : base(options, name)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/Storage/RemindersTableManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Reminders.AzureStorage;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    internal sealed class ReminderTableEntry : ITableEntity\n    {\n        public string GrainReference        { get; set; }    // Part of RowKey\n        public string ReminderName          { get; set; }    // Part of RowKey\n        public string ServiceId             { get; set; }    // Part of PartitionKey\n        public string DeploymentId          { get; set; }\n        public string StartAt               { get; set; }\n        public string Period                { get; set; }\n        public string GrainRefConsistentHash { get; set; }    // Part of PartitionKey\n\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n\n        public static string ConstructRowKey(GrainId grainId, string reminderName)\n            => AzureTableUtils.SanitizeTableProperty($\"{grainId}-{reminderName}\");\n\n        public static (string LowerBound, string UpperBound) ConstructRowKeyBounds(GrainId grainId)\n        {\n            var baseKey = AzureTableUtils.SanitizeTableProperty(grainId.ToString());\n            return (baseKey + '-', baseKey + (char)('-' + 1));\n        }\n\n        public static string ConstructPartitionKey(string serviceId, GrainId grainId)\n            => ConstructPartitionKey(serviceId, grainId.GetUniformHashCode());\n\n        public static string ConstructPartitionKey(string serviceId, uint number)\n        {\n            // IMPORTANT NOTE: Other code using this return data is very sensitive to format changes,\n            //       so take great care when making any changes here!!!\n\n            // this format of partition key makes sure that the comparisons in FindReminderEntries(begin, end) work correctly\n            // the idea is that when converting to string, negative numbers start with 0, and positive start with 1. Now,\n            // when comparisons will be done on strings, this will ensure that positive numbers are always greater than negative\n            // string grainHash = number < 0 ? string.Format(\"0{0}\", number.ToString(\"X\")) : string.Format(\"1{0:d16}\", number);\n\n            return AzureTableUtils.SanitizeTableProperty($\"{serviceId}_{number:X8}\");\n        }\n\n        public static (string LowerBound, string UpperBound) ConstructPartitionKeyBounds(string serviceId)\n        {\n            var baseKey = AzureTableUtils.SanitizeTableProperty(serviceId);\n            return (baseKey + '_', baseKey + (char)('_' + 1));\n        }\n\n        public override string ToString() => $\"Reminder [PartitionKey={PartitionKey} RowKey={RowKey} GrainId={GrainReference} ReminderName={ReminderName} Deployment={DeploymentId} ServiceId={ServiceId} StartAt={StartAt} Period={Period} GrainRefConsistentHash={GrainRefConsistentHash}]\";\n    }\n\n    internal sealed partial class RemindersTableManager : AzureTableDataManager<ReminderTableEntry>\n    {\n        private readonly string _serviceId;\n        private readonly string _clusterId;\n\n        public RemindersTableManager(\n            string serviceId,\n            string clusterId,\n            AzureStorageOperationOptions options,\n            ILoggerFactory loggerFactory)\n            : base(options, loggerFactory.CreateLogger<RemindersTableManager>())\n        {\n            _clusterId = clusterId;\n            _serviceId = serviceId;\n        }\n\n        internal async Task<List<(ReminderTableEntry Entity, string ETag)>> FindReminderEntries(uint begin, uint end)\n        {\n            string sBegin = ReminderTableEntry.ConstructPartitionKey(_serviceId, begin);\n            string sEnd = ReminderTableEntry.ConstructPartitionKey(_serviceId, end);\n            string query;\n            if (begin < end)\n            {\n                // Query between the specified lower and upper bounds.\n                // Note that the lower bound is exclusive and the upper bound is inclusive in the below query.\n                query = TableClient.CreateQueryFilter($\"(PartitionKey gt {sBegin}) and (PartitionKey le {sEnd})\");\n            }\n            else\n            {\n                var (partitionKeyLowerBound, partitionKeyUpperBound) = ReminderTableEntry.ConstructPartitionKeyBounds(_serviceId);\n                if (begin == end)\n                {\n                    // Query the entire range\n                    query = TableClient.CreateQueryFilter($\"(PartitionKey gt {partitionKeyLowerBound}) and (PartitionKey lt {partitionKeyUpperBound})\");\n                }\n                else\n                {\n                    // (begin > end)\n                    // Query wraps around the ends of the range, so the query is the union of two disjunct queries\n                    // Include everything outside of the (begin, end] range, which wraps around to become:\n                    // [partitionKeyLowerBound, end] OR (begin, partitionKeyUpperBound]\n                    Debug.Assert(begin > end);\n                    query = TableClient.CreateQueryFilter($\"((PartitionKey gt {partitionKeyLowerBound}) and (PartitionKey le {sEnd})) or ((PartitionKey gt {sBegin}) and (PartitionKey lt {partitionKeyUpperBound}))\");\n                }\n            }\n\n            return await ReadTableEntriesAndEtagsAsync(query);\n        }\n\n        internal async Task<List<(ReminderTableEntry Entity, string ETag)>> FindReminderEntries(GrainId grainId)\n        {\n            var partitionKey = ReminderTableEntry.ConstructPartitionKey(_serviceId, grainId);\n            var (rowKeyLowerBound, rowKeyUpperBound) = ReminderTableEntry.ConstructRowKeyBounds(grainId);\n            var query = TableClient.CreateQueryFilter($\"(PartitionKey eq {partitionKey}) and ((RowKey gt {rowKeyLowerBound}) and (RowKey le {rowKeyUpperBound}))\");\n            return await ReadTableEntriesAndEtagsAsync(query);\n        }\n\n        internal async Task<(ReminderTableEntry Entity, string ETag)> FindReminderEntry(GrainId grainId, string reminderName)\n        {\n            string partitionKey = ReminderTableEntry.ConstructPartitionKey(_serviceId, grainId);\n            string rowKey = ReminderTableEntry.ConstructRowKey(grainId, reminderName);\n\n            return await ReadSingleTableEntryAsync(partitionKey, rowKey);\n        }\n\n        private Task<List<(ReminderTableEntry Entity, string ETag)>> FindAllReminderEntries()\n        {\n            return FindReminderEntries(0, 0);\n        }\n\n        internal async Task<string> UpsertRow(ReminderTableEntry reminderEntry)\n        {\n            try\n            {\n                return await UpsertTableEntryAsync(reminderEntry);\n            }\n            catch(Exception exc)\n            {\n                if (AzureTableUtils.EvaluateException(exc, out var httpStatusCode, out var restStatus))\n                {\n                    LogTraceUpsertRowFailed(Logger, httpStatusCode, restStatus);\n                    if (AzureTableUtils.IsContentionError(httpStatusCode)) return null; // false;\n                }\n                throw;\n            }\n        }\n\n\n        internal async Task<bool> DeleteReminderEntryConditionally(ReminderTableEntry reminderEntry, string eTag)\n        {\n            try\n            {\n                await DeleteTableEntryAsync(reminderEntry, eTag);\n                return true;\n            }\n            catch(Exception exc)\n            {\n                if (AzureTableUtils.EvaluateException(exc, out var httpStatusCode, out var restStatus))\n                {\n                    LogTraceDeleteReminderEntryConditionallyFailed(Logger, httpStatusCode, restStatus);\n                    if (AzureTableUtils.IsContentionError(httpStatusCode)) return false;\n                }\n                throw;\n            }\n        }\n\n        internal async Task DeleteTableEntries()\n        {\n            List<(ReminderTableEntry Entity, string ETag)> entries = await FindAllReminderEntries();\n            // return manager.DeleteTableEntries(entries); // this doesnt work as entries can be across partitions, which is not allowed\n            // group by grain hashcode so each query goes to different partition\n            var tasks = new List<Task>();\n            var groupedByHash = entries\n                .Where(tuple => tuple.Entity.ServiceId.Equals(_serviceId))\n                .Where(tuple => tuple.Entity.DeploymentId.Equals(_clusterId))  // delete only entries that belong to our DeploymentId.\n                .GroupBy(x => x.Entity.GrainRefConsistentHash).ToDictionary(g => g.Key, g => g.ToList());\n\n            foreach (var entriesPerPartition in groupedByHash.Values)\n            {\n                foreach (var batch in entriesPerPartition.BatchIEnumerable(this.StoragePolicyOptions.MaxBulkUpdateRows))\n                {\n                    tasks.Add(DeleteTableEntriesAsync(batch));\n                }\n            }\n\n            await Task.WhenAll(tasks);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"UpsertRow failed with HTTP status code: {HttpStatusCode}, REST status: {RestStatus}\"\n        )]\n        private static partial void LogTraceUpsertRowFailed(ILogger logger, HttpStatusCode httpStatusCode, string restStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"DeleteReminderEntryConditionally failed with HTTP status code: {HttpStatusCode}, REST status: {RestStatus}\"\n        )]\n        private static partial void LogTraceDeleteReminderEntryConditionallyFailed(ILogger logger, HttpStatusCode httpStatusCode, string restStatus);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.AzureStorage/Utilities/AzureReminderErrorCode.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.AzureUtils.Utilities\n{\n    [SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n    internal enum AzureReminderErrorCode\n    {\n        Runtime = 100000,\n        AzureTableBase = Runtime + 800,\n\n        // reminders related\n        AzureTable_38 = AzureTableBase + 38,\n        AzureTable_39 = AzureTableBase + 39,\n        AzureTable_40 = AzureTableBase + 40,\n        AzureTable_42 = AzureTableBase + 42,\n        AzureTable_43 = AzureTableBase + 43,\n        AzureTable_44 = AzureTableBase + 44,\n        AzureTable_45 = AzureTableBase + 45,\n        AzureTable_46 = AzureTableBase + 46,\n        AzureTable_47 = AzureTableBase + 47,\n        AzureTable_49 = AzureTableBase + 49,\n\n        AzureTable_ReadWrongReminder = AzureTableBase + 64\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/CosmosReminderTable.cs",
    "content": "using System.Net;\nusing System.Diagnostics;\nusing Orleans.Reminders.Cosmos.Models;\n\nnamespace Orleans.Reminders.Cosmos;\n\ninternal partial class CosmosReminderTable : IReminderTable\n{\n    private const HttpStatusCode TooManyRequests = (HttpStatusCode)429;\n    private const string PARTITION_KEY_PATH = \"/PartitionKey\";\n    private readonly CosmosReminderTableOptions _options;\n    private readonly ClusterOptions _clusterOptions;\n    private readonly ILogger _logger;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly Func<ReminderEntity, ReminderEntry> _convertEntityToEntry;\n    private readonly ICosmosOperationExecutor _executor;\n    private CosmosClient _client = default!;\n    private Container _container = default!;\n\n    public CosmosReminderTable(\n        ILoggerFactory loggerFactory,\n        IServiceProvider serviceProvider,\n        IOptions<CosmosReminderTableOptions> options,\n        IOptions<ClusterOptions> clusterOptions)\n    {\n        _logger = loggerFactory.CreateLogger<CosmosReminderTable>();\n        _serviceProvider = serviceProvider;\n        _options = options.Value;\n        _clusterOptions = clusterOptions.Value;\n        _convertEntityToEntry = FromEntity;\n        _executor = options.Value.OperationExecutor;\n    }\n\n    public async Task Init()\n    {\n        var stopWatch = Stopwatch.StartNew();\n\n        try\n        {\n            LogDebugInitializingCosmosReminderTable(_clusterOptions.ServiceId, _options.ContainerName);\n\n            await InitializeCosmosClient();\n\n            if (_options.IsResourceCreationEnabled)\n            {\n                if (_options.CleanResourcesOnInitialization)\n                {\n                    await TryDeleteDatabase();\n                }\n\n                await TryCreateCosmosResources();\n            }\n\n            _container = _client.GetContainer(_options.DatabaseName, _options.ContainerName);\n\n            stopWatch.Stop();\n\n            LogTraceInitializingCosmosReminderTableTook(stopWatch.ElapsedMilliseconds);\n        }\n        catch (Exception exc)\n        {\n            stopWatch.Stop();\n            LogErrorInitializationFailedForProviderCosmosReminderTable(exc, stopWatch.ElapsedMilliseconds);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<ReminderTableData> ReadRows(GrainId grainId)\n    {\n        try\n        {\n            var pk = new PartitionKey(ReminderEntity.ConstructPartitionKey(_clusterOptions.ServiceId, grainId));\n            var requestOptions = new QueryRequestOptions { PartitionKey = pk };\n            var response = await _executor.ExecuteOperation(static async args =>\n            {\n                var (self, grainId, requestOptions) = args;\n                var query = self._container.GetItemLinqQueryable<ReminderEntity>(requestOptions: requestOptions).ToFeedIterator();\n\n                var reminders = new List<ReminderEntity>();\n                do\n                {\n                    var queryResponse = await query.ReadNextAsync().ConfigureAwait(false);\n                    if (queryResponse != null && queryResponse.Count > 0)\n                    {\n                        reminders.AddRange(queryResponse);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                } while (query.HasMoreResults);\n\n                return reminders;\n            },\n            (this, grainId, requestOptions)).ConfigureAwait(false);\n\n            return new ReminderTableData(response.Select(_convertEntityToEntry));\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureReadingRemindersForGrain(exc, grainId, _container.Id);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<ReminderTableData> ReadRows(uint begin, uint end)\n    {\n        try\n        {\n            var response = await _executor.ExecuteOperation(static async args =>\n            {\n                var (self, begin, end) = args;\n                var query = self._container.GetItemLinqQueryable<ReminderEntity>()\n                    .Where(entity => entity.ServiceId == self._clusterOptions.ServiceId);\n\n                query = begin < end\n                    ? query.Where(r => r.GrainHash > begin && r.GrainHash <= end)\n                    : query.Where(r => r.GrainHash > begin || r.GrainHash <= end);\n\n                var iterator = query.ToFeedIterator();\n                var reminders = new List<ReminderEntity>();\n                do\n                {\n                    var queryResponse = await iterator.ReadNextAsync().ConfigureAwait(false);\n                    if (queryResponse != null && queryResponse.Count > 0)\n                    {\n                        reminders.AddRange(queryResponse);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                } while (iterator.HasMoreResults);\n\n                return reminders;\n            },\n            (this, begin, end)).ConfigureAwait(false);\n\n            return new ReminderTableData(response.Select(_convertEntityToEntry));\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureReadingRemindersForService(exc, _clusterOptions.ServiceId, new(begin), new(end));\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n    {\n        try\n        {\n            var pk = new PartitionKey(ReminderEntity.ConstructPartitionKey(_clusterOptions.ServiceId, grainId));\n            var id = ReminderEntity.ConstructId(grainId, reminderName);\n            var response = await _executor.ExecuteOperation(async args =>\n            {\n                try\n                {\n                    var (self, id, pk) = args;\n                    var result = await self._container.ReadItemAsync<ReminderEntity>(id, pk).ConfigureAwait(false);\n                    return result.Resource;\n                }\n                catch (CosmosException ce) when (ce.StatusCode == HttpStatusCode.NotFound)\n                {\n                    return null;\n                }\n            },\n            (this, id, pk)).ConfigureAwait(false);\n\n            return response != null ? FromEntity(response)! : default!;\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureReadingReminder(exc, reminderName, _clusterOptions.ServiceId, grainId);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<string> UpsertRow(ReminderEntry entry)\n    {\n        try\n        {\n            var entity = ToEntity(entry);\n            var pk = new PartitionKey(ReminderEntity.ConstructPartitionKey(_clusterOptions.ServiceId, entry.GrainId));\n            var options = new ItemRequestOptions { IfMatchEtag = entity.ETag };\n\n            var response = await _executor.ExecuteOperation(static async args =>\n            {\n                var (self, pk, entity, options) = args;\n                var result = await self._container.UpsertItemAsync(entity, pk, options).ConfigureAwait(false);\n                return result.Resource;\n            },\n            (this, pk, entity, options)).ConfigureAwait(false);\n\n            return response.ETag;\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureToUpsertReminder(exc, _clusterOptions.ServiceId);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n    {\n        try\n        {\n            var id = ReminderEntity.ConstructId(grainId, reminderName);\n            var options = new ItemRequestOptions { IfMatchEtag = eTag, };\n            var pk = new PartitionKey(ReminderEntity.ConstructPartitionKey(_clusterOptions.ServiceId, grainId));\n            await _executor.ExecuteOperation(static args =>\n            {\n                var (self, id, pk, options) = args;\n                return self._container.DeleteItemAsync<ReminderEntity>(id, pk, options);\n            },\n            (this, id, pk, options)).ConfigureAwait(false);\n\n            return true;\n        }\n        catch (CosmosException dce) when (dce.StatusCode is HttpStatusCode.PreconditionFailed)\n        {\n            return false;\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureRemovingReminders(exc, _clusterOptions.ServiceId, grainId, reminderName);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    public async Task TestOnlyClearTable()\n    {\n        try\n        {\n            var entities = await _executor.ExecuteOperation(static async self =>\n            {\n                var query = self._container.GetItemLinqQueryable<ReminderEntity>()\n                    .Where(entity => entity.ServiceId == self._clusterOptions.ServiceId)\n                    .ToFeedIterator();\n                var reminders = new List<ReminderEntity>();\n                do\n                {\n                    var queryResponse = await query.ReadNextAsync().ConfigureAwait(false);\n                    if (queryResponse != null && queryResponse.Count > 0)\n                    {\n                        reminders.AddRange(queryResponse);\n                    }\n                    else\n                    {\n                        break;\n                    }\n                } while (query.HasMoreResults);\n\n                return reminders;\n            }, this).ConfigureAwait(false);\n\n            var deleteTasks = new List<Task>();\n            foreach (var entity in entities)\n            {\n                deleteTasks.Add(_executor.ExecuteOperation(\n                    static args =>\n                    {\n                        var (self, id, pk) = args;\n                        return self._container.DeleteItemAsync<ReminderEntity>(id, pk);\n                    },\n                    (this, entity.Id, new PartitionKey(entity.PartitionKey))));\n            }\n            await Task.WhenAll(deleteTasks).ConfigureAwait(false);\n        }\n        catch (Exception exc)\n        {\n            LogErrorFailureToClearReminders(exc, _clusterOptions.ServiceId);\n            WrappedException.CreateAndRethrow(exc);\n            throw;\n        }\n    }\n\n    private async Task InitializeCosmosClient()\n    {\n        try\n        {\n            _client = await _options.CreateClient!(_serviceProvider).ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            LogErrorInitializingAzureCosmosDbClient(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task TryDeleteDatabase()\n    {\n        try\n        {\n            await _client.GetDatabase(_options.DatabaseName).DeleteAsync().ConfigureAwait(false);\n        }\n        catch (CosmosException dce) when (dce.StatusCode == HttpStatusCode.NotFound)\n        {\n            return;\n        }\n        catch (Exception ex)\n        {\n            LogErrorDeletingAzureCosmosDBDatabase(ex);\n            WrappedException.CreateAndRethrow(ex);\n            throw;\n        }\n    }\n\n    private async Task TryCreateCosmosResources()\n    {\n        var dbResponse = await _client.CreateDatabaseIfNotExistsAsync(_options.DatabaseName, _options.DatabaseThroughput).ConfigureAwait(false);\n        var db = dbResponse.Database;\n\n        var remindersCollection = new ContainerProperties(_options.ContainerName, PARTITION_KEY_PATH);\n\n        remindersCollection.IndexingPolicy.IndexingMode = IndexingMode.Consistent;\n        remindersCollection.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = \"/*\" });\n        remindersCollection.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/StartAt/*\" });\n        remindersCollection.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = \"/Period/*\" });\n        remindersCollection.IndexingPolicy.IndexingMode = IndexingMode.Consistent;\n\n        const int maxRetries = 3;\n        for (var retry = 0; retry <= maxRetries; ++retry)\n        {\n            var collResponse = await db.CreateContainerIfNotExistsAsync(remindersCollection, _options.ContainerThroughputProperties).ConfigureAwait(false);\n\n            if (retry == maxRetries || dbResponse.StatusCode != HttpStatusCode.Created || collResponse.StatusCode == HttpStatusCode.Created)\n            {\n                break;  // Apparently some throttling logic returns HttpStatusCode.OK (not 429) when the collection wasn't created in a new DB.\n            }\n\n            await Task.Delay(1000);\n        }\n    }\n\n    private ReminderEntry FromEntity(ReminderEntity entity)\n    {\n        return new ReminderEntry\n        {\n            GrainId = GrainId.Parse(entity.GrainId),\n            ReminderName = entity.Name,\n            Period = entity.Period,\n            StartAt = entity.StartAt.UtcDateTime,\n            ETag = entity.ETag\n        };\n    }\n\n    private ReminderEntity ToEntity(ReminderEntry entry)\n    {\n        return new ReminderEntity\n        {\n            Id = ReminderEntity.ConstructId(entry.GrainId, entry.ReminderName),\n            PartitionKey = ReminderEntity.ConstructPartitionKey(_clusterOptions.ServiceId, entry.GrainId),\n            ServiceId = _clusterOptions.ServiceId,\n            GrainHash = entry.GrainId.GetUniformHashCode(),\n            GrainId = entry.GrainId.ToString(),\n            Name = entry.ReminderName,\n            StartAt = entry.StartAt,\n            Period = entry.Period\n        };\n    }\n\n    private readonly struct UIntLogValue(uint value)\n    {\n        public override string ToString() => value.ToString(\"X\");\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Azure Cosmos DB Reminder Storage CosmosReminderTable is initializing: Name=CosmosReminderTable ServiceId={ServiceId} Collection={Container}\"\n    )]\n    private partial void LogDebugInitializingCosmosReminderTable(string serviceId, string container);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Initializing CosmosReminderTable took {Elapsed} milliseconds\"\n    )]\n    private partial void LogTraceInitializingCosmosReminderTableTook(long elapsed);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Initialization failed for provider CosmosReminderTable in {Elapsed} milliseconds\"\n    )]\n    private partial void LogErrorInitializationFailedForProviderCosmosReminderTable(Exception ex, long elapsed);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure reading reminders for grain {GrainId} in container {Container}\"\n    )]\n    private partial void LogErrorFailureReadingRemindersForGrain(Exception ex, GrainId grainId, string container);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure reading reminders for service {Service} for range {Begin} to {End}\"\n    )]\n    private partial void LogErrorFailureReadingRemindersForService(Exception ex, string service, UIntLogValue begin, UIntLogValue end);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure reading reminder {Name} for service {ServiceId} and grain {GrainId}\"\n    )]\n    private partial void LogErrorFailureReadingReminder(Exception ex, string name, string serviceId, GrainId grainId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure to upsert reminder for service {ServiceId}\"\n    )]\n    private partial void LogErrorFailureToUpsertReminder(Exception ex, string serviceId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure removing reminders for service {ServiceId} with GrainId {GrainId} and name {ReminderName}\"\n    )]\n    private partial void LogErrorFailureRemovingReminders(Exception ex, string serviceId, GrainId grainId, string reminderName);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failure to clear reminders for service {ServiceId}\"\n    )]\n    private partial void LogErrorFailureToClearReminders(Exception ex, string serviceId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error initializing Azure Cosmos DB client for membership table provider\"\n    )]\n    private partial void LogErrorInitializingAzureCosmosDbClient(Exception ex);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error deleting Azure Cosmos DB database\"\n    )]\n    private partial void LogErrorDeletingAzureCosmosDBDatabase(Exception ex);\n}"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/CosmosReminderTableOptions.cs",
    "content": "namespace Orleans.Reminders.Cosmos;\n\n/// <summary>\n/// Options for Azure Cosmos DB Reminder Storage.\n/// </summary>\npublic class CosmosReminderTableOptions : CosmosOptions\n{\n    private const string ORLEANS_REMINDERS_CONTAINER = \"OrleansReminders\";\n\n    /// <summary>\n    /// Initializes a new <see cref=\"CosmosReminderTableOptions\"/> instance.\n    /// </summary>\n    public CosmosReminderTableOptions()\n    {\n        ContainerName = ORLEANS_REMINDERS_CONTAINER;\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/HostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Reminders.Cosmos;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Extension methods for configuring the Azure Cosmos DB reminder table provider.\n/// </summary>\npublic static class HostingExtensions\n{\n    /// <summary>\n    /// Adds reminder storage backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">\n    /// The builder.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the reminder store.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n    /// </returns>\n    public static ISiloBuilder UseCosmosReminderService(this ISiloBuilder builder, Action<CosmosReminderTableOptions> configure)\n    {\n        builder.Services.UseCosmosReminderService(configure);\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds reminder storage backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"builder\">\n    /// The builder.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the reminder store.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n    /// </returns>\n    public static ISiloBuilder UseCosmosReminderService(this ISiloBuilder builder, Action<OptionsBuilder<CosmosReminderTableOptions>> configure)\n    {\n        builder.Services.UseCosmosReminderService(configure);\n        return builder;\n    }\n\n    /// <summary>\n    /// Adds reminder storage backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">\n    /// The service collection.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the reminder store.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n    /// </returns>\n    public static IServiceCollection UseCosmosReminderService(this IServiceCollection services, Action<CosmosReminderTableOptions> configure)\n        => services.UseCosmosReminderService(optionsBuilder => optionsBuilder.Configure(configure));\n\n    /// <summary>\n    /// Adds reminder storage backed by Azure Cosmos DB.\n    /// </summary>\n    /// <param name=\"services\">\n    /// The service collection.\n    /// </param>\n    /// <param name=\"configure\">\n    /// The delegate used to configure the reminder store.\n    /// </param>\n    /// <returns>\n    /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n    /// </returns>\n    public static IServiceCollection UseCosmosReminderService(this IServiceCollection services, Action<OptionsBuilder<CosmosReminderTableOptions>> configure)\n    {\n        services.AddReminders();\n        services.AddSingleton<IReminderTable, CosmosReminderTable>();\n        configure(services.AddOptions<CosmosReminderTableOptions>());\n        services.ConfigureFormatter<CosmosReminderTableOptions>();\n        services.AddTransient<IConfigurationValidator>(sp =>\n            new CosmosOptionsValidator<CosmosReminderTableOptions>(\n                sp.GetRequiredService<IOptionsMonitor<CosmosReminderTableOptions>>().CurrentValue,\n                nameof(CosmosReminderTableOptions)));\n        return services;\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/Models/ReminderEntity.cs",
    "content": "using Newtonsoft.Json;\nusing static Orleans.Reminders.Cosmos.CosmosIdSanitizer;\n\nnamespace Orleans.Reminders.Cosmos.Models;\n\ninternal class ReminderEntity : BaseEntity\n{\n    [JsonProperty(nameof(PartitionKey))]\n    [JsonPropertyName(nameof(PartitionKey))]\n    public string PartitionKey { get; set; } = default!;\n\n    [JsonProperty(nameof(ServiceId))]\n    [JsonPropertyName(nameof(ServiceId))]\n    public string ServiceId { get; set; } = default!;\n\n    [JsonProperty(nameof(GrainId))]\n    [JsonPropertyName(nameof(GrainId))]\n    public string GrainId { get; set; } = default!;\n\n    [JsonProperty(nameof(Name))]\n    [JsonPropertyName(nameof(Name))]\n    public string Name { get; set; } = default!;\n\n    [JsonProperty(nameof(StartAt))]\n    [JsonPropertyName(nameof(StartAt))]\n    public DateTimeOffset StartAt { get; set; }\n\n    [JsonProperty(nameof(Period))]\n    [JsonPropertyName(nameof(Period))]\n    public TimeSpan Period { get; set; }\n\n    [JsonProperty(nameof(GrainHash))]\n    [JsonPropertyName(nameof(GrainHash))]\n    public uint GrainHash { get; set; }\n\n    public static string ConstructId(GrainId grainId, string reminderName)\n    {\n        var grainType = grainId.Type.ToString();\n        var grainKey = grainId.Key.ToString();\n\n        if (grainType is null || grainKey is null)\n        {\n            throw new ArgumentNullException(nameof(grainId));\n        }\n\n        return $\"{Sanitize(grainType)}{SeparatorChar}{Sanitize(grainKey)}{SeparatorChar}{Sanitize(reminderName)}\";\n    }\n\n    public static string ConstructPartitionKey(string serviceId, GrainId grainId) => $\"{serviceId}_{grainId.GetUniformHashCode():X}\";\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/Orleans.Reminders.Cosmos.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Reminders.Cosmos</PackageId>\n    <Title>Microsoft Orleans Reminders Azure Cosmos DB</Title>\n    <Description>Microsoft Orleans reminders provider for Azure Cosmos DB</Description>\n    <PackageTags>$(PackageTags) Azure Cosmos DB</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Reminders.Cosmos</AssemblyName>\n    <RootNamespace>Orleans.Reminders.Cosmos</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_REMINDERS</DefineConstants>\n    <Nullable>enable</Nullable>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptions.cs\" Link=\"Storage\\CosmosOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosOptionsValidator.cs\" Link=\"Storage\\CosmosOptionsValidator.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\BaseEntity.cs\" Link=\"Storage\\BaseEntity.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\Usings.cs\" Link=\"Storage\\Usings.cs\" />\n    <Compile Include=\"..\\Shared\\Cosmos\\CosmosIdSanitizer.cs\" Link=\"Storage\\CosmosIdSanitizer.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Microsoft.Azure.Cosmos\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Include=\"System.Runtime.CompilerServices.InternalsVisibleToAttribute\">\n    <_Parameter1>Orleans.Cosmos.Tests</_Parameter1>\n    </AssemblyAttribute>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Azure/Orleans.Reminders.Cosmos/README.md",
    "content": "# Microsoft Orleans Reminders for Azure Cosmos DB\n\n## Introduction\nMicrosoft Orleans Reminders for Azure Cosmos DB provides persistence for Orleans reminders using Azure Cosmos DB. This allows your Orleans applications to schedule persistent reminders that will be triggered even after silo restarts or grain deactivation.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Reminders.Cosmos\n```\n\n## Example - Configuring Azure Cosmos DB Reminders\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Cosmos DB as reminder storage\n            .UseCosmosDBReminders(options =>\n            {\n                options.AccountEndpoint = \"https://YOUR_COSMOS_ENDPOINT\";\n                options.AccountKey = \"YOUR_COSMOS_KEY\";\n                options.DB = \"YOUR_DATABASE_NAME\";\n                options.CanCreateResources = true;\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Reminders in a Grain\n```csharp\npublic interface IReminderGrain\n{\n    Task StartReminder(string reminderName);\n    Task StopReminder();\n}\n\npublic class ReminderGrain : Grain, IReminderGrain, IRemindable\n{\n    private string _reminderName = \"MyReminder\";\n\n    public async Task StartReminder(string reminderName)\n    {\n        _reminderName = reminderName;\n        \n        // Register a persistent reminder\n        await RegisterOrUpdateReminder(\n            reminderName,\n            TimeSpan.FromMinutes(2),  // Time to delay before the first tick (must be > 1 minute)\n            TimeSpan.FromMinutes(5)); // Period of the reminder (must be > 1 minute)\n    }\n\n    public async Task StopReminder()\n    {\n        // Find and unregister the reminder\n        var reminder = await GetReminder(_reminderName);\n        if (reminder != null)\n        {\n            await UnregisterReminder(reminder);\n        }\n    }\n\n    public Task ReceiveReminder(string reminderName, TickStatus status)\n    {\n        // This method is called when the reminder ticks\n        Console.WriteLine($\"Reminder {reminderName} triggered at {DateTime.UtcNow}. Status: {status}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Reminders and Timers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n- [Reminder Services](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/reminder-services)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Hosting/AzureQueueStreamProviderBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Azure.Storage.Queues;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"AzureQueueStorage\", \"Streaming\", \"Silo\", typeof(AzureQueueStreamProviderBuilder))]\n[assembly: RegisterProvider(\"AzureQueueStorage\", \"Streaming\", \"Client\", typeof(AzureQueueStreamProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\npublic sealed class AzureQueueStreamProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureQueueStreams(name, GetQueueOptionBuilder(configurationSection));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddAzureQueueStreams(name, GetQueueOptionBuilder(configurationSection));\n    }\n\n    private static Action<OptionsBuilder<AzureQueueOptions>> GetQueueOptionBuilder(IConfigurationSection configurationSection)\n    {\n        return (OptionsBuilder<AzureQueueOptions> optionsBuilder) =>\n        {\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var queueNames = configurationSection.GetSection(\"QueueNames\")?.Get<List<string>>();\n                if (queueNames != null)\n                {\n                    options.QueueNames = queueNames;\n                }\n\n                var visibilityTimeout = configurationSection[\"MessageVisibilityTimeout\"];\n                if (TimeSpan.TryParse(visibilityTimeout, out var visibilityTimeoutTimeSpan))\n                {\n                    options.MessageVisibilityTimeout = visibilityTimeoutTimeSpan;\n                }\n\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a client by name.\n                    options.QueueServiceClient = services.GetRequiredKeyedService<QueueServiceClient>(serviceKey);\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))\n                        {\n                            if (!string.IsNullOrEmpty(uri.Query))\n                            {\n                                // SAS URI\n                                options.QueueServiceClient = new QueueServiceClient(uri);\n                            }\n                            else\n                            {\n                                options.QueueServiceClient = new QueueServiceClient(uri, credential: new Azure.Identity.DefaultAzureCredential());\n                            }\n                        }\n                        else\n                        {\n                            options.QueueServiceClient = new QueueServiceClient(connectionString);\n                        }\n                    }\n                }\n            });\n        };\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Hosting/ClientBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class ClientBuilderExtensions\n    {\n        /// <summary>\n        /// Configure cluster client to use azure queue persistent streams.\n        /// </summary>\n        public static IClientBuilder AddAzureQueueStreams(this IClientBuilder builder,\n            string name,\n            Action<ClusterClientAzureQueueStreamConfigurator> configure)\n        {\n            //the constructor wires up DI with AzureQueueStream, so has to be called regardless configure is null or not\n            var configurator = new ClusterClientAzureQueueStreamConfigurator(name, builder);\n            configure?.Invoke(configurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure cluster client to use azure queue persistent streams.\n        /// </summary>\n        public static IClientBuilder AddAzureQueueStreams(this IClientBuilder builder,\n            string name, Action<OptionsBuilder<AzureQueueOptions>> configureOptions)\n        {\n            builder.AddAzureQueueStreams(name, b=>\n                 b.ConfigureAzureQueue(configureOptions));\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Hosting/SiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.LeaseProviders;\n\nnamespace Orleans.Hosting\n{\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use azure queue persistent streams.\n        /// </summary>\n        public static ISiloBuilder AddAzureQueueStreams(this ISiloBuilder builder, string name,\n            Action<SiloAzureQueueStreamConfigurator> configure)\n        {\n            var configurator = new SiloAzureQueueStreamConfigurator(name,\n                configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n            configure?.Invoke(configurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure silo to use azure queue persistent streams with default settings\n        /// </summary>\n        public static ISiloBuilder AddAzureQueueStreams(this ISiloBuilder builder, string name, Action<OptionsBuilder<AzureQueueOptions>> configureOptions)\n        {\n            builder.AddAzureQueueStreams(name, b =>\n                 b.ConfigureAzureQueue(configureOptions));\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob lease provider\n        /// </summary>\n        public static ISiloBuilder UseAzureBlobLeaseProvider(this ISiloBuilder builder, Action<OptionsBuilder<AzureBlobLeaseProviderOptions>> configureOptions)\n        {\n            builder.ConfigureServices(services => ConfigureAzureBlobLeaseProviderServices(services, configureOptions));\n            return builder;\n        }\n\n        private static void ConfigureAzureBlobLeaseProviderServices(IServiceCollection services, Action<OptionsBuilder<AzureBlobLeaseProviderOptions>> configureOptions)\n        {\n            configureOptions?.Invoke(services.AddOptions<AzureBlobLeaseProviderOptions>());\n            services.AddTransient<IConfigurationValidator, AzureBlobLeaseProviderOptionsValidator>();\n            services.ConfigureFormatter<AzureBlobLeaseProviderOptions>();\n            services.AddTransient<AzureBlobLeaseProvider>();\n            services.AddFromExisting<ILeaseProvider, AzureBlobLeaseProvider>();\n        }\n\n        /// <summary>\n        /// Configure silo to use azure blob lease provider\n        /// </summary>\n        public static void UseAzureBlobLeaseProvider(this ISiloPersistentStreamConfigurator configurator, Action<OptionsBuilder<AzureBlobLeaseProviderOptions>> configureOptions)\n        {\n            configurator.ConfigureDelegate(services =>\n            {\n                services.AddTransient(sp => AzureBlobLeaseProviderOptionsValidator.Create(sp, configurator.Name));\n            });\n            configurator.ConfigureComponent(AzureBlobLeaseProvider.Create, configureOptions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Options/AzureBlobLeaseProviderOptions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Core;\nusing Azure.Storage;\nusing Azure.Storage.Blobs;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Streaming.AzureStorage;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring a lease provider backed by Azure Blob Storage leases.\n    /// </summary>\n    public class AzureBlobLeaseProviderOptions\n    {\n        private BlobServiceClient _blobServiceClient;\n\n        public string BlobContainerName { get; set; } = DefaultBlobContainerName;\n        public const string DefaultBlobContainerName = \"Leases\";\n\n        /// <summary>\n        /// Options to be used when configuring the blob storage client, or <see langword=\"null\"/> to use the default options.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public BlobClientOptions ClientOptions { get; set; }\n\n        /// <summary>\n        /// The optional delegate used to create a <see cref=\"BlobServiceClient\"/> instance.\n        /// </summary>\n        internal Func<Task<BlobServiceClient>> CreateClient { get; private set; }\n\n        /// <summary>\n        /// Gets or sets the client used to access the Azure Blob Service.\n        /// </summary>\n        public BlobServiceClient BlobServiceClient\n        {\n            get => _blobServiceClient;\n            set\n            {\n                _blobServiceClient = value;\n                CreateClient = () => Task.FromResult(value);\n            }\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using a connection string.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(string connectionString)\n        {\n            BlobServiceClient = new BlobServiceClient(connectionString, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using the provided callback.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Func<Task<BlobServiceClient>> createClientCallback)\n        {\n            CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.Core.TokenCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, TokenCredential tokenCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, tokenCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.AzureSasCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, AzureSasCredential azureSasCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, azureSasCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"BlobServiceClient\"/> using an authenticated service URI and a <see cref=\"StorageSharedKeyCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(BlobServiceClient)} property directly.\")]\n        public void ConfigureBlobServiceClient(Uri serviceUri, StorageSharedKeyCredential sharedKeyCredential)\n        {\n            BlobServiceClient = new BlobServiceClient(serviceUri, sharedKeyCredential, ClientOptions);\n        }\n    }\n\n    /// <summary>\n    /// Configuration validator for AzureBlobLeaseProviderOptions\n    /// </summary>\n    public class AzureBlobLeaseProviderOptionsValidator : IConfigurationValidator\n    {\n        private readonly AzureBlobLeaseProviderOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        public AzureBlobLeaseProviderOptionsValidator(IOptions<AzureBlobLeaseProviderOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <summary>\n        /// Creates creates validator for named instance of AzureBlobLeaseProviderOptions options.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"name\"></param>\n        /// <returns></returns>\n        public static IConfigurationValidator Create(IServiceProvider services, string name)\n        {\n            var options = services.GetOptionsByName<AzureBlobLeaseProviderOptions>(name);\n            return new AzureBlobLeaseProviderOptionsValidator(options, name);\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        private AzureBlobLeaseProviderOptionsValidator(AzureBlobLeaseProviderOptions options, string name)\n        {\n            this.options = options;\n            this.name = name ?? string.Empty;\n        }\n\n        public void ValidateConfiguration()\n        {\n            // name can be null, but not empty or white space.\n            if(this.name != null && string.IsNullOrWhiteSpace(this.name))\n            {\n                throw new OrleansConfigurationException($\"Named option {nameof(AzureBlobLeaseProviderOptions)} of name {this.name} is invalid.  Name cannot be empty or whitespace.\");\n            }\n\n            if (this.options.CreateClient is null)\n            {\n                throw new OrleansConfigurationException($\"No credentials specified for Azure Blob Service lease provider \\\"{name}\\\". Use the {options.GetType().Name}.{nameof(AzureBlobLeaseProviderOptions.ConfigureBlobServiceClient)} method to configure the Azure Blob Service client.\");\n            }\n\n            try\n            {\n                AzureBlobUtils.ValidateContainerName(this.options.BlobContainerName);\n            }\n            catch (ArgumentException e)\n            {\n                var errorStr = string.IsNullOrEmpty(this.name)\n                    ? $\"Configuration for {nameof(AzureBlobLeaseProviderOptions)} {this.name} is invalid. {nameof(this.options.BlobContainerName)} is not valid\"\n                    : $\"Configuration for {nameof(AzureBlobLeaseProviderOptions)} is invalid. {nameof(this.options.BlobContainerName)} is not valid\";\n                throw new OrleansConfigurationException(errorStr , e);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Orleans.Streaming.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Streaming.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Queue Storage Streaming Provider</Title>\n    <Description>Microsoft Orleans streaming provider backed by Azure Queue Storage</Description>\n    <PackageTags>$(PackageTags) Azure Table Blob Storage</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Streaming.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.Streaming.AzureStorage</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_STREAMING</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureBlobUtils.cs\" Link=\"Utilities\\AzureBlobUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"Azure.Storage.Blobs\" />\n    <PackageReference Include=\"Azure.Storage.Queues\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Lease/AzureBlobLeaseProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Models;\nusing Azure.Storage.Blobs.Specialized;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.LeaseProviders\n{\n    public class AzureBlobLeaseProvider : ILeaseProvider\n    {\n        private BlobContainerClient container;\n        private readonly AzureBlobLeaseProviderOptions options;\n        private BlobServiceClient blobClient;\n        public AzureBlobLeaseProvider(IOptions<AzureBlobLeaseProviderOptions> options)\n            : this(options.Value)\n        {\n        }\n\n        private AzureBlobLeaseProvider(AzureBlobLeaseProviderOptions options)\n        {\n            this.options = options;\n        }\n\n        private async Task InitContainerIfNotExistsAsync()\n        {\n            if (this.container == null)\n            {\n                this.blobClient = await options.CreateClient();\n                var tmpContainer = blobClient.GetBlobContainerClient(this.options.BlobContainerName);\n                await tmpContainer.CreateIfNotExistsAsync().ConfigureAwait(false);\n                this.container = tmpContainer;\n            }\n        }\n\n        private BlobClient GetBlobClient(string category, string resourceKey) => this.container.GetBlobClient($\"{category.ToLowerInvariant()}-{resourceKey.ToLowerInvariant()}.json\");\n\n        public async Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests)\n        {\n            await InitContainerIfNotExistsAsync();\n            var tasks = new List<Task<AcquireLeaseResult>>(leaseRequests.Length);\n            foreach (var leaseRequest in leaseRequests)\n            {\n                tasks.Add(Acquire(category, leaseRequest));\n            }\n            //Task.WhenAll will return results for each task in an array, in the same order of supplied tasks\n            return await Task.WhenAll(tasks);\n        }\n\n        private async Task<AcquireLeaseResult> Acquire(string category, LeaseRequest leaseRequest)\n        {\n            try\n            {\n                var blobClient = GetBlobClient(category, leaseRequest.ResourceKey);\n                //create this blob\n                await blobClient.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes(\"blob\")), new BlobHttpHeaders { ContentType = \"application/json\" });\n                var leaseClient = blobClient.GetBlobLeaseClient();\n                var lease = await leaseClient.AcquireAsync(leaseRequest.Duration);\n                return new AcquireLeaseResult(new AcquiredLease(leaseRequest.ResourceKey, leaseRequest.Duration, lease.Value.LeaseId, DateTime.UtcNow), ResponseCode.OK, null);\n            }\n            catch (RequestFailedException e)\n            {\n                ResponseCode statusCode;\n                //This mapping is based on references : https://learn.microsoft.com/rest/api/storageservices/blob-service-error-codes\n                // https://learn.microsoft.com/rest/api/storageservices/Lease-Blob?redirectedfrom=MSDN\n                switch (e.Status)\n                {\n                    case 404:\n                    case 409:\n                    case 412: statusCode = ResponseCode.LeaseNotAvailable; break;\n                    default: statusCode = ResponseCode.TransientFailure; break;\n                }\n                return new AcquireLeaseResult(new AcquiredLease(leaseRequest.ResourceKey), statusCode, e);\n            }\n        }\n\n        public async Task Release(string category, AcquiredLease[] acquiredLeases)\n        {\n            await InitContainerIfNotExistsAsync();\n            var tasks = new List<Task>(acquiredLeases.Length);\n            foreach (var acquiredLease in acquiredLeases)\n            {\n                tasks.Add(Release(category, acquiredLease));\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        private Task Release(string category, AcquiredLease acquiredLease)\n        {\n            var leaseClient = GetBlobClient(category, acquiredLease.ResourceKey).GetBlobLeaseClient(acquiredLease.Token);\n            return leaseClient.ReleaseAsync();\n        }\n\n        public async Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] acquiredLeases)\n        {\n            await InitContainerIfNotExistsAsync();\n            var tasks = new List<Task<AcquireLeaseResult>>(acquiredLeases.Length);\n            foreach (var acquiredLease in acquiredLeases)\n            {\n                tasks.Add(Renew(category, acquiredLease));\n            }\n            //Task.WhenAll will return results for each task in an array, in the same order of supplied tasks\n            return await Task.WhenAll(tasks);\n        }\n\n        private async Task<AcquireLeaseResult> Renew(string category, AcquiredLease acquiredLease)\n        {\n            var leaseClient = GetBlobClient(category, acquiredLease.ResourceKey).GetBlobLeaseClient(acquiredLease.Token);\n\n            try\n            {\n                await leaseClient.RenewAsync();\n                return new AcquireLeaseResult(new AcquiredLease(acquiredLease.ResourceKey, acquiredLease.Duration, acquiredLease.Token, DateTime.UtcNow),\n                    ResponseCode.OK, null);\n            }\n            catch (RequestFailedException e)\n            {\n                ResponseCode statusCode;\n                //This mapping is based on references : https://learn.microsoft.com/rest/api/storageservices/blob-service-error-codes\n                // https://learn.microsoft.com/rest/api/storageservices/Lease-Blob?redirectedfrom=MSDN\n                switch (e.Status)\n                {\n                    case 404:\n                    case 409:\n                    case 412: statusCode = ResponseCode.InvalidToken; break;\n                    default: statusCode = ResponseCode.TransientFailure; break;\n                }\n                return new AcquireLeaseResult(new AcquiredLease(acquiredLease.ResourceKey), statusCode, e);\n            }\n        }\n\n        public static ILeaseProvider Create(IServiceProvider services, string name)\n        {\n            AzureBlobLeaseProviderOptions options = services.GetOptionsByName<AzureBlobLeaseProviderOptions>(name);\n            return new AzureBlobLeaseProvider(options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueAdapter.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    internal sealed class AzureQueueAdapter : IQueueAdapter\n    {\n        private readonly AzureQueueOptions queueOptions;\n        private readonly HashRingBasedPartitionedStreamQueueMapper streamQueueMapper;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ConcurrentDictionary<QueueId, AzureQueueDataManager> Queues = new();\n        private readonly IQueueDataAdapter<string, IBatchContainer> dataAdapter;\n\n        public string Name { get; }\n        public bool IsRewindable => false;\n\n        public StreamProviderDirection Direction => StreamProviderDirection.ReadWrite;\n\n        public AzureQueueAdapter(\n            IQueueDataAdapter<string, IBatchContainer> dataAdapter,\n            HashRingBasedPartitionedStreamQueueMapper streamQueueMapper,\n            ILoggerFactory loggerFactory,\n            AzureQueueOptions queueOptions,\n            string providerName)\n        {\n            this.queueOptions = queueOptions;\n            Name = providerName;\n            this.streamQueueMapper = streamQueueMapper;\n            this.dataAdapter = dataAdapter;\n            this.loggerFactory = loggerFactory;\n        }\n\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId) => AzureQueueAdapterReceiver.Create(loggerFactory, streamQueueMapper.QueueToPartition(queueId), queueOptions, dataAdapter);\n\n        public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            if(token != null) throw new ArgumentException(\"AzureQueue stream provider currently does not support non-null StreamSequenceToken.\", nameof(token));\n            var queueId = streamQueueMapper.GetQueueForStream(streamId);\n            if (!Queues.TryGetValue(queueId, out var queue))\n            {\n                var tmpQueue = new AzureQueueDataManager(loggerFactory, streamQueueMapper.QueueToPartition(queueId), queueOptions);\n                await tmpQueue.InitQueueAsync();\n                queue = Queues.GetOrAdd(queueId, tmpQueue);\n            }\n            var cloudMsg = this.dataAdapter.ToQueueMessage(streamId, events, null, requestContext);\n            await queue.AddQueueMessage(cloudMsg);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueAdapterFactory.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    /// <summary> Factory class for Azure Queue based stream provider.</summary>\n    public class AzureQueueAdapterFactory : IQueueAdapterFactory\n    {\n        private readonly string providerName;\n        private readonly AzureQueueOptions options;\n        private readonly IQueueDataAdapter<string, IBatchContainer> dataAdapter;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly HashRingBasedPartitionedStreamQueueMapper streamQueueMapper;\n        private readonly SimpleQueueAdapterCache adapterCache;\n\n        /// <summary>\n        /// Application level failure handler override.\n        /// </summary>\n        protected Func<QueueId, Task<IStreamFailureHandler>> StreamFailureHandlerFactory { private get; set; }\n\n        public AzureQueueAdapterFactory(\n            string name,\n            AzureQueueOptions options,\n            SimpleQueueCacheOptions cacheOptions,\n            IQueueDataAdapter<string, IBatchContainer> dataAdapter,\n            ILoggerFactory loggerFactory)\n        {\n            this.providerName = name;\n            this.options = options ?? throw new ArgumentNullException(nameof(options));\n            this.dataAdapter = dataAdapter ?? throw new ArgumentNullException(nameof(dataAdapter));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.streamQueueMapper = new(options.QueueNames, providerName);\n            this.adapterCache = new SimpleQueueAdapterCache(cacheOptions, this.providerName, this.loggerFactory);\n        }\n\n        /// <summary> Init the factory.</summary>\n        public virtual void Init()\n        {\n            this.StreamFailureHandlerFactory = this.StreamFailureHandlerFactory ??\n                    ((qid) => Task.FromResult<IStreamFailureHandler>(new NoOpStreamDeliveryFailureHandler()));\n        }\n\n        /// <summary>Creates the Azure Queue based adapter.</summary>\n        public virtual Task<IQueueAdapter> CreateAdapter()\n        {\n            var adapter = new AzureQueueAdapter(\n                this.dataAdapter,\n                this.streamQueueMapper,\n                this.loggerFactory,\n                this.options,\n                this.providerName);\n            return Task.FromResult<IQueueAdapter>(adapter);\n        }\n\n        /// <summary>Creates the adapter cache.</summary>\n        public virtual IQueueAdapterCache GetQueueAdapterCache()\n        {\n            return adapterCache;\n        }\n\n        /// <summary>Creates the factory stream queue mapper.</summary>\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            return streamQueueMapper;\n        }\n\n        /// <summary>\n        /// Creates a delivery failure handler for the specified queue.\n        /// </summary>\n        /// <param name=\"queueId\"></param>\n        /// <returns></returns>\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            return StreamFailureHandlerFactory(queueId);\n        }\n\n        public static AzureQueueAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var azureQueueOptions = services.GetOptionsByName<AzureQueueOptions>(name);\n            var cacheOptions = services.GetOptionsByName<SimpleQueueCacheOptions>(name);\n            var dataAdapter = services.GetKeyedService<IQueueDataAdapter<string, IBatchContainer>>(name)\n                ?? services.GetService<IQueueDataAdapter<string, IBatchContainer>>();\n            var factory = ActivatorUtilities.CreateInstance<AzureQueueAdapterFactory>(services, name, azureQueueOptions, cacheOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueAdapterReceiver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Azure.Storage.Queues.Models;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils;\nusing Orleans.AzureUtils.Utilities;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    /// <summary>\n    /// Receives batches of messages from a single partition of a message queue.\n    /// </summary>\n    internal partial class AzureQueueAdapterReceiver : IQueueAdapterReceiver\n    {\n        private AzureQueueDataManager queue;\n        private long lastReadMessage;\n        private Task outstandingTask;\n        private readonly ILogger logger;\n        private readonly IQueueDataAdapter<string, IBatchContainer> dataAdapter;\n        private readonly List<PendingDelivery> pending;\n\n        private readonly string azureQueueName;\n\n        public static IQueueAdapterReceiver Create(ILoggerFactory loggerFactory, string azureQueueName, AzureQueueOptions queueOptions, IQueueDataAdapter<string, IBatchContainer> dataAdapter)\n        {\n            if (azureQueueName == null) throw new ArgumentNullException(nameof(azureQueueName));\n            if (queueOptions == null) throw new ArgumentNullException(nameof(queueOptions));\n            if (dataAdapter == null) throw new ArgumentNullException(nameof(dataAdapter));\n\n            var queue = new AzureQueueDataManager(loggerFactory, azureQueueName, queueOptions);\n            return new AzureQueueAdapterReceiver(azureQueueName, loggerFactory, queue, dataAdapter);\n        }\n\n        private AzureQueueAdapterReceiver(string azureQueueName, ILoggerFactory loggerFactory, AzureQueueDataManager queue, IQueueDataAdapter<string, IBatchContainer> dataAdapter)\n        {\n            this.azureQueueName = azureQueueName ?? throw new ArgumentNullException(nameof(azureQueueName));\n            this.queue = queue?? throw new ArgumentNullException(nameof(queue));\n            this.dataAdapter = dataAdapter?? throw new ArgumentNullException(nameof(dataAdapter));\n            this.logger = loggerFactory.CreateLogger<AzureQueueAdapterReceiver>();\n            this.pending = new List<PendingDelivery>();\n        }\n\n        public Task Initialize(TimeSpan timeout)\n        {\n            if (queue != null) // check in case we already shut it down.\n            {\n                return queue.InitQueueAsync();\n            }\n            return Task.CompletedTask;\n        }\n\n        public async Task Shutdown(TimeSpan timeout)\n        {\n            try\n            {\n                // await the last storage operation, so after we shutdown and stop this receiver we don't get async operation completions from pending storage operations.\n                if (outstandingTask != null)\n                    await outstandingTask;\n            }\n            finally\n            {\n                // remember that we shut down so we never try to read from the queue again.\n                queue = null;\n            }\n        }\n\n        public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n        {\n            const int MaxNumberOfMessagesToPeek = 32;\n\n            try\n            {\n                var queueRef = queue; // store direct ref, in case we are somehow asked to shutdown while we are receiving.\n                if (queueRef == null) return new List<IBatchContainer>();\n\n                int count = maxCount < 0 || maxCount == QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG ?\n                    MaxNumberOfMessagesToPeek : Math.Min(maxCount, MaxNumberOfMessagesToPeek) ;\n\n                var task = queueRef.GetQueueMessages(count);\n                outstandingTask = task;\n                IEnumerable<QueueMessage> messages = await task;\n\n                List<IBatchContainer> azureQueueMessages = new List<IBatchContainer>();\n                foreach (var message in messages)\n                {\n                    IBatchContainer container = this.dataAdapter.FromQueueMessage(message.MessageText, lastReadMessage++);\n                    azureQueueMessages.Add(container);\n                    this.pending.Add(new PendingDelivery(container.SequenceToken, message));\n                }\n\n                return azureQueueMessages;\n            }\n            finally\n            {\n                outstandingTask = null;\n            }\n        }\n\n        public async Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n        {\n            try\n            {\n                var queueRef = queue; // store direct ref, in case we are somehow asked to shutdown while we are receiving.\n                if (messages.Count == 0 || queueRef==null) return;\n                // get sequence tokens of delivered messages\n                List<StreamSequenceToken> deliveredTokens = messages.Select(message => message.SequenceToken).ToList();\n                // find oldest delivered message\n                StreamSequenceToken oldest = deliveredTokens.Max();\n                // finalize all pending messages at or befor the oldest\n                List<PendingDelivery> finalizedDeliveries = pending\n                    .Where(pendingDelivery => !pendingDelivery.Token.Newer(oldest))\n                    .ToList();\n                if (finalizedDeliveries.Count == 0) return;\n                // remove all finalized deliveries from pending, regardless of if it was delivered or not.\n                pending.RemoveRange(0, finalizedDeliveries.Count);\n                // get the queue messages for all finalized deliveries that were delivered.\n                List<QueueMessage> deliveredCloudQueueMessages = finalizedDeliveries\n                    .Where(finalized => deliveredTokens.Contains(finalized.Token))\n                    .Select(finalized => finalized.Message)\n                    .ToList();\n                if (deliveredCloudQueueMessages.Count == 0) return;\n                // delete all delivered queue messages from the queue.  Anything finalized but not delivered will show back up later\n                outstandingTask = Task.WhenAll(deliveredCloudQueueMessages.Select(queueRef.DeleteQueueMessage));\n                try\n                {\n                    await outstandingTask;\n                }\n                catch (Exception exc)\n                {\n                    LogWarningOnDeleteQueueMessage(exc, this.azureQueueName);\n                }\n            }\n            finally\n            {\n                outstandingTask = null;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)AzureQueueErrorCode.AzureQueue_15,\n            Message = \"Exception upon DeleteQueueMessage on queue {QueueName}. Ignoring.\"\n        )]\n        private partial void LogWarningOnDeleteQueueMessage(Exception exception, string queueName);\n\n        private class PendingDelivery\n        {\n            public PendingDelivery(StreamSequenceToken token, QueueMessage message)\n            {\n                this.Token = token;\n                this.Message = message;\n            }\n\n            public QueueMessage Message { get; }\n\n            public StreamSequenceToken Token { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueBatchContainer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Newtonsoft.Json;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    [Serializable]\n    [GenerateSerializer]\n    internal class AzureQueueBatchContainer : IBatchContainer\n    {\n        [JsonProperty]\n        [Id(0)]\n        private EventSequenceToken sequenceToken;\n\n        [JsonProperty]\n        [Id(1)]\n        private readonly List<object> events;\n\n        [JsonProperty]\n        [Id(2)]\n        private readonly Dictionary<string, object> requestContext;\n\n        [Id(3)]\n        public StreamId StreamId { get; private set; }\n\n        public StreamSequenceToken SequenceToken\n        {\n            get { return sequenceToken; }\n        }\n\n        internal EventSequenceToken RealSequenceToken\n        {\n            set { sequenceToken = value; }\n        }\n\n        [JsonConstructor]\n        public AzureQueueBatchContainer(\n            StreamId streamId,\n            List<object> events,\n            Dictionary<string, object> requestContext,\n            EventSequenceToken sequenceToken)\n            : this(streamId, events, requestContext)\n        {\n            this.sequenceToken = sequenceToken;\n        }\n\n        public AzureQueueBatchContainer(StreamId streamId, List<object> events, Dictionary<string, object> requestContext)\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events), \"Message contains no events\");\n\n            StreamId = streamId;\n            this.events = events;\n            this.requestContext = requestContext;\n        }\n\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return events.OfType<T>().Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, sequenceToken.CreateSequenceTokenForEvent(i)));\n        }\n\n        public bool ImportRequestContext()\n        {\n            if (requestContext != null)\n            {\n                RequestContextExtensions.Import(requestContext);\n                return true;\n            }\n            return false;\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"[AzureQueueBatchContainer:Stream={0},#Items={1}]\", StreamId, events.Count);\n            //return string.Format(\"[AzureBatch:#Items={0},Items{1}]\", events.Count, Utils.EnumerableToString(events.Select((e, i) => String.Format(\"{0}-{1}\", e, sequenceToken.CreateSequenceTokenForEvent(i)))));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueBatchContainerV2.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Newtonsoft.Json;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    /// <summary>\n    /// Second version of AzureQueueBatchContainer.  This version supports external serializers (like json)\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    internal class AzureQueueBatchContainerV2 : IBatchContainer\n    {\n        [JsonProperty]\n        [Id(0)]\n        private EventSequenceTokenV2 sequenceToken;\n\n        [JsonProperty]\n        [Id(1)]\n        private readonly List<object> events;\n\n        [JsonProperty]\n        [Id(2)]\n        private readonly Dictionary<string, object> requestContext;\n\n        [Id(3)]\n        public StreamId StreamId { get; }\n\n        public StreamSequenceToken SequenceToken => sequenceToken;\n\n        internal EventSequenceTokenV2 RealSequenceToken\n        {\n            set { sequenceToken = value; }\n        }\n\n        [JsonConstructor]\n        public AzureQueueBatchContainerV2(\n            StreamId streamId,\n            List<object> events,\n            Dictionary<string, object> requestContext,\n            EventSequenceTokenV2 sequenceToken)\n            : this(streamId, events, requestContext)\n        {\n            this.sequenceToken = sequenceToken;\n        }\n\n        public AzureQueueBatchContainerV2(StreamId streamId, List<object> events, Dictionary<string, object> requestContext)\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events), \"Message contains no events\");\n\n            StreamId = streamId;\n            this.events = events;\n            this.requestContext = requestContext;\n        }\n\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return events.OfType<T>().Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, sequenceToken.CreateSequenceTokenForEvent(i)));\n        }\n\n        public bool ImportRequestContext()\n        {\n            if (requestContext != null)\n            {\n                RequestContextExtensions.Import(requestContext);\n                return true;\n            }\n            return false;\n        }\n\n        public override string ToString()\n        {\n            return $\"[AzureQueueBatchContainerV2:Stream={StreamId},#Items={events.Count}]\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueStreamBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    public interface IAzureQueueStreamConfigurator : INamedServiceConfigurator { }\n\n    public static class AzureQueueStreamConfiguratorExtensions\n    {\n        public static void ConfigureAzureQueue(this IAzureQueueStreamConfigurator configurator, Action<OptionsBuilder<AzureQueueOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        public static void ConfigureQueueDataAdapter(this IAzureQueueStreamConfigurator configurator, Func<IServiceProvider, string, IQueueDataAdapter<string, IBatchContainer>> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n\n        public static void ConfigureQueueDataAdapter<TQueueDataAdapter>(this IAzureQueueStreamConfigurator configurator)\n            where TQueueDataAdapter : IQueueDataAdapter<string, IBatchContainer>\n        {\n            configurator.ConfigureComponent<IQueueDataAdapter<string, IBatchContainer>>((sp, n) => ActivatorUtilities.CreateInstance<TQueueDataAdapter>(sp));\n        }\n    }\n\n    public interface ISiloAzureQueueStreamConfigurator : IAzureQueueStreamConfigurator, ISiloPersistentStreamConfigurator { }\n\n    public static class SiloAzureQueueStreamConfiguratorExtensions\n    {\n        public static void ConfigureCacheSize(this ISiloAzureQueueStreamConfigurator configurator, int cacheSize = SimpleQueueCacheOptions.DEFAULT_CACHE_SIZE)\n        {\n            configurator.Configure<SimpleQueueCacheOptions>(ob => ob.Configure(options => options.CacheSize = cacheSize));\n        }\n    }\n\n    public class SiloAzureQueueStreamConfigurator : SiloPersistentStreamConfigurator, ISiloAzureQueueStreamConfigurator\n    {\n        public SiloAzureQueueStreamConfigurator(string name, Action<Action<IServiceCollection>> configureServicesDelegate)\n            : base(name, configureServicesDelegate, AzureQueueAdapterFactory.Create)\n        {\n            this.ConfigureComponent(AzureQueueOptionsValidator.Create);\n            this.ConfigureComponent(SimpleQueueCacheOptionsValidator.Create);\n\n            //configure default queue names\n            this.ConfigureAzureQueue(ob => ob.PostConfigure<IOptions<ClusterOptions>>((op, clusterOp) =>\n            {\n                if (op.QueueNames == null || op.QueueNames?.Count == 0)\n                {\n                    op.QueueNames =\n                        AzureQueueStreamProviderUtils.GenerateDefaultAzureQueueNames(clusterOp.Value.ServiceId,\n                            this.Name);\n                }\n            }));\n            this.ConfigureDelegate(services => services.TryAddSingleton<IQueueDataAdapter<string, IBatchContainer>, AzureQueueDataAdapterV2>());\n        }\n    }\n\n    public interface IClusterClientAzureQueueStreamConfigurator : IAzureQueueStreamConfigurator, IClusterClientPersistentStreamConfigurator { }\n\n    public class ClusterClientAzureQueueStreamConfigurator : ClusterClientPersistentStreamConfigurator, IClusterClientAzureQueueStreamConfigurator\n    {\n        public ClusterClientAzureQueueStreamConfigurator(string name, IClientBuilder builder)\n            : base(name, builder, AzureQueueAdapterFactory.Create)\n        {\n            this.ConfigureComponent(AzureQueueOptionsValidator.Create);\n\n            //configure default queue names\n            this.ConfigureAzureQueue(ob => ob.PostConfigure<IOptions<ClusterOptions>>((op, clusterOp) =>\n            {\n                if (op.QueueNames == null || op.QueueNames?.Count == 0)\n                {\n                    op.QueueNames =\n                        AzureQueueStreamProviderUtils.GenerateDefaultAzureQueueNames(clusterOp.Value.ServiceId, this.Name);\n                }\n            }));\n            this.ConfigureDelegate(services => services.TryAddSingleton<IQueueDataAdapter<string, IBatchContainer>, AzureQueueDataAdapterV2>());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueStreamOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Core;\nusing Azure.Storage;\nusing Azure.Storage.Queues;\nusing Orleans.AzureUtils;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Azure queue stream provider options.\n    /// </summary>\n    public class AzureQueueOptions\n    {\n        private QueueServiceClient _queueServiceClient;\n\n        /// <summary>\n        /// Options to be used when configuring the queue storage client, or <see langword=\"null\"/> to use the default options.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public QueueClientOptions ClientOptions { get; set; } = new QueueClientOptions\n        {\n            Retry =\n            {\n                Mode = RetryMode.Fixed,\n                Delay = AzureQueueDefaultPolicies.PauseBetweenQueueOperationRetries,\n                MaxRetries = AzureQueueDefaultPolicies.MaxQueueOperationRetries,\n                NetworkTimeout = AzureQueueDefaultPolicies.QueueOperationTimeout,\n            }\n        };\n\n        /// <summary>\n        /// The optional delegate used to create a <see cref=\"QueueServiceClient\"/> instance.\n        /// </summary>\n        internal Func<Task<QueueServiceClient>> CreateClient { get; private set; }\n\n        public TimeSpan? MessageVisibilityTimeout { get; set; }\n\n        public List<string> QueueNames { get; set; }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"QueueServiceClient\"/> used to access the Azure Queue Service.\n        /// </summary>\n        public QueueServiceClient QueueServiceClient\n        {\n            get => _queueServiceClient;\n\n            set\n            {\n                _queueServiceClient = value;\n                CreateClient = () => Task.FromResult(value);\n            }\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using a connection string.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(string connectionString)\n        {\n            if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullException(nameof(connectionString));\n            CreateClient = () => Task.FromResult(new QueueServiceClient(connectionString, ClientOptions));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using an authenticated service URI.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(Uri serviceUri)\n        {\n            if (serviceUri is null) throw new ArgumentNullException(nameof(serviceUri));\n            CreateClient = () => Task.FromResult(new QueueServiceClient(serviceUri, ClientOptions));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using the provided callback.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(Func<Task<QueueServiceClient>> createClientCallback)\n        {\n            CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.Core.TokenCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(Uri serviceUri, TokenCredential tokenCredential)\n        {\n            if (serviceUri is null) throw new ArgumentNullException(nameof(serviceUri));\n            if (tokenCredential is null) throw new ArgumentNullException(nameof(tokenCredential));\n            CreateClient = () => Task.FromResult(new QueueServiceClient(serviceUri, tokenCredential, ClientOptions));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.AzureSasCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(Uri serviceUri, AzureSasCredential azureSasCredential)\n        {\n            if (serviceUri is null) throw new ArgumentNullException(nameof(serviceUri));\n            if (azureSasCredential is null) throw new ArgumentNullException(nameof(azureSasCredential));\n            CreateClient = () => Task.FromResult(new QueueServiceClient(serviceUri, azureSasCredential, ClientOptions));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"QueueServiceClient\"/> using an authenticated service URI and a <see cref=\"StorageSharedKeyCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(QueueServiceClient)} property directly.\")]\n        public void ConfigureQueueServiceClient(Uri serviceUri, StorageSharedKeyCredential sharedKeyCredential)\n        {\n            if (serviceUri is null) throw new ArgumentNullException(nameof(serviceUri));\n            if (sharedKeyCredential is null) throw new ArgumentNullException(nameof(sharedKeyCredential));\n            CreateClient = () => Task.FromResult(new QueueServiceClient(serviceUri, sharedKeyCredential, ClientOptions));\n        }\n    }\n\n    public class AzureQueueOptionsValidator : IConfigurationValidator\n    {\n        private readonly AzureQueueOptions options;\n        private readonly string name;\n\n        private AzureQueueOptionsValidator(AzureQueueOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (this.options.CreateClient is null)\n            {\n                throw new OrleansConfigurationException($\"No credentials specified. Use the {options.GetType().Name}.{nameof(AzureQueueOptions.ConfigureQueueServiceClient)} method to configure the Azure Queue Service client.\");\n            }\n\n            if (options.QueueNames == null || options.QueueNames.Count == 0)\n                throw new OrleansConfigurationException(\n                    $\"{nameof(AzureQueueOptions)} on stream provider {this.name} is invalid. {nameof(AzureQueueOptions.QueueNames)} is invalid\");\n        }\n\n        public static IConfigurationValidator Create(IServiceProvider services, string name)\n        {\n            AzureQueueOptions aqOptions = services.GetOptionsByName<AzureQueueOptions>(name);\n            return new AzureQueueOptionsValidator(aqOptions, name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/AzureQueueStreamProviderUtils.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    /// <summary>\n    /// Utility functions for azure queue Persistent stream provider.\n    /// </summary>\n    public class AzureQueueStreamProviderUtils\n    {\n        /// <summary>\n        /// Generate default azure queue names\n        /// </summary>\n        /// <param name=\"serviceId\"></param>\n        /// <param name=\"providerName\"></param>\n        /// <returns></returns>\n        public static List<string> GenerateDefaultAzureQueueNames(string serviceId, string providerName)\n        {\n            var defaultQueueMapper = new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions(), providerName);\n            return defaultQueueMapper.GetAllQueues()\n                .Select(queueName => $\"{serviceId}-{queueName}\").ToList();\n        }\n\n        /// <summary>\n        /// Helper method for testing. Deletes all the queues used by the specified stream provider.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"azureQueueNames\">azure queue names to be deleted.</param>\n        /// <param name=\"storageConnectionString\">The azure storage connection string.</param>\n        public static async Task DeleteAllUsedAzureQueues(ILoggerFactory loggerFactory, List<string> azureQueueNames, string storageConnectionString)\n        {\n            var options = new AzureQueueOptions();\n            options.QueueServiceClient = new(storageConnectionString);\n            await DeleteAllUsedAzureQueues(loggerFactory, azureQueueNames, options);\n        }\n\n        /// <summary>\n        /// Helper method for testing. Deletes all the queues used by the specified stream provider.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"azureQueueNames\">azure queue names to be deleted.</param>\n        /// <param name=\"queueOptions\">The azure storage options.</param>\n        public static async Task DeleteAllUsedAzureQueues(ILoggerFactory loggerFactory, List<string> azureQueueNames, AzureQueueOptions queueOptions)\n        {\n            var deleteTasks = new List<Task>();\n            foreach (var queueName in azureQueueNames)\n            {\n                var manager = new AzureQueueDataManager(loggerFactory, queueName, queueOptions);\n                deleteTasks.Add(manager.DeleteQueue());\n            }\n\n            await Task.WhenAll(deleteTasks);\n        }\n\n        /// <summary>\n        /// Helper method for testing. Clears all messages in all the queues used by the specified stream provider.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"azureQueueNames\">The deployment ID hosting the stream provider.</param>\n        /// <param name=\"storageConnectionString\">The azure storage connection string.</param>\n        public static async Task ClearAllUsedAzureQueues(ILoggerFactory loggerFactory, List<string> azureQueueNames, string storageConnectionString)\n        {\n            var options = new AzureQueueOptions();\n            options.QueueServiceClient = new(storageConnectionString);\n            await ClearAllUsedAzureQueues(loggerFactory, azureQueueNames, options);\n        }\n\n        /// <summary>\n        /// Helper method for testing. Clears all messages in all the queues used by the specified stream provider.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"azureQueueNames\">The deployment ID hosting the stream provider.</param>\n        /// <param name=\"queueOptions\">The azure storage options.</param>\n        public static async Task ClearAllUsedAzureQueues(ILoggerFactory loggerFactory, List<string> azureQueueNames, AzureQueueOptions queueOptions)\n        {\n            var deleteTasks = new List<Task>();\n            foreach (var queueName in azureQueueNames)\n            {\n                var manager = new AzureQueueDataManager(loggerFactory, queueName, queueOptions);\n                deleteTasks.Add(manager.ClearQueue());\n            }\n\n            await Task.WhenAll(deleteTasks);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/AzureQueue/IAzureQueueDataAdapter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    /// <summary>\n    /// Original data adapter.  Here to maintain backwards compatibility, but does not support json and other custom serializers\n    /// </summary>\n    [SerializationCallbacks(typeof(OnDeserializedCallbacks))]\n    public class AzureQueueDataAdapterV1 : IQueueDataAdapter<string, IBatchContainer>, IOnDeserialized\n    {\n        private Serializer<AzureQueueBatchContainer> serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AzureQueueDataAdapterV1\"/> class.\n        /// </summary>\n        /// <param name=\"serializer\"></param>\n        public AzureQueueDataAdapterV1(Serializer serializer)\n        {\n            this.serializer = serializer.GetSerializer<AzureQueueBatchContainer>();\n        }\n\n        /// <summary>\n        /// Creates a cloud queue message from stream event data.\n        /// </summary>\n        public string ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            var azureQueueBatchMessage = new AzureQueueBatchContainer(streamId, events.Cast<object>().ToList(), requestContext);\n            var rawBytes = this.serializer.SerializeToArray(azureQueueBatchMessage);\n            return Convert.ToBase64String(rawBytes);\n        }\n\n        /// <summary>\n        /// Creates a batch container from a cloud queue message\n        /// </summary>\n        public IBatchContainer FromQueueMessage(string cloudMsg, long sequenceId)\n        {\n            var azureQueueBatch = this.serializer.Deserialize(Convert.FromBase64String(cloudMsg));\n            azureQueueBatch.RealSequenceToken = new EventSequenceToken(sequenceId);\n            return azureQueueBatch;\n        }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            this.serializer = context.ServiceProvider.GetRequiredService<Serializer<AzureQueueBatchContainer>>();\n        }\n    }\n\n    /// <summary>\n    /// Data adapter that uses types that support custom serializers (like json).\n    /// </summary>\n    [SerializationCallbacks(typeof(OnDeserializedCallbacks))]\n    public class AzureQueueDataAdapterV2 : IQueueDataAdapter<string, IBatchContainer>, IOnDeserialized\n    {\n        private Serializer<AzureQueueBatchContainerV2> serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AzureQueueDataAdapterV2\"/> class.\n        /// </summary>\n        /// <param name=\"serializer\"></param>\n        public AzureQueueDataAdapterV2(Serializer serializer)\n        {\n            this.serializer = serializer.GetSerializer<AzureQueueBatchContainerV2>();\n        }\n\n        /// <summary>\n        /// Creates a cloud queue message from stream event data.\n        /// </summary>\n        public string ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            var azureQueueBatchMessage = new AzureQueueBatchContainerV2(streamId, events.Cast<object>().ToList(), requestContext);\n            var rawBytes = this.serializer.SerializeToArray(azureQueueBatchMessage);\n            return Convert.ToBase64String(rawBytes);\n        }\n\n        /// <summary>\n        /// Creates a batch container from a cloud queue message\n        /// </summary>\n        public IBatchContainer FromQueueMessage(string cloudMsg, long sequenceId)\n        {\n            var azureQueueBatch = this.serializer.Deserialize(Convert.FromBase64String(cloudMsg));\n            azureQueueBatch.RealSequenceToken = new EventSequenceTokenV2(sequenceId);\n            return azureQueueBatch;\n        }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            this.serializer = context.ServiceProvider.GetRequiredService<Serializer<AzureQueueBatchContainerV2>>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/PersistentStreams/AzureTableStorageStreamFailureHandler.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streaming.AzureStorage;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.PersistentStreams\n{\n    /// <summary>\n    /// Delivery failure handler that writes failures to azure table storage.\n    /// </summary>\n    /// <typeparam name=\"TEntity\"></typeparam>\n    public class AzureTableStorageStreamFailureHandler<TEntity> : IStreamFailureHandler where TEntity : StreamDeliveryFailureEntity, new()\n    {\n        private static readonly Func<TEntity> DefaultCreateEntity = () => new TEntity();\n        private readonly Serializer<StreamSequenceToken> serializer;\n        private readonly string clusterId;\n        private readonly AzureTableDataManager<TEntity> dataManager;\n        private readonly Func<TEntity> createEntity;\n\n        /// <summary>\n        /// Delivery failure handler that writes failures to azure table storage.\n        /// </summary>\n        /// <param name=\"serializer\"></param>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"faultOnFailure\"></param>\n        /// <param name=\"clusterId\"></param>\n        /// <param name=\"azureStorageOptions\"></param>\n        /// <param name=\"createEntity\"></param>\n        public AzureTableStorageStreamFailureHandler(Serializer<StreamSequenceToken> serializer, ILoggerFactory loggerFactory, bool faultOnFailure, string clusterId, AzureStorageOperationOptions azureStorageOptions, Func<TEntity> createEntity = null)\n        {\n            if (string.IsNullOrEmpty(clusterId))\n            {\n                throw new ArgumentNullException(nameof(clusterId));\n            }\n            if (string.IsNullOrEmpty(azureStorageOptions.TableName))\n            {\n                throw new ArgumentNullException(nameof(azureStorageOptions.TableName));\n            }\n\n            this.serializer = serializer;\n            this.clusterId = clusterId;\n            ShouldFaultSubsriptionOnError = faultOnFailure;\n            this.createEntity = createEntity ?? DefaultCreateEntity;\n            dataManager = new AzureTableDataManager<TEntity>(\n                azureStorageOptions,\n                loggerFactory.CreateLogger<AzureTableDataManager<TEntity>>());\n        }\n\n        /// <summary>\n        /// Indicates if the subscription should be put in a faulted state upon stream failures\n        /// </summary>\n        public bool ShouldFaultSubsriptionOnError { get; private set; }\n\n        /// <summary>\n        /// Initialization\n        /// </summary>\n        /// <returns></returns>\n        public Task InitAsync()\n        {\n            return dataManager.InitTableAsync();\n        }\n\n        /// <summary>\n        /// Should be called when an event could not be delivered to a consumer, after exhausting retry attempts.\n        /// </summary>\n        /// <param name=\"subscriptionId\"></param>\n        /// <param name=\"streamProviderName\"></param>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"sequenceToken\"></param>\n        /// <returns></returns>\n        public Task OnDeliveryFailure(GuidId subscriptionId, string streamProviderName, StreamId streamId,\n            StreamSequenceToken sequenceToken)\n        {\n            return OnFailure(subscriptionId, streamProviderName, streamId, sequenceToken);\n        }\n\n        /// <summary>\n        /// Should be called when a subscription requested by a consumer could not be setup, after exhausting retry attempts.\n        /// </summary>\n        /// <param name=\"subscriptionId\"></param>\n        /// <param name=\"streamProviderName\"></param>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"sequenceToken\"></param>\n        /// <returns></returns>\n        public Task OnSubscriptionFailure(GuidId subscriptionId, string streamProviderName, StreamId streamId,\n            StreamSequenceToken sequenceToken)\n        {\n            return OnFailure(subscriptionId, streamProviderName, streamId, sequenceToken);\n        }\n\n        private async Task OnFailure(GuidId subscriptionId, string streamProviderName, StreamId streamId,\n                StreamSequenceToken sequenceToken)\n        {\n            if (subscriptionId == null)\n            {\n                throw new ArgumentNullException(nameof(subscriptionId));\n            }\n            if (string.IsNullOrWhiteSpace(streamProviderName))\n            {\n                throw new ArgumentNullException(nameof(streamProviderName));\n            }\n\n            var failureEntity = createEntity();\n            failureEntity.SubscriptionId = subscriptionId.Guid;\n            failureEntity.StreamProviderName = streamProviderName;\n            failureEntity.StreamGuid = streamId.GetKeyAsString();\n            failureEntity.StreamNamespace = streamId.GetNamespace();\n            failureEntity.SetSequenceToken(this.serializer, sequenceToken);\n            failureEntity.SetPartitionKey(this.clusterId);\n            failureEntity.SetRowkey();\n            await dataManager.CreateTableEntryAsync(failureEntity);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Providers/Streams/PersistentStreams/StreamDeliveryFailureEntity.cs",
    "content": "using System;\nusing Azure;\nusing Azure.Data.Tables;\nusing Orleans.Serialization;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.PersistentStreams\n{\n    /// <summary>\n    /// Delivery failure table storage entity.\n    /// </summary>\n    public class StreamDeliveryFailureEntity : ITableEntity\n    {\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n\n        /// <summary>\n        /// Id of the subscription on which this delivery failure occurred.\n        /// </summary>\n        public Guid SubscriptionId { get; set; }\n\n        /// <summary>\n        /// Name of the stream provider generating this failure.\n        /// </summary>\n        public string StreamProviderName { get; set; }\n\n        /// <summary>\n        /// Guid Id of the stream on which the failure occurred.\n        /// </summary>\n        public string StreamGuid { get; set; }\n\n        /// <summary>\n        /// Namespace of the stream on which the failure occurred.\n        /// </summary>\n        public string StreamNamespace { get; set; }\n\n        /// <summary>\n        /// Serialized sequence token of the event that failed delivery.\n        /// </summary>\n        public byte[] SequenceToken { get; set; }\n\n        /// <summary>\n        /// Sets the partition key before persist call.\n        /// </summary>\n        public virtual void SetPartitionKey(string deploymentId)\n        {\n            PartitionKey = MakeDefaultPartitionKey(StreamProviderName, deploymentId);\n        }\n\n        /// <summary>\n        /// Default partition key\n        /// </summary>\n        public static string MakeDefaultPartitionKey(string streamProviderName, string deploymentId)\n        {\n            return $\"DeliveryFailure_{streamProviderName}_{deploymentId}\";\n        }\n\n        /// <summary>\n        /// Sets the row key before persist call\n        /// </summary>\n        public virtual void SetRowkey()\n        {\n            RowKey = $\"{ReverseOrderTimestampTicks():x16}_{Guid.NewGuid()}\";\n        }\n\n        /// <summary>\n        /// Sets sequence token by serializing it to property.\n        /// </summary>\n        /// <param name=\"serializer\"></param>\n        /// <param name=\"token\"></param>\n        public virtual void SetSequenceToken(Serializer<StreamSequenceToken> serializer, StreamSequenceToken token)\n        {\n            SequenceToken = token != null ? serializer.SerializeToArray(token) : null;\n        }\n\n        /// <summary>\n        /// Gets sequence token by deserializing it from property.\n        /// </summary>\n        /// <returns></returns>\n        public virtual StreamSequenceToken GetSequenceToken(Serializer<StreamSequenceToken> serializer)\n        {\n            return SequenceToken != null ? serializer.Deserialize(SequenceToken) : null;\n        }\n\n        /// <summary>\n        /// Returns the number of ticks from now (UTC) to the year 9683.\n        /// </summary>\n        /// <remarks>\n        /// This is useful for ordering the most recent failures at the start of the partition.  While useful\n        ///  for efficient table storage queries, under heavy failure load this may cause a hot spot in the\n        ///  table. This is not an expected occurrence, but if it happens, we recommend subdividing your row\n        ///  key with some other field (stream namespace?).\n        /// </remarks>\n        /// <returns></returns>\n        protected static long ReverseOrderTimestampTicks()\n        {\n            var now = DateTime.UtcNow;\n            return DateTime.MaxValue.Ticks - now.Ticks;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/README.md",
    "content": "# Microsoft Orleans Streaming for Azure Storage Queues\n\n## Introduction\nMicrosoft Orleans Streaming for Azure Storage provides a stream provider implementation for Orleans using Azure Storage Queues. This allows for publishing and subscribing to streams of events with Azure Storage Queues as the underlying messaging infrastructure.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Streaming.AzureStorage\n```\n\n## Example - Configuring Azure Storage Queues Streaming\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Streams;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Storage Queues as a stream provider\n            .AddAzureQueueStreams(\n                name: \"AzureQueueStreamProvider\", \n                b => b.ConfigureAzureQueue(ob => ob.Configure((options, dep) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.QueueNames = Enumerable.Range(0, 8).Select(num => $\"{dep.Value.ClusterId}-{num}\").ToList();\n                })));\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Azure Storage Queue Streams in a Grain\n```csharp\n// Producer grain\npublic class ProducerGrain : Grain, IProducerGrain\n{\n    private IAsyncStream<string> _stream;\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"AzureQueueStreamProvider\");\n        _stream = streamProvider.GetStream<string>(Guid.NewGuid(), \"MyStreamNamespace\");\n        \n        return base.OnActivateAsync(cancellationToken);\n    }\n\n    public async Task SendMessage(string message)\n    {\n        // Send a message to the stream\n        await _stream.OnNextAsync(message);\n    }\n}\n\n// Consumer grain\npublic class ConsumerGrain : Grain, IConsumerGrain, IAsyncObserver<string>\n{\n    private StreamSubscriptionHandle<string> _subscription;\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get a reference to a stream\n        var streamProvider = GetStreamProvider(\"AzureQueueStreamProvider\");\n        var stream = streamProvider.GetStream<string>(this.GetPrimaryKey(), \"MyStreamNamespace\");\n        \n        // Subscribe to the stream\n        _subscription = await stream.SubscribeAsync(this);\n        \n        await base.OnActivateAsync(cancellationToken);\n    }\n\n    public Task OnNextAsync(string item, StreamSequenceToken token = null)\n    {\n        Console.WriteLine($\"Received message: {item}\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnCompletedAsync()\n    {\n        Console.WriteLine(\"Stream completed\");\n        return Task.CompletedTask;\n    }\n\n    public Task OnErrorAsync(Exception ex)\n    {\n        Console.WriteLine($\"Stream error: {ex.Message}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Streams](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/index)\n- [Stream Providers](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/stream-providers)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Storage/AzureQueueDataManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Storage.Queues;\nusing Azure.Storage.Queues.Models;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils.Utilities;\nusing Orleans.Configuration;\n\nnamespace Orleans.AzureUtils\n{\n    /// <summary>\n    /// How to use the Queue Storage Service: http://www.windowsazure.com/en-us/develop/net/how-to-guides/queue-service/\n    /// Windows Azure Storage Abstractions and their Scalability Targets: http://blogs.msdn.com/b/windowsazurestorage/archive/2010/05/10/windows-azure-storage-abstractions-and-their-scalability-targets.aspx\n    /// Naming Queues and Metadata: http://msdn.microsoft.com/en-us/library/windowsazure/dd179349.aspx\n    /// Windows Azure Queues and Windows Azure Service Bus Queues - Compared and Contrasted: http://msdn.microsoft.com/en-us/library/hh767287(VS.103).aspx\n    /// Status and Error Codes: http://msdn.microsoft.com/en-us/library/dd179382.aspx\n    ///\n    /// http://blogs.msdn.com/b/windowsazurestorage/archive/tags/scalability/\n    /// http://blogs.msdn.com/b/windowsazurestorage/archive/2010/12/30/windows-azure-storage-architecture-overview.aspx\n    /// http://blogs.msdn.com/b/windowsazurestorage/archive/2010/11/06/how-to-get-most-out-of-windows-azure-tables.aspx\n    ///\n    /// </summary>\n    internal static class AzureQueueDefaultPolicies\n    {\n        public static int MaxQueueOperationRetries;\n        public static TimeSpan PauseBetweenQueueOperationRetries;\n        public static TimeSpan QueueOperationTimeout;\n\n        static AzureQueueDefaultPolicies()\n        {\n            MaxQueueOperationRetries = 5;\n            PauseBetweenQueueOperationRetries = TimeSpan.FromMilliseconds(100);\n            QueueOperationTimeout = PauseBetweenQueueOperationRetries.Multiply(MaxQueueOperationRetries).Multiply(6);    // 3 sec\n        }\n    }\n\n    /// <summary>\n    /// Utility class to encapsulate access to Azure queue storage.\n    /// </summary>\n    /// <remarks>\n    /// Used by Azure queue streaming provider.\n    /// </remarks>\n    public partial class AzureQueueDataManager\n    {\n        /// <summary> Name of the table queue instance is managing. </summary>\n        public string QueueName { get; private set; }\n\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        private readonly ILogger logger;\n        private readonly TimeSpan? messageVisibilityTimeout;\n        private readonly AzureQueueOptions options;\n        private QueueClient _queueClient;\n\n        /// <summary>\n        /// Constructor.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"queueName\">Name of the queue to be connected to.</param>\n        /// <param name=\"storageConnectionString\">Connection string for the Azure storage account used to host this table.</param>\n        /// <param name=\"visibilityTimeout\">A TimeSpan specifying the visibility timeout interval</param>\n        public AzureQueueDataManager(ILoggerFactory loggerFactory, string queueName, string storageConnectionString, TimeSpan? visibilityTimeout = null)\n            : this (loggerFactory, queueName, ConfigureOptions(storageConnectionString, visibilityTimeout))\n        {\n        }\n\n        private static AzureQueueOptions ConfigureOptions(string storageConnectionString, TimeSpan? visibilityTimeout)\n        {\n            var options = new AzureQueueOptions\n            {\n                MessageVisibilityTimeout = visibilityTimeout\n            };\n            options.QueueServiceClient = new(storageConnectionString);\n            return options;\n        }\n\n        /// <summary>\n        /// Constructor.\n        /// </summary>\n        /// <param name=\"loggerFactory\">logger factory to use</param>\n        /// <param name=\"queueName\">Name of the queue to be connected to.</param>\n        /// <param name=\"options\">Queue connection options.</param>\n        public AzureQueueDataManager(ILoggerFactory loggerFactory, string queueName, AzureQueueOptions options)\n        {\n            queueName = SanitizeQueueName(queueName);\n            ValidateQueueName(queueName);\n\n            logger = loggerFactory.CreateLogger<AzureQueueDataManager>();\n            QueueName = queueName;\n            messageVisibilityTimeout = options.MessageVisibilityTimeout;\n            this.options = options;\n        }\n\n        private ValueTask<QueueClient> GetQueueClient()\n        {\n            if (_queueClient is { } client)\n            {\n                return new(client);\n            }\n\n            return GetQueueClientAsync();\n            async ValueTask<QueueClient> GetQueueClientAsync() => _queueClient ??= await GetCloudQueueClient(options);\n        }\n\n        /// <summary>\n        /// Initializes the connection to the queue.\n        /// </summary>\n        public async Task InitQueueAsync()\n        {\n            var startTime = DateTime.UtcNow;\n\n            try\n            {\n                // Create the queue if it doesn't already exist.\n                var client = await GetQueueClient();\n                var response = await client.CreateIfNotExistsAsync();\n                LogInfoAzureQueueConnection(QueueName);\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"CreateIfNotExist\", AzureQueueErrorCode.AzureQueue_02);\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"InitQueue_Async\");\n            }\n        }\n\n        /// <summary>\n        /// Deletes the queue.\n        /// </summary>\n        public async Task DeleteQueue()\n        {\n            var startTime = DateTime.UtcNow;\n            LogTraceDeletingQueue(QueueName);\n            try\n            {\n                // that way we don't have first to create the queue to be able later to delete it.\n                var client = await GetQueueClient();\n                if (await client.DeleteIfExistsAsync())\n                {\n                    LogInfoAzureQueueDeleted(QueueName);\n                }\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"DeleteQueue\", AzureQueueErrorCode.AzureQueue_04);\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"DeleteQueue\");\n            }\n        }\n\n        /// <summary>\n        /// Clears the queue.\n        /// </summary>\n        public async Task ClearQueue()\n        {\n            var startTime = DateTime.UtcNow;\n            LogTraceClearingAQueue(QueueName);\n            try\n            {\n                // that way we don't have first to create the queue to be able later to delete it.\n                var client = await GetQueueClient();\n                await client.ClearMessagesAsync();\n                LogInfoAzureQueueClear(QueueName);\n            }\n            catch (RequestFailedException exc)\n            {\n                if (exc.Status != (int)HttpStatusCode.NotFound)\n                {\n                    ReportErrorAndRethrow(exc, \"ClearQueue\", AzureQueueErrorCode.AzureQueue_06);\n                }\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"ClearQueue\", AzureQueueErrorCode.AzureQueue_06);\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"ClearQueue\");\n            }\n        }\n\n        /// <summary>\n        /// Adds a new message to the queue.\n        /// </summary>\n        /// <param name=\"message\">Message to be added to the queue.</param>\n        public async Task AddQueueMessage(string message)\n        {\n            var startTime = DateTime.UtcNow;\n            LogTraceAddingMessage(message, QueueName);\n            try\n            {\n                var client = await GetQueueClient();\n                await client.SendMessageAsync(message);\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"AddQueueMessage\", AzureQueueErrorCode.AzureQueue_07);\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"AddQueueMessage\");\n            }\n        }\n\n        /// <summary>\n        /// Peeks in the queue for latest message, without dequeuing it.\n        /// </summary>\n        public async Task<PeekedMessage> PeekQueueMessage()\n        {\n            var startTime = DateTime.UtcNow;\n            LogTracePeekingMessage(QueueName);\n            try\n            {\n                var client = await GetQueueClient();\n                var messages = await client.PeekMessagesAsync(maxMessages: 1);\n                return messages.Value.FirstOrDefault();\n\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"PeekQueueMessage\", AzureQueueErrorCode.AzureQueue_08);\n                return null; // Dummy statement to keep compiler happy\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"PeekQueueMessage\");\n            }\n        }\n\n\n        /// <summary>\n        /// Gets a new message from the queue.\n        /// </summary>\n        public async Task<QueueMessage> GetQueueMessage()\n        {\n               var startTime = DateTime.UtcNow;\n            LogTraceGettingMessage(QueueName);\n            try\n            {\n                //BeginGetMessage and EndGetMessage is not supported in netstandard, may be use GetMessageAsync\n                // http://msdn.microsoft.com/en-us/library/ee758456.aspx\n                // If no messages are visible in the queue, GetMessage returns null.\n                var client = await GetQueueClient();\n                var messages = await client.ReceiveMessagesAsync(maxMessages: 1, messageVisibilityTimeout);\n                return messages.Value.FirstOrDefault();\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"GetQueueMessage\", AzureQueueErrorCode.AzureQueue_09);\n                return null; // Dummy statement to keep compiler happy\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"GetQueueMessage\");\n            }\n        }\n\n        /// <summary>\n        /// Gets a number of new messages from the queue.\n        /// </summary>\n        /// <param name=\"count\">Number of messages to get from the queue.</param>\n        public async Task<IEnumerable<QueueMessage>> GetQueueMessages(int? count = null)\n        {\n            var startTime = DateTime.UtcNow;\n            if (count == -1)\n            {\n                count = null;\n            }\n\n            LogTraceGettingUpToMessages(count, QueueName);\n            try\n            {\n                var client = await GetQueueClient();\n                var messages = await client.ReceiveMessagesAsync(count, messageVisibilityTimeout);\n                return messages.Value;\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"GetQueueMessages\", AzureQueueErrorCode.AzureQueue_10);\n                return null; // Dummy statement to keep compiler happy\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"GetQueueMessages\");\n            }\n        }\n\n        /// <summary>\n        /// Deletes a messages from the queue.\n        /// </summary>\n        /// <param name=\"message\">A message to be deleted from the queue.</param>\n        public async Task DeleteQueueMessage(QueueMessage message)\n        {\n            var startTime = DateTime.UtcNow;\n            LogTraceDeletingAMessage(QueueName);\n            try\n            {\n                var client = await GetQueueClient();\n                await client.DeleteMessageAsync(message.MessageId, message.PopReceipt);\n\n            }\n            catch (RequestFailedException exc)\n            {\n                if (exc.Status != (int)HttpStatusCode.NotFound)\n                {\n                    ReportErrorAndRethrow(exc, \"DeleteMessage\", AzureQueueErrorCode.AzureQueue_11);\n                }\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"DeleteMessage\", AzureQueueErrorCode.AzureQueue_11);\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"DeleteQueueMessage\");\n            }\n        }\n\n        internal async Task GetAndDeleteQueueMessage()\n        {\n            var message = await GetQueueMessage();\n            await DeleteQueueMessage(message);\n        }\n\n        /// <summary>\n        /// Returns an approximate number of messages in the queue.\n        /// </summary>\n        public async Task<int> GetApproximateMessageCount()\n        {\n            var startTime = DateTime.UtcNow;\n            LogTraceGetApproximateMessageCount(QueueName);\n            try\n            {\n                var client = await GetQueueClient();\n                var properties = await client.GetPropertiesAsync();\n                return properties.Value.ApproximateMessagesCount;\n\n            }\n            catch (Exception exc)\n            {\n                ReportErrorAndRethrow(exc, \"FetchAttributes\", AzureQueueErrorCode.AzureQueue_12);\n                return 0; // Dummy statement to keep compiler happy\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, \"GetApproximateMessageCount\");\n            }\n        }\n\n        private void CheckAlertSlowAccess(DateTime startOperation, string operation)\n        {\n            var timeSpan = DateTime.UtcNow - startOperation;\n            if (timeSpan > AzureQueueDefaultPolicies.QueueOperationTimeout)\n            {\n                LogWarningSlowAzureQueueAccess(QueueName, operation, timeSpan);\n            }\n        }\n\n        private void ReportErrorAndRethrow(Exception exc, string operation, AzureQueueErrorCode errorCode)\n        {\n            var errMsg = string.Format(\n                \"Error doing {0} for Azure storage queue {1} \" + Environment.NewLine\n                + \"Exception = {2}\", operation, QueueName, exc);\n            logger.LogError((int)errorCode, exc, \"{Message}\", errMsg); // TODO: pending on https://github.com/dotnet/runtime/issues/110570\n            throw new AggregateException(errMsg, exc);\n        }\n\n        private async Task<QueueClient> GetCloudQueueClient(AzureQueueOptions options)\n        {\n            try\n            {\n                var client = await options.CreateClient();\n                return client.GetQueueClient(QueueName);\n            }\n            catch (Exception exc)\n            {\n                LogErrorCreatingAzureQueueClient(exc);\n                throw;\n            }\n        }\n\n        private static string SanitizeQueueName(string queueName)\n        {\n            var tmp = queueName;\n            //Azure queue naming rules : https://learn.microsoft.com/rest/api/storageservices/Naming-Queues-and-Metadata?redirectedfrom=MSDN\n            tmp = tmp.ToLowerInvariant();\n            tmp = tmp\n                .Replace('/', '-') // Forward slash\n                .Replace('\\\\', '-') // Backslash\n                .Replace('#', '-') // Pound sign\n                .Replace('?', '-') // Question mark\n                .Replace('&', '-')\n                .Replace('+', '-')\n                .Replace(':', '-')\n                .Replace('.', '-')\n                .Replace('%', '-');\n            return tmp;\n        }\n\n        private static void ValidateQueueName(string queueName)\n        {\n            // Naming Queues and Metadata: http://msdn.microsoft.com/en-us/library/windowsazure/dd179349.aspx\n            if (!(queueName.Length >= 3 && queueName.Length <= 63))\n            {\n                // A queue name must be from 3 through 63 characters long.\n                throw new ArgumentException(string.Format(\"A queue name must be from 3 through 63 characters long, while your queueName length is {0}, queueName is {1}.\", queueName.Length, queueName), queueName);\n            }\n\n            if (!char.IsLetterOrDigit(queueName.First()))\n            {\n                // A queue name must start with a letter or number\n                throw new ArgumentException(string.Format(\"A queue name must start with a letter or number, while your queueName is {0}.\", queueName), queueName);\n            }\n\n            if (!char.IsLetterOrDigit(queueName.Last()))\n            {\n                // The first and last letters in the queue name must be alphanumeric. The dash (-) character cannot be the first or last character.\n                throw new ArgumentException(string.Format(\"The last letter in the queue name must be alphanumeric, while your queueName is {0}.\", queueName), queueName);\n            }\n\n            if (!queueName.All(c => char.IsLetterOrDigit(c) || c.Equals('-')))\n            {\n                // A queue name can only contain letters, numbers, and the dash (-) character.\n                throw new ArgumentException(string.Format(\"A queue name can only contain letters, numbers, and the dash (-) character, while your queueName is {0}.\", queueName), queueName);\n            }\n\n            if (queueName.Contains(\"--\"))\n            {\n                // Consecutive dash characters are not permitted in the queue name.\n                throw new ArgumentException(string.Format(\"Consecutive dash characters are not permitted in the queue name, while your queueName is {0}.\", queueName), queueName);\n            }\n\n            if (queueName.Where(char.IsLetter).Any(c => !char.IsLower(c)))\n            {\n                // All letters in a queue name must be lowercase.\n                throw new ArgumentException(string.Format(\"All letters in a queue name must be lowercase, while your queueName is {0}.\", queueName), queueName);\n            }\n        }\n\n        [LoggerMessage(\n            EventId = (int)AzureQueueErrorCode.AzureQueue_01,\n            Level = LogLevel.Information,\n            Message = \"Connected to Azure storage queue {QueueName}\"\n        )]\n        private partial void LogInfoAzureQueueConnection(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Deleting queue: {QueueName}\"\n        )]\n        private partial void LogTraceDeletingQueue(string queueName);\n\n        [LoggerMessage(\n            EventId = (int)AzureQueueErrorCode.AzureQueue_03,\n            Level = LogLevel.Information,\n            Message = \"Deleted Azure Queue {QueueName}\"\n        )]\n        private partial void LogInfoAzureQueueDeleted(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Clearing a queue: {QueueName}\"\n        )]\n        private partial void LogTraceClearingAQueue(string queueName);\n\n        [LoggerMessage(\n            EventId = (int)AzureQueueErrorCode.AzureQueue_05,\n            Level = LogLevel.Information,\n            Message = \"Cleared Azure Queue {QueueName}\"\n        )]\n        private partial void LogInfoAzureQueueClear(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Adding message {Data} to queue: {QueueName}\"\n        )]\n        private partial void LogTraceAddingMessage(string data, string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Peeking a message from queue: {QueueName}\"\n        )]\n        private partial void LogTracePeekingMessage(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Getting a message from queue: {QueueName}\"\n        )]\n        private partial void LogTraceGettingMessage(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Getting up to {MessageCount} messages from queue: {QueueName}\"\n        )]\n        private partial void LogTraceGettingUpToMessages(int? messageCount, string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Deleting a message from queue: {QueueName}\"\n        )]\n        private partial void LogTraceDeletingAMessage(string queueName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"GetApproximateMessageCount a message from queue: {QueueName}\"\n        )]\n        private partial void LogTraceGetApproximateMessageCount(string queueName);\n\n        [LoggerMessage(\n            EventId = (int)AzureQueueErrorCode.AzureQueue_13,\n            Level = LogLevel.Warning,\n            Message = \"Slow access to Azure queue {QueueName} for {Operation}, which took {TimeSpan}.\"\n        )]\n        private partial void LogWarningSlowAzureQueueAccess(string queueName, string operation, TimeSpan timeSpan);\n\n        [LoggerMessage(\n            EventId = (int)AzureQueueErrorCode.AzureQueue_14,\n            Level = LogLevel.Error,\n            Message = \"Error creating Azure Storage Queues client\"\n        )]\n        private partial void LogErrorCreatingAzureQueueClient(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.AzureStorage/Utilities/AzureQueueErrorCode.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.AzureUtils.Utilities\n{\n    [SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n    internal enum AzureQueueErrorCode\n    {\n        Runtime = 100000,\n        AzureQueueBase = Runtime + 3200,\n\n        AzureQueue_01 = AzureQueueBase + 1,\n        AzureQueue_02 = AzureQueueBase + 2,\n        AzureQueue_03 = AzureQueueBase + 3,\n        AzureQueue_04 = AzureQueueBase + 4,\n        AzureQueue_05 = AzureQueueBase + 5,\n        AzureQueue_06 = AzureQueueBase + 6,\n        AzureQueue_07 = AzureQueueBase + 7,\n        AzureQueue_08 = AzureQueueBase + 8,\n        AzureQueue_09 = AzureQueueBase + 9,\n        AzureQueue_10 = AzureQueueBase + 10,\n        AzureQueue_11 = AzureQueueBase + 11,\n        AzureQueue_12 = AzureQueueBase + 12,\n        AzureQueue_13 = AzureQueueBase + 13,\n        AzureQueue_14 = AzureQueueBase + 14,\n        AzureQueue_15 = AzureQueueBase + 15,\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Hosting/ClientBuilderExtensions.cs",
    "content": "using System;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class ClientBuilderExtensions\n    {\n        /// <summary>\n        /// Configure cluster client to use event hub persistent streams.\n        /// </summary>\n        public static IClientBuilder AddEventHubStreams(\n           this IClientBuilder builder,\n           string name,\n           Action<IClusterClientEventHubStreamConfigurator> configure)\n        {\n            var configurator = new ClusterClientEventHubStreamConfigurator(name,builder);\n            configure?.Invoke(configurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure cluster client to use event hub persistent streams with default settings.\n        /// </summary>\n        public static IClientBuilder AddEventHubStreams(\n            this IClientBuilder builder,\n            string name, Action<EventHubOptions> configureEventHub)\n        {\n            builder.AddEventHubStreams(name, b=>b.ConfigureEventHub(ob => ob.Configure(configureEventHub)));\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Hosting/DeveloperExtensions.cs",
    "content": "using System;\n\nnamespace Orleans.Hosting.Developer\n{\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use event data generator streams.\n        /// </summary>\n        public static ISiloBuilder AddEventDataGeneratorStreams(\n            this ISiloBuilder builder,\n            string name,\n            Action<IEventDataGeneratorStreamConfigurator> configure)\n        {\n            var configurator = new EventDataGeneratorStreamConfigurator(name,\n                configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n            configure?.Invoke(configurator);\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Hosting/SiloBuilderExtensions.cs",
    "content": "using System;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use event hub persistent streams.\n        /// </summary>\n        public static ISiloBuilder AddEventHubStreams(\n            this ISiloBuilder builder,\n            string name,\n            Action<ISiloEventHubStreamConfigurator> configure)\n        {\n            var configurator = new SiloEventHubStreamConfigurator(name,\n                configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n            configure?.Invoke(configurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure silo to use event hub persistent streams with default check pointer and other settings\n        /// </summary>\n        public static ISiloBuilder AddEventHubStreams(\n            this ISiloBuilder builder,\n            string name, Action<EventHubOptions> configureEventHub, Action<AzureTableStreamCheckpointerOptions> configureDefaultCheckpointer)\n        {\n            return builder.AddEventHubStreams(name, b =>\n            {\n                b.ConfigureEventHub(ob => ob.Configure(configureEventHub));\n                b.UseAzureTableCheckpointer(ob => ob.Configure(configureDefaultCheckpointer));\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Orleans.Streaming.EventHubs.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Streaming.EventHubs</PackageId>\n    <Title>Microsoft Orleans Azure Event Hubs Streaming Provider</Title>\n    <Description>Microsoft Orleans streaming provider backed by Azure Event Hubs</Description>\n    <PackageTags>$(PackageTags) Azure EventHubs</PackageTags>\n    <DefineConstants>$(DefineConstants);ORLEANS_EVENTHUBS</DefineConstants>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Streaming.EventHubs</AssemblyName>\n    <RootNamespace>Orleans.Streaming.EventHubs</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n    <PackageReference Include=\"Azure.Messaging.EventHubs\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Streaming.EventHubs.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/OrleansServiceBusErrorCode.cs",
    "content": "namespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Orleans ServiceBus error codes\n    /// </summary>\n    internal enum OrleansEventHubErrorCode\n    {\n        /// <summary>\n        /// Start of orlean servicebus error codes\n        /// </summary>\n        ServiceBus = 1<<16,\n\n        FailedPartitionRead = ServiceBus + 1,\n        RetryReceiverInit   = ServiceBus + 2,\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/EventDataGeneratorAdapterFactory.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Azure.Messaging.EventHubs;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Statistics;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    /// <summary>\n    /// This is a persistent stream provider adapter that generates it's own events rather than reading them from Eventhub.\n    /// This is primarily for test purposes.\n    ///  </summary>\n    public partial class EventDataGeneratorAdapterFactory : EventHubAdapterFactory, IControllable\n    {\n        private readonly EventDataGeneratorStreamOptions ehGeneratorOptions;\n\n        public EventDataGeneratorAdapterFactory(\n            string name,\n            EventDataGeneratorStreamOptions options,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions,\n            StreamCacheEvictionOptions evictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdapter,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n            : base(name, ehOptions, receiverOptions, cacheOptions, evictionOptions, statisticOptions, dataAdapter, serviceProvider, loggerFactory, environmentStatisticsProvider)\n        {\n            this.ehGeneratorOptions = options;\n        }\n\n        public override void Init()\n        {\n            this.EventHubReceiverFactory = this.EHGeneratorReceiverFactory;\n            base.Init();\n        }\n\n        /// <inheritdoc/>\n        protected override void InitEventHubClient()\n        {\n            //do nothing, EventDataGeneratorStreamProvider doesn't need connection with EventHubClient\n        }\n\n        /// <summary>\n        /// Generate mocked eventhub partition Ids from EventHubGeneratorStreamProviderSettings\n        /// </summary>\n        /// <returns></returns>\n        protected override Task<string[]> GetPartitionIdsAsync()\n        {\n            return Task.FromResult(GenerateEventHubPartitions(this.ehGeneratorOptions.EventHubPartitionCount));\n        }\n\n        private IEventHubReceiver EHGeneratorReceiverFactory(EventHubPartitionSettings settings, string offset, ILogger logger)\n        {\n            var streamGeneratorFactory = this.serviceProvider.GetKeyedService<Func<StreamId, IStreamDataGenerator<EventData>>>(this.Name)\n                ?? SimpleStreamEventDataGenerator.CreateFactory(this.serviceProvider);\n            var generator = new EventHubPartitionDataGenerator(this.ehGeneratorOptions, streamGeneratorFactory, logger);\n            return new EventHubPartitionGeneratorReceiver(generator);\n        }\n\n        private void RandomlyPlaceStreamToQueue(StreamRandomPlacementArg args)\n        {\n            if (args == null)\n                return;\n\n            var allQueueInTheCluster = EventHubQueueMapper?.GetAllQueues();\n            if (allQueueInTheCluster != null)\n            {\n                var allQueues = allQueueInTheCluster as QueueId[] ?? allQueueInTheCluster.ToArray();\n                //every agent receive the same random number, do a mod on queue count, get the same random queue to assign stream to.\n                var queueToAssign = allQueues[args.RandomNumber % allQueues.Length];\n                if (EventHubReceivers.TryGetValue(queueToAssign, out var receiverToAssign))\n                {\n                    receiverToAssign.ConfigureDataGeneratorForStream(args.StreamId);\n                    LogInfoStreamAssignedToQueue(logger, args.StreamId, queueToAssign);\n                }\n            }\n            else\n            {\n                LogInfoCannotGetQueues(logger);\n            }\n        }\n\n        private void StopProducingOnStream(StreamId streamId)\n        {\n            foreach (var ehReceiver in this.EventHubReceivers)\n            {\n                //if the stream is assigned to this receiver/queue, then it will ask the data generator to stop producing\n                ehReceiver.Value.StopProducingOnStream(streamId);\n            }\n        }\n\n        public static string[] GenerateEventHubPartitions(int partitionCount)\n        {\n            var partitions = new string[partitionCount];\n            for (int i = 0; i < partitions.Length; i++)\n                partitions[i] = $\"partition-{i}\";\n            return partitions;\n        }\n\n        /// <summary>\n        /// Commands for IControllable\n        /// </summary>\n        public enum Commands\n        {\n            /// <summary>\n            /// Command for Randomly_Place_Stream_To_Queue\n            /// </summary>\n            Randomly_Place_Stream_To_Queue = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 4,\n            /// <summary>\n            /// Command for Stop_Producing_On_Stream\n            /// </summary>\n            Stop_Producing_On_Stream = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 5\n        }\n\n        /// <summary>\n        /// Args for RandomlyPlaceStreamToQueue method\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public class StreamRandomPlacementArg\n        {\n            /// <summary>\n            /// StreamId\n            /// </summary>\n            [Id(0)]\n            public StreamId StreamId { get; set; }\n\n            /// <summary>\n            /// A random number\n            /// </summary>\n            [Id(1)]\n            public int RandomNumber { get; set; }\n\n            /// <summary>\n            /// Constructor\n            /// </summary>\n            /// <param name=\"streamId\"></param>\n            /// <param name=\"randomNumber\"></param>\n            public StreamRandomPlacementArg(StreamId streamId, int randomNumber)\n            {\n                this.StreamId = streamId;\n                this.RandomNumber = randomNumber;\n            }\n        }\n\n        /// <summary>\n        /// Execute Command\n        /// </summary>\n        /// <param name=\"command\"></param>\n        /// <param name=\"arg\"></param>\n        /// <returns></returns>\n        public virtual Task<object> ExecuteCommand(int command, object arg)\n        {\n            switch (command)\n            {\n                case (int)Commands.Randomly_Place_Stream_To_Queue:\n                    this.RandomlyPlaceStreamToQueue(arg as StreamRandomPlacementArg);\n                    break;\n                case (int)Commands.Stop_Producing_On_Stream:\n                    this.StopProducingOnStream((StreamId) arg);\n                    break;\n                default: break;\n\n            }\n            return Task.FromResult((object)true);\n        }\n\n        public new static EventDataGeneratorAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var generatorOptions= services.GetOptionsByName<EventDataGeneratorStreamOptions>(name);\n            var ehOptions = services.GetOptionsByName<EventHubOptions>(name);\n            var receiverOptions = services.GetOptionsByName<EventHubReceiverOptions>(name);\n            var cacheOptions = services.GetOptionsByName<EventHubStreamCachePressureOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            var evictionOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            IEventHubDataAdapter dataAdapter = services.GetKeyedService<IEventHubDataAdapter>(name)\n                ?? services.GetService<IEventHubDataAdapter>()\n                ?? ActivatorUtilities.CreateInstance<EventHubDataAdapter>(services);\n            var factory = ActivatorUtilities.CreateInstance<EventDataGeneratorAdapterFactory>(services, name, generatorOptions, ehOptions, receiverOptions, cacheOptions,\n                evictionOptions, statisticOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Stream {StreamId} is assigned to queue {QueueId}\"\n        )]\n        private static partial void LogInfoStreamAssignedToQueue(ILogger logger, StreamId streamId, QueueId queueId);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Cannot get queues in the cluster, current streamQueueMapper is not EventHubQueueMapper\"\n        )]\n        private static partial void LogInfoCannotGetQueues(ILogger logger);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/EventDataGeneratorStreamOptions.cs",
    "content": "﻿\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Setting class for EHGeneratorStreamProvider\n    /// </summary>\n    public class EventDataGeneratorStreamOptions \n    {\n        /// <summary>\n        /// Configure eventhub partition count wanted. EventDataGeneratorStreamProvider would generate the same set of partitions based on the count, when initializing.\n        /// For example, if partition count set at 5, the generated partitions will be  partition-0, partition-1, partition-2, partition-3, partition-4\n        /// </summary>\n        public int EventHubPartitionCount = DefaultEventHubPartitionCount;\n        /// <summary>\n        /// Default EventHubPartitionRangeStart\n        /// </summary>\n        public const int DefaultEventHubPartitionCount = 4;\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/EventHubPartitionDataGenerator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing Azure.Messaging.EventHubs;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    /// <summary>\n    /// Generate data for one stream\n    /// </summary>\n    public partial class SimpleStreamEventDataGenerator : IStreamDataGenerator<EventData>\n    {\n        /// <inheritdoc />\n        public StreamId StreamId { get; set; }\n\n        /// <inheritdoc />\n        public IIntCounter SequenceNumberCounter { set; private get; }\n        /// <inheritdoc />\n        public bool ShouldProduce { private get; set; }\n\n        private readonly ILogger logger;\n        private readonly DeepCopier deepCopier;\n        private readonly Serializer serializer;\n\n        public SimpleStreamEventDataGenerator(StreamId streamId, ILogger<SimpleStreamEventDataGenerator> logger, DeepCopier deepCopier, Serializer serializer)\n        {\n            this.StreamId = streamId;\n            this.logger = logger;\n            this.ShouldProduce = true;\n            this.deepCopier = deepCopier;\n            this.serializer = serializer;\n        }\n\n        /// <inheritdoc />\n        public bool TryReadEvents(int maxCount, out IEnumerable<EventData> events)\n        {\n            if (!this.ShouldProduce)\n            {\n                events = null;\n                return false;\n            }\n            int count = maxCount;\n            List<EventData> eventDataList = new List<EventData>(maxCount);\n            while (count-- > 0)\n            {\n                this.SequenceNumberCounter.Increment();\n\n                // Create an EventData instance with an empty body. The body will be set later\n                // from the batch container's context. Because there is a need to explicitly set\n                // broker-owned properties such as the offset, sequence number, and partition key,\n                // an instance is created using the model factory, which avoids the need to set\n                // directly via the underlying AMQP message.\n                var eventData = EventHubsModelFactory.EventData(\n                        eventBody: BinaryData.Empty,\n                        partitionKey: StreamId.GetKeyAsString(),\n                        offsetString: DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture),\n                        sequenceNumber: this.SequenceNumberCounter.Value);\n\n                EventHubBatchContainer.UpdateEventData(\n                    eventData,\n                    this.serializer,\n                    this.StreamId,\n                    GenerateEvent(this.SequenceNumberCounter.Value),\n                    RequestContextExtensions.Export(this.deepCopier));\n\n                eventDataList.Add(eventData);\n                LogInfoGenerateData(this.SequenceNumberCounter.Value, this.StreamId);\n            }\n\n            events = eventDataList;\n            return eventDataList.Count > 0;\n        }\n\n        private static IEnumerable<int> GenerateEvent(int sequenceNumber)\n        {\n            return [sequenceNumber];\n        }\n\n        public static Func<StreamId, IStreamDataGenerator<EventData>> CreateFactory(IServiceProvider services)\n        {\n            return (streamId) => ActivatorUtilities.CreateInstance<SimpleStreamEventDataGenerator>(services, streamId);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Generate data of SequenceNumber {SequenceNumber} for stream {StreamId}\"\n        )]\n        private partial void LogInfoGenerateData(int sequenceNumber, StreamId streamId);\n    }\n\n    /// <summary>\n    /// EHPartitionDataGenerator generate data for a EH partition, which can include data from different streams\n    /// </summary>\n    public partial class EventHubPartitionDataGenerator : IDataGenerator<EventData>, IStreamDataGeneratingController\n    {\n        //differnt stream in the same partition should use the same sequenceNumberCounter\n        private readonly EventDataGeneratorStreamOptions options;\n        private readonly IntCounter sequenceNumberCounter = new IntCounter();\n        private readonly ILogger logger;\n        private readonly Func<StreamId, IStreamDataGenerator<EventData>> generatorFactory;\n        private readonly List<IStreamDataGenerator<EventData>> generators;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <param name=\"generatorFactory\"></param>\n        /// <param name=\"logger\"></param>\n        public EventHubPartitionDataGenerator(EventDataGeneratorStreamOptions options, Func<StreamId, IStreamDataGenerator<EventData>> generatorFactory, ILogger logger)\n        {\n            this.options = options;\n            this.generatorFactory = generatorFactory;\n            this.generators = new List<IStreamDataGenerator<EventData>>();\n            this.logger = logger;\n        }\n        /// <inheritdoc />\n        public void AddDataGeneratorForStream(StreamId streamId)\n        {\n            var generator =  this.generatorFactory(streamId);\n            generator.SequenceNumberCounter = sequenceNumberCounter;\n            LogInfoOnStreamSetup(streamId);\n            this.generators.Add(generator);\n        }\n        /// <inheritdoc />\n        public void StopProducingOnStream(StreamId streamId)\n        {\n            this.generators.ForEach(generator => {\n                if (generator.StreamId.Equals(streamId))\n                {\n                    generator.ShouldProduce = false;\n                    LogInfoOnStreamStop(streamId);\n                }\n            });\n        }\n        /// <inheritdoc />\n        public bool TryReadEvents(int maxCount, out IEnumerable<EventData> events)\n        {\n            if (this.generators.Count == 0)\n            {\n                events = new List<EventData>();\n                return false;\n            }\n            var eventDataList = new List<EventData>();\n            var iterator = this.generators.AsEnumerable().GetEnumerator();\n            var batchCount = maxCount / this.generators.Count;\n            batchCount = batchCount == 0 ? batchCount + 1 : batchCount;\n            while (eventDataList.Count < maxCount)\n            {\n                //if reach to the end of the list, reset iterator to the head\n                if (!iterator.MoveNext())\n                {\n                    iterator.Reset();\n                    iterator.MoveNext();\n                }\n                IEnumerable<EventData> eventData;\n                var remainingCount = maxCount - eventDataList.Count;\n                var count = remainingCount > batchCount ? batchCount : remainingCount;\n                if (iterator.Current.TryReadEvents(count, out eventData))\n                {\n                    foreach (var data in eventData)\n                    {\n                        eventDataList.Add(data);\n                    }\n                }\n            }\n            iterator.Dispose();\n            events = eventDataList.AsEnumerable();\n            return eventDataList.Count > 0;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Data generator set up on stream {StreamId}.\"\n        )]\n        private partial void LogInfoOnStreamSetup(StreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Stop producing data on stream {StreamId}.\"\n        )]\n        private partial void LogInfoOnStreamStop(StreamId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/EventHubPartitionGeneratorReceiver.cs",
    "content": "using Orleans.Runtime;\nusing Azure.Messaging.EventHubs;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    /// <summary>\n    /// Eventhub receiver which configured with data generator\n    /// </summary>\n    public class EventHubPartitionGeneratorReceiver : IEventHubReceiver\n    {\n        private readonly IDataGenerator<EventData> generator;\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"generator\"></param>\n        public EventHubPartitionGeneratorReceiver(IDataGenerator<EventData> generator)\n        {\n            this.generator = generator;\n        }\n        /// <inheritdoc />\n        public async Task<IEnumerable<EventData>> ReceiveAsync(int maxCount, TimeSpan waitTime)\n        {\n            IEnumerable<EventData> events;\n            //mimic real life response time\n            await Task.Delay(TimeSpan.FromMilliseconds(30));\n            if (generator.TryReadEvents(maxCount, out events))\n            {\n                return events;\n            }\n            //if no events generated, wait for waitTime to pass\n            await Task.Delay(waitTime);\n            return new List<EventData>().AsEnumerable();\n        }\n\n        /// <inheritdoc />\n        public void StopProducingOnStream(StreamId streamId)\n        {\n            (this.generator as IStreamDataGeneratingController)?.StopProducingOnStream(streamId);\n        }\n\n        /// <inheritdoc />\n        public void ConfigureDataGeneratorForStream(StreamId streamId)\n        {\n            (this.generator as IStreamDataGeneratingController)?.AddDataGeneratorForStream(streamId);\n        }\n\n        /// <inheritdoc />\n        public Task CloseAsync()\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/IEventDataGenerator.cs",
    "content": "using Orleans.Runtime;\nusing System.Collections.Generic;\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    /// <summary>\n    /// Data generator for test purpose\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface IDataGenerator<T>\n    {\n        /// <summary>\n        /// Data generator mimic event reading\n        /// </summary>\n        /// <param name=\"maxCount\"></param>\n        /// <param name=\"events\"></param>\n        /// <returns></returns>\n        bool TryReadEvents(int maxCount, out IEnumerable<T> events);\n    }\n\n    /// <summary>\n    /// StreamDataGeneratingController control stream data generating start and stop\n    /// </summary>\n    public interface IStreamDataGeneratingController\n    {\n        /// <summary>\n        /// configure data generator for a stream\n        /// </summary>\n        /// <param name=\"streamId\"></param>\n        void AddDataGeneratorForStream(StreamId streamId);\n        /// <summary>\n        /// Ask one stream to stop producing\n        /// </summary>\n        /// <param name=\"streamId\"></param>\n        void StopProducingOnStream(StreamId streamId);\n    }\n\n    /// <summary>\n    /// data generator for a specific stream\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface IStreamDataGenerator<T>: IDataGenerator<T>\n    {\n        /// <summary>\n        /// counter for sequence number\n        /// </summary>\n        IIntCounter SequenceNumberCounter { set; }\n        /// <summary>\n        /// Stream identity for this data generator\n        /// </summary>\n        StreamId StreamId { get; }\n        /// <summary>\n        ///\n        /// </summary>\n        bool ShouldProduce { set; }\n    }\n\n    /// <summary>\n    /// counter for integer\n    /// </summary>\n    public interface IIntCounter\n    {\n        /// <summary>\n        /// counter value\n        /// </summary>\n        int Value { get; }\n        /// <summary>\n        /// increment the counter\n        /// </summary>\n        void Increment();\n    }\n\n    internal class IntCounter : IIntCounter\n    {\n        private int counter = 0;\n        public int Value { get { return this.counter; } }\n        public void Increment()\n        {\n            counter++;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/EventDataGeneratorStreamProvider/NoOpCheckpointer.cs",
    "content": "﻿using Orleans.Streams;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    public class NoOpCheckpointerFactory : IStreamQueueCheckpointerFactory\n    {\n        public static NoOpCheckpointerFactory Instance = new NoOpCheckpointerFactory();\n        public Task<IStreamQueueCheckpointer<string>> Create(string partition)\n        {\n            return Task.FromResult<IStreamQueueCheckpointer<string>>(NoOpCheckpointer.Instance);\n        }\n    }\n    /// <summary>\n    /// NoOpCheckpointer is used in EventDataGeneratorStreamProvider ecosystem to replace the default Checkpointer which requires a back end storage. In EventHubDataGeneratorStreamProvider,\n    /// it is generating EventData on the fly when receiver pull messages from the queue, which means it doesn't support recoverable stream, hence check pointing won't bring much value there. \n    /// So a checkpointer with no ops should be enough.\n    /// </summary>\n    public class NoOpCheckpointer : IStreamQueueCheckpointer<string>\n    {\n        public static NoOpCheckpointer Instance = new NoOpCheckpointer();\n\n        public bool CheckpointExists => true;\n        public Task<string> Load()\n        {\n            return Task.FromResult(EventHubConstants.StartOfStream);\n        }\n        public void Update(string offset, DateTime utcNow)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/CachePressureMonitors/AggregatedCachePressureMonitor.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Aggregated cache pressure monitor\n    /// </summary>\n    public partial class AggregatedCachePressureMonitor : List<ICachePressureMonitor>, ICachePressureMonitor\n    {\n        private bool isUnderPressure;\n        private readonly ILogger logger;\n        /// <summary>\n        /// Cache monitor which is used to report cache related metrics\n        /// </summary>\n        public ICacheMonitor CacheMonitor { set; private get; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public AggregatedCachePressureMonitor(ILogger logger, ICacheMonitor monitor = null)\n        {\n            this.isUnderPressure = false;\n            this.logger = logger;\n            this.CacheMonitor = monitor;\n        }\n\n        /// <summary>\n        /// Record cache pressure to every monitor in this aggregated cache monitor group\n        /// </summary>\n        /// <param name=\"cachePressureContribution\"></param>\n        public void RecordCachePressureContribution(double cachePressureContribution)\n        {\n            this.ForEach(monitor =>\n            {\n                monitor.RecordCachePressureContribution(cachePressureContribution);\n            });\n        }\n\n        /// <summary>\n        /// Add one monitor to this aggregated cache monitor group\n        /// </summary>\n        /// <param name=\"monitor\"></param>\n        public void AddCachePressureMonitor(ICachePressureMonitor monitor)\n        {\n            this.Add(monitor);\n        }\n\n        /// <summary>\n        /// If any monitor in this aggregated cache monitor group is under pressure, then return true\n        /// </summary>\n        /// <param name=\"utcNow\"></param>\n        /// <returns></returns>\n        public bool IsUnderPressure(DateTime utcNow)\n        {\n            bool underPressure = this.Exists(monitor => monitor.IsUnderPressure(utcNow));\n            if (this.isUnderPressure != underPressure)\n            {\n                this.isUnderPressure = underPressure;\n                this.CacheMonitor?.TrackCachePressureMonitorStatusChange(this.GetType().Name, this.isUnderPressure, null, null, null);\n                if (this.isUnderPressure)\n                {\n                    LogInfoIngestingMessagesTooFast();\n                }\n                else\n                {\n                    LogInfoMessageIngestionIsHealthy();\n                }\n            }\n            return underPressure;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Ingesting messages too fast. Throttling message reading.\"\n        )]\n        private partial void LogInfoIngestingMessagesTooFast();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Message ingestion is healthy.\"\n        )]\n        private partial void LogInfoMessageIngestionIsHealthy();\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/CachePressureMonitors/AveragingCachePressureMonitor.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Configuration;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Cache pressure monitor whose back pressure algorithm is based on averaging pressure value\n    /// over all pressure contribution\n    /// </summary>\n    public partial class AveragingCachePressureMonitor : ICachePressureMonitor\n    {\n        /// <summary>\n        /// Cache monitor which is used to report cache related metrics\n        /// </summary>\n        public ICacheMonitor CacheMonitor { set; private get; }\n        private static readonly TimeSpan checkPeriod = TimeSpan.FromSeconds(2);\n        private readonly ILogger logger;\n\n        private double accumulatedCachePressure;\n        private double cachePressureContributionCount;\n        private DateTime nextCheckedTime;\n        private bool isUnderPressure;\n        private readonly double flowControlThreshold;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public AveragingCachePressureMonitor(ILogger logger, ICacheMonitor monitor=null)\n            :this(EventHubStreamCachePressureOptions.DEFAULT_AVERAGING_CACHE_PRESSURE_MONITORING_THRESHOLD, logger, monitor)\n        { }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"flowControlThreshold\"></param>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public AveragingCachePressureMonitor(double flowControlThreshold, ILogger logger, ICacheMonitor monitor=null)\n        {\n            this.flowControlThreshold = flowControlThreshold;\n            this.logger = logger;\n            nextCheckedTime = DateTime.MinValue;\n            isUnderPressure = false;\n            this.CacheMonitor = monitor;\n        }\n\n        /// <inheritdoc />\n        public void RecordCachePressureContribution(double cachePressureContribution)\n        {\n            // Weight unhealthy contributions thrice as much as healthy ones.\n            // This is a crude compensation for the fact that healthy consumers wil consume more often than unhealthy ones.\n            double weight = cachePressureContribution < flowControlThreshold ? 1.0 : 3.0;\n            accumulatedCachePressure += cachePressureContribution * weight;\n            cachePressureContributionCount += weight;\n        }\n\n        /// <inheritdoc />\n        public bool IsUnderPressure(DateTime utcNow)\n        {\n            if (nextCheckedTime < utcNow)\n            {\n                CalculatePressure();\n                nextCheckedTime = utcNow + checkPeriod;\n            }\n            return isUnderPressure;\n        }\n\n        private void CalculatePressure()\n        {\n            // if we don't have any contributions, don't change status\n            if (cachePressureContributionCount < 0.5)\n            {\n                // after 5 checks with no contributions, check anyway\n                cachePressureContributionCount += 0.1;\n                return;\n            }\n\n            double pressure = accumulatedCachePressure / cachePressureContributionCount;\n            bool wasUnderPressure = isUnderPressure;\n            isUnderPressure = pressure > flowControlThreshold;\n            // If we changed state, log\n            if (isUnderPressure != wasUnderPressure)\n            {\n                this.CacheMonitor?.TrackCachePressureMonitorStatusChange(this.GetType().Name, isUnderPressure, cachePressureContributionCount, pressure, this.flowControlThreshold);\n                if (isUnderPressure)\n                {\n                    LogDebugIngestingMessagesTooFast(accumulatedCachePressure, cachePressureContributionCount, pressure, flowControlThreshold);\n                }\n                else\n                {\n                    LogDebugMessageIngestionIsHealthy(accumulatedCachePressure, cachePressureContributionCount, pressure, flowControlThreshold);\n                }\n            }\n            cachePressureContributionCount = 0.0;\n            accumulatedCachePressure = 0.0;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Ingesting messages too fast. Throttling message reading. AccumulatedCachePressure: {AccumulatedCachePressure}, Contributions: {Contributions}, AverageCachePressure: {AverageCachePressure}, Threshold: {FlowControlThreshold}\"\n        )]\n        private partial void LogDebugIngestingMessagesTooFast(double accumulatedCachePressure, double contributions, double averageCachePressure, double flowControlThreshold);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Message ingestion is healthy. AccumulatedCachePressure: {AccumulatedCachePressure}, Contributions: {Contributions}, AverageCachePressure: {AverageCachePressure}, Threshold: {FlowControlThreshold}\"\n        )]\n        private partial void LogDebugMessageIngestionIsHealthy(double accumulatedCachePressure, double contributions, double averageCachePressure, double flowControlThreshold);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/CachePressureMonitors/ICachePressureMonitor.cs",
    "content": "﻿using Orleans.Providers.Streams.Common;\nusing System;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Cache pressure monitor records pressure contribution to the cache, and determine if the cache is under pressure based on its \n    /// back pressure algorithm\n    /// </summary>\n    public interface ICachePressureMonitor\n    {\n        /// <summary>\n        /// Record cache pressure contribution to the monitor\n        /// </summary>\n        /// <param name=\"cachePressureContribution\"></param>\n        void RecordCachePressureContribution(double cachePressureContribution);\n\n        /// <summary>\n        /// Determine if the monitor is under pressure\n        /// </summary>\n        /// <param name=\"utcNow\"></param>\n        /// <returns></returns>\n        bool IsUnderPressure(DateTime utcNow);\n\n        /// <summary>\n        /// Cache monitor which is used to report cache related metrics\n        /// </summary>\n        ICacheMonitor CacheMonitor { set; }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/CachePressureMonitors/SlowConsumingPressureMonitor.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Pressure monitor which is in favor of the slow consumer in the cache\n    /// </summary>\n    public partial class SlowConsumingPressureMonitor : ICachePressureMonitor\n    {\n        /// <summary>\n        /// DefaultPressureWindowSize\n        /// </summary>\n        public static TimeSpan DefaultPressureWindowSize = TimeSpan.FromMinutes(1);\n        /// <summary>\n        /// Cache monitor which is used to report cache related metrics\n        /// </summary>\n        public ICacheMonitor CacheMonitor { set; private get; }\n        /// <summary>\n        /// Default flow control threshold\n        /// </summary>\n        public const double DefaultFlowControlThreshold = 0.5;\n\n        /// <summary>\n        /// PressureWindowSize\n        /// </summary>\n        public TimeSpan PressureWindowSize { get; set; }\n        /// <summary>\n        /// FlowControlThreshold\n        /// </summary>\n        public double FlowControlThreshold { get; set; }\n\n        private readonly ILogger logger;\n        private double biggestPressureInCurrentWindow;\n        private DateTime nextCheckedTime;\n        private bool wasUnderPressure;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public SlowConsumingPressureMonitor(ILogger logger, ICacheMonitor monitor = null)\n            : this(DefaultFlowControlThreshold, DefaultPressureWindowSize, logger, monitor)\n        { }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"pressureWindowSize\"></param>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public SlowConsumingPressureMonitor(TimeSpan pressureWindowSize, ILogger logger, ICacheMonitor monitor = null)\n            : this(DefaultFlowControlThreshold, pressureWindowSize, logger, monitor)\n        {\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"flowControlThreshold\"></param>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public SlowConsumingPressureMonitor(double flowControlThreshold, ILogger logger, ICacheMonitor monitor = null)\n            : this(flowControlThreshold, DefaultPressureWindowSize, logger, monitor)\n        {\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"flowControlThreshold\"></param>\n        /// <param name=\"pressureWindowSzie\"></param>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"monitor\"></param>\n        public SlowConsumingPressureMonitor(double flowControlThreshold, TimeSpan pressureWindowSzie, ILogger logger, ICacheMonitor monitor = null)\n        {\n            this.FlowControlThreshold = flowControlThreshold;\n            this.logger = logger;\n            this.nextCheckedTime = DateTime.MinValue;\n            this.biggestPressureInCurrentWindow = 0;\n            this.wasUnderPressure = false;\n            this.CacheMonitor = monitor;\n            this.PressureWindowSize = pressureWindowSzie;\n        }\n\n        /// <inheritdoc />\n        public void RecordCachePressureContribution(double cachePressureContribution)\n        {\n            if (cachePressureContribution > this.biggestPressureInCurrentWindow)\n                biggestPressureInCurrentWindow = cachePressureContribution;\n        }\n\n        /// <inheritdoc />\n        public bool IsUnderPressure(DateTime utcNow)\n        {\n            //if any pressure contribution in current period is bigger than flowControlThreshold\n            //we see the cache is under pressure\n            bool underPressure = this.biggestPressureInCurrentWindow > this.FlowControlThreshold;\n\n            if (underPressure && !this.wasUnderPressure)\n            {\n                //if under pressure, extend the nextCheckedTime, make sure wasUnderPressure is true for a whole window\n                this.wasUnderPressure = underPressure;\n                this.nextCheckedTime = utcNow + this.PressureWindowSize;\n                this.CacheMonitor?.TrackCachePressureMonitorStatusChange(this.GetType().Name, underPressure, null, biggestPressureInCurrentWindow, this.FlowControlThreshold);\n                LogDebugIngestingMessagesTooFast(biggestPressureInCurrentWindow, FlowControlThreshold);\n                this.biggestPressureInCurrentWindow = 0;\n            }\n\n            if (this.nextCheckedTime < utcNow)\n            {\n                //at the end of each check period, reset biggestPressureInCurrentPeriod\n                this.nextCheckedTime = utcNow + this.PressureWindowSize;\n                this.biggestPressureInCurrentWindow = 0;\n                //if at the end of the window, pressure clears out, log\n                if (this.wasUnderPressure && !underPressure)\n                {\n                    this.CacheMonitor?.TrackCachePressureMonitorStatusChange(this.GetType().Name, underPressure, null, biggestPressureInCurrentWindow, this.FlowControlThreshold);\n                    LogDebugMessageIngestionIsHealthy(biggestPressureInCurrentWindow, FlowControlThreshold);\n                }\n                this.wasUnderPressure = underPressure;\n            }\n\n            return this.wasUnderPressure;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Ingesting messages too fast. Throttling message reading. BiggestPressureInCurrentPeriod: {BiggestPressureInCurrentWindow}, Threshold: {FlowControlThreshold}\"\n        )]\n        private partial void LogDebugIngestingMessagesTooFast(double biggestPressureInCurrentWindow, double flowControlThreshold);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Message ingestion is healthy. BiggestPressureInCurrentPeriod: {BiggestPressureInCurrentWindow}, Threshold: {FlowControlThreshold}\"\n        )]\n        private partial void LogDebugMessageIngestionIsHealthy(double biggestPressureInCurrentWindow, double flowControlThreshold);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventDataExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Azure.Messaging.EventHubs;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Extends EventData to support streaming\n    /// </summary>\n    public static class EventDataExtensions\n    {\n        private const string EventDataPropertyStreamNamespaceKey = \"StreamNamespace\";\n\n        /// <summary>\n        /// Adds stream namespace to the EventData\n        /// </summary>\n        /// <param name=\"eventData\"></param>\n        /// <param name=\"streamNamespace\"></param>\n        public static void SetStreamNamespaceProperty(this EventData eventData, string streamNamespace)\n        {\n            eventData.Properties[EventDataPropertyStreamNamespaceKey] = streamNamespace;\n        }\n\n        /// <summary>\n        /// Gets stream namespace from the EventData\n        /// </summary>\n        /// <param name=\"eventData\"></param>\n        /// <returns></returns>\n        public static string GetStreamNamespaceProperty(this EventData eventData)\n        {\n            object namespaceObj;\n            if (eventData.Properties.TryGetValue(EventDataPropertyStreamNamespaceKey, out namespaceObj))\n            {\n                return (string)namespaceObj;\n            }\n            return null;\n        }\n\n        /// <summary>\n        /// Serializes event data properties\n        /// </summary>\n        public static byte[] SerializeProperties(this EventData eventData, Serialization.Serializer serializer)\n        {\n            var result = serializer.SerializeToArray(eventData.Properties.Where(kvp => !string.Equals(kvp.Key, EventDataPropertyStreamNamespaceKey, StringComparison.Ordinal)).ToList());\n            return result;\n        }\n\n        /// <summary>\n        /// Deserializes event data properties\n        /// </summary>\n        public static IDictionary<string, object> DeserializeProperties(this ArraySegment<byte> bytes, Serialization.Serializer serializer)\n        {\n            return serializer.Deserialize<List<KeyValuePair<string, object>>>(bytes.AsSpan()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventDataGeneratorStreamConfigurator.cs",
    "content": "\nusing System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streaming.EventHubs.Testing;\n\nnamespace Orleans.Hosting.Developer\n{\n    public interface IEventDataGeneratorStreamConfigurator : ISiloRecoverableStreamConfigurator { }\n\n    public static class EventDataGeneratorConfiguratorExtensions\n    {\n        public static void UseDataAdapter(this IEventDataGeneratorStreamConfigurator configurator, Func<IServiceProvider, string, IEventHubDataAdapter> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n\n        public static void ConfigureCachePressuring(this IEventDataGeneratorStreamConfigurator configurator, Action<OptionsBuilder<EventHubStreamCachePressureOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n    }\n    \n    public class EventDataGeneratorStreamConfigurator : SiloRecoverableStreamConfigurator, IEventDataGeneratorStreamConfigurator\n    {\n        public EventDataGeneratorStreamConfigurator(string name,\n            Action<Action<IServiceCollection>> configureServicesDelegate)\n            : base(name, configureServicesDelegate, EventDataGeneratorAdapterFactory.Create)\n        {\n            this.ConfigureDelegate(services => services.ConfigureNamedOptionForLogging<EventHubOptions>(name)\n                .ConfigureNamedOptionForLogging<EventHubReceiverOptions>(name)\n                .ConfigureNamedOptionForLogging<EventHubStreamCachePressureOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new EventHubOptionsValidator(sp.GetOptionsByName<EventHubOptions>(name), name))\n                .AddTransient<IConfigurationValidator>(sp => new StreamCheckpointerConfigurationValidator(sp, name)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubAdapterFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Azure.Messaging.EventHubs;\nusing Azure.Messaging.EventHubs.Producer;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Statistics;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Queue adapter factory which allows the PersistentStreamProvider to use EventHub as its backend persistent event queue.\n    /// </summary>\n    public class EventHubAdapterFactory : IQueueAdapterFactory, IQueueAdapter, IQueueAdapterCache\n    {\n        private readonly ILoggerFactory loggerFactory;\n        private readonly IEnvironmentStatisticsProvider environmentStatisticsProvider;\n\n        /// <summary>\n        /// Data adapter\n        /// </summary>\n        protected readonly IEventHubDataAdapter dataAdapter;\n\n        /// <summary>\n        /// Orleans logging\n        /// </summary>\n        protected ILogger logger;\n\n        /// <summary>\n        /// Framework service provider\n        /// </summary>\n        protected readonly IServiceProvider serviceProvider;\n\n        /// <summary>\n        /// Stream provider settings\n        /// </summary>\n        private readonly EventHubOptions ehOptions;\n        private readonly EventHubStreamCachePressureOptions cacheOptions;\n        private readonly EventHubReceiverOptions receiverOptions;\n        private readonly StreamStatisticOptions statisticOptions;\n        private readonly StreamCacheEvictionOptions cacheEvictionOptions;\n        private HashRingBasedPartitionedStreamQueueMapper streamQueueMapper;\n        private string[] partitionIds;\n        private ConcurrentDictionary<QueueId, EventHubAdapterReceiver> receivers;\n        private EventHubProducerClient client;\n\n        /// <summary>\n        /// Name of the adapter. Primarily for logging purposes\n        /// </summary>\n        public string Name { get; }\n\n        /// <summary>\n        /// Determines whether this is a rewindable stream adapter - supports subscribing from previous point in time.\n        /// </summary>\n        /// <returns>True if this is a rewindable stream adapter, false otherwise.</returns>\n        public bool IsRewindable => true;\n\n        /// <summary>\n        /// Direction of this queue adapter: Read, Write or ReadWrite.\n        /// </summary>\n        /// <returns>The direction in which this adapter provides data.</returns>\n        public StreamProviderDirection Direction { get; protected set; } = StreamProviderDirection.ReadWrite;\n\n        /// <summary>\n        /// Creates a message cache for an eventhub partition.\n        /// </summary>\n        protected Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> CacheFactory { get; set; }\n\n        /// <summary>\n        /// Creates a partition checkpointer.\n        /// </summary>\n        private IStreamQueueCheckpointerFactory checkpointerFactory;\n\n        /// <summary>\n        /// Creates a failure handler for a partition.\n        /// </summary>\n        protected Func<string, Task<IStreamFailureHandler>> StreamFailureHandlerFactory { get; set; }\n\n        /// <summary>\n        /// Create a queue mapper to map EventHub partitions to queues\n        /// </summary>\n        protected Func<string[], HashRingBasedPartitionedStreamQueueMapper> QueueMapperFactory { get; set; }\n\n        /// <summary>\n        /// Create a receiver monitor to report performance metrics.\n        /// Factory function should return an IEventHubReceiverMonitor.\n        /// </summary>\n        protected Func<EventHubReceiverMonitorDimensions, ILoggerFactory, IQueueAdapterReceiverMonitor> ReceiverMonitorFactory { get; set; }\n\n        //for testing purpose, used in EventHubGeneratorStreamProvider\n        /// <summary>\n        /// Factory to create a IEventHubReceiver\n        /// </summary>\n        protected Func<EventHubPartitionSettings, string, ILogger, IEventHubReceiver> EventHubReceiverFactory;\n        internal ConcurrentDictionary<QueueId, EventHubAdapterReceiver> EventHubReceivers => receivers;\n        internal HashRingBasedPartitionedStreamQueueMapper EventHubQueueMapper => streamQueueMapper;\n\n        public EventHubAdapterFactory(\n            string name,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions, \n            StreamCacheEvictionOptions cacheEvictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdapter,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n        {\n            this.Name = name;\n            this.cacheEvictionOptions = cacheEvictionOptions ?? throw new ArgumentNullException(nameof(cacheEvictionOptions));\n            this.statisticOptions = statisticOptions ?? throw new ArgumentNullException(nameof(statisticOptions));\n            this.ehOptions = ehOptions ?? throw new ArgumentNullException(nameof(ehOptions));\n            this.cacheOptions = cacheOptions?? throw new ArgumentNullException(nameof(cacheOptions));\n            this.dataAdapter = dataAdapter ?? throw new ArgumentNullException(nameof(dataAdapter));\n            this.receiverOptions = receiverOptions?? throw new ArgumentNullException(nameof(receiverOptions));\n            this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.environmentStatisticsProvider = environmentStatisticsProvider;\n        }\n\n        public virtual void Init()\n        {\n            this.receivers = new ConcurrentDictionary<QueueId, EventHubAdapterReceiver>();\n\n            InitEventHubClient();\n\n            if (this.CacheFactory == null)\n            {\n                this.CacheFactory = CreateCacheFactory(this.cacheOptions).CreateCache;\n            }\n\n            if (this.StreamFailureHandlerFactory == null)\n            {\n                //TODO: Add a queue specific default failure handler with reasonable error reporting.\n                this.StreamFailureHandlerFactory = partition => Task.FromResult<IStreamFailureHandler>(new NoOpStreamDeliveryFailureHandler());\n            }\n\n            if (this.QueueMapperFactory == null)\n            {\n                this.QueueMapperFactory = partitions => new(partitions, this.Name);\n            }\n\n            if (this.ReceiverMonitorFactory == null)\n            {\n                this.ReceiverMonitorFactory = (dimensions, logger) => new DefaultEventHubReceiverMonitor(dimensions);\n            }\n\n            this.logger = this.loggerFactory.CreateLogger($\"{this.GetType().FullName}.{this.ehOptions.EventHubName}\");\n        }\n\n        //should only need checkpointer on silo side, so move its init logic when it is used\n        private void InitCheckpointerFactory()\n        {\n            this.checkpointerFactory = this.serviceProvider.GetRequiredKeyedService<IStreamQueueCheckpointerFactory>(this.Name);\n        }\n        /// <summary>\n        /// Create queue adapter.\n        /// </summary>\n        /// <returns></returns>\n        public async Task<IQueueAdapter> CreateAdapter()\n        {\n            if (this.streamQueueMapper == null)\n            {\n                this.partitionIds = await GetPartitionIdsAsync();\n                this.streamQueueMapper = this.QueueMapperFactory(this.partitionIds);\n            }\n            return this;\n        }\n\n        /// <summary>\n        /// Create queue message cache adapter\n        /// </summary>\n        /// <returns></returns>\n        public IQueueAdapterCache GetQueueAdapterCache()\n        {\n            return this;\n        }\n\n        /// <summary>\n        /// Create queue mapper\n        /// </summary>\n        /// <returns></returns>\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            //TODO: CreateAdapter must be called first.  Figure out how to safely enforce this\n            return this.streamQueueMapper;\n        }\n\n        /// <summary>\n        /// Acquire delivery failure handler for a queue\n        /// </summary>\n        /// <param name=\"queueId\"></param>\n        /// <returns></returns>\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            return this.StreamFailureHandlerFactory(this.streamQueueMapper.QueueToPartition(queueId));\n        }\n\n        /// <summary>\n        /// Writes a set of events to the queue as a single batch associated with the provided streamId.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"events\"></param>\n        /// <param name=\"token\"></param>\n        /// <param name=\"requestContext\"></param>\n        /// <returns></returns>\n        public virtual Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token,\n            Dictionary<string, object> requestContext)\n        {\n            EventData eventData = this.dataAdapter.ToQueueMessage(streamId, events, token, requestContext);\n            string partitionKey = this.dataAdapter.GetPartitionKey(streamId);\n            return this.client.SendAsync(new[] { eventData }, new SendEventOptions { PartitionKey = partitionKey });\n        }\n\n        /// <summary>\n        /// Creates a queue receiver for the specified queueId\n        /// </summary>\n        /// <param name=\"queueId\"></param>\n        /// <returns></returns>\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n        {\n            return GetOrCreateReceiver(queueId);\n        }\n\n        /// <summary>\n        /// Create a cache for a given queue id\n        /// </summary>\n        /// <param name=\"queueId\"></param>\n        public IQueueCache CreateQueueCache(QueueId queueId)\n        {\n            return GetOrCreateReceiver(queueId);\n        }\n\n        private EventHubAdapterReceiver GetOrCreateReceiver(QueueId queueId)\n        {\n            return this.receivers.GetOrAdd(queueId, (q, instance) => instance.MakeReceiver(q), this);\n        }\n\n        protected virtual void InitEventHubClient()\n        {\n            var connectionOptions = ehOptions.ConnectionOptions;\n            var connection = ehOptions.CreateConnection(connectionOptions);\n            this.client = new EventHubProducerClient(connection, new EventHubProducerClientOptions { ConnectionOptions = connectionOptions });\n        }\n\n        /// <summary>\n        /// Create a IEventHubQueueCacheFactory. It will create a EventHubQueueCacheFactory by default.\n        /// User can override this function to return their own implementation of IEventHubQueueCacheFactory,\n        /// and other customization of IEventHubQueueCacheFactory if they may.\n        /// </summary>\n        /// <returns></returns>\n        protected virtual IEventHubQueueCacheFactory CreateCacheFactory(EventHubStreamCachePressureOptions eventHubCacheOptions)\n        {\n           var eventHubPath = this.ehOptions.EventHubName;\n            var sharedDimensions = new EventHubMonitorAggregationDimensions(eventHubPath);\n            return new EventHubQueueCacheFactory(eventHubCacheOptions, cacheEvictionOptions, statisticOptions, this.dataAdapter, sharedDimensions);\n        }\n\n        private EventHubAdapterReceiver MakeReceiver(QueueId queueId)\n        {\n            var config = new EventHubPartitionSettings\n            {\n                Hub = ehOptions,\n                Partition = this.streamQueueMapper.QueueToPartition(queueId),\n                ReceiverOptions = this.receiverOptions\n            };\n\n            var receiverMonitorDimensions = new EventHubReceiverMonitorDimensions\n            {\n                EventHubPartition = config.Partition,\n                EventHubPath = config.Hub.EventHubName,\n            };\n            if (this.checkpointerFactory == null)\n                InitCheckpointerFactory();\n            return new EventHubAdapterReceiver(\n                config,\n                this.CacheFactory,\n                this.checkpointerFactory.Create,\n                this.loggerFactory,\n                this.ReceiverMonitorFactory(receiverMonitorDimensions, this.loggerFactory),\n                this.serviceProvider.GetRequiredService<IOptions<LoadSheddingOptions>>().Value,\n                this.environmentStatisticsProvider,\n                this.EventHubReceiverFactory);\n        }\n\n        /// <summary>\n        /// Get partition Ids from eventhub\n        /// </summary>\n        /// <returns></returns>\n        protected virtual async Task<string[]> GetPartitionIdsAsync()\n        {\n            return await client.GetPartitionIdsAsync();\n        }\n\n        public static EventHubAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var ehOptions = services.GetOptionsByName<EventHubOptions>(name);\n            var receiverOptions = services.GetOptionsByName<EventHubReceiverOptions>(name);\n            var cacheOptions = services.GetOptionsByName<EventHubStreamCachePressureOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            var evictionOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            IEventHubDataAdapter dataAdapter = services.GetKeyedService<IEventHubDataAdapter>(name)\n                ?? services.GetService<IEventHubDataAdapter>()\n                ?? ActivatorUtilities.CreateInstance<EventHubDataAdapter>(services);\n            var factory = ActivatorUtilities.CreateInstance<EventHubAdapterFactory>(services, name, ehOptions, receiverOptions, cacheOptions, evictionOptions, statisticOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubAdapterReceiver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Azure.Messaging.EventHubs;\nusing Orleans.Statistics;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Event Hub Partition settings\n    /// </summary>\n    public class EventHubPartitionSettings\n    {\n        /// <summary>\n        /// Eventhub settings\n        /// </summary>\n        public EventHubOptions Hub { get; set; }\n\n        public EventHubReceiverOptions ReceiverOptions { get; set; }\n\n        /// <summary>\n        /// Partition name\n        /// </summary>\n        public string Partition { get; set; }\n    }\n\n    internal partial class EventHubAdapterReceiver : IQueueAdapterReceiver, IQueueCache\n    {\n        public const int MaxMessagesPerRead = 1000;\n        private static readonly TimeSpan ReceiveTimeout = TimeSpan.FromSeconds(5);\n\n        private readonly EventHubPartitionSettings settings;\n        private readonly Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> cacheFactory;\n        private readonly Func<string, Task<IStreamQueueCheckpointer<string>>> checkpointerFactory;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ILogger logger;\n        private readonly IQueueAdapterReceiverMonitor monitor;\n        private readonly LoadSheddingOptions loadSheddingOptions;\n        private readonly IEnvironmentStatisticsProvider environmentStatisticsProvider;\n        private IEventHubQueueCache cache;\n\n        private IEventHubReceiver receiver;\n\n        private readonly Func<EventHubPartitionSettings, string, ILogger, IEventHubReceiver> eventHubReceiverFactory;\n\n        private IStreamQueueCheckpointer<string> checkpointer;\n        private AggregatedQueueFlowController flowController;\n\n        // Receiver life cycle\n        private int receiverState = ReceiverShutdown;\n\n        private const int ReceiverShutdown = 0;\n        private const int ReceiverRunning = 1;\n\n        public int GetMaxAddCount()\n        {\n            return this.flowController.GetMaxAddCount();\n        }\n\n        public EventHubAdapterReceiver(EventHubPartitionSettings settings,\n            Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> cacheFactory,\n            Func<string, Task<IStreamQueueCheckpointer<string>>> checkpointerFactory,\n            ILoggerFactory loggerFactory,\n            IQueueAdapterReceiverMonitor monitor,\n            LoadSheddingOptions loadSheddingOptions,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider,\n            Func<EventHubPartitionSettings, string, ILogger, IEventHubReceiver> eventHubReceiverFactory = null)\n        {\n            this.settings = settings ?? throw new ArgumentNullException(nameof(settings));\n            this.cacheFactory = cacheFactory ?? throw new ArgumentNullException(nameof(cacheFactory));\n            this.checkpointerFactory = checkpointerFactory ?? throw new ArgumentNullException(nameof(checkpointerFactory));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.logger = this.loggerFactory.CreateLogger<EventHubAdapterReceiver>();\n            this.monitor = monitor ?? throw new ArgumentNullException(nameof(monitor));\n            this.loadSheddingOptions = loadSheddingOptions ?? throw new ArgumentNullException(nameof(loadSheddingOptions));\n            this.environmentStatisticsProvider = environmentStatisticsProvider;\n            this.eventHubReceiverFactory = eventHubReceiverFactory == null ? EventHubAdapterReceiver.CreateReceiver : eventHubReceiverFactory;\n        }\n\n        public Task Initialize(TimeSpan timeout)\n        {\n            LogInfoInitializingEventHubPartition(this.settings.Hub.EventHubName, this.settings.Partition);\n\n            // if receiver was already running, do nothing\n            return ReceiverRunning == Interlocked.Exchange(ref this.receiverState, ReceiverRunning)\n                ? Task.CompletedTask\n                : Initialize();\n        }\n\n        /// <summary>\n        /// Initialization of EventHub receiver is performed at adapter receiver initialization, but if it fails,\n        ///  it will be retried when messages are requested\n        /// </summary>\n        /// <returns></returns>\n        private async Task Initialize()\n        {\n            var watch = Stopwatch.StartNew();\n            try\n            {\n                this.checkpointer = await this.checkpointerFactory(this.settings.Partition);\n                if(this.cache != null)\n                {\n                    this.cache.Dispose();\n                    this.cache = null;\n                }\n                this.cache = this.cacheFactory(this.settings.Partition, this.checkpointer, this.loggerFactory);\n                this.flowController = new AggregatedQueueFlowController(MaxMessagesPerRead) { this.cache, LoadShedQueueFlowController.CreateAsPercentOfLoadSheddingLimit(this.loadSheddingOptions, environmentStatisticsProvider) };\n                string offset = await this.checkpointer.Load();\n                this.receiver = this.eventHubReceiverFactory(this.settings, offset, this.logger);\n                watch.Stop();\n                this.monitor?.TrackInitialization(true, watch.Elapsed, null);\n            }\n            catch (Exception ex)\n            {\n                watch.Stop();\n                this.monitor?.TrackInitialization(false, watch.Elapsed, ex);\n                throw;\n            }\n        }\n\n        public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n        {\n            if (this.receiverState == ReceiverShutdown || maxCount <= 0)\n            {\n                return new List<IBatchContainer>();\n            }\n\n            // if receiver initialization failed, retry\n            if (this.receiver == null)\n            {\n                LogWarningRetryingInitializationOfEventHubPartition(this.settings.Hub.EventHubName, this.settings.Partition);\n                await Initialize();\n                if (this.receiver == null)\n                {\n                    // should not get here, should throw instead, but just incase.\n                    return new List<IBatchContainer>();\n                }\n            }\n            var watch = Stopwatch.StartNew();\n            List<EventData> messages;\n            try\n            {\n\n                messages = (await this.receiver.ReceiveAsync(maxCount, ReceiveTimeout))?.ToList();\n                watch.Stop();\n\n                this.monitor?.TrackRead(true, watch.Elapsed, null);\n            }\n            catch (Exception ex)\n            {\n                watch.Stop();\n                this.monitor?.TrackRead(false, watch.Elapsed, ex);\n                LogWarningFailedToReadFromEventHubPartition(this.settings.Hub.EventHubName, this.settings.Partition, ex);\n                throw;\n            }\n\n            var batches = new List<IBatchContainer>();\n            if (messages == null || messages.Count == 0)\n            {\n                this.monitor?.TrackMessagesReceived(0, null, null);\n                return batches;\n            }\n\n            // monitor message age\n            var dequeueTimeUtc = DateTime.UtcNow;\n\n            DateTime oldestMessageEnqueueTime = messages[0].EnqueuedTime.UtcDateTime;\n            DateTime newestMessageEnqueueTime = messages[messages.Count - 1].EnqueuedTime.UtcDateTime;\n\n            this.monitor?.TrackMessagesReceived(messages.Count, oldestMessageEnqueueTime, newestMessageEnqueueTime);\n\n            List<StreamPosition> messageStreamPositions = this.cache.Add(messages, dequeueTimeUtc);\n            foreach (var streamPosition in messageStreamPositions)\n            {\n                batches.Add(new StreamActivityNotificationBatch(streamPosition));\n            }\n            if (!this.checkpointer.CheckpointExists)\n            {\n                this.checkpointer.Update(\n                    messages[0].OffsetString,\n                    DateTime.UtcNow);\n            }\n            return batches;\n        }\n\n        public void AddToCache(IList<IBatchContainer> messages)\n        {\n            // do nothing, we add data directly into cache.  No need for agent involvement\n        }\n\n        public bool TryPurgeFromCache(out IList<IBatchContainer> purgedItems)\n        {\n            purgedItems = null;\n\n            //if not under pressure, signal the cache to do a time based purge\n            //if under pressure, which means consuming speed is less than producing speed, then shouldn't purge, and don't read more message into the cache\n            if (!this.IsUnderPressure())\n                this.cache.SignalPurge();\n            return false;\n        }\n\n        public IQueueCacheCursor GetCacheCursor(StreamId streamId, StreamSequenceToken token)\n        {\n            return new Cursor(this.cache, streamId, token);\n        }\n\n        public bool IsUnderPressure()\n        {\n            return this.GetMaxAddCount() <= 0;\n        }\n\n        public Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task Shutdown(TimeSpan timeout)\n        {\n            var watch = Stopwatch.StartNew();\n            try\n            {\n                // if receiver was already shutdown, do nothing\n                if (ReceiverShutdown == Interlocked.Exchange(ref this.receiverState, ReceiverShutdown))\n                {\n                    return;\n                }\n\n                LogInfoStoppingReadingFromEventHubPartition(this.settings.Hub.EventHubName, this.settings.Partition);\n\n                // clear cache and receiver\n                IEventHubQueueCache localCache = Interlocked.Exchange(ref this.cache, null);\n\n                var localReceiver = Interlocked.Exchange(ref this.receiver, null);\n\n                // start closing receiver\n                Task closeTask = Task.CompletedTask;\n                if (localReceiver != null)\n                {\n                    closeTask = localReceiver.CloseAsync();\n                }\n                // dispose of cache\n                localCache?.Dispose();\n\n                // finish return receiver closing task\n                await closeTask;\n                watch.Stop();\n                this.monitor?.TrackShutdown(true, watch.Elapsed, null);\n            }\n            catch (Exception ex)\n            {\n                watch.Stop();\n                this.monitor?.TrackShutdown(false, watch.Elapsed, ex);\n                throw;\n            }\n        }\n\n        private static IEventHubReceiver CreateReceiver(EventHubPartitionSettings partitionSettings, string offset, ILogger logger)\n        {\n            return new EventHubReceiverProxy(partitionSettings, offset, logger);\n        }\n\n        /// <summary>\n        /// For test purpose. ConfigureDataGeneratorForStream will configure a data generator for the stream\n        /// </summary>\n        /// <param name=\"streamId\"></param>\n        internal void ConfigureDataGeneratorForStream(StreamId streamId)\n        {\n            (this.receiver as EventHubPartitionGeneratorReceiver)?.ConfigureDataGeneratorForStream(streamId);\n        }\n\n        internal void StopProducingOnStream(StreamId streamId)\n        {\n            (this.receiver as EventHubPartitionGeneratorReceiver)?.StopProducingOnStream(streamId);\n        }\n\n        [GenerateSerializer]\n        internal class StreamActivityNotificationBatch : IBatchContainer\n        {\n            [Id(0)]\n            public StreamPosition Position { get; }\n\n            public StreamId StreamId => this.Position.StreamId;\n            public StreamSequenceToken SequenceToken => this.Position.SequenceToken;\n\n            public StreamActivityNotificationBatch(StreamPosition position)\n            {\n                this.Position = position;\n            }\n\n            public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>() { throw new NotSupportedException(); }\n            public bool ImportRequestContext() { throw new NotSupportedException(); }\n        }\n\n        private class Cursor : IQueueCacheCursor\n        {\n            private readonly IEventHubQueueCache cache;\n            private readonly object cursor;\n            private IBatchContainer current;\n\n            public Cursor(IEventHubQueueCache cache, StreamId streamId, StreamSequenceToken token)\n            {\n                this.cache = cache;\n                this.cursor = cache.GetCursor(streamId, token);\n            }\n\n            public void Dispose()\n            {\n            }\n\n            public IBatchContainer GetCurrent(out Exception exception)\n            {\n                exception = null;\n                return this.current;\n            }\n\n            public bool MoveNext()\n            {\n                IBatchContainer next;\n                if (!this.cache.TryGetNextMessage(this.cursor, out next))\n                {\n                    return false;\n                }\n\n                this.current = next;\n                return true;\n            }\n\n            public void Refresh(StreamSequenceToken token)\n            {\n            }\n\n            public void RecordDeliveryFailure()\n            {\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Initializing EventHub partition {EventHubName}-{Partition}.\"\n        )]\n        private partial void LogInfoInitializingEventHubPartition(string eventHubName, string partition);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Stopping reading from EventHub partition {EventHubName}-{Partition}\"\n        )]\n        private partial void LogInfoStoppingReadingFromEventHubPartition(string eventHubName, string partition);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)OrleansEventHubErrorCode.FailedPartitionRead,\n            Message = \"Retrying initialization of EventHub partition {EventHubName}-{Partition}.\"\n        )]\n        private partial void LogWarningRetryingInitializationOfEventHubPartition(string eventHubName, string partition);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)OrleansEventHubErrorCode.FailedPartitionRead,\n            Message = \"Failed to read from EventHub partition {EventHubName}-{Partition}\"\n        )]\n        private partial void LogWarningFailedToReadFromEventHubPartition(string eventHubName, string partition, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubBatchContainer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Azure.Messaging.EventHubs;\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Batch container that is delivers payload and stream position information for a set of events in an EventHub EventData.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventHubBatchContainer : IBatchContainer\n    {\n        [JsonProperty]\n        [Id(0)]\n        private readonly EventHubMessage eventHubMessage;\n\n        [JsonIgnore]\n        [field: NonSerialized]\n        internal Serializer Serializer { get; set; }\n\n        [JsonProperty]\n        [Id(1)]\n        private readonly EventHubSequenceToken token;\n\n        /// <summary>\n        /// Stream identifier for the stream this batch is part of.\n        /// </summary>\n        public StreamId StreamId => eventHubMessage.StreamId;\n\n        /// <summary>\n        /// Stream Sequence Token for the start of this batch.\n        /// </summary>\n        public StreamSequenceToken SequenceToken => token;\n\n        // Payload is local cache of deserialized payloadBytes.  Should never be serialized as part of batch container.  During batch container serialization raw payloadBytes will always be used.\n        [NonSerialized]\n        private Body payload;\n\n        private Body GetPayload() => payload ?? (payload = this.Serializer.Deserialize<Body>(eventHubMessage.Payload));\n\n        [Serializable]\n        [GenerateSerializer]\n        internal class Body\n        {\n            [Id(0)]\n            public List<object> Events { get; set; }\n            [Id(1)]\n            public Dictionary<string, object> RequestContext { get; set; }\n        }\n\n        /// <summary>\n        /// Batch container that delivers events from cached EventHub data associated with an orleans stream\n        /// </summary>\n        public EventHubBatchContainer(EventHubMessage eventHubMessage, Serializer serializer)\n        {\n            this.eventHubMessage = eventHubMessage;\n            this.Serializer = serializer;\n            token = new EventHubSequenceTokenV2(eventHubMessage.Offset, eventHubMessage.SequenceNumber, 0);\n        }\n\n        [GeneratedActivatorConstructor]\n        internal EventHubBatchContainer(Serializer serializer)\n        {\n            this.Serializer = serializer;\n        }\n\n        /// <summary>\n        /// Gets events of a specific type from the batch.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return GetPayload().Events.Cast<T>().Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, new EventHubSequenceTokenV2(token.EventHubOffset, token.SequenceNumber, i)));\n        }\n\n        /// <summary>\n        /// Gives an opportunity to IBatchContainer to set any data in the RequestContext before this IBatchContainer is sent to consumers.\n        /// It can be the data that was set at the time event was generated and enqueued into the persistent provider or any other data.\n        /// </summary>\n        /// <returns>True if the RequestContext was indeed modified, false otherwise.</returns>\n        public bool ImportRequestContext()\n        {\n            if (GetPayload().RequestContext != null)\n            {\n                RequestContextExtensions.Import(GetPayload().RequestContext);\n                return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Put events list and its context into a EventData object\n        /// </summary>\n        public static EventData ToEventData<T>(Serializer bodySerializer, StreamId streamId, IEnumerable<T> events, Dictionary<string, object> requestContext)\n        {\n            var eventData = new EventData();\n\n            UpdateEventData(eventData, bodySerializer, streamId, events.Cast<object>().ToList(), requestContext);\n            return eventData;\n        }\n\n        /// <summary>\n        /// Updates the event data with the events list and its context.\n        /// </summary>\n        /// <param name=\"eventData\">The <see cref=\"EventData\"/> instance to update with a new body and context.</param>\n        /// <param name=\"bodySerializer\">The serializer to use for creating the event body payload.</param>\n        /// <param name=\"streamId\">The stream identifier to associate with the event context.</param>\n        /// <param name=\"events\">The events list to use for the payload.</param>\n        /// <param name=\"requestContext\">The request context to associate with the event.</param>\n        public static void UpdateEventData<T>(EventData eventData, Serializer bodySerializer, StreamId streamId, IEnumerable<T> events, Dictionary<string, object> requestContext)\n        {\n            eventData.EventBody = CreateEventDataBody(bodySerializer, events, requestContext);\n            eventData.SetStreamNamespaceProperty(streamId.GetNamespace());\n        }\n\n        private static BinaryData CreateEventDataBody<T>(Serializer bodySerializer, IEnumerable<T> events, Dictionary<string, object> requestContext)\n        {\n            var payload = new Body\n            {\n                Events = events.Cast<object>().ToList(),\n                RequestContext = requestContext\n            };\n\n            var bytes = bodySerializer.SerializeToArray(payload);\n            return new BinaryData(bytes);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubCheckpointer.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration.Overrides;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    public class EventHubCheckpointerFactory : IStreamQueueCheckpointerFactory\n    {\n        private readonly ILoggerFactory loggerFactory;\n        private readonly string providerName;\n        private readonly AzureTableStreamCheckpointerOptions options;\n        private readonly ClusterOptions clusterOptions;\n\n        public EventHubCheckpointerFactory(string providerName, AzureTableStreamCheckpointerOptions options, IOptions<ClusterOptions> clusterOptions, ILoggerFactory loggerFactory)\n        {\n            this.options = options;\n            this.clusterOptions = clusterOptions.Value;\n            this.loggerFactory = loggerFactory;\n            this.providerName = providerName;\n        }\n\n        public Task<IStreamQueueCheckpointer<string>> Create(string partition)\n        {\n            return EventHubCheckpointer.Create(options, providerName, partition, this.clusterOptions.ServiceId.ToString(), loggerFactory);\n        }\n\n        public static IStreamQueueCheckpointerFactory CreateFactory(IServiceProvider services, string providerName)\n        {\n            var options = services.GetOptionsByName<AzureTableStreamCheckpointerOptions>(providerName);\n            IOptions<ClusterOptions> clusterOptions = services.GetProviderClusterOptions(providerName);\n            return ActivatorUtilities.CreateInstance<EventHubCheckpointerFactory>(services, providerName, options, clusterOptions);\n        }\n    }\n\n    /// <summary>\n    /// This class stores EventHub partition checkpointer information (a partition offset) in azure table storage.\n    /// </summary>\n    public partial class EventHubCheckpointer : IStreamQueueCheckpointer<string>\n    {\n        private readonly AzureTableDataManager<EventHubPartitionCheckpointEntity> dataManager;\n        private readonly TimeSpan persistInterval;\n        private readonly ILogger logger;\n\n        private EventHubPartitionCheckpointEntity entity;\n        private Task inProgressSave;\n        private DateTime? throttleSavesUntilUtc;\n\n        /// <summary>\n        /// Indicates if a checkpoint exists\n        /// </summary>\n        public bool CheckpointExists => entity != null && entity.Offset != EventHubConstants.StartOfStream;\n\n        /// <summary>\n        /// Factory function that creates and initializes the checkpointer\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <param name=\"streamProviderName\"></param>\n        /// <param name=\"partition\"></param>\n        /// <param name=\"serviceId\"></param>\n        /// <param name=\"loggerFactory\"></param>\n        /// <returns></returns>\n        public static async Task<IStreamQueueCheckpointer<string>> Create(AzureTableStreamCheckpointerOptions options, string streamProviderName, string partition, string serviceId, ILoggerFactory loggerFactory)\n        {\n            var checkpointer = new EventHubCheckpointer(options, streamProviderName, partition, serviceId, loggerFactory);\n            await checkpointer.Initialize();\n            return checkpointer;\n        }\n\n        private EventHubCheckpointer(AzureTableStreamCheckpointerOptions options, string streamProviderName, string partition, string serviceId, ILoggerFactory loggerFactory)\n        {\n            if (options == null)\n            {\n                throw new ArgumentNullException(nameof(options));\n            }\n            if (string.IsNullOrWhiteSpace(streamProviderName))\n            {\n                throw new ArgumentNullException(nameof(streamProviderName));\n            }\n            if (string.IsNullOrWhiteSpace(partition))\n            {\n                throw new ArgumentNullException(nameof(partition));\n            }\n            this.logger = loggerFactory.CreateLogger<EventHubCheckpointer>();\n            LogCreatingEventHubCheckpointer(partition, streamProviderName, serviceId);\n            persistInterval = options.PersistInterval;\n            dataManager = new AzureTableDataManager<EventHubPartitionCheckpointEntity>(\n                options,\n                loggerFactory.CreateLogger<EventHubPartitionCheckpointEntity>());\n            entity = EventHubPartitionCheckpointEntity.Create(streamProviderName, serviceId, partition);\n        }\n\n        private Task Initialize()\n        {\n            return dataManager.InitTableAsync();\n        }\n\n        /// <summary>\n        /// Loads a checkpoint\n        /// </summary>\n        /// <returns></returns>\n        public async Task<string> Load()\n        {\n            var results = await dataManager.ReadSingleTableEntryAsync(entity.PartitionKey, entity.RowKey);\n            if (results.Entity != null)\n            {\n                entity = results.Entity;\n            }\n\n            return entity.Offset;\n        }\n\n        /// <summary>\n        /// Updates the checkpoint.  This is a best effort.  It does not always update the checkpoint.\n        /// </summary>\n        /// <param name=\"offset\"></param>\n        /// <param name=\"utcNow\"></param>\n        public void Update(string offset, DateTime utcNow)\n        {\n            // if offset has not changed, do nothing\n            if (string.Compare(entity.Offset, offset, StringComparison.Ordinal) == 0)\n            {\n                return;\n            }\n\n            // if we've saved before but it's not time for another save or the last save operation has not completed, do nothing\n            if (throttleSavesUntilUtc.HasValue && (throttleSavesUntilUtc.Value > utcNow || !inProgressSave.IsCompleted))\n            {\n                return;\n            }\n\n            entity.Offset = offset;\n            throttleSavesUntilUtc = utcNow + persistInterval;\n            inProgressSave = dataManager.UpsertTableEntryAsync(entity);\n            inProgressSave.Ignore();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Creating EventHub checkpointer for partition {Partition} of stream provider {StreamProviderName} with serviceId {ServiceId}.\"\n        )]\n        private partial void LogCreatingEventHubCheckpointer(string partition, string streamProviderName, string serviceId);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubCheckpointerOptions.cs",
    "content": "using Orleans.Streaming.EventHubs;\nusing System;\n\nnamespace Orleans.Configuration\n{\n    public class AzureTableStreamCheckpointerOptions : AzureStorageOperationOptions\n    {\n        /// <summary>\n        /// Azure table name.\n        /// </summary>\n        public override string TableName { get; set; } = DEFAULT_TABLE_NAME;\n        public const string DEFAULT_TABLE_NAME = \"Checkpoint\";\n\n        /// <summary>\n        /// Interval to write checkpoints.  Prevents spamming storage.\n        /// </summary>\n        public TimeSpan PersistInterval { get; set; } = DEFAULT_CHECKPOINT_PERSIST_INTERVAL;\n        public static readonly TimeSpan DEFAULT_CHECKPOINT_PERSIST_INTERVAL = TimeSpan.FromMinutes(1);\n    }\n\n    //TOOD: how to wire this validator into DI?\n    public class AzureTableStreamCheckpointerOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableStreamCheckpointerOptions>\n    {\n        public AzureTableStreamCheckpointerOptionsValidator(AzureTableStreamCheckpointerOptions options, string name) : base(options, name)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubConstants.cs",
    "content": "namespace Orleans.Streaming.EventHubs\n{\n    internal class EventHubConstants\n    {\n        public const string StartOfStream = \"-1\";\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubDataAdapter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Azure.Messaging.EventHubs;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Default event hub data adapter.  Users may subclass to override event data to stream mapping.\n    /// </summary>\n    public class EventHubDataAdapter : IEventHubDataAdapter\n    {\n        private readonly Serialization.Serializer serializer;\n\n        /// <summary>\n        /// Cache data adapter that adapts EventHub's EventData to CachedEventHubMessage used in cache\n        /// </summary>\n        public EventHubDataAdapter(Serialization.Serializer serializer)\n        {\n            this.serializer = serializer;\n        }\n\n        /// <summary>\n        /// Converts a cached message to a batch container for delivery\n        /// </summary>\n        /// <param name=\"cachedMessage\"></param>\n        /// <returns></returns>\n        public virtual IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage)\n        {\n            var evenHubMessage = new EventHubMessage(cachedMessage, this.serializer);\n            return GetBatchContainer(evenHubMessage);\n        }\n\n        /// <summary>\n        /// Convert an EventHubMessage to a batch container\n        /// </summary>\n        /// <param name=\"eventHubMessage\"></param>\n        /// <returns></returns>\n        protected virtual IBatchContainer GetBatchContainer(EventHubMessage eventHubMessage)\n        {\n            return new EventHubBatchContainer(eventHubMessage, this.serializer);\n        }\n\n        /// <summary>\n        /// Gets the stream sequence token from a cached message.\n        /// </summary>\n        /// <param name=\"cachedMessage\"></param>\n        /// <returns></returns>\n        public virtual StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n        {\n            return new EventHubSequenceTokenV2(\"\", cachedMessage.SequenceNumber, 0);\n        }\n\n        public virtual EventData ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            if (token != null) throw new ArgumentException(\"EventHub streams currently does not support non-null StreamSequenceToken.\", nameof(token));\n            return EventHubBatchContainer.ToEventData(this.serializer, streamId, events, requestContext);\n        }\n\n        public virtual CachedMessage FromQueueMessage(StreamPosition streamPosition, EventData queueMessage, DateTime dequeueTime, Func<int, ArraySegment<byte>> getSegment)\n        {\n            return new CachedMessage()\n            {\n                StreamId = streamPosition.StreamId,\n                SequenceNumber = queueMessage.SequenceNumber,\n                EventIndex = streamPosition.SequenceToken.EventIndex,\n                EnqueueTimeUtc = queueMessage.EnqueuedTime.UtcDateTime,\n                DequeueTimeUtc = dequeueTime,\n                Segment = EncodeMessageIntoSegment(queueMessage, getSegment)\n            };\n        }\n\n        public virtual StreamPosition GetStreamPosition(string partition, EventData queueMessage)\n        {\n            StreamId streamId = this.GetStreamIdentity(queueMessage);\n            StreamSequenceToken token =\n                new EventHubSequenceTokenV2(queueMessage.OffsetString, queueMessage.SequenceNumber, 0);\n            return new StreamPosition(streamId, token);\n        }\n\n        /// <summary>\n        /// Get offset from cached message.  Left to derived class, as only it knows how to get this from the cached message.\n        /// </summary>\n        public virtual string GetOffset(CachedMessage lastItemPurged)\n        {\n            // TODO figure out how to get this from the adapter\n            int readOffset = 0;\n            return SegmentBuilder.ReadNextString(lastItemPurged.Segment, ref readOffset); // read offset\n        }\n\n        /// <summary>\n        /// Get the Event Hub partition key to use for a stream.\n        /// </summary>\n        /// <param name=\"streamId\">The stream Guid.</param>\n        /// <returns>The partition key to use for the stream.</returns>\n        public virtual string GetPartitionKey(StreamId streamId) => streamId.GetKeyAsString();\n\n        /// <summary>\n        /// Get the <see cref=\"IStreamIdentity\"/> for an event message.\n        /// </summary>\n        /// <param name=\"queueMessage\">The event message.</param>\n        /// <returns>The stream identity.</returns>\n        public virtual StreamId GetStreamIdentity(EventData queueMessage)\n        {\n            string streamKey = queueMessage.PartitionKey;\n            string streamNamespace = queueMessage.GetStreamNamespaceProperty();\n            return StreamId.Create(streamNamespace, streamKey);\n        }\n\n        // Placed object message payload into a segment.\n        protected virtual ArraySegment<byte> EncodeMessageIntoSegment(EventData queueMessage, Func<int, ArraySegment<byte>> getSegment)\n        {\n            byte[] propertiesBytes = queueMessage.SerializeProperties(this.serializer);\n            var payload = queueMessage.Body.Span;\n            var offset = queueMessage.OffsetString;\n            // get size of namespace, offset, partitionkey, properties, and payload\n            int size = SegmentBuilder.CalculateAppendSize(offset) +\n                SegmentBuilder.CalculateAppendSize(queueMessage.PartitionKey) +\n                SegmentBuilder.CalculateAppendSize(propertiesBytes) +\n                SegmentBuilder.CalculateAppendSize(payload);\n\n            // get segment\n            ArraySegment<byte> segment = getSegment(size);\n\n            // encode namespace, offset, partitionkey, properties and payload into segment\n            int writeOffset = 0;\n            SegmentBuilder.Append(segment, ref writeOffset, offset);\n            SegmentBuilder.Append(segment, ref writeOffset, queueMessage.PartitionKey);\n            SegmentBuilder.Append(segment, ref writeOffset, propertiesBytes);\n            SegmentBuilder.Append(segment, ref writeOffset, payload);\n\n            return segment;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubMessage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Replication of EventHub EventData class, reconstructed from cached data CachedEventHubMessage\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventHubMessage\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"streamId\">Stream Identity</param>\n        /// <param name=\"partitionKey\">EventHub partition key for message</param>\n        /// <param name=\"offset\">Offset into the EventHub partition where this message was from</param>\n        /// <param name=\"sequenceNumber\">Offset into the EventHub partition where this message was from</param>\n        /// <param name=\"enqueueTimeUtc\">Time in UTC when this message was injected by EventHub</param>\n        /// <param name=\"dequeueTimeUtc\">Time in UTC when this message was read from EventHub into the current service</param>\n        /// <param name=\"properties\">User properties from EventData object</param>\n        /// <param name=\"payload\">Binary data from EventData object</param>\n        public EventHubMessage(StreamId streamId, string partitionKey, string offset, long sequenceNumber,\n            DateTime enqueueTimeUtc, DateTime dequeueTimeUtc, IDictionary<string, object> properties, byte[] payload)\n        {\n            StreamId = streamId;\n            PartitionKey = partitionKey;\n            Offset = offset;\n            SequenceNumber = sequenceNumber;\n            EnqueueTimeUtc = enqueueTimeUtc;\n            DequeueTimeUtc = dequeueTimeUtc;\n            Properties = properties;\n            Payload = payload;\n        }\n\n        /// <summary>\n        /// Duplicate of EventHub's EventData class.\n        /// </summary>\n        public EventHubMessage(CachedMessage cachedMessage, Serialization.Serializer serializer)\n        {\n            int readOffset = 0;\n            StreamId = cachedMessage.StreamId;\n            Offset = SegmentBuilder.ReadNextString(cachedMessage.Segment, ref readOffset);\n            PartitionKey = SegmentBuilder.ReadNextString(cachedMessage.Segment, ref readOffset);\n            SequenceNumber = cachedMessage.SequenceNumber;\n            EnqueueTimeUtc = cachedMessage.EnqueueTimeUtc;\n            DequeueTimeUtc = cachedMessage.DequeueTimeUtc;\n            Properties = SegmentBuilder.ReadNextBytes(cachedMessage.Segment, ref readOffset).DeserializeProperties(serializer);\n            Payload = SegmentBuilder.ReadNextBytes(cachedMessage.Segment, ref readOffset).ToArray();\n        }\n\n        /// <summary>\n        /// Stream identifier\n        /// </summary>\n        [Id(0)]\n        public StreamId StreamId { get; }\n\n        /// <summary>\n        /// EventHub partition key\n        /// </summary>\n        [Id(1)]\n        public string PartitionKey { get; }\n\n        /// <summary>\n        /// Offset into EventHub partition\n        /// </summary>\n        [Id(2)]\n        public string Offset { get; }\n\n        /// <summary>\n        /// Sequence number in EventHub partition\n        /// </summary>\n        [Id(3)]\n        public long SequenceNumber { get; }\n\n        /// <summary>\n        /// Time event was written to EventHub\n        /// </summary>\n        [Id(4)]\n        public DateTime EnqueueTimeUtc { get; }\n\n        /// <summary>\n        /// Time event was read from EventHub and added to cache\n        /// </summary>\n        [Id(5)]\n        public DateTime DequeueTimeUtc { get; }\n\n        /// <summary>\n        /// User EventData properties\n        /// </summary>\n        [Id(6)]\n        public IDictionary<string, object> Properties { get; }\n\n        /// <summary>\n        /// Binary event data\n        /// </summary>\n        [Id(7)]\n        public byte[] Payload { get; }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubPartitionCheckpointEntity.cs",
    "content": "using System;\nusing Azure;\nusing Azure.Data.Tables;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    internal class EventHubPartitionCheckpointEntity : ITableEntity\n    {\n        public string Offset { get; set; }\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n\n        public EventHubPartitionCheckpointEntity()\n        {\n            Offset = EventHubConstants.StartOfStream;\n        }\n\n        public static EventHubPartitionCheckpointEntity Create(string streamProviderName, string serviceId, string partition)\n        {\n            return new EventHubPartitionCheckpointEntity\n            {\n                PartitionKey = MakePartitionKey(streamProviderName, serviceId),\n                RowKey = MakeRowKey(partition)\n            };\n        }\n\n        public static string MakePartitionKey(string streamProviderName, string checkpointNamespace)\n        {\n            string key = $\"EventHubCheckpoints_{streamProviderName}_{checkpointNamespace}\";\n            return AzureTableUtils.SanitizeTableProperty(key);\n        }\n\n        public static string MakeRowKey(string partition)\n        {\n            string key = $\"partition_{partition}\";\n            return AzureTableUtils.SanitizeTableProperty(key);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubQueueCache.cs",
    "content": "using System;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Azure.Messaging.EventHubs;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// EventHub queue cache\n    /// </summary>\n    public partial class EventHubQueueCache : IEventHubQueueCache\n    {\n        public string Partition { get; private set; }\n\n        /// <summary>\n        /// Default max number of items that can be added to the cache between purge calls\n        /// </summary>\n        private readonly int defaultMaxAddCount;\n        /// <summary>\n        /// Underlying message cache implementation\n        /// Protected for test purposes\n        /// </summary>\n        protected readonly PooledQueueCache cache;\n        private readonly IObjectPool<FixedSizeBuffer> bufferPool;\n        private readonly IEventHubDataAdapter dataAdapter;\n        private readonly IEvictionStrategy evictionStrategy;\n        private readonly IStreamQueueCheckpointer<string> checkpointer;\n        private readonly ILogger logger;\n        private readonly AggregatedCachePressureMonitor cachePressureMonitor;\n        private readonly ICacheMonitor cacheMonitor;\n        private FixedSizeBuffer currentBuffer;\n\n        /// <summary>\n        /// EventHub queue cache.\n        /// </summary>\n        /// <param name=\"partition\">Partition this instance is caching.</param>\n        /// <param name=\"defaultMaxAddCount\">Default max number of items that can be added to the cache between purge calls.</param>\n        /// <param name=\"bufferPool\">raw data block pool.</param>\n        /// <param name=\"dataAdapter\">Adapts EventData to cached.</param>\n        /// <param name=\"evictionStrategy\">Eviction strategy manage purge related events</param>\n        /// <param name=\"checkpointer\">Logic used to store queue position.</param>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"cacheMonitor\"></param>\n        /// <param name=\"cacheMonitorWriteInterval\"></param>\n        /// <param name=\"metadataMinTimeInCache\"></param>\n        public EventHubQueueCache(\n            string partition,\n            int defaultMaxAddCount,\n            IObjectPool<FixedSizeBuffer> bufferPool,\n            IEventHubDataAdapter dataAdapter,\n            IEvictionStrategy evictionStrategy,\n            IStreamQueueCheckpointer<string> checkpointer,\n            ILogger logger,\n            ICacheMonitor cacheMonitor,\n            TimeSpan? cacheMonitorWriteInterval,\n            TimeSpan? metadataMinTimeInCache)\n        {\n            this.Partition = partition;\n            this.defaultMaxAddCount = defaultMaxAddCount;\n            this.bufferPool = bufferPool;\n            this.dataAdapter = dataAdapter;\n            this.checkpointer = checkpointer;\n            this.cache = new PooledQueueCache(dataAdapter, logger, cacheMonitor, cacheMonitorWriteInterval, metadataMinTimeInCache);\n            this.cacheMonitor = cacheMonitor;\n            this.evictionStrategy = evictionStrategy;\n            this.evictionStrategy.OnPurged = this.OnPurge;\n            this.evictionStrategy.PurgeObservable = this.cache;\n            this.cachePressureMonitor = new AggregatedCachePressureMonitor(logger, cacheMonitor);\n            this.logger = logger;\n        }\n\n        /// <inheritdoc />\n        public void SignalPurge()\n        {\n            this.evictionStrategy.PerformPurge(DateTime.UtcNow);\n        }\n\n        /// <summary>\n        /// Add cache pressure monitor to the cache's back pressure algorithm\n        /// </summary>\n        /// <param name=\"monitor\"></param>\n        public void AddCachePressureMonitor(ICachePressureMonitor monitor)\n        {\n            monitor.CacheMonitor = this.cacheMonitor;\n            this.cachePressureMonitor.AddCachePressureMonitor(monitor);\n        }\n\n        /// <summary>\n        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n        /// </summary>\n        /// <filterpriority>2</filterpriority>\n        public void Dispose()\n        {\n            this.evictionStrategy.OnPurged = null;\n        }\n\n        /// <summary>\n        /// The limit of the maximum number of items that can be added\n        /// </summary>\n        public int GetMaxAddCount()\n        {\n            return cachePressureMonitor.IsUnderPressure(DateTime.UtcNow) ? 0 : defaultMaxAddCount;\n        }\n\n        /// <summary>\n        /// Add a list of EventHub EventData to the cache.\n        /// </summary>\n        /// <param name=\"messages\"></param>\n        /// <param name=\"dequeueTimeUtc\"></param>\n        /// <returns></returns>\n        public List<StreamPosition> Add(List<EventData> messages, DateTime dequeueTimeUtc)\n        {\n            List<StreamPosition> positions = new List<StreamPosition>();\n            List<CachedMessage> cachedMessages = new List<CachedMessage>();\n            foreach (EventData message in messages)\n            {\n                StreamPosition position = this.dataAdapter.GetStreamPosition(this.Partition, message);\n                cachedMessages.Add(this.dataAdapter.FromQueueMessage(position, message, dequeueTimeUtc, this.GetSegment));\n                positions.Add(position);\n            }\n            cache.Add(cachedMessages, dequeueTimeUtc);\n            return positions;\n        }\n\n        /// <summary>\n        /// Get a cursor into the cache to read events from a stream.\n        /// </summary>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"sequenceToken\"></param>\n        /// <returns></returns>\n        public object GetCursor(StreamId streamId, StreamSequenceToken sequenceToken)\n        {\n            return cache.GetCursor(streamId, sequenceToken);\n        }\n\n        /// <summary>\n        /// Try to get the next message in the cache for the provided cursor.\n        /// </summary>\n        /// <param name=\"cursorObj\"></param>\n        /// <param name=\"message\"></param>\n        /// <returns></returns>\n        public bool TryGetNextMessage(object cursorObj, out IBatchContainer message)\n        {\n            if (!cache.TryGetNextMessage(cursorObj, out message))\n                return false;\n            double cachePressureContribution;\n            cachePressureMonitor.RecordCachePressureContribution(\n                TryCalculateCachePressureContribution(message.SequenceToken, out cachePressureContribution)\n                    ? cachePressureContribution\n                    : 0.0);\n            return true;\n        }\n\n        /// <summary>\n        /// Handles cache purge signals\n        /// </summary>\n        /// <param name=\"lastItemPurged\"></param>\n        /// <param name=\"newestItem\"></param>\n        private void OnPurge(CachedMessage? lastItemPurged, CachedMessage? newestItem)\n        {\n            if (lastItemPurged.HasValue && newestItem.HasValue)\n            {\n                LogDebugCachePeriod(\n                    new(lastItemPurged.Value.EnqueueTimeUtc),\n                    new(newestItem.Value.EnqueueTimeUtc),\n                    new(lastItemPurged.Value.DequeueTimeUtc),\n                    new(newestItem.Value.DequeueTimeUtc));\n            }\n            if (lastItemPurged.HasValue)\n            {\n                checkpointer.Update(this.dataAdapter.GetOffset(lastItemPurged.Value), DateTime.UtcNow);\n            }\n        }\n\n        /// <summary>\n        /// cachePressureContribution should be a double between 0-1, indicating how much danger the item is of being removed from the cache.\n        ///   0 indicating  no danger,\n        ///   1 indicating removal is imminent.\n        /// </summary>\n        private bool TryCalculateCachePressureContribution(StreamSequenceToken token, out double cachePressureContribution)\n        {\n            cachePressureContribution = 0;\n            // if cache is empty or has few items, don't calculate pressure\n            if (cache.IsEmpty ||\n                !cache.Newest.HasValue ||\n                !cache.Oldest.HasValue ||\n                cache.Newest.Value.SequenceNumber - cache.Oldest.Value.SequenceNumber < 10 * defaultMaxAddCount) // not enough items in cache.\n            {\n                return false;\n            }\n\n            IEventHubPartitionLocation location = (IEventHubPartitionLocation)token;\n            double cacheSize = cache.Newest.Value.SequenceNumber - cache.Oldest.Value.SequenceNumber;\n            long distanceFromNewestMessage = cache.Newest.Value.SequenceNumber - location.SequenceNumber;\n            // pressure is the ratio of the distance from the front of the cache to the\n            cachePressureContribution = distanceFromNewestMessage / cacheSize;\n\n            return true;\n        }\n\n        private ArraySegment<byte> GetSegment(int size)\n        {\n            // get segment from current block\n            ArraySegment<byte> segment;\n            if (currentBuffer == null || !currentBuffer.TryGetSegment(size, out segment))\n            {\n                // no block or block full, get new block and try again\n                currentBuffer = bufferPool.Allocate();\n                //call EvictionStrategy's OnBlockAllocated method\n                this.evictionStrategy.OnBlockAllocated(currentBuffer);\n                // if this fails with clean block, then requested size is too big\n                if (!currentBuffer.TryGetSegment(size, out segment))\n                {\n                    throw new ArgumentOutOfRangeException(nameof(size), $\"Message size is to big. MessageSize: {size}\");\n                }\n            }\n            return segment;\n        }\n\n        private readonly struct DateTimeLogRecord(DateTime ts)\n        {\n            public override string ToString() => LogFormatter.PrintDate(ts);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"CachePeriod: EnqueueTimeUtc: {OldestEnqueueTimeUtc} to {NewestEnqueueTimeUtc}, DequeueTimeUtc: {OldestDequeueTimeUtc} to {NewestDequeueTimeUtc}\"\n        )]\n        private partial void LogDebugCachePeriod(\n            DateTimeLogRecord oldestEnqueueTimeUtc,\n            DateTimeLogRecord newestEnqueueTimeUtc,\n            DateTimeLogRecord oldestDequeueTimeUtc,\n            DateTimeLogRecord newestDequeueTimeUtc);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubQueueCacheFactory.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\nusing Orleans.Streaming.EventHubs.StatisticMonitors;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Factory class to configure and create IEventHubQueueCache\n    /// </summary>\n    public class EventHubQueueCacheFactory : IEventHubQueueCacheFactory\n    {\n        private readonly EventHubStreamCachePressureOptions cacheOptions;\n        private readonly StreamCacheEvictionOptions evictionOptions;\n        private readonly StreamStatisticOptions statisticOptions;\n        private readonly IEventHubDataAdapter dataAdater;\n        private readonly TimePurgePredicate timePurge;\n        private readonly EventHubMonitorAggregationDimensions sharedDimensions;\n        private IObjectPool<FixedSizeBuffer> bufferPool;\n        private string bufferPoolId;\n\n        /// <summary>\n        /// Create a cache monitor to report performance metrics.\n        /// Factory function should return an ICacheMonitor.\n        /// </summary>\n        public Func<EventHubCacheMonitorDimensions, ILoggerFactory, ICacheMonitor> CacheMonitorFactory { set; get; }\n\n        /// <summary>\n        /// Create a block pool monitor to report performance metrics.\n        /// Factory function should return an IObjectPoolMonitor.\n        /// </summary>\n        public Func<EventHubBlockPoolMonitorDimensions, ILoggerFactory, IBlockPoolMonitor> BlockPoolMonitorFactory { set; get; }\n\n        /// <summary>\n        /// Constructor for EventHubQueueCacheFactory\n        /// </summary>\n        public EventHubQueueCacheFactory(\n            EventHubStreamCachePressureOptions cacheOptions,\n            StreamCacheEvictionOptions evictionOptions, \n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdater,\n            EventHubMonitorAggregationDimensions sharedDimensions,\n            Func<EventHubCacheMonitorDimensions, ILoggerFactory, ICacheMonitor> cacheMonitorFactory = null,\n            Func<EventHubBlockPoolMonitorDimensions, ILoggerFactory, IBlockPoolMonitor> blockPoolMonitorFactory = null)\n        {\n            this.cacheOptions = cacheOptions;\n            this.evictionOptions = evictionOptions;\n            this.statisticOptions = statisticOptions;\n            this.dataAdater = dataAdater;\n            this.timePurge = new TimePurgePredicate(evictionOptions.DataMinTimeInCache, evictionOptions.DataMaxAgeInCache);\n            this.sharedDimensions = sharedDimensions;\n            this.CacheMonitorFactory = cacheMonitorFactory ?? ((dimensions, logger) => new DefaultEventHubCacheMonitor(dimensions));\n            this.BlockPoolMonitorFactory = blockPoolMonitorFactory ?? ((dimensions, logger) => new DefaultEventHubBlockPoolMonitor(dimensions));\n        }\n\n        /// <summary>\n        /// Function which create an EventHubQueueCache, which by default will configure the EventHubQueueCache using configuration in CreateBufferPool function\n        /// and AddCachePressureMonitors function.\n        /// </summary>\n        /// <returns></returns>\n        public IEventHubQueueCache CreateCache(string partition, IStreamQueueCheckpointer<string> checkpointer, ILoggerFactory loggerFactory)\n        {\n            string blockPoolId;\n            var blockPool = CreateBufferPool(this.statisticOptions, loggerFactory, this.sharedDimensions, out blockPoolId);\n            var cache = CreateCache(partition, dataAdater, this.statisticOptions, this.evictionOptions, checkpointer, loggerFactory, blockPool, blockPoolId, this.timePurge, this.sharedDimensions);\n            AddCachePressureMonitors(cache, this.cacheOptions, loggerFactory.CreateLogger($\"{typeof(EventHubQueueCache).FullName}.{this.sharedDimensions.EventHubPath}.{partition}\"));\n            return cache;\n        }\n\n        /// <summary>\n        /// Function used to configure BufferPool for EventHubQueueCache. User can override this function to provide more customization on BufferPool creation\n        /// </summary>\n        protected virtual IObjectPool<FixedSizeBuffer> CreateBufferPool(StreamStatisticOptions statisticOptions, ILoggerFactory loggerFactory, EventHubMonitorAggregationDimensions sharedDimensions, out string blockPoolId)\n        {\n            if (this.bufferPool == null)\n            {\n                var bufferSize = 1 << 20;\n                this.bufferPoolId = $\"BlockPool-{new Guid().ToString()}-BlockSize-{bufferSize}\";\n                var monitorDimensions = new EventHubBlockPoolMonitorDimensions(sharedDimensions, this.bufferPoolId);\n                var objectPoolMonitor = new ObjectPoolMonitorBridge(this.BlockPoolMonitorFactory(monitorDimensions, loggerFactory), bufferSize);\n                this.bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(bufferSize),\n                    objectPoolMonitor, statisticOptions.StatisticMonitorWriteInterval);\n            }\n            blockPoolId = this.bufferPoolId;\n            return this.bufferPool;\n        }\n\n        /// <summary>\n        /// Function used to configure cache pressure monitors for EventHubQueueCache. \n        /// User can override this function to provide more customization on cache pressure monitors\n        /// </summary>\n        /// <param name=\"cache\"></param>\n        /// <param name=\"providerOptions\"></param>\n        /// <param name=\"cacheLogger\"></param>\n        protected virtual void AddCachePressureMonitors(\n            IEventHubQueueCache cache,\n            EventHubStreamCachePressureOptions providerOptions,\n            ILogger cacheLogger)\n        {\n            if (providerOptions.AveragingCachePressureMonitorFlowControlThreshold.HasValue)\n            {\n                var avgMonitor = new AveragingCachePressureMonitor(\n                    providerOptions.AveragingCachePressureMonitorFlowControlThreshold.Value, cacheLogger);\n                cache.AddCachePressureMonitor(avgMonitor);\n            }\n\n            if (providerOptions.SlowConsumingMonitorPressureWindowSize.HasValue\n                || providerOptions.SlowConsumingMonitorFlowControlThreshold.HasValue)\n            {\n                var slowConsumeMonitor = new SlowConsumingPressureMonitor(cacheLogger);\n                if (providerOptions.SlowConsumingMonitorFlowControlThreshold.HasValue)\n                {\n                    slowConsumeMonitor.FlowControlThreshold = providerOptions.SlowConsumingMonitorFlowControlThreshold.Value;\n                }\n                if (providerOptions.SlowConsumingMonitorPressureWindowSize.HasValue)\n                {\n                    slowConsumeMonitor.PressureWindowSize = providerOptions.SlowConsumingMonitorPressureWindowSize.Value;\n                }\n\n                cache.AddCachePressureMonitor(slowConsumeMonitor);\n            }\n        }\n\n        /// <summary>\n        /// Default function to be called to create an EventhubQueueCache in IEventHubQueueCacheFactory.CreateCache method. User can \n        /// override this method to add more customization.\n        /// </summary>\n        protected virtual IEventHubQueueCache CreateCache(\n            string partition,\n            IEventHubDataAdapter dataAdatper,\n            StreamStatisticOptions statisticOptions,\n            StreamCacheEvictionOptions streamCacheEvictionOptions,\n            IStreamQueueCheckpointer<string> checkpointer,\n            ILoggerFactory loggerFactory,\n            IObjectPool<FixedSizeBuffer> bufferPool,\n            string blockPoolId,\n            TimePurgePredicate timePurge,\n            EventHubMonitorAggregationDimensions sharedDimensions)\n        {\n            var cacheMonitorDimensions = new EventHubCacheMonitorDimensions(sharedDimensions, partition, blockPoolId);\n            var cacheMonitor = this.CacheMonitorFactory(cacheMonitorDimensions, loggerFactory);\n            var logger = loggerFactory.CreateLogger($\"{typeof(EventHubQueueCache).FullName}.{sharedDimensions.EventHubPath}.{partition}\");\n            var evictionStrategy = new ChronologicalEvictionStrategy(logger, timePurge, cacheMonitor, statisticOptions.StatisticMonitorWriteInterval);\n            return new EventHubQueueCache(partition, EventHubAdapterReceiver.MaxMessagesPerRead, bufferPool, dataAdatper, evictionStrategy, checkpointer, logger,  \n                cacheMonitor, statisticOptions.StatisticMonitorWriteInterval, streamCacheEvictionOptions.MetadataMinTimeInCache);\n        }\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubSequenceToken.cs",
    "content": "\nusing System;\nusing System.Globalization;\nusing Newtonsoft.Json;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Location of a message within an EventHub partition\n    /// </summary>\n    public interface IEventHubPartitionLocation\n    {\n        /// <summary>\n        /// Offset of the message within an EventHub partition\n        /// </summary>\n        string EventHubOffset { get; }\n\n        /// <summary>\n        /// EventHub sequence id of the message\n        /// </summary>\n        long SequenceNumber { get; }\n    }\n\n    /// <summary>\n    /// Event Hub messages consist of a batch of application layer events, so EventHub tokens contain three pieces of information.\n    /// EventHubOffset - this is a unique value per partition that is used to start reading from this message in the partition.\n    /// SequenceNumber - EventHub sequence numbers are unique ordered message IDs for messages within a partition.  \n    ///   The SequenceNumber is required for uniqueness and ordering of EventHub messages within a partition.\n    /// event Index - Since each EventHub message may contain more than one application layer event, this value\n    ///   indicates which application layer event this token is for, within an EventHub message.  It is required for uniqueness\n    ///   and ordering of application layer events within an EventHub message.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventHubSequenceToken : EventSequenceToken, IEventHubPartitionLocation\n    {\n        /// <summary>\n        /// Offset of the message within an EventHub partition\n        /// </summary>\n        [Id(0)]\n        [JsonProperty]\n        public string EventHubOffset { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventHubSequenceToken\" /> class.\n        /// </summary>\n        /// <param name=\"eventHubOffset\">EventHub offset within the partition from which this message came.</param>\n        /// <param name=\"sequenceNumber\">EventHub sequenceNumber for this message.</param>\n        /// <param name=\"eventIndex\">Index into a batch of events, if multiple events were delivered within a single EventHub message.</param>\n        public EventHubSequenceToken(string eventHubOffset, long sequenceNumber, int eventIndex)\n            : base(sequenceNumber, eventIndex)\n        {\n            EventHubOffset = eventHubOffset;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventHubSequenceToken\" /> class.\n        /// </summary>\n        /// <remarks>\n        /// This constructor is exposed for serializer use only.\n        /// </remarks>\n        public EventHubSequenceToken() : base()\n        {\n        }\n\n        /// <summary>Returns a string that represents the current object.</summary>\n        /// <returns>A string that represents the current object.</returns>\n        /// <filterpriority>2</filterpriority>\n        public override string ToString()\n        {\n            return string.Format(CultureInfo.InvariantCulture, \"EventHubSequenceToken(EventHubOffset: {0}, SequenceNumber: {1}, EventIndex: {2})\", EventHubOffset, SequenceNumber, EventIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubSequenceTokenV2.cs",
    "content": "using System;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Event Hub messages consist of a batch of application layer events, so EventHub tokens contain three pieces of information.\n    /// EventHubOffset - this is a unique value per partition that is used to start reading from this message in the partition.\n    /// SequenceNumber - EventHub sequence numbers are unique ordered message IDs for messages within a partition.  \n    ///   The SequenceNumber is required for uniqueness and ordering of EventHub messages within a partition.\n    /// event Index - Since each EventHub message may contain more than one application layer event, this value\n    ///   indicates which application layer event this token is for, within an EventHub message.  It is required for uniqueness\n    ///   and ordering of application layer events within an EventHub message.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventHubSequenceTokenV2 : EventHubSequenceToken\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventHubSequenceTokenV2\" /> class.\n        /// </summary>\n        /// <param name=\"eventHubOffset\">EventHub offset within the partition from which this message came.</param>\n        /// <param name=\"sequenceNumber\">EventHub sequenceNumber for this message.</param>\n        /// <param name=\"eventIndex\">Index into a batch of events, if multiple events were delivered within a single EventHub message.</param>\n        public EventHubSequenceTokenV2(string eventHubOffset, long sequenceNumber, int eventIndex)\n            : base(eventHubOffset, sequenceNumber, eventIndex)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventHubSequenceTokenV2\" /> class.\n        /// </summary>\n        /// <remarks>\n        /// This constructor is exposed for serializer use only.\n        /// </remarks>\n        public EventHubSequenceTokenV2() : base()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubStreamBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    public interface IEventHubStreamConfigurator : INamedServiceConfigurator {}\n\n    public static class EventHubStreamConfiguratorExtensions\n    {\n        public static void ConfigureEventHub(this IEventHubStreamConfigurator configurator, Action<OptionsBuilder<EventHubOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        public static void UseDataAdapter(this IEventHubStreamConfigurator configurator, Func<IServiceProvider, string, IEventHubDataAdapter> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n    }\n\n    public interface ISiloEventHubStreamConfigurator : IEventHubStreamConfigurator, ISiloRecoverableStreamConfigurator { }\n\n\n    public static class SiloEventHubStreamConfiguratorExtensions\n    {\n        public static void ConfigureCheckpointer<TOptions>(this ISiloEventHubStreamConfigurator configurator, Func<IServiceProvider, string, IStreamQueueCheckpointerFactory> checkpointerFactoryBuilder, Action<OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new()\n        {\n            configurator.ConfigureComponent(checkpointerFactoryBuilder, configureOptions);\n        }\n\n        public static void ConfigurePartitionReceiver(this ISiloEventHubStreamConfigurator configurator, Action<OptionsBuilder<EventHubReceiverOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        public static void ConfigureCachePressuring(this ISiloEventHubStreamConfigurator configurator, Action<OptionsBuilder<EventHubStreamCachePressureOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        public static void UseAzureTableCheckpointer(this ISiloEventHubStreamConfigurator configurator, Action<OptionsBuilder<AzureTableStreamCheckpointerOptions>> configureOptions)\n        {\n            configurator.ConfigureCheckpointer(EventHubCheckpointerFactory.CreateFactory, configureOptions);\n        }\n    }\n\n    public class SiloEventHubStreamConfigurator : SiloRecoverableStreamConfigurator, ISiloEventHubStreamConfigurator\n    {\n        public SiloEventHubStreamConfigurator(string name,\n            Action<Action<IServiceCollection>> configureServicesDelegate)\n            : base(name, configureServicesDelegate, EventHubAdapterFactory.Create)\n        {\n            this.ConfigureDelegate(services => services.ConfigureNamedOptionForLogging<EventHubOptions>(name)\n                .ConfigureNamedOptionForLogging<EventHubReceiverOptions>(name)\n                .ConfigureNamedOptionForLogging<EventHubStreamCachePressureOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new EventHubOptionsValidator(sp.GetOptionsByName<EventHubOptions>(name), name))\n                .AddTransient<IConfigurationValidator>(sp => new StreamCheckpointerConfigurationValidator(sp, name)));\n        }\n    }\n\n    public interface IClusterClientEventHubStreamConfigurator : IEventHubStreamConfigurator, IClusterClientPersistentStreamConfigurator { }\n\n    public class ClusterClientEventHubStreamConfigurator : ClusterClientPersistentStreamConfigurator, IClusterClientEventHubStreamConfigurator\n    {\n        public ClusterClientEventHubStreamConfigurator(string name, IClientBuilder builder)\n           : base(name, builder, EventHubAdapterFactory.Create)\n        {\n            builder\n                .ConfigureServices(services => services.ConfigureNamedOptionForLogging<EventHubOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new EventHubOptionsValidator(sp.GetOptionsByName<EventHubOptions>(name), name)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubStreamOptions.cs",
    "content": "using Azure;\nusing Azure.Core;\nusing Azure.Messaging.EventHubs;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// EventHub settings for a specific hub\n    /// </summary>\n    public class EventHubOptions\n    {\n        /// <summary>\n        /// Gets the delegate used to create connections to Azure Event Hub.\n        /// </summary>\n        internal CreateConnectionDelegate CreateConnection { get; private set; }\n\n        /// <summary>\n        /// Event Hub consumer group.\n        /// </summary>\n        internal string ConsumerGroup { get; private set; }\n\n        /// <summary>\n        /// Event Hub name.\n        /// </summary>\n        internal string EventHubName { get; private set; }\n\n        /// <summary>\n        /// Connection options used when creating a connection to an Azure Event Hub.\n        /// </summary>\n        public EventHubConnectionOptions ConnectionOptions { get; set; } = new EventHubConnectionOptions { TransportType = EventHubsTransportType.AmqpTcp };\n\n        /// <summary>\n        /// Creates an Azure Event Hub connection.\n        /// </summary>\n        /// <param name=\"connectionOptions\">The connection options.</param>\n        /// <returns>An Azure Event Hub connection.</returns>\n        public delegate EventHubConnection CreateConnectionDelegate(EventHubConnectionOptions connectionOptions);\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided connection string.\n        /// </summary>\n        public void ConfigureEventHubConnection(string connectionString, string eventHubName, string consumerGroup)\n        {\n            EventHubName = eventHubName;\n            ConsumerGroup = consumerGroup;\n\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(connectionString));\n            }\n\n            ValidateValues(eventHubName, consumerGroup);\n\n            CreateConnection = connectionOptions => new EventHubConnection(connectionString, EventHubName, connectionOptions);\n        }\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided fully-qualified namespace string and credential.\n        /// </summary>\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, AzureNamedKeyCredential credential)\n        {\n            EventHubName = eventHubName;\n            ConsumerGroup = consumerGroup;\n\n            if (string.IsNullOrWhiteSpace(fullyQualifiedNamespace))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(fullyQualifiedNamespace));\n            }\n\n            ValidateValues(eventHubName, consumerGroup);\n\n            if (credential is null)\n            {\n                throw new ArgumentNullException(nameof(credential));\n            }\n\n            CreateConnection = connectionOptions => new EventHubConnection(fullyQualifiedNamespace, EventHubName, credential, connectionOptions);\n        }\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided fully-qualified namespace string and credential.\n        /// </summary>\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, AzureSasCredential credential)\n        {\n            EventHubName = eventHubName;\n            ConsumerGroup = consumerGroup;\n\n            if (string.IsNullOrWhiteSpace(fullyQualifiedNamespace))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(fullyQualifiedNamespace));\n            }\n\n            ValidateValues(eventHubName, consumerGroup);\n\n            if (credential is null)\n            {\n                throw new ArgumentNullException(nameof(credential));\n            }\n\n            CreateConnection = connectionOptions => new EventHubConnection(fullyQualifiedNamespace, EventHubName, credential, connectionOptions);\n        }\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided fully-qualified namespace string and credential.\n        /// </summary>\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, TokenCredential credential)\n        {\n            EventHubName = eventHubName;\n            ConsumerGroup = consumerGroup;\n            if (string.IsNullOrWhiteSpace(fullyQualifiedNamespace))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(fullyQualifiedNamespace));\n            }\n\n            ValidateValues(eventHubName, consumerGroup);\n            if (credential is null)\n            {\n                throw new ArgumentNullException(nameof(credential));\n            }\n            \n            CreateConnection = connectionOptions => new EventHubConnection(fullyQualifiedNamespace, EventHubName, credential, connectionOptions);\n        }\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided connection instance.\n        /// </summary>\n        public void ConfigureEventHubConnection(EventHubConnection connection, string consumerGroup)\n        {\n            EventHubName = connection.EventHubName;\n            ConsumerGroup = consumerGroup;\n            ValidateValues(connection.EventHubName, consumerGroup);\n            if (connection is null) throw new ArgumentNullException(nameof(connection));\n            CreateConnection = _ => connection;\n        }\n\n        /// <summary>\n        /// Configures the Azure Event Hub connection using the provided delegate.\n        /// </summary>\n        public void ConfigureEventHubConnection(CreateConnectionDelegate createConnection, string eventHubName, string consumerGroup)\n        {\n            EventHubName = eventHubName;\n            ConsumerGroup = consumerGroup;\n            ValidateValues(eventHubName, consumerGroup);\n            CreateConnection = createConnection ?? throw new ArgumentNullException(nameof(createConnection));\n        }\n\n        private static void ValidateValues(string eventHubName, string consumerGroup)\n        {\n            if (string.IsNullOrWhiteSpace(eventHubName))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(eventHubName));\n            }\n\n            if (string.IsNullOrWhiteSpace(consumerGroup))\n            {\n                throw new ArgumentException(\"A non-null, non-empty value must be provided.\", nameof(consumerGroup));\n            }\n        }\n    }\n\n    public class EventHubOptionsValidator : IConfigurationValidator\n    {\n        private readonly EventHubOptions options;\n        private readonly string name;\n        public EventHubOptionsValidator(EventHubOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n        public void ValidateConfiguration()\n        {\n            if (options.CreateConnection is null)\n            {\n                throw new OrleansConfigurationException($\"Azure Event Hub connection not configured for stream provider options {nameof(EventHubOptions)} with name \\\"{name}\\\". Use the {options.GetType().Name}.{nameof(EventHubOptions.ConfigureEventHubConnection)} method to configure the connection.\");\n            }\n\n            if (string.IsNullOrEmpty(options.ConsumerGroup))\n            {\n                throw new OrleansConfigurationException($\"{nameof(EventHubOptions)} on stream provider {this.name} is invalid. {nameof(EventHubOptions.ConsumerGroup)} is invalid\");\n            }\n\n            if (string.IsNullOrEmpty(options.EventHubName))\n            {\n                throw new OrleansConfigurationException($\"{nameof(EventHubOptions)} on stream provider {this.name} is invalid. {nameof(EventHubOptions.EventHubName)} is invalid\");\n            }\n        }\n    }\n\n    public class StreamCheckpointerConfigurationValidator : IConfigurationValidator\n    {\n        private readonly IServiceProvider services;\n        private readonly string name;\n        public StreamCheckpointerConfigurationValidator(IServiceProvider services, string name)\n        {\n            this.services = services;\n            this.name = name;\n        }\n        public void ValidateConfiguration()\n        {\n            var checkpointerFactory = services.GetKeyedService<IStreamQueueCheckpointerFactory>(this.name);\n            if (checkpointerFactory == null)\n                throw new OrleansConfigurationException($\"No IStreamQueueCheckpointer is configured with PersistentStreamProvider {this.name}. Please configure one.\");\n        }\n    }\n\n    public class EventHubReceiverOptions\n    {\n        /// <summary>\n        /// Optional parameter that configures the receiver prefetch count.\n        /// </summary>\n        public int? PrefetchCount { get; set; }\n        /// <summary>\n        /// In cases where no checkpoint is found, this indicates if service should read from the most recent data, or from the beginning of a partition.\n        /// </summary>\n        public bool StartFromNow { get; set; } = DEFAULT_START_FROM_NOW;\n        private const bool DEFAULT_START_FROM_NOW = true;\n    }\n\n    public class EventHubStreamCachePressureOptions\n    {\n        /// <summary>\n        /// SlowConsumingPressureMonitorConfig\n        /// </summary>\n        public double? SlowConsumingMonitorFlowControlThreshold { get; set; }\n\n        /// <summary>\n        /// SlowConsumingMonitorPressureWindowSize\n        /// </summary>\n        public TimeSpan? SlowConsumingMonitorPressureWindowSize { get; set; }\n\n        /// <summary>\n        /// AveragingCachePressureMonitorFlowControlThreshold, AveragingCachePressureMonitor is turn on by default. \n        /// User can turn it off by setting this value to null\n        /// </summary>\n        public double? AveragingCachePressureMonitorFlowControlThreshold { get; set; } = DEFAULT_AVERAGING_CACHE_PRESSURE_MONITORING_THRESHOLD;\n        internal const double DEFAULT_AVERAGING_CACHE_PRESSURE_MONITORING_THRESHOLD = 1.0 / 3.0;\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/IEventHubDataAdapter.cs",
    "content": "using System;\nusing Azure.Messaging.EventHubs;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    public interface IEventHubDataAdapter : IQueueDataAdapter<EventData>, ICacheDataAdapter\n    {\n        CachedMessage FromQueueMessage(StreamPosition position, EventData queueMessage, DateTime dequeueTime, Func<int, ArraySegment<byte>> getSegment);\n\n        StreamPosition GetStreamPosition(string partition, EventData queueMessage);\n\n        string GetOffset(CachedMessage cachedMessage);\n\n        string GetPartitionKey(StreamId streamId);\n\n        StreamId GetStreamIdentity(EventData queueMessage);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/IEventHubQueueCache.cs",
    "content": "using System;\nusing Orleans.Streams;\nusing System.Collections.Generic;\nusing Azure.Messaging.EventHubs;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Interface for a stream message cache that stores EventHub EventData\n    /// </summary>\n    public interface IEventHubQueueCache : IQueueFlowController, IDisposable\n    {\n        /// <summary>\n        /// Add a list of EventHub EventData to the cache.\n        /// </summary>\n        /// <param name=\"message\"></param>\n        /// <param name=\"dequeueTimeUtc\"></param>\n        /// <returns></returns>\n        List<StreamPosition> Add(List<EventData> message, DateTime dequeueTimeUtc);\n\n        /// <summary>\n        /// Get a cursor into the cache to read events from a stream.\n        /// </summary>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"sequenceToken\"></param>\n        /// <returns></returns>\n        object GetCursor(StreamId streamId, StreamSequenceToken sequenceToken);\n        /// <summary>\n        /// Try to get the next message in the cache for the provided cursor.\n        /// </summary>\n        /// <param name=\"cursorObj\"></param>\n        /// <param name=\"message\"></param>\n        /// <returns></returns>\n        bool TryGetNextMessage(object cursorObj, out IBatchContainer message);\n\n        /// <summary>\n        /// Add cache pressure monitor to the cache's back pressure algorithm\n        /// </summary>\n        /// <param name=\"monitor\"></param>\n        void AddCachePressureMonitor(ICachePressureMonitor monitor);\n\n        /// <summary>\n        /// Send purge signal to the cache, the cache will perform a time based purge on its cached messages\n        /// </summary>\n        void SignalPurge();\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/IEventHubQueueCacheFactory.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Factory responsible for creating a message cache for an EventHub partition.\n    /// </summary>\n    public interface IEventHubQueueCacheFactory\n    {\n        /// <summary>\n        /// Function used to create a IEventHubQueueCache\n        /// </summary>\n        IEventHubQueueCache CreateCache(string partition, IStreamQueueCheckpointer<string> checkpointer, ILoggerFactory loggerFactory);\n    }\n}"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/IEventHubReceiver.cs",
    "content": "using Azure.Messaging.EventHubs;\nusing Azure.Messaging.EventHubs.Consumer;\nusing Azure.Messaging.EventHubs.Primitives;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Abstraction on EventhubReceiver class, used to configure EventHubReceiver class in EventhubAdapterReceiver,\n    /// also used to configure EHGeneratorReceiver in EventHubAdapterReceiver for testing purpose\n    /// </summary>\n    public interface IEventHubReceiver\n    {\n        /// <summary>\n        /// Send an async message to the partition asking for more messages\n        /// </summary>\n        /// <param name=\"maxCount\">Max amount of message which should be delivered in this request</param>\n        /// <param name=\"waitTime\">Wait time of this request</param>\n        /// <returns></returns>\n        Task<IEnumerable<EventData>> ReceiveAsync(int maxCount, TimeSpan waitTime);\n\n        /// <summary>\n        /// Send a clean up message\n        /// </summary>\n        /// <returns></returns>\n        Task CloseAsync();\n    }\n\n    /// <summary>\n    /// pass through decorator class for EventHubReceiver\n    /// </summary>\n    internal partial class EventHubReceiverProxy : IEventHubReceiver\n    {\n        private readonly PartitionReceiver client;\n\n        public EventHubReceiverProxy(EventHubPartitionSettings partitionSettings, string offset, ILogger logger)\n        {\n            var receiverOptions = new PartitionReceiverOptions();\n            if (partitionSettings.ReceiverOptions.PrefetchCount != null)\n            {\n                receiverOptions.PrefetchCount = partitionSettings.ReceiverOptions.PrefetchCount.Value;\n            }\n\n            var options = partitionSettings.Hub;\n            receiverOptions.ConnectionOptions = options.ConnectionOptions;\n            var connection = options.CreateConnection(options.ConnectionOptions);\n            this.client = new PartitionReceiver(options.ConsumerGroup, partitionSettings.Partition, GetEventPosition(), connection, receiverOptions);\n\n            EventPosition GetEventPosition()\n            {\n                EventPosition eventPosition;\n\n                // If we have a starting offset, read from offset\n                if (offset != EventHubConstants.StartOfStream)\n                {\n                    LogInfoStartingRead(logger, options.EventHubName, partitionSettings.Partition, offset);\n                    eventPosition = EventPosition.FromOffset(offset, true);\n                }\n                // else, if configured to start from now, start reading from most recent data\n                else if (partitionSettings.ReceiverOptions.StartFromNow)\n                {\n                    eventPosition = EventPosition.Latest;\n                    LogInfoStartingReadLatest(logger, options.EventHubName, partitionSettings.Partition);\n                }\n                else\n                // else, start reading from begining of the partition\n                {\n                    eventPosition = EventPosition.Earliest;\n                    LogInfoStartingReadBegin(logger, options.EventHubName, partitionSettings.Partition);\n                }\n\n                return eventPosition;\n            }\n        }\n\n        public async Task<IEnumerable<EventData>> ReceiveAsync(int maxCount, TimeSpan waitTime)\n        {\n            return await client.ReceiveBatchAsync(maxCount, waitTime);\n        }\n\n        public async Task CloseAsync()\n        {\n            await client.CloseAsync();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Starting to read from EventHub partition {EventHubName}-{Partition} at offset {Offset}\"\n        )]\n        private static partial void LogInfoStartingRead(ILogger logger, string eventHubName, string partition, string offset);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Starting to read latest messages from EventHub partition {EventHubName}-{Partition}.\"\n        )]\n        private static partial void LogInfoStartingReadLatest(ILogger logger, string eventHubName, string partition);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Starting to read messages from begining of EventHub partition {EventHubName}-{Partition}.\"\n        )]\n        private static partial void LogInfoStartingReadBegin(ILogger logger, string eventHubName, string partition);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/StatisticMonitors/DefaultEventHubBlockPoolMonitor.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streaming.EventHubs.StatisticMonitors\n{\n    /// <summary>\n    /// Default monitor for Object pool used by EventHubStreamProvider\n    /// </summary>\n    public class DefaultEventHubBlockPoolMonitor : DefaultBlockPoolMonitor\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        public DefaultEventHubBlockPoolMonitor(EventHubBlockPoolMonitorDimensions dimensions) : base(new KeyValuePair<string, object>[] { new(\"Path\", dimensions.EventHubPath), new(\"ObjectPoolId\", dimensions.BlockPoolId) })\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/StatisticMonitors/DefaultEventHubCacheMonitor.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streaming.EventHubs.StatisticMonitors\n{\n    /// <summary>\n    /// Default cache monitor for eventhub streaming provider ecosystem\n    /// </summary>\n    public class DefaultEventHubCacheMonitor : DefaultCacheMonitor\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        public DefaultEventHubCacheMonitor(EventHubCacheMonitorDimensions dimensions)\n            : base(new KeyValuePair<string, object>[] { new(\"Path\", dimensions.EventHubPath), new(\"Partition\", dimensions.EventHubPartition) })\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/StatisticMonitors/DefaultEventHubReceiverMonitor.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Default EventHub receiver monitor that tracks metrics using loggers PKI support.\n    /// </summary>\n    public class DefaultEventHubReceiverMonitor : DefaultQueueAdapterReceiverMonitor\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\">Aggregation Dimension bag for EventhubReceiverMonitor</param>\n        public DefaultEventHubReceiverMonitor(EventHubReceiverMonitorDimensions dimensions)\n            : base(new KeyValuePair<string, object>[] { new(\"Path\", dimensions.EventHubPath), new(\"Partition\", dimensions.EventHubPartition) })\n        {\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/StatisticMonitors/MonitorAggregationDimentions.cs",
    "content": "\nnamespace Orleans.Streaming.EventHubs\n{\n    /// <summary>\n    /// Base class for monitor aggregation dimensions, which is an information bag for the monitoring target. \n    /// Monitors can use this information bag to build its aggregation dimensions.\n    /// </summary>\n    public class EventHubMonitorAggregationDimensions\n    {\n        /// <summary>\n        /// Eventhub path\n        /// </summary>\n        public string EventHubPath { get; set; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"ehHubPath\"></param>\n        public EventHubMonitorAggregationDimensions(string ehHubPath)\n        {\n            this.EventHubPath = ehHubPath;\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        public EventHubMonitorAggregationDimensions(EventHubMonitorAggregationDimensions dimensions)\n        {\n            this.EventHubPath = dimensions.EventHubPath;\n        }\n\n        /// <summary>\n        /// Zero parameter constructor\n        /// </summary>\n        public EventHubMonitorAggregationDimensions()\n        {\n        }\n    }\n\n    /// <summary>\n    /// Aggregation dimensions for EventHubReceiverMonitor\n    /// </summary>\n    public class EventHubReceiverMonitorDimensions : EventHubMonitorAggregationDimensions\n    {\n        /// <summary>\n        /// Eventhub partition\n        /// </summary>\n        public string EventHubPartition { get; set; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        /// <param name=\"ehPartition\"></param>\n        public EventHubReceiverMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string ehPartition)\n            :base(dimensions)\n        {\n            this.EventHubPartition = ehPartition;\n        }\n\n        /// <summary>\n        /// Zero parameter constructor\n        /// </summary>\n        public EventHubReceiverMonitorDimensions()\n        {\n        }\n    }\n\n    /// <summary>\n    /// Aggregation dimensions for cache monitor used in Eventhub stream provider ecosystem\n    /// </summary>\n    public class EventHubCacheMonitorDimensions : EventHubReceiverMonitorDimensions\n    {\n        /// <summary>\n        /// Block pool this cache belongs to\n        /// </summary>\n        public string BlockPoolId { get; set; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        /// <param name=\"ehPartition\"></param>\n        /// <param name=\"blockPoolId\"></param>\n        public EventHubCacheMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string ehPartition, string blockPoolId)\n            :base(dimensions, ehPartition)\n        {\n            this.BlockPoolId = blockPoolId;\n        }\n\n        /// <summary>\n        /// Zero parameters constructor\n        /// </summary>\n        public EventHubCacheMonitorDimensions()\n        {\n        }\n    }\n\n    /// <summary>\n    /// Aggregation dimensions for block pool monitor used in Eventhub stream provider ecosystem\n    /// </summary>\n    public class EventHubBlockPoolMonitorDimensions : EventHubMonitorAggregationDimensions\n    {\n        /// <summary>\n        /// Block pool Id\n        /// </summary>\n        public string BlockPoolId { get; set; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"dimensions\"></param>\n        /// <param name=\"blockPoolId\"></param>\n        public EventHubBlockPoolMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string blockPoolId)\n            :base(dimensions)\n        {\n            this.BlockPoolId = blockPoolId;\n        }\n\n        /// <summary>\n        /// Zero parameter constructor\n        /// </summary>\n        public EventHubBlockPoolMonitorDimensions()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Streaming.EventHubs/README.md",
    "content": "# Microsoft Orleans Stream Provider for Azure Event Hubs\n\n## Introduction\nMicrosoft Orleans Stream Provider for Azure Event Hubs enables Orleans applications to leverage Azure Event Hubs for reliable, scalable event processing. This provider allows you to use Event Hubs as a streaming backbone for your Orleans application to both produce and consume streams of events.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Streaming.EventHubs\n```\n\n## Example - Configuring Event Hubs Stream Provider\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nnamespace ExampleGrains;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Azure Event Hubs as a stream provider\n            .AddEventHubStreams(\n                \"EventHubStreamProvider\",\n                configurator => \n                {\n                    configurator.ConfigureEventHub(builder => builder.Configure(options => \n                    {\n                        options.ConnectionString = \"YOUR_EVENT_HUB_CONNECTION_STRING\";\n                        options.ConsumerGroup = \"YOUR_CONSUMER_GROUP\"; // Default is \"$Default\"\n                        options.Path = \"YOUR_EVENT_HUB_NAME\";\n                    }));\n                    \n                    configurator.UseAzureTableCheckpointer(builder => builder.Configure(options => \n                    {\n                        options.ConnectionString = \"YOUR_STORAGE_CONNECTION_STRING\";\n                        options.TableName = \"EventHubCheckpoints\"; // Optional\n                    }));\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Event Hub Streams in a Grain\n\n```csharp\n// Grain interface\npublic interface IStreamProcessingGrain : IGrainWithGuidKey\n{\n    Task StartProcessing();\n}\n\n// Grain implementation\npublic class StreamProcessingGrain : Grain, IStreamProcessingGrain\n{\n    private IStreamProvider _streamProvider;\n    private IAsyncStream<MyEvent> _stream;\n    private StreamSubscriptionHandle<MyEvent> _subscription;\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get the stream provider\n        _streamProvider = GetStreamProvider(\"EventHubStreamProvider\");\n        \n        // Get a reference to a specific stream\n        _stream = _streamProvider.GetStream<MyEvent>(this.GetPrimaryKey(), \"MyStreamNamespace\");\n        \n        await base.OnActivateAsync(cancellationToken);\n    }\n\n    public async Task StartProcessing()\n    {\n        // Subscribe to the stream to process events\n        _subscription = await _stream.SubscribeAsync(OnNextAsync);\n    }\n\n    private Task OnNextAsync(MyEvent evt, StreamSequenceToken token)\n    {\n        Console.WriteLine($\"Received event: {evt.Data}\");\n        return Task.CompletedTask;\n    }\n\n    // Produce an event to the stream\n    public Task SendEvent(MyEvent evt)\n    {\n        return _stream.OnNextAsync(evt);\n    }\n}\n\n// Event class\n\npublic class MyEvent\n{\n    public string Data { get; set; }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Streams](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/)\n- [Event Hubs integration](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/streams-implementation)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/Hosting/AzureTableTransactionServicecollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.AzureStorage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class AzureTableTransactionServicecollectionExtensions\n    {\n        internal static IServiceCollection AddAzureTableTransactionalStateStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<AzureTableTransactionalStateOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<AzureTableTransactionalStateOptions>(name));\n            services.AddTransient<IConfigurationValidator>(sp => new AzureTableTransactionalStateOptionsValidator(sp.GetRequiredService<IOptionsMonitor<AzureTableTransactionalStateOptions>>().Get(name), name));\n\n            services.TryAddSingleton<ITransactionalStateStorageFactory>(sp => sp.GetKeyedService<ITransactionalStateStorageFactory>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n            services.AddKeyedSingleton<ITransactionalStateStorageFactory>(name, (sp, key) => AzureTableTransactionalStateStorageFactory.Create(sp, key as string));\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>>(s => (ILifecycleParticipant<ISiloLifecycle>)s.GetRequiredKeyedService<ITransactionalStateStorageFactory>(name));\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/Hosting/AzureTableTransactionsSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    public static class AzureTableTransactionSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use azure table storage as the default transactional grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableTransactionalStateStorageAsDefault(this ISiloBuilder builder, Action<AzureTableTransactionalStateOptions> configureOptions)\n        {\n            return builder.AddAzureTableTransactionalStateStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage for transactional grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableTransactionalStateStorage(this ISiloBuilder builder, string name, Action<AzureTableTransactionalStateOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableTransactionalStateStorage(name, ob => ob.Configure(configureOptions)));\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage as the default transactional grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableTransactionalStateStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<AzureTableTransactionalStateOptions>> configureOptions = null)\n        {\n            return builder.AddAzureTableTransactionalStateStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use azure table storage for transactional grain storage.\n        /// </summary>\n        public static ISiloBuilder AddAzureTableTransactionalStateStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<AzureTableTransactionalStateOptions>> configureOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddAzureTableTransactionalStateStorage(name, configureOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/Orleans.Transactions.AzureStorage.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Transactions.AzureStorage</PackageId>\n    <Title>Microsoft Orleans Azure Storage Transactions Provider</Title>\n    <Description>Microsoft Orleans transactions storage provider backed by Azure Storage</Description>\n    <PackageTags>$(PackageTags) Azure Transactions</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Transactions.AzureStorage</AssemblyName>\n    <RootNamespace>Orleans.Transactions.AzureStorage</RootNamespace>\n    <DefineConstants>$(DefineConstants);ORLEANS_TRANSACTIONS</DefineConstants>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableDataManager.cs\" Link=\"Storage\\AzureTableDataManager.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureTableUtils.cs\" Link=\"Storage\\AzureTableUtils.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStorageOperationOptions.cs\" Link=\"Storage\\AzureStorageOperationOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Storage\\AzureStoragePolicyOptions.cs\" Link=\"Storage\\AzureStoragePolicyOptions.cs\" />\n    <Compile Include=\"..\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Core\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n    <ProjectReference Include=\"..\\..\\Orleans.Transactions\\Orleans.Transactions.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/README.md",
    "content": "# Microsoft Orleans Transactions for Azure Storage\n\n## Introduction\nMicrosoft Orleans Transactions for Azure Storage provides the infrastructure to store Orleans transaction logs in Azure Storage. This package allows Orleans applications to use ACID transactions across multiple grain calls with Azure Storage as the backing transaction log store.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Transactions.AzureStorage\n```\n\n## Example - Configuring Azure Storage for Transactions\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Transactions;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Enable transactions\n            .AddAzureTableTransactionalStateStorage(\n                name: \"TransactionStore\",\n                configureOptions: options =>\n                {\n                    options.ConnectionString = \"YOUR_AZURE_STORAGE_CONNECTION_STRING\";\n                })\n            .UseTransactions();\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Transactions in Grains\n```csharp\n// A grain with transactional state\npublic class MyTransactionalGrain : Grain, IMyTransactionalGrain\n{\n    private readonly ITransactionalState<MyState> _state;\n\n    // Inject the transactional state\n    public MyTransactionalGrain(\n        [TransactionalState(\"state\", \"TransactionStore\")]\n        ITransactionalState<MyState> state)\n    {\n        _state = state;\n    }\n\n    // Method that performs a transaction\n    [Transaction(TransactionOption.Create)]\n    public async Task Transfer(string otherGrainKey, int amount)\n    {\n        // Read our state within the transaction\n        var myState = await _state.PerformRead(state => state);\n        \n        // Ensure we have enough balance\n        if (myState.Balance < amount)\n            throw new InvalidOperationException(\"Insufficient funds\");\n            \n        // Update our state within the transaction\n        await _state.PerformUpdate(s => s.Balance -= amount);\n        \n        // Call another grain within the same transaction\n        var otherGrain = GrainFactory.GetGrain<IMyTransactionalGrain>(otherGrainKey);\n        await otherGrain.Deposit(amount);\n    }\n\n    // Method that participates in a transaction\n    [Transaction(TransactionOption.Join)]\n    public Task Deposit(int amount)\n    {\n        // Update state within the joined transaction\n        return _state.PerformUpdate(s => s.Balance += amount);\n    }\n\n    // Read operation within a transaction\n    [Transaction(TransactionOption.CreateOrJoin)]\n    public Task<int> GetBalance()\n    {\n        return _state.PerformRead(s => s.Balance);\n    }\n}\n\n// State class\n\npublic class MyState\n{\n    public int Balance { get; set; }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Transactions](https://learn.microsoft.com/en-us/dotnet/orleans/grains/transactions)\n- [Distributed ACID Transactions](https://learn.microsoft.com/en-us/dotnet/orleans/grains/transactions/acid-transactions)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/AzureTableTransactionalStateOptions.cs",
    "content": "using Orleans.Transactions.AzureStorage;\n\nnamespace Orleans.Configuration\n{\n    public class AzureTableTransactionalStateOptions : AzureStorageOperationOptions\n    {\n        /// <summary>\n        /// Azure table where transactional grain state will be stored\n        /// </summary>\n        public override string TableName { get; set; } = \"TransactionalState\";\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n    }\n\n    /// <summary>\n    /// Configuration validator for <see cref=\"AzureTableTransactionalStateOptions\"/>.\n    /// </summary>\n    public class AzureTableTransactionalStateOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableTransactionalStateOptions>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AzureTableTransactionalStateOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The option to be validated.</param>\n        /// <param name=\"name\">The option name to be validated.</param>\n        public AzureTableTransactionalStateOptionsValidator(AzureTableTransactionalStateOptions options, string name) : base(options, name)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/AzureTableTransactionalStateStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Newtonsoft.Json;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage\n{\n    public partial class AzureTableTransactionalStateStorage<TState> : ITransactionalStateStorage<TState>\n        where TState : class, new()\n    {\n        private readonly TableClient table;\n        private readonly string partition;\n        private readonly JsonSerializerSettings jsonSettings;\n        private readonly ILogger logger;\n\n        private KeyEntity key;\n        private List<KeyValuePair<long, StateEntity>> states;\n\n        public AzureTableTransactionalStateStorage(TableClient table, string partition, JsonSerializerSettings JsonSettings, ILogger<AzureTableTransactionalStateStorage<TState>> logger)\n        {\n            this.table = table;\n            this.partition = partition;\n            this.jsonSettings = JsonSettings;\n            this.logger = logger;\n\n            // default values must be included\n            // otherwise, we get errors for explicitly specified default values\n            // (e.g.  Orleans.Transactions.Azure.Tests.TestState.state)\n            this.jsonSettings.DefaultValueHandling = DefaultValueHandling.Include;\n        }\n\n        public async Task<TransactionalStorageLoadResponse<TState>> Load()\n        {\n            try\n            {\n                var keyTask = ReadKey();\n                var statesTask = ReadStates();\n                key = await keyTask.ConfigureAwait(false);\n                states = await statesTask.ConfigureAwait(false);\n\n                if (string.IsNullOrEmpty(key.ETag.ToString()))\n                {\n                    LogDebugLoadedV0Fresh(partition);\n\n                    // first time load\n                    return new TransactionalStorageLoadResponse<TState>();\n                }\n                else\n                {\n                    TState committedState;\n                    if (this.key.CommittedSequenceId == 0)\n                    {\n                        committedState = new TState();\n                    }\n                    else\n                    {\n                        if (!FindState(this.key.CommittedSequenceId, out var pos))\n                        {\n                            var error = $\"Storage state corrupted: no record for committed state v{this.key.CommittedSequenceId}\";\n                            LogCriticalPartitionError(partition, error);\n                            throw new InvalidOperationException(error);\n                        }\n                        committedState = states[pos].Value.GetState<TState>(this.jsonSettings);\n                    }\n\n                    var PrepareRecordsToRecover = new List<PendingTransactionState<TState>>();\n                    for (int i = 0; i < states.Count; i++)\n                    {\n                        var kvp = states[i];\n\n                        // pending states for already committed transactions can be ignored\n                        if (kvp.Key <= key.CommittedSequenceId)\n                            continue;\n\n                        // upon recovery, local non-committed transactions are considered aborted\n                        if (kvp.Value.TransactionManager == null)\n                            break;\n\n                        ParticipantId tm = JsonConvert.DeserializeObject<ParticipantId>(kvp.Value.TransactionManager, this.jsonSettings);\n\n                        PrepareRecordsToRecover.Add(new PendingTransactionState<TState>()\n                        {\n                            SequenceId = kvp.Key,\n                            State = kvp.Value.GetState<TState>(this.jsonSettings),\n                            TimeStamp = kvp.Value.TransactionTimestamp,\n                            TransactionId = kvp.Value.TransactionId,\n                            TransactionManager = tm\n                        });\n                    }\n\n                    // clear the state strings... no longer needed, ok to GC now\n                    for (int i = 0; i < states.Count; i++)\n                    {\n                        var entity = states[i].Value;\n                        entity.StateJson = null;\n                    }\n\n                    LogDebugLoadedPartitionKeyRows(partition, this.key.CommittedSequenceId, new(states));\n\n                    TransactionalStateMetaData metadata = JsonConvert.DeserializeObject<TransactionalStateMetaData>(this.key.Metadata, this.jsonSettings);\n                    return new TransactionalStorageLoadResponse<TState>(this.key.ETag.ToString(), committedState, this.key.CommittedSequenceId, metadata, PrepareRecordsToRecover);\n                }\n            }\n            catch (Exception ex)\n            {\n                LogErrorTransactionalStateLoadFailed(ex);\n                throw;\n            }\n        }\n\n        public async Task<string> Store(string expectedETag, TransactionalStateMetaData metadata, List<PendingTransactionState<TState>> statesToPrepare, long? commitUpTo, long? abortAfter)\n        {\n            var keyETag = key.ETag.ToString();\n            if ((!string.IsNullOrWhiteSpace(keyETag) || !string.IsNullOrWhiteSpace(expectedETag)) && keyETag != expectedETag)\n            {\n                throw new ArgumentException(nameof(expectedETag), \"Etag does not match\");\n            }\n\n            // assemble all storage operations into a single batch\n            // these operations must commit in sequence, but not necessarily atomically\n            // so we can split this up if needed\n            var batchOperation = new BatchOperation(logger, key, table);\n\n            // first, clean up aborted records\n            if (abortAfter.HasValue && states.Count != 0)\n            {\n                while (states.Count > 0 && states[states.Count - 1].Key > abortAfter)\n                {\n                    var entity = states[states.Count - 1].Value;\n                    await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.Delete, entity.Entity, entity.ETag)).ConfigureAwait(false);\n                    key.ETag = batchOperation.KeyETag;\n                    states.RemoveAt(states.Count - 1);\n\n                    LogTraceDeleteTransaction(partition, entity.RowKey, entity.TransactionId);\n                }\n            }\n\n            // second, persist non-obsolete prepare records\n            var obsoleteBefore = commitUpTo.HasValue ? commitUpTo.Value : key.CommittedSequenceId;\n            if (statesToPrepare != null)\n                foreach (var s in statesToPrepare)\n                    if (s.SequenceId >= obsoleteBefore)\n                    {\n                        if (FindState(s.SequenceId, out var pos))\n                        {\n                            // overwrite with new pending state\n                            StateEntity existing = states[pos].Value;\n                            existing.TransactionId = s.TransactionId;\n                            existing.TransactionTimestamp = s.TimeStamp;\n                            existing.TransactionManager = JsonConvert.SerializeObject(s.TransactionManager, this.jsonSettings);\n                            existing.SetState(s.State, this.jsonSettings);\n                            await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, existing.Entity, existing.ETag)).ConfigureAwait(false);\n                            key.ETag = batchOperation.KeyETag;\n\n                            LogTraceUpdateTransaction(partition, existing.RowKey, existing.TransactionId);\n                        }\n                        else\n                        {\n                            var entity = StateEntity.Create(this.jsonSettings, this.partition, s);\n                            await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.Add, entity.Entity)).ConfigureAwait(false);\n                            key.ETag = batchOperation.KeyETag;\n                            states.Insert(pos, new KeyValuePair<long, StateEntity>(s.SequenceId, entity));\n\n                            LogTraceInsertTransaction(partition, entity.RowKey, entity.TransactionId);\n                        }\n                    }\n\n            // third, persist metadata and commit position\n            key.Metadata = JsonConvert.SerializeObject(metadata, this.jsonSettings);\n            if (commitUpTo.HasValue && commitUpTo.Value > key.CommittedSequenceId)\n            {\n                key.CommittedSequenceId = commitUpTo.Value;\n            }\n            if (string.IsNullOrEmpty(this.key.ETag.ToString()))\n            {\n                await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.Add, key)).ConfigureAwait(false);\n                key.ETag = batchOperation.KeyETag;\n\n                LogTraceInsertWithCount(partition, KeyEntity.RK, this.key.CommittedSequenceId, metadata.CommitRecords.Count);\n            }\n            else\n            {\n                await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, key, key.ETag)).ConfigureAwait(false);\n                key.ETag = batchOperation.KeyETag;\n\n                LogTraceUpdateWithCount(partition, KeyEntity.RK, this.key.CommittedSequenceId, metadata.CommitRecords.Count);\n            }\n\n            // fourth, remove obsolete records\n            if (states.Count > 0 && states[0].Key < obsoleteBefore)\n            {\n                FindState(obsoleteBefore, out var pos);\n                for (int i = 0; i < pos; i++)\n                {\n                    await batchOperation.Add(new TableTransactionAction(TableTransactionActionType.Delete, states[i].Value.Entity, states[i].Value.ETag)).ConfigureAwait(false);\n                    key.ETag = batchOperation.KeyETag;\n\n                    LogTraceDeleteTransaction(partition, states[i].Value.RowKey, states[i].Value.TransactionId);\n                }\n                states.RemoveRange(0, pos);\n            }\n\n            await batchOperation.Flush().ConfigureAwait(false);\n\n            LogDebugStoredETag(partition, this.key.CommittedSequenceId, key.ETag);\n\n            return key.ETag.ToString();\n        }\n\n        private bool FindState(long sequenceId, out int pos)\n        {\n            pos = 0;\n            while (pos < states.Count)\n            {\n                switch (states[pos].Key.CompareTo(sequenceId))\n                {\n                    case 0:\n                        return true;\n                    case -1:\n                        pos++;\n                        continue;\n                    case 1:\n                        return false;\n                }\n            }\n            return false;\n        }\n\n        private async Task<KeyEntity> ReadKey()\n        {\n            var queryResult = table.QueryAsync<KeyEntity>(AzureTableUtils.PointQuery(this.partition, KeyEntity.RK)).ConfigureAwait(false);\n            await foreach (var result in queryResult)\n            {\n                return result;\n            }\n\n            return new KeyEntity()\n            {\n                PartitionKey = partition,\n                RowKey = KeyEntity.RK\n            };\n        }\n\n        private async Task<List<KeyValuePair<long, StateEntity>>> ReadStates()\n        {\n            var query = AzureTableUtils.RangeQuery(this.partition, StateEntity.RK_MIN, StateEntity.RK_MAX);\n            var results = new List<KeyValuePair<long, StateEntity>>();\n            var queryResult = table.QueryAsync<TableEntity>(query).ConfigureAwait(false);\n            await foreach (var entity in queryResult)\n            {\n                var state = new StateEntity(entity);\n                results.Add(new KeyValuePair<long, StateEntity>(state.SequenceId, state));\n            };\n            return results;\n        }\n\n        private class BatchOperation\n        {\n            private readonly List<TableTransactionAction> batchOperation;\n            private readonly ILogger logger;\n            private readonly TableClient table;\n            private KeyEntity key;\n\n            private int keyIndex = -1;\n\n            public BatchOperation(ILogger logger, KeyEntity key, TableClient table)\n            {\n                this.batchOperation = new();\n                this.logger = logger;\n                this.key = key;\n                this.table = table;\n            }\n\n            public ETag KeyETag => key.ETag;\n            private bool BatchHasKey => keyIndex >= 0;\n\n            public async ValueTask Add(TableTransactionAction operation)\n            {\n                if (!BatchHasKey && operation.Entity.RowKey == key.RowKey && operation.Entity.PartitionKey == key.PartitionKey)\n                {\n                    key = (KeyEntity)operation.Entity;\n                    keyIndex = batchOperation.Count;\n                }\n\n                batchOperation.Add(operation);\n\n                if (batchOperation.Count == AzureTableConstants.MaxBatchSize - (BatchHasKey ? 0 : 1))\n                {\n                    // the key serves as a synchronizer, to prevent modification by multiple grains under edge conditions,\n                    // like duplicate activations or deployments.Every batch write needs to include the key,\n                    // even if the key values don't change.\n\n                    if (!BatchHasKey)\n                    {\n                        keyIndex = batchOperation.Count;\n                        if (string.IsNullOrEmpty(key.ETag.ToString()))\n                        {\n                            batchOperation.Add(new TableTransactionAction(TableTransactionActionType.Add, key));\n                        }\n                        else\n                        {\n                            batchOperation.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, key, key.ETag));\n                        }\n                    }\n\n                    await Flush().ConfigureAwait(false);\n                }\n            }\n\n            public async Task Flush()\n            {\n                if (batchOperation.Count > 0)\n                {\n                    try\n                    {\n                        var batchResponse = await table.SubmitTransactionAsync(batchOperation).ConfigureAwait(false);\n                        if (batchResponse?.Value is { Count: > 0 } responses)\n                        {\n                            if (BatchHasKey && responses.Count >= keyIndex && responses[keyIndex].Headers.ETag is { } etag)\n                            {\n                                key.ETag = etag;\n                            }\n                        }\n\n                        if (logger.IsEnabled(LogLevel.Trace))\n                        {\n                            for (int i = 0; i < batchOperation.Count; i++)\n                            {\n                                LogTraceBatchOpOk(logger, batchOperation[i].Entity.PartitionKey, batchOperation[i].Entity.RowKey, i);\n                            }\n                        }\n\n                        batchOperation.Clear();\n                        keyIndex = -1;\n                    }\n                    catch (Exception ex)\n                    {\n                        if (logger.IsEnabled(LogLevel.Trace))\n                        {\n                            for (int i = 0; i < batchOperation.Count; i++)\n                            {\n                                LogTraceBatchOpFailed(logger, batchOperation[i].Entity.PartitionKey, batchOperation[i].Entity.RowKey, i);\n                            }\n                        }\n\n                        LogErrorTransactionalStateStoreFailed(logger, ex);\n                        throw;\n                    }\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{Partition} Loaded v0, fresh\"\n        )]\n        private partial void LogDebugLoadedV0Fresh(string partition);\n\n        [LoggerMessage(\n            Level = LogLevel.Critical,\n            Message = \"{Partition} {Error}\"\n        )]\n        private partial void LogCriticalPartitionError(string partition, string error);\n\n        private readonly struct StatesLogRecord(List<KeyValuePair<long, StateEntity>> states)\n        {\n            public override string ToString() => string.Join(\",\", states.Select(s => s.Key.ToString(\"x16\")));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{PartitionKey} Loaded v{CommittedSequenceId} rows={Data}\"\n        )]\n        private partial void LogDebugLoadedPartitionKeyRows(string partitionKey, long committedSequenceId, StatesLogRecord data);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Transactional state load failed\"\n        )]\n        private partial void LogErrorTransactionalStateLoadFailed(Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} Delete {TransactionId}\"\n        )]\n        private partial void LogTraceDeleteTransaction(string partitionKey, string rowKey, string transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} Update {TransactionId}\"\n        )]\n        private partial void LogTraceUpdateTransaction(string partitionKey, string rowKey, string transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} Insert {TransactionId}\"\n        )]\n        private partial void LogTraceInsertTransaction(string partitionKey, string rowKey, string transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} Insert. v{CommittedSequenceId}, {CommitRecordsCount}c\"\n        )]\n        private partial void LogTraceInsertWithCount(string partitionKey, string rowKey, long committedSequenceId, int commitRecordsCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} Update. v{CommittedSequenceId}, {CommitRecordsCount}c\"\n        )]\n        private partial void LogTraceUpdateWithCount(string partitionKey, string rowKey, long committedSequenceId, int commitRecordsCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{PartitionKey} Stored v{CommittedSequenceId} eTag={ETag}\"\n        )]\n        private partial void LogDebugStoredETag(string partitionKey, long committedSequenceId, ETag eTag);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} batch-op ok {BatchCount}\"\n        )]\n        private static partial void LogTraceBatchOpOk(ILogger logger, string partitionKey, string rowKey, int batchCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{PartitionKey}.{RowKey} batch-op failed {BatchCount}\"\n        )]\n        private static partial void LogTraceBatchOpFailed(ILogger logger, string partitionKey, string rowKey, int batchCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Transactional state store failed.\"\n        )]\n        private static partial void LogErrorTransactionalStateStoreFailed(ILogger logger, Exception ex);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/AzureTableTransactionalStateStorageFactory.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage\n{\n    public class AzureTableTransactionalStateStorageFactory : ITransactionalStateStorageFactory, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly string name;\n        private readonly AzureTableTransactionalStateOptions options;\n        private readonly ClusterOptions clusterOptions;\n        private readonly JsonSerializerSettings jsonSettings;\n        private readonly ILoggerFactory loggerFactory;\n        private TableClient table;\n\n        public static ITransactionalStateStorageFactory Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<AzureTableTransactionalStateOptions>>();\n            return ActivatorUtilities.CreateInstance<AzureTableTransactionalStateStorageFactory>(services, name, optionsMonitor.Get(name));\n        }\n\n        public AzureTableTransactionalStateStorageFactory(string name, AzureTableTransactionalStateOptions options, IOptions<ClusterOptions> clusterOptions, IServiceProvider services, ILoggerFactory loggerFactory)\n        {\n            this.name = name;\n            this.options = options;\n            this.clusterOptions = clusterOptions.Value;\n            this.jsonSettings = TransactionalStateFactory.GetJsonSerializerSettings(services);\n            this.loggerFactory = loggerFactory;\n        }\n\n        public ITransactionalStateStorage<TState> Create<TState>(string stateName, IGrainContext context) where TState : class, new()\n        {\n            string partitionKey = MakePartitionKey(context, stateName);\n            return ActivatorUtilities.CreateInstance<AzureTableTransactionalStateStorage<TState>>(context.ActivationServices, this.table, partitionKey, this.jsonSettings);\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<AzureTableTransactionalStateStorageFactory>(this.name), this.options.InitStage, Init);\n        }\n\n        private string MakePartitionKey(IGrainContext context, string stateName)\n        {\n            string grainKey = context.GrainReference.GrainId.ToString();\n            var key = $\"{grainKey}_{this.clusterOptions.ServiceId}_{stateName}\";\n            return AzureTableUtils.SanitizeTableProperty(key);\n        }\n\n        private async Task CreateTable()\n        {\n            var tableManager = new AzureTableDataManager<TableEntity>(\n                this.options,\n                this.loggerFactory.CreateLogger<AzureTableDataManager<TableEntity>>());\n            await tableManager.InitTableAsync();\n            this.table = tableManager.Table;\n        }\n\n        private Task Init(CancellationToken cancellationToken)\n        {\n            return CreateTable();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/KeyEntity.cs",
    "content": "using System;\nusing Azure;\nusing Azure.Data.Tables;\n\nnamespace Orleans.Transactions.AzureStorage\n{\n    internal class KeyEntity : ITableEntity\n    {\n        public const string RK = \"k\";\n\n        public KeyEntity()\n        {\n            this.RowKey = RK;\n        }\n\n        public long CommittedSequenceId { get; set; }\n        public string Metadata { get; set; }\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/StateEntity.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing Azure;\nusing Azure.Data.Tables;\nusing Newtonsoft.Json;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage\n{\n    internal readonly struct StateEntity\n    {\n        // Each property can hold 64KB of data and each entity can take 1MB in total, so 15 full properties take\n        // 15 * 64 = 960 KB leaving room for the primary key, timestamp etc\n        private const int MAX_DATA_CHUNK_SIZE = 64 * 1024;\n        private const int MAX_STRING_PROPERTY_LENGTH = 32 * 1024;\n        private const int MAX_DATA_CHUNKS_COUNT = 15;\n        private const string STRING_DATA_PROPERTY_NAME_PREFIX = nameof(StateJson);\n\n        private static readonly string[] StringDataPropertyNames = GetPropertyNames().ToArray();\n\n        public TableEntity Entity { get; }\n\n        public StateEntity(TableEntity entity) => Entity = entity;\n\n        public string PartitionKey => Entity.PartitionKey;\n        public string RowKey => Entity.RowKey;\n        public DateTimeOffset? Timestamp => Entity.Timestamp;\n        public ETag ETag => Entity.ETag;\n\n        public static string MakeRowKey(long sequenceId)\n        {\n            return $\"{RK_PREFIX}{sequenceId.ToString(\"x16\")}\";\n        }\n\n        public long SequenceId => long.Parse(this.RowKey[RK_PREFIX.Length..], NumberStyles.AllowHexSpecifier);\n\n        // Row keys range from s0000000000000001 to s7fffffffffffffff\n        public const string RK_PREFIX = \"s_\";\n        public const string RK_MIN = RK_PREFIX;\n        public const string RK_MAX = RK_PREFIX + \"~\";\n\n        public string TransactionId\n        {\n            get => this.GetPropertyOrDefault(nameof(this.TransactionId)) as string;\n            set => this.Entity[nameof(this.TransactionId)] = value;\n        }\n\n        public DateTime TransactionTimestamp\n        {\n            get => this.Entity.GetDateTimeOffset(nameof(this.TransactionTimestamp)).GetValueOrDefault().UtcDateTime;\n            set => this.Entity[nameof(this.TransactionTimestamp)] = new DateTimeOffset(value.ToUniversalTime());\n        }\n\n        public string TransactionManager\n        {\n            get => this.GetPropertyOrDefault(nameof(this.TransactionManager)) as string;\n            set => this.Entity[nameof(this.TransactionManager)] = value;\n        }\n\n        public string StateJson { get => this.GetStateInternal(); set => this.SetStateInternal(value); }\n\n        public static StateEntity Create<T>(JsonSerializerSettings JsonSettings,\n            string partitionKey, PendingTransactionState<T> pendingState)\n            where T : class, new()\n        {\n            var entity = new TableEntity(partitionKey, MakeRowKey(pendingState.SequenceId));\n            var result = new StateEntity(entity)\n            {\n                TransactionId = pendingState.TransactionId,\n                TransactionTimestamp = pendingState.TimeStamp,\n                TransactionManager = JsonConvert.SerializeObject(pendingState.TransactionManager, JsonSettings),\n            };\n\n            result.SetState(pendingState.State, JsonSettings);\n            return result;\n        }\n\n        public T GetState<T>(JsonSerializerSettings jsonSettings)\n        {\n            return JsonConvert.DeserializeObject<T>(this.GetStateInternal(), jsonSettings);\n        }\n\n        public void SetState<T>(T state, JsonSerializerSettings jsonSettings)\n        {\n            this.SetStateInternal(JsonConvert.SerializeObject(state, jsonSettings));\n        }\n\n        private void SetStateInternal(string stringData)\n        {\n            CheckMaxDataSize((stringData ?? string.Empty).Length * 2, MAX_DATA_CHUNK_SIZE * MAX_DATA_CHUNKS_COUNT);\n\n            foreach (var key in StringDataPropertyNames)\n            {\n                this.Entity.Remove(key);\n            }\n\n            foreach (var entry in SplitStringData(stringData))\n            {\n                this.Entity[entry.Key] = entry.Value;\n            }\n\n            static IEnumerable<KeyValuePair<string, object>> SplitStringData(string stringData)\n            {\n                if (string.IsNullOrEmpty(stringData)) yield break;\n\n                var columnIndex = 0;\n                var stringStartIndex = 0;\n                while (stringStartIndex < stringData.Length)\n                {\n                    var chunkSize = Math.Min(MAX_STRING_PROPERTY_LENGTH, stringData.Length - stringStartIndex);\n\n                    var key = StringDataPropertyNames[columnIndex];\n                    var value = stringData.Substring(stringStartIndex, chunkSize);\n                    yield return new KeyValuePair<string, object>(key, value);\n\n                    columnIndex++;\n                    stringStartIndex += chunkSize;\n                }\n            }\n        }\n\n        private string GetStateInternal()\n        {\n            return string.Concat(ReadStringDataChunks(this.Entity));\n\n            static IEnumerable<string> ReadStringDataChunks(IDictionary<string, object> properties)\n            {\n                foreach (var stringDataPropertyName in StringDataPropertyNames)\n                {\n                    if (properties.TryGetValue(stringDataPropertyName, out var dataProperty))\n                    {\n                        if (dataProperty is string { Length: >0 } data)\n                        {\n                            yield return data;\n                        }\n                    }\n                }\n            }\n        }\n\n        private object GetPropertyOrDefault(string key)\n        {\n            this.Entity.TryGetValue(key, out var result);\n            return result;\n        }\n\n        private static void CheckMaxDataSize(int dataSize, int maxDataSize)\n        {\n            if (dataSize > maxDataSize)\n            {\n                var msg = string.Format(\"Data too large to write to table. Size={0} MaxSize={1}\", dataSize, maxDataSize);\n                throw new ArgumentOutOfRangeException(\"state\", msg);\n            }\n        }\n\n        private static IEnumerable<string> GetPropertyNames()\n        {\n            yield return STRING_DATA_PROPERTY_NAME_PREFIX;\n            for (var i = 1; i < MAX_DATA_CHUNKS_COUNT; ++i)\n            {\n                yield return STRING_DATA_PROPERTY_NAME_PREFIX + i.ToString(CultureInfo.InvariantCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Cosmos/BaseEntity.cs",
    "content": "using Newtonsoft.Json;\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.Cosmos;\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.Cosmos;\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.Cosmos;\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.Cosmos;\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.Cosmos;\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n\ninternal abstract class BaseEntity\n{\n    internal const string ID_FIELD = \"id\";\n    internal const string ETAG_FIELD = \"_etag\";    \n\n    [JsonProperty(ID_FIELD)]\n    [JsonPropertyName(ID_FIELD)]\n    public string Id { get; set; } = default!;\n\n    [JsonProperty(ETAG_FIELD)]\n    [JsonPropertyName(ETAG_FIELD)]\n    public string ETag { get; set; } = default!;\n}"
  },
  {
    "path": "src/Azure/Shared/Cosmos/CosmosIdSanitizer.cs",
    "content": "#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.Cosmos;\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.Cosmos;\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.Cosmos;\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.Cosmos;\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.Cosmos;\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n\ninternal static class CosmosIdSanitizer\n{\n    private const char EscapeChar = '~';\n    private static ReadOnlySpan<char> SanitizedCharacters => new[] { '/', '\\\\', '?', '#', SeparatorChar, EscapeChar };\n    private static ReadOnlySpan<char> ReplacementCharacters => new[] { '0', '1', '2', '3', '4', '5' };\n\n    public const char SeparatorChar = '_';\n\n    public static string Sanitize(string input)\n    {\n        var count = 0;\n        foreach (var c in input)\n        {\n            var charId = SanitizedCharacters.IndexOf(c);\n            if (charId >= 0)\n            {\n                ++count;\n            }\n        }\n\n        if (count == 0)\n        {\n            return input;\n        }\n\n        return string.Create(input.Length + count, input, static (output, input) =>\n        {\n            var i = 0;\n            foreach (var c in input)\n            {\n                var charId = SanitizedCharacters.IndexOf(c);\n                if (charId < 0)\n                {\n                    output[i++] = c;\n                    continue;\n                }\n\n                output[i++] = EscapeChar;\n                output[i++] = ReplacementCharacters[charId];\n            }\n        });\n    }\n\n    public static string Unsanitize(string input)\n    {\n        var count = 0;\n        foreach (var c in input)\n        {\n            if (c == EscapeChar)\n            {\n                ++count;\n            }\n        }\n\n        if (count == 0)\n        {\n            return input;\n        }\n\n        return string.Create(input.Length - count, input, static (output, input) =>\n        {\n            var i = 0;\n            var isEscaped = false;\n            foreach (var c in input)\n            {\n                if (isEscaped)\n                {\n                    var charId = ReplacementCharacters.IndexOf(c);\n                    if (charId < 0)\n                    {\n                        throw new ArgumentException($\"Input is not in a valid format: Encountered unsupported escape sequence\");\n                    }\n\n                    output[i++] = SanitizedCharacters[charId];\n                    isEscaped = false;\n                }\n                else if (c == EscapeChar)\n                {\n                    isEscaped = true;\n                }\n                else\n                {\n                    output[i++] = c;\n                }\n            }\n        });\n    }\n}"
  },
  {
    "path": "src/Azure/Shared/Cosmos/CosmosOptions.cs",
    "content": "using System.Net;\nusing Azure;\nusing Azure.Core;\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.Cosmos;\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.Cosmos;\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.Cosmos;\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.Cosmos;\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.Cosmos;\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n\n/// <summary>\n/// Options for Azure Cosmos DB storage.\n/// </summary>\npublic abstract class CosmosOptions\n{\n    /// <summary>\n    /// Tries to create the database and container used for clustering if it does not exist. Defaults to <see langword=\"false\"/>.\n    /// </summary>\n    public bool IsResourceCreationEnabled { get; set; }\n\n    /// <summary>\n    /// Database configured throughput. If set to <see langword=\"null\"/>, which is the default value, it will not be configured. \n    /// </summary>\n    /// <seealso href=\"https://learn.microsoft.com/azure/cosmos-db/set-throughput\"/>\n    public int? DatabaseThroughput { get; set; }\n\n    /// <summary>\n    /// The name of the database to use for clustering information. Defaults to <c>Orleans</c>.\n    /// </summary>\n    public string DatabaseName { get; set; } = \"Orleans\";\n\n    /// <summary>\n    /// The name of the container to use to store clustering information.\n    /// </summary>\n    public string ContainerName { get; set; } = default!;\n\n    /// <summary>\n    /// Throughput properties for containers. The default value is <see langword=\"null\"/>, which indicates that the serverless throughput mode will be used.\n    /// </summary>\n    /// <seealso href=\"https://learn.microsoft.com/azure/cosmos-db/set-throughput\"/>\n    public ThroughputProperties? ContainerThroughputProperties { get; set; }\n\n    /// <summary>\n    /// Delete the database on initialization. Intended only for testing scenarios.\n    /// </summary>\n    /// <remarks>This is only intended for use in testing scenarios.</remarks>\n    public bool CleanResourcesOnInitialization { get; set; }\n\n    /// <summary>\n    /// The options passed to the Cosmos DB client.\n    /// </summary>\n    public CosmosClientOptions ClientOptions { get; set; } = new();\n\n    /// <summary>\n    /// The operation executor used to execute operations using the Cosmos DB client.\n    /// </summary>\n    public ICosmosOperationExecutor OperationExecutor { get; set; } = DefaultCosmosOperationExecutor.Instance;\n\n    /// <summary>\n    /// Configures the Cosmos DB client.\n    /// </summary>\n    /// <param name=\"connectionString\">The connection string.</param>\n    /// <see cref=\"CosmosClient(string, CosmosClientOptions)\"/>\n    public void ConfigureCosmosClient(string connectionString)\n    {\n        CreateClient = _ => new(new CosmosClient(connectionString, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the Cosmos DB client.\n    /// </summary>\n    /// <param name=\"accountEndpoint\">The account endpoint. In the form of <code>https://{databaseaccount}.documents.azure.com:443/</code>, <see href=\"https://learn.microsoft.com/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest\"/></param>\n    /// <param name=\"authKeyOrResourceTokenCredential\"><see cref=\"AzureKeyCredential\"/> with master-key or resource token.</param>\n    /// <see cref=\"CosmosClient(string, AzureKeyCredential, CosmosClientOptions)\"/>\n    public void ConfigureCosmosClient(string accountEndpoint, AzureKeyCredential authKeyOrResourceTokenCredential)\n    {\n        CreateClient = _ => new(new CosmosClient(accountEndpoint, authKeyOrResourceTokenCredential, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the Cosmos DB client.\n    /// </summary>\n    /// <param name=\"accountEndpoint\">The account endpoint. In the form of <code>https://{databaseaccount}.documents.azure.com:443/</code>, <see href=\"https://learn.microsoft.com/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest\"/></param>\n    /// <param name=\"tokenCredential\">The token to provide AAD for authorization.</param>\n    /// <see cref=\"CosmosClient(string, TokenCredential, CosmosClientOptions)\"/>\n    public void ConfigureCosmosClient(string accountEndpoint, TokenCredential tokenCredential)\n    {\n        CreateClient = _ => new(new CosmosClient(accountEndpoint, tokenCredential, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the Cosmos DB client.\n    /// </summary>\n    /// <param name=\"accountEndpoint\">The account endpoint. In the form of <code>https://{databaseaccount}.documents.azure.com:443/</code>, <see href=\"https://learn.microsoft.com/rest/api/cosmos-db/cosmosdb-resource-uri-syntax-for-rest\"/></param>\n    /// <param name=\"authKeyOrResourceToken\">The Cosmos account key or resource token to use to create the client.</param>\n    /// <see cref=\"CosmosClient(string, TokenCredential, CosmosClientOptions)\"/>\n    public void ConfigureCosmosClient(string accountEndpoint, string authKeyOrResourceToken)\n    {\n        CreateClient = _ => new(new CosmosClient(accountEndpoint, authKeyOrResourceToken, ClientOptions));\n    }\n\n    /// <summary>\n    /// Configures the Cosmos DB client.\n    /// </summary>\n    /// <param name=\"createClient\">The delegate used to create the Cosmos DB client.</param>\n    public void ConfigureCosmosClient(Func<IServiceProvider, ValueTask<CosmosClient>> createClient)\n    {\n        CreateClient = createClient ?? throw new ArgumentNullException(nameof(createClient));\n    }\n\n    /// <summary>\n    /// Factory method for creating a <see cref=\"CosmosClient\"/>.\n    /// </summary>\n    internal Func<IServiceProvider, ValueTask<CosmosClient>> CreateClient { get; private set; } = null!;\n}\n\n/// <summary>\n/// Functionality for executing operations using the Cosmos DB client.\n/// </summary>\npublic interface ICosmosOperationExecutor\n{\n    /// <summary>\n    /// Executes the provided Cosmos DB operation.\n    /// </summary>\n    /// <typeparam name=\"TArg\">The function argument.</typeparam>\n    /// <typeparam name=\"TResult\">The result value.</typeparam>\n    /// <param name=\"func\">The delegate to execute.</param>\n    /// <param name=\"arg\">The argument to pass to delegate invocations.</param>\n    /// <returns>The result of invoking the delegate.</returns>\n    Task<TResult> ExecuteOperation<TArg, TResult>(Func<TArg, Task<TResult>> func, TArg arg);\n}\n\ninternal sealed class DefaultCosmosOperationExecutor : ICosmosOperationExecutor\n{\n    public static readonly DefaultCosmosOperationExecutor Instance = new();\n    private const HttpStatusCode TOO_MANY_REQUESTS = (HttpStatusCode)429;\n    public async Task<TResult> ExecuteOperation<TArg, TResult>(Func<TArg, Task<TResult>> func, TArg arg)\n    {\n        // From:  https://blogs.msdn.microsoft.com/bigdatasupport/2015/09/02/dealing-with-requestratetoolarge-errors-in-azure-documentdb-and-testing-performance/\n        while (true)\n        {\n            TimeSpan sleepTime;\n            try\n            {\n                return await func(arg).ConfigureAwait(false);\n            }\n            catch (CosmosException dce) when (dce.StatusCode == TOO_MANY_REQUESTS)\n            {\n                sleepTime = dce.RetryAfter ?? TimeSpan.Zero;\n            }\n            catch (AggregateException ae) when (ae.InnerException is CosmosException dce && dce.StatusCode == TOO_MANY_REQUESTS)\n            {\n                sleepTime = dce.RetryAfter ?? TimeSpan.Zero;\n            }\n\n            await Task.Delay(sleepTime);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Cosmos/CosmosOptionsValidator.cs",
    "content": "#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.Cosmos;\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.Cosmos;\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.Cosmos;\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.Cosmos;\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.Cosmos;\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n\n/// <summary>\n/// Validates instances of <see cref=\"CosmosOptions\"/>.\n/// </summary>\n/// <typeparam name=\"TOptions\">The options type.</typeparam>\npublic class CosmosOptionsValidator<TOptions> : IConfigurationValidator where TOptions : CosmosOptions\n{\n    private readonly TOptions _options;\n    private readonly string _name;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CosmosOptionsValidator{TOptions}\"/> type.\n    /// </summary>\n    /// <param name=\"options\">The instance to be validated.</param>\n    /// <param name=\"name\">The option name to be validated.</param>\n    public CosmosOptionsValidator(TOptions options, string name)\n    {\n        _options = options;\n        _name = name;\n    }\n\n    /// <inheritdoc/>\n    public void ValidateConfiguration()\n    {\n        if (string.IsNullOrWhiteSpace(_options.DatabaseName))\n            throw new OrleansConfigurationException(\n                $\"Configuration for Azure Cosmos DB provider {_name} is invalid. {nameof(_options.DatabaseName)} is not valid.\");\n\n        if (string.IsNullOrWhiteSpace(_options.ContainerName))\n            throw new OrleansConfigurationException(\n                $\"Configuration for Azure Cosmos DB provider {_name} is invalid. {nameof(_options.ContainerName)} is not valid.\");\n\n        if (_options.CreateClient is null)\n        {\n            throw new OrleansConfigurationException(\n                $\"Configuration for Azure Cosmos DB provider {_name} is invalid. You must call {nameof(_options.ConfigureCosmosClient)} to configure access to Azure Cosmos DB.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Azure/Shared/Cosmos/Usings.cs",
    "content": "global using System;\nglobal using System.Linq;\nglobal using System.Threading.Tasks;\nglobal using System.Collections.Generic;\nglobal using System.Text.Json.Serialization;\nglobal using Orleans.Runtime;\nglobal using Orleans.Serialization;\nglobal using Orleans.Configuration;\nglobal using Microsoft.Azure.Cosmos;\nglobal using Microsoft.Azure.Cosmos.Linq;\nglobal using Microsoft.Extensions.Options;\nglobal using Microsoft.Extensions.Logging;"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureBlobUtils.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Text.RegularExpressions;\n\n#if ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// General utility functions related to Azure Blob storage.\n    /// </summary>\n    internal static partial class AzureBlobUtils\n    {\n        [GeneratedRegex(\"^[a-z0-9]+(-[a-z0-9]+)*$\", RegexOptions.ExplicitCapture | RegexOptions.Singleline | RegexOptions.CultureInvariant)]\n        private static partial Regex ContainerNameRegex();\n\n        internal static void ValidateContainerName(string containerName)\n        {\n            if (string.IsNullOrWhiteSpace(containerName) || containerName.Length < 3 || containerName.Length > 63 || !ContainerNameRegex().IsMatch(containerName))\n            {\n                throw new ArgumentException(\"Invalid container name\", nameof(containerName));\n            }\n        }\n\n        internal static void ValidateBlobName(string blobName)\n        {\n            if (string.IsNullOrWhiteSpace(blobName) || blobName.Length > 1024 || blobName.Count(c => c == '/') >= 254)\n            {\n                throw new ArgumentException(\"Invalid blob name\", nameof(blobName));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureStorageOperationOptions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Core;\nusing Azure.Data.Tables;\nusing Orleans.Runtime;\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    public class AzureStorageOperationOptions\n    {\n        private TableServiceClient _tableServiceClient;\n\n        /// <summary>\n        /// Table name for Azure Storage\n        /// </summary>\n        public virtual string TableName { get; set; }\n\n        /// <summary>\n        /// Azure Storage Policy Options\n        /// </summary>\n        public AzureStoragePolicyOptions StoragePolicyOptions { get; } = new AzureStoragePolicyOptions();\n\n        /// <summary>\n        /// Options to be used when configuring the table storage client, or <see langword=\"null\"/> to use the default options.\n        /// </summary>\n        public TableClientOptions ClientOptions { get; set; }\n\n        /// <summary>\n        /// The delegate used to create a <see cref=\"TableServiceClient\"/> instance.\n        /// </summary>\n        internal Func<Task<TableServiceClient>> CreateClient { get; private set; }\n\n        /// <summary>\n        /// Gets or sets the client used to access the Azure Table Service.\n        /// </summary>\n        public TableServiceClient TableServiceClient\n        {\n            get => _tableServiceClient;\n            set\n            {\n                _tableServiceClient = value;\n                CreateClient = () => Task.FromResult(value);\n            }\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using a connection string.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString)\n        {\n            if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullException(nameof(connectionString));\n            TableServiceClient = new TableServiceClient(connectionString, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using an authenticated service URI.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(Uri serviceUri)\n        {\n            if (serviceUri is null) throw new ArgumentNullException(nameof(serviceUri));\n            TableServiceClient = new TableServiceClient(serviceUri, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using the provided callback.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(Func<Task<TableServiceClient>> createClientCallback)\n        {\n            CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.Core.TokenCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(Uri serviceUri, TokenCredential tokenCredential)\n        {\n            TableServiceClient = new TableServiceClient(serviceUri, tokenCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using an authenticated service URI and a <see cref=\"Azure.AzureSasCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(Uri serviceUri, AzureSasCredential azureSasCredential)\n        {\n            TableServiceClient = new TableServiceClient(serviceUri, azureSasCredential, ClientOptions);\n        }\n\n        /// <summary>\n        /// Configures the <see cref=\"TableServiceClient\"/> using an authenticated service URI and a <see cref=\"TableSharedKeyCredential\"/>.\n        /// </summary>\n        [Obsolete($\"Set the {nameof(TableServiceClient)} property directly.\")]\n        public void ConfigureTableServiceClient(Uri serviceUri, TableSharedKeyCredential sharedKeyCredential)\n        {\n            TableServiceClient = new TableServiceClient(serviceUri, sharedKeyCredential, ClientOptions);\n        }\n\n        internal void Validate(string name)\n        {\n            if (CreateClient is null)\n            {\n                throw new OrleansConfigurationException($\"No credentials specified. Use the {GetType().Name}.{nameof(ConfigureTableServiceClient)} method to configure the Azure Table Service client.\");\n            }\n\n            try\n            {\n                AzureTableUtils.ValidateTableName(TableName);\n            }\n            catch (Exception ex)\n            {\n                throw GetException($\"{nameof(TableName)} is not valid.\", ex);\n            }\n\n            Exception GetException(string message, Exception inner = null) =>\n                new OrleansConfigurationException($\"Configuration for {GetType().Name} {name} is invalid. {message}\", inner);\n        }\n    }\n\n    public class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null)\n        {\n            Options = options;\n            Name = name;\n        }\n\n        public TOptions Options { get; }\n        public string Name { get; }\n\n        public virtual void ValidateConfiguration()\n        {\n            Options.Validate(Name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureStoragePolicyOptions.cs",
    "content": "using System;\nusing System.Threading;\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    public class AzureStoragePolicyOptions\n    {\n        private TimeSpan? creationTimeout;\n        private TimeSpan? operationTimeout;\n\n        public int MaxBulkUpdateRows { get; set; } = 100;\n        public int MaxCreationRetries { get; set; } = 60;\n        public int MaxOperationRetries { get; set; } = 5;\n\n        public TimeSpan PauseBetweenCreationRetries { get; set; } = TimeSpan.FromSeconds(1);\n\n        public TimeSpan PauseBetweenOperationRetries { get; set; } = TimeSpan.FromMilliseconds(100);\n\n        public TimeSpan CreationTimeout\n        {\n            get => this.creationTimeout ?? TimeSpan.FromMilliseconds(this.PauseBetweenCreationRetries.TotalMilliseconds * this.MaxCreationRetries * 3);\n            set => SetIfValidTimeout(ref this.creationTimeout, value, nameof(CreationTimeout));\n        }\n\n        public TimeSpan OperationTimeout\n        {\n            get => this.operationTimeout ?? TimeSpan.FromMilliseconds(this.PauseBetweenOperationRetries.TotalMilliseconds * this.MaxOperationRetries * 6);\n            set => SetIfValidTimeout(ref this.operationTimeout, value, nameof(OperationTimeout));\n        }\n\n        private static void SetIfValidTimeout(ref TimeSpan? field, TimeSpan value, string propertyName)\n        {\n            if (value > TimeSpan.Zero || value.Equals(Timeout.InfiniteTimeSpan))\n            {\n                field = value;\n            }\n            else\n            {\n                throw new ArgumentNullException(propertyName);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureTableDataManager.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Azure;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\n//\n// Number of #ifs can be reduced (or removed), once we separate test projects by feature/area, otherwise we are ending up with ambigous types and build errors.\n//\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Utility class to encapsulate row-based access to Azure table storage.\n    /// </summary>\n    /// <typeparam name=\"T\">Table data entry used by this table / manager.</typeparam>\n    internal partial class AzureTableDataManager<T> where T : class, ITableEntity\n    {\n        private readonly AzureStorageOperationOptions options;\n\n        /// <summary> Name of the table this instance is managing. </summary>\n        public string TableName { get; }\n\n        /// <summary> Logger for this table manager instance. </summary>\n        protected internal ILogger Logger { get; }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get; }\n\n        public TableClient Table { get; private set; }\n\n        /// <summary>\n        /// Creates a new <see cref=\"AzureTableDataManager{T}\"/> instance.\n        /// </summary>\n        /// <param name=\"options\">Storage configuration.</param>\n        /// <param name=\"logger\">Logger to use.</param>\n        public AzureTableDataManager(AzureStorageOperationOptions options, ILogger logger)\n        {\n            this.options = options ?? throw new ArgumentNullException(nameof(options));\n\n            Logger = logger ?? throw new ArgumentNullException(nameof(logger));\n            TableName = options.TableName ?? throw new ArgumentNullException(nameof(options.TableName));\n            StoragePolicyOptions = options.StoragePolicyOptions ?? throw new ArgumentNullException(nameof(options.StoragePolicyOptions));\n\n            AzureTableUtils.ValidateTableName(TableName);\n        }\n\n        /// <summary>\n        /// Connects to, or creates and initializes a new Azure table if it does not already exist.\n        /// </summary>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task InitTableAsync()\n        {\n            const string operation = \"InitTable\";\n            var startTime = DateTime.UtcNow;\n\n            try\n            {\n                TableServiceClient tableCreationClient = await GetCloudTableCreationClientAsync();\n                var table = tableCreationClient.GetTableClient(TableName);\n                var response = await table.CreateIfNotExistsAsync();\n                var alreadyExisted = response.GetRawResponse().Status == (int)HttpStatusCode.Conflict;\n\n                LogInfoTableCreation(Logger, alreadyExisted ? \"Attached to\" : \"Created\", TableName);\n                Table = table;\n            }\n            catch (TimeoutException te)\n            {\n                LogErrorTableCreationInTimeout(Logger, te, StoragePolicyOptions.CreationTimeout);\n                throw new OrleansException($\"Unable to create or connect to the Azure table in {StoragePolicyOptions.CreationTimeout}\", te);\n            }\n            catch (Exception exc)\n            {\n                LogErrorTableCreation(Logger, exc, TableName);\n                throw;\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Deletes the Azure table.\n        /// </summary>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task DeleteTableAsync()\n        {\n            const string operation = \"DeleteTable\";\n            var startTime = DateTime.UtcNow;\n\n            try\n            {\n                var tableCreationClient = await GetCloudTableCreationClientAsync();\n                var response = await tableCreationClient.DeleteTableAsync(TableName);\n                if (response.Status == 204)\n                {\n                    LogInfoTableDeletion(Logger, TableName);\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorTableDeletion(Logger, exc, TableName);\n                throw;\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Deletes all entities the Azure table.\n        /// </summary>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task ClearTableAsync()\n        {\n            var items = await ReadAllTableEntriesAsync();\n            IEnumerable<Task> work = items.GroupBy(item => item.Item1.PartitionKey)\n                                          .SelectMany(partition => partition.ToBatch(this.StoragePolicyOptions.MaxBulkUpdateRows))\n                                          .Select(batch => DeleteTableEntriesAsync(batch.ToList()));\n            await Task.WhenAll(work);\n        }\n\n        /// <summary>\n        /// Create a new data entry in the Azure table (insert new, not update existing).\n        /// Fails if the data already exists.\n        /// </summary>\n        /// <param name=\"data\">Data to be inserted into the table.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        public async Task<string> CreateTableEntryAsync(T data)\n        {\n            const string operation = \"CreateTableEntry\";\n            var startTime = DateTime.UtcNow;\n\n            LogTraceTableEntryCreation(Logger, TableName, data);\n            try\n            {\n                try\n                {\n                    // Presumably FromAsync(BeginExecute, EndExecute) has a slightly better performance then CreateIfNotExistsAsync.\n                    var opResult = await Table.AddEntityAsync(data);\n                    return opResult.Headers.ETag.GetValueOrDefault().ToString();\n                }\n                catch (Exception exc)\n                {\n                    CheckAlertWriteError(operation, data, null, exc);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Inserts a data entry in the Azure table: creates a new one if does not exists or overwrites (without eTag) an already existing version (the \"update in place\" semantics).\n        /// </summary>\n        /// <param name=\"data\">Data to be inserted or replaced in the table.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        public async Task<string> UpsertTableEntryAsync(T data)\n        {\n            const string operation = \"UpsertTableEntry\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntry(Logger, operation, data, TableName);\n            try\n            {\n                try\n                {\n                    var opResult = await Table.UpsertEntityAsync(data);\n                    return opResult.Headers.ETag.GetValueOrDefault().ToString();\n                }\n                catch (Exception exc)\n                {\n                    LogWarningUpsertTableEntry(Logger, exc, data, TableName);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Inserts a data entry in the Azure table: creates a new one if does not exists\n        /// </summary>\n        /// <param name=\"data\">Data to be inserted or replaced in the table.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        public async Task<(bool isSuccess, string eTag)> InsertTableEntryAsync(T data)\n        {\n            const string operation = \"InsertTableEntry\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntry(Logger, operation, data, TableName);\n            try\n            {\n                try\n                {\n                    var opResult = await Table.AddEntityAsync(data);\n                    return (true, opResult.Headers.ETag.GetValueOrDefault().ToString());\n                }\n                catch (RequestFailedException storageException) when (storageException.Status == (int)HttpStatusCode.Conflict)\n                {\n                    return (false, null);\n                }\n                catch (Exception exc)\n                {\n                    LogWarningInsertTableEntry(Logger, exc, data, TableName);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Merges a data entry in the Azure table.\n        /// </summary>\n        /// <param name=\"data\">Data to be merged in the table.</param>\n        /// <param name=\"eTag\">ETag to apply.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        internal Task<string> MergeTableEntryAsync(T data, string eTag) => MergeTableEntryAsync(data, new ETag(eTag));\n\n        /// <summary>\n        /// Merges a data entry in the Azure table.\n        /// </summary>\n        /// <param name=\"data\">Data to be merged in the table.</param>\n        /// <param name=\"eTag\">ETag to apply.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        internal async Task<string> MergeTableEntryAsync(T data, ETag eTag)\n        {\n            const string operation = \"MergeTableEntry\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntry(Logger, operation, data, TableName);\n            try\n            {\n                try\n                {\n                    // Merge requires an ETag (which may be the '*' wildcard).\n                    data.ETag = eTag;\n                    var opResult = await Table.UpdateEntityAsync(data, data.ETag, TableUpdateMode.Merge);\n                    return opResult.Headers.ETag.GetValueOrDefault().ToString();\n                }\n                catch (Exception exc)\n                {\n                    LogWarningMergeTableEntry(Logger, exc, data, TableName);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Updates a data entry in the Azure table: updates an already existing data in the table, by using eTag.\n        /// Fails if the data does not already exist or of eTag does not match.\n        /// </summary>\n        /// <param name=\"data\">Data to be updated into the table.</param>\n        /// /// <param name=\"dataEtag\">ETag to use.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        public Task<string> UpdateTableEntryAsync(T data, string dataEtag) => UpdateTableEntryAsync(data, new ETag(dataEtag));\n\n        /// <summary>\n        /// Updates a data entry in the Azure table: updates an already existing data in the table, by using eTag.\n        /// Fails if the data does not already exist or of eTag does not match.\n        /// </summary>\n        /// <param name=\"data\">Data to be updated into the table.</param>\n        /// /// <param name=\"dataEtag\">ETag to use.</param>\n        /// <returns>Value promise with new Etag for this data entry after completing this storage operation.</returns>\n        public async Task<string> UpdateTableEntryAsync(T data, ETag dataEtag)\n        {\n            const string operation = \"UpdateTableEntryAsync\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntry(Logger, operation, data, TableName);\n\n            try\n            {\n                try\n                {\n                    data.ETag = dataEtag;\n                    var opResult = await Table.UpdateEntityAsync(data, data.ETag, TableUpdateMode.Replace);\n\n                    //The ETag of data is needed in further operations.\n                    return opResult.Headers.ETag.GetValueOrDefault().ToString();\n                }\n                catch (Exception exc)\n                {\n                    CheckAlertWriteError(operation, data, null, exc);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Deletes an already existing data in the table, by using eTag.\n        /// Fails if the data does not already exist or if eTag does not match.\n        /// </summary>\n        /// <param name=\"data\">Data entry to be deleted from the table.</param>\n        /// <param name=\"eTag\">ETag to use.</param>\n        /// <returns>Completion promise for this storage operation.</returns>\n        public Task DeleteTableEntryAsync(T data, string eTag) => DeleteTableEntryAsync(data, new ETag(eTag));\n\n        /// <summary>\n        /// Deletes an already existing data in the table, by using eTag.\n        /// Fails if the data does not already exist or if eTag does not match.\n        /// </summary>\n        /// <param name=\"data\">Data entry to be deleted from the table.</param>\n        /// <param name=\"eTag\">ETag to use.</param>\n        /// <returns>Completion promise for this storage operation.</returns>\n        public async Task DeleteTableEntryAsync(T data, ETag eTag)\n        {\n            const string operation = \"DeleteTableEntryAsync\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntry(Logger, operation, data, TableName);\n            try\n            {\n                data.ETag = eTag;\n                try\n                {\n                    var response = await Table.DeleteEntityAsync(data.PartitionKey, data.RowKey, data.ETag);\n                    if (response is { Status: 404 })\n                    {\n                        throw new RequestFailedException(response.Status, \"Resource not found\", response.ReasonPhrase, null);\n                    }\n                }\n                catch (Exception exc)\n                {\n                    LogWarningDeleteTableEntry(Logger, exc, data, TableName);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Read a single table entry from the storage table.\n        /// </summary>\n        /// <param name=\"partitionKey\">The partition key for the entry.</param>\n        /// <param name=\"rowKey\">The row key for the entry.</param>\n        /// <returns>Value promise for tuple containing the data entry and its corresponding etag.</returns>\n        public async Task<(T Entity, string ETag)> ReadSingleTableEntryAsync(string partitionKey, string rowKey)\n        {\n            const string operation = \"ReadSingleTableEntryAsync\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableOperation(Logger, operation, TableName, partitionKey, rowKey);\n            try\n            {\n                try\n                {\n                    var result = await Table.GetEntityIfExistsAsync<T>(partitionKey, rowKey);\n                    if (result.HasValue)\n                    {\n                        //The ETag of data is needed in further operations.\n                        return (result.Value, result.Value.ETag.ToString());\n                    }\n                }\n                catch (RequestFailedException exception)\n                {\n                    if (!AzureTableUtils.TableStorageDataNotFound(exception))\n                    {\n                        throw;\n                    }\n                }\n\n                LogDebugTableEntryNotFound(Logger, partitionKey, rowKey);\n                return (default, default);  // No data\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Read all entries in one partition of the storage table.\n        /// NOTE: This could be an expensive and slow operation for large table partitions!\n        /// </summary>\n        /// <param name=\"partitionKey\">The key for the partition to be searched.</param>\n        /// <returns>Enumeration of all entries in the specified table partition.</returns>\n        public Task<List<(T Entity, string ETag)>> ReadAllTableEntriesForPartitionAsync(string partitionKey)\n        {\n            string query = TableClient.CreateQueryFilter($\"PartitionKey eq {partitionKey}\");\n            return ReadTableEntriesAndEtagsAsync(query);\n        }\n\n        /// <summary>\n        /// Read all entries in the table.\n        /// NOTE: This could be a very expensive and slow operation for large tables!\n        /// </summary>\n        /// <returns>Enumeration of all entries in the table.</returns>\n        public Task<List<(T Entity, string ETag)>> ReadAllTableEntriesAsync()\n        {\n            return ReadTableEntriesAndEtagsAsync(null);\n        }\n\n        /// <summary>\n        /// Deletes a set of already existing data entries in the table, by using eTag.\n        /// Fails if the data does not already exist or if eTag does not match.\n        /// </summary>\n        /// <param name=\"collection\">Data entries and their corresponding etags to be deleted from the table.</param>\n        /// <returns>Completion promise for this storage operation.</returns>\n        public async Task DeleteTableEntriesAsync(List<(T Entity, string ETag)> collection)\n        {\n            const string operation = \"DeleteTableEntries\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntries(Logger, operation, new(collection), TableName);\n\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            if (collection.Count > this.StoragePolicyOptions.MaxBulkUpdateRows)\n            {\n                throw new ArgumentOutOfRangeException(nameof(collection), collection.Count,\n                        \"Too many rows for bulk delete - max \" + this.StoragePolicyOptions.MaxBulkUpdateRows);\n            }\n\n            if (collection.Count == 0)\n            {\n                return;\n            }\n\n            try\n            {\n                var entityBatch = new List<TableTransactionAction>();\n                foreach (var tuple in collection)\n                {\n                    T item = tuple.Entity;\n                    item.ETag = new ETag(tuple.ETag);\n                    entityBatch.Add(new TableTransactionAction(TableTransactionActionType.Delete, item, item.ETag));\n                }\n\n                try\n                {\n                    _ = await Table.SubmitTransactionAsync(entityBatch);\n                }\n                catch (Exception exc)\n                {\n                    LogWarningDeleteTableEntries(Logger, exc, new(collection), TableName);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Read data entries and their corresponding eTags from the Azure table.\n        /// </summary>\n        /// <param name=\"filter\">Filter string to use for querying the table and filtering the results.</param>\n        /// <returns>Enumeration of entries in the table which match the query condition.</returns>\n        public async Task<List<(T Entity, string ETag)>> ReadTableEntriesAndEtagsAsync(string filter)\n        {\n            const string operation = \"ReadTableEntriesAndEtags\";\n            var startTime = DateTime.UtcNow;\n\n            try\n            {\n                try\n                {\n                    async Task<List<(T Entity, string ETag)>> executeQueryHandleContinuations()\n                    {\n                        var list = new List<(T, string)>();\n                        var results = Table.QueryAsync<T>(filter);\n                        await foreach (var value in results)\n                        {\n                            list.Add((value, value.ETag.ToString()));\n                        }\n\n                        return list;\n                    }\n\n#if !ORLEANS_TRANSACTIONS\n                    IBackoffProvider backoff = new FixedBackoff(this.StoragePolicyOptions.PauseBetweenOperationRetries);\n\n                    List<(T, string)> results = await AsyncExecutorWithRetries.ExecuteWithRetries(\n                        counter => executeQueryHandleContinuations(),\n                        this.StoragePolicyOptions.MaxOperationRetries,\n                        (exc, counter) => AzureTableUtils.AnalyzeReadException(exc.GetBaseException(), counter, TableName, Logger),\n                        this.StoragePolicyOptions.OperationTimeout,\n                        backoff);\n#else\n                    List<(T, string)> results = await executeQueryHandleContinuations();\n#endif\n                    // Data was read successfully if we got to here\n                    return results;\n\n                }\n                catch (Exception exc)\n                {\n                    // Out of retries...\n                    if (!AzureTableUtils.TableStorageDataNotFound(exc))\n                    {\n                        LogWarningReadTable(Logger, exc, TableName);\n                    }\n\n                    throw new OrleansException($\"Failed to read Azure Storage table {TableName}\", exc);\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        /// <summary>\n        /// Inserts a set of new data entries into the table.\n        /// Fails if the data does already exists.\n        /// </summary>\n        /// <param name=\"collection\">Data entries to be inserted into the table.</param>\n        /// <returns>Completion promise for this storage operation.</returns>\n        public async Task BulkInsertTableEntries(IReadOnlyCollection<T> collection)\n        {\n            const string operation = \"BulkInsertTableEntries\";\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n            if (collection.Count > this.StoragePolicyOptions.MaxBulkUpdateRows)\n            {\n                throw new ArgumentOutOfRangeException(nameof(collection), collection.Count,\n                        \"Too many rows for bulk update - max \" + this.StoragePolicyOptions.MaxBulkUpdateRows);\n            }\n\n            if (collection.Count == 0)\n            {\n                return;\n            }\n\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntriesCount(Logger, operation, collection.Count, TableName);\n            try\n            {\n                var entityBatch = new List<TableTransactionAction>(collection.Count);\n                foreach (T entry in collection)\n                {\n                    entityBatch.Add(new TableTransactionAction(TableTransactionActionType.Add, entry));\n                }\n\n                try\n                {\n                    await Table.SubmitTransactionAsync(entityBatch);\n                }\n                catch (Exception exc)\n                {\n                    LogWarningBulkInsertTableEntries(Logger, exc, collection.Count, TableName);\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        internal async Task<(string, string)> InsertTwoTableEntriesConditionallyAsync(T data1, T data2, string data2Etag)\n        {\n            const string operation = \"InsertTableEntryConditionally\";\n            string data2Str = data2 == null ? \"null\" : data2.ToString();\n            var startTime = DateTime.UtcNow;\n\n            LogTraceTableEntries(Logger, operation, data1, data2Str, TableName);\n            try\n            {\n                try\n                {\n                    data2.ETag = new ETag(data2Etag);\n                    var opResults = await Table.SubmitTransactionAsync(new TableTransactionAction[]\n                    {\n                        new TableTransactionAction(TableTransactionActionType.Add, data1),\n                        new TableTransactionAction(TableTransactionActionType.UpdateReplace, data2, data2.ETag)\n                    });\n\n                    //The batch results are returned in order of execution,\n                    //see reference at https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.table.cloudtable.executebatch.aspx.\n                    //The ETag of data is needed in further operations.\n                    var resultETag1 = opResults.Value[0].Headers.ETag.GetValueOrDefault().ToString();\n                    var resultETag2 = opResults.Value[1].Headers.ETag.GetValueOrDefault().ToString();\n                    return (resultETag1, resultETag2);\n                }\n                catch (Exception exc)\n                {\n                    CheckAlertWriteError(operation, data1, data2Str, exc);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        internal async Task<(string, string)> UpdateTwoTableEntriesConditionallyAsync(T data1, string data1Etag, T data2, string data2Etag)\n        {\n            const string operation = \"UpdateTableEntryConditionally\";\n            string data2Str = data2 == null ? \"null\" : data2.ToString();\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntries(Logger, operation, data1, data2Str, TableName);\n\n            try\n            {\n                try\n                {\n                    data1.ETag = new ETag(data1Etag);\n                    var entityBatch = new List<TableTransactionAction>(2);\n                    entityBatch.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, data1, data1.ETag));\n\n                    if (data2 != null && data2Etag != null)\n                    {\n                        data2.ETag = new ETag(data2Etag);\n                        entityBatch.Add(new TableTransactionAction(TableTransactionActionType.UpdateReplace, data2, data2.ETag));\n                    }\n\n                    var opResults = await Table.SubmitTransactionAsync(entityBatch);\n\n                    //The batch results are returned in order of execution,\n                    //see reference at https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.table.cloudtable.executebatch.aspx.\n                    //The ETag of data is needed in further operations.\n                    var resultETag1 = opResults.Value[0].Headers.ETag.GetValueOrDefault().ToString();\n                    var resultETag2 = opResults.Value[1].Headers.ETag.GetValueOrDefault().ToString();\n                    return (resultETag1, resultETag2);\n                }\n                catch (Exception exc)\n                {\n                    CheckAlertWriteError(operation, data1, data2Str, exc);\n                    throw;\n                }\n            }\n            finally\n            {\n                CheckAlertSlowAccess(startTime, operation);\n            }\n        }\n\n        private async ValueTask<TableServiceClient> GetCloudTableCreationClientAsync()\n        {\n            try\n            {\n                return await options.CreateClient();\n            }\n            catch (Exception exc)\n            {\n                LogErrorTableServiceClientCreation(Logger, exc);\n                throw;\n            }\n        }\n\n        private void CheckAlertWriteError(string operation, object data1, string data2, Exception exc)\n        {\n            HttpStatusCode httpStatusCode;\n            if (AzureTableUtils.EvaluateException(exc, out httpStatusCode, out _) && AzureTableUtils.IsContentionError(httpStatusCode))\n            {\n                // log at Verbose, since failure on conditional is not not an error. Will analyze and warn later, if required.\n                LogWarningTableWrite(Logger, operation, TableName, data1 ?? \"null\", data2 ?? \"null\");\n            }\n            else\n            {\n                LogErrorTableWrite(Logger, exc, operation, TableName, data1);\n            }\n        }\n\n        private void CheckAlertSlowAccess(DateTime startOperation, string operation)\n        {\n            var timeSpan = DateTime.UtcNow - startOperation;\n            if (timeSpan > this.StoragePolicyOptions.OperationTimeout)\n            {\n                LogWarningSlowAccess(Logger, operation, TableName, timeSpan);\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)Utilities.ErrorCode.AzureTable_01,\n            Message = \"{Action} Azure storage table {TableName}\"\n        )]\n        private static partial void LogInfoTableCreation(ILogger logger, string action, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)Utilities.ErrorCode.AzureTable_TableNotCreated,\n            Message = \"Unable to create or connect to the Azure table in {CreationTimeout}\"\n        )]\n        private static partial void LogErrorTableCreationInTimeout(ILogger logger, TimeoutException exception, TimeSpan creationTimeout);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)Utilities.ErrorCode.AzureTable_02,\n            Message = \"Could not initialize connection to storage table {TableName}\"\n        )]\n        private static partial void LogErrorTableCreation(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)Utilities.ErrorCode.AzureTable_03,\n            Message = \"Deleted Azure storage table {TableName}\"\n        )]\n        private static partial void LogInfoTableDeletion(ILogger logger, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)Utilities.ErrorCode.AzureTable_04,\n            Message = \"Could not delete storage table {TableName}\"\n        )]\n        private static partial void LogErrorTableDeletion(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Creating {TableName} table entry: {Data}\"\n        )]\n        private static partial void LogTraceTableEntryCreation(ILogger logger, string tableName, T data);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{Operation} entry {Data} into table {TableName}\"\n        )]\n        private static partial void LogTraceTableEntry(ILogger logger, string operation, T data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_06,\n            Message = \"Intermediate error upserting entry {Data} to the table {TableName}\"\n        )]\n        private static partial void LogWarningUpsertTableEntry(ILogger logger, Exception exception, T data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_06,\n            Message = \"Intermediate error inserting entry {Data} to the table {TableName}\"\n        )]\n        private static partial void LogWarningInsertTableEntry(ILogger logger, Exception exception, T data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_07,\n            Message = \"Intermediate error merging entry {Data} to the table {TableName}\"\n        )]\n        private static partial void LogWarningMergeTableEntry(ILogger logger, Exception exception, T data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_08,\n            Message = \"Intermediate error deleting entry {Data} from the table {TableName}.\"\n        )]\n        private static partial void LogWarningDeleteTableEntry(ILogger logger, Exception exception, T data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{Operation} table {TableName} partitionKey {PartitionKey} rowKey {RowKey}\"\n        )]\n        private static partial void LogTraceTableOperation(ILogger logger, string operation, string tableName, string partitionKey, string rowKey);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Could not find table entry for PartitionKey={PartitionKey} RowKey={RowKey}\"\n        )]\n        private static partial void LogDebugTableEntryNotFound(ILogger logger, string partitionKey, string rowKey);\n\n        private readonly struct CollectionLogEntry(List<(T Entity, string ETag)> collection)\n        {\n            public override string ToString() => Utils.EnumerableToString(collection);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{Operation} entries: {Data} table {TableName}\"\n        )]\n        private static partial void LogTraceTableEntries(ILogger logger, string operation, CollectionLogEntry data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_08,\n            Message = \"Intermediate error deleting entries {Data} from the table {TableName}.\"\n        )]\n        private static partial void LogWarningDeleteTableEntries(ILogger logger, Exception exception, CollectionLogEntry data, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_09,\n            Message = \"Failed to read Azure Storage table {TableName}\"\n        )]\n        private static partial void LogWarningReadTable(ILogger logger, Exception exception, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{Operation} {Count} entries table {TableName}\"\n        )]\n        private static partial void LogTraceTableEntriesCount(ILogger logger, string operation, int count, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_37,\n            Message = \"Intermediate error bulk inserting {Count} entries in the table {TableName}\"\n        )]\n        private static partial void LogWarningBulkInsertTableEntries(ILogger logger, Exception exception, int count, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{Operation} data1 {Data1} data2 {Data2} table {TableName}\"\n        )]\n        private static partial void LogTraceTableEntries(ILogger logger, string operation, T data1, string data2, string tableName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error creating TableServiceClient.\"\n        )]\n        private static partial void LogErrorTableServiceClientCreation(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)Utilities.ErrorCode.AzureTable_13,\n            Message = \"Intermediate Azure table write error {Operation} to table {TableName} data1 {Data1} data2 {Data2}\"\n        )]\n        private static partial void LogWarningTableWrite(ILogger logger, string operation, string tableName, object data1, object data2);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)Utilities.ErrorCode.AzureTable_14,\n            Message = \"Azure table access write error {Operation} to table {TableName} entry {Data1}\"\n        )]\n        private static partial void LogErrorTableWrite(ILogger logger, Exception exception, string operation, string tableName, object data1);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_15,\n            Message = \"Slow access to Azure Table {TableName} for {Operation}, which took {Duration}\"\n        )]\n        private static partial void LogWarningSlowAccess(ILogger logger, string tableName, string operation, TimeSpan duration);\n    }\n\n    internal static class TableDataManagerInternalExtensions\n    {\n        internal static IEnumerable<IEnumerable<TItem>> ToBatch<TItem>(this IEnumerable<TItem> source, int size)\n        {\n            using (IEnumerator<TItem> enumerator = source.GetEnumerator())\n                while (enumerator.MoveNext())\n                    yield return Take(enumerator, size);\n        }\n\n        private static IEnumerable<TItem> Take<TItem>(IEnumerator<TItem> source, int size)\n        {\n            int i = 0;\n            do\n                yield return source.Current;\n            while (++i < size && source.MoveNext());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureTableDefaultPolicies.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Microsoft.Azure.Cosmos.Table;\n\n//\n// Number of #ifs can be reduced (or removed), once we separate test projects by feature/area, otherwise we are ending up with ambigous types and build errors.\n//\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Utility class for default retry / timeout settings for Azure storage.\n    /// </summary>\n    /// <remarks>\n    /// These functions are mostly intended for internal usage by Orleans runtime, but due to certain assembly packaging constraints this class needs to have public visibility.\n    /// </remarks>\n    public static class AzureTableDefaultPolicies\n    {\n        public static int MaxTableCreationRetries { get; private set; }\n        public static int MaxTableOperationRetries { get; private set; }\n        public static int MaxBusyRetries { get; internal set; }\n\n        public static TimeSpan PauseBetweenTableCreationRetries { get; private set; }\n        public static TimeSpan PauseBetweenTableOperationRetries { get; private set; }\n        public static TimeSpan PauseBetweenBusyRetries { get; private set; }\n\n        public static TimeSpan TableCreationTimeout { get; private set; }\n        public static TimeSpan TableOperationTimeout { get; private set; }\n        public static TimeSpan BusyRetriesTimeout { get; private set; }\n\n        public static IRetryPolicy TableCreationRetryPolicy { get; private set; }\n        public static IRetryPolicy TableOperationRetryPolicy { get; private set; }\n\n        public const int MAX_BULK_UPDATE_ROWS = 100;\n\n        static AzureTableDefaultPolicies()\n        {\n            MaxTableCreationRetries = 60;\n            PauseBetweenTableCreationRetries = (!Debugger.IsAttached)\n                ? TimeSpan.FromSeconds(1)\n                : TimeSpan.FromSeconds(100);\n\n            MaxTableOperationRetries = 5;\n            PauseBetweenTableOperationRetries = (!Debugger.IsAttached)\n                ? TimeSpan.FromMilliseconds(100)\n                : TimeSpan.FromSeconds(10);\n\n            MaxBusyRetries = 120;\n            PauseBetweenBusyRetries = (!Debugger.IsAttached)\n                ? TimeSpan.FromMilliseconds(500)\n                : TimeSpan.FromSeconds(5);\n\n            TableCreationRetryPolicy = new LinearRetry(PauseBetweenTableCreationRetries, MaxTableCreationRetries); // 60 x 1s\n            TableCreationTimeout = TimeSpan.FromMilliseconds(PauseBetweenTableCreationRetries.TotalMilliseconds * MaxTableCreationRetries * 3);    // 3 min\n\n            TableOperationRetryPolicy = new LinearRetry(PauseBetweenTableOperationRetries, MaxTableOperationRetries); // 5 x 100ms\n            TableOperationTimeout = TimeSpan.FromMilliseconds(PauseBetweenTableOperationRetries.TotalMilliseconds * MaxTableOperationRetries *6);    // 3 sec\n\n            BusyRetriesTimeout = TimeSpan.FromMilliseconds(PauseBetweenBusyRetries.TotalMilliseconds * MaxBusyRetries);  // 1 minute\n        }\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Storage/AzureTableUtils.cs",
    "content": "using System;\nusing System.Net;\nusing System.Text.RegularExpressions;\nusing Azure;\nusing Azure.Data.Tables;\nusing Azure.Data.Tables.Models;\nusing Microsoft.Extensions.Logging;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\n//\n// Number of #ifs can be reduced (or removed), once we separate test projects by feature/area, otherwise we are ending up with ambiguous types and build errors.\n//\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    /// <summary>\n    /// Constants related to Azure Table storage (also applies to Table endpoints in Cosmos DB).\n    /// </summary>\n    internal static class AzureTableConstants\n    {\n        public const string ANY_ETAG = \"*\";\n\n        public const string PKProperty = nameof(ITableEntity.PartitionKey);\n        public const string RKProperty = nameof(ITableEntity.RowKey);\n\n        public const int MaxBatchSize = 100;\n    }\n\n    /// <summary>\n    /// General utility functions related to Azure Table storage (also applies to Table endpoints in Cosmos DB).\n    /// </summary>\n    internal static partial class AzureTableUtils\n    {\n        /// <summary>\n        /// ETag of value \"*\" to match any etag for conditional table operations (update, merge, delete).\n        /// </summary>\n        public const string ANY_ETAG = AzureTableConstants.ANY_ETAG;\n\n        /// <summary>\n        /// Inspect an exception returned from Azure storage libraries to check whether it means that attempt was made to read some data that does not exist in storage table.\n        /// </summary>\n        /// <param name=\"exc\">Exception that was returned by Azure storage library operation</param>\n        /// <returns><c>True</c> if this exception means the data being read was not present in Azure table storage</returns>\n        public static bool TableStorageDataNotFound(Exception exc)\n        {\n            if (EvaluateException(exc, out var httpStatusCode, out var restStatus, true))\n            {\n                if (IsNotFoundError(httpStatusCode))\n                {\n                    return true;\n                }\n\n                return TableErrorCode.EntityNotFound.ToString().Equals(restStatus, StringComparison.OrdinalIgnoreCase)\n                    || TableErrorCode.ResourceNotFound.ToString().Equals(restStatus, StringComparison.OrdinalIgnoreCase);\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Extract REST error code from DataServiceClientException or DataServiceQueryException\n        /// </summary>\n        /// <param name=\"exc\">Exception to be inspected.</param>\n        /// <returns>Returns REST error code if found, otherwise <c>null</c></returns>\n        private static string ExtractRestErrorCode(Exception exc)\n        {\n            while (exc != null && exc is not RequestFailedException)\n            {\n                exc = exc?.InnerException?.GetBaseException();\n            }\n\n            return (exc as RequestFailedException)?.ErrorCode;\n        }\n\n        /// <summary>\n        /// Examine a storage exception, and if applicable extracts the HTTP status code, and REST error code if <c>getRESTErrors=true</c>.\n        /// </summary>\n        /// <param name=\"e\">Exception to be examined.</param>\n        /// <param name=\"httpStatusCode\">Output HTTP status code if applicable, otherwise HttpStatusCode.Unused (306)</param>\n        /// <param name=\"restStatus\">When <c>getRESTErrors=true</c>, will output REST error code if applicable, otherwise <c>null</c></param>\n        /// <param name=\"getRESTErrors\">Whether REST error code should also be examined / extracted.</param>\n        /// <returns>Returns <c>true</c> if HTTP status code and REST error were extracted.</returns>\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Design\", \"CA1031:DoNotCatchGeneralExceptionTypes\")]\n        public static bool EvaluateException(\n            Exception e,\n            out HttpStatusCode httpStatusCode,\n            out string restStatus,\n            bool getRESTErrors = false)\n        {\n            httpStatusCode = HttpStatusCode.Unused;\n            restStatus = null;\n\n            try\n            {\n                while (e != null)\n                {\n                    if (e is RequestFailedException ste)\n                    {\n                        httpStatusCode = (HttpStatusCode)ste.Status;\n                        if (getRESTErrors)\n                        {\n                            restStatus = ExtractRestErrorCode(ste);\n                        }\n                        return true;\n                    }\n                    e = e.InnerException;\n                }\n            }\n            catch\n            {\n                // if we failed to parse the exception, treat it as if we could not EvaluateException.\n                return false;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Returns true if the specified HTTP status / error code is returned in a transient / retriable error condition\n        /// </summary>\n        /// <param name=\"httpStatusCode\">HTTP error code value</param>\n        /// <param name=\"restStatusCode\">REST error code value</param>\n        /// <returns><c>true</c> if this is a transient / retriable error condition</returns>\n        public static bool IsRetriableHttpError(HttpStatusCode httpStatusCode, string restStatusCode)\n        {\n            // Note: We ignore the 20X values as they are successful outcomes, not errors\n\n            return (\n                httpStatusCode == HttpStatusCode.RequestTimeout /* 408 */\n                || httpStatusCode == HttpStatusCode.BadGateway          /* 502 */\n                || httpStatusCode == HttpStatusCode.ServiceUnavailable  /* 503 */\n                || httpStatusCode == HttpStatusCode.GatewayTimeout      /* 504 */\n                || (httpStatusCode == HttpStatusCode.InternalServerError /* 500 */\n                    && !string.IsNullOrEmpty(restStatusCode)\n                    && TableErrorCode.OperationTimedOut.ToString().Equals(restStatusCode, StringComparison.OrdinalIgnoreCase))\n            );\n        }\n\n        /// <summary>\n        /// Check whether a HTTP status code returned from a REST call might be due to a (temporary) storage contention error.\n        /// </summary>\n        /// <param name=\"httpStatusCode\">HTTP status code to be examined.</param>\n        /// <returns>Returns <c>true</c> if the HTTP status code is due to storage contention.</returns>\n        public static bool IsContentionError(HttpStatusCode httpStatusCode)\n        {\n            // Status and Error Codes\n            // http://msdn.microsoft.com/en-us/library/dd179382.aspx\n\n            if (httpStatusCode == HttpStatusCode.PreconditionFailed) return true;\n            if (httpStatusCode == HttpStatusCode.Conflict) return true;     //Primary key violation. The app is trying to insert an entity, but there’s an entity on the table with the same values for PartitionKey and RowKey properties on the entity being inserted.\n            if (httpStatusCode == HttpStatusCode.NotFound) return true;\n            if (httpStatusCode == HttpStatusCode.NotImplemented) return true; // New table: Azure table schema not yet initialized, so need to do first create\n            return false;\n        }\n\n        /// <summary>\n        /// Check whether a HTTP status code returned from a REST call might be due to a (temporary) storage contention error.\n        /// </summary>\n        /// <param name=\"httpStatusCode\">HTTP status code to be examined.</param>\n        /// <returns>Returns <c>true</c> if the HTTP status code is due to storage contention.</returns>\n        public static bool IsNotFoundError(HttpStatusCode httpStatusCode)\n        {\n            // Status and Error Codes\n            // http://msdn.microsoft.com/en-us/library/dd179382.aspx\n\n            if (httpStatusCode == HttpStatusCode.NotFound) return true;\n            if (httpStatusCode == HttpStatusCode.NotImplemented) return true; // New table: Azure table schema not yet initialized, so need to do first create\n            return false;\n        }\n\n        [GeneratedRegex(\"^[A-Za-z][A-Za-z0-9]{2,62}$\")]\n        private static partial Regex TableNameRegex();\n\n        internal static void ValidateTableName(string tableName)\n        {\n            // Regular expression from documentation: https://learn.microsoft.com/rest/api/storageservices/understanding-the-table-service-data-model#table-names\n            if (!TableNameRegex().IsMatch(tableName))\n            {\n                throw new ArgumentException($\"Table name \\\"{tableName}\\\" is invalid according to the following rules:\"\n                    + \" 1. Table names may contain only alphanumeric characters.\"\n                    + \" 2. Table names cannot begin with a numeric character.\"\n                    + \" 3. Table names must be from 3 to 63 characters long.\");\n            }\n        }\n\n        /// <summary>\n        /// Remove any characters that can't be used in Azure PartitionKey or RowKey values.\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <returns></returns>\n        public static string SanitizeTableProperty(string key)\n        {\n            // Remove any characters that can't be used in Azure PartitionKey or RowKey values\n            // http://www.jamestharpe.com/web-development/azure-table-service-character-combinations-disallowed-in-partitionkey-rowkey/\n            key = key\n                .Replace('/', '_')        // Forward slash\n                .Replace('\\\\', '_')       // Backslash\n                .Replace('#', '_')        // Pound sign\n                .Replace('?', '_');       // Question mark\n\n            if (key.Length >= 1024)\n                throw new ArgumentException(string.Format(\"Key length {0} is too long to be an Azure table key. Key={1}\", key.Length, key));\n\n            return key;\n        }\n\n        internal static bool AnalyzeReadException(Exception exc, int iteration, string tableName, ILogger logger)\n        {\n            bool isLastErrorRetriable;\n            var we = exc as WebException;\n            if (we != null)\n            {\n                isLastErrorRetriable = true;\n                LogWarningIntermediateIssue(logger, exc, tableName, we.Status);\n            }\n            else\n            {\n                if (EvaluateException(exc, out var httpStatusCode, out var restStatus, true))\n                {\n                    if (nameof(TableErrorCode.ResourceNotFound).Equals(restStatus))\n                    {\n                        LogDebugDataNotFound(logger, exc, tableName, iteration == 0 ? string.Empty : (\" Repeat=\" + iteration), httpStatusCode, restStatus);\n                        isLastErrorRetriable = false;\n                    }\n                    else\n                    {\n                        isLastErrorRetriable = IsRetriableHttpError(httpStatusCode, restStatus);\n                        LogWarningIntermediateIssueWithRestStatusCode(logger, exc, tableName, iteration == 0 ? \"\" : (\" Repeat=\" + iteration), isLastErrorRetriable, httpStatusCode, restStatus);\n                    }\n                }\n                else\n                {\n                    LogErrorUnexpectedIssue(logger, exc, tableName);\n                    isLastErrorRetriable = false;\n                }\n            }\n            return isLastErrorRetriable;\n        }\n\n        internal static string PrintStorageException(Exception exception)\n        {\n            if (exception is not RequestFailedException storeExc)\n            {\n                throw new ArgumentException($\"Unexpected exception type {exception.GetType().FullName}\");\n            }\n\n            return $\"Message = {storeExc.Message}, HTTP Status = {storeExc.Status}, HTTP Error Code = {storeExc.ErrorCode}.\";\n        }\n\n        internal static string PointQuery(string partitionKey, string rowKey)\n        {\n            return TableClient.CreateQueryFilter($\"(PartitionKey eq {partitionKey}) and (RowKey eq {rowKey})\");\n        }\n\n        internal static string RangeQuery(string partitionKey, string minRowKey, string maxRowKey)\n        {\n            return TableClient.CreateQueryFilter($\"((PartitionKey eq {partitionKey}) and (RowKey ge {minRowKey})) and (RowKey le {maxRowKey})\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_10,\n            Message = \"Intermediate issue reading Azure storage table {TableName}: HTTP status code={StatusCode}\"\n        )]\n        private static partial void LogWarningIntermediateIssue(ILogger logger, Exception exception, string tableName, WebExceptionStatus statusCode);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)Utilities.ErrorCode.AzureTable_DataNotFound,\n            Message = \"DataNotFound reading Azure storage table {TableName}:{Retry} HTTP status code={StatusCode} REST status code={RESTStatusCode}\"\n        )]\n        private static partial void LogDebugDataNotFound(ILogger logger, Exception exception, string tableName, string retry, HttpStatusCode statusCode, string restStatusCode);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)Utilities.ErrorCode.AzureTable_11,\n            Message = \"Intermediate issue reading Azure storage table {TableName}:{Retry} IsRetriable={IsLastErrorRetriable} HTTP status code={StatusCode} REST status code={RestStatusCode}\"\n        )]\n        private static partial void LogWarningIntermediateIssueWithRestStatusCode(ILogger logger, Exception exception, string tableName, string retry, bool isLastErrorRetriable, HttpStatusCode statusCode, string restStatusCode);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)Utilities.ErrorCode.AzureTable_12,\n            Message = \"Unexpected issue reading Azure storage table {TableName}\"\n        )]\n        private static partial void LogErrorUnexpectedIssue(ILogger logger, Exception exception, string tableName);\n    }\n}\n"
  },
  {
    "path": "src/Azure/Shared/Utilities/ErrorCode.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\n//\n// Number of #ifs can be reduced (or removed), once we separate test projects by feature/area, otherwise we are ending up with ambigous types and build errors.\n//\n\n#if ORLEANS_CLUSTERING\nnamespace Orleans.Clustering.AzureStorage.Utilities\n#elif ORLEANS_PERSISTENCE\nnamespace Orleans.Persistence.AzureStorage.Utilities\n#elif ORLEANS_REMINDERS_PROVIDER\nnamespace Orleans.Reminders\n#elif ORLEANS_REMINDERS\nnamespace Orleans.Reminders.AzureStorage.Utilities\n#elif ORLEANS_STREAMING\nnamespace Orleans.Streaming.AzureStorage.Utilities\n#elif ORLEANS_EVENTHUBS\nnamespace Orleans.Streaming.EventHubs.Utilities\n#elif TESTER_AZUREUTILS\nnamespace Orleans.Tests.AzureUtils.Utilities\n#elif ORLEANS_TRANSACTIONS\nnamespace Orleans.Transactions.AzureStorage.Utilities\n#elif ORLEANS_DIRECTORY\nnamespace Orleans.GrainDirectory.AzureStorage.Utilities\n#else\n// No default namespace intentionally to cause compile errors if something is not defined\n#endif\n{\n    [SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n    internal enum ErrorCode\n    {\n        Runtime = 100000,\n        AzureTableBase = Runtime + 800,\n\n        AzureTable_01 = AzureTableBase + 1,\n        AzureTable_02 = AzureTableBase + 2,\n        AzureTable_03 = AzureTableBase + 3,\n        AzureTable_04 = AzureTableBase + 4,\n        AzureTable_06 = AzureTableBase + 6,\n        AzureTable_07 = AzureTableBase + 7,\n        AzureTable_08 = AzureTableBase + 8,\n        AzureTable_09 = AzureTableBase + 9,\n        AzureTable_10 = AzureTableBase + 10,\n        AzureTable_11 = AzureTableBase + 11,\n        AzureTable_12 = AzureTableBase + 12,\n        AzureTable_13 = AzureTableBase + 13,\n        AzureTable_14 = AzureTableBase + 14,\n        AzureTable_15 = AzureTableBase + 15,\n        AzureTable_17 = AzureTableBase + 17,\n        AzureTable_18 = AzureTableBase + 18,\n        AzureTable_19 = AzureTableBase + 19,\n        AzureTable_37 = AzureTableBase + 37,\n        // Azure storage provider related\n        AzureTable_DataNotFound = AzureTableBase + 50,\n        AzureTable_TableNotCreated = AzureTableBase + 51,\n    }\n}\n"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/CassandraClusteringTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Cassandra;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.Cassandra.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.Clustering.Cassandra;\n\ninternal sealed class CassandraClusteringTable : IMembershipTable\n{\n    private const string NotInitializedMessage = $\"This instance has not been initialized. Ensure that {nameof(IMembershipTable.InitializeMembershipTable)} is called to initialize this instance before use.\";\n    private readonly ClusterOptions _clusterOptions;\n    private readonly CassandraClusteringOptions _options;\n    private readonly int? _ttlSeconds;\n    private readonly IServiceProvider _serviceProvider;\n    private ISession? _session;\n    private OrleansQueries? _queries;\n    private readonly string _identifier;\n\n    public CassandraClusteringTable(\n        IOptions<ClusterOptions> clusterOptions,\n        IOptions<CassandraClusteringOptions> options,\n        IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n        IServiceProvider serviceProvider)\n    {\n        _clusterOptions = clusterOptions.Value;\n        _options = options.Value;\n        _identifier = $\"{_clusterOptions.ServiceId}-{_clusterOptions.ClusterId}\";\n        _serviceProvider = serviceProvider;\n        _ttlSeconds = _options.GetCassandraTtlSeconds(clusterMembershipOptions.Value);\n    }\n\n    private ISession Session => _session ?? throw new InvalidOperationException(NotInitializedMessage);\n\n    private OrleansQueries Queries => _queries ?? throw new InvalidOperationException(NotInitializedMessage);\n\n    async Task IMembershipTable.InitializeMembershipTable(bool tryInitTableVersion)\n    {\n        _session = await _options.CreateSessionAsync(_serviceProvider);\n        if (_session is null)\n        {\n            throw new InvalidOperationException($\"Session created from configuration '{nameof(CassandraClusteringOptions)}' is null.\");\n        }\n\n        _queries = await OrleansQueries.CreateInstance(_session);\n\n        await _queries.EnsureTableExistsAsync(_options.InitializeRetryMaxDelay, _ttlSeconds);\n\n        if (tryInitTableVersion)\n            await _queries.EnsureClusterVersionExistsAsync(_options.InitializeRetryMaxDelay, _identifier);\n    }\n\n    async Task IMembershipTable.DeleteMembershipTableEntries(string clusterId)\n    {\n        if (string.Compare(clusterId, _clusterOptions.ClusterId, StringComparison.InvariantCultureIgnoreCase) != 0)\n        {\n            throw new ArgumentException(\n                $\"Cluster id {clusterId} does not match CassandraClusteringTable value of '{_clusterOptions.ClusterId}'.\",\n                nameof(clusterId));\n        }\n\n        await Session.ExecuteAsync(await Queries.DeleteMembershipTableEntries(_identifier));\n    }\n\n    async Task<bool> IMembershipTable.InsertRow(MembershipEntry entry, TableVersion tableVersion)\n    {\n        // Prevent duplicate rows\n        var existingRow = await ((IMembershipTable)this).ReadRow(entry.SiloAddress);\n        if (existingRow is not null)\n        {\n            if (existingRow.Version.Version >= tableVersion.Version)\n            {\n                return false;\n            }\n\n            if (existingRow.Members.Any(m => m.Item1.SiloAddress.Equals(entry.SiloAddress)))\n            {\n                return false;\n            }\n        }\n\n        var query = await Session.ExecuteAsync(await Queries.InsertMembership(_identifier, entry, tableVersion.Version - 1));\n        return (bool)query.First()[\"[applied]\"];\n    }\n\n    async Task<bool> IMembershipTable.UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n    {\n        var query = await Session.ExecuteAsync(await Queries.UpdateMembership(_identifier, entry, tableVersion.Version - 1));\n        return (bool)query.First()[\"[applied]\"];\n    }\n\n    private static MembershipEntry? GetMembershipEntry(Row row)\n    {\n        if (row[\"start_time\"] == null)\n        {\n            return null;\n        }\n\n        var result = new MembershipEntry\n        {\n            SiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Parse((string)row[\"address\"]), (int)row[\"port\"]), (int)row[\"generation\"]),\n            SiloName = (string)row[\"silo_name\"],\n            HostName = (string)row[\"host_name\"],\n            Status = (SiloStatus)(int)row[\"status\"],\n            ProxyPort = (int)row[\"proxy_port\"],\n            StartTime = ((DateTimeOffset)row[\"start_time\"]).UtcDateTime,\n            IAmAliveTime = ((DateTimeOffset)row[\"i_am_alive_time\"]).UtcDateTime\n        };\n\n        var suspectingSilos = (string)row[\"suspect_times\"];\n        if (!string.IsNullOrWhiteSpace(suspectingSilos))\n        {\n            result.SuspectTimes =\n            [\n                .. suspectingSilos.Split('|').Select(s =>\n                {\n                    var split = s.Split(',');\n                    return new Tuple<SiloAddress, DateTime>(SiloAddress.FromParsableString(split[0]), LogFormatter.ParseDate(split[1]));\n                }),\n            ];\n        }\n\n        return result;\n    }\n\n    private async Task<MembershipTableData> GetMembershipTableData(RowSet rows)\n    {\n        var firstRow = rows.FirstOrDefault();\n        if (firstRow != null)\n        {\n            var version = (int)firstRow[\"version\"];\n\n            var entries = new List<Tuple<MembershipEntry, string>>();\n            foreach (var row in new[] { firstRow }.Concat(rows))\n            {\n                var entry = GetMembershipEntry(row);\n                if (entry != null)\n                {\n                    entries.Add(new Tuple<MembershipEntry, string>(entry, string.Empty));\n                }\n            }\n\n            return new MembershipTableData(entries, new TableVersion(version, version.ToString()));\n        }\n        else\n        {\n            var result = (await Session.ExecuteAsync(await Queries.MembershipReadVersion(_identifier))).FirstOrDefault();\n            if (result is null)\n            {\n                return new MembershipTableData([], new TableVersion(0, \"0\"));\n            }\n\n            var version = (int)result[\"version\"];\n            return new MembershipTableData([], new TableVersion(version, version.ToString()));\n        }\n    }\n\n    async Task<MembershipTableData> IMembershipTable.ReadAll()\n    {\n        return await GetMembershipTableData(await Session.ExecuteAsync(await Queries.MembershipReadAll(_identifier)));\n    }\n\n    async Task<MembershipTableData> IMembershipTable.ReadRow(SiloAddress key)\n    {\n        return await GetMembershipTableData(await Session.ExecuteAsync(await Queries.MembershipReadRow(_identifier, key)));\n    }\n\n    async Task IMembershipTable.UpdateIAmAlive(MembershipEntry entry)\n    {\n        if (_ttlSeconds.HasValue)\n        {\n            // User has opted in to Cassandra TTL behavior for membership table rows, which means the entire row's data\n            // has to be written back so each cell's TTL can be updated\n            MembershipTableData existingRow = await ((IMembershipTable)this).ReadRow(entry.SiloAddress);\n\n            await Session.ExecuteAsync(await Queries.UpdateIAmAliveTimeWithTtL(\n                clusterIdentifier: _identifier,\n                // The MembershipEntry given to this method by Orleans only contains the SiloAddress and new IAmAliveTime\n                iAmAliveEntry: entry,\n                existingEntry: existingRow.Members[0].Item1,\n                existingVersion: existingRow.Version));\n        }\n        else\n        {\n            await Session.ExecuteAsync(await Queries.UpdateIAmAliveTime(_identifier, entry));\n        }\n    }\n\n    public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n    {\n        var allEntries =\n            (await Session.ExecuteAsync(await Queries.MembershipReadAll(_identifier)))\n            .Select(GetMembershipEntry)\n            .Where((MembershipEntry? e) => e is not null)\n            .Cast<MembershipEntry>();\n\n        foreach (var e in allEntries)\n        {\n            if (e is not { Status: SiloStatus.Active } && new DateTime(Math.Max(e.IAmAliveTime.Ticks, e.StartTime.Ticks), DateTimeKind.Utc) < beforeDate)\n            {\n                await Session.ExecuteAsync(await Queries.DeleteMembershipEntry(_identifier, e));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/CassandraGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Cassandra;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.Cassandra.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Clustering.Cassandra;\n\ninternal sealed class CassandraGatewayListProvider : IGatewayListProvider\n{\n    private const string NotInitializedMessage = $\"This instance has not been initialized. Ensure that {nameof(IGatewayListProvider.InitializeGatewayListProvider)} is called to initialize this instance before use.\";\n    private readonly TimeSpan _maxStaleness;\n    private readonly string _identifier;\n    private readonly CassandraClusteringOptions _options;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly int? _ttlSeconds;\n    private ISession? _session;\n    private OrleansQueries? _queries;\n    private DateTime _cacheUntil;\n    private List<Uri>? _cachedResult;\n\n    TimeSpan IGatewayListProvider.MaxStaleness => _maxStaleness;\n\n    bool IGatewayListProvider.IsUpdatable => true;\n\n    public CassandraGatewayListProvider(\n        IOptions<ClusterOptions> clusterOptions,\n        IOptions<GatewayOptions> gatewayOptions,\n        IOptions<CassandraClusteringOptions> options,\n        IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n        IServiceProvider serviceProvider)\n    {\n        _identifier = $\"{clusterOptions.Value.ServiceId}-{clusterOptions.Value.ClusterId}\";\n        _options = options.Value;\n        _serviceProvider = serviceProvider;\n\n        _maxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n        _ttlSeconds = _options.GetCassandraTtlSeconds(clusterMembershipOptions.Value);\n    }\n\n    private ISession Session => _session ?? throw new InvalidOperationException(NotInitializedMessage);\n\n    private OrleansQueries Queries => _queries ?? throw new InvalidOperationException(NotInitializedMessage);\n\n    async Task IGatewayListProvider.InitializeGatewayListProvider()\n    {\n        _session = await _options.CreateSessionAsync(_serviceProvider);\n        if (_session is null)\n        {\n            throw new InvalidOperationException($\"Session created from configuration '{nameof(CassandraClusteringOptions)}' is null.\");\n        }\n\n        _queries = await OrleansQueries.CreateInstance(_session);\n\n        await _queries.EnsureTableExistsAsync(_options.InitializeRetryMaxDelay, _ttlSeconds);\n    }\n    \n    async Task<IList<Uri>> IGatewayListProvider.GetGateways()\n    {\n        if (_cachedResult is not null && _cacheUntil > DateTime.UtcNow)\n        {\n            return [.. _cachedResult];\n        }\n\n        var rows = await Session.ExecuteAsync(await Queries.GatewaysQuery(_identifier, (int)SiloStatus.Active));\n        var result = new List<Uri>();\n\n        foreach (var row in rows)\n        {\n            result.Add(SiloAddress.New(new IPEndPoint(IPAddress.Parse((string)row[\"address\"]), (int)row[\"proxy_port\"]), (int)row[\"generation\"]).ToGatewayUri());\n        }\n\n        _cacheUntil = DateTime.UtcNow + _maxStaleness;\n        _cachedResult = result;\n        return [.. result];\n    }\n}"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/Hosting/CassandraClusteringOptions.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Cassandra;\nusing Orleans.Configuration;\n\nnamespace Orleans.Clustering.Cassandra.Hosting;\n\n/// <summary>\n/// Options for configuring Cassandra clustering.\n/// </summary>\npublic class CassandraClusteringOptions\n{\n    /// <summary>\n    /// Optionally configure time-to-live behavior for the membership table row data in Cassandra itself, allowing\n    /// defunct silo cleanup even if a cluster is no longer running.\n    /// <para/>\n    /// When this is <c>true</c>, <see cref=\"ClusterMembershipOptions.DefunctSiloCleanupPeriod\"/> CAN be null to enable\n    /// Cassandra-only defunct silo cleanup. Either way, the Cassandra TTL will still be configured from the\n    /// configured <see cref=\"ClusterMembershipOptions.DefunctSiloExpiration\"/> value.\n    /// </summary>\n    /// <remarks>\n    /// Initial implementation of https://github.com/dotnet/orleans/issues/9164 in that it only affects silo entries\n    /// that are updated with IAmAlive and will not attempt to update, for instance, the entire membership table. It\n    /// also will not affect membership tables that have already been created, since it uses the Cassandra table-level\n    /// <c>default_time_to_live</c>.\n    /// </remarks>\n    public bool UseCassandraTtl { get; set; }\n\n    /// <summary>\n    /// Specifies the maximum amount of time to wait after encountering\n    /// contention during initialization before retrying.\n    /// </summary>\n    /// <remarks>This is generally only encountered with large numbers of silos connecting\n    /// in a short time period and using multi-datacenter Cassandara clusters</remarks>\n    public TimeSpan InitializeRetryMaxDelay { get; set; } = TimeSpan.FromSeconds(20);\n\n    internal int? GetCassandraTtlSeconds(ClusterMembershipOptions clusterMembershipOptions) =>\n        UseCassandraTtl\n            ? Convert.ToInt32(\n                Math.Round(\n                    clusterMembershipOptions.DefunctSiloExpiration.TotalSeconds,\n                    MidpointRounding.AwayFromZero))\n            : null;\n\n    /// <summary>\n    /// Configures the Cassandra client.\n    /// </summary>\n    /// <param name=\"connectionString\">The connection string.</param>\n    /// <param name=\"keyspace\">The keyspace.</param>\n    public void ConfigureClient(string connectionString, string keyspace = \"orleans\")\n    {\n        ArgumentException.ThrowIfNullOrEmpty(connectionString);\n        ArgumentNullException.ThrowIfNull(keyspace);\n        CreateSessionAsync = async sp =>\n        {\n            var c = Cluster.Builder().WithConnectionString(connectionString)\n                .Build();\n\n            var session = await c.ConnectAsync(keyspace).ConfigureAwait(false);\n            return session;\n        };\n    }\n\n    /// <summary>\n    /// Configures the Cassandra client.\n    /// </summary>\n    /// <param name=\"configurationDelegate\">The connection string.</param>\n    public void ConfigureClient(Func<IServiceProvider, Task<ISession>> configurationDelegate)\n    {\n        ArgumentNullException.ThrowIfNull(configurationDelegate);\n        CreateSessionAsync = configurationDelegate;\n    }\n\n    [NotNull]\n    internal Func<IServiceProvider, Task<ISession>> CreateSessionAsync { get; private set; } = default!;\n}"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/Hosting/CassandraMembershipHostingExtensions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Cassandra;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Messaging;\n\nnamespace Orleans.Clustering.Cassandra.Hosting;\n\n/// <summary>\n/// Extension methods for configuring Cassandra as a clustering provider.\n/// </summary>\npublic static class CassandraMembershipHostingExtensions\n{\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <returns>The client builder.</returns>\n    public static IClientBuilder UseCassandraClustering(this IClientBuilder builder) =>\n        builder.ConfigureServices(services =>\n        {\n            services.AddSingleton<IGatewayListProvider, CassandraGatewayListProvider>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <param name=\"sessionProvider\">A delegate used to create an <see cref=\"ISession\"/>.</param>\n    /// <returns>The client builder.</returns>\n    public static IClientBuilder UseCassandraClustering(this IClientBuilder builder, Func<IServiceProvider, Task<ISession>> sessionProvider) =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(o => o.ConfigureClient(sessionProvider));\n            services.AddSingleton<IGatewayListProvider, CassandraGatewayListProvider>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the Cassandra client.</param>\n    /// <returns>The client builder.</returns>\n    public static IClientBuilder UseCassandraClustering(this IClientBuilder builder, Action<CassandraClusteringOptions> configureOptions) =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(configureOptions);\n            services.AddSingleton<IGatewayListProvider, CassandraGatewayListProvider>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The client builder.</param>\n    /// <param name=\"connectionString\">The Cassandra connection string.</param>\n    /// <param name=\"keyspace\">The Cassandra keyspace, which defaults to <c>orleans</c>.</param>\n    /// <returns>The client builder.</returns>\n    public static IClientBuilder UseCassandraClustering(this IClientBuilder builder, string connectionString, string keyspace = \"orleans\") =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(o => o.ConfigureClient(connectionString, keyspace));\n            services.AddSingleton<IGatewayListProvider, CassandraGatewayListProvider>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <returns>The silo builder.</returns>\n    /// <remarks>Pulls <see cref=\"IOptions{TOptions}\"/> of type <see cref=\"ClusterOptions\"/> and <see cref=\"ISession\"/> from the DI container</remarks>\n    public static ISiloBuilder UseCassandraClustering(this ISiloBuilder builder) =>\n        builder.ConfigureServices(services =>\n        {\n            services.AddSingleton<IMembershipTable, CassandraClusteringTable>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"sessionProvider\">A delegate used to create an <see cref=\"ISession\"/>.</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder UseCassandraClustering(this ISiloBuilder builder, Func<IServiceProvider, Task<ISession>> sessionProvider) =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(o => o.ConfigureClient(sessionProvider));\n            services.AddSingleton<IMembershipTable, CassandraClusteringTable>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the Cassandra client.</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder UseCassandraClustering(this ISiloBuilder builder, Action<CassandraClusteringOptions> configureOptions) =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(configureOptions);\n            services.AddSingleton<IMembershipTable, CassandraClusteringTable>();\n        });\n\n    /// <summary>\n    /// Configures Orleans clustering using Cassandra.\n    /// </summary>\n    /// <param name=\"builder\">The silo builder.</param>\n    /// <param name=\"connectionString\">The Cassandra connection string.</param>\n    /// <param name=\"keyspace\">The Cassandra keyspace, which defaults to <c>orleans</c>.</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder UseCassandraClustering(this ISiloBuilder builder, string connectionString, string keyspace = \"orleans\") =>\n        builder.ConfigureServices(services =>\n        {\n            services.Configure<CassandraClusteringOptions>(o => o.ConfigureClient(connectionString, keyspace));\n            services.AddSingleton<IMembershipTable, CassandraClusteringTable>();\n        });\n}"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/Orleans.Clustering.Cassandra.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.Cassandra</PackageId>\n    <Title>Microsoft Orleans Cassandra Clustering Provider</Title>\n    <Description>Microsoft Orleans clustering provider backed by Cassandra</Description>\n    <PackageTags>$(PackageTags) Cassandra</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Clustering.Cassandra</AssemblyName>\n    <RootNamespace>Orleans.Clustering.Cassandra</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_CLUSTERING</DefineConstants>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"CassandraCSharpDriver\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Clustering.Cassandra.Tests\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Cassandra/Orleans.Clustering.Cassandra/OrleansQueries.cs",
    "content": "using System;\nusing Cassandra;\nusing Orleans.Runtime;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Clustering.Cassandra;\n\n/// <summary>\n/// This class is responsible for keeping a list of prepared queries and\n/// knowing their parameters (including type and conversion to the target\n/// type).\n/// </summary>\ninternal sealed class OrleansQueries\n{\n    public ISession Session { get; }\n\n    private PreparedStatement? _insertMembershipVersionPreparedStatement;\n    private PreparedStatement? _deleteMembershipTablePreparedStatement;\n    private PreparedStatement? _insertMembershipPreparedStatement;\n    private PreparedStatement? _membershipReadAllPreparedStatement;\n    private PreparedStatement? _membershipReadVersionPreparedStatement;\n    private PreparedStatement? _updateIAmAlivePreparedStatement;\n    private PreparedStatement? _updateIAmAliveWithTtlPreparedStatement;\n    private PreparedStatement? _deleteMembershipEntryPreparedStatement;\n    private PreparedStatement? _updateMembershipPreparedStatement;\n    private PreparedStatement? _membershipReadRowPreparedStatement;\n    private PreparedStatement? _membershipGatewaysQueryPreparedStatement;\n\n    public static Task<OrleansQueries> CreateInstance(ISession session)\n    {\n        return Task.FromResult(new OrleansQueries(session));\n    }\n\n    private OrleansQueries(ISession session)\n    {\n        MembershipReadConsistencyLevel = ConsistencyLevel.Quorum;\n        MembershipWriteConsistencyLevel = ConsistencyLevel.Quorum;\n\n        Session = session;\n    }\n\n    internal async Task EnsureTableExistsAsync(TimeSpan maxRetryDelay, int? ttl)\n    {\n        if (!await DoesTableAlreadyExistAsync())\n        {\n            try\n            {\n                await MakeTableAsync(ttl);\n            }\n            catch (WriteTimeoutException) // If there's contention on table creation, backoff a bit and try once more\n            {\n                // Randomize the delay to avoid contention, preferring that more instances will wait longer\n                var nextSingle = Random.Shared.NextSingle();\n                await Task.Delay(maxRetryDelay * Math.Sqrt(nextSingle));\n\n                if (!await DoesTableAlreadyExistAsync())\n                {\n                    await MakeTableAsync(ttl);\n                }\n            }\n        }\n    }\n\n    internal async Task EnsureClusterVersionExistsAsync(TimeSpan maxRetryDelay, string clusterIdentifier)\n    {\n        if (!await DoesClusterVersionAlreadyExistAsync(clusterIdentifier))\n        {\n            try\n            {\n                await Session.ExecuteAsync(await InsertMembershipVersion(clusterIdentifier));\n            }\n            catch (WriteTimeoutException) // If there's contention on table creation, backoff a bit and try once more\n            {\n                // Randomize the delay to avoid contention, preferring that more instances will wait longer\n                var nextSingle = Random.Shared.NextSingle();\n                await Task.Delay(maxRetryDelay * Math.Sqrt(nextSingle));\n\n                if (!await DoesClusterVersionAlreadyExistAsync(clusterIdentifier))\n                {\n                    await Session.ExecuteAsync(await InsertMembershipVersion(clusterIdentifier));\n                }\n            }\n        }\n    }\n\n    private async Task<bool> DoesClusterVersionAlreadyExistAsync(string clusterIdentifier)\n    {\n        try\n        {\n            var resultSet = await Session.ExecuteAsync(CheckIfClusterVersionExists(clusterIdentifier, ConsistencyLevel.LocalOne));\n            return resultSet.Any();\n        }\n        catch (UnavailableException)\n        {\n            var resultSet = await Session.ExecuteAsync(CheckIfClusterVersionExists(clusterIdentifier, ConsistencyLevel.One));\n            return resultSet.Any();\n        }\n    }\n\n    private async Task<bool> DoesTableAlreadyExistAsync()\n    {\n        try\n        {\n            var resultSet = await Session.ExecuteAsync(CheckIfTableExists(Session.Keyspace, ConsistencyLevel.LocalOne));\n            return resultSet.Any();\n        }\n        catch (UnavailableException)\n        {\n            var resultSet = await Session.ExecuteAsync(CheckIfTableExists(Session.Keyspace, ConsistencyLevel.One));\n            return resultSet.Any();\n        }\n        catch (UnauthorizedException)\n        {\n            return false;\n        }\n    }\n\n    private async Task MakeTableAsync(int? ttlSeconds)\n    {\n        await Session.ExecuteAsync(EnsureTableExists(ttlSeconds));\n        await Session.ExecuteAsync(EnsureIndexExists);\n    }\n\n    public ConsistencyLevel MembershipWriteConsistencyLevel { get; set; }\n\n    public ConsistencyLevel MembershipReadConsistencyLevel { get; set; }\n\n    public IStatement CheckIfClusterVersionExists(string clusterIdentifier, ConsistencyLevel consistencyLevel) =>\n        new SimpleStatement(\n                $\"SELECT version FROM membership WHERE partition_key = '{clusterIdentifier}';\")\n            .SetConsistencyLevel(consistencyLevel);\n\n    public IStatement CheckIfTableExists(string keyspace, ConsistencyLevel consistencyLevel) =>\n        new SimpleStatement(\n                $\"SELECT * FROM system_schema.tables WHERE keyspace_name = '{keyspace}' AND table_name = 'membership';\")\n            .SetConsistencyLevel(consistencyLevel);\n\n    /// <remarks>\n    /// In Cassandra, a table-level <c>default_time_to_live</c> of <c>0</c> is treated as <c>disabled</c>.\n    /// <para/>\n    /// See https://docs.datastax.com/en/cql-oss/3.3/cql/cql_reference/cqlCreateTable.html#tabProp__cqlTableDefaultTTL\n    /// </remarks>\n    public IStatement EnsureTableExists(int? defaultTimeToLiveSeconds) => new SimpleStatement(\n        $$\"\"\"\n          CREATE TABLE IF NOT EXISTS membership\n          (\n              partition_key ascii,\n              version int static,\n              address ascii,\n              port int,\n              generation int,\n              silo_name text,\n              host_name text,\n              status int,\n              proxy_port int,\n              suspect_times ascii,\n              start_time timestamp,\n              i_am_alive_time timestamp,\n\n              PRIMARY KEY(partition_key, address, port, generation)\n          )\n          WITH compression = { 'class' : 'LZ4Compressor', 'enabled' : true }\n            AND default_time_to_live = {{defaultTimeToLiveSeconds.GetValueOrDefault(0)}};\n          \"\"\");\n    \n    public IStatement EnsureIndexExists => new SimpleStatement(\"\"\"\n            CREATE INDEX IF NOT EXISTS ix_membership_status ON membership(status);\n            \"\"\");\n\n    public async ValueTask<IStatement> InsertMembership(string clusterIdentifier, MembershipEntry membershipEntry, int version)\n    {\n        _insertMembershipPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n           UPDATE membership\n           SET\n             version = :new_version,\n             status = :status,\n             start_time = :start_time,\n             silo_name = :silo_name,\n             host_name = :host_name,\n             proxy_port = :proxy_port,\n             i_am_alive_time = :i_am_alive_time\n           WHERE\n             partition_key = :partition_key\n             AND address = :address\n             AND port = :port\n             AND generation = :generation\n           IF\n             version = :expected_version;\n           \"\"\", MembershipWriteConsistencyLevel);\n        return _insertMembershipPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            address = membershipEntry.SiloAddress.Endpoint.Address.ToString(),\n            port = membershipEntry.SiloAddress.Endpoint.Port,\n            generation = membershipEntry.SiloAddress.Generation,\n            silo_name = membershipEntry.SiloName,\n            host_name = membershipEntry.HostName,\n            status = (int)membershipEntry.Status,\n            proxy_port = membershipEntry.ProxyPort,\n            start_time = membershipEntry.StartTime,\n            i_am_alive_time = membershipEntry.IAmAliveTime,\n            new_version = version + 1,\n            expected_version = version\n        });\n    }\n\n    public async ValueTask<IStatement> InsertMembershipVersion(string clusterIdentifier)\n    {\n        _insertMembershipVersionPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            INSERT INTO membership(\n            \tpartition_key,\n            \tversion\n            )\n            VALUES (\n            \t:partition_key,\n            \t0\n            )\n            IF NOT EXISTS;\n            \"\"\", MembershipWriteConsistencyLevel);\n        return _insertMembershipVersionPreparedStatement.Bind(clusterIdentifier);\n    }\n\n    public async ValueTask<IStatement> DeleteMembershipTableEntries(string clusterIdentifier)\n    {\n        _deleteMembershipTablePreparedStatement ??= await PrepareStatementAsync(\"\"\"\n                DELETE FROM membership WHERE partition_key = :partition_key;\n                \"\"\",\n            MembershipWriteConsistencyLevel);\n        return _deleteMembershipTablePreparedStatement.Bind(clusterIdentifier);\n    }\n\n    public async ValueTask<IStatement> UpdateIAmAliveTime(string clusterIdentifier, MembershipEntry membershipEntry)\n    {\n        _updateIAmAlivePreparedStatement ??= await PrepareStatementAsync(\"\"\"\n             UPDATE membership\n             SET\n                i_am_alive_time = :i_am_alive_time\n             WHERE\n                partition_key = :partition_key\n                AND address = :address\n                AND port = :port\n                AND generation = :generation;\n             \"\"\",\n            ConsistencyLevel.Any);\n\n        return _updateIAmAlivePreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            i_am_alive_time = membershipEntry.IAmAliveTime,\n            address = membershipEntry.SiloAddress.Endpoint.Address.ToString(),\n            port = membershipEntry.SiloAddress.Endpoint.Port,\n            generation = membershipEntry.SiloAddress.Generation\n        });\n    }\n\n    /// <remarks>\n    /// When the user has opted in to Cassandra TTL behavior, the entire membership row needs to be read and written\n    /// back so that each cell is updated with the table's default TTL.\n    /// <para/>\n    /// Cassandra TTLs are cell-based, not row-based, which is why all the data needs to be re-inserted in order to\n    /// update the TTLs for all cells in the row.\n    /// <para/>\n    /// https://docs.datastax.com/en/cql-oss/3.x/cql/cql_reference/cqlInsert.html\n    /// </remarks>\n    public async ValueTask<IStatement> UpdateIAmAliveTimeWithTtL(\n        string clusterIdentifier,\n        MembershipEntry iAmAliveEntry,\n        MembershipEntry existingEntry,\n        TableVersion existingVersion)\n    {\n        _updateIAmAliveWithTtlPreparedStatement ??= await PrepareStatementAsync(\n            \"\"\"\n            UPDATE membership\n            SET\n                version = :same_version,\n                silo_name = :silo_name,\n                host_name = :host_name,\n                status = :status,\n                proxy_port = :proxy_port,\n                suspect_times = :suspect_times,\n                start_time = :start_time,\n                i_am_alive_time = :i_am_alive_time\n            WHERE\n                partition_key = :partition_key\n                AND address = :address\n                AND port = :port\n                AND generation = :generation\n            IF\n            \tversion = :expected_version;\n            \"\"\",\n            // This is ignored because we're creating a LWT\n            MembershipWriteConsistencyLevel);\n\n        BoundStatement updateIAmAliveTimeWithTtL = _updateIAmAliveWithTtlPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            // The same version still needs to be written, to update its cell-level TTL\n            same_version = existingVersion.Version,\n            address = existingEntry.SiloAddress.Endpoint.Address.ToString(),\n            port = existingEntry.SiloAddress.Endpoint.Port,\n            generation = existingEntry.SiloAddress.Generation,\n            silo_name = existingEntry.SiloName,\n            host_name = existingEntry.HostName,\n            status = (int)existingEntry.Status,\n            proxy_port = existingEntry.ProxyPort,\n            suspect_times = GetSuspectTimesString(existingEntry),\n            start_time = existingEntry.StartTime,\n            i_am_alive_time = iAmAliveEntry.IAmAliveTime,\n            // But we still check that the version was the same during the update so we don't stomp on another update\n            expected_version = existingVersion.Version,\n        });\n\n        // To improve performance, we allow IAmAlive updates to be LocalSerial\n        updateIAmAliveTimeWithTtL.SetSerialConsistencyLevel(ConsistencyLevel.LocalSerial);\n        return updateIAmAliveTimeWithTtL;\n    }\n\n    public async ValueTask<IStatement> DeleteMembershipEntry(string clusterIdentifier, MembershipEntry membershipEntry)\n    {\n        _deleteMembershipEntryPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            DELETE FROM\n            \tmembership\n            WHERE\n            \tpartition_key = :partition_key\n            \tAND address = :address\n            \tAND port = :port\n            \tAND generation = :generation;\n            \"\"\", MembershipWriteConsistencyLevel);\n        return _deleteMembershipEntryPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            address = membershipEntry.SiloAddress.Endpoint.Address.ToString(),\n            port = membershipEntry.SiloAddress.Endpoint.Port,\n            generation = membershipEntry.SiloAddress.Generation\n        });\n    }\n\n    public async ValueTask<IStatement> UpdateMembership(string clusterIdentifier, MembershipEntry membershipEntry, int version)\n    {\n        _updateMembershipPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            UPDATE membership\n            SET\n            \tversion = :new_version,\n            \tstatus = :status,\n            \tsuspect_times = :suspect_times,\n            \ti_am_alive_time = :i_am_alive_time\n            WHERE\n            \tpartition_key = :partition_key\n            \tAND address = :address\n            \tAND port = :port\n            \tAND generation = :generation\n            IF\n            \tversion = :expected_version;\n            \"\"\", MembershipWriteConsistencyLevel);\n        return _updateMembershipPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            new_version = version + 1,\n            expected_version = version,\n            status = (int)membershipEntry.Status,\n            suspect_times = GetSuspectTimesString(membershipEntry),\n            i_am_alive_time = membershipEntry.IAmAliveTime,\n            address = membershipEntry.SiloAddress.Endpoint.Address.ToString(),\n            port = membershipEntry.SiloAddress.Endpoint.Port,\n            generation = membershipEntry.SiloAddress.Generation\n        });\n    }\n\n    public async ValueTask<IStatement> MembershipReadVersion(string clusterIdentifier)\n    {\n        _membershipReadVersionPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n                SELECT\n                \tversion\n                FROM\n                \tmembership\n                WHERE\n                \tpartition_key = :partition_key;\n                \"\"\",\n            MembershipReadConsistencyLevel);\n        return _membershipReadVersionPreparedStatement.Bind(clusterIdentifier);\n    }\n\n    public async ValueTask<IStatement> MembershipReadAll(string clusterIdentifier)\n    {\n        _membershipReadAllPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            SELECT\n                version,\n                address,\n                port,\n                generation,\n                silo_name,\n                host_name,\n                status,\n                proxy_port,\n                suspect_times,\n                start_time,\n                i_am_alive_time\n            FROM\n                membership\n            WHERE\n                partition_key = :partition_key;\n            \"\"\",\n            MembershipReadConsistencyLevel);\n        return _membershipReadAllPreparedStatement.Bind(clusterIdentifier);\n    }\n\n    public async ValueTask<IStatement> MembershipReadRow(string clusterIdentifier, SiloAddress siloAddress)\n    {\n        _membershipReadRowPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            SELECT\n                version,\n                address,\n                port,\n                generation,\n                silo_name,\n                host_name,\n                status,\n                proxy_port,\n                suspect_times,\n                start_time,\n                i_am_alive_time\n            FROM\n                membership\n            WHERE\n                partition_key = :partition_key\n                AND address = :address\n                AND port = :port\n                AND generation = :generation;\n            \"\"\",\n            MembershipReadConsistencyLevel);\n        return _membershipReadRowPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            address = siloAddress.Endpoint.Address.ToString(),\n            port = siloAddress.Endpoint.Port,\n            generation = siloAddress.Generation\n        });\n    }\n\n    public async ValueTask<IStatement> GatewaysQuery(string clusterIdentifier, int status)\n    {\n        // Filtering is only for the `proxy_port` filtering. We're already hitting the partition\n        // and secondary index on status which both don't need \"ALLOW FILTERING\"\n        _membershipGatewaysQueryPreparedStatement ??= await PrepareStatementAsync(\"\"\"\n            SELECT\n                address,\n                proxy_port,\n                generation\n            FROM\n                membership\n            WHERE\n                partition_key = :partition_key\n                AND status = :status\n                AND proxy_port > 0\n            ALLOW FILTERING;\n            \"\"\",\n            MembershipReadConsistencyLevel);\n        return _membershipGatewaysQueryPreparedStatement.Bind(new\n        {\n            partition_key = clusterIdentifier,\n            status = status\n        });\n    }\n\n    private async ValueTask<PreparedStatement> PrepareStatementAsync(string cql, ConsistencyLevel consistencyLevel)\n    {\n        var statement = await Session.PrepareAsync(cql);\n        statement.SetConsistencyLevel(consistencyLevel);\n        return statement;\n    }\n\n    private static string? GetSuspectTimesString(MembershipEntry entry) =>\n        entry.SuspectTimes == null\n            ? null\n            : string.Join(\n                \"|\",\n                entry.SuspectTimes.Select((Tuple<SiloAddress, DateTime> s) =>\n                    $\"{s.Item1.ToParsableString()},{LogFormatter.PrintDate(s.Item2)}\"));\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/.azdo/.npmrc",
    "content": "registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/\n\nalways-auth=true\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/DashboardClient.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\n\nnamespace Orleans.Dashboard.Core;\n\ninternal sealed class DashboardClient(IGrainFactory grainFactory) : IDashboardClient\n{\n    private readonly IDashboardGrain _dashboardGrain = grainFactory.GetGrain<IDashboardGrain>(0);\n    private readonly IDashboardRemindersGrain _remindersGrain = grainFactory.GetGrain<IDashboardRemindersGrain>(0);\n    private readonly IGrainFactory _grainFactory = grainFactory;\n\n    public async Task<Immutable<DashboardCounters>> DashboardCounters(string[] exclusions) => await _dashboardGrain.GetCounters(exclusions);\n\n    public async Task<Immutable<Dictionary<string, GrainTraceEntry>>> ClusterStats() => await _dashboardGrain.GetClusterTracing();\n\n    public async Task<Immutable<ReminderResponse>> GetReminders(int pageNumber, int pageSize) => await _remindersGrain.GetReminders(pageNumber, pageSize);\n\n    public async Task<Immutable<SiloRuntimeStatistics[]>> HistoricalStats(string siloAddress) => await Silo(siloAddress).GetRuntimeStatistics();\n\n    public async Task<Immutable<Dictionary<string, string>>> SiloProperties(string siloAddress) => await Silo(siloAddress).GetExtendedProperties();\n\n    public async Task<Immutable<Dictionary<string, string>>> SiloMetadata(string siloAddress) => await Silo(siloAddress).GetMetadata();\n\n    public async Task<Immutable<Dictionary<string, GrainTraceEntry>>> SiloStats(string siloAddress) => await _dashboardGrain.GetSiloTracing(siloAddress);\n\n    public async Task<Immutable<StatCounter[]>> GetCounters(string siloAddress) => await Silo(siloAddress).GetCounters();\n\n    public async Task<Immutable<Dictionary<string, Dictionary<string, GrainTraceEntry>>>> GrainStats(\n        string grainName) => await _dashboardGrain.GetGrainTracing(grainName);\n\n    public async Task<Immutable<Dictionary<string, GrainMethodAggregate[]>>> TopGrainMethods(int take, string[] exclusions) => await _dashboardGrain.TopGrainMethods(take, exclusions);\n\n    private ISiloGrainProxy Silo(string siloAddress) => _grainFactory.GetGrain<ISiloGrainProxy>(siloAddress);\n\n    public async Task<Immutable<string>> GetGrainState(string id, string grainType) => await _dashboardGrain.GetGrainState(id, grainType);\n\n    public async Task<Immutable<string[]>> GetGrainTypes(string[] exclusions = null) => await _dashboardGrain.GetGrainTypes(exclusions);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/Extensions.cs",
    "content": "using System;\nusing System.Globalization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Dashboard.Core;\n\ninternal static class Extensions\n{\n    private static readonly DateTime UnixStart = new(1970, 1, 1);\n\n    public static string PrimaryKeyAsString(this GrainReference grainRef)\n    {\n        if (grainRef.IsPrimaryKeyBasedOnLong()) // Long\n        {\n            var longKey = grainRef.GetPrimaryKeyLong(out var longExt);\n\n            return longExt != null ? $\"{longKey} + {longExt}\" : longKey.ToString();\n        }\n\n        var stringKey = grainRef.GetPrimaryKeyString();\n\n        if (stringKey == null) // Guid\n        {\n            var guidKey = grainRef.GetPrimaryKey(out var guidExt).ToString();\n\n            return guidExt != null ? $\"{guidKey} + {guidExt}\" : guidKey;\n        }\n\n        return stringKey;\n    }\n\n    public static string ToPeriodString(this DateTime value) => value.ToString(\"yyyy-MM-ddTHH:mm:ss\");\n\n    public static long ToPeriodNumber(this DateTime value) => (long)value.Subtract(UnixStart).TotalSeconds;\n\n    public static string ToISOString(this DateTime value) => value.ToUniversalTime().ToString(\"yyyy-MM-ddTHH:mm:ss.fffZ\", CultureInfo.InvariantCulture);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/IDashboardClient.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\n\nnamespace Orleans.Dashboard.Core;\n\ninternal interface IDashboardClient\n{\n    Task<Immutable<DashboardCounters>> DashboardCounters(string[] exclusions = null);\n\n    Task<Immutable<Dictionary<string, GrainTraceEntry>>> ClusterStats();\n\n    Task<Immutable<ReminderResponse>> GetReminders(int pageNumber, int pageSize);\n\n    Task<Immutable<SiloRuntimeStatistics[]>> HistoricalStats(string siloAddress);\n\n    Task<Immutable<Dictionary<string, string>>> SiloProperties(string siloAddress);\n\n    Task<Immutable<Dictionary<string, string>>> SiloMetadata(string siloAddress);\n\n    Task<Immutable<Dictionary<string, GrainTraceEntry>>> SiloStats(string siloAddress);\n\n    Task<Immutable<StatCounter[]>> GetCounters(string siloAddress);\n\n    Task<Immutable<Dictionary<string, Dictionary<string, GrainTraceEntry>>>> GrainStats(string grainName);\n\n    Task<Immutable<Dictionary<string, GrainMethodAggregate[]>>> TopGrainMethods(int take, string[] exclusions = null);\n\n    Task<Immutable<string>> GetGrainState(string id, string grainType);\n\n    Task<Immutable<string[]>> GetGrainTypes(string[] exclusions = null);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/IDashboardGrain.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\n\nnamespace Orleans.Dashboard.Core;\n\n[Alias(\"Orleans.Dashboard.Core.IDashboardGrain\")]\ninternal interface IDashboardGrain : IGrainWithIntegerKey\n{\n    [OneWay]\n    [Alias(\"InitializeAsync\")]\n    Task InitializeAsync();\n\n    [OneWay]\n    [Alias(\"SubmitTracing\")]\n    Task SubmitTracing(string siloAddress, Immutable<SiloGrainTraceEntry[]> grainCallTime);\n\n    [Alias(\"GetCounters\")]\n    Task<Immutable<DashboardCounters>> GetCounters(string[] exclusions = null);\n\n    [Alias(\"GetGrainTracing\")]\n    Task<Immutable<Dictionary<string, Dictionary<string, GrainTraceEntry>>>> GetGrainTracing(string grain);\n\n    [Alias(\"GetClusterTracing\")]\n    Task<Immutable<Dictionary<string, GrainTraceEntry>>> GetClusterTracing();\n\n    [Alias(\"GetSiloTracing\")]\n    Task<Immutable<Dictionary<string, GrainTraceEntry>>> GetSiloTracing(string address);\n\n    [Alias(\"TopGrainMethods\")]\n    Task<Immutable<Dictionary<string, GrainMethodAggregate[]>>> TopGrainMethods(int take, string[] exclusions = null);\n\n    [Alias(\"GetGrainState\")]\n    Task<Immutable<string>> GetGrainState(string id, string grainType);\n\n    [Alias(\"GetGrainTypes\")]\n    Task<Immutable<string[]>> GetGrainTypes(string[] exclusions = null);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/IDashboardRemindersGrain.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Dashboard.Model;\n\nnamespace Orleans.Dashboard.Core;\n\n[Alias(\"Orleans.Dashboard.Core.IDashboardRemindersGrain\")]\ninternal interface IDashboardRemindersGrain : IGrainWithIntegerKey\n{\n    [Alias(\"GetReminders\")]\n    Task<Immutable<ReminderResponse>> GetReminders(int pageNumber, int pageSize);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/ISiloGrainClient.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Services;\n\nnamespace Orleans.Dashboard.Core;\n\ninternal interface ISiloGrainClient : IGrainServiceClient<ISiloGrainService>\n{\n    ISiloGrainService GrainService(SiloAddress destination);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/ISiloGrainProxy.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace Orleans.Dashboard.Core;\n\n[Alias(\"Orleans.Dashboard.Core.ISiloGrainProxy\")]\ninternal interface ISiloGrainProxy : IGrainWithStringKey, ISiloGrainService\n{\n\n    [Alias(\"GetMetadata\")]\n    Task<Immutable<Dictionary<string, string>>> GetMetadata();\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Core/ISiloGrainService.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Services;\nusing Orleans.Dashboard.Model;\n\nnamespace Orleans.Dashboard.Core;\n\n[Alias(\"Orleans.Dashboard.Core.ISiloGrainService\")]\ninternal interface ISiloGrainService : IGrainService\n{\n    [Alias(\"SetVersion\")]\n    Task SetVersion(string orleans, string host);\n\n    [OneWay]\n    [Alias(\"ReportCounters\")]\n    Task ReportCounters(Immutable<StatCounter[]> stats);\n\n    [Alias(\"Enable\")]\n    Task Enable(bool enabled);\n\n    [Alias(\"GetExtendedProperties\")]\n    Task<Immutable<Dictionary<string, string>>> GetExtendedProperties();\n\n    [Alias(\"GetRuntimeStatistics\")]\n    Task<Immutable<SiloRuntimeStatistics[]>> GetRuntimeStatistics();\n\n    [Alias(\"GetCounters\")]\n    Task<Immutable<StatCounter[]>> GetCounters();\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/DashboardHost.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing OpenTelemetry;\nusing OpenTelemetry.Metrics;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Implementation;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard;\n\ninternal sealed class DashboardHost(\n    ILogger<DashboardHost> logger,\n    ILocalSiloDetails localSiloDetails,\n    IGrainFactory grainFactory,\n    DashboardTelemetryExporter dashboardTelemetryExporter,\n    ISiloGrainClient siloGrainClient) : IHostedService, IAsyncDisposable, IDisposable\n{\n    private MeterProvider _meterProvider;\n\n    public async Task StartAsync(CancellationToken cancellationToken)\n    {\n        await Task.WhenAll(\n            ActivateDashboardGrainAsync(),\n            ActivateSiloGrainAsync(),\n            StartOpenTelemetryConsumerAsync()).ConfigureAwait(false);\n    }\n\n    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n\n    private async Task ActivateSiloGrainAsync()\n    {\n        try\n        {\n            var siloGrain = siloGrainClient.GrainService(localSiloDetails.SiloAddress);\n            await siloGrain.SetVersion(GetOrleansVersion(), GetHostVersion()).ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            logger.LogWarning(ex, \"Unable to activate silo grain service during startup. The service will be activated on first use.\");\n        }\n    }\n\n    private async Task ActivateDashboardGrainAsync()\n    {\n        try\n        {\n            var dashboardGrain = grainFactory.GetGrain<IDashboardGrain>(0);\n            await dashboardGrain.InitializeAsync().ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            logger.LogWarning(ex, \"Unable to activate dashboard grain during startup. The grain will be activated on first use.\");\n        }\n    }\n\n    private Task StartOpenTelemetryConsumerAsync()\n    {\n        _meterProvider = Sdk.CreateMeterProviderBuilder()\n            .AddMeter(\"Orleans\")\n            .AddReader(new PeriodicExportingMetricReader(dashboardTelemetryExporter, 1000, 1000))\n            .Build();\n        return Task.CompletedTask;\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        await DisposeAsync(_meterProvider).ConfigureAwait(false);\n\n        static async ValueTask DisposeAsync(object obj)\n        {\n            try\n            {\n                if (obj is IAsyncDisposable asyncDisposable)\n                {\n                    await asyncDisposable.DisposeAsync().ConfigureAwait(false);\n                }\n                else if (obj is IDisposable disposable)\n                {\n                    disposable.Dispose();\n                }\n            }\n            catch\n            {\n                // Ignore.\n            }\n        }\n    }\n\n\n    public void Dispose()\n    {\n        try\n        {\n            _meterProvider?.Dispose();\n        }\n        catch\n        {\n            /* NOOP */\n        }\n    }\n\n    private static string GetOrleansVersion()\n    {\n        var assembly = typeof(SiloAddress).GetTypeInfo().Assembly;\n        return $\"{assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion} ({assembly.GetName().Version})\";\n    }\n\n    private static string GetHostVersion()\n    {\n        try\n        {\n            var assembly = Assembly.GetEntryAssembly();\n\n            if (assembly != null)\n            {\n                return assembly.GetName().Version.ToString();\n            }\n        }\n        catch\n        {\n            /* NOOP */\n        }\n\n        return \"1.0.0.0\";\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/DashboardOptions.cs",
    "content": "namespace Orleans.Dashboard;\n\n/// <summary>\n/// Configuration options for the Orleans Dashboard.\n/// </summary>\npublic sealed class DashboardOptions\n{\n    /// <summary>\n    /// Gets or sets a value indicating whether to disable the trace feature.\n    /// When true, the live log streaming endpoint will be disabled.\n    /// The default is false.\n    /// </summary>\n    public bool HideTrace { get; set; }\n\n    /// <summary>\n    /// Gets or sets the number of milliseconds between counter samples.\n    /// Must be greater than or equal to 1000.\n    /// The default is 1000 (1 second).\n    /// </summary>\n    public int CounterUpdateIntervalMs { get; set; } = 1000;\n\n    /// <summary>\n    /// Gets or sets the length of the history to maintain for metrics.\n    /// Higher values provide more historical data but consume more memory.\n    /// The default is 100.\n    /// </summary>\n    public int HistoryLength { get; set; } = 100;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/EmbeddedAssetProvider.cs",
    "content": "using System;\nusing System.Collections.Frozen;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Linq;\nusing System.Reflection;\nusing System.Security.Cryptography;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.StaticFiles;\nusing Microsoft.Extensions.Primitives;\nusing Microsoft.Net.Http.Headers;\n\nnamespace Orleans.Dashboard;\n\ninternal sealed class EmbeddedAssetProvider\n{\n    private const string GZipEncodingValue = \"gzip\";\n    private static readonly StringValues GzipEncodingHeader = new(GZipEncodingValue);\n    private static readonly Assembly Assembly = typeof(EmbeddedAssetProvider).Assembly;\n    private static readonly FileExtensionContentTypeProvider ContentTypeProvider = new();\n    private static readonly StringValues CacheControl = new(new CacheControlHeaderValue()\n    {\n        NoCache = true,\n        NoStore = true,\n    }.ToString());\n\n    private readonly FrozenDictionary<string, ResourceEntry> _resourceCache;\n\n    public EmbeddedAssetProvider()\n    {\n        // Build resource cache for all embedded resources\n        var resourceNamePrefix = $\"{Assembly.GetName().Name}.wwwroot.\";\n        _resourceCache = Assembly\n            .GetManifestResourceNames()\n            .Where(p => p.StartsWith(resourceNamePrefix, StringComparison.Ordinal))\n            .ToFrozenDictionary(\n                p => p[resourceNamePrefix.Length..],\n                CreateResourceEntry,\n                StringComparer.OrdinalIgnoreCase);\n    }\n\n    public IResult ServeAsset(string name, HttpContext context)\n    {\n        // Embedded resources use dots instead of slashes for directory separators\n        var resourceKey = name.Replace('/', '.');\n\n        if (!_resourceCache.TryGetValue(resourceKey, out var entry))\n        {\n            return Results.NotFound();\n        }\n\n        // Check if client has cached version\n        if (context.Request.Headers.IfNoneMatch == entry.ETag)\n        {\n            return Results.StatusCode(StatusCodes.Status304NotModified);\n        }\n\n        byte[] contents;\n        var response = context.Response;\n        response.Headers.CacheControl = CacheControl;\n        if (entry.CompressedContent is not null && IsGZipAccepted(context.Request))\n        {\n            response.Headers.ContentEncoding = GzipEncodingHeader;\n            contents = entry.CompressedContent;\n        }\n        else\n        {\n            contents = entry.DecompressedContent;\n        }\n\n        return Results.Bytes(\n            contents,\n            contentType: entry.ContentType,\n            entityTag: new EntityTagHeaderValue(entry.ETag));\n    }\n\n    private static bool IsGZipAccepted(HttpRequest httpRequest)\n    {\n        if (httpRequest.GetTypedHeaders().AcceptEncoding is not { Count: > 0 } acceptEncoding)\n        {\n            return false;\n        }\n\n        for (int i = 0; i < acceptEncoding.Count; i++)\n        {\n            var encoding = acceptEncoding[i];\n            if (encoding.Quality is not 0 &&\n                string.Equals(encoding.Value.Value, GZipEncodingValue, StringComparison.OrdinalIgnoreCase))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private static ResourceEntry CreateResourceEntry(string fullResourceName)\n    {\n        using var resourceStream = Assembly.GetManifestResourceStream(fullResourceName) ?? throw new FileNotFoundException($\"Embedded resource not found: {fullResourceName}\");\n        using var decompressedContent = new MemoryStream();\n        resourceStream.CopyTo(decompressedContent);\n        var decompressedArray = decompressedContent.ToArray();\n\n        // Compress the content\n        using var compressedContent = new MemoryStream();\n        using (var gzip = new GZipStream(compressedContent, CompressionMode.Compress, leaveOpen: true))\n        {\n            gzip.Write(decompressedArray);\n        }\n\n        // Only use compression if it actually reduces size\n        byte[] compressedArray = compressedContent.Length < decompressedArray.Length\n            ? compressedContent.ToArray()\n            : null;\n\n        var hash = SHA256.HashData(compressedArray ?? decompressedArray);\n        var eTag = $\"\\\"{Convert.ToBase64String(hash)}\\\"\";\n\n        // Extract just the file name with extension for content type detection\n        var fileName = fullResourceName.Split('.').TakeLast(2).FirstOrDefault() + \".\" + fullResourceName.Split('.').Last();\n        var contentType = ContentTypeProvider.TryGetContentType(fileName, out var ct)\n            ? ct\n            : \"application/octet-stream\";\n\n        return new ResourceEntry(decompressedArray, compressedArray, eTag, contentType);\n    }\n\n    private sealed class ResourceEntry(byte[] decompressedContent, byte[] compressedContent, string eTag, string contentType)\n    {\n        public byte[] CompressedContent { get; } = compressedContent;\n        public string ContentType { get; } = contentType;\n        public byte[] DecompressedContent { get; } = decompressedContent;\n        public string ETag { get; } = eTag;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/GrainProfilerOptions.cs",
    "content": "namespace Orleans.Dashboard;\n\n/// <summary>\n/// Configuration options for the grain profiler.\n/// </summary>\npublic sealed class GrainProfilerOptions\n{\n    /// <summary>\n    /// Gets or sets a value indicating whether tracing should always be enabled, regardless of dashboard activity.\n    /// When set to <see langword=\"true\"/>, profiling data is continuously collected even when the dashboard is not being queried.\n    /// When set to <see langword=\"false\"/> (default), profiling is automatically disabled after <see cref=\"DeactivationTime\"/> of inactivity.\n    /// Default is <see langword=\"false\"/>.\n    /// </summary>\n    public bool TraceAlways { get; set; }\n\n    /// <summary>\n    /// Gets or sets the duration of inactivity (no dashboard queries) after which profiling is automatically disabled.\n    /// This setting only applies when <see cref=\"TraceAlways\"/> is <see langword=\"false\"/>.\n    /// After this period without queries, profiling stops to reduce overhead until the next dashboard query.\n    /// Default is 1 minute.\n    /// </summary>\n    public TimeSpan DeactivationTime { get; set; } = TimeSpan.FromMinutes(1);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/DashboardLogger.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Logging;\n\n#pragma warning disable IDE0069 // Disposable fields should be disposed\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal sealed class DashboardLogger : ILoggerProvider, ILogger\n{\n    private readonly NoopDisposable _scope = new();\n    private ImmutableArray<Action<EventId, LogLevel, string>> _actions = [];\n\n    public void Add(Action<EventId, LogLevel, string> action) => _actions = _actions.Add(action);\n\n    public void Remove(Action<EventId, LogLevel, string> action) => _actions = _actions.Remove(action);\n\n    public void Dispose()\n    {\n    }\n\n    public ILogger CreateLogger(string categoryName) => this;\n\n    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n    {\n        var currentActions = _actions;\n\n        if (currentActions.Length <= 0)\n        {\n            return;\n        }\n\n        var logMessage = formatter(state, exception);\n\n        foreach (var action in currentActions)\n        {\n            action(eventId, logLevel, logMessage);\n        }\n    }\n\n    public bool IsEnabled(LogLevel logLevel) => true;\n\n    public IDisposable BeginScope<TState>(TState state) => _scope;\n\n    private sealed class NoopDisposable : IDisposable\n    {\n        public void Dispose()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/DashboardTelemetryExporter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing Microsoft.Extensions.Logging;\nusing OpenTelemetry;\nusing OpenTelemetry.Metrics;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal sealed class DashboardTelemetryExporter(\n    ILocalSiloDetails localSiloDetails,\n    ISiloGrainClient siloGrainClient,\n    ILogger<DashboardTelemetryExporter> logger) : BaseExporter<Metric>\n{\n    private readonly Dictionary<string, Value<double>> _metrics = [];\n    private readonly ISiloGrainClient _siloGrainClient = siloGrainClient;\n    private readonly ILogger<DashboardTelemetryExporter> _logger = logger;\n    private readonly SiloAddress _siloAddress = localSiloDetails.SiloAddress;\n\n    public readonly struct Value<T>\n    {\n        public readonly T Current;\n        public readonly T Last;\n\n        public Value(T value)\n            : this(value, value)\n        {\n        }\n\n        public Value(T last, T current)\n        {\n            Last = last;\n\n            Current = current;\n        }\n\n        public Value<T> Update(T newValue) => new(Current, newValue);\n    }\n\n    public override ExportResult Export(in Batch<Metric> batch)\n    {\n        var grain = _siloGrainClient.GrainService(_siloAddress);\n\n        CollectMetricsFromBatch(batch);\n\n        if (_metrics.Count == 0)\n        {\n            return ExportResult.Success;\n        }\n\n        var counters = new StatCounter[_metrics.Count];\n        var countersIndex = 0;\n\n        foreach (var (key, value) in _metrics)\n        {\n            // In case new values have been added to metrics in another thread. It will be pushed the next time then.\n            if (countersIndex == counters.Length)\n            {\n                break;\n            }\n\n            counters[countersIndex] =\n                new StatCounter(\n                    key,\n                    value.Current.ToString(CultureInfo.InvariantCulture),\n                    ComputeDelta(value));\n\n            countersIndex++;\n        }\n\n        grain.ReportCounters(counters.AsImmutable());\n        return ExportResult.Success;\n    }\n\n    private void CollectMetricsFromBatch(in Batch<Metric> batch)\n    {\n        foreach (var metric in batch)\n        {\n            switch (metric.MetricType)\n            {\n                case MetricType.LongSum:\n                    CollectMetric(metric, p => p.GetSumLong());\n                    break;\n                case MetricType.DoubleSum:\n                    CollectMetric(metric, p => p.GetSumDouble());\n                    break;\n                case MetricType.LongGauge:\n                    CollectMetric(metric, p => p.GetGaugeLastValueLong());\n                    break;\n                case MetricType.DoubleGauge:\n                    CollectMetric(metric, p => p.GetGaugeLastValueDouble());\n                    break;\n                case MetricType.Histogram:\n                    CollectMetric(metric, p => p.GetHistogramSum());\n                    break;\n                default:\n                    _logger.LogWarning(\"Ignoring unknown metric type {MetricType}\", metric.MetricType);\n                    break;\n            }\n        }\n    }\n\n    private void CollectMetric(Metric metric, Func<MetricPoint, double> getValue)\n    {\n        foreach (var point in metric.GetMetricPoints())\n        {\n            var value = getValue(point);\n            if (!_metrics.ContainsKey(metric.Name))\n                _metrics[metric.Name] = new Value<double>(0);\n            _metrics[metric.Name] = _metrics[metric.Name].Update(value);\n        }\n    }\n\n    private static string ComputeDelta(Value<double> metric)\n    {\n        var delta = metric.Current - metric.Last;\n\n        return delta.ToString(CultureInfo.InvariantCulture);\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Details/MembershipTableSiloDetailsProvider.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Metrics.Details;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard.Implementation.Details;\n\ninternal sealed class MembershipTableSiloDetailsProvider : ISiloDetailsProvider\n{\n    private readonly IGrainFactory grainFactory;\n\n    public MembershipTableSiloDetailsProvider(IGrainFactory grainFactory)\n    {\n        this.grainFactory = grainFactory;\n    }\n\n    public async Task<SiloDetails[]> GetSiloDetails()\n    {\n        //default implementation uses managementgrain details\n        var grain = grainFactory.GetGrain<IManagementGrain>(0);\n\n        var hosts = await grain.GetDetailedHosts(true);\n\n        return hosts.Select(x => new SiloDetails\n        {\n            FaultZone = x.FaultZone,\n            HostName = x.HostName,\n            IAmAliveTime = x.IAmAliveTime.ToISOString(),\n            ProxyPort = x.ProxyPort,\n            RoleName = x.RoleName,\n            SiloAddress = x.SiloAddress.ToParsableString(),\n            SiloName = x.SiloName,\n            StartTime = x.StartTime.ToISOString(),\n            Status = x.Status.ToString(),\n            SiloStatus = x.Status,\n            UpdateZone = x.UpdateZone\n        }).ToArray();\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Details/SiloStatusOracleSiloDetailsProvider.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Metrics.Details;\nusing Orleans.Dashboard.Model;\n\nnamespace Orleans.Dashboard.Implementation.Details;\n\ninternal sealed class SiloStatusOracleSiloDetailsProvider(ISiloStatusOracle siloStatusOracle) : ISiloDetailsProvider\n{\n    public Task<SiloDetails[]> GetSiloDetails()\n    {\n        return Task.FromResult(siloStatusOracle.GetApproximateSiloStatuses(true)\n            .Select(x => new SiloDetails\n            {\n                Status = x.Value.ToString(),\n                SiloStatus = x.Value,\n                SiloAddress = x.Key.ToParsableString(),\n                SiloName = x.Key.ToParsableString() // Use the address for naming\n            })\n            .ToArray());\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/GrainProfilerFilter.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Dashboard.Metrics;\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal sealed class GrainProfilerFilter(\n    IGrainProfiler profiler,\n    ILogger<GrainProfilerFilter> logger,\n    GrainProfilerFilter.GrainMethodFormatterDelegate formatMethodName) : IIncomingGrainCallFilter\n{\n    private readonly GrainMethodFormatterDelegate _formatMethodName = formatMethodName ?? DefaultGrainMethodFormatter;\n    private readonly IGrainProfiler _profiler = profiler;\n    private readonly ILogger<GrainProfilerFilter> _logger = logger;\n    private readonly ConcurrentDictionary<MethodInfo, bool> _shouldSkipCache = new();\n\n    public delegate string GrainMethodFormatterDelegate(IIncomingGrainCallContext callContext);\n\n    public static readonly GrainMethodFormatterDelegate DefaultGrainMethodFormatter = FormatMethodName;\n\n    public async Task Invoke(IIncomingGrainCallContext context)\n    {\n        if (!_profiler.IsEnabled)\n        {\n            await context.Invoke();\n            return;\n        }\n\n        if (ShouldSkipProfiling(context))\n        {\n            await context.Invoke();\n            return;\n        }\n\n        var stopwatch = Stopwatch.StartNew();\n\n        try\n        {\n            await context.Invoke();\n\n            Track(context, stopwatch, false);\n        }\n        catch (Exception)\n        {\n            Track(context, stopwatch, true);\n            throw;\n        }\n    }\n\n    private void Track(IIncomingGrainCallContext context, Stopwatch stopwatch, bool isException)\n    {\n        try\n        {\n            stopwatch.Stop();\n\n            var elapsedMs = stopwatch.Elapsed.TotalMilliseconds;\n\n            var grainMethodName = _formatMethodName(context);\n\n            _profiler.Track(elapsedMs, context.Grain.GetType(), grainMethodName, isException);\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(100002, ex, \"error recording results for grain\");\n        }\n    }\n\n    private static string FormatMethodName(IIncomingGrainCallContext context)\n    {\n        var methodName = context.ImplementationMethod?.Name ?? \"Unknown\";\n\n        if (methodName == nameof(IRemindable.ReceiveReminder) && context.Request.GetArgumentCount() == 2)\n        {\n            try\n            {\n                methodName = $\"{methodName}({context.Request.GetArgument(0)})\";\n            }\n            catch\n            {\n                // Could fail if the argument types do not match.\n            }\n        }\n\n        return methodName;\n    }\n\n    private bool ShouldSkipProfiling(IIncomingGrainCallContext context)\n    {\n        var grainMethod = context.ImplementationMethod;\n\n        if (grainMethod == null)\n        {\n            return false;\n        }\n\n        if (!_shouldSkipCache.TryGetValue(grainMethod, out var shouldSkip))\n        {\n            try\n            {\n                var grainType = context.Grain.GetType();\n\n                shouldSkip =\n                    grainType.GetCustomAttribute<NoProfilingAttribute>() != null ||\n                    grainMethod.GetCustomAttribute<NoProfilingAttribute>() != null;\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(100003, ex, \"error reading NoProfilingAttribute attribute for grain\");\n\n                shouldSkip = false;\n            }\n\n            _shouldSkipCache.TryAdd(grainMethod, shouldSkip);\n        }\n\n        return shouldSkip;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Grains/DashboardGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Dynamic;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Dashboard.Implementation.Helpers;\nusing Orleans.Dashboard.Metrics.Details;\nusing Orleans.Dashboard.Metrics.History;\nusing Orleans.Dashboard.Metrics.TypeFormatting;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard.Implementation.Grains;\n\n[Reentrant]\ninternal sealed class DashboardGrain : Grain, IDashboardGrain\n{\n    private readonly TraceHistory _history;\n    private readonly ISiloDetailsProvider _siloDetailsProvider;\n    private readonly ISiloGrainClient _siloGrainClient;\n    private readonly DashboardCounters _counters;\n    private readonly GrainProfilerOptions _grainProfilerOptions;\n    private readonly TypeManifestOptions _typeManifestOptions;\n    private readonly TimeSpan _updateInterval;\n    private bool _isUpdating;\n    private DateTime _startTime = DateTime.UtcNow;\n    private DateTime _lastRefreshTime = DateTime.UtcNow;\n    private DateTime _lastQuery = DateTime.UtcNow;\n    private bool _isEnabled;\n\n    public DashboardGrain(\n        IOptions<DashboardOptions> options,\n        IOptions<GrainProfilerOptions> grainProfilerOptions,\n        IOptions<TypeManifestOptions> typeManifestOptions,\n        ISiloDetailsProvider siloDetailsProvider,\n        ISiloGrainClient siloGrainClient)\n    {\n        _siloDetailsProvider = siloDetailsProvider;\n        _siloGrainClient = siloGrainClient;\n\n        // Store the options to bypass the broadcase of the isEnabled flag.\n        _grainProfilerOptions = grainProfilerOptions.Value;\n        _typeManifestOptions = typeManifestOptions.Value;\n\n        // Do not allow smaller timers than 1000ms = 1sec.\n        _updateInterval = TimeSpan.FromMilliseconds(Math.Max(options.Value.CounterUpdateIntervalMs, 1000));\n\n        // Make the history configurable.\n        _counters = new DashboardCounters(options.Value.HistoryLength);\n\n        _history = new TraceHistory(options.Value.HistoryLength);\n    }\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        _startTime = DateTime.UtcNow;\n\n        if (!_grainProfilerOptions.TraceAlways)\n        {\n            var interval = TimeSpan.FromMinutes(1);\n\n            this.RegisterGrainTimer(async x =>\n            {\n                var timeSinceLastQuery = DateTimeOffset.UtcNow - _lastQuery;\n\n                if (timeSinceLastQuery > _grainProfilerOptions.DeactivationTime && _isEnabled)\n                {\n                    _isEnabled = false;\n                    await BroadcaseEnabled();\n                }\n            }, new() { DueTime = interval, Period = interval, Interleave = true, KeepAlive = true });\n        }\n\n        return base.OnActivateAsync(cancellationToken);\n    }\n\n    private Task EnsureIsActive()\n    {\n        _lastQuery = DateTime.UtcNow;\n\n        if (!_isEnabled)\n        {\n            _isEnabled = true;\n            _ = BroadcaseEnabled();\n        }\n\n        return Task.CompletedTask;\n    }\n\n    private async Task BroadcaseEnabled()\n    {\n        if (_grainProfilerOptions.TraceAlways)\n        {\n            return;\n        }\n\n        var silos = await _siloDetailsProvider.GetSiloDetails();\n\n        foreach (var siloAddress in silos.Select(x => x.SiloAddress))\n        {\n            await _siloGrainClient.GrainService(SiloAddress.FromParsableString(siloAddress)).Enable(_isEnabled);\n        }\n    }\n\n    private async Task EnsureCountersAreUpToDate()\n    {\n        if (_isUpdating)\n        {\n            return;\n        }\n\n        var now = DateTime.UtcNow;\n\n        if ((now - _lastRefreshTime) < _updateInterval)\n        {\n            return;\n        }\n\n        _isUpdating = true;\n        try\n        {\n            var metricsGrain = GrainFactory.GetGrain<IManagementGrain>(0);\n            var activationCountTask = metricsGrain.GetTotalActivationCount();\n            var simpleGrainStatsTask = metricsGrain.GetSimpleGrainStatistics();\n            var siloDetailsTask = _siloDetailsProvider.GetSiloDetails();\n\n            await Task.WhenAll(activationCountTask, simpleGrainStatsTask, siloDetailsTask);\n\n            RecalculateCounters(activationCountTask.Result, siloDetailsTask.Result, simpleGrainStatsTask.Result);\n\n            _lastRefreshTime = now;\n        }\n        finally\n        {\n            _isUpdating = false;\n        }\n    }\n\n    internal void RecalculateCounters(int activationCount, SiloDetails[] hosts, IList<SimpleGrainStatistic> simpleGrainStatistics)\n    {\n        _counters.TotalActivationCount = activationCount;\n\n        _counters.TotalActiveHostCount = hosts.Count(x => x.SiloStatus == SiloStatus.Active);\n        _counters.TotalActivationCountHistory =\n            _counters.TotalActivationCountHistory.Enqueue(activationCount).Dequeue();\n        _counters.TotalActiveHostCountHistory =\n            _counters.TotalActiveHostCountHistory.Enqueue(_counters.TotalActiveHostCount).Dequeue();\n\n        var elapsedTime = Math.Min((DateTime.UtcNow - _startTime).TotalSeconds, 100);\n\n        _counters.Hosts = hosts;\n\n        var aggregatedTotals = _history.GroupByGrainAndSilo().ToLookup(x => (x.Grain, x.SiloAddress));\n\n        _counters.SimpleGrainStats = simpleGrainStatistics.Select(x =>\n        {\n            var grainName = TypeFormatter.Parse(x.GrainType);\n            var siloAddress = x.SiloAddress.ToParsableString();\n\n            var result = new SimpleGrainStatisticCounter\n            {\n                ActivationCount = x.ActivationCount,\n                GrainType = grainName,\n                SiloAddress = siloAddress,\n                TotalSeconds = elapsedTime,\n            };\n\n            foreach (var item in aggregatedTotals[(grainName, siloAddress)])\n            {\n                result.TotalAwaitTime += item.ElapsedTime;\n                result.TotalCalls += item.Count;\n                result.TotalExceptions += item.ExceptionCount;\n            }\n\n            return result;\n        })\n        .ToArray();\n    }\n\n    public async Task<Immutable<DashboardCounters>> GetCounters(string[] exclusions)\n    {\n        await EnsureIsActive();\n        await EnsureCountersAreUpToDate();\n\n        var simpleGrainStats = exclusions != null && exclusions.Length > 0\n            ? [.. _counters.SimpleGrainStats.Where(x => !exclusions.Any(f => x.GrainType.StartsWith(f, StringComparison.OrdinalIgnoreCase)))]\n            : _counters.SimpleGrainStats;\n\n        return new DashboardCounters\n        {\n            Hosts = _counters.Hosts,\n            SimpleGrainStats = simpleGrainStats,\n            TotalActiveHostCount = _counters.TotalActiveHostCount,\n            TotalActiveHostCountHistory = _counters.TotalActiveHostCountHistory,\n            TotalActivationCount = _counters.TotalActivationCount,\n            TotalActivationCountHistory = _counters.TotalActivationCountHistory,\n        }\n        .AsImmutable();\n    }\n\n    public async Task<Immutable<Dictionary<string, Dictionary<string, GrainTraceEntry>>>> GetGrainTracing(\n        string grain)\n    {\n        await EnsureIsActive();\n        await EnsureCountersAreUpToDate();\n\n        return _history.QueryGrain(grain).AsImmutable();\n    }\n\n    public async Task<Immutable<Dictionary<string, GrainTraceEntry>>> GetClusterTracing()\n    {\n        await EnsureIsActive();\n        await EnsureCountersAreUpToDate();\n\n        return _history.QueryAll().AsImmutable();\n    }\n\n    public async Task<Immutable<Dictionary<string, GrainTraceEntry>>> GetSiloTracing(string address)\n    {\n        await EnsureIsActive();\n        await EnsureCountersAreUpToDate();\n\n        return _history.QuerySilo(address).AsImmutable();\n    }\n\n    public async Task<Immutable<Dictionary<string, GrainMethodAggregate[]>>> TopGrainMethods(int take, string[] exclusions)\n    {\n        await EnsureIsActive();\n        await EnsureCountersAreUpToDate();\n\n        var values = _history.AggregateByGrainMethod(exclusions).ToList();\n\n        GrainMethodAggregate[] GetTotalCalls()\n        {\n            return values.OrderByDescending(x => x.Count).Take(take).ToArray();\n        }\n\n        GrainMethodAggregate[] GetLatency()\n        {\n            return values.OrderByDescending(x => x.Count).Take(take).ToArray();\n        }\n\n        GrainMethodAggregate[] GetErrors()\n        {\n            return values.Where(x => x.ExceptionCount > 0 && x.Count > 0)\n                .OrderByDescending(x => x.ExceptionCount / x.Count).Take(take).ToArray();\n        }\n\n        var result = new Dictionary<string, GrainMethodAggregate[]>\n        {\n            { \"calls\", GetTotalCalls() },\n            { \"latency\", GetLatency() },\n            { \"errors\", GetErrors() },\n        };\n\n        return result.AsImmutable();\n    }\n\n    public Task InitializeAsync() =>\n        // just used to activate the grain\n        Task.CompletedTask;\n\n    public Task SubmitTracing(string siloAddress, Immutable<SiloGrainTraceEntry[]> grainTrace)\n    {\n        _history.Add(DateTime.UtcNow, siloAddress, grainTrace.Value);\n\n        return Task.CompletedTask;\n    }\n\n    public async Task<Immutable<string>> GetGrainState(string id, string grainType)\n    {\n        var result = new ExpandoObject();\n\n        try\n        {\n            var implementationType = _typeManifestOptions.InterfaceImplementations\n                .FirstOrDefault(w => w.FullName.Equals(grainType));\n\n            var mappedGrainId = GrainStateHelper.GetGrainId(id, implementationType);\n            object grainId = mappedGrainId.Item1;\n            string keyExtension = mappedGrainId.Item2;\n\n            var propertiesAndFields = GrainStateHelper.GetPropertiesAndFieldsForGrainState(implementationType);\n\n            var getGrainMethod = GrainStateHelper.GenerateGetGrainMethod(GrainFactory, grainId, keyExtension);\n\n            var interfaceTypes = implementationType.GetInterfaces();\n\n            foreach (var interfaceType in interfaceTypes)\n            {\n                try\n                {\n                    object[] grainMethodParameters;\n                    if (string.IsNullOrWhiteSpace(keyExtension))\n                        grainMethodParameters = new object[] { interfaceType, grainId };\n                    else\n                        grainMethodParameters = new object[] { interfaceType, grainId, keyExtension };\n\n                    var grain = getGrainMethod.Invoke(GrainFactory, grainMethodParameters);\n\n                    var methods = interfaceType.GetMethods().Where(w => w.GetParameters().Length == 0);\n\n                    foreach (var method in methods)\n                    {\n                        try\n                        {\n                            if (method.ReturnType.IsAssignableTo(typeof(Task))\n                                &&\n                                (\n                                    method.ReturnType.GetGenericArguments()\n                                        .Any(a => propertiesAndFields.Any(f => f == a)\n                                                  || method.Name == \"GetState\")\n                                )\n                               )\n                            {\n                                var task = (method.Invoke(grain, null) as Task);\n                                var resultProperty = task.GetType().GetProperty(\"Result\");\n\n                                if (resultProperty == null)\n                                    continue;\n\n                                await task;\n\n                                result.TryAdd(method.Name, resultProperty.GetValue(task));\n                            }\n                        }\n                        catch\n                        {\n                            // Because we got all the interfaces some errors with boxing and unboxing may happen with invocations \n                        }\n                    }\n                }\n                catch\n                {\n                    // Because we got all the interfaces some errors with boxing and unboxing may happen when try to get the grain\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            result.TryAdd(\"error\", string.Concat(ex.Message, \" - \", ex?.InnerException.Message));\n        }\n\n        return JsonSerializer.Serialize(result, options: new JsonSerializerOptions()\n        {\n            WriteIndented = true,\n        }).AsImmutable();\n    }\n\n    public Task<Immutable<string[]>> GetGrainTypes(string[] exclusions)\n    {\n        return Task.FromResult(_typeManifestOptions.InterfaceImplementations\n            .Where(s => s.GetInterfaces().Any(i => i == typeof(IGrain) || i == typeof(ISystemTarget)))\n            .Where(s => exclusions == null || !exclusions.Any(e => s.FullName.StartsWith(e, StringComparison.OrdinalIgnoreCase)))\n            .Select(s => s.FullName)\n            .ToArray()\n            .AsImmutable());\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Grains/DashboardRemindersGrain.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Dashboard.Core;\nusing Orleans.Dashboard.Model;\n\nnamespace Orleans.Dashboard.Implementation.Grains;\n\ninternal sealed class DashboardRemindersGrain : Grain, IDashboardRemindersGrain\n{\n    private static readonly Immutable<ReminderResponse> EmptyReminders = new ReminderResponse\n    {\n        Reminders = []\n    }.AsImmutable();\n\n    private readonly IReminderTable _reminderTable;\n\n    public DashboardRemindersGrain(IServiceProvider serviceProvider)\n    {\n        _reminderTable = serviceProvider.GetService(typeof(IReminderTable)) as IReminderTable;\n    }\n\n    public async Task<Immutable<ReminderResponse>> GetReminders(int pageNumber, int pageSize)\n    {\n        if (_reminderTable == null)\n        {\n            return EmptyReminders;\n        }\n\n        var reminderData = await _reminderTable.ReadRows(0, 0xffffffff);\n\n        if(!reminderData.Reminders.Any())\n        {\n            return EmptyReminders;\n        }\n\n        return new ReminderResponse\n        {\n            Reminders = reminderData\n                .Reminders\n                .OrderBy(x => x.StartAt)\n                .Skip((pageNumber - 1) * pageSize)\n                .Take(pageSize)\n                .Select(ToReminderInfo)\n                .ToArray(),\n\n            Count = reminderData.Reminders.Count\n        }.AsImmutable();\n    }\n\n    private static ReminderInfo ToReminderInfo(ReminderEntry entry)\n    {\n        return new ReminderInfo\n        {\n            PrimaryKey = entry.GrainId.Key.ToString(),\n            GrainReference = entry.GrainId.ToString(),\n            Name = entry.ReminderName,\n            StartAt = entry.StartAt,\n            Period = entry.Period,\n        };\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Grains/SiloGrainProxy.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Dashboard.Core;\nusing Orleans.Dashboard.Model;\nusing Orleans.Placement;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\n\nnamespace Orleans.Dashboard.Implementation.Grains;\n\n[PreferLocalPlacement]\ninternal sealed class SiloGrainProxy : Grain, ISiloGrainProxy\n{\n    private readonly ISiloGrainService _siloGrainService;\n    private readonly Dictionary<string, string> _siloMetadata;\n\n    public SiloGrainProxy(ISiloGrainClient siloGrainClient, ISiloMetadataCache siloMetadataCache = null)\n    {\n        var siloAddress = SiloAddress.FromParsableString(this.GetPrimaryKeyString());\n        _siloGrainService = siloGrainClient.GrainService(siloAddress);\n        _siloMetadata = new Dictionary<string, string>(siloMetadataCache?.GetSiloMetadata(siloAddress).Metadata ?? ImmutableDictionary<string, string>.Empty);\n    }\n\n    public Task SetVersion(string orleans, string host) => _siloGrainService.SetVersion(orleans, host);\n\n    public Task ReportCounters(Immutable<StatCounter[]> stats) => _siloGrainService.ReportCounters(stats);\n\n    public Task Enable(bool enabled) => _siloGrainService.Enable(enabled);\n\n    public Task<Immutable<Dictionary<string, string>>> GetExtendedProperties() => _siloGrainService.GetExtendedProperties();\n\n    public Task<Immutable<Dictionary<string, string>>> GetMetadata() => Task.FromResult(_siloMetadata.AsImmutable());\n\n    public Task<Immutable<SiloRuntimeStatistics[]>> GetRuntimeStatistics() => _siloGrainService.GetRuntimeStatistics();\n\n    public Task<Immutable<StatCounter[]>> GetCounters() => _siloGrainService.GetCounters();\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/Helpers/GrainStateHelper.cs",
    "content": "using Orleans.Core;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Orleans.Dashboard.Implementation.Helpers;\n\ninternal static class GrainStateHelper\n{\n    public static (object, string) GetGrainId(string id, Type implementationType)\n    {\n        object grainId = null;\n        string keyExtension = \"\";\n        var splitedGrainId = id.Split(\",\");\n\n        try\n        {\n            if (implementationType.IsAssignableTo(typeof(IGrainWithGuidCompoundKey)))\n            {\n                if (splitedGrainId.Length != 2)\n                    throw new InvalidOperationException(\"Inform grain id in format `{ id},{additionalKey}`\");\n\n                grainId = Guid.Parse(splitedGrainId.First());\n                keyExtension = splitedGrainId.Last();\n            }\n            else if (implementationType.IsAssignableTo(typeof(IGrainWithIntegerCompoundKey)))\n            {\n                if (splitedGrainId.Length != 2)\n                    throw new InvalidOperationException(\"Inform grain id in format {id},{additionalKey}\");\n\n                grainId = Convert.ToInt64(splitedGrainId.First());\n                keyExtension = splitedGrainId.Last();\n            }\n            else if (implementationType.IsAssignableTo(typeof(IGrainWithIntegerKey)))\n            {\n                grainId = Convert.ToInt64(id);\n            }\n            else if (implementationType.IsAssignableTo(typeof(IGrainWithGuidKey)))\n            {\n                grainId = Guid.Parse(id);\n            }\n            else if (implementationType.IsAssignableTo(typeof(IGrainWithStringKey)))\n            {\n                grainId = id;\n            }\n        }\n        catch (Exception ex)\n        {\n            throw new Exception(\"Error when trying to convert grain Id\", ex);\n        }\n\n        return (grainId, keyExtension);\n    }\n\n    public static IEnumerable<Type> GetPropertiesAndFieldsForGrainState(Type implementationType)\n    {\n        var impProperties = implementationType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);\n\n        var impFields = implementationType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);\n\n        var filterProps = impProperties\n                            .Where(w => w.PropertyType.IsAssignableTo(typeof(IStorage)))\n                            .Select(s => s.PropertyType.GetGenericArguments().First());\n\n        var filterFields = impFields\n                            .Where(w => w.FieldType.IsAssignableTo(typeof(IStorage)))\n                            .Select(s => s.FieldType.GetGenericArguments().First());\n\n        return filterProps.Union(filterFields);\n    }\n\n    public static MethodInfo GenerateGetGrainMethod(IGrainFactory grainFactory, object grainId, string keyExtension)\n    {\n        if (string.IsNullOrWhiteSpace(keyExtension))\n        {\n            return grainFactory.GetType().GetMethods()\n                            .First(w => w.Name == \"GetGrain\"\n                                  && w.GetParameters().Count() == 2\n                                  && w.GetParameters()[0].ParameterType == typeof(Type)\n                                  && w.GetParameters()[1].ParameterType == grainId.GetType());\n        }\n        else\n        {\n            return grainFactory.GetType().GetMethods()\n                            .First(w => w.Name == \"GetGrain\"\n                                  && w.GetParameters().Count() == 3\n                                  && w.GetParameters()[0].ParameterType == typeof(Type)\n                                  && w.GetParameters()[1].ParameterType == grainId.GetType()\n                                  && w.GetParameters()[2].ParameterType == typeof(string));\n        }\n    }\n}"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/SiloGrainClient.cs",
    "content": "using System;\nusing Orleans.Dashboard.Core;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Services;\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal sealed class SiloGrainClient(IServiceProvider serviceProvider) : GrainServiceClient<ISiloGrainService>(serviceProvider), ISiloGrainClient\n{\n    public ISiloGrainService GrainService(SiloAddress destination)\n        => GetGrainService(destination);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/SiloGrainService.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Metrics;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal sealed class SiloGrainService : GrainService, ISiloGrainService\n{\n    private const int DefaultTimerIntervalMs = 1000; // 1 second\n    private readonly Queue<SiloRuntimeStatistics> _statistics;\n    private readonly Dictionary<string, StatCounter> _counters = [];\n    private readonly DashboardOptions _options;\n    private readonly IGrainProfiler _profiler;\n    private readonly IGrainFactory _grainFactory;\n    private readonly ILogger<SiloGrainService> _logger;\n    private IDisposable _timer;\n    private string _versionOrleans;\n    private string _versionHost;\n\n    public SiloGrainService(\n        GrainId grainId,\n        Silo silo,\n        ILoggerFactory loggerFactory,\n        IGrainProfiler profiler,\n        IOptions<DashboardOptions> options,\n        IGrainFactory grainFactory) : base(grainId, silo, loggerFactory)\n    {\n        _profiler = profiler;\n        _options = options.Value;\n        _grainFactory = grainFactory;\n        _statistics = new Queue<SiloRuntimeStatistics>(_options.HistoryLength + 1);\n        _logger = loggerFactory.CreateLogger<SiloGrainService>();\n    }\n\n    public override async Task Start()\n    {\n        foreach (var _ in Enumerable.Range(1, _options.HistoryLength))\n        {\n            _statistics.Enqueue(null);\n        }\n\n        var updateInterval = TimeSpan.FromMilliseconds(\n            Math.Max(_options.CounterUpdateIntervalMs, DefaultTimerIntervalMs)\n        );\n        try\n        {\n            _timer = RegisterTimer(x => CollectStatistics((bool) x), true, updateInterval, updateInterval);\n\n            await CollectStatistics(false);\n        }\n        catch (InvalidOperationException)\n        {\n            _logger.LogWarning(\"Not running in Orleans runtime\");\n        }\n\n        await base.Start();\n    }\n\n    private async Task CollectStatistics(bool canDeactivate)\n    {\n        var managementGrain = _grainFactory.GetGrain<IManagementGrain>(0);\n        try\n        {\n            var siloAddress = SiloAddress.FromParsableString(this.GetPrimaryKeyString());\n\n            var results = (await managementGrain.GetRuntimeStatistics([siloAddress])).FirstOrDefault();\n\n            _statistics.Enqueue(results);\n\n            while (_statistics.Count > _options.HistoryLength)\n            {\n                _statistics.Dequeue();\n            }\n        }\n        catch (Exception)\n        {\n            // we can't get the silo stats, it's probably dead, so kill the grain\n            if (canDeactivate)\n            {\n                _timer?.Dispose();\n                _timer = null;\n            }\n        }\n    }\n\n    public Task SetVersion(string orleans, string host)\n    {\n        _versionOrleans = orleans;\n        _versionHost = host;\n\n        return Task.CompletedTask;\n    }\n\n    public Task<Immutable<Dictionary<string, string>>> GetExtendedProperties()\n    {\n        var results = new Dictionary<string, string>\n        {\n            [\"hostVersion\"] = _versionHost,\n            [\"orleansVersion\"] = _versionOrleans\n        };\n\n        return Task.FromResult(results.AsImmutable());\n    }\n\n    public Task ReportCounters(Immutable<StatCounter[]> reportCounters)\n    {\n        foreach (var counter in reportCounters.Value)\n        {\n            if (!string.IsNullOrWhiteSpace(counter.Name))\n            {\n                _counters[counter.Name] = counter;\n            }\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public Task<Immutable<SiloRuntimeStatistics[]>> GetRuntimeStatistics()\n    {\n        return Task.FromResult(_statistics.ToArray().AsImmutable());\n    }\n\n    public Task<Immutable<StatCounter[]>> GetCounters()\n    {\n        return Task.FromResult(_counters.Values.OrderBy(x => x.Name).ToArray().AsImmutable());\n    }\n\n    public Task Enable(bool enabled)\n    {\n        _profiler.Enable(enabled);\n\n        return Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Implementation/TraceWriter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.IO;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Dashboard.Implementation;\n\ninternal class TraceWriter : IAsyncDisposable\n{\n    private readonly DashboardLogger _traceListener;\n    private readonly HttpContext _context;\n    private readonly StreamWriter _writer;\n\n    public TraceWriter(DashboardLogger traceListener, HttpContext context)\n    {\n        _context = context;\n\n        _writer = new StreamWriter(context.Response.Body);\n\n        _traceListener = traceListener;\n        _traceListener.Add(Write);\n    }\n\n    private void Write(EventId eventId, LogLevel level, string message)\n    {\n        var task = WriteAsync(eventId, level, message);\n\n        task.Ignore();\n    }\n\n    public async Task WriteAsync(string message)\n    {\n        try\n        {\n            await _writer.WriteAsync(message);\n            await _writer.WriteAsync(\"\\r\\n\");\n\n            await _writer.FlushAsync();\n\n            await _context.Response.Body.FlushAsync();\n        }\n        catch (ObjectDisposedException)\n        {\n        }\n    }\n\n    public async Task WriteAsync(EventId eventId, LogLevel level, string message)\n    {\n        try\n        {\n            await _writer.WriteAsync($\"{DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)} {GetLogLevelString(level)}: [{eventId,8}] {message}\\r\\n\");\n\n            await _writer.FlushAsync();\n\n            await _context.Response.Body.FlushAsync();\n        }\n        catch (ObjectDisposedException)\n        {\n        }\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        _traceListener.Remove(Write);\n\n        return _writer.DisposeAsync();\n    }\n\n    private static string GetLogLevelString(LogLevel logLevel)\n    {\n        switch (logLevel)\n        {\n            case LogLevel.Trace:\n                return \"trce\";\n            case LogLevel.Debug:\n                return \"dbug\";\n            case LogLevel.Information:\n                return \"info\";\n            case LogLevel.Warning:\n                return \"warn\";\n            case LogLevel.Error:\n                return \"fail\";\n            case LogLevel.Critical:\n                return \"crit\";\n            default:\n                throw new ArgumentOutOfRangeException(nameof(logLevel));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/Details/ISiloDetailsProvider.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Dashboard.Model;\n\nnamespace Orleans.Dashboard.Metrics.Details;\n\ninternal interface ISiloDetailsProvider\n{\n    Task<SiloDetails[]> GetSiloDetails();\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/GrainProfiler.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Metrics.TypeFormatting;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Dashboard.Core;\n\nnamespace Orleans.Dashboard.Metrics;\n\ninternal sealed class GrainProfiler(\n    IGrainFactory grainFactory,\n    ILogger<GrainProfiler> logger,\n    ILocalSiloDetails localSiloDetails,\n    IOptions<GrainProfilerOptions> options) : IGrainProfiler, ILifecycleParticipant<ISiloLifecycle>\n{\n    private ConcurrentDictionary<string, SiloGrainTraceEntry> _grainTrace = new();\n    private Timer _timer;\n    private string _siloAddress;\n    private bool _isEnabled;\n    private IDashboardGrain _dashboardGrain;\n\n    public bool IsEnabled => options.Value.TraceAlways || _isEnabled;\n\n    public void Participate(ISiloLifecycle lifecycle) => lifecycle.Subscribe<GrainProfiler>(ServiceLifecycleStage.Last, ct => OnStart(), ct => OnStop());\n\n    private Task OnStart()\n    {\n        _timer = new Timer(ProcessStats, null, 1 * 1000, 1 * 1000);\n        return Task.CompletedTask;\n    }\n\n    private Task OnStop()\n    {\n        _timer.Dispose();\n        return Task.CompletedTask;\n    }\n\n    public void Track(double elapsedMs, Type grainType, [CallerMemberName] string methodName = null, bool failed = false)\n    {\n        ArgumentNullException.ThrowIfNull(grainType);\n\n        if (string.IsNullOrWhiteSpace(methodName))\n        {\n            throw new ArgumentException(\"Method name cannot be null or empty.\", nameof(methodName));\n        }\n\n        if (!IsEnabled)\n        {\n            return;\n        }\n\n        // This is the method that Orleans uses to convert a grain type into the grain type name when calling the GetSimpleGrainStatistics method\n        var grainName = RuntimeTypeNameFormatter.Format(grainType);\n        var grainMethodKey = $\"{grainName}.{methodName}\";\n\n        var exceptionCount = (failed ? 1 : 0);\n\n        _grainTrace.AddOrUpdate(grainMethodKey, _ =>\n            new SiloGrainTraceEntry\n            {\n                Count = 1,\n                ExceptionCount = exceptionCount,\n                ElapsedTime = elapsedMs,\n                Grain = grainName,\n                Method = methodName\n            },\n        (_, last) =>\n        {\n            last.Count += 1;\n            last.ElapsedTime += elapsedMs;\n\n            if (failed)\n            {\n                last.ExceptionCount += exceptionCount;\n            }\n\n            return last;\n        });\n    }\n\n    private void ProcessStats(object state)\n    {\n        if (!IsEnabled)\n        {\n            return;\n        }\n\n        var currentTrace = Interlocked.Exchange(ref _grainTrace, new ConcurrentDictionary<string, SiloGrainTraceEntry>());\n\n        if (!currentTrace.IsEmpty)\n        {\n            _siloAddress ??= localSiloDetails.SiloAddress.ToParsableString();\n\n            var items = currentTrace.Values.ToArray();\n\n            foreach (var item in items)\n            {\n                item.Grain = TypeFormatter.Parse(item.Grain);\n            }\n\n            try\n            {\n                _dashboardGrain ??= grainFactory.GetGrain<IDashboardGrain>(0);\n\n                _dashboardGrain.SubmitTracing(_siloAddress, items.AsImmutable()).Ignore();\n            }\n            catch (Exception ex)\n            {\n                logger.LogWarning(100001, ex, \"Exception thrown sending tracing to dashboard grain\");\n            }\n        }\n    }\n\n    public void Enable(bool enabled) => _isEnabled = enabled;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/GrainProfilerExtensions.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Dashboard.Metrics;\n\ninternal static class GrainProfilerExtensions\n{\n    public static void Track<T>(this IGrainProfiler profiler, double elapsedMs, [CallerMemberName] string methodName = null, bool failed = false)\n        => profiler.Track(elapsedMs, typeof(T), methodName, failed);\n\n    public static async Task TrackAsync<T>(this IGrainProfiler profiler, Func<Task> handler, [CallerMemberName] string methodName = null)\n    {\n        if (!profiler.IsEnabled)\n        {\n            await handler();\n            return;\n        }\n\n        var stopwatch = Stopwatch.StartNew();\n\n        try\n        {\n            await handler();\n\n            stopwatch.Stop();\n\n            profiler.Track(stopwatch.Elapsed.TotalMilliseconds, typeof(T), methodName);\n        }\n        catch (Exception)\n        {\n            stopwatch.Stop();\n\n            profiler.Track(stopwatch.Elapsed.TotalMilliseconds, typeof(T), methodName, true);\n            throw;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/GrainTraceEntryEqualityComparer.cs",
    "content": "using Orleans.Dashboard.Model;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Dashboard.Metrics.History;\n\ninternal sealed class GrainTraceEqualityComparer : IEqualityComparer<GrainTraceEntry>\n{\n    private readonly bool _withSiloAddress;\n\n    public static readonly GrainTraceEqualityComparer ByGrainAndMethod = new(false);\n\n    public static readonly GrainTraceEqualityComparer ByGrainAndMethodAndSilo = new(true);\n\n    private GrainTraceEqualityComparer(bool withSiloAddress)\n    {\n        _withSiloAddress = withSiloAddress;\n    }\n\n    public bool Equals(GrainTraceEntry x, GrainTraceEntry y)\n    {\n        if (ReferenceEquals(x, y))\n        {\n            return true;\n        }\n\n        if (x == null || y == null)\n        {\n            return false;\n        }\n\n        var isEquals =\n            string.Equals(x.Grain, y.Grain, StringComparison.OrdinalIgnoreCase) &&\n            string.Equals(x.Method, y.Method, StringComparison.OrdinalIgnoreCase);\n\n        if (_withSiloAddress)\n        {\n            isEquals &= string.Equals(x.SiloAddress, y.SiloAddress, StringComparison.OrdinalIgnoreCase);\n        }\n\n        return isEquals;\n    }\n\n    public int GetHashCode(GrainTraceEntry obj)\n    {\n        if (obj == null)\n        {\n            return 0;\n        }\n\n        var hashCode = 17;\n\n        if (obj.Grain != null)\n        {\n            hashCode = hashCode * 23 + (obj.Grain?.GetHashCode() ?? 0);\n        }\n\n        if (obj.Grain != null)\n        {\n            hashCode = hashCode * 23 + (obj.Method?.GetHashCode() ?? 0);\n        }\n\n        if (obj.Grain != null && _withSiloAddress)\n        {\n            hashCode = hashCode * 23 + (obj.SiloAddress?.GetHashCode() ?? 0);\n        }\n\n        return hashCode;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/HistoryEntry.cs",
    "content": "using System;\n\nnamespace Orleans.Dashboard.Metrics.History;\n\ninternal record struct HistoryEntry\n{\n    public DateTime Period { get; set; }\n\n    public long PeriodNumber { get; set; }\n\n    public long Count { get; set; }\n\n    public long ExceptionCount { get; set; }\n\n    public double ElapsedTime { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/HistoryKey.cs",
    "content": "namespace Orleans.Dashboard.Metrics.History;\n\ninternal record struct HistoryKey(string SiloAddress, string Grain, string Method);\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/ITraceHistory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\n\nnamespace Orleans.Dashboard.Metrics.History;\n\ninternal interface ITraceHistory\n{\n    void Add(DateTime time, string siloAddress, SiloGrainTraceEntry[] grainTrace);\n\n    Dictionary<string, GrainTraceEntry> QueryAll();\n\n    Dictionary<string, GrainTraceEntry> QuerySilo(string siloAddress);\n\n    Dictionary<string, Dictionary<string, GrainTraceEntry>> QueryGrain(string grain);\n\n    IEnumerable<TraceAggregate> GroupByGrainAndSilo();\n\n    IEnumerable<GrainMethodAggregate> AggregateByGrainMethod(string[] exclusions = null);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/RingBuffer.cs",
    "content": "namespace Orleans.Dashboard.Metrics.History;\n\ninternal sealed class RingBuffer<T>(int capacity)\n{\n    private readonly T[] _items = new T[capacity];\n    private int _startIndex;\n\n    public int Count { get; private set; }\n\n    public T this[int index]\n    {\n        get\n        {\n            var finalIndex = (_startIndex + index) % _items.Length;\n\n            return _items[finalIndex];\n        }\n    }\n\n    public void Add(T item)\n    {\n        var newIndex = (_startIndex + Count) % _items.Length;\n\n        _items[newIndex] = item;\n\n        if (Count < _items.Length)\n        {\n            Count++;\n        }\n        else\n        {\n            _startIndex++;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/History/TraceHistory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Dashboard.Core;\nusing Orleans.Dashboard.Model;\nusing Orleans.Dashboard.Model.History;\n\nnamespace Orleans.Dashboard.Metrics.History;\n\ninternal sealed class TraceHistory(int capacity = 100) : ITraceHistory\n{\n    private readonly Dictionary<HistoryKey, RingBuffer<HistoryEntry>> _history = new(100);\n\n    public Dictionary<string, Dictionary<string, GrainTraceEntry>> QueryGrain(string grain)\n    {\n        var results = new Dictionary<string, Dictionary<string, GrainTraceEntry>>();\n\n        foreach (var group in _history.Where(x => x.Key.Grain == grain).GroupBy(x => (x.Key.Grain, x.Key.Method)))\n        {\n            var grainMethodKey = $\"{group.Key.Grain}.{group.Key.Method}\";\n\n            results[grainMethodKey] = GetTracings(group);\n        }\n\n        return results;\n    }\n\n    public Dictionary<string, GrainTraceEntry> QueryAll() => GetTracings([.. _history]);\n\n    public Dictionary<string, GrainTraceEntry> QuerySilo(string siloAddress)\n        => GetTracings([.. _history.Where(x => string.Equals(x.Key.SiloAddress, siloAddress, StringComparison.OrdinalIgnoreCase))]);\n\n    private Dictionary<string, GrainTraceEntry> GetTracings(IEnumerable<KeyValuePair<HistoryKey, RingBuffer<HistoryEntry>>> traces)\n    {\n        var time = GetRetirementWindow(DateTime.UtcNow);\n\n        var periodStart = time.ToPeriodNumber();\n\n        var aggregations = new GrainTraceEntry[capacity];\n\n        foreach (var traceList in traces)\n        {\n            var bufferList = traceList.Value;\n            var bufferCount = bufferList.Count;\n\n            for (var j = 0; j < bufferCount; j++)\n            {\n                var trace = bufferList[j];\n\n                var resultIndex = trace.PeriodNumber - periodStart;\n\n                if (resultIndex >= 0 && resultIndex < capacity)\n                {\n                    var entry = aggregations[resultIndex] ?? new GrainTraceEntry();\n\n                    entry.Count += trace.Count;\n                    entry.ElapsedTime += trace.ElapsedTime;\n                    entry.ExceptionCount += trace.ExceptionCount;\n\n                    aggregations[resultIndex] = entry;\n                }\n            }\n        }\n\n        var result = new Dictionary<string, GrainTraceEntry>(capacity);\n\n        for (var i = 0; i < capacity; i++)\n        {\n            time = time.AddSeconds(1);\n\n            var periodKey = time.ToPeriodString();\n\n            var entry = aggregations[i] ??= new GrainTraceEntry();\n\n            entry.Period = time;\n            entry.PeriodKey = periodKey;\n\n            result[periodKey] = entry;\n        }\n\n        return result;\n    }\n\n\n    public void Add(DateTime now, string siloAddress, SiloGrainTraceEntry[] grainTrace)\n    {\n        var periodNumber = now.ToPeriodNumber();\n\n        foreach (var trace in grainTrace)\n        {\n            var key = new HistoryKey(siloAddress, trace.Grain, trace.Method);\n\n            if (!_history.TryGetValue(key, out var historyBuffer))\n            {\n                historyBuffer = new RingBuffer<HistoryEntry>(capacity);\n                _history[key] = historyBuffer;\n            }\n\n            historyBuffer.Add(new HistoryEntry\n            {\n                Period = now,\n                PeriodNumber = periodNumber,\n                ExceptionCount = trace.ExceptionCount,\n                ElapsedTime = trace.ElapsedTime,\n                Count = trace.Count\n            });\n        }\n    }\n\n    private DateTime GetRetirementWindow(DateTime now) => now.AddSeconds(-capacity);\n\n    public IEnumerable<TraceAggregate> GroupByGrainAndSilo()\n    {\n        var time = GetRetirementWindow(DateTime.UtcNow);\n        var periodStart = time.ToPeriodNumber();\n\n        return _history.GroupBy(x => (x.Key.Grain, x.Key.SiloAddress)).Select(group =>\n        {\n            var result = new TraceAggregate\n            {\n                SiloAddress = group.Key.SiloAddress,\n                Grain = group.Key.Grain,\n            };\n\n            foreach (var traceList in group)\n            {\n                var bufferList = traceList.Value;\n                var bufferCount = bufferList.Count;\n\n                for (var i = 0; i < bufferCount; i++)\n                {\n                    var record = bufferList[i];\n                    if (record.PeriodNumber < periodStart) continue;\n\n                    result.Count += record.Count;\n                    result.ExceptionCount += record.ExceptionCount;\n                    result.ElapsedTime += record.ElapsedTime;\n                }\n            }\n\n            return result;\n        });\n    }\n\n    public IEnumerable<GrainMethodAggregate> AggregateByGrainMethod(string[] exclusions)\n    {\n        var time = GetRetirementWindow(DateTime.UtcNow);\n        var periodStart = time.ToPeriodNumber();\n        var history = exclusions != null && exclusions.Length > 0\n            ? _history.Where(x => !exclusions.Any(f => x.Key.Grain.StartsWith(f, StringComparison.OrdinalIgnoreCase)))\n            : _history;\n\n        return history.GroupBy(x => (x.Key.Grain, x.Key.Method)).Select(group =>\n        {\n            var result = new GrainMethodAggregate\n            {\n                Grain = group.Key.Grain,\n                Method = group.Key.Method,\n                NumberOfSamples = capacity\n            };\n\n            foreach (var traceList in group)\n            {\n                var bufferList = traceList.Value;\n                var bufferCount = bufferList.Count;\n\n                for (var i = 0; i < bufferCount; i++)\n                {\n                    var record = bufferList[i];\n                    if (record.PeriodNumber < periodStart) continue;\n\n                    result.Count += record.Count;\n                    result.ExceptionCount += record.ExceptionCount;\n                    result.ElapsedTime += record.ElapsedTime;\n                }\n            }\n\n            return result;\n        });\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/IGrainProfiler.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Dashboard.Metrics;\n\n/// <summary>\n/// Provides profiling capabilities for grain method invocations, tracking execution time and failures.\n/// </summary>\ninternal interface IGrainProfiler\n{\n    /// <summary>\n    /// Records a grain method invocation for profiling purposes.\n    /// </summary>\n    /// <param name=\"elapsedMs\">The elapsed time in milliseconds for the method invocation.</param>\n    /// <param name=\"grainType\">The type of the grain.</param>\n    /// <param name=\"methodName\">The name of the method that was invoked. Automatically captured from the caller if not specified.</param>\n    /// <param name=\"failed\">True if the method invocation resulted in an exception; otherwise, false.</param>\n    void Track(double elapsedMs, Type grainType, [CallerMemberName] string methodName = null, bool failed = false);\n\n    /// <summary>\n    /// Enables or disables the grain profiler.\n    /// </summary>\n    /// <param name=\"enabled\">True to enable profiling; false to disable.</param>\n    void Enable(bool enabled);\n\n    /// <summary>\n    /// Gets a value indicating whether the grain profiler is currently enabled.\n    /// </summary>\n    bool IsEnabled { get; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/TypeFormatting/ParseState.cs",
    "content": "namespace Orleans.Dashboard.Metrics.TypeFormatting;\n\ninternal enum ParseState\n{\n    TypeNameSection,\n    GenericCount,\n    GenericArray,\n    TypeArray\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/TypeFormatting/Token.cs",
    "content": "namespace Orleans.Dashboard.Metrics.TypeFormatting;\n\ninternal readonly struct Token(TokenType type, string value)\n{\n    public TokenType Type { get; } = type;\n    public string Value { get; } = value;\n    public override string ToString() => $\"{Type} = {Value}\";\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/TypeFormatting/TokenType.cs",
    "content": "namespace Orleans.Dashboard.Metrics.TypeFormatting;\n\ninternal enum TokenType\n{\n    TypeNameSection,\n    GenericCount,\n    GenericArrayStart,\n    GenericArrayEnd,\n    TypeArrayStart,\n    TypeArrayEnd,\n    GenericSeparator,\n    TypeSectionSeparator\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Metrics/TypeFormatting/TypeFormatter.cs",
    "content": "using Orleans.Serialization.TypeSystem;\nusing System.Collections.Concurrent;\nusing System.Linq;\n\nnamespace Orleans.Dashboard.Metrics.TypeFormatting;\n\ninternal sealed class TypeFormatter\n{\n    private static readonly ConcurrentDictionary<string, string> Cache = new();\n\n    public static string Parse(string typeName) => Cache.GetOrAdd(typeName, Format);\n\n    private static string Format(string typeName)\n    {\n        var typeInfo = RuntimeTypeNameParser.Parse(typeName);\n\n        return Format(typeInfo);\n    }\n\n    private static string Format(TypeSpec typeSpec)\n    {\n        switch (typeSpec)\n        {\n            case AssemblyQualifiedTypeSpec qualified:\n                return Format(qualified.Type);\n            case ConstructedGenericTypeSpec constructed:\n                return $\"{Format(constructed.UnconstructedType)}<{string.Join(\", \", constructed.Arguments.Select(Format))}>\";\n            default:\n                var name = typeSpec.Format();\n\n                const string SystemPrefix = \"System.\";\n\n                if (name.StartsWith(SystemPrefix))\n                {\n                    name = name[SystemPrefix.Length..];\n                }\n\n                var genericCardinalityIndex = name.IndexOf('`');\n\n                if (genericCardinalityIndex > 0)\n                {\n                    name = name[..genericCardinalityIndex];\n                }\n\n                return name;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/DashboardCounters.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.DashboardCounters\")]\ninternal class DashboardCounters\n{\n    [Id(0)]\n    public SiloDetails[] Hosts { get; set; } = Array.Empty<SiloDetails>();\n\n    [Id(1)]\n    public SimpleGrainStatisticCounter[] SimpleGrainStats { get; set; } = Array.Empty<SimpleGrainStatisticCounter>();\n\n    [Id(2)]\n    public int TotalActiveHostCount { get; set; }\n\n    [Id(3)]\n    public ImmutableQueue<int> TotalActiveHostCountHistory { get; set; }\n\n    [Id(4)]\n    public int TotalActivationCount { get; set; }\n\n    [Id(5)]\n    public ImmutableQueue<int> TotalActivationCountHistory { get; set; } = ImmutableQueue<int>.Empty;\n\n    public DashboardCounters()\n    {\n    }\n\n    public DashboardCounters(int initialLength)\n    {\n        var values = Enumerable.Repeat(1, initialLength).Select(x => 0);\n\n        TotalActivationCountHistory = ImmutableQueue.CreateRange(values);\n        TotalActiveHostCountHistory = ImmutableQueue.CreateRange(values);\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/GrainTraceEntry.cs",
    "content": "using System;\n\nnamespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.GrainTraceEntry\")]\ninternal class GrainTraceEntry\n{\n    [Id(0)]\n    public string PeriodKey { get; set; }\n\n    [Id(1)]\n    public DateTime Period { get; set; }\n\n    [Id(2)]\n    public string SiloAddress { get; set; }\n\n    [Id(3)]\n    public string Grain { get; set; }\n\n    [Id(4)]\n    public string Method { get; set; }\n\n    [Id(5)]\n    public long Count { get; set; }\n\n    [Id(6)]\n    public long ExceptionCount { get; set; }\n\n    [Id(7)]\n    public double ElapsedTime { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/History/GrainMethodAggregate.cs",
    "content": "namespace Orleans.Dashboard.Model.History;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.History.GrainMethodAggregate\")]\ninternal struct GrainMethodAggregate\n{\n    [Id(0)]\n    public string Grain { get; set; }\n\n    [Id(1)]\n    public string Method { get; set; }\n\n    [Id(2)]\n    public long Count { get; set; }\n\n    [Id(3)]\n    public long ExceptionCount { get; set; }\n\n    [Id(4)]\n    public double ElapsedTime { get; set; }\n\n    [Id(5)]\n    public long NumberOfSamples { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/History/TraceAggregate.cs",
    "content": "namespace Orleans.Dashboard.Model.History;\n\ninternal struct TraceAggregate\n{\n    public string SiloAddress { get; set; }\n\n    public string Grain { get; set; }\n\n    public long Count { get; set; }\n\n    public long ExceptionCount { get; set; }\n\n    public double ElapsedTime { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/ReminderInfo.cs",
    "content": "using System;\n\nnamespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.ReminderInfo\")]\ninternal sealed class ReminderInfo\n{\n    [Id(0)]\n    public string GrainReference { get; set; }\n\n    [Id(1)]\n    public string Name { get; set; }\n\n    [Id(2)]\n    public DateTime StartAt { get; set; }\n\n    [Id(3)]\n    public TimeSpan Period { get; set; }\n\n    [Id(4)]\n    public string PrimaryKey { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/ReminderResponse.cs",
    "content": "namespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.ReminderResponse\")]\ninternal sealed class ReminderResponse\n{\n    [Id(0)]\n    public int Count { get; set; }\n\n    [Id(1)]\n    public ReminderInfo[] Reminders { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/SiloDetails.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.SiloDetails\")]\ninternal class SiloDetails\n{\n    [Id(0)]\n    public int FaultZone { get; set; }\n\n    [Id(1)]\n    public string HostName { get; set; }\n\n    [Id(2)]\n    public string IAmAliveTime { get; set; }\n\n    [Id(3)]\n    public int ProxyPort { get; set; }\n\n    [Id(4)]\n    public string RoleName { get; set; }\n\n    [Id(5)]\n    public string SiloAddress { get; set; }\n\n    [Id(6)]\n    public string SiloName { get; set; }\n\n    [Id(7)]\n    public string StartTime { get; set; }\n\n    [Id(8)]\n    public string Status { get; set; }\n\n    [Id(9)]\n    public int UpdateZone { get; set; }\n\n    [Id(10)]\n    public SiloStatus SiloStatus { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/SiloGrainTraceEntry.cs",
    "content": "namespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.SiloGrainTraceEntry\")]\ninternal class SiloGrainTraceEntry\n{\n    [Id(0)]\n    public string Grain { get; set; }\n\n    [Id(1)]\n    public string Method { get; set; }\n\n    [Id(2)]\n    public long Count { get; set; }\n\n    [Id(3)]\n    public long ExceptionCount { get; set; }\n\n    [Id(4)]\n    public double ElapsedTime { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/SimpleGrainStatisticCounter.cs",
    "content": "namespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Dashboard.Model.SimpleGrainStatisticCounter\")]\ninternal sealed class SimpleGrainStatisticCounter\n{\n    [Id(0)]\n    public int ActivationCount { get; set; }\n\n    [Id(1)]\n    public string GrainType { get; set; }\n\n    [Id(2)]\n    public string SiloAddress { get; set; }\n\n    [Id(3)]\n    public double TotalAwaitTime { get; set; }\n\n    [Id(4)]\n    public long TotalCalls { get; set; }\n\n    [Id(5)]\n    public double CallsPerSecond { get; set; }\n\n    [Id(6)]\n    public object TotalSeconds { get; set; }\n\n    [Id(7)]\n    public long TotalExceptions { get; set; }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Model/StatCounter.cs",
    "content": "namespace Orleans.Dashboard.Model;\n\n[GenerateSerializer]\n[Immutable]\n[Alias(\"Orleans.Dashboard.Model.StatCounter\")]\ninternal readonly struct StatCounter\n{\n    [Id(0)]\n    public readonly string Name;\n\n    [Id(1)]\n    public readonly string Value;\n\n    [Id(2)]\n    public readonly string Delta;\n\n    public StatCounter(string name, string value, string delta) : this()\n    {\n        Name = name;\n        Value = value;\n        Delta = delta;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Orleans.Dashboard.Frontend.targets",
    "content": "<Project>\n\n  <PropertyGroup>\n    <!-- Frontend paths -->\n    <NpmAppRootDirectory>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\..\\Orleans.Dashboard.App'))</NpmAppRootDirectory>\n    <NpmBuildOutput>$([System.IO.Path]::GetFullPath('$(NpmAppRootDirectory)\\dist\\'))</NpmBuildOutput>\n    <AzureDevOpsNpmrcFile>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\\.azdo\\.npmrc'))</AzureDevOpsNpmrcFile>\n  </PropertyGroup>\n\n  <!-- Collect frontend source files for incremental build tracking -->\n  <ItemGroup>\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\src\\**\\*\" />\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\public\\**\\*\" />\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\package.json\" />\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\vite.config.ts\" />\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\tsconfig.json\" />\n    <NpmAppSources Include=\"$(NpmAppRootDirectory)\\index.html\" />\n  </ItemGroup>\n\n  <!-- Use a marker file for incremental build tracking -->\n  <PropertyGroup>\n    <NpmAppBuildMarker>$(BaseIntermediateOutputPath)frontend.build.marker</NpmAppBuildMarker>\n  </PropertyGroup>\n\n  <Target\n    Name=\"DeleteNpmBuildMarker\"\n    AfterTargets=\"Clean\"\n    Condition=\"Exists($(NpmAppBuildMarker))\">\n    <Delete Files=\"$(NpmAppBuildMarker)\" />\n  </Target>\n\n  <!-- Build the frontend application.\n       This target runs once regardless of how many target frameworks are being built.\n       See: https://learn.microsoft.com/visualstudio/msbuild/run-target-exactly-once -->\n  <Target Name=\"BuildNpmApp\" Inputs=\"@(NpmAppSources)\" Outputs=\"$(NpmAppBuildMarker)\">\n    <Exec Command=\"node --version\" ConsoleToMsBuild=\"true\" StandardOutputImportance=\"Low\">\n      <Output TaskParameter=\"ConsoleOutput\" PropertyName=\"NodeVersion\" />\n    </Exec>\n    <Message Importance=\"High\" Text=\"Building Orleans Dashboard frontend with Node.js $(NodeVersion)\" />\n\n    <!-- Use Azure DevOps npmrc if running in CI -->\n    <PropertyGroup>\n      <NpmConfigArg Condition=\"'$(TF_BUILD)' == 'true'\">--userconfig \"$(AzureDevOpsNpmrcFile)\"</NpmConfigArg>\n    </PropertyGroup>\n\n    <!-- Install dependencies -->\n    <Exec\n      Command=\"npm ci --prefer-offline --no-audit $(NpmConfigArg)\"\n      WorkingDirectory=\"$(NpmAppRootDirectory)\"\n      ConsoleToMsBuild=\"true\" />\n\n    <!-- Build the frontend -->\n    <Exec\n      Command=\"npm run build\"\n      WorkingDirectory=\"$(NpmAppRootDirectory)\"\n      ConsoleToMsBuild=\"true\" />\n\n    <!-- Create marker file to track successful build -->\n    <Touch Files=\"$(NpmAppBuildMarker)\" AlwaysCreate=\"true\" />\n  </Target>\n\n  <!-- Hook BuildNpmApp to run once before DispatchToInnerBuilds for multi-targeted builds.\n       DispatchToInnerBuilds only runs once during multi-targeted builds, so attaching here\n       ensures the npm build runs exactly once before all inner framework builds. -->\n  <Target\n    Name=\"BuildNpmAppBeforeOuterBuild\"\n    DependsOnTargets=\"BuildNpmApp\"\n    BeforeTargets=\"DispatchToInnerBuilds\"\n    />\n\n  <!-- Include frontend assets as embedded resources.\n       This target:\n       1. Calls BuildNpmApp to ensure the dist folder exists (via MSBuild task for outer build)\n       2. Validates required files exist\n       3. Dynamically discovers and adds all dist files as embedded resources\n       \n       BeforeTargets=\"BeforeBuild\" ensures items are added early enough to be processed by the compiler.\n       We use ItemGroup inside the target to dynamically discover files at target execution time,\n       rather than relying on static globs which are evaluated at project load time. -->\n  <Target Name=\"IncludeFrontendAssets\" BeforeTargets=\"BeforeBuild\">\n    <!-- Call BuildNpmApp once via the outer build (without TargetFramework) -->\n    <MSBuild\n      Projects=\"$(MSBuildProjectFullPath)\"\n      Targets=\"BuildNpmApp\"\n      RemoveProperties=\"TargetFramework\" />\n\n    <!-- Validate required files exist -->\n    <Error \n      Condition=\"!Exists('$(NpmBuildOutput)index.html')\" \n      Text=\"Required frontend asset is missing: $(NpmBuildOutput)index.html. The frontend build may have failed. Ensure Node.js is installed.\" />\n    <Error \n      Condition=\"!Exists('$(NpmBuildOutput)index.min.js')\" \n      Text=\"Required frontend asset is missing: $(NpmBuildOutput)index.min.js. The frontend build may have failed. Ensure Node.js is installed.\" />\n    <Error \n      Condition=\"!Exists('$(NpmBuildOutput)index.css')\" \n      Text=\"Required frontend asset is missing: $(NpmBuildOutput)index.css. The frontend build may have failed. Ensure Node.js is installed.\" />\n\n    <!-- Dynamically discover and add all dist files as embedded resources -->\n    <ItemGroup>\n      <_DistFiles Include=\"$(NpmBuildOutput)**\\*\" />\n      <EmbeddedResource Include=\"@(_DistFiles)\" Link=\"wwwroot\\%(RecursiveDir)%(Filename)%(Extension)\" />\n    </ItemGroup>\n\n    <!-- Fail the build if no assets were found -->\n    <Error Condition=\"'@(_DistFiles)' == ''\" Text=\"No frontend assets found in $(NpmBuildOutput). The frontend build may have failed.\" />\n  </Target>\n\n  <!-- Validate that frontend assets were actually included as embedded resources.\n       This runs after CreateManifestResourceNames has processed all EmbeddedResource items,\n       providing a final check that the resources will be compiled into the assembly.\n       Only runs during build (not during pack) by checking that IncludeFrontendAssets ran. -->\n  <Target Name=\"ValidateFrontendEmbeddedResources\" AfterTargets=\"CreateManifestResourceNames\" Condition=\"'@(_DistFiles)' != ''\">\n    <ItemGroup>\n      <_FrontendEmbeddedResources Include=\"@(EmbeddedResource)\" Condition=\"'%(Link)' != '' and $([System.String]::Copy('%(Link)').StartsWith('wwwroot'))\" />\n    </ItemGroup>\n\n    <Error \n      Condition=\"'@(_FrontendEmbeddedResources)' == ''\" \n      Text=\"No frontend assets found in EmbeddedResource items. The frontend assets were not properly included.\" />\n  </Target>\n\n</Project>\n\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/Orleans.Dashboard.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Dashboard</PackageId>\n    <Title>Microsoft Orleans Dashboard</Title>\n    <Description>Real-time monitoring and visualization dashboard for Microsoft Orleans showing grain statistics, performance metrics, and cluster health.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <RootNamespace>Orleans.Dashboard</RootNamespace>\n  </PropertyGroup>\n\n  <Import Project=\"Orleans.Dashboard.Frontend.targets\" />\n\n  <ItemGroup>\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"OpenTelemetry\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Dashboard.Abstractions\\Orleans.Dashboard.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\..\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"..\\..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"..\\..\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Dashboard.TestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.Dashboard.UnitTests\" />\n    <InternalsVisibleTo Include=\"Benchmarks\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/README.md",
    "content": "# Microsoft Orleans Dashboard\n\n## Introduction\nMicrosoft Orleans Dashboard is a web-based monitoring and diagnostics tool for Orleans applications. It provides real-time visualization of grain activations, runtime statistics, silo health, and performance metrics through an intuitive web interface.\n\n## Features\n- **Real-time Grain Statistics**: Monitor active grain counts, call rates, and exception rates\n- **Silo Health Monitoring**: View silo status, CPU usage, memory consumption, and network activity\n- **Performance Metrics**: Track method call latencies, throughput, and error rates\n- **Grain Method Profiling**: Analyze individual grain method performance\n- **Reminders Tracking**: View scheduled reminders across the cluster\n- **Dashboard Customization**: Configure authentication, port, and other options\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Dashboard\n```\n\n## Example - Adding Dashboard to a Silo\n\n```csharp\nusing Orleans.Dashboard;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder.UseLocalhostClustering();\n    siloBuilder.UseInMemoryReminderService();\n    siloBuilder.AddMemoryGrainStorageAsDefault();\n\n    // Add the dashboard\n    siloBuilder.AddDashboard();\n});\n\nvar app = builder.Build();\n\n// Map dashboard endpoints\napp.MapOrleansDashboard();\n\napp.Run();\n```\n\nThe dashboard will be accessible at the application's base URL (e.g., `http://localhost:5000/`).\n\n## Example - Adding Dashboard to a Separate Web Application\n\nFor scenarios where you want to host the dashboard separately from your silos:\n\n```csharp\nusing Orleans.Dashboard;\nusing System.Net;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Configure Orleans client\nbuilder.UseOrleansClient(clientBuilder =>\n{\n    clientBuilder.UseStaticClustering(options =>\n        options.Gateways.Add(new IPEndPoint(IPAddress.Loopback, 30000).ToGatewayUri()));\n\n    // Add dashboard services\n    clientBuilder.AddDashboard();\n});\n\nvar app = builder.Build();\n\n// Map dashboard endpoints\napp.MapOrleansDashboard();\n\nawait app.RunAsync();\n```\n\n## Configuration Options\n\nThe dashboard can be configured with various options:\n\n```csharp\nsiloBuilder.AddDashboard(options =>\n{\n    options.CounterUpdateIntervalMs = 1000; // Metrics update interval (default: 1000ms)\n});\n```\n\nYou can customize the route prefix when mapping dashboard endpoints:\n\n```csharp\n// Map dashboard at a custom path\napp.MapOrleansDashboard(routePrefix: \"/dashboard\");\n\n// Add authentication\napp.MapOrleansDashboard().RequireAuthorization();\n```\n\n## Dashboard URL\nOnce configured, the dashboard is accessible at:\n- Default: `http://localhost:{AppPort}/` (where AppPort is your web application's port)\n- With routePrefix: `http://localhost:{AppPort}/{routePrefix}/`\n\n## Examples\nFor complete working examples, see the playground projects:\n- `playground/DashboardCohosted` - Dashboard cohosted with Orleans in a web application\n- `playground/DashboardSeparateHost` - Dashboard in a separate web application connecting to an Orleans cluster\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans observability](https://learn.microsoft.com/en-us/dotnet/orleans/host/monitoring/)\n- [Server configuration](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/server-configuration)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/ServiceCollectionExtensions.cs",
    "content": "#nullable enable\nusing System;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Dashboard.Implementation;\nusing Orleans.Dashboard.Implementation.Details;\nusing Orleans.Dashboard.Metrics;\nusing Orleans.Dashboard.Metrics.Details;\nusing Orleans.Dashboard.Model;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Dashboard.Core;\nusing Microsoft.AspNetCore.Mvc;\nusing Orleans.Configuration.Internal;\n\n// ReSharper disable CheckNamespace\nnamespace Orleans.Dashboard;\n\n/// <summary>\n/// Provides extension methods for configuring and integrating the Orleans Dashboard.\n/// </summary>\npublic static class ServiceCollectionExtensions\n{\n    /// <summary>\n    /// Adds Orleans Dashboard services to the silo builder.\n    /// </summary>\n    /// <param name=\"siloBuilder\">The silo builder.</param>\n    /// <param name=\"configureOptions\">Optional configuration action for <see cref=\"DashboardOptions\"/>.</param>\n    /// <returns>The silo builder for method chaining.</returns>\n    public static ISiloBuilder AddDashboard(this ISiloBuilder siloBuilder, Action<DashboardOptions>? configureOptions = null)\n    {\n        siloBuilder.Services.AddOrleansDashboardForSiloCore(configureOptions);\n        return siloBuilder;\n    }\n\n    internal static IServiceCollection AddOrleansDashboardForSiloCore(\n        this IServiceCollection services,\n        Action<DashboardOptions>? configureOptions = null)\n    {\n        services.AddGrainService<SiloGrainService>();\n        services.AddHostedService<DashboardHost>();\n        services.Configure(configureOptions ?? (x => { }));\n        services.AddSingleton<DashboardTelemetryExporter>();\n        services.AddOptions<GrainProfilerOptions>();\n\n        services.AddSingleton<EmbeddedAssetProvider>();\n        services.AddSingleton<SiloStatusOracleSiloDetailsProvider>();\n        services.AddSingleton<MembershipTableSiloDetailsProvider>();\n        services.AddSingleton<IDashboardClient, DashboardClient>();\n        services.AddSingleton<DashboardLogger>();\n        services.AddFromExisting<ILoggerProvider, DashboardLogger>();\n        services.AddSingleton<IGrainProfiler, GrainProfiler>();\n        services.AddSingleton(c => (ILifecycleParticipant<ISiloLifecycle>)c.GetRequiredService<IGrainProfiler>());\n        services.AddSingleton<IIncomingGrainCallFilter, GrainProfilerFilter>();\n        services.AddSingleton<ISiloGrainClient, SiloGrainClient>();\n\n        services.AddSingleton<ISiloDetailsProvider>(c => c.GetService<IMembershipTable>() switch\n        {\n            not null => c.GetRequiredService<MembershipTableSiloDetailsProvider>(),\n            null => c.GetRequiredService<SiloStatusOracleSiloDetailsProvider>(),\n        });\n\n        services.TryAddSingleton(GrainProfilerFilter.DefaultGrainMethodFormatter);\n\n        return services;\n    }\n\n    /// <summary>\n    /// Maps Orleans Dashboard endpoints using ASP.NET Core minimal APIs.\n    /// Returns an <see cref=\"IEndpointConventionBuilder\"/> that can be used to apply authentication,\n    /// authorization, or other endpoint configuration.\n    /// </summary>\n    /// <example>\n    /// <code>\n    /// // Basic usage\n    /// app.MapOrleansDashboard();\n    ///\n    /// // With authentication\n    /// app.MapOrleansDashboard().RequireAuthorization();\n    ///\n    /// // With custom base path\n    /// app.MapOrleansDashboard(routePrefix: \"/dashboard\");\n    /// </code>\n    /// </example>\n    public static RouteGroupBuilder MapOrleansDashboard(\n        this IEndpointRouteBuilder endpoints,\n        [StringSyntax(\"Route\")] string? routePrefix = null)\n    {\n        // Create static assets provider\n        var assets = endpoints.ServiceProvider.GetService<EmbeddedAssetProvider>()\n            ?? throw new InvalidOperationException(\"Orleans Dashboard services have not been registered. \" +\n                \"Please call AddDashboard on ISiloBuilder or IClientBuilder.\");\n\n        // Create a route group for all dashboard endpoints\n        var group = endpoints.MapGroup(routePrefix ?? \"\");\n\n        // Static assets - these match the paths referenced in the built CSS/HTML\n        // When a routePrefix is specified, redirect requests without trailing slash to include it.\n        // This ensures relative asset paths (like index.min.js) resolve correctly.\n        group.MapGet(\"/\", (HttpContext ctx) =>\n        {\n            if (!string.IsNullOrEmpty(routePrefix) && ctx.Request.Path.Value?.EndsWith('/') == false)\n            {\n                // Redirect to the same path with a trailing slash, preserving the query string\n                var redirectUrl = $\"{ctx.Request.PathBase}{ctx.Request.Path}/{ctx.Request.QueryString}\";\n                return Results.Redirect(redirectUrl, permanent: true);\n            }\n            return assets.ServeAsset(\"index.html\", ctx);\n        });\n        group.MapGet(\"/index.html\", (HttpContext ctx) => assets.ServeAsset(\"index.html\", ctx));\n        group.MapGet(\"/favicon.ico\", (HttpContext ctx) => assets.ServeAsset(\"favicon.ico\", ctx));\n        group.MapGet(\"/index.min.js\", (HttpContext ctx) => assets.ServeAsset(\"index.min.js\", ctx));\n        group.MapGet(\"/index.css\", (HttpContext ctx) => assets.ServeAsset(\"index.css\", ctx));\n\n        // Font files - catch-all route for /fonts/ directory\n        group.MapGet(\"/fonts/{**path}\", (string path, HttpContext ctx) => assets.ServeAsset($\"fonts.{path}\", ctx));\n\n        // Image files - catch-all route for /img/ directory\n        group.MapGet(\"/img/{**path}\", (string path, HttpContext ctx) => assets.ServeAsset($\"img.{path}\", ctx));\n\n        // API endpoints\n        var jsonOptions = new JsonSerializerOptions\n        {\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            IncludeFields = true,\n            Converters = { new TimeSpanConverter() }\n        };\n\n        group.MapGet(\"/version\", () => Results.Json(\n            new { version = typeof(EmbeddedAssetProvider).Assembly.GetName().Version?.ToString() },\n            jsonOptions));\n\n        group.MapGet(\"/DashboardCounters\", async (string[] exclude, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.DashboardCounters(SanitizeExclusionFilters(exclude));\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/ClusterStats\", async ([FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.ClusterStats();\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/Reminders\", async ([FromServices] IDashboardClient client) => await GetRemindersPage(1, client, jsonOptions));\n        group.MapGet(\"/Reminders/{page:int}\", async (int page, [FromServices] IDashboardClient client) => await GetRemindersPage(page, client, jsonOptions));\n\n        group.MapGet(\"/HistoricalStats/{*path}\", async (string path, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.HistoricalStats(path);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/SiloProperties/{*address}\", async (string address, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.SiloProperties(address);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/SiloMetadata/{*address}\", async (string address, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.SiloMetadata(address);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/SiloStats/{*address}\", async (string address, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.SiloStats(address);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/SiloCounters/{*address}\", async (string address, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.GetCounters(address);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/GrainStats/{*grainName}\", async (string grainName, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.GrainStats(grainName);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/TopGrainMethods\", async (string[] exclude, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.TopGrainMethods(take: 5, SanitizeExclusionFilters(exclude));\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/GrainState\", async (HttpContext context, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                context.Request.Query.TryGetValue(\"grainId\", out var grainId);\n                context.Request.Query.TryGetValue(\"grainType\", out var grainType);\n                var result = await client.GetGrainState(grainId, grainType);\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/GrainTypes\", async (string[] exclude, [FromServices] IDashboardClient client) =>\n        {\n            try\n            {\n                var result = await client.GetGrainTypes(SanitizeExclusionFilters(exclude));\n                return Results.Json(result.Value, jsonOptions);\n            }\n            catch (SiloUnavailableException)\n            {\n                return CreateUnavailableResult(true);\n            }\n        });\n\n        group.MapGet(\"/Trace\", async (HttpContext context, [FromServices] IOptions<DashboardOptions> opts, [FromServices] DashboardLogger logger) =>\n        {\n            if (opts.Value.HideTrace)\n            {\n                return Results.Problem(\"The trace endpoint is disabled in the dashboard options.\",\n                    title: \"Trace Endpoint Disabled\", statusCode: StatusCodes.Status403Forbidden);\n            }\n\n            await StreamTraceAsync(context, logger);\n            return Results.Empty;\n        });\n\n        return group;\n    }\n\n    private static async Task<IResult> GetRemindersPage(int page, IDashboardClient client, JsonSerializerOptions jsonOptions)\n    {\n        try\n        {\n            var result = await client.GetReminders(page, 50);\n            return Results.Json(result.Value, jsonOptions);\n        }\n        catch (SiloUnavailableException)\n        {\n            return CreateUnavailableResult(true);\n        }\n        catch\n        {\n            // If reminders are not configured, return empty response\n            return Results.Json(new ReminderResponse { Reminders = [], Count = 0 }, jsonOptions);\n        }\n    }\n\n    private static async Task StreamTraceAsync(HttpContext context, DashboardLogger logger)\n    {\n        var token = context.RequestAborted;\n\n        try\n        {\n            await using var writer = new TraceWriter(logger, context);\n            await writer.WriteAsync(\"\"\"\n                   ____       _                        _____            _     _                         _\n                  / __ \\     | |                      |  __ \\          | |   | |                       | |\n                 | |  | |_ __| | ___  __ _ _ __  ___  | |  | | __ _ ___| |__ | |__   ___   __ _ _ __ __| |\n                 | |  | | '__| |/ _ \\/ _` | '_ \\/ __| | |  | |/ _` / __| '_ \\| '_ \\ / _ \\ / _` | '__/ _` |\n                 | |__| | |  | |  __/ (_| | | | \\__ \\ | |__| | (_| \\__ \\ | | | |_) | (_) | (_| | | | (_| |\n                  \\____/|_|  |_|\\___|\\__,_|_| |_|___/ |_____/ \\__,_|___/_| |_|_.__/ \\___/ \\__,_|_|  \\__,_|\n\n                You are connected to the Orleans Dashboard log streaming service\n                \"\"\");\n\n            await Task.Delay(TimeSpan.FromMinutes(60), token);\n            await writer.WriteAsync(\"Disconnecting after 60 minutes\\r\\n\");\n        }\n        catch (OperationCanceledException)\n        {\n        }\n    }\n\n    private static IResult CreateUnavailableResult(bool lostConnectivity)\n    {\n        var message = lostConnectivity\n            ? \"The dashboard has lost connectivity with the Orleans cluster\"\n            : \"The dashboard is still trying to connect to the Orleans cluster\";\n\n        return Results.Text(message, \"text/plain\", statusCode: 503);\n    }\n\n    private static string[] SanitizeExclusionFilters(string[] filters)\n    {\n        return (filters == null || filters.Length == 0) ? [] : [.. filters\n            .Select(f => f.Trim())\n            .Where(f => !string.IsNullOrWhiteSpace(f))\n            .Select(f => string.Concat(f, '.'))];\n    }\n\n    /// <summary>\n    /// Adds Orleans Dashboard services to an Orleans client builder.\n    /// This allows you to host the Orleans Dashboard application on an Orleans client, so long as the silos also have the dashboard added.\n    /// </summary>\n    /// <param name=\"clientBuilder\">The client builder.</param>\n    /// <param name=\"configureOptions\">Optional configuration action for <see cref=\"DashboardOptions\"/>.</param>\n    /// <returns>The service collection for method chaining.</returns>\n    public static IClientBuilder AddDashboard(this IClientBuilder clientBuilder, Action<DashboardOptions>? configureOptions = null)\n    {\n        clientBuilder.Services.Configure(configureOptions ?? (x => { }));\n        clientBuilder.Services.AddSingleton<DashboardLogger>();\n        clientBuilder.Services.AddFromExisting<ILoggerProvider, DashboardLogger>();\n        clientBuilder.Services.AddSingleton<IDashboardClient, DashboardClient>();\n        clientBuilder.Services.AddSingleton<EmbeddedAssetProvider>();\n\n        return clientBuilder;\n    }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard/TimeSpanConverter.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Orleans.Dashboard;\n\ninternal sealed class TimeSpanConverter : JsonConverter<TimeSpan>\n{\n    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        var text = reader.GetString();\n        return TimeSpan.Parse(text, CultureInfo.InvariantCulture);\n    }\n\n    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(\"c\", CultureInfo.InvariantCulture));\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.Abstractions/NoProfilingAttribute.cs",
    "content": "using System;\n\nnamespace Orleans.Dashboard;\n\n/// <summary>\n/// Suppresses profiling for grain classes or methods, preventing them from being tracked by the Orleans Dashboard profiler.\n/// Apply this attribute to exclude specific grains or methods from performance metrics collection.\n/// </summary>\n/// <example>\n/// <code>\n/// [NoProfiling]\n/// public class MyInternalGrain : Grain\n/// {\n///     // This entire grain will not be profiled\n/// }\n///\n/// public class MyGrain : Grain\n/// {\n///     [NoProfiling]\n///     public Task InternalMethod()\n///     {\n///         // This specific method will not be profiled\n///     }\n/// }\n/// </code>\n/// </example>\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]\npublic sealed class NoProfilingAttribute : Attribute\n{\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.Abstractions/Orleans.Dashboard.Abstractions.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Dashboard.Abstractions</PackageId>\n    <Title>Microsoft Orleans Dashboard Abstractions</Title>\n    <Description>Shared types used by the Orleans Dashboard package.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <RootNamespace>Orleans.Dashboard</RootNamespace>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Remove=\"Orleans.Metadata.FrameworkPartAttribute\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.Abstractions/README.md",
    "content": "# Microsoft Orleans Dashboard Core\n\n## Introduction\nMicrosoft Orleans Dashboard Core provides the foundational infrastructure and data collection services for the Orleans Dashboard. This package contains the core grain services, metrics collection, and data models used by the dashboard UI.\n\n## Getting Started\nThis package is typically referenced automatically when you install `Microsoft.Orleans.Dashboard`. You generally don't need to reference this package directly unless you're building custom monitoring solutions or extending the dashboard functionality.\n\nTo use this package directly, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Dashboard.Abstractions\n```\n\n## What's Included\nThis package provides:\n- **Metrics Collection Services**: Grain-based services that collect runtime statistics\n- **Data Models**: Shared types for representing silo and grain statistics\n- **History Tracking**: Time-series data storage for performance metrics\n- **Grain Profiling**: Method-level performance tracking infrastructure\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans observability](https://learn.microsoft.com/en-us/dotnet/orleans/host/monitoring/)\n- [Orleans Dashboard package](https://www.nuget.org/packages/Microsoft.Orleans.Dashboard/)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.*\n!.env.example\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n.output\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Sveltekit cache directory\n.svelte-kit/\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# Firebase cache directory\n.firebase/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v3\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Vite files\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n.vite/\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/.npmrc",
    "content": "# This file is intentionally empty for local development\n# Azure DevOps builds use .npmrc.azdo instead\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/README.md",
    "content": "# Orleans Dashboard App\n\nThis directory contains the frontend web application for the Orleans Dashboard, built with React and Vite.\n\n## Structure\n\n```\nOrleans.Dashboard.App/\n├── src/              # React application source code\n│   ├── components/   # Reusable React components\n│   ├── grains/       # Grain-specific views\n│   ├── logstream/    # Log streaming components\n│   ├── overview/     # Dashboard overview components\n│   ├── reminders/    # Reminders view components\n│   ├── silos/        # Silo management components\n│   ├── lib/          # Utility libraries\n│   └── index.jsx     # Application entry point\n├── public/           # Static assets (copied to build output)\n│   ├── favicon.ico\n│   ├── OrleansLogo.png\n│   └── *.css, *.js   # Third-party CSS/JS libraries\n├── screenshots/      # Dashboard screenshots for documentation\n├── index.html        # HTML template\n├── package.json      # npm dependencies and scripts\n├── vite.config.ts    # Vite build configuration\n└── tsconfig.json     # TypeScript configuration\n```\n\n## Development\n\n### Prerequisites\n\n- Node.js (v18 or later)\n- npm\n\n### Setup\n\n```bash\ncd src/Dashboard/Orleans.Dashboard.App\nnpm install\n```\n\n### Development Server\n\nRun the Vite development server for hot module replacement:\n\n```bash\nnpm run dev\n```\n\nThis will start the development server at `http://localhost:5173` (or another port if 5173 is in use).\n\n### Building\n\nTo build the production bundle:\n\n```bash\nnpm run build\n```\n\nThis builds the application to `../Orleans.Dashboard/wwwroot/` which is then embedded as resources in the Orleans.Dashboard C# project.\n\n### Preview Production Build\n\nTo preview the production build locally:\n\n```bash\nnpm run preview\n```\n\n## Integration with Orleans.Dashboard\n\nThe frontend application is automatically built when you build the Orleans.Dashboard C# project. The build process is managed by `Orleans.Dashboard.Frontend.targets` which:\n\n1. Installs npm packages if `node_modules` doesn't exist\n2. Runs `npm run build` to compile the frontend\n3. Embeds the built assets as resources in the Orleans.Dashboard assembly\n\nThe build uses incremental compilation, so the frontend is only rebuilt when source files change.\n\n## Migration from Browserify\n\nThis project was migrated from Browserify to Vite for improved:\n- Build performance\n- Development experience with HMR\n- Modern JavaScript/TypeScript support\n- Better tree-shaking and optimization\n\nThe migration updated:\n- React from v15 to v18\n- Chart.js from v2 to v4\n- Build tooling from Browserify/Babel to Vite\n- Module system from CommonJS to ESM\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <title>Orleans Dashboard</title>\n    <meta content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" name=\"viewport\" />\n    <link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\" />\n    <link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\" />\n</head>\n<body class=\"layout-fixed sidebar-expand-lg sidebar-mini\" id=\"body\">\n    <div id=\"error-message-content\" class=\"error-container\"></div>\n    <div class=\"app-wrapper\">\n        <!-- Main Sidebar Container -->\n        <aside class=\"app-sidebar elevation-4\">\n            <div id=\"brand-header\"></div>\n\n            <!-- Sidebar -->\n            <div class=\"sidebar\">\n                <nav>\n                    <div id=\"menu\"></div>\n                </nav>\n            </div>\n            <!-- /.sidebar -->\n        </aside>\n\n        <!-- Content Wrapper. Contains page content -->\n        <main class=\"app-main\" id=\"content\">\n            <div class=\"app-content\">\n                <span style=\"padding-top: 25px;\">\n                    <span><i class=\"fa fa-spinner fa-pulse fa-fw\"></i> Loading...</span>\n                </span>\n            </div>\n        </main>\n        <!-- /.app-main -->\n    </div>\n\n    <!-- Vite will inject the bundled JS here -->\n    <script type=\"module\" src=\"/src/index.tsx\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/package.json",
    "content": "{\n  \"name\": \"orleans-dashboard-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"An admin dashboard for Microsoft Orleans\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build\",\n    \"preview\": \"vite preview\",\n    \"lint\": \"eslint .\"\n  },\n  \"dependencies\": {\n    \"@fortawesome/fontawesome-free\": \"^7.1.0\",\n    \"admin-lte\": \"^4.0.0-rc.3\",\n    \"bootstrap\": \"^5.3.3\",\n    \"chart.js\": \"^4.4.8\",\n    \"eventthing\": \"^1.0.7\",\n    \"humanize-duration\": \"^3.32.1\",\n    \"react\": \"^18.3.1\",\n    \"react-chartjs-2\": \"^5.3.0\",\n    \"react-dom\": \"^18.3.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^29.0.0\",\n    \"@types/humanize-duration\": \"^3.27.4\",\n    \"@types/react\": \"^18.3.26\",\n    \"@types/react-dom\": \"^18.3.7\",\n    \"@vitejs/plugin-react\": \"^4.7.0\",\n    \"eslint\": \"^9.18.0\",\n    \"eslint-plugin-react-hooks\": \"^5.2.0\",\n    \"eslint-plugin-react-refresh\": \"^0.4.20\",\n    \"typescript\": \"~5.7.3\",\n    \"vite\": \"^5.4.21\",\n    \"vite-plugin-commonjs\": \"^0.10.4\"\n  },\n  \"author\": \"Microsoft\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/alert.tsx",
    "content": "import React from 'react';\n\ninterface AlertProps {\n  onClose?: () => void;\n  title?: string;\n  children?: React.ReactNode;\n}\n\nexport default class Alert extends React.Component<AlertProps> {\n  constructor(props: AlertProps) {\n    super(props);\n    this.handleClick = this.handleClick.bind(this);\n  }\n\n  handleClick() {\n    if (this.props.onClose) {\n      this.props.onClose();\n    }\n  }\n\n  render() {\n    return (\n      <div className=\"alert alert-danger alert-dismissible\">\n        <button\n          type=\"button\"\n          className=\"close\"\n          onClick={this.handleClick}\n        >\n          ×\n        </button>\n        <h4>\n          <i className=\"icon fa fa-ban\" /> {this.props.title || 'Error'}\n        </h4>\n        {this.props.children}.\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/brand-header.tsx",
    "content": "import React from 'react';\nimport logo from '../assets/img/OrleansLogo.png';\n\nexport default function BrandHeader() {\n  return (\n    <div className=\"brand-link\">\n      <a href=\"#\" style={{ textDecoration: 'none' }}>\n        <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>\n          <img src={logo} alt=\"Orleans Logo\" className=\"brand-logo\" />\n          <h1 className=\"brand-title\">\n            Orleans Dashboard\n          </h1>\n        </div>\n      </a>\n      <div id=\"version-content\" className=\"brand-version\"></div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/checkbox-filter.tsx",
    "content": "import React from 'react';\n\ninterface Settings {\n  systemGrainsHidden: boolean;\n  dashboardGrainsHidden: boolean;\n}\n\ninterface CheckboxFilterProps {\n  preference: 'system' | 'dashboard';\n  settings: Settings;\n  onChange: (newSettings: Partial<Settings>) => void;\n}\n\ninterface CheckboxFilterState {\n  hidden: boolean;\n}\n\nexport default class CheckboxFilter extends React.Component<CheckboxFilterProps, CheckboxFilterState> {\n  constructor(props: CheckboxFilterProps) {\n    super(props);\n    this.state = {\n      hidden:\n        this.props.preference === 'system'\n          ? this.props.settings.systemGrainsHidden\n          : this.props.settings.dashboardGrainsHidden\n    };\n    this.handleChangeFilter = this.handleChangeFilter.bind(this);\n  }\n\n  handleChangeFilter(e: React.MouseEvent<HTMLAnchorElement>) {\n    // Prevent link navigation.\n    e.preventDefault();\n\n    const hidden = (e.target as HTMLAnchorElement).getAttribute('name') === 'hidden';\n    const newSettings: Partial<Settings> = {\n      [this.props.preference === 'system'\n        ? 'systemGrainsHidden'\n        : 'dashboardGrainsHidden']: hidden\n    };\n    this.props.onChange(newSettings);\n    this.setState({ hidden });\n  }\n\n  render() {\n    return (\n      <div className=\"btn-group btn-group-sm\" role=\"group\">\n        <a\n          href=\"#/\"\n          className={this.state.hidden ? 'btn btn-default' : 'btn btn-primary'}\n          name=\"visible\"\n          onClick={this.handleChangeFilter}\n        >\n          Visible\n        </a>\n        <a\n          href=\"#/\"\n          className={this.state.hidden ? 'btn btn-primary' : 'btn btn-default'}\n          name=\"hidden\"\n          onClick={this.handleChangeFilter}\n        >\n          Hidden\n        </a>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/counter-widget.tsx",
    "content": "import React from 'react';\n\ninterface CounterWidgetProps {\n  icon: string;\n  title: string;\n  counter: number | string;\n  link?: string;\n  style?: React.CSSProperties;\n}\n\nexport default class CounterWidget extends React.Component<CounterWidgetProps> {\n  constructor(props: CounterWidgetProps) {\n    super(props);\n    this.renderMore = this.renderMore.bind(this);\n  }\n\n  renderMore() {\n    if (!this.props.link) return null;\n    return (\n      <a href={this.props.link} className=\"small-box-footer\">\n        More info <i className=\"fa fa-arrow-circle-right\" />\n      </a>\n    );\n  }\n\n  render() {\n    return (\n      <div className=\"info-box\" style={this.props.style}>\n        <span className=\"info-box-icon bg-purple\">\n          <i className={`fa fa-${this.props.icon}`} />\n        </span>\n        <div className=\"info-box-content\">\n          <span className=\"info-box-text\">{this.props.title}</span>\n          <span className=\"info-box-number\">{this.props.counter}</span>\n          {this.renderMore()}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/display-grain-state.tsx",
    "content": "import React from 'react';\n\ninterface DisplayGrainStateProps {\n  code: string;\n}\n\nexport default class DisplayGrainState extends React.Component<DisplayGrainStateProps> {\n  constructor(props: DisplayGrainStateProps) {\n    super(props);\n  }\n\n  render() {\n    return (\n      <pre style={{ margin: '0 0' }}>\n        {this.props.code}\n      </pre>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/gauge-widget.tsx",
    "content": "import React from 'react';\nimport { Doughnut as Chart } from 'react-chartjs-2';\n\ninterface GaugeWidgetProps {\n  title: string;\n  value: number;\n  max: number;\n  description: string;\n}\n\ninterface GaugeWidgetState {\n  width: number;\n}\n\nexport default class GaugeWidget extends React.Component<GaugeWidgetProps, GaugeWidgetState> {\n  private containerRef: React.RefObject<HTMLDivElement>;\n\n  constructor(props: GaugeWidgetProps) {\n    super(props);\n    this.state = { width: 0 };\n    this.containerRef = React.createRef();\n    this.getWidth = this.getWidth.bind(this);\n    this.getColour = this.getColour.bind(this);\n    this.renderChart = this.renderChart.bind(this);\n  }\n\n  getWidth() {\n    if (this.containerRef.current) {\n      this.setState({ width: this.containerRef.current.offsetWidth });\n    }\n  }\n\n  getColour(alpha: number): string {\n    return `rgba(120, 57, 136, ${alpha})`;\n    /*\n        var percent = 100 * this.props.value / this.props.max;\n        if (percent > 90) return 'rgba(201,48,44,' + alpha.toString() + ')';\n        if (percent > 66) return 'rgba(236,151,31,' + alpha.toString() + ')';\n        return 'rgba(51,122,183,' + alpha.toString() + ')';\n\t\t*/\n  }\n\n  renderChart() {\n    if (this.state.width === 0) return setTimeout(this.getWidth, 0);\n\n    const data = {\n      labels: ['', ''],\n      datasets: [\n        {\n          data: [this.props.value, this.props.max - this.props.value],\n          backgroundColor: [this.getColour(1), this.getColour(0.2)],\n          hoverBackgroundColor: [this.getColour(1), this.getColour(0.2)],\n          borderWidth: [0, 0],\n          hoverBorderWidth: [0, 0]\n        }\n      ]\n    };\n\n    const options = {\n      plugins: {\n        legend: { display: false },\n        tooltip: { enabled: false }\n      },\n      animation: false,\n      cutout: '92%'\n    };\n\n    return (\n      <Chart\n        data={data}\n        options={options}\n        width={this.state.width}\n        height={200}\n      />\n    );\n  }\n\n  render() {\n    const percent = Math.floor((100 * this.props.value) / this.props.max);\n    return (\n      <div\n        ref={this.containerRef}\n        style={{\n          textAlign: 'center',\n          position: 'relative',\n          minHeight: '100px'\n        }}\n      >\n        <h4>{this.props.title}</h4>\n        <div\n          style={{\n            position: 'absolute',\n            textAlign: 'center',\n            fontSize: '60px',\n            fontWeight: '100',\n            left: '0',\n            right: '0',\n            top: '50%',\n            marginTop: '-45px'\n          }}\n        >\n          {percent}%\n        </div>\n        <div\n          style={{\n            position: 'absolute',\n            textAlign: 'center',\n            fontSize: '60px',\n            fontWeight: '100',\n            width: '100%'\n          }}\n        />\n        {this.renderChart()}\n        <span style={{ lineHeight: '40px' }}>{this.props.description}</span>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/grain-method-table.tsx",
    "content": "import React from 'react';\nimport { getName } from '../lib/typeName';\n\ninterface GrainMethodValue {\n  grain: string;\n  method: string;\n  [key: string]: any;\n}\n\ninterface GrainMethodTableProps {\n  values?: GrainMethodValue[];\n  valueFormatter: (value: GrainMethodValue) => string | number;\n}\n\nexport default class GrainMethodTable extends React.Component<GrainMethodTableProps> {\n  constructor(props: GrainMethodTableProps) {\n    super(props);\n    this.renderRow = this.renderRow.bind(this);\n  }\n\n  renderRow(value: GrainMethodValue) {\n    return (\n      <tr key={`${value.grain}.${value.method}`}>\n        <td style={{ wordWrap: 'break-word' }}>\n          <span className=\"pull-right\">\n            <strong>{this.props.valueFormatter(value)}</strong>\n          </span>\n          {value.method}\n          <br />\n          <small>\n            <a href={`#/grain/${value.grain}`} title={value.grain}>{getName(value.grain)}</a>\n          </small>\n        </td>\n      </tr>\n    );\n  }\n\n  render() {\n    const values = this.props.values || [];\n\n    return (\n      <table className=\"table\" style={{ tableLayout: 'fixed', width: '100%' }}>\n        <tbody>\n          {values.map(this.renderRow)}\n          {values.length === 0 &&\n            <tr>\n              <td>\n                <i>No data</i>\n              </td>\n            </tr>\n          }\n        </tbody>\n      </table>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/grain-table.tsx",
    "content": "import React from 'react';\nimport { getName } from '../lib/typeName';\n\ninterface GrainStat {\n  grainType: string;\n  siloAddress: string;\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n}\n\ninterface AggregatedGrainStat {\n  grainType: string;\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n}\n\ninterface GrainTableProps {\n  data: GrainStat[];\n  silo?: string;\n}\n\ninterface GrainTableState {\n  sortBy: string;\n  sortByAsc: boolean;\n}\n\nexport default class GrainTable extends React.Component<GrainTableProps, GrainTableState> {\n  constructor(props: GrainTableProps) {\n    super(props);\n    this.state = {\n      sortBy: 'activationCount',\n      sortByAsc: false\n    };\n    this.handleChangeSort = this.handleChangeSort.bind(this);\n  }\n\n  getSorter(): ((a: AggregatedGrainStat, b: AggregatedGrainStat) => number) | null {\n    let sorter: (a: AggregatedGrainStat, b: AggregatedGrainStat) => number;\n    switch (this.state.sortBy) {\n      case 'activationCount':\n        sorter = this.state.sortByAsc\n          ? sortByActivationCountAsc\n          : sortByActivationCountDesc;\n        break;\n      case 'grain':\n        sorter = this.state.sortByAsc ? sortByGrainAsc : sortBygrainDesc;\n        break;\n      case 'exceptionRate':\n        sorter = this.state.sortByAsc\n          ? sortByExceptionRateAsc\n          : sortByExceptionRateDesc;\n        break;\n      case 'totalCalls':\n        sorter = this.state.sortByAsc\n          ? sortBytotalCallsAsc\n          : sortBytotalCallsDec;\n        break;\n      case 'totalAwaitTime':\n        sorter = this.state.sortByAsc\n          ? sortByTotalAwaitTimeAsc\n          : sortByTotalAwaitTimeDesc;\n        break;\n      default:\n        sorter = () => 0;\n        break;\n    }\n    return sorter;\n  }\n\n  handleChangeSort(e: React.MouseEvent<HTMLTableHeaderCellElement>) {\n    const column = e.currentTarget.dataset['column'];\n    if (column) {\n      this.setState({\n        sortBy: column,\n        sortByAsc: this.state.sortBy === column ? !this.state.sortByAsc : false\n      });\n    }\n  }\n\n  renderStat = (stat: AggregatedGrainStat) => {\n    // shorten fully-qualified type names, including generics\n    const grainClassName = getName(stat.grainType);\n    const systemGrain = stat.grainType.startsWith('Orleans.');\n    const dashboardGrain = stat.grainType.startsWith('OrleansDashboard.');\n    return (\n      <tr key={stat.grainType}>\n        <td style={{ textOverflow: 'ellipsis' }} title={stat.grainType}>\n          <a href={`#/grain/${stat.grainType}`}>{grainClassName}</a>\n        </td>\n        <td>\n          {systemGrain ? (\n            <span className=\"label label-primary\">System Grain</span>\n          ) : null}\n          {dashboardGrain ? (\n            <span className=\"label label-primary\">Dashboard Grain</span>\n          ) : null}\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>{stat.activationCount}</strong>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>\n              {stat.totalCalls === 0\n                ? '0.00'\n                : ((100 * stat.totalExceptions) / stat.totalCalls).toFixed(2)}\n            </strong>{' '}\n            <small>%</small>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>{(stat.totalCalls / 100).toFixed(2)}</strong>{' '}\n            <small>req/sec</small>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>\n              {stat.totalCalls === 0\n                ? '0'\n                : (stat.totalAwaitTime / stat.totalCalls).toFixed(2)}\n            </strong>{' '}\n            <small>ms/req</small>\n          </span>\n        </td>\n      </tr>\n    );\n  };\n\n  render() {\n    const grainTypes: { [key: string]: AggregatedGrainStat } = {};\n    if (!this.props.data) return null;\n\n    this.props.data.forEach(stat => {\n      if (this.props.silo && stat.siloAddress !== this.props.silo) return;\n\n      if (!grainTypes[stat.grainType]) {\n        grainTypes[stat.grainType] = {\n          grainType: stat.grainType,\n          activationCount: 0,\n          totalSeconds: 0,\n          totalAwaitTime: 0,\n          totalCalls: 0,\n          totalExceptions: 0\n        };\n      }\n\n      const x = grainTypes[stat.grainType];\n      x.activationCount += stat.activationCount;\n      x.totalSeconds += stat.totalSeconds;\n      x.totalAwaitTime += stat.totalAwaitTime;\n      x.totalCalls += stat.totalCalls;\n      x.totalExceptions += stat.totalExceptions;\n    });\n\n    const values = Object.keys(grainTypes).map(key => {\n      return grainTypes[key];\n    });\n\n    const sorter = this.getSorter();\n    if (sorter) {\n      values.sort(sorter);\n    }\n\n    return (\n      <table className=\"table\">\n        <tbody>\n          <tr>\n            <th data-column=\"grain\" onClick={this.handleChangeSort}>\n              Grain{' '}\n              {this.state.sortBy === 'grain' ? (\n                this.state.sortByAsc ? (\n                  <i className=\"fa fa-arrow-up\" />\n                ) : (\n                  <i className=\"fa fa-arrow-down\" />\n                )\n              ) : null}\n            </th>\n            <th />\n            <th\n              data-column=\"activationCount\"\n              onClick={this.handleChangeSort}\n              style={{ textAlign: 'right' }}\n            >\n              Activations{' '}\n              {this.state.sortBy === 'activationCount' ? (\n                this.state.sortByAsc ? (\n                  <i className=\"fa fa-arrow-up\" />\n                ) : (\n                  <i className=\"fa fa-arrow-down\" />\n                )\n              ) : null}\n            </th>\n            <th\n              data-column=\"exceptionRate\"\n              onClick={this.handleChangeSort}\n              style={{ textAlign: 'right' }}\n            >\n              Exception rate{' '}\n              {this.state.sortBy === 'exceptionRate' ? (\n                this.state.sortByAsc ? (\n                  <i className=\"fa fa-arrow-up\" />\n                ) : (\n                  <i className=\"fa fa-arrow-down\" />\n                )\n              ) : null}\n            </th>\n            <th\n              data-column=\"totalCalls\"\n              onClick={this.handleChangeSort}\n              style={{ textAlign: 'right' }}\n            >\n              Throughput{' '}\n              {this.state.sortBy === 'totalCalls' ? (\n                this.state.sortByAsc ? (\n                  <i className=\"fa fa-arrow-up\" />\n                ) : (\n                  <i className=\"fa fa-arrow-down\" />\n                )\n              ) : null}\n            </th>\n            <th\n              data-column=\"totalAwaitTime\"\n              onClick={this.handleChangeSort}\n              style={{ textAlign: 'right' }}\n            >\n              Latency{' '}\n              {this.state.sortBy === 'totalAwaitTime' ? (\n                this.state.sortByAsc ? (\n                  <i className=\"fa fa-arrow-up\" />\n                ) : (\n                  <i className=\"fa fa-arrow-down\" />\n                )\n              ) : null}\n            </th>\n          </tr>\n          {values.map(this.renderStat)}\n        </tbody>\n      </table>\n    );\n  }\n}\n\nfunction sortByActivationCountAsc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return a.activationCount - b.activationCount;\n}\n\nfunction sortByActivationCountDesc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return sortByActivationCountAsc(b, a);\n}\n\nfunction sortByGrainAsc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  const parts = (x: AggregatedGrainStat) => x.grainType.split('.');\n  const grainClassName = (x: AggregatedGrainStat) => parts(x)[parts(x).length - 1];\n  return grainClassName(a) < grainClassName(b)\n    ? -1\n    : grainClassName(a) > grainClassName(b)\n    ? 1\n    : 0;\n}\n\nfunction sortBygrainDesc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return sortByGrainAsc(b, a);\n}\n\nfunction sortByExceptionRateAsc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return a.totalExceptions - b.totalExceptions;\n}\n\nfunction sortByExceptionRateDesc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return sortByExceptionRateAsc(b, a);\n}\n\nfunction sortBytotalCallsAsc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return a.totalCalls - b.totalCalls;\n}\n\nfunction sortBytotalCallsDec(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return sortBytotalCallsAsc(b, a);\n}\n\nfunction sortByTotalAwaitTimeAsc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  if (a.totalCalls === 0 && b.totalCalls === 0) {\n    return 0;\n  } else if (a.totalCalls === 0 || b.totalCalls === 0) {\n    return a.totalAwaitTime - b.totalAwaitTime;\n  } else {\n    return a.totalAwaitTime / a.totalCalls - b.totalAwaitTime / b.totalCalls;\n  }\n}\n\nfunction sortByTotalAwaitTimeDesc(a: AggregatedGrainStat, b: AggregatedGrainStat): number {\n  return sortByTotalAwaitTimeAsc(b, a);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/loading.tsx",
    "content": "import React from 'react';\n\nexport default class Loading extends React.Component {\n  render() {\n    return (\n      <section className=\"content\" style={{ height: '100vh' }}>\n        <span style={{ paddingTop: '25px' }}>\n          <i className=\"fa fa-spinner fa-pulse fa-fw\" />Loading...\n        </span>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/menu.tsx",
    "content": "import React from 'react';\n\ninterface MenuSectionProps {\n  active?: boolean;\n  icon: string;\n  name: string;\n  path: string;\n  isSeparated?: boolean;\n}\n\ninterface MenuItem {\n  name: string;\n  path: string;\n  icon: string;\n  active?: boolean;\n  isSeparated?: boolean;\n}\n\ninterface MenuProps {\n  menu: MenuItem[];\n}\n\nclass MenuSection extends React.Component<MenuSectionProps> {\n  render() {\n    const className = 'nav-item' +\n      (this.props.active ? ' menu-open' : '') +\n      (this.props.isSeparated ? ' mt-auto' : '');\n\n    return (\n      <li className={className}>\n        <a href={this.props.path} className={'nav-link' + (this.props.active ? ' active' : '')}>\n          <i className={this.props.icon + ' nav-icon'} />\n          <p>{this.props.name}</p>\n        </a>\n      </li>\n    );\n  }\n}\n\nexport default class Menu extends React.Component<MenuProps> {\n  render() {\n    return (\n      <ul className=\"nav nav-pills nav-sidebar flex-column\" data-widget=\"treeview\" role=\"menu\" data-accordion=\"false\">\n        {this.props.menu.map(x => (\n          <MenuSection key={x.name}\n            active={x.active}\n            icon={x.icon}\n            name={x.name}\n            path={x.path}\n            isSeparated={x.isSeparated}\n          />\n        ))}\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/multi-series-chart-widget.tsx",
    "content": "import React from 'react';\nimport { Line as Chart } from 'react-chartjs-2';\n\nconst colours = [[120, 57, 136], [236, 151, 31]];\n\ninterface MultiSeriesChartWidgetProps {\n  series: number[][];\n}\n\ninterface MultiSeriesChartWidgetState {\n  width: number;\n  height: number;\n}\n\n// this control is a bit of a temporary hack, until I have a multi-series chart widget\nexport default class MultiSeriesChartWidget extends React.Component<MultiSeriesChartWidgetProps, MultiSeriesChartWidgetState> {\n  private containerRef: React.RefObject<HTMLDivElement>;\n\n  constructor(props: MultiSeriesChartWidgetProps) {\n    super(props);\n    this.state = { width: 0, height: 0 };\n    this.containerRef = React.createRef();\n    this.getDimensions = this.getDimensions.bind(this);\n    this.renderChart = this.renderChart.bind(this);\n  }\n\n  componentDidMount() {\n    this.getDimensions();\n  }\n\n  componentDidUpdate(prevProps: MultiSeriesChartWidgetProps, prevState: MultiSeriesChartWidgetState) {\n    // Re-measure if dimensions are still 0 (e.g., after tab switch)\n    if ((prevState.width === 0 && this.state.width === 0) ||\n        (prevState.height === 0 && this.state.height === 0)) {\n      this.getDimensions();\n    }\n  }\n\n  getDimensions() {\n    if (!this.containerRef.current) return;\n    this.setState({\n      width: this.containerRef.current.offsetWidth - 20,\n      height: this.containerRef.current.offsetHeight - 10\n    });\n  }\n\n  renderChart() {\n    if (this.state.width === 0 || this.state.height === 0) {\n      setTimeout(this.getDimensions, 0);\n      return null;\n    }\n\n    const data = {\n      labels: this.props.series[0].map(function(x) {\n        return '';\n      }),\n      datasets: this.props.series.map((data, index) => {\n        const colourString = colours[index % colours.length].join();\n        return {\n          label: '',\n\n          backgroundColor: `rgba(${colourString},0.1)`,\n          borderColor: `rgba(${colourString},1)`,\n          data: data,\n          pointRadius: 0\n        };\n      })\n    };\n\n    return (\n      <Chart\n        data={data}\n        options={{\n          animation: false,\n          plugins: {\n            legend: { display: false },\n            tooltip: { enabled: false }\n          },\n          maintainAspectRatio: false,\n          responsive: true,\n          scales: {\n            y: {\n              ticks: { beginAtZero: true }\n            }\n          }\n        }}\n        width={this.state.width}\n        height={this.state.height}\n      />\n    );\n  }\n\n  render() {\n    return <div ref={this.containerRef} style={{ width: '100%', height: '100%', flex: 1 }}>{this.renderChart()}</div>;\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/page.tsx",
    "content": "import React from 'react';\n\ninterface PageProps {\n  title: string;\n  subTitle?: React.ReactNode;\n  children: React.ReactNode;\n}\n\nexport default class Page extends React.Component<PageProps> {\n  render() {\n    return (\n      <div>\n        <div className=\"app-content-header\">\n          <div className=\"container-fluid\">\n            <div className=\"row mb-2\">\n              <div className=\"col-sm-12\">\n                <h1 className=\"m-0\">\n                  {this.props.title} <small> {this.props.subTitle}</small>\n                </h1>\n              </div>\n            </div>\n          </div>\n        </div>\n        <div className=\"app-content\">\n          <div className=\"container-fluid\">\n            {this.props.children}\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/panel.tsx",
    "content": "import React from 'react';\n\ninterface PanelProps {\n  title: string;\n  subTitle?: string;\n  children: React.ReactNode;\n  bodyPadding?: string;\n}\n\nexport default class Panel extends React.Component<PanelProps> {\n  render() {\n    let body: React.ReactNode;\n    let footer: React.ReactNode;\n\n    if (Array.isArray(this.props.children) && this.props.children.length) {\n      body = this.props.children[0];\n      footer = (\n        <div className=\"card-footer clearfix\">{this.props.children[1]}</div>\n      );\n    } else {\n      body = this.props.children;\n      footer = null;\n    }\n\n    const bodyStyle: React.CSSProperties = {};\n    if (this.props.bodyPadding) {\n      bodyStyle.padding = this.props.bodyPadding;\n    }\n    return (\n      <div className=\"card\">\n        <div className=\"card-header\">\n          <h3 className=\"card-title\">\n            {this.props.title}\n            <small style={{ marginLeft: '10px' }}>{this.props.subTitle}</small>\n          </h3>\n        </div>\n        <div className=\"card-body\" style={bodyStyle}>{body}</div>\n        {footer}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/preferences.tsx",
    "content": "import React from 'react';\nimport ThemeButtons from './theme-buttons';\nimport CheckboxFilter from './checkbox-filter';\nimport Panel from './panel';\n\ninterface Settings {\n  dashboardGrainsHidden: boolean;\n  systemGrainsHidden: boolean;\n}\n\ninterface PreferencesProps {\n  changeSettings: (newSettings: Partial<Settings>) => void;\n  settings: Settings;\n  defaultTheme: string;\n  light: () => void;\n  dark: () => void;\n}\n\nconst Preferences: React.FC<PreferencesProps> = (props) => (\n  <Panel title=\"Preferences\">\n    <div>\n      <p>\n        The following preferences can be used to customize the Orleans\n        Dashboard. The selected preferences are saved locally in this browser.\n        The selected preferences do not affect other browsers or users.\n      </p>\n      <p>\n        Selecting the \"Hidden\" option for System Grains or Dashboard Grains will\n        exclude the corresponding types from counters, graphs, and tables with\n        the exception of the Cluster Profiling graph on the Overview page and\n        the Silo Profiling graph on a silo overview page.\n      </p>\n      <div\n        style={{\n          alignItems: 'center',\n          display: 'grid',\n          grid: '1fr 1fr / auto 1fr',\n          gridGap: '0px 30px'\n        }}\n      >\n        <div>\n          <h4>Dashboard Grains</h4>\n        </div>\n        <div>\n          <CheckboxFilter\n            onChange={props.changeSettings}\n            settings={props.settings}\n            preference=\"dashboard\"\n          />\n        </div>\n        <div>\n          <h4>System Grains</h4>\n        </div>\n        <div>\n          <CheckboxFilter\n            onChange={props.changeSettings}\n            settings={props.settings}\n            preference=\"system\"\n          />\n        </div>\n        <div>\n          <h4>Theme</h4>\n        </div>\n        <div>\n          <ThemeButtons\n            defaultTheme={props.defaultTheme}\n            light={props.light}\n            dark={props.dark}\n          />\n        </div>\n      </div>\n    </div>\n  </Panel>\n);\n\nexport default Preferences;\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/properties-widget.tsx",
    "content": "import React from 'react';\n\ninterface PropertiesWidgetProps {\n  data: { [key: string]: any };\n}\n\nexport default class PropertiesWidget extends React.Component<PropertiesWidgetProps> {\n  constructor(props: PropertiesWidgetProps) {\n    super(props);\n    this.renderRow = this.renderRow.bind(this);\n  }\n\n  renderRow(key: string) {\n    return (\n      <tr key={key}>\n        <td style={{ textOverflow: 'ellipsis' }}>{key}</td>\n        <td style={{ textAlign: 'right' }}>\n          <strong>{this.props.data[key]}</strong>\n        </td>\n      </tr>\n    );\n  }\n\n  render() {\n    return (\n      <table className=\"table\">\n        <tbody>{Object.keys(this.props.data).map(this.renderRow)}</tbody>\n      </table>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/reminder-table.tsx",
    "content": "import React from 'react';\n\ninterface ReminderData {\n  grainReference: string;\n  primaryKey: string;\n  activationCount: number;\n  name: string;\n  startAt: string;\n  period: string;\n}\n\ninterface ReminderTableProps {\n  data?: ReminderData[];\n}\n\ninterface ReminderTableState {\n  grain_reference: string;\n  primary_key: string;\n  name: string;\n  startAt: string;\n  period: string;\n}\n\nexport default class ReminderTable extends React.Component<ReminderTableProps, ReminderTableState> {\n  constructor(props: ReminderTableProps) {\n    super(props);\n    this.state = {\n      grain_reference: '',\n      primary_key: '',\n      name: '',\n      startAt: '',\n      period: ''\n    };\n    this.handleChange = this.handleChange.bind(this);\n    this.renderReminder = this.renderReminder.bind(this);\n    this.filterData = this.filterData.bind(this);\n  }\n\n  handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n    this.setState({\n      [e.target.name]: e.target.value\n    } as Pick<ReminderTableState, keyof ReminderTableState>);\n  }\n\n  renderReminder(reminderData: ReminderData, index: number) {\n    return (\n      <tr key={index}>\n        <td>{reminderData.grainReference}</td>\n        <td>{reminderData.primaryKey}</td>\n        <td>\n          <span className=\"pull-right\">{reminderData.activationCount}</span>\n        </td>\n        <td>\n          <span className=\"pull-right\">{reminderData.name}</span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            {new Date(reminderData.startAt).toLocaleString()}\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">{reminderData.period}</span>\n        </td>\n      </tr>\n    );\n  }\n\n  filterData(data: ReminderData[]): ReminderData[] {\n    return data\n      .filter(x =>\n        this.state['grain_reference']\n          ? x.grainReference.indexOf(this.state['grain_reference']) > -1\n          : x\n      )\n      .filter(x =>\n        this.state['primary_key']\n          ? x.primaryKey.indexOf(this.state['primary_key']) > -1\n          : x\n      )\n      .filter(x =>\n        this.state['name'] ? x.name.indexOf(this.state['name']) > -1 : x\n      )\n      .filter(x =>\n        this.state['startAt']\n          ? x.startAt.indexOf(this.state['startAt']) > -1\n          : x\n      )\n      .filter(x =>\n        this.state['period'] ? x.period.indexOf(this.state['period']) > -1 : x\n      );\n  }\n\n  render() {\n    if (!this.props.data) return null;\n    const filteredData = this.filterData(this.props.data);\n    return (\n      <table className=\"table\">\n        <tbody>\n          <tr>\n            <th style={{ textAlign: 'left' }}>Grain Reference</th>\n            <th>Primary Key</th>\n            <th />\n            <th style={{ textAlign: 'left' }}>Name</th>\n            <th style={{ textAlign: 'left' }}>Start At</th>\n            <th style={{ textAlign: 'right' }}>Period</th>\n          </tr>\n          <tr>\n            <th style={{ textAlign: 'left' }}>\n              <input\n                onChange={this.handleChange}\n                value={this.state['grain_reference']}\n                type=\"text\"\n                name=\"grain_reference\"\n                className=\"form-control\"\n                placeholder=\"Filter by Grain Reference\"\n              />\n            </th>\n            <th style={{ textAlign: 'left' }}>\n              <input\n                onChange={this.handleChange}\n                value={this.state['primary_key']}\n                type=\"text\"\n                name=\"primary_key\"\n                className=\"form-control\"\n                placeholder=\"Filter by Primary Key\"\n              />\n            </th>\n            <th />\n            <th style={{ textAlign: 'left' }}>\n              <input\n                onChange={this.handleChange}\n                value={this.state['name']}\n                type=\"text\"\n                name=\"name\"\n                className=\"form-control\"\n                placeholder=\"Filter by Name\"\n              />\n            </th>\n            <th style={{ textAlign: 'left' }}>\n              <input\n                onChange={this.handleChange}\n                value={this.state['startAt']}\n                type=\"text\"\n                name=\"startAt\"\n                className=\"form-control\"\n                placeholder=\"Filter by Start At\"\n              />\n            </th>\n            <th style={{ textAlign: 'right' }}>\n              <input\n                onChange={this.handleChange}\n                value={this.state['period']}\n                type=\"text\"\n                name=\"period\"\n                className=\"form-control\"\n                placeholder=\"Filter by Period\"\n              />\n            </th>\n          </tr>\n          {filteredData.map(this.renderReminder)}\n        </tbody>\n      </table>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/theme-buttons.tsx",
    "content": "import React from 'react';\n\ninterface ThemeButtonsProps {\n  defaultTheme: string;\n  light: () => void;\n  dark: () => void;\n}\n\ninterface ThemeButtonsState {\n  light: boolean;\n}\n\nexport default class ThemeButtons extends React.Component<ThemeButtonsProps, ThemeButtonsState> {\n  constructor(props: ThemeButtonsProps) {\n    super(props);\n    this.state = {\n      light: this.props.defaultTheme !== 'dark'\n    };\n    this.pickLight = this.pickLight.bind(this);\n    this.pickDark = this.pickDark.bind(this);\n  }\n\n  pickLight(event: React.MouseEvent<HTMLAnchorElement>) {\n    // Prevent link navigation.\n    event.preventDefault();\n\n    this.props.light();\n    this.setState({ light: true });\n  }\n\n  pickDark(event: React.MouseEvent<HTMLAnchorElement>) {\n    // Prevent link navigation.\n    event.preventDefault();\n\n    this.props.dark();\n    this.setState({ light: false });\n  }\n\n  render() {\n    return (\n      <div className=\"btn-group btn-group-sm\" role=\"group\">\n        <a\n          href=\"#/\"\n          className={this.state.light ? 'btn btn-primary' : 'btn btn-default'}\n          onClick={this.pickLight}\n        >\n          Light\n        </a>\n        <a\n          href=\"#/\"\n          className={this.state.light ? 'btn btn-default' : 'btn btn-primary'}\n          onClick={this.pickDark}\n        >\n          Dark\n        </a>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/components/time-series-chart.tsx",
    "content": "import React from 'react';\nimport { Line as Chart } from 'react-chartjs-2';\n\ninterface TimeSeriesChartProps {\n  timepoints: string[];\n  series: number[][];\n}\n\ninterface TimeSeriesChartState {\n  width: number;\n}\n\n// this control is a bit of a temporary hack, until I have a multi-series chart widget\nexport default class TimeSeriesChart extends React.Component<TimeSeriesChartProps, TimeSeriesChartState> {\n  private containerRef: HTMLDivElement | null;\n  private options: any;\n\n  constructor(props: TimeSeriesChartProps) {\n    super(props);\n    this.state = {\n      width: 0\n    };\n    this.containerRef = null;\n    this.getWidth = this.getWidth.bind(this);\n    this.setContainerRef = this.setContainerRef.bind(this);\n\n    this.options = {\n      plugins: {\n        legend: { display: false },\n        tooltip: { enabled: false }\n      },\n      maintainAspectRatio: false,\n      animation: false,\n      responsive: true,\n      interaction: {\n        mode: 'index',\n        intersect: false\n      },\n      scales: {\n        x: {\n          display: true,\n          grid: {\n            offset: false,\n            drawOnChartArea: false\n          },\n          ticks: {\n            autoSkip: false,\n            maxRotation: 0,\n            minRotation: 0,\n            font: { size: 9 }\n          }\n        },\n        y1: {\n          type: 'linear',\n          display: true,\n          position: 'left',\n          grid: { drawOnChartArea: false },\n          ticks: { beginAtZero: true }\n        },\n        y2: {\n          type: 'linear',\n          display: true,\n          position: 'right',\n          grid: { drawOnChartArea: false },\n          ticks: { beginAtZero: true }\n        }\n      }\n    };\n  }\n\n  setContainerRef(element: HTMLDivElement | null) {\n    this.containerRef = element;\n  }\n\n  componentDidMount() {\n    this.getWidth();\n  }\n\n  componentDidUpdate(prevProps: TimeSeriesChartProps, prevState: TimeSeriesChartState) {\n    if (prevState.width === 0 && this.state.width === 0) {\n      this.getWidth();\n    }\n  }\n\n  getWidth() {\n    if (!this.containerRef) {\n      return;\n    }\n\n    this.setState({ width: this.containerRef.offsetWidth });\n  }\n\n  renderChart() {\n    if (this.state.width === 0) {\n      return null;\n    }\n\n    const data = {\n      labels: this.props.timepoints.map(timepoint => {\n        if (timepoint) {\n          try {\n            if (new Date(timepoint).getSeconds() % 30 == 0) {\n              return new Date(timepoint).toLocaleTimeString();\n            }\n          } catch (e) {\n            // not a valid date string\n          }\n        }\n\n        return '';\n      }),\n      datasets: [\n        {\n          label: 'Average Latency',\n          backgroundColor: `rgba(236,151,31,0.2)`,\n          borderColor: `rgba(236,151,31,1)`,\n          data: this.props.series[2],\n          pointRadius: 0,\n          yAxisID: 'y2',\n          fill: true,\n          tension: 0.4,\n          borderWidth: 2\n        },\n        {\n          label: 'Failed Requests',\n          backgroundColor: `rgba(236,31,31,0.4)`,\n          borderColor: `rgba(236,31,31,1)`,\n          data: this.props.series[0],\n          pointRadius: 0,\n          yAxisID: 'y1',\n          fill: true,\n          tension: 0.4,\n          borderWidth: 2\n        },\n        {\n          label: 'Requests per Second',\n          backgroundColor: `rgba(120,57,136,0.4)`,\n          borderColor: `rgba(120,57,136,1)`,\n          data: this.props.series[1],\n          pointRadius: 0,\n          yAxisID: 'y1',\n          fill: true,\n          tension: 0.4,\n          borderWidth: 2\n        }\n      ]\n    };\n\n    return (\n      <Chart\n        data={data}\n        options={this.options}\n        width={this.state.width}\n        height={180}\n      />\n    );\n  }\n\n  render() {\n    return <div ref={this.setContainerRef}>{this.renderChart()}</div>;\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/custom.css",
    "content": "/* Custom styles for Orleans Dashboard layout */\n\n/* Brand logo styling */\n.brand-logo {\n  height: 45px;\n  width: auto;\n  object-fit: contain;\n  filter: brightness(0.95);\n}\n\n.brand-title {\n  margin: 0;\n  font-size: 1.25rem;\n  font-weight: 300;\n  line-height: 1.2;\n}\n\n.brand-link {\n  display: block;\n  padding: 1rem 1rem 1.5rem 1rem;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  margin-bottom: 1rem;\n}\n\n.dark-mode .brand-link {\n  border-bottom-color: rgba(255, 255, 255, 0.1);\n}\n\n.dark-mode .brand-logo {\n  filter: brightness(1.1);\n}\n\n.brand-version {\n  margin-top: 0.5rem;\n  font-size: 0.875rem;\n  color: #6c757d;\n}\n\n.log {\n  height: 100%;\n}\n\n.log-filter {\n  padding-left: 20px;\n  border: 0;\n  z-index: 1;\n  outline: none;\n}\n\n.error-container {\n  position: fixed;\n  z-index: 10000;\n  width: 400px;\n  top: 20px;\n  left: 100%;\n  margin-left: -420px;\n}\n\n/* Close button styling for alerts */\n.alert .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  float: right;\n  font-size: 1.5rem;\n  font-weight: 700;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  opacity: 0.5;\n  background: transparent;\n  border: 0;\n  padding: 0;\n  cursor: pointer;\n  transition: opacity 0.15s ease-in-out;\n}\n\n.alert .close:hover,\n.alert .close:focus {\n  opacity: 0.75;\n  text-decoration: none;\n  outline: 0;\n}\n\n.alert-danger .close {\n  color: #721c24;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.dark-mode .alert .close {\n  color: #fff;\n  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);\n}\n\n.log {\n  position: absolute;\n  top: 50px;\n  left: 10px;\n  right: 10px;\n  border: 0;\n  bottom: 0;\n  margin: 0;\n}\n\n.box {\n  border-top: none;\n  margin-bottom: 20px;\n}\n\n.main-sidebar {\n  padding-top: 0 !important;\n}\n\n.content-wrapper {\n  padding-top: 0 !important;\n  padding: 1rem;\n}\n\n.content-wrapper .content {\n  padding-top: 0;\n}\n\nh1 {\n  font-weight: 100;\n}\n\nh2 {\n  font-weight: 100;\n}\n\nh3 {\n  font-weight: 100;\n}\n\n/* Fix info-box layout */\n.info-box {\n  display: flex;\n  min-height: 80px;\n  border-radius: .25rem;\n  box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);\n  margin-bottom: 1rem;\n}\n\n.info-box-icon {\n  border-radius: .25rem 0 0 .25rem;\n  width: 90px;\n  text-align: center;\n  font-size: 2.5rem;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.info-box-content {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  padding: .5rem 1rem;\n  flex: 1;\n}\n\n.info-box-text {\n  text-transform: uppercase;\n  font-size: .875rem;\n}\n\n.info-box-number {\n  font-weight: 700;\n  font-size: 1.5rem;\n}\n\n.small-box-footer {\n  display: block;\n  padding: 3px 0;\n  margin-top: 5px;\n  color: rgba(0,0,0,.5);\n  text-decoration: none;\n}\n\n.small-box-footer:hover {\n  color: rgba(0,0,0,.7);\n  text-decoration: none;\n}\n\n/* Card/Panel consistency */\n.card,\n.box {\n  border-radius: .25rem;\n  box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);\n  margin-bottom: 1rem;\n  height: 100%;\n}\n\n.card-header,\n.box-header {\n  padding: .75rem 1.25rem;\n}\n\n.card-body,\n.box-body {\n  padding: 1.25rem;\n}\n\n/* Ensure proper row spacing */\n.row {\n    --bs-gutter-x: 1rem;\n}\n\n/* Make cards in rows have equal heights */\n.row > [class*='col-'] {\n  display: flex;\n  flex-direction: column;\n  margin-bottom: 0;\n}\n\n.row > [class*='col-'] > .card,\n.row > [class*='col-'] > .box {\n  flex: 1;\n}\n\n/* Sidebar menu spacing */\n.sidebar .nav-sidebar {\n  display: flex;\n  flex-direction: column;\n  height: 100%;\n}\n\n.sidebar .nav-item.mt-auto {\n  margin-top: auto !important;\n}\n\n/* Ensure sidebar scrolls properly */\n.main-sidebar .sidebar {\n  display: flex;\n  flex-direction: column;\n  height: calc(100vh - 100px);\n  overflow-y: auto;\n}\n\n/* Fix menu items to display icon and text on same line */\n.nav-sidebar .nav-link {\n  display: flex;\n  align-items: center;\n  gap: 0.5rem;\n}\n\n.nav-sidebar .nav-link p {\n  margin: 0;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/grains/grain-details.tsx",
    "content": "import React from 'react';\nimport Page from '../components/page';\nimport http from '../lib/http';\nimport DisplayGrainState from '../components/display-grain-state';\nimport Panel from '../components/panel';\nimport { getName } from '../lib/typeName';\n\ninterface GrainDetailsProps {\n  grainTypes: string[];\n}\n\ninterface GrainDetailsState {\n  grainId: string;\n  grainType: string | null;\n  grainState: string;\n}\n\nexport default class GrainDetails extends React.Component<GrainDetailsProps, GrainDetailsState> {\n  constructor(props: GrainDetailsProps) {\n    super(props);\n    this.state = { grainId: '', grainType: null, grainState: '' };\n    this.handleGrainIdChange = this.handleGrainIdChange.bind(this);\n    this.handleGrainTypeChange = this.handleGrainTypeChange.bind(this);\n    this.handleSubmit = this.handleSubmit.bind(this);\n  }\n\n  handleGrainIdChange(event: React.ChangeEvent<HTMLInputElement>) {\n    this.setState({ grainId: event.target.value });\n  }\n\n  handleGrainTypeChange(event: React.ChangeEvent<HTMLSelectElement>) {\n    this.setState({ grainType: event.target.value });\n  }\n\n  handleSubmit(event: React.MouseEvent<HTMLInputElement>) {\n    const component = this;\n\n    http.get('GrainState?grainId=' + this.state.grainId + '&grainType=' + this.state.grainType, function (err, data) {\n      component.setState({ grainState: data });\n    }).then(() => {\n\n    });\n\n    event.preventDefault();\n  }\n\n  renderEmpty() {\n    return <span>No state retrieved</span>;\n  }\n\n  renderState() {\n    let displayComponent: React.ReactNode;\n\n    if (this.state.grainState !== '') {\n      displayComponent = <DisplayGrainState code={this.state.grainState} />;\n    } else {\n      displayComponent = <div></div>;\n    }\n\n    return (\n      <Page\n        title=\"Grain Details\"\n      >\n        <div>\n          <Panel title='Grain' subTitle=\"Only non generic grains are supported\">\n            <div className=\"row\">\n              <div className=\"col-md-6 col-lg-6 col-xl-6\">\n                <div className=\"input-group\">\n                  <select value={this.state.grainType || ''} className=\"form-control\" onChange={this.handleGrainTypeChange}>\n                    <option disabled value=\"\"> -- Select an grain type -- </option>\n                    {\n                      this.props.grainTypes.map((_item) => <option key={_item} value={_item} title={_item}>{getName(_item)}</option>)\n                    }\n                  </select>\n                </div>\n              </div>\n              <div className=\"col-md-4 col-lg-4 col-xl-5\">\n                <div className=\"input-group\">\n                  <input type=\"text\" placeholder='Grain Id' className=\"form-control\"\n                    value={this.state.grainId} onChange={this.handleGrainIdChange} />\n                </div>\n              </div>\n              <div className=\"col-md-2 col-lg-2 col-xl-1\">\n                <div className=\"input-group\">\n                  <input type=\"button\" value=\"Show Details\" className='btn btn-default btn-block' onClick={this.handleSubmit} />\n                </div>\n              </div>\n            </div>\n          </Panel>\n\n          <Panel title='State' bodyPadding='0px'>\n            <div className=\"row\">\n              <div className=\"col-md-12\">\n                {displayComponent}\n              </div>\n            </div>\n          </Panel>\n        </div>\n      </Page>\n    );\n  }\n\n  render() {\n    return this.renderState();\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/grains/grain.tsx",
    "content": "import React from 'react';\nimport Chart from '../components/time-series-chart';\nimport CounterWidget from '../components/counter-widget';\nimport SiloBreakdown from './silo-table';\nimport Panel from '../components/panel';\nimport Page from '../components/page';\nimport { getName } from '../lib/typeName';\n\n// Format a fully-qualified member name so the type is shortened but the\n// member/method part is preserved. Examples:\n//  - \"A.B.C<T>.M\" -> \"C<T>.M\"\n//  - \"A.B.C<T>.N.M\" -> \"C<T>.N.M\"\nfunction formatMemberName(value: string): string {\n  if (!value) return value;\n  // find last top-level separator (dot, slash, or '#') not inside generics\n  let depth = 0;\n  for (let i = value.length - 1; i >= 0; i--) {\n    const ch = value[i];\n    if (ch === '>' || ch === ']') depth++;\n    else if (ch === '<' || ch === '[') depth--;\n    else if (depth === 0 && (ch === '.' || ch === '/' || ch === '#')) {\n      const typePart = value.substring(0, i);\n      const memberPart = value.substring(i + 1);\n      return `${getName(typePart)}.${memberPart}`;\n    }\n  }\n\n  return getName(value);\n}\n\ninterface GrainMethodValue {\n  count: number;\n  elapsedTime: number;\n  period: number | string;\n  exceptionCount: number;\n}\n\ninterface GrainStats {\n  [grainMethod: string]: {\n    [key: string]: GrainMethodValue;\n  };\n}\n\ninterface SimpleGrainStat {\n  grainType: string;\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n  [key: string]: any;\n}\n\ninterface DashboardCounters {\n  simpleGrainStats: SimpleGrainStat[];\n}\n\ninterface GrainProps {\n  grainType: string;\n  dashboardCounters: DashboardCounters;\n  grainStats: GrainStats;\n}\n\ninterface GrainGraphProps {\n  stats: { [key: string]: GrainMethodValue };\n  grainMethod: string;\n}\n\nconst GrainGraph: React.FC<GrainGraphProps> = (props) => {\n  const values: GrainMethodValue[] = [];\n  const timepoints: (number | string)[] = [];\n  Object.keys(props.stats).forEach(key => {\n    values.push(props.stats[key]);\n    timepoints.push(props.stats[key].period);\n  });\n\n  if (!values.length) {\n    return null;\n  }\n\n  while (values.length < 100) {\n    values.unshift({ count: 0, elapsedTime: 0, period: 0, exceptionCount: 0 });\n    timepoints.unshift('');\n  }\n\n  return (\n    <div>\n      <h4>{props.grainMethod}</h4>\n      <Chart\n        timepoints={timepoints}\n        series={[\n          values.map(z => z.exceptionCount),\n          values.map(z => z.count),\n          values.map(z => (z.count === 0 ? 0 : z.elapsedTime / z.count))\n        ]}\n      />\n    </div>\n  );\n};\n\n// add multiple axis to the chart\n// https://jsfiddle.net/devonuto/pa7k6xn9/\nexport default class Grain extends React.Component<GrainProps> {\n  renderEmpty() {\n    return <span>No messages recorded</span>;\n  }\n\n  renderGraphs() {\n    const stats = {\n      activationCount: 0,\n      totalSeconds: 0,\n      totalAwaitTime: 0,\n      totalCalls: 0,\n      totalExceptions: 0\n    };\n    this.props.dashboardCounters.simpleGrainStats.forEach(stat => {\n      if (stat.grainType !== this.props.grainType) return;\n      stats.activationCount += stat.activationCount;\n      stats.totalSeconds += stat.totalSeconds;\n      stats.totalAwaitTime += stat.totalAwaitTime;\n      stats.totalCalls += stat.totalCalls;\n      stats.totalExceptions += stat.totalExceptions;\n    });\n\n    return (\n      <Page\n        title={getName(this.props.grainType)}\n        subTitle={this.props.grainType}\n      >\n        <div>\n          <div className=\"row\">\n            <div className=\"col-md-3\">\n              <CounterWidget\n                icon=\"cubes\"\n                counter={stats.activationCount}\n                title=\"Activations\"\n              />\n            </div>\n            <div className=\"col-md-3\">\n              <CounterWidget\n                icon=\"bug\"\n                counter={\n                  stats.totalCalls === 0\n                    ? '0.00'\n                    : (\n                        (100 * stats.totalExceptions) /\n                        stats.totalCalls\n                      ).toFixed(2) + '%'\n                }\n                title=\"Error Rate\"\n              />\n            </div>\n            <div className=\"col-md-3\">\n              <CounterWidget\n                icon=\"tachometer-alt\"\n                counter={(stats.totalCalls / 100).toFixed(2)}\n                title=\"Req/sec\"\n              />\n            </div>\n            <div className=\"col-md-3\">\n              <CounterWidget\n                icon=\"clock\"\n                counter={\n                  stats.totalCalls === 0\n                    ? '0'\n                    : (stats.totalAwaitTime / stats.totalCalls).toFixed(2) +\n                      'ms'\n                }\n                title=\"Average response time\"\n              />\n            </div>\n          </div>\n\n          <Panel title=\"Method Profiling\">\n            <div>\n              <span>\n                <strong style={{ color: '#783988', fontSize: '25px' }}>\n                  /\n                </strong>{' '}\n                number of requests per second\n                <br />\n                <strong style={{ color: '#EC1F1F', fontSize: '25px' }}>\n                  /\n                </strong>{' '}\n                failed requests\n              </span>\n              <span className=\"pull-right\">\n                <strong style={{ color: '#EC971F', fontSize: '25px' }}>\n                  /\n                </strong>{' '}\n                average latency in milliseconds\n              </span>\n              {Object.keys(this.props.grainStats)\n                .sort()\n                .map(key => (\n                  <GrainGraph key={key}\n                    stats={this.props.grainStats[key]}\n                    grainMethod={formatMemberName(key)}\n                  />\n                ))}\n            </div>\n          </Panel>\n\n          <Panel title=\"Activations by Silo\">\n            <SiloBreakdown\n              data={this.props.dashboardCounters.simpleGrainStats}\n              grainType={this.props.grainType}\n            />\n          </Panel>\n        </div>\n      </Page>\n    );\n  }\n\n  render() {\n    if (Object.keys(this.props.grainStats).length === 0)\n      return this.renderEmpty();\n    return this.renderGraphs();\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/grains/grains.tsx",
    "content": "import React from 'react';\nimport CounterWidget from '../components/counter-widget';\nimport ChartWidget from '../components/multi-series-chart-widget';\nimport GrainBreakdown from '../components/grain-table';\nimport Panel from '../components/panel';\n\ninterface SimpleGrainStat {\n  activationCount: number;\n  [key: string]: any;\n}\n\ninterface DashboardCounters {\n  simpleGrainStats: SimpleGrainStat[];\n  totalActivationCountHistory: number[];\n}\n\ninterface GrainsProps {\n  dashboardCounters: DashboardCounters;\n}\n\nexport default class Grains extends React.Component<GrainsProps> {\n  render() {\n    const stats = { totalActivationCount: 0 };\n    this.props.dashboardCounters.simpleGrainStats.forEach(stat => {\n      stats.totalActivationCount += stat.activationCount;\n    });\n\n    return (\n      <div>\n        <div className=\"row\">\n          <div className=\"col-md-4\">\n            <CounterWidget\n              icon=\"cubes\"\n              counter={stats.totalActivationCount}\n              title=\"Total Activations\"\n              style={{ height: '120px' }}\n            />\n          </div>\n          <div className=\"col-md-8\">\n            <div className=\"info-box\" style={{ padding: '5px', height: '120px', display: 'flex', flexDirection: 'column' }}>\n              <ChartWidget\n                series={[\n                  this.props.dashboardCounters.totalActivationCountHistory\n                ]}\n              />\n            </div>\n          </div>\n        </div>\n        <Panel title=\"Activations by Type\">\n          <GrainBreakdown\n            data={this.props.dashboardCounters.simpleGrainStats}\n          />\n        </Panel>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/grains/silo-table.tsx",
    "content": "import React from 'react';\n\ninterface SiloStat {\n  siloAddress: string;\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n}\n\ninterface GrainStat {\n  siloAddress: string;\n  grainType: string;\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n}\n\ninterface SiloTableProps {\n  data: GrainStat[];\n  grainType?: string;\n}\n\nexport default class SiloTable extends React.Component<SiloTableProps> {\n  renderStat(stat: SiloStat) {\n    return (\n      <tr key={stat.siloAddress}>\n        <td style={{ textOverflow: 'ellipsis' }} title={stat.siloAddress}>\n          <a href={`#/host/${stat.siloAddress}`}>{stat.siloAddress}</a>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>{stat.activationCount}</strong>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>\n              {stat.totalCalls === 0\n                ? '0.00'\n                : ((100 * stat.totalExceptions) / stat.totalCalls).toFixed(2)}\n            </strong>{' '}\n            <small>%</small>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>\n              {stat.totalSeconds === 0\n                ? '0'\n                : (stat.totalCalls / 100).toFixed(2)}\n            </strong>{' '}\n            <small>req/sec</small>\n          </span>\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>\n              {stat.totalCalls === 0\n                ? '0'\n                : (stat.totalAwaitTime / stat.totalCalls).toFixed(2)}\n            </strong>{' '}\n            <small>ms/req</small>\n          </span>\n        </td>\n      </tr>\n    );\n  }\n\n  render() {\n    const silos: { [key: string]: SiloStat } = {};\n    if (!this.props.data) return null;\n\n    this.props.data.forEach(stat => {\n      if (!silos[stat.siloAddress]) {\n        silos[stat.siloAddress] = {\n          siloAddress: stat.siloAddress,\n          activationCount: 0,\n          totalSeconds: 0,\n          totalAwaitTime: 0,\n          totalCalls: 0,\n          totalExceptions: 0\n        };\n      }\n\n      if (this.props.grainType && stat.grainType !== this.props.grainType)\n        return;\n\n      const x = silos[stat.siloAddress];\n      x.activationCount += stat.activationCount;\n      x.totalSeconds += stat.totalSeconds;\n      x.totalAwaitTime += stat.totalAwaitTime;\n      x.totalCalls += stat.totalCalls;\n      x.totalExceptions += stat.totalExceptions;\n    });\n\n    const values = Object.keys(silos)\n      .map(function(key) {\n        const x = silos[key];\n        x.siloAddress = key;\n        return x;\n      })\n      .sort(function(a, b) {\n        return b.activationCount - a.activationCount;\n      });\n\n    return (\n      <table className=\"table\">\n        <tbody>\n          <tr>\n            <th style={{ textAlign: 'left' }}>Silo</th>\n            <th style={{ textAlign: 'right' }}>Activations</th>\n            <th style={{ textAlign: 'right' }}>Exception rate</th>\n            <th style={{ textAlign: 'right' }}>Throughput</th>\n            <th style={{ textAlign: 'right' }}>Latency</th>\n          </tr>\n          {values.map(stat => this.renderStat(stat))}\n        </tbody>\n      </table>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/index.tsx",
    "content": "// Import styles\nimport './styles.css';\n\n// Register Chart.js components\nimport {\n  Chart as ChartJS,\n  CategoryScale,\n  LinearScale,\n  PointElement,\n  LineElement,\n  ArcElement,\n  Title,\n  Tooltip,\n  Legend,\n  Filler\n} from 'chart.js';\n\nChartJS.register(\n  CategoryScale,\n  LinearScale,\n  PointElement,\n  LineElement,\n  ArcElement,\n  Title,\n  Tooltip,\n  Legend,\n  Filler\n);\n\nimport http from './lib/http';\nimport React from 'react';\nimport ReactDom from 'react-dom';\nimport routie from './lib/routie';\nimport Silo from './silos/silo';\nimport events from 'eventthing';\nimport Grain from './grains/grain';\nimport GrainDetails from './grains/grain-details';\nimport Page from './components/page';\nimport Loading from './components/loading';\nimport Menu from './components/menu';\nimport BrandHeader from './components/brand-header';\nimport Grains from './grains/grains';\nimport Silos from './silos/silos';\nimport Overview from './overview/overview';\nimport SiloState from './silos/silo-state-label';\nimport Alert from './components/alert';\nimport LogStream from './logstream/log-stream';\nimport SiloCounters from './silos/silo-counters';\nimport Reminders from './reminders/reminders';\nimport Preferences from './components/preferences';\nimport storage from './lib/storage';\n\ninterface Settings {\n  dashboardGrainsHidden: boolean;\n  systemGrainsHidden: boolean;\n}\n\ninterface MenuItem {\n  name: string;\n  path: string;\n  icon: string;\n  active?: boolean;\n  isSeparated?: boolean;\n}\n\ninterface GrainStatItem {\n  grain?: string;\n  grainType?: string;\n}\n\nconst target = document.getElementById('content');\n\n// Restore theme preference.\nlet defaultTheme = storage.get('theme') || 'dark';\nif (defaultTheme === 'dark') {\n  document.getElementById('body')!.classList.add('dark-mode');\n  dark();\n} else {\n  light();\n}\n\n// Restore grain visibility preferences.\nlet settings: Settings = {\n  dashboardGrainsHidden: storage.get('dashboardGrains') === 'hidden',\n  systemGrainsHidden: storage.get('systemGrains') === 'hidden'\n};\n\n// Global state.\nlet dashboardCounters: any = {};\nlet routeIndex = 0;\n\nfunction scroll() {\n  try {\n    document.getElementsByClassName('wrapper')[0].scrollTo(0, 0);\n  } catch (e) { }\n}\n\nlet errorTimer: NodeJS.Timeout | null;\nfunction showError(message: string) {\n  ReactDom.render(\n    <Alert onClose={closeError}>{message}</Alert>,\n    document.getElementById('error-message-content')\n  );\n  if (errorTimer) clearTimeout(errorTimer);\n  errorTimer = setTimeout(closeError, 3000);\n}\n\nfunction closeError() {\n  if (errorTimer) clearTimeout(errorTimer);\n  errorTimer = null;\n  ReactDom.render(<span />, document.getElementById('error-message-content'));\n}\n\nhttp.onError(showError);\n\nfunction setIntervalDebounced(action: () => Promise<any>, interval: number) {\n  Promise.resolve(action()).finally(() => {\n    setTimeout(setIntervalDebounced.bind(this, action, interval), interval);\n  });\n}\n\n// continually poll the dashboard counters\nfunction loadDashboardCounters() {\n    return http.get(`DashboardCounters${getFilter(settings)}`, function (err, data) {\n    dashboardCounters = data;\n    events.emit('dashboard-counters', dashboardCounters);\n  });\n}\n\nfunction getVersion() {\n  let version = '2';\n  const renderVersion = function () {\n    ReactDom.render(\n      <span id=\"version\" style={{ marginLeft: 40 }}>\n        v.{version}\n        <i\n          style={{ marginLeft: '12px', marginRight: '5px' }}\n          className=\"fab fa-github\"\n        />\n        <a\n          style={{ color: '#b8c7ce', textDecoration: 'underline' }}\n          href=\"https://github.com/dotnet/orleans/tree/main/src/Dashboard/Orleans.Dashboard\"\n        >\n          Source\n        </a>\n      </span>,\n      document.getElementById('version-content')\n    );\n  };\n\n  const loadData = function (cb?: any) {\n    http.get('version', function (err, data) {\n      version = data.version;\n      renderVersion();\n    });\n  };\n  loadData();\n}\n\n// we always want to refresh the dashboard counters\nsetIntervalDebounced(loadDashboardCounters, 1000);\nloadDashboardCounters();\nlet render: () => void = () => { };\n\nfunction renderLoading() {\n  ReactDom.render(<Loading />, target);\n}\n\nconst menuElement = document.getElementById('menu');\nconst brandHeaderElement = document.getElementById('brand-header');\n\n// Render brand header once\nReactDom.render(<BrandHeader />, brandHeaderElement);\n\nfunction renderPage(jsx: JSX.Element, path: string) {\n  ReactDom.render(jsx, target);\n  const menu = getMenu();\n  menu.forEach(x => {\n    x.active = x.path === path;\n  });\n\n  ReactDom.render(<Menu menu={menu} />, menuElement);\n}\n\n(routie as any)('', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  let clusterStats: any = {};\n  let grainMethodStats: any = [];\n  let loadDataIsPending = false;\n  const loadData = function (cb?: any) {\n    if (!loadDataIsPending) {\n      loadDataIsPending = true;\n      http.get('ClusterStats', function (err, data) {\n        clusterStats = data;\n          http.get(`TopGrainMethods${getFilter(settings)}`, function (err, grainMethodsData) {\n          grainMethodStats = grainMethodsData;\n          render();\n        }).finally(() => loadDataIsPending = false);\n      }).catch(() => loadDataIsPending = false);\n    }\n  };\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Page title=\"Overview\">\n        <Overview\n          dashboardCounters={dashboardCounters}\n          clusterStats={clusterStats}\n          grainMethodStats={grainMethodStats}\n        />\n      </Page>,\n      '#/'\n    );\n  };\n\n  events.on('dashboard-counters', render);\n  events.on('refresh', loadData);\n  loadDashboardCounters();\n});\n\n(routie as any)('/grains', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Page title=\"Grains\">\n        <Grains dashboardCounters={dashboardCounters} />\n      </Page>,\n      '#/grains'\n    );\n  };\n\n  events.on('dashboard-counters', render);\n  events.on('refresh', render);\n\n  loadDashboardCounters();\n});\n\n(routie as any)('/silos', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Page title=\"Silos\">\n        <Silos dashboardCounters={dashboardCounters} />\n      </Page>,\n      '#/silos'\n    );\n  };\n\n  events.on('dashboard-counters', render);\n  events.on('refresh', render);\n\n  loadDashboardCounters();\n});\n\n(routie as any)('/host/:host', function (host: string) {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  let siloProperties: any = {};\n  let siloMetadata: any = {};\n\n  let siloData: any[] = [];\n  let siloStats: any[] = [];\n  const loadData = function (cb?: any) {\n    http.get(`HistoricalStats/${host}`, (err, data) => {\n      siloData = data;\n      render();\n    });\n    http.get(`SiloStats/${host}`, (err, data) => {\n      siloStats = data;\n      render();\n    });\n  };\n\n  const renderOverloaded = function () {\n    if (!siloData.length) return null;\n    if (!siloData[siloData.length - 1]) return null;\n    if (!siloData[siloData.length - 1].isOverloaded) return null;\n    return (\n      <small>\n        <span className=\"label label-danger\">OVERLOADED</span>\n      </small>\n    );\n  };\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    const silo =\n      (dashboardCounters.hosts || []).filter(\n        (x: any) => x.siloAddress === host\n      )[0] || {};\n    const subTitle = (\n      <span>\n        <SiloState status={silo.status} /> {renderOverloaded()}\n      </span>\n    );\n    renderPage(\n      <Page title={`Silo ${host}`} subTitle={subTitle}>\n        <Silo\n          silo={host}\n          data={siloData}\n          siloProperties={siloProperties}\n          siloMetadata={siloMetadata}\n          dashboardCounters={dashboardCounters}\n          siloStats={siloStats}\n        />\n      </Page>,\n      '#/silos'\n    );\n  };\n\n  events.on('dashboard-counters', render);\n  events.on('refresh', loadData);\n\n  http.get('SiloProperties/' + host, function (err, data) {\n    siloProperties = data;\n    loadData();\n  });\n\n  http.get('SiloMetadata/' + host, function (err, data) {\n    siloMetadata = data;\n    loadData();\n  });\n});\n\n(routie as any)('/host/:host/counters', function (host: string) {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  http.get(`SiloCounters/${host}`, (err, data) => {\n    if (routeIndex != thisRouteIndex) return;\n    const subTitle = <a href={`#/host/${host}`}>Silo Details</a>;\n    renderPage(\n      <Page title={`Silo ${host}`} subTitle={subTitle}>\n        <SiloCounters\n          silo={host}\n          dashboardCounters={dashboardCounters}\n          counters={data}\n        />\n      </Page>,\n      '#/silos'\n    );\n  });\n});\n\n(routie as any)('/grain/:grainType', function (grainType: string) {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  let grainStats: any = {};\n  let loadDataIsPending = false;\n  const loadData = function (cb?: any) {\n    if (!loadDataIsPending) {\n      http.get('GrainStats/' + grainType, function (err, data) {\n        grainStats = data;\n        render();\n      }).finally(() => loadDataIsPending = false);\n    }\n  };\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Grain\n        grainType={grainType}\n        dashboardCounters={dashboardCounters}\n        grainStats={grainStats}\n      />,\n      '#/grains'\n    );\n  };\n\n  events.on('dashboard-counters', render);\n  events.on('refresh', loadData);\n\n  loadData();\n});\n\n(routie as any)('/grainDetails', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  let grainTypes: any = {};\n  let loadDataIsPending = false;\n  const loadData = function (cb?: any) {\n    if (!loadDataIsPending) {\n      http.get(`GrainTypes${getFilter(settings)}`, function (err, data) {\n        grainTypes = data;\n        render();\n      }).finally(() => loadDataIsPending = false);\n    }\n  };\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <GrainDetails grainTypes={grainTypes} />,\n      '#/grainState'\n    );\n  };\n\n  loadData();\n});\n\n(routie as any)('/reminders/:page?', function (page?: string) {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  let remindersData: any[] = [];\n  let pageNum: number;\n  if (page) {\n    pageNum = parseInt(page);\n  } else {\n    pageNum = 1;\n  }\n\n  const renderReminders = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Page title=\"Reminders\">\n        <Reminders remindersData={remindersData} page={pageNum} />\n      </Page>,\n      '#/reminders'\n    );\n  };\n\n  const rerouteToLastPage = function (lastPage: number) {\n    return (document.location.hash = `/reminders/${lastPage}`);\n  };\n\n  let loadDataIsPending = false;\n  const loadData = function (cb?: any) {\n    if (!loadDataIsPending) {\n      loadDataIsPending = true;\n      http.get(`Reminders/${pageNum}`, function (err, data) {\n        remindersData = data;\n        renderReminders();\n      }).finally(() => loadDataIsPending = false);\n    }\n  };\n\n  events.on('long-refresh', loadData);\n\n  loadData();\n});\n\n(routie as any)('/trace', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  const xhr = http.stream('Trace');\n  renderPage(<LogStream xhr={xhr} />, '#/trace');\n});\n\n(routie as any)('/preferences', function () {\n  const thisRouteIndex = ++routeIndex;\n  events.clearAll();\n  scroll();\n  renderLoading();\n\n  const changeSettings = (newSettings: Partial<Settings>) => {\n    settings = {\n      ...settings\n    };\n\n    if (newSettings.hasOwnProperty('dashboardGrainsHidden')) {\n      storage.put(\n        'dashboardGrains',\n        newSettings.dashboardGrainsHidden ? 'hidden' : 'visible'\n      );\n      settings.dashboardGrainsHidden = newSettings.dashboardGrainsHidden!;\n    }\n\n    if (newSettings.hasOwnProperty('systemGrainsHidden')) {\n      storage.put(\n        'systemGrains',\n        newSettings.systemGrainsHidden ? 'hidden' : 'visible'\n      );\n      settings.systemGrainsHidden = newSettings.systemGrainsHidden!;\n    }\n    loadDashboardCounters();\n  };\n\n  render = function () {\n    if (routeIndex != thisRouteIndex) return;\n    renderPage(\n      <Page title=\"Preferences\">\n        <Preferences\n          changeSettings={changeSettings}\n          settings={settings}\n          defaultTheme={defaultTheme}\n          light={light}\n          dark={dark}\n        />\n      </Page>,\n      '#/preferences'\n    );\n  };\n  loadDashboardCounters();\n\n  render();\n});\n\nsetInterval(() => events.emit('refresh'), 1000);\nsetInterval(() => events.emit('long-refresh'), 10000);\n\n(routie as any).reload();\ngetVersion();\n\nfunction getMenu(): MenuItem[] {\n  const result: MenuItem[] = [\n    {\n      name: 'Overview',\n      path: '#/',\n      icon: 'fa fa-tachometer-alt'\n    },\n    {\n      name: 'Grains',\n      path: '#/grains',\n      icon: 'fa fa-cubes'\n    },\n    {\n      name: 'Grain Details',\n      path: '#/grainDetails',\n      icon: 'fa fa-cube'\n    },\n    {\n      name: 'Silos',\n      path: '#/silos',\n      icon: 'fa fa-database'\n    },\n    {\n      name: 'Reminders',\n      path: '#/reminders',\n      icon: 'fa fa-calendar'\n    }\n  ];\n\n  if (!(window as any).hideTrace) {\n    result.push({\n      name: 'Log Stream',\n      path: '#/trace',\n      icon: 'fa fa-bars'\n    });\n  }\n\n  result.push({\n    name: 'Preferences',\n    path: '#/preferences',\n    icon: 'fa fa-cog',\n    isSeparated: true\n  });\n\n  return result;\n}\n\nfunction getFilter(settings: Settings): string {\n  if (settings.dashboardGrainsHidden && settings.systemGrainsHidden) {\n      return '?exclude=Orleans.Runtime&exclude=Orleans.Streams&exclude=Orleans.Storage&exclude=Orleans.Providers&exclude=Orleans.Dashboard';\n  } else if (settings.dashboardGrainsHidden) {\n      return '?exclude=Orleans.Dashboard';\n  } else if (settings.systemGrainsHidden) {\n      return '?exclude=Orleans.Runtime&exclude=Orleans.Streams&exclude=Orleans.Storage&exclude=Orleans.Providers';\n  }\n  return '';\n}\n\nfunction light() {\n  // Save preference to localStorage.\n  storage.put('theme', 'light');\n  defaultTheme = 'light';\n\n  // Remove dark mode class from body and set Bootstrap theme to light.\n  const body = document.getElementById('body')!;\n  body.classList.remove('dark-mode');\n  body.setAttribute('data-bs-theme', 'light');\n}\n\nfunction dark() {\n  // Save preference to localStorage.\n  storage.put('theme', 'dark');\n  defaultTheme = 'dark';\n\n  // Add dark mode class to body and set Bootstrap theme to dark.\n  const body = document.getElementById('body')!;\n  body.classList.add('dark-mode');\n  body.setAttribute('data-bs-theme', 'dark');\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/lib/http.ts",
    "content": "import events from 'eventthing';\n\ntype HttpCallback = (error: string | null, result?: any) => void;\n\nfunction makeRequest(method: string, uri: string, body: string | null, cb: HttpCallback): Promise<any> {\n  return new Promise((resolve, reject) => {\n    const xhr = new XMLHttpRequest();\n    xhr.open(method, uri, true);\n    xhr.onreadystatechange = function() {\n      if (xhr.readyState !== 4) return;\n      if (xhr.status < 400 && xhr.status > 0) {\n        const result = JSON.parse(xhr.responseText || '{}');\n        resolve(result);\n        return cb(null, result);\n      }\n      const errorMessage =\n        'Error connecting to Orleans Silo. Status code: ' +\n        (xhr.status || 'NO_CONNECTION');\n      errorHandlers.forEach(x => x(errorMessage));\n      reject(errorMessage);\n    };\n    xhr.setRequestHeader('Content-Type', 'application/json');\n    xhr.setRequestHeader('Accept', 'application/json');\n    xhr.send(body);\n  });\n}\n\ntype ErrorHandler = (error: string) => void;\n\nconst errorHandlers: ErrorHandler[] = [];\n\nconst httpModule = {\n  get: function(url: string, cb: HttpCallback): Promise<any> {\n    return makeRequest('GET', url, null, cb);\n  },\n\n  stream: function(url: string): XMLHttpRequest {\n    const xhr = new XMLHttpRequest();\n    xhr.open('GET', url, true);\n    xhr.send();\n    return xhr;\n  },\n\n  onError: function(handler: ErrorHandler): void {\n    errorHandlers.push(handler);\n  }\n};\n\nexport default httpModule;\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/lib/routie.ts",
    "content": "interface RouteKey {\n  name: string;\n  optional: boolean;\n}\n\ninterface RouteMap {\n  [key: string]: Route;\n}\n\ninterface NavigateOptions {\n  silent?: boolean;\n}\n\nlet routes: Route[] = [];\nlet map: RouteMap = {};\nconst reference = 'routie';\nconst oldReference = (window as any)[reference];\n\nclass Route {\n  name: string | null;\n  path: string;\n  keys: RouteKey[];\n  fns: Function[];\n  params: { [key: string]: string };\n  regex: RegExp;\n\n  constructor(path: string, name: string | null) {\n    this.name = name;\n    this.path = path;\n    this.keys = [];\n    this.fns = [];\n    this.params = {};\n    this.regex = pathToRegexp(this.path, this.keys, false, false);\n  }\n\n  addHandler(fn: Function): void {\n    this.fns.push(fn);\n  }\n\n  removeHandler(fn: Function): void {\n    for (let i = 0, c = this.fns.length; i < c; i++) {\n      const f = this.fns[i];\n      if (fn == f) {\n        this.fns.splice(i, 1);\n        return;\n      }\n    }\n  }\n\n  run(params: any[]): void {\n    for (let i = 0, c = this.fns.length; i < c; i++) {\n      this.fns[i].apply(this, params);\n    }\n  }\n\n  match(path: string, params: any[]): boolean {\n    const m = this.regex.exec(path);\n\n    if (!m) return false;\n\n    for (let i = 1, len = m.length; i < len; ++i) {\n      const key = this.keys[i - 1];\n\n      const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];\n\n      if (key) {\n        this.params[key.name] = val;\n      }\n      params.push(val);\n    }\n\n    return true;\n  }\n\n  toURL(params: { [key: string]: string }): string {\n    let path = this.path;\n    for (const param in params) {\n      path = path.replace('/:' + param, '/' + params[param]);\n    }\n    path = path.replace(/\\/:.*\\?/g, '/').replace(/\\?/g, '');\n    if (path.indexOf(':') != -1) {\n      throw new Error('missing parameters for url: ' + path);\n    }\n    return path;\n  }\n}\n\nconst pathToRegexp = function(\n  path: string | RegExp | string[],\n  keys: RouteKey[],\n  sensitive: boolean,\n  strict: boolean\n): RegExp {\n  if (path instanceof RegExp) return path;\n  if (path instanceof Array) path = '(' + path.join('|') + ')';\n  path = (path as string)\n    .concat(strict ? '' : '/?')\n    .replace(/\\/\\(/g, '(?:/')\n    .replace(/\\+/g, '__plus__')\n    .replace(/(\\/)?(\\.)?:(\\w+)(?:(\\(.*?\\)))?(\\?)?/g, function(\n      _: string,\n      slash: string,\n      format: string,\n      key: string,\n      capture: string,\n      optional: string\n    ) {\n      keys.push({ name: key, optional: !!optional });\n      slash = slash || '';\n      return (\n        '' +\n        (optional ? '' : slash) +\n        '(?:' +\n        (optional ? slash : '') +\n        (format || '') +\n        (capture || ((format && '([^/.]+?)') || '([^/]+?)')) +\n        ')' +\n        (optional || '')\n      );\n    })\n    .replace(/([\\/.])/g, '\\\\$1')\n    .replace(/__plus__/g, '(.+)')\n    .replace(/\\*/g, '(.*)');\n  return new RegExp('^' + path + '$', sensitive ? '' : 'i');\n};\n\nconst addHandler = function(path: string, fn: Function): void {\n  const s = path.split(' ');\n  const name = s.length == 2 ? s[0] : null;\n  path = s.length == 2 ? s[1] : s[0];\n\n  if (!map[path]) {\n    map[path] = new Route(path, name);\n    routes.push(map[path]);\n  }\n  map[path].addHandler(fn);\n};\n\ninterface RoutieFunction {\n  (path: string, fn: Function): void;\n  (path: { [key: string]: Function }): void;\n  (path: string): void;\n  lookup: (name: string, obj: { [key: string]: string }) => string | undefined;\n  remove: (path: string, fn: Function) => void;\n  removeAll: () => void;\n  navigate: (path: string, options?: NavigateOptions) => void;\n  noConflict: () => RoutieFunction;\n  reload: () => void;\n}\n\nconst routie = function(path: string | { [key: string]: Function }, fn?: Function): void {\n  if (typeof fn == 'function') {\n    addHandler(path as string, fn);\n  } else if (typeof path == 'object') {\n    for (const p in path) {\n      addHandler(p, path[p]);\n    }\n  } else if (typeof fn === 'undefined') {\n    routie.navigate(path as string);\n  }\n} as RoutieFunction;\n\nroutie.lookup = function(name: string, obj: { [key: string]: string }): string | undefined {\n  for (let i = 0, c = routes.length; i < c; i++) {\n    const route = routes[i];\n    if (route.name == name) {\n      return route.toURL(obj);\n    }\n  }\n};\n\nroutie.remove = function(path: string, fn: Function): void {\n  const route = map[path];\n  if (!route) return;\n  route.removeHandler(fn);\n};\n\nroutie.removeAll = function(): void {\n  map = {};\n  routes = [];\n};\n\nroutie.navigate = function(path: string, options?: NavigateOptions): void {\n  options = options || {};\n  const silent = options.silent || false;\n\n  if (silent) {\n    removeListener();\n  }\n  setTimeout(function() {\n    window.location.hash = path;\n\n    if (silent) {\n      setTimeout(function() {\n        addListener();\n      }, 1);\n    }\n  }, 1);\n};\n\nroutie.noConflict = function(): RoutieFunction {\n  (window as any)[reference] = oldReference;\n  return routie;\n};\n\nconst getHash = function(): string {\n  return window.location.hash.substring(1);\n};\n\nconst checkRoute = function(hash: string, route: Route): boolean {\n  const params: any[] = [];\n  if (route.match(hash, params)) {\n    route.run(params);\n    return true;\n  }\n  return false;\n};\n\nconst hashChanged = (routie.reload = function(): void {\n  const hash = getHash();\n  for (let i = 0, c = routes.length; i < c; i++) {\n    const route = routes[i];\n    if (checkRoute(hash, route)) {\n      return;\n    }\n  }\n});\n\nconst addListener = function(): void {\n  if (window.addEventListener) {\n    window.addEventListener('hashchange', hashChanged, false);\n  } else {\n    (window as any).attachEvent('onhashchange', hashChanged);\n  }\n};\n\nconst removeListener = function(): void {\n  if (window.removeEventListener) {\n    window.removeEventListener('hashchange', hashChanged);\n  } else {\n    (window as any).detachEvent('onhashchange', hashChanged);\n  }\n};\n\naddListener();\n\nexport default routie;\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/lib/storage.ts",
    "content": "// polyfill localStorage with temp store\ninterface StorageInterface {\n  [key: string]: any;\n  removeItem?: (key: string) => void;\n}\n\nlet store: StorageInterface = {};\n\ntry {\n  if (typeof localStorage !== 'undefined') {\n    store = localStorage;\n  }\n} catch (e) {\n  // noop\n}\n\nconst storageModule = {\n  put: (key: string, value: string): void => {\n    store[key] = value;\n  },\n\n  get: (key: string): string | undefined => {\n    return store[key];\n  },\n\n  del: (key: string): void => {\n    if (store.removeItem) {\n      store.removeItem(key);\n    } else {\n      delete store[key];\n    }\n  }\n};\n\nexport default storageModule;\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/lib/typeName.ts",
    "content": "function trimIdentifier(id: string): string {\n  if (!id) return id;\n  const trimmed = stripAssemblyDetails(id.trim());\n  const parts = trimmed.split('.');\n  const last = parts[parts.length - 1];\n  const tickIndex = last.indexOf('`');\n  return tickIndex !== -1 ? last.substring(0, tickIndex) : last;\n}\n\nfunction stripAssemblyDetails(value: string): string {\n  let depth = 0;\n  for (let i = 0; i < value.length; i++) {\n    const ch = value[i];\n    if (ch === '<' || ch === '[') depth++;\n    else if (ch === '>' || ch === ']') depth--;\n    else if (ch === ',' && depth === 0) return value.substring(0, i).trim();\n  }\n\n  return value.trim();\n}\n\nfunction findMatchingCloser(value: string, start: number, opener: string, closer: string): number {\n  let depth = 0;\n  for (let i = start; i < value.length; i++) {\n    const ch = value[i];\n    if (ch === opener) depth++;\n    else if (ch === closer) {\n      depth--;\n      if (depth === 0) return i;\n    }\n  }\n\n  return -1;\n}\n\nfunction splitTopLevelArguments(value: string): string[] {\n  const args: string[] = [];\n  let argStart = 0;\n  let depth = 0;\n\n  for (let i = 0; i < value.length; i++) {\n    const ch = value[i];\n    if (ch === '<' || ch === '[') depth++;\n    else if (ch === '>' || ch === ']') depth--;\n    else if (ch === ',' && depth === 0) {\n      args.push(value.substring(argStart, i));\n      argStart = i + 1;\n    }\n  }\n\n  args.push(value.substring(argStart));\n  return args;\n}\n\nfunction parseSuffix(rem: string): string {\n  if (!rem) return '';\n  let i = 0;\n  while (i < rem.length && (rem[i] === '.' || rem[i] === ' ')) i++;\n  if (i === 0) return rem;\n\n  const segments: string[] = [];\n  let segStart = i;\n  let depth = 0;\n  for (let j = i; j < rem.length; j++) {\n    const ch = rem[j];\n    if (ch === '<' || ch === '[') depth++;\n    else if (ch === '>' || ch === ']') depth--;\n    else if (ch === '.' && depth === 0) {\n      segments.push(rem.substring(segStart, j));\n      segStart = j + 1;\n    }\n  }\n\n  if (segStart <= rem.length) segments.push(rem.substring(segStart));\n\n  return '.' + segments.map(seg => parseType(seg)).join('.');\n}\n\nfunction parseType(str: string): string {\n  if (!str) return str;\n  const s = stripAssemblyDetails(str.trim());\n  if (!s) return s;\n\n  // Handle assembly-qualified generic arguments wrapped in [ ... ].\n  if (s[0] === '[') {\n    const wrappedEnd = findMatchingCloser(s, 0, '[', ']');\n    if (wrappedEnd === s.length - 1) {\n      return parseType(stripAssemblyDetails(s.substring(1, wrappedEnd)));\n    }\n  }\n\n  // Find first generic opener: '<' or '['\n  const lt = s.indexOf('<');\n  const lb = s.indexOf('[');\n  let opener = '';\n  let openerPos = -1;\n  let closer = '';\n  if (lt !== -1 && (lb === -1 || lt < lb)) {\n    opener = '<';\n    closer = '>';\n    openerPos = lt;\n  } else if (lb !== -1) {\n    opener = '[';\n    closer = ']';\n    openerPos = lb;\n  }\n\n  if (openerPos === -1) {\n    return trimIdentifier(s);\n  }\n\n  const main = s.substring(0, openerPos);\n  const end = findMatchingCloser(s, openerPos, opener, closer);\n\n  if (end === -1) {\n    return trimIdentifier(s);\n  }\n\n  const inner = s.substring(openerPos + 1, end);\n  const remainder = s.substring(end + 1);\n  const parsed = splitTopLevelArguments(inner).map(arg => parseType(arg.trim()));\n\n  return `${trimIdentifier(main)}<${parsed.join(', ')}>${parseSuffix(remainder)}`;\n}\n\nexport function getName(value: string): string {\n  return parseType(value);\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/logstream/log-stream.tsx",
    "content": "import React from 'react';\n\ninterface LogStreamProps {\n  xhr: XMLHttpRequest;\n}\n\ninterface LogStreamState {\n  log: string;\n  filter: string;\n  scrollEnabled: boolean;\n  filterRegex?: RegExp;\n}\n\nexport default class LogStream extends React.Component<LogStreamProps, LogStreamState> {\n  private logRef: React.RefObject<HTMLPreElement>;\n\n  constructor(props: LogStreamProps) {\n    super(props);\n    this.state = {\n      log: 'Connecting...',\n      filter: '',\n      scrollEnabled: true\n    };\n    this.logRef = React.createRef();\n    this.scroll = this.scroll.bind(this);\n    this.onProgress = this.onProgress.bind(this);\n    this.toggle = this.toggle.bind(this);\n    this.filterChanged = this.filterChanged.bind(this);\n    this.getFilteredLog = this.getFilteredLog.bind(this);\n  }\n\n  scroll() {\n    if (this.logRef.current) {\n      this.logRef.current.scrollTop = this.logRef.current.scrollHeight;\n    }\n  }\n\n  onProgress() {\n    if (!this.state.scrollEnabled) return;\n\n    let newLog = this.props.xhr.responseText;\n\n    if (this.props.xhr.status === 403) {\n      const responseText = this.props.xhr.responseText;\n\n      if (responseText) {\n        try {\n          const parsed = JSON.parse(responseText) as { detail?: string };\n          newLog = parsed.detail ?? responseText;\n        } catch {\n          newLog = responseText;\n        }\n      }\n    }\n\n    this.setState(\n      {\n        log: newLog\n      },\n      this.scroll\n    );\n  }\n\n  componentDidMount() {\n    this.props.xhr.onprogress = this.onProgress;\n    this.props.xhr.onload = this.onProgress;\n    this.props.xhr.onerror = this.onProgress;\n  }\n\n  componentWillUnmount() {\n    this.props.xhr.abort();\n  }\n\n  toggle() {\n    this.setState({\n      scrollEnabled: !this.state.scrollEnabled\n    });\n  }\n\n  filterChanged(event: React.ChangeEvent<HTMLInputElement>) {\n    this.setState({\n      filter: event.target.value,\n      filterRegex: new RegExp(\n        `[^\\\\s-]* (Trace|Debug|Information|Warning|Error):.*${\n          event.target.value\n        }.*`,\n        'gmi'\n      )\n    });\n  }\n\n  getFilteredLog(): string {\n    if (!this.state.filter) return this.state.log;\n\n    const matches = this.state.log.match(this.state.filterRegex);\n    return matches ? matches.join('\\r\\n') : '';\n  }\n\n  render() {\n    return (\n      <div\n        style={{\n          display: 'flex',\n          flexDirection: 'column',\n          overflow: 'hidden',\n          maxHeight: '100%'\n        }}\n      >\n        <input\n          type=\"search\"\n          name=\"filter\"\n          className=\"text log-filter\"\n          style={{ width: '100%', height: '40px' }}\n          value={this.state.filter}\n          onChange={this.filterChanged}\n          placeholder={'Regex Filter'}\n        />\n        <pre\n          ref={this.logRef}\n          className=\"log\"\n          style={{\n            overflowY: 'auto',\n            height: 'calc(100vh - 60px)',\n            whiteSpace: 'pre-wrap'\n          }}\n        >\n          {this.getFilteredLog()}\n        </pre>\n        <a\n          href=\"javascript:void\"\n          onClick={this.toggle}\n          className=\"btn btn-default\"\n          style={{\n            marginLeft: '-100px',\n            position: 'fixed',\n            top: '70px',\n            left: '100%'\n          }}\n        >\n          {this.state.scrollEnabled ? 'Pause' : 'Resume'}\n        </a>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/overview/overview.tsx",
    "content": "import React from 'react';\nimport CounterWidget from '../components/counter-widget';\nimport Panel from '../components/panel';\nimport Chart from '../components/time-series-chart';\nimport GrainMethodTable from '../components/grain-method-table';\n\ninterface ClusterStatsValue {\n  count: number;\n  elapsedTime: number;\n  period: number | string;\n  exceptionCount: number;\n}\n\ninterface ClusterStats {\n  [key: string]: ClusterStatsValue;\n}\n\ninterface SimpleGrainStat {\n  activationCount: number;\n  totalSeconds: number;\n  totalAwaitTime: number;\n  totalCalls: number;\n  totalExceptions: number;\n}\n\ninterface DashboardCounters {\n  simpleGrainStats: SimpleGrainStat[];\n  totalActiveHostCount: number;\n}\n\ninterface GrainMethodStat {\n  count: number;\n  elapsedTime: number;\n  exceptionCount: number;\n  numberOfSamples: number;\n}\n\ninterface GrainMethodStats {\n  calls: GrainMethodStat[];\n  errors: GrainMethodStat[];\n  latency: GrainMethodStat[];\n}\n\ninterface OverviewProps {\n  dashboardCounters: DashboardCounters;\n  clusterStats: ClusterStats;\n  grainMethodStats: GrainMethodStats;\n}\n\ninterface ClusterGraphProps {\n  stats: ClusterStats;\n}\n\nconst ClusterGraph: React.FC<ClusterGraphProps> = (props) => {\n  const values: ClusterStatsValue[] = [];\n  const timepoints: (number | string)[] = [];\n  Object.keys(props.stats).forEach(key => {\n    values.push(props.stats[key]);\n    timepoints.push(props.stats[key].period);\n  });\n  if (!values.length) {\n    return null;\n  }\n\n  while (values.length < 100) {\n    values.unshift({ count: 0, elapsedTime: 0, period: 0, exceptionCount: 0 });\n    timepoints.unshift('');\n  }\n  const series0: number[] = [];\n  const series1: number[] = [];\n  const series2: number[] = [];\n  values.map(z => {\n    series0.push(z.exceptionCount);\n    series1.push(z.count);\n    series2.push(z.count === 0 ? 0 : z.elapsedTime / z.count);\n  });\n  return (\n    <div>\n      <Chart timepoints={timepoints} series={[series0, series1, series2]} />\n    </div>\n  );\n};\n\nexport default class Overview extends React.Component<OverviewProps> {\n  render() {\n    const stats = {\n      totalActivationCount: 0,\n      totalSeconds: 0,\n      totalAwaitTime: 0,\n      totalCalls: 0,\n      totalExceptions: 0\n    };\n    this.props.dashboardCounters.simpleGrainStats.forEach(stat => {\n      stats.totalActivationCount += stat.activationCount;\n      stats.totalSeconds += stat.totalSeconds;\n      stats.totalAwaitTime += stat.totalAwaitTime;\n      stats.totalCalls += stat.totalCalls;\n      stats.totalExceptions += stat.totalExceptions;\n    });\n\n    return (\n      <div>\n        <div className=\"row\">\n          <div className=\"col-md-6\">\n            <CounterWidget\n              icon=\"cubes\"\n              counter={stats.totalActivationCount}\n              title=\"Total Activations\"\n              link=\"#/grains\"\n            />\n          </div>\n          <div className=\"col-md-6\">\n            <CounterWidget\n              icon=\"database\"\n              counter={this.props.dashboardCounters.totalActiveHostCount}\n              title=\"Active Silos\"\n              link=\"#/silos\"\n            />\n          </div>\n        </div>\n        <div className=\"row\">\n          <div className=\"col-md-4\">\n            <CounterWidget\n              icon=\"bug\"\n              counter={\n                stats.totalCalls === 0\n                  ? '0.00'\n                  : ((100 * stats.totalExceptions) / stats.totalCalls).toFixed(\n                      2\n                    ) + '%'\n              }\n              title=\"Error Rate\"\n            />\n          </div>\n          <div className=\"col-md-4\">\n            <CounterWidget\n              icon=\"tachometer-alt\"\n              counter={(stats.totalCalls / 100).toFixed(2)}\n              title=\"Req/sec\"\n            />\n          </div>\n          <div className=\"col-md-4\">\n            <CounterWidget\n              icon=\"clock\"\n              counter={\n                stats.totalCalls === 0\n                  ? '0'\n                  : (stats.totalAwaitTime / stats.totalCalls).toFixed(2) + 'ms'\n              }\n              title=\"Average response time\"\n            />\n          </div>\n        </div>\n        <div className=\"row\">\n          <div className=\"col-md-12\">\n            <Panel title=\"Cluster Profiling\">\n              <div>\n                <span>\n                  <strong style={{ color: '#783988', fontSize: '25px' }}>\n                    /\n                  </strong>{' '}\n                  number of requests per second\n                  <br />\n                  <strong style={{ color: '#EC1F1F', fontSize: '25px' }}>\n                    /\n                  </strong>{' '}\n                  failed requests\n                </span>\n                <span className=\"pull-right\">\n                  <strong style={{ color: '#EC971F', fontSize: '25px' }}>\n                    /\n                  </strong>{' '}\n                  average latency in milliseconds\n                </span>\n                <ClusterGraph stats={this.props.clusterStats} />\n              </div>\n            </Panel>\n          </div>\n        </div>\n        <div className=\"row\">\n          <div className=\"col-md-4\">\n            <Panel title=\"Methods with Most Calls\">\n              <GrainMethodTable\n                values={this.props.grainMethodStats.calls}\n                valueFormatter={x =>\n                  `${(x.count / x.numberOfSamples).toFixed(2)}req/sec`\n                }\n              />\n            </Panel>\n          </div>\n          <div className=\"col-md-4\">\n            <Panel title=\"Methods with Most Exceptions\">\n              <GrainMethodTable\n                values={this.props.grainMethodStats.errors}\n                valueFormatter={x =>\n                  `${((100 * x.exceptionCount) / x.count).toFixed(2)}%`\n                }\n              />\n            </Panel>\n          </div>\n          <div className=\"col-md-4\">\n            <Panel title=\"Methods with Highest Latency\">\n              <GrainMethodTable\n                values={this.props.grainMethodStats.latency}\n                valueFormatter={x =>\n                  `${(x.elapsedTime / x.count).toFixed(2)}ms/req`\n                }\n              />\n            </Panel>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/reminders/reminders.tsx",
    "content": "import React from 'react';\nimport CounterWidget from '../components/counter-widget';\nimport ReminderTable from '../components/reminder-table';\nimport Panel from '../components/panel';\n\ninterface Reminder {\n  [key: string]: any;\n}\n\ninterface RemindersData {\n  count: number;\n  reminders: Reminder[];\n}\n\ninterface RemindersProps {\n  remindersData: RemindersData;\n  page: number;\n}\n\nexport default class Reminders extends React.Component<RemindersProps> {\n  render() {\n    const totalPages = Math.ceil(this.props.remindersData.count / 25);\n    const showFirst = this.props.page > 2;\n    const showPrevious = this.props.page > 1;\n    const showNext = totalPages > this.props.page;\n    const showLast = totalPages > this.props.page + 1;\n    return (\n      <div>\n        <div className=\"row\">\n          <div className=\"col-md-12\">\n            <CounterWidget\n              icon=\"calendar\"\n              counter={this.props.remindersData.count}\n              title=\"Reminders Count\"\n            />\n          </div>\n        </div>\n        <Panel title=\"Reminders\" subTitle={`Page ${this.props.page}`}>\n          <div>\n            <ReminderTable data={this.props.remindersData.reminders} />\n            <div style={{ textAlign: 'center' }}>\n              {showFirst ? (\n                <a className=\"btn btn-default bg-purple\" href={'#/reminders/1'}>\n                  <i className=\"fa fa-arrow-circle-left\" /> First\n                </a>\n              ) : null}\n              <span> </span>\n              {showPrevious ? (\n                <a\n                  className=\"btn btn-default bg-purple\"\n                  href={`#/reminders/${this.props.page - 1}`}\n                >\n                  <i className=\"fa fa-arrow-circle-left\" /> Previous\n                </a>\n              ) : null}\n              <span> </span>\n              {showNext ? (\n                <a\n                  className=\"btn btn-default bg-purple\"\n                  href={`#/reminders/${this.props.page + 1}`}\n                >\n                  Next <i className=\"fa fa-arrow-circle-right\" />\n                </a>\n              ) : null}\n              <span> </span>\n              {showLast ? (\n                <a\n                  className=\"btn btn-default bg-purple\"\n                  href={`#/reminders/${totalPages}`}\n                >\n                  Last <i className=\"fa fa-arrow-circle-right\" />\n                </a>\n              ) : null}\n            </div>\n          </div>\n        </Panel>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/host-table.tsx",
    "content": "import React from 'react';\nimport SiloState from './silo-state-label';\nimport humanize from 'humanize-duration';\n\ninterface SimpleGrainStat {\n  siloAddress: string;\n  activationCount: number;\n}\n\ninterface Silo {\n  siloAddress: string;\n  status: string;\n  siloName: string;\n  hostName: string;\n  startTime?: string;\n}\n\ninterface DashboardCounters {\n  hosts?: Silo[];\n  simpleGrainStats: SimpleGrainStat[];\n}\n\ninterface HostTableProps {\n  dashboardCounters: DashboardCounters;\n}\n\nfunction sortFunction(a: Silo, b: Silo): number {\n  const nameA = a.siloAddress.toUpperCase(); // ignore upper and lowercase\n  const nameB = b.siloAddress.toUpperCase(); // ignore upper and lowercase\n  if (nameA < nameB) return -1;\n  if (nameA > nameB) return 1;\n  return 0;\n}\n\nexport default class HostTable extends React.Component<HostTableProps> {\n  constructor(props: HostTableProps) {\n    super(props);\n    this.renderHost = this.renderHost.bind(this);\n  }\n\n  renderHost(host: string, silo: Silo) {\n    let subTotal = 0;\n    this.props.dashboardCounters.simpleGrainStats.forEach(function(stat) {\n      if (stat.siloAddress.toLowerCase() === host.toLowerCase())\n        subTotal += stat.activationCount;\n    });\n\n    return (\n      <tr key={host}>\n        <td>\n          <a href={'#/host/' + host}>{host}</a>\n        </td>\n        <td>\n          <SiloState status={silo.status} />\n        </td>\n        <td>\n          {silo.siloName}\n        </td>\n        <td>\n          {silo.hostName}\n        </td>\n        <td>\n          {silo.startTime ? (\n            <span>\n              up for{' '}\n              {humanize(\n                new Date().getTime() - new Date(silo.startTime).getTime(),\n                { round: true, largest: 2 }\n              )}\n            </span>\n          ) : (\n            <span>uptime is not available</span>\n          )}\n        </td>\n        <td>\n          <span className=\"pull-right\">\n            <strong>{subTotal}</strong> <small>activations</small>\n          </span>\n        </td>\n      </tr>\n    );\n  }\n\n  render() {\n    if (!this.props.dashboardCounters.hosts) return null;\n    return (\n      <table className=\"table\">\n        <tbody>\n          {this.props.dashboardCounters.hosts\n            .sort(sortFunction)\n            .map(function(silo) {\n              return this.renderHost(silo.siloAddress, silo);\n            }, this)}\n        </tbody>\n      </table>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/silo-counters.tsx",
    "content": "import React from 'react';\nimport Panel from '../components/panel';\n\ninterface Counter {\n  name: string;\n  value: string | number;\n  delta: string | number | null;\n}\n\ninterface SiloCountersProps {\n  counters: Counter[];\n}\n\nexport default class SiloCounters extends React.Component<SiloCountersProps> {\n  renderItem(item: Counter) {\n    return (\n      <tr key={item.name}>\n        <td style={{ textOverflow: 'ellipsis' }}>{item.name}</td>\n        <td>\n          <strong>{item.value}</strong>\n        </td>\n        <td style={{ whiteSpace: 'nowrap' }}>\n          {item.delta === null ? '' : <span>&Delta; {item.delta}</span>}\n        </td>\n      </tr>\n    );\n  }\n\n  render() {\n    return (\n      <div>\n        <Panel title=\"Silo Counters\">\n          <div>\n            <table className=\"table\">\n              <tbody>{this.props.counters.map(item => this.renderItem(item))}</tbody>\n            </table>\n            {this.props.counters.length === 0 ? (\n              <span>\n                <p className=\"lead\">No counters available.</p> It may take a few\n                minutes for data to be published.\n              </span>\n            ) : null}\n          </div>\n        </Panel>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/silo-grid.tsx",
    "content": "import React from 'react';\nimport SiloState from './silo-state-label';\n\ninterface Host {\n  siloAddress: string;\n  status: string;\n  updateZone: number;\n  faultZone: number;\n}\n\ninterface DashboardCounters {\n  hosts?: Host[];\n}\n\ninterface SiloGridProps {\n  dashboardCounters: DashboardCounters;\n}\n\nexport default class SiloGrid extends React.Component<SiloGridProps> {\n  constructor(props: SiloGridProps) {\n    super(props);\n    this.renderSilo = this.renderSilo.bind(this);\n    this.renderZone = this.renderZone.bind(this);\n  }\n\n  renderSilo(silo: Host) {\n    return (\n      <div key={silo.siloAddress} className=\"well well-sm\">\n        <a href={'#/host/' + silo.siloAddress}>{silo.siloAddress}</a>{' '}\n        <small>\n          <SiloState status={silo.status} />\n        </small>\n      </div>\n    );\n  }\n\n  renderZone(updateZone: number, faultZone: number) {\n    const matchingSilos = (this.props.dashboardCounters.hosts || []).filter(\n      x => x.updateZone === updateZone && x.faultZone === faultZone\n    );\n    return <span>{matchingSilos.map(this.renderSilo)}</span>;\n  }\n\n  render() {\n    const hosts = this.props.dashboardCounters.hosts || [];\n\n    if (hosts.length === 0) return <span>no data</span>;\n\n    const updateZones = hosts\n      .map(x => x.updateZone)\n      .sort()\n      .filter((v, i, a) => a.indexOf(v) === i);\n    const faultZones = hosts\n      .map(x => x.faultZone)\n      .sort()\n      .filter((v, i, a) => a.indexOf(v) === i);\n\n    return (\n      <div>\n        <table className=\"table table-bordered table-hovered\">\n          <tbody>\n            <tr>\n              <td />\n              {faultZones.map(faultZone => {\n                return <th key={faultZone}>Fault Zone {faultZone}</th>;\n              })}\n            </tr>\n            {updateZones.map(updateZone => {\n              return (\n                <tr key={updateZone}>\n                  <th>Update Zone {updateZone}</th>\n                  {faultZones.map(faultZone => {\n                    return (\n                      <td key={faultZone}>\n                        {this.renderZone(updateZone, faultZone)}\n                      </td>\n                    );\n                  })}\n                </tr>\n              );\n            })}\n          </tbody>\n        </table>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/silo-state-label.tsx",
    "content": "import React from 'react';\n\ntype SiloStatus = 'Created' | 'Joining' | 'Active' | 'ShuttingDown' | 'Stopping' | 'Dead';\n\nconst labelClassMapper: { [key in SiloStatus]: string } = {\n  Created: 'info',\n  Joining: 'info',\n  Active: 'success',\n  ShuttingDown: 'warning',\n  Stopping: 'warning',\n  Dead: 'danger'\n};\n\ninterface SiloStateLabelProps {\n  status: string;\n}\n\nexport default class SiloStateLabel extends React.Component<SiloStateLabelProps> {\n  render() {\n    const status = this.props.status as SiloStatus;\n    return (\n      <span className={'label label-' + (labelClassMapper[status] || 'default')}>\n        {this.props.status || 'unknown'}\n      </span>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/silo.tsx",
    "content": "import React from 'react';\nimport Gauge from '../components/gauge-widget';\nimport PropertiesWidget from '../components/properties-widget';\nimport GrainBreakdown from '../components/grain-table';\nimport ChartWidget from '../components/multi-series-chart-widget';\nimport Panel from '../components/panel';\nimport Chart from '../components/time-series-chart';\n\ninterface SiloDataPoint {\n  count: number;\n  elapsedTime: number;\n  period: number | string;\n  exceptionCount: number;\n  cpuUsage?: number;\n  totalPhysicalMemory?: number;\n  availableMemory?: number;\n  activationCount?: number;\n  recentlyUsedActivationCount?: number;\n  clientCount?: number;\n  receivedMessages?: number;\n  sentMessages?: number;\n  receiveQueueLength?: number;\n  requestQueueLength?: number;\n  sendQueueLength?: number;\n}\n\ninterface SiloStatsData {\n  [key: string]: SiloDataPoint;\n}\n\ninterface SimpleGrainStat {\n  siloAddress: string;\n  [key: string]: any;\n}\n\ninterface Host {\n  siloAddress: string;\n  hostName?: string;\n  roleName?: string;\n  siloName?: string;\n  proxyPort?: number;\n  updateZone?: number;\n  faultZone?: number;\n}\n\ninterface DashboardCounters {\n  simpleGrainStats?: SimpleGrainStat[];\n  hosts: Host[];\n}\n\ninterface SiloProperties {\n  orleansVersion?: string;\n  hostVersion?: string;\n}\n\ninterface SiloMetadata {\n  [key: string]: string;\n}\n\ninterface SiloProps {\n  silo: string;\n  data: (SiloDataPoint | null)[];\n  siloProperties: SiloProperties;\n  siloMetadata: (SiloMetadata | null)[];\n  dashboardCounters: DashboardCounters;\n  siloStats: SiloStatsData;\n}\n\ninterface SiloGraphProps {\n  stats: SiloStatsData;\n}\n\nconst SiloGraph: React.FC<SiloGraphProps> = (props) => {\n  const values: SiloDataPoint[] = [];\n  const timepoints: (number | string)[] = [];\n  Object.keys(props.stats).forEach(key => {\n    values.push(props.stats[key]);\n    timepoints.push(props.stats[key].period);\n  });\n\n  if (!values.length) {\n    return null;\n  }\n\n  while (values.length < 100) {\n    values.unshift({ count: 0, elapsedTime: 0, period: 0, exceptionCount: 0 });\n    timepoints.unshift('');\n  }\n\n  return (\n    <div>\n      <Chart\n        timepoints={timepoints}\n        series={[\n          values.map(z => z.exceptionCount),\n          values.map(z => z.count),\n          values.map(z => (z.count === 0 ? 0 : z.elapsedTime / z.count))\n        ]}\n      />\n    </div>\n  );\n};\n\nexport default class Silo extends React.Component<SiloProps> {\n  hasData(value: (SiloDataPoint | null)[]): boolean {\n    for (let i = 0; i < value.length; i++) {\n      if (value[i] !== null) return true;\n    }\n    return false;\n  }\n\n  querySeries(lambda: (x: SiloDataPoint) => number): number[] {\n    return this.props.data.map(function(x) {\n      if (!x) return 0;\n      return lambda(x);\n    });\n  }\n\n  hasSeries(lambda: (x: SiloDataPoint) => boolean): boolean {\n    let hasValue = false;\n\n    for (const key in this.props.data) {\n      const value = this.props.data[key];\n      if (value && lambda(value)) {\n        hasValue = true;\n      }\n    }\n\n    return hasValue;\n  }\n\n  render() {\n    if (!this.hasData(this.props.data)) {\n      return (\n        <Panel title=\"Error\">\n          <div>\n            <p className=\"lead\">No data available for this silo</p>\n            <p>\n              <a href=\"#/silos\">Show all silos</a>\n            </p>\n          </div>\n        </Panel>\n      );\n    }\n\n    const last = this.props.data[this.props.data.length - 1]!;\n    const properties: { [key: string]: string | number } = {\n      Clients: last.clientCount || '0',\n      'Messages received': last.receivedMessages || '0',\n      'Messages sent': last.sentMessages || '0',\n      'Receive queue': last.receiveQueueLength || '0',\n      'Request queue': last.requestQueueLength || '0',\n      'Send queue': last.sendQueueLength || '0'\n    };\n\n    const grainStats = (\n      this.props.dashboardCounters.simpleGrainStats || []\n    ).filter(function(x) {\n      return x.siloAddress === this.props.silo;\n    }, this);\n\n    const silo =\n      this.props.dashboardCounters.hosts.filter(\n        x => x.siloAddress === this.props.silo\n      )[0] || {};\n\n    const configuration: { [key: string]: string | number | undefined } = {\n      'Host name': silo.hostName,\n      'Role name': silo.roleName,\n      'Silo name': silo.siloName,\n      'Proxy port': silo.proxyPort,\n      'Update zone': silo.updateZone,\n      'Fault zone': silo.faultZone\n    };\n\n    if (this.props.siloProperties.orleansVersion) {\n      configuration['Orleans version'] = this.props.siloProperties.orleansVersion;\n    }\n\n    if (this.props.siloProperties.hostVersion) {\n      configuration['Host version'] = this.props.siloProperties.hostVersion;\n    }\n\n    let cpuGauge: React.ReactNode;\n    let memGauge: React.ReactNode;\n    let metadata: React.ReactNode;\n\n    if (this.hasSeries(x => (x.cpuUsage || 0) > 0)) {\n      cpuGauge = (\n        <div>\n          <Gauge\n            value={last.cpuUsage || 0}\n            max={100}\n            title=\"CPU Usage\"\n            description={Math.floor(last.cpuUsage || 0) + '% utilisation'}\n          />\n          <div style={{ width: '100%', height: '80px' }}>\n            <ChartWidget series={[this.querySeries(x => x.cpuUsage || 0)]} />\n          </div>\n        </div>\n      );\n    } else {\n      cpuGauge = (\n        <div style={{ textAlign: 'center', position: 'relative', minHeight: '100px' }}>\n          <h4>CPU Usage</h4>\n          <div style={{ height: '200px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n            <div style={{ lineHeight: '40px' }}>No data available</div>\n          </div>\n          <div style={{ height: '80px' }}></div>\n        </div>\n      );\n    }\n\n    if (this.hasSeries(x => (x.totalPhysicalMemory || 0) - (x.availableMemory || 0) > 0)) {\n      memGauge = (\n        <div>\n          <Gauge\n            value={\n              (last.totalPhysicalMemory || 0) - (last.availableMemory || 0)\n            }\n            max={last.totalPhysicalMemory || 1}\n            title=\"Memory Usage\"\n            description={\n              Math.floor((last.availableMemory || 0) / (1024 * 1024)) +\n              ' MB free'\n            }\n          />\n          <div style={{ width: '100%', height: '80px' }}>\n            <ChartWidget\n              series={[\n                this.querySeries(\n                  x => ((x.totalPhysicalMemory || 0) - (x.availableMemory || 0)) / (1024 * 1024)\n                )\n              ]}\n            />\n          </div>\n        </div>\n      );\n    } else {\n      memGauge = (\n        <div style={{ textAlign: 'center', position: 'relative', minHeight: '100px' }}>\n          <h4>Memory Usage</h4>\n          <div style={{ height: '200px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n            <div style={{ lineHeight: '40px' }}>No data available</div>\n          </div>\n          <div style={{ height: '80px' }}></div>\n        </div>\n      );\n    }\n\n    return (\n      <div>\n        <Panel title=\"Overview\">\n          <div className=\"row\">\n            <div className=\"col-md-4\">{cpuGauge}</div>\n            <div className=\"col-md-4\">{memGauge}</div>\n            <div className=\"col-md-4\">\n              <Gauge\n                value={last.recentlyUsedActivationCount || 0}\n                max={last.activationCount || 1}\n                title=\"Grain Usage\"\n                description={\n                  (last.activationCount || 0) +\n                  ' activations, ' +\n                  Math.floor(\n                    ((last.recentlyUsedActivationCount || 0) * 100) /\n                      (last.activationCount || 1)\n                  ) +\n                  '% recently used'\n                }\n              />\n              <div style={{ width: '100%', height: '80px' }}>\n                <ChartWidget\n                  series={[\n                    this.querySeries(x => x.activationCount || 0),\n                    this.querySeries(x => x.recentlyUsedActivationCount || 0)\n                  ]}\n                />\n              </div>\n            </div>\n          </div>\n        </Panel>\n\n        <Panel title=\"Silo Profiling\">\n          <div>\n            <span>\n              <strong style={{ color: '#783988', fontSize: '25px' }}>/</strong>{' '}\n              number of requests per second\n              <br />\n              <strong style={{ color: '#EC1F1F', fontSize: '25px' }}>\n                /\n              </strong>{' '}\n              failed requests\n            </span>\n            <span className=\"pull-right\">\n              <strong style={{ color: '#EC971F', fontSize: '25px' }}>/</strong>{' '}\n              average latency in milliseconds\n            </span>\n            <SiloGraph stats={this.props.siloStats} />\n          </div>\n        </Panel>\n\n        <div className=\"row\">\n          <div className=\"col-md-6\">\n            <Panel title=\"Silo Counters\">\n              <div>\n                <PropertiesWidget data={properties} />\n                <a href={`#/host/${this.props.silo}/counters`}>\n                  View all counters\n                </a>\n              </div>\n            </Panel>\n          </div>\n          <div className=\"col-md-6\">\n            <Panel title=\"Silo Metadata\">\n              <PropertiesWidget data={this.props.siloMetadata} />\n            </Panel>\n          </div>\n        </div>\n\n        <Panel title=\"Silo Properties\">\n          <PropertiesWidget data={configuration} />\n        </Panel>\n\n        <Panel title=\"Activations by Type\">\n          <GrainBreakdown data={grainStats} silo={this.props.silo} />\n        </Panel>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/silos/silos.tsx",
    "content": "import React from 'react';\nimport CounterWidget from '../components/counter-widget';\nimport ChartWidget from '../components/multi-series-chart-widget';\nimport HostsWidget from './host-table';\nimport SiloGrid from './silo-grid';\nimport Panel from '../components/panel';\n\ninterface DashboardCounters {\n  totalActiveHostCount: number;\n  totalActiveHostCountHistory: number[];\n  [key: string]: any;\n}\n\ninterface SilosProps {\n  dashboardCounters: DashboardCounters;\n}\n\nexport default class Silos extends React.Component<SilosProps> {\n  render() {\n    return (\n      <div>\n        <div className=\"row\">\n          <div className=\"col-md-4\">\n            <CounterWidget\n              icon=\"database\"\n              counter={this.props.dashboardCounters.totalActiveHostCount}\n              title=\"Active Silos\"\n              style={{ height: '120px' }}\n            />\n          </div>\n          <div className=\"col-md-8\">\n            <div className=\"info-box\" style={{ padding: '5px', height: '120px', display: 'flex', flexDirection: 'column' }}>\n              <ChartWidget\n                series={[\n                  this.props.dashboardCounters.totalActiveHostCountHistory\n                ]}\n              />\n            </div>\n          </div>\n        </div>\n\n        <Panel title=\"Silo Health\">\n          <HostsWidget dashboardCounters={this.props.dashboardCounters} />\n        </Panel>\n        <Panel title=\"Silo Map\">\n          <SiloGrid dashboardCounters={this.props.dashboardCounters} />\n        </Panel>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/skin-purple.css",
    "content": "/* Custom purple skin for Orleans Dashboard (compatible with AdminLTE v3) */\n\n/* Sidebar styling */\n.skin-purple .main-sidebar,\n.skin-purple .sidebar {\n  background-color: #222d32;\n}\n\n.skin-purple .nav-sidebar .nav-link {\n  color: #b8c7ce;\n  border-left: 3px solid transparent;\n}\n\n.skin-purple .nav-sidebar .nav-link:hover {\n  color: #fff;\n  background: #1e282c;\n}\n\n.skin-purple .nav-sidebar .nav-link.active,\n.skin-purple .nav-sidebar .nav-item.menu-open > .nav-link {\n  color: #fff;\n  background: #1e282c;\n  border-left-color: #663399;\n}\n\n.skin-purple .nav-sidebar .nav-link p {\n  color: inherit;\n}\n\n/* Info box styling for purple theme */\n.skin-purple .info-box {\n  box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);\n  margin-bottom: 1rem;\n}\n\n.skin-purple .info-box-icon {\n  border-radius: .25rem 0 0 .25rem;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.skin-purple .bg-purple {\n  background-color: #663399 !important;\n  color: #fff;\n}\n\n/* Panel/Box styling */\n.skin-purple .box,\n.skin-purple .card {\n  box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);\n}\n\n/* Ensure proper spacing */\n.skin-purple .content-wrapper {\n  min-height: 100vh;\n}\n\n/* Fix for sidebar menu items */\n.skin-purple .sidebar-menu > li.header {\n  color: #4b646f;\n  background: #1a2226;\n}\n\n.skin-purple .sidebar a:hover {\n  text-decoration: none;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/styles.css",
    "content": "/* Import Bootstrap */\n@import 'bootstrap/dist/css/bootstrap.css';\n\n/* Import Font Awesome */\n@import '@fortawesome/fontawesome-free/css/all.css';\n\n/* Import AdminLTE core styles */\n@import 'admin-lte/dist/css/adminlte.css';\n\n/* Import custom purple skin theme */\n@import './skin-purple.css';\n\n/* Import theme system (light/dark) */\n@import './themes.css';\n\n/* Import custom Orleans Dashboard styles */\n@import './custom.css';\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/themes.css",
    "content": "/* Theme system using CSS custom properties */\n\n/* Light theme (default) */\n:root {\n  --log-bg: #fff;\n  --log-border: #ddd;\n  --log-color: #333;\n\n  --form-control-bg: #fff;\n  --form-control-border: #ccc;\n  --form-control-color: #333;\n\n  --log-filter-bg: #f5f5f5;\n  --log-filter-shadow: #d8d9da;\n\n  --app-main-bg: #fff;\n  --app-main-color: #333;\n\n  --app-content-header-bg: #fff;\n  --app-content-header-color: #333;\n\n  --info-box-bg: #fff;\n  --info-box-color: #333;\n  --info-box-text-color: #333;\n\n  --card-bg: #fff;\n  --card-color: #333;\n  --card-border-top: #663399;\n\n  --card-header-bg: #f5f5f5;\n  --card-header-color: #333;\n  --card-header-border: rgba(0,0,0,.125);\n\n  --card-body-bg: #fff;\n  --card-body-color: #333;\n\n  --table-border: #dee2e6;\n  --table-color: #333;\n  --table-striped-bg: rgba(0,0,0,.05);\n\n  --well-bg: #f5f5f5;\n  --well-border: #e3e3e3;\n  --well-color: #333;\n\n  --small-color: #6c757d;\n\n  --btn-default-bg: #fff;\n  --btn-default-border: #ccc;\n  --btn-default-color: #333;\n  --btn-default-hover-bg: #e6e6e6;\n  --btn-default-hover-border: #adadad;\n\n  --btn-primary-bg: #663399;\n  --btn-primary-border: #663399;\n  --btn-primary-color: #ffffff;\n  --btn-primary-hover-bg: #552d80;\n  --btn-primary-hover-border: #4d2873;\n\n  --link-color: #7952b3;\n  --link-hover-color: #663399;\n\n  --sidebar-bg: #f8f9fa;\n  --sidebar-nav-link-color: #495057;\n  --sidebar-nav-link-hover-bg: #e9ecef;\n  --sidebar-nav-link-hover-color: #212529;\n  --sidebar-nav-link-active-bg: #663399;\n  --sidebar-nav-link-active-color: #ffffff;\n  --sidebar-nav-icon-color: #6c757d;\n  --sidebar-nav-icon-active-color: #ffffff;\n  --sidebar-brand-bg: #ffffff;\n  --sidebar-brand-border: #dee2e6;\n  --sidebar-brand-title-color: #212529;\n  --sidebar-brand-version-color: #6c757d;\n}\n\n/* Override Bootstrap 5 CSS variables for light theme */\n[data-bs-theme=\"light\"] {\n  --bs-body-bg: #fff;\n  --bs-body-color: #333;\n  --bs-table-bg: transparent;\n  --bs-table-color: #333;\n  --bs-card-bg: #fff;\n  --bs-card-color: #333;\n  --bs-border-color: #dee2e6;\n  --bs-primary: #663399;\n  --bs-primary-rgb: 102, 51, 153;\n  --bs-link-color: #7952b3;\n  --bs-link-hover-color: #663399;\n}\n\n/* Dark theme */\nbody.dark-mode {\n  --log-bg: #1e282c;\n  --log-border: #333;\n  --log-color: silver;\n\n  --form-control-bg: #222d32;\n  --form-control-border: #333;\n  --form-control-color: #c2c7d0;\n\n  --log-filter-bg: #222d32;\n  --log-filter-shadow: #444c52;\n\n  --app-main-bg: #1e282c;\n  --app-main-color: #c2c7d0;\n\n  --app-content-header-bg: #1e282c;\n  --app-content-header-color: #c2c7d0;\n\n  --info-box-bg: #343a40;\n  --info-box-color: #c2c7d0;\n  --info-box-text-color: #c2c7d0;\n\n  --card-bg: #343a40;\n  --card-color: #c2c7d0;\n  --card-border-top: #8b6bb3;\n\n  --card-header-bg: #3d444b;\n  --card-header-color: #c2c7d0;\n  --card-header-border: #6c757d;\n\n  --card-body-bg: #343a40;\n  --card-body-color: #c2c7d0;\n\n  --table-border: #454d55;\n  --table-color: #c2c7d0;\n  --table-striped-bg: rgba(255,255,255,.05);\n\n  --well-bg: #343a40;\n  --well-border: #6c757d;\n  --well-color: #c2c7d0;\n\n  --small-color: #adb5bd;\n\n  --btn-default-bg: #454d55;\n  --btn-default-border: #6c757d;\n  --btn-default-color: #c2c7d0;\n  --btn-default-hover-bg: #545b62;\n  --btn-default-hover-border: #6c757d;\n\n  --btn-primary-bg: #663399;\n  --btn-primary-border: #663399;\n  --btn-primary-color: #ffffff;\n  --btn-primary-hover-bg: #552d80;\n  --btn-primary-hover-border: #4d2873;\n\n  --link-color: #a78bfa;\n  --link-hover-color: #c4b5fd;\n\n  --sidebar-bg: #343a40;\n  --sidebar-nav-link-color: #c2c7d0;\n  --sidebar-nav-link-hover-bg: #3d444b;\n  --sidebar-nav-link-hover-color: #ffffff;\n  --sidebar-nav-link-active-bg: #663399;\n  --sidebar-nav-link-active-color: #ffffff;\n  --sidebar-nav-icon-color: #c2c7d0;\n  --sidebar-nav-icon-active-color: #ffffff;\n  --sidebar-brand-bg: #343a40;\n  --sidebar-brand-border: #4b545c;\n  --sidebar-brand-title-color: #b8c7ce;\n  --sidebar-brand-version-color: #b8c7ce;\n}\n\n/* Override Bootstrap 5 CSS variables for dark theme */\n[data-bs-theme=\"dark\"] {\n  --bs-body-bg: #1e282c;\n  --bs-body-color: #c2c7d0;\n  --bs-table-bg: transparent;\n  --bs-table-color: #c2c7d0;\n  --bs-card-bg: #343a40;\n  --bs-card-color: #c2c7d0;\n  --bs-border-color: #454d55;\n  --bs-primary: #663399;\n  --bs-primary-rgb: 102, 51, 153;\n  --bs-link-color: #a78bfa;\n  --bs-link-hover-color: #c4b5fd;\n}\n\n/* Apply theme variables to components */\n.log {\n  background: var(--log-bg) !important;\n  border: 1px solid var(--log-border) !important;\n  color: var(--log-color) !important;\n}\n\n.form-control {\n  background: var(--form-control-bg) !important;\n  border: 1px solid var(--form-control-border) !important;\n  color: var(--form-control-color) !important;\n}\n\n.log-filter {\n  background: var(--log-filter-bg) !important;\n  box-shadow: 4px -2px 5px 5px var(--log-filter-shadow) !important;\n}\n\n.app-main {\n  background: var(--app-main-bg) !important;\n  color: var(--app-main-color) !important;\n}\n\n.app-content {\n  background: var(--app-main-bg) !important;\n  color: var(--app-main-color) !important;\n}\n\n.app-content-header {\n  background: var(--app-content-header-bg) !important;\n  color: var(--app-content-header-color) !important;\n}\n\n.info-box {\n  background: var(--info-box-bg) !important;\n  color: var(--info-box-color) !important;\n}\n\n.info-box-text,\n.info-box-number {\n  color: var(--info-box-text-color) !important;\n}\n\n.card,\n.box {\n  background: var(--card-bg) !important;\n  color: var(--card-color) !important;\n  border-top-color: var(--card-border-top) !important;\n}\n\n.card-header,\n.box-header {\n  background: var(--card-header-bg) !important;\n  color: var(--card-header-color) !important;\n  border-bottom: 1px solid var(--card-header-border) !important;\n}\n\n.card-title,\n.box-title {\n  color: var(--card-header-color) !important;\n}\n\n.card-body,\n.box-body {\n  background: var(--card-body-bg) !important;\n  color: var(--card-body-color) !important;\n}\n\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  border-top: 1px solid var(--table-border) !important;\n  border-bottom: 1px solid var(--table-border) !important;\n  color: var(--table-color) !important;\n}\n\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid var(--table-border) !important;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n  background-color: var(--table-striped-bg) !important;\n}\n\n.well {\n  background: var(--well-bg) !important;\n  border: 1px solid var(--well-border) !important;\n  color: var(--well-color) !important;\n}\n\nsmall {\n  color: var(--small-color) !important;\n}\n\n.btn-default {\n  background-color: var(--btn-default-bg) !important;\n  border-color: var(--btn-default-border) !important;\n  color: var(--btn-default-color) !important;\n}\n\n.btn-default:hover {\n  background-color: var(--btn-default-hover-bg) !important;\n  border-color: var(--btn-default-hover-border) !important;\n}\n\n.btn-primary {\n  background-color: var(--btn-primary-bg) !important;\n  border-color: var(--btn-primary-border) !important;\n  color: var(--btn-primary-color) !important;\n}\n\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active {\n  background-color: var(--btn-primary-hover-bg) !important;\n  border-color: var(--btn-primary-hover-border) !important;\n  color: var(--btn-primary-color) !important;\n}\n\na {\n  color: var(--link-color) !important;\n}\n\na:hover {\n  color: var(--link-hover-color) !important;\n}\n\n/* Sidebar theming */\n.app-sidebar {\n  background-color: var(--sidebar-bg) !important;\n}\n\n.app-sidebar .sidebar {\n  background-color: var(--sidebar-bg) !important;\n}\n\n.nav-sidebar .nav-link {\n  color: var(--sidebar-nav-link-color) !important;\n}\n\n.nav-sidebar .nav-link:hover {\n  background-color: var(--sidebar-nav-link-hover-bg) !important;\n  color: var(--sidebar-nav-link-hover-color) !important;\n}\n\n.nav-sidebar .nav-link.active {\n  background-color: var(--sidebar-nav-link-active-bg) !important;\n  color: var(--sidebar-nav-link-active-color) !important;\n  margin-left: 0.5rem !important;\n  margin-right: 0.5rem !important;\n  border-radius: 0.25rem !important;\n}\n\n.nav-sidebar .nav-icon {\n  color: var(--sidebar-nav-icon-color) !important;\n}\n\n.nav-sidebar .nav-link.active .nav-icon {\n  color: var(--sidebar-nav-icon-active-color) !important;\n}\n\n.app-sidebar .brand-link {\n  background-color: var(--sidebar-brand-bg) !important;\n  border-bottom: 1px solid var(--sidebar-brand-border) !important;\n  padding: 15px !important;\n}\n\n.brand-title {\n  color: var(--sidebar-brand-title-color) !important;\n  font-weight: 500 !important;\n  margin-top: 5px !important;\n  margin-bottom: 0 !important;\n  font-size: 26px !important;\n}\n\n.brand-version {\n  color: var(--sidebar-brand-version-color) !important;\n  margin-top: 5px !important;\n  margin-bottom: 25px !important;\n}\n\n/* Bootstrap label/badge components - use purple theme */\n.label,\n.badge {\n  display: inline-block;\n  padding: 0.25em 0.6em;\n  font-size: 0.75rem;\n  font-weight: 600;\n  line-height: 1;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: 0.375rem;\n}\n\n.label-primary,\n.badge-primary {\n  background-color: #663399 !important;\n  color: #ffffff !important;\n}\n\n/* Bootstrap alert components */\n.alert-info {\n  background-color: #e7ddf7 !important;\n  border-color: #c4b5fd !important;\n  color: #4c2a85 !important;\n}\n\n/* Progress bars */\n.progress-bar-primary,\n.bg-primary {\n  background-color: #663399 !important;\n}\n\n/* Bootstrap 3 legacy classes for backwards compatibility */\n.pull-right {\n  float: right !important;\n}\n\n.pull-left {\n  float: left !important;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n\ndeclare module '*.png' {\n  const value: string;\n  export default value;\n}\n\ndeclare module '*.jpg' {\n  const value: string;\n  export default value;\n}\n\ndeclare module '*.jpeg' {\n  const value: string;\n  export default value;\n}\n\ndeclare module '*.svg' {\n  const value: string;\n  export default value;\n}\n\ndeclare module '*.gif' {\n  const value: string;\n  export default value;\n}\n\ndeclare module '*.webp' {\n  const value: string;\n  export default value;\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"isolatedModules\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noFallthroughCasesInSwitch\": true,\n\n    /* Paths */\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "src/Dashboard/Orleans.Dashboard.App/vite.config.ts",
    "content": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\nimport commonjs from \"vite-plugin-commonjs\";\nimport path from \"path\";\n\n// https://vite.dev/config/\nexport default defineConfig({\n  plugins: [commonjs(), react()],\n  base: \"./\",\n  resolve: {\n    alias: {\n      \"@\": path.resolve(__dirname, \"./src\"),\n    },\n  },\n  optimizeDeps: {\n    include: [\"react\", \"react-dom\"],\n  },\n  build: {\n    emptyOutDir: true,\n    sourcemap: true,\n    commonjsOptions: {\n      include: [/node_modules/, /src/],\n      transformMixedEsModules: true,\n    },\n    rollupOptions: {\n      output: {\n        manualChunks: undefined,\n        inlineDynamicImports: true,\n        entryFileNames: \"index.min.js\",\n        assetFileNames: (assetInfo) =>\n        {\n          if (assetInfo.name?.match(/\\.(woff|woff2|ttf|otf|eot)$/))\n          {\n            return \"fonts/[name][extname]\";\n          }\n          if (assetInfo.name?.match(/\\.(svg|png|jpg|jpeg|gif|webp|ico)$/))\n          {\n            return \"img/[name][extname]\";\n          }\n          return \"[name][extname]\";\n        },\n      },\n    },\n  },\n});\n"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project>\n  <PropertyGroup>\n    <_ParentDirectoryBuildPropsPath Condition=\"'$(_DirectoryBuildPropsFile)' != ''\">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildPropsFile)'))</_ParentDirectoryBuildPropsPath>\n  </PropertyGroup>\n\n  <Import Project=\"$(_ParentDirectoryBuildPropsPath)\" Condition=\"Exists('$(_ParentDirectoryBuildPropsPath)')\"/>\n\n  <PropertyGroup>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <CompatibilityTargetFrameworks>netstandard2.0</CompatibilityTargetFrameworks>\n    <DefaultTargetFrameworks>net8.0;net10.0</DefaultTargetFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <IsPackable>true</IsPackable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <ReadMePath>$(MSBuildProjectDirectory)\\README.md</ReadMePath>\n    <ReadMeExists Condition=\"Exists('$(ReadMePath)')\">true</ReadMeExists>\n    <PackageReadmeFile Condition=\"'$(PackageReadmeFile)' == '' And '$(ReadMeExists)' == 'true'\">README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <SourceLinkCreate>true</SourceLinkCreate>\n    <SourceLinkOriginUrl>https://github.com/dotnet/orleans</SourceLinkOriginUrl>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Include=\"Orleans.Metadata.FrameworkPartAttribute\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.DotNet.GenAPI.Task\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Directory.Build.targets",
    "content": "<Project>\n  <PropertyGroup>\n    <_ParentDirectoryBuildTargetsPath Condition=\"'$(_DirectoryBuildTargetsFile)' != ''\">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildTargetsFile)'))</_ParentDirectoryBuildTargetsPath>\n  </PropertyGroup>\n\n  <Import Project=\"$(_ParentDirectoryBuildTargetsPath)\" Condition=\"Exists('$(_ParentDirectoryBuildTargetsPath)')\"/>\n\n  <ItemGroup Condition=\"'$(IsPackable)'=='true' and '$(SourceLinkCreate)'=='true' and '$(IncludeBuildOutput)'=='true'\">\n    <PackageReference Include=\"Microsoft.SourceLink.AzureRepos.Git\" PrivateAssets=\"All\"/>\n    <PackageReference Include=\"Microsoft.SourceLink.GitHub\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <PropertyGroup>\n    <!-- Set DisableSourceLinkUrlTranslation to true when building a tool for internal use where sources only come from internal URIs -->\n    <DisableSourceLinkUrlTranslation Condition=\"'$(DisableSourceLinkUrlTranslation)' == ''\">false</DisableSourceLinkUrlTranslation>\n    <_TranslateUrlPattern>(https://.*\\.visualstudio\\.com/.*/_git/[^/]*)|(https://dev\\.azure\\.com/.*/_git/[^/]*)</_TranslateUrlPattern>\n    <_TranslateUrlReplacement>$(PublicRepositoryUrl)</_TranslateUrlReplacement>\n  </PropertyGroup>\n\n  <Target Name=\"_TranslateAzureDevOpsUrlToGitHubUrl\"\n          Condition=\"'$(DisableSourceLinkUrlTranslation)' == 'false'\"\n          DependsOnTargets=\"$(SourceControlManagerUrlTranslationTargets)\"\n          BeforeTargets=\"SourceControlManagerPublishTranslatedUrls\">\n\n    <PropertyGroup>\n      <ScmRepositoryUrl>$([System.Text.RegularExpressions.Regex]::Replace($(ScmRepositoryUrl), $(_TranslateUrlPattern), $(_TranslateUrlReplacement)))</ScmRepositoryUrl>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <SourceRoot Update=\"@(SourceRoot)\">\n        <ScmRepositoryUrl>$([System.Text.RegularExpressions.Regex]::Replace(%(SourceRoot.ScmRepositoryUrl), $(_TranslateUrlPattern), $(_TranslateUrlReplacement)))</ScmRepositoryUrl>\n      </SourceRoot>\n    </ItemGroup>\n  </Target>\n\n  <PropertyGroup>\n    <!-- If the project is packable, we generate its API surface in a separate file to be used by the API review process. -->\n    <GenAPITargetDirectory Condition=\"'$(IsPackable)' == 'true'\">$(MSBuildThisFileDirectory)/api/$([MSBuild]::MakeRelative($(MSBuildThisFileDirectory), $(MSBuildProjectDirectory)))/</GenAPITargetDirectory>\n    <GenAPITargetPath Condition=\"'$(IsPackable)' == 'true'\">$(GenAPITargetDirectory)$(AssemblyName).cs</GenAPITargetPath>\n  </PropertyGroup>\n\n  <Target Name=\"CreateGenAPITargetPathFolder\" BeforeTargets=\"GenAPIGenerateReferenceAssemblySource\">\n    <MakeDir Directories=\"$(GenAPITargetDirectory)\" Condition=\"!Exists('$(GenAPITargetDirectory)')\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Analyzers/AbstractPropertiesCannotBeSerializedAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Operations;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class AbstractPropertiesCannotBeSerializedAnalyzer : DiagnosticAnalyzer\n    {\n        public const string RuleId = \"ORLEANS0006\";\n        private const string Category = \"Usage\";\n        private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AbstractOrStaticMembersCannotBeSerializedTitle), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AbstractOrStaticMembersCannotBeSerializedMessageFormat), Resources.ResourceManager, typeof(Resources));\n\n        internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [Rule];\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.EnableConcurrentExecution();\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n            context.RegisterCompilationStartAction(context =>\n            {\n                var idAttribute = context.Compilation.GetTypeByMetadataName(\"Orleans.IdAttribute\");\n                var generateSerializerAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n                if (idAttribute is null || generateSerializerAttributeSymbol is null)\n                {\n                    return;\n                }\n\n                context.RegisterSymbolStartAction(context =>\n                {\n                    if (SerializationAttributesHelper.ShouldGenerateSerializer((INamedTypeSymbol)context.Symbol, generateSerializerAttributeSymbol))\n                    {\n                        context.RegisterOperationAction(context => AnalyzeAttribute(context, idAttribute), OperationKind.Attribute);\n                    }\n                }, SymbolKind.NamedType);\n            });\n        }\n\n        private static void AnalyzeAttribute(OperationAnalysisContext context, INamedTypeSymbol idAttribute)\n        {\n            var attributeOperation = (IAttributeOperation)context.Operation;\n            string modifier;\n            if (context.ContainingSymbol.IsAbstract)\n            {\n                modifier = \"abstract\";\n            }\n            else if (context.ContainingSymbol.IsStatic)\n            {\n                modifier = \"static\";\n            }\n            else\n            {\n                return;\n            }\n\n            if (attributeOperation.Operation is IObjectCreationOperation objectCreationOperation &&\n                idAttribute.Equals(objectCreationOperation.Constructor.ContainingType, SymbolEqualityComparer.Default))\n            {\n                context.ReportDiagnostic(Diagnostic.Create(Rule, attributeOperation.Syntax.GetLocation(), context.ContainingSymbol.Name, modifier));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/AliasClashAttributeAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Globalization;\n\nnamespace Orleans.Analyzers;\n\n[DiagnosticAnalyzer(LanguageNames.CSharp)]\npublic class AliasClashAttributeAnalyzer : DiagnosticAnalyzer\n{\n    private readonly record struct TypeAliasInfo(string TypeName, Location Location);\n\n    public const string RuleId = \"ORLEANS0011\";\n\n    private static readonly DiagnosticDescriptor Rule = new(\n        id: RuleId,\n        category: \"Usage\",\n        defaultSeverity: DiagnosticSeverity.Error,\n        isEnabledByDefault: true,\n        title: new LocalizableResourceString(nameof(Resources.AliasClashDetectedTitle), Resources.ResourceManager, typeof(Resources)),\n        messageFormat: new LocalizableResourceString(nameof(Resources.AliasClashDetectedMessageFormat), Resources.ResourceManager, typeof(Resources)),\n        description: new LocalizableResourceString(nameof(Resources.AliasClashDetectedDescription), Resources.ResourceManager, typeof(Resources)),\n        helpLinkUri: null,\n        customTags: [WellKnownDiagnosticTags.CompilationEnd]);\n\n    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [Rule];\n\n    public override void Initialize(AnalysisContext context)\n    {\n        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n\n        context.EnableConcurrentExecution();\n\n        context.RegisterCompilationStartAction(context =>\n        {\n            var aliasMap = new ConcurrentDictionary<string, ConcurrentBag<TypeAliasInfo>>();\n            var aliasAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.AliasAttribute\");\n            context.RegisterSymbolAction(\n                context => CollectTypeAliases(context, aliasMap, aliasAttributeSymbol),\n                SymbolKind.NamedType);\n\n            // We can immediately check duplicate method‐aliases in grain interfaces.\n            context.RegisterSymbolAction(\n                context => CheckMethodAliases(context, aliasMap, aliasAttributeSymbol),\n                SymbolKind.NamedType);\n\n            // Only at the very end, we do one single‐threaded scan for type‐alias clashes only.\n            context.RegisterCompilationEndAction(context =>\n            {\n                foreach (var kvp in aliasMap)\n                {\n                    var alias = kvp.Key;\n                    var infos = kvp.Value;\n\n                    var distinctTypes = infos\n                        .Select(i => i.TypeName)\n                        .Distinct()\n                        .ToList();\n\n                    if (distinctTypes.Count <= 1)\n                    {\n                        continue; // If more than one different type claimed it.\n                    }\n\n                    var firstType = distinctTypes[0];\n                    foreach (var info in infos.Where(i => i.TypeName != firstType))\n                    {\n                        context.ReportDiagnostic(Diagnostic.Create(Rule, info.Location, alias, firstType));\n                    }\n                }\n            });\n        });\n    }\n\n    private static void CollectTypeAliases(\n        SymbolAnalysisContext context,\n        ConcurrentDictionary<string, ConcurrentBag<TypeAliasInfo>> aliasMap,\n        INamedTypeSymbol aliasAttributeSymbol)\n    {\n        var typeSymbol = (INamedTypeSymbol)context.Symbol;\n        \n        if (typeSymbol.TypeKind == TypeKind.Interface && !typeSymbol.ExtendsGrainInterface())\n        {\n            return; // Skip interfaces that dont extend IAddressable\n        }\n\n        foreach (var attr in typeSymbol.GetAttributes())\n        {\n            if (!aliasAttributeSymbol.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))\n                continue;\n\n            var alias = attr.ConstructorArguments.FirstOrDefault().Value as string;\n            if (string.IsNullOrEmpty(alias))\n                continue;\n\n            var info = new TypeAliasInfo(typeSymbol.ToDisplayString(), attr.ApplicationSyntaxReference.GetSyntax().GetLocation());\n\n            aliasMap.AddOrUpdate(\n                key: alias,\n                addValueFactory: _ => new ConcurrentBag<TypeAliasInfo>([info]),\n                updateValueFactory: (_, bag) =>\n                {\n                    bag.Add(info);\n                    return bag;\n                });\n        }\n    }\n\n    private static void CheckMethodAliases(\n        SymbolAnalysisContext context,\n        ConcurrentDictionary<string, ConcurrentBag<TypeAliasInfo>> aliasMap,\n        INamedTypeSymbol aliasAttributeSymbol)\n    {\n        if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Interface } interfaceSymbol)\n        {\n            return;\n        }\n\n        var methodBags = new List<(string Alias, Location Location)>();\n\n        foreach (var method in interfaceSymbol.GetMembers().OfType<IMethodSymbol>())\n        {\n            foreach (var attr in method.GetAttributes())\n            {\n                if (!aliasAttributeSymbol.Equals(attr.AttributeClass, SymbolEqualityComparer.Default))\n                {\n                    continue;\n                }\n\n                var alias = attr.ConstructorArguments.FirstOrDefault().Value as string;\n                if (!string.IsNullOrEmpty(alias))\n                {\n                    methodBags.Add((alias, attr.ApplicationSyntaxReference.GetSyntax().GetLocation()));\n                }\n            }\n        }\n\n        // Find duplicate aliases within the interface's methods.\n        var duplicateMethodAliases = methodBags\n            .GroupBy(x => x.Alias)\n            .Where(g => g.Count() > 1);\n\n        foreach (var group in duplicateMethodAliases)\n        {\n            var duplicates = group.Skip(1).ToList();\n            var (prefix, suffix) = ParsePrefixAndNumericSuffix(group.Key);\n\n            foreach (var duplicate in duplicates)\n            {\n                string newAlias;\n                do\n                {\n                    suffix++;\n                    newAlias = $\"{prefix}{suffix}\";\n                }\n                while (aliasMap.ContainsKey(newAlias) || methodBags.Any(b => b.Alias == newAlias));\n\n                var properties = ImmutableDictionary.CreateBuilder<string, string>();\n\n                properties.Add(\"AliasName\", prefix);\n                properties.Add(\"AliasSuffix\", suffix.ToString(CultureInfo.InvariantCulture));\n\n                context.ReportDiagnostic(Diagnostic.Create(Rule, duplicate.Location, properties, group.Key));\n            }\n        }\n    }\n\n    private static (string Prefix, ulong Suffix) ParsePrefixAndNumericSuffix(string input)\n    {\n        var suffixLength = GetNumericSuffixLength(input);\n        if (suffixLength == 0)\n        {\n            return (input, 0);\n        }\n\n        return (\n            input.Substring(0, input.Length - suffixLength),\n            ulong.Parse(input.Substring(input.Length - suffixLength), CultureInfo.InvariantCulture)\n        );\n    }\n\n    private static int GetNumericSuffixLength(string input)\n    {\n        var suffixLength = 0;\n        for (var i = input.Length - 1; i >= 0; --i)\n        {\n            if (!char.IsDigit(input[i]))\n                break;\n            suffixLength++;\n        }\n        return suffixLength;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/AliasClashAttributeCodeFix.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Collections.Immutable;\nusing System.Composition;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Threading;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers;\n\n[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(GenerateAliasAttributesCodeFix)), Shared]\npublic class AliasClashAttributeCodeFix : CodeFixProvider\n{\n    public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(AliasClashAttributeAnalyzer.RuleId);\n    public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n    public override async Task RegisterCodeFixesAsync(CodeFixContext context)\n    {\n        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);\n        var diagnostic = context.Diagnostics.First();\n\n        if (root.FindNode(diagnostic.Location.SourceSpan) is not AttributeSyntax attribute)\n        {\n            return;\n        }\n\n        if (!diagnostic.Properties.TryGetValue(\"AliasName\", out var aliasName))\n        {\n            return;\n        }\n\n        if (!diagnostic.Properties.TryGetValue(\"AliasSuffix\", out var aliasSuffix))\n        {\n            return;\n        }\n\n        context.RegisterCodeFix(\n            CodeAction.Create(\n                Resources.AliasClashDetectedTitle,\n                createChangedDocument: _ =>\n                {\n                    var newAliasName = $\"{aliasName}{aliasSuffix}\";\n                    var newAttribute = attribute.ReplaceNode(\n                        attribute.ArgumentList.Arguments[0].Expression,\n                        LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(newAliasName)));\n\n                    var newRoot = root.ReplaceNode(attribute, newAttribute);\n                    var newDocument = context.Document.WithSyntaxRoot(newRoot);\n\n                    return Task.FromResult(newDocument);\n                },\n                equivalenceKey: AliasClashAttributeAnalyzer.RuleId),\n            diagnostic);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/AlwaysInterleaveDiagnosticAnalyzer.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class AlwaysInterleaveDiagnosticAnalyzer : DiagnosticAnalyzer\n    {\n        private const string AlwaysInterleaveAttributeName = \"Orleans.Concurrency.AlwaysInterleaveAttribute\";\n\n        public const string DiagnosticId = \"ORLEANS0001\";\n        public const string Title = \"[AlwaysInterleave] must only be used on the grain interface method and not the grain class method\";\n        public const string MessageFormat = Title;\n        public const string Category = \"Usage\";\n\n        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);\n            context.EnableConcurrentExecution();\n            context.RegisterCompilationStartAction(context =>\n            {\n                var alwaysInterleaveAttributeSymbol = context.Compilation.GetTypeByMetadataName(AlwaysInterleaveAttributeName);\n                if (alwaysInterleaveAttributeSymbol is not null)\n                {\n                    context.RegisterSymbolAction(context => AnalyzeMethod(context, alwaysInterleaveAttributeSymbol), SymbolKind.Method);\n                }\n            });\n        }\n\n        private static void AnalyzeMethod(SymbolAnalysisContext context, INamedTypeSymbol alwaysInterleaveAttribute)\n        {\n            var methodSymbol = (IMethodSymbol)context.Symbol;\n\n            if (methodSymbol.ContainingType.TypeKind == TypeKind.Interface)\n            {\n                // TODO: Check that interface inherits from IGrain\n                return;\n            }\n\n            foreach (var attribute in methodSymbol.GetAttributes())\n            {\n                if (!SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, alwaysInterleaveAttribute))\n                {\n                    return;\n                }\n\n                var syntaxReference = attribute.ApplicationSyntaxReference;\n\n                context.ReportDiagnostic(\n                    Diagnostic.Create(Rule, Location.Create(syntaxReference.SyntaxTree, syntaxReference.Span)));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/AnalyzerReleases.Shipped.md",
    "content": "## Release 3.3.0\n\n### New Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|--------------------\nORLEANS0003  | Usage   | Error  | Inherit from Grain\n\n## Release 7.0.0\n\n### New Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|--------------------\nORLEANS0001  | Usage   | Error  | [AlwaysInterleave] must only be used on the grain interface method and not the grain class method\nORLEANS0002  | Usage   | Error  | Reference parameter modifiers are not allowed\nORLEANS0004  | Usage   | Error  | Add serialization [Id] and [NonSerialized] attributes\nORLEANS0005  | Usage   | Info   | Add [GenerateSerializer] attribute to [Serializable] type\nORLEANS0006  | Usage   | Error  | Abstract/serialized properties cannot be serialized\nORLEANS0007  | Usage   | Error  | \nORLEANS0008  | Usage   | Error  | Grain interfaces cannot have properties\nORLEANS0009  | Usage   | Error  | Grain interface methods must return a compatible type\nORLEANS0010  | Usage   | Info   | Add missing [Alias] attribute\nORLEANS0011  | Usage   | Error  | The [Alias] attribute must be unique to the declaring type\nORLEANS0012  | Usage   | Error  | The [Id] attribute must be unique to each members of the declaring type\nORLEANS0013  | Usage   | Error  | This attribute should not be used on grain implementations\n\n### Removed Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|--------------------\nORLEANS0003  | Usage   | Error  | Inherit from Grain\n"
  },
  {
    "path": "src/Orleans.Analyzers/AnalyzerReleases.Unshipped.md",
    "content": "; Please do not edit this file manually, it should only be updated through code fix application.\n\n### New Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|-------\nORLEANS0014 | Usage | Warning | ConfigureAwaitAnalyzer, Grain code should not use ConfigureAwait(false) or ConfigureAwait without ContinueOnCapturedContext\n"
  },
  {
    "path": "src/Orleans.Analyzers/AtMostOneOrleansConstructorAnalyzer.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class AtMostOneOrleansConstructorAnalyzer : DiagnosticAnalyzer\n    {\n        public const string RuleId = \"ORLEANS0007\";\n        private const string Category = \"Usage\";\n        private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AtMostOneOrleansConstructorTitle), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AtMostOneOrleansConstructorMessageFormat), Resources.ResourceManager, typeof(Resources));\n\n        internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.EnableConcurrentExecution();\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n            context.RegisterCompilationStartAction(context =>\n            {\n                var generateSerializerAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n                if (generateSerializerAttributeSymbol is not null)\n                {\n                    context.RegisterSymbolAction(context => AnalyzeNamedType(context, generateSerializerAttributeSymbol), SymbolKind.NamedType);\n                }\n            });\n        }\n\n        private void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol generateSerializerAttributeSymbol)\n        {\n            var symbol = (INamedTypeSymbol)context.Symbol;\n            if (SerializationAttributesHelper.ShouldGenerateSerializer(symbol, generateSerializerAttributeSymbol))\n            {\n                var foundAttribute = false;\n                foreach (var constructor in symbol.Constructors)\n                {\n                    if (constructor.HasAttribute(generateSerializerAttributeSymbol))\n                    {\n                        if (foundAttribute)\n                        {\n                            context.ReportDiagnostic(Diagnostic.Create(Rule, symbol.Locations[0]));\n                            return;\n                        }\n\n                        foundAttribute = true;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/ConfigureAwaitAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Analyzers;\n\n/// <summary>\n/// An analyzer that warns when grain code uses ConfigureAwait(false) or ConfigureAwait(ConfigureAwaitOptions)\n/// without the ContinueOnCapturedContext flag.\n/// </summary>\n[DiagnosticAnalyzer(LanguageNames.CSharp)]\npublic class ConfigureAwaitAnalyzer : DiagnosticAnalyzer\n{\n    public const string RuleId = \"ORLEANS0014\";\n\n    private static readonly LocalizableString Title = new LocalizableResourceString(\n        nameof(Resources.AvoidConfigureAwaitFalseInGrainTitle),\n        Resources.ResourceManager,\n        typeof(Resources));\n\n    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(\n        nameof(Resources.AvoidConfigureAwaitFalseInGrainMessageFormat),\n        Resources.ResourceManager,\n        typeof(Resources));\n\n    private static readonly LocalizableString Description = new LocalizableResourceString(\n        nameof(Resources.AvoidConfigureAwaitFalseInGrainDescription),\n        Resources.ResourceManager,\n        typeof(Resources));\n\n    private static readonly DiagnosticDescriptor Rule = new(\n        id: RuleId,\n        title: Title,\n        messageFormat: MessageFormat,\n        category: \"Usage\",\n        defaultSeverity: DiagnosticSeverity.Warning,\n        isEnabledByDefault: true,\n        description: Description);\n\n    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n    public override void Initialize(AnalysisContext context)\n    {\n        context.EnableConcurrentExecution();\n        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);\n        context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression);\n    }\n\n    private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)\n    {\n        var invocation = (InvocationExpressionSyntax)context.Node;\n\n        // Check if this is a ConfigureAwait call\n        if (!IsConfigureAwaitCall(invocation, out var methodName))\n        {\n            return;\n        }\n\n        // Check if this code is inside a grain class\n        if (!IsInsideGrainClass(invocation, context.SemanticModel))\n        {\n            return;\n        }\n\n        // Get the symbol for the invocation to analyze the argument\n        var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken);\n        if (symbolInfo.Symbol is not IMethodSymbol methodSymbol)\n        {\n            return;\n        }\n\n        // Only check ConfigureAwait method\n        if (!string.Equals(methodSymbol.Name, \"ConfigureAwait\", StringComparison.Ordinal))\n        {\n            return;\n        }\n\n        // Check if it's a ConfigureAwait method on a Task-like type\n        var containingType = methodSymbol.ContainingType;\n        if (!IsTaskLikeType(containingType))\n        {\n            return;\n        }\n\n        // Get the arguments\n        var arguments = invocation.ArgumentList?.Arguments;\n        if (arguments is null || arguments.Value.Count == 0)\n        {\n            return;\n        }\n\n        var firstArgument = arguments.Value[0];\n        var argumentType = context.SemanticModel.GetTypeInfo(firstArgument.Expression, context.CancellationToken).Type;\n\n        if (argumentType is null)\n        {\n            return;\n        }\n\n        // Check for ConfigureAwait(bool) overload\n        if (argumentType.SpecialType == SpecialType.System_Boolean)\n        {\n            var constantValue = context.SemanticModel.GetConstantValue(firstArgument.Expression, context.CancellationToken);\n            if (constantValue.HasValue && constantValue.Value is false)\n            {\n                // ConfigureAwait(false) is not allowed\n                context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation()));\n            }\n            return;\n        }\n\n        // Check for ConfigureAwait(ConfigureAwaitOptions) overload\n        if (IsConfigureAwaitOptionsType(argumentType))\n        {\n            if (!HasContinueOnCapturedContextFlag(firstArgument.Expression, context.SemanticModel, context.CancellationToken))\n            {\n                context.ReportDiagnostic(Diagnostic.Create(Rule, invocation.GetLocation()));\n            }\n        }\n    }\n\n    private static bool IsConfigureAwaitCall(InvocationExpressionSyntax invocation, out string methodName)\n    {\n        methodName = null;\n\n        if (invocation.Expression is MemberAccessExpressionSyntax memberAccess)\n        {\n            methodName = memberAccess.Name.Identifier.Text;\n            return string.Equals(methodName, \"ConfigureAwait\", StringComparison.Ordinal);\n        }\n\n        return false;\n    }\n\n    private static bool IsInsideGrainClass(SyntaxNode node, SemanticModel semanticModel)\n    {\n        // Walk up to find the containing type declaration\n        var current = node.Parent;\n        while (current is not null)\n        {\n            if (current is ClassDeclarationSyntax classDeclaration)\n            {\n                var typeSymbol = semanticModel.GetDeclaredSymbol(classDeclaration);\n                if (typeSymbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGrainClass())\n                {\n                    return true;\n                }\n            }\n            else if (current is StructDeclarationSyntax or RecordDeclarationSyntax)\n            {\n                // If we hit a struct or record before finding a grain class, we're not in a grain\n                // (structs and records can't be grains)\n                return false;\n            }\n\n            current = current.Parent;\n        }\n\n        return false;\n    }\n\n    private static bool IsTaskLikeType(INamedTypeSymbol type)\n    {\n        if (type is null)\n        {\n            return false;\n        }\n\n        var fullName = type.ToDisplayString(NullableFlowState.None);\n\n        // Check for common task-like types that have ConfigureAwait\n        return fullName.StartsWith(\"System.Threading.Tasks.Task\", StringComparison.Ordinal)\n            || fullName.StartsWith(\"System.Threading.Tasks.ValueTask\", StringComparison.Ordinal)\n            || fullName.StartsWith(\"System.Runtime.CompilerServices.ConfiguredTaskAwaitable\", StringComparison.Ordinal)\n            || fullName.StartsWith(\"System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable\", StringComparison.Ordinal)\n            || fullName.StartsWith(\"System.Collections.Generic.IAsyncEnumerable\", StringComparison.Ordinal)\n            || fullName.StartsWith(\"System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable\", StringComparison.Ordinal);\n    }\n\n    private static bool IsConfigureAwaitOptionsType(ITypeSymbol type)\n    {\n        if (type is null)\n        {\n            return false;\n        }\n\n        return string.Equals(\n            type.ToDisplayString(NullableFlowState.None),\n            \"System.Threading.Tasks.ConfigureAwaitOptions\",\n            StringComparison.Ordinal);\n    }\n\n    private static bool HasContinueOnCapturedContextFlag(ExpressionSyntax expression, SemanticModel semanticModel, System.Threading.CancellationToken cancellationToken)\n    {\n        // ConfigureAwaitOptions.ContinueOnCapturedContext has value 1\n        const int ContinueOnCapturedContextValue = 1;\n\n        // Try to get the constant value\n        var constantValue = semanticModel.GetConstantValue(expression, cancellationToken);\n        if (constantValue.HasValue && constantValue.Value is int intValue)\n        {\n            // Check if ContinueOnCapturedContext flag (value 1) is set\n            return (intValue & ContinueOnCapturedContextValue) != 0;\n        }\n\n        // If we can't determine the value at compile time, we need to analyze the expression\n        // to check if it includes ContinueOnCapturedContext\n        return ExpressionIncludesContinueOnCapturedContext(expression, semanticModel, cancellationToken);\n    }\n\n    private static bool ExpressionIncludesContinueOnCapturedContext(ExpressionSyntax expression, SemanticModel semanticModel, System.Threading.CancellationToken cancellationToken)\n    {\n        // Handle member access like ConfigureAwaitOptions.ContinueOnCapturedContext\n        if (expression is MemberAccessExpressionSyntax memberAccess)\n        {\n            var memberName = memberAccess.Name.Identifier.Text;\n            if (string.Equals(memberName, \"ContinueOnCapturedContext\", StringComparison.Ordinal))\n            {\n                return true;\n            }\n        }\n\n        // Handle binary OR expressions like ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding\n        if (expression is BinaryExpressionSyntax binaryExpression &&\n            binaryExpression.IsKind(SyntaxKind.BitwiseOrExpression))\n        {\n            return ExpressionIncludesContinueOnCapturedContext(binaryExpression.Left, semanticModel, cancellationToken)\n                || ExpressionIncludesContinueOnCapturedContext(binaryExpression.Right, semanticModel, cancellationToken);\n        }\n\n        // Handle parenthesized expressions\n        if (expression is ParenthesizedExpressionSyntax parenthesized)\n        {\n            return ExpressionIncludesContinueOnCapturedContext(parenthesized.Expression, semanticModel, cancellationToken);\n        }\n\n        // Handle cast expressions\n        if (expression is CastExpressionSyntax castExpression)\n        {\n            return ExpressionIncludesContinueOnCapturedContext(castExpression.Expression, semanticModel, cancellationToken);\n        }\n\n        // If we encounter a variable or method call, we can't statically determine the flags\n        // In this case, we give the benefit of the doubt and don't report\n        if (expression is IdentifierNameSyntax or InvocationExpressionSyntax)\n        {\n            // Try to get the constant value as a fallback\n            var constantValue = semanticModel.GetConstantValue(expression, cancellationToken);\n            if (constantValue.HasValue && constantValue.Value is int intValue)\n            {\n                const int ContinueOnCapturedContextValue = 1;\n                return (intValue & ContinueOnCapturedContextValue) != 0;\n            }\n\n            // Can't determine - don't report false positives\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/ConfigureAwaitCodeFix.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Immutable;\nusing System.Composition;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers;\n\n/// <summary>\n/// A code fix provider that converts ConfigureAwait(false) to ConfigureAwait(true) and\n/// adds ContinueOnCapturedContext to ConfigureAwait(ConfigureAwaitOptions) calls.\n/// </summary>\n[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ConfigureAwaitCodeFix)), Shared]\npublic class ConfigureAwaitCodeFix : CodeFixProvider\n{\n    public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(ConfigureAwaitAnalyzer.RuleId);\n    public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)\n    {\n        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);\n        var diagnostic = context.Diagnostics.First();\n        var diagnosticSpan = diagnostic.Location.SourceSpan;\n\n        // Find the invocation expression identified by the diagnostic\n        var node = root.FindNode(diagnosticSpan);\n        var invocation = node.FirstAncestorOrSelf<InvocationExpressionSyntax>();\n\n        if (invocation is null)\n        {\n            return;\n        }\n\n        // Get semantic model to determine which fix to apply\n        var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);\n        var symbolInfo = semanticModel.GetSymbolInfo(invocation, context.CancellationToken);\n\n        if (symbolInfo.Symbol is not IMethodSymbol methodSymbol)\n        {\n            return;\n        }\n\n        // Check the parameter type to determine which fix to apply\n        if (methodSymbol.Parameters.Length == 1)\n        {\n            var parameterType = methodSymbol.Parameters[0].Type;\n\n            if (parameterType.SpecialType == SpecialType.System_Boolean)\n            {\n                // Fix for ConfigureAwait(bool) - change false to true\n                context.RegisterCodeFix(\n                    CodeAction.Create(\n                        title: Resources.ConfigureAwaitCodeFixTitle,\n                        createChangedDocument: ct => FixConfigureAwaitBoolAsync(context.Document, invocation, ct),\n                        equivalenceKey: ConfigureAwaitAnalyzer.RuleId + \"_Bool\"),\n                    diagnostic);\n            }\n            else if (string.Equals(parameterType.ToDisplayString(), \"System.Threading.Tasks.ConfigureAwaitOptions\", StringComparison.Ordinal))\n            {\n                // Fix for ConfigureAwait(ConfigureAwaitOptions) - add ContinueOnCapturedContext flag\n                context.RegisterCodeFix(\n                    CodeAction.Create(\n                        title: Resources.ConfigureAwaitCodeFixTitle,\n                        createChangedDocument: ct => FixConfigureAwaitOptionsAsync(context.Document, invocation, semanticModel, ct),\n                        equivalenceKey: ConfigureAwaitAnalyzer.RuleId + \"_Options\"),\n                    diagnostic);\n            }\n        }\n    }\n\n    private static async Task<Document> FixConfigureAwaitBoolAsync(\n        Document document,\n        InvocationExpressionSyntax invocation,\n        CancellationToken cancellationToken)\n    {\n        var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);\n\n        // Create new argument with 'true' instead of 'false'\n        var newArgument = Argument(LiteralExpression(SyntaxKind.TrueLiteralExpression));\n        var newArgumentList = ArgumentList(SingletonSeparatedList(newArgument));\n\n        // Replace the argument list\n        var newInvocation = invocation.WithArgumentList(newArgumentList);\n        var newRoot = root.ReplaceNode(invocation, newInvocation);\n\n        return document.WithSyntaxRoot(newRoot);\n    }\n\n    private static async Task<Document> FixConfigureAwaitOptionsAsync(\n        Document document,\n        InvocationExpressionSyntax invocation,\n        SemanticModel semanticModel,\n        CancellationToken cancellationToken)\n    {\n        var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);\n\n        var arguments = invocation.ArgumentList?.Arguments;\n        if (arguments is null || arguments.Value.Count == 0)\n        {\n            return document;\n        }\n\n        var existingArgument = arguments.Value[0].Expression;\n\n        // Check if the existing argument is ConfigureAwaitOptions.None\n        var constantValue = semanticModel.GetConstantValue(existingArgument, cancellationToken);\n        ExpressionSyntax newExpression;\n\n        if (constantValue.HasValue && constantValue.Value is int intValue && intValue == 0)\n        {\n            // If it's None (0), just replace with ContinueOnCapturedContext\n            newExpression = MemberAccessExpression(\n                SyntaxKind.SimpleMemberAccessExpression,\n                IdentifierName(\"ConfigureAwaitOptions\"),\n                IdentifierName(\"ContinueOnCapturedContext\"));\n        }\n        else\n        {\n            // Otherwise, add ContinueOnCapturedContext using bitwise OR\n            var continueOnCapturedContext = MemberAccessExpression(\n                SyntaxKind.SimpleMemberAccessExpression,\n                IdentifierName(\"ConfigureAwaitOptions\"),\n                IdentifierName(\"ContinueOnCapturedContext\"));\n\n            newExpression = BinaryExpression(\n                SyntaxKind.BitwiseOrExpression,\n                existingArgument.WithoutTrivia(),\n                continueOnCapturedContext);\n        }\n\n        var newArgument = Argument(newExpression);\n        var newArgumentList = ArgumentList(SingletonSeparatedList(newArgument));\n\n        var newInvocation = invocation.WithArgumentList(newArgumentList);\n        var newRoot = root.ReplaceNode(invocation, newInvocation);\n\n        return document.WithSyntaxRoot(newRoot);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/Constants.cs",
    "content": "namespace Orleans.Analyzers\n{\n    internal static class Constants\n    {\n        public const string SystemNamespace = \"System\";\n\n        public const string IAddressibleFullyQualifiedName = \"Orleans.Runtime.IAddressable\";\n        public const string GrainBaseFullyQualifiedName = \"Orleans.Grain\";\n        public const string IGrainBaseFullyQualifiedName = \"Orleans.IGrainBase\";\n        public const string IGrainFullyQualifiedName = \"Orleans.IGrain\";\n        public const string ISystemTargetFullyQualifiedName = \"Orleans.ISystemTarget\";\n\n        public const string IdAttributeName = \"Id\";\n        public const string IdAttributeFullyQualifiedName = \"global::Orleans.IdAttribute\";\n\n        public const string GenerateSerializerAttributeName = \"GenerateSerializer\";\n        public const string GenerateSerializerAttributeFullyQualifiedName = \"global::Orleans.GenerateSerializerAttribute\";\n\n        public const string SerializableAttributeName = \"Serializable\";\n\n        public const string NonSerializedAttribute = \"NonSerialized\";\n        public const string NonSerializedAttributeFullyQualifiedName = \"global::System.NonSerializedAttribute\";\n      \n        public const string AliasAttributeName = \"Alias\";\n        public const string AliasAttributeFullyQualifiedName = \"global::Orleans.AliasAttribute\"; \n    }\n}"
  },
  {
    "path": "src/Orleans.Analyzers/GenerateAliasAttributesAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text;\n\nnamespace Orleans.Analyzers;\n\n[DiagnosticAnalyzer(LanguageNames.CSharp)]\npublic class GenerateAliasAttributesAnalyzer : DiagnosticAnalyzer\n{\n    public const string RuleId = \"ORLEANS0010\";\n    private const string Category = \"Usage\";\n    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AddAliasAttributesTitle), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AddAliasMessageFormat), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AddAliasAttributesDescription), Resources.ResourceManager, typeof(Resources));\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description);\n\n    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n    public override void Initialize(AnalysisContext context)\n    {\n        context.EnableConcurrentExecution();\n        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n        context.RegisterCompilationStartAction(context =>\n        {\n            var aliasAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.AliasAttribute\");\n            var generateSerializerAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n            var grainSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.Grain\");\n            if (aliasAttributeSymbol is not null && generateSerializerAttributeSymbol is not null)\n            {\n                context.RegisterSymbolAction(context => AnalyzeNamedType(context, aliasAttributeSymbol, generateSerializerAttributeSymbol, grainSymbol), SymbolKind.NamedType);\n            }\n        });\n    }\n\n    private void AnalyzeNamedType(\n        SymbolAnalysisContext context,\n        INamedTypeSymbol aliasAttributeSymbol,\n        INamedTypeSymbol generateSerializerAttributeSymbol,\n        INamedTypeSymbol grainSymbol)\n    {\n        var symbol = (INamedTypeSymbol)context.Symbol;\n\n        // Interface types and their methods\n        if (symbol.TypeKind == TypeKind.Interface)\n        {\n            if (!symbol.ExtendsGrainInterface())\n            {\n                return;\n            }\n\n            if (!symbol.HasAttribute(aliasAttributeSymbol))\n            {\n                if (!TryGetDeclarationSyntax(symbol, out InterfaceDeclarationSyntax interfaceDeclaration))\n                {\n                    return;\n                }\n\n                ReportFor(\n                    context,\n                    interfaceDeclaration.GetLocation(),\n                    interfaceDeclaration.Identifier.ToString(),\n                    GetArity(interfaceDeclaration),\n                    GetNamespaceAndNesting(interfaceDeclaration));\n            }\n\n            foreach (var methodSymbol in symbol.GetMembers().OfType<IMethodSymbol>())\n            {\n                if (methodSymbol.IsStatic)\n                {\n                    continue;\n                }\n\n                if (!methodSymbol.HasAttribute(aliasAttributeSymbol))\n                {\n                    if (!TryGetDeclarationSyntax(methodSymbol, out MethodDeclarationSyntax methodDeclaration))\n                    {\n                        continue;\n                    }\n\n                    ReportFor(context, methodDeclaration.GetLocation(), methodSymbol.Name, arity: 0, namespaceAndNesting: null);\n                }\n            }\n\n            return;\n        }\n\n        // Rest of types: class, struct, record\n        if (symbol.TypeKind is TypeKind.Class or TypeKind.Struct)\n        {\n            if (symbol.DerivesFrom(grainSymbol))\n            {\n                return;\n            }\n\n            if (!symbol.HasAttribute(generateSerializerAttributeSymbol))\n            {\n                return;\n            }\n\n            if (symbol.HasAttribute(aliasAttributeSymbol))\n            {\n                return;\n            }\n\n            if (!TryGetDeclarationSyntax(symbol, out TypeDeclarationSyntax typeDeclaration))\n            {\n                return;\n            }\n\n            ReportFor(\n                context,\n                typeDeclaration.GetLocation(),\n                typeDeclaration.Identifier.ToString(),\n                GetArity(typeDeclaration),\n                GetNamespaceAndNesting(typeDeclaration));\n        }\n    }\n\n    private static int GetArity(TypeDeclarationSyntax typeDeclarationSyntax)\n    {\n        var node = typeDeclarationSyntax;\n        int arity = 0;\n        while (node is TypeDeclarationSyntax type)\n        {\n            arity += type.Arity;\n            node = type.Parent as TypeDeclarationSyntax;\n        }\n\n        return arity;\n    }\n\n    private static string GetNamespaceAndNesting(TypeDeclarationSyntax typeDeclarationSyntax)\n    {\n        SyntaxNode node = typeDeclarationSyntax.Parent;\n        StringBuilder sb = new();\n        Stack<string> segments = new();\n\n        while (node is not null)\n        {\n            if (node is TypeDeclarationSyntax type)\n            {\n                segments.Push(type.Identifier.ToString());\n            }\n            else if (node is BaseNamespaceDeclarationSyntax ns)\n            {\n                segments.Push(ns.Name.ToString());\n            }\n\n            node = node.Parent;\n        }\n\n        foreach (var segment in segments)\n        {\n            if (sb.Length > 0)\n            {\n                sb.Append('.');\n            }\n\n            sb.Append(segment);\n        }\n\n        return sb.ToString();\n    }\n\n    private static bool TryGetDeclarationSyntax<TSyntax>(ISymbol symbol, out TSyntax syntax)\n        where TSyntax : SyntaxNode\n    {\n        syntax = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() as TSyntax;\n        return syntax is not null;\n    }\n\n    private static void ReportFor(SymbolAnalysisContext context, Location location, string typeName, int arity, string namespaceAndNesting)\n    {\n        var builder = ImmutableDictionary.CreateBuilder<string, string>();\n\n        builder.Add(\"TypeName\", typeName);\n        builder.Add(\"NamespaceAndNesting\", namespaceAndNesting);\n        builder.Add(\"Arity\", arity.ToString(System.Globalization.CultureInfo.InvariantCulture));\n\n        context.ReportDiagnostic(Diagnostic.Create(\n            descriptor: Rule,\n            location: location,\n            properties: builder.ToImmutable()));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GenerateAliasAttributesCodeFix.cs",
    "content": "using System.Collections.Immutable;\nusing System.Threading.Tasks;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing System.Composition;\nusing Microsoft.CodeAnalysis.Editing;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Simplification;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers;\n\n[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(GenerateAliasAttributesCodeFix)), Shared]\npublic class GenerateAliasAttributesCodeFix : CodeFixProvider\n{\n    public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(GenerateAliasAttributesAnalyzer.RuleId);\n    public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n    public override async Task RegisterCodeFixesAsync(CodeFixContext context)\n    {\n        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);\n\n        foreach (var diagnostic in context.Diagnostics)\n        {\n            var node = root.FindNode(diagnostic.Location.SourceSpan);\n            if (node != null)\n            {\n                // Check if its an interface method\n                var methodDeclaration = node.FirstAncestorOrSelf<MethodDeclarationSyntax>();\n                if (methodDeclaration != null)\n                {\n                    await FixFor(context, diagnostic, methodDeclaration);\n                    continue;\n                }\n\n                // Check if its a type declaration (interface itself, class, struct, record)\n                var typeDeclaration = node.FirstAncestorOrSelf<TypeDeclarationSyntax>();\n                if (typeDeclaration != null)\n                {\n                    await FixFor(context, diagnostic, typeDeclaration);\n                    continue;\n                }\n            }\n        }\n    }\n\n    private static async Task FixFor(CodeFixContext context, Diagnostic diagnostic, SyntaxNode declaration)\n    {\n        var documentEditor = await DocumentEditor.CreateAsync(context.Document, context.CancellationToken);\n\n        var arityString = diagnostic.Properties[\"Arity\"] switch\n        {\n            null or \"0\" => \"\",\n            string value => $\"`{value}\"\n        };\n        var typeName = diagnostic.Properties[\"TypeName\"];\n        var ns = diagnostic.Properties[\"NamespaceAndNesting\"] switch\n        {\n            { Length: > 0 } value => $\"{value}.\",\n            _ => \"\"\n        };\n\n        var aliasAttribute =\n            Attribute(\n                ParseName(Constants.AliasAttributeFullyQualifiedName))\n                    .WithArgumentList(\n                        ParseAttributeArgumentList($\"(\\\"{ns}{typeName}{arityString}\\\")\"))\n                            .WithAdditionalAnnotations(Simplifier.Annotation);\n\n        documentEditor.AddAttribute(declaration, aliasAttribute);\n        var updatedDocument = documentEditor.GetChangedDocument();\n\n        context.RegisterCodeFix(\n            action: CodeAction.Create(\n                Resources.AddAliasAttributesTitle,\n                createChangedDocument: ct => Task.FromResult(updatedDocument),\n                equivalenceKey: GenerateAliasAttributesAnalyzer.RuleId),\n            diagnostic: diagnostic);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GenerateGenerateSerializerAttributeAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class GenerateGenerateSerializerAttributeAnalyzer : DiagnosticAnalyzer\n    {\n        public const string RuleId = \"ORLEANS0005\";\n        private const string Category = \"Usage\";\n        private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AddGenerateSerializerAttributesTitle), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AddGenerateSerializerAttributeMessageFormat), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AddGenerateSerializerAttributeDescription), Resources.ResourceManager, typeof(Resources));\n\n        internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [Rule];\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.EnableConcurrentExecution();\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n            context.RegisterCompilationStartAction(context =>\n            {\n                var serializableAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"System.SerializableAttribute\");\n                var generateSerializerAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n                if (serializableAttributeSymbol is not null && generateSerializerAttributeSymbol is not null)\n                {\n                    context.RegisterSymbolAction(context => AnalyzeNamedType(context, serializableAttributeSymbol, generateSerializerAttributeSymbol), SymbolKind.NamedType);\n                }\n            });\n        }\n\n        private static void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol serializableAttributeSymbol, INamedTypeSymbol generateSerializerAttributeSymbol)\n        {\n            var symbol = (INamedTypeSymbol)context.Symbol;\n            if (!symbol.IsStatic)\n            {\n                if (symbol.HasAttribute(serializableAttributeSymbol) && !symbol.HasAttribute(generateSerializerAttributeSymbol))\n                {\n                    context.ReportDiagnostic(Diagnostic.Create(Rule, symbol.Locations[0], symbol.Name));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GenerateSerializationAttributesAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class GenerateSerializationAttributesAnalyzer : DiagnosticAnalyzer\n    {\n        public const string RuleId = \"ORLEANS0004\";\n        private const string Category = \"Usage\";\n        private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AddSerializationAttributesTitle), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AddSerializationAttributesMessageFormat), Resources.ResourceManager, typeof(Resources));\n        private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AddSerializationAttributesDescription), Resources.ResourceManager, typeof(Resources));\n\n        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.EnableConcurrentExecution();\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);\n            context.RegisterSyntaxNodeAction(CheckSyntaxNode, SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordDeclaration, SyntaxKind.RecordStructDeclaration);\n        }\n\n        private void CheckSyntaxNode(SyntaxNodeAnalysisContext context)\n        {\n            if (context.Node is TypeDeclarationSyntax declaration && !declaration.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)))\n            {\n                if (declaration.TryGetAttribute(Constants.GenerateSerializerAttributeName, out var attribute))\n                {\n                    var analysis = SerializationAttributesHelper.AnalyzeTypeDeclaration(declaration);\n                    if (analysis.UnannotatedMembers.Count > 0)\n                    {\n                        // Check if GenerateFieldIds is set to PublicProperties\n                        var generateFieldIds = GetGenerateFieldIdsValue(attribute);\n                        if (generateFieldIds != GenerateFieldIds.PublicProperties)\n                        {\n                            context.ReportDiagnostic(Diagnostic.Create(Rule, attribute.GetLocation()));\n                        }\n                    }\n                }\n            }\n        }\n\n        private static GenerateFieldIds GetGenerateFieldIdsValue(AttributeSyntax attribute)\n        {\n            if (attribute.ArgumentList == null)\n            {\n                return GenerateFieldIds.None;\n            }\n\n            foreach (var argument in attribute.ArgumentList.Arguments)\n            {\n                if (argument.NameEquals?.Name.Identifier.Text == \"GenerateFieldIds\")\n                {\n                    if (argument.Expression is MemberAccessExpressionSyntax memberAccess)\n                    {\n                        var memberName = memberAccess.Name.Identifier.Text;\n                        if (memberName == \"PublicProperties\")\n                        {\n                            return GenerateFieldIds.PublicProperties;\n                        }\n                    }\n                }\n            }\n\n            return GenerateFieldIds.None;\n        }\n\n        private enum GenerateFieldIds\n        {\n            None,\n            PublicProperties\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GenerateSerializationAttributesCodeFix.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Editing;\nusing Microsoft.CodeAnalysis.Simplification;\nusing System;\nusing System.Collections.Immutable;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers\n{\n    [ExportCodeFixProvider(LanguageNames.CSharp)]\n    public class GenerateOrleansSerializationAttributesCodeFix : CodeFixProvider\n    {\n        public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(GenerateSerializationAttributesAnalyzer.RuleId, GenerateGenerateSerializerAttributeAnalyzer.RuleId);\n\n        public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n        public override async Task RegisterCodeFixesAsync(CodeFixContext context)\n        {\n            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);\n            var declaration = root.FindNode(context.Span).FirstAncestorOrSelf<TypeDeclarationSyntax>();\n            foreach (var diagnostic in context.Diagnostics)\n            {\n                switch (diagnostic.Id)\n                {\n                    case GenerateSerializationAttributesAnalyzer.RuleId:\n                        context.RegisterCodeFix(\n                            CodeAction.Create(\"Generate serialization attributes\", cancellationToken => AddSerializationAttributes(declaration, context, cancellationToken), equivalenceKey: GenerateSerializationAttributesAnalyzer.RuleId),\n                            diagnostic);\n                        context.RegisterCodeFix(\n                            CodeAction.Create(\"Mark properties and fields [NonSerialized]\", cancellationToken => AddNonSerializedAttributes(root, declaration, context, cancellationToken), equivalenceKey: GenerateSerializationAttributesAnalyzer.RuleId + \"NonSerialized\"),\n                            diagnostic);\n                        break;\n                    case GenerateGenerateSerializerAttributeAnalyzer.RuleId:\n                        context.RegisterCodeFix(\n                            CodeAction.Create(\"Add [GenerateSerializer] attribute\", cancellationToken => AddGenerateSerializerAttribute(declaration, context, cancellationToken), equivalenceKey: GenerateGenerateSerializerAttributeAnalyzer.RuleId),\n                            diagnostic);\n                        break;\n                }\n            }\n        }\n\n        private static async Task<Document> AddGenerateSerializerAttribute(TypeDeclarationSyntax declaration, CodeFixContext context, CancellationToken cancellationToken)\n        {\n            var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false);\n\n            // Add the [GenerateSerializer] attribute\n            var attribute = Attribute(ParseName(Constants.GenerateSerializerAttributeFullyQualifiedName))\n                .WithAdditionalAnnotations(Simplifier.Annotation);\n            editor.AddAttribute(declaration, attribute);\n            return editor.GetChangedDocument();\n        }\n\n        private static async Task<Document> AddSerializationAttributes(TypeDeclarationSyntax declaration, CodeFixContext context, CancellationToken cancellationToken)\n        {\n            var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false);\n            var analysis = SerializationAttributesHelper.AnalyzeTypeDeclaration(declaration);\n\n            var nextId = analysis.NextAvailableId;\n            foreach (var member in analysis.UnannotatedMembers)\n            {\n                // Add the [Id(x)] attribute\n                var attribute = Attribute(ParseName(Constants.IdAttributeFullyQualifiedName))\n                    .AddArgumentListArguments(AttributeArgument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal((int)nextId++))))\n                    .WithAdditionalAnnotations(Simplifier.Annotation);\n                editor.AddAttribute(member, attribute);\n            }\n\n            return editor.GetChangedDocument();\n        }\n\n        private static async Task<Document> AddNonSerializedAttributes(SyntaxNode root, TypeDeclarationSyntax declaration, CodeFixContext context, CancellationToken cancellationToken)\n        {\n            var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false);\n            var analysis = SerializationAttributesHelper.AnalyzeTypeDeclaration(declaration);\n\n            foreach (var member in analysis.UnannotatedMembers)\n            {\n                // Add the [NonSerialized] attribute\n                var attribute = AttributeList().AddAttributes(Attribute(ParseName(Constants.NonSerializedAttributeFullyQualifiedName)).WithAdditionalAnnotations(Simplifier.Annotation));\n\n                // Since [NonSerialized] is a field-only attribute, add the field target specifier.\n                if (member is PropertyDeclarationSyntax)\n                {\n                    attribute = attribute.WithTarget(AttributeTargetSpecifier(Token(SyntaxKind.FieldKeyword)));\n                }\n\n                editor.AddAttribute(member, attribute);\n            }\n\n            var document = editor.GetChangedDocument();\n            root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);\n\n            var insertUsingDirective = true;\n            if (root is CompilationUnitSyntax rootCompilationUnit)\n            {\n                foreach (var directive in rootCompilationUnit.Usings)\n                {\n                    if (string.Equals(directive.Name.ToString(), Constants.SystemNamespace, StringComparison.Ordinal))\n                    {\n                        insertUsingDirective = false;\n                        break;\n                    }\n                }\n\n                if (insertUsingDirective)\n                {\n                    var usingDirective = UsingDirective(IdentifierName(Constants.SystemNamespace)).WithTrailingTrivia(EndOfLine(\"\\r\\n\"));\n                    if (root is CompilationUnitSyntax compilationUnit)\n                    {\n                        root = compilationUnit.AddUsings(usingDirective);\n                    }\n                }\n            }\n\n            return document.WithSyntaxRoot(root);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GrainInterfaceMethodReturnTypeDiagnosticAnalyzer.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class GrainInterfaceMethodReturnTypeDiagnosticAnalyzer : DiagnosticAnalyzer\n    {\n        private const string BaseInterfaceName = \"Orleans.Runtime.IAddressable\";\n\n        public const string DiagnosticId = \"ORLEANS0009\";\n        public const string Title = \"Grain interfaces methods must return a compatible type\";\n        public const string MessageFormat = $\"Grain interfaces methods must return a compatible type, such as Task, Task<T>, ValueTask, ValueTask<T>, or void\";\n        public const string Category = \"Usage\";\n\n        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [Rule];\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n            context.EnableConcurrentExecution();\n            context.RegisterCompilationStartAction(context =>\n            {\n                if (context.Compilation.GetTypeByMetadataName(BaseInterfaceName) is not { } baseInterface)\n                {\n                    return;\n                }\n\n                var builder = ImmutableHashSet.CreateBuilder<ITypeSymbol>(SymbolEqualityComparer.Default);\n\n                AddIfNotNull(builder, context.Compilation.GetTypeByMetadataName(\"System.Threading.Tasks.Task\"));\n                AddIfNotNull(builder, context.Compilation.GetTypeByMetadataName(\"System.Threading.Tasks.Task`1\"));\n                AddIfNotNull(builder, context.Compilation.GetTypeByMetadataName(\"System.Threading.Tasks.ValueTask\"));\n                AddIfNotNull(builder, context.Compilation.GetTypeByMetadataName(\"System.Threading.Tasks.ValueTask`1\"));\n                AddIfNotNull(builder, context.Compilation.GetTypeByMetadataName(\"System.Collections.Generic.IAsyncEnumerable`1\"));\n                AddIfNotNull(builder, context.Compilation.GetSpecialType(SpecialType.System_Void));\n\n                context.RegisterSymbolAction(context => AnalyzeMethod(context, baseInterface, builder.ToImmutable()), SymbolKind.Method);\n            });\n\n\n            static void AddIfNotNull(ImmutableHashSet<ITypeSymbol>.Builder builder, INamedTypeSymbol symbol)\n            {\n                if (symbol is not null)\n                {\n                    builder.Add(symbol);\n                }\n            }\n        }\n\n        private static void AnalyzeMethod(SymbolAnalysisContext context, INamedTypeSymbol baseInterface, ImmutableHashSet<ITypeSymbol> supportedTypes)\n        {\n            var symbol = (IMethodSymbol)context.Symbol;\n\n            if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;\n\n            // allow static interface methods to return any type\n            if (symbol.IsStatic)\n                return;\n\n            var isIAddressableInterface = false;\n            foreach (var implementedInterface in symbol.ContainingType.AllInterfaces)\n            {\n                if (implementedInterface.Equals(baseInterface, SymbolEqualityComparer.Default))\n                {\n                    isIAddressableInterface = true;\n                    break;\n                }\n            }\n\n            if (!isIAddressableInterface || supportedTypes.Contains(symbol.ReturnType.OriginalDefinition))\n                return;\n\n            var syntaxReference = symbol.DeclaringSyntaxReferences;\n            context.ReportDiagnostic(Diagnostic.Create(Rule, Location.Create(syntaxReference[0].SyntaxTree, syntaxReference[0].Span)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/GrainInterfacePropertyDiagnosticAnalyzer.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class GrainInterfacePropertyDiagnosticAnalyzer : DiagnosticAnalyzer\n    {\n        private const string BaseInterfaceName = \"Orleans.Runtime.IAddressable\";\n        public const string DiagnosticId = \"ORLEANS0008\";\n        public const string Title = \"Grain interfaces must not contain properties\";\n        public const string MessageFormat = Title;\n        public const string Category = \"Usage\";\n\n        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);\n            context.EnableConcurrentExecution();\n            context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.PropertyDeclaration);\n        }\n\n        private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)\n        {\n            if (context.Node is not PropertyDeclarationSyntax syntax) return;\n\n            var symbol = context.SemanticModel.GetDeclaredSymbol(syntax, context.CancellationToken);\n\n            if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;\n\n            // ignore static members\n            if (symbol.IsStatic) return;\n\n            var isIAddressableInterface = false;\n            foreach (var implementedInterface in symbol.ContainingType.AllInterfaces)\n            {\n                if (BaseInterfaceName.Equals(implementedInterface.ToDisplayString(NullableFlowState.None), System.StringComparison.Ordinal))\n                {\n                    isIAddressableInterface = true;\n                    break;\n                }\n            }\n\n            if (!isIAddressableInterface) return;\n\n            var syntaxReference = symbol.DeclaringSyntaxReferences;\n            context.ReportDiagnostic(Diagnostic.Create(Rule, Location.Create(syntaxReference[0].SyntaxTree, syntaxReference[0].Span)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/IdClashAttributeAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Orleans.Analyzers;\n\n[DiagnosticAnalyzer(LanguageNames.CSharp)]\npublic class IdClashAttributeAnalyzer : DiagnosticAnalyzer\n{\n    private readonly record struct AliasBag(string Name, Location Location);\n\n    public const string RuleId = \"ORLEANS0012\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(\n       id: RuleId,\n       category: \"Usage\",\n       defaultSeverity: DiagnosticSeverity.Error,\n       isEnabledByDefault: true,\n       title: new LocalizableResourceString(nameof(Resources.IdClashDetectedTitle), Resources.ResourceManager, typeof(Resources)),\n       messageFormat: new LocalizableResourceString(nameof(Resources.IdClashDetectedMessageFormat), Resources.ResourceManager, typeof(Resources)),\n       description: new LocalizableResourceString(nameof(Resources.IdClashDetectedDescription), Resources.ResourceManager, typeof(Resources)));\n\n    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n    public override void Initialize(AnalysisContext context)\n    {\n        context.EnableConcurrentExecution();\n        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n        context.RegisterCompilationStartAction(context =>\n        {\n            var generateSerializerAttribute = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n            var idAttribute = context.Compilation.GetTypeByMetadataName(\"Orleans.IdAttribute\");\n            if (generateSerializerAttribute is not null && idAttribute is not null)\n            {\n                context.RegisterSymbolAction(context => AnalyzeNamedType(context, generateSerializerAttribute, idAttribute), SymbolKind.NamedType);\n            }\n        });\n    }\n\n    private static void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol generateSerializerAttribute, INamedTypeSymbol idAttribute)\n    {\n        var typeSymbol = (INamedTypeSymbol)context.Symbol;\n        if (!typeSymbol.HasAttribute(generateSerializerAttribute))\n        {\n            return;\n        }\n\n        List<AttributeArgumentBag<uint>> bags = [];\n        foreach (var member in typeSymbol.GetMembers())\n        {\n            foreach (var attribute in member.GetAttributes())\n            {\n                if (!idAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default))\n                {\n                    continue;\n                }\n\n                if (attribute.ConstructorArguments.Length == 1 &&\n                    attribute.ConstructorArguments[0].Value is uint idValue)\n                {\n                    var attributeSyntax = (AttributeSyntax)attribute.ApplicationSyntaxReference.GetSyntax();\n                    bags.Add(new AttributeArgumentBag<uint>(idValue, attributeSyntax.GetLocation()));\n                }\n            }\n        }\n\n        var duplicateIds = bags\n           .GroupBy(id => id.Value)\n           .Where(group => group.Count() > 1)\n           .Select(group => group.Key);\n\n        if (!duplicateIds.Any())\n        {\n            return;\n        }\n\n        foreach (var duplicateId in duplicateIds)\n        {\n            var filteredBags = bags.Where(x => x.Value == duplicateId);\n            var duplicateCount = filteredBags.Count();\n\n            if (duplicateCount > 1)\n            {\n                foreach (var bag in filteredBags)\n                {\n                    var builder = ImmutableDictionary.CreateBuilder<string, string>();\n\n                    builder.Add(\"IdValue\", bag.Value.ToString());\n\n                    context.ReportDiagnostic(Diagnostic.Create(\n                       descriptor: Rule,\n                       location: bag.Location,\n                       properties: builder.ToImmutable()));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/IdClashAttributeCodeFix.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Collections.Immutable;\nusing System.Composition;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers;\n\n[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(IdClashAttributeCodeFix)), Shared]\npublic class IdClashAttributeCodeFix : CodeFixProvider\n{\n    public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(IdClashAttributeAnalyzer.RuleId);\n    public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n    public override async Task RegisterCodeFixesAsync(CodeFixContext context)\n    {\n        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);\n        var diagnostic = context.Diagnostics.First();\n        if (root.FindNode(diagnostic.Location.SourceSpan) is not AttributeSyntax attribute)\n        {\n            return;\n        }\n\n        var idValue = diagnostic.Properties[\"IdValue\"];\n\n        context.RegisterCodeFix(\n            CodeAction.Create(\n                Resources.IdClashDetectedTitle,\n                createChangedDocument: _ =>\n                {\n                    var newIdValue = root\n                        .DescendantNodes()\n                        .OfType<AttributeSyntax>()\n                        .Where(a => a.IsAttribute(Constants.IdAttributeName))\n                        .Select(a => int.Parse(a.ArgumentList.Arguments.Single().ToString()))\n                        .Max() + 1;\n\n                    var newAttribute = attribute.ReplaceNode(\n                        attribute.ArgumentList.Arguments[0].Expression,\n                        LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(newIdValue)));\n\n                    var newRoot = root.ReplaceNode(attribute, newAttribute);\n                    var newDocument = context.Document.WithSyntaxRoot(newRoot);\n\n                    return Task.FromResult(newDocument);\n                },\n                equivalenceKey: IdClashAttributeAnalyzer.RuleId),\n            diagnostic);\n    }\n}"
  },
  {
    "path": "src/Orleans.Analyzers/IncorrectAttributeUseAnalyzer.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Analyzers;\n\n[DiagnosticAnalyzer(LanguageNames.CSharp)]\npublic class IncorrectAttributeUseAnalyzer : DiagnosticAnalyzer\n{\n    public const string RuleId = \"ORLEANS0013\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(\n       id: RuleId,\n       category: \"Usage\",\n       defaultSeverity: DiagnosticSeverity.Error,\n       isEnabledByDefault: true,\n       title: new LocalizableResourceString(nameof(Resources.IncorrectAttributeUseTitle), Resources.ResourceManager, typeof(Resources)),\n       messageFormat: new LocalizableResourceString(nameof(Resources.IncorrectAttributeUseMessageFormat), Resources.ResourceManager, typeof(Resources)),\n       description: new LocalizableResourceString(nameof(Resources.IncorrectAttributeUseTitleDescription), Resources.ResourceManager, typeof(Resources)));\n\n    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);\n\n    public override void Initialize(AnalysisContext context)\n    {\n        context.EnableConcurrentExecution();\n        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);\n\n        context.RegisterCompilationStartAction(context =>\n        {\n            var aliasAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.AliasAttribute\");\n            var grainSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.Grain\");\n            var generateSerializerAttributeSymbol = context.Compilation.GetTypeByMetadataName(\"Orleans.GenerateSerializerAttribute\");\n            if (aliasAttributeSymbol is not null && grainSymbol is not null)\n            {\n                context.RegisterSymbolAction(context => AnalyzeNamedType(context, aliasAttributeSymbol, grainSymbol, generateSerializerAttributeSymbol), SymbolKind.NamedType);\n            }\n        });\n    }\n\n    private static void AnalyzeNamedType(SymbolAnalysisContext context, INamedTypeSymbol aliasAttributeSymbol, INamedTypeSymbol grainSymbol, INamedTypeSymbol generateSerializerAttributeSymbol)\n    {\n        var symbol = (INamedTypeSymbol)context.Symbol;\n        if (!symbol.DerivesFrom(grainSymbol))\n        {\n            return;\n        }\n\n        TryReportFor(aliasAttributeSymbol, context, symbol);\n        TryReportFor(generateSerializerAttributeSymbol, context, symbol);\n    }\n\n    private static void TryReportFor(INamedTypeSymbol attributeSymbol, SymbolAnalysisContext context, INamedTypeSymbol symbol)\n    {\n        if (symbol.HasAttribute(attributeSymbol, out var location))\n        {\n            context.ReportDiagnostic(Diagnostic.Create(\n                descriptor: Rule,\n                location: location,\n                messageArgs: new object[] { attributeSymbol.Name }));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/IncorrectAttributeUseCodeFix.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing System.Collections.Immutable;\nusing System.Threading.Tasks;\nusing System.Composition;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Linq;\n\nnamespace Orleans.Analyzers;\n\n[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(IncorrectAttributeUseCodeFix)), Shared]\npublic class IncorrectAttributeUseCodeFix : CodeFixProvider\n{\n    public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(IncorrectAttributeUseAnalyzer.RuleId);\n    public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;\n\n    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)\n    {\n        var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);\n        var diagnostic = context.Diagnostics.First();\n\n        if (root.FindNode(diagnostic.Location.SourceSpan) is not AttributeSyntax node)\n        {\n            return;\n        }\n\n        context.RegisterCodeFix(\n            CodeAction.Create(\n                title: Resources.IncorrectAttributeUseTitle,\n                createChangedDocument: token =>\n                {\n                    var newRoot = root.RemoveNode(node.Parent, SyntaxRemoveOptions.KeepEndOfLine);\n                    return Task.FromResult(context.Document.WithSyntaxRoot(newRoot));\n\n                },\n                equivalenceKey: IncorrectAttributeUseAnalyzer.RuleId),\n            diagnostic);\n    }\n\n}"
  },
  {
    "path": "src/Orleans.Analyzers/NoRefParamsDiagnosticAnalyzer.cs",
    "content": "using System.Collections.Immutable;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\n\nnamespace Orleans.Analyzers\n{\n    [DiagnosticAnalyzer(LanguageNames.CSharp)]\n    public class NoRefParamsDiagnosticAnalyzer : DiagnosticAnalyzer\n    {\n        public const string DiagnosticId = \"ORLEANS0002\";\n        public const string Title = \"Reference parameter modifiers are not allowed\";\n        public const string MessageFormat = Title;\n        public const string Category = \"Usage\";\n\n        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [Rule];\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);\n            context.EnableConcurrentExecution();\n            context.RegisterCompilationStartAction(context =>\n            {\n                var baseInterface = context.Compilation.GetTypeByMetadataName(\"Orleans.Runtime.IAddressable\");\n                if (baseInterface is not null)\n                {\n                    context.RegisterSymbolAction(context => AnalyzeMethodSymbol(context, baseInterface), SymbolKind.Method);\n                }\n            });\n        }\n\n        private static void AnalyzeMethodSymbol(SymbolAnalysisContext context, INamedTypeSymbol baseInterface)\n        {\n            var symbol = (IMethodSymbol)context.Symbol;\n\n            if (symbol.ContainingType.TypeKind != TypeKind.Interface) return;\n\n            // ignore static members\n            if (symbol.IsStatic) return;\n\n            var implementedInterfaces = symbol.ContainingType\n                                              .AllInterfaces\n                                              .Select(interfaceDef => interfaceDef.Name);\n            if (!symbol.ContainingType.AllInterfaces.Contains(baseInterface)) return;\n\n            foreach(var param in symbol.Parameters)\n            {\n                if (param.RefKind == RefKind.None) continue;\n\n                var syntaxReference = param.DeclaringSyntaxReferences;\n                context.ReportDiagnostic(\n                    Diagnostic.Create(Rule, Location.Create(syntaxReference[0].SyntaxTree, syntaxReference[0].Span)));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/Orleans.Analyzers.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Analyzers</PackageId>\n    <Title>Microsoft Orleans Analyzers</Title>\n    <Description>C# Analyzers for Microsoft Orleans.</Description>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <NoPackageAnalysis>true</NoPackageAnalysis>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <DevelopmentDependency>true</DevelopmentDependency>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>\n    <NoWarn>$(NoWarn);RS1038</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" PrivateAssets=\"all\" />\n    <PackageReference Update=\"NETStandard.Library\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"$(OutputPath)\\$(AssemblyName).dll\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\n    <AdditionalFiles Include=\"AnalyzerReleases.Shipped.md\" />\n    <AdditionalFiles Include=\"AnalyzerReleases.Unshipped.md\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Remove=\"Orleans.Metadata.FrameworkPartAttribute\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Analyzers/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "src/Orleans.Analyzers/Resources.Designer.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Orleans.Analyzers {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Orleans.Analyzers.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The member &quot;{0}&quot; is marked as {1} and therefore cannot be serialized.\n        /// </summary>\n        internal static string AbstractOrStaticMembersCannotBeSerializedMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AbstractOrStaticMembersCannotBeSerializedMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Members which are static or abstract cannot be serialized.\n        /// </summary>\n        internal static string AbstractOrStaticMembersCannotBeSerializedTitle {\n            get {\n                return ResourceManager.GetString(\"AbstractOrStaticMembersCannotBeSerializedTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add [Alias] to specify well-known names that can be used to identify types or methods..\n        /// </summary>\n        internal static string AddAliasAttributesDescription {\n            get {\n                return ResourceManager.GetString(\"AddAliasAttributesDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add missing [Alias].\n        /// </summary>\n        internal static string AddAliasAttributesTitle {\n            get {\n                return ResourceManager.GetString(\"AddAliasAttributesTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add missing [Alias].\n        /// </summary>\n        internal static string AddAliasMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AddAliasMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add the [GenerateSerializer] attribute to serializable types in your application..\n        /// </summary>\n        internal static string AddGenerateSerializerAttributeDescription {\n            get {\n                return ResourceManager.GetString(\"AddGenerateSerializerAttributeDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The type &quot;{0}&quot; has the [Serializable] attribute but not the [GenerateSerializer] attribute.\n        /// </summary>\n        internal static string AddGenerateSerializerAttributeMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AddGenerateSerializerAttributeMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add the [GenerateSerializer] attribute.\n        /// </summary>\n        internal static string AddGenerateSerializerAttributesTitle {\n            get {\n                return ResourceManager.GetString(\"AddGenerateSerializerAttributesTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add attributes to properties and fields to direct serializer generation..\n        /// </summary>\n        internal static string AddSerializationAttributesDescription {\n            get {\n                return ResourceManager.GetString(\"AddSerializationAttributesDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add missing serialization attributes.\n        /// </summary>\n        internal static string AddSerializationAttributesMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AddSerializationAttributesMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Add missing serialization attributes.\n        /// </summary>\n        internal static string AddSerializationAttributesTitle {\n            get {\n                return ResourceManager.GetString(\"AddSerializationAttributesTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The [Alias] attribute must be unique to the declaring type..\n        /// </summary>\n        internal static string AliasClashDetectedDescription {\n            get {\n                return ResourceManager.GetString(\"AliasClashDetectedDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Rename duplicated [Alias].\n        /// </summary>\n        internal static string AliasClashDetectedMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AliasClashDetectedMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Rename duplicated [Alias].\n        /// </summary>\n        internal static string AliasClashDetectedTitle {\n            get {\n                return ResourceManager.GetString(\"AliasClashDetectedTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to A single type is not allowed to have multiple constructors annotated with the [OrleansConstructor] attribute.\n        /// </summary>\n        internal static string AtMostOneOrleansConstructorMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AtMostOneOrleansConstructorMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to At most one constructor can be annotated with the [OrleansConstructor] attribute.\n        /// </summary>\n        internal static string AtMostOneOrleansConstructorTitle {\n            get {\n                return ResourceManager.GetString(\"AtMostOneOrleansConstructorTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The [Id] attribute must be unique to each members of the declaring type..\n        /// </summary>\n        internal static string IdClashDetectedDescription {\n            get {\n                return ResourceManager.GetString(\"IdClashDetectedDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Change duplicated [Id].\n        /// </summary>\n        internal static string IdClashDetectedMessageFormat {\n            get {\n                return ResourceManager.GetString(\"IdClashDetectedMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Change duplicated [Id].\n        /// </summary>\n        internal static string IdClashDetectedTitle {\n            get {\n                return ResourceManager.GetString(\"IdClashDetectedTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Remove attribute [{0}].\n        /// </summary>\n        internal static string IncorrectAttributeUseMessageFormat {\n            get {\n                return ResourceManager.GetString(\"IncorrectAttributeUseMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Remove attribute.\n        /// </summary>\n        internal static string IncorrectAttributeUseTitle {\n            get {\n                return ResourceManager.GetString(\"IncorrectAttributeUseTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to This attribute should not be used on grain implementations..\n        /// </summary>\n        internal static string IncorrectAttributeUseTitleDescription {\n            get {\n                return ResourceManager.GetString(\"IncorrectAttributeUseTitleDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Grain code must maintain the grain's synchronization context...\n        /// </summary>\n        internal static string AvoidConfigureAwaitFalseInGrainDescription {\n            get {\n                return ResourceManager.GetString(\"AvoidConfigureAwaitFalseInGrainDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to ConfigureAwait in grain code must not use 'false' and must include ConfigureAwaitOptions.ContinueOnCapturedContext.\n        /// </summary>\n        internal static string AvoidConfigureAwaitFalseInGrainMessageFormat {\n            get {\n                return ResourceManager.GetString(\"AvoidConfigureAwaitFalseInGrainMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Avoid ConfigureAwait(false) or ConfigureAwait not specifying ContinueOnCapturedContext in grain code.\n        /// </summary>\n        internal static string AvoidConfigureAwaitFalseInGrainTitle {\n            get {\n                return ResourceManager.GetString(\"AvoidConfigureAwaitFalseInGrainTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Use ConfigureAwait with ContinueOnCapturedContext.\n        /// </summary>\n        internal static string ConfigureAwaitCodeFixTitle {\n            get {\n                return ResourceManager.GetString(\"ConfigureAwaitCodeFixTitle\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/Resources.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"AbstractOrStaticMembersCannotBeSerializedMessageFormat\" xml:space=\"preserve\">\n    <value>The member \"{0}\" is marked as {1} and therefore cannot be serialized</value>\n  </data>\n  <data name=\"AbstractOrStaticMembersCannotBeSerializedTitle\" xml:space=\"preserve\">\n    <value>Members which are static or abstract cannot be serialized</value>\n  </data>\n  <data name=\"AddGenerateSerializerAttributeDescription\" xml:space=\"preserve\">\n    <value>Add the [GenerateSerializer] attribute to serializable types in your application.</value>\n  </data>\n  <data name=\"AddGenerateSerializerAttributeMessageFormat\" xml:space=\"preserve\">\n    <value>The type \"{0}\" has the [Serializable] attribute but not the [GenerateSerializer] attribute</value>\n  </data>\n  <data name=\"AddGenerateSerializerAttributesTitle\" xml:space=\"preserve\">\n    <value>Add the [GenerateSerializer] attribute</value>\n  </data>\n  <data name=\"AddSerializationAttributesDescription\" xml:space=\"preserve\">\n    <value>Add attributes to properties and fields to direct serializer generation.</value>\n  </data>\n  <data name=\"AddSerializationAttributesMessageFormat\" xml:space=\"preserve\">\n    <value>Add missing serialization attributes</value>\n  </data>\n  <data name=\"AddSerializationAttributesTitle\" xml:space=\"preserve\">\n    <value>Add missing serialization attributes</value>\n  </data>\n  <data name=\"AtMostOneOrleansConstructorTitle\" xml:space=\"preserve\">\n    <value>At most one constructor can be annotated with the [OrleansConstructor] attribute</value>\n  </data>\n  <data name=\"AtMostOneOrleansConstructorMessageFormat\" xml:space=\"preserve\">\n    <value>A single type is not allowed to have multiple constructors annotated with the [OrleansConstructor] attribute</value>\n  </data>\n  <data name=\"AddAliasAttributesDescription\" xml:space=\"preserve\">\n    <value>Add [Alias] to specify well-known names that can be used to identify types or methods.</value>\n  </data>\n  <data name=\"AddAliasAttributesTitle\" xml:space=\"preserve\">\n    <value>Add missing [Alias]</value>\n  </data>\n  <data name=\"AddAliasMessageFormat\" xml:space=\"preserve\">\n    <value>Add missing [Alias]</value>\n  </data>\n  <data name=\"AliasClashDetectedDescription\" xml:space=\"preserve\">\n    <value>The [Alias] attribute must be unique to the declaring type.</value>\n  </data>\n  <data name=\"AliasClashDetectedMessageFormat\" xml:space=\"preserve\">\n    <value>Rename duplicated [Alias]</value>\n  </data>\n  <data name=\"AliasClashDetectedTitle\" xml:space=\"preserve\">\n    <value>Rename duplicated [Alias]</value>\n  </data>\n  <data name=\"IdClashDetectedDescription\" xml:space=\"preserve\">\n    <value>The [Id] attribute must be unique to each members of the declaring type.</value>\n  </data>\n  <data name=\"IdClashDetectedMessageFormat\" xml:space=\"preserve\">\n    <value>Change duplicated [Id]</value>\n  </data>\n  <data name=\"IdClashDetectedTitle\" xml:space=\"preserve\">\n    <value>Change duplicated [Id]</value>\n  </data>\n  <data name=\"IncorrectAttributeUseMessageFormat\" xml:space=\"preserve\">\n    <value>Remove attribute [{0}]</value>\n  </data>\n  <data name=\"IncorrectAttributeUseTitle\" xml:space=\"preserve\">\n    <value>Remove attribute</value>\n  </data>\n  <data name=\"IncorrectAttributeUseTitleDescription\" xml:space=\"preserve\">\n    <value>This attribute should not be used on grain implementations.</value>\n  </data>\n  <data name=\"AvoidConfigureAwaitFalseInGrainTitle\" xml:space=\"preserve\">\n    <value>Avoid ConfigureAwait(false) or ConfigureAwait not specifying ContinueOnCapturedContext in grain code</value>\n  </data>\n  <data name=\"AvoidConfigureAwaitFalseInGrainMessageFormat\" xml:space=\"preserve\">\n    <value>ConfigureAwait in grain code must not use 'false' and must include ConfigureAwaitOptions.ContinueOnCapturedContext</value>\n  </data>\n  <data name=\"AvoidConfigureAwaitFalseInGrainDescription\" xml:space=\"preserve\">\n    <value>Grain code must maintain the grain's execution context. Using ConfigureAwait(false) or ConfigureAwait without ContinueOnCapturedContext can cause the continuation to run outside the grain's context, leading to concurrency issues and loss of grain identity.</value>\n  </data>\n  <data name=\"ConfigureAwaitCodeFixTitle\" xml:space=\"preserve\">\n    <value>Use ConfigureAwait with ContinueOnCapturedContext</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Orleans.Analyzers/SerializationAttributesHelper.cs",
    "content": "#nullable enable\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Analyzers\n{\n    internal static class SerializationAttributesHelper\n    {\n        public static bool ShouldGenerateSerializer(INamedTypeSymbol symbol, INamedTypeSymbol generateSerializerAttributeSymbol)\n        {\n            if (!symbol.IsStatic && symbol.HasAttribute(generateSerializerAttributeSymbol))\n            {\n                return true;\n            }\n\n            return false;\n        }\n\n        public readonly record struct TypeAnalysis\n        {\n            public List<MemberDeclarationSyntax> UnannotatedMembers { get; init; }\n            public uint NextAvailableId { get; init; }\n        }\n\n        public static TypeAnalysis AnalyzeTypeDeclaration(TypeDeclarationSyntax declaration)\n        {\n            uint nextId = 0;\n            var unannotatedSerializableMembers = new List<MemberDeclarationSyntax>();\n            foreach (var member in declaration.Members)\n            {\n                // Skip members with existing [Id(x)] attributes, but record the highest value of x so that newly added attributes can begin from that value.\n                if (member.TryGetAttribute(Constants.IdAttributeName, out var attribute))\n                {\n                    var args = attribute.ArgumentList?.Arguments;\n                    if (args.HasValue)\n                    {\n                        if (args.Value.Count > 0)\n                        {\n                            var idArg = args.Value[0];\n                            if (idArg.Expression is LiteralExpressionSyntax literalExpression\n                                && uint.TryParse(literalExpression.Token.ValueText, out var value)\n                                && value >= nextId)\n                            {\n                                nextId = value + 1;\n                            }\n                        }\n                    }\n\n                    continue;\n                }\n\n                if (member is ConstructorDeclarationSyntax constructorDeclaration && constructorDeclaration.HasAttribute(Constants.GenerateSerializerAttributeName))\n                {\n                    continue;\n                }\n\n                if (!member.IsInstanceMember() || !member.IsFieldOrAutoProperty() || member.HasAttribute(Constants.NonSerializedAttribute) || member.IsAbstract())\n                {\n                    // No need to add any attribute.\n                    continue;\n                }\n\n                unannotatedSerializableMembers.Add(member);\n            }\n\n            return new TypeAnalysis\n            {\n                UnannotatedMembers = unannotatedSerializableMembers,\n                NextAvailableId = nextId,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/SymbolHelpers.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.Analyzers\n{\n    internal static class SymbolHelpers\n    {\n        public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeSymbol, out Location location)\n        {\n            foreach (var attribute in symbol.GetAttributes())\n            {\n                if (attributeSymbol.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default))\n                {\n                    location = attribute.ApplicationSyntaxReference.GetSyntax().GetLocation();\n                    return true;\n                }\n            }\n\n            location = null;\n            return false;\n        }\n\n        public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeSymbol)\n            => symbol.HasAttribute(attributeSymbol, out _);\n\n        public static bool DerivesFrom(this ITypeSymbol symbol, ITypeSymbol candidateBaseType)\n        {\n            var baseType = symbol.BaseType;\n            while (baseType is not null)\n            {\n                if (baseType.Equals(candidateBaseType, SymbolEqualityComparer.Default))\n                {\n                    return true;\n                }\n\n                baseType = baseType.BaseType;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Analyzers/SyntaxHelpers.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.Analyzers\n{\n    internal readonly record struct AttributeArgumentBag<T>(T Value, Location Location);\n\n    internal static class SyntaxHelpers\n    {\n        private static bool TryGetTypeName(this AttributeSyntax attributeSyntax, out string typeName)\n        {\n            typeName = attributeSyntax.Name switch\n            {\n                IdentifierNameSyntax id => id.Identifier.Text,\n                QualifiedNameSyntax qualified => qualified.Right.Identifier.Text,\n                GenericNameSyntax generic => generic.Identifier.Text,\n                AliasQualifiedNameSyntax aliased => aliased.Name.Identifier.Text,\n                _ => null\n            };\n\n            return typeName != null;\n        }\n\n        public static bool IsAttribute(this AttributeSyntax attributeSyntax, string attributeName) =>\n            attributeSyntax.TryGetTypeName(out var name) &&\n            (string.Equals(name, attributeName, StringComparison.Ordinal)\n             || (name.StartsWith(attributeName, StringComparison.Ordinal) && name.EndsWith(nameof(Attribute), StringComparison.Ordinal) && name.Length == attributeName.Length + nameof(Attribute).Length));\n\n        public static bool HasAttribute(this MemberDeclarationSyntax member, string attributeName)\n        {\n            foreach (var list in member.AttributeLists)\n            {\n                foreach (var attr in list.Attributes)\n                {\n                    if (attr.IsAttribute(attributeName))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        public static bool TryGetAttribute(this MemberDeclarationSyntax member, string attributeName, out AttributeSyntax attribute)\n        {\n            foreach (var list in member.AttributeLists)\n            {\n                foreach (var attr in list.Attributes)\n                {\n                    if (attr.IsAttribute(attributeName))\n                    {\n                        attribute = attr;\n                        return true;\n                    }\n                }\n            }\n\n            attribute = default;\n            return false;\n        }\n\n        public static bool IsAbstract(this MemberDeclarationSyntax member) => member.HasModifier(SyntaxKind.AbstractKeyword);\n\n        private static bool HasModifier(this MemberDeclarationSyntax member, SyntaxKind modifierKind)\n        {\n            foreach (var modifier in member.Modifiers)\n            {\n                var kind = modifier.Kind();\n                if (kind == modifierKind)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool IsInstanceMember(this MemberDeclarationSyntax member)\n        {\n            foreach (var modifier in member.Modifiers)\n            {\n                var kind = modifier.Kind();\n                if (kind == SyntaxKind.StaticKeyword || kind == SyntaxKind.ConstKeyword)\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        public static bool IsFieldOrAutoProperty(this MemberDeclarationSyntax member)\n        {\n            bool isFieldOrAutoProperty = false;\n            switch (member)\n            {\n                case FieldDeclarationSyntax:\n                    isFieldOrAutoProperty = true;\n                    break;\n                case PropertyDeclarationSyntax property:\n                    {\n                        bool hasBody = property.ExpressionBody is not null;\n                        var accessors = property.AccessorList?.Accessors;\n                        if (!hasBody && accessors.HasValue)\n                        {\n                            foreach (var accessor in accessors)\n                            {\n                                if (accessor.ExpressionBody is not null || accessor.Body is not null)\n                                {\n                                    hasBody = true;\n                                    break;\n                                }\n                            }\n                        }\n\n                        if (!hasBody)\n                        {\n                            isFieldOrAutoProperty = true;\n                        }\n\n                        break;\n                    }\n            }\n\n            return isFieldOrAutoProperty;\n        }\n\n        public static bool ExtendsGrainInterface(this INamedTypeSymbol symbol)\n        {\n            if (symbol is null || symbol.TypeKind != TypeKind.Interface)\n            {\n                return false;\n            }\n\n            foreach (var interfaceSymbol in symbol.AllInterfaces)\n            {\n                if (Constants.IAddressibleFullyQualifiedName.Equals(interfaceSymbol.ToDisplayString(NullableFlowState.None), StringComparison.Ordinal))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n        public static bool InheritsGrainClass(this ClassDeclarationSyntax declaration, SemanticModel semanticModel)\n        {\n            var baseTypes = declaration.BaseList?.Types;\n            if (baseTypes is null)\n            {\n                return false;\n            }\n\n            foreach (var baseTypeSyntax in baseTypes)\n            {\n                var baseTypeSymbol = semanticModel.GetTypeInfo(baseTypeSyntax.Type).Type;\n                if (baseTypeSymbol is INamedTypeSymbol currentTypeSymbol)\n                {\n                    if (currentTypeSymbol.IsGenericType &&\n                        currentTypeSymbol.TypeParameters.Length == 1 &&\n                        currentTypeSymbol.BaseType is { } baseBaseTypeSymbol)\n                    {\n                        currentTypeSymbol = baseBaseTypeSymbol;\n                    }\n\n                    if (Constants.GrainBaseFullyQualifiedName.Equals(currentTypeSymbol.ToDisplayString(NullableFlowState.None), StringComparison.Ordinal))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        public static bool IsGrainClass(this INamedTypeSymbol typeSymbol)\n        {\n            if (typeSymbol is null || typeSymbol.TypeKind != TypeKind.Class)\n            {\n                return false;\n            }\n\n            // Check if the type implements IGrain or ISystemTarget interface\n            foreach (var interfaceSymbol in typeSymbol.AllInterfaces)\n            {\n                var interfaceName = interfaceSymbol.ToDisplayString(NullableFlowState.None);\n                if (Constants.IGrainFullyQualifiedName.Equals(interfaceName, StringComparison.Ordinal) ||\n                    Constants.ISystemTargetFullyQualifiedName.Equals(interfaceName, StringComparison.Ordinal))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static AttributeArgumentBag<T> GetArgumentBag<T>(this AttributeSyntax attribute, SemanticModel semanticModel)\n        {\n            if (attribute is null)\n            {\n                return default;\n            }\n\n            var argument = attribute.ArgumentList?.Arguments.FirstOrDefault();\n            if (argument is null || argument.Expression is not { } expression)\n            {\n                return default;\n            }\n\n            var constantValue = semanticModel.GetConstantValue(expression);\n            return constantValue.HasValue && constantValue.Value is T value ?\n                new(value, attribute.GetLocation()) : default;\n        }\n\n        public static IEnumerable<AttributeSyntax> GetAttributeSyntaxes(this SyntaxList<AttributeListSyntax> attributeLists, string attributeName) =>\n            attributeLists\n                .SelectMany(attributeList => attributeList.Attributes)\n                .Where(attribute => attribute.IsAttribute(attributeName));\n\n        public static string GetArgumentValue(this AttributeSyntax attribute, SemanticModel semanticModel)\n        {\n            if (attribute?.ArgumentList == null || attribute.ArgumentList.Arguments.Count == 0)\n            {\n                return null;\n            }\n\n            var symbolInfo = semanticModel.GetSymbolInfo(attribute);\n            if (symbolInfo.Symbol == null && symbolInfo.CandidateSymbols.Length == 0)\n            {\n                return null;\n            }\n\n            var argumentExpression = attribute.ArgumentList.Arguments[0].Expression;\n            var constant = semanticModel.GetConstantValue(argumentExpression);\n\n            return constant.HasValue ? constant.Value?.ToString() : null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/BroadcastChannelConsumerExtension.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.BroadcastChannel\n{\n    internal interface IBroadcastChannelConsumerExtension : IGrainExtension\n    {\n        Task OnError(InternalChannelId streamId, Exception exception);\n        Task OnPublished(InternalChannelId streamId, object item);\n    }\n\n    internal class BroadcastChannelConsumerExtension : IBroadcastChannelConsumerExtension\n    {\n        private readonly ConcurrentDictionary<InternalChannelId, ICallback> _handlers = new();\n        private readonly IOnBroadcastChannelSubscribed _subscriptionObserver;\n        private readonly AsyncLock _lock = new AsyncLock();\n\n        private interface ICallback\n        {\n            Task OnError(Exception exception);\n\n            Task OnPublished(object item);\n        }\n\n        private class Callback<T> : ICallback\n        {\n            private readonly Func<T, Task> _onPublished;\n            private readonly Func<Exception, Task> _onError;\n\n            private static Task NoOp(Exception _) => Task.CompletedTask;\n\n            public Callback(Func<T, Task> onPublished, Func<Exception, Task> onError)\n            {\n                _onPublished = onPublished;\n                _onError = onError ?? NoOp;\n            }\n\n            public Task OnError(Exception exception) => _onError(exception);\n\n            public Task OnPublished(object item)\n            {\n                return item is T typedItem\n                    ? _onPublished(typedItem)\n                    : _onError(new InvalidCastException($\"Received an item of type {item.GetType().Name}, expected {typeof(T).FullName}\"));\n            }\n        }\n\n        public BroadcastChannelConsumerExtension(IGrainContextAccessor grainContextAccessor)\n        {\n            _subscriptionObserver = grainContextAccessor.GrainContext?.GrainInstance as IOnBroadcastChannelSubscribed;\n            if (_subscriptionObserver == null)\n            {\n                throw new ArgumentException($\"The grain doesn't implement interface {nameof(IOnBroadcastChannelSubscribed)}\");\n            }\n        }\n\n        public async Task OnError(InternalChannelId streamId, Exception exception)\n        {\n            var callback = await GetStreamCallback(streamId);\n            if (callback != default)\n            {\n                await callback.OnError(exception);\n            }\n        }\n\n        public async Task OnPublished(InternalChannelId streamId, object item)\n        {\n            var callback = await GetStreamCallback(streamId);\n            if (callback != default)\n            {\n                await callback.OnPublished(item);\n            }\n        }\n\n        public void Attach<T>(InternalChannelId streamId, Func<T, Task> onPublished, Func<Exception, Task> onError)\n        {\n            _handlers.TryAdd(streamId, new Callback<T>(onPublished, onError));\n        }\n\n        private async ValueTask<ICallback> GetStreamCallback(InternalChannelId streamId)\n        {\n            ICallback callback;\n            if (_handlers.TryGetValue(streamId, out callback))\n            {\n                return callback;\n            }\n            using (await _lock.LockAsync())\n            {\n                if (_handlers.TryGetValue(streamId, out callback))\n                {\n                    return callback;\n                }\n                // Give a chance to the grain to attach a handler for this streamId\n                var subscription = new BroadcastChannelSubscription(this, streamId);\n                await _subscriptionObserver.OnSubscribed(subscription);\n            }\n            _handlers.TryGetValue(streamId, out callback);\n            return callback;\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/BroadcastChannelOptions.cs",
    "content": "namespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Configuration options for broadcast channel\n    /// </summary>\n    public class BroadcastChannelOptions\n    {\n        /// <summary>\n        /// If set to true, the provider will not await calls to subscriber.\n        /// </summary>\n        public bool FireAndForgetDelivery { get; set; } = true;\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/BroadcastChannelProvider.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.BroadcastChannel.SubscriberTable;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Functionality for providing broadcast channel to producers.\n    /// </summary>\n    public interface IBroadcastChannelProvider\n    {\n        /// <summary>\n        /// Get a writer to a channel.\n        /// </summary>\n        /// <typeparam name=\"T\">The channel element type.</typeparam>\n        /// <param name=\"streamId\">The channel identifier.</param>\n        /// <returns></returns>\n        IBroadcastChannelWriter<T> GetChannelWriter<T>(ChannelId streamId);\n    }\n\n    internal class BroadcastChannelProvider : IBroadcastChannelProvider\n    {\n        private readonly string _providerName;\n        private readonly BroadcastChannelOptions _options;\n        private readonly IGrainFactory _grainFactory;\n        private readonly ImplicitChannelSubscriberTable _subscriberTable;\n        private readonly ILoggerFactory _loggerFactory;\n\n        public BroadcastChannelProvider(\n            string providerName,\n            BroadcastChannelOptions options,\n            IGrainFactory grainFactory,\n            ImplicitChannelSubscriberTable subscriberTable,\n            ILoggerFactory loggerFactory)\n        {\n            _providerName = providerName;\n            _options = options;\n            _grainFactory = grainFactory;\n            _subscriberTable = subscriberTable;\n            _loggerFactory = loggerFactory;\n        }\n\n        /// <inheritdoc />\n        public IBroadcastChannelWriter<T> GetChannelWriter<T>(ChannelId streamId)\n        {\n            return new BroadcastChannelWriter<T>(\n                new InternalChannelId(_providerName, streamId),\n                _grainFactory,\n                _subscriberTable,\n                _options.FireAndForgetDelivery,\n                _loggerFactory);\n        }\n\n        /// <summary>\n        /// Create a new channel provider.\n        /// </summary>\n        /// <param name=\"sp\">The service provider.</param>\n        /// <param name=\"name\">The name of the provider.</param>\n        /// <returns>The named channel provider.</returns>\n        public static IBroadcastChannelProvider Create(IServiceProvider sp, string name)\n        {\n            var opt = sp.GetOptionsByName<BroadcastChannelOptions>(name);\n            return ActivatorUtilities.CreateInstance<BroadcastChannelProvider>(sp, name, opt);\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/BroadcastChannelSubscription.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.BroadcastChannel\n{\n    public interface IBroadcastChannelSubscription\n    {\n        public ChannelId ChannelId { get; }\n\n        public string ProviderName { get; }\n\n        Task Attach<T>(Func<T, Task> onPublished, Func<Exception, Task> onError = null);\n    }\n\n    public interface IOnBroadcastChannelSubscribed\n    {\n        public Task OnSubscribed(IBroadcastChannelSubscription streamSubscription);\n    }\n\n    internal class BroadcastChannelSubscription : IBroadcastChannelSubscription\n    {\n        private readonly BroadcastChannelConsumerExtension _consumerExtension;\n        private readonly InternalChannelId _streamId;\n\n        public ChannelId ChannelId => _streamId.ChannelId;\n\n        public string ProviderName => _streamId.ProviderName;\n\n        public BroadcastChannelSubscription(BroadcastChannelConsumerExtension consumerExtension, InternalChannelId streamId)\n        {\n            _consumerExtension = consumerExtension;\n            _streamId = streamId;\n        }\n\n        public Task Attach<T>(Func<T, Task> onPublished, Func<Exception, Task> onError = null)\n        {\n            _consumerExtension.Attach(_streamId, onPublished, onError);\n            return Task.CompletedTask;\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/BroadcastChannelWriter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.BroadcastChannel.SubscriberTable;\nusing Orleans.Runtime;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Interface to allow writing to a channel.\n    /// </summary>\n    /// <typeparam name=\"T\">The channel element type.</typeparam>\n    public interface IBroadcastChannelWriter<T>\n    {\n        /// <summary>\n        /// Publish an element to the channel.\n        /// </summary>\n        /// <param name=\"item\">The element to publish.</param>\n        Task Publish(T item);\n    }\n\n    /// <inheritdoc />\n    internal partial class BroadcastChannelWriter<T> : IBroadcastChannelWriter<T>\n    {\n        private static readonly string LoggingCategory = typeof(BroadcastChannelWriter<>).FullName;\n\n        private readonly InternalChannelId _channelId;\n        private readonly IGrainFactory _grainFactory;\n        private readonly ImplicitChannelSubscriberTable _subscriberTable;\n        private readonly bool _fireAndForgetDelivery;\n        private readonly ILogger _logger;\n\n        public BroadcastChannelWriter(\n            InternalChannelId channelId,\n            IGrainFactory grainFactory,\n            ImplicitChannelSubscriberTable subscriberTable,\n            bool fireAndForgetDelivery,\n            ILoggerFactory loggerFactory)\n        {\n            _channelId = channelId;\n            _grainFactory = grainFactory;\n            _subscriberTable = subscriberTable;\n            _fireAndForgetDelivery = fireAndForgetDelivery;\n            _logger = loggerFactory.CreateLogger(LoggingCategory);\n        }\n\n        /// <inheritdoc />\n        public async Task Publish(T item)\n        {\n            var subscribers = _subscriberTable.GetImplicitSubscribers(_channelId, _grainFactory);\n\n            if (subscribers.Count == 0)\n            {\n                LogDebugNoConsumerFound(_logger, item);\n                return;\n            }\n\n            LogDebugPublishingItem(_logger, item, subscribers.Count);\n\n            if (_fireAndForgetDelivery)\n            {\n                foreach (var sub in subscribers)\n                {\n                    PublishToSubscriber(sub.Value, item).Ignore();\n                }\n            }\n            else\n            {\n                var tasks = new List<Task>();\n                foreach (var sub in subscribers)\n                {\n                    tasks.Add(PublishToSubscriber(sub.Value, item));\n                }\n                try\n                {\n                    await Task.WhenAll(tasks);\n                }\n                catch (Exception)\n                {\n                    throw new AggregateException(tasks.Select(t => t.Exception).Where(ex => ex != null));\n                }\n            }\n        }\n\n        private async Task PublishToSubscriber(IBroadcastChannelConsumerExtension consumer, T item)\n        {\n            try\n            {\n                await consumer.OnPublished(_channelId, item);\n            }\n            catch (Exception ex)\n            {\n                LogErrorExceptionWhenSendingItem(_logger, ex, consumer.GetGrainId());\n                if (!_fireAndForgetDelivery)\n                {\n                    throw;\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"No consumer found for {Item}\"\n        )]\n        private static partial void LogDebugNoConsumerFound(ILogger logger, T item);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Publishing item {Item} to {ConsumerCount} consumers\"\n        )]\n        private static partial void LogDebugPublishingItem(ILogger logger, T item, int consumerCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception when sending item to {GrainId}\"\n        )]\n        private static partial void LogErrorExceptionWhenSendingItem(ILogger logger, Exception exception, GrainId grainId);\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/ChannelId.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing Orleans.Runtime;\n\n#nullable enable\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Identifies a Channel within a provider\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct ChannelId : IEquatable<ChannelId>, IComparable<ChannelId>, ISerializable, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly byte[] fullKey;\n\n        [Id(1)]\n        private readonly ushort keyIndex;\n\n        [Id(2)]\n        private readonly int hash;\n\n        /// <summary>\n        /// Gets the full key.\n        /// </summary>\n        /// <value>The full key.</value>\n        public ReadOnlyMemory<byte> FullKey => fullKey;\n\n        /// <summary>\n        /// Gets the namespace.\n        /// </summary>\n        /// <value>The namespace.</value>\n        public ReadOnlyMemory<byte> Namespace => fullKey.AsMemory(0, this.keyIndex);\n\n        /// <summary>\n        /// Gets the key.\n        /// </summary>\n        /// <value>The key.</value>\n        public ReadOnlyMemory<byte> Key => fullKey.AsMemory(this.keyIndex);\n\n        private ChannelId(byte[] fullKey, ushort keyIndex, int hash)\n        {\n            this.fullKey = fullKey;\n            this.keyIndex = keyIndex;\n            this.hash = hash;\n        }\n\n        internal ChannelId(byte[] fullKey, ushort keyIndex)\n            : this(fullKey, keyIndex, (int)StableHash.ComputeHash(fullKey))\n        {\n        }\n\n        private ChannelId(SerializationInfo info, StreamingContext context)\n        {\n            fullKey = (byte[])info.GetValue(\"fk\", typeof(byte[]))!;\n            this.keyIndex = info.GetUInt16(\"ki\");\n            this.hash = info.GetInt32(\"fh\");\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChannelId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static ChannelId Create(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> key)\n        {\n            if (key.IsEmpty)\n                throw new ArgumentNullException(nameof(key));\n\n            if (!ns.IsEmpty)\n            {\n                var fullKeysBytes = new byte[ns.Length + key.Length];\n                ns.CopyTo(fullKeysBytes.AsSpan());\n                key.CopyTo(fullKeysBytes.AsSpan(ns.Length));\n                return new(fullKeysBytes, (ushort)ns.Length);\n            }\n            else\n            {\n                return new(key.ToArray(), 0);\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChannelId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static ChannelId Create(string ns, Guid key)\n        {\n            if (ns is null)\n            {\n                var buf = new byte[32];\n                Utf8Formatter.TryFormat(key, buf, out var len, 'N');\n                Debug.Assert(len == 32);\n                return new ChannelId(buf, 0);\n            }\n            else\n            {\n                var nsLen = Encoding.UTF8.GetByteCount(ns);\n                var buf = new byte[nsLen + 32];\n                Encoding.UTF8.GetBytes(ns, 0, ns.Length, buf, 0);\n                Utf8Formatter.TryFormat(key, buf.AsSpan(nsLen), out var len, 'N');\n                Debug.Assert(len == 32);\n                return new ChannelId(buf, (ushort)nsLen);\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChannelId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static ChannelId Create(string ns, string key)\n        {\n            if (ns is null)\n                return new ChannelId(Encoding.UTF8.GetBytes(key), 0);\n\n            var nsLen = Encoding.UTF8.GetByteCount(ns);\n            var keyLen = Encoding.UTF8.GetByteCount(key);\n            var buf = new byte[nsLen + keyLen];\n            Encoding.UTF8.GetBytes(ns, 0, ns.Length, buf, 0);\n            Encoding.UTF8.GetBytes(key, 0, key.Length, buf, nsLen);\n            return new ChannelId(buf, (ushort)nsLen);\n        }\n\n        /// <inheritdoc/>\n        public int CompareTo(ChannelId other) => fullKey.AsSpan().SequenceCompareTo(other.fullKey);\n\n        /// <inheritdoc/>\n        public bool Equals(ChannelId other) => fullKey.AsSpan().SequenceEqual(other.fullKey);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is ChannelId other ? this.Equals(other) : false;\n\n        /// <summary>\n        /// Compares two <see cref=\"ChannelId\"/> instances for equality.\n        /// </summary>\n        /// <param name=\"s1\">The first stream identity.</param>\n        /// <param name=\"s2\">The second stream identity.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator ==(ChannelId s1, ChannelId s2) => s1.Equals(s2);\n\n        /// <summary>\n        /// Compares two <see cref=\"ChannelId\"/> instances for equality.\n        /// </summary>\n        /// <param name=\"s1\">The first stream identity.</param>\n        /// <param name=\"s2\">The second stream identity.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator !=(ChannelId s1, ChannelId s2) => !s2.Equals(s1);\n\n        /// <inheritdoc/>\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"fk\", fullKey);\n            info.AddValue(\"ki\", this.keyIndex);\n            info.AddValue(\"fh\", this.hash);\n        }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{this}\";\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            var len = Encoding.UTF8.GetCharCount(fullKey);\n            if (keyIndex == 0)\n            {\n                if (destination.Length >= len + 5)\n                {\n                    \"null/\".CopyTo(destination);\n                    charsWritten = Encoding.UTF8.GetChars(fullKey, destination[5..]) + 5;\n                    return true;\n                }\n            }\n            else if (destination.Length > len)\n            {\n                len = Encoding.UTF8.GetChars(fullKey.AsSpan(0, keyIndex), destination);\n                destination[len++] = '/';\n                charsWritten = Encoding.UTF8.GetChars(fullKey.AsSpan(keyIndex), destination[len..]) + len;\n                return true;\n            }\n\n            charsWritten = 0;\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.hash;\n\n        internal uint GetUniformHashCode() => (uint)hash;\n\n        internal uint GetKeyIndex() => keyIndex;\n\n        /// <summary>\n        /// Returns the <see cref=\"Key\"/> component of this instance as a string.\n        /// </summary>\n        /// <returns>The key component of this instance.</returns>\n        public string GetKeyAsString() => Encoding.UTF8.GetString(fullKey, keyIndex, fullKey.Length - keyIndex);\n\n        /// <summary>\n        /// Returns the <see cref=\"Namespace\"/> component of this instance as a string.\n        /// </summary>\n        /// <returns>The namespace component of this instance.</returns>\n        public string? GetNamespace() => keyIndex == 0 ? null : Encoding.UTF8.GetString(fullKey, 0, keyIndex);\n\n        internal IdSpan GetKeyIdSpan() => keyIndex == 0 ? IdSpan.UnsafeCreate(fullKey, hash) : new(fullKey.AsSpan(keyIndex).ToArray());\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    internal readonly struct InternalChannelId : IEquatable<InternalChannelId>, IComparable<InternalChannelId>, ISerializable, ISpanFormattable\n    {\n        [Id(0)]\n        public readonly ChannelId ChannelId;\n\n        [Id(1)]\n        public readonly string ProviderName;\n\n        public InternalChannelId(string providerName, ChannelId streamId)\n        {\n            ProviderName = providerName;\n            ChannelId = streamId;\n        }\n\n        private InternalChannelId(SerializationInfo info, StreamingContext context)\n        {\n            ProviderName = info.GetString(\"pvn\")!;\n            ChannelId = (ChannelId)info.GetValue(\"sid\", typeof(ChannelId))!;\n        }\n\n        public static implicit operator ChannelId(InternalChannelId internalStreamId) => internalStreamId.ChannelId;\n\n        public bool Equals(InternalChannelId other) => ChannelId.Equals(other) && ProviderName.Equals(other.ProviderName);\n\n        public override bool Equals(object? obj) => obj is InternalChannelId other ? this.Equals(other) : false;\n\n        public static bool operator ==(InternalChannelId s1, InternalChannelId s2) => s1.Equals(s2);\n\n        public static bool operator !=(InternalChannelId s1, InternalChannelId s2) => !s2.Equals(s1);\n\n        public int CompareTo(InternalChannelId other) => ChannelId.CompareTo(other.ChannelId);\n\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"pvn\", ProviderName);\n            info.AddValue(\"sid\", ChannelId, typeof(ChannelId));\n        }\n\n        public override int GetHashCode() => HashCode.Combine(ProviderName, ChannelId);\n\n        public override string ToString() => $\"{ProviderName}/{ChannelId}\";\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"{ProviderName}/{ChannelId}\", out charsWritten);\n\n        internal string? GetNamespace() => ChannelId.GetNamespace();\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/Hosting/BroadcastChannelProviderBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"Default\", \"BroadcastChannel\", \"Client\", typeof(BroadcastChannelProviderBuilder))]\n[assembly: RegisterProvider(\"Default\", \"BroadcastChannel\", \"Silo\", typeof(BroadcastChannelProviderBuilder))]\n\nnamespace Orleans.Providers;\n\ninternal sealed class BroadcastChannelProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddBroadcastChannel(name, options => options.Bind(configurationSection));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddBroadcastChannel(name, options => options.Bind(configurationSection));\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/Hosting/ChannelHostingExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.BroadcastChannel;\nusing Orleans.BroadcastChannel.SubscriberTable;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class ChannelHostingExtensions\n    {\n        /// <summary>\n        /// Add a new broadcast channel to the silo.\n        /// </summary>\n        /// <param name=\"this\">The builder.</param>\n        /// <param name=\"name\">The name of the provider</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        /// <returns></returns>\n        public static ISiloBuilder AddBroadcastChannel(this ISiloBuilder @this, string name, Action<BroadcastChannelOptions> configureOptions)\n        {\n            @this.Services.AddBroadcastChannel(name, ob => ob.Configure(configureOptions));\n            @this.AddGrainExtension<IBroadcastChannelConsumerExtension, BroadcastChannelConsumerExtension>();\n            return @this;\n        }\n\n        /// <summary>\n        /// Add a new broadcast channel to the silo.\n        /// </summary>\n        /// <param name=\"this\">The builder.</param>\n        /// <param name=\"name\">The name of the provider</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static ISiloBuilder AddBroadcastChannel(this ISiloBuilder @this, string name, Action<OptionsBuilder<BroadcastChannelOptions>> configureOptions = null)\n        {\n            @this.Services.AddBroadcastChannel(name, configureOptions);\n            @this.AddGrainExtension<IBroadcastChannelConsumerExtension, BroadcastChannelConsumerExtension>();\n            return @this;\n        }\n\n        /// <summary>\n        /// Add a new broadcast channel to the client.\n        /// </summary>\n        /// <param name=\"this\">The builder.</param>\n        /// <param name=\"name\">The name of the provider</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static IClientBuilder AddBroadcastChannel(this IClientBuilder @this, string name, Action<BroadcastChannelOptions> configureOptions)\n        {\n            @this.Services.AddBroadcastChannel(name, ob => ob.Configure(configureOptions));\n            return @this;\n        }\n\n        /// <summary>\n        /// Add a new broadcast channel to the client.\n        /// </summary>\n        /// <param name=\"this\">The builder.</param>\n        /// <param name=\"name\">The name of the provider</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static IClientBuilder AddBroadcastChannel(this IClientBuilder @this, string name, Action<OptionsBuilder<BroadcastChannelOptions>> configureOptions = null)\n        {\n            @this.Services.AddBroadcastChannel(name, configureOptions);\n            return @this;\n        }\n\n        /// <summary>\n        /// Get the named broadcast channel provided.\n        /// </summary>\n        /// <param name=\"this\">The client.</param>\n        /// <param name=\"name\">The name of the provider</param>\n        public static IBroadcastChannelProvider GetBroadcastChannelProvider(this IClusterClient @this, string name)\n            => @this.ServiceProvider.GetRequiredKeyedService<IBroadcastChannelProvider>(name);\n\n        private static void AddBroadcastChannel(this IServiceCollection services, string name, Action<OptionsBuilder<BroadcastChannelOptions>> configureOptions)\n        {\n            configureOptions?.Invoke(services.AddOptions<BroadcastChannelOptions>(name));\n            services.ConfigureNamedOptionForLogging<BroadcastChannelOptions>(name);\n            services\n                .AddSingleton<ImplicitChannelSubscriberTable>()\n                .AddSingleton<IChannelNamespacePredicateProvider, DefaultChannelNamespacePredicateProvider>()\n                .AddSingleton<IChannelNamespacePredicateProvider, ConstructorChannelNamespacePredicateProvider>()\n                .AddKeyedSingleton<IChannelIdMapper, DefaultChannelIdMapper>(DefaultChannelIdMapper.Name)\n                .AddKeyedSingleton(name, (sp, key) => BroadcastChannelProvider.Create(sp, key as string));\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/IdMapping/DefaultChannelIdMapper.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\n#nullable enable\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// The default <see cref=\"IChannelIdMapper\"/> implementation.\n    /// </summary>\n    public sealed class DefaultChannelIdMapper : IChannelIdMapper\n    {\n        /// <summary>\n        /// The name of this stream identity mapper.\n        /// </summary>\n        public const string Name = \"default\";\n\n        /// <inheritdoc />\n        public IdSpan GetGrainKeyId(GrainBindings grainBindings, ChannelId streamId)\n        {\n            string? keyType = null;\n            bool includeNamespaceInGrainId = false;\n\n            foreach (var grainBinding in grainBindings.Bindings)\n            {\n                if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BindingTypeKey, out var type)\n                        || !string.Equals(type, WellKnownGrainTypeProperties.BroadcastChannelBindingTypeValue, StringComparison.Ordinal))\n                {\n                    continue;\n                }\n\n                if (grainBinding.TryGetValue(WellKnownGrainTypeProperties.LegacyGrainKeyType, out keyType))\n                {\n                    if (grainBinding.TryGetValue(WellKnownGrainTypeProperties.StreamBindingIncludeNamespaceKey, out var value)\n                        && string.Equals(value, \"true\", StringComparison.OrdinalIgnoreCase))\n                    {\n                        includeNamespaceInGrainId = true;\n                    }\n                }\n            }\n\n            return keyType switch\n            {\n                nameof(Guid) => GetGuidKey(streamId, includeNamespaceInGrainId),\n                nameof(Int64) => GetIntegerKey(streamId, includeNamespaceInGrainId),\n                _ => streamId.GetKeyIdSpan(), // null or string\n            };\n        }\n\n        private static IdSpan GetGuidKey(ChannelId streamId, bool includeNamespaceInGrainId)\n        {\n            var key = streamId.Key.Span;\n            if (!Utf8Parser.TryParse(key, out Guid guidKey, out var len, 'N') || len < key.Length) throw new ArgumentException(nameof(streamId));\n\n            if (!includeNamespaceInGrainId)\n                return streamId.GetKeyIdSpan();\n\n            var ns = streamId.Namespace.Span;\n            return ns.IsEmpty ? streamId.GetKeyIdSpan() : GrainIdKeyExtensions.CreateGuidKey(guidKey, ns);\n        }\n\n        private static IdSpan GetIntegerKey(ChannelId streamId, bool includeNamespaceInGrainId)\n        {\n            var key = streamId.Key.Span;\n            if (!Utf8Parser.TryParse(key, out int intKey, out var len) || len < key.Length) throw new ArgumentException(nameof(streamId));\n\n            return includeNamespaceInGrainId\n                ? GrainIdKeyExtensions.CreateIntegerKey(intKey, streamId.Namespace.Span)\n                : GrainIdKeyExtensions.CreateIntegerKey(intKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/IdMapping/IChannelIdMapper.cs",
    "content": "using Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Common interface for component that map a <see cref=\"ChannelId\"/> to a <see cref=\"GrainId.Key\"/>\n    /// </summary>\n    public interface IChannelIdMapper\n    {\n        /// <summary>\n        /// Get the <see cref=\"GrainId.Key\" /> which maps to the provided <see cref=\"ChannelId\" />\n        /// </summary>\n        /// <param name=\"grainBindings\">The grain bindings.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>The <see cref=\"GrainId.Key\"/> component.</returns>\n        IdSpan GetGrainKeyId(GrainBindings grainBindings, ChannelId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/Orleans.BroadcastChannel.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.BroadcastChannel</PackageId>\n    <Title>Microsoft Orleans Broadcast Channel Library</Title>\n    <Description>Broadcast Channel library for Microsoft Orleans used both on the client and server.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/ImplicitChannelSubscriberTable.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.BroadcastChannel.SubscriberTable\n{\n    internal class ImplicitChannelSubscriberTable\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly GrainBindingsResolver _bindings;\n        private readonly IChannelNamespacePredicateProvider[] _providers;\n        private readonly IServiceProvider _serviceProvider;\n        private Cache _cache;\n\n        public ImplicitChannelSubscriberTable(\n            GrainBindingsResolver bindings,\n            IEnumerable<IChannelNamespacePredicateProvider> providers,\n            IServiceProvider serviceProvider)\n        {\n            _bindings = bindings;\n            var initialBindings = bindings.GetAllBindings();\n            _providers = providers.ToArray();\n            _serviceProvider = serviceProvider;\n            _cache = BuildCache(initialBindings.Version, initialBindings.Bindings);\n        }\n\n        private Cache GetCache()\n        {\n            var cache = _cache;\n            var bindings = _bindings.GetAllBindings();\n            if (bindings.Version == cache.Version)\n            {\n                return cache;\n            }\n\n            lock (_lockObj)\n            {\n                bindings = _bindings.GetAllBindings();\n                if (bindings.Version == cache.Version)\n                {\n                    return cache;\n                }\n\n                return _cache = BuildCache(bindings.Version, bindings.Bindings);\n            }\n        }\n\n        private Cache BuildCache(MajorMinorVersion version, ImmutableDictionary<GrainType, GrainBindings> bindings)\n        {\n            var newPredicates = new List<BroadcastChannelSubscriberPredicate>();\n\n            foreach (var binding in bindings.Values)\n            {\n                foreach (var grainBinding in binding.Bindings)\n                {\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BindingTypeKey, out var type)\n                        || type != WellKnownGrainTypeProperties.BroadcastChannelBindingTypeValue)\n                    {\n                        continue;\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey, out var pattern))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Channel binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey}\\\" value\");\n                    }\n\n                    IChannelNamespacePredicate predicate = null;\n                    foreach (var provider in _providers)\n                    {\n                        if (provider.TryGetPredicate(pattern, out predicate)) break;\n                    }\n\n                    if (predicate is null)\n                    {\n                        throw new KeyNotFoundException(\n                            $\"Could not find an {nameof(IChannelNamespacePredicate)} for the pattern \\\"{pattern}\\\".\"\n                            + $\" Ensure that a corresponding {nameof(IChannelNamespacePredicateProvider)} is registered\");\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.ChannelIdMapperKey, out var mapperName))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Channel binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.ChannelIdMapperKey}\\\" value\");\n                    }\n\n                    var channelIdMapper = _serviceProvider.GetKeyedService<IChannelIdMapper>(string.IsNullOrWhiteSpace(mapperName) ? DefaultChannelIdMapper.Name : mapperName);\n                    var subscriber = new BroadcastChannelSubscriber(binding, channelIdMapper);\n                    newPredicates.Add(new BroadcastChannelSubscriberPredicate(subscriber, predicate));\n                }\n            }\n\n            return new Cache(version, newPredicates);\n        }\n\n        /// <summary>\n        /// Retrieve a map of implicit subscriptionsIds to implicit subscribers, given a channel ID. This method throws an exception if there's no namespace associated with the channel ID.\n        /// </summary>\n        /// <param name=\"channelId\">A channel ID.</param>\n        /// <param name=\"grainFactory\">The grain factory used to get consumer references.</param>\n        /// <returns>A set of references to implicitly subscribed grains. They are expected to support the broadcast channel consumer extension.</returns>\n        /// <exception cref=\"ArgumentException\">The channel ID doesn't have an associated namespace.</exception>\n        /// <exception cref=\"InvalidOperationException\">Internal invariant violation.</exception>\n        internal Dictionary<Guid, IBroadcastChannelConsumerExtension> GetImplicitSubscribers(InternalChannelId channelId, IGrainFactory grainFactory)\n        {\n            var channelNamespace = channelId.GetNamespace();\n            if (string.IsNullOrWhiteSpace(channelNamespace))\n            {\n                throw new ArgumentException(\"The channel ID doesn't have an associated namespace.\", nameof(channelId));\n            }\n\n            var entries = GetOrAddImplicitSubscribers(channelNamespace);\n\n            var result = new Dictionary<Guid, IBroadcastChannelConsumerExtension>();\n            foreach (var entry in entries)\n            {\n                var consumer = MakeConsumerReference(grainFactory, channelId, entry);\n                var subscriptionGuid = MakeSubscriptionGuid(entry.GrainType, channelId);\n                CollectionsMarshal.GetValueRefOrAddDefault(result, subscriptionGuid, out var duplicate) = consumer;\n                if (duplicate)\n                {\n                    throw new InvalidOperationException(\n                        $\"Internal invariant violation: generated duplicate subscriber reference: {consumer}, subscriptionId: {subscriptionGuid}\");\n                }\n            }\n            return result;\n        }\n\n        private HashSet<BroadcastChannelSubscriber> GetOrAddImplicitSubscribers(string channelNamespace)\n        {\n            var cache = GetCache();\n            if (cache.Namespaces.TryGetValue(channelNamespace, out var result))\n            {\n                return result;\n            }\n\n            return cache.Namespaces.GetOrAdd(channelNamespace, FindImplicitSubscribers(channelNamespace, cache.Predicates));\n        }\n\n        /// <summary>\n        /// Create a subscriptionId that is unique per grainId, grainType, namespace combination.\n        /// </summary>\n        private Guid MakeSubscriptionGuid(GrainType grainType, InternalChannelId channelId)\n        {\n            Span<byte> bytes = stackalloc byte[16];\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes, grainType.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[4..], channelId.ChannelId.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[8..], channelId.ChannelId.GetKeyIndex());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[12..], StableHash.ComputeHash(channelId.ProviderName));\n            bytes[15] |= 0x80; // set high bit of last byte (implicit subscription)\n            return new(bytes);\n        }\n\n        /// <summary>\n        /// Finds all implicit subscribers for the given channel namespace.\n        /// </summary>\n        private static HashSet<BroadcastChannelSubscriber> FindImplicitSubscribers(string channelNamespace, List<BroadcastChannelSubscriberPredicate> predicates)\n        {\n            var result = new HashSet<BroadcastChannelSubscriber>();\n            foreach (var predicate in predicates)\n            {\n                if (predicate.Predicate.IsMatch(channelNamespace))\n                {\n                    result.Add(predicate.Subscriber);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Create a reference to a grain that we expect to support the broadcast channel consumer extension.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory used to get consumer references.</param>\n        /// <param name=\"channelId\">The channel ID to use for the grain ID construction.</param>\n        /// <param name=\"channelSubscriber\">The GrainBindings for the grain to create</param>\n        /// <returns></returns>\n        private static IBroadcastChannelConsumerExtension MakeConsumerReference(\n            IGrainFactory grainFactory,\n            InternalChannelId channelId,\n            BroadcastChannelSubscriber channelSubscriber)\n        {\n            var grainId = channelSubscriber.GetGrainId(channelId);\n            return grainFactory.GetGrain<IBroadcastChannelConsumerExtension>(grainId);\n        }\n\n        private class BroadcastChannelSubscriberPredicate\n        {\n            public BroadcastChannelSubscriberPredicate(BroadcastChannelSubscriber subscriber, IChannelNamespacePredicate predicate)\n            {\n                Subscriber = subscriber;\n                Predicate = predicate;\n            }\n\n            public BroadcastChannelSubscriber Subscriber { get; }\n            public IChannelNamespacePredicate Predicate { get; }\n        }\n\n        private sealed class BroadcastChannelSubscriber : IEquatable<BroadcastChannelSubscriber>\n        {\n            public BroadcastChannelSubscriber(GrainBindings grainBindings, IChannelIdMapper channelIdMapper)\n            {\n                GrainBindings = grainBindings;\n                this.channelIdMapper = channelIdMapper;\n            }\n\n            public GrainType GrainType => GrainBindings.GrainType;\n\n            private GrainBindings GrainBindings { get; }\n\n            private IChannelIdMapper channelIdMapper { get; }\n\n            public override bool Equals(object obj) => Equals(obj as BroadcastChannelSubscriber);\n\n            public bool Equals(BroadcastChannelSubscriber other) => other != null && GrainType.Equals(other.GrainType);\n\n            public override int GetHashCode() => GrainType.GetHashCode();\n\n            internal GrainId GetGrainId(InternalChannelId channelId)\n            {\n                var grainKeyId = channelIdMapper.GetGrainKeyId(GrainBindings, channelId);\n                return GrainId.Create(GrainType, grainKeyId);\n            }\n        }\n\n        private class Cache\n        {\n            public Cache(MajorMinorVersion version, List<BroadcastChannelSubscriberPredicate> predicates)\n            {\n                Version = version;\n                Predicates = predicates;\n                Namespaces = new ConcurrentDictionary<string, HashSet<BroadcastChannelSubscriber>>();\n            }\n\n            public MajorMinorVersion Version { get; }\n            public ConcurrentDictionary<string, HashSet<BroadcastChannelSubscriber>> Namespaces { get; }\n            public List<BroadcastChannelSubscriberPredicate> Predicates { get; }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/AllStreamNamespacesPredicate.cs",
    "content": "namespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// A stream namespace predicate which matches all namespaces.\n    /// </summary>\n    internal class AllStreamNamespacesPredicate : IChannelNamespacePredicate\n    {\n        /// <inheritdoc/>\n        public string PredicatePattern => \"*\";\n\n        /// <inheritdoc/>\n        public bool IsMatch(string streamNamespace)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/DefaultStreamNamespacePredicateProvider.cs",
    "content": "using System;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Default implementation of <see cref=\"IChannelNamespacePredicateProvider\"/> for internally supported stream predicates.\n    /// </summary>\n    public class DefaultChannelNamespacePredicateProvider : IChannelNamespacePredicateProvider\n    {  \n        /// <inheritdoc/>\n        public bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate)\n        {\n            switch (predicatePattern)\n            {\n                case \"*\":\n                    predicate = new AllStreamNamespacesPredicate();\n                    return true;\n                case var regex when regex.StartsWith(RegexChannelNamespacePredicate.Prefix, StringComparison.Ordinal):\n                    predicate = new RegexChannelNamespacePredicate(regex[RegexChannelNamespacePredicate.Prefix.Length..]);\n                    return true;\n                case var ns when ns.StartsWith(ExactMatchChannelNamespacePredicate.Prefix, StringComparison.Ordinal):\n                    predicate = new ExactMatchChannelNamespacePredicate(ns[ExactMatchChannelNamespacePredicate.Prefix.Length..]);\n                    return true;\n            }\n\n            predicate = null;\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Stream namespace predicate provider which supports objects which can be constructed and optionally accept a string as a constructor argument.\n    /// </summary>\n    public class ConstructorChannelNamespacePredicateProvider : IChannelNamespacePredicateProvider\n    {\n        /// <summary>\n        /// The prefix used to identify this predicate provider.\n        /// </summary>\n        public const string Prefix = \"ctor\";\n\n        /// <summary>\n        /// Formats a stream namespace predicate which indicates a concrete <see cref=\"IChannelNamespacePredicate\"/> type to be constructed, along with an optional argument.\n        /// </summary>\n        public static string FormatPattern(Type predicateType, string constructorArgument)\n        {\n            if (constructorArgument is null)\n            {\n                return $\"{Prefix}:{RuntimeTypeNameFormatter.Format(predicateType)}\";\n            }\n\n            return $\"{Prefix}:{RuntimeTypeNameFormatter.Format(predicateType)}:{constructorArgument}\";\n        }\n\n        /// <inheritdoc/>\n        public bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate)\n        {\n            if (!predicatePattern.StartsWith(Prefix, StringComparison.Ordinal))\n            {\n                predicate = null;\n                return false;\n            }\n\n            var start = Prefix.Length + 1;\n            string typeName;\n            string arg;\n            var index = predicatePattern.IndexOf(':', start);\n            if (index < 0)\n            {\n                typeName = predicatePattern[start..];\n                arg = null;\n            }\n            else\n            {\n                typeName = predicatePattern[start..index];\n                arg = predicatePattern[(index + 1)..];\n            }\n\n            var type = Type.GetType(typeName, throwOnError: true);\n            if (string.IsNullOrEmpty(arg))\n            {\n                predicate = (IChannelNamespacePredicate)Activator.CreateInstance(type);\n            }\n            else\n            {\n                predicate = (IChannelNamespacePredicate)Activator.CreateInstance(type, arg);\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/ExactMatchStreamNamespacePredicate.cs",
    "content": "using System;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Stream namespace predicate which matches exactly one, specified\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class ExactMatchChannelNamespacePredicate : IChannelNamespacePredicate\n    {\n        internal const string Prefix = \"namespace:\";\n\n        [Id(0)]\n        private readonly string targetStreamNamespace;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExactMatchChannelNamespacePredicate\"/> class.\n        /// </summary>\n        /// <param name=\"targetStreamNamespace\">The target stream namespace.</param>\n        public ExactMatchChannelNamespacePredicate(string targetStreamNamespace)\n        {\n            this.targetStreamNamespace = targetStreamNamespace;\n        }\n\n        /// <inheritdoc/>\n        public string PredicatePattern => $\"{Prefix}{this.targetStreamNamespace}\";\n\n        /// <inheritdoc/>\n        public bool IsMatch(string streamNamespace)\n        {\n            return string.Equals(targetStreamNamespace, streamNamespace?.Trim());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/IChannelNamespacePredicate.cs",
    "content": "namespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// Stream namespace predicate used for filtering implicit subscriptions using \n    /// <see cref=\"ImplicitChannelSubscriptionAttribute\"/>.\n    /// </summary>\n    /// <remarks>All implementations must be serializable.</remarks>\n    public interface IChannelNamespacePredicate\n    {\n        /// <summary>\n        /// Defines if the consumer grain should subscribe to the specified namespace.\n        /// </summary>\n        /// <param name=\"streamNamespace\">The target stream namespace to check.</param>\n        /// <returns><c>true</c>, if the grain should subscribe to the specified namespace; <c>false</c>, otherwise.\n        /// </returns>\n        bool IsMatch(string streamNamespace);\n\n        /// <summary>\n        /// Gets a pattern to describe this predicate. This value is passed to instances of <see cref=\"IChannelNamespacePredicateProvider\"/> to recreate this predicate.\n        /// </summary>\n        string PredicatePattern { get; }\n    }\n\n    /// <summary>\n    /// Converts predicate pattern strings to <see cref=\"IChannelNamespacePredicate\"/> instances.\n    /// </summary>\n    /// <seealso cref=\"IChannelNamespacePredicate.PredicatePattern\"/>\n    public interface IChannelNamespacePredicateProvider\n    {\n        /// <summary>\n        /// Get the predicate matching the provided pattern. Returns <see langword=\"false\"/> if this provider cannot match the predicate.\n        /// </summary>\n        bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate);\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/ImplicitChannelSubscriptionAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.BroadcastChannel;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// The [Orleans.ImplicitStreamSubscription] attribute is used to mark grains as implicit stream subscriptions.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public class ImplicitChannelSubscriptionAttribute : Attribute, IGrainBindingsProviderAttribute\n    {\n        /// <summary>\n        /// Gets the stream namespace filter predicate.\n        /// </summary>\n        public IChannelNamespacePredicate Predicate { get; }\n\n        /// <summary>\n        /// Gets the name of the channel identifier mapper.\n        /// </summary>\n        /// <value>The name of the channel identifier mapper.</value>\n        public string ChannelIdMapper { get; }\n\n        /// <summary>\n        /// Used to subscribe to all stream namespaces.\n        /// </summary>\n        public ImplicitChannelSubscriptionAttribute()\n        {\n            Predicate = new AllStreamNamespacesPredicate();\n        }\n\n        /// <summary>\n        /// Used to subscribe to the specified stream namespace.\n        /// </summary>\n        /// <param name=\"streamNamespace\">The stream namespace to subscribe.</param>\n        /// <param name=\"channelIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitChannelSubscriptionAttribute(string streamNamespace, string channelIdMapper = null)\n        {\n            Predicate = new ExactMatchChannelNamespacePredicate(streamNamespace.Trim());\n            ChannelIdMapper = channelIdMapper;\n        }\n\n        /// <summary>\n        /// Allows to pass an arbitrary predicate type to filter stream namespaces to subscribe. The predicate type \n        /// must have a constructor without parameters.\n        /// </summary>\n        /// <param name=\"predicateType\">The stream namespace predicate type.</param>\n        /// <param name=\"channelIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitChannelSubscriptionAttribute(Type predicateType, string channelIdMapper = null)\n        {\n            Predicate = (IChannelNamespacePredicate) Activator.CreateInstance(predicateType);\n            ChannelIdMapper = channelIdMapper;\n        }\n\n        /// <summary>\n        /// Allows to pass an instance of the stream namespace predicate. To be used mainly as an extensibility point\n        /// via inheriting attributes.\n        /// </summary>\n        /// <param name=\"predicate\">The stream namespace predicate.</param>\n        /// <param name=\"channelIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitChannelSubscriptionAttribute(IChannelNamespacePredicate predicate, string channelIdMapper = null)\n        {\n            Predicate = predicate;\n            ChannelIdMapper = channelIdMapper;\n        }\n\n        /// <inheritdoc />\n        public IEnumerable<Dictionary<string, string>> GetBindings(IServiceProvider services, Type grainClass, GrainType grainType)\n        {\n            var binding = new Dictionary<string, string>\n            {\n                [WellKnownGrainTypeProperties.BindingTypeKey] = WellKnownGrainTypeProperties.BroadcastChannelBindingTypeValue,\n                [WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey] = this.Predicate.PredicatePattern,\n                [WellKnownGrainTypeProperties.ChannelIdMapperKey] = this.ChannelIdMapper,\n            };\n\n            if (LegacyGrainId.IsLegacyGrainType(grainClass))\n            {\n                string keyType;\n\n                if (typeof(IGrainWithGuidKey).IsAssignableFrom(grainClass) || typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(grainClass))\n                    keyType = nameof(Guid);\n                else if (typeof(IGrainWithIntegerKey).IsAssignableFrom(grainClass) || typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(grainClass))\n                    keyType = nameof(Int64);\n                else // fallback to string\n                    keyType = nameof(String);\n\n                binding[WellKnownGrainTypeProperties.LegacyGrainKeyType] = keyType;\n            }\n\n            if (LegacyGrainId.IsLegacyKeyExtGrainType(grainClass))\n            {\n                binding[WellKnownGrainTypeProperties.StreamBindingIncludeNamespaceKey] = \"true\";\n            }\n\n            yield return binding;\n        }\n    }\n\n    /// <summary>\n    /// The [Orleans.RegexImplicitStreamSubscription] attribute is used to mark grains as implicit stream\n    /// subscriptions by filtering stream namespaces to subscribe using a regular expression.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public sealed class RegexImplicitChannelSubscriptionAttribute : ImplicitChannelSubscriptionAttribute\n    {\n        /// <summary>\n        /// Allows to pass a regular expression to filter stream namespaces to subscribe to.\n        /// </summary>\n        /// <param name=\"pattern\">The stream namespace regular expression filter.</param>\n        public RegexImplicitChannelSubscriptionAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string pattern)\n            : base(new RegexChannelNamespacePredicate(pattern))\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.BroadcastChannel/SubscriberTable/Predicates/RegexChannelNamespacePredicate.cs",
    "content": "using System;\nusing System.Text.RegularExpressions;\n\nnamespace Orleans.BroadcastChannel\n{\n    /// <summary>\n    /// <see cref=\"IChannelNamespacePredicate\"/> implementation allowing to filter stream namespaces by regular\n    /// expression.\n    /// </summary>\n    public class RegexChannelNamespacePredicate : IChannelNamespacePredicate\n    {\n        internal const string Prefix = \"regex:\";\n        private readonly Regex regex;\n\n        /// <summary>\n        /// Returns a pattern used to describe this instance. The pattern will be parsed by an <see cref=\"IChannelNamespacePredicateProvider\"/> instance on each node.\n        /// </summary>\n        public string PredicatePattern => $\"{Prefix}{regex}\";\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"RegexChannelNamespacePredicate\"/> with the specified regular expression.\n        /// </summary>\n        /// <param name=\"regex\">The stream namespace regular expression.</param>\n        public RegexChannelNamespacePredicate(string regex)\n        {\n            if (regex is null) throw new ArgumentNullException(nameof(regex));\n            \n            this.regex = new Regex(regex, RegexOptions.Compiled);\n        }\n\n        /// <inheritdoc />\n        public bool IsMatch(string streamNameSpace)\n        {\n            return regex.IsMatch(streamNameSpace);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Client/Orleans.Client.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Client</PackageId>\n    <Title>Microsoft Orleans Client Libraries</Title>\n    <Description>Collection of Microsoft Orleans libraries and files needed on the client.</Description>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <NoPackageAnalysis>true</NoPackageAnalysis>\n    <IncludeSymbols>false</IncludeSymbols>\n    <IncludeSource>false</IncludeSource>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Client/README.md",
    "content": "# Microsoft Orleans Client\n\n## Introduction\nMicrosoft Orleans Client is a metapackage that includes all the necessary components to connect to an Orleans cluster from a client application. It provides a simplified way to set up an Orleans client by providing a single package reference rather than requiring you to reference multiple packages individually.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Client\n```\n\n## Example - Creating an Orleans Client\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\nnamespace ExampleGrains;\n\n// Define a grain interface\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<string> DoSomething();\n}\n\n\n// Create a client\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(client =>\n    {\n        client.UseLocalhostClustering();\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IMyGrain>(\"my-grain-id\");\nvar result = await grain.DoSomething();\n\n// Print the result\nConsole.WriteLine($\"Result: {result}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans client configuration](https://learn.microsoft.com/en-us/dotnet/orleans/host/client)\n- [Grain references](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-references)\n- [Orleans request context](https://learn.microsoft.com/en-us/dotnet/orleans/grains/request-context)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Clustering.Consul/ConsulBasedMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Consul;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Host;\n\nnamespace Orleans.Runtime.Membership\n{\n    /// <summary>\n    /// A Membership Table implementation using Consul 0.6.0  https://consul.io/\n    /// </summary>\n    public partial class ConsulBasedMembershipTable : IMembershipTable\n    {\n        private static readonly TableVersion NotFoundTableVersion = new TableVersion(0, \"0\");\n        private readonly ILogger _logger;\n        private readonly IConsulClient _consulClient;\n        private readonly ConsulClusteringOptions clusteringSiloTableOptions;\n        private readonly string clusterId;\n        private readonly string kvRootFolder;\n        private readonly string versionKey;\n\n        public ConsulBasedMembershipTable(\n            ILogger<ConsulBasedMembershipTable> logger,\n            IOptions<ConsulClusteringOptions> membershipTableOptions, \n            IOptions<ClusterOptions> clusterOptions)\n        {\n            this.clusterId = clusterOptions.Value.ClusterId;\n            this.kvRootFolder = membershipTableOptions.Value.KvRootFolder;\n            this._logger = logger;\n            this.clusteringSiloTableOptions = membershipTableOptions.Value;\n            this._consulClient = this.clusteringSiloTableOptions.CreateClient();\n            versionKey = ConsulSiloRegistrationAssembler.FormatVersionKey(clusterId, kvRootFolder);\n        }\n\n        /// <summary>\n        /// Initializes the Consul based membership table.\n        /// </summary>\n        /// <param name=\"tryInitTableVersion\">Will be ignored: Consul does not support the extended Membership Protocol TableVersion</param>\n        /// <returns></returns>\n        /// <remarks>\n        /// Consul Membership Provider does not support the extended Membership Protocol,\n        /// therefore there is no MembershipTable to Initialize\n        /// </remarks>\n        public Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            return Task.CompletedTask;\n        }\n\n\n        public async Task<MembershipTableData> ReadRow(SiloAddress siloAddress)\n        {\n            var (siloRegistration, tableVersion) = await GetConsulSiloRegistration(siloAddress);\n\n            return AssembleMembershipTableData(tableVersion, siloRegistration);\n        }\n\n        public Task<MembershipTableData> ReadAll()\n        {\n            return ReadAll(this._consulClient, this.clusterId, this.kvRootFolder, this._logger, this.versionKey);\n        }\n\n        public static async Task<MembershipTableData> ReadAll(IConsulClient consulClient, string clusterId, string kvRootFolder, ILogger logger, string versionKey)\n        {\n            var deploymentKVAddresses = await consulClient.KV.List(ConsulSiloRegistrationAssembler.FormatDeploymentKVPrefix(clusterId, kvRootFolder));\n            if (deploymentKVAddresses.Response == null)\n            {\n                LogDebugCouldNotFindSiloRegistrations(logger, clusterId);\n                return new MembershipTableData(NotFoundTableVersion);\n            }\n\n            var allSiloRegistrations =\n                deploymentKVAddresses.Response\n                .Where(siloKV => !siloKV.Key.EndsWith(ConsulSiloRegistrationAssembler.SiloIAmAliveSuffix, StringComparison.OrdinalIgnoreCase)\n                        && !siloKV.Key.EndsWith(ConsulSiloRegistrationAssembler.VersionSuffix, StringComparison.OrdinalIgnoreCase))\n                .Select(siloKV =>\n                {\n                    var iAmAliveKV = deploymentKVAddresses.Response.SingleOrDefault(kv => kv.Key.Equals(ConsulSiloRegistrationAssembler.FormatSiloIAmAliveKey(siloKV.Key), StringComparison.OrdinalIgnoreCase));\n                    return ConsulSiloRegistrationAssembler.FromKVPairs(clusterId, siloKV, iAmAliveKV);\n                }).ToArray();\n\n            var tableVersion = GetTableVersion(versionKey, deploymentKVAddresses);\n\n            return AssembleMembershipTableData(tableVersion, allSiloRegistrations);\n        }\n\n        public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            try\n            {\n                //Use \"0\" as the eTag then Consul KV CAS will treat the operation as an insert and return false if the KV already exiats.\n                var siloRegistration = ConsulSiloRegistrationAssembler.FromMembershipEntry(this.clusterId, entry, \"0\");\n                var insertKV = ConsulSiloRegistrationAssembler.ToKVPair(siloRegistration, this.kvRootFolder);\n                var rowInsert = new KVTxnOp(insertKV.Key, KVTxnVerb.CAS) { Index = siloRegistration.LastIndex, Value = insertKV.Value };\n                var versionUpdate = this.GetVersionRowUpdate(tableVersion);\n\n                var responses = await _consulClient.KV.Txn(new List<KVTxnOp> { rowInsert, versionUpdate });\n                if (!responses.Response.Success)\n                {\n                    LogDebugConsulMembershipProviderFailedToInsertRow(entry.SiloAddress);\n                    return false;\n                }\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                LogInformationConsulMembershipProviderFailedToInsertRegistration(ex, entry.SiloAddress);\n                throw;\n            }\n        }\n\n        public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            //Update Silo Liveness\n            try\n            {\n                var siloRegistration = ConsulSiloRegistrationAssembler.FromMembershipEntry(this.clusterId, entry, etag);\n                var updateKV = ConsulSiloRegistrationAssembler.ToKVPair(siloRegistration, this.kvRootFolder);\n\n                var rowUpdate = new KVTxnOp(updateKV.Key, KVTxnVerb.CAS) { Index = siloRegistration.LastIndex, Value = updateKV.Value };\n                var versionUpdate = this.GetVersionRowUpdate(tableVersion);\n\n                var responses = await _consulClient.KV.Txn(new List<KVTxnOp> { rowUpdate, versionUpdate });\n                if (!responses.Response.Success)\n                {\n                    LogDebugConsulMembershipProviderFailedCASCheck(entry.SiloAddress);\n                    return false;\n                }\n\n                return true;\n            }\n            catch (Exception ex)\n            {\n                LogInformationConsulMembershipProviderFailedToUpdateRegistration(ex, entry.SiloAddress);\n                throw;\n            }\n        }\n\n        public async Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            var iAmAliveKV = ConsulSiloRegistrationAssembler.ToIAmAliveKVPair(this.clusterId, this.kvRootFolder, entry.SiloAddress, entry.IAmAliveTime);\n            await _consulClient.KV.Put(iAmAliveKV);\n        }\n\n        public async Task DeleteMembershipTableEntries(string clusterId)\n        {\n            await _consulClient.KV.DeleteTree(ConsulSiloRegistrationAssembler.FormatDeploymentKVPrefix(this.clusterId, this.kvRootFolder));\n        }\n\n        private static TableVersion GetTableVersion(string versionKey, QueryResult<KVPair[]> entries)\n        {\n            TableVersion tableVersion;\n            var tableVersionEntry = entries?.Response?.FirstOrDefault(kv => kv.Key.Equals(versionKey ?? string.Empty, StringComparison.OrdinalIgnoreCase));\n            if (tableVersionEntry != null)\n            {\n                var versionNumber = 0;\n                if (tableVersionEntry.Value is byte[] versionData && versionData.Length > 0)\n                {\n                    int.TryParse(Encoding.UTF8.GetString(tableVersionEntry.Value), out versionNumber);\n                }\n\n                tableVersion = new TableVersion(versionNumber, tableVersionEntry.ModifyIndex.ToString(CultureInfo.InvariantCulture));\n            }\n            else\n            {\n                tableVersion = NotFoundTableVersion;\n            }\n\n            return tableVersion;\n        }\n\n        private KVTxnOp GetVersionRowUpdate(TableVersion version)\n        {\n            ulong.TryParse(version.VersionEtag, out var index);\n            var versionBytes = Encoding.UTF8.GetBytes(version.Version.ToString(CultureInfo.InvariantCulture));\n            return new KVTxnOp(this.versionKey, KVTxnVerb.CAS) { Index = index, Value = versionBytes };\n        }\n\n        private async Task<(ConsulSiloRegistration, TableVersion)> GetConsulSiloRegistration(SiloAddress siloAddress)\n        {\n            var deploymentKey = ConsulSiloRegistrationAssembler.FormatDeploymentKVPrefix(this.clusterId, this.kvRootFolder);\n            var siloKey = ConsulSiloRegistrationAssembler.FormatDeploymentSiloKey(this.clusterId, this.kvRootFolder, siloAddress);\n            var entries = await _consulClient.KV.List(deploymentKey);\n            if (entries.Response == null) return (null, NotFoundTableVersion);\n\n            var siloKV = entries.Response.Single(KV => KV.Key.Equals(siloKey, StringComparison.OrdinalIgnoreCase));\n            var iAmAliveKV = entries.Response.SingleOrDefault(KV => KV.Key.Equals(ConsulSiloRegistrationAssembler.FormatSiloIAmAliveKey(siloKey), StringComparison.OrdinalIgnoreCase));\n            var tableVersion = GetTableVersion(versionKey: versionKey, entries: entries);\n\n            var siloRegistration = ConsulSiloRegistrationAssembler.FromKVPairs(this.clusterId, siloKV, iAmAliveKV);\n\n            return (siloRegistration, tableVersion);\n        }\n\n        private static MembershipTableData AssembleMembershipTableData(TableVersion tableVersion, params ConsulSiloRegistration[] silos)\n        {\n            var membershipEntries = silos\n                .Where(silo => silo != null)\n                .Select(silo => ConsulSiloRegistrationAssembler.ToMembershipEntry(silo))\n                .ToList();\n\n            return new MembershipTableData(membershipEntries, tableVersion);\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            var allKVs = await _consulClient.KV.List(ConsulSiloRegistrationAssembler.FormatDeploymentKVPrefix(this.clusterId, this.kvRootFolder));\n            if (allKVs.Response == null)\n            {\n                LogDebugCouldNotFindSiloRegistrationsForCleanup(this.clusterId);\n                return;\n            }\n\n            var allRegistrations =\n                allKVs.Response\n                .Where(siloKV => !siloKV.Key.EndsWith(ConsulSiloRegistrationAssembler.SiloIAmAliveSuffix, StringComparison.OrdinalIgnoreCase)\n                    && !siloKV.Key.EndsWith(ConsulSiloRegistrationAssembler.VersionSuffix, StringComparison.OrdinalIgnoreCase))\n                .Select(siloKV =>\n                {\n                    var iAmAliveKV = allKVs.Response.SingleOrDefault(kv => kv.Key.Equals(ConsulSiloRegistrationAssembler.FormatSiloIAmAliveKey(siloKV.Key), StringComparison.OrdinalIgnoreCase));\n                    return new\n                    {\n                        RegistrationKey = siloKV.Key,\n                        Registration = ConsulSiloRegistrationAssembler.FromKVPairs(clusterId, siloKV, iAmAliveKV)\n                    };\n                }).ToArray();\n\n            foreach (var entry in allRegistrations)\n            {\n                if (entry.Registration.IAmAliveTime < beforeDate && entry.Registration.Status != SiloStatus.Active)\n                {\n                    await _consulClient.KV.DeleteTree(entry.RegistrationKey);\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Debug,\n            Message = \"Could not find any silo registrations for deployment {ClusterId}.\"\n        )]\n        private static partial void LogDebugCouldNotFindSiloRegistrations(ILogger logger, string clusterId);\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Debug,\n            Message = \"ConsulMembershipProvider failed to insert the row {SiloAddress}.\"\n        )]\n        private partial void LogDebugConsulMembershipProviderFailedToInsertRow(SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Information,\n            Message = \"ConsulMembershipProvider failed to insert registration for silo {SiloAddress}\"\n        )]\n        private partial void LogInformationConsulMembershipProviderFailedToInsertRegistration(Exception ex, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Debug,\n            Message = \"ConsulMembershipProvider failed the CAS check when updating the registration for silo {SiloAddress}.\"\n        )]\n        private partial void LogDebugConsulMembershipProviderFailedCASCheck(SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Information,\n            Message = \"ConsulMembershipProvider failed to update the registration for silo {SiloAddress}\"\n        )]\n        private partial void LogInformationConsulMembershipProviderFailedToUpdateRegistration(Exception ex, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = Microsoft.Extensions.Logging.LogLevel.Debug,\n            Message = \"Could not find any silo registrations for deployment {ClusterId}.\"\n        )]\n        private partial void LogDebugCouldNotFindSiloRegistrationsForCleanup(string clusterId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.Consul/ConsulClusteringProviderBuilder.cs",
    "content": "using System;\nusing Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\n[assembly: RegisterProvider(\"Consul\", \"Clustering\", \"Client\", typeof(ConsulClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"Consul\", \"Clustering\", \"Silo\", typeof(ConsulClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class ConsulClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseConsulSiloClustering(options => options.Bind(configurationSection));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseConsulClientClustering(options => options.Bind(configurationSection));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.Consul/ConsulGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Consul;\nusing Orleans.Messaging;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Membership\n{\n    public class ConsulGatewayListProvider : IGatewayListProvider\n    {\n        private IConsulClient consulClient;\n        private readonly string clusterId;\n        private readonly ILogger logger;\n        private readonly ConsulClusteringOptions options;\n        private readonly TimeSpan maxStaleness;\n        private readonly string kvRootFolder;\n\n        public ConsulGatewayListProvider(\n            ILogger<ConsulGatewayListProvider> logger, \n            IOptions<ConsulClusteringOptions> options, \n            IOptions<GatewayOptions> gatewayOptions, \n            IOptions<ClusterOptions> clusterOptions)\n        {\n            this.logger = logger;\n            this.clusterId = clusterOptions.Value.ClusterId;\n            this.maxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n            this.options = options.Value;\n            this.kvRootFolder = options.Value.KvRootFolder;\n        }\n\n        public TimeSpan MaxStaleness\n        {\n            get { return this.maxStaleness; }\n        }\n\n        public bool IsUpdatable\n        {\n            get { return true; }\n        }\n        public Task InitializeGatewayListProvider()\n        {\n            consulClient = options.CreateClient();\n            return Task.CompletedTask;\n        }\n\n        public async Task<IList<Uri>> GetGateways()\n        {\n            var membershipTableData = await ConsulBasedMembershipTable.ReadAll(this.consulClient, this.clusterId, this.kvRootFolder, this.logger, null);\n            if (membershipTableData == null) return new List<Uri>();\n\n            return membershipTableData.Members.Select(e => e.Item1).\n                Where(m => m.Status == SiloStatus.Active && m.ProxyPort != 0).\n                Select(m =>\n                {\n                    var gatewayAddress = SiloAddress.New(m.SiloAddress.Endpoint.Address, m.ProxyPort, m.SiloAddress.Generation);\n                    return gatewayAddress.ToGatewayUri();\n                }).ToList();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.Consul/ConsulUtilsHostingExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class ConsulUtilsHostingExtensions\n    {\n        /// <summary>\n        /// Configures the silo to use Consul for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseConsulSiloClustering(\n            this ISiloBuilder builder,\n            Action<ConsulClusteringOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IMembershipTable, ConsulBasedMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the silo to use Consul for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseConsulSiloClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<ConsulClusteringOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<ConsulClusteringOptions>());\n                    services.AddSingleton<IMembershipTable, ConsulBasedMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use Consul for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseConsulClientClustering(\n            this IClientBuilder builder,\n            Action<ConsulClusteringOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IGatewayListProvider, ConsulGatewayListProvider>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use Consul for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseConsulClientClustering(\n            this IClientBuilder builder,\n            Action<OptionsBuilder<ConsulClusteringOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<ConsulClusteringOptions>());\n                    services.AddSingleton<IGatewayListProvider, ConsulGatewayListProvider>();\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Clustering.Consul/Options/ConsulClusteringOptions.cs",
    "content": "using System;\nusing Consul;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Base class for consul-cluster-options.\n    /// </summary>\n    public class ConsulClusteringOptions\n    {        \n        /// <summary>\n        /// Consul KV root folder name.\n        /// </summary>\n        public string KvRootFolder { get; set; }       \n\n        /// <summary>\n        /// Factory for the used Consul-Client.\n        /// </summary>\n        public Func<IConsulClient> CreateClient { get; private set; }\n\n        /// <summary>\n        /// Configures the <see cref=\"CreateClient\"/> using the provided callback.\n        /// </summary>\n        public void ConfigureConsulClient(Func<IConsulClient> createClientCallback)\n        {\n            CreateClient = createClientCallback ?? throw new ArgumentNullException(nameof(createClientCallback));\n        }\n       \n        /// <summary>\n        /// Configures the <see cref=\"CreateClient\"/> using the consul-address and a acl-token.\n        /// </summary>\n        public void ConfigureConsulClient(Uri address, string aclClientToken = null)\n        {\n            if (address is null) throw new ArgumentNullException(nameof(address));            \n            \n            CreateClient = () => new ConsulClient(config =>\n            {\n                config.Address = address;\n                config.Token = aclClientToken;\n            });\n        }\n\n        public ConsulClusteringOptions()\n        {\n            this.CreateClient = () => new ConsulClient();\n        }\n\n        internal void Validate(string name)\n        {\n            if (CreateClient is null)\n            {\n                throw new OrleansConfigurationException($\"No callback specified. Use the {GetType().Name}.{nameof(ConsulClusteringOptions.ConfigureConsulClient)} method to configure the consul client.\");\n            }                       \n        }\n    }\n\n    public class ConsulClusteringOptionsValidator<TOptions> : IConfigurationValidator where TOptions : ConsulClusteringOptions\n    {\n        public ConsulClusteringOptionsValidator(TOptions options, string name = null)\n        {\n            Options = options;\n            Name = name;\n        }\n\n        public TOptions Options { get; }\n        public string Name { get; }\n\n        public virtual void ValidateConfiguration()\n        {\n            Options.Validate(Name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.Consul/Orleans.Clustering.Consul.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.Consul</PackageId>\n    <Title>Microsoft Orleans clustering provider for Consul</Title>\n    <Description>Microsoft Orleans clustering provider backed by Consul</Description>\n    <PackageTags>$(PackageTags) Consul</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Clustering.Consul</AssemblyName>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"Consul\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Clustering.Consul/SerializableMembershipTypes.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Consul;\nusing Newtonsoft.Json;\n\nnamespace Orleans.Runtime.Host\n{\n    /// <summary>\n    /// JSON Serializable Object that when serialized and Base64 encoded, forms the Value part of a Silo's Consul KVPair\n    /// </summary>\n    [JsonObject]\n    public class ConsulSiloRegistration\n    {\n        /// <summary>\n        /// Persisted as part of the KV Key therefore not serialised.\n        /// </summary>\n        [JsonIgnore]\n        internal string DeploymentId { get; set; }\n\n        /// <summary>\n        /// Persisted as part of the KV Key therefore not serialised.\n        /// </summary>\n        [JsonIgnore]\n        internal SiloAddress Address { get; set; }\n\n        /// <summary>\n        /// Persisted in a separate KV Subkey, therefore not serialised but held here to enable cleaner assembly to MembershipEntry.\n        /// </summary>\n        /// <remarks>\n        /// Stored in a separate KV otherwise the regular updates to IAmAlive cause the Silo's KV.ModifyIndex to change \n        /// which in turn cause UpdateRow operations to fail.\n        /// </remarks>\n        [JsonIgnore]\n        internal DateTime IAmAliveTime { get; set; }\n\n        /// <summary>\n        /// Used to compare CAS value on update, persisted as KV.ModifyIndex therefore not serialised.\n        /// </summary>\n        [JsonIgnore]\n        internal ulong LastIndex { get; set; }\n\n        //Public properties are serialized to the KV.Value\n        [JsonProperty]\n        public string Hostname { get; set; }\n\n        [JsonProperty]\n        public int ProxyPort { get; set; }\n\n        [JsonProperty]\n        public DateTime StartTime { get; set; }\n\n        [JsonProperty]\n        public SiloStatus Status { get; set; }\n\n        [JsonProperty]\n        public string SiloName { get; set; }\n\n        [JsonProperty]\n        public List<SuspectingSilo> SuspectingSilos { get; set; }\n\n        [JsonConstructor]\n        internal ConsulSiloRegistration()\n        {\n            SuspectingSilos = new List<SuspectingSilo>();\n        }\n    }\n\n    /// <summary>\n    /// JSON Serializable Object that when serialized and Base64 encoded, forms each entry in the SuspectingSilos list\n    /// </summary>\n    [JsonObject]\n    public class SuspectingSilo\n    {\n        [JsonProperty]\n        public string Id { get; set; }\n\n        [JsonProperty]\n        public DateTime Time { get; set; }\n    }\n\n    /// <summary>\n    /// Contains methods for converting a Consul KVPair to and from a MembershipEntry.  \n    /// This uses ConsulSiloRegistration objects as the serializable KV.Value and minimises conversion operations.\n    /// </summary>\n    internal class ConsulSiloRegistrationAssembler\n    {\n        private const string DeploymentKVPrefix = \"orleans\";  //Ensures a root KV namespace for orleans in Consul\n        private const char KeySeparator = '/';\n        internal const string SiloIAmAliveSuffix = \"iamalive\";\n        internal const string VersionSuffix = \"version\";\n\n        internal static string FormatVersionKey(string deploymentId, string rootKvFolder) => $\"{FormatDeploymentKVPrefix(deploymentId, rootKvFolder)}{KeySeparator}{VersionSuffix}\";\n\n        internal static string FormatDeploymentKVPrefix(string deploymentId, string rootKvFolder)\n        {\n            //Backward compatible\n            if (string.IsNullOrEmpty(rootKvFolder))\n            {\n                return $\"{DeploymentKVPrefix}{KeySeparator}{deploymentId}\";\n            }\n            else\n            {\n                return $\"{rootKvFolder}{KeySeparator}{DeploymentKVPrefix}{KeySeparator}{deploymentId}\";\n            }\n        }\n\n        internal static string FormatDeploymentSiloKey(string deploymentId, string rootKvFolder, SiloAddress siloAddress)\n        {\n            return $\"{FormatDeploymentKVPrefix(deploymentId, rootKvFolder)}{KeySeparator}{siloAddress.ToParsableString()}\";\n        }\n\n        internal static string FormatSiloIAmAliveKey(string siloKey)\n        {\n            return $\"{siloKey}{KeySeparator}{SiloIAmAliveSuffix}\";\n        }\n\n        internal static string FormatSiloIAmAliveKey(string deploymentId, string rootKvFolder, SiloAddress siloAddress)\n        {\n            return FormatSiloIAmAliveKey(FormatDeploymentSiloKey(deploymentId, rootKvFolder, siloAddress));\n        }\n\n        internal static ConsulSiloRegistration FromKVPairs(string deploymentId, KVPair siloKV, KVPair iAmAliveKV)\n        {\n            var ret = JsonConvert.DeserializeObject<ConsulSiloRegistration>(Encoding.UTF8.GetString(siloKV.Value));\n\n            var keyParts = siloKV.Key.Split(KeySeparator);\n            ret.Address = SiloAddress.FromParsableString(keyParts[^1]);\n            ret.DeploymentId = deploymentId;\n            ret.LastIndex = siloKV.ModifyIndex;\n\n            if (iAmAliveKV == null)\n                ret.IAmAliveTime = ret.StartTime;\n            else\n                ret.IAmAliveTime = JsonConvert.DeserializeObject<DateTime>(Encoding.UTF8.GetString(iAmAliveKV.Value));\n\n            return ret;\n        }\n\n        internal static ConsulSiloRegistration FromMembershipEntry(string deploymentId, MembershipEntry entry, string etag)\n        {\n            var ret = new ConsulSiloRegistration\n            {\n                DeploymentId = deploymentId,\n                Address = entry.SiloAddress,\n                IAmAliveTime = entry.IAmAliveTime,\n                LastIndex = Convert.ToUInt64(etag),\n                Hostname = entry.HostName,\n                ProxyPort = entry.ProxyPort,\n                StartTime = entry.StartTime,\n                Status = entry.Status,\n                SiloName = entry.SiloName,\n                SuspectingSilos = entry.SuspectTimes?.Select(silo => new SuspectingSilo { Id = silo.Item1.ToParsableString(), Time = silo.Item2 }).ToList()\n            };\n\n            return ret;\n        }\n\n        internal static KVPair ToKVPair(ConsulSiloRegistration siloRegistration, string rootKvFolder)\n        {\n            var ret = new KVPair(ConsulSiloRegistrationAssembler.FormatDeploymentSiloKey(siloRegistration.DeploymentId, rootKvFolder, siloRegistration.Address));\n            ret.ModifyIndex = siloRegistration.LastIndex;\n            ret.Value = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(siloRegistration));\n            return ret;\n        }\n\n        internal static KVPair ToIAmAliveKVPair(string deploymentId, string rootKvFolder, SiloAddress siloAddress, DateTime iAmAliveTime)\n        {\n            var ret = new KVPair(ConsulSiloRegistrationAssembler.FormatSiloIAmAliveKey(deploymentId, rootKvFolder, siloAddress));\n            ret.Value = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(iAmAliveTime));\n            return ret;\n        }\n\n        internal static Tuple<MembershipEntry, string> ToMembershipEntry(ConsulSiloRegistration siloRegistration)\n        {\n            var entry = new MembershipEntry\n            {\n                SiloAddress = siloRegistration.Address,\n                HostName = siloRegistration.Hostname,\n                Status = siloRegistration.Status,\n                ProxyPort = siloRegistration.ProxyPort,\n                StartTime = siloRegistration.StartTime,\n                SuspectTimes = siloRegistration.SuspectingSilos?.Select(silo => new Tuple<SiloAddress, DateTime>(SiloAddress.FromParsableString(silo.Id), silo.Time)).ToList(),\n                IAmAliveTime = siloRegistration.IAmAliveTime,\n                SiloName = siloRegistration.SiloName,\n\n                // Optional - only for Azure role so initialised here\n                RoleName = string.Empty,\n                UpdateZone = 0,\n                FaultZone = 0\n            };\n\n            return new Tuple<MembershipEntry, string>(entry, siloRegistration.LastIndex.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/MembershipSerializerSettings.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Converters;\nusing Newtonsoft.Json.Linq;\n\nnamespace Orleans.Runtime.Host\n{\n    internal class MembershipSerializerSettings : JsonSerializerSettings\n    {\n        public static readonly MembershipSerializerSettings Instance = new MembershipSerializerSettings();\n\n        private MembershipSerializerSettings()\n        {\n            Converters.Add(new SiloAddressConverter());\n            Converters.Add(new MembershipEntryConverter());\n            Converters.Add(new StringEnumConverter());\n        }\n\n        private class MembershipEntryConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return (objectType == typeof(MembershipEntry));\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                MembershipEntry me = (MembershipEntry)value;\n                writer.WriteStartObject();\n                writer.WritePropertyName(\"SiloAddress\"); serializer.Serialize(writer, me.SiloAddress);\n                writer.WritePropertyName(\"HostName\"); writer.WriteValue(me.HostName);\n                writer.WritePropertyName(\"SiloName\"); writer.WriteValue(me.SiloName);\n                writer.WritePropertyName(\"InstanceName\"); writer.WriteValue(me.SiloName);\n                writer.WritePropertyName(\"Status\"); serializer.Serialize(writer, me.Status);\n                writer.WritePropertyName(\"ProxyPort\"); writer.WriteValue(me.ProxyPort);\n                writer.WritePropertyName(\"StartTime\"); writer.WriteValue(me.StartTime);\n                writer.WritePropertyName(\"SuspectTimes\"); serializer.Serialize(writer, me.SuspectTimes);\n                writer.WriteEndObject();\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue,\n                JsonSerializer serializer)\n            {\n                JObject jo = JObject.Load(reader);\n                return new MembershipEntry\n                {\n                    SiloAddress = jo[\"SiloAddress\"].ToObject<SiloAddress>(serializer),\n                    HostName = jo[\"HostName\"].ToObject<string>(),\n                    SiloName = (jo[\"SiloName\"] ?? jo[\"InstanceName\"]).ToObject<string>(),\n                    Status = jo[\"Status\"].ToObject<SiloStatus>(serializer),\n                    ProxyPort = jo[\"ProxyPort\"].Value<int>(),\n                    StartTime = jo[\"StartTime\"].Value<DateTime>(),\n                    SuspectTimes = jo[\"SuspectTimes\"].ToObject<List<Tuple<SiloAddress, DateTime>>>(serializer)\n                };\n            }\n        }\n\n        private class SiloAddressConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return (objectType == typeof(SiloAddress));\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                SiloAddress se = (SiloAddress)value;\n                writer.WriteStartObject();\n                writer.WritePropertyName(\"SiloAddress\");\n                writer.WriteValue(se.ToParsableString());\n                writer.WriteEndObject();\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue,\n                JsonSerializer serializer)\n            {\n                JObject jo = JObject.Load(reader);\n                string seStr = jo[\"SiloAddress\"].ToObject<string>(serializer);\n                return SiloAddress.FromParsableString(seStr);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/Options/ZooKeeperClusteringSiloOptions.cs",
    "content": "﻿namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Option to configure ZooKeeperMembership\n    /// </summary>\n    public class ZooKeeperClusteringSiloOptions\n    {\n        /// <summary>\n        /// Connection string for ZooKeeper Storage\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/Options/ZooKeeperGatewayListProviderOptions.cs",
    "content": "﻿namespace Orleans.Configuration\n{\n    public class ZooKeeperGatewayListProviderOptions\n    {\n        /// <summary>\n        /// Connection string for ZooKeeper storage\n        /// </summary>\n        [Redact]\n        public string ConnectionString { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/Orleans.Clustering.ZooKeeper.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Clustering.ZooKeeper</PackageId>\n    <Title>Microsoft Orleans clustering provider for ZooKeeper</Title>\n    <Description>Microsoft Orleans clustering provider backed by ZooKeeper</Description>\n    <PackageTags>$(PackageTags) ZooKeeper</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Clustering.ZooKeeper</AssemblyName>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <PackageReference Include=\"ZooKeeperNetEx\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/ZooKeeperBasedMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing org.apache.zookeeper;\nusing org.apache.zookeeper.data;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Host;\n\nnamespace Orleans.Runtime.Membership\n{\n    /// <summary>\n    /// A Membership Table implementation using Apache Zookeeper 3.4.6 https://zookeeper.apache.org/doc/r3.4.6/\n    /// </summary>\n    /// <remarks>\n    /// A brief overview of ZK features used: The data is represented by a tree of nodes (similar to a file system). \n    /// Every node is addressed by a path and can hold data as a byte array and has a version. When a node is created, \n    /// its version is 0. Upon updates, the version is atomically incremented. An update can also be conditional on an \n    /// expected current version. A transaction can hold several operations, which succeed or fail atomically.\n    /// when creating a zookeeper client, one can set a base path where all operations are relative to.\n    /// \n    /// In this implementation:\n    /// Every Orleans deployment has a node   /UniqueDeploymentId\n    /// Every Silo's state is saved in        /UniqueDeploymentId/IP:Port@Gen\n    /// Every Silo's IAmAlive is saved in     /UniqueDeploymentId/IP:Port@Gen/IAmAlive\n    /// IAmAlive is saved in a separate node because its updates are unconditional.\n    /// \n    /// a node's ZK version is its ETag:\n    /// the table version is the version of /UniqueDeploymentId\n    /// the silo entry version is the version of /UniqueDeploymentId/IP:Port@Gen\n    /// </remarks>\n    public partial class ZooKeeperBasedMembershipTable : IMembershipTable\n    {\n        private readonly ILogger logger;\n\n        private const int ZOOKEEPER_CONNECTION_TIMEOUT = 2000;\n\n        private readonly ZooKeeperWatcher watcher;\n\n        /// <summary>\n        /// The deployment connection string. for eg. \"192.168.1.1,192.168.1.2/ClusterId\"\n        /// </summary>\n        private readonly string deploymentConnectionString;\n\n        /// <summary>\n        /// the node name for this deployment. for eg. /ClusterId\n        /// </summary>\n        private readonly string clusterPath;\n\n        /// <summary>\n        /// The root connection string. for eg. \"192.168.1.1,192.168.1.2\"\n        /// </summary>\n        private readonly string rootConnectionString;\n        \n        public ZooKeeperBasedMembershipTable(\n            ILogger<ZooKeeperBasedMembershipTable> logger, \n            IOptions<ZooKeeperClusteringSiloOptions> membershipTableOptions, \n            IOptions<ClusterOptions> clusterOptions)\n        {\n            this.logger = logger;\n            var options = membershipTableOptions.Value;\n            watcher = new ZooKeeperWatcher(logger);\n            this.clusterPath = \"/\" + clusterOptions.Value.ClusterId;\n            rootConnectionString = options.ConnectionString;\n            deploymentConnectionString = options.ConnectionString + this.clusterPath;\n        }\n\n        /// <summary>\n        /// Initializes the ZooKeeper based membership table.\n        /// </summary>\n        /// <param name=\"tryInitPath\">if set to true, we'll try to create a node named \"/ClusterId\"</param>\n        /// <returns></returns>\n        public async Task InitializeMembershipTable(bool tryInitPath)\n        {\n            // even if I am not the one who created the path, \n            // try to insert an initial path if it is not already there,\n            // so we always have the path, before this silo starts working.\n            // note that when a zookeeper connection adds /ClusterId to the connection string, the nodes are relative\n            await UsingZookeeper(rootConnectionString, async zk =>\n            {\n                try\n                {\n                    await zk.createAsync(this.clusterPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n                    await zk.sync(this.clusterPath);\n                    //if we got here we know that we've just created the deployment path with version=0\n                    LogInformationCreatedNewDeploymentPath(this.clusterPath);\n                }\n                catch (KeeperException.NodeExistsException)\n                {\n                    LogDebugDeploymentPathAlreadyExists(this.clusterPath);\n                }\n            });\n        }\n\n        /// <summary>\n        /// Atomically reads the Membership Table information about a given silo.\n        /// The returned MembershipTableData includes one MembershipEntry entry for a given silo and the \n        /// TableVersion for this table. The MembershipEntry and the TableVersion have to be read atomically.\n        /// </summary>\n        /// <param name=\"siloAddress\">The address of the silo whose membership information needs to be read.</param>\n        /// <returns>The membership information for a given silo: MembershipTableData consisting one MembershipEntry entry and\n        /// TableVersion, read atomically.</returns>\n        public Task<MembershipTableData> ReadRow(SiloAddress siloAddress)\n        {\n            return UsingZookeeper(async zk =>\n            {\n                var getRowTask = GetRow(zk, siloAddress);\n                var getTableNodeTask = zk.getDataAsync(\"/\");//get the current table version\n\n                List<Tuple<MembershipEntry, string>> rows = new List<Tuple<MembershipEntry, string>>(1);\n                try\n                {\n                    await Task.WhenAll(getRowTask, getTableNodeTask);\n                    rows.Add(await getRowTask);\n                }\n                catch (KeeperException.NoNodeException)\n                {\n                    //that's ok because orleans expects an empty list in case of a missing row\n                }\n\n                var tableVersion = ConvertToTableVersion((await getTableNodeTask).Stat);\n                return new MembershipTableData(rows, tableVersion);\n            }, this.deploymentConnectionString, this.watcher, true);\n        }\n\n        /// <summary>\n        /// Atomically reads the full content of the Membership Table.\n        /// The returned MembershipTableData includes all MembershipEntry entry for all silos in the table and the \n        /// TableVersion for this table. The MembershipEntries and the TableVersion have to be read atomically.\n        /// </summary>\n        /// <returns>The membership information for a given table: MembershipTableData consisting multiple MembershipEntry entries and\n        /// TableVersion, all read atomically.</returns>\n        public Task<MembershipTableData> ReadAll()\n        {\n            return ReadAll(this.deploymentConnectionString, this.watcher);\n        }\n\n        internal static Task<MembershipTableData> ReadAll(string deploymentConnectionString, ZooKeeperWatcher watcher)\n        {\n            return UsingZookeeper(async zk =>\n            {\n                var childrenResult = await zk.getChildrenAsync(\"/\");//get all the child nodes (without the data)\n\n                var childrenTasks = //get the data from each child node\n                    childrenResult.Children.Select(child => GetRow(zk, SiloAddress.FromParsableString(child))).ToList();\n\n                var childrenTaskResults = await Task.WhenAll(childrenTasks);\n\n                var tableVersion = ConvertToTableVersion(childrenResult.Stat);//this is the current table version\n\n                return new MembershipTableData(childrenTaskResults.ToList(), tableVersion);\n            }, deploymentConnectionString, watcher, true);\n        }\n\n        /// <summary>\n        /// Atomically tries to insert (add) a new MembershipEntry for one silo and also update the TableVersion.\n        /// If operation succeeds, the following changes would be made to the table:\n        /// 1) New MembershipEntry will be added to the table.\n        /// 2) The newly added MembershipEntry will also be added with the new unique automatically generated eTag.\n        /// 3) TableVersion.Version in the table will be updated to the new TableVersion.Version.\n        /// 4) TableVersion etag in the table will be updated to the new unique automatically generated eTag.\n        /// All those changes to the table, insert of a new row and update of the table version and the associated etags, should happen atomically, or fail atomically with no side effects.\n        /// The operation should fail in each of the following conditions:\n        /// 1) A MembershipEntry for a given silo already exist in the table\n        /// 2) Update of the TableVersion failed since the given TableVersion etag (as specified by the TableVersion.VersionEtag property) did not match the TableVersion etag in the table.\n        /// </summary>\n        /// <param name=\"entry\">MembershipEntry to be inserted.</param>\n        /// <param name=\"tableVersion\">The new TableVersion for this table, along with its etag.</param>\n        /// <returns>True if the insert operation succeeded and false otherwise.</returns>\n        public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            string rowPath = ConvertToRowPath(entry.SiloAddress);\n            string rowIAmAlivePath = ConvertToRowIAmAlivePath(entry.SiloAddress);\n            byte[] newRowData = Serialize(entry);\n            byte[] newRowIAmAliveData = Serialize(entry.IAmAliveTime);\n\n            int expectedTableVersion = int.Parse(tableVersion.VersionEtag, CultureInfo.InvariantCulture);\n\n            return TryTransaction(t => t\n                .setData(\"/\", null, expectedTableVersion)//increments the version of node \"/\"\n                .create(rowPath, newRowData, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)\n                .create(rowIAmAlivePath, newRowIAmAliveData, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT));\n        }\n\n        /// <summary>\n        /// Atomically tries to update the MembershipEntry for one silo and also update the TableVersion.\n        /// If operation succeeds, the following changes would be made to the table:\n        /// 1) The MembershipEntry for this silo will be updated to the new MembershipEntry (the old entry will be fully substituted by the new entry) \n        /// 2) The eTag for the updated MembershipEntry will also be eTag with the new unique automatically generated eTag.\n        /// 3) TableVersion.Version in the table will be updated to the new TableVersion.Version.\n        /// 4) TableVersion etag in the table will be updated to the new unique automatically generated eTag.\n        /// All those changes to the table, update of a new row and update of the table version and the associated etags, should happen atomically, or fail atomically with no side effects.\n        /// The operation should fail in each of the following conditions:\n        /// 1) A MembershipEntry for a given silo does not exist in the table\n        /// 2) A MembershipEntry for a given silo exist in the table but its etag in the table does not match the provided etag.\n        /// 3) Update of the TableVersion failed since the given TableVersion etag (as specified by the TableVersion.VersionEtag property) did not match the TableVersion etag in the table.\n        /// </summary>\n        /// <param name=\"entry\">MembershipEntry to be updated.</param>\n        /// <param name=\"etag\">The etag  for the given MembershipEntry.</param>\n        /// <param name=\"tableVersion\">The new TableVersion for this table, along with its etag.</param>\n        /// <returns>True if the update operation succeeded and false otherwise.</returns>\n        public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            string rowPath = ConvertToRowPath(entry.SiloAddress);\n            string rowIAmAlivePath = ConvertToRowIAmAlivePath(entry.SiloAddress);\n            var newRowData = Serialize(entry);\n            var newRowIAmAliveData = Serialize(entry.IAmAliveTime);\n\n            int expectedTableVersion = int.Parse(tableVersion.VersionEtag, CultureInfo.InvariantCulture);\n            int expectedRowVersion = int.Parse(etag, CultureInfo.InvariantCulture);\n\n            return TryTransaction(t => t\n                .setData(\"/\", null, expectedTableVersion)//increments the version of node \"/\"\n                .setData(rowPath, newRowData, expectedRowVersion)//increments the version of node \"/IP:Port@Gen\"\n                .setData(rowIAmAlivePath, newRowIAmAliveData));\n        }\n\n        /// <summary>\n        /// Updates the IAmAlive part (column) of the MembershipEntry for this silo.\n        /// This operation should only update the IAmAlive column and not change other columns.\n        /// This operation is a \"dirty write\" or \"in place update\" and is performed without etag validation. \n        /// With regards to eTags update:\n        /// This operation may automatically update the eTag associated with the given silo row, but it does not have to. It can also leave the etag not changed (\"dirty write\").\n        /// With regards to TableVersion:\n        /// this operation should not change the TableVersion of the table. It should leave it untouched.\n        /// There is no scenario where this operation could fail due to table semantical reasons. It can only fail due to network problems or table unavailability.\n        /// </summary>\n        /// <param name=\"entry\">The target MembershipEntry tp update</param>\n        /// <returns>Task representing the successful execution of this operation. </returns>\n        public Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            string rowIAmAlivePath = ConvertToRowIAmAlivePath(entry.SiloAddress);\n            byte[] newRowIAmAliveData = Serialize(entry.IAmAliveTime);\n            //update the data for IAmAlive unconditionally\n            return UsingZookeeper(zk => zk.setDataAsync(rowIAmAlivePath, newRowIAmAliveData), this.deploymentConnectionString, this.watcher);\n        }\n\n        /// <summary>\n        /// Deletes all table entries of the given clusterId\n        /// </summary>\n        public Task DeleteMembershipTableEntries(string clusterId)\n        {\n            string pathToDelete = \"/\" + clusterId;\n            return UsingZookeeper(rootConnectionString, async zk =>\n            {\n                await ZKUtil.deleteRecursiveAsync(zk, pathToDelete);\n                await zk.sync(pathToDelete);\n            });\n        }\n\n        private async Task<bool> TryTransaction(Func<Transaction, Transaction> transactionFunc)\n        {\n            try\n            {\n                await UsingZookeeper(zk => transactionFunc(zk.transaction()).commitAsync(), this.deploymentConnectionString, this.watcher);\n                return true;\n            }\n            catch (KeeperException e)\n            {\n                //these exceptions are thrown when the transaction fails to commit due to semantical reasons\n                if (e is KeeperException.NodeExistsException || e is KeeperException.NoNodeException ||\n                    e is KeeperException.BadVersionException)\n                {\n                    return false;\n                }\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Reads the nodes /IP:Port@Gen and /IP:Port@Gen/IAmAlive (which together is one row)\n        /// </summary>\n        /// <param name=\"zk\">The zookeeper instance used for the read</param>\n        /// <param name=\"siloAddress\">The silo address.</param>\n        private static async Task<Tuple<MembershipEntry, string>> GetRow(ZooKeeper zk, SiloAddress siloAddress)\n        {\n            string rowPath = ConvertToRowPath(siloAddress);\n            string rowIAmAlivePath = ConvertToRowIAmAlivePath(siloAddress);\n\n            var rowDataTask = zk.getDataAsync(rowPath);\n            var rowIAmAliveDataTask = zk.getDataAsync(rowIAmAlivePath);\n\n            await Task.WhenAll(rowDataTask, rowIAmAliveDataTask);\n\n            MembershipEntry me = Deserialize<MembershipEntry>((await rowDataTask).Data);\n            me.IAmAliveTime = Deserialize<DateTime>((await rowIAmAliveDataTask).Data);\n\n            int rowVersion = (await rowDataTask).Stat.getVersion();\n\n            return new Tuple<MembershipEntry, string>(me, rowVersion.ToString(CultureInfo.InvariantCulture));\n        }\n\n        private static Task<T> UsingZookeeper<T>(Func<ZooKeeper, Task<T>> zkMethod, string deploymentConnectionString, ZooKeeperWatcher watcher, bool canBeReadOnly = false)\n        {\n            return ZooKeeper.Using(deploymentConnectionString, ZOOKEEPER_CONNECTION_TIMEOUT, watcher, zkMethod, canBeReadOnly);\n        }\n\n        private Task UsingZookeeper(string connectString, Func<ZooKeeper, Task> zkMethod)\n        {\n            return ZooKeeper.Using(connectString, ZOOKEEPER_CONNECTION_TIMEOUT, watcher, zkMethod);\n        }\n\n        private static string ConvertToRowPath(SiloAddress siloAddress)\n        {\n            return \"/\" + siloAddress.ToParsableString();\n        }\n\n        private static string ConvertToRowIAmAlivePath(SiloAddress siloAddress)\n        {\n            return ConvertToRowPath(siloAddress) + \"/IAmAlive\";\n        }\n\n        private static TableVersion ConvertToTableVersion(Stat stat)\n        {\n            int version = stat.getVersion();\n            return new TableVersion(version, version.ToString(CultureInfo.InvariantCulture));\n        }\n\n        private static byte[] Serialize(object obj)\n        {\n            return\n                Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj, Formatting.None,\n                    MembershipSerializerSettings.Instance));\n        }\n\n        private static T Deserialize<T>(byte[] data)\n        {\n            return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(data), MembershipSerializerSettings.Instance);\n        }\n\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            throw new NotImplementedException();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Created new deployment path: {DeploymentPath}\"\n        )]\n        private partial void LogInformationCreatedNewDeploymentPath(string deploymentPath);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Deployment path already exists: {DeploymentPath}\"\n        )]\n        private partial void LogDebugDeploymentPathAlreadyExists(string deploymentPath);\n    }\n\n    /// <summary>\n    /// the state of every ZooKeeper client and its push notifications are published using watchers.\n    /// in orleans the watcher is only for debugging purposes\n    /// </summary>\n    internal partial class ZooKeeperWatcher : Watcher\n    {\n        private readonly ILogger logger;\n        public ZooKeeperWatcher(ILogger logger)\n        {\n            this.logger = logger;\n        }\n\n        public override Task process(WatchedEvent @event)\n        {\n            LogDebugWatchedEvent(@event);\n            return Task.CompletedTask;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{EventString}\"\n        )]\n        private partial void LogDebugWatchedEvent(WatchedEvent eventString);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/ZooKeeperClusteringProviderBuilder.cs",
    "content": "using System;\nusing Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\n[assembly: RegisterProvider(\"ZooKeeper\", \"Clustering\", \"Client\", typeof(ZooKeeperClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"ZooKeeper\", \"Clustering\", \"Silo\", typeof(ZooKeeperClusteringProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class ZooKeeperClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseZooKeeperClustering(options => options.Bind(configurationSection));\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseZooKeeperClustering(options => options.Bind(configurationSection));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/ZooKeeperGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Messaging;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Membership\n{\n    public class ZooKeeperGatewayListProvider : IGatewayListProvider\n    {\n        private readonly ZooKeeperWatcher _watcher;\n\n        /// <summary>\n        /// the node name for this deployment. for eg. /ClusterId\n        /// </summary>\n        private readonly string _deploymentPath;\n\n        /// <summary>\n        /// The deployment connection string. for eg. \"192.168.1.1,192.168.1.2/ClusterId\"\n        /// </summary>\n        private readonly string _deploymentConnectionString;\n        private readonly TimeSpan _maxStaleness;\n\n        public ZooKeeperGatewayListProvider(\n            ILogger<ZooKeeperGatewayListProvider> logger,\n            IOptions<ZooKeeperGatewayListProviderOptions> options,\n            IOptions<GatewayOptions> gatewayOptions,\n            IOptions<ClusterOptions> clusterOptions)\n        {\n            _watcher = new ZooKeeperWatcher(logger);\n            _deploymentPath = \"/\" + clusterOptions.Value.ClusterId;\n            _deploymentConnectionString = options.Value.ConnectionString + _deploymentPath;\n            _maxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n        }\n\n        /// <summary>\n        /// Initializes the ZooKeeper based gateway provider\n        /// </summary>\n        public Task InitializeGatewayListProvider() => Task.CompletedTask;\n\n        /// <summary>\n        /// Returns the list of gateways (silos) that can be used by a client to connect to Orleans cluster.\n        /// The Uri is in the form of: \"gwy.tcp://IP:port/Generation\". See Utils.ToGatewayUri and Utils.ToSiloAddress for more details about Uri format.\n        /// </summary>\n        public async Task<IList<Uri>> GetGateways()\n        {\n            var membershipTableData = await ZooKeeperBasedMembershipTable.ReadAll(this._deploymentConnectionString, this._watcher);\n            return membershipTableData.Members.Select(e => e.Item1).\n                Where(m => m.Status == SiloStatus.Active && m.ProxyPort != 0).\n                Select(m =>\n                {\n                    var gatewayAddress = SiloAddress.New(m.SiloAddress.Endpoint.Address, m.ProxyPort, m.SiloAddress.Generation);\n                    return gatewayAddress.ToGatewayUri();\n                }).ToList();\n        }\n\n        /// <summary>\n        /// Specifies how often this IGatewayListProvider is refreshed, to have a bound on max staleness of its returned information.\n        /// </summary>\n        public TimeSpan MaxStaleness => _maxStaleness;\n\n        /// <summary>\n        /// Specifies whether this IGatewayListProvider ever refreshes its returned information, or always returns the same gw list.\n        /// (currently only the static config based StaticGatewayListProvider is not updatable. All others are.)\n        /// </summary>\n        public bool IsUpdatable => true;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Clustering.ZooKeeper/ZooKeeperHostingExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n\n    public static class ZooKeeperHostingExtensions\n    {\n        /// <summary>\n        /// Configures the silo to use ZooKeeper for cluster membership.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseZooKeeperClustering(\n            this ISiloBuilder builder,\n            Action<ZooKeeperClusteringSiloOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IMembershipTable, ZooKeeperBasedMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the silo to use ZooKeeper for cluster membership.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder UseZooKeeperClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<ZooKeeperClusteringSiloOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<ZooKeeperClusteringSiloOptions>());\n                    services.AddSingleton<IMembershipTable, ZooKeeperBasedMembershipTable>();\n                });\n        }\n\n        /// <summary>\n        /// Configure the client to use ZooKeeper for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseZooKeeperClustering(\n            this IClientBuilder builder,\n            Action<ZooKeeperGatewayListProviderOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    if (configureOptions != null)\n                    {\n                        services.Configure(configureOptions);\n                    }\n\n                    services.AddSingleton<IGatewayListProvider, ZooKeeperGatewayListProvider>();\n                });\n        }\n\n        /// <summary>\n        /// Configure the client to use ZooKeeper for clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configuration delegate.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseZooKeeperClustering(\n            this IClientBuilder builder,\n            Action<OptionsBuilder<ZooKeeperGatewayListProviderOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<ZooKeeperGatewayListProviderOptions>());\n                    services.AddSingleton<IGatewayListProvider, ZooKeeperGatewayListProvider>();\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/ActivatorGenerator.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing System.Collections.Generic;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class ActivatorGenerator\n    {\n        private readonly CodeGenerator _codeGenerator;\n\n        private struct ConstructorArgument\n        {\n            public TypeSyntax Type { get; set; }\n            public string FieldName { get; set; }\n            public string ParameterName { get; set; }\n        }\n\n        public ActivatorGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        public ClassDeclarationSyntax GenerateActivator(ISerializableTypeDescription type)\n        {\n            var simpleClassName = GetSimpleClassName(type);\n\n            var baseInterface = _codeGenerator.LibraryTypes.IActivator_1.ToTypeSyntax(type.TypeSyntax);\n\n            var orderedFields = new List<ConstructorArgument>();\n            var index = 0;\n            if (type.ActivatorConstructorParameters is { Count: > 0 } parameters)\n            {\n                foreach (var arg in parameters)\n                {\n                    orderedFields.Add(new ConstructorArgument { Type = arg, FieldName = $\"_arg{index}\", ParameterName = $\"arg{index}\" });\n                    index++;\n                }\n            }\n\n            var members = new List<MemberDeclarationSyntax>();\n            foreach (var field in orderedFields)\n            {\n                members.Add(\n                    FieldDeclaration(VariableDeclaration(field.Type, SingletonSeparatedList(VariableDeclarator(field.FieldName))))\n                    .AddModifiers(\n                        Token(SyntaxKind.PrivateKeyword),\n                        Token(SyntaxKind.ReadOnlyKeyword)));\n            }\n\n            if (orderedFields.Count > 0)\n                members.Add(GenerateConstructor(simpleClassName, orderedFields));\n\n            members.Add(GenerateCreateMethod(type, orderedFields));\n\n            var classDeclaration = ClassDeclaration(simpleClassName)\n                .AddBaseListTypes(SimpleBaseType(baseInterface))\n                .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes())\n                .AddMembers(members.ToArray());\n\n            if (type.IsGenericType)\n            {\n                classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, type.TypeParameters);\n            }\n\n            return classDeclaration;\n        }\n\n        public static string GetSimpleClassName(ISerializableTypeDescription serializableType) => $\"Activator_{serializableType.Name}\";\n\n        private ConstructorDeclarationSyntax GenerateConstructor(\n            string simpleClassName,\n            List<ConstructorArgument> orderedFields)\n        {\n            var parameters = new List<ParameterSyntax>();\n            var body = new List<StatementSyntax>();\n            foreach (var field in orderedFields)\n            {\n                parameters.Add(Parameter(field.ParameterName.ToIdentifier()).WithType(field.Type));\n\n                body.Add(ExpressionStatement(\n                            AssignmentExpression(\n                                SyntaxKind.SimpleAssignmentExpression,\n                                field.FieldName.ToIdentifierName(),\n                                Unwrapped(field.ParameterName.ToIdentifierName()))));\n            }\n\n            var constructorDeclaration = ConstructorDeclaration(simpleClassName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters.ToArray())\n                .AddBodyStatements(body.ToArray());\n\n            return constructorDeclaration;\n\n            static ExpressionSyntax Unwrapped(ExpressionSyntax expr)\n            {\n                return InvocationExpression(\n                    MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(\"OrleansGeneratedCodeHelper\"), IdentifierName(\"UnwrapService\")),\n                    ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(expr) })));\n            }\n        }\n\n        private MemberDeclarationSyntax GenerateCreateMethod(ISerializableTypeDescription type, List<ConstructorArgument> orderedFields)\n        {\n            ExpressionSyntax createObject;\n            if (type.ActivatorConstructorParameters is { Count: > 0 })\n            {\n                var argList = new List<ArgumentSyntax>();\n                foreach (var field in orderedFields)\n                {\n                    argList.Add(Argument(field.FieldName.ToIdentifierName()));\n                }\n\n                createObject = ObjectCreationExpression(type.TypeSyntax).WithArgumentList(ArgumentList(SeparatedList(argList)));\n            }\n            else\n            {\n                createObject = type.GetObjectCreationExpression();\n            }\n\n            return MethodDeclaration(type.TypeSyntax, \"Create\")\n                .WithExpressionBody(ArrowExpressionClause(createObject))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/AnalyzerReleases.Shipped.md",
    "content": "## Release 7.0.0\n\n### New Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|--------------------\nORLEANS0101 | Usage | Error | Serializable properties with bodies must be settable\nORLEANS0102 | Usage | Error | Invalid return type for RPC interface method\nORLEANS0103 | Usage | Error | An unhandled source generation exception occurred\nORLEANS0104 | Usage | Error | The proxy base class specified is not a valid proxy base class\nORLEANS0105 | Usage | Error | RPC interfaces must not contain properties\nORLEANS0106 | Usage | Error | An error is preventing implicit field identifier generation\nORLEANS0107 | Usage | Error | Serializable type is not accessible from generated code\nORLEANS0108 | Usage | Error | No declaring assembly for type passed to GenerateCodeForDeclaringAssemblyAttribute\n\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/AnalyzerReleases.Unshipped.md",
    "content": "; Unshipped analyzer release\n; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md\n\n### New Rules\n\nRule ID | Category | Severity | Notes\n--------|----------|----------|--------------------\nORLEANS0109 | Usage | Error | Method has multiple CancellationToken parameters\nORLEANS0110 | Usage | Error | ReferenceAssemblyWithGenerateSerializerDiagnostic\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/ApplicationPartAttributeGenerator.cs",
    "content": "﻿using System.Collections.Generic;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal static class ApplicationPartAttributeGenerator \n    {\n        public static List<AttributeListSyntax> GenerateSyntax(LibraryTypes wellKnownTypes, MetadataModel model)\n        {\n            var attributes = new List<AttributeListSyntax>();\n\n            foreach (var assemblyName in model.ApplicationParts)\n            {\n                // Generate an assembly-level attribute with an instance of that class.\n                var attribute = AttributeList(\n                    AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)),\n                    SingletonSeparatedList(\n                        Attribute(wellKnownTypes.ApplicationPartAttribute.ToNameSyntax())\n                            .AddArgumentListArguments(AttributeArgument(assemblyName.GetLiteralExpression()))));\n                attributes.Add(attribute);\n            }\n\n            return attributes;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/CodeGenerator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.Diagnostics;\nusing Orleans.CodeGenerator.Hashing;\nusing Orleans.CodeGenerator.Model;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing static Orleans.CodeGenerator.SyntaxGeneration.SymbolExtensions;\n\nnamespace Orleans.CodeGenerator\n{\n    public class CodeGeneratorOptions\n    {\n        public const string IdAttribute = \"Orleans.IdAttribute\";\n        public const string AliasAttribute = \"Orleans.AliasAttribute\";\n        public const string ImmutableAttribute = \"Orleans.ImmutableAttribute\";\n        public static readonly IReadOnlyList<string> ConstructorAttributes = [\"Orleans.OrleansConstructorAttribute\", \"Microsoft.Extensions.DependencyInjection.ActivatorUtilitiesConstructorAttribute\"];\n        public GenerateFieldIds GenerateFieldIds { get; set; }\n        public bool GenerateCompatibilityInvokers { get; set; }\n    }\n\n    public class CodeGenerator\n    {\n        internal const string CodeGeneratorName = \"OrleansCodeGen\";\n        private readonly Dictionary<string, List<MemberDeclarationSyntax>> _namespacedMembers = new();\n        private readonly Dictionary<InvokableMethodId, InvokableMethodDescription> _invokableMethodDescriptions = new();\n        private readonly HashSet<INamedTypeSymbol> _visitedInterfaces = new(SymbolEqualityComparer.Default);\n        private readonly List<string> DisabledWarnings = new() { \"CS1591\", \"RS0016\", \"RS0041\" };\n\n        public CodeGenerator(Compilation compilation, CodeGeneratorOptions options)\n        {\n            Compilation = compilation;\n            Options = options;\n            LibraryTypes = LibraryTypes.FromCompilation(compilation, options);\n            MetadataModel = new MetadataModel();\n            CopierGenerator = new CopierGenerator(this);\n            SerializerGenerator = new SerializerGenerator(this);\n            ProxyGenerator = new ProxyGenerator(this);\n            InvokableGenerator = new InvokableGenerator(this);\n            MetadataGenerator = new MetadataGenerator(this);\n            ActivatorGenerator = new ActivatorGenerator(this);\n        }\n\n        public Compilation Compilation { get; }\n        public CodeGeneratorOptions Options { get; }\n        internal LibraryTypes LibraryTypes { get; }\n        internal MetadataModel MetadataModel { get; }\n        internal CopierGenerator CopierGenerator { get; }\n        internal SerializerGenerator SerializerGenerator { get; }\n        internal ProxyGenerator ProxyGenerator { get; }\n        internal InvokableGenerator InvokableGenerator { get; }\n        internal MetadataGenerator MetadataGenerator { get; }\n        internal ActivatorGenerator ActivatorGenerator { get; }\n\n        public CompilationUnitSyntax GenerateCode(CancellationToken cancellationToken)\n        {\n            var assembliesToExamine = new HashSet<IAssemblySymbol>(SymbolEqualityComparer.Default);\n            var compilationAsm = LibraryTypes.Compilation.Assembly;\n            ComputeAssembliesToExamine(compilationAsm, assembliesToExamine);\n\n            // Expand the set of referenced assemblies\n            MetadataModel.ApplicationParts.Add(compilationAsm.MetadataName);\n            foreach (var reference in LibraryTypes.Compilation.References)\n            {\n                if (LibraryTypes.Compilation.GetAssemblyOrModuleSymbol(reference) is not IAssemblySymbol asm)\n                {\n                    continue;\n                }\n\n                if (asm.GetAttributes(LibraryTypes.ApplicationPartAttribute, out var attrs))\n                {\n                    MetadataModel.ApplicationParts.Add(asm.MetadataName);\n                    foreach (var attr in attrs)\n                    {\n                        MetadataModel.ApplicationParts.Add((string)attr.ConstructorArguments.First().Value);\n                    }\n                }\n            }\n\n            // The mapping of proxy base types to a mapping of return types to invokable base types. Used to set default invokable base types for each proxy base type.\n            var proxyBaseTypeInvokableBaseTypes = new Dictionary<INamedTypeSymbol, Dictionary<INamedTypeSymbol, INamedTypeSymbol>>(SymbolEqualityComparer.Default);\n\n            foreach (var asm in assembliesToExamine)\n            {\n                var containingAssemblyAttributes = asm.GetAttributes();\n\n                foreach (var symbol in asm.GetDeclaredTypes())\n                {\n                    if (GetWellKnownTypeId(symbol) is uint wellKnownTypeId)\n                    {\n                        MetadataModel.WellKnownTypeIds.Add((symbol.ToOpenTypeSyntax(), wellKnownTypeId));\n                    }\n\n                    if (GetAlias(symbol) is string typeAlias)\n                    {\n                        MetadataModel.TypeAliases.Add((symbol.ToOpenTypeSyntax(), typeAlias));\n                    }\n\n                    if (GetCompoundTypeAlias(symbol) is CompoundTypeAliasComponent[] compoundTypeAlias)\n                    {\n                        MetadataModel.CompoundTypeAliases.Add(compoundTypeAlias, symbol.ToOpenTypeSyntax());\n                    }\n\n                    if (FSharpUtilities.IsUnionCase(LibraryTypes, symbol, out var sumType) && ShouldGenerateSerializer(sumType))\n                    {\n                        if (!Compilation.IsSymbolAccessibleWithin(sumType, Compilation.Assembly))\n                        {\n                            throw new OrleansGeneratorDiagnosticAnalysisException(InaccessibleSerializableTypeDiagnostic.CreateDiagnostic(sumType));\n                        }\n\n                        var typeDescription = new FSharpUtilities.FSharpUnionCaseTypeDescription(Compilation, symbol, LibraryTypes);\n                        MetadataModel.SerializableTypes.Add(typeDescription);\n                    }\n                    else if (ShouldGenerateSerializer(symbol))\n                    {\n                        // https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.referenceassemblyattribute\n                        if (containingAssemblyAttributes.Any(attributeData => attributeData.AttributeClass is\n                            {\n                                Name: \"ReferenceAssemblyAttribute\",\n                                ContainingNamespace:\n                                {\n                                    Name: \"CompilerServices\",\n                                    ContainingNamespace:\n                                    {\n                                        Name: \"Runtime\",\n                                        ContainingNamespace:\n                                        {\n                                            Name: \"System\",\n                                            ContainingNamespace.IsGlobalNamespace: true\n                                        }\n                                    }\n                                }\n                            }))\n                        {\n                            // not ALWAYS will be properly processed, therefore emit a warning\n                            throw new OrleansGeneratorDiagnosticAnalysisException(ReferenceAssemblyWithGenerateSerializerDiagnostic.CreateDiagnostic(symbol));\n                        }\n\n                        if (!Compilation.IsSymbolAccessibleWithin(symbol, Compilation.Assembly))\n                        {\n                            throw new OrleansGeneratorDiagnosticAnalysisException(InaccessibleSerializableTypeDiagnostic.CreateDiagnostic(symbol));\n                        }\n\n                        if (FSharpUtilities.IsRecord(LibraryTypes, symbol))\n                        {\n                            var typeDescription = new FSharpUtilities.FSharpRecordTypeDescription(Compilation, symbol, LibraryTypes);\n                            MetadataModel.SerializableTypes.Add(typeDescription);\n                        }\n                        else\n                        {\n                            // Regular type\n                            var includePrimaryConstructorParameters = ShouldIncludePrimaryConstructorParameters(symbol);\n                            var constructorParameters = ImmutableArray<IParameterSymbol>.Empty;\n                            if (includePrimaryConstructorParameters)\n                            {\n                                if (symbol.IsRecord)\n                                {\n                                    // If there is a primary constructor then that will be declared before the copy constructor\n                                    // A record always generates a copy constructor and marks it as compiler generated\n                                    // todo: find an alternative to this magic\n                                    var potentialPrimaryConstructor = symbol.Constructors[0];\n                                    if (!potentialPrimaryConstructor.IsImplicitlyDeclared && !potentialPrimaryConstructor.IsCompilerGenerated())\n                                    {\n                                        constructorParameters = potentialPrimaryConstructor.Parameters;\n                                    }\n                                }\n                                else\n                                {\n                                    var annotatedConstructors = symbol.Constructors.Where(ctor => ctor.HasAnyAttribute(LibraryTypes.ConstructorAttributeTypes)).ToList();\n                                    if (annotatedConstructors.Count == 1)\n                                    {\n                                        constructorParameters = annotatedConstructors[0].Parameters;\n                                    }\n                                    else\n                                    {\n                                        // record structs from referenced assemblies do not return IsRecord=true\n                                        // above. See https://github.com/dotnet/roslyn/issues/69326\n                                        // So we implement the same heuristics from ShouldIncludePrimaryConstructorParameters\n                                        // to detect a primary constructor.\n                                        var properties = symbol.GetMembers().OfType<IPropertySymbol>().ToImmutableArray();\n                                        var primaryConstructor = symbol.GetMembers()\n                                            .OfType<IMethodSymbol>()\n                                            .Where(m => m.MethodKind == MethodKind.Constructor && m.Parameters.Length > 0)\n                                            // Check for a ctor where all parameters have a corresponding compiler-generated prop.\n                                            .FirstOrDefault(ctor => ctor.Parameters.All(prm =>\n                                                properties.Any(prop => prop.Name.Equals(prm.Name, StringComparison.Ordinal) && prop.IsCompilerGenerated())));\n\n                                        if (primaryConstructor != null)\n                                            constructorParameters = primaryConstructor.Parameters;\n                                    }\n                                }\n                            }\n\n                            var implicitMemberSelectionStrategy = (Options.GenerateFieldIds, GetGenerateFieldIdsOptionFromType(symbol)) switch\n                            {\n                                (_, GenerateFieldIds.PublicProperties) => GenerateFieldIds.PublicProperties,\n                                (GenerateFieldIds.PublicProperties, _) => GenerateFieldIds.PublicProperties,\n                                _ => GenerateFieldIds.None\n                            };\n                            var fieldIdAssignmentHelper = new FieldIdAssignmentHelper(symbol, constructorParameters, implicitMemberSelectionStrategy, LibraryTypes);\n                            if (!fieldIdAssignmentHelper.IsValidForSerialization)\n                            {\n                                throw new OrleansGeneratorDiagnosticAnalysisException(CanNotGenerateImplicitFieldIdsDiagnostic.CreateDiagnostic(symbol, fieldIdAssignmentHelper.FailureReason));\n                            }\n\n                            var typeDescription = new SerializableTypeDescription(Compilation, symbol, includePrimaryConstructorParameters, GetDataMembers(fieldIdAssignmentHelper), LibraryTypes);\n                            MetadataModel.SerializableTypes.Add(typeDescription);\n                        }\n                    }\n\n                    if (symbol.TypeKind == TypeKind.Interface)\n                    {\n                        VisitInterface(symbol.OriginalDefinition);\n                    }\n\n                    if ((symbol.TypeKind == TypeKind.Class || symbol.TypeKind == TypeKind.Struct)\n                        && !symbol.IsAbstract\n                        && (symbol.DeclaredAccessibility == Accessibility.Public || symbol.DeclaredAccessibility == Accessibility.Internal))\n                    {\n                        if (symbol.HasAttribute(LibraryTypes.RegisterSerializerAttribute))\n                        {\n                            MetadataModel.DetectedSerializers.Add(symbol);\n                        }\n\n                        if (symbol.HasAttribute(LibraryTypes.RegisterActivatorAttribute))\n                        {\n                            MetadataModel.DetectedActivators.Add(symbol);\n                        }\n\n                        if (symbol.HasAttribute(LibraryTypes.RegisterCopierAttribute))\n                        {\n                            MetadataModel.DetectedCopiers.Add(symbol);\n                        }\n\n                        if (symbol.HasAttribute(LibraryTypes.RegisterConverterAttribute))\n                        {\n                            MetadataModel.DetectedConverters.Add(symbol);\n                        }\n\n                        // Find all implementations of invokable interfaces\n                        foreach (var iface in symbol.AllInterfaces)\n                        {\n                            var attribute = iface.GetAttribute(\n                                LibraryTypes.GenerateMethodSerializersAttribute,\n                                inherited: true);\n                            if (attribute != null)\n                            {\n                                MetadataModel.InvokableInterfaceImplementations.Add(symbol);\n                                break;\n                            }\n                        }\n                    }\n\n                    GenerateFieldIds GetGenerateFieldIdsOptionFromType(INamedTypeSymbol t)\n                    {\n                        var attribute = t.GetAttribute(LibraryTypes.GenerateSerializerAttribute);\n                        if (attribute is null)\n                            return GenerateFieldIds.None;\n\n                        foreach (var namedArgument in attribute.NamedArguments)\n                        {\n                            if (namedArgument.Key == \"GenerateFieldIds\")\n                            {\n                                var value = namedArgument.Value.Value;\n                                return value == null ? GenerateFieldIds.None : (GenerateFieldIds)(int)value;\n                            }\n                        }\n                        return GenerateFieldIds.None;\n                    }\n\n                    bool ShouldGenerateSerializer(INamedTypeSymbol t) => t.HasAttribute(LibraryTypes.GenerateSerializerAttribute);\n\n                    bool ShouldIncludePrimaryConstructorParameters(INamedTypeSymbol t)\n                    {\n                        static bool? TestGenerateSerializerAttribute(INamedTypeSymbol t, INamedTypeSymbol at)\n                        {\n                            var attribute = t.GetAttribute(at);\n                            if (attribute != null)\n                            {\n                                foreach (var namedArgument in attribute.NamedArguments)\n                                {\n                                    if (namedArgument.Key == \"IncludePrimaryConstructorParameters\")\n                                    {\n                                        if (namedArgument.Value.Kind == TypedConstantKind.Primitive && namedArgument.Value.Value is bool b)\n                                        {\n                                            return b;\n                                        }\n                                    }\n                                }\n                            }\n\n                            // If there is no such named argument, return null so that other attributes have a chance to apply and defaults can be applied.\n                            return null;\n                        }\n\n                        if (TestGenerateSerializerAttribute(t, LibraryTypes.GenerateSerializerAttribute) is bool res)\n                        {\n                            return res;\n                        }\n\n                        // Default to true for records.\n                        if (t.IsRecord)\n                            return true;\n\n                        var properties = t.GetMembers().OfType<IPropertySymbol>().ToImmutableArray();\n\n                        return t.GetMembers()\n                            .OfType<IMethodSymbol>()\n                            .Where(m => m.MethodKind == MethodKind.Constructor && m.Parameters.Length > 0)\n                            // Check for a ctor where all parameters have a corresponding compiler-generated prop.\n                            .Any(ctor => ctor.Parameters.All(prm =>\n                                properties.Any(prop => prop.Name.Equals(prm.Name, StringComparison.Ordinal) && prop.IsCompilerGenerated())));\n                    }\n                }\n            }\n\n            // Generate serializers.\n            foreach (var type in MetadataModel.SerializableTypes)\n            {\n                string ns = type.GeneratedNamespace;\n\n                // Generate a partial serializer class for each serializable type.\n                var serializer = SerializerGenerator.Generate(type);\n                AddMember(ns, serializer);\n\n                // Generate a copier for each serializable type.\n                if (CopierGenerator.GenerateCopier(type, MetadataModel.DefaultCopiers) is { } copier)\n                    AddMember(ns, copier);\n\n                if (!type.IsAbstractType && !type.IsEnumType && (!type.IsValueType && type.IsEmptyConstructable && !type.UseActivator && type is not GeneratedInvokableDescription || type.HasActivatorConstructor))\n                {\n                    MetadataModel.ActivatableTypes.Add(type);\n\n                    // Generate an activator class for types with default constructor or activator constructor.\n                    var activator = ActivatorGenerator.GenerateActivator(type);\n                    AddMember(ns, activator);\n                }\n            }\n\n            // Generate metadata.\n            var metadataClassNamespace = CodeGeneratorName + \".\" + SyntaxGeneration.Identifier.SanitizeIdentifierName(Compilation.AssemblyName);\n            var metadataClass = MetadataGenerator.GenerateMetadata();\n            AddMember(ns: metadataClassNamespace, member: metadataClass);\n            var metadataAttribute = AttributeList()\n                .WithTarget(AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)))\n                .WithAttributes(\n                    SingletonSeparatedList(\n                        Attribute(LibraryTypes.TypeManifestProviderAttribute.ToNameSyntax())\n                            .AddArgumentListArguments(AttributeArgument(TypeOfExpression(QualifiedName(IdentifierName(metadataClassNamespace), IdentifierName(metadataClass.Identifier.Text)))))));\n\n            var assemblyAttributes = ApplicationPartAttributeGenerator.GenerateSyntax(LibraryTypes, MetadataModel);\n            assemblyAttributes.Add(metadataAttribute);\n\n            if (assemblyAttributes.Count > 0)\n            {\n                assemblyAttributes[0] = assemblyAttributes[0]\n                    .WithLeadingTrivia(\n                        SyntaxFactory.TriviaList(\n                            new List<SyntaxTrivia>\n                            {\n                                Trivia(\n                                   PragmaWarningDirectiveTrivia(\n                                       Token(SyntaxKind.DisableKeyword),\n                                       SeparatedList(DisabledWarnings.Select(str =>\n                                       {\n                                           var syntaxToken = SyntaxFactory.Literal(\n                                                SyntaxFactory.TriviaList(),\n                                                str,\n                                                str,\n                                                SyntaxFactory.TriviaList());\n\n                                            return (ExpressionSyntax)SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, syntaxToken);\n                                       })),\n                                       isActive: true)),\n                            }));\n            }\n\n            var usings = List(new[] { UsingDirective(ParseName(\"global::Orleans.Serialization.Codecs\")), UsingDirective(ParseName(\"global::Orleans.Serialization.GeneratedCodeHelpers\")) });\n            var namespaces = new List<MemberDeclarationSyntax>(_namespacedMembers.Count);\n            foreach (var pair in _namespacedMembers)\n            {\n                var ns = pair.Key;\n                var member = pair.Value;\n\n                namespaces.Add(NamespaceDeclaration(ParseName(ns)).WithMembers(List(member)).WithUsings(usings));\n            }\n\n            if (namespaces.Count > 0)\n            {\n                namespaces[namespaces.Count - 1] = namespaces[namespaces.Count - 1]\n                    .WithTrailingTrivia(\n                       SyntaxFactory.TriviaList(\n                           new List<SyntaxTrivia>\n                           {\n                                Trivia(\n                                   PragmaWarningDirectiveTrivia(\n                                       Token(SyntaxKind.RestoreKeyword),\n                                       SeparatedList(DisabledWarnings.Select(str =>\n                                       {\n                                           var syntaxToken = SyntaxFactory.Literal(\n                                                SyntaxFactory.TriviaList(),\n                                                str,\n                                                str,\n                                                SyntaxFactory.TriviaList());\n\n                                            return (ExpressionSyntax)SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, syntaxToken);\n                                       })),\n                                       isActive: true)),\n                           }));\n            }\n\n            return CompilationUnit()\n                .WithAttributeLists(List(assemblyAttributes))\n                .WithMembers(List(namespaces));\n        }\n\n        public static string GetGeneratedNamespaceName(ITypeSymbol type) => type.GetNamespaceAndNesting() switch\n        {\n            { Length: > 0 } ns => $\"{CodeGeneratorName}.{ns}\",\n            _ => CodeGeneratorName\n        };\n\n        public void AddMember(string ns, MemberDeclarationSyntax member)\n        {\n            if (!_namespacedMembers.TryGetValue(ns, out var existing))\n            {\n                existing = _namespacedMembers[ns] = new List<MemberDeclarationSyntax>();\n            }\n\n            existing.Add(member);\n        }\n\n        private void ComputeAssembliesToExamine(IAssemblySymbol asm, HashSet<IAssemblySymbol> expandedAssemblies)\n        {\n            if (!expandedAssemblies.Add(asm))\n            {\n                return;\n            }\n\n            if (!asm.GetAttributes(LibraryTypes.GenerateCodeForDeclaringAssemblyAttribute, out var attrs)) return;\n\n            foreach (var attr in attrs)\n            {\n                var param = attr.ConstructorArguments.First();\n                if (param.Kind != TypedConstantKind.Type)\n                {\n                    throw new ArgumentException($\"Unrecognized argument type in attribute [{attr.AttributeClass.Name}({param.ToCSharpString()})]\");\n                }\n\n                var type = (ITypeSymbol)param.Value;\n\n                // Recurse on the assemblies which the type was declared in.\n                var declaringAsm = type.OriginalDefinition.ContainingAssembly;\n                if (declaringAsm is null)\n                {\n                    var diagnostic = GenerateCodeForDeclaringAssemblyAttribute_NoDeclaringAssembly_Diagnostic.CreateDiagnostic(attr, type);\n                    throw new OrleansGeneratorDiagnosticAnalysisException(diagnostic);\n                }\n                else\n                {\n                    ComputeAssembliesToExamine(declaringAsm, expandedAssemblies);\n                }\n            }\n        }\n\n        // Returns descriptions of all data members (fields and properties)\n        private static IEnumerable<IMemberDescription> GetDataMembers(FieldIdAssignmentHelper fieldIdAssignmentHelper)\n        {\n            var members = new Dictionary<(uint, bool), IMemberDescription>();\n\n            foreach (var member in fieldIdAssignmentHelper.Members)\n            {\n                if (!fieldIdAssignmentHelper.TryGetSymbolKey(member, out var key))\n                    continue;\n                var (id, isConstructorParameter) = key;\n\n                // FieldDescription takes precedence over PropertyDescription (never replace)\n                if (member is IPropertySymbol property && !members.TryGetValue((id, isConstructorParameter), out _))\n                {\n                    members[(id, isConstructorParameter)] = new PropertyDescription(id, isConstructorParameter, property);\n                }\n\n                if (member is IFieldSymbol field)\n                {\n                    // FieldDescription takes precedence over PropertyDescription (add or replace)\n                    if (!members.TryGetValue((id, isConstructorParameter), out var existing) || existing is PropertyDescription)\n                    {\n                        members[(id, isConstructorParameter)] = new FieldDescription(id, isConstructorParameter, field);\n                    }\n                }\n            }\n            return members.Values;\n        }\n\n        public uint? GetId(ISymbol memberSymbol) => GetId(LibraryTypes, memberSymbol);\n\n        internal static uint? GetId(LibraryTypes libraryTypes, ISymbol memberSymbol)\n        {\n            return memberSymbol.GetAttribute(libraryTypes.IdAttributeType) is { } attr\n                ? (uint)attr.ConstructorArguments.First().Value\n                : null;\n        }\n\n        internal static string CreateHashedMethodId(IMethodSymbol methodSymbol)\n        {\n            var methodSignature = Format(methodSymbol);\n            var hash = XxHash32.Hash(Encoding.UTF8.GetBytes(methodSignature));\n            return $\"{HexConverter.ToString(hash)}\";\n\n            static string Format(IMethodSymbol methodInfo)\n            {\n                var result = new StringBuilder();\n                result.Append(methodInfo.ContainingType.ToDisplayName());\n                result.Append('.');\n                result.Append(methodInfo.Name);\n\n                if (methodInfo.IsGenericMethod)\n                {\n                    result.Append('<');\n                    var first = true;\n                    foreach (var typeArgument in methodInfo.TypeArguments)\n                    {\n                        if (!first) result.Append(',');\n                        else first = false;\n                        result.Append(typeArgument.Name);\n                    }\n\n                    result.Append('>');\n                }\n\n                {\n                    result.Append('(');\n                    var parameters = methodInfo.Parameters;\n                    var first = true;\n                    foreach (var parameter in parameters)\n                    {\n                        if (!first)\n                        {\n                            result.Append(',');\n                        }\n\n                        var parameterType = parameter.Type;\n                        switch (parameterType)\n                        {\n                            case ITypeParameterSymbol _:\n                                result.Append(parameterType.Name);\n                                break;\n                            default:\n                                result.Append(parameterType.ToDisplayName());\n                                break;\n                        }\n\n                        first = false;\n                    }\n                }\n\n                result.Append(')');\n                return result.ToString();\n            }\n        }\n\n        private uint? GetWellKnownTypeId(ISymbol symbol) => GetId(symbol);\n\n        public string GetAlias(ISymbol symbol) => (string)symbol.GetAttribute(LibraryTypes.AliasAttribute)?.ConstructorArguments.First().Value;\n\n        private CompoundTypeAliasComponent[] GetCompoundTypeAlias(ISymbol symbol)\n        {\n            var attr = symbol.GetAttribute(LibraryTypes.CompoundTypeAliasAttribute);\n            if (attr is null)\n            {\n                return null;\n            }\n\n            var allArgs = attr.ConstructorArguments;\n            if (allArgs.Length != 1 || allArgs[0].Values.Length == 0)\n            {\n                throw new ArgumentException($\"Unsupported arguments in attribute [{attr.AttributeClass.Name}({string.Join(\", \", allArgs.Select(a => a.ToCSharpString()))})]\");\n            }\n\n            var args = allArgs[0].Values;\n            var result = new CompoundTypeAliasComponent[args.Length];\n            for (var i = 0; i < args.Length; i++)\n            {\n                var arg = args[i];\n                if (arg.IsNull)\n                {\n                    throw new ArgumentNullException($\"Unsupported null argument in attribute [{attr.AttributeClass.Name}({string.Join(\", \", allArgs.Select(a => a.ToCSharpString()))})]\");\n                }\n\n                result[i] = arg.Value switch\n                {\n                    ITypeSymbol type => new CompoundTypeAliasComponent(type),\n                    string str => new CompoundTypeAliasComponent(str),\n                    _ => throw new ArgumentException($\"Unrecognized argument type for argument {arg.ToCSharpString()} in attribute [{attr.AttributeClass.Name}({string.Join(\", \", allArgs.Select(a => a.ToCSharpString()))})]\"),\n                };\n            }\n\n            return result;\n        }\n\n        internal static AttributeListSyntax GetGeneratedCodeAttributes() => GeneratedCodeAttributeSyntax;\n        private static readonly AttributeListSyntax GeneratedCodeAttributeSyntax =\n            AttributeList().AddAttributes(\n                Attribute(ParseName(\"global::System.CodeDom.Compiler.GeneratedCodeAttribute\"))\n                    .AddArgumentListArguments(\n                        AttributeArgument(CodeGeneratorName.GetLiteralExpression()),\n                        AttributeArgument(typeof(CodeGenerator).Assembly.GetName().Version.ToString().GetLiteralExpression())),\n                Attribute(ParseName(\"global::System.ComponentModel.EditorBrowsableAttribute\"))\n                    .AddArgumentListArguments(\n                        AttributeArgument(ParseName(\"global::System.ComponentModel.EditorBrowsableState\").Member(\"Never\"))),\n                        Attribute(ParseName(\"global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute\"))\n            );\n\n        internal static AttributeSyntax GetMethodImplAttributeSyntax() => MethodImplAttributeSyntax;\n        private static readonly AttributeSyntax MethodImplAttributeSyntax =\n            Attribute(ParseName(\"global::System.Runtime.CompilerServices.MethodImplAttribute\"))\n                .AddArgumentListArguments(AttributeArgument(ParseName(\"global::System.Runtime.CompilerServices.MethodImplOptions\").Member(\"AggressiveInlining\")));\n\n        internal void VisitInterface(INamedTypeSymbol interfaceType)\n        {\n            // Get or generate an invokable for the original method definition.\n            if (!SymbolEqualityComparer.Default.Equals(interfaceType, interfaceType.OriginalDefinition))\n            {\n                interfaceType = interfaceType.OriginalDefinition;\n            }\n\n            if (!_visitedInterfaces.Add(interfaceType))\n            {\n                return;\n            }\n\n            foreach (var proxyBase in GetProxyBases(interfaceType))\n            {\n                _ = GetInvokableInterfaceDescription(proxyBase.ProxyBaseType, interfaceType);\n            }\n\n            /*\n            foreach (var baseInterface in interfaceType.AllInterfaces)\n            {\n                VisitInterface(baseInterface);\n            }\n            */\n        }\n\n        internal bool TryGetInvokableInterfaceDescription(INamedTypeSymbol interfaceType, out ProxyInterfaceDescription result)\n        {\n            if (!TryGetProxyBaseDescription(interfaceType, out var description))\n            {\n                result = null;\n                return false;\n            }\n\n            result = GetInvokableInterfaceDescription(description.ProxyBaseType, interfaceType);\n            return true;\n        }\n\n        private readonly Dictionary<INamedTypeSymbol, List<InvokableMethodProxyBase>> _interfaceProxyBases = new(SymbolEqualityComparer.Default);\n        internal List<InvokableMethodProxyBase> GetProxyBases(INamedTypeSymbol interfaceType)\n        {\n            if (_interfaceProxyBases.TryGetValue(interfaceType, out var result))\n            {\n                return result;\n            }\n\n            result = new List<InvokableMethodProxyBase>();\n            if (interfaceType.GetAttributes(LibraryTypes.GenerateMethodSerializersAttribute, out var attributes, inherited: true))\n            {\n                foreach (var attribute in attributes)\n                {\n                    var proxyBase = GetProxyBaseDescription(attribute);\n                    if (!result.Contains(proxyBase))\n                    {\n                        result.Add(proxyBase);\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        internal bool TryGetProxyBaseDescription(INamedTypeSymbol interfaceType, out InvokableMethodProxyBase result)\n        {\n            var attribute = interfaceType.GetAttribute(LibraryTypes.GenerateMethodSerializersAttribute, inherited: true);\n            if (attribute == null)\n            {\n                result = null;\n                return false;\n            }\n\n            result = GetProxyBaseDescription(attribute);\n            return true;\n        }\n\n        private InvokableMethodProxyBase GetProxyBaseDescription(AttributeData attribute)\n        {\n            var proxyBaseType = ((INamedTypeSymbol)attribute.ConstructorArguments[0].Value).OriginalDefinition;\n            var isExtension = (bool)attribute.ConstructorArguments[1].Value;\n            var invokableBaseTypes = GetInvokableBaseTypes(proxyBaseType);\n            var descriptor = new InvokableMethodProxyBaseId(proxyBaseType, isExtension);\n            var description = new InvokableMethodProxyBase(this, descriptor, invokableBaseTypes);\n            return description;\n\n            Dictionary<INamedTypeSymbol, INamedTypeSymbol> GetInvokableBaseTypes(INamedTypeSymbol baseClass)\n            {\n                // Set the base invokable types which are used if attributes on individual methods do not override them.\n                if (!MetadataModel.ProxyBaseTypeInvokableBaseTypes.TryGetValue(baseClass, out var invokableBaseTypes))\n                {\n                    invokableBaseTypes = new Dictionary<INamedTypeSymbol, INamedTypeSymbol>(SymbolEqualityComparer.Default);\n                    if (baseClass.GetAttributes(LibraryTypes.DefaultInvokableBaseTypeAttribute, out var invokableBaseTypeAttributes))\n                    {\n                        foreach (var attr in invokableBaseTypeAttributes)\n                        {\n                            var ctorArgs = attr.ConstructorArguments;\n                            var returnType = (INamedTypeSymbol)ctorArgs[0].Value;\n                            var invokableBaseType = (INamedTypeSymbol)ctorArgs[1].Value;\n                            invokableBaseTypes[returnType] = invokableBaseType;\n                        }\n                    }\n\n                    MetadataModel.ProxyBaseTypeInvokableBaseTypes[baseClass] = invokableBaseTypes;\n                }\n\n                return invokableBaseTypes;\n            }\n        }\n\n        internal InvokableMethodProxyBase GetProxyBase(INamedTypeSymbol interfaceType)\n        {\n            if (!TryGetProxyBaseDescription(interfaceType, out var result))\n            {\n                throw new InvalidOperationException($\"Cannot get proxy base description for a type which does not have or inherit [{nameof(LibraryTypes.GenerateMethodSerializersAttribute)}]\");\n            }\n\n            return result;\n        }\n\n        private ProxyInterfaceDescription GetInvokableInterfaceDescription(INamedTypeSymbol proxyBaseType, INamedTypeSymbol interfaceType)\n        {\n            var originalInterface = interfaceType.OriginalDefinition;\n            if (MetadataModel.InvokableInterfaces.TryGetValue(originalInterface, out var description))\n            {\n                return description;\n            }\n\n            description = new ProxyInterfaceDescription(this, proxyBaseType, originalInterface);\n            MetadataModel.InvokableInterfaces.Add(originalInterface, description);\n\n            // Generate a proxy.\n            var (generatedClass, proxyDescription) = ProxyGenerator.Generate(description);\n\n            // Emit the generated proxy\n            if (Compilation.GetTypeByMetadataName(proxyDescription.MetadataName) == null)\n            {\n                AddMember(proxyDescription.InterfaceDescription.GeneratedNamespace, generatedClass);\n            }\n\n            MetadataModel.GeneratedProxies.Add(proxyDescription);\n\n            return description;\n        }\n\n        internal ProxyMethodDescription GetProxyMethodDescription(INamedTypeSymbol interfaceType, IMethodSymbol method)\n        {\n            var originalMethod = method.OriginalDefinition;\n            var proxyBaseInfo = GetProxyBase(interfaceType);\n\n            // For extensions, we want to ensure that the containing type is always the extension.\n            // This ensures that we will always know which 'component' to get in our SetTarget method.\n            // If the type is not an extension, use the original method definition's containing type.\n            // This is the interface where the type was originally defined.\n            var containingType = proxyBaseInfo.IsExtension ? interfaceType : originalMethod.ContainingType;\n\n            var invokableId = new InvokableMethodId(proxyBaseInfo, containingType, originalMethod);\n            var interfaceDescription = GetInvokableInterfaceDescription(invokableId.ProxyBase.ProxyBaseType, interfaceType);\n\n            // Get or generate an invokable for the original method definition.\n            if (!MetadataModel.GeneratedInvokables.TryGetValue(invokableId, out var generatedInvokable))\n            {\n                if (!_invokableMethodDescriptions.TryGetValue(invokableId, out var methodDescription))\n                {\n                    methodDescription = _invokableMethodDescriptions[invokableId] = InvokableMethodDescription.Create(invokableId, containingType);\n                }\n\n                generatedInvokable = MetadataModel.GeneratedInvokables[invokableId] = InvokableGenerator.Generate(methodDescription);\n\n                if (Compilation.GetTypeByMetadataName(generatedInvokable.MetadataName) == null)\n                {\n                    // Emit the generated code on-demand.\n                    AddMember(generatedInvokable.GeneratedNamespace, generatedInvokable.ClassDeclarationSyntax);\n\n                    // Ensure the type will have a serializer generated for it.\n                    MetadataModel.SerializableTypes.Add(generatedInvokable);\n\n                    foreach (var alias in generatedInvokable.CompoundTypeAliases)\n                    {\n                        MetadataModel.CompoundTypeAliases.Add(alias, generatedInvokable.OpenTypeSyntax);\n                    }\n                }\n            }\n\n            var proxyMethodDescription = ProxyMethodDescription.Create(interfaceDescription, generatedInvokable, method);\n\n            // For backwards compatibility, generate invokers for the specific implementation types as well, where they differ.\n            if (Options.GenerateCompatibilityInvokers && !SymbolEqualityComparer.Default.Equals(method.OriginalDefinition.ContainingType, interfaceType))\n            {\n                var compatInvokableId = new InvokableMethodId(proxyBaseInfo, interfaceType, method);\n                var compatMethodDescription = InvokableMethodDescription.Create(compatInvokableId, interfaceType);\n                var compatInvokable = InvokableGenerator.Generate(compatMethodDescription);\n                AddMember(compatInvokable.GeneratedNamespace, compatInvokable.ClassDeclarationSyntax);\n                var alias =\n                    InvokableGenerator.GetCompoundTypeAliasComponents(\n                        compatInvokableId,\n                        interfaceType,\n                        compatMethodDescription.GeneratedMethodId);\n                MetadataModel.CompoundTypeAliases.Add(alias, compatInvokable.OpenTypeSyntax);\n            }\n\n            return proxyMethodDescription;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/CopierGenerator.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing static Orleans.CodeGenerator.InvokableGenerator;\nusing static Orleans.CodeGenerator.SerializerGenerator;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class CopierGenerator\n    {\n        private const string BaseTypeCopierFieldName = \"_baseTypeCopier\";\n        private const string ActivatorFieldName = \"_activator\";\n        private const string DeepCopyMethodName = \"DeepCopy\";\n        private readonly CodeGenerator _codeGenerator;\n\n        public CopierGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        private LibraryTypes LibraryTypes => _codeGenerator.LibraryTypes;\n\n        public ClassDeclarationSyntax GenerateCopier(\n            ISerializableTypeDescription type,\n            Dictionary<ISerializableTypeDescription, TypeSyntax> defaultCopiers)\n        {\n            var isShallowCopyable = type.IsShallowCopyable;\n            if (isShallowCopyable && !type.IsGenericType)\n            {\n                defaultCopiers.Add(type, LibraryTypes.ShallowCopier.ToTypeSyntax(type.TypeSyntax));\n                return null;\n            }\n\n            var simpleClassName = GetSimpleClassName(type);\n\n            var members = new List<ISerializableMember>();\n            foreach (var member in type.Members)\n            {\n                if (!member.IsCopyable)\n                {\n                    continue;\n                }\n\n                if (member is ISerializableMember serializable)\n                {\n                    members.Add(serializable);\n                }\n                else if (member is IFieldDescription or IPropertyDescription)\n                {\n                    members.Add(new SerializableMember(_codeGenerator, member, members.Count));\n                }\n                else if (member is MethodParameterFieldDescription methodParameter)\n                {\n                    members.Add(new SerializableMethodMember(methodParameter));\n                }\n            }\n\n            var accessibility = type.Accessibility switch\n            {\n                Accessibility.Public => SyntaxKind.PublicKeyword,\n                _ => SyntaxKind.InternalKeyword,\n            };\n\n            var isExceptionType = type.IsExceptionType && type.SerializationHooks.Count == 0;\n\n            var baseType = isExceptionType ? QualifiedName(AliasQualifiedName(\"global\", IdentifierName(\"Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper\")), GenericName(Identifier(\"ExceptionCopier\"), TypeArgumentList(SeparatedList(new[] { type.TypeSyntax, type.BaseType.ToTypeSyntax() }))))\n                : (isShallowCopyable ? LibraryTypes.ShallowCopier : LibraryTypes.DeepCopier_1).ToTypeSyntax(type.TypeSyntax);\n\n            var classDeclaration = ClassDeclaration(simpleClassName)\n                .AddBaseListTypes(SimpleBaseType(baseType))\n                .AddModifiers(Token(accessibility), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes());\n\n            if (!isShallowCopyable)\n            {\n                var fieldDescriptions = GetFieldDescriptions(type, members, isExceptionType, out var onlyDeepFields);\n                var fieldDeclarations = GetFieldDeclarations(fieldDescriptions);\n                var ctor = GenerateConstructor(simpleClassName, fieldDescriptions, isExceptionType);\n\n                classDeclaration = classDeclaration.AddMembers(fieldDeclarations);\n\n                if (!isExceptionType)\n                {\n                    var copyMethod = GenerateMemberwiseDeepCopyMethod(type, fieldDescriptions, members, onlyDeepFields);\n                    classDeclaration = classDeclaration.AddMembers(copyMethod);\n                }\n\n                if (ctor != null)\n                    classDeclaration = classDeclaration.AddMembers(ctor);\n\n                if (isExceptionType || !type.IsSealedType)\n                {\n                    if (GenerateBaseCopierDeepCopyMethod(type, fieldDescriptions, members, isExceptionType) is { } baseCopier)\n                        classDeclaration = classDeclaration.AddMembers(baseCopier);\n\n                    if (!isExceptionType)\n                        classDeclaration = classDeclaration.AddBaseListTypes(SimpleBaseType(LibraryTypes.BaseCopier_1.ToTypeSyntax(type.TypeSyntax)));\n                }\n            }\n\n            if (type.IsGenericType)\n            {\n                classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, type.TypeParameters);\n            }\n\n            return classDeclaration;\n        }\n\n        public static string GetSimpleClassName(ISerializableTypeDescription serializableType) => GetSimpleClassName(serializableType.Name);\n\n        public static string GetSimpleClassName(string name) => $\"Copier_{name}\";\n\n        private MemberDeclarationSyntax[] GetFieldDeclarations(List<GeneratedFieldDescription> fieldDescriptions)\n        {\n            return fieldDescriptions.Select(GetFieldDeclaration).ToArray();\n\n            static MemberDeclarationSyntax GetFieldDeclaration(GeneratedFieldDescription description)\n            {\n                switch (description)\n                {\n                    case FieldAccessorDescription accessor when accessor.InitializationSyntax != null:\n                        return\n                            FieldDeclaration(VariableDeclaration(accessor.FieldType,\n                                SingletonSeparatedList(VariableDeclarator(accessor.FieldName).WithInitializer(EqualsValueClause(accessor.InitializationSyntax)))))\n                                .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                    case FieldAccessorDescription accessor when accessor.InitializationSyntax == null:\n                        //[UnsafeAccessor(UnsafeAccessorKind.Method, Name = \"set_Amount\")]\n                        //extern static void SetAmount(External instance, int value);\n                        return\n                            MethodDeclaration(\n                                PredefinedType(Token(SyntaxKind.VoidKeyword)),\n                                accessor.AccessorName)\n                                .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ExternKeyword), Token(SyntaxKind.StaticKeyword))\n                                .AddAttributeLists(AttributeList(SingletonSeparatedList(\n                                    Attribute(IdentifierName(\"System.Runtime.CompilerServices.UnsafeAccessor\"))\n                                        .AddArgumentListArguments(\n                                            AttributeArgument(\n                                                MemberAccessExpression(\n                                                        SyntaxKind.SimpleMemberAccessExpression,\n                                                        IdentifierName(\"System.Runtime.CompilerServices.UnsafeAccessorKind\"),\n                                                        IdentifierName(\"Method\"))),\n                                            AttributeArgument(\n                                                    LiteralExpression(\n                                                        SyntaxKind.StringLiteralExpression,\n                                                        Literal($\"set_{accessor.FieldName}\")))\n                                            .WithNameEquals(NameEquals(\"Name\"))))))\n                                .WithParameterList(\n                                    ParameterList(SeparatedList(new[]\n                                        {\n                                            Parameter(Identifier(\"instance\")).WithType(accessor.ContainingType),\n                                            Parameter(Identifier(\"value\")).WithType(description.FieldType)\n                                        })))\n                                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n                    default:\n                        return FieldDeclaration(VariableDeclaration(description.FieldType, SingletonSeparatedList(VariableDeclarator(description.FieldName))))\n                            .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                }\n            }\n        }\n\n        private ConstructorDeclarationSyntax GenerateConstructor(string simpleClassName, List<GeneratedFieldDescription> fieldDescriptions, bool isExceptionType)\n        {\n            var codecProviderAdded = false;\n            var parameters = new List<ParameterSyntax>();\n            var statements = new List<StatementSyntax>();\n\n            if (isExceptionType)\n            {\n                parameters.Add(Parameter(Identifier(\"codecProvider\")).WithType(LibraryTypes.ICodecProvider.ToTypeSyntax()));\n                codecProviderAdded = true;\n            }\n\n            foreach (var field in fieldDescriptions)\n            {\n                switch (field)\n                {\n                    case GeneratedFieldDescription _ when field.IsInjected:\n                        parameters.Add(Parameter(field.FieldName.ToIdentifier()).WithType(field.FieldType));\n                        statements.Add(ExpressionStatement(\n                            AssignmentExpression(\n                                SyntaxKind.SimpleAssignmentExpression,\n                                ThisExpression().Member(field.FieldName.ToIdentifierName()),\n                                Unwrapped(field.FieldName.ToIdentifierName()))));\n                        break;\n                    case CopierFieldDescription or BaseCopierFieldDescription when !field.IsInjected:\n                        if (!codecProviderAdded)\n                        {\n                            parameters.Add(Parameter(Identifier(\"codecProvider\")).WithType(LibraryTypes.ICodecProvider.ToTypeSyntax()));\n                            codecProviderAdded = true;\n                        }\n\n                        var copier = InvocationExpression(\n                            IdentifierName(\"OrleansGeneratedCodeHelper\").Member(GenericName(Identifier(\"GetService\"), TypeArgumentList(SingletonSeparatedList(field.FieldType)))),\n                            ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(IdentifierName(\"codecProvider\")) })));\n\n                        statements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, field.FieldName.ToIdentifierName(), copier)));\n                        break;\n                }\n            }\n\n            return statements.Count == 0 && !isExceptionType ? null : ConstructorDeclaration(simpleClassName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters.ToArray())\n                .AddBodyStatements(statements.ToArray())\n                .WithInitializer(isExceptionType ? ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(IdentifierName(\"codecProvider\"))))) : null);\n\n            static ExpressionSyntax Unwrapped(ExpressionSyntax expr)\n            {\n                return InvocationExpression(\n                    IdentifierName(\"OrleansGeneratedCodeHelper\").Member(\"UnwrapService\"),\n                    ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(expr) })));\n            }\n        }\n\n        private List<GeneratedFieldDescription> GetFieldDescriptions(\n            ISerializableTypeDescription serializableTypeDescription,\n            List<ISerializableMember> members,\n            bool isExceptionType,\n            out bool onlyDeepFields)\n        {\n            var serializationHooks = serializableTypeDescription.SerializationHooks;\n            onlyDeepFields = serializableTypeDescription.IsValueType && serializationHooks.Count == 0;\n\n            var fields = new List<GeneratedFieldDescription>();\n\n            if (!isExceptionType && serializableTypeDescription.HasComplexBaseType)\n            {\n                fields.Add(GetBaseTypeField(serializableTypeDescription));\n            }\n\n            if (!serializableTypeDescription.IsImmutable)\n            {\n                if (!isExceptionType && serializableTypeDescription.UseActivator && !serializableTypeDescription.IsAbstractType)\n                {\n                    onlyDeepFields = false;\n                    fields.Add(new ActivatorFieldDescription(LibraryTypes.IActivator_1.ToTypeSyntax(serializableTypeDescription.TypeSyntax), ActivatorFieldName));\n                }\n\n                // Add a copier field for any field in the target which does not have a static copier.\n                GetCopierFieldDescriptions(serializableTypeDescription.Members, fields);\n            }\n\n            foreach (var member in members)\n            {\n                if (onlyDeepFields && member.IsShallowCopyable) continue;\n\n                if (member.GetGetterFieldDescription() is { } getterFieldDescription)\n                {\n                    fields.Add(getterFieldDescription);\n                }\n\n                if (member.GetSetterFieldDescription() is { } setterFieldDescription)\n                {\n                    fields.Add(setterFieldDescription);\n                }\n            }\n\n            for (var hookIndex = 0; hookIndex < serializationHooks.Count; ++hookIndex)\n            {\n                var hookType = serializationHooks[hookIndex];\n                fields.Add(new SerializationHookFieldDescription(hookType.ToTypeSyntax(), $\"_hook{hookIndex}\"));\n            }\n\n            return fields;\n        }\n\n        private BaseCopierFieldDescription GetBaseTypeField(ISerializableTypeDescription serializableTypeDescription)\n        {\n            var baseType = serializableTypeDescription.BaseType;\n            if (baseType.HasAttribute(LibraryTypes.GenerateSerializerAttribute)\n                && (SymbolEqualityComparer.Default.Equals(baseType.ContainingAssembly, LibraryTypes.Compilation.Assembly) || baseType.ContainingAssembly.HasAttribute(LibraryTypes.TypeManifestProviderAttribute))\n                && baseType is not INamedTypeSymbol { IsGenericType: true })\n            {\n                // Use the concrete generated type and avoid expensive interface dispatch (except for generic types that will fall back to IBaseCopier<T>)\n                return new(QualifiedName(ParseName(GetGeneratedNamespaceName(baseType)), IdentifierName(GetSimpleClassName(baseType.Name))), true);\n            }\n\n            return new(LibraryTypes.BaseCopier_1.ToTypeSyntax(serializableTypeDescription.BaseTypeSyntax));\n        }\n\n        public void GetCopierFieldDescriptions(IEnumerable<IMemberDescription> members, List<GeneratedFieldDescription> fields)\n        {\n            var fieldIndex = 0;\n            var uniqueTypes = new HashSet<IMemberDescription>(MemberDescriptionTypeComparer.Default);\n            foreach (var member in members)\n            {\n                if (!member.IsCopyable)\n                {\n                    continue;\n                }\n\n                var t = member.Type;\n\n                if (LibraryTypes.IsShallowCopyable(t))\n                    continue;\n\n                foreach (var c in LibraryTypes.StaticCopiers)\n                    if (SymbolEqualityComparer.Default.Equals(c.UnderlyingType, t))\n                        goto skip;\n\n                if (member.Symbol.HasAttribute(LibraryTypes.ImmutableAttribute))\n                    continue;\n\n                if (!uniqueTypes.Add(member))\n                    continue;\n\n                TypeSyntax copierType;\n                if (t.HasAttribute(LibraryTypes.GenerateSerializerAttribute)\n                    && (SymbolEqualityComparer.Default.Equals(t.ContainingAssembly, LibraryTypes.Compilation.Assembly) || t.ContainingAssembly.HasAttribute(LibraryTypes.TypeManifestProviderAttribute))\n                    && t is not INamedTypeSymbol { IsGenericType: true, TypeArguments.Length: 0 })\n                {\n                    // Use the concrete generated type and avoid expensive interface dispatch (except for complex nested cases that will fall back to IDeepCopier<T>)\n                    SimpleNameSyntax name;\n                    if (t is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType)\n                    {\n                        // Construct the full generic type name\n                        name = GenericName(Identifier(GetSimpleClassName(t.Name)), TypeArgumentList(SeparatedList(namedTypeSymbol.TypeArguments.Select(arg => arg.ToTypeSyntax()))));\n                    }\n                    else\n                    {\n                        name = IdentifierName(GetSimpleClassName(t.Name));\n                    }\n                    copierType = QualifiedName(ParseName(GetGeneratedNamespaceName(t)), name);\n                }\n                else if (t is IArrayTypeSymbol { IsSZArray: true } array)\n                {\n                    copierType = LibraryTypes.ArrayCopier.Construct(array.ElementType).ToTypeSyntax();\n                }\n                else if (LibraryTypes.WellKnownCopiers.FindByUnderlyingType(t) is { } copier)\n                {\n                    // The copier is not a static copier and is also not a generic copiers.\n                    copierType = copier.CopierType.ToTypeSyntax();\n                }\n                else if (t is INamedTypeSymbol { ConstructedFrom: ISymbol unboundFieldType } named && LibraryTypes.WellKnownCopiers.FindByUnderlyingType(unboundFieldType) is { } genericCopier)\n                {\n                    // Construct the generic copier type using the field's type arguments.\n                    copierType = genericCopier.CopierType.Construct(named.TypeArguments.ToArray()).ToTypeSyntax();\n                }\n                else\n                {\n                    // Use the IDeepCopier<T> interface\n                    copierType = LibraryTypes.DeepCopier_1.ToTypeSyntax(member.TypeSyntax);\n                }\n\n                fields.Add(new CopierFieldDescription(copierType, $\"_copier{fieldIndex++}\", t));\nskip:;\n            }\n        }\n\n        private MemberDeclarationSyntax GenerateMemberwiseDeepCopyMethod(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> copierFields,\n            List<ISerializableMember> members,\n            bool onlyDeepFields)\n        {\n            var returnType = type.TypeSyntax;\n\n            var originalParam = \"original\".ToIdentifierName();\n            var contextParam = \"context\".ToIdentifierName();\n            var resultVar = \"result\".ToIdentifierName();\n\n            var body = new List<StatementSyntax>();\n\n            var membersCopied = false;\n            if (type.IsAbstractType)\n            {\n                // C#: return context.DeepCopy(original)\n                body.Add(ReturnStatement(InvocationExpression(contextParam.Member(\"DeepCopy\"), ArgumentList(SingletonSeparatedList(Argument(originalParam))))));\n                membersCopied = true;\n            }\n            else if (type.IsUnsealedImmutable)\n            {\n                // C#: return original is null || original.GetType() == typeof(T) ? original : context.DeepCopy(original);\n                var exactTypeMatch = BinaryExpression(SyntaxKind.EqualsExpression, InvocationExpression(originalParam.Member(\"GetType\")), TypeOfExpression(type.TypeSyntax));\n                var nullOrTypeMatch = BinaryExpression(SyntaxKind.LogicalOrExpression, BinaryExpression(SyntaxKind.IsExpression, originalParam, LiteralExpression(SyntaxKind.NullLiteralExpression)), exactTypeMatch);\n                var contextCopy = InvocationExpression(contextParam.Member(\"DeepCopy\"), ArgumentList(SingletonSeparatedList(Argument(originalParam))));\n                body.Add(ReturnStatement(ConditionalExpression(nullOrTypeMatch, originalParam, contextCopy)));\n                membersCopied = true;\n            }\n            else if (!type.IsValueType)\n            {\n                if (type.TrackReferences)\n                {\n                    // C#: if (context.TryGetCopy(original, out T existing)) return existing;\n                    var tryGetCopy = InvocationExpression(\n                        contextParam.Member(\"TryGetCopy\"),\n                        ArgumentList(SeparatedList(new[]\n                        {\n                            Argument(originalParam),\n                            Argument(DeclarationExpression(\n                                type.TypeSyntax,\n                                SingleVariableDesignation(Identifier(\"existing\"))))\n                                        .WithRefKindKeyword(Token(SyntaxKind.OutKeyword))\n                        })));\n                    body.Add(IfStatement(tryGetCopy, ReturnStatement(\"existing\".ToIdentifierName())));\n                }\n                else\n                {\n                    // C#: if (original is null) return null;\n                    body.Add(IfStatement(BinaryExpression(SyntaxKind.IsExpression, originalParam, LiteralExpression(SyntaxKind.NullLiteralExpression)), ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression))));\n                }\n\n                if (!type.IsSealedType)\n                {\n                    // C#: if (original.GetType() != typeof(T)) { return context.DeepCopy(original); }\n                    var exactTypeMatch = BinaryExpression(SyntaxKind.NotEqualsExpression, InvocationExpression(originalParam.Member(\"GetType\")), TypeOfExpression(type.TypeSyntax));\n                    var contextCopy = InvocationExpression(contextParam.Member(\"DeepCopy\"), ArgumentList(SingletonSeparatedList(Argument(originalParam))));\n                    body.Add(IfStatement(exactTypeMatch, ReturnStatement(contextCopy)));\n                }\n\n                // C#: var result = _activator.Create();\n                body.Add(LocalDeclarationStatement(\n                    VariableDeclaration(\n                        IdentifierName(\"var\"),\n                        SingletonSeparatedList(VariableDeclarator(\n                            resultVar.Identifier,\n                            argumentList: null,\n                            initializer: EqualsValueClause(GetCreateValueExpression(type, copierFields)))))));\n\n                if (type.TrackReferences)\n                {\n                    // C#: context.RecordCopy(original, result);\n                    body.Add(ExpressionStatement(InvocationExpression(contextParam.Member(\"RecordCopy\"), ArgumentList(SeparatedList(new[]\n                    {\n                        Argument(originalParam),\n                        Argument(resultVar)\n                    })))));\n                }\n\n                if (!type.IsSealedType)\n                {\n                    // C#: DeepCopy(original, result, context);\n                    body.Add(ExpressionStatement(InvocationExpression(IdentifierName(\"DeepCopy\"),\n                        ArgumentList(SeparatedList(new[] { Argument(originalParam), Argument(resultVar), Argument(contextParam) })))));\n                    body.Add(ReturnStatement(resultVar));\n                    membersCopied = true;\n                }\n                else if (type.HasComplexBaseType)\n                {\n                    // C#: _baseTypeCopier.DeepCopy(original, result, context);\n                    body.Add(\n                        ExpressionStatement(\n                            InvocationExpression(\n                                BaseTypeCopierFieldName.ToIdentifierName().Member(DeepCopyMethodName),\n                                ArgumentList(SeparatedList(new[]\n                                {\n                                    Argument(originalParam),\n                                    Argument(resultVar),\n                                    Argument(contextParam)\n                                })))));\n                }\n            }\n            else if (!onlyDeepFields)\n            {\n                // C#: var result = _activator.Create();\n                // or C#: var result = new TField();\n                // or C#: var result = default(TField);\n                body.Add(LocalDeclarationStatement(\n                    VariableDeclaration(\n                        IdentifierName(\"var\"),\n                        SingletonSeparatedList(VariableDeclarator(resultVar.Identifier)\n                        .WithInitializer(EqualsValueClause(GetCreateValueExpression(type, copierFields)))))));\n            }\n            else\n            {\n                originalParam = resultVar;\n            }\n\n            if (!membersCopied)\n            {\n                GenerateMemberwiseCopy(type, copierFields, members, originalParam, contextParam, resultVar, body, onlyDeepFields);\n                body.Add(ReturnStatement(resultVar));\n            }\n\n            var parameters = new[]\n            {\n                Parameter(originalParam.Identifier).WithType(type.TypeSyntax),\n                Parameter(contextParam.Identifier).WithType(LibraryTypes.CopyContext.ToTypeSyntax())\n            };\n\n            return MethodDeclaration(returnType, DeepCopyMethodName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n        }\n\n        private ExpressionSyntax GetCreateValueExpression(ISerializableTypeDescription type, List<GeneratedFieldDescription> copierFields)\n        {\n            return type.UseActivator switch\n            {\n                true => InvocationExpression(copierFields.Find(f => f is ActivatorFieldDescription).FieldName.ToIdentifierName().Member(\"Create\")),\n                false => type.GetObjectCreationExpression()\n            };\n        }\n\n        private MemberDeclarationSyntax GenerateBaseCopierDeepCopyMethod(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> copierFields,\n            List<ISerializableMember> members,\n            bool isExceptionType)\n        {\n            var inputParam = \"input\".ToIdentifierName();\n            var resultParam = \"output\".ToIdentifierName();\n            var contextParam = \"context\".ToIdentifierName();\n\n            var body = new List<StatementSyntax>();\n\n            if (type.HasComplexBaseType)\n            {\n                // C#: _baseTypeCopier.DeepCopy(original, result, context);\n                body.Add(\n                    ExpressionStatement(\n                        InvocationExpression(\n                            (isExceptionType ? (ExpressionSyntax)BaseExpression() : IdentifierName(BaseTypeCopierFieldName)).Member(DeepCopyMethodName),\n                            ArgumentList(SeparatedList(new[]\n                            {\n                                Argument(inputParam),\n                                Argument(resultParam),\n                                Argument(contextParam)\n                            })))));\n            }\n\n            var emptyBodyCount = body.Count;\n\n            GenerateMemberwiseCopy(\n                type,\n                copierFields,\n                members,\n                inputParam,\n                contextParam,\n                resultParam,\n                body);\n\n            if (isExceptionType && body.Count == emptyBodyCount)\n                return null;\n\n            var parameters = new[]\n            {\n                Parameter(inputParam.Identifier).WithType(type.TypeSyntax),\n                Parameter(resultParam.Identifier).WithType(type.TypeSyntax),\n                Parameter(contextParam.Identifier).WithType(LibraryTypes.CopyContext.ToTypeSyntax())\n            };\n\n            var method = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), DeepCopyMethodName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n\n            if (isExceptionType)\n                method = method.AddModifiers(Token(SyntaxKind.OverrideKeyword));\n\n            return method;\n        }\n\n        private void GenerateMemberwiseCopy(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> copierFields,\n            List<ISerializableMember> members,\n            IdentifierNameSyntax sourceVar,\n            IdentifierNameSyntax contextVar,\n            IdentifierNameSyntax destinationVar,\n            List<StatementSyntax> body,\n            bool onlyDeepFields = false)\n        {\n            AddSerializationCallbacks(type, sourceVar, destinationVar, \"OnCopying\", body);\n\n            var copiers = type.IsUnsealedImmutable ? null : copierFields.OfType<ICopierDescription>()\n                    .Concat(LibraryTypes.StaticCopiers)\n                    .ToList();\n\n            var orderedMembers = members.OrderBy(m => m.Member.FieldId);\n            foreach (var member in orderedMembers)\n            {\n                if (onlyDeepFields && member.IsShallowCopyable) continue;\n\n                var getValueExpression = GenerateMemberCopy(\n                    copierFields,\n                    inputValue: member.GetGetter(sourceVar),\n                    contextVar,\n                    copiers,\n                    member);\n                var memberAssignment = ExpressionStatement(member.GetSetter(destinationVar, getValueExpression));\n                body.Add(memberAssignment);\n            }\n\n            AddSerializationCallbacks(type, sourceVar, destinationVar, \"OnCopied\", body);\n        }\n\n        public ExpressionSyntax GenerateMemberCopy(\n            List<GeneratedFieldDescription> copierFields,\n            ExpressionSyntax inputValue,\n            ExpressionSyntax copyContextVar,\n            List<ICopierDescription> copiers,\n            ISerializableMember member)\n        {\n            if (copiers is null || member.IsShallowCopyable)\n                return inputValue;\n\n            var description = member.Member;\n\n            // Copiers can either be static classes or injected into the constructor.\n            // Either way, the member signatures are the same.\n            var memberType = description.Type;\n            var copier = copiers.Find(f => SymbolEqualityComparer.Default.Equals(f.UnderlyingType, memberType));\n            ExpressionSyntax getValueExpression;\n\n            if (copier is null)\n            {\n                getValueExpression = InvocationExpression(\n                    copyContextVar.Member(DeepCopyMethodName),\n                    ArgumentList(SeparatedList(new[] { Argument(inputValue) })));\n            }\n            else\n            {\n                ExpressionSyntax copierExpression;\n                var staticCopier = LibraryTypes.StaticCopiers.FindByUnderlyingType(memberType);\n                if (staticCopier != null)\n                {\n                    copierExpression = staticCopier.CopierType.ToNameSyntax();\n                }\n                else\n                {\n                    var instanceCopier = copierFields.First(f => f is CopierFieldDescription cf && SymbolEqualityComparer.Default.Equals(cf.UnderlyingType, memberType));\n                    copierExpression = IdentifierName(instanceCopier.FieldName);\n                }\n\n                getValueExpression = InvocationExpression(\n                    copierExpression.Member(DeepCopyMethodName),\n                    ArgumentList(SeparatedList(new[] { Argument(inputValue), Argument(copyContextVar) })));\n                if (!SymbolEqualityComparer.Default.Equals(copier.UnderlyingType, member.Member.Type))\n                {\n                    // If the member type type differs from the copier type (eg because the member is an array), cast the result.\n                    getValueExpression = CastExpression(description.TypeSyntax, getValueExpression);\n                }\n            }\n\n            return getValueExpression;\n        }\n\n        private void AddSerializationCallbacks(ISerializableTypeDescription type, IdentifierNameSyntax originalInstance, IdentifierNameSyntax resultInstance, string callbackMethodName, List<StatementSyntax> body)\n        {\n            var serializationHooks = type.SerializationHooks;\n            for (var hookIndex = 0; hookIndex < serializationHooks.Count; ++hookIndex)\n            {\n                var hookType = serializationHooks[hookIndex];\n                var member = hookType.GetAllMembers<IMethodSymbol>(callbackMethodName, Accessibility.Public).FirstOrDefault();\n                if (member is null || member.Parameters.Length != 2)\n                {\n                    continue;\n                }\n\n                var originalArgument = Argument(originalInstance);\n                if (member.Parameters[0].RefKind == RefKind.Ref)\n                {\n                    originalArgument = originalArgument.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                }\n\n                var resultArgument = Argument(resultInstance);\n                if (member.Parameters[1].RefKind == RefKind.Ref)\n                {\n                    resultArgument = resultArgument.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                }\n\n                body.Add(ExpressionStatement(InvocationExpression(\n                    IdentifierName($\"_hook{hookIndex}\").Member(callbackMethodName),\n                    ArgumentList(SeparatedList(new[] { originalArgument, resultArgument })))));\n            }\n        }\n\n        internal sealed class BaseCopierFieldDescription : GeneratedFieldDescription\n        {\n            public BaseCopierFieldDescription(TypeSyntax fieldType, bool concreteType = false) : base(fieldType, BaseTypeCopierFieldName)\n                => IsInjected = !concreteType;\n\n            public override bool IsInjected { get; }\n        }\n\n        internal sealed class CopierFieldDescription : GeneratedFieldDescription, ICopierDescription\n        {\n            public CopierFieldDescription(TypeSyntax fieldType, string fieldName, ITypeSymbol underlyingType) : base(fieldType, fieldName)\n            {\n                UnderlyingType = underlyingType;\n            }\n\n            public ITypeSymbol UnderlyingType { get; }\n            public override bool IsInjected => false;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/CanNotGenerateImplicitFieldIdsDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class CanNotGenerateImplicitFieldIdsDiagnostic\n{\n    public const string DiagnosticId = DiagnosticRuleId.CanNotGenerateImplicitFieldIds;\n    public const string Title = \"Implicit field identifiers could not be generated\";\n    public const string MessageFormat = \"Could not generate implicit field identifiers for the type {0}: {reason}\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n    internal static Diagnostic CreateDiagnostic(ISymbol symbol, string reason) => Diagnostic.Create(Rule, symbol.Locations.First(), symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), reason);\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/DiagnosticRuleId.cs",
    "content": "// Centralized diagnostic rule IDs for Orleans.CodeGenerator\nnamespace Orleans.CodeGenerator.Diagnostics;\n\ninternal static class DiagnosticRuleId\n{\n    public const string InaccessibleSetter = \"ORLEANS0101\";\n    public const string InvalidRpcMethodReturnType = \"ORLEANS0102\";\n    public const string UnhandledCodeGenerationException = \"ORLEANS0103\";\n    public const string IncorrectProxyBaseClassSpecification = \"ORLEANS0104\";\n    public const string RpcInterfaceProperty = \"ORLEANS0105\";\n    public const string CanNotGenerateImplicitFieldIds = \"ORLEANS0106\";\n    public const string InaccessibleSerializableType = \"ORLEANS0107\";\n    public const string GenerateCodeForDeclaringAssemblyAttribute_NoDeclaringAssembly = \"ORLEANS0108\";\n    public const string MultipleCancellationTokenParameters = \"ORLEANS0109\";\n    public const string ReferenceAssemblyWithGenerateSerializer = \"ORLEANS0110\";\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/GenerateCodeForDeclaringAssemblyAttribute_NoDeclaringAssembly_Diagnostic.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class GenerateCodeForDeclaringAssemblyAttribute_NoDeclaringAssembly_Diagnostic\n{\n    public const string DiagnosticId = DiagnosticRuleId.GenerateCodeForDeclaringAssemblyAttribute_NoDeclaringAssembly;\n    public const string Title = \"Types passed to GenerateCodeForDeclaringAssemblyAttribute must have a declaring assembly\";\n    public const string MessageFormat = \"The type {0} provided as an argument to {1} does not have a declaring assembly\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n    internal static Diagnostic CreateDiagnostic(AttributeData attribute, ITypeSymbol type) => Diagnostic.Create(Rule, attribute.ApplicationSyntaxReference.SyntaxTree.GetLocation(attribute.ApplicationSyntaxReference.Span), type.ToDisplayString(), attribute.ToString());\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/InaccessibleSerializableTypeDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class InaccessibleSerializableTypeDiagnostic\n{\n    public const string RuleId = DiagnosticRuleId.InaccessibleSerializableType; \n    public const string Title = \"Serializable type must be accessible from generated code\";\n    public const string MessageFormat = \"The type {0} is marked as being serializable but it is inaccessible from generated code\";\n    public const string Descsription = \"Source generation requires that all types marked as serializable are accessible from generated code. Either make the type public or make it internal and ensure that internals are visible to the generated code.\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Descsription);\n\n    internal static Diagnostic CreateDiagnostic(ISymbol symbol) => Diagnostic.Create(Rule, symbol.Locations.First(), symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/InaccessibleSetterDiagnostic.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class InaccessibleSetterDiagnostic\n{\n    public const string RuleId = DiagnosticRuleId.InaccessibleSetter; \n    private const string Category = \"Usage\";\n    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.InaccessibleSetterTitle), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.InaccessibleSetterMessageFormat), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.InaccessibleSetterDescription), Resources.ResourceManager, typeof(Resources));\n\n    internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n    public static Diagnostic CreateDiagnostic(Location location, string identifier) => Diagnostic.Create(Rule, location, identifier);\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/IncorrectProxyBaseClassSpecificationDiagnostic.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class IncorrectProxyBaseClassSpecificationDiagnostic\n{\n    public const string RuleId = DiagnosticRuleId.IncorrectProxyBaseClassSpecification; \n    private const string Category = \"Usage\";\n    private static readonly LocalizableString Title = \"The proxy base class specified is not a valid proxy base class\";\n    private static readonly LocalizableString MessageFormat = \"Proxy base class {0} does not conform to requirements: {1}\";\n    private static readonly LocalizableString Description = \"Proxy base clases must conform. Please report this bug by opening an issue https://github.com/dotnet/orleans/issues/new.\";\n\n    internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n    internal static Diagnostic CreateDiagnostic(INamedTypeSymbol baseClass, Location location, string complaint) => Diagnostic.Create(Rule, location, baseClass.ToDisplayString(), complaint);\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/InvalidRpcMethodReturnTypeDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class InvalidRpcMethodReturnTypeDiagnostic\n{\n    public const string RuleId = DiagnosticRuleId.InvalidRpcMethodReturnType; \n    private const string Category = \"Usage\";\n    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.InvalidRpcMethodReturnTypeTitle), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.InvalidRpcMethodReturnTypeMessageFormat), Resources.ResourceManager, typeof(Resources));\n    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.InvalidRpcMethodReturnTypeDescription), Resources.ResourceManager, typeof(Resources));\n\n    internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n    public static Diagnostic CreateDiagnostic(Location location, string returnType, string methodIdentifier, string supportedReturnTypeList) => Diagnostic.Create(Rule, location, returnType, methodIdentifier, supportedReturnTypeList);\n\n    internal static Diagnostic CreateDiagnostic(InvokableMethodDescription methodDescription)\n    {\n        var methodReturnType = methodDescription.Method.ReturnType;\n        var diagnostic = CreateDiagnostic(\n            methodDescription.Method.OriginalDefinition.Locations.FirstOrDefault(),\n            methodReturnType.ToDisplayString(),\n            methodDescription.Method.ToDisplayString(),\n            string.Join(\", \", methodDescription.InvokableBaseTypes.Keys.Select(v => v.ToDisplayString())));\n        return diagnostic;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/MultipleCancellationTokenParametersDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class MultipleCancellationTokenParametersDiagnostic\n{\n    public const string DiagnosticId = DiagnosticRuleId.MultipleCancellationTokenParameters;\n    public const string Title = \"Grain method has multiple parameters of type CancellationToken\";\n    public const string MessageFormat = \"The type {0} contains method {1} which has multiple CancellationToken parameters. Only a single CancellationToken parameter is supported.\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n    internal static Diagnostic CreateDiagnostic(IMethodSymbol symbol) => Diagnostic.Create(Rule, symbol.Locations.First(), symbol.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), symbol.Name);\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/ReferenceAssemblyWithGenerateSerializerDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class ReferenceAssemblyWithGenerateSerializerDiagnostic\n{\n    public const string DiagnosticId = DiagnosticRuleId.ReferenceAssemblyWithGenerateSerializer;\n    public const string Title = \"[GenerateSerializer] used in a reference assembly\";\n    public const string MessageFormat = \"The type {0} is marked with [GenerateSerializer] in a reference assembly\";\n    public const string Description = \"The type {0} is marked with [GenerateSerializer] in a reference assembly. Serialization is likely to fail. Options: (1) Enable code generation on the target project directly; (2) Disable reference assemblies using <ProduceReferenceAssembly>false</ProduceReferenceAssembly> in the codegen project; (3) Use a different serializer or create surrogates. See https://aka.ms/orleans-serialization for details.\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n    internal static Diagnostic CreateDiagnostic(ISymbol symbol) => Diagnostic.Create(Rule, symbol.Locations.First(), symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/RpcInterfacePropertyDiagnostic.cs",
    "content": "using System.Linq;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class RpcInterfacePropertyDiagnostic\n{\n    public const string DiagnosticId = DiagnosticRuleId.RpcInterfaceProperty;\n    public const string Title = \"RPC interfaces must not contain properties\";\n    public const string MessageFormat = \"The interface {0} contains a property {1}. RPC interfaces must not contain properties.\";\n    public const string Category = \"Usage\";\n\n    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true);\n\n    internal static Diagnostic CreateDiagnostic(INamedTypeSymbol interfaceSymbol, IPropertySymbol property) => Diagnostic.Create(Rule, property.Locations.First(), interfaceSymbol.ToDisplayString(), property.ToDisplayString());\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Diagnostics/UnhandledCodeGenerationExceptionDiagnostic.cs",
    "content": "using System;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.Diagnostics;\n\npublic static class UnhandledCodeGenerationExceptionDiagnostic\n{\n    public const string RuleId = DiagnosticRuleId.UnhandledCodeGenerationException; \n    private const string Category = \"Usage\";\n    private static readonly LocalizableString Title = \"An unhandled source generation exception occurred\";\n    private static readonly LocalizableString MessageFormat = \"An unhandled exception occurred while generating source for your project: {0} {1}\";\n    private static readonly LocalizableString Description = \"Please report this bug by opening an issue https://github.com/dotnet/orleans/issues/new.\";\n\n    internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);\n\n    internal static Diagnostic CreateDiagnostic(Exception exception) => Diagnostic.Create(Rule, location: null, messageArgs: new[] { exception.ToString(), exception.StackTrace });\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/FieldIdAssignmentHelper.cs",
    "content": "#nullable enable\nusing System;\nusing System.Buffers.Binary;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Microsoft.CodeAnalysis;\nusing Orleans.CodeGenerator.Hashing;\nusing Orleans.CodeGenerator.Model;\nusing Orleans.CodeGenerator.SyntaxGeneration;\n\nnamespace Orleans.CodeGenerator;\n\ninternal class FieldIdAssignmentHelper\n{\n    private readonly GenerateFieldIds _implicitMemberSelectionStrategy;\n    private readonly ImmutableArray<IParameterSymbol> _constructorParameters;\n    private readonly LibraryTypes _libraryTypes;\n    private readonly ISymbol[] _memberSymbols;\n    private readonly Dictionary<ISymbol, (uint, bool)> _symbols = new(SymbolEqualityComparer.Default);\n\n    public bool IsValidForSerialization { get; }\n    public string? FailureReason { get; private set; }\n    public IEnumerable<ISymbol> Members => _memberSymbols;\n\n    public FieldIdAssignmentHelper(INamedTypeSymbol typeSymbol, ImmutableArray<IParameterSymbol> constructorParameters,\n        GenerateFieldIds implicitMemberSelectionStrategy, LibraryTypes libraryTypes)\n    {\n        _constructorParameters = constructorParameters;\n        _implicitMemberSelectionStrategy = implicitMemberSelectionStrategy;\n        _libraryTypes = libraryTypes;\n        _memberSymbols = GetMembers(typeSymbol).ToArray();\n\n        IsValidForSerialization = _implicitMemberSelectionStrategy != GenerateFieldIds.None && !HasMemberWithIdAnnotation() ? GenerateImplicitFieldIds() : ExtractFieldIdAnnotations();\n    }\n\n    public bool TryGetSymbolKey(ISymbol symbol, out (uint, bool) key) => _symbols.TryGetValue(symbol, out key);\n\n    private bool HasMemberWithIdAnnotation() => Array.Exists(_memberSymbols, member => member.HasAttribute(_libraryTypes.IdAttributeType));\n\n    private IEnumerable<ISymbol> GetMembers(INamedTypeSymbol symbol)\n    {\n        foreach (var member in symbol.GetMembers().OrderBy(m => m.MetadataName))\n        {\n            if (member.IsStatic || member.IsAbstract)\n            {\n                continue;\n            }\n\n            if (member is not (IFieldSymbol or IPropertySymbol))\n            {\n                continue;\n            }\n\n            if (member.HasAttribute(_libraryTypes.NonSerializedAttribute))\n            {\n                continue;\n            }\n\n            yield return member;\n        }\n    }\n\n    private bool ExtractFieldIdAnnotations()\n    {\n        foreach (var member in _memberSymbols)\n        {\n            if (member is IPropertySymbol prop)\n            {\n                var id = CodeGenerator.GetId(_libraryTypes, prop);\n\n                if (id.HasValue)\n                {\n                    _symbols[member] = (id.Value, false);\n                }\n                else if (PropertyUtility.GetMatchingPrimaryConstructorParameter(prop, _constructorParameters) is { } prm)\n                {\n                    id = CodeGenerator.GetId(_libraryTypes, prop);\n                    if (id.HasValue)\n                    {\n                        _symbols[member] = (id.Value, true);\n                    }\n                    else\n                    {\n                        _symbols[member] = ((uint)_constructorParameters.IndexOf(prm), true);\n                    }\n                }\n            }\n\n            if (member is IFieldSymbol field)\n            {\n                var id = CodeGenerator.GetId(_libraryTypes, field);\n                var isConstructorParameter = false;\n\n                if (!id.HasValue)\n                {\n                    var property = PropertyUtility.GetMatchingProperty(field, _memberSymbols);\n                    if (property is null)\n                    {\n                        continue;\n                    }\n\n                    id = CodeGenerator.GetId(_libraryTypes, property);\n                    if (!id.HasValue)\n                    {\n                        var constructorParameter = _constructorParameters.FirstOrDefault(x => x.Name.Equals(property.Name, StringComparison.OrdinalIgnoreCase));\n                        if (constructorParameter is not null)\n                        {\n                            id = (uint)_constructorParameters.IndexOf(constructorParameter);\n                            isConstructorParameter = true;\n                        }\n                    }\n                }\n\n                if (id.HasValue)\n                {\n                    _symbols[member] = (id.Value, isConstructorParameter);\n                }\n            }\n        }\n        return true;\n    }\n\n    private static (string, uint) GetCanonicalNameAndFieldId(ITypeSymbol typeSymbol, string name)\n    {\n        name = PropertyUtility.GetCanonicalName(name);\n\n        // compute the hash from the type name (without namespace, to allow it to move around) and name\n        var typeName = typeSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);\n        var hashCode = ComputeHash($\"{typeName}%{name}\");\n        return (name, (uint)hashCode);\n\n        static unsafe uint ComputeHash(string data)\n        {\n            uint hash;\n            var input = BitConverter.IsLittleEndian ? MemoryMarshal.AsBytes(data.AsSpan()) : Encoding.Unicode.GetBytes(data);\n            XxHash32.TryHash(input, new Span<byte>((byte*)&hash, sizeof(uint)), out _);\n            return BitConverter.IsLittleEndian ? hash : BinaryPrimitives.ReverseEndianness(hash);\n        }\n    }\n\n    private bool GenerateImplicitFieldIds()\n    {\n        var constructorFieldIds = new Dictionary<string, uint>();\n        foreach (var parameter in _constructorParameters)\n        {\n            var (canonicalName, fieldId) = GetCanonicalNameAndFieldId(parameter.Type, parameter.Name);\n            constructorFieldIds[canonicalName] = fieldId;\n        }\n\n        var success = _implicitMemberSelectionStrategy switch\n        {\n            GenerateFieldIds.PublicProperties => GenerateFromProperties(_memberSymbols.OfType<IPropertySymbol>()),\n            _ => false\n        };\n\n        // validate - we can only use generated field ids if there were no collisions\n        if (success && _symbols.Values.Distinct().Count() != _symbols.Count)\n        {\n            FailureReason = \"hash collision (consider using explicit [Id] annotations for this type)\";\n            return false;\n        }\n\n        return success;\n\n        bool GenerateFromProperties(IEnumerable<IPropertySymbol> properties)\n        {\n            foreach (var property in properties)\n            {\n                var (canonicalName, fieldId) = GetCanonicalNameAndFieldId(property.Type, property.Name);\n                var isConstructorParameter = constructorFieldIds.TryGetValue(canonicalName, out var constructorFieldId);\n\n                // abort when inconsistencies are detected\n                if (isConstructorParameter && fieldId != constructorFieldId)\n                {\n                    FailureReason = $\"type mismatch for property {property.Name} and its corresponding constructor parameter\";\n                    return false;\n                }\n\n                // for immutable types we must currently use the backing field of the public property, as the serialization\n                // engine does not call a custom constructor to recreate the instance\n                var mustUseField = property.SetMethod == null || property.IsReadOnly\n                                                              || property.SetMethod.IsInitOnly\n                                                              || property.IsStatic\n                                                              || property.SetMethod.IsAbstract;\n                ISymbol? symbol = mustUseField ? PropertyUtility.GetMatchingField(property, _memberSymbols) : property;\n                if (symbol == null)\n                    continue;\n\n                _symbols[symbol] = (fieldId, isConstructorParameter);\n            }\n            return _symbols.Count > 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Hashing/BitOperations.cs",
    "content": "﻿#nullable enable\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.CodeGenerator.Hashing\n{\n    internal static class BitOperations\n    {\n        /// <summary>\n        /// Rotates the specified value left by the specified number of bits.\n        /// Similar in behavior to the x86 instruction ROL.\n        /// </summary>\n        /// <param name=\"value\">The value to rotate.</param>\n        /// <param name=\"offset\">The number of bits to rotate by.\n        /// Any value outside the range [0..31] is treated as congruent mod 32.</param>\n        /// <returns>The rotated value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static uint RotateLeft(uint value, int offset) => (value << offset) | (value >> (32 - offset));\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Hashing/HexConverter.cs",
    "content": "#nullable enable\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.CodeGenerator.Hashing\n{\n    internal static class HexConverter\n    {\n        public static unsafe string ToString(ReadOnlySpan<byte> bytes)\n        {\n            // Adapted from: https://github.com/dotnet/runtime/blob/f156fb9dcf121e536b93ae90bcc5e8e6d5336062/src/libraries/Common/src/System/HexConverter.cs#L196\n            \n            Span<char> result = bytes.Length > 16 ?\n                new char[bytes.Length * 2].AsSpan() :\n                stackalloc char[bytes.Length * 2];\n\n            int pos = 0;\n            foreach (byte b in bytes)\n            {\n                ToCharsBuffer(b, result, pos);\n                pos += 2;\n            }\n\n            return result.ToString();\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            static void ToCharsBuffer(byte value, Span<char> buffer, int startingIndex = 0)\n            {\n                var difference = ((value & 0xF0U) << 4) + (value & 0x0FU) - 0x8989U;\n                var packedResult = (((uint)-(int)difference & 0x7070U) >> 4) + difference + 0xB9B9U;\n\n                buffer[startingIndex + 1] = (char)(packedResult & 0xFF);\n                buffer[startingIndex] = (char)(packedResult >> 8);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Hashing/NonCryptographicHashAlgorithm.cs",
    "content": "#nullable enable\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System;\nusing System.Buffers;\nusing System.ComponentModel;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.CodeGenerator.Hashing\n{\n    /// <summary>\n    ///   Represents a non-cryptographic hash algorithm.\n    /// </summary>\n    internal abstract class NonCryptographicHashAlgorithm\n    {\n        /// <summary>\n        ///   Gets the number of bytes produced from this hash algorithm.\n        /// </summary>\n        /// <value>The number of bytes produced from this hash algorithm.</value>\n        public int HashLengthInBytes { get; }\n\n        /// <summary>\n        ///   Called from constructors in derived classes to initialize the\n        ///   <see cref=\"NonCryptographicHashAlgorithm\"/> class.\n        /// </summary>\n        /// <param name=\"hashLengthInBytes\">\n        ///   The number of bytes produced from this hash algorithm.\n        /// </param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">\n        ///   <paramref name=\"hashLengthInBytes\"/> is less than 1.\n        /// </exception>\n        protected NonCryptographicHashAlgorithm(int hashLengthInBytes)\n        {\n            if (hashLengthInBytes < 1)\n                throw new ArgumentOutOfRangeException(nameof(hashLengthInBytes));\n\n            HashLengthInBytes = hashLengthInBytes;\n        }\n\n        /// <summary>\n        ///   When overridden in a derived class,\n        ///   appends the contents of <paramref name=\"source\"/> to the data already\n        ///   processed for the current hash computation.\n        /// </summary>\n        /// <param name=\"source\">The data to process.</param>\n        public abstract void Append(ReadOnlySpan<byte> source);\n\n        /// <summary>\n        ///   When overridden in a derived class,\n        ///   resets the hash computation to the initial state.\n        /// </summary>\n        public abstract void Reset();\n\n        /// <summary>\n        ///   When overridden in a derived class,\n        ///   writes the computed hash value to <paramref name=\"destination\"/>\n        ///   without modifying accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <remarks>\n        ///   <para>\n        ///     Implementations of this method must write exactly\n        ///     <see cref=\"HashLengthInBytes\"/> bytes to <paramref name=\"destination\"/>.\n        ///     Do not assume that the buffer was zero-initialized.\n        ///   </para>\n        ///   <para>\n        ///     The <see cref=\"NonCryptographicHashAlgorithm\"/> class validates the\n        ///     size of the buffer before calling this method, and slices the span\n        ///     down to be exactly <see cref=\"HashLengthInBytes\"/> in length.\n        ///   </para>\n        /// </remarks>\n        protected abstract void GetCurrentHashCore(Span<byte> destination);\n\n        /// <summary>\n        ///   Appends the contents of <paramref name=\"source\"/> to the data already\n        ///   processed for the current hash computation.\n        /// </summary>\n        /// <param name=\"source\">The data to process.</param>\n        /// <exception cref=\"ArgumentNullException\">\n        ///   <paramref name=\"source\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        public void Append(byte[] source)\n        {\n            if (source is null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            Append(new ReadOnlySpan<byte>(source));\n        }\n\n        /// <summary>\n        ///   Appends the contents of <paramref name=\"stream\"/> to the data already\n        ///   processed for the current hash computation.\n        /// </summary>\n        /// <param name=\"stream\">The data to process.</param>\n        /// <exception cref=\"ArgumentNullException\">\n        ///   <paramref name=\"stream\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        /// <seealso cref=\"AppendAsync(Stream, CancellationToken)\"/>\n        public void Append(Stream stream)\n        {\n            if (stream is null)\n            {\n                throw new ArgumentNullException(nameof(stream));\n            }\n\n            byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);\n\n            while (true)\n            {\n                int read = stream.Read(buffer, 0, buffer.Length);\n\n                if (read == 0)\n                {\n                    break;\n                }\n\n                Append(new ReadOnlySpan<byte>(buffer, 0, read));\n            }\n\n            ArrayPool<byte>.Shared.Return(buffer);\n        }\n\n        /// <summary>\n        ///   Asychronously reads the contents of <paramref name=\"stream\"/>\n        ///   and appends them to the data already\n        ///   processed for the current hash computation.\n        /// </summary>\n        /// <param name=\"stream\">The data to process.</param>\n        /// <param name=\"cancellationToken\">\n        ///   The token to monitor for cancellation requests.\n        ///   The default value is <see cref=\"CancellationToken.None\"/>.\n        /// </param>\n        /// <returns>\n        ///   A task that represents the asynchronous append operation.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">\n        ///   <paramref name=\"stream\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        public Task AppendAsync(Stream stream, CancellationToken cancellationToken = default)\n        {\n            if (stream is null)\n            {\n                throw new ArgumentNullException(nameof(stream));\n            }\n\n            return AppendAsyncCore(stream, cancellationToken);\n        }\n\n        private async Task AppendAsyncCore(Stream stream, CancellationToken cancellationToken)\n        {\n            byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);\n\n            while (true)\n            {\n#if NETCOREAPP\n                int read = await stream.ReadAsync(buffer.AsMemory(), cancellationToken).ConfigureAwait(false);\n#else\n                int read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);\n#endif\n\n                if (read == 0)\n                {\n                    break;\n                }\n\n                Append(new ReadOnlySpan<byte>(buffer, 0, read));\n            }\n\n            ArrayPool<byte>.Shared.Return(buffer);\n        }\n\n        /// <summary>\n        ///   Gets the current computed hash value without modifying accumulated state.\n        /// </summary>\n        /// <returns>\n        ///   The hash value for the data already provided.\n        /// </returns>\n        public byte[] GetCurrentHash()\n        {\n            byte[] ret = new byte[HashLengthInBytes];\n            GetCurrentHashCore(ret);\n            return ret;\n        }\n\n        /// <summary>\n        ///   Attempts to write the computed hash value to <paramref name=\"destination\"/>\n        ///   without modifying accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <param name=\"bytesWritten\">\n        ///   On success, receives the number of bytes written to <paramref name=\"destination\"/>.\n        /// </param>\n        /// <returns>\n        ///   <see langword=\"true\"/> if <paramref name=\"destination\"/> is long enough to receive\n        ///   the computed hash value; otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool TryGetCurrentHash(Span<byte> destination, out int bytesWritten)\n        {\n            if (destination.Length < HashLengthInBytes)\n            {\n                bytesWritten = 0;\n                return false;\n            }\n\n            GetCurrentHashCore(destination.Slice(0, HashLengthInBytes));\n            bytesWritten = HashLengthInBytes;\n            return true;\n        }\n\n        /// <summary>\n        ///   Writes the computed hash value to <paramref name=\"destination\"/>\n        ///   without modifying accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <returns>\n        ///   The number of bytes written to <paramref name=\"destination\"/>,\n        ///   which is always <see cref=\"HashLengthInBytes\"/>.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">\n        ///   <paramref name=\"destination\"/> is shorter than <see cref=\"HashLengthInBytes\"/>.\n        /// </exception>\n        public int GetCurrentHash(Span<byte> destination)\n        {\n            if (destination.Length < HashLengthInBytes)\n            {\n                throw new ArgumentException(@\"destination too short\", nameof(destination));\n            }\n\n            GetCurrentHashCore(destination.Slice(0, HashLengthInBytes));\n            return HashLengthInBytes;\n        }\n\n        /// <summary>\n        ///   Gets the current computed hash value and clears the accumulated state.\n        /// </summary>\n        /// <returns>\n        ///   The hash value for the data already provided.\n        /// </returns>\n        public byte[] GetHashAndReset()\n        {\n            byte[] ret = new byte[HashLengthInBytes];\n            GetHashAndResetCore(ret);\n            return ret;\n        }\n\n        /// <summary>\n        ///   Attempts to write the computed hash value to <paramref name=\"destination\"/>.\n        ///   If successful, clears the accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <param name=\"bytesWritten\">\n        ///   On success, receives the number of bytes written to <paramref name=\"destination\"/>.\n        /// </param>\n        /// <returns>\n        ///   <see langword=\"true\"/> and clears the accumulated state\n        ///   if <paramref name=\"destination\"/> is long enough to receive\n        ///   the computed hash value; otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten)\n        {\n            if (destination.Length < HashLengthInBytes)\n            {\n                bytesWritten = 0;\n                return false;\n            }\n\n            GetHashAndResetCore(destination.Slice(0, HashLengthInBytes));\n            bytesWritten = HashLengthInBytes;\n            return true;\n        }\n\n        /// <summary>\n        ///   Writes the computed hash value to <paramref name=\"destination\"/>\n        ///   then clears the accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <returns>\n        ///   The number of bytes written to <paramref name=\"destination\"/>,\n        ///   which is always <see cref=\"HashLengthInBytes\"/>.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">\n        ///   <paramref name=\"destination\"/> is shorter than <see cref=\"HashLengthInBytes\"/>.\n        /// </exception>\n        public int GetHashAndReset(Span<byte> destination)\n        {\n            if (destination.Length < HashLengthInBytes)\n            {\n                throw new ArgumentException(@\"destination too short\", nameof(destination));\n            }\n\n            GetHashAndResetCore(destination.Slice(0, HashLengthInBytes));\n            return HashLengthInBytes;\n        }\n\n        /// <summary>\n        ///   Writes the computed hash value to <paramref name=\"destination\"/>\n        ///   then clears the accumulated state.\n        /// </summary>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <remarks>\n        ///   <para>\n        ///     Implementations of this method must write exactly\n        ///     <see cref=\"HashLengthInBytes\"/> bytes to <paramref name=\"destination\"/>.\n        ///     Do not assume that the buffer was zero-initialized.\n        ///   </para>\n        ///   <para>\n        ///     The <see cref=\"NonCryptographicHashAlgorithm\"/> class validates the\n        ///     size of the buffer before calling this method, and slices the span\n        ///     down to be exactly <see cref=\"HashLengthInBytes\"/> in length.\n        ///   </para>\n        ///   <para>\n        ///     The default implementation of this method calls\n        ///     <see cref=\"GetCurrentHashCore\"/> followed by <see cref=\"Reset\"/>.\n        ///     Overrides of this method do not need to call either of those methods,\n        ///     but must ensure that the caller cannot observe a difference in behavior.\n        ///   </para>\n        /// </remarks>\n        protected virtual void GetHashAndResetCore(Span<byte> destination)\n        {\n            Debug.Assert(destination.Length == HashLengthInBytes);\n\n            GetCurrentHashCore(destination);\n            Reset();\n        }\n\n        /// <summary>\n        ///   This method is not supported and should not be called.\n        ///   Call <see cref=\"GetCurrentHash()\"/> or <see cref=\"GetHashAndReset()\"/>\n        ///   instead.\n        /// </summary>\n        /// <returns>This method will always throw a <see cref=\"NotSupportedException\"/>.</returns>\n        /// <exception cref=\"NotSupportedException\">In all cases.</exception>\n        [EditorBrowsable(EditorBrowsableState.Never)]\n        [Obsolete(\"Use GetCurrentHash() to retrieve the computed hash code.\", true)]\n#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member\n        public override int GetHashCode()\n#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member\n        {\n            throw new NotSupportedException(\"GetHashCode\");\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Hashing/XxHash32.State.cs",
    "content": "#nullable enable\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System;\nusing System.Buffers.Binary;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\n\n// Implemented from the specification at\n// https://github.com/Cyan4973/xxHash/blob/f9155bd4c57e2270a4ffbb176485e5d713de1c9b/doc/xxhash_spec.md\n\nnamespace Orleans.CodeGenerator.Hashing\n{\n    internal sealed partial class XxHash32\n    {\n        private struct State\n        {\n            private const uint Prime32_1 = 0x9E3779B1;\n            private const uint Prime32_2 = 0x85EBCA77;\n            private const uint Prime32_3 = 0xC2B2AE3D;\n            private const uint Prime32_4 = 0x27D4EB2F;\n            private const uint Prime32_5 = 0x165667B1;\n\n            private uint _acc1;\n            private uint _acc2;\n            private uint _acc3;\n            private uint _acc4;\n            private readonly uint _smallAcc;\n            private bool _hadFullStripe;\n\n            internal State(uint seed)\n            {\n                _acc1 = seed + unchecked(Prime32_1 + Prime32_2);\n                _acc2 = seed + Prime32_2;\n                _acc3 = seed;\n                _acc4 = seed - Prime32_1;\n\n                _smallAcc = seed + Prime32_5;\n                _hadFullStripe = false;\n            }\n\n            internal void ProcessStripe(ReadOnlySpan<byte> source)\n            {\n                Debug.Assert(source.Length >= StripeSize);\n                source = source.Slice(0, StripeSize);\n\n                _acc1 = ApplyRound(_acc1, source);\n                _acc2 = ApplyRound(_acc2, source.Slice(sizeof(uint)));\n                _acc3 = ApplyRound(_acc3, source.Slice(2 * sizeof(uint)));\n                _acc4 = ApplyRound(_acc4, source.Slice(3 * sizeof(uint)));\n\n                _hadFullStripe = true;\n            }\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            private readonly uint Converge()\n            {\n                return\n                    BitOperations.RotateLeft(_acc1, 1) +\n                    BitOperations.RotateLeft(_acc2, 7) +\n                    BitOperations.RotateLeft(_acc3, 12) +\n                    BitOperations.RotateLeft(_acc4, 18);\n            }\n\n            private static uint ApplyRound(uint acc, ReadOnlySpan<byte> lane)\n            {\n                acc += BinaryPrimitives.ReadUInt32LittleEndian(lane) * Prime32_2;\n                acc = BitOperations.RotateLeft(acc, 13);\n                acc *= Prime32_1;\n\n                return acc;\n            }\n\n            internal readonly uint Complete(int length, ReadOnlySpan<byte> remaining)\n            {\n                uint acc = _hadFullStripe ? Converge() : _smallAcc;\n\n                acc += (uint)length;\n\n                while (remaining.Length >= sizeof(uint))\n                {\n                    uint lane = BinaryPrimitives.ReadUInt32LittleEndian(remaining);\n                    acc += lane * Prime32_3;\n                    acc = BitOperations.RotateLeft(acc, 17);\n                    acc *= Prime32_4;\n\n                    remaining = remaining.Slice(sizeof(uint));\n                }\n\n                for (int i = 0; i < remaining.Length; i++)\n                {\n                    uint lane = remaining[i];\n                    acc += lane * Prime32_5;\n                    acc = BitOperations.RotateLeft(acc, 11);\n                    acc *= Prime32_1;\n                }\n\n                acc ^= (acc >> 15);\n                acc *= Prime32_2;\n                acc ^= (acc >> 13);\n                acc *= Prime32_3;\n                acc ^= (acc >> 16);\n\n                return acc;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Hashing/XxHash32.cs",
    "content": "#nullable enable\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System;\nusing System.Buffers.Binary;\n\n// Implemented from the specification at\n// https://github.com/Cyan4973/xxHash/blob/f9155bd4c57e2270a4ffbb176485e5d713de1c9b/doc/xxhash_spec.md\n\nnamespace Orleans.CodeGenerator.Hashing\n{\n    /// <summary>\n    ///   Provides an implementation of the XxHash32 algorithm.\n    /// </summary>\n    internal sealed partial class XxHash32 : NonCryptographicHashAlgorithm\n    {\n        private const int HashSize = sizeof(uint);\n        private const int StripeSize = 4 * sizeof(uint);\n\n        private readonly uint _seed;\n        private State _state;\n        private byte[]? _holdback;\n        private int _length;\n\n        /// <summary>\n        ///   Initializes a new instance of the <see cref=\"XxHash32\"/> class.\n        /// </summary>\n        /// <remarks>\n        ///   The XxHash32 algorithm supports an optional seed value.\n        ///   Instances created with this constructor use the default seed, zero.\n        /// </remarks>\n        public XxHash32()\n            : this(0)\n        {\n        }\n\n        /// <summary>\n        ///   Initializes a new instance of the <see cref=\"XxHash32\"/> class with\n        ///   a specified seed.\n        /// </summary>\n        /// <param name=\"seed\">\n        ///   The hash seed value for computations from this instance.\n        /// </param>\n        public XxHash32(int seed)\n            : base(HashSize)\n        {\n            _seed = (uint)seed;\n            Reset();\n        }\n\n        /// <summary>\n        ///   Resets the hash computation to the initial state.\n        /// </summary>\n        public override void Reset()\n        {\n            _state = new State(_seed);\n            _length = 0;\n        }\n\n        /// <summary>\n        ///   Appends the contents of <paramref name=\"source\"/> to the data already\n        ///   processed for the current hash computation.\n        /// </summary>\n        /// <param name=\"source\">The data to process.</param>\n        public override void Append(ReadOnlySpan<byte> source)\n        {\n            // Every time we've read 16 bytes, process the stripe.\n            // Data that isn't perfectly mod-16 gets stored in a holdback\n            // buffer.\n\n            int held = _length & 0x0F;\n\n            if (held != 0)\n            {\n                int remain = StripeSize - held;\n\n                if (source.Length >= remain)\n                {\n                    source.Slice(0, remain).CopyTo(_holdback.AsSpan(held));\n                    _state.ProcessStripe(_holdback);\n\n                    source = source.Slice(remain);\n                    _length += remain;\n                }\n                else\n                {\n                    source.CopyTo(_holdback.AsSpan(held));\n                    _length += source.Length;\n                    return;\n                }\n            }\n\n            while (source.Length >= StripeSize)\n            {\n                _state.ProcessStripe(source);\n                source = source.Slice(StripeSize);\n                _length += StripeSize;\n            }\n\n            if (source.Length > 0)\n            {\n                _holdback ??= new byte[StripeSize];\n                source.CopyTo(_holdback);\n                _length += source.Length;\n            }\n        }\n\n        /// <summary>\n        ///   Writes the computed hash value to <paramref name=\"destination\"/>\n        ///   without modifying accumulated state.\n        /// </summary>\n        protected override void GetCurrentHashCore(Span<byte> destination)\n        {\n            int remainingLength = _length & 0x0F;\n            ReadOnlySpan<byte> remaining = ReadOnlySpan<byte>.Empty;\n\n            if (remainingLength > 0)\n            {\n                remaining = new ReadOnlySpan<byte>(_holdback, 0, remainingLength);\n            }\n\n            uint acc = _state.Complete(_length, remaining);\n            BinaryPrimitives.WriteUInt32BigEndian(destination, acc);\n        }\n\n        /// <summary>\n        ///   Computes the XxHash32 hash of the provided data.\n        /// </summary>\n        /// <param name=\"source\">The data to hash.</param>\n        /// <returns>The XxHash32 hash of the provided data.</returns>\n        /// <exception cref=\"ArgumentNullException\">\n        ///   <paramref name=\"source\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        public static byte[] Hash(byte[] source)\n        {\n            if (source is null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            return Hash(new ReadOnlySpan<byte>(source));\n        }\n\n        /// <summary>\n        ///   Computes the XxHash32 hash of the provided data using the provided seed.\n        /// </summary>\n        /// <param name=\"source\">The data to hash.</param>\n        /// <param name=\"seed\">The seed value for this hash computation.</param>\n        /// <returns>The XxHash32 hash of the provided data.</returns>\n        /// <exception cref=\"ArgumentNullException\">\n        ///   <paramref name=\"source\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        public static byte[] Hash(byte[] source, int seed)\n        {\n            if (source is null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            return Hash(new ReadOnlySpan<byte>(source), seed);\n        }\n\n        /// <summary>\n        ///   Computes the XxHash32 hash of the provided data.\n        /// </summary>\n        /// <param name=\"source\">The data to hash.</param>\n        /// <param name=\"seed\">The seed value for this hash computation. The default is zero.</param>\n        /// <returns>The XxHash32 hash of the provided data.</returns>\n        public static byte[] Hash(ReadOnlySpan<byte> source, int seed = 0)\n        {\n            byte[] ret = new byte[HashSize];\n            StaticHash(source, ret, seed);\n            return ret;\n        }\n\n        /// <summary>\n        ///   Attempts to compute the XxHash32 hash of the provided data into the provided destination.\n        /// </summary>\n        /// <param name=\"source\">The data to hash.</param>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <param name=\"bytesWritten\">\n        ///   On success, receives the number of bytes written to <paramref name=\"destination\"/>.\n        /// </param>\n        /// <param name=\"seed\">The seed value for this hash computation. The default is zero.</param>\n        /// <returns>\n        ///   <see langword=\"true\"/> if <paramref name=\"destination\"/> is long enough to receive\n        ///   the computed hash value (4 bytes); otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public static bool TryHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten, int seed = 0)\n        {\n            if (destination.Length < HashSize)\n            {\n                bytesWritten = 0;\n                return false;\n            }\n\n            bytesWritten = StaticHash(source, destination, seed);\n            return true;\n        }\n\n        /// <summary>\n        ///   Computes the XxHash32 hash of the provided data into the provided destination.\n        /// </summary>\n        /// <param name=\"source\">The data to hash.</param>\n        /// <param name=\"destination\">The buffer that receives the computed hash value.</param>\n        /// <param name=\"seed\">The seed value for this hash computation. The default is zero.</param>\n        /// <returns>\n        ///   The number of bytes written to <paramref name=\"destination\"/>.\n        /// </returns>\n        public static int Hash(ReadOnlySpan<byte> source, Span<byte> destination, int seed = 0)\n        {\n            if (destination.Length < HashSize)\n                throw new ArgumentException(@\"destination too short\", nameof(destination));\n\n            return StaticHash(source, destination, seed);\n        }\n\n        private static int StaticHash(ReadOnlySpan<byte> source, Span<byte> destination, int seed)\n        {\n            int totalLength = source.Length;\n            State state = new State((uint)seed);\n\n            while (source.Length >= StripeSize)\n            {\n                state.ProcessStripe(source);\n                source = source.Slice(StripeSize);\n            }\n\n            uint val = state.Complete(totalLength, source);\n            BinaryPrimitives.WriteUInt32BigEndian(destination, val);\n            return HashSize;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/InvokableGenerator.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.CodeGenerator.Diagnostics;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing System.Linq.Expressions;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Generates RPC stub objects called invokers.\n    /// </summary>\n    internal class InvokableGenerator\n    {\n        private readonly CodeGenerator _codeGenerator;\n\n        public InvokableGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        private LibraryTypes LibraryTypes => _codeGenerator.LibraryTypes;\n\n        public GeneratedInvokableDescription Generate(InvokableMethodDescription invokableMethodInfo)\n        {\n            var method = invokableMethodInfo.Method;\n            var generatedClassName = GetSimpleClassName(invokableMethodInfo);\n\n            var baseClassType = GetBaseClassType(invokableMethodInfo);\n            var fieldDescriptions = GetFieldDescriptions(invokableMethodInfo);\n            var fields = GetFieldDeclarations(invokableMethodInfo, fieldDescriptions);\n            var (ctor, ctorArgs) = GenerateConstructor(generatedClassName, invokableMethodInfo, baseClassType);\n            var accessibility = GetAccessibility(method);\n            var compoundTypeAliases = GetCompoundTypeAliasAttributeArguments(invokableMethodInfo, invokableMethodInfo.Key);\n\n            List<INamedTypeSymbol> serializationHooks = new();\n            if (baseClassType.GetAttributes(LibraryTypes.SerializationCallbacksAttribute, out var hookAttributes))\n            {\n                foreach (var hookAttribute in hookAttributes)\n                {\n                    var hookType = (INamedTypeSymbol)hookAttribute.ConstructorArguments[0].Value;\n                    serializationHooks.Add(hookType);\n                }\n            }\n\n            var targetField = fieldDescriptions.OfType<TargetFieldDescription>().Single();\n\n            var accessibilityKind = accessibility switch\n            {\n                Accessibility.Public => SyntaxKind.PublicKeyword,\n                _ => SyntaxKind.InternalKeyword,\n            };\n\n            var classDeclaration = GetClassDeclarationSyntax(\n                invokableMethodInfo,\n                generatedClassName,\n                baseClassType,\n                fieldDescriptions,\n                fields,\n                ctor,\n                compoundTypeAliases,\n                targetField,\n                accessibilityKind);\n\n            string returnValueInitializerMethod = null;\n            if (baseClassType.GetAttribute(LibraryTypes.ReturnValueProxyAttribute) is { ConstructorArguments: { Length: > 0 } attrArgs })\n            {\n                returnValueInitializerMethod = (string)attrArgs[0].Value;\n            }\n\n            while (baseClassType.HasAttribute(LibraryTypes.SerializerTransparentAttribute))\n            {\n                baseClassType = baseClassType.BaseType;\n            }\n\n            var invokerDescription = new GeneratedInvokableDescription(\n                invokableMethodInfo,\n                accessibility,\n                generatedClassName,\n                CodeGenerator.GetGeneratedNamespaceName(invokableMethodInfo.ContainingInterface),\n                fieldDescriptions.OfType<IMemberDescription>().ToList(),\n                serializationHooks,\n                baseClassType,\n                ctorArgs,\n                compoundTypeAliases,\n                returnValueInitializerMethod,\n                classDeclaration);\n            return invokerDescription;\n\n            static Accessibility GetAccessibility(IMethodSymbol methodSymbol)\n            {\n                Accessibility accessibility = methodSymbol.DeclaredAccessibility;\n                var t = methodSymbol.ContainingType;\n                while (t is not null)\n                {\n                    if ((int)t.DeclaredAccessibility < (int)accessibility)\n                    {\n                        accessibility = t.DeclaredAccessibility;\n                    }\n\n                    t = t.ContainingType;\n                }\n\n                return accessibility;\n            }\n        }\n\n        private ClassDeclarationSyntax GetClassDeclarationSyntax(\n            InvokableMethodDescription method,\n            string generatedClassName,\n            INamedTypeSymbol baseClassType,\n            List<InvokerFieldDescription> fieldDescriptions,\n            MemberDeclarationSyntax[] fields,\n            ConstructorDeclarationSyntax ctor,\n            List<CompoundTypeAliasComponent[]> compoundTypeAliases,\n            TargetFieldDescription targetField,\n            SyntaxKind accessibilityKind)\n        {\n            var classDeclaration = ClassDeclaration(generatedClassName)\n                .AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax(method.TypeParameterSubstitutions)))\n                .AddModifiers(Token(accessibilityKind), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes())\n                .AddMembers(fields);\n\n            foreach (var alias in compoundTypeAliases)\n            {\n                classDeclaration = classDeclaration.AddAttributeLists(\n                    AttributeList(SingletonSeparatedList(GetCompoundTypeAliasAttribute(alias))));\n            }\n\n            if (ctor != null)\n            {\n                classDeclaration = classDeclaration.AddMembers(ctor);\n            }\n\n            if (method.ResponseTimeoutTicks.HasValue)\n            {\n                classDeclaration = classDeclaration.AddMembers(GenerateResponseTimeoutPropertyMembers(method.ResponseTimeoutTicks.Value));\n            }\n\n            classDeclaration = AddOptionalMembers(classDeclaration,\n                    GenerateGetArgumentCount(method),\n                    GenerateGetMethodName(method),\n                    GenerateGetInterfaceName(method),\n                    GenerateGetActivityName(method),\n                    GenerateGetInterfaceType(method),\n                    GenerateGetMethod(),\n                    GenerateSetTargetMethod(method, targetField, fieldDescriptions),\n                    GenerateGetTargetMethod(targetField),\n                    GenerateDisposeMethod(fieldDescriptions, baseClassType),\n                    GenerateGetArgumentMethod(method, fieldDescriptions),\n                    GenerateSetArgumentMethod(method, fieldDescriptions),\n                    GenerateInvokeInnerMethod(method, fieldDescriptions, targetField),\n                    GenerateGetCancellationTokenMethod(method, fieldDescriptions),\n                    GenerateTryCancelMethod(method, fieldDescriptions),\n                    GenerateIsCancellableProperty(method));\n\n            if (method.AllTypeParameters.Count > 0)\n            {\n                classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, method.AllTypeParameters);\n            }\n\n            return classDeclaration;\n        }\n\n        private MemberDeclarationSyntax[] GenerateResponseTimeoutPropertyMembers(long value)\n        {\n            var timespanField = FieldDeclaration(\n                        VariableDeclaration(\n                            LibraryTypes.TimeSpan.ToTypeSyntax(),\n                            SingletonSeparatedList(VariableDeclarator(\"_responseTimeoutValue\")\n                            .WithInitializer(EqualsValueClause(\n                                InvocationExpression(\n                                    IdentifierName(\"global::System.TimeSpan\").Member(\"FromTicks\"),\n                                    ArgumentList(SeparatedList(new[]\n                                    {\n                                        Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(value)))\n                                    }))))))))\n                        .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n\n            var responseTimeoutProperty = MethodDeclaration(NullableType(LibraryTypes.TimeSpan.ToTypeSyntax()), \"GetDefaultResponseTimeout\")\n                .WithExpressionBody(ArrowExpressionClause(IdentifierName(\"_responseTimeoutValue\")))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword));\n            return new MemberDeclarationSyntax[] { timespanField, responseTimeoutProperty };\n        }\n\n        private ClassDeclarationSyntax AddOptionalMembers(ClassDeclarationSyntax decl, params MemberDeclarationSyntax[] items)\n            => decl.WithMembers(decl.Members.AddRange(items.Where(i => i != null)));\n\n        internal AttributeSyntax GetCompoundTypeAliasAttribute(CompoundTypeAliasComponent[] argValues)\n        {\n            var args = new AttributeArgumentSyntax[argValues.Length];\n            for (var i = 0; i < argValues.Length; i++)\n            {\n                ExpressionSyntax value;\n                value = argValues[i].Value switch\n                {\n                    string stringValue => LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(stringValue)),\n                    ITypeSymbol typeValue => TypeOfExpression(typeValue.ToOpenTypeSyntax()),\n                    _ => throw new InvalidOperationException($\"Unsupported value\")\n                };\n\n                args[i] = AttributeArgument(value);\n            }\n\n            return Attribute(LibraryTypes.CompoundTypeAliasAttribute.ToNameSyntax()).AddArgumentListArguments(args);\n        }\n\n        internal static List<CompoundTypeAliasComponent[]> GetCompoundTypeAliasAttributeArguments(InvokableMethodDescription methodDescription, InvokableMethodId invokableId)\n        {\n            var result = new List<CompoundTypeAliasComponent[]>(2);\n            var containingInterface = methodDescription.ContainingInterface;\n            if (methodDescription.HasAlias)\n            {\n                result.Add(GetCompoundTypeAliasComponents(invokableId, containingInterface, methodDescription.MethodId));\n            }\n\n            result.Add(GetCompoundTypeAliasComponents(invokableId, containingInterface, methodDescription.GeneratedMethodId));\n            return result;\n        }\n\n        public static CompoundTypeAliasComponent[] GetCompoundTypeAliasComponents(\n            InvokableMethodId invokableId,\n            INamedTypeSymbol containingInterface,\n            string methodId)\n        {\n            var proxyBase = invokableId.ProxyBase;\n            var proxyBaseComponents = proxyBase.CompositeAliasComponents;\n            var extensionArgCount = proxyBase.IsExtension ? 1 : 0;\n            var alias = new CompoundTypeAliasComponent[1 + proxyBaseComponents.Length + extensionArgCount + 2];\n            alias[0] = new(\"inv\");\n            for (var i = 0; i < proxyBaseComponents.Length; i++)\n            {\n                alias[i + 1] = proxyBaseComponents[i];\n            }\n\n            alias[1 + proxyBaseComponents.Length] = new(containingInterface);\n\n            // For grain extensions, also explicitly include the method's containing type.\n            // This is to distinguish between different extension methods with the same id (eg, alias) but different containing types.\n            if (proxyBase.IsExtension)\n            {\n                alias[1 + proxyBaseComponents.Length + 1] = new(invokableId.Method.ContainingType);\n            }\n\n            alias[1 + proxyBaseComponents.Length + extensionArgCount + 1] = new(methodId);\n            return alias;\n        }\n\n        private INamedTypeSymbol GetBaseClassType(InvokableMethodDescription method)\n        {\n            var methodReturnType = method.Method.ReturnType;\n            if (methodReturnType is not INamedTypeSymbol namedMethodReturnType)\n            {\n                throw new OrleansGeneratorDiagnosticAnalysisException(InvalidRpcMethodReturnTypeDiagnostic.CreateDiagnostic(method));\n            }\n\n            if (method.InvokableBaseTypes.TryGetValue(namedMethodReturnType, out var baseClassType))\n            {\n                return baseClassType;\n            }\n\n            if (namedMethodReturnType.ConstructedFrom is { IsGenericType: true, IsUnboundGenericType: false } constructedFrom)\n            {\n                var unbound = constructedFrom.ConstructUnboundGenericType();\n                if (method.InvokableBaseTypes.TryGetValue(unbound, out baseClassType))\n                {\n                    return baseClassType.ConstructedFrom.Construct(namedMethodReturnType.TypeArguments.ToArray());\n                }\n            }\n\n            throw new OrleansGeneratorDiagnosticAnalysisException(InvalidRpcMethodReturnTypeDiagnostic.CreateDiagnostic(method));\n        }\n\n        private MemberDeclarationSyntax GenerateSetTargetMethod(\n            InvokableMethodDescription methodDescription,\n            TargetFieldDescription targetField,\n            List<InvokerFieldDescription> fieldDescriptions)\n        {\n            var holder = IdentifierName(\"holder\");\n            var holderParameter = holder.Identifier;\n\n            var containingInterface = methodDescription.ContainingInterface;\n            var targetType = containingInterface.ToTypeSyntax();\n            var isExtension = methodDescription.Key.ProxyBase.IsExtension;\n            var (name, args) = isExtension switch\n            {\n                true => (\"GetComponent\", SingletonSeparatedList(Argument(TypeOfExpression(targetType)))),\n                _ => (\"GetTarget\", SeparatedList<ArgumentSyntax>())\n            };\n            var getTarget = CastExpression(\n                targetType,\n                InvocationExpression(\n                    MemberAccessExpression(\n                        SyntaxKind.SimpleMemberAccessExpression,\n                        holder,\n                        IdentifierName(name)),\n                    ArgumentList(args)));\n\n            var member =\n            MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), \"SetTarget\")\n                .WithParameterList(ParameterList(SingletonSeparatedList(Parameter(holderParameter).WithType(LibraryTypes.ITargetHolder.ToTypeSyntax()))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)));\n\n            var assignmentExpression = AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(targetField.FieldName), getTarget);\n            if (!methodDescription.IsCancellable)\n            {\n                return member.WithExpressionBody(ArrowExpressionClause(assignmentExpression)).WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n            }\n            else\n            {\n                var ctsField = fieldDescriptions.First(f => f is CancellationTokenSourceFieldDescription);\n                var cancellationTokenType = LibraryTypes.CancellationToken.ToTypeSyntax();\n                var ctField = fieldDescriptions.First(f => SymbolEqualityComparer.Default.Equals(LibraryTypes.CancellationToken, f.FieldType));\n                return member.WithBody(Block(\n                    new List<StatementSyntax>()\n                    {\n                        ExpressionStatement(assignmentExpression),\n                        ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(ctsField.FieldName), ImplicitObjectCreationExpression())),\n                        ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName(ctField.FieldName), IdentifierName(ctsField.FieldName).Member(\"Token\")))\n                    }));\n            }\n        }\n\n        private static MethodDeclarationSyntax GenerateGetTargetMethod(TargetFieldDescription targetField)\n        {\n            return MethodDeclaration(PredefinedType(Token(SyntaxKind.ObjectKeyword)), \"GetTarget\")\n                .WithParameterList(ParameterList())\n                .WithExpressionBody(ArrowExpressionClause(IdentifierName(targetField.FieldName)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)));\n        }\n\n        private MemberDeclarationSyntax GenerateGetCancellationTokenMethod(InvokableMethodDescription method, List<InvokerFieldDescription> fields)\n        {\n            if (!method.IsCancellable)\n            {\n                return null;\n            }\n\n            // Method to get the cancellationToken argument\n            // C#: CancellationToken GetCancellationToken() => <fieldName>\n            var cancellationTokenType = LibraryTypes.CancellationToken.ToTypeSyntax();\n            var cancellationTokenField = fields.First(f => SymbolEqualityComparer.Default.Equals(LibraryTypes.CancellationToken, f.FieldType));\n            var member = MethodDeclaration(cancellationTokenType, \"GetCancellationToken\")\n                .WithExpressionBody(ArrowExpressionClause(cancellationTokenField.FieldName.ToIdentifierName()))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n            return member;\n        }\n\n        private MemberDeclarationSyntax GenerateIsCancellableProperty(InvokableMethodDescription method)\n        {\n            if (!method.IsCancellable)\n            {\n                return null;\n            }\n\n            // Property to indicate if the invokable is cancellable\n            // C#: public override bool IsCancellable => true;\n            var member = PropertyDeclaration(PredefinedType(Token(SyntaxKind.BoolKeyword)), \"IsCancellable\")\n                .WithExpressionBody(ArrowExpressionClause(LiteralExpression(SyntaxKind.TrueLiteralExpression)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword));\n            return member;\n        }\n\n        private MemberDeclarationSyntax GenerateTryCancelMethod(InvokableMethodDescription method, List<InvokerFieldDescription> fields)\n        {\n            if (!method.IsCancellable)\n            {\n                return null;\n            }\n\n            // Method to set the CancellationToken argument.\n            // C#:\n            // TryCancel()\n            // {\n            //   if (_cts is { } cts)\n            //   {\n            //     cts.Cancel(false);\n            //     return true;\n            //   }\n            //   return false;\n            // }\n            var cancellationTokenField = fields.First(f => f is CancellationTokenSourceFieldDescription);\n            var member = MethodDeclaration(PredefinedType(Token(SyntaxKind.BoolKeyword)), \"TryCancel\")\n                .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))\n                .WithBody(Block(\n                    IfStatement(\n                        IsPatternExpression(\n                            IdentifierName(cancellationTokenField.FieldName),\n                            RecursivePattern()\n                                .WithPropertyPatternClause(PropertyPatternClause())\n                                .WithDesignation(SingleVariableDesignation(Identifier(\"cts\")))),\n                        Block(\n                            ExpressionStatement(InvocationExpression(\n                                MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(\"cts\"), IdentifierName(\"Cancel\")))\n                                .WithArgumentList(ArgumentList(SeparatedList([Argument(LiteralExpression(SyntaxKind.FalseLiteralExpression))])))),\n                            ReturnStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression)))),\n                    ReturnStatement(LiteralExpression(SyntaxKind.FalseLiteralExpression))));\n            return member;\n        }\n\n        private MemberDeclarationSyntax GenerateGetArgumentMethod(\n            InvokableMethodDescription methodDescription,\n            List<InvokerFieldDescription> fields)\n        {\n            if (methodDescription.Method.Parameters.Length == 0)\n                return null;\n\n            var index = IdentifierName(\"index\");\n\n            var cases = new List<SwitchSectionSyntax>();\n            foreach (var field in fields)\n            {\n                if (field is not MethodParameterFieldDescription parameter)\n                {\n                    continue;\n                }\n\n                // C#: case {index}: return {field}\n                var label = CaseSwitchLabel(\n                    LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(parameter.ParameterOrdinal)));\n                cases.Add(\n                    SwitchSection(\n                        SingletonList<SwitchLabelSyntax>(label),\n                        new SyntaxList<StatementSyntax>(\n                            ReturnStatement(\n                                IdentifierName(parameter.FieldName)))));\n            }\n\n            // C#: default: return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, {maxArgs})\n            var throwHelperMethod = MemberAccessExpression(\n                SyntaxKind.SimpleMemberAccessExpression,\n                IdentifierName(\"OrleansGeneratedCodeHelper\"),\n                IdentifierName(\"InvokableThrowArgumentOutOfRange\"));\n            cases.Add(\n                SwitchSection(\n                    SingletonList<SwitchLabelSyntax>(DefaultSwitchLabel()),\n                    new SyntaxList<StatementSyntax>(\n                        ReturnStatement(\n                            InvocationExpression(\n                                throwHelperMethod,\n                                ArgumentList(\n                                    SeparatedList(\n                                        new[]\n                                        {\n                                            Argument(index),\n                                            Argument(\n                                                LiteralExpression(\n                                                    SyntaxKind.NumericLiteralExpression,\n                                                    Literal(\n                                                        Math.Max(0, methodDescription.Method.Parameters.Length - 1))))\n                                        })))))));\n            var body = SwitchStatement(index, new SyntaxList<SwitchSectionSyntax>(cases));\n            return MethodDeclaration(PredefinedType(Token(SyntaxKind.ObjectKeyword)), \"GetArgument\")\n                .WithParameterList(\n                    ParameterList(\n                        SingletonSeparatedList(\n                            Parameter(Identifier(\"index\")).WithType(PredefinedType(Token(SyntaxKind.IntKeyword))))))\n                .WithBody(Block(body))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)));\n        }\n\n        private MemberDeclarationSyntax GenerateSetArgumentMethod(\n            InvokableMethodDescription methodDescription,\n            List<InvokerFieldDescription> fields)\n        {\n            if (methodDescription.Method.Parameters.Length == 0)\n                return null;\n\n            var index = IdentifierName(\"index\");\n            var value = IdentifierName(\"value\");\n\n            var cases = new List<SwitchSectionSyntax>();\n            foreach (var field in fields)\n            {\n                if (field is not MethodParameterFieldDescription parameter)\n                {\n                    continue;\n                }\n\n                // C#: case {index}: {field} = (TField)value; return;\n                var label = CaseSwitchLabel(\n                    LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(parameter.ParameterOrdinal)));\n                cases.Add(\n                    SwitchSection(\n                        SingletonList<SwitchLabelSyntax>(label),\n                        new SyntaxList<StatementSyntax>(\n                            new StatementSyntax[]\n                            {\n                                ExpressionStatement(\n                                    AssignmentExpression(\n                                        SyntaxKind.SimpleAssignmentExpression,\n                                        IdentifierName(parameter.FieldName),\n                                        CastExpression(parameter.FieldType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions), value))),\n                                ReturnStatement()\n                            })));\n            }\n\n            // C#: default: OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, {maxArgs})\n            var maxArgs = Math.Max(0, methodDescription.Method.Parameters.Length - 1);\n            var throwHelperMethod = MemberAccessExpression(\n                SyntaxKind.SimpleMemberAccessExpression,\n                IdentifierName(\"OrleansGeneratedCodeHelper\"),\n                IdentifierName(\"InvokableThrowArgumentOutOfRange\"));\n            cases.Add(\n                SwitchSection(\n                    SingletonList<SwitchLabelSyntax>(DefaultSwitchLabel()),\n                    new SyntaxList<StatementSyntax>(\n                        new StatementSyntax[]\n                        {\n                            ExpressionStatement(\n                                InvocationExpression(\n                                    throwHelperMethod,\n                                    ArgumentList(\n                                        SeparatedList(\n                                            new[]\n                                            {\n                                                Argument(index),\n                                                Argument(\n                                                    LiteralExpression(\n                                                        SyntaxKind.NumericLiteralExpression,\n                                                        Literal(maxArgs)))\n                                            })))),\n                            ReturnStatement()\n                        })));\n            var body = SwitchStatement(index, new SyntaxList<SwitchSectionSyntax>(cases));\n            return MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), \"SetArgument\")\n                .WithParameterList(\n                    ParameterList(\n                        SeparatedList(\n                            new[]\n                            {\n                                Parameter(Identifier(\"index\")).WithType(PredefinedType(Token(SyntaxKind.IntKeyword))),\n                                Parameter(Identifier(\"value\")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword)))\n                            }\n                        )))\n                .WithBody(Block(body))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)));\n        }\n\n        private MemberDeclarationSyntax GenerateInvokeInnerMethod(\n            InvokableMethodDescription method,\n            List<InvokerFieldDescription> fields,\n            TargetFieldDescription target)\n        {\n            var resultTask = IdentifierName(\"resultTask\");\n\n            // C# var resultTask = this.target.{Method}({params});\n            var args = SeparatedList(\n                fields.OfType<MethodParameterFieldDescription>()\n                    .OrderBy(p => p.ParameterOrdinal)\n                    .Select(p => Argument(IdentifierName(p.FieldName))));\n            ExpressionSyntax methodCall;\n            if (method.MethodTypeParameters.Count > 0)\n            {\n                methodCall = MemberAccessExpression(\n                    SyntaxKind.SimpleMemberAccessExpression,\n                    IdentifierName(target.FieldName),\n                    GenericName(\n                        Identifier(method.Method.Name),\n                        TypeArgumentList(\n                            SeparatedList<TypeSyntax>(\n                                method.MethodTypeParameters.Select(p => IdentifierName(p.Name))))));\n            }\n            else\n            {\n                methodCall = IdentifierName(target.FieldName).Member(method.Method.Name);\n            }\n\n            return MethodDeclaration(method.Method.ReturnType.ToTypeSyntax(method.TypeParameterSubstitutions), \"InvokeInner\")\n                .WithParameterList(ParameterList())\n                .WithExpressionBody(ArrowExpressionClause(InvocationExpression(methodCall, ArgumentList(args))))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))\n                .WithModifiers(TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)));\n        }\n\n        private MemberDeclarationSyntax GenerateDisposeMethod(\n            List<InvokerFieldDescription> fields,\n            INamedTypeSymbol baseClassType)\n        {\n            var body = new List<StatementSyntax>();\n            foreach (var field in fields)\n            {\n                if (field is CancellationTokenSourceFieldDescription ctsField)\n                {\n                    // C#\n                    // _cts?.Dispose();\n                    body.Add(\n                        ExpressionStatement(\n                            ConditionalAccessExpression(\n                                ctsField.FieldName.ToIdentifierName(),\n                                InvocationExpression(\n                                    MemberBindingExpression(IdentifierName(\"Dispose\"))))));\n                }\n\n                if (field.IsInstanceField)\n                {\n                    body.Add(\n                        ExpressionStatement(\n                            AssignmentExpression(\n                                SyntaxKind.SimpleAssignmentExpression,\n                                IdentifierName(field.FieldName),\n                                LiteralExpression(SyntaxKind.DefaultLiteralExpression))));\n                }\n            }\n\n            // C# base.Dispose();\n            if (baseClassType is { }\n                && baseClassType.AllInterfaces.Any(i => i.SpecialType == SpecialType.System_IDisposable)\n                && baseClassType.GetAllMembers<IMethodSymbol>(\"Dispose\").FirstOrDefault(m => !m.IsAbstract && m.DeclaredAccessibility != Accessibility.Private) is { })\n            {\n                body.Add(ExpressionStatement(InvocationExpression(BaseExpression().Member(\"Dispose\")).WithArgumentList(ArgumentList())));\n            }\n\n            return MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), \"Dispose\")\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithBody(Block(body));\n        }\n\n        private MemberDeclarationSyntax GenerateGetArgumentCount(InvokableMethodDescription methodDescription)\n            => methodDescription.Method.Parameters.Length is var count and not 0 ?\n            MethodDeclaration(PredefinedType(Token(SyntaxKind.IntKeyword)), \"GetArgumentCount\")\n                .WithExpressionBody(ArrowExpressionClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(count))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) : null;\n\n        private MemberDeclarationSyntax GenerateGetActivityName(InvokableMethodDescription methodDescription)\n        {\n            // This property is intended to contain a value suitable for use as an OpenTelemetry Span Name for RPC calls.\n            // Therefore, the interface name and method name components must not include periods or slashes.\n            // In order to avoid that, we omit the namespace from the interface name.\n            // See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md\n\n            var interfaceName = methodDescription.Method.ContainingType.ToDisplayName(methodDescription.TypeParameterSubstitutions, includeGlobalSpecifier: false, includeNamespace: false);\n            var methodName = methodDescription.Method.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);\n            var activityName = $\"{interfaceName}/{methodName}\";\n            return MethodDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)), \"GetActivityName\")\n                .WithExpressionBody(\n                    ArrowExpressionClause(\n                        LiteralExpression(\n                            SyntaxKind.NumericLiteralExpression,\n                            Literal(activityName))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n        }\n\n        private MemberDeclarationSyntax GenerateGetMethodName(\n            InvokableMethodDescription methodDescription) =>\n            MethodDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)), \"GetMethodName\")\n                .WithExpressionBody(\n                    ArrowExpressionClause(\n                        LiteralExpression(\n                            SyntaxKind.NumericLiteralExpression,\n                            Literal(methodDescription.Method.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n\n        private MemberDeclarationSyntax GenerateGetInterfaceName(\n            InvokableMethodDescription methodDescription) =>\n            MethodDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)), \"GetInterfaceName\")\n                .WithExpressionBody(\n                    ArrowExpressionClause(\n                        LiteralExpression(\n                            SyntaxKind.NumericLiteralExpression,\n                            Literal(methodDescription.Method.ContainingType.ToDisplayName(methodDescription.TypeParameterSubstitutions, includeGlobalSpecifier: false)))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n\n        private MemberDeclarationSyntax GenerateGetInterfaceType(\n            InvokableMethodDescription methodDescription) =>\n            MethodDeclaration(LibraryTypes.Type.ToTypeSyntax(), \"GetInterfaceType\")\n                .WithExpressionBody(\n                    ArrowExpressionClause(\n                        TypeOfExpression(methodDescription.Method.ContainingType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions))))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n\n        private MemberDeclarationSyntax GenerateGetMethod()\n            => MethodDeclaration(LibraryTypes.MethodInfo.ToTypeSyntax(), \"GetMethod\")\n                .WithExpressionBody(ArrowExpressionClause(IdentifierName(\"MethodBackingField\")))\n                .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))\n                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n\n        public static string GetSimpleClassName(InvokableMethodDescription method)\n        {\n            var genericArity = method.AllTypeParameters.Count;\n            var typeArgs = genericArity > 0 ? \"_\" + genericArity : string.Empty;\n            var proxyKey = method.ProxyBase.Key.GeneratedClassNameComponent;\n            return $\"Invokable_{method.ContainingInterface.Name}_{proxyKey}_{method.GeneratedMethodId}{typeArgs}\";\n        }\n\n        private MemberDeclarationSyntax[] GetFieldDeclarations(\n            InvokableMethodDescription method,\n            List<InvokerFieldDescription> fieldDescriptions)\n        {\n            return fieldDescriptions.Select(GetFieldDeclaration).ToArray();\n\n            MemberDeclarationSyntax GetFieldDeclaration(InvokerFieldDescription description)\n            {\n                FieldDeclarationSyntax field;\n                if (description is MethodInfoFieldDescription methodInfo)\n                {\n                    var methodTypeArguments = GetTypesArray(method, method.MethodTypeParameters.Select(p => p.Parameter));\n                    var parameterTypes = GetTypesArray(method, method.Method.Parameters.Select(p => p.Type));\n\n                    field = FieldDeclaration(\n                        VariableDeclaration(\n                            LibraryTypes.MethodInfo.ToTypeSyntax(),\n                            SingletonSeparatedList(VariableDeclarator(description.FieldName)\n                            .WithInitializer(EqualsValueClause(\n                                InvocationExpression(\n                                    IdentifierName(\"OrleansGeneratedCodeHelper\").Member(\"GetMethodInfoOrDefault\"),\n                                    ArgumentList(SeparatedList(new[]\n                                    {\n                                        Argument(TypeOfExpression(method.Method.ContainingType.ToTypeSyntax(method.TypeParameterSubstitutions))),\n                                        Argument(method.Method.Name.GetLiteralExpression()),\n                                        Argument(methodTypeArguments),\n                                        Argument(parameterTypes),\n                                    }))))))))\n                        .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                }\n                else\n                {\n                    field = FieldDeclaration(\n                        VariableDeclaration(\n                            description.FieldType.ToTypeSyntax(method.TypeParameterSubstitutions),\n                            SingletonSeparatedList(VariableDeclarator(description.FieldName))));\n                }\n\n                switch (description)\n                {\n                    case MethodParameterFieldDescription _:\n                        field = field.AddModifiers(Token(SyntaxKind.PublicKeyword));\n                        break;\n                }\n\n                return field;\n            }\n        }\n\n        private ExpressionSyntax GetTypesArray(InvokableMethodDescription method, IEnumerable<ITypeSymbol> typeSymbols)\n        {\n            var types = typeSymbols.ToArray();\n            return types.Length == 0 ? LiteralExpression(SyntaxKind.NullLiteralExpression)\n                : ImplicitArrayCreationExpression(InitializerExpression(SyntaxKind.ArrayInitializerExpression, SeparatedList<ExpressionSyntax>(\n                    types.Select(t => TypeOfExpression(t.ToTypeSyntax(method.TypeParameterSubstitutions))))));\n        }\n\n        private (ConstructorDeclarationSyntax Constructor, List<TypeSyntax> ConstructorArguments) GenerateConstructor(\n            string simpleClassName,\n            InvokableMethodDescription method,\n            INamedTypeSymbol baseClassType)\n        {\n            var parameters = new List<ParameterSyntax>();\n\n            var body = new List<StatementSyntax>();\n\n            List<TypeSyntax> constructorArgumentTypes = new();\n            List<ArgumentSyntax> baseConstructorArguments = new();\n            foreach (var constructor in baseClassType.GetAllMembers<IMethodSymbol>())\n            {\n                if (constructor.MethodKind != MethodKind.Constructor || constructor.DeclaredAccessibility == Accessibility.Private || constructor.IsImplicitlyDeclared)\n                {\n                    continue;\n                }\n\n                if (constructor.HasAttribute(LibraryTypes.GeneratedActivatorConstructorAttribute))\n                {\n                    var index = 0;\n                    foreach (var parameter in constructor.Parameters)\n                    {\n                        var identifier = $\"base{index}\";\n\n                        var argumentType = parameter.Type.ToTypeSyntax(method.TypeParameterSubstitutions);\n                        constructorArgumentTypes.Add(argumentType);\n                        parameters.Add(Parameter(identifier.ToIdentifier()).WithType(argumentType));\n                        baseConstructorArguments.Add(Argument(identifier.ToIdentifierName()));\n                        index++;\n                    }\n                    break;\n                }\n            }\n\n            foreach (var (methodName, methodArgument) in method.CustomInitializerMethods)\n            {\n                var argumentExpression = methodArgument.ToExpression();\n                body.Add(ExpressionStatement(InvocationExpression(IdentifierName(methodName), ArgumentList(SeparatedList(new[] { Argument(argumentExpression) })))));\n            }\n\n            if (body.Count == 0 && parameters.Count == 0)\n                return default;\n\n            var constructorDeclaration = ConstructorDeclaration(simpleClassName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters.ToArray())\n                .WithInitializer(\n                    ConstructorInitializer(\n                        SyntaxKind.BaseConstructorInitializer,\n                        ArgumentList(SeparatedList(baseConstructorArguments))))\n                .AddBodyStatements(body.ToArray());\n\n            return (constructorDeclaration, constructorArgumentTypes);\n        }\n\n        private List<InvokerFieldDescription> GetFieldDescriptions(InvokableMethodDescription method)\n        {\n            var fields = new List<InvokerFieldDescription>();\n            uint fieldId = 0;\n\n            foreach (var parameter in method.Method.Parameters)\n            {\n                var isSerializable = !SymbolEqualityComparer.Default.Equals(LibraryTypes.CancellationToken, parameter.Type);\n                fields.Add(new MethodParameterFieldDescription(method.CodeGenerator, parameter, $\"arg{fieldId}\", fieldId, method.TypeParameterSubstitutions, isSerializable));\n                fieldId++;\n            }\n\n            fields.Add(new TargetFieldDescription(method.Method.ContainingType));\n            fields.Add(new MethodInfoFieldDescription(LibraryTypes.MethodInfo, \"MethodBackingField\"));\n\n            if (method.IsCancellable)\n            {\n                fields.Add(new CancellationTokenSourceFieldDescription(LibraryTypes));\n            }\n\n            return fields;\n        }\n\n        internal abstract class InvokerFieldDescription\n        {\n            protected InvokerFieldDescription(ITypeSymbol fieldType, string fieldName)\n            {\n                FieldType = fieldType;\n                FieldName = fieldName;\n            }\n\n            public ITypeSymbol FieldType { get; }\n            public string FieldName { get; }\n            public abstract bool IsSerializable { get; }\n            public abstract bool IsInstanceField { get; }\n        }\n\n        internal sealed class TargetFieldDescription : InvokerFieldDescription\n        {\n            public TargetFieldDescription(ITypeSymbol fieldType) : base(fieldType, \"_target\") { }\n\n            public override bool IsSerializable => false;\n            public override bool IsInstanceField => true;\n        }\n\n        internal sealed class CancellationTokenSourceFieldDescription(LibraryTypes libraryTypes) : InvokerFieldDescription(libraryTypes.CancellationTokenSource, \"_cts\")\n        {\n            public override bool IsSerializable => false;\n            public override bool IsInstanceField => true;\n        }\n\n        internal sealed class CancellationTokenFieldDescription(LibraryTypes libraryTypes) : InvokerFieldDescription(libraryTypes.CancellationToken, \"_ct\")\n        {\n            public override bool IsSerializable => false;\n            public override bool IsInstanceField => true;\n        }\n\n        internal class MethodParameterFieldDescription : InvokerFieldDescription, IMemberDescription\n        {\n            public MethodParameterFieldDescription(\n                CodeGenerator codeGenerator,\n                IParameterSymbol parameter,\n                string fieldName,\n                uint fieldId,\n                Dictionary<ITypeParameterSymbol, string> typeParameterSubstitutions,\n                bool isSerializable)\n                : base(parameter.Type, fieldName)\n            {\n                TypeParameterSubstitutions = typeParameterSubstitutions;\n                FieldId = fieldId;\n                CodeGenerator = codeGenerator;\n                Parameter = parameter;\n                if (parameter.Type.TypeKind == TypeKind.Dynamic)\n                {\n                    TypeSyntax = PredefinedType(Token(SyntaxKind.ObjectKeyword));\n                    TypeName = \"dynamic\";\n                }\n                else\n                {\n                    TypeName = Type.ToDisplayName(TypeParameterSubstitutions);\n                    TypeSyntax = Type.ToTypeSyntax(TypeParameterSubstitutions);\n                }\n\n                Symbol = parameter;\n                IsSerializable = isSerializable;\n            }\n\n            public CodeGenerator CodeGenerator { get; }\n            public ISymbol Symbol { get; }\n            public Dictionary<ITypeParameterSymbol, string> TypeParameterSubstitutions { get; }\n            public int ParameterOrdinal => Parameter.Ordinal;\n            public uint FieldId { get; }\n            public ISymbol Member => Parameter;\n            public ITypeSymbol Type => FieldType;\n            public INamedTypeSymbol ContainingType => Parameter.ContainingType;\n            public TypeSyntax TypeSyntax { get; }\n            public IParameterSymbol Parameter { get; }\n            public override bool IsSerializable { get; }\n            public bool IsCopyable => true;\n            public override bool IsInstanceField => true;\n\n            public string AssemblyName => Parameter.Type.ContainingAssembly.ToDisplayName();\n            public string TypeName { get; }\n\n            public string TypeNameIdentifier\n            {\n                get\n                {\n                    if (Type is ITypeParameterSymbol tp && TypeParameterSubstitutions.TryGetValue(tp, out var name))\n                    {\n                        return name;\n                    }\n\n                    return Type.GetValidIdentifier();\n                }\n            }\n\n            public bool IsPrimaryConstructorParameter => false;\n\n            public TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol) => typeSymbol.ToTypeSyntax(TypeParameterSubstitutions);\n        }\n\n        internal sealed class MethodInfoFieldDescription : InvokerFieldDescription\n        {\n            public MethodInfoFieldDescription(ITypeSymbol fieldType, string fieldName) : base(fieldType, fieldName) { }\n\n            public override bool IsSerializable => false;\n            public override bool IsInstanceField => false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/LibraryTypes.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Orleans.CodeGenerator.SyntaxGeneration;\n\nnamespace Orleans.CodeGenerator\n{\n    internal sealed class LibraryTypes\n    {\n        private readonly ConcurrentDictionary<ITypeSymbol, bool> _shallowCopyableTypes = new(SymbolEqualityComparer.Default);\n\n        public static LibraryTypes FromCompilation(Compilation compilation, CodeGeneratorOptions options) => new LibraryTypes(compilation, options);\n\n        private LibraryTypes(Compilation compilation, CodeGeneratorOptions options)\n        {\n            Compilation = compilation;\n            ApplicationPartAttribute = Type(\"Orleans.ApplicationPartAttribute\");\n            Action_2 = Type(\"System.Action`2\");\n            TypeManifestProviderBase = Type(\"Orleans.Serialization.Configuration.TypeManifestProviderBase\");\n            Field = Type(\"Orleans.Serialization.WireProtocol.Field\");\n            FieldCodec_1 = Type(\"Orleans.Serialization.Codecs.IFieldCodec`1\");\n            AbstractTypeSerializer = Type(\"Orleans.Serialization.Serializers.AbstractTypeSerializer`1\");\n            DeepCopier_1 = Type(\"Orleans.Serialization.Cloning.IDeepCopier`1\");\n            ShallowCopier = Type(\"Orleans.Serialization.Cloning.ShallowCopier`1\");\n            CompoundTypeAliasAttribute = Type(\"Orleans.CompoundTypeAliasAttribute\");\n            CopyContext = Type(\"Orleans.Serialization.Cloning.CopyContext\");\n            MethodInfo = Type(\"System.Reflection.MethodInfo\");\n            Func_2 = Type(\"System.Func`2\");\n            GenerateMethodSerializersAttribute = Type(\"Orleans.GenerateMethodSerializersAttribute\");\n            GenerateSerializerAttribute = Type(\"Orleans.GenerateSerializerAttribute\");\n            SerializationCallbacksAttribute = Type(\"Orleans.SerializationCallbacksAttribute\");\n            IActivator_1 = Type(\"Orleans.Serialization.Activators.IActivator`1\");\n            IBufferWriter = Type(\"System.Buffers.IBufferWriter`1\");\n            IdAttributeType = Type(CodeGeneratorOptions.IdAttribute);\n            ConstructorAttributeTypes = CodeGeneratorOptions.ConstructorAttributes.Select(Type).ToArray();\n            AliasAttribute = Type(\"Orleans.AliasAttribute\");\n            IInvokable = Type(\"Orleans.Serialization.Invocation.IInvokable\");\n            InvokeMethodNameAttribute = Type(\"Orleans.InvokeMethodNameAttribute\");\n            RuntimeHelpers = Type(\"System.Runtime.CompilerServices.RuntimeHelpers\");\n            InvokableCustomInitializerAttribute = Type(\"Orleans.InvokableCustomInitializerAttribute\");\n            DefaultInvokableBaseTypeAttribute = Type(\"Orleans.DefaultInvokableBaseTypeAttribute\");\n            GenerateCodeForDeclaringAssemblyAttribute = Type(\"Orleans.GenerateCodeForDeclaringAssemblyAttribute\");\n            InvokableBaseTypeAttribute = Type(\"Orleans.InvokableBaseTypeAttribute\");\n            ReturnValueProxyAttribute = Type(\"Orleans.Invocation.ReturnValueProxyAttribute\");\n            RegisterSerializerAttribute = Type(\"Orleans.RegisterSerializerAttribute\");\n            ResponseTimeoutAttribute = Type(\"Orleans.ResponseTimeoutAttribute\");\n            GeneratedActivatorConstructorAttribute = Type(\"Orleans.GeneratedActivatorConstructorAttribute\");\n            SerializerTransparentAttribute = Type(\"Orleans.SerializerTransparentAttribute\");\n            RegisterActivatorAttribute = Type(\"Orleans.RegisterActivatorAttribute\");\n            RegisterConverterAttribute = Type(\"Orleans.RegisterConverterAttribute\");\n            RegisterCopierAttribute = Type(\"Orleans.RegisterCopierAttribute\");\n            UseActivatorAttribute = Type(\"Orleans.UseActivatorAttribute\");\n            SuppressReferenceTrackingAttribute = Type(\"Orleans.SuppressReferenceTrackingAttribute\");\n            OmitDefaultMemberValuesAttribute = Type(\"Orleans.OmitDefaultMemberValuesAttribute\");\n            ITargetHolder = Type(\"Orleans.Serialization.Invocation.ITargetHolder\");\n            TypeManifestProviderAttribute = Type(\"Orleans.Serialization.Configuration.TypeManifestProviderAttribute\");\n            NonSerializedAttribute = Type(\"System.NonSerializedAttribute\");\n            ObsoleteAttribute = Type(\"System.ObsoleteAttribute\");\n            BaseCodec_1 = Type(\"Orleans.Serialization.Serializers.IBaseCodec`1\");\n            BaseCopier_1 = Type(\"Orleans.Serialization.Cloning.IBaseCopier`1\");\n            ArrayCodec = Type(\"Orleans.Serialization.Codecs.ArrayCodec`1\");\n            ArrayCopier = Type(\"Orleans.Serialization.Codecs.ArrayCopier`1\");\n            Reader = Type(\"Orleans.Serialization.Buffers.Reader`1\");\n            TypeManifestOptions = Type(\"Orleans.Serialization.Configuration.TypeManifestOptions\");\n            Task = Type(\"System.Threading.Tasks.Task\");\n            Task_1 = Type(\"System.Threading.Tasks.Task`1\");\n            this.Type = Type(\"System.Type\");\n            _uri = Type(\"System.Uri\");\n            _int128 = TypeOrDefault(\"System.Int128\");\n            _uInt128 = TypeOrDefault(\"System.UInt128\");\n            _half = TypeOrDefault(\"System.Half\");\n            _dateOnly = TypeOrDefault(\"System.DateOnly\");\n            _dateTimeOffset = Type(\"System.DateTimeOffset\");\n            _bitVector32 = Type(\"System.Collections.Specialized.BitVector32\");\n            _compareInfo = Type(\"System.Globalization.CompareInfo\");\n            _cultureInfo = Type(\"System.Globalization.CultureInfo\");\n            _version = Type(\"System.Version\");\n            _timeOnly = TypeOrDefault(\"System.TimeOnly\");\n            Guid = Type(\"System.Guid\");\n            ICodecProvider = Type(\"Orleans.Serialization.Serializers.ICodecProvider\");\n            ValueSerializer = Type(\"Orleans.Serialization.Serializers.IValueSerializer`1\");\n            ValueTask = Type(\"System.Threading.Tasks.ValueTask\");\n            ValueTask_1 = Type(\"System.Threading.Tasks.ValueTask`1\");\n            ValueTypeGetter_2 = Type(\"Orleans.Serialization.Utilities.ValueTypeGetter`2\");\n            ValueTypeSetter_2 = Type(\"Orleans.Serialization.Utilities.ValueTypeSetter`2\");\n            Writer = Type(\"Orleans.Serialization.Buffers.Writer`1\");\n            FSharpSourceConstructFlagsOrDefault = TypeOrDefault(\"Microsoft.FSharp.Core.SourceConstructFlags\");\n            FSharpCompilationMappingAttributeOrDefault = TypeOrDefault(\"Microsoft.FSharp.Core.CompilationMappingAttribute\");\n            StaticCodecs = new List<WellKnownCodecDescription>\n                {\n                    new(compilation.GetSpecialType(SpecialType.System_Object), Type(\"Orleans.Serialization.Codecs.ObjectCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Boolean), Type(\"Orleans.Serialization.Codecs.BoolCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Char), Type(\"Orleans.Serialization.Codecs.CharCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Byte), Type(\"Orleans.Serialization.Codecs.ByteCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_SByte), Type(\"Orleans.Serialization.Codecs.SByteCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Int16), Type(\"Orleans.Serialization.Codecs.Int16Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Int32), Type(\"Orleans.Serialization.Codecs.Int32Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Int64), Type(\"Orleans.Serialization.Codecs.Int64Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_UInt16), Type(\"Orleans.Serialization.Codecs.UInt16Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_UInt32), Type(\"Orleans.Serialization.Codecs.UInt32Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_UInt64), Type(\"Orleans.Serialization.Codecs.UInt64Codec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_String), Type(\"Orleans.Serialization.Codecs.StringCodec\")),\n                    new(compilation.CreateArrayTypeSymbol(compilation.GetSpecialType(SpecialType.System_Byte), 1), Type(\"Orleans.Serialization.Codecs.ByteArrayCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Single), Type(\"Orleans.Serialization.Codecs.FloatCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Double), Type(\"Orleans.Serialization.Codecs.DoubleCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Decimal), Type(\"Orleans.Serialization.Codecs.DecimalCodec\")),\n                    new(compilation.GetSpecialType(SpecialType.System_DateTime), Type(\"Orleans.Serialization.Codecs.DateTimeCodec\")),\n                    new(Type(\"System.TimeSpan\"), Type(\"Orleans.Serialization.Codecs.TimeSpanCodec\")),\n                    new(Type(\"System.DateTimeOffset\"), Type(\"Orleans.Serialization.Codecs.DateTimeOffsetCodec\")),\n                    new(TypeOrDefault(\"System.DateOnly\"), TypeOrDefault(\"Orleans.Serialization.Codecs.DateOnlyCodec\")),\n                    new(TypeOrDefault(\"System.TimeOnly\"), TypeOrDefault(\"Orleans.Serialization.Codecs.TimeOnlyCodec\")),\n                    new(Type(\"System.Guid\"), Type(\"Orleans.Serialization.Codecs.GuidCodec\")),\n                    new(Type(\"System.Type\"), Type(\"Orleans.Serialization.Codecs.TypeSerializerCodec\")),\n                    new(Type(\"System.ReadOnlyMemory`1\").Construct(compilation.GetSpecialType(SpecialType.System_Byte)), Type(\"Orleans.Serialization.Codecs.ReadOnlyMemoryOfByteCodec\")),\n                    new(Type(\"System.Memory`1\").Construct(compilation.GetSpecialType(SpecialType.System_Byte)), Type(\"Orleans.Serialization.Codecs.MemoryOfByteCodec\")),\n                    new(Type(\"System.Net.IPAddress\"), Type(\"Orleans.Serialization.Codecs.IPAddressCodec\")),\n                    new(Type(\"System.Net.IPEndPoint\"), Type(\"Orleans.Serialization.Codecs.IPEndPointCodec\")),\n                    new(TypeOrDefault(\"System.UInt128\"), TypeOrDefault(\"Orleans.Serialization.Codecs.UInt128Codec\")),\n                    new(TypeOrDefault(\"System.Int128\"), TypeOrDefault(\"Orleans.Serialization.Codecs.Int128Codec\")),\n                    new(TypeOrDefault(\"System.Half\"), TypeOrDefault(\"Orleans.Serialization.Codecs.HalfCodec\")),\n                    new(Type(\"System.Uri\"), Type(\"Orleans.Serialization.Codecs.UriCodec\")),\n                }.Where(desc => desc.UnderlyingType is { } && desc.CodecType is { }).ToArray();\n            WellKnownCodecs = new WellKnownCodecDescription[]\n            {\n                    new(Type(\"System.Exception\"), Type(\"Orleans.Serialization.ExceptionCodec\")),\n                    new(Type(\"System.Collections.Generic.Dictionary`2\"), Type(\"Orleans.Serialization.Codecs.DictionaryCodec`2\")),\n                    new(Type(\"System.Collections.Generic.List`1\"), Type(\"Orleans.Serialization.Codecs.ListCodec`1\")),\n                    new(Type(\"System.Collections.Generic.HashSet`1\"), Type(\"Orleans.Serialization.Codecs.HashSetCodec`1\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Nullable_T), Type(\"Orleans.Serialization.Codecs.NullableCodec`1\")),\n            };\n            StaticCopiers = new WellKnownCopierDescription[]\n            {\n                    new(compilation.GetSpecialType(SpecialType.System_Object), Type(\"Orleans.Serialization.Codecs.ObjectCopier\")),\n                    new(compilation.CreateArrayTypeSymbol(compilation.GetSpecialType(SpecialType.System_Byte), 1), Type(\"Orleans.Serialization.Codecs.ByteArrayCopier\")),\n                    new(Type(\"System.ReadOnlyMemory`1\").Construct(compilation.GetSpecialType(SpecialType.System_Byte)), Type(\"Orleans.Serialization.Codecs.ReadOnlyMemoryOfByteCopier\")),\n                    new(Type(\"System.Memory`1\").Construct(compilation.GetSpecialType(SpecialType.System_Byte)), Type(\"Orleans.Serialization.Codecs.MemoryOfByteCopier\")),\n            };\n            WellKnownCopiers = new WellKnownCopierDescription[]\n            {\n                    new(Type(\"System.Exception\"), Type(\"Orleans.Serialization.ExceptionCodec\")),\n                    new(Type(\"System.Collections.Generic.Dictionary`2\"), Type(\"Orleans.Serialization.Codecs.DictionaryCopier`2\")),\n                    new(Type(\"System.Collections.Generic.List`1\"), Type(\"Orleans.Serialization.Codecs.ListCopier`1\")),\n                    new(Type(\"System.Collections.Generic.HashSet`1\"), Type(\"Orleans.Serialization.Codecs.HashSetCopier`1\")),\n                    new(compilation.GetSpecialType(SpecialType.System_Nullable_T), Type(\"Orleans.Serialization.Codecs.NullableCopier`1\")),\n            };\n            Exception = Type(\"System.Exception\");\n            ImmutableAttribute = Type(CodeGeneratorOptions.ImmutableAttribute);\n            TimeSpan = Type(\"System.TimeSpan\");\n            _ipAddress = Type(\"System.Net.IPAddress\");\n            _ipEndPoint = Type(\"System.Net.IPEndPoint\");\n            CancellationToken = Type(\"System.Threading.CancellationToken\");\n            CancellationTokenSource = Type(\"System.Threading.CancellationTokenSource\");\n            _immutableContainerTypes = new[]\n            {\n                    compilation.GetSpecialType(SpecialType.System_Nullable_T),\n                    Type(\"System.Tuple`1\"),\n                    Type(\"System.Tuple`2\"),\n                    Type(\"System.Tuple`3\"),\n                    Type(\"System.Tuple`4\"),\n                    Type(\"System.Tuple`5\"),\n                    Type(\"System.Tuple`6\"),\n                    Type(\"System.Tuple`7\"),\n                    Type(\"System.Tuple`8\"),\n                    Type(\"System.ValueTuple`1\"),\n                    Type(\"System.ValueTuple`2\"),\n                    Type(\"System.ValueTuple`3\"),\n                    Type(\"System.ValueTuple`4\"),\n                    Type(\"System.ValueTuple`5\"),\n                    Type(\"System.ValueTuple`6\"),\n                    Type(\"System.ValueTuple`7\"),\n                    Type(\"System.ValueTuple`8\"),\n                    Type(\"System.Collections.Immutable.ImmutableArray`1\"),\n                    Type(\"System.Collections.Immutable.ImmutableDictionary`2\"),\n                    Type(\"System.Collections.Immutable.ImmutableHashSet`1\"),\n                    Type(\"System.Collections.Immutable.ImmutableList`1\"),\n                    Type(\"System.Collections.Immutable.ImmutableQueue`1\"),\n                    Type(\"System.Collections.Immutable.ImmutableSortedDictionary`2\"),\n                    Type(\"System.Collections.Immutable.ImmutableSortedSet`1\"),\n                    Type(\"System.Collections.Immutable.ImmutableStack`1\"),\n                };\n\n            LanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;\n\n            INamedTypeSymbol Type(string metadataName)\n            {\n                var result = compilation.GetTypeByMetadataName(metadataName);\n                if (result is null)\n                {\n                    throw new InvalidOperationException(\"Cannot find type with metadata name \" + metadataName);\n                }\n\n                return result;\n            }\n\n            INamedTypeSymbol? TypeOrDefault(string metadataName)\n            {\n                var result = compilation.GetTypeByMetadataName(metadataName);\n                return result;\n            }\n        }\n\n        public INamedTypeSymbol Action_2 { get; private set; }\n        public INamedTypeSymbol TypeManifestProviderBase { get; private set; }\n        public INamedTypeSymbol Field { get; private set; }\n        public INamedTypeSymbol DeepCopier_1 { get; private set; }\n        public INamedTypeSymbol ShallowCopier { get; private set; }\n        public INamedTypeSymbol FieldCodec_1 { get; private set; }\n        public INamedTypeSymbol AbstractTypeSerializer { get; private set; }\n        public INamedTypeSymbol Func_2 { get; private set; }\n        public INamedTypeSymbol CompoundTypeAliasAttribute { get; private set; }\n        public INamedTypeSymbol GenerateMethodSerializersAttribute { get; private set; }\n        public INamedTypeSymbol GenerateSerializerAttribute { get; private set; }\n        public INamedTypeSymbol IActivator_1 { get; private set; }\n        public INamedTypeSymbol IBufferWriter { get; private set; }\n        public INamedTypeSymbol IInvokable { get; private set; }\n        public INamedTypeSymbol ITargetHolder { get; private set; }\n        public INamedTypeSymbol TypeManifestProviderAttribute { get; private set; }\n        public INamedTypeSymbol NonSerializedAttribute { get; private set; }\n        public INamedTypeSymbol ObsoleteAttribute { get; private set; }\n        public INamedTypeSymbol BaseCodec_1 { get; private set; }\n        public INamedTypeSymbol BaseCopier_1 { get; private set; }\n        public INamedTypeSymbol ArrayCodec { get; private set; }\n        public INamedTypeSymbol ArrayCopier { get; private set; }\n        public INamedTypeSymbol Reader { get; private set; }\n        public INamedTypeSymbol TypeManifestOptions { get; private set; }\n        public INamedTypeSymbol Task { get; private set; }\n        public INamedTypeSymbol Task_1 { get; private set; }\n        public INamedTypeSymbol Type { get; private set; }\n        private INamedTypeSymbol _uri;\n        private INamedTypeSymbol? _dateOnly;\n        private INamedTypeSymbol _dateTimeOffset;\n        private INamedTypeSymbol? _timeOnly;\n        public INamedTypeSymbol MethodInfo { get; private set; }\n        public INamedTypeSymbol ICodecProvider { get; private set; }\n        public INamedTypeSymbol ValueSerializer { get; private set; }\n        public INamedTypeSymbol ValueTask { get; private set; }\n        public INamedTypeSymbol ValueTask_1 { get; private set; }\n        public INamedTypeSymbol ValueTypeGetter_2 { get; private set; }\n        public INamedTypeSymbol ValueTypeSetter_2 { get; private set; }\n        public INamedTypeSymbol Writer { get; private set; }\n        public INamedTypeSymbol IdAttributeType { get; private set; }\n        public INamedTypeSymbol[] ConstructorAttributeTypes { get; private set; }\n        public INamedTypeSymbol AliasAttribute { get; private set; }\n        public WellKnownCodecDescription[] StaticCodecs { get; private set; }\n        public WellKnownCodecDescription[] WellKnownCodecs { get; private set; }\n        public WellKnownCopierDescription[] StaticCopiers { get; private set; }\n        public WellKnownCopierDescription[] WellKnownCopiers { get; private set; }\n        public INamedTypeSymbol RegisterCopierAttribute { get; private set; }\n        public INamedTypeSymbol RegisterSerializerAttribute { get; private set; }\n        public INamedTypeSymbol ResponseTimeoutAttribute { get; private set; }\n        public INamedTypeSymbol RegisterConverterAttribute { get; private set; }\n        public INamedTypeSymbol RegisterActivatorAttribute { get; private set; }\n        public INamedTypeSymbol UseActivatorAttribute { get; private set; }\n        public INamedTypeSymbol SuppressReferenceTrackingAttribute { get; private set; }\n        public INamedTypeSymbol OmitDefaultMemberValuesAttribute { get; private set; }\n        public INamedTypeSymbol CopyContext { get; private set; }\n        public INamedTypeSymbol CancellationToken { get; private set; }\n        public INamedTypeSymbol CancellationTokenSource { get; }\n        public INamedTypeSymbol Guid { get; private set; }\n        public Compilation Compilation { get; private set; }\n        public INamedTypeSymbol TimeSpan { get; private set; }\n        private INamedTypeSymbol _ipAddress;\n        private INamedTypeSymbol _ipEndPoint;\n        private INamedTypeSymbol[] _immutableContainerTypes;\n        private INamedTypeSymbol _bitVector32;\n        private INamedTypeSymbol _compareInfo;\n        private INamedTypeSymbol _cultureInfo;\n        private INamedTypeSymbol _version;\n        private INamedTypeSymbol? _int128;\n        private INamedTypeSymbol? _uInt128;\n        private INamedTypeSymbol? _half;\n        private INamedTypeSymbol[]? _regularShallowCopyableTypes;\n        private INamedTypeSymbol[] RegularShallowCopyableType => _regularShallowCopyableTypes ??= new List<INamedTypeSymbol?>\n        {\n            TimeSpan,\n            _dateOnly,\n            _timeOnly,\n            _dateTimeOffset,\n            Guid,\n            _bitVector32,\n            _compareInfo,\n            _cultureInfo,\n            _version,\n            _ipAddress,\n            _ipEndPoint,\n            CancellationToken,\n            Type,\n            _uri,\n            _uInt128,\n            _int128,\n            _half\n        }.Where(t => t is {}).ToArray()!;\n\n        public INamedTypeSymbol ImmutableAttribute { get; private set; }\n        public INamedTypeSymbol Exception { get; private set; }\n        public INamedTypeSymbol ApplicationPartAttribute { get; private set; }\n        public INamedTypeSymbol InvokeMethodNameAttribute { get; private set; }\n        public INamedTypeSymbol InvokableCustomInitializerAttribute { get; private set; }\n        public INamedTypeSymbol InvokableBaseTypeAttribute { get; private set; }\n        public INamedTypeSymbol ReturnValueProxyAttribute { get; private set; }\n        public INamedTypeSymbol DefaultInvokableBaseTypeAttribute { get; private set; }\n        public INamedTypeSymbol GenerateCodeForDeclaringAssemblyAttribute { get; private set; }\n        public INamedTypeSymbol SerializationCallbacksAttribute { get; private set; }\n        public INamedTypeSymbol GeneratedActivatorConstructorAttribute { get; private set; }\n        public INamedTypeSymbol SerializerTransparentAttribute { get; private set; }\n        public INamedTypeSymbol? FSharpCompilationMappingAttributeOrDefault { get; private set; }\n        public INamedTypeSymbol? FSharpSourceConstructFlagsOrDefault { get; private set; }\n        public INamedTypeSymbol RuntimeHelpers { get; private set; }\n\n        public LanguageVersion? LanguageVersion { get; private set; }\n\n        public bool IsShallowCopyable(ITypeSymbol type)\n        {\n            switch (type.SpecialType)\n            {\n                case SpecialType.System_Boolean:\n                case SpecialType.System_Char:\n                case SpecialType.System_SByte:\n                case SpecialType.System_Byte:\n                case SpecialType.System_Int16:\n                case SpecialType.System_UInt16:\n                case SpecialType.System_Int32:\n                case SpecialType.System_UInt32:\n                case SpecialType.System_Int64:\n                case SpecialType.System_UInt64:\n                case SpecialType.System_Decimal:\n                case SpecialType.System_Single:\n                case SpecialType.System_Double:\n                case SpecialType.System_String:\n                case SpecialType.System_DateTime:\n                    return true;\n            }\n\n            if (_shallowCopyableTypes.TryGetValue(type, out var result))\n            {\n                return result;\n            }\n\n            foreach (var shallowCopyable in RegularShallowCopyableType)\n            {\n                if (SymbolEqualityComparer.Default.Equals(shallowCopyable, type))\n                {\n                    return _shallowCopyableTypes[type] = true;\n                }\n            }\n\n            if (type.IsSealed && type.HasAttribute(ImmutableAttribute))\n            {\n                return _shallowCopyableTypes[type] = true;\n            }\n\n            if (type.HasBaseType(Exception))\n            {\n                return _shallowCopyableTypes[type] = true;\n            }\n\n            if (!(type is INamedTypeSymbol namedType))\n            {\n                return _shallowCopyableTypes[type] = false;\n            }\n\n            if (namedType.IsTupleType)\n            {\n                return _shallowCopyableTypes[type] = AreShallowCopyable(namedType.TupleElements);\n            }\n            else if (namedType.IsGenericType)\n            {\n                var def = namedType.ConstructedFrom;\n                foreach (var t in _immutableContainerTypes)\n                {\n                    if (SymbolEqualityComparer.Default.Equals(t, def))\n                        return _shallowCopyableTypes[type] = AreShallowCopyable(namedType.TypeArguments);\n                }\n            }\n            else\n            {\n                if (type.TypeKind == TypeKind.Enum)\n                {\n                    return _shallowCopyableTypes[type] = true;\n                }\n\n                if (type.TypeKind == TypeKind.Struct && !namedType.IsUnboundGenericType)\n                {\n                    return _shallowCopyableTypes[type] = IsValueTypeFieldsShallowCopyable(type);\n                }\n            }\n\n            return _shallowCopyableTypes[type] = false;\n        }\n\n        private bool IsValueTypeFieldsShallowCopyable(ITypeSymbol type)\n        {\n            foreach (var field in type.GetDeclaredInstanceMembers<IFieldSymbol>())\n            {\n                if (field.Type is not INamedTypeSymbol fieldType)\n                {\n                    return false;\n                }\n\n                if (SymbolEqualityComparer.Default.Equals(type, fieldType))\n                {\n                    return false;\n                }\n\n                if (!IsShallowCopyable(fieldType))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        private bool AreShallowCopyable(ImmutableArray<ITypeSymbol> types)\n        {\n            foreach (var t in types)\n                if (!IsShallowCopyable(t))\n                    return false;\n\n            return true;\n        }\n\n        private bool AreShallowCopyable(ImmutableArray<IFieldSymbol> fields)\n        {\n            foreach (var f in fields)\n                if (!IsShallowCopyable(f.Type))\n                    return false;\n\n            return true;\n        }\n    }\n\n    internal static class LibraryExtensions\n    {\n        public static WellKnownCodecDescription? FindByUnderlyingType(this WellKnownCodecDescription[] values, ISymbol type)\n        {\n            foreach (var c in values)\n                if (SymbolEqualityComparer.Default.Equals(c.UnderlyingType, type))\n                    return c;\n\n            return null;\n        }\n\n        public static WellKnownCopierDescription? FindByUnderlyingType(this WellKnownCopierDescription[] values, ISymbol type)\n        {\n            foreach (var c in values)\n                if (SymbolEqualityComparer.Default.Equals(c.UnderlyingType, type))\n                    return c;\n\n            return null;\n        }\n\n        public static bool HasScopedKeyword(this LibraryTypes libraryTypes) => libraryTypes.LanguageVersion is null or >= LanguageVersion.CSharp11;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/MetadataGenerator.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing System;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class MetadataGenerator\n    {\n        private readonly CodeGenerator _codeGenerator;\n\n        public MetadataGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        private MetadataModel MetadataModel => _codeGenerator.MetadataModel;\n\n        public ClassDeclarationSyntax GenerateMetadata()\n        {\n            var configParam = \"config\".ToIdentifierName();\n            var addSerializerMethod = configParam.Member(\"Serializers\").Member(\"Add\");\n            var addCopierMethod = configParam.Member(\"Copiers\").Member(\"Add\");\n            var addConverterMethod = configParam.Member(\"Converters\").Member(\"Add\");\n            var body = new List<StatementSyntax>();\n\n            foreach (var type in MetadataModel.SerializableTypes)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addSerializerMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(GetCodecTypeName(type))))))));\n            }\n\n            foreach (var type in MetadataModel.SerializableTypes)\n            {\n                if (type.IsEnumType) continue;\n\n                if (!MetadataModel.DefaultCopiers.TryGetValue(type, out var typeName))\n                    typeName = GetCopierTypeName(type);\n\n                body.Add(ExpressionStatement(InvocationExpression(addCopierMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(typeName)))))));\n            }\n\n            foreach (var type in MetadataModel.DetectedCopiers)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addCopierMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))));\n            }\n\n            foreach (var type in MetadataModel.DetectedSerializers)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addSerializerMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))));\n            }\n\n            foreach (var type in MetadataModel.DetectedConverters)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addConverterMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))));\n            }\n\n            var addProxyMethod = configParam.Member(\"InterfaceProxies\").Member(\"Add\");\n            foreach (var type in MetadataModel.GeneratedProxies)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addProxyMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.TypeSyntax)))))));\n            }\n\n            var addInvokableInterfaceMethod = configParam.Member(\"Interfaces\").Member(\"Add\");\n            foreach (var type in MetadataModel.InvokableInterfaces.Values)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addInvokableInterfaceMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.InterfaceType.ToOpenTypeSyntax())))))));\n            }\n\n            var addInvokableInterfaceImplementationMethod = configParam.Member(\"InterfaceImplementations\").Member(\"Add\");\n            foreach (var type in MetadataModel.InvokableInterfaceImplementations)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addInvokableInterfaceImplementationMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))));\n            }\n\n            var addActivatorMethod = configParam.Member(\"Activators\").Member(\"Add\");\n            foreach (var type in MetadataModel.ActivatableTypes)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addActivatorMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(GetActivatorTypeName(type))))))));\n            }\n\n            foreach (var type in MetadataModel.DetectedActivators)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addActivatorMethod,\n                    ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.ToOpenTypeSyntax())))))));\n            }\n\n            var addWellKnownTypeIdMethod = configParam.Member(\"WellKnownTypeIds\").Member(\"Add\");\n            foreach (var type in MetadataModel.WellKnownTypeIds)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addWellKnownTypeIdMethod,\n                    ArgumentList(SeparatedList(new[] { Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(type.Id))), Argument(TypeOfExpression(type.Type)) })))));\n            }\n\n            var addTypeAliasMethod = configParam.Member(\"WellKnownTypeAliases\").Member(\"Add\");\n            foreach (var type in MetadataModel.TypeAliases)\n            {\n                body.Add(ExpressionStatement(InvocationExpression(addTypeAliasMethod,\n                    ArgumentList(SeparatedList(new[] { Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(type.Alias))), Argument(TypeOfExpression(type.Type)) })))));\n            }\n\n            AddCompoundTypeAliases(configParam, body);\n\n            var configType = _codeGenerator.LibraryTypes.TypeManifestOptions;\n            var configureMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), \"ConfigureInner\")\n                .AddModifiers(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword))\n                .AddParameterListParameters(\n                    Parameter(configParam.Identifier).WithType(configType.ToTypeSyntax()))\n                .AddBodyStatements(body.ToArray());\n\n            var interfaceType = _codeGenerator.LibraryTypes.TypeManifestProviderBase;\n            return ClassDeclaration(\"Metadata_\" + SyntaxGeneration.Identifier.SanitizeIdentifierName(_codeGenerator.Compilation.AssemblyName))\n                .AddBaseListTypes(SimpleBaseType(interfaceType.ToTypeSyntax()))\n                .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes())\n                .AddMembers(configureMethod);\n        }\n\n        private void AddCompoundTypeAliases(IdentifierNameSyntax configParam, List<StatementSyntax> body)\n        {\n            // The goal is to emit a tree describing all of the generated invokers in the form:\n            // (\"inv\", typeof(ProxyBaseType), typeof(ContainingInterface), \"<MethodId>\")\n            // The first step is to collate the invokers into tree to ease the process of generating a tree in code.\n            var nodeId = 0;\n            AddCompoundTypeAliases(body, configParam.Member(\"CompoundTypeAliases\"), MetadataModel.CompoundTypeAliases);\n            void AddCompoundTypeAliases(List<StatementSyntax> body, ExpressionSyntax tree, CompoundTypeAliasTree aliases)\n            {\n                ExpressionSyntax node;\n\n                if (aliases.Key.IsDefault)\n                {\n                    // At the root node, do not create a new node, just enumerate over the child nodes.\n                    node = tree;\n                }\n                else\n                {\n                    var nodeName = IdentifierName($\"n{++nodeId}\");\n                    node = nodeName;\n                    var valueExpression = aliases.Value switch\n                    {\n                        { } type => Argument(TypeOfExpression(type)),\n                        _ => null\n                    };\n\n                    // Get the arguments for the Add call\n                    var addArguments = aliases.Key switch\n                    {\n                        { IsType: true } typeKey => valueExpression switch\n                        {\n                            // Call the two-argument Add overload to add a key and value.\n                            { } argument => new[] { Argument(TypeOfExpression(typeKey.TypeValue.ToOpenTypeSyntax())), argument },\n\n                            // Call the one-argument Add overload to add only a key.\n                            _ => new[] { Argument(TypeOfExpression(typeKey.TypeValue.ToOpenTypeSyntax())) },\n                        },\n                        { IsString: true } stringKey => valueExpression switch\n                        {\n                            // Call the two-argument Add overload to add a key and value.\n                            { } argument => new[] { Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(stringKey.StringValue))), argument },\n\n                            // Call the one-argument Add overload to add only a key.\n                            _ => new[] { Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(stringKey.StringValue))) },\n                        },\n                        _ => throw new InvalidOperationException(\"Unexpected alias key\")\n                    };\n\n                    if (aliases.Children is { Count: > 0 })\n                    {\n                        // C#: var {newTree.Identifier} = {tree}.Add({addArguments});\n                        body.Add(LocalDeclarationStatement(VariableDeclaration(\n                            ParseTypeName(\"var\"),\n                            SingletonSeparatedList(VariableDeclarator(nodeName.Identifier).WithInitializer(EqualsValueClause(InvocationExpression(\n                                tree.Member(\"Add\"),\n                                ArgumentList(SeparatedList(addArguments)))))))));\n                    }\n                    else\n                    {\n                        // Do not emit a variable.\n                        // C#: {tree}.Add({addArguments});\n                        body.Add(ExpressionStatement(InvocationExpression(tree.Member(\"Add\"), ArgumentList(SeparatedList(addArguments)))));\n                    }\n                }\n\n                if (aliases.Children is { Count: > 0 })\n                {\n                    foreach (var child in aliases.Children.Values)\n                    {\n                        AddCompoundTypeAliases(body, node, child);\n                    }\n                }\n            }\n        }\n\n        public static TypeSyntax GetCodecTypeName(ISerializableTypeDescription type)\n        {\n            var genericArity = type.TypeParameters.Count;\n            var name = SerializerGenerator.GetSimpleClassName(type);\n            if (genericArity > 0)\n            {\n                name = $\"{name}<{new string(',', genericArity - 1)}>\";\n            }\n\n            return ParseTypeName(type.GeneratedNamespace + \".\" + name);\n        }\n\n        public static TypeSyntax GetCopierTypeName(ISerializableTypeDescription type)\n        {\n            var genericArity = type.TypeParameters.Count;\n            var name = CopierGenerator.GetSimpleClassName(type);\n            if (genericArity > 0)\n            {\n                name = $\"{name}<{new string(',', genericArity - 1)}>\";\n            }\n\n            return ParseTypeName(type.GeneratedNamespace + \".\" + name);\n        }\n\n        public static TypeSyntax GetActivatorTypeName(ISerializableTypeDescription type)\n        {\n            var genericArity = type.TypeParameters.Count;\n            var name = ActivatorGenerator.GetSimpleClassName(type);\n            if (genericArity > 0)\n            {\n                name = $\"{name}<{new string(',', genericArity - 1)}>\";\n            }\n\n            return ParseTypeName(type.GeneratedNamespace + \".\" + name);\n        }\n\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/FieldDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class FieldDescription : IFieldDescription\n    {\n        public FieldDescription(uint fieldId, bool isPrimaryConstructorParameter, IFieldSymbol member)\n        {\n            FieldId = fieldId;\n            IsPrimaryConstructorParameter = isPrimaryConstructorParameter;\n            Field = member;\n            Type = member.Type;\n            ContainingType = member.ContainingType;\n\n            if (Type.TypeKind == TypeKind.Dynamic)\n            {\n                TypeSyntax = PredefinedType(Token(SyntaxKind.ObjectKeyword));\n            }\n            else\n            {\n                TypeSyntax = Type.ToTypeSyntax();\n            }\n        }\n\n        public ISymbol Symbol => Field;\n        public IFieldSymbol Field { get; }\n        public uint FieldId { get; }\n        public ITypeSymbol Type { get; }\n        public INamedTypeSymbol ContainingType { get; }\n        public TypeSyntax TypeSyntax { get; }\n\n        public string AssemblyName => Type.ContainingAssembly.ToDisplayName();\n        public string TypeName => Type.ToDisplayName();\n        public string TypeNameIdentifier => Type.GetValidIdentifier();\n        public bool IsPrimaryConstructorParameter { get; set; }\n        public bool IsSerializable => true;\n        public bool IsCopyable => true;\n\n        public TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol) => typeSymbol.ToTypeSyntax();\n    }\n\n    internal interface IFieldDescription : IMemberDescription\n    {\n        IFieldSymbol Field { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/GenerateFieldIds.cs",
    "content": "namespace Orleans.CodeGenerator.Model;\n\n/// <summary>\n/// This enum provides options for controlling the field id generation logic.\n/// </summary>\npublic enum GenerateFieldIds\n{\n    /// <summary>\n    /// Only members explicitly annotated with a field id will be serialized. This is the default.\n    /// </summary>\n    None,\n    /// <summary>\n    /// Field ids will be automatically assigned to eligible public properties. To qualify, a property must have an accessible getter, and either an accessible setter or a corresponding constructor parameter.\n    /// </summary>\n    /// <remarks>\n    /// The presence of an explicit field id annotation on any member of a type will automatically disable automatic field id generation for that type.\n    /// </remarks>\n    PublicProperties\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/GeneratedInvokableDescription.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    [DebuggerDisplay(\"{MethodDescription}\")]\n    internal sealed class GeneratedInvokableDescription : ISerializableTypeDescription\n    {\n        private TypeSyntax _openTypeSyntax;\n        private TypeSyntax _typeSyntax;\n        private TypeSyntax _baseTypeSyntax;\n\n        public GeneratedInvokableDescription(\n            InvokableMethodDescription methodDescription,\n            Accessibility accessibility,\n            string generatedClassName,\n            string generatedNamespaceName,\n            List<IMemberDescription> members,\n            List<INamedTypeSymbol> serializationHooks,\n            INamedTypeSymbol baseType,\n            List<TypeSyntax> constructorArguments,\n            List<CompoundTypeAliasComponent[]> compoundTypeAliases,\n            string returnValueInitializerMethod,\n            ClassDeclarationSyntax classDeclarationSyntax)\n        {\n            if (methodDescription.AllTypeParameters.Count == 0)\n            {\n                MetadataName = $\"{generatedNamespaceName}.{generatedClassName}\";\n            }\n            else\n            {\n                MetadataName = $\"{generatedNamespaceName}.{generatedClassName}`{methodDescription.AllTypeParameters.Count}\";\n            }\n\n            BaseType = baseType;\n            Name = generatedClassName;\n            GeneratedNamespace = generatedNamespaceName;\n            Members = members;\n            MethodDescription = methodDescription;\n            Accessibility = accessibility;\n            SerializationHooks = serializationHooks;\n            ActivatorConstructorParameters = constructorArguments;\n            CompoundTypeAliases = compoundTypeAliases;\n            ReturnValueInitializerMethod = returnValueInitializerMethod;\n            ClassDeclarationSyntax = classDeclarationSyntax;\n        }\n\n        public Accessibility Accessibility { get; }\n        public TypeSyntax TypeSyntax => _typeSyntax ??= CreateTypeSyntax();\n        public TypeSyntax OpenTypeSyntax => _openTypeSyntax ??= CreateOpenTypeSyntax();\n        public bool HasComplexBaseType => BaseType is { SpecialType: not SpecialType.System_Object };\n        public bool IncludePrimaryConstructorParameters => false;\n        public INamedTypeSymbol BaseType { get; }\n        public TypeSyntax BaseTypeSyntax => _baseTypeSyntax ??= BaseType.ToTypeSyntax(MethodDescription.TypeParameterSubstitutions);\n        public string Namespace => GeneratedNamespace;\n        public string GeneratedNamespace { get; }\n        public string Name { get; }\n        public bool IsValueType => false;\n        public bool IsSealedType => true;\n        public bool IsAbstractType => false;\n        public bool IsEnumType => false;\n        public bool IsGenericType => TypeParameters.Count > 0;\n        public List<IMemberDescription> Members { get; }\n        public Compilation Compilation => MethodDescription.CodeGenerator.Compilation;\n        public bool IsEmptyConstructable => ActivatorConstructorParameters is not { Count: > 0 };\n        public bool UseActivator => ActivatorConstructorParameters is { Count: > 0 };\n        public bool TrackReferences => false;\n        public bool OmitDefaultMemberValues => false;\n        public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters => MethodDescription.AllTypeParameters;\n        public List<INamedTypeSymbol> SerializationHooks { get; }\n        public bool IsShallowCopyable => false;\n        public bool IsUnsealedImmutable => false;\n        public bool IsImmutable => false;\n        public bool IsExceptionType => false;\n        public List<TypeSyntax> ActivatorConstructorParameters { get; }\n        public bool HasActivatorConstructor => UseActivator;\n        public List<CompoundTypeAliasComponent[]> CompoundTypeAliases { get; }\n        public ClassDeclarationSyntax ClassDeclarationSyntax { get; }\n        public string ReturnValueInitializerMethod { get; }\n\n        public InvokableMethodDescription MethodDescription { get; }\n        public string MetadataName { get; }\n\n        public ExpressionSyntax GetObjectCreationExpression() => ObjectCreationExpression(TypeSyntax, ArgumentList(), null);\n\n        private TypeSyntax CreateTypeSyntax()\n        {\n            var simpleName = InvokableGenerator.GetSimpleClassName(MethodDescription);\n            var subs = MethodDescription.TypeParameterSubstitutions;\n            return (TypeParameters, Namespace) switch\n            {\n                ({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter])))))),\n                ({ Count: > 0 }, _) => GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter]))))),\n                (_, { Length: > 0 }) => QualifiedName(ParseName(Namespace), IdentifierName(simpleName)),\n                _ => IdentifierName(simpleName),\n            };\n        }\n\n        private TypeSyntax CreateOpenTypeSyntax()\n        {\n            var simpleName = InvokableGenerator.GetSimpleClassName(MethodDescription);\n            return (TypeParameters, Namespace) switch\n            {\n                ({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => OmittedTypeArgument()))))),\n                ({ Count: > 0 }, _) => GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => OmittedTypeArgument())))),\n                (_, { Length: > 0 }) => QualifiedName(ParseName(Namespace), IdentifierName(simpleName)),\n                _ => IdentifierName(simpleName),\n            };\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/GeneratedProxyDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Linq;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class GeneratedProxyDescription\n    {\n        public GeneratedProxyDescription(ProxyInterfaceDescription interfaceDescription, string generatedClassName)\n        {\n            InterfaceDescription = interfaceDescription;\n            GeneratedClassName = generatedClassName;\n            TypeSyntax = GetProxyTypeName(interfaceDescription);\n            if (InterfaceDescription.TypeParameters.Count == 0)\n            {\n                MetadataName = $\"{InterfaceDescription.GeneratedNamespace}.{GeneratedClassName}\";\n            }\n            else\n            {\n                MetadataName =  $\"{InterfaceDescription.GeneratedNamespace}.{GeneratedClassName}`{InterfaceDescription.TypeParameters.Count}\";\n            }\n        }\n\n        public TypeSyntax TypeSyntax { get; }\n        public ProxyInterfaceDescription InterfaceDescription { get; }\n        public string GeneratedClassName { get; }\n        public string MetadataName { get; }\n\n        private static TypeSyntax GetProxyTypeName(ProxyInterfaceDescription interfaceDescription)\n        {\n            var interfaceType = interfaceDescription.InterfaceType;\n            var genericArity = interfaceType.GetAllTypeParameters().Count();\n            var name = ProxyGenerator.GetSimpleClassName(interfaceDescription);\n            if (genericArity > 0)\n            {\n                name += $\"<{new string(',', genericArity - 1)}>\";\n            }\n\n            return ParseTypeName(interfaceDescription.GeneratedNamespace + \".\" + name);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/ICodecDescription.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator\n{\n    internal interface ICopierDescription\n    {\n        ITypeSymbol UnderlyingType { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/IMemberDescription.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.CodeGenerator\n{\n    internal interface IMemberDescription\n    {\n        uint FieldId { get; }\n        ISymbol Symbol { get; }\n        ITypeSymbol Type { get; }\n        INamedTypeSymbol ContainingType { get; }\n        string AssemblyName { get; }\n        string TypeName { get; }\n        TypeSyntax TypeSyntax { get; }\n        string TypeNameIdentifier { get; }\n        TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol);\n        bool IsPrimaryConstructorParameter { get; } \n        bool IsSerializable { get; }\n        bool IsCopyable { get; }\n    }\n\n    internal sealed class MemberDescriptionTypeComparer : IEqualityComparer<IMemberDescription>\n    {\n        public static MemberDescriptionTypeComparer Default { get; } = new MemberDescriptionTypeComparer();\n\n        public bool Equals(IMemberDescription x, IMemberDescription y)\n        {\n            if (ReferenceEquals(x, y))\n            {\n                return true;\n            }\n\n            if (ReferenceEquals(x, null) || ReferenceEquals(y, null))\n            {\n                return false;\n            }\n\n           return string.Equals(x.TypeName, y.TypeName) && string.Equals(x.AssemblyName, y.AssemblyName);\n        }\n\n        public int GetHashCode(IMemberDescription obj)\n        {\n            int hashCode = -499943048;\n            hashCode = hashCode * -1521134295 + StringComparer.Ordinal.GetHashCode(obj.TypeName);\n            hashCode = hashCode * -1521134295 + StringComparer.Ordinal.GetHashCode(obj.AssemblyName);\n            return hashCode;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/ISerializableTypeDescription.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Collections.Generic;\n\nnamespace Orleans.CodeGenerator\n{\n    internal interface ISerializableTypeDescription\n    {\n        Accessibility Accessibility { get; }\n        TypeSyntax TypeSyntax { get; }\n        bool HasComplexBaseType { get; }\n        bool IncludePrimaryConstructorParameters { get; }\n        INamedTypeSymbol BaseType { get; }\n        TypeSyntax BaseTypeSyntax { get; }\n        string Namespace { get; }\n        string GeneratedNamespace { get; }\n        string Name { get; }\n        bool IsValueType { get; }\n        bool IsSealedType { get; }\n        bool IsAbstractType { get; }\n        bool IsEnumType { get; }\n        bool IsGenericType { get; }\n        List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }\n        List<IMemberDescription> Members { get; }\n        Compilation Compilation { get; }\n        bool UseActivator { get; }\n        bool IsEmptyConstructable { get; }\n        bool HasActivatorConstructor { get; }\n        bool TrackReferences { get; }\n        bool OmitDefaultMemberValues { get; }\n        ExpressionSyntax GetObjectCreationExpression();\n        List<INamedTypeSymbol> SerializationHooks { get; }\n        bool IsShallowCopyable { get; }\n        bool IsUnsealedImmutable { get; }\n        bool IsImmutable { get; }\n        bool IsExceptionType { get; }\n        List<TypeSyntax> ActivatorConstructorParameters { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/InvokableMethodDescription.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Describes an invokable method.\n    /// This is a method on the original interface which defined it.\n    /// By contrast, <see cref=\"ProxyMethodDescription\"/> describes a method on an interface which a proxy is being generated for, having type argument substitutions, etc.\n    /// </summary>\n    internal sealed class InvokableMethodDescription : IEquatable<InvokableMethodDescription>\n    {\n        public static InvokableMethodDescription Create(InvokableMethodId method, INamedTypeSymbol containingType) => new(method, containingType);\n\n        private InvokableMethodDescription(InvokableMethodId invokableId, INamedTypeSymbol containingType)\n        {\n            Key = invokableId;\n            ContainingInterface = containingType;\n            GeneratedMethodId = CodeGenerator.CreateHashedMethodId(Method);\n            MethodId = CodeGenerator.GetId(Method)?.ToString(CultureInfo.InvariantCulture) ?? CodeGenerator.GetAlias(Method) ?? GeneratedMethodId;\n\n            MethodTypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n\n            // Set defaults from the interface type.\n            var invokableBaseTypes = new Dictionary<INamedTypeSymbol, INamedTypeSymbol>(SymbolEqualityComparer.Default);\n            foreach (var pair in ProxyBase.InvokableBaseTypes)\n            {\n                invokableBaseTypes[pair.Key] = pair.Value;\n            }\n\n            InvokableBaseTypes = invokableBaseTypes;\n            foreach (var methodAttr in Method.GetAttributes())\n            {\n                if (methodAttr.AttributeClass.GetAttributes(CodeGenerator.LibraryTypes.InvokableBaseTypeAttribute, out var attrs))\n                {\n                    foreach (var attr in attrs)\n                    {\n                        var ctorArgs = attr.ConstructorArguments;\n                        var proxyBaseType = (INamedTypeSymbol)ctorArgs[0].Value;\n                        var returnType = (INamedTypeSymbol)ctorArgs[1].Value;\n                        var invokableBaseType = (INamedTypeSymbol)ctorArgs[2].Value;\n                        if (!SymbolEqualityComparer.Default.Equals(ProxyBase.ProxyBaseType, proxyBaseType))\n                        {\n                            // This attribute does not apply to this particular invoker, since it is for a different proxy base type.\n                            continue;\n                        }\n\n                        invokableBaseTypes[returnType] = invokableBaseType;\n                    }\n                }\n\n                if (methodAttr.AttributeClass.GetAttributes(CodeGenerator.LibraryTypes.InvokableCustomInitializerAttribute, out attrs))\n                {\n                    foreach (var attr in attrs)\n                    {\n                        var methodName = (string)attr.ConstructorArguments[0].Value;\n\n                        TypedConstant methodArgument;\n                        if (attr.ConstructorArguments.Length == 2)\n                        {\n                            // Take the value from the attribute directly.\n                            methodArgument = attr.ConstructorArguments[1];\n                        }\n                        else\n                        {\n                            // Take the value from the attribute which this attribute is attached to.\n                            if (TryGetNamedArgument(attr.NamedArguments, \"AttributeArgumentName\", out var argNameArg)\n                                && TryGetNamedArgument(methodAttr.NamedArguments, (string)argNameArg.Value, out var namedArgument))\n                            {\n                                methodArgument = namedArgument;\n                            }\n                            else\n                            {\n                                var index = 0;\n                                if (TryGetNamedArgument(attr.NamedArguments, \"AttributeArgumentIndex\", out var indexArg))\n                                {\n                                    index = (int)indexArg.Value;\n                                }\n\n                                methodArgument = methodAttr.ConstructorArguments[index];\n                            }\n                        }\n\n                        CustomInitializerMethods.Add((methodName, methodArgument));\n                    }\n                }\n\n                if (SymbolEqualityComparer.Default.Equals(methodAttr.AttributeClass, CodeGenerator.LibraryTypes.ResponseTimeoutAttribute))\n                {\n                    ResponseTimeoutTicks = TimeSpan.Parse((string)methodAttr.ConstructorArguments[0].Value).Ticks;\n                }\n            }\n\n            AllTypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n            MethodTypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n\n            var names = new HashSet<string>(StringComparer.Ordinal);\n            foreach (var typeParameter in ContainingInterface.GetAllTypeParameters())\n            {\n                var tpName = GetTypeParameterName(names, typeParameter);\n                AllTypeParameters.Add((tpName, typeParameter));\n            }\n\n            foreach (var typeParameter in Method.TypeParameters)\n            {\n                var tpName = GetTypeParameterName(names, typeParameter);\n                AllTypeParameters.Add((tpName, typeParameter));\n                MethodTypeParameters.Add((tpName, typeParameter));\n            }\n\n            TypeParameterSubstitutions = new(SymbolEqualityComparer.Default);\n            foreach (var (name, parameter) in AllTypeParameters)\n            {\n                TypeParameterSubstitutions[parameter] = name;\n            }\n\n            static string GetTypeParameterName(HashSet<string> names, ITypeParameterSymbol typeParameter)\n            {\n                var count = 0;\n                var result = typeParameter.Name;\n                while (names.Contains(result))\n                {\n                    result = $\"{typeParameter.Name}_{++count}\";\n                }\n\n                names.Add(result);\n                return result.EscapeIdentifier();\n            }\n\n            static bool TryGetNamedArgument(ImmutableArray<KeyValuePair<string, TypedConstant>> arguments, string name, out TypedConstant value)\n            {\n                foreach (var arg in arguments)\n                {\n                    if (string.Equals(arg.Key, name, StringComparison.Ordinal))\n                    {\n                        value = arg.Value;\n                        return true;\n                    }\n                }\n\n                value = default;\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Gets the source generator.\n        /// </summary>\n        public CodeGenerator CodeGenerator => ProxyBase.CodeGenerator;\n\n        /// <summary>\n        /// Gets the method identifier.\n        /// </summary>\n        public InvokableMethodId Key { get; }\n\n        /// <summary>\n        /// Gets the proxy base information for the method (eg, GrainReference, whether it is an extension).\n        /// </summary>\n        public InvokableMethodProxyBase ProxyBase => Key.ProxyBase;\n\n        /// <summary>\n        /// Gets the method symbol.\n        /// </summary>\n        public IMethodSymbol Method => Key.Method;\n\n        /// <summary>\n        /// Gets the dictionary of invokable base types. This indicates what invokable base type (eg, ValueTaskRequest) should be used for a given return type (eg, ValueTask).\n        /// </summary>\n        public IReadOnlyDictionary<INamedTypeSymbol, INamedTypeSymbol> InvokableBaseTypes { get; }\n\n        /// <summary>\n        /// Gets the response timeout ticks, if set.\n        /// </summary>\n        public long? ResponseTimeoutTicks { get; }\n\n        /// <summary>\n        /// Gets the list of custom initializer method names and their corresponding argument.\n        /// </summary>\n        public List<(string MethodName, TypedConstant MethodArgument)> CustomInitializerMethods { get; } = new();\n\n        /// <summary>\n        /// Gets the generated method identifier.\n        /// </summary>\n        public string GeneratedMethodId { get; }\n\n        /// <summary>\n        /// Gets the method identifier.\n        /// </summary>\n        public string MethodId { get; }\n\n        public List<(string Name, ITypeParameterSymbol Parameter)> AllTypeParameters { get; }\n        public List<(string Name, ITypeParameterSymbol Parameter)> MethodTypeParameters { get; }\n        public Dictionary<ITypeParameterSymbol, string> TypeParameterSubstitutions { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this method has an alias.\n        /// </summary>\n        public bool HasAlias => !string.Equals(MethodId, GeneratedMethodId, StringComparison.Ordinal);\n\n        /// <summary>\n        /// Gets the interface which this type is contained in.\n        /// </summary>\n        public INamedTypeSymbol ContainingInterface { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this method is cancellable.\n        /// </summary>\n        public bool IsCancellable => Method.Parameters.Any(parameterSymbol => SymbolEqualityComparer.Default.Equals(CodeGenerator.LibraryTypes.CancellationToken, parameterSymbol.Type));\n\n        public bool Equals(InvokableMethodDescription other) => Key.Equals(other.Key);\n        public override bool Equals(object obj) => obj is InvokableMethodDescription imd && Equals(imd);\n        public override int GetHashCode() => Key.GetHashCode();\n        public override string ToString() => $\"{ProxyBase}/{ContainingInterface.Name}/{Method.Name}\";\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/InvokableMethodId.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing System;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Identifies an invokable method.\n    /// </summary>\n    internal readonly struct InvokableMethodId(InvokableMethodProxyBase proxyBaseInfo, INamedTypeSymbol interfaceType, IMethodSymbol method) : IEquatable<InvokableMethodId>\n    {\n        /// <summary>\n        /// Gets the proxy base information for the method (eg, GrainReference, whether it is an extension).\n        /// </summary>\n        public InvokableMethodProxyBase ProxyBase { get; } = proxyBaseInfo;\n\n        /// <summary>\n        /// Gets the method symbol.\n        /// </summary>\n        public IMethodSymbol Method { get; } = method;\n\n        /// <summary>\n        /// Gets the containing interface symbol.\n        /// </summary>\n        public INamedTypeSymbol InterfaceType { get; } = interfaceType;\n\n        public bool Equals(InvokableMethodId other) =>\n            ProxyBase.Equals(other.ProxyBase)\n            && SymbolEqualityComparer.Default.Equals(Method, other.Method)\n            && SymbolEqualityComparer.Default.Equals(InterfaceType, other.InterfaceType);\n\n        public override bool Equals(object obj) => obj is InvokableMethodId imd && Equals(imd);\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                return ProxyBase.GetHashCode()\n                    * 17 ^ SymbolEqualityComparer.Default.GetHashCode(Method)\n                    * 17 ^ SymbolEqualityComparer.Default.GetHashCode(InterfaceType);\n            }\n        }\n\n        public override string ToString() => $\"{ProxyBase}/{InterfaceType.Name}/{Method.Name}\";\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/InvokableMethodProxyBase.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Describes the proxy base for an invokable method, including whether the proxy is a grain reference or extension, and what invokable base types should be used for a given return type.\n    /// </summary>\n    internal sealed class InvokableMethodProxyBase : IEquatable<InvokableMethodProxyBase>\n    {\n        public InvokableMethodProxyBase(CodeGenerator codeGenerator, InvokableMethodProxyBaseId descriptor, Dictionary<INamedTypeSymbol, INamedTypeSymbol> invokableBaseTypes)\n        {\n            CodeGenerator = codeGenerator;\n            Key = descriptor;\n            InvokableBaseTypes = invokableBaseTypes ?? throw new ArgumentNullException(nameof(invokableBaseTypes));\n        }\n\n        /// <summary>\n        /// Gets the source generator.\n        /// </summary>\n        public CodeGenerator CodeGenerator { get; }\n\n        /// <summary>\n        /// Gets the proxy base id.\n        /// </summary>\n        public InvokableMethodProxyBaseId Key { get; }\n\n        /// <summary>\n        /// Gets the proxy base type, eg <c>GrainReference</c>.\n        /// </summary>\n        public INamedTypeSymbol ProxyBaseType => Key.ProxyBaseType;\n\n        /// <summary>\n        /// Gets a value indicating whether this descriptor represents an extension.\n        /// </summary>\n        public bool IsExtension => Key.IsExtension;\n\n        /// <summary>\n        /// Gets the components of the compound type alias used to refer to this proxy base.\n        /// </summary>\n        public ImmutableArray<CompoundTypeAliasComponent> CompositeAliasComponents => Key.CompositeAliasComponents;\n\n        /// <summary>\n        /// Gets the dictionary of invokable base types. This indicates what invokable base type (eg, ValueTaskRequest) should be used for a given return type (eg, ValueTask).\n        /// </summary>\n        public IReadOnlyDictionary<INamedTypeSymbol, INamedTypeSymbol> InvokableBaseTypes { get; }\n\n        public bool Equals(InvokableMethodProxyBase other) => other is not null && Key.Equals(other.Key);\n        public override bool Equals(object obj) => obj is InvokableMethodProxyBase other && Equals(other);\n        public override int GetHashCode() => Key.GetHashCode();\n        public override string ToString() => Key.ToString();\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/InvokableMethodProxyBaseId.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Immutable;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Identifies a proxy base, including whether the proxy is a grain reference or extension.\n    /// </summary>\n    internal readonly struct InvokableMethodProxyBaseId : IEquatable<InvokableMethodProxyBaseId>\n    {\n        public InvokableMethodProxyBaseId(INamedTypeSymbol type, bool isExtension)\n        {\n            if (!SymbolEqualityComparer.Default.Equals(type, type.OriginalDefinition))\n            {\n                throw new ArgumentException(\"Type must be an original definition. This is a code generator bug.\");\n            }\n\n            ProxyBaseType = type;\n            IsExtension = isExtension;\n\n            if (IsExtension)\n            {\n                CompositeAliasComponents = ImmutableArray.Create(new CompoundTypeAliasComponent[] { new(ProxyBaseType), new(\"Ext\") });\n                GeneratedClassNameComponent = $\"{ProxyBaseType.Name}_Ext\";\n            }\n            else\n            {\n                CompositeAliasComponents = ImmutableArray.Create(new CompoundTypeAliasComponent[] { new(ProxyBaseType) });\n                GeneratedClassNameComponent = ProxyBaseType.Name;\n            }\n        }\n\n        /// <summary>\n        /// Gets the proxy base type, eg <c>GrainReference</c>.\n        /// </summary>\n        public INamedTypeSymbol ProxyBaseType { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this descriptor represents an extension.\n        /// </summary>\n        public bool IsExtension { get; }\n\n        /// <summary>\n        /// Gets the components of the compound type alias used to refer to this proxy base.\n        /// </summary>\n        public ImmutableArray<CompoundTypeAliasComponent> CompositeAliasComponents { get; }\n\n        /// <summary>\n        /// Gets a string used to distinguish this proxy base from others in generated class names.\n        /// </summary>\n        public string GeneratedClassNameComponent { get; }\n\n        public bool Equals(InvokableMethodProxyBaseId other) => SymbolEqualityComparer.Default.Equals(ProxyBaseType, other.ProxyBaseType) && IsExtension == other.IsExtension;\n        public override bool Equals(object obj) => obj is InvokableMethodProxyBaseId other && Equals(other);\n        public override int GetHashCode() => IsExtension.GetHashCode() * 17 ^ SymbolEqualityComparer.Default.GetHashCode(ProxyBaseType);\n        public override string ToString() => GeneratedClassNameComponent;\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/MetadataModel.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class MetadataModel\n    {\n        public List<ISerializableTypeDescription> SerializableTypes { get; } = new(1024);\n        public Dictionary<INamedTypeSymbol, ProxyInterfaceDescription> InvokableInterfaces { get; } = new(SymbolEqualityComparer.Default);\n        public List<INamedTypeSymbol> InvokableInterfaceImplementations { get; } = new(1024);\n        public Dictionary<InvokableMethodId, GeneratedInvokableDescription> GeneratedInvokables { get; } = new();\n        public List<GeneratedProxyDescription> GeneratedProxies { get; } = new(1024);\n        public List<ISerializableTypeDescription> ActivatableTypes { get; } = new(1024);\n        public List<INamedTypeSymbol> DetectedSerializers { get; } = new();\n        public List<INamedTypeSymbol> DetectedActivators { get; } = new();\n        public Dictionary<ISerializableTypeDescription, TypeSyntax> DefaultCopiers { get; } = new();\n        public List<INamedTypeSymbol> DetectedCopiers { get; } = new();\n        public List<INamedTypeSymbol> DetectedConverters { get; } = new();\n        public List<(TypeSyntax Type, string Alias)> TypeAliases { get; } = new(1024);\n        public CompoundTypeAliasTree CompoundTypeAliases { get; } = CompoundTypeAliasTree.Create();\n        public List<(TypeSyntax Type, uint Id)> WellKnownTypeIds { get; } = new(1024);\n        public HashSet<string> ApplicationParts { get; } = new();\n        internal Dictionary<INamedTypeSymbol, Dictionary<INamedTypeSymbol, INamedTypeSymbol>> ProxyBaseTypeInvokableBaseTypes { get; } = new (SymbolEqualityComparer.Default);\n    }\n\n    /// <summary>\n    /// Represents a compound type aliases as a prefix tree.\n    /// </summary>\n    internal sealed class CompoundTypeAliasTree\n    {\n        private Dictionary<object, CompoundTypeAliasTree> _children;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CompoundTypeAliasTree\"/> class.\n        /// </summary>\n        private CompoundTypeAliasTree(CompoundTypeAliasComponent key, TypeSyntax value)\n        {\n            Key = key;\n            Value = value;\n        }\n\n        /// <summary>\n        /// Gets the key for this node.\n        /// </summary>\n        public CompoundTypeAliasComponent Key { get; }\n\n        /// <summary>\n        /// Gets the value for this node.\n        /// </summary>\n        public TypeSyntax Value { get; private set; }\n\n        /// <summary>\n        /// Creates a new tree with a root node which has no key or value.\n        /// </summary>\n        public static CompoundTypeAliasTree Create() => new(default, default);\n\n        public Dictionary<object, CompoundTypeAliasTree> Children => _children;\n\n        internal CompoundTypeAliasTree GetChildOrDefault(object key)\n        {\n            TryGetChild(key, out var result);\n            return result;\n        }\n\n        internal bool TryGetChild(object key, out CompoundTypeAliasTree result)\n        {\n            if (_children is { } children)\n            {\n                return children.TryGetValue(key, out result);\n            }\n\n            result = default;\n            return false;\n        }\n\n        public void Add(CompoundTypeAliasComponent[] key, TypeSyntax value)\n        {\n            Add(key.AsSpan(), value);\n        }\n\n        public void Add(ReadOnlySpan<CompoundTypeAliasComponent> keys, TypeSyntax value)\n        {\n            if (keys.Length == 0)\n            {\n                throw new InvalidOperationException(\"No valid key specified.\");\n            }\n\n            var key = keys[0];\n            if (keys.Length == 1)\n            {\n                AddInternal(key, value);\n            }\n            else\n            {\n                var childNode = GetChildOrDefault(key) ?? AddInternal(key);\n                childNode.Add(keys.Slice(1), value);\n            }\n        }\n\n        /// <summary>\n        /// Adds a node to the tree.\n        /// </summary>\n        /// <param name=\"key\">The key for the new node.</param>\n        public CompoundTypeAliasTree Add(ITypeSymbol key) => AddInternal(new CompoundTypeAliasComponent(key));\n\n        /// <summary>\n        /// Adds a node to the tree.\n        /// </summary>\n        /// <param name=\"key\">The key for the new node.</param>\n        public CompoundTypeAliasTree Add(string key) => AddInternal(new CompoundTypeAliasComponent(key));\n\n        /// <summary>\n        /// Adds a node to the tree.\n        /// </summary>\n        /// <param name=\"key\">The key for the new node.</param>\n        /// <param name=\"value\">The value for the new node.</param>\n        public CompoundTypeAliasTree Add(string key, TypeSyntax value) => AddInternal(new CompoundTypeAliasComponent(key), value);\n\n        /// <summary>\n        /// Adds a node to the tree.\n        /// </summary>\n        /// <param name=\"key\">The key for the new node.</param>\n        /// <param name=\"value\">The value for the new node.</param>\n        public CompoundTypeAliasTree Add(ITypeSymbol key, TypeSyntax value) => AddInternal(new CompoundTypeAliasComponent(key), value);\n\n        private CompoundTypeAliasTree AddInternal(CompoundTypeAliasComponent key) => AddInternal(key, default);\n        private CompoundTypeAliasTree AddInternal(CompoundTypeAliasComponent key, TypeSyntax value)\n        {\n            _children ??= new();\n\n            if (_children.TryGetValue(key, out var existing))\n            {\n                if (value is not null && existing.Value is not null)\n                {\n                    throw new ArgumentException($\"A key with the value '{key}' already exists. Existing value: '{existing.Value}', new value: '{value}'\");\n                }\n\n                existing.Value = value;\n                return existing;\n            }\n            else\n            {\n                return _children[key] = new CompoundTypeAliasTree(key, value);\n            }\n        }\n    }\n\n    internal readonly struct CompoundTypeAliasComponent : IEquatable<CompoundTypeAliasComponent>\n    {\n        private readonly Either<string, ITypeSymbol> _value;\n        public CompoundTypeAliasComponent(string value) => _value = new Either<string, ITypeSymbol>(value);\n        public CompoundTypeAliasComponent(ITypeSymbol value) => _value = new Either<string, ITypeSymbol>(value);\n        public static CompoundTypeAliasComponent Default => new();\n        public bool IsDefault => _value.RawValue is null;\n        public bool IsString => _value.IsLeft;\n        public string StringValue => _value.LeftValue;\n        public bool IsType => _value.IsRight;\n        public ITypeSymbol TypeValue => _value.RightValue;\n        public object Value => _value.RawValue;\n\n        public bool Equals(CompoundTypeAliasComponent other) => (Value, other.Value) switch\n        {\n            (null, null) => true,\n            (string stringValue, string otherStringValue) => string.Equals(stringValue, otherStringValue),\n            (ITypeSymbol typeValue, ITypeSymbol otherTypeValue) => SymbolEqualityComparer.Default.Equals(typeValue, otherTypeValue),\n            _ => false,\n        };\n        public override bool Equals(object obj) => obj is CompoundTypeAliasComponent other && Equals(other);\n        public override int GetHashCode() => _value.RawValue switch\n        {\n            string stringValue => stringValue.GetHashCode(),\n            ITypeSymbol type => SymbolEqualityComparer.Default.GetHashCode(type),\n            _ => throw new InvalidOperationException($\"Unsupported type {_value.RawValue}\")\n        };\n\n        internal readonly struct EqualityComparer : IEqualityComparer<CompoundTypeAliasComponent>\n        {\n            public static EqualityComparer Default => default;\n            public bool Equals(CompoundTypeAliasComponent x, CompoundTypeAliasComponent y) => x.Equals(y);\n            public int GetHashCode(CompoundTypeAliasComponent obj) => obj.GetHashCode();\n        }\n\n        public override string ToString() => _value.RawValue?.ToString();\n    }\n\n    internal readonly struct Either<T, U> where T : class where U : class\n    {\n        private readonly bool _isLeft;\n        private readonly object _value;\n        public Either(T value)\n        {\n            _value = value;\n            _isLeft = true;\n        }\n\n        public Either(U value)\n        {\n            _value = value;\n            _isLeft = false;\n        }\n\n        public bool IsLeft => _isLeft;\n        public bool IsRight => !IsLeft;\n        public T LeftValue => (T)_value;\n        public U RightValue => (U)_value;\n        public object RawValue => _value;\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/MethodSignatureComparer.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.CodeGenerator\n{\n    internal sealed class MethodSignatureComparer : IEqualityComparer<IMethodSymbol>, IComparer<IMethodSymbol>\n        {\n            public static MethodSignatureComparer Default { get; } = new();\n\n            private MethodSignatureComparer()\n            {\n            }\n\n            public bool Equals(IMethodSymbol x, IMethodSymbol y)\n            {\n                if (!string.Equals(x.Name, y.Name, StringComparison.Ordinal))\n                {\n                    return false;\n                }\n\n                if (x.TypeArguments.Length != y.TypeArguments.Length)\n                {\n                    return false;\n                }\n\n                for (var i = 0; i < x.TypeArguments.Length; i++)\n                {\n                    if (!SymbolEqualityComparer.Default.Equals(x.TypeArguments[i], y.TypeArguments[i]))\n                    {\n                        return false;\n                    }\n                }\n\n                if (x.Parameters.Length != y.Parameters.Length)\n                {\n                    return false;\n                }\n\n                for (var i = 0; i < x.Parameters.Length; i++)\n                {\n                    if (!SymbolEqualityComparer.Default.Equals(x.Parameters[i].Type, y.Parameters[i].Type))\n                    {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n\n            public int GetHashCode(IMethodSymbol obj)\n            {\n                int hashCode = -499943048;\n                hashCode = hashCode * -1521134295 + StringComparer.Ordinal.GetHashCode(obj.Name);\n\n                foreach (var arg in obj.TypeArguments)\n                {\n                    hashCode = hashCode * -1521134295 + SymbolEqualityComparer.Default.GetHashCode(arg);\n                }\n\n                foreach (var parameter in obj.Parameters)\n                {\n                    hashCode = hashCode * -1521134295 + SymbolEqualityComparer.Default.GetHashCode(parameter.Type);\n                }\n\n                return hashCode;\n            }\n\n            public int Compare(IMethodSymbol x, IMethodSymbol y)\n            {\n                var result = StringComparer.Ordinal.Compare(x.Name, y.Name);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                result = x.TypeArguments.Length.CompareTo(y.TypeArguments.Length);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                for (var i = 0; i < x.TypeArguments.Length; i++)\n                {\n                    var xh = SymbolEqualityComparer.Default.GetHashCode(x.TypeArguments[i]);\n                    var yh = SymbolEqualityComparer.Default.GetHashCode(y.TypeArguments[i]);\n                    result = xh.CompareTo(yh);\n                    if (result != 0)\n                    {\n                        return result;\n                    }\n                }\n\n                result = x.Parameters.Length.CompareTo(y.Parameters.Length);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                for (var i = 0; i < x.Parameters.Length; i++)\n                {\n                    var xh = SymbolEqualityComparer.Default.GetHashCode(x.Parameters[i].Type);\n                    var yh = SymbolEqualityComparer.Default.GetHashCode(y.Parameters[i].Type);\n                    result = xh.CompareTo(yh);\n                    if (result != 0)\n                    {\n                        return result;\n                    }\n                }\n\n                return 0;\n            }\n        }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/PropertyDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal interface IPropertyDescription : IMemberDescription \n    {\n    }\n\n    internal class PropertyDescription : IPropertyDescription\n    {\n        public PropertyDescription(uint fieldId, bool isPrimaryConstructorParameter, IPropertySymbol property)\n        {\n            FieldId = fieldId;\n            IsPrimaryConstructorParameter = isPrimaryConstructorParameter;\n            Property = property;\n\n            if (Type.TypeKind == TypeKind.Dynamic)\n            {\n                TypeSyntax = PredefinedType(Token(SyntaxKind.ObjectKeyword));\n            }\n            else\n            {\n                TypeSyntax = Type.ToTypeSyntax();\n            }\n        }\n\n        public uint FieldId { get; }\n        public ISymbol Symbol => Property;\n        public ITypeSymbol Type => Property.Type;\n        public INamedTypeSymbol ContainingType => Property.ContainingType;\n        public IPropertySymbol Property { get; }\n\n        public TypeSyntax TypeSyntax { get; }\n\n        public string AssemblyName => Type.ContainingAssembly.ToDisplayName();\n        public string TypeName => Type.ToDisplayName();\n        public string TypeNameIdentifier => Type.GetValidIdentifier();\n        public bool IsPrimaryConstructorParameter { get; set; }\n        public bool IsSerializable => true;\n        public bool IsCopyable => true;\n\n        public TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol) => typeSymbol.ToTypeSyntax();\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/ProxyInterfaceDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\nusing Orleans.CodeGenerator.Diagnostics;\nusing System.Linq;\nusing System.Diagnostics;\n\nnamespace Orleans.CodeGenerator\n{\n    [DebuggerDisplay(\"{InterfaceType} (proxy base {ProxyBaseType})\")]\n    internal class ProxyInterfaceDescription : IEquatable<ProxyInterfaceDescription>\n    {\n        private static readonly char[] FilteredNameChars = new char[] { '`', '.' };\n        private List<ProxyMethodDescription> _methods;\n\n        public ProxyInterfaceDescription(\n            CodeGenerator codeGenerator,\n            INamedTypeSymbol proxyBaseType,\n            INamedTypeSymbol interfaceType)\n        {\n            ValidateBaseClass(codeGenerator.LibraryTypes, proxyBaseType);\n\n            var prop = interfaceType.GetAllMembers<IPropertySymbol>().FirstOrDefault();\n            if (prop is { })\n            {\n                throw new OrleansGeneratorDiagnosticAnalysisException(RpcInterfacePropertyDiagnostic.CreateDiagnostic(interfaceType, prop));\n            }\n\n            CodeGenerator = codeGenerator;\n            InterfaceType = interfaceType;\n            Name = codeGenerator.GetAlias(interfaceType) ?? interfaceType.Name;\n            ProxyBaseType = proxyBaseType;\n\n            // If the name is a user-defined name which specified a generic arity, strip the arity backtick now\n            if (Name.IndexOfAny(FilteredNameChars) >= 0)\n            {\n                foreach (var c in FilteredNameChars)\n                {\n                    Name = Name.Replace(c, '_');\n                }\n            }\n\n            GeneratedNamespace = InterfaceType.GetNamespaceAndNesting() switch\n            {\n                { Length: > 0 } ns => $\"{CodeGenerator.CodeGeneratorName}.{ns}\",\n                _ => CodeGenerator.CodeGeneratorName\n            };\n\n            var names = new HashSet<string>(StringComparer.Ordinal);\n            TypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n\n            foreach (var tp in interfaceType.GetAllTypeParameters())\n            {\n                var tpName = GetTypeParameterName(names, tp);\n                TypeParameters.Add((tpName, tp));\n            }\n\n            static string GetTypeParameterName(HashSet<string> names, ITypeParameterSymbol tp)\n            {\n                var count = 0;\n                var result = tp.Name;\n                while (names.Contains(result))\n                {\n                    result = $\"{tp.Name}_{++count}\";\n                }\n\n                names.Add(result);\n                return result;\n            }\n        }\n\n        public CodeGenerator CodeGenerator { get; }\n\n        private List<ProxyMethodDescription> GetMethods()\n        {\n            var result = new List<ProxyMethodDescription>();\n            foreach (var iface in GetAllInterfaces(InterfaceType))\n            {\n                foreach (var method in iface.GetDeclaredInstanceMembers<IMethodSymbol>())\n                {\n                    if (method.MethodKind == MethodKind.ExplicitInterfaceImplementation)\n                    {\n                        // Explicit implementations can be ignored when generating a proxy.\n                        // Proxies must implement every method explicitly to ensure faithful reproduction of the interface behavior.\n                        // At the calling side, the explicit implementation will be called if it was not overridden by a derived type.\n                        continue;\n                    }\n\n                    var methodDescription = CodeGenerator.GetProxyMethodDescription(InterfaceType, method: method);\n                    result.Add(methodDescription);\n                }\n            }\n\n            return result;\n\n            static IEnumerable<INamedTypeSymbol> GetAllInterfaces(INamedTypeSymbol s)\n            {\n                if (s.TypeKind == TypeKind.Interface)\n                {\n                    yield return s;\n                }\n\n                foreach (var i in s.AllInterfaces)\n\n                {\n                    yield return i;\n                }\n            }\n        }\n\n        public string Name { get; }\n        public INamedTypeSymbol InterfaceType { get; }\n        public List<ProxyMethodDescription> Methods => _methods ??= GetMethods(); \n        public SemanticModel SemanticModel { get; }\n        public string GeneratedNamespace { get; }\n        public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }\n        public INamedTypeSymbol ProxyBaseType { get; }\n\n        private static void ValidateBaseClass(LibraryTypes l, INamedTypeSymbol baseClass)\n        {\n            ValidateGenericInvokeAsync(l, baseClass);\n            ValidateNonGenericInvokeAsync(l, baseClass);\n\n            static void ValidateGenericInvokeAsync(LibraryTypes l, INamedTypeSymbol baseClass)\n            {\n                var found = false;\n                string complaint = null;\n                ISymbol complaintMember = null;\n                foreach (var member in baseClass.GetMembers(\"InvokeAsync\"))\n                {\n                    if (member is not IMethodSymbol method)\n                    {\n                        complaintMember = member;\n                        complaint = \"not a method\";\n                        continue;\n                    }\n\n                    if (method.TypeParameters.Length != 1)\n                    {\n                        complaintMember = member;\n                        complaint = \"incorrect number of type parameters (expected one type parameter)\";\n                        continue;\n                    }\n\n                    if (method.Parameters.Length != 1)\n                    {\n                        complaintMember = member;\n                        complaint = $\"missing parameter (expected a parameter of type {l.IInvokable.ToDisplayString()})\";\n                        continue;\n                    }\n\n                    var paramType = method.Parameters[0].Type;\n                    if (!SymbolEqualityComparer.Default.Equals(paramType, l.IInvokable))\n                    {\n                        var implementsIInvokable = false;\n                        foreach (var @interface in paramType.AllInterfaces)\n                        {\n                            if (SymbolEqualityComparer.Default.Equals(@interface, l.IInvokable))\n                            {\n                                implementsIInvokable = true;\n                                break;\n                            }\n                        }\n\n                        if (!implementsIInvokable)\n                        {\n                            complaintMember = member;\n                            complaint = $\"incorrect parameter type (found {paramType}, expected {l.IInvokable} or a type which implements {l.IInvokable})\";\n                            continue;\n                        }\n                    }\n\n                    var expectedReturnType = l.ValueTask_1.Construct(method.TypeParameters[0]);\n                    if (!SymbolEqualityComparer.Default.Equals(method.ReturnType, expectedReturnType))\n                    {\n                        complaintMember = member;\n                        complaint = $\"incorrect return type (found: {method.ReturnType.ToDisplayString()}, expected {expectedReturnType.ToDisplayString()})\";\n                        continue;\n                    }\n\n                    found = true;\n                }\n\n                if (!found)\n                {\n                    var notFoundMessage = $\"Proxy base class {baseClass} does not contain a definition for ValueTask<T> InvokeAsync<T>(IInvokable)\";\n                    var locationMember = complaintMember ?? baseClass;\n                    var complaintMessage = complaint switch\n                    {\n                        { Length: > 0 } => $\"{notFoundMessage}. Complaint: {complaint} for symbol: {complaintMember.ToDisplayString()}\",\n                        _ => notFoundMessage,\n                    };\n                    var diagnostic = IncorrectProxyBaseClassSpecificationDiagnostic.CreateDiagnostic(baseClass, locationMember.Locations.First(), complaintMessage);\n                    throw new OrleansGeneratorDiagnosticAnalysisException(diagnostic);\n                }\n            }\n            \n            static void ValidateNonGenericInvokeAsync(LibraryTypes l, INamedTypeSymbol baseClass)\n            {\n                var found = false;\n                string complaint = null;\n                ISymbol complaintMember = null;\n                foreach (var member in baseClass.GetMembers(\"InvokeAsync\"))\n                {\n                    if (member is not IMethodSymbol method)\n                    {\n                        complaintMember = member;\n                        complaint = \"not a method\";\n                        continue;\n                    }\n\n                    if (method.TypeParameters.Length != 0)\n                    {\n                        complaintMember = member;\n                        complaint = \"incorrect number of type parameters (expected zero)\";\n                        continue;\n                    }\n\n                    if (method.Parameters.Length != 1)\n                    {\n                        complaintMember = member;\n                        complaint = $\"missing parameter (expected a parameter of type {l.IInvokable.ToDisplayString()})\";\n                        continue;\n                    }\n\n                    var paramType = method.Parameters[0].Type;\n                    if (!SymbolEqualityComparer.Default.Equals(paramType, l.IInvokable))\n                    {\n                        var implementsIInvokable = false;\n                        foreach (var @interface in paramType.AllInterfaces)\n                        {\n                            if (SymbolEqualityComparer.Default.Equals(@interface, l.IInvokable))\n                            {\n                                implementsIInvokable = true;\n                                break;\n                            }\n                        }\n\n                        if (!implementsIInvokable)\n                        {\n                            complaintMember = member;\n                            complaint = $\"incorrect parameter type (found {method.Parameters[0].Type}, expected {l.IInvokable})\";\n                            continue;\n                        }\n                    }\n\n                    if (!SymbolEqualityComparer.Default.Equals(method.ReturnType, l.ValueTask))\n                    {\n                        complaintMember = member;\n                        complaint = $\"incorrect return type (found: {method.ReturnType.ToDisplayString()}, expected {l.ValueTask.ToDisplayString()})\";\n                        continue;\n                    }\n\n                    found = true;\n                }\n\n                if (!found)\n                {\n                    var notFoundMessage = $\"Proxy base class {baseClass} does not contain a definition for ValueTask InvokeAsync(IInvokable)\";\n                    var locationMember = complaintMember ?? baseClass;\n                    var complaintMessage = complaint switch\n                    {\n                        { Length: > 0 } => $\"{notFoundMessage}. Complaint: {complaint} for symbol: {complaintMember.ToDisplayString()}\",\n                        _ => notFoundMessage,\n                    };\n                    var diagnostic = IncorrectProxyBaseClassSpecificationDiagnostic.CreateDiagnostic(baseClass, locationMember.Locations.First(), complaintMessage);\n                    throw new OrleansGeneratorDiagnosticAnalysisException(diagnostic);\n                }\n            }\n        }\n\n        public bool Equals(ProxyInterfaceDescription other) => SymbolEqualityComparer.Default.Equals(InterfaceType, other.InterfaceType) && SymbolEqualityComparer.Default.Equals(ProxyBaseType, other.ProxyBaseType);\n        public override bool Equals(object obj) => obj is ProxyInterfaceDescription other && Equals(other);\n        public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(InterfaceType) * 17 ^ SymbolEqualityComparer.Default.GetHashCode(ProxyBaseType);\n        public override string ToString() => $\"Type: {InterfaceType}, ProxyBaseType: {ProxyBaseType}\";\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/ProxyMethodDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Collections.Immutable;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Describes an invokable method on a proxy interface.\n    /// </summary>\n    [DebuggerDisplay(\"{Method} (from {ProxyInterface})\")]\n    internal class ProxyMethodDescription : IEquatable<ProxyMethodDescription>\n    {\n        private readonly GeneratedInvokableDescription _originalInvokable;\n        public static ProxyMethodDescription Create(\n            ProxyInterfaceDescription proxyInterface,\n            GeneratedInvokableDescription generatedInvokable,\n            IMethodSymbol method)\n            => new(proxyInterface, generatedInvokable, method);\n\n        private ProxyMethodDescription(ProxyInterfaceDescription proxyInterface, GeneratedInvokableDescription generatedInvokable, IMethodSymbol method)\n        {\n            _originalInvokable = generatedInvokable;\n            Method = method;\n            ProxyInterface = proxyInterface;\n\n            TypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n            MethodTypeParameters = new List<(string Name, ITypeParameterSymbol Parameter)>();\n\n            TypeParametersWithArguments = Method.ContainingType.GetAllTypeParameters().Zip(method.ContainingType.GetAllTypeArguments(), (a, b) => (a, b)).ToImmutableArray();\n            var names = new HashSet<string>(StringComparer.Ordinal);\n            foreach (var (typeParameter, typeArgument) in TypeParametersWithArguments)\n            {\n                var tpName = GetTypeParameterName(names, typeParameter);\n                TypeParameters.Add((tpName, typeParameter));\n            }\n\n            foreach (var typeParameter in Method.TypeParameters)\n            {\n                var tpName = GetTypeParameterName(names, typeParameter);\n                TypeParameters.Add((tpName, typeParameter));\n                MethodTypeParameters.Add((tpName, typeParameter));\n            }\n\n            TypeParameterSubstitutions = new(SymbolEqualityComparer.Default);\n            foreach (var (name, parameter) in TypeParameters)\n            {\n                TypeParameterSubstitutions[parameter] = name;\n            }\n\n            foreach (var (parameter, arg) in TypeParametersWithArguments)\n            {\n                TypeParameterSubstitutions[parameter] = arg.ToDisplayName();\n            }\n\n            GeneratedInvokable = new ConstructedGeneratedInvokableDescription(generatedInvokable, this);\n            static string GetTypeParameterName(HashSet<string> names, ITypeParameterSymbol typeParameter)\n            {\n                var count = 0;\n                var result = typeParameter.Name;\n                while (names.Contains(result))\n                {\n                    result = $\"{typeParameter.Name}_{++count}\";\n                }\n\n                names.Add(result);\n                return result.EscapeIdentifier();\n            }\n        }\n\n        public CodeGenerator CodeGenerator => InvokableMethod.CodeGenerator;\n        public InvokableMethodDescription InvokableMethod => _originalInvokable.MethodDescription;\n        public ConstructedGeneratedInvokableDescription GeneratedInvokable { get; }\n        public ProxyInterfaceDescription ProxyInterface { get; }\n\n        public IMethodSymbol Method { get; }\n        public InvokableMethodId InvokableId { get; }\n        public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }\n        public List<(string Name, ITypeParameterSymbol Parameter)> MethodTypeParameters { get; }\n        public ImmutableArray<(ITypeParameterSymbol Parameter, ITypeSymbol Argument)> TypeParametersWithArguments { get; }\n        public Dictionary<ITypeParameterSymbol, string> TypeParameterSubstitutions { get; }\n\n        /// <summary>\n        /// Mapping of method return types to invokable base type. The code generator will create a derived type with the method arguments as fields.\n        /// </summary>\n        public IReadOnlyDictionary<INamedTypeSymbol, INamedTypeSymbol> InvokableBaseTypes => InvokableMethod.InvokableBaseTypes;\n        public InvokableMethodId InvokableKey => InvokableMethod.Key;\n        public List<(string, TypedConstant)> CustomInitializerMethods => InvokableMethod.CustomInitializerMethods;\n        public string GeneratedMethodId => InvokableMethod.GeneratedMethodId;\n        public string MethodId => InvokableMethod.MethodId;\n        public bool HasAlias => InvokableMethod.HasAlias;\n        public long? ResponseTimeoutTicks => InvokableMethod.ResponseTimeoutTicks;\n\n        public override int GetHashCode() => ProxyInterface.GetHashCode() * 17 ^ InvokableMethod.GetHashCode();\n        public bool Equals(ProxyMethodDescription other) => other is not null && InvokableMethod.Key.Equals(other.InvokableKey) && ProxyInterface.Equals(other.ProxyInterface);\n        public override bool Equals(object other) => other is ProxyMethodDescription imd && Equals(imd);\n\n        internal sealed class ConstructedGeneratedInvokableDescription : ISerializableTypeDescription\n        {\n            private TypeSyntax _typeSyntax;\n            private TypeSyntax _baseTypeSyntax;\n            private readonly GeneratedInvokableDescription _invokableDescription;\n            private readonly ProxyMethodDescription _proxyMethod;\n\n            public ConstructedGeneratedInvokableDescription(GeneratedInvokableDescription invokableDescription, ProxyMethodDescription proxyMethod)\n            {\n                _invokableDescription = invokableDescription;\n                _proxyMethod = proxyMethod;\n                Members = new List<IMemberDescription>(invokableDescription.Members.Count);\n                var proxyMethodParameters = proxyMethod.Method.Parameters;\n                foreach (var member in invokableDescription.Members.OfType<InvokableGenerator.MethodParameterFieldDescription>())\n                {\n                    Members.Add(new InvokableGenerator.MethodParameterFieldDescription(\n                        proxyMethod.CodeGenerator,\n                        proxyMethodParameters[member.ParameterOrdinal],\n                        member.FieldName,\n                        member.FieldId,\n                        proxyMethod.TypeParameterSubstitutions,\n                        member.IsSerializable));\n                }\n            }\n\n            public Accessibility Accessibility => _invokableDescription.Accessibility;\n            public TypeSyntax TypeSyntax => _typeSyntax ??= CreateTypeSyntax();\n            public TypeSyntax OpenTypeSyntax => _invokableDescription.OpenTypeSyntax;\n            public bool HasComplexBaseType => BaseType is { SpecialType: not SpecialType.System_Object };\n            public bool IncludePrimaryConstructorParameters => false;\n            public INamedTypeSymbol BaseType => _invokableDescription.BaseType;\n            public TypeSyntax BaseTypeSyntax => _baseTypeSyntax ??= BaseType.ToTypeSyntax(_proxyMethod.TypeParameterSubstitutions);\n            public string Namespace => GeneratedNamespace;\n            public string GeneratedNamespace => _invokableDescription.GeneratedNamespace;\n            public string Name => _invokableDescription.Name;\n            public bool IsValueType => _invokableDescription.IsValueType;\n            public bool IsSealedType => _invokableDescription.IsSealedType;\n            public bool IsAbstractType => _invokableDescription.IsAbstractType;\n            public bool IsEnumType => _invokableDescription.IsEnumType;\n            public bool IsGenericType => TypeParameters.Count > 0;\n            public List<IMemberDescription> Members { get; }\n            public Compilation Compilation => MethodDescription.CodeGenerator.Compilation;\n            public bool IsEmptyConstructable => ActivatorConstructorParameters is not { Count: > 0 };\n            public bool UseActivator => ActivatorConstructorParameters is { Count: > 0 };\n            public bool TrackReferences => _invokableDescription.TrackReferences;\n            public bool OmitDefaultMemberValues => _invokableDescription.OmitDefaultMemberValues;\n            public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters => _proxyMethod.TypeParameters;\n            public List<INamedTypeSymbol> SerializationHooks => _invokableDescription.SerializationHooks;\n            public bool IsShallowCopyable => _invokableDescription.IsShallowCopyable;\n            public bool IsUnsealedImmutable => _invokableDescription.IsUnsealedImmutable;\n            public bool IsImmutable => _invokableDescription.IsImmutable;\n            public bool IsExceptionType => _invokableDescription.IsExceptionType;\n            public List<TypeSyntax> ActivatorConstructorParameters => _invokableDescription.ActivatorConstructorParameters;\n            public bool HasActivatorConstructor => UseActivator;\n            public string ReturnValueInitializerMethod => _invokableDescription.ReturnValueInitializerMethod;\n\n            public InvokableMethodDescription MethodDescription => _invokableDescription.MethodDescription;\n\n            public ExpressionSyntax GetObjectCreationExpression() => ObjectCreationExpression(TypeSyntax, ArgumentList(), null);\n\n            private TypeSyntax CreateTypeSyntax()\n            {\n                var simpleName = InvokableGenerator.GetSimpleClassName(MethodDescription);\n                var subs = _proxyMethod.TypeParameterSubstitutions;\n                return (TypeParameters, Namespace) switch\n                {\n                    ({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter])))))),\n                    ({ Count: > 0 }, _) => GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(subs[p.Parameter]))))),\n                    (_, { Length: > 0 }) => QualifiedName(ParseName(Namespace), IdentifierName(simpleName)),\n                    _ => IdentifierName(simpleName),\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/SerializableTypeDescription.cs",
    "content": "using Orleans.CodeGenerator.SyntaxGeneration;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class SerializableTypeDescription : ISerializableTypeDescription\n    {\n        private readonly LibraryTypes _libraryTypes;\n        private TypeSyntax _typeSyntax;\n        private INamedTypeSymbol _baseType;\n        private TypeSyntax _baseTypeSyntax;\n\n        public SerializableTypeDescription(Compilation compilation, INamedTypeSymbol type, bool supportsPrimaryConstructorParameters, IEnumerable<IMemberDescription> members, LibraryTypes libraryTypes)\n        {\n            Type = type;\n            IncludePrimaryConstructorParameters = supportsPrimaryConstructorParameters;\n            Members = members.ToList();\n            Compilation = compilation;\n            _libraryTypes = libraryTypes;\n\n            var t = type;\n            Accessibility accessibility = t.DeclaredAccessibility;\n            while (t is not null)\n            {\n                if ((int)t.DeclaredAccessibility < (int)accessibility)\n                {\n                    accessibility = t.DeclaredAccessibility;\n                }\n\n                t = t.ContainingType;\n            }\n\n            Accessibility = accessibility;\n            TypeParameters = new();\n            var names = new HashSet<string>(StringComparer.Ordinal);\n            foreach (var tp in type.GetAllTypeParameters())\n            {\n                var tpName = GetTypeParameterName(names, tp);\n                TypeParameters.Add((tpName, tp));\n            }\n\n            SerializationHooks = new();\n            if (type.GetAttributes(libraryTypes.SerializationCallbacksAttribute, out var hookAttributes))\n            {\n                foreach (var hookAttribute in hookAttributes)\n                {\n                    var hookType = (INamedTypeSymbol)hookAttribute.ConstructorArguments[0].Value;\n                    SerializationHooks.Add(hookType);\n                }\n            }\n\n            if (TryGetActivatorConstructor(type, _libraryTypes, out var constructorParameters))\n            {\n                HasActivatorConstructor = true;\n                ActivatorConstructorParameters = constructorParameters;\n            }\n\n            static bool TryGetActivatorConstructor(INamedTypeSymbol type, LibraryTypes libraryTypes, out List<TypeSyntax> parameters)\n            {\n                parameters = null;\n                if (type.IsAbstract)\n                {\n                    return false;\n                }\n\n                foreach (var constructor in type.GetAllMembers<IMethodSymbol>())\n                {\n                    if (constructor.MethodKind != MethodKind.Constructor || constructor.DeclaredAccessibility == Accessibility.Private || constructor.IsImplicitlyDeclared)\n                    {\n                        continue;\n                    }\n\n                    if (constructor.HasAttribute(libraryTypes.GeneratedActivatorConstructorAttribute))\n                    {\n                        foreach (var parameter in constructor.Parameters)\n                        {\n                            var argumentType = parameter.Type.ToTypeSyntax();\n                            (parameters ??= new()).Add(argumentType);\n                        }\n\n                        break;\n                    }\n                }\n\n                return parameters is not null;\n            }\n\n            static string GetTypeParameterName(HashSet<string> names, ITypeParameterSymbol tp)\n            {\n                var count = 0;\n                var result = tp.Name;\n                while (names.Contains(result))\n                {\n                    result = $\"{tp.Name}_{++count}\";\n                }\n\n                names.Add(result);\n                return result.EscapeIdentifier();\n            }\n        }\n\n        private INamedTypeSymbol Type { get; }\n\n        public Accessibility Accessibility { get; }\n\n        public TypeSyntax TypeSyntax => _typeSyntax ??= Type.ToTypeSyntax();\n\n        public TypeSyntax BaseTypeSyntax => _baseTypeSyntax ??= BaseType.ToTypeSyntax();\n\n        public bool HasComplexBaseType => !IsValueType && BaseType is { SpecialType: not SpecialType.System_Object };\n\n        public bool IncludePrimaryConstructorParameters { get; }\n\n        public INamedTypeSymbol BaseType => _baseType ??= GetEffectiveBaseType();\n\n        private INamedTypeSymbol GetEffectiveBaseType()\n        {\n            var type = Type.EnumUnderlyingType ?? Type.BaseType;\n            while (type != null && type.HasAttribute(_libraryTypes.SerializerTransparentAttribute))\n                type = type.BaseType;\n            return type;\n        }\n\n        public string Namespace => Type.GetNamespaceAndNesting();\n\n        public string GeneratedNamespace => Namespace switch\n        {\n            { Length: > 0 } ns => $\"{CodeGenerator.CodeGeneratorName}.{ns}\",\n            _ => CodeGenerator.CodeGeneratorName\n        };\n\n        public string Name => Type.Name;\n\n        public bool IsValueType => Type.IsValueType;\n        public bool IsSealedType => Type.IsSealed;\n        public bool IsAbstractType => Type.IsAbstract;\n        public bool IsEnumType => Type.EnumUnderlyingType != null;\n\n        public bool IsGenericType => Type.IsGenericType;\n\n        public List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }\n\n        public List<IMemberDescription> Members { get; }\n        public Compilation Compilation { get; }\n        public List<TypeSyntax> ActivatorConstructorParameters { get; }\n\n        public bool IsEmptyConstructable\n        {\n            get\n            {\n                if (Type.Constructors.Length == 0)\n                {\n                    return true;\n                }\n\n                // Types which have required members are not empty constructable for Orleans, at least not yet.\n                var t = Type;\n                while (t != null)\n                {\n                    foreach (var member in t.GetMembers())\n                    {\n                        if (member is IPropertySymbol { IsRequired: true } or IFieldSymbol { IsRequired: true })\n                        {\n                            return false;\n                        }\n                    }\n\n                    t = t.BaseType;\n                }\n\n                foreach (var ctor in Type.Constructors)\n                {\n                    if (ctor.Parameters.Length != 0)\n                    {\n                        continue;\n                    }\n\n                    switch (ctor.DeclaredAccessibility)\n                    {\n                        case Accessibility.Public:\n                            return true;\n                    }\n                }\n\n                return false;\n            }\n        }\n\n        public bool HasActivatorConstructor { get; }\n\n        public bool UseActivator => Type.HasAttribute(_libraryTypes.UseActivatorAttribute) || !IsEmptyConstructable || HasActivatorConstructor;\n\n        public bool TrackReferences => !IsValueType && !IsExceptionType && !Type.HasAttribute(_libraryTypes.SuppressReferenceTrackingAttribute);\n        public bool OmitDefaultMemberValues => Type.HasAttribute(_libraryTypes.OmitDefaultMemberValuesAttribute);\n\n        public List<INamedTypeSymbol> SerializationHooks { get; }\n\n        public bool IsShallowCopyable => IsEnumType || !Type.HasBaseType(_libraryTypes.Exception) && _libraryTypes.IsShallowCopyable(Type);\n\n        public bool IsUnsealedImmutable => !Type.IsSealed && IsImmutable;\n\n        public bool IsImmutable => Type.HasAttribute(_libraryTypes.ImmutableAttribute);\n\n        public bool IsExceptionType => Type.HasBaseType(_libraryTypes.Exception);\n\n        public ExpressionSyntax GetObjectCreationExpression()\n        {\n            if (IsValueType)\n            {\n                return DefaultExpression(TypeSyntax);\n            }\n\n            var instanceConstructors = Type.InstanceConstructors;\n            var isConstructible = false;\n            if (!instanceConstructors.IsDefaultOrEmpty)\n            {\n                foreach (var ctor in instanceConstructors)\n                {\n                    if (ctor.Parameters.IsDefaultOrEmpty)\n                    {\n                        if (ctor.IsImplicitlyDeclared || ctor.DeclaredAccessibility is Accessibility.Public or Accessibility.Internal)\n                        {\n                            isConstructible = true;\n                        }\n\n                        break;\n                    }\n                }\n            }\n\n            if (isConstructible)\n            {\n                return ObjectCreationExpression(TypeSyntax, ArgumentList(), null);\n            }\n            else\n            {\n                return CastExpression(\n                    TypeSyntax,\n                    InvocationExpression(_libraryTypes.RuntimeHelpers.ToTypeSyntax().Member(\"GetUninitializedObject\"))\n                        .AddArgumentListArguments(\n                            Argument(TypeOfExpression(TypeSyntax))));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Model/WellKnownCodecDescription.cs",
    "content": "using Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator\n{\n    internal sealed class WellKnownCodecDescription\n    {\n        public WellKnownCodecDescription(ITypeSymbol underlyingType, INamedTypeSymbol codecType)\n        {\n            UnderlyingType = underlyingType;\n            CodecType = codecType;\n        }\n\n        public readonly ITypeSymbol UnderlyingType;\n        public readonly INamedTypeSymbol CodecType;\n    }\n\n    internal sealed class WellKnownCopierDescription : ICopierDescription\n    {\n        public WellKnownCopierDescription(ITypeSymbol underlyingType, INamedTypeSymbol codecType)\n        {\n            UnderlyingType = underlyingType;\n            CopierType = codecType;\n        }\n\n        public ITypeSymbol UnderlyingType { get; }\n\n        public INamedTypeSymbol CopierType { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Orleans.CodeGenerator.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.CodeGenerator</PackageId>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <PackageDescription>Code generation library for Orleans.Serialization</PackageDescription>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <NoPackageAnalysis>true</NoPackageAnalysis>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <DevelopmentDependency>true</DevelopmentDependency>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>\n    <IsRoslynComponent>true</IsRoslynComponent>\n    <NoWarn>$(NoWarn);RS1038;RS1042</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"AnalyzerReleases.Shipped.md\" />\n    <AdditionalFiles Include=\"AnalyzerReleases.Unshipped.md\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"$(OutputPath)\\$(AssemblyName).dll\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Analyzers\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Include=\"buildTransitive\\Microsoft.Orleans.CodeGenerator.props\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"build\\Microsoft.Orleans.CodeGenerator.props\">\n      <Pack>true</Pack>\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n    </Content>\n    <Content Include=\"buildMultiTargeting\\Microsoft.Orleans.CodeGenerator.props\">\n      <Pack>true</Pack>\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <ItemGroup>\n    <AssemblyAttribute Remove=\"Orleans.Metadata.FrameworkPartAttribute\"/>\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.CodeGenerator.Tests\"/>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/OrleansGeneratorDiagnosticAnalysisException.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing System;\n\nnamespace Orleans.CodeGenerator\n{\n    public class OrleansGeneratorDiagnosticAnalysisException : Exception\n    {\n        public OrleansGeneratorDiagnosticAnalysisException(Diagnostic diagnostic) : base(diagnostic.GetMessage())\n        {\n            Diagnostic = diagnostic;\n        }\n\n        public Diagnostic Diagnostic { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/OrleansSourceGenerator.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Text;\nusing Orleans.CodeGenerator.Diagnostics;\nusing Orleans.CodeGenerator.Model;\n\n#pragma warning disable RS1035 // Do not use APIs banned for analyzers\nnamespace Orleans.CodeGenerator\n{\n    [Generator]\n    public class OrleansSerializationSourceGenerator : ISourceGenerator\n    {\n        public void Execute(GeneratorExecutionContext context)\n        {\n            try\n            {\n                var processName = Process.GetCurrentProcess().ProcessName.ToLowerInvariant();\n                if (processName.Contains(\"devenv\") || processName.Contains(\"servicehub\"))\n                {\n                    return;\n                }\n\n                if (!Debugger.IsAttached &&\n                    context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(\"build_property.orleans_designtimebuild\", out var isDesignTimeBuild)\n                    && string.Equals(\"true\", isDesignTimeBuild, StringComparison.OrdinalIgnoreCase))\n                {\n                    return;\n                }\n\n                if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(\"build_property.orleans_attachdebugger\", out var attachDebuggerOption)\n                    && string.Equals(\"true\", attachDebuggerOption, StringComparison.OrdinalIgnoreCase))\n                {\n                    Debugger.Launch();\n                }\n\n                var options = new CodeGeneratorOptions();\n\n                if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(\"build_property.orleans_generatefieldids\", out var generateFieldIds) && generateFieldIds is { Length: > 0 })\n                {\n                    if (Enum.TryParse(generateFieldIds, out GenerateFieldIds fieldIdOption))\n                    {\n                        options.GenerateFieldIds = fieldIdOption;\n                    }\n                }\n\n                if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(\"build_property.orleansgeneratecompatibilityinvokers\", out var generateCompatInvokersValue)\n                    && bool.TryParse(generateCompatInvokersValue, out var genCompatInvokers))\n                {\n                    options.GenerateCompatibilityInvokers = genCompatInvokers;\n                }\n\n                var codeGenerator = new CodeGenerator(context.Compilation, options);\n                var syntax = codeGenerator.GenerateCode(context.CancellationToken);\n                var sourceString = syntax.NormalizeWhitespace().ToFullString();\n                var sourceText = SourceText.From(sourceString, Encoding.UTF8);\n                context.AddSource($\"{context.Compilation.AssemblyName ?? \"assembly\"}.orleans.g.cs\", sourceText);\n            }\n            catch (Exception exception)\n            {\n                if (!HandleException(context, exception))\n                {\n                    throw;\n                }\n            }\n\n            static bool HandleException(GeneratorExecutionContext context, Exception exception)\n            {\n                if (exception is OrleansGeneratorDiagnosticAnalysisException analysisException)\n                {\n                    context.ReportDiagnostic(analysisException.Diagnostic);\n                    return true;\n                }\n\n                context.ReportDiagnostic(UnhandledCodeGenerationExceptionDiagnostic.CreateDiagnostic(exception));\n                Console.WriteLine(exception);\n                Console.WriteLine(exception.StackTrace);\n                return false;\n            }\n        }\n\n        public void Initialize(GeneratorInitializationContext context)\n        {\n        }\n    }\n}\n#pragma warning restore RS1035 // Do not use APIs banned for analyzers\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Roslyn\": {\n      \"commandName\": \"DebugRoslynComponent\",\n      \"targetProject\": \"..\\\\..\\\\test\\\\Orleans.Serialization.UnitTests\\\\Orleans.Serialization.UnitTests.csproj\"\n    }\n  }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/PropertyUtility.cs",
    "content": "#nullable enable\nusing Microsoft.CodeAnalysis;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\n\nnamespace Orleans.CodeGenerator\n{\n    public static class PropertyUtility\n    {\n        private static readonly Regex PropertyMatchRegex = new(\"^<([^>]+)>.*$\", RegexOptions.Compiled);\n\n        public static IPropertySymbol? GetMatchingProperty(IFieldSymbol field)\n        {\n            if (field.ContainingType is null)\n                return null;\n            return GetMatchingProperty(field, field.ContainingType.GetMembers());\n        }\n\n        public static bool IsCompilerGenerated(this ISymbol? symbol)\n            => symbol?.GetAttributes().Any(a => a.AttributeClass?.Name == \"CompilerGeneratedAttribute\") == true;\n\n        public static bool IsCompilerGenerated(this IPropertySymbol? property)\n            => property?.GetMethod.IsCompilerGenerated() == true && property.SetMethod.IsCompilerGenerated();\n\n        public static IParameterSymbol? GetMatchingPrimaryConstructorParameter(IPropertySymbol property, IEnumerable<IParameterSymbol> constructorParameters)\n        {\n            if (!property.IsCompilerGenerated())\n                return null;\n\n            return constructorParameters.FirstOrDefault(p =>\n                string.Equals(p.Name, property.Name, StringComparison.Ordinal) &&\n                SymbolEqualityComparer.Default.Equals(p.Type, property.Type));\n        }\n\n        public static IPropertySymbol? GetMatchingProperty(IFieldSymbol field, IEnumerable<ISymbol> memberSymbols)\n        {\n            var propertyName = PropertyMatchRegex.Match(field.Name);\n            if (!propertyName.Success)\n            {\n                return null;\n            }\n\n            var name = propertyName.Groups[1].Value;\n            var candidates = memberSymbols.OfType<IPropertySymbol>()\n                .Where(property => string.Equals(name, property.Name, StringComparison.Ordinal)\n                                   && SymbolEqualityComparer.Default.Equals(field.Type, property.Type)).ToArray();\n            return candidates.Length == 1 ? candidates[0] : null;\n        }\n\n        public static IFieldSymbol? GetMatchingField(IPropertySymbol property)\n        {\n            if (property.ContainingType is null)\n                return null;\n            return GetMatchingField(property, property.ContainingType.GetMembers());\n        }\n\n        public static IFieldSymbol? GetMatchingField(IPropertySymbol property, IEnumerable<ISymbol> memberSymbols)\n        {\n            var backingFieldName = $\"<{property.Name}>k__BackingField\";\n            var candidates = (from field in memberSymbols.OfType<IFieldSymbol>()\n                where SymbolEqualityComparer.Default.Equals(field.Type, property.Type)\n                where field.Name == backingFieldName || GetCanonicalName(field.Name) == GetCanonicalName(property.Name)\n                select field).ToArray();\n            return candidates.Length == 1 ? candidates[0] : null;\n        }\n\n        public static string GetCanonicalName(string name)\n        {\n            name = name.TrimStart('_');\n            if (name.Length > 0 && char.IsUpper(name[0]))\n                name = $\"{char.ToLowerInvariant(name[0])}{name.Substring(1)}\";\n            return name;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/ProxyGenerator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.Diagnostics;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing static Orleans.CodeGenerator.CopierGenerator;\nusing static Orleans.CodeGenerator.InvokableGenerator;\nusing static Orleans.CodeGenerator.SerializerGenerator;\n\nnamespace Orleans.CodeGenerator\n{\n    /// <summary>\n    /// Generates RPC stub objects called invokers.\n    /// </summary>\n    internal class ProxyGenerator\n    {\n        private const string CopyContextPoolMemberName = \"CopyContextPool\";\n        private const string CodecProviderMemberName = \"CodecProvider\";\n        private readonly CodeGenerator _codeGenerator;\n\n        public ProxyGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        private LibraryTypes LibraryTypes => _codeGenerator.LibraryTypes;\n\n        public (ClassDeclarationSyntax, GeneratedProxyDescription) Generate(ProxyInterfaceDescription interfaceDescription)\n        {\n            var generatedClassName = GetSimpleClassName(interfaceDescription);\n\n            var fieldDescriptions = GetFieldDescriptions(interfaceDescription);\n            var fieldDeclarations = GetFieldDeclarations(fieldDescriptions);\n            var proxyMethods = CreateProxyMethods(fieldDescriptions, interfaceDescription);\n\n            var ctors = GenerateConstructors(generatedClassName, fieldDescriptions, interfaceDescription.ProxyBaseType);\n\n            var classDeclaration = ClassDeclaration(generatedClassName)\n                .AddBaseListTypes(\n                    SimpleBaseType(interfaceDescription.ProxyBaseType.ToTypeSyntax()),\n                    SimpleBaseType(interfaceDescription.InterfaceType.ToTypeSyntax()))\n                .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes())\n                .AddMembers(fieldDeclarations)\n                .AddMembers(ctors)\n                .AddMembers(proxyMethods);\n\n            var typeParameters = interfaceDescription.TypeParameters;\n            if (typeParameters.Count > 0)\n            {\n                classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, typeParameters);\n            }\n\n            return (classDeclaration, new GeneratedProxyDescription(interfaceDescription, generatedClassName));\n        }\n\n        public static string GetSimpleClassName(ProxyInterfaceDescription interfaceDescription)\n            => $\"Proxy_{SyntaxGeneration.Identifier.SanitizeIdentifierName(interfaceDescription.Name)}\";\n        \n        private List<GeneratedFieldDescription> GetFieldDescriptions(\n            ProxyInterfaceDescription interfaceDescription)\n        {\n            var fields = new List<GeneratedFieldDescription>();\n\n            // Add a copier field for any method parameter which does not have a static codec.\n            var paramCopiers = interfaceDescription.Methods\n                .Where(method => method.MethodTypeParameters.Count == 0)\n                .SelectMany(method => method.GeneratedInvokable.Members);\n            _codeGenerator.CopierGenerator.GetCopierFieldDescriptions(paramCopiers, fields);\n            return fields;\n        }\n\n        private MemberDeclarationSyntax[] GetFieldDeclarations(List<GeneratedFieldDescription> fieldDescriptions)\n        {\n            return fieldDescriptions.Select(GetFieldDeclaration).ToArray();\n\n            static MemberDeclarationSyntax GetFieldDeclaration(GeneratedFieldDescription description)\n            {\n                return FieldDeclaration(VariableDeclaration(description.FieldType, SingletonSeparatedList(VariableDeclarator(description.FieldName))))\n                    .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n            }\n        }\n\n        private MemberDeclarationSyntax[] CreateProxyMethods(\n            List<GeneratedFieldDescription> fieldDescriptions,\n            ProxyInterfaceDescription interfaceDescription)\n        {\n            var res = new List<MemberDeclarationSyntax>();\n            foreach (var methodDescription in interfaceDescription.Methods)\n            {\n                res.Add(CreateProxyMethod(methodDescription));\n            }\n            return res.ToArray();\n\n            MethodDeclarationSyntax CreateProxyMethod(ProxyMethodDescription methodDescription)\n            {\n                var (isAsync, body) = CreateAsyncProxyMethodBody(fieldDescriptions, methodDescription);\n                var method = methodDescription.Method;\n                var declaration = MethodDeclaration(method.ReturnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions), method.Name.EscapeIdentifier())\n                    .AddParameterListParameters(method.Parameters.Select((p, i) => GetParameterSyntax(i, p, methodDescription.TypeParameterSubstitutions)).ToArray())\n                    .WithBody(body);\n\n                if (isAsync)\n                {\n                    declaration = declaration.WithModifiers(TokenList(Token(SyntaxKind.AsyncKeyword)));\n                }\n\n                var explicitInterfaceSpecifier = ExplicitInterfaceSpecifier(methodDescription.Method.ContainingType.ToNameSyntax());\n                declaration = declaration.WithExplicitInterfaceSpecifier(explicitInterfaceSpecifier);\n\n                if (methodDescription.MethodTypeParameters.Count > 0)\n                {\n                    declaration = declaration.WithTypeParameterList(\n                        TypeParameterList(SeparatedList(methodDescription.MethodTypeParameters.Select(tp => TypeParameter(tp.Name)))));\n                }\n\n                return declaration;\n            }\n        }\n\n        private (bool IsAsync, BlockSyntax body) CreateAsyncProxyMethodBody(\n            List<GeneratedFieldDescription> fieldDescriptions,\n            ProxyMethodDescription methodDescription)\n        {\n            var statements = new List<StatementSyntax>();\n            var requestVar = IdentifierName(\"request\");\n            var methodSymbol = methodDescription.Method;\n            var invokable = methodDescription.GeneratedInvokable;\n            ExpressionSyntax createRequestExpr = (!invokable.IsEmptyConstructable || invokable.UseActivator) switch\n            {\n                true => InvocationExpression(ThisExpression().Member(\"GetInvokable\", invokable.TypeSyntax))\n                .WithArgumentList(ArgumentList(SeparatedList<ArgumentSyntax>())),\n                _ => ObjectCreationExpression(invokable.TypeSyntax).WithArgumentList(ArgumentList())\n            };\n\n            statements.Add(\n                LocalDeclarationStatement(\n                    VariableDeclaration(\n                        ParseTypeName(\"var\"),\n                        SingletonSeparatedList(\n                            VariableDeclarator(\n                                    Identifier(\"request\"))\n                                .WithInitializer(\n                                    EqualsValueClause(createRequestExpr))))));\n\n            var codecs = fieldDescriptions.OfType<ICopierDescription>()\n                    .Concat(_codeGenerator.LibraryTypes.StaticCopiers)\n                    .ToList();\n\n            // Set request object fields from method parameters.\n            var parameterIndex = 0;\n            var parameters = invokable.Members.OfType<MethodParameterFieldDescription>().Select(member => new SerializableMethodMember(member));\n            ExpressionSyntax copyContextPool = BaseExpression().Member(CopyContextPoolMemberName);\n            ExpressionSyntax copyContextVariable = IdentifierName(\"copyContext\");\n            var hasCopyContext = false;\n            foreach (var parameter in parameters)\n            {\n                // Only create a copy context as needed.\n                if (!hasCopyContext && !parameter.IsShallowCopyable)\n                {\n                    // C#: using var copyContext = base.CopyContext.GetContext();\n                    statements.Add(\n                            LocalDeclarationStatement(\n                                VariableDeclaration(\n                                    ParseTypeName(\"var\"),\n                                    SingletonSeparatedList(\n                                        VariableDeclarator(Identifier(\"copyContext\")).WithInitializer(\n                                            EqualsValueClause(InvocationExpression(\n                                                    copyContextPool.Member(\"GetContext\"),\n                                                    ArgumentList())))))).WithUsingKeyword(Token(SyntaxKind.UsingKeyword)));\n                    hasCopyContext = true;\n                }\n\n                var valueExpression = _codeGenerator.CopierGenerator.GenerateMemberCopy(\n                    fieldDescriptions,\n                    IdentifierName($\"arg{parameterIndex}\"),\n                    copyContextVariable,\n                    codecs,\n                    parameter);\n\n                statements.Add(\n                    ExpressionStatement(\n                        AssignmentExpression(\n                            SyntaxKind.SimpleAssignmentExpression,\n                            requestVar.Member($\"arg{parameterIndex}\"),\n                            valueExpression)));\n\n                parameterIndex++;\n            }\n\n            string invokeMethodName = default;\n            foreach (var attr in methodDescription.Method.GetAttributes())\n            {\n                if (attr.AttributeClass.GetAttributes(LibraryTypes.InvokeMethodNameAttribute, out var attrs))\n                {\n                    foreach (var methodAttr in attrs)\n                    {\n                        invokeMethodName = (string)methodAttr.ConstructorArguments.First().Value;\n                    }\n                }\n            }\n\n            var methodReturnType = methodDescription.Method.ReturnType;\n            if (methodReturnType is not INamedTypeSymbol namedMethodReturnType)\n            {\n                var diagnostic = InvalidRpcMethodReturnTypeDiagnostic.CreateDiagnostic(methodDescription.InvokableMethod);\n                throw new OrleansGeneratorDiagnosticAnalysisException(diagnostic);\n            }\n\n            ExpressionSyntax baseInvokeExpression;\n            var isVoid = methodReturnType.SpecialType is SpecialType.System_Void;\n            if (namedMethodReturnType.TypeArguments.Length == 1)\n            {\n                // Task<T> / ValueTask<T>\n                var resultType = namedMethodReturnType.TypeArguments[0];\n                baseInvokeExpression = BaseExpression().Member(\n                    invokeMethodName ?? \"InvokeAsync\",\n                    resultType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions));\n            }\n            else if (isVoid)\n            {\n                // void\n                baseInvokeExpression = BaseExpression().Member(invokeMethodName ?? \"Invoke\");\n            }\n            else\n            {\n                // Task / ValueTask\n                baseInvokeExpression = BaseExpression().Member(invokeMethodName ?? \"InvokeAsync\");\n            }\n\n            // C#: base.InvokeAsync<TReturn>(request);\n            var invocationExpression =\n                         InvocationExpression(\n                             baseInvokeExpression,\n                             ArgumentList(SeparatedList(new[] { Argument(requestVar) })));\n\n            var rt = namedMethodReturnType.ConstructedFrom;\n            bool isAsync;\n            if (SymbolEqualityComparer.Default.Equals(rt, LibraryTypes.Task_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, LibraryTypes.Task))\n            {\n                // C#: return <invocation>.AsTask()\n                statements.Add(ReturnStatement(InvocationExpression(invocationExpression.Member(\"AsTask\"), ArgumentList())));\n                isAsync = false;\n            }\n            else if (SymbolEqualityComparer.Default.Equals(rt, LibraryTypes.ValueTask_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, LibraryTypes.ValueTask))\n            {\n                // ValueTask<T> / ValueTask\n                // C#: return <invocation>\n                statements.Add(ReturnStatement(invocationExpression));\n                isAsync = false;\n            }\n            else if (invokable.ReturnValueInitializerMethod is { } returnValueInitializerMethod)\n            {\n                // C#: return request.<returnValueInitializerMethod>(this);\n                statements.Add(ReturnStatement(InvocationExpression(requestVar.Member(returnValueInitializerMethod), ArgumentList(SingletonSeparatedList(Argument(ThisExpression()))))));\n                isAsync = false;\n            }\n            else if (isVoid)\n            {\n                // C#: <invocation>\n                statements.Add(ExpressionStatement(invocationExpression));\n                isAsync = false;\n            }\n            else if (rt.Arity == 0)\n            {\n                // C#: await <invocation>\n                statements.Add(ExpressionStatement(AwaitExpression(invocationExpression)));\n                isAsync = true;\n            }\n            else\n            {\n                // C#: return await <invocation>\n                statements.Add(ReturnStatement(AwaitExpression(invocationExpression)));\n                isAsync = true;\n            }\n\n            return (isAsync, Block(statements));\n        }\n\n        private MemberDeclarationSyntax[] GenerateConstructors(\n            string simpleClassName,\n            List<GeneratedFieldDescription> fieldDescriptions,\n            INamedTypeSymbol baseType)\n        {\n            if (baseType is null)\n            {\n                return Array.Empty<MemberDeclarationSyntax>();\n            }\n\n            var bodyStatements = GetBodyStatements();\n            var res = new List<MemberDeclarationSyntax>();\n            foreach (var member in baseType.GetMembers())\n            {\n                if (member is not IMethodSymbol method)\n                {\n                    continue;\n                }\n\n                if (method.MethodKind != MethodKind.Constructor)\n                {\n                    continue;\n                }\n\n                if (method.DeclaredAccessibility == Accessibility.Private)\n                {\n                    continue;\n                }\n\n                res.Add(CreateConstructor(method));\n            }\n            return res.ToArray();\n\n            ConstructorDeclarationSyntax CreateConstructor(IMethodSymbol baseConstructor)\n            {\n                return ConstructorDeclaration(simpleClassName)\n                    .AddParameterListParameters(baseConstructor.Parameters.Select((p, i) => GetParameterSyntax(i, p, typeParameterSubstitutions: null)).ToArray())\n                    .WithModifiers(TokenList(GetModifiers(baseConstructor)))\n                    .WithInitializer(\n                        ConstructorInitializer(\n                            SyntaxKind.BaseConstructorInitializer,\n                            ArgumentList(\n                                SeparatedList(baseConstructor.Parameters.Select(GetBaseInitializerArgument)))))\n                    .WithBody(Block(bodyStatements));\n            }\n\n            static SyntaxToken[] GetModifiers(IMethodSymbol method)\n            {\n                switch (method.DeclaredAccessibility)\n                {\n                    case Accessibility.Public:\n                    case Accessibility.Protected:\n                        return new[] { Token(SyntaxKind.PublicKeyword) };\n                    case Accessibility.Internal:\n                    case Accessibility.ProtectedOrInternal:\n                    case Accessibility.ProtectedAndInternal:\n                        return new[] { Token(SyntaxKind.InternalKeyword) };\n                    default:\n                        return Array.Empty<SyntaxToken>();\n                }\n            }\n\n            static ArgumentSyntax GetBaseInitializerArgument(IParameterSymbol parameter, int index)\n            {\n                var name = $\"arg{index}\";\n                var result = Argument(IdentifierName(name));\n                switch (parameter.RefKind)\n                {\n                    case RefKind.None:\n                        break;\n                    case RefKind.Ref:\n                        result = result.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                        break;\n                    case RefKind.Out:\n                        result = result.WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword));\n                        break;\n                    default:\n                        break;\n                }\n\n                return result;\n            }\n\n            List<StatementSyntax> GetBodyStatements()\n            {\n                var res = new List<StatementSyntax>();\n                foreach (var field in fieldDescriptions)\n                {\n                    switch (field)\n                    {\n                        case GeneratedFieldDescription _ when field.IsInjected:\n                            res.Add(ExpressionStatement(\n                                AssignmentExpression(\n                                    SyntaxKind.SimpleAssignmentExpression,\n                                    ThisExpression().Member(field.FieldName.ToIdentifierName()),\n                                    Unwrapped(field.FieldName.ToIdentifierName()))));\n                            break;\n                        case CopierFieldDescription codec:\n                            {\n                                res.Add(ExpressionStatement(\n                                    AssignmentExpression(\n                                        SyntaxKind.SimpleAssignmentExpression,\n                                        field.FieldName.ToIdentifierName(),\n                                        GetService(field.FieldType))));\n                            }\n                            break;\n                    }\n                }\n                return res;\n\n                static ExpressionSyntax Unwrapped(ExpressionSyntax expr)\n                {\n                    return InvocationExpression(\n                        MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(\"OrleansGeneratedCodeHelper\"), IdentifierName(\"UnwrapService\")),\n                        ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(expr) })));\n                }\n\n                static ExpressionSyntax GetService(TypeSyntax type)\n                {\n                    return InvocationExpression(\n                        MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(\"OrleansGeneratedCodeHelper\"), GenericName(Identifier(\"GetService\"), TypeArgumentList(SingletonSeparatedList(type)))),\n                        ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(IdentifierName(CodecProviderMemberName)) })));\n                }\n            }\n        }\n\n        private ParameterSyntax GetParameterSyntax(int index, IParameterSymbol parameter, Dictionary<ITypeParameterSymbol, string> typeParameterSubstitutions)\n        {\n            var result = Parameter(Identifier($\"arg{index}\")).WithType(parameter.Type.ToTypeSyntax(typeParameterSubstitutions));\n            switch (parameter.RefKind)\n            {\n                case RefKind.None:\n                    break;\n                case RefKind.Ref:\n                    result = result.WithModifiers(TokenList(Token(SyntaxKind.RefKeyword)));\n                    break;\n                case RefKind.Out:\n                    result = result.WithModifiers(TokenList(Token(SyntaxKind.OutKeyword)));\n                    break;\n                case RefKind.In:\n                    result = result.WithModifiers(TokenList(Token(SyntaxKind.InKeyword)));\n                    break;\n                default:\n                    break;\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Orleans.CodeGenerator {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Orleans.CodeGenerator.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Serializable properties must have accessible setters. Ensure that the property has a non-private set method..\n        /// </summary>\n        internal static string InaccessibleSetterDescription {\n            get {\n                return ResourceManager.GetString(\"InaccessibleSetterDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Serializable property {0} does not have an accessible setter.\n        /// </summary>\n        internal static string InaccessibleSetterMessageFormat {\n            get {\n                return ResourceManager.GetString(\"InaccessibleSetterMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Serializable properties with bodies must be settable.\n        /// </summary>\n        internal static string InaccessibleSetterTitle {\n            get {\n                return ResourceManager.GetString(\"InaccessibleSetterTitle\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The return type of an RPC method must conform to the list of supported types, such as Task, Task&lt;T&gt;, ValueTask, and ValueTask&lt;T&gt;..\n        /// </summary>\n        internal static string InvalidRpcMethodReturnTypeDescription {\n            get {\n                return ResourceManager.GetString(\"InvalidRpcMethodReturnTypeDescription\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to The return type {0} for the RPC interface method {1} is unsupported and must be changed to one of the following types: {2}.\n        /// </summary>\n        internal static string InvalidRpcMethodReturnTypeMessageFormat {\n            get {\n                return ResourceManager.GetString(\"InvalidRpcMethodReturnTypeMessageFormat\", resourceCulture);\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized string similar to Invalid return type for RPC interface method.\n        /// </summary>\n        internal static string InvalidRpcMethodReturnTypeTitle {\n            get {\n                return ResourceManager.GetString(\"InvalidRpcMethodReturnTypeTitle\", resourceCulture);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"InaccessibleSetterDescription\" xml:space=\"preserve\">\n    <value>Serializable properties must have accessible setters. Ensure that the property has a non-private set method.</value>\n  </data>\n  <data name=\"InaccessibleSetterMessageFormat\" xml:space=\"preserve\">\n    <value>Serializable property {0} does not have an accessible setter</value>\n  </data>\n  <data name=\"InaccessibleSetterTitle\" xml:space=\"preserve\">\n    <value>Serializable properties with bodies must be settable</value>\n  </data>\n  <data name=\"InvalidRpcMethodReturnTypeDescription\" xml:space=\"preserve\">\n    <value>The return type of an RPC method must conform to the list of supported types, such as Task, Task&lt;T&gt;, ValueTask, and ValueTask&lt;T&gt;.</value>\n  </data>\n  <data name=\"InvalidRpcMethodReturnTypeMessageFormat\" xml:space=\"preserve\">\n    <value>The return type {0} for the RPC interface method {1} is unsupported and must be changed to one of the following types: {2}</value>\n  </data>\n  <data name=\"InvalidRpcMethodReturnTypeTitle\" xml:space=\"preserve\">\n    <value>Invalid return type for RPC interface method</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Orleans.CodeGenerator/SerializerGenerator.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.Diagnostics;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\nusing static Orleans.CodeGenerator.InvokableGenerator;\n\nnamespace Orleans.CodeGenerator\n{\n    internal class SerializerGenerator\n    {\n        private const string BaseTypeSerializerFieldName = \"_baseTypeSerializer\";\n        private const string ActivatorFieldName = \"_activator\";\n        private const string SerializeMethodName = \"Serialize\";\n        private const string DeserializeMethodName = \"Deserialize\";\n        private const string WriteFieldMethodName = \"WriteField\";\n        private const string ReadValueMethodName = \"ReadValue\";\n        private const string CodecFieldTypeFieldName = \"_codecFieldType\";\n        private readonly CodeGenerator _codeGenerator;\n\n        public SerializerGenerator(CodeGenerator codeGenerator)\n        {\n            _codeGenerator = codeGenerator;\n        }\n\n        private LibraryTypes LibraryTypes => _codeGenerator.LibraryTypes;\n\n        public ClassDeclarationSyntax Generate(ISerializableTypeDescription type)\n        {\n            var simpleClassName = GetSimpleClassName(type);\n\n            var members = new List<ISerializableMember>();\n            foreach (var member in type.Members)\n            {\n                if (!member.IsSerializable)\n                {\n                    continue;\n                }\n\n                if (member is ISerializableMember serializable)\n                {\n                    members.Add(serializable);\n                }\n                else if (member is IFieldDescription or IPropertyDescription)\n                {\n                    members.Add(new SerializableMember(_codeGenerator, member, members.Count));\n                }\n                else if (member is MethodParameterFieldDescription methodParameter)\n                {\n                    members.Add(new SerializableMethodMember(methodParameter));\n                }\n            }\n\n            var fieldDescriptions = GetFieldDescriptions(type, members);\n            var fieldDeclarations = GetFieldDeclarations(fieldDescriptions);\n            var ctor = GenerateConstructor(simpleClassName, fieldDescriptions);\n\n            var accessibility = type.Accessibility switch\n            {\n                Accessibility.Public => SyntaxKind.PublicKeyword,\n                _ => SyntaxKind.InternalKeyword,\n            };\n\n            var baseType = (type.IsAbstractType ? LibraryTypes.AbstractTypeSerializer : LibraryTypes.FieldCodec_1).ToTypeSyntax(type.TypeSyntax);\n\n            var classDeclaration = ClassDeclaration(simpleClassName)\n                .AddBaseListTypes(SimpleBaseType(baseType))\n                .AddModifiers(Token(accessibility), Token(SyntaxKind.SealedKeyword))\n                .AddAttributeLists(CodeGenerator.GetGeneratedCodeAttributes())\n                .AddMembers(fieldDeclarations);\n\n            if (ctor != null)\n                classDeclaration = classDeclaration.AddMembers(ctor);\n\n            if (type.IsEnumType)\n            {\n                var writeMethod = GenerateEnumWriteMethod(type);\n                var readMethod = GenerateEnumReadMethod(type);\n                classDeclaration = classDeclaration.AddMembers(writeMethod, readMethod);\n            }\n            else\n            {\n                var serializeMethod = GenerateSerializeMethod(type, fieldDescriptions, members);\n                var deserializeMethod = GenerateDeserializeMethod(type, fieldDescriptions, members);\n                if (type.IsAbstractType)\n                {\n                    if (serializeMethod != null) classDeclaration = classDeclaration.AddMembers(serializeMethod);\n                    if (deserializeMethod != null) classDeclaration = classDeclaration.AddMembers(deserializeMethod);\n                }\n                else\n                {\n                    var writeFieldMethod = GenerateCompoundTypeWriteFieldMethod(type);\n                    var readValueMethod = GenerateCompoundTypeReadValueMethod(type, fieldDescriptions);\n                    classDeclaration = classDeclaration.AddMembers(serializeMethod, deserializeMethod, writeFieldMethod, readValueMethod);\n\n                    var serializerInterface = type.IsValueType ? LibraryTypes.ValueSerializer : type.IsSealedType ? null : LibraryTypes.BaseCodec_1;\n                    if (serializerInterface != null)\n                        classDeclaration = classDeclaration.AddBaseListTypes(SimpleBaseType(serializerInterface.ToTypeSyntax(type.TypeSyntax)));\n                }\n            }\n\n            if (type.IsGenericType)\n            {\n                classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, type.TypeParameters);\n            }\n\n            return classDeclaration;\n        }\n\n        public static string GetSimpleClassName(ISerializableTypeDescription serializableType) => GetSimpleClassName(serializableType.Name);\n\n        public static string GetSimpleClassName(string name) => $\"Codec_{name}\";\n\n        public static string GetGeneratedNamespaceName(ITypeSymbol type) => type.GetNamespaceAndNesting() switch\n        {\n            { Length: > 0 } ns => $\"{CodeGenerator.CodeGeneratorName}.{ns}\",\n            _ => CodeGenerator.CodeGeneratorName\n        };\n\n        private MemberDeclarationSyntax[] GetFieldDeclarations(List<GeneratedFieldDescription> fieldDescriptions)\n        {\n            return fieldDescriptions.Select(GetFieldDeclaration).ToArray();\n\n            static MemberDeclarationSyntax GetFieldDeclaration(GeneratedFieldDescription description)\n            {\n                switch (description)\n                {\n                    case TypeFieldDescription type:\n                        return FieldDeclaration(\n                                VariableDeclaration(\n                                    type.FieldType,\n                                    SingletonSeparatedList(VariableDeclarator(type.FieldName)\n                                        .WithInitializer(EqualsValueClause(TypeOfExpression(type.UnderlyingTypeSyntax))))))\n                            .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                    case CodecFieldTypeFieldDescription type:\n                        return FieldDeclaration(\n                                VariableDeclaration(\n                                    type.FieldType,\n                                    SingletonSeparatedList(VariableDeclarator(type.FieldName)\n                                        .WithInitializer(EqualsValueClause(TypeOfExpression(type.CodecFieldType))))))\n                            .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                    case FieldAccessorDescription accessor when accessor.InitializationSyntax != null:\n                        return\n                            FieldDeclaration(VariableDeclaration(accessor.FieldType,\n                                SingletonSeparatedList(VariableDeclarator(accessor.FieldName).WithInitializer(EqualsValueClause(accessor.InitializationSyntax)))))\n                                .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                    case FieldAccessorDescription accessor when accessor.InitializationSyntax == null:\n                        //[UnsafeAccessor(UnsafeAccessorKind.Method, Name = \"set_Amount\")]\n                        //extern static void SetAmount(External instance, int value);\n                        return\n                            MethodDeclaration(\n                                PredefinedType(Token(SyntaxKind.VoidKeyword)),\n                                accessor.AccessorName)\n                                .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ExternKeyword), Token(SyntaxKind.StaticKeyword))\n                                .AddAttributeLists(AttributeList(SingletonSeparatedList(\n                                    Attribute(IdentifierName(\"System.Runtime.CompilerServices.UnsafeAccessor\"))\n                                        .AddArgumentListArguments(\n                                            AttributeArgument(\n                                                MemberAccessExpression(\n                                                        SyntaxKind.SimpleMemberAccessExpression,\n                                                        IdentifierName(\"System.Runtime.CompilerServices.UnsafeAccessorKind\"),\n                                                        IdentifierName(\"Method\"))),\n                                            AttributeArgument(\n                                                    LiteralExpression(\n                                                        SyntaxKind.StringLiteralExpression,\n                                                        Literal($\"set_{accessor.FieldName}\")))\n                                            .WithNameEquals(NameEquals(\"Name\"))))))\n                                .WithParameterList(\n                                    ParameterList(SeparatedList(new[]\n                                        {\n                                            Parameter(Identifier(\"instance\")).WithType(accessor.ContainingType),\n                                            Parameter(Identifier(\"value\")).WithType(description.FieldType)\n                                        })))\n                                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));\n                    default:\n                        return FieldDeclaration(VariableDeclaration(description.FieldType, SingletonSeparatedList(VariableDeclarator(description.FieldName))))\n                            .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword));\n                }\n            }\n        }\n\n        private ConstructorDeclarationSyntax GenerateConstructor(string simpleClassName, List<GeneratedFieldDescription> fieldDescriptions)\n        {\n            var codecProviderAdded = false;\n            var parameters = new List<ParameterSyntax>();\n            var statements = new List<StatementSyntax>();\n            foreach (var field in fieldDescriptions)\n            {\n                switch (field)\n                {\n                    case GeneratedFieldDescription _ when field.IsInjected:\n                        parameters.Add(Parameter(field.FieldName.ToIdentifier()).WithType(field.FieldType));\n                        statements.Add(ExpressionStatement(\n                            AssignmentExpression(\n                                SyntaxKind.SimpleAssignmentExpression,\n                                ThisExpression().Member(field.FieldName.ToIdentifierName()),\n                                Unwrapped(field.FieldName.ToIdentifierName()))));\n                        break;\n                    case CodecFieldDescription or BaseCodecFieldDescription when !field.IsInjected:\n                        if (!codecProviderAdded)\n                        {\n                            parameters.Add(Parameter(Identifier(\"codecProvider\")).WithType(LibraryTypes.ICodecProvider.ToTypeSyntax()));\n                            codecProviderAdded = true;\n                        }\n\n                        var codec = InvocationExpression(\n                            IdentifierName(\"OrleansGeneratedCodeHelper\").Member(GenericName(Identifier(\"GetService\"), TypeArgumentList(SingletonSeparatedList(field.FieldType)))),\n                            ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(IdentifierName(\"codecProvider\")) })));\n\n                        statements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, field.FieldName.ToIdentifierName(), codec)));\n                        break;\n                }\n            }\n\n            return statements.Count == 0 ? null : ConstructorDeclaration(simpleClassName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters.ToArray())\n                .AddBodyStatements(statements.ToArray());\n\n            static ExpressionSyntax Unwrapped(ExpressionSyntax expr)\n            {\n                return InvocationExpression(\n                    IdentifierName(\"OrleansGeneratedCodeHelper\").Member(\"UnwrapService\"),\n                    ArgumentList(SeparatedList(new[] { Argument(ThisExpression()), Argument(expr) })));\n            }\n        }\n\n        private List<GeneratedFieldDescription> GetFieldDescriptions(\n            ISerializableTypeDescription serializableTypeDescription,\n            List<ISerializableMember> members)\n        {\n            var fields = new List<GeneratedFieldDescription>();\n\n            if (!serializableTypeDescription.IsAbstractType)\n            {\n                fields.Add(new CodecFieldTypeFieldDescription(LibraryTypes.Type.ToTypeSyntax(), CodecFieldTypeFieldName, serializableTypeDescription.TypeSyntax));\n            }\n\n            if (serializableTypeDescription.HasComplexBaseType)\n            {\n                fields.Add(GetBaseTypeField(serializableTypeDescription));\n            }\n\n            if (serializableTypeDescription.UseActivator && !serializableTypeDescription.IsAbstractType)\n            {\n                fields.Add(new ActivatorFieldDescription(LibraryTypes.IActivator_1.ToTypeSyntax(serializableTypeDescription.TypeSyntax), ActivatorFieldName));\n            }\n\n            int typeIndex = 0;\n            foreach (var member in serializableTypeDescription.Members.Distinct(MemberDescriptionTypeComparer.Default))\n            {\n                if (!member.IsSerializable)\n                {\n                    continue;\n                }\n\n                // Add a codec field for any field in the target which does not have a static codec.\n                if (LibraryTypes.StaticCodecs.FindByUnderlyingType(member.Type) is not null)\n                    continue;\n\n                fields.Add(new TypeFieldDescription(LibraryTypes.Type.ToTypeSyntax(), $\"_type{typeIndex}\", member.TypeSyntax, member.Type));\n                fields.Add(GetCodecDescription(member, typeIndex));\n                typeIndex++;\n            }\n\n            foreach (var member in members)\n            {\n                if (member.GetGetterFieldDescription() is { } getterFieldDescription)\n                {\n                    fields.Add(getterFieldDescription);\n                }\n\n                if (member.GetSetterFieldDescription() is { } setterFieldDescription)\n                {\n                    fields.Add(setterFieldDescription);\n                }\n            }\n\n            for (var hookIndex = 0; hookIndex < serializableTypeDescription.SerializationHooks.Count; ++hookIndex)\n            {\n                var hookType = serializableTypeDescription.SerializationHooks[hookIndex];\n                fields.Add(new SerializationHookFieldDescription(hookType.ToTypeSyntax(), $\"_hook{hookIndex}\"));\n            }\n\n            return fields;\n\n            CodecFieldDescription GetCodecDescription(IMemberDescription member, int index)\n            {\n                var t = member.Type;\n                TypeSyntax codecType = null;\n                if (t.HasAttribute(LibraryTypes.GenerateSerializerAttribute)\n                    && (SymbolEqualityComparer.Default.Equals(t.ContainingAssembly, LibraryTypes.Compilation.Assembly) || t.ContainingAssembly.HasAttribute(LibraryTypes.TypeManifestProviderAttribute))\n                    && t is not INamedTypeSymbol { IsGenericType: true, TypeArguments.Length: 0 })\n                {\n                    // Use the concrete generated type and avoid expensive interface dispatch (except for complex nested cases that will fall back to IFieldCodec<TField>)\n                    SimpleNameSyntax name;\n                    if (t is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType)\n                    {\n                        // Construct the full generic type name\n                        name = GenericName(Identifier(GetSimpleClassName(t.Name)), TypeArgumentList(SeparatedList(namedTypeSymbol.TypeArguments.Select(arg => member.GetTypeSyntax(arg)))));\n                    }\n                    else\n                    {\n                        name = IdentifierName(GetSimpleClassName(t.Name));\n                    }\n                    codecType = QualifiedName(ParseName(GetGeneratedNamespaceName(t)), name);\n                }\n                else if (t is IArrayTypeSymbol { IsSZArray: true } array)\n                {\n                    codecType = LibraryTypes.ArrayCodec.Construct(array.ElementType).ToTypeSyntax();\n                }\n                else if (LibraryTypes.WellKnownCodecs.FindByUnderlyingType(t) is { } codec)\n                {\n                    // The codec is not a static codec and is also not a generic codec.\n                    codecType = codec.CodecType.ToTypeSyntax();\n                }\n                else if (t is INamedTypeSymbol { ConstructedFrom: { } unboundFieldType } named && LibraryTypes.WellKnownCodecs.FindByUnderlyingType(unboundFieldType) is { } genericCodec)\n                {\n                    // Construct the generic codec type using the field's type arguments.\n                    codecType = genericCodec.CodecType.Construct(named.TypeArguments.ToArray()).ToTypeSyntax();\n                }\n                else\n                {\n                    // Use the IFieldCodec<TField> interface\n                    codecType = LibraryTypes.FieldCodec_1.ToTypeSyntax(member.TypeSyntax);\n                }\n\n                return new CodecFieldDescription(codecType, $\"_codec{index}\", t);\n            }\n        }\n\n        private BaseCodecFieldDescription GetBaseTypeField(ISerializableTypeDescription serializableTypeDescription)\n        {\n            var baseType = serializableTypeDescription.BaseType;\n            if (baseType.HasAttribute(LibraryTypes.GenerateSerializerAttribute)\n                && (SymbolEqualityComparer.Default.Equals(baseType.ContainingAssembly, LibraryTypes.Compilation.Assembly) || baseType.ContainingAssembly.HasAttribute(LibraryTypes.TypeManifestProviderAttribute))\n                && baseType is not INamedTypeSymbol { IsGenericType: true })\n            {\n                // Use the concrete generated type and avoid expensive interface dispatch (except for generic types that will fall back to IBaseCodec<T>)\n                return new(QualifiedName(ParseName(GetGeneratedNamespaceName(baseType)), IdentifierName(GetSimpleClassName(baseType.Name))), true);\n            }\n\n            return new(LibraryTypes.BaseCodec_1.ToTypeSyntax(serializableTypeDescription.BaseTypeSyntax));\n        }\n\n        private MemberDeclarationSyntax GenerateSerializeMethod(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> serializerFields,\n            List<ISerializableMember> members)\n        {\n            var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword));\n\n            var writerParam = \"writer\".ToIdentifierName();\n            var instanceParam = \"instance\".ToIdentifierName();\n\n            var body = new List<StatementSyntax>();\n            if (type.HasComplexBaseType)\n            {\n                body.Add(\n                    ExpressionStatement(\n                        InvocationExpression(\n                            BaseTypeSerializerFieldName.ToIdentifierName().Member(SerializeMethodName),\n                            ArgumentList(SeparatedList(new[] { Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(instanceParam) })))));\n                body.Add(ExpressionStatement(InvocationExpression(writerParam.Member(\"WriteEndBase\"), ArgumentList())));\n            }\n\n            AddSerializationCallbacks(type, instanceParam, \"OnSerializing\", body);\n\n            // Order members according to their FieldId, since fields must be serialized in order and FieldIds are serialized as deltas.\n            var previousFieldIdVar = \"previousFieldId\".ToIdentifierName();\n            if (type.OmitDefaultMemberValues && members.Count > 0)\n            {\n                // C#: uint previousFieldId = 0;\n                body.Add(LocalDeclarationStatement(\n                    VariableDeclaration(\n                        PredefinedType(Token(SyntaxKind.UIntKeyword)),\n                        SingletonSeparatedList(VariableDeclarator(previousFieldIdVar.Identifier)\n                            .WithInitializer(EqualsValueClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0U))))))));\n            }\n\n            if (type.IncludePrimaryConstructorParameters)\n            {\n                AddSerializationMembers(type, serializerFields, members.Where(m => m.IsPrimaryConstructorParameter), writerParam, instanceParam, previousFieldIdVar, body);\n                body.Add(ExpressionStatement(InvocationExpression(writerParam.Member(\"WriteEndBase\"), ArgumentList())));\n            }\n\n            AddSerializationMembers(type, serializerFields, members.Where(m => !m.IsPrimaryConstructorParameter), writerParam, instanceParam, previousFieldIdVar, body);\n\n            AddSerializationCallbacks(type, instanceParam, \"OnSerialized\", body);\n\n            if (body.Count == 0 && type.IsAbstractType)\n                return null;\n\n            var parameters = new[]\n            {\n                Parameter(\"writer\".ToIdentifier()).WithType(LibraryTypes.Writer.ToTypeSyntax()).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(\"instance\".ToIdentifier()).WithType(type.TypeSyntax)\n            };\n\n            if (type.IsValueType)\n            {\n                parameters[1] = parameters[1].WithModifiers(LibraryTypes.HasScopedKeyword() ? TokenList(Token(SyntaxKind.ScopedKeyword), Token(SyntaxKind.RefKeyword)) : TokenList(Token(SyntaxKind.RefKeyword)));\n            }\n\n            var res = MethodDeclaration(returnType, SerializeMethodName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddTypeParameterListParameters(TypeParameter(\"TBufferWriter\"))\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n\n            res = type.IsAbstractType\n                ? res.AddModifiers(Token(SyntaxKind.OverrideKeyword))\n                : res.AddConstraintClauses(TypeParameterConstraintClause(\"TBufferWriter\").AddConstraints(TypeConstraint(LibraryTypes.IBufferWriter.ToTypeSyntax(PredefinedType(Token(SyntaxKind.ByteKeyword))))));\n\n            return res;\n        }\n\n        private void AddSerializationMembers(ISerializableTypeDescription type, List<GeneratedFieldDescription> serializerFields, IEnumerable<ISerializableMember> members, IdentifierNameSyntax writerParam, IdentifierNameSyntax instanceParam, IdentifierNameSyntax previousFieldIdVar, List<StatementSyntax> body)\n        {\n            uint previousFieldId = 0;\n            foreach (var member in members.OrderBy(m => m.Member.FieldId))\n            {\n                var description = member.Member;\n                ExpressionSyntax fieldIdDeltaExpr;\n                if (type.OmitDefaultMemberValues)\n                {\n                    // C#: <fieldId> - previousFieldId\n                    fieldIdDeltaExpr = BinaryExpression(SyntaxKind.SubtractExpression, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(description.FieldId)), previousFieldIdVar);\n                }\n                else\n                {\n                    var fieldIdDelta = description.FieldId - previousFieldId;\n                    previousFieldId = description.FieldId;\n                    fieldIdDeltaExpr = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(fieldIdDelta));\n                }\n\n                // Codecs can either be static classes or injected into the constructor.\n                // Either way, the member signatures are the same.\n                var memberType = description.Type;\n                var staticCodec = LibraryTypes.StaticCodecs.FindByUnderlyingType(memberType);\n                ExpressionSyntax codecExpression;\n                if (staticCodec != null)\n                {\n                    codecExpression = staticCodec.CodecType.ToNameSyntax();\n                }\n                else\n                {\n                    var instanceCodec = serializerFields.First(f => f is CodecFieldDescription cf && SymbolEqualityComparer.Default.Equals(cf.UnderlyingType, memberType));\n                    codecExpression = IdentifierName(instanceCodec.FieldName);\n                }\n\n               // When a static codec is available, we can call it directly and can skip passing the expected type,\n               // since it is known to be the static codec's field type:\n               //   C#: <staticCodec>.WriteField(ref writer, <fieldIdDelta, <member>)\n               // When no static codec is available:\n               //   C#: <codecField>.WriteField(ref writer, <fieldIdDelta>, <expectedType>, <member>)\n                var writeFieldArgs = new List<ArgumentSyntax> {\n                    Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                    Argument(fieldIdDeltaExpr)\n                };\n\n                if (staticCodec is null)\n                    writeFieldArgs.Add(Argument(serializerFields.First(f => f is TypeFieldDescription tf && SymbolEqualityComparer.Default.Equals(tf.UnderlyingType, memberType)).FieldName.ToIdentifierName()));\n\n                writeFieldArgs.Add(Argument(member.GetGetter(instanceParam)));\n\n                var writeFieldExpr = ExpressionStatement(InvocationExpression(codecExpression.Member(\"WriteField\"), ArgumentList(SeparatedList(writeFieldArgs))));\n\n                if (!type.OmitDefaultMemberValues)\n                {\n                    body.Add(writeFieldExpr);\n                }\n                else\n                {\n                    ExpressionSyntax condition = member.IsValueType switch\n                    {\n                        true => BinaryExpression(SyntaxKind.NotEqualsExpression, member.GetGetter(instanceParam), LiteralExpression(SyntaxKind.DefaultLiteralExpression)),\n                        false => IsPatternExpression(member.GetGetter(instanceParam), TypePattern(PredefinedType(Token(SyntaxKind.ObjectKeyword))))\n                    };\n\n                    body.Add(IfStatement(\n                        condition,\n                        Block(\n                            writeFieldExpr,\n                            ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, previousFieldIdVar, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(description.FieldId)))))));\n                }\n            }\n        }\n\n        private MemberDeclarationSyntax GenerateDeserializeMethod(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> serializerFields,\n            List<ISerializableMember> members)\n        {\n            var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword));\n\n            var readerParam = \"reader\".ToIdentifierName();\n            var instanceParam = \"instance\".ToIdentifierName();\n            var idVar = \"id\".ToIdentifierName();\n            var headerVar = \"header\".ToIdentifierName();\n\n            var body = new List<StatementSyntax>();\n\n            if (type.HasComplexBaseType)\n            {\n                // C#: _baseTypeSerializer.Deserialize(ref reader, instance);\n                body.Add(\n                    ExpressionStatement(\n                        InvocationExpression(\n                            BaseTypeSerializerFieldName.ToIdentifierName().Member(DeserializeMethodName),\n                            ArgumentList(SeparatedList(new[]\n                            {\n                                Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                Argument(instanceParam)\n                            })))));\n            }\n\n            AddSerializationCallbacks(type, instanceParam, \"OnDeserializing\", body);\n\n            int emptyBodyCount;\n            var nonCtorMembers = type.IncludePrimaryConstructorParameters ? members.FindAll(static m => !m.IsPrimaryConstructorParameter) : members;\n            if ((members.Count == 0 || nonCtorMembers.Count == 0) && !type.IncludePrimaryConstructorParameters)\n            {\n                // C#: reader.ConsumeEndBaseOrEndObject();\n                body.Add(ExpressionStatement(InvocationExpression(readerParam.Member(\"ConsumeEndBaseOrEndObject\"))));\n                emptyBodyCount = 1;\n            }\n            else\n            {\n                // C#: uint id = 0;\n                if (members.Count > 0)\n                {\n                    body.Add(LocalDeclarationStatement(\n                        VariableDeclaration(\n                            PredefinedType(Token(SyntaxKind.UIntKeyword)),\n                            SingletonSeparatedList(VariableDeclarator(idVar.Identifier, null, EqualsValueClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0U))))))));\n                }\n\n                // C#: Field header = default;\n                body.Add(LocalDeclarationStatement(\n                    VariableDeclaration(\n                        LibraryTypes.Field.ToTypeSyntax(),\n                        SingletonSeparatedList(VariableDeclarator(headerVar.Identifier, null, EqualsValueClause(LiteralExpression(SyntaxKind.DefaultLiteralExpression)))))));\n\n                emptyBodyCount = 2;\n\n                if (type.IncludePrimaryConstructorParameters)\n                {\n                    var constructorParameterMembers = members.FindAll(m => m.IsPrimaryConstructorParameter);\n                    body.Add(GetDeserializerLoop(constructorParameterMembers));\n                    if (members.Count > 0)\n                    {\n                        body.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, idVar, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0U)))));\n                    }\n\n                    body.Add(IfStatement(headerVar.Member(\"IsEndBaseFields\"), GetDeserializerLoop(nonCtorMembers)));\n                }\n                else\n                {\n                    body.Add(GetDeserializerLoop(nonCtorMembers));\n                }\n            }\n\n            AddSerializationCallbacks(type, instanceParam, \"OnDeserialized\", body);\n\n            if (body.Count == emptyBodyCount && type.IsAbstractType)\n                return null;\n\n            var genericParam = ParseTypeName(\"TReaderInput\");\n            var parameters = new[]\n            {\n                Parameter(readerParam.Identifier).WithType(LibraryTypes.Reader.ToTypeSyntax(genericParam)).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(instanceParam.Identifier).WithType(type.TypeSyntax)\n            };\n\n            if (type.IsValueType)\n            {\n                parameters[1] = parameters[1].WithModifiers(LibraryTypes.HasScopedKeyword() ? TokenList(Token(SyntaxKind.ScopedKeyword), Token(SyntaxKind.RefKeyword)) : TokenList(Token(SyntaxKind.RefKeyword)));\n            }\n\n            var res = MethodDeclaration(returnType, DeserializeMethodName)\n                .AddTypeParameterListParameters(TypeParameter(\"TReaderInput\"))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n\n            if (type.IsAbstractType)\n                res = res.AddModifiers(Token(SyntaxKind.OverrideKeyword));\n\n            return res;\n\n            // Create the loop body.\n            StatementSyntax GetDeserializerLoop(List<ISerializableMember> members)\n            {\n                var refHeaderVar = ArgumentList(SingletonSeparatedList(Argument(null, Token(SyntaxKind.RefKeyword), headerVar)));\n                if (members.Count == 0)\n                {\n                    // C#: reader.ReadFieldHeader(ref header);\n                    // C#: reader.ConsumeEndBaseOrEndObject(ref header);\n                    return Block(\n                        ExpressionStatement(InvocationExpression(readerParam.Member(\"ReadFieldHeader\"), refHeaderVar)),\n                        ExpressionStatement(InvocationExpression(readerParam.Member(\"ConsumeEndBaseOrEndObject\"), refHeaderVar)));\n                }\n\n                var loopBody = new List<StatementSyntax>();\n\n                // C#: reader.ReadFieldHeader(ref header);\n                // C#: if (header.IsEndBaseOrEndObject) break;\n                // C#: id += header.FieldIdDelta;\n                var readFieldHeader = ExpressionStatement(InvocationExpression(readerParam.Member(\"ReadFieldHeader\"), refHeaderVar));\n                var endObjectCheck = IfStatement(headerVar.Member(\"IsEndBaseOrEndObject\"), BreakStatement());\n                var idUpdate = ExpressionStatement(AssignmentExpression(SyntaxKind.AddAssignmentExpression, idVar, headerVar.Member(\"FieldIdDelta\")));\n                loopBody.Add(readFieldHeader);\n                loopBody.Add(endObjectCheck);\n                loopBody.Add(idUpdate);\n\n                members.Sort((x, y) => x.Member.FieldId.CompareTo(y.Member.FieldId));\n                var contiguousIds = members[members.Count - 1].Member.FieldId == members.Count - 1;\n                foreach (var member in members)\n                {\n                    var description = member.Member;\n\n                    // C#: instance.<member> = <codec>.ReadValue(ref reader, header);\n                    // Codecs can either be static classes or injected into the constructor.\n                    // Either way, the member signatures are the same.\n                    ExpressionSyntax codecExpression;\n                    if (LibraryTypes.StaticCodecs.FindByUnderlyingType(description.Type) is { } staticCodec)\n                    {\n                        codecExpression = staticCodec.CodecType.ToNameSyntax();\n                    }\n                    else\n                    {\n                        var instanceCodec = serializerFields.Find(c => c is CodecFieldDescription f && SymbolEqualityComparer.Default.Equals(f.UnderlyingType, description.Type));\n                        codecExpression = IdentifierName(instanceCodec.FieldName);\n                    }\n\n                    ExpressionSyntax readValueExpression = InvocationExpression(\n                        codecExpression.Member(\"ReadValue\"),\n                        ArgumentList(SeparatedList(new[] { Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(headerVar) })));\n\n                    var memberAssignment = ExpressionStatement(member.GetSetter(instanceParam, readValueExpression));\n\n                    BlockSyntax ifBody;\n                    if (member != members[members.Count - 1])\n                    {\n                        ifBody = Block(memberAssignment, readFieldHeader, endObjectCheck, idUpdate);\n                    }\n                    else if (contiguousIds)\n                    {\n                        ifBody = Block(memberAssignment, readFieldHeader);\n                    }\n                    else\n                    {\n                        idUpdate = ExpressionStatement(PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, idVar));\n                        ifBody = Block(memberAssignment, readFieldHeader, endObjectCheck, idUpdate);\n                    }\n\n                    // C#: if (id == <fieldId>) { ... }\n                    var ifStatement = IfStatement(BinaryExpression(SyntaxKind.EqualsExpression, idVar, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(description.FieldId))),\n                        ifBody);\n\n                    loopBody.Add(ifStatement);\n                }\n\n                // Consume any unknown fields\n                if (contiguousIds)\n                {\n                    // C#: reader.ConsumeEndBaseOrEndObject(ref header); break;\n                    loopBody.Add(ExpressionStatement(InvocationExpression(readerParam.Member(\"ConsumeEndBaseOrEndObject\"), refHeaderVar)));\n                    loopBody.Add(BreakStatement());\n                }\n                else\n                {\n                    // C#: reader.ConsumeUnknownField(ref header);\n                    loopBody.Add(ExpressionStatement(InvocationExpression(readerParam.Member(\"ConsumeUnknownField\"), refHeaderVar)));\n                }\n\n                return WhileStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression), Block(loopBody));\n            }\n        }\n\n        private void AddSerializationCallbacks(ISerializableTypeDescription type, IdentifierNameSyntax instanceParam, string callbackMethodName, List<StatementSyntax> body)\n        {\n            for (var hookIndex = 0; hookIndex < type.SerializationHooks.Count; ++hookIndex)\n            {\n                var hookType = type.SerializationHooks[hookIndex];\n                var member = hookType.GetAllMembers<IMethodSymbol>(callbackMethodName, Accessibility.Public).FirstOrDefault();\n                if (member is null || member.Parameters.Length != 1)\n                {\n                    continue;\n                }\n\n                var argument = Argument(instanceParam);\n                if (member.Parameters[0].RefKind == RefKind.Ref)\n                {\n                    argument = argument.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                }\n\n                body.Add(ExpressionStatement(InvocationExpression(\n                    IdentifierName($\"_hook{hookIndex}\").Member(callbackMethodName),\n                    ArgumentList(SeparatedList(new[] { argument })))));\n            }\n        }\n\n        private MemberDeclarationSyntax GenerateCompoundTypeWriteFieldMethod(\n            ISerializableTypeDescription type)\n        {\n            var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword));\n\n            var writerParam = \"writer\".ToIdentifierName();\n            var fieldIdDeltaParam = \"fieldIdDelta\".ToIdentifierName();\n            var expectedTypeParam = \"expectedType\".ToIdentifierName();\n            var valueParam = \"value\".ToIdentifierName();\n\n            var innerBody = new List<StatementSyntax>();\n\n            if (type.IsValueType)\n            {\n                // C#: ReferenceCodec.MarkValueField(reader.Session);\n                innerBody.Add(ExpressionStatement(InvocationExpression(IdentifierName(\"ReferenceCodec\").Member(\"MarkValueField\"), ArgumentList(SingletonSeparatedList(Argument(writerParam.Member(\"Session\")))))));\n            }\n            else\n            {\n                if (type.TrackReferences)\n                {\n                    // C#: if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value)) return;\n                    innerBody.Add(\n                        IfStatement(\n                            InvocationExpression(\n                                IdentifierName(\"ReferenceCodec\").Member(\"TryWriteReferenceField\"),\n                                ArgumentList(SeparatedList(new[]\n                                {\n                            Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                            Argument(fieldIdDeltaParam),\n                            Argument(expectedTypeParam),\n                            Argument(valueParam)\n                                }))),\n                            ReturnStatement())\n                    );\n                }\n                else\n                {\n                    // C#: if (value is null) { ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta); return; }\n                    innerBody.Add(\n                        IfStatement(\n                            IsPatternExpression(valueParam, ConstantPattern(LiteralExpression(SyntaxKind.NullLiteralExpression))),\n                            Block(\n                                ExpressionStatement(InvocationExpression(IdentifierName(\"ReferenceCodec\").Member(\"WriteNullReference\"),\n                                    ArgumentList(SeparatedList(new[]\n                                    {\n                                        Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                        Argument(fieldIdDeltaParam)\n                                    })))),\n                                ReturnStatement()))\n                    );\n\n                    // C#: ReferenceCodec.MarkValueField(reader.Session);\n                    innerBody.Add(ExpressionStatement(InvocationExpression(IdentifierName(\"ReferenceCodec\").Member(\"MarkValueField\"), ArgumentList(SingletonSeparatedList(Argument(writerParam.Member(\"Session\")))))));\n                }\n            }\n\n            // C#: writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            innerBody.Add(\n                ExpressionStatement(InvocationExpression(writerParam.Member(\"WriteStartObject\"),\n                ArgumentList(SeparatedList(new[]{\n                            Argument(fieldIdDeltaParam),\n                            Argument(expectedTypeParam),\n                            Argument(IdentifierName(CodecFieldTypeFieldName))\n                    })))\n                ));\n\n            // C#: this.Serialize(ref writer, [ref] value);\n            var valueParamArgument = type.IsValueType switch\n            {\n                true => Argument(valueParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                false => Argument(valueParam)\n            };\n\n            innerBody.Add(\n                ExpressionStatement(\n                    InvocationExpression(\n                        IdentifierName(SerializeMethodName),\n                        ArgumentList(\n                            SeparatedList(\n                                new[]\n                                {\n                                    Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                    valueParamArgument\n                                })))));\n\n            // C#: writer.WriteEndObject();\n            innerBody.Add(ExpressionStatement(InvocationExpression(writerParam.Member(\"WriteEndObject\"))));\n\n            List<StatementSyntax> body;\n            if (type.IsSealedType)\n            {\n                body = innerBody;\n            }\n            else\n            {\n                // For types which are not sealed/value types, add some extra logic to support sub-types:\n                body = new()\n                {\n                    // C#: if (value is null || value.GetType() == typeof(TField)) { <inner body> }\n                    // C#: else writer.SerializeUnexpectedType(fieldIdDelta, expectedType, value);\n                    IfStatement(\n                        BinaryExpression(SyntaxKind.LogicalOrExpression,\n                            IsPatternExpression(valueParam, ConstantPattern(LiteralExpression(SyntaxKind.NullLiteralExpression))),\n                            BinaryExpression(SyntaxKind.EqualsExpression, InvocationExpression(valueParam.Member(\"GetType\")), TypeOfExpression(type.TypeSyntax))),\n                        Block(innerBody),\n                        ElseClause(ExpressionStatement(\n                            InvocationExpression(\n                                writerParam.Member(\"SerializeUnexpectedType\"),\n                                ArgumentList(\n                                    SeparatedList(new [] {\n                                        Argument(fieldIdDeltaParam),\n                                        Argument(expectedTypeParam),\n                                        Argument(valueParam)\n                                    })))\n                        )))\n                };\n            }\n\n            var parameters = new[]\n            {\n                Parameter(\"writer\".ToIdentifier()).WithType(LibraryTypes.Writer.ToTypeSyntax()).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(\"fieldIdDelta\".ToIdentifier()).WithType(PredefinedType(Token(SyntaxKind.UIntKeyword))),\n                Parameter(\"expectedType\".ToIdentifier()).WithType(LibraryTypes.Type.ToTypeSyntax()),\n                Parameter(\"value\".ToIdentifier()).WithType(type.TypeSyntax)\n            };\n\n            return MethodDeclaration(returnType, WriteFieldMethodName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddTypeParameterListParameters(TypeParameter(\"TBufferWriter\"))\n                .AddConstraintClauses(TypeParameterConstraintClause(\"TBufferWriter\").AddConstraints(TypeConstraint(LibraryTypes.IBufferWriter.ToTypeSyntax(PredefinedType(Token(SyntaxKind.ByteKeyword))))))\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n        }\n\n        private MemberDeclarationSyntax GenerateCompoundTypeReadValueMethod(\n            ISerializableTypeDescription type,\n            List<GeneratedFieldDescription> serializerFields)\n        {\n            var readerParam = \"reader\".ToIdentifierName();\n            var fieldParam = \"field\".ToIdentifierName();\n            var resultVar = \"result\".ToIdentifierName();\n            var readerInputTypeParam = ParseTypeName(\"TReaderInput\");\n\n            var body = new List<StatementSyntax>();\n            var innerBody = type.IsSealedType ? body : new List<StatementSyntax>();\n\n            if (!type.IsValueType)\n            {\n                // C#: if (field.IsReference) return ReferenceCodec.ReadReference<TField, TReaderInput>(ref reader, field);\n                body.Add(\n                    IfStatement(\n                        fieldParam.Member(\"IsReference\"),\n                        ReturnStatement(InvocationExpression(\n                            IdentifierName(\"ReferenceCodec\").Member(\"ReadReference\", new[] { type.TypeSyntax, readerInputTypeParam }),\n                            ArgumentList(SeparatedList(new[]\n                            {\n                                Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                Argument(fieldParam),\n                            })))))\n                    );\n            }\n\n            // C#: field.EnsureWireTypeTagDelimited();\n            body.Add(ExpressionStatement(InvocationExpression(fieldParam.Member(\"EnsureWireTypeTagDelimited\"))));\n\n            ExpressionSyntax createValueExpression = type.UseActivator switch\n            {\n                true => InvocationExpression(serializerFields.OfType<ActivatorFieldDescription>().Single().FieldName.ToIdentifierName().Member(\"Create\")),\n                false => type.GetObjectCreationExpression()\n            };\n\n            // C#: var result = _activator.Create();\n            // or C#: var result = new TField();\n            // or C#: var result = default(TField);\n            innerBody.Add(LocalDeclarationStatement(\n                VariableDeclaration(\n                    IdentifierName(\"var\"),\n                    SingletonSeparatedList(VariableDeclarator(resultVar.Identifier)\n                    .WithInitializer(EqualsValueClause(createValueExpression))))));\n\n            if (type.TrackReferences)\n            {\n                // C#: ReferenceCodec.RecordObject(reader.Session, result);\n                innerBody.Add(ExpressionStatement(InvocationExpression(IdentifierName(\"ReferenceCodec\").Member(\"RecordObject\"), ArgumentList(SeparatedList(new[] { Argument(readerParam.Member(\"Session\")), Argument(resultVar) })))));\n            }\n            else\n            {\n                // C#: ReferenceCodec.MarkValueField(reader.Session);\n                innerBody.Add(ExpressionStatement(InvocationExpression(IdentifierName(\"ReferenceCodec\").Member(\"MarkValueField\"), ArgumentList(SingletonSeparatedList(Argument(readerParam.Member(\"Session\")))))));\n            }\n\n            // C#: this.Deserializer(ref reader, [ref] result);\n            var resultArgument = type.IsValueType switch\n            {\n                true => Argument(resultVar).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                false => Argument(resultVar)\n            };\n            innerBody.Add(\n                ExpressionStatement(\n                    InvocationExpression(\n                        IdentifierName(DeserializeMethodName),\n                        ArgumentList(\n                            SeparatedList(\n                                new[]\n                                {\n                                    Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                    resultArgument\n                                })))));\n\n            innerBody.Add(ReturnStatement(resultVar));\n\n            if (!type.IsSealedType)\n            {\n                // C#: var fieldType = field.FieldType;\n                var valueTypeField = \"valueType\".ToIdentifierName();\n                body.Add(\n                    LocalDeclarationStatement(\n                        VariableDeclaration(\n                            LibraryTypes.Type.ToTypeSyntax(),\n                            SingletonSeparatedList(VariableDeclarator(valueTypeField.Identifier)\n                                .WithInitializer(EqualsValueClause(fieldParam.Member(\"FieldType\")))))));\n                body.Add(\n                    IfStatement(\n                        BinaryExpression(SyntaxKind.LogicalOrExpression,\n                        IsPatternExpression(valueTypeField, ConstantPattern(LiteralExpression(SyntaxKind.NullLiteralExpression))),\n                        BinaryExpression(SyntaxKind.EqualsExpression, valueTypeField, IdentifierName(CodecFieldTypeFieldName))),\n                        Block(innerBody)));\n\n                body.Add(ReturnStatement(\n                                InvocationExpression(\n                                    readerParam.Member(\"DeserializeUnexpectedType\", new[] { readerInputTypeParam, type.TypeSyntax }),\n                                    ArgumentList(\n                                        SingletonSeparatedList(Argument(null, Token(SyntaxKind.RefKeyword), fieldParam))))));\n            }\n\n            var parameters = new[]\n            {\n                Parameter(readerParam.Identifier).WithType(LibraryTypes.Reader.ToTypeSyntax(readerInputTypeParam)).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(fieldParam.Identifier).WithType(LibraryTypes.Field.ToTypeSyntax())\n            };\n\n            return MethodDeclaration(type.TypeSyntax, ReadValueMethodName)\n                .AddTypeParameterListParameters(TypeParameter(\"TReaderInput\"))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n        }\n\n        private MemberDeclarationSyntax GenerateEnumWriteMethod(\n            ISerializableTypeDescription type)\n        {\n            var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword));\n\n            var writerParam = \"writer\".ToIdentifierName();\n            var fieldIdDeltaParam = \"fieldIdDelta\".ToIdentifierName();\n            var expectedTypeParam = \"expectedType\".ToIdentifierName();\n            var valueParam = \"value\".ToIdentifierName();\n\n            var body = new List<StatementSyntax>();\n\n            // Codecs can either be static classes or injected into the constructor.\n            // Either way, the member signatures are the same.\n            var staticCodec = LibraryTypes.StaticCodecs.FindByUnderlyingType(type.BaseType);\n            var codecExpression = staticCodec.CodecType.ToNameSyntax();\n\n            body.Add(\n                ExpressionStatement(\n                    InvocationExpression(\n                        codecExpression.Member(\"WriteField\"),\n                        ArgumentList(\n                            SeparatedList(\n                                new[]\n                                {\n                                    Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),\n                                    Argument(fieldIdDeltaParam),\n                                    Argument(expectedTypeParam),\n                                    Argument(CastExpression(type.BaseTypeSyntax, valueParam)),\n                                    Argument(IdentifierName(CodecFieldTypeFieldName))\n                                })))));\n\n            var parameters = new[]\n            {\n                Parameter(\"writer\".ToIdentifier()).WithType(LibraryTypes.Writer.ToTypeSyntax()).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(\"fieldIdDelta\".ToIdentifier()).WithType(PredefinedType(Token(SyntaxKind.UIntKeyword))),\n                Parameter(\"expectedType\".ToIdentifier()).WithType(LibraryTypes.Type.ToTypeSyntax()),\n                Parameter(\"value\".ToIdentifier()).WithType(type.TypeSyntax)\n            };\n\n            return MethodDeclaration(returnType, WriteFieldMethodName)\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddTypeParameterListParameters(TypeParameter(\"TBufferWriter\"))\n                .AddConstraintClauses(TypeParameterConstraintClause(\"TBufferWriter\").AddConstraints(TypeConstraint(LibraryTypes.IBufferWriter.ToTypeSyntax(PredefinedType(Token(SyntaxKind.ByteKeyword))))))\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n        }\n\n        private MemberDeclarationSyntax GenerateEnumReadMethod(\n            ISerializableTypeDescription type)\n        {\n            var readerParam = \"reader\".ToIdentifierName();\n            var fieldParam = \"field\".ToIdentifierName();\n\n            var staticCodec = LibraryTypes.StaticCodecs.FindByUnderlyingType(type.BaseType);\n            ExpressionSyntax codecExpression = staticCodec.CodecType.ToNameSyntax();\n            ExpressionSyntax readValueExpression = InvocationExpression(\n                codecExpression.Member(\"ReadValue\"),\n                ArgumentList(SeparatedList(new[] { Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(fieldParam) })));\n\n            readValueExpression = CastExpression(type.TypeSyntax, readValueExpression);\n            var body = new List<StatementSyntax>\n            {\n                ReturnStatement(readValueExpression)\n            };\n\n            var genericParam = ParseTypeName(\"TReaderInput\");\n            var parameters = new[]\n            {\n                Parameter(readerParam.Identifier).WithType(LibraryTypes.Reader.ToTypeSyntax(genericParam)).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))),\n                Parameter(fieldParam.Identifier).WithType(LibraryTypes.Field.ToTypeSyntax())\n            };\n\n            return MethodDeclaration(type.TypeSyntax, ReadValueMethodName)\n                .AddTypeParameterListParameters(TypeParameter(\"TReaderInput\"))\n                .AddModifiers(Token(SyntaxKind.PublicKeyword))\n                .AddParameterListParameters(parameters)\n                .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetMethodImplAttributeSyntax())))\n                .AddBodyStatements(body.ToArray());\n        }\n\n        internal abstract class GeneratedFieldDescription\n        {\n            protected GeneratedFieldDescription(TypeSyntax fieldType, string fieldName)\n            {\n                FieldType = fieldType;\n                FieldName = fieldName;\n            }\n\n            public readonly TypeSyntax FieldType;\n            public readonly string FieldName;\n            public abstract bool IsInjected { get; }\n        }\n\n        internal sealed class BaseCodecFieldDescription : GeneratedFieldDescription\n        {\n            public BaseCodecFieldDescription(TypeSyntax fieldType, bool concreteType = false) : base(fieldType, BaseTypeSerializerFieldName)\n                => IsInjected = !concreteType;\n\n            public override bool IsInjected { get; }\n        }\n\n        internal sealed class ActivatorFieldDescription : GeneratedFieldDescription\n        {\n            public ActivatorFieldDescription(TypeSyntax fieldType, string fieldName) : base(fieldType, fieldName)\n            {\n            }\n\n            public override bool IsInjected => true;\n        }\n\n        internal sealed class CodecFieldDescription : GeneratedFieldDescription\n        {\n            public CodecFieldDescription(TypeSyntax fieldType, string fieldName, ITypeSymbol underlyingType) : base(fieldType, fieldName)\n            {\n                UnderlyingType = underlyingType;\n            }\n\n            public ITypeSymbol UnderlyingType { get; }\n            public override bool IsInjected => false;\n        }\n\n        internal sealed class TypeFieldDescription : GeneratedFieldDescription\n        {\n            public TypeFieldDescription(TypeSyntax fieldType, string fieldName, TypeSyntax underlyingTypeSyntax, ITypeSymbol underlyingType) : base(fieldType, fieldName)\n            {\n                UnderlyingType = underlyingType;\n                UnderlyingTypeSyntax = underlyingTypeSyntax;\n            }\n\n            public TypeSyntax UnderlyingTypeSyntax { get; }\n            public ITypeSymbol UnderlyingType { get; }\n            public override bool IsInjected => false;\n        }\n\n        internal sealed class CodecFieldTypeFieldDescription : GeneratedFieldDescription\n        {\n            public CodecFieldTypeFieldDescription(TypeSyntax fieldType, string fieldName, TypeSyntax codecFieldType) : base(fieldType, fieldName)\n            {\n                CodecFieldType = codecFieldType;\n            }\n\n            public TypeSyntax CodecFieldType { get; }\n            public override bool IsInjected => false;\n        }\n\n        internal sealed class FieldAccessorDescription : GeneratedFieldDescription\n        {\n            public FieldAccessorDescription(TypeSyntax containingType, TypeSyntax fieldType, string fieldName, string accessorName, ExpressionSyntax initializationSyntax = null) : base(fieldType, fieldName)\n            {\n                ContainingType = containingType;\n                AccessorName = accessorName;\n                InitializationSyntax = initializationSyntax;\n            }\n\n            public override bool IsInjected => false;\n            public readonly string AccessorName;\n            public readonly TypeSyntax ContainingType;\n            public readonly ExpressionSyntax InitializationSyntax;\n        }\n\n        internal sealed class SerializationHookFieldDescription : GeneratedFieldDescription\n        {\n            public SerializationHookFieldDescription(TypeSyntax fieldType, string fieldName) : base(fieldType, fieldName)\n            {\n            }\n\n            public override bool IsInjected => true;\n        }\n\n        internal interface ISerializableMember\n        {\n            bool IsShallowCopyable { get; }\n            bool IsValueType { get; }\n            bool IsPrimaryConstructorParameter { get; }\n\n            IMemberDescription Member { get; }\n\n            /// <summary>\n            /// Gets syntax representing the type of this field.\n            /// </summary>\n            TypeSyntax TypeSyntax { get; }\n\n            /// <summary>\n            /// Returns syntax for retrieving the value of this field, deep copying it if necessary.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <returns>Syntax for retrieving the value of this field.</returns>\n            ExpressionSyntax GetGetter(ExpressionSyntax instance);\n\n            /// <summary>\n            /// Returns syntax for setting the value of this field.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <param name=\"value\">Syntax for the new value.</param>\n            /// <returns>Syntax for setting the value of this field.</returns>\n            ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value);\n\n            FieldAccessorDescription GetGetterFieldDescription();\n            FieldAccessorDescription GetSetterFieldDescription();\n        }\n\n        /// <summary>\n        /// Represents a serializable member (field/property) of a type.\n        /// </summary>\n        internal class SerializableMethodMember : ISerializableMember\n        {\n            private readonly MethodParameterFieldDescription _member;\n\n            public SerializableMethodMember(MethodParameterFieldDescription member)\n            {\n                _member = member;\n            }\n\n            IMemberDescription ISerializableMember.Member => _member;\n            public MethodParameterFieldDescription Member => _member;\n\n            private LibraryTypes LibraryTypes => _member.CodeGenerator.LibraryTypes;\n\n            public bool IsShallowCopyable => LibraryTypes.IsShallowCopyable(_member.Parameter.Type) || _member.Parameter.HasAttribute(LibraryTypes.ImmutableAttribute);\n\n            /// <summary>\n            /// Gets syntax representing the type of this field.\n            /// </summary>\n            public TypeSyntax TypeSyntax => _member.TypeSyntax;\n\n            public bool IsValueType => _member.Type.IsValueType;\n\n            public bool IsPrimaryConstructorParameter => _member.IsPrimaryConstructorParameter;\n\n            /// <summary>\n            /// Returns syntax for retrieving the value of this field, deep copying it if necessary.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <returns>Syntax for retrieving the value of this field.</returns>\n            public ExpressionSyntax GetGetter(ExpressionSyntax instance) => instance.Member(_member.FieldName);\n\n            /// <summary>\n            /// Returns syntax for setting the value of this field.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <param name=\"value\">Syntax for the new value.</param>\n            /// <returns>Syntax for setting the value of this field.</returns>\n            public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value) => AssignmentExpression(\n                        SyntaxKind.SimpleAssignmentExpression,\n                        instance.Member(_member.FieldName),\n                        value);\n\n            public FieldAccessorDescription GetGetterFieldDescription() => null;\n            public FieldAccessorDescription GetSetterFieldDescription() => null;\n        }\n\n        /// <summary>\n        /// Represents a serializable member (field/property) of a type.\n        /// </summary>\n        internal class SerializableMember : ISerializableMember\n        {\n            private readonly IMemberDescription _member;\n            private readonly CodeGenerator _codeGenerator;\n            private IPropertySymbol _property;\n\n            /// <summary>\n            /// The ordinal assigned to this field.\n            /// </summary>\n            private readonly int _ordinal;\n\n            public SerializableMember(CodeGenerator codeGenerator, IMemberDescription member, int ordinal)\n            {\n                _codeGenerator = codeGenerator;\n                _ordinal = ordinal;\n                _member = member;\n            }\n\n            private Compilation Compilation => _codeGenerator.Compilation;\n            private LibraryTypes LibraryTypes => _codeGenerator.LibraryTypes;\n\n            public bool IsShallowCopyable =>\n                LibraryTypes.IsShallowCopyable(_member.Type)\n                || Property is { } prop && prop.HasAttribute(LibraryTypes.ImmutableAttribute)\n                || _member.Symbol.HasAttribute(LibraryTypes.ImmutableAttribute);\n\n            public bool IsValueType => Type.IsValueType;\n\n            public IMemberDescription Member => _member;\n\n            /// <summary>\n            /// Gets the underlying <see cref=\"Field\"/> instance.\n            /// </summary>\n            private IFieldSymbol Field => (_member as IFieldDescription)?.Field;\n\n            public ITypeSymbol Type => _member.Type;\n\n            public INamedTypeSymbol ContainingType => _member.ContainingType;\n\n            public string MemberName => Field?.Name ?? Property?.Name;\n\n            /// <summary>\n            /// Gets the name of the getter field.\n            /// </summary>\n            private string GetterFieldName => $\"getField{_ordinal}\";\n\n            /// <summary>\n            /// Gets the name of the setter field.\n            /// </summary>\n            private string SetterFieldName => $\"setField{_ordinal}\";\n\n            /// <summary>\n            /// Gets a value indicating if the member is a property.\n            /// </summary>\n            private bool IsProperty => Member.Symbol is IPropertySymbol;\n\n            /// <summary>\n            /// Gets a value indicating whether or not this member represents an accessible field.\n            /// </summary>\n            private bool IsGettableField => Field is { } fieldInfo && _codeGenerator.Compilation.IsSymbolAccessibleWithin(fieldInfo, Compilation.Assembly) && !IsObsolete;\n\n            /// <summary>\n            /// Gets a value indicating whether or not this member represents an accessible, mutable field.\n            /// </summary>\n            private bool IsSettableField => Field is { } fieldInfo && IsGettableField && !fieldInfo.IsReadOnly;\n\n            /// <summary>\n            /// Gets a value indicating whether or not this member represents a property with an accessible, non-obsolete getter.\n            /// </summary>\n            private bool IsGettableProperty => Property?.GetMethod is { } getMethod && Compilation.IsSymbolAccessibleWithin(getMethod, Compilation.Assembly) && !IsObsolete;\n\n            /// <summary>\n            /// Gets a value indicating whether or not this member represents a property with an accessible, non-obsolete setter.\n            /// </summary>\n            private bool IsSettableProperty => Property?.SetMethod is { } setMethod && Compilation.IsSymbolAccessibleWithin(setMethod, Compilation.Assembly) && !setMethod.IsInitOnly && !IsObsolete;\n\n            /// <summary>\n            /// Gets syntax representing the type of this field.\n            /// </summary>\n            public TypeSyntax TypeSyntax => Member.Type.TypeKind == TypeKind.Dynamic\n                ? PredefinedType(Token(SyntaxKind.ObjectKeyword))\n                : _member.GetTypeSyntax(Member.Type);\n\n            /// <summary>\n            /// Gets the <see cref=\"Property\"/> which this field is the backing property for, or\n            /// <see langword=\"null\" /> if this is not the backing field of an auto-property.\n            /// </summary>\n            private IPropertySymbol Property => _property ??= _property = Member.Symbol as IPropertySymbol ?? PropertyUtility.GetMatchingProperty(Field);\n\n            /// <summary>\n            /// Gets a value indicating whether or not this field is obsolete.\n            /// </summary>\n            private bool IsObsolete => Member.Symbol.HasAttribute(LibraryTypes.ObsoleteAttribute) ||\n                                       Property != null && Property.HasAttribute(LibraryTypes.ObsoleteAttribute);\n\n            public bool IsPrimaryConstructorParameter => _member.IsPrimaryConstructorParameter;\n\n            /// <summary>\n            /// Returns syntax for retrieving the value of this field, deep copying it if necessary.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <returns>Syntax for retrieving the value of this field.</returns>\n            public ExpressionSyntax GetGetter(ExpressionSyntax instance)\n            {\n                // If the field is the backing field for an accessible auto-property use the property directly.\n                ExpressionSyntax result;\n                if (IsGettableProperty)\n                {\n                    result = instance.Member(Property.Name);\n                }\n                else if (IsGettableField)\n                {\n                    result = instance.Member(Field.Name);\n                }\n                else\n                {\n\n                    var instanceArg = Argument(instance);\n                    if (ContainingType?.IsValueType == true)\n                    {\n                        instanceArg = instanceArg.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                    }\n\n                    // Retrieve the field using the generated getter.\n                    result =\n                        InvocationExpression(IdentifierName(GetterFieldName))\n                            .AddArgumentListArguments(instanceArg);\n                }\n\n                return result;\n            }\n\n            /// <summary>\n            /// Returns syntax for setting the value of this field.\n            /// </summary>\n            /// <param name=\"instance\">The instance of the containing type.</param>\n            /// <param name=\"value\">Syntax for the new value.</param>\n            /// <returns>Syntax for setting the value of this field.</returns>\n            public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value)\n            {\n                // If the field is the backing field for an accessible auto-property use the property directly.\n                if (IsSettableProperty)\n                {\n                    return AssignmentExpression(\n                        SyntaxKind.SimpleAssignmentExpression,\n                        instance.Member(Property.Name),\n                        value);\n                }\n\n                if (IsSettableField)\n                {\n                    return AssignmentExpression(\n                        SyntaxKind.SimpleAssignmentExpression,\n                        instance.Member(Field.Name),\n                        value);\n                }\n\n                // If the symbol itself is a property but is not settable, then error out, since we do not know how to set it value\n                if (IsProperty && !IsPrimaryConstructorParameter)\n                {\n                    Location location = default;\n                    if (Member.Symbol is IPropertySymbol prop && prop.SetMethod is { } setMethod)\n                    {\n                        location = setMethod.Locations.FirstOrDefault();\n                    }\n\n                    location ??= Member.Symbol.Locations.FirstOrDefault();\n\n                    throw new OrleansGeneratorDiagnosticAnalysisException(InaccessibleSetterDiagnostic.CreateDiagnostic(location, Member.Symbol?.ToDisplayString() ?? $\"{ContainingType.ToDisplayString()}.{MemberName}\"));\n                }\n\n                var instanceArg = Argument(instance);\n                if (ContainingType?.IsValueType == true)\n                {\n                    instanceArg = instanceArg.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                }\n\n                return\n                    InvocationExpression(IdentifierName(SetterFieldName))\n                        .AddArgumentListArguments(instanceArg, Argument(value));\n            }\n\n            public FieldAccessorDescription GetGetterFieldDescription()\n            {\n                if (IsGettableField || IsGettableProperty) return null;\n                return GetFieldAccessor(ContainingType, TypeSyntax, MemberName, GetterFieldName, LibraryTypes, false,\n                    IsPrimaryConstructorParameter && IsProperty);\n            }\n\n            public FieldAccessorDescription GetSetterFieldDescription()\n            {\n                if (IsSettableField || IsSettableProperty) return null;\n                return GetFieldAccessor(ContainingType, TypeSyntax, MemberName, SetterFieldName, LibraryTypes, true,\n                    IsPrimaryConstructorParameter && IsProperty);\n            }\n\n            public static FieldAccessorDescription GetFieldAccessor(INamedTypeSymbol containingType, TypeSyntax fieldType, string fieldName, string accessorName, LibraryTypes library, bool setter, bool useUnsafeAccessor = false)\n            {\n                var containingTypeSyntax = containingType.ToTypeSyntax();\n\n                if (useUnsafeAccessor)\n                    return new(containingTypeSyntax, fieldType, fieldName, accessorName);\n\n                var valueType = containingType.IsValueType;\n\n                var delegateType = (setter ? (valueType ? library.ValueTypeSetter_2 : library.Action_2) : (valueType ? library.ValueTypeGetter_2 : library.Func_2))\n                    .ToTypeSyntax(containingTypeSyntax, fieldType);\n\n                // Generate syntax to initialize the field in the constructor\n                var fieldAccessorUtility = AliasQualifiedName(\"global\", IdentifierName(\"Orleans.Serialization\")).Member(\"Utilities\").Member(\"FieldAccessor\");\n                var accessorMethod = setter ? (valueType ? \"GetValueSetter\" : \"GetReferenceSetter\") : (valueType ? \"GetValueGetter\" : \"GetGetter\");\n                var accessorInvoke = CastExpression(delegateType,\n                    InvocationExpression(fieldAccessorUtility.Member(accessorMethod))\n                        .AddArgumentListArguments(Argument(TypeOfExpression(containingTypeSyntax)), Argument(fieldName.GetLiteralExpression())));\n\n                // Existing case, accessor is the field in both cases\n                return new(containingTypeSyntax, delegateType, accessorName, accessorName, accessorInvoke);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/FSharpUtils.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Orleans.CodeGenerator.SyntaxGeneration;\nusing static Orleans.CodeGenerator.SerializerGenerator;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator\n{\n    internal static class FSharpUtilities\n    {\n        private const int SourceConstructFlagsSumTypeValue = 1;\n        private const int SourceConstructFlagsKindMaskValue = 31;\n        private const int SourceConstructFlagsRecordTypeValue = 2;\n\n        public static bool IsUnionCase(LibraryTypes libraryTypes, INamedTypeSymbol symbol, out INamedTypeSymbol sumType)\n        {\n            sumType = default;\n            var compilationAttributeType = libraryTypes.FSharpCompilationMappingAttributeOrDefault;\n            var sourceConstructFlagsType = libraryTypes.FSharpSourceConstructFlagsOrDefault;\n            var baseType = symbol.BaseType;\n            if (compilationAttributeType is null || sourceConstructFlagsType is null || baseType is null)\n            {\n                return false;\n            }\n\n            INamedTypeSymbol sumTypeCandidate;\n            if (symbol.GetAttributes(compilationAttributeType, out var compilationAttributes) && compilationAttributes.Length > 0)\n            {\n                sumTypeCandidate = symbol;\n            }\n            else if (baseType.GetAttributes(compilationAttributeType, out compilationAttributes) && compilationAttributes.Length > 0)\n            {\n                sumTypeCandidate = baseType;\n            }\n            else\n            {\n                return false;\n            }\n\n            var compilationAttribute = compilationAttributes[0];\n            var foundArg = false;\n            TypedConstant sourceConstructFlagsArgument = default;\n            foreach (var arg in compilationAttribute.ConstructorArguments)\n            {\n                if (SymbolEqualityComparer.Default.Equals(arg.Type, sourceConstructFlagsType))\n                {\n                    sourceConstructFlagsArgument = arg;\n                    foundArg = true;\n                    break;\n                }\n            }\n\n            if (!foundArg)\n            {\n                return false;\n            }\n\n            if (sourceConstructFlagsArgument.Value != null && ((int)sourceConstructFlagsArgument.Value & SourceConstructFlagsKindMaskValue) != SourceConstructFlagsSumTypeValue)\n            {\n                return false;\n            }\n\n            sumType = sumTypeCandidate;\n            return true;\n        }\n\n        public static bool IsRecord(LibraryTypes libraryTypes, INamedTypeSymbol symbol)\n        {\n            var compilationAttributeType = libraryTypes.FSharpCompilationMappingAttributeOrDefault;\n            var sourceConstructFlagsType = libraryTypes.FSharpSourceConstructFlagsOrDefault;\n            if (compilationAttributeType is null || sourceConstructFlagsType is null)\n            {\n                return false;\n            }\n\n            if (!symbol.GetAttributes(compilationAttributeType, out var compilationAttributes) || compilationAttributes.Length == 0)\n            {\n                return false;\n            }\n\n            var compilationAttribute = compilationAttributes[0];\n            var foundArg = false;\n            TypedConstant sourceConstructFlagsArgument = default;\n            foreach (var arg in compilationAttribute.ConstructorArguments)\n            {\n                if (SymbolEqualityComparer.Default.Equals(arg.Type, sourceConstructFlagsType))\n                {\n                    sourceConstructFlagsArgument = arg;\n                    foundArg = true;\n                    break;\n                }\n            }\n\n            if (!foundArg)\n            {\n                return false;\n            }\n\n            if ((int)sourceConstructFlagsArgument.Value != SourceConstructFlagsRecordTypeValue)\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        public class FSharpUnionCaseTypeDescription : SerializableTypeDescription\n        {\n            public FSharpUnionCaseTypeDescription(Compilation compilation, INamedTypeSymbol type, LibraryTypes libraryTypes) : base(compilation, type, false, GetUnionCaseDataMembers(libraryTypes, type), libraryTypes)\n            {\n            }\n\n            private static IEnumerable<IMemberDescription> GetUnionCaseDataMembers(LibraryTypes libraryTypes, INamedTypeSymbol symbol)\n            {\n                List<IFieldSymbol> dataMembers = new();\n                foreach (var field in symbol.GetDeclaredInstanceMembers<IFieldSymbol>())\n                {\n                    dataMembers.Add(field);\n                }\n\n                dataMembers.Sort(FSharpUnionCasePropertyNameComparer.Default);\n\n                uint id = 0;\n                foreach (var field in dataMembers)\n                {\n                    yield return new FSharpUnionCaseFieldDescription(libraryTypes, field, id);\n                    id++;\n                }\n            }\n\n            private class FSharpUnionCasePropertyNameComparer : IComparer<IFieldSymbol>\n            {\n                public static FSharpUnionCasePropertyNameComparer Default { get; } = new FSharpUnionCasePropertyNameComparer();\n\n                public int Compare(IFieldSymbol x, IFieldSymbol y)\n                {\n                    var xName = x.Name;\n                    var yName = y.Name;\n                    if (xName.Length > yName.Length)\n                    {\n                        return 1;\n                    }\n\n                    if (xName.Length < yName.Length)\n                    {\n                        return -1;\n                    }\n\n                    return string.CompareOrdinal(xName, yName);\n                }\n            }\n\n            private class FSharpUnionCaseFieldDescription : IMemberDescription, ISerializableMember\n            {\n                private readonly LibraryTypes _libraryTypes;\n                private readonly IFieldSymbol _field;\n\n                public FSharpUnionCaseFieldDescription(LibraryTypes libraryTypes, IFieldSymbol field, uint ordinal)\n                {\n                    _libraryTypes = libraryTypes;\n                    FieldId = ordinal;\n                    _field = field;\n                }\n\n                public uint FieldId { get; }\n\n                public bool IsShallowCopyable => _libraryTypes.IsShallowCopyable(Type) || _field.HasAttribute(_libraryTypes.ImmutableAttribute);\n\n                public bool IsValueType => Type.IsValueType;\n\n                public IMemberDescription Member => this;\n\n                public ITypeSymbol Type => _field.Type;\n\n                public INamedTypeSymbol ContainingType => _field.ContainingType;\n\n                public ISymbol Symbol => _field;\n\n                /// <summary>\n                /// Gets the name of the setter field.\n                /// </summary>\n                private string SetterFieldName => \"setField\" + FieldId;\n\n                /// <summary>\n                /// Gets syntax representing the type of this field.\n                /// </summary>\n                public TypeSyntax TypeSyntax => Type.TypeKind == TypeKind.Dynamic\n                    ? PredefinedType(Token(SyntaxKind.ObjectKeyword))\n                    : GetTypeSyntax(Type);\n\n                public string AssemblyName => Type.ContainingAssembly.ToDisplayName();\n                public string TypeName => Type.ToDisplayName();\n                public string TypeNameIdentifier => Type.GetValidIdentifier();\n\n                public bool IsPrimaryConstructorParameter => false;\n\n                public bool IsSerializable => true;\n                public bool IsCopyable => true;\n\n                public TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol) => typeSymbol.ToTypeSyntax();\n\n                /// <summary>\n                /// Returns syntax for retrieving the value of this field, deep copying it if necessary.\n                /// </summary>\n                /// <param name=\"instance\">The instance of the containing type.</param>\n                /// <returns>Syntax for retrieving the value of this field.</returns>\n                public ExpressionSyntax GetGetter(ExpressionSyntax instance) => instance.Member(_field.Name);\n\n                /// <summary>\n                /// Returns syntax for setting the value of this field.\n                /// </summary>\n                /// <param name=\"instance\">The instance of the containing type.</param>\n                /// <param name=\"value\">Syntax for the new value.</param>\n                /// <returns>Syntax for setting the value of this field.</returns>\n                public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value)\n                {\n                    var instanceArg = Argument(instance);\n                    if (ContainingType != null && ContainingType.IsValueType)\n                    {\n                        instanceArg = instanceArg.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                    }\n\n                    return\n                        InvocationExpression(IdentifierName(SetterFieldName))\n                            .AddArgumentListArguments(instanceArg, Argument(value));\n                }\n\n                public FieldAccessorDescription GetGetterFieldDescription() => null;\n\n                public FieldAccessorDescription GetSetterFieldDescription()\n                    => SerializableMember.GetFieldAccessor(ContainingType, TypeSyntax, _field.Name, SetterFieldName, _libraryTypes, true);\n            }\n        }\n\n        public class FSharpRecordTypeDescription : SerializableTypeDescription\n        {\n            public FSharpRecordTypeDescription(Compilation compilation, INamedTypeSymbol type, LibraryTypes libraryTypes) : base(compilation, type, false, GetRecordDataMembers(libraryTypes, type), libraryTypes)\n            {\n            }\n\n            private static IEnumerable<IMemberDescription> GetRecordDataMembers(LibraryTypes libraryTypes, INamedTypeSymbol symbol)\n            {\n                List<(IPropertySymbol, uint)> dataMembers = new();\n                foreach (var property in symbol.GetDeclaredInstanceMembers<IPropertySymbol>())\n                {\n                    var id = CodeGenerator.GetId(libraryTypes, property);\n                    if (!id.HasValue)\n                    {\n                        continue;\n                    }\n\n                    dataMembers.Add((property, id.Value));\n                }\n\n                foreach (var (property, id) in dataMembers)\n                {\n                    yield return new FSharpRecordPropertyDescription(libraryTypes, property, id);\n                }\n            }\n\n            private class FSharpRecordPropertyDescription : IMemberDescription, ISerializableMember\n            {\n                private readonly LibraryTypes _libraryTypes;\n                private readonly IPropertySymbol _property;\n\n                public FSharpRecordPropertyDescription(LibraryTypes libraryTypes, IPropertySymbol property, uint ordinal)\n                {\n                    _libraryTypes = libraryTypes;\n                    FieldId = ordinal;\n                    _property = property;\n                }\n\n                public uint FieldId { get; }\n\n                public bool IsShallowCopyable => _libraryTypes.IsShallowCopyable(Type) || _property.HasAttribute(_libraryTypes.ImmutableAttribute);\n\n                public bool IsValueType => Type.IsValueType;\n\n                public IMemberDescription Member => this;\n\n                public ITypeSymbol Type => _property.Type;\n\n                public ISymbol Symbol => _property;\n\n                public INamedTypeSymbol ContainingType => _property.ContainingType;\n\n                public string FieldName => _property.Name + \"@\"; \n\n                /// <summary>\n                /// Gets the name of the setter field.\n                /// </summary>\n                private string SetterFieldName => \"setField\" + FieldId;\n\n                /// <summary>\n                /// Gets syntax representing the type of this field.\n                /// </summary>\n                public TypeSyntax TypeSyntax => Type.TypeKind == TypeKind.Dynamic\n                    ? PredefinedType(Token(SyntaxKind.ObjectKeyword)) \n                    : GetTypeSyntax(Type);\n\n                /// <summary>\n                /// Gets the <see cref=\"Property\"/> which this field is the backing property for, or\n                /// <see langword=\"null\" /> if this is not the backing field of an auto-property.\n                /// </summary>\n                private IPropertySymbol Property => _property;\n\n                public string AssemblyName => Type.ContainingAssembly.ToDisplayName();\n                public string TypeName => Type.ToDisplayName();\n                public string TypeNameIdentifier => Type.GetValidIdentifier();\n\n                public bool IsPrimaryConstructorParameter => false;\n\n                public bool IsSerializable => true;\n                public bool IsCopyable => true;\n\n                public TypeSyntax GetTypeSyntax(ITypeSymbol typeSymbol) => typeSymbol.ToTypeSyntax();\n\n                /// <summary>\n                /// Returns syntax for retrieving the value of this field, deep copying it if necessary.\n                /// </summary>\n                /// <param name=\"instance\">The instance of the containing type.</param>\n                /// <returns>Syntax for retrieving the value of this field.</returns>\n                public ExpressionSyntax GetGetter(ExpressionSyntax instance) => instance.Member(Property.Name);\n\n                /// <summary>\n                /// Returns syntax for setting the value of this field.\n                /// </summary>\n                /// <param name=\"instance\">The instance of the containing type.</param>\n                /// <param name=\"value\">Syntax for the new value.</param>\n                /// <returns>Syntax for setting the value of this field.</returns>\n                public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value)\n                {\n                    var instanceArg = Argument(instance);\n                    if (ContainingType != null && ContainingType.IsValueType)\n                    {\n                        instanceArg = instanceArg.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword));\n                    }\n\n                    return\n                        InvocationExpression(IdentifierName(SetterFieldName))\n                            .AddArgumentListArguments(instanceArg, Argument(value));\n                }\n\n                public FieldAccessorDescription GetGetterFieldDescription() => null;\n\n                public FieldAccessorDescription GetSetterFieldDescription()\n                    => SerializableMember.GetFieldAccessor(ContainingType, TypeSyntax, FieldName, SetterFieldName, _libraryTypes, true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/Identifier.cs",
    "content": "using System.Text.RegularExpressions;\n\nnamespace Orleans.CodeGenerator.SyntaxGeneration\n{\n    internal static class Identifier\n    {\n        internal static bool IsCSharpKeyword(string identifier)\n        {\n            switch (identifier)\n            {\n                case \"abstract\":\n                case \"add\":\n                case \"alias\":\n                case \"as\":\n                case \"ascending\":\n                case \"async\":\n                case \"await\":\n                case \"base\":\n                case \"bool\":\n                case \"break\":\n                case \"byte\":\n                case \"case\":\n                case \"catch\":\n                case \"char\":\n                case \"checked\":\n                case \"class\":\n                case \"const\":\n                case \"continue\":\n                case \"decimal\":\n                case \"default\":\n                case \"delegate\":\n                case \"descending\":\n                case \"do\":\n                case \"double\":\n                case \"dynamic\":\n                case \"else\":\n                case \"enum\":\n                case \"event\":\n                case \"explicit\":\n                case \"extern\":\n                case \"false\":\n                case \"finally\":\n                case \"fixed\":\n                case \"float\":\n                case \"for\":\n                case \"foreach\":\n                case \"from\":\n                case \"get\":\n                case \"global\":\n                case \"goto\":\n                case \"group\":\n                case \"if\":\n                case \"implicit\":\n                case \"in\":\n                case \"int\":\n                case \"interface\":\n                case \"internal\":\n                case \"into\":\n                case \"is\":\n                case \"join\":\n                case \"let\":\n                case \"lock\":\n                case \"long\":\n                case \"nameof\":\n                case \"namespace\":\n                case \"new\":\n                case \"null\":\n                case \"object\":\n                case \"operator\":\n                case \"orderby\":\n                case \"out\":\n                case \"override\":\n                case \"params\":\n                case \"partial\":\n                case \"private\":\n                case \"protected\":\n                case \"public\":\n                case \"readonly\":\n                case \"ref\":\n                case \"remove\":\n                case \"return\":\n                case \"sbyte\":\n                case \"sealed\":\n                case \"select\":\n                case \"set\":\n                case \"short\":\n                case \"sizeof\":\n                case \"stackalloc\":\n                case \"static\":\n                case \"string\":\n                case \"struct\":\n                case \"switch\":\n                case \"this\":\n                case \"throw\":\n                case \"true\":\n                case \"try\":\n                case \"typeof\":\n                case \"uint\":\n                case \"ulong\":\n                case \"unchecked\":\n                case \"unsafe\":\n                case \"ushort\":\n                case \"using\":\n                case \"value\":\n                case \"var\":\n                case \"virtual\":\n                case \"void\":\n                case \"volatile\":\n                case \"when\":\n                case \"where\":\n                case \"while\":\n                case \"yield\":\n                    return true;\n                default:\n                    return false;\n            }\n        }\n\n        private static readonly Regex SanitizeIdentifierRegex = new(\"^([0-9]+)|([^0-9a-zA-Z_]+)\", RegexOptions.Compiled);\n\n        public static string SanitizeIdentifierName(string input) => SanitizeIdentifierRegex.Replace(\n            input,\n            static match => match.Value switch\n            {\n                // Prefix leading digits with an '_' to make them a valid identifier.\n                { Length: > 0 } value when char.IsDigit(value[0]) => $\"_{value}\",\n\n                // Eliminate all other matches by replacing them with an empty string.\n                _ => \"\"\n            });\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/StringExtensions.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\n\nnamespace Orleans.CodeGenerator.SyntaxGeneration\n{\n    /// <summary>\n    /// Extensions to the <see cref=\"string\"/> class to support code generation.\n    /// </summary>\n    internal static class StringExtensions\n    {\n        /// <summary>\n        /// Returns the provided string as a literal expression.\n        /// </summary>\n        /// <param name=\"str\">\n        /// The string.\n        /// </param>\n        /// <returns>\n        /// The literal expression.\n        /// </returns>\n        public static LiteralExpressionSyntax GetLiteralExpression(this string str)\n        {\n            var syntaxToken = SyntaxFactory.Literal(\n                SyntaxFactory.TriviaList(),\n                @\"\"\"\" + str + @\"\"\"\",\n                str,\n                SyntaxFactory.TriviaList());\n            return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, syntaxToken);\n        }\n\n        public static SyntaxToken ToIdentifier(this string identifier)\n        {\n            identifier = identifier.TrimStart('@');\n            if (Identifier.IsCSharpKeyword(identifier))\n            {\n                return SyntaxFactory.VerbatimIdentifier(\n                    SyntaxTriviaList.Empty,\n                    identifier,\n                    identifier,\n                    SyntaxTriviaList.Empty);\n            }\n\n            return SyntaxFactory.Identifier(SyntaxTriviaList.Empty, identifier, SyntaxTriviaList.Empty);\n        }\n\n        public static string EscapeIdentifier(this string str)\n        {\n            if (Identifier.IsCSharpKeyword(str))\n            {\n                return \"@\" + str;\n            }\n\n            return str;\n        }\n\n        public static IdentifierNameSyntax ToIdentifierName(this string identifier) => SyntaxFactory.IdentifierName(identifier.ToIdentifier());\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/SymbolExtensions.cs",
    "content": "#nullable enable\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator.SyntaxGeneration\n{\n    internal static class SymbolExtensions\n    {\n        private static readonly ConcurrentDictionary<ITypeSymbol, TypeSyntax> TypeCache = new(SymbolEqualityComparer.Default);\n        private static readonly ConcurrentDictionary<ISymbol, string> NameCache = new(SymbolEqualityComparer.Default);\n\n        public struct DisplayNameOptions\n        {\n            public DisplayNameOptions()\n            {\n                Substitutions = null;\n            }\n\n            public Dictionary<ITypeParameterSymbol, string>? Substitutions { get; set; }\n            public bool IncludeGlobalSpecifier { get; set; } = true;\n            public bool IncludeNamespace { get; set; } = true;\n        }\n\n        public static bool HasAttribute(this INamedTypeSymbol symbol, INamedTypeSymbol attributeType, bool inherited) => GetAttribute(symbol, attributeType, inherited) is not null;\n\n        public static AttributeData? GetAttribute(this INamedTypeSymbol symbol, INamedTypeSymbol attributeType, bool inherited)\n        {\n            var s = symbol;\n            if (s.GetAttribute(attributeType) is { } attribute)\n            {\n                return attribute;\n            }\n\n            if (inherited)\n            {\n                foreach (var iface in symbol.AllInterfaces)\n                {\n                    if (iface.GetAttribute(attributeType) is { } iattr)\n                    {\n                        return iattr;\n                    }\n                }\n\n                while ((s = s.BaseType) != null)\n                {\n                    if (s.GetAttribute(attributeType) is { } attr)\n                    {\n                        return attr;\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        public static TypeSyntax ToTypeSyntax(this ITypeSymbol typeSymbol)\n        {\n            if (typeSymbol.SpecialType == SpecialType.System_Void)\n            {\n                return PredefinedType(Token(SyntaxKind.VoidKeyword));\n            }\n\n            if (!TypeCache.TryGetValue(typeSymbol, out var result))\n            {\n                result = TypeCache[typeSymbol] = ParseTypeName(typeSymbol.ToDisplayName());\n            }\n\n            return result;\n        }\n\n        public static TypeSyntax ToTypeSyntax(this ITypeSymbol typeSymbol, Dictionary<ITypeParameterSymbol, string> substitutions)\n        {\n            if (substitutions is null or { Count: 0 })\n            {\n                return typeSymbol.ToTypeSyntax();\n            }\n\n            if (typeSymbol.SpecialType == SpecialType.System_Void)\n            {\n                return PredefinedType(Token(SyntaxKind.VoidKeyword));\n            }\n\n            var res = new StringBuilder();\n            var options = new DisplayNameOptions\n            {\n                Substitutions = substitutions,\n            };\n            ToTypeSyntaxInner(typeSymbol, res, options);\n            var result = ParseTypeName(res.ToString());\n            return result;\n        }\n\n        public static string ToDisplayName(this ITypeSymbol typeSymbol, Dictionary<ITypeParameterSymbol, string>? substitutions, bool includeGlobalSpecifier = true, bool includeNamespace = true)\n        {\n            return ToDisplayName(typeSymbol, new DisplayNameOptions { Substitutions = substitutions, IncludeGlobalSpecifier = includeGlobalSpecifier, IncludeNamespace = includeNamespace });\n        }\n\n        public static string ToDisplayName(this ITypeSymbol typeSymbol, DisplayNameOptions options)\n        {\n            if (typeSymbol.SpecialType == SpecialType.System_Void)\n            {\n                return \"void\";\n            }\n\n            var result = new StringBuilder();\n            ToTypeSyntaxInner(typeSymbol, result, options);\n            return result.ToString();\n        }\n\n        public static string ToDisplayName(this ITypeSymbol typeSymbol)\n        {\n            if (typeSymbol.SpecialType == SpecialType.System_Void)\n            {\n                return \"void\";\n            }\n\n            if (!NameCache.TryGetValue(typeSymbol, out var result))\n            {\n                result = NameCache[typeSymbol] = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);\n            }\n\n            return result;\n        }\n\n        public static string ToDisplayName(this IAssemblySymbol assemblySymbol)\n        {\n            if (assemblySymbol is null)\n            {\n                return string.Empty;\n            }\n\n            if (!NameCache.TryGetValue(assemblySymbol, out var result))\n            {\n                result = NameCache[assemblySymbol] = assemblySymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);\n            }\n\n            return result;\n        }\n\n        private static void ToTypeSyntaxInner(ITypeSymbol typeSymbol, StringBuilder res, DisplayNameOptions options)\n        {\n            switch (typeSymbol)\n            {\n                case IDynamicTypeSymbol:\n                    res.Append(\"dynamic\");\n                    break;\n                case IArrayTypeSymbol a:\n                    ToTypeSyntaxInner(a.ElementType, res, options);\n                    res.Append('[');\n                    if (a.Rank > 1)\n                    {\n                        res.Append(new string(',', a.Rank - 1));\n                    }\n\n                    res.Append(']');\n                    break;\n                case ITypeParameterSymbol tp:\n                    if (options.Substitutions is { } substitutions && substitutions.TryGetValue(tp, out var sub))\n                    {\n                        res.Append(sub);\n                    }\n                    else\n                    {\n                        res.Append(tp.Name.EscapeIdentifier());\n                    }\n                    break;\n                case INamedTypeSymbol n:\n                    OnNamedTypeSymbol(n, res, options);\n                    break;\n                default:\n                    throw new NotSupportedException($\"Symbols of type {typeSymbol?.GetType().ToString() ?? \"null\"} are not supported\");\n            }\n\n            static void OnNamedTypeSymbol(INamedTypeSymbol symbol, StringBuilder res, DisplayNameOptions options)\n            {\n                switch (symbol.ContainingSymbol)\n                {\n                    case INamespaceSymbol ns when options.IncludeNamespace:\n                        AddFullNamespace(ns, res, options.IncludeGlobalSpecifier);\n                        break;\n                    case INamedTypeSymbol containingType:\n                        OnNamedTypeSymbol(containingType, res, options);\n                        res.Append('.');\n                        break;\n                }\n\n                res.Append(symbol.Name.EscapeIdentifier());\n                if (symbol.TypeArguments.Length > 0)\n                {\n                    res.Append('<');\n                    bool first = true;\n                    foreach (var typeParameter in symbol.TypeArguments)\n                    {\n                        if (!first)\n                        {\n                            res.Append(',');\n                        }\n\n                        ToTypeSyntaxInner(typeParameter, res, options);\n                        first = false;\n                    }\n                    res.Append('>');\n                }\n            }\n\n            static void AddFullNamespace(INamespaceSymbol symbol, StringBuilder res, bool includeGlobalSpecifier)\n            {\n                if (symbol.ContainingNamespace is { } parent)\n                {\n                    AddFullNamespace(parent, res, includeGlobalSpecifier);\n                }\n\n                if (symbol.IsGlobalNamespace)\n                {\n                    if (includeGlobalSpecifier)\n                    {\n                        res.Append(\"global::\");\n                    }\n                }\n                else\n                {\n                    res.Append(symbol.Name.EscapeIdentifier());\n                    res.Append('.');\n                }\n            }\n        }\n\n        public static TypeSyntax ToTypeSyntax(this ITypeSymbol typeSymbol, params TypeSyntax[] genericParameters)\n        {\n            var displayString = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);\n            var nameSyntax = ParseName(displayString);\n\n            switch (nameSyntax)\n            {\n                case AliasQualifiedNameSyntax aliased:\n                    return aliased.WithName(WithGenericParameters(aliased.Name));\n                case QualifiedNameSyntax qualified:\n                    return qualified.WithRight(WithGenericParameters(qualified.Right));\n                case GenericNameSyntax g:\n                    return WithGenericParameters(g);\n                default:\n                    throw new InvalidOperationException(\n                        $\"Attempted to add generic parameters to non-generic type {displayString} ({nameSyntax.GetType()}, adding parameters {string.Join(\", \", genericParameters.Select(n => n.ToFullString()))}\");\n            }\n\n            SimpleNameSyntax WithGenericParameters(SimpleNameSyntax simpleNameSyntax)\n            {\n                if (simpleNameSyntax is GenericNameSyntax generic)\n                {\n                    return generic.WithTypeArgumentList(TypeArgumentList(SeparatedList(genericParameters)));\n                }\n\n                throw new InvalidOperationException(\n                    $\"Attempted to add generic parameters to non-generic type {displayString} ({nameSyntax.GetType()}, adding parameters {string.Join(\", \", genericParameters.Select(n => n.ToFullString()))}\");\n            }\n        }\n\n        public static TypeSyntax ToOpenTypeSyntax(this ITypeSymbol typeSymbol)\n        {\n            var displayString = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);\n            var nameSyntax = ParseName(displayString);\n            return Visit(nameSyntax);\n\n            static NameSyntax Visit(NameSyntax nameSyntax)\n            {\n                switch (nameSyntax)\n                {\n                    case GenericNameSyntax generic:\n                        {\n                            var argCount = generic.TypeArgumentList.Arguments.Count;\n                            return generic.WithTypeArgumentList(TypeArgumentList(SeparatedList<TypeSyntax>(Enumerable.Range(0, argCount).Select(_ => OmittedTypeArgument()))));\n                        }\n                    case AliasQualifiedNameSyntax aliased:\n                        return aliased.WithName((SimpleNameSyntax)Visit(aliased.Name));\n                    case QualifiedNameSyntax qualified:\n                        return qualified.WithRight((SimpleNameSyntax)Visit(qualified.Right)).WithLeft(Visit(qualified.Left));\n                    default:\n                        return nameSyntax;\n                }\n            }\n        }\n\n        public static NameSyntax ToNameSyntax(this ITypeSymbol typeSymbol) => ParseName(typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));\n\n        public static string GetValidIdentifier(this ITypeSymbol type) => type switch\n        {\n            INamedTypeSymbol named when !named.IsGenericType => $\"{named.Name}\",\n            INamedTypeSymbol named => $\"{named.Name}_{string.Join(\"_\", named.TypeArguments.Select(GetValidIdentifier))}\",\n            IArrayTypeSymbol array => $\"{GetValidIdentifier(array.ElementType)}_{array.Rank}\",\n            ITypeParameterSymbol parameter => $\"{parameter.Name}\",\n            _ => throw new NotSupportedException($\"Unable to format type of kind {type.GetType()} with name \\\"{type.Name}\\\"\"),\n        };\n\n        public static bool HasBaseType(this ITypeSymbol typeSymbol, INamedTypeSymbol baseType)\n        {\n            var current = typeSymbol;\n            for (; current != null; current = current.BaseType)\n            {\n                if (SymbolEqualityComparer.Default.Equals(baseType, current))\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        public static bool HasAnyAttribute(this ISymbol symbol, INamedTypeSymbol[] attributeTypes) => GetAnyAttribute(symbol, attributeTypes) != null;\n\n        public static AttributeData? GetAnyAttribute(this ISymbol symbol, INamedTypeSymbol[] attributeTypes)\n        {\n            foreach (var attr in symbol.GetAttributes())\n            {\n                foreach (var t in attributeTypes)\n                {\n                    if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, t))\n                    {\n                        return attr;\n                    }\n                }\n            }\n            return null;\n        }\n\n        public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType) => GetAttribute(symbol, attributeType) != null;\n\n        public static AttributeData? GetAttribute(this ISymbol symbol, INamedTypeSymbol attributeType)\n        {\n            foreach (var attr in symbol.GetAttributes())\n            {\n                if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeType))\n                {\n                    return attr;\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Gets all attributes which are assignable to the specified attribute type.\n        /// </summary>\n        public static bool GetAttributes(this ISymbol symbol, INamedTypeSymbol attributeType, out AttributeData[]? attributes)\n        {\n            var result = default(List<AttributeData>);\n            foreach (var attr in symbol.GetAttributes())\n            {\n                if (attr.AttributeClass is { } attrClass && !attrClass.HasBaseType(attributeType))\n                {\n                    continue;\n                }\n\n                if (result is null)\n                {\n                    result = new List<AttributeData>();\n                }\n\n                result.Add(attr);\n            }\n\n            attributes = result?.ToArray();\n            return attributes != null && attributes.Length > 0;\n        }\n\n        /// <summary>\n        /// Gets all attributes which are assignable to the specified attribute type.\n        /// </summary>\n        public static bool GetAttributes(this INamedTypeSymbol symbol, INamedTypeSymbol attributeType, out AttributeData[]? attributes, bool inherited = false)\n        {\n            var result = default(List<AttributeData>);\n            AddSymbolAttributes(symbol, attributeType, ref result);\n\n            if (inherited)\n            {\n                foreach (var iface in symbol.AllInterfaces)\n                {\n                    AddSymbolAttributes(iface, attributeType, ref result);\n                }\n\n                var s = symbol;\n                while ((s = s.BaseType) != null)\n                {\n                    AddSymbolAttributes(s, attributeType, ref result);\n                }\n            }\n\n            attributes = result?.ToArray();\n            return attributes != null && attributes.Length > 0;\n\n            static void AddSymbolAttributes(ISymbol symbol, INamedTypeSymbol attributeType, ref List<AttributeData>? result)\n            {\n                foreach (var attr in symbol.GetAttributes())\n                {\n                    if (attr.AttributeClass is { } attrClass && !attrClass.HasBaseType(attributeType))\n                    {\n                        continue;\n                    }\n\n                    if (result is null)\n                    {\n                        result = new List<AttributeData>();\n                    }\n\n                    result.Add(attr);\n                }\n            }\n        }\n\n        public static IEnumerable<TSymbol> GetAllMembers<TSymbol>(this ITypeSymbol type, string name) where TSymbol : ISymbol\n        {\n            foreach (var member in type.GetAllMembers<TSymbol>())\n            {\n                if (!string.Equals(member.Name, name, StringComparison.Ordinal))\n                {\n                    continue;\n                }\n\n                yield return member;\n            }\n        }\n\n        public static IEnumerable<TSymbol> GetAllMembers<TSymbol>(this ITypeSymbol type, string name, Accessibility accessibility) where TSymbol : ISymbol\n        {\n            foreach (var member in type.GetAllMembers<TSymbol>(name))\n            {\n                if (member.DeclaredAccessibility != accessibility)\n                {\n                    continue;\n                }\n\n                yield return member;\n            }\n        }\n\n        public static IEnumerable<TSymbol> GetAllMembers<TSymbol>(this ITypeSymbol type) where TSymbol : ISymbol\n        {\n            var bases = new Stack<ITypeSymbol>();\n            var b = type.BaseType;\n            while (b is { })\n            {\n                bases.Push(b);\n                b = b.BaseType;\n            }\n\n            foreach (var @base in bases)\n            {\n                foreach (var member in @base.GetDeclaredInstanceMembers<TSymbol>())\n                {\n                    yield return member;\n                }\n            }\n\n            foreach (var iface in type.AllInterfaces)\n            {\n                foreach (var member in iface.GetDeclaredInstanceMembers<TSymbol>())\n                {\n                    yield return member;\n                }\n            }\n\n            foreach (var member in type.GetDeclaredInstanceMembers<TSymbol>())\n            {\n                yield return member;\n            }\n        }\n        \n        public static IEnumerable<TSymbol> GetDeclaredInstanceMembers<TSymbol>(this ITypeSymbol type) where TSymbol : ISymbol\n        {\n            foreach (var candidate in type.GetMembers())\n            {\n                if (candidate.IsStatic)\n                {\n                    continue;\n                }\n\n                if (candidate is TSymbol symbol)\n                {\n                    yield return symbol;\n                }\n            }\n        }\n\n        public static string GetNamespaceAndNesting(this ISymbol symbol)\n        {\n            var result = new StringBuilder();\n            Visit(symbol, result);\n            return result.ToString();\n\n            static void Visit(ISymbol symbol, StringBuilder res)\n            {\n                switch (symbol.ContainingSymbol)\n                {\n                    case INamespaceOrTypeSymbol parent:\n                        Visit(parent, res);\n\n                        if (res is { Length: > 0 })\n                        {\n                            res.Append('.');\n                        }\n\n                        res.Append(parent.Name);\n                        break;\n                }\n            }\n        }\n\n        public static IEnumerable<ITypeParameterSymbol> GetAllTypeParameters(this INamedTypeSymbol symbol)\n        {\n            // Note that this will not work if multiple points in the inheritance hierarchy are containing within a single generic type.\n            // To solve that, we could retain some context throughout the recursive calls.\n            if (symbol.ContainingType is { } containingType && containingType.IsGenericType)\n            {\n                foreach (var containingTypeParameter in containingType.GetAllTypeParameters())\n                {\n                    yield return containingTypeParameter;\n                }\n            }\n\n            foreach (var tp in symbol.TypeParameters)\n            {\n                yield return tp;\n            }\n        }\n\n        public static IEnumerable<ITypeSymbol> GetAllTypeArguments(this INamedTypeSymbol symbol)\n        {\n            if (symbol.ContainingType is { } containingType && containingType.IsGenericType)\n            {\n                foreach (var containingTypeParameter in containingType.GetAllTypeArguments())\n                {\n                    yield return containingTypeParameter;\n                }\n            }\n\n            foreach (var tp in symbol.TypeArguments)\n            {\n                yield return tp;\n            }\n        }\n\n        public static bool IsAssignableFrom(this INamedTypeSymbol symbol, INamedTypeSymbol type)\n        {\n            if (symbol.TypeKind == TypeKind.Interface)\n            {\n                return IsInterfaceAssignableFromInternal(symbol, type);\n            }\n\n            return IsBaseAssignableFromInternal(symbol, type);\n        }\n\n        private static bool IsBaseAssignableFromInternal(this INamedTypeSymbol symbol, INamedTypeSymbol? type)\n        {\n            if (type is null) return false;\n            if (SymbolEqualityComparer.Default.Equals(symbol, type))\n            {\n                return true;\n            }\n\n            return IsBaseAssignableFromInternal(symbol, type.BaseType);\n        }\n\n        private static bool IsInterfaceAssignableFromInternal(this INamedTypeSymbol iface, INamedTypeSymbol type)\n        {\n            if (SymbolEqualityComparer.Default.Equals(iface, type))\n            {\n                return true;\n            }\n\n            foreach (var typeInterface in type.AllInterfaces)\n            {\n                if (SymbolEqualityComparer.Default.Equals(iface, typeInterface))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static IEnumerable<INamedTypeSymbol> GetDeclaredTypes(this IAssemblySymbol reference)\n        {\n            foreach (var module in reference.Modules)\n            {\n                foreach (var type in GetDeclaredTypes(module.GlobalNamespace))\n                {\n                    yield return type;\n                }\n            }\n\n            IEnumerable<INamedTypeSymbol> GetDeclaredTypes(INamespaceOrTypeSymbol ns)\n            {\n                foreach (var member in ns.GetMembers())\n                {\n                    switch (member)\n                    {\n                        case INamespaceSymbol nestedNamespace:\n                            foreach (var nested in GetDeclaredTypes(nestedNamespace)) yield return nested;\n                            break;\n                        case ITypeSymbol type:\n                            if (type is INamedTypeSymbol namedType) yield return namedType;\n                            foreach (var nested in GetDeclaredTypes(type)) yield return nested;\n                            break;\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/SymbolSyntaxExtensions.cs",
    "content": "using Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System;\nusing System.Reflection;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nusing System.Diagnostics;\nusing Microsoft.CodeAnalysis;\n\nnamespace Orleans.CodeGenerator.SyntaxGeneration\n{\n    internal static class SymbolSyntaxExtensions\n    {\n        public static ParenthesizedExpressionSyntax GetBindingFlagsParenthesizedExpressionSyntax(\n            SyntaxKind operationKind,\n            params BindingFlags[] bindingFlags)\n        {\n            if (bindingFlags.Length < 2)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(bindingFlags),\n                    $\"Can't create parenthesized binary expression with {bindingFlags.Length} arguments\");\n            }\n\n            var flags = AliasQualifiedName(\"global\", IdentifierName(\"System\")).Member(\"Reflection\").Member(\"BindingFlags\");\n            var bindingFlagsBinaryExpression = BinaryExpression(\n                operationKind,\n                flags.Member(bindingFlags[0].ToString()),\n                flags.Member(bindingFlags[1].ToString()));\n            for (var i = 2; i < bindingFlags.Length; i++)\n            {\n                bindingFlagsBinaryExpression = BinaryExpression(\n                    operationKind,\n                    bindingFlagsBinaryExpression,\n                    flags.Member(bindingFlags[i].ToString()));\n            }\n\n            return ParenthesizedExpression(bindingFlagsBinaryExpression);\n        }\n\n        /// <summary>\n        /// Returns the System.String that represents the current TypedConstant.\n        /// </summary>\n        /// <returns>A System.String that represents the current TypedConstant.</returns>\n        public static ExpressionSyntax ToExpression(this TypedConstant constant)\n        {\n            if (constant.IsNull)\n            {\n                return LiteralExpression(SyntaxKind.NullLiteralExpression);\n            }\n\n            if (constant.Kind == TypedConstantKind.Array)\n            {\n                throw new NotSupportedException($\"Unsupported TypedConstant: {constant.ToCSharpString()}\");\n            }\n\n            if (constant.Kind == TypedConstantKind.Type)\n            {\n                Debug.Assert(constant.Value is not null);\n                return TypeOfExpression(((ITypeSymbol)constant.Value).ToTypeSyntax());\n            }\n\n            if (constant.Kind == TypedConstantKind.Enum)\n            {\n                return DisplayEnumConstant(constant);\n            }\n\n            return ParseExpression(constant.ToCSharpString());\n        }\n\n        // Decode the value of enum constant\n        private static ExpressionSyntax DisplayEnumConstant(TypedConstant constant)\n        {\n            //string typeName = constant.Type.ToDisplayName();\n            var constantToDecode = ConvertToUInt64(constant.Value);\n            ulong curValue = 0;\n\n            // Iterate through all the constant members in the enum type\n            var members = constant.Type!.GetMembers();\n            var type = constant.Type.ToTypeSyntax();\n            ExpressionSyntax result = null;\n            foreach (var member in members)\n            {\n                var field = member as IFieldSymbol;\n\n                if (field is object && field.HasConstantValue)\n                {\n                    ulong memberValue = ConvertToUInt64(field.ConstantValue);\n\n                    if (memberValue == constantToDecode)\n                    {\n                        return constant.Type.ToTypeSyntax().Member(field.Name);\n                    }\n\n                    if ((memberValue & constantToDecode) == memberValue)\n                    {\n                        // update the current value\n                        curValue = curValue | memberValue;\n\n                        var valueExpression = type.Member(field.Name);\n                        if (result is null)\n                        {\n                            result = valueExpression;\n                        }\n                        else\n                        {\n                            result = BinaryExpression(SyntaxKind.BitwiseOrExpression, result, valueExpression);\n                        }\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        private static ulong ConvertToUInt64(object value)\n        {\n            return value switch\n            {\n                byte b => b,\n                sbyte sb => (ulong)sb,\n                short s => (ulong)s,\n                ushort us => us,\n                int i => (ulong)i,\n                uint ui => ui,\n                long l => (ulong)l,\n                ulong ul => ul,\n                _ => throw new NotSupportedException($\"Type {value?.GetType()} not supported\")\n            };\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/SyntaxGeneration/SyntaxFactoryUtility.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;\n\nnamespace Orleans.CodeGenerator.SyntaxGeneration\n{\n    internal static class SyntaxFactoryUtility\n    {\n        /// <summary>\n        /// Returns member access syntax.\n        /// </summary>\n        /// <param name=\"instance\">\n        /// The instance.\n        /// </param>\n        /// <param name=\"member\">\n        /// The member.\n        /// </param>\n        /// <returns>\n        /// The resulting <see cref=\"MemberAccessExpressionSyntax\"/>.\n        /// </returns>\n        public static MemberAccessExpressionSyntax Member(this ExpressionSyntax instance, string member) => instance.Member(member.ToIdentifierName());\n\n        /// <summary>\n        /// Returns member access syntax.\n        /// </summary>\n        /// <param name=\"instance\">\n        /// The instance.\n        /// </param>\n        /// <param name=\"member\">\n        /// The member.\n        /// </param>\n        /// <returns>\n        /// The resulting <see cref=\"MemberAccessExpressionSyntax\"/>.\n        /// </returns>\n        public static MemberAccessExpressionSyntax Member(this ExpressionSyntax instance, IdentifierNameSyntax member) => MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, instance, member);\n\n        public static MemberAccessExpressionSyntax Member(this ExpressionSyntax instance, GenericNameSyntax member) => MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, instance, member);\n\n        public static MemberAccessExpressionSyntax Member(\n            this ExpressionSyntax instance,\n            string member,\n            params TypeSyntax[] genericTypes) => instance.Member(\n                    member.ToGenericName()\n                        .AddTypeArgumentListArguments(genericTypes));\n\n        public static GenericNameSyntax ToGenericName(this string identifier) => GenericName(identifier.ToIdentifier());\n\n        public static ClassDeclarationSyntax AddGenericTypeParameters(\n            ClassDeclarationSyntax classDeclaration,\n            List<(string Name, ITypeParameterSymbol Parameter)> typeParameters)\n        {\n            var typeParametersWithConstraints = GetTypeParameterConstraints(typeParameters);\n            foreach (var (name, constraints) in typeParametersWithConstraints)\n            {\n                if (constraints.Count > 0)\n                {\n                    classDeclaration = classDeclaration.AddConstraintClauses(\n                        TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray()));\n                }\n            }\n\n            if (typeParametersWithConstraints.Count > 0)\n            {\n                classDeclaration = classDeclaration.WithTypeParameterList(\n                    TypeParameterList(SeparatedList(typeParametersWithConstraints.Select(tp => TypeParameter(tp.Name)))));\n            }\n\n            return classDeclaration;\n        }\n\n        public static List<(string Name, List<TypeParameterConstraintSyntax> Constraints)> GetTypeParameterConstraints(List<(string Name, ITypeParameterSymbol Parameter)> typeParameter)\n        {\n            var allConstraints = new List<(string, List<TypeParameterConstraintSyntax>)>();\n            foreach (var (name, tp) in typeParameter)\n            {\n                var constraints = new List<TypeParameterConstraintSyntax>();\n\n                if (tp.HasUnmanagedTypeConstraint)\n                {\n                    constraints.Add(TypeConstraint(IdentifierName(\"unmanaged\")));\n                }\n                else if (tp.HasValueTypeConstraint)\n                {\n                    constraints.Add(ClassOrStructConstraint(SyntaxKind.StructConstraint));\n                }\n                else if (tp.HasNotNullConstraint)\n                {\n                    constraints.Add(TypeConstraint(IdentifierName(\"notnull\")));\n                }\n                else if (tp.HasReferenceTypeConstraint)\n                {\n                    constraints.Add(ClassOrStructConstraint(SyntaxKind.ClassConstraint));\n                }\n\n                foreach (var c in tp.ConstraintTypes)\n                {\n                    constraints.Add(TypeConstraint(c.ToTypeSyntax()));\n                }\n\n                if (tp.HasConstructorConstraint)\n                {\n                    constraints.Add(ConstructorConstraint());\n                }\n\n                allConstraints.Add((name, constraints));\n            }\n\n            return allConstraints;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.CodeGenerator/build/Microsoft.Orleans.CodeGenerator.props",
    "content": "<Project>\n\n  <ItemGroup>\n    <CompilerVisibleProperty Include=\"Orleans_DesignTimeBuild\" />\n    <CompilerVisibleProperty Include=\"Orleans_AttachDebugger\" />\n    <CompilerVisibleProperty Include=\"Orleans_GenerateFieldIds\" />\n    <CompilerVisibleProperty Include=\"Orleans_ConstructorAttributes\" />\n    <CompilerVisibleProperty Include=\"OrleansGenerateCompatibilityInvokers\" />\n  </ItemGroup>\n\n  <PropertyGroup>\n    <Orleans_DesignTimeBuild>$(DesignTimeBuild)</Orleans_DesignTimeBuild>\n    <Orleans_GenerateFieldIds>$(OrleansGenerateFieldIds)</Orleans_GenerateFieldIds>\n    <Orleans_ConstructorAttributes>$(OrleansConstructorAttributes)</Orleans_ConstructorAttributes>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.CodeGenerator/buildMultiTargeting/Microsoft.Orleans.CodeGenerator.props",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.CodeGenerator.props\" />\n</Project>"
  },
  {
    "path": "src/Orleans.CodeGenerator/buildTransitive/Microsoft.Orleans.CodeGenerator.props",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.CodeGenerator.props\" />\n</Project>"
  },
  {
    "path": "src/Orleans.Connections.Security/Hosting/HostingExtensions.IClientBuilder.cs",
    "content": "using System;\nusing System.Security.Cryptography.X509Certificates;\nusing Orleans.Configuration;\nusing Orleans.Connections.Security;\n\nnamespace Orleans.Hosting\n{\n    public static partial class OrleansConnectionSecurityHostingExtensions\n    {\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"storeName\">The certificate store to load the certificate from.</param>\n        /// <param name=\"subject\">The subject name for the certificate to load.</param>\n        /// <param name=\"allowInvalid\">Indicates if invalid certificates should be considered, such as self-signed certificates.</param>\n        /// <param name=\"location\">The store location to load the certificate from.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder UseTls(\n            this IClientBuilder builder,\n            StoreName storeName,\n            string subject,\n            bool allowInvalid,\n            StoreLocation location,\n            Action<TlsOptions> configureOptions)\n        {\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            return builder.UseTls(\n                CertificateLoader.LoadFromStoreCert(subject, storeName.ToString(), location, allowInvalid, server: false),\n                configureOptions);\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"certificate\">The server certificate.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder UseTls(\n            this IClientBuilder builder,\n            X509Certificate2 certificate,\n            Action<TlsOptions> configureOptions)\n        {\n            if (certificate is null)\n            {\n                throw new ArgumentNullException(nameof(certificate));\n            }\n\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            if (!certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, nameof(certificate));\n            }\n\n            return builder.UseTls(options =>\n            {\n                options.LocalCertificate = certificate;\n                configureOptions(options);\n            });\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"certificate\">The server certificate.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder UseTls(\n            this IClientBuilder builder,\n            X509Certificate2 certificate)\n        {\n            if (certificate is null)\n            {\n                throw new ArgumentNullException(nameof(certificate));\n            }\n\n            if (!certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, nameof(certificate));\n            }\n\n            return builder.UseTls(options =>\n            {\n                options.LocalCertificate = certificate;\n            });\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder UseTls(\n            this IClientBuilder builder,\n            Action<TlsOptions> configureOptions)\n        {\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            var options = new TlsOptions();\n            configureOptions(options);\n            if (options.LocalCertificate is null && options.ClientCertificateMode == RemoteCertificateMode.RequireCertificate)\n            {\n                throw new InvalidOperationException(\"No certificate specified\");\n            }\n\n            if (options.LocalCertificate is X509Certificate2 certificate && !certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, $\"{nameof(TlsOptions)}.{nameof(TlsOptions.LocalCertificate)}\");\n            }\n\n            return builder.Configure<ClientConnectionOptions>(connectionOptions =>\n            {\n                connectionOptions.ConfigureConnection(connectionBuilder =>\n                {\n                    connectionBuilder.UseClientTls(options);\n                });\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Hosting/HostingExtensions.ISiloBuilder.cs",
    "content": "using System;\nusing System.Security.Cryptography.X509Certificates;\nusing Orleans.Configuration;\nusing Orleans.Connections.Security;\n\nnamespace Orleans.Hosting\n{\n    public static partial class OrleansConnectionSecurityHostingExtensions\n    {\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"storeName\">The certificate store to load the certificate from.</param>\n        /// <param name=\"subject\">The subject name for the certificate to load.</param>\n        /// <param name=\"allowInvalid\">Indicates if invalid certificates should be considered, such as self-signed certificates.</param>\n        /// <param name=\"location\">The store location to load the certificate from.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder UseTls(\n            this ISiloBuilder builder,\n            StoreName storeName,\n            string subject,\n            bool allowInvalid,\n            StoreLocation location,\n            Action<TlsOptions> configureOptions)\n        {\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            return builder.UseTls(\n                CertificateLoader.LoadFromStoreCert(subject, storeName.ToString(), location, allowInvalid, server: true),\n                configureOptions);\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"certificate\">The server certificate.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder UseTls(\n            this ISiloBuilder builder,\n            X509Certificate2 certificate,\n            Action<TlsOptions> configureOptions)\n        {\n            if (certificate is null)\n            {\n                throw new ArgumentNullException(nameof(certificate));\n            }\n\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            if (!certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, nameof(certificate));\n            }\n\n            return builder.UseTls(options =>\n            {\n                options.LocalCertificate = certificate;\n                configureOptions(options);\n            });\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"certificate\">The server certificate.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder UseTls(\n            this ISiloBuilder builder,\n            X509Certificate2 certificate)\n        {\n            if (certificate is null)\n            {\n                throw new ArgumentNullException(nameof(certificate));\n            }\n\n            if (!certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, nameof(certificate));\n            }\n\n            return builder.UseTls(options =>\n            {\n                options.LocalCertificate = certificate;\n            });\n        }\n\n        /// <summary>\n        /// Configures TLS.\n        /// </summary>\n        /// <param name=\"builder\">The builder to configure.</param>\n        /// <param name=\"configureOptions\">An Action to configure the <see cref=\"TlsOptions\"/>.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder UseTls(\n            this ISiloBuilder builder,\n            Action<TlsOptions> configureOptions)\n        {\n            if (configureOptions is null)\n            {\n                throw new ArgumentNullException(nameof(configureOptions));\n            }\n\n            var options = new TlsOptions();\n            configureOptions(options);\n            if (options.LocalCertificate is null && options.LocalServerCertificateSelector is null)\n            {\n                throw new InvalidOperationException(\"No certificate specified\");\n            }\n\n            if (options.LocalCertificate is X509Certificate2 certificate && !certificate.HasPrivateKey)\n            {\n                TlsConnectionBuilderExtensions.ThrowNoPrivateKey(certificate, $\"{nameof(TlsOptions)}.{nameof(TlsOptions.LocalCertificate)}\");\n            }\n\n            return builder.Configure<SiloConnectionOptions>(connectionOptions =>\n            {\n                connectionOptions.ConfigureSiloInboundConnection(connectionBuilder =>\n                {\n                    connectionBuilder.UseServerTls(options);\n                });\n\n                connectionOptions.ConfigureGatewayInboundConnection(connectionBuilder =>\n                {\n                    connectionBuilder.UseServerTls(options);\n                });\n\n                connectionOptions.ConfigureSiloOutboundConnection(connectionBuilder =>\n                {\n                    connectionBuilder.UseClientTls(options);\n                });\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Hosting/HostingExtensions.cs",
    "content": "using System;\nusing System.Security.Cryptography.X509Certificates;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Connections.Security;\n\nnamespace Orleans\n{\n    public static class TlsConnectionBuilderExtensions\n    {\n        public static void UseServerTls(\n            this IConnectionBuilder builder,\n            TlsOptions options)\n        {\n            if (options is null)\n            {\n                throw new ArgumentNullException(nameof(options));\n            }\n\n            var loggerFactory = builder.ApplicationServices.GetService(typeof(ILoggerFactory)) as ILoggerFactory ?? NullLoggerFactory.Instance;\n            builder.Use(next =>\n            {\n                var middleware = new TlsServerConnectionMiddleware(next, options, loggerFactory);\n                return middleware.OnConnectionAsync;\n            });\n        }\n\n        public static void UseClientTls(\n            this IConnectionBuilder builder,\n            TlsOptions options)\n        {\n            if (options is null)\n            {\n                throw new ArgumentNullException(nameof(options));\n            }\n\n            var loggerFactory = builder.ApplicationServices.GetService(typeof(ILoggerFactory)) as ILoggerFactory ?? NullLoggerFactory.Instance;\n            builder.Use(next =>\n            {\n                var middleware = new TlsClientConnectionMiddleware(next, options, loggerFactory);\n                return middleware.OnConnectionAsync;\n            });\n        }\n\n        internal static void ThrowNoPrivateKey(X509Certificate2 certificate, string parameterName)\n        {\n            throw new ArgumentException($\"Certificate {certificate.ToString(verbose: true)} does not contain a private key\", parameterName);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Orleans.Connections.Security.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Connections.Security</PackageId>\n    <Title>Microsoft Orleans TLS support</Title>\n    <Description>Support for security communication using TLS in Microsoft Orleans.</Description>\n    <PackageTags>$(PackageTags) TLS SSL</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/CertificateLoader.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Orleans.Connections.Security\n{\n    public static class CertificateLoader\n    {\n        // See http://oid-info.com/get/1.3.6.1.5.5.7.3.1\n        // Indicates that a certificate can be used as a TLS server certificate\n        private const string ServerAuthenticationOid = \"1.3.6.1.5.5.7.3.1\";\n\n        // See http://oid-info.com/get/1.3.6.1.5.5.7.3.2\n        // Indicates that a certificate can be used as a TLS client certificate\n        private const string ClientAuthenticationOid = \"1.3.6.1.5.5.7.3.2\";\n\n        public static X509Certificate2 LoadFromStoreCert(string subject, string storeName, StoreLocation storeLocation, bool allowInvalid, bool server)\n        {\n            using (var store = new X509Store(storeName, storeLocation))\n            {\n                X509Certificate2Collection storeCertificates = null;\n                X509Certificate2 foundCertificate = null;\n\n                try\n                {\n                    store.Open(OpenFlags.ReadOnly);\n                    storeCertificates = store.Certificates;\n                    var foundCertificates = storeCertificates.Find(X509FindType.FindBySubjectName, subject, !allowInvalid);\n                    foundCertificate = foundCertificates\n                        .OfType<X509Certificate2>()\n                        .Where(c => server ? IsCertificateAllowedForServerAuth(c) : IsCertificateAllowedForClientAuth(c))\n                        .Where(DoesCertificateHaveAnAccessiblePrivateKey)\n                        .OrderByDescending(certificate => certificate.NotAfter)\n                        .FirstOrDefault();\n\n                    if (foundCertificate == null)\n                    {\n                        throw new InvalidOperationException($\"Certificate {subject} not found in store {storeLocation} / {storeName}. AllowInvalid: {allowInvalid}\");\n                    }\n\n                    return foundCertificate;\n                }\n                finally\n                {\n                    DisposeCertificates(storeCertificates, except: foundCertificate);\n                }\n            }\n        }\n\n        internal static bool IsCertificateAllowedForServerAuth(X509Certificate2 certificate) => IsCertificateAllowedForKeyUsage(certificate, ServerAuthenticationOid);\n\n        internal static bool IsCertificateAllowedForClientAuth(X509Certificate2 certificate) => IsCertificateAllowedForKeyUsage(certificate, ClientAuthenticationOid);\n\n        private static bool IsCertificateAllowedForKeyUsage(X509Certificate2 certificate, string purposeOid)\n        {\n            /* If the Extended Key Usage extension is included, then we check that the serverAuth usage is included. (http://oid-info.com/get/1.3.6.1.5.5.7.3.1)\n             * If the Extended Key Usage extension is not included, then we assume the certificate is allowed for all usages.\n             *\n             * See also https://blogs.msdn.microsoft.com/kaushal/2012/02/17/client-certificates-vs-server-certificates/\n             *\n             * From https://tools.ietf.org/html/rfc3280#section-4.2.1.13 \"Certificate Extensions: Extended Key Usage\"\n             *\n             * If the (Extended Key Usage) extension is present, then the certificate MUST only be used\n             * for one of the purposes indicated.  If multiple purposes are\n             * indicated the application need not recognize all purposes indicated,\n             * as long as the intended purpose is present.  Certificate using\n             * applications MAY require that a particular purpose be indicated in\n             * order for the certificate to be acceptable to that application.\n             */\n\n            var hasEkuExtension = false;\n\n            foreach (var extension in certificate.Extensions.OfType<X509EnhancedKeyUsageExtension>())\n            {\n                hasEkuExtension = true;\n                foreach (var oid in extension.EnhancedKeyUsages)\n                {\n                    if (oid.Value.Equals(purposeOid, StringComparison.Ordinal))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return !hasEkuExtension;\n        }\n\n        internal static bool DoesCertificateHaveAnAccessiblePrivateKey(X509Certificate2 certificate)\n            => certificate.HasPrivateKey;\n\n        private static void DisposeCertificates(X509Certificate2Collection certificates, X509Certificate2 except)\n        {\n            if (certificates != null)\n            {\n                foreach (var certificate in certificates)\n                {\n                    if (!certificate.Equals(except))\n                    {\n                        certificate.Dispose();\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/DuplexPipeStream.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.IO;\nusing System.IO.Pipelines;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Connections.Security\n{\n    internal class DuplexPipeStream : Stream\n    {\n        private readonly PipeReader _reader;\n        private readonly PipeWriter _writer;\n\n        public override bool CanRead => true;\n        public override bool CanSeek => false;\n        public override bool CanWrite => true;\n        public override long Length => throw new NotSupportedException();\n        public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }\n\n        public DuplexPipeStream(IDuplexPipe pipe)\n        {\n            _reader = pipe.Input;\n            _writer = pipe.Output;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                _reader.Complete();\n                _writer.Complete();\n            }\n            base.Dispose(disposing);\n        }\n\n        public override async ValueTask DisposeAsync()\n        {\n            await _reader.CompleteAsync().ConfigureAwait(false);\n            await _writer.CompleteAsync().ConfigureAwait(false);\n        }\n\n        public override void Flush()\n        {\n            FlushAsync().GetAwaiter().GetResult();\n        }\n\n        public override async Task FlushAsync(CancellationToken cancellationToken)\n        {\n            FlushResult r = await _writer.FlushAsync(cancellationToken).ConfigureAwait(false);\n            if (r.IsCanceled) throw new OperationCanceledException(cancellationToken);\n        }\n\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n            ValidateBufferArguments(buffer, offset, count);\n\n            ValueTask<int> t = ReadAsync(buffer.AsMemory(offset, count));\n            return\n                t.IsCompleted ? t.GetAwaiter().GetResult() :\n                t.AsTask().GetAwaiter().GetResult();\n        }\n\n        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)\n        {\n            ValidateBufferArguments(buffer, offset, count);\n\n            return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();\n        }\n\n        public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)\n        {\n            ReadResult result = await _reader.ReadAsync(cancellationToken).ConfigureAwait(false);\n\n            if (result.IsCanceled)\n            {\n                throw new OperationCanceledException();\n            }\n\n            ReadOnlySequence<byte> sequence = result.Buffer;\n            long bufferLength = sequence.Length;\n            SequencePosition consumed = sequence.Start;\n\n            try\n            {\n                if (bufferLength != 0)\n                {\n                    int actual = (int)Math.Min(bufferLength, buffer.Length);\n\n                    ReadOnlySequence<byte> slice = actual == bufferLength ? sequence : sequence.Slice(0, actual);\n                    consumed = slice.End;\n                    slice.CopyTo(buffer.Span);\n\n                    return actual;\n                }\n\n                if (result.IsCompleted)\n                {\n                    return 0;\n                }\n            }\n            finally\n            {\n                _reader.AdvanceTo(consumed);\n            }\n\n            // This is a buggy PipeReader implementation that returns 0 byte reads even though the PipeReader\n            // isn't completed or canceled.\n            throw new InvalidOperationException(\"Read zero bytes unexpectedly\");\n        }\n\n        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)\n        {\n            return TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state);\n        }\n\n        public override int EndRead(IAsyncResult asyncResult)\n        {\n            return TaskToApm.End<int>(asyncResult);\n        }\n\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void SetLength(long value)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void Write(byte[] buffer, int offset, int count)\n        {\n            WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();\n        }\n\n        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)\n        {\n            ValidateBufferArguments(buffer, offset, count);\n\n            return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();\n        }\n\n        public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)\n        {\n            FlushResult r = await _writer.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);\n            if (r.IsCanceled) throw new OperationCanceledException(cancellationToken);\n        }\n\n        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)\n        {\n            return TaskToApm.Begin(WriteAsync(buffer, offset, count), callback, state);\n        }\n\n        public override void EndWrite(IAsyncResult asyncResult)\n        {\n            TaskToApm.End(asyncResult);\n        }\n\n        public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)\n        {\n            return _reader.CopyToAsync(destination, cancellationToken);\n        }\n\n        /// <summary>\n        /// Provides support for efficiently using Tasks to implement the APM (Begin/End) pattern.\n        /// </summary>\n        internal static class TaskToApm\n        {\n            /// <summary>\n            /// Marshals the Task as an IAsyncResult, using the supplied callback and state\n            /// to implement the APM pattern.\n            /// </summary>\n            /// <param name=\"task\">The Task to be marshaled.</param>\n            /// <param name=\"callback\">The callback to be invoked upon completion.</param>\n            /// <param name=\"state\">The state to be stored in the IAsyncResult.</param>\n            /// <returns>An IAsyncResult to represent the task's asynchronous operation.</returns>\n            public static IAsyncResult Begin(Task task, AsyncCallback callback, object state) =>\n                new TaskAsyncResult(task, state, callback);\n\n            /// <summary>Processes an IAsyncResult returned by Begin.</summary>\n            /// <param name=\"asyncResult\">The IAsyncResult to unwrap.</param>\n            public static void End(IAsyncResult asyncResult)\n            {\n                if (GetTask(asyncResult) is Task t)\n                {\n                    t.GetAwaiter().GetResult();\n                    return;\n                }\n\n                ThrowArgumentException(asyncResult);\n            }\n\n            /// <summary>Processes an IAsyncResult returned by Begin.</summary>\n            /// <param name=\"asyncResult\">The IAsyncResult to unwrap.</param>\n            public static TResult End<TResult>(IAsyncResult asyncResult)\n            {\n                if (GetTask(asyncResult) is Task<TResult> task)\n                {\n                    return task.GetAwaiter().GetResult();\n                }\n\n                ThrowArgumentException(asyncResult);\n                return default!; // unreachable\n            }\n\n            /// <summary>Gets the task represented by the IAsyncResult.</summary>\n            public static Task GetTask(IAsyncResult asyncResult) => (asyncResult as TaskAsyncResult)?._task;\n\n            /// <summary>Throws an argument exception for the invalid <paramref name=\"asyncResult\"/>.</summary>\n            private static void ThrowArgumentException(IAsyncResult asyncResult) =>\n                throw (asyncResult is null ?\n                    new ArgumentNullException(nameof(asyncResult)) :\n                    new ArgumentException(null, nameof(asyncResult)));\n\n            /// <summary>Provides a simple IAsyncResult that wraps a Task.</summary>\n            /// <remarks>\n            /// We could use the Task as the IAsyncResult if the Task's AsyncState is the same as the object state,\n            /// but that's very rare, in particular in a situation where someone cares about allocation, and always\n            /// using TaskAsyncResult simplifies things and enables additional optimizations.\n            /// </remarks>\n            internal sealed class TaskAsyncResult : IAsyncResult\n            {\n                /// <summary>The wrapped Task.</summary>\n                internal readonly Task _task;\n                /// <summary>Callback to invoke when the wrapped task completes.</summary>\n                private readonly AsyncCallback _callback;\n\n                /// <summary>Initializes the IAsyncResult with the Task to wrap and the associated object state.</summary>\n                /// <param name=\"task\">The Task to wrap.</param>\n                /// <param name=\"state\">The new AsyncState value.</param>\n                /// <param name=\"callback\">Callback to invoke when the wrapped task completes.</param>\n                internal TaskAsyncResult(Task task, object state, AsyncCallback callback)\n                {\n                    Debug.Assert(task != null);\n                    _task = task;\n                    AsyncState = state;\n\n                    if (task.IsCompleted)\n                    {\n                        // Synchronous completion.  Invoke the callback.  No need to store it.\n                        CompletedSynchronously = true;\n                        callback?.Invoke(this);\n                    }\n                    else if (callback != null)\n                    {\n                        // Asynchronous completion, and we have a callback; schedule it. We use OnCompleted rather than ContinueWith in\n                        // order to avoid running synchronously if the task has already completed by the time we get here but still run\n                        // synchronously as part of the task's completion if the task completes after (the more common case).\n                        _callback = callback;\n                        _task.ConfigureAwait(continueOnCapturedContext: false)\n                             .GetAwaiter()\n                             .OnCompleted(InvokeCallback); // allocates a delegate, but avoids a closure\n                    }\n                }\n\n                /// <summary>Invokes the callback.</summary>\n                private void InvokeCallback()\n                {\n                    Debug.Assert(!CompletedSynchronously);\n                    Debug.Assert(_callback != null);\n                    _callback.Invoke(this);\n                }\n\n                /// <summary>Gets a user-defined object that qualifies or contains information about an asynchronous operation.</summary>\n                public object AsyncState { get; }\n                /// <summary>Gets a value that indicates whether the asynchronous operation completed synchronously.</summary>\n                /// <remarks>This is set lazily based on whether the <see cref=\"_task\"/> has completed by the time this object is created.</remarks>\n                public bool CompletedSynchronously { get; }\n                /// <summary>Gets a value that indicates whether the asynchronous operation has completed.</summary>\n                public bool IsCompleted => _task.IsCompleted;\n                /// <summary>Gets a <see cref=\"WaitHandle\"/> that is used to wait for an asynchronous operation to complete.</summary>\n                public WaitHandle AsyncWaitHandle => ((IAsyncResult)_task).AsyncWaitHandle;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/DuplexPipeStreamAdapter.cs",
    "content": "using System;\nusing System.IO;\nusing System.IO.Pipelines;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Connections.Security\n{\n    /// <summary>\n    /// A helper for wrapping a Stream decorator from an <see cref=\"IDuplexPipe\"/>.\n    /// </summary>\n    /// <typeparam name=\"TStream\"></typeparam>\n    internal class DuplexPipeStreamAdapter<TStream> : DuplexPipeStream, IDuplexPipe where TStream : Stream\n    {\n        private bool _disposed;\n#if NET9_0_OR_GREATER\n        private readonly Lock _disposeLock = new();\n#else\n        private readonly object _disposeLock = new();\n#endif\n\n        public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, Func<Stream, TStream> createStream) :\n            this(duplexPipe, new StreamPipeReaderOptions(leaveOpen: true), new StreamPipeWriterOptions(leaveOpen: true), createStream)\n        {\n        }\n\n        public DuplexPipeStreamAdapter(IDuplexPipe duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func<Stream, TStream> createStream) :\n            base(duplexPipe)\n        {\n            var stream = createStream(this);\n            Stream = stream;\n            Input = PipeReader.Create(stream, readerOptions);\n            Output = PipeWriter.Create(stream, writerOptions);\n        }\n\n        public TStream Stream { get; }\n\n        public PipeReader Input { get; }\n\n        public PipeWriter Output { get; }\n\n        public override async ValueTask DisposeAsync()\n        {\n            lock (_disposeLock)\n            {\n                if (_disposed)\n                {\n                    return;\n                }\n                _disposed = true;\n            }\n\n            await Input.CompleteAsync();\n            await Output.CompleteAsync();\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            lock (_disposeLock)\n            {\n                if (_disposed)\n                {\n                    return;\n                }\n                _disposed = true;\n            }\n\n            if (disposing)\n            {\n                Input.Complete();\n                Output.Complete();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/ITlsApplicationProtocolFeature.cs",
    "content": "using System;\n\nnamespace Orleans.Connections.Security\n{\n    public interface ITlsApplicationProtocolFeature\n    {\n        ReadOnlyMemory<byte> ApplicationProtocol { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/ITlsConnectionFeature.cs",
    "content": "using System.Security.Cryptography.X509Certificates;\nusing System.Threading.Tasks;\nusing System.Threading;\n\nnamespace Orleans.Connections.Security\n{\n    public interface ITlsConnectionFeature\n    {\n        /// <summary>\n        /// Synchronously retrieves the remote endpoint's certificate, if any.\n        /// </summary>\n        X509Certificate2 RemoteCertificate { get; set; }\n\n        /// <summary>\n        /// Asynchronously retrieves the remote endpoint's certificate, if any.\n        /// </summary>\n        /// <returns></returns>\n        Task<X509Certificate2> GetRemoteCertificateAsync(CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/ITlsHandshakeFeature.cs",
    "content": "using System;\nusing System.Net.Security;\nusing System.Security.Authentication;\n\nnamespace Orleans.Connections.Security\n{\n    public interface ITlsHandshakeFeature\n    {\n        SslProtocols Protocol { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"TlsCipherSuite\"/>.\n        /// </summary>\n        TlsCipherSuite? NegotiatedCipherSuite => null;\n\n        /// <summary>\n        /// Gets the host name from the \"server_name\" (SNI) extension of the client hello if present.\n        /// </summary>\n        string HostName => string.Empty;\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        CipherAlgorithmType CipherAlgorithm { get; }\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        int CipherStrength { get; }\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        HashAlgorithmType HashAlgorithm { get; }\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        int HashStrength { get; }\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        ExchangeAlgorithmType KeyExchangeAlgorithm { get; }\n\n#if NET10_0_OR_GREATER\n        [Obsolete(\"KeyExchangeAlgorithm, KeyExchangeStrength, CipherAlgorithm, CipherStrength, HashAlgorithm and HashStrength properties are obsolete. Use NegotiatedCipherSuite instead.\", DiagnosticId = \"SYSLIB0058\", UrlFormat = \"https://aka.ms/dotnet-warnings/{0}\")]\n#endif\n        int KeyExchangeStrength { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/MemoryPoolExtensions.cs",
    "content": "using System;\nusing System.Buffers;\n\nnamespace Orleans.Connections.Security\n{\n    internal static class MemoryPoolExtensions\n    {\n        /// <summary>\n        /// Computes a minimum segment size\n        /// </summary>\n        /// <param name=\"pool\"></param>\n        /// <returns></returns>\n        public static int GetMinimumSegmentSize(this MemoryPool<byte> pool)\n        {\n            if (pool == null)\n            {\n                return 4096;\n            }\n\n            return Math.Min(4096, pool.MaxBufferSize);\n        }\n\n        public static int GetMinimumAllocSize(this MemoryPool<byte> pool)\n        {\n            // 1/2 of a segment\n            return pool.GetMinimumSegmentSize() / 2;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/OrleansApplicationProtocol.cs",
    "content": "using System.Net.Security;\n\nnamespace Orleans.Connections.Security\n{\n    internal static class OrleansApplicationProtocol\n    {\n        public static readonly SslApplicationProtocol Orleans1 = new SslApplicationProtocol(\"Orleans1\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/RemoteCertificateMode.cs",
    "content": "namespace Orleans.Connections.Security\n{\n    /// <summary>\n    /// Describes the remote certificate requirements for a TLS connection.\n    /// </summary>\n    public enum RemoteCertificateMode\n    {\n        /// <summary>\n        /// A remote certificate is not required and will not be requested from remote endpoints.\n        /// </summary>\n        NoCertificate,\n\n        /// <summary>\n        /// A remote certificate will be requested; however, authentication will not fail if a certificate is not provided by the remote endpoint.\n        /// </summary>\n        AllowCertificate,\n\n        /// <summary>\n        /// A remote certificate will be requested, and the remote endpoint must provide a valid certificate for authentication.\n        /// </summary>\n        RequireCertificate\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsClientAuthenticationOptions.cs",
    "content": "using System.Collections.Generic;\nusing System.Net.Security;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Orleans.Connections.Security\n{\n    public delegate X509Certificate ClientCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers);\n\n    public class TlsClientAuthenticationOptions\n    {\n        internal SslClientAuthenticationOptions Value { get; } = new SslClientAuthenticationOptions\n        {\n            ApplicationProtocols = new List<SslApplicationProtocol>\n            {\n                OrleansApplicationProtocol.Orleans1\n            }\n        };\n\n        public ClientCertificateSelectionCallback LocalCertificateSelectionCallback\n        {\n            get => Value.LocalCertificateSelectionCallback is null ? null : new ClientCertificateSelectionCallback(Value.LocalCertificateSelectionCallback);\n            set => Value.LocalCertificateSelectionCallback = value is null ? null : new System.Net.Security.LocalCertificateSelectionCallback(value);\n        }\n\n        public X509CertificateCollection ClientCertificates\n        {\n            get => this.Value.ClientCertificates;\n            set => this.Value.ClientCertificates = value;\n        }\n\n        public SslProtocols EnabledSslProtocols\n        {\n            get => this.Value.EnabledSslProtocols;\n            set => this.Value.EnabledSslProtocols = value;\n        }\n\n        public X509RevocationMode CertificateRevocationCheckMode\n        {\n            get => this.Value.CertificateRevocationCheckMode;\n            set => this.Value.CertificateRevocationCheckMode = value;\n        }\n\n        public string TargetHost\n        {\n            get => this.Value.TargetHost;\n            set => this.Value.TargetHost = value;\n        }\n\n        public object SslClientAuthenticationOptions => this.Value;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsClientConnectionMiddleware.cs",
    "content": "using System;\nusing System.IO.Pipelines;\nusing System.Net.Security;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.AspNetCore.Connections.Features;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Connections.Security\n{\n    internal class TlsClientConnectionMiddleware\n    {\n        private readonly ConnectionDelegate _next;\n        private readonly TlsOptions _options;\n        private readonly ILogger _logger;\n        private readonly X509Certificate2 _certificate;\n        private readonly Func<object, string, X509CertificateCollection, X509Certificate, string[], X509Certificate2> _certificateSelector;\n\n        public TlsClientConnectionMiddleware(ConnectionDelegate next, TlsOptions options, ILoggerFactory loggerFactory)\n        {\n            if (options == null)\n            {\n                throw new ArgumentNullException(nameof(options));\n            }\n\n            _next = next;\n\n            // capture the certificate now so it can't be switched after validation\n            _certificate = ValidateCertificate(options.LocalCertificate, options.ClientCertificateMode);\n            _certificateSelector = options.LocalClientCertificateSelector;\n\n\n            _options = options;\n            _logger = loggerFactory?.CreateLogger<TlsClientConnectionMiddleware>();\n        }\n\n        public Task OnConnectionAsync(ConnectionContext context)\n        {\n            return InnerOnConnectionAsync(context);\n        }\n\n        private async Task InnerOnConnectionAsync(ConnectionContext context)\n        {\n            var feature = new TlsConnectionFeature();\n            context.Features.Set<ITlsConnectionFeature>(feature);\n            context.Features.Set<ITlsHandshakeFeature>(feature);\n\n            var memoryPool = context.Features.Get<IMemoryPoolFeature>()?.MemoryPool;\n\n            var inputPipeOptions = new StreamPipeReaderOptions\n            (\n                pool: memoryPool,\n                bufferSize: memoryPool.GetMinimumSegmentSize(),\n                minimumReadSize: memoryPool.GetMinimumAllocSize(),\n                leaveOpen: true\n            );\n\n            var outputPipeOptions = new StreamPipeWriterOptions\n            (\n                pool: memoryPool,\n                leaveOpen: true\n            );\n\n            TlsDuplexPipe tlsDuplexPipe = null;\n\n            if (_options.RemoteCertificateMode == RemoteCertificateMode.NoCertificate)\n            {\n                tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions);\n            }\n            else\n            {\n                tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream(\n                    s,\n                    leaveInnerStreamOpen: false,\n                    userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) =>\n                    {\n                        if (certificate == null)\n                        {\n                            return _options.RemoteCertificateMode != RemoteCertificateMode.RequireCertificate;\n                        }\n\n                        if (_options.RemoteCertificateValidation == null)\n                        {\n                            if (sslPolicyErrors != SslPolicyErrors.None)\n                            {\n                                return false;\n                            }\n                        }\n\n                        var certificate2 = ConvertToX509Certificate2(certificate);\n                        if (certificate2 == null)\n                        {\n                            return false;\n                        }\n\n                        if (_options.RemoteCertificateValidation != null)\n                        {\n                            if (!_options.RemoteCertificateValidation(certificate2, chain, sslPolicyErrors))\n                            {\n                                return false;\n                            }\n                        }\n\n                        return true;\n                    }));\n            }\n\n            var sslStream = tlsDuplexPipe.Stream;\n\n            using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout))\n            using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context))\n            {\n                try\n                {\n                    ClientCertificateSelectionCallback selector = null;\n                    if (_certificateSelector != null)\n                    {\n                        selector = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =>\n                        {\n                            var cert = _certificateSelector(sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers);\n                            if (cert != null)\n                            {\n                                EnsureCertificateIsAllowedForClientAuth(cert);\n                            }\n\n                            return cert;\n                        };\n                    }\n\n                    var sslOptions = new TlsClientAuthenticationOptions\n                    {\n                        ClientCertificates = _certificate == null || _certificateSelector != null ? null : new X509CertificateCollection { _certificate },\n                        LocalCertificateSelectionCallback = selector,\n                        EnabledSslProtocols = _options.SslProtocols,\n                    };\n\n                    _options.OnAuthenticateAsClient?.Invoke(context, sslOptions);\n\n                    await sslStream.AuthenticateAsClientAsync(sslOptions.Value, cancellationTokeSource.Token);\n                }\n                catch (OperationCanceledException ex)\n                {\n                    _logger?.LogWarning(2, ex, \"Authentication timed out\");\n                    await sslStream.DisposeAsync();\n                    return;\n                }\n                catch (Exception ex)\n                {\n                    _logger?.LogWarning(1, ex, \"Authentication failed\");\n                    await sslStream.DisposeAsync();\n                    return;\n                }\n            }\n\n            feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol;\n\n            context.Features.Set<ITlsApplicationProtocolFeature>(feature);\n            feature.LocalCertificate = ConvertToX509Certificate2(sslStream.LocalCertificate);\n            feature.RemoteCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);\n            feature.NegotiatedCipherSuite = sslStream.NegotiatedCipherSuite;\n#if NET10_0_OR_GREATER\n#pragma warning disable SYSLIB0058\n#endif\n            feature.CipherAlgorithm = sslStream.CipherAlgorithm;\n            feature.CipherStrength = sslStream.CipherStrength;\n            feature.HashAlgorithm = sslStream.HashAlgorithm;\n            feature.HashStrength = sslStream.HashStrength;\n            feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm;\n            feature.KeyExchangeStrength = sslStream.KeyExchangeStrength;\n#if NET10_0_OR_GREATER\n#pragma warning restore SYSLIB0058\n#endif\n            feature.Protocol = sslStream.SslProtocol;\n\n            var originalTransport = context.Transport;\n\n            try\n            {\n                context.Transport = tlsDuplexPipe;\n\n                // Disposing the stream will dispose the tlsDuplexPipe\n                await using (sslStream)\n                await using (tlsDuplexPipe)\n                {\n                    await _next(context);\n                    // Dispose the inner stream (tlsDuplexPipe) before disposing the SslStream\n                    // as the duplex pipe can hit an ODE as it still may be writing.\n                }\n            }\n            finally\n            {\n                // Restore the original so that it gets closed appropriately\n                context.Transport = originalTransport;\n            }\n        }\n\n        private static X509Certificate2 ValidateCertificate(X509Certificate2 certificate, RemoteCertificateMode mode)\n        {\n            switch (mode)\n            {\n                case RemoteCertificateMode.NoCertificate:\n                    return null;\n                case RemoteCertificateMode.AllowCertificate:\n                    //if certificate exists but can not be used for client authentication.\n                    if (certificate != null && CertificateLoader.IsCertificateAllowedForClientAuth(certificate))\n                        return certificate;\n                    return null;\n                case RemoteCertificateMode.RequireCertificate:\n                    EnsureCertificateIsAllowedForClientAuth(certificate);\n                    return certificate;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(mode), mode, null);\n            }\n        }\n\n        protected static void EnsureCertificateIsAllowedForClientAuth(X509Certificate2 certificate)\n        {\n            if (certificate is null)\n            {\n                throw new InvalidOperationException(\"No certificate provided for client authentication.\");\n            }\n\n            if (!CertificateLoader.IsCertificateAllowedForClientAuth(certificate))\n            {\n                throw new InvalidOperationException($\"Invalid client certificate for client authentication: {certificate.Thumbprint}\");\n            }\n        }\n\n        private static X509Certificate2 ConvertToX509Certificate2(X509Certificate certificate)\n        {\n            if (certificate is null)\n            {\n                return null;\n            }\n\n            return certificate as X509Certificate2 ?? new X509Certificate2(certificate);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsConnectionFeature.cs",
    "content": "using System;\nusing System.Net.Security;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Connections.Security\n{\n    internal class TlsConnectionFeature : ITlsConnectionFeature, ITlsApplicationProtocolFeature, ITlsHandshakeFeature\n    {\n        public X509Certificate2 LocalCertificate { get; set; }\n\n        public X509Certificate2 RemoteCertificate { get; set; }\n\n        public ReadOnlyMemory<byte> ApplicationProtocol { get; set; }\n\n        public SslProtocols Protocol { get; set; }\n\n        public TlsCipherSuite? NegotiatedCipherSuite { get; set; }\n\n        public string HostName { get; set; } = string.Empty;\n\n#if NET10_0_OR_GREATER\n#pragma warning disable SYSLIB0058\n#endif\n        public CipherAlgorithmType CipherAlgorithm { get; set; }\n\n        public int CipherStrength { get; set; }\n\n        public HashAlgorithmType HashAlgorithm { get; set; }\n\n        public int HashStrength { get; set; }\n\n        public ExchangeAlgorithmType KeyExchangeAlgorithm { get; set; }\n\n        public int KeyExchangeStrength { get; set; }\n#if NET10_0_OR_GREATER\n#pragma warning restore SYSLIB0058\n#endif\n\n        public Task<X509Certificate2> GetRemoteCertificateAsync(CancellationToken cancellationToken)\n        {\n            return Task.FromResult(RemoteCertificate);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsDuplexPipe.cs",
    "content": "using System;\nusing System.IO;\nusing System.IO.Pipelines;\nusing System.Net.Security;\n\nnamespace Orleans.Connections.Security\n{\n    internal class TlsDuplexPipe : DuplexPipeStreamAdapter<SslStream>\n    {\n        public TlsDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions)\n            : this(transport, readerOptions, writerOptions, s => new SslStream(s))\n        {\n\n        }\n\n        public TlsDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func<Stream, SslStream> factory) :\n            base(transport, readerOptions, writerOptions, factory)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsOptions.cs",
    "content": "using System;\nusing System.Net.Security;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Threading;\nusing Microsoft.AspNetCore.Connections;\n\nnamespace Orleans.Connections.Security\n{\n    public delegate bool RemoteCertificateValidator(X509Certificate2 certificate, X509Chain chain, SslPolicyErrors policyErrors);\n\n    /// <summary>\n    /// Settings for how TLS connections are handled.\n    /// </summary>\n    public class TlsOptions\n    {\n        private TimeSpan _handshakeTimeout = TimeSpan.FromSeconds(10);\n\n        /// <summary>\n        /// <para>\n        /// Specifies the local certificate used to authenticate TLS connections. This is ignored on server if LocalCertificateSelector is set.\n        /// </para>\n        /// <para>\n        /// To omit client authentication set to <c>null</c> on client and set <see cref=\"RemoteCertificateMode\"/> to <see cref=\"Orleans.Connections.Security.RemoteCertificateMode.AllowCertificate\"/> or <see cref=\"Orleans.Connections.Security.RemoteCertificateMode.NoCertificate\"/> on server.\n        /// </para>\n        /// <para>\n        /// If the certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1) for server and Client Authentication (OID 1.3.6.1.5.5.7.3.2) for client.\n        /// </para>\n        /// </summary>\n        public X509Certificate2 LocalCertificate { get; set; }\n\n        /// <summary>\n        /// <para>\n        /// A callback that will be invoked to dynamically select a local server certificate. This is higher priority than LocalCertificate.\n        /// If SNI is not available then the name parameter will be null.\n        /// </para>\n        /// <para>\n        /// If the certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1).\n        /// </para>\n        /// </summary>\n        public Func<ConnectionContext, string, X509Certificate2> LocalServerCertificateSelector { get; set; }\n\n        /// <summary>\n        /// <para>\n        /// A callback that will be invoked to dynamically select a local client certificate. This is higher priority than LocalCertificate.\n        /// </para>\n        /// <para>\n        /// If the certificate has an Extended Key Usage extension, the usages must include Client Authentication (OID 1.3.6.1.5.5.7.3.2).\n        /// </para>\n        /// </summary>\n        public Func<object, string, X509CertificateCollection, X509Certificate, string[], X509Certificate2> LocalClientCertificateSelector { get; set; }\n\n        /// <summary>\n        /// Specifies the remote endpoint certificate requirements for a TLS connection. Defaults to <see cref=\"Orleans.Connections.Security.RemoteCertificateMode.RequireCertificate\"/>.\n        /// </summary>\n        public RemoteCertificateMode RemoteCertificateMode { get; set; } = RemoteCertificateMode.RequireCertificate;\n\n        /// <summary>\n        /// Specifies the client authentication certificate requirements for a TLS connection to Silo. Defaults to <see cref=\"Orleans.Connections.Security.RemoteCertificateMode.AllowCertificate\"/>.\n        /// </summary>\n        public RemoteCertificateMode ClientCertificateMode { get; set; } = RemoteCertificateMode.AllowCertificate;\n\n        /// <summary>\n        /// Specifies a callback for additional remote certificate validation that will be invoked during authentication. This will be ignored\n        /// if <see cref=\"AllowAnyRemoteCertificate\"/> is called after this callback is set.\n        /// </summary>\n        public RemoteCertificateValidator RemoteCertificateValidation { get; set; }\n\n        /// <summary>\n        /// Specifies allowable SSL protocols. Defaults to <see cref=\"System.Security.Authentication.SslProtocols.Tls13\" /> and <see cref=\"System.Security.Authentication.SslProtocols.Tls12\"/>.\n        /// </summary>\n        public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls13 | SslProtocols.Tls12;\n\n        /// <summary>\n        /// Specifies whether the certificate revocation list is checked during authentication.\n        /// </summary>\n        public bool CheckCertificateRevocation { get; set; }\n\n        /// <summary>\n        /// Overrides the current <see cref=\"RemoteCertificateValidation\"/> callback and allows any client certificate.\n        /// </summary>\n        public void AllowAnyRemoteCertificate()\n        {\n            RemoteCertificateValidation = (_, __, ___) => true;\n        }\n\n        /// <summary>\n        /// Provides direct configuration of the <see cref=\"TlsServerAuthenticationOptions\"/> on a per-connection basis.\n        /// This is called after all of the other settings have already been applied.\n        /// </summary>\n        public Action<ConnectionContext, TlsServerAuthenticationOptions> OnAuthenticateAsServer { get; set; }\n\n        /// <summary>\n        /// Provides direct configuration of the <see cref=\"TlsClientAuthenticationOptions\"/> on a per-connection basis.\n        /// This is called after all of the other settings have already been applied.\n        /// Use this to set the target host name for SNI (Server Name Indication) via <see cref=\"TlsClientAuthenticationOptions.TargetHost\"/>.\n        /// </summary>\n        public Action<ConnectionContext, TlsClientAuthenticationOptions> OnAuthenticateAsClient { get; set; }\n\n        /// <summary>\n        /// Specifies the maximum amount of time allowed for the TLS/SSL handshake. This must be positive and finite.\n        /// </summary>\n        public TimeSpan HandshakeTimeout\n        {\n            get => _handshakeTimeout;\n            set\n            {\n                if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)\n                {\n                    throw new ArgumentOutOfRangeException(nameof(value), nameof(HandshakeTimeout) + \" must be positive\");\n                }\n\n                _handshakeTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsServerAuthenticationOptions.cs",
    "content": "using System.Collections.Generic;\nusing System.Net.Security;\nusing System.Security.Authentication;\nusing System.Security.Cryptography.X509Certificates;\n\nnamespace Orleans.Connections.Security\n{\n    public delegate X509Certificate ServerCertificateSelectionCallback(object sender, string hostName);\n\n    public class TlsServerAuthenticationOptions\n    {\n        internal SslServerAuthenticationOptions Value { get; } = new SslServerAuthenticationOptions\n        {\n            ApplicationProtocols = new List<SslApplicationProtocol>\n            {\n                OrleansApplicationProtocol.Orleans1\n            }\n        };\n\n        public X509Certificate ServerCertificate\n        {\n            get => Value.ServerCertificate;\n            set => Value.ServerCertificate = value;\n        }\n\n        public ServerCertificateSelectionCallback ServerCertificateSelectionCallback\n        {\n            get => Value.ServerCertificateSelectionCallback is null ? null : new ServerCertificateSelectionCallback(Value.ServerCertificateSelectionCallback);\n            set => Value.ServerCertificateSelectionCallback = value is null ? null : new System.Net.Security.ServerCertificateSelectionCallback(value);\n        }\n\n        public bool ClientCertificateRequired\n        {\n            get => Value.ClientCertificateRequired;\n            set => Value.ClientCertificateRequired = value;\n        }\n\n        public SslProtocols EnabledSslProtocols\n        {\n            get => Value.EnabledSslProtocols;\n            set => Value.EnabledSslProtocols = value;\n        }\n\n        public X509RevocationMode CertificateRevocationCheckMode\n        {\n            get => Value.CertificateRevocationCheckMode;\n            set => Value.CertificateRevocationCheckMode = value;\n        }\n\n        public object SslServerAuthenticationOptions => this.Value;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Connections.Security/Security/TlsServerConnectionMiddleware.cs",
    "content": "using System;\nusing System.IO.Pipelines;\nusing System.Net.Security;\nusing System.Security.Cryptography.X509Certificates;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.AspNetCore.Connections.Features;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Connections.Security\n{\n    internal class TlsServerConnectionMiddleware\n    {\n        private readonly ConnectionDelegate _next;\n        private readonly TlsOptions _options;\n        private readonly ILogger _logger;\n        private readonly X509Certificate2 _certificate;\n        private readonly Func<ConnectionContext, string, X509Certificate2> _certificateSelector;\n\n        public TlsServerConnectionMiddleware(ConnectionDelegate next, TlsOptions options, ILoggerFactory loggerFactory)\n        {\n            if (options == null)\n            {\n                throw new ArgumentNullException(nameof(options));\n            }\n\n            _next = next;\n\n            // capture the certificate now so it can't be switched after validation\n            _certificate = options.LocalCertificate;\n            _certificateSelector = options.LocalServerCertificateSelector;\n            if (_certificate == null && _certificateSelector == null)\n            {\n                throw new ArgumentException(\"Server certificate is required\", nameof(options));\n            }\n\n            // If a selector is provided then ignore the cert, it may be a default cert.\n            if (_certificateSelector != null)\n            {\n                // SslStream doesn't allow both.\n                _certificate = null;\n            }\n            else\n            {\n                EnsureCertificateIsAllowedForServerAuth(_certificate);\n            }\n\n            _options = options;\n            _logger = loggerFactory?.CreateLogger<TlsServerConnectionMiddleware>();\n        }\n\n        public Task OnConnectionAsync(ConnectionContext context)\n        {\n            return InnerOnConnectionAsync(context);\n        }\n\n        private async Task InnerOnConnectionAsync(ConnectionContext context)\n        {\n            bool certificateRequired;\n            var feature = new TlsConnectionFeature();\n            context.Features.Set<ITlsConnectionFeature>(feature);\n            context.Features.Set<ITlsHandshakeFeature>(feature);\n\n            var memoryPool = context.Features.Get<IMemoryPoolFeature>()?.MemoryPool;\n\n            var inputPipeOptions = new StreamPipeReaderOptions\n            (\n                pool: memoryPool,\n                bufferSize: memoryPool.GetMinimumSegmentSize(),\n                minimumReadSize: memoryPool.GetMinimumAllocSize(),\n                leaveOpen: true\n            );\n\n            var outputPipeOptions = new StreamPipeWriterOptions\n            (\n                pool: memoryPool,\n                leaveOpen: true\n            );\n\n            TlsDuplexPipe tlsDuplexPipe = null;\n\n            if (_options.RemoteCertificateMode == RemoteCertificateMode.NoCertificate)\n            {\n                tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions);\n                certificateRequired = false;\n            }\n            else\n            {\n                tlsDuplexPipe = new TlsDuplexPipe(context.Transport, inputPipeOptions, outputPipeOptions, s => new SslStream(\n                    s,\n                    leaveInnerStreamOpen: false,\n                    userCertificateValidationCallback: (sender, certificate, chain, sslPolicyErrors) =>\n                    {\n                        if (certificate == null)\n                        {\n                            return _options.RemoteCertificateMode != RemoteCertificateMode.RequireCertificate;\n                        }\n\n                        if (_options.RemoteCertificateValidation == null)\n                        {\n                            if (sslPolicyErrors != SslPolicyErrors.None)\n                            {\n                                return false;\n                            }\n                        }\n\n                        var certificate2 = ConvertToX509Certificate2(certificate);\n                        if (certificate2 == null)\n                        {\n                            return false;\n                        }\n\n                        if (_options.RemoteCertificateValidation != null)\n                        {\n                            if (!_options.RemoteCertificateValidation(certificate2, chain, sslPolicyErrors))\n                            {\n                                return false;\n                            }\n                        }\n\n                        return true;\n                    }));\n\n                certificateRequired = true;\n            }\n\n            var sslStream = tlsDuplexPipe.Stream;\n\n            using (var cancellationTokeSource = new CancellationTokenSource(_options.HandshakeTimeout))\n            using (cancellationTokeSource.Token.UnsafeRegister(state => ((ConnectionContext)state).Abort(), context))\n            {\n                try\n                {\n                    // Adapt to the SslStream signature\n                    ServerCertificateSelectionCallback selector = null;\n                    if (_certificateSelector != null)\n                    {\n                        selector = (sender, name) =>\n                        {\n                            feature.HostName = name ?? string.Empty;\n                            context.Features.Set(sslStream);\n                            var cert = _certificateSelector(context, name);\n                            if (cert != null)\n                            {\n                                EnsureCertificateIsAllowedForServerAuth(cert);\n                            }\n\n                            return cert;\n                        };\n                    }\n                    else if (_certificate != null)\n                    {\n                        // Even with a fixed certificate, we still want to capture the SNI hostname\n                        selector = (sender, name) =>\n                        {\n                            feature.HostName = name ?? string.Empty;\n                            return _certificate;\n                        };\n                    }\n\n                    var sslOptions = new TlsServerAuthenticationOptions\n                    {\n                        ServerCertificate = selector == null ? _certificate : null,\n                        ServerCertificateSelectionCallback = selector,\n                        ClientCertificateRequired = certificateRequired,\n                        EnabledSslProtocols = _options.SslProtocols,\n                        CertificateRevocationCheckMode = _options.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,\n                    };\n\n                    _options.OnAuthenticateAsServer?.Invoke(context, sslOptions);\n\n                    await sslStream.AuthenticateAsServerAsync(sslOptions.Value, cancellationTokeSource.Token);\n                }\n                catch (OperationCanceledException ex)\n                {\n                    _logger?.LogWarning(2, ex, \"Authentication timed out\");\n                    await sslStream.DisposeAsync();\n                    return;\n                }\n                catch (Exception ex)\n                {\n                    _logger?.LogWarning(1, ex, \"Authentication failed\");\n                    await sslStream.DisposeAsync();\n                    return;\n                }\n            }\n\n            feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol;\n\n            context.Features.Set<ITlsApplicationProtocolFeature>(feature);\n            feature.LocalCertificate = ConvertToX509Certificate2(sslStream.LocalCertificate);\n            feature.RemoteCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate);\n            feature.NegotiatedCipherSuite = sslStream.NegotiatedCipherSuite;\n#if NET10_0_OR_GREATER\n#pragma warning disable SYSLIB0058\n#endif\n            feature.CipherAlgorithm = sslStream.CipherAlgorithm;\n            feature.CipherStrength = sslStream.CipherStrength;\n            feature.HashAlgorithm = sslStream.HashAlgorithm;\n            feature.HashStrength = sslStream.HashStrength;\n            feature.KeyExchangeAlgorithm = sslStream.KeyExchangeAlgorithm;\n            feature.KeyExchangeStrength = sslStream.KeyExchangeStrength;\n#if NET10_0_OR_GREATER\n#pragma warning restore SYSLIB0058\n#endif\n            feature.Protocol = sslStream.SslProtocol;\n\n            var originalTransport = context.Transport;\n\n            try\n            {\n                context.Transport = tlsDuplexPipe;\n\n                // Disposing the stream will dispose the TlsDuplexPipe\n                await using (sslStream)\n                await using (tlsDuplexPipe)\n                {\n                    await _next(context);\n                    // Dispose the inner stream (TlsDuplexPipe) before disposing the SslStream\n                    // as the duplex pipe can hit an ODE as it still may be writing.\n                }\n            }\n            finally\n            {\n                // Restore the original so that it gets closed appropriately\n                context.Transport = originalTransport;\n            }\n        }\n\n        protected static void EnsureCertificateIsAllowedForServerAuth(X509Certificate2 certificate)\n        {\n            if (!CertificateLoader.IsCertificateAllowedForServerAuth(certificate))\n            {\n                throw new InvalidOperationException($\"Invalid server certificate for server authentication: {certificate.Thumbprint}\");\n            }\n        }\n\n        private static X509Certificate2 ConvertToX509Certificate2(X509Certificate certificate)\n        {\n            if (certificate is null)\n            {\n                return null;\n            }\n\n            return certificate as X509Certificate2 ?? new X509Certificate2(certificate);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Async/AsyncExecutorWithRetries.cs",
    "content": "using System;\nusing System.Runtime.ExceptionServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Internal\n{\n    /// <summary>\n    /// This class is a convenient utility class to execute a certain asynchronous function with retries,\n    /// allowing to specify custom retry filters and policies.\n    /// </summary>\n    public static class AsyncExecutorWithRetries\n    {\n        /// <summary>\n        /// Constant used to request an infinite number of retries.\n        /// </summary>\n        public static readonly int INFINITE_RETRIES = -1;\n\n        /// <summary>\n        /// Execute a given function a number of times, based on retry configuration parameters.\n        /// </summary>\n        /// <param name=\"action\">\n        /// The action to be executed.\n        /// </param>\n        /// <param name=\"maxNumErrorTries\">\n        /// The maximum number of retries.\n        /// </param>\n        /// <param name=\"retryExceptionFilter\">\n        /// The retry exception filter.\n        /// </param>\n        /// <param name=\"maxExecutionTime\">\n        /// The maximum execution time.\n        /// </param>\n        /// <param name=\"onErrorBackOff\">\n        /// The backoff provider.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        public static Task ExecuteWithRetries(\n            Func<int, Task> action,\n            int maxNumErrorTries,\n            Func<Exception, int, bool> retryExceptionFilter,\n            TimeSpan maxExecutionTime,\n            IBackoffProvider onErrorBackOff)\n        {\n            async Task<bool> function(int i) { await action(i); return true; }\n            return ExecuteWithRetriesHelper<bool>(\n                function,\n                0,\n                maxNumErrorTries,\n                maxExecutionTime,\n                DateTime.UtcNow,\n                null,\n                retryExceptionFilter,\n                null,\n                onErrorBackOff);\n        }\n\n        /// <summary>\n        /// Execute a given function a number of times, based on retry configuration parameters.\n        /// </summary>\n        /// <param name=\"function\">\n        /// The delegate to be executed.\n        /// </param>\n        /// <param name=\"maxNumErrorTries\">\n        /// The maximum number of retries.\n        /// </param>\n        /// <param name=\"retryExceptionFilter\">\n        /// The retry exception filter.\n        /// </param>\n        /// <param name=\"maxExecutionTime\">\n        /// The maximum execution time.\n        /// </param>\n        /// <param name=\"onErrorBackOff\">\n        /// The backoff provider.\n        /// </param>\n        /// <returns>\n        /// The value returned from the successful invocation of the provided function.\n        /// </returns>\n        public static Task<T> ExecuteWithRetries<T>(\n            Func<int, Task<T>> function,\n            int maxNumErrorTries,\n            Func<Exception, int, bool> retryExceptionFilter,\n            TimeSpan maxExecutionTime,\n            IBackoffProvider onErrorBackOff,\n            CancellationToken cancellationToken = default)\n        {\n            return ExecuteWithRetries<T>(\n                function,\n                0,\n                maxNumErrorTries,\n                null,\n                retryExceptionFilter,\n                maxExecutionTime,\n                null,\n                onErrorBackOff,\n                cancellationToken);\n        }\n\n        /// <summary>\n        /// Execute a given <paramref name=\"function\"/> a number of times, based on retry configuration parameters.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The underlying return type of <paramref name=\"function\"/>.\n        /// </typeparam>\n        /// <param name=\"function\">\n        /// Function to execute\n        /// </param>\n        /// <param name=\"maxNumSuccessTries\">\n        /// Maximal number of successful execution attempts. <see cref=\"ExecuteWithRetries\"/> will try to re-execute the given <paramref name=\"function\"/> again if directed so by <paramref name=\"retryValueFilter\"/> .\n        /// Set to <c>-1</c> for unlimited number of success retries, until <paramref name=\"retryValueFilter\"/> is satisfied. Set to <c>0</c> for only one success attempt, which will cause <paramref name=\"retryValueFilter\"/> to be\n        /// ignored and the given <paramref name=\"function\"/> executed only once until first success.\n        /// </param>\n        /// <param name=\"maxNumErrorTries\">\n        /// Maximal number of execution attempts due to errors. Set to -1 for unlimited number of error retries, until <paramref name=\"retryExceptionFilter\"/> is satisfied.\n        /// </param>\n        /// <param name=\"retryValueFilter\">\n        /// Filter <paramref name=\"function\"/> to indicate if successful execution should be retried. Set to <see langword=\"null\"/> to disable successful retries.\n        /// </param>\n        /// <param name=\"retryExceptionFilter\">\n        /// Filter <paramref name=\"function\"/> to indicate if error execution should be retried. Set to <see langword=\"null\"/> to disable error retries.\n        /// </param>\n        /// <param name=\"maxExecutionTime\">\n        /// The maximal execution time of the <see cref=\"ExecuteWithRetries\"/> function.\n        /// </param>\n        /// <param name=\"onSuccessBackOff\">\n        /// The backoff provider object, which determines how much to wait between success retries.\n        /// </param>\n        /// <param name=\"onErrorBackOff\">\n        /// The backoff provider object, which determines how much to wait between error retries\n        /// </param>\n        /// <returns>\n        /// The value returned from the successful invocation of <paramref name=\"function\"/>.\n        /// </returns>\n        public static Task<T> ExecuteWithRetries<T>(\n            Func<int, Task<T>> function,\n            int maxNumSuccessTries,\n            int maxNumErrorTries,\n            Func<T, int, bool> retryValueFilter,\n            Func<Exception, int, bool> retryExceptionFilter,\n            TimeSpan maxExecutionTime = default,\n            IBackoffProvider onSuccessBackOff = null,\n            IBackoffProvider onErrorBackOff = null,\n            CancellationToken cancellationToken = default)\n        {\n            return ExecuteWithRetriesHelper<T>(\n                function,\n                maxNumSuccessTries,\n                maxNumErrorTries,\n                maxExecutionTime,\n                DateTime.UtcNow,\n                retryValueFilter,\n                retryExceptionFilter,\n                onSuccessBackOff,\n                onErrorBackOff,\n                cancellationToken);\n        }\n\n        /// <summary>\n        /// Execute a given <paramref name=\"function\"/> a number of times, based on retry configuration parameters.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The underlying return type of <paramref name=\"function\"/>.\n        /// </typeparam>\n        /// <param name=\"function\">\n        /// Function to execute.\n        /// </param>\n        /// <param name=\"maxNumSuccessTries\">\n        /// Maximal number of successful execution attempts. <see cref=\"ExecuteWithRetries\"/> will try to re-execute the given <paramref name=\"function\"/> again if directed so by <paramref name=\"retryValueFilter\"/> .\n        /// Set to <c>-1</c> for unlimited number of success retries, until <paramref name=\"retryValueFilter\"/> is satisfied. Set to <c>0</c> for only one success attempt, which will cause <paramref name=\"retryValueFilter\"/> to be\n        /// ignored and the given <paramref name=\"function\"/> executed only once until first success.\n        /// </param>\n        /// <param name=\"maxNumErrorTries\">\n        /// Maximal number of execution attempts due to errors. Set to -1 for unlimited number of error retries, until <paramref name=\"retryExceptionFilter\"/> is satisfied.\n        /// </param>\n        /// <param name=\"maxExecutionTime\">\n        /// The maximal execution time of the <see cref=\"ExecuteWithRetries\"/> function.\n        /// </param>\n        /// <param name=\"startExecutionTime\">\n        /// The time at which execution was started.\n        /// </param>\n        /// <param name=\"retryValueFilter\">\n        /// Filter <paramref name=\"function\"/> to indicate if successful execution should be retried. Set to <see langword=\"null\"/> to disable successful retries.\n        /// </param>\n        /// <param name=\"retryExceptionFilter\">\n        /// Filter <paramref name=\"function\"/> to indicate if error execution should be retried. Set to <see langword=\"null\"/> to disable error retries.\n        /// </param>\n        /// <param name=\"onSuccessBackOff\">\n        /// The backoff provider object, which determines how much to wait between success retries.\n        /// </param>\n        /// <param name=\"onErrorBackOff\">\n        /// The backoff provider object, which determines how much to wait between error retries\n        /// </param>\n        /// <returns>\n        /// The value returned from the successful invocation of <paramref name=\"function\"/>.\n        /// </returns>\n        private static async Task<T> ExecuteWithRetriesHelper<T>(\n            Func<int, Task<T>> function,\n            int maxNumSuccessTries,\n            int maxNumErrorTries,\n            TimeSpan maxExecutionTime,\n            DateTime startExecutionTime,\n            Func<T, int, bool> retryValueFilter = null,\n            Func<Exception, int, bool> retryExceptionFilter = null,\n            IBackoffProvider onSuccessBackOff = null,\n            IBackoffProvider onErrorBackOff = null,\n            CancellationToken cancellationToken = default)\n        {\n            T result = default;\n            ExceptionDispatchInfo lastExceptionInfo = null;\n            bool retry;\n            var callCounter = 0;\n\n            do\n            {\n                retry = false;\n                cancellationToken.ThrowIfCancellationRequested();\n\n                if (maxExecutionTime != Timeout.InfiniteTimeSpan && maxExecutionTime != default)\n                {\n                    DateTime now = DateTime.UtcNow;\n                    if (now - startExecutionTime > maxExecutionTime)\n                    {\n                        if (lastExceptionInfo == null)\n                        {\n                            throw new TimeoutException(\n                                $\"ExecuteWithRetries has exceeded its max execution time of {maxExecutionTime}. Now is {LogFormatter.PrintDate(now)}, started at {LogFormatter.PrintDate(startExecutionTime)}, passed {now - startExecutionTime}\");\n                        }\n\n                        lastExceptionInfo.Throw();\n                    }\n                }\n\n                int counter = callCounter;\n\n                try\n                {\n                    callCounter++;\n                    result = await function(counter);\n                    lastExceptionInfo = null;\n\n                    if (callCounter < maxNumSuccessTries || maxNumSuccessTries == INFINITE_RETRIES) // -1 for infinite retries\n                    {\n                        if (retryValueFilter != null)\n                            retry = retryValueFilter(result, counter);\n                    }\n\n                    if (retry && !cancellationToken.IsCancellationRequested)\n                    {\n                        TimeSpan? delay = onSuccessBackOff?.Next(counter);\n\n                        if (delay.HasValue)\n                        {\n                            await Task.Delay(delay.Value, cancellationToken);\n                        }\n                    }\n                }\n                catch (Exception exc)\n                {\n                    retry = false;\n\n                    if (callCounter < maxNumErrorTries || maxNumErrorTries == INFINITE_RETRIES)\n                    {\n                        if (retryExceptionFilter != null)\n                            retry = retryExceptionFilter(exc, counter);\n                    }\n\n                    if (!retry || cancellationToken.IsCancellationRequested)\n                    {\n                        throw;\n                    }\n\n                    lastExceptionInfo = ExceptionDispatchInfo.Capture(exc);\n\n                    TimeSpan? delay = onErrorBackOff?.Next(counter);\n\n                    if (delay.HasValue)\n                    {\n                        await Task.Delay(delay.Value, cancellationToken);\n                    }\n                }\n            } while (retry);\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Functionality for determining how long to wait between successive operation attempts.\n    /// </summary>\n    public interface IBackoffProvider\n    {\n        /// <summary>\n        /// Returns the amount of time to wait before attempting a subsequent operation.\n        /// </summary>\n        /// <param name=\"attempt\">The number of operation attempts which have been made.</param>\n        /// <returns>The amount of time to wait before attempting a subsequent operation.</returns>\n        TimeSpan Next(int attempt);\n    }\n\n    /// <summary>\n    /// A fixed-duration backoff implementation, which always returns the configured delay.\n    /// </summary>\n    public class FixedBackoff : IBackoffProvider\n    {\n        private readonly TimeSpan fixedDelay;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FixedBackoff\"/> class.\n        /// </summary>\n        /// <param name=\"delay\">\n        /// The fixed delay between attempts.\n        /// </param>\n        public FixedBackoff(TimeSpan delay)\n        {\n            fixedDelay = delay;\n        }\n\n        /// <inheritdoc/>\n        public TimeSpan Next(int attempt)\n        {\n            return fixedDelay;\n        }\n    }\n\n    /// <summary>\n    /// An exponential backoff implementation, which initially returns the minimum delay it is configured\n    /// with and exponentially increases its delay by two raised to the power of the attempt number until\n    /// the maximum backoff delay is reached.\n    /// </summary>\n    internal class ExponentialBackoff : IBackoffProvider\n    {\n        private readonly TimeSpan minDelay;\n        private readonly TimeSpan maxDelay;\n        private readonly TimeSpan step;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExponentialBackoff\"/> class.\n        /// </summary>\n        /// <param name=\"minDelay\">\n        /// The minimum delay.\n        /// </param>\n        /// <param name=\"maxDelay\">\n        /// The maximum delay.\n        /// </param>\n        /// <param name=\"step\">\n        /// The step, which is multiplied by two raised to the power of the attempt number and added to the minimum delay to compute the delay for each iteration.\n        /// </param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">\n        /// One or more argument values are outside out of their valid range.\n        /// </exception>\n        public ExponentialBackoff(TimeSpan minDelay, TimeSpan maxDelay, TimeSpan step)\n        {\n            if (minDelay <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(minDelay), minDelay, \"ExponentialBackoff min delay must be a positive number.\");\n            if (maxDelay <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(maxDelay), maxDelay, \"ExponentialBackoff max delay must be a positive number.\");\n            if (step <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(step), step, \"ExponentialBackoff step must be a positive number.\");\n            if (minDelay >= maxDelay) throw new ArgumentOutOfRangeException(nameof(minDelay), minDelay, \"ExponentialBackoff min delay must be greater than max delay.\");\n\n            this.minDelay = minDelay;\n            this.maxDelay = maxDelay;\n            this.step = step;\n        }\n\n        /// <inheritdoc/>\n        public TimeSpan Next(int attempt)\n        {\n            TimeSpan currMax;\n            try\n            {\n                long multiple = checked(1 << attempt);\n                currMax = minDelay + step.Multiply(multiple); // may throw OverflowException\n                if (currMax <= TimeSpan.Zero)\n                {\n                    throw new OverflowException();\n                }\n            }\n            catch (OverflowException)\n            {\n                currMax = maxDelay;\n            }\n            currMax = StandardExtensions.Min(currMax, maxDelay);\n\n            if (minDelay >= currMax) throw new ArgumentOutOfRangeException($\"minDelay {minDelay}, currMax = {currMax}\");\n            return RandomTimeSpan.Next(minDelay, currMax);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Async/AsyncLock.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// An async mutual exclusion mechanism that supports scoping via ‘using’.\n    /// </summary>\n    /// <remarks>\n    /// (Adapted from http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx)\n    ///\n    /// When programming with <b>async</b>, the <b>lock</b> keyword is problematic:\n    /// <list type=\"bullet\">\n    ///     <item><description><b>lock</b> will cause the thread to block while it waits for exclusive access to the critical section of code.</description></item>\n    ///     <item><description>The <b>await</b> keyword cannot be used within the scope of a <b>lock</b> construct.</description></item>\n    /// </list>\n    ///\n    /// It is still useful, at times, to provide exclusive access to a critical section of code. AsyncLock provides semantics\n    /// that correspond to that of a (non-recursive) mutex, while maintaining compatibility with the tenets of async programming.\n    /// </remarks>\n    /// <example>\n    /// The following example implements some work that needs to be done under lock:\n    /// <code>\n    /// class Test\n    /// {\n    ///     private AsyncLock _initLock = new AsyncLock();\n    ///     public async Task&lt;int> WorkUnderLock()\n    ///     {\n    ///             using (await _initLock.LockAsync()) // analogous to lock(_initLock)\n    ///             {\n    ///                  return await DoSomeWork();\n    ///             }\n    ///     }\n    /// }\n    /// </code>\n    /// </example>\n    ///\n    /// We decided to keep the implementation simple and mimic the semantics of a regular mutex as much as possible.\n    /// 1) AsyncLock is NOT IDisposable, since we don't want to give the developer an option to erroneously manually dispose the lock\n    /// while there may be some unreleased LockReleasers.\n    /// 2) AsyncLock does NOT have to implement the Finalizer function. The underlying resource of SemaphoreSlim will be eventually released by the .NET,\n    /// when SemaphoreSlim is finalized. Having finalizer for AsyncLock will not speed it up.\n    /// 3) LockReleaser is IDisposable to implement the \"using\" pattern.\n    /// 4) LockReleaser does NOT have to implement the Finalizer function. If users forget to Dispose the LockReleaser (analogous to forgetting to release a mutex)\n    /// the AsyncLock will remain locked, which may potentially cause deadlock. This is OK, since these are the exact regular mutex semantics - if one forgets to unlock the mutex, it stays locked.\n    [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Design\", \"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable\")]\n    internal class AsyncLock\n    {\n        private readonly SemaphoreSlim semaphore;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AsyncLock\"/> class.\n        /// </summary>\n        public AsyncLock()\n        {\n            semaphore = new SemaphoreSlim(1);\n        }\n\n        /// <summary>\n        /// Acquires the lock asynchronously.\n        /// </summary>\n        /// <returns>An <see cref=\"IDisposable\"/> which must be used to release the lock.</returns>\n        public ValueTask<IDisposable> LockAsync()\n        {\n            Task wait = semaphore.WaitAsync();\n            if (wait.IsCompletedSuccessfully)\n            {\n                return new(new LockReleaser(this));\n            }\n            else\n            {\n                return LockAsyncInternal(this, wait);\n\n                static async ValueTask<IDisposable> LockAsyncInternal(AsyncLock self, Task waitTask)\n                {\n                    await waitTask.ConfigureAwait(false);\n                    return new LockReleaser(self);\n                }\n            }\n        }\n\n        private class LockReleaser : IDisposable\n        {\n            private AsyncLock target;\n\n            internal LockReleaser(AsyncLock target)\n            {\n                this.target = target;\n            }\n\n            public void Dispose()\n            {\n                if (target == null)\n                    return;\n\n                // first null it, next Release, so even if Release throws, we don't hold the reference any more.\n                AsyncLock tmp = target;\n                target = null;\n                try\n                {\n                    tmp.semaphore.Release();\n                }\n                catch (Exception) { } // just ignore the Exception\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Async/AsyncSerialExecutor.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// A utility class that provides serial execution of async functions.\n    /// In can be used inside reentrant grain code to execute some methods in a non-reentrant (serial) way.\n    /// </summary>\n    /// <typeparam name=\"TResult\">\n    /// The underlying type returned from functions invoked by this executor.\n    /// </typeparam>\n    public class AsyncSerialExecutor<TResult>\n    {\n        private readonly ConcurrentQueue<Tuple<TaskCompletionSource<TResult>, Func<Task<TResult>>>> actions = new ConcurrentQueue<Tuple<TaskCompletionSource<TResult>, Func<Task<TResult>>>>();\n        private readonly InterlockedExchangeLock locker = new InterlockedExchangeLock();\n\n        /// <summary>\n        /// A lock which relies on <see cref=\"Interlocked.Exchange(ref long, long)\"/>\n        /// </summary>\n        private class InterlockedExchangeLock\n        {\n            private const int Locked = 1;\n            private const int Unlocked = 0;\n            private int lockState = Unlocked;\n\n            /// <summary>\n            /// Attempts to acquire the lock, returning <see langword=\"true\"/> if the lock was acquired and <see langword=\"false\"/> otherwise.\n            /// </summary>\n            /// <returns>\n            /// <see langword=\"true\"/> if the lock was acquired and <see langword=\"false\"/> otherwise.\n            /// </returns>\n            public bool TryGetLock()\n            {\n                return Interlocked.Exchange(ref lockState, Locked) != Locked;\n            }\n\n            /// <summary>\n            /// Releases the lock unconditionally.\n            /// </summary>\n            public void ReleaseLock()\n            {\n                Interlocked.Exchange(ref lockState, Unlocked);\n            }\n        }\n\n        /// <summary>\n        /// Submit the next function for execution. It will execute after all previously submitted functions have finished, without interleaving their executions.\n        /// Returns a promise that represents the execution of this given function. \n        /// The returned promise will be resolved when the given function is done executing.\n        /// </summary>\n        /// <param name=\"func\">The function to schedule for invocation.</param>\n        /// <returns>The result of the scheduled function invocation.</returns>\n        public Task<TResult> AddNext(Func<Task<TResult>> func)\n        {\n            var resolver = new TaskCompletionSource<TResult>(TaskCreationOptions.RunContinuationsAsynchronously);\n            actions.Enqueue(new Tuple<TaskCompletionSource<TResult>, Func<Task<TResult>>>(resolver, func));\n            Task<TResult> task = resolver.Task;\n            ExecuteNext().Ignore();\n            return task;\n        }\n\n        /// <summary>\n        /// Executes the next scheduled function.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        private async Task ExecuteNext()\n        {\n            while (!actions.IsEmpty)\n            {\n                bool gotLock = false;\n                try\n                {\n                    if (!(gotLock = locker.TryGetLock()))\n                    {\n                        return;\n                    }\n\n                    while (!actions.IsEmpty)\n                    {\n                        Tuple<TaskCompletionSource<TResult>, Func<Task<TResult>>> actionTuple;\n                        if (actions.TryDequeue(out actionTuple))\n                        {\n                            try\n                            {\n                                TResult result = await actionTuple.Item2();\n                                actionTuple.Item1.TrySetResult(result);\n                            }\n                            catch (Exception exc)\n                            {\n                                actionTuple.Item1.TrySetException(exc);\n                            }\n                        }\n                    }\n                }\n                finally\n                {\n                    if (gotLock)\n                        locker.ReleaseLock();\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// A utility class that provides serial execution of async functions.\n    /// In can be used inside reentrant grain code to execute some methods in a non-reentrant (serial) way.\n    /// </summary>\n    public class AsyncSerialExecutor\n    {\n        private readonly AsyncSerialExecutor<bool> executor = new AsyncSerialExecutor<bool>();\n\n        /// <summary>\n        /// Submits the next function for execution. It will execute after all previously submitted functions have finished, without interleaving their executions.\n        /// Returns a promise that represents the execution of this given function. \n        /// The returned promise will be resolved when the given function is done executing.\n        /// </summary>\n        /// <param name=\"func\">The function to schedule for invocation.</param>\n        /// <returns>The result of the scheduled function invocation.</returns>\n        public Task AddNext(Func<Task> func)\n        {\n            return this.executor.AddNext(() => Wrap(func));\n        }\n\n        private static async Task<bool> Wrap(Func<Task> func)\n        {\n            await func();\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Async/BatchWorker.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Timers.Internal;\n\n#nullable enable\nnamespace Orleans\n{\n    /// <summary>\n    /// General pattern for an asynchronous worker that performs a work task, when notified,\n    /// to service queued work. Each work cycle handles ALL the queued work. \n    /// If new work arrives during a work cycle, another cycle is scheduled. \n    /// The worker never executes more than one instance of the work cycle at a time, \n    /// and consumes no resources when idle. It uses TaskScheduler.Current \n    /// to schedule the work cycles.\n    /// </summary>\n    public abstract class BatchWorker\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock lockable = new();\n#else\n        private readonly object lockable = new();\n#endif\n\n        private DateTime? scheduledNotify;\n\n        // Task for the current work cycle, or null if idle\n        private Task? currentWorkCycle;\n\n        // Flag is set to indicate that more work has arrived during execution of the task\n        private bool moreWork;\n\n        // Used to communicate the task for the next work cycle to waiters.\n        // This value is non-null only if there are waiters.\n        private TaskCompletionSource<Task>? nextWorkCyclePromise;\n        private Task? nextWorkCycle;\n\n        /// <summary>Implement this member in derived classes to define what constitutes a work cycle</summary>\n        /// <returns>>\n        /// A <see cref=\"Task\"/>\n        /// </returns>\n        protected abstract Task Work();\n\n        /// <summary>\n        /// Gets or sets the cancellation used to cancel this batch worker.\n        /// </summary>\n        protected CancellationToken CancellationToken { get; set; }\n\n        /// <summary>\n        /// Notify the worker that there is more work.\n        /// </summary>\n        public void Notify()\n        {\n            lock (lockable)\n            {\n                if (currentWorkCycle != null)\n                {\n                    // lets the current work cycle know that there is more work\n                    moreWork = true;\n                }\n                else\n                {\n                    // start a work cycle\n                    Start();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Instructs the batch worker to run again to check for work, if\n        /// it has not run again already by then, at specified <paramref name=\"utcTime\"/>.\n        /// </summary>\n        /// <param name=\"utcTime\"></param>\n        public void Notify(DateTime utcTime)\n        {\n            var now = DateTime.UtcNow;\n\n            if (now >= utcTime)\n            {\n                Notify();\n            }\n            else\n            {\n                lock (lockable)\n                {\n                    if (!scheduledNotify.HasValue || scheduledNotify.Value > utcTime)\n                    {\n                        scheduledNotify = utcTime;\n\n                        ScheduleNotify(utcTime, now).Ignore();\n                    }\n                }\n            }\n        }\n\n        private async Task ScheduleNotify(DateTime time, DateTime now)\n        {\n            await TimerManager.Delay(time - now, this.CancellationToken);\n\n            if (scheduledNotify == time)\n            {\n                Notify();\n            }\n        }\n\n        private Task Start()\n        {\n            // Clear any scheduled runs\n            scheduledNotify = null;\n\n            // Queue a task that is doing the work\n            var task = Task.Factory.StartNew(s => ((BatchWorker)s!).Work(), this, default, default, TaskScheduler.Current).Unwrap();\n            currentWorkCycle = task;\n\n            // chain a continuation that checks for more work, on the same scheduler\n            task.ContinueWith((_, s) => ((BatchWorker)s!).CheckForMoreWork(), this);\n            return task;\n        }\n\n        /// <summary>\n        /// Executes at the end of each work cycle on the same task scheduler.\n        /// </summary>\n        private void CheckForMoreWork()\n        {\n            TaskCompletionSource<Task>? signal;\n            Task taskToSignal;\n\n            lock (lockable)\n            {\n                if (moreWork)\n                {\n                    moreWork = false;\n\n                    // see if someone created a promise for waiting for the next work cycle\n                    // if so, take it and remove it\n                    signal = this.nextWorkCyclePromise;\n                    this.nextWorkCyclePromise = null;\n                    this.nextWorkCycle = null;\n\n                    // start the next work cycle\n                    taskToSignal = Start();\n                }\n                else\n                {\n                    currentWorkCycle = null;\n                    return;\n                }\n            }\n\n            // to be safe, must do the signalling out here so it is not under the lock\n            signal?.SetResult(taskToSignal);\n        }\n\n        /// <summary>\n        /// Check if this worker is idle.\n        /// </summary>\n        public bool IsIdle() => currentWorkCycle == null;\n\n        /// <summary>\n        /// Wait for the current work cycle, and also the next work cycle if there is currently unserviced work.\n        /// </summary>\n        public Task WaitForCurrentWorkToBeServiced()\n        {\n            // Figure out exactly what we need to wait for\n            lock (lockable)\n            {\n                if (!moreWork)\n                {\n                    // Just wait for current work cycle\n                    return currentWorkCycle ?? Task.CompletedTask;\n                }\n                else\n                {\n                    // we need to wait for the next work cycle\n                    // but that task does not exist yet, so we use a promise that signals when the next work cycle is launched\n                    return nextWorkCycle ?? CreateNextWorkCyclePromise();\n                }\n            }\n        }\n\n        private Task CreateNextWorkCyclePromise()\n        {\n            // it's OK to run any continuations synchrnously because this promise only gets signaled at the very end of CheckForMoreWork\n            nextWorkCyclePromise = new TaskCompletionSource<Task>();\n            return nextWorkCycle = nextWorkCyclePromise.Task.Unwrap();\n        }\n\n        /// <summary>\n        /// Notify the worker that there is more work, and wait for the current work cycle, and also the next work cycle if there is currently unserviced work.\n        /// </summary>\n        public Task NotifyAndWaitForWorkToBeServiced()\n        {\n            lock (lockable)\n            {\n                if (currentWorkCycle != null)\n                {\n                    moreWork = true;\n                    return nextWorkCycle ?? CreateNextWorkCyclePromise();\n                }\n                else\n                {\n                    return Start();\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// A <see cref=\"BatchWorker\"/> implementation which executes a provided delegate as its <see cref=\"BatchWorker.Work\"/> implementation.\n    /// </summary>\n    public class BatchWorkerFromDelegate : BatchWorker\n    {\n        private readonly Func<Task> work;\n\n        /// <summary>\n        /// Initializes a new <see cref=\"BatchWorkerFromDelegate\"/> instance.\n        /// </summary>\n        /// <param name=\"work\">The delegate to invoke when <see cref=\"BatchWorker.Work\"/> is invoked.</param>\n        /// <param name=\"cancellationToken\">The cancellation token used to stop the worker.</param>\n        public BatchWorkerFromDelegate(Func<Task> work, CancellationToken cancellationToken = default)\n        {\n            this.work = work;\n            this.CancellationToken = cancellationToken;\n        }\n\n        /// <inheritdoc />\n        protected override Task Work()\n        {\n            return work();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Async/MultiTaskCompletionSource.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans;\n\n/// <summary>\n/// An alternative to <see cref=\"TaskCompletionSource{TResult}\"/> which completes only once a specified number of signals have been received.\n/// </summary>\ninternal sealed class MultiTaskCompletionSource\n{\n    private readonly TaskCompletionSource _tcs;\n    private int _count;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"MultiTaskCompletionSource\"/> class.\n    /// </summary>\n    /// <param name=\"count\">\n    /// The number of signals which must occur before this completion source completes.\n    /// </param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">\n    /// The count value is less than or equal to zero.\n    /// </exception>\n    public MultiTaskCompletionSource(int count)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(count, 0);\n        _tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        _count = count;\n    }\n\n    /// <summary>\n    /// Gets the task which is completed when a sufficient number of signals are received.\n    /// </summary>\n    public Task Task => _tcs.Task;\n\n    /// <summary>\n    /// Signals this instance.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">This method was called more times than the initially specified count argument allows.</exception>\n    public void SetOneResult()\n    {\n        var current = Interlocked.Decrement(ref _count);\n        if (current < 0)\n        {\n            throw new InvalidOperationException(\n                \"SetOneResult was called more times than initially specified by the count argument.\");\n        }\n\n        if (current == 0)\n        {\n            _tcs.SetResult();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Async/TaskExtensions.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Internal\n{\n    /// <summary>\n    /// Extensions for working with <see cref=\"Task\"/> and <see cref=\"Task{TResult}\"/>.\n    /// </summary>\n    internal static class OrleansTaskExtentions\n    {\n        public static ConfiguredTaskAwaitable SuppressThrowing(this ValueTask task) => task.AsTask().ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n        public static ConfiguredTaskAwaitable SuppressThrowing(this Task task) => task.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n        public static void Ignore(this ValueTask valueTask)\n        {\n            if (valueTask.IsCompletedSuccessfully)\n            {\n                valueTask.GetAwaiter().GetResult();\n            }\n            else\n            {\n                valueTask.AsTask().Ignore();\n            }\n        }\n\n        public static async Task LogException(this Task task, ILogger logger, ErrorCode errorCode, string message)\n        {\n            try\n            {\n                await task;\n            }\n            catch (Exception exc)\n            {\n                // TODO: pending on https://github.com/dotnet/runtime/issues/110570\n                logger.LogError((int)errorCode, exc, \"{Message}\", message);\n                throw;\n            }\n        }\n\n        // Executes an async function such as Exception is never thrown but rather always returned as a broken task.\n        public static async Task SafeExecute(Func<Task> action)\n        {\n            await action();\n        }\n\n        public static async Task ExecuteAndIgnoreException(Func<Task> action)\n        {\n            try\n            {\n                await action();\n            }\n            catch (Exception)\n            {\n                // dont re-throw, just eat it.\n            }\n        }\n\n        internal static string ToString(this Task t) => t == null ? \"null\" : $\"[Id={t.Id}, Status={t.Status}]\";\n\n        public static void WaitWithThrow(this Task task, TimeSpan timeout)\n        {\n            if (!task.Wait(timeout))\n            {\n                throw new TimeoutException($\"Task.WaitWithThrow has timed out after {timeout}.\");\n            }\n        }\n\n        internal static T WaitForResultWithThrow<T>(this Task<T> task, TimeSpan timeout)\n        {\n            if (!task.Wait(timeout))\n            {\n                throw new TimeoutException($\"Task<T>.WaitForResultWithThrow has timed out after {timeout}.\");\n            }\n            return task.Result;\n        }\n\n        /// <summary>\n        /// This will apply a timeout delay to the task, allowing us to exit early\n        /// </summary>\n        /// <param name=\"taskToComplete\">The task we will timeout after timeSpan</param>\n        /// <param name=\"timeout\">Amount of time to wait before timing out</param>\n        /// <param name=\"exceptionMessage\">Text to put into the timeout exception message</param>\n        /// <exception cref=\"TimeoutException\">If we time out we will get this exception</exception>\n        /// <returns>The completed task</returns>\n        public static async Task WithTimeout(this Task taskToComplete, TimeSpan timeout, string exceptionMessage = null)\n        {\n            if (taskToComplete.IsCompleted)\n            {\n                await taskToComplete;\n                return;\n            }\n\n            using var timeoutCancellationTokenSource = new CancellationTokenSource();\n            var completedTask = await Task.WhenAny(taskToComplete, Task.Delay(timeout, timeoutCancellationTokenSource.Token));\n\n            // We got done before the timeout, or were able to complete before this code ran, return the result\n            if (taskToComplete == completedTask)\n            {\n                timeoutCancellationTokenSource.Cancel();\n                // Await this so as to propagate the exception correctly\n                await taskToComplete;\n                return;\n            }\n\n            // We did not complete before the timeout, we fire and forget to ensure we observe any exceptions that may occur\n            taskToComplete.Ignore();\n            var errorMessage = exceptionMessage ?? $\"WithTimeout has timed out after {timeout}\";\n            throw new TimeoutException(errorMessage);\n        }\n\n        /// <summary>\n        /// This will apply a timeout delay to the task, allowing us to exit early\n        /// </summary>\n        /// <param name=\"taskToComplete\">The task we will timeout after timeSpan</param>\n        /// <param name=\"timeSpan\">Amount of time to wait before timing out</param>\n        /// <param name=\"exceptionMessage\">Text to put into the timeout exception message</param>\n        /// <exception cref=\"TimeoutException\">If we time out we will get this exception</exception>\n        /// <exception cref=\"TimeoutException\">If we time out we will get this exception</exception>\n        /// <returns>The value of the completed task</returns>\n        public static async Task<T> WithTimeout<T>(this Task<T> taskToComplete, TimeSpan timeSpan, string exceptionMessage = null)\n        {\n            if (taskToComplete.IsCompleted)\n            {\n                return await taskToComplete;\n            }\n\n            using var timeoutCancellationTokenSource = new CancellationTokenSource();\n            var completedTask = await Task.WhenAny(taskToComplete, Task.Delay(timeSpan, timeoutCancellationTokenSource.Token));\n\n            // We got done before the timeout, or were able to complete before this code ran, return the result\n            if (taskToComplete == completedTask)\n            {\n                timeoutCancellationTokenSource.Cancel();\n                // Await this so as to propagate the exception correctly\n                return await taskToComplete;\n            }\n\n            // We did not complete before the timeout, we fire and forget to ensure we observe any exceptions that may occur\n            taskToComplete.Ignore();\n            var errorMessage = exceptionMessage ?? $\"WithTimeout has timed out after {timeSpan}\";\n            throw new TimeoutException(errorMessage);\n        }\n\n        /// <summary>\n        /// For making an uncancellable task cancellable, by ignoring its result.\n        /// </summary>\n        /// <param name=\"taskToComplete\">The task to wait for unless cancelled</param>\n        /// <param name=\"message\">Message to set in the exception</param>\n        /// <param name=\"cancellationToken\">A cancellation token for cancelling the wait</param>\n        /// <returns></returns>\n        internal static async Task WithCancellation(\n            this Task taskToComplete,\n            string message,\n            CancellationToken cancellationToken)\n        {\n            try\n            {\n                await taskToComplete.WithCancellation(cancellationToken);\n            }\n            catch (TaskCanceledException ex)\n            {\n                throw new TaskCanceledException(message, ex);\n            }\n        }\n\n        /// <summary>\n        /// For making an uncancellable task cancellable, by ignoring its result.\n        /// </summary>\n        /// <param name=\"taskToComplete\">The task to wait for unless cancelled</param>\n        /// <param name=\"cancellationToken\">A cancellation token for cancelling the wait</param>\n        /// <returns></returns>\n        internal static Task WithCancellation(this Task taskToComplete, CancellationToken cancellationToken)\n        {\n            if (taskToComplete.IsCompleted || !cancellationToken.CanBeCanceled)\n            {\n                return taskToComplete;\n            }\n            else if (cancellationToken.IsCancellationRequested)\n            {\n                return Task.FromCanceled<object>(cancellationToken);\n            }\n            else\n            {\n                return MakeCancellable(taskToComplete, cancellationToken);\n            }\n        }\n\n        private static async Task MakeCancellable(Task task, CancellationToken cancellationToken)\n        {\n            var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);\n            using (cancellationToken.Register(() =>\n                      tcs.TrySetCanceled(cancellationToken), useSynchronizationContext: false))\n            {\n                var firstToComplete = await Task.WhenAny(task, tcs.Task).ConfigureAwait(false);\n\n                if (firstToComplete != task)\n                {\n                    task.Ignore();\n                }\n\n                await firstToComplete.ConfigureAwait(false);\n            }\n        }\n\n        internal static Task WrapInTask(Action action)\n        {\n            try\n            {\n                action();\n                return Task.CompletedTask;\n            }\n            catch (Exception exc)\n            {\n                return Task.FromException<object>(exc);\n            }\n        }\n\n        //The rationale for GetAwaiter().GetResult() instead of .Result\n        //is presented at https://github.com/aspnet/Security/issues/59.\n        internal static T GetResult<T>(this Task<T> task)\n        {\n            return task.GetAwaiter().GetResult();\n        }\n\n        internal static Task WhenCancelled(this CancellationToken token)\n        {\n            if (token.IsCancellationRequested)\n            {\n                return Task.CompletedTask;\n            }\n\n            var waitForCancellation = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);\n            token.Register(obj =>\n            {\n                var tcs = (TaskCompletionSource<object>)obj;\n                tcs.TrySetResult(null);\n            }, waitForCancellation);\n\n            return waitForCancellation.Task;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/ConcurrentLruCache.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing Orleans.Caching.Internal;\n\nnamespace Orleans.Caching;\n\n/// <summary>\n/// A pseudo LRU based on the TU-Q eviction policy. The LRU list is composed of 3 segments: hot, warm and cold.\n/// Cost of maintaining segments is amortized across requests. Items are only cycled when capacity is exceeded.\n/// Pure read does not cycle items if all segments are within capacity constraints. There are no global locks.\n/// On cache miss, a new item is added. Tail items in each segment are dequeued, examined, and are either enqueued\n/// or discarded.\n/// The TU-Q scheme of hot, warm and cold is similar to that used in MemCached (https://memcached.org/blog/modern-lru/)\n/// and OpenBSD (https://flak.tedunangst.com/post/2Q-buffer-cache-algorithm), but does not use a background thread\n/// to maintain the internal queues.\n/// </summary>\n/// <remarks>\n/// This implementation is derived from BitFaster.Caching (https://github.com/bitfaster/BitFaster.Caching), removing\n/// functionality that is not needed for Orleans (async, custom policies), to reduce the number of source files.\n/// \n/// Each segment has a capacity. When segment capacity is exceeded, items are moved as follows:\n/// <list type=\"number\">\n///   <item><description>New items are added to hot, WasAccessed = false.</description></item>\n///   <item><description>When items are accessed, update WasAccessed = true.</description></item>\n///   <item><description>When items are moved WasAccessed is set to false.</description></item>\n///   <item><description>When hot is full, hot tail is moved to either Warm or Cold depending on WasAccessed.</description></item>\n///   <item><description>When warm is full, warm tail is moved to warm head or cold depending on WasAccessed.</description></item>\n///   <item><description>When cold is full, cold tail is moved to warm head or removed from dictionary on depending on WasAccessed.</description></item>\n///</list>\n/// </remarks>\n/// <remarks>\n/// Initializes a new instance of the ConcurrentLruCore class with the specified concurrencyLevel, capacity, equality comparer, item policy and telemetry policy.\n/// </remarks>\n/// <param name=\"capacity\">The capacity.</param>\n/// <param name=\"comparer\">The equality comparer.</param>\ninternal class ConcurrentLruCache<K, V>(\n    int capacity,\n    IEqualityComparer<K>? comparer) : IEnumerable<KeyValuePair<K, V>>, ICacheMetrics, ConcurrentLruCache<K, V>.ITestAccessor\n    where K : notnull\n{\n    private readonly ConcurrentDictionary<K, LruItem> _dictionary = new(concurrencyLevel: -1, capacity: capacity, comparer: comparer);\n    private readonly ConcurrentQueue<LruItem> _hotQueue = new();\n    private readonly ConcurrentQueue<LruItem> _warmQueue = new();\n    private readonly ConcurrentQueue<LruItem> _coldQueue = new();\n    private readonly CapacityPartition _capacity = new(capacity);\n    private readonly TelemetryPolicy _telemetryPolicy = new();\n\n    // maintain count outside ConcurrentQueue, since ConcurrentQueue.Count holds a global lock\n    private PaddedQueueCount _counter;\n    private bool _isWarm;\n\n    /// <summary>\n    /// Initializes a new instance of the ConcurrentLruCore class with the specified capacity.\n    /// </summary>\n    /// <param name=\"capacity\">The capacity.</param>\n    public ConcurrentLruCache(int capacity) : this(capacity, comparer: null)\n    {\n    }\n\n    // No lock count: https://arbel.net/2013/02/03/best-practices-for-using-concurrentdictionary/\n    ///<inheritdoc/>\n    public int Count => _dictionary.Where(_ => true).Count();\n\n    ///<inheritdoc/>\n    public int Capacity => _capacity.Hot + _capacity.Warm + _capacity.Cold;\n\n    ///<inheritdoc/>\n    public ICacheMetrics Metrics => this;\n\n    /// <summary>\n    /// Gets the number of hot items.\n    /// </summary>\n    public int HotCount => Volatile.Read(ref _counter.Hot);\n\n    /// <summary>\n    /// Gets the number of warm items.\n    /// </summary>\n    public int WarmCount => Volatile.Read(ref _counter.Warm);\n\n    /// <summary>\n    /// Gets the number of cold items.\n    /// </summary>\n    public int ColdCount => Volatile.Read(ref _counter.Cold);\n\n    /// <summary>\n    /// Gets a collection containing the keys in the cache.\n    /// </summary>\n    public ICollection<K> Keys => _dictionary.Keys;\n\n    /// <summary>Returns an enumerator that iterates through the cache.</summary>\n    /// <returns>An enumerator for the cache.</returns>\n    /// <remarks>\n    /// The enumerator returned from the cache is safe to use concurrently with\n    /// reads and writes, however it does not represent a moment-in-time snapshot.\n    /// The contents exposed through the enumerator may contain modifications\n    /// made after <see cref=\"GetEnumerator\"/> was called.\n    /// </remarks>\n    public IEnumerator<KeyValuePair<K, V>> GetEnumerator()\n    {\n        foreach (var kvp in _dictionary)\n        {\n            yield return new KeyValuePair<K, V>(kvp.Key, kvp.Value.Value);\n        }\n    }\n\n    ///<inheritdoc/>\n    public V Get(K key)\n    {\n        if (!TryGet(key, out var value))\n        {\n            throw new KeyNotFoundException($\"Key '{key}' not found in the cache.\");\n        }\n\n        return value;\n    }\n\n    ///<inheritdoc/>\n    public bool TryGet(K key, [MaybeNullWhen(false)] out V value)\n    {\n        if (_dictionary.TryGetValue(key, out var item))\n        {\n            value = item.Value;\n            item.MarkAccessed();\n            _telemetryPolicy.IncrementHit();\n            return true;\n        }\n\n        value = default;\n        _telemetryPolicy.IncrementMiss();\n        return false;\n    }\n\n    public bool TryAdd(K key, V value)\n    {\n        var newItem = new LruItem(key, value);\n\n        if (_dictionary.TryAdd(key, newItem))\n        {\n            _hotQueue.Enqueue(newItem);\n            Cycle(Interlocked.Increment(ref _counter.Hot));\n            return true;\n        }\n\n        DisposeValue(newItem.Value);\n\n        return false;\n    }\n\n    ///<inheritdoc/>\n    public V GetOrAdd(K key, Func<K, V> valueFactory)\n    {\n        while (true)\n        {\n            if (TryGet(key, out var value))\n            {\n                return value;\n            }\n\n            // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.\n            value = valueFactory(key);\n\n            if (TryAdd(key, value))\n            {\n                return value;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the\n    /// existing value if the key already exists.\n    /// </summary>\n    /// <typeparam name=\"TArg\">The type of an argument to pass into valueFactory.</typeparam>\n    /// <param name=\"key\">The key of the element to add.</param>\n    /// <param name=\"valueFactory\">The factory function used to generate a value for the key.</param>\n    /// <param name=\"factoryArgument\">An argument value to pass into valueFactory.</param>\n    /// <returns>The value for the key. This will be either the existing value for the key if the key is already\n    /// in the cache, or the new value if the key was not in the cache.</returns>\n    public V GetOrAdd<TArg>(K key, Func<K, TArg, V> valueFactory, TArg factoryArgument)\n    {\n        while (true)\n        {\n            if (TryGet(key, out var value))\n            {\n                return value;\n            }\n\n            // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.\n            value = valueFactory(key, factoryArgument);\n\n            if (TryAdd(key, value))\n            {\n                return value;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Attempts to remove the specified key value pair.\n    /// </summary>\n    /// <param name=\"predicate\">The predicate used to determine if the item should be removed.</param>\n    /// <param name=\"predicateArgument\">Argument passed to the predicate.</param>\n    /// <returns>true if the item was removed successfully; otherwise, false.</returns>\n    public bool TryRemove<TArg>(K key, Func<V, TArg, bool> predicate, TArg predicateArgument)\n    {\n        if (_dictionary.TryGetValue(key, out var existing))\n        {\n            lock (existing)\n            {\n                if (predicate(existing.Value, predicateArgument))\n                {\n                    var kvp = new KeyValuePair<K, LruItem>(key, existing);\n                    if (_dictionary.TryRemove(kvp))\n                    {\n                        OnRemove(kvp.Value, ItemRemovedReason.Removed);\n                        return true;\n                    }\n                }\n            }\n\n            // it existed, but we couldn't remove - this means value was replaced after the TryGetValue (a race)\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Attempts to remove the specified key value pair.\n    /// </summary>\n    /// <param name=\"item\">The item to remove.</param>\n    /// <returns>true if the item was removed successfully; otherwise, false.</returns>\n    public bool TryRemove(KeyValuePair<K, V> item)\n    {\n        if (_dictionary.TryGetValue(item.Key, out var existing))\n        {\n            lock (existing)\n            {\n                if (EqualityComparer<V>.Default.Equals(existing.Value, item.Value))\n                {\n                    var kvp = new KeyValuePair<K, LruItem>(item.Key, existing);\n                    if (_dictionary.TryRemove(kvp))\n                    {\n                        OnRemove(kvp.Value, ItemRemovedReason.Removed);\n                        return true;\n                    }\n                }\n            }\n\n            // it existed, but we couldn't remove - this means value was replaced after the TryGetValue (a race)\n        }\n\n        return false;\n    }\n\n    /// <summary>\n    /// Attempts to remove and return the value that has the specified key.\n    /// </summary>\n    /// <param name=\"key\">The key of the element to remove.</param>\n    /// <param name=\"value\">When this method returns, contains the object removed, or the default value of the value type if key does not exist.</param>\n    /// <returns>true if the object was removed successfully; otherwise, false.</returns>\n    public bool TryRemove(K key, [MaybeNullWhen(false)] out V value)\n    {\n        if (_dictionary.TryRemove(key, out var item))\n        {\n            OnRemove(item, ItemRemovedReason.Removed);\n            value = item.Value;\n            return true;\n        }\n\n        value = default;\n        return false;\n    }\n\n    ///<inheritdoc/>\n    public bool TryRemove(K key) => TryRemove(key, out _);\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private void OnRemove(LruItem item, ItemRemovedReason reason)\n    {\n        // Mark as not accessed, it will later be cycled out of the queues because it can never be fetched\n        // from the dictionary. Note: Hot/Warm/Cold count will reflect the removed item until it is cycled\n        // from the queue.\n        item.WasAccessed = false;\n        item.WasRemoved = true;\n\n        if (reason == ItemRemovedReason.Evicted)\n        {\n            _telemetryPolicy.IncrementEvicted();\n        }\n\n        // serialize dispose (common case dispose not thread safe)\n        lock (item)\n        {\n            DisposeValue(item.Value);\n        }\n    }\n\n    ///<inheritdoc/>\n    ///<remarks>Note: Calling this method does not affect LRU order.</remarks>\n    public bool TryUpdate(K key, V value)\n    {\n        if (_dictionary.TryGetValue(key, out var existing))\n        {\n            lock (existing)\n            {\n                if (!existing.WasRemoved)\n                {\n                    var oldValue = existing.Value;\n\n                    existing.Value = value;\n\n                    _telemetryPolicy.IncrementUpdated();\n                    DisposeValue(oldValue);\n\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    ///<inheritdoc/>\n    ///<remarks>Note: Updates to existing items do not affect LRU order. Added items are at the top of the LRU.</remarks>\n    public void AddOrUpdate(K key, V value)\n    {\n        while (true)\n        {\n            // first, try to update\n            if (TryUpdate(key, value))\n            {\n                return;\n            }\n\n            // then try add\n            var newItem = new LruItem(key, value);\n\n            if (_dictionary.TryAdd(key, newItem))\n            {\n                _hotQueue.Enqueue(newItem);\n                Cycle(Interlocked.Increment(ref _counter.Hot));\n                return;\n            }\n\n            // if both update and add failed there was a race, try again\n        }\n    }\n\n    ///<inheritdoc/>\n    public void Clear()\n    {\n        // don't overlap Clear/Trim/TrimExpired\n        lock (_dictionary)\n        {\n            // evaluate queue count, remove everything including items removed from the dictionary but\n            // not the queues. This also avoids the expensive o(n) no lock count, or locking the dictionary.\n            var queueCount = HotCount + WarmCount + ColdCount;\n            TrimLiveItems(queueCount, ItemRemovedReason.Cleared);\n        }\n    }\n\n    /// <summary>\n    /// Trim the specified number of items from the cache. Removes items in LRU order.\n    /// </summary>\n    /// <param name=\"itemCount\">The number of items to remove.</param>\n    /// <returns>The number of items removed from the cache.</returns>\n    /// <exception cref=\"ArgumentOutOfRangeException\"><paramref name=\"itemCount\"/> is less than 0./</exception>\n    /// <exception cref=\"ArgumentOutOfRangeException\"><paramref name=\"itemCount\"/> is greater than capacity./</exception>\n    /// <remarks>\n    /// Note: Trim affects LRU order. Calling Trim resets the internal accessed status of items.\n    /// </remarks>\n    public void Trim(int itemCount)\n    {\n        var capacity = Capacity;\n        ArgumentOutOfRangeException.ThrowIfLessThan(itemCount, 1);\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(itemCount, capacity);\n\n        // clamp itemCount to number of items actually in the cache\n        itemCount = Math.Min(itemCount, HotCount + WarmCount + ColdCount);\n\n        // don't overlap Clear/Trim/TrimExpired\n        lock (_dictionary)\n        {\n            TrimLiveItems(itemCount, ItemRemovedReason.Trimmed);\n        }\n    }\n\n    private void TrimLiveItems(int itemCount, ItemRemovedReason reason)\n    {\n        // When items are touched, they are moved to warm by cycling. Therefore, to guarantee\n        // that we can remove itemCount items, we must cycle (2 * capacity.Warm) + capacity.Hot times.\n        // If clear is called during trimming, it would be possible to get stuck in an infinite\n        // loop here. The warm + hot limit also guards against this case.\n        var trimWarmAttempts = 0;\n        var itemsRemoved = 0;\n        var maxWarmHotAttempts = _capacity.Warm * 2 + _capacity.Hot;\n\n        while (itemsRemoved < itemCount && trimWarmAttempts < maxWarmHotAttempts)\n        {\n            if (Volatile.Read(ref _counter.Cold) > 0)\n            {\n                if (TryRemoveCold(reason) == (ItemDestination.Remove, 0))\n                {\n                    itemsRemoved++;\n                    trimWarmAttempts = 0;\n                }\n                else\n                {\n                    TrimWarmOrHot(reason);\n                }\n            }\n            else\n            {\n                TrimWarmOrHot(reason);\n                trimWarmAttempts++;\n            }\n        }\n\n        if (Volatile.Read(ref _counter.Warm) < _capacity.Warm)\n        {\n            Volatile.Write(ref _isWarm, false);\n        }\n    }\n\n    private void TrimWarmOrHot(ItemRemovedReason reason)\n    {\n        if (Volatile.Read(ref _counter.Warm) > 0)\n        {\n            CycleWarmUnchecked(reason);\n        }\n        else if (Volatile.Read(ref _counter.Hot) > 0)\n        {\n            CycleHotUnchecked(reason);\n        }\n    }\n\n    private void Cycle(int hotCount)\n    {\n        if (_isWarm)\n        {\n            (var dest, var count) = CycleHot(hotCount);\n\n            var cycles = 0;\n            while (cycles++ < 3 && dest != ItemDestination.Remove)\n            {\n                if (dest == ItemDestination.Warm)\n                {\n                    (dest, count) = CycleWarm(count);\n                }\n                else if (dest == ItemDestination.Cold)\n                {\n                    (dest, count) = CycleCold(count);\n                }\n            }\n\n            // If nothing was removed yet, constrain the size of warm and cold by discarding the coldest item.\n            if (dest != ItemDestination.Remove)\n            {\n                if (dest == ItemDestination.Warm && count > _capacity.Warm)\n                {\n                    count = LastWarmToCold();\n                }\n\n                ConstrainCold(count, ItemRemovedReason.Evicted);\n            }\n        }\n        else\n        {\n            // fill up the warm queue with new items until warm is full.\n            // else during warmup the cache will only use the hot + cold queues until any item is requested twice.\n            CycleDuringWarmup(hotCount);\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private void CycleDuringWarmup(int hotCount)\n    {\n        // do nothing until hot is full\n        if (hotCount > _capacity.Hot)\n        {\n            Interlocked.Decrement(ref _counter.Hot);\n\n            if (_hotQueue.TryDequeue(out var item))\n            {\n                // special case: removed during warmup\n                if (item.WasRemoved)\n                {\n                    return;\n                }\n\n                var count = Move(item, ItemDestination.Warm, ItemRemovedReason.Evicted);\n\n                // if warm is now full, overflow to cold and mark as warm\n                if (count > _capacity.Warm)\n                {\n                    Volatile.Write(ref _isWarm, true);\n                    count = LastWarmToCold();\n                    ConstrainCold(count, ItemRemovedReason.Evicted);\n                }\n            }\n            else\n            {\n                Interlocked.Increment(ref _counter.Hot);\n            }\n        }\n    }\n\n    private (ItemDestination, int) CycleHot(int hotCount)\n    {\n        if (hotCount > _capacity.Hot)\n        {\n            return CycleHotUnchecked(ItemRemovedReason.Evicted);\n        }\n\n        return (ItemDestination.Remove, 0);\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private (ItemDestination, int) CycleHotUnchecked(ItemRemovedReason removedReason)\n    {\n        Interlocked.Decrement(ref _counter.Hot);\n\n        if (_hotQueue.TryDequeue(out var item))\n        {\n            var where = RouteHot(item);\n            return (where, Move(item, where, removedReason));\n        }\n        else\n        {\n            Interlocked.Increment(ref _counter.Hot);\n            return (ItemDestination.Remove, 0);\n        }\n    }\n\n    private (ItemDestination, int) CycleWarm(int count)\n    {\n        if (count > _capacity.Warm)\n        {\n            return CycleWarmUnchecked(ItemRemovedReason.Evicted);\n        }\n\n        return (ItemDestination.Remove, 0);\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private (ItemDestination, int) CycleWarmUnchecked(ItemRemovedReason removedReason)\n    {\n        var wc = Interlocked.Decrement(ref _counter.Warm);\n\n        if (_warmQueue.TryDequeue(out var item))\n        {\n            if (item.WasRemoved)\n            {\n                return (ItemDestination.Remove, 0);\n            }\n\n            var where = RouteWarm(item);\n\n            // When the warm queue is full, we allow an overflow of 1 item before redirecting warm items to cold.\n            // This only happens when hit rate is high, in which case we can consider all items relatively equal in\n            // terms of which was least recently used.\n            if (where == ItemDestination.Warm && wc <= _capacity.Warm)\n            {\n                return (ItemDestination.Warm, Move(item, where, removedReason));\n            }\n            else\n            {\n                return (ItemDestination.Cold, Move(item, ItemDestination.Cold, removedReason));\n            }\n        }\n        else\n        {\n            Interlocked.Increment(ref _counter.Warm);\n            return (ItemDestination.Remove, 0);\n        }\n    }\n\n    private (ItemDestination, int) CycleCold(int count)\n    {\n        if (count > _capacity.Cold)\n        {\n            return TryRemoveCold(ItemRemovedReason.Evicted);\n        }\n\n        return (ItemDestination.Remove, 0);\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private (ItemDestination, int) TryRemoveCold(ItemRemovedReason removedReason)\n    {\n        Interlocked.Decrement(ref _counter.Cold);\n\n        if (_coldQueue.TryDequeue(out var item))\n        {\n            var where = RouteCold(item);\n            if (where == ItemDestination.Warm && Volatile.Read(ref _counter.Warm) <= _capacity.Warm)\n            {\n                return (ItemDestination.Warm, Move(item, where, removedReason));\n            }\n            else\n            {\n                Move(item, ItemDestination.Remove, removedReason);\n                return (ItemDestination.Remove, 0);\n            }\n        }\n        else\n        {\n            return (ItemDestination.Cold, Interlocked.Increment(ref _counter.Cold));\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private int LastWarmToCold()\n    {\n        Interlocked.Decrement(ref _counter.Warm);\n\n        if (_warmQueue.TryDequeue(out var item))\n        {\n            var destination = item.WasRemoved ? ItemDestination.Remove : ItemDestination.Cold;\n            return Move(item, destination, ItemRemovedReason.Evicted);\n        }\n        else\n        {\n            Interlocked.Increment(ref _counter.Warm);\n            return 0;\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private void ConstrainCold(int coldCount, ItemRemovedReason removedReason)\n    {\n        if (coldCount > _capacity.Cold && _coldQueue.TryDequeue(out var item))\n        {\n            Interlocked.Decrement(ref _counter.Cold);\n            Move(item, ItemDestination.Remove, removedReason);\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private int Move(LruItem item, ItemDestination where, ItemRemovedReason removedReason)\n    {\n        item.WasAccessed = false;\n\n        switch (where)\n        {\n            case ItemDestination.Warm:\n                _warmQueue.Enqueue(item);\n                return Interlocked.Increment(ref _counter.Warm);\n            case ItemDestination.Cold:\n                _coldQueue.Enqueue(item);\n                return Interlocked.Increment(ref _counter.Cold);\n            case ItemDestination.Remove:\n\n                var kvp = new KeyValuePair<K, LruItem>(item.Key, item);\n\n                if (_dictionary.TryRemove(kvp))\n                {\n                    OnRemove(item, removedReason);\n                }\n\n                break;\n        }\n\n        return 0;\n    }\n\n    /// <summary>Returns an enumerator that iterates through the cache.</summary>\n    /// <returns>An enumerator for the cache.</returns>\n    /// <remarks>\n    /// The enumerator returned from the cache is safe to use concurrently with\n    /// reads and writes, however it does not represent a moment-in-time snapshot.\n    /// The contents exposed through the enumerator may contain modifications\n    /// made after <see cref=\"GetEnumerator\"/> was called.\n    /// </remarks>\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n#if DEBUG\n    /// <summary>\n    /// Format the LRU as a string by converting all the keys to strings.\n    /// </summary>\n    /// <returns>The LRU formatted as a string.</returns>\n    internal string FormatLruString()\n    {\n        var sb = new System.Text.StringBuilder();\n\n        sb.Append(\"Hot [\");\n        sb.Append(string.Join(\",\", _hotQueue.Select(n => n.Key.ToString())));\n        sb.Append(\"] Warm [\");\n        sb.Append(string.Join(\",\", _warmQueue.Select(n => n.Key.ToString())));\n        sb.Append(\"] Cold [\");\n        sb.Append(string.Join(\",\", _coldQueue.Select(n => n.Key.ToString())));\n        sb.Append(']');\n\n        return sb.ToString();\n    }\n#endif\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static ItemDestination RouteHot(LruItem item)\n    {\n        if (item.WasRemoved)\n        {\n            return ItemDestination.Remove;\n        }\n\n        if (item.WasAccessed)\n        {\n            return ItemDestination.Warm;\n        }\n\n        return ItemDestination.Cold;\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static ItemDestination RouteWarm(LruItem item)\n    {\n        if (item.WasRemoved)\n        {\n            return ItemDestination.Remove;\n        }\n\n        if (item.WasAccessed)\n        {\n            return ItemDestination.Warm;\n        }\n\n        return ItemDestination.Cold;\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static ItemDestination RouteCold(LruItem item)\n    {\n        if (item.WasAccessed & !item.WasRemoved)\n        {\n            return ItemDestination.Warm;\n        }\n\n        return ItemDestination.Remove;\n    }\n\n    double ICacheMetrics.HitRatio => _telemetryPolicy.HitRatio;\n\n    long ICacheMetrics.Total => _telemetryPolicy.Total;\n\n    long ICacheMetrics.Hits => _telemetryPolicy.Hits;\n\n    long ICacheMetrics.Misses => _telemetryPolicy.Misses;\n\n    long ICacheMetrics.Evicted => _telemetryPolicy.Evicted;\n\n    long ICacheMetrics.Updated => _telemetryPolicy.Updated;\n\n    ConcurrentQueue<LruItem> ITestAccessor.HotQueue => _hotQueue;\n    ConcurrentQueue<LruItem> ITestAccessor.WarmQueue => _warmQueue;\n    ConcurrentQueue<LruItem> ITestAccessor.ColdQueue => _coldQueue;\n    ConcurrentDictionary<K, LruItem> ITestAccessor.Dictionary => _dictionary;\n    bool ITestAccessor.IsWarm => _isWarm;\n\n    /// <summary>\n    /// Represents an LRU item.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the LruItem class with the specified key and value.\n    /// </remarks>\n    /// <param name=\"key\">The key.</param>\n    /// <param name=\"value\">The value.</param>\n    // NOTE: Internal for testing\n    [DebuggerDisplay(\"[{Key}] = {Value}\")]\n    internal sealed class LruItem(K key, V value)\n    {\n        private V _data = value;\n\n        // only used when V is a non-atomic value type to prevent torn reads\n        private int _sequence;\n\n        /// <summary>\n        /// Gets the key.\n        /// </summary>\n        public readonly K Key = key;\n\n        /// <summary>\n        /// Gets or sets the value.\n        /// </summary>\n        public V Value\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get\n            {\n                if (TypeProps<V>.IsWriteAtomic)\n                {\n                    return _data;\n                }\n                else\n                {\n                    return SeqLockRead();\n                }\n            }\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set\n            {\n                if (TypeProps<V>.IsWriteAtomic)\n                {\n                    _data = value;\n                }\n                else\n                {\n                    SeqLockWrite(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the item was accessed.\n        /// </summary>\n        public bool WasAccessed { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the item was removed.\n        /// </summary>\n        public bool WasRemoved { get; set; }\n\n        /// <summary>\n        /// Marks the item as accessed, if it was not already accessed.\n        /// </summary>\n        public void MarkAccessed()\n        {\n            if (!WasAccessed)\n            {\n                WasAccessed = true;\n            }\n        }\n\n        internal V SeqLockRead()\n        {\n            var spin = new SpinWait();\n            while (true)\n            {\n                var start = Volatile.Read(ref _sequence);\n\n                if ((start & 1) == 1)\n                {\n                    // A write is in progress, spin.\n                    spin.SpinOnce();\n                    continue;\n                }\n\n                var copy = _data;\n\n                var end = Volatile.Read(ref _sequence);\n                if (start == end)\n                {\n                    return copy;\n                }\n            }\n        }\n\n        // Note: LruItem should be locked while invoking this method. Multiple writer threads are not supported.\n        internal void SeqLockWrite(V value)\n        {\n            Interlocked.Increment(ref _sequence);\n\n            _data = value;\n\n            Interlocked.Increment(ref _sequence);\n        }\n    }\n\n    /// <summary>\n    /// Represents a telemetry policy with counters and events.\n    /// </summary>\n    [DebuggerDisplay(\"Hit = {Hits}, Miss = {Misses}, Upd = {Updated}, Evict = {Evicted}\")]\n    internal readonly struct TelemetryPolicy\n    {\n        private readonly Counter _hitCount = new();\n        private readonly Counter _missCount = new();\n        private readonly Counter _evictedCount = new();\n        private readonly Counter _updatedCount = new();\n\n        public TelemetryPolicy()\n        {\n        }\n\n        ///<inheritdoc/>\n        public readonly double HitRatio => Total == 0 ? 0 : Hits / (double)Total;\n\n        ///<inheritdoc/>\n        public readonly long Total => _hitCount.Count() + _missCount.Count();\n\n        ///<inheritdoc/>\n        public readonly long Hits => _hitCount.Count();\n\n        ///<inheritdoc/>\n        public readonly long Misses => _missCount.Count();\n\n        ///<inheritdoc/>\n        public readonly long Evicted => _evictedCount.Count();\n\n        ///<inheritdoc/>\n        public readonly long Updated => _updatedCount.Count();\n\n        ///<inheritdoc/>\n        public readonly void IncrementMiss() => _missCount.Increment();\n\n        ///<inheritdoc/>\n        public readonly void IncrementHit() => _hitCount.Increment();\n\n        ///<inheritdoc/>\n        public readonly void IncrementEvicted() => _evictedCount.Increment();\n\n        ///<inheritdoc/>\n        public readonly void IncrementUpdated() => _updatedCount.Increment();\n    }\n\n    private enum ItemDestination\n    {\n        Warm,\n        Cold,\n        Remove\n    }\n\n    private enum ItemRemovedReason\n    {\n        Removed,\n        Evicted,\n        Cleared,\n        Trimmed,\n    }\n\n    internal interface ITestAccessor\n    {\n        public ConcurrentQueue<LruItem> HotQueue { get; }\n        public ConcurrentQueue<LruItem> WarmQueue { get; }\n        public ConcurrentQueue<LruItem> ColdQueue { get; }\n        public ConcurrentDictionary<K, LruItem> Dictionary { get; }\n        public bool IsWarm { get; }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static void DisposeValue(V value)\n    {\n        if (value is IDisposable d)\n        {\n            d.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/CacheDebugView.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Caching.Internal;\n\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/CacheDebugView.cs\n[ExcludeFromCodeCoverage]\ninternal sealed class CacheDebugView<K, V>\n    where K : notnull\n{\n    private readonly ConcurrentLruCache<K, V> _cache;\n\n    public CacheDebugView(ConcurrentLruCache<K, V> cache)\n    {\n        ArgumentNullException.ThrowIfNull(cache);\n        _cache = cache;\n    }\n\n    public KeyValuePair<K, V>[] Items\n    {\n        get\n        {\n            var items = new KeyValuePair<K, V>[_cache.Count];\n\n            var index = 0;\n            foreach (var kvp in _cache)\n            {\n                items[index++] = kvp;\n            }\n            return items;\n        }\n    }\n\n    public ICacheMetrics? Metrics => _cache.Metrics;\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/CapacityPartition.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace Orleans.Caching.Internal;\n\n/// <summary>\n/// A capacity partitioning scheme that favors frequently accessed items by allocating 80%\n/// capacity to the warm queue.\n/// </summary>\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Lru/FavorWarmPartition.cs\n[DebuggerDisplay(\"{Hot}/{Warm}/{Cold}\")]\ninternal readonly struct CapacityPartition\n{\n    /// <summary>\n    /// Default to 80% capacity allocated to warm queue, 20% split equally for hot and cold.\n    /// This favors frequently accessed items.\n    /// </summary>\n    public const double DefaultWarmRatio = 0.8;\n\n    /// <summary>\n    /// Initializes a new instance of the CapacityPartition class with the specified capacity and the default warm ratio.\n    /// </summary>\n    /// <param name=\"totalCapacity\">The total capacity.</param>\n    public CapacityPartition(int totalCapacity)\n        : this(totalCapacity, DefaultWarmRatio)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the CapacityPartition class with the specified capacity and warm ratio.\n    /// </summary>\n    /// <param name=\"totalCapacity\">The total capacity.</param>\n    /// <param name=\"warmRatio\">The ratio of warm items to hot and cold items.</param>\n    public CapacityPartition(int totalCapacity, double warmRatio)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThan(totalCapacity, 3);\n        ArgumentOutOfRangeException.ThrowIfLessThan(warmRatio, 0.0);\n        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(warmRatio, 1.0);\n\n        var (hot, warm, cold) = ComputeQueueCapacity(totalCapacity, warmRatio);\n        Debug.Assert(cold >= 1);\n        Debug.Assert(warm >= 1);\n        Debug.Assert(hot >= 1);\n        Hot = hot;\n        Warm = warm;\n        Cold = cold;\n    }\n\n    public int Cold { get; }\n\n    public int Warm { get; }\n\n    public int Hot { get; }\n\n    private static (int hot, int warm, int cold) ComputeQueueCapacity(int capacity, double warmRatio)\n    {\n        var warm2 = (int)(capacity * warmRatio);\n        var hot2 = (capacity - warm2) / 2;\n\n        if (hot2 < 1)\n        {\n            hot2 = 1;\n        }\n\n        var cold2 = hot2;\n\n        var overflow = warm2 + hot2 + cold2 - capacity;\n        warm2 -= overflow;\n\n        return (hot2, warm2, cold2);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/Counter.cs",
    "content": "#nullable enable\n/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/publicdomain/zero/1.0/\n */\n\nusing Orleans;\n\nnamespace Orleans.Caching.Internal;\n\n/// <summary>\n/// A thread-safe counter suitable for high throughput counting across many concurrent threads.\n/// </summary>\n/// Based on the LongAdder class by Doug Lea.\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Counters/Counter.cs\ninternal sealed class Counter : Striped64\n{\n    /// <summary>\n    /// Creates a new Counter with an initial sum of zero.\n    /// </summary>\n    public Counter() { }\n\n    /// <summary>\n    /// Computes the current count.\n    /// </summary>\n    /// <returns>The current sum.</returns>\n    public long Count()\n    {\n        var @as = cells; Cell a;\n        var sum = @base.VolatileRead();\n        if (@as != null)\n        {\n            for (var i = 0; i < @as.Length; ++i)\n            {\n                if ((a = @as[i]) != null)\n                    sum += a.Value.VolatileRead();\n            }\n        }\n        return sum;\n    }\n\n    /// <summary>\n    /// Increment by 1.\n    /// </summary>\n    public void Increment()\n    {\n        Add(1L);\n    }\n\n    /// <summary>\n    /// Adds the specified value.\n    /// </summary>\n    /// <param name=\"value\">The value to add.</param>\n    public void Add(long value)\n    {\n        Cell[]? @as;\n        long b, v;\n        int m;\n        Cell a;\n        if ((@as = cells) != null || !@base.CompareAndSwap(b = @base.VolatileRead(), b + value))\n        {\n            var uncontended = true;\n            if (@as == null || (m = @as.Length - 1) < 0 || (a = @as[GetProbe() & m]) == null || !(uncontended = a.Value.CompareAndSwap(v = a.Value.VolatileRead(), v + value)))\n            {\n                LongAccumulate(value, uncontended);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/ICacheMetrics.cs",
    "content": "namespace Orleans.Caching.Internal;\n\n/// <summary>\n/// Represents cache metrics collected over the lifetime of the cache.\n/// If metrics are disabled.\n/// </summary>\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/ICacheMetrics.cs?plain=1#L8C22-L8C35\ninternal interface ICacheMetrics\n{\n    /// <summary>\n    /// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits.\n    /// </summary>\n    double HitRatio { get; }\n\n    /// <summary>\n    /// Gets the total number of requests made to the cache.\n    /// </summary>\n    long Total { get; }\n\n    /// <summary>\n    /// Gets the total number of cache hits.\n    /// </summary>\n    long Hits { get; }\n\n    /// <summary>\n    /// Gets the total number of cache misses.\n    /// </summary>\n    long Misses { get; }\n\n    /// <summary>\n    /// Gets the total number of evicted items.\n    /// </summary>\n    long Evicted { get; }\n\n    /// <summary>\n    /// Gets the total number of updated items.\n    /// </summary>\n    long Updated { get; }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/PaddedLong.cs",
    "content": "using System.Runtime.InteropServices;\nusing System.Threading;\n\nnamespace Orleans.Caching.Internal;\n\n/// <summary>\n/// A long value padded by the size of a CPU cache line to mitigate false sharing.\n/// </summary>\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Counters/PaddedLong.cs\n[StructLayout(LayoutKind.Explicit, Size = 2 * Padding.CACHE_LINE_SIZE)] // padding before/between/after fields\ninternal struct PaddedLong\n{\n    /// <summary>\n    /// The value.\n    /// </summary>\n    [FieldOffset(Padding.CACHE_LINE_SIZE)] public long Value;\n\n    /// <summary>\n    /// Reads the value of the field, and on systems that require it inserts a memory barrier to \n    /// prevent reordering of memory operations.\n    /// </summary>\n    /// <returns>The value that was read.</returns>\n    public long VolatileRead() => Volatile.Read(ref Value);\n\n    /// <summary>\n    /// Compares the current value with an expected value, if they are equal replaces the current value.\n    /// </summary>\n    /// <param name=\"expected\">The expected value.</param>\n    /// <param name=\"updated\">The updated value.</param>\n    /// <returns>True if the value is updated, otherwise false.</returns>\n    public bool CompareAndSwap(long expected, long updated) => Interlocked.CompareExchange(ref Value, updated, expected) == expected;\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/PaddedQueueCount.cs",
    "content": "using System.Diagnostics;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Caching.Internal;\n\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Lru/PaddedQueueCount.cs\n[DebuggerDisplay(\"Hot = {Hot}, Warm = {Warm}, Cold = {Cold}\")]\n[StructLayout(LayoutKind.Explicit, Size = 4 * Padding.CACHE_LINE_SIZE)] // padding before/between/after fields\ninternal struct PaddedQueueCount\n{\n    [FieldOffset(1 * Padding.CACHE_LINE_SIZE)] public int Hot;\n    [FieldOffset(2 * Padding.CACHE_LINE_SIZE)] public int Warm;\n    [FieldOffset(3 * Padding.CACHE_LINE_SIZE)] public int Cold;\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/Padding.cs",
    "content": "namespace Orleans.Caching.Internal;\n\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Padding.cs\ninternal static class Padding\n{\n#if TARGET_ARM64 || TARGET_LOONGARCH64\n    internal const int CACHE_LINE_SIZE = 128;\n#else\n    internal const int CACHE_LINE_SIZE = 64;\n#endif\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/Striped64.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\n\n/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/publicdomain/zero/1.0/\n */\n\nnamespace Orleans.Caching.Internal;\n\n/*\n * This class maintains a lazily-initialized table of atomically\n * updated variables, plus an extra \"base\" field. The table size\n * is a power of two. Indexing uses masked per-thread hash codes.\n * Nearly all declarations in this class are package-private,\n * accessed directly by subclasses.\n *\n * Table entries are of class Cell; a variant of AtomicLong padded\n * to reduce cache contention on most processors. Padding is\n * overkill for most Atomics because they are usually irregularly\n * scattered in memory and thus don't interfere much with each\n * other. But Atomic objects residing in arrays will tend to be\n * placed adjacent to each other, and so will most often share\n * cache lines (with a huge negative performance impact) without\n * this precaution.\n *\n * In part because Cells are relatively large, we avoid creating\n * them until they are needed.  When there is no contention, all\n * updates are made to the base field.  Upon first contention (a\n * failed CAS on base update), the table is initialized to size 2.\n * The table size is doubled upon further contention until\n * reaching the nearest power of two greater than or equal to the\n * number of CPUS. Table slots remain empty (null) until they are\n * needed.\n *\n * A single spinlock (\"busy\") is used for initializing and\n * resizing the table, as well as populating slots with new Cells.\n * There is no need for a blocking lock; when the lock is not\n * available, threads try other slots (or the base).  During these\n * retries, there is increased contention and reduced locality,\n * which is still better than alternatives.\n *\n * Per-thread hash codes are initialized to random values.\n * Contention and/or table collisions are indicated by failed\n * CASes when performing an update operation (see method\n * retryUpdate). Upon a collision, if the table size is less than\n * the capacity, it is doubled in size unless some other thread\n * holds the lock. If a hashed slot is empty, and lock is\n * available, a new Cell is created. Otherwise, if the slot\n * exists, a CAS is tried.  Retries proceed by \"double hashing\",\n * using a secondary hash (Marsaglia XorShift) to try to find a\n * free slot.\n *\n * The table size is capped because, when there are more threads\n * than CPUs, supposing that each thread were bound to a CPU,\n * there would exist a perfect hash function mapping threads to\n * slots that eliminates collisions. When we reach capacity, we\n * search for this mapping by randomly varying the hash codes of\n * colliding threads.  Because search is random, and collisions\n * only become known via CAS failures, convergence can be slow,\n * and because threads are typically not bound to CPUS forever,\n * may not occur at all. However, despite these limitations,\n * observed contention rates are typically low in these cases.\n *\n * It is possible for a Cell to become unused when threads that\n * once hashed to it terminate, as well as in the case where\n * doubling the table causes no thread to hash to it under\n * expanded mask.  We do not try to detect or remove such cells,\n * under the assumption that for long-running instances, observed\n * contention levels will recur, so the cells will eventually be\n * needed again; and for short-lived ones, it does not matter.\n */\n\n/// <summary>\n/// Maintains a lazily-initialized table of atomically updated variables, plus an extra \n/// \"base\" field. The table size is a power of two. Indexing uses masked thread IDs.\n/// </summary>\n// Derived from BitFaster.Caching by Alex Peck\n// https://github.com/bitfaster/BitFaster.Caching/blob/5b2d64a1afcc251787fbe231c6967a62820fc93c/BitFaster.Caching/Counters/Striped64.cs\n[ExcludeFromCodeCoverage]\ninternal abstract class Striped64\n{\n    // Number of CPUS, to place bound on table size\n    private static readonly int MaxBuckets = Environment.ProcessorCount * 4;\n\n    /// <summary>\n    /// The base value used mainly when there is no contention, but also as a fallback \n    /// during table initialization races. Updated via CAS.\n    /// </summary>\n    protected PaddedLong @base;\n\n    /// <summary>\n    /// When non-null, size is a power of 2.\n    /// </summary>\n    protected Cell[]? cells;\n    private int _cellsBusy;\n\n    /// <summary>\n    /// A wrapper for PaddedLong.\n    /// </summary>\n    /// <param name=\"value\">The value.</param>\n    protected sealed class Cell(long value)\n    {\n        /// <summary>\n        /// The value of the cell.\n        /// </summary>\n        public PaddedLong Value = new() { Value = value };\n    }\n\n    /**\n     * CASes the cellsBusy field from 0 to 1 to acquire lock.\n     */\n    private bool CasCellsBusy() => Interlocked.CompareExchange(ref _cellsBusy, 1, 0) == 0;\n\n    private void VolatileWriteNotBusy() => Volatile.Write(ref _cellsBusy, 0);\n\n    /**\n     * Returns the probe value for the current thread.\n     * Duplicated from ThreadLocalRandom because of packaging restrictions.\n     */\n    protected static int GetProbe() =>\n        // Note: this results in higher throughput than introducing a random.\n        Environment.CurrentManagedThreadId;\n\n    /**\n    * Pseudo-randomly advances and records the given probe value for the\n    * given thread.\n    * Duplicated from ThreadLocalRandom because of packaging restrictions.\n    */\n    private static int AdvanceProbe(int probe)\n    {\n        // xorshift\n        probe ^= probe << 13;\n        probe ^= (int)((uint)probe >> 17);\n        probe ^= probe << 5;\n        return probe;\n    }\n\n    /**\n     * Handles cases of updates involving initialization, resizing,\n     * creating new Cells, and/or contention. See above for\n     * explanation. This method suffers the usual non-modularity\n     * problems of optimistic retry code, relying on rechecked sets of\n     * reads.\n     *\n     * @param x the value\n     * @param wasUncontended false if CAS failed before call\n     */\n    protected void LongAccumulate(long x, bool wasUncontended)\n    {\n        var h = GetProbe();\n\n        // True if last slot nonempty\n        var collide = false;\n        while (true)\n        {\n            Cell[]? @as; Cell a; int n; long v;\n            if ((@as = cells) != null && (n = @as.Length) > 0)\n            {\n                if ((a = @as[n - 1 & h]) == null)\n                {\n                    if (_cellsBusy == 0)\n                    {\n                        // Try to attach new Cell\n                        // Optimistically create\n                        var r = new Cell(x);\n                        if (_cellsBusy == 0 && CasCellsBusy())\n                        {\n                            try\n                            {\n                                // Recheck under lock\n                                Cell[]? rs; int m, j;\n                                if ((rs = cells) != null &&\n                                    (m = rs.Length) > 0 &&\n                                    rs[j = m - 1 & h] == null)\n                                {\n                                    rs[j] = r;\n                                    break;\n                                }\n                            }\n                            finally\n                            {\n                                VolatileWriteNotBusy();\n                            }\n\n                            // Slot is now non-empty\n                            continue;\n                        }\n                    }\n                    collide = false;\n                }\n                else if (!wasUncontended)\n                {\n                    // CAS already known to fail\n                    // Continue after rehash\n                    wasUncontended = true;\n                }\n                else if (a.Value.CompareAndSwap(v = a.Value.VolatileRead(), v + x))\n                {\n                    break;\n                }\n                else if (n >= MaxBuckets || cells != @as)\n                {\n                    // At max size or stale\n                    collide = false;\n                }\n                else if (!collide)\n                {\n                    collide = true;\n                }\n                else if (_cellsBusy == 0 && CasCellsBusy())\n                {\n                    try\n                    {\n                        if (cells == @as)\n                        {\n                            // Expand table unless stale\n                            var rs = new Cell[n << 1];\n                            for (var i = 0; i < n; ++i)\n                            {\n                                rs[i] = @as[i];\n                            }\n\n                            cells = rs;\n                        }\n                    }\n                    finally\n                    {\n                        VolatileWriteNotBusy();\n                    }\n\n                    collide = false;\n\n                    // Retry with expanded table\n                    continue;\n                }\n\n                // Rehash\n                h = AdvanceProbe(h);\n            }\n            else if (_cellsBusy == 0 && cells == @as && CasCellsBusy())\n            {\n                try\n                {\n                    // Initialize table\n                    if (cells == @as)\n                    {\n                        var rs = new Cell[2];\n                        rs[h & 1] = new Cell(x);\n                        cells = rs;\n                        break;\n                    }\n                }\n                finally\n                {\n                    VolatileWriteNotBusy();\n                }\n            }\n\n            // Fall back on using base\n            else if (@base.CompareAndSwap(v = @base.VolatileRead(), v + x))\n            {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Caching/Internal/TypeProps.cs",
    "content": "using System;\n\nnamespace Orleans.Caching.Internal;\n\n// https://source.dot.net/#System.Collections.Concurrent/System/Collections/Concurrent/ConcurrentDictionary.cs,2293\ninternal static class TypeProps<T>\n{\n    /// <summary>Whether T's type can be written atomically (i.e., with no danger of torn reads).</summary>\n    internal static readonly bool IsWriteAtomic = IsWriteAtomicPrivate();\n\n    private static bool IsWriteAtomicPrivate()\n    {\n        // Section 12.6.6 of ECMA CLI explains which types can be read and written atomically without\n        // the risk of tearing. See https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf\n\n        if (!typeof(T).IsValueType ||\n            typeof(T) == typeof(nint) ||\n            typeof(T) == typeof(nuint))\n        {\n            return true;\n        }\n\n        switch (Type.GetTypeCode(typeof(T)))\n        {\n            case TypeCode.Boolean:\n            case TypeCode.Byte:\n            case TypeCode.Char:\n            case TypeCode.Int16:\n            case TypeCode.Int32:\n            case TypeCode.SByte:\n            case TypeCode.Single:\n            case TypeCode.UInt16:\n            case TypeCode.UInt32:\n                return true;\n\n            case TypeCode.Double:\n            case TypeCode.Int64:\n            case TypeCode.UInt64:\n                return nint.Size == 8;\n\n            default:\n                return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Cancellation/IGrainCallCancellationExtension.cs",
    "content": "#nullable enable\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime;\n\ninternal interface IGrainCallCancellationExtension : IGrainExtension\n{\n    /// <summary>\n    /// Indicates that a cancellation token has been canceled.\n    /// </summary>\n    /// <param name=\"senderGrainId\">\n    /// The <see cref=\"GrainId\"/> of the original message sender.\n    /// </param>\n    /// <param name=\"messageId\">\n    /// The message id of the request message being canceled.\n    /// </param>\n    /// <returns>\n    /// A <see cref=\"Task\"/> representing the operation.\n    /// </returns>\n    [AlwaysInterleave, OneWay]\n    ValueTask CancelRequestAsync(GrainId senderGrainId, CorrelationId messageId);\n}\n\n/// <summary>\n/// Functionality for cancelling grain calls.\n/// </summary>\ninternal interface IGrainCallCancellationManager\n{\n    /// <summary>\n    /// Attempts to cancel a grain call.\n    /// </summary>\n    void SignalCancellation(SiloAddress? targetSilo, GrainId targetGrainId, GrainId sendingGrainId, CorrelationId messageId);\n}\n\ninternal sealed class ExternalClientGrainCallCancellationManager(IInternalGrainFactory grainFactory) : IGrainCallCancellationManager\n{\n    public void SignalCancellation(SiloAddress? targetSilo, GrainId targetGrainId, GrainId sendingGrainId, CorrelationId messageId)\n    {\n        var targetGrain = grainFactory.GetGrain<IGrainCallCancellationExtension>(targetGrainId);\n        targetGrain.CancelRequestAsync(sendingGrainId, messageId).Ignore();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/ClientObservers/ClientGatewayObserver.cs",
    "content": "using Orleans.Messaging;\nusing Orleans.Runtime;\n\nnamespace Orleans.ClientObservers\n{\n    /// <summary>\n    /// Handles gateway notifications which are sent to connected clients.\n    /// </summary>\n    internal interface IClientGatewayObserver : IGrainObserver\n    {\n        /// <summary>\n        /// Signals a client that it should stop sending messages to the specified gateway.\n        /// </summary>\n        /// <param name=\"gateway\">The gateway</param>\n        void StopSendingToGateway(SiloAddress gateway);\n    }\n\n    /// <summary>\n    /// Handles gateway notification events.\n    /// </summary>\n    internal sealed class ClientGatewayObserver : ClientObserver, IClientGatewayObserver\n    {\n        private static readonly IdSpan ScopedId = IdSpan.Create(nameof(ClientGatewayObserver));\n\n        private readonly GatewayManager gatewayManager;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientGatewayObserver\"/> class.\n        /// </summary>\n        /// <param name=\"gatewayManager\">\n        /// The gateway manager.\n        /// </param>\n        public ClientGatewayObserver(GatewayManager gatewayManager)\n        {\n            this.gatewayManager = gatewayManager;\n        }\n\n        /// <inheritdoc />\n        public void StopSendingToGateway(SiloAddress gateway) => this.gatewayManager.MarkAsUnavailableForSend(gateway);\n\n        internal override ObserverGrainId GetObserverGrainId(ClientGrainId clientId) => ObserverGrainId.Create(clientId, ScopedId);\n\n        internal static IClientGatewayObserver GetObserver(IInternalGrainFactory grainFactory, ClientGrainId clientId)\n        {\n            var observerId = ObserverGrainId.Create(clientId, ScopedId);\n            return grainFactory.GetGrain<IClientGatewayObserver>(observerId.GrainId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/ClientObservers/ClientObserver.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans.ClientObservers\n{\n    /// <summary>\n    /// Base type for special client-wide observers.\n    /// </summary>\n    internal abstract class ClientObserver\n    {\n        /// <summary>\n        /// Gets the observer id.\n        /// </summary>\n        /// <param name=\"clientId\">The client id.</param>\n        /// <returns>The observer id.</returns>\n        internal abstract ObserverGrainId GetObserverGrainId(ClientGrainId clientId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/CodeGeneration/GrainInterfaceUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.CodeGeneration\n{\n    /// <summary>\n    /// Utilities for grain interface types.\n    /// </summary>\n    internal static class GrainInterfaceUtils\n    {\n        /// <summary>\n        /// Gets all grain interface methods for a specified type, which may be a class.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"bAllMethods\">Whether to get all methods or only declared methods.</param>\n        /// <returns>All grain interface methods for a specified type.</returns>\n        public static MethodInfo[] GetMethods(Type grainType, bool bAllMethods = true)\n        {\n            var methodInfos = new List<MethodInfo>();\n            GetMethodsImpl(grainType, grainType, methodInfos);\n            var flags = BindingFlags.Public | BindingFlags.Instance;\n            if (!bAllMethods)\n                flags |= BindingFlags.DeclaredOnly;\n\n            MethodInfo[] infos = grainType.GetMethods(flags);\n            foreach (var methodInfo in infos)\n            {\n                if (!methodInfos.Contains(methodInfo, MethodInfoComparer.Default))\n                {\n                    methodInfos.Add(methodInfo);\n                }\n            }\n\n            return methodInfos.ToArray();\n\n            static void GetMethodsImpl(Type grainType, Type serviceType, List<MethodInfo> methodInfos)\n            {\n                foreach (var iType in GetGrainInterfaces(serviceType))\n                {\n                    if (grainType.IsClass)\n                    {\n                        var mapping = grainType.GetInterfaceMap(iType);\n                        foreach (var methodInfo in iType.GetMethods(BindingFlags.Instance | BindingFlags.Public))\n                        {\n                            foreach (var info in mapping.TargetMethods)\n                            {\n                                if (info.DeclaringType == grainType && MethodInfoComparer.Default.Equals(methodInfo, info))\n                                {\n                                    if (!methodInfos.Contains(methodInfo, MethodInfoComparer.Default))\n                                        methodInfos.Add(methodInfo);\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                    else if (grainType.IsInterface)\n                    {\n                        foreach (var methodInfo in iType.GetMethods(BindingFlags.Instance | BindingFlags.Public))\n                        {\n                            if (!methodInfos.Contains(methodInfo, MethodInfoComparer.Default))\n                                methodInfos.Add(methodInfo);\n                        }\n                    }\n                }\n            }\n\n            static List<Type> GetGrainInterfaces(Type type)\n            {\n                var res = new List<Type>();\n\n                if (IsGrainInterface(type))\n                {\n                    res.Add(type);\n                }\n\n                foreach (var interfaceType in type.GetInterfaces())\n                {\n                    res.Add(interfaceType);\n                }\n\n                return res;\n            }\n\n            static bool IsGrainInterface(Type t)\n            {\n                if (t.IsClass)\n                    return false;\n                if (t == typeof(IGrainObserver) || t == typeof(IAddressable) || t == typeof(IGrainExtension))\n                    return false;\n                if (t == typeof(IGrain) || t == typeof(IGrainWithGuidKey) || t == typeof(IGrainWithIntegerKey)\n                    || t == typeof(IGrainWithGuidCompoundKey) || t == typeof(IGrainWithIntegerCompoundKey))\n                    return false;\n                if (t == typeof(ISystemTarget))\n                    return false;\n\n                return typeof(IAddressable).IsAssignableFrom(t);\n            }\n        }\n\n        public static int GetGrainClassTypeCode(Type grainClass) => (int)StableHash.ComputeHash(RuntimeTypeNameFormatter.Format(grainClass));\n\n        private sealed class MethodInfoComparer : IEqualityComparer<MethodInfo>, IComparer<MethodInfo>\n        {\n            public static MethodInfoComparer Default { get; } = new();\n\n            private MethodInfoComparer()\n            {\n            }\n\n            public bool Equals(MethodInfo x, MethodInfo y)\n            {\n                if (!string.Equals(x.Name, y.Name, StringComparison.Ordinal))\n                {\n                    return false;\n                }\n\n                var xArgs = x.GetGenericArguments();\n                var yArgs = y.GetGenericArguments();\n                if (xArgs.Length != yArgs.Length)\n                {\n                    return false;\n                }\n\n                for (var i = 0; i < x.GetGenericArguments().Length; i++)\n                {\n                    if (xArgs[i] != yArgs[i])\n                    {\n                        return false;\n                    }\n                }\n\n                var xParams = x.GetParameters();\n                var yParams = y.GetParameters();\n                if (xParams.Length != yParams.Length)\n                {\n                    return false;\n                }\n\n                for (var i = 0; i < xParams.Length; i++)\n                {\n                    if (xParams[i].ParameterType != yParams[i].ParameterType)\n                    {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n\n            public int GetHashCode(MethodInfo obj)\n            {\n                int hashCode = -499943048;\n                hashCode = hashCode * -1521134295 + StringComparer.Ordinal.GetHashCode(obj.Name);\n\n                foreach (var arg in obj.GetGenericArguments())\n                {\n                    hashCode = hashCode * -1521134295 + arg.GetHashCode();\n                }\n\n                foreach (var parameter in obj.GetParameters())\n                {\n                    hashCode = hashCode * -1521134295 + parameter.ParameterType.GetHashCode();\n                }\n\n                return hashCode;\n            }\n\n            public int Compare(MethodInfo x, MethodInfo y)\n            {\n                var result = StringComparer.Ordinal.Compare(x.Name, y.Name);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                var xArgs = x.GetGenericArguments();\n                var yArgs = y.GetGenericArguments();\n                result = xArgs.Length.CompareTo(yArgs.Length);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                for (var i = 0; i < xArgs.Length; i++)\n                {\n                    var xh = xArgs[i].GetHashCode();\n                    var yh = yArgs[i].GetHashCode();\n                    result = xh.CompareTo(yh);\n                    if (result != 0)\n                    {\n                        return result;\n                    }\n                }\n\n                var xParams = x.GetParameters();\n                var yParams = y.GetParameters();\n                result = xParams.Length.CompareTo(yParams.Length);\n                if (result != 0)\n                {\n                    return result;\n                }\n\n                for (var i = 0; i < xParams.Length; i++)\n                {\n                    var xh = xParams[i].ParameterType.GetHashCode();\n                    var yh = yParams[i].ParameterType.GetHashCode();\n                    result = xh.CompareTo(yh);\n                    if (result != 0)\n                    {\n                        return result;\n                    }\n                }\n\n                return 0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/CodeGeneration/IGrainState.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Defines the state of a grain\n    /// </summary>\n    /// <typeparam name=\"T\">\n    /// The underlying state type.\n    /// </typeparam>\n    public interface IGrainState<T>\n    {\n        /// <summary>\n        /// Gets or sets the state.\n        /// </summary>\n        T State { get; set; }\n\n        /// <summary>Gets or sets the ETag that allows optimistic concurrency checks at the storage provider level.</summary>\n        string ETag { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the record exists in storage.\n        /// </summary>\n        bool RecordExists { get; set; }\n    }\n\n    /// <summary>\n    /// Default implementation of <see cref=\"IGrainState{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of application level payload.</typeparam>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GrainState<T> : IGrainState<T>\n    {\n        /// <inheritdoc />\n        [Id(0)]\n        public T State { get; set; }\n\n        /// <inheritdoc />\n        [Id(1)]\n        public string ETag { get; set; }\n\n        /// <inheritdoc />\n        [Id(2)]\n        public bool RecordExists { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainState{T}\"/> class. \n        /// </summary>\n        public GrainState()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainState{T}\"/> class. \n        /// </summary>\n        /// <param name=\"state\">\n        /// The initial value of the state.\n        /// </param>\n        public GrainState(T state) : this(state, null)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainState{T}\"/> class.\n        /// </summary>\n        /// <param name=\"state\">\n        /// The initial value of the state.\n        /// </param>\n        /// <param name=\"eTag\">\n        /// The initial e-tag value that allows optimistic concurrency checks at the storage provider level.\n        /// </param>\n        public GrainState(T state, string eTag)\n        {\n            State = state;\n            ETag = eTag;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/CollectionAgeLimitAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Specifies the period of inactivity before a grain is available for collection and deactivation.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public class CollectionAgeLimitAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        private TimeSpan? _value;\n\n        /// <summary>\n        /// Specifies the period of inactivity before a grain is available for collection and deactivation.\n        /// </summary>\n        /// <remarks>\n        /// Use the <see cref=\"Minutes\"/>, <see cref=\"Days\"/>, and <see cref=\"Hours\"/> properties or the <see cref=\"AlwaysActive\"/> to set the limit.\n        /// </remarks>\n        public CollectionAgeLimitAttribute() { }\n\n        /// <summary>\n        /// Specifies the period of inactivity before a grain is available for collection and deactivation.\n        /// </summary>\n        /// <param name=\"inactivityPeriod\">The period of inactivity before a grain is available for collection and deactivation, expressed as a string using <see cref=\"TimeSpan.Parse(string)\"/> syntax.</param>\n        public CollectionAgeLimitAttribute(string inactivityPeriod) => _value = TimeSpan.Parse(inactivityPeriod);\n\n        /// <summary>\n        /// Gets the minimum activation age.\n        /// </summary>\n        public static readonly TimeSpan MinAgeLimit = TimeSpan.FromMinutes(1);\n\n        /// <summary>\n        /// Gets or sets the number of days to delay collecting an idle activation for.\n        /// </summary>\n        public double Days { get; set; } \n\n        /// <summary>\n        /// Gets or sets the number of hours to delay collecting an idle activation for.\n        /// </summary>\n        public double Hours { get; set; } \n\n        /// <summary>\n        /// Gets or sets the number of minutes to delay collecting an idle activation for.\n        /// </summary>\n        public double Minutes { get; set; } \n\n        /// <summary>\n        /// Gets or sets a value indicating whether this grain should never be collected by the idle activation collector.\n        /// </summary>\n        public bool AlwaysActive { get; set; }\n\n        /// <summary>\n        /// Gets the idle activation collection age.\n        /// </summary>\n        public TimeSpan AgeLimit => _value ??= CalculateValue();\n\n        /// <inheritdoc />\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            string idleDeactivationPeriod;\n\n            if (AlwaysActive)\n            {\n                idleDeactivationPeriod = WellKnownGrainTypeProperties.IndefiniteIdleDeactivationPeriodValue;\n            }\n            else\n            {\n                idleDeactivationPeriod = AgeLimit.ToString(\"c\");\n            }\n\n            properties[WellKnownGrainTypeProperties.IdleDeactivationPeriod] = idleDeactivationPeriod;\n        }\n\n        private TimeSpan CalculateValue()\n        {\n            var span = AlwaysActive\n            ? TimeSpan.FromDays(short.MaxValue)\n            : TimeSpan.FromDays(Days) + TimeSpan.FromHours(Hours) + TimeSpan.FromMinutes(Minutes);\n            return span < MinAgeLimit\n                ? MinAgeLimit\n                : span;\n        }\n    }\n\n    /// <summary>\n    /// When applied to a grain implementation type this attribute specifies that activations of the grain shouldn't be collected by the idle activation collector.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public class KeepAliveAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        /// <inheritdoc />\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.IdleDeactivationPeriod] = WellKnownGrainTypeProperties.IndefiniteIdleDeactivationPeriodValue;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/ConfigUtilities.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Net;\nusing System.Net.NetworkInformation;\nusing System.Net.Sockets;\n\nnamespace Orleans.Runtime.Configuration\n{\n    /// <summary>\n    /// Utilities class for working with configuration.\n    /// </summary>\n    public static class ConfigUtilities\n    {\n        // Time spans are entered as a string of decimal digits, optionally followed by a unit string: \"ms\", \"s\", \"m\", \"hr\"\n        internal static TimeSpan ParseTimeSpan(string input, string errorMessage)\n        {\n            long unitSize;\n            string numberInput;\n            var trimmedInput = input.Trim().ToLowerInvariant();\n            if (trimmedInput.EndsWith(\"ms\", StringComparison.Ordinal))\n            {\n                unitSize = 10000;\n                numberInput = trimmedInput.Remove(trimmedInput.Length - 2).Trim();\n            }\n            else if (trimmedInput.EndsWith('s'))\n            {\n                unitSize = 1000 * 10000;\n                numberInput = trimmedInput.Remove(trimmedInput.Length - 1).Trim();\n            }\n            else if (trimmedInput.EndsWith('m'))\n            {\n                unitSize = 60 * 1000 * 10000;\n                numberInput = trimmedInput.Remove(trimmedInput.Length - 1).Trim();\n            }\n            else if (trimmedInput.EndsWith(\"hr\", StringComparison.Ordinal))\n            {\n                unitSize = 60 * 60 * 1000 * 10000L;\n                numberInput = trimmedInput.Remove(trimmedInput.Length - 2).Trim();\n            }\n            else\n            {\n                unitSize = 1000 * 10000; // Default is seconds\n                numberInput = trimmedInput;\n            }\n            decimal rawTimeSpan;\n            if (!decimal.TryParse(numberInput, NumberStyles.Any, CultureInfo.InvariantCulture, out rawTimeSpan))\n            {\n                throw new FormatException(errorMessage + \". Tried to parse \" + input);\n            }\n            return TimeSpan.FromTicks((long)(rawTimeSpan * unitSize));\n        }\n\n        internal static IPAddress ResolveIPAddressOrDefault(byte[] subnet, AddressFamily family)\n        {\n            IList<IPAddress> nodeIps = NetworkInterface.GetAllNetworkInterfaces()\n                            .Where(iface => iface.OperationalStatus == OperationalStatus.Up)\n                            .SelectMany(iface => iface.GetIPProperties().UnicastAddresses)\n                            .Select(addr => addr.Address)\n                            .Where(addr => addr.AddressFamily == family && !IPAddress.IsLoopback(addr))\n                            .ToList();\n\n            var ipAddress = PickIPAddress(nodeIps, subnet, family);\n            return ipAddress;\n        }\n\n        internal static IPAddress ResolveIPAddressOrDefault(string addrOrHost, byte[] subnet, AddressFamily family)\n        {\n            var loopback = family == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback;\n\n            // if the address is an empty string, just enumerate all ip addresses available\n            // on this node\n            if (string.IsNullOrEmpty(addrOrHost))\n            {\n                return ResolveIPAddressOrDefault(subnet, family);\n            }\n            else\n            {\n                // Fix StreamFilteringTests_SMS tests\n                if (addrOrHost.Equals(\"loopback\", StringComparison.OrdinalIgnoreCase))\n                {\n                    return loopback;\n                }\n\n                // check if addrOrHost is a valid IP address including loopback (127.0.0.0/8, ::1) and any (0.0.0.0/0, ::) addresses\n                if (IPAddress.TryParse(addrOrHost, out var address))\n                {\n                    return address;\n                }\n\n                // Get IP address from DNS. If addrOrHost is localhost will \n                // return loopback IPv4 address (or IPv4 and IPv6 addresses if OS is supported IPv6)\n                var nodeIps = Dns.GetHostAddresses(addrOrHost);\n                return PickIPAddress(nodeIps, subnet, family);\n            }\n        }\n\n        private static IPAddress PickIPAddress(IList<IPAddress> nodeIps, byte[] subnet, AddressFamily family)\n        {\n            var candidates = new List<IPAddress>();\n            foreach (var nodeIp in nodeIps.Where(x => x.AddressFamily == family))\n            {\n                // If the subnet does not match - we can't resolve this address.\n                // If subnet is not specified - pick smallest address deterministically.\n                if (subnet == null)\n                {\n                    candidates.Add(nodeIp);\n                }\n                else\n                {\n                    var ip = nodeIp;\n                    if (subnet.Select((b, i) => ip.GetAddressBytes()[i] == b).All(x => x))\n                    {\n                        candidates.Add(nodeIp);\n                    }\n                }\n            }\n\n            return candidates.Count > 0 ? PickIPAddress(candidates) : null;\n        }\n\n        private static IPAddress PickIPAddress(IReadOnlyList<IPAddress> candidates)\n        {\n            IPAddress chosen = null;\n            foreach (IPAddress addr in candidates)\n            {\n                if (chosen == null)\n                {\n                    chosen = addr;\n                }\n                else\n                {\n                    if (CompareIPAddresses(addr, chosen)) // pick smallest address deterministically\n                        chosen = addr;\n                }\n            }\n            return chosen;\n\n            // returns true if lhs is \"less\" (in some repeatable sense) than rhs\n            static bool CompareIPAddresses(IPAddress lhs, IPAddress rhs)\n            {\n                byte[] lbytes = lhs.GetAddressBytes();\n                byte[] rbytes = rhs.GetAddressBytes();\n\n                if (lbytes.Length != rbytes.Length) return lbytes.Length < rbytes.Length;\n\n                // compare starting from most significant octet.\n                // 10.68.20.21 < 10.98.05.04\n                for (int i = 0; i < lbytes.Length; i++)\n                {\n                    if (lbytes[i] != rbytes[i])\n                    {\n                        return lbytes[i] < rbytes[i];\n                    }\n                }\n                // They're equal\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Gets the address of the local server.\n        /// If there are multiple addresses in the correct family in the server's DNS record, the first will be returned.\n        /// </summary>\n        /// <returns>The server's IPv4 address.</returns>\n        internal static IPAddress GetLocalIPAddress(AddressFamily family = AddressFamily.InterNetwork, string interfaceName = null)\n        {\n            var loopback = (family == AddressFamily.InterNetwork) ? IPAddress.Loopback : IPAddress.IPv6Loopback;\n            // get list of all network interfaces\n            NetworkInterface[] netInterfaces = NetworkInterface.GetAllNetworkInterfaces();\n\n            var candidates = new List<IPAddress>();\n            // loop through interfaces\n            for (int i = 0; i < netInterfaces.Length; i++)\n            {\n                NetworkInterface netInterface = netInterfaces[i];\n\n                if (netInterface.OperationalStatus != OperationalStatus.Up)\n                {\n                    // Skip network interfaces that are not operational\n                    continue;\n                }\n                if (!string.IsNullOrWhiteSpace(interfaceName) &&\n                    !netInterface.Name.StartsWith(interfaceName, StringComparison.Ordinal)) continue;\n\n                bool isLoopbackInterface = (netInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback);\n                // get list of all unicast IPs from current interface\n                UnicastIPAddressInformationCollection ipAddresses = netInterface.GetIPProperties().UnicastAddresses;\n\n                // loop through IP address collection\n                foreach (UnicastIPAddressInformation ip in ipAddresses)\n                {\n                    if (ip.Address.AddressFamily == family) // Picking the first address of the requested family for now. Will need to revisit later\n                    {\n                        //don't pick loopback address, unless we were asked for a loopback interface\n                        if (!(isLoopbackInterface && ip.Address.Equals(loopback)))\n                        {\n                            candidates.Add(ip.Address); // collect all candidates.\n                        }\n                    }\n                }\n            }\n            return ResolveLocalIPAddress(candidates, family, interfaceName);\n        }\n\n        internal static IPAddress ResolveLocalIPAddress(IReadOnlyList<IPAddress> candidates, AddressFamily family, string interfaceName)\n        {\n            if (candidates.Count > 0)\n            {\n                return PickIPAddress(candidates);\n            }\n\n            if (string.IsNullOrWhiteSpace(interfaceName))\n            {\n                return family switch\n                {\n                    AddressFamily.InterNetwork => IPAddress.Loopback,\n                    AddressFamily.InterNetworkV6 => IPAddress.IPv6Loopback,\n                    _ => throw new OrleansException(\"Failed to get a local IP address.\"),\n                };\n            }\n\n            throw new OrleansException(\"Failed to get a local IP address.\");\n        }\n\n        /// <summary>\n        /// Prints the DataConnectionString,\n        /// without disclosing any credential info\n        /// such as the Azure Storage AccountKey, SqlServer password or AWS SecretKey.\n        /// </summary>\n        /// <param name=\"connectionString\">The connection string to print.</param>\n        /// <returns>The string representation of the DataConnectionString with account credential info redacted.</returns>\n        public static string RedactConnectionStringInfo(string connectionString)\n        {\n            string[] secretKeys =\n            {\n                \"AccountKey=\",                              // Azure Storage\n                \"SharedAccessSignature=\",                   // Many Azure services\n                \"SharedAccessKey=\", \"SharedSecretValue=\",   // ServiceBus\n                \"Password=\",                                // SQL\n                \"SecretKey=\", \"SessionToken=\",              // DynamoDb\n            };\n            var mark = \"<--SNIP-->\";\n            if (string.IsNullOrEmpty(connectionString)) return \"null\";\n            //if connection string format doesn't contain any secretKey, then return just <--SNIP-->\n            if (!Array.Exists(secretKeys, key => connectionString.Contains(key))) return mark;\n\n            string connectionInfo = connectionString;\n\n            // Remove any secret keys from connection string info written to log files\n            foreach (var secretKey in secretKeys)\n            {\n                int keyPos = connectionInfo.IndexOf(secretKey, StringComparison.OrdinalIgnoreCase);\n                if (keyPos >= 0)\n                {\n                    connectionInfo = connectionInfo.Remove(keyPos + secretKey.Length) + mark;\n                }\n            }\n\n            return connectionInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/GrainTypeOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Configuration;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Contains grain type descriptions.\n    /// </summary>\n    public class GrainTypeOptions\n    {\n        /// <summary>\n        /// Gets a collection of metadata about grain classes.\n        /// </summary>\n        public HashSet<Type> Classes { get; } = new ();\n\n        /// <summary>\n        /// Gets a collection of metadata about grain interfaces.\n        /// </summary>\n        public HashSet<Type> Interfaces { get; } = new ();\n    }\n\n    /// <summary>\n    /// The default configuration provider for <see cref=\"GrainTypeOptions\"/>.\n    /// </summary>\n    internal sealed class DefaultGrainTypeOptionsProvider : IConfigureOptions<GrainTypeOptions>\n    {\n        private readonly TypeManifestOptions _typeManifestOptions;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultGrainTypeOptionsProvider\"/> class.\n        /// </summary>\n        /// <param name=\"typeManifestOptions\">The type manifest options.</param>\n        public DefaultGrainTypeOptionsProvider(IOptions<TypeManifestOptions> typeManifestOptions) => _typeManifestOptions = typeManifestOptions.Value;\n\n        /// <inheritdoc />\n        public void Configure(GrainTypeOptions options)\n        {\n            foreach (var type in _typeManifestOptions.Interfaces)\n            {\n                if (typeof(IAddressable).IsAssignableFrom(type))\n                {\n                    options.Interfaces.Add(type);\n                }\n            }\n\n            foreach (var type in _typeManifestOptions.InterfaceImplementations)\n            {\n                if (IsImplementationType(type))\n                {\n                    options.Classes.Add(type switch\n                    {\n                        { IsGenericType: true, IsConstructedGenericType: false } => type.GetGenericTypeDefinition(),\n                        _ => type\n                    });\n                }\n            }\n\n            static bool IsImplementationType(Type type)\n            {\n                if (type.IsAbstract || type.IsInterface)\n                {\n                    return false;\n                }\n\n                if (typeof(IGrain).IsAssignableFrom(type))\n                {\n                    return true;\n                }\n\n                return false;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Validates <see cref=\"GrainTypeOptions\"/>.\n    /// </summary>\n    public sealed class GrainTypeOptionsValidator : IConfigurationValidator\n    {\n        private readonly IOptions<GrainTypeOptions> _options;\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainTypeOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        public GrainTypeOptionsValidator(IOptions<GrainTypeOptions> options, IServiceProvider serviceProvider)\n        {\n            _options = options;\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (_options.Value.Interfaces is not { Count: > 0 })\n            {\n                throw new OrleansConfigurationException($\"No grain interfaces have been configured. Either add some grain interfaces and reference the Orleans.Sdk package, or remove {nameof(GrainTypeOptionsValidator)} from the services collection.\");\n            }\n\n            var isSilo = _serviceProvider.GetService(typeof(ILocalSiloDetails)) != null;\n            if (isSilo)\n            {\n                if (_options.Value.Classes is not { Count: > 0 })\n                {\n                    throw new OrleansConfigurationException($\"No grain classes have been configured. Either add some grain classes and reference the Orleans.Sdk package, or remove {nameof(GrainTypeOptionsValidator)} from the services collection.\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/NamedServiceConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Functionality for configuring a named service.\n    /// </summary>\n    public interface INamedServiceConfigurator\n    {\n        /// <summary>\n        /// Gets the service name.\n        /// </summary>\n        string Name { get; }\n\n        /// <summary>\n        /// Gets the delegate used to configure the service.\n        /// </summary>\n        Action<Action<IServiceCollection>> ConfigureDelegate { get; }\n    }\n\n    /// <summary>\n    /// Component configurator base class for names services\n    /// This associates any configurations or subcomponents with the same name as the service being configured\n    /// </summary>\n    public class NamedServiceConfigurator : INamedServiceConfigurator\n    {\n        /// <inheritdoc />\n        public string Name { get; }\n\n        /// <inheritdoc />\n        public Action<Action<IServiceCollection>> ConfigureDelegate { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NamedServiceConfigurator\"/> class.\n        /// </summary>\n        /// <param name=\"name\">\n        /// The name.\n        /// </param>\n        /// <param name=\"configureDelegate\">\n        /// The configuration delegate.\n        /// </param>\n        public NamedServiceConfigurator(string name, Action<Action<IServiceCollection>> configureDelegate)\n        {\n            this.Name = name;\n            this.ConfigureDelegate = configureDelegate;\n        }\n    }\n\n    /// <summary>\n    /// Extensions for working with <see cref=\"INamedServiceConfigurator\"/>.\n    /// </summary>\n    public static class NamedServiceConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures options for a named service.\n        /// </summary>\n        /// <param name=\"configurator\">\n        /// The named service configurator.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The options configuration delegate.\n        /// </param>\n        /// <typeparam name=\"TOptions\">\n        /// The underlying options type.\n        /// </typeparam>\n        public static void Configure<TOptions>(this INamedServiceConfigurator configurator, Action<OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new()\n        {\n            configurator.ConfigureDelegate(services =>\n            {\n                configureOptions?.Invoke(services.AddOptions<TOptions>(configurator.Name));\n                services.ConfigureNamedOptionForLogging<TOptions>(configurator.Name);\n            });\n        }\n\n        /// <summary>\n        /// Adds a singleton component to a named service and configures options for the named service.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type being configured.</typeparam>\n        /// <typeparam name=\"TComponent\">The component service type being registered.</typeparam>\n        /// <param name=\"configurator\">The named configurator which the component and options will be configured for.</param>\n        /// <param name=\"factory\">The factory used to create the component for the named service.</param>\n        /// <param name=\"configureOptions\">The delegate used to configure options for the named service.</param>\n        public static void ConfigureComponent<TOptions, TComponent>(this INamedServiceConfigurator configurator, Func<IServiceProvider, string, TComponent> factory, Action<OptionsBuilder<TOptions>> configureOptions = null)\n            where TOptions : class, new()\n            where TComponent : class\n        {\n            configurator.Configure(configureOptions);\n            configurator.ConfigureComponent(factory);\n        }\n\n        /// <summary>\n        /// Adds a singleton component to a named service.\n        /// </summary>\n        /// <typeparam name=\"TComponent\">The component service type.</typeparam>\n        /// <param name=\"configurator\">The named configurator which the component will be configured for.</param>\n        /// <param name=\"factory\">The factory used to create the component for the named service.</param>\n        public static void ConfigureComponent<TComponent>(this INamedServiceConfigurator configurator, Func<IServiceProvider, string, TComponent> factory)\n           where TComponent : class\n        {\n            configurator.ConfigureDelegate(services =>\n            {\n                services.AddKeyedSingleton<TComponent>(configurator.Name, (sp, key) => factory(sp, key as string));\n            });\n        }\n\n        public static void ConfigureLifecycle<T>(this INamedServiceConfigurator configurator) where T : ILifecycleSubject\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionLogger/DefaultOptionsFormatter.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Default implementation of <see cref=\"IOptionFormatter{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The options type.</typeparam>\n    internal sealed class DefaultOptionsFormatter<T> : IOptionFormatter<T> where T : class\n    {\n        private readonly T _options;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultOptionsFormatter{T}\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        public DefaultOptionsFormatter(IOptions<T> options)\n        {\n            _options = options.Value;\n            Name = OptionFormattingUtilities.Name<T>();\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultOptionsFormatter{T}\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The options name.</param>\n        /// <param name=\"options\">The options.</param>\n        internal DefaultOptionsFormatter(string name, T options)\n        {\n            _options = options;\n            Name = OptionFormattingUtilities.Name<T>(name);\n        }\n\n        /// <summary>\n        /// Gets the options name.\n        /// </summary>\n        public string Name { get; }\n\n        /// <summary>\n        /// For\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerable<string> Format()\n        {\n            foreach (var prop in typeof(T).GetProperties())\n            {\n                if (!IsFormattableProperty(prop))\n                {\n                    continue;\n                }\n\n                foreach (var formattedValue in FormatProperty(_options, prop))\n                {\n                    yield return formattedValue;\n                }\n            }\n        }\n\n        private static bool IsFormattableProperty(PropertyInfo prop)\n        {\n            if (prop is null) return false;\n            if (!IsFormattableType(prop.PropertyType)) return false;\n            if (prop.GetCustomAttribute<ObsoleteAttribute>() is not null) return false;\n            if (!IsAccessibleMethod(prop.GetSetMethod())) return false;\n            if (!IsAccessibleMethod(prop.GetGetMethod())) return false;\n            return true;\n        }\n\n        private static bool IsAccessibleMethod(MethodInfo accessor)\n        {\n            if (accessor is null) return false;\n            if (!accessor.IsPublic) return false;\n            if (accessor.GetCustomAttribute<ObsoleteAttribute>() is not null) return false;\n            return true;\n        }\n\n        private static bool IsFormattableType(Type type)\n        {\n            if (type is null) return false;\n            if (typeof(Delegate).IsAssignableFrom(type)) return false;\n            return true;\n        }\n\n        private static IEnumerable<string> FormatProperty(object options, PropertyInfo property)\n        {\n            var name = property.Name;\n            var value = property.GetValue(options);\n            var redactAttribute = property.GetCustomAttribute<RedactAttribute>(inherit: true);\n\n            // If redact specified, let the attribute implementation do the work\n            if (redactAttribute != null)\n            {\n                yield return OptionFormattingUtilities.Format(name, redactAttribute.Redact(value));\n            }\n            else\n            {\n                if (value is IDictionary dict)\n                {\n                    // If it is a dictionary -> one line per item\n                    var enumerator = dict.GetEnumerator();\n                    while (enumerator.MoveNext())\n                    {\n                        var kvp = enumerator.Entry;\n                        yield return $\"{name}.{kvp.Key}: {kvp.Value}\";\n                    }\n                }\n                else if (value is ICollection coll)\n                {\n                    // If it is a simple collection -> one line per item\n                    if (coll.Count > 0)\n                    {\n                        var index = 0;\n                        foreach (var item in coll)\n                        {\n                            yield return $\"{name}.{index}: {item}\";\n                            index++;\n                        }\n                    }\n                }\n                else\n                {\n                    // Simple case\n                    yield return OptionFormattingUtilities.Format(name, value);\n                }\n            }\n        }\n    }\n\n    internal class DefaultOptionsFormatterResolver<T> : IOptionFormatterResolver<T> where T: class\n    {\n        private readonly IOptionsMonitor<T> _optionsMonitor;\n\n        public DefaultOptionsFormatterResolver(IOptionsMonitor<T> optionsMonitor)\n        {\n            _optionsMonitor = optionsMonitor;\n        }\n\n        public IOptionFormatter<T> Resolve(string name) => new DefaultOptionsFormatter<T>(name, _optionsMonitor.Get(name));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionLogger/IOptionFormatter.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// format the option and give it a category and a name\n    /// </summary>\n    public interface IOptionFormatter\n    {\n        /// <summary>\n        /// Gets the name of the options object.\n        /// </summary>\n        string Name { get; }\n\n        /// <summary>\n        /// Formats the options object into a collection of strings.\n        /// </summary>\n        /// <returns>A collection of formatted string-value pairs corresponding the the properties on the options object.</returns>\n        IEnumerable<string> Format();\n    }\n\n    /// <summary>\n    /// Option formatter for a certain option type <typeparamref name=\"T\"/>\n    /// </summary>\n    /// <typeparam name=\"T\">The options type.</typeparam>\n    public interface IOptionFormatter<T> : IOptionFormatter\n    {\n    }\n\n    /// <summary>\n    /// IOptionFormatterResolver resolve specific OptionFormatter for certain named option\n    /// </summary>\n    /// <typeparam name=\"T\">The options type.</typeparam>\n    public interface IOptionFormatterResolver<T>\n    {\n        /// <summary>\n        /// Resolves the options formatter for the specified options type with the specified options name.\n        /// </summary>\n        /// <param name=\"name\">The options name.</param>\n        /// <returns>The options type.</returns>\n        IOptionFormatter<T> Resolve(string name);\n    }\n\n    /// <summary>\n    /// Utility class for option formatting\n    /// </summary>\n    public static class OptionFormattingUtilities\n    {\n        /// <summary>\n        /// The default format string.\n        /// </summary>\n        private const string DefaultFormatFormatting = \"{0}: {1}\";\n\n        /// <summary>\n        /// The default format string for options types which are named.\n        /// </summary>\n        private const string DefaultNamedFormatting = \"{0}-{1}\";\n\n        /// <summary>\n        /// Formats a key-value pair using default format\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"value\">\n        /// The value.\n        /// </param>\n        /// <param name=\"formatting\">\n        /// The format string.\n        /// </param>\n        /// <returns>A formatted key-value pair.</returns>\n        public static string Format(object key, object value, string formatting = null)\n        {\n            var valueFormat = formatting ?? DefaultFormatFormatting;\n            return string.Format(valueFormat, key, value);\n        }\n\n        /// <summary>\n        /// Formats the name of an options object.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type.</typeparam>\n        /// <param name=\"name\">The options name.</param>\n        /// <param name=\"formatting\">The format string.</param>\n        /// <returns>The formatted options object name.</returns>\n        public static string Name<TOptions>(string name = null, string formatting = null)\n        {\n            return name is null && formatting is null ? typeof(TOptions).FullName\n                : string.Format(formatting ?? DefaultNamedFormatting, typeof(TOptions).FullName, name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionLogger/IOptionsLogger.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Logger for options on the client.\n    /// </summary>\n    internal class ClientOptionsLogger : OptionsLogger, ILifecycleParticipant<IClusterClientLifecycle>\n    {\n        /// <summary>\n        /// Logs options as soon as possible.\n        /// </summary>\n        private const int ClientOptionLoggerLifeCycleRing = int.MinValue;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientOptionsLogger\"/> class.\n        /// </summary>\n        /// <param name=\"logger\">\n        /// The logger.\n        /// </param>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        public ClientOptionsLogger(ILogger<ClientOptionsLogger> logger, IServiceProvider services)\n            : base(logger, services)\n        {\n        }\n\n        /// <inheritdoc />\n        public void Participate(IClusterClientLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<ClientOptionsLogger>(ClientOptionLoggerLifeCycleRing, this.OnStart);\n        }\n\n        /// <inheritdoc />\n        public Task OnStart(CancellationToken token)\n        {\n            this.LogOptions();\n            return Task.CompletedTask;\n        }\n    }\n\n    /// <summary>\n    /// Base class for client and silo default options loggers.\n    /// </summary>\n    public abstract partial class OptionsLogger\n    {\n        private readonly ILogger logger;\n        private readonly IServiceProvider services;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OptionsLogger\"/> class.\n        /// </summary>\n        /// <param name=\"logger\">\n        /// The logger.\n        /// </param>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        protected OptionsLogger(ILogger logger, IServiceProvider services)\n        {\n            this.logger = logger;\n            this.services = services;\n        }\n\n        /// <summary>\n        /// Log all options with registered formatters\n        /// </summary>\n        public void LogOptions()\n        {\n            this.LogOptions(services.GetServices<IOptionFormatter>());\n        }\n\n        /// <summary>\n        /// Log options using a set of formatters.\n        /// </summary>\n        /// <param name=\"formatters\">The collection of options formatters.</param>\n        public void LogOptions(IEnumerable<IOptionFormatter> formatters)\n        {\n            foreach (var optionFormatter in formatters.OrderBy(f => f.Name))\n            {\n                this.LogOption(optionFormatter);\n            }\n        }\n\n        /// <summary>\n        /// Log an options using a formatter.\n        /// </summary>\n        /// <param name=\"formatter\">The options formatter.</param>\n        public void LogOption(IOptionFormatter formatter)\n        {\n            try\n            {\n                var stringBuilder = new StringBuilder();\n                foreach (var setting in formatter.Format())\n                {\n                    stringBuilder.AppendLine($\"{setting}\");\n                }\n                LogInformationOptions(logger, formatter.Name, stringBuilder.ToString());\n            }\n            catch(Exception ex)\n            {\n                LogErrorOptions(logger, ex, formatter.Name);\n                throw;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Configuration {Name}:\\n{Options}\"\n        )]\n        private static partial void LogInformationOptions(ILogger logger, string name, string options);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"An error occurred while logging '{Name}' options.\"\n        )]\n        private static partial void LogErrorOptions(ILogger logger, Exception exception, string name);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionLogger/OptionFormatterExtensionMethods.cs",
    "content": "using System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration.Internal;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Extension methods on <see cref=\"IServiceCollection\"/>, to provider better usability to IOptionFormatter.\n    /// </summary>\n    public static class OptionConfigureExtensionMethods\n    {\n        /// <summary>\n        /// Configures an options formatter for <typeparamref name=\"TOptions\"/>.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        /// <typeparam name=\"TOptions\">\n        /// The options type.\n        /// </typeparam>\n        /// <typeparam name=\"TOptionFormatter\">\n        /// The option formatter type.\n        /// </typeparam>\n        /// <returns>\n        /// The <see cref=\"IServiceCollection\"/>, for chaining with other calls.\n        /// </returns>\n        public static IServiceCollection ConfigureFormatter<TOptions, TOptionFormatter>(this IServiceCollection services)\n            where TOptions : class\n            where TOptionFormatter : class, IOptionFormatter<TOptions>\n        {\n            if (services.All(service => service.ServiceType != typeof(IOptionFormatter<TOptions>)))\n            {\n                services\n                    .AddSingleton<IOptionFormatter<TOptions>, TOptionFormatter>()\n                    .AddFromExisting<IOptionFormatter, IOptionFormatter<TOptions>>();\n            }\n            else\n            {\n                // override IOptionFormatter<TOptions>\n                services.AddSingleton<IOptionFormatter<TOptions>, TOptionFormatter>();\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Configures an options formatter for <typeparamref name=\"TOptions\"/>.\n        /// </summary>\n        /// <remarks>\n        /// This will use the default options formatter unless a non-default formatter is configured.\n        /// </remarks>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        /// <typeparam name=\"TOptions\">\n        /// The options type.\n        /// </typeparam>\n        /// <returns>\n        /// The <see cref=\"IServiceCollection\"/>, for chaining with other calls.\n        /// </returns>\n        public static IServiceCollection ConfigureFormatter<TOptions>(this IServiceCollection services)\n            where TOptions : class, new()\n        {\n            return services.AddSingleton<IOptionFormatter>(sp => sp.GetService<IOptionFormatter<TOptions>>());\n        }\n\n        /// <summary>\n        /// Configures an options formatter for <typeparamref name=\"TOptions\"/> if none are already configured.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        /// <typeparam name=\"TOptions\">\n        /// The options type.\n        /// </typeparam>\n        /// <typeparam name=\"TOptionFormatter\">\n        /// The option formatter type.\n        /// </typeparam>\n        /// <returns>\n        /// The <see cref=\"IServiceCollection\"/>, for chaining with other calls.\n        /// </returns>\n        public static IServiceCollection TryConfigureFormatter<TOptions, TOptionFormatter>(this IServiceCollection services)\n            where TOptions : class\n            where TOptionFormatter : class, IOptionFormatter<TOptions>\n        {\n            if (services.All(service => service.ServiceType != typeof(IOptionFormatter<TOptions>)))\n            {\n                services.ConfigureFormatter<TOptions, TOptionFormatter>();\n            }\n\n            return services;\n        }\n\n        /// <summary>\n        /// Configures an options formatter resolver for <typeparamref name=\"TOptions\"/>.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        /// <typeparam name=\"TOptions\">\n        /// The options type.\n        /// </typeparam>\n        /// <typeparam name=\"TOptionFormatterResolver\">\n        /// The option formatter resolver type.\n        /// </typeparam>\n        /// <returns>\n        /// The <see cref=\"IServiceCollection\"/>, for chaining with other calls.\n        /// </returns>\n        public static IServiceCollection ConfigureFormatterResolver<TOptions, TOptionFormatterResolver>(this IServiceCollection services)\n            where TOptions : class\n            where TOptionFormatterResolver : class, IOptionFormatterResolver<TOptions>\n        {\n            return services.AddSingleton<IOptionFormatterResolver<TOptions>, TOptionFormatterResolver>();\n        }\n\n        /// <summary>\n        /// Configure option formatter resolver for named option TOptions, if none is configured\n        /// </summary>\n        public static IServiceCollection TryConfigureFormatterResolver<TOptions, TOptionFormatterResolver>(this IServiceCollection services)\n            where TOptions : class\n            where TOptionFormatterResolver : class, IOptionFormatterResolver<TOptions>\n        {\n            if (services.All(service => service.ServiceType != typeof(IOptionFormatterResolver<TOptions>)))\n            {\n                return services.ConfigureFormatterResolver<TOptions, TOptionFormatterResolver>();\n            }\n\n            return services;\n        }\n\n        /// <summary>\n        /// Configures a named option to be logged.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">\n        /// The option object's type.\n        /// </typeparam>\n        /// <param name=\"services\">\n        /// The services.\n        /// </param>\n        /// <param name=\"name\">\n        /// The option object's name.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IServiceCollection\"/>, for chaining with other calls.\n        /// </returns>\n        public static IServiceCollection ConfigureNamedOptionForLogging<TOptions>(this IServiceCollection services, string name)\n            where TOptions : class\n        {\n            return services.AddSingleton<IOptionFormatter>(sp => sp.GetService<IOptionFormatterResolver<TOptions>>().Resolve(name));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionLogger/RedactMemberAttribute.cs",
    "content": "using Orleans.Runtime.Configuration;\nusing System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// When applied to a property on an options class, this attribute prevents the property value from being formatted by conforming <see cref=\"IOptionFormatter\"/> instances.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]\n    public class RedactAttribute : Attribute\n    {\n        /// <summary>\n        /// Redacts the provided value.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The redacted value.</returns>\n        public virtual string Redact(object value)\n        {\n            return \"REDACTED\";\n        }\n    }\n\n    /// <summary>\n    /// When applied to a connection string property on an options class, this attribute prevents the property value from being formatted by conforming <see cref=\"IOptionFormatter\"/> instances.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]\n    public class RedactConnectionStringAttribute : RedactAttribute\n    {\n        /// <summary>\n        /// Redacts the provided value.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The redacted value.</returns>\n        public override string Redact(object value)\n        {\n            return ConfigUtilities.RedactConnectionStringInfo(value as string);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/ClientMessagingOptions.cs",
    "content": "using System.Net;\nusing System.Net.Sockets;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Specifies global messaging options that are client related.\n    /// </summary>\n    public class ClientMessagingOptions : MessagingOptions\n    {\n        /// <summary>\n        ///  Gets or sets the total number of grain buckets used by the client in client-to-gateway communication\n        ///  protocol. In this protocol, grains are mapped to buckets and buckets are mapped to gateway connections, in order to enable stickiness\n        ///  of grain to gateway (messages to the same grain go to the same gateway, while evenly spreading grains across gateways).\n        ///  This number should be about 10 to 100 times larger than the expected number of gateway connections.\n        ///  If this attribute is not specified, then Math.Pow(2, 13) is used.\n        /// </summary>\n        public int ClientSenderBuckets { get; set; } = DEFAULT_CLIENT_SENDER_BUCKETS;\n\n        /// <summary>\n        /// The default value for <see cref=\"ClientSenderBuckets\"/>.\n        /// </summary>\n        /// <value>8192</value>\n        public const int DEFAULT_CLIENT_SENDER_BUCKETS = 8192;\n\n        /// <summary>\n        /// Gets or sets the preferred <see cref=\"AddressFamily\"/> to be used when determining an appropriate client identity.\n        /// </summary>\n        public AddressFamily PreferredFamily { get; set; } = DEFAULT_PREFERRED_FAMILY;\n\n        /// <summary>\n        /// The default value for <see cref=\"PreferredFamily\"/>.\n        /// </summary>\n        /// <value><see cref=\"AddressFamily.InterNetwork\"/></value>\n        public const AddressFamily DEFAULT_PREFERRED_FAMILY = AddressFamily.InterNetwork;\n\n        /// <summary>\n        /// Gets or sets the name of the network interface to use to work out an IP address for this machine.\n        /// </summary>\n        public string NetworkInterfaceName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the IP address used for cluster client.\n        /// </summary>\n        public IPAddress LocalAddress { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/ClusterMembershipOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Settings for cluster membership.\n    /// </summary>\n    public class ClusterMembershipOptions\n    {\n        /// <summary>\n        /// Gets or sets the number of missed \"I am alive\" updates in the table from a silo that causes warning to be logged.\n        /// </summary>\n        /// <seealso cref=\"IAmAliveTablePublishTimeout\"/>\n        public int NumMissedTableIAmAliveLimit { get; set; } = 3;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to disable silo liveness protocol (should be used only for testing).\n        /// If a silo is suspected to be down, but this attribute is set to <see langword=\"false\"/>, the suspicions will not propagated to the system and enforced.\n        /// This parameter is intended for use only for testing and troubleshooting.\n        /// In production, liveness should always be enabled.\n        /// </summary>\n        /// <value>Liveness is enabled by default.</value>\n        public bool LivenessEnabled { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets both the period between sending a liveness probe to any given host as well as the timeout for each probe.\n        /// </summary>\n        /// <value>Probes timeout and a new probe is sent every 5 seconds by default.</value>\n        public TimeSpan ProbeTimeout { get; set; } = TimeSpan.FromSeconds(5);\n\n        /// <summary>\n        /// Gets or sets the period between fetching updates from the membership table.\n        /// </summary>\n        /// <value>The membership table is refreshed every 60 seconds by default.</value>\n        public TimeSpan TableRefreshTimeout { get; set; } = TimeSpan.FromSeconds(60);\n\n        /// <summary>\n        /// Gets or sets the expiration time in seconds for votes in the membership table.\n        /// </summary>\n        /// <value>Votes expire after 2 minutes by default.</value>\n        public TimeSpan DeathVoteExpirationTimeout { get; set; } = TimeSpan.FromMinutes(2);\n\n        /// <summary>\n        /// Gets or sets the period between updating this silo's heartbeat in the membership table.\n        /// </summary>\n        /// <remarks>\n        /// These heartbeats are largely for diagnostic purposes, however they are also used to ignore entries\n        /// in the membership table in the event of a total cluster reset. This value multiplied by <see cref=\"NumMissedTableIAmAliveLimit\"/>\n        /// is used to skip hosts in the membership table when performing an initial connectivity check upon startup.\n        /// </remarks>\n        /// <value>Publish an update every 5 minutes by default.</value>\n        public TimeSpan IAmAliveTablePublishTimeout { get; set; } = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Gets or sets the maximum amount of time to attempt to join a cluster before giving up.\n        /// </summary>\n        /// <value>Attempt to join for 5 minutes before giving up by default.</value>\n        public TimeSpan MaxJoinAttemptTime { get; set; } = TimeSpan.FromMinutes(5);\n\n        /// <summary>\n        /// Gets or sets a value indicating whether gossip membership updates between hosts.\n        /// </summary>\n        /// <value>Membership updates are disseminated using gossip by default.</value>\n        public bool UseLivenessGossip { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets the number of silos each silo probes for liveness.\n        /// </summary>\n        /// <remarks>\n        /// This determines how many hosts each host will monitor by default.\n        /// A low value, such as 3, is generally sufficient and allows for prompt removal of another silo in the event that it stops functioning.\n        /// Monitoring is not expensive, however, and a higher value improves recovery during sudden changes in cluster size.\n        /// When a silo becomes suspicious of another silo, additional silos may begin to probe that silo to speed up the detection of non-functioning silos.\n        /// </remarks>\n        /// <value>Each silo will actively monitor up to 10 other silos by default.</value>\n        public int NumProbedSilos { get; set; } = 10;\n\n        /// <summary>\n        /// Gets or sets the number of missed probe requests from a silo that lead to suspecting this silo as down.\n        /// </summary>\n        /// <value>A silo will be suspected as being down if three probes are missed, by default.</value>\n        public int NumMissedProbesLimit { get; set; } = 3;\n\n        /// <summary>\n        /// Gets or sets the number of non-expired votes that are needed to declare some silo as down (should be at most <see cref=\"NumProbedSilos\"/>)\n        /// </summary>\n        /// <value>Two votes are sufficient for a silo to be declared as down, by default.</value>\n        public int NumVotesForDeathDeclaration { get; set; } = 2;\n\n        /// <summary>\n        /// Gets or sets the period of time after which membership entries for defunct silos are eligible for removal.\n        /// Valid only if <see cref=\"DefunctSiloCleanupPeriod\"/> is not <see langword=\"null\" />.\n        /// </summary>\n        /// <value>Defunct silos are removed from membership after one week by default.</value>\n        public TimeSpan DefunctSiloExpiration { get; set; } = TimeSpan.FromDays(7);\n\n        /// <summary>\n        /// Gets or sets the duration between membership table cleanup operations. When this period elapses, all defunct silo\n        /// entries older than <see cref=\"DefunctSiloExpiration\" /> are removed. This value is per-silo.\n        /// </summary>\n        /// <value>Membership is cleared of expired, defunct silos every hour, by default.</value>\n        public TimeSpan? DefunctSiloCleanupPeriod { get; set; } = TimeSpan.FromHours(1);\n\n        /// <summary>\n        /// /// Gets the period after which a silo is ignored for initial connectivity validation if it has not updated its heartbeat in the silo membership table.\n        /// </summary>\n        internal TimeSpan AllowedIAmAliveMissPeriod => IAmAliveTablePublishTimeout.Multiply(NumMissedTableIAmAliveLimit);\n\n        /// <summary>\n        /// Gets the amount of time to wait for the cluster membership system to terminate during shutdown.\n        /// </summary>\n        internal static TimeSpan ClusteringShutdownGracePeriod => TimeSpan.FromSeconds(5);\n\n        /// <summary>\n        /// Gets or sets the period between self-tests to log local health degradation status.\n        /// </summary>\n        /// <value>The local host will perform a self-test every ten seconds by default.</value>\n        public TimeSpan LocalHealthDegradationMonitoringPeriod { get; set; } = TimeSpan.FromSeconds(10);\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to extend the effective <see cref=\"ProbeTimeout\"/> value based upon current local health degradation.\n        /// </summary>\n        public bool ExtendProbeTimeoutDuringDegradation { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable probing silos indirectly, via other silos.\n        /// </summary>\n        public bool EnableIndirectProbes { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable membership eviction of silos when in a state of `Joining` or `Created` for longer than MaxJoinAttemptTime\n        /// </summary>\n        public bool EvictWhenMaxJoinAttemptTimeExceeded { get; set; } = true;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/ClusterOptions.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configures the Orleans cluster.\n    /// </summary>\n    public class ClusterOptions\n    {\n        /// <summary>\n        /// The default value of <see cref=\"ClusterId\"/>.\n        /// </summary>\n        public const string DefaultClusterId = \"default\";\n\n        /// <summary>\n        /// The default value of <see cref=\"ServiceId\"/>.\n        /// </summary>\n        public const string DefaultServiceId = \"default\";\n\n        /// <summary>\n        /// Default cluster id for development clusters.\n        /// </summary>\n        internal const string DevelopmentClusterId = \"dev\";\n\n        /// <summary>\n        /// Default service id for development clusters.\n        /// </summary>\n        internal const string DevelopmentServiceId = \"dev\";\n\n        /// <summary>\n        /// Gets or sets the cluster identity. This used to be called DeploymentId before Orleans 2.0 name.\n        /// </summary>\n        public string ClusterId { get; set; } = DefaultClusterId;\n\n        /// <summary>\n        /// Gets or sets a unique identifier for this service, which should survive deployment and redeployment, where as <see cref=\"ClusterId\"/> might not.\n        /// </summary>\n        public string ServiceId { get; set; } = DefaultServiceId;\n    }\n\n    /// <summary>\n    /// Validator for <see cref=\"ClusterOptions\"/>\n    /// </summary>\n    public class ClusterOptionsValidator : IConfigurationValidator\n    {\n        private readonly ClusterOptions options;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">\n        /// The options.\n        /// </param>\n        public ClusterOptionsValidator(IOptions<ClusterOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.ClusterId))\n            {\n                throw new OrleansConfigurationException(\n                    $\"Configuration for {nameof(ClusterOptions)} is invalid. \" +\n                    $\"A non-empty value for {nameof(options.ClusterId)} is required. \" +\n                    $\"See {Constants.TroubleshootingHelpLink} for more information.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ServiceId))\n            {\n                throw new OrleansConfigurationException(\n                    $\"Configuration for {nameof(ClusterOptions)} is invalid. \" +\n                    $\"A non-empty value for {nameof(options.ServiceId)} is required. \" +\n                    $\"See {Constants.TroubleshootingHelpLink} for more information.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/GatewayOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring how clients interact with gateway endpoints.\n    /// </summary>\n    public class GatewayOptions\n    {\n        /// <summary>\n        /// Gets or sets the period of time between refreshing the list of active gateways.\n        /// </summary>\n        /// <value>The list of active gateways will be refreshed every minute by default.</value>\n        public TimeSpan GatewayListRefreshPeriod { get; set; } = TimeSpan.FromMinutes(1);\n\n        /// <summary>\n        /// Default preferred gateway index,. Value -1 means prefer no gateway\n        /// </summary>\n        public const int DEFAULT_PREFERED_GATEWAY_INDEX = -1;\n\n        /// <summary>\n        /// Gets or sets the index of the preferred gateway within the list of active gateways.\n        /// </summary>\n        /// <remarks>Set this value to its default value, <c>-1</c>, to disable this functionality.</remarks>\n        /// <value>No gateway is preferred by default.</value>\n        public int PreferredGatewayIndex { get; set; } = DEFAULT_PREFERED_GATEWAY_INDEX;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/GrainVersioningOptions.cs",
    "content": "\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Versioning options govern grain implementation selection in heterogeneous deployments.\n    /// </summary>\n    public class GrainVersioningOptions\n    {\n        /// <summary>\n        /// Gets or sets the name of the default strategy used to determine grain compatibility in heterogeneous deployments.\n        /// </summary>\n        /// <value>The <see cref=\"BackwardCompatible\"/> strategy is used by default.</value>\n        public string DefaultCompatibilityStrategy { get; set; } = nameof(BackwardCompatible);\n\n        /// <summary>\n        /// Gets or sets the name of the default strategy for selecting grain versions in heterogeneous deployments.\n        /// </summary>\n        /// <value>The <see cref=\"AllCompatibleVersions\"/> strategy is used by default.</value>\n        public string DefaultVersionSelectorStrategy { get; set; } = nameof(AllCompatibleVersions);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/LoadSheddingOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options relating to load shedding.\n    /// </summary>\n    public class LoadSheddingOptions\n    {\n        /// <summary>\n        /// The default value for <see cref=\"LoadSheddingLimit\"/>.\n        /// </summary>\n        internal const int DefaultCpuThreshold = 95;\n\n        /// <summary>\n        /// The default value for <see cref=\"MemoryThreshold\"/>.\n        /// </summary>\n        internal const int DefaultMemoryThreshold = 90;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether load shedding in the client gateway and stream providers is enabled.\n        /// The default value is <see langword=\"false\"/>, meaning that load shedding is disabled.\n        /// </summary>\n        /// <value>Load shedding is disabled by default.</value>\n        public bool LoadSheddingEnabled { get; set; }\n\n        /// <summary>\n        /// Gets or sets the CPU utilization, expressed as a value between <c>0</c> and <c>100</c>, at which load shedding begins.\n        /// Note that this value is in %, so valid values range from 1 to 100, and a reasonable value is typically between 80 and 95.\n        /// This value is ignored if load shedding is disabled, which is the default.\n        /// </summary>\n        /// <value>Load shedding begins at a CPU utilization of 95% by default, if load shedding is enabled.</value>\n        /// <remarks>This property is deprecated. Use <see cref=\"CpuThreshold\"/> instead.</remarks>\n        [Obsolete($\"Use {nameof(CpuThreshold)} instead.\", error: true)]\n        public int LoadSheddingLimit { get => CpuThreshold; set => CpuThreshold = value; }\n\n        /// <summary>\n        /// Gets or sets the CPU utilization, expressed as a value between <c>0</c> and <c>100</c>, at which load shedding begins.\n        /// Note that this value is in %, so valid values range from 1 to 100, and a reasonable value is typically between 80 and 95.\n        /// This value is ignored if load shedding is disabled, which is the default.\n        /// </summary>\n        /// <value>Load shedding begins at a CPU utilization of 95% by default, if load shedding is enabled.</value>\n        public int CpuThreshold { get; set; } = DefaultCpuThreshold;\n\n        /// <summary>\n        /// Gets or sets the memory utilization, expressed as a value between <c>0</c> and <c>100</c>, at which load shedding begins.\n        /// Note that this value is in %, so valid values range from 1 to 100, and a reasonable value is typically between 80 and 95.\n        /// This value is ignored if load shedding is disabled, which is the default.\n        /// </summary>\n        /// <value>Load shedding begins at a memory utilization of 90% by default, if load shedding is enabled.</value>\n        public int MemoryThreshold { get; set; } = DefaultMemoryThreshold;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/MessagingOptions.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Specifies global messaging options that are common to client and silo.\n    /// </summary>\n    public abstract class MessagingOptions\n    {\n        /// <summary>\n        /// The <see cref=\"ResponseTimeout\"/> value.\n        /// </summary>\n        private TimeSpan _responseTimeout = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Gets or sets the default timeout before a request is assumed to have failed.\n        /// </summary>\n        /// <seealso cref=\"ResponseTimeoutWithDebugger\"/>\n        /// <value>Requests will timeout after 30 seconds by default.</value>\n        public TimeSpan ResponseTimeout\n        {\n            get { return Debugger.IsAttached ? ResponseTimeoutWithDebugger : _responseTimeout; }\n            set { this._responseTimeout = value; }\n        }\n\n        /// <summary>\n        /// Gets or sets the effective <see cref=\"ResponseTimeout\"/> value to use when a debugger is attached.\n        /// </summary>\n        /// <value>Requests will timeout after 30 minutes when a debugger is attached, by default.</value>\n        public TimeSpan ResponseTimeoutWithDebugger { get; set; } = TimeSpan.FromMinutes(30);\n\n        /// <summary>\n        /// Gets or sets a value indicating whether messages should be dropped once they expire, that is if it was not delivered\n        /// to the destination before it has timed out on the sender.\n        /// </summary>\n        /// <value>Messages are dropped once they expire, by default.</value>\n        public bool DropExpiredMessages { get; set; } = true;\n\n        /// <summary>\n        /// The maximum number of times a message send attempt will be retried.\n        /// </summary>\n        internal const short DEFAULT_MAX_MESSAGE_SEND_RETRIES = 1;\n\n        /// <summary>\n        /// The maximum size, in bytes, of the header for a message. The runtime will forcibly close the connection\n        /// if the header size is greater than this value.\n        /// </summary>\n        /// <value>The maximum message header size is 10 MB by default.</value>\n        public int MaxMessageHeaderSize { get; set; } = 10 * 1024 * 1024;\n\n        /// <summary>\n        /// The maximum size, in bytes, of the body for a message. The runtime will forcibly close the connection\n        /// if the body size is greater than this value.\n        /// </summary>\n        /// <value>The maximum message body size is 100 MB by default.</value>\n        public int MaxMessageBodySize { get; set; } = 100 * 1024 * 1024;\n\n        /// <summary>\n        /// Gets the response timeout underlying the <see cref=\"ResponseTimeout\"/> property, without debugger checks.\n        /// </summary>\n        internal TimeSpan ConfiguredResponseTimeout => _responseTimeout;\n\n        /// <summary>\n        /// Whether request cancellation should be attempted when a request times out.\n        /// </summary>\n        /// <remarks>\n        /// Request cancellation may involve sending a cancellation message to the silo which hosts the target grain.\n        /// Defaults to <see langword=\"false\"/>.\n        /// </remarks>\n        public bool CancelRequestOnTimeout { get; set; }\n\n        /// <summary>\n        /// Whether local calls should be cancelled immediately when cancellation is signaled (<see langword=\"false\"/>)\n        /// rather than waiting for callees to acknowledge cancellation before a call is considered cancelled (<see langword=\"true\"/>).\n        /// </summary>\n        /// <remarks>\n        /// Defaults to <see langword=\"false\"/>.\n        /// </remarks>\n        public bool WaitForCancellationAcknowledgement { get; set; }\n\n        /// <summary>\n        /// Whether request cancellation should be attempted when a status update is received for an unknown request.\n        /// </summary>\n        /// <remarks>\n        /// A status update for an unknown request likely indicates that the request previously timed out and was subsequently dropped.\n        /// Request cancellation may involve sending a cancellation message to the silo which hosts the target grain.\n        /// If the remote callee does not support cancellation, this setting has no effect.\n        /// Defaults to <see langword=\"false\"/>.\n        /// </remarks>\n        public bool CancelUnknownRequestOnStatusUpdate { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/StaticGatewayListProviderOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Hosting;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring a static list of gateways.\n    /// </summary>\n    /// <remarks>>\n    /// See <see cref=\"ClientBuilderExtensions.UseStaticClustering(IClientBuilder, System.Net.IPEndPoint[])\"/> for more information.\n    /// </remarks>\n    public class StaticGatewayListProviderOptions\n    {\n        /// <summary>\n        /// Gets or sets the list of gateway addresses.\n        /// </summary>\n        public List<Uri> Gateways { get; set; } = new List<Uri>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Options/TypeManagementOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Type management settings for in place upgrade.\n    /// </summary>\n    public class TypeManagementOptions\n    {\n        /// <summary>\n        /// The number of seconds to refresh the cluster grain interface map\n        /// </summary>\n        public TimeSpan TypeMapRefreshInterval { get; set; } = DEFAULT_REFRESH_CLUSTER_INTERFACEMAP_TIME;\n        public static readonly TimeSpan DEFAULT_REFRESH_CLUSTER_INTERFACEMAP_TIME = TimeSpan.FromMinutes(1);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/OptionsOverrides.cs",
    "content": "\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration.Overrides\n{\n    /// <summary>\n    /// Functionality for overriding options using named options, falling back to the default (unnamed) value.\n    /// </summary>\n    public static class OptionsOverrides\n    {\n        /// <summary>\n        /// Gets <see cref=\"ClusterOptions\"/> which may have been overridden on a per-provider basis.\n        /// Note: This is intended for migration purposes as a means to handle previously inconsistent behaviors in how providers used ServiceId and ClusterId.\n        /// </summary>\n        public static IOptions<ClusterOptions> GetProviderClusterOptions(this IServiceProvider services, string providerName) => services.GetOverridableOption<ClusterOptions>(providerName);\n\n        /// <summary>\n        /// Gets option that can be overridden by named service.\n        /// </summary>\n        private static IOptions<TOptions> GetOverridableOption<TOptions>(this IServiceProvider services, string key)\n            where TOptions : class, new()\n        {\n            TOptions option = services.GetKeyedService<TOptions>(key);\n            return option != null\n                ? Options.Create(option)\n                : services.GetRequiredService<IOptions<TOptions>>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/ServiceCollectionExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Configuration.Internal\n{\n    /// <summary>\n    /// Extension methods for configuring dependency injection.\n    /// </summary>\n    public static class ServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers an existing registration of <typeparamref name=\"TImplementation\"/> as a provider of service type <typeparamref name=\"TService\"/>.\n        /// </summary>\n        /// <typeparam name=\"TService\">The service type being provided.</typeparam>\n        /// <typeparam name=\"TImplementation\">The implementation of <typeparamref name=\"TService\"/>.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        public static void AddFromExisting<TService, TImplementation>(this IServiceCollection services) where TImplementation : TService\n        {\n            services.AddFromExisting(typeof(TService), typeof(TImplementation));\n        }\n\n        /// <summary>\n        /// Registers an existing registration of <paramref name=\"implementation\"/> as a provider of service type <paramref name=\"service\"/>.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"service\">The service type being provided.</param>\n        /// <param name=\"implementation\">The implementation of <paramref name=\"service\"/>.</param>\n        public static void AddFromExisting(this IServiceCollection services, Type service, Type implementation)\n        {\n            ServiceDescriptor registration = null;\n            foreach (var descriptor in services)\n            {\n                if (descriptor.ServiceType == implementation)\n                {\n                    registration = descriptor;\n                    break;\n                }\n            }\n\n            if (registration is null)\n            {\n                throw new ArgumentNullException(nameof(implementation), $\"Unable to find previously registered ServiceType of '{implementation.FullName}'\");\n            }\n\n            var newRegistration = new ServiceDescriptor(\n                service,\n                sp => sp.GetRequiredService(implementation),\n                registration.Lifetime);\n            services.Add(newRegistration);\n        }\n\n        /// <summary>\n        /// Registers an existing registration of <typeparamref name=\"TImplementation\"/> as a provider of <typeparamref name=\"TService\"/> if there are no existing <typeparamref name=\"TService\"/> implementations.\n        /// </summary>\n        /// <typeparam name=\"TService\">The service type being provided.</typeparam>\n        /// <typeparam name=\"TImplementation\">The implementation of <typeparamref name=\"TService\"/>.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        public static void TryAddFromExisting<TService, TImplementation>(this IServiceCollection services) where TImplementation : TService\n        {\n            if (services.All(service => service.ServiceType != typeof(TService)))\n            {\n                services.AddFromExisting<TService, TImplementation>();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Validators/ClientClusteringValidator.cs",
    "content": "using System;\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration.Validators\n{\n    /// <summary>\n    /// Validator for client-side clustering.\n    /// </summary>\n    internal class ClientClusteringValidator : IConfigurationValidator\n    {\n        /// <summary>\n        /// The error message displayed when clustering is misconfigured.\n        /// </summary>\n        internal const string ClusteringNotConfigured =\n            \"Clustering has not been configured. Configure clustering using one of the clustering packages, such as:\"\n            + \"\\n  * Microsoft.Orleans.Clustering.AzureStorage\"\n            + \"\\n  * Microsoft.Orleans.Clustering.AdoNet for ADO.NET systems such as SQL Server, MySQL, PostgreSQL, and Oracle\"\n            + \"\\n  * Microsoft.Orleans.Clustering.DynamoDB\"\n            + \"\\n  * Microsoft.Orleans.Clustering.Consul\"\n            + \"\\n  * Microsoft.Orleans.Clustering.ZooKeeper\"\n            + \"\\n  * Others, see: https://www.nuget.org/packages?q=Microsoft.Orleans.Clustering.\";\n\n        /// <summary>\n        /// The service provider.\n        /// </summary>\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientClusteringValidator\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public ClientClusteringValidator(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            var gatewayProvider = _serviceProvider.GetService<IGatewayListProvider>();\n            if (gatewayProvider == null)\n            {\n                throw new OrleansConfigurationException(ClusteringNotConfigured);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Validators/LoadSheddingValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration.Validators;\n\n/// <summary>\n/// Validates <see cref=\"LoadSheddingOptions\"/> configuration.\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"LoadSheddingValidator\"/> class.\n/// </remarks>\n/// <param name=\"loadSheddingOptions\">\n/// The load shedding options.\n/// </param>\ninternal class LoadSheddingValidator(IOptions<LoadSheddingOptions> loadSheddingOptions) : IConfigurationValidator\n{\n    private readonly LoadSheddingOptions _loadSheddingOptions = loadSheddingOptions.Value;\n\n    /// <inheritdoc />\n    public void ValidateConfiguration()\n    {\n        // When Load Shedding is disabled, don't validate configuration.\n        if (!_loadSheddingOptions.LoadSheddingEnabled)\n        {\n            return;\n        }\n\n        if (_loadSheddingOptions.CpuThreshold > 100 || _loadSheddingOptions.CpuThreshold <= 0)\n        {\n            throw new OrleansConfigurationException($\"Limit '{nameof(LoadSheddingOptions)}.{nameof(LoadSheddingOptions.CpuThreshold)}' must be greater than 0% and less than or equal to 100%.\");\n        }\n\n        if (_loadSheddingOptions.MemoryThreshold > 100 || _loadSheddingOptions.MemoryThreshold <= 0)\n        {\n            throw new OrleansConfigurationException($\"Limit '{nameof(LoadSheddingOptions)}.{nameof(LoadSheddingOptions.MemoryThreshold)}' must be greater than 0% and less than or equal to 100%.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Configuration/Validators/SerializerConfigurationValidator.cs",
    "content": "using System;\nusing System.Text;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Validates serializer configuration.\n    /// </summary>\n    public class SerializerConfigurationValidator : IConfigurationValidator\n    {\n        private readonly ICodecProvider _codecProvider;\n        private readonly TypeManifestOptions _options;\n        private readonly bool _enabled;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerConfigurationValidator\"/> class.\n        /// </summary>\n        /// <param name=\"codecProvider\">\n        /// The codec provider.\n        /// </param>\n        /// <param name=\"options\">\n        /// The type manifest options.\n        /// </param>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public SerializerConfigurationValidator(ICodecProvider codecProvider, IOptions<TypeManifestOptions> options, IServiceProvider serviceProvider)\n        {\n            _codecProvider = codecProvider;\n            _options = options.Value;\n\n            var configEnabled = _options.EnableConfigurationAnalysis;\n            if (configEnabled.HasValue)\n            {\n                _enabled = configEnabled.Value;\n            }\n            else\n            {\n                // Enable in development envioronment by default.\n                var environment = serviceProvider.GetService<IHostEnvironment>();\n                _enabled = environment is not null && environment.IsDevelopment();\n            }\n        }\n\n        void IConfigurationValidator.ValidateConfiguration()\n        {\n            if (!_enabled)\n            {\n                return;\n            }\n\n            var complaints = SerializerConfigurationAnalyzer.AnalyzeSerializerAvailability(_codecProvider, _options);\n            if (complaints.Count > 0)\n            {\n                var result = new StringBuilder();\n                result.AppendLine(\"Found unserializable or uncopyable types which are being referenced in grain interface signatures:\");\n                foreach (var (type, complaint) in complaints)\n                {\n                    result.Append($\"Type: {type}\");\n                    if (!complaint.HasSerializer)\n                    {\n                        result.Append(\" has no serializer\");\n                        if (!complaint.HasCopier)\n                        {\n                            result.Append(\" or copier\");\n                        }\n                    }\n                    else if (!complaint.HasCopier)\n                    {\n                        result.Append(\" has no copier\");\n                    }\n\n                    result.Append(\" and was referenced by the following:\");\n                    foreach (var (declaringType, methodList) in complaint.Methods)\n                    {\n                        result.Append($\"\\n\\t* {RuntimeTypeNameFormatter.Format(declaringType)} methods: {string.Join(\", \", methodList)}\");\n                    }\n\n                    result.AppendLine();\n                }\n\n                result.AppendLine(\"Ensure that all types which are used in grain interfaces have serializers available for them.\");\n                result.AppendLine(\"Applying the [GenerateSerializer] attribute to your type and adding [Id(x)] attributes to serializable properties and fields is the simplest way to accomplish this.\");\n                result.AppendLine(\"Alternatively, for types which are outside of your control, serializers may have to be manually crafted, potentially using surrogate types.\");\n\n                throw new OrleansConfigurationException(result.ToString());\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/ClientBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Builder for configuring an Orleans client.\n    /// </summary>\n    public class ClientBuilder : IClientBuilder\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientBuilder\"/> class.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        public ClientBuilder(IServiceCollection services, IConfiguration configuration)\n        {\n            Services = services;\n            Configuration = configuration;\n            DefaultClientServices.AddDefaultServices(this);\n        }\n\n        /// <inheritdoc/>\n        public IServiceCollection Services { get; }\n\n        /// <inheritdoc/>\n        public IConfiguration Configuration { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/ClientBuilderExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Net;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IClientBuilder\"/>.\n    /// </summary>\n    public static class ClientBuilderExtensions\n    {\n        /// <summary>\n        /// Configures the provided delegate as a connection retry filter, used to determine whether initial connection to the Orleans cluster should be retried after a failure.\n        /// </summary>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <param name=\"connectionRetryFilter\">The connection retry filter.</param>\n        /// <returns>The same instance of the <see cref=\"IClientBuilder\"/> for chaining.</returns>\n        public static IClientBuilder UseConnectionRetryFilter(this IClientBuilder builder, Func<Exception, CancellationToken, Task<bool>> connectionRetryFilter)\n        {\n            return builder.ConfigureServices(collection => collection.AddSingleton<IClientConnectionRetryFilter>(new DelegateConnectionRetryFilter(connectionRetryFilter)));\n        }\n\n        /// <summary>\n        /// Configures the provided delegate as a connection retry filter, used to determine whether initial connection to the Orleans cluster should be retried after a failure.\n        /// </summary>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <param name=\"connectionRetryFilter\">The connection retry filter.</param>\n        /// <returns>The same instance of the <see cref=\"IClientBuilder\"/> for chaining.</returns>\n        public static IClientBuilder UseConnectionRetryFilter(this IClientBuilder builder, IClientConnectionRetryFilter connectionRetryFilter)\n        {\n            return builder.ConfigureServices(collection => collection.AddSingleton<IClientConnectionRetryFilter>(connectionRetryFilter));\n        }\n\n        /// <summary>\n        /// Configures the provided <typeparamref name=\"TConnectionRetryFilter\"/> type as a connection retry filter, used to determine whether initial connection to the Orleans cluster should be retried after a failure.\n        /// </summary>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <returns>The same instance of the <see cref=\"IClientBuilder\"/> for chaining.</returns>\n        public static IClientBuilder UseConnectionRetryFilter<TConnectionRetryFilter>(this IClientBuilder builder) where TConnectionRetryFilter : class, IClientConnectionRetryFilter\n        {\n            return builder.ConfigureServices(collection => collection.AddSingleton<IClientConnectionRetryFilter, TConnectionRetryFilter>());\n        }\n\n        private sealed class DelegateConnectionRetryFilter : IClientConnectionRetryFilter\n        {\n            private readonly Func<Exception, CancellationToken, Task<bool>> _filter;\n            public DelegateConnectionRetryFilter(Func<Exception, CancellationToken, Task<bool>> connectionRetryFilter) => _filter = connectionRetryFilter ?? throw new ArgumentNullException(nameof(connectionRetryFilter));\n            public Task<bool> ShouldRetryConnectionAttempt(Exception exception, CancellationToken cancellationToken) => _filter(exception, cancellationToken);\n        }\n\n        /// <summary>\n        /// Adds services to the container. This can be called multiple times and the results will be additive.\n        /// </summary>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <param name=\"configureDelegate\"></param>\n        /// <returns>The same instance of the <see cref=\"IClientBuilder\"/> for chaining.</returns>\n        public static IClientBuilder ConfigureServices(this IClientBuilder builder, Action<IServiceCollection> configureDelegate)\n        {\n            if (configureDelegate == null) throw new ArgumentNullException(nameof(configureDelegate));\n            configureDelegate(builder.Services);\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers an action used to configure a particular type of options.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type to be configured.</typeparam>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <param name=\"configureOptions\">The action used to configure the options.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder Configure<TOptions>(this IClientBuilder builder, Action<TOptions> configureOptions) where TOptions : class\n        {\n            return builder.ConfigureServices(services => services.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Registers a configuration instance which <typeparamref name=\"TOptions\"/> will bind against.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type to be configured.</typeparam>\n        /// <param name=\"builder\">The host builder.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder Configure<TOptions>(this IClientBuilder builder, IConfiguration configuration) where TOptions : class\n        {\n            return builder.ConfigureServices(services => services.AddOptions<TOptions>().Bind(configuration));\n        }\n\n        /// <summary>\n        /// Registers a <see cref=\"GatewayCountChangedHandler\"/> event handler.\n        /// </summary>\n        public static IClientBuilder AddGatewayCountChangedHandler(this IClientBuilder builder, GatewayCountChangedHandler handler)\n        {\n            builder.ConfigureServices(services => services.AddSingleton(handler));\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers a <see cref=\"GatewayCountChangedHandler\"/> event handler.\n        /// </summary>\n        public static IClientBuilder AddGatewayCountChangedHandler(this IClientBuilder builder, Func<IServiceProvider, GatewayCountChangedHandler> handlerFactory)\n        {\n            builder.ConfigureServices(services => services.AddSingleton(handlerFactory));\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers a cluster connection status observer.\n        /// </summary>\n        public static IClientBuilder AddClusterConnectionStatusObserver<TObserver>(this IClientBuilder builder, TObserver observer)\n            where TObserver : IClusterConnectionStatusObserver\n        {\n            builder.Services.AddSingleton<IClusterConnectionStatusObserver>(observer);\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers a cluster connection status observer.\n        /// </summary>\n        public static IClientBuilder AddClusterConnectionStatusObserver<TObserver>(this IClientBuilder builder)\n            where TObserver : class, IClusterConnectionStatusObserver\n        {\n            builder.Services.AddSingleton<IClusterConnectionStatusObserver, TObserver>();\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers a <see cref=\"ConnectionToClusterLostHandler\"/> event handler.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"handler\">The handler.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder AddClusterConnectionLostHandler(this IClientBuilder builder, ConnectionToClusterLostHandler handler)\n        {\n            builder.ConfigureServices(services => services.AddSingleton(handler));\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers a <see cref=\"ConnectionToClusterLostHandler\"/> event handler.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"handlerFactory\">The handler factory.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder AddClusterConnectionLostHandler(this IClientBuilder builder, Func<IServiceProvider, ConnectionToClusterLostHandler> handlerFactory)\n        {\n            builder.ConfigureServices(services => services.AddSingleton(handlerFactory));\n            return builder;\n        }\n\n        /// <summary>\n        /// Add <see cref=\"Activity.Current\"/> propagation through grain calls.\n        /// Note: according to <see cref=\"ActivitySource.StartActivity(string, ActivityKind)\"/> activity will be created only when any listener for activity exists <see cref=\"ActivitySource.HasListeners()\"/> and <see cref=\"ActivityListener.Sample\"/> returns <see cref=\"ActivitySamplingResult.PropagationData\"/>.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n        public static IClientBuilder AddActivityPropagation(this IClientBuilder builder)\n        {\n            builder.Services.TryAddSingleton(DistributedContextPropagator.Current);\n\n            return builder\n                .AddOutgoingGrainCallFilter<ActivityPropagationOutgoingGrainCallFilter>()\n                .AddIncomingGrainCallFilter<ActivityPropagationIncomingGrainCallFilter>();\n        }\n\n        /// <summary>\n        /// Configures the client to connect to a silo on the localhost.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"gatewayPort\">\n        /// The local silo's gateway port.\n        /// </param>\n        /// <param name=\"serviceId\">\n        /// The service id.\n        /// </param>\n        /// <param name=\"clusterId\">\n        /// The cluster id.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseLocalhostClustering(\n            this IClientBuilder builder,\n            int gatewayPort = 30000,\n            string serviceId = ClusterOptions.DevelopmentServiceId,\n            string clusterId = ClusterOptions.DevelopmentClusterId)\n        {\n            return builder.UseLocalhostClustering(new [] {gatewayPort}, serviceId, clusterId);\n        }\n\n        /// <summary>\n        /// Configures the client to connect to a silo on the localhost.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"gatewayPorts\">\n        /// The local silo gateway ports.\n        /// </param>\n        /// <param name=\"serviceId\">\n        /// The service id.\n        /// </param>\n        /// <param name=\"clusterId\">\n        /// The cluster id.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseLocalhostClustering(this IClientBuilder builder,\n            int[] gatewayPorts,\n            string serviceId = ClusterOptions.DevelopmentServiceId,\n            string clusterId = ClusterOptions.DevelopmentClusterId)\n        {\n            return builder.UseStaticClustering(gatewayPorts.Select(p => new IPEndPoint(IPAddress.Loopback, p)).ToArray())\n                .ConfigureServices(services =>\n                {\n                    // If the caller did not override service id or cluster id, configure default values as a fallback.\n                    if (string.Equals(serviceId, ClusterOptions.DevelopmentServiceId) && string.Equals(clusterId, ClusterOptions.DevelopmentClusterId))\n                    {\n                        services.PostConfigure<ClusterOptions>(options =>\n                        {\n                            if (string.IsNullOrWhiteSpace(options.ClusterId)) options.ClusterId = ClusterOptions.DevelopmentClusterId;\n                            if (string.IsNullOrWhiteSpace(options.ServiceId)) options.ServiceId = ClusterOptions.DevelopmentServiceId;\n                        });\n                    }\n                    else\n                    {\n                        services.Configure<ClusterOptions>(options =>\n                        {\n                            options.ServiceId = serviceId;\n                            options.ClusterId = clusterId;\n                        });\n                    }\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use static clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"endpoints\">\n        /// The gateway endpoints.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, params IPEndPoint[] endpoints)\n        {\n            return builder.UseStaticClustering(options => options.Gateways = endpoints.Select(ep => ep.ToGatewayUri()).ToList());\n        }\n\n        /// <summary>\n        /// Configures the client to use static clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configure Options.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, Action<StaticGatewayListProviderOptions> configureOptions)\n        {\n            return builder.ConfigureServices(\n                collection =>\n                {\n                    if (configureOptions != null)\n                    {\n                        collection.Configure(configureOptions);\n                    }\n\n                    collection.AddSingleton<IGatewayListProvider, StaticGatewayListProvider>()\n                        .ConfigureFormatter<StaticGatewayListProviderOptions>();\n                });\n        }\n\n        /// <summary>\n        /// Configures the client to use static clustering.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The client builder.\n        /// </param>\n        /// <param name=\"configureOptions\">\n        /// The configure Options.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IClientBuilder\"/>.\n        /// </returns>\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, Action<OptionsBuilder<StaticGatewayListProviderOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                collection =>\n                {\n                    configureOptions?.Invoke(collection.AddOptions<StaticGatewayListProviderOptions>());\n                    collection.AddSingleton<IGatewayListProvider, StaticGatewayListProvider>()\n                        .ConfigureFormatter<StaticGatewayListProviderOptions>();\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/ClientBuilderGrainCallFilterExtensions.cs",
    "content": "namespace Orleans.Hosting;\n\n/// <summary>\n/// Extensions for configuring grain call filters.\n/// </summary>\npublic static class ClientBuilderGrainCallFilterExtensions\n{\n    /// <summary>\n    /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <param name=\"filter\">The filter.</param>\n    /// <returns>The builder.</returns>\n    public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IIncomingGrainCallFilter filter)\n    {\n        return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));\n    }\n\n    /// <summary>\n    /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n    /// </summary>\n    /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n    /// <param name=\"builder\">The builder.</param>\n    /// <returns>The builder.</returns>\n    public static IClientBuilder AddIncomingGrainCallFilter<TImplementation>(this IClientBuilder builder)\n        where TImplementation : class, IIncomingGrainCallFilter\n    {\n        return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter<TImplementation>());\n    }\n\n    /// <summary>\n    /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline via a delegate.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <param name=\"filter\">The filter.</param>\n    /// <returns>The builder.</returns>\n    public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IncomingGrainCallFilterDelegate filter)\n    {\n        return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));\n    }\n\n    /// <summary>\n    /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <param name=\"filter\">The filter.</param>\n    /// <returns>The <see cref=\"IClientBuilder\"/>.</returns>\n    public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, IOutgoingGrainCallFilter filter)\n    {\n        return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));\n    }\n\n    /// <summary>\n    /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n    /// </summary>\n    /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n    /// <param name=\"builder\">The builder.</param>\n    /// <returns>The <see cref=\"IClientBuilder\"/>.</returns>\n    public static IClientBuilder AddOutgoingGrainCallFilter<TImplementation>(this IClientBuilder builder)\n        where TImplementation : class, IOutgoingGrainCallFilter\n    {\n        return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter<TImplementation>());\n    }\n\n    /// <summary>\n    /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline via a delegate.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <param name=\"filter\">The filter.</param>\n    /// <returns>The <see cref=\"IClientBuilder\"/>.</returns>\n    public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, OutgoingGrainCallFilterDelegate filter)\n    {\n        return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/ClusterClient.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Client for communicating with clusters of Orleans silos.\n    /// </summary>\n    internal partial class ClusterClient : IInternalClusterClient, IHostedService\n    {\n        private readonly OutsideRuntimeClient _runtimeClient;\n        private readonly ILogger<ClusterClient> _logger;\n        private readonly ClusterClientLifecycle _clusterClientLifecycle;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterClient\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"runtimeClient\">The runtime client.</param>\n        /// <param name=\"loggerFactory\">Logger factory used to create loggers</param>\n        /// <param name=\"clientMessagingOptions\">Messaging parameters</param>\n        public ClusterClient(IServiceProvider serviceProvider, OutsideRuntimeClient runtimeClient, ILoggerFactory loggerFactory, IOptions<ClientMessagingOptions> clientMessagingOptions)\n        {\n            ValidateSystemConfiguration(serviceProvider);\n            runtimeClient.ConsumeServices();\n\n            _runtimeClient = runtimeClient;\n            _logger = loggerFactory.CreateLogger<ClusterClient>();\n            _clusterClientLifecycle = new ClusterClientLifecycle(_logger);\n\n            // register all lifecycle participants\n            IEnumerable<ILifecycleParticipant<IClusterClientLifecycle>> lifecycleParticipants = ServiceProvider.GetServices<ILifecycleParticipant<IClusterClientLifecycle>>();\n            foreach (var participant in lifecycleParticipants)\n            {\n                participant?.Participate(_clusterClientLifecycle);\n            }\n\n            static void ValidateSystemConfiguration(IServiceProvider serviceProvider)\n            {\n                var validators = serviceProvider.GetServices<IConfigurationValidator>();\n                foreach (var validator in validators)\n                {\n                    validator.ValidateConfiguration();\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public IServiceProvider ServiceProvider => _runtimeClient.ServiceProvider;\n\n        /// <inheritdoc />\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            await _runtimeClient.StartAsync(cancellationToken).ConfigureAwait(false);\n            await _clusterClientLifecycle.OnStart(cancellationToken).ConfigureAwait(false);\n        }\n\n        /// <inheritdoc />\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                LogClientShuttingDown(_logger);\n\n                await _clusterClientLifecycle.OnStop(cancellationToken).ConfigureAwait(false);\n                await _runtimeClient.StopAsync(cancellationToken).WaitAsync(cancellationToken);\n            }\n            finally\n            {\n                LogClientShutdownCompleted(_logger);\n            }\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidKey => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerKey => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj)\n            where TGrainObserverInterface : IGrainObserver => ((IGrainFactory)_runtimeClient.InternalGrainFactory).CreateObjectReference<TGrainObserverInterface>(obj);\n\n        /// <inheritdoc />\n        public void DeleteObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver => _runtimeClient.InternalGrainFactory.DeleteObjectReference<TGrainObserverInterface>(obj);\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IAddressable obj)\n            where TGrainObserverInterface : IAddressable => _runtimeClient.InternalGrainFactory.CreateObjectReference<TGrainObserverInterface>(obj);\n\n        /// <inheritdoc />\n        TGrainInterface IInternalGrainFactory.GetSystemTarget<TGrainInterface>(GrainType grainType, SiloAddress destination) => _runtimeClient.InternalGrainFactory.GetSystemTarget<TGrainInterface>(grainType, destination);\n\n        public TGrainInterface GetSystemTarget<TGrainInterface>(GrainId grainId) where TGrainInterface : ISystemTarget => _runtimeClient.InternalGrainFactory.GetSystemTarget<TGrainInterface>(grainId);\n\n        /// <inheritdoc />\n        TGrainInterface IInternalGrainFactory.Cast<TGrainInterface>(IAddressable grain) => _runtimeClient.InternalGrainFactory.Cast<TGrainInterface>(grain);\n\n        /// <inheritdoc />\n        TGrainInterface IGrainFactory.GetGrain<TGrainInterface>(GrainId grainId) => _runtimeClient.InternalGrainFactory.GetGrain<TGrainInterface>(grainId);\n\n        /// <inheritdoc />\n        IAddressable IGrainFactory.GetGrain(GrainId grainId) => _runtimeClient.InternalGrainFactory.GetGrain(grainId);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, string grainPrimaryKey)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey, string keyExtension)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainInterfaceType, grainPrimaryKey, keyExtension);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey, string keyExtension)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainInterfaceType, grainPrimaryKey, keyExtension);\n\n        /// <inheritdoc />\n        public object Cast(IAddressable grain, Type outputGrainInterfaceType)\n            => _runtimeClient.InternalGrainFactory.Cast(grain, outputGrainInterfaceType);\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(GrainId grainId, GrainInterfaceType interfaceType)\n            => _runtimeClient.InternalGrainFactory.GetGrain(grainId, interfaceType);\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix)\n            => _runtimeClient.InternalGrainFactory.GetGrain(interfaceType, grainKey, grainClassNamePrefix);\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey)\n            => _runtimeClient.InternalGrainFactory.GetGrain(interfaceType, grainKey);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Client shutting down.\"\n        )]\n        private static partial void LogClientShuttingDown(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Client shutdown completed.\"\n        )]\n        private static partial void LogClientShutdownCompleted(ILogger logger);\n      \n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/DefaultClientServices.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.Configuration.Validators;\nusing Orleans.GrainReferences;\nusing Orleans.Hosting;\nusing Orleans.Messaging;\nusing Orleans.Metadata;\nusing Orleans.Networking.Shared;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Versions;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Internal;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Statistics;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Configures the default services for a client.\n    /// </summary>\n    internal static class DefaultClientServices\n    {\n        private static readonly ServiceDescriptor ServiceDescriptor = new(typeof(ServicesAdded), new ServicesAdded());\n\n        /// <summary>\n        /// Configures the default services for a client.\n        /// </summary>\n        /// <param name=\"builder\">The client builder.</param>\n        public static void AddDefaultServices(IClientBuilder builder)\n        {\n            var services = builder.Services;\n            if (services.Contains(ServiceDescriptor))\n            {\n                return;\n            }\n\n            services.Add(ServiceDescriptor);\n\n            // Common services\n            services.AddLogging();\n            services.AddOptions();\n            services.AddMetrics();\n            services.TryAddSingleton<TimeProvider>(TimeProvider.System);\n            services.TryAddSingleton<OrleansInstruments>();\n\n            // Options logging\n            services.TryAddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.TryAddSingleton(typeof(IOptionFormatterResolver<>), typeof(DefaultOptionsFormatterResolver<>));\n\n            services.AddSingleton<ClientOptionsLogger>();\n            services.AddFromExisting<ILifecycleParticipant<IClusterClientLifecycle>, ClientOptionsLogger>();\n\n            // Lifecycle\n            services.AddSingleton<ServiceLifecycle<IClusterClientLifecycle>>();\n            services.TryAddFromExisting<IServiceLifecycle, ServiceLifecycle<IClusterClientLifecycle>>();\n            services.AddFromExisting<ILifecycleParticipant<IClusterClientLifecycle>, ServiceLifecycle<IClusterClientLifecycle>>();\n\n            // Statistics\n            services.AddSingleton<IEnvironmentStatisticsProvider, EnvironmentStatisticsProvider>();\n#pragma warning disable 618\n            services.AddSingleton<OldEnvironmentStatistics>();\n            services.AddFromExisting<IAppEnvironmentStatistics, OldEnvironmentStatistics>();\n            services.AddFromExisting<IHostEnvironmentStatistics, OldEnvironmentStatistics>();\n#pragma warning restore 618\n\n            services.TryAddSingleton<GrainBindingsResolver>();\n            services.TryAddSingleton<LocalClientDetails>();\n            services.TryAddSingleton<OutsideRuntimeClient>();\n            services.TryAddSingleton<InterfaceToImplementationMappingCache>();\n            services.TryAddSingleton<ClientGrainContext>();\n            services.AddSingleton<IClusterConnectionStatusObserver, ClusterConnectionStatusObserverAdaptor>();\n            services.AddFromExisting<IGrainContextAccessor, ClientGrainContext>();\n            services.TryAddFromExisting<IRuntimeClient, OutsideRuntimeClient>();\n            services.TryAddFromExisting<IClusterConnectionStatusListener, OutsideRuntimeClient>();\n            services.TryAddSingleton<GrainFactory>();\n            services.TryAddSingleton<GrainInterfaceTypeToGrainTypeResolver>();\n            services.TryAddSingleton<GrainReferenceActivator>();\n            services.AddSingleton<IGrainReferenceActivatorProvider, GrainReferenceActivatorProvider>();\n            services.AddSingleton<IGrainReferenceActivatorProvider, UntypedGrainReferenceActivatorProvider>();\n            services.TryAddSingleton<RpcProvider>();\n            services.TryAddSingleton<IGrainReferenceRuntime, GrainReferenceRuntime>();\n            services.TryAddSingleton<GrainPropertiesResolver>();\n            services.TryAddSingleton<IGrainCancellationTokenRuntime, GrainCancellationTokenRuntime>();\n            services.TryAddFromExisting<IGrainFactory, GrainFactory>();\n            services.TryAddFromExisting<IInternalGrainFactory, GrainFactory>();\n            services.TryAddSingleton<ClientProviderRuntime>();\n            services.TryAddSingleton<MessageFactory>();\n            services.TryAddFromExisting<IProviderRuntime, ClientProviderRuntime>();\n            services.TryAddSingleton<ClusterClient>();\n            services.TryAddFromExisting<IClusterClient, ClusterClient>();\n            services.TryAddFromExisting<IInternalClusterClient, ClusterClient>();\n            services.AddFromExisting<IHostedService, ClusterClient>();\n            services.AddTransient<IOptions<MessagingOptions>>(static sp => sp.GetRequiredService<IOptions<ClientMessagingOptions>>());\n            services.TryAddSingleton<IClientConnectionRetryFilter, LinearBackoffClientConnectionRetryFilter>();\n\n            services.AddSingleton<IConfigureOptions<GrainTypeOptions>, DefaultGrainTypeOptionsProvider>();\n\n            // Add default option formatter if none is configured, for options which are required to be configured\n            services.ConfigureFormatter<ClusterOptions>();\n            services.ConfigureFormatter<ClientMessagingOptions>();\n            services.ConfigureFormatter<ConnectionOptions>();\n\n            services.AddTransient<IConfigurationValidator, GrainTypeOptionsValidator>();\n            services.AddTransient<IConfigurationValidator, ClusterOptionsValidator>();\n            services.AddTransient<IConfigurationValidator, ClientClusteringValidator>();\n            services.AddTransient<IConfigurationValidator, SerializerConfigurationValidator>();\n\n            // TODO: abstract or move into some options.\n            services.AddSingleton<SocketSchedulers>();\n            services.AddSingleton<SharedMemoryPool>();\n\n            // Networking\n            services.TryAddSingleton<IMessageStatisticsSink, NoOpMessageStatisticsSink>();\n            services.TryAddSingleton<ConnectionCommon>();\n            services.TryAddSingleton<ConnectionManager>();\n            services.TryAddSingleton<ConnectionPreambleHelper>();\n            services.AddSingleton<ILifecycleParticipant<IClusterClientLifecycle>, ConnectionManagerLifecycleAdapter<IClusterClientLifecycle>>();\n\n            services.AddKeyedSingleton<IConnectionFactory>(\n                ClientOutboundConnectionFactory.ServicesKey,\n                (sp, key) => ActivatorUtilities.CreateInstance<SocketConnectionFactory>(sp));\n\n            services.AddSerializer();\n            services.AddSingleton<ITypeNameFilter, AllowOrleansTypes>();\n            services.AddSingleton<ISpecializableCodec, GrainReferenceCodecProvider>();\n            services.AddSingleton<ISpecializableCopier, GrainReferenceCopierProvider>();\n            services.AddSingleton<OnDeserializedCallbacks>();\n            services.AddSingleton<IPostConfigureOptions<OrleansJsonSerializerOptions>, ConfigureOrleansJsonSerializerOptions>();\n            services.AddSingleton<OrleansJsonSerializer>();\n\n            services.TryAddTransient(sp => ActivatorUtilities.CreateInstance<MessageSerializer>(\n                sp,\n                sp.GetRequiredService<IOptions<ClientMessagingOptions>>().Value));\n            services.TryAddSingleton<ConnectionFactory, ClientOutboundConnectionFactory>();\n            services.TryAddSingleton<ClientMessageCenter>(sp => sp.GetRequiredService<OutsideRuntimeClient>().MessageCenter);\n            services.TryAddFromExisting<IMessageCenter, ClientMessageCenter>();\n            services.AddSingleton<GatewayManager>();\n            services.AddSingleton<NetworkingTrace>();\n            services.AddSingleton<MessagingTrace>();\n\n            // Type metadata\n            services.AddSingleton<ClientClusterManifestProvider>();\n            services.AddFromExisting<IClusterManifestProvider, ClientClusterManifestProvider>();\n            services.AddSingleton<ClientManifestProvider>();\n            services.AddSingleton<IGrainInterfaceTypeProvider, AttributeGrainInterfaceTypeProvider>();\n            services.AddSingleton<GrainTypeResolver>();\n            services.AddSingleton<IGrainTypeProvider, AttributeGrainTypeProvider>();\n            services.AddSingleton<GrainPropertiesResolver>();\n            services.AddSingleton<GrainVersionManifest>();\n            services.AddSingleton<GrainInterfaceTypeResolver>();\n            services.AddSingleton<IGrainInterfacePropertiesProvider, AttributeGrainInterfacePropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, AttributeGrainPropertiesProvider>();\n            services.AddSingleton<IGrainInterfacePropertiesProvider, TypeNameGrainPropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, TypeNameGrainPropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, ImplementedInterfaceProvider>();\n\n            services.AddSingleton<IGrainCallCancellationManager, ExternalClientGrainCallCancellationManager>();\n            services.AddSingleton<ILocalActivationStatusChecker, ClientLocalActivationStatusChecker>();\n\n            ApplyConfiguration(builder);\n        }\n\n        private static void ApplyConfiguration(IClientBuilder builder)\n        {\n            var services = builder.Services;\n            var cfg = builder.Configuration.GetSection(\"Orleans\");\n            var knownProviderTypes = GetRegisteredProviders();\n\n            services.Configure<ClusterOptions>(cfg);\n            services.Configure<ClientMessagingOptions>(cfg.GetSection(\"Messaging\"));\n            services.Configure<GatewayOptions>(cfg.GetSection(\"Gateway\"));\n\n            if (bool.TryParse(cfg[\"EnableDistributedTracing\"], out var enableDistributedTracing) && enableDistributedTracing)\n            {\n                builder.AddActivityPropagation();\n            }\n\n            ApplySubsection(builder, cfg, knownProviderTypes, \"Clustering\");\n            ApplySubsection(builder, cfg, knownProviderTypes, \"Reminders\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"BroadcastChannel\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"Streaming\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"GrainStorage\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"GrainDirectory\");\n\n            static void ConfigureProvider(\n                IClientBuilder builder,\n                Dictionary<(string Kind, string Name), Type> knownProviderTypes,\n                string kind,\n                string? name,\n                IConfigurationSection configurationSection)\n            {\n                var providerType = configurationSection[\"ProviderType\"] ?? \"Default\";\n                var provider = GetRequiredProvider(knownProviderTypes, kind, providerType);\n                provider.Configure(builder, name, configurationSection);\n            }\n\n            static IProviderBuilder<IClientBuilder> GetRequiredProvider(Dictionary<(string Kind, string Name), Type> knownProviderTypes, string kind, string name)\n            {\n                if (knownProviderTypes.TryGetValue((kind, name), out var type))\n                {\n                    var instance = Activator.CreateInstance(type);\n                    return instance as IProviderBuilder<IClientBuilder>\n                        ?? throw new InvalidOperationException($\"{kind} provider, '{name}', of type {type}, does not implement {typeof(IProviderBuilder<IClientBuilder>)}.\");\n                }\n\n                var knownProvidersOfKind = knownProviderTypes\n                    .Where(kvp => string.Equals(kvp.Key.Kind, kind, StringComparison.OrdinalIgnoreCase))\n                    .Select(kvp => kvp.Key.Name)\n                    .OrderBy(n => n)\n                    .ToList();\n\n                var knownProvidersMessage = knownProvidersOfKind.Count > 0\n                    ? $\" Known {kind} providers: {string.Join(\", \", knownProvidersOfKind)}.\"\n                    : string.Empty;\n\n                throw new InvalidOperationException($\"Could not find {kind} provider named '{name}'. This can indicate that either the 'Microsoft.Orleans.Sdk' or the provider's package are not referenced by your application.{knownProvidersMessage}\");\n            }\n\n            static Dictionary<(string Kind, string Name), Type> GetRegisteredProviders()\n            {\n                var result = new Dictionary<(string, string), Type>();\n                foreach (var asm in ReferencedAssemblyProvider.GetRelevantAssemblies())\n                {\n                    foreach (var attr in asm.GetCustomAttributes<RegisterProviderAttribute>())\n                    {\n                        if (string.Equals(attr.Target, \"Client\"))\n                        {\n                            result[(attr.Kind, attr.Name)] = attr.Type;\n                        }\n                    }\n                }\n\n                return result;\n            }\n\n            static void ApplySubsection(IClientBuilder builder, IConfigurationSection cfg, Dictionary<(string Kind, string Name), Type> knownProviderTypes, string sectionName)\n            {\n                if (cfg.GetSection(sectionName) is { } section && section.Exists())\n                {\n                    ConfigureProvider(builder, knownProviderTypes, sectionName, name: null, section);\n                }\n            }\n\n            static void ApplyNamedSubsections(IClientBuilder builder, IConfigurationSection cfg, Dictionary<(string Kind, string Name), Type> knownProviderTypes, string sectionName)\n            {\n                if (cfg.GetSection(sectionName) is { } section && section.Exists())\n                {\n                    foreach (var child in section.GetChildren())\n                    {\n                        ConfigureProvider(builder, knownProviderTypes, sectionName, name: child.Key, child);\n                    }\n                }\n            }\n        }\n\n        internal partial class RootConfiguration\n        {\n            public IConfigurationSection? Clustering { get; set; }\n        }\n\n        /// <summary>\n        /// A <see cref=\"ITypeNameFilter\"/> which allows any type from an assembly containing \"Orleans\" in its name to be allowed for the purposes of serialization and deserialization.\n        /// </summary>\n        private class AllowOrleansTypes : ITypeNameFilter\n        {\n            /// <inheritdoc />\n            public bool? IsTypeNameAllowed(string typeName, string assemblyName)\n            {\n                if (assemblyName is { Length: > 0} && assemblyName.Contains(\"Orleans\"))\n                {\n                    return true;\n                }\n\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// A marker type used to determine\n        /// </summary>\n        private class ServicesAdded { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/GatewayCountChangedEventArgs.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Handler for client disconnection from a cluster.\n    /// </summary>\n    /// <param name=\"sender\">The sender.</param>\n    /// <param name=\"e\">The event arguments.</param>\n    public delegate void ConnectionToClusterLostHandler(object sender, EventArgs e);\n\n    /// <summary>\n    /// Handler for the number of gateways.\n    /// </summary>\n    /// <param name=\"sender\">The sender.</param>\n    /// <param name=\"e\">The event arguments.</param>\n    public delegate void GatewayCountChangedHandler(object sender, GatewayCountChangedEventArgs e);\n\n    /// <summary>\n    /// Event arguments for gateway connectivity events.\n    /// </summary>\n    public class GatewayCountChangedEventArgs : EventArgs\n    {\n        /// <summary>\n        /// Gets the number of gateways which this client is currently connected to.\n        /// </summary>\n        public int NumberOfConnectedGateways { get; }\n\n        /// <summary>\n        /// Gets the number of gateways which this client was currently connected to before this event.\n        /// </summary>\n        public int PreviousNumberOfConnectedGateways { get; }\n\n        /// <summary>\n        /// Helper to detect situations where cluster connectivity was regained.\n        /// </summary>\n        public bool ConnectionRecovered => this.NumberOfConnectedGateways > 0 && this.PreviousNumberOfConnectedGateways <= 0;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GatewayCountChangedEventArgs\"/> class.\n        /// </summary>\n        /// <param name=\"currentNumberOfConnectedGateways\">\n        /// The current number of connected gateways.\n        /// </param>\n        /// <param name=\"previousNumberOfConnectedGateways\">\n        /// The previous number of connected gateways.\n        /// </param>\n        public GatewayCountChangedEventArgs(int currentNumberOfConnectedGateways, int previousNumberOfConnectedGateways)\n        {\n            this.NumberOfConnectedGateways = currentNumberOfConnectedGateways;\n            this.PreviousNumberOfConnectedGateways = previousNumberOfConnectedGateways;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/GrainCallFilterServiceCollectionExtensions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class GrainCallFilterServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        [Obsolete(\"Use ISiloBuilder.\" + nameof(AddIncomingGrainCallFilter), error: true)]\n        public static IServiceCollection AddGrainCallFilter(this IServiceCollection services, IIncomingGrainCallFilter filter)\n        {\n            throw new NotSupportedException($\"{nameof(AddGrainCallFilter)} is no longer supported. Use ISiloBuilder.AddIncomingGrainCallFilter(...) instead.\");\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The service collection.</returns>\n        [Obsolete(\"Use ISiloBuilder.\" + nameof(AddIncomingGrainCallFilter), error: true)]\n        public static IServiceCollection AddGrainCallFilter<TImplementation>(this IServiceCollection services)\n            where TImplementation : class, IIncomingGrainCallFilter\n        {\n            throw new NotSupportedException($\"{nameof(AddGrainCallFilter)} is no longer supported. Use ISiloBuilder.AddIncomingGrainCallFilter(...) instead.\");\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline via a delegate.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        [Obsolete(\"Use ISiloBuilder.\" + nameof(AddIncomingGrainCallFilter), error: true)]\n        public static IServiceCollection AddGrainCallFilter(this IServiceCollection services, GrainCallFilterDelegate filter)\n        {\n            throw new NotSupportedException($\"{nameof(AddGrainCallFilter)} is no longer supported. Use ISiloBuilder.AddIncomingGrainCallFilter(...) instead.\");\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddIncomingGrainCallFilter(this IServiceCollection services, IIncomingGrainCallFilter filter)\n        {\n            return services.AddSingleton(filter);\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddIncomingGrainCallFilter<TImplementation>(this IServiceCollection services)\n            where TImplementation : class, IIncomingGrainCallFilter\n        {\n            return services.AddSingleton<IIncomingGrainCallFilter, TImplementation>();\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline via a delegate.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddIncomingGrainCallFilter(this IServiceCollection services, IncomingGrainCallFilterDelegate filter)\n        {\n            return services.AddSingleton<IIncomingGrainCallFilter>(new IncomingGrainCallFilterWrapper(filter));\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddOutgoingGrainCallFilter(this IServiceCollection services, IOutgoingGrainCallFilter filter)\n        {\n            return services.AddSingleton(filter);\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddOutgoingGrainCallFilter<TImplementation>(this IServiceCollection services)\n            where TImplementation : class, IOutgoingGrainCallFilter\n        {\n            return services.AddSingleton<IOutgoingGrainCallFilter, TImplementation>();\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline via a delegate.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The service collection.</returns>\n        internal static IServiceCollection AddOutgoingGrainCallFilter(this IServiceCollection services, OutgoingGrainCallFilterDelegate filter)\n        {\n            return services.AddSingleton<IOutgoingGrainCallFilter>(new OutgoingGrainCallFilterWrapper(filter));\n        }\n\n        /// <summary>\n        /// Adapts <see cref=\"OutgoingGrainCallFilterDelegate\"/> delegates to the <see cref=\"IOutgoingGrainCallFilter\"/> interface.\n        /// </summary>\n        private class OutgoingGrainCallFilterWrapper : IOutgoingGrainCallFilter\n        {\n            private readonly OutgoingGrainCallFilterDelegate interceptor;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"OutgoingGrainCallFilterWrapper\"/> class.\n            /// </summary>\n            /// <param name=\"interceptor\">\n            /// The interceptor.\n            /// </param>\n            public OutgoingGrainCallFilterWrapper(OutgoingGrainCallFilterDelegate interceptor)\n            {\n                this.interceptor = interceptor;\n            }\n\n            /// <inheritdoc />\n            public Task Invoke(IOutgoingGrainCallContext context) => this.interceptor.Invoke(context);\n        }\n\n        /// <summary>\n        /// Implements <see cref=\"IIncomingGrainCallFilter\"/> by delegating all <see cref=\"IIncomingGrainCallFilter.Invoke\"/> calls to the provided delegate.\n        /// </summary>\n        private class IncomingGrainCallFilterWrapper : IIncomingGrainCallFilter\n        {\n            private readonly IncomingGrainCallFilterDelegate interceptor;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"IncomingGrainCallFilterWrapper\"/> class.\n            /// </summary>\n            /// <param name=\"interceptor\">\n            /// The interceptor.\n            /// </param>\n            public IncomingGrainCallFilterWrapper(IncomingGrainCallFilterDelegate interceptor)\n            {\n                this.interceptor = interceptor;\n            }\n\n            /// <summary>\n            /// Invokes this filter.\n            /// </summary>\n            /// <param name=\"context\">The grain call context.</param>\n            /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n            public Task Invoke(IIncomingGrainCallContext context) => this.interceptor.Invoke(context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/GrainFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Factory for accessing grains.\n    /// </summary>\n    internal class GrainFactory : IInternalGrainFactory\n    {\n        private GrainReferenceRuntime grainReferenceRuntime;\n\n        /// <summary>\n        /// The cache of typed system target references.\n        /// </summary>\n        private readonly Dictionary<(GrainId, Type), ISystemTarget> typedSystemTargetReferenceCache = new Dictionary<(GrainId, Type), ISystemTarget>();\n\n        private readonly GrainReferenceActivator referenceActivator;\n        private readonly GrainInterfaceTypeResolver interfaceTypeResolver;\n        private readonly GrainInterfaceTypeToGrainTypeResolver interfaceTypeToGrainTypeResolver;\n        private readonly IRuntimeClient runtimeClient;\n\n        public GrainFactory(\n            IRuntimeClient runtimeClient,\n            GrainReferenceActivator referenceActivator,\n            GrainInterfaceTypeResolver interfaceTypeResolver,\n            GrainInterfaceTypeToGrainTypeResolver interfaceToTypeResolver)\n        {\n            this.runtimeClient = runtimeClient;\n            this.referenceActivator = referenceActivator;\n            this.interfaceTypeResolver = interfaceTypeResolver;\n            this.interfaceTypeToGrainTypeResolver = interfaceToTypeResolver;\n        }\n\n        private GrainReferenceRuntime GrainReferenceRuntime => this.grainReferenceRuntime ??= (GrainReferenceRuntime)this.runtimeClient.GrainReferenceRuntime;\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidKey\n        {\n            var grainKey = GrainIdKeyExtensions.CreateGuidKey(primaryKey);\n            return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerKey\n        {\n            var grainKey = GrainIdKeyExtensions.CreateIntegerKey(primaryKey);\n            return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(primaryKey);\n            var grainKey = IdSpan.Create(primaryKey);\n            return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey\n        {\n            ValidateGrainKeyExtension(keyExtension);\n\n            var grainKey = GrainIdKeyExtensions.CreateGuidKey(primaryKey, keyExtension);\n            return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey\n        {\n            ValidateGrainKeyExtension(keyExtension);\n\n            var grainKey = GrainIdKeyExtensions.CreateIntegerKey(primaryKey, keyExtension);\n            return (TGrainInterface)GetGrain(typeof(TGrainInterface), grainKey, grainClassNamePrefix: grainClassNamePrefix);\n        }\n\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj)\n            where TGrainObserverInterface : IGrainObserver\n        {\n            return this.CreateObjectReference<TGrainObserverInterface>((IAddressable)obj);\n        }\n\n        /// <inheritdoc />\n        public void DeleteObjectReference<TGrainObserverInterface>(\n            IGrainObserver obj) where TGrainObserverInterface : IGrainObserver\n        {\n            this.runtimeClient.DeleteObjectReference(obj);\n        }\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IAddressable obj)\n                where TGrainObserverInterface : IAddressable\n        {\n            return (TGrainObserverInterface)this.CreateObjectReference(typeof(TGrainObserverInterface), obj);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface Cast<TGrainInterface>(IAddressable grain)\n        {\n            var interfaceType = typeof(TGrainInterface);\n            return (TGrainInterface)this.Cast(grain, interfaceType);\n        }\n\n        /// <inheritdoc />\n        public object Cast(IAddressable grain, Type interfaceType) => this.GrainReferenceRuntime.Cast(grain, interfaceType);\n\n        public TGrainInterface GetSystemTarget<TGrainInterface>(GrainType grainType, SiloAddress destination)\n            where TGrainInterface : ISystemTarget\n        {\n            var grainId = SystemTargetGrainId.Create(grainType, destination);\n            return this.GetSystemTarget<TGrainInterface>(grainId.GrainId);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetSystemTarget<TGrainInterface>(GrainId grainId)\n            where TGrainInterface : ISystemTarget\n        {\n            ISystemTarget reference;\n            ValueTuple<GrainId, Type> key = ValueTuple.Create(grainId, typeof(TGrainInterface));\n\n            lock (this.typedSystemTargetReferenceCache)\n            {\n                if (this.typedSystemTargetReferenceCache.TryGetValue(key, out reference))\n                {\n                    return (TGrainInterface)reference;\n                }\n\n                reference = this.GetGrain<TGrainInterface>(grainId);\n                this.typedSystemTargetReferenceCache[key] = reference;\n                return (TGrainInterface)reference;\n            }\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(GrainId grainId) where TGrainInterface : IAddressable\n        {\n            return (TGrainInterface)this.CreateGrainReference(typeof(TGrainInterface), grainId);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(GrainId grainId) => this.referenceActivator.CreateReference(grainId, default);\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid key)\n        {\n            var grainKey = GrainIdKeyExtensions.CreateGuidKey(key);\n            return (IGrain)GetGrain(grainInterfaceType, grainKey, grainClassNamePrefix: null);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long key)\n        {\n            var grainKey = GrainIdKeyExtensions.CreateIntegerKey(key);\n            return (IGrain)GetGrain(grainInterfaceType, grainKey, grainClassNamePrefix: null);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, string key)\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(key);\n            var grainKey = IdSpan.Create(key);\n            return (IGrain)GetGrain(grainInterfaceType, grainKey, grainClassNamePrefix: null);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid key, string keyExtension)\n        {\n            var grainKey = GrainIdKeyExtensions.CreateGuidKey(key, keyExtension);\n            return (IGrain)GetGrain(grainInterfaceType, grainKey, grainClassNamePrefix: null);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long key, string keyExtension)\n        {\n            var grainKey = GrainIdKeyExtensions.CreateIntegerKey(key, keyExtension);\n            return (IGrain)GetGrain(grainInterfaceType, grainKey, grainClassNamePrefix: null);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(GrainId grainId, GrainInterfaceType interfaceType)\n        {\n            return this.referenceActivator.CreateReference(grainId, interfaceType);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey) => GetGrain(interfaceType, grainKey, null);\n\n        /// <summary>\n        /// Gets a grain reference which implements the specified grain interface type and has the specified grain key, without specifying the grain type directly.\n        /// </summary>\n        /// <remarks>\n        /// This method infers the most appropriate <see cref=\"GrainId.Type\"/> value based on the <paramref name=\"interfaceType\"/> argument and optional <paramref name=\"grainClassNamePrefix\"/> argument.\n        /// The <see cref=\"GrainInterfaceTypeToGrainTypeResolver\"/> type is responsible for determining the most appropriate grain type.\n        /// </remarks>\n        /// <param name=\"interfaceType\">The interface type which the returned grain reference will implement.</param>\n        /// <param name=\"grainKey\">The <see cref=\"GrainId.Key\"/> portion of the grain id.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional grain class name prefix.</param>\n        /// <returns>A grain reference which implements the provided interface.</returns>\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix = null)\n        {\n            ArgumentNullException.ThrowIfNull(interfaceType);\n\n            var grainInterfaceType = this.interfaceTypeResolver.GetGrainInterfaceType(interfaceType);\n\n            GrainType grainType;\n            if (!string.IsNullOrWhiteSpace(grainClassNamePrefix))\n            {\n                grainType = this.interfaceTypeToGrainTypeResolver.GetGrainType(grainInterfaceType, grainClassNamePrefix);\n            }\n            else\n            {\n                grainType = this.interfaceTypeToGrainTypeResolver.GetGrainType(grainInterfaceType);\n            }\n\n            var grainId = GrainId.Create(grainType, grainKey);\n            var grain = this.referenceActivator.CreateReference(grainId, grainInterfaceType);\n            return grain;\n        }\n\n        /// <summary>\n        /// Creates a grain reference.\n        /// </summary>\n        /// <param name=\"interfaceType\">The interface type which the reference must implement..</param>\n        /// <param name=\"grainId\">The grain id which the reference will target.</param>\n        /// <returns>A grain reference.</returns>\n        private object CreateGrainReference(Type interfaceType, GrainId grainId)\n        {\n            var grainInterfaceType = this.interfaceTypeResolver.GetGrainInterfaceType(interfaceType);\n            return this.referenceActivator.CreateReference(grainId, grainInterfaceType);\n        }\n\n        /// <summary>\n        /// Creates an object reference which points to the provided object.\n        /// </summary>\n        /// <param name=\"interfaceType\">The interface type which the reference must implement..</param>\n        /// <param name=\"obj\">The addressable object implementation.</param>\n        /// <returns>An object reference.</returns>\n        private object CreateObjectReference(Type interfaceType, IAddressable obj)\n        {\n            if (!interfaceType.IsInterface)\n            {\n                throw new ArgumentException(\n                    $\"The provided type parameter must be an interface. '{interfaceType.FullName}' is not an interface.\");\n            }\n\n            if (!interfaceType.IsInstanceOfType(obj))\n            {\n                throw new ArgumentException($\"The provided object must implement '{interfaceType.FullName}'.\", nameof(obj));\n            }\n\n            return this.Cast(this.runtimeClient.CreateObjectReference(obj), interfaceType);\n        }\n\n        /// <summary>\n        /// Validates the provided grain key extension.\n        /// </summary>\n        /// <param name=\"keyExt\">The grain key extension.</param>\n        /// <exception cref=\"ArgumentNullException\">The key is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\">The key is empty or contains only whitespace.</exception>\n        private static void ValidateGrainKeyExtension(string keyExt)\n        {\n            if (!string.IsNullOrWhiteSpace(keyExt)) return;\n\n            if (null == keyExt)\n            {\n                throw new ArgumentNullException(nameof(keyExt)); \n            }\n            \n            throw new ArgumentException(\"Key extension is empty or white space.\", nameof(keyExt));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing Orleans.Utilities;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Associates <see cref=\"GrainInterfaceType\"/>s with a compatible <see cref=\"GrainType\"/>.\n    /// </summary>\n    /// <remarks>\n    /// This is primarily intended for end-users calling <see cref=\"IGrainFactory\"/> methods without needing to be overly explicit.\n    /// </remarks>\n    public class GrainInterfaceTypeToGrainTypeResolver\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly ConcurrentDictionary<GrainInterfaceType, GrainType> _genericMapping = new ConcurrentDictionary<GrainInterfaceType, GrainType>();\n        private readonly IClusterManifestProvider _clusterManifestProvider;\n        private Cache _cache;\n\n        /// <summary>\n        /// Creates a new instance of the <see cref=\"GrainInterfaceTypeToGrainTypeResolver\"/> class.\n        /// </summary>\n        /// <param name=\"clusterManifestProvider\">The cluster manifest provider.</param>\n        public GrainInterfaceTypeToGrainTypeResolver(IClusterManifestProvider clusterManifestProvider)\n        {\n            _clusterManifestProvider = clusterManifestProvider;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"GrainType\"/> which supports the provided <see cref=\"GrainInterfaceType\"/> and which has an implementing type name beginning with the provided prefix string.\n        /// </summary>\n        public GrainType GetGrainType(GrainInterfaceType interfaceType, string prefix)\n        {\n            if (string.IsNullOrWhiteSpace(prefix))\n            {\n                return GetGrainType(interfaceType);\n            }\n\n            GrainType result = default;\n\n            GrainInterfaceType lookupType;\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var genericInterface))\n            {\n                lookupType = genericInterface.GetGenericGrainType().Value;\n            }\n            else\n            {\n                lookupType = interfaceType;\n            }\n\n            var cache = GetCache();\n            if (cache.Map.TryGetValue(lookupType, out var entry))\n            {\n                var hasCandidate = false;\n                foreach (var impl in entry.Implementations)\n                {\n                    if (impl.Prefix.StartsWith(prefix, StringComparison.Ordinal))\n                    {\n                        if (impl.Prefix.Length == prefix.Length)\n                        {\n                            // Exact matches take precedence\n                            result = impl.GrainType;\n                            break;\n                        }\n\n                        if (hasCandidate)\n                        {\n                            var candidates = string.Join(\", \", entry.Implementations.Select(i => $\"{i.GrainType} ({i.Prefix})\"));\n                            throw new ArgumentException($\"Unable to identify a single appropriate grain type for interface {interfaceType} with implementation prefix \\\"{prefix}\\\". Candidates: {candidates}\");\n                        }\n\n                        result = impl.GrainType;\n                        hasCandidate = true;\n                    }\n                }\n            }\n\n            if (result.IsDefault)\n            {\n                throw new ArgumentException($\"Could not find an implementation matching prefix \\\"{prefix}\\\" for interface {interfaceType}\");\n            }\n\n            if (GenericGrainType.TryParse(result, out var genericGrainType) && !genericGrainType.IsConstructed)\n            {\n                result = genericGrainType.GetConstructed(genericInterface);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"GrainType\"/> which implements the provided <see cref=\"GrainInterfaceType\"/>.\n        /// </summary>\n        public GrainType GetGrainType(GrainInterfaceType interfaceType)\n        {\n            if (!TryGetGrainType(interfaceType, out var result))\n            {\n                throw new ArgumentException($\"Could not find an implementation for interface {interfaceType}\");\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Resolves a <see cref=\"GrainType\"/> which implements the provided <see cref=\"GrainInterfaceType\"/>, returning <see langword=\"true\"/> if an implementation was found; otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if an implementation was found; otherwise <see langword=\"false\"/>.</returns>\n        public bool TryGetGrainType(GrainInterfaceType interfaceType, out GrainType result)\n        {\n            result = default;\n            var cache = GetCache();\n            if (cache.Map.TryGetValue(interfaceType, out var entry))\n            {\n                if (!entry.PrimaryImplementation.IsDefault)\n                {\n                    result = entry.PrimaryImplementation;\n                }\n                else if (entry.Implementations.Count == 1)\n                {\n                    result = entry.Implementations[0].GrainType;\n                }\n                else if (entry.Implementations.Count > 1)\n                {\n                    var candidates = string.Join(\", \", entry.Implementations.Select(i => $\"{i.GrainType} ({i.Prefix})\"));\n                    throw new ArgumentException($\"Unable to identify a single appropriate grain type for interface {interfaceType}. Candidates: {candidates}\");\n                }\n                else\n                {\n                    // No implementations\n                }\n            }\n            else if (_genericMapping.TryGetValue(interfaceType, out result))\n            {\n            }\n            else if (GenericGrainInterfaceType.TryParse(interfaceType, out var genericInterface) && genericInterface.IsConstructed)\n            {\n                var unconstructedInterface = genericInterface.GetGenericGrainType();\n                if (TryGetGrainType(unconstructedInterface.Value, out var unconstructed))\n                {\n                    if (GenericGrainType.TryParse(unconstructed, out var genericGrainType))\n                    {\n                        if (genericGrainType.IsConstructed)\n                        {\n                            result = genericGrainType.GrainType;\n                        }\n                        else\n                        {\n                            result = genericGrainType.GetConstructed(genericInterface);\n                        }\n                    }\n                    else\n                    {\n                        result = unconstructed;\n                    }\n                }\n\n                _genericMapping[interfaceType] = result;\n            }\n\n            return !result.IsDefault;\n        }\n\n        /// <summary>\n        /// Returns the cache, rebuilding it if it is out of date.\n        /// </summary>\n        /// <returns>The cache.</returns>\n        private Cache GetCache()\n        {\n            if (_cache is Cache cache && cache.Version == _clusterManifestProvider.Current.Version)\n            {\n                return cache;\n            }\n\n            lock (_lockObj)\n            {\n                var manifest = _clusterManifestProvider.Current;\n                cache = _cache;\n                if (cache is not null && cache.Version == manifest.Version)\n                {\n                    return cache;\n                }\n\n                return _cache = BuildCache(manifest);\n            }\n        }\n\n        /// <summary>\n        /// Builds a cached resolution mapping.\n        /// </summary>\n        /// <param name=\"clusterManifest\">The current cluster manifest.</param>\n        /// <returns>The cache.</returns>\n        private static Cache BuildCache(ClusterManifest clusterManifest)\n        {\n            var result = new Dictionary<GrainInterfaceType, CacheEntry>();\n\n            foreach (var manifest in clusterManifest.AllGrainManifests)\n            {\n                foreach (var grainType in manifest.Grains)\n                {\n                    var id = grainType.Key;\n                    grainType.Value.Properties.TryGetValue(WellKnownGrainTypeProperties.TypeName, out var typeName);\n                    grainType.Value.Properties.TryGetValue(WellKnownGrainTypeProperties.FullTypeName, out var fullTypeName);\n                    foreach (var property in grainType.Value.Properties)\n                    {\n                        if (!property.Key.StartsWith(WellKnownGrainTypeProperties.ImplementedInterfacePrefix, StringComparison.Ordinal)) continue;\n                        var implemented = GrainInterfaceType.Create(property.Value);\n                        string interfaceTypeName;\n                        if (manifest.Interfaces.TryGetValue(implemented, out var interfaceProperties))\n                        {\n                            interfaceProperties.Properties.TryGetValue(WellKnownGrainInterfaceProperties.TypeName, out interfaceTypeName);\n                        }\n                        else\n                        {\n                            interfaceTypeName = null;\n                        }\n\n                        // Try to work out the best primary implementation\n                        result.TryGetValue(implemented, out var entry);\n\n                        var implementations = entry.Implementations ?? new List<(string Prefix, GrainType GrainType)>();\n                        if (!implementations.Contains((fullTypeName, id))) implementations.Add((fullTypeName, id));\n\n                        GrainType primaryImplementation;\n                        if (!entry.PrimaryImplementation.IsDefault)\n                        {\n                            primaryImplementation = entry.PrimaryImplementation;\n                        }\n                        else if (interfaceProperties?.Properties is { } props && props.TryGetValue(WellKnownGrainInterfaceProperties.DefaultGrainType, out var defaultTypeString))\n                        {\n                            // A specified default grain type trumps others.\n                            primaryImplementation = GrainType.Create(defaultTypeString);\n                        }\n                        else if (string.Equals(interfaceTypeName?[1..], typeName, StringComparison.Ordinal))\n                        {\n                            // Otherwise, a substring match on the interface name, dropping the 'I', is used.\n                            primaryImplementation = id;\n                        }\n                        else\n                        {\n                            primaryImplementation = default;\n                        }\n                        result[implemented] = new CacheEntry(primaryImplementation, implementations);\n                    }\n                }\n            }\n\n            return new Cache(clusterManifest.Version, result);\n        }\n\n        /// <summary>\n        /// Contains a mapping from grain interface type to the implementations of that interface.\n        /// </summary>\n        private class Cache\n        {\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"Cache\"/> class.\n            /// </summary>\n            /// <param name=\"version\">The cluster manifest version which this instance corresponds to.</param>\n            /// <param name=\"map\">The interface map.</param>\n            public Cache(MajorMinorVersion version, Dictionary<GrainInterfaceType, CacheEntry> map)\n            {\n                this.Version = version;\n                this.Map = map;\n            }\n\n            /// <summary>\n            /// Gets the cluster manifest version which this cache corresponds to.\n            /// </summary>\n            public MajorMinorVersion Version { get; }\n\n            /// <summary>\n            /// Gets the mapping from grain interface type to implementations.\n            /// </summary>\n            public Dictionary<GrainInterfaceType, CacheEntry> Map { get; }\n        }\n\n        /// <summary>\n        /// Represents the implementation <see cref=\"GrainType\"/> values for a grain interface type.\n        /// </summary>\n        private readonly struct CacheEntry\n        {\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"CacheEntry\"/> struct.\n            /// </summary>\n            /// <param name=\"primaryImplementation\">The primary implementation type.</param>\n            /// <param name=\"implementations\">The set of other implementations along with their grain type prefixes.</param>\n            public CacheEntry(GrainType primaryImplementation, List<(string Prefix, GrainType GrainType)> implementations)\n            {\n                this.PrimaryImplementation = primaryImplementation;\n                this.Implementations = implementations;\n            }\n\n            /// <summary>\n            /// Gets the primary implementation type.\n            /// </summary>\n            public GrainType PrimaryImplementation { get; }\n\n            /// <summary>\n            /// Gets the collection of implementation types with their class name prefixes.\n            /// </summary>\n            public List<(string Prefix, GrainType GrainType)> Implementations { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/GrainMethodInvoker.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Runtime.ExceptionServices;\nusing System.Threading.Tasks;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Invokes a request on a grain.\n    /// </summary>\n    internal sealed class GrainMethodInvoker : IIncomingGrainCallContext\n    {\n        private readonly Message message;\n        private readonly IInvokable request;\n        private readonly List<IIncomingGrainCallFilter> filters;\n        private readonly InterfaceToImplementationMappingCache interfaceToImplementationMapping;\n        private readonly DeepCopier<Response> responseCopier;\n        private readonly IGrainContext grainContext;\n        private int stage;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainMethodInvoker\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"grainContext\">The grain.</param>\n        /// <param name=\"request\">The request.</param>\n        /// <param name=\"filters\">The invocation interceptors.</param>\n        /// <param name=\"interfaceToImplementationMapping\">The implementation map.</param>\n        /// <param name=\"responseCopier\">The response copier.</param>\n        public GrainMethodInvoker(\n            Message message,\n            IGrainContext grainContext,\n            IInvokable request,\n            List<IIncomingGrainCallFilter> filters,\n            InterfaceToImplementationMappingCache interfaceToImplementationMapping,\n            DeepCopier<Response> responseCopier)\n        {\n            this.message = message;\n            this.request = request;\n            this.grainContext = grainContext;\n            this.filters = filters;\n            this.interfaceToImplementationMapping = interfaceToImplementationMapping;\n            this.responseCopier = responseCopier;\n        }\n\n        public IInvokable Request => request;\n\n        public object Grain => grainContext.GrainInstance;\n\n        public MethodInfo InterfaceMethod => request.GetMethod();\n\n        public MethodInfo ImplementationMethod => GetMethodEntry().ImplementationMethod;\n\n        public object Result\n        {\n            get => Response switch\n            {\n                { Exception: null } response => response.Result,\n                _ => null\n            };\n            set => Response = Response.FromResult(value);\n        }\n\n        public Response Response { get; set; }\n\n        public GrainId? SourceId => message.SendingGrain is { IsDefault: false } source ? source : null;\n\n        public IGrainContext TargetContext => grainContext;\n\n        public GrainId TargetId => grainContext.GrainId;\n\n        public GrainInterfaceType InterfaceType => message.InterfaceType;\n\n        public string InterfaceName => request.GetInterfaceName();\n\n        public string MethodName => request.GetMethodName();\n\n        public async Task Invoke()\n        {\n            try\n            {\n                // Execute each stage in the pipeline. Each successive call to this method will invoke the next stage.\n                // Stages which are not implemented (eg, because the user has not specified an interceptor) are skipped.\n                var numFilters = filters.Count;\n                if (stage < numFilters)\n                {\n                    // Call each of the specified interceptors.\n                    var systemWideFilter = this.filters[stage];\n                    stage++;\n                    await systemWideFilter.Invoke(this);\n\n                    // If Response is null some filter did not continue the call chain\n                    if (this.Response is null)\n                    {\n                        ThrowBrokenCallFilterChain(systemWideFilter.GetType().Name);\n                    }\n\n                    return;\n                }\n\n                if (stage == numFilters)\n                {\n                    stage++;\n\n                    // Grain-level invoker, if present.\n                    if (this.Grain is IIncomingGrainCallFilter grainClassLevelFilter)\n                    {\n                        await grainClassLevelFilter.Invoke(this);\n\n                        // If Response is null some filter did not continue the call chain\n                        if (this.Response is null)\n                        {\n                            ThrowBrokenCallFilterChain(this.Grain.GetType().Name);\n                        }\n                        return;\n                    }\n                }\n\n                if (stage == numFilters + 1)\n                {\n                    // Finally call the root-level invoker.\n                    stage++;\n                    this.Response = await request.Invoke();\n\n                    // Propagate exceptions to other filters.\n                    if (this.Response.Exception is { } exception)\n                    {\n                        ExceptionDispatchInfo.Capture(exception).Throw();\n                    }\n\n                    this.Response = this.responseCopier.Copy(this.Response);\n\n                    return;\n                }\n            }\n            finally\n            {\n                stage--;\n            }\n\n            // If this method has been called more than the expected number of times, that is invalid.\n            ThrowInvalidCall();\n        }\n\n        private static void ThrowInvalidCall()\n        {\n            throw new InvalidOperationException(\n                $\"{nameof(GrainMethodInvoker)}.{nameof(Invoke)}() received an invalid call.\");\n        }\n\n        private static void ThrowBrokenCallFilterChain(string filterName)\n        {\n            throw new InvalidOperationException($\"{nameof(GrainMethodInvoker)}.{nameof(Invoke)}() invoked a broken filter: {filterName}.\");\n        }\n\n\n        private (MethodInfo ImplementationMethod, MethodInfo InterfaceMethod) GetMethodEntry()\n        {\n            var interfaceType = this.request.GetInterfaceType();\n            var implementationType = this.request.GetTarget().GetType();\n\n            // Get or create the implementation map for this object.\n            var implementationMap = interfaceToImplementationMapping.GetOrCreate(\n                implementationType,\n                interfaceType);\n\n            // Get the method info for the method being invoked.\n            var method = request.GetMethod();\n            if (method.IsConstructedGenericMethod)\n            {\n                if (implementationMap.TryGetValue(method.GetGenericMethodDefinition(), out var entry))\n                {\n                    return entry.GetConstructedGenericMethod(method);\n                }\n            }\n            else if (implementationMap.TryGetValue(method, out var entry))\n            {\n                return (entry.ImplementationMethod, entry.InterfaceMethod);\n            }\n\n            Debug.Assert(false, \"Method entry not found\");\n            return default;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Core/IClientBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Builder for configuring an Orleans client.\n    /// </summary>\n    public interface IClientBuilder\n    {\n        /// <summary>\n        /// Gets the services collection.\n        /// </summary>\n        IServiceCollection Services { get; }\n\n        /// <summary>\n        /// Gets the configuration.\n        /// </summary>\n        IConfiguration Configuration { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IClientConnectionRetryFilter.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Filter used to determine if cluster connection should be retried.\n    /// </summary>\n    public interface IClientConnectionRetryFilter\n    {\n        /// <summary>\n        /// Returns a value indicating whether connection to an Orleans cluster should be re-attempted.\n        /// </summary>\n        /// <param name=\"exception\">The exception thrown from the last connection attempt.</param>\n        /// <param name=\"cancellationToken\">The cancellation token used to notify when connection has been aborted externally.</param>\n        /// <returns><see langword=\"true\"/> if connection should be re-attempted, <see langword=\"false\"/> if attempts to connect to the cluster should be aborted.</returns>\n        Task<bool> ShouldRetryConnectionAttempt(Exception exception, CancellationToken cancellationToken);\n    }\n\n    internal sealed class LinearBackoffClientConnectionRetryFilter : IClientConnectionRetryFilter\n    {\n        private int _retryCount = 0;\n\n        private const int MaxRetry = 5;\n        private const int Delay = 1_500;\n\n        public async Task<bool> ShouldRetryConnectionAttempt(\n            Exception exception,\n            CancellationToken cancellationToken)\n        {\n            if (_retryCount >= MaxRetry)\n            {\n                return false;\n            }\n\n            if (!cancellationToken.IsCancellationRequested && exception is SiloUnavailableException)\n            {\n                await Task.Delay(++_retryCount * Delay, cancellationToken);\n                return true;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IClusterClient.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Client interface for interacting with an Orleans cluster.\n    /// </summary>\n    public interface IClusterClient : IGrainFactory\n    {\n        /// <summary>\n        /// Gets the service provider used by this client.\n        /// </summary>\n        IServiceProvider ServiceProvider { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IClusterConnectionStatusListener.cs",
    "content": "namespace Orleans\n{\n    /// <summary>\n    /// Interface for notifying observers that connection to the cluster has been lost.\n    /// </summary>\n    internal interface IClusterConnectionStatusListener\n    {\n        /// <summary>\n        /// Notifies this client that the number of connected gateways has changed\n        /// </summary>\n        /// <param name=\"currentNumberOfGateways\">\n        /// The current number of gateways.\n        /// </param>\n        /// <param name=\"previousNumberOfGateways\">\n        /// The previous number of gateways.\n        /// </param>\n        void NotifyGatewayCountChanged(int currentNumberOfGateways, int previousNumberOfGateways);\n\n        /// <summary>\n        /// Notifies this client that the connection to the cluster has been lost.\n        /// </summary>\n        void NotifyClusterConnectionLost();\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IClusterConnectionStatusObserver.cs",
    "content": "namespace Orleans;\n\n/// <summary>\n/// Interface that receives notifications about the status of the cluster connection.\n/// </summary>\npublic interface IClusterConnectionStatusObserver\n{\n    /// <summary>\n    /// Notifies this observer that the number of connected gateways has changed.\n    /// </summary>\n    /// <param name=\"currentNumberOfGateways\">\n    /// The current number of gateways.\n    /// </param>\n    /// <param name=\"previousNumberOfGateways\">\n    /// The previous number of gateways.\n    /// </param>\n    /// <param name=\"connectionRecovered\">Indicates whether a loss of connectivity has been resolved.</param>\n    void NotifyGatewayCountChanged(int currentNumberOfGateways, int previousNumberOfGateways, bool connectionRecovered);\n\n    /// <summary>\n    /// Notifies this observer that the connection to the cluster has been lost.\n    /// </summary>\n    void NotifyClusterConnectionLost();\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IInternalClusterClient.cs",
    "content": "namespace Orleans\n{\n    /// <summary>\n    /// The internal-facing client interface.\n    /// </summary>\n    internal interface IInternalClusterClient : IClusterClient, IInternalGrainFactory\n    {\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/IInternalGrainFactory.cs",
    "content": "using System;\n\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// The internal grain factory interface.\n    /// </summary>\n    internal interface IInternalGrainFactory : IGrainFactory\n    {\n        /// <summary>\n        /// Creates a reference to the provided object.\n        /// </summary>\n        /// <typeparam name=\"TGrainObserverInterface\">The interface which interface.</typeparam>\n        /// <param name=\"obj\">The object.</param>\n        /// <returns>A reference to the provided object.</returns>\n        TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IAddressable obj)\n            where TGrainObserverInterface : IAddressable;\n\n        /// <summary>\n        /// Gets a reference to the specified system target.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The system target interface.</typeparam>\n        /// <param name=\"grainType\">The type of the target.</param>\n        /// <param name=\"destination\">The destination silo.</param>\n        /// <returns>A reference to the specified system target.</returns>\n        TGrainInterface GetSystemTarget<TGrainInterface>(GrainType grainType, SiloAddress destination)\n            where TGrainInterface : ISystemTarget;\n\n        /// <summary>\n        /// Gets a reference to the specified system target.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The system target interface.</typeparam>\n        /// <param name=\"grainId\">The id of the target.</param>\n        /// <returns>A reference to the specified system target.</returns>\n        TGrainInterface GetSystemTarget<TGrainInterface>(GrainId grainId) where TGrainInterface : ISystemTarget;\n\n        /// <summary>\n        /// Casts the provided <paramref name=\"grain\"/> to the specified interface\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The target grain interface type.</typeparam>\n        /// <param name=\"grain\">The grain reference being cast.</param>\n        /// <returns>\n        /// A reference to <paramref name=\"grain\"/> which implements <typeparamref name=\"TGrainInterface\"/>.\n        /// </returns>\n        TGrainInterface Cast<TGrainInterface>(IAddressable grain);\n\n        /// <summary>\n        /// Casts the provided <paramref name=\"grain\"/> to the provided <paramref name=\"interfaceType\"/>.\n        /// </summary>\n        /// <param name=\"grain\">The grain.</param>\n        /// <param name=\"interfaceType\">The resulting interface type.</param>\n        /// <returns>A reference to <paramref name=\"grain\"/> which implements <paramref name=\"interfaceType\"/>.</returns>\n        object Cast(IAddressable grain, Type interfaceType);\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/InterfaceToImplementationMappingCache.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\nusing Orleans.CodeGeneration;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Maintains a map between grain classes and corresponding interface-implementation mappings.\n    /// </summary>\n    internal class InterfaceToImplementationMappingCache\n    {\n        /// <summary>\n        /// Maps a grain interface method's <see cref=\"MethodInfo\"/> to an implementation's <see cref=\"MethodInfo\"/>.\n        /// </summary>\n        public readonly struct Entry\n        {\n            public Entry(MethodInfo implementationMethod, MethodInfo interfaceMethod)\n            {\n                Debug.Assert(implementationMethod is not null);\n                Debug.Assert(interfaceMethod is not null);\n                ImplementationMethod = implementationMethod;\n                InterfaceMethod = interfaceMethod;\n            }\n\n            /// <summary>\n            /// Gets the grain implementation <see cref=\"MethodInfo\"/>.\n            /// </summary>\n            public MethodInfo ImplementationMethod { get; }\n\n            /// <summary>\n            /// Gets the grain interface <see cref=\"MethodInfo\"/>.\n            /// </summary>\n            public MethodInfo InterfaceMethod { get; }\n\n            public (MethodInfo ImplementationMethod, MethodInfo InterfaceMethod) GetConstructedGenericMethod(MethodInfo method)\n            {\n                return ConstructedGenericMethods.GetOrAdd(method.GetGenericArguments(), (key, state) =>\n                {\n                    var (entry, method) = state;\n                    var genericArgs = key;\n                    var constructedImplementationMethod = entry.ImplementationMethod.MakeGenericMethod(genericArgs);\n                    var constructedInterfaceMethod = entry.InterfaceMethod.MakeGenericMethod(genericArgs);\n                    return (constructedImplementationMethod, constructedInterfaceMethod);\n                }, (this, method));\n            }\n\n            /// <summary>\n            /// Gets the constructed generic instances of this method.\n            /// </summary>\n            public ConcurrentDictionary<Type[], (MethodInfo ImplementationMethod, MethodInfo InterfaceMethod)> ConstructedGenericMethods { get; } = new(TypeArrayComparer.Instance);\n\n            private sealed class TypeArrayComparer : IEqualityComparer<Type[]>\n            {\n                internal static readonly TypeArrayComparer Instance = new();\n\n                public bool Equals(Type[] x, Type[] y) => ReferenceEquals(x, y) || x is null && y is null || x.Length != y.Length || x.AsSpan().SequenceEqual(y.AsSpan());\n\n                public int GetHashCode([DisallowNull] Type[] obj)\n                {\n                    HashCode result = new();\n                    result.Add(obj.Length);\n                    foreach (var value in obj)\n                    {\n                        result.Add(value);\n                    }\n\n                    return result.ToHashCode();\n                }\n            }\n        }\n\n        /// <summary>\n        /// The map from implementation types to interface types to map of method to method infos.\n        /// </summary>\n        private readonly ConcurrentDictionary<Type, Dictionary<Type, Dictionary<MethodInfo, Entry>>> mappings = new();\n\n        /// <summary>\n        /// Returns a mapping from method id to method info for the provided implementation and interface types.\n        /// </summary>\n        /// <param name=\"implementationType\">The implementation type.</param>\n        /// <param name=\"interfaceType\">The interface type.</param>\n        /// <returns>\n        /// A mapping from method id to method info.\n        /// </returns>\n        public Dictionary<MethodInfo, Entry> GetOrCreate(Type implementationType, Type interfaceType)\n        {\n            // Get or create the mapping between interfaceId and invoker for the provided type.\n            if (!this.mappings.TryGetValue(implementationType, out var invokerMap))\n            {\n                // Generate an the invoker mapping using the provided invoker.\n                invokerMap = mappings.GetOrAdd(implementationType, CreateInterfaceToImplementationMap(implementationType));\n            }\n\n            // Attempt to get the invoker for the provided interfaceId.\n            if (!invokerMap.TryGetValue(interfaceType, out var interfaceToImplementationMap))\n            {\n                throw new InvalidOperationException($\"Type {implementationType} does not implement interface {interfaceType}\");\n            }\n\n            return interfaceToImplementationMap;\n        }\n\n        /// <summary>\n        /// Maps the interfaces of the provided <paramref name=\"implementationType\"/>.\n        /// </summary>\n        /// <param name=\"implementationType\">The implementation type.</param>\n        /// <returns>The mapped interface.</returns>\n        private static Dictionary<Type, Dictionary<MethodInfo, Entry>> CreateInterfaceToImplementationMap(Type implementationType)\n        {\n            var interfaces = implementationType.GetInterfaces();\n\n            // Create an invoker for every interface on the provided type.\n            var result = new Dictionary<Type, Dictionary<MethodInfo, Entry>>(interfaces.Length);\n            foreach (var iface in interfaces)\n            {\n                var methods = GrainInterfaceUtils.GetMethods(iface);\n\n                // Map every method on this interface from the definition interface onto the implementation class.\n                var methodMap = new Dictionary<MethodInfo, Entry>(methods.Length);\n\n                var mapping = default(InterfaceMapping);\n                for (var i = 0; i < methods.Length; i++)\n                {\n                    var method = methods[i];\n\n                    // If this method is not from the expected interface (eg, because it's from a parent interface), then\n                    // get the mapping for the interface which it does belong to.\n                    if (mapping.InterfaceType != method.DeclaringType)\n                    {\n                        mapping = implementationType.GetInterfaceMap(method.DeclaringType);\n                    }\n\n                    // Find the index of the interface method and then get the implementation method at that position.\n                    for (var k = 0; k < mapping.InterfaceMethods.Length; k++)\n                    {\n                        if (mapping.InterfaceMethods[k] != method) continue;\n                        Debug.Assert(method is not null);\n                        methodMap[method] = new Entry(mapping.TargetMethods[k], method);\n\n                        break;\n                    }\n                }\n\n                // Add the resulting map of methodId -> method to the interface map.\n                result[iface] = methodMap;\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Core/InvalidSchedulingContextException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n\n    /// <summary>\n    /// Signifies that an operation was attempted on an invalid SchedulingContext.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class InvalidSchedulingContextException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidSchedulingContextException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public InvalidSchedulingContextException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidSchedulingContextException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public InvalidSchedulingContextException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidSchedulingContextException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        [Obsolete]\n        private InvalidSchedulingContextException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/ActivityNames.cs",
    "content": "namespace Orleans.Runtime;\n\npublic static class ActivityNames\n{\n    public const string PlaceGrain = \"place grain\";\n    public const string FilterPlacementCandidates = \"filter placement candidates\";\n    public const string ActivateGrain = \"activate grain\";\n    public const string DeactivateGrain = \"deactivate grain\";\n    public const string OnActivate = \"execute OnActivateAsync\";\n    public const string OnDeactivate = \"execute OnDeactivateAsync\";\n    public const string RegisterDirectoryEntry = \"register directory entry\";\n    public const string StorageRead = \"read storage\";\n    public const string StorageWrite = \"write storage\";\n    public const string StorageClear = \"clear storage\";\n    public const string ActivationDehydrate = \"dehydrate activation\";\n    public const string ActivationRehydrate = \"rehydrate activation\";\n    public const string WaitMigration = \"wait migration\";\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/ActivityPropagationGrainCallFilter.cs",
    "content": "using System.Diagnostics;\nusing Orleans.Diagnostics;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// A grain call filter which helps to propagate activity correlation information across a call chain.\n    /// </summary>\n    internal abstract class ActivityPropagationGrainCallFilter\n    {\n        internal const string RpcSystem = \"orleans\";\n        internal const string OrleansNamespacePrefix = \"Orleans\";\n\n        protected static ActivitySource GetActivitySource(IGrainCallContext context)\n        {\n            var interfaceType = context.Request.GetInterfaceType();\n            var interfaceTypeName = interfaceType.Name;\n\n            switch (interfaceTypeName)\n            {\n                // Memory storage uses grains for its implementation\n                case \"IMemoryStorageGrain\":\n                    return ActivitySources.StorageGrainSource;\n\n                // This extension is for explicit migrate/deactivate calls\n                case \"IGrainManagementExtension\":\n                // This target is for accepting migration batches\n                case \"IActivationMigrationManagerSystemTarget\":\n                    return ActivitySources.LifecycleGrainSource;\n\n                // These extensions are for async stream subscriptions\n                case \"IAsyncEnumerableGrainExtension\":\n                    return ActivitySources.ApplicationGrainSource;\n\n                default:\n                    return interfaceType.Namespace?.StartsWith(OrleansNamespacePrefix) == true\n                        ? ActivitySources.RuntimeGrainSource\n                        : ActivitySources.ApplicationGrainSource;\n            }\n        }\n\n        protected static void GetRequestContextValue(object carrier, string fieldName, out string fieldValue, out IEnumerable<string> fieldValues)\n        {\n            fieldValues = default;\n            fieldValue = RequestContext.Get(fieldName) as string;\n        }\n\n        protected static async Task Process(IGrainCallContext context, Activity activity)\n        {\n            if (activity is not null)\n            {\n                // rpc attributes from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md\n                activity.SetTag(ActivityTagKeys.RpcSystem, RpcSystem);\n                activity.SetTag(ActivityTagKeys.RpcService, context.InterfaceName);\n                activity.SetTag(ActivityTagKeys.RpcMethod, context.MethodName);\n\n                if (activity.IsAllDataRequested)\n                {\n                    // Custom attributes\n                    activity.SetTag(ActivityTagKeys.RpcOrleansTargetId, context.TargetId.ToString());\n                    if (context.SourceId is GrainId sourceId)\n                    {\n                        activity.SetTag(ActivityTagKeys.RpcOrleansSourceId, sourceId.ToString());\n                    }\n                }\n            }\n\n            try\n            {\n                await context.Invoke();\n            }\n            catch (Exception e)\n            {\n                if (activity is not null && activity.IsAllDataRequested)\n                {\n                    activity.SetStatus(ActivityStatusCode.Error);\n\n                    // exception attributes from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md\n                    activity.SetTag(ActivityTagKeys.ExceptionType, e.GetType().FullName);\n                    activity.SetTag(ActivityTagKeys.ExceptionMessage, e.Message);\n\n                    // Note that \"exception.stacktrace\" is the full exception detail, not just the StackTrace property.\n                    // See https://opentelemetry.io/docs/specs/semconv/attributes-registry/exception/\n                    // and https://github.com/open-telemetry/opentelemetry-specification/pull/697#discussion_r453662519\n                    activity.SetTag(ActivityTagKeys.ExceptionStacktrace, e.ToString());\n                    activity.SetTag(ActivityTagKeys.ExceptionEscaped, true);\n                }\n\n                throw;\n            }\n            finally\n            {\n                activity?.Stop();\n            }\n        }\n    }\n\n    /// <summary>\n    /// Propagates distributed context information to outgoing requests.\n    /// </summary>\n    internal class ActivityPropagationOutgoingGrainCallFilter : ActivityPropagationGrainCallFilter, IOutgoingGrainCallFilter\n    {\n        private readonly DistributedContextPropagator _propagator;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ActivityPropagationOutgoingGrainCallFilter\"/> class.\n        /// </summary>\n        /// <param name=\"propagator\">The context propagator.</param>\n        public ActivityPropagationOutgoingGrainCallFilter(DistributedContextPropagator propagator)\n        {\n            _propagator = propagator;\n        }\n\n        /// <inheritdoc />\n        public Task Invoke(IOutgoingGrainCallContext context)\n        {\n            var source = GetActivitySource(context);\n            var activity = source.StartActivity(context.Request.GetActivityName(), ActivityKind.Client);\n\n            if (activity is null)\n            {\n                return context.Invoke();\n            }\n\n            _propagator.Inject(activity, null, static (carrier, key, value) => RequestContext.Set(key, value));\n            return Process(context, activity);\n        }\n    }\n\n    /// <summary>\n    /// Populates distributed context information from incoming requests.\n    /// </summary>\n    internal class ActivityPropagationIncomingGrainCallFilter : ActivityPropagationGrainCallFilter, IIncomingGrainCallFilter\n    {\n        private readonly DistributedContextPropagator _propagator;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ActivityPropagationIncomingGrainCallFilter\"/> class.\n        /// </summary>\n        /// <param name=\"propagator\">The context propagator.</param>\n        public ActivityPropagationIncomingGrainCallFilter(DistributedContextPropagator propagator)\n        {\n            _propagator = propagator;\n        }\n\n        /// <inheritdoc />\n        public Task Invoke(IIncomingGrainCallContext context)\n        {\n            Activity activity = default;\n            _propagator.ExtractTraceIdAndState(null, GetRequestContextValue, out var traceParent, out var traceState);\n\n            var source = GetActivitySource(context);\n            if (!string.IsNullOrEmpty(traceParent))\n            {\n                if (ActivityContext.TryParse(traceParent, traceState, isRemote: true, out ActivityContext parentContext))\n                {\n                    // traceParent is a W3CId\n                    activity = source.CreateActivity(context.Request.GetActivityName(), ActivityKind.Server, parentContext);\n                }\n                else\n                {\n                    // Most likely, traceParent uses ActivityIdFormat.Hierarchical\n                    activity = source.CreateActivity(context.Request.GetActivityName(), ActivityKind.Server, traceParent);\n                }\n\n                if (activity is not null)\n                {\n                    if (!string.IsNullOrEmpty(traceState))\n                    {\n                        activity.TraceStateString = traceState;\n                    }\n\n                    var baggage = _propagator.ExtractBaggage(null, GetRequestContextValue);\n\n                    if (baggage is not null)\n                    {\n                        foreach (var baggageItem in baggage)\n                        {\n                            activity.AddBaggage(baggageItem.Key, baggageItem.Value);\n                        }\n                    }\n                }\n            }\n            else\n            {\n                activity = source.CreateActivity(context.Request.GetActivityName(), ActivityKind.Server);\n            }\n\n            if (activity is null)\n            {\n                return context.Invoke();\n            }\n\n            activity.Start();\n            return Process(context, activity);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/EventSourceEvents.cs",
    "content": "using System.Diagnostics.Tracing;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Event source for <see cref=\"CallbackData\"/>.\n    /// </summary>\n    [EventSource(Name = \"Microsoft-Orleans-CallBackData\")]\n    internal sealed class OrleansCallBackDataEvent : EventSource\n    {\n        public static readonly OrleansCallBackDataEvent Log = new OrleansCallBackDataEvent();\n\n        /// <summary>\n        /// Indicates that a request timeout occurred.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        [NonEvent]\n        public void OnTimeout(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.OnTimeout();\n            }\n        }\n\n        /// <summary>\n        /// Indicates that a request timeout occurred.\n        /// </summary>\n        [Event(1, Level = EventLevel.Warning)]\n        private void OnTimeout() => this.WriteEvent(1);\n\n        /// <summary>\n        /// Indicates that a target silo failed.\n        /// </summary>\n        /// <param name=\"message\">A message addressed to the target silo.</param>\n        [NonEvent]\n        public void OnTargetSiloFail(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.OnTargetSiloFail();\n            }\n        }\n\n        /// <summary>\n        /// Indicates that a target silo failed.\n        /// </summary>\n        [Event(2, Level = EventLevel.Warning)]\n        private void OnTargetSiloFail() => this.WriteEvent(2);\n\n        /// <summary>\n        /// Indicates that a request completed.\n        /// </summary>\n        [NonEvent]\n        public void DoCallback(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.DoCallback();\n            }\n        }\n\n        /// <summary>\n        /// Indicates that a request completed.\n        /// </summary>\n        [Event(3, Level = EventLevel.Verbose)]\n        private void DoCallback() => this.WriteEvent(3);\n\n        /// <summary>\n        /// Indicates that a request was canceled.\n        /// </summary>\n        [NonEvent]\n        public void OnCanceled(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.OnCanceled();\n            }\n        }\n\n        /// <summary>\n        /// Indicates that a request was canceled.\n        /// </summary>\n        [Event(4, Level = EventLevel.Verbose)]\n        private void OnCanceled() => this.WriteEvent(4);\n    }\n\n    [EventSource(Name = \"Microsoft-Orleans-OutsideRuntimeClient\")]\n    internal sealed class OrleansOutsideRuntimeClientEvent : EventSource\n    {\n        public static readonly OrleansOutsideRuntimeClientEvent Log = new OrleansOutsideRuntimeClientEvent();\n\n        [NonEvent]\n        public void SendRequest(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.SendRequest();\n            }\n        }\n\n        [Event(1, Level = EventLevel.Verbose)]\n        private void SendRequest() => this.WriteEvent(1);\n\n        [NonEvent]\n        public void ReceiveResponse(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.ReceiveResponse();\n            }\n        }\n\n        [Event(2, Level = EventLevel.Verbose)]\n        private void ReceiveResponse() => this.WriteEvent(2);\n\n        [NonEvent]\n        public void SendResponse(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.SendResponse();\n            }\n        }\n\n        [Event(3, Level = EventLevel.Verbose)]\n        private void SendResponse() => this.WriteEvent(3);\n    }\n\n    [EventSource(Name = \"Microsoft-Orleans-Dispatcher\")]\n    internal sealed class OrleansDispatcherEvent : EventSource\n    {\n        public static readonly OrleansDispatcherEvent Log = new OrleansDispatcherEvent();\n\n        [NonEvent]\n        public void ReceiveMessage(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.ReceiveMessage();\n            }\n        }\n\n        [Event(1, Level = EventLevel.Verbose)]\n        private void ReceiveMessage() => WriteEvent(1);\n    }\n\n    [EventSource(Name = \"Microsoft-Orleans-InsideRuntimeClient\")]\n    internal sealed class OrleansInsideRuntimeClientEvent : EventSource\n    {\n        public static readonly OrleansInsideRuntimeClientEvent Log = new OrleansInsideRuntimeClientEvent();\n\n        [NonEvent]\n        public void SendRequest(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.SendRequest();\n            }\n        }\n\n        [Event(1, Level = EventLevel.Verbose)]\n        private void SendRequest() => WriteEvent(1);\n\n        [NonEvent]\n        public void ReceiveResponse(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.ReceiveResponse();\n            }\n        }\n\n        [Event(2, Level = EventLevel.Verbose)]\n        private void ReceiveResponse() => WriteEvent(2);\n\n        [NonEvent]\n        public void SendResponse(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.SendResponse();\n            }\n        }\n\n        [Event(3, Level = EventLevel.Verbose)]\n        private void SendResponse() => WriteEvent(3);\n    }\n\n    [EventSource(Name = \"Microsoft-Orleans-IncomingMessageAgent\")]\n    internal sealed class OrleansIncomingMessageAgentEvent : EventSource\n    {\n        public static readonly OrleansIncomingMessageAgentEvent Log = new OrleansIncomingMessageAgentEvent();\n\n        [NonEvent]\n        public void ReceiveMessage(Message message)\n        {\n            if (this.IsEnabled())\n            {\n                this.ReceiveMessage();\n            }\n        }\n\n        [Event(1, Level = EventLevel.Verbose)]\n        private void ReceiveMessage() => WriteEvent(1);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/MessagingTrace.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal class MessagingTrace : DiagnosticListener, ILogger\n    {\n        public const string Category = \"Orleans.Messaging\";\n\n        public const string CreateMessageEventName = Category + \".CreateMessage\";\n        public const string SendMessageEventName = Category + \".Outbound.Send\";\n        public const string IncomingMessageAgentReceiveMessageEventName = Category + \".IncomingMessageAgent.Receive\";\n        public const string DispatcherReceiveMessageEventName = Category + \".Dispatcher.Receive\";\n        public const string DropExpiredMessageEventName = Category + \".Drop.Expired\";\n        public const string DropSendingMessageEventName = Category + \".Drop.Sending\";\n        public const string DropBlockedApplicationMessageEventName = Category + \".Drop.Blocked\";\n        public const string EnqueueInboundMessageEventName = Category + \".Inbound.Enqueue\";\n        public const string DequeueInboundMessageEventName = Category + \".Inbound.Dequeue\";\n        public const string ScheduleMessageEventName = Category + \".Schedule\";\n        public const string EnqueueMessageOnActivationEventName = Category + \".Activation.Enqueue\";\n        public const string InvokeMessageEventName = Category + \".Invoke\";\n        public const string RejectSendMessageToDeadSiloEventName = Category + \".Reject.TargetDead\";\n\n        private static readonly Action<ILogger, Message, MessagingInstruments.Phase, Exception> LogDropExpiredMessage\n            = LoggerMessage.Define<Message, MessagingInstruments.Phase>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Messaging_DroppingExpiredMessage, DropExpiredMessageEventName),\n                \"Dropping expired message {Message} at phase {Phase}\");\n\n        private static readonly Action<ILogger, Message, Exception> LogDropBlockedApplicationMessage\n            = LoggerMessage.Define<Message>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Messaging_DroppingBlockedMessage, DropBlockedApplicationMessageEventName),\n                \"Dropping message {Message} since this silo is blocking application messages\");\n\n        private static readonly Action<ILogger, Message, Exception> LogEnqueueInboundMessage\n            = LoggerMessage.Define<Message>(\n                LogLevel.Trace,\n                new EventId((int)ErrorCode.Messaging_Inbound_Enqueue, EnqueueInboundMessageEventName),\n                \"Enqueueing inbound message {Message}\");\n\n        private static readonly Action<ILogger, Message, Exception> LogDequeueInboundMessage\n            = LoggerMessage.Define<Message>(\n                LogLevel.Trace,\n                new EventId((int)ErrorCode.Messaging_Inbound_Dequeue, DequeueInboundMessageEventName),\n                \"Dequeueing inbound message {Message}\");\n\n        private static readonly Action<ILogger, SiloAddress, Message, string, Exception> LogSiloDropSendingMessage\n            = LoggerMessage.Define<SiloAddress, Message, string>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Messaging_OutgoingMS_DroppingMessage, DropSendingMessageEventName),\n                \"Silo {SiloAddress} is dropping message {Message}. Reason: {Reason}\");\n\n        private static readonly Action<ILogger, SiloAddress, SiloAddress, Message, Exception> LogRejectSendMessageToDeadSilo\n            = LoggerMessage.Define<SiloAddress, SiloAddress, Message>(\n                LogLevel.Information,\n                new EventId((int)ErrorCode.MessagingSendingRejection, RejectSendMessageToDeadSiloEventName),\n                  \"Silo {SiloAddress} is rejecting message to known-dead silo {DeadSilo}: {Message}\");\n\n\n        private readonly ILogger log;\n\n        public MessagingTrace(ILoggerFactory loggerFactory) : base(Category)\n        {\n            this.log = loggerFactory.CreateLogger(Category);\n        }\n\n        public void OnSendMessage(Message message)\n        {\n            if (this.IsEnabled(SendMessageEventName))\n            {\n                this.Write(SendMessageEventName, message);\n            }\n        }\n\n        public void OnIncomingMessageAgentReceiveMessage(Message message)\n        {\n            if (this.IsEnabled(IncomingMessageAgentReceiveMessageEventName))\n            {\n                this.Write(IncomingMessageAgentReceiveMessageEventName, message);\n            }\n\n            OrleansIncomingMessageAgentEvent.Log.ReceiveMessage(message);\n            MessagingProcessingInstruments.OnImaMessageReceived(message);\n        }\n\n        public void OnDispatcherReceiveMessage(Message message)\n        {\n            if (this.IsEnabled(DispatcherReceiveMessageEventName))\n            {\n                this.Write(DispatcherReceiveMessageEventName, message);\n            }\n\n            OrleansDispatcherEvent.Log.ReceiveMessage(message);\n            MessagingProcessingInstruments.OnDispatcherMessageReceive(message);\n        }\n\n        internal void OnDropExpiredMessage(Message message, MessagingInstruments.Phase phase)\n        {\n            if (this.IsEnabled(DropExpiredMessageEventName))\n            {\n                this.Write(DropExpiredMessageEventName, new { Message = message, Phase = phase });\n            }\n\n            MessagingInstruments.OnMessageExpired(phase);\n            LogDropExpiredMessage(this, message, phase, null);\n        }\n\n        internal void OnDropBlockedApplicationMessage(Message message)\n        {\n            if (this.IsEnabled(DropBlockedApplicationMessageEventName))\n            {\n                this.Write(DropBlockedApplicationMessageEventName, message);\n            }\n\n            LogDropBlockedApplicationMessage(this, message, null);\n        }\n\n        internal void OnSiloDropSendingMessage(SiloAddress localSiloAddress, Message message, string reason)\n        {\n            MessagingInstruments.OnDroppedSentMessage(message);\n            LogSiloDropSendingMessage(this, localSiloAddress, message, reason, null);\n        }\n\n        public void OnEnqueueInboundMessage(Message message)\n        {\n            if (this.IsEnabled(EnqueueInboundMessageEventName))\n            {\n                this.Write(EnqueueInboundMessageEventName, message);\n            }\n\n            LogEnqueueInboundMessage(this, message, null);\n        }\n\n        public void OnDequeueInboundMessage(Message message)\n        {\n            if (this.IsEnabled(DequeueInboundMessageEventName))\n            {\n                this.Write(DequeueInboundMessageEventName, message);\n            }\n\n            LogDequeueInboundMessage(this, message, null);\n        }\n\n        internal void OnCreateMessage(Message message)\n        {\n            if (this.IsEnabled(CreateMessageEventName))\n            {\n                this.Write(CreateMessageEventName, message);\n            }\n        }\n\n        public void OnScheduleMessage(Message message)\n        {\n            if (this.IsEnabled(ScheduleMessageEventName))\n            {\n                this.Write(ScheduleMessageEventName, message);\n            }\n        }\n\n        public void OnEnqueueMessageOnActivation(Message message, IGrainContext context)\n        {\n            if (this.IsEnabled(EnqueueMessageOnActivationEventName))\n            {\n                this.Write(EnqueueMessageOnActivationEventName, message);\n            }\n\n            MessagingProcessingInstruments.OnImaMessageEnqueued(context);\n        }\n\n        public void OnInvokeMessage(Message message)\n        {\n            if (this.IsEnabled(InvokeMessageEventName))\n            {\n                this.Write(InvokeMessageEventName, message);\n            }\n        }\n\n        public void OnRejectSendMessageToDeadSilo(SiloAddress localSilo, Message message)\n        {\n            MessagingInstruments.OnFailedSentMessage(message);\n\n            if (this.IsEnabled(RejectSendMessageToDeadSiloEventName))\n            {\n                this.Write(RejectSendMessageToDeadSiloEventName, message);\n            }\n\n            LogRejectSendMessageToDeadSilo(\n                this,\n                localSilo,\n                message.TargetSilo,\n                message,\n                null);\n        }\n\n        internal void OnSendRequest(Message message)\n        {\n            OrleansInsideRuntimeClientEvent.Log.SendRequest(message);\n        }\n\n        public IDisposable BeginScope<TState>(TState state)\n        {\n            return this.log.BeginScope(state);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool IsEnabled(LogLevel logLevel)\n        {\n            return this.log.IsEnabled(logLevel);\n        }\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n        {\n            this.log.Log(logLevel, eventId, state, exception, formatter);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/AggregatorKey.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Runtime;\n\ninternal readonly struct AggregatorKey : IEquatable<AggregatorKey>\n{\n    public AggregatorKey(string instrumentName, KeyValuePair<string, object>[] tags)\n    {\n        InstrumentName = instrumentName;\n        Tags = tags;\n    }\n    public string InstrumentName { get; }\n    public KeyValuePair<string, object>[] Tags { get; }\n\n    public override int GetHashCode() => HashCode.Combine(InstrumentName, Tags);\n    public bool Equals(AggregatorKey other) => InstrumentName == other.InstrumentName && Tags.SequenceEqual(other.Tags);\n\n    public override bool Equals(object obj) => obj is AggregatorKey key && Equals(key);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/CounterAggregator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\ninternal sealed class CounterAggregator\n{\n    private readonly KeyValuePair<string, object>[] _tags;\n    private long _value = 0;\n    public CounterAggregator()\n    {\n        _tags = Array.Empty<KeyValuePair<string, object>>();\n    }\n\n    public CounterAggregator(in TagList tagList)\n    {\n        if (tagList.Name1 == null)\n        {\n            _tags = Array.Empty<KeyValuePair<string, object>>();\n        }\n        else if (tagList.Name2 == null)\n        {\n            _tags = new[] { new KeyValuePair<string, object>(tagList.Name1, tagList.Value1) };\n        }\n        else if (tagList.Name3 == null)\n        {\n            _tags = new[]\n            {\n                new KeyValuePair<string, object>(tagList.Name1, tagList.Value1),\n                new KeyValuePair<string, object>(tagList.Name2, tagList.Value2)\n            };\n        }\n        else if (tagList.Name4 == null)\n        {\n            _tags = new[]\n            {\n                new KeyValuePair<string, object>(tagList.Name1, tagList.Value1),\n                new KeyValuePair<string, object>(tagList.Name2, tagList.Value2),\n                new KeyValuePair<string, object>(tagList.Name3, tagList.Value3)\n            };\n        }\n        else\n        {\n            _tags = new[]\n            {\n                new KeyValuePair<string, object>(tagList.Name1, tagList.Value1),\n                new KeyValuePair<string, object>(tagList.Name2, tagList.Value2),\n                new KeyValuePair<string, object>(tagList.Name3, tagList.Value3),\n                new KeyValuePair<string, object>(tagList.Name4, tagList.Value4)\n            };\n        }\n    }\n\n    public long Value => _value;\n\n    public void Add(long measurement) => Interlocked.Add(ref _value, measurement);\n\n    public Measurement<long> Collect() => new(_value, _tags);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/CounterAggregatorGroup.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal sealed class CounterAggregatorGroup\n{\n    internal ConcurrentDictionary<TagList, CounterAggregator> Aggregators { get; } = new();\n\n    public CounterAggregator FindOrCreate(TagList tagList)\n    {\n        if (Aggregators.TryGetValue(tagList, out var stat))\n        {\n            return stat;\n        }\n        return Aggregators.GetOrAdd(tagList, new CounterAggregator(tagList));\n    }\n\n    public void Add(long measurement, string tagName1, object tagValue1)\n        => FindOrCreate(new(tagName1, tagValue1))\n            .Add(measurement);\n    public void Add(long measurement, string tagName1, object tagValue1, string tagName2, object tagValue2)\n        => FindOrCreate(new(tagName1, tagValue1, tagName2, tagValue2))\n            .Add(measurement);\n    public void Add(long measurement, string tagName1, object tagValue1, string tagName2, object tagValue2, string tagName3, object tagValue3)\n        => FindOrCreate(new(tagName1, tagValue1, tagName2, tagValue2, tagName3, tagValue3))\n            .Add(measurement);\n    public void Add(long measurement, string tagName1, object tagValue1, string tagName2, object tagValue2, string tagName3, object tagValue3, string tagName4, object tagValue4)\n        => FindOrCreate(new(tagName1, tagValue1, tagName2, tagValue2, tagName3, tagValue3, tagName4, tagValue4))\n            .Add(measurement);\n    public void Add(long measurement, TagList tagList)\n        => FindOrCreate(tagList)\n            .Add(measurement);\n\n    public IEnumerable<Measurement<long>> Collect()\n    {\n        foreach (var (_, aggregator) in Aggregators)\n        {\n            if (aggregator.Value != 0)\n            {\n                yield return aggregator.Collect();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/HistogramAggregator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Linq;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\ninternal class HistogramAggregator\n{\n    private readonly KeyValuePair<string, object>[] _tags;\n    private readonly HistogramBucketAggregator[] _buckets;\n    private long _count;\n    private long _sum;\n\n    public HistogramAggregator(long[] buckets, KeyValuePair<string, object>[] tags, Func<long, KeyValuePair<string, object>> getLabel)\n    {\n        if (buckets[^1] != long.MaxValue)\n        {\n            buckets = buckets.Concat(new[] { long.MaxValue }).ToArray();\n        }\n\n        _tags = tags;\n        _buckets = buckets.Select(b => new HistogramBucketAggregator(tags, b, getLabel(b))).ToArray();\n    }\n\n    public void Record(long number)\n    {\n        int i;\n        for (i = 0; i < _buckets.Length; i++)\n        {\n            if (number <= _buckets[i].Bound)\n            {\n                break;\n            }\n        }\n        _buckets[i].Add(1);\n        Interlocked.Increment(ref _count);\n        Interlocked.Add(ref _sum, number);\n    }\n\n    public IEnumerable<Measurement<long>> CollectBuckets()\n    {\n        foreach (var bucket in _buckets)\n        {\n            yield return bucket.Collect();\n        }\n    }\n\n    public Measurement<long> CollectCount() => new(_count, _tags);\n\n    public Measurement<long> CollectSum() => new(_sum, _tags);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/HistogramBucketAggregator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Linq;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\ninternal class HistogramBucketAggregator\n{\n    private long _value = 0;\n    private readonly KeyValuePair<string, object>[] _tags;\n    public long Bound { get; }\n\n    public HistogramBucketAggregator(KeyValuePair<string, object>[] tags, long bound, KeyValuePair<string, object> label)\n    {\n        _tags = tags.Concat(new[] { label }).ToArray();\n        Bound = bound;\n    }\n\n    public ReadOnlySpan<KeyValuePair<string, object>> Tags => _tags;\n\n    public long Value => _value;\n\n    public void Add(long measurement) => Interlocked.Add(ref _value, measurement);\n\n    public Measurement<long> Collect()\n    {\n        return new Measurement<long>(_value, _tags);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Aggregators/TagList.cs",
    "content": "namespace Orleans.Runtime;\n\ninternal record struct TagList(\n    string Name1,\n    object Value1,\n    string Name2 = default,\n    object Value2 = default,\n    string Name3 = default,\n    object Value3 = default,\n    string Name4 = default,\n    object Value4 = default);\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/ApplicationRequestInstruments.cs",
    "content": "using System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal class ApplicationRequestInstruments\n{\n    private readonly Counter<long> _timedOutRequestsCounter;\n    private readonly Counter<long> _canceledRequestsCounter;\n\n    private static readonly long[] AppRequestsLatencyHistogramBuckets = [1, 2, 4, 6, 8, 10, 50, 100, 200, 400, 800, 1_000, 1_500, 2_000, 5_000, 10_000, 15_000];\n    private readonly HistogramAggregator _appRequestsLatencyHistogramAggregator;\n    private readonly ObservableCounter<long> _appRequestsLatencyHistogramBucket;\n    private readonly ObservableCounter<long> _appRequestsLatencyHistogramCount;\n    private readonly ObservableCounter<long> _appRequestsLatencyHistogramSum;\n\n    internal ApplicationRequestInstruments(OrleansInstruments instruments)\n    {\n        _timedOutRequestsCounter = instruments.Meter.CreateCounter<long>(InstrumentNames.APP_REQUESTS_TIMED_OUT);\n        _canceledRequestsCounter = instruments.Meter.CreateCounter<long>(InstrumentNames.APP_REQUESTS_CANCELED);\n        _appRequestsLatencyHistogramAggregator = new(AppRequestsLatencyHistogramBuckets, [], value => new(\"duration\", $\"{value}ms\"));\n        _appRequestsLatencyHistogramBucket = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + \"-bucket\", _appRequestsLatencyHistogramAggregator.CollectBuckets);\n        _appRequestsLatencyHistogramCount = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + \"-count\", _appRequestsLatencyHistogramAggregator.CollectCount);\n        _appRequestsLatencyHistogramSum = instruments.Meter.CreateObservableCounter(InstrumentNames.APP_REQUESTS_LATENCY_HISTOGRAM + \"-sum\", _appRequestsLatencyHistogramAggregator.CollectSum);\n    }\n\n    internal void OnAppRequestsEnd(long durationMilliseconds)\n    {\n        if (_appRequestsLatencyHistogramSum.Enabled)\n            _appRequestsLatencyHistogramAggregator.Record(durationMilliseconds);\n    }\n\n    internal void OnAppRequestsTimedOut()\n    {\n        _timedOutRequestsCounter.Add(1);\n    }\n\n    internal void OnAppRequestsCanceled()\n    {\n        _canceledRequestsCounter.Add(1);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/CatalogInstruments.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class CatalogInstruments\n{\n    internal static Counter<int> ActivationFailedToActivate = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_FAILED_TO_ACTIVATE);\n\n    internal static Counter<int> ActivationCollections = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_COLLECTION_NUMBER_OF_COLLECTIONS);\n\n    internal static Counter<int> ActivationShutdown = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_SHUTDOWN);\n\n    internal static void ActivationShutdownViaCollection() => ActivationShutdown.Add(1, new KeyValuePair<string, object>(\"via\", \"collection\"));\n    internal static void ActivationShutdownViaDeactivateOnIdle() => ActivationShutdown.Add(1, new KeyValuePair<string, object>(\"via\", \"deactivateOnIdle\"));\n    internal static void ActivationShutdownViaMigration() => ActivationShutdown.Add(1, new KeyValuePair<string, object>(\"via\", \"migration\"));\n    internal static void ActivationShutdownViaDeactivateStuckActivation() => ActivationShutdown.Add(1, new KeyValuePair<string, object>(\"via\", \"deactivateStuckActivation\"));\n\n    internal static Counter<int> NonExistentActivations = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_NON_EXISTENT_ACTIVATIONS);\n\n    internal static Counter<int> ActivationConcurrentRegistrationAttempts = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_CONCURRENT_REGISTRATION_ATTEMPTS);\n\n    internal static readonly Counter<int> ActivationsCreated = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_CREATED);\n    internal static readonly Counter<int> ActivationsDestroyed = Instruments.Meter.CreateCounter<int>(InstrumentNames.CATALOG_ACTIVATION_DESTROYED);\n\n    internal static ObservableGauge<int> ActivationCount;\n    \n    internal static void RegisterActivationCountObserve(Func<int> observeValue)\n    {\n        ActivationCount = Instruments.Meter.CreateObservableGauge(InstrumentNames.CATALOG_ACTIVATION_COUNT, observeValue);\n    }\n\n    internal static ObservableGauge<int> ActivationWorkingSet;\n    internal static void RegisterActivationWorkingSetObserve(Func<int> observeValue)\n    {\n        ActivationWorkingSet = Instruments.Meter.CreateObservableGauge(InstrumentNames.CATALOG_ACTIVATION_WORKING_SET, observeValue);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/ClientInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\npublic static class ClientInstruments\n{\n    internal static ObservableGauge<int> ConnectedGatewayCount;\n    internal static void RegisterConnectedGatewayCountObserve(Func<int> observeValue)\n    {\n        ConnectedGatewayCount = Instruments.Meter.CreateObservableGauge(InstrumentNames.CLIENT_CONNECTED_GATEWAY_COUNT, observeValue);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/ConsistentRingInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class ConsistentRingInstruments\n{\n    internal static ObservableGauge<int> RingSize;\n    internal static void RegisterRingSizeObserve(Func<int> observeValue)\n    {\n        RingSize = Instruments.Meter.CreateObservableGauge(InstrumentNames.CONSISTENTRING_SIZE, observeValue);\n    }\n\n    internal static ObservableGauge<float> MyRangeRingPercentage;\n    internal static void RegisterMyRangeRingPercentageObserve(Func<float> observeValue)\n    {\n        MyRangeRingPercentage = Instruments.Meter.CreateObservableGauge(InstrumentNames.CONSISTENTRING_LOCAL_SIZE_PERCENTAGE, observeValue);\n    }\n    internal static ObservableGauge<float> AverageRingPercentage;\n    internal static void RegisterAverageRingPercentageObserve(Func<float> observeValue)\n    {\n        AverageRingPercentage = Instruments.Meter.CreateObservableGauge(InstrumentNames.CONSISTENTRING_AVERAGE_SIZE_PERCENTAGE, observeValue);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/DirectoryInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class DirectoryInstruments\n{\n    internal static readonly Counter<int> LookupsLocalIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_LOCAL_ISSUED);\n    internal static readonly Counter<int> LookupsLocalSuccesses = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_LOCAL_SUCCESSES);\n\n    internal static readonly Counter<int> LookupsFullIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_FULL_ISSUED);\n\n    internal static readonly Counter<int> LookupsRemoteSent = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_REMOTE_SENT);\n    internal static readonly Counter<int> LookupsRemoteReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_REMOTE_RECEIVED);\n\n    internal static readonly Counter<int> LookupsLocalDirectoryIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_LOCALDIRECTORY_ISSUED);\n    internal static readonly Counter<int> LookupsLocalDirectorySuccesses = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_LOCALDIRECTORY_SUCCESSES);\n\n    internal static readonly Counter<int> LookupsCacheIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_CACHE_ISSUED);\n    internal static readonly Counter<int> LookupsCacheSuccesses = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_LOOKUPS_CACHE_SUCCESSES);\n    internal static readonly Counter<int> ValidationsCacheSent = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_VALIDATIONS_CACHE_SENT);\n    internal static readonly Counter<int> ValidationsCacheReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_VALIDATIONS_CACHE_RECEIVED);\n\n    internal static readonly Counter<int> SnapshotTransferCount = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_RANGE_SNAPSHOT_TRANSFER_COUNT);\n    internal static readonly Histogram<long> SnapshotTransferDuration = Instruments.Meter.CreateHistogram<long>(InstrumentNames.DIRECTORY_RANGE_SNAPSHOT_TRANSFER_DURATION);\n    internal static readonly Counter<long> RangeRecoveryCount = Instruments.Meter.CreateCounter<long>(InstrumentNames.DIRECTORY_RANGE_RECOVERY_COUNT);\n    internal static readonly Histogram<long> RangeRecoveryDuration = Instruments.Meter.CreateHistogram<long>(InstrumentNames.DIRECTORY_RANGE_RECOVERY_DURATION);\n    internal static readonly Histogram<long> RangeLockHeldDuration = Instruments.Meter.CreateHistogram<long>(InstrumentNames.DIRECTORY_RANGE_LOCK_HELD_DURATION);\n\n    internal static ObservableGauge<int> DirectoryPartitionSize;\n    internal static void RegisterDirectoryPartitionSizeObserve(Func<int> observeValue)\n    {\n        DirectoryPartitionSize = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.DIRECTORY_PARTITION_SIZE, observeValue);\n    }\n\n    internal static ObservableGauge<int> CacheSize;\n    internal static void RegisterCacheSizeObserve(Func<int> observeValue)\n    {\n        CacheSize = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.DIRECTORY_CACHE_SIZE, observeValue);\n    }\n\n    internal static ObservableGauge<int> RingSize;\n    internal static void RegisterRingSizeObserve(Func<int> observeValue)\n    {\n        RingSize = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.DIRECTORY_RING_RINGSIZE, observeValue);\n    }\n\n    internal static ObservableGauge<long> MyPortionRingDistance;\n    internal static void RegisterMyPortionRingDistanceObserve(Func<long> observeValue)\n    {\n        MyPortionRingDistance = Instruments.Meter.CreateObservableGauge<long>(InstrumentNames.DIRECTORY_RING_MYPORTION_RINGDISTANCE, observeValue);\n    }\n\n    internal static ObservableGauge<float> MyPortionRingPercentage;\n    internal static void RegisterMyPortionRingPercentageObserve(Func<float> observeValue)\n    {\n        MyPortionRingPercentage = Instruments.Meter.CreateObservableGauge(InstrumentNames.DIRECTORY_RING_MYPORTION_RINGPERCENTAGE, observeValue);\n    }\n\n    internal static ObservableGauge<float> MyPortionAverageRingPercentage;\n    internal static void RegisterMyPortionAverageRingPercentageObserve(Func<float> observeValue)\n    {\n        MyPortionAverageRingPercentage = Instruments.Meter.CreateObservableGauge(InstrumentNames.DIRECTORY_RING_MYPORTION_AVERAGERINGPERCENTAGE, observeValue);\n    }\n\n    internal static readonly Counter<int> RegistrationsSingleActIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_REGISTRATIONS_SINGLE_ACT_ISSUED);\n    internal static readonly Counter<int> RegistrationsSingleActLocal = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_REGISTRATIONS_SINGLE_ACT_LOCAL);\n    internal static readonly Counter<int> RegistrationsSingleActRemoteSent = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_REGISTRATIONS_SINGLE_ACT_REMOTE_SENT);\n    internal static readonly Counter<int> RegistrationsSingleActRemoteReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_REGISTRATIONS_SINGLE_ACT_REMOTE_RECEIVED);\n    internal static readonly Counter<int> UnregistrationsIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_ISSUED);\n    internal static readonly Counter<int> UnregistrationsLocal = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_LOCAL);\n    internal static readonly Counter<int> UnregistrationsRemoteSent = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_REMOTE_SENT);\n    internal static readonly Counter<int> UnregistrationsRemoteReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_REMOTE_RECEIVED);\n    internal static readonly Counter<int> UnregistrationsManyIssued = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_MANY_ISSUED);\n    internal static readonly Counter<int> UnregistrationsManyRemoteSent = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_MANY_REMOTE_SENT);\n    internal static readonly Counter<int> UnregistrationsManyRemoteReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.DIRECTORY_UNREGISTRATIONS_MANY_REMOTE_RECEIVED);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/GatewayInstruments.cs",
    "content": "using System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class GatewayInstruments\n{\n    internal static readonly Counter<int> GatewaySent = Instruments.Meter.CreateCounter<int>(InstrumentNames.GATEWAY_SENT);\n    internal static readonly Counter<int> GatewayReceived = Instruments.Meter.CreateCounter<int>(InstrumentNames.GATEWAY_RECEIVED);\n    internal static readonly Counter<int> GatewayLoadShedding = Instruments.Meter.CreateCounter<int>(InstrumentNames.GATEWAY_LOAD_SHEDDING);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/GrainInstruments.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class GrainInstruments\n{\n    static GrainInstruments()\n    {\n        GrainMetricsListener.Start();\n    }\n\n    internal static UpDownCounter<int> GrainCounts = Instruments.Meter.CreateUpDownCounter<int>(InstrumentNames.GRAIN_COUNTS);\n    internal static void IncrementGrainCounts(string grainTypeName)\n    {\n        GrainCounts.Add(1, new KeyValuePair<string, object>(\"type\", grainTypeName));\n    }\n    internal static void DecrementGrainCounts(string grainTypeName)\n    {\n        GrainCounts.Add(-1, new KeyValuePair<string, object>(\"type\", grainTypeName));\n    }\n\n    internal static UpDownCounter<int> SystemTargetCounts = Instruments.Meter.CreateUpDownCounter<int>(InstrumentNames.SYSTEM_TARGET_COUNTS);\n    internal static void IncrementSystemTargetCounts(string systemTargetTypeName)\n    {\n        SystemTargetCounts.Add(1, new KeyValuePair<string, object>(\"type\", systemTargetTypeName));\n    }\n    internal static void DecrementSystemTargetCounts(string systemTargetTypeName)\n    {\n        SystemTargetCounts.Add(-1, new KeyValuePair<string, object>(\"type\", systemTargetTypeName));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/InstrumentNames.cs",
    "content": "namespace Orleans.Runtime;\n\ninternal static class InstrumentNames\n{\n    // Networking\n    public const string NETWORKING_SOCKETS_CLOSED = \"orleans-networking-sockets-closed\";\n    public const string NETWORKING_SOCKETS_OPENED = \"orleans-networking-sockets-opened\";\n\n    // Messaging\n    public const string MESSAGING_SENT_MESSAGES_SIZE = \"orleans-messaging-sent-messages-size\";\n    public const string MESSAGING_RECEIVED_MESSAGES_SIZE = \"orleans-messaging-received-messages-size\";\n    public const string MESSAGING_SENT_BYTES_HEADER = \"orleans-messaging-sent-header-size\";\n    public const string MESSAGING_SENT_FAILED = \"orleans-messaging-sent-failed\";\n    public const string MESSAGING_SENT_DROPPED = \"orleans-messaging-sent-dropped\";\n    public const string MESSAGING_RECEIVED_BYTES_HEADER = \"orleans-messaging-received-header-size\";\n\n    public const string MESSAGING_DISPATCHER_RECEIVED = \"orleans-messaging-processing-dispatcher-received\";\n    public const string MESSAGING_DISPATCHER_PROCESSED = \"orleans-messaging-processing-dispatcher-processed\";\n    public const string MESSAGING_DISPATCHER_FORWARDED = \"orleans-messaging-processing-dispatcher-forwarded\";\n    public const string MESSAGING_IMA_RECEIVED = \"orleans-messaging-processing-ima-received\";\n    public const string MESSAGING_IMA_ENQUEUED = \"orleans-messaging-processing-ima-enqueued\";\n    public const string MESSAGING_PROCESSING_ACTIVATION_DATA_ALL = \"orleans-messaging-processing-activation-data\";\n    public const string MESSAGING_PINGS_SENT = \"orleans-messaging-pings-sent\";\n    public const string MESSAGING_PINGS_RECEIVED = \"orleans-messaging-pings-received\";\n    public const string MESSAGING_PINGS_REPLYRECEIVED = \"orleans-messaging-pings-reply-received\";\n    public const string MESSAGING_PINGS_REPLYMISSED = \"orleans-messaging-pings-reply-missed\";\n    public const string MESSAGING_EXPIRED = \"orleans-messaging-expired\";\n    public const string MESSAGING_REJECTED = \"orleans-messaging-rejected\";\n    public const string MESSAGING_REROUTED = \"orleans-messaging-rerouted\";\n    public const string MESSAGING_SENT_LOCALMESSAGES = \"orleans-messaging-sent-local\";\n\n    // Gateway\n    public const string GATEWAY_CONNECTED_CLIENTS = \"orleans-gateway-connected-clients\";\n    public const string GATEWAY_SENT = \"orleans-gateway-sent\";\n    public const string GATEWAY_RECEIVED = \"orleans-gateway-received\";\n    public const string GATEWAY_LOAD_SHEDDING = \"orleans-gateway-load-shedding\";\n\n    // Runtime\n    public const string SCHEDULER_NUM_LONG_RUNNING_TURNS = \"orleans-scheduler-long-running-turns\";\n\n    // Catalog\n    public const string CATALOG_ACTIVATION_COUNT = \"orleans-catalog-activations\";\n    public const string CATALOG_ACTIVATION_WORKING_SET = \"orleans-catalog-activation-working-set\";\n    public const string CATALOG_ACTIVATION_CREATED = \"orleans-catalog-activation-created\";\n    public const string CATALOG_ACTIVATION_DESTROYED = \"orleans-catalog-activation-destroyed\";\n    public const string CATALOG_ACTIVATION_FAILED_TO_ACTIVATE = \"orleans-catalog-activation-failed-to-activate\";\n    public const string CATALOG_ACTIVATION_COLLECTION_NUMBER_OF_COLLECTIONS = \"orleans-catalog-activation-collections\";\n    public const string CATALOG_ACTIVATION_SHUTDOWN = \"orleans-catalog-activation-shutdown\";\n    public const string CATALOG_ACTIVATION_NON_EXISTENT_ACTIVATIONS = \"orleans-catalog-activation-non-existent\";\n    public const string CATALOG_ACTIVATION_CONCURRENT_REGISTRATION_ATTEMPTS = \"orleans-catalog-activation-concurrent-registration-attempts\";\n\n    // Directory\n    // not used...\n    public const string DIRECTORY_LOOKUPS_LOCAL_ISSUED = \"orleans-directory-lookups-local-issued\";\n    // not used...\n    public const string DIRECTORY_LOOKUPS_LOCAL_SUCCESSES = \"orleans-directory-lookups-local-successes\";\n    public const string DIRECTORY_LOOKUPS_FULL_ISSUED = \"orleans-directory-lookups-full-issued\";\n    public const string DIRECTORY_LOOKUPS_REMOTE_SENT = \"orleans-directory-lookups-remote-sent\";\n    public const string DIRECTORY_LOOKUPS_REMOTE_RECEIVED = \"orleans-directory-lookups-remote-received\";\n    public const string DIRECTORY_LOOKUPS_LOCALDIRECTORY_ISSUED = \"orleans-directory-lookups-local-directory-issued\";\n    public const string DIRECTORY_LOOKUPS_LOCALDIRECTORY_SUCCESSES = \"orleans-directory-lookups-local-directory-successes\";\n    // not used\n    public const string DIRECTORY_LOOKUPS_CACHE_ISSUED = \"orleans-directory-lookups-cache-issued\";\n    // not used\n    public const string DIRECTORY_LOOKUPS_CACHE_SUCCESSES = \"orleans-directory-lookups-cache-successes\";\n    public const string DIRECTORY_VALIDATIONS_CACHE_SENT = \"orleans-directory-validations-cache-sent\";\n    public const string DIRECTORY_VALIDATIONS_CACHE_RECEIVED = \"orleans-directory-validations-cache-received\";\n    public const string DIRECTORY_PARTITION_SIZE = \"orleans-directory-partition-size\";\n    public const string DIRECTORY_CACHE_SIZE = \"orleans-directory-cache-size\";\n    public const string DIRECTORY_RING_RINGSIZE = \"orleans-directory-ring-size\";\n    public const string DIRECTORY_RING_MYPORTION_RINGDISTANCE = \"orleans-directory-ring-local-portion-distance\";\n    public const string DIRECTORY_RING_MYPORTION_RINGPERCENTAGE = \"orleans-directory-ring-local-portion-percentage\";\n    public const string DIRECTORY_RING_MYPORTION_AVERAGERINGPERCENTAGE = \"orleans-directory-ring-local-portion-average-percentage\";\n    public const string DIRECTORY_REGISTRATIONS_SINGLE_ACT_ISSUED = \"orleans-directory-registrations-single-act-issued\";\n    public const string DIRECTORY_REGISTRATIONS_SINGLE_ACT_LOCAL = \"orleans-directory-registrations-single-act-local\";\n    public const string DIRECTORY_REGISTRATIONS_SINGLE_ACT_REMOTE_SENT = \"orleans-directory-registrations-single-act-remote-sent\";\n    public const string DIRECTORY_REGISTRATIONS_SINGLE_ACT_REMOTE_RECEIVED = \"orleans-directory-registrations-single-act-remote-received\";\n    public const string DIRECTORY_UNREGISTRATIONS_ISSUED = \"orleans-directory-unregistrations-issued\";\n    public const string DIRECTORY_UNREGISTRATIONS_LOCAL = \"orleans-directory-unregistrations-local\";\n    public const string DIRECTORY_UNREGISTRATIONS_REMOTE_SENT = \"orleans-directory-unregistrations-remote-sent\";\n    public const string DIRECTORY_UNREGISTRATIONS_REMOTE_RECEIVED = \"orleans-directory-unregistrations-remote-received\";\n    public const string DIRECTORY_UNREGISTRATIONS_MANY_ISSUED = \"orleans-directory-unregistrations-many-issued\";\n    public const string DIRECTORY_UNREGISTRATIONS_MANY_REMOTE_SENT = \"orleans-directory-unregistrations-many-remote-sent\";\n    public const string DIRECTORY_UNREGISTRATIONS_MANY_REMOTE_RECEIVED = \"orleans-directory-unregistrations-many-remote-received\";\n\n    public const string DIRECTORY_RANGE_SNAPSHOT_TRANSFER_COUNT = \"orleans-directory-snapshot-transfer-count\";\n    public const string DIRECTORY_RANGE_SNAPSHOT_TRANSFER_DURATION = \"orleans-directory-snapshot-transfer-duration\";\n    public const string DIRECTORY_RANGE_RECOVERY_COUNT = \"orleans-directory-recovery-count\";\n    public const string DIRECTORY_RANGE_RECOVERY_DURATION = \"orleans-directory-recovery-duration\";\n    public const string DIRECTORY_RANGE_LOCK_HELD_DURATION = \"orleans-directory-range-lock-held-duration\";\n\n    // ConsistentRing\n    public const string CONSISTENTRING_SIZE = \"orleans-consistent-ring-size\";\n    public const string CONSISTENTRING_LOCAL_SIZE_PERCENTAGE = \"orleans-consistent-ring-range-percentage-local\";\n    public const string CONSISTENTRING_AVERAGE_SIZE_PERCENTAGE = \"orleans-consistent-ring-range-percentage-average\";\n\n    // Watchdog\n    public const string WATCHDOG_NUM_HEALTH_CHECKS = \"orleans-watchdog-health-checks\";\n    public const string WATCHDOG_NUM_FAILED_HEALTH_CHECKS = \"orleans-watchdog-health-checks-failed\";\n\n    // Client\n    public const string CLIENT_CONNECTED_GATEWAY_COUNT = \"orleans-client-connected-gateways\";\n\n    // Misc\n    public const string GRAIN_COUNTS = \"orleans-grains\";\n    public const string SYSTEM_TARGET_COUNTS = \"orleans-system-targets\";\n\n    // App requests\n    public const string APP_REQUESTS_LATENCY_HISTOGRAM = \"orleans-app-requests-latency\";\n    public const string APP_REQUESTS_TIMED_OUT = \"orleans-app-requests-timedout\";\n    public const string APP_REQUESTS_CANCELED = \"orleans-app-requests-canceled\";\n\n    // Reminders\n    public const string REMINDERS_TARDINESS = \"orleans-reminders-tardiness\";\n    public const string REMINDERS_NUMBER_ACTIVE_REMINDERS = \"orleans-reminders-active\";\n    public const string REMINDERS_COUNTERS_TICKS_DELIVERED = \"orleans-reminders-ticks-delivered\";\n\n    // Storage\n    public const string STORAGE_READ_ERRORS = \"orleans-storage-read-errors\";\n    public const string STORAGE_WRITE_ERRORS = \"orleans-storage-write-errors\";\n    public const string STORAGE_CLEAR_ERRORS = \"orleans-storage-clear-errors\";\n    public const string STORAGE_READ_LATENCY = \"orleans-storage-read-latency\";\n    public const string STORAGE_WRITE_LATENCY = \"orleans-storage-write-latency\";\n    public const string STORAGE_CLEAR_LATENCY = \"orleans-storage-clear-latency\";\n\n    // Streams\n    public const string STREAMS_PUBSUB_PRODUCERS_ADDED = \"orleans-streams-pubsub-producers-added\";\n    public const string STREAMS_PUBSUB_PRODUCERS_REMOVED = \"orleans-streams-pubsub-producers-removed\";\n    public const string STREAMS_PUBSUB_PRODUCERS_TOTAL = \"orleans-streams-pubsub-producers\";\n    public const string STREAMS_PUBSUB_CONSUMERS_ADDED = \"orleans-streams-pubsub-consumers-added\";\n    public const string STREAMS_PUBSUB_CONSUMERS_REMOVED = \"orleans-streams-pubsub-consumers-removed\";\n    public const string STREAMS_PUBSUB_CONSUMERS_TOTAL = \"orleans-streams-pubsub-consumers\";\n\n    public const string STREAMS_PERSISTENT_STREAM_NUM_PULLING_AGENTS = \"orleans-streams-persistent-stream-pulling-agents\";\n    public const string STREAMS_PERSISTENT_STREAM_NUM_READ_MESSAGES = \"orleans-streams-persistent-stream-messages-read\";\n    public const string STREAMS_PERSISTENT_STREAM_NUM_SENT_MESSAGES = \"orleans-streams-persistent-stream-messages-sent\";\n    public const string STREAMS_PERSISTENT_STREAM_PUBSUB_CACHE_SIZE = \"orleans-streams-persistent-stream-pubsub-cache-size\";\n\n    public const string STREAMS_QUEUE_INITIALIZATION_FAILURES = \"orleans-streams-queue-initialization-failures\";\n    public const string STREAMS_QUEUE_INITIALIZATION_DURATION = \"orleans-streams-queue-initialization-duration\";\n    public const string STREAMS_QUEUE_INITIALIZATION_EXCEPTIONS = \"orleans-streams-queue-initialization-exceptions\";\n    public const string STREAMS_QUEUE_READ_FAILURES = \"orleans-streams-queue-read-failures\";\n    public const string STREAMS_QUEUE_READ_DURATION = \"orleans-streams-queue-read-duration\";\n    public const string STREAMS_QUEUE_READ_EXCEPTIONS = \"orleans-streams-queue-read-exceptions\";\n    public const string STREAMS_QUEUE_SHUTDOWN_FAILURES = \"orleans-streams-queue-shutdown-failures\";\n    public const string STREAMS_QUEUE_SHUTDOWN_DURATION = \"orleans-streams-queue-shutdown-duration\";\n    public const string STREAMS_QUEUE_SHUTDOWN_EXCEPTIONS = \"orleans-streams-queue-shutdown-exceptions\";\n    public const string STREAMS_QUEUE_MESSAGES_RECEIVED = \"orleans-streams-queue-messages-received\";\n    public const string STREAMS_QUEUE_OLDEST_MESSAGE_ENQUEUE_AGE = \"orleans-streams-queue-oldest-message-enqueue-age\";\n    public const string STREAMS_QUEUE_NEWEST_MESSAGE_ENQUEUE_AGE = \"orleans-streams-queue-newest-message-enqueue-age\";\n\n    public const string STREAMS_BLOCK_POOL_TOTAL_MEMORY = \"orleans-streams-block-pool-total-memory\";\n    public const string STREAMS_BLOCK_POOL_AVAILABLE_MEMORY = \"orleans-streams-block-pool-available-memory\";\n    public const string STREAMS_BLOCK_POOL_CLAIMED_MEMORY = \"orleans-streams-block-pool-claimed-memory\";\n    public const string STREAMS_BLOCK_POOL_RELEASED_MEMORY = \"orleans-streams-block-pool-released-memory\";\n    public const string STREAMS_BLOCK_POOL_ALLOCATED_MEMORY = \"orleans-streams-block-pool-allocated-memory\";\n\n    public const string STREAMS_QUEUE_CACHE_SIZE = \"orleans-streams-queue-cache-size\";\n    public const string STREAMS_QUEUE_CACHE_LENGTH = \"orleans-streams-queue-cache-length\";\n    public const string STREAMS_QUEUE_CACHE_MESSAGES_ADDED = \"orleans-streams-queue-cache-messages-added\";\n    public const string STREAMS_QUEUE_CACHE_MESSAGES_PURGED = \"orleans-streams-queue-cache-messages-purged\";\n    public const string STREAMS_QUEUE_CACHE_MEMORY_ALLOCATED = \"orleans-streams-queue-cache-memory-allocated\";\n    public const string STREAMS_QUEUE_CACHE_MEMORY_RELEASED = \"orleans-streams-queue-cache-memory-released\";\n    public const string STREAMS_QUEUE_CACHE_OLDEST_TO_NEWEST_DURATION = \"orleans-streams-queue-cache-oldest-to-newest-duration\";\n    public const string STREAMS_QUEUE_CACHE_OLDEST_AGE = \"orleans-streams-queue-cache-oldest-age\";\n    public const string STREAMS_QUEUE_CACHE_PRESSURE = \"orleans-streams-queue-cache-pressure\";\n    public const string STREAMS_QUEUE_CACHE_UNDER_PRESSURE = \"orleans-streams-queue-cache-under-pressure\";\n    public const string STREAMS_QUEUE_CACHE_PRESSURE_CONTRIBUTION_COUNT = \"orleans-streams-queue-cache-pressure-contribution-count\";\n\n    public const string RUNTIME_MEMORY_TOTAL_PHYSICAL_MEMORY_MB = \"orleans-runtime-total-physical-memory\";\n    public const string RUNTIME_MEMORY_AVAILABLE_MEMORY_MB = \"orleans-runtime-available-memory\";\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/Instruments.cs",
    "content": "using System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\npublic static class Instruments\n{\n    public static readonly Meter Meter = new(\"Microsoft.Orleans\");\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/MessagingInstruments.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\nusing Orleans.Messaging;\n\nnamespace Orleans.Runtime\n{\n    internal static class MessagingInstruments\n    {\n        internal static long _headerBytesSent;\n        internal static long _headerBytesReceived;\n        internal static readonly ObservableCounter<long> HeaderBytesSentCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_SENT_BYTES_HEADER, () => _headerBytesSent, \"bytes\");\n        internal static readonly ObservableCounter<long> HeaderBytesReceivedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_RECEIVED_BYTES_HEADER, () => _headerBytesReceived, \"bytes\");\n        internal static readonly CounterAggregator LocalMessagesSentCounterAggregator = new();\n        private static readonly ObservableCounter<long> LocalMessagesSentCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_SENT_LOCALMESSAGES, LocalMessagesSentCounterAggregator.Collect);\n\n        internal static readonly Counter<int> FailedSentMessagesCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_SENT_FAILED);\n        internal static readonly Counter<int> DroppedSentMessagesCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_SENT_DROPPED);\n        internal static readonly Counter<int> RejectedMessagesCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_REJECTED);\n        internal static readonly Counter<int> ReroutedMessagesCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_REROUTED);\n        internal static readonly Counter<int> ExpiredMessagesCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_EXPIRED);\n\n        internal static readonly UpDownCounter<int> ConnectedClient = Instruments.Meter.CreateUpDownCounter<int>(InstrumentNames.GATEWAY_CONNECTED_CLIENTS);\n        internal static readonly Counter<int> PingSendCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_PINGS_SENT);\n        internal static readonly Counter<int> PingReceivedCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_PINGS_RECEIVED);\n        internal static readonly Counter<int> PingReplyReceivedCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_PINGS_REPLYRECEIVED);\n        internal static readonly Counter<int> PingReplyMissedCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.MESSAGING_PINGS_REPLYMISSED);\n\n        // currently, bucket size need to be configured at collector side\n        // [Add \"hints\" in Metric API to provide things like histogram bounds]\n        // https://github.com/dotnet/runtime/issues/63650\n        // Histogram of sent  message size, starting from 0 in multiples of 2\n        // (1=2^0, 2=2^2, ... , 256=2^8, 512=2^9, 1024==2^10, ... , up to ... 2^30=1GB)\n        internal static readonly Histogram<int> MessageSentSizeHistogram = Instruments.Meter.CreateHistogram<int>(InstrumentNames.MESSAGING_SENT_MESSAGES_SIZE, \"bytes\");\n        internal static readonly Histogram<int> MessageReceivedSizeHistogram = Instruments.Meter.CreateHistogram<int>(InstrumentNames.MESSAGING_RECEIVED_MESSAGES_SIZE, \"bytes\");\n\n        internal enum Phase\n        {\n            Send,\n            Receive,\n            Dispatch,\n            Invoke,\n            Respond,\n        }\n\n        internal static void OnMessageExpired(Phase phase)\n        {\n            ExpiredMessagesCounter.Add(1, new KeyValuePair<string, object>(\"Phase\", phase));\n        }\n\n        internal static void OnPingSend(SiloAddress destination)\n        {\n            PingSendCounter.Add(1, new KeyValuePair<string, object>(\"Destination\", destination.ToString()));\n        }\n\n        internal static void OnPingReceive(SiloAddress destination)\n        {\n            PingReceivedCounter.Add(1, new KeyValuePair<string, object>(\"Destination\", destination.ToString()));\n        }\n\n        internal static void OnPingReplyReceived(SiloAddress replier)\n        {\n            PingReplyReceivedCounter.Add(1, new KeyValuePair<string, object>(\"Destination\", replier.ToString()));\n        }\n\n        internal static void OnPingReplyMissed(SiloAddress replier)\n        {\n            PingReplyMissedCounter.Add(1, new KeyValuePair<string, object>(\"Destination\", replier.ToString()));\n        }\n\n        internal static void OnFailedSentMessage(Message msg)\n        {\n            if (msg == null || !msg.HasDirection) return;\n            FailedSentMessagesCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", msg.Direction.ToString()));\n        }\n\n        internal static void OnDroppedSentMessage(Message msg)\n        {\n            if (msg == null || !msg.HasDirection) return;\n            DroppedSentMessagesCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", msg.Direction.ToString()));\n        }\n\n        internal static void OnRejectedMessage(Message msg)\n        {\n            if (msg == null || !msg.HasDirection) return;\n            RejectedMessagesCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", msg.Direction.ToString()));\n        }\n\n        internal static void OnMessageReRoute(Message msg)\n        {\n            ReroutedMessagesCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", msg.Direction.ToString()));\n        }\n\n        internal static void OnMessageReceive(Message msg, int numTotalBytes, int headerBytes, ConnectionDirection connectionDirection, SiloAddress remoteSiloAddress = null)\n        {\n            if (MessageReceivedSizeHistogram.Enabled)\n            {\n                if (remoteSiloAddress != null)\n                {\n                    MessageReceivedSizeHistogram.Record(numTotalBytes, new KeyValuePair<string, object>(\"ConnectionDirection\", connectionDirection.ToString()), new KeyValuePair<string, object>(\"MessageDirection\", msg.Direction.ToString()), new KeyValuePair<string, object>(\"silo\", remoteSiloAddress));\n                }\n                else\n                {\n                    MessageReceivedSizeHistogram.Record(numTotalBytes, new KeyValuePair<string, object>(\"ConnectionDirection\", connectionDirection.ToString()), new KeyValuePair<string, object>(\"MessageDirection\", msg.Direction.ToString()));\n                }\n            }\n\n            Interlocked.Add(ref _headerBytesReceived, headerBytes);\n        }\n\n        internal static void OnMessageSend(Message msg, int numTotalBytes, int headerBytes, ConnectionDirection connectionDirection, SiloAddress remoteSiloAddress = null)\n        {\n            Debug.Assert(numTotalBytes >= 0, $\"OnMessageSend(numTotalBytes={numTotalBytes})\");\n\n            if (MessageSentSizeHistogram.Enabled)\n            {\n                if (remoteSiloAddress != null)\n                {\n                    MessageSentSizeHistogram.Record(numTotalBytes, new KeyValuePair<string, object>(\"ConnectionDirection\", connectionDirection.ToString()), new KeyValuePair<string, object>(\"MessageDirection\", msg.Direction.ToString()), new KeyValuePair<string, object>(\"silo\", remoteSiloAddress));\n                }\n                else\n                {\n                    MessageSentSizeHistogram.Record(numTotalBytes, new KeyValuePair<string, object>(\"ConnectionDirection\", connectionDirection.ToString()), new KeyValuePair<string, object>(\"MessageDirection\", msg.Direction.ToString()));\n                }\n            }\n\n            Interlocked.Add(ref _headerBytesSent, headerBytes);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/MessagingProcessingInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class MessagingProcessingInstruments\n{\n    private static readonly CounterAggregatorGroup DispatcherMessagesProcessedCounterAggregatorGroup = new();\n    private static readonly ObservableCounter<long> DispatcherMessagesProcessedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_DISPATCHER_PROCESSED, DispatcherMessagesProcessedCounterAggregatorGroup.Collect);\n\n    private static readonly CounterAggregatorGroup DispatcherMessagesReceivedCounterAggregatorGroup = new();\n    private static readonly ObservableCounter<long> DispatcherMessagesReceivedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_DISPATCHER_RECEIVED, DispatcherMessagesReceivedCounterAggregatorGroup.Collect);\n\n    private static readonly CounterAggregator DispatcherMessagesForwardedCounterAggregator = new();\n    private static readonly ObservableCounter<long> DispatcherMessagesForwardedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_DISPATCHER_FORWARDED, DispatcherMessagesForwardedCounterAggregator.Collect);\n    private static readonly CounterAggregator ImaReceivedCounterAggregator = new();\n    private static readonly ObservableCounter<long> ImaReceivedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_IMA_RECEIVED, ImaReceivedCounterAggregator.Collect);\n    private static readonly CounterAggregatorGroup ImaEnqueuedCounterAggregatorGroup = new();\n    private static readonly ObservableCounter<long> ImaEnqueuedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.MESSAGING_IMA_ENQUEUED, ImaEnqueuedCounterAggregatorGroup.Collect);\n    private static readonly CounterAggregator ImaMessageEnqueuedNullContext;\n    private static readonly CounterAggregator ImaMessageEnqueuedSystemTarget;\n    private static readonly CounterAggregator ImaMessageEnqueuedGrain;\n    private static readonly CounterAggregator[] DispatcherMessagesReceivedCounters_NullContext;\n    private static readonly CounterAggregator[] DispatcherMessagesReceivedCounters_Grain;\n\n    private static readonly CounterAggregator[] DispatcherMessagesProcessedCounters_Ok;\n    private static readonly CounterAggregator[] DispatcherMessagesProcessedCounters_Error;\n\n    static MessagingProcessingInstruments()\n    {\n        ImaMessageEnqueuedNullContext = ImaEnqueuedCounterAggregatorGroup.FindOrCreate(new(\"Context\", \"ToNull\"));\n        ImaMessageEnqueuedSystemTarget = ImaEnqueuedCounterAggregatorGroup.FindOrCreate(new(\"Context\", \"ToSystemTarget\"));\n        ImaMessageEnqueuedGrain = ImaEnqueuedCounterAggregatorGroup.FindOrCreate(new(\"Context\", \"ToGrain\"));\n        var directionEnumValues = Enum.GetValues<Message.Directions>();\n        DispatcherMessagesReceivedCounters_NullContext = new CounterAggregator[directionEnumValues.Length + 1];\n        DispatcherMessagesReceivedCounters_Grain = new CounterAggregator[directionEnumValues.Length + 1];\n        DispatcherMessagesProcessedCounters_Ok = new CounterAggregator[directionEnumValues.Length + 1];\n        DispatcherMessagesProcessedCounters_Error = new CounterAggregator[directionEnumValues.Length + 1];\n        foreach (var value in directionEnumValues)\n        {\n            DispatcherMessagesReceivedCounters_NullContext[(int)value] = DispatcherMessagesReceivedCounterAggregatorGroup.FindOrCreate(new(\"Context\", \"None\", \"Direction\", value.ToString()));\n            DispatcherMessagesReceivedCounters_Grain[(int)value] = DispatcherMessagesReceivedCounterAggregatorGroup.FindOrCreate(new(\"Context\", \"Grain\", \"Direction\", value.ToString()));\n\n            DispatcherMessagesProcessedCounters_Ok[(int)value] = DispatcherMessagesProcessedCounterAggregatorGroup.FindOrCreate(new(\"Direction\", value.ToString(), \"Status\", \"Ok\"));\n            DispatcherMessagesProcessedCounters_Error[(int)value] = DispatcherMessagesProcessedCounterAggregatorGroup.FindOrCreate(new(\"Direction\", value.ToString(), \"Status\", \"Error\"));\n        }\n    }\n\n    internal static void OnDispatcherMessageReceive(Message msg)\n    {\n        if (!DispatcherMessagesReceivedCounter.Enabled)\n            return;\n        var context = RuntimeContext.Current;\n        var counters = context switch\n        {\n            null => DispatcherMessagesReceivedCounters_NullContext,\n            _ => DispatcherMessagesReceivedCounters_Grain,\n        };\n        counters[(int)msg.Direction].Add(1);\n    }\n\n    internal static void OnDispatcherMessageProcessedOk(Message msg)\n    {\n        if (DispatcherMessagesProcessedCounter.Enabled)\n        {\n            DispatcherMessagesProcessedCounters_Ok[(int)msg.Direction].Add(1);\n        }\n    }\n\n    internal static void OnDispatcherMessageProcessedError(Message msg)\n    {\n        if (DispatcherMessagesProcessedCounter.Enabled)\n        {\n            DispatcherMessagesProcessedCounters_Error[(int)msg.Direction].Add(1);\n        }\n    }\n\n    internal static void OnDispatcherMessageForwared(Message msg)\n    {\n        if (DispatcherMessagesForwardedCounter.Enabled)\n        {\n            DispatcherMessagesForwardedCounterAggregator.Add(1);\n        }\n    }\n\n    internal static void OnImaMessageReceived(Message msg)\n    {\n        if (ImaReceivedCounter.Enabled)\n        {\n            ImaReceivedCounterAggregator.Add(1);\n        }\n    }\n\n    internal static void OnImaMessageEnqueued(IGrainContext context)\n    {\n        if (!ImaEnqueuedCounter.Enabled)\n        {\n            return;\n        }\n\n        switch (context)\n        {\n            case null:\n                ImaMessageEnqueuedNullContext.Add(1);\n                break;\n            case ISystemTargetBase:\n                ImaMessageEnqueuedSystemTarget.Add(1);\n                break;\n            default:\n                ImaMessageEnqueuedGrain.Add(1);\n                break;\n        }\n    }\n\n    internal static ObservableGauge<long> ActivationDataAll;\n\n    internal static void RegisterActivationDataAllObserve(Func<long> observeValue)\n    {\n        ActivationDataAll = Instruments.Meter.CreateObservableGauge(InstrumentNames.MESSAGING_PROCESSING_ACTIVATION_DATA_ALL, observeValue);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/NetworkingInstruments.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing Orleans.Messaging;\n\nnamespace Orleans.Runtime;\n\ninternal static class NetworkingInstruments\n{\n    internal static Counter<int> ClosedSocketsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.NETWORKING_SOCKETS_CLOSED);\n    internal static Counter<int> OpenedSocketsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.NETWORKING_SOCKETS_OPENED);\n\n    internal static void OnOpenedSocket(ConnectionDirection direction)\n    {\n        OpenedSocketsCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", direction.ToString()));\n    }\n\n    internal static void OnClosedSocket(ConnectionDirection direction)\n    {\n        ClosedSocketsCounter.Add(1, new KeyValuePair<string, object>(\"Direction\", direction.ToString()));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/OrleansInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Provides the <see cref=\"Meter\"/> used by Orleans runtime metrics.\n/// </summary>\n/// <param name=\"meterFactory\">The meter factory used to create the Orleans meter.</param>\npublic class OrleansInstruments(IMeterFactory meterFactory)\n{\n    /// <summary>\n    /// Gets the Orleans runtime meter.\n    /// </summary>\n    public Meter Meter { get; } = (meterFactory ?? throw new ArgumentNullException(nameof(meterFactory))).Create(\"Microsoft.Orleans\");\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/ReminderInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class ReminderInstruments\n{\n    public static Histogram<double> TardinessSeconds = Instruments.Meter.CreateHistogram<double>(InstrumentNames.REMINDERS_TARDINESS, \"seconds\");\n    public static ObservableGauge<int> ActiveReminders;\n    public static void RegisterActiveRemindersObserve(Func<int> observeValue)\n    {\n        ActiveReminders = Instruments.Meter.CreateObservableGauge(InstrumentNames.REMINDERS_NUMBER_ACTIVE_REMINDERS, observeValue);\n    }\n\n    public static Counter<int> TicksDelivered = Instruments.Meter.CreateCounter<int>(InstrumentNames.REMINDERS_COUNTERS_TICKS_DELIVERED);\n\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/SchedulerInstruments.cs",
    "content": "using System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal class SchedulerInstruments\n{\n    internal static readonly Counter<int> LongRunningTurnsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.SCHEDULER_NUM_LONG_RUNNING_TURNS);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/StorageInstruments.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class StorageInstruments\n{\n    private static readonly Histogram<double> StorageReadHistogram = Instruments.Meter.CreateHistogram<double>(InstrumentNames.STORAGE_READ_LATENCY, \"ms\");\n    private static readonly Histogram<double> StorageWriteHistogram = Instruments.Meter.CreateHistogram<double>(InstrumentNames.STORAGE_WRITE_LATENCY, \"ms\");\n    private static readonly Histogram<double> StorageClearHistogram = Instruments.Meter.CreateHistogram<double>(InstrumentNames.STORAGE_CLEAR_LATENCY, \"ms\");\n    private static readonly Counter<int> StorageReadErrorsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.STORAGE_READ_ERRORS);\n    private static readonly Counter<int> StorageWriteErrorsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.STORAGE_WRITE_ERRORS);\n    private static readonly Counter<int> StorageClearErrorsCounter = Instruments.Meter.CreateCounter<int>(InstrumentNames.STORAGE_CLEAR_ERRORS);\n\n    internal static void OnStorageRead(TimeSpan latency, string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageReadHistogram.Enabled)\n        {\n            StorageReadHistogram.Record(\n                latency.TotalMilliseconds,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n\n    internal static void OnStorageWrite(TimeSpan latency, string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageWriteHistogram.Enabled)\n        {\n            StorageWriteHistogram.Record(\n                latency.TotalMilliseconds,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n\n    internal static void OnStorageReadError(string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageReadErrorsCounter.Enabled)\n        {\n            StorageReadErrorsCounter.Add(1,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n\n    internal static void OnStorageWriteError(string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageWriteErrorsCounter.Enabled)\n        {\n            StorageWriteErrorsCounter.Add(1,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n\n    internal static void OnStorageDelete(TimeSpan latency, string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageClearHistogram.Enabled)\n        {\n            StorageClearHistogram.Record(latency.TotalMilliseconds,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n\n    internal static void OnStorageDeleteError(string providerTypeName, string stateName, string stateTypeName)\n    {\n        if (StorageClearErrorsCounter.Enabled)\n        {\n            StorageClearErrorsCounter.Add(1,\n                [\n                    new KeyValuePair<string, object>(\"provider_type_name\", providerTypeName),\n                    new KeyValuePair<string, object>(\"state_name\", stateName),\n                    new KeyValuePair<string, object>(\"state_type\", stateTypeName)\n                ]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/StreamInstruments.cs",
    "content": "using System;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class StreamInstruments\n{\n    public static Counter<int> PubSubProducersAdded = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_PRODUCERS_ADDED);\n    public static Counter<int> PubSubProducersRemoved = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_PRODUCERS_REMOVED);\n    public static Counter<int> PubSubProducersTotal = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_PRODUCERS_TOTAL);\n    public static Counter<int> PubSubConsumersAdded = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_CONSUMERS_ADDED);\n    public static Counter<int> PubSubConsumersRemoved = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_CONSUMERS_REMOVED);\n    public static Counter<int> PubSubConsumersTotal = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PUBSUB_CONSUMERS_TOTAL);\n\n    public static ObservableGauge<int> PersistentStreamPullingAgents;\n    public static void RegisterPersistentStreamPullingAgentsObserve(Func<Measurement<int>> observeValue)\n    {\n        PersistentStreamPullingAgents = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.STREAMS_PERSISTENT_STREAM_NUM_PULLING_AGENTS, observeValue);\n    }\n    public static Counter<int> PersistentStreamReadMessages = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PERSISTENT_STREAM_NUM_READ_MESSAGES);\n    public static Counter<int> PersistentStreamSentMessages = Instruments.Meter.CreateCounter<int>(InstrumentNames.STREAMS_PERSISTENT_STREAM_NUM_SENT_MESSAGES);\n    public static ObservableGauge<int> PersistentStreamPubSubCacheSize;\n    public static void RegisterPersistentStreamPubSubCacheSizeObserve(Func<Measurement<int>> observeValue)\n    {\n        PersistentStreamPubSubCacheSize = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.STREAMS_PERSISTENT_STREAM_PUBSUB_CACHE_SIZE, observeValue);\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.Core/Diagnostics/Metrics/WatchdogInstruments.cs",
    "content": "using System.Diagnostics.Metrics;\n\nnamespace Orleans.Runtime;\n\ninternal static class WatchdogInstruments\n{\n    internal static Counter<int> HealthChecks = Instruments.Meter.CreateCounter<int>(InstrumentNames.WATCHDOG_NUM_HEALTH_CHECKS);\n    internal static Counter<int> FailedHealthChecks = Instruments.Meter.CreateCounter<int>(InstrumentNames.WATCHDOG_NUM_FAILED_HEALTH_CHECKS);\n}\n"
  },
  {
    "path": "src/Orleans.Core/GrainDirectory/IDhtGrainDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.GrainDirectory\n{\n    /// <summary>\n    /// Recursive distributed operations on grain directories.\n    /// Each operation may forward the request to a remote owner, increasing the hopCount.\n    ///\n    /// The methods here can be called remotely (where extended by IRemoteGrainDirectory) or\n    /// locally (where extended by ILocalGrainDirectory)\n    /// </summary>\n    internal interface IDhtGrainDirectory\n    {\n        /// <summary>\n        /// Record a new grain activation by adding it to the directory.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"address\">The address of the new activation.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos</param>\n        /// <returns>The registered address and the version associated with this directory mapping.</returns>\n        Task<AddressAndTag> RegisterAsync(GrainAddress address, int hopCount = 0);\n\n        /// <summary>\n        /// Record a new grain activation by adding it to the directory.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"address\">The address of the new activation.</param>\n        /// <param name=\"currentRegistration\">The existing registration, which may be null.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos</param>\n        /// <returns>The registered address and the version associated with this directory mapping.</returns>\n        Task<AddressAndTag> RegisterAsync(GrainAddress address, GrainAddress? currentRegistration, int hopCount = 0);\n\n        /// <summary>\n        /// Removes the record for an existing activation from the directory service.\n        /// This is used when an activation is being deleted.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"address\">The address of the activation to remove.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos.</param>\n        /// <param name=\"cause\">The reason for deregistration.</param>\n        /// <returns>An acknowledgement that the deregistration has completed.</returns>\n        Task UnregisterAsync(GrainAddress address, UnregistrationCause cause, int hopCount = 0);\n\n        /// <summary>\n        /// Unregister a batch of addresses at once\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"addresses\">The addresses to deregister.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos.</param>\n        /// <param name=\"cause\">The reason for deregistration.</param>\n        /// <returns>An acknowledgement that the unregistration has completed.</returns>\n        Task UnregisterManyAsync(List<GrainAddress> addresses, UnregistrationCause cause, int hopCount = 0);\n\n        /// <summary>\n        /// Removes all directory information about a grain.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"grainId\">The ID of the grain.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos.</param>\n        /// <returns>\n        /// An acknowledgement that the deletion has completed.\n        /// </returns>\n        Task DeleteGrainAsync(GrainId grainId, int hopCount = 0);\n\n        /// <summary>\n        /// Fetches complete directory information for a grain.\n        /// If there is no local information, then this method will query the appropriate remote directory node.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"grainId\">The ID of the grain to look up.</param>\n        /// <param name=\"hopCount\">Counts recursion depth across silos.</param>\n        /// <returns>A list of all known activations of the grain, and the e-tag.</returns>\n        Task<AddressAndTag> LookupAsync(GrainId grainId, int hopCount = 0);\n    }\n\n    /// <summary>\n    /// Represents the address of a grain as well as a version tag.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    internal readonly struct AddressAndTag\n    {\n        /// <summary>\n        /// The address.\n        /// </summary>\n        [Id(0)]\n        public readonly GrainAddress? Address;\n\n        /// <summary>\n        /// The version of this entry.\n        /// </summary>\n        [Id(1)]\n        public readonly int VersionTag;\n\n        public AddressAndTag(GrainAddress? address, int versionTag)\n        {\n            Address = address;\n            VersionTag = versionTag;\n        }\n    }\n\n    /// <summary>\n    /// Indicates the reason for removing activations from the directory.\n    /// This influences the conditions that are applied when determining whether or not to remove an entry.\n    /// </summary>\n    public enum UnregistrationCause : byte\n    {\n        /// <summary>\n        /// Remove the directory entry forcefully, without any conditions\n        /// </summary>\n        Force = 0,\n\n        /// <summary>\n        /// Remove the directory entry only if it is not too fresh (to avoid races on new registrations)\n        /// </summary>\n        NonexistentActivation = 1,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/GrainDirectory/IGrainLocator.cs",
    "content": "#nullable enable\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.GrainDirectory\n{\n    /// <summary>\n    /// Used to locate Grain activation in the cluster\n    /// </summary>\n    public interface IGrainLocator\n    {\n        /// <summary>\n        /// Registers the provided address in the appropriate grain directory.\n        /// </summary>\n        /// <param name=\"address\">The address to register.</param>\n        /// <returns>The grain address which is registered in the directory immediately following this call.</returns>\n        Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousRegistration);\n\n        /// <summary>\n        /// Deregisters a grain address from the directory.\n        /// </summary>\n        /// <param name=\"address\">The address to deregister.</param>\n        /// <param name=\"cause\">The cause for deregistration.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task Unregister(GrainAddress address, UnregistrationCause cause);\n\n        /// <summary>\n        /// Finds the corresponding address for a grain.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id.</param>\n        /// <returns>The address corresponding to the specified grain id, or <see langword=\"null\"/> if the grain is not currently registered.</returns>\n        ValueTask<GrainAddress?> Lookup(GrainId grainId);\n\n        /// <summary>\n        /// Updates the cache with a grain placement decision or known activation address.\n        /// </summary>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        /// <param name=\"siloAddress\">The silo which may host the grain.</param>\n        void UpdateCache(GrainId grainId, SiloAddress siloAddress);\n\n        /// <summary>\n        /// Invalidates any lookup cache entry associated with the provided grain id.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        void InvalidateCache(GrainId grainId);\n\n        /// <summary>\n        /// Removes the specified address from the lookup cache.\n        /// </summary>\n        /// <param name=\"address\">\n        /// The grain address to invalidate.\n        /// </param>\n        void InvalidateCache(GrainAddress address);\n\n        /// <summary>\n        /// Attempts to find the grain address for the provided grain id in the local lookup cache.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id to find.</param>\n        /// <param name=\"address\">The resulting grain address, if found, or <see langword=\"null\"/> if not found.</param>\n        /// <returns>A value indicating whether a valid entry was found.</returns>\n        bool TryLookupInCache(GrainId grainId, [NotNullWhen(true)] out GrainAddress? address);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/GrainReferences/GrainReferenceActivator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.CodeGeneration;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Versions;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.GrainReferences\n{\n    /// <summary>\n    /// The central point for creating <see cref=\"GrainReference\"/> instances.\n    /// </summary>\n    public sealed class GrainReferenceActivator\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly IServiceProvider _serviceProvider;\n        private readonly IGrainReferenceActivatorProvider[] _providers;\n        private Dictionary<(GrainType, GrainInterfaceType), IGrainReferenceActivator> _activators = new();\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceActivator\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"providers\">The collection of grain reference activator providers.</param>\n        public GrainReferenceActivator(\n            IServiceProvider serviceProvider,\n            IEnumerable<IGrainReferenceActivatorProvider> providers)\n        {\n            _serviceProvider = serviceProvider;\n            _providers = providers.ToArray();\n        }\n\n        /// <summary>\n        /// Creates a grain reference pointing to the specified grain id and implementing the specified grain interface type.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id.</param>\n        /// <param name=\"interfaceType\">The grain interface type.</param>\n        /// <returns>A new grain reference.</returns>\n        public GrainReference CreateReference(GrainId grainId, GrainInterfaceType interfaceType)\n        {\n            if (!_activators.TryGetValue((grainId.Type, interfaceType), out var entry))\n            {\n                entry = CreateActivator(grainId.Type, interfaceType);\n            }\n\n            var result = entry.CreateReference(grainId);\n            return result;\n        }\n\n        /// <summary>\n        /// Creates a grain reference activator for the provided arguments.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"interfaceType\">the grain interface type.</param>\n        /// <returns>An activator for the provided arguments.</returns>\n        /// <exception cref=\"InvalidOperationException\">No suitable activator was found.</exception>\n        private IGrainReferenceActivator CreateActivator(GrainType grainType, GrainInterfaceType interfaceType)\n        {\n            lock (_lockObj)\n            {\n                if (!_activators.TryGetValue((grainType, interfaceType), out var entry))\n                {\n                    IGrainReferenceActivator activator = null;\n                    foreach (var provider in _providers)\n                    {\n                        if (provider.TryGet(grainType, interfaceType, out activator))\n                        {\n                            break;\n                        }\n                    }\n\n                    if (activator is null)\n                    {\n                        throw new InvalidOperationException($\"Unable to find an {nameof(IGrainReferenceActivatorProvider)} for grain type {grainType}\");\n                    }\n\n                    entry = activator;\n                    _activators = new(_activators) { [(grainType, interfaceType)] = entry };\n                }\n\n                return entry;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Creates grain references which do not have any specified grain interface, only a target grain id.\n    /// </summary>\n    internal class UntypedGrainReferenceActivatorProvider : IGrainReferenceActivatorProvider\n    {\n        private readonly CopyContextPool _copyContextPool;\n        private readonly CodecProvider _codecProvider;\n        private readonly GrainVersionManifest _versionManifest;\n        private readonly IServiceProvider _serviceProvider;\n        private IGrainReferenceRuntime _grainReferenceRuntime;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UntypedGrainReferenceActivatorProvider\"/> class.\n        /// </summary>\n        /// <param name=\"manifest\">The grain version manifest.</param>\n        /// <param name=\"copyContextPool\">The copy context pool.</param>\n        /// <param name=\"codecProvider\">The serialization codec provider.</param>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        public UntypedGrainReferenceActivatorProvider(\n            GrainVersionManifest manifest,\n            CodecProvider codecProvider,\n            CopyContextPool copyContextPool,\n            IServiceProvider serviceProvider)\n        {\n            _versionManifest = manifest;\n            _codecProvider = codecProvider;\n            _copyContextPool = copyContextPool;\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public bool TryGet(GrainType grainType, GrainInterfaceType interfaceType, out IGrainReferenceActivator activator)\n        {\n            if (!interfaceType.IsDefault)\n            {\n                activator = default;\n                return false;\n            }\n\n            var interfaceVersion = _versionManifest.GetLocalVersion(interfaceType);\n\n            var runtime = _grainReferenceRuntime ??= _serviceProvider.GetRequiredService<IGrainReferenceRuntime>();\n            var shared = new GrainReferenceShared(\n                grainType,\n                interfaceType,\n                interfaceVersion,\n                runtime,\n                InvokeMethodOptions.None,\n                _codecProvider,\n                _copyContextPool,\n                _serviceProvider);\n            activator = new UntypedGrainReferenceActivator(shared);\n            return true;\n        }\n\n        /// <summary>\n        /// Activator for grain references which have no specified grain interface, only a target grain id.\n        /// </summary>\n        private class UntypedGrainReferenceActivator : IGrainReferenceActivator\n        {\n            private readonly GrainReferenceShared _shared;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"UntypedGrainReferenceActivator \"/> class.\n            /// </summary>\n            /// <param name=\"shared\">The shared functionality for all grains of a given type.</param>\n            public UntypedGrainReferenceActivator(GrainReferenceShared shared)\n            {\n                _shared = shared;\n            }\n\n            /// <inheritdoc />\n            public GrainReference CreateReference(GrainId grainId)\n            {\n                return GrainReference.FromGrainId(_shared, grainId);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Provides functionality for mapping from a <see cref=\"GrainInterfaceType\"/> to the corresponding generated proxy type.\n    /// </summary>\n    internal class RpcProvider\n    {\n        private readonly TypeConverter _typeConverter;\n        private readonly Dictionary<GrainInterfaceType, Type> _mapping;\n\n        /// <summary>\n        /// Initializes a new  instance of the <see cref=\"RpcProvider\"/> class.\n        /// </summary>\n        /// <param name=\"config\">The local type manifest.</param>\n        /// <param name=\"resolver\">The grain interface type to grain type resolver.</param>\n        /// <param name=\"typeConverter\">The type converter, for generic parameter.</param>\n        public RpcProvider(\n            IOptions<TypeManifestOptions> config,\n            GrainInterfaceTypeResolver resolver,\n            TypeConverter typeConverter)\n        {\n            _typeConverter = typeConverter;\n            var proxyTypes = config.Value.InterfaceProxies;\n            _mapping = new Dictionary<GrainInterfaceType, Type>();\n            foreach (var proxyType in proxyTypes)\n            {\n                if (!typeof(IAddressable).IsAssignableFrom(proxyType))\n                {\n                    continue;\n                }\n\n                var type = proxyType switch\n                {\n                    { IsGenericType: true } => proxyType.GetGenericTypeDefinition(),\n                    _ => proxyType\n                };\n\n                var grainInterface = GetMainInterface(type);\n                var id = resolver.GetGrainInterfaceType(grainInterface);\n                _mapping[id] = type;\n            }\n\n            static Type GetMainInterface(Type t)\n            {\n                var all = t.GetInterfaces();\n                Type result = null;\n                foreach (var candidate in all)\n                {\n                    if (result is null)\n                    {\n                        result = candidate;\n                    }\n                    else\n                    {\n                        if (result.IsAssignableFrom(candidate))\n                        {\n                            result = candidate;\n                        }\n                    }\n                }\n\n                return result switch\n                {\n                    { IsGenericType: true } => result.GetGenericTypeDefinition(),\n                    _ => result\n                };\n            }\n        }\n\n        /// <summary>\n        /// Gets the generated proxy object type corresponding to the specified <see cref=\"GrainInterfaceType\"/>.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type.</param>\n        /// <param name=\"result\">The proxy object type.</param>\n        /// <returns>A value indicating whether a suitable type was found and was able to be constructed.</returns>\n        public bool TryGet(GrainInterfaceType interfaceType, [NotNullWhen(true)] out Type result)\n        {\n            GrainInterfaceType lookupId;\n            Type[] args;\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var genericId))\n            {\n                lookupId = genericId.GetGenericGrainType().Value;\n                args = genericId.GetArguments(_typeConverter);\n            }\n            else\n            {\n                lookupId = interfaceType;\n                args = default;\n            }\n\n            if (!_mapping.TryGetValue(lookupId, out result))\n            {\n                return false;\n            }\n\n            if (args is not null)\n            {\n                result = result.MakeGenericType(args);\n            }\n\n            return true;\n        }\n    }\n\n    /// <summary>\n    /// Creates grain references using generated proxy objects.\n    /// </summary>\n    internal class GrainReferenceActivatorProvider : IGrainReferenceActivatorProvider\n    {\n        private readonly CopyContextPool _copyContextPool;\n        private readonly CodecProvider _codecProvider;\n        private readonly IServiceProvider _serviceProvider;\n        private readonly GrainPropertiesResolver _propertiesResolver;\n        private readonly RpcProvider _rpcProvider;\n        private readonly GrainVersionManifest _grainVersionManifest;\n        private IGrainReferenceRuntime _grainReferenceRuntime;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceActivatorProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"propertiesResolver\">The grain property resolver.</param>\n        /// <param name=\"rpcProvider\">The proxy object type provider.</param>\n        /// <param name=\"copyContextPool\">The copy context pool.</param>\n        /// <param name=\"codecProvider\">The serialization codec provider.</param>\n        /// <param name=\"grainVersionManifest\">The grain version manifest.</param>\n        public GrainReferenceActivatorProvider(\n            IServiceProvider serviceProvider,\n            GrainPropertiesResolver propertiesResolver,\n            RpcProvider rpcProvider,\n            CopyContextPool copyContextPool,\n            CodecProvider codecProvider,\n            GrainVersionManifest grainVersionManifest)\n        {\n            _serviceProvider = serviceProvider;\n            _propertiesResolver = propertiesResolver;\n            _rpcProvider = rpcProvider;\n            _copyContextPool = copyContextPool;\n            _codecProvider = codecProvider;\n            _grainVersionManifest = grainVersionManifest;\n        }\n\n        /// <inheritdoc />\n        public bool TryGet(GrainType grainType, GrainInterfaceType interfaceType, out IGrainReferenceActivator activator)\n        {\n            if (!_rpcProvider.TryGet(interfaceType, out var proxyType))\n            {\n                activator = default;\n                return false;\n            }\n\n            var unordered = false;\n            var properties = _propertiesResolver.GetGrainProperties(grainType);\n            if (properties.Properties.TryGetValue(WellKnownGrainTypeProperties.Unordered, out var unorderedString)\n                && string.Equals(\"true\", unorderedString, StringComparison.OrdinalIgnoreCase))\n            {\n                unordered = true;\n            }\n\n            var interfaceVersion = _grainVersionManifest.GetLocalVersion(interfaceType);\n\n            var invokeMethodOptions = unordered ? InvokeMethodOptions.Unordered : InvokeMethodOptions.None;\n            var runtime = _grainReferenceRuntime ??= _serviceProvider.GetRequiredService<IGrainReferenceRuntime>();\n            var shared = new GrainReferenceShared(\n                grainType,\n                interfaceType,\n                interfaceVersion,\n                runtime,\n                invokeMethodOptions,\n                _codecProvider,\n                _copyContextPool,\n                _serviceProvider);\n            activator = new GrainReferenceActivator(proxyType, shared);\n            return true;\n        }\n\n        /// <summary>\n        /// Creates grain references for a given grain type and grain interface type.\n        /// </summary>\n        private sealed class GrainReferenceActivator : IGrainReferenceActivator\n        {\n            private readonly GrainReferenceShared _shared;\n            private readonly Func<GrainReferenceShared, IdSpan, GrainReference> _create;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"GrainReferenceActivator\"/> class.\n            /// </summary>\n            /// <param name=\"referenceType\">The generated proxy object type.</param>\n            /// <param name=\"shared\">The functionality shared between all grain references for a specified grain type and grain interface type.</param>\n            public GrainReferenceActivator(Type referenceType, GrainReferenceShared shared)\n            {\n                _shared = shared;\n\n                var ctor = referenceType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, new[] { typeof(GrainReferenceShared), typeof(IdSpan) })\n                    ?? throw new SerializerException(\"Invalid proxy type: \" + referenceType);\n\n                var method = new DynamicMethod(referenceType.Name, typeof(GrainReference), new[] { typeof(object), typeof(GrainReferenceShared), typeof(IdSpan) });\n                var il = method.GetILGenerator();\n                // arg0 is unused for better delegate performance (avoids argument shuffling thunk)\n                il.Emit(OpCodes.Ldarg_1);\n                il.Emit(OpCodes.Ldarg_2);\n                il.Emit(OpCodes.Newobj, ctor);\n                il.Emit(OpCodes.Ret);\n                _create = method.CreateDelegate<Func<GrainReferenceShared, IdSpan, GrainReference>>();\n            }\n\n            public GrainReference CreateReference(GrainId grainId) => _create(_shared, grainId.Key);\n        }\n    }\n\n    /// <summary>\n    /// Functionality for getting the appropriate <see cref=\"IGrainReferenceActivator\"/> for a given <see cref=\"GrainType\"/> and <see cref=\"GrainInterfaceType\"/>.\n    /// </summary>\n    public interface IGrainReferenceActivatorProvider\n    {\n        /// <summary>\n        /// Gets a grain reference activator for the provided arguments.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"interfaceType\">The grain interface type.</param>\n        /// <param name=\"activator\">The grain activator.</param>\n        /// <returns>A value indicating whether a suitable grain activator was found.</returns>\n        bool TryGet(GrainType grainType, GrainInterfaceType interfaceType, [NotNullWhen(true)] out IGrainReferenceActivator activator);\n    }\n\n    /// <summary>\n    /// Creates grain references.\n    /// </summary>\n    public interface IGrainReferenceActivator\n    {\n        /// <summary>\n        /// Creates a new grain reference.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id.</param>\n        /// <returns>A new grain reference.</returns>\n        public GrainReference CreateReference(GrainId grainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Hosting/OrleansClientGenericHostExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\n\nnamespace Microsoft.Extensions.Hosting\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IHostBuilder\"/>.\n    /// </summary>\n    public static class OrleansClientGenericHostExtensions\n    {\n        private static readonly Type MarkerType = typeof(OrleansBuilderMarker);\n\n        /// <summary>\n        /// Configures the host app builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// Note that this method shouldn't be used in conjunction with HostApplicationBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostAppBuilder\"/> was null.</exception>\n        public static HostApplicationBuilder UseOrleansClient(this HostApplicationBuilder hostAppBuilder)\n            => UseOrleansClient(hostAppBuilder, _ => { });\n\n        /// <summary>\n        /// Configures the host app builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method shouldn't be used in conjunction with HostApplicationBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostAppBuilder\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static HostApplicationBuilder UseOrleansClient(\n            this HostApplicationBuilder hostAppBuilder,\n            Action<IClientBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostAppBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            hostAppBuilder.Services.AddOrleansClient(hostAppBuilder.Configuration, configureDelegate);\n\n            return hostAppBuilder;\n        }\n\n        /// Configures the host app builder to host an Orleans client.\n        /// <summary>\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// Note that this method shouldn't be used in conjunction with IHostApplicationBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostAppBuilder\"/> was null.</exception>\n        public static IHostApplicationBuilder UseOrleansClient(this IHostApplicationBuilder hostAppBuilder)\n            => UseOrleansClient(hostAppBuilder, _ => { });\n\n        /// <summary>\n        /// Configures the host app builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method shouldn't be used in conjunction with IHostApplicationBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostAppBuilder\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static IHostApplicationBuilder UseOrleansClient(\n            this IHostApplicationBuilder hostAppBuilder,\n            Action<IClientBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostAppBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            hostAppBuilder.Services.AddOrleansClient(hostAppBuilder.Configuration, configureDelegate);\n\n            return hostAppBuilder;\n        }\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// Note that this method should not be used in conjunction with IHostBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostBuilder\"/> was null.</exception>\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder) => hostBuilder.UseOrleansClient((_, _) => { });\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method should not be used in conjunction with IHostBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostBuilder\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder, Action<IClientBuilder> configureDelegate) =>\n            hostBuilder.UseOrleansClient((_, clientBuilder) => configureDelegate(clientBuilder));\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans client.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method should not be used in conjunction with IHostBuilder.UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"hostBuilder\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder, Action<HostBuilderContext, IClientBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            if (hostBuilder.Properties.ContainsKey(\"HasOrleansSiloBuilder\"))\n            {\n                throw GetOrleansSiloAddedException();\n            }\n\n            hostBuilder.Properties[\"HasOrleansClientBuilder\"] = \"true\";\n\n            return hostBuilder.ConfigureServices((ctx, services) => configureDelegate(ctx, AddOrleansClient(services, ctx.Configuration)));\n        }\n\n        /// <summary>\n        /// Configures the service collection to host an Orleans client.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The service collection.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method should not be used in conjunction with UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"services\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static IServiceCollection AddOrleansClient(this IServiceCollection services, Action<IClientBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            var clientBuilder = AddOrleansClient(services, configuration: null);\n            configureDelegate(clientBuilder);\n            return services;\n        }\n\n        /// <summary>\n        /// Configures the service collection to host an Orleans client.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the client.</param>\n        /// <returns>The service collection.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IClientBuilder\"/> instance will result in one client being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// Note that this method should not be used in conjunction with UseOrleans, since UseOrleans includes a client automatically.\n        /// </remarks>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"services\"/> was null or <paramref name=\"configureDelegate\"/> was null.</exception>\n        public static IServiceCollection AddOrleansClient(this IServiceCollection services, IConfiguration configuration, Action<IClientBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            var clientBuilder = AddOrleansClient(services, configuration: configuration);\n            configureDelegate(clientBuilder);\n            return services;\n        }\n\n        private static IClientBuilder AddOrleansClient(IServiceCollection services, IConfiguration configuration)\n        {\n            configuration ??= new ConfigurationBuilder().Build();\n            IClientBuilder clientBuilder = default;\n            foreach (var descriptor in services.Where(d => d.ServiceType.Equals(MarkerType)))\n            {\n                var instance = (OrleansBuilderMarker)descriptor.ImplementationInstance;\n                clientBuilder = instance.BuilderInstance switch\n                {\n                    IClientBuilder existingBuilder => existingBuilder,\n                    _ => throw GetOrleansSiloAddedException()\n                };\n            }\n\n            if (clientBuilder is null)\n            {\n                clientBuilder = new ClientBuilder(services, configuration);\n                services.AddSingleton(new OrleansBuilderMarker(clientBuilder));\n            }\n\n            return clientBuilder;\n        }\n\n        private static OrleansConfigurationException GetOrleansSiloAddedException() =>\n            new(\"Do not use UseOrleans with UseOrleansClient. If you want a client and server in the same process, only UseOrleans is necessary and the UseOrleansClient call can be removed.\");\n    }\n\n    /// <summary>\n    /// Marker type used for storing a builder in a service collection.\n    /// </summary>\n    internal sealed class OrleansBuilderMarker\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansBuilderMarker\"/> class.\n        /// </summary>\n        /// <param name=\"builderInstance\">The builder instance.</param>\n        public OrleansBuilderMarker(object builderInstance) => BuilderInstance = builderInstance;\n\n        /// <summary>\n        /// Gets the builder instance.\n        /// </summary>\n        public object BuilderInstance { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/IDs/GenericGrainInterfaceType.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Utilities;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a <see cref=\"GrainInterfaceType\"/> that is parameterized using type parameters.\n    /// </summary>\n    [Immutable]\n    public readonly struct GenericGrainInterfaceType\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GenericGrainInterfaceType\"/> struct.\n        /// </summary>\n        /// <param name=\"value\">The underlying grain interface type.</param>\n        private GenericGrainInterfaceType(GrainInterfaceType value, int arity)\n        {\n            Value = value;\n            Arity = arity;\n        }\n\n        /// <summary>\n        /// The underlying <see cref=\"GrainInterfaceType\"/>\n        /// </summary>\n        public GrainInterfaceType Value { get; }\n\n        /// <summary>\n        /// The arity of the generic type.\n        /// </summary>\n        public int Arity { get; }\n\n        /// <summary>\n        /// Returns <see langword=\"true\" /> if this instance contains concrete type parameters.\n        /// </summary>\n        public bool IsConstructed => TypeConverterExtensions.IsConstructed(this.Value.Value);\n\n        /// <summary>\n        /// Returns the generic interface id corresponding to the provided value.\n        /// </summary>\n        public static bool TryParse(GrainInterfaceType grainType, out GenericGrainInterfaceType result)\n        {\n            if (grainType.IsDefault)\n            {\n                result = default;\n                return false;\n            }\n\n            var arity = TypeConverterExtensions.GetGenericTypeArity(grainType.Value);\n            if (arity > 0)\n            {\n                result = new GenericGrainInterfaceType(grainType, arity);\n                return true;\n            }\n\n            result = default;\n            return false;\n        }\n\n        /// <summary>\n        /// Returns a non-constructed version of this instance.\n        /// </summary>\n        public GenericGrainInterfaceType GetGenericGrainType()\n        {\n            var generic = TypeConverterExtensions.GetDeconstructed(Value.Value);\n            return new GenericGrainInterfaceType(new GrainInterfaceType(generic), Arity);\n        }\n\n        /// <summary>\n        /// Returns a constructed version of this instance.\n        /// </summary>\n        public GenericGrainInterfaceType Construct(TypeConverter formatter, params Type[] typeArguments)\n        {\n            if (Arity != typeArguments.Length)\n            {\n                ThrowIncorrectArgumentLength(typeArguments);\n            }\n\n            var constructed = formatter.GetConstructed(this.Value.Value, typeArguments);\n            return new GenericGrainInterfaceType(new GrainInterfaceType(constructed), Arity);\n        }\n\n        /// <summary>\n        /// Returns the type arguments which this instance was constructed with.\n        /// </summary>\n        public Type[] GetArguments(TypeConverter formatter) => formatter.GetArguments(this.Value.Value);\n\n        /// <summary>\n        /// Returns a UTF8 interpretation of the current instance.\n        /// </summary>\n        public override string ToString() => Value.ToString();\n\n        [DoesNotReturn]\n        private void ThrowIncorrectArgumentLength(Type[] typeArguments) => throw new ArgumentException($\"Incorrect number of type arguments, {typeArguments.Length}, to construct a generic grain type with arity {Arity}.\", nameof(typeArguments));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/IDs/GenericGrainType.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Utilities;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a <see cref=\"GrainType\"/> that is parameterized using type parameters.\n    /// </summary>\n    [Immutable]\n    public readonly struct GenericGrainType : IEquatable<GenericGrainType>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GenericGrainType\"/> struct.\n        /// </summary>\n        /// <param name=\"grainType\">The underlying grain type.</param>\n        /// <param name=\"arity\">The generic arity of the grain type.</param>\n        private GenericGrainType(GrainType grainType, int arity)\n        {\n            GrainType = grainType;\n            Arity = arity;\n        }\n\n        /// <summary>\n        /// The underlying grain type.\n        /// </summary>\n        public GrainType GrainType { get; }\n\n        /// <summary>\n        /// The generic arity of the grain type.\n        /// </summary>\n        public int Arity { get; }\n\n        /// <summary>\n        /// Returns <see langword=\"true\" /> if this instance contains concrete type parameters.\n        /// </summary>\n        public bool IsConstructed => TypeConverterExtensions.IsConstructed(this.GrainType.Value);\n\n        /// <summary>\n        /// Returns the generic grain type corresponding to the provided value.\n        /// </summary>\n        public static bool TryParse(GrainType grainType, out GenericGrainType result)\n        {\n            var arity = TypeConverterExtensions.GetGenericTypeArity(grainType.Value);\n            if (arity > 0)\n            {\n                result = new GenericGrainType(grainType, arity);\n                return true;\n            }\n\n            result = default;\n            return false;\n        }\n\n        /// <summary>\n        /// Returns a non-constructed version of this instance.\n        /// </summary>\n        public GenericGrainType GetUnconstructedGrainType()\n        {\n            var generic = TypeConverterExtensions.GetDeconstructed(GrainType.Value);\n            return new GenericGrainType(new GrainType(generic), Arity);\n        }\n\n        /// <summary>\n        /// Returns a constructed version of this instance.\n        /// </summary>\n        public GenericGrainType Construct(TypeConverter formatter, params Type[] typeArguments)\n        {\n            if (Arity != typeArguments.Length)\n            {\n                ThrowIncorrectArgumentLength(typeArguments);\n            }\n\n            var constructed = formatter.GetConstructed(this.GrainType.Value, typeArguments);\n            return new GenericGrainType(new GrainType(constructed), Arity);\n        }\n\n        /// <summary>\n        /// Gets the type arguments using the provided type converter.\n        /// </summary>\n        /// <param name=\"converter\">The type converter</param>\n        /// <returns>The type arguments.</returns>\n        public Type[] GetArguments(TypeConverter converter) => converter.GetArguments(this.GrainType.Value);\n\n        /// <inheritdoc/>\n        public override string ToString() => this.GrainType.ToString();\n\n        /// <inheritdoc/>\n        public bool Equals(GenericGrainType other) => this.GrainType.Equals(other.GrainType);\n\n        /// <inheritdoc/>\n        public override bool Equals(object obj) => obj is GenericGrainType other && this.Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.GrainType.GetHashCode();\n\n        [DoesNotReturn]\n        private void ThrowIncorrectArgumentLength(Type[] typeArguments) => throw new ArgumentException($\"Incorrect number of type arguments, {typeArguments.Length}, to construct a generic grain type with arity {Arity}.\", nameof(typeArguments));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/ClusterClientLifecycle.cs",
    "content": "\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Implementation of <see cref=\"IClusterClientLifecycle\"/>.\n    /// </summary>\n    internal class ClusterClientLifecycle : LifecycleSubject, IClusterClientLifecycle\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterClientLifecycle\"/> class.\n        /// </summary>\n        /// <param name=\"logger\">The logger.</param>\n        public ClusterClientLifecycle(ILogger logger) : base(logger)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/ClusterClientLifecycleExtensions.cs",
    "content": "\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Extensions for <see cref=\"ILifecycleParticipant{TLifecycleObservable}\"/>.\n    /// </summary>\n    public static class LifecycleParticipantExtensions\n    {\n        /// <summary>\n        /// Conforms components written to participate with any <see cref=\"ILifecycleObservable\"/> to take part in specific lifecycles.\n        /// </summary>\n        /// <typeparam name=\"TLifecycle\">The target lifecycle observer type.</typeparam>\n        /// <param name=\"participant\">The lifecycle participant.</param>\n        /// <returns>An adapter wrapped around <paramref name=\"participant\"/> which implements <see cref=\"ILifecycleParticipant{TLifecycle}\"/>.</returns>\n        public static ILifecycleParticipant<TLifecycle> ParticipateIn<TLifecycle>(this ILifecycleParticipant<ILifecycleObservable> participant)\n            where TLifecycle : ILifecycleObservable\n        {\n            return new Bridge<TLifecycle>(participant);\n        }\n\n        /// <summary>\n        /// Adapts one lifecycle participant to a lifecycle participant of another observer type.\n        /// </summary>\n        /// <typeparam name=\"TLifecycle\"></typeparam>\n        private class Bridge<TLifecycle> : ILifecycleParticipant<TLifecycle>\n            where TLifecycle : ILifecycleObservable\n        {\n            private readonly ILifecycleParticipant<ILifecycleObservable> participant;\n            public Bridge(ILifecycleParticipant<ILifecycleObservable> participant)\n            {\n                this.participant = participant;\n            }\n\n            public void Participate(TLifecycle lifecycle)\n            {\n                this.participant?.Participate(lifecycle);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/IClusterClientLifecycle.cs",
    "content": "namespace Orleans\n{\n    /// <summary>\n    /// A <see cref=\"ILifecycleObservable\"/> marker type for client lifecycles.\n    /// </summary>\n    public interface IClusterClientLifecycle : ILifecycleObservable\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/LifecycleSubject.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Provides functionality for observing a lifecycle.\n    /// </summary>\n    /// <remarks>\n    /// <list type=\"bullet\">\n    /// <item><description>Single use, does not support multiple start/stop cycles.</description></item>\n    /// <item><description>Once started, no other observers can be subscribed.</description></item>\n    /// <item><description>OnStart starts stages in order until first failure or cancellation.</description></item>\n    /// <item><description>OnStop stops states in reverse order starting from highest started stage.</description></item>\n    /// <item><description>OnStop stops all stages regardless of errors even if canceled.</description></item>\n    /// </list>\n    /// </remarks>\n    public abstract partial class LifecycleSubject : ILifecycleSubject\n    {\n        private readonly List<OrderedObserver> subscribers = [];\n        protected readonly ILogger Logger;\n        private int? _highStage = null;\n\n        protected LifecycleSubject(ILogger logger)\n        {\n            ArgumentNullException.ThrowIfNull(logger);\n            Logger = logger;\n        }\n\n        /// <summary>\n        /// Gets the name of the specified numeric stage.\n        /// </summary>\n        /// <param name=\"stage\">The stage number.</param>\n        /// <returns>The name of the stage.</returns>\n        protected virtual string GetStageName(int stage) => stage.ToString();\n\n        /// <summary>\n        /// Gets the collection of all stage numbers and their corresponding names.\n        /// </summary>\n        /// <seealso cref=\"ServiceLifecycleStage\"/>\n        /// <param name=\"type\">The lifecycle stage class.</param>\n        /// <returns>The collection of all stage numbers and their corresponding names.</returns>\n        protected static ImmutableDictionary<int, string> GetStageNames(Type type)\n        {\n            try\n            {\n                var result = ImmutableDictionary.CreateBuilder<int, string>();\n                var fields = type.GetFields(\n                    System.Reflection.BindingFlags.Static\n                    | System.Reflection.BindingFlags.Public\n                    | System.Reflection.BindingFlags.NonPublic);\n                foreach (var field in fields)\n                {\n                    if (typeof(int).IsAssignableFrom(field.FieldType))\n                    {\n                        try\n                        {\n                            var value = (int)field.GetValue(null);\n                            result[value] = $\"{field.Name} ({value})\";\n                        }\n                        catch\n                        {\n                            // Ignore.\n                        }\n                    }\n                }\n\n                return result.ToImmutable();\n            }\n            catch\n            {\n                return ImmutableDictionary<int, string>.Empty;\n            }\n        }\n\n        /// <summary>\n        /// Logs the observed performance of an <see cref=\"OnStart\"/> call.\n        /// </summary>\n        /// <param name=\"stage\">The stage.</param>\n        /// <param name=\"elapsed\">The period of time which elapsed before <see cref=\"OnStart\"/> completed once it was initiated.</param>\n        protected virtual void PerfMeasureOnStart(int stage, TimeSpan elapsed)\n        {\n            LogLifecycleStageStarted(Logger, GetStageName(stage), elapsed);\n        }\n\n        /// <inheritdoc />\n        public virtual async Task OnStart(CancellationToken cancellationToken = default)\n        {\n            if (this._highStage.HasValue) throw new InvalidOperationException(\"Lifecycle has already been started.\");\n            try\n            {\n                foreach (IGrouping<int, OrderedObserver> observerGroup in this.subscribers\n                    .GroupBy(orderedObserver => orderedObserver.Stage)\n                    .OrderBy(group => group.Key))\n                {\n                    if (cancellationToken.IsCancellationRequested)\n                    {\n                        throw new OrleansLifecycleCanceledException($\"Lifecycle start canceled at stage '{GetStageName(observerGroup.Key)}' by request.\");\n                    }\n\n                    var stage = observerGroup.Key;\n                    this._highStage = stage;\n                    var stopWatch = ValueStopwatch.StartNew();\n                    await Task.WhenAll(observerGroup.Select(orderedObserver => CallOnStart(orderedObserver, cancellationToken)));\n                    stopWatch.Stop();\n                    this.PerfMeasureOnStart(stage, stopWatch.Elapsed);\n\n                    this.OnStartStageCompleted(stage);\n                }\n            }\n            catch (Exception ex) when (ex is not OrleansLifecycleCanceledException)\n            {\n                LogErrorLifecycleStartFailure(Logger, ex, _highStage is { } highStage ? GetStageName(highStage) : \"Unknown\");\n                throw;\n            }\n\n            static Task CallOnStart(OrderedObserver observer, CancellationToken cancellationToken)\n            {\n                try\n                {\n                    return observer.Observer?.OnStart(cancellationToken) ?? Task.CompletedTask;\n                }\n                catch (Exception ex)\n                {\n                    return Task.FromException(ex);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Signifies that <see cref=\"OnStart\"/> completed.\n        /// </summary>\n        /// <param name=\"stage\">The stage which completed.</param>\n        protected virtual void OnStartStageCompleted(int stage) { }\n\n        /// <summary>\n        /// Logs the observed performance of an <see cref=\"OnStop\"/> call.\n        /// </summary>\n        /// <param name=\"stage\">The stage.</param>\n        /// <param name=\"elapsed\">The period of time which elapsed before <see cref=\"OnStop\"/> completed once it was initiated.</param>\n        protected virtual void PerfMeasureOnStop(int stage, TimeSpan elapsed)\n        {\n            LogLifecycleStageStopped(Logger, GetStageName(stage), elapsed);\n        }\n\n        /// <inheritdoc />\n        public virtual async Task OnStop(CancellationToken cancellationToken = default)\n        {\n            // if not started, do nothing\n            if (!this._highStage.HasValue) return;\n            var loggedCancellation = false;\n            foreach (IGrouping<int, OrderedObserver> observerGroup in this.subscribers\n                // include up to highest started stage\n                .Where(orderedObserver => orderedObserver.Stage <= _highStage && orderedObserver.Observer != null)\n                .GroupBy(orderedObserver => orderedObserver.Stage)\n                .OrderByDescending(group => group.Key))\n            {\n                if (cancellationToken.IsCancellationRequested && !loggedCancellation)\n                {\n                    LogWarningLifecycleStopCanceled(Logger, GetStageName(observerGroup.Key));\n                    loggedCancellation = true;\n                }\n\n                var stage = observerGroup.Key;\n                this._highStage = stage;\n                try\n                {\n                    var stopwatch = ValueStopwatch.StartNew();\n                    await Task.WhenAll(observerGroup.Select(orderedObserver => orderedObserver?.Observer is not null ? CallObserverStopAsync(orderedObserver.Observer, cancellationToken) : Task.CompletedTask));\n                    stopwatch.Stop();\n                    this.PerfMeasureOnStop(stage, stopwatch.Elapsed);\n                }\n                catch (Exception ex)\n                {\n                    LogWarningLifecycleStopFailure(Logger, ex, _highStage is { } highStage ? GetStageName(highStage) : \"Unknown\");\n                }\n\n                this.OnStopStageCompleted(stage);\n            }\n        }\n\n        protected virtual Task CallObserverStopAsync(ILifecycleObserver observer, CancellationToken cancellationToken)\n        {\n            try\n            {\n                return observer.OnStop(cancellationToken) ?? Task.CompletedTask;\n            }\n            catch (Exception ex)\n            {\n                return Task.FromException(ex);\n            }\n        }\n\n        /// <summary>\n        /// Signifies that <see cref=\"OnStop\"/> completed.\n        /// </summary>\n        /// <param name=\"stage\">The stage which completed.</param>\n        protected virtual void OnStopStageCompleted(int stage) { }\n\n        public virtual IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer)\n        {\n            if (observer == null) throw new ArgumentNullException(nameof(observer));\n            if (this._highStage.HasValue) throw new InvalidOperationException(\"Lifecycle has already been started.\");\n\n            var orderedObserver = new OrderedObserver(stage, observer);\n            this.subscribers.Add(orderedObserver);\n            return orderedObserver;\n        }\n\n        /// <summary>\n        /// Represents a <see cref=\"ILifecycleObservable\"/>'s participation in a given lifecycle stage.\n        /// </summary>\n        private class OrderedObserver : IDisposable\n        {\n            /// <summary>\n            /// Gets the observer.\n            /// </summary>\n            public ILifecycleObserver Observer { get; private set; }\n\n            /// <summary>\n            /// Gets the stage which the observer is participating in.\n            /// </summary>\n            public int Stage { get; }\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"OrderedObserver\"/> class.\n            /// </summary>\n            /// <param name=\"stage\">The stage which the observer is participating in.</param>\n            /// <param name=\"observer\">The participating observer.</param>\n            public OrderedObserver(int stage, ILifecycleObserver observer)\n            {\n                this.Stage = stage;\n                this.Observer = observer;\n            }\n\n            /// <inheritdoc />\n            public void Dispose() => Observer = null;\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.LifecycleStartFailure,\n            Level = LogLevel.Error,\n            Message = \"Lifecycle start canceled due to errors at stage '{Stage}'.\"\n        )]\n        private static partial void LogErrorLifecycleStartFailure(ILogger logger, Exception ex, string stage);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.LifecycleStopFailure,\n            Level = LogLevel.Warning,\n            Message = \"Stopping lifecycle encountered an error at stage '{Stage}'. Continuing to stop.\"\n        )]\n        private static partial void LogWarningLifecycleStopFailure(ILogger logger, Exception ex, string stage);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Lifecycle stop operations canceled at stage '{Stage}' by request.\"\n        )]\n        private static partial void LogWarningLifecycleStopCanceled(ILogger logger, string stage);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Level = LogLevel.Trace,\n            Message = \"Starting lifecycle stage '{Stage}' took '{Elapsed}'.\"\n        )]\n        private static partial void LogLifecycleStageStarted(ILogger logger, string stage, TimeSpan elapsed);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Level = LogLevel.Trace,\n            Message = \"Stopping lifecycle stage '{Stage}' took '{Elapsed}'.\"\n        )]\n        private static partial void LogLifecycleStageStopped(ILogger logger, string stage, TimeSpan elapsed);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/MigrationContext.cs",
    "content": "#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Runtime;\n\n[GenerateSerializer, Immutable, Alias(\"MigrationCtx\")]\ninternal sealed class MigrationContext : IDehydrationContext, IRehydrationContext, IDisposable, IEnumerable<string>, IBufferWriter<byte>\n{\n#if NET9_0_OR_GREATER\n    [NonSerialized]\n    private readonly Lock _lock = new();\n#else\n    [NonSerialized]\n    private readonly object _lock = new();\n#endif\n\n    [NonSerialized]\n    internal readonly SerializerSessionPool _sessionPool;\n\n    [GeneratedActivatorConstructor]\n    public MigrationContext(SerializerSessionPool sessionPool)\n    {\n        _sessionPool = sessionPool;\n    }\n\n    [Id(0), Immutable]\n    private Dictionary<string, (int Offset, int Length)> _indices = new(StringComparer.Ordinal);\n\n    [Id(1), Immutable]\n    private PooledBuffer _buffer = new();\n\n    public void AddBytes(string key, ReadOnlySpan<byte> value)\n    {\n        lock (_lock)\n        {\n            _indices.Add(key, (_buffer.Length, value.Length));\n            _buffer.Write(value);\n        }\n    }\n\n    public void AddBytes<T>(string key, Action<T, IBufferWriter<byte>> valueWriter, T value)\n    {\n        lock (_lock)\n        {\n            var startOffset = _buffer.Length;\n            valueWriter(value, this);\n            var endOffset = _buffer.Length;\n            _indices.Add(key, (startOffset, endOffset - startOffset));\n        }\n    }\n\n    public bool TryAddValue<T>(string key, T? value)\n    {\n        if (_sessionPool.CodecProvider.TryGetCodec<T>() is { } codec)\n        {\n            lock (_lock)\n            {\n                ref var indexValue = ref CollectionsMarshal.GetValueRefOrAddDefault(_indices, key, out var exists);\n                if (!exists)\n                {\n                    var startOffset = _buffer.Length;\n\n                    using var session = _sessionPool.GetSession();\n                    var writer = Writer.Create(this, session);\n                    codec.WriteField(ref writer, 0, typeof(T), value!);\n                    writer.Commit();\n\n                    var endOffset = _buffer.Length;\n                    indexValue = (Offset: startOffset, Length: endOffset - startOffset);\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public IEnumerable<string> Keys => this;\n\n    public void Reset()\n    {\n        lock (_lock)\n        {\n            _indices = [];\n            _buffer.Reset();\n            _buffer = default;\n        }\n    }\n\n    public void Dispose() => Reset();\n\n    public bool TryGetBytes(string key, out ReadOnlySequence<byte> value)\n    {\n        lock (_lock)\n        {\n            if (_indices.TryGetValue(key, out var record))\n            {\n                value = _buffer.AsReadOnlySequence().Slice(record.Offset, record.Length);\n                return true;\n            }\n        }\n\n        value = default;\n        return false;\n    }\n\n    public bool TryGetValue<T>(string key, [NotNullWhen(true)] out T? value)\n    {\n        lock (_lock)\n        {\n            if (_indices.TryGetValue(key, out var record) && _sessionPool.CodecProvider.TryGetCodec<T>() is { } codec)\n            {\n                using var session = _sessionPool.GetSession();\n                var source = _buffer.Slice(record.Offset, record.Length);\n                var reader = Reader.Create(source, session);\n                var field = reader.ReadFieldHeader();\n                value = codec.ReadValue(ref reader, field);\n                return value is not null;\n            }\n        }\n\n        value = default;\n        return false;\n    }\n\n    // Implemented on this class to prevent the need to repeatedly box & unbox _buffer.\n    void IBufferWriter<byte>.Advance(int count) => _buffer.Advance(count);\n    Memory<byte> IBufferWriter<byte>.GetMemory(int sizeHint) => _buffer.GetMemory(sizeHint);\n    Span<byte> IBufferWriter<byte>.GetSpan(int sizeHint) => _buffer.GetSpan(sizeHint);\n\n    IEnumerator<string> IEnumerable<string>.GetEnumerator() => new Enumerator(this);\n    IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this);\n\n    private sealed class Enumerator(MigrationContext context) : IEnumerator<string>, IEnumerator\n    {\n        private Dictionary<string, (int Offset, int Length)>.KeyCollection.Enumerator _value = context._indices.Keys.GetEnumerator();\n\n        public string Current => _value.Current;\n        object IEnumerator.Current => Current;\n        public void Dispose() => _value.Dispose();\n        public bool MoveNext() => _value.MoveNext();\n        public void Reset()\n        {\n            var boxed = (IEnumerator)_value;\n            boxed.Reset();\n            _value = (Dictionary<string, (int Offset, int Length)>.KeyCollection.Enumerator)boxed;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/ServiceLifecycle.cs",
    "content": "using System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans;\n\n#nullable enable\n\n/// <summary>\n/// Allows consumers to observe and participate in the client/silo's lifecycle.\n/// </summary>\npublic interface IServiceLifecycle\n{\n    /// <summary>\n    /// Triggered when the client/silo has fully started and is ready to accept traffic.\n    /// </summary>\n    IServiceLifecycleStage Started { get; }\n\n    /// <summary>\n    /// Triggered when the client/silo is beginning the shutdown process.\n    /// </summary>\n    IServiceLifecycleStage Stopping { get; }\n\n    /// <summary>\n    /// Triggered when the client/silo has completed its shutdown process.\n    /// </summary>\n    IServiceLifecycleStage Stopped { get; }\n}\n\ninternal sealed class ServiceLifecycle<TLifecycleObservable>(ILogger<ServiceLifecycle<TLifecycleObservable>> logger) :\n    IServiceLifecycle, ILifecycleParticipant<TLifecycleObservable>\n        where TLifecycleObservable : ILifecycleObservable\n{\n    private readonly ServiceLifecycleNotificationStage _started = new(logger, \"Started\");\n    private readonly ServiceLifecycleNotificationStage _stopping = new(logger, \"Stopping\");\n    private readonly ServiceLifecycleNotificationStage _stopped = new(logger, \"Stopped\");\n\n    public IServiceLifecycleStage Started => _started;\n    public IServiceLifecycleStage Stopping => _stopping;\n    public IServiceLifecycleStage Stopped => _stopped;\n\n    public void Participate(TLifecycleObservable lifecycle)\n    {\n        lifecycle.Subscribe(\n            observerName: nameof(Started),\n            stage: ServiceLifecycleStage.Active,\n            onStart: _started.NotifyCompleted,\n            onStop: _ => Task.CompletedTask);\n\n        lifecycle.Subscribe(\n            observerName: nameof(Stopping),\n            stage: ServiceLifecycleStage.Active,\n            onStart: _ => Task.CompletedTask,\n            onStop: _stopping.NotifyCompleted);\n\n        lifecycle.Subscribe(\n            observerName: nameof(Stopped),\n            stage: ServiceLifecycleStage.RuntimeInitialize - 1,\n            onStart: _ => Task.CompletedTask,\n            onStop: _stopped.NotifyCompleted);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/ServiceLifecycleNotificationStage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans;\n\n#nullable enable\n\n/// <summary>\n/// Represents a specific stage in the client / silo lifecycle.\n/// </summary>\npublic interface IServiceLifecycleStage\n{\n    /// <summary>\n    /// Gets a cancellation token that is triggered when this stage completes.\n    /// </summary>\n    /// <remarks>Avoid registering callbacks in this token, prefer\n    /// <see cref=\"Register(Func{object?, CancellationToken, Task}, object?, bool)\"/> instead.</remarks>\n    CancellationToken Token { get; }\n\n    /// <summary>\n    /// Waits for this lifecycle stage to complete.\n    /// </summary>\n    /// <param name=\"cancellationToken\">\n    /// A token used to cancel the wait. This does not cancel the lifecycle stage itself!\n    /// </param>\n    Task WaitAsync(CancellationToken cancellationToken = default);\n\n    /// <summary>\n    /// Registers a callback to be executed during this lifecycle stage.\n    /// </summary>\n    /// <param name=\"callback\">\n    /// <para>The asynchronous operation to perform.</para>\n    /// <para><strong>Never call <see cref=\"WaitAsync(CancellationToken)\"/></strong> inside a callback, as it will result in a deadlock!</para>\n    /// </param>\n    /// <param name=\"terminateOnError\">\n    /// If <c>true</c>, the client / silo will shut down if there is a failure;\n    /// otherwise an error will be logged and the client / silo will continue to the next stage.\n    /// </param>\n    /// <param name=\"state\">An optional state to pass.</param>\n    /// <remarks>\n    /// Disposing the returned value removes the callback from the lifecycle stage.\n    /// This is useful for components that have a shorter lifespan than the client / silo to prevent holding onto the reference,\n    /// and ensure that cleanup logic is not executed for components that are no longer active.\n    /// </remarks>\n    IDisposable Register(Func<object?, CancellationToken, Task> callback, object? state = null, bool terminateOnError = true);\n}\n\ninternal sealed partial class ServiceLifecycleNotificationStage(ILogger logger, string name) : IServiceLifecycleStage\n{\n    // We use this so that late registrations can still be executed, otherwise\n    // we'd need to rely on the TCS which means we'd need to set it *before* the callbacks\n    // have been executed, ideally we should fire the TCS only after non-late registered callbacks have completed.\n    private bool _isNotifyingOrHasCompleted;\n\n    private readonly object _lock = new();\n    private readonly List<StageParticipant> _participants = [];\n    private readonly CancellationTokenSource _cts = new();\n    private readonly TaskCompletionSource _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n    public CancellationToken Token => _cts.Token;\n\n    public Task WaitAsync(CancellationToken cancellationToken) => _tcs.Task.WaitAsync(cancellationToken);\n\n    public IDisposable Register(Func<object?, CancellationToken, Task> callback, object? state, bool terminateOnError)\n    {\n        ArgumentNullException.ThrowIfNull(callback);\n\n        var participant = new StageParticipant(this, callback, state, terminateOnError);\n\n        lock (_lock)\n        {\n            if (_isNotifyingOrHasCompleted)\n            {\n                LogStageAlreadyCompleted(logger, name);\n\n                _ = Task.Run(() => ExecuteLateCallback(participant));\n\n                return participant;\n            }\n\n            _participants.Add(participant);\n        }\n\n        return participant;\n\n        async Task ExecuteLateCallback(StageParticipant participant)\n        {\n            try\n            {\n                // The original token passed to NotifyCompleted (typically related to the silo startup/shutdown) must be \"gone\" by now.\n                // Since the stage has already completed, there is no impending timeout for this late registration, so we pass CancellationToken.None.\n                // For late participants we do not check for termination!\n\n                await participant.ExecuteAsync(CancellationToken.None).ConfigureAwait(false);\n            }\n            catch (Exception ex)\n            {\n                LogLateCallbackError(logger, ex, name);\n            }\n        }\n    }\n\n    public async Task NotifyCompleted(CancellationToken cancellationToken)\n    {\n        List<StageParticipant>? snapshot;\n\n        lock (_lock)\n        {\n            if (_isNotifyingOrHasCompleted)\n            {\n                snapshot = null;\n            }\n            else\n            {\n                _isNotifyingOrHasCompleted = true;\n                snapshot = [.. _participants];\n            }\n        }\n\n        if (snapshot is null)\n        {\n            await _tcs.Task.WaitAsync(cancellationToken).ConfigureAwait(false);\n            return;\n        }\n\n        var tasks = new List<Task>(snapshot.Count + 1)\n            {\n                CancelTokenAsync()\n            };\n\n        foreach (var participant in snapshot)\n        {\n            tasks.Add(ExecuteParticipantAsync(participant, cancellationToken));\n        }\n\n        var allTasks = Task.WhenAll(tasks);\n\n        try\n        {\n            await allTasks.ConfigureAwait(false);\n            _tcs.SetResult();\n        }\n        catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)\n        {\n            _tcs.TrySetCanceled(cancellationToken);\n        }\n        catch (Exception ex)\n        {\n            // Note that awaiting WhenAll returns only the first exception, and we want to show all, if there are multiple.\n            if (allTasks.Exception is { } aggEx)\n            {\n                var flattened = aggEx.Flatten();\n\n                if (flattened.InnerExceptions.Count == 1)\n                {\n                    // For cleaner reporting in case one callback throws.\n                    _tcs.SetException(flattened.InnerExceptions[0]);\n                }\n                else\n                {\n                    // Otherwise we let the user see all failures.\n                    _tcs.SetException(flattened);\n                }\n            }\n            else\n            {\n                // Unlikely but hey!\n                _tcs.SetException(ex);\n            }\n\n            // We throw here regardless, because it's the callback participant who controls whether to TerminateOnError or not.\n            throw;\n        }\n    }\n\n    private async Task CancelTokenAsync()\n    {\n        try\n        {\n            await _cts.CancelAsync().ConfigureAwait(false);\n        }\n        catch (Exception ex)\n        {\n            // Should not happen if callers respect the contract to register\n            // callbacks with the proper method, but it can happen!\n            LogCancellationCallbackError(logger, ex, name);\n        }\n    }\n\n    private async Task ExecuteParticipantAsync(StageParticipant participant, CancellationToken cancellationToken)\n    {\n        if (cancellationToken.IsCancellationRequested)\n        {\n            return;\n        }\n\n        try\n        {\n            await participant.ExecuteAsync(cancellationToken).ConfigureAwait(false);\n        }\n        catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)\n        {\n            // If the upstream token triggered this, we rethrow so WhenAll knows we stopped due to cancellation.\n            throw;\n        }\n        catch (Exception ex)\n        {\n            LogCallbackError(logger, ex, name);\n\n            if (participant.TerminateOnError)\n            {\n                // This will cause WhenAll to fault, eventually triggering _tcs.SetException above.\n                // NotifyCompleted relies on us to throw in case TerminateOnError is set to true.\n                throw;\n            }\n        }\n    }\n\n    private void Unregister(StageParticipant participant)\n    {\n        lock (_lock)\n        {\n            _participants.Remove(participant);\n        }\n    }\n\n    private record StageParticipant(ServiceLifecycleNotificationStage Stage,\n        Func<object?, CancellationToken, Task> Callback, object? State, bool TerminateOnError) : IDisposable\n    {\n        public Task ExecuteAsync(CancellationToken cancellationToken) => Callback(State, cancellationToken);\n        void IDisposable.Dispose() => Stage.Unregister(this);\n    }\n\n    [LoggerMessage(Level = LogLevel.Information, Message = \"Lifecycle stage = '{StageName}' has already completed. Executing callback immediately.\")]\n    public static partial void LogStageAlreadyCompleted(ILogger logger, string stageName);\n\n    [LoggerMessage(Level = LogLevel.Error, Message = \"Error executing late-registered callback for lifecycle stage = '{StageName}'\")]\n    public static partial void LogLateCallbackError(ILogger logger, Exception exception, string stageName);\n\n    [LoggerMessage(Level = LogLevel.Information, Message = \"Lifecycle stage = '{StageName}' has been canceled.\")]\n    public static partial void LogStageCanceled(ILogger logger, string stageName);\n\n    [LoggerMessage(Level = LogLevel.Error, Message = \"Error executing callback for lifecycle stage = '{StageName}'\")]\n    public static partial void LogCallbackError(ILogger logger, Exception exception, string stageName);\n\n    [LoggerMessage(Level = LogLevel.Error, Message = \"An exception occurred inside a CancellationToken callback for lifecycle stage = '{StageName}'\")]\n    public static partial void LogCancellationCallbackError(ILogger logger, Exception exception, string stageName);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Lifecycle/ServiceLifecycleStage.cs",
    "content": "\nnamespace Orleans\n{\n    /// <summary>\n    /// Lifecycle stages of an Orleans client or silo.\n    /// </summary>\n    public static class ServiceLifecycleStage\n    {\n        /// <summary>\n        /// First valid stage in service's lifecycle\n        /// </summary>\n        public const int First = int.MinValue;\n\n        /// <summary>\n        /// Initialize runtime\n        /// </summary>\n        public const int RuntimeInitialize = 2000;\n\n        /// <summary>\n        /// Start runtime services\n        /// </summary>\n        public const int RuntimeServices = 4000;\n\n        /// <summary>\n        /// Initialize runtime storage\n        /// </summary>\n        public const int RuntimeStorageServices = 6000;\n\n        /// <summary>\n        /// Start runtime services\n        /// </summary>\n        public const int RuntimeGrainServices = 8000;\n\n        /// <summary>\n        /// After runtime services have started.\n        /// </summary>\n        public const int AfterRuntimeGrainServices = 8100;\n\n        /// <summary>\n        /// Start application layer services\n        /// </summary>\n        public const int ApplicationServices = 10000;\n\n        /// <summary>\n        /// Service will be active after this step.\n        /// It should only be used by the membership oracle \n        /// and the gateway, no other component should run\n        /// at this stage\n        /// </summary>\n        public const int BecomeActive = Active-1;\n\n        /// <summary>\n        /// Service is active.\n        /// </summary>\n        public const int Active = 20000;\n\n        /// <summary>\n        /// Last valid stage in service's lifecycle\n        /// </summary>\n        public const int Last = int.MaxValue;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/ClientClusterManifestProvider.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Messaging;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Utilities;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// <see cref=\"IClusterManifestProvider\"/> implementation for external clients.\n    /// </summary>\n    internal partial class ClientClusterManifestProvider : IClusterManifestProvider, IAsyncDisposable, IDisposable\n    {\n        private readonly TaskCompletionSource<bool> _initialized = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly ILogger<ClientClusterManifestProvider> _logger;\n        private readonly TypeManagementOptions _typeManagementOptions;\n        private readonly IServiceProvider _services;\n        private readonly LocalClientDetails _localClientDetails;\n        private readonly GatewayManager _gatewayManager;\n        private readonly AsyncEnumerable<ClusterManifest> _updates;\n        private readonly CancellationTokenSource _shutdownCts = new CancellationTokenSource();\n        private ClusterManifest _current;\n        private Task? _runTask;\n\n        public ClientClusterManifestProvider(\n            IServiceProvider services,\n            LocalClientDetails localClientDetails,\n            GatewayManager gatewayManager,\n            ILogger<ClientClusterManifestProvider> logger,\n            ClientManifestProvider clientManifestProvider,\n            IOptions<TypeManagementOptions> typeManagementOptions)\n        {\n            _logger = logger;\n            _typeManagementOptions = typeManagementOptions.Value;\n            _services = services;\n            _localClientDetails = localClientDetails;\n            _gatewayManager = gatewayManager;\n            LocalGrainManifest = clientManifestProvider.ClientManifest;\n\n            // Create a fake manifest for the very first generation, which only includes the local client's manifest.\n            var builder = ImmutableDictionary.CreateBuilder<SiloAddress, GrainManifest>();\n            builder.Add(_localClientDetails.ClientAddress, LocalGrainManifest);\n            _current = new ClusterManifest(MajorMinorVersion.MinValue, builder.ToImmutable());\n\n            _updates = new AsyncEnumerable<ClusterManifest>(\n                initialValue: _current,\n                updateValidator: (previous, proposed) => proposed.Version > previous.Version,\n                onPublished: update => Interlocked.Exchange(ref _current, update));\n        }\n\n        /// <inheritdoc />\n        public ClusterManifest Current => _current;\n\n        /// <inheritdoc />\n        public IAsyncEnumerable<ClusterManifest> Updates => _updates;\n\n        /// <inheritdoc />\n        public GrainManifest LocalGrainManifest { get; }\n\n        /// <summary>\n        /// Starts this service.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> which completes once the service has started.</returns>\n        public Task StartAsync()\n        {\n            _runTask = Task.Run(RunAsync);\n            return _initialized.Task;\n        }\n\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                _shutdownCts.Cancel();\n\n                if (_runTask is { } task)\n                {\n                    await task.WaitAsync(cancellationToken);\n                }\n            }\n            catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)\n            {\n                LogGracefulShutdownCanceled(_logger);\n            }\n            catch (Exception exception)\n            {\n                LogStoppingClusterManifestProvider(_logger, exception);\n            }\n        }\n\n        private async Task RunAsync()\n        {\n            try\n            {\n                var grainFactory = _services.GetRequiredService<IInternalGrainFactory>();\n                SiloAddress? gateway = null;\n                IClusterManifestSystemTarget? provider = null;\n                var minorVersion = 0;\n                var gatewayVersion = MajorMinorVersion.MinValue;\n                while (!_shutdownCts.IsCancellationRequested)\n                {\n                    // Select a new gateway if the current one is not available.\n                    // This could be caused by a temporary issue or a permanent gateway failure.\n                    if (gateway is null || !_gatewayManager.IsGatewayAvailable(gateway))\n                    {\n                        gateway = _gatewayManager.GetLiveGateway();\n                        if (gateway is null)\n                        {\n                            await Task.Delay(StandardExtensions.Min(_typeManagementOptions.TypeMapRefreshInterval, TimeSpan.FromMilliseconds(500)), _shutdownCts.Token);\n                            continue;\n                        }\n\n                        provider = grainFactory.GetGrain<IClusterManifestSystemTarget>(SystemTargetGrainId.Create(Constants.ManifestProviderType, gateway).GrainId);\n\n                        // Accept any cluster manifest version from the new gateway.\n                        // Since the minor version of the manifest is specific to each gateway, we reset it to the lowest possible value.\n                        // This means that it is possible to receive the an older or equivalent cluster manifest when the gateway changes.\n                        // That hiccup is addressed by resetting the expected manifest version and merging incomplete manifests until a complete\n                        // manifest is received.\n                        gatewayVersion = MajorMinorVersion.MinValue;\n                    }\n\n                    Debug.Assert(provider is not null);\n\n                    try\n                    {\n                        var updateResult = await GetClusterManifestUpdate(provider, gatewayVersion).WaitAsync(_shutdownCts.Token);\n                        if (updateResult is null)\n                        {\n                            // There was no newer cluster manifest, so wait for the next refresh interval and try again.\n                            await Task.Delay(_typeManagementOptions.TypeMapRefreshInterval, _shutdownCts.Token);\n                            continue;\n                        }\n\n                        gatewayVersion = updateResult.Version;\n\n                        // If the manifest does not contain all active servers, merge with the existing manifest until it does.\n                        // This prevents reversed progress at the expense of including potentially defunct silos.\n                        ImmutableDictionary<SiloAddress, GrainManifest> siloManifests;\n                        if (!updateResult.IncludesAllActiveServers)\n                        {\n                            // Merge manifests until the manifest contains all active servers.\n                            var mergedSilos = _current.Silos.ToBuilder();\n                            mergedSilos.Add(_localClientDetails.ClientAddress, LocalGrainManifest);\n                            foreach (var kvp in updateResult.SiloManifests)\n                            {\n                                mergedSilos[kvp.Key] = kvp.Value;\n                            }\n\n                            siloManifests = mergedSilos.ToImmutable();\n                        }\n                        else\n                        {\n                            siloManifests = updateResult.SiloManifests.Add(_localClientDetails.ClientAddress, LocalGrainManifest);\n                        }\n\n                        var updatedManifest = new ClusterManifest(new MajorMinorVersion(gatewayVersion.Major, ++minorVersion), siloManifests);\n                        if (!_updates.TryPublish(updatedManifest))\n                        {\n                            await Task.Delay(StandardExtensions.Min(_typeManagementOptions.TypeMapRefreshInterval, TimeSpan.FromMilliseconds(500)), _shutdownCts.Token);\n                            continue;\n                        }\n\n                        _initialized.TrySetResult(true);\n\n                        LogRefreshedClusterManifest(_logger);\n\n                        await Task.Delay(_typeManagementOptions.TypeMapRefreshInterval, _shutdownCts.Token);\n                    }\n                    catch (OperationCanceledException) when (_shutdownCts.IsCancellationRequested)\n                    {\n                        // Ignore during shutdown.\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorTryingToGetClusterManifest(_logger, exception, gateway);\n                        await Task.Delay(StandardExtensions.Min(_typeManagementOptions.TypeMapRefreshInterval, TimeSpan.FromSeconds(5)), _shutdownCts.Token).SuppressThrowing();\n\n                        // Reset the gateway so that another will be selected on the next iteration.\n                        gateway = null;\n                    }\n                }\n            }\n            finally\n            {\n                _initialized.TrySetResult(false);\n\n                LogStoppedRefreshingClusterManifest(_logger);\n            }\n        }\n\n        private async Task<ClusterManifestUpdate?> GetClusterManifestUpdate(IClusterManifestSystemTarget provider, MajorMinorVersion previousVersion)\n        {\n            try\n            {\n                // First, attempt to call the new API, which provides more information.\n                // This returns null if there is no newer cluster manifest.\n                return await provider.GetClusterManifestUpdate(previousVersion);\n            }\n            catch (Exception exception)\n            {\n                LogFailedToFetchClusterManifestUpdate(_logger, exception, provider);\n\n                // If the provider does not support the new API, fall back to the old one.\n                var manifest = await provider.GetClusterManifest();\n                var result = new ClusterManifestUpdate(manifest.Version, manifest.Silos, includesAllActiveServers: true);\n                return result;\n            }\n        }\n\n        /// <inheritdoc />\n        public async ValueTask DisposeAsync()\n        {\n            if (_shutdownCts.IsCancellationRequested)\n            {\n                return;\n            }\n\n            _shutdownCts.Cancel();\n            if (_runTask is Task task)\n            {\n                await task.SuppressThrowing();\n            }\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            _shutdownCts.Cancel();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Graceful shutdown of cluster manifest provider was canceled.\"\n        )]\n        private static partial void LogGracefulShutdownCanceled(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error stopping cluster manifest provider.\"\n        )]\n        private static partial void LogStoppingClusterManifestProvider(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Refreshed cluster manifest.\"\n        )]\n        private static partial void LogRefreshedClusterManifest(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error trying to get cluster manifest from gateway '{Gateway}'.\"\n        )]\n        private static partial void LogErrorTryingToGetClusterManifest(ILogger logger, Exception exception, SiloAddress gateway);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopped refreshing cluster manifest.\"\n        )]\n        private static partial void LogStoppedRefreshingClusterManifest(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to fetch cluster manifest update from '{Provider}'.\"\n        )]\n        private static partial void LogFailedToFetchClusterManifestUpdate(ILogger logger, Exception exception, IClusterManifestSystemTarget provider);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/ClientManifestProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Creates a manifest of the locally available grain interface types.\n    /// </summary>\n    internal class ClientManifestProvider\n    {\n        public ClientManifestProvider(\n            IEnumerable<IGrainInterfacePropertiesProvider> grainInterfacePropertiesProviders,\n            IOptions<GrainTypeOptions> grainTypeOptions,\n            GrainInterfaceTypeResolver interfaceTypeResolver)\n        {\n            var interfaces = CreateInterfaceManifest(grainInterfacePropertiesProviders, grainTypeOptions, interfaceTypeResolver);\n            this.ClientManifest = new GrainManifest(ImmutableDictionary<GrainType, GrainProperties>.Empty, interfaces);\n        }\n\n        /// <summary>\n        /// Gets the client manifest.\n        /// </summary>\n        public GrainManifest ClientManifest { get; }\n\n        private static ImmutableDictionary<GrainInterfaceType, GrainInterfaceProperties> CreateInterfaceManifest(\n            IEnumerable<IGrainInterfacePropertiesProvider> propertyProviders,\n            IOptions<GrainTypeOptions> grainTypeOptions,\n            GrainInterfaceTypeResolver interfaceTypeResolver)\n        {\n            var builder = ImmutableDictionary.CreateBuilder<GrainInterfaceType, GrainInterfaceProperties>();\n            foreach (var grainInterface in grainTypeOptions.Value.Interfaces)\n            {\n                var interfaceId = interfaceTypeResolver.GetGrainInterfaceType(grainInterface);\n                var properties = new Dictionary<string, string>();\n                foreach (var provider in propertyProviders)\n                {\n                    provider.Populate(grainInterface, interfaceId, properties);\n                }\n\n                var result = new GrainInterfaceProperties(properties.ToImmutableDictionary());\n                if (builder.TryGetValue(interfaceId, out var grainInterfaceProperty))\n                {\n                    throw new InvalidOperationException($\"An entry with the key {interfaceId} is already present.\"\n                        + $\"\\nExisting: {grainInterfaceProperty.ToDetailedString()}\\nTrying to add: {result.ToDetailedString()}\"\n                        + \"\\nConsider using the [GrainInterfaceType(\\\"name\\\")] attribute to give these interfaces unique names.\");\n                }\n\n                builder.Add(interfaceId, result);\n            }\n\n            return builder.ToImmutable();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/GrainBindings.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Threading;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Describes the bindings for a given grain type.\n    /// </summary>\n    /// <remarks>\n    /// Bindings are a way to declaratively connect grains with other resources.\n    /// </remarks>\n    public class GrainBindings\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainBindings\"/> class.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"bindings\">The bindings for the specified grain type.</param>\n        public GrainBindings(GrainType grainType, ImmutableArray<ImmutableDictionary<string, string>> bindings)\n        {\n            this.GrainType = grainType;\n            this.Bindings = bindings;\n        }\n\n        /// <summary>\n        /// Gets the grain type.\n        /// </summary>\n        public GrainType GrainType { get; }\n\n        /// <summary>\n        /// Gets the bindings for the specified grain type.\n        /// </summary>\n        public ImmutableArray<ImmutableDictionary<string, string>> Bindings { get; }\n    }\n\n    /// <summary>\n    /// Resolves bindings for grain types.\n    /// </summary>\n    public class GrainBindingsResolver\n    {\n        private const string BindingPrefix = WellKnownGrainTypeProperties.BindingPrefix + \".\";\n        private const char BindingIndexEnd = '.';\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly ConcurrentDictionary<GenericGrainType, GrainType> _genericMapping = new ConcurrentDictionary<GenericGrainType, GrainType>();\n        private readonly IClusterManifestProvider _clusterManifestProvider;\n        private Cache _cache;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainBindingsResolver\"/> class.\n        /// </summary>\n        /// <param name=\"clusterManifestProvider\">\n        /// The cluster manifest provider.\n        /// </param>\n        public GrainBindingsResolver(IClusterManifestProvider clusterManifestProvider)\n        {\n            _clusterManifestProvider = clusterManifestProvider;\n            _cache = BuildCache(_clusterManifestProvider.Current);\n        }\n\n        /// <summary>\n        /// Gets bindings for the provided grain type.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        /// <returns>The grain bindings.</returns>\n        public GrainBindings GetBindings(GrainType grainType)\n        {\n            GrainType lookupType;\n            if (GenericGrainType.TryParse(grainType, out var generic))\n            {\n                if (!_genericMapping.TryGetValue(generic, out lookupType))\n                {\n                    lookupType = _genericMapping[generic] = generic.GetUnconstructedGrainType().GrainType;\n                }\n            }\n            else\n            {\n                lookupType = grainType;\n            }\n\n            var cache = GetCache();\n            if (cache.Map.TryGetValue(lookupType, out var result))\n            {\n                return result;\n            }\n\n            return new GrainBindings(grainType, ImmutableArray<ImmutableDictionary<string, string>>.Empty);\n        }\n\n        /// <summary>\n        /// Gets all bindings.\n        /// </summary>\n        /// <returns>The collection of all grain bindings.</returns>\n        public (MajorMinorVersion Version, ImmutableDictionary<GrainType, GrainBindings> Bindings) GetAllBindings()\n        {\n            var cache = GetCache();\n            return (cache.Version, cache.Map);\n        }\n\n        private Cache GetCache()\n        {\n            var cache = _cache;\n            var manifest = _clusterManifestProvider.Current;\n            if (manifest.Version == cache.Version)\n            {\n                return cache;\n            }\n\n            lock (_lockObj)\n            {\n                cache = _cache;\n                manifest = _clusterManifestProvider.Current;\n                if (manifest.Version == cache.Version)\n                {\n                    return cache;\n                }\n\n                return _cache = BuildCache(manifest);\n            }\n        }\n\n        private static Cache BuildCache(ClusterManifest clusterManifest)\n        {\n            var result = new Dictionary<GrainType, GrainBindings>();\n\n            var bindings = new Dictionary<string, Dictionary<string, string>>();\n            foreach (var manifest in clusterManifest.AllGrainManifests)\n            {\n                foreach (var grainType in manifest.Grains)\n                {\n                    var id = grainType.Key;\n                    if (result.ContainsKey(id)) continue;\n                    bindings.Clear();\n                    foreach (var pair in grainType.Value.Properties)\n                    {\n                        if (TryExtractBindingProperty(pair, out var binding))\n                        {\n                            if (!bindings.TryGetValue(binding.Index, out var properties))\n                            {\n                                bindings[binding.Index] = properties = new Dictionary<string, string>();\n                            }\n\n                            properties.Add(binding.Key, binding.Value);\n                        }\n                    }\n\n                    var builder = ImmutableArray.CreateBuilder<ImmutableDictionary<string, string>>();\n                    foreach (var binding in bindings.Values)\n                    {\n                        builder.Add(ImmutableDictionary.CreateRange(binding));\n                    }\n\n                    result.Add(id, new GrainBindings(id, builder.ToImmutable()));\n                }\n            }\n\n            return new Cache(clusterManifest.Version, result.ToImmutableDictionary());\n\n            bool TryExtractBindingProperty(KeyValuePair<string, string> property, out (string Index, string Key, string Value) result)\n            {\n                if (!property.Key.StartsWith(BindingPrefix, StringComparison.Ordinal)\n                    || property.Key.IndexOf(BindingIndexEnd, BindingPrefix.Length) is int indexEndIndex && indexEndIndex < 0)\n                {\n                    result = default;\n                    return false;\n                }\n\n                var bindingIndex = property.Key[BindingPrefix.Length..indexEndIndex];\n                var bindingKey = property.Key[(indexEndIndex + 1)..];\n\n                if (string.IsNullOrWhiteSpace(bindingIndex) || string.IsNullOrWhiteSpace(bindingKey))\n                {\n                    result = default;\n                    return false;\n                }\n\n                result = (bindingIndex, bindingKey, property.Value);\n                return true;\n            }\n        }\n\n        private class Cache\n        {\n            public Cache(MajorMinorVersion version, ImmutableDictionary<GrainType, GrainBindings> map)\n            {\n                this.Version = version;\n                this.Map = map;\n            }\n\n            public MajorMinorVersion Version { get; }\n\n            public ImmutableDictionary<GrainType, GrainBindings> Map { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/GrainInterfaceTypeResolver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Associates a <see cref=\"GrainInterfaceType\"/> with a <see cref=\"Type\" />.\n    /// </summary>\n    public class GrainInterfaceTypeResolver\n    {\n        private readonly IGrainInterfaceTypeProvider[] _providers;\n        private readonly TypeConverter _typeConverter;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainInterfaceTypeResolver\"/> class.\n        /// </summary>\n        /// <param name=\"providers\">\n        /// The collection of grain interface type providers.\n        /// </param>\n        /// <param name=\"typeConverter\">\n        /// The type converter, used for generic parameter names.\n        /// </param>\n        public GrainInterfaceTypeResolver(\n            IEnumerable<IGrainInterfaceTypeProvider> providers,\n            TypeConverter typeConverter)\n        {\n            _providers = providers.ToArray();\n            _typeConverter = typeConverter;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"GrainInterfaceType\"/> for the provided interface.\n        /// </summary>\n        /// <param name=\"type\">The grain interface.</param>\n        /// <returns>The <see cref=\"GrainInterfaceType\"/> for the provided interface.</returns>\n        public GrainInterfaceType GetGrainInterfaceType(Type type)\n        {\n            if (!type.IsInterface)\n            {\n                throw new ArgumentException($\"Argument {nameof(type)} must be an interface. Provided value, \\\"{type}\\\", is not an interface.\", nameof(type));\n            }\n\n            // Configured providers take precedence\n            foreach (var provider in _providers)\n            {\n                if (provider.TryGetGrainInterfaceType(type, out var interfaceType))\n                {\n                    interfaceType = AddGenericParameters(interfaceType, type);\n                    return interfaceType;\n                }\n            }\n\n            // Conventions are used as a fallback.\n            return GetGrainInterfaceTypeByConvention(type);\n        }\n\n        /// <summary>\n        /// Gets a grain interface type based upon the default conventions.\n        /// </summary>\n        /// <param name=\"type\">The grain interface type.</param>\n        /// <returns>The grain interface type name.</returns>\n        public GrainInterfaceType GetGrainInterfaceTypeByConvention(Type type)\n        {\n            var result = GrainInterfaceType.Create(_typeConverter.Format(type, input => input switch\n            {\n                AssemblyQualifiedTypeSpec asm => asm.Type, // drop outer assembly qualification\n                _ => input\n            }));\n\n            result = AddGenericParameters(result, type);\n            return result;\n        }\n\n        private GrainInterfaceType AddGenericParameters(GrainInterfaceType result, Type type)\n        {\n            if (GenericGrainInterfaceType.TryParse(result, out var genericGrainType)\n                && type.IsConstructedGenericType\n                && !type.ContainsGenericParameters\n                && !genericGrainType.IsConstructed)\n            {\n                result = genericGrainType.Construct(_typeConverter, type.GetGenericArguments()).Value;\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/GrainPropertiesResolver.cs",
    "content": "using System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Responsible for resolving <see cref=\"GrainProperties\"/> for <see cref=\"GrainType\"/> values.\n    /// </summary>\n    public class GrainPropertiesResolver\n    {\n        private readonly IClusterManifestProvider _clusterManifestProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainPropertiesResolver\"/> class.\n        /// </summary>\n        /// <param name=\"clusterManifestProvider\">\n        /// The cluster manifest provider.\n        /// </param>\n        public GrainPropertiesResolver(IClusterManifestProvider clusterManifestProvider)\n        {\n            _clusterManifestProvider = clusterManifestProvider;\n        }\n\n        /// <summary>\n        /// Gets the grain properties for the provided type.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        /// <returns>\n        /// The grain properties.\n        /// </returns>\n        public GrainProperties GetGrainProperties(GrainType grainType)\n        {\n            if (!TryGetGrainProperties(grainType, out var result))\n            {\n                //ThrowNotFoundException(grainType);\n                result = new GrainProperties(ImmutableDictionary<string, string>.Empty);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Gets the grain properties for the provided type.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        /// <param name=\"properties\">\n        /// The grain properties.\n        /// </param>\n        /// <returns>\n        /// A value indicating whether grain properties could be found for the provided grain type.\n        /// </returns>\n        public bool TryGetGrainProperties(GrainType grainType, [NotNullWhen(true)] out GrainProperties properties)\n        {\n            var clusterManifest = _clusterManifestProvider.Current;\n            if (clusterManifest is null)\n            {\n                properties = default;\n                return false;\n            }\n\n            GrainType lookupKey;\n            if (GenericGrainType.TryParse(grainType, out var generic))\n            {\n                lookupKey = generic.GetUnconstructedGrainType().GrainType;\n            }\n            else\n            {\n                lookupKey = grainType;\n            }\n\n            foreach (var manifest in clusterManifest.AllGrainManifests)\n            {\n                if (manifest.Grains.TryGetValue(lookupKey, out properties))\n                {\n                    return true;\n                }\n            }\n\n            properties = default;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/GrainTypeResolver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Associates a <see cref=\"GrainType\"/> with a grain class.\n    /// </summary>\n    public class GrainTypeResolver\n    {\n        private const string GrainSuffix = \"grain\";\n        private readonly IGrainTypeProvider[] _providers;\n        private readonly TypeConverter _typeConverter;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainTypeResolver\"/> class.\n        /// </summary>\n        /// <param name=\"resolvers\">\n        /// The grain type name providers.\n        /// </param>\n        /// <param name=\"argumentFormatter\">\n        /// The type converter, used to format generic parameters.\n        /// </param>\n        public GrainTypeResolver(\n            IEnumerable<IGrainTypeProvider> resolvers,\n            TypeConverter argumentFormatter)\n        {\n            _providers = resolvers.ToArray();\n            _typeConverter = argumentFormatter;\n        }\n\n        /// <summary>\n        /// Returns the grain type for the provided class.\n        /// </summary>\n        /// <param name=\"type\">The grain class.</param>\n        /// <returns>The grain type for the provided class.</returns>\n        public GrainType GetGrainType(Type type)\n        {\n            if (!type.IsClass || type.IsAbstract)\n            {\n                throw new ArgumentException($\"Argument {nameof(type)} must be a non-abstract class. Provided value, \\\"{type}\\\", is not a class.\", nameof(type));\n            }\n\n            // Configured providers take precedence\n            foreach (var provider in _providers)\n            {\n                if (provider.TryGetGrainType(type, out var grainType))\n                {\n                    grainType = AddGenericParameters(grainType, type);\n\n                    return grainType;\n                }\n            }\n\n            // Conventions are used as a fallback\n            return GetGrainTypeByConvention(type);\n        }\n\n        private GrainType GetGrainTypeByConvention(Type type)\n        {\n            var name = type.Name.ToLowerInvariant();\n\n            // Trim generic arity\n            var index = name.IndexOf('`');\n            if (index > 0)\n            {\n                name = name[..index];\n            }\n\n            // Trim \"Grain\" suffix\n            index = name.LastIndexOf(GrainSuffix);\n            if (index > 0 && name.Length - index == GrainSuffix.Length)\n            {\n                name = name[..index];\n            }\n\n            // Append the generic arity, eg typeof(MyListGrain<T>) would eventually become mylist`1\n            if (type.IsGenericType)\n            {\n                name = name + '`' + type.GetGenericArguments().Length;\n            }\n\n            var grainType = GrainType.Create(name);\n            grainType = AddGenericParameters(grainType, type);\n            return grainType;\n        }\n\n        private GrainType AddGenericParameters(GrainType grainType, Type type)\n        {\n            if (GenericGrainType.TryParse(grainType, out var genericGrainType)\n                && type.IsConstructedGenericType\n                && !type.ContainsGenericParameters\n                && !genericGrainType.IsConstructed)\n            {\n                var typeArguments = type.GetGenericArguments();\n                grainType = genericGrainType.Construct(_typeConverter, typeArguments).GrainType;\n            }\n\n            return grainType;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/GrainVersionManifest.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime.Versions\n{\n    /// <summary>\n    /// Functionality for querying the declared version of grain interfaces.\n    /// </summary>\n    internal class GrainVersionManifest\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly ConcurrentDictionary<GrainInterfaceType, GrainInterfaceType> _genericInterfaceMapping = new ConcurrentDictionary<GrainInterfaceType, GrainInterfaceType>();\n        private readonly ConcurrentDictionary<GrainType, GrainType> _genericGrainTypeMapping = new ConcurrentDictionary<GrainType, GrainType>();\n        private readonly IClusterManifestProvider _clusterManifestProvider;\n        private readonly Dictionary<GrainInterfaceType, ushort> _localVersions;\n        private Cache _cache;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainVersionManifest\"/> class.\n        /// </summary>\n        /// <param name=\"clusterManifestProvider\">The cluster manifest provider.</param>\n        public GrainVersionManifest(IClusterManifestProvider clusterManifestProvider)\n        {\n            _clusterManifestProvider = clusterManifestProvider;\n            _cache = BuildCache(clusterManifestProvider.Current);\n            _localVersions = BuildLocalVersionMap(clusterManifestProvider.LocalGrainManifest);\n        }\n\n        /// <summary>\n        /// Gets the current cluster manifest version.\n        /// </summary>\n        public MajorMinorVersion LatestVersion => _clusterManifestProvider.Current.Version;\n\n        /// <summary>\n        /// Gets the local version for a specified grain interface type.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type name.</param>\n        /// <returns>The version of the specified grain interface.</returns>\n        public ushort GetLocalVersion(GrainInterfaceType interfaceType)\n        {\n            if (_localVersions.TryGetValue(interfaceType, out var result))\n            {\n                return result;\n            }\n\n            if (_genericInterfaceMapping.TryGetValue(interfaceType, out var genericInterfaceId))\n            {\n                return GetLocalVersion(genericInterfaceId);\n            }\n\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var generic) && generic.IsConstructed)\n            {\n                var genericId = _genericInterfaceMapping[interfaceType] = generic.GetGenericGrainType().Value;\n                return GetLocalVersion(genericId);\n            }\n\n            return 0;\n        }\n\n        /// <summary>\n        /// Gets a collection of all known versions for a grain interface.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type name.</param>\n        /// <returns>All known versions for the specified grain interface.</returns>\n        public (MajorMinorVersion Version, ushort[] Result) GetAvailableVersions(GrainInterfaceType interfaceType)\n        {\n            var cache = GetCache();\n            if (cache.AvailableVersions.TryGetValue(interfaceType, out var result))\n            {\n                return (cache.Version, result);\n            }\n\n            if (_genericInterfaceMapping.TryGetValue(interfaceType, out var genericInterfaceId))\n            {\n                return GetAvailableVersions(genericInterfaceId);\n            }\n\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var generic) && generic.IsConstructed)\n            {\n                var genericId = _genericInterfaceMapping[interfaceType] = generic.GetGenericGrainType().Value;\n                return GetAvailableVersions(genericId);\n            }\n\n            // No versions available.\n            return (cache.Version, Array.Empty<ushort>());\n        }\n\n        /// <summary>\n        /// Gets the set of supported silos for a specified grain interface and version.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type name.</param>\n        /// <param name=\"version\">The grain interface version.</param>\n        /// <returns>The set of silos which support the specified grain interface type and version.</returns>\n        public (MajorMinorVersion Version, SiloAddress[] Result) GetSupportedSilos(GrainInterfaceType interfaceType, ushort version)\n        {\n            var cache = GetCache();\n            if (cache.SupportedSilosByInterface.TryGetValue((interfaceType, version), out var result))\n            {\n                return (cache.Version, result);\n            }\n\n            if (_genericInterfaceMapping.TryGetValue(interfaceType, out var genericInterfaceId))\n            {\n                return GetSupportedSilos(genericInterfaceId, version);\n            }\n\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var generic) && generic.IsConstructed)\n            {\n                var genericId = _genericInterfaceMapping[interfaceType] = generic.GetGenericGrainType().Value;\n                return GetSupportedSilos(genericId, version);\n            }\n\n            // No supported silos for this version.\n            return (cache.Version, Array.Empty<SiloAddress>());\n        }\n\n        /// <summary>\n        /// Gets the set of supported silos for the specified grain type.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <returns>The silos which support the specified grain type.</returns>\n        public (MajorMinorVersion Version, SiloAddress[] Result) GetSupportedSilos(GrainType grainType)\n        {\n            var cache = GetCache();\n            if (cache.SupportedSilosByGrainType.TryGetValue(grainType, out var result))\n            {\n                return (cache.Version, result);\n            }\n\n            if (_genericGrainTypeMapping.TryGetValue(grainType, out var genericGrainType))\n            {\n                return GetSupportedSilos(genericGrainType);\n            }\n\n            if (GenericGrainType.TryParse(grainType, out var generic) && generic.IsConstructed)\n            {\n                var genericId = _genericGrainTypeMapping[grainType] = generic.GetUnconstructedGrainType().GrainType;\n                return GetSupportedSilos(genericId);\n            }\n\n            // No supported silos for this type.\n            return (cache.Version, Array.Empty<SiloAddress>());\n        }\n\n        /// <summary>\n        /// Gets the set of supported silos for the specified combination of grain type, interface type, and version.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"interfaceType\">The grain interface type name.</param>\n        /// <param name=\"versions\">The grain interface version.</param>\n        /// <returns>The set of silos which support the specified grain.</returns>\n        public (MajorMinorVersion Version, Dictionary<ushort, SiloAddress[]> Result) GetSupportedSilos(GrainType grainType, GrainInterfaceType interfaceType, ushort[] versions)\n        {\n            var result = new Dictionary<ushort, SiloAddress[]>();\n\n            // Track the minimum version in case of inconsistent reads, since the caller can use that information to\n            // ensure they refresh on the next call.\n            MajorMinorVersion? minCacheVersion = null;\n            foreach (var version in versions)\n            {\n                (var cacheVersion, var silosWithGrain) = this.GetSupportedSilos(grainType);\n                if (!minCacheVersion.HasValue || cacheVersion > minCacheVersion.Value)\n                {\n                    minCacheVersion = cacheVersion;\n                }\n\n                // We need to sort this so the list of silos returned will\n                // be the same across all silos in the cluster\n                SiloAddress[] silosWithCorrectVersion;\n                (cacheVersion, silosWithCorrectVersion) = this.GetSupportedSilos(interfaceType, version);\n\n                if (!minCacheVersion.HasValue || cacheVersion > minCacheVersion.Value)\n                {\n                    minCacheVersion = cacheVersion;\n                }\n\n                result[version] = silosWithCorrectVersion\n                    .Intersect(silosWithGrain)\n                    .OrderBy(addr => addr)\n                    .ToArray();\n            }\n\n            if (!minCacheVersion.HasValue) minCacheVersion = MajorMinorVersion.Zero;\n\n            return (minCacheVersion.Value, result);\n        }\n\n        private Cache GetCache()\n        {\n            var cache = _cache;\n            var manifest = _clusterManifestProvider.Current;\n            if (manifest.Version == cache.Version)\n            {\n                return cache;\n            }\n\n            lock (_lockObj)\n            {\n                cache = _cache;\n                manifest = _clusterManifestProvider.Current;\n                if (manifest.Version == cache.Version)\n                {\n                    return cache;\n                }\n\n                return _cache = BuildCache(manifest);\n            }\n        }\n\n        private static Dictionary<GrainInterfaceType, ushort> BuildLocalVersionMap(GrainManifest manifest)\n        {\n            var result = new Dictionary<GrainInterfaceType, ushort>();\n            foreach (var grainInterface in manifest.Interfaces)\n            {\n                var id = grainInterface.Key;\n\n                if (!grainInterface.Value.Properties.TryGetValue(WellKnownGrainInterfaceProperties.Version, out var versionString)\n                    || !ushort.TryParse(versionString, out var version))\n                {\n                    version = 0;\n                }\n\n                result[id] = version;\n            }\n\n            return result;\n        }\n\n        private static Cache BuildCache(ClusterManifest clusterManifest)\n        {\n            var available = new Dictionary<GrainInterfaceType, List<ushort>>();\n            var supportedInterfaces = new Dictionary<(GrainInterfaceType, ushort), List<SiloAddress>>();\n            var supportedGrains = new Dictionary<GrainType, List<SiloAddress>>();\n\n            foreach (var entry in clusterManifest.Silos)\n            {\n                var silo = entry.Key;\n\n                // Since clients are not eligible for placement, we exclude them here.\n                if (silo.IsClient)\n                {\n                    continue;\n                }\n\n                var manifest = entry.Value;\n                foreach (var grainInterface in manifest.Interfaces)\n                {\n                    var id = grainInterface.Key;\n\n                    if (!grainInterface.Value.Properties.TryGetValue(WellKnownGrainInterfaceProperties.Version, out var versionString)\n                        || !ushort.TryParse(versionString, out var version))\n                    {\n                        version = 0;\n                    }\n\n                    if (!available.TryGetValue(id, out var versions))\n                    {\n                        available[id] = new List<ushort> { version };\n                    }\n                    else if (!versions.Contains(version))\n                    {\n                        versions.Add(version);\n                    }\n\n                    if (!supportedInterfaces.TryGetValue((id, version), out var supportedSilos))\n                    {\n                        supportedInterfaces[(id, version)] = new List<SiloAddress> { silo };\n                    }\n                    else if (!supportedSilos.Contains(silo))\n                    {\n                        supportedSilos.Add(silo);\n                    }\n                }\n\n                foreach (var grainType in manifest.Grains)\n                {\n                    var id = grainType.Key;\n                    if (!supportedGrains.TryGetValue(id, out var supportedSilos))\n                    {\n                        supportedGrains[id] = new List<SiloAddress> { silo };\n                    }\n                    else if (!supportedSilos.Contains(silo))\n                    {\n                        supportedSilos.Add(silo);\n                    }\n                }\n            }\n\n            var resultAvailable = new Dictionary<GrainInterfaceType, ushort[]>();\n            foreach (var entry in available)\n            {\n                entry.Value.Sort();\n                resultAvailable[entry.Key] = entry.Value.ToArray();\n            }\n\n            var resultSupportedByInterface = new Dictionary<(GrainInterfaceType, ushort), SiloAddress[]>();\n            foreach (var entry in supportedInterfaces)\n            {\n                entry.Value.Sort();\n                resultSupportedByInterface[entry.Key] = entry.Value.ToArray();\n            }\n\n            var resultSupportedSilosByGrainType = new Dictionary<GrainType, SiloAddress[]>();\n            foreach (var entry in supportedGrains)\n            {\n                entry.Value.Sort();\n                resultSupportedSilosByGrainType[entry.Key] = entry.Value.ToArray();\n            }\n\n            return new Cache(clusterManifest.Version, resultAvailable, resultSupportedByInterface, resultSupportedSilosByGrainType);\n        }\n\n        private class Cache\n        {\n            public Cache(\n                MajorMinorVersion version,\n                Dictionary<GrainInterfaceType, ushort[]> availableVersions,\n                Dictionary<(GrainInterfaceType, ushort), SiloAddress[]> supportedSilosByInterface,\n                Dictionary<GrainType, SiloAddress[]> supportedSilosByGrainType)\n            {\n                this.Version = version;\n                this.AvailableVersions = availableVersions;\n                this.SupportedSilosByGrainType = supportedSilosByGrainType;\n                this.SupportedSilosByInterface = supportedSilosByInterface;\n            }\n\n            public MajorMinorVersion Version { get; }\n            public Dictionary<GrainInterfaceType, ushort[]> AvailableVersions { get; } \n            public Dictionary<(GrainInterfaceType, ushort), SiloAddress[]> SupportedSilosByInterface { get; } = new Dictionary<(GrainInterfaceType, ushort), SiloAddress[]>();\n            public Dictionary<GrainType, SiloAddress[]> SupportedSilosByGrainType { get; } = new Dictionary<GrainType, SiloAddress[]>();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Manifest/IClusterManifestProvider.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Provides access to the cluster manifest.\n    /// </summary>\n    /// <seealso cref=\"ClusterManifest\"/>\n    public interface IClusterManifestProvider\n    {\n        /// <summary>\n        /// Gets the current cluster manifest.\n        /// </summary>\n        ClusterManifest Current { get; }\n       \n        /// <summary>\n        /// Gets the stream of cluster manifest updates.\n        /// </summary>\n        IAsyncEnumerable<ClusterManifest> Updates { get; }\n\n        /// <summary>\n        /// Gets the local grain manifest.\n        /// </summary>\n        GrainManifest LocalGrainManifest { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/IClusterManifestSystemTarget.cs",
    "content": "#nullable enable\nusing System.Collections.Immutable;\nusing System.Threading.Tasks;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Internal interface for exposing the cluster manifest.\n    /// </summary>\n    internal interface IClusterManifestSystemTarget : ISystemTarget\n    {\n        /// <summary>\n        /// Gets the current cluster manifest.\n        /// </summary>\n        /// <returns>The current cluster manifest.</returns>\n        ValueTask<ClusterManifest> GetClusterManifest();\n\n        /// <summary>\n        /// Gets an updated cluster manifest if newer than the provided <paramref name=\"previousVersion\"/>.\n        /// </summary>\n        /// <returns>The current cluster manifest, or <see langword=\"null\"/> if it is not newer than the provided version.</returns>\n        ValueTask<ClusterManifestUpdate?> GetClusterManifestUpdate(MajorMinorVersion previousVersion);\n    }\n\n    /// <summary>\n    /// Represents an update to the cluster manifest.\n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public class ClusterManifestUpdate\n    {\n        public ClusterManifestUpdate(\n            MajorMinorVersion manifestVersion,\n            ImmutableDictionary<SiloAddress, GrainManifest> siloManifests,\n            bool includesAllActiveServers)\n        {\n            Version = manifestVersion;\n            SiloManifests = siloManifests;\n            IncludesAllActiveServers = includesAllActiveServers;\n        }\n\n        /// <summary>\n        /// Gets the version of this instance.\n        /// </summary>\n        [Id(0)]\n        public MajorMinorVersion Version { get; }\n\n        /// <summary>\n        /// Gets the manifests for each silo in the cluster.\n        /// </summary>\n        [Id(1)]\n        public ImmutableDictionary<SiloAddress, GrainManifest> SiloManifests { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this update includes all active servers.\n        /// </summary>\n        [Id(2)]\n        public bool IncludesAllActiveServers { get; } \n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/ImplementedInterfaceProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Populates grain interface properties with the grain interfaces implemented by a grain class.\n    /// </summary>\n    internal sealed class ImplementedInterfaceProvider : IGrainPropertiesProvider\n    {\n        private readonly GrainInterfaceTypeResolver interfaceTypeResolver;\n        private readonly string[] _cachedKeys = new string[16];\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImplementedInterfaceProvider\"/> class.\n        /// </summary>\n        /// <param name=\"interfaceTypeResolver\">The interface type resolver.</param>\n        public ImplementedInterfaceProvider(GrainInterfaceTypeResolver interfaceTypeResolver)\n        {\n            this.interfaceTypeResolver = interfaceTypeResolver;\n        }\n\n        /// <inheritdoc/>\n        public void Populate(Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            var counter = 0;\n            foreach (var @interface in grainClass.GetInterfaces())\n            {\n                if (!IsGrainInterface(@interface)) continue;\n\n                var type = @interface switch\n                {\n                    { IsGenericType: true } when grainClass is { IsGenericType: true } => @interface.GetGenericTypeDefinition(),\n                    _ => @interface\n                };\n                var interfaceId = this.interfaceTypeResolver.GetGrainInterfaceType(type);\n                var key = (uint)counter < (uint)_cachedKeys.Length ? (_cachedKeys[counter] ??= GetKey(counter)) : GetKey(counter);\n                properties[key] = interfaceId.ToString();\n                ++counter;\n            }\n        }\n\n        private static string GetKey(int counter) => $\"{WellKnownGrainTypeProperties.ImplementedInterfacePrefix}{counter}\";\n\n        /// <summary>\n        /// Gets a value indicating whether the specified type is a grain interface type.\n        /// </summary>\n        /// <param name=\"type\">The type to inspect.</param>\n        /// <returns>A value indicating whether the specified type is a grain interface type.</returns>\n        public static bool IsGrainInterface(Type type)\n        {\n            if (type.IsClass)\n                return false;\n            if (type == typeof(IGrainObserver) || type == typeof(IAddressable) || type == typeof(IGrainExtension))\n                return false;\n            if (type == typeof(IGrain) || type == typeof(IGrainWithGuidKey) || type == typeof(IGrainWithIntegerKey)\n                || type == typeof(IGrainWithGuidCompoundKey) || type == typeof(IGrainWithIntegerCompoundKey))\n                return false;\n            if (type == typeof(ISystemTarget))\n                return false;\n\n            return typeof(IAddressable).IsAssignableFrom(type);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Manifest/TypeNameGrainPropertiesProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Populates type names on grain properties and grain interface properties.\n    /// </summary>\n    internal sealed class TypeNameGrainPropertiesProvider : IGrainPropertiesProvider, IGrainInterfacePropertiesProvider\n    {\n        /// <inheritdoc/>\n        public void Populate(Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.TypeName] = grainClass.Name;\n            properties[WellKnownGrainTypeProperties.FullTypeName] = grainClass.FullName;\n            properties[\"diag.type\"] = RuntimeTypeNameFormatter.Format(grainClass);\n            properties[\"diag.asm\"] = CachedTypeResolver.GetName(grainClass.Assembly);\n        }\n\n        /// <inheritdoc/>\n        public void Populate(Type interfaceType, GrainInterfaceType interfaceId, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainInterfaceProperties.TypeName] = interfaceType.Name;\n            properties[\"diag.type\"] = RuntimeTypeNameFormatter.Format(interfaceType);\n            properties[\"diag.asm\"] = CachedTypeResolver.GetName(interfaceType.Assembly);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/CachingIdSpanCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Caching;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// A serializer for <see cref=\"IdSpan\"/> which caches values and avoids re-encoding and unnecessary allocations.\n    /// </summary>\n    internal sealed class CachingIdSpanCodec\n    {\n        private static readonly ConcurrentLruCache<IdSpan, IdSpan> SharedCache = new(capacity: 128_000);\n\n        // Purge entries which have not been accessed in over 2 minutes. \n        private const long PurgeAfterMilliseconds = 2 * 60 * 1000;\n\n        // Scan for entries which are expired every minute\n        private const long GarbageCollectionIntervalMilliseconds = 60 * 1000;\n\n        private readonly Dictionary<int, (byte[] Value, long LastSeen)> _cache = new();\n        private long _lastGarbageCollectionTimestamp;\n\n        public CachingIdSpanCodec()\n        {\n            _lastGarbageCollectionTimestamp = Environment.TickCount64;\n        }\n\n        public IdSpan ReadRaw<TInput>(ref Reader<TInput> reader)\n        {\n            var currentTimestamp = Environment.TickCount64;\n\n            var length = reader.ReadVarUInt32();\n            if (length == 0)\n                return default;\n\n            var hashCode = reader.ReadInt32();\n\n            IdSpan result = default;\n            byte[] payloadArray = default;\n            if (!reader.TryReadBytes((int)length, out var payloadSpan))\n            {\n                payloadSpan = payloadArray = reader.ReadBytes(length);\n            }\n\n            ref var cacheEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(_cache, hashCode, out var exists);\n            if (exists && payloadSpan.SequenceEqual(cacheEntry.Value))\n            {\n                result = IdSpan.UnsafeCreate(cacheEntry.Value, hashCode);\n            }\n            else\n            {\n                result = IdSpan.UnsafeCreate(payloadArray ?? payloadSpan.ToArray(), hashCode);\n\n                // Before adding this value to the private cache and returning it, intern it via the shared cache to hopefully reduce duplicates.\n                result = SharedCache.GetOrAdd(result, static (key, _) => key, (object)null);\n\n                // Update the cache. If there is a hash collision, the last entry wins.\n                cacheEntry.Value = IdSpan.UnsafeGetArray(result);\n            }\n            cacheEntry.LastSeen = currentTimestamp;\n\n            // Perform periodic maintenance to prevent unbounded memory leaks.\n            if (currentTimestamp - _lastGarbageCollectionTimestamp > GarbageCollectionIntervalMilliseconds)\n            {\n                PurgeStaleEntries();\n                _lastGarbageCollectionTimestamp = currentTimestamp;\n            }\n\n            return result;\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void PurgeStaleEntries()\n        {\n            var currentTimestamp = Environment.TickCount64;\n            foreach (var entry in _cache)\n            {\n                if (currentTimestamp - entry.Value.LastSeen > PurgeAfterMilliseconds)\n                {\n                    _cache.Remove(entry.Key);\n                }\n            }\n        }\n\n        public void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, IdSpan value) where TBufferWriter : IBufferWriter<byte>\n        {\n            IdSpanCodec.WriteRaw(ref writer, value);\n            SharedCache.GetOrAdd(value, static (key, _) => key, (object)null);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/CachingSiloAddressCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Caching;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// A serializer for <see cref=\"SiloAddress\"/> which caches values and avoids re-encoding and unnecessary allocations.\n    /// </summary>\n    internal sealed class CachingSiloAddressCodec\n    {\n        internal static ConcurrentLruCache<SiloAddress, (SiloAddress Value, byte[] Encoded)> SharedCache { get; } = new(capacity: 1024);\n\n        // Purge entries which have not been accessed in over 2 minutes.\n        private const long PurgeAfterMilliseconds = 2 * 60 * 1000;\n\n        // Scan for entries which are expired every minute\n        private const long GarbageCollectionIntervalMilliseconds = 60 * 1000;\n\n        private readonly Dictionary<int, (byte[] Encoded, SiloAddress Value, long LastSeen)> _cache = new();\n        private long _lastGarbageCollectionTimestamp;\n\n        public CachingSiloAddressCodec()\n        {\n            _lastGarbageCollectionTimestamp = Environment.TickCount64;\n        }\n\n        public SiloAddress ReadRaw<TInput>(ref Reader<TInput> reader)\n        {\n            var currentTimestamp = Environment.TickCount64;\n\n            SiloAddress result = null;\n            byte[] payloadArray = default;\n            var length = (int)reader.ReadVarUInt32();\n            if (length == 0)\n            {\n                return null;\n            }\n\n            if (!reader.TryReadBytes(length, out var payloadSpan))\n            {\n                payloadSpan = payloadArray = reader.ReadBytes((uint)length);\n            }\n\n            var innerReader = Reader.Create(payloadSpan, null);\n            var hashCode = innerReader.ReadInt32();\n\n            ref var cacheEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(_cache, hashCode, out var exists);\n            if (exists && payloadSpan.SequenceEqual(cacheEntry.Encoded))\n            {\n                result = cacheEntry.Value;\n                cacheEntry.LastSeen = currentTimestamp;\n            }\n            else\n            {\n                result = ReadSiloAddressInner(ref innerReader);\n                result.InternalSetConsistentHashCode(hashCode);\n\n                // Before adding this value to the private cache and returning it, intern it via the shared cache to hopefully reduce duplicates.\n                payloadArray ??= payloadSpan.ToArray();\n                (result, payloadArray) = SharedCache.GetOrAdd(result, static (key, encoded) => (key, encoded), payloadArray);\n\n                // If there is a hash collision, then the last seen entry will always win.\n                cacheEntry.Encoded = payloadArray;\n                cacheEntry.Value = result;\n                cacheEntry.LastSeen = currentTimestamp;\n            }\n\n            // Perform periodic maintenance to prevent unbounded memory leaks.\n            if (currentTimestamp - _lastGarbageCollectionTimestamp > GarbageCollectionIntervalMilliseconds)\n            {\n                PurgeStaleEntries();\n                _lastGarbageCollectionTimestamp = currentTimestamp;\n            }\n\n            return result;\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void PurgeStaleEntries()\n        {\n            var currentTimestamp = Environment.TickCount64;\n            foreach (var entry in _cache)\n            {\n                if (currentTimestamp - entry.Value.LastSeen > PurgeAfterMilliseconds)\n                {\n                    _cache.Remove(entry.Key);\n                }\n            }\n        }\n\n        private static SiloAddress ReadSiloAddressInner<TInput>(ref Reader<TInput> reader)\n        {\n            var ip = IPAddressCodec.ReadRaw(ref reader);\n            var port = (int)reader.ReadVarUInt32();\n            var generation = reader.ReadInt32();\n\n            return SiloAddress.New(ip, port, generation);\n        }\n\n        public void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, SiloAddress value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var currentTimestamp = Environment.TickCount64;\n            if (value is null)\n            {\n                writer.WriteByte(1); // writer.WriteVarUInt32(0);\n                return;\n            }\n\n            var hashCode = value.GetConsistentHashCode();\n            ref var cacheEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(_cache, hashCode, out var exists);\n            if (exists && value.Equals(cacheEntry.Value))\n            {\n                writer.WriteVarUInt32((uint)cacheEntry.Encoded.Length);\n                writer.Write(cacheEntry.Encoded);\n\n                cacheEntry.LastSeen = currentTimestamp;\n\n                // Perform periodic maintenance to prevent unbounded memory leaks.\n                if (currentTimestamp - _lastGarbageCollectionTimestamp > GarbageCollectionIntervalMilliseconds)\n                {\n                    PurgeStaleEntries();\n                    _lastGarbageCollectionTimestamp = currentTimestamp;\n                }\n\n                return;\n            }\n\n            var innerWriter = Writer.Create(new PooledBuffer(), null);\n            innerWriter.WriteInt32(value.GetConsistentHashCode());\n            WriteSiloAddressInner(ref innerWriter, value);\n            innerWriter.Commit();\n            var payloadArray = innerWriter.Output.ToArray();\n            innerWriter.Dispose();\n\n            writer.WriteVarUInt32((uint)payloadArray.Length);\n            writer.Write(payloadArray);\n\n            // Before adding this value to the private cache, intern it via the shared cache to hopefully reduce duplicates.\n            (_, payloadArray) = SharedCache.GetOrAdd(value, static (key, encoded) => (key, encoded), payloadArray);\n\n            // If there is a hash collision, then the last seen entry will always win.\n            cacheEntry.Encoded = payloadArray;\n            cacheEntry.Value = value;\n            cacheEntry.LastSeen = currentTimestamp;\n        }\n\n        private static void WriteSiloAddressInner<TBufferWriter>(ref Writer<TBufferWriter> writer, SiloAddress value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var ep = value.Endpoint;\n\n            // IP\n            IPAddressCodec.WriteRaw(ref writer, ep.Address);\n\n            // Port\n            writer.WriteVarUInt16((ushort)ep.Port);\n\n            // Generation\n            writer.WriteInt32(value.Generation);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/ClientMessageCenter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.Messaging\n{\n    // <summary>\n    // This class is used on the client only.\n    // It provides the client counterpart to the Gateway and GatewayAcceptor classes on the silo side.\n    //\n    // There is one ClientMessageCenter instance per OutsideRuntimeClient. There can be multiple ClientMessageCenter instances\n    // in a single process, but because RuntimeClient keeps a static pointer to a single OutsideRuntimeClient instance, this is not\n    // generally done in practice.\n    //\n    // Each ClientMessageCenter keeps a collection of GatewayConnection instances. Each of these represents a bidirectional connection\n    // to a single gateway endpoint. Requests are assigned to a specific connection based on the target grain ID, so that requests to\n    // the same grain will go to the same gateway, in sending order. To do this efficiently and scalably, we bucket grains together\n    // based on their hash code mod a reasonably large number (currently 8192).\n    //\n    // When the first message is sent to a bucket, we assign a gateway to that bucket, selecting in round-robin fashion from the known\n    // gateways. If this is the first message to be sent to the gateway, we will create a new connection for it and assign the bucket to\n    // the new connection. Either way, all messages to grains in that bucket will be sent to the assigned connection as long as the\n    // connection is live.\n    //\n    // Connections stay live as long as possible. If a socket error or other communications error occurs, then the client will try to\n    // reconnect twice before giving up on the gateway. If the connection cannot be re-established, then the gateway is deemed (temporarily)\n    // dead, and any buckets assigned to the connection are unassigned (so that the next message sent will cause a new gateway to be selected).\n    // There is no assumption that this death is permanent; the system will try to reuse the gateway every 5 minutes.\n    //\n    // The list of known gateways is managed by the GatewayManager class. See comments there for details.\n    // </summary>\n    internal partial class ClientMessageCenter : IMessageCenter, IDisposable\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock grainBucketUpdateLock = new();\n#else\n        private readonly object grainBucketUpdateLock = new();\n#endif\n\n        internal static readonly TimeSpan MINIMUM_INTERCONNECT_DELAY = TimeSpan.FromMilliseconds(100);   // wait one tenth of a second between connect attempts\n        internal const int CONNECT_RETRY_COUNT = 2;                                                      // Retry twice before giving up on a gateway server\n\n        internal ClientGrainId ClientId => _localClientDetails.ClientId;\n        public IRuntimeClient RuntimeClient { get; }\n        internal bool Running { get; private set; }\n\n        private readonly GatewayManager gatewayManager;\n        private Action<Message> messageHandler;\n        private int numMessages;\n        // The grainBuckets array is used to select the connection to use when sending an ordered message to a grain.\n        // Requests are bucketed by GrainID, so that all requests to a grain get routed through the same bucket.\n        // Each bucket holds a (possibly null) weak reference to a GatewayConnection object. That connection instance is used\n        // if the WeakReference is non-null, is alive, and points to a live gateway connection. If any of these conditions is\n        // false, then a new gateway is selected using the gateway manager, and a new connection established if necessary.\n        private readonly WeakReference<ClientOutboundConnection>[] grainBuckets;\n        private readonly ILogger logger;\n        public SiloAddress MyAddress => _localClientDetails.ClientAddress;\n        private int numberOfConnectedGateways = 0;\n        private readonly MessageFactory messageFactory;\n        private readonly IClusterConnectionStatusListener connectionStatusListener;\n        private readonly ConnectionManager connectionManager;\n        private readonly LocalClientDetails _localClientDetails;\n\n        public ClientMessageCenter(\n            IOptions<ClientMessagingOptions> clientMessagingOptions,\n            LocalClientDetails localClientDetails,\n            IRuntimeClient runtimeClient,\n            MessageFactory messageFactory,\n            IClusterConnectionStatusListener connectionStatusListener,\n            ILoggerFactory loggerFactory,\n            ConnectionManager connectionManager,\n            GatewayManager gatewayManager)\n        {\n            this.connectionManager = connectionManager;\n            _localClientDetails = localClientDetails;\n            this.RuntimeClient = runtimeClient;\n            this.messageFactory = messageFactory;\n            this.connectionStatusListener = connectionStatusListener;\n            Running = false;\n            this.gatewayManager = gatewayManager;\n            numMessages = 0;\n            this.grainBuckets = new WeakReference<ClientOutboundConnection>[clientMessagingOptions.Value.ClientSenderBuckets];\n            logger = loggerFactory.CreateLogger<ClientMessageCenter>();\n            ClientInstruments.RegisterConnectedGatewayCountObserve(() => connectionManager.ConnectionCount);\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            await EstablishInitialConnection(cancellationToken);\n\n            Running = true;\n            LogClientMessageCenterStarted();\n        }\n\n        private async Task EstablishInitialConnection(CancellationToken cancellationToken)\n        {\n            var liveGateways = gatewayManager.GetLiveGateways();\n\n            if (liveGateways.Count == 0)\n            {\n                throw new ConnectionFailedException(\"There are no available gateways.\");\n            }\n\n            var pendingTasks = new List<Task>(liveGateways.Count);\n            foreach (var gateway in liveGateways)\n            {\n                pendingTasks.Add(connectionManager.GetConnection(gateway).AsTask());\n            }\n\n            try\n            {\n                while (pendingTasks.Count > 0)\n                {\n                    var completedTask = await Task.WhenAny(pendingTasks).WaitAsync(cancellationToken);\n                    pendingTasks.Remove(completedTask);\n\n                    // If at least one gateway connection has been established, break out of the loop and continue startup.\n                    if (completedTask.IsCompletedSuccessfully)\n                    {\n                        break;\n                    }\n\n                    // If there are no more gateways, observe the most recent exception and bail out.\n                    if (pendingTasks.Count == 0)\n                    {\n                        await completedTask;\n                    }\n                    else\n                    {\n                        completedTask.Ignore();\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                throw new ConnectionFailedException(\n                    $\"Unable to connect to any of the {liveGateways.Count} available gateways.\",\n                    exception);\n            }\n        }\n\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            Running = false;\n            await gatewayManager.StopAsync(cancellationToken);\n        }\n\n        public void DispatchLocalMessage(Message message)\n        {\n            var handler = this.messageHandler;\n            if (handler is null)\n            {\n                ThrowNullMessageHandler();\n            }\n            else\n            {\n                handler(message);\n            }\n\n            static void ThrowNullMessageHandler() => throw new InvalidOperationException(\"MessageCenter does not have a message handler set\");\n        }\n\n        public void SendMessage(Message msg)\n        {\n            if (!Running)\n            {\n                LogNotRunning(msg);\n                return;\n            }\n\n            var connectionTask = this.GetGatewayConnection(msg);\n            if (connectionTask.IsCompletedSuccessfully)\n            {\n                var connection = connectionTask.Result;\n                if (connection is null) return;\n\n                connection.Send(msg);\n                LogSendingMessage(msg, connection.RemoteEndPoint);\n            }\n            else\n            {\n                _ = SendAsync(connectionTask, msg);\n\n                async Task SendAsync(ValueTask<Connection> task, Message message)\n                {\n                    try\n                    {\n                        var connection = await task;\n\n                        // If the connection returned is null then the message was already rejected due to a failure.\n                        if (connection is null) return;\n\n                        connection.Send(message);\n\n                        LogSendingMessage(message, connection.RemoteEndPoint);\n                    }\n                    catch (Exception exception)\n                    {\n                        if (message.RetryCount < MessagingOptions.DEFAULT_MAX_MESSAGE_SEND_RETRIES)\n                        {\n                            ++message.RetryCount;\n\n                            _ = Task.Factory.StartNew(\n                                state => this.SendMessage((Message)state),\n                                message,\n                                CancellationToken.None,\n                                TaskCreationOptions.DenyChildAttach,\n                                TaskScheduler.Default);\n                        }\n                        else\n                        {\n                            this.RejectMessage(message, $\"Unable to send message due to exception {exception}\", exception);\n                        }\n                    }\n                }\n            }\n        }\n\n        private ValueTask<Connection> GetGatewayConnection(Message msg)\n        {\n            // If there's a specific gateway specified, use it\n            if (msg.TargetSilo != null && gatewayManager.IsGatewayAvailable(msg.TargetSilo))\n            {\n                var siloAddress = SiloAddress.New(msg.TargetSilo.Endpoint, 0);\n                var connectionTask = this.connectionManager.GetConnection(siloAddress);\n                if (connectionTask.IsCompletedSuccessfully) return connectionTask;\n\n                return ConnectAsync(msg.TargetSilo, connectionTask, msg, directGatewayMessage: true);\n            }\n\n            // For untargeted messages to system targets, and for unordered messages, pick a next connection in round robin fashion.\n            if (msg.TargetGrain.IsSystemTarget() || msg.IsUnordered)\n            {\n                // Get the cached list of live gateways.\n                // Pick a next gateway name in a round robin fashion.\n                // See if we have a live connection to it.\n                // If Yes, use it.\n                // If not, create a new GatewayConnection and start it.\n                // If start fails, we will mark this connection as dead and remove it from the GetCachedLiveGatewayNames.\n                int msgNumber = Interlocked.Increment(ref numMessages);\n                var gatewayAddresses = gatewayManager.GetLiveGateways();\n                int numGateways = gatewayAddresses.Count;\n                if (numGateways == 0)\n                {\n                    RejectMessage(msg, \"No gateways available\");\n                    LogSendFailed(msg, gatewayManager);\n                    return new ValueTask<Connection>(default(Connection));\n                }\n\n                var gatewayAddress = gatewayAddresses[msgNumber % numGateways];\n\n                var connectionTask = this.connectionManager.GetConnection(gatewayAddress);\n                if (connectionTask.IsCompletedSuccessfully) return connectionTask;\n\n                return ConnectAsync(gatewayAddress, connectionTask, msg, directGatewayMessage: false);\n            }\n\n            // Otherwise, use the buckets to ensure ordering.\n            var index = GetHashCodeModulo(msg.TargetGrain.GetHashCode(), (uint)grainBuckets.Length);\n\n            // Repeated from above, at the declaration of the grainBuckets array:\n            // Requests are bucketed by GrainID, so that all requests to a grain get routed through the same bucket.\n            // Each bucket holds a (possibly null) weak reference to a GatewayConnection object. That connection instance is used\n            // if the WeakReference is non-null, is alive, and points to a live gateway connection. If any of these conditions is\n            // false, then a new gateway is selected using the gateway manager, and a new connection established if necessary.\n            WeakReference<ClientOutboundConnection> weakRef = grainBuckets[index];\n\n            if (weakRef != null\n                && weakRef.TryGetTarget(out var existingConnection)\n                && existingConnection.IsValid\n                && gatewayManager.IsGatewayAvailable(existingConnection.RemoteSiloAddress))\n            {\n                return new ValueTask<Connection>(existingConnection);\n            }\n\n            var addr = gatewayManager.GetLiveGateway();\n            if (addr == null)\n            {\n                RejectMessage(msg, \"No gateways available\");\n                LogNoGatewayAvailableForMessage(msg, gatewayManager);\n                return new ValueTask<Connection>(default(Connection));\n            }\n\n            var gatewayConnection = this.connectionManager.GetConnection(addr);\n            if (gatewayConnection.IsCompletedSuccessfully)\n            {\n                this.UpdateBucket(index, (ClientOutboundConnection)gatewayConnection.Result);\n                return gatewayConnection;\n            }\n\n            return AddToBucketAsync(index, gatewayConnection, addr);\n\n            async ValueTask<Connection> AddToBucketAsync(\n                uint bucketIndex,\n                ValueTask<Connection> connectionTask,\n                SiloAddress gatewayAddress)\n            {\n                try\n                {\n                    var connection = (ClientOutboundConnection)await connectionTask.ConfigureAwait(false);\n                    this.UpdateBucket(bucketIndex, connection);\n                    return connection;\n                }\n                catch\n                {\n                    this.gatewayManager.MarkAsDead(gatewayAddress);\n                    this.UpdateBucket(bucketIndex, null);\n                    throw;\n                }\n            }\n\n            async ValueTask<Connection> ConnectAsync(\n                SiloAddress gateway,\n                ValueTask<Connection> connectionTask,\n                Message message,\n                bool directGatewayMessage)\n            {\n                Connection result = default;\n                try\n                {\n                    return result = await connectionTask;\n                }\n                catch (Exception exception) when (directGatewayMessage)\n                {\n                    RejectMessage(message, $\"Target silo {message.TargetSilo} is unavailable\", exception);\n                    return null;\n                }\n                finally\n                {\n                    if (result is null) this.gatewayManager.MarkAsDead(gateway);\n                }\n            }\n\n            static uint GetHashCodeModulo(int key, uint umod)\n            {\n                int mod = (int)umod;\n                key = ((key % mod) + mod) % mod; // key should be positive now. So assert with checked.\n                return checked((uint)key);\n            }\n        }\n\n        private void UpdateBucket(uint index, ClientOutboundConnection connection)\n        {\n            lock (this.grainBucketUpdateLock)\n            {\n                var value = this.grainBuckets[index] ?? new WeakReference<ClientOutboundConnection>(connection);\n                value.SetTarget(connection);\n                this.grainBuckets[index] = value;\n            }\n        }\n\n        public void RegisterLocalMessageHandler(Action<Message> handler)\n        {\n            this.messageHandler = handler;\n        }\n\n        public void RejectMessage(Message msg, string reason, Exception exc = null)\n        {\n            if (!Running) return;\n\n            if (msg.Direction != Message.Directions.Request)\n            {\n                LogDroppingMessage(msg, reason);\n            }\n            else\n            {\n                LogRejectingMessage(msg, reason);\n                MessagingInstruments.OnRejectedMessage(msg);\n                var error = this.messageFactory.CreateRejectionResponse(msg, Message.RejectionTypes.Unrecoverable, reason, exc);\n                DispatchLocalMessage(error);\n            }\n        }\n\n        internal void OnGatewayConnectionOpen()\n        {\n            int newCount = Interlocked.Increment(ref numberOfConnectedGateways);\n            this.connectionStatusListener.NotifyGatewayCountChanged(newCount, newCount - 1);\n        }\n\n        internal void OnGatewayConnectionClosed()\n        {\n            var gatewayCount = Interlocked.Decrement(ref numberOfConnectedGateways);\n            if (gatewayCount == 0)\n            {\n                this.connectionStatusListener.NotifyClusterConnectionLost();\n            }\n\n            this.connectionStatusListener.NotifyGatewayCountChanged(gatewayCount, gatewayCount + 1);\n        }\n\n        public void Dispose()\n        {\n            gatewayManager.Dispose();\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_MsgCtrNotRunning,\n            Level = LogLevel.Error,\n            Message = \"Ignoring {Message} because the client message center is not running.\"\n        )]\n        private partial void LogNotRunning(Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_QueueRequest,\n            Level = LogLevel.Trace,\n            Message = \"Sending message {Message} via gateway '{Gateway}'.\"\n        )]\n        private partial void LogSendingMessage(Message message, EndPoint gateway);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Client message center started.\"\n        )]\n        private partial void LogClientMessageCenterStarted();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_CannotSend,\n            Level = LogLevel.Warning,\n            Message = \"Unable to send message {Message}; Gateway manager state is {GatewayManager}.\"\n        )]\n        private partial void LogSendFailed(Message message, GatewayManager gatewayManager);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_CannotSend_NoGateway,\n            Level = LogLevel.Warning,\n            Message = \"No gateway available to receive message {Message}; Gateway manager state is {GatewayManager}.\"\n        )]\n        private partial void LogNoGatewayAvailableForMessage(Message message, GatewayManager gatewayManager);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_DroppingMsg,\n            Level = LogLevel.Debug,\n            Message = \"Dropping message: {Message}. Reason = {Reason}\"\n        )]\n        private partial void LogDroppingMessage(Message message, string reason);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_RejectingMsg,\n            Level = LogLevel.Debug,\n            Message = \"Rejecting message: {Message}. Reason = {Reason}\"\n        )]\n        private partial void LogRejectingMessage(Message message, string reason);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/CorrelationId.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    [Serializable, GenerateSerializer, Immutable]\n    internal readonly struct CorrelationId : IEquatable<CorrelationId>, IComparable<CorrelationId>, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly long id;\n        private static long lastUsed;\n\n        public CorrelationId(long value) => id = value;\n\n        public CorrelationId(CorrelationId other) => id = other.id;\n\n        public static CorrelationId GetNext() => new(System.Threading.Interlocked.Increment(ref lastUsed));\n\n        public override int GetHashCode() => id.GetHashCode();\n\n        public override bool Equals(object? obj) => obj is CorrelationId correlationId && Equals(correlationId);\n\n        public bool Equals(CorrelationId other) => id == other.id;\n\n        public static bool operator ==(CorrelationId lhs, CorrelationId rhs) => rhs.id == lhs.id;\n\n        public static bool operator !=(CorrelationId lhs, CorrelationId rhs) => rhs.id != lhs.id;\n\n        public int CompareTo(CorrelationId other) => id.CompareTo(other.id);\n\n        public override string ToString() => id.ToString(\"X16\");\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => id.ToString(format ?? \"X16\", formatProvider);\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            if (format.IsEmpty)\n            {\n                format = \"X16\";\n            }\n\n            return id.TryFormat(destination, out charsWritten, format, provider);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal long ToInt64() => id;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/GatewayManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\nusing static Orleans.Internal.StandardExtensions;\n\nnamespace Orleans.Messaging\n{\n    /// <summary>\n    /// The GatewayManager class holds the list of known gateways, as well as maintaining the list of \"dead\" gateways.\n    ///\n    /// The known list can come from one of two places: the full list may appear in the client configuration object, or\n    /// the config object may contain an IGatewayListProvider delegate. If both appear, then the delegate takes priority.\n    /// </summary>\n    internal partial class GatewayManager : IDisposable\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock lockable = new();\n#else\n        private readonly object lockable = new();\n#endif\n        private readonly Dictionary<SiloAddress, DateTime> knownDead = new Dictionary<SiloAddress, DateTime>();\n        private readonly Dictionary<SiloAddress, DateTime> knownMasked = new Dictionary<SiloAddress, DateTime>();\n        private readonly IGatewayListProvider gatewayListProvider;\n        private readonly ILogger logger;\n        private readonly ConnectionManager connectionManager;\n        private readonly GatewayOptions gatewayOptions;\n        private readonly PeriodicTimer gatewayRefreshTimer;\n        private List<SiloAddress> cachedLiveGateways = [];\n        private HashSet<SiloAddress> cachedLiveGatewaysSet = [];\n        private List<SiloAddress> knownGateways = [];\n        private DateTime lastRefreshTime;\n        private int roundRobinCounter;\n        private bool gatewayRefreshCallInitiated;\n        private bool gatewayListProviderInitialized;\n        private Task? gatewayRefreshTimerTask;\n\n        public GatewayManager(\n            IOptions<GatewayOptions> gatewayOptions,\n            IGatewayListProvider gatewayListProvider,\n            ILoggerFactory loggerFactory,\n            ConnectionManager connectionManager,\n            TimeProvider timeProvider)\n        {\n            this.gatewayOptions = gatewayOptions.Value;\n            this.logger = loggerFactory.CreateLogger<GatewayManager>();\n            this.connectionManager = connectionManager;\n            this.gatewayListProvider = gatewayListProvider;\n\n            var refreshPeriod = Max(this.gatewayOptions.GatewayListRefreshPeriod, TimeSpan.FromMilliseconds(1));\n            this.gatewayRefreshTimer = new PeriodicTimer(this.gatewayOptions.GatewayListRefreshPeriod, timeProvider);\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            if (!gatewayListProviderInitialized)\n            {\n                await this.gatewayListProvider.InitializeGatewayListProvider();\n                gatewayListProviderInitialized = true;\n            }\n\n            var knownGateways = await this.gatewayListProvider.GetGateways();\n            if (knownGateways == null || knownGateways.Count == 0)\n            {\n                // this situation can occur if the client starts faster than the silos.\n                var providerName = this.gatewayListProvider.GetType().FullName;\n                LogNoGatewayDuringInitialization(this.logger, providerName);\n                var message = $\"Could not find any gateway in '{providerName}'. Orleans client cannot initialize until at least one gateway becomes available.\";\n                throw new SiloUnavailableException(message);\n            }\n\n            LogFoundGateways(this.logger, knownGateways.Count, new(knownGateways));\n\n            this.roundRobinCounter = this.gatewayOptions.PreferredGatewayIndex >= 0 ? this.gatewayOptions.PreferredGatewayIndex : Random.Shared.Next(knownGateways.Count);\n            var newGateways = new List<SiloAddress>();\n            foreach (var gatewayUri in knownGateways)\n            {\n                if (gatewayUri?.ToGatewayAddress() is { } gatewayAddress)\n                {\n                    newGateways.Add(gatewayAddress);\n                }\n            }\n\n            this.knownGateways = this.cachedLiveGateways = newGateways;\n            this.cachedLiveGatewaysSet = new HashSet<SiloAddress>(cachedLiveGateways);\n            this.lastRefreshTime = DateTime.UtcNow;\n            this.gatewayRefreshTimerTask ??= PeriodicallyRefreshGatewaySnapshot();\n        }\n\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            gatewayRefreshTimer.Dispose();\n            if (gatewayRefreshTimerTask is { } task)\n            {\n                await task.WaitAsync(cancellationToken);\n            }\n        }\n\n        public void MarkAsDead(SiloAddress gateway)\n        {\n            lock (lockable)\n            {\n                knownDead[gateway] = DateTime.UtcNow;\n                var copy = new List<SiloAddress>(cachedLiveGateways);\n                copy.Remove(gateway);\n                // swap the reference, don't mutate cachedLiveGateways, so we can access cachedLiveGateways without the lock.\n                cachedLiveGateways = copy;\n                cachedLiveGatewaysSet = new HashSet<SiloAddress>(cachedLiveGateways);\n            }\n        }\n\n        public void MarkAsUnavailableForSend(SiloAddress gateway)\n        {\n            lock (lockable)\n            {\n                knownMasked[gateway] = DateTime.UtcNow;\n                var copy = new List<SiloAddress>(cachedLiveGateways);\n                copy.Remove(gateway);\n                // swap the reference, don't mutate cachedLiveGateways, so we can access cachedLiveGateways without the lock.\n                cachedLiveGateways = copy;\n                cachedLiveGatewaysSet = new HashSet<SiloAddress>(cachedLiveGateways);\n            }\n        }\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n            sb.Append(\"GatewayManager: \");\n            lock (lockable)\n            {\n                if (cachedLiveGateways != null)\n                {\n                    sb.Append(cachedLiveGateways.Count);\n                    sb.Append(\" cachedLiveGateways, \");\n                }\n                if (knownDead != null)\n                {\n                    sb.Append(knownDead.Count);\n                    sb.Append(\" known dead gateways.\");\n                }\n            }\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// Selects a gateway to use for a new bucket.\n        ///\n        /// Note that if a list provider delegate was given, the delegate is invoked every time this method is called.\n        /// This method performs caching to avoid hammering the ultimate data source.\n        ///\n        /// This implementation does a simple round robin selection. It assumes that the gateway list from the provider\n        /// is in the same order every time.\n        /// </summary>\n        /// <returns></returns>\n        #nullable enable\n        public SiloAddress? GetLiveGateway()\n        #nullable disable\n        {\n            List<SiloAddress> live = GetLiveGateways();\n            int count = live.Count;\n            if (count > 0)\n            {\n                lock (lockable)\n                {\n                    // Round-robin through the known gateways and take the next live one, starting from where we last left off\n                    roundRobinCounter = (roundRobinCounter + 1) % count;\n                    return live[roundRobinCounter];\n                }\n            }\n            // If we drop through, then all of the known gateways are presumed dead\n            return null;\n        }\n\n\n        public List<SiloAddress> GetLiveGateways()\n        {\n            // Never takes a lock and returns the cachedLiveGateways list quickly without any operation.\n            // Asynchronously starts gateway refresh only when it is empty.\n            if (cachedLiveGateways.Count == 0)\n            {\n                ExpediteUpdateLiveGatewaysSnapshot();\n\n                if (knownGateways.Count > 0)\n                {\n                    lock (this.lockable)\n                    {\n                        if (cachedLiveGateways.Count == 0 && knownGateways.Count > 0)\n                        {\n                            LogAllGatewaysMarkedDead(this.logger);\n\n                            cachedLiveGateways = knownGateways;\n                            cachedLiveGatewaysSet = new HashSet<SiloAddress>(knownGateways);\n                        }\n                    }\n                }\n            }\n\n            return cachedLiveGateways;\n        }\n\n        public bool IsGatewayAvailable(SiloAddress siloAddress)\n        {\n            return cachedLiveGatewaysSet.Contains(siloAddress);\n        }\n\n        internal void ExpediteUpdateLiveGatewaysSnapshot()\n        {\n            // If there is already an expedited refresh call in place, don't call again, until the previous one is finished.\n            // We don't want to issue too many Gateway refresh calls.\n            if (gatewayListProvider == null || gatewayRefreshCallInitiated) return;\n\n            // Initiate gateway list refresh asynchronously. The Refresh timer will keep ticking regardless.\n            // We don't want to block the client with synchronously Refresh call.\n            // Client's call will fail with \"No Gateways found\" but we will try to refresh the list quickly.\n            gatewayRefreshCallInitiated = true;\n            _ = Task.Run(async () =>\n            {\n                try\n                {\n                    await RefreshGatewaySnapshot();\n                }\n                finally\n                {\n                    gatewayRefreshCallInitiated = false;\n                }\n            });\n        }\n\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Design\", \"CA1031:DoNotCatchGeneralExceptionTypes\")]\n        internal async Task PeriodicallyRefreshGatewaySnapshot()\n        {\n            await Task.Yield();\n\n            if (gatewayListProvider is null)\n            {\n                return;\n            }\n\n            while (await gatewayRefreshTimer.WaitForNextTickAsync())\n            {\n                await RefreshGatewaySnapshot();\n            }\n        }\n\n        private async Task RefreshGatewaySnapshot()\n        {\n            try\n            {\n                if (gatewayListProvider is null)\n                {\n                    return;\n                }\n\n                // the listProvider.GetGateways() is not under lock.\n                var allGateways = await gatewayListProvider.GetGateways();\n                var refreshedGateways = allGateways.Select(gw => gw.ToGatewayAddress()).ToList();\n\n                await UpdateLiveGatewaysSnapshot(refreshedGateways, gatewayListProvider.MaxStaleness);\n            }\n            catch (Exception exc)\n            {\n                LogErrorRefreshingGateways(this.logger, exc);\n            }\n        }\n\n        // This function is called asynchronously from gateway refresh timer.\n        private async Task UpdateLiveGatewaysSnapshot(IEnumerable<SiloAddress> refreshedGateways, TimeSpan maxStaleness)\n        {\n            List<SiloAddress> connectionsToKeepAlive;\n\n            // This is a short lock, protecting the access to knownDead, knownMasked and cachedLiveGateways.\n            lock (lockable)\n            {\n                // now take whatever listProvider gave us and exclude those we think are dead.\n                var live = new List<SiloAddress>();\n                var now = DateTime.UtcNow;\n\n                this.knownGateways = refreshedGateways as List<SiloAddress> ?? refreshedGateways.ToList();\n                foreach (SiloAddress trial in knownGateways)\n                {\n                    var address = trial.Generation == 0 ? trial : SiloAddress.New(trial.Endpoint, 0);\n\n                    // We consider a node to be dead if we recorded it is dead due to socket error\n                    // and it was recorded (diedAt) not too long ago (less than maxStaleness ago).\n                    // The latter is to cover the case when the Gateway provider returns an outdated list that does not yet reflect the actually recently died Gateway.\n                    // If it has passed more than maxStaleness - we assume maxStaleness is the upper bound on Gateway provider freshness.\n                    var isDead = false;\n                    if (knownDead.TryGetValue(address, out var diedAt))\n                    {\n                        if (now.Subtract(diedAt) < maxStaleness)\n                        {\n                            isDead = true;\n                        }\n                        else\n                        {\n                            // Remove stale entries.\n                            knownDead.Remove(address);\n                        }\n                    }\n                    if (knownMasked.TryGetValue(address, out var maskedAt))\n                    {\n                        if (now.Subtract(maskedAt) < maxStaleness)\n                        {\n                            isDead = true;\n                        }\n                        else\n                        {\n                            // Remove stale entries.\n                            knownMasked.Remove(address);\n                        }\n                    }\n\n                    if (!isDead)\n                    {\n                        live.Add(address);\n                    }\n                }\n\n                if (live.Count == 0)\n                {\n                    LogAllGatewaysDead(logger);\n                    live.AddRange(knownGateways);\n                    knownDead.Clear();\n                }\n\n                // swap cachedLiveGateways pointer in one atomic operation\n                cachedLiveGateways = live;\n                cachedLiveGatewaysSet = new HashSet<SiloAddress>(live);\n\n                DateTime prevRefresh = lastRefreshTime;\n                lastRefreshTime = now;\n                LogRefreshedLiveGatewayList(logger, knownGateways.Count, new(knownGateways), cachedLiveGateways.Count, new(cachedLiveGateways), prevRefresh);\n\n                // Close connections to known dead connections, but keep the \"masked\" ones.\n                // Client will not send any new request to the \"masked\" connections, but might still\n                // receive responses\n                connectionsToKeepAlive = new List<SiloAddress>(live);\n                connectionsToKeepAlive.AddRange(knownMasked.Select(e => e.Key));\n            }\n\n            await this.CloseEvictedGatewayConnections(connectionsToKeepAlive);\n        }\n\n        private async Task CloseEvictedGatewayConnections(List<SiloAddress> liveGateways)\n        {\n            if (this.connectionManager == null) return;\n\n            var connectedGateways = this.connectionManager.GetConnectedAddresses();\n            foreach (var address in connectedGateways)\n            {\n                var isLiveGateway = false;\n                foreach (var live in liveGateways)\n                {\n                    if (live.Matches(address))\n                    {\n                        isLiveGateway = true;\n                        break;\n                    }\n                }\n\n                if (!isLiveGateway)\n                {\n                    LogClosingConnectionToDeadGateway(this.logger, address);\n\n                    await this.connectionManager.CloseAsync(address);\n                }\n            }\n        }\n\n        public void Dispose()\n        {\n            this.gatewayRefreshTimer.Dispose();\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayManager_NoGateways,\n            Level = LogLevel.Warning,\n            Message = \"Could not find any gateway in '{GatewayListProviderName}'. Orleans client cannot initialize until at least one gateway becomes available.\"\n        )]\n        private static partial void LogNoGatewayDuringInitialization(ILogger logger, string gatewayListProviderName);\n\n        private readonly struct UrisLogValue(IList<Uri> uris)\n        {\n            public override readonly string ToString() => Utils.EnumerableToString(uris);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayManager_FoundKnownGateways,\n            Level = LogLevel.Information,\n            Message = \"Found '{GatewayCount}' gateways: '{Gateways}'.\"\n        )]\n        private static partial void LogFoundGateways(ILogger logger, int gatewayCount, UrisLogValue gateways);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"All known gateways have been marked dead locally. Expediting gateway refresh and resetting all gateways to live status.\"\n        )]\n        private static partial void LogAllGatewaysMarkedDead(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_GetGateways,\n            Level = LogLevel.Error,\n            Message = \"Error refreshing gateways.\"\n        )]\n        private static partial void LogErrorRefreshingGateways(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Closing connection to '{EndPoint}' because it has been marked as dead.\"\n        )]\n        private static partial void LogClosingConnectionToDeadGateway(ILogger logger, SiloAddress endPoint);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayManager_AllGatewaysDead,\n            Level = LogLevel.Warning,\n            Message = \"All gateways have previously been marked as dead. Clearing the list of dead gateways to expedite reconnection.\"\n        )]\n        private static partial void LogAllGatewaysDead(ILogger logger);\n\n        private readonly struct SiloAddressesLogValue(List<SiloAddress> addresses)\n        {\n            public override string ToString() => Utils.EnumerableToString(addresses);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayManager_FoundKnownGateways,\n            Level = LogLevel.Debug,\n            Message = \"Refreshed the live gateway list. Found '{KnownGatewayCount}' gateways from gateway list provider: '{KnownGateways}'. Picked only known live out of them. Now has '{LiveGatewayCount}' live gateways: '{LiveGateways}'. Previous refresh time was = '{PreviousRefreshTime}'\"\n        )]\n        private static partial void LogRefreshedLiveGatewayList(ILogger logger, int knownGatewayCount, SiloAddressesLogValue knownGateways, int liveGatewayCount, SiloAddressesLogValue liveGateways, DateTime previousRefreshTime);\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Messaging/IGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Messaging\n{\n    /// <summary>\n    /// Interface that provides Orleans gateways information.\n    /// </summary>\n    public interface IGatewayListProvider\n    {\n        /// <summary>\n        /// Initializes the provider, will be called before all other methods.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task InitializeGatewayListProvider();\n\n        /// <summary>\n        /// Returns the list of gateways (silos) that can be used by a client to connect to Orleans cluster.\n        /// The Uri is in the form of: \"gwy.tcp://IP:port/Generation\". See Utils.ToGatewayUri and Utils.ToSiloAddress for more details about Uri format.\n        /// </summary>\n        /// <returns>The list of gateway endpoints.</returns>\n        Task<IList<Uri>> GetGateways();\n\n        /// <summary>\n        /// Gets the period of time between refreshes.\n        /// </summary>\n        TimeSpan MaxStaleness { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this IGatewayListProvider ever refreshes its returned information, or always returns the same gateway list.\n        /// </summary>\n        [Obsolete(\"This attribute is no longer used and all providers are considered updatable\")]\n        bool IsUpdatable { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/IMessageCenter.cs",
    "content": "namespace Orleans.Runtime\n{\n    internal interface IMessageCenter\n    {\n        void SendMessage(Message msg);\n\n        void DispatchLocalMessage(Message message);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/InvalidMessageFrameException.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime.Messaging;\n\n/// <summary>\n/// Indicates that a message frame is invalid, either when sending a message or receiving a message.\n/// </summary>\n[GenerateSerializer]\npublic sealed class InvalidMessageFrameException : OrleansException\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"InvalidMessageFrameException\"/> class.\n    /// </summary>\n    public InvalidMessageFrameException()\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"InvalidMessageFrameException\"/> class.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    public InvalidMessageFrameException(string message) : base(message)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"InvalidMessageFrameException\"/> class.\n    /// </summary>\n    /// <param name=\"message\">The message that describes the error.</param>\n    /// <param name=\"innerException\">The exception that is the cause of the current exception.</param>\n    public InvalidMessageFrameException(string message, Exception innerException) : base(message, innerException)\n    {\n    }\n\n    [Obsolete]\n    protected InvalidMessageFrameException(SerializationInfo info, StreamingContext context) : base(info, context)\n    {\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Messaging/Message.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Threading;\n\nnamespace Orleans.Runtime\n{\n    [Id(101)]\n    internal sealed class Message : ISpanFormattable\n    {\n        public const int LENGTH_HEADER_SIZE = 8;\n        public const int LENGTH_META_HEADER = 4;\n\n        [NonSerialized]\n        private short _retryCount;\n\n        public CoarseStopwatch _timeToExpiry;\n\n        public object? BodyObject { get; set; }\n\n        public PackedHeaders _headers;\n        public CorrelationId _id;\n\n        public Dictionary<string, object>? _requestContextData;\n\n        public SiloAddress? _targetSilo;\n        public GrainId _targetGrain;\n\n        public SiloAddress? _sendingSilo;\n        public GrainId _sendingGrain;\n\n        public ushort _interfaceVersion;\n        public GrainInterfaceType _interfaceType;\n\n        public List<GrainAddressCacheUpdate>? _cacheInvalidationHeader;\n\n        public PackedHeaders Headers { get => _headers; set => _headers = value; }\n\n        [GenerateSerializer]\n        public enum Directions : byte\n        {\n            None,\n            Request,\n            Response,\n            OneWay\n        }\n\n        [GenerateSerializer]\n        public enum ResponseTypes : byte\n        {\n            None,\n            Success,\n            Error,\n            Rejection,\n            Status\n        }\n\n        [GenerateSerializer]\n        public enum RejectionTypes : byte\n        {\n            None,\n            Transient,\n            Overloaded,\n            Unrecoverable,\n            GatewayTooBusy,\n            CacheInvalidation\n        }\n\n        public Directions Direction\n        {\n            get => _headers.Direction;\n            set => _headers.Direction = value;\n        }\n\n        public bool HasDirection => _headers.Direction != Directions.None;\n\n        public bool IsSenderFullyAddressed => SendingSilo is not null && !SendingGrain.IsDefault;\n        public bool IsTargetFullyAddressed => TargetSilo is not null && !TargetGrain.IsDefault;\n\n        public bool IsExpired => _timeToExpiry is { IsDefault: false, ElapsedMilliseconds: > 0 };\n\n        public short RetryCount\n        {\n            get => _retryCount;\n            set => _retryCount = value;\n        }\n\n        public bool HasCacheInvalidationHeader => CacheInvalidationHeader is { Count: > 0 };\n\n        public bool IsSystemMessage\n        {\n            get => _headers.HasFlag(MessageFlags.SystemMessage);\n            set => _headers.SetFlag(MessageFlags.SystemMessage, value);\n        }\n\n        /// <summary>\n        /// Indicates whether the message does not mutate application state and therefore whether it can be interleaved with other read-only messages.\n        /// </summary>\n        /// <remarks>\n        /// Defaults to <see langword=\"false\"/>.\n        /// </remarks>\n        public bool IsReadOnly\n        {\n            get => _headers.HasFlag(MessageFlags.ReadOnly);\n            set => _headers.SetFlag(MessageFlags.ReadOnly, value);\n        }\n\n        public bool IsAlwaysInterleave\n        {\n            get => _headers.HasFlag(MessageFlags.AlwaysInterleave);\n            set => _headers.SetFlag(MessageFlags.AlwaysInterleave, value);\n        }\n\n        public bool IsUnordered\n        {\n            get => _headers.HasFlag(MessageFlags.Unordered);\n            set => _headers.SetFlag(MessageFlags.Unordered, value);\n        }\n\n        /// <summary>\n        /// Whether the message is allowed to be sent to another activation of the target grain.\n        /// </summary>\n        /// <remarks>\n        /// Defaults to <see langword=\"false\"/>.\n        /// </remarks>\n        public bool IsLocalOnly\n        {\n            get => _headers.HasFlag(MessageFlags.IsLocalOnly);\n            set => _headers.SetFlag(MessageFlags.IsLocalOnly, value);\n        }\n\n        /// <summary>\n        /// Whether the message is allowed to activate a grain and/or extend its lifetime.\n        /// </summary>\n        /// <remarks>\n        /// Defaults to <see langword=\"true\"/>.\n        /// </remarks>\n        public bool IsKeepAlive\n        {\n            get => !_headers.HasFlag(MessageFlags.SuppressKeepAlive);\n            set => _headers.SetFlag(MessageFlags.SuppressKeepAlive, !value);\n        }\n\n        public CorrelationId Id\n        {\n            get => _id;\n            set => _id = value;\n        }\n\n        public int ForwardCount\n        {\n            get => _headers.ForwardCount;\n            set => _headers.ForwardCount = value;\n        }\n\n        public SiloAddress? TargetSilo\n        {\n            get => _targetSilo;\n            set\n            {\n                _targetSilo = value;\n            }\n        }\n\n        public GrainId TargetGrain\n        {\n            get => _targetGrain;\n            set\n            {\n                _targetGrain = value;\n            }\n        }\n\n        public SiloAddress? SendingSilo\n        {\n            get => _sendingSilo;\n            set\n            {\n                _sendingSilo = value;\n            }\n        }\n\n        public GrainId SendingGrain\n        {\n            get => _sendingGrain;\n            set\n            {\n                _sendingGrain = value;\n            }\n        }\n\n        public ushort InterfaceVersion\n        {\n            get => _interfaceVersion;\n            set\n            {\n                _interfaceVersion = value;\n                _headers.SetFlag(MessageFlags.HasInterfaceVersion, value is not 0);\n            }\n        }\n\n        public ResponseTypes Result\n        {\n            get => _headers.ResponseType;\n            set => _headers.ResponseType = value;\n        }\n\n        public TimeSpan? TimeToLive\n        {\n            get => _timeToExpiry.IsDefault ? null : -_timeToExpiry.Elapsed;\n            set\n            {\n                if (value.HasValue)\n                {\n                    SetTimeToLiveMilliseconds((long)value.Value.TotalMilliseconds);\n                }\n                else\n                {\n                    SetInfiniteTimeToLive();\n                }\n            }\n        }\n\n        internal long GetTimeToLiveMilliseconds() => -_timeToExpiry.ElapsedMilliseconds;\n\n        internal void SetTimeToLiveMilliseconds(long milliseconds)\n        {\n            _headers.SetFlag(MessageFlags.HasTimeToLive, true);\n            _timeToExpiry = CoarseStopwatch.StartNew(-milliseconds);\n        }\n\n        internal void SetInfiniteTimeToLive()\n        {\n            _headers.SetFlag(MessageFlags.HasTimeToLive, false);\n            _timeToExpiry = default;\n        }\n\n        public List<GrainAddressCacheUpdate>? CacheInvalidationHeader\n        {\n            get => _cacheInvalidationHeader;\n            set\n            {\n                _cacheInvalidationHeader = value;\n                _headers.SetFlag(MessageFlags.HasCacheInvalidationHeader, value is not null);\n            }\n        }\n\n        public Dictionary<string, object>? RequestContextData\n        {\n            get => _requestContextData;\n            set\n            {\n                _requestContextData = value;\n                _headers.SetFlag(MessageFlags.HasRequestContextData, value is not null);\n            }\n        }\n\n        public GrainInterfaceType InterfaceType\n        {\n            get => _interfaceType;\n            set\n            {\n                _interfaceType = value;\n                _headers.SetFlag(MessageFlags.HasInterfaceType, !value.IsDefault);\n            }\n        }\n\n        public bool IsExpirableMessage()\n        {\n            GrainId id = TargetGrain;\n            if (id.IsDefault) return false;\n\n            // don't set expiration for one way, system target and system grain messages.\n            return Direction != Directions.OneWay && !id.IsSystemTarget();\n        }\n\n        internal void AddToCacheInvalidationHeader(GrainAddress invalidAddress, GrainAddress? validAddress)\n        {\n            var grainAddressCacheUpdate = new GrainAddressCacheUpdate(invalidAddress, validAddress);\n            if (_cacheInvalidationHeader is null)\n            {\n                var newList = new List<GrainAddressCacheUpdate> { grainAddressCacheUpdate };\n                if (Interlocked.CompareExchange(ref _cacheInvalidationHeader, newList, null) is not null)\n                {\n                    // Another thread initialized it, add to the existing list\n                    lock (_cacheInvalidationHeader)\n                    {\n                        _cacheInvalidationHeader.Add(grainAddressCacheUpdate);\n                    }\n                }\n                else\n                {\n                    _headers.SetFlag(MessageFlags.HasCacheInvalidationHeader, true);\n                }\n            }\n            else\n            {\n                lock (_cacheInvalidationHeader)\n                {\n                    _cacheInvalidationHeader.Add(grainAddressCacheUpdate);\n                }\n            }\n        }\n\n        public override string ToString() => $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> dst, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            ref var origin = ref MemoryMarshal.GetReference(dst);\n            int len;\n\n            if (IsReadOnly && !Append(ref dst, \"ReadOnly \")) goto grow;\n            if (IsAlwaysInterleave && !Append(ref dst, \"IsAlwaysInterleave \")) goto grow;\n\n            if (Direction == Directions.Response)\n            {\n                switch (Result)\n                {\n                    case ResponseTypes.Rejection when BodyObject is RejectionResponse rejection:\n                        if (!dst.TryWrite($\"{rejection.RejectionType} Rejection (info: {rejection.RejectionInfo}) \", out len)) goto grow;\n                        dst = dst[len..];\n                        break;\n\n                    case ResponseTypes.Error:\n                        if (!Append(ref dst, \"Error \")) goto grow;\n                        break;\n\n                    case ResponseTypes.Status:\n                        if (!Append(ref dst, \"Status \")) goto grow;\n                        break;\n                }\n            }\n\n            if (!dst.TryWrite($\"{Direction} [{SendingSilo} {SendingGrain}]->[{TargetSilo} {TargetGrain}]\", out len)) goto grow;\n            dst = dst[len..];\n\n            if (BodyObject is { } request)\n            {\n                if (!dst.TryWrite($\" {request}\", out len)) goto grow;\n                dst = dst[len..];\n            }\n\n            if (!dst.TryWrite($\" #{Id}\", out len)) goto grow;\n            dst = dst[len..];\n\n            if (ForwardCount > 0)\n            {\n                if (!dst.TryWrite($\"[ForwardCount={ForwardCount}]\", out len)) goto grow;\n                dst = dst[len..];\n            }\n\n            charsWritten = (int)Unsafe.ByteOffset(ref origin, ref MemoryMarshal.GetReference(dst)) / sizeof(char);\n            return true;\n\ngrow:\n            charsWritten = 0;\n            return false;\n\n            static bool Append(ref Span<char> dst, ReadOnlySpan<char> value)\n            {\n                if (!value.TryCopyTo(dst))\n                    return false;\n\n                dst = dst[value.Length..];\n                return true;\n            }\n        }\n\n        internal bool IsPing() => _requestContextData?.TryGetValue(RequestContext.PING_APPLICATION_HEADER, out var value) == true && value is bool isPing && isPing;\n\n        [Flags]\n        internal enum MessageFlags : ushort\n        {\n            SystemMessage = 1 << 0,\n            ReadOnly = 1 << 1,\n            AlwaysInterleave = 1 << 2,\n            Unordered = 1 << 3,\n\n            HasRequestContextData = 1 << 4,\n            HasInterfaceVersion = 1 << 5,\n            HasInterfaceType = 1 << 6,\n            HasCacheInvalidationHeader = 1 << 7,\n            HasTimeToLive = 1 << 8,\n\n            // Message cannot be forwarded to another activation.\n            IsLocalOnly = 1 << 9, \n\n            // Message must not trigger grain activation or extend an activation's lifetime.\n            SuppressKeepAlive = 1 << 10,  \n\n            // The most significant bit is reserved, possibly for use to indicate more data follows.\n            Reserved = 1 << 15,\n        }\n\n        internal struct PackedHeaders\n        {\n            private const uint DirectionMask = 0x000F_0000;\n            private const int DirectionShift = 16;\n            private const uint ResponseTypeMask = 0x00F0_0000;\n            private const int ResponseTypeShift = 20;\n            private const uint ForwardCountMask = 0xFF00_0000;\n            private const int ForwardCountShift = 24;\n\n            public static implicit operator PackedHeaders(uint fields) => new() { _fields = fields };\n            public static implicit operator uint(PackedHeaders value) => value._fields;\n\n            // 32 bits: HHHH_HHHH RRRR_DDDD FFFF_FFFF FFFF_FFFF\n            // F: 16 bits for MessageFlags\n            // D: 4 bits for Direction\n            // R: 4 bits for ResponseType\n            // H: 8 bits for ForwardCount (hop count)\n            private uint _fields;\n\n            public int ForwardCount\n            {\n                readonly get => (int)(_fields >> ForwardCountShift);\n                set => _fields = (_fields & ~ForwardCountMask) | (uint)value << ForwardCountShift;\n            }\n\n            public Directions Direction\n            {\n                readonly get => (Directions)((_fields & DirectionMask) >> DirectionShift);\n                set => _fields = (_fields & ~DirectionMask) | (uint)value << DirectionShift;\n            }\n\n            public ResponseTypes ResponseType\n            {\n                readonly get => (ResponseTypes)((_fields & ResponseTypeMask) >> ResponseTypeShift);\n                set => _fields = (_fields & ~ResponseTypeMask) | (uint)value << ResponseTypeShift;\n            }\n\n            public readonly bool HasFlag(MessageFlags flag) => (_fields & (uint)flag) != 0;\n\n            public void SetFlag(MessageFlags flag, bool value) => _fields = value switch\n            {\n                true => _fields | (uint)flag,\n                false => _fields & ~(uint)flag,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/MessageFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Orleans.CodeGeneration;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime\n{\n    internal partial class MessageFactory\n    {\n        private static ulong _nextId;\n\n        // The nonce reduces the chance of an id collision for a given grain to effectively zero. Id collisions are only relevant in scenarios\n        // where where the infinitesimally small chance of a collision is acceptable, such as call cancellation.\n        private readonly ulong _seed;\n        private readonly DeepCopier _deepCopier;\n        private readonly ILogger _logger;\n        private readonly MessagingTrace _messagingTrace;\n\n        public MessageFactory(DeepCopier deepCopier, ILogger<MessageFactory> logger, MessagingTrace messagingTrace)\n        {\n            _deepCopier = deepCopier;\n            _logger = logger;\n            _messagingTrace = messagingTrace;\n\n            // Generate a 64-bit nonce for the host, to be combined with per-message correlation ids to get a unique, per-host value.\n            // This avoids id collisions across different hosts for a given grain.\n            _seed = unchecked((ulong)Random.Shared.NextInt64());\n        }\n\n        public Message CreateMessage(object body, InvokeMethodOptions options)\n        {\n            var message = new Message\n            {\n                Direction = (options & InvokeMethodOptions.OneWay) != 0 ? Message.Directions.OneWay : Message.Directions.Request,\n                Id = GetNextCorrelationId(),\n                IsReadOnly = (options & InvokeMethodOptions.ReadOnly) != 0,\n                IsUnordered = (options & InvokeMethodOptions.Unordered) != 0,\n                IsAlwaysInterleave = (options & InvokeMethodOptions.AlwaysInterleave) != 0,\n                BodyObject = body,\n                RequestContextData = RequestContextExtensions.Export(_deepCopier),\n            };\n\n            _messagingTrace.OnCreateMessage(message);\n            return message;\n        }\n\n        private CorrelationId GetNextCorrelationId()\n        {\n            var id = _seed ^ Interlocked.Increment(ref _nextId);\n            return new CorrelationId(unchecked((long)id));\n        }\n\n        public Message CreateResponseMessage(Message request)\n        {\n            var response = new Message\n            {\n                IsSystemMessage = request.IsSystemMessage,\n                Direction = Message.Directions.Response,\n                Id = request.Id,\n                IsReadOnly = request.IsReadOnly,\n                IsAlwaysInterleave = request.IsAlwaysInterleave,\n                TargetSilo = request.SendingSilo,\n                TargetGrain = request.SendingGrain,\n                SendingSilo = request.TargetSilo,\n                SendingGrain = request.TargetGrain,\n                CacheInvalidationHeader = request.CacheInvalidationHeader,\n                TimeToLive = request.TimeToLive,\n                RequestContextData = RequestContextExtensions.Export(_deepCopier),\n            };\n\n            _messagingTrace.OnCreateMessage(response);\n            return response;\n        }\n\n        public Message CreateRejectionResponse(Message request, Message.RejectionTypes type, string info, Exception ex = null)\n        {\n            var response = CreateResponseMessage(request);\n            response.Result = Message.ResponseTypes.Rejection;\n            response.BodyObject = new RejectionResponse\n            {\n                RejectionType = type,\n                RejectionInfo = info,\n                Exception = ex,\n            };\n            LogCreatingRejectionResponse(_logger, ex, type, info);\n            return response;\n        }\n\n        internal Message CreateDiagnosticResponseMessage(Message request, bool isExecuting, bool isWaiting, List<string> diagnostics)\n        {\n            var response = CreateResponseMessage(request);\n            response.Result = Message.ResponseTypes.Status;\n            response.BodyObject = new StatusResponse(isExecuting, isWaiting, diagnostics);\n\n            LogCreatingStatusUpdate(_logger, request, new(diagnostics));\n            return response;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Creating '{RejectionType}' rejection with info '{Information}'.\"\n        )]\n        private static partial void LogCreatingRejectionResponse(ILogger logger, Exception exception, Message.RejectionTypes rejectionType, string information);\n\n        private readonly struct DiagnosticsLogValue(List<string> diagnostics)\n        {\n            public override string ToString() => string.Join(\", \", diagnostics);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Creating '{RequestMessage}' status update with diagnostics '{Diagnostics}'\"\n        )]\n        private static partial void LogCreatingStatusUpdate(ILogger logger, Message requestMessage, DiagnosticsLogValue diagnostics);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/MessageSerializer.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Buffers;\nusing System.Buffers.Binary;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Orleans.Configuration;\nusing Orleans.Networking.Shared;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing static Orleans.Runtime.Message;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class MessageSerializer\n    {\n        private const int FramingLength = Message.LENGTH_HEADER_SIZE;\n        private const int MessageSizeHint = 4096;\n        private readonly Dictionary<Type, ResponseCodec> _rawResponseCodecs = [];\n        private readonly CodecProvider _codecProvider;\n        private readonly IFieldCodec<GrainAddressCacheUpdate> _grainAddressCacheUpdateCodec;\n        private readonly CachingSiloAddressCodec _readerSiloAddressCodec = new();\n        private readonly CachingSiloAddressCodec _writerSiloAddressCodec = new();\n        private readonly CachingIdSpanCodec _idSpanCodec = new();\n        private readonly SerializerSession _serializationSession;\n        private readonly SerializerSession _deserializationSession;\n        private readonly int _maxHeaderLength;\n        private readonly int _maxBodyLength;\n        private readonly DictionaryCodec<string, object> _requestContextCodec;\n        private readonly PrefixingBufferWriter _bufferWriter;\n\n        public MessageSerializer(\n            SerializerSessionPool sessionPool,\n            SharedMemoryPool memoryPool,\n            MessagingOptions options)\n        {\n            _serializationSession = sessionPool.GetSession();\n            _deserializationSession = sessionPool.GetSession();\n            _maxHeaderLength = options.MaxMessageHeaderSize;\n            _maxBodyLength = options.MaxMessageBodySize;\n            _codecProvider = sessionPool.CodecProvider;\n            _requestContextCodec = OrleansGeneratedCodeHelper.GetService<DictionaryCodec<string, object>>(this, sessionPool.CodecProvider);\n            _grainAddressCacheUpdateCodec = OrleansGeneratedCodeHelper.GetService<IFieldCodec<GrainAddressCacheUpdate>>(this, sessionPool.CodecProvider);\n            _bufferWriter = new(FramingLength, MessageSizeHint, memoryPool.Pool);\n        }\n\n        public (int RequiredBytes, int HeaderLength, int BodyLength) TryRead(ref ReadOnlySequence<byte> input, out Message? message)\n        {\n            if (input.Length < FramingLength)\n            {\n                message = default;\n                return (FramingLength, 0, 0);\n            }\n\n            Span<byte> lengthBytes = stackalloc byte[FramingLength];\n            input.Slice(input.Start, FramingLength).CopyTo(lengthBytes);\n            var headerLength = BinaryPrimitives.ReadInt32LittleEndian(lengthBytes);\n            var bodyLength = BinaryPrimitives.ReadInt32LittleEndian(lengthBytes[4..]);\n\n            // Check lengths\n            ThrowIfLengthsInvalid(headerLength, bodyLength);\n\n            var requiredBytes = FramingLength + headerLength + bodyLength;\n            if (input.Length < requiredBytes)\n            {\n                message = default;\n                return (requiredBytes, 0, 0);\n            }\n\n            try\n            {\n                // Decode header\n                var header = input.Slice(FramingLength, headerLength);\n\n                // Decode body\n                int bodyOffset = FramingLength + headerLength;\n                var body = input.Slice(bodyOffset, bodyLength);\n\n                // Build message\n                message = new();\n                if (header.IsSingleSegment)\n                {\n                    var headersReader = Reader.Create(header.First.Span, _deserializationSession);\n                    Deserialize(ref headersReader, message);\n                }\n                else\n                {\n                    var headersReader = Reader.Create(header, _deserializationSession);\n                    Deserialize(ref headersReader, message);\n                }\n\n                if (bodyLength != 0)\n                {\n                    _deserializationSession.PartialReset();\n\n                    // Body deserialization is more likely to fail than header deserialization.\n                    // Separating the two allows for these kinds of errors to be propagated back to the caller.\n                    if (body.IsSingleSegment)\n                    {\n                        var reader = Reader.Create(body.First.Span, _deserializationSession);\n                        ReadBodyObject(message, ref reader);\n                    }\n                    else\n                    {\n                        var reader = Reader.Create(body, _deserializationSession);\n                        ReadBodyObject(message, ref reader);\n                    }\n                }\n\n                return (0, headerLength, bodyLength);\n            }\n            finally\n            {\n                input = input.Slice(requiredBytes);\n                _deserializationSession.Reset();\n            }\n        }\n\n        private void ReadBodyObject<TInput>(Message message, ref Reader<TInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n\n            if (message.Result == ResponseTypes.Success)\n            {\n                message.Result = ResponseTypes.None; // reset raw response indicator\n                if (!_rawResponseCodecs.TryGetValue(field.FieldType, out var rawCodec))\n                    rawCodec = GetRawCodec(field.FieldType);\n                message.BodyObject = rawCodec.ReadRaw(ref reader, ref field);\n            }\n            else\n            {\n                var bodyCodec = _codecProvider.GetCodec(field.FieldType);\n                message.BodyObject = bodyCodec.ReadValue(ref reader, field);\n            }\n        }\n\n        private ResponseCodec GetRawCodec(Type fieldType)\n        {\n            var rawCodec = (ResponseCodec)_codecProvider.GetCodec(typeof(Response<>).MakeGenericType(fieldType));\n            _rawResponseCodecs.Add(fieldType, rawCodec);\n            return rawCodec;\n        }\n\n        public (int HeaderLength, int BodyLength) Write(PipeWriter writer, Message message)\n        {\n            var headers = message.Headers;\n            IFieldCodec? bodyCodec = null;\n            ResponseCodec? rawCodec = null;\n            if (message.BodyObject is not null)\n            {\n                bodyCodec = _codecProvider.GetCodec(message.BodyObject.GetType());\n                if (headers.ResponseType is ResponseTypes.None && bodyCodec is ResponseCodec responseCodec)\n                {\n                    rawCodec = responseCodec;\n                    headers.ResponseType = ResponseTypes.Success; // indicates a raw simple response (not wrapped in Response<T>)\n                    // The raw encoding changes the type encoded in the field header from Response<T> to T\n                    // and does not encode a null reference value, but otherwise it's identical to normal encoding.\n                }\n            }\n\n            try\n            {\n                var bufferWriter = _bufferWriter;\n                bufferWriter.Init(writer);\n\n                var innerWriter = Writer.Create(new MessageBufferWriter(bufferWriter), _serializationSession);\n                Serialize(ref innerWriter, message, headers);\n                innerWriter.Commit();\n\n                var headerLength = bufferWriter.CommittedBytes;\n\n                _serializationSession.PartialReset();\n\n                if (bodyCodec is not null)\n                {\n                    innerWriter = Writer.Create(new MessageBufferWriter(bufferWriter), _serializationSession);\n                    if (rawCodec != null) rawCodec.WriteRaw(ref innerWriter, message.BodyObject!);\n                    else bodyCodec.WriteField(ref innerWriter, 0, null, message.BodyObject);\n                    innerWriter.Commit();\n                }\n\n                var bodyLength = bufferWriter.CommittedBytes - headerLength;\n\n                // Before completing, check lengths\n                ThrowIfLengthsInvalid(headerLength, bodyLength);\n\n                // Write length prefixes, first header length then body length.\n                var lengthFields = (headerLength, bodyLength);\n                if (!BitConverter.IsLittleEndian)\n                {\n                    lengthFields.headerLength = BinaryPrimitives.ReverseEndianness(headerLength);\n                    lengthFields.bodyLength = BinaryPrimitives.ReverseEndianness(bodyLength);\n                }\n                bufferWriter.Complete(MemoryMarshal.AsBytes(new Span<(int, int)>(ref lengthFields)));\n\n                return (headerLength, bodyLength);\n            }\n            finally\n            {\n                _bufferWriter.Reset();\n                _serializationSession.Reset();\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private void ThrowIfLengthsInvalid(int headerLength, int bodyLength)\n        {\n            if (headerLength <= 0 || headerLength > _maxHeaderLength) ThrowInvalidHeaderLength(headerLength);\n            if ((uint)bodyLength > (uint)_maxBodyLength) ThrowInvalidBodyLength(bodyLength);\n        }\n\n        private void ThrowInvalidHeaderLength(int headerLength) => throw new InvalidMessageFrameException($\"Invalid header size: {headerLength} (max configured value is {_maxHeaderLength}, see {nameof(MessagingOptions.MaxMessageHeaderSize)})\");\n        private void ThrowInvalidBodyLength(int bodyLength) => throw new InvalidMessageFrameException($\"Invalid body size: {bodyLength} (max configured value is {_maxBodyLength}, see {nameof(MessagingOptions.MaxMessageBodySize)})\");\n\n        private void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, Message value, PackedHeaders headers) where TBufferWriter : IBufferWriter<byte>\n        {\n            writer.WriteUInt32((uint)headers);\n\n            writer.WriteInt64(value.Id.ToInt64());\n            WriteGrainId(ref writer, value.SendingGrain);\n            WriteGrainId(ref writer, value.TargetGrain);\n            _writerSiloAddressCodec.WriteRaw(ref writer, value.SendingSilo);\n            _writerSiloAddressCodec.WriteRaw(ref writer, value.TargetSilo);\n\n            if (headers.HasFlag(MessageFlags.HasTimeToLive))\n            {\n                writer.WriteInt32((int)value.GetTimeToLiveMilliseconds());\n            }\n\n            if (headers.HasFlag(MessageFlags.HasInterfaceType))\n            {\n                _idSpanCodec.WriteRaw(ref writer, value.InterfaceType.Value);\n            }\n\n            if (headers.HasFlag(MessageFlags.HasInterfaceVersion))\n            {\n                writer.WriteVarUInt32(value.InterfaceVersion);\n            }\n\n            if (headers.HasFlag(MessageFlags.HasCacheInvalidationHeader))\n            {\n                WriteCacheInvalidationHeaders(ref writer, value);\n            }\n\n            // Always write RequestContext last\n            if (headers.HasFlag(MessageFlags.HasRequestContextData))\n            {\n                WriteRequestContext(ref writer, value.RequestContextData!);\n            }\n        }\n\n        private void Deserialize<TInput>(ref Reader<TInput> reader, Message result)\n        {\n            var headers = (PackedHeaders)reader.ReadUInt32();\n\n            result.Headers = headers;\n            result.Id = new CorrelationId(reader.ReadInt64());\n            result.SendingGrain = ReadGrainId(ref reader);\n            result.TargetGrain = ReadGrainId(ref reader);\n            result.SendingSilo = _readerSiloAddressCodec.ReadRaw(ref reader);\n            result.TargetSilo = _readerSiloAddressCodec.ReadRaw(ref reader);\n\n            if (headers.HasFlag(MessageFlags.HasTimeToLive))\n            {\n                result.SetTimeToLiveMilliseconds(reader.ReadInt32());\n            }\n            else\n            {\n                result.SetInfiniteTimeToLive();\n            }\n\n            if (headers.HasFlag(MessageFlags.HasInterfaceType))\n            {\n                var interfaceTypeSpan = _idSpanCodec.ReadRaw(ref reader);\n                result.InterfaceType = new GrainInterfaceType(interfaceTypeSpan);\n            }\n\n            if (headers.HasFlag(MessageFlags.HasInterfaceVersion))\n            {\n                result.InterfaceVersion = (ushort)reader.ReadVarUInt32();\n            }\n\n            if (headers.HasFlag(MessageFlags.HasCacheInvalidationHeader))\n            {\n                result.CacheInvalidationHeader = ReadCacheInvalidationHeaders(ref reader);\n            }\n\n            if (headers.HasFlag(MessageFlags.HasRequestContextData))\n            {\n                result.RequestContextData = ReadRequestContext(ref reader);\n            }\n        }\n\n        internal List<GrainAddressCacheUpdate> ReadCacheInvalidationHeaders<TInput>(ref Reader<TInput> reader)\n        {\n            var n = (int)reader.ReadVarUInt32();\n            if (n > 0)\n            {\n                var list = new List<GrainAddressCacheUpdate>(n);\n                for (int i = 0; i < n; i++)\n                {\n                    list.Add(_grainAddressCacheUpdateCodec.ReadValue(ref reader, reader.ReadFieldHeader()));\n                }\n\n                return list;\n            }\n\n            return [];\n        }\n\n        internal void WriteCacheInvalidationHeaders<TBufferWriter>(ref Writer<TBufferWriter> writer, Message message) where TBufferWriter : IBufferWriter<byte>\n        {\n            // Lock during enumeration to avoid concurrent modifications.\n            // The list can be modified by other threads after the message is queued for sending.\n            var cacheUpdates = message.CacheInvalidationHeader;\n            if (cacheUpdates is null)\n            {\n                writer.WriteVarUInt32(0u);\n            }\n            else\n            {\n                lock (cacheUpdates)\n                {\n                    writer.WriteVarUInt32((uint)cacheUpdates.Count);\n                    foreach (var entry in cacheUpdates)\n                    {\n                        _grainAddressCacheUpdateCodec.WriteField(ref writer, 0, typeof(GrainAddressCacheUpdate), entry);\n                    }\n                }\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static string? ReadString<TInput>(ref Reader<TInput> reader)\n        {\n            var length = (int)reader.ReadVarUInt32() - 1;\n            if (length <= 0)\n            {\n                if (length < 0)\n                {\n                    return null;\n                }\n\n                return string.Empty;\n            }\n\n            return StringCodec.ReadRaw(ref reader, (uint)length);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static void WriteString<TBufferWriter>(ref Writer<TBufferWriter> writer, string value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                writer.WriteByte(1); // Equivalent to `writer.WriteVarUInt32(0);`\n                return;\n            }\n\n            var numBytes = Encoding.UTF8.GetByteCount(value);\n            writer.WriteVarUInt32((uint)numBytes + 1);\n            StringCodec.WriteRaw(ref writer, value, numBytes);\n        }\n\n        private static void WriteRequestContext<TBufferWriter>(ref Writer<TBufferWriter> writer, Dictionary<string, object> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            writer.WriteVarUInt32((uint)value.Count);\n            foreach (var entry in value)\n            {\n                WriteString(ref writer, entry.Key);\n                ObjectCodec.WriteField(ref writer, 0, entry.Value);\n            }\n        }\n\n        private static Dictionary<string, object> ReadRequestContext<TInput>(ref Reader<TInput> reader)\n        {\n            var size = (int)reader.ReadVarUInt32();\n            var result = new Dictionary<string, object>(size);\n            for (var i = 0; i < size; i++)\n            {\n                var key = ReadString(ref reader);\n                var value = ObjectCodec.ReadValue(ref reader, reader.ReadFieldHeader());\n\n                Debug.Assert(key is not null);\n                result.Add(key, value);\n            }\n\n            return result;\n        }\n\n        private GrainId ReadGrainId<TInput>(ref Reader<TInput> reader)\n        {\n            var grainType = _idSpanCodec.ReadRaw(ref reader);\n            var grainKey = IdSpanCodec.ReadRaw(ref reader);\n            return new GrainId(new GrainType(grainType), grainKey);\n        }\n\n        private void WriteGrainId<TBufferWriter>(ref Writer<TBufferWriter> writer, GrainId value) where TBufferWriter : IBufferWriter<byte>\n        {\n            _idSpanCodec.WriteRaw(ref writer, value.Type.Value);\n            IdSpanCodec.WriteRaw(ref writer, value.Key);\n        }\n    }\n\n    internal readonly struct MessageBufferWriter : IBufferWriter<byte>\n    {\n        private readonly PrefixingBufferWriter _buffer;\n        public MessageBufferWriter(PrefixingBufferWriter buffer) => _buffer = buffer;\n        public void Advance(int count) => _buffer.Advance(count);\n        public Memory<byte> GetMemory(int sizeHint = 0) => _buffer.GetMemory(sizeHint);\n        public Span<byte> GetSpan(int sizeHint = 0) => _buffer.GetSpan(sizeHint);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/OverloadDetectionLogic.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.Statistics;\n\nnamespace Orleans.Core.Messaging;\n\ninternal static class OverloadDetectionLogic\n{\n    /// <summary>\n    /// Determines whether or not the process is overloaded.\n    /// </summary>\n    /// <remarks><see cref=\"LoadSheddingOptions.LoadSheddingEnabled\"/> is ignored here.</remarks>\n    public static bool IsOverloaded(ref readonly EnvironmentStatistics statistics, LoadSheddingOptions options)\n    {\n        bool isMemoryOverloaded = statistics.MemoryUsagePercentage > options.MemoryThreshold;\n        bool isCpuOverloaded = statistics.FilteredCpuUsagePercentage > options.CpuThreshold;\n\n        return isMemoryOverloaded || isCpuOverloaded;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/PrefixingBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// An <see cref=\"IBufferWriter{T}\"/> that reserves some fixed size for a header.\n    /// </summary>\n    /// <remarks>\n    /// This type is used for inserting the length of list in the header when the length is not known beforehand.\n    /// It is optimized to minimize or avoid copying.\n    /// </remarks>\n    internal sealed class PrefixingBufferWriter : IBufferWriter<byte>, IDisposable\n    {\n        private readonly MemoryPool<byte> memoryPool;\n\n        /// <summary>\n        /// The length of the header.\n        /// </summary>\n        private readonly int expectedPrefixSize;\n\n        /// <summary>\n        /// A hint from our owner at the size of the payload that follows the header.\n        /// </summary>\n        private readonly int payloadSizeHint;\n\n        /// <summary>\n        /// The underlying buffer writer.\n        /// </summary>\n        private PipeWriter innerWriter;\n\n        /// <summary>\n        /// The memory reserved for the header from the <see cref=\"innerWriter\"/>.\n        /// This memory is not reserved until the first call from this writer to acquire memory.\n        /// </summary>\n        private Memory<byte> prefixMemory;\n\n        /// <summary>\n        /// The memory acquired from <see cref=\"innerWriter\"/>.\n        /// This memory is not reserved until the first call from this writer to acquire memory.\n        /// </summary>\n        private Memory<byte> realMemory;\n\n        /// <summary>\n        /// The number of elements written to a buffer belonging to <see cref=\"innerWriter\"/>.\n        /// </summary>\n        private int advanced;\n\n        /// <summary>\n        /// The fallback writer to use when the caller writes more than we allowed for given the <see cref=\"payloadSizeHint\"/>\n        /// in anything but the initial call to <see cref=\"GetSpan(int)\"/>.\n        /// </summary>\n        private Sequence privateWriter;\n\n        private int _committedBytes;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PrefixingBufferWriter\"/> class.\n        /// </summary>\n        /// <param name=\"prefixSize\">The length of the header to reserve space for. Must be a positive number.</param>\n        /// <param name=\"payloadSizeHint\">A hint at the expected max size of the payload. The real size may be more or less than this, but additional copying is avoided if it does not exceed this amount. If 0, a reasonable guess is made.</param>\n        /// <param name=\"memoryPool\"></param>\n        public PrefixingBufferWriter(int prefixSize, int payloadSizeHint, MemoryPool<byte> memoryPool)\n        {\n            if (prefixSize <= 0)\n            {\n                ThrowPrefixSize();\n            }\n\n            this.expectedPrefixSize = prefixSize;\n            this.payloadSizeHint = payloadSizeHint;\n            this.memoryPool = memoryPool;\n            static void ThrowPrefixSize() => throw new ArgumentOutOfRangeException(nameof(prefixSize));\n        }\n\n        public int CommittedBytes => _committedBytes;\n\n        /// <inheritdoc />\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Advance(int count)\n        {\n            if (privateWriter == null)\n            {\n                advanced += count;\n                _committedBytes += count;\n            }\n            else\n            {\n                AdvancePrivateWriter(count);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void AdvancePrivateWriter(int count)\n        {\n            privateWriter.Advance(count);\n            _committedBytes += count;\n        }\n\n        /// <inheritdoc />\n        public Memory<byte> GetMemory(int sizeHint = 0)\n        {\n            if (privateWriter == null)\n            {\n                if (prefixMemory.IsEmpty)\n                    Initialize(sizeHint);\n\n                var res = realMemory[advanced..];\n                if (!res.IsEmpty && (uint)sizeHint <= (uint)res.Length)\n                    return res;\n\n                privateWriter = new(memoryPool);\n            }\n\n            return privateWriter.GetMemory(sizeHint);\n        }\n\n        /// <inheritdoc />\n        public Span<byte> GetSpan(int sizeHint = 0)\n        {\n            if (privateWriter == null)\n            {\n                var res = realMemory.Span[advanced..];\n                if (!res.IsEmpty && (uint)sizeHint <= (uint)res.Length)\n                    return res;\n            }\n\n            return GetMemory(sizeHint).Span;\n        }\n\n        /// <summary>\n        /// Inserts the prefix and commits the payload to the underlying <see cref=\"IBufferWriter{T}\"/>.\n        /// </summary>\n        /// <param name=\"prefix\">The prefix to write in. The length must match the one given in the constructor.</param>\n        public void Complete(ReadOnlySpan<byte> prefix)\n        {\n            if (prefix.Length != this.expectedPrefixSize)\n            {\n                ThrowPrefixLength();\n                static void ThrowPrefixLength() => throw new ArgumentOutOfRangeException(nameof(prefix), \"Prefix was not expected length.\");\n            }\n\n            if (this.prefixMemory.Length == 0)\n            {\n                // No payload was actually written, and we never requested memory, so just write it out.\n                this.innerWriter.Write(prefix);\n            }\n            else\n            {\n                // Payload has been written, so write in the prefix then commit the payload.\n                prefix.CopyTo(this.prefixMemory.Span);\n                this.innerWriter.Advance(prefix.Length + this.advanced);\n                if (this.privateWriter != null)\n                    CompletePrivateWriter();\n            }\n        }\n\n        private void CompletePrivateWriter()\n        {\n            var sequence = privateWriter.AsReadOnlySequence;\n            var sequenceLength = checked((int)sequence.Length);\n            sequence.CopyTo(innerWriter.GetSpan(sequenceLength));\n            innerWriter.Advance(sequenceLength);\n        }\n\n        /// <summary>\n        /// Sets this instance to a usable state.\n        /// </summary>\n        /// <param name=\"writer\">The underlying writer that should ultimately receive the prefix and payload.</param>\n        public void Init(PipeWriter writer) => innerWriter = writer;\n\n        /// <summary>\n        /// Resets this instance to a reusable state.\n        /// </summary>\n        public void Reset()\n        {\n            privateWriter?.Dispose();\n            privateWriter = null;\n            prefixMemory = default;\n            realMemory = default;\n            innerWriter = null;\n            advanced = 0;\n            _committedBytes = 0;\n        }\n\n        public void Dispose()\n        {\n            this.privateWriter?.Dispose();\n        }\n\n        /// <summary>\n        /// Makes the initial call to acquire memory from the underlying writer.\n        /// </summary>\n        /// <param name=\"sizeHint\">The size requested by the caller to either <see cref=\"GetMemory(int)\"/> or <see cref=\"GetSpan(int)\"/>.</param>\n        private void Initialize(int sizeHint)\n        {\n            int sizeToRequest = this.expectedPrefixSize + Math.Max(sizeHint, this.payloadSizeHint);\n            var memory = this.innerWriter.GetMemory(sizeToRequest);\n            this.prefixMemory = memory[..this.expectedPrefixSize];\n            this.realMemory = memory[this.expectedPrefixSize..];\n        }\n\n        /// <summary>\n        /// Manages a sequence of elements, readily castable as a <see cref=\"ReadOnlySequence{T}\"/>.\n        /// </summary>\n        /// <remarks>\n        /// Instance members are not thread-safe.\n        /// </remarks>\n        [DebuggerDisplay(\"{\" + nameof(DebuggerDisplay) + \",nq}\")]\n        private sealed class Sequence\n        {\n            private const int DefaultBufferSize = 4 * 1024;\n\n            private readonly Stack<SequenceSegment> segmentPool = new Stack<SequenceSegment>();\n\n            private readonly MemoryPool<byte> memoryPool;\n\n            private SequenceSegment first;\n\n            private SequenceSegment last;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"Sequence\"/> class.\n            /// </summary>\n            /// <param name=\"memoryPool\">The pool to use for recycling backing arrays.</param>\n            public Sequence(MemoryPool<byte> memoryPool)\n            {\n                if (memoryPool is null) ThrowNull();\n                this.memoryPool = memoryPool;\n\n                static void ThrowNull() => throw new ArgumentNullException(nameof(memoryPool));\n            }\n\n            /// <summary>\n            /// Gets this sequence expressed as a <see cref=\"ReadOnlySequence{T}\"/>.\n            /// </summary>\n            /// <returns>A read only sequence representing the data in this object.</returns>\n            public ReadOnlySequence<byte> AsReadOnlySequence => first != null ? new(first, first.Start, last, last.End) : default;\n\n            /// <summary>\n            /// Gets the value to display in a debugger datatip.\n            /// </summary>\n            private string DebuggerDisplay => $\"Length: {AsReadOnlySequence.Length}\";\n\n            /// <summary>\n            /// Advances the sequence to include the specified number of elements initialized into memory\n            /// returned by a prior call to <see cref=\"GetMemory(int)\"/>.\n            /// </summary>\n            /// <param name=\"count\">The number of elements written into memory.</param>\n            public void Advance(int count) => last.Advance(count);\n\n            /// <summary>\n            /// Gets writable memory that can be initialized and added to the sequence via a subsequent call to <see cref=\"Advance(int)\"/>.\n            /// </summary>\n            /// <param name=\"sizeHint\">The size of the memory required, or 0 to just get a convenient (non-empty) buffer.</param>\n            /// <returns>The requested memory.</returns>\n            public Memory<byte> GetMemory(int sizeHint)\n                => last?.TrailingSlack is { Length: > 0 } slack && (uint)slack.Length >= (uint)sizeHint ? slack : Append(sizeHint);\n\n            /// <summary>\n            /// Clears the entire sequence, recycles associated memory into pools,\n            /// and resets this instance for reuse.\n            /// This invalidates any <see cref=\"ReadOnlySequence{T}\"/> previously produced by this instance.\n            /// </summary>\n            public void Dispose()\n            {\n                var current = this.first;\n                while (current != null)\n                {\n                    current = this.RecycleAndGetNext(current);\n                }\n\n                this.first = this.last = null;\n            }\n\n            private Memory<byte> Append(int sizeHint)\n            {\n                var array = memoryPool.Rent(Math.Min(sizeHint > 0 ? sizeHint : DefaultBufferSize, memoryPool.MaxBufferSize));\n\n                var segment = this.segmentPool.Count > 0 ? this.segmentPool.Pop() : new SequenceSegment();\n                segment.SetMemory(array);\n\n                if (this.last == null)\n                {\n                    this.first = this.last = segment;\n                }\n                else\n                {\n                    if (this.last.Length > 0)\n                    {\n                        // Add a new block.\n                        this.last.SetNext(segment);\n                    }\n                    else\n                    {\n                        // The last block is completely unused. Replace it instead of appending to it.\n                        var current = this.first;\n                        if (this.first != this.last)\n                        {\n                            while (current.Next != this.last)\n                            {\n                                current = current.Next;\n                            }\n                        }\n                        else\n                        {\n                            this.first = segment;\n                        }\n\n                        current.SetNext(segment);\n                        this.RecycleAndGetNext(this.last);\n                    }\n\n                    this.last = segment;\n                }\n\n                return segment.AvailableMemory;\n            }\n\n            private SequenceSegment RecycleAndGetNext(SequenceSegment segment)\n            {\n                var recycledSegment = segment;\n                segment = segment.Next;\n                recycledSegment.ResetMemory();\n                this.segmentPool.Push(recycledSegment);\n                return segment;\n            }\n\n            private sealed class SequenceSegment : ReadOnlySequenceSegment<byte>\n            {\n                /// <summary>\n                /// Gets the index of the first element in <see cref=\"AvailableMemory\"/> to consider part of the sequence.\n                /// </summary>\n                /// <remarks>\n                /// The <see cref=\"Start\"/> represents the offset into <see cref=\"AvailableMemory\"/> where the range of \"active\" bytes begins. At the point when the block is leased\n                /// the <see cref=\"Start\"/> is guaranteed to be equal to 0. The value of <see cref=\"Start\"/> may be assigned anywhere between 0 and\n                /// <see cref=\"AvailableMemory\"/>.Length, and must be equal to or less than <see cref=\"End\"/>.\n                /// </remarks>\n                internal int Start { get; private set; }\n\n                /// <summary>\n                /// Gets or sets the index of the element just beyond the end in <see cref=\"AvailableMemory\"/> to consider part of the sequence.\n                /// </summary>\n                /// <remarks>\n                /// The <see cref=\"End\"/> represents the offset into <see cref=\"AvailableMemory\"/> where the range of \"active\" bytes ends. At the point when the block is leased\n                /// the <see cref=\"End\"/> is guaranteed to be equal to <see cref=\"Start\"/>. The value of <see cref=\"Start\"/> may be assigned anywhere between 0 and\n                /// <see cref=\"AvailableMemory\"/>.Length, and must be equal to or less than <see cref=\"End\"/>.\n                /// </remarks>\n                internal int End { get; private set; }\n\n                internal Memory<byte> TrailingSlack => this.AvailableMemory[this.End..];\n\n                private IMemoryOwner<byte> MemoryOwner;\n\n                internal Memory<byte> AvailableMemory;\n\n                internal int Length => this.End - this.Start;\n\n                internal new SequenceSegment Next\n                {\n                    get => (SequenceSegment)base.Next;\n                    set => base.Next = value;\n                }\n\n                internal void SetMemory(IMemoryOwner<byte> memoryOwner)\n                {\n                    this.MemoryOwner = memoryOwner;\n                    this.AvailableMemory = memoryOwner.Memory;\n                }\n\n                internal void ResetMemory()\n                {\n                    this.MemoryOwner.Dispose();\n                    this.MemoryOwner = null;\n                    this.AvailableMemory = default;\n\n                    this.Memory = default;\n                    this.Next = null;\n                    this.RunningIndex = 0;\n                    this.Start = 0;\n                    this.End = 0;\n                }\n\n                internal void SetNext(SequenceSegment segment)\n                {\n                    segment.RunningIndex = this.RunningIndex + this.End;\n                    this.Next = segment;\n                }\n\n                public void Advance(int count)\n                {\n                    if (count < 0) ThrowNegative();\n                    var value = End + count;\n\n                    // If we ever support creating these instances on existing arrays, such that\n                    // this.Start isn't 0 at the beginning, we'll have to \"pin\" this.Start and remove\n                    // Advance, forcing Sequence<T> itself to track it, the way Pipe does it internally.\n                    this.Memory = AvailableMemory[..value];\n                    this.End = value;\n\n                    static void ThrowNegative() => throw new ArgumentOutOfRangeException(\n                        nameof(count),\n                        \"Value must be greater than or equal to 0\");\n                }\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/RejectionResponse.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    [Id(102), GenerateSerializer, Immutable]\n    internal sealed class RejectionResponse\n    {\n        [Id(0)]\n        public string RejectionInfo { get; init; }\n\n        [Id(1)]\n        public Message.RejectionTypes RejectionType { get; init; }\n\n        [Id(2)]\n        public Exception Exception { get; init; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/StaticGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Messaging\n{\n    /// <summary>\n    /// <see cref=\"IGatewayListProvider\"/> implementation which returns a static list, configured via <see cref=\"StaticGatewayListProviderOptions\"/>.\n    /// </summary>\n    public class StaticGatewayListProvider : IGatewayListProvider\n    {\n        private readonly StaticGatewayListProviderOptions options;\n        private readonly TimeSpan maxStaleness;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StaticGatewayListProvider\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The specific options.</param>\n        /// <param name=\"gatewayOptions\">The general gateway options.</param>\n        public StaticGatewayListProvider(IOptions<StaticGatewayListProviderOptions> options, IOptions<GatewayOptions> gatewayOptions)\n        {\n            this.options = options.Value;\n            this.maxStaleness = gatewayOptions.Value.GatewayListRefreshPeriod;\n        }\n\n        /// <inheritdoc />\n        public Task InitializeGatewayListProvider() => Task.CompletedTask;\n        \n        /// <inheritdoc />\n        public Task<IList<Uri>> GetGateways() => Task.FromResult<IList<Uri>>(this.options.Gateways);\n\n        /// <inheritdoc />\n        public TimeSpan MaxStaleness\n        {\n            get => this.maxStaleness;\n        }\n\n        /// <inheritdoc />\n        public bool IsUpdatable\n        {\n            get => true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/StaticGatewayListProviderBuilder.cs",
    "content": "using System.Collections.Generic;\nusing System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"Development\", \"Clustering\", \"Client\", typeof(StaticGatewayListProviderBuilder))]\n[assembly: RegisterProvider(\"Static\", \"Clustering\", \"Client\", typeof(StaticGatewayListProviderBuilder))]\n\nnamespace Orleans.Providers;\n\ninternal sealed class StaticGatewayListProviderBuilder : IProviderBuilder<IClientBuilder>\n{\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        var endpoints = new List<IPEndPoint>();\n        var gatewaysSection = configurationSection.GetSection(\"Gateways\");\n        foreach (var child in gatewaysSection.GetChildren())\n        {\n            if (IPEndPoint.TryParse(child.Value, out var ep))\n            {\n                endpoints.Add(ep);\n            }\n        }\n\n        builder.UseStaticClustering([.. endpoints]);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Messaging/StatusResponse.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Runtime\n{\n    [Id(103), Serializable, GenerateSerializer, Immutable]\n    internal sealed class StatusResponse\n    {\n        [Id(0)]\n        private readonly uint _statusFlags;\n\n        public StatusResponse(bool isExecuting, bool isWaiting, List<string> diagnostics)\n        {\n            if (isExecuting) _statusFlags |= 0x1;\n            if (isWaiting) _statusFlags |= 0x2;\n\n            Diagnostics = diagnostics;\n        }\n\n        [Id(1)]\n        public List<string> Diagnostics { get; }\n\n        public bool IsExecuting => (_statusFlags & 0x1) != 0;\n\n        public bool IsWaiting => (_statusFlags & 0x2) != 0;\n\n        public override string ToString() => $\"IsExecuting: {IsExecuting}, IsWaiting: {IsWaiting}, Diagnostics: [{string.Join(\", \", this.Diagnostics)}]\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ClientConnectionOptions.cs",
    "content": "using System;\nusing Microsoft.AspNetCore.Connections;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for clients connections.\n    /// </summary>\n    public class ClientConnectionOptions\n    {\n        private readonly ConnectionBuilderDelegates delegates = new ConnectionBuilderDelegates();\n\n        /// <summary>\n        /// Adds a connection configuration delegate.\n        /// </summary>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        public void ConfigureConnection(Action<IConnectionBuilder> configure) => this.delegates.Add(configure);\n\n        /// <summary>\n        /// Configures the provided connection builder using these options.\n        /// </summary>\n        /// <param name=\"builder\">The connection builder.</param>\n        internal void ConfigureConnectionBuilder(IConnectionBuilder builder) => this.delegates.Invoke(builder);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ClientOutboundConnection.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed partial class ClientOutboundConnection : Connection\n    {\n        private readonly ClientMessageCenter messageCenter;\n        private readonly ConnectionManager connectionManager;\n        private readonly ConnectionOptions connectionOptions;\n        private readonly ClusterOptions clusterOptions;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n\n        public ClientOutboundConnection(\n            SiloAddress remoteSiloAddress,\n            ConnectionContext connection,\n            ConnectionDelegate middleware,\n            ClientMessageCenter messageCenter,\n            ConnectionManager connectionManager,\n            ConnectionOptions connectionOptions,\n            ConnectionCommon connectionShared,\n            ConnectionPreambleHelper connectionPreambleHelper,\n            ClusterOptions clusterOptions)\n            : base(connection, middleware, connectionShared)\n        {\n            this.messageCenter = messageCenter;\n            this.connectionManager = connectionManager;\n            this.connectionOptions = connectionOptions;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n            this.clusterOptions = clusterOptions;\n            this.RemoteSiloAddress = remoteSiloAddress ?? throw new ArgumentNullException(nameof(remoteSiloAddress));\n        }\n\n        public SiloAddress RemoteSiloAddress { get; }\n\n        protected override ConnectionDirection ConnectionDirection => ConnectionDirection.ClientToGateway;\n\n        protected override IMessageCenter MessageCenter => this.messageCenter;\n\n        protected override void RecordMessageReceive(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageReceive(msg, numTotalBytes, headerBytes, ConnectionDirection, RemoteSiloAddress);\n        }\n\n        protected override void RecordMessageSend(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageSend(msg, numTotalBytes, headerBytes, ConnectionDirection, RemoteSiloAddress);\n        }\n\n        protected override void OnReceivedMessage(Message message)\n        {\n            this.messageCenter.DispatchLocalMessage(message);\n        }\n\n        protected override async Task RunInternal()\n        {\n            Exception error = default;\n            try\n            {\n                this.messageCenter.OnGatewayConnectionOpen();\n\n                var myClusterId = clusterOptions.ClusterId;\n                await connectionPreambleHelper.Write(\n                    this.Context,\n                    new ConnectionPreamble\n                    {\n                        NetworkProtocolVersion = this.connectionOptions.ProtocolVersion,\n                        NodeIdentity = this.messageCenter.ClientId.GrainId,\n                        SiloAddress = null,\n                        ClusterId = myClusterId\n                    });\n\n                var preamble = await connectionPreambleHelper.Read(this.Context);\n                LogInformationEstablishedConnection(this.Log, preamble.SiloAddress, preamble.NetworkProtocolVersion.ToString());\n\n                if (preamble.ClusterId != myClusterId)\n                {\n                    throw new InvalidOperationException($@\"Unexpected cluster id \"\"{preamble.ClusterId}\"\", expected \"\"{myClusterId}\"\"\");\n                }\n\n                await base.RunInternal();\n            }\n            catch (Exception exception) when ((error = exception) is null)\n            {\n                Debug.Fail(\"Execution should not be able to reach this point.\");\n            }\n            finally\n            {\n                this.connectionManager.OnConnectionTerminated(this.RemoteSiloAddress, this, error);\n                this.messageCenter.OnGatewayConnectionClosed();\n            }\n        }\n\n        protected override bool PrepareMessageForSend(Message msg)\n        {\n            // Check to make sure we're not stopped\n            if (!this.IsValid)\n            {\n                // Recycle the message we've dequeued. Note that this will recycle messages that were queued up to be sent when the gateway connection is declared dead\n                msg.TargetSilo = null;\n                this.messageCenter.SendMessage(msg);\n                return false;\n            }\n\n            if (msg.TargetSilo != null) return true;\n\n            msg.TargetSilo = this.RemoteSiloAddress;\n\n            return true;\n        }\n\n        protected override void RetryMessage(Message msg, Exception ex = null)\n        {\n            if (msg == null) return;\n\n            if (msg.RetryCount < MessagingOptions.DEFAULT_MAX_MESSAGE_SEND_RETRIES)\n            {\n                ++msg.RetryCount;\n                this.messageCenter.SendMessage(msg);\n            }\n            else\n            {\n                var reason = new StringBuilder(\"Retry count exceeded. \");\n                if (ex != null)\n                {\n                    reason.Append(\"Original exception is: \").Append(ex.ToString());\n                }\n                reason.Append(\"Msg is: \").Append(msg);\n                FailMessage(msg, reason.ToString());\n            }\n        }\n\n        internal void SendRejection(Message msg, Message.RejectionTypes rejectionType, string reason)\n        {\n            MessagingInstruments.OnRejectedMessage(msg);\n            if (string.IsNullOrEmpty(reason)) reason = \"Rejection from silo - Unknown reason.\";\n            var error = this.MessageFactory.CreateRejectionResponse(msg, rejectionType, reason);\n\n            // rejection msgs are always originated locally, they are never remote.\n            this.OnReceivedMessage(error);\n        }\n\n        public void FailMessage(Message msg, string reason)\n        {\n            MessagingInstruments.OnFailedSentMessage(msg);\n            if (msg.Direction == Message.Directions.Request)\n            {\n                LogDebugClientIsRejectingMessage(this.Log, msg, reason);\n                // Done retrying, send back an error instead\n                this.SendRejection(msg, Message.RejectionTypes.Transient, $\"Client is rejecting message: {msg}. Reason = {reason}\");\n            }\n            else\n            {\n                LogInformationClientIsDroppingMessage(this.Log, msg, reason);\n                MessagingInstruments.OnDroppedSentMessage(msg);\n            }\n        }\n\n        protected override void OnSendMessageFailure(Message message, string error)\n        {\n            message.TargetSilo = null;\n            this.messageCenter.SendMessage(message);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Established connection to {Silo} with protocol version {ProtocolVersion}\"\n        )]\n        private static partial void LogInformationEstablishedConnection(ILogger logger, SiloAddress silo, string protocolVersion);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.MessagingSendingRejection,\n            Message = \"Client is rejecting message: {Message}. Reason = {Reason}\"\n        )]\n        private static partial void LogDebugClientIsRejectingMessage(ILogger logger, Message message, string reason);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.Messaging_OutgoingMS_DroppingMessage,\n            Message = \"Client is dropping message: {Message}. Reason = {Reason}\"\n        )]\n        private static partial void LogInformationClientIsDroppingMessage(ILogger logger, Message message, string reason);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ClientOutboundConnectionFactory.cs",
    "content": "using System.Threading;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class ClientOutboundConnectionFactory : ConnectionFactory\n    {\n        internal static readonly object ServicesKey = new object();\n        private readonly ConnectionCommon connectionShared;\n        private readonly ClientConnectionOptions clientConnectionOptions;\n        private readonly ClusterOptions clusterOptions;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n#if NET9_0_OR_GREATER\n        private readonly Lock initializationLock = new();\n#else\n        private readonly object initializationLock = new();\n#endif\n        private volatile bool isInitialized;\n        private ClientMessageCenter messageCenter;\n        private ConnectionManager connectionManager;\n\n        public ClientOutboundConnectionFactory(\n            IOptions<ConnectionOptions> connectionOptions,\n            IOptions<ClientConnectionOptions> clientConnectionOptions,\n            IOptions<ClusterOptions> clusterOptions,\n            ConnectionCommon connectionShared,\n            ConnectionPreambleHelper connectionPreambleHelper)\n            : base(connectionShared.ServiceProvider.GetRequiredKeyedService<IConnectionFactory>(ServicesKey), connectionShared.ServiceProvider, connectionOptions)\n        {\n            this.connectionShared = connectionShared;\n            this.clientConnectionOptions = clientConnectionOptions.Value;\n            this.clusterOptions = clusterOptions.Value;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n        }\n\n        protected override Connection CreateConnection(SiloAddress address, ConnectionContext context)\n        {\n            EnsureInitialized();\n\n            return new ClientOutboundConnection(\n                address,\n                context,\n                this.ConnectionDelegate,\n                this.messageCenter,\n                this.connectionManager,\n                this.ConnectionOptions,\n                this.connectionShared,\n                this.connectionPreambleHelper,\n                this.clusterOptions);\n        }\n\n        protected override void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder)\n        {\n            this.clientConnectionOptions.ConfigureConnectionBuilder(connectionBuilder);\n            base.ConfigureConnectionBuilder(connectionBuilder);\n        }\n\n        private void EnsureInitialized()\n        {\n            if (!isInitialized)\n            {\n                lock (this.initializationLock)\n                {\n                    if (!isInitialized)\n                    {\n                        this.messageCenter = this.connectionShared.ServiceProvider.GetRequiredService<ClientMessageCenter>();\n                        this.connectionManager = this.connectionShared.ServiceProvider.GetRequiredService<ConnectionManager>();\n                        this.isInitialized = true;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Connection.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.ObjectPool;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal abstract partial class Connection\n    {\n        private static readonly Func<ConnectionContext, Task> OnConnectedDelegate = context => OnConnectedAsync(context);\n        private static readonly Action<object> OnConnectionClosedDelegate = state => ((Connection)state).OnTransportConnectionClosed();\n        private static readonly UnboundedChannelOptions OutgoingMessageChannelOptions = new UnboundedChannelOptions\n        {\n            SingleReader = true,\n            SingleWriter = false,\n            AllowSynchronousContinuations = false\n        };\n\n        private static readonly ObjectPool<MessageHandler> MessageHandlerPool = ObjectPool.Create(new MessageHandlerPoolPolicy());\n        private readonly ConnectionCommon shared;\n        private readonly ConnectionDelegate middleware;\n        private readonly Channel<Message> outgoingMessages;\n        private readonly ChannelWriter<Message> outgoingMessageWriter;\n        private readonly List<Message> inflight = new List<Message>(4);\n        private readonly TaskCompletionSource<int> _transportConnectionClosed = new(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly TaskCompletionSource<int> _initializationTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n        private IDuplexPipe _transport;\n        private Task _processIncomingTask;\n        private Task _processOutgoingTask;\n        private Task _closeTask;\n\n        protected Connection(\n            ConnectionContext connection,\n            ConnectionDelegate middleware,\n            ConnectionCommon shared)\n        {\n            this.Context = connection ?? throw new ArgumentNullException(nameof(connection));\n            this.middleware = middleware ?? throw new ArgumentNullException(nameof(middleware));\n            this.shared = shared;\n            this.outgoingMessages = Channel.CreateUnbounded<Message>(OutgoingMessageChannelOptions);\n            this.outgoingMessageWriter = this.outgoingMessages.Writer;\n\n            // Set the connection on the connection context so that it can be retrieved by the middleware.\n            this.Context.Features.Set<Connection>(this);\n\n            this.RemoteEndPoint = NormalizeEndpoint(this.Context.RemoteEndPoint);\n            this.LocalEndPoint = NormalizeEndpoint(this.Context.LocalEndPoint);\n        }\n\n        public ConnectionCommon Shared => shared;\n        public string ConnectionId => this.Context?.ConnectionId;\n        public virtual EndPoint RemoteEndPoint { get; }\n        public virtual EndPoint LocalEndPoint { get; }\n        protected ConnectionContext Context { get; }\n        protected NetworkingTrace Log => this.shared.NetworkingTrace;\n        protected MessagingTrace MessagingTrace => this.shared.MessagingTrace;\n        protected abstract ConnectionDirection ConnectionDirection { get; }\n        protected MessageFactory MessageFactory => this.shared.MessageFactory;\n        protected abstract IMessageCenter MessageCenter { get; }\n\n        public bool IsValid => _closeTask is null;\n\n        public Task Initialized => _initializationTcs.Task;\n\n        public static void ConfigureBuilder(ConnectionBuilder builder) => builder.Run(OnConnectedDelegate);\n\n        /// <summary>\n        /// Start processing this connection.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> which completes when the connection terminates and has completed processing.</returns>\n        public async Task Run()\n        {\n            Exception error = default;\n            try\n            {\n                // Eventually calls through to OnConnectedAsync (unless the connection delegate has been misconfigured)\n                await this.middleware(this.Context);\n            }\n            catch (Exception exception)\n            {\n                error = exception;\n            }\n            finally\n            {\n                await this.CloseAsync(error);\n            }\n        }\n\n        private static Task OnConnectedAsync(ConnectionContext context)\n        {\n            var connection = context.Features.Get<Connection>();\n            context.ConnectionClosed.Register(OnConnectionClosedDelegate, connection);\n\n            NetworkingInstruments.OnOpenedSocket(connection.ConnectionDirection);\n            return connection.RunInternal();\n        }\n\n        protected virtual async Task RunInternal()\n        {\n            _transport = this.Context.Transport;\n            _processIncomingTask = this.ProcessIncoming();\n            _processOutgoingTask = this.ProcessOutgoing();\n            _initializationTcs.TrySetResult(0);\n            await Task.WhenAll(_processIncomingTask, _processOutgoingTask);\n        }\n\n        /// <summary>\n        /// Called immediately prior to transporting a message.\n        /// </summary>\n        /// <param name=\"msg\"></param>\n        /// <returns>Whether or not to continue transporting the message.</returns>\n        protected abstract bool PrepareMessageForSend(Message msg);\n\n        protected abstract void RetryMessage(Message msg, Exception ex = null);\n\n        public Task CloseAsync(Exception exception)\n        {\n            StartClosing(exception);\n            return _closeTask;\n        }\n\n        private void OnTransportConnectionClosed()\n        {\n            StartClosing(new ConnectionAbortedException(\"Underlying connection closed\"));\n            _transportConnectionClosed.SetResult(0);\n        }\n\n        private void StartClosing(Exception exception)\n        {\n            if (_closeTask is not null)\n            {\n                return;\n            }\n\n            var task = new Task<Task>(CloseAsync);\n            if (Interlocked.CompareExchange(ref _closeTask, task.Unwrap(), null) is not null)\n            {\n                return;\n            }\n\n            _initializationTcs.TrySetException(exception ?? new ConnectionAbortedException(\"Connection initialization failed\"));\n            _initializationTcs.Task.Ignore();\n\n            LogInformationClosingConnection(this.Log, exception, this);\n\n            task.Start(TaskScheduler.Default);\n        }\n\n        /// <summary>\n        /// Close the connection. This method should only be called by <see cref=\"StartClosing(Exception)\"/>.\n        /// </summary>\n        private async Task CloseAsync()\n        {\n            NetworkingInstruments.OnClosedSocket(this.ConnectionDirection);\n\n            // Signal the outgoing message processor to exit gracefully.\n            this.outgoingMessageWriter.TryComplete();\n\n            var transportFeature = Context.Features.Get<IUnderlyingTransportFeature>();\n            var transport = transportFeature?.Transport ?? _transport;\n            transport.Input.CancelPendingRead();\n            transport.Output.CancelPendingFlush();\n\n            // Try to gracefully stop the reader/writer loops, if they are running.\n            if (_processIncomingTask is { IsCompleted: false } incoming)\n            {\n                try\n                {\n                    await incoming;\n                }\n                catch (Exception processIncomingException)\n                {\n                    // Swallow any exceptions here.\n                    LogWarningExceptionProcessingIncomingMessages(this.Log, processIncomingException, this);\n                }\n            }\n\n            if (_processOutgoingTask is { IsCompleted: false } outgoing)\n            {\n                try\n                {\n                    await outgoing;\n                }\n                catch (Exception processOutgoingException)\n                {\n                    // Swallow any exceptions here.\n                    LogWarningExceptionProcessingOutgoingMessages(this.Log, processOutgoingException, this);\n                }\n            }\n\n            // Only wait for the transport to close if the connection actually started being processed.\n            if (_processIncomingTask is not null && _processOutgoingTask is not null)\n            {\n                // Abort the connection and wait for the transport to signal that it's closed before disposing it.\n                try\n                {\n                    this.Context.Abort();\n                }\n                catch (Exception exception)\n                {\n                    LogWarningExceptionAbortingConnection(this.Log, exception, this);\n                }\n\n                await _transportConnectionClosed.Task;\n            }\n\n            try\n            {\n                await this.Context.DisposeAsync();\n            }\n            catch (Exception abortException)\n            {\n                // Swallow any exceptions here.\n                LogWarningExceptionTerminatingConnection(this.Log, abortException, this);\n            }\n\n            // Reject in-flight messages.\n            foreach (var message in this.inflight)\n            {\n                this.OnSendMessageFailure(message, \"Connection terminated\");\n            }\n\n            this.inflight.Clear();\n\n            // Reroute enqueued messages.\n            var i = 0;\n            while (this.outgoingMessages.Reader.TryRead(out var message))\n            {\n                if (i == 0)\n                {\n                    LogInformationReroutingMessages(this.Log, new EndPointLogValue(this.RemoteEndPoint));\n                }\n\n                ++i;\n                this.RetryMessage(message);\n            }\n\n            if (i > 0)\n            {\n                LogInformationReroutedMessages(this.Log, i, new EndPointLogValue(this.RemoteEndPoint));\n            }\n        }\n\n        public virtual void Send(Message message)\n        {\n            Debug.Assert(!message.IsLocalOnly);\n            if (!this.outgoingMessageWriter.TryWrite(message))\n            {\n                this.RerouteMessage(message);\n            }\n        }\n\n        public override string ToString() => $\"[Local: {this.LocalEndPoint}, Remote: {this.RemoteEndPoint}, ConnectionId: {this.Context.ConnectionId}]\";\n\n        protected abstract void RecordMessageReceive(Message msg, int numTotalBytes, int headerBytes);\n        protected abstract void RecordMessageSend(Message msg, int numTotalBytes, int headerBytes);\n        protected abstract void OnReceivedMessage(Message message);\n        protected abstract void OnSendMessageFailure(Message message, string error);\n\n        private async Task ProcessIncoming()\n        {\n            await Task.Yield();\n\n            Exception error = default;\n            var serializer = this.shared.ServiceProvider.GetRequiredService<MessageSerializer>();\n            try\n            {\n                var input = this._transport.Input;\n                var requiredBytes = 0;\n                while (true)\n                {\n                    var readResult = await input.ReadAsync();\n\n                    var buffer = readResult.Buffer;\n                    if (buffer.Length >= requiredBytes)\n                    {\n                        do\n                        {\n                            Message message = default;\n                            try\n                            {\n                                int headerLength, bodyLength;\n                                (requiredBytes, headerLength, bodyLength) = serializer.TryRead(ref buffer, out message);\n                                if (requiredBytes == 0)\n                                {\n                                    Debug.Assert(message is not null);\n                                    RecordMessageReceive(message, bodyLength + headerLength, headerLength);\n                                    var handler = MessageHandlerPool.Get();\n                                    handler.Set(message, this);\n                                    ThreadPool.UnsafeQueueUserWorkItem(handler, preferLocal: true);\n                                }\n                            }\n                            catch (Exception exception)\n                            {\n                                if (!HandleReceiveMessageFailure(message, exception))\n                                {\n                                    throw;\n                                }   \n                            }\n                        } while (requiredBytes == 0);\n                    }\n\n                    if (readResult.IsCanceled || readResult.IsCompleted)\n                    {\n                        break;\n                    }\n\n                    input.AdvanceTo(buffer.Start, buffer.End);\n                }\n            }\n            catch (Exception exception)\n            {\n                if (IsValid)\n                {\n                    LogWarningExceptionProcessingMessagesFromRemote(this.Log, exception, this.RemoteEndPoint);\n                }\n\n                error = exception;\n            }\n            finally\n            {\n                _transport.Input.Complete();\n                this.StartClosing(error);\n            }\n        }\n\n        private async Task ProcessOutgoing()\n        {\n            await Task.Yield();\n\n            Exception error = default;\n            var serializer = this.shared.ServiceProvider.GetRequiredService<MessageSerializer>();\n            var messageObserver = this.shared.MessageStatisticsSink.GetMessageObserver();\n            try\n            {\n                var output = this._transport.Output;\n                var reader = this.outgoingMessages.Reader;\n\n                while (true)\n                {\n                    var more = await reader.WaitToReadAsync();\n                    if (!more)\n                    {\n                        break;\n                    }\n\n                    Message message = default;\n                    try\n                    {\n                        while (inflight.Count < inflight.Capacity && reader.TryRead(out message) && this.PrepareMessageForSend(message))\n                        {\n                            inflight.Add(message);\n                            var (headerLength, bodyLength) = serializer.Write(output, message);\n                            RecordMessageSend(message, headerLength + bodyLength, headerLength);\n                            messageObserver?.Invoke(message);\n                            message = null;\n                        }\n                    }\n                    catch (Exception exception)\n                    {\n                        if (!HandleSendMessageFailure(message, exception))\n                        {\n                            throw;\n                        }\n                    }\n\n                    var flushResult = await output.FlushAsync();\n                    if (flushResult.IsCompleted || flushResult.IsCanceled)\n                    {\n                        break;\n                    }\n\n                    inflight.Clear();\n                }\n            }\n            catch (Exception exception)\n            {\n                if (IsValid)\n                {\n                    LogWarningExceptionProcessingMessagesToRemote(this.Log, exception, this.RemoteEndPoint);\n                }\n\n                error = exception;\n            }\n            finally\n            {\n                _transport.Output.Complete();\n                this.StartClosing(error);\n            }\n        }\n\n        private void RerouteMessage(Message message)\n        {\n            LogInformationReroutingMessage(this.Log, message, new EndPointLogValue(this.RemoteEndPoint));\n\n            ThreadPool.UnsafeQueueUserWorkItem(state =>\n            {\n                var (t, msg) = ((Connection, Message))state;\n                t.RetryMessage(msg);\n            }, (this, message));\n        }\n\n        private static EndPoint NormalizeEndpoint(EndPoint endpoint)\n        {\n            if (!(endpoint is IPEndPoint ep)) return endpoint;\n\n            // Normalize endpoints\n            if (ep.Address.IsIPv4MappedToIPv6)\n            {\n                return new IPEndPoint(ep.Address.MapToIPv4(), ep.Port);\n            }\n\n            return ep;\n        }\n\n        /// <summary>\n        /// Handles a message receive failure.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the exception should not be caught and <see langword=\"false\"/> if it should be caught.</returns>\n        private bool HandleReceiveMessageFailure(Message message, Exception exception)\n        {\n            LogErrorExceptionReadingMessage(this.Log, exception, message, this.RemoteEndPoint, this.LocalEndPoint);\n\n            // If deserialization completely failed, rethrow the exception so that it can be handled at another level.\n            if (message is null || exception is InvalidMessageFrameException)\n            {\n                // Returning false here informs the caller that the exception should not be caught.\n                return false;\n            }\n\n            // The message body was not successfully decoded, but the headers were.\n            MessagingInstruments.OnRejectedMessage(message);\n\n            if (message.HasDirection)\n            {\n                if (message.Direction == Message.Directions.Request)\n                {\n                    // Send a fast fail to the caller.\n                    var response = this.MessageFactory.CreateResponseMessage(message);\n                    response.Result = Message.ResponseTypes.Error;\n                    response.BodyObject = Response.FromException(exception);\n\n                    // Send the error response and continue processing the next message.\n                    this.Send(response);\n                }\n                else if (message.Direction == Message.Directions.Response)\n                {\n                    // If the message was a response, propagate the exception to the intended recipient.\n                    message.Result = Message.ResponseTypes.Error;\n                    message.BodyObject = Response.FromException(exception);\n                    this.OnReceivedMessage(message);\n                }\n            }\n\n            // The exception has been handled by propagating it onwards.\n            return true;\n        }\n\n        private bool HandleSendMessageFailure(Message message, Exception exception)\n        {\n            // We get here if we failed to serialize the msg (or any other catastrophic failure).\n            // Request msg fails to serialize on the sender, so we just enqueue a rejection msg.\n            // Response msg fails to serialize on the responding silo, so we try to send an error response back.\n            LogErrorExceptionSendingMessage(this.Log, exception, message, this.RemoteEndPoint, this.LocalEndPoint);\n\n            if (message is null || exception is InvalidMessageFrameException)\n            {\n                // Returning false here informs the caller that the exception should not be caught.\n                return false;\n            }\n\n            MessagingInstruments.OnFailedSentMessage(message);\n\n            if (message.Direction == Message.Directions.Request)\n            {\n                var response = this.MessageFactory.CreateResponseMessage(message);\n                response.Result = Message.ResponseTypes.Error;\n                response.BodyObject = Response.FromException(exception);\n\n                this.MessageCenter.DispatchLocalMessage(response);\n            }\n            else if (message.Direction == Message.Directions.Response && message.RetryCount < MessagingOptions.DEFAULT_MAX_MESSAGE_SEND_RETRIES)\n            {\n                // If we failed sending an original response, turn the response body into an error and reply with it.\n                // unless we have already tried sending the response multiple times.\n                message.Result = Message.ResponseTypes.Error;\n                message.BodyObject = Response.FromException(exception);\n                ++message.RetryCount;\n\n                this.Send(message);\n            }\n            else\n            {\n                LogWarningDroppingMessage(\n                    this.Log,\n                    exception,\n                    message);\n\n                MessagingInstruments.OnDroppedSentMessage(message);\n            }\n\n            return true;\n        }\n\n        private sealed class MessageHandlerPoolPolicy : PooledObjectPolicy<MessageHandler>\n        {\n            public override MessageHandler Create() => new MessageHandler();\n\n            public override bool Return(MessageHandler obj)\n            {\n                obj.Reset();\n                return true;\n            }\n        }\n\n        private sealed class MessageHandler : IThreadPoolWorkItem\n        {\n            private Message message;\n            private Connection connection;\n\n            public void Set(Message m, Connection c)\n            {\n                this.message = m;\n                this.connection = c;\n            }\n\n            public void Execute()\n            {\n                this.connection.OnReceivedMessage(this.message);\n                MessageHandlerPool.Return(this);\n            }\n\n            public void Reset()\n            {\n                this.message = null;\n                this.connection = null;\n            }\n        }\n\n        private readonly struct EndPointLogValue(EndPoint endPoint)\n        {\n            public override string ToString() => endPoint?.ToString() ?? \"(never connected)\";\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Closing connection {Connection}\"\n        )]\n        private static partial void LogInformationClosingConnection(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception processing incoming messages on connection {Connection}\"\n        )]\n        private static partial void LogWarningExceptionProcessingIncomingMessages(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception processing outgoing messages on connection {Connection}\"\n        )]\n        private static partial void LogWarningExceptionProcessingOutgoingMessages(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception aborting connection {Connection}\"\n        )]\n        private static partial void LogWarningExceptionAbortingConnection(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception terminating connection {Connection}\"\n        )]\n        private static partial void LogWarningExceptionTerminatingConnection(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Rerouting messages for remote endpoint {EndPoint}\"\n        )]\n        private static partial void LogInformationReroutingMessages(ILogger logger, EndPointLogValue endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Rerouted {Count} messages for remote endpoint {EndPoint}\"\n        )]\n        private static partial void LogInformationReroutedMessages(ILogger logger, int count, EndPointLogValue endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception while processing messages from remote endpoint {EndPoint}\"\n        )]\n        private static partial void LogWarningExceptionProcessingMessagesFromRemote(ILogger logger, Exception exception, EndPoint endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception while processing messages to remote endpoint {EndPoint}\"\n        )]\n        private static partial void LogWarningExceptionProcessingMessagesToRemote(ILogger logger, Exception exception, EndPoint endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Rerouting message {Message} from remote endpoint {EndPoint}\"\n        )]\n        private static partial void LogInformationReroutingMessage(ILogger logger, Message message, EndPointLogValue endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception reading message {Message} from remote endpoint {Remote} to local endpoint {Local}\"\n        )]\n        private static partial void LogErrorExceptionReadingMessage(ILogger logger, Exception exception, Message message, EndPoint remote, EndPoint local);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception sending message {Message} to remote endpoint {Remote} from local endpoint {Local}\"\n        )]\n        private static partial void LogErrorExceptionSendingMessage(ILogger logger, Exception exception, Message message, EndPoint remote, EndPoint local);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Messaging_OutgoingMS_DroppingMessage,\n            Level = LogLevel.Warning,\n            Message = \"Dropping message which failed during serialization: {Message}\"\n        )]\n        private static partial void LogWarningDroppingMessage(ILogger logger, Exception exception, Message message);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionBuilderDelegates.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.AspNetCore.Connections;\n\nnamespace Orleans.Configuration\n{\n    internal class ConnectionBuilderDelegates\n    {\n        private readonly List<Action<IConnectionBuilder>> configurationDelegates = new List<Action<IConnectionBuilder>>();\n\n        public void Add(Action<IConnectionBuilder> configure)\n            => this.configurationDelegates.Add(configure ?? throw new ArgumentNullException(nameof(configure)));\n\n        public void Invoke(IConnectionBuilder builder)\n        {\n            foreach (var configureDelegate in this.configurationDelegates)\n            {\n                configureDelegate(builder);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionFactory.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal abstract class ConnectionFactory\n    {\n        private readonly IConnectionFactory connectionFactory;\n        private readonly IServiceProvider serviceProvider;\n        private ConnectionDelegate connectionDelegate;\n\n        protected ConnectionFactory(\n            IConnectionFactory connectionFactory,\n            IServiceProvider serviceProvider,\n            IOptions<ConnectionOptions> connectionOptions)\n        {\n            this.connectionFactory = connectionFactory;\n            this.serviceProvider = serviceProvider;\n            this.ConnectionOptions = connectionOptions.Value;\n        }\n\n        protected ConnectionOptions ConnectionOptions { get; }\n\n        protected ConnectionDelegate ConnectionDelegate\n        {\n            get\n            {\n                if (this.connectionDelegate != null) return this.connectionDelegate;\n\n                lock (this)\n                {\n                    if (this.connectionDelegate != null) return this.connectionDelegate;\n\n                    // Configure the connection builder using the user-defined options.\n                    var connectionBuilder = new ConnectionBuilder(this.serviceProvider);\n                    connectionBuilder.Use(next =>\n                    {\n                        return context =>\n                        {\n                            context.Features.Set<IUnderlyingTransportFeature>(new UnderlyingConnectionTransportFeature { Transport = context.Transport });\n                            return next(context);\n                        };\n                    });\n                    this.ConfigureConnectionBuilder(connectionBuilder);\n                    Connection.ConfigureBuilder(connectionBuilder);\n                    return this.connectionDelegate = connectionBuilder.Build();\n                }\n            }\n        }\n\n        protected virtual void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder) { }\n\n        protected abstract Connection CreateConnection(SiloAddress address, ConnectionContext context);\n\n        public virtual async ValueTask<Connection> ConnectAsync(SiloAddress address, CancellationToken cancellationToken)\n        {\n            var connectionContext = await this.connectionFactory.ConnectAsync(address.Endpoint, cancellationToken);\n            var connection = this.CreateConnection(address, connectionContext);\n            return connection;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionFailedException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// Indicates that a connection failed.\n    /// </summary>\n    public class ConnectionFailedException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConnectionFailedException\"/> class.\n        /// </summary>\n        public ConnectionFailedException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConnectionFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public ConnectionFailedException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConnectionFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public ConnectionFailedException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConnectionFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        protected ConnectionFailedException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionLogScope.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal class ConnectionLogScope : IReadOnlyList<KeyValuePair<string, object>>\n    {\n        private readonly Connection _connection;\n\n        private string _cachedToString;\n\n        public ConnectionLogScope(Connection connection)\n        {\n            _connection = connection;\n        }\n\n        public KeyValuePair<string, object> this[int index]\n        {\n            get\n            {\n                if (index == 0)\n                {\n                    return new KeyValuePair<string, object>(nameof(Connection.ConnectionId), _connection.ConnectionId);\n                }\n\n                if (index == 1)\n                {\n                    return new KeyValuePair<string, object>(nameof(Connection.LocalEndPoint), _connection.LocalEndPoint);\n                }\n\n                if (index == 2)\n                {\n                    return new KeyValuePair<string, object>(nameof(Connection.RemoteEndPoint), _connection.RemoteEndPoint);\n                }\n\n                throw new ArgumentOutOfRangeException(nameof(index));\n            }\n        }\n\n        public int Count => 3;\n\n        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()\n        {\n            for (int i = 0; i < Count; ++i)\n            {\n                yield return this[i];\n            }\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        public override string ToString()\n        {\n            if (_cachedToString == null)\n            {\n                _cachedToString = _connection.ToString();\n            }\n\n            return _cachedToString;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionManager.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed partial class ConnectionManager\n    {\n        [ThreadStatic]\n        private static uint nextConnection;\n\n        private readonly ConcurrentDictionary<SiloAddress, ConnectionEntry> connections = new();\n        private readonly ConnectionOptions connectionOptions;\n        private readonly ConnectionFactory connectionFactory;\n        private readonly NetworkingTrace trace;\n        private readonly CancellationTokenSource shutdownCancellation = new();\n#if NET9_0_OR_GREATER\n        private readonly Lock lockObj = new();\n#else\n        private readonly object lockObj = new();\n#endif\n        private readonly TaskCompletionSource<int> closedTaskCompletionSource = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        public ConnectionManager(\n            IOptions<ConnectionOptions> connectionOptions,\n            ConnectionFactory connectionFactory,\n            NetworkingTrace trace)\n        {\n            if (trace == null) throw new ArgumentNullException(nameof(trace));\n            this.connectionOptions = connectionOptions.Value;\n            this.connectionFactory = connectionFactory;\n            this.trace = trace;\n        }\n\n        public int ConnectionCount => connections.Sum(e => e.Value.Connections.Length);\n\n        public Task Closed => this.closedTaskCompletionSource.Task;\n\n        public List<SiloAddress> GetConnectedAddresses() => connections.Select(i => i.Key).ToList();\n\n        public ValueTask<Connection> GetConnection(SiloAddress endpoint)\n        {\n            if (this.connections.TryGetValue(endpoint, out var entry) && entry.NextConnection() is { } connection)\n            {\n                if (!entry.HasSufficientConnections(connectionOptions) && entry.PendingConnection is null)\n                {\n                    this.GetConnectionAsync(endpoint).Ignore();\n                }\n\n                // Return the existing connection.\n                return new(connection);\n            }\n\n            // Start a new connection attempt since there are no suitable connections.\n            return new(this.GetConnectionAsync(endpoint));\n        }\n\n        public bool TryGetConnection(SiloAddress endpoint, out Connection connection)\n        {\n            if (this.connections.TryGetValue(endpoint, out var entry) && entry.NextConnection() is { } c)\n            {\n                connection = c;\n                return true;\n            }\n\n            connection = null;\n            return false;\n        }\n\n        private async Task<Connection> GetConnectionAsync(SiloAddress endpoint)\n        {\n            await Task.Yield();\n            while (true)\n            {\n                if (this.shutdownCancellation.IsCancellationRequested)\n                {\n                    throw new OperationCanceledException(\"Shutting down\");\n                }\n\n                Task pendingAttempt;\n                lock (this.lockObj)\n                {\n                    var entry = this.GetOrCreateEntry(endpoint);\n                    entry.RemoveDefunct();\n\n                    // If there are sufficient connections available then return an existing connection.\n                    if (entry.HasSufficientConnections(connectionOptions) && entry.NextConnection() is { } connection)\n                    {\n                        return connection;\n                    }\n\n                    var remainingDelay = entry.GetRemainingRetryDelay(connectionOptions);\n                    if (remainingDelay.Ticks > 0)\n                    {\n                        throw new ConnectionFailedException($\"Unable to connect to {endpoint}, will retry after {remainingDelay.TotalMilliseconds}ms\");\n                    }\n\n                    // If there is no pending attempt then start one, otherwise the pending attempt will be awaited before reevaluating.\n                    pendingAttempt = entry.PendingConnection ??= ConnectAsync(endpoint, entry);\n                }\n\n                await pendingAttempt;\n            }\n        }\n\n        private void OnConnectionFailed(ConnectionEntry entry)\n        {\n            var lastFailure = DateTime.UtcNow;\n            lock (this.lockObj)\n            {\n                if (entry.LastFailure < lastFailure) entry.LastFailure = lastFailure;\n                entry.PendingConnection = null;\n                entry.RemoveDefunct();\n            }\n        }\n\n        public void OnConnected(SiloAddress address, Connection connection) => OnConnected(address, connection, null);\n\n        private void OnConnected(SiloAddress address, Connection connection, ConnectionEntry entry)\n        {\n            lock (this.lockObj)\n            {\n                entry ??= GetOrCreateEntry(address);\n                entry.Connections = entry.Connections.Contains(connection) ? entry.Connections : entry.Connections.Add(connection);\n                entry.LastFailure = default;\n                entry.PendingConnection = null;\n            }\n\n            LogInformationConnectionEstablished(this.trace, connection, address);\n        }\n\n        public void OnConnectionTerminated(SiloAddress address, Connection connection, Exception exception)\n        {\n            if (connection is null) return;\n\n            lock (this.lockObj)\n            {\n                if (this.connections.TryGetValue(address, out var entry))\n                {\n                    entry.Connections = entry.Connections.Remove(connection);\n\n                    if (entry.Connections.Length == 0 && entry.PendingConnection is null)\n                    {\n                        // Remove the entire entry.\n                        this.connections.TryRemove(address, out _);\n                    }\n                    else\n                    {\n                        entry.RemoveDefunct();\n                    }\n                }\n            }\n\n            if (exception != null && !this.shutdownCancellation.IsCancellationRequested)\n            {\n                LogWarningConnectionTerminated(this.trace, exception, connection);\n            }\n            else\n            {\n                LogDebugConnectionClosed(this.trace, connection);\n            }\n        }\n\n        private ConnectionEntry GetOrCreateEntry(SiloAddress address) => connections.GetOrAdd(address, _ => new());\n\n        private async Task<Connection> ConnectAsync(SiloAddress address, ConnectionEntry entry)\n        {\n            await Task.Yield();\n            CancellationTokenSource openConnectionCancellation = default;\n\n            try\n            {\n                LogInformationEstablishingConnection(this.trace, address);\n\n                // Cancel pending connection attempts either when the host terminates or after the configured time limit.\n                openConnectionCancellation = CancellationTokenSource.CreateLinkedTokenSource(this.shutdownCancellation.Token, default);\n                openConnectionCancellation.CancelAfter(this.connectionOptions.OpenConnectionTimeout);\n\n                var connection = await this.connectionFactory.ConnectAsync(address, openConnectionCancellation.Token);\n\n                LogInformationConnectedToEndpoint(this.trace, address);\n\n                this.StartConnection(address, connection);\n\n                await connection.Initialized.WaitAsync(openConnectionCancellation.Token);\n                this.OnConnected(address, connection, entry);\n\n                return connection;\n            }\n            catch (Exception exception)\n            {\n                this.OnConnectionFailed(entry);\n\n                LogWarningConnectionAttemptFailed(this.trace, exception, address);\n\n                if (exception is OperationCanceledException && openConnectionCancellation?.IsCancellationRequested == true && !shutdownCancellation.IsCancellationRequested)\n                    throw new ConnectionFailedException($\"Connection attempt to endpoint {address} timed out after {connectionOptions.OpenConnectionTimeout}\");\n\n                throw new ConnectionFailedException(\n                    $\"Unable to connect to endpoint {address}. See {nameof(exception.InnerException)}\", exception);\n            }\n            finally\n            {\n                openConnectionCancellation?.Dispose();\n            }\n        }\n\n        public async Task CloseAsync(SiloAddress endpoint)\n        {\n            ImmutableArray<Connection> connections;\n            lock (this.lockObj)\n            {\n                if (!this.connections.TryGetValue(endpoint, out var entry))\n                {\n                    return;\n                }\n\n                connections = entry.Connections;\n                if (entry.PendingConnection is null)\n                {\n                    this.connections.TryRemove(endpoint, out _);\n                }\n            }\n\n            if (connections.Length == 1)\n            {\n                await connections[0].CloseAsync(exception: null);\n            }\n            else if (!connections.IsEmpty)\n            {\n                var closeTasks = new List<Task>();\n                foreach (var connection in connections)\n                {\n                    try\n                    {\n                        closeTasks.Add(connection.CloseAsync(exception: null));\n                    }\n                    catch\n                    {\n                    }\n                }\n\n                await Task.WhenAll(closeTasks);\n            }\n        }\n\n        public async Task Close(CancellationToken ct)\n        {\n            try\n            {\n                LogDebugShuttingDownConnections(this.trace);\n\n                this.shutdownCancellation.Cancel(throwOnFirstException: false);\n\n                var cycles = 0;\n                for (var closeTasks = new List<Task>(); ; closeTasks.Clear())\n                {\n                    var pendingConnections = false;\n                    foreach (var kv in connections)\n                    {\n                        pendingConnections |= kv.Value.PendingConnection != null;\n                        foreach (var connection in kv.Value.Connections)\n                        {\n                            try\n                            {\n                                closeTasks.Add(connection.CloseAsync(exception: null));\n                            }\n                            catch\n                            {\n                            }\n                        }\n                    }\n\n                    if (closeTasks.Count > 0)\n                    {\n                        await Task.WhenAll(closeTasks).WaitAsync(ct).SuppressThrowing();\n                        if (ct.IsCancellationRequested) break;\n                    }\n                    else if (!pendingConnections) break;\n\n                    await Task.Delay(10);\n                    if (++cycles > 100 && cycles % 500 == 0 && this.ConnectionCount is var remaining and > 0)\n                    {\n                        LogWarningWaitingForConnectionsToTerminate(this.trace, remaining);\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                LogWarningExceptionDuringShutdown(this.trace, exception);\n            }\n            finally\n            {\n                this.closedTaskCompletionSource.TrySetResult(0);\n            }\n        }\n\n        private void StartConnection(SiloAddress address, Connection connection)\n        {\n            ThreadPool.UnsafeQueueUserWorkItem(state =>\n            {\n                var (t, address, connection) = ((ConnectionManager, SiloAddress, Connection))state;\n                t.RunConnectionAsync(address, connection).Ignore();\n            }, (this, address, connection));\n        }\n\n        private async Task RunConnectionAsync(SiloAddress address, Connection connection)\n        {\n            Exception error = default;\n            try\n            {\n                using (this.BeginConnectionScope(connection))\n                {\n                    await connection.Run();\n                }\n            }\n            catch (Exception exception)\n            {\n                error = exception;\n            }\n            finally\n            {\n                this.OnConnectionTerminated(address, connection, error);\n            }\n        }\n\n        private IDisposable BeginConnectionScope(Connection connection)\n        {\n            if (this.trace.IsEnabled(LogLevel.Critical))\n            {\n                return this.trace.BeginScope(new ConnectionLogScope(connection));\n            }\n\n            return null;\n        }\n\n        private sealed class ConnectionEntry\n        {\n            public Task PendingConnection { get; set; }\n            public DateTime LastFailure { get; set; }\n            public ImmutableArray<Connection> Connections { get; set; } = ImmutableArray<Connection>.Empty;\n\n            public TimeSpan GetRemainingRetryDelay(ConnectionOptions options)\n            {\n                var lastFailure = this.LastFailure;\n                if (lastFailure.Ticks > 0)\n                {\n                    var retryAfter = lastFailure + options.ConnectionRetryDelay;\n                    var remainingDelay = retryAfter - DateTime.UtcNow;\n                    if (remainingDelay.Ticks > 0)\n                    {\n                        return remainingDelay;\n                    }\n                }\n\n                return default;\n            }\n\n            public bool HasSufficientConnections(ConnectionOptions options) => Connections.Length >= options.ConnectionsPerEndpoint;\n\n            public Connection NextConnection()\n            {\n                var connections = this.Connections;\n                if (connections.IsEmpty)\n                {\n                    return null;\n                }\n\n                var result = connections.Length == 1 ? connections[0] : connections[(int)(++nextConnection % (uint)connections.Length)];\n                return result.IsValid ? result : null;\n            }\n\n            public void RemoveDefunct() => Connections = Connections.RemoveAll(c => !c.IsValid);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Connection {Connection} established with {Silo}\"\n        )]\n        private static partial void LogInformationConnectionEstablished(ILogger logger, Connection connection, SiloAddress silo);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Connection {Connection} terminated\"\n        )]\n        private static partial void LogWarningConnectionTerminated(ILogger logger, Exception exception, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Connection {Connection} closed\"\n        )]\n        private static partial void LogDebugConnectionClosed(ILogger logger, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Establishing connection to endpoint {EndPoint}\"\n        )]\n        private static partial void LogInformationEstablishingConnection(ILogger logger, SiloAddress endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Connected to endpoint {EndPoint}\"\n        )]\n        private static partial void LogInformationConnectedToEndpoint(ILogger logger, SiloAddress endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Connection attempt to endpoint {EndPoint} failed\"\n        )]\n        private static partial void LogWarningConnectionAttemptFailed(ILogger logger, Exception exception, SiloAddress endPoint);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Shutting down connections\"\n        )]\n        private static partial void LogDebugShuttingDownConnections(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Waiting for {NumRemaining} connections to terminate\"\n        )]\n        private static partial void LogWarningWaitingForConnectionsToTerminate(ILogger logger, int numRemaining);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception during shutdown\"\n        )]\n        private static partial void LogWarningExceptionDuringShutdown(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionManagerLifecycleAdapter.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal class ConnectionManagerLifecycleAdapter<TLifecycle>\n        : ILifecycleParticipant<TLifecycle>, ILifecycleObserver where TLifecycle : ILifecycleObservable\n    {\n        private readonly ConnectionManager connectionManager;\n\n        public ConnectionManagerLifecycleAdapter(ConnectionManager connectionManager)\n        {\n            this.connectionManager = connectionManager;\n        }\n\n        public Task OnStart(CancellationToken ct) => Task.CompletedTask;\n\n        public async Task OnStop(CancellationToken ct)\n        {\n            await Task.Run(() => this.connectionManager.Close(ct));\n        }\n\n        public void Participate(TLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(ConnectionManager),\n                ServiceLifecycleStage.RuntimeInitialize-1, // Components from RuntimeInitialize need network\n                this);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionOptions.cs",
    "content": "using System;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Connection options.\n    /// </summary>\n    public class ConnectionOptions\n    {\n        /// <summary>\n        /// Gets or sets the network protocol version to negotiate with.\n        /// </summary>\n        public NetworkProtocolVersion ProtocolVersion { get; set; } = NetworkProtocolVersion.Version1;\n\n        /// <summary>\n        /// Gets or sets the number of connections to maintain for each endpoint.\n        /// </summary>\n        public int ConnectionsPerEndpoint { get; set; } = 1;\n\n        /// <summary>\n        /// Gets or sets the amount of time to wait after a failed connection attempt before retrying the connection.\n        /// </summary>\n        public TimeSpan ConnectionRetryDelay { get; set; } = TimeSpan.FromSeconds(1);\n\n        /// <summary>\n        /// Gets or sets the timeout before a connection open is assumed to have failed.\n        /// </summary>\n        public TimeSpan OpenConnectionTimeout { get; set; } = DEFAULT_OPENCONNECTION_TIMEOUT;\n\n        /// <summary>\n        /// The default value for <see cref=\"OpenConnectionTimeout\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_OPENCONNECTION_TIMEOUT = TimeSpan.FromSeconds(5);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionPreamble.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Binary;\nusing System.IO.Pipelines;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime.Messaging\n{\n    [GenerateSerializer, Immutable]\n    internal sealed class ConnectionPreamble\n    {\n        [Id(0)]\n        public NetworkProtocolVersion NetworkProtocolVersion { get; init; }\n\n        [Id(1)]\n        public GrainId NodeIdentity { get; init; }\n\n        [Id(2)]\n        public SiloAddress SiloAddress { get; init; }\n\n        [Id(3)]\n        public string ClusterId { get; init; }\n    }\n\n    internal sealed class ConnectionPreambleHelper\n    {\n        private const int MaxPreambleLength = 1024;\n        private readonly Serializer<ConnectionPreamble> _preambleSerializer;\n        public ConnectionPreambleHelper(Serializer<ConnectionPreamble> preambleSerializer)\n        {\n            _preambleSerializer = preambleSerializer;\n        }\n\n        internal async ValueTask Write(ConnectionContext connection, ConnectionPreamble preamble)\n        {\n            var output = connection.Transport.Output;\n            using var outputWriter = new PrefixingBufferWriter(sizeof(int), 1024, MemoryPool<byte>.Shared);\n            outputWriter.Init(output);\n            _preambleSerializer.Serialize(\n                preamble,\n                outputWriter);\n\n            var length = outputWriter.CommittedBytes;\n\n            if (length > MaxPreambleLength)\n            {\n                throw new InvalidOperationException($\"Created preamble of length {length}, which is greater than maximum allowed size of {MaxPreambleLength}.\");\n            }\n\n            WriteLength(outputWriter, length);\n\n            var flushResult = await output.FlushAsync();\n            if (flushResult.IsCanceled)\n            {\n                throw new OperationCanceledException(\"Flush canceled\");\n            }\n\n            return;\n        }\n\n        private static void WriteLength(PrefixingBufferWriter outputWriter, int length)\n        {\n            Span<byte> lengthSpan = stackalloc byte[4];\n            BinaryPrimitives.WriteInt32LittleEndian(lengthSpan, length);\n            outputWriter.Complete(lengthSpan);\n        }\n\n        internal async ValueTask<ConnectionPreamble> Read(ConnectionContext connection)\n        {\n            var input = connection.Transport.Input;\n\n            var readResult = await input.ReadAsync();\n            var buffer = readResult.Buffer;\n            CheckForCompletion(ref readResult);\n            while (buffer.Length < 4)\n            {\n                input.AdvanceTo(buffer.Start, buffer.End);\n                readResult = await input.ReadAsync();\n                buffer = readResult.Buffer;\n                CheckForCompletion(ref readResult);\n            }\n\n            int ReadLength(ref ReadOnlySequence<byte> b)\n            {\n                Span<byte> lengthBytes = stackalloc byte[4];\n                b.Slice(0, 4).CopyTo(lengthBytes);\n                b = b.Slice(4);\n                return BinaryPrimitives.ReadInt32LittleEndian(lengthBytes);\n            }\n\n            var length = ReadLength(ref buffer);\n            if (length > MaxPreambleLength)\n            {\n                throw new InvalidOperationException($\"Remote connection sent preamble length of {length}, which is greater than maximum allowed size of {MaxPreambleLength}.\");\n            }\n\n            while (buffer.Length < length)\n            {\n                input.AdvanceTo(buffer.Start, buffer.End);\n                readResult = await input.ReadAsync();\n                buffer = readResult.Buffer;\n                CheckForCompletion(ref readResult);\n            }\n\n            var payloadBuffer = buffer.Slice(0, length);\n\n            try\n            {\n                var preamble = _preambleSerializer.Deserialize(payloadBuffer);\n                return preamble;\n            }\n            finally\n            {\n                input.AdvanceTo(payloadBuffer.End);\n            }\n\n            void CheckForCompletion(ref ReadResult r)\n            {\n                if (r.IsCanceled || r.IsCompleted) throw new InvalidOperationException(\"Connection terminated prematurely\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/ConnectionShared.cs",
    "content": "using System;\nusing Orleans.Placement.Repartitioning;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class ConnectionCommon(\n        IServiceProvider serviceProvider,\n        MessageFactory messageFactory,\n        MessagingTrace messagingTrace,\n        NetworkingTrace networkingTrace,\n        IMessageStatisticsSink messageStatisticsSink)\n    {\n        public MessageFactory MessageFactory { get; } = messageFactory;\n        public IServiceProvider ServiceProvider { get; } = serviceProvider;\n        public NetworkingTrace NetworkingTrace { get; } = networkingTrace;\n        public IMessageStatisticsSink MessageStatisticsSink { get; } = messageStatisticsSink;\n        public MessagingTrace MessagingTrace { get; } = messagingTrace;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/IUnderlyingTransportFeature.cs",
    "content": "using System.IO.Pipelines;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// Holds the underlying transport used by a connection.\n    /// </summary>\n    internal interface IUnderlyingTransportFeature\n    {\n        /// <summary>\n        /// Gets the underlying transport.\n        /// </summary>\n        IDuplexPipe Transport { get; }\n    }\n\n    /// <summary>\n    /// Holds the underlying transport used by a connection.\n    /// </summary>\n    internal class UnderlyingConnectionTransportFeature : IUnderlyingTransportFeature\n    {\n        /// <inheritdoc />\n        public IDuplexPipe Transport { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/NetworkProtocolVersion.cs",
    "content": "namespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// Identifies a network protocol version.\n    /// </summary>\n    public enum NetworkProtocolVersion : byte\n    {\n        Version1 = 1,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/NetworkingTrace.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class NetworkingTrace : DiagnosticListener, ILogger\n    {\n        private readonly ILogger log;\n\n        public NetworkingTrace(ILoggerFactory loggerFactory) : base(typeof(NetworkingTrace).FullName)\n        {\n            this.log = loggerFactory.CreateLogger(typeof(NetworkingTrace).FullName);\n        }\n\n        public IDisposable BeginScope<TState>(TState state)\n        {\n            return this.log.BeginScope(state);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool IsEnabled(LogLevel logLevel)\n        {\n            return this.log.IsEnabled(logLevel);\n        }\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n        {\n            this.log.Log(logLevel, eventId, state, exception, formatter);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/BufferExtensions.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Networking.Shared\n{\n    internal static class BufferExtensions\n    {\n        public static ArraySegment<byte> GetArray(this Memory<byte> memory) => ((ReadOnlyMemory<byte>)memory).GetArray();\n\n        public static ArraySegment<byte> GetArray(this ReadOnlyMemory<byte> memory)\n        {\n            if (!MemoryMarshal.TryGetArray(memory, out var result))\n            {\n                ThrowInvalid();\n            }\n\n            return result;\n            void ThrowInvalid() => throw new InvalidOperationException(\"Buffer backed by array was expected\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/CorrelationIdGenerator.cs",
    "content": "using System;\nusing System.Threading;\n\nnamespace Orleans.Networking.Shared\n{\n    internal static class CorrelationIdGenerator\n    {\n        // Base32 encoding - in ascii sort order for easy text based sorting\n        private static readonly char[] s_encode32Chars = \"0123456789ABCDEFGHIJKLMNOPQRSTUV\".ToCharArray();\n\n        // Seed the _lastConnectionId for this application instance with\n        // the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001\n        // for a roughly increasing _lastId over restarts\n        private static long _lastId = DateTime.UtcNow.Ticks;\n\n        public static string GetNextId() => GenerateId(Interlocked.Increment(ref _lastId));\n\n        private static string GenerateId(long id)\n        {\n            return string.Create(13, id, (buffer, value) =>\n            {\n                char[] encode32Chars = s_encode32Chars;\n\n                buffer[12] = encode32Chars[value & 31];\n                buffer[11] = encode32Chars[(value >> 5) & 31];\n                buffer[10] = encode32Chars[(value >> 10) & 31];\n                buffer[9] = encode32Chars[(value >> 15) & 31];\n                buffer[8] = encode32Chars[(value >> 20) & 31];\n                buffer[7] = encode32Chars[(value >> 25) & 31];\n                buffer[6] = encode32Chars[(value >> 30) & 31];\n                buffer[5] = encode32Chars[(value >> 35) & 31];\n                buffer[4] = encode32Chars[(value >> 40) & 31];\n                buffer[3] = encode32Chars[(value >> 45) & 31];\n                buffer[2] = encode32Chars[(value >> 50) & 31];\n                buffer[1] = encode32Chars[(value >> 55) & 31];\n                buffer[0] = encode32Chars[(value >> 60) & 31];\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/DuplexPipe.cs",
    "content": "using System.IO.Pipelines;\n\nnamespace Orleans.Networking.Shared\n{\n    internal class DuplexPipe : IDuplexPipe\n    {\n        public DuplexPipe(PipeReader reader, PipeWriter writer)\n        {\n            Input = reader;\n            Output = writer;\n        }\n\n        public PipeReader Input { get; }\n\n        public PipeWriter Output { get; }\n\n        public static DuplexPipePair CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions)\n        {\n            var input = new Pipe(inputOptions);\n            var output = new Pipe(outputOptions);\n\n            var transportToApplication = new DuplexPipe(output.Reader, input.Writer);\n            var applicationToTransport = new DuplexPipe(input.Reader, output.Writer);\n\n            return new DuplexPipePair(applicationToTransport, transportToApplication);\n        }\n\n        // This class exists to work around issues with value tuple on .NET Framework\n        public readonly struct DuplexPipePair\n        {\n            public IDuplexPipe Transport { get; }\n            public IDuplexPipe Application { get; }\n\n            public DuplexPipePair(IDuplexPipe transport, IDuplexPipe application)\n            {\n                Transport = transport;\n                Application = application;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/IOQueue.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.IO.Pipelines;\nusing System.Threading;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class IOQueue : PipeScheduler,  IThreadPoolWorkItem\n    {\n        private readonly ConcurrentQueue<(Action<object> Callback, object State)> _workItems = new();\n        private int _doingWork;\n\n        public override void Schedule(Action<object> action, object state)\n        {\n            _workItems.Enqueue((action, state));\n\n            // Set working if it wasn't (via atomic Interlocked).\n            if (Interlocked.CompareExchange(ref _doingWork, 1, 0) == 0)\n            {\n                // Wasn't working, schedule.\n                _ = System.Threading.ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);\n            }\n        }\n\n        public void Execute()\n        {\n            while (true)\n            {\n                while (_workItems.TryDequeue(out var item))\n                {\n                    item.Callback(item.State);\n                }\n\n                // All work done.\n\n                // Set _doingWork (0 == false) prior to checking IsEmpty to catch any missed work in interim.\n                // This doesn't need to be volatile due to the following barrier (i.e. it is volatile).\n                _doingWork = 0;\n\n                // Ensure _doingWork is written before IsEmpty is read.\n                // As they are two different memory locations, we insert a barrier to guarantee ordering.\n                Thread.MemoryBarrier();\n\n                // Check if there is work to do\n                if (_workItems.IsEmpty)\n                {\n                    // Nothing to do, exit.\n                    break;\n                }\n\n                // Is work, can we set it as active again (via atomic Interlocked), prior to scheduling?\n                if (Interlocked.Exchange(ref _doingWork, 1) == 1)\n                {\n                    // Execute has been rescheduled already, exit.\n                    break;\n                }\n\n                // Is work, wasn't already scheduled so continue loop.\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/ISocketsTrace.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Networking.Shared\n{\n    internal interface ISocketsTrace : ILogger\n    {\n        void ConnectionReadFin(string connectionId);\n\n        void ConnectionWriteFin(string connectionId, string reason);\n\n        void ConnectionError(string connectionId, Exception ex);\n\n        void ConnectionReset(string connectionId);\n\n        void ConnectionPause(string connectionId);\n\n        void ConnectionResume(string connectionId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/KestrelMemoryPool.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Networking.Shared\n{\n    internal static class KestrelMemoryPool\n    {\n        public static MemoryPool<byte> Create()\n        {\n            return CreateSlabMemoryPool();\n        }\n\n        public static MemoryPool<byte> CreateSlabMemoryPool()\n        {\n            return new SlabMemoryPool();\n        }\n\n        public static readonly int MinimumSegmentSize = 4096;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/MemoryPoolBlock.cs",
    "content": "﻿using System;\nusing System.Buffers;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Networking.Shared\n{\n    /// <summary>\n    /// Block tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The\n    /// individual blocks are then treated as independent array segments.\n    /// </summary>\n    internal sealed class MemoryPoolBlock : IMemoryOwner<byte>\n    {\n        private readonly int _offset;\n        private readonly int _length;\n\n        /// <summary>\n        /// This object cannot be instantiated outside of the static Create method\n        /// </summary>\n        internal MemoryPoolBlock(SlabMemoryPool pool, MemoryPoolSlab slab, int offset, int length)\n        {\n            _offset = offset;\n            _length = length;\n\n            Pool = pool;\n            Slab = slab;\n\n            Memory = MemoryMarshal.CreateFromPinnedArray(slab.Array, _offset, _length);\n        }\n\n        /// <summary>\n        /// Back-reference to the memory pool which this block was allocated from. It may only be returned to this pool.\n        /// </summary>\n        public SlabMemoryPool Pool { get; }\n\n        /// <summary>\n        /// Back-reference to the slab from which this block was taken, or null if it is one-time-use memory.\n        /// </summary>\n        public MemoryPoolSlab Slab { get; }\n\n        public Memory<byte> Memory { get; }\n\n        ~MemoryPoolBlock()\n        {\n            Pool.RefreshBlock(Slab, _offset, _length);\n        }\n\n        public void Dispose()\n        {\n            Pool.Return(this);\n        }\n\n        public void Lease()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/MemoryPoolSlab.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Networking.Shared\n{\n    /// <summary>\n    /// Slab tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The\n    /// individual blocks are then treated as independent array segments.\n    /// </summary>\n    internal class MemoryPoolSlab : IDisposable\n    {\n        /// <summary>\n        /// This handle pins the managed array in memory until the slab is disposed. This prevents it from being\n        /// relocated and enables any subsections of the array to be used as native memory pointers to P/Invoked API calls.\n        /// </summary>\n        private GCHandle _gcHandle;\n        private bool _isDisposed;\n\n        public MemoryPoolSlab(byte[] data)\n        {\n            Array = data;\n            _gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);\n            NativePointer = _gcHandle.AddrOfPinnedObject();\n        }\n\n        /// <summary>\n        /// True as long as the blocks from this slab are to be considered returnable to the pool. In order to shrink the\n        /// memory pool size an entire slab must be removed. That is done by (1) setting IsActive to false and removing the\n        /// slab from the pool's _slabs collection, (2) as each block currently in use is Return()ed to the pool it will\n        /// be allowed to be garbage collected rather than re-pooled, and (3) when all block tracking objects are garbage\n        /// collected and the slab is no longer references the slab will be garbage collected and the memory unpinned will\n        /// be unpinned by the slab's Dispose.\n        /// </summary>\n        public bool IsActive => !_isDisposed;\n\n        public IntPtr NativePointer { get; private set; }\n\n        public byte[] Array { get; private set; }\n\n        public static MemoryPoolSlab Create(int length)\n        {\n            // allocate and pin requested memory length\n            var array = new byte[length];\n\n            // allocate and return slab tracking object\n            return new MemoryPoolSlab(array);\n        }\n\n        protected void Dispose(bool disposing)\n        {\n            if (_isDisposed)\n            {\n                return;\n            }\n\n            _isDisposed = true;\n\n            Array = null;\n            NativePointer = IntPtr.Zero;\n\n            if (_gcHandle.IsAllocated)\n            {\n                _gcHandle.Free();\n            }\n        }\n\n        ~MemoryPoolSlab()\n        {\n            Dispose(false);\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SharedMemoryPool.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class SharedMemoryPool\n    {\n        public MemoryPool<byte> Pool { get; } = KestrelMemoryPool.Create();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SlabMemoryPool.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Threading;\n\nnamespace Orleans.Networking.Shared\n{\n    /// <summary>\n    /// Used to allocate and distribute re-usable blocks of memory.\n    /// </summary>\n    internal sealed class SlabMemoryPool : MemoryPool<byte>\n    {\n        /// <summary>\n        /// The size of a block. 4096 is chosen because most operating systems use 4k pages.\n        /// </summary>\n        private const int _blockSize = 4096;\n\n        /// <summary>\n        /// Allocating 32 contiguous blocks per slab makes the slab size 128k. This is larger than the 85k size which will place the memory\n        /// in the large object heap. This means the GC will not try to relocate this array, so the fact it remains pinned does not negatively\n        /// affect memory management's compactification.\n        /// </summary>\n        private const int _blockCount = 32;\n\n        /// <summary>\n        /// Max allocation block size for pooled blocks,\n        /// larger values can be leased but they will be disposed after use rather than returned to the pool.\n        /// </summary>\n        public override int MaxBufferSize { get; } = _blockSize;\n\n        /// <summary>\n        /// The size of a block. 4096 is chosen because most operating systems use 4k pages.\n        /// </summary>\n        public static int BlockSize => _blockSize;\n\n        /// <summary>\n        /// 4096 * 32 gives you a slabLength of 128k contiguous bytes allocated per slab\n        /// </summary>\n        private static readonly int _slabLength = _blockSize * _blockCount;\n\n        /// <summary>\n        /// Thread-safe collection of blocks which are currently in the pool. A slab will pre-allocate all of the block tracking objects\n        /// and add them to this collection. When memory is requested it is taken from here first, and when it is returned it is re-added.\n        /// </summary>\n        private readonly ConcurrentQueue<MemoryPoolBlock> _blocks = new ConcurrentQueue<MemoryPoolBlock>();\n\n        /// <summary>\n        /// Thread-safe collection of slabs which have been allocated by this pool. As long as a slab is in this collection and slab.IsActive,\n        /// the blocks will be added to _blocks when returned.\n        /// </summary>\n        private readonly ConcurrentStack<MemoryPoolSlab> _slabs = new ConcurrentStack<MemoryPoolSlab>();\n\n        /// <summary>\n        /// This is part of implementing the IDisposable pattern.\n        /// </summary>\n        private bool _isDisposed; // To detect redundant calls\n\n        private int _totalAllocatedBlocks;\n\n        private readonly object _disposeSync = new object();\n\n        /// <summary>\n        /// This default value passed in to Rent to use the default value for the pool.\n        /// </summary>\n        private const int AnySize = -1;\n\n        public override IMemoryOwner<byte> Rent(int size = AnySize)\n        {\n            if (size > _blockSize)\n            {\n                ThrowArgumentOutOfRangeException_BufferRequestTooLarge(_blockSize);\n            }\n\n            var block = Lease();\n            return block;\n        }\n\n        /// <summary>\n        /// Called to take a block from the pool.\n        /// </summary>\n        /// <returns>The block that is reserved for the called. It must be passed to Return when it is no longer being used.</returns>\n        private MemoryPoolBlock Lease()\n        {\n            if (_isDisposed)\n            {\n                ThrowObjectDisposedException();\n            }\n\n            if (_blocks.TryDequeue(out MemoryPoolBlock block))\n            {\n                // block successfully taken from the stack - return it\n\n                block.Lease();\n                return block;\n            }\n            // no blocks available - grow the pool\n            block = AllocateSlab();\n            block.Lease();\n            return block;\n        }\n\n        /// <summary>\n        /// Internal method called when a block is requested and the pool is empty. It allocates one additional slab, creates all of the\n        /// block tracking objects, and adds them all to the pool.\n        /// </summary>\n        private MemoryPoolBlock AllocateSlab()\n        {\n            var slab = MemoryPoolSlab.Create(_slabLength);\n            _slabs.Push(slab);\n\n            var basePtr = slab.NativePointer;\n            // Page align the blocks\n            var offset = (int)((((ulong)basePtr + (uint)_blockSize - 1) & ~((uint)_blockSize - 1)) - (ulong)basePtr);\n            // Ensure page aligned\n            Debug.Assert(((ulong)basePtr + (uint)offset) % _blockSize == 0);\n\n            var blockCount = (_slabLength - offset) / _blockSize;\n            Interlocked.Add(ref _totalAllocatedBlocks, blockCount);\n\n            MemoryPoolBlock block = null;\n\n            for (int i = 0; i < blockCount; i++)\n            {\n                block = new MemoryPoolBlock(this, slab, offset, _blockSize);\n\n                if (i != blockCount - 1) // last block\n                {\n#if BLOCK_LEASE_TRACKING\n                    block.IsLeased = true;\n#endif\n                    Return(block);\n                }\n\n                offset += _blockSize;\n            }\n\n            return block;\n        }\n\n        /// <summary>\n        /// Called to return a block to the pool. Once Return has been called the memory no longer belongs to the caller, and\n        /// Very Bad Things will happen if the memory is read of modified subsequently. If a caller fails to call Return and the\n        /// block tracking object is garbage collected, the block tracking object's finalizer will automatically re-create and return\n        /// a new tracking object into the pool. This will only happen if there is a bug in the server, however it is necessary to avoid\n        /// leaving \"dead zones\" in the slab due to lost block tracking objects.\n        /// </summary>\n        /// <param name=\"block\">The block to return. It must have been acquired by calling Lease on the same memory pool instance.</param>\n        internal void Return(MemoryPoolBlock block)\n        {\n#if BLOCK_LEASE_TRACKING\n            Debug.Assert(block.Pool == this, \"Returned block was not leased from this pool\");\n            Debug.Assert(block.IsLeased, $\"Block being returned to pool twice: {block.Leaser}{Environment.NewLine}\");\n            block.IsLeased = false;\n#endif\n\n            if (!_isDisposed)\n            {\n                _blocks.Enqueue(block);\n            }\n            else\n            {\n                GC.SuppressFinalize(block);\n            }\n        }\n\n        // This method can ONLY be called from the finalizer of MemoryPoolBlock\n        internal void RefreshBlock(MemoryPoolSlab slab, int offset, int length)\n        {\n            lock (_disposeSync)\n            {\n                if (!_isDisposed && slab != null && slab.IsActive)\n                {\n                    // Need to make a new object because this one is being finalized\n                    // Note, this must be called within the _disposeSync lock because the block\n                    // could be disposed at the same time as the finalizer.\n                    Return(new MemoryPoolBlock(this, slab, offset, length));\n                }\n            }\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (_isDisposed)\n            {\n                return;\n            }\n\n            lock (_disposeSync)\n            {\n                _isDisposed = true;\n\n                if (disposing)\n                {\n                    while (_slabs.TryPop(out MemoryPoolSlab slab))\n                    {\n                        // dispose managed state (managed objects).\n                        slab.Dispose();\n                    }\n                }\n\n                // Discard blocks in pool\n                while (_blocks.TryDequeue(out MemoryPoolBlock block))\n                {\n                    GC.SuppressFinalize(block);\n                }\n            }\n        }\n\n        private static void ThrowArgumentOutOfRangeException_BufferRequestTooLarge(int maxSize)\n        {\n            throw new ArgumentOutOfRangeException(\"size\", $\"Cannot allocate more than {maxSize} bytes in a single buffer\");\n        }\n\n        private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(\"MemoryPool\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketAwaitableEventArgs.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Net.Sockets;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Networking.Shared\n{\n    internal class SocketAwaitableEventArgs : SocketAsyncEventArgs, ICriticalNotifyCompletion\n    {\n        private static readonly Action _callbackCompleted = () => { };\n\n        private readonly PipeScheduler _ioScheduler;\n\n        private Action _callback;\n\n        public SocketAwaitableEventArgs(PipeScheduler ioScheduler)\n        {\n            _ioScheduler = ioScheduler;\n        }\n\n        public SocketAwaitableEventArgs GetAwaiter() => this;\n        public bool IsCompleted => ReferenceEquals(_callback, _callbackCompleted);\n\n        public int GetResult()\n        {\n            Debug.Assert(ReferenceEquals(_callback, _callbackCompleted));\n\n            _callback = null;\n\n            if (SocketError != SocketError.Success)\n            {\n                ThrowSocketException(SocketError);\n            }\n\n            return BytesTransferred;\n\n            void ThrowSocketException(SocketError e)\n            {\n                throw new SocketException((int)e);\n            }\n        }\n\n        public void OnCompleted(Action continuation)\n        {\n            if (ReferenceEquals(_callback, _callbackCompleted) ||\n                ReferenceEquals(Interlocked.CompareExchange(ref _callback, continuation, null), _callbackCompleted))\n            {\n                Task.Run(continuation);\n            }\n        }\n\n        public void UnsafeOnCompleted(Action continuation)\n        {\n            OnCompleted(continuation);\n        }\n\n        public void Complete()\n        {\n            OnCompleted(this);\n        }\n\n        protected override void OnCompleted(SocketAsyncEventArgs _)\n        {\n            var continuation = Interlocked.Exchange(ref _callback, _callbackCompleted);\n\n            if (continuation != null)\n            {\n                _ioScheduler.Schedule(state => ((Action)state)(), continuation);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketConnection.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Net.Sockets;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed partial class SocketConnection : TransportConnection\n    {\n        private static readonly int MinAllocBufferSize = SlabMemoryPool.BlockSize / 2;\n        private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);\n        private static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);\n\n        private readonly Socket _socket;\n        private readonly ISocketsTrace _trace;\n        private readonly SocketReceiver _receiver;\n        private readonly SocketSender _sender;\n        private readonly CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();\n\n#if NET9_0_OR_GREATER\n        private readonly Lock _shutdownLock = new();\n#else\n        private readonly object _shutdownLock = new();\n#endif\n        private volatile bool _socketDisposed;\n        private volatile Exception _shutdownReason;\n        private Task _processingTask;\n        private readonly TaskCompletionSource<object> _waitForConnectionClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);\n        private bool _connectionClosed;\n\n        internal SocketConnection(Socket socket,\n                                  MemoryPool<byte> memoryPool,\n                                  PipeScheduler scheduler,\n                                  ISocketsTrace trace,\n                                  long? maxReadBufferSize = null,\n                                  long? maxWriteBufferSize = null)\n        {\n            Debug.Assert(socket != null);\n            Debug.Assert(memoryPool != null);\n            Debug.Assert(trace != null);\n\n            _socket = socket;\n            MemoryPool = memoryPool;\n            _trace = trace;\n\n            LocalEndPoint = _socket.LocalEndPoint;\n            RemoteEndPoint = _socket.RemoteEndPoint;\n\n            ConnectionClosed = _connectionClosedTokenSource.Token;\n\n            // On *nix platforms, Sockets already dispatches to the ThreadPool.\n            // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.\n            // https://github.com/aspnet/KestrelHttpServer/issues/2573\n            var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;\n\n            _receiver = new SocketReceiver(_socket, awaiterScheduler);\n            _sender = new SocketSender(_socket, awaiterScheduler);\n\n            maxReadBufferSize = maxReadBufferSize ?? 0;\n            maxWriteBufferSize = maxWriteBufferSize ?? 0;\n\n            var inputOptions = new PipeOptions(MemoryPool, PipeScheduler.ThreadPool, scheduler, maxReadBufferSize.Value, maxReadBufferSize.Value / 2, useSynchronizationContext: false);\n            var outputOptions = new PipeOptions(MemoryPool, scheduler, PipeScheduler.ThreadPool, maxWriteBufferSize.Value, maxWriteBufferSize.Value / 2, useSynchronizationContext: false);\n\n            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);\n\n            // Set the transport and connection id\n            Transport = pair.Transport;\n            Application = pair.Application;\n        }\n\n        public PipeWriter Input => Application.Output;\n\n        public PipeReader Output => Application.Input;\n\n        public override MemoryPool<byte> MemoryPool { get; }\n\n        public void Start()\n        {\n            _processingTask = StartAsync();\n        }\n\n        private async Task StartAsync()\n        {\n            try\n            {\n                // Spawn send and receive logic\n                var receiveTask = DoReceive();\n                var sendTask = DoSend();\n\n                // Now wait for both to complete\n                await receiveTask;\n                await sendTask;\n\n                _receiver.Dispose();\n                _sender.Dispose();\n            }\n            catch (Exception ex)\n            {\n                LogErrorUnexpectedExceptionInStartAsync(_trace, ex);\n            }\n        }\n\n        public override void Abort(ConnectionAbortedException abortReason)\n        {\n            // Try to gracefully close the socket to match libuv behavior.\n            Shutdown(abortReason);\n\n            // Cancel ProcessSends loop after calling shutdown to ensure the correct _shutdownReason gets set.\n            Output.CancelPendingRead();\n        }\n\n        // Only called after connection middleware is complete which means the ConnectionClosed token has fired.\n        public override async ValueTask DisposeAsync()\n        {\n            Transport.Input.Complete();\n            Transport.Output.Complete();\n\n            if (_processingTask != null)\n            {\n                await _processingTask;\n            }\n\n            _connectionClosedTokenSource.Dispose();\n        }\n\n        private async Task DoReceive()\n        {\n            Exception error = null;\n\n            try\n            {\n                await ProcessReceives();\n            }\n            catch (SocketException ex) when (IsConnectionResetError(ex.SocketErrorCode))\n            {\n                // This could be ignored if _shutdownReason is already set.\n                error = new ConnectionResetException(ex.Message, ex);\n\n                // There's still a small chance that both DoReceive() and DoSend() can log the same connection reset.\n                // Both logs will have the same ConnectionId. I don't think it's worthwhile to lock just to avoid this.\n                if (!_socketDisposed)\n                {\n                    _trace.ConnectionReset(ConnectionId);\n                }\n            }\n            catch (Exception ex)\n                when ((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) ||\n                       ex is ObjectDisposedException)\n            {\n                // This exception should always be ignored because _shutdownReason should be set.\n                error = ex;\n\n                if (!_socketDisposed)\n                {\n                    // This is unexpected if the socket hasn't been disposed yet.\n                    _trace.ConnectionError(ConnectionId, error);\n                }\n            }\n            catch (Exception ex)\n            {\n                // This is unexpected.\n                error = ex;\n                _trace.ConnectionError(ConnectionId, error);\n            }\n            finally\n            {\n                // If Shutdown() has already bee called, assume that was the reason ProcessReceives() exited.\n                Input.Complete(_shutdownReason ?? error);\n\n                FireConnectionClosed();\n\n                await _waitForConnectionClosedTcs.Task;\n            }\n        }\n\n        private async Task ProcessReceives()\n        {\n            // Resolve `input` PipeWriter via the IDuplexPipe interface prior to loop start for performance.\n            var input = Input;\n            while (true)\n            {\n                // Wait for data before allocating a buffer.\n                await _receiver.WaitForDataAsync();\n\n                // Ensure we have some reasonable amount of buffer space\n                var buffer = input.GetMemory(MinAllocBufferSize);\n\n                var bytesReceived = await _receiver.ReceiveAsync(buffer);\n\n                if (bytesReceived == 0)\n                {\n                    // FIN\n                    _trace.ConnectionReadFin(ConnectionId);\n                    break;\n                }\n\n                input.Advance(bytesReceived);\n\n                var flushTask = input.FlushAsync();\n\n                var paused = !flushTask.IsCompleted;\n\n                if (paused)\n                {\n                    _trace.ConnectionPause(ConnectionId);\n                }\n\n                var result = await flushTask;\n\n                if (paused)\n                {\n                    _trace.ConnectionResume(ConnectionId);\n                }\n\n                if (result.IsCompleted || result.IsCanceled)\n                {\n                    // Pipe consumer is shut down, do we stop writing\n                    break;\n                }\n            }\n        }\n\n        private async Task DoSend()\n        {\n            Exception shutdownReason = null;\n            Exception unexpectedError = null;\n\n            try\n            {\n                await ProcessSends();\n            }\n            catch (SocketException ex) when (IsConnectionResetError(ex.SocketErrorCode))\n            {\n                shutdownReason = new ConnectionResetException(ex.Message, ex);\n                _trace.ConnectionReset(ConnectionId);\n            }\n            catch (Exception ex)\n                when ((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) ||\n                       ex is ObjectDisposedException)\n            {\n                // This should always be ignored since Shutdown() must have already been called by Abort().\n                shutdownReason = ex;\n            }\n            catch (Exception ex)\n            {\n                shutdownReason = ex;\n                unexpectedError = ex;\n                _trace.ConnectionError(ConnectionId, unexpectedError);\n            }\n            finally\n            {\n                Shutdown(shutdownReason);\n\n                // Complete the output after disposing the socket\n                Output.Complete(unexpectedError);\n\n                // Cancel any pending flushes so that the input loop is un-paused\n                Input.CancelPendingFlush();\n            }\n        }\n\n        private async Task ProcessSends()\n        {\n            // Resolve `output` PipeReader via the IDuplexPipe interface prior to loop start for performance.\n            var output = Output;\n            while (true)\n            {\n                var result = await output.ReadAsync();\n\n                if (result.IsCanceled)\n                {\n                    break;\n                }\n\n                var buffer = result.Buffer;\n\n                var end = buffer.End;\n                var isCompleted = result.IsCompleted;\n                if (!buffer.IsEmpty)\n                {\n                    await _sender.SendAsync(buffer);\n                }\n\n                output.AdvanceTo(end);\n\n                if (isCompleted)\n                {\n                    break;\n                }\n            }\n        }\n\n        private void FireConnectionClosed()\n        {\n            // Guard against scheduling this multiple times\n            if (_connectionClosed)\n            {\n                return;\n            }\n\n            _connectionClosed = true;\n\n            ThreadPool.UnsafeQueueUserWorkItem(state =>\n            {\n                ((SocketConnection)state).CancelConnectionClosedToken();\n\n                ((SocketConnection)state)._waitForConnectionClosedTcs.TrySetResult(null);\n            },\n            this);\n        }\n\n        private void Shutdown(Exception shutdownReason)\n        {\n            lock (_shutdownLock)\n            {\n                if (_socketDisposed)\n                {\n                    return;\n                }\n\n                // Make sure to close the connection only after the _aborted flag is set.\n                // Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when\n                // a BadHttpRequestException is thrown instead of a TaskCanceledException.\n                _socketDisposed = true;\n\n                // shutdownReason should only be null if the output was completed gracefully, so no one should ever\n                // ever observe the nondescript ConnectionAbortedException except for connection middleware attempting\n                // to half close the connection which is currently unsupported.\n                _shutdownReason = shutdownReason ?? new ConnectionAbortedException(\"The Socket transport's send loop completed gracefully.\");\n\n                _trace.ConnectionWriteFin(ConnectionId, _shutdownReason.Message);\n\n                try\n                {\n                    // Try to gracefully close the socket even for aborts to match libuv behavior.\n                    _socket.Shutdown(SocketShutdown.Both);\n                }\n                catch\n                {\n                    // Ignore any errors from Socket.Shutdown() since we're tearing down the connection anyway.\n                }\n\n                _socket.Dispose();\n            }\n        }\n\n        private void CancelConnectionClosedToken()\n        {\n            try\n            {\n                _connectionClosedTokenSource.Cancel();\n            }\n            catch (Exception ex)\n            {\n                LogErrorUnexpectedExceptionInCancelConnectionClosedToken(_trace, ex);\n            }\n        }\n\n        private static bool IsConnectionResetError(SocketError errorCode)\n        {\n            // A connection reset can be reported as SocketError.ConnectionAborted on Windows.\n            // ProtocolType can be removed once https://github.com/dotnet/corefx/issues/31927 is fixed.\n            return errorCode == SocketError.ConnectionReset ||\n                   errorCode == SocketError.Shutdown ||\n                   (errorCode == SocketError.ConnectionAborted && IsWindows) ||\n                   (errorCode == SocketError.ProtocolType && IsMacOS);\n        }\n\n        private static bool IsConnectionAbortError(SocketError errorCode)\n        {\n            // Calling Dispose after ReceiveAsync can cause an \"InvalidArgument\" error on *nix.\n            return errorCode == SocketError.OperationAborted ||\n                   errorCode == SocketError.Interrupted ||\n                   (errorCode == SocketError.InvalidArgument && !IsWindows);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unexpected exception in SocketConnection.StartAsync.\"\n        )]\n        private static partial void LogErrorUnexpectedExceptionInStartAsync(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unexpected exception in SocketConnection.CancelConnectionClosedToken.\"\n        )]\n        private static partial void LogErrorUnexpectedExceptionInCancelConnectionClosedToken(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketConnectionFactory.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Runtime.Serialization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Networking.Shared\n{\n    internal class SocketConnectionFactory : IConnectionFactory\n    {\n        private readonly SocketsTrace trace;\n        private readonly SocketSchedulers schedulers;\n        private readonly MemoryPool<byte> memoryPool;\n        private readonly SocketConnectionOptions _options;\n\n        public SocketConnectionFactory(ILoggerFactory loggerFactory, SocketSchedulers schedulers, SharedMemoryPool memoryPool, IOptions<SocketConnectionOptions> options)\n        {\n            var logger = loggerFactory.CreateLogger(\"Orleans.Sockets\");\n            this.trace = new SocketsTrace(logger);\n            this.schedulers = schedulers;\n            this.memoryPool = memoryPool.Pool;\n            _options = options.Value;\n        }\n\n        public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken)\n        {\n            var socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)\n            {\n                LingerState = new LingerOption(true, 0),\n                NoDelay = _options.NoDelay,\n            };\n\n            if (_options.KeepAlive)\n            {\n                socket.EnableKeepAlive(\n                    timeSeconds: _options.KeepAliveTimeSeconds,\n                    intervalSeconds: _options.KeepAliveIntervalSeconds,\n                    retryCount: _options.KeepAliveRetryCount);\n            }\n\n            socket.EnableFastPath();\n            using var completion = new SingleUseSocketAsyncEventArgs\n            {\n                RemoteEndPoint = endpoint\n            };\n\n            if (socket.ConnectAsync(completion))\n            {\n                using (cancellationToken.Register(s => Socket.CancelConnectAsync((SingleUseSocketAsyncEventArgs)s), completion))\n                {\n                    await completion.Task;\n                }\n            }\n\n            if (completion.SocketError != SocketError.Success)\n            {\n                if (completion.SocketError == SocketError.OperationAborted)\n                    cancellationToken.ThrowIfCancellationRequested();\n                throw new SocketConnectionException($\"Unable to connect to {endpoint}. Error: {completion.SocketError}\");\n            }\n\n            var scheduler = this.schedulers.GetScheduler();\n            var connection = new SocketConnection(socket, this.memoryPool, scheduler, this.trace);\n            connection.Start();\n            return connection;\n        }\n\n        private sealed class SingleUseSocketAsyncEventArgs : SocketAsyncEventArgs\n        {\n            private readonly TaskCompletionSource<object> completion = new();\n\n            public Task Task => completion.Task;\n\n            protected override void OnCompleted(SocketAsyncEventArgs _) => this.completion.TrySetResult(null);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class SocketConnectionException : OrleansException\n    {\n        public SocketConnectionException(string message) : base(message) { }\n\n        public SocketConnectionException(string message, Exception innerException) : base(message, innerException) { }\n\n        [Obsolete]\n        public SocketConnectionException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketConnectionListener.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class SocketConnectionListener : IConnectionListener\n    {\n        private readonly MemoryPool<byte> _memoryPool;\n        private readonly SocketSchedulers _schedulers;\n        private readonly ISocketsTrace _trace;\n        private Socket _listenSocket;\n        private readonly SocketConnectionOptions _options;\n\n        public EndPoint EndPoint { get; private set; }\n\n        internal SocketConnectionListener(\n            EndPoint endpoint,\n            SocketConnectionOptions options,\n            ISocketsTrace trace,\n            SocketSchedulers schedulers)\n        {\n            Debug.Assert(endpoint != null);\n            Debug.Assert(endpoint is IPEndPoint);\n            Debug.Assert(trace != null);\n\n            EndPoint = endpoint;\n            _trace = trace;\n            _schedulers = schedulers;\n            _options = options;\n            _memoryPool = options.MemoryPoolFactory();\n        }\n\n        internal void Bind()\n        {\n            if (_listenSocket != null)\n            {\n                throw new InvalidOperationException(\"Transport already bound\");\n            }\n\n            var listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)\n            {\n                LingerState = new LingerOption(true, 0),\n                NoDelay = true\n            };\n\n            listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);\n            if (_options.KeepAlive)\n            {\n                listenSocket.EnableKeepAlive(\n                    timeSeconds: _options.KeepAliveTimeSeconds,\n                    intervalSeconds: _options.KeepAliveIntervalSeconds,\n                    retryCount: _options.KeepAliveRetryCount);\n            }\n\n            listenSocket.EnableFastPath();\n\n            // Kestrel expects IPv6Any to bind to both IPv6 and IPv4\n            if (EndPoint is IPEndPoint ip && ip.Address == IPAddress.IPv6Any)\n            {\n                listenSocket.DualMode = true;\n            }\n\n            try\n            {\n                listenSocket.Bind(EndPoint);\n            }\n            catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)\n            {\n                throw new AddressInUseException(e.Message, e);\n            }\n\n            EndPoint = listenSocket.LocalEndPoint;\n\n            listenSocket.Listen(512);\n\n            _listenSocket = listenSocket;\n        }\n\n        public async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default)\n        {\n            while (true)\n            {\n                try\n                {\n                    var acceptSocket = await _listenSocket.AcceptAsync();\n                    acceptSocket.NoDelay = _options.NoDelay;\n                    if (_options.KeepAlive)\n                    {\n                        acceptSocket.EnableKeepAlive(\n                            timeSeconds: _options.KeepAliveTimeSeconds,\n                            intervalSeconds: _options.KeepAliveIntervalSeconds,\n                            retryCount: _options.KeepAliveRetryCount);\n                    }\n\n                    var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers.GetScheduler(), _trace);\n\n                    connection.Start();\n\n                    return connection;\n                }\n                catch (ObjectDisposedException)\n                {\n                    // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done\n                    return null;\n                }\n                catch (SocketException e) when (e.SocketErrorCode == SocketError.OperationAborted)\n                {\n                    // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done\n                    return null;\n                }\n                catch (SocketException)\n                {\n                    // The connection got reset while it was in the backlog, so we try again.\n                    _trace.ConnectionReset(connectionId: \"(null)\");\n                }\n            }\n        }\n\n        public ValueTask UnbindAsync(CancellationToken cancellationToken)\n        {\n            _listenSocket?.Dispose();\n\n            return default;\n        }\n\n        public ValueTask DisposeAsync()\n        {\n            _listenSocket?.Dispose();\n            // Dispose the memory pool\n            _memoryPool.Dispose();\n            return default;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketConnectionListenerFactory.cs",
    "content": "using System;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class SocketConnectionListenerFactory : IConnectionListenerFactory\n    {\n        private readonly SocketConnectionOptions socketConnectionOptions;\n        private readonly SocketsTrace trace;\n        private readonly SocketSchedulers schedulers;\n\n        public SocketConnectionListenerFactory(\n            ILoggerFactory loggerFactory,\n            IOptions<SocketConnectionOptions> socketConnectionOptions,\n            SocketSchedulers schedulers)\n        {\n            if (loggerFactory == null)\n            {\n                throw new ArgumentNullException(nameof(loggerFactory));\n            }\n\n            this.socketConnectionOptions = socketConnectionOptions.Value;\n            var logger = loggerFactory.CreateLogger(\"Orleans.Sockets\");\n            this.trace = new SocketsTrace(logger);\n            this.schedulers = schedulers;\n        }\n\n        public ValueTask<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default)\n        {\n            if (!(endpoint is IPEndPoint ipEndpoint))\n            {\n                throw new ArgumentNullException(nameof(endpoint));\n            }\n\n            var listener = new SocketConnectionListener(ipEndpoint, this.socketConnectionOptions, this.trace, this.schedulers);\n            listener.Bind();\n            return new ValueTask<IConnectionListener>(listener);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketConnectionOptions.cs",
    "content": "using System;\nusing System.Buffers;\n\nnamespace Orleans.Networking.Shared\n{\n    /// <summary>\n    /// Options for configuring socket connections.\n    /// </summary>\n    public class SocketConnectionOptions\n    {\n        /// <summary>\n        /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool.\n        /// </summary>\n        /// <remarks>\n        /// Defaults to <see cref=\"Environment.ProcessorCount\" /> rounded down and clamped between 1 and 16.\n        /// </remarks>\n        public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16);\n\n        /// <summary>\n        /// Whether the Nagle algorithm should be enabled or disabled.\n        /// </summary>\n        public bool NoDelay { get; set; } = true;\n\n        /// <summary>\n        /// Whether TCP KeepAlive is enabled or disabled.\n        /// </summary>\n        public bool KeepAlive { get; set; } = true;\n\n        /// <summary>\n        /// The number of seconds before the first keep-alive packet is sent on an idle connection.\n        /// </summary>\n        /// <seealso cref=\"System.Net.Sockets.SocketOptionName.TcpKeepAliveTime\"/>\n        public int KeepAliveTimeSeconds { get; set; } = 90;\n\n        /// <summary>\n        /// The number of seconds between keep-alive packets when the remote endpoint is not responding.\n        /// </summary>\n        /// <seealso cref=\"System.Net.Sockets.SocketOptionName.TcpKeepAliveInterval\"/>\n        public int KeepAliveIntervalSeconds { get; set; } = 30;\n\n        /// <summary>\n        /// The number of retry attempts for keep-alive packets before the connection is considered dead.\n        /// </summary>\n        /// <seealso cref=\"System.Net.Sockets.SocketOptionName.TcpKeepAliveRetryCount\"/>\n        public int KeepAliveRetryCount { get; set; } = 10;\n\n        /// <summary>\n        /// Gets or sets the memory pool factory.\n        /// </summary>\n        internal Func<MemoryPool<byte>> MemoryPoolFactory { get; set; } = () => KestrelMemoryPool.Create();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketExtensions.cs",
    "content": "using System;\nusing System.Net.Sockets;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Networking.Shared\n{\n    internal static class SocketExtensions\n    {\n        private const int SIO_LOOPBACK_FAST_PATH = -1744830448;\n        private static readonly byte[] Enabled = BitConverter.GetBytes(1);\n\n        /// <summary>\n        /// Enables TCP Loopback Fast Path on a socket.\n        /// See https://blogs.technet.microsoft.com/wincat/2012/12/05/fast-tcp-loopback-performance-and-low-latency-with-windows-server-2012-tcp-loopback-fast-path/\n        /// for more information.\n        /// </summary>\n        /// <param name=\"socket\">The socket for which FastPath should be enabled.</param>\n        internal static void EnableFastPath(this Socket socket)\n        {\n            try { socket.NoDelay = true; } catch { }\n\n            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n            {\n                return;\n            }\n\n            try\n            {\n                // Win8/Server2012+ only\n                var osVersion = Environment.OSVersion.Version;\n                if (osVersion.Major > 6 || osVersion.Major == 6 && osVersion.Minor >= 2)\n                {\n                    socket.IOControl(SIO_LOOPBACK_FAST_PATH, Enabled, null);\n                }\n            }\n            catch\n            {\n                // If the operating system version on this machine did\n                // not support SIO_LOOPBACK_FAST_PATH (i.e. version\n                // prior to Windows 8 / Windows Server 2012), handle the exception\n            }\n        }\n\n        /// <summary>\n        /// Enables TCP KeepAlive on a socket.\n        /// </summary>\n        /// <param name=\"socket\">The socket.</param>\n        internal static void EnableKeepAlive(this Socket socket, int timeSeconds = 90, int intervalSeconds = 30, int retryCount = 2)\n        {\n            try\n            {\n                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);\n                socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, timeSeconds);\n                socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, intervalSeconds);\n                socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, retryCount);\n            }\n            catch\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketReceiver.cs",
    "content": "using System;\nusing System.IO.Pipelines;\nusing System.Net.Sockets;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class SocketReceiver : SocketSenderReceiverBase\n    {\n        public SocketReceiver(Socket socket, PipeScheduler scheduler) : base(socket, scheduler)\n        {\n        }\n\n        public SocketAwaitableEventArgs WaitForDataAsync()\n        {\n            _awaitableEventArgs.SetBuffer(Memory<byte>.Empty);\n\n            if (!_socket.ReceiveAsync(_awaitableEventArgs))\n            {\n                _awaitableEventArgs.Complete();\n            }\n\n            return _awaitableEventArgs;\n        }\n\n        public SocketAwaitableEventArgs ReceiveAsync(Memory<byte> buffer)\n        {\n            _awaitableEventArgs.SetBuffer(buffer);\n\n            if (!_socket.ReceiveAsync(_awaitableEventArgs))\n            {\n                _awaitableEventArgs.Complete();\n            }\n\n            return _awaitableEventArgs;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketSchedulers.cs",
    "content": "using System.IO.Pipelines;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Networking.Shared\n{\n    internal class SocketSchedulers\n    {\n        private static readonly PipeScheduler[] ThreadPoolSchedulerArray = new PipeScheduler[] { PipeScheduler.ThreadPool };\n        private readonly int _numSchedulers;\n        private readonly PipeScheduler[] _schedulers;\n        private int nextScheduler;\n\n        public SocketSchedulers(IOptions<SocketConnectionOptions> options)\n        {\n            var o = options.Value;\n            if (o.IOQueueCount > 0)\n            {\n                _numSchedulers = o.IOQueueCount;\n                _schedulers = new IOQueue[_numSchedulers];\n\n                for (var i = 0; i < _numSchedulers; i++)\n                {\n                    _schedulers[i] = new IOQueue();\n                }\n            }\n            else\n            {\n                _numSchedulers = ThreadPoolSchedulerArray.Length;\n                _schedulers = ThreadPoolSchedulerArray;\n            }\n        }\n\n        public PipeScheduler GetScheduler() => _schedulers[++nextScheduler % _numSchedulers];\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketSender.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO.Pipelines;\nusing System.Net.Sockets;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Networking.Shared\n{\n    internal sealed class SocketSender : SocketSenderReceiverBase\n    {\n        private List<ArraySegment<byte>> _bufferList;\n\n        public SocketSender(Socket socket, PipeScheduler scheduler) : base(socket, scheduler)\n        {\n        }\n\n        public SocketAwaitableEventArgs SendAsync(in ReadOnlySequence<byte> buffers)\n        {\n            if (buffers.IsSingleSegment)\n            {\n                return SendAsync(buffers.First);\n            }\n\n            if (!_awaitableEventArgs.Equals(Memory<byte>.Empty))\n            {\n                _awaitableEventArgs.SetBuffer(null, 0, 0);\n            }\n\n            _awaitableEventArgs.BufferList = GetBufferList(buffers);\n\n            if (!_socket.SendAsync(_awaitableEventArgs))\n            {\n                _awaitableEventArgs.Complete();\n            }\n\n            return _awaitableEventArgs;\n        }\n\n        private SocketAwaitableEventArgs SendAsync(ReadOnlyMemory<byte> memory)\n        {\n            // The BufferList getter is much less expensive then the setter.\n            if (_awaitableEventArgs.BufferList != null)\n            {\n                _awaitableEventArgs.BufferList = null;\n            }\n\n            _awaitableEventArgs.SetBuffer(MemoryMarshal.AsMemory(memory));\n\n            if (!_socket.SendAsync(_awaitableEventArgs))\n            {\n                _awaitableEventArgs.Complete();\n            }\n\n            return _awaitableEventArgs;\n        }\n\n        private List<ArraySegment<byte>> GetBufferList(in ReadOnlySequence<byte> buffer)\n        {\n            Debug.Assert(!buffer.IsEmpty);\n            Debug.Assert(!buffer.IsSingleSegment);\n\n            if (_bufferList == null)\n            {\n                _bufferList = new List<ArraySegment<byte>>();\n            }\n            else\n            {\n                // Buffers are pooled, so it's OK to root them until the next multi-buffer write.\n                _bufferList.Clear();\n            }\n\n            foreach (var b in buffer)\n            {\n                _bufferList.Add(b.GetArray());\n            }\n\n            return _bufferList;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketSenderReceiverBase.cs",
    "content": "using System;\nusing System.IO.Pipelines;\nusing System.Net.Sockets;\n\nnamespace Orleans.Networking.Shared\n{\n    internal abstract class SocketSenderReceiverBase : IDisposable\n    {\n        protected readonly Socket _socket;\n        protected readonly SocketAwaitableEventArgs _awaitableEventArgs;\n\n        protected SocketSenderReceiverBase(Socket socket, PipeScheduler scheduler)\n        {\n            _socket = socket;\n            _awaitableEventArgs = new SocketAwaitableEventArgs(scheduler);\n        }\n\n        public void Dispose() => _awaitableEventArgs.Dispose();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/SocketsTrace.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Networking.Shared\n{\n    internal partial class SocketsTrace : ISocketsTrace\n    {\n        // ConnectionRead: Reserved: 3\n        private readonly ILogger _logger;\n\n        public SocketsTrace(ILogger logger)\n        {\n            _logger = logger;\n        }\n\n        public void ConnectionRead(string connectionId, int count)\n        {\n            // Don't log for now since this could be *too* verbose.\n            // Reserved: Event ID 3\n        }\n\n        [LoggerMessage(\n            EventId = 6,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" received FIN.\"\n        )]\n        public partial void ConnectionReadFin(string connectionId);\n\n        [LoggerMessage(\n            EventId = 7,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" sending FIN because: \"\"{Reason}\"\"\"\n        )]\n        public partial void ConnectionWriteFin(string connectionId, string reason);\n\n        public void ConnectionWrite(string connectionId, int count)\n        {\n            // Don't log for now since this could be *too* verbose.\n            // Reserved: Event ID 11\n        }\n\n        public void ConnectionWriteCallback(string connectionId, int status)\n        {\n            // Don't log for now since this could be *too* verbose.\n            // Reserved: Event ID 12\n        }\n\n        [LoggerMessage(\n            EventId = 13,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" sending FIN.\"\n        )]\n        public partial void ConnectionError(string connectionId, Exception ex);\n\n        [LoggerMessage(\n            EventId = 19,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" reset.\"\n        )]\n        public partial void ConnectionReset(string connectionId);\n\n        [LoggerMessage(\n            EventId = 4,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" paused.\"\n        )]\n        public partial void ConnectionPause(string connectionId);\n\n        [LoggerMessage(\n            EventId = 5,\n            Level = LogLevel.Debug,\n            Message = @\"Connection id \"\"{ConnectionId}\"\" resumed.\"\n        )]\n        public partial void ConnectionResume(string connectionId);\n\n        public IDisposable BeginScope<TState>(TState state) => _logger.BeginScope(state);\n\n        public bool IsEnabled(LogLevel logLevel) => _logger.IsEnabled(logLevel);\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n            => _logger.Log(logLevel, eventId, state, exception, formatter);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/TransportConnection.Features.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.IO.Pipelines;\nusing System.Threading;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.AspNetCore.Connections.Features;\nusing Microsoft.AspNetCore.Http.Features;\n\nnamespace Orleans.Networking.Shared\n{\n    internal interface IConnectionIdFeature\n    {\n        string ConnectionId { get; set; }\n    }\n\n    internal interface IConnectionTransportFeature\n    {\n        IDuplexPipe Transport { get; set; }\n    }\n    internal interface IConnectionItemsFeature\n    {\n        IDictionary<object, object> Items { get; set; }\n    }\n\n    internal partial class TransportConnection : IConnectionIdFeature,\n                                                 IConnectionTransportFeature,\n                                                 IConnectionItemsFeature,\n                                                 IMemoryPoolFeature,\n                                                 IConnectionLifetimeFeature\n    {\n        // NOTE: When feature interfaces are added to or removed from this TransportConnection class implementation,\n        // then the list of `features` in the generated code project MUST also be updated.\n        // See also: tools/CodeGenerator/TransportConnectionFeatureCollection.cs\n\n        MemoryPool<byte> IMemoryPoolFeature.MemoryPool => MemoryPool;\n\n        IDuplexPipe IConnectionTransportFeature.Transport\n        {\n            get => Transport;\n            set => Transport = value;\n        }\n\n        IDictionary<object, object> IConnectionItemsFeature.Items\n        {\n            get => Items;\n            set => Items = value;\n        }\n\n        CancellationToken IConnectionLifetimeFeature.ConnectionClosed\n        {\n            get => ConnectionClosed;\n            set => ConnectionClosed = value;\n        }\n\n        void IConnectionLifetimeFeature.Abort() => Abort(new ConnectionAbortedException(\"The connection was aborted by the application via IConnectionLifetimeFeature.Abort().\"));\n    }\n\n    internal partial class TransportConnection : IFeatureCollection\n    {\n        private static readonly Type IConnectionIdFeatureType = typeof(IConnectionIdFeature);\n        private static readonly Type IConnectionTransportFeatureType = typeof(IConnectionTransportFeature);\n        private static readonly Type IConnectionItemsFeatureType = typeof(IConnectionItemsFeature);\n        private static readonly Type IMemoryPoolFeatureType = typeof(IMemoryPoolFeature);\n        private static readonly Type IConnectionLifetimeFeatureType = typeof(IConnectionLifetimeFeature);\n\n        private object _currentIConnectionIdFeature;\n        private object _currentIConnectionTransportFeature;\n        private object _currentIConnectionItemsFeature;\n        private object _currentIMemoryPoolFeature;\n        private object _currentIConnectionLifetimeFeature;\n\n        private int _featureRevision;\n\n        private List<KeyValuePair<Type, object>> MaybeExtra;\n\n        private void FastReset()\n        {\n            _currentIConnectionIdFeature = this;\n            _currentIConnectionTransportFeature = this;\n            _currentIConnectionItemsFeature = this;\n            _currentIMemoryPoolFeature = this;\n            _currentIConnectionLifetimeFeature = this;\n\n        }\n\n        // Internal for testing\n        internal void ResetFeatureCollection()\n        {\n            FastReset();\n            MaybeExtra?.Clear();\n            _featureRevision++;\n        }\n\n        private object ExtraFeatureGet(Type key)\n        {\n            if (MaybeExtra == null)\n            {\n                return null;\n            }\n            for (var i = 0; i < MaybeExtra.Count; i++)\n            {\n                var kv = MaybeExtra[i];\n                if (kv.Key == key)\n                {\n                    return kv.Value;\n                }\n            }\n            return null;\n        }\n\n        private void ExtraFeatureSet(Type key, object value)\n        {\n            if (MaybeExtra == null)\n            {\n                MaybeExtra = new List<KeyValuePair<Type, object>>(2);\n            }\n\n            for (var i = 0; i < MaybeExtra.Count; i++)\n            {\n                if (MaybeExtra[i].Key == key)\n                {\n                    MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);\n                    return;\n                }\n            }\n            MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));\n        }\n\n        bool IFeatureCollection.IsReadOnly => false;\n\n        int IFeatureCollection.Revision => _featureRevision;\n\n        object IFeatureCollection.this[Type key]\n        {\n            get\n            {\n                object feature = null;\n                if (key == IConnectionIdFeatureType)\n                {\n                    feature = _currentIConnectionIdFeature;\n                }\n                else if (key == IConnectionTransportFeatureType)\n                {\n                    feature = _currentIConnectionTransportFeature;\n                }\n                else if (key == IConnectionItemsFeatureType)\n                {\n                    feature = _currentIConnectionItemsFeature;\n                }\n                else if (key == IMemoryPoolFeatureType)\n                {\n                    feature = _currentIMemoryPoolFeature;\n                }\n                else if (key == IConnectionLifetimeFeatureType)\n                {\n                    feature = _currentIConnectionLifetimeFeature;\n                }\n                else if (MaybeExtra != null)\n                {\n                    feature = ExtraFeatureGet(key);\n                }\n\n                return feature;\n            }\n\n            set\n            {\n                _featureRevision++;\n\n                if (key == IConnectionIdFeatureType)\n                {\n                    _currentIConnectionIdFeature = value;\n                }\n                else if (key == IConnectionTransportFeatureType)\n                {\n                    _currentIConnectionTransportFeature = value;\n                }\n                else if (key == IConnectionItemsFeatureType)\n                {\n                    _currentIConnectionItemsFeature = value;\n                }\n                else if (key == IMemoryPoolFeatureType)\n                {\n                    _currentIMemoryPoolFeature = value;\n                }\n                else if (key == IConnectionLifetimeFeatureType)\n                {\n                    _currentIConnectionLifetimeFeature = value;\n                }\n                else\n                {\n                    ExtraFeatureSet(key, value);\n                }\n            }\n        }\n\n        TFeature IFeatureCollection.Get<TFeature>()\n        {\n            TFeature feature = default;\n            if (typeof(TFeature) == typeof(IConnectionIdFeature))\n            {\n                feature = (TFeature)_currentIConnectionIdFeature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionTransportFeature))\n            {\n                feature = (TFeature)_currentIConnectionTransportFeature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionItemsFeature))\n            {\n                feature = (TFeature)_currentIConnectionItemsFeature;\n            }\n            else if (typeof(TFeature) == typeof(IMemoryPoolFeature))\n            {\n                feature = (TFeature)_currentIMemoryPoolFeature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))\n            {\n                feature = (TFeature)_currentIConnectionLifetimeFeature;\n            }\n            else if (MaybeExtra != null)\n            {\n                feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));\n            }\n\n            return feature;\n        }\n\n        void IFeatureCollection.Set<TFeature>(TFeature feature)\n        {\n            _featureRevision++;\n            if (typeof(TFeature) == typeof(IConnectionIdFeature))\n            {\n                _currentIConnectionIdFeature = feature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionTransportFeature))\n            {\n                _currentIConnectionTransportFeature = feature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionItemsFeature))\n            {\n                _currentIConnectionItemsFeature = feature;\n            }\n            else if (typeof(TFeature) == typeof(IMemoryPoolFeature))\n            {\n                _currentIMemoryPoolFeature = feature;\n            }\n            else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature))\n            {\n                _currentIConnectionLifetimeFeature = feature;\n            }\n            else\n            {\n                ExtraFeatureSet(typeof(TFeature), feature);\n            }\n        }\n\n        private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()\n        {\n            if (_currentIConnectionIdFeature != null)\n            {\n                yield return new KeyValuePair<Type, object>(IConnectionIdFeatureType, _currentIConnectionIdFeature);\n            }\n            if (_currentIConnectionTransportFeature != null)\n            {\n                yield return new KeyValuePair<Type, object>(IConnectionTransportFeatureType, _currentIConnectionTransportFeature);\n            }\n            if (_currentIConnectionItemsFeature != null)\n            {\n                yield return new KeyValuePair<Type, object>(IConnectionItemsFeatureType, _currentIConnectionItemsFeature);\n            }\n            if (_currentIMemoryPoolFeature != null)\n            {\n                yield return new KeyValuePair<Type, object>(IMemoryPoolFeatureType, _currentIMemoryPoolFeature);\n            }\n            if (_currentIConnectionLifetimeFeature != null)\n            {\n                yield return new KeyValuePair<Type, object>(IConnectionLifetimeFeatureType, _currentIConnectionLifetimeFeature);\n            }\n\n            if (MaybeExtra != null)\n            {\n                foreach (var item in MaybeExtra)\n                {\n                    yield return item;\n                }\n            }\n        }\n\n        IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();\n\n        IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/Shared/TransportConnection.cs",
    "content": "using System.Buffers;\nusing System.Collections.Generic;\nusing System.IO.Pipelines;\nusing System.Net;\nusing System.Threading;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.AspNetCore.Http.Features;\n\nnamespace Orleans.Networking.Shared\n{\n    internal abstract partial class TransportConnection : ConnectionContext\n    {\n        private IDictionary<object, object> _items;\n        private string _connectionId;\n\n        public TransportConnection()\n        {\n            FastReset();\n        }\n\n        public override EndPoint LocalEndPoint { get; set; }\n        public override EndPoint RemoteEndPoint { get; set; }\n\n        public override string ConnectionId\n        {\n            get\n            {\n                if (_connectionId == null)\n                {\n                    _connectionId = CorrelationIdGenerator.GetNextId();\n                }\n\n                return _connectionId;\n            }\n            set\n            {\n                _connectionId = value;\n            }\n        }\n\n        public override IFeatureCollection Features => this;\n\n        public virtual MemoryPool<byte> MemoryPool { get; }\n\n        public override IDuplexPipe Transport { get; set; }\n\n        public IDuplexPipe Application { get; set; }\n\n        public override IDictionary<object, object> Items\n        {\n            get\n            {\n                // Lazily allocate connection metadata\n                return _items ?? (_items = new ConnectionItems());\n            }\n            set\n            {\n                _items = value;\n            }\n        }\n\n        public override CancellationToken ConnectionClosed { get; set; }\n\n        // DO NOT remove this override to ConnectionContext.Abort. Doing so would cause\n        // any TransportConnection that does not override Abort or calls base.Abort\n        // to stack overflow when IConnectionLifetimeFeature.Abort() is called.\n        // That said, all derived types should override this method should override\n        // this implementation of Abort because canceling pending output reads is not\n        // sufficient to abort the connection if there is backpressure.\n        public override void Abort(ConnectionAbortedException abortReason)\n        {\n            Application.Input.CancelPendingRead();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Networking/SocketDirection.cs",
    "content": "namespace Orleans.Messaging\n{\n    internal enum ConnectionDirection : byte\n    {\n        SiloToSilo,\n        ClientToGateway,\n        GatewayToClient\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Orleans.Core.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Core</PackageId>\n    <Title>Microsoft Orleans Core Library</Title>\n    <Description>Core library of Microsoft Orleans used both on the client and server.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <RootNamespace>Orleans</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n  <ItemGroup>\n    <Content Include=\"buildMultiTargeting\\Microsoft.Orleans.Core.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"buildTransitive\\Microsoft.Orleans.Core.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"build\\Microsoft.Orleans.Core.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Update=\"Configuration\\OrleansConfiguration.xsd\">\n      <SubType>Designer</SubType>\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      <Pack>false</Pack>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Connections.Abstractions\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyModel\" />\n    <PackageReference Include=\"Microsoft.Extensions.ObjectPool\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options.ConfigurationExtensions\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" />\n    <PackageReference Include=\"Newtonsoft.Json\" />\n    <PackageReference Include=\"System.Memory.Data\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Benchmarks\" />\n    <InternalsVisibleTo Include=\"CodeGenerator.Tests\" />\n    <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" />\n    <InternalsVisibleTo Include=\"GoogleUtils.Tests\" />\n    <InternalsVisibleTo Include=\"LoadTestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.BroadcastChannel\" />\n    <InternalsVisibleTo Include=\"Orleans.Clustering.ZooKeeper.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.CodeGeneration\" />\n    <InternalsVisibleTo Include=\"Orleans.CodeGeneration.Build\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Cosmos.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DurableJobs\" />\n    <InternalsVisibleTo Include=\"Orleans.DurableJobs.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.GrainDirectory.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Placement.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Reminders\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.EventHubs.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.TestingHost\" />\n    <InternalsVisibleTo Include=\"TestExtensions\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Core/Placement/IPlacementContext.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Provides context for a grain placement operation.\n    /// </summary>\n    public interface IPlacementContext\n    {\n        /// <summary>\n        /// Gets the collection of silos which are compatible with the provided placement target.\n        /// </summary>\n        /// <param name=\"target\">\n        /// A description of the grain being placed as well as contextual information about the request which is triggering placement.\n        /// </param>\n        /// <returns>The collection of silos which are compatible with the provided placement target.</returns>\n        SiloAddress[] GetCompatibleSilos(PlacementTarget target);\n\n        /// <summary>\n        /// Gets the collection of silos which are compatible with the provided placement target, along with the versions of the grain interface which each server supports.\n        /// </summary>\n        /// <param name=\"target\">\n        /// A description of the grain being placed as well as contextual information about the request which is triggering placement.\n        /// </param>\n        /// <returns>The collection of silos which are compatible with the provided placement target, along with the versions of the grain interface which each server supports.</returns>\n        IReadOnlyDictionary<ushort, SiloAddress[]> GetCompatibleSilosWithVersions(PlacementTarget target);\n\n        /// <summary>\n        /// Gets the local silo's identity.\n        /// </summary>\n        SiloAddress LocalSilo { get; }\n\n        /// <summary>\n        /// Gets the local silo's status.\n        /// </summary>\n        SiloStatus LocalSiloStatus { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/IPlacementDirector.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Interface for placement directors.\n    /// </summary>\n    public interface IPlacementDirector\n    {\n        /// <summary>\n        /// Gets the <see cref=\"PlacementTarget.RequestContextData\"/> key used to store the placement hint, if present.\n        /// </summary>\n        public const string PlacementHintKey = nameof(PlacementHintKey);\n\n        /// <summary>\n        /// Picks an appropriate silo to place the specified target on.\n        /// </summary>\n        /// <param name=\"strategy\">The target's placement strategy.</param>\n        /// <param name=\"target\">The grain being placed as well as information about the request which triggered the placement.</param>\n        /// <param name=\"context\">The placement context.</param>\n        /// <returns>An appropriate silo to place the specified target on.</returns>\n        Task<SiloAddress> OnAddActivation(\n            PlacementStrategy strategy, PlacementTarget target, IPlacementContext context);\n\n        /// <summary>\n        /// Gets the placement hint from the provided request context data, if present and valid.\n        /// </summary>\n        /// <param name=\"requestContextData\">The request context data.</param>\n        /// <param name=\"compatibleSilos\">The compatible silos.</param>\n        /// <returns>The placement hint, if present and valid, or <see landword=\"null\"/> otherwise.</returns>\n        public static SiloAddress GetPlacementHint(Dictionary<string, object> requestContextData, SiloAddress[] compatibleSilos)\n        {\n            if (requestContextData is { Count: > 0 } data\n                && data.TryGetValue(PlacementHintKey, out var value)\n                && value is SiloAddress placementHint\n                && compatibleSilos.Contains(placementHint))\n            {\n                return placementHint;\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/IPlacementFilterDirector.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\n\n#nullable enable\nnamespace Orleans.Placement;\n\npublic interface IPlacementFilterDirector\n{\n    IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/PlacementFilterExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\n#nullable enable\nnamespace Orleans.Placement;\n\npublic static class PlacementFilterExtensions\n{\n    /// <summary>\n    /// Configures a <typeparamref name=\"TFilter\"/> for filtering candidate grain placements.\n    /// </summary>\n    /// <typeparam name=\"TFilter\">The placement filter.</typeparam>\n    /// <typeparam name=\"TDirector\">The placement filter director.</typeparam>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"strategyLifetime\">The lifetime of the placement strategy.</param>\n    /// <returns>The service collection.</returns>\n    public static IServiceCollection AddPlacementFilter<TFilter, TDirector>(this IServiceCollection services, ServiceLifetime strategyLifetime)\n        where TFilter : PlacementFilterStrategy, new()\n        where TDirector : class, IPlacementFilterDirector\n    {\n        services.Add(ServiceDescriptor.DescribeKeyed(typeof(PlacementFilterStrategy), typeof(TFilter).Name, typeof(TFilter), strategyLifetime));\n        services.AddKeyedSingleton<IPlacementFilterDirector, TDirector>(typeof(TFilter));\n\n        return services;\n    }\n\n}"
  },
  {
    "path": "src/Orleans.Core/Placement/PlacementTarget.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Describes a placement target, which is a grain as well as context regarding the request which is triggering grain placement.\n    /// </summary>\n    public readonly struct PlacementTarget\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PlacementTarget\"/> struct.\n        /// </summary>\n        /// <param name=\"grainIdentity\">The grain being targeted.</param>\n        /// <param name=\"requestContextData\">The <see cref=\"RequestContext\"/> dictionary for the request which triggered placement.</param>\n        /// <param name=\"interfaceType\">The interface being requested.</param>\n        /// <param name=\"interfaceVersion\">The interface version being requested.</param>\n        public PlacementTarget(GrainId grainIdentity, Dictionary<string, object> requestContextData, GrainInterfaceType interfaceType, ushort interfaceVersion)\n        {\n            this.GrainIdentity = grainIdentity;\n            this.InterfaceType = interfaceType;\n            this.InterfaceVersion = interfaceVersion;\n            this.RequestContextData = requestContextData;\n        }\n\n        /// <summary>\n        /// Gets the grain being targeted.\n        /// </summary>\n        public GrainId GrainIdentity { get; }\n\n        /// <summary>\n        /// Gets the interface type of the interface which is being called on the grain which triggered this placement request.\n        /// </summary>\n        public GrainInterfaceType InterfaceType { get; }\n\n        /// <summary>\n        /// Gets the interface version being requested.\n        /// </summary>\n        public ushort InterfaceVersion { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"RequestContext\"/> dictionary for the request which triggered placement.\n        /// </summary>\n        public Dictionary<string, object> RequestContextData { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/IActivationRebalancer.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Placement.Rebalancing;\n\n/// <summary>\n/// A gateway to interface with the activation rebalancer.\n/// </summary>\n/// <remarks>This is available only on the silo.</remarks>\npublic interface IActivationRebalancer\n{\n    /// <summary>\n    /// Returns the rebalancing report.\n    /// <para>The report can lag behind if you choose a session cycle period less than <see cref=\"IActivationRebalancerMonitor.WorkerReportPeriod\"/>.</para>\n    /// </summary>\n    /// <param name=\"force\">If set to <see langword=\"true\"/> returns the most current report.</param>\n    /// <remarks>Using <paramref name=\"force\"/> incurs an asynchronous operation.</remarks>\n    ValueTask<RebalancingReport> GetRebalancingReport(bool force = false);\n\n    /// <inheritdoc cref=\"IActivationRebalancerWorker.ResumeRebalancing\"/>\n    Task ResumeRebalancing();\n\n    /// <inheritdoc cref=\"IActivationRebalancerWorker.SuspendRebalancing(TimeSpan?)\"/>\n    Task SuspendRebalancing(TimeSpan? duration = null);\n\n    /// <summary>\n    /// Subscribe to activation rebalancer reports.\n    /// </summary>\n    /// <param name=\"listener\">The component that will be notified.</param>\n    void SubscribeToReports(IActivationRebalancerReportListener listener);\n\n    /// <summary>\n    /// Unsubscribe from activation rebalancer reports.\n    /// </summary>\n    /// <param name=\"listener\">The already subscribed component.</param>\n    void UnsubscribeFromReports(IActivationRebalancerReportListener listener);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/IActivationRebalancerMonitor.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\n#nullable enable\n\nnamespace Orleans.Placement.Rebalancing;\n\n[Alias(\"IActivationRebalancerMonitor\")]\ninternal interface IActivationRebalancerMonitor : ISystemTarget, IActivationRebalancer\n{\n    /// <summary>\n    /// The period on which the <see cref=\"IActivationRebalancerWorker\"/> must report back to the monitor.\n    /// </summary>\n    public static readonly TimeSpan WorkerReportPeriod = TimeSpan.FromSeconds(30);\n\n    /// <summary>\n    /// Invoked periodically by the <see cref=\"IActivationRebalancerWorker\"/>.\n    /// </summary>\n    [Alias(\"Report\")] Task Report(RebalancingReport report);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/IActivationRebalancerReportListener.cs",
    "content": "namespace Orleans.Placement.Rebalancing;\n\n/// <summary>\n/// Interface for types which listen to rebalancer status changes.\n/// </summary>\npublic interface IActivationRebalancerReportListener\n{\n    /// <summary>\n    /// Triggered when rebalancer has provided a new <see cref=\"RebalancingReport\"/>.\n    /// </summary>\n    /// <param name=\"report\">Latest report from the rebalancer.</param>\n    void OnReport(RebalancingReport report);\n}"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/IActivationRebalancerWorker.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\n\nnamespace Orleans.Placement.Rebalancing;\n\n[Alias(\"IActivationRebalancerWorker\")]\ninternal interface IActivationRebalancerWorker : IGrainWithIntegerKey\n{\n    /// <summary>\n    /// Returns the most recent rebalancing report.\n    /// </summary>\n    /// <remarks>Acts also as a way to wake up the rebalancer, if its deactivated.</remarks>\n    [AlwaysInterleave, Alias(\"GetReport\")] ValueTask<RebalancingReport> GetReport();\n\n    /// <summary>\n    /// Resumes rebalancing if its suspended, otherwise its a no-op.\n    /// </summary>\n    [Alias(\"ResumeRebalancing\")] Task ResumeRebalancing();\n\n    /// <summary>\n    /// Suspends rebalancing if its running, otherwise its a no-op.\n    /// </summary>\n    /// <param name=\"duration\">\n    /// The amount of time to suspend the rebalancer.\n    /// <para><see langword=\"null\"/> means suspend indefinitely.</para>\n    /// </param>\n    [Alias(\"SuspendRebalancing\")] Task SuspendRebalancing(TimeSpan? duration);\n}"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/IFailedSessionBackoffProvider.cs",
    "content": "using Orleans.Internal;\n\nnamespace Orleans.Placement.Rebalancing;\n\n/// <summary>\n/// Determines how long to wait between successive rebalancing sessions, if an aprior session has failed.\n/// </summary>\n/// <remarks>\n/// A session is considered \"failed\" if n-consecutive number of cycles yielded no significant improvement\n/// to the cluster's entropy.\n/// </remarks>\npublic interface IFailedSessionBackoffProvider : IBackoffProvider { }"
  },
  {
    "path": "src/Orleans.Core/Placement/Rebalancing/RebalancingReport.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Orleans.Runtime;\n\nnamespace Orleans.Placement.Rebalancing;\n\n/// <summary>\n/// The status of the <see cref=\"IActivationRebalancerWorker\"/>.\n/// </summary>\n[GenerateSerializer]\npublic enum RebalancerStatus : byte\n{\n    /// <summary>\n    /// It is executing.\n    /// </summary>\n    Executing = 0,\n    /// <summary>\n    /// It is suspended.\n    /// </summary>\n    Suspended = 1\n}\n\n/// <summary>\n/// A report of the current state of the activation rebalancer.\n/// </summary>\n[GenerateSerializer, Immutable, Alias(\"RebalancingReport\")]\npublic readonly struct RebalancingReport\n{\n    /// <summary>\n    /// The silo where the rebalancer is currently located.\n    /// </summary>\n    [Id(0)] public required SiloAddress Host { get; init; }\n\n    /// <summary>\n    /// The current status of the rebalancer.\n    /// </summary>\n    [Id(1)] public required RebalancerStatus Status { get; init; }\n\n    /// <summary>\n    /// The amount of time the rebalancer is suspended (if at all).\n    /// </summary>\n    /// <remarks>This will always be <see langword=\"null\"/> if <see cref=\"Status\"/> is <see cref=\"RebalancerStatus.Executing\"/>.</remarks>\n    [Id(2)] public TimeSpan? SuspensionDuration { get; init; }\n\n    /// <summary>\n    /// The current view of the cluster's imbalance.\n    /// </summary>\n    /// <remarks>Range: [0-1]</remarks>\n    [Id(3)] public required double ClusterImbalance { get; init; }\n\n    /// <summary>\n    /// Latest rebalancing statistics.\n    /// </summary>\n    [Id(4)] public required ImmutableArray<RebalancingStatistics> Statistics { get; init; }\n}\n\n/// <summary>\n/// Rebalancing statistics for the given <see cref=\"SiloAddress\"/>.\n/// </summary>\n/// <remarks>\n/// Used for diagnostics / metrics purposes. Note that statistics are an approximation.</remarks>\n[GenerateSerializer, Immutable, Alias(\"RebalancingStatistics\")]\npublic readonly struct RebalancingStatistics\n{\n    /// <summary>\n    /// The time these statistics were assembled.\n    /// </summary>\n    [Id(0)] public required DateTime TimeStamp { get; init; }\n\n    /// <summary>\n    /// The silo to which these statistics belong to.\n    /// </summary>\n    [Id(1)] public required SiloAddress SiloAddress { get; init; }\n\n    /// <summary>\n    /// The approximate number of activations that have been dispersed from this silo thus far.\n    /// </summary>\n    [Id(2)] public required ulong DispersedActivations { get; init; }\n\n    /// <summary>\n    /// The approximate number of activations that have been acquired by this silo thus far.\n    /// </summary>\n    [Id(3)] public required ulong AcquiredActivations { get; init; }\n}"
  },
  {
    "path": "src/Orleans.Core/Placement/Repartitioning/IActivationRepartitionerSystemTarget.cs",
    "content": "using System.Threading.Tasks;\nusing System.Collections.Immutable;\nusing Orleans.Runtime;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System;\n\nnamespace Orleans.Placement.Repartitioning;\n\n[Alias(\"IActivationRepartitionerSystemTarget\")]\ninternal interface IActivationRepartitionerSystemTarget : ISystemTarget\n{\n    static IActivationRepartitionerSystemTarget GetReference(IGrainFactory grainFactory, SiloAddress targetSilo)\n        => grainFactory.GetGrain<IActivationRepartitionerSystemTarget>(SystemTargetGrainId.Create(Constants.ActivationRepartitionerType, targetSilo).GrainId);\n\n    [ResponseTimeout(\"00:10:00\")]\n    ValueTask TriggerExchangeRequest();\n\n    [ResponseTimeout(\"00:10:00\")]\n    ValueTask<AcceptExchangeResponse> AcceptExchangeRequest(AcceptExchangeRequest request);\n\n    /// <summary>\n    /// For use in testing only!\n    /// </summary>\n    ValueTask ResetCounters();\n\n    /// <summary>\n    /// For use in testing only!\n    /// </summary>\n    ValueTask<int> GetActivationCount();\n\n    /// <summary>\n    /// For use in testing only!\n    /// </summary>\n    ValueTask SetActivationCountOffset(int activationCountOffset);\n\n    /// <summary>\n    /// For diagnostics only.\n    /// </summary>\n    ValueTask<ImmutableArray<(Edge, ulong)>> GetGrainCallFrequencies();\n\n    /// <summary>\n    /// For use in testing only! Flushes buffered messages.\n    /// </summary>\n    ValueTask FlushBuffers();\n}\n\n// We use a readonly struct so that we can fully decouple the message-passing and potentially modifications to the Silo fields.\n/// <summary>\n/// Data structure representing a 'communication edge' between a source and target.\n/// </summary>\n[GenerateSerializer, Immutable, DebuggerDisplay(\"Source: [{Source.Id} - {Source.Silo}] | Target: [{Target.Id} - {Target.Silo}]\")]\ninternal readonly struct Edge(EdgeVertex source, EdgeVertex target) : IEquatable<Edge>\n{\n    [Id(0)]\n    public EdgeVertex Source { get; } = source;\n\n    [Id(1)]\n    public EdgeVertex Target { get; } = target;\n\n    public static bool operator ==(Edge left, Edge right) => left.Equals(right);\n    public static bool operator !=(Edge left, Edge right) => !left.Equals(right);\n\n    public override bool Equals([NotNullWhen(true)] object obj) => obj is Edge other && Equals(other);\n    public bool Equals(Edge other) => Source == other.Source && Target == other.Target;\n\n    public override int GetHashCode() => HashCode.Combine(Source, Target);\n\n    /// <summary>\n    /// Returns a copy of this but with flipped sources and targets.\n    /// </summary>\n    public Edge Flip() => new(source: Target, target: Source);\n\n    public override string ToString() => $\"[{Source} -> {Target}]\";\n}\n\n/// <summary>\n/// Data structure representing one side of a <see cref=\"Edge\"/>.\n/// </summary>\n[GenerateSerializer, Immutable]\npublic readonly struct EdgeVertex(\n    GrainId id,\n    SiloAddress silo,\n    bool isMigratable) : IEquatable<EdgeVertex>\n{\n    [Id(0)]\n    public readonly GrainId Id = id;\n\n    [Id(1)]\n    public readonly SiloAddress Silo = silo;\n\n    [Id(2)]\n    public readonly bool IsMigratable = isMigratable;\n\n    public static bool operator ==(EdgeVertex left, EdgeVertex right) => left.Equals(right);\n    public static bool operator !=(EdgeVertex left, EdgeVertex right) => !left.Equals(right);\n\n    public override bool Equals([NotNullWhen(true)] object obj) => obj is EdgeVertex other && Equals(other);\n    public bool Equals(EdgeVertex other) => Id == other.Id && Silo == other.Silo && IsMigratable == other.IsMigratable;\n\n    public override int GetHashCode() => HashCode.Combine(Id, Silo, IsMigratable);\n\n    public override string ToString() => $\"[{Id}@{Silo}{(IsMigratable ? \"\" : \"/NotMigratable\")}]\";\n}\n\n/// <summary>\n/// A candidate vertex to be transferred to another silo.\n/// </summary>\n[GenerateSerializer, DebuggerDisplay(\"Id = {Id} | Accumulated = {AccumulatedTransferScore}\")]\ninternal sealed class CandidateVertex\n{\n    /// <summary>\n    /// The id of the candidate grain.\n    /// </summary>\n    [Id(0), Immutable]\n    public GrainId Id { get; init; }\n\n    /// <summary>\n    /// The cost reduction expected from migrating the vertex with <see cref=\"Id\"/> to another silo.\n    /// </summary>\n    [Id(1)]\n    public long AccumulatedTransferScore { get; set; }\n\n    /// <summary>\n    /// These are all the vertices connected to the vertex with <see cref=\"Id\"/>.\n    /// </summary>\n    /// <remarks>These will be important when this vertex is removed from the max-sorted heap on the receiver silo.</remarks>\n    [Id(2), Immutable]\n    public ImmutableArray<CandidateConnectedVertex> ConnectedVertices { get; init; } = [];\n\n    public override string ToString() => $\"[{Id} * {AccumulatedTransferScore} -> [{string.Join(\", \", ConnectedVertices)}]]\";\n}\n\n[GenerateSerializer, Immutable]\npublic readonly struct CandidateConnectedVertex(GrainId id, long transferScore)\n{\n    [Id(0)]\n    public GrainId Id { get; } = id;\n\n    [Id(1)]\n    public long TransferScore { get; } = transferScore;\n\n    public static bool operator ==(CandidateConnectedVertex left, CandidateConnectedVertex right) => left.Equals(right);\n    public static bool operator !=(CandidateConnectedVertex left, CandidateConnectedVertex right) => !left.Equals(right);\n\n    public override bool Equals([NotNullWhen(true)] object obj) => obj is CandidateConnectedVertex other && Equals(other);\n    public bool Equals(CandidateConnectedVertex other) => Id == other.Id && TransferScore == other.TransferScore;\n\n    public override int GetHashCode() => HashCode.Combine(Id, TransferScore);\n\n    public override string ToString() => $\"[{Id} * {TransferScore}]\";\n}\n\n[GenerateSerializer, Immutable]\ninternal sealed class AcceptExchangeRequest(SiloAddress sendingSilo, ImmutableArray<CandidateVertex> exchangeSet, int activationCountSnapshot)\n{\n    /// <summary>\n    /// The silo which is offering to transfer grains to us.\n    /// </summary>\n    [Id(0)]\n    public SiloAddress SendingSilo { get; } = sendingSilo;\n\n    /// <summary>\n    /// The set of grains which the sending silo is offering to transfer to us.\n    /// </summary>\n    [Id(1)]\n    public ImmutableArray<CandidateVertex> ExchangeSet { get; } = exchangeSet;\n\n    /// <summary>\n    /// The activation count of the sending silo at the time of the exchange request.\n    /// </summary>\n    [Id(2)]\n    public int ActivationCountSnapshot { get; } = activationCountSnapshot;\n}\n\n[GenerateSerializer, Immutable]\ninternal sealed class AcceptExchangeResponse(AcceptExchangeResponse.ResponseType type, ImmutableArray<GrainId> acceptedGrains, ImmutableArray<GrainId> givenGrains)\n{\n    public static readonly AcceptExchangeResponse CachedExchangedRecently = new(ResponseType.ExchangedRecently, [], []);\n    public static readonly AcceptExchangeResponse CachedMutualExchangeAttempt = new(ResponseType.MutualExchangeAttempt, [], []);\n\n    [Id(0)]\n    public ResponseType Type { get; } = type;\n\n    /// <summary>\n    /// The grains which the sender is asking the receiver to transfer.\n    /// </summary>\n    [Id(1)]\n    public ImmutableArray<GrainId> AcceptedGrainIds { get; } = acceptedGrains;\n\n    /// <summary>\n    /// The grains which the receiver is transferring to the sender.\n    /// </summary>\n    [Id(2)]\n    public ImmutableArray<GrainId> GivenGrainIds { get; } = givenGrains;\n\n    [GenerateSerializer]\n    public enum ResponseType\n    {\n        /// <summary>\n        /// The exchange was accepted and an exchange set is returned.\n        /// </summary>\n        Success,\n\n        /// <summary>\n        /// The other silo has been recently involved in another exchange.\n        /// </summary>\n        ExchangedRecently,\n\n        /// <summary>\n        /// An attempt to do an exchange between this and the other silo was about to happen at the same time.\n        /// </summary>\n        MutualExchangeAttempt\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Placement/Repartitioning/IImbalanceToleranceRule.cs",
    "content": "namespace Orleans.Placement.Repartitioning;\n\n/// <summary>\n/// Represents a rule that controls the degree of imbalance between the number of grain activations (that is considered tolerable), when any pair of silos are exchanging activations.\n/// </summary>\npublic interface IImbalanceToleranceRule\n{\n    /// <summary>\n    /// Checks if this rule is satisfied by <paramref name=\"imbalance\"/>.\n    /// </summary>\n    /// <param name=\"imbalance\">The imbalance between the exchanging silo pair that will be, if this method were to return <see langword=\"true\"/></param>\n    bool IsSatisfiedBy(uint imbalance);\n}"
  },
  {
    "path": "src/Orleans.Core/Placement/Repartitioning/IMessageStatisticsSink.cs",
    "content": "#nullable enable\nusing System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Placement.Repartitioning;\n\ninternal interface IMessageStatisticsSink\n{\n    Action<Message>? GetMessageObserver();\n}\n\ninternal sealed class NoOpMessageStatisticsSink : IMessageStatisticsSink\n{\n    public Action<Message>? GetMessageObserver() => null;\n}"
  },
  {
    "path": "src/Orleans.Core/Providers/ClientProviderRuntime.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// <see cref=\"IProviderRuntime\"/> for clients.\n    /// </summary>\n    /// <seealso cref=\"Orleans.Providers.IProviderRuntime\" />\n    internal class ClientProviderRuntime : IProviderRuntime\n    {\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly ClientGrainContext clientContext;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientProviderRuntime\"/> class.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"clientContext\">The client context.</param>\n        public ClientProviderRuntime(\n            IInternalGrainFactory grainFactory,\n            IServiceProvider serviceProvider,\n            ClientGrainContext clientContext)\n        {\n            this.grainFactory = grainFactory;\n            this.ServiceProvider = serviceProvider;\n            this.clientContext = clientContext;\n        }\n\n        /// <inheritdoc/>\n        public IGrainFactory GrainFactory => this.grainFactory;\n\n        /// <inheritdoc/>\n        public IServiceProvider ServiceProvider { get; }\n\n        /// <inheritdoc/>\n        public (TExtension Extension, TExtensionInterface ExtensionReference) BindExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            return this.clientContext.GetOrSetExtension<TExtension, TExtensionInterface>(newExtensionFunc);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/GrainStorageHelpers.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Providers;\n\nnamespace Orleans.Storage;\n\n/// <summary>\n/// Utility functions for grain storage.\n/// </summary>\npublic static class GrainStorageHelpers\n{\n    /// <summary>\n    /// Gets the <see cref=\"IGrainStorage\"/> associated with the specified grain type, which must derive from <see cref=\"Grain{T}\"/>.\n    /// </summary>\n    /// <param name=\"grainType\">The grain type, which must derive from <see cref=\"Grain{T}\"/>.</param>\n    /// <param name=\"services\">The service provider.</param>\n    /// <returns>\n    /// The <see cref=\"IGrainStorage\"/> associated with the specified grain type, which must derive from <see cref=\"Grain{T}\"/>.\n    /// </returns>\n    public static IGrainStorage GetGrainStorage(Type grainType, IServiceProvider services)\n    {\n        if (grainType is null) throw new ArgumentNullException(nameof(grainType));\n        var attrs = grainType.GetCustomAttributes(typeof(StorageProviderAttribute), true);\n        var attr = attrs.Length > 0 ? (StorageProviderAttribute)attrs[0] : null;\n        var storageProvider = attr != null\n            ? services.GetKeyedService<IGrainStorage>(attr.ProviderName)\n            : services.GetService<IGrainStorage>();\n        if (storageProvider == null)\n        {\n            ThrowMissingProviderException(grainType, attr?.ProviderName);\n        }\n\n        return storageProvider;\n    }\n\n    [DoesNotReturn]\n    private static void ThrowMissingProviderException(Type grainType, string? name)\n    {\n        var grainTypeName = grainType.FullName;\n        var errMsg = string.IsNullOrEmpty(name)\n            ? $\"No default storage provider found loading grain type {grainTypeName}.\"\n            : $\"No storage provider named \\\"{name}\\\" found loading grain type {grainTypeName}.\";\n        throw new BadProviderConfigException(errMsg);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IControllable.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// A general interface for controllable components inside Orleans runtime.\n    /// </summary>\n    public interface IControllable\n    {\n        /// <summary>\n        /// A function to execute a control command.\n        /// </summary>\n        /// <param name=\"command\">A serial number of the command.</param>\n        /// <param name=\"arg\">An opaque command argument.</param>\n        /// <returns>The value returned from the command handler.</returns>\n        Task<object> ExecuteCommand(int command, object arg);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IGrainStorage.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing System.Net;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Interface to be implemented for a storage able to read and write Orleans grain state data.\n    /// </summary>\n    public interface IGrainStorage\n    {\n        /// <summary>Read data function for this storage instance.</summary>\n        /// <param name=\"stateName\">Name of the state for this grain</param>\n        /// <param name=\"grainId\">Grain ID</param>\n        /// <param name=\"grainState\">State data object to be populated for this grain.</param>\n        /// <typeparam name=\"T\">The grain state type.</typeparam>\n        /// <returns>Completion promise for the Read operation on the specified grain.</returns>\n        Task ReadStateAsync<T>(string stateName, GrainId grainId, IGrainState<T> grainState);\n\n        /// <summary>Write data function for this storage instance.</summary>\n        /// <param name=\"stateName\">Name of the state for this grain</param>\n        /// <param name=\"grainId\">Grain ID</param>\n        /// <param name=\"grainState\">State data object to be written for this grain.</param>\n        /// <typeparam name=\"T\">The grain state type.</typeparam>\n        /// <returns>Completion promise for the Write operation on the specified grain.</returns>\n        Task WriteStateAsync<T>(string stateName, GrainId grainId, IGrainState<T> grainState);\n\n        /// <summary>Delete / Clear data function for this storage instance.</summary>\n        /// <param name=\"stateName\">Name of the state for this grain</param>\n        /// <param name=\"grainId\">Grain ID</param>\n        /// <param name=\"grainState\">Copy of last-known state data object for this grain.</param>\n        /// <typeparam name=\"T\">The grain state type.</typeparam>\n        /// <returns>Completion promise for the Delete operation on the specified grain.</returns>\n        Task ClearStateAsync<T>(string stateName, GrainId grainId, IGrainState<T> grainState);\n    }\n\n    /// <summary>\n    /// Interface to be optionally implemented by storage to return richer exception details.\n    /// TODO: Remove this interface.  Move to decorator pattern for monitoring purposes. - jbragg\n    /// </summary>\n    public interface IRestExceptionDecoder\n    {\n        /// <summary>\n        /// Decode details of the exception.\n        /// </summary>\n        /// <param name=\"exception\">Exception to decode.</param>\n        /// <param name=\"httpStatusCode\">HTTP status code for the error.</param>\n        /// <param name=\"restStatus\">REST status for the error.</param>\n        /// <param name=\"getExtendedErrors\">Whether or not to extract REST error code.</param>\n        /// <returns>A value indicating whether the exception was decoded.</returns>\n        bool DecodeException(Exception exception, out HttpStatusCode httpStatusCode, out string restStatus, bool getExtendedErrors = false);\n    }\n\n    /// <summary>\n    /// Exception thrown when a storage detects an Etag inconsistency when attempting to perform a WriteStateAsync operation.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class InconsistentStateException : OrleansException\n    {\n        /// <summary>\n        /// Gets or sets a value indicating whether this exception occurred on the current activation.\n        /// </summary>\n        [Id(0)]\n        internal bool IsSourceActivation { get; set; } = true;\n\n        /// <summary>Gets the Etag value currently held in persistent storage.</summary>\n        [Id(1)]\n        public string StoredEtag { get; private set; }\n\n        /// <summary>Gets the Etag value currently help in memory, and attempting to be updated.</summary>\n        [Id(2)]\n        public string CurrentEtag { get; private set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        public InconsistentStateException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public InconsistentStateException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public InconsistentStateException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        protected InconsistentStateException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.StoredEtag = info.GetString(nameof(StoredEtag));\n            this.CurrentEtag = info.GetString(nameof(CurrentEtag));\n            this.IsSourceActivation = info.GetBoolean(nameof(this.IsSourceActivation));\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"errorMsg\">The error message.</param>\n        /// <param name=\"storedEtag\">The stored ETag.</param>\n        /// <param name=\"currentEtag\">The current ETag.</param>\n        /// <param name=\"storageException\">The inner exception.</param>\n        public InconsistentStateException(\n          string errorMsg,\n          string storedEtag,\n          string currentEtag,\n          Exception storageException) : base(errorMsg, storageException)\n        {\n            StoredEtag = storedEtag;\n            CurrentEtag = currentEtag;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"errorMsg\">The error message.</param>\n        /// <param name=\"storedEtag\">The stored ETag.</param>\n        /// <param name=\"currentEtag\">The current ETag.</param>\n        public InconsistentStateException(\n          string errorMsg,\n          string storedEtag,\n          string currentEtag)\n            : this(errorMsg, storedEtag, currentEtag, null)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"storedEtag\">The stored ETag.</param>\n        /// <param name=\"currentEtag\">The current ETag.</param>\n        /// <param name=\"storageException\">The storage exception.</param>\n        public InconsistentStateException(string storedEtag, string currentEtag, Exception storageException)\n            : this(storageException.Message, storedEtag, currentEtag, storageException)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            return string.Format(\"InconsistentStateException: {0} Expected Etag={1} Received Etag={2} {3}\",\n                Message, StoredEtag, CurrentEtag, InnerException);\n        }\n\n        /// <inheritdoc/>\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            if (info == null) throw new ArgumentNullException(nameof(info));\n\n            info.AddValue(nameof(StoredEtag), this.StoredEtag);\n            info.AddValue(nameof(CurrentEtag), this.CurrentEtag);\n            info.AddValue(nameof(this.IsSourceActivation), this.IsSourceActivation);\n            base.GetObjectData(info, context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IGrainStorageSerializer.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Common interface for grain state serializers.\n    /// </summary>\n    public interface IGrainStorageSerializer\n    {\n        /// <summary>\n        /// Serializes the object input.\n        /// </summary>\n        /// <param name=\"input\">The object to serialize.</param>\n        /// <typeparam name=\"T\">The input type.</typeparam>\n        /// <returns>The serialized input.</returns>\n        BinaryData Serialize<T>(T input);\n\n        /// <summary>\n        /// Deserializes the provided data.\n        /// </summary>\n        /// <param name=\"input\">The data to deserialize.</param>\n        /// <typeparam name=\"T\">The output type.</typeparam>\n        /// <returns>The deserialized object.</returns>\n        T Deserialize<T>(BinaryData input);\n    }\n\n    /// <summary>\n    /// Extensions for <see cref=\"IGrainStorageSerializer\"/>.\n    /// </summary>\n    public static class GrainStorageSerializerExtensions\n    {\n        /// <summary>\n        /// Deserializes the provided data.\n        /// </summary>\n        /// <param name=\"serializer\">The grain state serializer.</param>\n        /// <param name=\"input\">The data to deserialize.</param>\n        /// <typeparam name=\"T\">The output type.</typeparam>\n        /// <returns>The deserialized object.</returns>\n        public static T Deserialize<T>(this IGrainStorageSerializer serializer, ReadOnlyMemory<byte> input)\n            => serializer.Deserialize<T>(new BinaryData(input));\n    }\n\n    /// <summary>\n    /// Interface to be implemented by the storage provider options.\n    /// </summary>\n    public interface IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Gets or sets the serializer to use for this storage provider.\n        /// </summary>\n        IGrainStorageSerializer GrainStorageSerializer { get; set; }\n    }\n\n    /// <summary>\n    /// Provides default configuration for <see cref=\"IStorageProviderSerializerOptions.GrainStorageSerializer\"/>.\n    /// </summary>\n    /// <typeparam name=\"TOptions\">The options type.</typeparam>\n    public class DefaultStorageProviderSerializerOptionsConfigurator<TOptions> : IPostConfigureOptions<TOptions> where TOptions : class, IStorageProviderSerializerOptions\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultStorageProviderSerializerOptionsConfigurator{TOptions}\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        public DefaultStorageProviderSerializerOptionsConfigurator(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc/>\n        public void PostConfigure(string name, TOptions options)\n        {\n            if (options.GrainStorageSerializer == default)\n            {\n                // First, try to get a IGrainStorageSerializer that was registered with \n                // the same name as the storage provider\n                // If none is found, fallback to system wide default\n                options.GrainStorageSerializer = _serviceProvider.GetKeyedService<IGrainStorageSerializer>(name) ?? _serviceProvider.GetRequiredService<IGrainStorageSerializer>();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/ILeaseProvider.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.LeaseProviders\n{\n    /// <summary>\n    /// Acquired lease\n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public sealed class AcquiredLease\n    {\n        /// <summary>\n        /// The resource key which the lease is attached to \n        /// </summary>\n        [Id(0)]\n        public string ResourceKey { get; }\n\n        /// <summary>\n        /// Duration of the acquired lease\n        /// </summary>\n        [Id(1)]\n        public TimeSpan Duration { get; }\n\n        /// <summary>\n        /// Lease token, which will be null if acquiring or renewing the lease failed\n        /// </summary>\n        [Id(2)]\n        public string Token { get; }\n\n        /// <summary>\n        /// Caller side start time for this lease, which is when the lease is acquired or renewed\n        /// </summary>\n        [Id(3)]\n        public DateTime StartTimeUtc { get; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"resourceKey\"></param>\n        /// <param name=\"duration\"></param>\n        /// <param name=\"token\"></param>\n        /// <param name=\"startTimeUtc\"></param>\n        public AcquiredLease(string resourceKey, TimeSpan duration, string token, DateTime startTimeUtc)\n        {\n            this.ResourceKey = resourceKey;\n            this.Duration = duration;\n            this.Token = token;\n            this.StartTimeUtc = startTimeUtc;\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"resourceKey\"></param>\n        public AcquiredLease(string resourceKey)\n        {\n            this.ResourceKey = resourceKey;\n        }\n    }\n\n    /// <summary>\n    /// AcquireLeaseResult class, which demonstrates result of acquiring or renewing lease operation\n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public sealed class AcquireLeaseResult\n    {\n        /// <summary>\n        /// Acquired lease, which will be null if acquire or renew operation failed.\n        /// </summary>\n        [Id(0)]\n        public AcquiredLease AcquiredLease { get; }\n\n        /// <summary>\n        /// Response status\n        /// </summary>\n        [Id(1)]\n        public ResponseCode StatusCode { get; }\n\n        /// <summary>\n        /// If acquiring or renewing the lease failed, this is the exception which caused it. This field would be null if operation succeed.\n        /// </summary>\n        [Id(2)]\n        public Exception FailureException { get; }\n\n        public AcquireLeaseResult(AcquiredLease acquiredLease, ResponseCode statusCode, Exception failureException)\n        {\n            this.AcquiredLease = acquiredLease;\n            this.StatusCode = statusCode;\n            this.FailureException = failureException;\n        }\n    }\n\n    [GenerateSerializer]\n    public enum ResponseCode\n    {\n        /// <summary>\n        /// Operation succeed\n        /// </summary>\n        OK,\n        /// <summary>\n        /// Lease is owned by other entity\n        /// </summary>\n        LeaseNotAvailable,\n        /// <summary>\n        /// The token in the AcquiredLease is invalid, which means the lease expired\n        /// </summary>\n        InvalidToken,\n        /// <summary>\n        /// TransientFailure, which should be retriable. \n        /// </summary>\n        TransientFailure\n    }\n    \n    /// <summary>\n    /// Lease request where you can specify ResourceKey and duration of your lease. \n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public sealed class LeaseRequest\n    {\n        /// <summary>\n        /// The key of the resource where you want to apply the lease on\n        /// </summary>\n        [Id(0)]\n        public string ResourceKey { get; }\n\n        /// <summary>\n        /// Duration of the lease\n        /// </summary>\n        [Id(1)]\n        public TimeSpan Duration { get; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"resourceKey\"></param>\n        /// <param name=\"duration\"></param>\n        public LeaseRequest(string resourceKey, TimeSpan duration)\n        {\n            this.ResourceKey = resourceKey;\n            this.Duration = duration;\n        }\n    }\n\n    /// <summary>\n    /// Lease provider interface \n    /// </summary>\n    public interface ILeaseProvider\n    {\n        /// <summary>\n        /// Batch acquire leases operation\n        /// </summary>\n        /// <param name=\"category\">resource category</param>\n        /// <param name=\"leaseRequests\"></param>\n        /// <returns>Lease acquiring results array, whose order is the same with leaseRequstes</returns>\n        Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests);\n        /// <summary>\n        /// Batch renew lease operation\n        /// </summary>\n        /// <param name=\"category\">resource category</param>\n        /// <param name=\"aquiredLeases\"></param>\n        /// <returns>Lease renew results array, whose order is the same with acquiredLeases</returns>\n        Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] aquiredLeases);\n        /// <summary>\n        /// Batch release lease operation\n        /// </summary>\n        /// <param name=\"category\">resource category</param>\n        /// <param name=\"aquiredLeases\"></param>\n        /// <returns></returns>\n        Task Release(string category, AcquiredLease[] aquiredLeases);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IMemoryStorageGrain.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Grain interface for internal memory storage grain used by Orleans in-memory storage provider.\n    /// </summary>\n    public interface IMemoryStorageGrain : IGrainWithIntegerKey\n    {\n        /// <summary>Async method to cause retrieval of the specified grain state data from memory store.</summary>\n        /// <param name=\"grainStoreKey\">Store key for this grain.</param>\n        /// <returns>Value promise for the currently stored grain state for the specified grain.</returns>\n        Task<IGrainState<T>> ReadStateAsync<T>(string grainStoreKey);\n\n        /// <summary>Async method to cause update of the specified grain state data into memory store.</summary>\n        /// <param name=\"grainStoreKey\">Grain ID.</param>\n        /// <param name=\"grainState\">New state data to be stored for this grain.</param>\n        /// <returns>Completion promise with new eTag for the update operation for stored grain state for the specified grain.</returns>\n        Task<string> WriteStateAsync<T>(string grainStoreKey, IGrainState<T> grainState);\n        \n        /// <param name=\"grainStoreKey\">Store key for this grain.</param>\n        /// <param name=\"eTag\">The previous etag that was read.</param>\n        /// <returns>Completion promise for the update operation for stored grain state for the specified grain.</returns>\n        Task DeleteStateAsync<T>(string grainStoreKey, string eTag);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IProviderRuntime.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Interface to allow callbacks from providers into their assigned provider-manager.\n    /// This allows access to runtime functionality, such as logging.\n    /// </summary>\n    public interface IProviderRuntime\n    {\n        /// <summary>\n        /// Gets factory for getting references to grains.\n        /// </summary>\n        IGrainFactory GrainFactory { get; }\n\n        /// <summary>\n        /// Gets service provider for dependency injection.\n        /// </summary>\n        IServiceProvider ServiceProvider { get; }\n\n        /// <summary>\n        /// Binds an extension to an addressable object, if not already done.\n        /// </summary>\n        /// <typeparam name=\"TExtension\">The type of the extension (e.g. StreamConsumerExtension).</typeparam>\n        /// <typeparam name=\"TExtensionInterface\">The public interface type of the implementation.</typeparam>\n        /// <param name=\"newExtensionFunc\">A factory function that constructs a new extension object.</param>\n        /// <returns>A tuple, containing first the extension and second an addressable reference to the extension's interface.</returns>\n        (TExtension Extension, TExtensionInterface ExtensionReference) BindExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/IStorageProvider.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Exception thrown whenever a grain call is attempted with a bad / missing storage provider configuration settings for that grain.\n    /// </summary>\n    [Serializable, GenerateSerializer]\n    public sealed class BadProviderConfigException : OrleansException\n    {\n        public BadProviderConfigException()\n        { }\n        public BadProviderConfigException(string msg)\n            : base(msg)\n        { }\n        public BadProviderConfigException(string msg, Exception exc)\n            : base(msg, exc)\n        { }\n\n        [Obsolete]\n        private BadProviderConfigException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/ProviderInitializationException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Exception thrown whenever a provider has failed to be initialized.\n    /// </summary>\n    [Serializable, GenerateSerializer]\n    public sealed class ProviderInitializationException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderInitializationException\"/> class.\n        /// </summary>\n        public ProviderInitializationException()\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderInitializationException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public ProviderInitializationException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderInitializationException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public ProviderInitializationException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderInitializationException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private ProviderInitializationException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/ProviderStateManager.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    internal enum ProviderState\n    {\n        None,\n\n        Initialized,\n        Started,\n        Closed\n    }\n    internal class ProviderStateManager\n    {\n        public ProviderState State { get; private set; }\n        private ProviderState presetState;\n\n        public ProviderStateManager()\n        {\n            State = ProviderState.None;\n        }\n\n        public bool PresetState(ProviderState state)\n        {\n            presetState = state;\n            switch (state)\n            {\n                case ProviderState.None:\n                    throw new ProviderStateException(\"Provider state can not be set to none.\");\n\n                case ProviderState.Initialized:\n                    switch(State)\n                    {\n                        case ProviderState.None:\n                            return true;\n                    }\n                    break;\n\n                case ProviderState.Started:\n                    switch(State)\n                    {\n                        case ProviderState.None:\n                            throw new ProviderStateException(\"Trying to start a provider that hasn't been initialized.\");\n                        case ProviderState.Initialized:\n                            return true;\n                        case ProviderState.Closed:\n                            throw new ProviderStateException(\"Trying to start a provider that has been closed.\");\n                    }\n                    break;\n\n                case ProviderState.Closed:\n                    switch (State)\n                    {\n                        case ProviderState.None:\n                            throw new ProviderStateException(\"Trying to close a provider that hasn't been initialized.\");\n                        case ProviderState.Initialized:\n                        case ProviderState.Started:\n                            return true;\n                    }\n                    return true;\n            }\n\n            return false;\n        }\n\n        public void CommitState()\n        {\n            State = presetState;\n        }\n    }\n\n    [Serializable, GenerateSerializer]\n    public sealed class ProviderStateException : OrleansException\n    {\n        public ProviderStateException() : base(\"Unexpected provider state\")\n        { }\n        public ProviderStateException(string message) : base(message) { }\n\n        public ProviderStateException(string message, Exception innerException) : base(message, innerException) { }\n\n        [Obsolete]\n        private ProviderStateException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/StorageSerializer/GrainStorageSerializer.cs",
    "content": "using System;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Provides functionality for serializing and deserializing grain state, delegating to a prefered and fallback implementation of <see cref=\"IGrainStorageSerializer\"/>.\n    /// </summary>\n    public class GrainStorageSerializer : IGrainStorageSerializer\n    {\n        private readonly IGrainStorageSerializer _serializer;\n        private readonly IGrainStorageSerializer _fallbackDeserializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainStorageSerializer\"/> class.\n        /// </summary>\n        /// <param name=\"serializer\">The grain storage serializer.</param>\n        /// <param name=\"fallbackDeserializer\">The fallback grain storage serializer.</param>\n        public GrainStorageSerializer(IGrainStorageSerializer serializer, IGrainStorageSerializer fallbackDeserializer)\n        {\n            _serializer = serializer;\n            _fallbackDeserializer = fallbackDeserializer;\n        }\n\n        /// <inheritdoc/>\n        public BinaryData Serialize<T>(T input) => _serializer.Serialize(input);\n\n        /// <inheritdoc/>\n        public T Deserialize<T>(BinaryData input)\n        {\n            try\n            {\n                return _serializer.Deserialize<T>(input);\n            }\n            catch (Exception ex1)\n            {\n                try\n                {\n                    return _fallbackDeserializer.Deserialize<T>(input);\n                }\n                catch (Exception ex2)\n                {\n                    throw new AggregateException(\"Failed to deserialize input\", ex1, ex2);\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/StorageSerializer/JsonGrainStorageSerializer.cs",
    "content": "using System;\nusing Orleans.Serialization;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Grain storage serializer that uses Newtonsoft.Json\n    /// </summary>\n    public class JsonGrainStorageSerializer : IGrainStorageSerializer\n    {\n        private readonly OrleansJsonSerializer _orleansJsonSerializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JsonGrainStorageSerializer\"/> class.\n        /// </summary>\n        public JsonGrainStorageSerializer(OrleansJsonSerializer orleansJsonSerializer)\n        {\n            _orleansJsonSerializer = orleansJsonSerializer;\n        }\n\n        /// <inheritdoc/>\n        public BinaryData Serialize<T>(T value)\n        {\n            var data = _orleansJsonSerializer.Serialize(value, typeof(T));\n            return new BinaryData(data);\n        }\n\n        /// <inheritdoc/>\n        public T Deserialize<T>(BinaryData input)\n        {\n            return (T)_orleansJsonSerializer.Deserialize(typeof(T), input.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Providers/StorageSerializer/OrleansGrainStateSerializer.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Grain storage serializer that uses the Orleans <see cref=\"Serializer\"/>.\n    /// </summary>\n    public class OrleansGrainStorageSerializer : IGrainStorageSerializer\n    {\n        private readonly Serializer serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansGrainStorageSerializer\"/> class.\n        /// </summary>\n        /// <param name=\"serializer\">The serializer.</param>\n        public OrleansGrainStorageSerializer(Serializer serializer)\n        {\n            this.serializer = serializer;\n        }\n\n        /// <inheritdoc/>\n        public BinaryData Serialize<T>(T value)\n        {\n            var buffer = new ArrayBufferWriter<byte>();\n            this.serializer.Serialize(value, buffer);\n            return new BinaryData(buffer.WrittenMemory);\n        }\n\n        /// <inheritdoc/>\n        public T Deserialize<T>(BinaryData input)\n        {\n            return this.serializer.Deserialize<T>(input.ToMemory());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/README.md",
    "content": "# Microsoft Orleans Core Library\n\n## Introduction\nMicrosoft Orleans Core is the primary library used by both client and server applications. It provides the runtime components necessary for Orleans applications, including serialization, communication, and the core hosting infrastructure.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Core\n```\n\nThis package is automatically included when you reference the Orleans SDK or the Orleans client/server metapackages.\n\n## Example - Configuring a Client\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Configuration;\nusing System;\nusing System.Threading.Tasks;\n\n// Define a grain interface\nnamespace MyGrainNamespace;\n\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\n// Implement the grain interface\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"Hello! I got: {greeting}\");\n    }\n}\n\n// Create a client\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(client =>\n    {\n        client.UseLocalhostClustering();\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar grain = host.Services.GetRequiredService<IClusterClient>().GetGrain<IHelloGrain>(\"grain-id\");\nvar response = await grain.SayHello(\"Hello from client!\");\n\n// Print the result\nConsole.WriteLine($\"Response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Client Configuration](https://learn.microsoft.com/en-us/dotnet/orleans/host/client)\n- [Dependency Injection](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/dependency-injection)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Core/Runtime/AsyncEnumerableGrainExtension.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Timers;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Grain-side support for returning <see cref=\"IAsyncEnumerable{T}\"/> from grain methods.\n/// </summary>\ninternal sealed partial class AsyncEnumerableGrainExtension : IAsyncEnumerableGrainExtension, IAsyncDisposable, IDisposable\n{\n    private static readonly DiagnosticListener DiagnosticListener = new(\"Orleans.Runtime.AsyncEnumerableGrainExtension\");\n    private readonly Dictionary<Guid, EnumeratorState> _enumerators = [];\n    private readonly ILogger<AsyncEnumerableGrainExtension> _logger;\n    private readonly MessagingOptions _messagingOptions;\n\n    // Internal for testing\n    internal IGrainTimer Timer { get; }\n    internal IGrainContext GrainContext { get; }\n\n    /// <summary>\n    /// Initializes a new <see cref=\"AsyncEnumerableGrainExtension\"/> instance.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain which this extension is attached to.</param>\n    public AsyncEnumerableGrainExtension(\n        IGrainContext grainContext,\n        IOptions<MessagingOptions> messagingOptions,\n        ILogger<AsyncEnumerableGrainExtension> logger)\n    {\n        _logger = logger;\n        GrainContext = grainContext;\n\n        _messagingOptions = messagingOptions.Value;\n        var registry = GrainContext.GetComponent<ITimerRegistry>();\n        var cleanupPeriod = messagingOptions.Value.ResponseTimeout;\n        Timer = registry.RegisterGrainTimer(\n            GrainContext,\n            static async (state, cancellationToken) => await state.RemoveExpiredAsync(cancellationToken),\n            this,\n            new()\n            {\n                DueTime = cleanupPeriod,\n                Period = cleanupPeriod,\n                Interleave = true,\n                KeepAlive = false\n            });\n        OnAsyncEnumeratorGrainExtensionCreated(this);\n    }\n\n    /// <inheritdoc/>\n    public ValueTask DisposeAsync(Guid requestId) => RemoveEnumeratorAsync(requestId);\n\n    private async ValueTask RemoveExpiredAsync(CancellationToken cancellationToken)\n    {\n        List<Guid> toRemove = default;\n        foreach (var (requestId, state) in _enumerators)\n        {\n            if (MarkAndCheck(requestId))\n            {\n                toRemove ??= [];\n                toRemove.Add(requestId);\n            }\n\n            bool MarkAndCheck(Guid requestId)\n            {\n                ref var state = ref CollectionsMarshal.GetValueRefOrNullRef(_enumerators, requestId);\n                if (Unsafe.IsNullRef(ref state))\n                {\n                    return false;\n                }\n\n                // Returns true if no flags were set.\n                return state.ClearSeen();\n            }\n        }\n\n        List<Task> tasks = default;\n        if (toRemove is not null)\n        {\n            foreach (var requestId in toRemove)\n            {\n                var removeTask = RemoveEnumeratorAsync(requestId);\n                if (!removeTask.IsCompletedSuccessfully)\n                {\n                    tasks ??= [];\n                    tasks.Add(removeTask.AsTask());\n                }\n            }\n        }\n\n        if (tasks is { Count: > 0 })\n        {\n            await Task.WhenAll(tasks).WaitAsync(cancellationToken);\n        }\n\n        OnEnumeratorCleanupCompleted(this);\n    }\n\n    /// <inheritdoc/>\n    public ValueTask<(EnumerationResult Status, object Value)> StartEnumeration<T>(Guid requestId, [Immutable] IAsyncEnumerableRequest<T> request, CancellationToken cancellationToken)\n    {\n        ref var entry = ref CollectionsMarshal.GetValueRefOrAddDefault(_enumerators, requestId, out bool exists);\n        if (exists)\n        {\n            return ThrowAlreadyExists();\n        }\n\n        request.SetTarget(GrainContext);\n        var cts = CancellationTokenSource.CreateLinkedTokenSource(request.GetCancellationToken());\n        var enumerable = request.InvokeImplementation();\n        var enumerator = enumerable.GetAsyncEnumerator(cts.Token);\n        entry.Enumerator = enumerator;\n        entry.MaxBatchSize = request.MaxBatchSize;\n        entry.CancellationTokenSource = cts;\n        Debug.Assert(entry.MaxBatchSize > 0, \"Max batch size must be positive.\");\n        return MoveNextCore(ref entry, requestId, enumerator, cancellationToken);\n\n        static ValueTask<(EnumerationResult Status, object Value)> ThrowAlreadyExists() => ValueTask.FromException<(EnumerationResult Status, object Value)>(new InvalidOperationException(\"An enumerator with the same id already exists.\"));\n    }\n\n    /// <inheritdoc/>\n    public ValueTask<(EnumerationResult Status, object Value)> MoveNext<T>(Guid requestId, CancellationToken cancellationToken)\n    {\n        ref var entry = ref CollectionsMarshal.GetValueRefOrNullRef(_enumerators, requestId);\n        if (Unsafe.IsNullRef(ref entry))\n        {\n            return new((EnumerationResult.MissingEnumeratorError, default));\n        }\n\n        if (entry.Enumerator is not IAsyncEnumerator<T> typedEnumerator)\n        {\n            throw new InvalidCastException(\"Attempted to access an enumerator of the wrong type.\");\n        }\n\n        return MoveNextCore(ref entry, requestId, typedEnumerator, cancellationToken);\n    }\n\n    private ValueTask<(EnumerationResult Status, object Value)> MoveNextCore<T>(\n        ref EnumeratorState entry,\n        Guid requestId,\n        IAsyncEnumerator<T> typedEnumerator,\n        CancellationToken cancellationToken)\n    {\n        Debug.Assert(entry.MaxBatchSize > 0, \"Max batch size must be positive.\");\n        entry.SetSeen();\n\n        try\n        {\n            var currentBatchSize = 0;\n            if (entry.MoveNextTask is null)\n            {\n                ValueTask<bool> moveNextValueTask;\n                object result = null;\n                do\n                {\n                    // Check if the enumerator has a result ready synchronously.\n                    moveNextValueTask = typedEnumerator.MoveNextAsync();\n                    if (moveNextValueTask.IsCompletedSuccessfully)\n                    {\n                        var hasValue = moveNextValueTask.Result;\n                        if (hasValue)\n                        {\n                            // Account for the just-emitted element.\n                            ++currentBatchSize;\n                            var value = typedEnumerator.Current;\n                            if (currentBatchSize == 1)\n                            {\n                                result = value;\n                            }\n                            else if (currentBatchSize == 2)\n                            {\n                                // Grow from a single element to a list.\n                                result = new List<T> { (T)result, value };\n                            }\n                            else\n                            {\n                                ((List<T>)result).Add(value);\n                            }\n                        }\n                        else\n                        {\n                            // Completed successfully, possibly with some final elements.\n                            if (currentBatchSize == 0)\n                            {\n                                return OnTerminateAsync(requestId, EnumerationResult.Completed, default);\n                            }\n                            else if (currentBatchSize == 1)\n                            {\n                                return OnTerminateAsync(requestId, EnumerationResult.CompletedWithElement, result);\n                            }\n\n                            return OnTerminateAsync(requestId, EnumerationResult.CompletedWithBatch, result);\n                        }\n                    }\n                    else\n                    {\n                        // The enumerator did not complete synchronously, so we need to await the result for subsequent elements.\n                        entry.MoveNextTask = moveNextValueTask.AsTask();\n                        break;\n                    }\n                } while (currentBatchSize < entry.MaxBatchSize);\n\n                // If there are elements, return them now instead of waiting for the pending operation to complete.\n                if (currentBatchSize == 1)\n                {\n                    return new((EnumerationResult.Element, result));\n                }\n                else if (currentBatchSize > 1)\n                {\n                    return new((EnumerationResult.Batch, result));\n                }\n\n                // There are no elements, so wait for the pending operation to complete.\n            }\n\n            // Prevent the enumerator from being collected while we are enumerating it.\n            entry.SetBusy();\n            return AwaitMoveNextAsync(requestId, typedEnumerator, entry.MoveNextTask, cancellationToken);\n        }\n        catch (Exception exception)\n        {\n            return OnTerminateAsync(requestId, EnumerationResult.Error, exception);\n        }\n    }\n\n    private async ValueTask<(EnumerationResult Status, object Value)> AwaitMoveNextAsync<T>(\n        Guid requestId,\n        IAsyncEnumerator<T> typedEnumerator,\n        Task<bool> moveNextTask,\n        CancellationToken cancellationToken)\n    {\n        try\n        {\n            // Wait for either the MoveNextAsync task to complete or the polling timeout to elapse.\n            using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n            var longPollingTimeout = _messagingOptions.ConfiguredResponseTimeout / 2;\n            cts.CancelAfter(longPollingTimeout);\n            await moveNextTask.WaitAsync(cts.Token).SuppressThrowing();\n\n            // Update the enumerator state to indicate that we are not currently waiting for MoveNextAsync to complete.\n            // If the MoveNextAsync task completed then clear that now, too.\n            UpdateEnumeratorState(requestId, clearMoveNextTask: moveNextTask.IsCompleted);\n            void UpdateEnumeratorState(Guid requestId, bool clearMoveNextTask)\n            {\n                ref var state = ref CollectionsMarshal.GetValueRefOrNullRef(_enumerators, requestId);\n                if (Unsafe.IsNullRef(ref state))\n                {\n                    return;\n                }\n\n                state.ClearBusy();\n                if (clearMoveNextTask)\n                {\n                    state.MoveNextTask = null;\n                }\n            }\n\n            if (moveNextTask.IsCompletedSuccessfully)\n            {\n                var hasValue = moveNextTask.GetAwaiter().GetResult();\n   \n                if (hasValue)\n                {\n                    return (EnumerationResult.Element, typedEnumerator.Current);\n                }\n                else\n                {\n                    await RemoveEnumeratorAsync(requestId);\n                    return (EnumerationResult.Completed, default);\n                }\n            }\n            else if (moveNextTask.IsCanceled || cancellationToken.IsCancellationRequested)\n            {\n                await RemoveEnumeratorAsync(requestId);\n                return (EnumerationResult.Canceled, default);\n            }\n            else if (moveNextTask.Exception is { } moveNextException)\n            {\n                // Completed, but not successfully.\n                var exception = moveNextException.InnerExceptions.Count == 1 ? moveNextException.InnerException : moveNextException;\n                await RemoveEnumeratorAsync(requestId);\n                return (EnumerationResult.Error, exception);\n            }\n\n            return (EnumerationResult.Heartbeat, default);\n        }\n        catch (Exception exception)\n        {\n            await RemoveEnumeratorAsync(requestId);\n            return (EnumerationResult.Error, exception);\n        }\n    }\n\n    private async ValueTask RemoveEnumeratorAsync(Guid requestId)\n    {\n        if (_enumerators.Remove(requestId, out var state))\n        {\n            await DisposeEnumeratorAsync(state);\n        }\n    }\n\n    private async ValueTask<(EnumerationResult Status, object Value)> OnTerminateAsync(Guid requestId, EnumerationResult status, object value)\n    {\n        await RemoveEnumeratorAsync(requestId);\n        return (status, value);\n    }\n    \n    /// <inheritdoc/>\n    public async ValueTask DisposeAsync()\n    {\n        if (_enumerators.Count > 0)\n        {\n            var enumerators = new List<EnumeratorState>(_enumerators.Values);\n            _enumerators.Clear();\n\n            foreach (var enumerator in enumerators)\n            {\n                await DisposeEnumeratorAsync(enumerator);\n            }\n        }\n\n        Timer.Dispose();\n    }\n\n    private async ValueTask DisposeEnumeratorAsync(EnumeratorState enumerator)\n    {\n        try\n        {\n            enumerator.CancellationTokenSource.Cancel();\n        }\n        catch (Exception exception)\n        {\n            LogWarningErrorCancellingEnumerator(exception);\n        }\n\n        try\n        {\n            using var cts = new CancellationTokenSource(_messagingOptions.ResponseTimeout);\n            if (enumerator.MoveNextTask is { } task)\n            {\n                await task.WaitAsync(cts.Token).SuppressThrowing();\n            }\n\n            if (enumerator.MoveNextTask is null or { IsCompleted: true } && enumerator.Enumerator is { } value)\n            {\n                await value.DisposeAsync().AsTask().WaitAsync(cts.Token).SuppressThrowing();\n            }\n        }\n        catch (Exception exception)\n        {\n            LogWarningErrorDisposingEnumerator(exception);\n        }\n    }\n\n    /// <inheritdoc/>\n    public void Dispose()\n    {\n        Timer.Dispose();\n    }\n\n    private static void OnAsyncEnumeratorGrainExtensionCreated(AsyncEnumerableGrainExtension extension)\n    {\n        if (DiagnosticListener.IsEnabled())\n        {\n            DiagnosticListener.Write(nameof(OnAsyncEnumeratorGrainExtensionCreated), extension);\n        }\n    }\n\n    private static void OnEnumeratorCleanupCompleted(AsyncEnumerableGrainExtension extension)\n    {\n        if (DiagnosticListener.IsEnabled())\n        {\n            DiagnosticListener.Write(nameof(OnEnumeratorCleanupCompleted), extension);\n        }\n    }\n\n    private struct EnumeratorState\n    {\n        private const int SeenFlag = 0x01;\n        private const int BusyFlag = 0x10;\n        private int _flags;\n        public IAsyncDisposable Enumerator;\n        public Task<bool> MoveNextTask;\n        public int MaxBatchSize;\n        internal CancellationTokenSource CancellationTokenSource;\n        public void SetSeen() => _flags |= SeenFlag;\n        public void SetBusy() => _flags |= BusyFlag | SeenFlag;\n        public void ClearBusy() => _flags = SeenFlag; // Clear the 'Busy' flag, but set the 'Seen' flag.\n        public bool ClearSeen()\n        {\n            // Clear the 'Seen' flag and check if any flags were set previously.\n            var isExpired = _flags == 0;\n            _flags &= ~SeenFlag;\n            return isExpired;\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error cancelling enumerator.\"\n    )]\n    private partial void LogWarningErrorCancellingEnumerator(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error disposing enumerator.\"\n    )]\n    private partial void LogWarningErrorDisposingEnumerator(Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/CallbackData.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    internal sealed partial class CallbackData\n    {\n        private readonly SharedCallbackData shared;\n        private readonly IResponseCompletionSource context;\n        private readonly ApplicationRequestInstruments _applicationRequestInstruments;\n        private int completed;\n        private StatusResponse? lastKnownStatus;\n        private ValueStopwatch stopwatch;\n        private CancellationTokenRegistration _cancellationTokenRegistration;\n\n        public CallbackData(\n            SharedCallbackData shared,\n            IResponseCompletionSource ctx,\n            Message msg,\n            ApplicationRequestInstruments applicationRequestInstruments)\n        {\n            this.shared = shared;\n            this.context = ctx;\n            this.Message = msg;\n            _applicationRequestInstruments = applicationRequestInstruments;\n            this.stopwatch = ValueStopwatch.StartNew();\n        }\n\n        public Message Message { get; } // might hold metadata used by response pipeline\n\n        public bool IsCompleted => this.completed == 1;\n\n        public void SubscribeForCancellation(CancellationToken cancellationToken)\n        {\n            if (!cancellationToken.CanBeCanceled)\n            {\n                return;\n            }\n\n            cancellationToken.ThrowIfCancellationRequested();\n            _cancellationTokenRegistration = cancellationToken.UnsafeRegister(static arg =>\n            {\n                var callbackData = (CallbackData)arg!;\n                callbackData.OnCancellation();\n            }, this);\n        }\n\n        private void SignalCancellation()\n        {\n            // Only cancel requests which honor cancellation token.\n            // Not all targets support IGrainCallCancellationExtension, so sending a cancellation in those cases could result in an error.\n            // There are opportunities to cancel requests at the infrastructure layer which this will not exploit if the target method does not support cancellation.\n            if (Message.BodyObject is IInvokable invokable && invokable.IsCancellable)\n            {\n                shared.CancellationManager?.SignalCancellation(Message.TargetSilo, Message.TargetGrain, Message.SendingGrain, Message.Id);\n            }\n        }\n\n        public void OnStatusUpdate(StatusResponse status)\n        {\n            this.lastKnownStatus = status;\n        }\n\n        public bool IsExpired(long currentTimestamp)\n        {\n            var duration = currentTimestamp - this.stopwatch.GetRawTimestamp();\n            return duration > GetResponseTimeoutStopwatchTicks();\n        }\n\n        private long GetResponseTimeoutStopwatchTicks()\n        {\n            var defaultResponseTimeout = (Message.BodyObject as IInvokable)?.GetDefaultResponseTimeout();\n            if (defaultResponseTimeout.HasValue)\n            {\n                return (long)(defaultResponseTimeout.Value.TotalSeconds * Stopwatch.Frequency);\n            }\n\n            return shared.ResponseTimeoutStopwatchTicks;\n        }\n\n        private TimeSpan GetResponseTimeout() => (Message.BodyObject as IInvokable)?.GetDefaultResponseTimeout() ?? shared.ResponseTimeout;\n\n        private void OnCancellation()\n        {\n            // If waiting for acknowledgement is enabled, simply signal to the remote grain that cancellation\n            // is requested and return.\n            if (shared.WaitForCancellationAcknowledgement)\n            {\n                SignalCancellation();\n                return;\n            }\n\n            // Otherwise, cancel the request immediately, without waiting for the callee to acknowledge the\n            // cancellation request. The callee will still be signaled.\n            if (Interlocked.CompareExchange(ref completed, 1, 0) != 0)\n            {\n                return;\n            }\n\n            stopwatch.Stop();\n            SignalCancellation();\n            shared.Unregister(Message);\n            _applicationRequestInstruments.OnAppRequestsEnd((long)stopwatch.Elapsed.TotalMilliseconds);\n            _applicationRequestInstruments.OnAppRequestsTimedOut();\n            OrleansCallBackDataEvent.Log.OnCanceled(Message);\n            context.Complete(Response.FromException(new OperationCanceledException(_cancellationTokenRegistration.Token)));\n            _cancellationTokenRegistration.Dispose();\n        }\n\n        public void OnTimeout()\n        {\n            if (Interlocked.CompareExchange(ref completed, 1, 0) != 0)\n            {\n                return;\n            }\n\n            this.stopwatch.Stop();\n            if (shared.CancelRequestOnTimeout)\n            {\n                SignalCancellation();\n            }\n\n            this.shared.Unregister(this.Message);\n            _cancellationTokenRegistration.Dispose();\n            _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds);\n            _applicationRequestInstruments.OnAppRequestsTimedOut();\n\n            OrleansCallBackDataEvent.Log.OnTimeout(this.Message);\n\n            var msg = this.Message; // Local working copy\n\n            var statusMessage = lastKnownStatus is StatusResponse status ? $\"Last known status is {status}. \" : string.Empty;\n            var timeout = GetResponseTimeout();\n            LogTimeout(this.shared.Logger, timeout, msg, statusMessage);\n\n            var exception = new TimeoutException($\"Response did not arrive on time in {timeout} for message: {msg}. {statusMessage}\");\n            context.Complete(Response.FromException(exception));\n        }\n\n        public void OnTargetSiloFail()\n        {\n            if (Interlocked.CompareExchange(ref this.completed, 1, 0) != 0)\n            {\n                return;\n            }\n\n            this.stopwatch.Stop();\n            this.shared.Unregister(this.Message);\n            _cancellationTokenRegistration.Dispose();\n            _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds);\n\n            OrleansCallBackDataEvent.Log.OnTargetSiloFail(this.Message);\n            var msg = this.Message;\n            var statusMessage = lastKnownStatus is StatusResponse status ? $\"Last known status is {status}. \" : string.Empty;\n            LogTargetSiloFail(this.shared.Logger, msg, statusMessage, Constants.TroubleshootingHelpLink);\n            var exception = new SiloUnavailableException($\"The target silo became unavailable for message: {msg}. {statusMessage}See {Constants.TroubleshootingHelpLink} for troubleshooting help.\");\n            this.context.Complete(Response.FromException(exception));\n        }\n\n        public void DoCallback(Message response)\n        {\n            if (Interlocked.CompareExchange(ref this.completed, 1, 0) != 0)\n            {\n                return;\n            }\n\n            OrleansCallBackDataEvent.Log.DoCallback(this.Message);\n\n            this.stopwatch.Stop();\n            _cancellationTokenRegistration.Dispose();\n            _applicationRequestInstruments.OnAppRequestsEnd((long)this.stopwatch.Elapsed.TotalMilliseconds);\n\n            // do callback outside the CallbackData lock. Just not a good practice to hold a lock for this unrelated operation.\n            ResponseCallback(response, this.context);\n        }\n\n        private static void ResponseCallback(Message message, IResponseCompletionSource context)\n        {\n            try\n            {\n                var body = message.BodyObject;\n                if (body is Response response)\n                {\n                    context.Complete(response);\n                }\n                else\n                {\n                    HandleRejectionResponse(context, body as RejectionResponse);\n                }\n            }\n            catch (Exception exc)\n            {\n                // catch the exception and break the promise with it.\n                context.Complete(Response.FromException(exc));\n            }\n\n            static void HandleRejectionResponse(IResponseCompletionSource context, RejectionResponse? rejection)\n            {\n                Exception exception;\n                if (rejection?.RejectionType is Message.RejectionTypes.GatewayTooBusy)\n                {\n                    exception = new GatewayTooBusyException();\n                }\n                else\n                {\n                    exception = rejection?.Exception ?? new OrleansMessageRejectionException(rejection?.RejectionInfo ?? \"Unable to send request - no rejection info available\");\n                }\n\n                context.Complete(Response.FromException(exception));\n            }\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100157,\n            Level = LogLevel.Warning,\n            Message = \"Response did not arrive on time in '{Timeout}' for message: '{Message}'. {StatusMessage}About to break its promise.\"\n        )]\n        private static partial void LogTimeout(ILogger logger, TimeSpan timeout, Message message, string statusMessage);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100157,\n            Level = LogLevel.Warning,\n            Message = \"The target silo became unavailable for message: '{Message}'. {StatusMessage}See {TroubleshootingHelpLink} for troubleshooting help. About to break its promise.\"\n        )]\n        private static partial void LogTargetSiloFail(ILogger logger, Message message, string statusMessage, string troubleshootingHelpLink);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/ClientGrainContext.cs",
    "content": "#nullable enable\nusing System.Collections.Concurrent;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans\n{\n    internal sealed class ClientGrainContext : IGrainContext, IGrainExtensionBinder, IGrainContextAccessor\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly ConcurrentDictionary<Type, (object Implementation, IAddressable Reference)> _extensions = new();\n        private readonly ConcurrentDictionary<Type, object> _components = new();\n        private readonly OutsideRuntimeClient _runtimeClient;\n        private GrainReference? _grainReference;\n\n        public ClientGrainContext(OutsideRuntimeClient runtimeClient)\n        {\n            _runtimeClient = runtimeClient;\n        }\n\n        public GrainReference GrainReference => _grainReference ??= (GrainReference)_runtimeClient.InternalGrainFactory.GetGrain(this.GrainId);\n\n        public GrainId GrainId => _runtimeClient.CurrentActivationAddress.GrainId;\n\n        public object? GrainInstance => null;\n\n        public ActivationId ActivationId => _runtimeClient.CurrentActivationAddress.ActivationId;\n\n        public GrainAddress Address => _runtimeClient.CurrentActivationAddress;\n\n        public IServiceProvider ActivationServices => _runtimeClient.ServiceProvider;\n\n        public IGrainLifecycle ObservableLifecycle => throw new NotSupportedException();\n\n        IGrainContext IGrainContextAccessor.GrainContext => this;\n\n        public IWorkItemScheduler Scheduler => throw new NotSupportedException();\n\n        public bool Equals(IGrainContext? other) => ReferenceEquals(this, other);\n\n        public object? GetComponent(Type componentType)\n        {\n            if (componentType.IsAssignableFrom(GetType())) return this;\n            if (_components.TryGetValue(componentType, out var result))\n            {\n                return result;\n            }\n            else if (componentType == typeof(PlacementStrategy))\n            {\n                return ClientObserversPlacement.Instance;\n            }\n\n            lock (_lockObj)\n            {\n                if (ActivationServices.GetService(componentType) is { } activatedComponent)\n                {\n                    return _components.GetOrAdd(componentType, activatedComponent);\n                }\n            }\n\n            return default;\n        }\n\n        public object? GetTarget() => this;\n\n        public void SetComponent<TComponent>(TComponent? instance) where TComponent : class\n        {\n            if (this is TComponent)\n            {\n                throw new ArgumentException(\"Cannot override a component which is implemented by the client context\");\n            }\n\n            lock (_lockObj)\n            {\n                if (instance == null)\n                {\n                    _components.Remove(typeof(TComponent), out _);\n                    return;\n                }\n\n                _components[typeof(TComponent)] = instance;\n            }\n        }\n\n        public (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            (TExtension, TExtensionInterface) result;\n            if (this.TryGetExtension(out result))\n            {\n                return result;\n            }\n\n            lock (_lockObj)\n            {\n                if (this.TryGetExtension(out result))\n                {\n                    return result;\n                }\n\n                var implementation = newExtensionFunc();\n                var reference = _runtimeClient.InternalGrainFactory.CreateObjectReference<TExtensionInterface>(implementation);\n                _extensions[typeof(TExtensionInterface)] = (implementation, reference);\n                result = (implementation, reference);\n                return result;\n            }\n        }\n\n        private bool TryGetExtension<TExtension, TExtensionInterface>(out (TExtension, TExtensionInterface) result)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (_extensions.TryGetValue(typeof(TExtensionInterface), out var existing))\n            {\n                if (existing.Implementation is TExtension typedResult)\n                {\n                    result = (typedResult, existing.Reference.AsReference<TExtensionInterface>());\n                    return true;\n                }\n\n                throw new InvalidCastException($\"Cannot cast existing extension of type {existing.Implementation} to target type {typeof(TExtension)}\");\n            }\n\n            result = default;\n            return false;\n        }\n\n        private bool TryGetExtension<TExtensionInterface>([NotNullWhen(true)] out TExtensionInterface? result)\n            where TExtensionInterface : IGrainExtension\n        {\n            if (_extensions.TryGetValue(typeof(TExtensionInterface), out var existing))\n            {\n                result = (TExtensionInterface)existing.Implementation;\n                return true;\n            }\n\n            result = default;\n            return false;\n        }\n\n        public TExtensionInterface GetExtension<TExtensionInterface>()\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (this.TryGetExtension<TExtensionInterface>(out var result))\n            {\n                return result;\n            }\n\n            lock (_lockObj)\n            {\n                if (this.TryGetExtension(out result))\n                {\n                    return result;\n                }\n\n                var implementation = this.ActivationServices.GetKeyedService<IGrainExtension>(typeof(TExtensionInterface));\n                if (implementation is null)\n                {\n                    throw new GrainExtensionNotInstalledException($\"No extension of type {typeof(TExtensionInterface)} is installed on this instance and no implementations are registered for automated install\");\n                }\n\n                var reference = this.GrainReference.Cast<TExtensionInterface>();\n                _extensions[typeof(TExtensionInterface)] = (implementation, reference);\n                result = (TExtensionInterface)implementation;\n                return result;\n            }\n        }\n\n        public void ReceiveMessage(object message) => throw new NotSupportedException();\n\n        public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }\n        public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }\n\n        public void Rehydrate(IRehydrationContext context)\n        {\n            // Migration is not supported, but we need to dispose of the context if it's provided\n            (context as IDisposable)?.Dispose();\n        }\n\n        public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n        {\n            // Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.\n        }\n\n        public Task Deactivated => Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/ClientLocalActivationStatusChecker.cs",
    "content": "#nullable enable\nnamespace Orleans.Runtime;\n\ninternal sealed class ClientLocalActivationStatusChecker : ILocalActivationStatusChecker\n{\n    public bool IsLocallyActivated(GrainId grainId) => false;\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/ClusterConnectionStatusObserverAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime;\n\ninternal sealed partial class ClusterConnectionStatusObserverAdaptor(\n    IEnumerable<GatewayCountChangedHandler> gatewayCountChangedHandlers,\n    IEnumerable<ConnectionToClusterLostHandler> connectionLostHandlers,\n    ILogger<ClusterClient> logger) : IClusterConnectionStatusObserver\n{\n    private readonly ImmutableArray<GatewayCountChangedHandler> _gatewayCountChangedHandlers = gatewayCountChangedHandlers.ToImmutableArray();\n    private readonly ImmutableArray<ConnectionToClusterLostHandler> _connectionLostHandler = connectionLostHandlers.ToImmutableArray();\n\n    public void NotifyClusterConnectionLost()\n    {\n        foreach (var handler in _connectionLostHandler)\n        {\n            try\n            {\n                handler(null, EventArgs.Empty);\n            }\n            catch (Exception ex)\n            {\n                LogErrorSendingClusterConnectionLostNotification(logger, ex);\n            }\n        }\n    }\n\n    public void NotifyGatewayCountChanged(int currentNumberOfGateways, int previousNumberOfGateways, bool connectionRecovered)\n    {\n        var args = new GatewayCountChangedEventArgs(currentNumberOfGateways, previousNumberOfGateways);\n        foreach (var handler in _gatewayCountChangedHandlers)\n        {\n            try\n            {\n                handler(null, args);\n            }\n            catch (Exception ex)\n            {\n                LogErrorSendingGatewayCountChangedNotification(logger, ex);\n            }\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error sending cluster connection lost notification.\"\n    )]\n    private static partial void LogErrorSendingClusterConnectionLostNotification(ILogger logger, Exception ex);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error sending gateway count changed notification.\"\n    )]\n    private static partial void LogErrorSendingGatewayCountChangedNotification(ILogger logger, Exception ex);\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/Constants.cs",
    "content": "using System;\nusing System.Collections.Frozen;\nusing System.Collections.Generic;\n\nnamespace Orleans.Runtime\n{\n    internal static class Constants\n    {\n        public const string TroubleshootingHelpLink = \"https://aka.ms/orleans-troubleshooting\";\n\n        public static readonly GrainType DirectoryServiceType = SystemTargetGrainId.CreateGrainType(\"dir.mem\");\n        public static readonly GrainType DirectoryCacheValidatorType = SystemTargetGrainId.CreateGrainType(\"dir.cache-validator\");\n        public static readonly GrainType ClientDirectoryType = SystemTargetGrainId.CreateGrainType(\"dir.client\");\n        public static readonly GrainType SiloControlType = SystemTargetGrainId.CreateGrainType(\"silo-control\");\n        public static readonly GrainType SiloMetadataType = SystemTargetGrainId.CreateGrainType(\"silo-metadata\");\n        public static readonly GrainType CatalogType = SystemTargetGrainId.CreateGrainType(\"catalog\");\n        public static readonly GrainType MembershipServiceType = SystemTargetGrainId.CreateGrainType(\"clustering\");\n        public static readonly GrainType SystemMembershipTableType = SystemTargetGrainId.CreateGrainType(\"clustering.dev\");\n        public static readonly GrainType DeploymentLoadPublisherSystemTargetType = SystemTargetGrainId.CreateGrainType(\"load-publisher\");\n        public static readonly GrainType TestHooksSystemTargetType = SystemTargetGrainId.CreateGrainType(\"test.hooks\");\n        public static readonly GrainType TransactionAgentSystemTargetType = SystemTargetGrainId.CreateGrainType(\"txn.agent\");\n        public static readonly GrainType StreamProviderManagerAgentSystemTargetType = SystemTargetGrainId.CreateGrainType(\"stream.provider-manager\");\n        public static readonly GrainType StreamPullingAgentManagerType = SystemTargetGrainId.CreateGrainType(\"stream.agent-mgr\");\n        public static readonly GrainType StreamPullingAgentType = SystemTargetGrainId.CreateGrainType(\"stream.agent\");\n        public static readonly GrainType ManifestProviderType = SystemTargetGrainId.CreateGrainType(\"manifest\");\n        public static readonly GrainType ActivationMigratorType = SystemTargetGrainId.CreateGrainType(\"migrator\");\n        public static readonly GrainType CancellationManagerType = SystemTargetGrainId.CreateGrainType(\"canceler\");\n        public static readonly GrainType ActivationRepartitionerType = SystemTargetGrainId.CreateGrainType(\"repartitioner\");\n        public static readonly GrainType ActivationRebalancerMonitorType = SystemTargetGrainId.CreateGrainType(\"rebalancer-monitor\");\n        public static readonly GrainType GrainDirectoryPartitionType = SystemTargetGrainId.CreateGrainType(\"dir.grain.part\");\n        public static readonly GrainType GrainDirectoryType = SystemTargetGrainId.CreateGrainType(\"dir.grain\");\n\n        public static readonly GrainId SiloDirectConnectionId = GrainId.Create(\n            GrainType.Create(GrainTypePrefix.SystemPrefix + \"silo\"),\n            IdSpan.Create(\"01111111-1111-1111-1111-111111111111\"));\n\n        public static readonly TimeSpan DEFAULT_CLIENT_DROP_TIMEOUT = TimeSpan.FromMinutes(1);\n\n        private static readonly FrozenDictionary<GrainType, string> SingletonSystemTargetNames = new Dictionary<GrainType, string>\n        {\n            {DirectoryServiceType, \"DirectoryService\"},\n            {DirectoryCacheValidatorType, \"DirectoryCacheValidator\"},\n            {SiloControlType, \"SiloControl\"},\n            {SiloMetadataType, \"SiloMetadata\"},\n            {ClientDirectoryType, \"ClientDirectory\"},\n            {CatalogType,\"Catalog\"},\n            {MembershipServiceType,\"MembershipService\"},\n            {DeploymentLoadPublisherSystemTargetType, \"DeploymentLoadPublisherSystemTarget\"},\n            {StreamProviderManagerAgentSystemTargetType,\"StreamProviderManagerAgent\"},\n            {TestHooksSystemTargetType,\"TestHooksSystemTargetType\"},\n            {TransactionAgentSystemTargetType,\"TransactionAgentSystemTarget\"},\n            {SystemMembershipTableType,\"SystemMembershipTable\"},\n            {StreamPullingAgentManagerType, \"PullingAgentsManagerSystemTarget\"},\n            {StreamPullingAgentType, \"PullingAgentSystemTarget\"},\n            {ManifestProviderType, \"ManifestProvider\"},\n            {ActivationMigratorType, \"ActivationMigrator\"},\n            {ActivationRepartitionerType, \"ActivationRepartitioner\"},\n            {ActivationRebalancerMonitorType, \"ActivationRebalancerMonitor\"},\n            {GrainDirectoryType, \"GrainDirectory\"},\n        }.ToFrozenDictionary();\n\n        public static string SystemTargetName(GrainType id) => SingletonSystemTargetNames.TryGetValue(id, out var name) ? name : id.ToString();\n        public static bool IsSingletonSystemTarget(GrainType id) => SingletonSystemTargetNames.ContainsKey(id);\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/GrainCancellationTokenRuntime.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Internal;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Runtime\n{\n    internal class GrainCancellationTokenRuntime : IGrainCancellationTokenRuntime\n    {\n        private const int MaxNumCancelErrorTries = 30;\n        private readonly TimeSpan _cancelCallMaxWaitTime = TimeSpan.FromSeconds(300);\n        private readonly IBackoffProvider _cancelCallBackoffProvider = new FixedBackoff(TimeSpan.FromSeconds(1));\n        private readonly Func<Exception, int, bool> _cancelCallRetryExceptionFilter =\n            (exception, i) => exception is GrainExtensionNotInstalledException;\n\n        public Task Cancel(Guid id, CancellationTokenSource tokenSource, ConcurrentDictionary<GrainId, GrainReference> grainReferences)\n        {\n            if (tokenSource.IsCancellationRequested)\n            {\n                // This token has already been canceled.\n                return Task.CompletedTask;\n            }\n\n            // propagate the exception from the _cancellationTokenSource.Cancel back to the caller\n            // but also cancel _targetGrainReferences.\n            Task localTask = null;\n            try\n            {\n                // Cancel the token now, preventing recursion.\n                tokenSource.Cancel();\n            }\n            catch (Exception exception)\n            {\n                localTask = Task.FromException(exception);\n            }\n\n            List<Task> tasks = null;\n            foreach (var reference in grainReferences)\n            {\n                if (tasks is null)\n                {\n                    tasks = new();\n                    if (localTask != null) tasks.Add(localTask);\n                }\n                tasks.Add(CancelTokenWithRetries(id, grainReferences, reference.Key, reference.Value.AsReference<ICancellationSourcesExtension>()));\n            }\n\n            return tasks is null ? localTask ?? Task.CompletedTask : Task.WhenAll(tasks);\n        }\n\n         private async Task CancelTokenWithRetries(\n             Guid id,\n             ConcurrentDictionary<GrainId, GrainReference> grainReferences,\n             GrainId key,\n             ICancellationSourcesExtension tokenExtension)\n        {\n            await AsyncExecutorWithRetries.ExecuteWithRetries(\n                i => tokenExtension.CancelRemoteToken(id),\n                MaxNumCancelErrorTries,\n                _cancelCallRetryExceptionFilter,\n                _cancelCallMaxWaitTime,\n                _cancelCallBackoffProvider);\n            grainReferences.TryRemove(key, out _);\n        }\n    }\n\n    [RegisterSerializer]\n    internal class GrainCancellationTokenCodec : GeneralizedReferenceTypeSurrogateCodec<GrainCancellationToken, GrainCancellationTokenSurrogate>\n    {\n        private readonly IGrainCancellationTokenRuntime _runtime;\n\n        public GrainCancellationTokenCodec(IGrainCancellationTokenRuntime runtime, IValueSerializer<GrainCancellationTokenSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n            _runtime = runtime;\n        }\n\n        public override GrainCancellationToken ConvertFromSurrogate(ref GrainCancellationTokenSurrogate surrogate)\n        {\n            return new GrainCancellationToken(surrogate.TokenId, surrogate.IsCancellationRequested, _runtime);\n        }\n\n        public override void ConvertToSurrogate(GrainCancellationToken value, ref GrainCancellationTokenSurrogate surrogate)\n        {\n            surrogate.IsCancellationRequested = value.IsCancellationRequested;\n            surrogate.TokenId = value.Id;\n        }\n    }\n\n    [GenerateSerializer]\n    internal struct GrainCancellationTokenSurrogate\n    {\n        [Id(0)]\n        public bool IsCancellationRequested;\n\n        [Id(1)]\n        public Guid TokenId;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/GrainReferenceRuntime.cs",
    "content": "using Orleans.CodeGeneration;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Serialization.Invocation;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    internal class GrainReferenceRuntime : IGrainReferenceRuntime\n    {\n        private readonly GrainReferenceActivator referenceActivator;\n        private readonly GrainInterfaceTypeResolver interfaceTypeResolver;\n        private readonly IGrainCancellationTokenRuntime cancellationTokenRuntime;\n        private readonly IOutgoingGrainCallFilter[] filters;\n        private readonly Action<GrainReference, IResponseCompletionSource, IInvokable, InvokeMethodOptions> sendRequest;\n\n        public GrainReferenceRuntime(\n            IRuntimeClient runtimeClient,\n            IGrainCancellationTokenRuntime cancellationTokenRuntime,\n            IEnumerable<IOutgoingGrainCallFilter> outgoingCallFilters,\n            GrainReferenceActivator referenceActivator,\n            GrainInterfaceTypeResolver interfaceTypeResolver)\n        {\n            this.RuntimeClient = runtimeClient;\n            this.cancellationTokenRuntime = cancellationTokenRuntime;\n            this.referenceActivator = referenceActivator;\n            this.interfaceTypeResolver = interfaceTypeResolver;\n            this.filters = outgoingCallFilters.ToArray();\n            this.sendRequest = (GrainReference reference, IResponseCompletionSource callback, IInvokable body, InvokeMethodOptions options) => RuntimeClient.SendRequest(reference, body, callback, options);\n        }\n\n        public IRuntimeClient RuntimeClient { get; private set; }\n\n        public ValueTask<TResult> InvokeMethodAsync<TResult>(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n        {\n            // TODO: Remove expensive interface type check\n            if (this.filters.Length == 0 && request is not IOutgoingGrainCallFilter)\n            {\n                SetGrainCancellationTokensTarget(reference, request);\n                var responseCompletionSource = ResponseCompletionSourcePool.Get<TResult>();\n                this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options);\n                return responseCompletionSource.AsValueTask();\n            }\n            else\n            {\n                return InvokeMethodWithFiltersAsync<TResult>(reference, request, options);\n            }\n        }\n\n        public ValueTask InvokeMethodAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n        {\n            // TODO: Remove expensive interface type check\n            if (filters.Length == 0 && request is not IOutgoingGrainCallFilter)\n            {\n                SetGrainCancellationTokensTarget(reference, request);\n                var responseCompletionSource = ResponseCompletionSourcePool.Get();\n                this.RuntimeClient.SendRequest(reference, request, responseCompletionSource, options);\n                return responseCompletionSource.AsVoidValueTask();\n            }\n            else\n            {\n                return InvokeMethodWithFiltersAsync(reference, request, options);\n            }\n        }\n\n        public void InvokeMethod(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n        {\n            Debug.Assert((options & InvokeMethodOptions.OneWay) != 0);\n\n            // TODO: Remove expensive interface type check\n            if (filters.Length == 0 && request is not IOutgoingGrainCallFilter)\n            {\n                SetGrainCancellationTokensTarget(reference, request);\n                this.RuntimeClient.SendRequest(reference, request, context: null, options);\n            }\n            else\n            {\n                InvokeMethodWithFiltersAsync(reference, request, options).AsTask().Ignore();\n            }\n        }\n\n        private async ValueTask<TResult> InvokeMethodWithFiltersAsync<TResult>(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n        {\n            SetGrainCancellationTokensTarget(reference, request);\n            var invoker = new OutgoingCallInvoker<TResult>(reference, request, options, this.sendRequest, this.filters);\n            await invoker.Invoke();\n            return invoker.TypedResult;\n        }\n\n        private async ValueTask InvokeMethodWithFiltersAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n        {\n            SetGrainCancellationTokensTarget(reference, request);\n            var invoker = new OutgoingCallInvoker<object>(reference, request, options, this.sendRequest, this.filters);\n            await invoker.Invoke();\n        }\n\n        public object Cast(IAddressable grain, Type grainInterface)\n        {\n            var grainId = grain.GetGrainId();\n            if (grain is GrainReference && grainInterface.IsAssignableFrom(grain.GetType()))\n            {\n                return grain;\n            }\n\n            var interfaceType = this.interfaceTypeResolver.GetGrainInterfaceType(grainInterface);\n            return this.referenceActivator.CreateReference(grainId, interfaceType);\n        }\n\n        /// <summary>\n        /// Sets target grain to the found instances of type GrainCancellationToken\n        /// </summary>\n        private void SetGrainCancellationTokensTarget(GrainReference target, IInvokable request)\n        {\n            var argumentCount = request.GetArgumentCount();\n            for (var i = 0; i < argumentCount; i++)\n            {\n                var arg = request.GetArgument(i);\n                if (arg is not GrainCancellationToken grainToken)\n                {\n                    continue;\n                }\n\n                grainToken.AddGrainReference(this.cancellationTokenRuntime, target);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/IHealthCheckable.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Interface for services which can be probed for health status.\n    /// </summary>\n    public interface IHealthCheckable\n    {\n        /// <summary>\n        /// Returns a value indicating the health of this instance.\n        /// </summary>\n        /// <param name=\"lastCheckTime\">The last time which this instance health was checked.</param>\n        /// <param name=\"reason\">If this method returns <see langword=\"false\"/>, this parameter will describe the reason for that verdict.</param>\n        /// <returns><see langword=\"true\"/> if the instance is healthy, <see langword=\"false\"/> otherwise.</returns>\n        bool CheckHealth(DateTime lastCheckTime, out string reason);\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/ILocalSiloDetails.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Details of the local silo.\n    /// </summary>\n    public interface ILocalSiloDetails\n    {\n        /// <summary>\n        /// Gets the name of this silo.\n        /// </summary>\n        string Name { get; }\n\n        /// <summary>\n        /// Gets the cluster identity. This used to be called DeploymentId before Orleans 2.0 name.\n        /// </summary>\n        string ClusterId { get; }\n\n        /// <summary>\n        /// Gets the host name of this silo.\n        /// </summary>\n        /// <remarks>\n        /// This is equal to <see cref=\"System.Net.Dns.GetHostName()\"/>.\n        /// </remarks>\n        string DnsHostName { get; }\n\n        /// <summary>\n        /// Gets the address of this silo's inter-silo endpoint.\n        /// </summary>\n        SiloAddress SiloAddress { get; }\n\n        /// <summary>\n        /// Gets the address of this silo's gateway proxy endpoint.\n        /// </summary>\n        SiloAddress GatewayAddress { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/IRuntimeClient.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGeneration;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The IRuntimeClient interface defines a subset of the runtime API that is exposed to both silo and client.\n    /// </summary>\n    internal interface IRuntimeClient\n    {\n        /// <summary>\n        /// Gets the time provider used by the system.\n        /// </summary>\n        TimeProvider TimeProvider { get; }\n\n        /// <summary>\n        /// Grain Factory to get and cast grain references.\n        /// </summary>\n        IInternalGrainFactory InternalGrainFactory { get; }\n\n        /// <summary>\n        /// A unique identifier for the current client.\n        /// There is no semantic content to this string, but it may be useful for logging.\n        /// </summary>\n        string CurrentActivationIdentity { get; }\n\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        IServiceProvider ServiceProvider { get; }\n\n        /// <summary>\n        /// Get the current response timeout setting for this client.\n        /// </summary>\n        /// <returns>Response timeout value</returns>\n        TimeSpan GetResponseTimeout();\n\n        /// <summary>\n        /// Sets the current response timeout setting for this client.\n        /// </summary>\n        /// <param name=\"timeout\">New response timeout value</param>\n        void SetResponseTimeout(TimeSpan timeout);\n\n        void SendRequest(GrainReference target, IInvokable request, IResponseCompletionSource context, InvokeMethodOptions options);\n\n        void SendResponse(Message request, Response response);\n\n        void ReceiveResponse(Message message);\n\n        IAddressable CreateObjectReference(IAddressable obj);\n\n        void DeleteObjectReference(IAddressable obj);\n\n        IGrainReferenceRuntime GrainReferenceRuntime { get; }\n\n        void BreakOutstandingMessagesToSilo(SiloAddress deadSilo);\n\n        // For testing purposes only.\n        int GetRunningRequestsCount(GrainInterfaceType grainInterfaceType);\n    }\n\n    /// <summary>\n    /// Helper class used to invoke <see cref=\"IOnDeserialized.OnDeserialized\"/> on objects which implement <see cref=\"IOnDeserialized\"/>, immediately after deserialization.\n    /// </summary>\n    public class OnDeserializedCallbacks : DeserializationContext\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OnDeserializedCallbacks\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public OnDeserializedCallbacks(IServiceProvider serviceProvider)\n        {\n            ServiceProvider = serviceProvider;\n            RuntimeClient = serviceProvider.GetRequiredService<IRuntimeClient>();\n        }\n\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        public override IServiceProvider ServiceProvider { get; }\n\n        /// <summary>\n        /// Gets the runtime client.\n        /// </summary>\n        public override object RuntimeClient { get; }\n\n        /// <summary>\n        /// The hook method invoked by the serialization infrastructure.\n        /// </summary>\n        /// <param name=\"value\">The value which was deserialized.</param>\n        public void OnDeserialized(IOnDeserialized value) => value.OnDeserialized(this);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/InvokableObjectManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans\n{\n    internal sealed partial class InvokableObjectManager : IDisposable\n    {\n        private readonly CancellationTokenSource disposed = new CancellationTokenSource();\n        private readonly ConcurrentDictionary<ObserverGrainId, LocalObjectData> localObjects = new ConcurrentDictionary<ObserverGrainId, LocalObjectData>();\n\n        private readonly InterfaceToImplementationMappingCache _interfaceToImplementationMapping;\n        private readonly IGrainContext rootGrainContext;\n        private readonly IRuntimeClient runtimeClient;\n        private readonly ILogger logger;\n        private readonly DeepCopier deepCopier;\n        private readonly DeepCopier<Response> _responseCopier;\n        private readonly MessagingTrace messagingTrace;\n        private List<IIncomingGrainCallFilter>? _grainCallFilters;\n\n        private List<IIncomingGrainCallFilter> GrainCallFilters\n            => _grainCallFilters ??= [.. runtimeClient.ServiceProvider.GetServices<IIncomingGrainCallFilter>()];\n\n        public InvokableObjectManager(\n            IGrainContext rootGrainContext,\n            IRuntimeClient runtimeClient,\n            DeepCopier deepCopier,\n            MessagingTrace messagingTrace,\n            DeepCopier<Response> responseCopier,\n            InterfaceToImplementationMappingCache interfaceToImplementationMapping,\n            ILogger logger)\n        {\n            this.rootGrainContext = rootGrainContext;\n            this.runtimeClient = runtimeClient;\n            this.deepCopier = deepCopier;\n            this.messagingTrace = messagingTrace;\n            _responseCopier = responseCopier;\n            _interfaceToImplementationMapping = interfaceToImplementationMapping;\n            this.logger = logger;\n        }\n\n        public bool TryRegister(IAddressable obj, ObserverGrainId objectId)\n        {\n            return this.localObjects.TryAdd(objectId, new LocalObjectData(obj, objectId, this));\n        }\n\n        public bool TryDeregister(ObserverGrainId objectId)\n        {\n            return this.localObjects.TryRemove(objectId, out _);\n        }\n\n        public void Dispatch(Message message)\n        {\n            if (!ObserverGrainId.TryParse(message.TargetGrain, out var observerId))\n            {\n                LogNotAddressedToAnObserver(logger, message);\n                return;\n            }\n\n            if (this.localObjects.TryGetValue(observerId, out var objectData))\n            {\n                objectData.ReceiveMessage(message);\n            }\n            else\n            {\n                LogUnexpectedTargetInRequest(logger, message.TargetGrain, message);\n            }\n        }\n\n        public void Dispose()\n        {\n            var tokenSource = this.disposed;\n            Utils.SafeExecute(() => tokenSource?.Cancel(false));\n            Utils.SafeExecute(() => tokenSource?.Dispose());\n        }\n\n        public sealed partial class LocalObjectData : IGrainContext, IGrainCallCancellationExtension\n        {\n            private static readonly Func<object?, Task> HandleFunc = self => ((LocalObjectData)self!).LocalObjectMessagePumpAsync();\n            private readonly InvokableObjectManager _manager;\n            private readonly Dictionary<Message, Task?> _runningRequests = [];\n            private Task? _messagePumpTask;\n\n            internal LocalObjectData(IAddressable obj, ObserverGrainId observerId, InvokableObjectManager manager)\n            {\n                this.LocalObject = new WeakReference(obj);\n                this.ObserverId = observerId;\n                this.Messages = new Queue<Message>();\n                this.Running = false;\n                _manager = manager;\n            }\n\n            internal WeakReference LocalObject { get; }\n            internal ObserverGrainId ObserverId { get; }\n            internal Queue<Message> Messages { get; }\n            internal bool Running { get; set; }\n\n            GrainId IGrainContext.GrainId => this.ObserverId.GrainId;\n\n            GrainReference IGrainContext.GrainReference =>\n                _manager.runtimeClient.InternalGrainFactory.GetGrain(ObserverId.GrainId).AsReference();\n\n            object? IGrainContext.GrainInstance => this.LocalObject.Target;\n\n            ActivationId IGrainContext.ActivationId => throw new NotImplementedException();\n\n            GrainAddress IGrainContext.Address => throw new NotImplementedException();\n\n            IServiceProvider IGrainContext.ActivationServices => throw new NotSupportedException();\n\n            IGrainLifecycle IGrainContext.ObservableLifecycle => throw new NotImplementedException();\n\n            public IWorkItemScheduler Scheduler => throw new NotImplementedException();\n\n            void IGrainContext.SetComponent<TComponent>(TComponent? value) where TComponent : class\n            {\n                if (this.LocalObject.Target is TComponent)\n                {\n                    throw new ArgumentException(\"Cannot override a component which is implemented by this grain\");\n                }\n\n                _manager.rootGrainContext.SetComponent(value);\n            }\n\n            public object? GetComponent(Type componentType)\n            {\n                if (componentType.IsAssignableFrom(this.LocalObject.Target?.GetType()))\n                {\n                    return LocalObject.Target;\n                }\n                else if (componentType.IsAssignableFrom(GetType()))\n                {\n                    return this;\n                }\n\n                return _manager.rootGrainContext.GetComponent(componentType);\n            }\n\n            public object? GetTarget() => this.LocalObject.Target;\n\n            bool IEquatable<IGrainContext>.Equals(IGrainContext? other) => ReferenceEquals(this, other);\n\n            public void ReceiveMessage(object msg)\n            {\n                var message = (Message)msg;\n                var obj = this.LocalObject.Target;\n                if (obj is null)\n                {\n                    // Remove from the dictionary record for the garbage collected object? But now we won't be able to detect invalid dispatch IDs anymore.\n                    LogObserverGarbageCollected(_manager.logger, this.ObserverId, message);\n                    // Try to remove. If it's not there, we don't care.\n                    _manager.TryDeregister(this.ObserverId);\n                    return;\n                }\n\n                // Handle AlwaysInterleave messages (like cancellation requests) immediately without queueing.\n                // These messages need to be processed right away, even if another request is currently running.\n                if (message.IsAlwaysInterleave)\n                {\n                    // Track the running request so it can be cancelled.\n                    lock (Messages)\n                    {\n                        var task = Task.Factory.StartNew(\n                            static state =>\n                            {\n                                var (self, msg) = ((LocalObjectData, Message))state!;\n                                return self.ProcessMessageAsync(msg);\n                            },\n                            (this, message),\n                            CancellationToken.None,\n                            TaskCreationOptions.DenyChildAttach,\n                            TaskScheduler.Default).Unwrap();\n                        _runningRequests.Add(message, task);\n                    }\n\n                    return;\n                }\n\n                bool start;\n                lock (this.Messages)\n                {\n                    this.Messages.Enqueue(message);\n                    start = !this.Running;\n                    this.Running = true;\n                }\n\n                LogInvokeLocalObjectAsync(_manager.logger, message, start);\n\n                if (start)\n                {\n                    // we want to ensure that the message pump operates asynchronously\n                    // with respect to the current thread. see\n                    // http://channel9.msdn.com/Events/TechEd/Europe/2013/DEV-B317#fbid=aIWUq0ssW74\n                    // at position 54:45.\n                    //\n                    // according to the information posted at:\n                    // http://stackoverflow.com/questions/12245935/is-task-factory-startnew-guaranteed-to-use-another-thread-than-the-calling-thr\n                    // this idiom is dependent upon the a TaskScheduler not implementing the\n                    // override QueueTask as task inlining (as opposed to queueing). this seems\n                    // implausible to the author, since none of the .NET schedulers do this and\n                    // it is considered bad form (the OrleansTaskScheduler does not do this).\n                    //\n                    // if, for some reason this doesn't hold true, we can guarantee what we\n                    // want by passing a placeholder continuation token into Task.StartNew()\n                    // instead. i.e.:\n                    //\n                    // return Task.StartNew(() => ..., new CancellationToken());\n                    // We pass these options to Task.Factory.StartNew as they make the call identical\n                    // to Task.Run. See: https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/\n                    _messagePumpTask = Task.Factory.StartNew(\n                            HandleFunc,\n                            this,\n                            CancellationToken.None,\n                            TaskCreationOptions.DenyChildAttach,\n                            TaskScheduler.Default);\n                }\n            }\n\n            private async Task LocalObjectMessagePumpAsync()\n            {\n                while (TryDequeueMessage(out var message))\n                {\n                    await ProcessMessageAsync(message);\n                }\n\n                bool TryDequeueMessage([NotNullWhen(true)] out Message? message)\n                {\n                    lock (Messages)\n                    {\n                        var result = Messages.TryDequeue(out message);\n                        if (!result)\n                        {\n                            Running = false;\n                        }\n                        else\n                        {\n                            _runningRequests.Add(message!, _messagePumpTask);\n                        }\n\n                        return result;\n                    }\n                }\n            }\n\n            private async Task ProcessMessageAsync(Message message)\n            {\n                try\n                {\n                    if (message.IsExpired)\n                    {\n                        _manager.messagingTrace.OnDropExpiredMessage(message, MessagingInstruments.Phase.Invoke);\n                        return;\n                    }\n\n                    if (message.RequestContextData is { Count: > 0 })\n                    {\n                        RequestContextExtensions.Import(message.RequestContextData);\n                    }\n\n                    IInvokable? request;\n                    try\n                    {\n                        if (message.BodyObject is not IInvokable invokableBody)\n                        {\n                            _manager.runtimeClient.SendResponse(\n                                message,\n                                Response.FromException(new InvalidOperationException(\"Message body is not an invokable request\")));\n                            return;\n                        }\n\n                        request = invokableBody;\n                    }\n                    catch (Exception deserializationException)\n                    {\n                        LogErrorDeserializingMessageBody(_manager.logger, deserializationException, message);\n                        _manager.runtimeClient.SendResponse(message, Response.FromException(deserializationException));\n                        return;\n                    }\n\n                    try\n                    {\n                        request.SetTarget(this);\n                        var filters = _manager.GrainCallFilters;\n                        Response response;\n                        if (filters is { Count: > 0 } || LocalObject is IIncomingGrainCallFilter)\n                        {\n                            var invoker = new GrainMethodInvoker(message, this, request, filters, _manager._interfaceToImplementationMapping, _manager._responseCopier);\n                            await invoker.Invoke();\n                            response = invoker.Response;\n                        }\n                        else\n                        {\n                            response = await request.Invoke();\n                            response = _manager._responseCopier.Copy(response);\n                        }\n\n                        if (message.Direction != Message.Directions.OneWay)\n                        {\n                            this.SendResponseAsync(message, response);\n                        }\n                    }\n                    catch (Exception exc)\n                    {\n                        this.ReportException(message, exc);\n                    }\n                    finally\n                    {\n                        // Clear the running request when done.\n                        lock (Messages)\n                        {\n                            _runningRequests.Remove(message);\n                        }\n                    }\n                }\n                catch (Exception outerException)\n                {\n                    // Ignore and keep looping.\n                    LogErrorProcessingMessage(_manager.logger, outerException, message);\n                }\n            }\n\n            private void SendResponseAsync(Message message, Response resultObject)\n            {\n                if (message.IsExpired)\n                {\n                    _manager.messagingTrace.OnDropExpiredMessage(message, MessagingInstruments.Phase.Respond);\n                    return;\n                }\n\n                Response deepCopy;\n                try\n                {\n                    // we're expected to notify the caller if the deep copy failed.\n                    deepCopy = _manager.deepCopier.Copy(resultObject);\n                }\n                catch (Exception exc2)\n                {\n                    _manager.runtimeClient.SendResponse(message, Response.FromException(exc2));\n                    LogErrorSendingResponse(_manager.logger, exc2);\n                    return;\n                }\n\n                // the deep-copy succeeded.\n                _manager.runtimeClient.SendResponse(message, deepCopy);\n                return;\n            }\n\n            private void ReportException(Message message, Exception exception)\n            {\n                switch (message.Direction)\n                {\n                    case Message.Directions.OneWay:\n                        LogErrorInvokingOneWayRequest(_manager.logger, exception, message.BodyObject?.ToString(), message.InterfaceType);\n                        break;\n\n                    case Message.Directions.Request:\n                        Exception deepCopy;\n                        try\n                        {\n                            // we're expected to notify the caller if the deep copy failed.\n                            deepCopy = _manager.deepCopier.Copy(exception);\n                        }\n                        catch (Exception ex2)\n                        {\n                            _manager.runtimeClient.SendResponse(message, Response.FromException(ex2));\n                            LogErrorSendingExceptionResponse(_manager.logger, ex2);\n                            return;\n                        }\n\n                        // the deep-copy succeeded.\n                        var response = Response.FromException(deepCopy);\n                        _manager.runtimeClient.SendResponse(message, response);\n                        break;\n\n                    default:\n                        throw new InvalidOperationException($\"Unrecognized direction for message {message}, which resulted in exception: {exception}\");\n                }\n            }\n\n            public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }\n            public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }\n\n            public void Rehydrate(IRehydrationContext context)\n            {\n                // Migration is not supported, but we need to dispose of the context if it's provided\n                (context as IDisposable)?.Dispose();\n            }\n\n            public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n            {\n                // Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.\n            }\n\n            ValueTask IGrainCallCancellationExtension.CancelRequestAsync(GrainId senderGrainId, CorrelationId messageId)\n            {\n                if (!TryCancelRequest())\n                {\n                    // The message being canceled may not have arrived yet, so retry a few times.\n                    return RetryCancellationAfterDelay();\n                }\n\n                return ValueTask.CompletedTask;\n\n                async ValueTask RetryCancellationAfterDelay()\n                {\n                    var attemptsRemaining = 3;\n                    do\n                    {\n                        await Task.Delay(1_000);\n\n                        if (TryCancelRequest())\n                        {\n                            return;\n                        }\n\n                    } while (--attemptsRemaining > 0);\n                }\n\n                bool TryCancelRequest()\n                {\n                    Message? message = null;\n                    var wasWaiting = false;\n                    lock (Messages)\n                    {\n                        // Check the running requests.\n                        foreach (var runningRequest in _runningRequests.Keys)\n                        {\n                            if (runningRequest.Id == messageId && runningRequest.SendingGrain == senderGrainId)\n                            {\n                                message = runningRequest;\n                                break;\n                            }\n                        }\n\n                        if (message is null)\n                        {\n                            // Check the waiting requests.\n                            foreach (var waitingRequest in Messages)\n                            {\n                                var waiting = waitingRequest;\n                                if (waiting.Id == messageId && waiting.SendingGrain == senderGrainId)\n                                {\n                                    message = waiting;\n                                    wasWaiting = true;\n\n                                    // Remove the message, since it will be rejected immediately (outside the lock) without being executed.\n                                    var initialCount = Messages.Count;\n                                    for (var i = 0; i < initialCount; i++)\n                                    {\n                                        var current = Messages.Dequeue();\n                                        if (!ReferenceEquals(current, message))\n                                        {\n                                            Messages.Enqueue(current);\n                                        }\n                                    }\n\n                                    break;\n                                }\n                            }\n                        }\n                    }\n\n                    var didCancel = false;\n                    if (message is not null)\n                    {\n                        // The message never began executing, so send a canceled response immediately.\n                        // If the message did begin executing, wait for it to observe the cancellation token and respond itself.\n                        if (wasWaiting)\n                        {\n                            _manager.runtimeClient.SendResponse(message, Response.FromException(new OperationCanceledException()));\n                            didCancel = true;\n                        }\n                        else if (message.BodyObject is IInvokable invokableRequest)\n                        {\n                            didCancel = TryCancelInvokable(invokableRequest) || !invokableRequest.IsCancellable;\n                        }\n                        else\n                        {\n                            // Assume the request is not cancellable.\n                            didCancel = true;\n                        }\n                    }\n\n                    return didCancel;\n                }\n\n                bool TryCancelInvokable(IInvokable request)\n                {\n                    try\n                    {\n                        return request.TryCancel();\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorCancellationCallbackFailed(_manager.logger, exception);\n                        return true;\n                    }\n                }\n            }\n\n            [LoggerMessage(\n                Level = LogLevel.Warning,\n                Message = \"One or more cancellation callbacks failed.\"\n            )]\n            private static partial void LogErrorCancellationCallbackFailed(ILogger logger, Exception exception);\n\n            public Task Deactivated => Task.CompletedTask;\n        }\n\n        private readonly struct ObserverGrainIdLogValue(ObserverGrainId observerId)\n        {\n            public override string ToString() => observerId.ToString();\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_OGC_TargetNotFound_2,\n            Level = LogLevel.Error,\n            Message = \"Message is not addressed to an observer. Message: '{Message}'.\"\n        )]\n        private static partial void LogNotAddressedToAnObserver(ILogger logger, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.ProxyClient_OGC_TargetNotFound,\n            Level = LogLevel.Error,\n            Message = \"Unexpected target grain in request: {TargetGrain}. Message: '{Message}'.\"\n        )]\n        private static partial void LogUnexpectedTargetInRequest(ILogger logger, GrainId targetGrain, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.Runtime_Error_100162,\n            Message = \"Object associated with id '{ObserverId}' has been garbage collected. Deleting object reference and unregistering it. Message: '{Message}'.\"\n        )]\n        private static partial void LogObserverGarbageCollected(ILogger logger, ObserverGrainId observerId, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"InvokeLocalObjectAsync '{Message}' start '{Start}'.\"\n        )]\n        private static partial void LogInvokeLocalObjectAsync(ILogger logger, Message message, bool start);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.ProxyClient_OGC_SendResponseFailed,\n            Message = \"Error sending a response.\"\n        )]\n        private static partial void LogErrorSendingResponse(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.ProxyClient_OGC_UnhandledExceptionInOneWayInvoke,\n            Message = \"Exception during invocation of notification '{Request}', interface '{Interface}'. Ignoring exception because this is a one way request.\"\n        )]\n        private static partial void LogErrorInvokingOneWayRequest(ILogger logger, Exception exception, string? request, GrainInterfaceType @interface);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.ProxyClient_OGC_SendExceptionResponseFailed,\n            Message = \"Error sending an exception response.\"\n        )]\n        private static partial void LogErrorSendingExceptionResponse(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception during message body deserialization for message: '{Message}'.\"\n        )]\n        private static partial void LogErrorDeserializingMessageBody(ILogger logger, Exception exception, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception processing message '{Message}'.\"\n        )]\n        private static partial void LogErrorProcessingMessage(ILogger logger, Exception exception, Message message);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/LocalClientDetails.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Configuration;\n\nnamespace Orleans\n{\n    internal class LocalClientDetails\n    {\n        public LocalClientDetails(IOptions<ClientMessagingOptions> clientMessagingOptions)\n        {\n            var options = clientMessagingOptions.Value;\n            var ipAddress = options.LocalAddress ?? ConfigUtilities.GetLocalIPAddress(options.PreferredFamily, options.NetworkInterfaceName);\n\n            // Client generations are negative\n            var generation = -SiloAddress.AllocateNewGeneration();\n            ClientAddress = SiloAddress.New(ipAddress, 0, generation);\n            ClientId = ClientGrainId.Create();\n        }\n\n        public ClientGrainId ClientId { get; }\n        public IPAddress IPAddress => ClientAddress.Endpoint.Address;\n        public SiloAddress ClientAddress { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/MembershipTableSnapshot.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    [GenerateSerializer, Immutable]\n    internal sealed class MembershipTableSnapshot\n    {\n        private static readonly MembershipTableSnapshot InitialValue = new(MembershipVersion.MinValue, ImmutableDictionary<SiloAddress, MembershipEntry>.Empty);\n\n        public MembershipTableSnapshot(\n            MembershipVersion version,\n            ImmutableDictionary<SiloAddress, MembershipEntry> entries)\n        {\n            this.Version = version;\n            this.Entries = entries;\n        }\n\n        public static MembershipTableSnapshot Create(MembershipTableData table) => Update(InitialValue, table);\n\n        public static MembershipTableSnapshot Update(MembershipTableSnapshot previousSnapshot, MembershipTableData table)\n        {\n            ArgumentNullException.ThrowIfNull(previousSnapshot);\n            ArgumentNullException.ThrowIfNull(table);\n            var version = (table.Version.Version == 0 && table.Version.VersionEtag == \"0\")\n              ? MembershipVersion.MinValue\n              : new MembershipVersion(table.Version.Version);\n            return Update(previousSnapshot, version, table.Members.Select(t => t.Item1));\n        }\n\n        public static MembershipTableSnapshot Update(MembershipTableSnapshot previousSnapshot, MembershipTableSnapshot updated)\n        {\n            ArgumentNullException.ThrowIfNull(previousSnapshot);\n            ArgumentNullException.ThrowIfNull(updated);\n            return Update(previousSnapshot, updated.Version, updated.Entries.Values);\n        }\n\n        private static MembershipTableSnapshot Update(MembershipTableSnapshot previousSnapshot, MembershipVersion version, IEnumerable<MembershipEntry> updatedEntries)\n        {\n            ArgumentNullException.ThrowIfNull(previousSnapshot);\n            ArgumentNullException.ThrowIfNull(updatedEntries);\n\n            var entries = ImmutableDictionary.CreateBuilder<SiloAddress, MembershipEntry>();\n            foreach (var item in updatedEntries)\n            {\n                var entry = item;\n                entry = PreserveIAmAliveTime(previousSnapshot, entry);\n                entries.Add(entry.SiloAddress, entry);\n            }\n\n            return new MembershipTableSnapshot(version, entries.ToImmutable());\n        }\n\n        private static MembershipEntry PreserveIAmAliveTime(MembershipTableSnapshot previousSnapshot, MembershipEntry entry)\n        {\n            // Retain the maximum IAmAliveTime, since IAmAliveTime updates do not increase membership version\n            // and therefore can be clobbered by torn reads.\n            if (previousSnapshot.Entries.TryGetValue(entry.SiloAddress, out var previousEntry)\n                && previousEntry.IAmAliveTime > entry.IAmAliveTime)\n            {\n                entry = entry.WithIAmAliveTime(previousEntry.IAmAliveTime);\n            }\n\n            return entry;\n        }\n\n        [Id(0)]\n        public MembershipVersion Version { get; }\n        \n        [Id(1)]\n        public ImmutableDictionary<SiloAddress, MembershipEntry> Entries { get; }\n\n        public int ActiveNodeCount\n        {\n            get\n            {\n                var count = 0;\n                foreach (var entry in this.Entries)\n                {\n                    if (entry.Value.Status == SiloStatus.Active)\n                    {\n                        ++count;\n                    }\n                }\n\n                return count;\n            }\n        }\n\n        public SiloStatus GetSiloStatus(SiloAddress silo)\n        {\n            var status = this.Entries.TryGetValue(silo, out var entry) ? entry.Status : SiloStatus.None;\n            if (status == SiloStatus.None)\n            {\n                foreach (var member in this.Entries)\n                {\n                    if (member.Key.IsSuccessorOf(silo))\n                    {\n                        status = SiloStatus.Dead;\n                        break;\n                    }\n                }\n            }\n\n            return status;\n        }\n\n        public bool IsSuccessorTo(MembershipTableSnapshot other)\n        {\n            if (Version > other.Version)\n            {\n                return true;\n            }\n\n            if (Version < other.Version)\n            {\n                return false;\n            }\n\n            if (Entries.Count > other.Entries.Count)\n            {\n                // Something is amiss.\n                return false;\n            }\n\n            foreach (var entry in Entries)\n            {\n                if (!other.Entries.TryGetValue(entry.Key, out var otherEntry))\n                {\n                    // Something is amiss.\n                    return false;\n                }\n            }\n\n            // This is a successor if any silo has a later EffectiveIAmAliveTime.\n            foreach (var entry in Entries)\n            {\n                if (entry.Value.EffectiveIAmAliveTime > other.Entries[entry.Key].EffectiveIAmAliveTime)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n            sb.Append($\"[Version: {this.Version}, {this.Entries.Count} silos\");\n            foreach (var entry in this.Entries) sb.Append($\", {entry.Value}\");\n            sb.Append(']');\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/OutgoingCallInvoker.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Orleans.CodeGeneration;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Invokes a request on a grain reference.\n    /// </summary>\n    internal sealed class OutgoingCallInvoker<TResult> : IOutgoingGrainCallContext\n    {\n        private readonly IInvokable request;\n        private readonly InvokeMethodOptions options;\n        private readonly Action<GrainReference, IResponseCompletionSource, IInvokable, InvokeMethodOptions> sendRequest;\n        private readonly IOutgoingGrainCallFilter[] filters;\n        private readonly int stages;\n        private readonly GrainReference grainReference;\n        private readonly IOutgoingGrainCallFilter requestFilter;\n        private int stage;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OutgoingCallInvoker{TResult}\"/> class.\n        /// </summary>\n        /// <param name=\"grain\">The grain reference.</param>\n        /// <param name=\"request\">The request.</param>\n        /// <param name=\"options\"></param>\n        /// <param name=\"sendRequest\"></param>\n        /// <param name=\"filters\">The invocation interceptors.</param>\n        public OutgoingCallInvoker(\n            GrainReference grain,\n            IInvokable request,\n            InvokeMethodOptions options,\n            Action<GrainReference, IResponseCompletionSource, IInvokable, InvokeMethodOptions> sendRequest,\n            IOutgoingGrainCallFilter[] filters)\n        {\n            this.request = request;\n            this.options = options;\n            this.sendRequest = sendRequest;\n            this.grainReference = grain;\n            this.filters = filters;\n            this.stages = filters.Length;\n            SourceContext = RuntimeContext.Current;\n\n            if (request is IOutgoingGrainCallFilter requestFilter)\n            {\n                this.requestFilter = requestFilter;\n                ++this.stages;\n            }\n        }\n\n        public IInvokable Request => this.request;\n\n        public object Grain => this.grainReference;\n\n        public MethodInfo InterfaceMethod => request.GetMethod();\n\n        public object Result { get => TypedResult; set => TypedResult = (TResult)value; }\n\n        public Response Response { get; set; }\n\n        public TResult TypedResult { get => Response.GetResult<TResult>(); set => Response = Response.FromResult(value); }\n\n        public IGrainContext SourceContext { get; }\n\n        public GrainId? SourceId => SourceContext?.GrainId;\n\n        public GrainId TargetId => grainReference.GrainId;\n\n        public GrainInterfaceType InterfaceType => grainReference.InterfaceType;\n\n        public string InterfaceName => request.GetInterfaceName();\n\n        public string MethodName => request.GetMethodName();\n\n        public async Task Invoke()\n        {\n            try\n            {\n                // Execute each stage in the pipeline. Each successive call to this method will invoke the next stage.\n                // Stages which are not implemented (eg, because the user has not specified an interceptor) are skipped.\n                if (stage < this.filters.Length)\n                {\n                    // Call each of the specified interceptors.\n                    var systemWideFilter = this.filters[stage];\n                    stage++;\n                    await systemWideFilter.Invoke(this);\n\n                    // If Response is null some filter did not continue the call chain\n                    if (this.Response is null)\n                    {\n                        ThrowBrokenCallFilterChain(systemWideFilter.GetType().Name);\n                    }\n\n                    return;\n                }\n                else if (stage < this.stages)\n                {\n                    stage++;\n                    await this.requestFilter.Invoke(this);\n\n                    // If Response is null some filter did not continue the call chain\n                    if (this.Response is null)\n                    {\n                        ThrowBrokenCallFilterChain(this.requestFilter.GetType().Name);\n                    }\n\n                    return;\n                }\n                else if (stage == this.stages)\n                {\n                    // Finally call the root-level invoker.\n                    stage++;\n                    var responseCompletionSource = ResponseCompletionSourcePool.Get();\n                    this.sendRequest(this.grainReference, responseCompletionSource, this.request, this.options);\n                    this.Response = await responseCompletionSource.AsValueTask();\n\n                    return;\n                }\n            }\n            finally\n            {\n                stage--;\n            }\n\n            // If this method has been called more than the expected number of times, that is invalid.\n            ThrowInvalidCall();\n        }\n\n        private void ThrowInvalidCall()\n        {\n            throw new InvalidOperationException($\"{typeof(OutgoingCallInvoker<TResult>)}.{nameof(Invoke)}() received an invalid call.\");\n        }\n\n        private void ThrowBrokenCallFilterChain(string filterName)\n        {\n            throw new InvalidOperationException($\"{typeof(OutgoingCallInvoker<TResult>)}.{nameof(Invoke)}() invoked a broken filter: {filterName}.\");\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/OutsideRuntimeClient.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.ClientObservers;\nusing Orleans.CodeGeneration;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\nusing static Orleans.Internal.StandardExtensions;\n\nnamespace Orleans\n{\n    internal partial class OutsideRuntimeClient : IRuntimeClient, IDisposable, IClusterConnectionStatusListener\n    {\n        internal static bool TestOnlyThrowExceptionDuringInit { get; set; }\n\n        private readonly ILogger logger;\n        private readonly ClientMessagingOptions clientMessagingOptions;\n\n        private readonly ConcurrentDictionary<CorrelationId, CallbackData> callbacks;\n        private InvokableObjectManager localObjects;\n        private bool disposing;\n        private bool disposed;\n\n        private readonly MessagingTrace messagingTrace;\n        private readonly InterfaceToImplementationMappingCache _interfaceToImplementationMapping;\n        private readonly ApplicationRequestInstruments _applicationRequestInstruments;\n        private IGrainCallCancellationManager _cancellationManager;\n        private IClusterConnectionStatusObserver[] _statusObservers;\n\n        public IInternalGrainFactory InternalGrainFactory { get; private set; }\n\n        private ClientClusterManifestProvider _manifestProvider;\n        private MessageFactory messageFactory;\n        private readonly LocalClientDetails _localClientDetails;\n        private readonly ILoggerFactory loggerFactory;\n\n        private readonly SharedCallbackData sharedCallbackData;\n        private readonly PeriodicTimer callbackTimer;\n        private Task callbackTimerTask;\n\n        public GrainAddress CurrentActivationAddress\n        {\n            get;\n            private set;\n        }\n        public ClientGatewayObserver gatewayObserver { get; private set; }\n\n        public string CurrentActivationIdentity\n        {\n            get { return CurrentActivationAddress.ToString(); }\n        }\n\n        public IGrainReferenceRuntime GrainReferenceRuntime { get; private set; }\n\n        internal ClientMessageCenter MessageCenter { get; private set; }\n\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Reliability\", \"CA2000:Dispose objects before losing scope\",\n            Justification = \"MessageCenter is IDisposable but cannot call Dispose yet as it lives past the end of this method call.\")]\n        public OutsideRuntimeClient(\n            LocalClientDetails localClientDetails,\n            ILoggerFactory loggerFactory,\n            IOptions<ClientMessagingOptions> clientMessagingOptions,\n            MessagingTrace messagingTrace,\n            IServiceProvider serviceProvider,\n            TimeProvider timeProvider,\n            InterfaceToImplementationMappingCache interfaceToImplementationMapping,\n            OrleansInstruments orleansInstruments)\n        {\n            TimeProvider = timeProvider;\n            _interfaceToImplementationMapping = interfaceToImplementationMapping;\n            _applicationRequestInstruments = new(orleansInstruments);\n            this.ServiceProvider = serviceProvider;\n            _localClientDetails = localClientDetails;\n            this.loggerFactory = loggerFactory;\n            this.messagingTrace = messagingTrace;\n            this.logger = loggerFactory.CreateLogger<OutsideRuntimeClient>();\n            callbacks = new ConcurrentDictionary<CorrelationId, CallbackData>();\n            this.clientMessagingOptions = clientMessagingOptions.Value;\n            var period = Max(\n                TimeSpan.FromMilliseconds(1),\n                Min(\n                    this.clientMessagingOptions.ResponseTimeout,\n                    TimeSpan.FromSeconds(1)));\n            this.callbackTimer = new PeriodicTimer(period, timeProvider);\n            this.sharedCallbackData = new SharedCallbackData(\n                msg => this.UnregisterCallback(msg.Id),\n                this.loggerFactory.CreateLogger<CallbackData>(),\n                this.clientMessagingOptions.ResponseTimeout,\n                this.clientMessagingOptions.CancelRequestOnTimeout,\n                this.clientMessagingOptions.WaitForCancellationAcknowledgement,\n                null);\n        }\n\n        internal void ConsumeServices()\n        {\n            try\n            {\n                _statusObservers = this.ServiceProvider.GetServices<IClusterConnectionStatusObserver>().ToArray();\n                _manifestProvider = ServiceProvider.GetRequiredService<ClientClusterManifestProvider>();\n\n                this.InternalGrainFactory = this.ServiceProvider.GetRequiredService<IInternalGrainFactory>();\n                _cancellationManager = sharedCallbackData.CancellationManager = ServiceProvider.GetRequiredService<IGrainCallCancellationManager>();\n                this.messageFactory = this.ServiceProvider.GetService<MessageFactory>();\n                this.localObjects = new InvokableObjectManager(\n                    ServiceProvider.GetRequiredService<ClientGrainContext>(),\n                    this,\n                    ServiceProvider.GetRequiredService<DeepCopier>(),\n                    messagingTrace,\n                    ServiceProvider.GetRequiredService<DeepCopier<Response>>(),\n                    _interfaceToImplementationMapping,\n                    loggerFactory.CreateLogger<ClientGrainContext>());\n\n                this.callbackTimerTask = Task.Run(MonitorCallbackExpiry);\n\n                this.GrainReferenceRuntime = this.ServiceProvider.GetRequiredService<IGrainReferenceRuntime>();\n\n                // Client init / sign-on message\n                LogStartingClient(logger, RuntimeVersion.Current, _localClientDetails.ClientAddress, _localClientDetails.ClientId);\n\n                if (TestOnlyThrowExceptionDuringInit)\n                {\n                    throw new InvalidOperationException(\"TestOnlyThrowExceptionDuringInit\");\n                }\n            }\n            catch (Exception exc)\n            {\n                LogConstructorException(logger, exc);\n                ConstructorReset();\n                throw;\n            }\n        }\n\n        public IServiceProvider ServiceProvider { get; private set; }\n\n        public TimeProvider TimeProvider { get; }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            // Deliberately avoid capturing the current synchronization context during startup and execute on the default scheduler.\n            // This helps to avoid any issues (such as deadlocks) caused by executing with the client's synchronization context/scheduler.\n            await Task.Run(() => this.StartInternal(cancellationToken)).ConfigureAwait(false);\n\n            LogStartedClient(logger, CurrentActivationAddress, _localClientDetails.ClientId);\n        }\n\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            this.callbackTimer.Dispose();\n\n            if (this.callbackTimerTask is { } task)\n            {\n                await task.WaitAsync(cancellationToken);\n            }\n\n            if (MessageCenter is { } messageCenter)\n            {\n                await messageCenter.StopAsync(cancellationToken);\n            }\n\n            if (_manifestProvider is { } provider)\n            {\n                await provider.StopAsync(cancellationToken);\n            }\n\n            ConstructorReset();\n        }\n\n        // used for testing to (carefully!) allow two clients in the same process\n        private async Task StartInternal(CancellationToken cancellationToken)\n        {\n            var retryFilter = ServiceProvider.GetService<IClientConnectionRetryFilter>();\n\n            var gatewayManager = this.ServiceProvider.GetRequiredService<GatewayManager>();\n            await ExecuteWithRetries(\n                async () => await gatewayManager.StartAsync(cancellationToken),\n                retryFilter,\n                cancellationToken);\n\n            MessageCenter = ActivatorUtilities.CreateInstance<ClientMessageCenter>(this.ServiceProvider);\n            MessageCenter.RegisterLocalMessageHandler(this.HandleMessage);\n            await ExecuteWithRetries(\n                async () => await MessageCenter.StartAsync(cancellationToken),\n                retryFilter,\n                cancellationToken);\n            CurrentActivationAddress = GrainAddress.NewActivationAddress(MessageCenter.MyAddress, _localClientDetails.ClientId.GrainId);\n\n            this.gatewayObserver = new ClientGatewayObserver(gatewayManager);\n            this.InternalGrainFactory.CreateObjectReference<IClientGatewayObserver>(this.gatewayObserver);\n\n            await ExecuteWithRetries(\n                _manifestProvider.StartAsync,\n                retryFilter,\n                cancellationToken);\n\n            static async Task ExecuteWithRetries(Func<Task> task, IClientConnectionRetryFilter retryFilter, CancellationToken cancellationToken)\n            {\n                do\n                {\n                    try\n                    {\n                        await task();\n                        return;\n                    }\n                    catch (Exception exception) when (retryFilter is not null && !cancellationToken.IsCancellationRequested)\n                    {\n                        var shouldRetry = await retryFilter.ShouldRetryConnectionAttempt(exception, cancellationToken);\n                        if (cancellationToken.IsCancellationRequested || !shouldRetry)\n                        {\n                            throw;\n                        }\n                    }\n                }\n                while (!cancellationToken.IsCancellationRequested);\n            }\n        }\n\n        private void HandleMessage(Message message)\n        {\n            switch (message.Direction)\n            {\n                case Message.Directions.Response:\n                    {\n                        ReceiveResponse(message);\n                        break;\n                    }\n                case Message.Directions.OneWay:\n                case Message.Directions.Request:\n                    {\n                        this.localObjects.Dispatch(message);\n                        break;\n                    }\n                default:\n                    LogMessageNotSupported(logger, message);\n                    break;\n            }\n        }\n\n        public void SendResponse(Message request, Response response)\n        {\n            ThrowIfDisposed();\n            var message = this.messageFactory.CreateResponseMessage(request);\n            OrleansOutsideRuntimeClientEvent.Log.SendResponse(message);\n            message.BodyObject = response;\n\n            MessageCenter.SendMessage(message);\n        }\n\n        public void SendRequest(GrainReference target, IInvokable request, IResponseCompletionSource context, InvokeMethodOptions options)\n        {\n            ThrowIfDisposed();\n            var cancellationToken = request.GetCancellationToken();\n            cancellationToken.ThrowIfCancellationRequested();\n            var message = this.messageFactory.CreateMessage(request, options);\n            OrleansOutsideRuntimeClientEvent.Log.SendRequest(message);\n\n            message.InterfaceType = target.InterfaceType;\n            message.InterfaceVersion = target.InterfaceVersion;\n            var targetGrainId = target.GrainId;\n            var oneWay = (options & InvokeMethodOptions.OneWay) != 0;\n            message.SendingGrain = CurrentActivationAddress.GrainId;\n            message.TargetGrain = targetGrainId;\n\n            if (SystemTargetGrainId.TryParse(targetGrainId, out var systemTargetGrainId))\n            {\n                // If the silo isn't be supplied, it will be filled in by the sender to be the gateway silo\n                message.TargetSilo = systemTargetGrainId.GetSiloAddress();\n            }\n\n            if (this.clientMessagingOptions.DropExpiredMessages && message.IsExpirableMessage())\n            {\n                // don't set expiration for system target messages.\n                var ttl = request.GetDefaultResponseTimeout() ?? this.clientMessagingOptions.ResponseTimeout;\n                message.TimeToLive = ttl;\n            }\n\n            if (!oneWay)\n            {\n                var callbackData = new CallbackData(this.sharedCallbackData, context, message, _applicationRequestInstruments);\n                callbackData.SubscribeForCancellation(cancellationToken);\n                callbacks.TryAdd(message.Id, callbackData);\n            }\n            else\n            {\n                context?.Complete();\n            }\n\n            LogSendingMessage(logger, message);\n            MessageCenter.SendMessage(message);\n        }\n\n        public void ReceiveResponse(Message response)\n        {\n            OrleansOutsideRuntimeClientEvent.Log.ReceiveResponse(response);\n\n            LogReceivedMessage(logger, response);\n\n            if (response.Result is Message.ResponseTypes.Status)\n            {\n                var status = (StatusResponse)response.BodyObject;\n                callbacks.TryGetValue(response.Id, out var callback);\n                var request = callback?.Message;\n                if (request is not null)\n                {\n                    callback.OnStatusUpdate(status);\n                    if (status.Diagnostics != null && status.Diagnostics.Count > 0)\n                    {\n                        LogReceivedStatusUpdateForPendingRequest(logger, request, new(status.Diagnostics));\n                    }\n                }\n                else\n                {\n                    if (clientMessagingOptions.CancelUnknownRequestOnStatusUpdate)\n                    {\n                        // Cancel the call since the caller has abandoned it.\n                        // Note that the target and sender arguments are swapped because this is a response to the original request.\n                        _cancellationManager?.SignalCancellation(\n                            response.SendingSilo,\n                            targetGrainId: response.SendingGrain,\n                            sendingGrainId: response.TargetGrain,\n                            messageId: response.Id);\n                    }\n\n                    if (status.Diagnostics != null && status.Diagnostics.Count > 0)\n                    {\n                        LogReceivedStatusUpdateForUnknownRequest(logger, response, new(status.Diagnostics));\n                    }\n                }\n\n                return;\n            }\n\n            CallbackData callbackData;\n            var found = callbacks.TryRemove(response.Id, out callbackData);\n            if (found)\n            {\n                // We need to import the RequestContext here as well.\n                // Unfortunately, it is not enough, since CallContext.LogicalGetData will not flow \"up\" from task completion source into the resolved task.\n                // RequestContextExtensions.Import(response.RequestContextData);\n                callbackData.DoCallback(response);\n            }\n            else\n            {\n                LogDebugNoCallbackForResponseMessage(logger, response);\n            }\n        }\n\n        private void UnregisterCallback(CorrelationId id)\n        {\n            callbacks.TryRemove(id, out _);\n        }\n\n        private void ConstructorReset()\n        {\n            Utils.SafeExecute(() => this.Dispose());\n        }\n\n        /// <inheritdoc />\n        public TimeSpan GetResponseTimeout() => this.sharedCallbackData.ResponseTimeout;\n\n        /// <inheritdoc />\n        public void SetResponseTimeout(TimeSpan timeout) => this.sharedCallbackData.ResponseTimeout = timeout;\n\n        public IAddressable CreateObjectReference(IAddressable obj)\n        {\n            if (obj is GrainReference)\n                throw new ArgumentException(\"Argument obj is already a grain reference.\", nameof(obj));\n\n            if (obj is IGrainBase)\n                throw new ArgumentException(\"Argument must not be a grain class.\", nameof(obj));\n\n            var observerId = obj is ClientObserver clientObserver\n                ? clientObserver.GetObserverGrainId(_localClientDetails.ClientId)\n                : ObserverGrainId.Create(_localClientDetails.ClientId);\n            var reference = this.InternalGrainFactory.GetGrain(observerId.GrainId);\n\n            if (!localObjects.TryRegister(obj, observerId))\n            {\n                throw new ArgumentException($\"Failed to add new observer {reference} to localObjects collection.\", \"reference\");\n            }\n\n            return reference;\n        }\n\n        public void DeleteObjectReference(IAddressable obj)\n        {\n            if (!(obj is GrainReference reference))\n            {\n                throw new ArgumentException(\"Argument reference is not a grain reference.\");\n            }\n\n            if (!ObserverGrainId.TryParse(reference.GrainId, out var observerId))\n            {\n                throw new ArgumentException($\"Reference {reference.GrainId} is not an observer reference\");\n            }\n\n            if (!localObjects.TryDeregister(observerId))\n            {\n                throw new ArgumentException(\"Reference is not associated with a local object.\", \"reference\");\n            }\n        }\n\n        public void Dispose()\n        {\n            if (this.disposing) return;\n            this.disposing = true;\n\n            Utils.SafeExecute(() => this.callbackTimer.Dispose());\n\n            Utils.SafeExecute(() => MessageCenter?.Dispose());\n\n            GC.SuppressFinalize(this);\n            disposed = true;\n        }\n\n        public void BreakOutstandingMessagesToSilo(SiloAddress deadSilo)\n        {\n            foreach (var callback in callbacks)\n            {\n                if (deadSilo.Equals(callback.Value.Message.TargetSilo))\n                {\n                    callback.Value.OnTargetSiloFail();\n                }\n            }\n        }\n\n        public int GetRunningRequestsCount(GrainInterfaceType grainInterfaceType)\n            => this.callbacks.Count(c => c.Value.Message.InterfaceType == grainInterfaceType);\n\n        /// <inheritdoc />\n        public void NotifyClusterConnectionLost()\n        {\n            foreach (var observer in _statusObservers)\n            {\n                try\n                {\n                    observer.NotifyClusterConnectionLost();\n                }\n                catch (Exception ex)\n                {\n                    LogErrorSendingClusterDisconnectionNotification(logger, ex);\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public void NotifyGatewayCountChanged(int currentNumberOfGateways, int previousNumberOfGateways)\n        {\n            foreach (var observer in _statusObservers)\n            {\n                try\n                {\n                    observer.NotifyGatewayCountChanged(\n                        currentNumberOfGateways,\n                        previousNumberOfGateways,\n                        currentNumberOfGateways > 0 && previousNumberOfGateways <= 0);\n                }\n                catch (Exception ex)\n                {\n                    LogErrorSendingGatewayCountChangedNotification(logger, ex);\n                }\n            }\n        }\n\n        private async Task MonitorCallbackExpiry()\n        {\n            while (await callbackTimer.WaitForNextTickAsync())\n            {\n                try\n                {\n                    var currentStopwatchTicks = ValueStopwatch.GetTimestamp();\n                    foreach (var (_, callback) in callbacks)\n                    {\n                        if (callback.IsCompleted)\n                        {\n                            continue;\n                        }\n\n                        if (callback.IsExpired(currentStopwatchTicks))\n                        {\n                            callback.OnTimeout();\n                        }\n                    }\n                }\n                catch (Exception ex)\n                {\n                    LogErrorWhileProcessingCallbackExpiry(logger, ex);\n                }\n            }\n        }\n\n        private void ThrowIfDisposed()\n        {\n            if (disposed)\n            {\n                ThrowObjectDisposedException();\n            }\n\n            void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(OutsideRuntimeClient));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.ClientStarting,\n            Message = \"Starting Orleans client with runtime version '{RuntimeVersion}', local address '{LocalAddress}' and client id '{ClientId}'.\"\n        )]\n        private static partial void LogStartingClient(ILogger logger, string runtimeVersion, SiloAddress localAddress, ClientGrainId clientId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Runtime_Error_100319,\n            Message = \"OutsideRuntimeClient constructor failed.\"\n        )]\n        private static partial void LogConstructorException(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.ProxyClient_StartDone,\n            Message = \"Started client with address '{ActivationAddress}' and id '{ClientId}'.\"\n        )]\n        private static partial void LogStartedClient(ILogger logger, GrainAddress activationAddress, ClientGrainId clientId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Send '{Message}'.\"\n        )]\n        private static partial void LogSendingMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Received '{Message}'.\"\n        )]\n        private static partial void LogReceivedMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Message not supported: '{Message}'.\"\n        )]\n        private static partial void LogMessageNotSupported(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error sending cluster disconnection notification.\"\n        )]\n        private static partial void LogErrorSendingClusterDisconnectionNotification(ILogger logger, Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error sending gateway count changed notification.\"\n        )]\n        private static partial void LogErrorSendingGatewayCountChangedNotification(ILogger logger, Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error while processing callback expiry.\"\n        )]\n        private static partial void LogErrorWhileProcessingCallbackExpiry(ILogger logger, Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.Runtime_Error_100011,\n            Message = \"No callback for response message '{ResponseMessage}'\"\n        )]\n        private static partial void LogDebugNoCallbackForResponseMessage(ILogger logger, Message responseMessage);\n\n        private readonly struct DiagnosticsLogData(List<string> diagnostics)\n        {\n            public override string ToString() => string.Join(\"\\n\", diagnostics);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Received status update for pending request, Request: '{RequestMessage}'. Status: '{Diagnostics}'.\"\n        )]\n        private static partial void LogReceivedStatusUpdateForPendingRequest(ILogger logger, Message requestMessage, DiagnosticsLogData diagnostics);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Received status update for unknown request. Message: '{StatusMessage}'. Status: '{Diagnostics}'.\"\n        )]\n        private static partial void LogReceivedStatusUpdateForUnknownRequest(ILogger logger, Message statusMessage, DiagnosticsLogData diagnostics);\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/RequestContextExtensions.cs",
    "content": "#nullable enable\nusing System.Diagnostics;\nusing Orleans.Diagnostics;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Extensions for working with <see cref=\"RequestContext\"/>.\n    /// </summary>\n    public static class RequestContextExtensions\n    {\n        /// <summary>\n        /// Imports the specified context data into the current <see cref=\"RequestContext\"/>, clearing all existing values.\n        /// </summary>\n        /// <param name=\"contextData\">The context data.</param>\n        public static void Import(Dictionary<string, object>? contextData)\n        {\n            var values = contextData switch\n            {\n                { Count: > 0 } => contextData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value),\n                _ => null,\n            };\n\n            RequestContext.CallContextData.Value = new RequestContext.ContextProperties\n            {\n                Values = values,\n            };\n        }\n\n        /// <summary>\n        /// Exports a copy of the current <see cref=\"RequestContext\"/>.\n        /// </summary>\n        /// <param name=\"copier\">The copier.</param>\n        /// <returns>A copy of the current request context.</returns>\n        public static Dictionary<string, object>? Export(DeepCopier copier)\n        {\n            var properties = RequestContext.CallContextData.Value;\n            var values = properties.Values;\n\n            var resultValues = (values != null && values.Count > 0)\n                ? copier.Copy(values)\n                : null;\n            return resultValues;\n        }\n\n        internal static Guid GetReentrancyId(this Message message) => GetReentrancyId(message?.RequestContextData);\n\n        internal static Guid GetReentrancyId(Dictionary<string, object>? contextData)\n        {\n            if (contextData is not { Count: > 0 }) return Guid.Empty;\n            _ = contextData.TryGetValue(RequestContext.CALL_CHAIN_REENTRANCY_HEADER, out var reentrancyId);\n            return reentrancyId is Guid guid ? guid : Guid.Empty;\n        }\n\n        /// <summary>\n        /// Extracts an ActivityContext from request context data if present.\n        /// </summary>\n        internal static ActivityContext? TryGetActivityContext(this Dictionary<string, object>? requestContextData)\n        {\n            if (requestContextData is not { Count: > 0 })\n            {\n                return null;\n            }\n\n            string? traceParent = null;\n            string? traceState = null;\n\n            if (requestContextData.TryGetValue(OpenTelemetryHeaders.TraceParent, out var traceParentObj) && traceParentObj is string tp)\n            {\n                traceParent = tp;\n            }\n\n            if (requestContextData.TryGetValue(OpenTelemetryHeaders.TraceState, out var traceStateObj) && traceStateObj is string ts)\n            {\n                traceState = ts;\n            }\n\n            if (!string.IsNullOrEmpty(traceParent) && ActivityContext.TryParse(traceParent, traceState, isRemote: true, out var parentContext))\n            {\n                return parentContext;\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/RingRange.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a range or set of ranges around a virtual ring where points along the ring are identified using <see cref=\"uint\"/> values.\n    /// </summary>\n    public interface IRingRange\n    {\n        /// <summary>\n        /// Returns a value indicating whether <paramref name=\"value\"/> is within this ring range.\n        /// </summary>\n        /// <param name=\"value\">\n        /// The value to check.\n        /// </param>\n        /// <returns><see langword=\"true\"/> if the reminder is in our responsibility range, <see langword=\"false\"/> otherwise.</returns>\n        bool InRange(uint value);\n\n        /// <summary>\n        /// Returns a value indicating whether <paramref name=\"grainId\"/> is within this ring range.\n        /// </summary>\n        /// <param name=\"grainId\">The value to check.</param>\n        /// <returns><see langword=\"true\"/> if the reminder is in our responsibility range, <see langword=\"false\"/> otherwise.</returns>\n        public sealed bool InRange(GrainId grainId) => InRange(grainId.GetUniformHashCode());\n    }\n\n    // This is the internal interface to be used only by the different range implementations.\n    internal interface IRingRangeInternal : IRingRange\n    {\n        double RangePercentage();\n    }\n\n    /// <summary>\n    /// Represents a single, contiguous range round a virtual ring where points along the ring are identified using <see cref=\"uint\"/> values.\n    /// </summary>\n    /// <seealso cref=\"Orleans.Runtime.IRingRange\" />\n    public interface ISingleRange : IRingRange\n    {\n        /// <summary>\n        /// Gets the exclusive lower bound of the range.\n        /// </summary>\n        uint Begin { get; }\n\n        /// <summary>\n        /// Gets the inclusive upper bound of the range.\n        /// </summary>\n        uint End { get; }\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class SingleRange : IRingRangeInternal, IEquatable<SingleRange>, ISingleRange, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly uint begin;\n\n        [Id(1)]\n        private readonly uint end;\n\n        /// <summary>\n        /// Exclusive\n        /// </summary>\n        public uint Begin { get { return begin; } }\n\n        /// <summary>\n        /// Inclusive\n        /// </summary>\n        public uint End { get { return end; } }\n\n        public SingleRange(uint begin, uint end)\n        {\n            this.begin = begin;\n            this.end = end;\n        }\n\n        /// <summary>\n        /// checks if n is element of (Begin, End], while remembering that the ranges are on a ring\n        /// </summary>\n        /// <param name=\"n\"></param>\n        /// <returns>true if n is in (Begin, End], false otherwise</returns>\n        public bool InRange(uint n)\n        {\n            uint num = n;\n            if (begin < end)\n            {\n                return num > begin && num <= end;\n            }\n            // Begin > End\n            return num > begin || num <= end;\n        }\n\n        public long RangeSize()\n        {\n            if (begin < end)\n            {\n                return end - begin;\n            }\n            return RangeFactory.RING_SIZE - (begin - end);\n        }\n\n        public double RangePercentage() => RangeSize() * (100.0 / RangeFactory.RING_SIZE);\n\n        public bool Equals(SingleRange? other) => other != null && begin == other.begin && end == other.end;\n\n        public override bool Equals(object? obj) => Equals(obj as SingleRange);\n\n        public override int GetHashCode() => HashCode.Combine(GetType(), begin, end);\n\n        public override string ToString() => begin == 0 && end == 0 ? \"<(0 0], Size=x100000000, %Ring=100%>\" : $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            return begin == 0 && end == 0\n                ? destination.TryWrite($\"<(0 0], Size=x100000000, %Ring=100%>\", out charsWritten)\n                : destination.TryWrite($\"<(x{begin:X8} x{end:X8}], Size=x{RangeSize():X8}, %Ring={RangePercentage():0.000}%>\", out charsWritten);\n        }\n\n        internal bool Overlaps(SingleRange other) => Equals(other) || InRange(other.begin) || other.InRange(begin);\n\n        internal SingleRange Merge(SingleRange other)\n        {\n            if ((begin | end) == 0 || (other.begin | other.end) == 0)\n            {\n                return RangeFactory.FullRange;\n            }\n\n            if (Equals(other))\n            {\n                return this;\n            }\n\n            if (InRange(other.begin))\n            {\n                return MergeEnds(other);\n            }\n\n            if (other.InRange(begin))\n            {\n                return other.MergeEnds(this);\n            }\n\n            throw new InvalidOperationException(\"Ranges don't overlap\");\n        }\n\n        // other range begins inside this range, merge it based on where it ends\n        private SingleRange MergeEnds(SingleRange other)\n        {\n            if (begin == other.end)\n            {\n                return RangeFactory.FullRange;\n            }\n\n            if (!InRange(other.end))\n            {\n                return new SingleRange(begin, other.end);\n            }\n\n            if (other.InRange(begin))\n            {\n                return RangeFactory.FullRange;\n            }\n\n            return this;\n        }\n    }\n\n    /// <summary>\n    /// Utility class for creating <see cref=\"IRingRange\" /> values.\n    /// </summary>\n    public static class RangeFactory\n    {\n        /// <summary>\n        /// The ring size.\n        /// </summary>\n        public const long RING_SIZE = (long)uint.MaxValue + 1;\n\n        /// <summary>\n        /// Represents an empty range.\n        /// </summary>\n        private static readonly GeneralMultiRange EmptyRange = new(new());\n        /// <summary>\n        /// Represents a full range.\n        /// </summary>\n        internal static readonly SingleRange FullRange = new(0, 0);\n\n        /// <summary>\n        /// Creates the full range.\n        /// </summary>\n        /// <returns>IRingRange.</returns>\n        public static IRingRange CreateFullRange() => FullRange;\n\n        /// <summary>\n        /// Creates a new <see cref=\"IRingRange\"/> representing the values between the exclusive lower bound, <paramref name=\"begin\"/>, and the inclusive upper bound, <paramref name=\"end\"/>.\n        /// </summary>\n        /// <param name=\"begin\">The exclusive lower bound.</param>\n        /// <param name=\"end\">The inclusive upper bound.</param>\n        /// <returns>A new <see cref=\"IRingRange\"/> representing the values between the exclusive lower bound, <paramref name=\"begin\"/>, and the inclusive upper bound, <paramref name=\"end\"/>.</returns>\n        public static IRingRange CreateRange(uint begin, uint end) => new SingleRange(begin, end);\n\n        /// <summary>\n        /// Creates a new <see cref=\"IRingRange\"/> representing the union of all provided ranges.\n        /// </summary>\n        /// <param name=\"inRanges\">The ranges.</param>\n        /// <returns>A new <see cref=\"IRingRange\"/> representing the union of all provided ranges.</returns>\n        public static IRingRange CreateRange(List<IRingRange> inRanges) => inRanges.Count switch\n        {\n            0 => EmptyRange,\n            1 => inRanges[0],\n            _ => GeneralMultiRange.Create(inRanges)\n        };\n\n        /// <summary>\n        /// Creates equally divided sub-ranges from the provided range and returns one sub-range from that range.\n        /// </summary>\n        /// <param name=\"range\">The range.</param>\n        /// <param name=\"numSubRanges\">The number of sub-ranges.</param>\n        /// <param name=\"mySubRangeIndex\">The index of the sub-range to return.</param>\n        /// <returns>The identified sub-range.</returns>\n        internal static IRingRange GetEquallyDividedSubRange(IRingRange range, int numSubRanges, int mySubRangeIndex)\n            => EquallyDividedMultiRange.GetEquallyDividedSubRange(range, numSubRanges, mySubRangeIndex);\n\n        /// <summary>\n        /// Gets the contiguous sub-ranges represented by the provided range.\n        /// </summary>\n        /// <param name=\"range\">The range.</param>\n        /// <returns>The contiguous sub-ranges represented by the provided range.</returns>\n        public static IEnumerable<ISingleRange> GetSubRanges(IRingRange range) => range switch\n        {\n            ISingleRange single => new[] { single },\n            GeneralMultiRange m => m.Ranges,\n            _ => throw new NotSupportedException(),\n        };\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class GeneralMultiRange : IRingRangeInternal, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly List<SingleRange> ranges;\n\n        [Id(1)]\n        private readonly long rangeSize;\n\n        internal List<SingleRange> Ranges => ranges;\n\n        internal GeneralMultiRange(List<SingleRange> ranges)\n        {\n            Debug.Assert(ranges.Count != 1);\n            this.ranges = ranges;\n            foreach (var r in ranges)\n                rangeSize += r.RangeSize();\n        }\n\n        internal static IRingRange Create(List<IRingRange> inRanges)\n        {\n            var ranges = inRanges.ConvertAll(r => (SingleRange)r);\n            return HasOverlaps() ? Compact() : new GeneralMultiRange(ranges);\n\n            bool HasOverlaps()\n            {\n                var last = ranges[0];\n                for (var i = 1; i < ranges.Count; i++)\n                {\n                    if (last.Overlaps(last = ranges[i])) return true;\n                }\n\n                return false;\n            }\n\n            IRingRange Compact()\n            {\n                var lastIdx = 0;\n                var last = ranges[0];\n                for (var i = 1; i < ranges.Count; i++)\n                {\n                    var r = ranges[i];\n                    if (last.Overlaps(r)) ranges[lastIdx] = last = last.Merge(r);\n                    else ranges[++lastIdx] = last = r;\n                }\n                if (lastIdx == 0) return last;\n                ranges.RemoveRange(++lastIdx, ranges.Count - lastIdx);\n                return new GeneralMultiRange(ranges);\n            }\n        }\n\n        public bool InRange(uint n)\n        {\n            foreach (var s in ranges)\n            {\n                if (s.InRange(n)) return true;\n            }\n            return false;\n        }\n\n        public double RangePercentage() => rangeSize * (100.0 / RangeFactory.RING_SIZE);\n\n        public override string ToString() => ranges.Count == 0 ? \"Empty MultiRange\" : $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            return ranges.Count == 0\n                ? destination.TryWrite($\"Empty MultiRange\", out charsWritten)\n                : destination.TryWrite($\"<MultiRange: Size=x{rangeSize:X8}, %Ring={RangePercentage():0.000}%>\", out charsWritten);\n        }\n    }\n\n    internal static class EquallyDividedMultiRange\n    {\n        private static SingleRange GetEquallyDividedSubRange(SingleRange singleRange, int numSubRanges, int mySubRangeIndex)\n        {\n            var rangeSize = singleRange.RangeSize();\n            uint portion = (uint)(rangeSize / numSubRanges);\n            uint remainder = (uint)(rangeSize - portion * numSubRanges);\n            uint start = singleRange.Begin;\n            for (int i = 0; i < numSubRanges; i++)\n            {\n                // (Begin, End]\n                uint end = unchecked(start + portion);\n                // I want it to overflow on purpose. It will do the right thing.\n                if (remainder > 0)\n                {\n                    end++;\n                    remainder--;\n                }\n                if (i == mySubRangeIndex)\n                    return new SingleRange(start, end);\n                start = end; // nextStart\n            }\n            throw new ArgumentException(nameof(mySubRangeIndex));\n        }\n\n        // Takes a range and divides it into numSubRanges equal ranges and returns the subrange at mySubRangeIndex.\n        public static IRingRange GetEquallyDividedSubRange(IRingRange range, int numSubRanges, int mySubRangeIndex)\n        {\n            if (numSubRanges <= 0) throw new ArgumentOutOfRangeException(nameof(numSubRanges));\n            if ((uint)mySubRangeIndex >= (uint)numSubRanges) throw new ArgumentOutOfRangeException(nameof(mySubRangeIndex));\n\n            if (numSubRanges == 1) return range;\n\n            switch (range)\n            {\n                case SingleRange singleRange:\n                    return GetEquallyDividedSubRange(singleRange, numSubRanges, mySubRangeIndex);\n\n                case GeneralMultiRange multiRange:\n                    switch (multiRange.Ranges.Count)\n                    {\n                        case 0: return multiRange;\n                        default:\n                            // Take each of the single ranges in the multi range and divide each into equal sub ranges.\n                            var singlesForThisIndex = new List<SingleRange>(multiRange.Ranges.Count);\n                            foreach (var singleRange in multiRange.Ranges)\n                                singlesForThisIndex.Add(GetEquallyDividedSubRange(singleRange, numSubRanges, mySubRangeIndex));\n                            return new GeneralMultiRange(singlesForThisIndex);\n                    }\n\n                default: throw new ArgumentOutOfRangeException(nameof(range));\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/RuntimeVersion.cs",
    "content": "using System.Diagnostics;\nusing System.Reflection;\n\nnamespace Orleans.Runtime\n{\n    internal static class RuntimeVersion\n    {\n        /// <summary>\n        /// The full version string of the Orleans runtime, eg: '2012.5.9.51607 Build:12345 Timestamp: 20120509-185359'\n        /// </summary>\n        public static string Current\n        {\n            get\n            {\n                Assembly thisProg = typeof(RuntimeVersion).Assembly;\n                var ApiVersion = thisProg.GetName().Version.ToString();\n                if (string.IsNullOrWhiteSpace(thisProg.Location))\n                {\n                    return ApiVersion;\n                }\n                FileVersionInfo progVersionInfo = FileVersionInfo.GetVersionInfo(thisProg.Location);\n                bool isDebug = IsAssemblyDebugBuild(thisProg);\n                string productVersion = progVersionInfo.ProductVersion + (isDebug ? \" (Debug).\" : \" (Release).\"); // progVersionInfo.IsDebug; does not work\n                return string.IsNullOrEmpty(productVersion) ? ApiVersion : productVersion;\n            }\n        }\n\n        /// <summary>\n        /// Returns a value indicating whether the provided <paramref name=\"assembly\"/> was built in debug mode.\n        /// </summary>\n        /// <param name=\"assembly\">\n        /// The assembly to check.\n        /// </param>\n        /// <returns>\n        /// A value indicating whether the provided assembly was built in debug mode.\n        /// </returns>\n        internal static bool IsAssemblyDebugBuild(Assembly assembly)\n        {\n            foreach (var debuggableAttribute in assembly.GetCustomAttributes<DebuggableAttribute>())\n            {\n                return debuggableAttribute.IsJITTrackingEnabled;\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Runtime/SharedCallbackData.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime;\n\ninternal sealed class SharedCallbackData\n{\n    public readonly Action<Message> Unregister;\n    public readonly ILogger Logger;\n    private TimeSpan _responseTimeout;\n    public long ResponseTimeoutStopwatchTicks;\n\n    public SharedCallbackData(\n        Action<Message> unregister,\n        ILogger logger,\n        TimeSpan responseTimeout,\n        bool cancelOnTimeout,\n        bool waitForCancellationAcknowledgement,\n        IGrainCallCancellationManager cancellationManager)\n    {\n        Unregister = unregister;\n        Logger = logger;\n        ResponseTimeout = responseTimeout;\n        CancelRequestOnTimeout = cancelOnTimeout;\n        WaitForCancellationAcknowledgement = waitForCancellationAcknowledgement;\n        CancellationManager = cancellationManager;\n    }\n\n    public TimeSpan ResponseTimeout\n    {\n        get => _responseTimeout;\n        set\n        {\n            _responseTimeout = value;\n            ResponseTimeoutStopwatchTicks = (long)(value.TotalSeconds * Stopwatch.Frequency);\n        }\n    }\n\n    public IGrainCallCancellationManager CancellationManager { get; internal set; }\n\n    public bool CancelRequestOnTimeout { get; }\n\n    public bool WaitForCancellationAcknowledgement { get; }\n}"
  },
  {
    "path": "src/Orleans.Core/Runtime/SiloStatus.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Possible statuses of a silo.\n    /// </summary>\n    [GenerateSerializer]\n    public enum SiloStatus\n    {\n        /// <summary>\n        /// No known status.\n        /// </summary>\n        None = 0,\n\n        /// <summary>\n        /// This silo was just created, but not started yet.\n        /// </summary>\n        Created = 1,\n\n        /// <summary>\n        /// This silo has just started, but not ready yet. It is attempting to join the cluster.\n        /// </summary>\n        Joining = 2,         \n\n        /// <summary>\n        /// This silo is alive and functional.\n        /// </summary>\n        Active = 3,\n\n        /// <summary>\n        /// This silo is shutting itself down.\n        /// </summary>\n        ShuttingDown = 4,    \n\n        /// <summary>\n        /// This silo is stopping itself down.\n        /// </summary>\n        Stopping = 5,\n\n        /// <summary>\n        /// This silo is deactivated/considered to be dead.\n        /// </summary>\n        Dead = 6\n    }\n\n    /// <summary>\n    /// Extensions for <see cref=\"SiloStatus\"/>.\n    /// </summary>\n    public static class SiloStatusExtensions\n    {\n        /// <summary>\n        /// Return true if this silo is currently terminating: ShuttingDown, Stopping or Dead.\n        /// </summary>\n        /// <param name=\"siloStatus\">The silo status.</param>\n        /// <returns><c>true</c> if the specified silo status is terminating; otherwise, <c>false</c>.</returns>\n        public static bool IsTerminating(this SiloStatus siloStatus)\n        {\n            return siloStatus == SiloStatus.ShuttingDown || siloStatus == SiloStatus.Stopping || siloStatus == SiloStatus.Dead;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Serialization/OrleansJsonSerializationBinder.cs",
    "content": "using System;\nusing Newtonsoft.Json.Serialization;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Implementation of <see cref=\"ISerializationBinder\"/> which resolves types using a <see cref=\"TypeResolver\"/>.\n    /// </summary>\n    public class OrleansJsonSerializationBinder : DefaultSerializationBinder\n    {\n        private readonly TypeResolver typeResolver;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansJsonSerializationBinder\"/> class.\n        /// </summary>\n        /// <param name=\"typeResolver\">The type resolver.</param>\n        public OrleansJsonSerializationBinder(TypeResolver typeResolver)\n        {\n            this.typeResolver = typeResolver;\n        }\n\n        /// <inheritdoc />\n        public override Type BindToType(string assemblyName, string typeName)\n        {\n            var fullName = !string.IsNullOrWhiteSpace(assemblyName) ? typeName + ',' + assemblyName : typeName;\n            if (typeResolver.TryResolveType(fullName, out var type)) return type;\n\n            return base.BindToType(assemblyName, typeName);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Serialization/OrleansJsonSerializer.cs",
    "content": "using System;\nusing System.Net;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Runtime;\nusing Orleans.GrainReferences;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Serialization\n{\n\n    /// <summary>\n    /// Utility class for configuring <see cref=\"JsonSerializerSettings\"/> to support Orleans types.\n    /// </summary>\n    public class OrleansJsonSerializer\n    {\n        public const string UseFullAssemblyNamesProperty = \"UseFullAssemblyNames\";\n        public const string IndentJsonProperty = \"IndentJSON\";\n        public const string TypeNameHandlingProperty = \"TypeNameHandling\";\n        private readonly JsonSerializerSettings settings;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansJsonSerializer\"/> class.\n        /// </summary>\n        public OrleansJsonSerializer(IOptions<OrleansJsonSerializerOptions> options)\n        {\n            this.settings = options.Value.JsonSerializerSettings;\n        }\n\n        /// <summary>\n        /// Deserializes an object of the specified expected type from the provided input.\n        /// </summary>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"input\">The input.</param>\n        /// <returns>The deserialized object.</returns>\n        public object Deserialize(Type expectedType, string input)\n        {\n            if (string.IsNullOrWhiteSpace(input))\n            {\n                return null;\n            }\n\n            return JsonConvert.DeserializeObject(input, expectedType, this.settings);\n        }\n\n        /// <summary>\n        /// Serializes an object to a JSON string.\n        /// </summary>\n        /// <param name=\"item\">The object to serialize.</param>\n        /// <param name=\"expectedType\">The type the deserializer should expect.</param>\n        public string Serialize(object item, Type expectedType) => JsonConvert.SerializeObject(item, expectedType, this.settings);\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"IPAddress\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class IPAddressConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType)\n        {\n            return (objectType == typeof(IPAddress));\n        }\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            IPAddress ip = (IPAddress)value;\n            writer.WriteValue(ip.ToString());\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            JToken token = JToken.Load(reader);\n            return IPAddress.Parse(token.Value<string>());\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"GrainId\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class GrainIdConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType) => objectType == typeof(GrainId);\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            GrainId id = (GrainId)value;\n            writer.WriteStartObject();\n            writer.WritePropertyName(\"Type\");\n            writer.WriteValue(id.Type.ToString());\n            writer.WritePropertyName(\"Key\");\n            writer.WriteValue(id.Key.ToString());\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            JObject jo = JObject.Load(reader);\n            GrainId grainId = GrainId.Create(jo[\"Type\"].ToObject<string>(), jo[\"Key\"].ToObject<string>());\n            return grainId;\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"ActivationId\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class ActivationIdConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType) => objectType == typeof(ActivationId);\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            ActivationId id = (ActivationId)value;\n            writer.WriteValue(id.ToParsableString());\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            return reader.Value switch\n            {\n                string { Length: > 0 } str => ActivationId.FromParsableString(str),\n                _ => default\n            };\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"SiloAddress\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class SiloAddressJsonConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType)\n        {\n            return (objectType == typeof(SiloAddress));\n        }\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            SiloAddress addr = (SiloAddress)value;\n            writer.WriteValue(addr.ToParsableString());\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            switch (reader.TokenType)\n            {\n                case JsonToken.StartObject:\n                    var jo = JObject.Load(reader);\n                    return SiloAddress.FromParsableString(jo[\"SiloAddress\"].ToObject<string>());\n                case JsonToken.String:\n                    return SiloAddress.FromParsableString(reader.Value as string);\n            }\n\n            return null;\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"MembershipVersion\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class MembershipVersionJsonConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType) => objectType == typeof(MembershipVersion);\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            MembershipVersion typedValue = (MembershipVersion)value;\n            writer.WriteValue(typedValue.Value);\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            return reader.Value switch\n            {\n                long l => new MembershipVersion(l),\n                _ => default\n            };\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"UniqueKey\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class UniqueKeyConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType)\n        {\n            return (objectType == typeof(UniqueKey));\n        }\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            UniqueKey key = (UniqueKey)value;\n            writer.WriteStartObject();\n            writer.WritePropertyName(\"UniqueKey\");\n            writer.WriteValue(key.ToHexString());\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            JObject jo = JObject.Load(reader);\n            UniqueKey addr = UniqueKey.Parse(jo[\"UniqueKey\"].ToObject<string>().AsSpan());\n            return addr;\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"IPEndPoint\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class IPEndPointConverter : JsonConverter\n    {\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType)\n        {\n            return (objectType == typeof(IPEndPoint));\n        }\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            IPEndPoint ep = (IPEndPoint)value;\n            writer.WriteStartObject();\n            writer.WritePropertyName(\"Address\");\n            serializer.Serialize(writer, ep.Address);\n            writer.WritePropertyName(\"Port\");\n            writer.WriteValue(ep.Port);\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            JObject jo = JObject.Load(reader);\n            IPAddress address = jo[\"Address\"].ToObject<IPAddress>(serializer);\n            int port = jo[\"Port\"].Value<int>();\n            return new IPEndPoint(address, port);\n        }\n    }\n\n    /// <summary>\n    /// <see cref=\"Newtonsoft.Json.JsonConverter\" /> implementation for <see cref=\"GrainReference\"/>.\n    /// </summary>\n    /// <seealso cref=\"Newtonsoft.Json.JsonConverter\" />\n    public class GrainReferenceJsonConverter : JsonConverter\n    {\n        private static readonly Type AddressableType = typeof(IAddressable);\n        private readonly GrainReferenceActivator referenceActivator;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceJsonConverter\"/> class.\n        /// </summary>\n        /// <param name=\"referenceActivator\">The grain reference activator.</param>\n        public GrainReferenceJsonConverter(GrainReferenceActivator referenceActivator)\n        {\n            this.referenceActivator = referenceActivator;\n        }\n\n        /// <inheritdoc/>\n        public override bool CanConvert(Type objectType)\n        {\n            return AddressableType.IsAssignableFrom(objectType);\n        }\n\n        /// <inheritdoc/>\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            var val = ((IAddressable)value).AsReference();  \n            writer.WriteStartObject();\n            writer.WritePropertyName(\"Id\");\n            writer.WriteStartObject();\n            writer.WritePropertyName(\"Type\");\n            writer.WriteValue(val.GrainId.Type.ToString());\n            writer.WritePropertyName(\"Key\");\n            writer.WriteValue(val.GrainId.Key.ToString());\n            writer.WriteEndObject();\n            writer.WritePropertyName(\"Interface\");\n            writer.WriteValue(val.InterfaceType.ToString());\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            JObject jo = JObject.Load(reader);\n            var id = jo[\"Id\"];\n            GrainId grainId = GrainId.Create(id[\"Type\"].ToObject<string>(), id[\"Key\"].ToObject<string>());\n            var encodedInterface = jo[\"Interface\"].ToString();\n            var iface = string.IsNullOrWhiteSpace(encodedInterface) ? default : GrainInterfaceType.Create(encodedInterface);\n            return this.referenceActivator.CreateReference(grainId, iface);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Serialization/OrleansJsonSerializerOptions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\n\nnamespace Orleans.Serialization\n{\n    public class OrleansJsonSerializerOptions\n    {\n        public JsonSerializerSettings JsonSerializerSettings { get; set; }\n\n        public OrleansJsonSerializerOptions()\n        {\n            JsonSerializerSettings = OrleansJsonSerializerSettings.GetDefaultSerializerSettings();\n        }\n    }\n\n    public class ConfigureOrleansJsonSerializerOptions : IPostConfigureOptions<OrleansJsonSerializerOptions>\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        public ConfigureOrleansJsonSerializerOptions(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        public void PostConfigure(string name, OrleansJsonSerializerOptions options)\n        {\n            OrleansJsonSerializerSettings.Configure(_serviceProvider, options.JsonSerializerSettings);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Serialization/OrleansJsonSerializerSettings.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing Orleans.GrainReferences;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Serialization\n{\n    public static class OrleansJsonSerializerSettings\n    {\n        internal static JsonSerializerSettings GetDefaultSerializerSettings()\n        {\n            return new JsonSerializerSettings\n            {\n                TypeNameHandling = TypeNameHandling.All,\n                PreserveReferencesHandling = PreserveReferencesHandling.Objects,\n                DateFormatHandling = DateFormatHandling.IsoDateFormat,\n                DefaultValueHandling = DefaultValueHandling.Ignore,\n                MissingMemberHandling = MissingMemberHandling.Ignore,\n                NullValueHandling = NullValueHandling.Ignore,\n                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,\n                TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,\n                Formatting = Formatting.None,\n                SerializationBinder = null,\n            };\n        }\n\n        /// <summary>\n        /// Returns the default serializer settings.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service provider.\n        /// </param>\n        /// <returns>The default serializer settings.</returns>\n        public static JsonSerializerSettings GetDefaultSerializerSettings(IServiceProvider services)\n        {\n            var settings = GetDefaultSerializerSettings();\n            Configure(services, settings);\n            return settings;\n        }\n\n        internal static void Configure(IServiceProvider services, JsonSerializerSettings jsonSerializerSettings)\n        {\n            if (jsonSerializerSettings.SerializationBinder == null)\n            {\n                var typeResolver = services.GetRequiredService<TypeResolver>();\n                jsonSerializerSettings.SerializationBinder = new OrleansJsonSerializationBinder(typeResolver);\n            }\n\n            jsonSerializerSettings.Converters.Add(new IPAddressConverter());\n            jsonSerializerSettings.Converters.Add(new IPEndPointConverter());\n            jsonSerializerSettings.Converters.Add(new GrainIdConverter());\n            jsonSerializerSettings.Converters.Add(new ActivationIdConverter());\n            jsonSerializerSettings.Converters.Add(new SiloAddressJsonConverter());\n            jsonSerializerSettings.Converters.Add(new MembershipVersionJsonConverter());\n            jsonSerializerSettings.Converters.Add(new UniqueKeyConverter());\n            jsonSerializerSettings.Converters.Add(new GrainReferenceJsonConverter(services.GetRequiredService<GrainReferenceActivator>()));\n        }\n\n        /// <summary>\n        /// Updates the provided serializer settings with the specified options.\n        /// </summary>\n        /// <param name=\"settings\">The settings.</param>\n        /// <param name=\"useFullAssemblyNames\">if set to <c>true</c>, use full assembly-qualified names when formatting type names.</param>\n        /// <param name=\"indentJson\">if set to <c>true</c>, indent the formatted JSON.</param>\n        /// <param name=\"typeNameHandling\">The type name handling options.</param>\n        /// <returns>The provided serializer settings.</returns>\n        public static JsonSerializerSettings UpdateSerializerSettings(JsonSerializerSettings settings, bool useFullAssemblyNames, bool indentJson, TypeNameHandling? typeNameHandling)\n        {\n            if (useFullAssemblyNames)\n            {\n                settings.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full;\n            }\n\n            if (indentJson)\n            {\n                settings.Formatting = Formatting.Indented;\n            }\n\n            if (typeNameHandling.HasValue)\n            {\n                settings.TypeNameHandling = typeNameHandling.Value;\n            }\n\n            return settings;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Statistics/EnvironmentStatisticsProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Metrics;\nusing System.Diagnostics.Tracing;\nusing Orleans.Runtime;\n\nnamespace Orleans.Statistics;\n\n#nullable enable\ninternal sealed class EnvironmentStatisticsProvider : IEnvironmentStatisticsProvider, IDisposable\n{\n    private const float OneKiloByte = 1024f;\n\n    private long _availableMemoryBytes;\n    private long _maximumAvailableMemoryBytes;\n\n    private readonly EventCounterListener _eventCounterListener = new();\n\n    [SuppressMessage(\"CodeQuality\", \"IDE0052:Remove unread private members\", Justification = \"Used for memory-dump debugging.\")]\n    private readonly ObservableCounter<long> _availableMemoryCounter;\n\n    [SuppressMessage(\"CodeQuality\", \"IDE0052:Remove unread private members\", Justification = \"Used for memory-dump debugging.\")]\n    private readonly ObservableCounter<long> _maximumAvailableMemoryCounter;\n\n    private readonly DualModeKalmanFilter _cpuUsageFilter = new();\n    private readonly DualModeKalmanFilter _memoryUsageFilter = new();\n\n    public EnvironmentStatisticsProvider()\n    {\n        GC.Collect(0, GCCollectionMode.Forced, true); // we make sure the GC structure wont be empty, also performing a blocking GC guarantees immediate collection.\n\n        _availableMemoryCounter = Instruments.Meter.CreateObservableCounter(InstrumentNames.RUNTIME_MEMORY_AVAILABLE_MEMORY_MB, () => (long)(_availableMemoryBytes / OneKiloByte / OneKiloByte), unit: \"MB\");\n        _maximumAvailableMemoryCounter = Instruments.Meter.CreateObservableCounter(InstrumentNames.RUNTIME_MEMORY_TOTAL_PHYSICAL_MEMORY_MB, () => (long)(_maximumAvailableMemoryBytes / OneKiloByte / OneKiloByte), unit: \"MB\");\n    }\n\n    /// <inheritdoc />\n    public EnvironmentStatistics GetEnvironmentStatistics()\n    {\n        var cpuUsage = _eventCounterListener.CpuUsage;\n\n        var memoryInfo = GC.GetGCMemoryInfo();\n        var maximumAvailableMemoryBytes = memoryInfo.TotalAvailableMemoryBytes;\n        var memoryUsage = Math.Clamp(memoryInfo.TotalCommittedBytes - memoryInfo.FragmentedBytes, 0, maximumAvailableMemoryBytes);\n        var availableMemory = maximumAvailableMemoryBytes - memoryUsage;\n        var filteredCpuUsage = _cpuUsageFilter.Filter(cpuUsage);\n        var filteredMemoryUsage = (long)_memoryUsageFilter.Filter(memoryUsage);\n        var filteredAvailableMemory = maximumAvailableMemoryBytes - filteredMemoryUsage;\n\n        var result = new EnvironmentStatistics(\n            cpuUsagePercentage: filteredCpuUsage,\n            rawCpuUsagePercentage: cpuUsage,\n            memoryUsageBytes: filteredMemoryUsage,\n            rawMemoryUsageBytes: memoryUsage,\n            availableMemoryBytes: filteredAvailableMemory,\n            rawAvailableMemoryBytes: availableMemory,\n            maximumAvailableMemoryBytes: maximumAvailableMemoryBytes);\n\n        _maximumAvailableMemoryBytes = result.MaximumAvailableMemoryBytes;\n        _availableMemoryBytes = result.RawAvailableMemoryBytes;\n        return result;\n    }\n\n    public void Dispose() => _eventCounterListener.Dispose();\n\n    private sealed class EventCounterListener : EventListener\n    {\n        public float CpuUsage { get; private set; }\n\n        protected override void OnEventSourceCreated(EventSource source)\n        {\n            if (source.Name.Equals(\"System.Runtime\"))\n            {\n                Dictionary<string, string?>? refreshInterval = new() { [\"EventCounterIntervalSec\"] = \"1\" };\n                EnableEvents(source, EventLevel.Informational, (EventKeywords)(-1), refreshInterval);\n            }\n        }\n\n        protected override void OnEventWritten(EventWrittenEventArgs eventData)\n        {\n            if (\"EventCounters\".Equals(eventData.EventName) && eventData.Payload is { } payload)\n            {\n                for (var i = 0; i < payload.Count; i++)\n                {\n                    if (payload[i] is IDictionary<string, object?> eventPayload\n                        && eventPayload.TryGetValue(\"Name\", out var name)\n                        && \"cpu-usage\".Equals(name)\n                        && eventPayload.TryGetValue(\"Mean\", out var mean)\n                        && mean is double value)\n                    {\n                        CpuUsage = Math.Clamp((float)value, 0f, 100f);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    // See: https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/\n\n    // The rationale behind using a cooperative dual-mode KF, is that we want the input signal to follow a trajectory that\n    // decays with a slower rate than the original one, but also tracks the signal in case of signal increases\n    // (which represent potential of overloading). Both are important, but they are inversely correlated to each other.\n    private sealed class DualModeKalmanFilter\n    {\n        private const float SlowProcessNoiseCovariance = 0f;\n        private const float FastProcessNoiseCovariance = 0.01f;\n\n        private KalmanFilter _slowFilter = new();\n        private KalmanFilter _fastFilter = new();\n\n        private FilterRegime _regime = FilterRegime.Slow;\n\n        private enum FilterRegime\n        {\n            Slow,\n            Fast\n        }\n\n        public float Filter(float measurement)\n        {\n            float slowEstimate = _slowFilter.Filter(measurement, SlowProcessNoiseCovariance);\n            float fastEstimate = _fastFilter.Filter(measurement, FastProcessNoiseCovariance);\n\n            if (measurement > slowEstimate)\n            {\n                if (_regime == FilterRegime.Slow)\n                {\n                    _regime = FilterRegime.Fast;\n                    _fastFilter.SetState(measurement, 0f);\n                    fastEstimate = _fastFilter.Filter(measurement, FastProcessNoiseCovariance);\n                }\n\n                return fastEstimate;\n            }\n            else\n            {\n                if (_regime == FilterRegime.Fast)\n                {\n                    _regime = FilterRegime.Slow;\n                    _slowFilter.SetState(_fastFilter.PriorEstimate, _fastFilter.PriorErrorCovariance);\n                    slowEstimate = _slowFilter.Filter(measurement, SlowProcessNoiseCovariance);\n                }\n\n                return slowEstimate;\n            }\n        }\n\n        private struct KalmanFilter()\n        {\n            public float PriorEstimate { get; private set; } = 0f;\n            public float PriorErrorCovariance { get; private set; } = 1f;\n\n            public void SetState(float estimate, float errorCovariance)\n            {\n                PriorEstimate = estimate;\n                PriorErrorCovariance = errorCovariance;\n            }\n\n            public float Filter(float measurement, float processNoiseCovariance)\n            {\n                float estimate = PriorEstimate;\n                float errorCovariance = PriorErrorCovariance + processNoiseCovariance;\n\n                float gain = errorCovariance / (errorCovariance + 1f);\n                float newEstimate = estimate + gain * (measurement - estimate);\n                float newErrorCovariance = (1f - gain) * errorCovariance;\n\n                PriorEstimate = newEstimate;\n                PriorErrorCovariance = newErrorCovariance;\n\n                return newEstimate;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Statistics/GrainCountStatistics.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Centralized statistics on per-grain-type activation counts.\n/// </summary>\ninternal class GrainCountStatistics\n{\n    public IEnumerable<KeyValuePair<string, long>> GetSimpleGrainStatistics()\n    {\n        return GrainMetricsListener\n            .GrainCounts\n            .Select(s => new KeyValuePair<string, long>(s.Key, s.Value))\n            .Where(p => p.Value > 0);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Statistics/GrainMetricsListener.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\ninternal static class GrainMetricsListener\n{\n    internal static readonly ConcurrentDictionary<string, int> GrainCounts = new();\n    private static readonly MeterListener MeterListener = new();\n    static GrainMetricsListener()\n    {\n        MeterListener.InstrumentPublished = (instrument, listener) =>\n        {\n            if (instrument.Name == InstrumentNames.GRAIN_COUNTS)\n            {\n                listener.EnableMeasurementEvents(instrument);\n            }\n        };\n        MeterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);\n    }\n\n    internal static void Start()\n    {\n        MeterListener.Start();\n    }\n\n    // Alternatives:\n    // 1. Use existing *Statistics counters\n    // 2. Copy source code from System.Diagnostics.Metrics.AggregationManager\n    private static void OnMeasurementRecorded(Instrument instrument, int measurement, ReadOnlySpan<KeyValuePair<string, object>> tags, object state)\n    {\n        var typeTag = tags[0];\n        var grainType = (string)typeTag.Value;\n        if (measurement == 1)\n        {\n            GrainCounts.AddOrUpdate(grainType, 1, (k, v) => Interlocked.Increment(ref v));\n        }\n        else if (measurement == -1)\n        {\n            GrainCounts.AddOrUpdate(grainType, -1, (k, v) => Interlocked.Decrement(ref v));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Statistics/OldEnvironmentStatistics.cs",
    "content": "using System;\n\nnamespace Orleans.Statistics;\n\n[Obsolete(\"Used only until the interfaces that it implements are removed from the codebase\")]\ninternal sealed class OldEnvironmentStatistics(IEnvironmentStatisticsProvider statistics) : IAppEnvironmentStatistics, IHostEnvironmentStatistics\n{\n    public float? CpuUsage => statistics.GetEnvironmentStatistics().FilteredCpuUsagePercentage;\n    public long? MemoryUsage => statistics.GetEnvironmentStatistics().FilteredMemoryUsageBytes;\n    public long? AvailableMemory => statistics.GetEnvironmentStatistics().FilteredAvailableMemoryBytes;\n    public long? TotalPhysicalMemory => statistics.GetEnvironmentStatistics().MaximumAvailableMemoryBytes;\n}\n"
  },
  {
    "path": "src/Orleans.Core/Statistics/SiloRuntimeMetricsListener.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Linq;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\n// Can not use MetricsEventSource because it only supports single listener.\npublic static class SiloRuntimeMetricsListener\n{\n    private static readonly MeterListener MeterListener = new();\n\n    private static long _connectedClientCount;\n    public static long ConnectedClientCount => _connectedClientCount;\n    private static long _messageReceivedTotal;\n    public static long MessageReceivedTotal => _messageReceivedTotal;\n    private static long _messageSentTotal;\n    public static long MessageSentTotal => _messageSentTotal;\n\n    private static readonly string[] MetricNames =\n    {\n        // orleans\n        InstrumentNames.GATEWAY_CONNECTED_CLIENTS,\n        InstrumentNames.MESSAGING_RECEIVED_MESSAGES_SIZE,\n    };\n\n    static SiloRuntimeMetricsListener()\n    {\n        MeterListener.InstrumentPublished = (instrument, listener) =>\n        {\n            if (instrument.Meter != Instruments.Meter)\n            {\n                return;\n            }\n\n            if (MetricNames.Contains(instrument.Name))\n            {\n                listener.EnableMeasurementEvents(instrument);\n            }\n        };\n        MeterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);\n    }\n\n    internal static void Start()\n    {\n        MeterListener.Start();\n    }\n\n    private static void OnMeasurementRecorded(Instrument instrument, int measurement, ReadOnlySpan<KeyValuePair<string, object>> tags, object state)\n    {\n        if (instrument == MessagingInstruments.ConnectedClient)\n        {\n            Interlocked.Add(ref _connectedClientCount, measurement);\n        }\n        if (instrument == MessagingInstruments.MessageReceivedSizeHistogram)\n        {\n            Interlocked.Add(ref _messageReceivedTotal, measurement);\n        }\n        if (instrument == MessagingInstruments.MessageSentSizeHistogram)\n        {\n            Interlocked.Add(ref _messageSentTotal, measurement);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Statistics/SiloRuntimeStatistics.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Core.Messaging;\nusing Orleans.Statistics;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Snapshot of current runtime statistics for a silo\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class SiloRuntimeStatistics\n    {\n        /// <summary>\n        /// Total number of activations in a silo.\n        /// </summary>\n        [Id(0)]\n        public int ActivationCount { get; }\n\n        /// <summary>\n        /// Number of activations in a silo that have been recently used.\n        /// </summary>\n        [Id(1)]\n        public int RecentlyUsedActivationCount { get; }\n\n        /// <summary>\n        /// The CPU utilization.\n        /// </summary>\n        [Id(2), Obsolete($\"The will be removed, use {nameof(EnvironmentStatistics)}.{nameof(EnvironmentStatistics.FilteredCpuUsagePercentage)} instead.\", error: false)]\n        public float? CpuUsage { get; }\n\n        /// <summary>\n        /// The amount of memory available in the silo [bytes].\n        /// </summary>\n        [Id(3), Obsolete($\"The will be removed, use {nameof(EnvironmentStatistics)}.{nameof(EnvironmentStatistics.FilteredAvailableMemoryBytes)} instead.\", error: false)]\n        public float? AvailableMemory { get; }\n\n        /// <summary>\n        /// The used memory size.\n        /// </summary>\n        [Id(4), Obsolete($\"The will be removed, use {nameof(EnvironmentStatistics)}.{nameof(EnvironmentStatistics.FilteredMemoryUsageBytes)} instead.\", error: false)]\n        public long? MemoryUsage { get; }\n\n        /// <summary>\n        /// The total physical memory available [bytes].\n        /// </summary>\n        [Id(5), Obsolete($\"The will be removed, use {nameof(EnvironmentStatistics)}.{nameof(EnvironmentStatistics.MaximumAvailableMemoryBytes)} instead.\", error: false)]\n        public long? TotalPhysicalMemory { get; }\n\n        /// <summary>\n        /// Is this silo overloaded.\n        /// </summary>\n        [Id(6)]\n        public bool IsOverloaded { get; }\n\n        /// <summary>\n        /// The number of clients currently connected to that silo.\n        /// </summary>\n        [Id(7)]\n        public long ClientCount { get; }\n\n        /// <summary>\n        /// The number of messages received by that silo.\n        /// </summary>\n        [Id(8)]\n        public long ReceivedMessages { get; }\n\n        /// <summary>\n        /// The number of messages sent by that silo.\n        /// </summary>\n        [Id(9)]\n        public long SentMessages { get; }\n\n        /// <summary>\n        /// The DateTime when this statistics was created.\n        /// </summary>\n        [Id(10)]\n        public DateTime DateTime { get; }\n\n        [Id(11)]\n        public EnvironmentStatistics EnvironmentStatistics { get; }\n\n        internal SiloRuntimeStatistics(\n            int activationCount,\n            int recentlyUsedActivationCount,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            DateTime dateTime)\n        {\n            ActivationCount = activationCount;\n            RecentlyUsedActivationCount = recentlyUsedActivationCount;\n            ClientCount = SiloRuntimeMetricsListener.ConnectedClientCount;      \n            ReceivedMessages = SiloRuntimeMetricsListener.MessageReceivedTotal;\n            SentMessages = SiloRuntimeMetricsListener.MessageSentTotal;\n            DateTime = dateTime;\n\n            var statistics = environmentStatisticsProvider.GetEnvironmentStatistics();\n\n            EnvironmentStatistics = statistics;\n            IsOverloaded = loadSheddingOptions.Value.LoadSheddingEnabled && OverloadDetectionLogic.IsOverloaded(ref statistics, loadSheddingOptions.Value);\n\n#pragma warning disable 618\n            CpuUsage = statistics.FilteredCpuUsagePercentage;\n            MemoryUsage = statistics.FilteredMemoryUsageBytes;\n            AvailableMemory = statistics.FilteredAvailableMemoryBytes;\n            TotalPhysicalMemory = statistics.MaximumAvailableMemoryBytes;\n#pragma warning restore 618\n        }\n\n        public override string ToString() => @$\"SiloRuntimeStatistics: ActivationCount={ActivationCount} RecentlyUsedActivationCount={RecentlyUsedActivationCount\n            } CpuUsagePercentage={EnvironmentStatistics.FilteredCpuUsagePercentage} MemoryUsageBytes={EnvironmentStatistics.FilteredMemoryUsageBytes\n            } AvailableMemory={EnvironmentStatistics.FilteredAvailableMemoryBytes} MaximumAvailableMemoryBytes={EnvironmentStatistics.MaximumAvailableMemoryBytes\n            } IsOverloaded={IsOverloaded} ClientCount={ClientCount} ReceivedMessages={ReceivedMessages} SentMessages={SentMessages} DateTime={DateTime}\";\n    }\n\n    /// <summary>\n    /// Simple snapshot of current statistics for a given grain type on a given silo.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class SimpleGrainStatistic\n    {\n        /// <summary>\n        /// The type of the grain for this SimpleGrainStatistic.\n        /// </summary>\n        [Id(0)]\n        public string GrainType { get; init; }\n\n        /// <summary>\n        /// The silo address for this SimpleGrainStatistic.\n        /// </summary>\n        [Id(1)]\n        public SiloAddress SiloAddress { get; init; }\n\n        /// <summary>\n        /// The number of activations of this grain type on this given silo.\n        /// </summary>\n        [Id(2)]\n        public int ActivationCount { get; init; }\n\n        /// <summary>\n        /// Returns the string representation of this SimpleGrainStatistic.\n        /// </summary>\n        public override string ToString() => $\"SimpleGrainStatistic: GrainType={GrainType} Silo={SiloAddress} NumActivations={ActivationCount} \";\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class DetailedGrainStatistic\n    {\n        /// <summary>\n        /// The type of the grain for this DetailedGrainStatistic.\n        /// </summary>\n        [Id(0)]\n        public string GrainType { get; init; }\n\n        /// <summary>\n        /// The silo address for this DetailedGrainStatistic.\n        /// </summary>\n        [Id(1)]\n        public SiloAddress SiloAddress { get; init; }\n\n        /// <summary>\n        /// Unique Id for the grain.\n        /// </summary>\n        [Id(2)]\n        public GrainId GrainId { get; init; }\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class DetailedGrainReport\n    {\n        [Id(0)]\n        public GrainId Grain { get; init; }\n\n        /// <summary>silo on which these statistics come from</summary>\n        [Id(1)]\n        public SiloAddress SiloAddress { get; init; }\n\n        /// <summary>silo on which these statistics come from</summary>\n        [Id(2)]\n        public string SiloName { get; init; }\n\n        /// <summary>activation addresses in the local directory cache</summary>\n        [Id(3)]\n        public GrainAddress LocalCacheActivationAddress { get; init; }\n\n        /// <summary>activation addresses in the local directory.</summary>\n        [Id(4)]\n        public GrainAddress LocalDirectoryActivationAddress { get; init; }\n\n        /// <summary>primary silo for this grain</summary>\n        [Id(5)]\n        public SiloAddress PrimaryForGrain { get; init; }\n\n        /// <summary>the name of the class that implements this grain.</summary>\n        [Id(6)]\n        public string GrainClassTypeName { get; init; }\n\n        /// <summary>activation on this silo</summary>\n        [Id(7)]\n        public string LocalActivation { get; init; }\n\n        public override string ToString() => @$\"{Environment.NewLine\n            }**DetailedGrainReport for grain {Grain} from silo {SiloName} SiloAddress={SiloAddress}{Environment.NewLine\n            }   LocalCacheActivationAddresses={LocalCacheActivationAddress}{Environment.NewLine\n            }   LocalDirectoryActivationAddresses={LocalDirectoryActivationAddress}{Environment.NewLine\n            }   PrimaryForGrain={PrimaryForGrain}{Environment.NewLine\n            }   GrainClassTypeName={GrainClassTypeName}{Environment.NewLine\n            }   LocalActivation:{Environment.NewLine\n            }{LocalActivation}.{Environment.NewLine}\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/SystemTargetInterfaces/IDeploymentLoadPublisher.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Concurrency;\n\nnamespace Orleans.Runtime\n{\n    internal interface IDeploymentLoadPublisher : ISystemTarget\n    {\n        [OneWay]\n        Task UpdateRuntimeStatistics(SiloAddress siloAddress, SiloRuntimeStatistics siloStats);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/SystemTargetInterfaces/IManagementGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Providers;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Interface for system management functions of silos,\n    /// exposed as a grain for receiving remote requests / commands.\n    /// </summary>\n    public interface IManagementGrain : IGrainWithIntegerKey, IVersionManager\n    {\n        /// <summary>\n        /// Get the list of silo hosts and statuses currently known about in this cluster.\n        /// </summary>\n        /// <param name=\"onlyActive\">Whether data on just current active silos should be returned,\n        /// or by default data for all current and previous silo instances [including those in Joining or Dead status].</param>\n        /// <returns>The hosts and their corresponding statuses.</returns>\n        Task<Dictionary<SiloAddress, SiloStatus>> GetHosts(bool onlyActive = false);\n\n        /// <summary>\n        /// Get the list of silo hosts and membership information currently known about in this cluster.\n        /// </summary>\n        /// <param name=\"onlyActive\">Whether data on just current active silos should be returned,\n        /// or by default data for all current and previous silo instances [including those in Joining or Dead status].</param>\n        /// <returns>The host entries.</returns>\n        Task<MembershipEntry[]> GetDetailedHosts(bool onlyActive = false);\n\n        /// <summary>\n        /// Perform a run of the .NET garbage collector in the specified silos.\n        /// </summary>\n        /// <param name=\"hostsIds\">List of silos this command is to be sent to.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task ForceGarbageCollection(SiloAddress[] hostsIds);\n\n        /// <summary>Perform a run of the Orleans activation collector in the specified silos.</summary>\n        /// <param name=\"hostsIds\">List of silos this command is to be sent to.</param>\n        /// <param name=\"ageLimit\">Maximum idle time of activations to be collected.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task ForceActivationCollection(SiloAddress[] hostsIds, TimeSpan ageLimit);\n\n        /// <summary>\n        /// Forces activation collection.\n        /// </summary>\n        /// <param name=\"ageLimit\">The age limit. Grains which have been idle for longer than this period of time will be eligible for collection.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task ForceActivationCollection(TimeSpan ageLimit);\n\n        /// <summary>Perform a run of the silo statistics collector in the specified silos.</summary>\n        /// <param name=\"siloAddresses\">List of silos this command is to be sent to.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task ForceRuntimeStatisticsCollection(SiloAddress[] siloAddresses);\n\n        /// <summary>\n        /// Return the most recent silo runtime statistics information for the specified silos.\n        /// </summary>\n        /// <param name=\"hostsIds\">List of silos this command is to be sent to.</param>\n        /// <returns>Runtime statistics from the specified hosts.</returns>\n        Task<SiloRuntimeStatistics[]> GetRuntimeStatistics(SiloAddress[] hostsIds);\n\n        /// <summary>\n        /// Return the most recent grain statistics information, amalgamated across silos.\n        /// </summary>\n        /// <param name=\"hostsIds\">List of silos this command is to be sent to.</param>\n        /// <returns>Simple grain statistics for the specified hosts.</returns>\n        Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics(SiloAddress[] hostsIds);\n\n        /// <summary>\n        /// Return the most recent grain statistics information, amalgamated across all silos.\n        /// </summary>\n        /// <returns>Simple grain statistics.</returns>\n        Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics();\n\n        /// <summary>\n        /// Returns the most recent detailed grain statistics information, amalgamated across silos for the specified types.\n        /// </summary>\n        /// <param name=\"hostsIds\">List of silos this command is to be sent to.</param>\n        /// <param name=\"types\">Array of grain types to filter the results with</param>\n        /// <returns>Detailed grain statistics.</returns>\n        Task<DetailedGrainStatistic[]> GetDetailedGrainStatistics(string[] types = null, SiloAddress[] hostsIds = null);\n        /// <summary>\n        /// Gets the grain activation count for a specific grain type.\n        /// </summary>\n        /// <param name=\"grainReference\">The grain reference.</param>\n        /// <returns>Gets the number of activations of grains with the same type as the provided grain reference.</returns>\n        Task<int> GetGrainActivationCount(GrainReference grainReference);\n        /// <summary>\n        /// Return the total count of all current grain activations across all silos.\n        /// </summary>\n        /// <returns>The total number of grain activations across all silos.</returns>\n        Task<int> GetTotalActivationCount();\n\n        /// <summary>\n        /// Execute a control command on the specified providers on all silos in the cluster.\n        /// Commands are sent to all known providers on each silo which match both the <c>providerTypeFullName</c> AND <c>providerName</c> parameters.\n        /// </summary>\n        /// <remarks>\n        /// Providers must implement the <c>Orleans.Providers.IControllable</c>\n        /// interface in order to receive these control channel commands.\n        /// </remarks>\n        /// <param name=\"providerName\">Provider name to send this command to.</param>\n        /// <param name=\"command\">An id / serial number of this command.\n        /// This is an opaque value to the Orleans runtime - the control protocol semantics are decided between the sender and provider.</param>\n        /// <param name=\"arg\">An opaque command argument.\n        /// This is an opaque value to the Orleans runtime - the control protocol semantics are decided between the sender and provider.</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public Task<object[]> SendControlCommandToProvider<T>(string providerName, int command, object arg = null) where T : IControllable;\n\n        /// <summary>\n        /// Return the <see cref=\"Orleans.Runtime.SiloAddress\"/> where a given Grain is activated (if any).\n        /// </summary>\n        /// <remarks>\n        /// Please note that this method does not represent a strong consistent view of the Grain Catalog.\n        /// The return of this method is taken based on a last known state of the grain which may or may not be up-to-date by the time the caller receive the request.\n        /// </remarks>\n        /// <param name=\"reference\">The <see cref=\"Orleans.Runtime.IAddressable\"/> to look up.</param>\n        /// <returns>The <see cref=\"Orleans.Runtime.SiloAddress\"/> where the Grain is activated or null if not activated taken from a snapshot of the last known state of the Grain Catalog.</returns>\n        ValueTask<SiloAddress> GetActivationAddress(IAddressable reference);\n\n        /// <summary>\n        /// Returns all activations of the specified grain type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>A list of all active grains of the specified type.</returns>\n        ValueTask<List<GrainId>> GetActiveGrains(GrainType type);\n\n        /// <summary>\n        /// Gets estimated grain call frequency statistics from the specified hosts.\n        /// </summary>\n        /// <param name=\"hostsIds\">The hosts to request grain call frequency counts from.</param>\n        /// <returns>A list of estimated grain call frequencies.</returns>\n        /// <remarks>\n        /// Note that this resulting collection does not necessarily contain all grain calls. It contains an estimation of the calls with the highest frequency.\n        /// </remarks>\n        Task<List<GrainCallFrequency>> GetGrainCallFrequencies(SiloAddress[] hostsIds = null);\n\n        /// <summary>\n        /// For testing only. Resets grain call frequency counts on the specified hosts.\n        /// </summary>\n        /// <param name=\"hostsIds\">The hosts to invoke the operation on.</param>\n        /// <returns>A task representing the work performed.</returns>\n        ValueTask ResetGrainCallFrequencies(SiloAddress[] hostsIds = null);\n    }\n\n    /// <summary>\n    /// Represents an estimation of the frequency calls made from a source grain to a target grain.\n    /// </summary>\n    [GenerateSerializer]\n    [Alias(\"Orleans.Runtime.GrainCallFrequency\")]\n    [Immutable]\n    public struct GrainCallFrequency\n    {\n        /// <summary>\n        /// The source grain.\n        /// </summary>\n        [Id(0)]\n        public GrainId SourceGrain { get; set; }\n\n        /// <summary>\n        /// The target grain.\n        /// </summary>\n        [Id(1)]\n        public GrainId TargetGrain { get; set; }\n\n        /// <summary>\n        /// The source host.\n        /// </summary>\n        [Id(2)]\n        public SiloAddress SourceHost { get; set; }\n\n        /// <summary>\n        /// The target host.\n        /// </summary>\n        [Id(3)]\n        public SiloAddress TargetHost { get; set; }\n\n        /// <summary>\n        /// The estimated number of calls made.\n        /// </summary>\n        [Id(4)]\n        public ulong CallCount { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/SystemTargetInterfaces/IMembershipService.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\n\nnamespace Orleans.Runtime\n{\n    internal interface IMembershipService : ISystemTarget\n    {\n        /// <summary>\n        /// Receive notifications about a change in the membership table\n        /// </summary>\n        /// <param name=\"snapshot\">Snapshot of the membership table</param>\n        /// <returns></returns>\n        Task MembershipChangeNotification(MembershipTableSnapshot snapshot);\n\n        /// <summary>\n        /// Ping request from another silo that probes the liveness of the recipient silo.\n        /// </summary>\n        /// <param name=\"pingNumber\">A unique sequence number for ping message, to facilitate testing and debugging.</param>\n        Task Ping(int pingNumber);\n\n        Task<IndirectProbeResponse> ProbeIndirectly(SiloAddress target, TimeSpan probeTimeout, int probeNumber);\n    }\n\n    /// <summary>\n    /// Represents the result of probing a node via an intermediary node.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct IndirectProbeResponse\n    {\n        /// <summary>\n        /// The health score of the intermediary node.\n        /// </summary>\n        [Id(0)]\n        public int IntermediaryHealthScore { get; init; }\n\n        /// <summary>\n        /// <see langword=\"true\"/> if the probe succeeded; otherwise, <see langword=\"false\"/>.\n        /// </summary>\n        [Id(1)]\n        public bool Succeeded { get; init; }\n\n        /// <summary>\n        /// The duration of the probe attempt.\n        /// </summary>\n        [Id(2)]\n        public TimeSpan ProbeResponseTime { get; init; }\n\n        /// <summary>\n        /// The failure message if the probe did not succeed.\n        /// </summary>\n        [Id(3)]\n        public string FailureMessage { get; init; }\n\n        /// <inheritdoc />\n        public override string ToString() => $\"IndirectProbeResponse {{ Succeeded: {Succeeded}, IntermediaryHealthScore: {IntermediaryHealthScore}, ProbeResponseTime: {ProbeResponseTime}, FailureMessage: {FailureMessage} }}\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Text.Json.Serialization;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Interface for Membership Table.\n    /// </summary>\n    public interface IMembershipTable\n    {\n        /// <summary>\n        /// Initializes the membership table, will be called before all other methods\n        /// </summary>\n        /// <param name=\"tryInitTableVersion\">whether an attempt will be made to init the underlying table</param>\n        Task InitializeMembershipTable(bool tryInitTableVersion);\n\n        /// <summary>\n        /// Deletes all table entries of the given clusterId\n        /// </summary>\n        Task DeleteMembershipTableEntries(string clusterId);\n\n        /// <summary>\n        /// Delete all dead silo entries older than <paramref name=\"beforeDate\"/>\n        /// </summary>\n        Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate);\n\n        /// <summary>\n        /// Atomically reads the Membership Table information about a given silo.\n        /// The returned MembershipTableData includes one MembershipEntry entry for a given silo and the \n        /// TableVersion for this table. The MembershipEntry and the TableVersion have to be read atomically.\n        /// </summary>\n        /// <param name=\"key\">The address of the silo whose membership information needs to be read.</param>\n        /// <returns>The membership information for a given silo: MembershipTableData consisting one MembershipEntry entry and\n        /// TableVersion, read atomically.</returns>\n        Task<MembershipTableData> ReadRow(SiloAddress key);\n\n        /// <summary>\n        /// Atomically reads the full content of the Membership Table.\n        /// The returned MembershipTableData includes all MembershipEntry entry for all silos in the table and the \n        /// TableVersion for this table. The MembershipEntries and the TableVersion have to be read atomically.\n        /// </summary>\n        /// <returns>The membership information for a given table: MembershipTableData consisting multiple MembershipEntry entries and\n        /// TableVersion, all read atomically.</returns>\n        Task<MembershipTableData> ReadAll();\n\n        /// <summary>\n        /// Atomically tries to insert (add) a new MembershipEntry for one silo and also update the TableVersion.\n        /// If operation succeeds, the following changes would be made to the table:\n        /// 1) New MembershipEntry will be added to the table.\n        /// 2) The newly added MembershipEntry will also be added with the new unique automatically generated eTag.\n        /// 3) TableVersion.Version in the table will be updated to the new TableVersion.Version.\n        /// 4) TableVersion etag in the table will be updated to the new unique automatically generated eTag.\n        /// All those changes to the table, insert of a new row and update of the table version and the associated etags, should happen atomically, or fail atomically with no side effects.\n        /// The operation should fail in each of the following conditions:\n        /// 1) A MembershipEntry for a given silo already exist in the table\n        /// 2) Update of the TableVersion failed since the given TableVersion etag (as specified by the TableVersion.VersionEtag property) did not match the TableVersion etag in the table.\n        /// </summary>\n        /// <param name=\"entry\">MembershipEntry to be inserted.</param>\n        /// <param name=\"tableVersion\">The new TableVersion for this table, along with its etag.</param>\n        /// <returns>True if the insert operation succeeded and false otherwise.</returns>\n        Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion);\n\n        /// <summary>\n        /// Atomically tries to update the MembershipEntry for one silo and also update the TableVersion.\n        /// If operation succeeds, the following changes would be made to the table:\n        /// 1) The MembershipEntry for this silo will be updated to the new MembershipEntry (the old entry will be fully substituted by the new entry) \n        /// 2) The eTag for the updated MembershipEntry will also be eTag with the new unique automatically generated eTag.\n        /// 3) TableVersion.Version in the table will be updated to the new TableVersion.Version.\n        /// 4) TableVersion etag in the table will be updated to the new unique automatically generated eTag.\n        /// All those changes to the table, update of a new row and update of the table version and the associated etags, should happen atomically, or fail atomically with no side effects.\n        /// The operation should fail in each of the following conditions:\n        /// 1) A MembershipEntry for a given silo does not exist in the table\n        /// 2) A MembershipEntry for a given silo exist in the table but its etag in the table does not match the provided etag.\n        /// 3) Update of the TableVersion failed since the given TableVersion etag (as specified by the TableVersion.VersionEtag property) did not match the TableVersion etag in the table.\n        /// </summary>\n        /// <param name=\"entry\">MembershipEntry to be updated.</param>\n        /// <param name=\"etag\">The etag  for the given MembershipEntry.</param>\n        /// <param name=\"tableVersion\">The new TableVersion for this table, along with its etag.</param>\n        /// <returns>True if the update operation succeeded and false otherwise.</returns>\n        Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion);\n\n        /// <summary>\n        /// Updates the IAmAlive part (column) of the MembershipEntry for this silo.\n        /// This operation should only update the IAmAlive column and not change other columns.\n        /// This operation is a \"dirty write\" or \"in place update\" and is performed without etag validation. \n        /// With regards to eTags update:\n        /// This operation may automatically update the eTag associated with the given silo row, but it does not have to. It can also leave the etag not changed (\"dirty write\").\n        /// With regards to TableVersion:\n        /// this operation should not change the TableVersion of the table. It should leave it untouched.\n        /// There is no scenario where this operation could fail due to table semantical reasons. It can only fail due to network problems or table unavailability.\n        /// </summary>\n        /// <param name=\"entry\"></param>\n        /// <returns>Task representing the successful execution of this operation. </returns>\n        Task UpdateIAmAlive(MembershipEntry entry);\n    }\n\n    /// <summary>\n    /// Membership table interface for system target based implementation.\n    /// </summary>\n    public interface IMembershipTableSystemTarget : IMembershipTable, ISystemTarget\n    {\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class TableVersion : ISpanFormattable, IEquatable<TableVersion>\n    {\n        /// <summary>\n        /// The version part of this TableVersion. Monotonically increasing number.\n        /// </summary>\n        [Id(0)]\n        public int Version { get; }\n\n        /// <summary>\n        /// The etag of this TableVersion, used for validation of table update operations.\n        /// </summary>\n        [Id(1)]\n        public string VersionEtag { get; }\n\n        public TableVersion(int version, string eTag)\n        {\n            Version = version;\n            VersionEtag = eTag;\n        }\n\n        public TableVersion Next() => new (Version + 1, VersionEtag);\n\n        public override string ToString() => $\"<{Version}, {VersionEtag}>\";\n        string IFormattable.ToString(string format, IFormatProvider formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)\n            => destination.TryWrite($\"<{Version}, {VersionEtag}>\", out charsWritten);\n\n        public override bool Equals(object obj) => Equals(obj as TableVersion);\n        public override int GetHashCode() => HashCode.Combine(Version, VersionEtag);\n        public bool Equals(TableVersion other) => other is not null && Version == other.Version && VersionEtag == other.VersionEtag;\n        public static bool operator ==(TableVersion left, TableVersion right) => EqualityComparer<TableVersion>.Default.Equals(left, right);\n        public static bool operator !=(TableVersion left, TableVersion right) => !(left == right);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class MembershipTableData\n    {\n        [Id(0)]\n        public IReadOnlyList<Tuple<MembershipEntry, string>> Members { get; private set; }\n\n        [Id(1)]\n        public TableVersion Version { get; private set; }\n\n        public MembershipTableData(List<Tuple<MembershipEntry, string>> list, TableVersion version)\n        {\n            // put deads at the end, just for logging.\n            list.Sort(\n               (x, y) =>\n               {\n                   if (x.Item1.Status == SiloStatus.Dead) return 1; // put Deads at the end\n                   if (y.Item1.Status == SiloStatus.Dead) return -1; // put Deads at the end\n                   return string.CompareOrdinal(x.Item1.SiloName, y.Item1.SiloName);\n               });\n            Members = list;\n            Version = version;\n        }\n\n        public MembershipTableData(Tuple<MembershipEntry, string> tuple, TableVersion version)\n        {\n            Members = new[] { tuple };\n            Version = version;\n        }\n\n        public MembershipTableData(TableVersion version)\n        {\n            Members = Array.Empty<Tuple<MembershipEntry, string>>();\n            Version = version;\n        }\n\n        public Tuple<MembershipEntry, string> TryGet(SiloAddress silo)\n        {\n            foreach (var item in Members)\n                if (item.Item1.SiloAddress.Equals(silo))\n                    return item;\n\n            return null;\n        }\n\n        public override string ToString()\n        {\n            int active = Members.Count(e => e.Item1.Status == SiloStatus.Active);\n            int dead = Members.Count(e => e.Item1.Status == SiloStatus.Dead);\n            int created = Members.Count(e => e.Item1.Status == SiloStatus.Created);\n            int joining = Members.Count(e => e.Item1.Status == SiloStatus.Joining);\n            int shuttingDown = Members.Count(e => e.Item1.Status == SiloStatus.ShuttingDown);\n            int stopping = Members.Count(e => e.Item1.Status == SiloStatus.Stopping);\n\n            return @$\"{Members.Count} silos, {active} are Active, {dead} are Dead{\n                (created > 0 ? $\", {created} are Created\" : null)}{\n                (joining > 0 ? $\", {joining} are Joining\" : null)}{\n                (shuttingDown > 0 ? $\", {shuttingDown} are ShuttingDown\" : null)}{\n                (stopping > 0 ? $\", {stopping} are Stopping\" : null)\n                }, Version={Version}. All silos: {Utils.EnumerableToString(Members.Select(t => t.Item1))}\";\n        }\n\n        // return a copy of the table removing all dead appereances of dead nodes, except for the last one.\n        public MembershipTableData WithoutDuplicateDeads()\n        {\n            var dead = new Dictionary<IPEndPoint, Tuple<MembershipEntry, string>>();\n            // pick only latest Dead for each instance\n            foreach (var next in Members.Where(item => item.Item1.Status == SiloStatus.Dead))\n            {\n                var ipEndPoint = next.Item1.SiloAddress.Endpoint;\n                Tuple<MembershipEntry, string> prev;\n                if (!dead.TryGetValue(ipEndPoint, out prev))\n                {\n                    dead[ipEndPoint] = next;\n                }\n                else\n                {\n                    // later dead.\n                    if (next.Item1.SiloAddress.Generation.CompareTo(prev.Item1.SiloAddress.Generation) > 0)\n                        dead[ipEndPoint] = next;\n                }\n            }\n            //now add back non-dead\n            List<Tuple<MembershipEntry, string>> all = dead.Values.ToList();\n            all.AddRange(Members.Where(item => item.Item1.Status != SiloStatus.Dead));\n            return new MembershipTableData(all, Version);\n        }\n\n        internal Dictionary<SiloAddress, SiloStatus> GetSiloStatuses(Func<SiloStatus, bool> filter, bool includeMyself, SiloAddress myAddress)\n        {\n            var result = new Dictionary<SiloAddress, SiloStatus>();\n            foreach (var memberEntry in this.Members)\n            {\n                var entry = memberEntry.Item1;\n                if (!includeMyself && entry.SiloAddress.Equals(myAddress)) continue;\n                if (filter(entry.Status)) result[entry.SiloAddress] = entry.Status;\n            }\n\n            return result;\n        }\n    }\n\n    [GenerateSerializer]\n    [Serializable]\n    public sealed class MembershipEntry\n    {\n        /// <summary>\n        /// The silo unique identity (ip:port:epoch). Used mainly by the Membership Protocol.\n        /// </summary>\n        [Id(0)]\n        public SiloAddress SiloAddress { get; set; }\n\n        /// <summary>\n        /// The silo status. Managed by the Membership Protocol.\n        /// </summary>\n        [Id(1)]\n        public SiloStatus Status { get; set; }\n\n        /// <summary>\n        /// The list of silos that suspect this silo. Managed by the Membership Protocol.\n        /// </summary>\n        [Id(2)]\n        public List<Tuple<SiloAddress, DateTime>> SuspectTimes { get; set; }\n\n        /// <summary>\n        /// Silo to clients TCP port. Set on silo startup.\n        /// </summary>    \n        [Id(3)]\n        public int ProxyPort { get; set; }\n\n        /// <summary>\n        /// The DNS host name of the silo. Equals to Dns.GetHostName(). Set on silo startup.\n        /// </summary>\n        [Id(4)]\n        public string HostName { get; set; }\n\n        /// <summary>\n        /// the name of the specific silo instance within a cluster. \n        /// If running in Azure - the name of this role instance. Set on silo startup.\n        /// </summary>\n        [Id(5)]\n        public string SiloName { get; set; }\n\n        [Id(6)]\n        public string RoleName { get; set; } // Optional - only for Azure role  \n        [Id(7)]\n        public int UpdateZone { get; set; }  // Optional - only for Azure role\n        [Id(8)]\n        public int FaultZone { get; set; }   // Optional - only for Azure role\n\n        /// <summary>\n        /// Time this silo was started. For diagnostics and troubleshooting only.\n        /// </summary>\n        [Id(9)]\n        public DateTime StartTime { get; set; }\n\n        /// <summary>\n        /// the last time this silo reported that it is alive. For diagnostics and troubleshooting only.\n        /// </summary>\n        [Id(10)]\n        public DateTime IAmAliveTime { get; set; }\n\n        internal DateTime EffectiveIAmAliveTime\n        {\n            get\n            {\n                var startTimeUtc = DateTime.SpecifyKind(StartTime, DateTimeKind.Utc);\n                var iAmAliveTimeUtc = DateTime.SpecifyKind(IAmAliveTime, DateTimeKind.Utc);\n                return startTimeUtc > iAmAliveTimeUtc ? startTimeUtc : iAmAliveTimeUtc;\n            }\n        }\n\n        public void AddOrUpdateSuspector(SiloAddress localSilo, DateTime voteTime, int maxVotes)\n        {\n            var allVotes = SuspectTimes ??= new List<Tuple<SiloAddress, DateTime>>();\n\n            // Find voting place:\n            //      update my vote, if I voted previously\n            //      OR if the list is not full - just add a new vote\n            //      OR overwrite the oldest entry.\n            int indexToWrite = allVotes.FindIndex(voter => localSilo.Equals(voter.Item1));\n            if (indexToWrite == -1)\n            {\n                // My vote is not recorded. Find the most outdated vote if the list is full, and overwrite it\n                if (allVotes.Count >= maxVotes) // if the list is full\n                {\n                    // The list is full, so pick the most outdated value to overwrite.\n                    DateTime minVoteTime = allVotes.Min(voter => voter.Item2);\n\n                    // Only overwrite an existing vote if the local time is greater than the current minimum vote time.\n                    if (voteTime >= minVoteTime)\n                    {\n                        indexToWrite = allVotes.FindIndex(voter => voter.Item2.Equals(minVoteTime));\n                    }\n                }\n            }\n\n            if (indexToWrite == -1)\n            {\n                AddSuspector(localSilo, voteTime);\n            }\n            else\n            {\n                var newEntry = new Tuple<SiloAddress, DateTime>(localSilo, voteTime);\n                SuspectTimes[indexToWrite] = newEntry;\n            }\n        }\n\n        public void AddSuspector(SiloAddress suspectingSilo, DateTime suspectingTime)\n            => (SuspectTimes ??= new()).Add(Tuple.Create(suspectingSilo, suspectingTime));\n\n        internal MembershipEntry Copy()\n        {\n            var copy = new MembershipEntry\n            {\n                SiloAddress = SiloAddress,\n                Status = Status,\n                SuspectTimes = SuspectTimes is null ? null : new(SuspectTimes),\n                ProxyPort = ProxyPort,\n                HostName = HostName,\n                SiloName = SiloName,\n                RoleName = RoleName,\n                UpdateZone = UpdateZone,\n                FaultZone = FaultZone,\n                StartTime = StartTime,\n                IAmAliveTime = IAmAliveTime\n            };\n\n            return copy;\n        }\n\n        internal MembershipEntry WithStatus(SiloStatus status)\n        {\n            var updated = this.Copy();\n            updated.Status = status;\n            return updated;\n        }\n\n        internal MembershipEntry WithIAmAliveTime(DateTime iAmAliveTime)\n        {\n            var updated = this.Copy();\n            updated.IAmAliveTime = iAmAliveTime;\n            return updated;\n        }\n\n        internal ImmutableList<Tuple<SiloAddress, DateTime>> GetFreshVotes(DateTime now, TimeSpan expiration)\n        {\n            if (this.SuspectTimes == null)\n                return ImmutableList<Tuple<SiloAddress, DateTime>>.Empty;\n\n            var result = ImmutableList.CreateBuilder<Tuple<SiloAddress, DateTime>>();\n\n            // Find the latest time from the set of suspect times and the local time.\n            // This prevents local clock skew from resulting in a different tally of fresh votes.\n            var recencyWindowEndTime = Max(now, SuspectTimes);\n            foreach (var voter in this.SuspectTimes)\n            {\n                // If now is smaller than otherVoterTime, than assume the otherVoterTime is fresh.\n                // This could happen if clocks are not synchronized and the other voter clock is ahead of mine.\n                var suspectTime = voter.Item2;\n                if (recencyWindowEndTime.Subtract(suspectTime) < expiration)\n                {\n                    result.Add(voter);\n                }\n            }\n\n            return result.ToImmutable();\n\n            static DateTime Max(DateTime localTime, List<Tuple<SiloAddress, DateTime>> suspectTimes)\n            {\n                var maxValue = localTime;\n                foreach (var entry in suspectTimes)\n                {\n                    var suspectTime = entry.Item2;\n                    if (suspectTime > maxValue) maxValue = suspectTime;\n                }\n\n                return maxValue;\n            }\n        }\n\n        public override string ToString() => $\"SiloAddress={SiloAddress} SiloName={SiloName} Status={Status}\";\n\n        public string ToFullString()\n        {\n            var suspecters = SuspectTimes == null ? null : Utils.EnumerableToString(SuspectTimes.Select(tuple => tuple.Item1));\n            var suspectTimes = SuspectTimes == null ? null : Utils.EnumerableToString(SuspectTimes.Select(tuple => LogFormatter.PrintDate(tuple.Item2)));\n\n            return @$\"[SiloAddress={SiloAddress} SiloName={SiloName} Status={Status} HostName={HostName} ProxyPort={ProxyPort} RoleName={RoleName\n                } UpdateZone={UpdateZone} FaultZone={FaultZone} StartTime={LogFormatter.PrintDate(StartTime)} IAmAliveTime={LogFormatter.PrintDate(IAmAliveTime)\n                }{(suspecters == null ? null : \" Suspecters=\")}{suspecters}{(suspectTimes == null ? null : \" SuspectTimes=\")}{suspectTimes}]\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/SystemTargetInterfaces/ISiloControl.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Providers;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    internal interface ISiloControl : ISystemTarget, IVersionManager\n    {\n        Task Ping(string message);\n\n        Task ForceGarbageCollection();\n        Task ForceActivationCollection(TimeSpan ageLimit);\n        Task ForceRuntimeStatisticsCollection();\n\n        Task<SiloRuntimeStatistics> GetRuntimeStatistics();\n        Task<List<Tuple<GrainId, string, int>>> GetGrainStatistics();\n        Task<List<DetailedGrainStatistic>> GetDetailedGrainStatistics(string[] types = null);\n        Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics();\n        Task<DetailedGrainReport> GetDetailedGrainReport(GrainId grainId);\n\n        Task<int> GetActivationCount();\n        Task MigrateRandomActivations(SiloAddress target, int count);\n\n        Task<object> SendControlCommandToProvider<T>(string providerName, int command, object arg) where T : IControllable;\n        Task<List<GrainId>> GetActiveGrains(GrainType grainType);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Threading/RecursiveInterlockedExchangeLock.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\n\nnamespace Orleans.Threading\n{\n    /// <summary>\n    /// Lightweight recursive lock.\n    /// </summary>\n    internal sealed class RecursiveInterlockedExchangeLock\n    {\n        private const int UNLOCKED = -1;\n\n        [ThreadStatic]\n        private static int localThreadId;\n        private int lockState = UNLOCKED;\n        private readonly Func<bool> spinCondition;\n\n        public RecursiveInterlockedExchangeLock()\n        {\n            this.spinCondition = this.TryGet;\n        }\n\n        private static int ThreadId => localThreadId != 0 ? localThreadId : localThreadId = Environment.CurrentManagedThreadId;\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool TryGet()\n        {\n            var previousValue = Interlocked.CompareExchange(ref this.lockState, ThreadId, UNLOCKED);\n            return previousValue == UNLOCKED || previousValue == ThreadId;\n        }\n        \n        /// <summary>\n        /// Acquire the lock, blocking the thread if necessary.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Get()\n        {\n            if (this.TryGet())\n            {\n                return;\n            }\n\n            SpinWait.SpinUntil(this.spinCondition);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool TryRelease()\n        {\n            var threadId = ThreadId;\n            var previousValue = Interlocked.CompareExchange(ref this.lockState, UNLOCKED, threadId);\n            return previousValue == UNLOCKED || previousValue == threadId;\n        }\n\n        public override string ToString()\n        {\n            var state = Volatile.Read(ref this.lockState);\n            return state == UNLOCKED ? \"Unlocked\" : $\"Locked by Thread {state}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Timers/CoarseStopwatch.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Cheap, non-allocating stopwatch for timing durations with an accuracy within tens of milliseconds.\n    /// </summary>\n    internal struct CoarseStopwatch\n    {\n        private long _value;\n\n        /// <summary>\n        /// Starts a new instance.\n        /// </summary>\n        /// <returns>A new, running stopwatch.</returns>\n        public static CoarseStopwatch StartNew() => new(GetTimestamp());\n\n        /// <summary>\n        /// Starts a new instance with the specified duration already elapsed.\n        /// </summary>\n        /// <returns>A new, running stopwatch.</returns>\n        public static CoarseStopwatch StartNew(long elapsedMs) => new(GetTimestamp() - elapsedMs);\n\n        /// <summary>\n        /// Creates a new instance with the specified timestamp.\n        /// </summary>\n        /// <returns>A new stopwatch.</returns>\n        public static CoarseStopwatch FromTimestamp(long timestamp) => new(timestamp);\n\n        private CoarseStopwatch(long timestamp)\n        {\n            _value = timestamp;\n        }\n\n        /// <summary>\n        /// The number of ticks per second for this stopwatch.\n        /// </summary>\n        public const long Frequency = 1000;\n\n        /// <summary>\n        /// Returns true if this instance is running or false otherwise.\n        /// </summary>\n        public readonly bool IsRunning => _value > 0;\n\n        /// <summary>\n        /// Returns the elapsed time.\n        /// </summary>\n        public TimeSpan Elapsed => TimeSpan.FromMilliseconds(ElapsedMilliseconds);\n\n        /// <summary>\n        /// Returns a value indicating whether this instance has the default value.\n        /// </summary>\n        public readonly bool IsDefault => _value == 0;\n\n        /// <summary>\n        /// Returns the elapsed ticks.\n        /// </summary>\n        public readonly long ElapsedMilliseconds\n        {\n            get\n            {\n                // A positive timestamp value indicates the start time of a running stopwatch,\n                // a negative value indicates the negative total duration of a stopped stopwatch.\n                var timestamp = _value;\n\n                long delta;\n                if (IsRunning)\n                {\n                    // The stopwatch is still running.\n                    var start = timestamp;\n                    var end = GetTimestamp();\n                    delta = end - start;\n                }\n                else\n                {\n                    // The stopwatch has been stopped.\n                    delta = -timestamp;\n                }\n\n                return delta;\n            }\n        }\n\n        /// <summary>\n        /// Gets the number of ticks in the timer mechanism.\n        /// </summary>\n        /// <returns>The number of ticks in the timer mechanism</returns>\n        public static long GetTimestamp() => Environment.TickCount64;\n\n        /// <summary>\n        /// Returns a new, stopped <see cref=\"CoarseStopwatch\"/> with the provided start and end timestamps.\n        /// </summary>\n        /// <param name=\"start\">The start timestamp.</param>\n        /// <param name=\"end\">The end timestamp.</param>\n        /// <returns>A new, stopped <see cref=\"CoarseStopwatch\"/> with the provided start and end timestamps.</returns>\n        public static CoarseStopwatch FromTimestamp(long start, long end) => new(-(end - start));\n\n        /// <summary>\n        /// Gets the raw counter value for this instance.\n        /// </summary>\n        /// <remarks> \n        /// A positive timestamp value indicates the start time of a running stopwatch,\n        /// a negative value indicates the negative total duration of a stopped stopwatch.\n        /// </remarks>\n        /// <returns>The raw counter value.</returns>\n        public readonly long GetRawTimestamp() => _value;\n\n        /// <summary>\n        /// Starts the stopwatch.\n        /// </summary>\n        public void Start()\n        {\n            var timestamp = _value;\n\n            // If already started, do nothing.\n            if (IsRunning) return;\n\n            // Stopwatch is stopped, therefore value is zero or negative.\n            // Add the negative value to the current timestamp to start the stopwatch again.\n            var newValue = GetTimestamp() + timestamp;\n            if (newValue == 0) newValue = 1;\n            _value = newValue;\n        }\n\n        /// <summary>\n        /// Restarts this stopwatch, beginning from zero time elapsed.\n        /// </summary>\n        public void Restart() => _value = GetTimestamp();\n\n        /// <summary>\n        /// Resets this stopwatch into a stopped state with no elapsed duration.\n        /// </summary>\n        public void Reset() => _value = 0;\n\n        /// <summary>\n        /// Stops this stopwatch.\n        /// </summary>\n        public void Stop()\n        {\n            var timestamp = _value;\n\n            // If already stopped, do nothing.\n            if (!IsRunning) return;\n\n            var end = GetTimestamp();\n            var delta = end - timestamp;\n\n            _value = -delta;\n        }\n\n        public override readonly bool Equals(object obj) => obj is CoarseStopwatch stopwatch && _value == stopwatch._value;\n        public readonly bool Equals(CoarseStopwatch other) => _value == other._value;\n        public override readonly int GetHashCode() => HashCode.Combine(_value);\n        public static bool operator ==(CoarseStopwatch left, CoarseStopwatch right) => left.Equals(right);\n        public static bool operator !=(CoarseStopwatch left, CoarseStopwatch right) => !left.Equals(right);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Timers/NonCapturingTimer.cs",
    "content": "using System;\nusing System.Threading;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// A convenience API for interacting with System.Threading.Timer in a way\n    /// that doesn't capture the ExecutionContext. We should be using this (or equivalent)\n    /// everywhere we use timers to avoid rooting any values stored in AsyncLocals.\n    /// </summary>\n    /// <see href=\"https://github.com/dotnet/extensions/blob/a1389576a3bbc85a48bdcadce4f16bcf7cdfa088/src/Shared/src/NonCapturingTimer/NonCapturingTimer.cs\"/>\n    internal static class NonCapturingTimer\n    {\n        public static Timer Create(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)\n        {\n            if (callback == null)\n            {\n                throw new ArgumentNullException(nameof(callback));\n            }\n\n            // Don't capture the current ExecutionContext and its AsyncLocals onto the timer\n            using var suppressExecutionContext = new ExecutionContextSuppressor();\n\n            return new Timer(callback, state, dueTime, period);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Timers/TimerManager.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Threading;\n\nnamespace Orleans.Timers.Internal\n{\n    /// <summary>\n    /// Provides functionality for managing single-shot timers.\n    /// </summary>\n    public interface ITimerManager\n    {\n        /// <summary>\n        /// Returns a task which will complete when the specified timespan elapses or the provided cancellation token is canceled.\n        /// </summary>\n        /// <param name=\"timeSpan\">The time span.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns><see langword=\"true\"/> if the timer ran to completion; otherwise <see langword=\"false\"/>.</returns>\n        Task<bool> Delay(TimeSpan timeSpan, CancellationToken cancellationToken = default);\n    }\n\n    internal class TimerManagerImpl : ITimerManager\n    {\n        public Task<bool> Delay(TimeSpan timeSpan, CancellationToken cancellationToken = default) => TimerManager.Delay(timeSpan, cancellationToken);\n    }\n\n    internal static class TimerManager\n    {\n        public static Task<bool> Delay(TimeSpan timeSpan, CancellationToken cancellationToken = default) => DelayUntil(DateTime.UtcNow + timeSpan, cancellationToken);\n\n        public static Task<bool> DelayUntil(DateTime dueTime, CancellationToken cancellationToken = default)\n        {\n            var result = new DelayTimer(dueTime, cancellationToken);\n            TimerManager<DelayTimer>.Register(result);\n            return result.Completion;\n        }\n\n        private sealed class DelayTimer : ITimerCallback, ILinkedListElement<DelayTimer>\n        {\n            private readonly TaskCompletionSource<bool> completion =\n                new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            public DelayTimer(DateTime dueTime, CancellationToken cancellationToken)\n            {\n                this.DueTime = dueTime;\n                this.CancellationToken = cancellationToken;\n            }\n\n            public Task<bool> Completion => this.completion.Task;\n\n            public DateTime DueTime { get; }\n\n            public CancellationToken CancellationToken { get; }\n\n            public void OnTimeout() => this.completion.TrySetResult(true);\n\n            public void OnCanceled() => this.completion.TrySetResult(false);\n\n            DelayTimer ILinkedListElement<DelayTimer>.Next { get; set; }\n        }\n    }\n\n    /// <summary>\n    /// Manages timers of a specified type, firing them after they expire.\n    /// </summary>\n    /// <typeparam name=\"T\">The timer type.</typeparam>\n    internal static class TimerManager<T> where T : class, ITimerCallback, ILinkedListElement<T>\n    {\n        /// <summary>\n        /// The maximum number of times a queue can be denied servicing before servicing is mandatory.\n        /// </summary>\n        private const int MAX_STARVATION = 2;\n\n        /// <summary>\n        /// The number of milliseconds between timer servicing ticks.\n        /// </summary>\n        private const int TIMER_TICK_MILLISECONDS = 50;\n\n        /// <summary>\n        /// Lock protecting <see cref=\"allQueues\"/>.\n        /// </summary>\n        // ReSharper disable once StaticMemberInGenericType\n        private static readonly object AllQueuesLock = new object();\n\n#pragma warning disable IDE0052 // Remove unread private members\n        private static readonly Timer QueueChecker;\n#pragma warning restore IDE0052 // Remove unread private members\n\n        /// <summary>\n        /// Collection of all thread-local timer queues.\n        /// </summary>\n        private static ThreadLocalQueue[] allQueues = new ThreadLocalQueue[16];\n\n        /// <summary>\n        /// The queue for the current thread.\n        /// </summary>\n        [ThreadStatic]\n        private static ThreadLocalQueue threadLocalQueue;\n\n        static TimerManager()\n        {\n            var timerPeriod = TimeSpan.FromMilliseconds(TIMER_TICK_MILLISECONDS);\n            QueueChecker = NonCapturingTimer.Create(_ => CheckQueues(), null, timerPeriod, timerPeriod);\n        }\n\n        /// <summary>\n        /// Registers a timer.\n        /// </summary>\n        public static void Register(T timer)\n        {\n            ExpiredTimers expired = null;\n            var queue = EnsureCurrentThreadHasQueue();\n\n            try\n            {\n                queue.Lock.Get();\n                queue.AddTail(timer);\n\n                if (queue.StarvationCount >= MAX_STARVATION)\n                {\n                    // If the queue is too starved, service it now.\n                    expired = new ExpiredTimers();\n                    CheckQueueInLock(queue, DateTime.UtcNow, expired);\n                    Interlocked.Exchange(ref queue.StarvationCount, 0);\n                }\n            }\n            finally\n            {\n                queue.Lock.TryRelease();\n\n                // Fire expired timers outside of lock.\n                expired?.FireTimers();\n            }\n        }\n        \n        private static void CheckQueues()\n        {\n            var expired = new ExpiredTimers();\n            var now = DateTime.UtcNow;\n            try\n            {\n                foreach (var queue in allQueues)\n                {\n                    if (queue == null)\n                    {\n                        continue;\n                    }\n\n                    if (!queue.Lock.TryGet())\n                    {\n                        // Check for starvation.\n                        if (Interlocked.Increment(ref queue.StarvationCount) > MAX_STARVATION)\n                        {\n                            // If the queue starved, block until the lock can be acquired.\n                            queue.Lock.Get();\n                            Interlocked.Exchange(ref queue.StarvationCount, 0);\n                        }\n                        else\n                        {\n                            // Move on to the next queue.\n                            continue;\n                        }\n                    }\n\n                    try\n                    {\n                        CheckQueueInLock(queue, now, expired);\n                    }\n                    finally\n                    {\n                        queue.Lock.TryRelease();\n                    }\n                }\n            }\n            finally\n            {\n                // Expire timers outside of the loop and outside of any lock.\n                expired.FireTimers();\n            }\n        }\n\n        private static void CheckQueueInLock(ThreadLocalQueue queue, DateTime now, ExpiredTimers expired)\n        {\n            var previous = default(T);\n\n            for (var current = queue.Head; current != null; current = current.Next)\n            {\n                if (current.CancellationToken.IsCancellationRequested || current.DueTime < now)\n                {\n                    // Dequeue and add to expired list for later execution.\n                    queue.Remove(previous, current);\n                    expired.AddTail(current);\n                }\n                else\n                {\n                    // If the current item wasn't removed, update previous.\n                    previous = current;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns the queue for the current thread, creating and registering one if it does not yet exist.\n        /// </summary>\n        /// <returns>The current thread's <see cref=\"ThreadLocalQueue\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static ThreadLocalQueue EnsureCurrentThreadHasQueue()\n        {\n            return threadLocalQueue ?? (threadLocalQueue = InitializeThreadLocalQueue());\n\n            ThreadLocalQueue InitializeThreadLocalQueue()\n            {\n                var threadLocal = new ThreadLocalQueue();\n                while (true)\n                {\n                    lock (AllQueuesLock)\n                    {\n                        var queues = Volatile.Read(ref allQueues);\n\n                        // Find a spot in the existing array to register this thread.\n                        for (var i = 0; i < queues.Length; i++)\n                        {\n                            if (Volatile.Read(ref queues[i]) == null)\n                            {\n                                Volatile.Write(ref queues[i], threadLocal);\n                                return threadLocal;\n                            }\n                        }\n\n                        // The existing array is full, so copy all values to a new, larger array and register this thread.\n                        var newQueues = new ThreadLocalQueue[queues.Length * 2];\n                        Array.Copy(queues, newQueues, queues.Length);\n                        newQueues[queues.Length] = threadLocal;\n                        Volatile.Write(ref allQueues, newQueues);\n                        return threadLocal;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Holds per-thread timer data.\n        /// </summary>\n        private sealed class ThreadLocalQueue : ILinkedList<T>\n        {\n            public readonly RecursiveInterlockedExchangeLock Lock = new RecursiveInterlockedExchangeLock();\n\n            /// <summary>\n            /// The number of times that this queue has been starved since it was last serviced.\n            /// </summary>\n            public int StarvationCount;\n\n            public T Head { get; set; }\n\n            public T Tail { get; set; }\n        }\n\n        /// <summary>\n        /// Holds timers that have expired and should be fired.\n        /// </summary>\n        private sealed class ExpiredTimers : ILinkedList<T>\n        {\n            public T Head { get; set; }\n\n            public T Tail { get; set; }\n\n            public void FireTimers()\n            {\n                var current = this.Head;\n                while (current != null)\n                {\n                    try\n                    {\n                        if (current.CancellationToken.IsCancellationRequested)\n                        {\n                            current.OnCanceled();\n                        }\n                        else\n                        {\n                            current.OnTimeout();\n                        }\n                    }\n                    catch\n                    {\n                        // Ignore any exceptions during firing.\n                    }\n\n                    current = current.Next;\n                }\n            }\n        }\n    }\n\n    internal interface ITimerCallback\n    {\n        /// <summary>\n        /// The UTC time when this timer is due.\n        /// </summary>\n        DateTime DueTime { get; }\n\n        CancellationToken CancellationToken { get; }\n\n        void OnTimeout();\n\n        void OnCanceled();\n    }\n\n    /// <summary>\n    /// Represents a linked list.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    internal interface ILinkedList<T> where T : ILinkedListElement<T>\n    {\n        /// <summary>\n        /// Gets or sets the first element in the list.\n        /// This value must never be accessed or modified by user code.\n        /// </summary>\n        T Head { get; set; }\n\n        /// <summary>\n        /// Gets or sets the last element in the list.\n        /// This value must never be accessed or modified by user code.\n        /// </summary>\n        T Tail { get; set; }\n    }\n\n    /// <summary>\n    /// Represents an element in a linked list.\n    /// </summary>\n    /// <typeparam name=\"TSelf\">Self-type. The type implementing this interface.</typeparam>\n    internal interface ILinkedListElement<TSelf> where TSelf : ILinkedListElement<TSelf>\n    {\n        /// <summary>\n        /// The next element in the list.\n        /// This value must never be accessed or modified by user code.\n        /// </summary>\n        TSelf Next { get; set; }\n    }\n\n    internal static class LinkedList\n    {\n        /// <summary>\n        /// Appends an item to the tail of a linked list.\n        /// </summary>\n        /// <param name=\"list\">The linked list.</param>\n        /// <param name=\"element\">The element to append.</param>\n        public static void AddTail<TList, TElement>(this TList list, TElement element)\n            where TList : class, ILinkedList<TElement> where TElement : class, ILinkedListElement<TElement>\n        {\n            // If this is the first element, update the head.\n            if (list.Head is null) list.Head = element;\n\n            // If this is not the first element, update the current tail.\n            var prevTail = list.Tail;\n            if (!(prevTail is null)) prevTail.Next = element;\n\n            // Update the tail.\n            list.Tail = element;\n        }\n\n        /// <summary>\n        /// Removes an item from a linked list.\n        /// </summary>\n        /// <param name=\"list\">The linked list.</param>\n        /// <param name=\"previous\">The element before <paramref name=\"current\"/>.</param>\n        /// <param name=\"current\">The element to remove.</param>\n        public static void Remove<TList, TElement>(this TList list, TElement previous, TElement current)\n            where TList : class, ILinkedList<TElement> where TElement : class, ILinkedListElement<TElement>\n        {\n            var next = current.Next;\n\n            // If not removing the first element, point the previous element at the next element.\n            if (!(previous is null)) previous.Next = next;\n\n            // If removing the first element, point the tail at the next element.\n            if (ReferenceEquals(list.Head, current))\n            {\n                list.Head = next ?? previous;\n            }\n\n            // If removing the last element, point the tail at the previous element.\n            if (ReferenceEquals(list.Tail, current))\n            {\n                list.Tail = previous;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Timers/ValueStopwatch.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Non-allocating stopwatch for timing durations.\n    /// </summary>\n    internal struct ValueStopwatch\n    {\n        private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;\n        private long _value;\n\n        /// <summary>\n        /// Starts a new instance.\n        /// </summary>\n        /// <returns>A new, running stopwatch.</returns>\n        public static ValueStopwatch StartNew() => new(GetTimestamp());\n\n        /// <summary>\n        /// Starts a new instance with an initial elapsed duration.\n        /// </summary>\n        /// <param name=\"elapsed\">\n        /// The initial elapsed duration.\n        /// </param>\n        /// <returns>A new, running stopwatch.</returns>\n        public static ValueStopwatch StartNew(TimeSpan elapsed) => new(GetTimestamp() - (long)(elapsed.TotalSeconds * Stopwatch.Frequency));\n\n        private ValueStopwatch(long timestamp)\n        {\n            this._value = timestamp;\n        }\n\n        /// <summary>\n        /// Returns true if this instance is running or false otherwise.\n        /// </summary>\n        public readonly bool IsRunning => this._value > 0;\n\n        /// <summary>\n        /// Returns the elapsed time.\n        /// </summary>\n        public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks);\n\n        /// <summary>\n        /// Returns the elapsed ticks.\n        /// </summary>\n        public readonly long ElapsedTicks\n        {\n            get\n            {\n                // A positive timestamp value indicates the start time of a running stopwatch,\n                // a negative value indicates the negative total duration of a stopped stopwatch.\n                var timestamp = this._value;\n\n                long delta;\n                if (this.IsRunning)\n                {\n                    // The stopwatch is still running.\n                    var start = timestamp;\n                    var end = Stopwatch.GetTimestamp();\n                    delta = end - start;\n                }\n                else\n                {\n                    // The stopwatch has been stopped.\n                    delta = -timestamp;\n                }\n\n                return (long)(delta * TimestampToTicks);\n            }\n        }\n\n        /// <summary>\n        /// Gets the number of ticks in the timer mechanism.\n        /// </summary>\n        /// <returns>The number of ticks in the timer mechanism</returns>\n        public static long GetTimestamp() => Stopwatch.GetTimestamp();\n\n        /// <summary>\n        /// Returns a new, stopped <see cref=\"ValueStopwatch\"/> with the provided start and end timestamps.\n        /// </summary>\n        /// <param name=\"start\">The start timestamp.</param>\n        /// <param name=\"end\">The end timestamp.</param>\n        /// <returns>A new, stopped <see cref=\"ValueStopwatch\"/> with the provided start and end timestamps.</returns>\n        public static ValueStopwatch FromTimestamp(long start, long end) => new ValueStopwatch(-(end - start));\n\n        /// <summary>\n        /// Gets the raw counter value for this instance.\n        /// </summary>\n        /// <remarks> \n        /// A positive timestamp value indicates the start time of a running stopwatch,\n        /// a negative value indicates the negative total duration of a stopped stopwatch.\n        /// </remarks>\n        /// <returns>The raw counter value.</returns>\n        public readonly long GetRawTimestamp() => this._value;\n\n        /// <summary>\n        /// Starts the stopwatch.\n        /// </summary>\n        public void Start()\n        {\n            var timestamp = this._value;\n\n            // If already started, do nothing.\n            if (this.IsRunning) return;\n\n            // Stopwatch is stopped, therefore value is zero or negative.\n            // Add the negative value to the current timestamp to start the stopwatch again.\n            var newValue = GetTimestamp() + timestamp;\n            if (newValue == 0) newValue = 1;\n            this._value = newValue;\n        }\n\n        /// <summary>\n        /// Restarts this stopwatch, beginning from zero time elapsed.\n        /// </summary>\n        public void Restart() => this._value = GetTimestamp();\n\n        /// <summary>\n        /// Resets this stopwatch into a stopped state with no elapsed duration.\n        /// </summary>\n        public void Reset() => this._value = 0;\n\n        /// <summary>\n        /// Stops this stopwatch.\n        /// </summary>\n        public void Stop()\n        {\n            var timestamp = this._value;\n\n            // If already stopped, do nothing.\n            if (!this.IsRunning) return;\n\n            var end = GetTimestamp();\n            var delta = end - timestamp;\n\n            this._value = -delta;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Utils/AsyncEnumerable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.Utilities\n{\n    internal static class AsyncEnumerable\n    {\n        internal static readonly object InitialValue = new();\n        internal static readonly object DisposedValue = new();\n    }\n\n    internal sealed class AsyncEnumerable<T> : IAsyncEnumerable<T>\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _updateLock = new();\n#else\n        private readonly object _updateLock = new();\n#endif\n        private readonly Func<T, T, bool> _updateValidator;\n        private readonly Action<T> _onPublished;\n        private Element _current;\n        \n        public AsyncEnumerable(T initialValue, Func<T, T, bool> updateValidator, Action<T> onPublished)\n        {\n            _updateValidator = updateValidator;\n            _current = new Element(initialValue);\n            _onPublished = onPublished;\n            onPublished(initialValue);\n        }\n\n        public bool TryPublish(T value) => TryPublish(new Element(value)) == PublishResult.Success;\n        \n        public void Publish(T value)\n        {\n            switch (TryPublish(new Element(value)))\n            {\n                case PublishResult.Success:\n                    return;\n                case PublishResult.InvalidUpdate:\n                    ThrowInvalidUpdate();\n                    break;\n                case PublishResult.Disposed:\n                    ThrowDisposed();\n                    break;\n            }\n        }\n\n        public bool TryPublish<TState>(Func<T, TState, T> updateFunc, TState state) => TryPublishCore(updateFunc, state) == PublishResult.Success;\n        \n        public void Publish<TState>(Func<T, TState, T> updateFunc, TState state)\n        {\n            switch (TryPublishCore(updateFunc, state))\n            {\n                case PublishResult.Success:\n                    return;\n                case PublishResult.InvalidUpdate:\n                    ThrowInvalidUpdate();\n                    break;\n                case PublishResult.Disposed:\n                    ThrowDisposed();\n                    break;\n            }\n        }\n\n        private PublishResult TryPublish(Element newItem)\n        {\n            if (_current.IsDisposed) return PublishResult.Disposed;\n\n            lock (_updateLock)\n            {\n                if (_current.IsDisposed) return PublishResult.Disposed;\n\n                if (_current.IsValid && newItem.IsValid && !_updateValidator(_current.Value, newItem.Value))\n                {\n                    return PublishResult.InvalidUpdate;\n                }\n\n                var curr = _current;\n                Interlocked.Exchange(ref _current, newItem);\n                if (newItem.IsValid) _onPublished(newItem.Value);\n                curr.SetNext(newItem);\n\n                return PublishResult.Success;\n            }\n        }\n\n        private PublishResult TryPublishCore<TState>(Func<T, TState, T> updateFunc, TState state)\n        {\n            if (_current.IsDisposed) return PublishResult.Disposed;\n\n            lock (_updateLock)\n            {\n                if (_current.IsDisposed) return PublishResult.Disposed;\n\n                var curr = _current;\n                var newItem = new Element(updateFunc(curr.Value, state));\n\n                if (curr.IsValid && newItem.IsValid && !_updateValidator(curr.Value, newItem.Value))\n                {\n                    return PublishResult.InvalidUpdate;\n                }\n\n                Interlocked.Exchange(ref _current, newItem);\n                if (newItem.IsValid) _onPublished(newItem.Value);\n                curr.SetNext(newItem);\n\n                return PublishResult.Success;\n            }\n        }\n\n        public void Dispose()\n        {\n            if (_current.IsDisposed) return;\n\n            lock (_updateLock)\n            {\n                if (_current.IsDisposed) return;\n\n                TryPublish(Element.CreateDisposed());\n            }\n        }\n\n        [DoesNotReturn]\n        private static void ThrowInvalidUpdate() => throw new ArgumentException(\"The value was not valid.\");\n\n        [DoesNotReturn]\n        private static void ThrowDisposed() => throw new ObjectDisposedException(\"This instance has been disposed.\");\n\n        public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new AsyncEnumerator(_current, cancellationToken);\n\n        private enum PublishResult\n        {\n            Success,\n            InvalidUpdate,\n            Disposed\n        }\n\n        private sealed class AsyncEnumerator : IAsyncEnumerator<T>\n        {\n            private readonly CancellationTokenSource _cts;\n            private Element _current;\n\n            public AsyncEnumerator(Element initial, CancellationToken cancellationToken)\n            {\n                _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n                if (!initial.IsValid)\n                {\n                    _current = initial;\n                }\n                else\n                {\n                    var result = Element.CreateInitial();\n                    result.SetNext(initial);\n                    _current = result;\n                }\n            }\n\n            T IAsyncEnumerator<T>.Current => _current.Value;\n\n            async ValueTask<bool> IAsyncEnumerator<T>.MoveNextAsync()\n            {\n                if (_current.IsDisposed)\n                {\n                    return false;\n                }\n\n                _current = await _current.NextAsync().WaitAsync(_cts.Token);\n                return _current.IsValid;\n            }\n\n            async ValueTask IAsyncDisposable.DisposeAsync()\n            {\n                await _cts.CancelAsync().SuppressThrowing();\n                _cts.Dispose();\n            }\n        }\n\n        private sealed class Element\n        {\n            private readonly TaskCompletionSource<Element> _next;\n            private readonly object _value;\n\n            public Element(T value) : this(value, new TaskCompletionSource<Element>(TaskCreationOptions.RunContinuationsAsynchronously))\n            {\n            }\n\n            private Element(object value, TaskCompletionSource<Element> next)\n            {\n                _value = value;\n                _next = next;\n            }\n\n            public static Element CreateInitial() => new(\n                AsyncEnumerable.InitialValue,\n                new TaskCompletionSource<Element>(TaskCreationOptions.RunContinuationsAsynchronously));\n\n            public static Element CreateDisposed()\n            {\n                var tcs = new TaskCompletionSource<Element>(TaskCreationOptions.RunContinuationsAsynchronously);\n                tcs.SetException(new ObjectDisposedException(\"This instance has been disposed\"));\n                return new Element(AsyncEnumerable.DisposedValue, tcs);\n            }\n\n            public bool IsValid => !IsInitial && !IsDisposed;\n\n            public T Value\n            {\n                get\n                {\n                    if (IsInitial) ThrowInvalidInstance();\n                    ObjectDisposedException.ThrowIf(IsDisposed, this);\n                    if (_value is T typedValue) return typedValue;\n                    return default;\n                }\n            }\n\n            public bool IsInitial => ReferenceEquals(_value, AsyncEnumerable.InitialValue);\n            public bool IsDisposed => ReferenceEquals(_value, AsyncEnumerable.DisposedValue);\n\n            public Task<Element> NextAsync() => _next.Task;\n\n            public void SetNext(Element next) => _next.SetResult(next);\n\n            private static void ThrowInvalidInstance() => throw new InvalidOperationException(\"This instance does not have a value set.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/ExecutionContextSuppressor.cs",
    "content": "using System.Threading;\n\nnamespace Orleans.Runtime.Internal;\n\n/// <summary>\n/// Suppresses the flow of <see cref=\"ExecutionContext\"/> until it is disposed.\n/// </summary>\n/// <remarks>\n/// Note that this is a ref-struct to avoid it being used in an async method.\n/// </remarks>\npublic ref struct ExecutionContextSuppressor\n{\n    private readonly bool _restoreFlow;\n\n    /// <summary>\n    /// Initializes a new <see cref=\"ExecutionContextSuppressor\"/> instance.\n    /// </summary>\n    public ExecutionContextSuppressor()\n    {\n        if (!ExecutionContext.IsFlowSuppressed())\n        {\n            ExecutionContext.SuppressFlow();\n            _restoreFlow = true;\n        }\n        else\n        {\n            _restoreFlow = false;\n        }\n    }\n\n    /// <summary>\n    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n    /// </summary>\n    public readonly void Dispose()\n    {\n        if (_restoreFlow)\n        {\n            ExecutionContext.RestoreFlow();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/Factory.cs",
    "content": "namespace Orleans\n{\n    /// <summary>\n    /// Creates an instance of <typeparamref name=\"TInstance\"/>.\n    /// </summary>\n    /// <typeparam name=\"TInstance\"></typeparam>\n    /// <returns>The instance.</returns>\n    public delegate TInstance Factory<out TInstance>();\n\n    /// <summary>\n    /// Creates an instance of <typeparamref name=\"TInstance\"/>.\n    /// </summary>\n    /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n    /// <typeparam name=\"TParam1\">The parameter type.</typeparam>\n    /// <returns>The instance.</returns>\n    public delegate TInstance Factory<in TParam1, out TInstance>(TParam1 param1);\n\n    /// <summary>\n    /// Creates an instance of <typeparamref name=\"TInstance\"/>.\n    /// </summary>\n    /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n    /// <typeparam name=\"TParam1\">The first parameter type.</typeparam>\n    /// <typeparam name=\"TParam2\">The second parameter type.</typeparam>\n    /// <returns>The instance.</returns>\n    public delegate TInstance Factory<in TParam1, in TParam2, out TInstance>(TParam1 param1, TParam2 param2);\n\n    /// <summary>\n    /// Creates an instance of <typeparamref name=\"TInstance\"/>.\n    /// </summary>\n    /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n    /// <typeparam name=\"TParam1\">The first parameter type.</typeparam>\n    /// <typeparam name=\"TParam2\">The second parameter type.</typeparam>\n    /// <typeparam name=\"TParam3\">The third parameter type.</typeparam>\n    /// <returns>The instance.</returns>\n    public delegate TInstance Factory<in TParam1, in TParam2, in TParam3, out TInstance>(TParam1 param1, TParam2 param2, TParam3 param3);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/NamedOptionExtension.cs",
    "content": "using Microsoft.Extensions.Options;\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Extensions for working with named option classes.\n    /// </summary>\n    public static class NamedOptionExtensions\n    {\n        /// <summary>\n        /// Gets a named options instance.\n        /// </summary>\n        /// <typeparam name=\"TOption\">The type of the t option.</typeparam>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The name.</param>\n        /// <returns>TOption.</returns>\n        public static TOption GetOptionsByName<TOption>(this IServiceProvider services, string name)\n            where TOption : class, new()\n        {\n            return services.GetRequiredService<IOptionsMonitor<TOption>>().Get(name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/ObserverManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing System.Collections;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\nusing System.Linq;\n\nnamespace Orleans.Utilities;\n\n/// <summary>\n/// Maintains a collection of observers.\n/// </summary>\n/// <typeparam name=\"TObserver\">\n/// The observer type.\n/// </typeparam>\npublic class ObserverManager<TObserver> : ObserverManager<IAddressable, TObserver>\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ObserverManager{TObserver}\"/> class.\n    /// </summary>\n    /// <param name=\"expiration\">\n    /// The expiration.\n    /// </param>\n    /// <param name=\"log\">The log.</param>\n    public ObserverManager(TimeSpan expiration, ILogger log) : base(expiration, log)\n    {\n    }\n}\n\n/// <summary>\n/// Maintains a collection of observers.\n/// </summary>\n/// <typeparam name=\"TIdentity\">\n/// The address type, used to identify observers.\n/// </typeparam>\n/// <typeparam name=\"TObserver\">\n/// The observer type.\n/// </typeparam>\npublic partial class ObserverManager<TIdentity, TObserver> : IEnumerable<TObserver> where TIdentity : notnull\n{\n    /// <summary>\n    /// The observers.\n    /// </summary>\n    private Dictionary<TIdentity, ObserverEntry> _observers = [];\n\n    /// <summary>\n    /// The log.\n    /// </summary>\n    private readonly ILogger _log;\n\n    // The number of concurrent readers.\n    private int _numReaders;\n\n    // The most recently captured read snapshot.\n    // Each time a reader is added, we capture the current _observers reference here, signaling to writers\n    // that _observers must be set to a copy before modifying.\n    private Dictionary<TIdentity, ObserverEntry>? _readSnapshot;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ObserverManager{TIdentity,TObserver}\"/> class.\n    /// </summary>\n    /// <param name=\"expiration\">\n    /// The expiration.\n    /// </param>\n    /// <param name=\"log\">The log.</param>\n    public ObserverManager(TimeSpan expiration, ILogger log)\n    {\n        ArgumentNullException.ThrowIfNull(log);\n        ExpirationDuration = expiration;\n        _log = log;\n        GetDateTime = () => DateTime.UtcNow;\n    }\n\n    /// <summary>\n    /// Gets or sets the delegate used to get the date and time, for expiry.\n    /// </summary>\n    public Func<DateTime> GetDateTime { get; set; }\n\n    /// <summary>\n    /// Gets or sets the expiration time span, after which observers are lazily removed.\n    /// </summary>\n    public TimeSpan ExpirationDuration { get; set; }\n\n    /// <summary>\n    /// Gets the number of observers.\n    /// </summary>\n    public int Count => _observers.Count;\n\n    /// <summary>\n    /// Gets a copy of the observers.\n    /// </summary>\n    public IReadOnlyDictionary<TIdentity, TObserver> Observers => _observers.ToDictionary(_ => _.Key, _ => _.Value.Observer);\n\n    /// <summary>\n    /// Removes all observers.\n    /// </summary>\n    public void Clear()\n    {\n        var observers = GetWritableObservers();\n        observers.Clear();\n    }\n\n    /// <summary>\n    /// Ensures that the provided <paramref name=\"observer\"/> is subscribed, renewing its subscription.\n    /// </summary>\n    /// <param name=\"id\">\n    /// The observer's identity.\n    /// </param>\n    /// <param name=\"observer\">\n    /// The observer.\n    /// </param>\n    /// <exception cref=\"Exception\">A delegate callback throws an exception.</exception>\n    public void Subscribe(TIdentity id, TObserver observer)\n    {\n        var observers = GetWritableObservers();\n\n        // Add or update the subscription.\n        var now = GetDateTime();\n        if (observers.TryGetValue(id, out var entry))\n        {\n            entry.LastSeen = now;\n            entry.Observer = observer;\n            LogDebugUpdatingEntry(id, observer, _observers.Count);\n        }\n        else\n        {\n            _observers[id] = new ObserverEntry { LastSeen = now, Observer = observer };\n            LogDebugAddingEntry(id, observer, _observers.Count);\n        }\n    }\n\n    /// <summary>\n    /// Ensures that the provided <paramref name=\"id\"/> is unsubscribed.\n    /// </summary>\n    /// <param name=\"id\">\n    /// The observer.\n    /// </param>\n    public void Unsubscribe(TIdentity id)\n    {\n        var observers = GetWritableObservers();\n\n        observers.Remove(id, out _);\n        LogDebugRemovedEntry(id, observers.Count);\n    }\n\n    /// <summary>\n    /// Notifies all observers.\n    /// </summary>\n    /// <param name=\"notification\">\n    /// The notification delegate to call on each observer.\n    /// </param>\n    /// <param name=\"predicate\">\n    /// The predicate used to select observers to notify.\n    /// </param>\n    /// <returns>\n    /// A <see cref=\"Task\"/> representing the work performed.\n    /// </returns>\n    public async Task Notify(Func<TObserver, Task> notification, Func<TObserver, bool>? predicate = null)\n    {\n        var now = GetDateTime();\n        var defunct = default(List<TIdentity>);\n\n        using (var snapshot = CreateReadSnapshot())\n        {\n            foreach (var observerEntryPair in snapshot.Observers)\n            {\n                if (observerEntryPair.Value.LastSeen + ExpirationDuration < now)\n                {\n                    // Expired observers will be removed.\n                    defunct ??= [];\n                    defunct.Add(observerEntryPair.Key);\n                    continue;\n                }\n\n                // Skip observers which don't match the provided predicate.\n                if (predicate is not null && !predicate(observerEntryPair.Value.Observer))\n                {\n                    continue;\n                }\n\n                try\n                {\n                    await notification(observerEntryPair.Value.Observer);\n                }\n                catch (Exception)\n                {\n                    // Failing observers are considered defunct and will be removed.\n                    defunct ??= [];\n                    defunct.Add(observerEntryPair.Key);\n                }\n            }\n        }\n\n        RemoveDefunct(defunct);\n    }\n\n    /// <summary>\n    /// Notifies all observers which match the provided <paramref name=\"predicate\"/>.\n    /// </summary>\n    /// <param name=\"notification\">\n    /// The notification delegate to call on each observer.\n    /// </param>\n    /// <param name=\"predicate\">\n    /// The predicate used to select observers to notify.\n    /// </param>\n    public void Notify(Action<TObserver> notification, Func<TObserver, bool>? predicate = null)\n    {\n        var now = GetDateTime();\n        var defunct = default(List<TIdentity>);\n\n        using (var snapshot = CreateReadSnapshot())\n        {\n            foreach (var observerEntryPair in snapshot.Observers)\n            {\n                if (observerEntryPair.Value.LastSeen + ExpirationDuration < now)\n                {\n                    // Expired observers will be removed.\n                    defunct ??= [];\n                    defunct.Add(observerEntryPair.Key);\n                    continue;\n                }\n\n                // Skip observers which don't match the provided predicate.\n                if (predicate is not null && !predicate(observerEntryPair.Value.Observer))\n                {\n                    continue;\n                }\n\n                try\n                {\n                    notification(observerEntryPair.Value.Observer);\n                }\n                catch (Exception)\n                {\n                    // Failing observers are considered defunct and will be removed.\n                    defunct ??= [];\n                    defunct.Add(observerEntryPair.Key);\n                }\n            }\n        }\n\n        RemoveDefunct(defunct);\n    }\n\n    /// <summary>\n    /// Removed all expired observers.\n    /// </summary>\n    public void ClearExpired()\n    {\n        var defunct = default(List<TIdentity>);\n        using (var snapshot = CreateReadSnapshot())\n        {\n            var now = GetDateTime();\n\n            foreach (var observerEntryPair in snapshot.Observers)\n            {\n                if (observerEntryPair.Value.LastSeen + ExpirationDuration < now)\n                {\n                    // Expired observers will be removed.\n                    defunct ??= [];\n                    defunct.Add(observerEntryPair.Key);\n                }\n            }\n        }\n\n        RemoveDefunct(defunct);\n    }\n\n    private void RemoveDefunct(List<TIdentity>? defunct)\n    {\n        // Remove defunct observers.\n        if (defunct is { Count: > 0 })\n        {\n            var observers = GetWritableObservers();\n\n            LogDebugRemovingDefunctObservers(defunct.Count);\n            foreach (var observerIdToRemove in defunct)\n            {\n                observers.Remove(observerIdToRemove, out _);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Returns an enumerator that iterates through the collection.\n    /// </summary>\n    /// <returns>\n    /// A <see cref=\"T:System.Collections.Generic.IEnumerator`1\"/> that can be used to iterate through the collection.\n    /// </returns>\n    public IEnumerator<TObserver> GetEnumerator() => new ObserverEnumerator(CreateReadSnapshot());\n\n    /// <summary>\n    /// Returns an enumerator that iterates through a collection.\n    /// </summary>\n    /// <returns>\n    /// An <see cref=\"T:System.Collections.IEnumerator\"/> object that can be used to iterate through the collection.\n    /// </returns>\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    private ReadSnapshot CreateReadSnapshot()\n    {\n        ++_numReaders;\n        var observers = _readSnapshot = _observers;\n        return new(this, observers);\n    }\n\n    private Dictionary<TIdentity, ObserverEntry> GetWritableObservers()\n    {\n        if (_numReaders > 0 && ReferenceEquals(_observers, _readSnapshot))\n        {\n            _observers = new Dictionary<TIdentity, ObserverEntry>(_observers);\n        }\n\n        return _observers;\n    }\n\n    /// <summary>\n    /// An observer entry.\n    /// </summary>\n    private sealed class ObserverEntry\n    {\n        /// <summary>\n        /// Gets or sets the observer.\n        /// </summary>\n        public required TObserver Observer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the UTC last seen time.\n        /// </summary>\n        public DateTime LastSeen { get; set; }\n    }\n\n    private readonly struct ReadSnapshot(\n        ObserverManager<TIdentity, TObserver> manager,\n        IReadOnlyDictionary<TIdentity, ObserverEntry> snapshot) : IDisposable\n    {\n        public IReadOnlyDictionary<TIdentity, ObserverEntry> Observers { get; } = snapshot;\n\n        public void Dispose()\n        {\n            if (--manager._numReaders == 0)\n            {\n                manager._readSnapshot = null;\n            }\n        }\n    }\n\n    private sealed class ObserverEnumerator(ReadSnapshot snapshot) : IEnumerator<TObserver>\n    {\n        private bool _isDisposed;\n        private readonly IEnumerator<KeyValuePair<TIdentity, ObserverEntry>> _enumerator = snapshot.Observers.GetEnumerator();\n        public TObserver Current => _enumerator.Current.Value.Observer;\n        object? IEnumerator.Current => Current;\n        public void Dispose()\n        {\n            if (!_isDisposed)\n            {\n                _isDisposed = true;\n                _enumerator.Dispose();\n                snapshot.Dispose();\n            }\n        }\n\n        public bool MoveNext() => _enumerator.MoveNext();\n        public void Reset() => _enumerator.Reset();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Updating entry for {Id}/{Observer}. {Count} total observers.\"\n    )]\n    private partial void LogDebugUpdatingEntry(TIdentity id, TObserver observer, int count);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Adding entry for {Id}/{Observer}. {Count} total observers after add.\"\n    )]\n    private partial void LogDebugAddingEntry(TIdentity id, TObserver observer, int count);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Removed entry for {Id}. {Count} total observers after remove.\"\n    )]\n    private partial void LogDebugRemovedEntry(TIdentity id, int count);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Removing {Count} defunct observers entries.\"\n    )]\n    private partial void LogDebugRemovingDefunctObservers(int count);\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/RandomTimeSpan.cs",
    "content": "using System;\n\nnamespace Orleans.Internal\n{\n    /// <summary>\n    /// Random TimeSpan generator\n    /// </summary>\n    internal static class RandomTimeSpan\n    {\n        public static TimeSpan Next(TimeSpan timeSpan)\n        {\n            if (timeSpan.Ticks <= 0) throw new ArgumentOutOfRangeException(nameof(timeSpan), timeSpan, \"TimeSpan must be positive.\");\n            return TimeSpan.FromTicks(Random.Shared.NextInt64(timeSpan.Ticks));\n        }\n\n        public static TimeSpan Next(TimeSpan minValue, TimeSpan maxValue)\n        {\n            if (minValue.Ticks <= 0) throw new ArgumentOutOfRangeException(nameof(minValue), minValue, \"MinValue must be positive.\");\n            if (minValue >= maxValue) throw new ArgumentOutOfRangeException(nameof(minValue), minValue, \"MinValue must be less than maxValue.\");\n            return minValue + Next(maxValue - minValue);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/ReferenceEqualsComparer.cs",
    "content": "using System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans\n{\n    internal class ReferenceEqualsComparer : IEqualityComparer<object>\n    {\n        /// <summary>\n        /// Gets an instance of this class.\n        /// </summary>\n        public static ReferenceEqualsComparer Default { get; } = new ReferenceEqualsComparer();\n\n        /// <summary>\n        /// Defines object equality by reference equality (eq, in LISP).\n        /// </summary>\n        /// <returns>\n        /// true if the specified objects are equal; otherwise, false.\n        /// </returns>\n        /// <param name=\"x\">The first object to compare.</param><param name=\"y\">The second object to compare.</param>\n        public new bool Equals(object x, object y) => object.ReferenceEquals(x, y);\n\n        public int GetHashCode(object obj) => obj == null ? 0 : RuntimeHelpers.GetHashCode(obj);\n    }\n\n    internal class ReferenceEqualsComparer<T> : IEqualityComparer<T> where T : class\n    {\n        /// <summary>\n        /// Gets an instance of this class.\n        /// </summary>\n        public static ReferenceEqualsComparer<T> Default { get; } = new ReferenceEqualsComparer<T>();\n\n        /// <summary>\n        /// Defines object equality by reference equality (eq, in LISP).\n        /// </summary>\n        /// <returns>\n        /// true if the specified objects are equal; otherwise, false.\n        /// </returns>\n        /// <param name=\"x\">The first object to compare.</param><param name=\"y\">The second object to compare.</param>\n        public bool Equals(T x, T y) => object.ReferenceEquals(x, y);\n\n        public int GetHashCode(T obj) => obj == null ? 0 : RuntimeHelpers.GetHashCode(obj);\n    }\n}"
  },
  {
    "path": "src/Orleans.Core/Utils/SetExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans\n{\n    internal static class SetExtensions\n    {\n        /// <summary>\n        /// Shortcut to create HashSet from IEnumerable that supports type inference\n        /// (which the standard constructor does not)\n        /// </summary>\n        /// <typeparam name=\"T\">The element type</typeparam>\n        public static HashSet<T> ToSet<T>(this IEnumerable<T> values)\n        {\n            if (values == null)\n                return null;\n            return new HashSet<T>(values);\n        }\n\n        /// <summary>\n        /// ToString every element of an enumeration\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"list\"></param>\n        /// <param name=\"toString\">Can supply null to use Object.ToString()</param>\n        /// <param name=\"separator\">Before each element, or space if unspecified</param>\n        /// <returns></returns>\n        public static string ToStrings<T>(this IEnumerable<T> list, Func<T, object> toString = null, string separator = \" \")\n        {\n            if (list == null) return \"\";\n            toString = toString ?? (x => x);\n            //Func<T, string> toStringPrinter = (x => \n            //    {\n            //        object obj = toString(x);\n            //        if(obj != null)\n            //            return obj.ToString();\n            //        else\n            //            return \"null\";\n            //    });\n            //return Utils.IEnumerableToString(list, toStringPrinter, separator);\n            //Do NOT use Aggregate for string concatenation. It is very inefficient, will reallocate and copy lots of intermediate strings.\n            //toString = toString ?? (x => x);\n            return list.Aggregate(\"\", (s, x) => s + separator + toString(x));\n        }\n\n        public static T GetValueOrAddNew<T, TU>(this Dictionary<TU, T> dictionary, TU key) where T : new()\n        {\n            T result;\n            if (dictionary.TryGetValue(key, out result))\n                return result;\n\n            result = new T();\n            dictionary[key] = result;\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/StandardExtensions.cs",
    "content": "using System;\n\n\nnamespace Orleans.Internal\n{\n    /// <summary>\n    /// The Utils class contains a variety of utility methods for use in application and grain code.\n    /// </summary>\n    internal static class StandardExtensions\n    {\n        public static TimeSpan Max(TimeSpan first, TimeSpan second) => first >= second ? first : second;\n\n        public static TimeSpan Min(TimeSpan first, TimeSpan second) => first < second ? first : second;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/Utils/TypeConverterExtensions.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Utilities\n{\n    /// <summary>\n    /// Extensions for working with <see cref=\"TypeConverter\"/>.\n    /// </summary>\n    internal static class TypeConverterExtensions\n    {\n        private const char GenericTypeIndicator = '`';\n        private const char StartArgument = '[';\n\n        /// <summary>\n        /// Returns true if the provided type string is a generic type.\n        /// </summary>\n        public static bool IsGenericType(IdSpan type) => type.AsSpan().IndexOf((byte)GenericTypeIndicator) >= 0;\n\n        /// <summary>\n        /// Returns the generic arity of the specified grain type.\n        /// </summary>\n        public static int GetGenericTypeArity(IdSpan type)\n        {\n            var typeSpan = type.AsSpan();\n            var startIndex = typeSpan.IndexOf((byte)GenericTypeIndicator) + 1;\n            if (startIndex <= 0 || startIndex >= typeSpan.Length)\n            {\n                return 0;\n            }\n\n            int endIndex;\n            for (endIndex = startIndex; endIndex < typeSpan.Length; endIndex++)\n            {\n                var c = typeSpan[endIndex];\n                if (c is < ((byte)'0') or > ((byte)'9'))\n                {\n                    break;\n                }\n            }\n\n            if (endIndex > startIndex && Utf8Parser.TryParse(typeSpan[startIndex..endIndex], out int arity, out _))\n            {\n                return arity;\n            }\n\n            throw new InvalidOperationException($\"Unable to parse arity from type \\\"{type}\\\"\");\n        }\n\n        /// <summary>\n        /// Returns true if the provided type string is a constructed generic type.\n        /// </summary>\n        public static bool IsConstructed(IdSpan type) => type.AsSpan().IndexOf((byte)StartArgument) > 0;\n\n        /// <summary>\n        /// Returns the deconstructed form of the provided generic type.\n        /// </summary>\n        public static IdSpan GetDeconstructed(IdSpan type)\n        {\n            var span = type.AsSpan();\n            var index = span.IndexOf((byte)StartArgument);\n            return index <= 0 ? type : new IdSpan(span[..index].ToArray());\n        }\n\n        /// <summary>\n        /// Returns the constructed form of the provided generic type.\n        /// </summary>\n        public static IdSpan GetConstructed(this TypeConverter formatter, IdSpan unconstructed, params Type[] typeArguments)\n        {\n            var typeString = unconstructed.AsSpan();\n            var indicatorIndex = typeString.IndexOf((byte)GenericTypeIndicator);\n            var arityString = typeString[(indicatorIndex + 1)..];\n            if (indicatorIndex < 0 || arityString.IndexOf((byte)StartArgument) >= 0)\n            {\n                throw new InvalidOperationException(\"Cannot construct an already-constructed type\");\n            }\n\n            if (!Utf8Parser.TryParse(arityString, out int arity, out var len) || len < arityString.Length || typeArguments.Length != arity)\n            {\n                throw new InvalidOperationException($\"Insufficient number of type arguments, {typeArguments.Length}, provided while constructing type \\\"{unconstructed}\\\"\");\n            }\n\n            var typeSpecs = new TypeSpec[typeArguments.Length];\n            for (var i = 0; i < typeArguments.Length; i++)\n            {\n                typeSpecs[i] = RuntimeTypeNameParser.Parse(formatter.Format(typeArguments[i]));\n            }\n\n            var constructed = new ConstructedGenericTypeSpec(new NamedTypeSpec(null, unconstructed.ToString(), typeArguments.Length), typeArguments.Length, typeSpecs).Format();\n            return IdSpan.Create(constructed);\n        }\n\n        /// <summary>\n        /// Returns the constructed form of the provided generic grain type using the type arguments from the provided constructed interface type.\n        /// </summary>\n        public static GrainType GetConstructed(this GenericGrainType genericGrainType, GenericGrainInterfaceType genericGrainInterfaceType)\n        {\n            if (genericGrainType.Arity != genericGrainInterfaceType.Arity)\n            {\n                ThrowGenericArityMismatch(genericGrainType, genericGrainInterfaceType);\n            }\n\n            var grainType = genericGrainType.GrainType;\n            var typeArguments = genericGrainInterfaceType.Value;\n            var args = typeArguments.Value.AsSpan();\n            var index = args.IndexOf((byte)StartArgument);\n            if (index <= 0) return grainType; // if no type arguments are provided, then the current logic expects the unconstructed form (but the grain call is going to fail later anyway...)\n            args = args[index..];\n\n            var type = grainType.Value.AsSpan();\n            var buf = new byte[type.Length + args.Length];\n            type.CopyTo(buf);\n            args.CopyTo(buf.AsSpan(type.Length));\n            return new GrainType(buf);\n        }\n\n        /// <summary>\n        /// Returns the type arguments for the provided constructed generic type string.\n        /// </summary>\n        public static Type[] GetArguments(this TypeConverter formatter, IdSpan constructed)\n        {\n            var str = constructed.AsSpan();\n            var index = str.IndexOf((byte)StartArgument);\n            if (index <= 0)\n            {\n                return Array.Empty<Type>();\n            }\n\n            var safeString = \"safer\" + Encoding.UTF8.GetString(str[str.IndexOf((byte)GenericTypeIndicator)..]);\n            var parsed = RuntimeTypeNameParser.Parse(safeString);\n            if (!(parsed is ConstructedGenericTypeSpec spec))\n            {\n                throw new InvalidOperationException($\"Unable to correctly parse grain type {constructed}\");\n            }\n\n            var result = new Type[spec.Arguments.Length];\n            for (var i = 0; i < result.Length; i++)\n            {\n                var arg = spec.Arguments[i];\n                var formattedArg = arg.Format();\n                result[i] = formatter.Parse(formattedArg);\n                if (result[i] is null)\n                {\n                    throw new InvalidOperationException($\"Unable to parse argument \\\"{formattedArg}\\\" as a type for grain type \\\"{constructed}\\\"\");\n                }\n            }\n\n            return result;\n        }\n\n        [DoesNotReturn]\n        private static void ThrowGenericArityMismatch(GenericGrainType genericGrainType, GenericGrainInterfaceType genericInterfaceType)\n            => throw new ArgumentException($\"Cannot construct generic grain \\\"{genericGrainType.GrainType}\\\" using arguments from generic interface \\\"{genericInterfaceType}\\\" because the generic arities are not equal: {genericGrainType.Arity} is not equal to {genericInterfaceType.Arity}.\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core/build/Microsoft.Orleans.Core.targets",
    "content": "<Project>\n\n  <ItemGroup Condition=\"'$(ImplicitUsings)' == 'enable' or '$(ImplicitUsings)' == 'true'\">\n    <Using Include=\"Orleans\" />\n    <Using Include=\"Orleans.Hosting\" />\n    <Using Include=\"Orleans.Runtime\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Core/buildMultiTargeting/Microsoft.Orleans.Core.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Core.targets\" />\n</Project>\n"
  },
  {
    "path": "src/Orleans.Core/buildTransitive/Microsoft.Orleans.Core.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Core.targets\" />\n</Project>\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Cancellation/GrainCancellationToken.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// An analogue to <see cref=\"CancellationToken\"/> which can be sent between grains.\n    /// </summary>\n    [Immutable]\n    public sealed class GrainCancellationToken : IDisposable\n    {\n        /// <summary>\n        /// The underlying cancellation token source.\n        /// </summary>\n        [NonSerialized]\n        private readonly CancellationTokenSource _cancellationTokenSource;\n\n        /// <summary>\n        /// References to remote grains to which this token was passed.\n        /// </summary>\n        [NonSerialized]\n        private readonly ConcurrentDictionary<GrainId, GrainReference> _targetGrainReferences;\n\n        /// <summary>\n        /// The runtime used to manage grain cancellation tokens.\n        /// </summary>\n        [NonSerialized]\n        private IGrainCancellationTokenRuntime? _cancellationTokenRuntime;\n\n        /// <summary>\n        /// Initializes the <see cref=\"T:Orleans.GrainCancellationToken\"/>.\n        /// </summary>\n        /// <param name=\"id\">\n        /// The token id.\n        /// </param>\n        internal GrainCancellationToken(Guid id)\n        {\n            _cancellationTokenSource = new CancellationTokenSource();\n            Id = id;\n            _targetGrainReferences = new ConcurrentDictionary<GrainId, GrainReference>();\n        }\n\n        /// <summary>\n        /// Initializes the <see cref=\"T:Orleans.GrainCancellationToken\"/>.\n        /// </summary>\n        /// <param name=\"id\">\n        /// The token id.\n        /// </param>\n        /// <param name=\"canceled\">\n        /// Whether or not the instance is already canceled.\n        /// </param>\n        /// <param name=\"runtime\">\n        /// The runtime.\n        /// </param>\n        internal GrainCancellationToken(Guid id, bool canceled, IGrainCancellationTokenRuntime? runtime = null) : this(id)\n        {\n            _cancellationTokenRuntime = runtime;\n            if (canceled)\n            {\n                // we Cancel _cancellationTokenSource just \"to store\" the cancelled state.\n                _cancellationTokenSource.Cancel();\n            }\n        }\n\n        /// <summary>\n        /// Gets the unique id of the token\n        /// </summary>\n        internal Guid Id { get; private set; }\n\n        /// <summary>\n        /// Gets the underlying cancellation token.\n        /// </summary>\n        public CancellationToken CancellationToken => _cancellationTokenSource.Token;\n\n        /// <summary>\n        /// Gets a value indicating if cancellation is requested.\n        /// </summary>\n        internal bool IsCancellationRequested => _cancellationTokenSource.IsCancellationRequested;\n\n        /// <summary>\n        /// Cancels the cancellation token.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        internal Task Cancel()\n        {\n            if (_cancellationTokenRuntime == null)\n            {\n                // Wrap in task\n                try\n                {\n                    _cancellationTokenSource.Cancel();\n                    return Task.CompletedTask;\n                }\n                catch (Exception exception)\n                {\n                    var completion = new TaskCompletionSource<object>();\n                    completion.TrySetException(exception);\n                    return completion.Task;\n                }\n            }\n\n            return _cancellationTokenRuntime.Cancel(Id, _cancellationTokenSource, _targetGrainReferences);\n        }\n\n        /// <summary>\n        /// Subscribes the provided grain reference to cancellation notifications.\n        /// </summary>\n        /// <param name=\"runtime\">The grain cancellation runtime.</param>\n        /// <param name=\"grainReference\">The grain reference to add.</param>\n        internal void AddGrainReference(IGrainCancellationTokenRuntime runtime, GrainReference grainReference)\n        {\n            if (_cancellationTokenRuntime == null)\n                _cancellationTokenRuntime = runtime;\n            _targetGrainReferences.TryAdd(grainReference.GrainId, grainReference);\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            _cancellationTokenSource.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Cancellation/GrainCancellationTokenSource.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing System.Threading;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// An analogue to <see cref=\"CancellationTokenSource\"/> which can be sent between grains.\n    /// </summary>\n    public sealed class GrainCancellationTokenSource : IDisposable\n    {\n        /// <summary>\n        /// The underlying grain cancellation token.\n        /// </summary>\n        private readonly GrainCancellationToken _grainCancellationToken;\n\n        /// <summary>\n        /// Initializes the <see cref=\"T:Orleans.GrainCancellationTokenSource\"/>.\n        /// </summary>\n        public GrainCancellationTokenSource()\n        {\n            _grainCancellationToken = new GrainCancellationToken(Guid.NewGuid());\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"GrainCancellationTokenSource\">CancellationToken</see>\n        /// associated with this <see cref=\"GrainCancellationTokenSource\"/>.\n        /// </summary>\n        /// <value>The <see cref=\"GrainCancellationToken\">CancellationToken</see>\n        /// associated with this <see cref=\"GrainCancellationToken\"/>.</value>\n        public GrainCancellationToken Token\n        {\n            get { return _grainCancellationToken; }\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether cancellation has been requested.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// This property indicates whether cancellation has been requested for this token source, such as due to a call to its <see cref=\"Cancel()\" /> method.\n        /// </para>\n        /// <para>\n        /// If this property returns true, it only guarantees that cancellation has been requested. It does not guarantee that every handler registered with the corresponding token has finished executing, nor that\n        /// cancellation requests have finished propagating to all registered handlers and remote targets. Additional synchronization may be required, particularly in situations where related objects are being canceled\n        /// concurrently.\n        /// </para>\n        /// </remarks>\n        public bool IsCancellationRequested\n        {\n            get { return _grainCancellationToken.IsCancellationRequested; }\n        }\n\n        /// <summary>\n        /// Communicates a request for cancellation.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// The associated <see cref=\"GrainCancellationToken\" /> will be notified of the cancellation and will transition to a state where\n        /// <see cref=\"GrainCancellationToken.CancellationToken\"><see cref=\"IsCancellationRequested\"/></see> returns true. Any callbacks or cancelable operations registered with the\n        /// <see cref=\"CancellationToken\" /> will be executed.\n        /// </para>\n        /// <para>\n        /// Cancelable operations and callbacks registered with the token should not <see langword=\"throw\"/> exceptions. However, this overload of <see cref=\"Cancel\"/> will aggregate any exceptions thrown into a\n        /// <see cref=\"AggregateException\" /> , such that one callback throwing an exception will not prevent other registered callbacks from being executed.\n        /// </para>\n        /// <para>The <see cref=\"System.Threading.ExecutionContext\" /> that was captured when each callback was registered will be reestablished when the callback is invoked.</para>\n        /// </remarks>\n        /// <exception cref=\"AggregateException\">An aggregate exception containing all the exceptions thrown by the registered callbacks on the associated <see cref=\"GrainCancellationToken\" /> .</exception>\n        /// <exception cref=\"ObjectDisposedException\">This <see cref=\"GrainCancellationTokenSource\" /> has been disposed.</exception>\n        public Task Cancel()\n        {\n            return _grainCancellationToken.Cancel();\n        }\n\n        /// <summary>\n        /// Releases the resources used by this <see cref=\"T:Orleans.Async.GrainCancellationTokenSource\" />.\n        /// </summary>\n        /// <remarks>\n        /// This method is not thread-safe for any other concurrent calls.\n        /// </remarks>\n        public void Dispose()\n        {\n            _grainCancellationToken.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Cancellation/ICancellationSourcesExtension.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Extension used by the grain cancellation runtime to propagate cancellation notifications to grains.\n    /// </summary>\n    internal interface ICancellationSourcesExtension : IGrainExtension\n    {\n        /// <summary>\n        /// Indicates that a cancellation token has been canceled.\n        /// </summary>\n        /// <param name=\"tokenId\">\n        /// The token id.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        [AlwaysInterleave]\n        Task CancelRemoteToken(Guid tokenId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/CodeGeneration/IOnDeserialized.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Indicates that a class is to be notified when it has been deserialized.\n    /// </summary>\n    public interface IOnDeserialized\n    {\n        /// <summary>\n        /// Notifies this instance that it has been fully deserialized.\n        /// </summary>\n        /// <param name=\"context\">The serializer context.</param>\n        void OnDeserialized(DeserializationContext context);\n    }\n\n    public abstract class DeserializationContext\n    {\n        public abstract IServiceProvider ServiceProvider { get; }\n        public abstract object RuntimeClient { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/CodeGeneration/InvokeMethodOptions.cs",
    "content": "using System;\n\nnamespace Orleans.CodeGeneration\n{\n    /// <summary>\n    /// Invoke options for an <c>InvokeMethodRequest</c>\n    /// </summary>\n    /// <remarks>\n    /// These flag values are used in Orleans generated invoker code, and should not be altered. </remarks>\n    [Flags]\n    [GenerateSerializer]\n    public enum InvokeMethodOptions\n    {\n        /// <summary>No options defined.</summary>\n        None = 0,\n\n        /// <summary>Invocation is one-way with no feedback on whether the call succeeds or fails.</summary>\n        OneWay = 1 << 0,\n\n        /// <summary>Invocation is read-only and can interleave with other read-only invocations.</summary>\n        ReadOnly = 1 << 1,\n\n        /// <summary>The invocation can interleave with any other request type, including write requests.</summary>\n        AlwaysInterleave = 1 << 2,\n\n        /// <summary>Invocation does not care about ordering and can consequently be optimized.</summary>\n        Unordered = 1 << 3,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/CodeGeneration/VersionAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing Orleans.Metadata;\n\nnamespace Orleans.CodeGeneration\n{\n    /// <summary>\n    /// The VersionAttribute allows to specify the version number of the interface\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Interface)]\n    public sealed class VersionAttribute : Attribute, IGrainInterfacePropertiesProviderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"VersionAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"version\">\n        /// The version.\n        /// </param>\n        public VersionAttribute(ushort version)\n        {\n            Version = version;\n        }\n\n        /// <summary>\n        /// Gets the version.\n        /// </summary>\n        public ushort Version { get; private set; }\n\n        /// <inheritdoc />\n        void IGrainInterfacePropertiesProviderAttribute.Populate(IServiceProvider services, Type type, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainInterfaceProperties.Version] = this.Version.ToString(CultureInfo.InvariantCulture);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Concurrency/GrainAttributeConcurrency.cs",
    "content": "using Orleans.CodeGeneration;\nusing Orleans.Metadata;\nusing Orleans.Placement;\nusing Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\n\nnamespace Orleans.Concurrency\n{\n    /// <summary>\n    /// The ReadOnly attribute is used to mark methods that do not modify the state of a grain.\n    /// <para>\n    /// Marking methods as ReadOnly allows the run-time system to perform a number of optimizations\n    /// that may significantly improve the performance of your application.\n    /// </para>\n    /// </summary>\n    [InvokableCustomInitializer(nameof(IRequest.AddInvokeMethodOptions), InvokeMethodOptions.ReadOnly)]\n    [AttributeUsage(AttributeTargets.Method)]\n    public sealed class ReadOnlyAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// The Reentrant attribute is used to mark grain implementation classes that allow request interleaving within a task.\n    /// <para>\n    /// This is an advanced feature and should not be used unless the implications are fully understood.\n    /// That said, allowing request interleaving allows the run-time system to perform a number of optimizations\n    /// that may significantly improve the performance of your application.\n    /// </para>\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class ReentrantAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        /// <inheritdoc/>\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.Reentrant] = \"true\";\n        }\n    }\n\n    /// <summary>\n    /// The Unordered attribute is used to mark grain interface in which the delivery order of\n    /// messages is not significant.\n    /// </summary>\n    /// <remarks>\n    /// This attribute has no effect and it may be removed in a future release.\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Interface)]\n    [Obsolete(\"Message ordering is not guaranteed regardless of whether this attribute is used. This attribute has no effect.\")]\n    public sealed class UnorderedAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// The StatelessWorker attribute is used to mark grain class in which there is no expectation\n    /// of preservation of grain state between requests and where multiple activations of the same grain are allowed to be created by the runtime.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class StatelessWorkerAttribute : PlacementAttribute, IGrainPropertiesProviderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"maxLocalWorkers\">The maximum local workers.</param>\n        public StatelessWorkerAttribute(int maxLocalWorkers)\n            : base(new StatelessWorkerPlacement(maxLocalWorkers))\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"maxLocalWorkers\">The maximum local workers.</param>\n        public StatelessWorkerAttribute(int maxLocalWorkers, bool removeIdleWorkers)\n            : base(new StatelessWorkerPlacement(maxLocalWorkers, removeIdleWorkers))\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerAttribute\"/> class.\n        /// </summary>\n        public StatelessWorkerAttribute()\n            : base(new StatelessWorkerPlacement())\n        {\n        }\n\n        /// <inheritdoc/>\n        public override void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            base.Populate(services, grainClass, grainType, properties);\n            properties[WellKnownGrainTypeProperties.Unordered] = \"true\";\n        }\n    }\n\n    /// <summary>\n    /// The AlwaysInterleaveAttribute attribute is used to mark methods that can interleave with any method, including write (non ReadOnly) requests.\n    /// </summary>\n    /// <remarks>\n    /// Note that this attribute is applied to method declaration in the grain interface,\n    /// and not to the method in the implementation class itself.\n    /// </remarks>\n    [InvokableCustomInitializer(nameof(IRequest.AddInvokeMethodOptions), InvokeMethodOptions.AlwaysInterleave)]\n    [AttributeUsage(AttributeTargets.Method)]\n    public sealed class AlwaysInterleaveAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// The MayInterleaveAttribute attribute is used to mark classes\n    /// that want to control request interleaving via supplied method callback.\n    /// </summary>\n    /// <remarks>\n    /// The callback method name should point to a public static function declared on the same class\n    /// and having the following signature: <c>public static bool MayInterleave(IInvokable req)</c>\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class MayInterleaveAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MayInterleaveAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"callbackMethodName\">\n        /// The callback method name. This should resolve to a method with the \n        /// following signature: <c>public static bool NameOfMethod(IInvokable req)</c>\n        /// </param>\n        public MayInterleaveAttribute(string callbackMethodName)\n        {\n            this.CallbackMethodName = callbackMethodName;\n        }\n\n        /// <summary>\n        /// Gets the name of the callback method\n        /// </summary>\n        internal string CallbackMethodName { get; private set; }\n\n\n        /// <inheritdoc/>\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.MayInterleavePredicate] = this.CallbackMethodName;\n        }\n    }\n\n    /// <summary>\n    /// Indicates that a method on a grain interface is one-way and that no response message will be sent to the caller.\n    /// </summary>\n    [InvokableCustomInitializer(nameof(IRequest.AddInvokeMethodOptions), InvokeMethodOptions.OneWay)]\n    [AttributeUsage(AttributeTargets.Method)]\n    public sealed class OneWayAttribute : Attribute\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/DeactivationReason.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Represents a reason for initiating grain deactivation.\n    /// </summary>\n    public readonly struct DeactivationReason\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DeactivationReason\"/> struct.\n        /// </summary>\n        /// <param name=\"code\">\n        /// The code identifying the deactivation reason.\n        /// </param>\n        /// <param name=\"text\">\n        /// A descriptive reason for the deactivation.\n        /// </param>\n        public DeactivationReason(DeactivationReasonCode code, string text)\n        {\n            ReasonCode = code;\n            Description = text;\n            Exception = null;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DeactivationReason\"/> struct.\n        /// </summary>\n        /// <param name=\"code\">\n        /// The code identifying the deactivation reason.\n        /// </param>\n        /// <param name=\"exception\">\n        /// The exception which resulted in deactivation.\n        /// </param>\n        /// <param name=\"text\">\n        /// A descriptive reason for the deactivation.\n        /// </param>\n        public DeactivationReason(DeactivationReasonCode code, Exception? exception, string text)\n        {\n            ReasonCode = code;\n            Description = text;\n            Exception = exception;\n        }\n\n        /// <summary>\n        /// Gets the descriptive reason for the deactivation.\n        /// </summary>\n        public string Description { get; }\n\n        /// <summary>\n        /// Gets the reason for deactivation.\n        /// </summary>\n        public DeactivationReasonCode ReasonCode { get; }\n\n        /// <summary>\n        /// Gets the exception which resulted in deactivation.\n        /// </summary>\n        public Exception? Exception { get; }\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            if (Exception is not null)\n            {\n                return $\"{ReasonCode}: {Description}. Exception: {Exception}\";\n            }\n\n            return $\"{ReasonCode}: {Description}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/Grain.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Core;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans;\n\n/// <summary>\n/// The abstract base class for all grain classes.\n/// </summary>\npublic abstract partial class Grain : IGrainBase, IAddressable\n{\n    // Do not use this directly because we currently don't provide a way to inject it;\n    // any interaction with it will result in non unit-testable code. Any behavior that can be accessed\n    // from within client code (including subclasses of this class), should be exposed through IGrainRuntime.\n    // The better solution is to refactor this interface and make it injectable through the constructor.\n    [AllowNull]\n    public IGrainContext GrainContext { get; private set; }\n\n    public GrainReference GrainReference { get { return GrainContext.GrainReference; } }\n\n    internal IGrainRuntime Runtime { get; }\n\n    /// <summary>\n    /// Gets an object which can be used to access other grains. Null if this grain is not associated with a Runtime, such as when created directly for unit testing.\n    /// </summary>\n    protected IGrainFactory GrainFactory => Runtime.GrainFactory;\n\n    /// <summary>\n    /// Gets the IServiceProvider managed by the runtime. Null if this grain is not associated with a Runtime, such as when created directly for unit testing.\n    /// </summary>\n    // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n    protected internal IServiceProvider ServiceProvider => GrainContext?.ActivationServices ?? Runtime?.ServiceProvider!;\n\n    internal GrainId GrainId => GrainContext.GrainId;\n\n    /// <summary>\n    /// This constructor should never be invoked. We expose it so that client code (subclasses of Grain) do not have to add a constructor.\n    /// Client code should use the GrainFactory property to get a reference to a Grain.\n    /// </summary>\n    // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n    protected Grain() : this(RuntimeContext.Current!, grainRuntime: null)\n    {}\n\n    /// <summary>\n    /// Grain implementers do NOT have to expose this constructor but can choose to do so.\n    /// This constructor is particularly useful for unit testing where test code can create a Grain and replace\n    /// the IGrainIdentity and IGrainRuntime with test doubles (mocks/stubs).\n    /// </summary>\n    protected Grain(IGrainContext grainContext, IGrainRuntime? grainRuntime = null)\n    {\n        GrainContext = grainContext;\n\n        // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n        Runtime = grainRuntime ?? grainContext?.ActivationServices.GetService<IGrainRuntime>()!;\n    }\n\n    /// <summary>\n    /// String representation of grain's SiloIdentity including type and primary key.\n    /// </summary>\n    public string IdentityString => GrainId.ToString();\n\n    /// <summary>\n    /// A unique identifier for the current silo.\n    /// There is no semantic content to this string, but it may be useful for logging.\n    /// </summary>\n    public string RuntimeIdentity => Runtime?.SiloIdentity ?? string.Empty;\n\n    /// <summary>\n    /// Registers a timer to send periodic callbacks to this grain.\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// This timer will not prevent the current grain from being deactivated.\n    /// If the grain is deactivated, then the timer will be discarded.\n    /// </para>\n    /// <para>\n    /// Until the Task returned from the callback is resolved,\n    /// the next timer tick will not be scheduled.\n    /// That is to say, timer callbacks never interleave their turns.\n    /// </para>\n    /// <para>\n    /// The timer may be stopped at any time by calling the <c>Dispose</c> method\n    /// on the timer handle returned from this call.\n    /// </para>\n    /// <para>\n    /// Any exceptions thrown by or faulted Task's returned from the callback \n    /// will be logged, but will not prevent the next timer tick from being queued.\n    /// </para>\n    /// </remarks>\n    /// <param name=\"callback\">Callback function to be invoked when timer ticks.</param>\n    /// <param name=\"state\">State object that will be passed as argument when calling the <paramref name=\"callback\"/>.</param>\n    /// <param name=\"dueTime\">Due time for first timer tick.</param>\n    /// <param name=\"period\">Period of subsequent timer ticks.</param>\n    /// <returns>Handle for this timer.</returns>\n    [Obsolete(\"Use 'this.RegisterGrainTimer(callback, state, new() { DueTime = dueTime, Period = period, Interleave = true })' instead.\")]\n    protected IDisposable RegisterTimer(Func<object?, Task> callback, object? state, TimeSpan dueTime, TimeSpan period)\n    {\n        ArgumentNullException.ThrowIfNull(callback);\n\n        EnsureRuntime();\n\n        // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n        return Runtime.TimerRegistry.RegisterTimer(GrainContext ?? RuntimeContext.Current!, callback, state, dueTime, period);\n    }\n\n    /// <summary>\n    /// Deactivate this activation of the grain after the current grain method call is completed.\n    /// This call will mark this activation of the current grain to be deactivated and removed at the end of the current method.\n    /// The next call to this grain will result in a different activation to be used, which typical means a new activation will be created automatically by the runtime.\n    /// </summary>\n    protected void DeactivateOnIdle()\n    {\n        EnsureRuntime();\n\n        // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n        Runtime.DeactivateOnIdle(GrainContext ?? RuntimeContext.Current!);\n    }\n\n    /// <summary>\n    /// Starts an attempt to migrating this instance to another location.\n    /// Migration captures the current <see cref=\"RequestContext\"/>, making it available to the activation's placement director so that it can consider it when selecting a new location.\n    /// Migration will occur asynchronously, when no requests are executing, and will not occur if the activation's placement director does not select an alternative location.\n    /// </summary>\n    protected void MigrateOnIdle()\n    {\n        EnsureRuntime();\n        ((IGrainBase)this).MigrateOnIdle();\n    }\n\n    /// <summary>\n    /// Delay Deactivation of this activation at least for the specified time duration.\n    /// A positive <c>timeSpan</c> value means “prevent GC of this activation for that time span”.\n    /// A negative <c>timeSpan</c> value means “cancel the previous setting of the DelayDeactivation call and make this activation behave based on the regular Activation Garbage Collection settings”.\n    /// DeactivateOnIdle method would undo / override any current “keep alive” setting,\n    /// making this grain immediately available for deactivation.\n    /// </summary>\n    protected void DelayDeactivation(TimeSpan timeSpan)\n    {\n        EnsureRuntime();\n\n        // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n        Runtime.DelayDeactivation(GrainContext ?? RuntimeContext.Current!, timeSpan);\n    }\n\n    /// <summary>\n    /// This method is called at the end of the process of activating a grain.\n    /// It is called before any messages have been dispatched to the grain.\n    /// For grains with declared persistent state, this method is called after the State property has been populated.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A cancellation token which signals when activation is being canceled.</param>\n    public virtual Task OnActivateAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n\n    /// <summary>\n    /// This method is called at the beginning of the process of deactivating a grain.\n    /// </summary>\n    /// <param name=\"reason\">The reason for deactivation. Informational only.</param>\n    /// <param name=\"cancellationToken\">A cancellation token which signals when deactivation should complete promptly.</param>\n    public virtual Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken) => Task.CompletedTask;\n\n    internal void EnsureRuntime()\n    {\n        if (Runtime == null)\n        {\n            throw new InvalidOperationException(\"Grain was created outside of the Orleans creation process and no runtime was specified.\");\n        }\n    }\n}\n\n/// <summary>\n/// Base class for a Grain with declared persistent state.\n/// </summary>\n/// <typeparam name=\"TGrainState\">The class of the persistent state object</typeparam>\npublic class Grain<TGrainState> : Grain\n{\n    /// <summary>\n    /// The underlying state storage.\n    /// </summary>\n    [AllowNull] // This is set by the runtime during activation, so it can be null in the constructor.\n    private IStorage<TGrainState> _storage;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Grain{TGrainState}\"/> class.\n    /// </summary>\n    /// <remarks>\n    /// This constructor should never be invoked. We expose it so that client code (subclasses of this class) do not have to add a constructor.\n    /// Client code should use the GrainFactory to get a reference to a Grain.\n    /// </remarks>\n    protected Grain()\n    {\n        var observer = new LifecycleObserver(this);\n\n        // ! The runtime ensures that this is not null and Unit testing frameworks must make sure that this is not null.\n        var lifecycle = RuntimeContext.Current!.ObservableLifecycle;\n        lifecycle.AddMigrationParticipant(observer);\n        lifecycle.Subscribe(RuntimeTypeNameFormatter.Format(GetType()), GrainLifecycleStage.SetupState, observer);\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"Grain{TGrainState}\"/> class.\n    /// </summary>\n    /// <param name=\"storage\">\n    /// The storage implementation.\n    /// </param>\n    /// <remarks>\n    /// Grain implementers do NOT have to expose this constructor but can choose to do so.\n    /// This constructor is particularly useful for unit testing where test code can create a Grain and replace\n    /// the IGrainIdentity, IGrainRuntime and State with test doubles (mocks/stubs).\n    /// </remarks>\n    protected Grain(IStorage<TGrainState> storage)\n    {\n        _storage = storage;\n    }\n\n    /// <summary>\n    /// Gets or sets the grain state.\n    /// </summary>\n    protected TGrainState State\n    {\n        get => _storage.State;\n        set => _storage.State = value;\n    }\n\n    /// <summary>\n    /// Clears the current grain state data from backing store.\n    /// </summary>\n    /// <returns>\n    /// A <see cref=\"Task\"/> representing the operation.\n    /// </returns>\n    protected virtual Task ClearStateAsync() => _storage.ClearStateAsync();\n\n    /// <summary>\n    /// Write the current grain state data into the backing store.\n    /// </summary>\n    /// <returns>\n    /// A <see cref=\"Task\"/> representing the operation.\n    /// </returns>\n    protected virtual Task WriteStateAsync() => _storage.WriteStateAsync();\n\n    /// <summary>\n    /// Reads grain state from backing store, updating <see cref=\"State\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Any previous contents of the grain state data will be overwritten.\n    /// </remarks>\n    /// <returns>\n    /// A <see cref=\"Task\"/> representing the operation.\n    /// </returns>\n    protected virtual Task ReadStateAsync() => _storage.ReadStateAsync();\n\n    private class LifecycleObserver : ILifecycleObserver, IGrainMigrationParticipant\n    {\n        private const string StorageMigratedKey = \"grain-state-migrated\";\n        private readonly Grain<TGrainState> _grain;\n        private bool _isInitialized;\n\n        public LifecycleObserver(Grain<TGrainState> grain) => _grain = grain;\n\n        private void SetupStorage() => _grain._storage ??= _grain.Runtime.GetStorage<TGrainState>(_grain.GrainContext);\n\n        public void OnDehydrate(IDehydrationContext dehydrationContext)\n        {\n            var storage = _grain._storage;\n            if (storage is IGrainMigrationParticipant migrationParticipant)\n            {\n                dehydrationContext.TryAddValue(StorageMigratedKey, true);\n                migrationParticipant.OnDehydrate(dehydrationContext);\n            }\n        }\n\n        public void OnRehydrate(IRehydrationContext rehydrationContext)\n        {\n            SetupStorage();\n            if (_grain._storage is IGrainMigrationParticipant migrationParticipant)\n            {\n                _isInitialized = rehydrationContext.TryGetValue(StorageMigratedKey, out bool isMigrated) && isMigrated;\n                migrationParticipant.OnRehydrate(rehydrationContext);\n            }\n        }\n\n        public Task OnStart(CancellationToken cancellationToken = default)\n        {\n            if (cancellationToken.IsCancellationRequested)\n            {\n                return Task.CompletedTask;\n            }\n\n            // Avoid reading the state if it is already present because of rehydration\n            if (_isInitialized || _grain._storage?.Etag is not null)\n            {\n                return Task.CompletedTask;\n            }\n\n            SetupStorage();\n            return _grain.ReadStateAsync();\n        }\n\n        public Task OnStop(CancellationToken cancellationToken = default) => Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/GrainExtensions.cs",
    "content": "using System;\nusing Orleans.Runtime;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Extension methods for grains.\n    /// </summary>\n    public static class GrainExtensions\n    {\n        private const string WRONG_GRAIN_ERROR_MSG = \"Passing a half baked grain as an argument. It is possible that you instantiated a grain class explicitly, as a regular object and not via Orleans runtime or via proper test mocking\";\n\n        /// <summary>\n        /// Returns a reference to the provided grain.\n        /// </summary>\n        /// <param name=\"grain\">The grain to create a reference for.</param>\n        /// <returns>A reference to the provided grain.</returns>\n        internal static GrainReference AsReference(this IAddressable grain)\n        {\n            if (grain is null)\n            {\n                ThrowGrainNull();\n            }\n\n            // When called against an instance of a grain reference class, do nothing\n            var reference = grain as GrainReference;\n            if (reference != null) return reference;\n\n            var context = grain switch\n            {\n                Grain grainBase => grainBase.GrainContext,\n                IGrainBase activation => activation.GrainContext,\n                ISystemTargetBase systemTarget => systemTarget,\n                _ => throw new ArgumentException(GetWrongGrainTypeErrorMessage(grain), nameof(grain))\n            };\n\n            if (context?.GrainReference is not { } grainRef)\n            {\n                throw new ArgumentException(WRONG_GRAIN_ERROR_MSG, nameof(grain));\n            }\n\n            return grainRef;\n        }\n\n        /// <summary>\n        /// Returns a typed reference to the provided grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The type of the grain interface.</typeparam>\n        /// <param name=\"grain\">The grain to convert.</param>\n        /// <remarks>\n        /// If the provided value is a grain instance, this will create a reference which implements the provided interface.\n        /// If the provided value is already grain reference, this will create a new reference which implements the provided interface.\n        /// </remarks>\n        /// <returns>A strongly typed reference to the provided grain which implements <typeparamref name=\"TGrainInterface\"/>.</returns>\n        public static TGrainInterface AsReference<TGrainInterface>(this IAddressable grain)\n        {\n            if (grain is null)\n            {\n                ThrowGrainNull();\n            }\n\n            var grainReference = grain.AsReference();\n            return (TGrainInterface)grainReference.Runtime.Cast(grain, typeof(TGrainInterface));\n        }\n\n        /// <summary>\n        /// Returns a typed reference to the provided grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The type of the grain interface.</typeparam>\n        /// <param name=\"grain\">The grain to convert.</param>\n        /// <remarks>\n        /// This method is equivalent to <see cref=\"AsReference{TGrainInterface}\"/>.\n        /// If the provided value is a grain instance, this will create a reference which implements the provided interface.\n        /// If the provided value is already grain reference, this will create a new reference which implements the provided interface.\n        /// </remarks>\n        /// <returns>A strongly typed reference to the provided grain which implements <typeparamref name=\"TGrainInterface\"/>.</returns>\n        public static TGrainInterface Cast<TGrainInterface>(this IAddressable grain) => grain.AsReference<TGrainInterface>();\n\n        /// <summary>\n        /// Returns a typed reference to the provided grain.\n        /// </summary>\n        /// <param name=\"grain\">The grain to convert.</param>\n        /// <param name=\"interfaceType\">The type of the grain interface.</param>\n        /// <remarks>\n        /// If the provided value is a grain instance, this will create a reference which implements the provided interface.\n        /// If the provided value is already grain reference, this will create a new reference which implements the provided interface.\n        /// </remarks>\n        /// <returns>A strongly typed reference to the provided grain which implements <paramref name=\"interfaceType\"/>.</returns>\n        public static object AsReference(this IAddressable grain, Type interfaceType) => grain.AsReference().Runtime.Cast(grain, interfaceType);\n\n        /// <summary>\n        /// Returns a typed reference to the provided grain.\n        /// </summary>\n        /// <param name=\"grain\">The grain to convert.</param>\n        /// <param name=\"interfaceType\">The type of the grain interface.</param>\n        /// <remarks>\n        /// This method is equivalent to <see cref=\"AsReference(IAddressable, Type)\"/>.\n        /// If the provided value is a grain instance, this will create a reference which implements the provided interface.\n        /// If the provided value is already grain reference, this will create a new reference which implements the provided interface.\n        /// </remarks>\n        /// <returns>A strongly typed reference to the provided grain which implements <paramref name=\"interfaceType\"/>.</returns>\n        public static object Cast(this IAddressable grain, Type interfaceType) => grain.AsReference().Runtime.Cast(grain, interfaceType);\n\n        /// <summary>\n        /// Returns the grain id corresponding to the provided grain.\n        /// </summary>\n        /// <param name=\"grain\">The grain</param>\n        /// <returns>The grain id corresponding to the provided grain.</returns>\n        /// <exception cref=\"ArgumentException\">The provided value has the wrong type or has no id.</exception>\n        public static GrainId GetGrainId(this IAddressable grain)\n        {\n            var grainId = grain switch\n            {\n                Grain grainBase => grainBase.GrainId,\n                GrainReference grainReference => grainReference.GrainId,\n                IGrainBase grainActivation => grainActivation.GrainContext.GrainId,\n                ISystemTargetBase systemTarget => systemTarget.GrainId,\n                _ => throw new ArgumentException(GetWrongGrainTypeErrorMessage(grain), nameof(grain))\n            };\n\n            if (grainId.IsDefault)\n            {\n                throw new ArgumentException(WRONG_GRAIN_ERROR_MSG, nameof(grain));\n            }\n\n            return grainId;\n        }\n\n        /// <summary>\n        /// Gets the exception message which is thrown when a grain argument has a non-supported implementation type.\n        /// </summary>\n        /// <param name=\"grain\">The argument.</param>\n        /// <returns>The exception message which is thrown when a grain argument has a non-supported implementation type.</returns>\n        private static string GetWrongGrainTypeErrorMessage(IAddressable grain) =>\n            $\"{nameof(GetGrainId)} has been called on an unexpected type: {grain.GetType().FullName}.\"\n            + $\" If the parameter is a grain implementation, you can derive from {nameof(Grain)} or implement\"\n            + $\" {nameof(IGrainBase)} in order to support this method. Alternatively, inject {nameof(IGrainContext)} and\"\n            + $\" access the {nameof(IGrainContext.GrainId)} or {nameof(IGrainContext.GrainReference)} property.\";\n\n        /// <summary>\n        /// Returns whether part of the primary key is of type <see langword=\"long\"/>.\n        /// </summary>\n        /// <param name=\"grain\">The target grain.</param>\n        /// <exception cref=\"InvalidOperationException\">The provided grain does not have a <see cref=\"long\"/>-based key.</exception>\n        public static bool IsPrimaryKeyBasedOnLong(this IAddressable grain)\n        {\n            var grainId = GetGrainId(grain);\n            if (grainId.TryGetIntegerKey(out _))\n            {\n                return true;\n            }\n\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n            {\n                return legacyId.IsLongKey;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Returns the <see langword=\"long\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grain\">The grain to find the primary key for.</param>\n        /// <param name=\"keyExt\">The output parameter to return the extended key part of the grain primary key, if extended primary key was provided for that grain.</param>\n        /// <returns>A <see langword=\"long\"/> representing the primary key for this grain.</returns>\n        /// <exception cref=\"InvalidOperationException\">The provided grain does not have a <see cref=\"long\"/>-based key.</exception>\n        public static long GetPrimaryKeyLong(this IAddressable grain, out string? keyExt)\n        {\n            var grainId = GetGrainId(grain);\n            if (grainId.TryGetIntegerKey(out var primaryKey, out keyExt))\n            {\n                return primaryKey;\n            }\n\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n            {\n                return legacyId.GetPrimaryKeyLong(out keyExt);\n            }\n\n            throw new InvalidOperationException($\"Unable to extract integer key from grain id {grainId}\");\n        }\n\n        /// <summary>\n        /// Returns the <see langword=\"long\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grain\">The grain to find the primary key for.</param>\n        /// <returns>A <see langword=\"long\"/> representing the primary key for this grain.</returns>\n        /// <exception cref=\"InvalidOperationException\">The provided grain does not have a <see cref=\"long\"/>-based key.</exception>\n        public static long GetPrimaryKeyLong(this IAddressable grain)\n        {\n            var grainId = GetGrainId(grain);\n            if (grainId.TryGetIntegerKey(out var primaryKey))\n            {\n                return primaryKey;\n            }\n\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n            {\n                return legacyId.GetPrimaryKeyLong();\n            }\n\n            throw new InvalidOperationException($\"Unable to extract integer key from grain id {grainId}\");\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"Guid\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grain\">The grain to find the primary key for.</param>\n        /// <param name=\"keyExt\">The output parameter to return the extended key part of the grain primary key, if extended primary key was provided for that grain.</param>\n        /// <returns>A <see cref=\"Guid\"/> representing the primary key for this grain.</returns>\n        /// <exception cref=\"InvalidOperationException\">The provided grain does not have a <see cref=\"Guid\"/>-based key.</exception>\n        public static Guid GetPrimaryKey(this IAddressable grain, out string? keyExt)\n        {\n            var grainId = GetGrainId(grain);\n            if (grainId.TryGetGuidKey(out var guid, out keyExt))\n            {\n                return guid;\n            }\n\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n            {\n                return legacyId.GetPrimaryKey(out keyExt);\n            }\n\n            if (grainId.TryGetIntegerKey(out var integerKey, out keyExt))\n            {\n                var N1 = integerKey;\n                return new Guid(0, 0, 0, (byte)N1, (byte)(N1 >> 8), (byte)(N1 >> 16), (byte)(N1 >> 24), (byte)(N1 >> 32), (byte)(N1 >> 40), (byte)(N1 >> 48), (byte)(N1 >> 56));\n            }\n\n            throw new InvalidOperationException($\"Unable to extract GUID key from grain id {grainId}\");\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"Guid\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grain\">The grain to find the primary key for.</param>\n        /// <returns>A <see cref=\"Guid\"/> representing the primary key for this grain.</returns>\n        /// <exception cref=\"InvalidOperationException\">The provided grain does not have a <see cref=\"Guid\"/>-based key.</exception>\n        public static Guid GetPrimaryKey(this IAddressable grain)\n        {\n            var grainId = GetGrainId(grain);\n            if (grainId.TryGetGuidKey(out var guid))\n                return guid;\n\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n                return legacyId.GetPrimaryKey();\n\n            if (grainId.TryGetIntegerKey(out var integerKey))\n            {\n                var N1 = integerKey;\n                return new Guid(0, 0, 0, (byte)N1, (byte)(N1 >> 8), (byte)(N1 >> 16), (byte)(N1 >> 24), (byte)(N1 >> 32), (byte)(N1 >> 40), (byte)(N1 >> 48), (byte)(N1 >> 56));\n            }\n\n            throw new InvalidOperationException($\"Unable to extract GUID key from grain id {grainId}\");\n        }\n\n        /// <summary>\n        /// Returns the <see langword=\"string\"/> primary key of the grain.\n        /// </summary>\n        /// <param name=\"grain\">The grain to find the primary key for.</param>\n        /// <returns>A <see langword=\"string\"/> representing the primary key for this grain.</returns>\n        public static string GetPrimaryKeyString(this IAddressable grain)\n        {\n            var grainId = GetGrainId(grain);\n            if (LegacyGrainId.TryConvertFromGrainId(grainId, out var legacyId))\n            {\n                return legacyId.GetPrimaryKeyString();\n            }\n\n            return grainId.Key.ToString();\n        }\n\n        /// <summary>\n        /// Throw an <see cref=\"ArgumentNullException\"/> indicating that the grain argument is null.\n        /// </summary>\n        /// <exception cref=\"ArgumentNullException\">The grain argument is null.</exception>\n        [DoesNotReturn]\n        private static void ThrowGrainNull() => throw new ArgumentNullException(\"grain\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IConfigurationValidator.cs",
    "content": "namespace Orleans\n{\n    /// <summary>\n    /// Describes a configuration validator which is called during client and silo initialization.\n    /// </summary>\n    public interface IConfigurationValidator\n    {\n        /// <summary>\n        /// Validates system configuration and throws an exception if configuration is not valid.\n        /// </summary>\n        void ValidateConfiguration();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrain.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    using Orleans.Runtime;\n\n    /// <summary>\n    /// Marker interface for grains\n    /// </summary>\n    public interface IGrain : IAddressable\n    {\n    }\n\n    /// <summary>\n    /// Marker interface for grains with <see cref=\"Guid\"/> keys.\n    /// </summary>\n    public interface IGrainWithGuidKey : IGrain\n    {\n    }\n\n    /// <summary>\n    /// Marker interface for grains with <see cref=\"long\"/> keys.\n    /// </summary>\n    public interface IGrainWithIntegerKey : IGrain\n    {\n    }\n\n    /// <summary>\n    /// Marker interface for grains with <see cref=\"string\"/> keys.\n    /// </summary>\n    public interface IGrainWithStringKey : IGrain\n    {\n    }\n\n    /// <summary>\n    /// Marker interface for grains with compound keys.\n    /// </summary>\n    public interface IGrainWithGuidCompoundKey : IGrain\n    {\n    }\n\n    /// <summary>\n    /// Marker interface for grains with compound keys.\n    /// </summary>\n    public interface IGrainWithIntegerCompoundKey : IGrain\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainBase.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Timers;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Interface for grain implementations\n    /// </summary>\n    public interface IGrainBase\n    {\n        /// <summary>\n        /// Gets the grain context.\n        /// </summary>\n        IGrainContext GrainContext { get; }\n\n        /// <summary>\n        /// Method overridden by grain implementations to handle activation.\n        /// </summary>\n        /// <param name=\"token\">The cancellation token used to signify that activation should abort promptly.</param>\n        /// <returns>A <see cref=\"Task\"/> which represents the operation.</returns>\n        Task OnActivateAsync(CancellationToken token) => Task.CompletedTask;\n\n        /// <summary>\n        /// Method overridden by grain implementations to handle deactivation.\n        /// </summary>\n        /// <param name=\"reason\">The reason for deactivation.</param>\n        /// <param name=\"token\">The cancellation token used to signify that deactivation should complete promptly.</param>\n        /// <returns>A <see cref=\"Task\"/> which represents the operation.</returns>\n        Task OnDeactivateAsync(DeactivationReason reason, CancellationToken token) => Task.CompletedTask;\n    }\n\n    /// <summary>\n    /// Helper methods for <see cref=\"IGrainBase\"/> implementations.\n    /// </summary>\n    public static class GrainBaseExtensions\n    {\n        /// <summary>\n        /// Deactivate this grain activation after the current grain method call is completed.\n        /// This call will mark this activation of the current grain to be deactivated and removed at the end of the current method.\n        /// The next call to this grain will result in a different activation to be used, which typical means a new activation will be created automatically by the runtime.\n        /// </summary>\n        public static void DeactivateOnIdle(this IGrainBase grain) =>\n            grain.GrainContext.Deactivate(new(DeactivationReasonCode.ApplicationRequested, $\"{nameof(DeactivateOnIdle)} was called.\"));\n\n        /// <summary>\n        /// Starts an attempt to migrating this instance to another location.\n        /// Migration captures the current <see cref=\"RequestContext\"/>, making it available to the activation's placement director so that it can consider it when selecting a new location.\n        /// Migration will occur asynchronously, when no requests are executing, and will not occur if the activation's placement director does not select an alternative location.\n        /// </summary>\n        public static void MigrateOnIdle(this IGrainBase grain) => grain.GrainContext.Migrate(RequestContext.CallContextData?.Value.Values);\n\n        /// <summary>\n        /// Creates a grain timer.\n        /// </summary>\n        /// <param name=\"callback\">The timer callback, which will be invoked whenever the timer becomes due.</param>\n        /// <param name=\"state\">The state passed to the callback.</param>\n        /// <param name=\"options\">\n        /// The options for creating the timer.\n        /// </param>\n        /// <typeparam name=\"TState\">The type of the <paramref name=\"state\"/> parameter.</typeparam>\n        /// <returns>\n        /// The <see cref=\"IGrainTimer\"/> instance which represents the timer.\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// Grain timers do not keep grains active by default. Setting <see cref=\"GrainTimerCreationOptions.KeepAlive\"/> to\n        /// <see langword=\"true\"/> causes each timer tick to extend the grain activation's lifetime.\n        /// If the timer ticks are infrequent, the grain can still be deactivated due to idleness.\n        /// When a grain is deactivated, all active timers are discarded.\n        /// </para>\n        /// <para>\n        /// Until the <see cref=\"Task\"/> returned from the callback is resolved, the next timer tick will not be scheduled.\n        /// That is to say, a timer callback will never be concurrently executed with itself.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"true\"/>, the timer callback will be allowed\n        /// to interleave with with other grain method calls and other timers.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"false\"/>, the timer callback will respect the\n        /// reentrancy setting of the grain, just like a typical grain method call.\n        /// </para>\n        /// <para>\n        /// The timer may be stopped at any time by calling the <see cref=\"IGrainTimer\"/>'s <see cref=\"IDisposable.Dispose\"/> method.\n        /// Disposing a timer prevents any further timer ticks from being scheduled.\n        /// </para>\n        /// <para>\n        /// The timer due time and period can be updated by calling its <see cref=\"IGrainTimer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// Each time the timer is updated, the next timer tick will be scheduled based on the updated due time.\n        /// Subsequent ticks will be scheduled after the updated period elapses.\n        /// Note that this behavior is the same as the <see cref=\"Timer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// </para>\n        /// <para>\n        /// Exceptions thrown from the callback will be logged, but will not prevent the next timer tick from being queued.\n        /// </para>\n        /// </remarks>\n        public static IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, Func<TState, CancellationToken, Task> callback, TState state, GrainTimerCreationOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(callback);\n            if (grain is Grain grainClass)\n            {\n                ArgumentNullException.ThrowIfNull(callback);\n\n                grainClass.EnsureRuntime();\n                return grainClass.Runtime.TimerRegistry.RegisterGrainTimer(grainClass.GrainContext, callback, state, options);\n            }\n\n            return grain.GrainContext.ActivationServices.GetRequiredService<ITimerRegistry>().RegisterGrainTimer(grain.GrainContext, callback, state, options);\n        }\n\n        /// <summary>\n        /// Creates a grain timer.\n        /// </summary>\n        /// <param name=\"grain\">The grain instance.</param>\n        /// <param name=\"callback\">The timer callback, which will be invoked whenever the timer becomes due.</param>\n        /// <param name=\"options\">\n        /// The options for creating the timer.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IGrainTimer\"/> instance which represents the timer.\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// Grain timers do not keep grains active by default. Setting <see cref=\"GrainTimerCreationOptions.KeepAlive\"/> to\n        /// <see langword=\"true\"/> causes each timer tick to extend the grain activation's lifetime.\n        /// If the timer ticks are infrequent, the grain can still be deactivated due to idleness.\n        /// When a grain is deactivated, all active timers are discarded.\n        /// </para>\n        /// <para>\n        /// Until the <see cref=\"Task\"/> returned from the callback is resolved, the next timer tick will not be scheduled.\n        /// That is to say, a timer callback will never be concurrently executed with itself.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"true\"/>, the timer callback will be allowed\n        /// to interleave with with other grain method calls and other timers.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"false\"/>, the timer callback will respect the\n        /// reentrancy setting of the grain, just like a typical grain method call.\n        /// </para>\n        /// <para>\n        /// The timer may be stopped at any time by calling the <see cref=\"IGrainTimer\"/>'s <see cref=\"IDisposable.Dispose\"/> method.\n        /// Disposing a timer prevents any further timer ticks from being scheduled.\n        /// </para>\n        /// <para>\n        /// The timer due time and period can be updated by calling its <see cref=\"IGrainTimer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// Each time the timer is updated, the next timer tick will be scheduled based on the updated due time.\n        /// Subsequent ticks will be scheduled after the updated period elapses.\n        /// Note that this behavior is the same as the <see cref=\"Timer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// </para>\n        /// <para>\n        /// Exceptions thrown from the callback will be logged, but will not prevent the next timer tick from being queued.\n        /// </para>\n        /// </remarks>\n        public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func<CancellationToken, Task> callback, GrainTimerCreationOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(callback);\n            return RegisterGrainTimer(grain, static (callback, cancellationToken) => callback(cancellationToken), callback, options);\n        }\n\n        public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func<Task> callback, GrainTimerCreationOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(callback);\n            return RegisterGrainTimer(grain, static (callback, cancellationToken) => callback(), callback, options);\n        }\n\n        /// <inheritdoc cref=\"RegisterGrainTimer(IGrainBase, Func{Task}, GrainTimerCreationOptions)\"/>\n        /// <param name=\"state\">The state passed to the callback.</param>\n        /// <typeparam name=\"TState\">The type of the <paramref name=\"state\"/> parameter.</typeparam>\n        public static IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, Func<TState, Task> callback, TState state, GrainTimerCreationOptions options)\n        {\n            ArgumentNullException.ThrowIfNull(callback);\n            return RegisterGrainTimer(grain, static (state, _) => state.Callback(state.State), (Callback: callback, State: state), options);\n        }\n\n        /// <summary>\n        /// Creates a grain timer.\n        /// </summary>\n        /// <param name=\"grain\">The grain instance.</param>\n        /// <param name=\"callback\">The timer callback, which will be invoked whenever the timer becomes due.</param>\n        /// <param name=\"dueTime\">\n        /// A <see cref=\"TimeSpan\"/> representing the amount of time to delay before invoking the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n        /// Specify <see cref=\"TimeSpan.Zero\"/> to start the timer immediately.\n        /// </param>\n        /// <param name=\"period\">\n        /// The time interval between invocations of the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan \"/> to disable periodic signaling.\n        /// </param>\n        /// <returns>\n        /// The <see cref=\"IGrainTimer\"/> instance which represents the timer.\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// Grain timers do not keep grains active by default. Setting <see cref=\"GrainTimerCreationOptions.KeepAlive\"/> to\n        /// <see langword=\"true\"/> causes each timer tick to extend the grain activation's lifetime.\n        /// If the timer ticks are infrequent, the grain can still be deactivated due to idleness.\n        /// When a grain is deactivated, all active timers are discarded.\n        /// </para>\n        /// <para>\n        /// Until the <see cref=\"Task\"/> returned from the callback is resolved, the next timer tick will not be scheduled.\n        /// That is to say, a timer callback will never be concurrently executed with itself.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"true\"/>, the timer callback will be allowed\n        /// to interleave with with other grain method calls and other timers.\n        /// If <see cref=\"GrainTimerCreationOptions.Interleave\"/> is set to <see langword=\"false\"/>, the timer callback will respect the\n        /// reentrancy setting of the grain, just like a typical grain method call.\n        /// </para>\n        /// <para>\n        /// The timer may be stopped at any time by calling the <see cref=\"IGrainTimer\"/>'s <see cref=\"IDisposable.Dispose\"/> method.\n        /// Disposing a timer prevents any further timer ticks from being scheduled.\n        /// </para>\n        /// <para>\n        /// The timer due time and period can be updated by calling its <see cref=\"IGrainTimer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// Each time the timer is updated, the next timer tick will be scheduled based on the updated due time.\n        /// Subsequent ticks will be scheduled after the updated period elapses.\n        /// Note that this behavior is the same as the <see cref=\"Timer.Change(TimeSpan, TimeSpan)\"/> method.\n        /// </para>\n        /// <para>\n        /// Exceptions thrown from the callback will be logged, but will not prevent the next timer tick from being queued.\n        /// </para>\n        /// </remarks>\n        public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func<Task> callback, TimeSpan dueTime, TimeSpan period)\n            => RegisterGrainTimer(grain, callback, new() { DueTime = dueTime, Period = period });\n\n        /// <inheritdoc cref=\"RegisterGrainTimer(IGrainBase, Func{Task}, TimeSpan, TimeSpan)\"/>\n        public static IGrainTimer RegisterGrainTimer(this IGrainBase grain, Func<CancellationToken, Task> callback, TimeSpan dueTime, TimeSpan period)\n            => RegisterGrainTimer(grain, callback, new() { DueTime = dueTime, Period = period });\n\n        /// <inheritdoc cref=\"RegisterGrainTimer(IGrainBase, Func{Task}, TimeSpan, TimeSpan)\"/>\n        /// <param name=\"state\">The state passed to the callback.</param>\n        /// <typeparam name=\"TState\">The type of the <paramref name=\"state\"/> parameter.</typeparam>\n        public static IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, Func<TState, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            => RegisterGrainTimer(grain, callback, state, new() { DueTime = dueTime, Period = period });\n\n        /// <inheritdoc cref=\"RegisterGrainTimer(IGrainBase, Func{Task}, TimeSpan, TimeSpan)\"/>\n        /// <param name=\"state\">The state passed to the callback.</param>\n        /// <typeparam name=\"TState\">The type of the <paramref name=\"state\"/> parameter.</typeparam>\n        public static IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, Func<TState, CancellationToken, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            => RegisterGrainTimer(grain, callback, state, new() { DueTime = dueTime, Period = period });\n    }\n\n    /// <summary>\n    /// An informational reason code for deactivation.\n    /// </summary>\n    [GenerateSerializer]\n    public enum DeactivationReasonCode : byte\n    {\n        /// <summary>\n        /// No reason provided.\n        /// </summary>\n        None,\n\n        /// <summary>\n        /// The process is currently shutting down.\n        /// </summary>\n        ShuttingDown,\n\n        /// <summary>\n        /// Activation of the grain failed.\n        /// </summary>\n        ActivationFailed,\n\n        /// <summary>\n        /// This activation is affected by an internal failure in the distributed grain directory.\n        /// </summary>\n        /// <remarks>\n        /// This could be caused by the failure of a process hosting this activation's grain directory partition, for example.\n        /// </remarks>\n        DirectoryFailure,\n\n        /// <summary>\n        /// This activation is idle.\n        /// </summary>\n        ActivationIdle,\n\n        /// <summary>\n        /// This activation is unresponsive to commands or requests.\n        /// </summary>\n        ActivationUnresponsive,\n\n        /// <summary>\n        /// Another instance of this grain has been activated.\n        /// </summary>\n        DuplicateActivation,\n\n        /// <summary>\n        /// This activation received a request which cannot be handled by the locally running process.\n        /// </summary>\n        IncompatibleRequest,\n\n        /// <summary>\n        /// An application error occurred.\n        /// </summary>\n        ApplicationError,\n\n        /// <summary>\n        /// The application requested to deactivate this activation.\n        /// </summary>\n        ApplicationRequested,\n\n        /// <summary>\n        /// This activation is migrating to a new location.\n        /// </summary>\n        Migrating,\n\n        /// <summary>\n        /// The runtime requested to deactivate this activation.\n        /// </summary>\n        RuntimeRequested,\n\n        /// <summary>\n        /// Runtime detected that app is running on low memory, and forcefully decided to deactivate.\n        /// </summary>\n        HighMemoryPressure,\n    }\n\n    internal static class DeactivationReasonCodeExtensions\n    {\n        public static bool IsTransientError(this DeactivationReasonCode reasonCode)\n        {\n            return reasonCode is DeactivationReasonCode.DirectoryFailure;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainCallContext.cs",
    "content": "using System.Reflection;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// A delegate used to intercept invocation of a request.\n    /// </summary>\n    /// <param name=\"context\">The invocation context.</param>\n    /// <returns>A <see cref=\"Task\"/> which must be awaited before processing continues.</returns>\n    public delegate Task GrainCallFilterDelegate(IGrainCallContext context);\n\n    /// <summary>\n    /// A delegate used to intercept an incoming request.\n    /// </summary>\n    /// <param name=\"context\">The invocation context.</param>\n    /// <returns>A <see cref=\"Task\"/> which must be awaited before processing continues.</returns>\n    public delegate Task OutgoingGrainCallFilterDelegate(IOutgoingGrainCallContext context);\n\n    /// <summary>\n    /// A delegate used to intercept an outgoing request.\n    /// </summary>\n    /// <param name=\"context\">The invocation context.</param>\n    /// <returns>A <see cref=\"Task\"/> which must be awaited before processing continues.</returns>\n    public delegate Task IncomingGrainCallFilterDelegate(IIncomingGrainCallContext context);\n\n    /// <summary>\n    /// Represents a method invocation as well as the result of invocation.\n    /// </summary>\n    public interface IGrainCallContext\n    {\n        /// <summary>\n        /// Gets the request.\n        /// </summary>\n        IInvokable Request { get; }\n\n        /// <summary>\n        /// Gets the grain being invoked.\n        /// </summary>\n        object Grain { get; }\n\n        /// <summary>\n        /// Gets the identity of the source, if available.\n        /// </summary>\n        GrainId? SourceId { get; }\n\n        /// <summary>\n        /// Gets the identity of the target.\n        /// </summary>\n        GrainId TargetId { get; }\n\n        /// <summary>\n        /// Gets the type of the interface being invoked.\n        /// </summary>\n        GrainInterfaceType InterfaceType { get; }\n\n        /// <summary>\n        /// Gets the name of the interface being invoked.\n        /// </summary>\n        string InterfaceName { get; }\n\n        /// <summary>\n        /// Gets the name of the method being invoked.\n        /// </summary>\n        string MethodName { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"MethodInfo\"/> for the interface method being invoked.\n        /// </summary>\n        MethodInfo InterfaceMethod { get; }\n\n        /// <summary>\n        /// Gets or sets the result.\n        /// </summary>\n        object? Result { get; set; }\n       \n        /// <summary>\n        /// Gets or sets the response.\n        /// </summary>\n        Response? Response { get; set; }\n\n        /// <summary>\n        /// Invokes the request.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the invocation.\n        /// </returns>\n        Task Invoke();\n    }\n\n    /// <summary>\n    /// Represents an incoming method invocation as well as the result of invocation.\n    /// </summary>\n    public interface IIncomingGrainCallContext : IGrainCallContext\n    {\n        /// <summary>\n        /// Gets the grain context of the target.\n        /// </summary>\n        public IGrainContext TargetContext { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"MethodInfo\"/> for the implementation method being invoked.\n        /// </summary>\n        MethodInfo ImplementationMethod { get; }\n    }\n\n    /// <summary>\n    /// Represents an outgoing method invocation as well as the result of invocation.\n    /// </summary>\n    public interface IOutgoingGrainCallContext : IGrainCallContext\n    {\n        /// <summary>\n        /// Gets the grain context of the sender.\n        /// </summary>\n        public IGrainContext? SourceContext { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainCallFilter.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Interface for incoming grain call filters.\n    /// </summary>\n    public interface IIncomingGrainCallFilter\n    {\n        /// <summary>\n        /// Invokes this filter.\n        /// </summary>\n        /// <param name=\"context\">The grain call context.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task Invoke(IIncomingGrainCallContext context);\n    }\n\n    /// <summary>\n    /// Interface for outgoing grain call filters.\n    /// </summary>\n    public interface IOutgoingGrainCallFilter\n    {\n        /// <summary>\n        /// Invokes this filter.\n        /// </summary>\n        /// <param name=\"context\">The grain call context.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task Invoke(IOutgoingGrainCallContext context);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainContext.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a grain from the perspective of the runtime.\n    /// </summary>\n    public interface IGrainContext : ITargetHolder, IEquatable<IGrainContext>\n    {\n        /// <summary>\n        /// Gets a reference to this grain.\n        /// </summary>\n        GrainReference GrainReference { get; }\n\n        /// <summary>\n        /// Gets the grain identity.\n        /// </summary>\n        GrainId GrainId { get; }\n\n        /// <summary>\n        /// Gets the grain instance, or <see langword=\"null\"/> if the grain instance has not been set yet.\n        /// </summary>\n        object? GrainInstance { get; }\n\n        /// <summary>\n        /// Gets the activation id.\n        /// </summary>\n        ActivationId ActivationId { get; }\n\n        /// <summary>\n        /// Gets the activation address.\n        /// </summary>\n        GrainAddress Address { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"IServiceProvider\" /> that provides access to the grain activation's service container.\n        /// </summary>\n        IServiceProvider ActivationServices { get; }\n\n        /// <summary>\n        /// Gets the observable <see cref=\"Grain\"/> lifecycle, which can be used to add lifecycle hooks.\n        /// </summary>\n        IGrainLifecycle ObservableLifecycle { get; }\n\n        /// <summary>\n        /// Gets the scheduler.\n        /// </summary>\n        IWorkItemScheduler Scheduler { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"Task\"/> which completes when the grain has deactivated.\n        /// </summary>\n        Task Deactivated { get; }\n\n        /// <summary>\n        /// Sets the provided value as the component for type <typeparamref name=\"TComponent\"/>.\n        /// </summary>\n        /// <typeparam name=\"TComponent\">The type used to lookup this component.</typeparam>\n        /// <param name=\"value\">The component instance.</param>\n        void SetComponent<TComponent>(TComponent? value) where TComponent : class;\n\n        /// <summary>\n        /// Submits an incoming message to this instance.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        void ReceiveMessage(object message);\n\n        /// <summary>\n        /// Start activating this instance.\n        /// </summary>\n        /// <param name=\"requestContext\">The request context of the request which is causing this instance to be activated, if any.</param>\n        /// <param name=\"cancellationToken\">A cancellation token which, when canceled, indicates that the process should complete promptly.</param>\n        void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Start deactivating this instance.\n        /// </summary>\n        /// <param name=\"deactivationReason\">The reason for deactivation, for informational purposes.</param>\n        /// <param name=\"cancellationToken\">A cancellation token which, when canceled, indicates that the process should complete promptly.</param>\n        void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Start rehydrating this instance from the provided rehydration context.\n        /// </summary>\n        void Rehydrate(IRehydrationContext context);\n\n        /// <summary>\n        /// Starts an attempt to migrating this instance to another location.\n        /// Migration captures the current <see cref=\"RequestContext\"/>, making it available to the activation's placement director so that it can consider it when selecting a new location.\n        /// Migration will occur asynchronously, when no requests are executing, and will not occur if the activation's placement director does not select an alternative location.\n        /// </summary>\n        /// <param name=\"requestContext\">The request context, which is provided to the placement director so that it can be examined when selecting a new location.</param>\n        /// <param name=\"cancellationToken\">A cancellation token which, when canceled, indicates that the process should complete promptly.</param>\n        void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken = default);\n    }\n\n    /// <summary>\n    /// Extensions for <see cref=\"IGrainContext\"/>.\n    /// </summary>\n    public static class GrainContextExtensions\n    {\n        /// <summary>\n        /// Deactivates the provided grain.\n        /// </summary>\n        /// <param name=\"grainContext\">\n        /// The grain context.\n        /// </param>\n        /// <param name=\"deactivationReason\">\n        /// The deactivation reason.\n        /// </param>\n        /// <param name=\"cancellationToken\">A cancellation token which when canceled, indicates that the process should complete promptly.</param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> which will complete once the grain has deactivated.\n        /// </returns>\n        [Obsolete(\"This method is error-prone: waiting deactivation to complete from within the grain being deactivated will usually result in a deadlock.\")]\n        public static Task DeactivateAsync(this IGrainContext grainContext, DeactivationReason deactivationReason, CancellationToken cancellationToken = default)\n        {\n            grainContext.Deactivate(deactivationReason, cancellationToken);\n            return grainContext.Deactivated;\n        }\n    }\n\n    /// <summary>\n    /// Defines functionality required for grains which are subject to activation collection.\n    /// </summary>\n    internal interface ICollectibleGrainContext : IGrainContext\n    {\n        /// <summary>\n        /// Gets a value indicating whether the instance is available to process messages.\n        /// </summary>\n        bool IsValid { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is exempt from collection.\n        /// </summary>\n        bool IsExemptFromCollection { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is not currently processing a request.\n        /// </summary>\n        bool IsInactive { get; }\n\n        /// <summary>\n        /// Gets the collection age limit, which defines how long an instance must be inactive before it is eligible for collection.\n        /// </summary>\n        TimeSpan CollectionAgeLimit { get; }\n\n        /// <summary>\n        /// Gets the keep alive override value, which is the earliest time after which this instance will be available for collection.\n        /// </summary>\n        DateTime KeepAliveUntil { get; }\n\n        /// <summary>\n        /// Gets or sets the collection ticket, which is a special value used for tracking this activation's lifetime.\n        /// </summary>\n        DateTime CollectionTicket { get; set; }\n\n        /// <summary>\n        /// Gets a value indicating whether this activation has been idle longer than its <see cref=\"CollectionAgeLimit\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the activation is stale, otherwise <see langword=\"false\"/>.</returns>\n        bool IsStale();\n\n        /// <summary>\n        /// Gets the duration which this activation has been idle for.\n        /// </summary>\n        /// <returns>\n        /// The duration which this activation has been idle for.\n        /// </returns>\n        TimeSpan GetIdleness();\n\n        /// <summary>\n        /// Delays activation collection until at least until the specified duration has elapsed.\n        /// </summary>\n        /// <param name=\"timeSpan\">The period of time to delay activation collection for.</param>\n        void DelayDeactivation(TimeSpan timeSpan);\n    }\n\n    /// <summary>\n    /// Functionality to schedule tasks on a grain.\n    /// </summary>\n    public interface IWorkItemScheduler\n    {\n        /// <summary>\n        /// Schedules an action for execution by this instance.\n        /// </summary>\n        /// <param name=\"action\">\n        /// The action.\n        /// </param>\n        void QueueAction(Action action);\n\n        /// <summary>\n        /// Schedules a task to be started by this instance.\n        /// </summary>\n        /// <param name=\"task\">The task.</param>\n        void QueueTask(Task task);\n\n        /// <summary>\n        /// Schedules a work item for execution by this instance.\n        /// </summary>\n        /// <param name=\"action\">The work item.</param>\n        /// <param name=\"state\">The state passed when invoking the item.</param>\n        void QueueAction(Action<object> action, object state);\n    }\n\n    /// <summary>\n    /// Provides access to the currently executing grain context.\n    /// </summary>\n    public interface IGrainContextAccessor\n    {\n        /// <summary>\n        /// Gets the currently executing grain context.\n        /// </summary>\n        IGrainContext GrainContext { get; }\n    }\n\n    /// <summary>\n    /// Functionality for accessing or installing an extension on a grain.\n    /// </summary>\n    public interface IGrainExtensionBinder\n    {\n        /// <summary>\n        /// Returns the grain extension registered for the provided <typeparamref name=\"TExtensionInterface\"/>.\n        /// </summary>\n        /// <typeparam name=\"TExtensionInterface\">\n        /// The grain extension interface.\n        /// </typeparam>\n        /// <returns>\n        /// The implementation of the extension which is bound to this grain.\n        /// </returns>\n        TExtensionInterface GetExtension<TExtensionInterface>() where TExtensionInterface : class, IGrainExtension;\n\n        /// <summary>\n        /// Binds an extension to an addressable object, if not already done.\n        /// </summary>\n        /// <typeparam name=\"TExtension\">The type of the extension (e.g. StreamConsumerExtension).</typeparam>\n        /// <typeparam name=\"TExtensionInterface\">The public interface type of the implementation.</typeparam>\n        /// <param name=\"newExtensionFunc\">A factory function that constructs a new extension object.</param>\n        /// <returns>A tuple, containing first the extension and second an addressable reference to the extension's interface.</returns>\n        (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainFactory.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    public static class GrainFactoryExtensions\n    {\n        /// <summary>\n        /// Returns a reference for the provided grain id which implements the specified interface type.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"grainPrimaryKey\">The primary key of the grain</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <typeparam name=\"TGrainInterface\">The grain interface type which the returned grain reference must implement.</typeparam>\n        /// <returns>\n        /// A reference for the provided grain id which implements the specified interface type.\n        /// </returns>\n        public static TGrainInterface GetGrain<TGrainInterface>(this IGrainFactory grainFactory, IdSpan grainPrimaryKey, string grainClassNamePrefix) where TGrainInterface : IGrain\n        {\n            ArgumentNullException.ThrowIfNull(grainFactory);\n            return grainFactory.GetGrain(typeof(TGrainInterface), grainPrimaryKey, grainClassNamePrefix).AsReference<TGrainInterface>();\n        }\n\n        /// <summary>\n        /// Returns a reference for the provided grain id which implements the specified interface type.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"grainPrimaryKey\">The primary key of the grain</param>\n        /// <typeparam name=\"TGrainInterface\">The grain interface type which the returned grain reference must implement.</typeparam>\n        /// <returns>\n        /// A reference for the provided grain id which implements the specified interface type.\n        /// </returns>\n        public static TGrainInterface GetGrain<TGrainInterface>(this IGrainFactory grainFactory, IdSpan grainPrimaryKey) where TGrainInterface : IGrain\n        {\n            ArgumentNullException.ThrowIfNull(grainFactory);\n            return grainFactory.GetGrain(typeof(TGrainInterface), grainPrimaryKey).AsReference<TGrainInterface>();\n        }\n    }\n\n    /// <summary>\n    /// Functionality for creating references to grains.\n    /// </summary>\n    public interface IGrainFactory\n    {\n        /// <summary>\n        /// Gets a reference to a grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The interface type.</typeparam>\n        /// <param name=\"primaryKey\">The primary key of the grain.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>A reference to the specified grain.</returns>\n        TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string? grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidKey;\n\n        /// <summary>\n        /// Gets a reference to a grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The interface type.</typeparam>\n        /// <param name=\"primaryKey\">The primary key of the grain.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>A reference to the specified grain.</returns>\n        TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string? grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerKey;\n\n        /// <summary>\n        /// Gets a reference to a grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The interface type.</typeparam>\n        /// <param name=\"primaryKey\">The primary key of the grain.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>A reference to the specified grain.</returns>\n        TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string? grainClassNamePrefix = null) where TGrainInterface : IGrainWithStringKey;\n\n        /// <summary>\n        /// Gets a reference to a grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The interface type.</typeparam>\n        /// <param name=\"primaryKey\">The primary key of the grain.</param>\n        /// <param name=\"keyExtension\">The key extension of the grain.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>A reference to the specified grain.</returns>\n        TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string keyExtension, string? grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidCompoundKey;\n\n        /// <summary>\n        /// Gets a reference to a grain.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The interface type.</typeparam>\n        /// <param name=\"primaryKey\">The primary key of the grain.</param>\n        /// <param name=\"keyExtension\">The key extension of the grain.</param>\n        /// <param name=\"grainClassNamePrefix\">An optional class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>A reference to the specified grain.</returns>\n        TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string? grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerCompoundKey;\n\n        /// <summary>\n        /// Creates a reference to the provided <paramref name=\"obj\"/>.\n        /// </summary>\n        /// <typeparam name=\"TGrainObserverInterface\">\n        /// The specific <see cref=\"IGrainObserver\"/> type of <paramref name=\"obj\"/>.\n        /// </typeparam>\n        /// <param name=\"obj\">The object to create a reference to.</param>\n        /// <returns>The reference to <paramref name=\"obj\"/>.</returns>\n        TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver;\n\n        /// <summary>\n        /// Deletes the provided object reference.\n        /// </summary>\n        /// <typeparam name=\"TGrainObserverInterface\">\n        /// The specific <see cref=\"IGrainObserver\"/> type of <paramref name=\"obj\"/>.\n        /// </typeparam>\n        /// <param name=\"obj\">The reference being deleted.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        void DeleteObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver;\n\n        /// <summary>\n        /// Returns a reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </summary>\n        /// <param name=\"grainInterfaceType\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </param>\n        /// <param name=\"grainPrimaryKey\">\n        /// The primary key of the grain\n        /// </param>\n        /// <returns>\n        /// A reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </returns>\n        IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey);\n\n        /// <summary>\n        /// Returns a reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </summary>\n        /// <param name=\"grainInterfaceType\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </param>\n        /// <param name=\"grainPrimaryKey\">\n        /// The primary key of the grain\n        /// </param>\n        /// <returns>\n        /// A reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </returns>\n        IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey);\n\n        /// <summary>\n        /// Returns a reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </summary>\n        /// <param name=\"grainInterfaceType\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </param>\n        /// <param name=\"grainPrimaryKey\">\n        /// The primary key of the grain\n        /// </param>\n        /// <returns>\n        /// A reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </returns>\n        IGrain GetGrain(Type grainInterfaceType, string grainPrimaryKey);\n\n        /// <summary>\n        /// Returns a reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </summary>\n        /// <param name=\"grainInterfaceType\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </param>\n        /// <param name=\"grainPrimaryKey\">\n        /// The primary key of the grain\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The grain key extension component.\n        /// </param>\n        /// <returns>\n        /// A reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </returns>\n        IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey, string keyExtension);\n\n        /// <summary>\n        /// Returns a reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </summary>\n        /// <param name=\"grainInterfaceType\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </param>\n        /// <param name=\"grainPrimaryKey\">\n        /// The primary key of the grain\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The grain key extension component.\n        /// </param>\n        /// <returns>\n        /// A reference to the grain which is the primary implementation of the provided interface type and has the provided primary key.\n        /// </returns>\n        IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey, string keyExtension);\n\n        /// <summary>\n        /// Returns a reference to the specified grain which implements the specified interface.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <typeparam name=\"TGrainInterface\">\n        /// The grain interface type which the returned grain reference must implement.\n        /// </typeparam>\n        /// <returns>\n        /// A reference to the specified grain which implements the specified interface.\n        /// </returns>\n        TGrainInterface GetGrain<TGrainInterface>(GrainId grainId) where TGrainInterface : IAddressable;\n\n        /// <summary>\n        /// Returns an untyped reference for the provided grain id.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <returns>\n        /// An untyped reference for the provided grain id.\n        /// </returns>\n        IAddressable GetGrain(GrainId grainId);\n\n        /// <summary>\n        /// Returns a reference for the provided grain id which implements the specified interface type.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"interfaceType\">\n        /// The interface type which the returned grain reference must implement.\n        /// </param>\n        /// <returns>\n        /// A reference for the provided grain id which implements the specified interface type.\n        /// </returns>\n        IAddressable GetGrain(GrainId grainId, GrainInterfaceType interfaceType);\n\n        /// <summary>\n        /// Returns a reference for the provided grain id which implements the specified interface type.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type which the returned grain reference must implement.</param>\n        /// <param name=\"grainKey\">The primary key of the grain</param>\n        /// <param name=\"grainClassNamePrefix\">A class name prefix used to find the runtime type of the grain.</param>\n        /// <returns>\n        /// A reference for the provided grain id which implements the specified interface type.\n        /// </returns>\n        IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix);\n\n        /// <summary>\n        /// Returns a reference for the provided grain id which implements the specified interface type.\n        /// </summary>\n        /// <param name=\"interfaceType\">The grain interface type which the returned grain reference must implement.</param>\n        /// <param name=\"grainKey\">The primary key of the grain</param>\n        /// <returns>\n        /// A reference for the provided grain id which implements the specified interface type.\n        /// </returns>\n        IAddressable GetGrain(Type interfaceType, IdSpan grainKey);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IGrainObserver.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// A marker interface for grain observers.\n    /// Observers are used to receive notifications from grains; that is, they represent the subscriber side of a \n    /// publisher/subscriber interface.\n    /// </summary>\n    public interface IGrainObserver : IAddressable\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/ILocalActivationStatusChecker.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans;\n\n/// <summary>\n/// Provides a way to check whether a grain is locally activated.\n/// </summary>\npublic interface ILocalActivationStatusChecker\n{\n    /// <summary>\n    /// Returns <see langword=\"true\"/> if the provided grain is locally activated; otherwise, <see langword=\"false\"/>.\n    /// </summary>\n    /// <param name=\"grainId\">The identifier of the grain to check.</param>\n    /// <returns><see langword=\"true\"/> if the provided grain is locally activated; otherwise, <see langword=\"false\"/>.</returns>\n    bool IsLocallyActivated(GrainId grainId);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/IStorage.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Core\n{\n    /// <summary>\n    /// Provides method for operating on grain storage.\n    /// </summary>\n    public interface IStorage\n    {\n        /// <summary>\n        /// Gets the ETag.\n        /// </summary>\n        /// <remarks>\n        /// An ETag, or entity tag, is a value used to prevent concurrent writes where one or more of those writes has not first observed the most recent operation.\n        /// </remarks>\n        string? Etag { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether the record already exists.\n        /// </summary>\n        bool RecordExists { get; }\n\n        /// <summary>\n        /// Clears the grain state.\n        /// </summary>\n        /// <remarks>\n        /// This will usually mean the state record is deleted from backing store, but the specific behavior is defined by the storage provider instance configured for this grain.\n        /// If the Etag does not match what is present in the backing store, then this operation will fail; Set <see cref=\"Etag\"/> to <see langword=\"null\"/> to indicate \"always delete\".\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task ClearStateAsync();\n\n        /// <summary>\n        /// Writes grain state to storage.\n        /// </summary>\n        /// <remarks>\n        /// If the Etag does not match what is present in the backing store, then this operation will fail; Set <see cref=\"Etag\"/> to <see langword=\"null\"/> to indicate \"always delete\".\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task WriteStateAsync();\n\n        /// <summary>\n        /// Reads grain state from storage.\n        /// </summary>\n        /// <remarks>\n        /// Any previous contents of the grain state data will be overwritten.\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task ReadStateAsync();\n\n        /// <summary>\n        /// Clears the grain state.\n        /// </summary>\n        /// <param name=\"cancellationToken\"></param>\n        /// <remarks>\n        /// This will usually mean the state record is deleted from backing store, but the specific behavior is defined by the storage provider instance configured for this grain.\n        /// If the Etag does not match what is present in the backing store, then this operation will fail; Set <see cref=\"Etag\"/> to <see langword=\"null\"/> to indicate \"always delete\".\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task ClearStateAsync(CancellationToken cancellationToken) => ClearStateAsync();\n\n        /// <summary>\n        /// Writes grain state to storage.\n        /// </summary>\n        /// <param name=\"cancellationToken\"></param>\n        /// <remarks>\n        /// If the Etag does not match what is present in the backing store, then this operation will fail; Set <see cref=\"Etag\"/> to <see langword=\"null\"/> to indicate \"always delete\".\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task WriteStateAsync(CancellationToken cancellationToken) => WriteStateAsync();\n\n        /// <summary>\n        /// Reads grain state from storage.\n        /// </summary>\n        /// <param name=\"cancellationToken\"></param>\n        /// <remarks>\n        /// Any previous contents of the grain state data will be overwritten.\n        /// </remarks>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task ReadStateAsync(CancellationToken cancellationToken) => ReadStateAsync();\n    }\n\n    /// <summary>\n    /// Provides method for operating on grain state.\n    /// </summary>\n    public interface IStorage<TState> : IStorage\n    {\n        /// <summary>\n        /// Gets or sets the state.\n        /// </summary>\n        TState State { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/Immutable.cs",
    "content": "namespace Orleans.Concurrency\n{\n    /// <summary>\n    /// Wrapper class for carrying immutable data.\n    /// </summary>\n    /// <remarks>\n    /// Objects that are known to be immutable are given special fast-path handling by the Orleans serializer \n    /// -- which in a nutshell allows the DeepCopy step to be skipped during message sends where the sender and receiver grain are in the same silo.\n    /// \n    /// One very common usage pattern for Immutable is when passing byte[] parameters to a grain. \n    /// If a program knows it will not alter the contents of the byte[] (for example, if it contains bytes from a static image file read from disk)\n    /// then considerable savings in memory usage and message throughput can be obtained by marking that byte[] argument as <c>Immutable</c>.\n    /// </remarks>\n    /// <typeparam name=\"T\">Type of data to be wrapped by this Immutable</typeparam>\n    [GenerateSerializer, Immutable]\n    public readonly struct Immutable<T>\n    {\n        /// <summary> Return reference to the original value stored in this Immutable wrapper. </summary>\n        [Id(0)]\n        public readonly T Value;\n\n        /// <summary>\n        /// Constructor to wrap the specified data object in new Immutable wrapper.\n        /// </summary>\n        /// <param name=\"value\">Value to be wrapped and marked as immutable.</param>\n        public Immutable(T value) => Value = value;\n    }\n\n    /// <summary>\n    /// Utility class to add the .AsImmutable method to all objects.\n    /// </summary>\n    public static class ImmutableExtensions\n    {\n        /// <summary>\n        /// Extension method to return this value wrapped in <c>Immutable</c>.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"value\">Value to be wrapped.</param>\n        /// <returns>Immutable wrapper around the original object.</returns>\n        /// <seealso cref=\"Immutable{T}\"/>\"/>\n        public static Immutable<T> AsImmutable<T>(this T value) => new(value);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/Internal/ICallChainReentrantGrainContext.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Core.Internal\n{\n    /// <summary>\n    /// Provides functionality for entering and exiting sections of code within a grain during which requests bearing the same <see cref=\"RequestContext.ReentrancyId\"/> are allowed to re-enter the grain.\n    /// </summary>\n    public interface ICallChainReentrantGrainContext\n    {\n        /// <summary>\n        /// Marks the beginning of a section of code within a grain during which requests bearing the same <see cref=\"RequestContext.ReentrancyId\"/> are allowed to re-enter the grain.\n        /// </summary>\n        void OnEnterReentrantSection(Guid reentrancyId);\n\n        /// <summary>\n        /// Marks the end of a section of code within a grain during which requests bearing the same <see cref=\"RequestContext.ReentrancyId\"/> are allowed to re-enter the grain.\n        /// </summary>\n        void OnExitReentrantSection(Guid reentrancyId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Core/Internal/IGrainManagementExtension.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Core.Internal\n{\n    /// <summary>\n    /// Provides functionality for performing management operations on a grain activation.\n    /// </summary>\n    public interface IGrainManagementExtension : IGrainExtension\n    {\n        /// <summary>\n        /// Deactivates the current instance once it becomes idle.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> which represents the method call.</returns>\n        ValueTask DeactivateOnIdle();\n\n        /// <summary>\n        /// Attempts to migrate the current instance to a new location once it becomes idle.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> which represents the method call.</returns>\n        ValueTask MigrateOnIdle();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Diagnostics/ActivitySources.cs",
    "content": "using System.Diagnostics;\n\nnamespace Orleans.Diagnostics;\n\npublic static class ActivitySources\n{\n    /// <summary>\n    /// Spans triggered from application level code\n    /// </summary>\n    public const string ApplicationGrainActivitySourceName = \"Microsoft.Orleans.Application\";\n    /// <summary>\n    /// Spans triggered from Orleans runtime code\n    /// </summary>\n    public const string RuntimeActivitySourceName = \"Microsoft.Orleans.Runtime\";\n    /// <summary>\n    /// Spans tied to lifecycle operations such as activation, migration, and deactivation.\n    /// </summary>\n    public const string LifecycleActivitySourceName = \"Microsoft.Orleans.Lifecycle\";\n    /// <summary>\n    /// Spans tied to persistent storage operations.\n    /// </summary>\n    public const string StorageActivitySourceName = \"Microsoft.Orleans.Storage\";\n    /// <summary>\n    /// A wildcard name to match all Orleans activity sources.\n    /// </summary>\n    public const string AllActivitySourceName = \"Microsoft.Orleans.*\";\n\n    internal static readonly ActivitySource ApplicationGrainSource = new(ApplicationGrainActivitySourceName, \"1.1.0\");\n    internal static readonly ActivitySource RuntimeGrainSource = new(RuntimeActivitySourceName, \"2.0.0\");\n    internal static readonly ActivitySource LifecycleGrainSource = new(LifecycleActivitySourceName, \"1.0.0\");\n    internal static readonly ActivitySource StorageGrainSource = new(StorageActivitySourceName, \"1.0.0\");\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Diagnostics/ActivityTagKeys.cs",
    "content": "namespace Orleans.Diagnostics;\n\n/// <summary>\n/// Contains constants for Activity tag keys used throughout Orleans.\n/// </summary>\ninternal static class ActivityTagKeys\n{\n    /// <summary>\n    /// The request ID for an async enumerable operation.\n    /// </summary>\n    public const string AsyncEnumerableRequestId = \"orleans.async_enumerable.request_id\";\n\n    /// <summary>\n    /// The activation ID tag key.\n    /// </summary>\n    public const string ActivationId = \"orleans.activation.id\";\n\n    /// <summary>\n    /// The activation cause tag key (e.g., \"new\" or \"rehydrate\").\n    /// </summary>\n    public const string ActivationCause = \"orleans.activation.cause\";\n\n    /// <summary>\n    /// The deactivation reason tag key.\n    /// </summary>\n    public const string DeactivationReason = \"orleans.deactivation.reason\";\n\n    /// <summary>\n    /// The grain ID tag key.\n    /// </summary>\n    public const string GrainId = \"orleans.grain.id\";\n\n    /// <summary>\n    /// The grain type tag key.\n    /// </summary>\n    public const string GrainType = \"orleans.grain.type\";\n\n    /// <summary>\n    /// The grain type tag key.\n    /// </summary>\n    public const string GrainState = \"orleans.grain.state\";\n\n    /// <summary>\n    /// The silo ID tag key.\n    /// </summary>\n    public const string SiloId = \"orleans.silo.id\";\n\n    /// <summary>\n    /// The directory previous registration present tag key.\n    /// </summary>\n    public const string DirectoryPreviousRegistrationPresent = \"orleans.directory.previousRegistration.present\";\n\n    /// <summary>\n    /// The directory registered address tag key.\n    /// </summary>\n    public const string DirectoryRegisteredAddress = \"orleans.directory.registered.address\";\n\n    /// <summary>\n    /// The directory forwarding address tag key.\n    /// </summary>\n    public const string DirectoryForwardingAddress = \"orleans.directory.forwarding.address\";\n\n    /// <summary>\n    /// The exception type tag key.\n    /// </summary>\n    public const string ExceptionType = \"exception.type\";\n\n    /// <summary>\n    /// The exception message tag key.\n    /// </summary>\n    public const string ExceptionMessage = \"exception.message\";\n\n    /// <summary>\n    /// The placement filter type tag key.\n    /// </summary>\n    public const string PlacementFilterType = \"orleans.placement.filter.type\";\n\n    /// <summary>\n    /// The storage provider tag key.\n    /// </summary>\n    public const string StorageProvider = \"orleans.storage.provider\";\n\n    /// <summary>\n    /// The storage state name tag key.\n    /// </summary>\n    public const string StorageStateName = \"orleans.storage.state.name\";\n\n    /// <summary>\n    /// The storage state type tag key.\n    /// </summary>\n    public const string StorageStateType = \"orleans.storage.state.type\";\n\n    /// <summary>\n    /// The RPC system tag key.\n    /// </summary>\n    public const string RpcSystem = \"rpc.system\";\n\n    /// <summary>\n    /// The RPC service tag key.\n    /// </summary>\n    public const string RpcService = \"rpc.service\";\n\n    /// <summary>\n    /// The RPC method tag key.\n    /// </summary>\n    public const string RpcMethod = \"rpc.method\";\n\n    /// <summary>\n    /// The RPC Orleans target ID tag key.\n    /// </summary>\n    public const string RpcOrleansTargetId = \"rpc.orleans.target_id\";\n\n    /// <summary>\n    /// The RPC Orleans source ID tag key.\n    /// </summary>\n    public const string RpcOrleansSourceId = \"rpc.orleans.source_id\";\n\n    /// <summary>\n    /// The exception stacktrace tag key.\n    /// </summary>\n    public const string ExceptionStacktrace = \"exception.stacktrace\";\n\n    /// <summary>\n    /// The exception escaped tag key.\n    /// </summary>\n    public const string ExceptionEscaped = \"exception.escaped\";\n\n    /// <summary>\n    /// Indicates whether a rehydration attempt was ignored.\n    /// </summary>\n    public const string RehydrateIgnored = \"orleans.rehydrate.ignored\";\n\n    /// <summary>\n    /// The reason why a rehydration attempt was ignored.\n    /// </summary>\n    public const string RehydrateIgnoredReason = \"orleans.rehydrate.ignored.reason\";\n\n    /// <summary>\n    /// The previous registration address during rehydration.\n    /// </summary>\n    public const string RehydratePreviousRegistration = \"orleans.rehydrate.previousRegistration\";\n\n    /// <summary>\n    /// The target silo address for migration.\n    /// </summary>\n    public const string MigrationTargetSilo = \"orleans.migration.target.silo\";\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Diagnostics/OpenTelemetryHeaders.cs",
    "content": "namespace Orleans.Diagnostics;\n\ninternal static class OpenTelemetryHeaders\n{\n    internal const string TraceParent = \"traceparent\";\n    internal const string TraceState = \"tracestate\";\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/ClientNotAvailableException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Indicates that a client is not longer reachable.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n#pragma warning disable RCS1194 // Implement exception constructors.\n    public sealed class ClientNotAvailableException : OrleansException\n#pragma warning restore RCS1194 // Implement exception constructors.\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"clientId\">\n        /// The client id.\n        /// </param>\n        internal ClientNotAvailableException(GrainId clientId)\n            : base($\"No activation for client {clientId}\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The exception message.\n        /// </param>\n        internal ClientNotAvailableException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        internal ClientNotAvailableException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClientNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        [Obsolete]\n        private ClientNotAvailableException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/GatewayTooBusyException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Signifies that a gateway silo is currently in overloaded / load shedding state\n    /// and is unable to currently accept this message being sent.\n    /// </summary>\n    /// <remarks>\n    /// This situation is usually a transient condition.\n    /// The message is likely to be accepted by this or another gateway if it is retransmitted at a later time.\n    /// </remarks>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GatewayTooBusyException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GatewayTooBusyException\"/> class.\n        /// </summary>\n        public GatewayTooBusyException()\n            : base(\"Gateway too busy\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GatewayTooBusyException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public GatewayTooBusyException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GatewayTooBusyException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public GatewayTooBusyException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GatewayTooBusyException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        [Obsolete]\n        private GatewayTooBusyException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/GrainExtensionNotInstalledException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Signifies that an attempt was made to invoke a grain extension method on a grain where that extension was not installed.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GrainExtensionNotInstalledException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainExtensionNotInstalledException\"/> class.\n        /// </summary>\n        public GrainExtensionNotInstalledException()\n            : base(\"GrainExtensionNotInstalledException\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainExtensionNotInstalledException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public GrainExtensionNotInstalledException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainExtensionNotInstalledException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public GrainExtensionNotInstalledException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainExtensionNotInstalledException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        [Obsolete]\n        private GrainExtensionNotInstalledException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/LimitExceededException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Signifies that a grain is in an overloaded state where some runtime limit setting is currently being exceeded,\n    /// and so that grain is unable to currently accept the message being sent.\n    /// </summary>\n    /// <remarks>\n    /// This situation is often a transient condition.\n    /// The message is likely to be accepted by this grain if it is retransmitted at a later time.\n    /// </remarks>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class LimitExceededException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LimitExceededException\"/> class.\n        /// </summary>\n        public LimitExceededException()\n            : base(\"Limit exceeded\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LimitExceededException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public LimitExceededException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LimitExceededException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public LimitExceededException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LimitExceededException\"/> class.\n        /// </summary>\n        /// <param name=\"limitName\">\n        /// The limit name.\n        /// </param>\n        /// <param name=\"current\">\n        /// The current value.\n        /// </param>\n        /// <param name=\"threshold\">\n        /// The threshold value.\n        /// </param>\n        /// <param name=\"extraInfo\">\n        /// Extra, descriptive information.\n        /// </param>\n        public LimitExceededException(string limitName, int current, int threshold, object extraInfo)\n            : base($\"Limit exceeded {limitName} Current={current} Threshold={threshold} {extraInfo}\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LimitExceededException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        [Obsolete]\n        private LimitExceededException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/OrleansConfigurationException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a configuration exception.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansConfigurationException : Exception\n    {\n        /// <inheritdoc />\n        public OrleansConfigurationException(string message)\n            : base(message)\n        {\n        }\n\n        /// <inheritdoc />\n        public OrleansConfigurationException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <inheritdoc />\n        /// <exception cref=\"SerializationException\">The class name is <see langword=\"null\" /> or <see cref=\"P:System.Exception.HResult\" /> is zero (0).</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"info\" /> is <see langword=\"null\" />.</exception>\n        [Obsolete]\n        private OrleansConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/OrleansException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// An exception class used by the Orleans runtime for reporting errors.\n    /// </summary>\n    /// <remarks>\n    /// This is also the base class for any more specific exceptions\n    /// raised by the Orleans runtime.\n    /// </remarks>\n    [Serializable]\n    [GenerateSerializer]\n    public class OrleansException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansException\"/> class.\n        /// </summary>\n        public OrleansException()\n            : base(\"Unexpected error.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public OrleansException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public OrleansException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        /// <exception cref=\"SerializationException\">The class name is <see langword=\"null\" /> or <see cref=\"P:System.Exception.HResult\" /> is zero (0).</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"info\" /> is <see langword=\"null\" />.</exception>\n        [Obsolete]\n        protected OrleansException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/OrleansLifecycleCanceledException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Indicates a lifecycle was canceled, either by request or due to observer error.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansLifecycleCanceledException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansLifecycleCanceledException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        internal OrleansLifecycleCanceledException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansLifecycleCanceledException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        internal OrleansLifecycleCanceledException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansLifecycleCanceledException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        /// <exception cref=\"SerializationException\">The class name is <see langword=\"null\" /> or <see cref=\"P:System.Exception.HResult\" /> is zero (0).</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"info\" /> is <see langword=\"null\" />.</exception>\n        [Obsolete]\n        private OrleansLifecycleCanceledException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/OrleansMessageRejectionException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Indicates that an Orleans message was rejected.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class OrleansMessageRejectionException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMessageRejectionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        internal OrleansMessageRejectionException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMessageRejectionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        internal OrleansMessageRejectionException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMessageRejectionException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        /// <exception cref=\"SerializationException\">\n        /// The class name is <see langword=\"null\"/> or <see cref=\"P:System.Exception.HResult\"/> is zero (0).\n        /// </exception>\n        /// <exception cref=\"ArgumentNullException\">\n        /// <paramref name=\"info\"/> is <see langword=\"null\"/>.\n        /// </exception>\n        [Obsolete]\n        protected OrleansMessageRejectionException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/SiloUnavailableException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Signifies that an request was canceled due to target silo unavailability.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class SiloUnavailableException : OrleansMessageRejectionException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloUnavailableException\"/> class.\n        /// </summary>\n        public SiloUnavailableException()\n            : base(\"Silo unavailable\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloUnavailableException\"/> class.\n        /// </summary>\n        /// <param name=\"msg\">\n        /// The msg.\n        /// </param>\n        public SiloUnavailableException(string msg)\n            : base(msg)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloUnavailableException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        /// <param name=\"innerException\">\n        /// The inner exception.\n        /// </param>\n        public SiloUnavailableException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloUnavailableException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        /// <exception cref=\"SerializationException\">The class name is <see langword=\"null\" /> or <see cref=\"P:System.Exception.HResult\" /> is zero (0).</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"info\" /> is <see langword=\"null\" />.</exception>\n        [Obsolete]\n        private SiloUnavailableException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Exceptions/WrappedException.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.ExceptionServices;\nusing System.Runtime.Serialization;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// An exception class used by the Orleans runtime for reporting errors.\n    /// </summary>\n    /// <remarks>\n    /// This is also the base class for any more specific exceptions\n    /// raised by the Orleans runtime.\n    /// </remarks>\n    [Serializable]\n    [GenerateSerializer]\n    public class WrappedException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"WrappedException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">\n        /// The message.\n        /// </param>\n        public WrappedException(string message)\n            : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"WrappedException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        /// <exception cref=\"SerializationException\">The class name is <see langword=\"null\" /> or <see cref=\"P:System.Exception.HResult\" /> is zero (0).</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"info\" /> is <see langword=\"null\" />.</exception>\n        [Obsolete]\n        protected WrappedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            OriginalExceptionType = info.GetString(nameof(OriginalExceptionType));\n        }\n\n        /// <summary>\n        /// Gets or sets the type of the original exception.\n        /// </summary>\n        [Id(0)]\n        public string? OriginalExceptionType { get; set; }\n\n        /// <inheritdoc/>\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(OriginalExceptionType), OriginalExceptionType);\n        }\n\n        /// <summary>\n        /// Creates a new instance of the <see cref=\"WrappedException\"/> class and rethrows it using the provided exception's stack trace.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        [DoesNotReturn]\n        public static void CreateAndRethrow(Exception exception)\n        {\n            var error = exception switch\n            {\n                WrappedException => exception,\n                { } => CreateFromException(exception),\n                null => throw new ArgumentNullException(nameof(exception))\n            };\n\n            ExceptionDispatchInfo.Throw(error);\n        }\n\n        private static WrappedException CreateFromException(Exception exception)\n        {\n            var originalExceptionType = RuntimeTypeNameFormatter.Format(exception.GetType());\n            var detailedMessage = LogFormatter.PrintException(exception);\n            var result = new WrappedException(detailedMessage)\n            {\n                OriginalExceptionType = originalExceptionType,\n            };\n\n            if (exception.StackTrace is { } stackTrace)\n            {\n                ExceptionDispatchInfo.SetRemoteStackTrace(result, exception.StackTrace);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            return $\"{nameof(WrappedException)} OriginalType: {OriginalExceptionType}, Message: {Message}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/GrainDirectory/GrainDirectoryAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.GrainDirectory\n{\n    /// <summary>\n    /// Specifies the name of the grain directory provider to use for the grain class which this attribute is applied to.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class GrainDirectoryAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        /// <summary>\n        /// The default grain directory.\n        /// </summary>\n        public const string DEFAULT_GRAIN_DIRECTORY = \"default\";\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainDirectoryAttribute\"/> class.\n        /// </summary>\n        public GrainDirectoryAttribute() : this(DEFAULT_GRAIN_DIRECTORY)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainDirectoryAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"grainDirectoryName\">\n        /// The grain directory provider name.\n        /// </param>\n        public GrainDirectoryAttribute(string grainDirectoryName)\n        {\n            this.GrainDirectoryName = grainDirectoryName;\n        }\n\n        /// <summary>\n        /// Gets or sets the grain directory provider name.\n        /// </summary>\n        public string GrainDirectoryName { get; set; }\n\n        /// <inheritdoc />\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.GrainDirectory] = this.GrainDirectoryName ?? DEFAULT_GRAIN_DIRECTORY;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/GrainDirectory/IGrainDirectory.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.GrainDirectory\n{\n    /// <summary>\n    /// Interface for grain directory implementations\n    /// </summary>\n    public interface IGrainDirectory\n    {\n        /// <summary>\n        /// Register a <see cref=\"GrainAddress\"/> entry in the directory.\n        /// Only one <see cref=\"GrainAddress\"/> per <see cref=\"GrainAddress.GrainId\"/> can be registered. If there is already an\n        /// existing entry, the directory will not override it.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"GrainAddress\"/> to register</param>\n        /// <returns>The <see cref=\"GrainAddress\"/> that is effectively registered in the directory.</returns>\n        Task<GrainAddress?> Register(GrainAddress address);\n\n        /// <summary>\n        /// Register a <see cref=\"GrainAddress\"/> entry in the directory.\n        /// Only one <see cref=\"GrainAddress\"/> per <see cref=\"GrainAddress.GrainId\"/> can be registered. If there is already an\n        /// existing entry, the directory will not override it.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"GrainAddress\"/> to register</param>\n        /// <returns>The <see cref=\"GrainAddress\"/> that is effectively registered in the directory.</returns>\n        Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress) => GrainDirectoryExtension.Register(this, address, previousAddress);\n\n        /// <summary>\n        /// Unregisters the specified <see cref=\"GrainAddress\"/> entry from the directory.\n        /// </summary>\n        /// <param name=\"address\">\n        /// The <see cref=\"GrainAddress\"/> to unregister.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task Unregister(GrainAddress address);\n\n        /// <summary>\n        /// Lookup for a <see cref=\"GrainAddress\"/> for a given Grain ID.\n        /// </summary>\n        /// <param name=\"grainId\">The Grain ID to lookup</param>\n        /// <returns>The <see cref=\"GrainAddress\"/> entry found in the directory, if any</returns>\n        Task<GrainAddress?> Lookup(GrainId grainId);\n\n        /// <summary>\n        /// Unregisters all grain directory entries which point to any of the specified silos.\n        /// </summary>\n        /// <remarks>\n        /// Can be a No-Op depending on the implementation.\n        /// </remarks>\n        /// <param name=\"siloAddresses\">The silos to be removed from the directory</param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        Task UnregisterSilos(List<SiloAddress> siloAddresses);\n    }\n\n    internal static class GrainDirectoryExtension\n    {\n        internal static async Task<GrainAddress?> Register(IGrainDirectory directory, GrainAddress address, GrainAddress? previousAddress)\n        {\n            if (previousAddress is not null)\n            {\n                await directory.Unregister(previousAddress);\n            }\n\n            return await directory.Register(address);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/ActivationId.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Runtime.Serialization;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Uniquely identifies a grain activation.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    [JsonConverter(typeof(ActivationIdConverter))]\n    public readonly struct ActivationId : IEquatable<ActivationId>, ISpanFormattable\n    {\n        [DataMember(Order = 0)]\n        [Id(0)]\n        internal readonly Guid Key;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ActivationId\"/> struct.\n        /// </summary>\n        /// <param name=\"key\">The activation id.</param>\n        public ActivationId(Guid key) => Key = key;\n\n        /// <summary>\n        /// Gets a value indicating whether the instance is the default instance.\n        /// </summary>\n        public bool IsDefault => Key == default;\n\n        /// <summary>\n        /// Returns a new, random activation id.\n        /// </summary>\n        /// <returns>A new, random activation id.</returns>\n        public static ActivationId NewId() => new(Guid.NewGuid());\n\n        /// <summary>\n        /// Returns an activation id which has been computed deterministically and reproducibly from the provided grain id.\n        /// </summary>\n        /// <param name=\"grain\">The grain id.</param>\n        /// <returns>An activation id which has been computed deterministically and reproducibly from the provided grain id.</returns>\n        public static ActivationId GetDeterministic(GrainId grain)\n        {\n            Span<byte> temp = stackalloc byte[16];\n            BinaryPrimitives.WriteUInt64LittleEndian(temp, grain.Type.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt64LittleEndian(temp[8..], grain.Key.GetUniformHashCode());\n            var key = new Guid(temp);\n            return new ActivationId(key);\n        }\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => obj is ActivationId other && Key.Equals(other.Key);\n\n        /// <inheritdoc />\n        public bool Equals(ActivationId other) => Key.Equals(other.Key);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Key.GetHashCode();\n\n        /// <inheritdoc />\n        public override string ToString() => $\"@{Key:N}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"@{Key:N}\", out charsWritten);\n\n        /// <summary>\n        /// Returns a string representation of this activation id which can be parsed by <see cref=\"FromParsableString\"/>.\n        /// </summary>\n        /// <returns>A string representation of this activation id which can be parsed by <see cref=\"FromParsableString\"/>.</returns>\n        public string ToParsableString() => ToString();\n\n        /// <summary>\n        /// Parses a string representation of an activation id which was created using <see cref=\"ToParsableString\"/>.\n        /// </summary>\n        /// <param name=\"activationId\">The string representation of the activation id.</param>\n        /// <returns>The activation id.</returns>\n        public static ActivationId FromParsableString(string activationId)\n        {\n            var span = activationId.AsSpan();\n            return span.Length == 33 && span[0] == '@' ? new(Guid.ParseExact(span[1..], \"N\")) : throw new FormatException($\"Invalid activation id: {activationId}\");\n        }\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(ActivationId left, ActivationId right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(ActivationId left, ActivationId right) => !(left == right);\n    }\n\n    /// <summary>\n    /// Functionality for converting <see cref=\"ActivationId\"/> instances to and from their JSON representation.\n    /// </summary>\n    public sealed class ActivationIdConverter : JsonConverter<ActivationId>\n    {\n        /// <inheritdoc />\n        public override ActivationId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString() is { } str ? ActivationId.FromParsableString(str) : default;\n\n        /// <inheritdoc />\n        public override void Write(Utf8JsonWriter writer, ActivationId value, JsonSerializerOptions options)\n        {\n            Span<byte> buf = stackalloc byte[33];\n            buf[0] = (byte)'@';\n            Utf8Formatter.TryFormat(value.Key, buf[1..], out var len, 'N');\n            Debug.Assert(len == 32);\n            writer.WriteStringValue(buf);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/ClientGrainId.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies a client.\n    /// </summary>\n    internal readonly struct ClientGrainId : IEquatable<ClientGrainId>, IComparable<ClientGrainId>, ISpanFormattable\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"ClientGrainId\"/> instance.\n        /// </summary>\n        private ClientGrainId(GrainId grainId) => this.GrainId = grainId;\n\n        /// <summary>\n        /// Gets the underlying <see cref=\"GrainId\"/>.\n        /// </summary>\n        public readonly GrainId GrainId;\n\n        /// <summary>\n        /// Creates a new <see cref=\"ClientGrainId\"/> instance.\n        /// </summary>\n        public static ClientGrainId Create() => Create(GrainIdKeyExtensions.CreateGuidKey(Guid.NewGuid()));\n\n        /// <summary>\n        /// Creates a new <see cref=\"ClientGrainId\"/> instance.\n        /// </summary>\n        public static ClientGrainId Create(string id)\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(id);\n            return Create(IdSpan.Create(id));\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"ClientGrainId\"/> instance.\n        /// </summary>\n        public static ClientGrainId Create(IdSpan id) => new ClientGrainId(new GrainId(GrainTypePrefix.ClientGrainType, id));\n\n        /// <summary>\n        /// Converts the provided <see cref=\"GrainId\"/> to a <see cref=\"ClientGrainId\"/>. A return value indicates whether the operation succeeded.\n        /// </summary>\n        public static bool TryParse(GrainId grainId, out ClientGrainId clientId)\n        {\n            if (!grainId.Type.IsClient())\n            {\n                clientId = default;\n                return false;\n            }\n\n            // Strip the observer id, if present.\n            var key = grainId.Key.AsSpan();\n            if (key.IndexOf((byte)ObserverGrainId.SegmentSeparator) is int index && index >= 0)\n            {\n                key = key[..index];\n                grainId = new GrainId(grainId.Type, new IdSpan(key.ToArray()));\n            }\n\n            clientId = new ClientGrainId(grainId);\n            return true;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is ClientGrainId clientId && GrainId.Equals(clientId.GrainId);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.GrainId.GetHashCode();\n\n        /// <inheritdoc/>\n        public override string ToString() => this.GrainId.ToString();\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => ((ISpanFormattable)GrainId).TryFormat(destination, out charsWritten, format, provider);\n\n        /// <inheritdoc/>\n        public bool Equals(ClientGrainId other) => this.GrainId.Equals(other.GrainId);\n\n        /// <inheritdoc/>\n        public int CompareTo(ClientGrainId other) => this.GrainId.CompareTo(other.GrainId);\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(ClientGrainId left, ClientGrainId right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(ClientGrainId left, ClientGrainId right) => !(left == right);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainAddress.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing System.Text.Json.Serialization;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents an entry in a <see cref=\"IGrainDirectory\"/>\n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public sealed class GrainAddress : IEquatable<GrainAddress>, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly GrainId _grainId;\n\n        [Id(1)]\n        private readonly ActivationId _activationId;\n\n        /// <summary>\n        /// Identifier of the Grain\n        /// </summary>\n        public GrainId GrainId { get => _grainId; init => _grainId = value; }\n\n        /// <summary>\n        /// Id of the specific Grain activation\n        /// </summary>\n        public ActivationId ActivationId { get => _activationId; init => _activationId = value; }\n\n        /// <summary>\n        /// Address of the silo where the grain activation lives\n        /// </summary>\n        [Id(2)]\n        public SiloAddress? SiloAddress { get; init; }\n\n        /// <summary>\n        /// MembershipVersion at the time of registration\n        /// </summary>\n        [Id(3)]\n        public MembershipVersion MembershipVersion { get; init; } = MembershipVersion.MinValue;\n\n        [JsonIgnore]\n        public bool IsComplete => !_grainId.IsDefault && !_activationId.IsDefault && SiloAddress != null;\n\n        public override bool Equals(object? obj) => Equals(obj as GrainAddress);\n\n        public bool Equals(GrainAddress? other)\n        {\n            if (ReferenceEquals(this, other)) return true;\n            return MatchesGrainIdAndSilo(this, other)\n                && _activationId.Equals(other._activationId);\n        }\n\n        /// <summary>\n        /// Two grain addresses match if they have equal <see cref=\"SiloAddress\"/> and <see cref=\"GrainId\"/> values\n        /// and either one has a default <see cref=\"ActivationId\"/> value or both have equal <see cref=\"ActivationId\"/> values.\n        /// </summary>\n        /// <param name=\"other\"> The other <see cref=\"GrainAddress\"/> to compare this one with.</param>\n        /// <returns> Returns <c>true</c> if the two <see cref=\"GrainAddress\"/> are considered to match.</returns>\n        public bool Matches([NotNullWhen(true)] GrainAddress? other)\n        {\n            if (ReferenceEquals(this, other)) return true;\n            return MatchesGrainIdAndSilo(this, other)\n                && (_activationId.IsDefault || other._activationId.IsDefault || _activationId.Equals(other._activationId));\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static bool MatchesGrainIdAndSilo([NotNullWhen(true)] GrainAddress? address, [NotNullWhen(true)] GrainAddress? other)\n        {\n            return other is not null\n                && address is not null\n                && address.GrainId.Equals(other.GrainId)\n                && !(address.SiloAddress is null ^ other.SiloAddress is null)\n                && (address.SiloAddress is null || address.SiloAddress.Equals(other.SiloAddress));\n        }\n\n        public override int GetHashCode() => HashCode.Combine(SiloAddress, _grainId, _activationId);\n\n        public override string ToString() => $\"[{nameof(GrainAddress)} GrainId {_grainId}, ActivationId: {_activationId}, SiloAddress: {SiloAddress}]\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"[{nameof(GrainAddress)} GrainId {_grainId}, ActivationId: {_activationId}, SiloAddress: {SiloAddress}]\", out charsWritten);\n\n        public string ToFullString() => $\"[{nameof(GrainAddress)} GrainId {_grainId}, ActivationId: {_activationId}, SiloAddress: {SiloAddress}, MembershipVersion: {MembershipVersion}]\";\n\n        internal static GrainAddress NewActivationAddress(SiloAddress silo, GrainId grain) => GetAddress(silo, grain, ActivationId.NewId());\n\n        internal static GrainAddress GetAddress(SiloAddress? silo, GrainId grain, ActivationId activation)\n        {\n            // Silo part is not mandatory\n            if (grain.IsDefault) throw new ArgumentNullException(nameof(grain));\n\n            return new GrainAddress\n            {\n                GrainId = grain,\n                ActivationId = activation,\n                SiloAddress = silo,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainAddressCacheUpdate.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Represents a directive to update an invalid, cached <see cref=\"GrainAddress\"/> to a valid <see cref=\"GrainAddress\"/>.\n/// </summary>\n[GenerateSerializer, Immutable]\npublic sealed class GrainAddressCacheUpdate : ISpanFormattable\n{\n    [Id(0)]\n    private readonly GrainId _grainId;\n\n    [Id(1)]\n    private readonly ActivationId _invalidActivationId;\n\n    [Id(2)]\n    private readonly SiloAddress? _invalidSiloAddress;\n\n    [Id(3)]\n    private readonly MembershipVersion _invalidMembershipVersion = MembershipVersion.MinValue;\n\n    [Id(4)]\n    private readonly ActivationId _validActivationId;\n\n    [Id(5)]\n    private readonly SiloAddress? _validSiloAddress;\n\n    [Id(6)]\n    private readonly MembershipVersion _validMembershipVersion = MembershipVersion.MinValue;\n\n    public GrainAddressCacheUpdate(GrainAddress invalidAddress, GrainAddress? validAddress)\n    {\n        ArgumentNullException.ThrowIfNull(invalidAddress);\n\n        _grainId = invalidAddress.GrainId;\n        _invalidActivationId = invalidAddress.ActivationId;\n        _invalidSiloAddress = invalidAddress.SiloAddress;\n        _invalidMembershipVersion = invalidAddress.MembershipVersion;\n\n        if (validAddress is not null)\n        {\n            if (invalidAddress.GrainId != validAddress.GrainId)\n            {\n                ThrowGrainIdDoesNotMatch(invalidAddress, validAddress);\n                return;\n            }\n\n            _validActivationId = validAddress.ActivationId;\n            _validSiloAddress = validAddress.SiloAddress;\n            _validMembershipVersion = validAddress.MembershipVersion;\n        }\n    }\n\n    /// <summary>\n    /// Identifier of the Grain.\n    /// </summary>\n    public GrainId GrainId => _grainId;\n\n    /// <summary>\n    /// Identifier of the invalid grain activation.\n    /// </summary>\n    public ActivationId InvalidActivationId => _invalidActivationId;\n\n    /// <summary>\n    /// Address of the silo indicated by the invalid grain activation cache entry.\n    /// </summary>\n    public SiloAddress? InvalidSiloAddress => _invalidSiloAddress;\n\n    /// <summary>\n    /// Gets the valid grain activation address.\n    /// </summary>\n    public GrainAddress? ValidGrainAddress => _validSiloAddress switch\n    {\n        null => null,\n        _ => new()\n        {\n            GrainId = _grainId,\n            ActivationId = _validActivationId,\n            SiloAddress = _validSiloAddress,\n            MembershipVersion = _validMembershipVersion,\n        }\n    };\n\n    /// <summary>\n    /// Gets the invalid grain activation address.\n    /// </summary>\n    public GrainAddress InvalidGrainAddress => new()\n    {\n        GrainId = _grainId,\n        ActivationId = _invalidActivationId,\n        SiloAddress = _invalidSiloAddress,\n        MembershipVersion = _invalidMembershipVersion,\n    };\n\n    public override string ToString() => $\"[{nameof(GrainAddressCacheUpdate)} GrainId {_grainId}, InvalidActivationId: {_invalidActivationId}, InvalidSiloAddress: {_invalidSiloAddress}, ValidGrainAddress: {ValidGrainAddress}]\";\n\n    string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n    bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        => destination.TryWrite($\"[{nameof(GrainAddressCacheUpdate)} GrainId {_grainId}, InvalidActivationId: {_invalidActivationId}, InvalidSiloAddress: {_invalidSiloAddress}, ValidGrainAddress: {ValidGrainAddress}]\", out charsWritten);\n\n    public string ToFullString() => $\"[{nameof(GrainAddressCacheUpdate)} GrainId {_grainId}, InvalidActivationId: {_invalidActivationId}, InvalidSiloAddress: {_invalidSiloAddress}, ValidGrainAddress: {ValidGrainAddress}, MembershipVersion: {_invalidMembershipVersion}]\";\n\n    [DoesNotReturn]\n    private static void ThrowGrainIdDoesNotMatch(GrainAddress invalidAddress, GrainAddress validAddress) => throw new ArgumentException($\"Invalid grain address grain id {invalidAddress.GrainId} does not match valid grain address grain id {validAddress.GrainId}.\", nameof(validAddress));\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainId.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies a grain.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    [JsonConverter(typeof(GrainIdJsonConverter))]\n    public readonly struct GrainId : IEquatable<GrainId>, IComparable<GrainId>, ISerializable, ISpanFormattable, ISpanParsable<GrainId>\n    {\n        [Id(0)]\n        private readonly GrainType _type;\n\n        [Id(1)]\n        private readonly IdSpan _key;\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        public GrainId(GrainType type, IdSpan key)\n        {\n            _type = type;\n            _key = key;\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        private GrainId(SerializationInfo info, StreamingContext context)\n        {\n            _type = new GrainType(IdSpan.UnsafeCreate((byte[]?)info.GetValue(\"tv\", typeof(byte[])), info.GetInt32(\"th\")));\n            _key = IdSpan.UnsafeCreate((byte[]?)info.GetValue(\"kv\", typeof(byte[])), info.GetInt32(\"kh\"));\n        }\n\n        /// <summary>\n        /// Gets the grain type.\n        /// </summary>\n        public GrainType Type => _type;\n\n        /// <summary>\n        /// Gets the grain key.\n        /// </summary>\n        public IdSpan Key => _key;\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        public static GrainId Create(string type, string key) => Create(GrainType.Create(type), key);\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        public static GrainId Create(GrainType type, string key)\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(key);\n            return new GrainId(type, IdSpan.Create(key));\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        public static GrainId Create(GrainType type, IdSpan key) => new GrainId(type, key);\n\n        /// <summary>\n        /// Parses a <see cref=\"GrainId\"/> from the span.\n        /// </summary>\n        public static GrainId Parse(ReadOnlySpan<char> value, IFormatProvider? provider = null)\n        {\n            if (!TryParse(value, provider, out var result))\n            {\n                ThrowInvalidGrainId(value);\n\n                static void ThrowInvalidGrainId(ReadOnlySpan<char> value) => throw new ArgumentException($\"Unable to parse \\\"{value}\\\" as a grain id\");\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Tries to parse a <see cref=\"GrainId\"/> from the span.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if a valid <see cref=\"GrainId\"/> was parsed. <see langword=\"false\"/> otherwise</returns>\n        public static bool TryParse(ReadOnlySpan<char> value, IFormatProvider? provider, out GrainId result)\n        {\n            int i;\n            if ((i = value.IndexOf('/')) < 0)\n            {\n                result = default;\n                return false;\n            }\n\n            var typeSpan = value[0..i];\n            var type = new byte[Encoding.UTF8.GetByteCount(typeSpan)];\n            Encoding.UTF8.GetBytes(typeSpan, type);\n\n            var idSpan = value[(i + 1)..];\n            var id = new byte[Encoding.UTF8.GetByteCount(idSpan)];\n            Encoding.UTF8.GetBytes(idSpan, id);\n\n            result = new(new GrainType(type), new IdSpan(id));\n            return true;\n        }\n\n        /// <summary>\n        /// Parses a <see cref=\"GrainId\"/> from the string.\n        /// </summary>\n        public static GrainId Parse(string value)\n            => Parse(value.AsSpan(), null);\n\n        /// <summary>\n        /// Parses a <see cref=\"GrainId\"/> from the string.\n        /// </summary>\n        public static GrainId Parse(string value, IFormatProvider? provider = null)\n            => Parse(value.AsSpan(), provider);\n\n        /// <summary>\n        /// Tries to parse a <see cref=\"GrainId\"/> from the string.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if a valid <see cref=\"GrainId\"/> was parsed. <see langword=\"false\"/> otherwise</returns>\n        public static bool TryParse(string? value, out GrainId result)\n            => TryParse(value.AsSpan(), null, out result);\n\n        /// <summary>\n        /// Tries to parse a <see cref=\"GrainId\"/> from the string.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if a valid <see cref=\"GrainId\"/> was parsed. <see langword=\"false\"/> otherwise</returns>\n        public static bool TryParse(string? value, IFormatProvider? provider, out GrainId result)\n            => TryParse(value.AsSpan(), provider, out result);\n\n        /// <summary>\n        /// <see langword=\"true\"/> if this instance is the default value, <see langword=\"false\"/> if it is not.\n        /// </summary>\n        public bool IsDefault => _type.IsDefault && _key.IsDefault;\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is GrainId id && Equals(id);\n\n        /// <inheritdoc/>\n        public bool Equals(GrainId other) => _key.Equals(other._key) && _type.Equals(other._type);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => HashCode.Combine(_type, _key);\n\n        /// <summary>\n        /// Generates a uniform, stable hash code for a grain id.\n        /// </summary>\n        public uint GetUniformHashCode()\n        {\n            // This value must be stable for a given id and equal for all nodes in a cluster.\n            // HashCode.Combine does not currently offer stability with respect to its inputs.\n            return _type.GetUniformHashCode() * 31 + _key.GetUniformHashCode();\n        }\n\n        /// <inheritdoc/>\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"tv\", GrainType.UnsafeGetArray(_type));\n            info.AddValue(\"th\", _type.GetHashCode());\n            info.AddValue(\"kv\", IdSpan.UnsafeGetArray(_key));\n            info.AddValue(\"kh\", _key.GetHashCode());\n        }\n\n        /// <inheritdoc/>\n        public int CompareTo(GrainId other)\n        {\n            var typeComparison = _type.CompareTo(other._type);\n            if (typeComparison != 0) return typeComparison;\n\n            return _key.CompareTo(other._key);\n        }\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(GrainId left, GrainId right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(GrainId left, GrainId right) => !left.Equals(right);\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{_type}/{_key}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"{_type}/{_key}\", out charsWritten);\n    }\n\n    /// <summary>\n    /// Functionality for converting a <see cref=\"GrainId\"/> to and from a JSON string.\n    /// </summary>\n    public sealed class GrainIdJsonConverter : JsonConverter<GrainId>\n    {\n        /// <inheritdoc />\n        public override GrainId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            var valueLength = reader.HasValueSequence\n                ? checked((int)reader.ValueSequence.Length)\n                : reader.ValueSpan.Length;\n\n            Span<char> buf = valueLength <= 128\n                ? (stackalloc char[128])[..valueLength]\n                : new char[valueLength];\n\n            var written = reader.CopyString(buf);\n            buf = buf[..written];\n\n            return GrainId.Parse(buf);\n        }\n\n        /// <inheritdoc />\n        public override GrainId ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n            => Read(ref reader, typeToConvert, options);\n\n        /// <inheritdoc />\n        public override void Write(Utf8JsonWriter writer, GrainId value, JsonSerializerOptions options)\n            => WriteGrainId(writer, value, isPropertyName: false);\n\n        /// <inheritdoc />\n        public override void WriteAsPropertyName(Utf8JsonWriter writer, [DisallowNull] GrainId value, JsonSerializerOptions options)\n            => WriteGrainId(writer, value, isPropertyName: true);\n\n        private static void WriteGrainId(Utf8JsonWriter writer, GrainId value, bool isPropertyName)\n        {\n            var type = value.Type.AsSpan();\n            var key = value.Key.AsSpan();\n            Span<byte> buf = stackalloc byte[type.Length + key.Length + 1];\n\n            type.CopyTo(buf);\n            buf[type.Length] = (byte)'/';\n            key.CopyTo(buf[(type.Length + 1)..]);\n\n            if (isPropertyName)\n            {\n                writer.WritePropertyName(buf);\n            }\n            else\n            {\n                writer.WriteStringValue(buf);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainIdKeyExtensions.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Extensions for <see cref=\"GrainId\"/> keys.\n    /// </summary>\n    public static class GrainIdKeyExtensions\n    {\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"long\"/> key.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key.\n        /// </returns>\n        public static IdSpan CreateIntegerKey(long key)\n        {\n            Span<byte> buf = stackalloc byte[sizeof(long) * 2];\n            Utf8Formatter.TryFormat(key, buf, out var len, 'X');\n            Debug.Assert(len > 0, \"Unable to format the provided value as a UTF8 string\");\n            return new IdSpan(buf[..len].ToArray());\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"long\"/> key and key extension string.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The UTF-8 encoded key extension.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key and key extension.\n        /// </returns>\n        public static IdSpan CreateIntegerKey(long key, ReadOnlySpan<byte> keyExtension)\n        {\n            if (keyExtension.IsEmpty)\n                return CreateIntegerKey(key);\n\n            Span<byte> tmp = stackalloc byte[sizeof(long) * 2];\n            Utf8Formatter.TryFormat(key, tmp, out var len, 'X');\n            Debug.Assert(len > 0, \"Unable to format the provided value as a UTF8 string\");\n\n            var buf = new byte[len + 1 + keyExtension.Length];\n            tmp[..len].CopyTo(buf);\n            buf[len] = (byte)'+';\n            keyExtension.CopyTo(buf.AsSpan(len + 1));\n            return new(buf);\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"long\"/> key and key extension string.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The key extension.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key and key extension.\n        /// </returns>\n        public static IdSpan CreateIntegerKey(long key, string? keyExtension)\n        {\n            if (string.IsNullOrWhiteSpace(keyExtension))\n            {\n                return CreateIntegerKey(key);\n            }\n\n            Span<byte> tmp = stackalloc byte[sizeof(long) * 2];\n            Utf8Formatter.TryFormat(key, tmp, out var len, 'X');\n            Debug.Assert(len > 0, \"Unable to format the provided value as a UTF8 string\");\n\n            var extLen = Encoding.UTF8.GetByteCount(keyExtension);\n            var buf = new byte[len + 1 + extLen];\n            tmp[..len].CopyTo(buf);\n            buf[len] = (byte)'+';\n            Encoding.UTF8.GetBytes(keyExtension, 0, keyExtension.Length, buf, len + 1);\n\n            return new IdSpan(buf);\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"Guid\"/> key.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key.\n        /// </returns>\n        public static IdSpan CreateGuidKey(Guid key)\n        {\n            var buf = new byte[32];\n            Utf8Formatter.TryFormat(key, buf, out var len, 'N');\n            Debug.Assert(len == 32, \"Unable to format the provided value as a UTF8 string\");\n            return new IdSpan(buf);\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"Guid\"/> key and key extension string.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The UTF-8 encoded key extension.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key and key extension.\n        /// </returns>\n        public static IdSpan CreateGuidKey(Guid key, ReadOnlySpan<byte> keyExtension)\n        {\n            if (keyExtension.IsEmpty)\n                return CreateGuidKey(key);\n\n            var buf = new byte[32 + 1 + keyExtension.Length];\n            Utf8Formatter.TryFormat(key, buf, out var len, 'N');\n            Debug.Assert(len == 32, \"Unable to format the provided value as a UTF8 string\");\n            buf[32] = (byte)'+';\n            keyExtension.CopyTo(buf.AsSpan(len + 1));\n            return new(buf);\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"IdSpan\"/> representing a <see cref=\"Guid\"/> key and key extension string.\n        /// </summary>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExtension\">\n        /// The key extension.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> representing the provided key and key extension.\n        /// </returns>\n        public static IdSpan CreateGuidKey(Guid key, string? keyExtension)\n        {\n            if (string.IsNullOrWhiteSpace(keyExtension))\n            {\n                return CreateGuidKey(key);\n            }\n\n            var extLen = Encoding.UTF8.GetByteCount(keyExtension);\n            var buf = new byte[32 + 1 + extLen];\n            Utf8Formatter.TryFormat(key, buf, out var len, 'N');\n            Debug.Assert(len == 32, \"Unable to format the provided value as a UTF8 string\");\n            buf[32] = (byte)'+';\n            Encoding.UTF8.GetBytes(keyExtension, 0, keyExtension.Length, buf, 33);\n\n            return new IdSpan(buf);\n        }\n\n        /// <summary>\n        /// Tries to parse the <see cref=\"GrainId.Key\"/> portion of the provided grain id to extract a <see cref=\"long\"/> key and <see cref=\"string\"/> key extension.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExt\">\n        /// The key extension.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> when the grain id was successfully parsed, <see langword=\"false\" /> otherwise.\n        /// </returns>\n        public static bool TryGetIntegerKey(this GrainId grainId, out long key, out string? keyExt)\n        {\n            keyExt = null;\n            var keyString = grainId.Key.AsSpan();\n            if (keyString.IndexOf((byte)'+') is int index && index >= 0)\n            {\n                keyExt = Encoding.UTF8.GetString(keyString[(index + 1)..]);\n                keyString = keyString[..index];\n            }\n\n            return Utf8Parser.TryParse(keyString, out key, out var len, 'X') && len == keyString.Length;\n        }\n\n        /// <summary>\n        /// Tries to parse the <see cref=\"GrainId.Key\"/> portion of the provided grain id to extract a <see cref=\"long\"/> key.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> when the grain id was successfully parsed, <see langword=\"false\" /> otherwise.\n        /// </returns>\n        internal static bool TryGetIntegerKey(this GrainId grainId, out long key)\n        {\n            var keyString = grainId.Key.AsSpan();\n            if (keyString.IndexOf((byte)'+') is int index && index >= 0)\n                keyString = keyString[..index];\n\n            return Utf8Parser.TryParse(keyString, out key, out var len, 'X') && len == keyString.Length;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"long\"/> representation of a grain key.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id.</param>\n        /// <param name=\"keyExt\">The output parameter to return the extended key part of the grain primary key, if extended primary key was provided for that grain.</param>\n        /// <returns>A long representing the key for this grain.</returns>\n        public static long GetIntegerKey(this GrainId grainId, out string? keyExt)\n        {\n            if (!grainId.TryGetIntegerKey(out var result, out keyExt))\n            {\n                ThrowInvalidIntegerKeyFormat(grainId);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"long\"/> representation of a grain key.\n        /// </summary>\n        /// <param name=\"grainId\">The grain to find the key for.</param>\n        /// <returns>A <see cref=\"long\"/> representing the key for this grain.</returns>\n        public static long GetIntegerKey(this GrainId grainId)\n        {\n            if (!grainId.TryGetIntegerKey(out var result))\n            {\n                ThrowInvalidIntegerKeyFormat(grainId);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Tries to parse the <see cref=\"GrainId.Key\"/> portion of the provided grain id to extract a <see cref=\"Guid\"/> key and <see cref=\"string\"/> key extension.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <param name=\"keyExt\">\n        /// The key extension.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> when the grain id was successfully parsed, <see langword=\"false\" /> otherwise.\n        /// </returns>\n        public static bool TryGetGuidKey(this GrainId grainId, out Guid key, out string? keyExt)\n        {\n            keyExt = null;\n            var keyString = grainId.Key.AsSpan();\n            if (keyString.Length > 32 && keyString[32] == (byte)'+')\n            {\n                keyExt = Encoding.UTF8.GetString(keyString[33..]);\n                keyString = keyString[..32];\n            }\n            else if (keyString.Length != 32)\n            {\n                key = default;\n                return false;\n            }\n\n            return Utf8Parser.TryParse(keyString, out key, out var len, 'N') && len == 32;\n        }\n\n        /// <summary>\n        /// Tries to parse the <see cref=\"GrainId.Key\"/> portion of the provided grain id to extract a <see cref=\"Guid\"/> key.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"key\">\n        /// The key.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> when the grain id was successfully parsed, <see langword=\"false\" /> otherwise.\n        /// </returns>\n        internal static bool TryGetGuidKey(this GrainId grainId, out Guid key)\n        {\n            var keyString = grainId.Key.AsSpan();\n            if (keyString.Length > 32 && keyString[32] == (byte)'+')\n            {\n                keyString = keyString[..32];\n            }\n            else if (keyString.Length != 32)\n            {\n                key = default;\n                return false;\n            }\n\n            return Utf8Parser.TryParse(keyString, out key, out var len, 'N') && len == 32;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"Guid\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grainId\">The grain to find the primary key for.</param>\n        /// <param name=\"keyExt\">The output parameter to return the extended key part of the grain primary key, if extended primary key was provided for that grain.</param>\n        /// <returns>A <see cref=\"Guid\"/> representing the primary key for this grain.</returns>\n        public static Guid GetGuidKey(this GrainId grainId, out string? keyExt)\n        {\n            if (!grainId.TryGetGuidKey(out var result, out keyExt))\n            {\n                ThrowInvalidGuidKeyFormat(grainId);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"Guid\"/> representation of a grain primary key.\n        /// </summary>\n        /// <param name=\"grainId\">The grain to find the primary key for.</param>\n        /// <returns>A <see cref=\"Guid\"/> representing the primary key for this grain.</returns>\n        public static Guid GetGuidKey(this GrainId grainId)\n        {\n            if (!grainId.TryGetGuidKey(out var result))\n            {\n                ThrowInvalidGuidKeyFormat(grainId);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Throws an exception indicating that a <see cref=\"Guid\"/>-based grain id was incorrectly formatted.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        private static void ThrowInvalidGuidKeyFormat(GrainId grainId) => throw new ArgumentException($\"Value \\\"{grainId}\\\" is not in the correct format for a Guid key.\", nameof(grainId));\n\n        /// <summary>\n        /// Throws an exception indicating that a <see cref=\"long\"/>-based grain id was incorrectly formatted.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        private static void ThrowInvalidIntegerKeyFormat(GrainId grainId) => throw new ArgumentException($\"Value \\\"{grainId}\\\" is not in the correct format for an Integer key.\", nameof(grainId));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainInterfaceType.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Uniquely identifies a grain interface.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct GrainInterfaceType : IEquatable<GrainInterfaceType>, ISpanFormattable\n    {\n        /// <summary>\n        /// The underlying value.\n        /// </summary>\n        [Id(0)]\n        private readonly IdSpan _value;\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainInterfaceType\"/> instance.\n        /// </summary>\n        public GrainInterfaceType(string value)\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(value);\n            _value = IdSpan.Create(value);\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainInterfaceType\"/> instance.\n        /// </summary>\n        public GrainInterfaceType(IdSpan value) => _value = value;\n\n        /// <summary>\n        /// Returns the <see cref=\"IdSpan\"/> value underlying this instance.\n        /// </summary>\n        public IdSpan Value => _value;\n\n        /// <summary>\n        /// Returns true if this value is equal to the <see langword=\"default\"/> instance.\n        /// </summary>\n        public bool IsDefault => _value.IsDefault;\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainInterfaceType\"/> instance.\n        /// </summary>\n        public static GrainInterfaceType Create(string value) => new GrainInterfaceType(value);\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => obj is GrainInterfaceType id && Equals(id);\n\n        /// <inheritdoc />\n        public bool Equals(GrainInterfaceType other) => _value.Equals(other._value);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => _value.GetHashCode();\n\n        /// <summary>\n        /// Returns a UTF8 interpretation of the current instance.\n        /// </summary>\n        /// <returns></returns>\n        public override string ToString() => _value.ToString();\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString() ?? \"\";\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => _value.TryFormat(destination, out charsWritten);\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(GrainInterfaceType left, GrainInterfaceType right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(GrainInterfaceType left, GrainInterfaceType right) => !left.Equals(right);\n    }\n\n    /// <summary>\n    /// Gets a <see cref=\"GrainInterfaceType\"/> for an interface.\n    /// </summary>\n    public interface IGrainInterfaceTypeProvider\n    {\n        /// <summary>\n        /// Gets the <see cref=\"GrainInterfaceType\"/> corresponding to the specified <paramref name=\"type\"/>.\n        /// </summary>\n        /// <param name=\"type\">The grain interface type instance.</param>\n        /// <param name=\"grainInterfaceType\">The resulting grain interface type identifier.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if a <see cref=\"GrainInterfaceType\"/> corresponding to the provided type was found, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        bool TryGetGrainInterfaceType(Type type, out GrainInterfaceType grainInterfaceType);\n    }\n\n    /// <summary>\n    /// Gets a <see cref=\"GrainInterfaceType\"/> from attributes implementing <see cref=\"IGrainInterfaceTypeProviderAttribute\"/>.\n    /// </summary>\n    public class AttributeGrainInterfaceTypeProvider : IGrainInterfaceTypeProvider\n    {\n        /// <summary>\n        /// The service provider.\n        /// </summary>\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Creates a <see cref=\"AttributeGrainInterfaceTypeProvider\"/> instance.\n        /// </summary>\n        public AttributeGrainInterfaceTypeProvider(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public bool TryGetGrainInterfaceType(Type type, out GrainInterfaceType grainInterfaceType)\n        {\n            foreach (var attr in type.GetCustomAttributes(inherit: false))\n            {\n                if (attr is IGrainInterfaceTypeProviderAttribute provider)\n                {\n                    grainInterfaceType = provider.GetGrainInterfaceType(this._serviceProvider, type);\n                    return true;\n                }\n            }\n\n            grainInterfaceType = default;\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// An <see cref=\"Attribute\"/> which implements this specifies the <see cref=\"GrainInterfaceType\"/> of the\n    /// type which it is attached to.\n    /// </summary>\n    public interface IGrainInterfaceTypeProviderAttribute\n    {\n        /// <summary>\n        /// Gets the grain interface identifier.\n        /// </summary>\n        /// <param name=\"services\">The service provider.</param>\n        /// <param name=\"type\">The grain interface type.</param>\n        /// <returns>\n        /// The <see cref=\"GrainInterfaceType\"/> corresponding to the provided type.\n        /// </returns>\n        GrainInterfaceType GetGrainInterfaceType(IServiceProvider services, Type type);\n    }\n\n    /// <summary>\n    /// When applied to a grain interface, specifies the <see cref=\"GrainInterfaceType\"/>.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)]\n    public sealed class GrainInterfaceTypeAttribute : Attribute, IGrainInterfaceTypeProviderAttribute\n    {\n        /// <summary>\n        /// The grain interface type.\n        /// </summary>\n        private readonly GrainInterfaceType _value;\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainInterfaceTypeAttribute\"/> instance.\n        /// </summary>\n        public GrainInterfaceTypeAttribute(string value)\n        {\n            _value = GrainInterfaceType.Create(value);\n        }\n\n        /// <inheritdoc />\n        public GrainInterfaceType GetGrainInterfaceType(IServiceProvider services, Type type) => _value;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainType.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents the type of a grain.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct GrainType : IEquatable<GrainType>, IComparable<GrainType>, ISerializable, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly IdSpan _value;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainType\"/> struct. \n        /// </summary>\n        /// <param name=\"id\">\n        /// The id.\n        /// </param>\n        public GrainType(IdSpan id) => _value = id;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainType\"/> struct. \n        /// </summary>\n        /// <param name=\"value\">\n        /// The raw id value.\n        /// </param>\n        public GrainType(byte[] value) => _value = new IdSpan(value);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainType\"/> struct. \n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        private GrainType(SerializationInfo info, StreamingContext context)\n        {\n            _value = IdSpan.UnsafeCreate((byte[]?)info.GetValue(\"v\", typeof(byte[])), info.GetInt32(\"h\"));\n        }\n\n        /// <summary>\n        /// Gets the underlying value.\n        /// </summary>\n        public IdSpan Value => _value;\n\n        /// <summary>\n        /// Returns a span representation of this instance.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"ReadOnlySpan{Byte}\"/> representation of the value.\n        /// </returns>\n        public ReadOnlySpan<byte> AsSpan() => _value.AsSpan();\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainType\"/> instance.\n        /// </summary>\n        /// <param name=\"value\">\n        /// The value.\n        /// </param>\n        /// <returns>\n        /// The newly created <see cref=\"GrainType\"/> instance.\n        /// </returns>\n        public static GrainType Create(string value)\n        {\n            ArgumentNullException.ThrowIfNullOrWhiteSpace(value);\n            return new GrainType(Encoding.UTF8.GetBytes(value));\n        }\n\n        /// <summary>\n        /// Converts a <see cref=\"GrainType\"/> to a <see cref=\"IdSpan\"/>.\n        /// </summary>\n        /// <param name=\"kind\">The grain type to convert.</param>\n        /// <returns>The corresponding <see cref=\"IdSpan\"/>.</returns>\n        public static explicit operator IdSpan(GrainType kind) => kind._value;\n\n        /// <summary>\n        /// Converts a <see cref=\"IdSpan\"/> to a <see cref=\"GrainType\"/>.\n        /// </summary>\n        /// <param name=\"id\">The id span to convert.</param>\n        /// <returns>The corresponding <see cref=\"GrainType\"/>.</returns>\n        public static explicit operator GrainType(IdSpan id) => new GrainType(id);\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is the default value.\n        /// </summary>\n        public bool IsDefault => _value.IsDefault;\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is GrainType kind && Equals(kind);\n\n        /// <inheritdoc/>\n        public bool Equals(GrainType obj) => _value.Equals(obj._value);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => _value.GetHashCode();\n\n        /// <summary>\n        /// Generates a uniform, stable hash code for this grain type. \n        /// </summary>\n        /// <returns>\n        /// A uniform, stable hash of this instance.\n        /// </returns>\n        public uint GetUniformHashCode() => _value.GetUniformHashCode();\n\n        /// <summary>\n        /// Returns the array underlying a grain type instance.\n        /// </summary>\n        /// <param name=\"id\">The grain type.</param>\n        /// <returns>The array underlying a grain type instance.</returns>\n        /// <remarks>\n        /// The returned array must not be modified.\n        /// </remarks>\n        public static byte[]? UnsafeGetArray(GrainType id) => IdSpan.UnsafeGetArray(id._value);\n\n        /// <inheritdoc/>\n        public int CompareTo(GrainType other) => _value.CompareTo(other._value);\n\n        /// <inheritdoc/>\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"v\", IdSpan.UnsafeGetArray(_value));\n            info.AddValue(\"h\", _value.GetHashCode());\n        }\n\n        /// <summary>\n        /// Returns a string representation of this instance, decoding the value as UTF8.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"string\"/> representation of this instance.\n        /// </returns>\n        public override string? ToString() => _value.ToString();\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString() ?? \"\";\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => _value.TryFormat(destination, out charsWritten);\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(GrainType left, GrainType right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(GrainType left, GrainType right) => !(left == right);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GrainTypePrefix.cs",
    "content": "using System;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Prefixes and corresponding helper methods for <see cref=\"GrainType\"/>.\n    /// </summary>\n    public static class GrainTypePrefix\n    {\n        /// <summary>\n        /// The prefix for system types.\n        /// </summary>\n        public const string SystemPrefix = \"sys.\";\n\n        /// <summary>\n        /// The prefix for system targets.\n        /// </summary>\n        public const string SystemTargetPrefix = SystemPrefix + \"svc.\";\n\n        /// <summary>\n        /// A span representation of <see cref=\"SystemTargetPrefix\" />.\n        /// </summary>\n        public static readonly ReadOnlyMemory<byte> SystemTargetPrefixBytes = Encoding.UTF8.GetBytes(SystemTargetPrefix);\n\n        /// <summary>\n        /// The prefix for grain service types.\n        /// </summary>\n        public const string GrainServicePrefix = SystemTargetPrefix + \"user.\";\n\n        /// <summary>\n        /// A span representation of <see cref=\"ClientPrefix\" />.\n        /// </summary>\n        public static readonly ReadOnlyMemory<byte> GrainServicePrefixBytes = Encoding.UTF8.GetBytes(GrainServicePrefix);\n\n        /// <summary>\n        /// The prefix for clients.\n        /// </summary>\n        public const string ClientPrefix = SystemPrefix + \"client\";\n\n        /// <summary>\n        /// A span representation of <see cref=\"ClientPrefix\" />.\n        /// </summary>\n        public static readonly ReadOnlyMemory<byte> ClientPrefixBytes = Encoding.UTF8.GetBytes(ClientPrefix);\n\n        /// <summary>\n        /// The prefix used to represent a grain client.\n        /// </summary>\n        public static readonly GrainType ClientGrainType = GrainType.Create(ClientPrefix);\n\n        /// <summary>\n        /// The prefix for legacy grains.\n        /// </summary>\n        public const string LegacyGrainPrefix = SystemPrefix + \"grain.v1.\";\n\n        /// <summary>\n        /// A span representation of <see cref=\"LegacyGrainPrefixBytes\" />.\n        /// </summary>\n        public static readonly ReadOnlyMemory<byte> LegacyGrainPrefixBytes = Encoding.UTF8.GetBytes(LegacyGrainPrefix);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the type is a client, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"type\">The grain type.</param>\n        /// <returns><see langword=\"true\"/> if the type is a client, <see langword=\"false\"/> if not.</returns>\n        public static bool IsClient(this in GrainType type) => type.AsSpan().StartsWith(ClientPrefixBytes.Span);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the type is a system target, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"type\">The grain type.</param>\n        /// <returns><see langword=\"true\"/> if the type is a system target, <see langword=\"false\"/> if not.</returns>\n        public static bool IsSystemTarget(this in GrainType type) => type.AsSpan().StartsWith(SystemTargetPrefixBytes.Span);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the type is a legacy grain, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"type\">The grain type.</param>\n        /// <returns><see langword=\"true\"/> if the type is a legacy grain, <see langword=\"false\"/> if not.</returns>\n        public static bool IsLegacyGrain(this in GrainType type) => type.AsSpan().StartsWith(LegacyGrainPrefixBytes.Span);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the type is a grain service, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"type\">The grain type.</param>\n        /// <returns><see langword=\"true\"/> if the type is a grain service, <see langword=\"false\"/> if not.</returns>\n        public static bool IsGrainService(this in GrainType type) => type.AsSpan().StartsWith(GrainServicePrefixBytes.Span);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the id represents a client, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"id\">The grain id.</param>\n        /// <returns><see langword=\"true\"/> if the type is a client, <see langword=\"false\"/> if not.</returns>\n        public static bool IsClient(this in GrainId id) => id.Type.IsClient();\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the id represents a system target, <see langword=\"false\"/> if not.\n        /// </summary>\n        /// <param name=\"id\">The grain id.</param>\n        /// <returns><see langword=\"true\"/> if the type is a system target, <see langword=\"false\"/> if not.</returns>\n        public static bool IsSystemTarget(this in GrainId id) => id.Type.IsSystemTarget();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/GuidId.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// A unique identifier based on a <see cref=\"Guid\"/>.\n    /// </summary>\n    [Serializable]\n    [Immutable]\n    [GenerateSerializer]\n    public sealed class GuidId : IEquatable<GuidId>, IComparable<GuidId>, ISerializable\n    {\n        private static readonly Interner<Guid, GuidId> guidIdInternCache = new Interner<Guid, GuidId>(InternerConstants.SIZE_LARGE);\n\n        /// <summary>\n        /// The underlying <see cref=\"Guid\"/>.\n        /// </summary>\n        [Id(0)]\n        public readonly Guid Guid;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GuidId\"/> class.\n        /// </summary>\n        /// <param name=\"guid\">\n        /// The underlying <see cref=\"Guid\"/>.\n        /// </param>\n        private GuidId(Guid guid)\n        {\n            this.Guid = guid;\n        }\n\n        /// <summary>\n        /// Returns a new, randomly generated <see cref=\"GuidId\"/>.\n        /// </summary>\n        /// <returns>A new, randomly generated <see cref=\"GuidId\"/>.</returns>\n        public static GuidId GetNewGuidId()\n        {\n            return FindOrCreateGuidId(Guid.NewGuid());\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"GuidId\"/> instance corresponding to the provided <see cref=\"Guid\"/>.\n        /// </summary>\n        /// <param name=\"guid\">The guid.</param>\n        /// <returns>A <see cref=\"GuidId\"/> instance corresponding to the provided <see cref=\"Guid\"/>.</returns>\n        public static GuidId GetGuidId(Guid guid)\n        {\n            return FindOrCreateGuidId(guid);\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"GuidId\"/> instance corresponding to the provided <see cref=\"Guid\"/>.\n        /// </summary>\n        /// <param name=\"guid\">The <see cref=\"Guid\"/>.</param>\n        /// <returns>A <see cref=\"GuidId\"/> instance corresponding to the provided <see cref=\"Guid\"/>.</returns>\n        private static GuidId FindOrCreateGuidId(Guid guid)\n        {\n            return guidIdInternCache.FindOrCreate(guid, g => new GuidId(g));\n        }\n\n        /// <inheritdoc />\n        public int CompareTo(GuidId? other) => other is null ? 1 : Guid.CompareTo(other.Guid);\n\n        /// <inheritdoc />\n        public bool Equals(GuidId? other) => other is not null && Guid.Equals(other.Guid);\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => Equals(obj as GuidId);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Guid.GetHashCode();\n\n        /// <inheritdoc />\n        public override string ToString() => Guid.ToString();\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(GuidId? left, GuidId? right) => ReferenceEquals(left, right) || (left?.Equals(right) ?? false);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(GuidId? left, GuidId? right) => !(left == right);\n\n        /// <inheritdoc />\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"Guid\", Guid, typeof(Guid));\n        }\n\n        private GuidId(SerializationInfo info, StreamingContext context)\n        {\n            // ! This is an older pattern which is not compatible with nullable reference types.\n            Guid = (Guid)info.GetValue(\"Guid\", typeof(Guid))!;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/IdSpan.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Primitive type for identities, representing a sequence of bytes.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct IdSpan : IEquatable<IdSpan>, IComparable<IdSpan>, ISerializable, ISpanFormattable\n    {\n        /// <summary>\n        /// The stable hash of the underlying value.\n        /// </summary>\n        [Id(0)]\n        private readonly int _hashCode;\n\n        /// <summary>\n        /// The underlying value.\n        /// </summary>\n        [Id(1)]\n        private readonly byte[]? _value;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdSpan\"/> struct.\n        /// </summary>\n        /// <param name=\"value\">\n        /// The value.\n        /// </param>\n        public IdSpan(byte[] value)\n        {\n            _value = value;\n            _hashCode = (int)StableHash.ComputeHash(value);\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdSpan\"/> struct.\n        /// </summary>\n        /// <param name=\"value\">\n        /// The value.\n        /// </param>\n        /// <param name=\"hashCode\">\n        /// The hash code of the value.\n        /// </param>\n        private IdSpan(byte[]? value, int hashCode)\n        {\n            _value = value;\n            _hashCode = hashCode;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdSpan\"/> struct.\n        /// </summary>\n        /// <param name=\"info\">\n        /// The serialization info.\n        /// </param>\n        /// <param name=\"context\">\n        /// The context.\n        /// </param>\n        private IdSpan(SerializationInfo info, StreamingContext context)\n        {\n            _value = (byte[]?)info.GetValue(\"v\", typeof(byte[]));\n            _hashCode = info.GetInt32(\"h\");\n        }\n\n        /// <summary>\n        /// Gets the underlying value.\n        /// </summary>\n        public ReadOnlyMemory<byte> Value => _value;\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is the default value.\n        /// </summary>\n        public bool IsDefault => _value is null || _value.Length == 0;\n\n        /// <summary>\n        /// Creates a new <see cref=\"IdSpan\"/> instance from the provided value.\n        /// </summary>\n        /// <returns>\n        /// A new <see cref=\"IdSpan\"/> corresponding to the provided id.\n        /// </returns>\n        public static IdSpan Create(string id) => new(Encoding.UTF8.GetBytes(id));\n\n        /// <summary>\n        /// Returns a span representation of this instance.\n        /// </summary>\n        /// <returns>\n        /// A span representation of this instance.\n        /// </returns>\n        public ReadOnlySpan<byte> AsSpan() => _value;\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is IdSpan kind && Equals(kind);\n\n        /// <inheritdoc/>\n        public bool Equals(IdSpan obj)\n        {\n            if (_value == obj._value)\n            {\n                return true;\n            }\n\n            if (_value is null || obj._value is null)\n            {\n                return false;\n            }\n\n            return _value.AsSpan().SequenceEqual(obj._value);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => _hashCode;\n\n        /// <summary>\n        /// Returns a uniform, stable hash code for an <see cref=\"IdSpan\"/>.\n        /// </summary>\n        /// <returns>\n        /// The hash code of this instance.\n        /// </returns>\n        public uint GetUniformHashCode() => unchecked((uint)_hashCode);\n\n        /// <inheritdoc/>\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"v\", _value);\n            info.AddValue(\"h\", _hashCode);\n        }\n\n        /// <summary>\n        /// Creates an instance, specifying both the hash code and the value.\n        /// </summary>\n        /// <remarks>\n        /// This method is intended for use by serializers and other low-level libraries.\n        /// </remarks>\n        /// <param name=\"value\">\n        /// The underlying value.\n        /// </param>\n        /// <param name=\"hashCode\">\n        /// The hash of the underlying value.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IdSpan\"/> instance.\n        /// </returns>\n        public static IdSpan UnsafeCreate(byte[]? value, int hashCode) => new(value, hashCode);\n\n        /// <summary>\n        /// Gets the underlying array from this instance.\n        /// </summary>\n        /// <param name=\"id\">The id span.</param>\n        /// <returns>The underlying array from this instance.</returns>\n        public static byte[]? UnsafeGetArray(IdSpan id) => id._value;\n\n        /// <inheritdoc/>\n        public int CompareTo(IdSpan other)\n        {\n            if (_value is null)\n            {\n                return other._value is null ? 0 : -1;\n            }\n\n            if (other._value is null)\n            {\n                return 1;\n            }\n\n            return _value.AsSpan().SequenceCompareTo(other._value.AsSpan());\n        }\n\n        /// <summary>\n        /// Returns a string representation of this instance, decoding the value as UTF8.\n        /// </summary>\n        /// <returns>\n        /// A string representation fo this instance.\n        /// </returns>\n        public override string ToString() => _value is null ? \"\" : Encoding.UTF8.GetString(_value);\n\n        public bool TryFormat(Span<char> destination, out int charsWritten)\n        {\n            if (_value is null)\n            {\n                charsWritten = 0;\n                return true;\n            }\n\n            var len = Encoding.UTF8.GetCharCount(_value);\n            if (destination.Length < len)\n            {\n                charsWritten = 0;\n                return false;\n            }\n\n            charsWritten = Encoding.UTF8.GetChars(_value, destination);\n            return true;\n        }\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => TryFormat(destination, out charsWritten);\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(IdSpan left, IdSpan right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(IdSpan left, IdSpan right) => !left.Equals(right);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/IdSpanCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Functionality for serializing and deserializing <see cref=\"IdSpan\"/> instances.\n/// </summary>\n[RegisterSerializer]\npublic sealed class IdSpanCodec : IFieldCodec<IdSpan>\n{\n    private readonly Type _codecType = typeof(IdSpan);\n\n    /// <inheritdoc />\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void WriteField<TBufferWriter>(\n        ref Writer<TBufferWriter> writer,\n        uint fieldIdDelta,\n        Type expectedType,\n        IdSpan value)\n        where TBufferWriter : IBufferWriter<byte>\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, _codecType, WireType.LengthPrefixed);\n        var bytes = value.AsSpan();\n        if (bytes.IsEmpty) writer.WriteByte(1); // Equivalent to `writer.WriteVarUInt32(0);`\n        else\n        {\n            writer.WriteVarUInt32((uint)(sizeof(int) + bytes.Length));\n            writer.WriteInt32(value.GetHashCode());\n            writer.Write(bytes);\n        }\n    }\n\n    /// <summary>\n    /// Writes an <see cref=\"IdSpan\"/> value to the provided writer without field framing.\n    /// </summary>\n    /// <param name=\"writer\">The writer.</param>\n    /// <param name=\"value\">The value to write.</param>\n    /// <typeparam name=\"TBufferWriter\">The underlying buffer writer type.</typeparam>\n    public static void WriteRaw<TBufferWriter>(\n        ref Writer<TBufferWriter> writer,\n        IdSpan value)\n        where TBufferWriter : IBufferWriter<byte>\n    {\n        var bytes = value.AsSpan();\n        writer.WriteVarUInt32((uint)bytes.Length);\n        if (!bytes.IsEmpty)\n        {\n            writer.WriteInt32(value.GetHashCode());\n            writer.Write(bytes);\n        }\n    }\n\n    /// <summary>\n    /// Reads an <see cref=\"IdSpan\"/> value from a reader without any field framing.\n    /// </summary>\n    /// <typeparam name=\"TInput\">The underlying reader input type.</typeparam>\n    /// <param name=\"reader\">The reader.</param>\n    /// <returns>An <see cref=\"IdSpan\"/>.</returns>\n    public static unsafe IdSpan ReadRaw<TInput>(ref Reader<TInput> reader)\n    {\n        var length = reader.ReadVarUInt32();\n        if (length == 0)\n            return default;\n\n        var hashCode = reader.ReadInt32();\n        var payloadArray = reader.ReadBytes(length);\n        return IdSpan.UnsafeCreate(payloadArray, hashCode);\n    }\n\n    /// <inheritdoc />\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public unsafe IdSpan ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        field.EnsureWireType(WireType.LengthPrefixed);\n        ReferenceCodec.MarkValueField(reader.Session);\n\n        var length = reader.ReadVarUInt32();\n        if (length == 0)\n            return default;\n\n        var hashCode = reader.ReadInt32();\n        var payloadArray = reader.ReadBytes(length - sizeof(int));\n        return IdSpan.UnsafeCreate(payloadArray, hashCode);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/Legacy/LegacyGrainId.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class LegacyGrainId : IEquatable<LegacyGrainId>, IComparable<LegacyGrainId>\n    {\n        private static readonly Interner<UniqueKey, LegacyGrainId> grainIdInternCache = new Interner<UniqueKey, LegacyGrainId>(InternerConstants.SIZE_LARGE);\n        private static readonly Interner<UniqueKey, byte[]> grainTypeInternCache = new Interner<UniqueKey, byte[]>();\n        private static readonly Interner<UniqueKey, byte[]> grainKeyInternCache = new Interner<UniqueKey, byte[]>();\n        private static readonly ReadOnlyMemory<byte> ClientPrefixBytes = Encoding.UTF8.GetBytes(GrainTypePrefix.ClientPrefix + \".\");\n\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        [DataMember]\n        [Id(0)]\n        internal readonly UniqueKey Key;\n\n        public UniqueKey.Category Category => Key.IdCategory;\n\n        public bool IsSystemTarget => Key.IsSystemTargetKey;\n\n        public bool IsGrain => Category == UniqueKey.Category.Grain || Category == UniqueKey.Category.KeyExtGrain;\n\n        public bool IsClient => Category == UniqueKey.Category.Client;\n\n        internal LegacyGrainId(UniqueKey key)\n        {\n            this.Key = key;\n        }\n\n        public static implicit operator GrainId(LegacyGrainId legacy) => legacy.ToGrainId();\n\n        public static LegacyGrainId NewId()\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(Guid.NewGuid(), UniqueKey.Category.Grain));\n        }\n\n        public static LegacyGrainId NewClientId()\n        {\n            return NewClientId(Guid.NewGuid());\n        }\n\n        internal static LegacyGrainId NewClientId(Guid id)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(id, UniqueKey.Category.Client, 0));\n        }\n\n        internal static LegacyGrainId GetGrainId(UniqueKey key)\n        {\n            return FindOrCreateGrainId(key);\n        }\n\n        // For testing only.\n        internal static LegacyGrainId GetGrainIdForTesting(Guid guid)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(guid));\n        }\n\n        internal static LegacyGrainId GetSystemTargetGrainId(long typeData)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewEmptySystemTargetKey(typeData));\n        }\n\n        internal static GrainType GetGrainType(long typeCode, bool isKeyExt)\n        {\n            return GetGrainType(isKeyExt\n                ? UniqueKey.NewKey(0, UniqueKey.Category.KeyExtGrain, typeCode, \"keyext\")\n                : UniqueKey.NewKey(0, UniqueKey.Category.Grain, typeCode));\n        }\n\n        internal static LegacyGrainId GetGrainId(long typeCode, long primaryKey, string? keyExt = null)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(primaryKey,\n                keyExt == null ? UniqueKey.Category.Grain : UniqueKey.Category.KeyExtGrain,\n                typeCode, keyExt));\n        }\n\n        internal static LegacyGrainId GetGrainId(long typeCode, Guid primaryKey, string? keyExt = null)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(primaryKey,\n                keyExt == null ? UniqueKey.Category.Grain : UniqueKey.Category.KeyExtGrain,\n                typeCode, keyExt));\n        }\n\n        internal static LegacyGrainId GetGrainId(long typeCode, string primaryKey)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewKey(0L,\n                UniqueKey.Category.KeyExtGrain,\n                typeCode, primaryKey));\n        }\n\n        internal static LegacyGrainId GetGrainServiceGrainId(short id, int typeData)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewGrainServiceKey(id, typeData));\n        }\n\n        internal static LegacyGrainId GetGrainServiceGrainId(int typeData, string systemGrainId)\n        {\n            return FindOrCreateGrainId(UniqueKey.NewGrainServiceKey(systemGrainId, typeData));\n        }\n\n        public Guid PrimaryKey\n        {\n            get { return GetPrimaryKey(); }\n        }\n\n        public long PrimaryKeyLong\n        {\n            get { return GetPrimaryKeyLong(); }\n        }\n\n        public string PrimaryKeyString\n        {\n            get { return GetPrimaryKeyString(); }\n        }\n\n        public string IdentityString\n        {\n            get { return ToDetailedString(); }\n        }\n\n        public bool IsLongKey\n        {\n            get { return Key.IsLongKey; }\n        }\n\n        public long GetPrimaryKeyLong(out string? keyExt)\n        {\n            return Key.PrimaryKeyToLong(out keyExt);\n        }\n\n        internal long GetPrimaryKeyLong()\n        {\n            return Key.PrimaryKeyToLong();\n        }\n\n        public Guid GetPrimaryKey(out string? keyExt)\n        {\n            return Key.PrimaryKeyToGuid(out keyExt);\n        }\n\n        internal Guid GetPrimaryKey()\n        {\n            return Key.PrimaryKeyToGuid();\n        }\n\n        internal string GetPrimaryKeyString()\n        {\n            _ = GetPrimaryKey(out string? key);\n            return key ?? string.Empty;\n        }\n\n        public int TypeCode => Key.BaseTypeCode;\n\n        private static GrainType GetGrainType(UniqueKey key)\n        {\n            return new GrainType(grainTypeInternCache.FindOrCreate(key, key =>\n            {\n                var prefixBytes = key.IsSystemTargetKey ? GrainTypePrefix.SystemTargetPrefixBytes\n                    : key.IdCategory == UniqueKey.Category.Client ? ClientPrefixBytes\n                    : GrainTypePrefix.LegacyGrainPrefixBytes;\n\n                return CreateGrainType(prefixBytes, key.TypeCodeData);\n            }));\n        }\n\n        private static byte[] CreateGrainType(ReadOnlyMemory<byte> prefixBytes, ulong typeCode)\n        {\n            var prefix = prefixBytes.Span;\n            var buf = new byte[prefix.Length + 16];\n            prefix.CopyTo(buf);\n            Utf8Formatter.TryFormat(typeCode, buf.AsSpan(prefix.Length), out var len, new StandardFormat('X', 16));\n            Debug.Assert(len == 16);\n            return buf;\n        }\n\n        public static GrainType CreateGrainTypeForGrain(int typeCode)\n        {\n            return new GrainType(CreateGrainType(GrainTypePrefix.LegacyGrainPrefixBytes, (ulong)typeCode));\n        }\n\n        public static GrainType CreateGrainTypeForSystemTarget(int typeCode)\n        {\n            return new GrainType(CreateGrainType(GrainTypePrefix.SystemTargetPrefixBytes, (ulong)typeCode));\n        }\n\n        private IdSpan GetGrainKey()\n        {\n            return new IdSpan(grainKeyInternCache.FindOrCreate(Key, k => Encoding.UTF8.GetBytes($\"{k.N0:X16}{k.N1:X16}{(k.HasKeyExt ? \"+\" : null)}{k.KeyExt}\")));\n        }\n\n        public GrainId ToGrainId()\n        {\n            return new GrainId(GetGrainType(Key), this.GetGrainKey());\n        }\n\n        public static bool TryConvertFromGrainId(GrainId id, [NotNullWhen(true)] out LegacyGrainId? legacyId)\n        {\n            legacyId = FromGrainIdInternal(id);\n            return legacyId is not null;\n        }\n\n        public static LegacyGrainId FromGrainId(GrainId id)\n        {\n            return FromGrainIdInternal(id) ?? ThrowNotLegacyGrainId(id);\n        }\n\n        private static LegacyGrainId? FromGrainIdInternal(GrainId id)\n        {\n            var typeSpan = id.Type.AsSpan();\n            if (typeSpan.Length != GrainTypePrefix.LegacyGrainPrefix.Length + 16)\n                return null;\n            if (!typeSpan.StartsWith(GrainTypePrefix.LegacyGrainPrefixBytes.Span))\n                return null;\n\n            typeSpan = typeSpan.Slice(GrainTypePrefix.LegacyGrainPrefix.Length, 16);\n            if (!Utf8Parser.TryParse(typeSpan, out ulong typeCodeData, out var len, 'X') || len < 16)\n                return null;\n\n            string? keyExt = null;\n            var keySpan = id.Key.Value.Span;\n            if (keySpan.Length < 32) return null;\n\n            if (!Utf8Parser.TryParse(keySpan[..16], out ulong n0, out len, 'X') || len < 16)\n                return null;\n\n            if (!Utf8Parser.TryParse(keySpan.Slice(16, 16), out ulong n1, out len, 'X') || len < 16)\n                return null;\n\n            if (keySpan.Length > 32)\n            {\n                if (keySpan[32] != '+') return null;\n                keyExt = Encoding.UTF8.GetString(keySpan[33..]);\n            }\n\n            return FindOrCreateGrainId(UniqueKey.NewKey(n0, n1, typeCodeData, keyExt));\n        }\n\n        private static LegacyGrainId ThrowNotLegacyGrainId(GrainId id)\n        {\n            throw new InvalidOperationException($\"Cannot convert non-legacy id {id} into legacy id\");\n        }\n\n        private static LegacyGrainId FindOrCreateGrainId(UniqueKey key)\n        {\n            return grainIdInternCache.FindOrCreate(key, k => new LegacyGrainId(k));\n        }\n\n        public bool Equals(LegacyGrainId? other)\n        {\n            return other != null && Key.Equals(other.Key);\n        }\n\n        public override bool Equals(object? obj)\n        {\n            var o = obj as LegacyGrainId;\n            return o != null && Key.Equals(o.Key);\n        }\n\n        // Keep compiler happy -- it does not like classes to have Equals(...) without GetHashCode() methods\n        public override int GetHashCode()\n        {\n            return Key.GetHashCode();\n        }\n\n        /// <summary>\n        /// Get a uniformly distributed hash code value for this grain, based on Jenkins Hash function.\n        /// NOTE: Hash code value may be positive or NEGATIVE.\n        /// </summary>\n        /// <returns>Hash code for this LegacyGrainId</returns>\n        public uint GetUniformHashCode()\n        {\n            return Key.GetUniformHashCode();\n        }\n\n        public override string ToString()\n        {\n            return ToStringImpl(false);\n        }\n\n        // same as ToString, just full primary key and type code\n        internal string ToDetailedString()\n        {\n            return ToStringImpl(true);\n        }\n\n        // same as ToString, just full primary key and type code\n        private string ToStringImpl(bool detailed)\n        {\n            // TODO Get name of system/target grain + name of the grain type\n\n            var keyString = Key.ToString();\n            // this should grab the least-significant half of n1, suffixing it with the key extension.\n            string idString = keyString;\n            if (!detailed)\n            {\n                if (keyString.Length >= 48)\n                    idString = keyString.Substring(24, 8) + keyString[48..];\n                else\n                    idString = keyString.Substring(24, 8);\n            }\n\n            string fullString;\n            switch (Category)\n            {\n                case UniqueKey.Category.Grain:\n                case UniqueKey.Category.KeyExtGrain:\n                    var typeString = TypeCode.ToString(\"X\");\n                    if (!detailed) typeString = typeString[Math.Max(0, typeString.Length - 8)..];\n                    fullString = $\"*grn/{typeString}/{idString}\";\n                    break;\n                case UniqueKey.Category.Client:\n                    fullString = $\"*cli/{idString}\";\n                    break;\n                case UniqueKey.Category.SystemTarget:\n                case UniqueKey.Category.KeyExtSystemTarget:\n                    fullString = $\"*stg/{Key.N1}/{idString}\";\n                    break;\n                case UniqueKey.Category.SystemGrain:\n                    fullString = $\"*sgn/{Key.PrimaryKeyToGuid()}/{idString}\";\n                    break;\n                default:\n                    fullString = \"???/\" + idString;\n                    break;\n            }\n            return detailed ? string.Format(\"{0}-0x{1, 8:X8}\", fullString, GetUniformHashCode()) : fullString;\n        }\n\n        public static bool IsLegacyGrainType(Type type)\n        {\n            return typeof(IGrainWithGuidKey).IsAssignableFrom(type)\n                || typeof(IGrainWithIntegerKey).IsAssignableFrom(type)\n                || typeof(IGrainWithStringKey).IsAssignableFrom(type)\n                || typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(type)\n                || typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(type);\n        }\n\n        public static bool IsLegacyKeyExtGrainType(Type type)\n        {\n            return typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(type)\n                || typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(type);\n        }\n\n        /// <summary>\n        /// Return this LegacyGrainId in a standard string form, suitable for later use with the <c>FromParsableString</c> method.\n        /// </summary>\n        /// <returns>LegacyGrainId in a standard string format.</returns>\n        internal string ToParsableString()\n        {\n            // NOTE: This function must be the \"inverse\" of FromParsableString, and data must round-trip reliably.\n\n            return Key.ToHexString();\n        }\n\n        /// <summary>\n        /// Create a new LegacyGrainId object by parsing string in a standard form returned from <c>ToParsableString</c> method.\n        /// </summary>\n        /// <param name=\"grainId\">String containing the LegacyGrainId info to be parsed.</param>\n        /// <returns>New LegacyGrainId object created from the input data.</returns>\n        internal static LegacyGrainId FromParsableString(string grainId)\n        {\n            return FromParsableString(grainId.AsSpan());\n        }\n\n        /// <summary>\n        /// Create a new LegacyGrainId object by parsing string in a standard form returned from <c>ToParsableString</c> method.\n        /// </summary>\n        /// <param name=\"grainId\">String containing the LegacyGrainId info to be parsed.</param>\n        /// <returns>New LegacyGrainId object created from the input data.</returns>\n        internal static LegacyGrainId FromParsableString(ReadOnlySpan<char> grainId)\n        {\n            // NOTE: This function must be the \"inverse\" of ToParsableString, and data must round-trip reliably.\n\n            var key = UniqueKey.Parse(grainId);\n            return FindOrCreateGrainId(key);\n        }\n\n        public uint GetHashCode_Modulo(uint umod)\n        {\n            int key = Key.GetHashCode();\n            int mod = (int)umod;\n            key = ((key % mod) + mod) % mod; // key should be positive now. So assert with checked.\n            return checked((uint)key);\n        }\n\n        public int CompareTo(LegacyGrainId? other)\n        {\n            if (other is null) return 1; // null is less than any non-null instance\n            return Key.CompareTo(other.Key);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/Legacy/UniqueKey.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Globalization;\nusing System.IO;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    [Serializable, GenerateSerializer, Immutable]\n    [SuppressReferenceTracking]\n    public sealed class UniqueKey : IComparable<UniqueKey>, IEquatable<UniqueKey>\n    {\n        /// <summary>\n        /// Type id values encoded into UniqueKeys\n        /// </summary>\n        public enum Category : byte\n        {\n            None = 0,\n            SystemTarget = 1,\n            SystemGrain = 2,\n            Grain = 3,\n            Client = 4,\n            KeyExtGrain = 6,\n            // 7 was GeoClient\n            KeyExtSystemTarget = 8,\n        }\n\n        [Id(0)]\n        public ulong N0 { get; private set; }\n        [Id(1)]\n        public ulong N1 { get; private set; }\n        [Id(2)]\n        public ulong TypeCodeData { get; private set; }\n        [Id(3)]\n        public string? KeyExt { get; private set; }\n\n        [NonSerialized]\n        private uint uniformHashCache;\n\n        public int BaseTypeCode => (int)TypeCodeData;\n\n        public Category IdCategory => GetCategory(TypeCodeData);\n\n        public bool IsLongKey => N0 == 0;\n\n        public bool IsSystemTargetKey\n            => IsSystemTarget(IdCategory);\n\n        private static bool IsSystemTarget(Category category)\n            => category == Category.SystemTarget || category == Category.KeyExtSystemTarget;\n\n        public bool HasKeyExt => IsKeyExt(IdCategory);\n\n        private static bool IsKeyExt(Category category)\n            => category == Category.KeyExtGrain || category == Category.KeyExtSystemTarget;\n\n        internal static readonly UniqueKey Empty = new UniqueKey();\n\n        internal static UniqueKey Parse(ReadOnlySpan<char> input)\n        {\n            const int minimumValidKeyLength = 48;\n            input = input.Trim();\n            if (input.Length >= minimumValidKeyLength)\n            {\n                var n0 = ulong.Parse(input[..16].ToString(), NumberStyles.AllowHexSpecifier);\n                var n1 = ulong.Parse(input.Slice(16, 16).ToString(), NumberStyles.AllowHexSpecifier);\n                var typeCodeData = ulong.Parse(input.Slice(32, 16).ToString(), NumberStyles.AllowHexSpecifier);\n                string? keyExt = null;\n                if (input.Length > minimumValidKeyLength)\n                {\n                    if (input[48] != '+') throw new InvalidDataException(\"UniqueKey hex string missing + separator.\");\n                    keyExt = input[49..].ToString();\n                }\n\n                return NewKey(n0, n1, typeCodeData, keyExt);\n            }\n\n            // last, for convenience we attempt to parse the string using GUID syntax. this is needed by unit\n            // tests but i don't know if it's needed for production.\n            return NewKey(Guid.Parse(input.ToString()));\n        }\n\n        internal static UniqueKey NewKey(ulong n0, ulong n1, Category category, long typeData, string? keyExt)\n            => NewKey(n0, n1, GetTypeCodeData(category, typeData), keyExt);\n\n        internal static UniqueKey NewKey(long longKey, Category category = Category.None, long typeData = 0, string? keyExt = null)\n        {\n            ThrowIfIsSystemTargetKey(category);\n\n            var key = NewKey(GetTypeCodeData(category, typeData), keyExt);\n            key.N1 = (ulong)longKey;\n            return key;\n        }\n\n        public static UniqueKey NewKey() => new UniqueKey { Guid = Guid.NewGuid() };\n\n        internal static UniqueKey NewKey(Guid guid) => new UniqueKey { Guid = guid };\n\n        internal static UniqueKey NewKey(Guid guid, Category category = Category.None, long typeData = 0, string? keyExt = null)\n        {\n            ThrowIfIsSystemTargetKey(category);\n\n            var key = NewKey(GetTypeCodeData(category, typeData), keyExt);\n            key.Guid = guid;\n            return key;\n        }\n\n        internal static UniqueKey NewEmptySystemTargetKey(long typeData)\n            => new UniqueKey { TypeCodeData = GetTypeCodeData(Category.SystemTarget, typeData) };\n\n        public static UniqueKey NewSystemTargetKey(Guid guid, long typeData)\n            => new UniqueKey { Guid = guid, TypeCodeData = GetTypeCodeData(Category.SystemTarget, typeData) };\n\n        public static UniqueKey NewSystemTargetKey(short systemId)\n            => new UniqueKey { N1 = (ulong)systemId, TypeCodeData = GetTypeCodeData(Category.SystemTarget) };\n\n        public static UniqueKey NewGrainServiceKey(short key, long typeData)\n            => new UniqueKey { N1 = (ulong)key, TypeCodeData = GetTypeCodeData(Category.SystemTarget, typeData) };\n\n        public static UniqueKey NewGrainServiceKey(string key, long typeData)\n            => NewKey(GetTypeCodeData(Category.KeyExtSystemTarget, typeData), key);\n\n        internal static UniqueKey NewKey(ulong n0, ulong n1, ulong typeCodeData, string? keyExt)\n        {\n            var key = NewKey(typeCodeData, keyExt);\n            key.N0 = n0;\n            key.N1 = n1;\n            return key;\n        }\n\n        private static UniqueKey NewKey(ulong typeCodeData, string? keyExt)\n        {\n            if (IsKeyExt(GetCategory(typeCodeData)))\n            {\n                if (string.IsNullOrWhiteSpace(keyExt))\n                    throw keyExt is null ? new ArgumentNullException(nameof(keyExt)) : throw new ArgumentException(\"Extended key is empty or white space.\", nameof(keyExt));\n            }\n            else if (keyExt != null) throw new ArgumentException(\"Only key extended grains can specify a non-null key extension.\");\n            return new UniqueKey { TypeCodeData = typeCodeData, KeyExt = keyExt };\n        }\n\n        private void ThrowIfIsNotLong()\n        {\n            if (!IsLongKey)\n                throw new InvalidOperationException(\"this key cannot be interpreted as a long value\");\n        }\n\n        private static void ThrowIfIsSystemTargetKey(Category category)\n        {\n            if (IsSystemTarget(category))\n                throw new ArgumentException(\n                    \"This overload of NewKey cannot be used to construct an instance of UniqueKey containing a SystemTarget id.\");\n        }\n\n        private void ThrowIfHasKeyExt(string methodName)\n        {\n            if (KeyExt != null)\n                throw new InvalidOperationException(\n                    string.Format(\n                        \"This overload of {0} cannot be used if the grain uses the primary key extension feature.\",\n                        methodName));\n        }\n\n        public long PrimaryKeyToLong(out string? extendedKey)\n        {\n            ThrowIfIsNotLong();\n\n            extendedKey = this.KeyExt;\n            return unchecked((long)N1);\n        }\n\n        public long PrimaryKeyToLong()\n        {\n            ThrowIfIsNotLong();\n            ThrowIfHasKeyExt(\"UniqueKey.PrimaryKeyToLong\");\n            return (long)N1;\n        }\n\n        public Guid PrimaryKeyToGuid(out string? extendedKey)\n        {\n            extendedKey = this.KeyExt;\n            return Guid;\n        }\n\n        public Guid PrimaryKeyToGuid()\n        {\n            ThrowIfHasKeyExt(\"UniqueKey.PrimaryKeyToGuid\");\n            return Guid;\n        }\n\n        public override bool Equals(object? o) => o is UniqueKey key && Equals(key);\n\n        // We really want Equals to be as fast as possible, as a minimum cost, as close to native as possible.\n        // No function calls, no boxing, inline.\n        public bool Equals(UniqueKey? other)\n        {\n            return other is not null\n                   && N0 == other.N0\n                   && N1 == other.N1\n                   && TypeCodeData == other.TypeCodeData\n                   && (KeyExt is null || KeyExt == other.KeyExt);\n        }\n\n        // We really want CompareTo to be as fast as possible, as a minimum cost, as close to native as possible.\n        // No function calls, no boxing, inline.\n        public int CompareTo(UniqueKey? other)\n        {\n            if (other is null) return 1;\n\n            return TypeCodeData < other.TypeCodeData ? -1\n               : TypeCodeData > other.TypeCodeData ? 1\n               : N0 < other.N0 ? -1\n               : N0 > other.N0 ? 1\n               : N1 < other.N1 ? -1\n               : N1 > other.N1 ? 1\n               : KeyExt == null ? 0\n               : string.CompareOrdinal(KeyExt, other.KeyExt);\n        }\n\n        public override int GetHashCode()\n        {\n            return unchecked((int)GetUniformHashCode());\n        }\n\n        internal uint GetUniformHashCode()\n        {\n            // Disabling this ReSharper warning; hashCache is a logically read-only variable, so accessing them in GetHashCode is safe.\n            // ReSharper disable NonReadonlyFieldInGetHashCode\n            if (uniformHashCache == 0)\n            {\n                if (KeyExt != null)\n                {\n                    uniformHashCache = StableHash.ComputeHash(this.ToByteArray());\n                }\n                else\n                {\n                    Span<byte> data = stackalloc byte[24];\n                    BinaryPrimitives.WriteUInt64LittleEndian(data, TypeCodeData);\n                    BinaryPrimitives.WriteUInt64LittleEndian(data[8..], N0);\n                    BinaryPrimitives.WriteUInt64LittleEndian(data[16..], N1);\n                    uniformHashCache = StableHash.ComputeHash(data);\n                }\n            }\n            return uniformHashCache;\n            // ReSharper restore NonReadonlyFieldInGetHashCode\n        }\n\n        /// <summary>\n        /// If KeyExt not exists, returns following structure\n        /// |8 bytes|8 bytes|8 bytes|4 bytes| - total 28 bytes.\n        /// If KeyExt exists, adds additional KeyExt bytes length\n        /// </summary>\n        /// <returns></returns>\n        internal ReadOnlySpan<byte> ToByteArray()\n        {\n            var extBytes = this.KeyExt != null ? Encoding.UTF8.GetBytes(KeyExt) : null;\n            var extBytesLength = extBytes?.Length ?? 0;\n            var sizeWithoutExtBytes = sizeof(ulong) * 3 + sizeof(int);\n\n            var spanBytes = new byte[sizeWithoutExtBytes + extBytesLength].AsSpan();\n\n            BinaryPrimitives.WriteUInt64LittleEndian(spanBytes, N0);\n            BinaryPrimitives.WriteUInt64LittleEndian(spanBytes.Slice(8, 8), N1);\n            BinaryPrimitives.WriteUInt64LittleEndian(spanBytes.Slice(16, 8), TypeCodeData);\n\n            const int offset = sizeof(ulong) * 3;\n            // Copy KeyExt\n            if (extBytes != null)\n            {\n                BinaryPrimitives.WriteInt32LittleEndian(spanBytes.Slice(offset, sizeof(int)), extBytesLength);\n                extBytes.CopyTo(spanBytes[(offset + sizeof(int))..]);\n            }\n            else\n            {\n                BinaryPrimitives.WriteInt32LittleEndian(spanBytes.Slice(offset, sizeof(int)), -1);\n            }\n\n            return spanBytes;\n        }\n\n        private unsafe Guid Guid\n        {\n            get\n            {\n                if (BitConverter.IsLittleEndian && sizeof(Guid) == 2 * sizeof(ulong))\n                {\n                    Guid value;\n                    ((ulong*)&value)[0] = N0;\n                    ((ulong*)&value)[1] = N1;\n                    return value;\n                }\n                return new Guid((uint)N0, (ushort)(N0 >> 32), (ushort)(N0 >> 48), (byte)N1, (byte)(N1 >> 8), (byte)(N1 >> 16), (byte)(N1 >> 24), (byte)(N1 >> 32), (byte)(N1 >> 40), (byte)(N1 >> 48), (byte)(N1 >> 56));\n            }\n            set\n            {\n                if (BitConverter.IsLittleEndian && sizeof(Guid) == 2 * sizeof(ulong))\n                {\n                    N0 = ((ulong*)&value)[0];\n                    N1 = ((ulong*)&value)[1];\n                }\n                else\n                {\n                    var guid = value.ToByteArray().AsSpan();\n                    N0 = BinaryPrimitives.ReadUInt64LittleEndian(guid);\n                    N1 = BinaryPrimitives.ReadUInt64LittleEndian(guid[8..]);\n                }\n            }\n        }\n\n        public override string ToString()\n        {\n            return ToHexString();\n        }\n\n        internal string ToHexString()\n        {\n            const string format = \"{0:x16}{1:x16}{2:x16}\";\n            return KeyExt is null ? string.Format(format, N0, N1, TypeCodeData)\n                : string.Format(format + \"+{3}\", N0, N1, TypeCodeData, KeyExt);\n        }\n\n        internal string ToGrainKeyString()\n        {\n            string keyString;\n            if (HasKeyExt)\n            {\n                string? extension;\n                keyString = IsLongKey ? PrimaryKeyToLong(out extension).ToString() : PrimaryKeyToGuid(out extension).ToString();\n                keyString = $\"{keyString}+{extension ?? string.Empty}\";\n            }\n            else\n            {\n                keyString = this.IsLongKey ? PrimaryKeyToLong().ToString() : this.PrimaryKeyToGuid().ToString();\n            }\n            return keyString;\n        }\n\n        internal static Category GetCategory(ulong typeCodeData)\n        {\n            return (Category)((typeCodeData >> 56) & 0xFF);\n        }\n\n        private static ulong GetTypeCodeData(Category category, long typeData = 0) => ((ulong)category << 56) + ((ulong)typeData & 0x00FFFFFFFFFFFFFF);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/ObserverGrainId.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies a client-side observer object.\n    /// </summary>\n    internal readonly struct ObserverGrainId : IEquatable<ObserverGrainId>, IComparable<ObserverGrainId>, ISpanFormattable\n    {\n        /// <summary>\n        /// The separator between the client id portion of the observer id and the client-scoped observer id portion.\n        /// </summary>\n        internal const char SegmentSeparator = '+';\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ObserverGrainId\"/> struct.\n        /// </summary>\n        private ObserverGrainId(GrainId grainId)\n        {\n            this.GrainId = grainId;\n        }\n\n        /// <summary>\n        /// Gets the underlying <see cref=\"GrainId\"/>.\n        /// </summary>\n        public readonly GrainId GrainId;\n\n        /// <summary>\n        /// Returns a new, random <see cref=\"ObserverGrainId\"/> instance for the provided client id.\n        /// </summary>\n        /// <param name=\"clientId\">\n        /// The client id.\n        /// </param>\n        /// <returns>\n        /// A new, random <see cref=\"ObserverGrainId\"/> instance for the provided client id.\n        /// </returns>\n        public static ObserverGrainId Create(ClientGrainId clientId) => Create(clientId, GrainIdKeyExtensions.CreateGuidKey(Guid.NewGuid()));\n\n        /// <summary>\n        /// Returns a new <see cref=\"ObserverGrainId\"/> instance for the provided client id.\n        /// </summary>\n        /// <param name=\"clientId\">\n        /// The client id.\n        /// </param>\n        /// <param name=\"scopedId\">\n        /// The client-scoped observer id.\n        /// </param>\n        /// <returns>\n        /// A new <see cref=\"ObserverGrainId\"/> instance for the provided client id.\n        /// </returns>\n        public static ObserverGrainId Create(ClientGrainId clientId, IdSpan scopedId) => new ObserverGrainId(ConstructGrainId(clientId, scopedId));\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided instance represents an observer, <see langword=\"false\"/> if otherwise.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the provided grain id is an observer id, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        public static bool IsObserverGrainId(GrainId grainId) => grainId.IsClient() && grainId.Key.AsSpan().IndexOf((byte)SegmentSeparator) >= 0;\n\n        /// <summary>\n        /// Converts the provided <see cref=\"GrainId\"/> to a <see cref=\"ObserverGrainId\"/>. A return value indicates whether the operation succeeded.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"observerId\">\n        /// The corresponding observer id.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the provided grain id is an observer id, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        public static bool TryParse(GrainId grainId, out ObserverGrainId observerId)\n        {\n            if (!IsObserverGrainId(grainId))\n            {\n                observerId = default;\n                return false;\n            }\n\n            observerId = new ObserverGrainId(grainId);\n            return true;\n        }\n\n        private static GrainId ConstructGrainId(ClientGrainId clientId, IdSpan scopedId)\n        {\n            var grain = clientId.GrainId.Key.AsSpan();\n            var scope = scopedId.AsSpan();\n\n            var buf = new byte[grain.Length + 1 + scope.Length];\n            grain.CopyTo(buf);\n            buf[grain.Length] = (byte)SegmentSeparator;\n            scope.CopyTo(buf.AsSpan(grain.Length + 1));\n\n            return GrainId.Create(clientId.GrainId.Type, new IdSpan(buf));\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(ObserverGrainId other) => this.GrainId.Equals(other.GrainId);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is ObserverGrainId observer && this.Equals(observer);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.GrainId.GetHashCode();\n\n        /// <inheritdoc/>\n        public override string ToString() => this.GrainId.ToString();\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => ((ISpanFormattable)GrainId).TryFormat(destination, out charsWritten, format, provider);\n\n        /// <inheritdoc/>\n        public int CompareTo(ObserverGrainId other) => this.GrainId.CompareTo(other.GrainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/SiloAddress.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Data class encapsulating the details of silo addresses.\n    /// </summary>\n    [Serializable, Immutable]\n    [JsonConverter(typeof(SiloAddressConverter))]\n    [DebuggerDisplay(\"SiloAddress {ToString()}\")]\n    [SuppressReferenceTracking]\n    public sealed class SiloAddress : IEquatable<SiloAddress>, IComparable<SiloAddress>, ISpanFormattable\n    {\n        [NonSerialized]\n        private int hashCode;\n\n        [NonSerialized]\n        private bool hashCodeSet;\n\n        [NonSerialized]\n        private uint[]? uniformHashCache;\n\n        /// <summary>\n        /// Gets the endpoint.\n        /// </summary>\n        [Id(0)]\n        public IPEndPoint Endpoint { get; }\n\n        /// <summary>\n        /// Gets the generation.\n        /// </summary>\n        [Id(1)]\n        public int Generation { get; }\n\n        [NonSerialized]\n        private byte[]? utf8;\n\n        private const char SEPARATOR = '@';\n\n        private static readonly object LastGenerationLock = new();\n        private static long LastGeneration = 0;\n        private static readonly long epoch = new DateTime(2022, 1, 1).Ticks;\n\n        private static readonly Interner<(IPAddress Address, int Port, int Generation), SiloAddress> siloAddressInterningCache = new(InternerConstants.SIZE_MEDIUM);\n\n        /// <summary>Gets the special constant value which indicate an empty <see cref=\"SiloAddress\"/>.</summary>\n        public static SiloAddress Zero { get; } = New(new IPAddress(0), 0, 0);\n\n        /// <summary>\n        /// Factory for creating new SiloAddresses with specified IP endpoint address and silo generation number.\n        /// </summary>\n        /// <param name=\"ep\">IP endpoint address of the silo.</param>\n        /// <param name=\"gen\">Generation number of the silo.</param>\n        /// <returns>SiloAddress object initialized with specified address and silo generation.</returns>\n        public static SiloAddress New(IPEndPoint ep, int gen)\n        {\n            return siloAddressInterningCache.FindOrCreate((ep.Address, ep.Port, gen),\n                // Normalize endpoints\n                (k, ep) => k.Address.IsIPv4MappedToIPv6 ? New(k.Address.MapToIPv4(), k.Port, k.Generation) : new(ep, k.Generation), ep);\n        }\n\n        /// <summary>\n        /// Factory for creating new SiloAddresses with specified IP endpoint address and silo generation number.\n        /// </summary>\n        /// <param name=\"address\">IP address of the silo.</param>\n        /// <param name=\"port\">Port number</param>\n        /// <param name=\"generation\">Generation number of the silo.</param>\n        /// <returns>SiloAddress object initialized with specified address and silo generation.</returns>\n        public static SiloAddress New(IPAddress address, int port, int generation)\n        {\n            return siloAddressInterningCache.FindOrCreate((address, port, generation),\n                // Normalize endpoints\n                k => k.Address.IsIPv4MappedToIPv6 ? New(k.Address.MapToIPv4(), k.Port, k.Generation) : new(new(k.Address, k.Port), k.Generation));\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloAddress\"/> class.\n        /// </summary>\n        /// <param name=\"endpoint\">The endpoint.</param>\n        /// <param name=\"generation\">The generation.</param>\n        private SiloAddress(IPEndPoint endpoint, int generation)\n        {\n            Endpoint = endpoint;\n            Generation = generation;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance represents a client (versus a server).\n        /// </summary>\n        public bool IsClient { get { return Generation < 0; } }\n\n        /// <summary> Allocate a new silo generation number. </summary>\n        /// <returns>A new silo generation number.</returns>\n        public static int AllocateNewGeneration()\n        {\n            long elapsed = (DateTime.UtcNow.Ticks - epoch) / TimeSpan.TicksPerSecond;\n\n            // For tests which restart silos within 1 second, we need to ensure that the generation number is always increasing,\n            // since generation for a restarting silo must be unique.\n            lock (LastGenerationLock)\n            {\n                LastGeneration = elapsed = Math.Max(elapsed, LastGeneration + 1);\n            }\n            \n            return unchecked((int)elapsed); // Unchecked to truncate any bits beyond the lower 32\n        }\n\n        /// <summary>\n        /// Return this SiloAddress in a standard string form, suitable for later use with the <c>FromParsableString</c> method.\n        /// </summary>\n        /// <returns>SiloAddress in a standard string format.</returns>\n        public string ToParsableString()\n        {\n            // This must be the \"inverse\" of FromParsableString, and must be the same across all silos in a deployment.\n            // Basically, this should never change unless the data content of SiloAddress changes\n            if (utf8 != null) return Encoding.UTF8.GetString(utf8);\n            return $\"{new SpanFormattableIPAddress(Endpoint.Address)}:{Endpoint.Port}@{Generation}\";\n        }\n\n        /// <summary>\n        /// Returns a UTF8-encoded representation of this instance as a byte array.\n        /// </summary>\n        /// <returns>A UTF8-encoded representation of this instance as a byte array.</returns>\n        internal byte[] ToUtf8String()\n        {\n            if (utf8 is null)\n            {\n                Span<char> chars = stackalloc char[45];\n                var addr = Endpoint.Address.TryFormat(chars, out var len) ? chars[..len] : Endpoint.Address.ToString().AsSpan();\n                var size = Encoding.UTF8.GetByteCount(addr);\n\n                // Allocate sufficient room for: address + ':' + port + '@' + generation\n                Span<byte> buf = stackalloc byte[size + 1 + 11 + 1 + 11];\n                size = Encoding.UTF8.GetBytes(addr, buf);\n\n                buf[size++] = (byte)':';\n                var success = Utf8Formatter.TryFormat(Endpoint.Port, buf[size..], out len);\n                Debug.Assert(success);\n                Debug.Assert(len > 0);\n                Debug.Assert(len <= 11);\n                size += len;\n\n                buf[size++] = (byte)SEPARATOR;\n                success = Utf8Formatter.TryFormat(Generation, buf[size..], out len);\n                Debug.Assert(success);\n                Debug.Assert(len > 0);\n                Debug.Assert(len <= 11);\n                size += len;\n\n                utf8 = buf[..size].ToArray();\n            }\n\n            return utf8;\n        }\n\n        /// <summary>\n        /// Create a new SiloAddress object by parsing string in a standard form returned from <c>ToParsableString</c> method.\n        /// </summary>\n        /// <param name=\"addr\">String containing the SiloAddress info to be parsed.</param>\n        /// <returns>New SiloAddress object created from the input data.</returns>\n        public static SiloAddress FromParsableString(string addr)\n        {\n            // This must be the \"inverse\" of ToParsableString, and must be the same across all silos in a deployment.\n            // Basically, this should never change unless the data content of SiloAddress changes\n\n            // First is the IPEndpoint; then '@'; then the generation\n            int atSign = addr.LastIndexOf(SEPARATOR);\n            // IPEndpoint is the host, then ':', then the port\n            int lastColon = addr.LastIndexOf(':', atSign - 1);\n            if (atSign < 0 || lastColon < 0) throw new FormatException(\"Invalid string SiloAddress: \" + addr);\n\n            var host = IPAddress.Parse(addr.AsSpan(0, lastColon));\n            int port = int.Parse(addr.AsSpan(lastColon + 1, atSign - lastColon - 1), NumberStyles.None);\n            var gen = int.Parse(addr.AsSpan(atSign + 1), NumberStyles.None);\n            return New(host, port, gen);\n        }\n\n        /// <summary>\n        /// Create a new SiloAddress object by parsing string in a standard form returned from <c>ToParsableString</c> method.\n        /// </summary>\n        /// <param name=\"addr\">String containing the SiloAddress info to be parsed.</param>\n        /// <returns>New SiloAddress object created from the input data.</returns>\n        public static SiloAddress FromUtf8String(ReadOnlySpan<byte> addr)\n        {\n            // This must be the \"inverse\" of ToParsableString, and must be the same across all silos in a deployment.\n            // Basically, this should never change unless the data content of SiloAddress changes\n\n            // First is the IPEndpoint; then '@'; then the generation\n            var atSign = addr.LastIndexOf((byte)SEPARATOR);\n            if (atSign < 0) ThrowInvalidUtf8SiloAddress(addr);\n\n            // IPEndpoint is the host, then ':', then the port\n            var endpointSlice = addr[..atSign];\n            int lastColon = endpointSlice.LastIndexOf((byte)':');\n            if (lastColon < 0) ThrowInvalidUtf8SiloAddress(addr);\n\n            var ipSlice = endpointSlice[..lastColon];\n            Span<char> buf = stackalloc char[45];\n            var hostString = Encoding.UTF8.GetCharCount(ipSlice) is int len && len <= buf.Length\n                ? buf[..Encoding.UTF8.GetChars(ipSlice, buf)]\n                : Encoding.UTF8.GetString(ipSlice).AsSpan();\n            if (!IPAddress.TryParse(hostString, out var host))\n                ThrowInvalidUtf8SiloAddress(addr);\n\n            var portSlice = endpointSlice[(lastColon + 1)..];\n            if (!Utf8Parser.TryParse(portSlice, out int port, out len) || len < portSlice.Length)\n                ThrowInvalidUtf8SiloAddress(addr);\n\n            var genSlice = addr[(atSign + 1)..];\n            if (!Utf8Parser.TryParse(genSlice, out int generation, out len) || len < genSlice.Length)\n                ThrowInvalidUtf8SiloAddress(addr);\n\n            return New(host, port, generation);\n        }\n\n        [DoesNotReturn]\n        private static void ThrowInvalidUtf8SiloAddress(ReadOnlySpan<byte> addr)\n            => throw new FormatException(\"Invalid string SiloAddress: \" + Encoding.UTF8.GetString(addr));\n\n        /// <summary>\n        /// Return a long string representation of this SiloAddress.\n        /// </summary>\n        /// <remarks>\n        /// Note: This string value is not comparable with the <see cref=\"FromParsableString\"/> method -- use the <see cref=\"ToParsableString\"/> method for that purpose.\n        /// </remarks>\n        /// <returns>String representation of this SiloAddress.</returns>\n        public override string ToString() => $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            if (!destination.TryWrite($\"{(IsClient ? 'C' : 'S')}{new SpanFormattableIPEndPoint(Endpoint)}:{Generation}\", out charsWritten))\n                return false;\n\n            if (format.Length == 1 && format[0] == 'H')\n            {\n                if (!destination[charsWritten..].TryWrite($\"/x{GetConsistentHashCode():X8}\", out var len))\n                    return false;\n\n                charsWritten += len;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Return a long string representation of this SiloAddress, including it's consistent hash value.\n        /// </summary>\n        /// <remarks>\n        /// Note: This string value is not comparable with the <c>FromParsableString</c> method -- use the <c>ToParsableString</c> method for that purpose.\n        /// </remarks>\n        /// <returns>String representation of this SiloAddress.</returns>\n        public string ToStringWithHashCode() => $\"{this:H}\";\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => Equals(obj as SiloAddress);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Endpoint.GetHashCode() ^ Generation;\n\n        /// <summary>Returns a consistent hash value for this silo address.</summary>\n        /// <returns>Consistent hash value for this silo address.</returns>\n        public int GetConsistentHashCode() => hashCodeSet ? hashCode : CalculateConsistentHashCode();\n\n        /// <summary>Returns a consistent hash value for this silo address.</summary>\n        /// <returns>Consistent hash value for this silo address.</returns>\n        internal int GetConsistentHashCode(int seed)\n        {\n            var tmp = (0, 0L, 0L, 0L); // avoid stackalloc overhead by using a fixed size buffer\n            var buf = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref tmp, 1))[..28];\n\n            Endpoint.Address.TryWriteBytes(buf, out var len);\n            Debug.Assert(len is 4 or 16);\n\n            BinaryPrimitives.WriteInt32LittleEndian(buf[16..], Endpoint.Port);\n            BinaryPrimitives.WriteInt32LittleEndian(buf[20..], Generation);\n            BinaryPrimitives.WriteInt32LittleEndian(buf[24..], seed);\n\n            return (int)StableHash.ComputeHash(buf);\n        }\n\n        private int CalculateConsistentHashCode()\n        {\n            var tmp = (0L, 0L, 0L); // avoid stackalloc overhead by using a fixed size buffer\n            var buf = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref tmp, 1))[..24];\n\n            Endpoint.Address.TryWriteBytes(buf, out var len);\n            Debug.Assert(len is 4 or 16);\n\n            BinaryPrimitives.WriteInt32LittleEndian(buf[16..], Endpoint.Port);\n            BinaryPrimitives.WriteInt32LittleEndian(buf[20..], Generation);\n\n            hashCode = (int)StableHash.ComputeHash(buf);\n            hashCodeSet = true;\n            return hashCode;\n        }\n\n        internal void InternalSetConsistentHashCode(int hashCode)\n        {\n            this.hashCode = hashCode;\n            this.hashCodeSet = true;\n        }\n\n        /// <summary>\n        /// Returns a collection of uniform hash codes variants for this instance.\n        /// </summary>\n        /// <param name=\"numHashes\">The number of hash codes to return.</param>\n        /// <returns>A collection of uniform hash codes variants for this instance.</returns>\n        public uint[] GetUniformHashCodes(int numHashes)\n        {\n            var cache = uniformHashCache;\n            if (cache is not null && cache.Length == numHashes) return cache;\n            return uniformHashCache = GetUniformHashCodesImpl(numHashes);\n        }\n\n        private uint[] GetUniformHashCodesImpl(int numHashes)\n        {\n            Span<byte> bytes = stackalloc byte[16 + sizeof(int) + sizeof(int) + sizeof(int)]; // ip + port + generation + extraBit\n\n            // Endpoint IP Address\n            var address = Endpoint.Address;\n            if (address.AddressFamily == AddressFamily.InterNetwork) // IPv4\n            {\n#pragma warning disable CS0618 // Type or member is obsolete\n                BinaryPrimitives.WriteInt32LittleEndian(bytes[12..], (int)address.Address);\n#pragma warning restore CS0618\n                bytes[..12].Clear();\n            }\n            else // IPv6\n            {\n                address.TryWriteBytes(bytes, out var len);\n                Debug.Assert(len == 16);\n            }\n            var offset = 16;\n            // Port\n            BinaryPrimitives.WriteInt32LittleEndian(bytes[offset..], Endpoint.Port);\n            offset += sizeof(int);\n            // Generation\n            BinaryPrimitives.WriteInt32LittleEndian(bytes[offset..], Generation);\n            offset += sizeof(int);\n\n            var hashes = new uint[numHashes];\n            for (int extraBit = 0; extraBit < numHashes; extraBit++)\n            {\n                BinaryPrimitives.WriteInt32LittleEndian(bytes[offset..], extraBit);\n                hashes[extraBit] = StableHash.ComputeHash(bytes);\n            }\n\n            return hashes;\n        }\n\n        /// <summary>\n        /// Two silo addresses match if they are equal or if one generation or the other is 0.\n        /// </summary>\n        /// <param name=\"other\"> The other SiloAddress to compare this one with. </param>\n        /// <returns>Returns <c>true</c> if the two SiloAddresses are considered to match -- if they are equal or if one generation or the other is 0. </returns>\n        internal bool Matches([NotNullWhen(true)] SiloAddress? other)\n        {\n            return other != null && Endpoint.Address.Equals(other.Endpoint.Address) && Endpoint.Port == other.Endpoint.Port &&\n                (Generation == other.Generation || Generation == 0 || other.Generation == 0);\n        }\n\n        /// <inheritdoc/>\n        public bool Equals([NotNullWhen(true)] SiloAddress? other)\n            => other != null && Generation == other.Generation && Endpoint.Address.Equals(other.Endpoint.Address) && Endpoint.Port == other.Endpoint.Port;\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided value represents the same logical server as this value, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"other\">\n        /// The other instance.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the provided value represents the same logical server as this value, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        internal bool IsSameLogicalSilo([NotNullWhen(true)] SiloAddress? other)\n            => other != null && Endpoint.Address.Equals(other.Endpoint.Address) && Endpoint.Port == other.Endpoint.Port;\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided value represents the same logical server as this value and is a successor to this server, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"other\">\n        /// The other instance.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the provided value represents the same logical server as this value and is a successor to this server, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        public bool IsSuccessorOf(SiloAddress other) => IsSameLogicalSilo(other) && other.Generation > 0 && Generation > other.Generation;\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided value represents the same logical server as this value and is a predecessor to this server, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"other\">\n        /// The other instance.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the provided value represents the same logical server as this value and is a predecessor to this server, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        public bool IsPredecessorOf(SiloAddress other) => IsSameLogicalSilo(other) && Generation > 0 && Generation < other.Generation;\n\n        /// <inheritdoc/>\n        public int CompareTo(SiloAddress? other)\n        {\n            if (other == null) return 1;\n            // Compare Generation first. It gives a cheap and fast way to compare, avoiding allocations \n            // and is also semantically meaningful - older silos (with smaller Generation) will appear first in the comparison order.\n            // Only if Generations are the same, go on to compare Ports and IPAddress (which is more expansive to compare).\n            // Alternatively, we could compare ConsistentHashCode or UniformHashCode.\n            int comp = Generation.CompareTo(other.Generation);\n            if (comp != 0) return comp;\n\n            comp = Endpoint.Port.CompareTo(other.Endpoint.Port);\n            if (comp != 0) return comp;\n\n            return CompareIpAddresses(Endpoint.Address, other.Endpoint.Address);\n        }\n\n        // The comparison code is taken from: http://www.codeproject.com/Articles/26550/Extending-the-IPAddress-object-to-allow-relative-c\n        // Also note that this comparison does not handle semantic equivalence  of IPv4 and IPv6 addresses.\n        // In particular, 127.0.0.1 and::1 are semantically the same, but not syntactically.\n        // For more information refer to: http://stackoverflow.com/questions/16618810/compare-ipv4-addresses-in-ipv6-notation \n        // and http://stackoverflow.com/questions/22187690/ip-address-class-getaddressbytes-method-putting-octets-in-odd-indices-of-the-byt\n        // and dual stack sockets, described at https://msdn.microsoft.com/en-us/library/system.net.ipaddress.maptoipv6(v=vs.110).aspx\n        private static int CompareIpAddresses(IPAddress one, IPAddress two)\n        {\n            var f1 = one.AddressFamily;\n            var f2 = two.AddressFamily;\n            if (f1 != f2)\n                return f1 < f2 ? -1 : 1;\n\n            if (f1 == AddressFamily.InterNetwork)\n            {\n#pragma warning disable CS0618 // Type or member is obsolete\n                return one.Address.CompareTo(two.Address);\n#pragma warning restore CS0618\n            }\n\n            Span<byte> b1 = stackalloc byte[16];\n            one.TryWriteBytes(b1, out var len);\n            Debug.Assert(len == 16);\n\n            Span<byte> b2 = stackalloc byte[16];\n            two.TryWriteBytes(b2, out len);\n            Debug.Assert(len == 16);\n\n            return b1.SequenceCompareTo(b2);\n        }\n    }\n\n    /// <summary>\n    /// Functionality for converting <see cref=\"SiloAddress\"/> instances to and from their JSON representation.\n    /// </summary>\n    public sealed class SiloAddressConverter : JsonConverter<SiloAddress>\n    {\n        /// <inheritdoc />\n        public override SiloAddress? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetString() is { } str ? SiloAddress.FromParsableString(str) : null;\n\n        /// <inheritdoc />\n        public override void Write(Utf8JsonWriter writer, SiloAddress value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToUtf8String());\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/SiloAddressCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Runtime.Serialization\n{\n    /// <summary>\n    /// Serializer and deserializer for <see cref=\"SiloAddress\"/> instances.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class SiloAddressCodec : IFieldCodec<SiloAddress>\n    {\n        /// <inheritdoc />\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, SiloAddress? value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, typeof(SiloAddress));\n            IPAddressCodec.WriteField(ref writer, 0, value.Endpoint.Address);\n            uint delta = 2;\n            if (value.Endpoint.Port != 0) UInt16Codec.WriteField(ref writer, delta = 1, (ushort)value.Endpoint.Port);\n            if (value.Generation != 0) Int32Codec.WriteField(ref writer, delta, value.Generation);\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public SiloAddress ReadValue<TReaderInput>(ref Reader<TReaderInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<SiloAddress, TReaderInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Field header = default;\n            int port = 0, generation = 0;\n\n            reader.ReadFieldHeader(ref header);\n            if (!header.HasFieldId || header.FieldIdDelta != 0) throw new RequiredFieldMissingException(\"Serialized SiloAddress is missing its address field.\");\n            var address = IPAddressCodec.ReadValue(ref reader, header);\n\n            reader.ReadFieldHeader(ref header);\n            if (!header.IsEndBaseOrEndObject)\n            {\n                var id = header.FieldIdDelta;\n                if (id == 1)\n                {\n                    port = UInt16Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.HasFieldId) id += header.FieldIdDelta;\n                }\n\n                if (id == 2)\n                {\n                    generation = Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n            }\n\n            return SiloAddress.New(address, port, generation);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/StableHash.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.IO.Hashing;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Orleans\n{\n    public static class StableHash\n    {\n        /// <summary>\n        /// Computes a hash digest of the input.\n        /// </summary>\n        /// <param name=\"data\">\n        /// The input data.\n        /// </param>\n        /// <returns>\n        /// A hash digest of the input.\n        /// </returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static unsafe uint ComputeHash(ReadOnlySpan<byte> data)\n        {\n            uint hash;\n            XxHash32.TryHash(data, new Span<byte>((byte*)&hash, sizeof(uint)), out _);\n            return BitConverter.IsLittleEndian ? hash : BinaryPrimitives.ReverseEndianness(hash);\n        }\n\n        /// <summary>\n        /// Computes a hash digest of the input.\n        /// </summary>\n        /// <param name=\"data\">\n        /// The input data.\n        /// </param>\n        /// <returns>\n        /// A hash digest of the input.\n        /// </returns>\n        public static uint ComputeHash(string data) => ComputeHash(BitConverter.IsLittleEndian ? MemoryMarshal.AsBytes(data.AsSpan()) : Encoding.Unicode.GetBytes(data));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/IDs/SystemTargetGrainId.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies a system target.\n    /// </summary>\n    [Immutable]\n    public readonly struct SystemTargetGrainId : IEquatable<SystemTargetGrainId>, IComparable<SystemTargetGrainId>, ISpanFormattable\n    {\n        private const char SegmentSeparator = '+';\n        private readonly GrainId _grainId;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SystemTargetGrainId\"/> struct.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        private SystemTargetGrainId(GrainId grainId) => _grainId = grainId;\n\n        /// <summary>\n        /// Gets the underlying identity.\n        /// </summary>\n        public GrainId GrainId => _grainId;\n\n        /// <summary>\n        /// Creates a new <see cref=\"SystemTargetGrainId\"/> instance.\n        /// </summary>\n        /// <param name=\"kind\">\n        /// The grain type.\n        /// </param>\n        /// <param name=\"address\">\n        /// The server which the system target exists on.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"SystemTargetGrainId\"/>.\n        /// </returns>\n        public static SystemTargetGrainId Create(GrainType kind, SiloAddress address) => new SystemTargetGrainId(new GrainId(kind, new IdSpan(address.ToUtf8String())));\n\n        /// <summary>\n        /// Creates a new <see cref=\"SystemTargetGrainId\"/> instance.\n        /// </summary>\n        /// <param name=\"kind\">\n        /// The grain type.\n        /// </param>\n        /// <param name=\"address\">\n        /// The server which the system target exists on.\n        /// </param>\n        /// <param name=\"extraIdentifier\">\n        /// An optional key extension.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"SystemTargetGrainId\"/>.\n        /// </returns>\n        public static SystemTargetGrainId Create(GrainType kind, SiloAddress address, string? extraIdentifier)\n        {\n            var addr = address.ToUtf8String();\n            if (extraIdentifier is not null)\n            {\n                var extraLen = Encoding.UTF8.GetByteCount(extraIdentifier);\n                var buf = new byte[addr.Length + 1 + extraLen];\n                addr.CopyTo(buf.AsSpan());\n                buf[addr.Length] = (byte)SegmentSeparator;\n                Encoding.UTF8.GetBytes(extraIdentifier, 0, extraIdentifier.Length, buf, addr.Length + 1);\n                addr = buf;\n            }\n\n            return new SystemTargetGrainId(new GrainId(kind, new IdSpan(addr)));\n        }\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided instance represents a system target, <see langword=\"false\"/> if otherwise.\n        /// </summary>\n        /// <param name=\"id\">\n        /// The grain id.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the value is a system target grain id, <see langword=\"false\"/> otherwise.\n        /// </returns>\n        public static bool IsSystemTargetGrainId(in GrainId id) => id.Type.AsSpan().StartsWith(GrainTypePrefix.SystemTargetPrefixBytes.Span);\n\n        /// <summary>\n        /// Converts the provided <see cref=\"GrainId\"/> to a <see cref=\"SystemTargetGrainId\"/>. A return value indicates whether the operation succeeded.\n        /// </summary>\n        /// <param name=\"grainId\">\n        /// The grain id.\n        /// </param>\n        /// <param name=\"systemTargetId\">\n        /// The resulting system target id.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the value is a system target grain id, <see langword=\"false\"/> otherwise.\n        /// </returns>\n        public static bool TryParse(GrainId grainId, out SystemTargetGrainId systemTargetId)\n        {\n            if (!IsSystemTargetGrainId(grainId))\n            {\n                systemTargetId = default;\n                return false;\n            }\n\n            systemTargetId = new SystemTargetGrainId(grainId);\n            return true;\n        }\n\n        /// <summary>\n        /// Returns a new <see cref=\"SystemTargetGrainId\"/> targeting the provided address.\n        /// </summary>\n        /// <param name=\"siloAddress\">\n        /// The silo address.\n        /// </param>\n        /// <returns>\n        /// A new <see cref=\"SystemTargetGrainId\"/> targeting the provided address.\n        /// </returns>\n        public SystemTargetGrainId WithSiloAddress(SiloAddress siloAddress)\n        {\n            var addr = siloAddress.ToUtf8String();\n            var key = _grainId.Key.AsSpan();\n            if (key.IndexOf((byte)SegmentSeparator) is int index && index >= 0)\n            {\n                var extraIdentifier = key[(index + 1)..];\n\n                var buf = new byte[addr.Length + 1 + extraIdentifier.Length];\n                addr.CopyTo(buf.AsSpan());\n                buf[addr.Length] = (byte)SegmentSeparator;\n                extraIdentifier.CopyTo(buf.AsSpan(addr.Length + 1));\n                addr = buf;\n            }\n\n            return new SystemTargetGrainId(new GrainId(_grainId.Type, new IdSpan(addr)));\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"SiloAddress\"/> of the system target.\n        /// </summary>\n        /// <returns>\n        /// The silo address corresponding to this system target id.\n        /// </returns>\n        public SiloAddress GetSiloAddress()\n        {\n            var key = _grainId.Key.AsSpan();\n            if (key.IndexOf((byte)SegmentSeparator) is int index && index >= 0)\n            {\n                key = key[..index];\n            }\n\n            return SiloAddress.FromUtf8String(key);\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainId\"/> for a grain service.\n        /// </summary>\n        /// <param name=\"typeCode\">\n        /// The type code.\n        /// </param>\n        /// <param name=\"grainSystemId\">\n        /// The system id.\n        /// </param>\n        /// <param name=\"address\">\n        /// The silo address.\n        /// </param>\n        /// <returns>A grain id for a grain service instance.</returns>\n        public static GrainId CreateGrainServiceGrainId(int typeCode, string grainSystemId, SiloAddress address)\n            => CreateGrainServiceGrainId(CreateGrainServiceGrainType(typeCode, grainSystemId), address);\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainId\"/> for a grain service.\n        /// </summary>\n        /// <param name=\"typeCode\">\n        /// The type code.\n        /// </param>\n        /// <param name=\"grainSystemId\">\n        /// The system id.\n        /// </param>\n        /// <returns>A grain id for a grain service instance.</returns>\n        internal static GrainType CreateGrainServiceGrainType(int typeCode, string? grainSystemId)\n        {\n            var extraLen = grainSystemId is null ? 0 : Encoding.UTF8.GetByteCount(grainSystemId);\n            var buf = new byte[GrainTypePrefix.GrainServicePrefix.Length + 8 + extraLen];\n            GrainTypePrefix.GrainServicePrefixBytes.Span.CopyTo(buf);\n            Utf8Formatter.TryFormat(typeCode, buf.AsSpan(GrainTypePrefix.GrainServicePrefix.Length), out var len, new StandardFormat('X', 8));\n            Debug.Assert(len == 8);\n            if (grainSystemId != null) Encoding.UTF8.GetBytes(grainSystemId, 0, grainSystemId.Length, buf, buf.Length - extraLen);\n            return new GrainType(buf);\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"GrainId\"/> for a grain service.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        /// <param name=\"address\">\n        /// The silo address.\n        /// </param>\n        /// <returns>A grain id for a grain service instance.</returns>\n        internal static GrainId CreateGrainServiceGrainId(GrainType grainType, SiloAddress address)\n            => new GrainId(grainType, new IdSpan(address.ToUtf8String()));\n\n        /// <summary>\n        /// Creates a system target <see cref=\"GrainType\"/> with the provided name.\n        /// </summary>\n        /// <param name=\"name\">\n        /// The system target grain type name.\n        /// </param>\n        /// <returns>\n        /// The grain type.\n        /// </returns>\n        public static GrainType CreateGrainType(string name) => GrainType.Create($\"{GrainTypePrefix.SystemTargetPrefix}{name}\");\n\n        /// <inheritdoc/>\n        public bool Equals(SystemTargetGrainId other) => _grainId.Equals(other._grainId);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is SystemTargetGrainId observer && this.Equals(observer);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => _grainId.GetHashCode();\n\n        /// <inheritdoc/>\n        public override string ToString() => _grainId.ToString();\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => ((ISpanFormattable)_grainId).TryFormat(destination, out charsWritten, format, provider);\n\n        /// <inheritdoc/>\n        public int CompareTo(SystemTargetGrainId other) => _grainId.CompareTo(other._grainId);\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(SystemTargetGrainId left, SystemTargetGrainId right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(SystemTargetGrainId left, SystemTargetGrainId right) => !(left == right);\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <(SystemTargetGrainId left, SystemTargetGrainId right) => left.CompareTo(right) < 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <=(SystemTargetGrainId left, SystemTargetGrainId right) => left.CompareTo(right) <= 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >(SystemTargetGrainId left, SystemTargetGrainId right) => left.CompareTo(right) > 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >=(SystemTargetGrainId left, SystemTargetGrainId right) => left.CompareTo(right) >= 0;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/IGrainLifecycle.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The observable grain lifecycle.\n    /// </summary>\n    /// <remarks>\n    /// This type is usually used as the generic parameter in <see cref=\"ILifecycleParticipant{IGrainLifecycle}\"/> as\n    /// a means of participating in the lifecycle stages of a grain activation.\n    /// </remarks>\n    public interface IGrainLifecycle : ILifecycleObservable\n    {\n        /// <summary>\n        /// Registers a grain migration participant.\n        /// </summary>\n        /// <param name=\"participant\">The participant.</param>\n        void AddMigrationParticipant(IGrainMigrationParticipant participant);\n\n        /// <summary>\n        /// Unregisters a grain migration participant.\n        /// </summary>\n        /// <param name=\"participant\">The participant.</param>\n        void RemoveMigrationParticipant(IGrainMigrationParticipant participant);\n    }\n\n    public interface IGrainMigrationParticipant\n    {\n        /// <summary>\n        /// Called on the original activation when migration is initiated, after <see cref=\"IGrainBase.OnDeactivateAsync(DeactivationReason, CancellationToken)\"/> completes.\n        /// The participant can access and update the dehydration context.\n        /// </summary>\n        /// <param name=\"dehydrationContext\">The dehydration context.</param>\n        void OnDehydrate(IDehydrationContext dehydrationContext);\n\n        /// <summary>\n        /// Called on the new activation after a migration, before <see cref=\"IGrainBase.OnActivateAsync(CancellationToken)\"/> is called.\n        /// The participant can restore state from the migration context.\n        /// </summary>\n        /// <param name=\"rehydrationContext\">The rehydration context.</param>\n        void OnRehydrate(IRehydrationContext rehydrationContext);\n    }\n\n    /// <summary>\n    /// Records the state of a grain activation which is in the process of being dehydrated for migration to another location.\n    /// </summary>\n    public interface IDehydrationContext\n    {\n        /// <summary>\n        /// Gets the keys in the context.\n        /// </summary>\n        IEnumerable<string> Keys { get; }\n\n        /// <summary>\n        /// Adds a sequence of bytes to the dehydration context, associating the sequence with the provided key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value.</param>\n        void AddBytes(string key, ReadOnlySpan<byte> value);\n\n        /// <summary>\n        /// Adds a sequence of bytes to the dehydration context, associating the sequence with the provided key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"valueWriter\">A delegate used to write the provided value to the context.</param>\n        /// <param name=\"value\">The value to provide to <paramref name=\"valueWriter\"/>.</param>\n        void AddBytes<T>(string key, Action<T, IBufferWriter<byte>> valueWriter, T value);\n\n        /// <summary>\n        /// Attempts to a value to the dehydration context, associated with the provided key, serializing it using <see cref=\"Orleans.Serialization.Serializer\"/>.\n        /// If a serializer is found for the value, and the key has not already been added, then the value is added and the method returns <see langword=\"true\"/>.\n        /// If no serializer exists or the key has already been added, then the value is not added and the method returns <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value to add.</param>\n        bool TryAddValue<T>(string key, T? value);\n    }\n\n    /// <summary>\n    /// Contains the state of a grain activation which is in the process of being rehydrated after moving from another location.\n    /// </summary>\n    public interface IRehydrationContext\n    {\n        /// <summary>\n        /// Gets the keys in the context.\n        /// </summary>\n        IEnumerable<string> Keys { get; }\n\n        /// <summary>\n        /// Tries to get a sequence of bytes from the rehydration context, associated with the provided key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value, if present.</param>\n        /// <returns><see langword=\"true\"/> if the key exists in the context, otherwise <see langword=\"false\"/>.</returns>\n        bool TryGetBytes(string key, out ReadOnlySequence<byte> value);\n\n        /// <summary>\n        /// Tries to get a value from the rehydration context, associated with the provided key, deserializing it using <see cref=\"Orleans.Serialization.Serializer\"/>.\n        /// If a serializer is found for the value, and the key is present, then the value is deserialized and the method returns <see langword=\"true\"/>.\n        /// If no serializer exists or the key has already been added, then the value is not added and the method returns <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value, if present.</param>\n        /// <returns><see langword=\"true\"/> if the key exists in the context, otherwise <see langword=\"false\"/>.</returns>\n        bool TryGetValue<T>(string key, [NotNullWhen(true)] out T? value);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/ILifecycleObservable.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Observable lifecycle.\n    /// Each stage of the lifecycle is observable. All observers will be notified when the stage is reached when starting, and stopping.\n    /// Stages are started in ascending order, and stopped in descending order.\n    /// </summary>\n    public interface ILifecycleObservable\n    {\n        /// <summary>\n        /// Subscribe for notification when a stage is reached while starting or stopping.\n        /// </summary>\n        /// <param name=\"observerName\">The name of the observer, for reporting purposes.</param>\n        /// <param name=\"stage\">The stage of to subscribe to.</param>\n        /// <param name=\"observer\">The observer.</param>\n        /// <returns>A disposable that can be disposed of to unsubscribe.</returns>\n        IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/ILifecycleObserver.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Lifecycle observer used to handle start and stop notification.\n    /// </summary>\n    public interface ILifecycleObserver\n    {\n        /// <summary>\n        /// Handle start notifications.\n        /// </summary>\n        /// <param name=\"cancellationToken\">\n        /// The cancellation token which indicates that the operation should be aborted promptly when it is canceled.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> which represents the operation.\n        /// </returns>\n        Task OnStart(CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Handle stop notifications.\n        /// </summary>\n        /// <param name=\"cancellationToken\">\n        /// The cancellation token which indicates that the operation should be stopped promptly when it is canceled.\n        /// </param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> which represents the operation.\n        /// </returns>\n        Task OnStop(CancellationToken cancellationToken = default);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/ILifecycleParticipant.cs",
    "content": "\nnamespace Orleans\n{\n    /// <summary>\n    /// Provides hook to take part in lifecycle.\n    /// Also may act as a signal interface indicating that an object can take part in lifecycle.\n    /// </summary>\n    /// <typeparam name=\"TLifecycleObservable\">\n    /// The type of lifecycle being observed.\n    /// </typeparam>\n    public interface ILifecycleParticipant<TLifecycleObservable>\n        where TLifecycleObservable : ILifecycleObservable\n    {\n        /// <summary>\n        /// Adds the provided observer as a participant in the lifecycle.\n        /// </summary>\n        /// <param name=\"lifecycle\">\n        /// The observer.\n        /// </param>\n        void Participate(TLifecycleObservable lifecycle);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/ILifecycleSubject.cs",
    "content": "﻿\nnamespace Orleans\n{\n    /// <summary>\n    /// Both a lifecycle observer and observable lifecycle.\n    /// </summary>\n    public interface ILifecycleSubject : ILifecycleObservable, ILifecycleObserver\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Lifecycle/LifecycleExtensions.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Extensions for working with lifecycle observers.\n    /// </summary>\n    public static class LifecycleExtensions\n    {\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"observerName\">The name of the observer.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"onStart\">The delegate called when starting the specified lifecycle stage.</param>\n        /// <param name=\"onStop\">The delegate to be called when stopping the specified lifecycle stage.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe(this ILifecycleObservable observable, string observerName, int stage, Func<CancellationToken, Task> onStart, Func<CancellationToken, Task>? onStop)\n        {\n            if (observable is null)\n            {\n                throw new ArgumentNullException(nameof(observable));\n            }\n\n            if (onStart is null)\n            {\n                throw new ArgumentNullException(nameof(onStart));\n            }\n\n            if (onStop is null)\n            {\n                return StartupObserver.Create(observable, observerName, stage, onStart);\n            }\n\n            return observable.Subscribe(observerName, stage, new Observer(onStart, onStop));\n        }\n\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"observerName\">The name of the observer.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"onStart\">The delegate called when starting the specified lifecycle stage.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe(this ILifecycleObservable observable, string observerName, int stage, Func<CancellationToken, Task> onStart)\n        {\n            return observable.Subscribe(observerName, stage, onStart, null);\n        }\n\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <typeparam name=\"TObserver\">\n        /// The observer type, used for diagnostics.\n        /// </typeparam>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"observer\">The observer.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, ILifecycleObserver observer)\n        {\n            return observable.Subscribe(GetTypeName(typeof(TObserver)), stage, observer);\n        }\n\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <typeparam name=\"TObserver\">\n        /// The observer type, used for diagnostics.\n        /// </typeparam>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"onStart\">The delegate called when starting the specified lifecycle stage.</param>\n        /// <param name=\"onStop\">Teh delegate to be called when stopping the specified lifecycle stage.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, Func<CancellationToken, Task> onStart, Func<CancellationToken, Task> onStop)\n        {\n            return observable.Subscribe(GetTypeName(typeof(TObserver)), stage, onStart, onStop);\n        }\n\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <typeparam name=\"TObserver\">\n        /// The observer type, used for diagnostics.\n        /// </typeparam>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"onStart\">The delegate called when starting the specified lifecycle stage.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, Func<CancellationToken, Task> onStart)\n        {\n            return observable.Subscribe(GetTypeName(typeof(TObserver)), stage, onStart, null);\n        }\n\n        /// <summary>\n        /// Creates a disposable subscription to the lifecycle.\n        /// </summary>\n        /// <param name=\"observable\">The lifecycle observable.</param>\n        /// <param name=\"stage\">The stage to participate in.</param>\n        /// <param name=\"observer\">The observer.</param>\n        /// <returns>A <see cref=\"IDisposable\"/> instance which can be disposed to unsubscribe the observer from the lifecycle.</returns>\n        public static IDisposable Subscribe(this ILifecycleObservable observable, int stage, ILifecycleObserver observer)\n        {\n            return observable.Subscribe(GetTypeName(observer.GetType()), stage, observer);\n        }\n\n        private class Observer : ILifecycleObserver\n        {\n            private readonly Func<CancellationToken, Task> onStart;\n            private readonly Func<CancellationToken, Task> onStop;\n\n            public Observer(Func<CancellationToken, Task> onStart, Func<CancellationToken, Task> onStop)\n            {\n                this.onStart = onStart;\n                this.onStop = onStop;\n            }\n\n            public Task OnStart(CancellationToken ct) => this.onStart(ct);\n            public Task OnStop(CancellationToken ct) => this.onStop(ct);\n        }\n\n        private sealed class StartupObserver : ILifecycleObserver\n        {\n            private readonly Func<CancellationToken, Task> _onStart;\n            private readonly IDisposable _registration;\n\n            private StartupObserver(ILifecycleObservable observable, string observerName, int stage, Func<CancellationToken, Task> onStart)\n            {\n                _onStart = onStart;\n                _registration = observable.Subscribe(observerName, stage, this);\n            }\n\n            public static IDisposable Create(ILifecycleObservable observable, string observerName, int stage, Func<CancellationToken, Task> onStart)\n            {\n                var observer = new StartupObserver(observable, observerName, stage, onStart);\n                return observer._registration;\n            }\n\n            public Task OnStart(CancellationToken ct)\n            {\n                var task = _onStart(ct);\n                _registration?.Dispose();\n                return task;\n            }\n\n            public Task OnStop(CancellationToken ct) => Task.CompletedTask;\n        }\n\n        private static string GetTypeName(Type type) => type.FullName ?? type.Name;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Logging/ErrorCodes.cs",
    "content": "// ReSharper disable InconsistentNaming\nnamespace Orleans\n{\n    /// <summary>\n    /// The set of error codes used by the Orleans runtime libraries for logging errors.\n    /// </summary>\n    public enum ErrorCode\n    {\n        Runtime = 100000,\n        Runtime_Error_100001 = Runtime + 1,\n        Runtime_Error_100002 = Runtime + 2,\n        Runtime_Error_100003 = Runtime + 3,\n        Runtime_Error_100004 = Runtime + 4,\n        Runtime_Error_100005 = Runtime + 5,\n        Runtime_Error_100006 = Runtime + 6,\n        Runtime_Error_100007 = Runtime + 7,\n        Runtime_Error_100008 = Runtime + 8,\n        Runtime_Error_100009 = Runtime + 9,\n        Runtime_Error_100010 = Runtime + 10,\n        Runtime_Error_100011 = Runtime + 11,\n        Runtime_Error_100012 = Runtime + 12,\n        Runtime_Error_100013 = Runtime + 13,\n        Runtime_Error_100014 = Runtime + 14,\n        Runtime_Error_100015 = Runtime + 15,\n        Runtime_Error_100016 = Runtime + 16,\n        Runtime_Error_100017 = Runtime + 17,\n        Runtime_Error_100018 = Runtime + 18,\n        Runtime_Error_100019 = Runtime + 19,\n        Runtime_Error_100020 = Runtime + 20,\n        Runtime_Error_100021 = Runtime + 21,\n        Runtime_Error_100022 = Runtime + 22,\n        Runtime_Error_100023 = Runtime + 23,\n        Runtime_Error_100024 = Runtime + 24,\n        Runtime_Error_100025 = Runtime + 25,\n        Runtime_Error_100026 = Runtime + 26,\n        Runtime_Error_100027 = Runtime + 27,\n        Runtime_Error_100028 = Runtime + 28,\n        Runtime_Error_100029 = Runtime + 29,\n        Runtime_Error_100030 = Runtime + 30,\n        Runtime_Error_100031 = Runtime + 31,\n        Runtime_Error_100032 = Runtime + 32,\n        Runtime_Error_100033 = Runtime + 33,\n        Runtime_Error_100034 = Runtime + 34,\n        Runtime_Error_100035 = Runtime + 35,\n        Runtime_Error_100036 = Runtime + 36,\n        Runtime_Error_100037 = Runtime + 37,\n        //Runtime_Error_100038 = Runtime + 38,\n        Runtime_Error_100039 = Runtime + 39,\n        Runtime_Error_100040 = Runtime + 40,\n        Runtime_Error_100041 = Runtime + 41,\n        Runtime_Error_100042 = Runtime + 42,\n        Runtime_Error_100043 = Runtime + 43,\n        Runtime_Error_100044 = Runtime + 44,\n        Runtime_Error_100045 = Runtime + 45,\n        Runtime_Error_100046 = Runtime + 46,\n        Runtime_Error_100047 = Runtime + 47,\n        Runtime_Error_100048 = Runtime + 48,\n        Runtime_Error_100049 = Runtime + 49,\n        Runtime_Error_100050 = Runtime + 50,\n        Runtime_Error_100051 = Runtime + 51,\n        Runtime_Error_100052 = Runtime + 52,\n        Runtime_Error_100053 = Runtime + 53,\n        Runtime_Error_100054 = Runtime + 54,\n        Runtime_Error_100055 = Runtime + 55,\n        Runtime_Error_100056 = Runtime + 56,\n        Runtime_Error_100057 = Runtime + 57,\n        Runtime_Error_100058 = Runtime + 58,\n        Runtime_Error_100059 = Runtime + 59,\n        Runtime_Error_100060 = Runtime + 60,\n        Runtime_Error_100061 = Runtime + 61,\n        Runtime_Error_100062 = Runtime + 62,\n        Runtime_Error_100063 = Runtime + 63,\n        Runtime_Error_100064 = Runtime + 64,\n        Runtime_Error_100065 = Runtime + 65,\n        Runtime_Error_100066 = Runtime + 66,\n        Runtime_Error_100067 = Runtime + 67,\n        Runtime_Error_100068 = Runtime + 68,\n        Runtime_Error_100069 = Runtime + 69,\n        Runtime_Error_100070 = Runtime + 70,\n        Runtime_Error_100071 = Runtime + 71,\n        Runtime_Error_100072 = Runtime + 72,\n        Runtime_Error_100073 = Runtime + 73,\n        Runtime_Error_100074 = Runtime + 74,\n        Runtime_Error_100075 = Runtime + 75,\n        Runtime_Error_100076 = Runtime + 76,\n        Runtime_Error_100077 = Runtime + 77,\n        Runtime_Error_100078 = Runtime + 78,\n        Runtime_Error_100079 = Runtime + 79,\n        Runtime_Error_100080 = Runtime + 80,\n        Runtime_Error_100081 = Runtime + 81,\n        Runtime_Error_100082 = Runtime + 82,\n        Runtime_Error_100083 = Runtime + 83,\n        Runtime_Error_100084 = Runtime + 84,\n        Runtime_Error_100085 = Runtime + 85,\n        Runtime_Error_100086 = Runtime + 86,\n        Runtime_Error_100087 = Runtime + 87,\n        Runtime_Error_100088 = Runtime + 88,\n        Runtime_Error_100089 = Runtime + 89,\n        Runtime_Error_100090 = Runtime + 90,\n        Runtime_Error_100091 = Runtime + 91,\n        Runtime_Error_100092 = Runtime + 92,\n        Runtime_Error_100093 = Runtime + 93,\n        Runtime_Error_100094 = Runtime + 94,\n        Runtime_Error_100095 = Runtime + 95,\n        Runtime_Error_100096 = Runtime + 96,\n        Runtime_Error_100097 = Runtime + 97,\n        Runtime_Error_100098 = Runtime + 98,\n        Runtime_Error_100099 = Runtime + 99,\n        Runtime_Error_100100 = Runtime + 100,\n        Runtime_Error_100101 = Runtime + 101,\n        Runtime_Error_100102 = Runtime + 102,\n        Runtime_Error_100103 = Runtime + 103,\n        Runtime_Error_100104 = Runtime + 104,\n        Runtime_Error_100105 = Runtime + 105,\n        Runtime_Error_100106 = Runtime + 106,\n        Runtime_Error_100107 = Runtime + 107,\n        Runtime_Error_100108 = Runtime + 108,\n        Runtime_Error_100109 = Runtime + 109,\n        Runtime_Error_100110 = Runtime + 110,\n        Runtime_Error_100111 = Runtime + 111,\n        Runtime_Error_100112 = Runtime + 112,\n        Runtime_Error_100113 = Runtime + 113,\n        Runtime_Error_100114 = Runtime + 114,\n        Runtime_Error_100115 = Runtime + 115,\n        Runtime_Error_100116 = Runtime + 116,\n        Runtime_Error_100117 = Runtime + 117,\n        Runtime_Error_100118 = Runtime + 118,\n        Runtime_Error_100119 = Runtime + 119,\n        Runtime_Error_100120 = Runtime + 120,\n        Runtime_Error_100121 = Runtime + 121,\n        Runtime_Error_100122 = Runtime + 122,\n        Runtime_Error_100123 = Runtime + 123,\n        Runtime_Error_100124 = Runtime + 124,\n        Runtime_Error_100125 = Runtime + 125,\n        Runtime_Error_100126 = Runtime + 126,\n        Runtime_Error_100127 = Runtime + 127,\n        Runtime_Error_100128 = Runtime + 128,\n        Runtime_Error_100129 = Runtime + 129,\n        Runtime_Error_100130 = Runtime + 130,\n        Runtime_Error_100131 = Runtime + 131,\n        Runtime_Error_100132 = Runtime + 132,\n        Runtime_Error_100133 = Runtime + 133,\n        Runtime_Error_100134 = Runtime + 134,\n        Runtime_Error_100135 = Runtime + 135,\n        Runtime_Error_100136 = Runtime + 136,\n        Runtime_Error_100137 = Runtime + 137,\n        Runtime_Error_100138 = Runtime + 138,\n        Runtime_Error_100139 = Runtime + 139,\n        Runtime_Error_100140 = Runtime + 140,\n        Runtime_Error_100141 = Runtime + 141,\n        Runtime_Error_100142 = Runtime + 142,\n        Runtime_Error_100143 = Runtime + 143,\n        Runtime_Error_100144 = Runtime + 144,\n        Runtime_Error_100145 = Runtime + 145,\n        Runtime_Error_100146 = Runtime + 146,\n        Runtime_Error_100147 = Runtime + 147,\n        Runtime_Error_100148 = Runtime + 148,\n        Runtime_Error_100149 = Runtime + 149,\n        Runtime_Error_100150 = Runtime + 150,\n        Runtime_Error_100151 = Runtime + 151,\n        Runtime_Error_100152 = Runtime + 152,\n        Runtime_Error_100153 = Runtime + 153,\n        Runtime_Error_100154 = Runtime + 154,\n        Runtime_Error_100155 = Runtime + 155,\n        Runtime_Error_100156 = Runtime + 156,\n        Runtime_Error_100157 = Runtime + 157,\n        Runtime_Error_100158 = Runtime + 158,\n        Runtime_Error_100159 = Runtime + 159,\n        Runtime_Error_100160 = Runtime + 160,\n        Runtime_Error_100161 = Runtime + 161,\n        Runtime_Error_100162 = Runtime + 162,\n        Runtime_Error_100163 = Runtime + 163,\n        Runtime_Error_100164 = Runtime + 164,\n        Runtime_Error_100165 = Runtime + 165,\n        Runtime_Error_100166 = Runtime + 166,\n        Runtime_Error_100167 = Runtime + 167,\n        Runtime_Error_100168 = Runtime + 168,\n        Runtime_Error_100169 = Runtime + 169,\n        Runtime_Error_100170 = Runtime + 170,\n        Runtime_Error_100171 = Runtime + 171,\n        Runtime_Error_100172 = Runtime + 172,\n        Runtime_Error_100173 = Runtime + 173,\n        Runtime_Error_100174 = Runtime + 174,\n        Runtime_Error_100175 = Runtime + 175,\n        Runtime_Error_100176 = Runtime + 176,\n        Runtime_Error_100177 = Runtime + 177,\n        Runtime_Error_100178 = Runtime + 178,\n        Runtime_Error_100179 = Runtime + 179,\n        Runtime_Error_100180 = Runtime + 180,\n        Runtime_Error_100181 = Runtime + 181,\n        Runtime_Error_100182 = Runtime + 182,\n        Runtime_Error_100183 = Runtime + 183,\n        Runtime_Error_100184 = Runtime + 184,\n        Runtime_Error_100185 = Runtime + 185,\n        Runtime_Error_100186 = Runtime + 186,\n        Runtime_Error_100187 = Runtime + 187,\n        Runtime_Error_100188 = Runtime + 188,\n        Runtime_Error_100189 = Runtime + 189,\n        Runtime_Error_100190 = Runtime + 190,\n        Runtime_Error_100191 = Runtime + 191,\n        Runtime_Error_100192 = Runtime + 192,\n        Runtime_Error_100193 = Runtime + 193,\n        Runtime_Error_100194 = Runtime + 194,\n        Runtime_Error_100195 = Runtime + 195,\n        Runtime_Error_100196 = Runtime + 196,\n        Runtime_Error_100197 = Runtime + 197,\n        Runtime_Error_100198 = Runtime + 198,\n        Runtime_Error_100199 = Runtime + 199,\n        Runtime_Error_100200 = Runtime + 200,\n        Runtime_Error_100201 = Runtime + 201,\n        Runtime_Error_100202 = Runtime + 202,\n        Runtime_Error_100203 = Runtime + 203,\n        Runtime_Error_100204 = Runtime + 204,\n        Runtime_Error_100205 = Runtime + 205,\n        Runtime_Error_100206 = Runtime + 206,\n        Runtime_Error_100207 = Runtime + 207,\n        Runtime_Error_100208 = Runtime + 208,\n        Runtime_Error_100209 = Runtime + 209,\n        Runtime_Error_100210 = Runtime + 210,\n        Runtime_Error_100211 = Runtime + 211,\n        Runtime_Error_100212 = Runtime + 212,\n        Runtime_Error_100213 = Runtime + 213,\n        Runtime_Error_100214 = Runtime + 214,\n        Runtime_Error_100215 = Runtime + 215,\n        Runtime_Error_100216 = Runtime + 216,\n        Runtime_Error_100217 = Runtime + 217,\n        Runtime_Error_100218 = Runtime + 218,\n        Runtime_Error_100219 = Runtime + 219,\n        Runtime_Error_100220 = Runtime + 220,\n        Runtime_Error_100221 = Runtime + 221,\n        Runtime_Error_100222 = Runtime + 222,\n        Runtime_Error_100223 = Runtime + 223,\n        Runtime_Error_100224 = Runtime + 224,\n        Runtime_Error_100225 = Runtime + 225,\n        Runtime_Error_100226 = Runtime + 226,\n        Runtime_Error_100227 = Runtime + 227,\n        Runtime_Error_100228 = Runtime + 228,\n        Runtime_Error_100229 = Runtime + 229,\n        Runtime_Error_100230 = Runtime + 230,\n        Runtime_Error_100231 = Runtime + 231,\n        Runtime_Error_100232 = Runtime + 232,\n        Runtime_Error_100233 = Runtime + 233,\n        Runtime_Error_100234 = Runtime + 234,\n        Runtime_Error_100235 = Runtime + 235,\n        Runtime_Error_100236 = Runtime + 236,\n        Runtime_Error_100237 = Runtime + 237,\n        Runtime_Error_100238 = Runtime + 238,\n        Runtime_Error_100239 = Runtime + 239,\n        Runtime_Error_100240 = Runtime + 240,\n        Runtime_Error_100241 = Runtime + 241,\n        Runtime_Error_100242 = Runtime + 242,\n        Runtime_Error_100243 = Runtime + 243,\n        Runtime_Error_100244 = Runtime + 244,\n        Runtime_Error_100245 = Runtime + 245,\n        Runtime_Error_100246 = Runtime + 246,\n        Runtime_Error_100247 = Runtime + 247,\n        Runtime_Error_100248 = Runtime + 248,\n        Runtime_Error_100249 = Runtime + 249,\n        Runtime_Error_100250 = Runtime + 250,\n        Runtime_Error_100251 = Runtime + 251,\n        Runtime_Error_100252 = Runtime + 252,\n        Runtime_Error_100253 = Runtime + 253,\n        Runtime_Error_100254 = Runtime + 254,\n        Runtime_Error_100255 = Runtime + 255,\n        Runtime_Error_100256 = Runtime + 256,\n        Runtime_Error_100257 = Runtime + 257,\n        Runtime_Error_100258 = Runtime + 258,\n        Runtime_Error_100259 = Runtime + 259,\n        Runtime_Error_100260 = Runtime + 260,\n        Runtime_Error_100261 = Runtime + 261,\n        Runtime_Error_100262 = Runtime + 262,\n        Runtime_Error_100263 = Runtime + 263,\n        Runtime_Error_100264 = Runtime + 264,\n        Runtime_Error_100265 = Runtime + 265,\n        Runtime_Error_100266 = Runtime + 266,\n        Runtime_Error_100267 = Runtime + 267,\n        Runtime_Error_100268 = Runtime + 268,\n        Runtime_Error_100269 = Runtime + 269,\n        Runtime_Error_100270 = Runtime + 270,\n        Runtime_Error_100271 = Runtime + 271,\n        Runtime_Error_100272 = Runtime + 272,\n        Runtime_Error_100273 = Runtime + 273,\n        Runtime_Error_100274 = Runtime + 274,\n        Runtime_Error_100275 = Runtime + 275,\n        Runtime_Error_100276 = Runtime + 276,\n        Runtime_Error_100277 = Runtime + 277,\n        Runtime_Error_100278 = Runtime + 278,\n        Runtime_Error_100279 = Runtime + 279,\n        Runtime_Error_100280 = Runtime + 280,\n        Runtime_Error_100281 = Runtime + 281,\n        Runtime_Error_100282 = Runtime + 282,\n        Runtime_Error_100283 = Runtime + 283,\n        Runtime_Error_100284 = Runtime + 284,\n        Runtime_Error_100285 = Runtime + 285,\n        Runtime_Error_100286 = Runtime + 286,\n        Runtime_Error_100287 = Runtime + 287,\n        Runtime_Error_100288 = Runtime + 288,\n        Runtime_Error_100289 = Runtime + 289,\n        Runtime_Error_100290 = Runtime + 290,\n        Runtime_Error_100291 = Runtime + 291,\n        Runtime_Error_100292 = Runtime + 292,\n        Runtime_Error_100293 = Runtime + 293,\n        Runtime_Error_100294 = Runtime + 294,\n        Runtime_Error_100295 = Runtime + 295,\n        Runtime_Error_100296 = Runtime + 296,\n        Runtime_Error_100297 = Runtime + 297,\n        Runtime_Error_100298 = Runtime + 298,\n        Runtime_Error_100299 = Runtime + 299,\n        Runtime_Error_100300 = Runtime + 300,\n        Runtime_Error_100301 = Runtime + 301,\n        Runtime_Error_100302 = Runtime + 302,\n        Runtime_Error_100303 = Runtime + 303,\n        Runtime_Error_100304 = Runtime + 304,\n        Runtime_Error_100305 = Runtime + 305,\n        Runtime_Error_100306 = Runtime + 306,\n        Runtime_Error_100307 = Runtime + 307,\n        Runtime_Error_100308 = Runtime + 308,\n        Runtime_Error_100309 = Runtime + 309,\n        Runtime_Error_100310 = Runtime + 310,\n        Runtime_Error_100311 = Runtime + 311,\n        Runtime_Error_100312 = Runtime + 312,\n        ClientInitializing = Runtime + 313,\n        ClientStarting = Runtime + 314,\n        ClientError = Runtime + 315,\n        Runtime_Error_100316 = Runtime + 316,\n        Runtime_Error_100317 = Runtime + 317,\n        Runtime_Error_100318 = Runtime + 318,\n        Runtime_Error_100319 = Runtime + 319,\n        Runtime_Error_100320 = Runtime + 320,\n        Runtime_Error_100321 = Runtime + 321,\n        GrainInvokeException = Runtime + 322,\n        Runtime_Error_100323 = Runtime + 323,\n        Runtime_Error_100324 = Runtime + 324,\n        Runtime_Error_100325 = Runtime + 325,\n        Runtime_Error_100326 = Runtime + 326,\n        Runtime_Error_100327 = Runtime + 327,\n        Runtime_Error_100328 = Runtime + 328,\n        Runtime_Error_100329 = Runtime + 329,\n        Runtime_Error_100330 = Runtime + 330,\n        Runtime_Error_100331 = Runtime + 331,\n\n        SiloBase = Runtime + 400,\n        SiloStarting = SiloBase + 1,\n        SiloStarted = SiloBase + 2,\n        SiloInitializing = SiloBase + 3,\n        SiloGcSetting = SiloBase + 4,\n        SiloGcWarning = SiloBase + 5,\n        SiloSetDeploymentId = SiloBase + 6,\n        SiloSetSiloEndpoint = SiloBase + 7,\n        SiloSetProxyEndpoint = SiloBase + 8,\n        SiloSetSeedNode = SiloBase + 9,\n        SiloAddSeedNode = SiloBase + 10,\n        SiloSetPrimaryNode = SiloBase + 11,\n        SiloSetWorkingDir = SiloBase + 12,\n        SiloStopped = SiloBase + 13,\n        SiloStopping = SiloBase + 14,\n        SiloInitConfig = SiloBase + 15,\n        SiloDebugDump = SiloBase + 16,\n        SiloShuttingDown = SiloBase + 17,\n        SiloShutDown = SiloBase + 18,\n        SiloFailedToStopMembership = SiloBase + 19,\n        SiloIgnoreErrorDuringStop = SiloBase + 20,\n        SiloHeartbeatTimerStalled = Runtime_Error_100150, // Backward compatability\n        SiloCannotResetHeartbeatTimer = SiloBase + 21,\n        SiloInitializingFinished = SiloBase + 22,\n        SiloSetSiloType = SiloBase + 23,\n        SiloStartupEventName = SiloBase + 24,\n        SiloStartupEventCreated = SiloBase + 25,\n        SiloStartupEventOpened = SiloBase + 26,\n        SiloStopInProgress = SiloBase + 27,\n        WaitingForSiloStop = SiloBase + 28,\n        CannotCheckRoleEnvironment = SiloBase + 29,\n        SiloConfiguredThreadPool = SiloBase + 30,\n        SiloFailedToConfigureThreadPool = SiloBase + 31,\n        SetSiloLivenessType = SiloBase + 34,\n        SiloEndpointConfigError = SiloBase + 35,\n        SiloConfiguredServicePointManager = SiloBase + 36,\n        SiloCallingProviderInit = SiloBase + 37,\n        SetReminderServiceType = SiloBase + 38,\n        SiloStartError = SiloBase + 39,\n        SiloConfigDeprecated = SiloBase + 40,\n        SiloShutdownEventName = SiloBase + 41,\n        SiloShutdownEventCreated = SiloBase + 42,\n        SiloShutdownEventOpened = SiloBase + 43,\n        SiloShutdownEventReceived = SiloBase + 44,\n        SiloLoadedDI = SiloBase + 45, // Not used anymore\n        SiloFailedToLoadDI = SiloBase + 46, // Not used anymore\n        SiloFileNotFoundLoadingDI = SiloBase + 47, // Not used anymore\n        SiloStartupEventFailure = SiloBase + 48,\n        SiloShutdownEventFailure = SiloBase + 49,\n        LifecycleStartFailure = SiloBase + 50,\n        LifecycleStopFailure = SiloBase + 51,\n        SiloStartPerfMeasure = SiloBase + 52,\n        LifecycleStagesReport = SiloBase + 53,\n\n        CatalogBase = Runtime + 500,\n        CatalogNonExistingActivation1 = CatalogBase + 1,\n        Catalog_UnregisterManyAsync = CatalogBase + 2,\n        Catalog_DestroyActivations = CatalogBase + 3,\n        Catalog_UnknownActivation = CatalogBase + 4,\n        Catalog_ActivationException = CatalogBase + 5,\n        Catalog_GetApproximateSiloStatuses = CatalogBase + 6,\n        Catalog_BeforeCollection = CatalogBase + 7,\n        Catalog_AfterCollection = CatalogBase + 8,\n        Catalog_ShutdownActivations_1 = CatalogBase + 9,\n        CatalogNonExistingActivation2 = CatalogBase + 10,\n        Catalog_BeforeCallingActivate = CatalogBase + 11,\n        Catalog_AfterCallingActivate = CatalogBase + 12,\n        Catalog_ErrorCallingActivate = CatalogBase + 13,\n        Catalog_BeforeCallingDeactivate = CatalogBase + 14,\n        Catalog_AfterCallingDeactivate = CatalogBase + 15,\n        Catalog_ErrorCallingDeactivate = CatalogBase + 16,\n        Catalog_MissingTypeOnCreate = CatalogBase + 17,\n        Catalog_ResendDuplicateFailed = CatalogBase + 18,\n        Catalog_NullGetTypeAndStrategies = CatalogBase + 19,\n        Catalog_DuplicateActivation = CatalogBase + 20,\n        Catalog_RegistrationFailure = CatalogBase + 21,\n        Catalog_Warn_ActivationTooManyRequests = CatalogBase + 22,\n        Catalog_Reject_ActivationTooManyRequests = CatalogBase + 23,\n        Catalog_SiloStatusChangeNotification = CatalogBase + 24,\n        Catalog_SiloStatusChangeNotification_Exception = CatalogBase + 25,\n        Catalog_AttemptToCollectActivationEarly = CatalogBase + 26,\n        Catalog_DeactivateActivation_Exception = CatalogBase + 27,\n        Catalog_ActivationDirectory_Statistics = CatalogBase + 28,\n        Catalog_UnregisterMessageTarget1 = CatalogBase + 29,\n        Catalog_UnregisterMessageTarget2 = CatalogBase + 30,\n        Catalog_UnregisterMessageTarget3 = CatalogBase + 31,\n        Catalog_UnregisterMessageTarget4 = CatalogBase + 32,\n        Catalog_Failed_SetupActivationState = CatalogBase + 33,\n        Catalog_Failed_InvokeActivate = CatalogBase + 34,\n        Catalog_RerouteAllQueuedMessages = CatalogBase + 35,\n        Catalog_WaitForAllTimersToFinish_Exception = CatalogBase + 36,\n        Catalog_ActivationCollector_BadState_1 = CatalogBase + 37,\n        Catalog_ActivationCollector_BadState_2 = CatalogBase + 38,\n        Catalog_DestroyActivations_Done = CatalogBase + 39,\n        Catalog_ShutdownActivations_2 = CatalogBase + 40,\n        Catalog_ShutdownActivations_3 = CatalogBase + 41,\n        Catalog_DeactivateStreamResources_Exception = CatalogBase + 42,\n        Catalog_FinishDeactivateActivation_Exception = CatalogBase + 43,\n        Catalog_FinishGrainDeactivateAndCleanupStreams_Exception = CatalogBase + 44,\n        Catalog_DeactivateAllActivations = CatalogBase + 45,\n        Catalog_ActivationCollector_BadState_3 = CatalogBase + 46,\n        Catalog_UnregisterAsync = CatalogBase + 47,\n        Catalog_CancelledActivate = CatalogBase + 48,\n        Catalog_DisposedObjectAccess = CatalogBase + 49,\n\n        MembershipBase = Runtime + 600,\n        MembershipCantWriteLivenessDisabled = Runtime_Error_100225, // Backward compatability\n        MembershipNodeMigrated = MembershipBase + 1,\n        MembershipNodeRestarted = MembershipBase + 2,\n        MembershipStarting = MembershipBase + 3,\n        MembershipBecomeActive = MembershipBase + 4,\n        MembershipFinishBecomeActive = MembershipBase + 5,\n        MembershipShutDown = MembershipBase + 6,\n        MembershipStop = MembershipBase + 7,\n        MembershipReadTable = MembershipBase + 8,\n        MembershipKillMyself = MembershipBase + 9,\n        MembershipVotingForKill = MembershipBase + 10,\n        MembershipMarkingAsDead = MembershipBase + 11,\n        MembershipWatchList = MembershipBase + 12,\n        MembershipMissedPing = MembershipBase + 13,\n        MembershipSendingPreJoinPing = MembershipBase + 14,\n        MembershipFailedToWrite = MembershipBase + 15,\n        MembershipFailedToWriteConditional = MembershipBase + 16,\n        MembershipFoundMyselfDead1 = MembershipBase + 17,\n        MembershipFoundMyselfDead2 = MembershipBase + 18,\n        MembershipDetectedOlder = MembershipBase + 19,\n        MembershipDetectedNewer = MembershipBase + 20,\n        MembershipDelayedTableUpdateTimer = MembershipBase + 21,\n        MembershipDelayedProbeOtherSilosTimer = MembershipBase + 22,\n        MembershipFailedToReadSilo = MembershipBase + 23,\n        MembershipDelayedIAmAliveUpdateTimer = MembershipBase + 24,\n        MembershipMissedIAmAliveTableUpdate = MembershipBase + 25,\n        MembershipLocalSubscriberException = MembershipBase + 26,\n        MembershipKillMyselfLocally = MembershipBase + 27,\n        MembershipFoundMyselfDead3 = MembershipBase + 28,\n        MembershipMarkDeadWriteFailed = MembershipBase + 29,\n        MembershipTableGrainInit1 = MembershipBase + 30,\n        MembershipTableGrainInit2 = MembershipBase + 31,\n        MembershipTableGrainInit3 = MembershipBase + 32,\n        MembershipTableGrainInit4 = MembershipBase + 33,\n        MembershipReadAll_1 = MembershipBase + 34,\n        MembershipFactory1 = MembershipBase + 35,\n        MembershipFactory2 = MembershipBase + 36,\n        MembershipGrainBasedTable1 = MembershipBase + 37,\n        MembershipGrainBasedTable2 = MembershipBase + 38,\n        MembershipGrainBasedTable3 = MembershipBase + 39,\n        MembershipFileBasedTable1 = MembershipBase + 40,\n        MembershipFileBasedTable2 = MembershipBase + 41,\n        MembershipFileBasedTable3 = MembershipBase + 42,\n        MembershipFileBasedTable4 = MembershipBase + 43,\n        MembershipPingedSiloNotInWatchList = MembershipBase + 44,\n        MembershipReadAll_2 = MembershipBase + 45,\n        MembershipFailedToStart = MembershipBase + 46,\n        MembershipFailedToBecomeActive = MembershipBase + 47,\n        MembershipFailedToStop = MembershipBase + 48,\n        MembershipFailedToShutdown = MembershipBase + 49,\n        MembershipFailedToKillMyself = MembershipBase + 50,\n        MembershipFailedToSuspect = MembershipBase + 51,\n        MembershipReadAll_Cleanup = MembershipBase + 52,\n        MembershipShutDownFailure = MembershipBase + 53,\n        MembershipKillMyselfFailure = MembershipBase + 54,\n        MembershipGossipProcessingFailure = MembershipBase + 55,\n        MembershipGossipSendFailure = MembershipBase + 56,\n        MembershipTimerProcessingFailure = MembershipBase + 57,\n        MembershipSendPingFailure = MembershipBase + 58,\n        MembershipUpdateIAmAliveFailure = MembershipBase + 59,\n        MembershipStartingIAmAliveTimer = MembershipBase + 60,\n        MembershipJoiningPreconditionFailure = MembershipBase + 61,\n        MembershipCleanDeadEntriesFailure = MembershipBase + 62,\n        MembershipJoining = MembershipBase + 63,\n        MembershipFailedToJoin = MembershipBase + 64,\n\n        NSMembershipStarting = MembershipBase + 70,\n        NSMembershipBecomeActive = MembershipBase + 71,\n        NSMembershipFailedToBecomeActive = MembershipBase + 72,\n        NSMembershipShutDown = MembershipBase + 73,\n        NSMembershipStop = MembershipBase + 74,\n        NSMembershipKillMyself = MembershipBase + 75,\n        NSMembershipKillMyselfLocally = MembershipBase + 76,\n        NSMembershipNotificationProcessingFailure = MembershipBase + 77,\n        NSMembershipReadAll_1 = MembershipBase + 78,\n        NSMembershipReadAll_2 = MembershipBase + 79,\n        NSMembershipFoundMyselfDead2 = MembershipBase + 80,\n        NSMembershipDetectedOlder = MembershipBase + 81,\n        NSMembershipDetectedNewer = MembershipBase + 82,\n        NSMembershipTimerProcessingFailure = MembershipBase + 83,\n        NSMembershipShutDownFailure = MembershipBase + 84,\n        NSMembershipKillMyselfFailure = MembershipBase + 85,\n        NSMembershipNSDetails = MembershipBase + 86,\n        SSMT_ReadRowError = MembershipBase + 87,\n        SSMT_ReadAllError = MembershipBase + 88,\n        SSMT_InsertRowError = MembershipBase + 89,\n        SSMT_UpdateRowError = MembershipBase + 90,\n        SSMT_MergeRowError = MembershipBase + 91,\n        SSMT_EtagMismatch_Insert = MembershipBase + 92,\n        SSMT_EtagMismatch_Update = MembershipBase + 93,\n\n        PerfCounterBase = Runtime + 700,\n        PerfCounterNotFound = PerfCounterBase + 1,\n        PerfCounterStarting = PerfCounterBase + 2,\n        PerfCounterStopping = PerfCounterBase + 3,\n        PerfCounterDumpAll = PerfCounterBase + 4,\n        PerfCounterWriteErrors = PerfCounterBase + 5,\n        PerfCounterWriteSuccess = PerfCounterBase + 6,\n        PerfCounterWriteTooManyErrors = PerfCounterBase + 7,\n        PerfCounterNotRegistered = PerfCounterBase + 8,\n        PerfCounterUnableToConnect = PerfCounterBase + 9,\n        PerfCounterUnableToWrite = PerfCounterBase + 10,\n        PerfCounterWriting = PerfCounterBase + 11,\n        PerfCounterSkipping = PerfCounterBase + 12,\n        PerfMetricsStoppingTimer = PerfCounterBase + 13,\n        PerfMetricsStartingTimer = PerfCounterBase + 14,\n        PerfStatistics = PerfCounterBase + 15,\n        PerfCounterRegistering = PerfCounterBase + 16,\n        PerfCounterTimerError = PerfCounterBase + 17,\n        PerfCounterCategoryCheckError = PerfCounterBase + 18,\n        PerfCounterConnectError = PerfCounterBase + 19,\n        PerfCounterFailedToInitialize = PerfCounterBase + 20,\n\n        ProxyClientBase = Runtime + 900,\n        ProxyClient_ReceiveError = Runtime_Error_100021, // Backward compatability\n        ProxyClient_SerializationError = Runtime_Error_100159, // Backward compatability\n        ProxyClient_SocketSendError = Runtime_Error_100161, // Backward compatability\n        ProxyClient_ByteCountMismatch = Runtime_Error_100163, // Backward compatability\n        ProxyClient_CannotConnect = Runtime_Error_100178, // Backward compatability\n        ProxyClientUnhandledExceptionWhileSending = ProxyClientBase + 1,\n        ProxyClientUnhandledExceptionWhileReceiving = ProxyClientBase + 2,\n        ProxyClient_CannotSend = ProxyClientBase + 3,\n        ProxyClient_CannotSend_NoGateway = ProxyClientBase + 4,\n        ProxyClient_DroppingMsg = ProxyClientBase + 5,\n        ProxyClient_RejectingMsg = ProxyClientBase + 6,\n        ProxyClient_MsgSent = ProxyClientBase + 7,\n        ProxyClient_Connected = ProxyClientBase + 8,\n        ProxyClient_PauseBeforeRetry = ProxyClientBase + 9,\n        ProxyClient_MsgCtrNotRunning = ProxyClientBase + 10,\n        ProxyClient_DeadGateway = ProxyClientBase + 11,\n        ProxyClient_MarkGatewayDead = ProxyClientBase + 12,\n        ProxyClient_MarkGatewayDisconnected = ProxyClientBase + 13,\n        ProxyClient_GatewayConnStarted = ProxyClientBase + 14,\n        ProxyClient_CreatedGatewayUnordered = ProxyClientBase + 15,\n        ProxyClient_CreatedGatewayToGrain = ProxyClientBase + 16,\n        ProxyClient_NewBucketIndex = ProxyClientBase + 17,\n        ProxyClient_QueueRequest = ProxyClientBase + 18,\n        ProxyClient_ThreadAbort = ProxyClientBase + 19,\n        ProxyClient_OperationCancelled = ProxyClientBase + 20,\n        ProxyClient_GetGateways = ProxyClientBase + 21,\n        ProxyClient_NetworkError = ProxyClientBase + 22,\n        ProxyClient_SendException = ProxyClientBase + 23,\n        ProxyClient_OGC_TargetNotFound = ProxyClientBase + 24,\n        ProxyClient_OGC_SendResponseFailed = ProxyClientBase + 25,\n        ProxyClient_OGC_SendExceptionResponseFailed = ProxyClientBase + 26,\n        ProxyClient_OGC_UnhandledExceptionInOneWayInvoke = ProxyClientBase + 27,\n        ProxyClient_ClientInvokeCallback_Error = ProxyClientBase + 28,\n        ProxyClient_StartDone = ProxyClientBase + 29,\n        ProxyClient_OGC_TargetNotFound_2 = ProxyClientBase + 30,\n        ProxyClient_AppDomain_Unload = ProxyClientBase + 31,\n        ProxyClient_GatewayUnknownStatus = ProxyClientBase + 32,\n        ProxyClient_FailedToUnregisterCallback = ProxyClientBase + 33,\n\n        MessagingBase = Runtime + 1000,\n        Messaging_IMA_DroppingConnection = MessagingBase + 1,\n        Messaging_Dispatcher_DiscardRejection = MessagingBase + 2,\n        MessagingBeginReceiveException = MessagingBase + 3,\n        MessagingBeginAcceptSocketException = MessagingBase + 4,\n        MessagingAcceptingSocketClosed = MessagingBase + 5,\n        MessagingEndAcceptSocketException = MessagingBase + 6,\n        MessagingUnexpectedSendError = MessagingBase + 7,\n        MessagingSendingRejection = MessagingBase + 8,\n        MessagingMessageFromUnknownActivation = MessagingBase + 9,\n        Messaging_IMA_OpenedListeningSocket = MessagingBase + 10,\n        Messaging_IMA_AcceptCallbackNullState = MessagingBase + 11,\n        Messaging_IMA_AcceptCallbackUnexpectedState = MessagingBase + 12,\n        Messaging_IMA_NewBeginReceiveException = MessagingBase + 13,\n        Messaging_Socket_ReceiveError = MessagingBase + 14,\n        Messaging_IMA_ClosingSocket = MessagingBase + 15,\n        Messaging_OutgoingMS_DroppingMessage = MessagingBase + 16,\n        MessagingProcessReceiveBufferException = MessagingBase + 17,\n        Messaging_LargeMsg_Outgoing = MessagingBase + 18,\n        Messaging_LargeMsg_Incoming = MessagingBase + 19,\n        Messaging_SiloNetworkError = MessagingBase + 20,\n        Messaging_UnableToGetSendingSocket = MessagingBase + 21,\n        Messaging_ExceptionSending = MessagingBase + 22,\n        Messaging_CountMismatchSending = MessagingBase + 23,\n        Messaging_ExceptionReceiving = MessagingBase + 24,\n        Messaging_ExceptionBeginReceiving = MessagingBase + 25,\n        Messaging_IMA_ExceptionAccepting = MessagingBase + 26,\n        Messaging_IMA_BadBufferReceived = MessagingBase + 27,\n        Messaging_IMA_ActivationOverloaded = MessagingBase + 28,\n        Messaging_SerializationError = MessagingBase + 29,\n        Messaging_UnableToDeserializeBody = MessagingBase + 30,\n        Messaging_Dispatcher_TryForward = MessagingBase + 31,\n        Messaging_Dispatcher_TryForwardFailed = MessagingBase + 32,\n        Messaging_Dispatcher_ForwardingRequests = MessagingBase + 33,\n        Messaging_SimulatedMessageLoss = MessagingBase + 34,\n        Messaging_Dispatcher_ReturnToOriginCluster = MessagingBase + 35,\n        MessagingAcceptAsyncSocketException = MessagingBase + 36,\n        Messaging_ExceptionReceiveAsync = MessagingBase + 37,\n        Messaging_DroppingExpiredMessage = MessagingBase + 38,\n        Messaging_DroppingBlockedMessage = MessagingBase + 39,\n        Messaging_Inbound_Enqueue = MessagingBase + 40,\n        Messaging_Inbound_Dequeue = MessagingBase + 41,\n        Messaging_Dispatcher_Rejected = MessagingBase + 42,\n\n        DirectoryBase = Runtime + 1100,\n        DirectoryBothPrimaryAndBackupForGrain = DirectoryBase + 1,\n        DirectoryPartitionPredecessorExpected = DirectoryBase + 2,\n        DirectoryUnexpectedDelta = DirectoryBase + 4,\n        Directory_SiloStatusChangeNotification_Exception = DirectoryBase + 5,\n\n        SchedulerBase = Runtime + 1200,\n        SchedulerWorkerPoolThreadQueueWaitTime = SchedulerBase + 1,\n        SchedulerWorkItemGroupQueueWaitTime = SchedulerBase + 2,\n        SchedulerStatistics = SchedulerBase + 3,\n        SchedulerFinishShutdown = SchedulerBase + 4,\n        SchedulerNullActivation = SchedulerBase + 5,\n        SchedulerExceptionFromExecute = SchedulerBase + 6,\n        SchedulerNullContext = SchedulerBase + 7,\n        SchedulerTaskExecuteIncomplete1 = SchedulerBase + 8,\n        WaitCalledInsideGrain = SchedulerBase + 9,\n        SchedulerStatus = SchedulerBase + 10,\n        WaitCalledInServerCode = SchedulerBase + 11,\n        ExecutorTurnTooLong = SchedulerBase + 12,\n        SchedulerTooManyPendingItems = SchedulerBase + 13,\n        SchedulerTurnTooLong2 = SchedulerBase + 14,\n        SchedulerTurnTooLong3 = SchedulerBase + 15,\n        SchedulerWorkGroupShuttingDown = SchedulerBase + 16,\n        SchedulerEnqueueWorkWhenShutdown = SchedulerBase + 17,\n        SchedulerNotExecuteWhenShutdown = SchedulerBase + 18,\n        SchedulerAppTurnsStopped_1 = SchedulerBase + 19,\n        SchedulerWorkGroupStopping = SchedulerBase + 20,\n        SchedulerSkipWorkStopping = SchedulerBase + 21,\n        SchedulerSkipWorkCancelled = SchedulerBase + 22,\n        SchedulerTaskRunningOnWrongScheduler1 = SchedulerBase + 23,\n        SchedulerQueueWorkItemWrongCall = SchedulerBase + 24,\n        SchedulerQueueTaskWrongCall = SchedulerBase + 25,\n        SchedulerTaskExecuteIncomplete2 = SchedulerBase + 26,\n        SchedulerTaskExecuteIncomplete3 = SchedulerBase + 27,\n        SchedulerTaskExecuteIncomplete4 = SchedulerBase + 28,\n        SchedulerTaskWaitIncomplete = SchedulerBase + 29,\n        ExecutorWorkerThreadExc = SchedulerBase + 30,\n        SchedulerQueueWorkItemWrongContext = SchedulerBase + 31,\n        SchedulerAppTurnsStopped_2 = SchedulerBase + 32,\n        ExecutorProcessingError = SchedulerBase + 33,\n\n        GatewayBase = Runtime + 1300,\n        GatewayClientOpenedSocket = GatewayBase + 1,\n        GatewayClientClosedSocket = GatewayBase + 2,\n        GatewayDroppingClient = GatewayBase + 3,\n        GatewayTryingToSendToUnrecognizedClient = GatewayBase + 4,\n        GatewayByteCountMismatch = GatewayBase + 5,\n        GatewayExceptionSendingToClient = GatewayBase + 6,\n        GatewayAcceptor_SocketClosed = GatewayBase + 7,\n        GatewayAcceptor_ExceptionReceiving = GatewayBase + 8,\n        GatewayManager_FoundKnownGateways = GatewayBase + 9,\n        MessageAcceptor_Connection = GatewayBase + 10,\n        MessageAcceptor_NotAProxiedConnection = GatewayBase + 11,\n        MessageAcceptor_UnexpectedProxiedConnection = GatewayBase + 12,\n        GatewayManager_NoGateways = GatewayBase + 13,\n        GatewayNetworkError = GatewayBase + 14,\n        GatewayFailedToParse = GatewayBase + 15,\n        ClientRegistrarFailedToRegister = GatewayBase + 16,\n        ClientRegistrarFailedToRegister_2 = GatewayBase + 17,\n        ClientRegistrarFailedToUnregister = GatewayBase + 18,\n        ClientRegistrarTimerFailed = GatewayBase + 19,\n        GatewayAcceptor_WrongClusterId = GatewayBase + 20,\n        GatewayManager_AllGatewaysDead = GatewayBase + 21,\n        GatewayAcceptor_InvalidSize = GatewayBase + 22,\n\n        TimerBase = Runtime + 1400,\n        TimerChangeError = PerfCounterTimerError, // Backward compatability\n        //TimerCallbackError                    = Runtime_Error_100306, // Backward compatability\n        TimerCallbackError = Runtime_Error_100037, // Backward compatability\n        TimerDisposeError = TimerBase + 1,\n        TimerStopError = TimerBase + 2,\n        TimerQueueTickError = TimerBase + 3,\n        TimerChanging = TimerBase + 4,\n        TimerBeforeCallback = TimerBase + 5,\n        TimerAfterCallback = TimerBase + 6,\n        TimerNextTick = TimerBase + 7,\n        TimerDisposing = TimerBase + 8,\n        TimerStopped = TimerBase + 9,\n        Timer_TimerInsideGrainIsNotTicking = TimerBase + 10,\n        Timer_TimerInsideGrainIsDelayed = TimerBase + 11,\n        Timer_SafeTimerIsNotTicking = TimerBase + 12,\n        Timer_GrainTimerCallbackError = TimerBase + 13,\n        Timer_InvalidContext = TimerBase + 14,\n\n        DispatcherBase = Runtime + 1500,\n        Dispatcher_SelectTarget_Failed = Runtime_Error_100071, // Backward compatability\n        Dispatcher_InvalidEnum_Direction = Runtime_Error_100072, // Backward compatability\n        Dispatcher_NoCallbackForRejectionResp = Runtime_Error_100073, // Backward compatability\n        Dispatcher_InvalidEnum_RejectionType = Runtime_Error_100075, // Backward compatability\n        Dispatcher_NoCallbackForResp = Runtime_Error_100076, // Backward compatability\n        Dispatcher_InvalidMsg_Direction = Runtime_Error_100077, // Backward compatability\n        Dispatcher_Intermediate_GetOrCreateActivation = Runtime_Error_100147, // Backward compatability\n        Dispatcher_NoTargetActivation = Runtime_Error_100148, // Backward compatability\n        Dispatcher_QueueingRequestBadTargetState = Runtime_Error_100152, // Backward compatability\n        Dispatcher_InjectingRejection = Runtime_Error_100299, // Backward compatability\n        Dispatcher_InjectingMessageLoss = Runtime_Error_100300, // Backward compatability\n        Dispatcher_UnknownTypeCode = Runtime_Error_100303, // Backward compatability\n        Dispatcher_SelectTarget_FailPending = DispatcherBase + 1,\n        Dispatcher_RegisterCallback_Replaced = DispatcherBase + 2,\n        Dispatcher_Send_BufferResponse = DispatcherBase + 3,\n        Dispatcher_Send_AddressedMessage = DispatcherBase + 4,\n        Dispatcher_Receive_InvalidActivation = DispatcherBase + 5,\n        Dispatcher_WriteGrainFailed = DispatcherBase + 6,\n        Dispatcher_ActivationEndedTurn_Waiting = DispatcherBase + 7,\n        Dispatcher_Retarget = DispatcherBase + 8,\n        Dispatcher_TryAcceptMessage = DispatcherBase + 9,\n        Dispatcher_UpdateReceiveOrder = DispatcherBase + 10,\n        Dispatcher_ReceiveOrderCorrelation = DispatcherBase + 11,\n        Dispatcher_AddSendOrder = DispatcherBase + 12,\n        Dispatcher_AddSendOrderNoPrior = DispatcherBase + 13,\n        Dispatcher_AddSendOrder_PriorIds = DispatcherBase + 14,\n        Dispatcher_AddSendOrder_First = DispatcherBase + 15,\n        Dispatcher_EnqueueMessage = DispatcherBase + 16,\n        Dispatcher_AddressMsg = DispatcherBase + 17,\n        Dispatcher_AddressMsg_GrainOrder = DispatcherBase + 18,\n        Dispatcher_AddressMsg_NullingLastSentTo = DispatcherBase + 19,\n        Dispatcher_AddressMsg_SMPlacement = DispatcherBase + 20,\n        Dispatcher_AddressMsg_UnregisteredClient = DispatcherBase + 21,\n        Dispatcher_AddressMsg_SelectTarget = DispatcherBase + 22,\n        Dispatcher_HandleMsg = DispatcherBase + 23,\n        Dispatcher_OnActivationCompletedRequest_Waiting = DispatcherBase + 24,\n        IGC_DisposeError = DispatcherBase + 25,\n        IGC_SendRequest_NullContext = DispatcherBase + 26,\n        IGC_SniffIncomingMessage_Exc = DispatcherBase + 27,\n        Dispatcher_DetectedDeadlock = DispatcherBase + 28,\n        Dispatcher_ActivationOverloaded = DispatcherBase + 30,\n        IGC_SendResponseFailed = DispatcherBase + 31,\n        IGC_SendExceptionResponseFailed = DispatcherBase + 32,\n        IGC_UnhandledExceptionInInvoke = DispatcherBase + 33,\n        Dispatcher_ExtendedMessageProcessing = DispatcherBase + 34,\n        Dispatcher_FailedToUnregisterNonExistingAct = DispatcherBase + 35,\n        Dispatcher_NoGrainInstance = DispatcherBase + 36,\n        Dispatcher_RuntimeStatisticsUnavailable = DispatcherBase + 37,\n        Dispatcher_InvalidActivation = DispatcherBase + 38,\n        InvokeWorkItem_UnhandledExceptionInInvoke = DispatcherBase + 39,\n        Dispatcher_ErrorCreatingActivation = DispatcherBase + 40,\n        Dispatcher_StuckActivation = DispatcherBase + 41,\n        Dispatcher_FailedToUnregisterCallback = DispatcherBase + 42,\n\n        SerializationBase = Runtime + 1600,\n        Ser_IncompatibleIntermediateType = Runtime_Error_100033, // Backward compatability\n        Ser_CannotConstructBaseObj = Runtime_Error_100034, // Backward compatability\n        Ser_IncompatibleType = Runtime_Error_100035, // Backward compatability\n        Ser_AssemblyLoadError = SerializationBase + 1,\n        Ser_BadRegisterSerializer = SerializationBase + 2,\n        Ser_AssemblyLoadErrorDetails = SerializationBase + 3,\n        Ser_AssemblyLoadSuccess = SerializationBase + 4,\n        Ser_LargeObjectAllocated = SerializationBase + 5,\n\n        LoaderBase = Runtime + 1700,\n        Loader_NotGrainAssembly = Runtime_Error_100047, // Backward compatability\n        Loader_TypeLoadError = Runtime_Error_100048, // Backward compatability\n        Loader_ProxyLoadError = Runtime_Error_100049, // Backward compatability\n        Loader_AssemblyLookupFailed = LoaderBase + 1,\n        Loader_AssemblyLookupResolved = LoaderBase + 2,\n        Loader_LoadingFromDir = LoaderBase + 3,\n        Loader_LoadingFromFile = LoaderBase + 4,\n        Loader_DirNotFound = LoaderBase + 5,\n        Loader_LoadingSerInfo = LoaderBase + 6,\n        Loader_LoadingGrainType = LoaderBase + 7,\n        Loader_SkippingFile = LoaderBase + 8,\n        Loader_SkippingDynamicAssembly = LoaderBase + 9,\n        Loader_AssemblyInspectError = LoaderBase + 10,\n        Loader_GrainTypeFullList = LoaderBase + 11,\n        Loader_IgnoreAbstractGrainClass = LoaderBase + 12,\n        Loader_AssemblyInspectionError = LoaderBase + 13,\n        Loader_FoundBinary = LoaderBase + 14,\n        Loader_IgnoreNonPublicGrainClass = LoaderBase + 15,\n        Loader_UnexpectedException = LoaderBase + 16,\n        Loader_SkippingBadAssembly = LoaderBase + 17,\n        Loader_TypeLoadError_2 = LoaderBase + 18,\n        Loader_TypeLoadError_3 = LoaderBase + 19,\n        Loader_TypeLoadError_4 = LoaderBase + 20,\n        Loader_LoadAndCreateInstance_Failure = LoaderBase + 21,\n        Loader_TryLoadAndCreateInstance_Failure = LoaderBase + 22,\n        Loader_TypeLoadError_5 = LoaderBase + 23,\n        Loader_AssemblyLoadError = LoaderBase + 24,\n\n        PlacementBase = Runtime + 1800,\n        Placement_RuntimeStatisticsUpdateFailure_1 = PlacementBase + 1,\n        Placement_RuntimeStatisticsUpdateFailure_2 = PlacementBase + 2,\n        Placement_RuntimeStatisticsUpdateFailure_3 = PlacementBase + 3,\n        Placement_ActivationCountBasedDirector_NoSilos = PlacementBase + 4,\n\n        StorageProviderBase = Runtime + 2200,\n        StorageProvider_ReadFailed = StorageProviderBase + 2,\n        StorageProvider_WriteFailed = StorageProviderBase + 3,\n        StorageProvider_DeleteFailed = StorageProviderBase + 4,\n        StorageProvider_ForceReRead = StorageProviderBase + 5,\n\n        SerializationManagerBase = Runtime + 2400,\n        SerMgr_TypeRegistrationFailure = SerializationManagerBase + 1,\n        SerMgr_MissingRegisterMethod = SerializationManagerBase + 2,\n        SerMgr_ErrorBindingMethods = SerializationManagerBase + 3,\n        SerMgr_ErrorLoadingAssemblyTypes = SerializationManagerBase + 4,\n        SerMgr_TooLongSerialize = SerializationManagerBase + 5,\n        SerMgr_TooLongDeserialize = SerializationManagerBase + 6,\n        SerMgr_TooLongDeepCopy = SerializationManagerBase + 7,\n        SerMgr_IgnoreAssembly = SerializationManagerBase + 8,\n        SerMgr_TypeRegistrationFailureIgnore = SerializationManagerBase + 9,\n        SerMgr_ArtifactReport = SerializationManagerBase + 10,\n        SerMgr_UnavailableSerializer = SerializationManagerBase + 11,\n        SerMgr_SerializationMethodsMissing = SerializationManagerBase + 12,\n\n        WatchdogBase = Runtime + 2600,\n        Watchdog_ParticipantThrownException = WatchdogBase + 1,\n        Watchdog_InternalError = WatchdogBase + 2,\n        Watchdog_HealthCheckFailure = WatchdogBase + 3,\n\n        LoggerBase = Runtime + 2700,\n        Logger_ProcessCrashing = Runtime_Error_100002, // Backward compatability\n        Logger_LogMessageTruncated = LoggerBase + 1,\n\n        WFServiceBase = Runtime + 2800,\n        WFService_Error_1 = WFServiceBase + 1,\n        WFService_Error_2 = WFServiceBase + 2,\n        WFService_Error_3 = WFServiceBase + 3,\n        WFService_Error_4 = WFServiceBase + 4,\n        WFService_Error_5 = WFServiceBase + 5,\n        WFService_Error_6 = WFServiceBase + 6,\n        WFService_Error_7 = WFServiceBase + 7,\n        WFService_Error_8 = WFServiceBase + 8,\n        WFService_Error_9 = WFServiceBase + 9,\n\n        // Codes for the Reminder Service\n        ReminderServiceBase = Runtime + 2900,\n        RS_Register_TableError = ReminderServiceBase + 5,\n        RS_Register_AlreadyRegistered = ReminderServiceBase + 7,\n        RS_Register_InvalidPeriod = ReminderServiceBase + 8,\n        RS_Register_NotRemindable = ReminderServiceBase + 9,\n        RS_NotResponsible = ReminderServiceBase + 10,\n        RS_Unregister_NotFoundLocally = ReminderServiceBase + 11,\n        RS_Unregister_TableError = ReminderServiceBase + 12,\n        RS_Table_Insert = ReminderServiceBase + 13,\n        RS_Table_Remove = ReminderServiceBase + 14,\n        RS_Tick_Delivery_Error = ReminderServiceBase + 15,\n        RS_Not_Started = ReminderServiceBase + 16,\n        RS_UnregisterGrain_TableError = ReminderServiceBase + 17,\n        RS_GrainBasedTable1 = ReminderServiceBase + 18,\n        RS_Factory1 = ReminderServiceBase + 19,\n        RS_FailedToReadTableAndStartTimer = ReminderServiceBase + 20,\n        RS_TableGrainInit1 = ReminderServiceBase + 21,\n        RS_TableGrainInit2 = ReminderServiceBase + 22,\n        RS_TableGrainInit3 = ReminderServiceBase + 23,\n        RS_GrainBasedTable2 = ReminderServiceBase + 24,\n        RS_ServiceStarting = ReminderServiceBase + 25,\n        RS_ServiceStarted = ReminderServiceBase + 26,\n        RS_ServiceStopping = ReminderServiceBase + 27,\n        RS_RegisterOrUpdate = ReminderServiceBase + 28,\n        RS_Unregister = ReminderServiceBase + 29,\n        RS_Stop = ReminderServiceBase + 30,\n        RS_RemoveFromTable = ReminderServiceBase + 31,\n        RS_GetReminder = ReminderServiceBase + 32,\n        RS_GetReminders = ReminderServiceBase + 33,\n        RS_RangeChanged = ReminderServiceBase + 34,\n        RS_LocalStop = ReminderServiceBase + 35,\n        RS_Started = ReminderServiceBase + 36,\n        RS_ServiceInitialLoadFailing = ReminderServiceBase + 37,\n        RS_ServiceInitialLoadFailed = ReminderServiceBase + 38,\n        RS_FastReminderInterval = ReminderServiceBase + 39,\n\n\n        // Codes for the Consistent Ring Provider\n        ConsistentRingProviderBase = Runtime + 3000,\n        CRP_Local_Subscriber_Exception = ConsistentRingProviderBase + 1,\n        CRP_ForGrains_Local_Subscriber_Exception_1 = ConsistentRingProviderBase + 2,\n        CRP_Added_Silo = ConsistentRingProviderBase + 3,\n        CRP_Removed_Silo = ConsistentRingProviderBase + 4,\n        CRP_Notify = ConsistentRingProviderBase + 5,\n        CRP_ForGrains_Local_Subscriber_Exception_2 = ConsistentRingProviderBase + 6,\n\n        ProviderManagerBase = Runtime + 3100,\n        Provider_InstanceConstructionError1 = ProviderManagerBase + 1,\n        Provider_Loaded = ProviderManagerBase + 2,\n        Provider_AssemblyLoadError = ProviderManagerBase + 3,\n        Provider_CatalogNoStorageProvider_1 = ProviderManagerBase + 4,\n        Provider_CatalogNoStorageProvider_2 = ProviderManagerBase + 5,\n        Provider_CatalogStorageProviderAllocated = ProviderManagerBase + 6,\n        Provider_NoDefaultProvider = ProviderManagerBase + 7,\n        Provider_ConfiguredProviderNotLoaded = ProviderManagerBase + 8,\n        Provider_ErrorFromInit = ProviderManagerBase + 9,\n        Provider_IgnoringExplicitSet = ProviderManagerBase + 10,\n        Provider_NotLoaded = ProviderManagerBase + 11,\n        Provider_Manager_Already_Loaded = ProviderManagerBase + 12,\n        Provider_CatalogNoStorageProvider_3 = ProviderManagerBase + 13,\n        Provider_ProviderLoadedOk = ProviderManagerBase + 14,\n        Provider_ProviderNotFound = ProviderManagerBase + 15,\n        Provider_ProviderNotControllable = ProviderManagerBase + 16,\n        Provider_CatalogNoLogConsistencyProvider = ProviderManagerBase + 17,\n        Provider_CatalogLogConsistencyProviderAllocated = ProviderManagerBase + 18,\n        Provider_ErrorFromClose = ProviderManagerBase + 19,\n\n        PersistentStreamPullingAgentBase = Runtime + 3300,\n        PersistentStreamPullingAgent_01 = PersistentStreamPullingAgentBase + 1,\n        PersistentStreamPullingAgent_02 = PersistentStreamPullingAgentBase + 2,\n        PersistentStreamPullingAgent_03 = PersistentStreamPullingAgentBase + 3,\n        PersistentStreamPullingAgent_04 = PersistentStreamPullingAgentBase + 4,\n        PersistentStreamPullingAgent_05 = PersistentStreamPullingAgentBase + 5,\n        PersistentStreamPullingAgent_06 = PersistentStreamPullingAgentBase + 6,\n        PersistentStreamPullingAgent_07 = PersistentStreamPullingAgentBase + 7,\n        PersistentStreamPullingAgent_08 = PersistentStreamPullingAgentBase + 8,\n        PersistentStreamPullingAgent_09 = PersistentStreamPullingAgentBase + 9,\n        PersistentStreamPullingAgent_10 = PersistentStreamPullingAgentBase + 10,\n        PersistentStreamPullingAgent_11 = PersistentStreamPullingAgentBase + 11,\n        PersistentStreamPullingAgent_12 = PersistentStreamPullingAgentBase + 12,\n        PersistentStreamPullingAgent_13 = PersistentStreamPullingAgentBase + 13,\n        PersistentStreamPullingAgent_14 = PersistentStreamPullingAgentBase + 14,\n        PersistentStreamPullingAgent_15 = PersistentStreamPullingAgentBase + 15,\n        PersistentStreamPullingAgent_16 = PersistentStreamPullingAgentBase + 16,\n        PersistentStreamPullingAgent_17 = PersistentStreamPullingAgentBase + 17,\n        PersistentStreamPullingAgent_18 = PersistentStreamPullingAgentBase + 18,\n        PersistentStreamPullingAgent_19 = PersistentStreamPullingAgentBase + 19,\n        PersistentStreamPullingAgent_20 = PersistentStreamPullingAgentBase + 20,\n        PersistentStreamPullingAgent_21 = PersistentStreamPullingAgentBase + 21,\n        PersistentStreamPullingAgent_22 = PersistentStreamPullingAgentBase + 22,\n        PersistentStreamPullingAgent_23 = PersistentStreamPullingAgentBase + 23,\n        PersistentStreamPullingAgent_24 = PersistentStreamPullingAgentBase + 24,\n        PersistentStreamPullingAgent_25 = PersistentStreamPullingAgentBase + 25,\n        PersistentStreamPullingAgent_26 = PersistentStreamPullingAgentBase + 26,\n        PersistentStreamPullingAgent_27 = PersistentStreamPullingAgentBase + 27,\n        PersistentStreamPullingAgent_28 = PersistentStreamPullingAgentBase + 28,\n\n        StreamProviderManagerBase = Runtime + 3400,\n        StreamProvider_FailedToDispose = StreamProviderManagerBase + 1,\n        StreamProvider_ProducerFailedToUnregister = StreamProviderManagerBase + 2,\n        StreamProvider_NoStreamForItem = StreamProviderManagerBase + 3,\n        StreamProvider_AddObserverException = StreamProviderManagerBase + 4,\n        Stream_ExtensionNotInstalled = StreamProviderManagerBase + 5,\n        Stream_ProducerIsDead = StreamProviderManagerBase + 6,\n        StreamProvider_NoStreamForBatch = StreamProviderManagerBase + 7,\n        StreamProvider_ConsumerFailedToUnregister = StreamProviderManagerBase + 8,\n        Stream_ConsumerIsDead = StreamProviderManagerBase + 9,\n        Stream_RegisterProducerFailed = StreamProviderManagerBase + 10,\n        Stream_UnregisterProducerFailed = StreamProviderManagerBase + 11,\n        Stream_RegisterConsumerFailed = StreamProviderManagerBase + 12,\n        Stream_UnregisterConsumerFailed = StreamProviderManagerBase + 13,\n        Stream_SetSubscriptionToFaultedFailed = StreamProviderManagerBase + 14,\n\n        PersistentStreamPullingManagerBase = Runtime + 3500,\n        PersistentStreamPullingManager_01 = PersistentStreamPullingManagerBase + 1,\n        PersistentStreamPullingManager_02 = PersistentStreamPullingManagerBase + 2,\n        PersistentStreamPullingManager_03 = PersistentStreamPullingManagerBase + 3,\n        PersistentStreamPullingManager_04 = PersistentStreamPullingManagerBase + 4,\n        PersistentStreamPullingManager_05 = PersistentStreamPullingManagerBase + 5,\n        PersistentStreamPullingManager_06 = PersistentStreamPullingManagerBase + 6,\n        PersistentStreamPullingManager_07 = PersistentStreamPullingManagerBase + 7,\n        PersistentStreamPullingManager_08 = PersistentStreamPullingManagerBase + 8,\n        PersistentStreamPullingManager_09 = PersistentStreamPullingManagerBase + 9,\n        PersistentStreamPullingManager_10 = PersistentStreamPullingManagerBase + 10,\n        PersistentStreamPullingManager_11 = PersistentStreamPullingManagerBase + 11,\n        PersistentStreamPullingManager_12 = PersistentStreamPullingManagerBase + 12,\n        PersistentStreamPullingManager_13 = PersistentStreamPullingManagerBase + 13,\n        PersistentStreamPullingManager_14 = PersistentStreamPullingManagerBase + 14,\n        PersistentStreamPullingManager_15 = PersistentStreamPullingManagerBase + 15,\n        PersistentStreamPullingManager_16 = PersistentStreamPullingManagerBase + 16,\n        PersistentStreamPullingManager_Starting = PersistentStreamPullingManagerBase + 17,\n        PersistentStreamPullingManager_Stopping = PersistentStreamPullingManagerBase + 18,\n        PersistentStreamPullingManager_Started = PersistentStreamPullingManagerBase + 19,\n        PersistentStreamPullingManager_Stopped = PersistentStreamPullingManagerBase + 20,\n        PersistentStreamPullingManager_AlreadyStarted = PersistentStreamPullingManagerBase + 21,\n        PersistentStreamPullingManager_AlreadyStopped = PersistentStreamPullingManagerBase + 22,\n        PersistentStreamPullingManager_PeriodicPrint = PersistentStreamPullingManagerBase + 23,\n\n        AzureServiceRuntimeWrapper = Runtime + 3700,\n        AzureServiceRuntime_NotLoaded = AzureServiceRuntimeWrapper + 1,\n        AzureServiceRuntime_FailedToLoad = AzureServiceRuntimeWrapper + 2,\n\n        CodeGenBase = Runtime + 3800,\n        CodeGenCompilationFailed = CodeGenBase + 1,\n        CodeGenCompilationSucceeded = CodeGenBase + 2,\n        CodeGenSourceGenerated = CodeGenBase + 3,\n        CodeGenSerializerGenerator = CodeGenBase + 4,\n        CodeGenIgnoringTypes = CodeGenBase + 5,\n        CodeGenDllMissing = CodeGenBase + 6,\n        CodeGenSystemTypeRequiresSerializer = CodeGenBase + 7,\n\n        MultiClusterNetworkBase = Runtime + 3900,\n        MultiClusterNetwork_Starting = MultiClusterNetworkBase + 1,\n        MultiClusterNetwork_Started = MultiClusterNetworkBase + 2,\n        MultiClusterNetwork_FailedToStart = MultiClusterNetworkBase + 3,\n        MultiClusterNetwork_LocalSubscriberException = MultiClusterNetworkBase + 4,\n        MultiClusterNetwork_GossipCommunicationFailure = MultiClusterNetworkBase + 5,\n        MultiClusterNetwork_NoChannelsConfigured = MultiClusterNetworkBase + 6,\n\n        CancellationTokenManagerBase = Runtime + 4000,\n        CancellationTokenCancelFailed = CancellationTokenManagerBase + 1,\n        CancellationExtensionCreationFailed = CancellationTokenManagerBase + 2,\n\n        GlobalSingleInstanceBase = Runtime + 4100,\n        GlobalSingleInstance_ProtocolError = GlobalSingleInstanceBase + 1,\n        GlobalSingleInstance_WarningInvalidOrigin = GlobalSingleInstanceBase + 2,\n        GlobalSingleInstance_MaintainerException = GlobalSingleInstanceBase + 3,\n        GlobalSingleInstance_MultipleOwners = GlobalSingleInstanceBase + 4,\n\n        TypeManagerBase = Runtime + 4200,\n        TypeManager_GetSiloGrainInterfaceMapError = TypeManagerBase + 1,\n        TypeManager_GetClusterGrainTypeResolverError = TypeManagerBase + 2,\n\n        LogConsistencyBase = Runtime + 4300,\n        LogConsistency_UserCodeException = LogConsistencyBase + 1,\n        LogConsistency_CaughtException = LogConsistencyBase + 2,\n        LogConsistency_ProtocolError = LogConsistencyBase + 3,\n        LogConsistency_ProtocolFatalError = LogConsistencyBase + 4,\n\n        // Note: individual Service Fabric error codes are defined in\n        // Microsoft.Orleans.ServiceFabric.Utilities.ErrorCode.\n        ServiceFabricBase = Runtime + 4400,\n\n        TransactionsBase = Runtime + 4500,\n        Transactions_SendingTMRequest = TransactionsBase + 1,\n        Transactions_ReceivedTMResponse = TransactionsBase + 2,\n        Transactions_TMError = TransactionsBase + 3,\n\n        OSBase = Runtime + 4600,\n        OS_InvalidOS = OSBase + 1\n    }\n}\n// ReSharper restore InconsistentNaming\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Logging/LogFormatter.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Globalization;\nusing System.Reflection;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Formats values for logging purposes.\n    /// </summary>\n    public static class LogFormatter\n    {\n        public const int MAX_LOG_MESSAGE_SIZE = 20000;\n        private const string TIME_FORMAT = \"HH:mm:ss.fff 'GMT'\"; // Example: 09:50:43.341 GMT\n        private const string DATE_FORMAT = \"yyyy-MM-dd \" + TIME_FORMAT; // Example: 2010-09-02 09:50:43.341 GMT - Variant of UniversalSorta­bleDateTimePat­tern\n        private static readonly ConcurrentDictionary<Type, Func<Exception, string>> exceptionDecoders = new ConcurrentDictionary<Type, Func<Exception, string>>();\n\n        /// <summary>\n        /// Utility function to convert a <c>DateTime</c> object into printable data format used by the Logger subsystem.\n        /// </summary>\n        /// <param name=\"date\">The <c>DateTime</c> value to be printed.</param>\n        /// <returns>Formatted string representation of the input data, in the printable format used by the Logger subsystem.</returns>\n        public static string PrintDate(DateTime date)\n        {\n            return date.ToString(DATE_FORMAT, CultureInfo.InvariantCulture);\n        }\n\n        /// <summary>\n        /// Parses a date.\n        /// </summary>\n        /// <param name=\"dateStr\">The date string.</param>\n        /// <returns>The parsed date.</returns>\n        public static DateTime ParseDate(string dateStr)\n        {\n            return DateTime.ParseExact(dateStr, DATE_FORMAT, CultureInfo.InvariantCulture);\n        }\n\n        /// <summary>\n        /// Utility function to convert a <c>DateTime</c> object into printable time format used by the Logger subsystem.\n        /// </summary>\n        /// <param name=\"date\">The <c>DateTime</c> value to be printed.</param>\n        /// <returns>Formatted string representation of the input data, in the printable format used by the Logger subsystem.</returns>\n        public static string PrintTime(DateTime date)\n        {\n            return date.ToString(TIME_FORMAT, CultureInfo.InvariantCulture);\n        }\n\n        /// <summary>\n        /// Utility function to convert an exception into printable format, including expanding and formatting any nested sub-expressions.\n        /// </summary>\n        /// <param name=\"exception\">The exception to be printed.</param>\n        /// <returns>Formatted string representation of the exception, including expanding and formatting any nested sub-expressions.</returns>\n        public static string PrintException(Exception exception)\n        {\n            if (exception == null)\n                return \"\";\n\n            var sb = new StringBuilder();\n            PrintException_Helper(sb, exception, 0);\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// Configures the exception decoder for the specified exception type.\n        /// </summary>\n        /// <param name=\"exceptionType\">The exception type to configure a decoder for.</param>\n        /// <param name=\"decoder\">The decoder.</param>\n        public static void SetExceptionDecoder(Type exceptionType, Func<Exception, string> decoder)\n        {\n            exceptionDecoders.TryAdd(exceptionType, decoder);\n        }\n\n        private static void PrintException_Helper(StringBuilder sb, Exception exception, int level)\n        {\n            if (exception == null) return;\n\n            var message = exceptionDecoders.TryGetValue(exception.GetType(), out var decoder) ? decoder(exception) : exception.Message;\n            sb.Append($\"{Environment.NewLine}Exc level {level}: {exception.GetType()}: {message}\");\n\n            if (exception.StackTrace is { } stack)\n            {\n                sb.Append($\"{Environment.NewLine}{stack}\");\n            }\n\n            if (exception is ReflectionTypeLoadException typeLoadException)\n            {\n                var loaderExceptions = typeLoadException.LoaderExceptions;\n                if (loaderExceptions == null || loaderExceptions.Length == 0)\n                {\n                    sb.Append(\"No LoaderExceptions found\");\n                }\n                else\n                {\n                    foreach (Exception? inner in loaderExceptions)\n                    {\n                        if (inner is not null)\n                        {\n                            // call recursively on all loader exceptions. Same level for all.\n                            PrintException_Helper(sb, inner, level + 1);\n                        }\n                    }\n                }\n            }\n            else if (exception.InnerException != null)\n            {\n                if (exception is AggregateException { InnerExceptions: { Count: > 1 } innerExceptions })\n                {\n                    foreach (Exception inner in innerExceptions)\n                    {\n                        // call recursively on all inner exceptions. Same level for all.\n                        PrintException_Helper(sb, inner, level + 1);\n                    }\n                }\n                else\n                {\n                    // call recursively on a single inner exception.\n                    PrintException_Helper(sb, exception.InnerException, level + 1);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/ClusterManifest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Information about types which are available in the cluster.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class ClusterManifest\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterManifest\"/> class.\n        /// </summary>\n        /// <param name=\"version\">\n        /// The manifest version.\n        /// </param>\n        /// <param name=\"silos\">\n        /// The silo manifests.\n        /// </param>\n        public ClusterManifest(\n            MajorMinorVersion version,\n            ImmutableDictionary<SiloAddress, GrainManifest> silos)\n        {\n            Version = version;\n            Silos = silos;\n            AllGrainManifests = silos.Values.ToImmutableArray();\n        }\n\n        /// <summary>\n        /// Gets the version of this instance.\n        /// </summary>\n        [Id(0)]\n        public MajorMinorVersion Version { get; }\n\n        /// <summary>\n        /// Gets the manifests for each silo in the cluster.\n        /// </summary>\n        [Id(1)]\n        public ImmutableDictionary<SiloAddress, GrainManifest> Silos { get; }\n\n        /// <summary>\n        /// Gets all grain manifests.\n        /// </summary>\n        [Id(2)]\n        public ImmutableArray<GrainManifest> AllGrainManifests { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/GrainInterfaceProperties.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Text;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Information about a communication interface.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class GrainInterfaceProperties\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainInterfaceProperties\"/> class.\n        /// </summary>\n        /// <param name=\"values\">\n        /// The interface property values.\n        /// </param>\n        public GrainInterfaceProperties(ImmutableDictionary<string, string> values)\n        {\n            this.Properties = values;\n        }\n\n        /// <summary>\n        /// Gets the properties.\n        /// </summary>\n        [Id(0)]\n        public ImmutableDictionary<string, string> Properties { get; }\n\n        /// <summary>\n        /// Returns a detailed string representation of this instance.\n        /// </summary>\n        /// <returns>\n        /// A detailed, string representation of this instance.\n        /// </returns>\n        public string ToDetailedString()\n        {\n            if (this.Properties is null) return string.Empty;\n            var result = new StringBuilder(\"[\");\n            bool first = true;\n            foreach (var entry in this.Properties)\n            {\n                if (!first)\n                {\n                    result.Append(\", \");\n                }\n\n                result.Append($\"\\\"{entry.Key}\\\": \\\"{entry.Value}\\\"\");\n                first = false;\n            }\n            result.Append(\"]\");\n\n            return result.ToString();\n        }\n    }\n\n    /// <summary>\n    /// Well-known grain interface property keys.\n    /// </summary>\n    /// <seealso cref=\"GrainInterfaceProperties\"/>\n    public static class WellKnownGrainInterfaceProperties\n    {\n        /// <summary>\n        /// The version of this interface encoded as a decimal integer.\n        /// </summary>\n        public const string Version = \"version\";\n\n        /// <summary>\n        /// The encoded <see cref=\"GrainType\"/> corresponding to the primary implementation of an interface.\n        /// This is used for resolving a grain type from an interface.\n        /// </summary>\n        public const string DefaultGrainType = \"primary-grain-type\";\n\n        /// <summary>\n        /// The name of the type of this interface. Used for convention-based matching of primary implementations.\n        /// </summary>\n        public const string TypeName = \"type-name\";\n    }\n\n    /// <summary>\n    /// Provides grain properties.\n    /// </summary>\n    public interface IGrainInterfacePropertiesProvider\n    {\n        /// <summary>\n        /// Adds grain interface properties to <paramref name=\"properties\"/>.\n        /// </summary>\n        /// <param name=\"interfaceType\">\n        /// The interface type.\n        /// </param>\n        /// <param name=\"grainInterfaceType\">\n        /// The interface type id.\n        /// </param>\n        /// <param name=\"properties\">\n        /// The properties collection which this calls to this method should populate.\n        /// </param>\n        void Populate(Type interfaceType, GrainInterfaceType grainInterfaceType, Dictionary<string, string> properties);\n    }\n\n    /// <summary>\n    /// Interface for <see cref=\"Attribute\"/> classes which provide information about a grain interface.\n    /// </summary>\n    public interface IGrainInterfacePropertiesProviderAttribute\n    {\n        /// <summary>\n        /// Adds grain interface properties to <paramref name=\"properties\"/>.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service provider.\n        /// </param>\n        /// <param name=\"interfaceType\">\n        /// The interface type.\n        /// </param>\n        /// <param name=\"properties\">\n        /// The properties collection which this calls to this method should populate.\n        /// </param>\n        void Populate(IServiceProvider services, Type interfaceType, Dictionary<string, string> properties);\n    }\n\n    /// <summary>\n    /// Provides grain interface properties from attributes implementing <see cref=\"IGrainInterfacePropertiesProviderAttribute\"/>.\n    /// </summary>\n    internal sealed class AttributeGrainInterfacePropertiesProvider : IGrainInterfacePropertiesProvider\n    {\n        private readonly IServiceProvider serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AttributeGrainInterfacePropertiesProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public AttributeGrainInterfacePropertiesProvider(IServiceProvider serviceProvider)\n        {\n            this.serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void Populate(Type interfaceType, GrainInterfaceType grainInterfaceType, Dictionary<string, string> properties)\n        {\n            foreach (var attr in interfaceType.GetCustomAttributes(inherit: true))\n            {\n                if (attr is IGrainInterfacePropertiesProviderAttribute providerAttribute)\n                {\n                    providerAttribute.Populate(this.serviceProvider, interfaceType, properties);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Specifies the default grain type to use when constructing a grain reference for this interface without specifying a grain type.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)]\n    public sealed class DefaultGrainTypeAttribute : Attribute, IGrainInterfacePropertiesProviderAttribute\n    {\n        private readonly string grainType;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultGrainTypeAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        public DefaultGrainTypeAttribute(string grainType)\n        {\n            this.grainType = grainType;\n        }\n\n        /// <inheritdoc />\n        void IGrainInterfacePropertiesProviderAttribute.Populate(IServiceProvider services, Type type, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainInterfaceProperties.DefaultGrainType] = this.grainType;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/GrainManifest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Information about available grains.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class GrainManifest\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainManifest\"/> class.\n        /// </summary>\n        /// <param name=\"grains\">\n        /// The grain properties.\n        /// </param>\n        /// <param name=\"interfaces\">\n        /// The interface properties.\n        /// </param>\n        public GrainManifest(\n            ImmutableDictionary<GrainType, GrainProperties> grains,\n            ImmutableDictionary<GrainInterfaceType, GrainInterfaceProperties> interfaces)\n        {\n            this.Interfaces = interfaces;\n            this.Grains = grains;\n        }\n\n        /// <summary>\n        /// Gets the interfaces available on this silo.\n        /// </summary>\n        [Id(0)]\n        public ImmutableDictionary<GrainInterfaceType, GrainInterfaceProperties> Interfaces { get; }\n\n        /// <summary>\n        /// Gets the grain types available on this silo.\n        /// </summary>\n        [Id(1)]\n        public ImmutableDictionary<GrainType, GrainProperties> Grains { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/GrainProperties.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Text;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Information about a logical grain type <see cref=\"GrainType\"/>.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class GrainProperties\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainProperties\"/> class.\n        /// </summary>\n        /// <param name=\"values\">\n        /// The underlying property collection.\n        /// </param>\n        public GrainProperties(ImmutableDictionary<string, string> values)\n        {\n            this.Properties = values;\n        }\n\n        /// <summary>\n        /// Gets the properties.\n        /// </summary>\n        [Id(0)]\n        public ImmutableDictionary<string, string> Properties { get; }\n\n        /// <summary>\n        /// Returns a detailed, string representation of this instance.\n        /// </summary>\n        /// <returns>\n        /// A detailed, string representation of this instance.\n        /// </returns>\n        public string ToDetailedString()\n        {\n            if (this.Properties is null) return string.Empty;\n            var result = new StringBuilder(\"[\");\n            bool first = true;\n            foreach (var entry in this.Properties)\n            {\n                if (!first)\n                {\n                    result.Append(\", \");\n                }\n\n                result.Append($\"\\\"{entry.Key}\\\": \\\"{entry.Value}\\\"\");\n                first = false;\n            }\n            result.Append(\"]\");\n\n            return result.ToString();\n        }\n    }\n\n    /// <summary>\n    /// Well-known grain properties.\n    /// </summary>\n    /// <seealso cref=\"GrainProperties\"/>\n    public static class WellKnownGrainTypeProperties\n    {\n        /// <summary>\n        /// The name of the placement strategy for grains of this type.\n        /// </summary>\n        public const string PlacementStrategy = \"placement-strategy\";\n\n        /// <summary>\n        /// The name of the placement strategy for grains of this type.\n        /// </summary>\n        public const string PlacementFilter = \"placement-filter\";\n\n        /// <summary>\n        /// The directory policy for grains of this type.\n        /// </summary>\n        public const string GrainDirectory = \"directory-policy\";\n\n        /// <summary>\n        /// Whether or not messages to this grain are unordered.\n        /// </summary>\n        public const string Unordered = \"unordered\";\n\n        /// <summary>\n        /// Prefix for keys which indicate <see cref=\"GrainInterfaceType\"/> of interfaces which a grain class implements.\n        /// </summary>\n        public const string ImplementedInterfacePrefix = \"interface.\";\n\n        /// <summary>\n        /// The period after which an idle grain will be deactivated.\n        /// </summary>\n        public const string IdleDeactivationPeriod = \"idle-duration\";\n\n        /// <summary>\n        /// The value for <see cref=\"IdleDeactivationPeriod\"/> used to specify that the grain should not be deactivated due to idleness.\n        /// </summary>\n        public const string IndefiniteIdleDeactivationPeriodValue = \"indefinite\";\n\n        /// <summary>\n        /// The name of the primary implementation type. Used for convention-based matching of primary interface implementations.\n        /// </summary>\n        public const string TypeName = \"type-name\";\n\n        /// <summary>\n        /// The full name of the primary implementation type. Used for prefix-based matching of implementations.\n        /// </summary>\n        public const string FullTypeName = \"full-type-name\";\n\n        /// <summary>\n        /// The prefix for binding declarations\n        /// </summary>\n        public const string BindingPrefix = \"binding\";\n\n        /// <summary>\n        /// The key for defining a binding type.\n        /// </summary>\n        public const string BindingTypeKey = \"type\";\n\n        /// <summary>\n        /// The binding type for Orleans streams.\n        /// </summary>\n        public const string StreamBindingTypeValue = \"stream\";\n\n        /// <summary>\n        /// The binding type for Broadcast Channels.\n        /// </summary>\n        public const string BroadcastChannelBindingTypeValue = \"broadcast-channel\";\n\n        /// <summary>\n        /// The key to specify a stream binding pattern.\n        /// </summary>\n        public const string StreamBindingPatternKey = \"pattern\";\n\n        /// <summary>\n        /// The key to specify a channel binding pattern.\n        /// </summary>\n        public const string BroadcastChannelBindingPatternKey = \"channel-pattern\";\n\n        /// <summary>\n        /// The key to specify a stream id mapper\n        /// </summary>\n        public const string StreamIdMapperKey = \"streamid-mapper\";\n\n        /// <summary>\n        /// The key to specify a channel id mapper\n        /// </summary>\n        public const string ChannelIdMapperKey = \"channelid-mapper\";\n\n        /// <summary>\n        /// Whether to include the namespace name in the grain id.\n        /// </summary>\n        public const string StreamBindingIncludeNamespaceKey = \"include-namespace\";\n\n        /// <summary>\n        /// Key type of the grain, if it implement a legacy interface. Valid values are nameof(String), nameof(Int64) and nameof(Guid)\n        /// </summary>\n        public const string LegacyGrainKeyType = \"legacy-grain-key-type\";\n\n        /// <summary>\n        /// Whether a grain is reentrant or not.\n        /// </summary>\n        public const string Reentrant = \"reentrant\";\n\n        /// <summary>\n        /// Specifies the name of a method used to determine if a request can interleave other requests.\n        /// </summary>\n        public const string MayInterleavePredicate = \"may-interleave-predicate\";\n\n        /// <summary>\n        /// Whether a grain can be migrated by active-rebalancing or not.\n        /// </summary>\n        public const string Immovable = \"immovable\";\n    }\n\n    /// <summary>\n    /// Provides grain properties.\n    /// </summary>\n    public interface IGrainPropertiesProvider\n    {\n        /// <summary>\n        /// Adds grain properties to <paramref name=\"properties\"/>.\n        /// </summary>\n        /// <param name=\"grainClass\">\n        /// The grain class.\n        /// </param>\n        /// <param name=\"grainType\">\n        /// The grain type id.\n        /// </param>\n        /// <param name=\"properties\">\n        /// The properties collection which calls to this method should populate.\n        /// </param>\n        void Populate(Type grainClass, GrainType grainType, Dictionary<string, string> properties);\n    }\n\n    /// <summary>\n    /// Interface for <see cref=\"Attribute\"/> classes which provide information about a grain.\n    /// </summary>\n    public interface IGrainPropertiesProviderAttribute\n    {\n        /// <summary>\n        /// Adds grain properties to <paramref name=\"properties\"/>.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service provider.\n        /// </param>\n        /// <param name=\"grainClass\">\n        /// The grain class.\n        /// </param>\n        /// <param name=\"grainType\">\n        /// The grain type id.\n        /// </param>\n        /// <param name=\"properties\">\n        /// The properties collection which calls to this method should populate.\n        /// </param>\n        void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties);\n    }\n\n    /// <summary>\n    /// Provides grain interface properties from attributes implementing <see cref=\"IGrainPropertiesProviderAttribute\"/>.\n    /// </summary>\n    public sealed class AttributeGrainPropertiesProvider : IGrainPropertiesProvider\n    {\n        private readonly IServiceProvider serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AttributeGrainPropertiesProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public AttributeGrainPropertiesProvider(IServiceProvider serviceProvider)\n        {\n            this.serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void Populate(Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            foreach (var attr in grainClass.GetCustomAttributes(inherit: true))\n            {\n                if (attr is IGrainPropertiesProviderAttribute providerAttribute)\n                {\n                    providerAttribute.Populate(this.serviceProvider, grainClass, grainType, properties);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Interface for <see cref=\"Attribute\"/> classes which provide information about a grain.\n    /// </summary>\n    public interface IGrainBindingsProviderAttribute\n    {\n        /// <summary>\n        /// Gets bindings for the type this attribute is attached to.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service provider.\n        /// </param>\n        /// <param name=\"grainClass\">\n        /// The grain class.\n        /// </param>\n        /// <param name=\"grainType\">\n        /// The grain type.\n        /// </param>\n        /// <returns>\n        /// The bindings for the specified grain.\n        /// </returns>\n        IEnumerable<Dictionary<string, string>> GetBindings(IServiceProvider services, Type grainClass, GrainType grainType);\n    }\n\n    /// <summary>\n    /// Provides grain interface properties from attributes implementing <see cref=\"IGrainPropertiesProviderAttribute\"/>.\n    /// </summary>\n    public sealed class AttributeGrainBindingsProvider : IGrainPropertiesProvider\n    {\n        /// <summary>\n        /// A hopefully unique name to describe bindings added by this provider.\n        /// Binding names are meaningless and are only used to group properties for a given binding together.\n        /// </summary>\n        private const string BindingPrefix = WellKnownGrainTypeProperties.BindingPrefix + \".attr-\";\n        private readonly IServiceProvider serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AttributeGrainBindingsProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public AttributeGrainBindingsProvider(IServiceProvider serviceProvider)\n        {\n            this.serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void Populate(Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            var bindingIndex = 1;\n            foreach (var attr in grainClass.GetCustomAttributes(inherit: true))\n            {\n                if (!(attr is IGrainBindingsProviderAttribute providerAttribute))\n                {\n                    continue;\n                }\n\n                foreach (var binding in providerAttribute.GetBindings(this.serviceProvider, grainClass, grainType))\n                {\n                    foreach (var pair in binding)\n                    {\n                        properties[BindingPrefix + bindingIndex.ToString(CultureInfo.InvariantCulture) + '.' + pair.Key] = pair.Value;\n                    }\n\n                    ++bindingIndex;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/IGrainTypeProvider.cs",
    "content": "using System;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Associates a <see cref=\"GrainType\"/> with a grain class.\n    /// </summary>\n    public interface IGrainTypeProvider\n    {\n        /// <summary>\n        /// Returns the grain type corresponding to the class identified by <paramref name=\"type\"/>.\n        /// </summary>\n        bool TryGetGrainType(Type type, out GrainType grainType);\n    }\n\n    /// <summary>\n    /// Gets the corresponding <see cref=\"GrainType\"/> for a grain class from an <see cref=\"Attribute\"/>\n    /// implementing <see cref=\"IGrainTypeProviderAttribute\"/> on that class.\n    /// </summary>\n    public class AttributeGrainTypeProvider : IGrainTypeProvider\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AttributeGrainTypeProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">\n        /// The service provider.\n        /// </param>\n        public AttributeGrainTypeProvider(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public bool TryGetGrainType(Type grainClass, out GrainType grainType)\n        {\n            foreach (var attr in grainClass.GetCustomAttributes(inherit: false))\n            {\n                if (attr is IGrainTypeProviderAttribute typeProviderAttribute)\n                {\n                    grainType = typeProviderAttribute.GetGrainType(this._serviceProvider, grainClass);\n                    return true;\n                }\n            }\n\n            grainType = default;\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Functionality which can be implemented by a custom <see cref=\"Attribute\"/> which implements this specifies the <see cref=\"GrainType\"/> of the\n    /// type which it is attached to.\n    /// </summary>\n    public interface IGrainTypeProviderAttribute\n    {\n        /// <summary>\n        /// Gets the <see cref=\"GrainType\"/> for the attached <see cref=\"Type\"/>.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service provider.\n        /// </param>\n        /// <param name=\"type\">\n        /// The grain class.\n        /// </param>\n        GrainType GetGrainType(IServiceProvider services, Type type);\n    }\n}\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Specifies the grain type of the grain class which it is attached to.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class GrainTypeAttribute : Attribute, IGrainTypeProviderAttribute\n    {\n        /// <summary>\n        /// The grain type name.\n        /// </summary>\n        private readonly GrainType _grainType;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainTypeAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"grainType\">\n        /// The grain type name.\n        /// </param>\n        public GrainTypeAttribute(string grainType)\n        {\n            this._grainType = GrainType.Create(grainType);\n        }\n\n        /// <inheritdoc />\n        public GrainType GetGrainType(IServiceProvider services, Type type) => this._grainType;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Manifest/MajorMinorVersion.cs",
    "content": "using System;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Represents a version with two components, a major (most-significant) component, and a minor (least-significant) component.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct MajorMinorVersion : IComparable<MajorMinorVersion>, IEquatable<MajorMinorVersion>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MajorMinorVersion\"/> struct.\n        /// </summary>\n        /// <param name=\"majorVersion\">The major version component.</param>\n        /// <param name=\"minorVersion\">The minor version component.</param>\n        public MajorMinorVersion(long majorVersion, long minorVersion)\n        {\n            Major = majorVersion;\n            Minor = minorVersion;\n        }\n\n        /// <summary>\n        /// Gets the zero value.\n        /// </summary>\n        public static MajorMinorVersion Zero => new(0, 0);\n\n        /// <summary>\n        /// Gets the minimum value.\n        /// </summary>\n        public static MajorMinorVersion MinValue => new(long.MinValue, long.MinValue);\n\n        /// <summary>\n        /// Gets the most significant version component.\n        /// </summary>\n        [Id(0)]\n        public long Major { get; }\n\n        /// <summary>\n        /// Gets the least significant version component.\n        /// </summary>\n        [Id(1)]\n        public long Minor { get; }\n\n        /// <inheritdoc />\n        public int CompareTo(MajorMinorVersion other)\n        {\n            var major = Major.CompareTo(other.Major);\n            if (major != 0) return major;\n\n            return Minor.CompareTo(other.Minor);\n        }\n\n        /// <inheritdoc />\n        public bool Equals(MajorMinorVersion other) => Major == other.Major && Minor == other.Minor;\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => obj is MajorMinorVersion other && this.Equals(other);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => HashCode.Combine(Major, Minor);\n\n        /// <summary>\n        /// Parses a <see cref=\"MajorMinorVersion\"/>.\n        /// </summary>\n        /// <param name=\"value\">\n        /// The string representation.\n        /// </param>\n        /// <returns>\n        /// The parsed <see cref=\"MajorMinorVersion\"/> value.\n        /// </returns>\n        public static MajorMinorVersion Parse(string value)\n        {\n            if (string.IsNullOrWhiteSpace(value)) throw new ArgumentNullException(nameof(value));\n\n            var i = value.IndexOf('.');\n            if (i < 0) throw new ArgumentException(nameof(value));\n            return new MajorMinorVersion(long.Parse(value[..i]), long.Parse(value[(i + 1)..]));\n        }\n\n        /// <inheritdoc />\n        public override string ToString() => $\"{Major}.{Minor}\";\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(MajorMinorVersion left, MajorMinorVersion right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(MajorMinorVersion left, MajorMinorVersion right) => !left.Equals(right);\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >=(MajorMinorVersion left, MajorMinorVersion right) => left.CompareTo(right) >= 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <=(MajorMinorVersion left, MajorMinorVersion right) => left.CompareTo(right) <= 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >(MajorMinorVersion left, MajorMinorVersion right) => left.CompareTo(right) > 0;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <(MajorMinorVersion left, MajorMinorVersion right) => left.CompareTo(right) < 0;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Orleans.Core.Abstractions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Core.Abstractions</PackageId>\n    <Title>Microsoft Orleans Core Abstractions</Title>\n    <Description>Core abstractions library of Microsoft Orleans</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <RootNamespace>Orleans</RootNamespace>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\"buildMultiTargeting\\Microsoft.Orleans.Core.Abstractions.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"buildTransitive\\Microsoft.Orleans.Core.Abstractions.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"build\\Microsoft.Orleans.Core.Abstractions.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Abstractions\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.GrainDirectory.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Placement.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Reminders\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.Abstractions\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.EventHubs.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.TestingHost\" />\n    <InternalsVisibleTo Include=\"TestInternalGrainInterfaces\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/ActivationCountBasedPlacement.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// A placement strategy which attempts to achieve approximately even load based upon the number of recently-active grains on each server.\n    /// </summary>\n    /// <remarks>\n    /// The intention of this placement strategy is to place new grain activations on the least heavily loaded server based on the number of recently busy grains.\n    /// It includes a mechanism in which all servers periodically publish their total activation count to all other servers.\n    /// The placement director then selects a server which is predicted to have the fewest activations by examining the most recently\n    /// reported activation count and a making prediction of the current activation count based upon the recent activation count made by\n    /// the placement director on the current server. The director selects a number of servers at random when making this prediction,\n    /// in an attempt to avoid multiple separate servers overloading the same server. By default, two servers are selected at random,\n    /// but this value is configurable via <c>Orleans.Runtime.ActivationCountBasedPlacementOptions</c>.\n    /// <br/>\n    /// This algorithm is based on the thesis The Power of Two Choices in Randomized Load Balancing by Michael David Mitzenmacher <see href=\"https://www.eecs.harvard.edu/~michaelm/postscripts/mythesis.pdf\"/>,\n    /// and is also used in NGINX for distributed load balancing, as described in the article NGINX and the \"Power of Two Choices\" Load-Balancing Algorithm <see href=\"https://www.nginx.com/blog/nginx-power-of-two-choices-load-balancing-algorithm/\"/>.\n    /// <br/>\n    /// This placement strategy is configured by adding the <see cref=\"Orleans.Placement.ActivationCountBasedPlacementAttribute\"/> attribute to a grain.\n    /// </remarks>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class ActivationCountBasedPlacement : PlacementStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        internal static ActivationCountBasedPlacement Singleton { get; } = new ActivationCountBasedPlacement();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/ClientObserversPlacement.cs",
    "content": "namespace Orleans.Runtime\n{\n    [GenerateSerializer, Immutable, SuppressReferenceTracking]\n    internal class ClientObserversPlacement : PlacementStrategy\n    {\n        public static ClientObserversPlacement Instance { get; } = new();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/HashBasedPlacement.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Places activations on compatible silos by hashing the grain identifier using a stable hash and selecting a silo from a sorted set using a modulo operation.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class HashBasedPlacement : PlacementStrategy\n    {\n        internal static HashBasedPlacement Singleton { get; } = new HashBasedPlacement();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/PlacementAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing static Orleans.Placement.ImmovableAttribute;\n\nnamespace Orleans.Placement\n{\n    /// <summary>\n    /// Base for all placement policy marker attributes.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public abstract class PlacementAttribute : Attribute, IGrainPropertiesProviderAttribute\n    {\n        public PlacementStrategy PlacementStrategy { get; private set; }\n\n        protected PlacementAttribute(PlacementStrategy placement)\n        {\n            if (placement == null) throw new ArgumentNullException(nameof(placement));\n\n            this.PlacementStrategy = placement;\n        }\n\n        /// <inheritdoc />\n        public virtual void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            this.PlacementStrategy?.PopulateGrainProperties(services, grainClass, grainType, properties);\n        }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"RandomPlacement\"/> policy.\n    /// </summary>\n    /// <remarks>\n    /// This is the default placement policy, so this attribute does not need to be used for normal grains.\n    /// </remarks>\n    /// <inheritdoc cref=\"RandomPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class RandomPlacementAttribute : PlacementAttribute\n    {\n        public RandomPlacementAttribute() :\n            base(RandomPlacement.Singleton)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"HashBasedPlacement\"/> policy.\n    /// </summary>\n    /// <inheritdoc cref=\"HashBasedPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class HashBasedPlacementAttribute : PlacementAttribute\n    {\n        public HashBasedPlacementAttribute() :\n            base(HashBasedPlacement.Singleton)\n        { }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"PreferLocalPlacement\"/> policy.\n    /// </summary>\n    /// <inheritdoc cref=\"PreferLocalPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class PreferLocalPlacementAttribute : PlacementAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PreferLocalPlacementAttribute\"/> class.\n        /// </summary>\n        public PreferLocalPlacementAttribute()\n            : base(PreferLocalPlacement.Singleton)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"ActivationCountBasedPlacement\"/> policy, which attempts to balance\n    /// grain placement across servers based upon the relative number of recently active grains on each one.\n    /// </summary>\n    /// <inheritdoc cref=\"ActivationCountBasedPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class ActivationCountBasedPlacementAttribute : PlacementAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ActivationCountBasedPlacementAttribute\"/> class.\n        /// </summary>\n        public ActivationCountBasedPlacementAttribute()\n            : base(ActivationCountBasedPlacement.Singleton)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"SiloRoleBasedPlacement\"/> policy.\n    /// </summary>\n    /// <inheritdoc cref=\"SiloRoleBasedPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class SiloRoleBasedPlacementAttribute : PlacementAttribute\n    {\n        public SiloRoleBasedPlacementAttribute() :\n            base(SiloRoleBasedPlacement.Singleton)\n        { }\n    }\n\n    /// <summary>\n    /// Marks a grain class as using the <see cref=\"ResourceOptimizedPlacement\"/> policy.\n    /// </summary>\n    /// <inheritdoc cref=\"ResourceOptimizedPlacement\"/>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class ResourceOptimizedPlacementAttribute : PlacementAttribute\n    {\n        public ResourceOptimizedPlacementAttribute() :\n            base(ResourceOptimizedPlacement.Singleton)\n        { }\n    }\n\n    /// <summary>\n    /// Ensures that activations of this grain type will not be migrated automatically.\n    /// </summary>\n    /// <remarks>Activations can still be migrated by user initiated code.</remarks>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class ImmovableAttribute(ImmovableKind kind = ImmovableKind.Any)\n        : Attribute, IGrainPropertiesProviderAttribute\n    {\n        /// <summary>\n        /// The kind of immovability.\n        /// </summary>\n        public ImmovableKind Kind { get; } = kind;\n\n        /// <inheritdoc/>\n        public void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n            => properties[WellKnownGrainTypeProperties.Immovable] = ((byte)Kind).ToString();\n    }\n\n    /// <summary>\n    /// Emphasizes that immovability is restricted to certain components.\n    /// </summary>\n    [Flags]\n    public enum ImmovableKind : byte\n    {\n        /// <summary>\n        /// Activations of this grain type will not be migrated by the repartitioner.\n        /// </summary>\n        Repartitioner = 1,\n        /// <summary>\n        /// Activations of this grain type will not be migrated by the rebalancer.\n        /// </summary>\n        Rebalancer = 2,\n        /// <summary>\n        /// Activations of this grain type will not be migrated by anything.\n        /// </summary>\n        Any = Repartitioner | Rebalancer\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/PlacementFilterAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.Placement;\n\n/// <summary>\n/// Base for all placement filter marker attributes.\n/// </summary>\n[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\npublic abstract class PlacementFilterAttribute : Attribute, IGrainPropertiesProviderAttribute\n{\n    /// <summary>\n    /// Gets the placement filter strategy.\n    /// </summary>\n    public PlacementFilterStrategy PlacementFilterStrategy { get; private set; }\n\n    protected PlacementFilterAttribute(PlacementFilterStrategy placement)\n    {\n        ArgumentNullException.ThrowIfNull(placement);\n        PlacementFilterStrategy = placement;\n    }\n\n    /// <inheritdoc />\n    public virtual void Populate(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        => PlacementFilterStrategy?.PopulateGrainProperties(services, grainClass, grainType, properties);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/PlacementFilterStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.Placement;\n\n/// <summary>\n/// Represents a strategy for filtering silos which a grain can be placed on.\n/// </summary>\npublic abstract class PlacementFilterStrategy\n{\n    public int Order { get; private set; }\n\n    protected PlacementFilterStrategy(int order)\n    {\n        Order = order;\n    }\n\n    /// <summary>\n    /// Initializes an instance of this type using the provided grain properties.\n    /// </summary>\n    /// <param name=\"properties\">\n    /// The grain properties.\n    /// </param>\n    public void Initialize(GrainProperties properties)\n    {\n        var orderProperty = GetPlacementFilterGrainProperty(\"order\", properties);\n        if (!int.TryParse(orderProperty, out var parsedOrder))\n        {\n            throw new ArgumentException(\"Invalid order property value.\");\n        }\n\n        Order = parsedOrder;\n\n        AdditionalInitialize(properties);\n    }\n\n    public virtual void AdditionalInitialize(GrainProperties properties)\n    {\n    }\n\n    /// <summary>\n    /// Populates grain properties to specify the preferred placement strategy.\n    /// </summary>\n    /// <param name=\"services\">The service provider.</param>\n    /// <param name=\"grainClass\">The grain class.</param>\n    /// <param name=\"grainType\">The grain type.</param>\n    /// <param name=\"properties\">The grain properties which will be populated by this method call.</param>\n    public void PopulateGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n    {\n        var typeName = GetType().Name;\n        if (properties.TryGetValue(WellKnownGrainTypeProperties.PlacementFilter, out var existingValue))\n        {\n            properties[WellKnownGrainTypeProperties.PlacementFilter] = $\"{existingValue},{typeName}\";\n        }\n        else\n        {\n            properties[WellKnownGrainTypeProperties.PlacementFilter] = typeName;\n        }\n\n        properties[$\"{WellKnownGrainTypeProperties.PlacementFilter}.{typeName}.order\"] = Order.ToString(CultureInfo.InvariantCulture);\n\n        foreach (var additionalGrainProperty in GetAdditionalGrainProperties(services, grainClass, grainType, properties))\n        {\n            properties[$\"{WellKnownGrainTypeProperties.PlacementFilter}.{typeName}.{additionalGrainProperty.Key}\"] = additionalGrainProperty.Value;\n        }\n    }\n\n    protected string? GetPlacementFilterGrainProperty(string key, GrainProperties properties)\n    {\n        var typeName = GetType().Name;\n        return properties.Properties.TryGetValue($\"{WellKnownGrainTypeProperties.PlacementFilter}.{typeName}.{key}\", out var value) ? value : null;\n    }\n\n    protected virtual IEnumerable<KeyValuePair<string, string>> GetAdditionalGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType, IReadOnlyDictionary<string, string> existingProperties)\n        => Array.Empty<KeyValuePair<string, string>>();\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/PlacementStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The base type for all placement strategies.\n    /// </summary>\n    /// <remarks>\n    /// Orleans uses a configurable placement system to decide which server to place a grain on.\n    /// Placement directors are used to decide where a grain activation should be placed.\n    /// Placement directors are associated with grains using a placement strategy.\n    /// Grains indicate their preferred placement strategy using an attribute on the grain class.\n    /// </remarks>\n    [Serializable, SerializerTransparent]\n    public abstract class PlacementStrategy\n    {\n        /// <summary>\n        /// Gets a value indicating whether or not this placement strategy requires activations to be registered in\n        /// the grain directory.\n        /// </summary>\n        public virtual bool IsUsingGrainDirectory => true;\n\n        /// <summary>\n        /// Initializes an instance of this type using the provided grain properties.\n        /// </summary>\n        /// <param name=\"properties\">\n        /// The grain properties.\n        /// </param>\n        public virtual void Initialize(GrainProperties properties)\n        {\n        }\n\n        /// <summary>\n        /// Populates grain properties to specify the preferred placement strategy.\n        /// </summary>\n        /// <param name=\"services\">The service provider.</param>\n        /// <param name=\"grainClass\">The grain class.</param>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"properties\">The grain properties which will be populated by this method call.</param>\n        public virtual void PopulateGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[WellKnownGrainTypeProperties.PlacementStrategy] = this.GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/PreferLocalPlacement.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The prefer local placement strategy indicates that a grain should always be placed on the local host if the grain\n    /// is not already active elsewhere in the cluster and the local host is compatible with it.\n    /// </summary>\n    /// <remarks>\n    /// If the host is not compatible with the grain type or if a grain receives an incompatible request, the grain will be\n    /// placed on a random, compatible server.\n    /// </remarks>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class PreferLocalPlacement : PlacementStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        internal static PreferLocalPlacement Singleton { get; } = new PreferLocalPlacement();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/RandomPlacement.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The random placement strategy specifies that new activations of a grain should be placed on a random, compatible server.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class RandomPlacement : PlacementStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        internal static RandomPlacement Singleton { get; } = new RandomPlacement();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/ResourceOptimizedPlacement.cs",
    "content": "namespace Orleans.Runtime;\n\n/// <summary>\n/// A placement strategy which attempts to optimize resource distribution across the cluster.\n/// </summary>\n/// <remarks>\n/// <para>It assigns weights to runtime statistics to prioritize different resources and calculates a normalized score for each silo.\n/// Following the <u>power of k-choices</u> algorithm, K silos are picked as potential targets, where K is equal to the square root of the number of silos.\n/// Out of those K silos, the one with the lowest score is chosen for placing the activation. Normalization ensures that each property contributes proportionally\n/// to the overall score. You can adjust the weights based on your specific requirements and priorities for load balancing.\n/// In addition to normalization, an <u>online adaptive</u> algorithm provides a smoothing effect (filters out high frequency components) and avoids rapid signal\n/// drops by transforming it into a polynomial-like decay process. This contributes to avoiding resource saturation on the silos and especially newly joined silos.</para>\n/// <para>Silos which are overloaded by definition of the load shedding mechanism are not considered as candidates for new placements.</para>\n/// <para><i>This placement strategy is configured by adding the <see cref=\"Placement.ResourceOptimizedPlacementAttribute\"/> attribute to a grain.</i></para>\n/// </remarks>\n[GenerateSerializer, Immutable, SuppressReferenceTracking]\npublic sealed class ResourceOptimizedPlacement : PlacementStrategy\n{\n    internal static readonly ResourceOptimizedPlacement Singleton = new();\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/SiloRoleBasedPlacement.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The silo role placement strategy specifies that a grain should be placed on a compatible silo which has the role specified by the strategy's placement attribute.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public class SiloRoleBasedPlacement : PlacementStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        internal static SiloRoleBasedPlacement Singleton { get; } = new SiloRoleBasedPlacement();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/StatelessWorkerPlacement.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The stateless worker placement strategy allows multiple instances of a given grain to co-exist simultaneously on any host and is reserved for stateless worker grains.\n    /// </summary>\n    [Serializable, GenerateSerializer]\n    internal sealed class StatelessWorkerPlacement : PlacementStrategy\n    {\n        private const string MaxLocalPropertyKey = \"max-local-instances\";\n        private const string RemoveIdleWorkersPropertyKey = \"remove-idle-workers\";\n\n        private static readonly int DefaultMaxStatelessWorkers = Environment.ProcessorCount;\n\n        /// <inheritdoc/>\n        public override bool IsUsingGrainDirectory => false;\n\n        /// <summary>\n        /// Gets the maximum number of local instances which can be simultaneously active for a given grain.\n        /// </summary>\n        [Id(0)]\n        public int MaxLocal { get; private set; }\n\n        /// <summary>\n        /// When set to <see langword=\"true\"/>, idle workers will be proactively deactivated by the runtime.\n        /// Otherwise if <see langword=\"false\"/>, than the workers will be deactivated according to collection age.\n        /// </summary>\n        [Id(1)]\n        public bool RemoveIdleWorkers { get; private set; } = true;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerPlacement\"/> class.\n        /// </summary>\n        /// <param name=\"maxLocal\">\n        /// The maximum number of local instances which can be simultaneously active for a given grain.\n        /// </param>\n        internal StatelessWorkerPlacement(int maxLocal) : this(maxLocal, true)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerPlacement\"/> class.\n        /// </summary>\n        /// <param name=\"maxLocal\">\n        /// The maximum number of local instances which can be simultaneously active for a given grain.\n        /// </param>\n        /// <param name=\"removeIdleWorkers\">\n        /// Whether idle workers will be proactively deactivated by the runtime instead of only being deactivated according to collection age.\n        /// </param>\n        internal StatelessWorkerPlacement(int maxLocal, bool removeIdleWorkers)\n        {\n            // If maxLocal was not specified on the StatelessWorkerAttribute,\n            // we will use the defaultMaxStatelessWorkers, which is System.Environment.ProcessorCount.\n            this.MaxLocal = maxLocal > 0 ? maxLocal : DefaultMaxStatelessWorkers;\n            this.RemoveIdleWorkers = removeIdleWorkers;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StatelessWorkerPlacement\"/> class.\n        /// </summary>\n        public StatelessWorkerPlacement() : this(-1)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"StatelessWorkerPlacement(MaxLocal={MaxLocal}, RemoveIdleWorkers={RemoveIdleWorkers})\";\n\n        /// <inheritdoc/>\n        public override void Initialize(GrainProperties properties)\n        {\n            base.Initialize(properties);\n\n            if (properties.Properties.TryGetValue(MaxLocalPropertyKey, out var maxLocalValue) &&\n                !string.IsNullOrWhiteSpace(maxLocalValue))\n            {\n                if (int.TryParse(maxLocalValue, out var maxLocal))\n                {\n                    MaxLocal = maxLocal;\n                }\n            }\n\n            if (properties.Properties.TryGetValue(RemoveIdleWorkersPropertyKey, out var removeIdleValue) &&\n                !string.IsNullOrWhiteSpace(removeIdleValue))\n            {\n                if (bool.TryParse(removeIdleValue, out var removeIdle))\n                {\n                    RemoveIdleWorkers = removeIdle;\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void PopulateGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            properties[MaxLocalPropertyKey] = MaxLocal.ToString(CultureInfo.InvariantCulture);\n            properties[RemoveIdleWorkersPropertyKey] = RemoveIdleWorkers.ToString(CultureInfo.InvariantCulture);\n\n            base.PopulateGrainProperties(services, grainClass, grainType, properties);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Placement/SystemTargetPlacementStrategy.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// The placement strategy used by system targets.\n    /// </summary>\n    [GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class SystemTargetPlacementStrategy : PlacementStrategy\n    {\n        public static SystemTargetPlacementStrategy Instance { get; } = new();\n\n        public override bool IsUsingGrainDirectory => false;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Properties/IsExternalInit.cs",
    "content": "namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Providers/IProviderBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\n\nnamespace Orleans.Providers;\n\n/// <summary>\n/// Interface for providers which configure Orleans services.\n/// </summary>\n/// <typeparam name=\"TBuilder\">The type of the builder, such as <c>ISiloBuilder</c> or <c>IClientBuilder</c>.</typeparam>\npublic interface IProviderBuilder<TBuilder>\n{\n    /// <summary>\n    /// Configures the provider.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <param name=\"name\">The provider name, or <see langword=\"null\"/> if no name is specified.</param>\n    /// <param name=\"configurationSection\">The configuration section containing provider configuration.</param>\n    void Configure(TBuilder builder, string? name, IConfigurationSection configurationSection);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Providers/ProviderConstants.cs",
    "content": "namespace Orleans.Providers\n{\n    /// <summary>\n    /// Constant values used by providers.\n    /// </summary>\n    public static class ProviderConstants\n    {\n        /// <summary>\n        /// The default storage provider name.\n        /// </summary>\n        public const string DEFAULT_STORAGE_PROVIDER_NAME = \"Default\";\n\n        /// <summary>\n        /// The default log consistency provider name.\n        /// </summary>\n        public const string DEFAULT_LOG_CONSISTENCY_PROVIDER_NAME = \"Default\";\n\n        public const string DEFAULT_PUBSUB_PROVIDER_NAME = \"PubSubStore\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Providers/ProviderGrainAttributes.cs",
    "content": "using System;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// The [Orleans.Providers.StorageProvider] attribute is used to define which storage provider to use for persistence of grain state.\n    /// <para>\n    /// Specifying [Orleans.Providers.StorageProvider] property is recommended for all grains which extend Grain&lt;T&gt;.\n    /// If no [Orleans.Providers.StorageProvider] attribute is  specified, then a \"Default\" storage provider will be used.\n    /// If a suitable storage provider cannot be located for this grain, then the grain will fail to load into the Silo.\n    /// </para>\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class StorageProviderAttribute : Attribute\n    {\n        /// <summary>\n        /// Gets or sets the name of the provider to be used for persisting of grain state.\n        /// </summary>\n        public string ProviderName { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StorageProviderAttribute\"/> class.\n        /// </summary>\n        public StorageProviderAttribute()\n        {\n            ProviderName = ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME;\n        }\n    }\n\n    /// <summary>\n    /// The [Orleans.Providers.LogConsistencyProvider] attribute is used to define which consistency provider to use for grains using the log-view state abstraction.\n    /// <para>\n    /// Specifying [Orleans.Providers.LogConsistencyProvider] property is recommended for all grains that derive\n    /// from LogConsistentGrain, such as JournaledGrain.\n    /// If no [Orleans.Providers.LogConsistencyProvider] attribute is  specified, then the runtime tries to locate\n    /// one as follows. First, it looks for a\n    /// \"Default\" provider in the configuration file, then it checks if the grain type defines a default.\n    /// If a consistency provider cannot be located for this grain, then the grain will fail to load into the Silo.\n    /// </para>\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class LogConsistencyProviderAttribute : Attribute\n    {\n        /// <summary>\n        /// Gets or sets name of the provider to be used for consistency.\n        /// </summary>\n        public string ProviderName { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LogConsistencyProviderAttribute\"/> class.\n        /// </summary>\n        public LogConsistencyProviderAttribute()\n        {\n            ProviderName = ProviderConstants.DEFAULT_LOG_CONSISTENCY_PROVIDER_NAME;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/README.md",
    "content": "# Microsoft Orleans Core Abstractions\n\n## Introduction\nMicrosoft Orleans Core Abstractions is the foundational library for Orleans containing the public programming APIs for implementing grains and client code. This package defines the core abstractions that form the Orleans programming model, including grain interfaces, grain reference interfaces, and attributes.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Core.Abstractions\n```\n\nThis package is a dependency of both client and silo (server) applications and is automatically included when you reference the Orleans SDK or the Orleans client/server metapackages.\n\n## Example - Defining a Grain Interface\n```csharp\nusing Orleans;\n\nnamespace MyGrainInterfaces;\n\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain interfaces](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-interfaces)\n- [Grain references](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-references)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/AsyncEnumerableRequest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.ExceptionServices;\nusing System.Runtime.Serialization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Diagnostics;\nusing Orleans.Invocation;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Identifies enumeration results.\n/// </summary>\n[GenerateSerializer]\npublic enum EnumerationResult\n{\n    /// <summary>\n    /// This result represents a heartbeat. Issue a subsequent enumeration call to receive a new result.\n    /// </summary>\n    Heartbeat = 1,\n\n    /// <summary>\n    /// This result represents a value from the enumeration.\n    /// </summary>\n    Element = 1 << 1,\n\n    /// <summary>\n    /// This result represents a sequence of values from the enumeration.\n    /// </summary>\n    Batch = 1 << 2,\n\n    /// <summary>\n    /// This result indicates that enumeration has completed and that no further results will be produced.\n    /// </summary>\n    Completed = 1 << 3,\n\n    /// <summary>\n    /// The attempt to enumerate failed because the enumerator was not found.\n    /// </summary>\n    MissingEnumeratorError = 1 << 4,\n\n    /// <summary>\n    /// The attempt to enumerate failed because the enumeration threw an exception.\n    /// </summary>\n    Error = 1 << 5,\n\n    /// <summary>\n    /// Enumeration was canceled.\n    /// </summary>\n    Canceled = 1 << 6,\n\n    /// <summary>\n    /// This result indicates that enumeration has completed and that no further results will be produced.\n    /// </summary>\n    CompletedWithElement = Completed | Element,\n\n    /// <summary>\n    /// This result indicates that enumeration has completed and that no further results will be produced.\n    /// </summary>\n    CompletedWithBatch = Completed | Batch,\n}\n\ninternal static class EnumeratorResultExtensions\n{\n    private const int TerminatedMask = (int)(EnumerationResult.Completed | EnumerationResult.MissingEnumeratorError | EnumerationResult.Error | EnumerationResult.Canceled);\n    public static bool IsTerminated(this EnumerationResult value) => ((int)value & TerminatedMask) != 0;\n    public static bool IsActive(this EnumerationResult value) => ((int)value & TerminatedMask) == 0;\n}\n\n/// <summary>\n/// Grain extension interface for grains which return <see cref=\"IAsyncEnumerable{T}\"/> from grain methods.\n/// </summary>\npublic interface IAsyncEnumerableGrainExtension : IGrainExtension\n{\n    /// <summary>\n    /// Invokes an <see cref=\"IAsyncEnumerable{T}\"/> request and begins enumeration.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    /// <param name=\"requestId\">The request id, generated by the caller.</param>\n    /// <param name=\"request\">The request.</param>\n    /// <returns>The result of enumeration</returns>\n    [AlwaysInterleave]\n    public ValueTask<(EnumerationResult Status, object Value)> StartEnumeration<T>(Guid requestId, [Immutable] IAsyncEnumerableRequest<T> request)\n        => StartEnumeration(requestId, request, CancellationToken.None);\n\n    /// <summary>\n    /// Invokes an <see cref=\"IAsyncEnumerable{T}\"/> request and begins enumeration.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    /// <param name=\"requestId\">The request id, generated by the caller.</param>\n    /// <param name=\"request\">The request.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>The result of enumeration</returns>\n    [AlwaysInterleave]\n    public ValueTask<(EnumerationResult Status, object Value)> StartEnumeration<T>(Guid requestId, [Immutable] IAsyncEnumerableRequest<T> request, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Continues enumerating an <see cref=\"IAsyncEnumerable{T}\"/> value.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    /// <param name=\"requestId\">The request id, generated by the caller.</param>\n    /// <returns>The result of enumeration</returns>\n    [AlwaysInterleave]\n    public ValueTask<(EnumerationResult Status, object Value)> MoveNext<T>(Guid requestId)\n        => MoveNext<T>(requestId, CancellationToken.None);\n\n    /// <summary>\n    /// Continues enumerating an <see cref=\"IAsyncEnumerable{T}\"/> value.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    /// <param name=\"requestId\">The request id, generated by the caller.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>The result of enumeration</returns>\n    [AlwaysInterleave]\n    public ValueTask<(EnumerationResult Status, object Value)> MoveNext<T>(Guid requestId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Disposes an <see cref=\"IAsyncEnumerable{T}\"/> value.\n    /// </summary>\n    /// <param name=\"requestId\">The request id, generated by the caller.</param>\n    /// <returns>A task representing the operation.</returns>\n    [AlwaysInterleave]\n    public ValueTask DisposeAsync(Guid requestId);\n}\n\n/// <summary>\n/// Interface for requests to a <see cref=\"IAsyncEnumerable{T}\"/>-returning methods.\n/// </summary>\npublic interface IAsyncEnumerableRequest<T> : IRequest\n{\n    /// <summary>\n    /// Gets or sets the maximum batch size for the request.\n    /// </summary>\n    int MaxBatchSize { get; set; }\n\n    /// <summary>\n    /// Invokes the request.\n    /// </summary>\n    /// <returns>The result of invocation.</returns>\n    IAsyncEnumerable<T> InvokeImplementation();\n}\n\n/// <summary>\n/// Represents a request to an <see cref=\"IAsyncEnumerable{T}\"/>-returning method.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[GenerateSerializer]\n[SuppressReferenceTracking]\n[ReturnValueProxy(nameof(InitializeRequest))]\npublic abstract class AsyncEnumerableRequest<T> : RequestBase, IAsyncEnumerable<T>, IAsyncEnumerableRequest<T>\n{\n    /// <summary>\n    /// The target grain instance.\n    /// </summary>\n    [field: NonSerialized]\n    internal GrainReference? TargetGrain { get; private set; }\n\n    /// <inheritdoc/>\n    [Id(0)]\n    public int MaxBatchSize { get; set; } = 100;\n\n    /// <inheritdoc/>\n    public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new AsyncEnumeratorProxy<T>(this, cancellationToken);\n\n    // Called upon creation in generated code by the creating grain reference by virtue of the [ReturnValueProxy(nameof(InitializeRequest))] attribute on this class.\n    public IAsyncEnumerable<T> InitializeRequest(GrainReference targetGrainReference)\n    {\n        TargetGrain = targetGrainReference;\n        return this;\n    }\n\n    /// <inheritdoc/>\n    public override ValueTask<Response> Invoke() => throw new NotImplementedException($\"{nameof(IAsyncEnumerable<T>)} requests can not be invoked directly\");\n\n    /// <inheritdoc/>\n    public IAsyncEnumerable<T> InvokeImplementation() => InvokeInner();\n\n    // Generated\n    protected abstract IAsyncEnumerable<T> InvokeInner();\n}\n\n/// <summary>\n/// A proxy for an <see cref=\"IAsyncEnumerator{T}\"/> instance returned from a grain method.\n/// </summary>\ninternal sealed class AsyncEnumeratorProxy<T> : IAsyncEnumerator<T>\n{\n    private readonly AsyncEnumerableRequest<T> _request;\n    private readonly CancellationToken _cancellationToken;\n    private readonly CancellationTokenSource? _cancellationTokenSource;\n    private readonly IAsyncEnumerableGrainExtension _target;\n    private readonly Guid _requestId;\n    private (EnumerationResult State, object Value) _current;\n    private int _batchIndex;\n    private bool _disposed;\n    private bool _isInitialized;\n    private Activity? _sessionActivity;\n\n    private bool IsBatch => (_current.State & EnumerationResult.Batch) != 0;\n    private bool IsElement => (_current.State & EnumerationResult.Element) != 0;\n    private bool IsCompleted => (_current.State & EnumerationResult.Completed) != 0;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"AsyncEnumeratorProxy{T}\"/> class.\n    /// </summary>\n    /// <param name=\"request\">The request which this instanced proxies.</param>\n    public AsyncEnumeratorProxy(AsyncEnumerableRequest<T> request, CancellationToken cancellationToken)\n    {\n        Debug.Assert(request.TargetGrain is not null);\n        _request = request;\n        var requestCancellationToken = request.GetCancellationToken();\n        if (requestCancellationToken == cancellationToken)\n        {\n            // The same token was passed to the request and the enumerator.\n            _cancellationToken = cancellationToken;\n        }\n        else if (requestCancellationToken.CanBeCanceled && cancellationToken.CanBeCanceled)\n        {\n            // Both are distinct, cancellable tokens.\n            _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(requestCancellationToken, cancellationToken);\n            _cancellationToken = _cancellationTokenSource.Token;\n        }\n        else if (cancellationToken.CanBeCanceled)\n        {\n            _cancellationToken = cancellationToken;\n        }\n        else\n        {\n            Debug.Assert(requestCancellationToken.CanBeCanceled);\n            _cancellationToken = requestCancellationToken;\n        }\n\n        _requestId = Guid.NewGuid();\n        _target = _request.TargetGrain.AsReference<IAsyncEnumerableGrainExtension>();\n    }\n\n    public int MaxBatchSize { get; set; } = 100;\n\n    /// <inheritdoc/>\n    public T Current\n    {\n        get\n        {\n            ObjectDisposedException.ThrowIf(_disposed, this);\n            if (IsElement)\n            {\n                return (T)_current.Value;\n            }\n\n            if (IsBatch)\n            {\n                return ((List<T>)_current.Value)[_batchIndex];\n            }\n\n            throw new InvalidOperationException(\"Cannot get current value of an invalid enumerator.\");\n        }\n    }\n\n    /// <inheritdoc/>\n    public async ValueTask DisposeAsync()\n    {\n        if (_disposed)\n        {\n            return;\n        }\n\n        if (_isInitialized)\n        {\n            // Restore the session activity as the current activity so that DisposeAsync RPC is parented to it\n            var previousActivity = Activity.Current;\n            Activity.Current = _sessionActivity;\n            try\n            {\n                await _target.DisposeAsync(_requestId);\n            }\n            catch (Exception exception)\n            {\n                var logger = ((GrainReference)_target).Shared.ServiceProvider.GetRequiredService<ILogger<AsyncEnumerableRequest<T>>>();\n                logger.LogWarning(exception, \"Failed to dispose async enumerator.\");\n            }\n            finally\n            {\n                Activity.Current = previousActivity;\n            }\n        }\n\n        _cancellationTokenSource?.Dispose();\n\n        // Stop the session activity after DisposeAsync completes\n        _sessionActivity?.Stop();\n        _sessionActivity?.Dispose();\n\n        _disposed = true;\n    }\n\n    /// <inheritdoc/>\n    public async ValueTask<bool> MoveNextAsync()\n    {\n        ObjectDisposedException.ThrowIf(_disposed, this);\n\n        // Enumerate the existing batch before fetching more.\n        if (IsBatch && ++_batchIndex < ((List<T>)_current.Value).Count)\n        {\n            return true;\n        }\n\n        if (IsCompleted)\n        {\n            return false;\n        }\n\n        var isActive = _isInitialized;\n\n        // Restore the session activity as the current activity so that RPC calls are parented to it\n        var previousActivity = Activity.Current;\n        if (_sessionActivity is not null)\n        {\n            Activity.Current = _sessionActivity;\n        }\n\n        try\n        {\n            (EnumerationResult Status, object Value) result;\n            while (true)\n            {\n                _cancellationToken.ThrowIfCancellationRequested();\n\n                if (!_isInitialized)\n                {\n                    // Start the session activity on first enumeration call\n                    // This span wraps the entire enumeration session\n                    _sessionActivity = ActivitySources.ApplicationGrainSource.StartActivity(_request.GetActivityName(), ActivityKind.Client);\n                    _sessionActivity?.SetTag(ActivityTagKeys.AsyncEnumerableRequestId, _requestId.ToString());\n\n                    // Assume the enumerator is active as soon as the call begins.\n                    isActive = true;\n                    result = await _target.StartEnumeration(_requestId, _request, _cancellationToken);\n                    _isInitialized = true;\n                }\n                else\n                {\n                    result = await _target.MoveNext<T>(_requestId, _cancellationToken);\n                }\n\n                isActive = result.Status.IsActive();\n                if (result.Status is EnumerationResult.Error)\n                {\n                    _sessionActivity?.SetStatus(ActivityStatusCode.Error);\n                    ExceptionDispatchInfo.Capture((Exception)result.Value).Throw();\n                }\n                else if (result.Status is EnumerationResult.Canceled)\n                {\n                    _sessionActivity?.SetStatus(ActivityStatusCode.Error, \"Canceled\");\n                    throw new OperationCanceledException();\n                }\n\n                if (result.Status is not EnumerationResult.Heartbeat)\n                {\n                    break;\n                }\n            }\n\n            if (result.Status is EnumerationResult.MissingEnumeratorError)\n            {\n                _sessionActivity?.SetStatus(ActivityStatusCode.Error, \"MissingEnumerator\");\n                throw new EnumerationAbortedException(\"Enumeration aborted: the remote target does not have a record of this enumerator.\"\n                    + \" This likely indicates that the remote grain was deactivated since enumeration begun or that the enumerator was idle for longer than the expiration period.\");\n            }\n\n            Debug.Assert((result.Status & (EnumerationResult.Element | EnumerationResult.Batch | EnumerationResult.Completed)) != 0);\n\n            _batchIndex = 0;\n            _current = result;\n            return (result.Status & (EnumerationResult.Element | EnumerationResult.Batch)) != 0;\n        }\n        catch when (isActive)\n        {\n            // If the enumerator was active, we should try to dispose it now.\n            await _target.DisposeAsync(_requestId).AsTask()\n                .ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing);\n            throw;\n        }\n        finally\n        {\n            // Restore the previous activity after each call\n            Activity.Current = previousActivity;\n        }\n    }\n}\n\npublic static class AsyncEnumerableExtensions\n{\n    /// <summary>\n    /// Specifies the maximum batch size for an <see cref=\"IAsyncEnumerable{T}\"/> request.\n    /// </summary>\n    /// <typeparam name=\"T\">The underlying element type.</typeparam>\n    /// <param name=\"self\">The instance to configure.</param>\n    /// <param name=\"maxBatchSize\">The batch size.</param>\n    /// <returns>The original instance.</returns>\n    public static IAsyncEnumerable<T> WithBatchSize<T>(this IAsyncEnumerable<T> self, int maxBatchSize)\n    {\n        if (self is AsyncEnumerableRequest<T> request)\n        {\n            request.MaxBatchSize = maxBatchSize;\n            return request;\n        }\n\n        return self;\n    }\n}\n\n/// <summary>\n/// Indicates that an enumeration was aborted.\n/// </summary>\n[GenerateSerializer]\npublic sealed class EnumerationAbortedException : Exception\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"EnumerationAbortedException\"/> class.\n    /// </summary>\n    public EnumerationAbortedException()\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"EnumerationAbortedException\"/> class.\n    /// </summary>\n    public EnumerationAbortedException(string message) : base(message)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"EnumerationAbortedException\"/> class.\n    /// </summary>\n    public EnumerationAbortedException(string message, Exception innerException) : base(message, innerException)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"EnumerationAbortedException\"/> class.\n    /// </summary>\n    [Obsolete]\n    protected EnumerationAbortedException(SerializationInfo info, StreamingContext context) : base(info, context)\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/GrainContextComponentExtensions.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Extensions for <see cref=\"IGrainContext\"/> related to <see cref=\"IGrainExtension\"/>.\n    /// </summary>\n    public static class GrainContextComponentExtensions\n    {\n        /// <summary>\n        /// Used by generated code for <see cref=\"IGrainExtension\" /> interfaces.\n        /// </summary>\n        /// <typeparam name=\"TComponent\">\n        /// The type of the component to get.\n        /// </typeparam>\n        /// <param name=\"context\">\n        /// The grain context.\n        /// </param>\n        /// <returns>\n        /// The grain extension.\n        /// </returns>\n        public static TComponent GetGrainExtension<TComponent>(this IGrainContext context)\n            where TComponent : class, IGrainExtension\n        {\n            var binder = context.GetComponent<IGrainExtensionBinder>();\n            if (binder is null)\n            {\n                throw new InvalidOperationException($\"No {nameof(IGrainExtensionBinder)} is available on the current grain context.\");\n            }\n\n            return binder.GetExtension<TComponent>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/GrainLifecycleStage.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Stages of a grains lifecycle.\n    /// TODO: Add more later, see ActivationInitializationStage\n    /// Full grain lifecycle, including register, state setup, and\n    ///   stream cleanup should all eventually be triggered by the\n    ///   grain lifecycle.\n    /// </summary>\n    public static class GrainLifecycleStage\n    {\n        /// <summary>\n        /// First valid stage in grain's lifecycle.\n        /// </summary>\n        public const int First = int.MinValue;\n\n        /// <summary>\n        /// Setup grain state prior to activation.\n        /// </summary>\n        public const int SetupState = 1000;\n\n        /// <summary>\n        /// Activate grain.\n        /// </summary>\n        public const int Activate = 2000;\n\n        /// <summary>\n        /// Last valid stage in grain's lifecycle.\n        /// </summary>\n        public const int Last = int.MaxValue;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/GrainReference.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Serializers;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGeneration;\nusing System.Text;\nusing System.Diagnostics;\nusing System.Collections.Generic;\nusing System.Threading;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Properties common to <see cref=\"GrainReference\"/> instances with the same <see cref=\"GrainType\"/> and <see cref=\"GrainInterfaceType\"/>.\n    /// </summary>\n    public class GrainReferenceShared\n    {\n        public GrainReferenceShared(\n            GrainType grainType,\n            GrainInterfaceType grainInterfaceType,\n            ushort interfaceVersion,\n            IGrainReferenceRuntime runtime,\n            InvokeMethodOptions invokeMethodOptions,\n            CodecProvider codecProvider,\n            CopyContextPool copyContextPool,\n            IServiceProvider serviceProvider)\n        {\n            this.GrainType = grainType;\n            this.InterfaceType = grainInterfaceType;\n            this.Runtime = runtime;\n            this.InvokeMethodOptions = invokeMethodOptions;\n            this.CodecProvider = codecProvider;\n            this.CopyContextPool = copyContextPool;\n            this.ServiceProvider = serviceProvider;\n            this.InterfaceVersion = interfaceVersion;\n        }\n\n        /// <summary>\n        /// Gets the grain reference runtime.\n        /// </summary>\n        public IGrainReferenceRuntime Runtime { get; }\n\n        /// <summary>\n        /// Gets the grain type.\n        /// </summary>\n        public GrainType GrainType { get; }\n\n        /// <summary>\n        /// Gets the interface type.\n        /// </summary>\n        public GrainInterfaceType InterfaceType { get; }\n\n        /// <summary>\n        /// Gets the common invocation options.\n        /// </summary>\n        public InvokeMethodOptions InvokeMethodOptions { get; }\n\n        /// <summary>\n        /// Gets the serialization codec provider.\n        /// </summary>\n        public CodecProvider CodecProvider { get; }\n\n        /// <summary>\n        /// Gets the serialization copy context pool.\n        /// </summary>\n        public CopyContextPool CopyContextPool { get; }\n\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        public IServiceProvider ServiceProvider { get; }\n\n        /// <summary>\n        /// Gets the interface version.\n        /// </summary>\n        public ushort InterfaceVersion { get; }\n    }\n\n    /// <summary>\n    /// Functionality for serializing and deserializing <see cref=\"GrainReference\"/> and derived types.\n    /// </summary>\n    [RegisterSerializer]\n    internal class GrainReferenceCodec : GeneralizedReferenceTypeSurrogateCodec<IAddressable, GrainReferenceSurrogate>\n    {\n        private readonly IGrainFactory _grainFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceCodec\"/> class.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"surrogateSerializer\">The serializer for the surrogate type used by this class.</param>\n        public GrainReferenceCodec(IGrainFactory grainFactory, IValueSerializer<GrainReferenceSurrogate> surrogateSerializer)\n            : base(surrogateSerializer)\n        {\n            _grainFactory = grainFactory;\n        }\n\n        /// <inheritdoc/>\n        public override IAddressable ConvertFromSurrogate(ref GrainReferenceSurrogate surrogate)\n        {\n            return _grainFactory.GetGrain(surrogate.GrainId, surrogate.GrainInterfaceType);\n        }\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(IAddressable value, ref GrainReferenceSurrogate surrogate)\n        {\n            var refValue = value.AsReference();\n            surrogate.GrainId = refValue.GrainId;\n            surrogate.GrainInterfaceType = refValue.InterfaceType;\n        }\n    }\n\n    [RegisterCopier]\n    internal sealed class GrainReferenceCopier : ShallowCopier<GrainReference>, IDerivedTypeCopier { }\n\n    /// <summary>\n    /// Provides specialized copier instances for grain reference types.\n    /// </summary>\n    internal class GrainReferenceCopierProvider : ISpecializableCopier\n    {\n        /// <inheritdoc/>\n        // ! Activator.CreateInstance will not return null for these arguments.\n        public IDeepCopier GetSpecializedCopier(Type type) => (IDeepCopier)Activator.CreateInstance(typeof(TypedGrainReferenceCopier<>).MakeGenericType(type))!;\n\n        /// <inheritdoc/>\n        public bool IsSupportedType(Type type) => typeof(IAddressable).IsAssignableFrom(type) && type.IsInterface;\n    }\n\n    /// <summary>\n    /// A strongly-typed copier for grain reference instances.\n    /// </summary>\n    /// <typeparam name=\"TInterface\">The grain interface type.</typeparam>\n    internal class TypedGrainReferenceCopier<TInterface> : IDeepCopier<TInterface>\n    {\n        /// <inheritdoc/>\n        public TInterface DeepCopy(TInterface input, CopyContext context)\n        {\n            if (input is null) return input;\n            if (input is GrainReference) return input;\n            if (input is IGrainObserver observer)\n            {\n                GrainReferenceCodecProvider.ThrowGrainObserverInvalidException(observer);\n            }\n\n            var addressable = (IAddressable)input;\n            var grainReference = addressable.AsReference();\n            return (TInterface)grainReference.Runtime.Cast(addressable, typeof(TInterface));\n        }\n    }\n\n    /// <summary>\n    /// Provides specialized codec instances for grain reference types.\n    /// </summary>\n    internal class GrainReferenceCodecProvider : ISpecializableCodec\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceCodecProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        public GrainReferenceCodecProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;\n\n        /// <inheritdoc/>\n        public IFieldCodec GetSpecializedCodec(Type type) => (IFieldCodec)ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, typeof(TypedGrainReferenceCodec<>).MakeGenericType(type));\n\n        /// <inheritdoc/>\n        public bool IsSupportedType(Type type) => typeof(IAddressable).IsAssignableFrom(type);\n\n        /// <summary>\n        /// Throws an exception indicating that a parameter type is not supported.\n        /// </summary>\n        /// <param name=\"observer\">The observer.</param>\n        internal static void ThrowGrainObserverInvalidException(IGrainObserver observer)\n            => throw new NotSupportedException($\"IGrainObserver parameters must be GrainReference or Grain and cannot be type {observer.GetType()}. Did you forget to CreateObjectReference?\");\n    }\n\n    /// <summary>\n    /// A strongly-typed codec for grain reference instances.\n    /// </summary>\n    /// <typeparam name=\"T\">The grain reference interface type.</typeparam>\n    internal class TypedGrainReferenceCodec<T> : GeneralizedReferenceTypeSurrogateCodec<T, GrainReferenceSurrogate>\n        where T : class, IAddressable\n    {\n        private readonly IGrainFactory _grainFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypedGrainReferenceCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public TypedGrainReferenceCodec(IGrainFactory grainFactory, IValueSerializer<GrainReferenceSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n            _grainFactory = grainFactory;\n        }\n\n        /// <inheritdoc/>\n        public override T ConvertFromSurrogate(ref GrainReferenceSurrogate surrogate)\n        {\n            return (T)_grainFactory.GetGrain(surrogate.GrainId, surrogate.GrainInterfaceType);\n        }\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(T value, ref GrainReferenceSurrogate surrogate)\n        {\n            // Check that the typical case is false before performing the more expensive interface check\n            if (value is not GrainReference refValue)\n            {\n                if (value is IGrainObserver observer)\n                {\n                    GrainReferenceCodecProvider.ThrowGrainObserverInvalidException(observer);\n                }\n\n                refValue = (GrainReference)(object)value.AsReference<T>();\n            }\n\n            surrogate.GrainId = refValue.GrainId;\n            surrogate.GrainInterfaceType = refValue.InterfaceType;\n        }\n    }\n\n    /// <summary>\n    /// A surrogate used to represent <see cref=\"GrainReference\"/> implementations for serialization.\n    /// </summary>\n    [GenerateSerializer]\n    internal struct GrainReferenceSurrogate\n    {\n        /// <summary>\n        /// Gets or sets the grain id.\n        /// </summary>\n        [Id(0)]\n        public GrainId GrainId;\n\n        /// <summary>\n        /// Gets or sets the grain interface type.\n        /// </summary>\n        [Id(1)]\n        public GrainInterfaceType GrainInterfaceType;\n    }\n\n    /// <summary>\n    /// This is the base class for all grain references.\n    /// </summary>\n    [Alias(\"GrainRef\")]\n    [DefaultInvokableBaseType(typeof(ValueTask<>), typeof(Request<>))]\n    [DefaultInvokableBaseType(typeof(ValueTask), typeof(Request))]\n    [DefaultInvokableBaseType(typeof(Task<>), typeof(TaskRequest<>))]\n    [DefaultInvokableBaseType(typeof(Task), typeof(TaskRequest))]\n    [DefaultInvokableBaseType(typeof(void), typeof(VoidRequest))]\n    [DefaultInvokableBaseType(typeof(IAsyncEnumerable<>), typeof(AsyncEnumerableRequest<>))]\n    public class GrainReference : IAddressable, IEquatable<GrainReference>, ISpanFormattable\n    {\n        /// <summary>\n        /// The grain reference functionality which is shared by all grain references of a given type.\n        /// </summary>\n        [NonSerialized]\n        private readonly GrainReferenceShared _shared;\n\n        /// <summary>\n        /// The underlying grain id key.\n        /// </summary>\n        [NonSerialized]\n        private readonly IdSpan _key;\n\n        /// <summary>\n        /// Gets the grain reference functionality which is shared by all grain references of a given type.\n        /// </summary>\n        internal GrainReferenceShared Shared => _shared ?? throw new GrainReferenceNotBoundException(this);\n\n        /// <summary>\n        /// Gets the grain reference runtime.\n        /// </summary>\n        internal IGrainReferenceRuntime Runtime => Shared.Runtime;\n\n        /// <summary>\n        /// Gets the grain id.\n        /// </summary>\n        public GrainId GrainId => GrainId.Create(_shared.GrainType, _key);\n\n        /// <summary>\n        /// Gets the interface type.\n        /// </summary>\n        public GrainInterfaceType InterfaceType => _shared.InterfaceType;\n\n        /// <summary>\n        /// Gets the serialization copy context pool.\n        /// </summary>\n        protected CopyContextPool CopyContextPool => _shared.CopyContextPool;\n\n        /// <summary>\n        /// Gets the serialization codec provider.\n        /// </summary>\n        protected CodecProvider CodecProvider => _shared.CodecProvider;\n\n        /// <summary>Initializes a new instance of the <see cref=\"GrainReference\"/> class.</summary>\n        /// <param name=\"shared\">\n        /// The grain reference functionality which is shared by all grain references of a given type.\n        /// </param>\n        /// <param name=\"key\">\n        /// The key portion of the grain id.\n        /// </param>\n        protected GrainReference(GrainReferenceShared shared, IdSpan key)\n        {\n            _shared = shared;\n            _key = key;\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"GrainReference\"/> instance for the specified <paramref name=\"grainId\"/>.\n        /// </summary>\n        internal static GrainReference FromGrainId(GrainReferenceShared shared, GrainId grainId) => new(shared, grainId.Key);\n\n        /// <summary>\n        /// Creates a new grain reference which implements the specified grain interface.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">\n        /// The grain interface type.\n        /// </typeparam>\n        /// <returns>A new grain reference which implements the specified interface type.</returns>\n        public virtual TGrainInterface Cast<TGrainInterface>()\n            where TGrainInterface : IAddressable\n            => (TGrainInterface)_shared.Runtime.Cast(this, typeof(TGrainInterface));\n\n        /// <summary>\n        /// Tests this reference for equality to another object.\n        /// Two grain references are equal if they both refer to the same grain.\n        /// </summary>\n        /// <param name=\"obj\">The object to test for equality against this reference.</param>\n        /// <returns><c>true</c> if the object is equal to this reference.</returns>\n        public override bool Equals(object? obj)\n        {\n            return Equals(obj as GrainReference);\n        }\n\n        /// <inheritdoc />\n        public bool Equals(GrainReference? other) => other is not null && this.GrainId.Equals(other.GrainId);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => this.GrainId.GetHashCode();\n\n        /// <summary>\n        /// Get a uniform hash code for this grain reference.\n        /// </summary>\n        /// <returns>\n        /// The uniform hash code.\n        /// </returns>\n        public uint GetUniformHashCode()\n        {\n            // GrainId already includes the hashed type code for generic arguments.\n            return GrainId.GetUniformHashCode();\n        }\n\n        /// <summary>\n        /// Compares two references for equality.\n        /// Two grain references are equal if they both refer to the same grain.\n        /// </summary>\n        /// <param name=\"reference1\">First grain reference to compare.</param>\n        /// <param name=\"reference2\">Second grain reference to compare.</param>\n        /// <returns><c>true</c> if both grain references refer to the same grain (by grain identifier).</returns>\n        public static bool operator ==(GrainReference? reference1, GrainReference? reference2)\n        {\n            if (reference1 is null) return reference2 is null;\n\n            return reference1.Equals(reference2);\n        }\n\n        /// <summary>\n        /// Compares two references for inequality.\n        /// Two grain references are equal if they both refer to the same grain.\n        /// </summary>\n        /// <param name=\"reference1\">First grain reference to compare.</param>\n        /// <param name=\"reference2\">Second grain reference to compare.</param>\n        /// <returns><c>false</c> if both grain references are resolved to the same grain (by grain identifier).</returns>\n        public static bool operator !=(GrainReference? reference1, GrainReference? reference2)\n        {\n            if (reference1 is null) return !(reference2 is null);\n\n            return !reference1.Equals(reference2);\n        }\n\n        /// <summary>\n        /// Gets the interface version.\n        /// </summary>\n        public ushort InterfaceVersion => Shared.InterfaceVersion;\n\n        /// <summary>\n        /// Gets the interface name.\n        /// </summary>\n        public virtual string InterfaceName => InterfaceType.ToString();\n\n        /// <inheritdoc/>\n        public sealed override string ToString() => $\"GrainReference:{GrainId}:{InterfaceType}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"GrainReference:{GrainId}:{InterfaceType}\", out charsWritten);\n\n        protected TInvokable GetInvokable<TInvokable>() => ActivatorUtilities.GetServiceOrCreateInstance<TInvokable>(Shared.ServiceProvider);\n\n        /// <summary>\n        /// Invokes the provided method.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying method return type.</typeparam>\n        /// <param name=\"methodDescription\">The method description.</param>\n        /// <returns>The result of the invocation.</returns>\n        protected ValueTask<T> InvokeAsync<T>(IRequest methodDescription)\n        {\n            return this.Runtime.InvokeMethodAsync<T>(this, methodDescription, methodDescription.Options);\n        }\n\n        /// <summary>\n        /// Invokes the provided method.\n        /// </summary>\n        /// <param name=\"methodDescription\">The method description.</param>\n        /// <returns>A <see cref=\"ValueTask\"/> representing the operation.</returns>\n        protected ValueTask InvokeAsync(IRequest methodDescription)\n        {\n            return this.Runtime.InvokeMethodAsync(this, methodDescription, methodDescription.Options);\n        }\n\n        /// <summary>\n        /// Invokes the provided method.\n        /// </summary>\n        /// <param name=\"methodDescription\">The method description.</param>\n        protected void Invoke(IRequest methodDescription)\n        {\n            this.Runtime.InvokeMethod(this, methodDescription, methodDescription.Options);\n        }\n    }\n\n    /// <summary>\n    /// Represents a request to invoke a method on a grain.\n    /// </summary>\n    public interface IRequest : IInvokable\n    {\n        /// <summary>\n        /// Gets the invocation options.\n        /// </summary>\n        InvokeMethodOptions Options { get; }\n\n        /// <summary>\n        /// Incorporates the provided invocation options.\n        /// </summary>\n        /// <param name=\"options\">\n        /// The options.\n        /// </param>\n        void AddInvokeMethodOptions(InvokeMethodOptions options);\n\n        /// <summary>\n        /// Returns a string representation of the request.\n        /// </summary>\n        /// <returns>A string representation of the request.</returns>\n        public static string ToString(IRequest request)\n        {\n            var result = new StringBuilder();\n            result.Append(request.GetInterfaceName());\n            if (request.GetTarget() is { } target)\n            {\n                result.Append(\"[(\");\n                result.Append(request.GetInterfaceName());\n                result.Append(')');\n                result.Append(target.ToString());\n                result.Append(']');\n            }\n\n            result.Append('.');\n            result.Append(request.GetMethodName());\n            result.Append('(');\n            var argTypes = request.GetMethod()?.GetParameters();\n            if (argTypes is not null)\n            {\n                var argumentCount = argTypes.Length;\n                for (var n = 0; n < argumentCount; n++)\n                {\n                    if (n > 0)\n                    {\n                        result.Append(\", \");\n                    }\n\n                    result.Append(argTypes[n].ParameterType);\n                }\n            }\n            else\n            {\n                var argumentCount = request.GetArgumentCount();\n                for (var n = 0; n < argumentCount; n++)\n                {\n                    if (n > 0)\n                    {\n                        result.Append(\", \");\n                    }\n\n                    result.Append(request.GetArgument(n)?.GetType()?.ToString() ?? \"null\");\n                }\n            }\n\n            result.Append(')');\n            return result.ToString();\n        }\n\n        /// <summary>\n        /// Returns a string representation of the request.\n        /// </summary>\n        /// <returns>A string representation of the request.</returns>\n        public static string ToMethodCallString(IRequest request)\n        {\n            var result = new StringBuilder();\n            result.Append(request.GetInterfaceName());\n            result.Append('.');\n            result.Append(request.GetMethodName());\n            result.Append('(');\n            var argumentCount = request.GetArgumentCount();\n            for (var n = 0; n < argumentCount; n++)\n            {\n                if (n > 0)\n                {\n                    result.Append(\", \");\n                }\n\n                result.Append(request.GetArgument(n));\n            }\n\n            result.Append(')');\n            return result.ToString();\n        }\n    }\n\n    /// <summary>\n    /// Base type used for method requests.\n    /// </summary>\n    [SuppressReferenceTracking]\n    [SerializerTransparent]\n    public abstract class RequestBase : IRequest\n    {\n        /// <summary>\n        /// Gets the invocation options.\n        /// </summary>\n        [field: NonSerialized]\n        public InvokeMethodOptions Options { get; protected set; }\n\n        /// <inheritdoc/>\n        public virtual int GetArgumentCount() => 0;\n\n        /// <summary>\n        /// Incorporates the provided invocation options.\n        /// </summary>\n        /// <param name=\"options\">\n        /// The options.\n        /// </param>\n        public void AddInvokeMethodOptions(InvokeMethodOptions options)\n        {\n            Options |= options;\n        }\n\n        /// <inheritdoc/>\n        public abstract ValueTask<Response> Invoke();\n\n        /// <inheritdoc/>\n        public abstract object GetTarget();\n\n        /// <inheritdoc/>\n        public abstract void SetTarget(ITargetHolder holder);\n\n        /// <inheritdoc/>\n        public virtual object GetArgument(int index) => throw new ArgumentOutOfRangeException(message: \"The request has zero arguments\", null);\n\n        /// <inheritdoc/>\n        public virtual void SetArgument(int index, object value) => throw new ArgumentOutOfRangeException(message: \"The request has zero arguments\", null);\n\n        /// <inheritdoc/>\n        public abstract void Dispose();\n\n        /// <inheritdoc/>\n        public abstract string GetMethodName();\n\n        /// <inheritdoc/>\n        public abstract string GetInterfaceName();\n\n        /// <inheritdoc/>\n        public abstract string GetActivityName();\n\n        /// <inheritdoc/>\n        public abstract Type GetInterfaceType();\n\n        /// <inheritdoc/>\n        public abstract MethodInfo GetMethod();\n\n        /// <inheritdoc/>\n        public override string ToString() => IRequest.ToString(this);\n\n        /// <inheritdoc/>\n        public virtual TimeSpan? GetDefaultResponseTimeout() => null;\n\n        public virtual bool TryCancel() => false;\n\n        public virtual CancellationToken GetCancellationToken() => default;\n\n        public virtual bool IsCancellable => false;\n    }\n\n    /// <summary>\n    /// Base class for requests for methods which return <see cref=\"ValueTask\"/>.\n    /// </summary>\n    [SerializerTransparent]\n    public abstract class Request : RequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.Completed);\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.Completed;\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract ValueTask InvokeInner();\n    }\n\n    /// <summary>\n    /// Base class for requests for methods which return <see cref=\"ValueTask{TResult}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TResult\">\n    /// The underlying result type.\n    /// </typeparam>\n    [SerializerTransparent]\n    public abstract class Request<TResult> : RequestBase\n    {\n        /// <inheritdoc/>\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.Result));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        /// <summary>\n        /// Invokes the request against the target.\n        /// </summary>\n        /// <returns>The invocation result.</returns>\n        protected abstract ValueTask<TResult> InvokeInner();\n    }\n\n    /// <summary>\n    /// Base class for requests for methods which return <see cref=\"Task{TResult}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TResult\">\n    /// The underlying result type.\n    /// </typeparam>\n    [SerializerTransparent]\n    public abstract class TaskRequest<TResult> : RequestBase\n    {\n        /// <inheritdoc/>\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.GetAwaiter().GetResult()));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        /// <summary>\n        /// Invokes the request against the target.\n        /// </summary>\n        /// <returns>The invocation result.</returns>\n        protected abstract Task<TResult> InvokeInner();\n    }\n\n    /// <summary>\n    /// Base class for requests for methods which return <see cref=\"ValueTask\"/>.\n    /// </summary>\n    [SerializerTransparent]\n    public abstract class TaskRequest : RequestBase\n    {\n        /// <inheritdoc/>\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.Completed);\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.Completed;\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        /// <summary>\n        /// Invokes the request against the target.\n        /// </summary>\n        /// <returns>The invocation result.</returns>\n        protected abstract Task InvokeInner();\n    }\n\n    /// <summary>\n    /// Base class for requests for void-returning methods.\n    /// </summary>\n    [SerializerTransparent]\n    public abstract class VoidRequest : RequestBase\n    {\n        protected VoidRequest()\n        {\n            // All void requests are inherently one-way.\n            Options = InvokeMethodOptions.OneWay;\n        }\n\n        /// <inheritdoc/>\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                InvokeInner();\n                return new ValueTask<Response>(Response.Completed);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        /// <summary>\n        /// Invokes the request against the target.\n        /// </summary>\n        protected abstract void InvokeInner();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/GrainReferenceNotBoundException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Indicates that a <see cref=\"GrainReference\"/> was not bound to the runtime before being used.\n    /// </summary>\n    [Serializable, GenerateSerializer]\n    public sealed class GrainReferenceNotBoundException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceNotBoundException\"/> class.\n        /// </summary>\n        /// <param name=\"grainReference\">The unbound grain reference.</param>\n        internal GrainReferenceNotBoundException(GrainReference grainReference) : base(CreateMessage(grainReference)) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceNotBoundException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        internal GrainReferenceNotBoundException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceNotBoundException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        internal GrainReferenceNotBoundException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainReferenceNotBoundException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private GrainReferenceNotBoundException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n\n        private static string CreateMessage(GrainReference grainReference)\n        {\n            return $\"Attempted to use an invalid GrainReference, which has not been constructed by the runtime: {grainReference}.\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IAddressable.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Marker interface for addressable endpoints, such as grains, observers, and other system-internal addressable endpoints\n    /// </summary>\n    [GenerateMethodSerializers(typeof(GrainReference))]\n    public interface IAddressable\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IGrainCancellationTokenRuntime.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Functionality required by <see cref=\"GrainCancellationToken\"/> and <see cref=\"GrainCancellationTokenSource\"/>.\n    /// </summary>\n    internal interface IGrainCancellationTokenRuntime\n    {\n        /// <summary>\n        /// Cancels the <see cref=\"GrainCancellationToken\"/> with the provided id.\n        /// </summary>\n        /// <param name=\"id\">The grain cancellation token id.</param>\n        /// <param name=\"tokenSource\">The grain cancellation token source being canceled.</param>\n        /// <param name=\"grainReferences\">The grain references which are observing the cancellation token.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Cancel(Guid id, CancellationTokenSource tokenSource, ConcurrentDictionary<GrainId, GrainReference> grainReferences);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IGrainExtension.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Marker interface for grain extensions, used by internal runtime extension endpoints.\n    /// </summary>\n    [GenerateMethodSerializers(typeof(GrainReference), isExtension: true)]\n    public interface IGrainExtension : IAddressable\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IGrainReferenceRuntime.cs",
    "content": "using Orleans.CodeGeneration;\nusing Orleans.Serialization.Invocation;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Runtime logic for <see cref=\"GrainReference\"/>s to be usable.\n    /// This service is not meant to be used directly by user code.\n    /// </summary>\n    public interface IGrainReferenceRuntime\n    {\n        /// <summary>\n        /// Invokes the specified method on the provided grain interface.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying return type of the method.</typeparam>\n        /// <param name=\"reference\">The grain reference.</param>\n        /// <param name=\"request\">The method description.</param>\n        /// <param name=\"options\">The invocation options.</param>\n        /// <returns>The result of invocation.</returns>\n        ValueTask<T> InvokeMethodAsync<T>(GrainReference reference, IInvokable request, InvokeMethodOptions options);\n\n        /// <summary>\n        /// Invokes the specified method on the provided grain interface.\n        /// </summary>\n        /// <param name=\"reference\">The grain reference.</param>\n        /// <param name=\"request\">The method description.</param>\n        /// <param name=\"options\">The invocation options.</param>\n        /// <returns>A <see cref=\"ValueTask\"/> representing the operation</returns>\n        ValueTask InvokeMethodAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options);\n\n        /// <summary>\n        /// Invokes the specified void-returning method on the provided grain interface without waiting for a response.\n        /// </summary>\n        /// <param name=\"reference\">The grain reference.</param>\n        /// <param name=\"request\">The method description.</param>\n        /// <param name=\"options\">The invocation options.</param>\n        void InvokeMethod(GrainReference reference, IInvokable request, InvokeMethodOptions options);\n\n        /// <summary>\n        /// Converts the provided <paramref name=\"grain\"/> to the provided <paramref name=\"interfaceType\"/>.\n        /// </summary>\n        /// <param name=\"grain\">The grain.</param>\n        /// <param name=\"interfaceType\">The resulting interface type.</param>\n        /// <returns>A reference to <paramref name=\"grain\"/> which implements <paramref name=\"interfaceType\"/>.</returns>\n        object Cast(IAddressable grain, Type interfaceType);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IGrainRuntime.cs",
    "content": "using System;\nusing Orleans.Core;\nusing Orleans.Timers;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// The gateway of the <see cref=\"Grain\"/> to the Orleans runtime. The <see cref=\"Grain\"/> should only interact with the runtime through this interface.\n/// </summary>\npublic interface IGrainRuntime\n{\n    /// <summary>\n    /// Gets a unique identifier for the current silo.\n    /// There is no semantic content to this string, but it may be useful for logging.\n    /// </summary>\n    string SiloIdentity { get; }\n\n    /// <summary>\n    /// Gets the silo address associated with this instance.\n    /// </summary>\n    SiloAddress SiloAddress { get; }\n\n    /// <summary>\n    /// Gets the grain factory.\n    /// </summary>\n    IGrainFactory GrainFactory { get; }\n\n    /// <summary>\n    /// Gets the timer registry.\n    /// </summary>\n    ITimerRegistry TimerRegistry { get; }\n\n    /// <summary>\n    /// Gets the service provider.\n    /// </summary>\n    IServiceProvider ServiceProvider { get; }\n\n    /// <summary>\n    /// Gets the time provider.\n    /// </summary>\n    TimeProvider TimeProvider => TimeProvider.System;\n\n    /// <summary>\n    /// Deactivates the provided grain when it becomes idle.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain context.</param>\n    void DeactivateOnIdle(IGrainContext grainContext);\n\n    /// <summary>\n    /// Delays idle activation collection of the provided grain due to inactivity until at least the specified time has elapsed.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain context.</param>\n    /// <param name=\"timeSpan\">The time to delay idle activation collection for.</param>\n    void DelayDeactivation(IGrainContext grainContext, TimeSpan timeSpan);\n\n    /// <summary>\n    /// Gets grain storage for the provided grain.\n    /// </summary>\n    /// <typeparam name=\"TGrainState\">The grain state type.</typeparam>\n    /// <param name=\"grainContext\">The grain context.</param>\n    /// <returns>The grain storage for the provided grain.</returns>\n    IStorage<TGrainState> GetStorage<TGrainState>(IGrainContext grainContext);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/IGrainTimer.cs",
    "content": "using System;\nusing System.Threading;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Represents a timer belonging to a grain.\n/// </summary>\npublic interface IGrainTimer : IDisposable\n{\n    /// <summary>Changes the start time and the interval between method invocations for a timer, using <see cref=\"TimeSpan\"/> values to measure time intervals.</summary>\n    /// <param name=\"dueTime\">\n    /// A <see cref=\"TimeSpan\"/> representing the amount of time to delay before invoking the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from restarting.\n    /// Specify <see cref=\"TimeSpan.Zero\"/> to restart the timer immediately.\n    /// </param>\n    /// <param name=\"period\">\n    /// The time interval between invocations of the callback method specified when the timer was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to disable periodic signaling.\n    /// </param>\n    /// <exception cref=\"ArgumentOutOfRangeException\">The <paramref name=\"dueTime\"/> or <paramref name=\"period\"/> parameter, in milliseconds, is less than -1 or greater than 4294967294.</exception>\n    void Change(TimeSpan dueTime, TimeSpan period);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/MembershipVersion.cs",
    "content": "using System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies the version of a cluster membership configuration.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    [JsonConverter(typeof(MembershipVersionConverter))]\n    public readonly struct MembershipVersion : IComparable<MembershipVersion>, IEquatable<MembershipVersion>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MembershipVersion\"/> struct.\n        /// </summary>\n        /// <param name=\"version\">The underlying version.</param>\n        public MembershipVersion(long version)\n        {\n            this.Value = version;\n        }\n\n        /// <summary>\n        /// Gets the version.\n        /// </summary>\n        [Id(0)]\n        public long Value { get; init; }\n\n        /// <summary>\n        /// Gets the minimum possible version.\n        /// </summary>\n        public static MembershipVersion MinValue => new MembershipVersion(long.MinValue);\n\n        /// <inheritdoc/>\n        public int CompareTo(MembershipVersion other) => this.Value.CompareTo(other.Value);\n\n        /// <inheritdoc/>\n        public bool Equals(MembershipVersion other) => this.Value == other.Value;\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is MembershipVersion other && this.Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.Value.GetHashCode();\n\n        /// <inheritdoc/>\n        public override string ToString() => Value != MinValue.Value ? $\"{Value}\" : \"default\";\n\n        /// <summary>\n        /// Compares the provided operands for equality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(MembershipVersion left, MembershipVersion right) => left.Value == right.Value;\n\n        /// <summary>\n        /// Compares the provided operands for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the provided values are not equal, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(MembershipVersion left, MembershipVersion right) => left.Value != right.Value;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >=(MembershipVersion left, MembershipVersion right) => left.Value >= right.Value;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than or equal to the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <=(MembershipVersion left, MembershipVersion right) => left.Value <= right.Value;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is greater than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator >(MembershipVersion left, MembershipVersion right) => left.Value > right.Value;\n\n        /// <summary>\n        /// Compares the provided operands and returns <see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.\n        /// </summary>\n        /// <param name=\"left\">The left operand.</param>\n        /// <param name=\"right\">The right operand.</param>\n        /// <returns><see langword=\"true\"/> if the left operand is less than the right operand, otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator <(MembershipVersion left, MembershipVersion right) => left.Value < right.Value;\n    }\n\n    /// <summary>\n    /// Functionality for converting <see cref=\"MembershipVersion\"/> instances to and from JSON.\n    /// </summary>\n    public sealed class MembershipVersionConverter : JsonConverter<MembershipVersion>\n    {\n        /// <inheritdoc />\n        public override MembershipVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => new(reader.GetInt64());\n\n        /// <inheritdoc />\n        public override void Write(Utf8JsonWriter writer, MembershipVersion value, JsonSerializerOptions options) => writer.WriteNumberValue(value.Value);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/RequestContext.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Orleans.Core.Internal;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// This class holds information regarding the request currently being processed.\n    /// It is explicitly intended to be available to application code.\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// The request context is represented as a property bag.\n    /// Some values are provided by default; others are derived from messages headers in the\n    /// request that led to the current processing.\n    /// </para>\n    /// <para>\n    /// Information stored in <see cref=\"RequestContext\"/> is propagated from Orleans clients to Orleans grains automatically by the Orleans runtime.\n    /// </para>\n    /// </remarks>\n    public static class RequestContext\n    {\n        internal const string CALL_CHAIN_REENTRANCY_HEADER = \"#CCR\";\n        internal const string PING_APPLICATION_HEADER = \"Ping\";\n\n        internal static readonly AsyncLocal<ContextProperties> CallContextData = new();\n\n        public static Guid ReentrancyId\n        {\n            get => Get(CALL_CHAIN_REENTRANCY_HEADER) is Guid guid ? guid : Guid.Empty;\n            set\n            {\n                if (value == Guid.Empty)\n                {\n                    Remove(CALL_CHAIN_REENTRANCY_HEADER);\n                }\n                else\n                {\n                    Set(CALL_CHAIN_REENTRANCY_HEADER, value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Allows reentrancy for subsequent calls issued before the returned <see cref=\"ReentrancySection\"/> is disposed.\n        /// </summary>\n        public static ReentrancySection AllowCallChainReentrancy()\n        {\n            var originalCallChainId = ReentrancyId;\n            var newCallChainId = originalCallChainId == Guid.Empty ? Guid.NewGuid() : originalCallChainId;\n            return new ReentrancySection(originalCallChainId, newCallChainId);\n        }\n\n        /// <summary>\n        /// Suppresses reentrancy for subsequent calls issued before the returned <see cref=\"ReentrancySection\"/> is disposed.\n        /// </summary>\n        public static ReentrancySection SuppressCallChainReentrancy() => new(ReentrancyId, Guid.Empty);\n\n        /// <summary>\n        /// Retrieves a value from the request context.\n        /// </summary>\n        /// <param name=\"key\">The key for the value to be retrieved.</param>\n        /// <returns>\n        /// The value currently associated with the provided key, otherwise <see langword=\"null\"/> if no data is present for that key.\n        /// </returns>\n        public static object? Get(string key)\n        {\n            var properties = CallContextData.Value;\n            var values = properties.Values;\n\n            if (values != null && values.TryGetValue(key, out var result))\n            {\n                return result;\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Sets a value in the request context.\n        /// </summary>\n        /// <param name=\"key\">The key for the value to be updated or added.</param>\n        /// <param name=\"value\">The value to be stored into the request context.</param>\n        public static void Set(string key, object value)\n        {\n            var properties = CallContextData.Value;\n            var values = properties.Values;\n\n            if (values == null)\n            {\n                values = new Dictionary<string, object>(1);\n            }\n            else\n            {\n                // Have to copy the actual Dictionary value, mutate it and set it back.\n                // This is since AsyncLocal copies link to dictionary, not create a new one.\n                // So we need to make sure that modifying the value, we doesn't affect other threads.\n                var hadPreviousValue = values.ContainsKey(key);\n                var newValues = new Dictionary<string, object>(values.Count + (hadPreviousValue ? 0 : 1));\n                foreach (var pair in values)\n                {\n                    newValues.Add(pair.Key, pair.Value);\n                }\n\n                values = newValues;\n            }\n\n            values[key] = value;\n            CallContextData.Value = new ContextProperties\n            {\n                Values = values\n            };\n        }\n\n        /// <summary>\n        /// Remove a value from the request context.\n        /// </summary>\n        /// <param name=\"key\">The key for the value to be removed.</param>\n        /// <returns><see langword=\"true\"/> if the value was previously in the request context and has now been removed, otherwise <see langword=\"false\"/>.</returns>\n        public static bool Remove(string key)\n        {\n            var properties = CallContextData.Value;\n            var values = properties.Values;\n\n            if (values == null || values.Count == 0 || !values.ContainsKey(key))\n            {\n                return false;\n            }\n\n            if (values.Count == 1)\n            {\n                CallContextData.Value = new ContextProperties\n                {\n                    Values = null\n                };\n                return true;\n            }\n            else\n            {\n                var newValues = new Dictionary<string, object>(values);\n                newValues.Remove(key);\n                CallContextData.Value = new ContextProperties\n                {\n                    Values = newValues\n                };\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Clears the current request context.\n        /// </summary>\n        public static void Clear()\n        {\n            // Remove the key to prevent passing of its value from this point on\n            if (!CallContextData.Value.IsDefault)\n            {\n                CallContextData.Value = default;\n            }\n        }\n\n        /// <summary>\n        /// Gets the collection of keys for the values currently in the request context.\n        /// </summary>\n        public static IEnumerable<string> Keys => CallContextData.Value.Values?.Keys ?? Enumerable.Empty<string>();\n\n        /// <summary>\n        /// Gets the collection of entries currently in the request context.\n        /// </summary>\n        public static IEnumerable<KeyValuePair<string, object>> Entries => CallContextData.Value.Values ?? Enumerable.Empty<KeyValuePair<string, object>>();\n\n        internal readonly struct ContextProperties\n        {\n            public Dictionary<string, object>? Values { get; init; }\n            public bool IsDefault => Values is null;\n        }\n\n        public readonly struct ReentrancySection : IDisposable\n        {\n            private readonly Guid _originalReentrancyId;\n            private readonly Guid _newReentrancyId;\n\n            public ReentrancySection(Guid originalReentrancyId, Guid newReentrancyId)\n            {\n                _originalReentrancyId = originalReentrancyId;\n                _newReentrancyId = newReentrancyId;\n\n                if (newReentrancyId != originalReentrancyId)\n                {\n                    ReentrancyId = newReentrancyId;\n                }\n\n                if (newReentrancyId != Guid.Empty)\n                {\n                    var grain = RuntimeContext.Current as ICallChainReentrantGrainContext;\n                    grain?.OnEnterReentrantSection(_newReentrancyId);\n                }\n            }\n\n            public void Dispose()\n            {\n                if (_newReentrancyId != Guid.Empty)\n                {\n                    var grain = RuntimeContext.Current as ICallChainReentrantGrainContext;\n                    grain?.OnExitReentrantSection(_newReentrancyId);\n                }\n\n                if (_newReentrancyId != _originalReentrancyId)\n                {\n                    ReentrancyId = _originalReentrancyId;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Runtime/RuntimeContext.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Functionality for managing the current grain context.\n    /// </summary>\n    internal static class RuntimeContext\n    {\n        /// <summary>\n        /// The thread-local context.\n        /// </summary>\n        [ThreadStatic]\n        private static IGrainContext? _threadLocalContext;\n\n        /// <summary>\n        /// Gets the current grain context.\n        /// </summary>\n        public static IGrainContext? Current => _threadLocalContext;\n\n        /// <summary>\n        /// Sets the current grain context.\n        /// </summary>\n        /// <param name=\"newContext\">The new context.</param>\n        /// <param name=\"currentContext\">The current context at the time of the call.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static void SetExecutionContext(IGrainContext newContext, out IGrainContext? currentContext)\n        {\n            currentContext = _threadLocalContext;\n            _threadLocalContext = newContext;\n        }\n\n        /// <summary>\n        /// Resets the current grain context to the provided original context.\n        /// </summary>\n        /// <param name=\"originalContext\">The original context.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static void ResetExecutionContext(IGrainContext? originalContext)\n        {\n            _threadLocalContext = originalContext;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Services/IGrainService.cs",
    "content": "namespace Orleans.Services\n{\n    /// <summary>\n    /// Base interface for grain services.\n    /// </summary>\n    public interface IGrainService : ISystemTarget\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Services/IGrainServiceClient.cs",
    "content": "namespace Orleans.Services\n{\n    /// <summary>\n    /// Base interface for grain service clients.\n    /// </summary>\n    /// <typeparam name=\"TGrainService\">The grain service interface type.</typeparam>\n    public interface IGrainServiceClient<TGrainService>\n        where TGrainService : IGrainService\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Statistics/EnvironmentStatisticExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Statistics;\n\ninternal static class EnvironmentStatisticExtensions\n{\n    public static bool IsValid(this EnvironmentStatistics statistics)\n        => statistics.MaximumAvailableMemoryBytes > 0;\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Statistics/IAppEnvironmentStatistics.cs",
    "content": "using System;\n\nnamespace Orleans.Statistics\n{\n    /// <summary>\n    /// Provides functionality for accessing statistics relating to the application environment.\n    /// </summary>\n    [Obsolete($\"This functionality will be removed, use {nameof(IEnvironmentStatisticsProvider)}.{nameof(IEnvironmentStatisticsProvider.GetEnvironmentStatistics)} instead.\")]\n    public interface IAppEnvironmentStatistics\n    {\n        /// <summary>\n        /// Gets the total memory usage, in bytes, if available.\n        /// </summary>\n        long? MemoryUsage { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Statistics/IEnvironmentStatisticsProvider.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization;\nusing System.Diagnostics;\n\nnamespace Orleans.Statistics;\n\n/// <summary>\n/// Provides statistics about the current process and its execution environment.\n/// </summary>\npublic interface IEnvironmentStatisticsProvider\n{\n    /// <summary>\n    /// Gets the current environment statistics. May apply filtering or processing based on the runtime configuration.\n    /// </summary>\n    EnvironmentStatistics GetEnvironmentStatistics();\n}\n\n// This struct is intentionally 'packed' in order to avoid extra padding.\n// This will be created very frequently, so we reduce stack size and lower the serialization cost.\n// As more fields are added to this, they could be placed in such a manner that it may result in a lot of 'empty' space.\n/// <summary>\n/// Contains statistics about the current process and its execution environment.\n/// </summary>\n[Immutable]\n[GenerateSerializer]\n[StructLayout(LayoutKind.Sequential, Pack = 1)]\n[Alias(\"Orleans.Statistics.EnvironmentStatistics\")]\n[DebuggerDisplay(\"{ToString(),nq}\")]\npublic readonly struct EnvironmentStatistics\n{\n    /// <summary>\n    /// The system CPU usage.\n    /// <br/>\n    /// Applies Kalman filtering to smooth out short-term fluctuations.\n    /// See <see href=\"https://en.wikipedia.org/wiki/Kalman_filter\"/>;\n    /// <see href=\"https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/\"/>\n    /// </summary>\n    /// <remarks>Ranges from 0.0-100.0.</remarks>\n    [Id(0)]\n    public readonly float FilteredCpuUsagePercentage;\n\n    /// <summary>\n    /// The amount of managed memory currently consumed by the process.\n    /// <br/>\n    /// Applies Kalman filtering to smooth out short-term fluctuations.\n    /// See <see href=\"https://en.wikipedia.org/wiki/Kalman_filter\"/>;\n    /// <see href=\"https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/\"/>\n    /// </summary>\n    /// <remarks>\n    /// Includes fragmented memory, which is the unused memory between objects on the managed heaps.\n    /// </remarks>\n    [Id(1)]\n    public readonly long FilteredMemoryUsageBytes;\n\n    /// <summary>\n    /// The amount of memory currently available for allocations to the process.\n    /// <br/>\n    /// Applies Kalman filtering to smooth out short-term fluctuations.\n    /// See <see href=\"https://en.wikipedia.org/wiki/Kalman_filter\"/>;\n    /// <see href=\"https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/\"/>\n    /// </summary>\n    /// <remarks>\n    /// Includes the currently available memory of the process and the system.\n    /// </remarks>\n    [Id(2)]\n    public readonly long FilteredAvailableMemoryBytes;\n\n    /// <summary>\n    /// The maximum amount of memory available to the process.\n    /// </summary>\n    /// <remarks>\n    /// This value is computed as the lower of two amounts:\n    /// <list type=\"bullet\">\n    ///   <item><description>The amount of memory after which the garbage collector will begin aggressively collecting memory, defined by <see cref=\"GCMemoryInfo.HighMemoryLoadThresholdBytes\"/>.</description></item>\n    ///   <item><description>The process' configured memory limit, defined by <see cref=\"GCMemoryInfo.TotalAvailableMemoryBytes\"/>.</description></item>\n    /// </list>\n    /// Memory limits are common in containerized environments. For more information on configuring memory limits, see <see href=\"https://learn.microsoft.com/en-us/dotnet/core/runtime-config/garbage-collector#heap-limit\"/>\n    /// </remarks>\n    [Id(3)]\n    public readonly long MaximumAvailableMemoryBytes;\n\n    /// <summary>\n    /// The system CPU usage.\n    /// </summary>\n    /// <remarks>Ranges from 0.0-100.0.</remarks>\n    [Id(4)]\n    public readonly float RawCpuUsagePercentage;\n\n    /// <summary>\n    /// The amount of managed memory currently consumed by the process.\n    /// </summary>\n    [Id(5)]\n    public readonly long RawMemoryUsageBytes;\n\n    /// <summary>\n    /// The amount of memory currently available for allocations to the process.\n    /// </summary>\n    [Id(6)]\n    public readonly long RawAvailableMemoryBytes;\n\n    /// <summary>\n    /// Gets the percentage of memory used relative to currently available memory, clamped between 0 and 100.\n    /// </summary>\n    public float MemoryUsagePercentage\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var percent = (double)RawMemoryUsageBytes / MaximumAvailableMemoryBytes * 100.0;\n            return (float)Math.Clamp(percent, 0.0, 100.0);\n        }\n    }\n\n    /// <summary>\n    /// Gets the percentage of available memory relative to currently used memory, clamped between 0 and 100.\n    /// </summary>\n    /// <remarks>\n    /// A value of <c>0</c> indicates that all available memory is currently in use.\n    /// A value of <c>100</c> indicates that all memory is currently available.\n    /// </remarks>\n    public float AvailableMemoryPercentage\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var percent = (double)RawAvailableMemoryBytes / MaximumAvailableMemoryBytes * 100.0;\n            return (float)Math.Clamp(percent, 0.0, 100.0);\n        }\n    }\n\n    /// <summary>\n    /// Gets the normalized memory usage (0.0 to 1.0).\n    /// </summary>\n    public float NormalizedMemoryUsage\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var fraction = (double)RawMemoryUsageBytes / MaximumAvailableMemoryBytes;\n            return (float)Math.Clamp(fraction, 0.0, 1.0);\n        }\n    }\n\n    /// <summary>\n    /// Gets the normalized filtered memory usage (0.0 to 1.0).\n    /// </summary>\n    public float NormalizedFilteredMemoryUsage\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var fraction = (double)FilteredMemoryUsageBytes / MaximumAvailableMemoryBytes;\n            return (float)Math.Clamp(fraction, 0.0, 1.0);\n        }\n    }\n\n    /// <summary>\n    /// Gets the normalized available memory (0.0 to 1.0).\n    /// </summary>\n    public float NormalizedAvailableMemory\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var fraction = (double)RawAvailableMemoryBytes / MaximumAvailableMemoryBytes;\n            return (float)Math.Clamp(fraction, 0.0, 1.0);\n        }\n    }\n\n    /// <summary>\n    /// Gets the normalized filtered available memory (0.0 to 1.0).\n    /// </summary>\n    public float NormalizedFilteredAvailableMemory\n    {\n        get\n        {\n            if (MaximumAvailableMemoryBytes <= 0) return 0f;\n            var fraction = (double)FilteredAvailableMemoryBytes / MaximumAvailableMemoryBytes;\n            return (float)Math.Clamp(fraction, 0.0, 1.0);\n        }\n    }\n\n    private static string FormatBytes(long bytes)\n    {\n        const long KB = 1024;\n        const long MB = KB * 1024;\n        const long GB = MB * 1024;\n        if (bytes >= GB)\n            return $\"{bytes / (double)GB:F2} GB\";\n        if (bytes >= MB)\n            return $\"{bytes / (double)MB:F2} MB\";\n        if (bytes >= KB)\n            return $\"{bytes / (double)KB:F2} KB\";\n        return $\"{bytes} B\";\n    }\n\n    public override string ToString()\n        => $\"CpuUsage: {FilteredCpuUsagePercentage:F2}% (raw: {RawCpuUsagePercentage:F2}%) | \" +\n           $\"MemoryUsage: {FormatBytes(FilteredMemoryUsageBytes)} (raw: {FormatBytes(RawMemoryUsageBytes)}) [{MemoryUsagePercentage:F2}%] | \" +\n           $\"AvailableMemory: {FormatBytes(FilteredAvailableMemoryBytes)} (raw: {FormatBytes(RawAvailableMemoryBytes)}) [{AvailableMemoryPercentage:F2}%] | \" +\n           $\"MaximumAvailableMemory: {FormatBytes(MaximumAvailableMemoryBytes)}\";\n\n    internal EnvironmentStatistics(\n        float cpuUsagePercentage,\n        float rawCpuUsagePercentage,\n        long memoryUsageBytes,\n        long rawMemoryUsageBytes,\n        long availableMemoryBytes,\n        long rawAvailableMemoryBytes,\n        long maximumAvailableMemoryBytes)\n    {\n        FilteredCpuUsagePercentage = Math.Clamp(cpuUsagePercentage, 0f, 100f);\n        RawCpuUsagePercentage = Math.Clamp(rawCpuUsagePercentage, 0f, 100f);\n        FilteredMemoryUsageBytes = memoryUsageBytes;\n        RawMemoryUsageBytes = rawMemoryUsageBytes;\n        FilteredAvailableMemoryBytes = availableMemoryBytes;\n        RawAvailableMemoryBytes = rawAvailableMemoryBytes;\n        MaximumAvailableMemoryBytes = maximumAvailableMemoryBytes;\n\n#if DEBUG\n        Debug.Assert(MaximumAvailableMemoryBytes >= 0, $\"{nameof(MaximumAvailableMemoryBytes)} must be non-negative. {this}\");\n        Debug.Assert(RawMemoryUsageBytes >= 0, $\"{nameof(RawMemoryUsageBytes)} must be non-negative. {this}\");\n        Debug.Assert(RawAvailableMemoryBytes >= 0, $\"{nameof(RawAvailableMemoryBytes)} must be non-negative. {this}\");\n        Debug.Assert(RawMemoryUsageBytes + RawAvailableMemoryBytes <= MaximumAvailableMemoryBytes,\n            $\"Sum of {nameof(RawMemoryUsageBytes)} and {nameof(RawAvailableMemoryBytes)} must not exceed {nameof(MaximumAvailableMemoryBytes)}. {this}\");\n\n        Debug.Assert(FilteredMemoryUsageBytes >= 0, $\"{nameof(FilteredMemoryUsageBytes)} must be non-negative. {this}\");\n        Debug.Assert(FilteredAvailableMemoryBytes >= 0, $\"{nameof(FilteredAvailableMemoryBytes)} must be non-negative. {this}\");\n\n        Debug.Assert(RawCpuUsagePercentage is >= 0.0f and <= 100.0f, $\"{nameof(RawCpuUsagePercentage)} must be between 0.0 and 100.0. {this}\");\n        Debug.Assert(FilteredCpuUsagePercentage is >= 0.0f and <= 100.0f, $\"{nameof(FilteredCpuUsagePercentage)} must be between 0.0 and 100.0. {this}\");\n\n        Debug.Assert(MemoryUsagePercentage is >= 0.0f and <= 100.0f, $\"{nameof(MemoryUsagePercentage)} must be between 0.0 and 100.0. {this}\");\n        Debug.Assert(AvailableMemoryPercentage is >= 0.0f and <= 100.0f, $\"{nameof(AvailableMemoryPercentage)} must be between 0.0 and 100.0. {this}\");\n        Debug.Assert(NormalizedMemoryUsage is >= 0.0f and <= 1.0f, $\"{nameof(NormalizedMemoryUsage)} must be between 0.0 and 1.0. {this}\");\n        Debug.Assert(NormalizedAvailableMemory is >= 0.0f and <= 1.0f, $\"{nameof(NormalizedAvailableMemory)} must be between 0.0 and 1.0. {this}\");\n        Debug.Assert(NormalizedFilteredMemoryUsage is >= 0.0f and <= 1.0f, $\"{nameof(NormalizedFilteredMemoryUsage)} must be between 0.0 and 1.0. {this}\");\n        Debug.Assert(NormalizedFilteredAvailableMemory is >= 0.0f and <= 1.0f, $\"{nameof(NormalizedFilteredAvailableMemory)} must be between 0.0 and 1.0. {this}\");\n#endif\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Statistics/IHostEnvironmentStatistics.cs",
    "content": "using System;\n\nnamespace Orleans.Statistics\n{\n\n    /// <summary>\n    /// Functionality for accessing statistics relating to the hosting environment.\n    /// </summary>\n    [Obsolete($\"This functionality will be removed, use {nameof(IEnvironmentStatisticsProvider)}.{nameof(IEnvironmentStatisticsProvider.GetEnvironmentStatistics)} instead.\")]\n    public interface IHostEnvironmentStatistics\n    {\n        /// <summary>\n        /// Gets the total physical memory on the host in bytes.\n        /// </summary>\n        /// <example>\n        /// <c>16426476000L</c> for 16 GB.\n        /// </example>\n        long? TotalPhysicalMemory { get; }\n\n        /// <summary>\n        /// Gets the host CPU usage from 0.0-100.0.\n        /// </summary>\n        /// <example>\n        /// <c>70.0f</c> for 70% CPU usage.\n        /// </example>\n        float? CpuUsage { get; }\n\n        /// <summary>\n        /// Gets the total memory available for allocation on the host in bytes.\n        /// </summary>\n        /// <example>\n        /// <c>14426476000L</c> for 14 GB.\n        /// </example>\n        long? AvailableMemory { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/SystemTargetInterfaces/ISystemTarget.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// This is a markup interface for system targets.\n    /// System target are internal runtime objects that share some behavior with grains, but also impose certain restrictions. In particular:\n    /// System target are asynchronously addressable actors.\n    /// Proxy class is being generated for ISystemTarget, just like for IGrain\n    /// System target are scheduled by the runtime scheduler and follow turn based concurrency.\n    /// </summary>\n    public interface ISystemTarget : IAddressable\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/SystemTargetInterfaces/ISystemTargetBase.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Internal interface implemented by the SystemTarget base class that enables generation of grain references for system targets.\n    /// </summary>\n    internal interface ISystemTargetBase : IGrainContext\n    {\n        /// <summary>\n        /// Gets the address of the server which this system target is activated on.\n        /// </summary>\n        SiloAddress Silo { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/SystemTargetInterfaces/IVersionManager.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Functionality for managing how grain interface versions are negotiated.\n    /// </summary>\n    public interface IVersionManager\n    {\n        /// <summary>\n        /// Set the compatibility strategy.\n        /// </summary>\n        /// <param name=\"strategy\">The strategy to set. Set to <see langword=\"null\"/> to revert to the default strategy provided in configuration.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task SetCompatibilityStrategy(CompatibilityStrategy strategy);\n\n        /// <summary>\n        /// Set the selector strategy.\n        /// </summary>\n        /// <param name=\"strategy\">The strategy to set. Set to <see langword=\"null\"/> to revert to the default strategy provided in configuration.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task SetSelectorStrategy(VersionSelectorStrategy strategy);\n\n        /// <summary>\n        /// Set the compatibility strategy for a specific interface.\n        /// </summary>\n        /// <param name=\"interfaceType\">The type of the interface.</param>\n        /// <param name=\"strategy\">The strategy to set. Set to <see langword=\"null\"/> to revert to the default strategy provided in configuration.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task SetCompatibilityStrategy(GrainInterfaceType interfaceType, CompatibilityStrategy strategy);\n\n        /// <summary>\n        /// Set the selector strategy for a specific interface.\n        /// </summary>\n        /// <param name=\"interfaceType\">The type of the interface.</param>\n        /// <param name=\"strategy\">The strategy to set. Set to <see langword=\"null\"/> to revert to the default strategy provided in configuration.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task SetSelectorStrategy(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Timers/GrainTimerCreationOptions.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing Orleans.Concurrency;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Options for creating grain timers.\n/// </summary>\npublic readonly struct GrainTimerCreationOptions()\n{\n    /// <summary>\n    /// Initializes a new <see cref=\"GrainTimerCreationOptions\"/> instance.\n    /// </summary>\n    /// <param name=\"dueTime\">\n    /// A <see cref=\"TimeSpan\"/> representing the amount of time to delay before invoking the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n    /// Specify <see cref=\"TimeSpan.Zero\"/> to start the timer immediately.\n    /// </param>\n    /// <param name=\"period\">\n    /// The time interval between invocations of the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan \"/> to disable periodic signaling.\n    /// </param>\n    [SetsRequiredMembers]\n    public GrainTimerCreationOptions(TimeSpan dueTime, TimeSpan period) : this()\n    {\n        DueTime = dueTime;\n        Period = period;\n    }\n\n    /// <summary>\n    /// A <see cref=\"TimeSpan\"/> representing the amount of time to delay before invoking the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n    /// Specify <see cref=\"TimeSpan.Zero\"/> to start the timer immediately.\n    /// </summary>\n    public required TimeSpan DueTime { get; init; }\n\n    /// <summary>\n    /// The time interval between invocations of the callback method specified when the <see cref=\"IGrainTimer\"/> was constructed.\n    /// Specify <see cref=\"Timeout.InfiniteTimeSpan \"/> to disable periodic signaling.\n    /// </summary>\n    public required TimeSpan Period { get; init; }\n\n    /// <summary>\n    /// Gets a value indicating whether callbacks scheduled by this timer are allowed to interleave execution with other timers and grain calls.\n    /// Defaults to <see langword=\"false\"/>.\n    /// </summary>\n    /// <remarks>\n    /// If this value is <see langword=\"false\"/>, the timer callback will be treated akin to a grain call. If the grain scheduling this timer is reentrant\n    /// (i.e., it has the <see cref=\"ReentrantAttribute\"/> attributed applied to its implementation class), the timer callback will be allowed\n    /// to interleave with other grain calls and timers regardless of the value of this property.\n    /// If this value is <see langword=\"true\"/>, the timer callback will be allowed to interleave with other timers and grain calls.\n    /// </remarks>\n    public bool Interleave { get; init; }\n\n    /// <summary>\n    /// Gets a value indicating whether callbacks scheduled by this timer should extend the lifetime of the grain activation.\n    /// Defaults to <see langword=\"false\"/>.\n    /// </summary>\n    /// <remarks>\n    /// If this value is <see langword=\"false\"/>, timer callbacks will not extend a grain activation's lifetime.\n    /// If a grain is only processing this timer's callbacks and no other messages, the grain will be collected after its idle collection period expires.\n    /// If this value is <see langword=\"true\"/>, timer callback will extend a grain activation's lifetime.\n    /// If the timer period is shorter than the grain's idle collection period, the grain will not be collected due to idleness.\n    /// </remarks>\n    public bool KeepAlive { get; init; }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Timers/ITimerRegistry.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Timers;\n\n/// <summary>\n/// Functionality for managing grain timers.\n/// </summary>\npublic interface ITimerRegistry\n{\n    /// <summary>\n    /// Creates a grain timer.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain which the timer is associated with.</param>\n    /// <param name=\"callback\">The timer callback, which will fire whenever the timer becomes due.</param>\n    /// <param name=\"state\">The state object passed to the callback.</param>\n    /// <param name=\"dueTime\">\n    /// The amount of time to delay before the <paramref name=\"callback\"/> is invoked.\n    /// Specify <see cref=\"System.Threading.Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n    /// Specify <see cref=\"TimeSpan.Zero\"/> to invoke the callback promptly.\n    /// </param>\n    /// <param name=\"period\">\n    /// The time interval between invocations of <paramref name=\"callback\"/>.\n    /// Specify <see cref=\"System.Threading.Timeout.InfiniteTimeSpan\"/> to disable periodic signaling.\n    /// </param>\n    /// <returns>\n    /// An <see cref=\"IDisposable\"/> instance which represents the timer.\n    /// </returns>\n    [Obsolete(\"Use 'RegisterGrainTimer(grainContext, callback, state, new() { DueTime = dueTime, Period = period, Interleave = true })' instead.\")]\n    IDisposable RegisterTimer(IGrainContext grainContext, Func<object?, Task> callback, object? state, TimeSpan dueTime, TimeSpan period);\n\n    /// <inheritdoc cref=\"GrainBaseExtensions.RegisterGrainTimer{TState}(IGrainBase, Func{TState, CancellationToken, Task}, TState, GrainTimerCreationOptions)\"/>\n    /// <param name=\"grainContext\">The grain which the timer is associated with.</param>\n    /// <typeparam name=\"TState\">The type of the <paramref name=\"state\"/> parameter.</typeparam>\n    IGrainTimer RegisterGrainTimer<TState>(IGrainContext grainContext, Func<TState, CancellationToken, Task> callback, TState state, GrainTimerCreationOptions options);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Utils/Interner.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Constants used by the generic <see cref=\"Interner{K, T}\"/> class.\n    /// </summary>\n    internal static class InternerConstants\n    {\n        /* Recommended cache sizes, based on expansion policy of ConcurrentDictionary\n        // Internal implementation of ConcurrentDictionary resizes to prime numbers (not divisible by 3 or 5 or 7)\n        31\n        67\n        137\n        277\n        557\n        1,117\n        2,237\n        4,477\n        8,957\n        17,917\n        35,837\n        71,677\n        143,357\n        286,717\n        573,437\n        1,146,877\n        2,293,757\n        4,587,517\n        9,175,037\n        18,350,077\n        36,700,157\n        */\n        public const int SIZE_SMALL = 67;\n        public const int SIZE_MEDIUM = 1117;\n        public const int SIZE_LARGE = 143357;\n        public const int SIZE_X_LARGE = 2293757;\n    }\n\n    /// <summary>\n    /// Provide a weakly-referenced cache of interned objects.\n    /// Interner is used to optimize garbage collection.\n    /// We use it to store objects that are allocated frequently and may have long lifetime.\n    /// This means those object may quickly fill gen 2 and cause frequent costly full heap collections.\n    /// Specifically, a message that arrives to a silo and all the headers and ids inside it may stay alive long enough to reach gen 2.\n    /// Therefore, we store all ids in interner to re-use their memory across different messages.\n    /// </summary>\n    /// <typeparam name=\"TKey\">Type of objects to be used for intern keys.</typeparam>\n    /// <typeparam name=\"TValue\">Type of objects to be interned.</typeparam>\n    internal sealed class Interner<TKey, TValue> : IDisposable\n        where TKey : IEquatable<TKey>\n        where TValue : class\n    {\n        private readonly Timer cacheCleanupTimer;\n\n        [NonSerialized]\n        private readonly ConcurrentDictionary<TKey, WeakReference<TValue>> internCache;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Interner{K, T}\"/> class.\n        /// </summary>\n        /// <param name=\"initialSize\">The initial size of the interner mapping.</param>\n        public Interner(int initialSize = InternerConstants.SIZE_SMALL)\n        {\n            int concurrencyLevel = Environment.ProcessorCount; // Default from ConcurrentDictionary class in .NET Core for size 31\n            if (initialSize >= InternerConstants.SIZE_MEDIUM) concurrencyLevel *= 4;\n            if (initialSize >= InternerConstants.SIZE_LARGE) concurrencyLevel *= 4;\n            concurrencyLevel = Math.Min(concurrencyLevel, 1024);\n            this.internCache = new ConcurrentDictionary<TKey, WeakReference<TValue>>(concurrencyLevel, initialSize);\n\n            var period = TimeSpan.FromMinutes(10);\n            var dueTime = period + TimeSpan.FromTicks(Random.Shared.Next((int)TimeSpan.TicksPerMinute)); // add some initial jitter\n            cacheCleanupTimer = new Timer(InternCacheCleanupTimerCallback, null, dueTime, period);\n        }\n\n        /// <summary>\n        /// Find cached copy of object with specified key, otherwise create new one using the supplied creator-function.\n        /// </summary>\n        /// <param name=\"key\">key to find</param>\n        /// <param name=\"creatorFunc\">function to create new object and store for this key if no cached copy exists</param>\n        /// <returns>Object with specified key - either previous cached copy or newly created</returns>\n        public TValue FindOrCreate(TKey key, Func<TKey, TValue> creatorFunc)\n        {\n            // Attempt to get the existing value from cache.\n            // If no cache entry exists, create and insert a new one using the creator function.\n            if (!internCache.TryGetValue(key, out var cacheEntry))\n            {\n                var obj = creatorFunc(key);\n                internCache[key] = new WeakReference<TValue>(obj);\n                return obj;\n            }\n\n            // If a cache entry did exist, determine if it still holds a valid value.\n            if (!cacheEntry.TryGetTarget(out var result))\n            {\n                // Create new object and ensure the entry is still valid by re-inserting it into the cache.\n                var obj = creatorFunc(key);\n                cacheEntry.SetTarget(obj);\n                return obj;\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Find cached copy of object with specified key, otherwise create new one using the supplied creator-function.\n        /// </summary>\n        /// <param name=\"key\">key to find</param>\n        /// <param name=\"creatorFunc\">function to create new object and store for this key if no cached copy exists</param>\n        /// <param name=\"state\">State to be passed to <paramref name=\"creatorFunc\"/>.</param>\n        /// <returns>Object with specified key - either previous cached copy or newly created</returns>\n        public TValue FindOrCreate<TState>(TKey key, Func<TKey, TState, TValue> creatorFunc, TState state)\n        {\n            // Attempt to get the existing value from cache.\n            // If no cache entry exists, create and insert a new one using the creator function.\n            if (!internCache.TryGetValue(key, out var cacheEntry))\n            {\n                var obj = creatorFunc(key, state);\n                internCache[key] = new WeakReference<TValue>(obj);\n                return obj;\n            }\n\n            // If a cache entry did exist, determine if it still holds a valid value.\n            if (!cacheEntry.TryGetTarget(out var result))\n            {\n                // Create new object and ensure the entry is still valid by re-inserting it into the cache.\n                var obj = creatorFunc(key, state);\n                cacheEntry.SetTarget(obj);\n                return obj;\n            }\n\n            return result;\n        }\n\n        private void InternCacheCleanupTimerCallback(object? state)\n        {\n            foreach (var e in internCache)\n            {\n                if (!e.Value.TryGetTarget(out _))\n                {\n                    internCache.TryRemove(e.Key, out _);\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            cacheCleanupTimer?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Utils/PublicOrleansTaskExtensions.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Utility functions for dealing with <see cref=\"Task\"/> instances.\n    /// </summary>\n    public static class PublicOrleansTaskExtensions\n    {\n        private static readonly Action<Task> IgnoreTaskContinuation = t => { _ = t.Exception; };\n\n        /// <summary>\n        /// Observes and ignores a potential exception on a given Task.\n        /// If a Task fails and throws an exception which is never observed, it will be caught by the .NET finalizer thread.\n        /// This function awaits the given task and if the exception is thrown, it observes this exception and simply ignores it.\n        /// This will prevent the escalation of this exception to the .NET finalizer thread.\n        /// </summary>\n        /// <param name=\"task\">The task to be ignored.</param>\n        public static void Ignore(this Task task)\n        {\n            if (task.IsCompleted)\n            {\n                _ = task.Exception;\n            }\n            else\n            {\n                task.ContinueWith(\n                    IgnoreTaskContinuation,\n                    CancellationToken.None,\n                    TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously,\n                    TaskScheduler.Default);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Utils/SpanFormattableIPEndPoint.cs",
    "content": "using System;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace Orleans;\n\ninternal readonly struct SpanFormattableIPEndPoint : ISpanFormattable\n{\n    private readonly IPEndPoint? _value;\n\n    public SpanFormattableIPEndPoint(IPEndPoint? value) => _value = value;\n\n    public override string ToString() => $\"{this}\";\n    public string ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n    public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n    {\n        if (_value is null)\n        {\n            charsWritten = 0;\n            return true;\n        }\n\n        return _value.Address.AddressFamily == AddressFamily.InterNetworkV6\n            ? destination.TryWrite($\"[{new SpanFormattableIPAddress(_value.Address)}]:{_value.Port}\", out charsWritten)\n            : destination.TryWrite($\"{new SpanFormattableIPAddress(_value.Address)}:{_value.Port}\", out charsWritten);\n    }\n}\n\ninternal readonly struct SpanFormattableIPAddress : ISpanFormattable\n{\n    private readonly IPAddress _value;\n\n    public SpanFormattableIPAddress(IPAddress value) => _value = value;\n\n    public override string ToString() => _value.ToString();\n    public string ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n    public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => _value.TryFormat(destination, out charsWritten);\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Utils/Utils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The Utils class contains a variety of utility methods for use in application and grain code.\n    /// </summary>\n    public static partial class Utils\n    {\n        /// <summary>\n        /// Returns a human-readable text string that describes an IEnumerable collection of objects.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the list elements.</typeparam>\n        /// <param name=\"collection\">The IEnumerable to describe.</param>\n        /// <param name=\"toString\">Converts the element to a string. If none specified, <see cref=\"object.ToString\"/> will be used.</param>\n        /// <param name=\"separator\">The separator to use.</param>\n        /// <param name=\"putInBrackets\">Puts elements within brackets</param>\n        /// <returns>A string assembled by wrapping the string descriptions of the individual\n        /// elements with square brackets and separating them with commas.</returns>\n        public static string EnumerableToString<T>(IEnumerable<T>? collection, Func<T, string>? toString = null,\n                                                        string separator = \", \", bool putInBrackets = true)\n        {\n            if (collection == null)\n                return putInBrackets ? \"[]\" : \"null\";\n\n            if (collection is ICollection<T> { Count: 0 })\n                return putInBrackets ? \"[]\" : \"\";\n\n            var enumerator = collection.GetEnumerator();\n            if (!enumerator.MoveNext())\n                return putInBrackets ? \"[]\" : \"\";\n\n            var firstValue = enumerator.Current;\n            if (!enumerator.MoveNext())\n            {\n                return putInBrackets\n                    ? toString != null ? $\"[{toString(firstValue)}]\" : firstValue == null ? \"[null]\" : $\"[{firstValue}]\"\n                    : toString != null ? toString(firstValue) : firstValue == null ? \"null\" : (firstValue.ToString() ?? \"\");\n            }\n\n            var sb = new StringBuilder();\n            if (putInBrackets) sb.Append('[');\n\n            if (toString != null) sb.Append(toString(firstValue));\n            else if (firstValue == null) sb.Append(\"null\");\n            else sb.Append($\"{firstValue}\");\n\n            do\n            {\n                sb.Append(separator);\n\n                var value = enumerator.Current;\n                if (toString != null) sb.Append(toString(value));\n                else if (value == null) sb.Append(\"null\");\n                else sb.Append($\"{value}\");\n            } while (enumerator.MoveNext());\n\n            if (putInBrackets) sb.Append(']');\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// Returns a human-readable text string that describes a dictionary that maps objects to objects.\n        /// </summary>\n        /// <typeparam name=\"T1\">The type of the dictionary keys.</typeparam>\n        /// <typeparam name=\"T2\">The type of the dictionary elements.</typeparam>\n        /// <param name=\"dict\">The dictionary to describe.</param>\n        /// <param name=\"toString\">Converts the element to a string. If none specified, <see cref=\"object.ToString\"/> will be used.</param>\n        /// <param name=\"separator\">The separator to use. If none specified, the elements should appear separated by a new line.</param>\n        /// <returns>A string assembled by wrapping the string descriptions of the individual\n        /// pairs with square brackets and separating them with commas.\n        /// Each key-value pair is represented as the string description of the key followed by\n        /// the string description of the value,\n        /// separated by \" -> \", and enclosed in curly brackets.</returns>\n        public static string DictionaryToString<T1, T2>(ICollection<KeyValuePair<T1, T2>> dict, Func<T2, string?>? toString = null, string? separator = null)\n        {\n            if (dict == null || dict.Count == 0)\n            {\n                return \"[]\";\n            }\n            if (separator == null)\n            {\n                separator = Environment.NewLine;\n            }\n            var sb = new StringBuilder(\"[\");\n            var enumerator = dict.GetEnumerator();\n            int index = 0;\n            while (enumerator.MoveNext())\n            {\n                var pair = enumerator.Current;\n                sb.Append(\"{\");\n                sb.Append(pair.Key);\n                sb.Append(\" -> \");\n\n                string? val;\n                if (toString != null)\n                    val = toString(pair.Value);\n                else\n                    val = pair.Value == null ? \"null\" : pair.Value.ToString();\n                sb.Append(val);\n\n                sb.Append(\"}\");\n                if (index++ < dict.Count - 1)\n                    sb.Append(separator);\n            }\n            sb.Append(\"]\");\n            return sb.ToString();\n        }\n\n        public static string TimeSpanToString(TimeSpan timeSpan)\n        {\n            //00:03:32.8289777\n            return $\"{timeSpan.Hours}h:{timeSpan.Minutes}m:{timeSpan.Seconds}s.{timeSpan.Milliseconds}ms\";\n        }\n\n        public static long TicksToMilliSeconds(long ticks) => ticks / TimeSpan.TicksPerMillisecond;\n\n        public static float AverageTicksToMilliSeconds(float ticks) => ticks / TimeSpan.TicksPerMillisecond;\n\n        /// <summary>\n        /// Parse a Uri as an IPEndpoint.\n        /// </summary>\n        /// <param name=\"uri\">The input Uri</param>\n        /// <returns></returns>\n        public static System.Net.IPEndPoint? ToIPEndPoint(this Uri uri) => uri.Scheme switch\n        {\n            \"gwy.tcp\" => new System.Net.IPEndPoint(System.Net.IPAddress.Parse(uri.Host), uri.Port),\n            _ => null,\n        };\n\n        /// <summary>\n        /// Parse a Uri as a Silo address, excluding the generation identifier.\n        /// </summary>\n        /// <param name=\"uri\">The input Uri</param>\n        public static SiloAddress? ToGatewayAddress(this Uri uri) => uri.Scheme switch\n        {\n            \"gwy.tcp\" => SiloAddress.New(System.Net.IPAddress.Parse(uri.Host), uri.Port, 0),\n            _ => null,\n        };\n\n        /// <summary>\n        /// Represent an IP end point in the gateway URI format..\n        /// </summary>\n        /// <param name=\"ep\">The input IP end point</param>\n        /// <returns></returns>\n        public static Uri ToGatewayUri(this System.Net.IPEndPoint ep) => new($\"gwy.tcp://{new SpanFormattableIPEndPoint(ep)}/0\");\n\n        /// <summary>\n        /// Represent a silo address in the gateway URI format.\n        /// </summary>\n        /// <param name=\"address\">The input silo address</param>\n        /// <returns></returns>\n        public static Uri ToGatewayUri(this SiloAddress address) => new($\"gwy.tcp://{new SpanFormattableIPEndPoint(address.Endpoint)}/{address.Generation}\");\n\n        public static void SafeExecute(Action action)\n        {\n            try\n            {\n                action();\n            }\n            catch { }\n        }\n\n        public static void SafeExecute(Action action, ILogger? logger = null, string? caller = null)\n        {\n            try\n            {\n                action();\n            }\n            catch (Exception exc)\n            {\n                if (logger != null)\n                    LogIgnoredException(logger, exc, caller);\n            }\n        }\n\n        public static async Task SafeExecuteAsync(Task task)\n        {\n            try\n            {\n                await task;\n            }\n            catch { }\n        }\n\n        internal static void LogIgnoredException(ILogger logger, Exception exc, string? caller)\n        {\n            try\n            {\n                if (exc is AggregateException { InnerExceptions.Count: 1 })\n                {\n                    Debug.Assert(exc.InnerException is not null, \"AggregateException should have an inner exception.\");\n                    exc = exc.InnerException;\n                }\n\n                LogWarningIgnoringException(logger, exc, new(exc), caller ?? string.Empty);\n            }\n            catch\n            {\n                // now really, really ignore.\n            }\n        }\n\n        public static IEnumerable<List<T>> BatchIEnumerable<T>(this IEnumerable<T> sequence, int batchSize)\n        {\n            var batch = new List<T>(batchSize);\n            foreach (var item in sequence)\n            {\n                batch.Add(item);\n                // when we've accumulated enough in the batch, send it out  \n                if (batch.Count >= batchSize)\n                {\n                    yield return batch; // batch.ToArray();\n                    batch = new List<T>(batchSize);\n                }\n            }\n            if (batch.Count > 0)\n            {\n                yield return batch; //batch.ToArray();\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public static string GetStackTrace(int skipFrames = 0)\n        {\n            skipFrames += 1; //skip this method from the stack trace\n            return new System.Diagnostics.StackTrace(skipFrames).ToString();\n        }\n\n        private readonly struct ExceptionTypeLogValue(Exception exc)\n        {\n            public override string? ToString() => exc.GetType().FullName;\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100325,\n            Level = LogLevel.Warning,\n            Message = \"Ignoring {ExceptionType} exception thrown from an action called by {Caller}.\"\n        )]\n        private static partial void LogWarningIgnoringException(ILogger logger, Exception exception, ExceptionTypeLogValue exceptionType, string caller);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Compatibility/AllVersionsCompatible.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Compatibility\n{\n    /// <summary>\n    /// A grain interface version compatibility strategy which treats all versions of an interface compatible with any requested version.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class AllVersionsCompatible : CompatibilityStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static AllVersionsCompatible Singleton { get; } = new AllVersionsCompatible();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Compatibility/BackwardCompatible.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Compatibility\n{\n    /// <summary>\n    /// A grain interface version compatibility strategy which treats all versions of an interface compatible only with equal and lower requested versions.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class BackwardCompatible : CompatibilityStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static BackwardCompatible Singleton { get; } = new BackwardCompatible();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Compatibility/ICompatibilityDirector.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Compatibility\n{\n    /// <summary>\n    /// Functionality for grain interface compatibility directors.\n    /// </summary>\n    public interface ICompatibilityDirector\n    {\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the current version of an interface is compatible with the requested version, <see langword=\"false\"/> otherwise.\n        /// </summary>\n        /// <param name=\"requestedVersion\">The requested interface version.</param>\n        /// <param name=\"currentVersion\">The currently available interface version.</param>\n        /// <returns><see langword=\"true\"/> if the current version of an interface is compatible with the requested version, <see langword=\"false\"/> otherwise.</returns>\n        bool IsCompatible(ushort requestedVersion, ushort currentVersion);\n    }\n\n    /// <summary>\n    /// Base class for all grain interface version compatibility strategies.\n    /// </summary>\n    [Serializable, SerializerTransparent]\n    public abstract class CompatibilityStrategy\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Compatibility/StrictVersionCompatible.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Compatibility\n{\n    /// <summary>\n    /// A grain interface version compatibility strategy which treats all versions of an interface compatible only with equal requested versions.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class StrictVersionCompatible : CompatibilityStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static StrictVersionCompatible Singleton { get; } = new StrictVersionCompatible();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/IVersionStore.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Versions\n{\n    /// <summary>\n    /// Functionality for accessing runtime-modifiable grain interface version strategies.\n    /// </summary>\n    public interface IVersionStore : IVersionManager\n    {\n        /// <summary>\n        /// Gets a value indicating whether this instance is enabled.\n        /// </summary>\n        bool IsEnabled { get; }\n\n        /// <summary>\n        /// Gets the mapping from grain interface type to grain interface version compatibility strategy.\n        /// </summary>\n        /// <returns>The mapping from grain interface type to grain interface version compatibility strategy.</returns>\n        Task<Dictionary<GrainInterfaceType, CompatibilityStrategy>> GetCompatibilityStrategies();\n\n        /// <summary>\n        /// Gets the mapping from grain interface type to grain interface version selector strategy.\n        /// </summary>\n        /// <returns>The mapping from grain interface type to grain interface version selector strategy.</returns>\n        Task<Dictionary<GrainInterfaceType, VersionSelectorStrategy>> GetSelectorStrategies();\n\n        /// <summary>\n        /// Gets the default grain interface version compatibility strategy.\n        /// </summary>\n        /// <returns>The default grain interface version compatibility strategy.</returns>\n        Task<CompatibilityStrategy> GetCompatibilityStrategy();\n\n        /// <summary>\n        /// Gets the default grain interface version selector strategy.\n        /// </summary>\n        /// <returns>The default grain interface version selector strategy.</returns>\n        Task<VersionSelectorStrategy> GetSelectorStrategy();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Selector/AllCompatibleVersions.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Selector\n{\n    /// <summary>\n    /// Grain interface version selector which allows any compatible version to be chosen.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class AllCompatibleVersions : VersionSelectorStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static AllCompatibleVersions Singleton { get; } = new AllCompatibleVersions();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Selector/IVersionSelector.cs",
    "content": "using System;\nusing Orleans.Versions.Compatibility;\n\nnamespace Orleans.Versions.Selector\n{\n    /// <summary>\n    /// Functionality for selecting which versions of a grain interface should be preferred when performing grain placement.\n    /// </summary>\n    public interface IVersionSelector\n    {\n        /// <summary>\n        /// Returns a collection of suitable interface versions for a given request.\n        /// </summary>\n        /// <param name=\"requestedVersion\">The requested grain interface version.</param>\n        /// <param name=\"availableVersions\">The collection of available interface versions.</param>\n        /// <param name=\"compatibilityDirector\">The compatibility director.</param>\n        /// <returns>A collection of suitable interface versions for a given request.</returns>\n        ushort[] GetSuitableVersion(ushort requestedVersion, ushort[] availableVersions, ICompatibilityDirector compatibilityDirector);\n    }\n\n    /// <summary>\n    /// Base class for all grain interface version selector strategies.\n    /// </summary>\n    [Serializable, SerializerTransparent]\n    public abstract class VersionSelectorStrategy\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Selector/LatestVersion.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Selector\n{\n    /// <summary>\n    /// Grain interface version selector which always selects the highest compatible version.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class LatestVersion : VersionSelectorStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static LatestVersion Singleton { get; } = new LatestVersion();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/Versions/Selector/MinimumVersion.cs",
    "content": "using System;\n\nnamespace Orleans.Versions.Selector\n{\n    /// <summary>\n    /// Grain interface version selector which always selects the lowest compatible version.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable, SuppressReferenceTracking]\n    public sealed class MinimumVersion : VersionSelectorStrategy\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static MinimumVersion Singleton { get; } = new MinimumVersion();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/build/Microsoft.Orleans.Core.Abstractions.targets",
    "content": "<Project>\n\n  <ItemGroup Condition=\"'$(ImplicitUsings)' == 'enable' or '$(ImplicitUsings)' == 'true'\">\n    <Using Include=\"Orleans\"/>\n    <Using Include=\"Orleans.Runtime\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/buildMultiTargeting/Microsoft.Orleans.Core.Abstractions.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Core.Abstractions.targets\" />\n</Project>\n"
  },
  {
    "path": "src/Orleans.Core.Abstractions/buildTransitive/Microsoft.Orleans.Core.Abstractions.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Core.Abstractions.targets\" />\n</Project>\n"
  },
  {
    "path": "src/Orleans.DurableJobs/DurableJob.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Represents a durable job that will be executed at a specific time.\n/// </summary>\n[GenerateSerializer]\n[Alias(\"Orleans.DurableJobs.DurableJob\")]\npublic sealed class DurableJob\n{\n    /// <summary>\n    /// Gets the unique identifier for this durable job.\n    /// </summary>\n    [Id(0)]\n    public required string Id { get; init; }\n    \n    /// <summary>\n    /// Gets the name of the durable job.\n    /// </summary>\n    [Id(1)]\n    public required string Name { get; init; }\n    \n    /// <summary>\n    /// Gets the time when this job is due to be executed.\n    /// </summary>\n    [Id(2)]\n    public DateTimeOffset DueTime { get; init; }\n    \n    /// <summary>\n    /// Gets the identifier of the target grain that will handle this job.\n    /// </summary>\n    [Id(3)]\n    public GrainId TargetGrainId { get; init; }\n    \n    /// <summary>\n    /// Gets the identifier of the shard that manages this durable job.\n    /// </summary>\n    [Id(4)]\n    public required string ShardId { get; init; }\n    \n    /// <summary>\n    /// Gets optional metadata associated with this durable job.\n    /// </summary>\n    [Id(5)]\n    public IReadOnlyDictionary<string, string>? Metadata { get; init; }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/DurableJobRunResult.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Represents the result of a durable job execution.\n/// </summary>\n[GenerateSerializer]\npublic sealed class DurableJobRunResult\n{\n    /// <summary>\n    /// Gets a value indicating whether the job execution failed.\n    /// </summary>\n    [MemberNotNullWhen(true, nameof(Exception))]\n    public bool IsFailed => Status == DurableJobRunStatus.Failed;\n\n    /// <summary>\n    /// Gets a value indicating whether the job should be polled again after a delay.\n    /// </summary>\n    [MemberNotNullWhen(true, nameof(PollAfterDelay))]\n    public bool IsPending => Status == DurableJobRunStatus.PollAfter;\n\n    private DurableJobRunResult(DurableJobRunStatus status, TimeSpan? pollAfter, Exception? exception)\n    {\n        Status = status;\n        PollAfterDelay = pollAfter;\n        Exception = exception;\n    }\n\n    /// <summary>\n    /// Gets the status of the job execution.\n    /// </summary>\n    [Id(0)]\n    public DurableJobRunStatus Status { get; }\n\n    /// <summary>\n    /// Gets the delay before the next status check when <see cref=\"Status\"/> is <see cref=\"DurableJobRunStatus.PollAfter\"/>.\n    /// </summary>\n    [Id(1)]\n    public TimeSpan? PollAfterDelay { get; }\n\n    /// <summary>\n    /// Gets the exception associated with a failed job execution when <see cref=\"Status\"/> is <see cref=\"DurableJobRunStatus.Failed\"/>.\n    /// </summary>\n    [Id(2)]\n    public Exception? Exception { get; }\n\n    private static readonly DurableJobRunResult CompletedInstance = new(DurableJobRunStatus.Completed, null, null);\n\n    /// <summary>\n    /// Gets a result indicating the job completed successfully.\n    /// </summary>\n    public static DurableJobRunResult Completed => CompletedInstance;\n\n    /// <summary>\n    /// Creates a result indicating the job should be polled again after the specified delay.\n    /// </summary>\n    /// <param name=\"delay\">The time to wait before checking the job status again.</param>\n    /// <returns>A poll-after job result.</returns>\n    /// <remarks>\n    /// The job will remain in an inline polling loop without being re-queued.\n    /// The polling loop will hold a concurrency slot until the job completes or fails.\n    /// TODO: Add validation for minimum/maximum poll delays to prevent abuse.\n    /// TODO: Consider concurrency slot management for long-running polls.\n    /// </remarks>\n    public static DurableJobRunResult PollAfter(TimeSpan delay)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(delay, TimeSpan.Zero, nameof(delay));\n        return new(DurableJobRunStatus.PollAfter, delay, null);\n    }\n\n    /// <summary>\n    /// Creates a result indicating the job failed.\n    /// </summary>\n    /// <param name=\"exception\">The exception that caused the failure. This will be passed to the retry policy.</param>\n    /// <returns>A failed job result.</returns>\n    /// <remarks>\n    /// The exception will be passed to the retry callback to determine if the job should be retried.\n    /// </remarks>\n    public static DurableJobRunResult Failed(Exception exception)\n    {\n        ArgumentNullException.ThrowIfNull(exception);\n        return new(DurableJobRunStatus.Failed, null, exception);\n    }\n}\n\n/// <summary>\n/// Represents the status of a durable job execution.\n/// </summary>\npublic enum DurableJobRunStatus\n{\n    /// <summary>\n    /// The job completed successfully and should be removed from the queue.\n    /// </summary>\n    Completed,\n\n    /// <summary>\n    /// The job is still running and should be polled again after the specified delay.\n    /// </summary>\n    PollAfter,\n\n    /// <summary>\n    /// The job failed and should be processed through the retry policy.\n    /// </summary>\n    Failed\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/Hosting/DurableJobsExtensions.cs",
    "content": "using System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Extensions to <see cref=\"ISiloBuilder\"/> for configuring durable jobs.\n/// </summary>\npublic static class DurableJobsExtensions\n{\n    /// <summary>\n    /// Adds support for durable jobs to this silo.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder AddDurableJobs(this ISiloBuilder builder) => builder.ConfigureServices(services => AddDurableJobs(services));\n\n    /// <summary>\n    /// Adds support for durable jobs to this silo.\n    /// </summary>\n    /// <param name=\"services\">The services.</param>\n    public static void AddDurableJobs(this IServiceCollection services)\n    {\n        if (services.Any(service => service.ServiceType.Equals(typeof(LocalDurableJobManager))))\n        {\n            return;\n        }\n\n        services.AddSingleton<IConfigurationValidator, DurableJobsOptionsValidator>();\n        services.AddSingleton<ShardExecutor>();\n        services.AddSingleton<LocalDurableJobManager>();\n        services.AddFromExisting<ILocalDurableJobManager, LocalDurableJobManager>();\n        services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, LocalDurableJobManager>();\n        services.AddKeyedTransient<IGrainExtension>(typeof(IDurableJobReceiverExtension), (sp, _) =>\n        {\n            var grainContextAccessor = sp.GetRequiredService<IGrainContextAccessor>();\n            return new DurableJobReceiverExtension(grainContextAccessor.GrainContext, sp.GetRequiredService<ILogger<DurableJobReceiverExtension>>());\n        });\n    }\n\n    /// <summary>\n    /// Configures durable jobs storage using an in-memory, non-persistent store.\n    /// </summary>\n    /// <remarks>\n    /// Note that this is for development and testing scenarios only and should not be used in production.\n    /// </remarks>\n    /// <param name=\"builder\">The silo host builder.</param>\n    /// <returns>The provided <see cref=\"ISiloBuilder\"/>, for chaining.</returns>\n    public static ISiloBuilder UseInMemoryDurableJobs(this ISiloBuilder builder)\n    {\n        builder.AddDurableJobs();\n\n        builder.ConfigureServices(services => services.UseInMemoryDurableJobs());\n        return builder;\n    }\n\n    /// <summary>\n    /// Configures durable jobs storage using an in-memory, non-persistent store.\n    /// </summary>\n    /// <remarks>\n    /// Note that this is for development and testing scenarios only and should not be used in production.\n    /// </remarks>\n    /// <param name=\"services\">The service collection.</param>\n    /// <returns>The provided <see cref=\"IServiceCollection\"/>, for chaining.</returns>\n    internal static IServiceCollection UseInMemoryDurableJobs(this IServiceCollection services)\n    {\n        services.AddSingleton<InMemoryJobShardManager>(sp =>\n        {\n            var siloDetails = sp.GetRequiredService<ILocalSiloDetails>();\n            var membershipService = sp.GetRequiredService<IClusterMembershipService>();\n            var durableJobsOptions = sp.GetRequiredService<IOptions<DurableJobsOptions>>();\n            return new InMemoryJobShardManager(siloDetails.SiloAddress, membershipService, durableJobsOptions.Value.MaxAdoptedCount);\n        });\n        services.AddFromExisting<JobShardManager, InMemoryJobShardManager>();\n        return services;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/Hosting/DurableJobsOptions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Configuration options for the durable jobs feature.\n/// </summary>\npublic sealed class DurableJobsOptions\n{\n    /// <summary>\n    /// Gets or sets the duration of each job shard. Smaller values reduce latency but increase overhead.\n    /// For optimal alignment with hour boundaries, choose durations that evenly divide 60 minutes\n    /// (e.g., 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, or 60 minutes) to avoid bucket drift across hours.\n    /// Default: 1 hour.\n    /// </summary>\n    public TimeSpan ShardDuration { get; set; } = TimeSpan.FromHours(1);\n\n    /// <summary>\n    /// Gets or sets how far in advance (before the shard's start time) the shard should\n    /// begin processing. This prevents holding idle shards for extended periods.\n    /// Default: 5 minutes.\n    /// </summary>\n    public TimeSpan ShardActivationBufferPeriod { get; set; } = TimeSpan.FromMinutes(5);\n\n    /// <summary>\n    /// Gets or sets the maximum number of jobs that can be executed concurrently on a single silo.\n    /// Default: 10,000 × processor count.\n    /// </summary>\n    public int MaxConcurrentJobsPerSilo { get; set; } = 10_000 * Environment.ProcessorCount;\n\n    /// <summary>\n    /// Gets or sets the delay between overload checks when the host is overloaded.\n    /// Job batch processing will pause for this duration before rechecking the overload status.\n    /// Default: 5 second.\n    /// </summary>\n    public TimeSpan OverloadBackoffDelay { get; set; } = TimeSpan.FromSeconds(5);\n\n    /// <summary>\n    /// Gets or sets whether concurrent job slow start is enabled.\n    /// When enabled, job concurrency is gradually increased during startup to avoid starvation\n    /// issues that can occur before caches, connection pools, and thread pool sizing have warmed up.\n    /// Concurrency starts at <see cref=\"SlowStartInitialConcurrency\"/> and doubles every\n    /// <see cref=\"SlowStartInterval\"/> until <see cref=\"MaxConcurrentJobsPerSilo\"/> is reached.\n    /// Default: <see langword=\"true\"/>.\n    /// </summary>\n    public bool ConcurrencySlowStartEnabled { get; set; } = true;\n\n    /// <summary>\n    /// Gets or sets the initial number of concurrent jobs allowed per silo when slow start is enabled.\n    /// Concurrency will exponentially increase from this value until <see cref=\"MaxConcurrentJobsPerSilo\"/> is reached.\n    /// Default: <see cref=\"Environment.ProcessorCount\"/>.\n    /// </summary>\n    public int SlowStartInitialConcurrency { get; set; } = Environment.ProcessorCount;\n\n    /// <summary>\n    /// Gets or sets the interval at which concurrency is doubled during slow start ramp-up.\n    /// Default: 10 seconds.\n    /// </summary>\n    public TimeSpan SlowStartInterval { get; set; } = TimeSpan.FromSeconds(10);\n\n    /// <summary>\n    /// Gets or sets the function that determines whether a failed job should be retried and when.\n    /// The function receives the job context and the exception that caused the failure, and returns\n    /// the time when the job should be retried, or <see langword=\"null\"/> if the job should not be retried.\n    /// Default: Retry up to 5 times with exponential backoff (2^n seconds).\n    /// </summary>\n    public Func<IJobRunContext, Exception, DateTimeOffset?> ShouldRetry { get; set; } = DefaultShouldRetry;\n\n    /// <summary>\n    /// Gets or sets the maximum number of times a shard can be adopted from a dead owner before\n    /// being marked as poisoned. A shard that repeatedly causes silos to crash will exceed this\n    /// threshold as it bounces between owners. When the next adoption would cause the adopted count\n    /// to exceed this value, the shard is considered poisoned and will no longer be assigned to any silo.\n    /// Default: 3.\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// The adopted count is only incremented when a shard is taken from a dead silo (i.e., the previous\n    /// owner crashed). It is NOT incremented when a silo gracefully shuts down and releases ownership.\n    /// </para>\n    /// <para>\n    /// When a shard completes successfully (all jobs processed), the adopted count is reset to 0.\n    /// </para>\n    /// </remarks>\n    public int MaxAdoptedCount { get; set; } = 3;\n\n    private static DateTimeOffset? DefaultShouldRetry(IJobRunContext jobContext, Exception ex)\n    {\n        // Default retry logic: retry up to 5 times with exponential backoff\n        if (jobContext.DequeueCount >= 5)\n        {\n            return null;\n        }\n        var delay = TimeSpan.FromSeconds(Math.Pow(2, jobContext.DequeueCount));\n        return DateTimeOffset.UtcNow.Add(delay);\n    }\n}\n\npublic sealed class DurableJobsOptionsValidator : IConfigurationValidator\n{\n    private readonly ILogger<DurableJobsOptionsValidator> _logger;\n    private readonly IOptions<DurableJobsOptions> _options;\n\n    public DurableJobsOptionsValidator(ILogger<DurableJobsOptionsValidator> logger, IOptions<DurableJobsOptions> options)\n    {\n        _logger = logger;\n        _options = options;\n    }\n\n    public void ValidateConfiguration()\n    {\n        var options = _options.Value;\n        if (options.ShardDuration <= TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException(\"DurableJobsOptions.ShardDuration must be greater than zero.\");\n        }\n        if (options.ShouldRetry is null)\n        {\n            throw new OrleansConfigurationException(\"DurableJobsOptions.ShouldRetry must not be null.\");\n        }\n        if (options.ConcurrencySlowStartEnabled && options.SlowStartInitialConcurrency <= 0)\n        {\n            throw new OrleansConfigurationException(\"DurableJobsOptions.SlowStartInitialConcurrency must be greater than zero.\");\n        }\n        if (options.ConcurrencySlowStartEnabled && options.SlowStartInterval <= TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException(\"DurableJobsOptions.SlowStartInterval must be greater than zero when slow start is enabled.\");\n        }\n        if (options.ConcurrencySlowStartEnabled && options.SlowStartInitialConcurrency > options.MaxConcurrentJobsPerSilo)\n        {\n            _logger.LogWarning(\n                \"DurableJobsOptions.SlowStartInitialConcurrency ({SlowStartInitialConcurrency}) exceeds MaxConcurrentJobsPerSilo ({MaxConcurrentJobsPerSilo}); slow start will not be applied.\",\n                options.SlowStartInitialConcurrency,\n                options.MaxConcurrentJobsPerSilo);\n        }\n        if (options.MaxAdoptedCount < 0)\n        {\n            throw new OrleansConfigurationException(\"DurableJobsOptions.MaxAdoptedCount must be greater than or equal to zero.\");\n        }\n        _logger.LogInformation(\"DurableJobsOptions validated: ShardDuration={ShardDuration}\", options.ShardDuration);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/IDurableJobHandler.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Provides contextual information about a durable job execution.\n/// </summary>\npublic interface IJobRunContext\n{\n    /// <summary>\n    /// Gets the durable job being executed.\n    /// </summary>\n    DurableJob Job { get; }\n\n    /// <summary>\n    /// Gets the unique identifier for this execution run.\n    /// </summary>\n    string RunId { get; }\n\n    /// <summary>\n    /// Gets the number of times this job has been dequeued for execution, including retries.\n    /// </summary>\n    int DequeueCount { get; }\n}\n\n/// <summary>\n/// Represents the execution context for a durable job.\n/// </summary>\n[GenerateSerializer]\ninternal class JobRunContext : IJobRunContext\n{\n    /// <summary>\n    /// Gets the durable job being executed.\n    /// </summary>\n    [Id(0)]\n    public DurableJob Job { get; }\n\n    /// <summary>\n    /// Gets the unique identifier for this execution run.\n    /// </summary>\n    [Id(1)]\n    public string RunId { get; }\n\n    /// <summary>\n    /// Gets the number of times this job has been dequeued for execution, including retries.\n    /// </summary>\n    [Id(2)]\n    public int DequeueCount { get; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"JobRunContext\"/> class.\n    /// </summary>\n    /// <param name=\"job\">The durable job to execute.</param>\n    /// <param name=\"runId\">The unique identifier for this execution run.</param>\n    /// <param name=\"retryCount\">The number of times this job has been dequeued, including retries.</param>\n    public JobRunContext(DurableJob job, string runId, int retryCount)\n    {\n        Job = job;\n        RunId = runId;\n        DequeueCount = retryCount;\n    }\n}\n\n/// <summary>\n/// Defines the interface for handling durable job execution.\n/// Grains implement this interface to receive and process durable jobs.\n/// </summary>\n/// <remarks>\n/// <para>\n/// Grains that implement this interface can be targeted by durable jobs.\n/// The <see cref=\"ExecuteJobAsync\"/> method is invoked when the job's due time is reached.\n/// </para>\n/// <example>\n/// The following example demonstrates a grain that implements <see cref=\"IDurableJobHandler\"/>:\n/// <code>\n/// public class MyGrain : Grain, IDurableJobHandler\n/// {\n///     public Task ExecuteJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n///     {\n///         // Process the durable job\n///         var jobName = context.Job.Name;\n///         var dueTime = context.Job.DueTime;\n///         \n///         // Perform job logic here\n///         \n///         return Task.CompletedTask;\n///     }\n/// }\n/// </code>\n/// </example>\n/// </remarks>\npublic interface IDurableJobHandler\n{\n    /// <summary>\n    /// Executes the durable job with the provided context.\n    /// </summary>\n    /// <param name=\"context\">The context containing information about the durable job execution.</param>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task that represents the asynchronous job execution operation.</returns>\n    /// <remarks>\n    /// <para>\n    /// This method is invoked by the Orleans durable jobs infrastructure when a job's due time is reached.\n    /// Implementations should handle job execution logic and can use information from the <paramref name=\"context\"/>\n    /// to access job metadata, dequeue count for retry logic, and other execution details.\n    /// </para>\n    /// <para>\n    /// If the method throws an exception and a retry policy is configured, the job may be retried.\n    /// The <see cref=\"IJobRunContext.DequeueCount\"/> property can be used to determine if this is a retry attempt.\n    /// </para>\n    /// </remarks>\n    Task ExecuteJobAsync(IJobRunContext context, CancellationToken cancellationToken);\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/IDurableJobReceiverExtension.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Extension interface for grains that can receive durable job invocations.\n/// </summary>\ninternal interface IDurableJobReceiverExtension : IGrainExtension\n{\n    /// <summary>\n    /// Handles a durable job by either starting execution or checking the status of an already running job.\n    /// If the job identified by <see cref=\"IJobRunContext.RunId\"/> has not been started, it will be executed.\n    /// If it is already running, the current status is returned.\n    /// </summary>\n    /// <param name=\"context\">The context containing information about the durable job.</param>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>A task that represents the asynchronous operation and contains the job execution result.</returns>\n    [AlwaysInterleave]\n    Task<DurableJobRunResult> HandleDurableJobAsync(IJobRunContext context, CancellationToken cancellationToken);\n}\n\n/// <inheritdoc />\ninternal sealed partial class DurableJobReceiverExtension : IDurableJobReceiverExtension\n{\n    private readonly IGrainContext _grain;\n    private readonly ILogger<DurableJobReceiverExtension> _logger;\n    private readonly ConcurrentDictionary<string, Task> _runningJobs = new();\n\n    public DurableJobReceiverExtension(IGrainContext grain, ILogger<DurableJobReceiverExtension> logger)\n    {\n        _grain = grain;\n        _logger = logger;\n    }\n\n    /// <inheritdoc />\n    public Task<DurableJobRunResult> HandleDurableJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n    {\n        if (_runningJobs.TryGetValue(context.RunId, out var runningTask))\n        {\n            return GetJobStatus(context, runningTask);\n        }\n\n        return StartJobAsync(context, cancellationToken);\n    }\n\n    private Task<DurableJobRunResult> StartJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n    {\n        if (_grain.GrainInstance is not IDurableJobHandler handler)\n        {\n            LogGrainDoesNotImplementHandler(_grain.GrainId);\n            throw new InvalidOperationException($\"Grain {_grain.GrainId} does not implement IDurableJobHandler\");\n        }\n\n        var task = handler.ExecuteJobAsync(context, cancellationToken);\n        _runningJobs[context.RunId] = task;\n\n        return GetJobStatus(context, task);\n    }\n\n    private Task<DurableJobRunResult> GetJobStatus(IJobRunContext context, Task task)\n    {\n        // Cancellation is cooperative: only terminal task state is authoritative for job outcome.\n        if (!task.IsCompleted)\n        {\n            return Task.FromResult(DurableJobRunResult.PollAfter(TimeSpan.FromSeconds(1)));\n        }\n\n        _runningJobs.TryRemove(context.RunId, out _);\n\n        if (task.IsCompletedSuccessfully)\n        {\n            return Task.FromResult(DurableJobRunResult.Completed);\n        }\n\n        if (task.IsFaulted)\n        {\n            var ex = task.Exception!.InnerException ?? task.Exception;\n            LogErrorExecutingDurableJob(ex, context.Job.Id, _grain.GrainId);\n            return Task.FromResult(DurableJobRunResult.Failed(ex));\n        }\n\n        return Task.FromCanceled<DurableJobRunResult>(new CancellationToken(canceled: true));\n    }\n\n    [LoggerMessage(Level = LogLevel.Error, Message = \"Error executing durable job {JobId} on grain {GrainId}\")]\n    private partial void LogErrorExecutingDurableJob(Exception exception, string jobId, GrainId grainId);\n\n    [LoggerMessage(Level = LogLevel.Error, Message = \"Grain {GrainId} does not implement IDurableJobHandler\")]\n    private partial void LogGrainDoesNotImplementHandler(GrainId grainId);\n}\n\n"
  },
  {
    "path": "src/Orleans.DurableJobs/ILocalDurableJobManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Provides functionality for scheduling and managing jobs on the local silo.\n/// </summary>\npublic interface ILocalDurableJobManager\n{\n    /// <summary>\n    /// Schedules a job to be executed at a specific time on the target grain.\n    /// </summary>\n    /// <param name=\"request\">The request containing the job scheduling parameters.</param>\n    /// <param name=\"cancellationToken\">A cancellation token to cancel the operation.</param>\n    /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation that returns the durable job.</returns>\n    Task<DurableJob> ScheduleJobAsync(ScheduleJobRequest request, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Attempts to cancel a previously scheduled durable job.\n    /// </summary>\n    /// <param name=\"job\">The durable job to cancel.</param>\n    /// <param name=\"cancellationToken\">A cancellation token to cancel the operation.</param>\n    /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation that returns <see langword=\"true\"/> if the job was successfully canceled; otherwise, <see langword=\"false\"/>.</returns>\n    Task<bool> TryCancelDurableJobAsync(DurableJob job, CancellationToken cancellationToken);\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/InMemoryJobQueue.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Provides an in-memory priority queue for managing durable jobs based on their due times.\n/// Jobs are organized into time-based buckets and enumerated asynchronously as they become due.\n/// </summary>\ninternal sealed class InMemoryJobQueue : IAsyncEnumerable<IJobRunContext>\n{\n    private readonly PriorityQueue<JobBucket, DateTimeOffset> _queue = new();\n    private readonly Dictionary<string, JobBucket> _jobsIdToBucket = new();\n    private readonly Dictionary<DateTimeOffset, JobBucket> _buckets = new();\n    private bool _isComplete;\n#if NET9_0_OR_GREATER\n    private readonly Lock _syncLock = new();\n#else\n    private readonly object _syncLock = new();\n#endif\n\n    /// <summary>\n    /// Gets the total number of jobs currently in the queue.\n    /// </summary>\n    public int Count => _jobsIdToBucket.Count;\n\n    /// <summary>\n    /// Adds a durable job to the queue with the specified dequeue count.\n    /// </summary>\n    /// <param name=\"job\">The durable job to enqueue.</param>\n    /// <param name=\"dequeueCount\">The number of times this job has been dequeued previously.</param>\n    /// <exception cref=\"InvalidOperationException\">Thrown when attempting to enqueue a job to a completed queue.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when job is null.</exception>\n    public void Enqueue(DurableJob job, int dequeueCount)\n    {\n        ArgumentNullException.ThrowIfNull(job);\n\n        lock (_syncLock)\n        {\n            if (_isComplete)\n                throw new InvalidOperationException(\"Cannot enqueue job to a completed queue.\");\n\n            var bucket = GetJobBucket(job.DueTime);\n            bucket.AddJob(job, dequeueCount);\n            _jobsIdToBucket[job.Id] = bucket;\n        }\n    }\n\n    /// <summary>\n    /// Marks the queue as complete, preventing any further jobs from being enqueued.\n    /// Once marked complete, the queue will finish processing remaining jobs and then terminate enumeration.\n    /// </summary>\n    public void MarkAsComplete()\n    {\n        lock (_syncLock)\n        {\n            _isComplete = true;\n        }\n    }\n\n    /// <summary>\n    /// Cancels a durable job by removing it from the queue.\n    /// </summary>\n    /// <param name=\"jobId\">The unique identifier of the job to cancel.</param>\n    /// <returns>True if the job was found and removed; false if the job was not found.</returns>\n    /// <remarks>\n    /// The job's bucket remains in the priority queue until processed, but the job itself is removed immediately.\n    /// </remarks>\n    public bool CancelJob(string jobId)\n    {\n        lock (_syncLock)\n        {\n            if (_jobsIdToBucket.TryGetValue(jobId, out var bucket))\n            {\n                // Try to remove from bucket (may already be dequeued)\n                bucket.RemoveJob(jobId);\n                _jobsIdToBucket.Remove(jobId);\n                // Note: The bucket remains in the priority queue until processed\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Reschedules a job for retry with a new due time.\n    /// </summary>\n    /// <param name=\"jobContext\">The context of the job to retry.</param>\n    /// <param name=\"newDueTime\">The new due time for the job.</param>\n    /// <remarks>\n    /// The job is removed from its current bucket and added to a new bucket based on the specified due time.\n    /// The dequeue count from the context is preserved.\n    /// </remarks>\n    public void RetryJobLater(IJobRunContext jobContext, DateTimeOffset newDueTime)\n    {\n        var jobId = jobContext.Job.Id;\n        var newJob = new DurableJob\n        {\n            Id = jobContext.Job.Id,\n            Name = jobContext.Job.Name,\n            DueTime = newDueTime,\n            TargetGrainId = jobContext.Job.TargetGrainId,\n            ShardId = jobContext.Job.ShardId,\n            Metadata = jobContext.Job.Metadata\n        };\n\n        lock (_syncLock)\n        {\n            if (_jobsIdToBucket.TryGetValue(jobId, out var oldBucket))\n            {\n                oldBucket.RemoveJob(jobId);\n                _jobsIdToBucket.Remove(jobId);\n                var newBucket = GetJobBucket(newDueTime);\n                newBucket.AddJob(newJob, jobContext.DequeueCount);\n                _jobsIdToBucket[jobId] = newBucket;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Returns an asynchronous enumerator that yields durable jobs as they become due.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to monitor for cancellation requests.</param>\n    /// <returns>\n    /// An async enumerator that returns <see cref=\"IJobRunContext\"/> instances for jobs that are due.\n    /// The enumerator checks for due jobs every second and terminates when the queue is marked complete and empty.\n    /// </returns>\n    public async IAsyncEnumerator<IJobRunContext> GetAsyncEnumerator(CancellationToken cancellationToken = default)\n    {\n        using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));\n        while (true)\n        {\n            JobBucket? bucketToProcess = null;\n            DateTimeOffset bucketKey = default;\n\n            lock (_syncLock)\n            {\n                if (Count == 0)\n                {\n                    if (_isComplete)\n                    {\n                        yield break; // Exit if the queue is frozen and empty\n                    }\n                }\n                else if (_queue.Count > 0)\n                {\n                    var nextBucket = _queue.Peek();\n                    if (nextBucket.DueTime < DateTimeOffset.UtcNow)\n                    {\n                        // Dequeue the entire bucket to process outside the lock\n                        bucketToProcess = _queue.Dequeue();\n                        bucketKey = bucketToProcess.DueTime;\n                    }\n                }\n            }\n\n            if (bucketToProcess is not null)\n            {\n                // Process all jobs in the bucket outside the lock for better concurrency\n                foreach (var (job, dequeueCount) in bucketToProcess.Jobs.ToList())\n                {\n                    // Verify job hasn't been cancelled while we were processing\n                    bool shouldYield;\n                    lock (_syncLock)\n                    {\n                        shouldYield = _jobsIdToBucket.ContainsKey(job.Id);\n                        // Keep job in _jobsIdToBucket for explicit removal via CancelJob/RetryJobLater\n                    }\n\n                    if (shouldYield)\n                    {\n                        yield return new JobRunContext(job, Guid.NewGuid().ToString(), dequeueCount + 1);\n                    }\n                }\n\n                // Clean up the bucket from dictionary after processing all jobs\n                lock (_syncLock)\n                {\n                    _buckets.Remove(bucketKey);\n                }\n            }\n            else\n            {\n                await timer.WaitForNextTickAsync(cancellationToken);\n            }\n        }\n    }\n\n    private JobBucket GetJobBucket(DateTimeOffset dueTime)\n    {\n        // Truncate to second precision and add 1 second to normalize bucket key\n        // This ensures all jobs within the same second (e.g., 12:00:00.000-12:00:00.999) share the same bucket (12:00:01)\n        var key = new DateTimeOffset(dueTime.Year, dueTime.Month, dueTime.Day, dueTime.Hour, dueTime.Minute, dueTime.Second, dueTime.Offset);\n        key = key.AddSeconds(1);\n        if (!_buckets.TryGetValue(key, out var bucket))\n        {\n            bucket = new JobBucket(key);\n            _buckets[key] = bucket;\n            _queue.Enqueue(bucket, key);\n        }\n        return bucket;\n    }   \n}\n\ninternal sealed class JobBucket\n{\n    private readonly Dictionary<string, (DurableJob Job, int DequeueCount)> _jobs = new();\n\n    public int Count => _jobs.Count;\n\n    public DateTimeOffset DueTime { get; private set; }\n\n    public IEnumerable<(DurableJob Job, int DequeueCount)> Jobs => _jobs.Values;\n\n    public JobBucket(DateTimeOffset dueTime)\n    {\n        DueTime = dueTime;\n    }\n\n    public void AddJob(DurableJob job, int dequeueCount)\n    {\n        _jobs[job.Id] = (job, dequeueCount);\n    }\n\n    public bool RemoveJob(string jobId)\n    {\n        return _jobs.Remove(jobId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/InMemoryJobShard.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n[DebuggerDisplay(\"ShardId={Id}, StartTime={StartTime}, EndTime={EndTime}\")]\ninternal sealed class InMemoryJobShard : JobShard\n{\n    public InMemoryJobShard(string shardId, DateTimeOffset minDueTime, DateTimeOffset maxDueTime, IDictionary<string, string>? metadata)\n        : base(shardId, minDueTime, maxDueTime)\n    {\n        Metadata = metadata;\n    }\n\n    protected override Task PersistAddJobAsync(string jobId, string jobName, DateTimeOffset dueTime, GrainId target, IReadOnlyDictionary<string, string>? metadata, CancellationToken cancellationToken)\n    {\n        return Task.CompletedTask;\n    }\n\n    protected override Task PersistRemoveJobAsync(string jobId, CancellationToken cancellationToken)\n    {\n        return Task.CompletedTask;\n    }\n\n    protected override Task PersistRetryJobAsync(string jobId, DateTimeOffset newDueTime, CancellationToken cancellationToken)\n    {\n        return Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/JobShard.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Represents a shard of durable jobs that manages a collection of jobs within a specific time range.\n/// A job shard is responsible for storing, retrieving, and managing the lifecycle of durable jobs\n/// that fall within its designated time window.\n/// </summary>\n/// <remarks>\n/// Job shards are used to partition durable jobs across time ranges to improve scalability\n/// and performance. Each shard has a defined start and end time that determines which jobs\n/// it manages. Shards can be marked as complete when all jobs within their time range\n/// have been processed.\n/// </remarks>\npublic interface IJobShard : IAsyncDisposable\n{\n    /// <summary>\n    /// Gets the unique identifier for this job shard.\n    /// </summary>\n    string Id { get; }\n\n    /// <summary>\n    /// Gets the start time of the time range managed by this shard.\n    /// </summary>\n    DateTimeOffset StartTime { get; }\n\n    /// <summary>\n    /// Gets the end time of the time range managed by this shard.\n    /// </summary>\n    DateTimeOffset EndTime { get; }\n\n    /// <summary>\n    /// Gets optional metadata associated with this job shard.\n    /// </summary>\n    IDictionary<string, string>? Metadata { get; }\n\n    /// <summary>\n    /// Gets a value indicating whether this shard has been marked as complete and is no longer accepting new jobs.\n    /// </summary>\n    /// <remarks>\n    /// When a shard is marked as complete (via <see cref=\"MarkAsCompleteAsync\"/>), no new jobs can be added to it.\n    /// </remarks>\n    bool IsAddingCompleted { get; }\n\n    /// <summary>\n    /// Consumes durable jobs from this shard in order of their due time.\n    /// </summary>\n    /// <returns>An asynchronous enumerable of durable job contexts.</returns>\n    IAsyncEnumerable<IJobRunContext> ConsumeDurableJobsAsync();\n\n    /// <summary>\n    /// Gets the number of jobs currently scheduled in this shard.\n    /// </summary>\n    /// <returns>A task that represents the asynchronous operation. The task result contains the job count.</returns>\n    ValueTask<int> GetJobCountAsync();\n\n    /// <summary>\n    /// Marks this shard as complete, preventing new jobs from being scheduled.\n    /// </summary>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation.</returns>\n    Task MarkAsCompleteAsync(CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Removes a durable job from this shard.\n    /// </summary>\n    /// <param name=\"jobId\">The unique identifier of the job to remove.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation. The task result contains true if the job was successfully removed, or false if the job was not found.</returns>\n    Task<bool> RemoveJobAsync(string jobId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Reschedules a job to be retried at a later time.\n    /// </summary>\n    /// <param name=\"jobContext\">The context of the job to retry.</param>\n    /// <param name=\"newDueTime\">The new due time for the job.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation.</returns>\n    Task RetryJobLaterAsync(IJobRunContext jobContext, DateTimeOffset newDueTime, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Attempts to schedule a new job on this shard.\n    /// </summary>\n    /// <param name=\"request\">The request containing the job scheduling parameters.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation. The task result contains the durable job if successful, or null if the job could not be scheduled (e.g., the shard was marked as complete).</returns>\n    /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the due time is outside the shard's time range.</exception>\n    Task<DurableJob?> TryScheduleJobAsync(ScheduleJobRequest request, CancellationToken cancellationToken);\n}\n\n/// <summary>\n/// Base implementation of <see cref=\"IJobShard\"/> that provides common functionality for job shard implementations.\n/// </summary>\npublic abstract class JobShard : IJobShard\n{\n    private readonly InMemoryJobQueue _jobQueue;\n\n    /// <inheritdoc/>\n    public string Id { get; protected set; }\n\n    /// <inheritdoc/>\n    public DateTimeOffset StartTime { get; protected set; }\n\n    /// <inheritdoc/>\n    public DateTimeOffset EndTime { get; protected set; }\n\n    /// <inheritdoc/>\n    public IDictionary<string, string>? Metadata { get; protected set; }\n\n    /// <inheritdoc/>\n    public bool IsAddingCompleted { get; protected set; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"JobShard\"/> class.\n    /// </summary>\n    /// <param name=\"id\">The unique identifier for this job shard.</param>\n    /// <param name=\"startTime\">The start time of the time range managed by this shard.</param>\n    /// <param name=\"endTime\">The end time of the time range managed by this shard.</param>\n    protected JobShard(string id, DateTimeOffset startTime, DateTimeOffset endTime)\n    {\n        Id = id;\n        StartTime = startTime;\n        EndTime = endTime;\n        _jobQueue = new InMemoryJobQueue();\n    }\n\n    /// <inheritdoc/>\n    public ValueTask<int> GetJobCountAsync() => ValueTask.FromResult(_jobQueue.Count);\n\n    /// <inheritdoc/>\n    public IAsyncEnumerable<IJobRunContext> ConsumeDurableJobsAsync()\n    {\n        return _jobQueue;\n    }\n\n    /// <inheritdoc/>\n    public async Task<DurableJob?> TryScheduleJobAsync(ScheduleJobRequest request, CancellationToken cancellationToken)\n    {\n        if (IsAddingCompleted)\n        {\n            return null;\n        }\n\n        if (request.DueTime < StartTime || request.DueTime > EndTime)\n        {\n            throw new ArgumentOutOfRangeException(nameof(request), \"Scheduled time is out of shard bounds.\");\n        }\n\n        var jobId = Guid.NewGuid().ToString();\n        var job = new DurableJob\n        {\n            Id = jobId,\n            TargetGrainId = request.Target,\n            Name = request.JobName,\n            DueTime = request.DueTime,\n            ShardId = Id,\n            Metadata = request.Metadata\n        };\n\n        await PersistAddJobAsync(jobId, request.JobName, request.DueTime, request.Target, request.Metadata, cancellationToken);\n        _jobQueue.Enqueue(job, 0);\n        return job;\n    }\n\n    /// <inheritdoc/>\n    public async Task<bool> RemoveJobAsync(string jobId, CancellationToken cancellationToken)\n    {\n        await PersistRemoveJobAsync(jobId, cancellationToken);\n        return _jobQueue.CancelJob(jobId);\n    }\n\n    /// <inheritdoc/>\n    public Task MarkAsCompleteAsync(CancellationToken cancellationToken)\n    {\n        IsAddingCompleted = true;\n        _jobQueue.MarkAsComplete();\n        return Task.CompletedTask;\n    }\n\n    /// <inheritdoc/>\n    public async Task RetryJobLaterAsync(IJobRunContext jobContext, DateTimeOffset newDueTime, CancellationToken cancellationToken)\n    {\n        await PersistRetryJobAsync(jobContext.Job.Id, newDueTime, cancellationToken);\n        _jobQueue.RetryJobLater(jobContext, newDueTime);\n    }\n\n    /// <summary>\n    /// Enqueues a job into the in-memory queue with the specified dequeue count.\n    /// </summary>\n    /// <param name=\"job\">The job to enqueue.</param>\n    /// <param name=\"dequeueCount\">The number of times this job has been dequeued.</param>\n    protected void EnqueueJob(DurableJob job, int dequeueCount)\n    {\n        _jobQueue.Enqueue(job, dequeueCount);\n    }\n\n    /// <summary>\n    /// Persists the addition of a new job to the underlying storage.\n    /// </summary>\n    /// <param name=\"jobId\">The unique identifier of the job.</param>\n    /// <param name=\"jobName\">The name of the job.</param>\n    /// <param name=\"dueTime\">The time when the job should be executed.</param>\n    /// <param name=\"target\">The grain identifier of the target grain.</param>\n    /// <param name=\"metadata\">Optional metadata to associate with the job.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation.</returns>\n    protected abstract Task PersistAddJobAsync(string jobId, string jobName, DateTimeOffset dueTime, GrainId target, IReadOnlyDictionary<string, string>? metadata, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Persists the removal of a job from the underlying storage.\n    /// </summary>\n    /// <param name=\"jobId\">The unique identifier of the job to remove.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation.</returns>\n    protected abstract Task PersistRemoveJobAsync(string jobId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Persists the rescheduling of a job to the underlying storage.\n    /// </summary>\n    /// <param name=\"jobId\">The unique identifier of the job to retry.</param>\n    /// <param name=\"newDueTime\">The new due time for the job.</param>\n    /// <param name=\"cancellationToken\">A token to cancel the operation.</param>\n    /// <returns>A task that represents the asynchronous operation.</returns>\n    protected abstract Task PersistRetryJobAsync(string jobId, DateTimeOffset newDueTime, CancellationToken cancellationToken);\n\n    /// <inheritdoc/>\n    public virtual ValueTask DisposeAsync()\n    {\n        GC.SuppressFinalize(this);\n        return default;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/JobShardManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Manages the lifecycle of job shards for a specific silo.\n/// Each silo instance has its own shard manager.\n/// </summary>\npublic abstract class JobShardManager\n{\n    /// <summary>\n    /// Gets the silo address this manager is associated with.\n    /// </summary>\n    protected SiloAddress SiloAddress { get; }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"JobShardManager\"/> class.\n    /// </summary>\n    /// <param name=\"siloAddress\">The silo address this manager represents.</param>\n    protected JobShardManager(SiloAddress siloAddress)\n    {\n        SiloAddress = siloAddress;\n    }\n\n    /// <summary>\n    /// Assigns orphaned job shards to this silo.\n    /// </summary>\n    /// <param name=\"maxDueTime\">Maximum due time for shards to consider.</param>\n    /// <param name=\"cancellationToken\">Cancellation token.</param>\n    /// <returns>A list of job shards assigned to this silo.</returns>\n    public abstract Task<List<IJobShard>> AssignJobShardsAsync(DateTimeOffset maxDueTime, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Creates a new job shard owned by this silo.\n    /// </summary>\n    /// <param name=\"minDueTime\">The minimum due time for jobs in this shard.</param>\n    /// <param name=\"maxDueTime\">The maximum due time for jobs in this shard.</param>\n    /// <param name=\"metadata\">Optional metadata for the shard.</param>\n    /// <param name=\"cancellationToken\">Cancellation token.</param>\n    /// <returns>The newly created job shard.</returns>\n    public abstract Task<IJobShard> CreateShardAsync(DateTimeOffset minDueTime, DateTimeOffset maxDueTime, IDictionary<string, string> metadata, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Unregisters a shard owned by this silo.\n    /// </summary>\n    /// <param name=\"shard\">The shard to unregister.</param>\n    /// <param name=\"cancellationToken\">Cancellation token.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    public abstract Task UnregisterShardAsync(IJobShard shard, CancellationToken cancellationToken);\n}\n\ninternal class InMemoryJobShardManager : JobShardManager\n{\n    // Shared storage across all manager instances to support multi-silo scenarios\n    private static readonly Dictionary<string, ShardOwnership> _globalShardStore = new();\n    private static readonly SemaphoreSlim _asyncLock = new(1, 1);\n    private readonly IClusterMembershipService? _membershipService;\n    private readonly int _maxAdoptedCount;\n\n    public InMemoryJobShardManager(SiloAddress siloAddress) : this(siloAddress, null, 3)\n    {\n    }\n\n    public InMemoryJobShardManager(SiloAddress siloAddress, IClusterMembershipService? membershipService) : this(siloAddress, membershipService, 3)\n    {\n    }\n\n    public InMemoryJobShardManager(SiloAddress siloAddress, IClusterMembershipService? membershipService, int maxAdoptedCount) : base(siloAddress)\n    {\n        _membershipService = membershipService;\n        _maxAdoptedCount = maxAdoptedCount;\n    }\n\n    /// <summary>\n    /// Clears all shards from the global store. For testing purposes only.\n    /// </summary>\n    internal static async Task ClearAllShardsAsync()\n    {\n        await _asyncLock.WaitAsync();\n        try\n        {\n            _globalShardStore.Clear();\n        }\n        finally\n        {\n            _asyncLock.Release();\n        }\n    }\n\n    /// <summary>\n    /// Gets ownership info for a shard. For testing purposes only.\n    /// </summary>\n    internal static async Task<(string? Owner, int AdoptedCount)?> GetOwnershipInfoAsync(string shardId)\n    {\n        await _asyncLock.WaitAsync();\n        try\n        {\n            if (_globalShardStore.TryGetValue(shardId, out var ownership))\n            {\n                return (ownership.OwnerSiloAddress, ownership.AdoptedCount);\n            }\n            return null;\n        }\n        finally\n        {\n            _asyncLock.Release();\n        }\n    }\n\n    public override async Task<List<IJobShard>> AssignJobShardsAsync(DateTimeOffset maxDueTime, CancellationToken cancellationToken)\n    {\n        var alreadyOwnedShards = new List<IJobShard>();\n        var adoptedShards = new List<IJobShard>();\n        \n        await _asyncLock.WaitAsync(cancellationToken);\n        try\n        {\n            var snapshot = _membershipService?.CurrentSnapshot;\n            var deadSilos = new HashSet<string>();\n            \n            if (snapshot is not null)\n            {\n                foreach (var member in snapshot.Members.Values)\n                {\n                    if (member.Status == SiloStatus.Dead)\n                    {\n                        deadSilos.Add(member.SiloAddress.ToString());\n                    }\n                }\n            }\n\n            // Assign shards from dead silos or orphaned shards\n            foreach (var kvp in _globalShardStore)\n            {\n                var shardId = kvp.Key;\n                var ownership = kvp.Value;\n                \n                // Skip shards that are already owned by this silo\n                if (ownership.OwnerSiloAddress == SiloAddress.ToString())\n                {\n                    if (ownership.Shard.StartTime <= maxDueTime)\n                    {\n                        alreadyOwnedShards.Add(ownership.Shard);\n                    }\n                    continue;\n                }\n\n                // Check if this is an orphaned shard (gracefully released) or adopted (from dead silo)\n                var isOrphaned = ownership.OwnerSiloAddress is null;\n                var ownerAddress = ownership.OwnerSiloAddress;\n                var isFromDeadSilo = ownerAddress is not null && deadSilos.Contains(ownerAddress);\n\n                if (isOrphaned || isFromDeadSilo)\n                {\n                    if (ownership.Shard.StartTime <= maxDueTime)\n                    {\n                        // If adopted from dead silo, increment adopted count\n                        if (isFromDeadSilo)\n                        {\n                            ownership.AdoptedCount++;\n\n                            // Check if shard is poisoned\n                            if (ownership.AdoptedCount > _maxAdoptedCount)\n                            {\n                                // Shard is poisoned - don't assign it\n                                continue;\n                            }\n                        }\n\n                        ownership.OwnerSiloAddress = SiloAddress.ToString();\n                        adoptedShards.Add(ownership.Shard);\n                    }\n                }\n            }\n        }\n        finally\n        {\n            _asyncLock.Release();\n        }\n\n        foreach (var shard in adoptedShards)\n        {\n            // Mark adopted shards as complete\n            await shard.MarkAsCompleteAsync(CancellationToken.None);\n        }\n\n        return [.. alreadyOwnedShards, .. adoptedShards];\n    }\n\n    public override async Task<IJobShard> CreateShardAsync(DateTimeOffset minDueTime, DateTimeOffset maxDueTime, IDictionary<string, string> metadata, CancellationToken cancellationToken)\n    {\n        await _asyncLock.WaitAsync(cancellationToken);\n        try\n        {\n            var shardId = $\"{SiloAddress}-{Guid.NewGuid()}\";\n            var newShard = new InMemoryJobShard(shardId, minDueTime, maxDueTime, metadata);\n            \n            _globalShardStore[shardId] = new ShardOwnership\n            {\n                Shard = newShard,\n                OwnerSiloAddress = SiloAddress.ToString()\n            };\n            \n            return newShard;\n        }\n        finally\n        {\n            _asyncLock.Release();\n        }\n    }\n\n    public override async Task UnregisterShardAsync(IJobShard shard, CancellationToken cancellationToken)\n    {\n        var jobCount = await shard.GetJobCountAsync();\n        \n        await _asyncLock.WaitAsync(cancellationToken);\n        try\n        {\n            // Only remove shards that have no jobs remaining\n            if (_globalShardStore.TryGetValue(shard.Id, out var ownership))\n            {\n                if (jobCount == 0)\n                {\n                    _globalShardStore.Remove(shard.Id);\n                }\n                else\n                {\n                    // Mark as unowned so another silo can pick it up\n                    ownership.OwnerSiloAddress = null;\n                    // Reset adopted count since we're gracefully releasing (not crashing)\n                    ownership.AdoptedCount = 0;\n                }\n            }\n        }\n        finally\n        {\n            _asyncLock.Release();\n        }\n    }\n\n    private sealed class ShardOwnership\n    {\n        public required IJobShard Shard { get; init; }\n        public string? OwnerSiloAddress { get; set; }\n        public int AdoptedCount { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/LocalDurableJobManager.Log.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\ninternal partial class LocalDurableJobManager\n{\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Scheduling job '{JobName}' for grain {TargetGrain} at {DueTime}\"\n    )]\n    private static partial void LogSchedulingJob(ILogger logger, string jobName, GrainId targetGrain, DateTimeOffset dueTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Job '{JobName}' (ID: {JobId}) scheduled to shard {ShardId} for grain {TargetGrain}\"\n    )]\n    private static partial void LogJobScheduled(ILogger logger, string jobName, string jobId, string shardId, GrainId targetGrain);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"LocalDurableJobManager starting\"\n    )]\n    private static partial void LogStarting(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"LocalDurableJobManager started\"\n    )]\n    private static partial void LogStarted(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"LocalDurableJobManager stopping. Running shards: {RunningShardCount}\"\n    )]\n    private static partial void LogStopping(ILogger logger, int runningShardCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"LocalDurableJobManager stopped\"\n    )]\n    private static partial void LogStopped(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Attempting to cancel job {JobId} (Name: '{JobName}') in shard {ShardId}\"\n    )]\n    private static partial void LogCancellingJob(ILogger logger, string jobId, string jobName, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to cancel job {JobId} (Name: '{JobName}') - shard {ShardId} not found in cache\"\n    )]\n    private static partial void LogJobCancellationFailed(ILogger logger, string jobId, string jobName, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Job {JobId} (Name: '{JobName}') cancelled from shard {ShardId}\"\n    )]\n    private static partial void LogJobCancelled(ILogger logger, string jobId, string jobName, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing cluster membership update\"\n    )]\n    private static partial void LogErrorProcessingClusterMembership(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Checking for unassigned shards\"\n    )]\n    private static partial void LogCheckingForUnassignedShards(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Assigned {ShardCount} shard(s)\"\n    )]\n    private static partial void LogAssignedShards(ILogger logger, int shardCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"No unassigned shards found\"\n    )]\n    private static partial void LogNoShardsToAssign(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Starting shard {ShardId} (Start: {StartTime}, End: {EndTime})\"\n    )]\n    private static partial void LogStartingShard(ILogger logger, string shardId, DateTimeOffset startTime, DateTimeOffset endTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Shard {ShardId} not ready yet. Start time: {StartTime}\"\n    )]\n    private static partial void LogShardNotReadyYet(ILogger logger, string shardId, DateTimeOffset startTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Checking for pending shards to start\"\n    )]\n    private static partial void LogCheckingPendingShards(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error in periodic shard check\"\n    )]\n    private static partial void LogErrorInPeriodicCheck(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Unregistered shard {ShardId}\"\n    )]\n    private static partial void LogUnregisteredShard(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error unregistering shard {ShardId}\"\n    )]\n    private static partial void LogErrorUnregisteringShard(ILogger logger, Exception exception, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error disposing shard {ShardId}\"\n    )]\n    private static partial void LogErrorDisposingShard(ILogger logger, Exception exception, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Creating new shard for key {ShardKey}\"\n    )]\n    private static partial void LogCreatingNewShard(ILogger logger, DateTimeOffset shardKey);\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/LocalDurableJobManager.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.DurableJobs;\n\n/// <inheritdoc/>\ninternal partial class LocalDurableJobManager : SystemTarget, ILocalDurableJobManager, ILifecycleParticipant<ISiloLifecycle>\n{\n    private readonly JobShardManager _shardManager;\n    private readonly ShardExecutor _shardExecutor;\n    private readonly IAsyncEnumerable<ClusterMembershipSnapshot> _clusterMembershipUpdates;\n    private readonly ILogger<LocalDurableJobManager> _logger;\n    private readonly DurableJobsOptions _options;\n    private readonly CancellationTokenSource _cts = new();\n    private Task? _listenForClusterChangesTask;\n    private Task? _periodicCheckTask;\n\n    // Shard tracking state\n    private readonly ConcurrentDictionary<string, IJobShard> _shardCache = new();\n    private readonly ConcurrentDictionary<DateTimeOffset, IJobShard> _writeableShards = new();\n    private readonly ConcurrentDictionary<string, Task> _runningShards = new();\n    private readonly SemaphoreSlim _shardCreationLock = new(1, 1);\n    private readonly SemaphoreSlim _shardCheckSignal = new(0);\n\n    private static readonly IDictionary<string, string> EmptyMetadata = new Dictionary<string, string>();\n\n    public LocalDurableJobManager(\n        JobShardManager shardManager,\n        ShardExecutor shardExecutor,\n        IClusterMembershipService clusterMembership,\n        IOptions<DurableJobsOptions> options,\n        SystemTargetShared shared,\n        ILogger<LocalDurableJobManager> logger)\n        : base(SystemTargetGrainId.CreateGrainType(\"job-manager\"), shared)\n    {\n        _shardManager = shardManager;\n        _shardExecutor = shardExecutor;\n        _clusterMembershipUpdates = clusterMembership.MembershipUpdates;\n        _logger = logger;\n        _options = options.Value;\n    }\n\n    /// <inheritdoc/>\n    public async Task<DurableJob> ScheduleJobAsync(ScheduleJobRequest request, CancellationToken cancellationToken)\n    {\n        LogSchedulingJob(_logger, request.JobName, request.Target, request.DueTime);\n\n        var shardKey = GetShardKey(request.DueTime);\n\n        while (true)\n        {\n            // Fast path: shard already exists\n            if (_writeableShards.TryGetValue(shardKey, out var existingShard))\n            {\n                var job = await existingShard.TryScheduleJobAsync(request, cancellationToken);\n                if (job is not null)\n                {\n                    LogJobScheduled(_logger, request.JobName, job.Id, existingShard.Id, request.Target);\n                    return job;\n                }\n\n                // Shard is full or no longer writable, remove from writable shards and try again\n                _writeableShards.TryRemove(shardKey, out _);\n                continue;\n            }\n\n            // Slow path: need to create shard\n            await _shardCreationLock.WaitAsync(cancellationToken);\n            try\n            {\n                // Double-check after acquiring lock\n                if (_writeableShards.TryGetValue(shardKey, out existingShard))\n                {\n                    continue;\n                }\n\n                // Create new shard\n                using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cts.Token);\n                var endTime = shardKey.Add(_options.ShardDuration);\n                var newShard = await _shardManager.CreateShardAsync(shardKey, endTime, EmptyMetadata, linkedCts.Token);\n\n                LogCreatingNewShard(_logger, shardKey);\n                _writeableShards[shardKey] = newShard;\n                _shardCache.TryAdd(newShard.Id, newShard);\n                TryActivateShard(newShard);\n            }\n            finally\n            {\n                _shardCreationLock.Release();\n            }\n        }\n    }\n\n    public void Participate(ISiloLifecycle lifecycle)\n    {\n        lifecycle.Subscribe(\n            nameof(LocalDurableJobManager),\n            ServiceLifecycleStage.Active,\n            ct => Start(ct),\n            ct => Stop(ct));\n    }\n\n    private Task Start(CancellationToken ct)\n    {\n        LogStarting(_logger);\n\n        using (var _ = new ExecutionContextSuppressor())\n        {\n            _listenForClusterChangesTask = Task.Factory.StartNew(\n                state => ((LocalDurableJobManager)state!).ProcessMembershipUpdates(),\n                this,\n                CancellationToken.None,\n                TaskCreationOptions.None,\n                WorkItemGroup.TaskScheduler).Unwrap();\n            _listenForClusterChangesTask.Ignore();\n\n            _periodicCheckTask = Task.Factory.StartNew(\n                state => ((LocalDurableJobManager)state!).PeriodicShardCheck(),\n                this,\n                CancellationToken.None,\n                TaskCreationOptions.None,\n                WorkItemGroup.TaskScheduler).Unwrap();\n            _periodicCheckTask.Ignore();\n        }\n\n        LogStarted(_logger);\n        return Task.CompletedTask;\n    }\n\n    private async Task Stop(CancellationToken ct)\n    {\n        LogStopping(_logger, _runningShards.Count);\n\n        _cts.Cancel();\n\n        if (_listenForClusterChangesTask is not null)\n        {\n            await _listenForClusterChangesTask.SuppressThrowing();\n        }\n\n        if (_periodicCheckTask is not null)\n        {\n            await _periodicCheckTask.SuppressThrowing();\n        }\n\n        await Task.WhenAll(_runningShards.Values.ToArray());\n\n        LogStopped(_logger);\n    }\n\n    /// <inheritdoc/>\n    public async Task<bool> TryCancelDurableJobAsync(DurableJob job, CancellationToken cancellationToken)\n    {\n        LogCancellingJob(_logger, job.Id, job.Name, job.ShardId);\n\n        if (!_shardCache.TryGetValue(job.ShardId, out var shard))\n        {\n            LogJobCancellationFailed(_logger, job.Id, job.Name, job.ShardId);\n            return false;\n        }\n\n        using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cts.Token);\n        var wasRemoved = await shard.RemoveJobAsync(job.Id, linkedCts.Token);\n        LogJobCancelled(_logger, job.Id, job.Name, job.ShardId);\n        return wasRemoved;\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.ContinueOnCapturedContext);\n        var current = new HashSet<SiloAddress>();\n\n        try\n        {\n            await foreach (var membershipSnapshot in _clusterMembershipUpdates.WithCancellation(_cts.Token))\n            {\n                try\n                {\n                    // Get active members\n                    var update = new HashSet<SiloAddress>(membershipSnapshot.Members.Values\n                        .Where(member => member.Status == SiloStatus.Active)\n                        .Select(member => member.SiloAddress));\n\n                    // If active list has changed, trigger immediate shard check\n                    if (!current.SetEquals(update))\n                    {\n                        current = update;\n                        _shardCheckSignal.Release();\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorProcessingClusterMembership(_logger, exception);\n                }\n            }\n        }\n        catch (OperationCanceledException)\n        {\n            if (!_cts.Token.IsCancellationRequested)\n            {\n                throw;\n            }\n        }\n    }\n\n    private async Task PeriodicShardCheck()\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n        using var timer = new PeriodicTimer(TimeSpan.FromMinutes(10));\n\n        Task timerTask = Task.CompletedTask;\n        while (!_cts.Token.IsCancellationRequested)\n        {\n            try\n            {\n                // Wait for either periodic timer OR signal from membership changes\n                if (timerTask.IsCompleted)\n                {\n                    timerTask = timer.WaitForNextTickAsync(_cts.Token).AsTask();\n                }\n\n                var signalTask = _shardCheckSignal.WaitAsync(_cts.Token);\n                await Task.WhenAny(timerTask, signalTask);\n\n                LogCheckingPendingShards(_logger);\n\n                // Clean up old writable shards that have passed their time window\n                var now = DateTimeOffset.UtcNow;\n                foreach (var key in _writeableShards.Keys.ToArray())\n                {\n                    var shardEndTime = key.Add(_options.ShardDuration);\n                    if (shardEndTime < now)\n                    {\n                        _writeableShards.TryRemove(key, out _);\n                    }\n                }\n\n                // Query ShardManager for assigned shards (source of truth)\n                var shards = await _shardManager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), _cts.Token);\n                if (shards.Count > 0)\n                {\n                    LogAssignedShards(_logger, shards.Count);\n                    foreach (var shard in shards)\n                    {\n                        _shardCache.TryAdd(shard.Id, shard);\n\n                        if (!_runningShards.ContainsKey(shard.Id))\n                        {\n                            TryActivateShard(shard);\n                        }\n                    }\n                }\n                else\n                {\n                    LogNoShardsToAssign(_logger);\n                }\n            }\n            catch (OperationCanceledException)\n            {\n                break;\n            }\n            catch (Exception ex)\n            {\n                LogErrorInPeriodicCheck(_logger, ex);\n                await Task.Delay(TimeSpan.FromSeconds(5), _cts.Token).SuppressThrowing();\n            }\n        }\n    }\n\n    private void TryActivateShard(IJobShard shard)\n    {\n        // Only start if not already running\n        if (_runningShards.ContainsKey(shard.Id))\n        {\n            return;\n        }\n\n        // Only start if it's time to start (within buffer period)\n        if (!ShouldStartShardNow(shard))\n        {\n            LogShardNotReadyYet(_logger, shard.Id, shard.StartTime);\n            return;\n        }\n\n        if (_runningShards.TryAdd(shard.Id, Task.CompletedTask))\n        {\n            LogStartingShard(_logger, shard.Id, shard.StartTime, shard.EndTime);\n            _runningShards[shard.Id] = RunShardWithCleanupAsync(shard);\n        }\n    }\n\n    private async Task RunShardWithCleanupAsync(IJobShard shard)\n    {\n        try\n        {\n            await _shardExecutor.RunShardAsync(shard, _cts.Token);\n\n            // Unregister the shard from the manager\n            try\n            {\n                await _shardManager.UnregisterShardAsync(shard, _cts.Token);\n                LogUnregisteredShard(_logger, shard.Id);\n            }\n            catch (Exception ex) when (ex is not OperationCanceledException)\n            {\n                LogErrorUnregisteringShard(_logger, ex, shard.Id);\n            }\n        }\n        finally\n        {\n            // Clean up tracking and dispose the shard\n            _shardCache.TryRemove(shard.Id, out _);\n            _runningShards.TryRemove(shard.Id, out _);\n\n            try\n            {\n                await shard.DisposeAsync();\n            }\n            catch (Exception ex)\n            {\n                LogErrorDisposingShard(_logger, ex, shard.Id);\n            }\n        }\n    }\n\n    private bool ShouldStartShardNow(IJobShard shard)\n    {\n        var activationTime = shard.StartTime.Subtract(_options.ShardActivationBufferPeriod);\n        return DateTimeOffset.UtcNow >= activationTime;\n    }\n\n    private DateTimeOffset GetShardKey(DateTimeOffset scheduledTime)\n    {\n        var shardDurationTicks = _options.ShardDuration.Ticks;\n        var epochTicks = scheduledTime.UtcTicks;\n        var bucketTicks = (epochTicks / shardDurationTicks) * shardDurationTicks;\n        return new DateTimeOffset(bucketTicks, TimeSpan.Zero);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/Orleans.DurableJobs.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.DurableJobs</PackageId>\n    <Title>Microsoft Orleans Durable Jobs Library</Title>\n    <Description>Durable Jobs library for Microsoft Orleans used on the server.</Description>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <DefineConstants>$(DefineConstants)</DefineConstants>\n    <VersionSuffix Condition=\"$(VersionSuffix) != ''\">$(VersionSuffix).alpha.1</VersionSuffix>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DurableJobs.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.DurableJobs/README.md",
    "content": "# Microsoft Orleans Durable Jobs\n\n## Introduction\nMicrosoft Orleans Durable Jobs provides a distributed, scalable system for scheduling one-time jobs that execute at a specific time. Unlike Orleans Reminders which are designed for recurring tasks, Durable Jobs are ideal for one-time future events such as appointment notifications, delayed processing, scheduled workflow steps, and time-based triggers.\n\n**Key Features:**\n- **At Least One-time Execution**: Jobs are scheduled to run at least once\n- **Persistent**: Jobs survive grain deactivation and silo restarts\n- **Distributed**: Jobs are automatically distributed and rebalanced across silos\n- **Reliable**: Failed jobs can be automatically retried with configurable policies\n- **Rich Metadata**: Associate custom metadata with each job\n- **Cancellable**: Jobs can be canceled before execution\n\n## Getting Started\n\n### Installation\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.DurableJobs\n```\n\nFor production scenarios with persistence, also install a storage provider:\n\n```shell\ndotnet add package Microsoft.Orleans.DurableJobs.AzureStorage\n```\n\n### Configuration\n\n#### Using In-Memory Storage (Development/Testing)\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseLocalhostClustering()\n        // Configure in-memory Durable Jobs (no persistence)\n        .UseInMemoryDurableJobs();\n});\n\nawait builder.Build().RunAsync();\n```\n\n#### Using Azure Storage (Production)\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseLocalhostClustering()\n        // Configure Azure Storage Durable Jobs\n        .UseAzureStorageDurableJobs(options =>\n        {\n            options.Configure(o =>\n            {\n                o.BlobServiceClient = new Azure.Storage.Blobs.BlobServiceClient(\"YOUR_CONNECTION_STRING\");\n                o.ContainerName = \"durable-jobs\";\n            });\n        });\n});\n\nawait builder.Build().RunAsync();\n```\n\n#### Advanced Configuration\n```csharp\nbuilder.UseOrleans(siloBuilder =>\n{\n    siloBuilder\n        .UseLocalhostClustering()\n        .UseInMemoryDurableJobs()\n        .ConfigureServices(services =>\n        {\n            services.Configure<DurableJobsOptions>(options =>\n            {\n                // Duration of each job shard (jobs are partitioned by time)\n                options.ShardDuration = TimeSpan.FromMinutes(5);\n                \n                // Maximum number of jobs that can execute concurrently on each silo\n                options.MaxConcurrentJobsPerSilo = 100;\n                \n                // Custom retry policy\n                options.ShouldRetry = (context, exception) =>\n                {\n                    // Retry up to 3 times with exponential backoff\n                    if (context.DequeueCount < 3)\n                    {\n                        var delay = TimeSpan.FromSeconds(Math.Pow(2, context.DequeueCount));\n                        return DateTimeOffset.UtcNow.Add(delay);\n                    }\n                    return null; // Don't retry\n                };\n            });\n        });\n});\n```\n\n## Usage Examples\n\n### Basic Job Scheduling\n\n#### 1. Implement the IDurableJobHandler Interface\n```csharp\nusing Orleans;\nusing Orleans.DurableJobs;\n\npublic interface INotificationGrain : IGrainWithStringKey\n{\n    Task ScheduleNotification(string message, DateTimeOffset sendTime);\n    Task CancelScheduledNotification();\n}\n\npublic class NotificationGrain : Grain, INotificationGrain, IDurableJobHandler\n{\n    private readonly ILocalDurableJobManager _jobManager;\n    private readonly ILogger<NotificationGrain> _logger;\n    private IDurableJob? _durableJob;\n\n    public NotificationGrain(\n        ILocalDurableJobManager jobManager,\n        ILogger<NotificationGrain> logger)\n    {\n        _jobManager = jobManager;\n        _logger = logger;\n    }\n\n    public async Task ScheduleNotification(string message, DateTimeOffset sendTime)\n    {\n        var userId = this.GetPrimaryKeyString();\n        var metadata = new Dictionary<string, string>\n        {\n            [\"Message\"] = message\n        };\n\n        _durableJob = await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"SendNotification\",\n                DueTime = sendTime,\n                Metadata = metadata\n            },\n            CancellationToken.None);\n\n        _logger.LogInformation(\n            \"Scheduled notification for user {UserId} at {SendTime} (JobId: {JobId})\",\n            userId, sendTime, _durableJob.Id);\n    }\n\n    public async Task CancelScheduledNotification()\n    {\n        if (_durableJob is null)\n        {\n            _logger.LogWarning(\"No scheduled notification to cancel\");\n            return;\n        }\n\n        var canceled = await _jobManager.TryCancelDurableJobAsync(_durableJob);\n        _logger.LogInformation(\"Notification {JobId} canceled: {Canceled}\", _durableJob.Id, canceled);\n        \n        if (canceled)\n        {\n            _durableJob = null;\n        }\n    }\n\n    // This method is called when the durable job executes\n    public Task ExecuteJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n    {\n        var userId = this.GetPrimaryKeyString();\n        var message = context.Job.Metadata?[\"Message\"];\n\n        _logger.LogInformation(\n            \"Sending notification to user {UserId}: {Message} (Job: {JobId}, Run: {RunId}, Attempt: {DequeueCount})\",\n            userId, message, context.Job.Id, context.RunId, context.DequeueCount);\n\n        // Send the notification here\n        // If this throws an exception, the job can be retried based on your retry policy\n        \n        _durableJob = null;\n        return Task.CompletedTask;\n    }\n}\n```\n\n#### 2. Order Workflow with Multiple Jobs\n```csharp\npublic interface IOrderGrain : IGrainWithGuidKey\n{\n    Task PlaceOrder(OrderDetails details);\n    Task CancelOrder();\n}\n\npublic class OrderGrain : Grain, IOrderGrain, IDurableJobHandler\n{\n    private readonly ILocalDurableJobManager _jobManager;\n    private readonly IOrderService _orderService;\n    private readonly IGrainFactory _grainFactory;\n    private readonly ILogger<OrderGrain> _logger;\n\n    public OrderGrain(\n        ILocalDurableJobManager jobManager,\n        IOrderService orderService,\n        IGrainFactory grainFactory,\n        ILogger<OrderGrain> logger)\n    {\n        _jobManager = jobManager;\n        _orderService = orderService;\n        _grainFactory = grainFactory;\n        _logger = logger;\n    }\n\n    public async Task PlaceOrder(OrderDetails details)\n    {\n        var orderId = this.GetPrimaryKey();\n        \n        // Create the order\n        await _orderService.CreateOrderAsync(orderId, details);\n        \n        // Schedule delivery reminder for 24 hours before delivery\n        var reminderTime = details.DeliveryDate.AddHours(-24);\n        await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"DeliveryReminder\",\n                DueTime = reminderTime,\n                Metadata = new Dictionary<string, string>\n                {\n                    [\"Step\"] = \"DeliveryReminder\",\n                    [\"CustomerId\"] = details.CustomerId,\n                    [\"OrderNumber\"] = details.OrderNumber\n                }\n            },\n            CancellationToken.None);\n\n        // Schedule order expiration if payment not received\n        var expirationTime = DateTimeOffset.UtcNow.AddHours(24);\n        await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = \"OrderExpiration\",\n                DueTime = expirationTime,\n                Metadata = new Dictionary<string, string>\n                {\n                    [\"Step\"] = \"OrderExpiration\"\n                }\n            },\n            CancellationToken.None);\n    }\n\n    public async Task CancelOrder()\n    {\n        var orderId = this.GetPrimaryKey();\n        await _orderService.CancelOrderAsync(orderId);\n    }\n\n    public async Task ExecuteJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n    {\n        var step = context.Job.Metadata![\"Step\"];\n        var orderId = this.GetPrimaryKey();\n\n        switch (step)\n        {\n            case \"DeliveryReminder\":\n                await HandleDeliveryReminder(context, cancellationToken);\n                break;\n\n            case \"OrderExpiration\":\n                await HandleOrderExpiration(cancellationToken);\n                break;\n        }\n    }\n\n    private async Task HandleDeliveryReminder(IJobRunContext context, CancellationToken ct)\n    {\n        var customerId = context.Job.Metadata![\"CustomerId\"];\n        var orderNumber = context.Job.Metadata[\"OrderNumber\"];\n        \n        var notificationGrain = _grainFactory.GetGrain<INotificationGrain>(customerId);\n        await notificationGrain.ScheduleNotification(\n            $\"Your order #{orderNumber} will be delivered tomorrow!\",\n            DateTimeOffset.UtcNow);\n    }\n\n    private async Task HandleOrderExpiration(CancellationToken ct)\n    {\n        var orderId = this.GetPrimaryKey();\n        var order = await _orderService.GetOrderAsync(orderId, ct);\n        \n        if (order?.Status == OrderStatus.Pending)\n        {\n            await _orderService.CancelOrderAsync(orderId, ct);\n            _logger.LogInformation(\"Order {OrderId} expired and canceled\", orderId);\n        }\n    }\n}\n```\n\n### Advanced Scenarios\n\n#### Job with Retry Logic\n```csharp\npublic class PaymentProcessorGrain : Grain, IDurableJobHandler\n{\n    private readonly IPaymentService _paymentService;\n    private readonly ILogger<PaymentProcessorGrain> _logger;\n\n    public Task ExecuteJobAsync(IJobRunContext context, CancellationToken cancellationToken)\n    {\n        var paymentId = context.Job.Metadata?[\"PaymentId\"];\n        \n        _logger.LogInformation(\n            \"Processing payment {PaymentId} (Attempt {Attempt})\",\n            paymentId, context.DequeueCount);\n\n        try\n        {\n            await _paymentService.ProcessPaymentAsync(paymentId, cancellationToken);\n            return Task.CompletedTask;\n        }\n        catch (TransientException ex)\n        {\n            _logger.LogWarning(ex, \"Payment processing failed with transient error, will retry\");\n            throw; // Let the retry policy handle it\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Payment processing failed with permanent error\");\n            throw; // This will not be retried if the retry policy returns null\n        }\n    }\n}\n```\n\n#### Tracking Job Completion\n```csharp\npublic class WorkflowGrain : Grain, IDurableJobHandler\n{\n    private readonly Dictionary<string, TaskCompletionSource> _pendingJobs = new();\n\n    public async Task<IDurableJob> ScheduleWorkflowStep(string stepName, DateTimeOffset executeAt)\n    {\n        var job = await _jobManager.ScheduleJobAsync(\n            new ScheduleJobRequest\n            {\n                Target = this.GetGrainId(),\n                JobName = stepName,\n                DueTime = executeAt,\n                Metadata = null\n            },\n            CancellationToken.None);\n\n        _pendingJobs[job.Id] = new TaskCompletionSource();\n        return job;\n    }\n\n    public async Task WaitForJobCompletion(string jobId, TimeSpan timeout)\n    {\n        if (_pendingJobs.TryGetValue(jobId, out var tcs))\n        {\n            using var cts = new CancellationTokenSource(timeout);\n            await tcs.Task.WaitAsync(cts.Token);\n        }\n    }\n\n    public Task ExecuteJobAsync(IDurableJobContext context, CancellationToken cancellationToken)\n    {\n        // Execute the workflow step...\n        \n        // Mark as complete\n        if (_pendingJobs.TryRemove(context.Job.Id, out var tcs))\n        {\n            tcs.SetResult();\n        }\n\n        return Task.CompletedTask;\n    }\n}\n```\n\n## How It Works\n\n### Architecture Overview\n1. **Job Sharding**: Jobs are partitioned into time-based shards (default: 1-minute windows)\n2. **Shard Ownership**: Each shard is owned by a single silo for execution\n3. **Automatic Rebalancing**: When a silo fails, its shards are automatically reassigned to healthy silos\n4. **Ordered Execution**: Within a shard, jobs are processed in order of their due time\n5. **Concurrency Control**: The `MaxConcurrentJobsPerSilo` setting limits concurrent job execution\n\n### Job Lifecycle\n```\n┌─────────────┐\n│  Scheduled  │ ──▶ Job is created and added to appropriate shard\n└─────────────┘\n      │\n      ▼\n┌─────────────┐\n│   Waiting   │ ──▶ Job waits in queue until due time\n└─────────────┘\n      │\n      ▼\n┌─────────────┐\n│  Executing  │ ──▶ Job handler is invoked on target grain\n└─────────────┘\n      │\n      ├──▶ Success ──▶ Job is removed\n      │\n      └──▶ Failure ──▶ Retry policy decides:\n                        • Retry: Job is re-queued with new due time\n                        • No Retry: Job is removed\n```\n\n## Configuration Reference\n\n### DurableJobsOptions\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `ShardDuration` | `TimeSpan` | 1 minute | Duration of each job shard. Smaller values reduce latency but increase overhead. |\n| `MaxConcurrentJobsPerSilo` | `int` | 100 | Maximum number of jobs that can execute simultaneously on a silo. |\n| `ShouldRetry` | `Func<IDurableJobContext, Exception, DateTimeOffset?>` | 3 retries with exp. backoff | Determines if a failed job should be retried. Return the new due time or `null` to not retry. |\n\n## Best Practices\n\n1. **Set Reasonable Concurrency Limits**: Prevent resource exhaustion\n   ```csharp\n   options.MaxConcurrentJobsPerSilo = 100; // Adjust based on your workload\n   ```\n\n2. **Implement Idempotent Job Handlers**: Jobs may be retried, ensure handlers are idempotent\n   ```csharp\n   public async Task ExecuteJobAsync(IDurableJobContext context, CancellationToken ct)\n   {\n       var jobId = context.Job.Id;\n       // Check if already processed\n       if (await _state.IsProcessed(jobId))\n           return;\n           \n       // Process job...\n       await _state.MarkProcessed(jobId);\n   }\n   ```\n\n3. **Use Metadata Wisely**: Keep metadata lightweight\n   ```csharp\n   // Good: Store IDs\n   var metadata = new Dictionary<string, string> { [\"OrderId\"] = \"12345\" };\n   \n   // Bad: Store large objects\n   var metadata = new Dictionary<string, string> { [\"Order\"] = JsonSerializer.Serialize(largeOrder) };\n   ```\n\n4. **Handle Cancellation**: Respect the cancellation token\n   ```csharp\n   public async Task ExecuteJobAsync(IDurableJobContext context, CancellationToken ct)\n   {\n       await SomeLongRunningOperation(ct);\n   }\n   ```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Timers and Reminders](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Orleans.DurableJobs/ScheduleJobRequest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Represents a request to schedule a durable job.\n/// </summary>\npublic readonly struct ScheduleJobRequest\n{\n    /// <summary>\n    /// Gets the grain identifier of the target grain that will receive the durable job.\n    /// </summary>\n    public required GrainId Target { get; init; }\n\n    /// <summary>\n    /// Gets the name of the job for identification purposes.\n    /// </summary>\n    public required string JobName { get; init; }\n\n    /// <summary>\n    /// Gets the date and time when the job should be executed.\n    /// </summary>\n    public required DateTimeOffset DueTime { get; init; }\n\n    /// <summary>\n    /// Gets optional metadata associated with the job.\n    /// </summary>\n    public IReadOnlyDictionary<string, string>? Metadata { get; init; }\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/ShardExecutor.Log.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.DurableJobs;\n\ninternal sealed partial class ShardExecutor\n{\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Waiting {Delay} for shard {ShardId} start time {StartTime}\"\n    )]\n    private static partial void LogWaitingForShardStartTime(ILogger logger, string shardId, TimeSpan delay, DateTimeOffset startTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Begin processing shard {ShardId}\"\n    )]\n    private static partial void LogBeginProcessingShard(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Executing job {JobId} (Name: '{JobName}') for grain {TargetGrain}, due at {DueTime}\"\n    )]\n    private static partial void LogExecutingJob(ILogger logger, string jobId, string jobName, GrainId targetGrain, DateTimeOffset dueTime);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Job {JobId} (Name: '{JobName}') executed successfully\"\n    )]\n    private static partial void LogJobExecutedSuccessfully(ILogger logger, string jobId, string jobName);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error executing job {JobId}\"\n    )]\n    private static partial void LogErrorExecutingJob(ILogger logger, Exception exception, string jobId);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Retrying job {JobId} (Name: '{JobName}') at {RetryTime}. Dequeue count: {DequeueCount}\"\n    )]\n    private static partial void LogRetryingJob(ILogger logger, string jobId, string jobName, DateTimeOffset retryTime, int dequeueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Polling job {JobId} (Name: '{JobName}') - will check status again in {PollDelay}\"\n    )]\n    private static partial void LogPollingJob(ILogger logger, string jobId, string jobName, TimeSpan pollDelay);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Job {JobId} (Name: '{JobName}') returned Failed status\"\n    )]\n    private static partial void LogJobFailedWithResult(ILogger logger, string jobId, string jobName);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Job {JobId} (Name: '{JobName}') failed after {DequeueCount} attempts and will not be retried\"\n    )]\n    private static partial void LogJobFailedNoRetry(ILogger logger, string jobId, string jobName, int dequeueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Completed processing shard {ShardId}\"\n    )]\n    private static partial void LogCompletedProcessingShard(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Shard {ShardId} processing cancelled\"\n    )]\n    private static partial void LogShardCancelled(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Overload detected for shard {ShardId}, pausing job processing\"\n    )]\n    private static partial void LogOverloadDetected(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Overload cleared for shard {ShardId}, resuming job processing\"\n    )]\n    private static partial void LogOverloadCleared(ILogger logger, string shardId);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Slow start initiated: initial concurrency {InitialConcurrency}, target {TargetConcurrency}, interval {Interval}\"\n    )]\n    private static partial void LogSlowStartBegin(ILogger logger, int initialConcurrency, int targetConcurrency, TimeSpan interval);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Slow start: concurrency increased to {CurrentConcurrency} (target: {TargetConcurrency})\"\n    )]\n    private static partial void LogSlowStartConcurrencyIncreased(ILogger logger, int currentConcurrency, int targetConcurrency);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Slow start complete: concurrency reached target {TargetConcurrency}\"\n    )]\n    private static partial void LogSlowStartComplete(ILogger logger, int targetConcurrency);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Slow start ramp-up failed; all remaining concurrency has been released\"\n    )]\n    private static partial void LogSlowStartError(ILogger logger, Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.DurableJobs/ShardExecutor.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.DurableJobs;\n\n/// <summary>\n/// Handles the execution of job shards and individual durable jobs.\n/// </summary>\ninternal sealed partial class ShardExecutor\n{\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly ILogger<ShardExecutor> _logger;\n    private readonly DurableJobsOptions _options;\n    private readonly SemaphoreSlim _jobConcurrencyLimiter;\n    private readonly IOverloadDetector _overloadDetector;\n    private int _currentCapacity;\n    private int _slowStartRampUpStarted;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ShardExecutor\"/> class.\n    /// </summary>\n    /// <param name=\"grainFactory\">The grain factory for creating grain references.</param>\n    /// <param name=\"options\">The durable jobs configuration options.</param>\n    /// <param name=\"overloadDetector\">The overload detector for throttling job execution.</param>\n    /// <param name=\"logger\">The logger instance.</param>\n    public ShardExecutor(\n        IInternalGrainFactory grainFactory,\n        IOptions<DurableJobsOptions> options,\n        IOverloadDetector overloadDetector,\n        ILogger<ShardExecutor> logger)\n    {\n        _grainFactory = grainFactory;\n        _logger = logger;\n        _options = options.Value;\n        _overloadDetector = overloadDetector;\n\n        _currentCapacity = _options.ConcurrencySlowStartEnabled && _options.SlowStartInitialConcurrency < _options.MaxConcurrentJobsPerSilo\n            ? _options.SlowStartInitialConcurrency\n            : _options.MaxConcurrentJobsPerSilo;\n\n        _jobConcurrencyLimiter = new SemaphoreSlim(_currentCapacity);\n    }\n\n    /// <summary>\n    /// Runs a shard, processing all jobs within it until completion or cancellation.\n    /// </summary>\n    /// <param name=\"shard\">The shard to execute.</param>\n    /// <param name=\"cancellationToken\">Cancellation token to stop processing.</param>\n    /// <returns>A task representing the asynchronous operation.</returns>\n    public async Task RunShardAsync(IJobShard shard, CancellationToken cancellationToken)\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n        if (Volatile.Read(ref _currentCapacity) < _options.MaxConcurrentJobsPerSilo\n            && Interlocked.CompareExchange(ref _slowStartRampUpStarted, 1, 0) == 0)\n        {\n            _ = Task.Run(SlowStartRampUpAsync);\n        }\n\n        var tasks = new ConcurrentDictionary<string, Task>();\n        try\n        {\n            if (shard.StartTime > DateTime.UtcNow)\n            {\n                // Wait until the shard's start time\n                var delay = shard.StartTime - DateTimeOffset.UtcNow;\n                LogWaitingForShardStartTime(_logger, shard.Id, delay, shard.StartTime);\n                await Task.Delay(delay, cancellationToken);\n            }\n\n            LogBeginProcessingShard(_logger, shard.Id);\n\n            // Process all jobs in the shard\n            await foreach (var jobContext in shard.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n            {\n                // Check for overload and pause batch processing if needed\n                if (_overloadDetector.IsOverloaded)\n                {\n                    LogOverloadDetected(_logger, shard.Id);\n                    while (_overloadDetector.IsOverloaded)\n                    {\n                        await Task.Delay(_options.OverloadBackoffDelay, cancellationToken);\n                    }\n                    LogOverloadCleared(_logger, shard.Id);\n                }\n\n                // Wait for concurrency slot\n                await _jobConcurrencyLimiter.WaitAsync(cancellationToken);\n                // Start processing the job. RunJobAsync will release the semaphore when done and remove itself from the tasks dictionary\n                tasks[jobContext.Job.Id] = RunJobAsync(jobContext, shard, tasks, cancellationToken);\n            }\n\n            LogCompletedProcessingShard(_logger, shard.Id);\n        }\n        catch (OperationCanceledException)\n        {\n            LogShardCancelled(_logger, shard.Id);\n            throw;\n        }\n        finally\n        {\n            // Wait for all jobs to complete\n            await Task.WhenAll(tasks.Values);\n        }\n    }\n\n    private async Task SlowStartRampUpAsync()\n    {\n        var targetCapacity = _options.MaxConcurrentJobsPerSilo;\n        LogSlowStartBegin(_logger, Volatile.Read(ref _currentCapacity), targetCapacity, _options.SlowStartInterval);\n\n        try\n        {\n            while (Volatile.Read(ref _currentCapacity) < targetCapacity)\n            {\n                await Task.Delay(_options.SlowStartInterval);\n\n                while (true)\n                {\n                    var currentCapacity = Volatile.Read(ref _currentCapacity);\n                    if (currentCapacity >= targetCapacity)\n                    {\n                        break;\n                    }\n\n                    var newCapacity = (int)Math.Min((long)currentCapacity * 2, targetCapacity);\n                    var toRelease = newCapacity - currentCapacity;\n                    if (toRelease <= 0)\n                    {\n                        break;\n                    }\n\n                    if (Interlocked.CompareExchange(ref _currentCapacity, newCapacity, currentCapacity) == currentCapacity)\n                    {\n                        _jobConcurrencyLimiter.Release(toRelease);\n                        LogSlowStartConcurrencyIncreased(_logger, newCapacity, targetCapacity);\n                        break;\n                    }\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            // If the ramp-up fails for any reason, release all remaining capacity to avoid being stuck at low concurrency.\n            var currentCapacity = Volatile.Read(ref _currentCapacity);\n            var remaining = targetCapacity - currentCapacity;\n            if (remaining > 0)\n            {\n                _jobConcurrencyLimiter.Release(remaining);\n                Interlocked.Exchange(ref _currentCapacity, targetCapacity);\n            }\n\n            LogSlowStartError(_logger, ex);\n            return;\n        }\n\n        LogSlowStartComplete(_logger, Volatile.Read(ref _currentCapacity));\n    }\n\n    private async Task RunJobAsync(\n        IJobRunContext jobContext,\n        IJobShard shard,\n        ConcurrentDictionary<string, Task> runningTasks,\n        CancellationToken cancellationToken)\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding);\n\n        Exception? failureException = null;\n\n        try\n        {\n            try\n            {\n                LogExecutingJob(_logger, jobContext.Job.Id, jobContext.Job.Name, jobContext.Job.TargetGrainId, jobContext.Job.DueTime);\n\n                var target = _grainFactory.GetGrain<IDurableJobReceiverExtension>(jobContext.Job.TargetGrainId);\n\n                var result = await target.HandleDurableJobAsync(jobContext, cancellationToken);\n\n                // Handle the result based on status\n                while (result.IsPending)\n                {\n                    // Enter polling loop\n                    LogPollingJob(_logger, jobContext.Job.Id, jobContext.Job.Name, result.PollAfterDelay.Value);\n\n                    await Task.Delay(result.PollAfterDelay.Value, cancellationToken);\n\n                    result = await target.HandleDurableJobAsync(jobContext, cancellationToken);\n                }\n\n                if (result.Status == DurableJobRunStatus.Completed)\n                {\n                    await shard.RemoveJobAsync(jobContext.Job.Id, cancellationToken);\n                    LogJobExecutedSuccessfully(_logger, jobContext.Job.Id, jobContext.Job.Name);\n                }\n                else if (result.IsFailed)\n                {\n                    // Handle failed result through retry policy\n                    LogJobFailedWithResult(_logger, jobContext.Job.Id, jobContext.Job.Name);\n                    failureException = result.Exception;\n                }\n            }\n            catch (Exception ex) when (ex is not OperationCanceledException)\n            {\n                LogErrorExecutingJob(_logger, ex, jobContext.Job.Id);\n                failureException = ex;\n            }\n\n            // Cancellation is handled by shard takeover, so only non-cancellation failures are retried here.\n            if (failureException is not null)\n            {\n                var retryTime = _options.ShouldRetry(jobContext, failureException);\n                if (retryTime is not null)\n                {\n                    LogRetryingJob(_logger, jobContext.Job.Id, jobContext.Job.Name, retryTime.Value, jobContext.DequeueCount);\n                    await shard.RetryJobLaterAsync(jobContext, retryTime.Value, cancellationToken);\n                }\n                else\n                {\n                    LogJobFailedNoRetry(_logger, jobContext.Job.Id, jobContext.Job.Name, jobContext.DequeueCount);\n                }\n            }\n        }\n        finally\n        {\n            // Cleanup must happen even when retry persistence throws, otherwise slots leak and shard processing can stall.\n            _jobConcurrencyLimiter.Release();\n            runningTasks.TryRemove(jobContext.Job.Id, out _);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Common/ConnectionIssues.cs",
    "content": "using System;\n\nnamespace Orleans.EventSourcing.Common\n{\n    /// <summary>\n    /// Describes a connection issue that occurred when communicating with primary storage.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class PrimaryOperationFailed : ConnectionIssue\n    {\n        /// <summary>\n        /// The exception that was caught when communicating with the primary.\n        /// </summary>\n        [Id(0)]\n        public Exception Exception { get; set; }\n\n        /// <inheritdoc/>\n        public override TimeSpan ComputeRetryDelay(TimeSpan? previous)\n        {\n            // after first fail do not backoff yet... keep it at zero\n            if (previous == null)\n            {\n                return TimeSpan.Zero;\n            }\n\n            var backoff = previous.Value.TotalMilliseconds;\n\n            // grows exponentially up to slowpoll interval\n            if (previous.Value.TotalMilliseconds < slowpollinterval)\n                backoff = (int)((backoff + Random.Shared.Next(5, 15)) * 1.5);\n\n            // during slowpoll, slightly randomize\n            if (backoff > slowpollinterval)\n                backoff = slowpollinterval + Random.Shared.Next(1, 200);\n\n            return TimeSpan.FromMilliseconds(backoff);\n        }\n\n        private const int slowpollinterval = 10000;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Common/NotificationMessage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.EventSourcing.Common\n{\n    /// <summary>\n    /// Base class for notification messages that are sent by log view adaptors to other \n    /// clusters, after updating the log. All subclasses must be serializable.\n    /// </summary>\n    public interface INotificationMessage : ILogConsistencyProtocolMessage\n    {\n        ///<summary>The version number.</summary>\n        int Version { get; }\n\n        // a log-consistency provider can subclass this to add more information\n        // for example, the log entries that were appended, or the view\n    }\n\n    /// <summary>A simple notification message containing only the version.</summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class VersionNotificationMessage : INotificationMessage\n    {\n        /// <inheritdoc/>\n        [Id(0)]\n        public int Version { get; set;  }\n    }\n\n\n    /// <summary>A notification message containing a batch of notification messages.</summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class BatchedNotificationMessage : INotificationMessage\n    {\n        /// <summary>The notification messages contained in this batch.</summary>\n        [Id(0)]\n        public List<INotificationMessage> Notifications { get; set; }\n\n        /// <summary>The version number - for a batch, this is the maximum version contained.</summary>\n        public int Version {\n            get\n            {\n                return Notifications.Aggregate(0, (v, m) => Math.Max(v, m.Version));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Common/PrimaryBasedLogViewAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.EventSourcing.Common\n{\n    /// <summary>\n    /// A general template for constructing log view adaptors that are based on\n    /// a sequentially read and written primary. We use this to construct \n    /// a variety of different log-consistency providers, all following the same basic pattern \n    /// (read and write latest view from/to primary, and send notifications after writing).\n    ///<para>\n    /// Note that the log itself is transient, i.e. not actually saved to storage - only the latest view and some \n    /// metadata (the log position, and write flags) is stored in the primary. \n    /// It is safe to interleave calls to this adaptor (using grain scheduler only, of course).\n    /// </para>\n    ///<para>\n    /// Subclasses override ReadAsync and WriteAsync to read from / write to primary.\n    /// Calls to the primary are serialized, i.e. never interleave.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"TLogView\">The user-defined view of the log</typeparam>\n    /// <typeparam name=\"TLogEntry\">The type of the log entries</typeparam>\n    /// <typeparam name=\"TSubmissionEntry\">The type of submission entries stored in pending queue</typeparam>\n    public abstract class PrimaryBasedLogViewAdaptor<TLogView, TLogEntry, TSubmissionEntry> : ILogViewAdaptor<TLogView, TLogEntry>\n    where TLogView : class, new()\n        where TLogEntry : class\n        where TSubmissionEntry : SubmissionEntry<TLogEntry>\n    {\n        /// <summary>\n        /// Set confirmed view the initial value (a view of the empty log)\n        /// </summary>\n        protected abstract void InitializeConfirmedView(TLogView initialstate);\n\n        /// <summary>\n        /// Read cached global state.\n        /// </summary>\n        protected abstract TLogView LastConfirmedView();\n\n        /// <summary>\n        /// Read version of cached global state.\n        /// </summary>\n        protected abstract int GetConfirmedVersion();\n\n        /// <summary>\n        /// Read the latest primary state. Must block/retry until successful.\n        /// Should not throw exceptions, but record them in <see cref=\"LastPrimaryIssue\"/>\n        /// </summary>\n        /// <returns></returns>\n        protected abstract Task ReadAsync();\n\n        /// <summary>\n        /// Apply pending entries to the primary. Must block/retry until successful. \n        /// Should not throw exceptions, but record them in <see cref=\"LastPrimaryIssue\"/>\n        /// </summary>\n        protected abstract Task<int> WriteAsync();\n\n        /// <summary>\n        /// Create a submission entry for the submitted log entry. \n        /// Using a type parameter so we can add protocol-specific info to this class.\n        /// </summary>\n        /// <returns></returns>\n        protected abstract TSubmissionEntry MakeSubmissionEntry(TLogEntry entry);\n\n        /// <summary>\n        /// Whether this cluster supports submitting updates\n        /// </summary>\n        protected virtual bool SupportSubmissions { get { return true; } }\n\n        /// <summary>\n        /// Handle protocol messages.\n        /// </summary>\n        protected virtual Task<ILogConsistencyProtocolMessage> OnMessageReceived(ILogConsistencyProtocolMessage payload)\n        {\n            // subclasses that define custom protocol messages must override this\n            throw new NotImplementedException();\n        }\n\n        public virtual Task<IReadOnlyList<TLogEntry>> RetrieveLogSegment(int fromVersion, int length)\n        {\n            throw new NotSupportedException();\n        }\n\n        /// <summary>\n        /// Clear the persisted log stream completely.\n        /// </summary>\n        protected virtual Task ClearPrimaryLogAsync(CancellationToken cancellationToken)\n        {\n            throw new NotSupportedException();\n        }\n\n        /// <inheritdoc/>\n        public virtual Task ClearLogAsync(CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            if (clearLogRequest is null || clearLogRequest.Task.IsCompleted)\n            {\n                clearLogCancellationToken = cancellationToken;\n                clearLogRequest = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n            }\n\n            worker.Notify();\n\n            var clearLogTask = clearLogRequest.Task;\n\n            return cancellationToken.CanBeCanceled\n                ? clearLogTask.WaitAsync(cancellationToken)\n                : clearLogTask;\n        }\n\n        /// <summary>\n        /// Handle notification messages. Override this to handle notification subtypes.\n        /// </summary>\n        protected virtual void OnNotificationReceived(INotificationMessage payload)\n        {\n            var msg = payload as VersionNotificationMessage;\n            if (msg != null)\n            {\n                if (msg.Version > lastVersionNotified)\n                    lastVersionNotified = msg.Version;\n                return;\n            }\n\n            var batchmsg = payload as BatchedNotificationMessage;\n            if (batchmsg != null)\n            {\n                foreach (var bm in batchmsg.Notifications)\n                    OnNotificationReceived(bm);\n                return;\n            }\n\n            // subclass should have handled this in override\n            throw new ProtocolTransportException(string.Format(\"message type {0} not handled by OnNotificationReceived\", payload.GetType().FullName));\n        }\n\n        /// <summary>\n        /// The last version we have been notified of\n        /// </summary>\n        private int lastVersionNotified;\n\n        /// <summary>\n        /// Process stored notifications during worker cycle. Override to handle notification subtypes.\n        /// </summary>\n        protected virtual void ProcessNotifications()\n        {\n            if (lastVersionNotified > this.GetConfirmedVersion())\n            {\n                Services.Log(LogLevel.Debug, \"force refresh because of version notification v{0}\", lastVersionNotified);\n                needRefresh = true;\n            }\n        }\n\n        /// <summary>\n        /// Merge two notification messages, for batching. Override to handle notification subtypes.\n        /// </summary>\n        protected virtual INotificationMessage Merge(INotificationMessage earliermessage, INotificationMessage latermessage)\n        {\n            return new VersionNotificationMessage()\n            {\n                Version = latermessage.Version\n            };\n        }\n\n        /// <summary>\n        /// The grain that is using this adaptor.\n        /// </summary>\n        protected ILogViewAdaptorHost<TLogView, TLogEntry> Host { get; private set; }\n\n        /// <summary>\n        /// The runtime services required for implementing notifications between grain instances in different cluster.\n        /// </summary>\n        protected ILogConsistencyProtocolServices Services { get; private set; }\n\n        /// <summary>\n        /// Construct an instance, for the given parameters.\n        /// </summary>\n        protected PrimaryBasedLogViewAdaptor(\n            ILogViewAdaptorHost<TLogView, TLogEntry> host,\n            TLogView initialstate,\n            ILogConsistencyProtocolServices services)\n        {\n            Debug.Assert(host != null && services != null && initialstate != null);\n            this.Host = host;\n            this.Services = services;\n            this.InitialState = Services.DeepCopy(initialstate);\n            InitializeConfirmedView(initialstate);\n            worker = new BatchWorkerFromDelegate(Work);\n        }\n\n        /// <inheritdoc/>\n        public virtual Task PreOnActivate()\n        {\n            Services.Log(LogLevel.Trace, \"PreActivation Started\");\n\n            // this flag indicates we have not done an initial load from storage yet\n            // we do not act on this yet, but wait until after user OnActivate has run. \n            needInitialRead = true;\n\n            Services.Log(LogLevel.Trace, \"PreActivation Complete\");\n\n            return Task.CompletedTask;\n        }\n\n        public virtual Task PostOnActivate()\n        {\n            Services.Log(LogLevel.Trace, \"PostActivation Started\");\n\n            // start worker, if it has not already happened\n            if (needInitialRead)\n                worker.Notify();\n\n            Services.Log(LogLevel.Trace, \"PostActivation Complete\");\n\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc/>\n        public virtual async Task PostOnDeactivate()\n        {\n            Services.Log(LogLevel.Trace, \"Deactivation Started\");\n\n            while (!worker.IsIdle())\n            {\n                await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding);\n                await worker.WaitForCurrentWorkToBeServiced();\n            }\n\n            Services.Log(LogLevel.Trace, \"Deactivation Complete\");\n        }\n\n\n        // the currently submitted, unconfirmed entries. \n        private readonly List<TSubmissionEntry> pending = new List<TSubmissionEntry>();\n\n\n        /// called at beginning of WriteAsync to the current tentative state\n        protected TLogView CopyTentativeState()\n        {\n            var state = TentativeView;\n            tentativeStateInternal = null; // to avoid aliasing\n            return state;\n        }\n        /// called at beginning of WriteAsync to the current batch of updates\n        protected TSubmissionEntry[] GetCurrentBatchOfUpdates()\n        {\n            return pending.ToArray(); // must use a copy\n        }\n        /// called at beginning of WriteAsync to get current number of pending updates\n        protected int GetNumberPendingUpdates()\n        {\n            return pending.Count;\n        }\n\n        /// <summary>\n        ///  Tentative State. Represents Stable State + effects of pending updates.\n        ///  Computed lazily (null if not in use)\n        /// </summary>\n        private TLogView tentativeStateInternal;\n\n        /// <summary>\n        /// A flag that indicates to the worker that the client wants to refresh the state\n        /// </summary>\n        private bool needRefresh;\n\n        /// <summary>\n        /// A flag that indicates that we have not read global state at all yet, and should do so\n        /// </summary>\n        private bool needInitialRead;\n\n        /// <summary>\n        /// A pending clear-log request to be processed by the worker.\n        /// </summary>\n        private TaskCompletionSource<bool> clearLogRequest;\n        private CancellationToken clearLogCancellationToken;\n\n        /// <summary>\n        /// Background worker which asynchronously sends operations to the leader\n        /// </summary>\n        private readonly BatchWorker worker;\n\n        /// <summary>\n        /// Cached version of initial state used during initialization. And for resetting.\n        /// </summary>\n        protected TLogView InitialState { init; get => Services.DeepCopy(field); }\n\n        /// statistics gathering. Is null unless stats collection is turned on.\n        protected LogConsistencyStatistics stats = null;\n\n\n        /// For use by protocols. Determines if this cluster is part of the configured multicluster.\n        protected bool IsMyClusterJoined()\n        {\n            return true;\n        }\n\n        /// <summary>\n        /// Block until this cluster is joined to the multicluster.\n        /// </summary>\n        protected async Task EnsureClusterJoinedAsync()\n        {\n            while (!IsMyClusterJoined())\n            {\n                Services.Log(LogLevel.Debug, \"Waiting for join\");\n                await Task.Delay(5000);\n            }\n        }\n\n        /// <inheritdoc />\n        public void Submit(TLogEntry logEntry)\n        {\n            if (!SupportSubmissions)\n                throw new InvalidOperationException(\"provider does not support submissions on cluster \" + Services.MyClusterId);\n\n            if (stats != null) stats.EventCounters[\"SubmitCalled\"]++;\n\n            Services.Log(LogLevel.Trace, \"Submit\");\n\n            SubmitInternal(DateTime.UtcNow, logEntry);\n\n            worker.Notify();\n        }\n\n        /// <inheritdoc />\n        public void SubmitRange(IEnumerable<TLogEntry> logEntries)\n        {\n            if (!SupportSubmissions)\n                throw new InvalidOperationException(\"Provider does not support submissions on cluster \" + Services.MyClusterId);\n\n            if (stats != null) stats.EventCounters[\"SubmitRangeCalled\"]++;\n\n            Services.Log(LogLevel.Trace, \"SubmitRange\");\n\n            var time = DateTime.UtcNow;\n\n            foreach (var e in logEntries)\n                SubmitInternal(time, e);\n\n            worker.Notify();\n        }\n\n        /// <inheritdoc />\n        public Task<bool> TryAppend(TLogEntry logEntry)\n        {\n            if (!SupportSubmissions)\n                throw new InvalidOperationException(\"Provider does not support submissions on cluster \" + Services.MyClusterId);\n\n            if (stats != null) stats.EventCounters[\"TryAppendCalled\"]++;\n\n            Services.Log(LogLevel.Trace, \"TryAppend\");\n\n            var promise = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            SubmitInternal(DateTime.UtcNow, logEntry, GetConfirmedVersion() + pending.Count, promise);\n\n            worker.Notify();\n\n            return promise.Task;\n        }\n\n        /// <inheritdoc />\n        public Task<bool> TryAppendRange(IEnumerable<TLogEntry> logEntries)\n        {\n            if (!SupportSubmissions)\n                throw new InvalidOperationException(\"Provider does not support submissions on cluster \" + Services.MyClusterId);\n\n            if (stats != null) stats.EventCounters[\"TryAppendRangeCalled\"]++;\n\n            Services.Log(LogLevel.Trace, \"TryAppendRange\");\n\n            var promise = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n            var time = DateTime.UtcNow;\n            var pos = GetConfirmedVersion() + pending.Count;\n\n            bool first = true;\n            foreach (var e in logEntries)\n            {\n                SubmitInternal(time, e, pos++, first ? promise : null);\n                first = false;\n            }\n\n            worker.Notify();\n\n            return promise.Task;\n        }\n\n\n        private const int unconditional = -1;\n\n        private void SubmitInternal(DateTime time, TLogEntry logentry, int conditionalPosition = unconditional, TaskCompletionSource<bool> resultPromise = null)\n        {\n            // create a submission entry\n            var submissionentry = this.MakeSubmissionEntry(logentry);\n            submissionentry.SubmissionTime = time;\n            submissionentry.ResultPromise = resultPromise;\n            submissionentry.ConditionalPosition = conditionalPosition;\n\n            // add submission to queue\n            pending.Add(submissionentry);\n\n            // if we have a tentative state in use, update it\n            if (this.tentativeStateInternal != null)\n            {\n                try\n                {\n                    Host.UpdateView(this.tentativeStateInternal, logentry);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"UpdateView\", nameof(SubmitInternal), e);\n                }\n            }\n\n            try\n            {\n                Host.OnViewChanged(true, false);\n            }\n            catch (Exception e)\n            {\n                Services.CaughtUserCodeException(\"OnViewChanged\", nameof(SubmitInternal), e);\n            }\n        }\n\n        /// <inheritdoc />\n        public TLogView TentativeView\n        {\n            get\n            {\n                if (stats != null)\n                    stats.EventCounters[\"TentativeViewCalled\"]++;\n\n                if (tentativeStateInternal == null)\n                    CalculateTentativeState();\n\n                return tentativeStateInternal;\n            }\n        }\n\n        /// <inheritdoc />\n        public TLogView ConfirmedView\n        {\n            get\n            {\n                if (stats != null)\n                    stats.EventCounters[\"ConfirmedViewCalled\"]++;\n\n                return LastConfirmedView();\n            }\n        }\n\n        /// <inheritdoc />\n        public int ConfirmedVersion\n        {\n            get\n            {\n                if (stats != null)\n                    stats.EventCounters[\"ConfirmedVersionCalled\"]++;\n\n                return GetConfirmedVersion();\n            }\n        }\n\n        /// <summary>\n        /// Called from network\n        /// </summary>\n        /// <param name=\"payLoad\"></param>\n        /// <returns></returns>\n        public async Task<ILogConsistencyProtocolMessage> OnProtocolMessageReceived(ILogConsistencyProtocolMessage payLoad)\n        {\n            var notificationMessage = payLoad as INotificationMessage;\n\n            if (notificationMessage != null)\n            {\n                Services.Log(LogLevel.Debug, \"NotificationReceived v{0}\", notificationMessage.Version);\n\n                OnNotificationReceived(notificationMessage);\n\n                // poke worker so it will process the notifications\n                worker.Notify();\n\n                return null;\n            }\n            else\n            {\n                //it's a protocol message\n                return await OnMessageReceived(payLoad);\n            }\n        }\n\n        /// <summary>\n        /// method is virtual so subclasses can add their own events\n        /// </summary>\n        public virtual void EnableStatsCollection()\n        {\n\n            stats = new LogConsistencyStatistics()\n            {\n                EventCounters = new Dictionary<string, long>(),\n                StabilizationLatenciesInMsecs = new List<int>()\n            };\n\n            stats.EventCounters.Add(\"TentativeViewCalled\", 0);\n            stats.EventCounters.Add(\"ConfirmedViewCalled\", 0);\n            stats.EventCounters.Add(\"ConfirmedVersionCalled\", 0);\n            stats.EventCounters.Add(\"SubmitCalled\", 0);\n            stats.EventCounters.Add(\"SubmitRangeCalled\", 0);\n            stats.EventCounters.Add(\"TryAppendCalled\", 0);\n            stats.EventCounters.Add(\"TryAppendRangeCalled\", 0);\n            stats.EventCounters.Add(\"ConfirmSubmittedEntriesCalled\", 0);\n            stats.EventCounters.Add(\"SynchronizeNowCalled\", 0);\n\n            stats.EventCounters.Add(\"WritebackEvents\", 0);\n\n            stats.StabilizationLatenciesInMsecs = new List<int>();\n        }\n\n        /// <summary>\n        /// Disable stats collection\n        /// </summary>\n        public void DisableStatsCollection()\n        {\n            stats = null;\n        }\n\n        /// <summary>\n        /// Get states\n        /// </summary>\n        /// <returns></returns>\n        public LogConsistencyStatistics GetStats()\n        {\n            return stats;\n        }\n\n        private void CalculateTentativeState()\n        {\n            // copy the confirmed view\n            this.tentativeStateInternal = Services.DeepCopy(LastConfirmedView());\n\n            // Now apply all operations in pending \n            foreach (var u in this.pending)\n                try\n                {\n                    Host.UpdateView(this.tentativeStateInternal, u.Entry);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"UpdateView\", nameof(CalculateTentativeState), e);\n                }\n        }\n\n        /// <summary>\n        /// Clears the pending operations and resets the tentative state.\n        /// </summary>\n        internal void ResetTentativeState()\n        {\n            this.pending.Clear();\n\n            CalculateTentativeState();\n        }\n\n        private async Task ProcessClearLogRequest()\n        {\n            var clearLogTask = clearLogRequest;\n            if (clearLogTask is null || clearLogTask.Task.IsCompleted)\n                return;\n\n            try\n            {\n                clearLogCancellationToken.ThrowIfCancellationRequested();\n\n                await ClearPrimaryLogAsync(clearLogCancellationToken);\n\n                InitializeConfirmedView(this.InitialState);\n                ResetTentativeState();\n                needRefresh = needInitialRead = false;\n                lastVersionNotified = 0;\n\n                try\n                {\n                    Host.OnViewChanged(true, true);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"OnViewChanged\", nameof(ProcessClearLogRequest), e);\n                }\n\n                clearLogTask.TrySetResult(true);\n            }\n            catch (OperationCanceledException) when (clearLogCancellationToken.IsCancellationRequested)\n            {\n                clearLogTask.TrySetCanceled(clearLogCancellationToken);\n            }\n            catch (Exception exception)\n            {\n                clearLogTask.TrySetException(exception);\n            }\n            finally\n            {\n                if (ReferenceEquals(clearLogRequest, clearLogTask))\n                    clearLogRequest = null;\n            }\n        }\n\n\n        /// <summary>\n        /// batch worker performs reads from and writes to global state.\n        /// only one work cycle is active at any time.\n        /// </summary>\n        internal async Task Work()\n        {\n            await ProcessClearLogRequest();\n\n            Services.Log(LogLevel.Debug, \"<1 ProcessNotifications\");\n\n            var version = GetConfirmedVersion();\n\n            ProcessNotifications();\n\n            Services.Log(LogLevel.Debug, \"<2 NotifyViewChanges\");\n\n            NotifyViewChanges(ref version);\n\n            bool haveToWrite = (pending.Count != 0);\n\n            bool haveToRead = needInitialRead || (needRefresh && !haveToWrite);\n\n            Services.Log(LogLevel.Debug, \"<3 Storage htr={0} htw={1}\", haveToRead, haveToWrite);\n\n            try\n            {\n                if (haveToRead)\n                {\n                    needRefresh = needInitialRead = false; // retrieving fresh version\n\n                    await ReadAsync();\n\n                    NotifyViewChanges(ref version);\n                }\n\n                if (haveToWrite)\n                {\n                    needRefresh = needInitialRead = false; // retrieving fresh version\n\n                    await UpdatePrimary();\n\n                    if (stats != null) stats.EventCounters[\"WritebackEvents\"]++;\n                }\n\n            }\n            catch (Exception e)\n            {\n                // this should never happen - we are supposed to catch and store exceptions \n                // in the correct place (LastPrimaryException or notification trackers)\n                Services.ProtocolError($\"Exception in Worker Cycle: {e}\", true);\n\n            }\n\n            Services.Log(LogLevel.Debug, \"<4 Done\");\n        }\n\n\n        /// <summary>\n        /// This function stores the operations in the pending queue as a batch to the primary.\n        /// Retries until some batch commits or there are no updates left.\n        /// </summary>\n        internal async Task UpdatePrimary()\n        {\n            int version = GetConfirmedVersion();\n\n            while (true)\n            {\n                try\n                {\n                    // find stale conditional updates, remove them, and notify waiters\n                    RemoveStaleConditionalUpdates();\n\n                    if (pending.Count == 0)\n                        return; // no updates to write.\n\n                    // try to write the updates as a batch\n                    var writeResult = await WriteAsync();\n\n                    NotifyViewChanges(ref version, writeResult);\n\n                    // if the batch write failed due to conflicts, retry.\n                    if (writeResult == 0)\n                        continue;\n\n                    try\n                    {\n                        Host.OnViewChanged(false, true);\n                    }\n                    catch (Exception e)\n                    {\n                        Services.CaughtUserCodeException(\"OnViewChanged\", nameof(UpdatePrimary), e);\n                    }\n\n                    // notify waiting promises of the success of conditional updates\n                    NotifyPromises(writeResult, true);\n\n                    // record stabilization time, for statistics\n                    if (stats != null)\n                    {\n                        var timeNow = DateTime.UtcNow;\n                        for (int i = 0; i < writeResult; i++)\n                        {\n                            var latency = timeNow - pending[i].SubmissionTime;\n                            stats.StabilizationLatenciesInMsecs.Add(latency.Milliseconds);\n                        }\n                    }\n\n                    // remove completed updates from queue\n                    pending.RemoveRange(0, writeResult);\n\n                    return;\n                }\n                catch (Exception e)\n                {\n                    // this should never happen - we are supposed to catch and store exceptions \n                    // in the correct place (LastPrimaryException or notification trackers)\n                    Services.ProtocolError($\"Exception in {nameof(UpdatePrimary)}: {e}\", true);\n                }\n            }\n        }\n\n\n        private void NotifyViewChanges(ref int version, int numWritten = 0)\n        {\n            var v = GetConfirmedVersion();\n            bool tentativeChanged = (v != version + numWritten);\n            bool confirmedChanged = (v != version);\n            if (tentativeChanged || confirmedChanged)\n            {\n                tentativeStateInternal = null; // conservative.\n                try\n                {\n                    Host.OnViewChanged(tentativeChanged, confirmedChanged);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"OnViewChanged\", nameof(NotifyViewChanges), e);\n                }\n                version = v;\n            }\n        }\n\n        /// <summary>\n        /// Store the last issue that occurred while reading or updating primary.\n        /// Is null if successful.\n        /// </summary>\n        protected RecordedConnectionIssue LastPrimaryIssue;\n\n\n\n        /// <inheritdoc />\n        public async Task Synchronize()\n        {\n            if (stats != null)\n                stats.EventCounters[\"SynchronizeNowCalled\"]++;\n\n            Services.Log(LogLevel.Debug, \"SynchronizeNowStart\");\n\n            needRefresh = true;\n            await worker.NotifyAndWaitForWorkToBeServiced();\n\n            Services.Log(LogLevel.Debug, \"SynchronizeNowComplete\");\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<TLogEntry> UnconfirmedSuffix\n        {\n            get\n            {\n                return pending.Select(te => te.Entry);\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task ConfirmSubmittedEntries()\n        {\n            if (stats != null)\n                stats.EventCounters[\"ConfirmSubmittedEntriesCalled\"]++;\n\n            Services.Log(LogLevel.Debug, \"ConfirmSubmittedEntriesStart\");\n\n            if (pending.Count != 0)\n                await worker.WaitForCurrentWorkToBeServiced();\n\n            Services.Log(LogLevel.Debug, \"ConfirmSubmittedEntriesEnd\");\n        }\n\n        /// <summary>\n        /// send failure notifications\n        /// </summary>\n        protected void NotifyPromises(int count, bool success)\n        {\n            for (int i = 0; i < count; i++)\n            {\n                var promise = pending[i].ResultPromise;\n                if (promise != null)\n                    promise.SetResult(success);\n            }\n        }\n\n        /// <summary>\n        /// go through updates and remove all the conditional updates that have already failed\n        /// </summary>\n        protected void RemoveStaleConditionalUpdates()\n        {\n            int version = GetConfirmedVersion();\n            bool foundFailedConditionalUpdates = false;\n\n            for (int pos = 0; pos < pending.Count; pos++)\n            {\n                var submissionEntry = pending[pos];\n                if (submissionEntry.ConditionalPosition != unconditional\n                    && (foundFailedConditionalUpdates ||\n                           submissionEntry.ConditionalPosition != (version + pos)))\n                {\n                    foundFailedConditionalUpdates = true;\n                    if (submissionEntry.ResultPromise != null)\n                        submissionEntry.ResultPromise.SetResult(false);\n                }\n            }\n\n            if (foundFailedConditionalUpdates)\n            {\n                pending.RemoveAll(e => e.ConditionalPosition != unconditional);\n                tentativeStateInternal = null;\n                try\n                {\n                    Host.OnViewChanged(true, false);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"OnViewChanged\", nameof(RemoveStaleConditionalUpdates), e);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Base class for submission entries stored in pending queue. \n    /// </summary>\n    /// <typeparam name=\"TLogEntry\">The type of entry for this submission</typeparam>\n    public class SubmissionEntry<TLogEntry>\n    {\n        /// <summary> The log entry that is submitted. </summary>\n        public TLogEntry Entry;\n\n        /// <summary> A timestamp for this submission. </summary>\n        public DateTime SubmissionTime;\n\n        /// <summary> For conditional updates, a promise that resolves once it is known whether the update was successful or not.</summary>\n        public TaskCompletionSource<bool> ResultPromise;\n\n        /// <summary> For conditional updates, the log position at which this update is supposed to be applied. </summary>\n        public int ConditionalPosition;\n    }\n\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Common/RecordedConnectionIssue.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.EventSourcing.Common\n{\n    /// <summary>\n    /// Utility class for recording connection issues.\n    /// It is public, not internal, because it is a useful building block for implementing other consistency providers.\n    /// </summary>\n    public struct RecordedConnectionIssue\n    {\n        /// <summary>\n        /// The recorded connection issue, or null if none\n        /// </summary>\n        public ConnectionIssue Issue { get; private set; }\n\n        /// <summary>\n        /// record a connection issue, filling in timestamps etc.\n        /// and notify the listener\n        /// </summary>\n        /// <param name=\"newIssue\">the connection issue to be recorded</param>\n        /// <param name=\"listener\">the listener for connection issues</param>\n        /// <param name=\"services\">for reporting exceptions in listener</param>\n        public void Record(ConnectionIssue newIssue, IConnectionIssueListener listener, ILogConsistencyProtocolServices services)\n        {\n            newIssue.TimeStamp = DateTime.UtcNow;\n            if (Issue != null)\n            {\n                newIssue.TimeOfFirstFailure = Issue.TimeOfFirstFailure;\n                newIssue.NumberOfConsecutiveFailures = Issue.NumberOfConsecutiveFailures + 1;\n                newIssue.RetryDelay = newIssue.ComputeRetryDelay(Issue.RetryDelay);\n            }\n            else\n            {\n                newIssue.TimeOfFirstFailure = newIssue.TimeStamp;\n                newIssue.NumberOfConsecutiveFailures = 1;\n                newIssue.RetryDelay = newIssue.ComputeRetryDelay(null);\n            }\n\n            Issue = newIssue;\n\n            try\n            {\n                listener.OnConnectionIssue(newIssue);\n            }\n            catch (Exception e)\n            {\n                services.CaughtUserCodeException(\"OnConnectionIssue\", nameof(Record), e);\n            }\n        }\n\n        /// <summary>\n        /// if there is a recorded issue, notify listener and clear it.\n        /// </summary>\n        /// <param name=\"listener\">the listener for connection issues</param>\n        /// <param name=\"services\">for reporting exceptions in listener</param>\n        public void Resolve(IConnectionIssueListener listener, ILogConsistencyProtocolServices services)\n        {\n            if (Issue != null)\n            {\n                try\n                {\n                    listener.OnConnectionIssueResolved(Issue);\n                }\n                catch (Exception e)\n                {\n                    services.CaughtUserCodeException(\"OnConnectionIssueResolved\", nameof(Record), e);\n                }\n                Issue = null;\n            }\n        }\n\n        /// <summary>\n        /// delays if there was an issue in last attempt, for the duration specified by the retry delay\n        /// </summary>\n        /// <returns></returns>\n        public async readonly Task DelayBeforeRetry()\n        {\n            if (Issue == null)\n                return;\n\n            await Task.Delay(Issue.RetryDelay);\n        }\n\n        /// <inheritdoc/>\n        public override readonly string ToString()\n        {\n            if (Issue == null)\n                return \"\";\n            else\n                return Issue.ToString();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Common/StringEncodedWriteVector.cs",
    "content": "﻿namespace Orleans.EventSourcing.Common\n{\n    public static class StringEncodedWriteVector\n    {\n\n        // BitVector of replicas is implemented as a set of replica strings encoded within a string\n        // The bitvector is represented as the set of replica ids whose bit is 1\n        // This set is written as a string that contains the replica ids preceded by a comma each\n        //\n        // Assuming our replicas are named A, B, and BB, then\n        // \"\"     represents    {}        represents 000 \n        // \",A\"   represents    {A}       represents 100 \n        // \",A,B\" represents    {A,B}     represents 110 \n        // \",BB,A,B\" represents {A,B,BB}  represents 111 \n\n        /// <summary>\n        /// Gets one of the bits in writeVector\n        /// </summary>\n        /// <param name=\"writeVector\">The write vector which we want get the bit from</param>\n        /// <param name=\"Replica\">The replica for which we want to look up the bit</param>\n        /// <returns></returns>\n        public static bool GetBit(string writeVector, string Replica)\n        {\n            var pos = writeVector.IndexOf(Replica);\n            return pos != -1 && writeVector[pos - 1] == ',';\n        }\n\n        /// <summary>\n        /// toggle one of the bits in writeVector and return the new value.\n        /// </summary>\n        /// <param name=\"writeVector\">The write vector in which we want to flip the bit</param>\n        /// <param name=\"Replica\">The replica for which we want to flip the bit</param>\n        /// <returns>the state of the bit after flipping it</returns>\n        public static bool FlipBit(ref string writeVector, string Replica)\n        {\n            var pos = writeVector.IndexOf(Replica);\n            if (pos != -1 && writeVector[pos - 1] == ',')\n            {\n                var pos2 = writeVector.IndexOf(',', pos + 1);\n                if (pos2 == -1)\n                    pos2 = writeVector.Length;\n                writeVector = writeVector.Remove(pos - 1, pos2 - pos + 1);\n                return false;\n            }\n            else\n            {\n                writeVector = string.Format(\",{0}{1}\", Replica, writeVector);\n                return true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/CustomStorage/CustomStorageLogConsistencyOptions.cs",
    "content": "﻿\nnamespace Orleans.Configuration\n{\n    public class CustomStorageLogConsistencyOptions\n    {\n        public string PrimaryCluster { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/CustomStorage/ICustomStorageInterface.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.EventSourcing.CustomStorage\n{\n    /// <summary>\n    /// The storage interface exposed by grains that want to use the CustomStorage log-consistency provider\n    /// </summary>\n    /// <typeparam name=\"TState\">The type for the state of the grain.</typeparam>\n    /// <typeparam name=\"TDelta\">The type for delta objects that represent updates to the state.</typeparam>\n    public interface ICustomStorageInterface<TState, TDelta>\n    {\n        /// <summary>\n        /// Reads the current state and version from storage\n        /// (note that the state object may be mutated by the provider, so it must not be shared).\n        /// </summary>\n        /// <returns>the version number and a state object.</returns>\n        Task<KeyValuePair<int,TState>> ReadStateFromStorage();\n\n        /// <summary>\n        /// Applies the given array of deltas to storage, and returns true, if the version in storage matches the expected version. \n        /// Otherwise, does nothing and returns false. If successful, the version of storage must be increased by the number of deltas.\n        /// </summary>\n        /// <returns>true if the deltas were applied, false otherwise</returns>\n        Task<bool> ApplyUpdatesToStorage(IReadOnlyList<TDelta> updates, int expectedVersion);\n\n        /// <summary>\n        /// Clears the stored state in storage.\n        /// </summary>\n        /// <returns>A task that represents the asynchronous clear operation.</returns>\n        Task ClearStoredState() => throw new NotSupportedException();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/CustomStorage/LogConsistencyProvider.cs",
    "content": "using Orleans.Storage;\nusing Orleans.Configuration;\nusing System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.EventSourcing.CustomStorage\n{\n    /// <summary>\n    /// A log-consistency provider that relies on grain-specific custom code for \n    /// reading states from storage, and appending deltas to storage.\n    /// Grains that wish to use this provider must implement the <see cref=\"ICustomStorageInterface{TState, TDelta}\"/>\n    /// interface, to define how state is read and how deltas are written.\n    /// If the provider attribute \"PrimaryCluster\" is supplied in the provider configuration, then only the specified cluster\n    /// accesses storage, and other clusters may not issue updates. \n    /// </summary>\n    public class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        private readonly CustomStorageLogConsistencyOptions options;\n\n        /// <summary>\n        /// Specifies a cluster id of the primary cluster from which to access storage exclusively, null if\n        /// storage should be accessed directly from all clusters.\n        /// </summary>\n        public string PrimaryCluster => options.PrimaryCluster;\n\n        /// <inheritdoc/>\n        public bool UsesStorageProvider => false;\n        \n        public LogConsistencyProvider(CustomStorageLogConsistencyOptions options)\n        {\n            this.options = options;\n        }\n\n        /// <inheritdoc/>\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where TView : class, new()\n            where TEntry : class\n        {\n            return new CustomStorageAdaptor<TView, TEntry>(hostGrain, initialState, services, PrimaryCluster);\n        }\n    }\n\n    public static class LogConsistencyProviderFactory\n    {\n        public static ILogViewAdaptorFactory Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<CustomStorageLogConsistencyOptions>>();\n            return ActivatorUtilities.CreateInstance<LogConsistencyProvider>(services, optionsMonitor.Get(name));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.EventSourcing/CustomStorage/LogViewAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Storage;\nusing Orleans.EventSourcing.Common;\n\nnamespace Orleans.EventSourcing.CustomStorage\n{\n    /// <summary>\n    /// A log consistency adaptor that uses the user-provided storage interface <see cref=\"ICustomStorageInterface{T,E}\"/>. \n    /// This interface must be implemented by any grain that uses this log view adaptor.\n    /// </summary>\n    /// <typeparam name=\"TLogView\">log view type</typeparam>\n    /// <typeparam name=\"TLogEntry\">log entry type</typeparam>\n    internal class CustomStorageAdaptor<TLogView, TLogEntry> : PrimaryBasedLogViewAdaptor<TLogView, TLogEntry, SubmissionEntry<TLogEntry>>\n        where TLogView : class, new()\n        where TLogEntry : class\n    {\n        /// <summary>\n        /// Initialize a new instance of CustomStorageAdaptor class\n        /// </summary>\n        public CustomStorageAdaptor(ILogViewAdaptorHost<TLogView, TLogEntry> host, TLogView initialState,\n            ILogConsistencyProtocolServices services, string primaryCluster)\n            : base(host, initialState, services)\n        {\n            if (!(host is ICustomStorageInterface<TLogView, TLogEntry> customGrainStorage))\n            {\n                throw new BadProviderConfigException(\"Must implement ICustomStorageInterface<TLogView,TLogEntry> for CustomStorageLogView provider\");\n            }\n\n            this.customGrainStorage = customGrainStorage;\n            this.primaryCluster = primaryCluster;\n        }\n\n        private readonly string primaryCluster;\n        private readonly ICustomStorageInterface<TLogView, TLogEntry> customGrainStorage;\n\n        private TLogView cached;\n        private int version;\n\n        /// <inheritdoc/>\n        protected override TLogView LastConfirmedView()\n        {\n            return cached;\n        }\n\n        /// <inheritdoc/>\n        protected override int GetConfirmedVersion()\n        {\n            return version;\n        }\n\n        /// <inheritdoc/>\n        protected override Task ClearPrimaryLogAsync(CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            return this.customGrainStorage.ClearStoredState();\n        }\n\n        /// <inheritdoc/>\n        protected override void InitializeConfirmedView(TLogView initialstate)\n        {\n            cached = initialstate;\n            version = 0;\n        }\n\n        /// <inheritdoc/>\n        protected override bool SupportSubmissions\n        {\n            get\n            {\n                return true;\n            }\n        }\n\n        /// <inheritdoc/>\n        protected override SubmissionEntry<TLogEntry> MakeSubmissionEntry(TLogEntry entry)\n        {\n           // no special tagging is required, thus we create a plain submission entry\n           return new SubmissionEntry<TLogEntry>() { Entry = entry };\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        internal sealed class ReadRequest : ILogConsistencyProtocolMessage\n        {\n            [Id(0)]\n            public int KnownVersion { get; set; }\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        internal sealed class ReadResponse<ViewType> : ILogConsistencyProtocolMessage\n        {\n            [Id(0)]\n            public int Version { get; set; }\n\n            [Id(1)]\n            public ViewType Value { get; set; }\n        }\n\n        /// <inheritdoc/>\n        protected override Task<ILogConsistencyProtocolMessage> OnMessageReceived(ILogConsistencyProtocolMessage payload)\n        {\n            var request = (ReadRequest) payload;\n\n            var response = new ReadResponse<TLogView>() { Version = version };\n\n            // optimization: include value only if version is newer\n            if (version > request.KnownVersion)\n                response.Value = cached;\n\n            return Task.FromResult<ILogConsistencyProtocolMessage>(response);\n        }\n\n        /// <inheritdoc/>\n        protected override async Task ReadAsync()\n        {\n            enter_operation(\"ReadAsync\");\n\n            while (true)\n            {\n                try\n                {\n                    // read from storage\n                    var result = await ((ICustomStorageInterface<TLogView, TLogEntry>)Host).ReadStateFromStorage();\n                    version = result.Key;\n                    cached = result.Value;\n\n                    Services.Log(LogLevel.Debug, \"read success v{0}\", version);\n\n                    LastPrimaryIssue.Resolve(Host, Services);\n\n                    break; // successful\n                }\n                catch (Exception e)\n                {\n                    // unwrap inner exception that was forwarded - helpful for debugging\n                    if ((e as ProtocolTransportException)?.InnerException != null)\n                        e = ((ProtocolTransportException)e).InnerException;\n\n                    LastPrimaryIssue.Record(new ReadFromPrimaryFailed() { Exception = e }, Host, Services);\n                }\n\n                Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n\n                await LastPrimaryIssue.DelayBeforeRetry();\n            }\n\n            exit_operation(\"ReadAsync\");\n        }\n\n        /// <inheritdoc/>\n        protected override async Task<int> WriteAsync()\n        {\n            enter_operation(\"WriteAsync\");\n\n            var updates = GetCurrentBatchOfUpdates().Select(submissionentry => submissionentry.Entry).ToList();\n            bool writesuccessful = false;\n            bool transitionssuccessful = false;\n\n            try\n            {\n                writesuccessful = await ((ICustomStorageInterface<TLogView,TLogEntry>) Host).ApplyUpdatesToStorage(updates, version);\n\n                LastPrimaryIssue.Resolve(Host, Services);\n            }\n            catch (Exception e)\n            {\n                // unwrap inner exception that was forwarded - helpful for debugging\n                if ((e as ProtocolTransportException)?.InnerException != null)\n                    e = ((ProtocolTransportException)e).InnerException;\n\n                LastPrimaryIssue.Record(new UpdatePrimaryFailed() { Exception = e }, Host, Services);\n            }\n\n            if (writesuccessful)\n            {\n                Services.Log(LogLevel.Debug, \"write ({0} updates) success v{1}\", updates.Count, version + updates.Count);\n\n                // now we update the cached state by applying the same updates\n                // in case we encounter any exceptions we will re-read the whole state from storage\n                try\n                {\n                    foreach (var u in updates)\n                    {\n                        version++;\n                        Host.UpdateView(this.cached, u);\n                    }\n\n                    transitionssuccessful = true;\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"UpdateView\", nameof(WriteAsync), e);\n                }\n            }\n\n            if (!writesuccessful || !transitionssuccessful)\n            {\n                Services.Log(LogLevel.Debug, \"{0} failed {1}\", writesuccessful ? \"transitions\" : \"write\", LastPrimaryIssue);\n\n                while (true) // be stubborn until we can re-read the state from storage\n                {\n                    await LastPrimaryIssue.DelayBeforeRetry();\n\n                    try\n                    {\n                        var result = await ((ICustomStorageInterface<TLogView, TLogEntry>)Host).ReadStateFromStorage();\n                        version = result.Key;\n                        cached = result.Value;\n\n                        Services.Log(LogLevel.Debug, \"read success v{0}\", version);\n\n                        LastPrimaryIssue.Resolve(Host, Services);\n\n                        break;\n                    }\n                    catch (Exception e)\n                    {\n                        // unwrap inner exception that was forwarded - helpful for debugging\n                        if ((e as ProtocolTransportException)?.InnerException != null)\n                            e = ((ProtocolTransportException)e).InnerException;\n\n                        LastPrimaryIssue.Record(new ReadFromPrimaryFailed() { Exception = e }, Host, Services);\n                    }\n\n                    Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n                }\n            }\n\n            exit_operation(\"WriteAsync\");\n\n            return writesuccessful ? updates.Count : 0;\n        }\n\n        /// <summary>\n        /// Describes a connection issue that occurred when updating the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class UpdatePrimaryFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"update primary failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// Describes a connection issue that occurred when reading from the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class ReadFromPrimaryFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"read from primary failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// A notification message that is sent to remote instances of this grain after the primary has been\n        /// updated, to let them know the latest version. Contains all the updates that were applied.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        protected internal sealed class UpdateNotificationMessage : INotificationMessage\n        {\n            /// <inheritdoc/>\n            [Id(0)]\n            public int Version { get; set; }\n\n            /// <summary> The list of updates that were applied. </summary>\n            [Id(1)]\n            public List<TLogEntry> Updates { get; set; }\n\n            /// <summary>\n            /// A representation of this notification message suitable for tracing.\n            /// </summary>\n            public override string ToString()\n            {\n                return string.Format(\"v{0} ({1} updates)\", Version, Updates.Count);\n            }\n        }\n   \n        private readonly SortedList<long, UpdateNotificationMessage> notifications = new SortedList<long,UpdateNotificationMessage>();\n\n        /// <inheritdoc/>\n        protected override void OnNotificationReceived(INotificationMessage payload)\n        {\n           var um = payload as UpdateNotificationMessage;\n            if (um != null)\n                notifications.Add(um.Version - um.Updates.Count, um);\n            else\n                base.OnNotificationReceived(payload);\n        }\n\n        /// <inheritdoc/>\n        protected override void ProcessNotifications()\n        {\n\n            // discard notifications that are behind our already confirmed state\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key < version)\n            {\n                Services.Log(LogLevel.Debug, \"discarding notification {0}\", notifications.ElementAt(0).Value);\n                notifications.RemoveAt(0);\n            }\n\n            // process notifications that reflect next global version\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key == version)\n            {\n                var updatenotification = notifications.ElementAt(0).Value;\n                notifications.RemoveAt(0);\n\n                // Apply all operations in pending \n                foreach (var u in updatenotification.Updates)\n                    try\n                    {\n                        Host.UpdateView(cached, u);\n                    }\n                    catch (Exception e)\n                    {\n                        Services.CaughtUserCodeException(\"UpdateView\", nameof(ProcessNotifications), e);\n                    }\n\n                version = updatenotification.Version;\n\n                Services.Log(LogLevel.Debug, \"notification success ({0} updates) v{1}\", updatenotification.Updates.Count, version);\n            }\n\n            Services.Log(LogLevel.Trace, \"unprocessed notifications in queue: {0}\", notifications.Count);\n\n            base.ProcessNotifications();\n        \n        }\n\n        [Conditional(\"DEBUG\")]\n        private void enter_operation(string name)\n        {\n            Services.Log(LogLevel.Trace, \"/-- enter {0}\", name);\n        }\n\n        [Conditional(\"DEBUG\")]\n        private void exit_operation(string name)\n        {\n            Services.Log(LogLevel.Trace, \"\\\\-- exit {0}\", name);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Hosting/CustomStorageSiloBuilderExtensions.cs",
    "content": "\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.EventSourcing;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.EventSourcing.CustomStorage;\nusing Orleans.Configuration;\n\nnamespace Orleans.Hosting\n{\n    public static class CustomStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds a custom storage log consistency provider as default consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddCustomStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder, string primaryCluster = null)\n        {\n            return builder.AddCustomStorageBasedLogConsistencyProvider(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, primaryCluster);\n        }\n\n        /// <summary>\n        /// Adds a custom storage log consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddCustomStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"LogStorage\", string primaryCluster = null)\n        {\n            return builder.ConfigureServices(services => services.AddCustomStorageBasedLogConsistencyProvider(name, primaryCluster));\n        }\n\n        internal static void AddCustomStorageBasedLogConsistencyProvider(this IServiceCollection services, string name, string primaryCluster)\n        {\n            services.AddLogConsistencyProtocolServicesFactory();\n            services.AddOptions<CustomStorageLogConsistencyOptions>(name)\n                    .Configure(options => options.PrimaryCluster = primaryCluster);\n            services.ConfigureNamedOptionForLogging<CustomStorageLogConsistencyOptions>(name)\n                .AddKeyedSingleton<ILogViewAdaptorFactory>(name, (sp, key) => LogConsistencyProviderFactory.Create(sp, key as string))\n                .TryAddSingleton<ILogViewAdaptorFactory>(sp => sp.GetKeyedService<ILogViewAdaptorFactory>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Hosting/LogConsistencyProtocolSiloBuilderExtensions.cs",
    "content": "\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.EventSourcing;\nusing Orleans.Runtime;\nusing Orleans.Runtime.LogConsistency;\n\nnamespace Orleans.Hosting\n{\n    internal static class LogConsistencyProtocolSiloBuilderExtensions\n    {\n        internal static IServiceCollection AddLogConsistencyProtocolServicesFactory(this IServiceCollection services)\n        {\n            services.TryAddSingleton<Factory<IGrainContext, ILogConsistencyProtocolServices>>(serviceProvider =>\n            {\n                var factory = ActivatorUtilities.CreateFactory(typeof(ProtocolServices), new[] { typeof(IGrainContext) });\n                return arg1 => (ILogConsistencyProtocolServices)factory(serviceProvider, new object[] { arg1 });\n            });\n\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.EventSourcing/Hosting/LogStorageSiloBuilderExtensions.cs",
    "content": "\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.EventSourcing;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.EventSourcing.LogStorage;\n\nnamespace Orleans.Hosting\n{\n    public static class LogStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds a log storage log consistency provider as default consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddLogStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder)\n        {\n            return builder.AddLogStorageBasedLogConsistencyProvider(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME);\n        }\n\n        /// <summary>\n        /// Adds a log storage log consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddLogStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"LogStorage\")\n        {\n            return builder.ConfigureServices(services => services.AddLogStorageBasedLogConsistencyProvider(name));\n        }\n\n        internal static IServiceCollection AddLogStorageBasedLogConsistencyProvider(this IServiceCollection services, string name)\n        {\n            services.AddLogConsistencyProtocolServicesFactory();\n            services.TryAddSingleton<ILogViewAdaptorFactory>(sp => sp.GetKeyedService<ILogViewAdaptorFactory>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n            return services.AddKeyedSingleton<ILogViewAdaptorFactory, LogConsistencyProvider>(name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Hosting/StateStorageSiloBuilderExtensions.cs",
    "content": "\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.EventSourcing;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.EventSourcing.StateStorage;\n\nnamespace Orleans.Hosting\n{\n    public static class StateStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds a state storage log consistency provider as default consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddStateStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder)\n        {\n            return builder.AddStateStorageBasedLogConsistencyProvider(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME);\n        }\n\n        /// <summary>\n        /// Adds a state storage log consistency provider\"/>\n        /// </summary>\n        public static ISiloBuilder AddStateStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"StateStorage\")\n        {\n            return builder.ConfigureServices(services => services.AddStateStorageBasedLogConsistencyProvider(name));\n        }\n\n        internal static IServiceCollection AddStateStorageBasedLogConsistencyProvider(this IServiceCollection services, string name)\n        {\n            services.AddLogConsistencyProtocolServicesFactory();\n            services.TryAddSingleton<ILogViewAdaptorFactory>(sp => sp.GetKeyedService<ILogViewAdaptorFactory>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n            return services.AddKeyedSingleton<ILogViewAdaptorFactory, LogConsistencyProvider>(name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/JournaledGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Storage;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// A base class for log-consistent grains using standard event-sourcing terminology.\n    /// All operations are reentrancy-safe.\n    /// </summary>\n    /// <typeparam name=\"TGrainState\">The type for the grain state, i.e. the aggregate view of the event log.</typeparam>\n    public abstract class JournaledGrain<TGrainState> : JournaledGrain<TGrainState, object>\n        where TGrainState : class, new()\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JournaledGrain{TGrainState}\"/> class.\n        /// </summary>\n        protected JournaledGrain() { }\n    }\n\n    /// <summary>\n    /// A base class for log-consistent grains using standard event-sourcing terminology.\n    /// All operations are reentrancy-safe.\n    /// </summary>\n    /// <typeparam name=\"TGrainState\">The type for the grain state, i.e. the aggregate view of the event log.</typeparam>\n    /// <typeparam name=\"TEventBase\">The common base class for the events</typeparam>\n    public abstract class JournaledGrain<TGrainState,TEventBase> :\n        LogConsistentGrain<TGrainState>,\n        ILogConsistencyProtocolParticipant,\n        ILogViewAdaptorHost<TGrainState, TEventBase>\n        where TGrainState : class, new()\n        where TEventBase: class\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JournaledGrain{TGrainState, TEventBase}\"/> class.\n        /// </summary>\n        protected JournaledGrain() { }\n\n        /// <summary>\n        /// Raises an event.\n        /// </summary>\n        /// <param name=\"event\">Event to raise.</param>\n        protected virtual void RaiseEvent<TEvent>(TEvent @event) \n            where TEvent : TEventBase\n        {\n            if (@event == null) throw new ArgumentNullException(nameof(@event));\n\n            LogViewAdaptor.Submit(@event);\n        }\n\n        /// <summary>\n        /// Raise multiple events, as an atomic sequence.\n        /// </summary>\n        /// <param name=\"events\">Events to raise.</param>\n        protected virtual void RaiseEvents<TEvent>(IEnumerable<TEvent> events) \n            where TEvent : TEventBase\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events));\n\n            LogViewAdaptor.SubmitRange((IEnumerable<TEventBase>) events);\n        }\n\n        /// <summary>\n        /// Raise an event conditionally. \n        /// Succeeds only if there are no conflicts, that is, no other events were raised in the meantime.\n        /// </summary>\n        /// <param name=\"event\">Event to raise.</param>\n        /// <returns><see langword=\"true\"/> if successful, <see langword=\"false\"/> if there was a conflict.</returns>\n        protected virtual Task<bool> RaiseConditionalEvent<TEvent>(TEvent @event)\n            where TEvent : TEventBase\n        {\n            if (@event == null) throw new ArgumentNullException(nameof(@event));\n\n            return LogViewAdaptor.TryAppend(@event);\n        }\n\n        /// <summary>\n        /// Raise multiple events, as an atomic sequence, conditionally. \n        /// Succeeds only if there are no conflicts, that is, no other events were raised in the meantime.\n        /// </summary>\n        /// <param name=\"events\">Events to raise</param>\n        /// <returns><see langword=\"true\"/> if successful, <see langword=\"false\"/> if there was a conflict.</returns>\n        protected virtual Task<bool> RaiseConditionalEvents<TEvent>(IEnumerable<TEvent> events)\n            where TEvent : TEventBase\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events));\n            return LogViewAdaptor.TryAppendRange((IEnumerable<TEventBase>) events);\n        }\n\n        /// <summary>\n        /// Gets the current confirmed state. \n        /// Includes only confirmed events.\n        /// </summary>\n        protected TGrainState State\n        {\n            get { return this.LogViewAdaptor.ConfirmedView; }\n        }\n\n        /// <summary>\n        /// Gets the version of the current confirmed state. \n        /// Equals the total number of confirmed events.\n        /// </summary>\n        protected int Version\n        {\n            get { return this.LogViewAdaptor.ConfirmedVersion; }\n        }\n\n        /// <summary>\n        /// Called whenever the tentative state may have changed due to local or remote events.\n        /// <para>Override this to react to changes of the state.</para>\n        /// </summary>\n        protected virtual void OnTentativeStateChanged()\n        {\n        }\n\n        /// <summary>\n        /// Gets the current tentative state.\n        /// Includes both confirmed and unconfirmed events.\n        /// </summary>\n        protected TGrainState TentativeState\n        {\n            get { return this.LogViewAdaptor.TentativeView; }\n        }\n\n        /// <summary>\n        /// Called after the confirmed state may have changed (i.e. the confirmed version number is larger).\n        /// <para>Override this to react to changes of the confirmed state.</para>\n        /// </summary>\n        protected virtual void OnStateChanged()\n        {\n            // overridden by journaled grains that want to react to state changes\n        }\n\n        /// <summary>\n        /// Waits until all previously raised events have been confirmed. \n        /// <para>await this after raising one or more events, to ensure events are persisted before proceeding, or to guarantee strong consistency (linearizability) even if there are multiple instances of this grain</para>\n        /// </summary>\n        /// <returns>a task that completes once the events have been confirmed.</returns>\n        protected Task ConfirmEvents()\n        {\n            return LogViewAdaptor.ConfirmSubmittedEntries();\n        }\n\n        /// <summary>\n        /// Retrieves the latest state now, and confirms all previously raised events. \n        /// Effectively, this enforces synchronization with the global state.\n        /// <para>Await this before reading the state to ensure strong consistency (linearizability) even if there are multiple instances of this grain</para>\n        /// </summary>\n        /// <returns>a task that completes once the log has been refreshed and the events have been confirmed.</returns>\n        protected Task RefreshNow()\n        {\n            return LogViewAdaptor.Synchronize();\n        }\n\n        /// <summary>\n        /// Returns the current queue of unconfirmed events.\n        /// </summary>\n        public IEnumerable<TEventBase> UnconfirmedEvents\n        {\n            get { return LogViewAdaptor.UnconfirmedSuffix; }\n        }\n\n        /// <summary>\n        /// By default, upon activation, the journaled grain waits until it has loaded the latest\n        /// view from storage. Subclasses can override this behavior,\n        /// and skip the wait if desired.\n        /// </summary>\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return LogViewAdaptor.Synchronize();\n        }\n\n        /// <summary>\n        /// Retrieves a segment of the confirmed event sequence, possibly from storage. \n        /// Throws <see cref=\"NotSupportedException\"/> if the events are not available to read.\n        /// Whether events are available, and for how long, depends on the providers used and how they are configured.\n        /// </summary>\n        /// <param name=\"fromVersion\">the position of the event sequence from which to start</param>\n        /// <param name=\"toVersion\">the position of the event sequence on which to end</param>\n        /// <returns>a task which returns the sequence of events between the two versions</returns>\n        protected Task<IReadOnlyList<TEventBase>> RetrieveConfirmedEvents(int fromVersion, int toVersion)\n        {\n            if (fromVersion < 0)\n                throw new ArgumentException(\"invalid range\", nameof(fromVersion));\n            if (toVersion < fromVersion || toVersion > LogViewAdaptor.ConfirmedVersion)\n                throw new ArgumentException(\"invalid range\", nameof(toVersion));\n\n            return LogViewAdaptor.RetrieveLogSegment(fromVersion, toVersion);\n        }\n\n        /// <summary>\n        /// Clears the log of all confirmed events. Reset the state to the initial state, and discards all unconfirmed events.\n        /// Throws <see cref=\"NotSupportedException\"/> if the log cannot be cleared.\n        /// </summary>\n        protected Task ClearLogAsync(CancellationToken cancellationToken = default)\n        { \n            return LogViewAdaptor.ClearLogAsync(cancellationToken);\n        }\n\n        /// <summary>\n        /// Called when the underlying persistence or replication protocol is running into some sort of connection trouble.\n        /// <para>Override this to monitor the health of the log-consistency protocol and/or\n        /// to customize retry delays.\n        /// Any exceptions thrown are caught and logged by the <see cref=\"ILogViewAdaptorFactory\"/>.</para>\n        /// </summary>\n        /// <returns>The time to wait before retrying</returns>\n        protected virtual void OnConnectionIssue(ConnectionIssue issue)\n        {\n        }\n\n        /// <summary>\n        /// Called when a previously reported connection issue has been resolved.\n        /// <para>Override this to monitor the health of the log-consistency protocol. \n        /// Any exceptions thrown are caught and logged by the <see cref=\"ILogViewAdaptorFactory\"/>.</para>\n        /// </summary>\n        protected virtual void OnConnectionIssueResolved(ConnectionIssue issue)\n        {\n        }\n\n        /// <inheritdoc />\n        protected void EnableStatsCollection()\n        {\n            LogViewAdaptor.EnableStatsCollection();\n        }\n\n        /// <inheritdoc />\n        protected void DisableStatsCollection()\n        {\n            LogViewAdaptor.DisableStatsCollection();\n        }\n\n        /// <inheritdoc />\n        protected LogConsistencyStatistics GetStats()\n        {\n            return LogViewAdaptor.GetStats();\n        }\n\n        /// <summary>\n        /// Defines how to apply events to the state. Unless it is overridden in the subclass, it calls\n        /// a dynamic \"Apply\" function on the state, with the event as a parameter.\n        /// All exceptions thrown by this method are caught and logged by the log view provider.\n        /// <para>Override this to customize how to transition the state for a given event.</para>\n        /// </summary>\n        /// <param name=\"state\">The state.</param>\n        /// <param name=\"event\">The event.</param>\n        protected virtual void TransitionState(TGrainState state, TEventBase @event)\n        {\n            dynamic s = state;\n            dynamic e = @event;\n            s.Apply(e);\n        }\n\n        /// <summary>\n        /// Gets the adaptor for the log-consistency protocol, which is installed by the log-consistency provider.\n        /// </summary>\n        internal ILogViewAdaptor<TGrainState, TEventBase> LogViewAdaptor { get; private set; }\n\n        /// <summary>\n        /// Called right after grain is constructed, to install the adaptor.\n        /// The log-consistency provider contains a factory method that constructs the adaptor with chosen types for this grain\n        /// </summary>\n        protected override void InstallAdaptor(ILogViewAdaptorFactory factory, object initialState, string graintypename, IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n        {\n            // call the log consistency provider to construct the adaptor, passing the type argument\n            LogViewAdaptor = factory.MakeLogViewAdaptor<TGrainState, TEventBase>(this, (TGrainState)initialState, graintypename, grainStorage, services);\n        }\n\n        /// <summary>\n        /// If there is no log-consistency provider specified, store versioned state using default storage provider\n        /// </summary>\n        protected override ILogViewAdaptorFactory DefaultAdaptorFactory\n        {\n            get\n            {\n                return new StateStorage.DefaultAdaptorFactory();\n            }\n        }\n\n        /// <summary>\n        /// Called by adaptor to update the view when entries are appended.\n        /// </summary>\n        /// <param name=\"view\">The log view.</param>\n        /// <param name=\"entry\">The entry.</param>\n        void ILogViewAdaptorHost<TGrainState, TEventBase>.UpdateView(TGrainState view, TEventBase entry)\n        {\n            TransitionState(view, entry);\n        }\n\n        /// <summary>\n        /// Notify log view adaptor of activation (called before user-level OnActivate)\n        /// </summary>\n        async Task ILogConsistencyProtocolParticipant.PreActivateProtocolParticipant()\n        {\n            await LogViewAdaptor.PreOnActivate();\n        }\n\n        /// <summary>\n        /// Notify log view adaptor of activation (called after user-level OnActivate)\n        /// </summary>\n        async Task ILogConsistencyProtocolParticipant.PostActivateProtocolParticipant()\n        {\n            await LogViewAdaptor.PostOnActivate();\n        }\n\n        /// <summary>\n        /// Notify log view adaptor of deactivation\n        /// </summary>\n        Task ILogConsistencyProtocolParticipant.DeactivateProtocolParticipant()\n        {\n            return LogViewAdaptor.PostOnDeactivate();\n        }\n\n        /// <summary>\n        /// Called by adaptor on state change. \n        /// </summary>\n        void ILogViewAdaptorHost<TGrainState, TEventBase>.OnViewChanged(bool tentative, bool confirmed)\n        {\n            if (tentative)\n                OnTentativeStateChanged();\n            if (confirmed)\n                OnStateChanged();\n        }\n\n        /// <summary>\n        /// called by adaptor on connection issues. \n        /// </summary>\n        void IConnectionIssueListener.OnConnectionIssue(ConnectionIssue connectionIssue)\n        {\n            OnConnectionIssue(connectionIssue);\n        }\n\n        /// <summary>\n        /// Called by adaptor when a connection issue is resolved. \n        /// </summary>\n        void IConnectionIssueListener.OnConnectionIssueResolved(ConnectionIssue connectionIssue)\n        {\n            OnConnectionIssueResolved(connectionIssue);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ConnectionIssues.cs",
    "content": "using System;\n\nnamespace Orleans.EventSourcing\n{\n\n    /// <summary>\n    /// Represents information about connection issues encountered inside log consistency protocols.\n    /// It is used both inside the protocol to track retry loops, and is made visible to users \n    /// who want to monitor their log-consistent grains for communication issues.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class ConnectionIssue\n    {\n        /// <summary>\n        /// The UTC timestamp of the last time at which the issue was observed\n        /// </summary>\n        [Id(0)]\n        public DateTime TimeStamp { get; set; }\n\n        /// <summary>\n        /// The UTC timestamp of the first time we observed this issue\n        /// </summary>\n        [Id(1)]\n        public DateTime TimeOfFirstFailure { get; set; }\n\n        /// <summary>\n        /// The number of times we have observed this issue since the first failure\n        /// </summary>\n        [Id(2)]\n        public int NumberOfConsecutiveFailures { get; set; }\n\n        /// <summary>\n        /// The delay we are waiting before the next retry\n        /// </summary>\n        [Id(3)]\n        public TimeSpan RetryDelay { get; set; }\n\n        /// <summary>\n        /// Computes the retry delay based on the rest of the information. Is overridden by subclasses\n        /// that represent specific categories of issues.\n        /// </summary>\n        /// <param name=\"previous\">The previously used retry delay</param>\n        /// <returns></returns>\n        public abstract TimeSpan ComputeRetryDelay(TimeSpan? previous);\n    }\n}"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/IConnectionIssueListener.cs",
    "content": "namespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// An interface that is implemented by log-consistent grains using virtual protected methods\n    /// that can be overridden by users, in order to monitor the connection issues.\n    /// </summary>\n    public interface IConnectionIssueListener\n    {\n        /// <summary>\n        /// Called when running into some sort of connection trouble.\n        /// The called code can modify the retry delay if desired, to change the default.\n        /// </summary>\n        void OnConnectionIssue(ConnectionIssue connectionIssue);\n\n        /// <summary>\n        /// Called when a previously reported connection issue has been resolved.\n        /// </summary>\n        void OnConnectionIssueResolved(ConnectionIssue connectionIssue);\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogConsistencyDiagnostics.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Interface for diagnostics.\n    /// </summary>\n    public interface ILogConsistencyDiagnostics\n    {\n        /// <summary>Turns on the statistics collection for this log-consistent grain.</summary>\n        void EnableStatsCollection();\n\n        /// <summary>Turns off the statistics collection for this log-consistent grain.</summary>\n        void DisableStatsCollection();\n\n        /// <summary>Gets the collected statistics for this log-consistent grain.</summary>\n        LogConsistencyStatistics GetStats();\n\n    }\n\n    /// <summary>\n    /// A collection of statistics for grains using log-consistency. See <see cref=\"LogConsistentGrain{T}\"/>\n    /// </summary>\n    public class LogConsistencyStatistics\n    {\n        /// <summary>\n        /// A map from event names to event counts\n        /// </summary>\n        public Dictionary<string, long> EventCounters;\n        /// <summary>\n        /// A list of all measured stabilization latencies\n        /// </summary>\n        public List<int> StabilizationLatenciesInMsecs;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogConsistencyProtocolGateway.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.EventSourcing;\nusing Orleans.Runtime;\n\nnamespace Orleans.SystemTargetInterfaces\n{\n    /// <summary>\n    /// The  protocol gateway is a relay that forwards incoming protocol messages from other clusters\n    /// to the appropriate grain in this cluster.\n    /// </summary>\n    internal interface ILogConsistencyProtocolGateway : ISystemTarget\n    {\n        Task<ILogConsistencyProtocolMessage> RelayMessage(GrainId id, ILogConsistencyProtocolMessage payload);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogConsistencyProtocolServices.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Functionality for use by log view adaptors that use custom consistency or replication protocols.\n    /// Abstracts communication between replicas of the log-consistent grain in different clusters.\n    /// </summary>\n    public interface ILogConsistencyProtocolServices\n    {\n        /// <summary>\n        /// The ID for this grain.\n        /// </summary>\n        GrainId GrainId { get;  }\n\n        /// <summary>\n        /// Copies the provided argument.\n        /// </summary>\n        T DeepCopy<T>(T value);\n\n        /// <summary>\n        /// The id of this cluster. Returns \"I\" if no multi-cluster network is present.\n        /// </summary>\n        /// <returns></returns>\n        string MyClusterId { get; }\n\n        /// <summary>\n        /// Log an error that occurred in a log-consistency protocol.\n        /// </summary>\n        void ProtocolError(string msg, bool throwexception);\n\n        /// <summary>\n        /// Log an exception that was caught in the log-consistency protocol.\n        /// </summary> \n        void CaughtException(string where, Exception e);\n\n        /// <summary>\n        /// Log an exception that occurred in user code, for some callback\n        /// </summary>\n        /// <param name=\"callback\">The name of the callback</param>\n        /// <param name=\"where\">The context from which the callback was called</param>\n        /// <param name=\"e\">The caught exception</param>\n        void CaughtUserCodeException(string callback, string where, Exception e);\n\n        /// <summary> Output the specified message at the specified log level. </summary>\n        void Log(LogLevel level, string format, params object[] args);\n    }\n\n\n\n    /// <summary>\n    /// Exception thrown by protocol messaging layer.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ProtocolTransportException : OrleansException\n    {\n        public ProtocolTransportException()\n        { }\n        public ProtocolTransportException(string msg)\n            : base(msg)\n        { }\n        public ProtocolTransportException(string msg, Exception exc)\n            : base(msg, exc)\n        { }\n\n        [Obsolete]\n        protected ProtocolTransportException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        { }\n\n        public override string ToString()\n        {\n            if (InnerException != null)\n                return $\"ProtocolTransportException: {InnerException}\";\n            else\n                return Message;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogViewAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// A log view adaptor is the storage interface for <see cref=\"LogConsistentGrain{T}\"/>, whose state is defined as a log view. \n    ///<para>\n    /// There is one adaptor per grain, which is installed by <see cref=\"ILogViewAdaptorFactory\"/> when the grain is activated.\n    ///</para>\n    /// </summary>\n    /// <typeparam name=\"TLogView\"> Type for the log view </typeparam>\n    /// <typeparam name=\"TLogEntry\"> Type for the log entry </typeparam>\n    public interface ILogViewAdaptor<TLogView, TLogEntry> :\n          ILogViewRead<TLogView, TLogEntry>,\n          ILogViewUpdate<TLogEntry>,\n          ILogConsistencyDiagnostics\n        where TLogView : new()\n    {\n        /// <summary>Called during activation, right before the user-defined <see cref=\"Grain.OnActivateAsync(CancellationToken)\"/>.</summary>\n        Task PreOnActivate();\n\n        /// <summary>Called during activation, right after the user-defined <see cref=\"Grain.OnActivateAsync(CancellationToken)\"/>..</summary>\n        Task PostOnActivate();\n\n        /// <summary>Called during deactivation, right after the user-defined <see cref=\"Grain.OnDeactivateAsync(DeactivationReason, CancellationToken)\"/>.</summary>\n        Task PostOnDeactivate();\n    }\n\n    /// <summary>\n    /// Interface for reading the log view.\n    /// </summary>\n    /// <typeparam name=\"TView\">The type of the view (state of the grain).</typeparam>\n    /// <typeparam name=\"TLogEntry\">The type of log entries.</typeparam>\n    public interface ILogViewRead<TView, TLogEntry>\n    {\n        /// <summary>\n        /// Local, tentative view of the log (reflecting both confirmed and unconfirmed entries)\n        /// </summary>\n        TView TentativeView { get; }\n\n        /// <summary>\n        /// Confirmed view of the log (reflecting only confirmed entries)\n        /// </summary>\n        TView ConfirmedView { get; }\n\n        /// <summary>\n        /// The length of the confirmed prefix of the log\n        /// </summary>\n        int ConfirmedVersion { get; }\n\n        /// <summary>\n        /// A list of the submitted entries that do not yet appear in the confirmed prefix.\n        /// </summary>\n        IEnumerable<TLogEntry> UnconfirmedSuffix { get; }\n\n        /// <summary>\n        /// Attempt to retrieve a segment of the log, possibly from storage. Throws <see cref=\"NotSupportedException\"/> if\n        /// the log cannot be read, which depends on the providers used and how they are configured.\n        /// </summary>\n        /// <param name=\"fromVersion\">the start position </param>\n        /// <param name=\"toVersion\">the end position</param>\n        /// <returns>a </returns>\n        Task<IReadOnlyList<TLogEntry>> RetrieveLogSegment(int fromVersion, int toVersion);\n\n    }\n\n    /// <summary>\n    /// Interface for updating the log.\n    /// </summary>\n    /// <typeparam name=\"TLogEntry\">The type of log entries.</typeparam>\n    public interface ILogViewUpdate<TLogEntry>\n    {\n        /// <summary>\n        /// Submit a single log entry to be appended to the global log,\n        /// either at the current or at any later position.\n        /// </summary>\n        void Submit(TLogEntry entry);\n\n        /// <summary>\n        /// Submit a range of log entries to be appended atomically to the global log,\n        /// either at the current or at any later position.\n        /// </summary>\n        void SubmitRange(IEnumerable<TLogEntry> entries);\n\n        /// <summary>\n        /// Try to append a single log entry at the current position of the log.\n        /// </summary>\n        /// <returns>true if the entry was appended successfully, or false \n        /// if there was a concurrency conflict (i.e. some other entries were previously appended).\n        /// </returns>\n        Task<bool> TryAppend(TLogEntry entry);\n\n        /// <summary>\n        /// Try to append a range of log entries atomically at the current position of the log.\n        /// </summary>\n        /// <returns>true if the entries were appended successfully, or false \n        /// if there was a concurrency conflict (i.e. some other entries were previously appended).\n        /// </returns>\n        Task<bool> TryAppendRange(IEnumerable<TLogEntry> entries);\n\n        /// <summary>\n        /// Confirm all submitted entries.\n        ///<para>Waits until all previously submitted entries appear in the confirmed prefix of the log.</para>\n        /// </summary>\n        /// <returns>A task that completes after all entries are confirmed.</returns>\n        Task ConfirmSubmittedEntries();\n\n        /// <summary>\n        /// Get the latest log view and confirm all submitted entries.\n        ///<para>Waits until all previously submitted entries appear in the confirmed prefix of the log, and forces a refresh of the confirmed prefix.</para>\n        /// </summary>\n        /// <returns>A task that completes after getting the latest version and confirming all entries.</returns>\n        Task Synchronize();\n\n        /// <summary>\n        /// Clear the log stream completely. Throws <see cref=\"NotSupportedException\"/> if\n        /// the log stream does not support clearing.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token to cancel the operation.</param>\n        /// <returns>A task that represents the asynchronous clear operation.</returns>\n        Task ClearLogAsync(CancellationToken cancellationToken)\n        {\n            throw new NotSupportedException($\"The operation {nameof(ClearLogAsync)} is not supported by this implementation of {nameof(ILogViewUpdate<TLogEntry>)}.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogViewAdaptorFactory.cs",
    "content": "\nusing Orleans.Storage;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Interface to be implemented for a log-view adaptor factory\n    /// </summary>\n    public interface ILogViewAdaptorFactory  \n    {\n        /// <summary> Returns true if a storage provider is required for constructing adaptors. </summary>\n        bool UsesStorageProvider { get; }\n\n        /// <summary>\n        /// Constructs a <see cref=\"ILogViewAdaptor{TLogView,TLogEntry}\"/> to be installed in the given host grain.\n        /// </summary>\n        /// <typeparam name=\"TLogView\">The type of the view</typeparam>\n        /// <typeparam name=\"TLogEntry\">The type of the log entries</typeparam>\n        /// <param name=\"hostGrain\">The grain that is hosting this adaptor</param>\n        /// <param name=\"initialState\">The initial state for this view</param>\n        /// <param name=\"grainTypeName\">The type name of the grain</param>\n        /// <param name=\"grainStorage\">Storage provider</param>\n        /// <param name=\"services\">Runtime services for multi-cluster coherence protocols</param>\n        ILogViewAdaptor<TLogView, TLogEntry> MakeLogViewAdaptor<TLogView, TLogEntry>(\n            ILogViewAdaptorHost<TLogView, TLogEntry> hostGrain,\n            TLogView initialState,\n            string grainTypeName,\n            IGrainStorage grainStorage,\n            ILogConsistencyProtocolServices services)\n\n            where TLogView : class, new()\n            where TLogEntry : class;\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ILogViewAdaptorHost.cs",
    "content": "namespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Interface implemented by all grains which use log-view consistency\n    /// It gives the log view adaptor access to grain-specific information and callbacks.\n    /// </summary>\n    /// <typeparam name=\"TLogView\">type of the log view</typeparam>\n    /// <typeparam name=\"TLogEntry\">type of log entries</typeparam>\n    public interface ILogViewAdaptorHost<TLogView, TLogEntry> : IConnectionIssueListener\n    {\n        /// <summary>\n        /// Implementation of view transitions. \n        /// Any exceptions thrown will be caught and logged as a warning./>.\n        /// </summary>\n        void UpdateView(TLogView view, TLogEntry entry);\n\n        /// <summary>\n        /// Notifies the host grain about state changes. \n        /// Called by <see cref=\"ILogViewAdaptor{TLogView,TLogEntry}\"/> whenever the tentative or confirmed state changes.\n        /// Implementations may vary as to whether and how much they batch change notifications.\n        /// Any exceptions thrown will be caught and logged as a warning./>.\n        /// </summary>\n        void OnViewChanged(bool tentative, bool confirmed);\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/IProtocolParticipant.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Grain interface for grains that participate in multi-cluster log-consistency protocols.\n    /// </summary>\n    public interface ILogConsistencyProtocolParticipant  : IGrain  \n    {\n        /// <summary>\n        /// Called immediately before the user-level OnActivateAsync, on same scheduler.\n        /// </summary>\n        /// <returns></returns>\n        Task PreActivateProtocolParticipant();\n\n        /// <summary>\n        /// Called immediately after the user-level OnActivateAsync, on same scheduler.\n        /// </summary>\n        /// <returns></returns>\n        Task PostActivateProtocolParticipant();\n\n        /// <summary>\n        /// Called immediately after the user-level OnDeactivateAsync, on same scheduler.\n        /// </summary>\n        /// <returns></returns>\n        Task DeactivateProtocolParticipant();\n    }\n\n    /// <summary>\n    /// interface to mark classes that represent protocol messages.\n    /// All such classes must be serializable.\n    /// </summary>\n    public interface ILogConsistencyProtocolMessage\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/LogConsistentGrain.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.Providers;\n\nnamespace Orleans.EventSourcing\n{\n    /// <summary>\n    /// Base class for all grains that use log-consistency for managing  the state.\n    /// It is the equivalent of <see cref=\"Grain{T}\"/> for grains using log-consistency.\n    /// (SiloAssemblyLoader uses it to extract type)\n    /// </summary>\n    /// <typeparam name=\"TView\">The type of the view</typeparam>\n    public abstract class LogConsistentGrain<TView> : Grain, ILifecycleParticipant<IGrainLifecycle>\n    {\n        /// <summary>\n        /// called right after grain construction to install the log view adaptor\n        /// </summary>\n        /// <param name=\"factory\"> The adaptor factory to use </param>\n        /// <param name=\"state\"> The initial state of the view </param>\n        /// <param name=\"grainTypeName\"> The type name of the grain </param>\n        /// <param name=\"grainStorage\"> The grain storage, if needed </param>\n        /// <param name=\"services\"> Protocol services </param>\n        protected abstract void InstallAdaptor(ILogViewAdaptorFactory factory, object state, string grainTypeName, IGrainStorage grainStorage, ILogConsistencyProtocolServices services);\n\n        /// <summary>\n        /// Gets the default adaptor factory to use, or null if there is no default\n        /// (in which case user MUST configure a consistency provider)\n        /// </summary>\n        protected abstract ILogViewAdaptorFactory DefaultAdaptorFactory { get; }\n\n        public virtual void Participate(IGrainLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<LogConsistentGrain<TView>>(GrainLifecycleStage.SetupState, OnSetupState, OnDeactivateState);\n            if (this is ILogConsistencyProtocolParticipant)\n            {\n                lifecycle.Subscribe<LogConsistentGrain<TView>>(GrainLifecycleStage.Activate - 1, PreActivate);\n                lifecycle.Subscribe<LogConsistentGrain<TView>>(GrainLifecycleStage.Activate + 1, PostActivate);\n            }\n        }\n\n        private async Task OnDeactivateState(CancellationToken ct)\n        {\n            if (this is ILogConsistencyProtocolParticipant participant)\n            {\n                await participant.DeactivateProtocolParticipant();\n            }\n        }\n\n        private Task OnSetupState(CancellationToken ct)\n        {\n            if (ct.IsCancellationRequested) return Task.CompletedTask;\n            IGrainContextAccessor grainContextAccessor = this.ServiceProvider.GetRequiredService<IGrainContextAccessor>();\n            Factory<IGrainContext, ILogConsistencyProtocolServices> protocolServicesFactory = this.ServiceProvider.GetRequiredService<Factory<IGrainContext, ILogConsistencyProtocolServices>>();\n            var grainContext = grainContextAccessor.GrainContext;\n            ILogViewAdaptorFactory consistencyProvider = SetupLogConsistencyProvider(grainContext);\n            IGrainStorage grainStorage = consistencyProvider.UsesStorageProvider ? GrainStorageHelpers.GetGrainStorage(grainContext?.GrainInstance.GetType(), this.ServiceProvider) : null;\n            InstallLogViewAdaptor(grainContext, protocolServicesFactory, consistencyProvider, grainStorage);\n            return Task.CompletedTask;\n        }\n\n        private async Task PreActivate(CancellationToken ct)\n        {\n            await ((ILogConsistencyProtocolParticipant)this).PreActivateProtocolParticipant();\n        }\n\n        private async Task PostActivate(CancellationToken ct)\n        {\n            await ((ILogConsistencyProtocolParticipant)this).PostActivateProtocolParticipant();\n        }\n\n        private void InstallLogViewAdaptor(\n            IGrainContext grainContext,\n            Factory<IGrainContext, ILogConsistencyProtocolServices> protocolServicesFactory,\n            ILogViewAdaptorFactory factory,\n            IGrainStorage grainStorage)\n        {\n            // encapsulate runtime services used by consistency adaptors\n            ILogConsistencyProtocolServices svc = protocolServicesFactory(grainContext);\n\n            TView state = (TView)Activator.CreateInstance(typeof(TView));\n\n            this.InstallAdaptor(factory, state, this.GetType().FullName, grainStorage, svc);\n        }\n\n        private ILogViewAdaptorFactory SetupLogConsistencyProvider(IGrainContext activationContext)\n        {\n            var attr = this.GetType().GetCustomAttributes<LogConsistencyProviderAttribute>(true).FirstOrDefault();\n\n            ILogViewAdaptorFactory defaultFactory = attr != null\n                ? this.ServiceProvider.GetKeyedService<ILogViewAdaptorFactory>(attr.ProviderName)\n                : this.ServiceProvider.GetService<ILogViewAdaptorFactory>();\n            if (attr != null && defaultFactory == null)\n            {\n                var errMsg = $\"Cannot find consistency provider with Name={attr.ProviderName} for grain type {this.GetType().FullName}\";\n                throw new BadProviderConfigException(errMsg);\n            }\n\n            // use default if none found\n            defaultFactory = defaultFactory ?? this.DefaultAdaptorFactory;\n            if (defaultFactory == null)\n            {\n                var errMsg = $\"No log consistency provider found loading grain type {this.GetType().FullName}\";\n                throw new BadProviderConfigException(errMsg);\n            };\n\n            return defaultFactory;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogConsistency/ProtocolServices.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.EventSourcing;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime.LogConsistency\n{\n    /// <summary>\n    /// Functionality for use by log view adaptors that run distributed protocols.\n    /// This class allows access to these services to providers that cannot see runtime-internals.\n    /// It also stores grain-specific information like the grain reference, and caches\n    /// </summary>\n    internal class ProtocolServices : ILogConsistencyProtocolServices\n    {\n        private readonly ILogger log;\n        private readonly DeepCopier deepCopier;\n        private readonly IGrainContext grainContext;   // links to the grain that owns this service object\n\n        public ProtocolServices(\n            IGrainContext grainContext,\n            ILoggerFactory loggerFactory,\n            DeepCopier deepCopier,\n            ILocalSiloDetails siloDetails)\n        {\n            this.grainContext = grainContext;\n            this.log = loggerFactory.CreateLogger<ProtocolServices>();\n            this.deepCopier = deepCopier;\n            this.MyClusterId = siloDetails.ClusterId;\n        }\n\n        public GrainId GrainId => grainContext.GrainId;\n\n        public string MyClusterId { get; }\n\n        public T DeepCopy<T>(T value) => this.deepCopier.Copy(value);\n\n        public void ProtocolError(string msg, bool throwexception)\n        {\n            log.LogError(\n                (int)(throwexception ? ErrorCode.LogConsistency_ProtocolFatalError : ErrorCode.LogConsistency_ProtocolError),\n                \"{GrainId} Protocol Error: {Message}\",\n                grainContext.GrainId,\n                msg);\n\n            if (!throwexception)\n                return;\n\n            throw new OrleansException(string.Format(\"{0} (grain={1}, cluster={2})\", msg, grainContext.GrainId, this.MyClusterId));\n        }\n\n        public void CaughtException(string where, Exception e)\n        {\n            log.LogError(\n                (int)ErrorCode.LogConsistency_CaughtException,\n                e,\n               \"{GrainId} exception caught at {Location}\",\n               grainContext.GrainId,\n               where);\n        }\n\n        public void CaughtUserCodeException(string callback, string where, Exception e)\n        {\n            log.LogWarning(\n                (int)ErrorCode.LogConsistency_UserCodeException,\n                e,\n                \"{GrainId} exception caught in user code for {Callback}, called from {Location}\",\n                grainContext.GrainId,\n                callback,\n                where);\n        }\n\n        public void Log(LogLevel level, string format, params object[] args)\n        {\n            if (log != null && log.IsEnabled(level))\n            {\n                var msg = $\"{grainContext.GrainId} {string.Format(format, args)}\";\n                log.Log(level, 0, msg, null, (m, exc) => $\"{m}\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogStorage/DefaultAdaptorFactory.cs",
    "content": "using Orleans.Storage;\n\nnamespace Orleans.EventSourcing.LogStorage\n{\n    internal class DefaultAdaptorFactory : ILogViewAdaptorFactory\n    {\n        public bool UsesStorageProvider\n        {\n            get\n            {\n                return true;\n            }\n        }\n\n         public ILogViewAdaptor<T, E> MakeLogViewAdaptor<T, E>(ILogViewAdaptorHost<T, E> hostgrain, T initialstate, string graintypename, IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where T : class, new() where E : class\n        {\n            return new LogViewAdaptor<T, E>(hostgrain, initialstate, grainStorage, graintypename, services);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogStorage/LogConsistencyProvider.cs",
    "content": "using Orleans.Storage;\n\n\nnamespace Orleans.EventSourcing.LogStorage\n{\n    /// <summary>\n    /// A log-consistency provider that stores the latest view in primary storage, using any standard storage provider.\n    /// Supports multiple clusters connecting to the same primary storage (doing optimistic concurrency control via e-tags)\n    ///<para>\n    /// The log itself is transient, i.e. not actually saved to storage - only the latest view (snapshot) and some \n    /// metadata (the log position, and write flags) are stored in the primary. \n    /// </para>\n    /// </summary>\n    public class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        /// <inheritdoc/>\n        public bool UsesStorageProvider\n        {\n            get\n            {\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Make log view adaptor \n        /// </summary>\n        /// <typeparam name=\"TView\">The type of the view</typeparam>\n        /// <typeparam name=\"TEntry\">The type of the log entries</typeparam>\n        /// <param name=\"hostGrain\">The grain that is hosting this adaptor</param>\n        /// <param name=\"initialState\">The initial state for this view</param>\n        /// <param name=\"grainTypeName\">The type name of the grain</param>\n        /// <param name=\"grainStorage\">Storage provider</param>\n        /// <param name=\"services\">Runtime services for multi-cluster coherence protocols</param>\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, IGrainStorage grainStorage, ILogConsistencyProtocolServices services) \n            where TView : class, new()\n            where TEntry : class\n        {\n            return new LogViewAdaptor<TView,TEntry>(hostGrain, initialState, grainStorage, grainTypeName, services);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.EventSourcing/LogStorage/LogStateWithMetaData.cs",
    "content": "using Orleans.EventSourcing.Common;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.EventSourcing.LogStorage\n{\n    /// <summary>\n    /// A class that extends grain state with versioning metadata, so that a grain with log-view consistency\n    /// can use a standard storage provider.\n    /// </summary>\n    /// <typeparam name=\"TEntry\">The type used for log entries</typeparam>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class LogStateWithMetaDataAndETag<TEntry> : IGrainState<LogStateWithMetaData<TEntry>> where TEntry : class\n    {\n        /// <summary>\n        /// Gets and Sets StateAndMetaData\n        /// </summary>\n        [Id(0)]\n        public LogStateWithMetaData<TEntry> StateAndMetaData { get; set; }\n\n        /// <summary>\n        /// Gets and Sets Etag\n        /// </summary>\n        [Id(1)]\n        public string ETag { get; set; }\n\n        [Id(2)]\n        public bool RecordExists { get; set; }\n\n        public LogStateWithMetaData<TEntry> State { get => StateAndMetaData; set => StateAndMetaData = value; }\n\n        /// <summary>\n        /// Initializes a new instance of GrainStateWithMetaDataAndETag class\n        /// </summary>\n        public LogStateWithMetaDataAndETag()\n        {\n            StateAndMetaData = new LogStateWithMetaData<TEntry>();\n        }\n\n        /// <summary>\n        /// Convert current GrainStateWithMetaDataAndETag object information to a string\n        /// </summary>\n        public override string ToString()\n        {\n            return string.Format(\"v{0} Flags={1} ETag={2} Data={3}\", StateAndMetaData.GlobalVersion, StateAndMetaData.WriteVector, ETag, StateAndMetaData.Log);\n        }\n    }\n\n    /// <summary>\n    /// A class that extends grain state with versioning metadata, so that a log-consistent grain\n    /// can use a standard storage provider.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class LogStateWithMetaData<TEntry> where TEntry : class\n    {\n        /// <summary>\n        /// The stored view of the log\n        /// </summary>\n        [Id(0)]\n        public List<TEntry> Log { get; set; }\n\n        /// <summary>\n        /// The length of the log\n        /// </summary>\n        public int GlobalVersion { get { return Log.Count; } }\n\n        /// <summary>\n        /// Metadata that is used to avoid duplicate appends.\n        /// Logically, this is a (string->bit) map, the keys being replica ids\n        /// But this map is represented compactly as a simple string to reduce serialization/deserialization overhead\n        /// Bits are read by <see cref=\"GetBit\"/> and flipped by  <see cref=\"FlipBit\"/>.\n        /// Bits are toggled when writing, so that the retry logic can avoid appending an entry twice\n        /// when retrying a failed append.\n        /// </summary>\n        [Id(1)]\n        public string WriteVector { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LogStateWithMetaData{TView}\"/> class.\n        /// </summary>\n        public LogStateWithMetaData()\n        {\n            Log = [];\n            WriteVector = \"\";\n        }\n\n        /// <summary>\n        /// Gets one of the bits in <see cref=\"WriteVector\"/>\n        /// </summary>\n        /// <param name=\"replica\">The replica for which we want to look up the bit</param>\n        /// <returns></returns>\n        public bool GetBit(string replica)\n        {\n            return StringEncodedWriteVector.GetBit(WriteVector, replica);\n        }\n\n        /// <summary>\n        /// Toggle one of the bits in <see cref=\"WriteVector\"/> and return the new value.\n        /// </summary>\n        /// <param name=\"replica\">The replica for which we want to flip the bit</param>\n        /// <returns>the state of the bit after flipping it</returns>\n        public bool FlipBit(string replica)\n        {\n            var str = WriteVector;\n            var result = StringEncodedWriteVector.FlipBit(ref str, replica);\n            WriteVector = str;\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/LogStorage/LogViewAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Storage;\nusing Orleans.EventSourcing.Common;\n\nnamespace Orleans.EventSourcing.LogStorage\n{\n    /// <summary>\n    /// A log view adaptor that wraps around a traditional storage adaptor, and uses batching and e-tags\n    /// to append entries.\n    ///<para>\n    /// The log itself is transient, i.e. not actually saved to storage - only the latest view and some\n    /// metadata (the log position, and write flags) are stored.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"TLogView\">Type of log view</typeparam>\n    /// <typeparam name=\"TLogEntry\">Type of log entry</typeparam>\n    internal class LogViewAdaptor<TLogView, TLogEntry> : PrimaryBasedLogViewAdaptor<TLogView, TLogEntry, SubmissionEntry<TLogEntry>> where TLogView : class, new() where TLogEntry : class\n    {\n        /// <summary>\n        /// Initialize a StorageProviderLogViewAdaptor class\n        /// </summary>\n        public LogViewAdaptor(ILogViewAdaptorHost<TLogView, TLogEntry> host, TLogView initialState, IGrainStorage globalGrainStorage, string grainTypeName, ILogConsistencyProtocolServices services)\n            : base(host, initialState, services)\n        {\n            this.globalGrainStorage = globalGrainStorage;\n            this.grainTypeName = grainTypeName;\n        }\n\n\n        private const int maxEntriesInNotifications = 200;\n        private readonly IGrainStorage globalGrainStorage;\n        private readonly string grainTypeName;\n\n        // the object containing the entire log, as retrieved from / sent to storage\n        private LogStateWithMetaDataAndETag<TLogEntry> GlobalLog;\n\n        // the confirmed view\n        private TLogView ConfirmedViewInternal;\n        private int ConfirmedVersionInternal;\n\n        /// <inheritdoc/>\n        protected override TLogView LastConfirmedView()\n        {\n            return ConfirmedViewInternal;\n        }\n\n        /// <inheritdoc/>\n        protected override int GetConfirmedVersion()\n        {\n            return ConfirmedVersionInternal;\n        }\n\n        /// <inheritdoc/>\n        protected override void InitializeConfirmedView(TLogView initialstate)\n        {\n            GlobalLog = new LogStateWithMetaDataAndETag<TLogEntry>();\n            ConfirmedViewInternal = initialstate;\n            ConfirmedVersionInternal = 0;\n        }\n\n        protected override Task ClearPrimaryLogAsync(CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            return this.globalGrainStorage.ClearStateAsync(grainTypeName, Services.GrainId, GlobalLog);\n        }\n\n        private void UpdateConfirmedView()\n        {\n            for (int i = ConfirmedVersionInternal; i < GlobalLog.StateAndMetaData.Log.Count; i++)\n            {\n                try\n                {\n                    Host.UpdateView(ConfirmedViewInternal, GlobalLog.StateAndMetaData.Log[i]);\n                }\n                catch (Exception e)\n                {\n                    Services.CaughtUserCodeException(\"UpdateView\", nameof(UpdateConfirmedView), e);\n                }\n            }\n            ConfirmedVersionInternal = GlobalLog.StateAndMetaData.GlobalVersion;\n        }\n\n\n        /// <inheritdoc/>\n        public override Task<IReadOnlyList<TLogEntry>> RetrieveLogSegment(int fromVersion, int toVersion)\n        {\n\n            // make a copy of the entries in the range asked for\n            IReadOnlyList<TLogEntry> segment = GlobalLog.StateAndMetaData.Log.GetRange(fromVersion, (toVersion - fromVersion));\n\n            return Task.FromResult(segment);\n        }\n\n        // no special tagging is required, thus we create a plain submission entry\n        /// <inheritdoc/>\n        protected override SubmissionEntry<TLogEntry> MakeSubmissionEntry(TLogEntry entry)\n        {\n            return new SubmissionEntry<TLogEntry>() { Entry = entry };\n        }\n\n\n        /// <inheritdoc/>\n        protected override async Task ReadAsync()\n        {\n            enter_operation(\"ReadAsync\");\n\n            while (true)\n            {\n                try\n                {\n                    // for manual testing\n                    //await Task.Delay(5000);\n\n                    await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainId, GlobalLog);\n\n                    Services.Log(LogLevel.Debug, \"read success {0}\", GlobalLog);\n\n                    UpdateConfirmedView();\n\n                    LastPrimaryIssue.Resolve(Host, Services);\n\n                    break; // successful\n                }\n                catch (Exception e)\n                {\n                    LastPrimaryIssue.Record(new ReadFromLogStorageFailed() { Exception = e }, Host, Services);\n                }\n\n                Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n\n                await LastPrimaryIssue.DelayBeforeRetry();\n            }\n\n            exit_operation(\"ReadAsync\");\n        }\n\n\n        /// <inheritdoc/>\n        protected override async Task<int> WriteAsync()\n        {\n            enter_operation(\"WriteAsync\");\n\n            var updates = GetCurrentBatchOfUpdates();\n            bool batchsuccessfullywritten = false;\n\n            var writebit = GlobalLog.StateAndMetaData.FlipBit(Services.MyClusterId);\n            foreach (var x in updates)\n                GlobalLog.StateAndMetaData.Log.Add(x.Entry);\n\n            try\n            {\n                // for manual testing\n                //await Task.Delay(5000);\n\n                await globalGrainStorage.WriteStateAsync(grainTypeName, Services.GrainId, GlobalLog);\n\n                batchsuccessfullywritten = true;\n\n                Services.Log(LogLevel.Debug, \"write ({0} updates) success {1}\", updates.Length, GlobalLog);\n\n                UpdateConfirmedView();\n\n                LastPrimaryIssue.Resolve(Host, Services);\n            }\n            catch (Exception e)\n            {\n                LastPrimaryIssue.Record(new UpdateLogStorageFailed() { Exception = e }, Host, Services);\n            }\n\n            if (!batchsuccessfullywritten)\n            {\n                Services.Log(LogLevel.Debug, \"write apparently failed {0}\", LastPrimaryIssue);\n\n                while (true) // be stubborn until we can read what is there\n                {\n\n                    await LastPrimaryIssue.DelayBeforeRetry();\n\n                    try\n                    {\n                        await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainId, GlobalLog);\n\n                        Services.Log(LogLevel.Debug, \"read success {0}\", GlobalLog);\n\n                        UpdateConfirmedView();\n\n                        LastPrimaryIssue.Resolve(Host, Services);\n\n                        break;\n                    }\n                    catch (Exception e)\n                    {\n                        LastPrimaryIssue.Record(new ReadFromLogStorageFailed() { Exception = e }, Host, Services);\n                    }\n\n                    Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n                }\n\n                // check if last apparently failed write was in fact successful\n\n                if (writebit == GlobalLog.StateAndMetaData.GetBit(Services.MyClusterId))\n                {\n                    Services.Log(LogLevel.Debug, \"last write ({0} updates) was actually a success {1}\", updates.Length, GlobalLog);\n\n                    batchsuccessfullywritten = true;\n                }\n            }\n\n            exit_operation(\"WriteAsync\");\n\n            if (!batchsuccessfullywritten)\n                return 0;\n\n            return updates.Length;\n        }\n\n\n        /// <summary>\n        /// Describes a connection issue that occurred when updating the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class UpdateLogStorageFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"write entire log to storage failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// Describes a connection issue that occurred when reading from the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class ReadFromLogStorageFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"read entire log from storage failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// A notification message sent to remote instances after updating this grain in storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        protected internal sealed class UpdateNotificationMessage : INotificationMessage\n        {\n            /// <inheritdoc/>\n            [Id(0)]\n            public int Version { get; set; }\n\n            /// <summary> The cluster that performed the update </summary>\n            [Id(1)]\n            public string Origin { get; set; }\n\n            /// <summary> The list of updates that were applied </summary>\n            [Id(2)]\n            public List<TLogEntry> Updates { get; set; }\n\n            /// <summary> The e-tag of the storage after applying the updates</summary>\n            [Id(3)]\n            public string ETag { get; set; }\n\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return string.Format(\"v{0} ({1} updates by {2}) etag={3}\", Version, Updates.Count, Origin, ETag);\n            }\n         }\n\n        /// <inheritdoc/>\n        protected override INotificationMessage Merge(INotificationMessage earlierMessage, INotificationMessage laterMessage)\n        {\n            var earlier = earlierMessage as UpdateNotificationMessage;\n            var later = laterMessage as UpdateNotificationMessage;\n\n            if (earlier != null\n                && later != null\n                && earlier.Origin == later.Origin\n                && earlier.Version + later.Updates.Count == later.Version\n                && earlier.Updates.Count + later.Updates.Count < maxEntriesInNotifications)\n\n                return new UpdateNotificationMessage()\n                {\n                    Version = later.Version,\n                    Origin = later.Origin,\n                    Updates = earlier.Updates.Concat(later.Updates).ToList(),\n                    ETag = later.ETag\n                };\n\n            else\n                return base.Merge(earlierMessage, laterMessage); // keep only the version number\n        }\n\n        private readonly SortedList<long, UpdateNotificationMessage> notifications = new SortedList<long,UpdateNotificationMessage>();\n\n        /// <inheritdoc/>\n        protected override void OnNotificationReceived(INotificationMessage payload)\n        {\n            var um = payload as UpdateNotificationMessage;\n            if (um != null)\n                notifications.Add(um.Version - um.Updates.Count, um);\n            else\n                base.OnNotificationReceived(payload);\n        }\n\n        /// <inheritdoc/>\n        protected override void ProcessNotifications()\n        {\n            // discard notifications that are behind our already confirmed state\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key < GlobalLog.StateAndMetaData.GlobalVersion)\n            {\n                Services.Log(LogLevel.Debug, \"discarding notification {0}\", notifications.ElementAt(0).Value);\n                notifications.RemoveAt(0);\n            }\n\n            // process notifications that reflect next global version\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key == GlobalLog.StateAndMetaData.GlobalVersion)\n            {\n                var updateNotification = notifications.ElementAt(0).Value;\n                notifications.RemoveAt(0);\n\n                // append all operations in pending\n                foreach (var u in updateNotification.Updates)\n                    GlobalLog.StateAndMetaData.Log.Add(u);\n\n                GlobalLog.StateAndMetaData.FlipBit(updateNotification.Origin);\n\n                GlobalLog.ETag = updateNotification.ETag;\n\n                UpdateConfirmedView();\n\n                Services.Log(LogLevel.Debug, \"notification success ({0} updates) {1}\", updateNotification.Updates.Count, GlobalLog);\n            }\n\n            Services.Log(LogLevel.Trace, \"unprocessed notifications in queue: {0}\", notifications.Count);\n\n            base.ProcessNotifications();\n\n        }\n\n\n#if DEBUG\n        private bool operation_in_progress;\n#endif\n\n        [Conditional(\"DEBUG\")]\n        private void enter_operation(string name)\n        {\n#if DEBUG\n            Services.Log(LogLevel.Trace, \"/-- enter {0}\", name);\n            Debug.Assert(!operation_in_progress);\n            operation_in_progress = true;\n#endif\n        }\n\n        [Conditional(\"DEBUG\")]\n        private void exit_operation(string name)\n        {\n#if DEBUG\n            Services.Log(LogLevel.Trace, \"\\\\-- exit {0}\", name);\n            Debug.Assert(operation_in_progress);\n            operation_in_progress = false;\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/Orleans.EventSourcing.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.EventSourcing</PackageId>\n    <Title>Microsoft Orleans Event-Sourcing</Title>\n    <Description>Base types for creating Microsoft Orleans grains with event-sourced state.</Description>\n    <PackageTags>$(PackageTags) EventSourcing</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <AssemblyName>Orleans.EventSourcing</AssemblyName>\n    <RootNamespace>OrleansEventSourcing</RootNamespace>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"LoadTestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.CodeGeneration.Build\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.EventSourcing/README.md",
    "content": "# Microsoft Orleans Event Sourcing\n\n## Introduction\nMicrosoft Orleans Event Sourcing provides support for implementing event-sourced grains. Event sourcing is a pattern where state changes are recorded as a sequence of events rather than just storing the current state. This provides a complete history of changes and allows for powerful capabilities like replaying events, temporal querying, and more robust auditing.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.EventSourcing\n```\n\n## Example - Creating an Event-Sourced Grain\n\n```csharp\nusing Orleans;\nusing Orleans.EventSourcing;\nusing System;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;\nusing System.Linq;\n\n// Define grain state and events\nnamespace BankAccount;\n\npublic class BankAccountState\n{\n    public decimal Balance { get; set; }\n    public string AccountHolder { get; set; }\n    public int Version { get; set; }\n}\n\npublic class DepositEvent\n{\n    public decimal Amount { get; set; }\n}\n\npublic class WithdrawalEvent\n{\n    public decimal Amount { get; set; }\n}\n\n// Grain interface\npublic interface IBankAccountGrain : IGrainWithStringKey\n{\n    Task<decimal> GetBalance();\n    Task Deposit(decimal amount);\n    Task Withdraw(decimal amount);\n    Task<IReadOnlyList<object>> GetHistory();\n}\n\n// Event-sourced grain implementation using JournaledGrain\npublic class BankAccountGrain : JournaledGrain<BankAccountState, object>, IBankAccountGrain\n{\n    public async Task<decimal> GetBalance()\n    {\n        // The state is automatically hydrated from the event log\n        return State.Balance;\n    }\n\n    public async Task Deposit(decimal amount)\n    {\n        if (amount <= 0)\n            throw new ArgumentException(\"Deposit amount must be positive\");\n\n        // Record the event - this will be persisted and applied to state\n        RaiseEvent(new DepositEvent { Amount = amount });\n        \n        // Confirm the event is persisted\n        await ConfirmEvents();\n    }\n\n    public async Task Withdraw(decimal amount)\n    {\n        if (amount <= 0)\n            throw new ArgumentException(\"Withdrawal amount must be positive\");\n            \n        if (State.Balance < amount)\n            throw new InvalidOperationException(\"Insufficient funds\");\n\n        // Record the event\n        RaiseEvent(new WithdrawalEvent { Amount = amount });\n        \n        // Confirm the event is persisted\n        await ConfirmEvents();\n    }\n\n    public Task<IReadOnlyList<object>> GetHistory()\n    {\n        // Return the complete history of events\n        return Task.FromResult<IReadOnlyList<object>>(RetrieveConfirmedEvents(0, Version).ToList());\n    }\n\n    // Event handlers to update the state based on events\n    protected override void ApplyEvent(object @event)\n    {\n        switch (@event)\n        {\n            case DepositEvent deposit:\n                State.Balance += deposit.Amount;\n                break;\n                \n            case WithdrawalEvent withdrawal:\n                State.Balance -= withdrawal.Amount;\n                break;\n        }\n    }\n}\n```\n\n## Example - Configuring Event Sourcing with Storage\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.EventSourcing;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure the log consistency provider for event sourcing\n            .AddLogStorageBasedLogConsistencyProvider(\"LogStorage\")\n            // Configure a storage provider to store the events\n            .AddMemoryGrainStorage(\"PubSubStore\")\n            .ConfigureServices(services =>\n            {\n                // Configure default log consistency provider\n                services.Configure<JournaledGrainOptions>(options =>\n                {\n                    options.DefaultLogConsistencyProvider = \"LogStorage\";\n                });\n            });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar bankAccount = client.GetGrain<IBankAccountGrain>(\"account-123\");\n\n// Call grain methods\nawait bankAccount.Deposit(100);\nawait bankAccount.Withdraw(25);\nvar balance = await bankAccount.GetBalance();\n\n// Print the result\nConsole.WriteLine($\"Account balance: ${balance}\");\n\nvar history = await bankAccount.GetHistory();\nConsole.WriteLine($\"Transaction history: {history.Count} events\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Event Sourcing Overview](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/event-sourcing/overview)\n- [Journaled Grains](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/event-sourcing/journaled-grains)\n- [Replicated Grains](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/event-sourcing/replicated-grains)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.EventSourcing/StateStorage/DefaultAdaptorFactory.cs",
    "content": "﻿using Orleans.Storage;\n\nnamespace Orleans.EventSourcing.StateStorage\n{\n    internal class DefaultAdaptorFactory : ILogViewAdaptorFactory\n    {\n        public bool UsesStorageProvider\n        {\n            get\n            {\n                return true;\n            }\n        }\n\n         public ILogViewAdaptor<T, E> MakeLogViewAdaptor<T, E>(ILogViewAdaptorHost<T, E> hostgrain, T initialstate, string graintypename, IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where T : class, new() where E : class\n        {\n            return new LogViewAdaptor<T, E>(hostgrain, initialstate, grainStorage, graintypename, services);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/StateStorage/GrainStateWithMetaData.cs",
    "content": "using Orleans.EventSourcing.Common;\nusing System;\n\nnamespace Orleans.EventSourcing.StateStorage\n{\n    /// <summary>\n    /// A class that extends grain state with versioning metadata, so that a grain with log-view consistency\n    /// can use a standard storage provider.\n    /// </summary>\n    /// <typeparam name=\"TView\">The type used for log view</typeparam>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GrainStateWithMetaDataAndETag<TView> : IGrainState<GrainStateWithMetaData<TView>> where TView : class, new()\n    {\n        /// <summary>\n        /// Gets and Sets StateAndMetaData\n        /// </summary>\n        [Id(0)]\n        public GrainStateWithMetaData<TView> StateAndMetaData { get; set; }\n\n        /// <summary>\n        /// Gets and Sets Etag\n        /// </summary>\n        [Id(1)]\n        public string ETag { get; set; }\n\n        [Id(2)]\n        public bool RecordExists { get; set; }\n\n        public GrainStateWithMetaData<TView> State { get => StateAndMetaData; set => StateAndMetaData = value; }\n\n        /// <summary>\n        /// Initialize a new instance of GrainStateWithMetaDataAndETag class with an initialView\n        /// </summary>\n        public GrainStateWithMetaDataAndETag(TView initialview)\n        {\n            StateAndMetaData = new GrainStateWithMetaData<TView>(initialview);\n        }\n\n        /// <summary>\n        /// Initializes a new instance of GrainStateWithMetaDataAndETag class\n        /// </summary>\n        public GrainStateWithMetaDataAndETag()\n        {\n            StateAndMetaData = new GrainStateWithMetaData<TView>();\n        }\n\n        /// <summary>\n        /// Convert current GrainStateWithMetaDataAndETag object information to a string\n        /// </summary>\n        public override string ToString()\n        {\n            return string.Format(\"v{0} Flags={1} ETag={2} Data={3}\", StateAndMetaData.GlobalVersion, StateAndMetaData.WriteVector, ETag, StateAndMetaData.State);\n        }\n    }\n\n\n    /// <summary>\n    /// A class that extends grain state with versioning metadata, so that a log-consistent grain\n    /// can use a standard storage provider.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GrainStateWithMetaData<TView> where TView : class, new()\n    {\n        /// <summary>\n        /// The stored view of the log\n        /// </summary>\n        [Id(0)]\n        public TView State { get; set; }\n\n        /// <summary>\n        /// The length of the log\n        /// </summary>\n        [Id(1)]\n        public int GlobalVersion { get; set; }\n\n\n        /// <summary>\n        /// Metadata that is used to avoid duplicate appends.\n        /// Logically, this is a (string->bit) map, the keys being replica ids\n        /// But this map is represented compactly as a simple string to reduce serialization/deserialization overhead\n        /// Bits are read by <see cref=\"GetBit\"/> and flipped by  <see cref=\"FlipBit\"/>.\n        /// Bits are toggled when writing, so that the retry logic can avoid appending an entry twice\n        /// when retrying a failed append.\n        /// </summary>\n        [Id(2)]\n        public string WriteVector { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainStateWithMetaData{TView}\"/> class.\n        /// </summary>\n        public GrainStateWithMetaData()\n        {\n            State = new TView();\n            GlobalVersion = 0;\n            WriteVector = \"\";\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainStateWithMetaData{TView}\"/> class.\n        /// </summary>\n        /// <param name=\"initialstate\">The initial state of the view</param>\n        public GrainStateWithMetaData(TView initialstate)\n        {\n            this.State = initialstate;\n            GlobalVersion = 0;\n            WriteVector = \"\";\n        }\n\n\n        /// <summary>\n        /// Gets one of the bits in <see cref=\"WriteVector\"/>\n        /// </summary>\n        /// <param name=\"Replica\">The replica for which we want to look up the bit</param>\n        /// <returns></returns>\n        public bool GetBit(string Replica)\n        {\n            return StringEncodedWriteVector.GetBit(WriteVector, Replica);\n        }\n\n        /// <summary>\n        /// toggle one of the bits in <see cref=\"WriteVector\"/> and return the new value.\n        /// </summary>\n        /// <param name=\"Replica\">The replica for which we want to flip the bit</param>\n        /// <returns>the state of the bit after flipping it</returns>\n        public bool FlipBit(string Replica)\n        {\n            var str = WriteVector;\n            var rval = StringEncodedWriteVector.FlipBit(ref str, Replica);\n            WriteVector = str;\n            return rval;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.EventSourcing/StateStorage/LogConsistencyProvider.cs",
    "content": "using Orleans.Storage;\n\nnamespace Orleans.EventSourcing.StateStorage\n{\n    /// <summary>\n    /// A log-consistency provider that stores the latest view in primary storage, using any standard storage provider.\n    /// Supports multiple clusters connecting to the same primary storage (doing optimistic concurrency control via e-tags)\n    ///<para>\n    /// The log itself is transient, i.e. not actually saved to storage - only the latest view (snapshot) and some \n    /// metadata (the log position, and write flags) are stored in the primary. \n    /// </para>\n    /// </summary>\n    public class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        /// <inheritdoc/>\n        public bool UsesStorageProvider\n        {\n            get\n            {\n                return true;\n            }\n        }\n\n        /// <inheritdoc/>\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, IGrainStorage grainStorage, ILogConsistencyProtocolServices services) \n            where TView : class, new()\n            where TEntry : class\n        {\n            return new LogViewAdaptor<TView,TEntry>(hostGrain, initialState, grainStorage, grainTypeName, services);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.EventSourcing/StateStorage/LogViewAdaptor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Storage;\nusing Orleans.EventSourcing.Common;\n\nnamespace Orleans.EventSourcing.StateStorage\n{\n    /// <summary>\n    /// A log view adaptor that wraps around a traditional storage adaptor, and uses batching and e-tags\n    /// to append entries.\n    ///<para>\n    /// The log itself is transient, i.e. not actually saved to storage - only the latest view and some\n    /// metadata (the log position, and write flags) are stored.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"TLogView\">Type of log view</typeparam>\n    /// <typeparam name=\"TLogEntry\">Type of log entry</typeparam>\n    internal class LogViewAdaptor<TLogView, TLogEntry> : PrimaryBasedLogViewAdaptor<TLogView, TLogEntry, SubmissionEntry<TLogEntry>> where TLogView : class, new() where TLogEntry : class\n    {\n        /// <summary>\n        /// Initialize a StorageProviderLogViewAdaptor class\n        /// </summary>\n        public LogViewAdaptor(ILogViewAdaptorHost<TLogView, TLogEntry> host, TLogView initialState, IGrainStorage globalGrainStorage, string grainTypeName, ILogConsistencyProtocolServices services)\n            : base(host, initialState, services)\n        {\n            this.globalGrainStorage = globalGrainStorage;\n            this.grainTypeName = grainTypeName;\n        }\n\n\n        private const int maxEntriesInNotifications = 200;\n        private readonly IGrainStorage globalGrainStorage;\n        private readonly string grainTypeName;        // stores the confirmed state including metadata\n        private GrainStateWithMetaDataAndETag<TLogView> GlobalStateCache;\n\n        /// <inheritdoc/>\n        protected override TLogView LastConfirmedView()\n        {\n            return GlobalStateCache.StateAndMetaData.State;\n        }\n\n        /// <inheritdoc/>\n        protected override int GetConfirmedVersion()\n        {\n            return GlobalStateCache.StateAndMetaData.GlobalVersion;\n        }\n\n        /// <inheritdoc/>\n        protected override void InitializeConfirmedView(TLogView initialstate)\n        {\n            GlobalStateCache = new GrainStateWithMetaDataAndETag<TLogView>(initialstate);\n        }\n\n        protected override Task ClearPrimaryLogAsync(CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n\n            return this.globalGrainStorage.ClearStateAsync(grainTypeName, Services.GrainId, GlobalStateCache);\n        }\n\n        // no special tagging is required, thus we create a plain submission entry\n        /// <inheritdoc/>\n        protected override SubmissionEntry<TLogEntry> MakeSubmissionEntry(TLogEntry entry)\n        {\n            return new SubmissionEntry<TLogEntry>() { Entry = entry };\n        }\n\n        /// <inheritdoc/>\n        protected override async Task ReadAsync()\n        {\n            enter_operation(\"ReadAsync\");\n\n            while (true)\n            {\n                try\n                {\n                    // for manual testing\n                    //await Task.Delay(5000);\n\n                    var readState = new GrainStateWithMetaDataAndETag<TLogView>();\n\n                    await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainId, readState);\n\n                    GlobalStateCache = readState;\n\n                    Services.Log(LogLevel.Debug, \"read success {0}\", GlobalStateCache);\n\n                    LastPrimaryIssue.Resolve(Host, Services);\n\n                    break; // successful\n                }\n                catch (Exception e)\n                {\n                    LastPrimaryIssue.Record(new ReadFromStateStorageFailed() { Exception = e }, Host, Services);\n                }\n\n                Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n\n                await LastPrimaryIssue.DelayBeforeRetry();\n            }\n\n            exit_operation(\"ReadAsync\");\n        }\n\n\n        /// <inheritdoc/>\n        protected override async Task<int> WriteAsync()\n        {\n            enter_operation(\"WriteAsync\");\n\n            var state = CopyTentativeState();\n            var updates = GetCurrentBatchOfUpdates();\n            bool batchsuccessfullywritten = false;\n\n            var nextglobalstate = new GrainStateWithMetaDataAndETag<TLogView>(state);\n            nextglobalstate.StateAndMetaData.WriteVector = GlobalStateCache.StateAndMetaData.WriteVector;\n            nextglobalstate.StateAndMetaData.GlobalVersion = GlobalStateCache.StateAndMetaData.GlobalVersion + updates.Length;\n            nextglobalstate.ETag = GlobalStateCache.ETag;\n\n            var writebit = nextglobalstate.StateAndMetaData.FlipBit(Services.MyClusterId);\n\n            try\n            {\n                // for manual testing\n                //await Task.Delay(5000);\n\n                await globalGrainStorage.WriteStateAsync(grainTypeName, Services.GrainId, nextglobalstate);\n\n                batchsuccessfullywritten = true;\n\n                GlobalStateCache = nextglobalstate;\n\n                Services.Log(LogLevel.Debug, \"write ({0} updates) success {1}\", updates.Length, GlobalStateCache);\n\n                LastPrimaryIssue.Resolve(Host, Services);\n            }\n            catch (Exception e)\n            {\n                LastPrimaryIssue.Record(new UpdateStateStorageFailed() { Exception = e }, Host, Services);\n            }\n\n            if (!batchsuccessfullywritten)\n            {\n                Services.Log(LogLevel.Debug, \"write apparently failed {0} {1}\", nextglobalstate, LastPrimaryIssue);\n\n                while (true) // be stubborn until we can read what is there\n                {\n\n                    await LastPrimaryIssue.DelayBeforeRetry();\n\n                    try\n                    {\n                        await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainId, GlobalStateCache);\n\n                        Services.Log(LogLevel.Debug, \"read success {0}\", GlobalStateCache);\n\n                        LastPrimaryIssue.Resolve(Host, Services);\n\n                        break;\n                    }\n                    catch (Exception e)\n                    {\n                        LastPrimaryIssue.Record(new ReadFromStateStorageFailed() { Exception = e }, Host, Services);\n                    }\n\n                    Services.Log(LogLevel.Debug, \"read failed {0}\", LastPrimaryIssue);\n                }\n\n                // check if last apparently failed write was in fact successful\n\n                if (writebit == GlobalStateCache.StateAndMetaData.GetBit(Services.MyClusterId))\n                {\n                    GlobalStateCache = nextglobalstate;\n\n                    Services.Log(LogLevel.Debug, \"last write ({0} updates) was actually a success {1}\", updates.Length, GlobalStateCache);\n\n                    batchsuccessfullywritten = true;\n                }\n            }\n\n            exit_operation(\"WriteAsync\");\n\n            if (!batchsuccessfullywritten)\n                return 0;\n\n            return updates.Length;\n        }\n\n\n        /// <summary>\n        /// Describes a connection issue that occurred when updating the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class UpdateStateStorageFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"write state to storage failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// Describes a connection issue that occurred when reading from the primary storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class ReadFromStateStorageFailed : PrimaryOperationFailed\n        {\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return $\"read state from storage failed: caught {Exception.GetType().Name}: {Exception.Message}\";\n            }\n        }\n\n\n        /// <summary>\n        /// A notification message sent to remote instances after updating this grain in storage.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        protected internal sealed class UpdateNotificationMessage : INotificationMessage\n        {\n            /// <inheritdoc/>\n            [Id(0)]\n            public int Version { get; set; }\n\n            /// <summary> The cluster that performed the update </summary>\n            [Id(1)]\n            public string Origin { get; set; }\n\n            /// <summary> The list of updates that were applied </summary>\n            [Id(2)]\n            public List<TLogEntry> Updates { get; set; }\n\n            /// <summary> The e-tag of the storage after applying the updates</summary>\n            [Id(3)]\n            public string ETag { get; set; }\n\n            /// <inheritdoc/>\n            public override string ToString()\n            {\n                return string.Format(\"v{0} ({1} updates by {2}) etag={3}\", Version, Updates.Count, Origin, ETag);\n            }\n         }\n\n        /// <inheritdoc/>\n        protected override INotificationMessage Merge(INotificationMessage earlierMessage, INotificationMessage laterMessage)\n        {\n            var earlier = earlierMessage as UpdateNotificationMessage;\n            var later = laterMessage as UpdateNotificationMessage;\n\n            if (earlier != null\n                && later != null\n                && earlier.Origin == later.Origin\n                && earlier.Version + later.Updates.Count == later.Version\n                && earlier.Updates.Count + later.Updates.Count < maxEntriesInNotifications)\n\n                return new UpdateNotificationMessage()\n                {\n                    Version = later.Version,\n                    Origin = later.Origin,\n                    Updates = earlier.Updates.Concat(later.Updates).ToList(),\n                    ETag = later.ETag\n                };\n\n            else\n                return base.Merge(earlierMessage, laterMessage); // keep only the version number\n        }\n\n        private readonly SortedList<long, UpdateNotificationMessage> notifications = new SortedList<long,UpdateNotificationMessage>();\n\n        /// <inheritdoc/>\n        protected override void OnNotificationReceived(INotificationMessage payload)\n        {\n            var um = payload as UpdateNotificationMessage;\n            if (um != null)\n                notifications.Add(um.Version - um.Updates.Count, um);\n            else\n                base.OnNotificationReceived(payload);\n        }\n\n        /// <inheritdoc/>\n        protected override void ProcessNotifications()\n        {\n            // discard notifications that are behind our already confirmed state\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key < GlobalStateCache.StateAndMetaData.GlobalVersion)\n            {\n                Services.Log(LogLevel.Debug, \"discarding notification {0}\", notifications.ElementAt(0).Value);\n                notifications.RemoveAt(0);\n            }\n\n            // process notifications that reflect next global version\n            while (notifications.Count > 0 && notifications.ElementAt(0).Key == GlobalStateCache.StateAndMetaData.GlobalVersion)\n            {\n                var updateNotification = notifications.ElementAt(0).Value;\n                notifications.RemoveAt(0);\n\n                // Apply all operations in pending\n                foreach (var u in updateNotification.Updates)\n                    try\n                    {\n                        Host.UpdateView(GlobalStateCache.StateAndMetaData.State, u);\n                    }\n                    catch (Exception e)\n                    {\n                        Services.CaughtUserCodeException(\"UpdateView\", nameof(ProcessNotifications), e);\n                    }\n\n                GlobalStateCache.StateAndMetaData.GlobalVersion = updateNotification.Version;\n\n                GlobalStateCache.StateAndMetaData.FlipBit(updateNotification.Origin);\n\n                GlobalStateCache.ETag = updateNotification.ETag;\n\n                Services.Log(LogLevel.Debug, \"notification success ({0} updates) {1}\", updateNotification.Updates.Count, GlobalStateCache);\n            }\n\n            Services.Log(LogLevel.Trace, \"unprocessed notifications in queue: {0}\", notifications.Count);\n\n            base.ProcessNotifications();\n\n        }\n\n\n#if DEBUG\n        private bool operation_in_progress;\n#endif\n\n        [Conditional(\"DEBUG\")]\n        private void enter_operation(string name)\n        {\n#if DEBUG\n            Services.Log(LogLevel.Trace, \"/-- enter {0}\", name);\n            Debug.Assert(!operation_in_progress);\n            operation_in_progress = true;\n#endif\n        }\n\n        [Conditional(\"DEBUG\")]\n        private void exit_operation(string name)\n        {\n#if DEBUG\n            Services.Log(LogLevel.Trace, \"\\\\-- exit {0}\", name);\n            Debug.Assert(operation_in_progress);\n            operation_in_progress = false;\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/ConfigureKubernetesHostingOptions.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace Orleans.Hosting.Kubernetes\n{\n    internal class ConfigureKubernetesHostingOptions :\n        IConfigureOptions<ClusterOptions>,\n        IConfigureOptions<SiloOptions>,\n        IPostConfigureOptions<EndpointOptions>,\n        IConfigureOptions<KubernetesHostingOptions>\n    {\n        private readonly IServiceProvider _serviceProvider;\n\n        public ConfigureKubernetesHostingOptions(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        public void Configure(KubernetesHostingOptions options)\n        {\n            options.Namespace ??= Environment.GetEnvironmentVariable(KubernetesHostingOptions.PodNamespaceEnvironmentVariable) ?? ReadNamespaceFromServiceAccount();\n            options.PodName ??= Environment.GetEnvironmentVariable(KubernetesHostingOptions.PodNameEnvironmentVariable) ?? Environment.MachineName;\n            options.PodIP ??= Environment.GetEnvironmentVariable(KubernetesHostingOptions.PodIPEnvironmentVariable);\n        }\n\n        public void Configure(ClusterOptions options)\n        {\n            var serviceIdEnvVar = Environment.GetEnvironmentVariable(KubernetesHostingOptions.ServiceIdEnvironmentVariable);\n            if (!string.IsNullOrWhiteSpace(serviceIdEnvVar))\n            {\n                options.ServiceId = serviceIdEnvVar;\n            }\n\n            var clusterIdEnvVar = Environment.GetEnvironmentVariable(KubernetesHostingOptions.ClusterIdEnvironmentVariable);\n            if (!string.IsNullOrWhiteSpace(clusterIdEnvVar))\n            {\n                options.ClusterId = clusterIdEnvVar;\n            }\n        }\n\n        public void Configure(SiloOptions options)\n        {\n            var hostingOptions = _serviceProvider.GetRequiredService<IOptions<KubernetesHostingOptions>>().Value;\n            if (!string.IsNullOrWhiteSpace(hostingOptions.PodName))\n            {\n                options.SiloName = hostingOptions.PodName;\n            }\n        }\n\n        public void PostConfigure(string? name, EndpointOptions options)\n        {\n            // Use PostConfigure to give the developer an opportunity to set SiloPort and GatewayPort using regular\n            // Configure methods without needing to worry about ordering with respect to the UseKubernetesHosting call.\n            if (options.AdvertisedIPAddress is null)\n            {\n                var hostingOptions = _serviceProvider.GetRequiredService<IOptions<KubernetesHostingOptions>>().Value;\n                IPAddress? podIp = null;\n                if (hostingOptions.PodIP is not null)\n                {\n                    podIp = IPAddress.Parse(hostingOptions.PodIP);\n                }\n                else\n                {\n                    var hostAddresses = Dns.GetHostAddresses(hostingOptions.PodName);\n                    if (hostAddresses != null)\n                    {\n                        podIp = IPAddressSelector.PickIPAddress(hostAddresses);\n                    }\n                }\n\n                if (podIp is not null)\n                {\n                    options.AdvertisedIPAddress = podIp;\n                }\n            }\n\n            if (options.SiloListeningEndpoint is null)\n            {\n                options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, options.SiloPort);\n            }\n\n            if (options.GatewayListeningEndpoint is null && options.GatewayPort > 0)\n            {\n                options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, options.GatewayPort);\n            }\n        }\n\n        private static string? ReadNamespaceFromServiceAccount()\n        {\n            // Read the namespace from the pod's service account.\n            var serviceAccountNamespacePath = Path.Combine($\"{Path.DirectorySeparatorChar}var\", \"run\", \"secrets\", \"kubernetes.io\", \"serviceaccount\", \"namespace\");\n            if (File.Exists(serviceAccountNamespacePath))\n            {\n                return File.ReadAllText(serviceAccountNamespacePath).Trim();\n            }\n\n            return null;\n        }\n\n        private static class IPAddressSelector\n        {\n            // IANA private IPv4 addresses\n            private static readonly (IPAddress Address, IPAddress SubnetMask)[] PreferredRanges = new []\n            {\n                (IPAddress.Parse(\"192.168.0.0\"), IPAddress.Parse(\"255.255.0.0\")),\n                (IPAddress.Parse(\"10.0.0.0\"), IPAddress.Parse(\"255.0.0.0\")),\n                (IPAddress.Parse(\"172.16.0.0\"), IPAddress.Parse(\"255.240.0.0\")),\n            };\n\n            public static IPAddress? PickIPAddress(IReadOnlyList<IPAddress> candidates)\n            {\n                IPAddress? chosen = null;\n                foreach (var address in candidates)\n                {\n                    if (chosen is null)\n                    {\n                        chosen = address;\n                    }\n                    else\n                    {\n                        if (CompareIPAddresses(address, chosen))\n                        {\n                            chosen = address;\n                        }\n                    }\n                }\n                return chosen;\n\n                // returns true if lhs is \"less\" (in some repeatable sense) than rhs\n                static bool CompareIPAddresses(IPAddress lhs, IPAddress rhs)\n                {\n                    var lhsBytes = lhs.GetAddressBytes();\n                    var rhsBytes = rhs.GetAddressBytes();\n\n                    if (lhsBytes.Length != rhsBytes.Length)\n                    {\n                        return lhsBytes.Length < rhsBytes.Length;\n                    }\n\n                    // Prefer IANA private IPv4 address ranges 10.x.x.x, 192.168.x.x, 172.16-31.x.x over other addresses.\n                    if (lhs.AddressFamily is AddressFamily.InterNetwork && rhs.AddressFamily is AddressFamily.InterNetwork)\n                    {\n                        var lhsPref = GetPreferredSubnetRank(lhs);\n                        var rhsPref = GetPreferredSubnetRank(rhs);\n                        if (lhsPref != rhsPref)\n                        {\n                            return lhsPref < rhsPref;\n                        }\n                    }\n\n                    // Compare starting from most significant octet.\n                    // 10.68.20.21 < 10.98.05.04\n                    return lhsBytes.AsSpan().SequenceCompareTo(rhsBytes.AsSpan()) < 0;\n                }\n\n                static int GetPreferredSubnetRank(IPAddress ip)\n                {\n                    var ipBytes = ip.GetAddressBytes();\n                    Span<byte> masked = stackalloc byte[ipBytes.Length];\n                    var i = 0;\n                    foreach (var (Address, SubnetMask) in PreferredRanges)\n                    {\n                        ipBytes.CopyTo(masked);\n                        var subnetMaskBytes = SubnetMask.GetAddressBytes();\n                        if (ipBytes.Length != subnetMaskBytes.Length)\n                        {\n                            continue;\n                        }\n\n                        And(ipBytes, subnetMaskBytes, masked);\n                        if (masked.SequenceEqual(Address.GetAddressBytes()))\n                        {\n                            return i;\n                        }\n\n                        ++i;\n                    }\n\n                    return PreferredRanges.Length;\n                    static void And(ReadOnlySpan<byte> lhs, ReadOnlySpan<byte> rhs, Span<byte> result)\n                    {\n                        Debug.Assert(lhs.Length == rhs.Length);\n                        Debug.Assert(lhs.Length == result.Length);\n\n                        for (var i = 0; i < lhs.Length; i++)\n                        {\n                            result[i] = (byte)(lhs[i] & rhs[i]);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/KubernetesClusterAgent.cs",
    "content": "using k8s;\nusing k8s.Autorest;\nusing k8s.Models;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Hosting.Kubernetes\n{\n    /// <summary>\n    /// Reflects cluster configuration changes between Orleans and Kubernetes.\n    /// </summary>\n    public sealed partial class KubernetesClusterAgent : ILifecycleParticipant<ISiloLifecycle>\n    {\n        private const string ExampleRoleBinding =\n            \"\"\"\n            kind: Role\n            apiVersion: rbac.authorization.k8s.io/v1\n            metadata:\n              name: pod-updater\n            rules:\n            - apiGroups: [ \"\" ]\n              resources: [\"pods\"]\n              verbs: [\"get\", \"watch\", \"list\", \"patch\"]\n            ---\n            kind: RoleBinding\n            apiVersion: rbac.authorization.k8s.io/v1\n            metadata:\n              name: pod-updater-binding\n            subjects:\n            - kind: ServiceAccount\n              name: default\n              apiGroup: ''\n            roleRef:\n              kind: Role\n              name: pod-updater\n              apiGroup: ''\n            \"\"\";\n\n        private readonly IOptionsMonitor<KubernetesHostingOptions> _options;\n        private readonly ClusterOptions _clusterOptions;\n        private readonly IClusterMembershipService _clusterMembershipService;\n        private readonly KubernetesClientConfiguration _config;\n        private readonly k8s.Kubernetes _client;\n        private readonly string _podLabelSelector;\n        private readonly string _podNamespace;\n        private readonly string _podName;\n        private readonly ILocalSiloDetails _localSiloDetails;\n        private readonly ILogger<KubernetesClusterAgent> _logger;\n        private readonly CancellationTokenSource _shutdownToken;\n        private readonly SemaphoreSlim _pauseMonitoringSemaphore = new SemaphoreSlim(0);\n        private volatile bool _enableMonitoring;\n        private Task _runTask;\n\n        public KubernetesClusterAgent(\n            IClusterMembershipService clusterMembershipService,\n            ILogger<KubernetesClusterAgent> logger,\n            IOptionsMonitor<KubernetesHostingOptions> options,\n            IOptions<ClusterOptions> clusterOptions,\n            ILocalSiloDetails localSiloDetails)\n        {\n            _localSiloDetails = localSiloDetails;\n            _logger = logger;\n            _shutdownToken = new CancellationTokenSource();\n            _options = options;\n            _clusterOptions = clusterOptions.Value;\n            _clusterMembershipService = clusterMembershipService;\n            _config = _options.CurrentValue.GetClientConfiguration?.Invoke() ?? throw new ArgumentNullException(nameof(KubernetesHostingOptions) + \".\" + nameof(KubernetesHostingOptions.GetClientConfiguration));\n            _client = new k8s.Kubernetes(_config);\n            _podLabelSelector = $\"{KubernetesHostingOptions.ServiceIdLabel}={_clusterOptions.ServiceId},{KubernetesHostingOptions.ClusterIdLabel}={_clusterOptions.ClusterId}\";\n            _podNamespace = _options.CurrentValue.Namespace;\n            _podName = _options.CurrentValue.PodName;\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(KubernetesClusterAgent),\n                ServiceLifecycleStage.AfterRuntimeGrainServices,\n                OnStart,\n                OnStop);\n        }\n\n        private async Task OnStart(CancellationToken cancellation)\n        {\n            var attempts = 0;\n            while (!cancellation.IsCancellationRequested)\n            {\n                try\n                {\n                    await AddClusterOptionsToPodLabels(cancellation);\n\n                    // Find the currently known cluster members first, before interrogating Kubernetes\n                    await _clusterMembershipService.Refresh();\n                    var snapshot = _clusterMembershipService.CurrentSnapshot.Members;\n\n                    // Find the pods which correspond to this cluster\n                    var pods = await _client.ListNamespacedPodAsync(\n                        namespaceParameter: _podNamespace,\n                        labelSelector: _podLabelSelector,\n                        cancellationToken: cancellation);\n                    var clusterPods = new HashSet<string> { _podName };\n                    foreach (var pod in pods.Items)\n                    {\n                        clusterPods.Add(pod.Metadata.Name);\n                    }\n\n                    var known = new HashSet<string>();\n                    var knownMap = new Dictionary<string, ClusterMember>();\n                    known.Add(_podName);\n                    foreach (var member in snapshot.Values)\n                    {\n                        if (member.Status == SiloStatus.Dead)\n                        {\n                            continue;\n                        }\n\n                        known.Add(member.Name);\n                        knownMap[member.Name] = member;\n                    }\n\n                    var unknownPods = new List<string>(clusterPods.Except(known));\n                    unknownPods.Sort();\n                    foreach (var pod in unknownPods)\n                    {\n                        LogWarningUnknownPod(pod);\n\n                        // Delete the pod once it has been active long enough?\n                    }\n\n                    var unmatched = new List<string>(known.Except(clusterPods));\n                    unmatched.Sort();\n                    foreach (var pod in unmatched)\n                    {\n                        var siloAddress = knownMap[pod];\n                        if (siloAddress.Status is not SiloStatus.Active)\n                        {\n                            continue;\n                        }\n\n                        LogWarningSiloWithoutPod(siloAddress);\n                        await _clusterMembershipService.TryKill(siloAddress.SiloAddress);\n                    }\n\n                    break;\n                }\n                catch (HttpOperationException exception) when (exception.Response.StatusCode is System.Net.HttpStatusCode.Forbidden)\n                {\n                    LogErrorInsufficientPermissions(exception);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorInitializing(exception);\n                    if (++attempts > _options.CurrentValue.MaxKubernetesApiRetryAttempts)\n                    {\n                        throw;\n                    }\n\n                    await Task.Delay(1000, cancellation);\n                }\n            }\n\n            // Start monitoring loop\n            ThreadPool.UnsafeQueueUserWorkItem(_ => _runTask = Task.WhenAll(Task.Run(MonitorOrleansClustering), Task.Run(MonitorKubernetesPods)), null);\n        }\n\n        private async Task AddClusterOptionsToPodLabels(CancellationToken cancellation)\n        {\n            // Propagate our configured cluster membership options to our pod\n            var thisPod = await _client.ReadNamespacedPodAsync(_podName, namespaceParameter: _podNamespace, cancellationToken: cancellation);\n\n            var labels = thisPod.Labels();\n            if (labels is null\n                || !labels.TryGetValue(KubernetesHostingOptions.ServiceIdLabel, out var sidVal) || !string.Equals(_clusterOptions.ServiceId, sidVal, StringComparison.Ordinal)\n                || !labels.TryGetValue(KubernetesHostingOptions.ClusterIdLabel, out var cidVal) || !string.Equals(_clusterOptions.ClusterId, cidVal, StringComparison.Ordinal))\n            {\n                var patch =\n                    $$\"\"\"\n                    {\n                        \"metadata\": {\n                            \"labels\": {\n                                \"{{KubernetesHostingOptions.ClusterIdLabel}}\": \"{{_clusterOptions.ClusterId}}\",\n                                \"{{KubernetesHostingOptions.ServiceIdLabel}}\": \"{{_clusterOptions.ServiceId}}\"\n                            }\n                        }\n                    }\n                    \"\"\";\n                await _client.PatchNamespacedPodAsync(new V1Patch(patch, V1Patch.PatchType.MergePatch), _podName, _podNamespace, cancellationToken: cancellation);\n            }\n        }\n\n        public async Task OnStop(CancellationToken cancellationToken)\n        {\n            _shutdownToken.Cancel();\n            _enableMonitoring = false;\n            _pauseMonitoringSemaphore.Release();\n\n            if (_runTask is not null)\n            {\n                await Task.WhenAny(_runTask, Task.Delay(TimeSpan.FromMinutes(1), cancellationToken));\n            }\n        }\n\n        private async Task MonitorOrleansClustering()\n        {\n            var previous = _clusterMembershipService.CurrentSnapshot;\n            while (!_shutdownToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await foreach (var update in _clusterMembershipService.MembershipUpdates.WithCancellation(_shutdownToken.Token))\n                    {\n                        // Determine which silos should be monitoring Kubernetes\n                        var chosenSilos = _clusterMembershipService.CurrentSnapshot.Members.Values\n                            .Where(s => s.Status == SiloStatus.Active)\n                            .OrderBy(s => s.SiloAddress)\n                            .Take(_options.CurrentValue.MaxAgents)\n                            .ToList();\n\n                        if (!_enableMonitoring && chosenSilos.Exists(s => s.SiloAddress.Equals(_localSiloDetails.SiloAddress)))\n                        {\n                            _enableMonitoring = true;\n                            _pauseMonitoringSemaphore.Release(1);\n                        }\n                        else if (_enableMonitoring)\n                        {\n                            _enableMonitoring = false;\n                        }\n\n                        if (_enableMonitoring && _options.CurrentValue.DeleteDefunctSiloPods)\n                        {\n                            var delta = update.CreateUpdate(previous);\n                            foreach (var change in delta.Changes)\n                            {\n                                if (change.SiloAddress.Equals(_localSiloDetails.SiloAddress))\n                                {\n                                    // Ignore all changes for this silo\n                                    continue;\n                                }\n\n                                if (change.Status == SiloStatus.Dead)\n                                {\n                                    try\n                                    {\n                                        LogInformationDeletingDeadSiloPod(change.SiloAddress, change.Name, _podNamespace);\n\n                                        await _client.DeleteNamespacedPodAsync(change.Name, _podNamespace);\n                                    }\n                                    catch (Exception exception)\n                                    {\n                                        // Ignore NotFound errors, as the pod may have already been deleted by other means\n                                        if (exception is not HttpOperationException { Response.StatusCode: HttpStatusCode.NotFound })\n                                        {\n                                            LogErrorDeletingPod(exception, change.Name, _podNamespace, change.SiloAddress);\n                                        }\n                                    }\n                                }\n                            }\n                        }\n\n                        previous = update;\n                    }\n                }\n                catch (OperationCanceledException) when (_shutdownToken.IsCancellationRequested)\n                {\n                }\n                catch (Exception exception)\n                {\n                    LogDebugErrorMonitoringCluster(exception);\n\n                    if (!_shutdownToken.IsCancellationRequested)\n                    {\n                        await Task.Delay(5000);\n                    }\n                }\n            }\n        }\n\n        private async Task MonitorKubernetesPods()\n        {\n            while (!_shutdownToken.IsCancellationRequested)\n            {\n                try\n                {\n                    if (!_enableMonitoring)\n                    {\n                        // Wait on the semaphore to avoid spinning in a tight loop.\n                        await _pauseMonitoringSemaphore.WaitAsync();\n                        continue;\n                    }\n\n                    if (_shutdownToken.IsCancellationRequested)\n                    {\n                        break;\n                    }\n\n                    var pods = _client.CoreV1.WatchListNamespacedPodAsync(\n                        namespaceParameter: _podNamespace,\n                        labelSelector: _podLabelSelector,\n                        cancellationToken: _shutdownToken.Token);\n\n                    await foreach (var (eventType, pod) in pods.WithCancellation(_shutdownToken.Token))\n                    {\n                        if (!_enableMonitoring || _shutdownToken.IsCancellationRequested)\n                        {\n                            break;\n                        }\n\n                        if (string.Equals(pod.Metadata.Name, _podName, StringComparison.Ordinal))\n                        {\n                            // Never declare ourselves dead this way.\n                            continue;\n                        }\n\n                        if (eventType == WatchEventType.Modified)\n                        {\n                            // TODO: Remember silo addresses for pods that are restarting/terminating\n                        }\n\n                        if (eventType == WatchEventType.Deleted)\n                        {\n                            if (this.TryMatchSilo(pod, out var member) && member.Status != SiloStatus.Dead)\n                            {\n                                LogInformationDeclaringServerDead(member.SiloAddress, pod.Metadata.Name);\n\n                                await _clusterMembershipService.TryKill(member.SiloAddress);\n                            }\n                        }\n                    }\n\n                    if (_enableMonitoring && !_shutdownToken.IsCancellationRequested)\n                    {\n                        LogDebugUnexpectedEndOfStream();\n\n                        await Task.Delay(5000);\n                    }\n                }\n                catch (Exception exception) when (!(_shutdownToken.IsCancellationRequested && exception is OperationCanceledException))\n                {\n                    LogErrorMonitoringPods(exception);\n                    if (!_shutdownToken.IsCancellationRequested)\n                    {\n                        await Task.Delay(5000);\n                    }\n                }\n            }\n        }\n\n        private bool TryMatchSilo(V1Pod pod, out ClusterMember server)\n        {\n            var snapshot = _clusterMembershipService.CurrentSnapshot;\n            foreach (var member in snapshot.Members)\n            {\n                if (string.Equals(member.Value.Name, pod.Metadata.Name, StringComparison.Ordinal))\n                {\n                    server = member.Value;\n                    return true;\n                }\n            }\n\n            server = default;\n            return false;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Pod {PodName} does not correspond to any known silos\"\n        )]\n        private partial void LogWarningUnknownPod(string podName);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Silo {SiloAddress} does not correspond to any known pod. Marking it as dead.\"\n        )]\n        private partial void LogWarningSiloWithoutPod(ClusterMember siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = $\"Unable to monitor pods due to insufficient permissions. Ensure that this pod has an appropriate Kubernetes role binding. Here is an example role binding:\\n{ExampleRoleBinding}\"\n        )]\n        private partial void LogErrorInsufficientPermissions(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error while initializing Kubernetes cluster agent\"\n        )]\n        private partial void LogErrorInitializing(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Silo {SiloAddress} is dead, proceeding to delete the corresponding pod, {PodName}, in namespace {PodNamespace}\"\n        )]\n        private partial void LogInformationDeletingDeadSiloPod(SiloAddress siloAddress, string podName, string podNamespace);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error deleting pod {PodName} in namespace {PodNamespace} corresponding to defunct silo {SiloAddress}\"\n        )]\n        private partial void LogErrorDeletingPod(Exception exception, string podName, string podNamespace, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Error while monitoring cluster changes\"\n        )]\n        private partial void LogDebugErrorMonitoringCluster(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unexpected end of stream from Kubernetes API. Will try again.\"\n        )]\n        private partial void LogDebugUnexpectedEndOfStream();\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error monitoring Kubernetes pods\"\n        )]\n        private partial void LogErrorMonitoringPods(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Declaring server {Silo} dead since its corresponding pod, {Pod}, has been deleted\"\n        )]\n        private partial void LogInformationDeclaringServerDead(SiloAddress silo, string pod);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/KubernetesHostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting.Kubernetes;\nusing Orleans.Runtime;\nusing System;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for hosting a silo in Kubernetes.\n    /// </summary>\n    public static class KubernetesHostingExtensions\n    {\n        /// <summary>\n        /// Adds Kubernetes hosting support.\n        /// </summary>\n        public static ISiloBuilder UseKubernetesHosting(this ISiloBuilder siloBuilder)\n        {\n            return siloBuilder.ConfigureServices(services => services.UseKubernetesHosting(configureOptions: null));\n        }\n\n        /// <summary>\n        /// Adds Kubernetes hosting support.\n        /// </summary>\n        public static ISiloBuilder UseKubernetesHosting(this ISiloBuilder siloBuilder, Action<OptionsBuilder<KubernetesHostingOptions>> configureOptions)\n        {\n            return siloBuilder.ConfigureServices(services => services.UseKubernetesHosting(configureOptions));\n        }\n\n        /// <summary>\n        /// Adds Kubernetes hosting support.\n        /// </summary>\n        public static IServiceCollection UseKubernetesHosting(this IServiceCollection services) => services.UseKubernetesHosting(configureOptions: null);\n\n        /// <summary>\n        /// Adds Kubernetes hosting support.\n        /// </summary>\n        public static IServiceCollection UseKubernetesHosting(this IServiceCollection services, Action<OptionsBuilder<KubernetesHostingOptions>> configureOptions)\n        {\n            configureOptions?.Invoke(services.AddOptions<KubernetesHostingOptions>());\n\n            // Configure defaults based on the current environment.\n            services.AddSingleton<IConfigureOptions<ClusterOptions>, ConfigureKubernetesHostingOptions>();\n            services.AddSingleton<IConfigureOptions<SiloOptions>, ConfigureKubernetesHostingOptions>();\n            services.AddSingleton<IPostConfigureOptions<EndpointOptions>, ConfigureKubernetesHostingOptions>();\n            services.AddSingleton<IConfigureOptions<KubernetesHostingOptions>, ConfigureKubernetesHostingOptions>();\n            services.AddSingleton<IValidateOptions<KubernetesHostingOptions>, KubernetesHostingOptionsValidator>();\n\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, KubernetesClusterAgent>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/KubernetesHostingOptions.cs",
    "content": "using k8s;\nusing System;\n\nnamespace Orleans.Hosting.Kubernetes\n{\n    /// <summary>\n    /// Options for hosting in Kubernetes.\n    /// </summary>\n    public sealed class KubernetesHostingOptions\n    {\n        private readonly Lazy<KubernetesClientConfiguration> _clientConfiguration;\n\n        /// <summary>\n        /// The environment variable for specifying the Kubernetes namespace which all silos in this cluster belong to.\n        /// </summary>\n        public const string PodNamespaceEnvironmentVariable = \"POD_NAMESPACE\";\n\n        /// <summary>\n        /// The environment variable for specifying the name of the Kubernetes pod which this silo is executing in.\n        /// </summary>\n        public const string PodNameEnvironmentVariable = \"POD_NAME\";\n\n        /// <summary>\n        /// The environment variable for specifying the IP address of this pod.\n        /// </summary>\n        public const string PodIPEnvironmentVariable = \"POD_IP\";\n\n        /// <summary>\n        /// The environment variable for specifying <see cref=\"Orleans.Configuration.ClusterOptions.ClusterId\"/>.\n        /// </summary>\n        public const string ClusterIdEnvironmentVariable = \"ORLEANS_CLUSTER_ID\";\n\n        /// <summary>\n        /// The environment variable for specifying <see cref=\"Orleans.Configuration.ClusterOptions.ServiceId\"/>.\n        /// </summary>\n        public const string ServiceIdEnvironmentVariable = \"ORLEANS_SERVICE_ID\";\n\n        /// <summary>\n        /// The name of the <see cref=\"Orleans.Configuration.ClusterOptions.ServiceId\"/> label on the pod.\n        /// </summary>\n        public const string ServiceIdLabel = \"orleans/serviceId\";\n\n        /// <summary>\n        /// The name of the <see cref=\"Orleans.Configuration.ClusterOptions.ClusterId\"/> label on the pod.\n        /// </summary>\n        public const string ClusterIdLabel = \"orleans/clusterId\";\n\n        public KubernetesHostingOptions()\n        {\n            _clientConfiguration = new Lazy<KubernetesClientConfiguration>(() => this.GetClientConfiguration());\n        }\n\n        /// <summary>\n        /// Gets the client configuration.\n        /// </summary>\n        internal KubernetesClientConfiguration ClientConfiguration => _clientConfiguration.Value;\n\n        /// <summary>\n        /// The delegate used to get an instance of <see cref=\"KubernetesClientConfiguration\"/>.\n        /// </summary>\n        public Func<KubernetesClientConfiguration> GetClientConfiguration { get; set; } = KubernetesClientConfiguration.InClusterConfig;\n\n        /// <summary>\n        /// The number of silos in the cluster which should monitor Kubernetes.\n        /// </summary>\n        /// <remarks>\n        /// Setting this to a small number can reduce the load on the Kubernetes API server.\n        /// </remarks>\n        public int MaxAgents { get; set; } = 2;\n\n        /// <summary>\n        /// Gets or sets the maximum number of attempts to retry Kubernetes API calls.\n        /// </summary>\n        public int MaxKubernetesApiRetryAttempts { get; set; } = 10;\n\n        /// <summary>\n        /// Whether or not to delete pods which correspond to silos which have become defunct since this silo became active.\n        /// </summary>\n        public bool DeleteDefunctSiloPods { get; set; } = false;\n\n        /// <summary>\n        /// The Kubernetes namespace which this silo and all other silos belong to.\n        /// </summary>\n        internal string Namespace { get; set; }\n\n        /// <summary>\n        /// The name of the Kubernetes pod which this silo is executing in.\n        /// </summary>\n        internal string PodName { get; set; }\n\n        /// <summary>\n        /// The PodIP of the Kubernetes pod which this silo is executing in.\n        /// </summary>\n        internal string PodIP { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/KubernetesHostingOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\nusing System.Collections.Generic;\n\nnamespace Orleans.Hosting.Kubernetes\n{\n    /// <summary>\n    /// Validates <see cref=\"KubernetesHostingOptions\"/>.\n    /// </summary>\n    internal class KubernetesHostingOptionsValidator : IValidateOptions<KubernetesHostingOptions>\n    {\n        public ValidateOptionsResult Validate(string name, KubernetesHostingOptions options)\n        {\n            List<string> failures = default;\n            if (string.IsNullOrWhiteSpace(options.Namespace))\n            {\n                failures ??= new List<string>();\n                failures.Add($\"{nameof(KubernetesHostingOptions)}.{nameof(KubernetesHostingOptions.Namespace)} is not set. Set it via the {KubernetesHostingOptions.PodNamespaceEnvironmentVariable} environment variable\");\n            }\n\n            if (string.IsNullOrWhiteSpace(options.PodName))\n            {\n                failures ??= new List<string>();\n                failures.Add($\"{nameof(KubernetesHostingOptions)}.{nameof(KubernetesHostingOptions.PodName)} is not set. Set it via the {KubernetesHostingOptions.PodNameEnvironmentVariable} environment variable\");\n            }\n\n            if (failures is not null) return ValidateOptionsResult.Fail(failures);\n\n            return ValidateOptionsResult.Success;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Hosting.Kubernetes/Orleans.Hosting.Kubernetes.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Hosting.Kubernetes</PackageId>\n    <Title>Microsoft Orleans Hosting for Kubernetes</Title>\n    <Description>Microsoft Orleans hosting support for Kubernetes</Description>\n    <PackageTags>$(PackageTags) Kubernetes k8s</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"KubernetesClient\" />\n    <PackageReference Include=\"Microsoft.Extensions.Http\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableDictionary.cs",
    "content": "using System.Buffers;\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableDictionary<K, V> : IDictionary<K, V> where K : notnull\n{\n}\n\n[DebuggerTypeProxy(typeof(IDurableDictionaryDebugView<,>))]\n[DebuggerDisplay(\"Count = {Count}\")]\ninternal class DurableDictionary<K, V> : IDurableDictionary<K, V>, IDurableStateMachine where K : notnull\n{\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<K> _keyCodec;\n    private readonly IFieldCodec<V> _valueCodec;\n    private const byte VersionByte = 0;\n    private readonly Dictionary<K, V> _items = [];\n    private IStateMachineLogWriter? _storage;\n\n    protected DurableDictionary(IFieldCodec<K> keyCodec, IFieldCodec<V> valueCodec, SerializerSessionPool serializerSessionPool)\n    {\n        _keyCodec = keyCodec;\n        _valueCodec = valueCodec;\n        _serializerSessionPool = serializerSessionPool;\n    }\n\n    public DurableDictionary([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<K> keyCodec, IFieldCodec<V> valueCodec, SerializerSessionPool serializerSessionPool) : this(keyCodec, valueCodec, serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public V this[K key]\n    {\n        get => _items[key];\n\n        set\n        {\n            ApplySet(key, value);\n            AppendSet(key, value);\n        }\n    }\n\n    public int Count => _items.Count;\n\n    public ICollection<K> Keys => _items.Keys;\n\n    public ICollection<V> Values => _items.Values;\n\n    public bool IsReadOnly => ((ICollection<KeyValuePair<K, V>>)_items).IsReadOnly;\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        _items.Clear();\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableDictionary<K, V>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.Set:\n                ApplySet(ReadKey(ref reader), ReadValue(ref reader));\n                break;\n            case CommandType.Remove:\n                ApplyRemove(ReadKey(ref reader));\n                break;\n            case CommandType.Clear:\n                ApplyClear();\n                break;\n            case CommandType.Snapshot:\n                ApplySnapshot(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        K ReadKey(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _keyCodec.ReadValue(ref reader, field);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        V ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _valueCodec.ReadValue(ref reader, field);\n        }\n\n        void ApplySnapshot(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var count = (int)reader.ReadVarUInt32();\n            _items.Clear();\n            _items.EnsureCapacity(count);\n            for (var i = 0; i < count; i++)\n            {\n                var key = ReadKey(ref reader);\n                var value = ReadValue(ref reader);\n                ApplySet(key, value);\n            }\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        // This state machine implementation appends log entries as the data structure is modified, so there is no need to perform separate writing here.\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter)\n    {\n        snapshotWriter.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Snapshot);\n            writer.WriteVarUInt32((uint)self._items.Count);\n            foreach (var (key, value) in self._items)\n            {\n                self._keyCodec.WriteField(ref writer, 0, typeof(K), key);\n                self._valueCodec.WriteField(ref writer, 0, typeof(V), value);\n            }\n\n            writer.Commit();\n        }, this);\n    }\n\n    public void Clear()\n    {\n        ApplyClear();\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            using var session = state._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Clear);\n            writer.Commit();\n        },\n        this);\n    }\n\n    public bool Contains(K key) => _items.ContainsKey(key);\n\n    public bool Remove(K key)\n    {\n        if (ApplyRemove(key))\n        {\n            AppendRemove(key);\n            return true;\n        }\n\n        return false;\n    }\n\n    private void AppendRemove(K key)\n    {\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, key) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Remove);\n            self._keyCodec.WriteField(ref writer, 0, typeof(K), key);\n            writer.Commit();\n        }, (this, key));\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n\n    private void AppendSet(K key, V value)\n    {\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, key, value) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Set);\n            self._keyCodec.WriteField(ref writer, 0, typeof(K), key);\n            self._valueCodec.WriteField(ref writer, 1, typeof(V), value);\n            writer.Commit();\n        },\n        (this, key, value));\n    }\n\n    protected virtual void OnSet(K key, V value) { }\n\n    private void ApplySet(K key, V value)\n    {\n        _items[key] = value;\n        OnSet(key, value);\n    }\n\n    internal bool ApplyRemove(K key) => _items.Remove(key);\n    private void ApplyClear() => _items.Clear();\n\n    protected virtual IStateMachineLogWriter GetStorage()\n    {\n        Debug.Assert(_storage is not null);\n        return _storage;\n    }\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n    public void Add(K key, V value)\n    {\n        _items.Add(key, value);\n        OnSet(key, value);\n        AppendSet(key, value);\n    }\n\n    public bool ContainsKey(K key) => _items.ContainsKey(key);\n    public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) => _items.TryGetValue(key, out value);\n    public void Add(KeyValuePair<K, V> item) => Add(item.Key, item.Value);\n    public bool Contains(KeyValuePair<K, V> item) => _items.Contains(item);\n    public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) => ((ICollection<KeyValuePair<K, V>>)_items).CopyTo(array, arrayIndex);\n    public bool Remove(KeyValuePair<K, V> item)\n    {\n        if (((ICollection<KeyValuePair<K, V>>)_items).Remove(item))\n        {\n            AppendRemove(item.Key);\n            return true;\n        }\n\n        return false;\n    }\n\n    public IEnumerator<KeyValuePair<K, V>> GetEnumerator() => ((IEnumerable<KeyValuePair<K, V>>)_items).GetEnumerator();\n\n    private enum CommandType\n    {\n        Set = 0,\n        Remove = 1,\n        Clear = 2,\n        Snapshot = 3 \n    }\n}\n\n[DebuggerDisplay(\"{Value}\", Name = \"[{Key}]\")]\ninternal readonly struct DebugViewDictionaryItem<TKey, TValue>\n{\n    public DebugViewDictionaryItem(TKey key, TValue value)\n    {\n        Key = key;\n        Value = value;\n    }\n\n    public DebugViewDictionaryItem(KeyValuePair<TKey, TValue> keyValue)\n    {\n        Key = keyValue.Key;\n        Value = keyValue.Value;\n    }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]\n    public TKey Key { get; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]\n    public TValue Value { get; }\n}\n\ninternal sealed class IDurableDictionaryDebugView<TKey, TValue> where TKey : notnull\n{\n    private readonly IDurableDictionary<TKey, TValue> _dict;\n\n    public IDurableDictionaryDebugView(IDurableDictionary<TKey, TValue> dictionary)\n    {\n        ArgumentNullException.ThrowIfNull(dictionary);\n        _dict = dictionary;\n    }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public DebugViewDictionaryItem<TKey, TValue>[] Items\n    {\n        get\n        {\n            var keyValuePairs = new KeyValuePair<TKey, TValue>[_dict.Count];\n            _dict.CopyTo(keyValuePairs, 0);\n            var items = new DebugViewDictionaryItem<TKey, TValue>[keyValuePairs.Length];\n            for (int i = 0; i < items.Length; i++)\n            {\n                items[i] = new DebugViewDictionaryItem<TKey, TValue>(keyValuePairs[i]);\n            }\n            return items;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Journaling;\n\npublic abstract class DurableGrain : Grain, IGrainBase\n{\n    protected DurableGrain()\n    {\n        StateMachineManager = ServiceProvider.GetRequiredService<IStateMachineManager>();\n        if (StateMachineManager is ILifecycleParticipant<IGrainLifecycle> participant)\n        {\n            participant.Participate(((IGrainBase)this).GrainContext.ObservableLifecycle);\n        }\n    }\n\n    protected IStateMachineManager StateMachineManager { get; }\n\n    protected TStateMachine GetOrCreateStateMachine<TStateMachine>(string name) where TStateMachine : class, IDurableStateMachine\n        => GetOrCreateStateMachine(name, static sp => sp.GetRequiredService<TStateMachine>(), ServiceProvider);\n\n    protected TStateMachine GetOrCreateStateMachine<TState, TStateMachine>(string name, Func<TState, TStateMachine> createStateMachine, TState state) where TStateMachine : class, IDurableStateMachine\n    {\n        if (StateMachineManager.TryGetStateMachine(name, out var stateMachine))\n        {\n            return stateMachine as TStateMachine\n                ?? throw new InvalidOperationException($\"A state machine named '{name}' already exists with an incompatible type {stateMachine.GetType()} versus {typeof(TStateMachine)}\");\n        }\n\n        var result = createStateMachine(state);\n        StateMachineManager.RegisterStateMachine(name, result);\n        return result;\n    }\n\n    protected ValueTask WriteStateAsync(CancellationToken cancellationToken = default) => StateMachineManager.WriteStateAsync(cancellationToken);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableList.cs",
    "content": "using System.Buffers;\nusing System.Collections;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableList<T> : IList<T>\n{\n    void AddRange(IEnumerable<T> collection);\n    ReadOnlyCollection<T> AsReadOnly();\n}\n\n[DebuggerTypeProxy(typeof(IDurableCollectionDebugView<>))]\n[DebuggerDisplay(\"Count = {Count}\")]\ninternal sealed class DurableList<T> : IDurableList<T>, IDurableStateMachine\n{\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private const byte VersionByte = 0;\n    private readonly List<T> _items = [];\n    private IStateMachineLogWriter? _storage;\n\n    public DurableList([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<T> codec, SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public T this[int index]\n    {\n        get => _items[index];\n\n        set\n        {\n            if ((uint)index >= (uint)_items.Count)\n            {\n                ThrowIndexOutOfRange();\n            }\n\n            ApplySet(index, value);\n            GetStorage().AppendEntry(static (state, bufferWriter) =>\n            {\n                var (self, index, value) = state;\n                using var session = self._serializerSessionPool.GetSession();\n                var writer = Writer.Create(bufferWriter, session);\n                writer.WriteByte(VersionByte);\n                writer.WriteVarUInt32((uint)CommandType.Set);\n                writer.WriteVarUInt32((uint)index);\n                self._codec.WriteField(ref writer, 0, typeof(T), value!);\n                writer.Commit();\n            },\n            (this, index, value));\n        }\n    }\n\n    public int Count => _items.Count;\n\n    bool ICollection<T>.IsReadOnly => false;\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        _items.Clear();\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableList<T>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.Add:\n                ApplyAdd(ReadValue(ref reader));\n                break;\n            case CommandType.Set:\n                {\n                    var index = (int)reader.ReadVarUInt32();\n                    var value = ReadValue(ref reader);\n                    ApplySet(index, value);\n                }\n                break;\n            case CommandType.Insert:\n                {\n                    var index = (int)reader.ReadVarUInt32();\n                    var value = ReadValue(ref reader);\n                    ApplyInsert(index, value);\n                }\n                break;\n            case CommandType.Remove:\n                ApplyRemoveAt((int)reader.ReadVarUInt32());\n                break;\n            case CommandType.Clear:\n                ApplyClear();\n                break;\n            case CommandType.Snapshot:\n                ApplySnapshot(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        T ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        void ApplySnapshot(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var count = reader.ReadVarUInt32();\n            ApplyClear();\n            _items.EnsureCapacity((int)count);\n            for (var i = 0; i < count; i++)\n            {\n                ApplyAdd(ReadValue(ref reader));\n            }\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        // This state machine implementation appends log entries as the data structure is modified, so there is no need to perform separate writing here.\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter)\n    {\n        snapshotWriter.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Snapshot);\n            writer.WriteVarUInt32((uint)self._items.Count);\n            foreach (var item in self._items)\n            {\n                self._codec.WriteField(ref writer, 0, typeof(T), item);\n            }\n\n            writer.Commit();\n        }, this);\n    }\n\n    public void Add(T item)\n    {\n        ApplyAdd(item);\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, item) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Add);\n            self._codec.WriteField(ref writer, 0, typeof(T), item!);\n            writer.Commit();\n        },\n        (this, item));\n    }\n\n    public void Clear()\n    {\n        ApplyClear();\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            using var session = state._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Clear);\n            writer.Commit();\n        },\n        this);\n    }\n\n    public bool Contains(T item) => _items.Contains(item);\n    public void CopyTo(T[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex);\n    public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();\n    public int IndexOf(T item) => _items.IndexOf(item);\n    public void Insert(int index, T item)\n    {\n        ApplyInsert(index, item);\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, index, value) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Insert);\n            writer.WriteVarUInt32((uint)index);\n            self._codec.WriteField(ref writer, 0, typeof(T), value!);\n            writer.Commit();\n        },\n        (this, index, item));\n    }\n\n    public bool Remove(T item)\n    {\n        var index = _items.IndexOf(item);\n        if (index >= 0)\n        {\n            RemoveAt(index);\n            return true;\n        }\n\n        return false;\n    }\n\n    public void RemoveAt(int index)\n    {\n        ApplyRemoveAt(index);\n\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, index) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Remove);\n            writer.WriteVarUInt32((uint)index);\n            writer.Commit();\n        }, (this, index));\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n\n    protected void ApplyAdd(T item) => _items.Add(item);\n    protected void ApplySet(int index, T item) => _items[index] = item;\n    protected void ApplyInsert(int index, T item) => _items.Insert(index, item);\n    protected void ApplyRemoveAt(int index) => _items.RemoveAt(index);\n    protected void ApplyClear() => _items.Clear();\n\n    [DoesNotReturn]\n    private static void ThrowIndexOutOfRange() => throw new ArgumentOutOfRangeException(\"index\", \"Index was out of range. Must be non-negative and less than the size of the collection\");\n\n    private IStateMachineLogWriter GetStorage()\n    {\n        Debug.Assert(_storage is not null);\n        return _storage;\n    }\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n    public void AddRange(IEnumerable<T> collection)\n    {\n        foreach (var element in collection)\n        {\n            Add(element);\n        }\n    }\n\n    public ReadOnlyCollection<T> AsReadOnly() => _items.AsReadOnly();\n\n    private enum CommandType\n    {\n        Add = 0,\n        Set = 1,\n        Insert = 2,\n        Remove = 3,\n        Clear = 4,\n        Snapshot = 5\n    }\n}\n\ninternal sealed class IDurableCollectionDebugView<T>\n{\n    private readonly ICollection<T> _collection;\n\n    public IDurableCollectionDebugView(ICollection<T> collection)\n    {\n#if NET\n        ArgumentNullException.ThrowIfNull(collection);\n#else\n            if (collection is null)\n            {\n                throw new ArgumentNullException(nameof(collection));\n            }\n#endif\n\n        _collection = collection;\n    }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public T[] Items\n    {\n        get\n        {\n            T[] items = new T[_collection.Count];\n            _collection.CopyTo(items, 0);\n            return items;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Journaling/DurableNothing.cs",
    "content": "using System.Buffers;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// A durable object which does nothing, used for retiring other durable types.\n/// </summary>\npublic interface IDurableNothing\n{\n}\n\n/// <summary>\n/// A durable object which does nothing, used for retiring other durable types.\n/// </summary>\ninternal sealed class DurableNothing : IDurableNothing, IDurableStateMachine\n{\n    public DurableNothing([ServiceKey] string key, IStateMachineManager manager)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        manager.RegisterStateMachine(key, this);\n    }\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage) { }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry) { }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter) { }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter) { }\n\n    public IDurableStateMachine DeepCopy() => this;\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableQueue.cs",
    "content": "﻿using System.Buffers;\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableQueue<T> : IEnumerable<T>, IReadOnlyCollection<T>\n{\n    void Clear();\n    bool Contains(T item);\n    void CopyTo(T[] array, int arrayIndex);\n    T Dequeue();\n    void Enqueue(T item);\n    T Peek();\n    bool TryDequeue([MaybeNullWhen(false)] out T item);\n    bool TryPeek([MaybeNullWhen(false)] out T item);\n}\n\n[DebuggerTypeProxy(typeof(DurableQueueDebugView<>))]\n[DebuggerDisplay(\"Count = {Count}\")]\ninternal sealed class DurableQueue<T> : IDurableQueue<T>, IDurableStateMachine\n{\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private const byte VersionByte = 0;\n    private readonly Queue<T> _items = new();\n    private IStateMachineLogWriter? _storage;\n\n    public DurableQueue([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<T> codec, SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public int Count => _items.Count;\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        _items.Clear();\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableQueue<T>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.Enqueue:\n                ApplyEnqueue(ReadValue(ref reader));\n                break;\n            case CommandType.Dequeue:\n                _ = ApplyDequeue();\n                break;\n            case CommandType.Clear:\n                ApplyClear();\n                break;\n            case CommandType.Snapshot:\n                ApplySnapshot(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        T ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        void ApplySnapshot(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var count = (int)reader.ReadVarUInt32();\n            ApplyClear();\n            _items.EnsureCapacity(count);\n            for (var i = 0; i < count; i++)\n            {\n                ApplyEnqueue(ReadValue(ref reader));\n            }\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        // This state machine implementation appends log entries as the data structure is modified, so there is no need to perform separate writing here.\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter)\n    {\n        snapshotWriter.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Snapshot);\n            writer.WriteVarUInt32((uint)self._items.Count);\n            foreach (var item in self._items)\n            {\n                self._codec.WriteField(ref writer, 0, typeof(T), item);\n            }\n\n            writer.Commit();\n        }, this);\n    }\n\n    public void Clear()\n    {\n        ApplyClear();\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            using var session = state._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Clear);\n            writer.Commit();\n        },\n        this);\n    }\n\n    public T Peek() => _items.Peek();\n    public bool TryPeek([MaybeNullWhen(false)] out T item) => _items.TryPeek(out item);\n    public bool Contains(T item) => _items.Contains(item);\n    public void CopyTo(T[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex);\n    public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();\n    public void Enqueue(T item)\n    {\n        ApplyEnqueue(item);\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var (self, value) = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Enqueue);\n            self._codec.WriteField(ref writer, 0, typeof(T), value!);\n            writer.Commit();\n        },\n        (this, item));\n    }\n\n    public T Dequeue()\n    {\n        var result = ApplyDequeue();\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            var self = state;\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Dequeue);\n            writer.Commit();\n        }, this);\n        return result;\n    }\n\n    public bool TryDequeue([MaybeNullWhen(false)] out T item)\n    {\n        if (ApplyTryDequeue(out item))\n        {\n            GetStorage().AppendEntry(static (state, bufferWriter) =>\n            {\n                var self = state;\n                using var session = self._serializerSessionPool.GetSession();\n                var writer = Writer.Create(bufferWriter, session);\n                writer.WriteByte(VersionByte);\n                writer.WriteVarUInt32((uint)CommandType.Dequeue);\n                writer.Commit();\n            }, this);\n            return true;\n        }\n\n        return false;\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n\n    protected void ApplyEnqueue(T item) => _items.Enqueue(item);\n    protected T ApplyDequeue() => _items.Dequeue();\n    protected bool ApplyTryDequeue([MaybeNullWhen(false)] out T value) => _items.TryDequeue(out value);\n    protected void ApplyClear() => _items.Clear();\n\n    [DoesNotReturn]\n    private static void ThrowIndexOutOfRange() => throw new ArgumentOutOfRangeException(\"index\", \"Index was out of range. Must be non-negative and less than the size of the collection\");\n\n    private IStateMachineLogWriter GetStorage()\n    {\n        Debug.Assert(_storage is not null);\n        return _storage;\n    }\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n\n    private enum CommandType\n    {\n        Enqueue = 0,\n        Dequeue = 1,\n        Clear = 2,\n        Snapshot = 3,\n    }\n}\n\ninternal sealed class DurableQueueDebugView<T>\n{\n    private readonly DurableQueue<T> _queue;\n\n    public DurableQueueDebugView(DurableQueue<T> queue)\n    {\n        ArgumentNullException.ThrowIfNull(queue);\n\n        _queue = queue;\n    }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public T[] Items\n    {\n        get\n        {\n            return _queue.ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableSet.cs",
    "content": "﻿using System.Buffers;\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableSet<T> : ISet<T>, IReadOnlyCollection<T>, IReadOnlySet<T>\n{\n    new int Count { get; }\n    new bool Contains(T item);\n    new bool Add(T item);\n    new bool IsProperSubsetOf(IEnumerable<T> other);\n    new bool IsProperSupersetOf(IEnumerable<T> other);\n    new bool IsSubsetOf(IEnumerable<T> other);\n    new bool IsSupersetOf(IEnumerable<T> other);\n    new bool Overlaps(IEnumerable<T> other);\n    new bool SetEquals(IEnumerable<T> other);\n}\n\n[DebuggerTypeProxy(typeof(IDurableCollectionDebugView<>))]\n[DebuggerDisplay(\"Count = {Count}\")]\ninternal sealed class DurableSet<T> : IDurableSet<T>, IDurableStateMachine\n{\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private const byte VersionByte = 0;\n    private readonly HashSet<T> _items = [];\n    private IStateMachineLogWriter? _storage;\n\n    public DurableSet([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<T> codec, SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public int Count => _items.Count;\n    public bool IsReadOnly => false;\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        _items.Clear();\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableSet<T>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.Add:\n                ApplyAdd(ReadValue(ref reader));\n                break;\n            case CommandType.Remove:\n                ApplyRemove(ReadValue(ref reader));\n                break;\n            case CommandType.Clear:\n                ApplyClear();\n                break;\n            case CommandType.Snapshot:\n                ApplySnapshot(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        T ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        void ApplySnapshot(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var count = (int)reader.ReadVarUInt32();\n            ApplyClear();\n            _items.EnsureCapacity(count);\n            for (var i = 0; i < count; i++)\n            {\n                ApplyAdd(ReadValue(ref reader));\n            }\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        // This state machine implementation appends log entries as the data structure is modified, so there is no need to perform separate writing here.\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter)\n    {\n        snapshotWriter.AppendEntry(WriteSnapshotToBufferWriter, this);\n    }\n\n    private static void WriteSnapshotToBufferWriter(DurableSet<T> self, IBufferWriter<byte> bufferWriter)\n    {\n        using var session = self._serializerSessionPool.GetSession();\n        var writer = Writer.Create(bufferWriter, session);\n        writer.WriteByte(VersionByte);\n        writer.WriteVarUInt32((uint)CommandType.Snapshot);\n        writer.WriteVarUInt32((uint)self._items.Count);\n        foreach (var item in self._items)\n        {\n            self._codec.WriteField(ref writer, 0, typeof(T), item);\n        }\n\n        writer.Commit();\n    }\n\n    public void Clear()\n    {\n        ApplyClear();\n        GetStorage().AppendEntry(static (state, bufferWriter) =>\n        {\n            using var session = state._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.Clear);\n            writer.Commit();\n        },\n        this);\n    }\n\n    public bool Contains(T item) => _items.Contains(item);\n    public void CopyTo(T[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex);\n    public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();\n    public bool Add(T item)\n    {\n        if (ApplyAdd(item))\n        {\n            GetStorage().AppendEntry(static (state, bufferWriter) =>\n            {\n                var (self, item) = state;\n                using var session = self._serializerSessionPool.GetSession();\n                var writer = Writer.Create(bufferWriter, session);\n                writer.WriteByte(VersionByte);\n                writer.WriteVarUInt32((uint)CommandType.Add);\n                self._codec.WriteField(ref writer, 0, typeof(T), item!);\n                writer.Commit();\n            },\n            (this, item));\n            return true;\n        }\n\n        return false;\n    }\n\n    public bool Remove(T item)\n    {\n        if (ApplyRemove(item))\n        {\n            GetStorage().AppendEntry(static (state, bufferWriter) =>\n            {\n                var (self, item) = state;\n                using var session = self._serializerSessionPool.GetSession();\n                var writer = Writer.Create(bufferWriter, session);\n                writer.WriteByte(VersionByte);\n                writer.WriteVarUInt32((uint)CommandType.Remove);\n                self._codec.WriteField(ref writer, 0, typeof(T), item!);\n                writer.Commit();\n            },\n            (this, item));\n            return true;\n        }\n\n        return false;\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n\n    protected bool ApplyAdd(T item) => _items.Add(item);\n    protected bool ApplyRemove(T item) => _items.Remove(item);\n    protected void ApplyClear() => _items.Clear();\n\n    [DoesNotReturn]\n    private static void ThrowIndexOutOfRange() => throw new ArgumentOutOfRangeException(\"index\", \"Index was out of range. Must be non-negative and less than the size of the collection\");\n\n    private IStateMachineLogWriter GetStorage()\n    {\n        Debug.Assert(_storage is not null);\n        return _storage;\n    }\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n    public void ExceptWith(IEnumerable<T> other)\n    {\n        foreach (var item in other)\n        {\n            Remove(item);\n        }\n    }\n\n    public bool IsProperSubsetOf(IEnumerable<T> other) => _items.IsProperSubsetOf(other);\n    public bool IsProperSupersetOf(IEnumerable<T> other) => _items.IsProperSupersetOf(other);\n    public bool IsSubsetOf(IEnumerable<T> other) => _items.IsSubsetOf(other);\n    public bool IsSupersetOf(IEnumerable<T> other) => _items.IsSupersetOf(other);\n    public bool Overlaps(IEnumerable<T> other) => _items.Overlaps(other);\n    public bool SetEquals(IEnumerable<T> other) => _items.SetEquals(other);\n    void ICollection<T>.Add(T item) => Add(item);\n\n    public void IntersectWith(IEnumerable<T> other)\n    {\n        var initialCount = Count;\n        _items.IntersectWith(other);\n        if (Count != initialCount)\n        {\n            GetStorage().AppendEntry(WriteSnapshotToBufferWriter, this);\n        }\n    }\n\n    public void SymmetricExceptWith(IEnumerable<T> other)\n    {\n        var initialCount = Count;\n        _items.SymmetricExceptWith(other);\n        if (Count != initialCount)\n        {\n            GetStorage().AppendEntry(WriteSnapshotToBufferWriter, this);\n        }\n    }\n\n    public void UnionWith(IEnumerable<T> other)\n    {\n        foreach (var item in other)\n        {\n            Add(item);\n        }\n    }\n\n    private enum CommandType\n    {\n        Add = 0,\n        Remove = 1,\n        Clear = 2,\n        Snapshot = 3,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableState.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Core;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\n[DebuggerDisplay(\"{Value}\")]\ninternal sealed class DurableState<T> : IPersistentState<T>, IDurableStateMachine\n{\n    private const byte VersionByte = 0;\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private readonly IStateMachineManager _manager;\n    private T? _value;\n    private ulong _version;\n\n    public DurableState([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<T> codec, SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n        _manager = manager;\n    }\n\n    public Action? OnPersisted { get; set; }\n    T IStorage<T>.State\n    {\n        get => _value ??= Activator.CreateInstance<T>();\n        set => _value = value;\n    }\n\n    string IStorage.Etag => $\"{_version}\";\n    bool IStorage.RecordExists => _version > 0;\n\n    void IDurableStateMachine.OnWriteCompleted()\n    {\n        _version++;\n        OnPersisted?.Invoke();\n    }\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage) => _value = default;\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableState<T>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.ClearValue:\n                ClearValue(ref reader);\n                break;\n            case CommandType.SetValue:\n                SetValue(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        void SetValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            _value = _codec.ReadValue(ref reader, field);\n            _version = reader.ReadVarUInt64();\n        }\n\n        void ClearValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            _value = default;\n            _version = 0;\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter) => WriteState(logWriter);\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter) => WriteState(snapshotWriter);\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n\n    private void WriteState(StateMachineStorageWriter writer)\n    {\n        writer.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.SetValue);\n            self._codec.WriteField(ref writer, 0, typeof(T), self._value!);\n            writer.WriteVarUInt64(self._version);\n            writer.Commit();\n        }, this);\n    }\n\n    Task IStorage.ClearStateAsync() => ((IStorage)this).ClearStateAsync(CancellationToken.None);\n    async Task IStorage.ClearStateAsync(CancellationToken cancellationToken)\n    {\n        _value = default;\n        _version = 0;\n        await _manager.WriteStateAsync(cancellationToken);\n    }\n\n    Task IStorage.WriteStateAsync() => ((IStorage)this).WriteStateAsync(CancellationToken.None);\n    async Task IStorage.WriteStateAsync(CancellationToken cancellationToken) => await _manager.WriteStateAsync(cancellationToken);\n    Task IStorage.ReadStateAsync() => ((IStorage)this).ReadStateAsync(CancellationToken.None);\n    Task IStorage.ReadStateAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n\n    private enum CommandType\n    {\n        SetValue,\n        ClearValue,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableTaskCompletionSource.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableTaskCompletionSource<T>\n{\n    Task<T> Task { get; }\n    DurableTaskCompletionSourceState<T> State { get; }\n\n    bool TrySetCanceled();\n    bool TrySetException(Exception exception);\n    bool TrySetResult(T value);\n}\n\n[DebuggerDisplay(\"Status = {Status}\")]\ninternal sealed class DurableTaskCompletionSource<T> : IDurableTaskCompletionSource<T>, IDurableStateMachine\n{\n    private const byte SupportedVersion = 0;\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private readonly IFieldCodec<Exception> _exceptionCodec;\n    private readonly DeepCopier<T> _copier;\n    private readonly DeepCopier<Exception> _exceptionCopier;\n\n    private TaskCompletionSource<T> _completion = new(TaskCreationOptions.RunContinuationsAsynchronously);\n    private IStateMachineLogWriter? _storage;\n    private DurableTaskCompletionSourceStatus _status;\n    private T? _value;\n    private Exception? _exception;\n\n    public DurableTaskCompletionSource(\n        [ServiceKey] string key,\n        IStateMachineManager manager,\n        IFieldCodec<T> codec,\n        DeepCopier<T> copier,\n        IFieldCodec<Exception> exceptionCodec,\n        DeepCopier<Exception> exceptionCopier,\n        SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _copier = copier;\n        _exceptionCodec = exceptionCodec;\n        _exceptionCopier = exceptionCopier;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public bool TrySetResult(T value)\n    {\n        if (_status is not DurableTaskCompletionSourceStatus.Pending)\n        {\n            return false;\n        }\n\n        _status = DurableTaskCompletionSourceStatus.Completed;\n        _value = _copier.Copy(value);\n        return true;\n    }\n\n    public bool TrySetException(Exception exception)\n    {\n        if (_status is not DurableTaskCompletionSourceStatus.Pending)\n        {\n            return false;\n        }\n\n        _status = DurableTaskCompletionSourceStatus.Faulted;\n        _exception = _exceptionCopier.Copy(exception);\n        return true;\n    }\n\n    public bool TrySetCanceled()\n    {\n        if (_status is not DurableTaskCompletionSourceStatus.Pending)\n        {\n            return false;\n        }\n\n        _status = DurableTaskCompletionSourceStatus.Canceled;\n        return true;\n    }\n\n    public Task<T> Task => _completion.Task;\n\n    public DurableTaskCompletionSourceState<T> State => _status switch\n    {\n        DurableTaskCompletionSourceStatus.Pending => new DurableTaskCompletionSourceState<T> { Status = DurableTaskCompletionSourceStatus.Pending },\n        DurableTaskCompletionSourceStatus.Completed => new DurableTaskCompletionSourceState<T> { Status = DurableTaskCompletionSourceStatus.Completed, Value = _value },\n        DurableTaskCompletionSourceStatus.Faulted => new DurableTaskCompletionSourceState<T> { Status = DurableTaskCompletionSourceStatus.Faulted, Exception = _exception },\n        DurableTaskCompletionSourceStatus.Canceled => new DurableTaskCompletionSourceState<T> { Status = DurableTaskCompletionSourceStatus.Canceled },\n        _ => throw new InvalidOperationException($\"Unexpected status, \\\"{_status}\\\"\"),\n    };\n\n    private void OnValuePersisted()\n    {\n        switch (_status)\n        {\n            case DurableTaskCompletionSourceStatus.Completed:\n                _completion.TrySetResult(_value!);\n                break;\n            case DurableTaskCompletionSourceStatus.Faulted:\n                _completion.TrySetException(_exception!);\n                break;\n            case DurableTaskCompletionSourceStatus.Canceled:\n                _completion.TrySetCanceled();\n                break;\n            default:\n                break;\n        }\n    }\n\n    void IDurableStateMachine.OnRecoveryCompleted() => OnValuePersisted();\n    void IDurableStateMachine.OnWriteCompleted() => OnValuePersisted();\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        // Reset the task completion source if necessary.\n        if (_completion.Task.IsCompleted)\n        {\n            _completion = new(TaskCreationOptions.RunContinuationsAsynchronously);\n        }\n\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != SupportedVersion)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableTaskCompletionSource<T>)} supports version {(uint)SupportedVersion} and not version {(uint)version}.\");\n        }\n\n        _status = (DurableTaskCompletionSourceStatus)reader.ReadByte();\n        switch (_status)\n        {\n            case DurableTaskCompletionSourceStatus.Completed:\n                _value = ReadValue(ref reader);\n                break;\n            case DurableTaskCompletionSourceStatus.Faulted:\n                _exception = ReadException(ref reader);\n                break;\n            default:\n                break;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        T ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        Exception ReadException(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _exceptionCodec.ReadValue(ref reader, field);\n        }\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        if (_status is not DurableTaskCompletionSourceStatus.Pending)\n        {\n            WriteState(logWriter);\n        }\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter) => WriteState(snapshotWriter);\n\n    private void WriteState(StateMachineStorageWriter writer)\n    {\n        writer.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(DurableTaskCompletionSource<T>.SupportedVersion);\n            var status = self._status;\n            writer.WriteByte((byte)status);\n            if (status is DurableTaskCompletionSourceStatus.Completed)\n            {\n                self._codec.WriteField(ref writer, 0, typeof(T), self._value!);\n            }\n            else if (status is DurableTaskCompletionSourceStatus.Faulted)\n            {\n                self._exceptionCodec.WriteField(ref writer, 0, typeof(Exception), self._exception!);\n            }\n\n            writer.Commit();\n        }, this);\n    }\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n}\n\n[GenerateSerializer]\npublic enum DurableTaskCompletionSourceStatus : byte\n{\n    Pending = 0,\n    Completed,\n    Faulted,\n    Canceled\n}\n\n[GenerateSerializer, Immutable]\npublic readonly struct DurableTaskCompletionSourceState<T>\n{\n    [Id(0)]\n    public DurableTaskCompletionSourceStatus Status { get; init; }\n\n    [Id(1)]\n    public T? Value { get; init; }\n\n    [Id(2)]\n    public Exception? Exception { get; init; }\n}\n\n"
  },
  {
    "path": "src/Orleans.Journaling/DurableValue.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\npublic interface IDurableValue<T>\n{\n    T? Value { get; set; }\n}\n\n[DebuggerDisplay(\"{Value}\")]\ninternal sealed class DurableValue<T> : IDurableValue<T>, IDurableStateMachine\n{\n    private const byte VersionByte = 0;\n    private readonly SerializerSessionPool _serializerSessionPool;\n    private readonly IFieldCodec<T> _codec;\n    private IStateMachineLogWriter? _storage;\n    private T? _value;\n    private bool _isDirty;\n\n    public DurableValue([ServiceKey] string key, IStateMachineManager manager, IFieldCodec<T> codec, SerializerSessionPool serializerSessionPool)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(key);\n        _codec = codec;\n        _serializerSessionPool = serializerSessionPool;\n        manager.RegisterStateMachine(key, this);\n    }\n\n    public T? Value\n    {\n        get => _value;\n        set\n        {\n            _value = value;\n            OnModified();\n        }\n    }\n\n    public Action? OnPersisted { get; set; }\n\n    private void OnValuePersisted() => OnPersisted?.Invoke();\n\n    public void OnModified() => _isDirty = true;\n\n    void IDurableStateMachine.OnRecoveryCompleted() => OnValuePersisted();\n    void IDurableStateMachine.OnWriteCompleted() => OnValuePersisted();\n\n    void IDurableStateMachine.Reset(IStateMachineLogWriter storage)\n    {\n        _value = default;\n        _storage = storage;\n    }\n\n    void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry)\n    {\n        using var session = _serializerSessionPool.GetSession();\n        var reader = Reader.Create(logEntry, session);\n        var version = reader.ReadByte();\n        if (version != VersionByte)\n        {\n            throw new NotSupportedException($\"This instance of {nameof(DurableValue<T>)} supports version {(uint)VersionByte} and not version {(uint)version}.\");\n        }\n\n        var commandType = (CommandType)reader.ReadVarUInt32();\n        switch (commandType)\n        {\n            case CommandType.SetValue:\n                SetValue(ref reader);\n                break;\n            default:\n                throw new NotSupportedException($\"Command type {commandType} is not supported\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        T ReadValue(ref Reader<ReadOnlySequenceInput> reader)\n        {\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        void SetValue(ref Reader<ReadOnlySequenceInput> reader) => _value = ReadValue(ref reader);\n    }\n\n    void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter)\n    {\n        if (_isDirty)\n        {\n            WriteState(logWriter);\n            _isDirty = false;\n        }\n    }\n\n    void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter) => WriteState(snapshotWriter);\n\n    public IDurableStateMachine DeepCopy() => throw new NotImplementedException();\n\n    private void WriteState(StateMachineStorageWriter writer)\n    {\n        writer.AppendEntry(static (self, bufferWriter) =>\n        {\n            using var session = self._serializerSessionPool.GetSession();\n            var writer = Writer.Create(bufferWriter, session);\n            writer.WriteByte(VersionByte);\n            writer.WriteVarUInt32((uint)CommandType.SetValue);\n            self._codec.WriteField(ref writer, 0, typeof(T), self._value!);\n            writer.Commit();\n        }, this);\n    }\n\n    [DoesNotReturn]\n    private static void ThrowIndexOutOfRange() => throw new ArgumentOutOfRangeException(\"index\", \"Index was out of range. Must be non-negative and less than the size of the collection\");\n\n    private IStateMachineLogWriter GetStorage()\n    {\n        Debug.Assert(_storage is not null);\n        return _storage;\n    }\n\n    private enum CommandType\n    {\n        SetValue,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/HostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.Configuration;\n\nnamespace Orleans.Journaling;\n\npublic static class HostingExtensions\n{\n    public static ISiloBuilder AddStateMachineStorage(this ISiloBuilder builder)\n    {\n        builder.Services.AddOptions<StateMachineManagerOptions>();\n        builder.Services.TryAddScoped<IStateMachineStorage>(sp => sp.GetRequiredService<IStateMachineStorageProvider>().Create(sp.GetRequiredService<IGrainContext>()));\n        builder.Services.TryAddScoped<IStateMachineManager, StateMachineManager>();\n        builder.Services.TryAddKeyedScoped(typeof(IDurableDictionary<,>), KeyedService.AnyKey, typeof(DurableDictionary<,>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableList<>), KeyedService.AnyKey, typeof(DurableList<>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableQueue<>), KeyedService.AnyKey, typeof(DurableQueue<>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableSet<>), KeyedService.AnyKey, typeof(DurableSet<>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableValue<>), KeyedService.AnyKey, typeof(DurableValue<>));\n        builder.Services.TryAddKeyedScoped(typeof(IPersistentState<>), KeyedService.AnyKey, typeof(DurableState<>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableTaskCompletionSource<>), KeyedService.AnyKey, typeof(DurableTaskCompletionSource<>));\n        builder.Services.TryAddKeyedScoped(typeof(IDurableNothing), KeyedService.AnyKey, typeof(DurableNothing));\n        return builder;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/IDurableStateMachine.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// Interface for a state machine which can be persisted to durable storage.\n/// </summary>\npublic interface IDurableStateMachine\n{\n    /// <summary>\n    /// Resets the state machine.\n    /// </summary>\n    /// <remarks>\n    /// If the state machine has any volatile state, it must be cleared by this method.\n    /// This method can be called at any point in the state machine's lifetime, including during recovery.\n    /// </remarks>\n    void Reset(IStateMachineLogWriter storage);\n\n    /// <summary>\n    /// Called during recovery to apply the provided log entry or snapshot.\n    /// </summary>\n    /// <param name=\"entry\">The log entry or snapshot.</param>\n    void Apply(ReadOnlySequence<byte> entry);\n\n    /// <summary>\n    /// Notifies the state machine that all prior log entries and snapshots have been applied.\n    /// </summary>\n    /// <remarks>\n    /// The state machine should not expect any additional <see cref=\"Apply\"/> calls after this method is called,\n    /// unless <see cref=\"Reset\"/> is called to reset the state machine to its initial state.\n    /// This method will be called before any <see cref=\"AppendEntries\"/> or <see cref=\"AppendSnapshot\"/> calls.\n    /// </remarks>\n    void OnRecoveryCompleted() { }\n\n    /// <summary>\n    /// Writes pending state changes to the log.\n    /// </summary>\n    /// <param name=\"writer\">The log writer.</param>\n    void AppendEntries(StateMachineStorageWriter writer);\n\n    /// <summary>\n    /// Writes a snapshot of the state machine to the provided writer.\n    /// </summary>\n    /// <param name=\"writer\">The log writer.</param>\n    void AppendSnapshot(StateMachineStorageWriter writer);\n\n    /// <summary>\n    /// Notifies the state machine that all prior log entries and snapshots which it has written have been written to stable storage.\n    /// </summary>\n    void OnWriteCompleted() { }\n\n    /// <summary>\n    /// Creates and returns a deep copy of this instance. All replicas must be independent such that changes to one do not affect any other.\n    /// </summary>\n    /// <returns>A replica of this instance.</returns>\n    IDurableStateMachine DeepCopy();\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/IStateMachineLogWriter.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// Provides functionality for writing out-of-band log entries to the log for the state machine which holds this instance.\n/// </summary>\npublic interface IStateMachineLogWriter\n{\n    /// <summary>\n    /// Appends an entry to the log for the state machine which holds this instance.\n    /// </summary>\n    /// <typeparam name=\"TState\">The state, passed to the <paramred name=\"action\"/> delegate.</typeparam>\n    /// <param name=\"action\">The delegate invoked to append a log entry.</param>\n    /// <param name=\"state\">The state passed to <paramref name=\"action\"/>.</param>\n    void AppendEntry<TState>(Action<TState, IBufferWriter<byte>> action, TState state);\n\n    /// <summary>\n    /// Appends an entry to the log for the state machine which holds this instance.\n    /// </summary>\n    /// <typeparam name=\"TState\">The state, passed to the <paramred name=\"action\"/> delegate.</typeparam>\n    /// <param name=\"action\">The delegate invoked to append a log entry.</param>\n    /// <param name=\"state\">The state passed to <paramref name=\"action\"/>.</param>\n    void AppendEntries<TState>(Action<TState, StateMachineStorageWriter> action, TState state);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/IStateMachineManager.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// Manages the state machines for a given grain.\n/// </summary>\npublic interface IStateMachineManager\n{\n    /// <summary>\n    /// Initializes the state machine manager.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> which represents the operation.</returns>\n    ValueTask InitializeAsync(CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Registers a state machine with the manager.\n    /// </summary>\n    /// <param name=\"name\">The state machine's stable identifier.</param>\n    /// <param name=\"stateMachine\">The state machine instance to register.</param>\n    void RegisterStateMachine(string name, IDurableStateMachine stateMachine);\n\n    /// <summary>\n    /// Registers a state machine with the manager.\n    /// </summary>\n    /// <param name=\"name\">The state machine's stable identifier.</param>\n    /// <param name=\"stateMachine\">The state machine instance to register.</param>\n    bool TryGetStateMachine(string name, [NotNullWhen(true)] out IDurableStateMachine? stateMachine);\n\n    /// <summary>\n    /// Prepares and persists an update to the log.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> which represents the operation.</returns>\n    ValueTask WriteStateAsync(CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Resets this instance, removing any persistent state.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> which represents the operation.</returns>\n    ValueTask DeleteStateAsync(CancellationToken cancellationToken);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/IStateMachineStorage.cs",
    "content": "namespace Orleans.Journaling;\n\n/// <summary>\n/// Provides storage for state machines.\n/// </summary>\npublic interface IStateMachineStorage\n{\n    /// <summary>\n    /// Returns an ordered collection of all log segments belonging to this instance.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>An ordered collection of all log segments belonging to this instance.</returns>\n    IAsyncEnumerable<LogExtent> ReadAsync(CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Replaces the log with the provided value atomically.\n    /// </summary>\n    /// <param name=\"value\">The value to write.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> representing the operation.</returns>\n    ValueTask ReplaceAsync(LogExtentBuilder value, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Appends the provided segment to the log atomically.\n    /// </summary>\n    /// <param name=\"value\">The segment to append.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> representing the operation.</returns>\n    ValueTask AppendAsync(LogExtentBuilder value, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Deletes the state machine's log atomically.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A <see cref=\"ValueTask\"/> representing the operation.</returns>\n    ValueTask DeleteAsync(CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Gets a value indicating whether the state machine has requested a snapshot.\n    /// </summary>\n    bool IsCompactionRequested { get; }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/IStateMachineStorageProvider.cs",
    "content": "namespace Orleans.Journaling;\n\npublic interface IStateMachineStorageProvider\n{\n    IStateMachineStorage Create(IGrainContext grainContext);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/LogExtent.cs",
    "content": "using System.Buffers;\nusing System.Collections;\nusing Orleans.Serialization.Buffers;\nusing System.Diagnostics;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// Represents a log segment which has been sealed and is no longer mutable.\n/// </summary>\npublic sealed class LogExtent(ArcBuffer buffer) : IDisposable\n{\n    private ArcBuffer _buffer = buffer;\n\n    public LogExtent() : this(new())\n    {\n    }\n\n    public bool IsEmpty => _buffer.Length == 0;\n\n    internal EntryEnumerator Entries => EntryEnumerator.Create(this);\n\n    public void Dispose() => _buffer.Dispose();\n\n    public readonly record struct Entry(StateMachineId StreamId, ReadOnlySequence<byte> Payload);\n\n    internal struct EntryEnumerator : IEnumerable<Entry>, IEnumerator<Entry>, IDisposable\n    {\n        private LogExtent _logExtent;\n        private ReadOnlySequence<byte> _current;\n        private int _length;\n\n        private EntryEnumerator(LogExtent logExtent)\n        {\n            _logExtent = logExtent;\n            _current = logExtent._buffer.AsReadOnlySequence();\n            _length = -2;\n        }\n\n        public readonly EntryEnumerator GetEnumerator() => this;\n\n        public static EntryEnumerator Create(LogExtent logSegment) => new(logSegment);\n\n        public bool MoveNext()\n        {\n            if (_length == -1)\n            {\n                ThrowEnumerationNotStartedOrEnded();\n            }\n\n            if (_length >= 0)\n            {\n                // Advance the cursor.\n                _current = _current.Slice(_length);\n            }\n\n            if (_current.Length == 0)\n            {\n                _length = -1;\n                return false;\n            }\n\n            var reader = Reader.Create(_current, null);\n            _length = (int)reader.ReadVarUInt32();\n            _current = _current.Slice(reader.Position);\n            return true;\n        }\n\n        public readonly Entry Current\n        {\n            get\n            {\n                if (_length < 0)\n                {\n                    ThrowEnumerationNotStartedOrEnded();\n                }\n\n                var slice = _current.Slice(0, _length);\n                var reader = Reader.Create(slice, null);\n                var id = reader.ReadVarUInt32();\n                return new(new(id), slice.Slice(reader.Position));\n            }\n        }\n\n        private readonly void ThrowEnumerationNotStartedOrEnded()\n        {\n            Debug.Assert(_length is (-1) or (-2));\n            throw new InvalidOperationException(_length == -2 ? \"Enumeration has not started.\" : \"Enumeration has completed.\");\n        }\n\n        readonly object? IEnumerator.Current => Current;\n\n        public void Reset() => this = new(_logExtent);\n\n        public void Dispose() => _length = -1;\n\n        readonly IEnumerator<Entry> IEnumerable<Entry>.GetEnumerator() => GetEnumerator();\n        readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/LogExtentBuilder.ReadOnlyStream.cs",
    "content": "using System.Diagnostics;\nusing System.Numerics;\n\nnamespace Orleans.Journaling;\n\npublic sealed partial class LogExtentBuilder\n{\n    public sealed class ReadOnlyStream : Stream\n    {\n        private LogExtentBuilder? _builder;\n        private int _length;\n        private int _position;\n\n        public ReadOnlyStream() { }\n\n        public override bool CanRead => true;\n        public override bool CanSeek => true;\n        public override bool CanWrite => false;\n        public override long Length => _length;\n        public override long Position { get => _position; set => SetPosition((int)value); }\n\n        public override int Read(byte[] buffer, int offset, int count) => Read(buffer.AsSpan(offset, count));\n\n        public override int Read(Span<byte> buffer) => throw new NotImplementedException();\n\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            switch (origin)\n            {\n                case SeekOrigin.Begin:\n                    SetPosition((int)offset);\n                    break;\n                case SeekOrigin.Current:\n                    SetPosition(_position + (int)offset);\n                    break;\n                case SeekOrigin.End:\n                    SetPosition(_length - (int)offset);\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(origin));\n            }\n\n            return Position;\n        }\n\n        private void SetPosition(int value)\n        {\n            if (value > _length || value < 0) throw new ArgumentOutOfRangeException(nameof(value));\n            _position = value;\n        }\n\n        public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) => new(Read(buffer.Span));\n        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => Task.FromResult(Read(buffer, offset, count));\n\n        public override void CopyTo(Stream destination, int bufferSize)\n        {\n            ValidateCopyToArguments(destination, bufferSize);\n            _builder!.CopyToAsync(destination, bufferSize, default).AsTask().GetAwaiter().GetResult();\n        }\n\n        public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)\n        {\n            ValidateCopyToArguments(destination, bufferSize);\n\n            if (_position != 0) throw new NotImplementedException(\"Position must be zero for this copy operation\");\n            \n            return _builder!.CopyToAsync(destination, bufferSize, cancellationToken).AsTask();\n        }\n\n        public override void Flush() => throw GetReadOnlyException();\n        public override void WriteByte(byte value) => throw GetReadOnlyException();\n        public override void SetLength(long value) => throw GetReadOnlyException();\n        public override void Write(byte[] buffer, int offset, int count) => throw GetReadOnlyException();\n        public override void Write(ReadOnlySpan<byte> buffer) => throw GetReadOnlyException();\n        public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) => throw GetReadOnlyException();\n\n        public void SetBuilder(LogExtentBuilder builder)\n        {\n            _builder = builder;\n            _position = 0;\n            _length = ComputeLength();\n        }\n\n        public void Reset()\n        {\n            _builder = default;\n            _position = 0;\n            _length = 0;\n        }\n\n        private int ComputeLength()\n        {\n            Debug.Assert(_builder!._entryLengths is not null);\n            var length = _builder!._buffer.Length;\n            foreach (var entry in _builder!._entryLengths)\n            {\n                length += GetVarIntWidth(entry);\n            }\n\n            return length;\n        }\n\n        private static int GetVarIntWidth(uint value) => 1 + (int)((uint)BitOperations.Log2(value) / 7);\n\n        private static NotSupportedException GetReadOnlyException() => new(\"This stream is read-only\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/LogExtentBuilder.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\n\nnamespace Orleans.Journaling;\n\n/// <summary>\n/// A mutable builder for creating log segments.\n/// </summary>\npublic sealed partial class LogExtentBuilder(ArcBufferWriter buffer) : IDisposable, IBufferWriter<byte>\n{\n    private readonly List<uint> _entryLengths = [];\n    private readonly byte[] _scratch = new byte[8];\n    private readonly ArcBufferWriter _buffer = buffer;\n\n    public LogExtentBuilder() : this(new())\n    {\n    }\n\n    public long Length => _buffer.Length;\n\n    public byte[] ToArray()\n    {\n        using var memoryStream = new PooledBufferStream();\n        CopyTo(memoryStream, 4096);\n        return memoryStream.ToArray();\n    }\n\n    public StateMachineStorageWriter CreateLogWriter(StateMachineId id) => new(id, this);\n\n    public bool IsEmpty => _buffer.Length == 0;\n\n    internal void AppendEntry(StateMachineId id, byte[] value) => AppendEntry(id, (ReadOnlySpan<byte>)value);\n    internal void AppendEntry(StateMachineId id, Span<byte> value) => AppendEntry(id, (ReadOnlySpan<byte>)value);\n    internal void AppendEntry(StateMachineId id, Memory<byte> value) => AppendEntry(id, value.Span);\n    internal void AppendEntry(StateMachineId id, ReadOnlyMemory<byte> value) => AppendEntry(id, value.Span);\n    internal void AppendEntry(StateMachineId id, ArraySegment<byte> value) => AppendEntry(id, value.AsSpan());\n    internal void AppendEntry(StateMachineId id, ReadOnlySpan<byte> value)\n    {\n        var startOffset = _buffer.Length;\n        var writer = Writer.Create(this, session: null);\n        writer.WriteVarUInt64(id.Value);\n        writer.Commit();\n\n        _buffer.Write(value);\n\n        var endOffset = _buffer.Length;\n        _entryLengths.Add((uint)(endOffset - startOffset));\n    }\n\n    internal void AppendEntry(StateMachineId id, ReadOnlySequence<byte> value)\n    {\n        var startOffset = _buffer.Length;\n\n        var writer = Writer.Create(this, session: null);\n        writer.WriteVarUInt64(id.Value);\n        writer.Commit();\n\n        _buffer.Write(value);\n\n        var endOffset = _buffer.Length;\n        _entryLengths.Add((uint)(endOffset - startOffset));\n    }\n\n    internal void AppendEntry<T>(StateMachineId id, Action<T, IBufferWriter<byte>> valueWriter, T value)\n    {\n        var startOffset = _buffer.Length;\n\n        var writer = Writer.Create(this, session: null);\n        writer.WriteVarUInt64(id.Value);\n        writer.Commit();\n        valueWriter(value, this);\n\n        var endOffset = _buffer.Length;\n        _entryLengths.Add((uint)(endOffset - startOffset));\n    }\n\n    public void Reset()\n    {\n        _buffer.Reset();\n        _entryLengths.Clear();\n    }\n\n    public void Dispose() => Reset();\n\n    // Implemented on this class to prevent the need to repeatedly box & unbox _buffer.\n    void IBufferWriter<byte>.Advance(int count) => _buffer.AdvanceWriter(count);\n    Memory<byte> IBufferWriter<byte>.GetMemory(int sizeHint) => _buffer.GetMemory(sizeHint);\n    Span<byte> IBufferWriter<byte>.GetSpan(int sizeHint) => _buffer.GetSpan(sizeHint);\n\n    public async ValueTask CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)\n    {\n        using var buffer = _buffer.PeekSlice(_buffer.Length);\n        var segments = buffer.MemorySegments;\n        var currentSegment = ReadOnlyMemory<byte>.Empty;\n        foreach (var entryLength in _entryLengths)\n        {\n            await destination.WriteAsync(GetLengthBytes(_scratch, entryLength), cancellationToken);\n\n            var remainingEntryLength = entryLength;\n            while (remainingEntryLength > 0)\n            {\n                // Move to the next memory segment if necessary.\n                if (currentSegment.Length == 0)\n                {\n                    var hasNext = segments.MoveNext();\n                    Debug.Assert(hasNext);\n                    currentSegment = segments.Current;\n                    continue;\n                }\n\n                var copyLen = Math.Min((uint)bufferSize, Math.Min(remainingEntryLength, (uint)currentSegment.Length));\n\n                await destination.WriteAsync(currentSegment[..(int)copyLen], cancellationToken);\n\n                remainingEntryLength -= copyLen;\n                currentSegment = currentSegment[(int)copyLen..];\n            }\n        }\n    }\n\n    public void CopyTo(Stream destination, int bufferSize)\n    {\n        using var buffer = _buffer.PeekSlice(_buffer.Length);\n        var segments = buffer.MemorySegments;\n        var currentSegment = ReadOnlyMemory<byte>.Empty;\n        foreach (var entryLength in _entryLengths)\n        {\n            destination.Write(GetLengthBytes(_scratch, entryLength).Span);\n\n            var remainingEntryLength = entryLength;\n            while (remainingEntryLength > 0)\n            {\n                // Move to the next memory segment if necessary.\n                if (currentSegment.Length == 0)\n                {\n                    var hasNext = segments.MoveNext();\n                    Debug.Assert(hasNext);\n                    currentSegment = segments.Current;\n                    continue;\n                }\n\n                var copyLen = Math.Min((uint)bufferSize, Math.Min(remainingEntryLength, (uint)currentSegment.Length));\n\n                destination.Write(currentSegment[..(int)copyLen].Span);\n\n                remainingEntryLength -= copyLen;\n                currentSegment = currentSegment[(int)copyLen..];\n            }\n        }\n    }\n\n    private static ReadOnlyMemory<byte> GetLengthBytes(byte[] scratch, uint length)\n    {\n        var writer = Writer.Create(scratch, null);\n        writer.WriteVarUInt32(length);\n        return new ReadOnlyMemory<byte>(scratch, 0, writer.Position);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/Orleans.Journaling.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Journaling</PackageId>\n    <Title>Microsoft Orleans Journaling</Title>\n    <Description>Extensible persistence for grains based on replicated state machines.</Description>\n    <PackageTags>$(PackageTags) Persistence State Machines</PackageTags>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <Nullable>enable</Nullable>\n    <VersionSuffix Condition=\"$(VersionSuffix) != ''\">$(VersionSuffix).alpha.1</VersionSuffix>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Journaling.Tests\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Using Include=\"Orleans.Runtime\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Journaling/Properties/AssemblyInfo.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\n[assembly: Experimental(\"ORLEANSEXP005\")]\n"
  },
  {
    "path": "src/Orleans.Journaling/StateMachineId.cs",
    "content": "﻿namespace Orleans.Journaling;\n\n/// <summary>\n/// Identifies a state machine.\n/// </summary>\n/// <param name=\"Value\">The underlying identity value.</param>\npublic readonly record struct StateMachineId(ulong Value);\n"
  },
  {
    "path": "src/Orleans.Journaling/StateMachineManager.cs",
    "content": "using System.Buffers;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime.Internal;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Journaling;\n\ninternal sealed partial class StateMachineManager : IStateMachineManager, ILifecycleParticipant<IGrainLifecycle>, ILifecycleObserver, IDisposable\n{\n    private const int MinApplicationStateMachineId = 8;\n    private static readonly StringCodec StringCodec = new();\n    private static readonly UInt64Codec UInt64Codec = new();\n    private static readonly DateTimeCodec DateTimeCodec = new();\n#if NET9_0_OR_GREATER\n    private readonly Lock _lock = new();\n#else\n    private readonly object _lock = new();\n#endif\n    private readonly Dictionary<string, IDurableStateMachine> _stateMachines = new(StringComparer.Ordinal);\n    private readonly Dictionary<ulong, IDurableStateMachine> _stateMachinesMap = [];\n    private readonly IStateMachineStorage _storage;\n    private readonly ILogger<StateMachineManager> _logger;\n    private readonly TimeProvider _timeProvider;\n    private readonly SingleWaiterAutoResetEvent _workSignal = new() { RunContinuationsAsynchronously = true };\n    private readonly Queue<WorkItem> _workQueue = new();\n    private readonly CancellationTokenSource _shutdownCancellation = new();\n    private readonly StateMachineManagerState _stateMachineIds;\n    private readonly StateMachinesRetirementTracker _retirementTracker;\n    private readonly TimeSpan _retirementGracePeriod;\n    private Task? _workLoop;\n    private ManagerState _state;\n    private Task? _pendingWrite;\n    private ulong _nextStateMachineId = MinApplicationStateMachineId;\n    private LogExtentBuilder? _currentLogSegment;\n\n    public StateMachineManager(\n        IStateMachineStorage storage,\n        ILogger<StateMachineManager> logger,\n        IOptions<StateMachineManagerOptions> options,\n        SerializerSessionPool serializerSessionPool,\n        TimeProvider timeProvider)\n    {\n        _storage = storage;\n        _logger = logger;\n        _timeProvider = timeProvider;\n        _retirementGracePeriod = options.Value.RetirementGracePeriod;\n\n        // The list of known state machines is itself stored as a durable state machine with the implicit id 0.\n        // This allows us to recover the list of state machines ids without having to store it separately.\n        _stateMachineIds = new StateMachineManagerState(this, StringCodec, UInt64Codec, serializerSessionPool);\n        _stateMachinesMap[StateMachineManagerState.Id] = _stateMachineIds;\n\n        // The retirement tracker is a special internal state machine with a fixed id.\n        // It is not stored in _stateMachineIds and does not participate in the general name->id mapping.\n        _retirementTracker = new StateMachinesRetirementTracker(this, StringCodec, DateTimeCodec, serializerSessionPool);\n        _stateMachinesMap[StateMachinesRetirementTracker.Id] = _retirementTracker;\n    }\n\n    public void RegisterStateMachine(string name, IDurableStateMachine stateMachine)\n    {\n        ArgumentNullException.ThrowIfNullOrEmpty(name);\n        _shutdownCancellation.Token.ThrowIfCancellationRequested();\n\n        lock (_lock)\n        {\n            if (_stateMachines.TryGetValue(name, out var machine))\n            {\n                if (machine is RetiredStateMachineVessel vessel)\n                {\n                    // If the existing machine is a vessel for a retired one, it means the machine was loaded from a previous\n                    // log during recovery but has not been re-registered. We effectively are \"staging\" the resurrection of the machine.\n                    // The removal from the tracker is handled within the serialized loop. This is to prevent logical race conditions with the recovery process.\n                    // We also make sure to apply any buffered data that could have occured while the vessel took this machine's place.\n                    stateMachine.Reset(new StateMachineLogWriter(this, new(_stateMachineIds[name])));      \n                    foreach (var entry in vessel.BufferedData)\n                    {\n                        stateMachine.Apply(new ReadOnlySequence<byte>(entry));\n                    }\n                    _stateMachines[name] = stateMachine;\n                }\n                else\n                {\n                    // A real state machine is already registered with this name, this must be a developer error.\n                    throw new ArgumentException($\"A state machine with the key '{name}' has already been registered.\");\n                }\n            }\n            else\n            {\n                _stateMachines.Add(name, stateMachine);\n            }\n\n            _workQueue.Enqueue(new WorkItem(WorkItemType.RegisterStateMachine, completion: null)\n            {\n                Context = name\n            });\n        }\n\n        _workSignal.Signal();\n    }\n\n    public async ValueTask InitializeAsync(CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        _shutdownCancellation.Token.ThrowIfCancellationRequested();\n        Debug.Assert(_workLoop is null, \"InitializeAsync should only be called once.\");\n        _workLoop = Start();\n\n        Task task;\n        lock (_lock)\n        {\n            var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n            task = completion.Task;\n            _workQueue.Enqueue(new WorkItem(WorkItemType.Initialize, completion));\n        }\n\n        _workSignal.Signal();\n        await task;\n    }\n\n    private Task Start()\n    {\n        using var suppressExecutionContext = new ExecutionContextSuppressor();\n        return WorkLoop();\n    }\n\n    private async Task WorkLoop()\n    {\n        var cancellationToken = _shutdownCancellation.Token;\n        using var cancellationRegistration = cancellationToken.Register(state => ((StateMachineManager)state!)._workSignal.Signal(), this);\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding);\n        var needsRecovery = true;\n        while (true)\n        {\n            try\n            {\n                await _workSignal.WaitAsync().ConfigureAwait(true);\n                cancellationToken.ThrowIfCancellationRequested();\n\n                while (true)\n                {\n                    if (needsRecovery)\n                    {\n                        await RecoverAsync(cancellationToken).ConfigureAwait(true);\n                        needsRecovery = false;\n                    }\n\n                    WorkItem workItem;\n                    lock (_lock)\n                    {\n                        if (!_workQueue.TryDequeue(out workItem))\n                        {\n                            // Wait for the queue to be signaled again.\n                            break;\n                        }\n                    }\n\n                    try\n                    {\n                        // Note that the implementation of each command is inlined to avoid allocating unnecessary async state machines.\n                        // We are ok sacrificing some code organization for performance in the inner loop.\n                        if (workItem.Type is WorkItemType.AppendLog or WorkItemType.WriteSnapshot)\n                        {\n                            // TODO: decide whether it's best to snapshot or append. Eg, by summing the size of the most recent snapshots and the current log length.\n                            //       If the current log length is greater than the snapshot size, then take a snapshot instead of appending more log entries.\n                            var isSnapshot = workItem.Type is WorkItemType.WriteSnapshot;\n                            LogExtentBuilder? logSegment;\n\n                            lock (_lock)\n                            {\n                                if (isSnapshot)\n                                {\n                                    // If there are pending writes, reset them since they will be captured by the snapshot instead.\n                                    // If we did not do this, the log would begin with some writes which would be followed by a snapshot which also included those writes.\n                                    _currentLogSegment?.Reset();\n\n                                    if (_retirementTracker.Count > 0)\n                                    {\n                                        RetireOrResurectStateMachines();\n                                    }\n                                }\n\n                                _currentLogSegment ??= new();\n\n                                // The map of state machine ids is itself stored as a durable state machine with the id 0.\n                                // This must be stored first, since it includes the identities of all other state machines, which are needed when replaying the log.\n                                // If we removed retired machines, this snapshot will persist that change.\n                                AppendUpdatesOrSnapshotStateMachine(_currentLogSegment, isSnapshot, 0, _stateMachineIds);\n\n                                foreach (var (id, stateMachine) in _stateMachinesMap)\n                                {\n                                    if (id is 0 || stateMachine is null)\n                                    {\n                                        continue;\n                                    }\n\n                                    AppendUpdatesOrSnapshotStateMachine(_currentLogSegment, isSnapshot, id, stateMachine);\n                                }\n\n                                if (_currentLogSegment.IsEmpty)\n                                {\n                                    logSegment = null;\n                                }\n                                else\n                                {\n                                    logSegment = _currentLogSegment;\n                                    _currentLogSegment = null;\n                                }\n                            }\n\n                            if (logSegment is not null)\n                            {\n                                if (isSnapshot)\n                                {\n                                    await _storage.ReplaceAsync(logSegment, cancellationToken).ConfigureAwait(true);\n                                }\n                                else\n                                {\n                                    await _storage.AppendAsync(logSegment, cancellationToken).ConfigureAwait(true);\n                                }\n\n                                // Notify all state machines that the operation completed.\n                                lock (_lock)\n                                {\n                                    foreach (var stateMachine in _stateMachines.Values)\n                                    {\n                                        stateMachine.OnWriteCompleted();\n                                    }\n                                }\n                            }\n                        }\n                        else if (workItem.Type is WorkItemType.DeleteState)\n                        {\n                            // Clear storage.\n                            await _storage.DeleteAsync(cancellationToken).ConfigureAwait(true);\n\n                            lock (_lock)\n                            {\n                                // Reset the state machine id collection.\n                                _stateMachineIds.ResetVolatileState();\n\n                                // Allocate new state machine ids for each state machine.\n                                // Doing so will trigger a reset, since _stateMachineIds will call OnSetStateMachineId, which resets the state machine in question.\n                                _nextStateMachineId = 1;\n                                foreach (var (name, stateMachine) in _stateMachines)\n                                {\n                                    var id = _nextStateMachineId++;\n                                    _stateMachineIds[name] = id;\n                                }\n                            }\n                        }\n                        else if (workItem.Type is WorkItemType.Initialize)\n                        {\n                            lock (_lock)\n                            {\n                                _state = ManagerState.Ready;\n                            }\n                        }\n                        else if (workItem.Type is WorkItemType.RegisterStateMachine)\n                        {\n                            lock (_lock)\n                            {\n                                if (_state is not ManagerState.Unknown)\n                                {\n                                    throw new NotSupportedException(\"Registering a state machine after activation is not supported.\");\n                                }\n\n                                var name = (string)workItem.Context!;\n                                if (!_stateMachineIds.ContainsKey(name))\n                                {\n                                    // Doing so will trigger a reset, since _stateMachineIds will call OnSetStateMachineId, which resets the state machine in question.\n                                    _stateMachineIds[name] = _nextStateMachineId++;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            Debug.Fail($\"The command {workItem.Type} is unsupported\");\n                        }\n\n                        workItem.CompletionSource?.SetResult();\n                    }\n                    catch (Exception exception)\n                    {\n                        workItem.CompletionSource?.SetException(exception);\n                        needsRecovery = true;\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                needsRecovery = true;\n                if (cancellationToken.IsCancellationRequested)\n                {\n                    return;\n                }\n\n                LogErrorProcessingWorkItems(_logger, exception);\n            }\n        }\n    }\n\n    private void RetireOrResurectStateMachines()\n    {\n        foreach (var (name, timestamp) in _retirementTracker)\n        {\n            var isDuetime = _timeProvider.GetUtcNow().UtcDateTime - timestamp >= _retirementGracePeriod;\n            if (isDuetime && _stateMachineIds.TryGetValue(name, out var id))\n            {\n                var stateMachine = _stateMachines[name];\n\n                Debug.Assert(stateMachine is not null);\n\n                if (stateMachine is RetiredStateMachineVessel)\n                {\n                    LogRemovingRetiredStateMachine(_logger, name);\n\n                    // Since we are permanently removing this state machine, we will clean it up by reseting it.\n                    stateMachine.Reset(new StateMachineLogWriter(this, new(id)));\n\n                    _stateMachinesMap.Remove(id);\n                    // We remove these from memory only, since the snapshot will persist these changes.\n                    _stateMachineIds.ApplyRemove(name);\n                    _retirementTracker.ApplyRemove(name);\n                }\n                else\n                {\n                    LogRetiredStateMachineComebackDetected(_logger, name);\n                    // We remove the tracker from memory only, since the snapshot will persist the change.\n                    _retirementTracker.ApplyRemove(name);\n                }\n            }\n        }\n    }\n\n    private static void AppendUpdatesOrSnapshotStateMachine(LogExtentBuilder logSegment, bool isSnapshot, ulong id, IDurableStateMachine stateMachine)\n    {\n        var writer = logSegment.CreateLogWriter(new(id));\n        if (isSnapshot)\n        {\n            stateMachine.AppendSnapshot(writer);\n        }\n        else\n        {\n            stateMachine.AppendEntries(writer);\n        }\n    }\n\n    public async ValueTask DeleteStateAsync(CancellationToken cancellationToken)\n    {\n        Task task;\n        lock (_lock)\n        {\n            var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n            task = completion.Task;\n            _workQueue.Enqueue(new WorkItem(WorkItemType.DeleteState, completion));\n        }\n\n        _workSignal.Signal();\n        await task;\n    }\n\n    private async Task RecoverAsync(CancellationToken cancellationToken)\n    {\n        lock (_lock)\n        {\n            _stateMachineIds.ResetVolatileState();\n        }\n\n        await foreach (var segment in _storage.ReadAsync(cancellationToken).ConfigureAwait(true))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            try\n            {\n                foreach (var entry in segment.Entries)\n                {\n                    var stateMachine = _stateMachinesMap[entry.StreamId.Value];\n                    stateMachine.Apply(entry.Payload);\n                }\n            }\n            finally\n            {\n                segment.Dispose();\n            }\n        }\n\n        lock (_lock)\n        {\n            foreach ((var name, var stateMachine) in _stateMachines)\n            {\n                stateMachine.OnRecoveryCompleted();\n\n                if (stateMachine is RetiredStateMachineVessel)\n                {\n                    // We can use TryAdd since recovery has finished.\n                    if (_retirementTracker.TryAdd(name, _timeProvider.GetUtcNow().UtcDateTime))\n                    {\n                        LogRetiredStateMachineDetected(_logger, name);\n                    }\n                }\n            }\n        }\n    }\n\n    public async ValueTask WriteStateAsync(CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n\n        Task? pendingWrite;\n        var didEnqueue = false;\n        lock (_lock)\n        {\n            // If the pending write is faulted, recovery will need to be performed.\n            // For now, await it so that we can propagate the exception consistently.\n            if (_pendingWrite is not { IsFaulted: true })\n            {\n                var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n                _pendingWrite = completion.Task;\n                var workItemType = _storage.IsCompactionRequested switch\n                {\n                    true => WorkItemType.WriteSnapshot,\n                    false => WorkItemType.AppendLog,\n                };\n\n                _workQueue.Enqueue(new WorkItem(workItemType, completion));\n                didEnqueue = true;\n            }\n\n            pendingWrite = _pendingWrite;\n        }\n\n        if (didEnqueue)\n        {\n            _workSignal.Signal();\n        }\n\n        if (pendingWrite is { } task)\n        {\n            await task.WaitAsync(cancellationToken);\n        }\n    }\n\n    private void OnSetStateMachineId(string name, ulong id)\n    {\n        lock (_lock)\n        {\n            if (id >= _nextStateMachineId)\n            {\n                _nextStateMachineId = id + 1;\n            }\n\n            if (_stateMachines.TryGetValue(name, out var stateMachine))\n            {\n                _stateMachinesMap[id] = stateMachine;\n                stateMachine.Reset(new StateMachineLogWriter(this, new(id)));\n            }\n            else\n            {\n                var vessel = new RetiredStateMachineVessel();\n\n                // We must not make the vessel self-register with the manager, since it will\n                // result in a late-registration after the manager is 'ready'. Instead we add it inline here.\n\n                _stateMachines.Add(name, vessel);\n                _stateMachinesMap[id] = vessel;\n            }\n        }\n    }\n\n    public bool TryGetStateMachine(string name, [NotNullWhen(true)] out IDurableStateMachine? stateMachine) => _stateMachines.TryGetValue(name, out stateMachine);\n\n    void ILifecycleParticipant<IGrainLifecycle>.Participate(IGrainLifecycle observer) => observer.Subscribe(GrainLifecycleStage.SetupState, this);\n    Task ILifecycleObserver.OnStart(CancellationToken cancellationToken) => InitializeAsync(cancellationToken).AsTask();\n    async Task ILifecycleObserver.OnStop(CancellationToken cancellationToken)\n    {\n        _shutdownCancellation.Cancel();\n        _workSignal.Signal();\n        if (_workLoop is { } task)\n        {\n            await task.WaitAsync(cancellationToken).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing);\n        }\n    }\n\n    void IDisposable.Dispose()\n    {\n        _shutdownCancellation.Dispose();\n    }\n\n    private sealed class StateMachineLogWriter(StateMachineManager manager, StateMachineId streamId) : IStateMachineLogWriter\n    {\n        private readonly StateMachineManager _manager = manager;\n        private readonly StateMachineId _id = streamId;\n\n        public void AppendEntry<TState>(Action<TState, IBufferWriter<byte>> action, TState state)\n        {\n            lock (_manager._lock)\n            {\n                var segment = _manager._currentLogSegment ??= new();\n                var logWriter = segment.CreateLogWriter(_id);\n                logWriter.AppendEntry(action, state);\n            }\n        }\n\n        public void AppendEntries<TState>(Action<TState, StateMachineStorageWriter> action, TState state)\n        {\n            lock (_manager._lock)\n            {\n                var segment = _manager._currentLogSegment ??= new();\n                var logWriter = segment.CreateLogWriter(_id);\n                action(state, logWriter);\n            }\n        }\n    }\n\n    private readonly struct WorkItem(StateMachineManager.WorkItemType type, TaskCompletionSource? completion)\n    {\n        public WorkItemType Type { get; } = type;\n        public TaskCompletionSource? CompletionSource { get; } = completion;\n        public object? Context { get; init; }\n    }\n\n    private enum WorkItemType\n    {\n        Initialize,\n        AppendLog,\n        WriteSnapshot,\n        DeleteState,\n        RegisterStateMachine\n    }\n\n    private enum ManagerState\n    {\n        Unknown,\n        Ready\n    }\n\n    private sealed class StateMachineManagerState(\n        StateMachineManager manager,\n        IFieldCodec<string> keyCodec,\n        IFieldCodec<ulong> valueCodec,\n        SerializerSessionPool serializerSessionPool) : DurableDictionary<string, ulong>(keyCodec, valueCodec, serializerSessionPool)\n    {\n        public const int Id = 0;\n\n        private readonly StateMachineManager _manager = manager;\n\n        public void ResetVolatileState() => ((IDurableStateMachine)this).Reset(new StateMachineLogWriter(_manager, new(Id)));\n\n        protected override void OnSet(string key, ulong value) => _manager.OnSetStateMachineId(key, value);\n    }\n\n    /// <summary>\n    /// Used to track state machines that are not registered via user-code anymore, until time-based purging has elapsed.\n    /// </summary>\n    /// <remarks>Resurrecting of retired machines is supported.</remarks>\n    private sealed class StateMachinesRetirementTracker(\n        StateMachineManager manager, IFieldCodec<string> keyCodec, IFieldCodec<DateTime> valueCodec, SerializerSessionPool sessionPool)\n            : DurableDictionary<string, DateTime>(keyCodec, valueCodec, sessionPool)\n    {\n        public const int Id = 1;\n\n        private readonly StateMachineLogWriter _logWriter = new(manager, new(Id));\n\n        protected override IStateMachineLogWriter GetStorage() => _logWriter;\n    }\n\n    /// <summary>\n    /// Used to keep retired machines into a purgatory state until time-based purging or if a comeback occurs.\n    /// This keeps buffering entries and dumps them back into the log upon compaction.\n    /// </summary>\n    [DebuggerDisplay(nameof(RetiredStateMachineVessel))]\n    private sealed class RetiredStateMachineVessel : IDurableStateMachine\n    {\n        private readonly List<byte[]> _bufferedData = [];\n\n        public ReadOnlyCollection<byte[]> BufferedData => _bufferedData.AsReadOnly();\n\n        void IDurableStateMachine.AppendSnapshot(StateMachineStorageWriter snapshotWriter)\n        {\n            foreach (var data in _bufferedData)\n            {\n                snapshotWriter.AppendEntry(data);\n            }\n        }\n\n        void IDurableStateMachine.Reset(IStateMachineLogWriter storage) => _bufferedData.Clear();\n        void IDurableStateMachine.Apply(ReadOnlySequence<byte> logEntry) => _bufferedData.Add(logEntry.ToArray());\n        void IDurableStateMachine.AppendEntries(StateMachineStorageWriter logWriter) { }\n        IDurableStateMachine IDurableStateMachine.DeepCopy() => throw new NotSupportedException();\n    }\n\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing work items.\")]\n    private static partial void LogErrorProcessingWorkItems(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"State machine \\\"{Name}\\\" was not found. I have substituted a placeholder for graceful time-based retirement.\")]\n    private static partial void LogRetiredStateMachineDetected(ILogger logger, string name);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"State machine \\\"{Name}\\\" was previously retired (but not removed), and has hence been re-introduced. \" +\n                  \"There is still time left before its permanent removal, so I will resurrect it.\")]\n    private static partial void LogRetiredStateMachineComebackDetected(ILogger logger, string name);\n\n    [LoggerMessage(\n        Level = LogLevel.Information,\n        Message = \"Removing retired state machine \\\"{Name}\\\" and its data. Operation will be durably persisted shortly after compaction has finalized.\")]\n    private static partial void LogRemovingRetiredStateMachine(ILogger logger, string name);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/StateMachineManagerOptions.cs",
    "content": "namespace Orleans.Journaling;\n\n/// <summary>\n/// Options to configure the <see cref=\"IStateMachineManager\"/>.\n/// </summary>\npublic sealed class StateMachineManagerOptions\n{\n    /// <summary>\n    /// Specifies the period of time to wait until the manager retires\n    /// a <see cref=\"IDurableStateMachine\"/> if its not registered in the manager anymore.\n    /// </summary>\n    /// <remarks>\n    /// <para>The act of retirement removes this state machine from the log.</para>\n    /// <para>If the state machine is reintroduced (within the grace period), than it will not be removed by the manager.</para>\n    /// <para>\n    /// This value represents the <b>minimum</b> time the fate of the state machine will be postponed.\n    /// The final decision can take longer - usually <see cref=\"RetirementGracePeriod\"/> + [time until next compaction occurs].\n    /// </para>\n    /// </remarks>\n    public TimeSpan RetirementGracePeriod { get; set; } = DEFAULT_RETIREMENT_GRACE_PERIOD;\n\n    /// <summary>\n    /// The default value of <see cref=\"RetirementGracePeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_RETIREMENT_GRACE_PERIOD = TimeSpan.FromDays(7);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/StateMachineStorageWriter.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Journaling;\n\npublic readonly struct StateMachineStorageWriter\n{\n    private readonly StateMachineId _id;\n    private readonly LogExtentBuilder _segment;\n\n    internal StateMachineStorageWriter(StateMachineId id, LogExtentBuilder segment)\n    {\n        _id = id;\n        _segment = segment;\n    }\n\n    public void AppendEntry(byte[] value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(Span<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(Memory<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(ReadOnlyMemory<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(ArraySegment<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(ReadOnlySpan<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry(ReadOnlySequence<byte> value) => _segment.AppendEntry(_id, value);\n    public void AppendEntry<T>(Action<T, IBufferWriter<byte>> valueWriter, T value) => _segment.AppendEntry(_id, valueWriter, value);\n}\n"
  },
  {
    "path": "src/Orleans.Journaling/VolatileStateMachineStorage.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing System.Collections.Concurrent;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Journaling;\n\npublic sealed class VolatileStateMachineStorageProvider : IStateMachineStorageProvider\n{\n    private readonly ConcurrentDictionary<GrainId, VolatileStateMachineStorage> _storage = new();\n    public IStateMachineStorage Create(IGrainContext grainContext) => _storage.GetOrAdd(grainContext.GrainId, _ => new VolatileStateMachineStorage());\n}\n\n/// <summary>\n/// An in-memory, volatile implementation of <see cref=\"IStateMachineStorage\"/> for non-durable use cases, such as development and testing.\n/// </summary>\npublic sealed class VolatileStateMachineStorage : IStateMachineStorage\n{\n    private readonly List<byte[]> _segments = [];\n\n    public bool IsCompactionRequested => _segments.Count > 10;\n\n    /// <inheritdoc/>\n    public async IAsyncEnumerable<LogExtent> ReadAsync([EnumeratorCancellation] CancellationToken cancellationToken)\n    {\n        await Task.CompletedTask;\n        using var buffer = new ArcBufferWriter();\n        foreach (var segment in _segments)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            buffer.Write(segment);\n            yield return new LogExtent(buffer.ConsumeSlice(segment.Length));\n        }\n    }\n\n    /// <inheritdoc/>\n    public ValueTask AppendAsync(LogExtentBuilder segment, CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        _segments.Add(segment.ToArray());\n        return default;\n    }\n\n    /// <inheritdoc/>\n    public ValueTask ReplaceAsync(LogExtentBuilder snapshot, CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        _segments.Clear();\n        _segments.Add(snapshot.ToArray());\n        return default;\n    }\n\n    public ValueTask DeleteAsync(CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        _segments.Clear();\n        return default;\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Hosting/MemoryGrainStorageProviderBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Runtime.Hosting.ProviderConfiguration;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"Memory\", \"GrainStorage\", \"Silo\", typeof(MemoryGrainStorageProviderBuilder))]\n\nnamespace Orleans.Runtime.Hosting.ProviderConfiguration;\n\ninternal sealed class MemoryGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddMemoryGrainStorage(name, (OptionsBuilder<MemoryGrainStorageOptions> optionsBuilder) => optionsBuilder.Configure<IServiceProvider>((options, services) =>\n        {\n            if (int.TryParse(configurationSection[nameof(options.NumStorageGrains)], out var nsg))\n            {\n                options.NumStorageGrains = nsg;\n            }\n\n            var serializerKey = configurationSection[\"SerializerKey\"];\n            if (!string.IsNullOrEmpty(serializerKey))\n            {\n                options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n            }\n        }));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Hosting/MemoryGrainStorageSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo host builder extensions\n    /// </summary>\n    public static class MemoryGrainStorageSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure silo to use memory grain storage as the default grain storage.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryGrainStorageAsDefault(this ISiloBuilder builder, Action<MemoryGrainStorageOptions> configureOptions)\n        {\n            return builder.AddMemoryGrainStorageAsDefault(ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use memory grain storage.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The name of the storage provider. This must match with the <c>StorageName</c> property specified when injecting state into a grain.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryGrainStorage(this ISiloBuilder builder, string name, Action<MemoryGrainStorageOptions> configureOptions)\n        {\n            return builder.AddMemoryGrainStorage(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configure silo to use memory grain storage as the default grain storage.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<MemoryGrainStorageOptions>> configureOptions = null)\n        {\n            return builder.AddMemoryGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configure silo to use memory grain storage.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The name of the storage provider. This must match with the <c>StorageName</c> property specified when injecting state into a grain.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<MemoryGrainStorageOptions>> configureOptions = null)\n        {\n            return builder\n                .ConfigureServices(services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<MemoryGrainStorageOptions>(name));\n                    services.AddTransient<IPostConfigureOptions<MemoryGrainStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<MemoryGrainStorageOptions>>();\n                    services.ConfigureNamedOptionForLogging<MemoryGrainStorageOptions>(name);\n                    services.AddGrainStorage(name, MemoryGrainStorageFactory.Create);\n                });\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Options/MemoryGrainStorageOptions.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Storage;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for MemoryGrainStorage\n    /// </summary>\n    public class MemoryGrainStorageOptions : IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Default number of queue storage grains.\n        /// </summary>\n        public const int NumStorageGrainsDefaultValue = 10;\n\n        /// <summary>\n        /// Gets or sets the number of store grains to use.\n        /// </summary>\n        public int NumStorageGrains { get; set; } = NumStorageGrainsDefaultValue;\n\n        /// <summary>\n        /// Gets or sets the stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n\n        /// <inheritdoc/>\n        public IGrainStorageSerializer GrainStorageSerializer { get; set; }\n\n        /// <summary>\n        /// Default init stage\n        /// </summary>\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n    }\n\n    /// <summary>\n    /// Validates <see cref=\"MemoryGrainStorageOptions\"/>.\n    /// </summary>\n    public class MemoryGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        private readonly MemoryGrainStorageOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryGrainStorageOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"name\">The name.</param>\n        public MemoryGrainStorageOptionsValidator(MemoryGrainStorageOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n        \n        /// <inheritdoc/>\n        public void ValidateConfiguration()\n        {\n            if (this.options.NumStorageGrains <= 0)\n                throw new OrleansConfigurationException(\n                    $\"Configuration for {nameof(MemoryGrainStorage)} {name} is invalid. {nameof(this.options.NumStorageGrains)} must be larger than 0.\");\n            if(this.options.InitStage < ServiceLifecycleStage.RuntimeGrainServices)\n                throw new OrleansConfigurationException(\n                   $\"Configuration for {nameof(MemoryGrainStorage)} {name} is invalid. {nameof(this.options.InitStage)} must be larger than {ServiceLifecycleStage.RuntimeGrainServices} since \" +\n                   $\"{nameof(MemoryGrainStorage)} depends on {nameof(MemoryStorageGrain)} to have grain environment to finish set up.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Orleans.Persistence.Memory.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Persistence.Memory</PackageId>\n    <Title>Microsoft Orleans grain persistence provider which holds state only in memory.</Title>\n    <Description>In-memory storage for Microsoft Orleans</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Persistence.Memory</AssemblyName>\n    <RootNamespace>Orleans.Persistence.Memory</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"TestExtensions\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Storage/MemoryStorage.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage.Internal;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// This is a simple in-memory grain implementation of a storage provider.\n    /// </summary>\n    /// <remarks>\n    /// This storage provider is ONLY intended for simple in-memory Development / Unit Test scenarios.\n    /// This class should NOT be used in Production environment,\n    ///  because [by-design] it does not provide any resilience\n    ///  or long-term persistence capabilities.\n    /// </remarks>\n    [DebuggerDisplay(\"MemoryStore:{\" + nameof(name) + \"}\")]\n    public partial class MemoryGrainStorage : IGrainStorage, IDisposable\n    {\n        private Lazy<IMemoryStorageGrain>[] storageGrains;\n        private readonly ILogger logger;\n        private readonly IActivatorProvider _activatorProvider;\n        private readonly IGrainStorageSerializer storageSerializer;\n\n        /// <summary> Name of this storage provider instance. </summary>\n        private readonly string name;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryGrainStorage\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The name.</param>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"defaultGrainStorageSerializer\">The default grain storage serializer.</param>\n        public MemoryGrainStorage(\n            string name,\n            MemoryGrainStorageOptions options,\n            ILogger<MemoryGrainStorage> logger,\n            IGrainFactory grainFactory,\n            IGrainStorageSerializer defaultGrainStorageSerializer,\n            IActivatorProvider activatorProvider)\n        {\n            this.name = name;\n            this.logger = logger;\n            _activatorProvider = activatorProvider;\n            this.storageSerializer = options.GrainStorageSerializer ?? defaultGrainStorageSerializer;\n\n            LogDebugInit(name, options.NumStorageGrains);\n            storageGrains = new Lazy<IMemoryStorageGrain>[options.NumStorageGrains];\n            for (int i = 0; i < storageGrains.Length; i++)\n            {\n                int idx = i; // Capture variable to avoid modified closure error\n                storageGrains[idx] = new Lazy<IMemoryStorageGrain>(() => grainFactory.GetGrain<IMemoryStorageGrain>(idx));\n            }\n        }\n\n        /// <inheritdoc/>\n        public virtual async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var key = MakeKey(grainType, grainId);\n\n            LogTraceRead(key);\n            IMemoryStorageGrain storageGrain = GetStorageGrain(key);\n            var state = await storageGrain.ReadStateAsync<ReadOnlyMemory<byte>>(key);\n            if (state != null)\n            {\n                var loadedState = ConvertFromStorageFormat<T>(state.State);\n                grainState.ETag = state.ETag;\n                grainState.State = loadedState ?? CreateInstance<T>();\n                grainState.RecordExists = loadedState != null;\n            }\n            else\n            {\n                grainState.ETag = null;\n                grainState.State = CreateInstance<T>();\n                grainState.RecordExists = false;\n            }\n        }\n\n        /// <inheritdoc/>\n        public virtual async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var key = MakeKey(grainType, grainId);\n            LogTraceWrite(key, grainState.State!, grainState.ETag);\n            IMemoryStorageGrain storageGrain = GetStorageGrain(key);\n            try\n            {\n                var data = ConvertToStorageFormat<T>(grainState.State);\n                var binaryGrainState = new GrainState<ReadOnlyMemory<byte>>(data, grainState.ETag)\n                {\n                    RecordExists = grainState.RecordExists\n                };\n                grainState.ETag = await storageGrain.WriteStateAsync(key, binaryGrainState);\n                grainState.RecordExists = true;\n            }\n            catch (MemoryStorageEtagMismatchException e)\n            {\n                throw e.AsInconsistentStateException();\n            }\n        }\n\n        /// <inheritdoc/>\n        public virtual async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var key = MakeKey(grainType, grainId);\n            LogTraceDelete(key, grainState.ETag);\n            IMemoryStorageGrain storageGrain = GetStorageGrain(key);\n            try\n            {\n                await storageGrain.DeleteStateAsync<ReadOnlyMemory<byte>>(key, grainState.ETag);\n                grainState.ETag = null;\n                grainState.RecordExists = false;\n                grainState.State = CreateInstance<T>();\n            }\n            catch (MemoryStorageEtagMismatchException e)\n            {\n                throw e.AsInconsistentStateException();\n            }\n        }\n\n        private static string MakeKey(string grainType, GrainId grainId) => $\"{grainType}/{grainId}\";\n\n        private IMemoryStorageGrain GetStorageGrain(string id)\n        {\n            var idx = (uint)id.GetHashCode() % (uint)storageGrains.Length;\n            return storageGrains[idx].Value;\n        }\n\n        /// <inheritdoc/>\n        public void Dispose() { }\n\n        /// <summary>\n        /// Deserialize from binary data\n        /// </summary>\n        /// <param name=\"data\">The serialized stored data</param>\n        internal T? ConvertFromStorageFormat<T>(ReadOnlyMemory<byte> data)\n        {\n            T? dataValue = default;\n            try\n            {\n                dataValue = this.storageSerializer.Deserialize<T>(data);\n            }\n            catch (Exception exc)\n            {\n                var sb = new StringBuilder();\n                if (data.ToArray().Length > 0)\n                {\n                    sb.AppendFormat(\"Unable to convert from storage format GrainStateEntity.Data={0}\", data);\n                }\n\n                if (dataValue != null)\n                {\n                    sb.AppendFormat(\"Data Value={0} Type={1}\", dataValue, dataValue.GetType());\n                }\n                LogError(sb, exc);\n                throw new AggregateException(sb.ToString(), exc);\n            }\n\n            return dataValue;\n        }\n\n        /// <summary>\n        /// Serialize to the storage format.\n        /// </summary>\n        /// <param name=\"grainState\">The grain state data to be serialized</param>\n        /// <remarks>\n        /// See:\n        /// http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx\n        /// for more on the JSON serializer.\n        /// </remarks>\n        internal ReadOnlyMemory<byte> ConvertToStorageFormat<T>(T grainState)\n        {\n            // Convert to binary format\n            return this.storageSerializer.Serialize<T>(grainState);\n        }\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Init: Name={Name} NumStorageGrains={NumStorageGrains}\"\n        )]\n        private partial void LogDebugInit(string name, int numStorageGrains);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Read Keys={Keys}\"\n        )]\n        private partial void LogTraceRead(string keys);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Write Keys={Keys} Data={Data} Etag={Etag}\"\n        )]\n        private partial void LogTraceWrite(string keys, object data, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Delete Keys={Keys} Etag={Etag}\"\n        )]\n        private partial void LogTraceDelete(string keys, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"{Message}\"\n        )]\n        private partial void LogError(StringBuilder message, Exception exception);\n    }\n\n    /// <summary>\n    /// Factory for creating MemoryGrainStorage\n    /// </summary>\n    public static class MemoryGrainStorageFactory\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"MemoryGrainStorage\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The name.</param>\n        /// <returns>The storage.</returns>\n        public static MemoryGrainStorage Create(IServiceProvider services, string name)\n        {\n            return ActivatorUtilities.CreateInstance<MemoryGrainStorage>(services,\n                services.GetRequiredService<IOptionsMonitor<MemoryGrainStorageOptions>>().Get(name), name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Storage/MemoryStorageEtagMismatchException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Storage.Internal\n{\n    /// <summary>Exception used to communicate with the storage provider, so that it throws this exception to its caller.</summary>\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class MemoryStorageEtagMismatchException : Exception\n    {\n        /// <summary>Gets the Etag value currently held in persistent storage.</summary>\n        [Id(0)]\n        public string StoredEtag { get; private set; }\n\n        /// <summary>Gets the Etag value currently help in memory, and attempting to be updated.</summary>\n        [Id(1)]\n        public string ReceivedEtag { get; private set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryStorageEtagMismatchException\"/> class.\n        /// </summary>\n        /// <param name=\"storedEtag\">The stored etag.</param>\n        /// <param name=\"receivedEtag\">The received etag.</param>\n        public MemoryStorageEtagMismatchException(string storedEtag, string receivedEtag)\n        {\n            StoredEtag = storedEtag;\n            ReceivedEtag = receivedEtag;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryStorageEtagMismatchException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n        [Obsolete]\n        private MemoryStorageEtagMismatchException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.StoredEtag = info.GetString(nameof(StoredEtag));\n            this.ReceivedEtag = info.GetString(nameof(ReceivedEtag));\n        }\n\n        /// <inheritdoc/>\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            if (info == null) throw new ArgumentNullException(nameof(info));\n\n            info.AddValue(nameof(StoredEtag), this.StoredEtag);\n            info.AddValue(nameof(ReceivedEtag), this.ReceivedEtag);\n            base.GetObjectData(info, context);\n        }\n\n        /// <summary>\n        /// Converts this instance into an <see cref=\"InconsistentStateException\"/>.\n        /// </summary>\n        /// <returns>A new <see cref=\"InconsistentStateException\"/>.</returns>\n        public InconsistentStateException AsInconsistentStateException()\n        {\n            var message = $\"e-Tag mismatch in Memory Storage. Stored = { StoredEtag ?? \"null\"} Received = {ReceivedEtag}\";\n            return new InconsistentStateException(message, StoredEtag, ReceivedEtag, this);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Storage/MemoryStorageGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Storage.Internal;\n\nnamespace Orleans.Storage\n{\n    /// <summary>\n    /// Implementation class for the Storage Grain used by In-memory storage provider\n    /// <c>Orleans.Storage.MemoryStorage</c>\n    /// </summary>\n    [KeepAlive]\n    internal partial class MemoryStorageGrain : Grain, IMemoryStorageGrain\n    {\n        private readonly Dictionary<string, object> _store = new();\n        private readonly ILogger _logger;\n\n        public MemoryStorageGrain(ILogger<MemoryStorageGrain> logger)\n        {\n            _logger = logger;\n        }\n\n        public Task<IGrainState<T>> ReadStateAsync<T>(string grainStoreKey)\n        {\n            LogDebugReadState(grainStoreKey);\n            _store.TryGetValue(grainStoreKey, out var entry);\n            return Task.FromResult((IGrainState<T>)entry);\n        }\n\n        public Task<string> WriteStateAsync<T>(string grainStoreKey, IGrainState<T> grainState)\n        {\n            LogDebugWriteState(grainStoreKey, grainState.ETag);\n            var currentETag = GetETagFromStorage<T>(grainStoreKey);\n            ValidateEtag(currentETag, grainState.ETag, grainStoreKey, \"Update\");\n            grainState.ETag = NewEtag();\n            _store[grainStoreKey] = grainState;\n            LogDebugDoneWriteState(grainStoreKey, grainState.ETag);\n            return Task.FromResult(grainState.ETag);\n        }\n\n        public Task DeleteStateAsync<T>(string grainStoreKey, string etag)\n        {\n            LogDebugDeleteState(grainStoreKey, etag);\n\n            var currentETag = GetETagFromStorage<T>(grainStoreKey);\n            ValidateEtag(currentETag, etag, grainStoreKey, \"Delete\");\n            // Do not remove it from the dictionary, just set the value to null to remember that this item\n            // was once in the store, and now is deleted\n            _store[grainStoreKey] = null;\n            return Task.CompletedTask;\n        }\n\n        private static string NewEtag()\n        {\n            return Guid.NewGuid().ToString(\"N\");\n        }\n\n        private string GetETagFromStorage<T>(string grainStoreKey)\n        {\n            string currentETag = null;\n            if (_store.TryGetValue(grainStoreKey, out var entry))\n            {\n                // If the entry is null, it was removed from storage\n                currentETag = entry != null ? ((IGrainState<T>)entry).ETag : string.Empty;\n            }\n            return currentETag;\n        }\n\n        private void ValidateEtag(string currentETag, string receivedEtag, string grainStoreKey, string operation)\n        {\n            // if we have no current etag, we will accept the users data.\n            // This is a mitigation for when the memory storage grain is lost due to silo crash.\n            if (currentETag == null)\n                return;\n\n            // if this is our first write, and we have an empty etag, we're good\n            if (string.IsNullOrEmpty(currentETag) && receivedEtag == null)\n                return;\n\n            // if current state and new state have matching etags, or we're to ignore the ETag, we're good\n            if (receivedEtag == currentETag || receivedEtag == \"*\")\n                return;\n\n            // else we have an etag mismatch\n            LogWarningEtagMismatch(operation, grainStoreKey, currentETag, receivedEtag);\n            throw new MemoryStorageEtagMismatchException(currentETag, receivedEtag);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"ReadStateAsync for grain: {GrainStoreKey}\"\n        )]\n        private partial void LogDebugReadState(string grainStoreKey);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"WriteStateAsync for grain: {GrainStoreKey} eTag: {ETag}\"\n        )]\n        private partial void LogDebugWriteState(string grainStoreKey, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Done WriteStateAsync for grain: {GrainStoreKey} eTag: {ETag}\"\n        )]\n        private partial void LogDebugDoneWriteState(string grainStoreKey, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"DeleteStateAsync for grain: {GrainStoreKey} eTag: {ETag}\"\n        )]\n        private partial void LogDebugDeleteState(string grainStoreKey, string etag);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = 0,\n            Message = \"Etag mismatch during {Operation} for grain {GrainStoreKey}: Expected = {Expected} Received = {Received}\"\n        )]\n        private partial void LogWarningEtagMismatch(string operation, string grainStoreKey, string expected, string received);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Persistence.Memory/Storage/MemoryStorageWithLatency.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Storage\n{\n\n    /// <summary>\n    /// Options for the <see cref=\"MemoryGrainStorageWithLatency\"/> storage provider.\n    /// </summary>\n    public class MemoryStorageWithLatencyOptions : MemoryGrainStorageOptions\n    {\n        /// <summary>\n        /// The default latency.\n        /// </summary>\n        public static readonly TimeSpan DefaultLatency = TimeSpan.FromMilliseconds(200);\n\n        /// <summary>\n        /// Gets or sets the latency.\n        /// </summary>\n        /// <value>The latency.</value>\n        public TimeSpan Latency { get; set; } = DefaultLatency;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to mock calls instead of issuing real storage calls.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if the provider should mock calls; otherwise, <see langword=\"false\" />.</value>\n        public bool MockCallsOnly { get;set; }\n    }\n\n    /// <summary>\n    /// This is a simple in-memory implementation of a storage provider which presents fixed latency of storage calls.\n    /// This class is useful for system testing and investigation of the effects of storage latency.\n    /// </summary>\n    /// <remarks>\n    /// This storage provider is ONLY intended for simple in-memory Test scenarios.\n    /// This class should NOT be used in Production environment, \n    ///  because [by-design] it does not provide any resilience \n    ///  or long-term persistence capabilities.\n    /// </remarks>\n    [DebuggerDisplay(\"MemoryStore:{Name},WithLatency:{latency}\")]\n    public class MemoryGrainStorageWithLatency :IGrainStorage\n    {\n        private readonly MemoryGrainStorage baseGranStorage;\n        private readonly MemoryStorageWithLatencyOptions options;\n        /// <summary> Default constructor. </summary>\n        public MemoryGrainStorageWithLatency(\n            string name,\n            MemoryStorageWithLatencyOptions options,\n            ILoggerFactory loggerFactory,\n            IGrainFactory grainFactory,\n            IActivatorProvider activatorProvider,\n            IGrainStorageSerializer defaultGrainStorageSerializer)\n        {\n            this.baseGranStorage = new MemoryGrainStorage(\n                name,\n                options,\n                loggerFactory.CreateLogger<MemoryGrainStorage>(),\n                grainFactory,\n                defaultGrainStorageSerializer,\n                activatorProvider);\n            this.options = options;\n        }\n\n        /// <summary> Read state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ReadStateAsync{T}\"/>\n        public Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            return MakeFixedLatencyCall(() => baseGranStorage.ReadStateAsync(grainType, grainId, grainState));\n        }\n\n        /// <summary> Write state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.WriteStateAsync{T}\"/>\n        public Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n           return MakeFixedLatencyCall(() => baseGranStorage.WriteStateAsync(grainType, grainId, grainState));\n        }\n\n        /// <summary> Delete / Clear state data function for this storage provider. </summary>\n        /// <see cref=\"IGrainStorage.ClearStateAsync{T}\"/>\n        public Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            return MakeFixedLatencyCall(() => baseGranStorage.ClearStateAsync(grainType, grainId, grainState));\n        }\n\n        private async Task MakeFixedLatencyCall(Func<Task> action)\n        {\n            var sw = Stopwatch.StartNew();\n            Exception error = null;\n            try\n            {\n                if (this.options.MockCallsOnly)\n                {\n                    // Simulated call with slight delay\n                    await Task.Delay(10);\n                }\n                else\n                {\n                    // Make the real call\n                    await action();\n                }\n            }\n            catch (Exception exc)\n            {\n                error = exc;\n            }\n\n            do\n            {\n                // Work out the remaining time to wait so that this operation exceeds the required Latency.\n                // Also adds an extra fudge factor to account for any system clock resolution edge cases.\n                var extraDelay = TimeSpan.FromTicks(\n                     5 * TimeSpan.TicksPerMillisecond + this.options.Latency.Ticks - sw.Elapsed.Ticks);\n\n                if (extraDelay > TimeSpan.Zero)\n                {\n                    await Task.Delay(extraDelay);\n                }\n                else\n                {\n                    break;\n                }\n            } while (true);\n\n            Debug.Assert(sw.Elapsed >= this.options.Latency, \"sw.Elapsed >= this.options.Latency\");\n            if (error != null)\n            {\n                // Wrap in AggregateException so that the original error stack trace is preserved.\n                throw new AggregateException(error);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Constants/ReminderOptionsDefaults.cs",
    "content": "using Orleans.Hosting;\n\nnamespace Orleans;\n\ninternal static class ReminderOptionsDefaults\n{\n    /// <summary>\n    /// Minimum period for registering a reminder ... we want to enforce a lower bound <see cref=\"ReminderOptions.MinimumReminderPeriod\"/>.\n    /// </summary>\n    /// <remarks>Increase this period, reminders are supposed to be less frequent ... we use 2 seconds just to reduce the running time of the unit tests</remarks>\n    public const uint MinimumReminderPeriodMinutes = 1;\n\n    /// <summary>\n    /// Period (in minutes) between refreshing local reminder list to reflect the global reminder table every <see cref=\"ReminderOptions.RefreshReminderListPeriod\"/>.\n    /// </summary>\n    public const uint RefreshReminderListPeriodMinutes = 5;\n\n    /// <summary>\n    /// The maximum amount of time (in minutes) to attempt to initialize reminders giving up <see cref=\"ReminderOptions.InitializationTimeout\"/>.\n    /// </summary>\n    public const uint InitializationTimeoutMinutes = 5;\n}"
  },
  {
    "path": "src/Orleans.Reminders/Constants/RemindersConstants.cs",
    "content": "namespace Orleans;\n\ninternal static class RemindersConstants\n{\n    internal const string LocalReminderService = nameof(LocalReminderService);\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/ErrorCodes.cs",
    "content": "// ReSharper disable InconsistentNaming\nnamespace Orleans.Reminders;\n\n/// <summary>\n/// The set of error codes used by the Orleans runtime libraries for logging errors. For Reminders.\n/// </summary>\npublic enum RSErrorCode\n{\n    ReminderServiceBase = /* Runtime */ 100000 + 2900,\n    RS_Register_TableError = ReminderServiceBase + 5,\n    RS_Register_AlreadyRegistered = ReminderServiceBase + 7,\n    RS_Register_InvalidPeriod = ReminderServiceBase + 8,\n    RS_Register_NotRemindable = ReminderServiceBase + 9,\n    RS_NotResponsible = ReminderServiceBase + 10,\n    RS_Unregister_NotFoundLocally = ReminderServiceBase + 11,\n    RS_Unregister_TableError = ReminderServiceBase + 12,\n    RS_Table_Insert = ReminderServiceBase + 13,\n    RS_Table_Remove = ReminderServiceBase + 14,\n    RS_Tick_Delivery_Error = ReminderServiceBase + 15,\n    RS_Not_Started = ReminderServiceBase + 16,\n    RS_UnregisterGrain_TableError = ReminderServiceBase + 17,\n    RS_GrainBasedTable1 = ReminderServiceBase + 18,\n    RS_Factory1 = ReminderServiceBase + 19,\n    RS_FailedToReadTableAndStartTimer = ReminderServiceBase + 20,\n    RS_TableGrainInit1 = ReminderServiceBase + 21,\n    RS_TableGrainInit2 = ReminderServiceBase + 22,\n    RS_TableGrainInit3 = ReminderServiceBase + 23,\n    RS_GrainBasedTable2 = ReminderServiceBase + 24,\n    RS_ServiceStarting = ReminderServiceBase + 25,\n    RS_ServiceStarted = ReminderServiceBase + 26,\n    RS_ServiceStopping = ReminderServiceBase + 27,\n    RS_RegisterOrUpdate = ReminderServiceBase + 28,\n    RS_Unregister = ReminderServiceBase + 29,\n    RS_Stop = ReminderServiceBase + 30,\n    RS_RemoveFromTable = ReminderServiceBase + 31,\n    RS_GetReminder = ReminderServiceBase + 32,\n    RS_GetReminders = ReminderServiceBase + 33,\n    RS_RangeChanged = ReminderServiceBase + 34,\n    RS_LocalStop = ReminderServiceBase + 35,\n    RS_Started = ReminderServiceBase + 36,\n    RS_ServiceInitialLoadFailing = ReminderServiceBase + 37,\n    RS_ServiceInitialLoadFailed = ReminderServiceBase + 38,\n    RS_FastReminderInterval = ReminderServiceBase + 39,\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/GrainReminderExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Timers;\n\n#nullable enable\nnamespace Orleans;\n\n/// <summary>\n/// Extension methods for accessing reminders from a <see cref=\"Grain\"/> or <see cref=\"IGrainBase\"/> implementation.\n/// </summary>\npublic static class GrainReminderExtensions\n{\n    /// <summary>\n    /// Registers a persistent, reliable reminder to send regular notifications (reminders) to the grain.\n    /// The grain must implement the <c>Orleans.IRemindable</c> interface, and reminders for this grain will be sent to the <c>ReceiveReminder</c> callback method.\n    /// If the current grain is deactivated when the timer fires, a new activation of this grain will be created to receive this reminder.\n    /// If an existing reminder with the same name already exists, that reminder will be overwritten with this new reminder.\n    /// Reminders will always be received by one activation of this grain, even if multiple activations exist for this grain.\n    /// </summary>\n    /// <param name=\"grain\">The grain instance.</param>\n    /// <param name=\"reminderName\">Name of this reminder</param>\n    /// <param name=\"dueTime\">Due time for this reminder</param>\n    /// <param name=\"period\">Frequency period for this reminder</param>\n    /// <returns>Promise for Reminder handle.</returns>\n    public static Task<IGrainReminder> RegisterOrUpdateReminder(this Grain grain, string reminderName, TimeSpan dueTime, TimeSpan period)\n        => RegisterOrUpdateReminder(grain is IRemindable, grain?.GrainContext, reminderName, dueTime, period);\n\n    /// <summary>\n    /// Registers a persistent, reliable reminder to send regular notifications (reminders) to the grain.\n    /// The grain must implement the <c>Orleans.IRemindable</c> interface, and reminders for this grain will be sent to the <c>ReceiveReminder</c> callback method.\n    /// If the current grain is deactivated when the timer fires, a new activation of this grain will be created to receive this reminder.\n    /// If an existing reminder with the same name already exists, that reminder will be overwritten with this new reminder.\n    /// Reminders will always be received by one activation of this grain, even if multiple activations exist for this grain.\n    /// </summary>\n    /// <param name=\"grain\">The grain instance.</param>\n    /// <param name=\"reminderName\">Name of this reminder</param>\n    /// <param name=\"dueTime\">Due time for this reminder</param>\n    /// <param name=\"period\">Frequency period for this reminder</param>\n    /// <returns>Promise for Reminder handle.</returns>\n    public static Task<IGrainReminder> RegisterOrUpdateReminder(this IGrainBase grain, string reminderName, TimeSpan dueTime, TimeSpan period)\n        => RegisterOrUpdateReminder(grain is IRemindable, grain?.GrainContext, reminderName, dueTime, period);\n\n    private static Task<IGrainReminder> RegisterOrUpdateReminder(bool remindable, IGrainContext? grainContext, string reminderName, TimeSpan dueTime, TimeSpan period)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext, \"grain\");\n        if (string.IsNullOrWhiteSpace(reminderName)) throw new ArgumentNullException(nameof(reminderName));\n        if (!remindable) throw new InvalidOperationException($\"Grain {grainContext.GrainId} is not '{nameof(IRemindable)}'. A grain should implement {nameof(IRemindable)} to use the persistent reminder service\");\n\n        return GetReminderRegistry(grainContext).RegisterOrUpdateReminder(grainContext.GrainId, reminderName, dueTime, period);\n    }\n\n    /// <summary>\n    /// Unregisters a previously registered reminder.\n    /// </summary>\n    /// <param name=\"grain\">The grain instance.</param>\n    /// <param name=\"reminder\">Reminder to unregister.</param>\n    /// <returns>Completion promise for this operation.</returns>\n    public static Task UnregisterReminder(this Grain grain, IGrainReminder reminder) => UnregisterReminder(grain?.GrainContext, reminder);\n\n    /// <summary>\n    /// Unregisters a previously registered reminder.\n    /// </summary>\n    /// <param name=\"grain\">The grain instance.</param>\n    /// <param name=\"reminder\">Reminder to unregister.</param>\n    /// <returns>Completion promise for this operation.</returns>\n    public static Task UnregisterReminder(this IGrainBase grain, IGrainReminder reminder) => UnregisterReminder(grain?.GrainContext, reminder);\n\n    private static Task UnregisterReminder(IGrainContext? grainContext, IGrainReminder reminder)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext, \"grain\");\n        return GetReminderRegistry(grainContext).UnregisterReminder(grainContext.GrainId, reminder);\n    }\n\n    /// <summary>\n    /// Returns a previously registered reminder.\n    /// </summary>\n    /// <param name=\"grain\">The grain instance.</param>\n    /// <param name=\"reminderName\">Reminder to return</param>\n    /// <returns>Promise for Reminder handle.</returns>\n    public static Task<IGrainReminder?> GetReminder(this Grain grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);\n\n    /// <summary>\n    /// Returns a previously registered reminder.\n    /// </summary>\n    /// <param name=\"grain\">A grain.</param>\n    /// <param name=\"reminderName\">Reminder to return</param>\n    /// <returns>Promise for Reminder handle.</returns>\n    public static Task<IGrainReminder?> GetReminder(this IGrainBase grain, string reminderName) => GetReminder(grain?.GrainContext, reminderName);\n\n    private static Task<IGrainReminder?> GetReminder(IGrainContext? grainContext, string reminderName)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext, \"grain\");\n        if (string.IsNullOrWhiteSpace(reminderName)) throw new ArgumentNullException(nameof(reminderName));\n\n        return GetReminderRegistry(grainContext).GetReminder(grainContext.GrainId, reminderName);\n    }\n\n    /// <summary>\n    /// Returns a list of all reminders registered by the grain.\n    /// </summary>\n    /// <returns>Promise for list of Reminders registered for this grain.</returns>\n    public static Task<List<IGrainReminder>> GetReminders(this Grain grain) => GetReminders(grain?.GrainContext);\n\n    /// <summary>\n    /// Returns a list of all reminders registered by the grain.\n    /// </summary>\n    /// <returns>Promise for list of Reminders registered for this grain.</returns>\n    public static Task<List<IGrainReminder>> GetReminders(this IGrainBase grain) => GetReminders(grain?.GrainContext);\n\n    private static Task<List<IGrainReminder>> GetReminders(IGrainContext? grainContext)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext, \"grain\");\n        return GetReminderRegistry(grainContext).GetReminders(grainContext.GrainId);\n    }\n\n    /// <summary>\n    /// Gets the <see cref=\"IReminderRegistry\"/>.\n    /// </summary>\n    private static IReminderRegistry GetReminderRegistry(IGrainContext grainContext)\n    {\n        return grainContext.ActivationServices.GetRequiredService<IReminderRegistry>();\n    }\n}"
  },
  {
    "path": "src/Orleans.Reminders/Hosting/MemoryReminderTableBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Runtime.Hosting.ProviderConfiguration;\n\n[assembly: RegisterProvider(\"Memory\", \"Reminders\", \"Silo\", typeof(MemoryReminderTableBuilder))]\n\nnamespace Orleans.Runtime.Hosting.ProviderConfiguration;\n\ninternal sealed class MemoryReminderTableBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseInMemoryReminderService();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Hosting/SiloBuilderReminderExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Configuration.Internal;\nusing System.Linq;\nusing Orleans.Runtime.ReminderService;\nusing Orleans.Timers;\n\nnamespace Orleans.Hosting;\n\npublic static class SiloBuilderReminderExtensions\n{\n    /// <summary>\n    /// Adds support for reminders to this silo.\n    /// </summary>\n    /// <param name=\"builder\">The builder.</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder AddReminders(this ISiloBuilder builder) => builder.ConfigureServices(services => AddReminders(services));\n\n    /// <summary>\n    /// Add support for reminders to this client.\n    /// </summary>\n    /// <param name=\"services\">The services.</param>\n    public static void AddReminders(this IServiceCollection services)\n    {\n        if (services.Any(service => service.ServiceType.Equals(typeof(LocalReminderService))))\n        {\n            return;\n        }\n\n        services.AddSingleton<LocalReminderService>();\n        services.AddFromExisting<IReminderService, LocalReminderService>();\n        services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, LocalReminderService>();\n        services.AddSingleton<IReminderRegistry, ReminderRegistry>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Hosting/SiloBuilderReminderMemoryExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.ReminderService;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions to <see cref=\"ISiloBuilder\"/> for configuring the in-memory reminder provider.\n    /// </summary>\n    public static class SiloBuilderReminderMemoryExtensions\n    {\n        /// <summary>\n        /// Configures reminder storage using an in-memory, non-persistent store.\n        /// </summary>\n        /// <remarks>\n        /// Note that this is for development and testing scenarios only and should not be used in production.\n        /// </remarks>\n        /// <param name=\"builder\">The silo host builder.</param>\n        /// <returns>The provided <see cref=\"ISiloBuilder\"/>, for chaining.</returns>\n        public static ISiloBuilder UseInMemoryReminderService(this ISiloBuilder builder)\n        {\n            builder.AddReminders();\n\n            // The reminder table is a reference to a singleton IReminderTableGrain.\n            builder.ConfigureServices(services => services.UseInMemoryReminderService());\n            return builder;\n        }\n\n        /// <summary>\n        /// Configures reminder storage using an in-memory, non-persistent store.\n        /// </summary>\n        /// <remarks>\n        /// Note that this is for development and testing scenarios only and should not be used in production.\n        /// </remarks>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The provided <see cref=\"IServiceCollection\"/>, for chaining.</returns>\n        internal static IServiceCollection UseInMemoryReminderService(this IServiceCollection services)\n        {\n            services.AddSingleton<InMemoryReminderTable>();\n            services.AddFromExisting<IReminderTable, InMemoryReminderTable>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, InMemoryReminderTable>();\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Reminders/Options/ReminderOptions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Reminders;\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting;\n\n/// <summary>\n/// Options for the reminder service.\n/// </summary>\npublic sealed class ReminderOptions\n{\n    /// <summary>\n    /// Gets or sets the minimum period for reminders.\n    /// </summary>\n    /// <remarks>\n    /// High-frequency reminders are dangerous for production systems.\n    /// </remarks>\n    public TimeSpan MinimumReminderPeriod { get; set; } = TimeSpan.FromMinutes(ReminderOptionsDefaults.MinimumReminderPeriodMinutes);\n\n    /// <summary>\n    /// Gets or sets the period between reminder table refreshes.\n    /// </summary>\n    /// <value>Refresh the reminder table every 5 minutes by default.</value>\n    public TimeSpan RefreshReminderListPeriod { get; set; } = TimeSpan.FromMinutes(ReminderOptionsDefaults.RefreshReminderListPeriodMinutes);\n\n    /// <summary>\n    /// Gets or sets the maximum amount of time to attempt to initialize reminders before giving up.\n    /// </summary>\n    /// <value>Attempt to initialize for 5 minutes before giving up by default.</value>\n    public TimeSpan InitializationTimeout { get; set; } = TimeSpan.FromMinutes(ReminderOptionsDefaults.InitializationTimeoutMinutes);\n}\n\n/// <summary>\n/// Validator for <see cref=\"ReminderOptions\"/>.\n/// </summary>\ninternal sealed partial class ReminderOptionsValidator : IConfigurationValidator\n{\n    private readonly ILogger<ReminderOptionsValidator> logger;\n    private readonly IOptions<ReminderOptions> options;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ReminderOptionsValidator\"/> class.\n    /// </summary>\n    /// <param name=\"logger\">\n    /// The logger.\n    /// </param>\n    /// <param name=\"reminderOptions\">\n    /// The reminder options.\n    /// </param>\n    public ReminderOptionsValidator(ILogger<ReminderOptionsValidator> logger, IOptions<ReminderOptions> reminderOptions)\n    {\n        this.logger = logger;\n        options = reminderOptions;\n    }\n\n    /// <inheritdoc />\n    public void ValidateConfiguration()\n    {\n        if (options.Value.MinimumReminderPeriod < TimeSpan.Zero)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ReminderOptions)}.{nameof(ReminderOptions.MinimumReminderPeriod)} must not be less than {TimeSpan.Zero}\");\n        }\n\n        if (options.Value.MinimumReminderPeriod.TotalMinutes < ReminderOptionsDefaults.MinimumReminderPeriodMinutes)\n        {\n            LogWarnFastReminderInterval(options.Value.MinimumReminderPeriod, ReminderOptionsDefaults.MinimumReminderPeriodMinutes);\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        EventId = (int)RSErrorCode.RS_FastReminderInterval,\n        Message = $\"{nameof(ReminderOptions)}.{nameof(ReminderOptions.MinimumReminderPeriod)} is {{MinimumReminderPeriod}} (default {{MinimumReminderPeriodMinutes}}. High-Frequency reminders are unsuitable for production use.\"\n    )]\n    private partial void LogWarnFastReminderInterval(TimeSpan minimumReminderPeriod, uint minimumReminderPeriodMinutes);\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Orleans.Reminders.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Reminders</PackageId>\n    <Title>Microsoft Orleans Reminders Library</Title>\n    <Description>Reminders library for Microsoft Orleans used on the server.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <DefineConstants>$(DefineConstants);ORLEANS_REMINDERS_PROVIDER</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"LoadTestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Reminders/ReminderService/GrainBasedReminderTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Reminders;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    [Reentrant]\n    [KeepAlive]\n    internal sealed partial class ReminderTableGrain : Grain, IReminderTableGrain, IGrainMigrationParticipant\n    {\n        private readonly ILogger _logger;\n        private Dictionary<GrainId, Dictionary<string, ReminderEntry>> _reminderTable = new();\n\n        public ReminderTableGrain(ILogger<ReminderTableGrain> logger)\n        {\n            _logger = logger;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            LogDebugActivated();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            LogDebugDeactivated();\n            return Task.CompletedTask;\n        }\n\n        public Task TestOnlyClearTable()\n        {\n            LogDebugTestOnlyClearTable();\n            _reminderTable.Clear();\n            return Task.CompletedTask;\n        }\n\n        public Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            var result = _reminderTable.TryGetValue(grainId, out var reminders) ? new ReminderTableData(reminders.Values) : new();\n            return Task.FromResult(result);\n        }\n\n        public Task<ReminderTableData> ReadRows(uint begin, uint end)\n        {\n            var range = RangeFactory.CreateRange(begin, end);\n\n            var list = new List<ReminderEntry>();\n            foreach (var e in _reminderTable)\n                if (range.InRange(e.Key))\n                    list.AddRange(e.Value.Values);\n\n            LogTraceSelectedReminders(list.Count, new(_reminderTable), range, new(list));\n\n            var result = new ReminderTableData(list);\n            LogDebugReadReminders(result.Reminders.Count, new(result.Reminders));\n            return Task.FromResult(result);\n        }\n\n        public Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            ReminderEntry result = null;\n            if (_reminderTable.TryGetValue(grainId, out var reminders))\n            {\n                reminders.TryGetValue(reminderName, out result);\n            }\n\n            if (result is null)\n            {\n                LogTraceReminderNotFound(grainId, reminderName);\n            }\n            else\n            {\n                LogTraceReadRow(grainId, reminderName, result);\n            }\n\n            return Task.FromResult(result);\n        }\n\n        public Task<string> UpsertRow(ReminderEntry entry)\n        {\n            entry.ETag = Guid.NewGuid().ToString();\n            var d = CollectionsMarshal.GetValueRefOrAddDefault(_reminderTable, entry.GrainId, out _) ??= new();\n            ref var entryRef = ref CollectionsMarshal.GetValueRefOrAddDefault(d, entry.ReminderName, out _);\n\n            var old = entryRef; // tracing purposes only\n            entryRef = entry;\n            LogTraceUpsertedEntry(entry, old);\n\n            return Task.FromResult(entry.ETag);\n        }\n\n        public Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            LogDebugRemoveRow(grainId, reminderName, eTag);\n            if (_reminderTable.TryGetValue(grainId, out var data)\n                && data.TryGetValue(reminderName, out var e)\n                && e.ETag == eTag)\n            {\n                if (data.Count > 1)\n                {\n                    data.Remove(reminderName);\n                }\n                else\n                {\n                    _reminderTable.Remove(grainId);\n                }\n\n                return Task.FromResult(true);\n            }\n\n            LogWarningRemoveRow(grainId, reminderName, eTag, new(_reminderTable));\n            return Task.FromResult(false);\n        }\n\n        void IGrainMigrationParticipant.OnDehydrate(IDehydrationContext dehydrationContext)\n        {\n            dehydrationContext.TryAddValue(\"table\", _reminderTable);\n        }\n\n        void IGrainMigrationParticipant.OnRehydrate(IRehydrationContext rehydrationContext)\n        {\n            if (rehydrationContext.TryGetValue(\"table\", out Dictionary<GrainId, Dictionary<string, ReminderEntry>> table))\n            {\n                _reminderTable = table;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Activated\"\n        )]\n        private partial void LogDebugActivated();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Deactivated\"\n        )]\n        private partial void LogDebugDeactivated();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TestOnlyClearTable\"\n        )]\n        private partial void LogDebugTestOnlyClearTable();\n\n        private readonly struct TotalCountLogRecord(Dictionary<GrainId, Dictionary<string, ReminderEntry>> reminderTable)\n        {\n            public override string ToString() => reminderTable.Values.Sum(r => r.Count).ToString();\n        }\n\n        private readonly struct RemindersLogRecord(IEnumerable<ReminderEntry> reminders)\n        {\n            public override string ToString() => Utils.EnumerableToString(reminders);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Selected {SelectCount} out of {TotalCount} reminders from memory for {Range}. Selected: {Reminders}\"\n        )]\n        private partial void LogTraceSelectedReminders(int selectCount, TotalCountLogRecord totalCount, IRingRange range, RemindersLogRecord reminders);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Read {ReminderCount} reminders from memory: {Reminders}\"\n        )]\n        private partial void LogDebugReadReminders(int reminderCount, RemindersLogRecord reminders);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Reminder not found for grain {Grain} reminder {ReminderName}\"\n        )]\n        private partial void LogTraceReminderNotFound(GrainId grain, string reminderName);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Read for grain {Grain} reminder {ReminderName} row {Reminder}\"\n        )]\n        private partial void LogTraceReadRow(GrainId grain, string reminderName, ReminderEntry reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Upserted entry {Updated}, replaced {Replaced}\"\n        )]\n        private partial void LogTraceUpsertedEntry(ReminderEntry updated, ReminderEntry replaced);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"RemoveRow Grain = {Grain}, ReminderName = {ReminderName}, eTag = {ETag}\"\n        )]\n        private partial void LogDebugRemoveRow(GrainId grain, string reminderName, string eTag);\n\n        private readonly struct NewValuesLogRecord(Dictionary<GrainId, Dictionary<string, ReminderEntry>> reminderTable)\n        {\n            public override string ToString() => Utils.EnumerableToString(reminderTable.Values.SelectMany(x => x.Values));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)RSErrorCode.RS_Table_Remove,\n            Message = \"RemoveRow failed for Grain = {Grain}, ReminderName = {ReminderName}, eTag = {ETag}. Table now is: {NewValues}\"\n        )]\n        private partial void LogWarningRemoveRow(GrainId grain, string reminderName, string eTag, NewValuesLogRecord newValues);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/ReminderService/InMemoryReminderTable.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    internal sealed class InMemoryReminderTable : IReminderTable, ILifecycleParticipant<ISiloLifecycle>\n    {\n        internal const long ReminderTableGrainId = 12345;\n        private readonly IReminderTableGrain reminderTableGrain;\n        private bool isAvailable;\n\n        public InMemoryReminderTable(IGrainFactory grainFactory)\n        {\n            this.reminderTableGrain = grainFactory.GetGrain<IReminderTableGrain>(ReminderTableGrainId);\n        }\n\n        public Task Init() => Task.CompletedTask;\n\n        public Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            this.ThrowIfNotAvailable();\n            return this.reminderTableGrain.ReadRow(grainId, reminderName);\n        }\n\n        public Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            this.ThrowIfNotAvailable();\n            return this.reminderTableGrain.ReadRows(grainId);\n        }\n\n        public Task<ReminderTableData> ReadRows(uint begin, uint end)\n        {\n            return this.isAvailable ? this.reminderTableGrain.ReadRows(begin, end) : Task.FromResult(new ReminderTableData());\n        }\n\n        public Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            this.ThrowIfNotAvailable();\n            return this.reminderTableGrain.RemoveRow(grainId, reminderName, eTag);\n        }\n\n        public Task TestOnlyClearTable()\n        {\n            this.ThrowIfNotAvailable();\n            return this.reminderTableGrain.TestOnlyClearTable();\n        }\n\n        public Task<string> UpsertRow(ReminderEntry entry)\n        {\n            this.ThrowIfNotAvailable();\n            return this.reminderTableGrain.UpsertRow(entry);\n        }\n\n        private void ThrowIfNotAvailable()\n        {\n            if (!this.isAvailable) throw new InvalidOperationException(\"The reminder service is not currently available.\");\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            Task OnApplicationServicesStart(CancellationToken ct)\n            {\n                this.isAvailable = true;\n                return Task.CompletedTask;\n            }\n\n            Task OnApplicationServicesStop(CancellationToken ct)\n            {\n                this.isAvailable = false;\n                return Task.CompletedTask;\n            }\n\n            lifecycle.Subscribe(\n                nameof(InMemoryReminderTable),\n                ServiceLifecycleStage.ApplicationServices,\n                OnApplicationServicesStart,\n                OnApplicationServicesStop);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/ReminderService/LocalReminderService.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.CodeGeneration;\nusing Orleans.GrainReferences;\nusing Orleans.Hosting;\nusing Orleans.Internal;\nusing Orleans.Metadata;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime.ReminderService\n{\n    internal sealed partial class LocalReminderService : GrainService, IReminderService, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private const int InitialReadRetryCountBeforeFastFailForUpdates = 2;\n        private static readonly TimeSpan InitialReadMaxWaitTimeForUpdates = TimeSpan.FromSeconds(20);\n        private static readonly TimeSpan InitialReadRetryPeriod = TimeSpan.FromSeconds(30);\n        private readonly ILogger logger;\n        private readonly ReminderOptions reminderOptions;\n        private readonly Dictionary<ReminderIdentity, LocalReminderData> localReminders = new();\n        private readonly IReminderTable reminderTable;\n        private readonly TaskCompletionSource<bool> startedTask;\n        private readonly IAsyncTimerFactory asyncTimerFactory;\n        private readonly IAsyncTimer listRefreshTimer; // timer that refreshes our list of reminders to reflect global reminder table\n        private readonly GrainReferenceActivator _referenceActivator;\n        private readonly GrainInterfaceType _grainInterfaceType;\n        private long localTableSequence;\n        private uint initialReadCallCount = 0;\n        private Task runTask;\n\n        public LocalReminderService(\n            GrainReferenceActivator referenceActivator,\n            GrainInterfaceTypeResolver interfaceTypeResolver,\n            IReminderTable reminderTable,\n            IAsyncTimerFactory asyncTimerFactory,\n            IOptions<ReminderOptions> reminderOptions,\n            IConsistentRingProvider ringProvider,\n            SystemTargetShared shared)\n            : base(\n                  SystemTargetGrainId.CreateGrainServiceGrainId(GrainInterfaceUtils.GetGrainClassTypeCode(typeof(IReminderService)), null, shared.SiloAddress),\n                  ringProvider,\n                  shared)\n        {\n            _referenceActivator = referenceActivator;\n            _grainInterfaceType = interfaceTypeResolver.GetGrainInterfaceType(typeof(IRemindable));\n            this.reminderOptions = reminderOptions.Value;\n            this.reminderTable = reminderTable;\n            this.asyncTimerFactory = asyncTimerFactory;\n            ReminderInstruments.RegisterActiveRemindersObserve(() => localReminders.Count);\n            startedTask = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n            this.logger = shared.LoggerFactory.CreateLogger<LocalReminderService>();\n            this.listRefreshTimer = asyncTimerFactory.Create(this.reminderOptions.RefreshReminderListPeriod, \"ReminderService.ReminderListRefresher\");\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle observer)\n        {\n            observer.Subscribe(\n                nameof(LocalReminderService),\n                ServiceLifecycleStage.BecomeActive,\n                async ct =>\n                {\n                    try\n                    {\n                        await this.QueueTask(() => Initialize(ct));\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorActivatingReminderService(exception);\n                        throw;\n                    }\n                },\n                async ct =>\n                {\n                    try\n                    {\n                        await this.QueueTask(Stop).WaitAsync(ct);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorStoppingReminderService(exception);\n                        throw;\n                    }\n                });\n            observer.Subscribe(\n                nameof(LocalReminderService),\n                ServiceLifecycleStage.Active,\n                async ct =>\n                {\n                    using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);\n                    cts.CancelAfter(this.reminderOptions.InitializationTimeout);\n\n                    try\n                    {\n                        await this.QueueTask(Start).WaitAsync(cts.Token);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorStartingReminderService(exception);\n                        throw;\n                    }\n                },\n                ct => Task.CompletedTask);\n        }\n\n        /// <summary>\n        /// Attempt to retrieve reminders, that are my responsibility, from the global reminder table when starting this silo (reminder service instance)\n        /// </summary>\n        /// <returns></returns>\n        private async Task Initialize(CancellationToken cancellationToken)\n        {\n            using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n            cts.CancelAfter(this.reminderOptions.InitializationTimeout);\n\n            // Confirm that it can access the underlying store, as after this the ReminderService will load in the background, without the opportunity to prevent the Silo from starting\n            await reminderTable.StartAsync(cts.Token);\n        }\n\n        public async override Task Stop()\n        {\n            await base.Stop();\n\n            if (listRefreshTimer != null)\n            {\n                listRefreshTimer.Dispose();\n                if (this.runTask is Task task)\n                {\n                    await task;\n                }\n            }\n\n            foreach (LocalReminderData r in localReminders.Values)\n            {\n                r.StopReminder();\n            }\n\n            await reminderTable.StopAsync();\n\n            // For a graceful shutdown, also handover reminder responsibilities to new owner, and update the ReminderTable\n            // currently, this is taken care of by periodically reading the reminder table\n        }\n\n        public async Task<IGrainReminder> RegisterOrUpdateReminder(GrainId grainId, string reminderName, TimeSpan dueTime, TimeSpan period)\n        {\n            var entry = new ReminderEntry\n            {\n                GrainId = grainId,\n                ReminderName = reminderName,\n                StartAt = DateTime.UtcNow.Add(dueTime),\n                Period = period,\n            };\n\n            LogDebugRegisterOrUpdateReminder(entry);\n            await DoResponsibilitySanityCheck(grainId, \"RegisterReminder\");\n            var newEtag = await reminderTable.UpsertRow(entry);\n\n            if (newEtag != null)\n            {\n                LogDebugRegisterReminder(entry, localTableSequence);\n                entry.ETag = newEtag;\n                StartAndAddTimer(entry);\n                if (logger.IsEnabled(LogLevel.Trace)) PrintReminders();\n                return new ReminderData(grainId, reminderName, newEtag);\n            }\n\n            LogErrorRegisterReminder(entry);\n            throw new ReminderException($\"Could not register reminder {entry} to reminder table due to a race. Please try again later.\");\n        }\n\n        /// <summary>\n        /// Stop the reminder locally, and remove it from the external storage system\n        /// </summary>\n        /// <param name=\"reminder\"></param>\n        /// <returns></returns>\n        public async Task UnregisterReminder(IGrainReminder reminder)\n        {\n            var remData = (ReminderData)reminder;\n            LogDebugUnregisterReminder(reminder, localTableSequence);\n\n            var grainId = remData.GrainId;\n            string reminderName = remData.ReminderName;\n            string eTag = remData.ETag;\n\n            await DoResponsibilitySanityCheck(grainId, \"RemoveReminder\");\n\n            // it may happen that we dont have this reminder locally ... even then, we attempt to remove the reminder from the reminder\n            // table ... the periodic mechanism will stop this reminder at any silo's LocalReminderService that might have this reminder locally\n\n            // remove from persistent/memory store\n            var success = await reminderTable.RemoveRow(grainId, reminderName, eTag);\n            if (success)\n            {\n                bool removed = TryStopPreviousTimer(grainId, reminderName);\n                if (removed)\n                {\n                    LogStoppedReminder(reminder);\n                    if (logger.IsEnabled(LogLevel.Trace)) PrintReminders($\"After removing {reminder}.\");\n                }\n                else\n                {\n                    // no-op\n                    LogRemovedReminderFromTable(reminder);\n                }\n            }\n            else\n            {\n                LogErrorUnregisterReminder(reminder);\n                throw new ReminderException($\"Could not unregister reminder {reminder} from the reminder table, due to tag mismatch. You can retry.\");\n            }\n        }\n\n        public async Task<IGrainReminder> GetReminder(GrainId grainId, string reminderName)\n        {\n            LogDebugGetReminder(grainId, reminderName);\n            var entry = await reminderTable.ReadRow(grainId, reminderName);\n            return entry == null ? null : entry.ToIGrainReminder();\n        }\n\n        public async Task<List<IGrainReminder>> GetReminders(GrainId grainId)\n        {\n            LogDebugGetReminders(grainId);\n            var tableData = await reminderTable.ReadRows(grainId);\n            return tableData.Reminders.Select(entry => entry.ToIGrainReminder()).ToList();\n        }\n\n        /// <summary>\n        /// Attempt to retrieve reminders from the global reminder table\n        /// </summary>\n        private Task ReadAndUpdateReminders()\n        {\n            if (StoppedCancellationTokenSource.IsCancellationRequested) return Task.CompletedTask;\n\n            RemoveOutOfRangeReminders();\n\n            // try to retrieve reminders from all my subranges\n            var rangeSerialNumberCopy = RangeSerialNumber;\n            LogTraceRingRange(RingRange, RangeSerialNumber, localReminders.Count);\n            var acks = new List<Task>();\n            foreach (var range in RangeFactory.GetSubRanges(RingRange))\n            {\n                acks.Add(ReadTableAndStartTimers(range, rangeSerialNumberCopy));\n            }\n            var task = Task.WhenAll(acks);\n            if (logger.IsEnabled(LogLevel.Trace)) task.ContinueWith(_ => PrintReminders(), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);\n            return task;\n        }\n\n        private void RemoveOutOfRangeReminders()\n        {\n            var remindersOutOfRange = 0;\n\n            foreach (var r in localReminders)\n            {\n                if (RingRange.InRange(r.Key.GrainId)) continue;\n                remindersOutOfRange++;\n\n                LogTraceRemovingReminder(r.Value);\n                // remove locally\n                r.Value.StopReminder();\n                localReminders.Remove(r.Key);\n            }\n\n            if (remindersOutOfRange > 0)\n            {\n                LogInfoRemovedLocalReminders(remindersOutOfRange);\n            }\n        }\n\n        public override Task OnRangeChange(IRingRange oldRange, IRingRange newRange, bool increased)\n        {\n            _ = base.OnRangeChange(oldRange, newRange, increased);\n            if (Status == GrainServiceStatus.Started)\n                return ReadAndUpdateReminders();\n            LogIgnoringRangeChange(Status);\n            return Task.CompletedTask;\n        }\n\n        private async Task RunAsync()\n        {\n            await Task.Yield();\n            TimeSpan? overrideDelay = RandomTimeSpan.Next(InitialReadRetryPeriod);\n            while (await listRefreshTimer.NextTick(overrideDelay))\n            {\n                try\n                {\n                    overrideDelay = null;\n                    switch (Status)\n                    {\n                        case GrainServiceStatus.Booting:\n                            await DoInitialReadAndUpdateReminders();\n                            break;\n                        case GrainServiceStatus.Started:\n                            await ReadAndUpdateReminders();\n                            break;\n                        default:\n                            listRefreshTimer.Dispose();\n                            return;\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogWarningReadingReminders(exception);\n                    overrideDelay = RandomTimeSpan.Next(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));\n                }\n            }\n        }\n\n        protected override async Task StartInBackground()\n        {\n            await DoInitialReadAndUpdateReminders();\n            this.runTask = RunAsync();\n        }\n\n        private async Task DoInitialReadAndUpdateReminders()\n        {\n            try\n            {\n                if (StoppedCancellationTokenSource.IsCancellationRequested) return;\n\n                initialReadCallCount++;\n                await this.ReadAndUpdateReminders();\n                Status = GrainServiceStatus.Started;\n                startedTask.TrySetResult(true);\n            }\n            catch (Exception ex)\n            {\n                if (StoppedCancellationTokenSource.IsCancellationRequested) return;\n\n                if (initialReadCallCount <= InitialReadRetryCountBeforeFastFailForUpdates)\n                {\n                    LogWarningInitialLoadFailing(ex, initialReadCallCount);\n                }\n                else\n                {\n                    LogErrorInitialLoadFailed(ex, initialReadCallCount);\n                    startedTask.TrySetException(new OrleansException(\"ReminderService failed initial load of reminders and cannot guarantee that the service will be eventually start without manual intervention or restarting the silo.\", ex));\n                }\n            }\n        }\n\n        private async Task ReadTableAndStartTimers(ISingleRange range, int rangeSerialNumberCopy)\n        {\n            LogDebugReadingRows(range);\n            localTableSequence++;\n            long cachedSequence = localTableSequence;\n\n            try\n            {\n                var table = await reminderTable.ReadRows(range.Begin, range.End); // get all reminders, even the ones we already have\n\n                if (rangeSerialNumberCopy < RangeSerialNumber)\n                {\n                    LogDebugRangeChangedWhileFromTable(RangeSerialNumber, rangeSerialNumberCopy);\n                    return;\n                }\n\n                if (StoppedCancellationTokenSource.IsCancellationRequested) return;\n\n                // If null is a valid value, it means that there's nothing to do.\n                if (table is null) return;\n\n                var remindersNotInTable = new Dictionary<ReminderIdentity, LocalReminderData>(); // shallow copy\n                foreach (var r in localReminders)\n                    if (range.InRange(r.Key.GrainId))\n                        remindersNotInTable.Add(r.Key, r.Value);\n\n                LogDebugReadRemindersFromTable(range, table.Reminders.Count, localTableSequence, cachedSequence);\n                foreach (var entry in table.Reminders)\n                {\n                    var key = new ReminderIdentity(entry.GrainId, entry.ReminderName);\n                    if (localReminders.TryGetValue(key, out var localRem))\n                    {\n                        if (cachedSequence > localRem.LocalSequenceNumber) // info read from table is same or newer than local info\n                        {\n                            if (localRem.IsRunning) // if ticking\n                            {\n                                LogTraceInTableInLocalOldTicking(localRem);\n                                // it might happen that our local reminder is different than the one in the table, i.e., eTag is different\n                                // if so, stop the local timer for the old reminder, and start again with new info\n                                if (!localRem.ETag.Equals(entry.ETag))\n                                // this reminder needs a restart\n                                {\n                                    LogTraceLocalReminderNeedsRestart(localRem);\n                                    localRem.StopReminder();\n                                    localReminders.Remove(localRem.Identity);\n                                    StartAndAddTimer(entry);\n                                }\n                            }\n                            else // if not ticking\n                            {\n                                // no-op\n                                LogTraceInTableInLocalOldNotTicking(localRem);\n                            }\n                        }\n                        else // cachedSequence < localRem.LocalSequenceNumber ... // info read from table is older than local info\n                        {\n                            if (localRem.IsRunning) // if ticking\n                            {\n                                // no-op\n                                LogTraceInTableInLocalNewerTicking(localRem);\n                            }\n                            else // if not ticking\n                            {\n                                // no-op\n                                LogTraceInTableInLocalNewerNotTicking(localRem);\n                            }\n                        }\n                    }\n                    else // exists in table, but not locally\n                    {\n                        LogTraceInTableNotInLocal(entry);\n                        // create and start the reminder\n                        StartAndAddTimer(entry);\n                    }\n                    // keep a track of extra reminders ... this 'reminder' is useful, so remove it from extra list\n                    remindersNotInTable.Remove(key);\n                } // foreach reminder read from table\n\n                int remindersCountBeforeRemove = localReminders.Count;\n\n                // foreach reminder that is not in global table, but exists locally\n                foreach (var kv in remindersNotInTable)\n                {\n                    var reminder = kv.Value;\n                    if (cachedSequence < reminder.LocalSequenceNumber)\n                    {\n                        // no-op\n                        LogTraceNotInTableInLocalNewer(reminder);\n                    }\n                    else // cachedSequence > reminder.LocalSequenceNumber\n                    {\n                        LogTraceNotInTableInLocalOld(reminder);\n                        // remove locally\n                        reminder.StopReminder();\n                        localReminders.Remove(reminder.Identity);\n                    }\n                }\n                LogDebugRemovedRemindersFromLocalTable(localReminders.Count - remindersCountBeforeRemove);\n            }\n            catch (Exception exc)\n            {\n                LogErrorFailedToReadTableAndStartTimer(exc);\n                throw;\n            }\n        }\n\n        private void StartAndAddTimer(ReminderEntry entry)\n        {\n            // it might happen that we already have a local reminder with a different eTag\n            // if so, stop the local timer for the old reminder, and start again with new info\n            // Note: it can happen here that we restart a reminder that has the same eTag as what we just registered ... its a rare case, and restarting it doesn't hurt, so we don't check for it\n            if (localReminders.TryGetValue(new(entry.GrainId, entry.ReminderName), out var prevReminder)) // if found locally\n            {\n                LogDebugLocallyStoppingReminder(prevReminder, entry);\n                prevReminder.StopReminder();\n                localReminders.Remove(prevReminder.Identity);\n            }\n\n            var newReminder = new LocalReminderData(entry, this);\n            localTableSequence++;\n            newReminder.LocalSequenceNumber = localTableSequence;\n            localReminders.Add(newReminder.Identity, newReminder);\n            newReminder.StartTimer();\n            LogDebugStartedReminder(entry);\n        }\n\n        // stop without removing it. will remove later.\n        private bool TryStopPreviousTimer(GrainId grainId, string reminderName)\n        {\n            // we stop the locally running timer for this reminder\n            if (!localReminders.TryGetValue(new(grainId, reminderName), out var localRem)) return false;\n\n            // if we have it locally\n            localTableSequence++; // move to next sequence\n            localRem.LocalSequenceNumber = localTableSequence;\n            localRem.StopReminder();\n            return true;\n        }\n\n        private Task DoResponsibilitySanityCheck(GrainId grainId, string debugInfo)\n        {\n            switch (Status)\n            {\n                case GrainServiceStatus.Booting:\n                    // if service didn't finish the initial load, it could still be loading normally or it might have already\n                    // failed a few attempts and callers should not be hold waiting for it to complete\n                    var task = this.startedTask.Task;\n                    if (task.IsCompleted)\n                    {\n                        // task at this point is already Faulted\n                        task.GetAwaiter().GetResult();\n                    }\n                    else\n                    {\n                        return WaitForInitCompletion();\n                        async Task WaitForInitCompletion()\n                        {\n                            try\n                            {\n                                // wait for the initial load task to complete (with a timeout)\n                                await task.WaitAsync(InitialReadMaxWaitTimeForUpdates);\n                            }\n                            catch (TimeoutException ex)\n                            {\n                                throw new OrleansException(\"Reminder Service is still initializing and it is taking a long time. Please retry again later.\", ex);\n                            }\n                            CheckRange();\n                        }\n                    }\n                    break;\n                case GrainServiceStatus.Started:\n                    break;\n                case GrainServiceStatus.Stopped:\n                    throw new OperationCanceledException(\"ReminderService has been stopped.\");\n                default:\n                    throw new InvalidOperationException(\"status\");\n            }\n            CheckRange();\n            return Task.CompletedTask;\n\n            void CheckRange()\n            {\n                if (!RingRange.InRange(grainId))\n                {\n                    LogWarningNotResponsible(debugInfo, grainId, RingRange);\n                    // For now, we still let the caller proceed without throwing an exception... the periodical mechanism will take care of reminders being registered at the wrong silo\n                    // otherwise, we can either reject the request, or re-route the request\n                }\n            }\n        }\n\n        // Note: The list of reminders can be huge in production!\n        private void PrintReminders(string msg = null)\n        {\n            if (!logger.IsEnabled(LogLevel.Trace)) return;\n\n            var str = $\"{(msg ?? \"Current list of reminders:\")}{Environment.NewLine}{Utils.EnumerableToString(localReminders, null, Environment.NewLine)}\";\n            logger.LogTrace(\"{Message}\", str);\n        }\n\n        private IRemindable GetGrain(GrainId grainId) => (IRemindable)_referenceActivator.CreateReference(grainId, _grainInterfaceType);\n\n        private sealed class LocalReminderData\n        {\n            private readonly IRemindable remindable;\n            private readonly DateTime firstTickTime; // time for the first tick of this reminder\n            private readonly TimeSpan period;\n            private readonly ILogger logger;\n            private readonly IAsyncTimer timer;\n\n            private ValueStopwatch stopwatch;\n            private Task runTask;\n\n            internal LocalReminderData(ReminderEntry entry, LocalReminderService reminderService)\n            {\n                Identity = new ReminderIdentity(entry.GrainId, entry.ReminderName);\n                firstTickTime = entry.StartAt;\n                period = entry.Period;\n                remindable = reminderService.GetGrain(entry.GrainId);\n                ETag = entry.ETag;\n                LocalSequenceNumber = -1;\n                logger = reminderService.logger;\n                this.timer = reminderService.asyncTimerFactory.Create(period, \"\");\n            }\n\n            public ReminderIdentity Identity { get; }\n\n            public string ETag { get; }\n\n            /// <summary>\n            /// Locally, we use this for resolving races between the periodic table reader, and any concurrent local register/unregister requests\n            /// </summary>\n            public long LocalSequenceNumber { get; set; }\n\n            /// <summary>\n            /// Gets a value indicating whether this instance is running.\n            /// </summary>\n            public bool IsRunning => runTask is Task task && !task.IsCompleted;\n\n            public void StartTimer()\n            {\n                if (runTask is null)\n                {\n                    using var suppressExecutionContext = new ExecutionContextSuppressor();\n                    this.runTask = this.RunAsync();\n                }\n                else\n                {\n                    throw new InvalidOperationException($\"{nameof(StartTimer)} may only be called once per instance and has already been called on this instance.\");\n                }\n            }\n\n            public void StopReminder()\n            {\n                timer.Dispose();\n            }\n\n            private async Task RunAsync()\n            {\n                TimeSpan? dueTimeSpan = CalculateDueTime();\n                while (await this.timer.NextTick(dueTimeSpan))\n                {\n                    try\n                    {\n                        await OnTimerTick();\n                        ReminderInstruments.TicksDelivered.Add(1);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogWarningFiringReminder(logger, Identity.ReminderName, Identity.GrainId, exception);\n                    }\n\n                    dueTimeSpan = CalculateDueTime();\n                }\n            }\n\n            private TimeSpan CalculateDueTime()\n            {\n                TimeSpan dueTimeSpan;\n                var now = DateTime.UtcNow;\n                if (now < firstTickTime) // if the time for first tick hasn't passed yet\n                {\n                    dueTimeSpan = firstTickTime.Subtract(now); // then duetime is duration between now and the first tick time\n                }\n                else // the first tick happened in the past ... compute duetime based on the first tick time, and period\n                {\n                    // formula used:\n                    // due = period - 'time passed since last tick (==sinceLast)'\n                    // due = period - ((Now - FirstTickTime) % period)\n                    // explanation of formula:\n                    // (Now - FirstTickTime) => gives amount of time since first tick happened\n                    // (Now - FirstTickTime) % period => gives amount of time passed since the last tick should have triggered\n                    var sinceFirstTick = now.Subtract(firstTickTime);\n                    var sinceLastTick = TimeSpan.FromTicks(sinceFirstTick.Ticks % period.Ticks);\n                    dueTimeSpan = period.Subtract(sinceLastTick);\n\n                    // in corner cases, dueTime can be equal to period ... so, take another mod\n                    dueTimeSpan = TimeSpan.FromTicks(dueTimeSpan.Ticks % period.Ticks);\n                }\n\n                // If the previous tick took no percievable time, be sure to wait at least one period until the next tick.\n                // If the previous tick took one period or greater, then we will skip up to one period.\n                // That is preferable over double-firing for fast ticks, which are expected to be more common.\n                if (dueTimeSpan <= TimeSpan.FromMilliseconds(30))\n                {\n                    dueTimeSpan = period;\n                }\n\n                return dueTimeSpan;\n            }\n\n            public async Task OnTimerTick()\n            {\n                var before = DateTime.UtcNow;\n                var status = new TickStatus(firstTickTime, period, before);\n\n                LogTraceTriggeringTick(logger, this, status, before);\n                try\n                {\n                    if (stopwatch.IsRunning)\n                    {\n                        stopwatch.Stop();\n                        var tardiness = stopwatch.Elapsed - period;\n                        ReminderInstruments.TardinessSeconds.Record(Math.Max(0, tardiness.TotalSeconds));\n                    }\n\n                    await remindable.ReceiveReminder(Identity.ReminderName, status);\n\n                    stopwatch.Restart();\n\n                    var after = DateTime.UtcNow;\n                    LogTraceTickTriggered(logger, this, (after - before).TotalSeconds, after + period);\n                }\n                catch (Exception exc)\n                {\n                    var after = DateTime.UtcNow;\n                    LogErrorDeliveringReminderTick(logger, this, after + period, exc);\n                    // What to do with repeated failures to deliver a reminder's ticks?\n                }\n            }\n\n            public override string ToString()\n                => $\"[{Identity.ReminderName}, {Identity.GrainId}, {period}, {LogFormatter.PrintDate(firstTickTime)}, {ETag}, {LocalSequenceNumber}, {(timer == null ? \"Not_ticking\" : \"Ticking\")}]\";\n        }\n\n        private readonly struct ReminderIdentity : IEquatable<ReminderIdentity>\n        {\n            public readonly GrainId GrainId;\n            public readonly string ReminderName;\n\n            public ReminderIdentity(GrainId grainId, string reminderName)\n            {\n                if (grainId.IsDefault)\n                    throw new ArgumentNullException(nameof(grainId));\n\n                if (string.IsNullOrWhiteSpace(reminderName))\n                    throw new ArgumentException(\"The reminder name is either null or whitespace.\", nameof(reminderName));\n\n                this.GrainId = grainId;\n                this.ReminderName = reminderName;\n            }\n\n            public readonly bool Equals(ReminderIdentity other) => GrainId.Equals(other.GrainId) && ReminderName.Equals(other.ReminderName);\n\n            public override readonly bool Equals(object other) => other is ReminderIdentity id && Equals(id);\n\n            public override readonly int GetHashCode() => HashCode.Combine(GrainId, ReminderName);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error activating reminder service.\"\n        )]\n        private partial void LogErrorActivatingReminderService(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error stopping reminder service.\"\n        )]\n        private partial void LogErrorStoppingReminderService(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error starting reminder service.\"\n        )]\n        private partial void LogErrorStartingReminderService(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_RegisterOrUpdate,\n            Message = \"RegisterOrUpdateReminder: {Entry}\"\n        )]\n        private partial void LogDebugRegisterOrUpdateReminder(ReminderEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Registered reminder {Entry} in table, assigned localSequence {LocalSequence}\"\n        )]\n        private partial void LogDebugRegisterReminder(ReminderEntry entry, long localSequence);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.RS_Register_TableError,\n            Message = \"Could not register reminder {Entry} to reminder table due to a race. Please try again later.\"\n        )]\n        private partial void LogErrorRegisterReminder(ReminderEntry entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_Unregister,\n            Message = \"UnregisterReminder: {Entry}, LocalTableSequence: {LocalTableSequence}\"\n        )]\n        private partial void LogDebugUnregisterReminder(IGrainReminder entry, long localTableSequence);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_Stop,\n            Message = \"Stopped reminder {Entry}\"\n        )]\n        private partial void LogStoppedReminder(IGrainReminder entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_RemoveFromTable,\n            Message = \"Removed reminder from table which I didn't have locally: {Entry}.\"\n        )]\n        private partial void LogRemovedReminderFromTable(IGrainReminder entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.RS_Unregister_TableError,\n            Message = \"Could not unregister reminder {Reminder} from the reminder table, due to tag mismatch. You can retry.\"\n        )]\n        private partial void LogErrorUnregisterReminder(IGrainReminder reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_GetReminder,\n            Message = \"GetReminder: GrainId={GrainId} ReminderName={ReminderName}\"\n        )]\n        private partial void LogDebugGetReminder(GrainId grainId, string reminderName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_GetReminders,\n            Message = \"GetReminders: GrainId={GrainId}\"\n        )]\n        private partial void LogDebugGetReminders(GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"My range {RingRange}, RangeSerialNumber {RangeSerialNumber}. Local reminders count {LocalRemindersCount}\"\n        )]\n        private partial void LogTraceRingRange(IRingRange ringRange, int rangeSerialNumber, int localRemindersCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Not in my range anymore, so removing. {Reminder}\"\n        )]\n        private partial void LogTraceRemovingReminder(LocalReminderData reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Removed {RemovedCount} local reminders that are now out of my range.\"\n        )]\n        private partial void LogInfoRemovedLocalReminders(int removedCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Ignoring range change until ReminderService is Started -- Current status = {Status}\"\n        )]\n        private partial void LogIgnoringRangeChange(GrainServiceStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception while reading reminders\"\n        )]\n        private partial void LogWarningReadingReminders(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.RS_ServiceInitialLoadFailing,\n            Message = \"ReminderService failed initial load of reminders and will retry. Attempt #{AttemptNumber}\"\n        )]\n        private partial void LogWarningInitialLoadFailing(Exception exception, uint attemptNumber);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.RS_ServiceInitialLoadFailed,\n            Message = \"ReminderService failed initial load of reminders and cannot guarantee that the service will be eventually start without manual intervention or restarting the silo. Attempt #{AttemptNumber}\"\n        )]\n        private partial void LogErrorInitialLoadFailed(Exception exception, uint attemptNumber);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Reading rows from {Range}\"\n        )]\n        private partial void LogDebugReadingRows(IRingRange range);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"My range changed while reading from the table, ignoring the results. Another read has been started. RangeSerialNumber {RangeSerialNumber}, RangeSerialNumberCopy {RangeSerialNumberCopy}.\"\n        )]\n        private partial void LogDebugRangeChangedWhileFromTable(int rangeSerialNumber, int rangeSerialNumberCopy);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"For range {Range}, I read in {ReminderCount} reminders from table. LocalTableSequence {LocalTableSequence}, CachedSequence {CachedSequence}\"\n        )]\n        private partial void LogDebugReadRemindersFromTable(IRingRange range, int reminderCount, long localTableSequence, long cachedSequence);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"In table, In local, Old, & Ticking {LocalReminder}\"\n        )]\n        private partial void LogTraceInTableInLocalOldTicking(LocalReminderData localReminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{LocalReminder} Needs a restart\"\n        )]\n        private partial void LogTraceLocalReminderNeedsRestart(LocalReminderData localReminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"In table, In local, Old, & Not Ticking {LocalReminder}\"\n        )]\n        private partial void LogTraceInTableInLocalOldNotTicking(LocalReminderData localReminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"In table, In local, Newer, & Ticking {LocalReminder}\"\n        )]\n        private partial void LogTraceInTableInLocalNewerTicking(LocalReminderData localReminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"In table, In local, Newer, & Not Ticking {LocalReminder}\"\n        )]\n        private partial void LogTraceInTableInLocalNewerNotTicking(LocalReminderData localReminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"In table, Not in local, {Reminder}\"\n        )]\n        private partial void LogTraceInTableNotInLocal(ReminderEntry reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Not in table, In local, Newer, {Reminder}\"\n        )]\n        private partial void LogTraceNotInTableInLocalNewer(LocalReminderData reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Not in table, In local, Old, so removing. {Reminder}\"\n        )]\n        private partial void LogTraceNotInTableInLocalOld(LocalReminderData reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Removed {RemovedCount} reminders from local table\"\n        )]\n        private partial void LogDebugRemovedRemindersFromLocalTable(int removedCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.RS_FailedToReadTableAndStartTimer,\n            Message = \"Failed to read rows from table.\"\n        )]\n        private partial void LogErrorFailedToReadTableAndStartTimer(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_LocalStop,\n            Message = \"Locally stopping reminder {PreviousReminder} as it is different than newly registered reminder {Reminder}\"\n        )]\n        private partial void LogDebugLocallyStoppingReminder(LocalReminderData previousReminder, ReminderEntry reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.RS_Started,\n            Message = \"Started reminder {Reminder}.\"\n        )]\n        private partial void LogDebugStartedReminder(ReminderEntry reminder);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.RS_NotResponsible,\n            Message = \"I shouldn't have received request '{Request}' for {GrainId}. It is not in my responsibility range: {Range}\"\n        )]\n        private partial void LogWarningNotResponsible(string request, GrainId grainId, IRingRange range);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception firing reminder \\\"{ReminderName}\\\" for grain {GrainId}\"\n        )]\n        private static partial void LogWarningFiringReminder(ILogger logger, string reminderName, GrainId grainId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Triggering tick for {Instance}, status {Status}, now {CurrentTime}\"\n        )]\n        private static partial void LogTraceTriggeringTick(ILogger logger, LocalReminderData instance, TickStatus status, DateTime currentTime);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Tick triggered for {Instance}, dt {DueTime} sec, next@~ {NextDueTime}\"\n        )]\n        private static partial void LogTraceTickTriggered(ILogger logger, LocalReminderData instance, double dueTime, DateTime nextDueTime);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not deliver reminder tick for {Instance}, next {NextDueTime}.\"\n        )]\n        private static partial void LogErrorDeliveringReminderTick(ILogger logger, LocalReminderData instance, DateTime nextDueTime, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/ReminderService/ReminderRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime.Services;\nusing Orleans.Timers;\n\n#nullable enable\nnamespace Orleans.Runtime.ReminderService\n{\n    internal sealed class ReminderRegistry : GrainServiceClient<IReminderService>, IReminderRegistry\n    {\n        private IServiceProvider? serviceProvider;\n        private readonly ReminderOptions options;\n\n        public ReminderRegistry(IServiceProvider serviceProvider, IOptions<ReminderOptions> options) : base(serviceProvider)\n        {\n            this.serviceProvider = serviceProvider;\n            this.options = options.Value;\n        }\n\n        public Task<IGrainReminder> RegisterOrUpdateReminder(GrainId callingGrainId, string reminderName, TimeSpan dueTime, TimeSpan period)\n        {\n            // Perform input volatility checks \n            if (dueTime == Timeout.InfiniteTimeSpan)\n                throw new ArgumentOutOfRangeException(nameof(dueTime), \"Cannot use InfiniteTimeSpan dueTime to create a reminder\");\n\n            if (dueTime.Ticks < 0)\n                throw new ArgumentOutOfRangeException(nameof(dueTime), \"Cannot use negative dueTime to create a reminder\");\n\n            if (period == Timeout.InfiniteTimeSpan)\n                throw new ArgumentOutOfRangeException(nameof(period), \"Cannot use InfiniteTimeSpan period to create a reminder\");\n\n            if (period.Ticks < 0)\n                throw new ArgumentOutOfRangeException(nameof(period), \"Cannot use negative period to create a reminder\");\n            \n            var minReminderPeriod = options.MinimumReminderPeriod;\n            if (period < minReminderPeriod)\n                throw new ArgumentException($\"Cannot register reminder {reminderName} as requested period ({period}) is less than minimum allowed reminder period ({minReminderPeriod})\");\n\n            if (string.IsNullOrEmpty(reminderName))\n                throw new ArgumentException(\"Cannot use null or empty name for the reminder\", nameof(reminderName));\n\n            EnsureReminderServiceRegisteredAndInGrainContext();\n            return GetGrainService(callingGrainId).RegisterOrUpdateReminder(callingGrainId, reminderName, dueTime, period);\n        }\n\n        public Task UnregisterReminder(GrainId callingGrainId, IGrainReminder reminder)\n        {\n            EnsureReminderServiceRegisteredAndInGrainContext();\n            return GetGrainService(callingGrainId).UnregisterReminder(reminder);\n        }\n\n        public Task<IGrainReminder> GetReminder(GrainId callingGrainId, string reminderName)\n        {\n            if (string.IsNullOrEmpty(reminderName))\n                throw new ArgumentException(\"Cannot use null or empty name for the reminder\", nameof(reminderName));\n\n            EnsureReminderServiceRegisteredAndInGrainContext();\n            return GetGrainService(callingGrainId).GetReminder(callingGrainId, reminderName);\n        }\n\n        public Task<List<IGrainReminder>> GetReminders(GrainId callingGrainId)\n        {\n            EnsureReminderServiceRegisteredAndInGrainContext();\n            return GetGrainService(callingGrainId).GetReminders(callingGrainId);\n        }\n\n        private void EnsureReminderServiceRegisteredAndInGrainContext()\n        {\n            if (RuntimeContext.Current is null) ThrowInvalidContext();\n            if (serviceProvider != null) ValidateServiceProvider();\n        }\n\n        private void ValidateServiceProvider()\n        {\n            if (serviceProvider is { } sp && sp.GetService<IReminderTable>() is null)\n            {\n                throw new OrleansConfigurationException(\n                    \"The reminder service has not been configured. Reminders can be configured using extension methods from the following packages:\"\n                    + \"\\n  * Microsoft.Orleans.Reminders.AzureStorage via ISiloBuilder.UseAzureTableReminderService(...)\"\n                    + \"\\n  * Microsoft.Orleans.Reminders.AdoNet via ISiloBuilder.UseAdoNetReminderService(...)\"\n                    + \"\\n  * Microsoft.Orleans.Reminders.DynamoDB via via ISiloBuilder.UseDynamoDBReminderService(...)\"\n                    + \"\\n  * Microsoft.Orleans.OrleansRuntime via ISiloBuilder.UseInMemoryReminderService(...) (Note: for development purposes only)\"\n                    + \"\\n  * Others, see: https://www.nuget.org/packages?q=Microsoft.Orleans.Reminders.\");\n            }\n\n            serviceProvider = null;\n        }\n\n        private static void ThrowInvalidContext()\n        {\n            throw new InvalidOperationException(\"Attempted to access grain from a non-grain context, such as a background thread, which is invalid.\"\n                + \" Ensure that you are only accessing grain functionality from within the context of a grain.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/SystemTargetInterfaces/IReminderService.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Services;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Functionality for managing reminders.\n    /// </summary>\n    public interface IReminderService : IGrainService\n    {\n        /// <summary>\n        /// Starts the service.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Start();\n\n        /// <summary>\n        /// Stops the service.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Stop();\n\n        /// <summary>\n        /// Registers a new reminder or updates an existing one.\n        /// </summary>\n        /// <param name=\"grainId\">A reference to the grain which the reminder is being registered or updated on behalf of.</param>\n        /// <param name=\"reminderName\">The reminder name.</param>\n        /// <param name=\"dueTime\">The amount of time to delay before firing the reminder initially.</param>\n        /// <param name=\"period\">The time interval between invocations of the reminder.</param>\n        /// <returns>The reminder.</returns>\n        Task<IGrainReminder> RegisterOrUpdateReminder(GrainId grainId, string reminderName, TimeSpan dueTime, TimeSpan period);\n\n        /// <summary>\n        /// Unregisters the specified reminder.\n        /// </summary>\n        /// <param name=\"reminder\">The reminder.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task UnregisterReminder(IGrainReminder reminder);\n\n        /// <summary>\n        /// Gets the reminder registered to the specified grain with the provided name.\n        /// </summary>\n        /// <param name=\"grainId\">A reference to the grain which the reminder is registered on.</param>\n        /// <param name=\"reminderName\">The name of the reminder.</param>\n        /// <returns>The reminder.</returns>\n        Task<IGrainReminder> GetReminder(GrainId grainId, string reminderName);\n\n        /// <summary>\n        /// Gets all reminders registered for the specified grain.\n        /// </summary>\n        /// <param name=\"grainId\">A reference to the grain.</param>\n        /// <returns>A list of all registered reminders for the specified grain.</returns>\n        Task<List<IGrainReminder>> GetReminders(GrainId grainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/SystemTargetInterfaces/IReminderTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Interface for implementations of the underlying storage for reminder data:\n    /// Azure Table, SQL, development emulator grain, and a mock implementation.\n    /// Defined as a grain interface for the development emulator grain case.\n    /// </summary>  \n    public interface IReminderTable\n    {\n        /// <summary>\n        /// Initializes this instance.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task StartAsync(CancellationToken cancellationToken = default)\n#pragma warning disable CS0618 // Type or member is obsolete\n            => Init();\n#pragma warning restore CS0618 // Type or member is obsolete\n\n        /// <summary>\n        /// Initializes this instance.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        [Obsolete(\"Implement and use StartAsync instead\")]\n        Task Init() => Task.CompletedTask;\n\n        /// <summary>\n        /// Reads the reminder table entries associated with the specified grain.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <returns>The reminder table entries associated with the specified grain.</returns>\n        Task<ReminderTableData> ReadRows(GrainId grainId);\n\n        /// <summary>\n        /// Returns all rows that have their <see cref=\"GrainId.GetUniformHashCode\"/> in the range (begin, end].\n        /// If begin is greater or equal to end, returns all entries with hash greater begin or hash less or equal to end.\n        /// </summary>\n        /// <param name=\"begin\">The exclusive lower bound.</param>\n        /// <param name=\"end\">The inclusive upper bound.</param>\n        /// <returns>The reminder table entries which fall within the specified range.</returns>\n        Task<ReminderTableData> ReadRows(uint begin, uint end);\n\n        /// <summary>\n        /// Reads the specified entry.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <param name=\"reminderName\">Name of the reminder.</param>\n        /// <returns>The reminder table entry.</returns>\n        Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName);\n\n        /// <summary>\n        /// Upserts the specified entry.\n        /// </summary>\n        /// <param name=\"entry\">The entry.</param>\n        /// <returns>The row's new ETag.</returns>\n        Task<string> UpsertRow(ReminderEntry entry);\n\n        /// <summary>\n        /// Removes a row from the table.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <param name=\"reminderName\">The reminder name.</param>\n        /// /// <param name=\"eTag\">The ETag.</param>\n        /// <returns>true if a row with <paramref name=\"grainId\"/> and <paramref name=\"reminderName\"/> existed and was removed successfully, false otherwise</returns>\n        Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag);\n\n        /// <summary>\n        /// Clears the table.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task TestOnlyClearTable();\n\n        /// <summary>\n        /// Stops the reminder table.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task StopAsync(CancellationToken cancellationToken = default) => Task.CompletedTask;\n    }\n\n    /// <summary>\n    /// Reminder table interface for grain based implementation.\n    /// </summary>\n    internal interface IReminderTableGrain : IGrainWithIntegerKey\n    {\n        Task<ReminderTableData> ReadRows(GrainId grainId);\n\n        Task<ReminderTableData> ReadRows(uint begin, uint end);\n\n        Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName);\n\n        Task<string> UpsertRow(ReminderEntry entry);\n\n        Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag);\n\n        Task TestOnlyClearTable();\n    }\n\n    /// <summary>\n    /// Represents a collection of reminder table entries.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ReminderTableData\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReminderTableData\"/> class.\n        /// </summary>\n        /// <param name=\"list\">The entries.</param>\n        public ReminderTableData(IEnumerable<ReminderEntry> list)\n        {\n            Reminders = new List<ReminderEntry>(list);\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReminderTableData\"/> class.\n        /// </summary>\n        /// <param name=\"entry\">The entry.</param>\n        public ReminderTableData(ReminderEntry entry)\n        {\n            Reminders = new[] { entry };\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReminderTableData\"/> class.\n        /// </summary>\n        public ReminderTableData()\n        {\n            Reminders = Array.Empty<ReminderEntry>();\n        }\n\n        /// <summary>\n        /// Gets the reminders.\n        /// </summary>\n        /// <value>The reminders.</value>\n        [Id(0)]\n        public IList<ReminderEntry> Reminders { get; private set; }\n\n        /// <summary>\n        /// Returns a <see cref=\"string\" /> that represents this instance.\n        /// </summary>\n        /// <returns>A <see cref=\"string\" /> that represents this instance.</returns>\n        public override string ToString() => $\"[{Reminders.Count} reminders: {Utils.EnumerableToString(Reminders)}.\";\n    }\n\n    /// <summary>\n    /// Represents a reminder table entry.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ReminderEntry\n    {\n        /// <summary>\n        /// Gets or sets the grain ID of the grain that created the reminder. Forms the reminder\n        /// primary key together with <see cref=\"ReminderName\"/>.\n        /// </summary>\n        [Id(0)]\n        public GrainId GrainId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the reminder. Forms the reminder primary key together with \n        /// <see cref=\"GrainId\"/>.\n        /// </summary>\n        [Id(1)]\n        public string ReminderName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the time when the reminder was supposed to tick in the first time\n        /// </summary>\n        [Id(2)]\n        public DateTime StartAt { get; set; }\n\n        /// <summary>\n        /// Gets or sets the time period for the reminder\n        /// </summary>\n        [Id(3)]\n        public TimeSpan Period { get; set; }\n\n        /// <summary>\n        /// Gets or sets the ETag.\n        /// </summary>\n        /// <value>The ETag.</value>\n        [Id(4)]\n        public string ETag { get; set; }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"<GrainId={GrainId} ReminderName={ReminderName} Period={Period}>\";\n\n        /// <summary>\n        /// Returns an <see cref=\"IGrainReminder\"/> representing the data in this instance.\n        /// </summary>\n        /// <returns>The <see cref=\"IGrainReminder\"/>.</returns>\n        internal IGrainReminder ToIGrainReminder() => new ReminderData(GrainId, ReminderName, ETag);\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class ReminderData : IGrainReminder\n    {\n        [Id(0)]\n        public readonly GrainId GrainId;\n        [Id(1)]\n        public string ReminderName { get; }\n        [Id(2)]\n        public readonly string ETag;\n\n        internal ReminderData(GrainId grainId, string reminderName, string eTag)\n        {\n            GrainId = grainId;\n            ReminderName = reminderName;\n            ETag = eTag;\n        }\n\n        public override string ToString() => $\"<IOrleansReminder: GrainId={GrainId} ReminderName={ReminderName} ETag={ETag}>\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Timers/IRemindable.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Threading.Tasks;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Callback interface that grains must implement in order to be able to register and receive Reminders.\n    /// </summary>\n    public interface IRemindable : IGrain\n    {\n        /// <summary>\n        /// Receive a new Reminder.\n        /// </summary>\n        /// <param name=\"reminderName\">Name of this Reminder</param>\n        /// <param name=\"status\">Status of this Reminder tick</param>\n        /// <returns>Completion promise which the grain will resolve when it has finished processing this Reminder tick.</returns>\n        Task ReceiveReminder(string reminderName, Runtime.TickStatus status);\n    }\n\n    namespace Runtime\n    {\n        /// <summary>\n        /// Handle for a persistent Reminder.\n        /// </summary>\n        public interface IGrainReminder\n        {\n            /// <summary>\n            /// Gets the name of this reminder.\n            /// </summary>\n            string ReminderName { get; }\n        }\n\n        /// <summary>\n        /// The status of a tick when the tick is delivered to the registrar grain.\n        /// In case of failures, it may happen that a tick is not delivered on time. The app can notice such missed ticks as follows.\n        /// Upon receiving a tick, the app can calculate the theoretical number of ticks since start of the reminder as: \n        /// curCount = (Now - FirstTickTime) / Period\n        /// The app can keep track of it as 'count'. Upon receiving a tick, the number of missed ticks = curCount - count - 1\n        /// Thereafter, the app can set count = curCount\n        /// </summary>\n        [Serializable, GenerateSerializer, Immutable]\n        public readonly struct TickStatus\n        {\n            /// <summary>\n            /// Gets the time at which the first tick of this reminder is due, or was triggered.\n            /// </summary>\n            [Id(0)]\n            public DateTime FirstTickTime { get; }\n\n            /// <summary>\n            /// Gets the period of the reminder.\n            /// </summary>\n            [Id(1)]\n            public TimeSpan Period { get; }\n\n            /// <summary>\n            /// Gets the time on the runtime silo when the silo initiated the delivery of this tick.\n            /// </summary>\n            [Id(2)]\n            public DateTime CurrentTickTime { get; }\n\n            /// <summary>\n            /// Creates a new <see cref=\"TickStatus\"/> instance.\n            /// </summary>\n            /// <param name=\"firstTickTime\">The time at which the first tick of the reminder is due.</param>\n            /// <param name=\"period\">The period of the reminder.</param>\n            /// <param name=\"timeStamp\">The time when delivery of the current tick was initiated.</param>\n            /// <returns></returns>\n            public TickStatus(DateTime firstTickTime, TimeSpan period, DateTime timeStamp)\n            {\n                FirstTickTime = firstTickTime;\n                Period = period;\n                CurrentTickTime = timeStamp;\n            }\n\n            /// <inheritdoc/>\n            public override string ToString() => $\"<{FirstTickTime}, {Period}, {CurrentTickTime}>\";\n        }\n\n        /// <summary>\n        /// Exception related to Orleans Reminder functions or Reminder service.\n        /// </summary>\n        [Serializable, GenerateSerializer]\n        public sealed class ReminderException : OrleansException\n        {\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"ReminderException\"/> class.\n            /// </summary>\n            /// <param name=\"message\">The message.</param>\n            public ReminderException(string message) : base(message) { }\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"ReminderException\"/> class.\n            /// </summary>\n            /// <param name=\"info\">The serialization info.</param>\n            /// <param name=\"context\">The context.</param>\n            [Obsolete]\n            public ReminderException(SerializationInfo info, StreamingContext context)\n                : base(info, context)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Reminders/Timers/IReminderRegistry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Services;\n\nnamespace Orleans.Timers\n{\n    /// <summary>\n    /// Functionality for managing reminders.\n    /// </summary>\n    public interface IReminderRegistry : IGrainServiceClient<IReminderService>\n    {\n        /// <summary>\n        /// Register or update the reminder with the specified name for the currently active grain.\n        /// </summary>\n        /// <param name=\"callingGrainId\">The ID of the the currently executing grain</param>\n        /// <param name=\"reminderName\">The reminder name.</param>\n        /// <param name=\"dueTime\">The amount of time to delay before initially invoking the reminder.</param>\n        /// <param name=\"period\">The time interval between invocations of the reminder.</param>\n        /// <returns>The reminder.</returns>\n        Task<IGrainReminder> RegisterOrUpdateReminder(GrainId callingGrainId, string reminderName, TimeSpan dueTime, TimeSpan period);\n\n        /// <summary>\n        /// Unregisters a reminder from the currently active grain.\n        /// </summary>\n        /// <param name=\"callingGrainId\">The ID of the the currently executing grain</param>\n        /// <param name=\"reminder\">The reminder to unregister.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task UnregisterReminder(GrainId callingGrainId, IGrainReminder reminder);\n\n        /// <summary>\n        /// Gets the reminder with the specified name which is registered to the currently active grain.\n        /// </summary>\n        /// <param name=\"callingGrainId\">The ID of the the currently executing grain</param>\n        /// <param name=\"reminderName\">The reminder name.</param>\n        /// <returns>The reminder.</returns>\n        Task<IGrainReminder> GetReminder(GrainId callingGrainId, string reminderName);\n\n        /// <summary>\n        /// Gets all reminders which are currently registered to the active grain.\n        /// </summary>\n        /// <param name=\"callingGrainId\">The ID of the the currently executing grain</param>\n        /// <returns>All reminders which are currently registered to the active grain.</returns>\n        Task<List<IGrainReminder>> GetReminders(GrainId callingGrainId);\n    }\n}"
  },
  {
    "path": "src/Orleans.Reminders.Abstractions/Orleans.Reminders.Abstractions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Reminders.Abstractions</PackageId>\n    <Title>Microsoft Orleans Reminders Abstractions</Title>\n    <Description>Reminders abstractions library for Microsoft Orleans</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <RootNamespace>Orleans</RootNamespace>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>$(DefineConstants);ORLEANS_REMINDERS_PROVIDER</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Options\" Version=\"$(MicrosoftExtensionsOptionsVersion)\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"$(MicrosoftExtensionsLoggingAbstractionsVersion)\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Reminders\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"TestExtensions\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Activation/ActivationDataActivatorProvider.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.ExceptionServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime\n{\n    internal partial class ActivationDataActivatorProvider : IGrainContextActivatorProvider\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly IActivationWorkingSet _activationWorkingSet;\n        private readonly ILogger<WorkItemGroup> _workItemGroupLogger;\n        private readonly ILogger<Grain> _grainLogger;\n        private readonly ILogger<ActivationTaskScheduler> _activationTaskSchedulerLogger;\n        private readonly IOptions<SchedulingOptions> _schedulingOptions;\n        private readonly GrainTypeSharedContextResolver _sharedComponentsResolver;\n        private readonly GrainClassMap _grainClassMap;\n        private readonly ILoggerFactory _loggerFactory;\n        private readonly GrainReferenceActivator _grainReferenceActivator;\n\n        public ActivationDataActivatorProvider(\n            GrainClassMap grainClassMap,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            GrainReferenceActivator grainReferenceActivator,\n            GrainTypeSharedContextResolver sharedComponentsResolver,\n            IActivationWorkingSet activationWorkingSet,\n            ILogger<Grain> grainLogger,\n            ILogger<WorkItemGroup> workItemGroupLogger,\n            ILogger<ActivationTaskScheduler> activationTaskSchedulerLogger,\n            IOptions<SchedulingOptions> schedulingOptions)\n        {\n            _activationWorkingSet = activationWorkingSet;\n            _workItemGroupLogger = workItemGroupLogger;\n            _grainLogger = grainLogger;\n            _activationTaskSchedulerLogger = activationTaskSchedulerLogger;\n            _schedulingOptions = schedulingOptions;\n            _sharedComponentsResolver = sharedComponentsResolver;\n            _grainClassMap = grainClassMap;\n            _serviceProvider = serviceProvider;\n            _loggerFactory = loggerFactory;\n            _grainReferenceActivator = grainReferenceActivator;\n        }\n\n        public bool TryGet(GrainType grainType, [NotNullWhen(true)] out IGrainContextActivator? activator)\n        {\n            if (!_grainClassMap.TryGetGrainClass(grainType, out var grainClass) || !typeof(IGrain).IsAssignableFrom(grainClass))\n            {\n                activator = null;\n                return false;\n            }\n\n            var sharedContext = _sharedComponentsResolver.GetComponents(grainType);\n            var instanceActivator = sharedContext.GetComponent<IGrainActivator>();\n            if (instanceActivator is null)\n            {\n                throw new InvalidOperationException($\"Could not find a suitable {nameof(IGrainActivator)} implementation for grain type {grainType}\");\n            }\n\n            var innerActivator = new ActivationDataActivator(\n                instanceActivator,\n                _serviceProvider,\n                sharedContext,\n                _grainLogger,\n                _workItemGroupLogger,\n                _activationTaskSchedulerLogger,\n                _schedulingOptions);\n\n            if (sharedContext.PlacementStrategy is StatelessWorkerPlacement)\n            {\n                activator = new StatelessWorkerActivator(sharedContext, innerActivator);\n            }\n            else\n            {\n                activator = innerActivator;\n            }\n\n            return true;\n        }\n\n        private partial class ActivationDataActivator : IGrainContextActivator\n        {\n            private readonly ILogger<WorkItemGroup> _workItemGroupLogger;\n            private readonly ILogger<ActivationTaskScheduler> _activationTaskSchedulerLogger;\n            private readonly IOptions<SchedulingOptions> _schedulingOptions;\n            private readonly IGrainActivator _grainActivator;\n            private readonly IServiceProvider _serviceProvider;\n            private readonly GrainTypeSharedContext _sharedComponents;\n            private readonly ILogger<Grain> _grainLogger;\n            private readonly Func<IGrainContext, WorkItemGroup> _createWorkItemGroup;\n            private readonly Action<object?> _startActivation;\n\n            public ActivationDataActivator(\n                IGrainActivator grainActivator,\n                IServiceProvider serviceProvider,\n                GrainTypeSharedContext sharedComponents,\n                ILogger<Grain> grainLogger,\n                ILogger<WorkItemGroup> workItemGroupLogger,\n                ILogger<ActivationTaskScheduler> activationTaskSchedulerLogger,\n                IOptions<SchedulingOptions> schedulingOptions)\n            {\n                _workItemGroupLogger = workItemGroupLogger;\n                _activationTaskSchedulerLogger = activationTaskSchedulerLogger;\n                _schedulingOptions = schedulingOptions;\n                _grainActivator = grainActivator;\n                _serviceProvider = serviceProvider;\n                _sharedComponents = sharedComponents;\n                _grainLogger = grainLogger;\n                _createWorkItemGroup = context => new WorkItemGroup(\n                    context,\n                    _workItemGroupLogger,\n                    _activationTaskSchedulerLogger,\n                    _schedulingOptions);\n                 _startActivation = state => ((ActivationData)state!).Start(_grainActivator);\n            }\n\n            public IGrainContext CreateContext(GrainAddress activationAddress)\n            {\n                var context = new ActivationData(\n                    activationAddress,\n                    _createWorkItemGroup,\n                    _serviceProvider,\n                    _sharedComponents);\n\n                using var ecSuppressor = ExecutionContext.SuppressFlow();\n                _ = Task.Factory.StartNew(\n                    _startActivation,\n                    context,\n                    CancellationToken.None,\n                    TaskCreationOptions.DenyChildAttach,\n                    context.ActivationTaskScheduler);\n                return context;\n            }\n\n            [LoggerMessage(\n                Level = LogLevel.Error,\n                Message = \"Failed to dispose grain '{GrainId}'.\"\n            )]\n            private static partial void LogErrorFailedToDisposeGrain(ILogger logger, Exception exception, GrainId grainId);\n        }\n    }\n\n    internal class StatelessWorkerActivator : IGrainContextActivator\n    {\n        private readonly IGrainContextActivator _innerActivator;\n        private readonly GrainTypeSharedContext _sharedContext;\n\n        public StatelessWorkerActivator(GrainTypeSharedContext sharedContext, IGrainContextActivator innerActivator)\n        {\n            _innerActivator = innerActivator;\n            _sharedContext = sharedContext;\n        }\n\n        public IGrainContext CreateContext(GrainAddress address) => new StatelessWorkerGrainContext(address, _sharedContext, _innerActivator);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Activation/ConfigureDefaultGrainActivator.cs",
    "content": "using System;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    internal class ConfigureDefaultGrainActivator : IConfigureGrainTypeComponents\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly GrainClassMap _grainClassMap;\n\n        public ConfigureDefaultGrainActivator(GrainClassMap grainClassMap, IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider;\n            _grainClassMap = grainClassMap;\n        }\n\n        public void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared)\n        {\n            if (shared.GetComponent<IGrainActivator>() is not null) return;\n\n            if (!_grainClassMap.TryGetGrainClass(grainType, out var grainClass))\n            {\n                return;\n            }\n\n            var instanceActivator = new DefaultGrainActivator(_serviceProvider, grainClass);\n            shared.SetComponent<IGrainActivator>(instanceActivator);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Activation/DefaultGrainActivator.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The default <see cref=\"IGrainActivator\"/> implementation.\n    /// </summary>\n    public class DefaultGrainActivator : IGrainActivator\n    {\n        private readonly ObjectFactory _grainInstanceFactory;\n        private readonly GrainConstructorArgumentFactory _argumentFactory;\n        private readonly Type _grainClass;\n\n        /// <summary>\n        /// Initializes a new <see cref=\"DefaultGrainActivator\"/> instance.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"grainClass\">The grain class.</param>\n        public DefaultGrainActivator(IServiceProvider serviceProvider, Type grainClass)\n        {\n            _argumentFactory = new GrainConstructorArgumentFactory(serviceProvider, grainClass);\n            _grainInstanceFactory = ActivatorUtilities.CreateFactory(grainClass, _argumentFactory.ArgumentTypes);\n            _grainClass = grainClass;\n        }\n\n        /// <inheritdoc/>\n        public object CreateInstance(IGrainContext context)\n        {\n            try\n            {\n                var args = _argumentFactory.CreateArguments(context);\n                return _grainInstanceFactory(context.ActivationServices, args);\n            }\n            catch (Exception exception)\n            {\n                throw new InvalidOperationException(\n                    $\"Failed to create an instance of grain type '{_grainClass}'. See {nameof(Exception.InnerException)} for details.\",\n                    exception);\n            }\n        }\n\n        /// <inheritdoc/>\n        public async ValueTask DisposeInstance(IGrainContext context, object instance)\n        {\n            switch (instance)\n            {\n                case IAsyncDisposable asyncDisposable:\n                    await asyncDisposable.DisposeAsync();\n                    break;\n                case IDisposable disposable:\n                    disposable.Dispose();\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Activation/GrainContextAccessor.cs",
    "content": "namespace Orleans.Runtime\n{\n    internal class GrainContextAccessor : IGrainContextAccessor\n    {\n        private readonly HostedClient _hostedClient;\n\n        public GrainContextAccessor(HostedClient hostedClient)\n        {\n            _hostedClient = hostedClient;\n        }\n\n        public IGrainContext GrainContext => RuntimeContext.Current ?? _hostedClient;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Activation/IGrainActivator.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Creates a grain instance for a given grain context.\n    /// </summary>\n    public interface IGrainActivator\n    {\n        /// <summary>\n        /// Returns a new grain instance for the provided grain context.\n        /// </summary>\n        /// <param name=\"context\">The grain context.</param>\n        /// <returns>The grain instance.</returns>\n        object CreateInstance(IGrainContext context);\n\n        /// <summary>\n        /// Disposes the provided grain instance which is associated with the provided grain context.\n        /// </summary>\n        /// <param name=\"context\">The grain context.</param>\n        /// <param name=\"instance\">The grain instance.</param>\n        /// <returns>A <see cref=\"ValueTask\"/> representing the work performed.</returns>\n        ValueTask DisposeInstance(IGrainContext context, object instance);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Activation/IGrainContextActivator.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Configuration;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Placement;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The central point for creating grain contexts.\n    /// </summary>\n    public sealed class GrainContextActivator\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly IGrainContextActivatorProvider[] _activatorProviders;\n        private readonly IConfigureGrainContextProvider[] _configuratorProviders;\n        private readonly GrainPropertiesResolver _resolver;\n        private ImmutableDictionary<GrainType, (IGrainContextActivator Activator, IConfigureGrainContext[] ConfigureActions)> _activators\n            = ImmutableDictionary<GrainType, (IGrainContextActivator, IConfigureGrainContext[])>.Empty;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainContextActivator\"/> class.\n        /// </summary>\n        /// <param name=\"providers\">The grain context activator providers.</param>\n        /// <param name=\"configureContextActions\">The <see cref=\"IConfigureGrainContext\"/> providers.</param>\n        /// <param name=\"grainPropertiesResolver\">The grain properties resolver.</param>\n        public GrainContextActivator(\n            IEnumerable<IGrainContextActivatorProvider> providers,\n            IEnumerable<IConfigureGrainContextProvider> configureContextActions,\n            GrainPropertiesResolver grainPropertiesResolver)\n        {\n            _resolver = grainPropertiesResolver;\n            _activatorProviders = providers.ToArray();\n            _configuratorProviders = configureContextActions.ToArray();\n        }\n\n        /// <summary>\n        /// Creates a new grain context for the provided grain address.\n        /// </summary>\n        /// <param name=\"address\">The grain address.</param>\n        /// <returns>The grain context.</returns>\n        public IGrainContext CreateInstance(GrainAddress address)\n        {\n            var grainId = address.GrainId;\n            if (!_activators.TryGetValue(grainId.Type, out var activator))\n            {\n                activator = this.CreateActivator(grainId.Type);\n            }\n\n            var result = activator.Activator.CreateContext(address);\n            foreach (var configure in activator.ConfigureActions)\n            {\n                configure.Configure(result);\n            }\n\n            return result;\n        }\n\n        private (IGrainContextActivator, IConfigureGrainContext[]) CreateActivator(GrainType grainType)\n        {\n            lock (_lockObj)\n            {\n                if (!_activators.TryGetValue(grainType, out var configuredActivator))\n                {\n                    IGrainContextActivator unconfiguredActivator = null;\n                    foreach (var provider in this._activatorProviders)\n                    {\n                        if (provider.TryGet(grainType, out unconfiguredActivator))\n                        {\n                            break;\n                        }\n                    }\n\n                    if (unconfiguredActivator is null)\n                    {\n                        throw new InvalidOperationException($\"Unable to find an {nameof(IGrainContextActivatorProvider)} for grain type {grainType}\");\n                    }\n\n                    var properties = _resolver.GetGrainProperties(grainType);\n                    List<IConfigureGrainContext> configureActions = new List<IConfigureGrainContext>();\n                    foreach (var provider in _configuratorProviders)\n                    {\n                        if (provider.TryGetConfigurator(grainType, properties, out var configurator))\n                        {\n                            configureActions.Add(configurator);\n                        }\n                    }\n\n                    configuredActivator = (unconfiguredActivator, configureActions.ToArray());\n                    _activators = _activators.SetItem(grainType, configuredActivator);\n                }\n\n                return configuredActivator;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Provides a <see cref=\"IGrainContextActivator\"/> for a specified grain type.\n    /// </summary>\n    public interface IGrainContextActivatorProvider\n    {\n        /// <summary>\n        /// Returns a grain context activator for the given grain type.\n        /// </summary>\n        /// <param name=\"grainType\">Type of the grain.</param>\n        /// <param name=\"activator\">The grain context activator.</param>\n        /// <returns><see langword=\"true\"/> if an appropriate activator was found, otherwise <see langword=\"false\"/>.</returns>\n        bool TryGet(GrainType grainType, [NotNullWhen(true)] out IGrainContextActivator activator);\n    }\n\n    /// <summary>\n    /// Creates a grain context for the given grain address.\n    /// </summary>\n    public interface IGrainContextActivator\n    {\n        /// <summary>\n        /// Creates a grain context for the given grain address.\n        /// </summary>\n        /// <param name=\"address\">The grain address.</param>\n        /// <returns>The newly created grain context.</returns>\n        public IGrainContext CreateContext(GrainAddress address);\n    }\n\n    /// <summary>\n    /// Provides a <see cref=\"IConfigureGrainContext\"/> instance for the provided grain type.\n    /// </summary>\n    public interface IConfigureGrainContextProvider\n    {\n        /// <summary>\n        /// Provides a <see cref=\"IConfigureGrainContext\" /> instance for the provided grain type.\n        /// </summary>\n        /// <param name=\"grainType\">Type of the grain.</param>\n        /// <param name=\"properties\">The grain properties.</param>\n        /// <param name=\"configurator\">The configuration provider.</param>\n        /// <returns><see langword=\"true\"/> if a configuration provider was found, <see langword=\"false\"/> otherwise.</returns>\n        bool TryGetConfigurator(GrainType grainType, GrainProperties properties, [NotNullWhen(true)] out IConfigureGrainContext configurator);\n    }\n\n    /// <summary>\n    /// Configures the provided grain context.\n    /// </summary>\n    public interface IConfigureGrainContext\n    {\n        /// <summary>\n        /// Configures the provided grain context.\n        /// </summary>\n        /// <param name=\"context\">The grain context.</param>\n        void Configure(IGrainContext context);\n    }\n\n    /// <summary>\n    /// Resolves components which are common to all instances of a given grain type.\n    /// </summary>\n    public class GrainTypeSharedContextResolver\n    {\n        private readonly ConcurrentDictionary<GrainType, GrainTypeSharedContext> _components = new();\n        private readonly IConfigureGrainTypeComponents[] _configurators;\n        private readonly GrainPropertiesResolver _grainPropertiesResolver;\n        private readonly Func<GrainType, GrainTypeSharedContext> _createFunc;\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainTypeSharedContextResolver\"/> class.\n        /// </summary>\n        /// <param name=\"configurators\">The grain type component configuration providers.</param>\n        /// <param name=\"grainPropertiesResolver\">The grain properties resolver.</param>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        public GrainTypeSharedContextResolver(\n            IEnumerable<IConfigureGrainTypeComponents> configurators,\n            GrainPropertiesResolver grainPropertiesResolver,\n            IServiceProvider serviceProvider)\n        {\n            _configurators = configurators.ToArray();\n            _grainPropertiesResolver = grainPropertiesResolver;\n            _serviceProvider = serviceProvider;\n            _createFunc = Create;\n        }\n\n        /// <summary>\n        /// Returns shared grain components for the provided grain type.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <returns>The shared context for all grains of the provided type.</returns>\n        public GrainTypeSharedContext GetComponents(GrainType grainType) => _components.GetOrAdd(grainType, _createFunc);\n\n        private GrainTypeSharedContext Create(GrainType grainType)\n        {\n            var result = ActivatorUtilities.CreateInstance<GrainTypeSharedContext>(_serviceProvider, grainType);\n            var properties = _grainPropertiesResolver.GetGrainProperties(grainType);\n            foreach (var configurator in _configurators)\n            {\n                configurator.Configure(grainType, properties, result);\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Configures shared components which are common for all instances of a given grain type.\n    /// </summary>\n    public interface IConfigureGrainTypeComponents\n    {\n        /// <summary>\n        /// Configures shared components which are common for all instances of a given grain type.\n        /// </summary>\n        /// <param name=\"grainType\">The grain type.</param>\n        /// <param name=\"properties\">The grain properties.</param>\n        /// <param name=\"shared\">The shared context for all grains of the specified type.</param>\n        void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared);\n    }\n\n    internal class ReentrantSharedComponentsConfigurator : IConfigureGrainTypeComponents\n    {\n        public void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared)\n        {\n            if (properties.Properties.TryGetValue(WellKnownGrainTypeProperties.Reentrant, out var value) && bool.Parse(value))\n            {\n                var component = shared.GetComponent<GrainCanInterleave>();\n                if (component is null)\n                {\n                    component = new GrainCanInterleave();\n                    shared.SetComponent<GrainCanInterleave>(component);\n                }\n\n                component.MayInterleavePredicates.Add(ReentrantPredicate.Instance);\n            }\n        }\n    }\n\n    internal class MayInterleaveConfiguratorProvider : IConfigureGrainContextProvider\n    {\n        private readonly GrainClassMap _grainClassMap;\n\n        public MayInterleaveConfiguratorProvider(GrainClassMap grainClassMap)\n        {\n            _grainClassMap = grainClassMap;\n        }\n\n        public bool TryGetConfigurator(GrainType grainType, GrainProperties properties, out IConfigureGrainContext configurator)\n        {\n            if (properties.Properties.TryGetValue(WellKnownGrainTypeProperties.MayInterleavePredicate, out _)\n                && _grainClassMap.TryGetGrainClass(grainType, out var grainClass))\n            {\n                var predicate = GetMayInterleavePredicate(grainClass);\n                configurator = new MayInterleaveConfigurator(predicate);\n                return true;\n            }\n\n            configurator = null;\n            return false;\n        }\n\n        /// <summary>\n        /// Returns interleave predicate depending on whether class is marked with <see cref=\"MayInterleaveAttribute\"/> or not.\n        /// </summary>\n        /// <param name=\"grainType\">Grain class.</param>\n        private static IMayInterleavePredicate GetMayInterleavePredicate(Type grainType)\n        {\n            var attribute = grainType.GetCustomAttribute<MayInterleaveAttribute>();\n            if (attribute is null)\n            {\n                return null;\n            }\n\n            // here\n            var callbackMethodName = attribute.CallbackMethodName;\n            var method = grainType.GetMethod(callbackMethodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);\n            if (method == null)\n            {\n                throw new InvalidOperationException(\n                    $\"Class {grainType.FullName} doesn't declare public method \" +\n                    $\"with name {callbackMethodName} specified in MayInterleave attribute\");\n            }\n\n            if (method.ReturnType != typeof(bool) ||\n                method.GetParameters().Length != 1 ||\n                method.GetParameters()[0].ParameterType != typeof(IInvokable))\n            {\n                throw new InvalidOperationException(\n                    $\"Wrong signature of callback method {callbackMethodName} \" +\n                    $\"specified in MayInterleave attribute for grain class {grainType.FullName}. \\n\" +\n                    $\"Expected: public bool {callbackMethodName}(IInvokable req)\");\n            }\n\n            if (method.IsStatic)\n            {\n                return new MayInterleaveStaticPredicate(method.CreateDelegate<Func<IInvokable, bool>>());\n            }\n\n            var predicateType = typeof(MayInterleaveInstancedPredicate<>).MakeGenericType(grainType);\n            return (IMayInterleavePredicate)Activator.CreateInstance(predicateType, method);\n        }\n    }\n\n    internal interface IMayInterleavePredicate\n    {\n        bool Invoke(object instance, IInvokable bodyObject);\n    }\n\n    internal class ReentrantPredicate : IMayInterleavePredicate\n    {\n        private ReentrantPredicate()\n        {\n        }\n\n        public static ReentrantPredicate Instance { get; } = new();\n\n        public bool Invoke(object _, IInvokable bodyObject) => true;\n    }\n\n    internal class MayInterleaveStaticPredicate : IMayInterleavePredicate\n    {\n        private readonly Func<IInvokable, bool> _mayInterleavePredicate;\n\n        public MayInterleaveStaticPredicate(Func<IInvokable, bool> mayInterleavePredicate)\n        {\n            _mayInterleavePredicate = mayInterleavePredicate;\n        }\n\n        public bool Invoke(object _, IInvokable bodyObject) => _mayInterleavePredicate(bodyObject);\n    }\n\n    internal class MayInterleaveInstancedPredicate<T> : IMayInterleavePredicate where T : class\n    {\n        private readonly Func<T, IInvokable, bool> _mayInterleavePredicate;\n\n        public MayInterleaveInstancedPredicate(MethodInfo mayInterleavePredicateInfo)\n        {\n            _mayInterleavePredicate = mayInterleavePredicateInfo.CreateDelegate<Func<T, IInvokable, bool>>();\n        }\n\n        public bool Invoke(object instance, IInvokable bodyObject) => _mayInterleavePredicate(instance as T, bodyObject);\n    }\n\n    internal class MayInterleaveConfigurator : IConfigureGrainContext\n    {\n        private readonly IMayInterleavePredicate _mayInterleavePredicate;\n\n        public MayInterleaveConfigurator(IMayInterleavePredicate mayInterleavePredicate)\n        {\n            _mayInterleavePredicate = mayInterleavePredicate;\n        }\n\n        public void Configure(IGrainContext context)\n        {\n            var component = context.GetComponent<GrainCanInterleave>();\n            if (component is null)\n            {\n                component = new GrainCanInterleave();\n                context.SetComponent<GrainCanInterleave>(component);\n            }\n\n            component.MayInterleavePredicates.Add(_mayInterleavePredicate);\n        }\n    }\n\n    internal class GrainCanInterleave\n    {\n        public List<IMayInterleavePredicate> MayInterleavePredicates { get; } = new List<IMayInterleavePredicate>();\n        public bool MayInterleave(object instance, Message message)\n        {\n            foreach (var predicate in this.MayInterleavePredicates)\n            {\n                if (predicate.Invoke(instance, message.BodyObject as IInvokable)) return true;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Cancellation/CancellationSourcesExtension.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing System.Collections.Concurrent;\nusing System.Threading;\nusing System.Diagnostics;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Contains list of cancellation token source corresponding to the tokens\n    /// passed to the related grain activation.\n    /// </summary>\n    internal partial class CancellationSourcesExtension : ICancellationSourcesExtension, IDisposable\n    {\n        private readonly ConcurrentDictionary<Guid, Entry> _cancellationTokens = new ConcurrentDictionary<Guid, Entry>();\n        private readonly ILogger _logger;\n        private readonly IGrainCancellationTokenRuntime _cancellationTokenRuntime;\n        private readonly Timer _cleanupTimer;\n        private readonly Func<Guid, Entry> _createToken;\n        private static readonly TimeSpan _cleanupFrequency = TimeSpan.FromMinutes(7);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CancellationSourcesExtension\"/> class.\n        /// </summary>\n        /// <param name=\"loggerFactory\">The logger factory.</param>\n        /// <param name=\"cancellationRuntime\">The cancellation runtime.</param>\n        public CancellationSourcesExtension(ILoggerFactory loggerFactory, IGrainCancellationTokenRuntime cancellationRuntime)\n        {\n            _logger = loggerFactory.CreateLogger<CancellationSourcesExtension>();\n            _cancellationTokenRuntime = cancellationRuntime;\n            _cleanupTimer = new Timer(obj => ((CancellationSourcesExtension)obj).ExpireTokens(), this, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));\n            _createToken = id => new Entry(new GrainCancellationToken(id, false, _cancellationTokenRuntime));\n        }\n\n        /// <inheritdoc />\n        public Task CancelRemoteToken(Guid tokenId)\n        {\n            if (!_cancellationTokens.TryGetValue(tokenId, out var entry))\n            {\n                LogCancellationFailed(tokenId);\n\n                // Record the cancellation anyway, in case the call which would have registered the cancellation is still pending.\n                this.RecordCancellationToken(tokenId, isCancellationRequested: true);\n                return Task.CompletedTask;\n            }\n\n            entry.Touch();\n            var token = entry.Token;\n            return token.Cancel();\n        }\n\n        /// <summary>\n        /// Adds <see cref=\"CancellationToken\"/> to the grain extension so that it can be canceled through remote call to the CancellationSourcesExtension.\n        /// </summary>\n        /// <param name=\"target\"></param>\n        /// <param name=\"request\"></param>\n        internal static void RegisterCancellationTokens(\n            IGrainContext target,\n            IInvokable request)\n        {\n            var argumentCount = request.GetArgumentCount();\n            for (var i = 0; i < argumentCount; i++)\n            {\n                var arg = request.GetArgument(i);\n                if (arg is not GrainCancellationToken grainToken)\n                {\n                    continue;\n                }\n\n                var cancellationExtension = (CancellationSourcesExtension)target.GetGrainExtension<ICancellationSourcesExtension>();\n\n                // Replacing the half baked GrainCancellationToken that came from the wire with locally fully created one.\n                request.SetArgument(i, cancellationExtension.RecordCancellationToken(grainToken.Id, grainToken.IsCancellationRequested));\n            }\n        }\n\n        private GrainCancellationToken RecordCancellationToken(Guid tokenId, bool isCancellationRequested)\n        {\n            if (_cancellationTokens.TryGetValue(tokenId, out var entry))\n            {\n                entry.Touch();\n                return entry.Token;\n            }\n\n            entry = _cancellationTokens.GetOrAdd(tokenId, _createToken);\n            if (isCancellationRequested)\n            {\n                entry.Token.Cancel();\n            }\n\n            return entry.Token;\n        }\n\n        private void ExpireTokens()\n        {\n            var now = Stopwatch.GetTimestamp();\n            foreach (var token in _cancellationTokens)\n            {\n                if (token.Value.IsExpired(_cleanupFrequency, now))\n                {\n                    _cancellationTokens.TryRemove(token.Key, out _);\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            _cleanupTimer.Dispose();\n        }\n\n        private class Entry\n        {\n            private long _createdTime;\n\n            public Entry(GrainCancellationToken token)\n            {\n                Token = token;\n                _createdTime = Stopwatch.GetTimestamp();\n            }\n\n            public void Touch() => _createdTime = Stopwatch.GetTimestamp();\n\n            public GrainCancellationToken Token { get; }\n\n            public bool IsExpired(TimeSpan expiry, long nowTimestamp)\n            {\n                var untouchedTime = TimeSpan.FromSeconds((nowTimestamp - _createdTime) / (double)Stopwatch.Frequency);\n\n                return untouchedTime >= expiry;\n            }\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CancellationTokenCancelFailed,\n            Level = LogLevel.Warning,\n            Message = \"Received a cancel call for token with id '{TokenId}', but the token was not found.\"\n        )]\n        private partial void LogCancellationFailed(Guid tokenId);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Cancellation/GrainCallCancellationManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Remote interface for cancelling grain calls.\n/// </summary>\ninternal interface IGrainCallCancellationManagerSystemTarget : ISystemTarget\n{\n    /// <summary>\n    /// Cancels a collection of grain calls.\n    /// </summary>\n    ValueTask CancelCallsAsync([Immutable] List<GrainCallCancellationRequest> cancellationRequests);\n}\n\n[GenerateSerializer, Immutable]\ninternal struct GrainCallCancellationRequest(GrainId targetGrainId, GrainId sourceGrainId, CorrelationId messageId)\n{\n    [Id(0)]\n    public GrainId TargetGrainId { get; set; } = targetGrainId;\n\n    [Id(1)]\n    public GrainId SourceGrainId { get; set; } = sourceGrainId;\n\n    [Id(2)]\n    public CorrelationId MessageId { get; set; } = messageId;\n}\n\n/// <summary>\n/// Cancels grain calls issued to remote hosts and handles cancellation requests from other hosts.\n/// </summary>\ninternal partial class GrainCallCancellationManager : SystemTarget, IGrainCallCancellationManagerSystemTarget, IGrainCallCancellationManager, ILifecycleParticipant<ISiloLifecycle>\n{\n    private const int MaxBatchSize = 1_000;\n    private readonly ConcurrentDictionary<SiloAddress, (Task PumpTask, Channel<GrainCallCancellationRequest> WorkItemChannel, CancellationTokenSource Cts)> _workers = new();\n    private readonly CancellationTokenSource _shuttingDownCts = new();\n    private readonly IServiceProvider _serviceProvider;\n    private readonly ILogger<GrainCallCancellationManager> _logger;\n    private readonly Catalog _catalog;\n    private readonly ActivationDirectory _activationDirectory;\n    private readonly IClusterMembershipService _clusterMembershipService;\n#if NET9_0_OR_GREATER\n    private readonly Lock _lock = new();\n#else\n    private readonly object _lock = new();\n#endif\n    private readonly Task? _membershipUpdatesTask;\n    private IInternalGrainFactory? _grainFactory;\n\n    public GrainCallCancellationManager(\n        ILocalSiloDetails localSiloDetails,\n        ILoggerFactory loggerFactory,\n        IServiceProvider serviceProvider,\n        Catalog catalog,\n        ActivationDirectory activationDirectory,\n        IClusterMembershipService clusterMembershipService,\n        SystemTargetShared shared) : base(Constants.CancellationManagerType, shared)\n    {\n        _serviceProvider = serviceProvider;\n        _logger = loggerFactory.CreateLogger<GrainCallCancellationManager>();\n        _catalog = catalog;\n        _activationDirectory = activationDirectory;\n        _clusterMembershipService = clusterMembershipService;\n\n        using (new ExecutionContextSuppressor())\n        {\n            _membershipUpdatesTask = Task.Factory.StartNew(\n                state => ((GrainCallCancellationManager)state!).ProcessMembershipUpdates(),\n                this,\n                CancellationToken.None,\n                TaskCreationOptions.None,\n                WorkItemGroup.TaskScheduler).Unwrap();\n            _membershipUpdatesTask.Ignore();\n        }\n\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    private IInternalGrainFactory GrainFactory => _grainFactory ??= _serviceProvider.GetRequiredService<IInternalGrainFactory>();\n\n    public ValueTask CancelCallsAsync(List<GrainCallCancellationRequest> cancellationRequests)\n    {\n        foreach (var request in cancellationRequests)\n        {\n            // Try to directly call the cancellation method locally\n            if (_activationDirectory.FindTarget(request.TargetGrainId) is IGrainCallCancellationExtension extension)\n            {\n                extension.CancelRequestAsync(request.SourceGrainId, request.MessageId).Ignore();\n            }\n            else\n            {\n                // Fall back to a regular grain call.\n                GrainFactory.GetGrain<IGrainCallCancellationExtension>(request.TargetGrainId).CancelRequestAsync(request.SourceGrainId, request.MessageId).Ignore();\n            }\n        }\n\n        return ValueTask.CompletedTask;\n    }\n\n    public void SignalCancellation(SiloAddress? targetSilo, GrainId targetGrainId, GrainId sourceGrainId, CorrelationId messageId)\n    {\n        if (targetSilo is not null\n            && GetOrCreateWorker(targetSilo).Writer.TryWrite(new GrainCallCancellationRequest(targetGrainId, sourceGrainId, messageId)))\n        {\n            return;\n        }\n\n        var request = GrainFactory.GetGrain<IGrainCallCancellationExtension>(targetGrainId).CancelRequestAsync(sourceGrainId, messageId);\n        request.Ignore();\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        await Task.Yield();\n\n        try\n        {\n            LogDebugMonitoringClusterMembershipUpdates(_logger);\n\n            var previousSnapshot = _clusterMembershipService.CurrentSnapshot;\n            await foreach (var snapshot in _clusterMembershipService.MembershipUpdates.WithCancellation(_shuttingDownCts.Token))\n            {\n                try\n                {\n                    var diff = snapshot.CreateUpdate(previousSnapshot);\n                    previousSnapshot = snapshot;\n                    foreach (var change in diff.Changes)\n                    {\n                        if (change.Status is SiloStatus.Dead or SiloStatus.None\n                            && _workers.TryGetValue(change.SiloAddress, out var worker))\n                        {\n                            worker.WorkItemChannel.Writer.TryComplete();\n                            try\n                            {\n                                worker.Cts.Cancel(throwOnFirstException: false);\n                            }\n                            catch\n                            {\n                            }\n                        }\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorProcessingClusterMembershipUpdates(_logger, exception);\n                }\n            }\n        }\n        finally\n        {\n            LogDebugNoLongerMonitoringClusterMembershipUpdates(_logger);\n        }\n    }\n\n    private async Task PumpCancellationQueue(SiloAddress targetSilo, Channel<GrainCallCancellationRequest> workItems, CancellationToken cancellationToken)\n    {\n        try\n        {\n            var remote = GrainFactory.GetSystemTarget<IGrainCallCancellationManagerSystemTarget>(Constants.CancellationManagerType, targetSilo);\n            await Task.Yield();\n\n            LogDebugStartingCancellationWorker(_logger, targetSilo);\n\n            var batch = new List<GrainCallCancellationRequest>();\n            var reader = workItems.Reader;\n            while (await reader.WaitToReadAsync(cancellationToken))\n            {\n                try\n                {\n                    // Collect a batch of work items.\n                    while (batch.Count < MaxBatchSize && reader.TryRead(out var workItem))\n                    {\n                        batch.Add(workItem);\n                    }\n\n                    // Attempt to cancel the batch.\n                    await remote.CancelCallsAsync(batch).AsTask().WaitAsync(cancellationToken);\n\n                    LogDebugCancelledRequests(_logger, batch.Count, targetSilo);\n\n                    batch.Clear();\n                }\n                catch (Exception exception)\n                {\n                    if (cancellationToken.IsCancellationRequested)\n                    {\n                        break;\n                    }\n\n                    LogErrorCancellingRequests(_logger, exception, batch.Count, targetSilo);\n                    await Task.Delay(5_000, cancellationToken);\n                }\n            }\n        }\n        catch\n        {\n            if (!cancellationToken.IsCancellationRequested)\n            {\n                throw;\n            }\n        }\n        finally\n        {\n            // Remove ourselves and clean up.\n            RemoveWorker(targetSilo);\n            LogDebugExitingCancellationWorker(_logger, targetSilo);\n        }\n    }\n\n    private (ChannelWriter<GrainCallCancellationRequest> Writer, CancellationTokenSource Cts) GetOrCreateWorker(SiloAddress targetSilo)\n    {\n        if (!_workers.TryGetValue(targetSilo, out var worker))\n        {\n            lock (_lock)\n            {\n                if (!_workers.TryGetValue(targetSilo, out worker))\n                {\n                    using var _ = new ExecutionContextSuppressor();\n                    var cts = CancellationTokenSource.CreateLinkedTokenSource(_shuttingDownCts.Token);\n                    var channel = Channel.CreateUnbounded<GrainCallCancellationRequest>();\n                    var pumpTask = Task.Factory.StartNew(\n                        () => PumpCancellationQueue(targetSilo, channel, cts.Token),\n                        CancellationToken.None,\n                        TaskCreationOptions.None,\n                        WorkItemGroup.TaskScheduler).Unwrap();\n                    pumpTask.Ignore();\n\n                    worker = (pumpTask, channel, cts);\n                    var didAdd = _workers.TryAdd(targetSilo, worker);\n                    Debug.Assert(didAdd);\n                }\n            }\n        }\n\n        return (worker.WorkItemChannel.Writer, worker.Cts);\n    }\n\n    private void RemoveWorker(SiloAddress targetSilo)\n    {\n        if (_workers.TryRemove(targetSilo, out var entry))\n        {\n            LogDebugTargetSiloNoLongerActive(_logger, targetSilo);\n            entry.Cts.Dispose();\n        }\n    }\n\n    private Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n    private async Task StopAsync(CancellationToken cancellationToken)\n    {\n        var tasks = new List<Task>();\n        if (_membershipUpdatesTask is { } task)\n        {\n            tasks.Add(task);\n        }\n\n        foreach (var (_, worker) in _workers)\n        {\n            worker.WorkItemChannel.Writer.TryComplete();\n            try\n            {\n                worker.Cts.Cancel(throwOnFirstException: false);\n            }\n            catch\n            {\n            }\n            tasks.Add(worker.PumpTask);\n        }\n\n        try\n        {\n            _shuttingDownCts.Cancel(throwOnFirstException: false);\n        }\n        catch (Exception exception)\n        {\n            LogWarningErrorSignalingShutdown(_logger, exception);\n        }\n\n        await Task.WhenAll(tasks).WaitAsync(cancellationToken).SuppressThrowing();\n    }\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        _ = GrainFactory;\n        lifecycle.Subscribe(\n            nameof(GrainCallCancellationManager),\n            ServiceLifecycleStage.RuntimeGrainServices,\n                ct => this.RunOrQueueTask(() => StartAsync(ct)),\n                ct => this.RunOrQueueTask(() => StopAsync(ct)));\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Monitoring cluster membership updates\"\n    )]\n    private static partial void LogDebugMonitoringClusterMembershipUpdates(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Starting cancellation worker for target silo {SiloAddress}\"\n    )]\n    private static partial void LogDebugStartingCancellationWorker(ILogger logger, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Cancelled {Count} requests to target silo {SiloAddress}\"\n    )]\n    private static partial void LogDebugCancelledRequests(ILogger logger, int count, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error while cancelling {Count} requests to {SiloAddress}\"\n    )]\n    private static partial void LogErrorCancellingRequests(ILogger logger, Exception exception, int count, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Exiting cancellation worker for target silo {SiloAddress}\"\n    )]\n    private static partial void LogDebugExitingCancellationWorker(ILogger logger, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Target silo '{SiloAddress}' is no longer active, so this cancellation activation worker is terminating\"\n    )]\n    private static partial void LogDebugTargetSiloNoLongerActive(ILogger logger, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error signaling shutdown.\"\n    )]\n    private static partial void LogWarningErrorSignalingShutdown(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"No longer monitoring cluster membership updates\"\n    )]\n    private static partial void LogDebugNoLongerMonitoringClusterMembershipUpdates(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing cluster membership updates\"\n    )]\n    private static partial void LogErrorProcessingClusterMembershipUpdates(ILogger logger, Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationCollector.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Internal;\nusing Orleans.Statistics;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies activations that have been idle long enough to be deactivated.\n    /// </summary>\n    internal partial class ActivationCollector : IActivationWorkingSetObserver, ILifecycleParticipant<ISiloLifecycle>, IDisposable\n    {\n        private readonly TimeSpan shortestAgeLimit;\n        private readonly ConcurrentDictionary<DateTime, Bucket> buckets = new();\n        private readonly CancellationTokenSource _shutdownCts = new();\n        private DateTime nextTicket;\n        private static readonly List<ICollectibleGrainContext> nothing = new(0);\n        private readonly ILogger logger;\n        private int collectionNumber;\n\n        // internal for testing\n        internal int _activationCount;\n\n        private readonly PeriodicTimer _collectionTimer;\n        private Task _collectionLoopTask;\n\n        private readonly IEnvironmentStatisticsProvider _environmentStatisticsProvider;\n        private readonly GrainCollectionOptions _grainCollectionOptions;\n        private readonly PeriodicTimer _memBasedDeactivationTimer;\n        private Task _memBasedDeactivationLoopTask;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ActivationCollector\"/> class.\n        /// </summary>\n        /// <param name=\"timeProvider\">The time provider.</param>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"logger\">The logger.</param>\n        public ActivationCollector(\n            TimeProvider timeProvider,\n            IOptions<GrainCollectionOptions> options,\n            ILogger<ActivationCollector> logger,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n        {\n            _grainCollectionOptions = options.Value;\n\n            shortestAgeLimit = new(_grainCollectionOptions.ClassSpecificCollectionAge.Values.Aggregate(_grainCollectionOptions.CollectionAge.Ticks, (a, v) => Math.Min(a, v.Ticks)));\n            nextTicket = MakeTicketFromDateTime(timeProvider.GetUtcNow().UtcDateTime);\n            this.logger = logger;\n            _collectionTimer = new PeriodicTimer(_grainCollectionOptions.CollectionQuantum);\n\n            _environmentStatisticsProvider = environmentStatisticsProvider;\n            if (_grainCollectionOptions.EnableActivationSheddingOnMemoryPressure)\n            {\n                _memBasedDeactivationTimer = new PeriodicTimer(_grainCollectionOptions.MemoryUsagePollingPeriod);\n            }\n        }\n\n        // Return the number of activations that were used (touched) in the last recencyPeriod.\n        public int GetNumRecentlyUsed(TimeSpan recencyPeriod)\n        {\n            var now = DateTime.UtcNow;\n            int sum = 0;\n            foreach (var bucket in buckets)\n            {\n                // Ticket is the date time when this bucket should be collected (last touched time plus age limit)\n                // For now we take the shortest age limit as an approximation of the per-type age limit.\n                DateTime ticket = bucket.Key;\n                var timeTillCollection = ticket - now;\n                var timeSinceLastUsed = shortestAgeLimit - timeTillCollection;\n                if (timeSinceLastUsed <= recencyPeriod)\n                {\n                    sum += bucket.Value.Items.Count;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Collects all eligible grain activations which have been idle for at least <paramref name=\"ageLimit\"/>.\n        /// </summary>\n        /// <param name=\"ageLimit\">The age limit.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        public Task CollectActivations(TimeSpan ageLimit, CancellationToken cancellationToken) => CollectActivationsImpl(false, ageLimit, cancellationToken);\n\n        /// <summary>\n        /// Schedules the provided grain context for collection if it becomes idle for the specified duration.\n        /// </summary>\n        /// <param name=\"item\">\n        /// The grain context.\n        /// </param>\n        /// <param name=\"timeout\">\n        /// The current idle collection time for the grain.\n        /// </param>\n        public void ScheduleCollection(ICollectibleGrainContext item, TimeSpan timeout, DateTime now)\n        {\n            lock (item)\n            {\n                if (item.IsExemptFromCollection)\n                {\n                    return;\n                }\n\n                DateTime ticket = MakeTicketFromTimeSpan(timeout, now);\n\n                if (default != item.CollectionTicket)\n                {\n                    throw new InvalidOperationException(\"Call CancelCollection before calling ScheduleCollection.\");\n                }\n\n                Add(item, ticket);\n            }\n        }\n\n        /// <summary>\n        /// Tries the cancel idle activation collection.\n        /// </summary>\n        /// <param name=\"item\">The grain context.</param>\n        /// <returns><see langword=\"true\"/> if collection was canceled, <see langword=\"false\"/> otherwise.</returns>\n        public bool TryCancelCollection(ICollectibleGrainContext item)\n        {\n            if (item is null) return false;\n            if (item.IsExemptFromCollection) return false;\n\n            lock (item)\n            {\n                DateTime ticket = item.CollectionTicket;\n                if (default == ticket) return false;\n                if (IsExpired(ticket)) return false;\n\n                // first, we attempt to remove the ticket.\n                Bucket bucket;\n                if (!buckets.TryGetValue(ticket, out bucket) || !bucket.TryRemove(item)) return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Tries the reschedule collection.\n        /// </summary>\n        /// <param name=\"item\">The grain context.</param>\n        /// <returns><see langword=\"true\"/> if collection was canceled, <see langword=\"false\"/> otherwise.</returns>\n        public bool TryRescheduleCollection(ICollectibleGrainContext item)\n        {\n            if (item.IsExemptFromCollection) return false;\n\n            lock (item)\n            {\n                if (TryRescheduleCollection_Impl(item, item.CollectionAgeLimit)) return true;\n\n                item.CollectionTicket = default;\n                return false;\n            }\n        }\n\n        private bool TryRescheduleCollection_Impl(ICollectibleGrainContext item, TimeSpan timeout)\n        {\n            // note: we expect the activation lock to be held.\n            if (default == item.CollectionTicket) return false;\n            ThrowIfTicketIsInvalid(item.CollectionTicket);\n            if (IsExpired(item.CollectionTicket)) return false;\n\n            DateTime oldTicket = item.CollectionTicket;\n            DateTime newTicket = MakeTicketFromTimeSpan(timeout, DateTime.UtcNow);\n            // if the ticket value doesn't change, then the source and destination bucket are the same and there's nothing to do.\n            if (newTicket.Equals(oldTicket)) return true;\n\n            Bucket bucket;\n            if (!buckets.TryGetValue(oldTicket, out bucket) || !bucket.TryRemove(item))\n            {\n                // fail: item is not associated with currentKey.\n                return false;\n            }\n\n            // it shouldn't be possible for Add to throw an exception here, as only one concurrent competitor should be able to reach to this point in the method.\n            Add(item, newTicket);\n            return true;\n        }\n\n        private bool DequeueQuantum(out List<ICollectibleGrainContext> items, DateTime now)\n        {\n            DateTime key;\n            lock (buckets)\n            {\n                if (nextTicket > now)\n                {\n                    items = null;\n                    return false;\n                }\n\n                key = nextTicket;\n                nextTicket += _grainCollectionOptions.CollectionQuantum;\n            }\n\n            Bucket bucket;\n            if (!buckets.TryRemove(key, out bucket))\n            {\n                items = nothing;\n                return true;\n            }\n\n            items = bucket.CancelAll();\n            return true;\n        }\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            var now = DateTime.UtcNow;\n            var all = buckets.ToList();\n            var bucketsText = Utils.EnumerableToString(all.OrderBy(bucket => bucket.Key), bucket => $\"{Utils.TimeSpanToString(bucket.Key - now)}->{bucket.Value.Items.Count} items\");\n            return $\"<#Activations={all.Sum(b => b.Value.Items.Count)}, #Buckets={all.Count}, buckets={bucketsText}>\";\n        }\n\n        /// <summary>\n        /// Scans for activations that are due for collection.\n        /// </summary>\n        /// <returns>A list of activations that are due for collection.</returns>\n        public List<ICollectibleGrainContext> ScanStale()\n        {\n            var now = DateTime.UtcNow;\n            List<ICollectibleGrainContext> condemned = null;\n            while (DequeueQuantum(out var activations, now))\n            {\n                // At this point, all tickets associated with activations are cancelled and any attempts to reschedule will fail silently.\n                // If the activation is to be reactivated, it's our job to clear the activation's copy of the ticket.\n                foreach (var activation in activations)\n                {\n                    lock (activation)\n                    {\n                        activation.CollectionTicket = default;\n                        if (!activation.IsValid)\n                        {\n                            // This is not an error scenario because the activation may have become invalid between the time\n                            // we captured a snapshot in 'DequeueQuantum' and now. We are not be able to observe such changes.\n                            // Do nothing: don't collect, don't reschedule.\n                        }\n                        else if (activation.KeepAliveUntil > now)\n                        {\n                            var keepAliveDuration = activation.KeepAliveUntil - now;\n                            var timeout = TimeSpan.FromTicks(Math.Max(keepAliveDuration.Ticks, activation.CollectionAgeLimit.Ticks));\n                            ScheduleCollection(activation, timeout, now);\n                        }\n                        else if (!activation.IsInactive || !activation.IsStale())\n                        {\n                            ScheduleCollection(activation, activation.CollectionAgeLimit, now);\n                        }\n                        else\n                        {\n                            // Atomically set Deactivating state, to disallow any new requests or new timer ticks to be dispatched on this activation.\n                            condemned ??= [];\n                            condemned.Add(activation);\n                        }\n                    }\n                }\n            }\n\n            return condemned ?? nothing;\n        }\n\n        /// <summary>\n        /// Scans for activations that have been idle for the specified age limit.\n        /// </summary>\n        /// <param name=\"ageLimit\">The age limit.</param>\n        /// <returns>The grain activations which have been idle for at least the specified age limit.</returns>\n        public List<ICollectibleGrainContext> ScanAll(TimeSpan ageLimit)\n        {\n            List<ICollectibleGrainContext> condemned = null;\n            var now = DateTime.UtcNow;\n            foreach (var kv in buckets)\n            {\n                var bucket = kv.Value;\n                foreach (var kvp in bucket.Items)\n                {\n                    var activation = kvp.Value;\n                    lock (activation)\n                    {\n                        if (!activation.IsValid)\n                        {\n                            // Do nothing: don't collect, don't reschedule.\n                        }\n                        else if (activation.KeepAliveUntil > now)\n                        {\n                            // do nothing\n                        }\n                        else if (!activation.IsInactive)\n                        {\n                            // do nothing\n                        }\n                        else\n                        {\n                            if (activation.GetIdleness() >= ageLimit)\n                            {\n                                if (bucket.TryRemove(activation))\n                                {\n                                    condemned ??= [];\n                                    condemned.Add(activation);\n                                }\n\n                                // someone else has already deactivated the activation, so there's nothing to do.\n                            }\n                            else\n                            {\n                                // activation is not idle long enough for collection. do nothing.\n                            }\n                        }\n                    }\n                }\n            }\n\n            return condemned ?? nothing;\n        }\n\n        // Internal for testing. It's expected that when this returns true, activation shedding will occur.\n        internal bool IsMemoryOverloaded(out int surplusActivationCount)\n        {\n            var stats = _environmentStatisticsProvider.GetEnvironmentStatistics();\n            var limit = _grainCollectionOptions.MemoryUsageLimitPercentage / 100f;\n\n            var usage = stats.NormalizedMemoryUsage;\n            if (usage <= limit)\n            {\n                // High memory pressure is not detected, so we do not need to deactivate any activations.\n                surplusActivationCount = 0;\n                return false;\n            }\n\n            // Calculate the surplus activations based the memory usage target.\n            var activationCount = _activationCount;\n            var target = _grainCollectionOptions.MemoryUsageTargetPercentage / 100f;\n            surplusActivationCount = (int)Math.Max(0, activationCount - Math.Floor(activationCount * target / usage));\n            if (surplusActivationCount <= 0)\n            {\n                surplusActivationCount = 0;\n                return false;\n            }\n\n            var surplusActivationPercentage = 100 * (1 - target / usage);\n            LogCurrentHighMemoryPressureStats(stats.MemoryUsagePercentage, _grainCollectionOptions.MemoryUsageLimitPercentage, deactivationTarget: surplusActivationCount, activationCount, surplusActivationPercentage);\n            return true;\n        }\n\n        /// <summary>\n        /// Deactivates <param name=\"count\" /> activations in due time order\n        /// <remarks>internal for testing</remarks>\n        /// </summary>\n        internal async Task DeactivateInDueTimeOrder(int count, CancellationToken cancellationToken)\n        {\n            var watch = ValueStopwatch.StartNew();\n            var number = Interlocked.Increment(ref collectionNumber);\n            long memBefore = GC.GetTotalMemory(false) / (1024 * 1024); // MB\n            LogBeforeCollection(number, memBefore, _activationCount, this);\n\n            var candidates = new List<ICollectibleGrainContext>(count);\n\n            // snapshot to avoid concurrency collection modification issues\n            var bucketSnapshot = buckets.ToArray();\n            foreach (var bucket in bucketSnapshot.OrderBy(b => b.Key))\n            {\n                foreach (var item in bucket.Value.Items)\n                {\n                    if (candidates.Count >= count)\n                    {\n                        break;\n                    }\n\n                    var activation = item.Value;\n\n                    candidates.Add(activation);\n                }\n\n                if (candidates.Count >= count)\n                {\n                    break;\n                }\n            }\n\n            CatalogInstruments.ActivationCollections.Add(1);\n            if (candidates.Count > 0) \n            {\n                LogCollectActivations(new(candidates));\n\n                var reason = new DeactivationReason(\n                    DeactivationReasonCode.HighMemoryPressure,\n                    $\"Process memory utilization exceeded the configured limit of '{_grainCollectionOptions.MemoryUsageLimitPercentage}'. Detected memory usage is {memBefore} MB.\");\n\n                await DeactivateActivationsFromCollector(candidates, cancellationToken, reason);\n            }\n\n            long memAfter = GC.GetTotalMemory(false) / (1024 * 1024);\n            watch.Stop();\n            LogAfterCollection(number, memAfter, _activationCount, candidates.Count, this, watch.Elapsed);\n        }\n\n        private static DeactivationReason GetDeactivationReason()\n        {\n            var reasonText = \"This activation has become idle.\";\n            var reason = new DeactivationReason(DeactivationReasonCode.ActivationIdle, reasonText);\n            return reason;\n        }\n\n        private void ThrowIfTicketIsInvalid(DateTime ticket)\n        {\n            if (ticket.Ticks == 0) throw new ArgumentException(\"Empty ticket is not allowed in this context.\");\n            if (0 != ticket.Ticks % _grainCollectionOptions.CollectionQuantum.Ticks)\n            {\n                throw new ArgumentException(string.Format(\"invalid ticket ({0})\", ticket));\n            }\n        }\n\n        private bool IsExpired(DateTime ticket)\n        {\n            return ticket < nextTicket;\n        }\n\n        public DateTime MakeTicketFromDateTime(DateTime timestamp)\n        {\n            // Round the timestamp to the next _grainCollectionOptions.CollectionQuantum. e.g. if the _grainCollectionOptions.CollectionQuantum is 1 minute and the timestamp is 3:45:22, then the ticket will be 3:46.\n            // Note that TimeStamp.Ticks and DateTime.Ticks both return a long.\n            var ticketTicks = ((timestamp.Ticks - 1) / _grainCollectionOptions.CollectionQuantum.Ticks + 1) * _grainCollectionOptions.CollectionQuantum.Ticks;\n            if (ticketTicks > DateTime.MaxValue.Ticks)\n            {\n                return DateTime.MaxValue;\n            }\n\n            var ticket = new DateTime(ticketTicks, DateTimeKind.Utc);\n            if (ticket < nextTicket)\n            {\n                throw new ArgumentException(string.Format(\"The earliest collection that can be scheduled from now is for {0}\", new DateTime(nextTicket.Ticks - _grainCollectionOptions.CollectionQuantum.Ticks + 1, DateTimeKind.Utc)));\n            }\n\n            return ticket;\n        }\n\n        private DateTime MakeTicketFromTimeSpan(TimeSpan timeout, DateTime now)\n        {\n            if (timeout < _grainCollectionOptions.CollectionQuantum)\n            {\n                throw new ArgumentException(string.Format(\"timeout must be at least {0}, but it is {1}\", _grainCollectionOptions.CollectionQuantum, timeout), nameof(timeout));\n            }\n\n            return MakeTicketFromDateTime(now + timeout);\n        }\n\n        private void Add(ICollectibleGrainContext item, DateTime ticket)\n        {\n            // note: we expect the activation lock to be held.\n            item.CollectionTicket = ticket;\n            var bucket = buckets.GetOrAdd(ticket, _ => new Bucket());\n            bucket.Add(item);\n        }\n\n        void IActivationWorkingSetObserver.OnAdded(IActivationWorkingSetMember member)\n        {\n            if (member is ICollectibleGrainContext activation)\n            {\n                Interlocked.Increment(ref _activationCount);\n                if (activation.CollectionTicket == default)\n                {\n                    ScheduleCollection(activation, activation.CollectionAgeLimit, DateTime.UtcNow);\n                }\n                else\n                {\n                    TryRescheduleCollection(activation);\n                }\n            }\n        }\n\n        void IActivationWorkingSetObserver.OnActive(IActivationWorkingSetMember member)\n        {\n            // We do not need to do anything when a grain becomes active, since we can lazily handle it when scanning its bucket instead.\n            // This reduces the amount of unnecessary work performed.\n        }\n\n        void IActivationWorkingSetObserver.OnEvicted(IActivationWorkingSetMember member)\n        {\n            if (member is ICollectibleGrainContext activation && activation.CollectionTicket == default)\n            {\n                TryRescheduleCollection(activation);\n            }\n        }\n\n        void IActivationWorkingSetObserver.OnDeactivating(IActivationWorkingSetMember member)\n        {\n            if (member is ICollectibleGrainContext activation)\n            {\n                TryCancelCollection(activation);\n            }\n        }\n\n        void IActivationWorkingSetObserver.OnDeactivated(IActivationWorkingSetMember member)\n        {\n            Interlocked.Decrement(ref _activationCount);\n            _ = TryCancelCollection(member as ICollectibleGrainContext);\n        }\n\n        private Task Start(CancellationToken cancellationToken)\n        {\n            using var _ = new ExecutionContextSuppressor();\n            _collectionLoopTask = RunActivationCollectionLoop();\n\n            if (_grainCollectionOptions.EnableActivationSheddingOnMemoryPressure)\n            {\n                _memBasedDeactivationLoopTask = RunMemoryBasedDeactivationLoop();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        private async Task Stop(CancellationToken cancellationToken)\n        {\n            using var registration = cancellationToken.Register(() => _shutdownCts.Cancel());\n            _collectionTimer.Dispose();\n            _memBasedDeactivationTimer?.Dispose();\n\n            if (_collectionLoopTask is Task task)\n            {\n                await task.WaitAsync(cancellationToken);\n            }\n\n            if (_memBasedDeactivationLoopTask is Task deactivationLoopTask)\n            {\n                await deactivationLoopTask.WaitAsync(cancellationToken);\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(ActivationCollector),\n                ServiceLifecycleStage.RuntimeServices,\n                Start,\n                Stop);\n        }\n\n        private async Task RunActivationCollectionLoop()\n        {\n            await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n            var cancellationToken = _shutdownCts.Token;\n            while (await _collectionTimer.WaitForNextTickAsync())\n            {\n                try\n                {\n                    await this.CollectActivationsImpl(true, ageLimit: default, cancellationToken);\n                }\n                catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)\n                {\n                    // most probably shutdown\n                }\n                catch (Exception exception)\n                {\n                    LogErrorWhileCollectingActivations(exception);\n                }\n            }\n        }\n\n        private async Task RunMemoryBasedDeactivationLoop()\n        {\n            await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n            var cancellationToken = _shutdownCts.Token;\n\n            int lastGen2GcCount = 0;\n\n            try\n            {\n                while (await _memBasedDeactivationTimer.WaitForNextTickAsync(cancellationToken))\n                {\n                    try\n                    {\n                        var currentGen2GcCount = GC.CollectionCount(2);\n\n                        // note: GC.CollectionCount(2) will return 0 if no gen2 gc happened yet and we rely on this behavior:\n                        //       high memory pressure situation cannot occur until gen2 occurred at least once\n                        if (currentGen2GcCount <= lastGen2GcCount)\n                        {\n                            // No Gen2 GC since last deactivation cycle.\n                            // Wait for Gen2 GC between cycles to be sure that \n                            continue;\n                        }\n\n                        if (!IsMemoryOverloaded(out var surplusActivationCount))\n                        {\n                            continue;\n                        }\n\n                        lastGen2GcCount = currentGen2GcCount;\n                        await DeactivateInDueTimeOrder(surplusActivationCount, cancellationToken);\n                    }\n                    catch (Exception exception)\n                    {\n                        // Ignore cancellation exceptions during shutdown.\n                        if (exception is OperationCanceledException && cancellationToken.IsCancellationRequested)\n                        {\n                            break;\n                        }\n\n                        LogErrorWhileCollectingActivations(exception);\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                if (exception is OperationCanceledException && cancellationToken.IsCancellationRequested)\n                {\n                    // Ignore cancellation exceptions during shutdown.\n                }\n                else\n                {\n                    throw;\n                }\n            }\n        }\n\n        private async Task CollectActivationsImpl(bool scanStale, TimeSpan ageLimit, CancellationToken cancellationToken)\n        {\n            var watch = ValueStopwatch.StartNew();\n            var number = Interlocked.Increment(ref collectionNumber);\n            long memBefore = GC.GetTotalMemory(false) / (1024 * 1024);\n\n            LogBeforeCollection(number, memBefore, _activationCount, this);\n\n            List<ICollectibleGrainContext> list = scanStale ? ScanStale() : ScanAll(ageLimit);\n            CatalogInstruments.ActivationCollections.Add(1);\n            if (list is { Count: > 0 })\n            {\n                LogCollectActivations(new(list));\n                await DeactivateActivationsFromCollector(list, cancellationToken);\n            }\n\n            long memAfter = GC.GetTotalMemory(false) / (1024 * 1024);\n            watch.Stop();\n\n            LogAfterCollection(number, memAfter, _activationCount, list?.Count ?? 0, this, watch.Elapsed);\n        }\n\n        private async Task DeactivateActivationsFromCollector(List<ICollectibleGrainContext> list, CancellationToken cancellationToken, DeactivationReason? deactivationReason = null)\n        {\n            LogDeactivateActivationsFromCollector(list.Count);\n            CatalogInstruments.ActivationShutdownViaCollection();\n\n            deactivationReason ??= GetDeactivationReason();\n\n            var options = new ParallelOptions\n            {\n                // Avoid passing the cancellation token, since we want all of these activations to be deactivated, even if cancellation is triggered.\n                CancellationToken = CancellationToken.None,\n                MaxDegreeOfParallelism = Environment.ProcessorCount * 512\n            };\n\n            await Parallel.ForEachAsync(list, options, async (activationData, token) =>\n            {\n                // Continue deactivation when ready.\n                activationData.Deactivate(deactivationReason.Value, cancellationToken);\n                await activationData.Deactivated.ConfigureAwait(false);\n            }).WaitAsync(cancellationToken);\n        }\n\n        public void Dispose()\n        {\n            _collectionTimer.Dispose();\n            _shutdownCts.Dispose();\n            _memBasedDeactivationTimer?.Dispose();\n        }\n\n        private class Bucket\n        {\n            public ConcurrentDictionary<ICollectibleGrainContext, ICollectibleGrainContext> Items { get; } = new(ReferenceEqualsComparer.Default);\n\n            public void Add(ICollectibleGrainContext item)\n            {\n                if (!Items.TryAdd(item, item))\n                {\n                    throw new InvalidOperationException(\"item is already associated with this bucket\");\n                }\n            }\n\n            public bool TryRemove(ICollectibleGrainContext item)\n            {\n                lock (item)\n                {\n                    if (item.CollectionTicket == default)\n                    {\n                        return false;\n                    }\n\n                    item.CollectionTicket = default;\n                }\n\n                return Items.TryRemove(item, out _);\n            }\n\n            public List<ICollectibleGrainContext> CancelAll()\n            {\n                List<ICollectibleGrainContext> result = null;\n                foreach (var pair in Items)\n                {\n                    // Attempt to cancel the item. if we succeed, it wasn't already cancelled and we can return it. otherwise, we silently ignore it.\n                    var item = pair.Value;\n                    lock (item)\n                    {\n                        if (item.CollectionTicket == default)\n                        {\n                            continue;\n                        }\n\n                        item.CollectionTicket = default;\n                    }\n\n                    result ??= [];\n                    result.Add(pair.Value);\n                }\n\n                return result ?? nothing;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"High memory pressure detected ({MemoryUsagePercentage:F2}% > {MemoryUsageLimitPercentage:F2}%). Deactivating up to {DeactivationTarget:N0}/{ActivationCount:N0} ({SurplusActivationPercentage:F2}%) grains to free memory.\"\n        )]\n        private partial void LogCurrentHighMemoryPressureStats(double memoryUsagePercentage, double memoryUsageLimitPercentage, int deactivationTarget, int activationCount, double surplusActivationPercentage);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error while collecting activations.\"\n        )]\n        private partial void LogErrorWhileCollectingActivations(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Catalog_BeforeCollection,\n            Level = LogLevel.Debug,\n            Message = \"Before collection #{CollectionNumber}: memory: {MemoryBefore}MB, #activations: {ActivationCount}, collector: {CollectorStatus}\"\n        )]\n        private partial void LogBeforeCollection(int collectionNumber, long memoryBefore, int activationCount, ActivationCollector collectorStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"CollectActivations {Activations}\"\n        )]\n        private partial void LogCollectActivations(ActivationsLogValue activations);\n        private struct ActivationsLogValue(List<ICollectibleGrainContext> list)\n        {\n            public override string ToString() => list.ToStrings(d => d.GrainId.ToString() + d.ActivationId);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Catalog_AfterCollection,\n            Level = LogLevel.Debug,\n            Message =  \"After collection #{CollectionNumber} memory: {MemoryAfter}MB, #activations: {ActivationCount}, collected {CollectedCount} activations, collector: {CollectorStatus}, collection time: {CollectionTime}\"\n        )]\n        private partial void LogAfterCollection(int collectionNumber, long memoryAfter, int activationCount, int collectedCount, ActivationCollector collectorStatus, TimeSpan collectionTime);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Catalog_ShutdownActivations_1,\n            Level = LogLevel.Information,\n            Message = \"Deactivating '{Count}' idle activations.\"\n        )]\n        private partial void LogDeactivateActivationsFromCollector(int count);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationData.cs",
    "content": "#nullable enable\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Core.Internal;\nusing Orleans.Diagnostics;\nusing Orleans.GrainDirectory;\nusing Orleans.Internal;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Maintains additional per-activation state that is required for Orleans internal operations.\n/// MUST lock this object for any concurrent access\n/// MUST lock on `this` object because there are locks taken on ActivationData instances in various places in the codebase such as ActivationCollector.ScheduleCollection.\n/// Consider: compartmentalize by usage, e.g., using separate interfaces for data for catalog, etc.\n/// </summary>\n[DebuggerDisplay(\"GrainId = {GrainId}, State = {State}, Waiting = {WaitingCount}, Executing = {IsCurrentlyExecuting}\")]\ninternal sealed partial class ActivationData :\n    IGrainContext,\n    ICollectibleGrainContext,\n    IGrainExtensionBinder,\n    IActivationWorkingSetMember,\n    IGrainTimerRegistry,\n    IGrainManagementExtension,\n    IGrainCallCancellationExtension,\n    ICallChainReentrantGrainContext,\n    IAsyncDisposable,\n    IDisposable\n{\n    private const string GrainAddressMigrationContextKey = \"sys.addr\";\n    private readonly GrainTypeSharedContext _shared;\n    private readonly IServiceScope _serviceScope;\n    private readonly WorkItemGroup _workItemGroup;\n    private readonly List<(Message Message, CoarseStopwatch QueuedTime)> _waitingRequests = new();\n    private readonly Dictionary<Message, CoarseStopwatch> _runningRequests = new();\n    private readonly SingleWaiterAutoResetEvent _workSignal = new() { RunContinuationsAsynchronously = true };\n    private GrainLifecycle? _lifecycle;\n    private Queue<object>? _pendingOperations;\n    private Message? _blockingRequest;\n    private bool _isInWorkingSet = true;\n    private CoarseStopwatch _busyDuration;\n    private CoarseStopwatch _idleDuration;\n    private GrainReference? _selfReference;\n\n    // Values which are needed less frequently and do not warrant living directly on activation for object size reasons.\n    // The values in this field are typically used to represent termination state of an activation or features which are not\n    // used by all grains, such as grain timers.\n    private ActivationDataExtra? _extras;\n\n    // The task representing this activation's message loop.\n    // This field is assigned and never read and exists only for debugging purposes (eg, in memory dumps, to associate a loop task with an activation).\n#pragma warning disable IDE0052 // Remove unread private members\n    private Task? _messageLoopTask;\n#pragma warning restore IDE0052 // Remove unread private members\n\n    private Activity? _activationActivity;\n\n    /// <summary>\n    /// Constants for activity error event names used during activation lifecycle.\n    /// </summary>\n    private static class ActivityErrorEvents\n    {\n        public const string InstanceCreateFailed = \"instance-create-failed\";\n        public const string DirectoryRegisterFailed = \"directory-register-failed\";\n        public const string ActivationCancelled = \"activation-cancelled\";\n        public const string ActivationFailed = \"activation-failed\";\n        public const string ActivationError = \"activation-error\";\n        public const string OnActivateFailed = \"on-activate-failed\";\n        public const string OnDeactivateFailed = \"on-deactivate-failed\";\n        public const string RehydrateError = \"rehydrate-error\";\n        public const string DehydrateError = \"dehydrate-error\";\n    }\n\n    public ActivationData(\n        GrainAddress grainAddress,\n        Func<IGrainContext, WorkItemGroup> createWorkItemGroup,\n        IServiceProvider applicationServices,\n        GrainTypeSharedContext shared)\n    {\n        ArgumentNullException.ThrowIfNull(grainAddress);\n        ArgumentNullException.ThrowIfNull(createWorkItemGroup);\n        ArgumentNullException.ThrowIfNull(applicationServices);\n        ArgumentNullException.ThrowIfNull(shared);\n        _shared = shared;\n        Address = grainAddress;\n        _serviceScope = applicationServices.CreateScope();\n        Debug.Assert(_serviceScope != null, \"_serviceScope must not be null.\");\n        _workItemGroup = createWorkItemGroup(this);\n        Debug.Assert(_workItemGroup != null, \"_workItemGroup must not be null.\");\n    }\n\n    internal void SetActivationActivity(Activity activity)\n    {\n        _activationActivity = activity;\n    }\n\n    /// <summary>\n    /// Gets the activity context for the activation activity, if available.\n    /// This allows child activities to be properly parented during activation lifecycle operations.\n    /// </summary>\n    internal ActivityContext? GetActivationActivityContext()\n    {\n        return _activationActivity?.Context;\n    }\n\n    public void Start(IGrainActivator grainActivator)\n    {\n        Debug.Assert(Equals(ActivationTaskScheduler, TaskScheduler.Current));\n        // locking on `this` is intentional as there are other places in the codebase taking locks on ActivationData instances\n        lock (this)\n        {\n            try\n            {\n                var instance = grainActivator.CreateInstance(this);\n                SetGrainInstance(instance);\n                _activationActivity?.AddEvent(new ActivityEvent(\"instance-created\"));\n            }\n            catch (Exception exception)\n            {\n                SetActivityError(_activationActivity, exception, ActivityErrorEvents.InstanceCreateFailed);\n\n                Deactivate(new(DeactivationReasonCode.ActivationFailed, exception, \"Error constructing grain instance.\"), _activationActivity?.Context, CancellationToken.None);\n            }\n\n            _messageLoopTask = RunMessageLoop();\n        }\n    }\n\n    public ActivationTaskScheduler ActivationTaskScheduler => _workItemGroup.TaskScheduler;\n    public IGrainRuntime GrainRuntime => _shared.Runtime;\n    public object? GrainInstance { get; private set; }\n    public GrainAddress Address { get; private set; }\n    public GrainReference GrainReference => _selfReference ??= _shared.GrainReferenceActivator.CreateReference(GrainId, default);\n    public ActivationState State { get; private set; } = ActivationState.Creating;\n    public PlacementStrategy PlacementStrategy => _shared.PlacementStrategy;\n    public DateTime CollectionTicket { get; set; }\n    public IServiceProvider ActivationServices => _serviceScope.ServiceProvider;\n    public ActivationId ActivationId => Address.ActivationId;\n    public IGrainLifecycle ObservableLifecycle\n    {\n        get\n        {\n            if (_lifecycle is { } lifecycle) return lifecycle;\n            lock (this) { return _lifecycle ??= new GrainLifecycle(_shared.Logger); }\n        }\n    }\n\n    internal GrainTypeSharedContext Shared => _shared;\n\n    public GrainId GrainId => Address.GrainId;\n    public bool IsExemptFromCollection => _shared.CollectionAgeLimit == Timeout.InfiniteTimeSpan;\n    public DateTime KeepAliveUntil { get; set; } = DateTime.MinValue;\n    public bool IsValid => State is ActivationState.Valid;\n\n    // Currently, the only supported multi-activation grain is one using the StatelessWorkerPlacement strategy.\n    internal bool IsStatelessWorker => PlacementStrategy is StatelessWorkerPlacement;\n\n    /// <summary>\n    /// Returns a value indicating whether or not this placement strategy requires activations to be registered in\n    /// the grain directory.\n    /// </summary>\n    internal bool IsUsingGrainDirectory => PlacementStrategy.IsUsingGrainDirectory;\n\n    public int WaitingCount => _waitingRequests.Count;\n    public bool IsInactive => !IsCurrentlyExecuting && _waitingRequests.Count == 0;\n    public bool IsCurrentlyExecuting => _runningRequests.Count > 0;\n    public IWorkItemScheduler Scheduler => _workItemGroup;\n    public Task Deactivated => GetDeactivationCompletionSource().Task;\n\n    public SiloAddress? ForwardingAddress\n    {\n        get => _extras?.ForwardingAddress;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.ForwardingAddress = value;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Gets the previous directory registration for this grain, if known.\n    /// This is used to update the grain directory to point to the new registration during activation.\n    /// </summary>\n    public GrainAddress? PreviousRegistration\n    {\n        get => _extras?.PreviousRegistration;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.PreviousRegistration = value;\n            }\n        }\n    }\n\n    private Exception? DeactivationException => _extras?.DeactivationReason.Exception;\n\n    private DeactivationReason DeactivationReason\n    {\n        get => _extras?.DeactivationReason ?? default;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.DeactivationReason = value;\n            }\n        }\n    }\n\n    private HashSet<IGrainTimer>? Timers\n    {\n        get => _extras?.Timers;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.Timers = value;\n            }\n        }\n    }\n\n    private DateTime? DeactivationStartTime\n    {\n        get => _extras?.DeactivationStartTime;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.DeactivationStartTime = value;\n            }\n        }\n    }\n\n    private bool IsStuckDeactivating\n    {\n        get => _extras?.IsStuckDeactivating ?? false;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.IsStuckDeactivating = value;\n            }\n        }\n    }\n\n    private bool IsStuckProcessingMessage\n    {\n        get => _extras?.IsStuckProcessingMessage ?? false;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.IsStuckProcessingMessage = value;\n            }\n        }\n    }\n\n    private DehydrationContextHolder? DehydrationContext\n    {\n        get => _extras?.DehydrationContext;\n        set\n        {\n            lock (this)\n            {\n                _extras ??= new();\n                _extras.DehydrationContext = value;\n            }\n        }\n    }\n\n    public TimeSpan CollectionAgeLimit => _shared.CollectionAgeLimit;\n\n    public object? GetTarget() => GrainInstance;\n\n    object? ITargetHolder.GetComponent(Type componentType)\n    {\n        var result = GetComponent(componentType);\n        if (result is null && typeof(IGrainExtension).IsAssignableFrom(componentType))\n        {\n            var implementation = ActivationServices.GetKeyedService<IGrainExtension>(componentType);\n            if (implementation is not { } typedResult)\n            {\n                throw new GrainExtensionNotInstalledException($\"No extension of type {componentType} is installed on this instance and no implementations are registered for automated install\");\n            }\n\n            SetComponent(componentType, typedResult);\n            result = typedResult;\n        }\n\n        return result;\n    }\n\n    public TComponent? GetComponent<TComponent>() where TComponent : class => GetComponent(typeof(TComponent)) as TComponent;\n\n    public object? GetComponent(Type componentType)\n    {\n        object? result;\n        if (componentType.IsAssignableFrom(GrainInstance?.GetType()))\n        {\n            result = GrainInstance;\n        }\n        else if (componentType.IsAssignableFrom(GetType()))\n        {\n            result = this;\n        }\n        else if (_extras is { } components && components.TryGetValue(componentType, out var resultObj))\n        {\n            result = resultObj;\n        }\n        else if (_shared.GetComponent(componentType) is { } sharedComponent)\n        {\n            result = sharedComponent;\n        }\n        else if (ActivationServices.GetService(componentType) is { } component)\n        {\n            SetComponent(componentType, component);\n            result = component;\n        }\n        else\n        {\n            result = null;\n        }\n\n        return result;\n    }\n\n    public void SetComponent<TComponent>(TComponent? instance) where TComponent : class => SetComponent(typeof(TComponent), instance);\n\n    public void SetComponent(Type componentType, object? instance)\n    {\n        if (componentType.IsAssignableFrom(GrainInstance?.GetType()))\n        {\n            throw new ArgumentException(\"Cannot override a component which is implemented by this grain\");\n        }\n        else if (componentType.IsAssignableFrom(GetType()))\n        {\n            throw new ArgumentException(\"Cannot override a component which is implemented by this grain context\");\n        }\n\n        lock (this)\n        {\n            if (instance == null)\n            {\n                _extras?.Remove(componentType);\n                return;\n            }\n\n            _extras ??= new();\n            _extras[componentType] = instance;\n        }\n    }\n\n    internal void SetGrainInstance(object grainInstance)\n    {\n        ArgumentNullException.ThrowIfNull(grainInstance);\n\n        lock (this)\n        {\n            if (GrainInstance is not null)\n            {\n                throw new InvalidOperationException(\"Grain instance is already set.\");\n            }\n\n            if (State is not ActivationState.Creating)\n            {\n                throw new InvalidOperationException(\"Grain instance can only be set during creation.\");\n            }\n\n            GrainInstance = grainInstance;\n\n            _shared.OnCreateActivation(this);\n            GetComponent<IActivationLifecycleObserver>()?.OnCreateActivation(this);\n\n            if (grainInstance is ILifecycleParticipant<IGrainLifecycle> participant)\n            {\n                participant.Participate(ObservableLifecycle);\n            }\n        }\n    }\n\n    public void SetState(ActivationState state)\n    {\n        State = state;\n    }\n\n    /// <summary>\n    /// Check whether this activation is overloaded.\n    /// Returns LimitExceededException if overloaded, otherwise <c>null</c>c>\n    /// </summary>\n    /// <returns>Returns LimitExceededException if overloaded, otherwise <c>null</c>c></returns>\n    public LimitExceededException? CheckOverloaded()\n    {\n        string limitName = nameof(SiloMessagingOptions.MaxEnqueuedRequestsHardLimit);\n        int maxRequestsHardLimit = _shared.MessagingOptions.MaxEnqueuedRequestsHardLimit;\n        int maxRequestsSoftLimit = _shared.MessagingOptions.MaxEnqueuedRequestsSoftLimit;\n        if (IsStatelessWorker)\n        {\n            limitName = nameof(SiloMessagingOptions.MaxEnqueuedRequestsHardLimit_StatelessWorker);\n            maxRequestsHardLimit = _shared.MessagingOptions.MaxEnqueuedRequestsHardLimit_StatelessWorker;\n            maxRequestsSoftLimit = _shared.MessagingOptions.MaxEnqueuedRequestsSoftLimit_StatelessWorker;\n        }\n\n        if (maxRequestsHardLimit <= 0 && maxRequestsSoftLimit <= 0) return null; // No limits are set\n\n        int count = GetRequestCount();\n\n        if (maxRequestsHardLimit > 0 && count > maxRequestsHardLimit) // Hard limit\n        {\n            LogRejectActivationTooManyRequests(_shared.Logger, count, this, maxRequestsHardLimit);\n            return new LimitExceededException(limitName, count, maxRequestsHardLimit, ToString());\n        }\n\n        if (maxRequestsSoftLimit > 0 && count > maxRequestsSoftLimit) // Soft limit\n        {\n            LogWarnActivationTooManyRequests(_shared.Logger, count, this, maxRequestsSoftLimit);\n            return null;\n        }\n\n        return null;\n    }\n\n    internal int GetRequestCount()\n    {\n        lock (this)\n        {\n            return _runningRequests.Count + WaitingCount;\n        }\n    }\n\n    internal List<Message> DequeueAllWaitingRequests()\n    {\n        lock (this)\n        {\n            var result = new List<Message>(_waitingRequests.Count);\n            foreach (var (message, _) in _waitingRequests)\n            {\n                // Local-only messages are not allowed to escape the activation.\n                if (message.IsLocalOnly)\n                {\n                    continue;\n                }\n\n                result.Add(message);\n            }\n\n            _waitingRequests.Clear();\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Returns how long this activation has been idle.\n    /// </summary>\n    public TimeSpan GetIdleness() => _idleDuration.Elapsed;\n\n    /// <summary>\n    /// Returns whether this activation has been idle long enough to be collected.\n    /// </summary>\n    public bool IsStale() => GetIdleness() >= _shared.CollectionAgeLimit;\n\n    public void DelayDeactivation(TimeSpan timespan)\n    {\n        if (timespan == TimeSpan.MaxValue || timespan == Timeout.InfiniteTimeSpan)\n        {\n            // otherwise creates negative time.\n            KeepAliveUntil = DateTime.MaxValue;\n        }\n        else if (timespan <= TimeSpan.Zero)\n        {\n            // reset any current keepAliveUntil\n            ResetKeepAliveRequest();\n        }\n        else\n        {\n            KeepAliveUntil = GrainRuntime.TimeProvider.GetUtcNow().UtcDateTime + timespan;\n        }\n    }\n\n    public void ResetKeepAliveRequest() => KeepAliveUntil = DateTime.MinValue;\n\n    private void ScheduleOperation(object operation)\n    {\n        lock (this)\n        {\n            _pendingOperations ??= new();\n            _pendingOperations.Enqueue(operation);\n        }\n\n        _workSignal.Signal();\n    }\n\n    private void CancelPendingOperations()\n    {\n        lock (this)\n        {\n            // If the grain is currently activating, cancel that operation.\n            if (_pendingOperations is not { Count: > 0 } operations)\n            {\n                return;\n            }\n\n            var opCount = operations.Count;\n            // We could be using an ArrayPool<Command> here, but we would need to filter out the\n            // non-command types, which means we would need to loop over _pendingOperations, which\n            // defeats the purpose of making a snapshot.\n            // Note: CopyTo does not use the queue's enumerator, so its safe to take a snapshot this way.\n            var array = ArrayPool<object>.Shared.Rent(opCount);\n\n            operations.CopyTo(array, 0);\n\n            var snapshot = new Span<object>(array, 0, opCount);\n\n            try\n            {\n                foreach (var op in snapshot)\n                {\n                    if (op is Command cmd)\n                    {\n                        try\n                        {\n                            cmd.Cancel();\n                        }\n                        catch (Exception exception)\n                        {\n                            if (exception is not ObjectDisposedException)\n                            {\n                                LogErrorCancellingOperation(_shared.Logger, exception, cmd);\n                            }\n                        }\n                    }\n                }\n            }\n            finally\n            {\n                ArrayPool<object>.Shared.Return(array, true);\n            }\n        }\n    }\n\n    public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken = default)\n    {\n        lock (this)\n        {\n            if (State is not (ActivationState.Activating or ActivationState.Valid or ActivationState.Deactivating))\n            {\n                return;\n            }\n\n            // If migration has not already been started, set a migration context to capture any state which should be transferred.\n            // Doing this signals to the deactivation process that a migration is occurring, so it is important that this happens before we begin deactivation.\n            DehydrationContext ??= new(_shared.SerializerSessionPool, requestContext);\n\n            if (State is not ActivationState.Deactivating)\n            {\n                // Start deactivating the grain to prepare for migration.\n                Deactivate(new DeactivationReason(DeactivationReasonCode.Migrating, \"Migrating to a new location.\"), cancellationToken);\n            }\n        }\n    }\n\n    public void Deactivate(DeactivationReason reason, ActivityContext? activityContext, CancellationToken cancellationToken = default)\n    {\n        var currentActivity = Activity.Current;\n        var deactivateActivity = activityContext is { } parent\n            ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.DeactivateGrain, ActivityKind.Internal, parentContext:parent)\n            : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.DeactivateGrain);\n        \n        lock (this)\n        {\n            try\n            {\n                var state = State;\n                if (deactivateActivity is { IsAllDataRequested: true })\n                {\n                    deactivateActivity.SetTag(ActivityTagKeys.GrainState, state);\n                }\n\n                if (state is ActivationState.Invalid)\n                {\n                    deactivateActivity?.Stop();\n                    return;\n                }\n\n                if (DeactivationReason.ReasonCode == DeactivationReasonCode.None)\n                {\n                    DeactivationReason = reason;\n                }\n\n                if (deactivateActivity is { IsAllDataRequested: true })\n                {\n                    deactivateActivity.SetTag(ActivityTagKeys.DeactivationReason, DeactivationReason);\n                }\n\n                if (!DeactivationStartTime.HasValue)\n                {\n                    DeactivationStartTime = GrainRuntime.TimeProvider.GetUtcNow().UtcDateTime;\n                }\n\n                if (state is ActivationState.Creating or ActivationState.Activating or ActivationState.Valid)\n                {\n                    CancelPendingOperations();\n\n                    _shared.InternalRuntime.ActivationWorkingSet.OnDeactivating(this);\n                    SetState(ActivationState.Deactivating);\n                    var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n                    cts.CancelAfter(_shared.InternalRuntime.CollectionOptions.Value.DeactivationTimeout);\n                    ScheduleOperation(new Command.Deactivate(cts, state, deactivateActivity));\n                }\n                else\n                {\n                    deactivateActivity?.Stop();\n                }\n            }\n            catch (Exception ex)\n            {\n                SetActivityError(deactivateActivity, ex, \"Error deactivating grain\");\n                deactivateActivity?.Stop();\n                throw;\n            }\n            finally\n            {\n                Activity.Current = currentActivity;\n            }\n        }\n    }\n\n    public void Deactivate(DeactivationReason reason, CancellationToken cancellationToken = default) => Deactivate(reason, Activity.Current?.Context, cancellationToken);\n\n    private void DeactivateStuckActivation()\n    {\n        IsStuckProcessingMessage = true;\n        var msg = $\"Activation {this} has been processing request {_blockingRequest} since {_busyDuration} and is likely stuck.\";\n        var reason = new DeactivationReason(DeactivationReasonCode.ActivationUnresponsive, msg);\n\n        // Mark the grain as deactivating so that messages are forwarded instead of being invoked\n        Deactivate(reason, cancellationToken: default);\n\n        // Try to remove this activation from the catalog and directory\n        // This leaves this activation dangling, stuck processing the current request until it eventually completes\n        // (which likely will never happen at this point, since if the grain was deemed stuck then there is probably some kind of\n        // application bug, perhaps a deadlock)\n        UnregisterMessageTarget();\n        _shared.InternalRuntime.GrainLocator.Unregister(Address, UnregistrationCause.Force).Ignore();\n    }\n\n    void IGrainTimerRegistry.OnTimerCreated(IGrainTimer timer)\n    {\n        lock (this)\n        {\n            Timers ??= new HashSet<IGrainTimer>();\n            Timers.Add(timer);\n        }\n    }\n\n    void IGrainTimerRegistry.OnTimerDisposed(IGrainTimer timer)\n    {\n        lock (this) // need to lock since dispose can be called on finalizer thread, outside grain context (not single threaded).\n        {\n            if (Timers is null)\n            {\n                return;\n            }\n\n            Timers.Remove(timer);\n        }\n    }\n\n    private void DisposeTimers()\n    {\n        lock (this)\n        {\n            if (Timers is null)\n            {\n                return;\n            }\n\n            // Need to set Timers to null since OnTimerDisposed mutates the timers set if it is not null.\n            var timers = Timers;\n            Timers = null;\n\n            // Dispose all timers.\n            foreach (var timer in timers)\n            {\n                timer.Dispose();\n            }\n        }\n    }\n\n    public void AnalyzeWorkload(DateTime now, IMessageCenter messageCenter, MessageFactory messageFactory, SiloMessagingOptions options)\n    {\n        var slowRunningRequestDuration = options.RequestProcessingWarningTime;\n        var longQueueTimeDuration = options.RequestQueueDelayWarningTime;\n\n        List<string>? diagnostics = null;\n        lock (this)\n        {\n            if (State != ActivationState.Valid)\n            {\n                return;\n            }\n\n            if (_blockingRequest is not null)\n            {\n                var message = _blockingRequest;\n                TimeSpan? timeSinceQueued = default;\n                if (_runningRequests.TryGetValue(message, out var waitTime))\n                {\n                    timeSinceQueued = waitTime.Elapsed;\n                }\n\n                var executionTime = _busyDuration.Elapsed;\n                if (executionTime >= slowRunningRequestDuration && !message.IsLocalOnly)\n                {\n                    GetStatusList(ref diagnostics);\n                    if (timeSinceQueued.HasValue)\n                    {\n                        diagnostics.Add($\"Message {message} was enqueued {timeSinceQueued} ago and has now been executing for {executionTime}.\");\n                    }\n                    else\n                    {\n                        diagnostics.Add($\"Message {message} has been executing for {executionTime}.\");\n                    }\n\n                    var response = messageFactory.CreateDiagnosticResponseMessage(message, isExecuting: true, isWaiting: false, diagnostics);\n                    messageCenter.SendMessage(response);\n                }\n            }\n\n            foreach (var running in _runningRequests)\n            {\n                var message = running.Key;\n                var runDuration = running.Value;\n                if (ReferenceEquals(message, _blockingRequest) || message.IsLocalOnly)\n                {\n                    continue;\n                }\n\n                // Check how long they've been executing.\n                var executionTime = runDuration.Elapsed;\n                if (executionTime >= slowRunningRequestDuration)\n                {\n                    // Interleaving message X has been executing for a long time\n                    GetStatusList(ref diagnostics);\n                    var messageDiagnostics = new List<string>(diagnostics)\n                    {\n                        $\"Interleaving message {message} has been executing for {executionTime}.\"\n                    };\n\n                    var response = messageFactory.CreateDiagnosticResponseMessage(message, isExecuting: true, isWaiting: false, messageDiagnostics);\n                    messageCenter.SendMessage(response);\n                }\n            }\n\n            var queueLength = 1;\n            foreach (var pair in _waitingRequests)\n            {\n                var message = pair.Message;\n                if (message.IsLocalOnly)\n                {\n                    continue;\n                }\n\n                var queuedTime = pair.QueuedTime.Elapsed;\n                if (queuedTime >= longQueueTimeDuration)\n                {\n                    // Message X has been enqueued on the target grain for Y and is currently position QueueLength in queue for processing.\n                    GetStatusList(ref diagnostics);\n                    var messageDiagnostics = new List<string>(diagnostics)\n                    {\n                       $\"Message {message} has been enqueued on the target grain for {queuedTime} and is currently position {queueLength} in queue for processing.\"\n                    };\n\n                    var response = messageFactory.CreateDiagnosticResponseMessage(message, isExecuting: false, isWaiting: true, messageDiagnostics);\n                    messageCenter.SendMessage(response);\n                }\n\n                queueLength++;\n            }\n        }\n\n        void GetStatusList([NotNull] ref List<string>? diagnostics)\n        {\n            if (diagnostics is not null) return;\n\n            diagnostics = new List<string>\n            {\n                ToDetailedString(),\n                $\"TaskScheduler status: {_workItemGroup.DumpStatus()}\"\n            };\n        }\n    }\n\n    public override string ToString() => $\"[Activation: {Address.SiloAddress}/{GrainId}{ActivationId}{GetActivationInfoString()} State={State}]\";\n\n    internal string ToDetailedString(bool includeExtraDetails = false)\n    {\n        lock (this)\n        {\n            var currentlyExecuting = includeExtraDetails ? _blockingRequest : null;\n            return @$\"[Activation: {Address.SiloAddress}/{GrainId}{ActivationId} {GetActivationInfoString()} State={State} NonReentrancyQueueSize={WaitingCount} NumRunning={_runningRequests.Count} IdlenessTimeSpan={GetIdleness()} CollectionAgeLimit={_shared.CollectionAgeLimit}{(currentlyExecuting != null ? \" CurrentlyExecuting=\" : null)}{currentlyExecuting}]\";\n        }\n    }\n\n    private string GetActivationInfoString()\n    {\n        var placement = PlacementStrategy?.GetType().Name;\n        var grainTypeName = _shared.GrainTypeName ?? GrainInstance switch\n        {\n            { } grainInstance => RuntimeTypeNameFormatter.Format(grainInstance.GetType()),\n            _ => null\n        };\n        return grainTypeName is null ? $\"#Placement={placement}\" : $\"#GrainType={grainTypeName} Placement={placement}\";\n    }\n\n    public void Dispose() => DisposeAsync().AsTask().Wait();\n\n    public async ValueTask DisposeAsync()\n    {\n        _extras ??= new();\n        if (_extras.IsDisposing) return;\n        _extras.IsDisposing = true;\n\n        CancelPendingOperations();\n\n        lock (this)\n        {\n            _shared.InternalRuntime.ActivationWorkingSet.OnDeactivated(this);\n            SetState(ActivationState.Invalid);\n        }\n\n        DisposeTimers();\n\n        try\n        {\n            var activator = _shared.GetComponent(typeof(IGrainActivator)) as IGrainActivator;\n            if (activator != null && GrainInstance is { } instance)\n            {\n                await activator.DisposeInstance(this, instance);\n            }\n        }\n        catch (ObjectDisposedException)\n        {\n        }\n\n        try\n        {\n            _shared.OnDestroyActivation(this);\n            GetComponent<IActivationLifecycleObserver>()?.OnDestroyActivation(this);\n        }\n        catch (ObjectDisposedException)\n        {\n        }\n\n        await DisposeAsync(_serviceScope);\n    }\n\n    private static async ValueTask DisposeAsync(object obj)\n    {\n        try\n        {\n            if (obj is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync();\n            }\n            else if (obj is IDisposable disposable)\n            {\n                disposable.Dispose();\n            }\n        }\n        catch\n        {\n            // Ignore.\n        }\n    }\n\n    bool IEquatable<IGrainContext>.Equals(IGrainContext? other) => ReferenceEquals(this, other);\n\n    public (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n        where TExtension : class, TExtensionInterface\n        where TExtensionInterface : class, IGrainExtension\n    {\n        TExtension implementation;\n        if (GetComponent<TExtensionInterface>() is object existing)\n        {\n            if (existing is TExtension typedResult)\n            {\n                implementation = typedResult;\n            }\n            else\n            {\n                throw new InvalidCastException($\"Cannot cast existing extension of type {existing.GetType()} to target type {typeof(TExtension)}\");\n            }\n        }\n        else\n        {\n            implementation = newExtensionFunc();\n            SetComponent<TExtensionInterface>(implementation);\n        }\n\n        var reference = GrainReference.Cast<TExtensionInterface>();\n        return (implementation, reference);\n    }\n\n    public TExtensionInterface GetExtension<TExtensionInterface>()\n        where TExtensionInterface : class, IGrainExtension\n    {\n        if (GetComponent<TExtensionInterface>() is TExtensionInterface result)\n        {\n            return result;\n        }\n\n        var implementation = ActivationServices.GetKeyedService<IGrainExtension>(typeof(TExtensionInterface));\n        if (implementation is not TExtensionInterface typedResult)\n        {\n            throw new GrainExtensionNotInstalledException($\"No extension of type {typeof(TExtensionInterface)} is installed on this instance and no implementations are registered for automated install\");\n        }\n\n        SetComponent(typedResult);\n        return typedResult;\n    }\n\n    bool IActivationWorkingSetMember.IsCandidateForRemoval(bool wouldRemove)\n    {\n        const int IdlenessLowerBound = 10_000;\n        lock (this)\n        {\n            var inactive = IsInactive && _idleDuration.ElapsedMilliseconds > IdlenessLowerBound;\n\n            // This instance will remain in the working set if it is either not pending removal or if it is currently active.\n            _isInWorkingSet = !wouldRemove || !inactive;\n            return inactive;\n        }\n    }\n\n    private async Task RunMessageLoop()\n    {\n        // Note that this loop never terminates. That might look strange, but there is a reason for it:\n        // a grain must always accept and process any incoming messages. How a grain processes\n        // those messages is up to the grain's state to determine. If the grain has not yet\n        // completed activating, it will let the messages continue to queue up until it completes activation.\n        // If the grain failed to activate, messages will be responded to with a rejection.\n        // If the grain has terminated, messages will be forwarded on to a new instance of this grain.\n        // The loop will eventually be garbage collected when the grain gets deactivated and there are no\n        // rooted references to it.\n        while (true)\n        {\n            try\n            {\n                if (!IsCurrentlyExecuting)\n                {\n                    bool hasPendingOperations;\n                    lock (this)\n                    {\n                        hasPendingOperations = _pendingOperations is { Count: > 0 };\n                    }\n\n                    if (hasPendingOperations)\n                    {\n                        await ProcessOperationsAsync();\n                    }\n                }\n\n                ProcessPendingRequests();\n\n                await _workSignal.WaitAsync();\n            }\n            catch (Exception exception)\n            {\n                _shared.InternalRuntime.MessagingTrace.LogError(exception, \"Error in grain message loop\");\n            }\n        }\n\n        void ProcessPendingRequests()\n        {\n            var i = 0;\n\n            do\n            {\n                Message? message = null;\n                lock (this)\n                {\n                    if (_waitingRequests.Count <= i)\n                    {\n                        break;\n                    }\n\n                    message = _waitingRequests[i].Message;\n\n                    // If the activation is not valid, reject all pending messages except for local-only messages.\n                    // Local-only messages are used for internal system operations and should not be rejected while the grain is valid or deactivating.\n                    if (State != ActivationState.Valid && !(message.IsLocalOnly && State is ActivationState.Deactivating))\n                    {\n                        ProcessRequestsToInvalidActivation();\n                        break;\n                    }\n\n                    try\n                    {\n                        if (!MayInvokeRequest(message))\n                        {\n                            // The activation is not able to process this message right now, so try the next message.\n                            ++i;\n\n                            if (_blockingRequest != null)\n                            {\n                                var currentRequestActiveTime = _busyDuration.Elapsed;\n                                if (currentRequestActiveTime > _shared.MaxRequestProcessingTime && !IsStuckProcessingMessage)\n                                {\n                                    DeactivateStuckActivation();\n                                }\n                                else if (currentRequestActiveTime > _shared.MaxWarningRequestProcessingTime)\n                                {\n                                    // Consider: Handle long request detection for reentrant activations -- this logic only works for non-reentrant activations\n                                    LogWarningDispatcher_ExtendedMessageProcessing(\n                                        _shared.Logger,\n                                        currentRequestActiveTime,\n                                        new(this),\n                                        _blockingRequest,\n                                        message);\n                                }\n                            }\n\n                            continue;\n                        }\n\n                        // If the current message is incompatible, deactivate this activation and eventually forward the message to a new incarnation.\n                        if (message.InterfaceVersion > 0)\n                        {\n                            var compatibilityDirector = _shared.InternalRuntime.CompatibilityDirectorManager.GetDirector(message.InterfaceType);\n                            var currentVersion = _shared.InternalRuntime.GrainVersionManifest.GetLocalVersion(message.InterfaceType);\n                            if (!compatibilityDirector.IsCompatible(message.InterfaceVersion, currentVersion))\n                            {\n                                // Add this activation to cache invalidation headers.\n                                message.AddToCacheInvalidationHeader(Address, validAddress: null);\n\n                                var reason = new DeactivationReason(\n                                    DeactivationReasonCode.IncompatibleRequest,\n                                    $\"Received incompatible request for interface {message.InterfaceType} version {message.InterfaceVersion}. This activation supports interface version {currentVersion}.\");\n\n                                var activityContext = message.RequestContextData.TryGetActivityContext();\n\n                                Deactivate(reason, activityContext, cancellationToken: default);\n                                return;\n                            }\n                        }\n                    }\n                    catch (Exception exception)\n                    {\n                        if (!message.IsLocalOnly)\n                        {\n                            _shared.InternalRuntime.MessageCenter.RejectMessage(message, Message.RejectionTypes.Transient, exception);\n                        }\n\n                        _waitingRequests.RemoveAt(i);\n                        continue;\n                    }\n\n                    // Process this message, removing it from the queue.\n                    _waitingRequests.RemoveAt(i);\n\n                    Debug.Assert(State == ActivationState.Valid || message.IsLocalOnly);\n                    RecordRunning(message, message.IsAlwaysInterleave);\n                }\n\n                // Start invoking the message outside of the lock\n                InvokeIncomingRequest(message);\n            }\n            while (true);\n        }\n\n        void RecordRunning(Message message, bool isInterleavable)\n        {\n            var stopwatch = CoarseStopwatch.StartNew();\n            _runningRequests.Add(message, stopwatch);\n\n            if (_blockingRequest != null || isInterleavable) return;\n\n            // This logic only works for non-reentrant activations\n            // Consider: Handle long request detection for reentrant activations.\n            _blockingRequest = message;\n            _busyDuration = stopwatch;\n        }\n\n        void ProcessRequestsToInvalidActivation()\n        {\n            if (State is ActivationState.Creating or ActivationState.Activating)\n            {\n                // Do nothing until the activation becomes either valid or invalid\n                return;\n            }\n\n            if (State is ActivationState.Deactivating)\n            {\n                // Determine whether to declare this activation as stuck\n                var deactivatingTime = GrainRuntime.TimeProvider.GetUtcNow().UtcDateTime - DeactivationStartTime!.Value;\n                if (deactivatingTime > _shared.MaxRequestProcessingTime && !IsStuckDeactivating)\n                {\n                    IsStuckDeactivating = true;\n                    if (DeactivationReason.Description is { Length: > 0 } && DeactivationReason.ReasonCode != DeactivationReasonCode.ActivationUnresponsive)\n                    {\n                        DeactivationReason = new(DeactivationReasonCode.ActivationUnresponsive,\n                            $\"{DeactivationReason.Description}. Activation {this} has been deactivating since {DeactivationStartTime.Value} and is likely stuck\");\n                    }\n                }\n\n                if (!IsStuckDeactivating && !IsStuckProcessingMessage)\n                {\n                    // Do not forward messages while the grain is still deactivating and has not been declared stuck, since they\n                    // will be forwarded to the same grain instance.\n                    return;\n                }\n            }\n\n            if (DeactivationException is null || ForwardingAddress is { })\n            {\n                // Either this was a duplicate activation or it was at some point successfully activated\n                // Forward all pending messages\n                RerouteAllQueuedMessages();\n            }\n            else\n            {\n                // Reject all pending messages\n                RejectAllQueuedMessages();\n            }\n        }\n\n        bool MayInvokeRequest(Message incoming)\n        {\n            if (!IsCurrentlyExecuting)\n            {\n                return true;\n            }\n\n            // Otherwise, allow request invocation if the grain is reentrant or the message can be interleaved\n            if (incoming.IsAlwaysInterleave)\n            {\n                return true;\n            }\n\n            if (_blockingRequest is null)\n            {\n                return true;\n            }\n\n            if (_blockingRequest.IsReadOnly && incoming.IsReadOnly)\n            {\n                return true;\n            }\n\n            // Handle call-chain reentrancy\n            if (incoming.GetReentrancyId() is Guid id\n                && IsReentrantSection(id))\n            {\n                return true;\n            }\n\n            if (GetComponent<GrainCanInterleave>() is GrainCanInterleave canInterleave)\n            {\n                try\n                {\n                    return canInterleave.MayInterleave(GrainInstance, incoming)\n                        || canInterleave.MayInterleave(GrainInstance, _blockingRequest);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorInvokingMayInterleavePredicate(_shared.Logger, exception, this, incoming);\n                    throw;\n                }\n            }\n\n            return false;\n        }\n\n        async Task ProcessOperationsAsync()\n        {\n            object? op = null;\n            while (true)\n            {\n                lock (this)\n                {\n                    Debug.Assert(_pendingOperations is not null);\n\n                    // Remove the previous operation.\n                    // Operations are not removed until they are completed, allowing for them to see each other.\n                    // Eg, a deactivation request can see any on-going activation request and cancel it.\n                    if (op is not null)\n                    {\n                        _pendingOperations.Dequeue();\n                    }\n\n                    // Try to get the next operation.\n                    if (!_pendingOperations.TryPeek(out op))\n                    {\n                        _pendingOperations = null;\n                        return;\n                    }\n                }\n\n                try\n                {\n                    switch (op)\n                    {\n                        case Command.Rehydrate command:\n                            RehydrateInternal(command.Context);\n                            break;\n                        case Command.Activate command:\n                            await ActivateAsync(command.RequestContext, command.CancellationToken).SuppressThrowing();\n                            break;\n                        case Command.Deactivate command:\n                            await FinishDeactivating(command, command.CancellationToken).SuppressThrowing();\n                            break;\n                        case Command.Delay command:\n                            await Task.Delay(command.Duration, GrainRuntime.TimeProvider, command.CancellationToken).SuppressThrowing();\n                            break;\n                        default:\n                            throw new NotSupportedException($\"Encountered unknown operation of type {op?.GetType().ToString() ?? \"null\"} {op}.\");\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorInProcessOperationsAsync(_shared.Logger, exception, this);\n                }\n                finally\n                {\n                    if (op is not null)\n                    {\n                        await DisposeAsync(op);\n                    }\n                }\n            }\n        }\n    }\n\n    private void RehydrateInternal(IRehydrationContext context)\n    {\n        Activity? rehydrateSpan = null;\n        try\n        {\n            LogRehydratingGrain(_shared.Logger, this);\n\n            var grainMigrationParticipant = GrainInstance as IGrainMigrationParticipant;\n\n            if (grainMigrationParticipant is not null)\n            {\n                // Start a span for rehydration\n                rehydrateSpan = _activationActivity is not null\n                    ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivationRehydrate,\n                        ActivityKind.Internal, _activationActivity.Context)\n                    : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivationRehydrate,\n                        ActivityKind.Internal);\n                rehydrateSpan?.SetTag(ActivityTagKeys.GrainId, GrainId.ToString());\n                rehydrateSpan?.SetTag(ActivityTagKeys.GrainType, _shared.GrainTypeName);\n                rehydrateSpan?.SetTag(ActivityTagKeys.SiloId, _shared.Runtime.SiloAddress.ToString());\n                rehydrateSpan?.SetTag(ActivityTagKeys.ActivationId, ActivationId.ToString());\n            }\n\n            lock (this)\n            {\n                if (State != ActivationState.Creating)\n                {\n                    LogIgnoringRehydrateAttempt(_shared.Logger, this, State);\n                    rehydrateSpan?.SetTag(ActivityTagKeys.RehydrateIgnored, true);\n                    rehydrateSpan?.SetTag(ActivityTagKeys.RehydrateIgnoredReason, $\"State is {State}\");\n                    return;\n                }\n\n                if (context.TryGetValue(GrainAddressMigrationContextKey, out GrainAddress? previousRegistration) &&\n                    previousRegistration is not null)\n                {\n                    PreviousRegistration = previousRegistration;\n                    LogPreviousActivationAddress(_shared.Logger, previousRegistration);\n                    rehydrateSpan?.SetTag(ActivityTagKeys.RehydratePreviousRegistration,\n                        previousRegistration.ToFullString());\n                }\n\n                if (_lifecycle is { } lifecycle)\n                {\n                    foreach (var participant in lifecycle.GetMigrationParticipants())\n                    {\n                        participant.OnRehydrate(context);\n                    }\n                }\n\n                grainMigrationParticipant?.OnRehydrate(context);\n            }\n\n            LogRehydratedGrain(_shared.Logger);\n            rehydrateSpan?.AddEvent(new ActivityEvent(\"rehydrated\"));\n        }\n        catch (Exception exception)\n        {\n            LogErrorRehydratingActivation(_shared.Logger, exception);\n            SetActivityError(rehydrateSpan, exception, ActivityErrorEvents.RehydrateError);\n        }\n        finally\n        {\n            rehydrateSpan?.Dispose();\n        }\n    }\n\n    private void OnDehydrate(IDehydrationContext context)\n    {\n        LogDehydratingActivation(_shared.Logger);\n\n        lock (this)\n        {\n            Debug.Assert(context is not null);\n\n            if (IsUsingGrainDirectory)\n            {\n                context.TryAddValue(GrainAddressMigrationContextKey, Address);\n            }\n            \n            Activity? dehydrateSpan = null;\n            try\n            {\n                // Get the parent activity context from the dehydration context holder (captured when migration was initiated)\n                var parentContext = DehydrationContext?.MigrationActivityContext;\n\n                var grainMigrationParticipant = GrainInstance as IGrainMigrationParticipant;\n\n                if (grainMigrationParticipant is not null)\n                {\n                    // Start a span for dehydration, parented to the migration request that triggered it\n                    dehydrateSpan = parentContext.HasValue\n                        ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivationDehydrate,\n                            ActivityKind.Internal, parentContext.Value)\n                        : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivationDehydrate,\n                            ActivityKind.Internal);\n                    if (dehydrateSpan is { IsAllDataRequested: true })\n                    {\n                        dehydrateSpan.SetTag(ActivityTagKeys.GrainId, GrainId.ToString());\n                        dehydrateSpan.SetTag(ActivityTagKeys.GrainType, _shared.GrainTypeName);\n                        dehydrateSpan.SetTag(ActivityTagKeys.SiloId, _shared.Runtime.SiloAddress.ToString());\n                        dehydrateSpan.SetTag(ActivityTagKeys.ActivationId, ActivationId.ToString());\n                        if (ForwardingAddress is { } fwd)\n                        {\n                            dehydrateSpan.SetTag(ActivityTagKeys.MigrationTargetSilo, fwd.ToString());\n                        }\n                    }\n                }\n\n                // Note that these calls are in reverse order from Rehydrate, not for any particular reason other than symmetry.\n                grainMigrationParticipant?.OnDehydrate(context);\n\n                if (_lifecycle is { } lifecycle)\n                {\n                    foreach (var participant in lifecycle.GetMigrationParticipants())\n                    {\n                        participant.OnDehydrate(context);\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                LogErrorDehydratingActivation(_shared.Logger, exception);\n                SetActivityError(dehydrateSpan, exception, ActivityErrorEvents.DehydrateError);\n            }\n            finally\n            {\n                dehydrateSpan?.Dispose();\n            }\n        }\n\n        LogDehydratedActivation(_shared.Logger);\n    }\n\n\n    /// <summary>\n    /// Handle an incoming message and queue/invoke appropriate handler\n    /// </summary>\n    /// <param name=\"message\"></param>\n    private void InvokeIncomingRequest(Message message)\n    {\n        MessagingProcessingInstruments.OnDispatcherMessageProcessedOk(message);\n        _shared.InternalRuntime.MessagingTrace.OnScheduleMessage(message);\n\n        try\n        {\n            var task = _shared.InternalRuntime.RuntimeClient.Invoke(this, message);\n\n            // Note: This runs for all outcomes - both Success or Fault\n            if (task.IsCompleted)\n            {\n                OnCompletedRequest(message);\n            }\n            else\n            {\n                _ = OnCompleteAsync(this, message, task);\n            }\n        }\n        catch\n        {\n            OnCompletedRequest(message);\n        }\n\n        static async ValueTask OnCompleteAsync(ActivationData activation, Message message, Task task)\n        {\n            try\n            {\n                await task;\n            }\n            catch\n            {\n            }\n            finally\n            {\n                activation.OnCompletedRequest(message);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Invoked when an activation has finished a transaction and may be ready for additional transactions\n    /// </summary>\n    /// <param name=\"message\">The message that has just completed processing.</param>\n    private void OnCompletedRequest(Message message)\n    {\n        lock (this)\n        {\n            _runningRequests.Remove(message);\n\n            // If the message is meant to keep the activation active, reset the idle timer and ensure the activation\n            // is in the activation working set.\n            if (message.IsKeepAlive)\n            {\n                _idleDuration = CoarseStopwatch.StartNew();\n\n                if (!_isInWorkingSet)\n                {\n                    _isInWorkingSet = true;\n                    _shared.InternalRuntime.ActivationWorkingSet.OnActive(this);\n                }\n            }\n\n            // The below logic only works for non-reentrant activations\n            if (_blockingRequest is null || message.Equals(_blockingRequest))\n            {\n                _blockingRequest = null;\n                _busyDuration = default;\n            }\n        }\n\n        // Signal the message pump to see if there is another request which can be processed now that this one has completed\n        _workSignal.Signal();\n    }\n\n    public void ReceiveMessage(object message) => ReceiveMessage((Message)message);\n    public void ReceiveMessage(Message message)\n    {\n        _shared.InternalRuntime.MessagingTrace.OnDispatcherReceiveMessage(message);\n\n        // Don't process messages that have already timed out\n        if (message.IsExpired)\n        {\n            MessagingProcessingInstruments.OnDispatcherMessageProcessedError(message);\n            _shared.InternalRuntime.MessagingTrace.OnDropExpiredMessage(message, MessagingInstruments.Phase.Dispatch);\n            return;\n        }\n\n        if (message.Direction == Message.Directions.Response)\n        {\n            ReceiveResponse(message);\n        }\n        else // Request or OneWay\n        {\n            ReceiveRequest(message);\n        }\n    }\n\n    private void ReceiveResponse(Message message)\n    {\n        lock (this)\n        {\n            if (State == ActivationState.Invalid)\n            {\n                _shared.InternalRuntime.MessagingTrace.OnDispatcherReceiveInvalidActivation(message, State);\n\n                // Always process responses\n                _shared.InternalRuntime.RuntimeClient.ReceiveResponse(message);\n                return;\n            }\n\n            MessagingProcessingInstruments.OnDispatcherMessageProcessedOk(message);\n            _shared.InternalRuntime.RuntimeClient.ReceiveResponse(message);\n        }\n    }\n\n    private void ReceiveRequest(Message message)\n    {\n        var overloadException = CheckOverloaded();\n        if (overloadException != null && !message.IsLocalOnly)\n        {\n            MessagingProcessingInstruments.OnDispatcherMessageProcessedError(message);\n            _shared.InternalRuntime.MessageCenter.RejectMessage(message, Message.RejectionTypes.Overloaded, overloadException, \"Target activation is overloaded \" + this);\n            return;\n        }\n\n        lock (this)\n        {\n            _waitingRequests.Add((message, CoarseStopwatch.StartNew()));\n        }\n\n        _workSignal.Signal();\n    }\n\n    /// <summary>\n    /// Rejects all messages enqueued for the provided activation.\n    /// </summary>\n    private void RejectAllQueuedMessages()\n    {\n        lock (this)\n        {\n            List<Message> msgs = DequeueAllWaitingRequests();\n            if (msgs == null || msgs.Count <= 0) return;\n\n            LogRejectAllQueuedMessages(_shared.Logger, msgs.Count, this);\n            _shared.InternalRuntime.GrainLocator.InvalidateCache(Address);\n            _shared.InternalRuntime.MessageCenter.ProcessRequestsToInvalidActivation(\n                msgs,\n                Address,\n                forwardingAddress: ForwardingAddress,\n                failedOperation: DeactivationReason.Description,\n                exc: DeactivationException,\n                rejectMessages: true);\n        }\n    }\n\n    private void RerouteAllQueuedMessages()\n    {\n        lock (this)\n        {\n            List<Message> msgs = DequeueAllWaitingRequests();\n            if (msgs is not { Count: > 0 })\n            {\n                return;\n            }\n\n            // If deactivation was caused by a transient failure, allow messages to be forwarded.\n            if (DeactivationReason.ReasonCode.IsTransientError())\n            {\n                foreach (var msg in msgs)\n                {\n                    msg.ForwardCount = Math.Max(msg.ForwardCount - 1, 0);\n                }\n            }\n\n            if (_shared.Logger.IsEnabled(LogLevel.Debug))\n            {\n                if (ForwardingAddress is { } address)\n                {\n                    LogReroutingMessages(_shared.Logger, msgs.Count, this, address);\n                }\n                else\n                {\n                    LogReroutingMessagesNoForwarding(_shared.Logger, msgs.Count, this);\n                }\n            }\n\n            _shared.InternalRuntime.GrainLocator.InvalidateCache(Address);\n            _shared.InternalRuntime.MessageCenter.ProcessRequestsToInvalidActivation(msgs, Address, ForwardingAddress, DeactivationReason.Description, DeactivationException);\n        }\n    }\n\n    #region Activation\n    public void Rehydrate(IRehydrationContext context)\n    {\n        ScheduleOperation(new Command.Rehydrate(context));\n    }\n\n    public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n    {\n        var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n        cts.CancelAfter(_shared.InternalRuntime.CollectionOptions.Value.ActivationTimeout);\n\n        ScheduleOperation(new Command.Activate(requestContext, cts));\n    }\n\n    private async Task ActivateAsync(Dictionary<string, object>? requestContextData, CancellationToken cancellationToken)\n    {\n        if (State != ActivationState.Creating)\n        {\n            LogIgnoringActivateAttempt(_shared.Logger, this, State);\n            return;\n        }\n\n        _activationActivity?.AddEvent(new ActivityEvent(\"activation-start\"));\n        try\n        {\n            if (IsUsingGrainDirectory)\n            {\n                bool success;\n                Exception? registrationException;\n\n                // Start directory registration activity as a child of the activation activity\n                using (var registerSpan = _activationActivity is not null\n                    ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.RegisterDirectoryEntry, ActivityKind.Internal, _activationActivity.Context)\n                    : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.RegisterDirectoryEntry, ActivityKind.Internal))\n                {\n                    registerSpan?.SetTag(ActivityTagKeys.GrainId, GrainId.ToString());\n                    registerSpan?.SetTag(ActivityTagKeys.SiloId, _shared.Runtime.SiloAddress.ToString());\n                    registerSpan?.SetTag(ActivityTagKeys.ActivationId, ActivationId.ToString());\n                    registerSpan?.SetTag(ActivityTagKeys.DirectoryPreviousRegistrationPresent,\n                        PreviousRegistration is not null);\n                    var previousRegistration = PreviousRegistration;\n                    \n                    try\n                    {\n                        while (true)\n                        {\n                            LogRegisteringGrain(_shared.Logger, this, previousRegistration);\n\n                            var result = await _shared.InternalRuntime.GrainLocator\n                                .Register(Address, previousRegistration).WaitAsync(cancellationToken);\n                            if (Address.Matches(result))\n                            {\n                                Address = result;\n                                success = true;\n                                _activationActivity?.AddEvent(new ActivityEvent(\"directory-register-success\"));\n                                registerSpan?.AddEvent(new ActivityEvent(\"success\"));\n                                registerSpan?.SetTag(ActivityTagKeys.DirectoryRegisteredAddress, result.ToFullString());\n                            }\n                            else if (result?.SiloAddress is { } registeredSilo &&\n                                     registeredSilo.Equals(Address.SiloAddress))\n                            {\n                                previousRegistration = result;\n                                LogAttemptToRegisterWithPreviousActivation(_shared.Logger, GrainId, result);\n                                _activationActivity?.AddEvent(new ActivityEvent(\"directory-register-retry-previous\"));\n                                registerSpan?.AddEvent(new ActivityEvent(\"retry-previous\"));\n                                continue;\n                            }\n                            else\n                            {\n                                ForwardingAddress = result?.SiloAddress;\n                                if (ForwardingAddress is { } address)\n                                {\n                                    DeactivationReason = new(DeactivationReasonCode.DuplicateActivation,\n                                        $\"This grain is active on another host ({address}).\");\n                                }\n\n                                success = false;\n                                CatalogInstruments.ActivationConcurrentRegistrationAttempts.Add(1);\n                                LogDuplicateActivation(\n                                    _shared.Logger,\n                                    Address,\n                                    ForwardingAddress,\n                                    GrainInstance?.GetType(),\n                                    new(Address),\n                                    WaitingCount);\n                                _activationActivity?.AddEvent(new ActivityEvent(\"duplicate-activation\"));\n                                registerSpan?.AddEvent(new ActivityEvent(\"duplicate\"));\n                                if (ForwardingAddress is { } fwd)\n                                {\n                                    registerSpan?.SetTag(ActivityTagKeys.DirectoryForwardingAddress, fwd.ToString());\n                                }\n                            }\n\n                            break;\n                        }\n\n                        registrationException = null;\n                    }\n                    catch (Exception exception)\n                    {\n                        registrationException = exception;\n                        if (!cancellationToken.IsCancellationRequested)\n                        {\n                            LogFailedToRegisterGrain(_shared.Logger, registrationException, this);\n                        }\n\n                        success = false;\n                        _activationActivity?.AddEvent(new ActivityEvent(\"directory-register-failed\"));\n                        SetActivityError(registerSpan, exception, ActivityErrorEvents.DirectoryRegisterFailed);\n                    }\n\n                }\n                if (!success)\n                {\n                    Deactivate(new(DeactivationReasonCode.DirectoryFailure, registrationException, \"Failed to register activation in grain directory.\"));\n\n                    // Activation failed.\n                    if (registrationException is not null)\n                    {\n                        SetActivityError(_activationActivity, registrationException, ActivityErrorEvents.ActivationCancelled);\n                    }\n                    else\n                    {\n                        SetActivityError(_activationActivity, ActivityErrorEvents.ActivationCancelled);\n                    }\n\n                    return;\n                }\n            }\n\n            lock (this)\n            {\n                SetState(ActivationState.Activating);\n            }\n            _activationActivity?.AddEvent(new ActivityEvent(\"state-activating\"));\n\n            LogActivatingGrain(_shared.Logger, this);\n\n            try\n            {\n                RequestContextExtensions.Import(requestContextData);\n                try\n                {\n                    if (_lifecycle is { } lifecycle)\n                    {\n                        _activationActivity?.AddEvent(new ActivityEvent(\"lifecycle-start\"));\n                        await lifecycle.OnStart(cancellationToken).WaitAsync(cancellationToken);\n                        _activationActivity?.AddEvent(new ActivityEvent(\"lifecycle-started\"));\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorStartingLifecycle(_shared.Logger, exception, this);\n                    _activationActivity?.AddEvent(new ActivityEvent(\"lifecycle-start-failed\"));\n                    throw;\n                }\n\n                if (GrainInstance is IGrainBase grainBase)\n                {\n                    // Start a span for OnActivateAsync execution\n                    using var onActivateSpan = _activationActivity is not null\n                        ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.OnActivate, ActivityKind.Internal, _activationActivity.Context)\n                        : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.OnActivate, ActivityKind.Internal);\n                    if (onActivateSpan is { IsAllDataRequested: true })\n                    {\n                        onActivateSpan.SetTag(ActivityTagKeys.GrainId, GrainId.ToString());\n                        onActivateSpan.SetTag(ActivityTagKeys.GrainType, _shared.GrainTypeName ?? GrainInstance.GetType().FullName);\n                        onActivateSpan.SetTag(ActivityTagKeys.SiloId, _shared.Runtime.SiloAddress.ToString());\n                        onActivateSpan.SetTag(ActivityTagKeys.ActivationId, ActivationId.ToString());\n                    }\n\n                    try\n                    {\n                        await grainBase.OnActivateAsync(cancellationToken).WaitAsync(cancellationToken);\n                    }\n                    catch (Exception exception)\n                    {\n                        if (cancellationToken.IsCancellationRequested && exception is ObjectDisposedException or OperationCanceledException)\n                        {\n                            CatalogInstruments.ActivationFailedToActivate.Add(1);\n\n                            // This captures the case where user code in OnActivateAsync doesn't use the passed cancellation token\n                            // and makes a call that tries to resolve the scoped IServiceProvider or other type that has been disposed because of cancellation,\n                            // or a direct OperationCanceledException from cancellation.\n                            if (exception is ObjectDisposedException ode)\n                            {\n                                LogActivationDisposedObjectAccessed(_shared.Logger, ode.ObjectName, this);\n                                Deactivate(\n                                    new(DeactivationReasonCode.RuntimeRequested, ode,\n                                        $\"Disposed object {ode.ObjectName} referenced after cancellation of activation was requested.\"),\n                                    CancellationToken.None);\n                            }\n                            else\n                            {\n                                Deactivate(\n                                    new(DeactivationReasonCode.RuntimeRequested, exception,\n                                        \"Activation was cancelled by the runtime.\"), CancellationToken.None);\n                            }\n\n                            SetActivityError(_activationActivity, exception, ActivityErrorEvents.ActivationCancelled);\n                            LogActivationCancelled(_shared.Logger, this, cancellationToken.IsCancellationRequested,\n                                DeactivationReason.ReasonCode, DeactivationReason.Description, ForwardingAddress);\n                            _activationActivity?.Dispose();\n                            _activationActivity = null;\n                            return;\n                        }\n\n                        LogErrorInGrainMethod(_shared.Logger, exception, nameof(IGrainBase.OnActivateAsync), this);\n                        SetActivityError(onActivateSpan, exception, ActivityErrorEvents.OnActivateFailed);\n                        throw;\n                    }\n                }\n\n                lock (this)\n                {\n                    if (State is ActivationState.Activating)\n                    {\n                        SetState(ActivationState.Valid);\n                        _shared.InternalRuntime.ActivationWorkingSet.OnActivated(this);\n                    }\n                }\n                _activationActivity?.AddEvent(new ActivityEvent(\"state-valid\"));\n                _activationActivity?.Dispose();\n                _activationActivity = null;\n\n                LogFinishedActivatingGrain(_shared.Logger, this);\n            }\n            catch (Exception exception)\n            {\n                CatalogInstruments.ActivationFailedToActivate.Add(1);\n                var sourceException = (exception as OrleansLifecycleCanceledException)?.InnerException ?? exception;\n                LogErrorActivatingGrain(_shared.Logger, sourceException, this);\n                if (!cancellationToken.IsCancellationRequested)\n                {\n                    ScheduleOperation(new Command.Delay(TimeSpan.FromSeconds(5)));\n                }\n                Deactivate(new(DeactivationReasonCode.ActivationFailed, sourceException, \"Failed to activate grain.\"), CancellationToken.None);\n                SetActivityError(_activationActivity, ActivityErrorEvents.ActivationFailed);\n                _activationActivity?.Dispose();\n                _activationActivity = null;\n                return;\n            }\n        }\n        catch (Exception exception)\n        {\n            LogActivationFailed(_shared.Logger, exception, this);\n            Deactivate(new(DeactivationReasonCode.ApplicationError, exception, \"Failed to activate grain.\"), CancellationToken.None);\n            SetActivityError(_activationActivity, ActivityErrorEvents.ActivationError);\n            _activationActivity?.Dispose();\n            _activationActivity = null;\n        }\n        finally\n        {\n            _workSignal.Signal();\n        }\n    }\n\n    private void SetActivityError(Activity? erroredActivity, string? errorEventName)\n    {\n        if (erroredActivity is { } activity)\n        {\n            activity.SetStatus(ActivityStatusCode.Error, errorEventName);\n        }\n    }\n\n    private void SetActivityError(Activity? erroredActivity, Exception exception, string? errorEventName)\n    {\n        if (erroredActivity is { } activity)\n        {\n            activity.SetStatus(ActivityStatusCode.Error, errorEventName);\n            activity.SetTag(ActivityTagKeys.ExceptionType, exception.GetType().FullName);\n            activity.SetTag(ActivityTagKeys.ExceptionMessage, exception.Message);\n        }\n    }\n\n    #endregion\n\n    #region Deactivation\n\n    /// <summary>\n    /// Completes the deactivation process.\n    /// </summary>\n    private async Task FinishDeactivating(Command.Deactivate deactivateCommand, CancellationToken cancellationToken)\n    {\n        using var _ = deactivateCommand.Activity;\n\n        var migrating = false;\n        var encounteredError = false;\n        try\n        {\n            LogCompletingDeactivation(_shared.Logger, this);\n\n            // Stop timers from firing.\n            DisposeTimers();\n\n            // If the grain was valid when deactivation started, call OnDeactivateAsync.\n            if (deactivateCommand.PreviousState == ActivationState.Valid)\n            {\n                if (GrainInstance is IGrainBase grainBase)\n                {\n                    // Start a span for OnActivateAsync execution\n                    \n                    using var onDeactivateSpan = deactivateCommand.Activity is not null\n                        ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.OnDeactivate, ActivityKind.Internal, parentContext:deactivateCommand.Activity.Context)\n                        : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.OnDeactivate, ActivityKind.Internal);\n                    if (onDeactivateSpan is { IsAllDataRequested: true })\n                    {\n                        onDeactivateSpan.SetTag(ActivityTagKeys.GrainId, GrainId.ToString());\n                        onDeactivateSpan.SetTag(ActivityTagKeys.GrainType, _shared.GrainTypeName ?? GrainInstance.GetType().FullName);\n                        onDeactivateSpan.SetTag(ActivityTagKeys.SiloId, _shared.Runtime.SiloAddress.ToString());\n                        onDeactivateSpan.SetTag(ActivityTagKeys.ActivationId, ActivationId.ToString());\n                        onDeactivateSpan.SetTag(ActivityTagKeys.DeactivationReason, DeactivationReason.ToString());\n                    }\n\n                    try\n                    {\n                        LogBeforeOnDeactivateAsync(_shared.Logger, this);\n\n                        await grainBase.OnDeactivateAsync(DeactivationReason, cancellationToken).WaitAsync(cancellationToken);\n\n                        LogAfterOnDeactivateAsync(_shared.Logger, this);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorInGrainMethod(_shared.Logger, exception, nameof(IGrainBase.OnDeactivateAsync), this);\n                        SetActivityError(onDeactivateSpan, exception, ActivityErrorEvents.OnDeactivateFailed);\n\n                        // Swallow the exception and continue with deactivation.\n                        encounteredError = true;\n                    }\n                }\n            }\n\n            try\n            {\n                if (_lifecycle is { } lifecycle)\n                {\n                    // Stops the lifecycle stages which were previously started.\n                    // Stages which were never started are ignored.\n                    await lifecycle.OnStop(cancellationToken).WaitAsync(cancellationToken);\n                }\n            }\n            catch (Exception exception)\n            {\n                LogErrorStartingLifecycle(_shared.Logger, exception, this);\n\n                // Swallow the exception and continue with deactivation.\n                encounteredError = true;\n            }\n\n            if (!encounteredError\n                && DehydrationContext is { } context\n                && _shared.MigrationManager is { } migrationManager\n                && !cancellationToken.IsCancellationRequested)\n            {\n                migrating = await StartMigrationAsync(context, migrationManager, cancellationToken);\n            }\n\n            // If the instance is being deactivated due to a directory failure, we should not unregister it.\n            var isDirectoryFailure = DeactivationReason.ReasonCode is DeactivationReasonCode.DirectoryFailure;\n            var isShuttingDown = DeactivationReason.ReasonCode is DeactivationReasonCode.ShuttingDown;\n\n            if (!migrating && IsUsingGrainDirectory && !cancellationToken.IsCancellationRequested && !isDirectoryFailure && !isShuttingDown)\n            {\n                // Unregister from directory.\n                // If the grain was migrated, the new activation will perform a check-and-set on the registration itself.\n                try\n                {\n                    await _shared.InternalRuntime.GrainLocator.Unregister(Address, UnregistrationCause.Force).WaitAsync(cancellationToken);\n                }\n                catch (Exception exception)\n                {\n                    if (!cancellationToken.IsCancellationRequested)\n                    {\n                        LogFailedToUnregisterActivation(_shared.Logger, exception, this);\n                    }\n                }\n            }\n            else if (isDirectoryFailure)\n            {\n                // Optimization: forward to the same host to restart activation without needing to invalidate caches.\n                ForwardingAddress ??= Address.SiloAddress;\n            }\n        }\n        catch (Exception ex)\n        {\n            SetActivityError(deactivateCommand.Activity, ex, \"Error in FinishDeactivating\");\n            LogErrorDeactivating(_shared.Logger, ex, this);\n        }\n\n        if (IsStuckDeactivating)\n        {\n            CatalogInstruments.ActivationShutdownViaDeactivateStuckActivation();\n        }\n        else if (migrating)\n        {\n            CatalogInstruments.ActivationShutdownViaMigration();\n        }\n        else if (_isInWorkingSet)\n        {\n            CatalogInstruments.ActivationShutdownViaDeactivateOnIdle();\n        }\n        else\n        {\n            CatalogInstruments.ActivationShutdownViaCollection();\n        }\n\n        UnregisterMessageTarget();\n\n        try\n        {\n            await DisposeAsync();\n        }\n        catch (Exception exception)\n        {\n            SetActivityError(deactivateCommand.Activity, exception, \"Error in FinishDeactivating\");\n            LogExceptionDisposing(_shared.Logger, exception, this);\n        }\n\n        // Signal deactivation\n        GetDeactivationCompletionSource().TrySetResult(true);\n        _workSignal.Signal();\n\n        async ValueTask<bool> StartMigrationAsync(DehydrationContextHolder context, IActivationMigrationManager migrationManager, CancellationToken cancellationToken)\n        {\n            try\n            {\n                if (ForwardingAddress is null)\n                {\n                    var selectedAddress = await PlaceMigratingGrainAsync(context.RequestContext, cancellationToken);\n                    if (selectedAddress is null)\n                    {\n                        return false;\n                    }\n\n                    ForwardingAddress = selectedAddress;\n                }\n\n                // Populate the dehydration context.\n                if (context.RequestContext is { } requestContext)\n                {\n                    RequestContextExtensions.Import(requestContext);\n                }\n\n                OnDehydrate(context.MigrationContext);\n\n                // Send the dehydration context to the target host.\n                await migrationManager.MigrateAsync(ForwardingAddress, GrainId, context.MigrationContext).AsTask().WaitAsync(cancellationToken);\n                _shared.InternalRuntime.GrainLocator.UpdateCache(GrainId, ForwardingAddress);\n                return true;\n            }\n            catch (Exception exception)\n            {\n                LogFailedToMigrateActivation(_shared.Logger, exception, this);\n                return false;\n            }\n        }\n    }\n\n    private TaskCompletionSource<bool> GetDeactivationCompletionSource()\n    {\n        lock (this)\n        {\n            _extras ??= new();\n            return _extras.DeactivationTask ??= new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n        }\n    }\n\n    ValueTask IGrainManagementExtension.DeactivateOnIdle()\n    {\n        Deactivate(new(DeactivationReasonCode.ApplicationRequested, $\"{nameof(IGrainManagementExtension.DeactivateOnIdle)} was called.\"), CancellationToken.None);\n        return default;\n    }\n\n    async ValueTask IGrainManagementExtension.MigrateOnIdle()\n    {\n        var requestContextData = RequestContext.CallContextData?.Value.Values;\n        var selectedAddress = await PlaceMigratingGrainAsync(requestContextData, CancellationToken.None);\n        if (selectedAddress is null)\n        {\n            return;\n        }\n\n        // Only migrate if a different silo was selected.\n        ForwardingAddress = selectedAddress;\n        LogDebugMigrating(_shared.Logger, GrainId, ForwardingAddress);\n        Migrate(requestContextData, cancellationToken: CancellationToken.None);\n    }\n\n    private async ValueTask<SiloAddress?> PlaceMigratingGrainAsync(Dictionary<string, object>? requestContextData, CancellationToken cancellationToken)\n    {\n        try\n        {\n            var placementService = _shared.Runtime.ServiceProvider.GetRequiredService<PlacementService>();\n            var selectedAddress = await placementService.PlaceGrainAsync(GrainId, requestContextData, PlacementStrategy);\n\n            if (selectedAddress is null)\n            {\n                // No appropriate silo was selected for this grain.\n                LogDebugPlacementStrategyFailedToSelectDestination(_shared.Logger, PlacementStrategy, GrainId);\n                return null;\n            }\n            else if (selectedAddress.Equals(_shared.Runtime.SiloAddress))\n            {\n                // This could be because this is the only (compatible) silo for the grain or because the placement director chose this\n                // silo for some other reason.\n                LogDebugPlacementStrategySelectedCurrentSilo(_shared.Logger, PlacementStrategy, GrainId);\n                return null;\n            }\n\n            return selectedAddress;\n        }\n        catch (Exception exception)\n        {\n            LogErrorSelectingMigrationDestination(_shared.Logger, exception, GrainId);\n            return null;\n        }\n    }\n\n    private void UnregisterMessageTarget()\n    {\n        _shared.InternalRuntime.Catalog.UnregisterMessageTarget(this);\n    }\n\n    void ICallChainReentrantGrainContext.OnEnterReentrantSection(Guid reentrancyId)\n    {\n        var tracker = GetComponent<ReentrantRequestTracker>();\n        if (tracker is null)\n        {\n            tracker = new ReentrantRequestTracker();\n            SetComponent(tracker);\n        }\n\n        tracker.EnterReentrantSection(reentrancyId);\n    }\n\n    void ICallChainReentrantGrainContext.OnExitReentrantSection(Guid reentrancyId)\n    {\n        var tracker = GetComponent<ReentrantRequestTracker>();\n        if (tracker is null)\n        {\n            throw new InvalidOperationException(\"Attempted to exit reentrant section without entering it.\");\n        }\n\n        tracker.LeaveReentrantSection(reentrancyId);\n    }\n\n    private bool IsReentrantSection(Guid reentrancyId)\n    {\n        if (reentrancyId == Guid.Empty)\n        {\n            return false;\n        }\n\n        var tracker = GetComponent<ReentrantRequestTracker>();\n        if (tracker is null)\n        {\n            return false;\n        }\n\n        return tracker.IsReentrantSectionActive(reentrancyId);\n    }\n\n    ValueTask IGrainCallCancellationExtension.CancelRequestAsync(GrainId senderGrainId, CorrelationId messageId)\n        => this.RunOrQueueTask(static state => state.self.CancelRequestAsyncCore(state.senderGrainId, state.messageId), (self: this, senderGrainId, messageId));\n\n    private ValueTask CancelRequestAsyncCore(GrainId senderGrainId, CorrelationId messageId)\n    {\n        if (!TryCancelRequest())\n        {\n            // The message being canceled may not have arrived yet, so retry a few times.\n            return RetryCancellationAfterDelay();\n        }\n\n        return ValueTask.CompletedTask;\n\n        async ValueTask RetryCancellationAfterDelay()\n        {\n            var attemptsRemaining = 3;\n            do\n            {\n                await Task.Delay(1_000);\n            } while (!TryCancelRequest() && --attemptsRemaining > 0);\n        }\n\n        bool TryCancelRequest()\n        {\n            Message? message = null;\n            var wasWaiting = false;\n            lock (this)\n            {\n                // Check the running requests.\n                foreach (var candidate in _runningRequests.Keys)\n                {\n                    if (candidate.Id == messageId && candidate.SendingGrain == senderGrainId)\n                    {\n                        message = candidate;\n                        break;\n                    }\n                }\n\n                if (message is null)\n                {\n                    // Check the waiting requests.\n                    for (var i = 0; i < _waitingRequests.Count; i++)\n                    {\n                        var candidate = _waitingRequests[i].Message;\n                        if (candidate.Id == messageId && candidate.SendingGrain == senderGrainId)\n                        {\n                            message = candidate;\n                            _waitingRequests.RemoveAt(i);\n                            wasWaiting = true;\n                            break;\n                        }\n                    }\n                }\n            }\n\n            var didCancel = false;\n            if (message is not null && message.BodyObject is IInvokable request)\n            {\n                if (wasWaiting)\n                {\n                    // If the request was waiting, then we necessarily did manage to cancel it, so send the response now.\n                    _shared.InternalRuntime.RuntimeClient.SendResponse(message, Response.FromException(new OperationCanceledException()));\n                    didCancel = true;\n                }\n                else\n                {\n                    didCancel = TryCancelInvokable(request) || !request.IsCancellable;\n                }\n            }\n\n            return didCancel;\n        }\n\n        bool TryCancelInvokable(IInvokable request)\n        {\n            try\n            {\n                return request.TryCancel();\n            }\n            catch (Exception exception)\n            {\n                LogErrorCancellationCallbackFailed(Shared.Logger, exception);\n                return true;\n            }\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"One or more cancellation callbacks failed.\"\n    )]\n    private static partial void LogErrorCancellationCallbackFailed(ILogger logger, Exception exception);\n\n    #endregion\n\n    /// <summary>\n    /// Additional properties which are not needed for the majority of an activation's lifecycle.\n    /// </summary>\n    private class ActivationDataExtra : Dictionary<object, object>\n    {\n        private const int IsStuckProcessingMessageFlag = 1 << 0;\n        private const int IsStuckDeactivatingFlag = 1 << 1;\n        private const int IsDisposingFlag = 1 << 2;\n        private byte _flags;\n\n        public HashSet<IGrainTimer>? Timers { get => GetValueOrDefault<HashSet<IGrainTimer>>(nameof(Timers)); set => SetOrRemoveValue(nameof(Timers), value); }\n\n        /// <summary>\n        /// During rehydration, this may contain the address for the previous (recently dehydrated) activation of this grain.\n        /// </summary>\n        public GrainAddress? PreviousRegistration { get => GetValueOrDefault<GrainAddress>(nameof(PreviousRegistration)); set => SetOrRemoveValue(nameof(PreviousRegistration), value); }\n\n        /// <summary>\n        /// If State == Invalid, this may contain a forwarding address for incoming messages\n        /// </summary>\n        public SiloAddress? ForwardingAddress { get => GetValueOrDefault<SiloAddress>(nameof(ForwardingAddress)); set => SetOrRemoveValue(nameof(ForwardingAddress), value); }\n\n        /// <summary>\n        /// A <see cref=\"TaskCompletionSource{TResult}\"/> which completes when a grain has deactivated.\n        /// </summary>\n        public TaskCompletionSource<bool>? DeactivationTask { get => GetDeactivationInfoOrDefault()?.DeactivationTask; set => EnsureDeactivationInfo().DeactivationTask = value; }\n\n        public DateTime? DeactivationStartTime { get => GetDeactivationInfoOrDefault()?.DeactivationStartTime; set => EnsureDeactivationInfo().DeactivationStartTime = value; }\n\n        public DeactivationReason DeactivationReason { get => GetDeactivationInfoOrDefault()?.DeactivationReason ?? default; set => EnsureDeactivationInfo().DeactivationReason = value; }\n\n        /// <summary>\n        /// When migrating to another location, this contains the information to preserve across activations.\n        /// </summary>\n        public DehydrationContextHolder? DehydrationContext { get => GetValueOrDefault<DehydrationContextHolder>(nameof(DehydrationContext)); set => SetOrRemoveValue(nameof(DehydrationContext), value); }\n\n        private DeactivationInfo? GetDeactivationInfoOrDefault() => GetValueOrDefault<DeactivationInfo>(nameof(DeactivationInfo));\n        private DeactivationInfo EnsureDeactivationInfo()\n        {\n            ref var info = ref CollectionsMarshal.GetValueRefOrAddDefault(this, nameof(DeactivationInfo), out _);\n            info ??= new DeactivationInfo();\n            return (DeactivationInfo)info;\n        }\n\n        public bool IsStuckProcessingMessage { get => GetFlag(IsStuckProcessingMessageFlag); set => SetFlag(IsStuckProcessingMessageFlag, value); }\n        public bool IsStuckDeactivating { get => GetFlag(IsStuckDeactivatingFlag); set => SetFlag(IsStuckDeactivatingFlag, value); }\n        public bool IsDisposing { get => GetFlag(IsDisposingFlag); set => SetFlag(IsDisposingFlag, value); }\n\n        private void SetFlag(int flag, bool value)\n        {\n            if (value)\n            {\n                _flags |= (byte)flag;\n            }\n            else\n            {\n                _flags &= (byte)~flag;\n            }\n        }\n\n        private bool GetFlag(int flag) => (_flags & flag) != 0;\n        private T? GetValueOrDefault<T>(object key)\n        {\n            TryGetValue(key, out var result);\n            return (T?)result;\n        }\n\n        private void SetOrRemoveValue(object key, object? value)\n        {\n            if (value is null)\n            {\n                Remove(key);\n            }\n            else\n            {\n                base[key] = value;\n            }\n        }\n\n        private sealed class DeactivationInfo\n        {\n            public DateTime? DeactivationStartTime;\n            public DeactivationReason DeactivationReason;\n            public TaskCompletionSource<bool>? DeactivationTask;\n        }\n    }\n\n    private abstract class Command(CancellationTokenSource cts) : IDisposable\n    {\n        private bool _disposed;\n        private readonly CancellationTokenSource _cts = cts;\n        public CancellationToken CancellationToken => _cts.Token;\n\n        public virtual void Cancel()\n        {\n            lock (this)\n            {\n                if (_disposed) return;\n                _cts.Cancel();\n            }\n        }\n\n        public virtual void Dispose()\n        {\n            try\n            {\n                lock (this)\n                {\n                    _disposed = true;\n                    _cts.Dispose();\n                }\n            }\n            catch\n            {\n                // Ignore.\n            }\n\n            GC.SuppressFinalize(this);\n        }\n\n        public sealed class Deactivate(CancellationTokenSource cts, ActivationState previousState, Activity? activity) : Command(cts)\n        {\n            public ActivationState PreviousState { get; } = previousState;\n            public Activity? Activity { get; } = activity;\n        }\n\n        public sealed class Activate(Dictionary<string, object>? requestContext, CancellationTokenSource cts) : Command(cts)\n        {\n            public Dictionary<string, object>? RequestContext { get; } = requestContext;\n        }\n\n        public sealed class Rehydrate(IRehydrationContext context) : Command(new())\n        {\n            public readonly IRehydrationContext Context = context;\n\n            public override void Dispose()\n            {\n                base.Dispose();\n                (Context as IDisposable)?.Dispose();\n            }\n        }\n\n        public sealed class Delay(TimeSpan duration) : Command(new())\n        {\n            public TimeSpan Duration { get; } = duration;\n        }\n    }\n\n    internal class ReentrantRequestTracker : Dictionary<Guid, int>\n    {\n        public void EnterReentrantSection(Guid reentrancyId)\n        {\n            Debug.Assert(reentrancyId != Guid.Empty);\n            ref var count = ref CollectionsMarshal.GetValueRefOrAddDefault(this, reentrancyId, out _);\n            ++count;\n        }\n\n        public void LeaveReentrantSection(Guid reentrancyId)\n        {\n            Debug.Assert(reentrancyId != Guid.Empty);\n            ref var count = ref CollectionsMarshal.GetValueRefOrNullRef(this, reentrancyId);\n            if (Unsafe.IsNullRef(ref count))\n            {\n                return;\n            }\n\n            if (--count <= 0)\n            {\n                Remove(reentrancyId);\n            }\n        }\n\n        public bool IsReentrantSectionActive(Guid reentrancyId)\n        {\n            Debug.Assert(reentrancyId != Guid.Empty);\n            return TryGetValue(reentrancyId, out var count) && count > 0;\n        }\n    }\n\n    private class DehydrationContextHolder(SerializerSessionPool sessionPool, Dictionary<string, object>? requestContext)\n    {\n        public readonly MigrationContext MigrationContext = new(sessionPool);\n        public readonly Dictionary<string, object>? RequestContext = requestContext;\n        \n        /// <summary>\n        /// The activity context from the grain call that initiated the migration.\n        /// This is used to parent the dehydrate span to the migration request trace.\n        /// </summary>\n        public ActivityContext? MigrationActivityContext { get; set; } = Activity.Current?.Context;\n    }\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_Reject_ActivationTooManyRequests,\n        Level = LogLevel.Warning,\n        Message = \"Overload - {Count} enqueued requests for activation {Activation}, exceeding hard limit rejection threshold of {HardLimit}\"\n    )]\n    private static partial void LogRejectActivationTooManyRequests(ILogger logger, int count, ActivationData activation, int hardLimit);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_Warn_ActivationTooManyRequests,\n        Level = LogLevel.Warning,\n        Message = \"Hot - {Count} enqueued requests for activation {Activation}, exceeding soft limit warning threshold of {SoftLimit}\"\n    )]\n    private static partial void LogWarnActivationTooManyRequests(ILogger logger, int count, ActivationData activation, int softLimit);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error while cancelling on-going operation '{Operation}'.\"\n    )]\n    private static partial void LogErrorCancellingOperation(ILogger logger, Exception exception, object operation);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Migrating {GrainId} to {SiloAddress}\"\n    )]\n    private static partial void LogDebugMigrating(ILogger logger, GrainId grainId, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error while selecting a migration destination for {GrainId}\"\n    )]\n    private static partial void LogErrorSelectingMigrationDestination(ILogger logger, Exception exception, GrainId grainId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Placement strategy {PlacementStrategy} failed to select a destination for migration of {GrainId}\"\n    )]\n    private static partial void LogDebugPlacementStrategyFailedToSelectDestination(ILogger logger, PlacementStrategy placementStrategy, GrainId grainId);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Placement strategy {PlacementStrategy} selected the current silo as the destination for migration of {GrainId}\"\n    )]\n    private static partial void LogDebugPlacementStrategySelectedCurrentSilo(ILogger logger, PlacementStrategy placementStrategy, GrainId grainId);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error invoking MayInterleave predicate on grain {Grain} for message {Message}\"\n    )]\n    private static partial void LogErrorInvokingMayInterleavePredicate(ILogger logger, Exception exception, ActivationData grain, Message message);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error in ProcessOperationsAsync for grain activation '{Activation}'.\"\n    )]\n    private static partial void LogErrorInProcessOperationsAsync(ILogger logger, Exception exception, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Rehydrating grain '{GrainContext}' from previous activation.\"\n    )]\n    private static partial void LogRehydratingGrain(ILogger logger, ActivationData grainContext);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Ignoring attempt to rehydrate grain '{GrainContext}' in the '{State}' state.\"\n    )]\n    private static partial void LogIgnoringRehydrateAttempt(ILogger logger, ActivationData grainContext, ActivationState state);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Previous activation address was {PreviousRegistration}\"\n    )]\n    private static partial void LogPreviousActivationAddress(ILogger logger, GrainAddress previousRegistration);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Rehydrated grain from previous activation\"\n    )]\n    private static partial void LogRehydratedGrain(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error while rehydrating activation\"\n    )]\n    private static partial void LogErrorRehydratingActivation(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Dehydrating grain activation\"\n    )]\n    private static partial void LogDehydratingActivation(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Dehydrated grain activation\"\n    )]\n    private static partial void LogDehydratedActivation(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error while dehydrating activation\"\n    )]\n    private static partial void LogErrorDehydratingActivation(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_RerouteAllQueuedMessages,\n        Level = LogLevel.Debug,\n        Message = \"Rejecting {Count} messages from invalid activation {Activation}.\"\n    )]\n    private static partial void LogRejectAllQueuedMessages(ILogger logger, int count, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Registering grain '{Grain}' in activation directory. Previous known registration is '{PreviousRegistration}'.\")]\n    private static partial void LogRegisteringGrain(ILogger logger, ActivationData grain, GrainAddress? previousRegistration);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"The grain directory has an existing entry pointing to a different activation of this grain, '{GrainId}', on this silo: '{PreviousRegistration}'.\"\n            + \" This may indicate that the previous activation was deactivated but the directory was not successfully updated.\"\n            + \" The directory will be updated to point to this activation.\"\n    )]\n    private static partial void LogAttemptToRegisterWithPreviousActivation(ILogger logger, GrainId grainId, GrainAddress previousRegistration);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Dispatcher_ExtendedMessageProcessing,\n        Level = LogLevel.Warning,\n        Message = \"Current request has been active for {CurrentRequestActiveTime} for grain {Grain}. Currently executing {BlockingRequest}. Trying to enqueue {Message}.\")]\n    private static partial void LogWarningDispatcher_ExtendedMessageProcessing(\n        ILogger logger,\n        TimeSpan currentRequestActiveTime,\n        ActivationDataLogValue grain,\n        Message blockingRequest,\n        Message message);\n\n    private readonly struct ActivationDataLogValue(ActivationData activation, bool includeExtraDetails = false)\n    {\n        public override string ToString() => activation.ToDetailedString(includeExtraDetails);\n    }\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Runtime_Error_100064,\n        Level = LogLevel.Warning,\n        Message = \"Failed to register grain {Grain} in grain directory\")]\n    private static partial void LogFailedToRegisterGrain(ILogger logger, Exception exception, ActivationData grain);\n\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Ignoring activation request for {Grain} because this grain is in the '{State}' state\")]\n    private static partial void LogIgnoringActivateAttempt(ILogger logger, ActivationData grain, ActivationState state);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_BeforeCallingActivate,\n        Level = LogLevel.Debug,\n        Message = \"Activating grain {Grain}\")]\n    private static partial void LogActivatingGrain(ILogger logger, ActivationData grain);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error starting lifecycle for activation '{Activation}'\")]\n    private static partial void LogErrorStartingLifecycle(ILogger logger, Exception exception, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error thrown from {MethodName} for activation '{Activation}'\")]\n    private static partial void LogErrorInGrainMethod(ILogger logger, Exception exception, string methodName, ActivationData activation);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_AfterCallingActivate,\n        Level = LogLevel.Debug,\n        Message = \"Finished activating grain {Grain}\")]\n    private static partial void LogFinishedActivatingGrain(ILogger logger, ActivationData grain);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_ErrorCallingActivate,\n        Level = LogLevel.Error,\n        Message = \"Error activating grain {Grain}\")]\n    private static partial void LogErrorActivatingGrain(ILogger logger, Exception exception, ActivationData grain);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_DisposedObjectAccess,\n        Level = LogLevel.Warning,\n        Message = \"Disposed object {ObjectName} accessed in OnActivateAsync for grain {Grain}. Ensure the cancellationToken is passed to all async methods or they have .WaitAsync(cancellationToken) called on them.\")]\n    private static partial void LogActivationDisposedObjectAccessed(ILogger logger, string objectName, ActivationData grain);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_CancelledActivate,\n        Level = LogLevel.Information,\n        Message = \"Activation was cancelled for {Grain}. CancellationRequested={CancellationRequested}, DeactivationReasonCode={DeactivationReasonCode}, DeactivationReason={DeactivationReason}, ForwardingAddress={ForwardingAddress}\"\n    )]\n    private static partial void LogActivationCancelled(ILogger logger, ActivationData grain, bool cancellationRequested, DeactivationReasonCode deactivationReasonCode, string? deactivationReason, SiloAddress? forwardingAddress);\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Completing deactivation of '{Activation}'\")]\n    private static partial void LogCompletingDeactivation(ILogger logger, ActivationData activation);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_BeforeCallingDeactivate,\n        Level = LogLevel.Debug,\n        Message = \"About to call OnDeactivateAsync for '{Activation}'\")]\n    private static partial void LogBeforeOnDeactivateAsync(ILogger logger, ActivationData activation);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_AfterCallingDeactivate,\n        Level = LogLevel.Debug,\n        Message = \"Returned from calling '{Activation}' OnDeactivateAsync method\")]\n    private static partial void LogAfterOnDeactivateAsync(ILogger logger, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failed to unregister activation '{Activation}' from directory\")]\n    private static partial void LogFailedToUnregisterActivation(ILogger logger, Exception exception, ActivationData activation);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_DeactivateActivation_Exception,\n        Level = LogLevel.Warning,\n        Message = \"Error deactivating '{Activation}'\")]\n    private static partial void LogErrorDeactivating(ILogger logger, Exception exception, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Exception disposing activation '{Activation}'\")]\n    private static partial void LogExceptionDisposing(ILogger logger, Exception exception, ActivationData activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to migrate activation '{Activation}'\")]\n    private static partial void LogFailedToMigrateActivation(ILogger logger, Exception exception, ActivationData activation);\n\n    private readonly struct FullAddressLogRecord(GrainAddress address)\n    {\n        public override string ToString() => address.ToFullString();\n    }\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_DuplicateActivation,\n        Level = LogLevel.Debug,\n        Message = \"Tried to create a duplicate activation {Address}, but we'll use {ForwardingAddress} instead. GrainInstance type is {GrainInstanceType}. Full activation address is {FullAddress}. We have {WaitingCount} messages to forward\")]\n    private static partial void LogDuplicateActivation(\n        ILogger logger,\n        GrainAddress address,\n        SiloAddress? forwardingAddress,\n        Type? grainInstanceType,\n        FullAddressLogRecord fullAddress,\n        int waitingCount);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_RerouteAllQueuedMessages,\n        Level = LogLevel.Debug,\n        Message = \"Rerouting {NumMessages} messages from invalid grain activation {Grain} to {ForwardingAddress}\")]\n    private static partial void LogReroutingMessages(ILogger logger, int numMessages, ActivationData grain, SiloAddress forwardingAddress);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Catalog_RerouteAllQueuedMessages,\n        Level = LogLevel.Debug,\n        Message = \"Rerouting {NumMessages} messages from invalid grain activation {Grain}\")]\n    private static partial void LogReroutingMessagesNoForwarding(ILogger logger, int numMessages, ActivationData grain);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Activation of grain {Grain} failed\")]\n    private static partial void LogActivationFailed(ILogger logger, Exception exception, ActivationData grain);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime;\n\ninternal sealed class ActivationDirectory : IEnumerable<KeyValuePair<GrainId, IGrainContext>>, IAsyncDisposable, IDisposable\n{\n    private int _activationsCount;\n\n    private readonly ConcurrentDictionary<GrainId, IGrainContext> _activations = new();\n\n    public ActivationDirectory()\n    {\n        CatalogInstruments.RegisterActivationCountObserve(() => Count);\n    }\n\n    public int Count => _activationsCount;\n\n    public IGrainContext? FindTarget(GrainId key)\n    {\n        _activations.TryGetValue(key, out var result);\n        return result;\n    }\n\n    public void RecordNewTarget(IGrainContext target)\n    {\n        if (_activations.TryAdd(target.GrainId, target))\n        {\n            Interlocked.Increment(ref _activationsCount);\n        }\n    }\n\n    public bool RemoveTarget(IGrainContext target)\n    {\n        if (_activations.TryRemove(KeyValuePair.Create(target.GrainId, target)))\n        {\n            Interlocked.Decrement(ref _activationsCount);\n            return true;\n        }\n\n        return false;\n    }\n\n    public IEnumerator<KeyValuePair<GrainId, IGrainContext>> GetEnumerator() => _activations.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    async ValueTask IAsyncDisposable.DisposeAsync()\n    {\n        var tasks = new List<Task>();\n        foreach (var (_, value) in _activations)\n        {\n            try\n            {\n                if (value is IAsyncDisposable asyncDisposable)\n                {\n                    tasks.Add(asyncDisposable.DisposeAsync().AsTask());\n                }\n                else if (value is IDisposable disposable)\n                {\n                    disposable.Dispose();\n                }\n            }\n            catch\n            {\n                // Ignore exceptions during disposal.\n            }\n        }\n\n        await Task.WhenAll(tasks).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n    }\n\n    void IDisposable.Dispose()\n    {\n        foreach (var (_, value) in _activations)\n        {\n            try\n            {\n                if (value is IDisposable disposable)\n                {\n                    disposable.Dispose();\n                }\n            }\n            catch\n            {\n                // Ignore exceptions during disposal.\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationMigrationManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing System.Threading.Tasks.Sources;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.ObjectPool;\nusing Orleans.Diagnostics;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Remote interface for migrating grain activations to a silo.\n/// </summary>\ninternal interface IActivationMigrationManagerSystemTarget : ISystemTarget\n{\n    /// <summary>\n    /// Accepts migrating grains on a best-effort basis.\n    /// </summary>\n    ValueTask AcceptMigratingGrains([Immutable] List<GrainMigrationPackage> migratingGrains);\n}\n\n[GenerateSerializer, Immutable]\ninternal struct GrainMigrationPackage\n{\n    [Id(0)]\n    public GrainId GrainId { get; set; }\n\n    [Id(1)]\n    public MigrationContext MigrationContext { get; set; }\n}\n\n/// <summary>\n/// Functionality for migrating an activation to a new location.\n/// </summary>\ninternal interface IActivationMigrationManager\n{\n    /// <summary>\n    /// Attempts to migrate a grain to the specified target.\n    /// </summary>\n    /// <param name=\"target\">The migration target.</param>\n    /// <param name=\"grainId\">The grain being migrated.</param>\n    /// <param name=\"migrationContext\">Information about the grain being migrated, which will be consumed by the new activation.</param>\n    ValueTask MigrateAsync(SiloAddress target, GrainId grainId, MigrationContext migrationContext);\n}\n\n/// <summary>\n/// Migrates grain activations to target hosts and handles migration requests from other hosts.\n/// </summary>\ninternal sealed partial class ActivationMigrationManager : SystemTarget, IActivationMigrationManagerSystemTarget, IActivationMigrationManager, ILifecycleParticipant<ISiloLifecycle>\n{\n    private const int MaxBatchSize = 1_000;\n    private readonly ConcurrentDictionary<SiloAddress, (Task PumpTask, Channel<MigrationWorkItem> WorkItemChannel)> _workers = new();\n    private readonly ObjectPool<MigrationWorkItem> _workItemPool = ObjectPool.Create(new MigrationWorkItem.ObjectPoolPolicy());\n    private readonly CancellationTokenSource _shuttingDownCts = new();\n    private readonly ILogger<ActivationMigrationManager> _logger;\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly Catalog _catalog;\n    private readonly IClusterMembershipService _clusterMembershipService;\n#if NET9_0_OR_GREATER\n    private readonly Lock _lock = new();\n#else\n    private readonly object _lock = new();\n#endif\n\n#pragma warning disable IDE0052 // Remove unread private members. Justification: this field is only for diagnostic purposes.\n    private readonly Task? _membershipUpdatesTask;\n#pragma warning restore IDE0052 // Remove unread private members\n\n    public ActivationMigrationManager(\n        ILocalSiloDetails localSiloDetails,\n        ILoggerFactory loggerFactory,\n        IInternalGrainFactory grainFactory,\n        Catalog catalog,\n        SystemTargetShared shared,\n        IClusterMembershipService clusterMembershipService) : base(Constants.ActivationMigratorType, shared)\n    {\n        _grainFactory = grainFactory;\n        _logger = loggerFactory.CreateLogger<ActivationMigrationManager>();\n        _catalog = catalog;\n        _clusterMembershipService = clusterMembershipService;\n        shared.ActivationDirectory.RecordNewTarget(this);\n\n        {\n            using var _ = new ExecutionContextSuppressor();\n            _membershipUpdatesTask = Task.Factory.StartNew(\n                state => ((ActivationMigrationManager)state!).ProcessMembershipUpdates(),\n                this,\n                CancellationToken.None,\n                TaskCreationOptions.None,\n                WorkItemGroup.TaskScheduler).Unwrap();\n            _membershipUpdatesTask.Ignore();\n        }\n    }\n\n    public async ValueTask AcceptMigratingGrains(List<GrainMigrationPackage> migratingGrains)\n    {\n        var activations = new List<ActivationData>();\n        var currentActivity = Activity.Current;\n        foreach (var package in migratingGrains)\n        {\n            // If the activation does not exist, create it and provide it with the migration context while doing so.\n            // If the activation already exists or cannot be created, it is too late to perform migration, so ignore the request.\n            var context = _catalog.GetOrCreateActivation(package.GrainId, requestContextData: null, package.MigrationContext);\n            if (context is ActivationData activation)\n            {\n                activations.Add(activation);\n            }\n\n            Activity.Current = currentActivity;\n        }\n\n        // Wait for all activations to become active or reach a terminal state.\n        // This ensures that the activation has completed registration in the directory (or is abandoned) before we return.\n        // Otherwise, there could be a race where the original silo removes the activation from its catalog, receives a new message for that activation,\n        // and re-activates it before the new activation on this silo has been registered with the directory.\n        using var waitActivity = ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.WaitMigration);\n        while (true)\n        {\n            var allActiveOrTerminal = true;\n            foreach (var activation in activations)\n            {\n                lock (activation)\n                {\n                    if (activation.State is not (ActivationState.Valid or ActivationState.Invalid))\n                    {\n                        allActiveOrTerminal = false;\n                        break;\n                    }\n                }\n            }\n\n            if (allActiveOrTerminal)\n            {\n                break;\n            }\n\n            // Wait a short amount of time and poll the activations again.\n            await Task.Delay(5);\n        }\n    }\n\n    public ValueTask MigrateAsync(SiloAddress targetSilo, GrainId grainId, MigrationContext migrationContext)\n    {\n        var workItem = _workItemPool.Get();\n        var migrationPackage = new GrainMigrationPackage { GrainId = grainId, MigrationContext = migrationContext };\n        workItem.Initialize(migrationPackage);\n        var workItemWriter = GetOrCreateWorker(targetSilo);\n        if (!workItemWriter.TryWrite(workItem))\n        {\n            workItem.SetException(new SiloUnavailableException($\"Silo {targetSilo} is no longer active\"));\n        }\n\n        return workItem.AsValueTask();\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        await Task.Yield();\n\n        try\n        {\n            LogDebugMonitoringUpdates();\n\n            var previousSnapshot = _clusterMembershipService.CurrentSnapshot;\n            await foreach (var snapshot in _clusterMembershipService.MembershipUpdates)\n            {\n                try\n                {\n                    var diff = snapshot.CreateUpdate(previousSnapshot);\n                    previousSnapshot = snapshot;\n                    foreach (var change in diff.Changes)\n                    {\n                        if (change.Status.IsTerminating())\n                        {\n                            RemoveWorker(change.SiloAddress);\n                        }\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorProcessingMembershipUpdates(exception);\n                }\n            }\n        }\n        finally\n        {\n            LogDebugNoLongerMonitoring();\n        }\n    }\n\n    private async Task PumpMigrationQueue(SiloAddress targetSilo, Channel<MigrationWorkItem> workItems)\n    {\n        try\n        {\n            var remote = _grainFactory.GetSystemTarget<IActivationMigrationManagerSystemTarget>(Constants.ActivationMigratorType, targetSilo);\n            await Task.Yield();\n\n            LogDebugStartingWorker(targetSilo);\n\n            var items = new List<MigrationWorkItem>();\n            var batch = new List<GrainMigrationPackage>();\n            var reader = workItems.Reader;\n            while (await reader.WaitToReadAsync())\n            {\n                try\n                {\n                    // Collect a batch of work items.\n                    while (batch.Count < MaxBatchSize && reader.TryRead(out var workItem))\n                    {\n                        items.Add(workItem);\n                        batch.Add(workItem.Value);\n                    }\n\n                    // Attempt to migrate the batch.\n                    await remote.AcceptMigratingGrains(batch).AsTask().WaitAsync(_shuttingDownCts.Token);\n\n                    foreach (var item in items)\n                    {\n                        item.SetCompleted();\n                    }\n\n                    LogDebugMigratedActivations(items.Count, targetSilo);\n                }\n                catch (Exception exception)\n                {\n                    if (!_shuttingDownCts.IsCancellationRequested)\n                    {\n                        LogErrorMigratingActivations(exception, items.Count, targetSilo);\n                    }\n\n                    foreach (var item in items)\n                    {\n                        item.SetException(exception);\n                    }\n\n                    // If the silo is terminating, we should stop trying to migrate activations to it.\n                    if (_clusterMembershipService.CurrentSnapshot.GetSiloStatus(targetSilo).IsTerminating())\n                    {\n                        break;\n                    }\n                }\n                finally\n                {\n                    items.Clear();\n                    batch.Clear();\n                }\n            }\n\n            // Remove ourselves and clean up.\n            RemoveWorker(targetSilo);\n        }\n        finally\n        {\n            LogDebugExitingWorker(targetSilo);\n        }\n    }\n\n    private ChannelWriter<MigrationWorkItem> GetOrCreateWorker(SiloAddress targetSilo)\n    {\n        if (!_workers.TryGetValue(targetSilo, out var entry))\n        {\n            lock (_lock)\n            {\n                if (!_workers.TryGetValue(targetSilo, out entry))\n                {\n                    using var _ = new ExecutionContextSuppressor();\n                    var channel = Channel.CreateUnbounded<MigrationWorkItem>();\n                    var pumpTask = Task.Factory.StartNew(\n                        () => PumpMigrationQueue(targetSilo, channel),\n                        CancellationToken.None,\n                        TaskCreationOptions.None,\n                        WorkItemGroup.TaskScheduler).Unwrap();\n                    pumpTask.Ignore();\n\n                    entry = (pumpTask, channel);\n                    var didAdd = _workers.TryAdd(targetSilo, entry);\n                    Debug.Assert(didAdd);\n                }\n            }\n        }\n\n        return entry.WorkItemChannel.Writer;\n    }\n\n    private void RemoveWorker(SiloAddress targetSilo)\n    {\n        if (_workers.TryRemove(targetSilo, out var entry))\n        {\n            LogDebugTargetSilo(targetSilo);\n\n            entry.WorkItemChannel.Writer.TryComplete();\n\n            var exception = new SiloUnavailableException($\"Silo {targetSilo} is no longer active\");\n            while (entry.WorkItemChannel.Reader.TryRead(out var item))\n            {\n                item.SetException(exception);\n            }\n        }\n    }\n\n    private Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;\n    private async Task StopAsync(CancellationToken cancellationToken)\n    {\n        var workerTasks = new List<Task>();\n        foreach (var (_, value) in _workers)\n        {\n            value.WorkItemChannel.Writer.TryComplete();\n            workerTasks.Add(value.PumpTask);\n        }\n\n        try\n        {\n            _shuttingDownCts.Cancel();\n        }\n        catch (Exception exception)\n        {\n            LogWarningSignalShutdownError(exception);\n        }\n\n        await Task.WhenAll(workerTasks).WaitAsync(cancellationToken).SuppressThrowing();\n    }\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        lifecycle.Subscribe(\n            nameof(ActivationMigrationManager),\n            ServiceLifecycleStage.RuntimeGrainServices,\n                ct => this.RunOrQueueTask(() => StartAsync(ct)),\n                ct => this.RunOrQueueTask(() => StopAsync(ct)));\n    }\n\n    private class MigrationWorkItem : IValueTaskSource\n    {\n        private ManualResetValueTaskSourceCore<int> _core = new() { RunContinuationsAsynchronously = true };\n        private GrainMigrationPackage _migrationPackage;\n\n        public void Initialize(GrainMigrationPackage package) => _migrationPackage = package;\n        public void Reset() => _core.Reset();\n\n        public GrainMigrationPackage Value => _migrationPackage;\n\n        public void SetCompleted() => _core.SetResult(0);\n        public void SetException(Exception exception) => _core.SetException(exception);\n        public ValueTask AsValueTask() => new (this, _core.Version);\n\n        public void GetResult(short token)\n        {\n            try\n            {\n                _core.GetResult(token);\n            }\n            finally\n            {\n                Reset();\n            }\n        }\n\n        public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);\n        public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags);\n\n        public sealed class ObjectPoolPolicy : IPooledObjectPolicy<MigrationWorkItem>\n        {\n            public MigrationWorkItem Create() => new();\n            public bool Return(MigrationWorkItem obj)\n            {\n                obj.Reset();\n                return true;\n            }\n        }\n    }\n\n    // Log value types\n    private readonly struct SiloAddressLogValue\n    {\n        private readonly SiloAddress _silo;\n        public SiloAddressLogValue(SiloAddress silo) => _silo = silo;\n        public override string ToString() => _silo.ToStringWithHashCode();\n    }\n\n    // Logger methods at end of class\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Monitoring cluster membership updates\")]\n    private partial void LogDebugMonitoringUpdates();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing cluster membership updates\"\n    )]\n    private partial void LogErrorProcessingMembershipUpdates(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"No longer monitoring cluster membership updates\")]\n    private partial void LogDebugNoLongerMonitoring();\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Starting migration worker for target silo {SiloAddress}\")]\n    private partial void LogDebugStartingWorker(SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Migrated {Count} activations to target silo {SiloAddress}\")]\n    private partial void LogDebugMigratedActivations(int count, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error while migrating {Count} grain activations to {SiloAddress}\")]\n    private partial void LogErrorMigratingActivations(Exception exception, int count, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Exiting migration worker for target silo {SiloAddress}\")]\n    private partial void LogDebugExitingWorker(SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Target silo {SiloAddress} is no longer active, so this migration activation worker is terminating\"\n    )]\n    private partial void LogDebugTargetSilo(SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error signaling shutdown\"\n    )]\n    private partial void LogWarningSignalShutdownError(Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationState.cs",
    "content": "namespace Orleans.Runtime\n{\n    internal enum ActivationState\n    {\n        /// <summary>\n        /// Activation is being created\n        /// </summary>\n        Creating,\n        \n        /// <summary>\n        /// Activation is in the middle of activation process.\n        /// </summary>\n        Activating,\n        \n        /// <summary>\n        /// Activation was successfully activated and ready to process requests.\n        /// </summary>\n        Valid,\n        \n        /// <summary>\n        /// Activation is in the middle of deactivation process.\n        /// </summary>\n        Deactivating,\n        \n        /// <summary>\n        /// Tombstone for an activation which has terminated.\n        /// </summary>\n        Invalid\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ActivationWorkingSet.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Maintains a list of activations which are recently active.\n    /// </summary>\n    internal sealed partial class ActivationWorkingSet : IActivationWorkingSet, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private class MemberState\n        {\n            public bool IsIdle { get; set; }\n        }\n\n        private readonly ConcurrentDictionary<IActivationWorkingSetMember, MemberState> _members = new();\n        private readonly ILogger _logger;\n        private readonly IAsyncTimer _scanPeriodTimer;\n        private readonly List<IActivationWorkingSetObserver> _observers;\n\n        private int _activeCount;\n        private Task _runTask;\n\n        public ActivationWorkingSet(\n            IAsyncTimerFactory asyncTimerFactory,\n            ILogger<ActivationWorkingSet> logger,\n            IEnumerable<IActivationWorkingSetObserver> observers)\n        {\n            _logger = logger;\n            _scanPeriodTimer = asyncTimerFactory.Create(TimeSpan.FromMilliseconds(5_000), nameof(ActivationWorkingSet) + \".\" + nameof(MonitorWorkingSet));\n            _observers = observers.ToList();\n            CatalogInstruments.RegisterActivationWorkingSetObserve(() => Count);\n        }\n\n        public int Count => _activeCount;\n\n        public void OnActivated(IActivationWorkingSetMember member)\n        {\n            Debug.Assert(member is not ICollectibleGrainContext collectible || collectible.IsValid);\n            if (_members.TryAdd(member, new MemberState()))\n            {\n                Interlocked.Increment(ref _activeCount);\n                foreach (var observer in _observers)\n                {\n                    observer.OnAdded(member);\n                }\n\n                return;\n            }\n\n            throw new InvalidOperationException($\"Member {member} is already a member of the working set\");\n        }\n\n        public void OnActive(IActivationWorkingSetMember member)\n        {\n            if (_members.TryGetValue(member, out var state))\n            {\n                state.IsIdle = false;\n            }\n            else if (_members.TryAdd(member, new()))\n            {\n                Interlocked.Increment(ref _activeCount);\n            }\n\n            foreach (var observer in _observers)\n            {\n                observer.OnActive(member);\n            }\n        }\n\n        public void OnEvicted(IActivationWorkingSetMember member)\n        {\n            if (_members.TryRemove(member, out _))\n            {\n                Interlocked.Decrement(ref _activeCount);\n                foreach (var observer in _observers)\n                {\n                    observer.OnEvicted(member);\n                }\n            }\n        }\n\n        public void OnDeactivating(IActivationWorkingSetMember member)\n        {\n            OnEvicted(member);\n            foreach (var observer in _observers)\n            {\n                observer.OnDeactivating(member);\n            }\n        }\n\n        public void OnDeactivated(IActivationWorkingSetMember member)\n        {\n            OnEvicted(member);\n            foreach (var observer in _observers)\n            {\n                observer.OnDeactivated(member);\n            }\n        }\n\n        private async Task MonitorWorkingSet()\n        {\n            while (await _scanPeriodTimer.NextTick())\n            {\n                foreach (var pair in _members)\n                {\n                    try\n                    {\n                        VisitMember(pair.Key, pair.Value);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogExceptionVisitingWorkingSetMember(exception, pair.Key);\n                    }\n                }\n            }\n        }\n\n        private void VisitMember(IActivationWorkingSetMember member, MemberState state)\n        {\n            var wouldRemove = state.IsIdle;\n            if (member.IsCandidateForRemoval(wouldRemove))\n            {\n                if (wouldRemove)\n                {\n                    OnEvicted(member);\n                }\n                else\n                {\n                    state.IsIdle = true;\n                    foreach (var observer in _observers)\n                    {\n                        observer.OnIdle(member);\n                    }\n                }\n            }\n            else\n            {\n                state.IsIdle = false;\n                foreach (var observer in _observers)\n                {\n                    observer.OnActive(member);\n                }\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(ActivationWorkingSet),\n                ServiceLifecycleStage.BecomeActive,\n                ct =>\n                {\n                    using var _ = new ExecutionContextSuppressor();\n                    _runTask = Task.Run(MonitorWorkingSet);\n                    return Task.CompletedTask;\n                },\n                async ct =>\n                {\n                    _scanPeriodTimer.Dispose();\n                    if (_runTask is Task task)\n                    {\n                        await task.WaitAsync(ct).SuppressThrowing();\n                    }\n                });\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception visiting working set member {Member}\"\n        )]\n        private partial void LogExceptionVisitingWorkingSetMember(Exception exception, IActivationWorkingSetMember member);\n    }\n\n    /// <summary>\n    /// Manages the set of recently active <see cref=\"IGrainContext\"/> instances.\n    /// </summary>\n    public interface IActivationWorkingSet\n    {\n        /// <summary>\n        /// Returns the number of grain activations which were recently active.\n        /// </summary>\n        public int Count { get; }\n\n        /// <summary>\n        /// Adds a new member to the working set.\n        /// </summary>\n        void OnActivated(IActivationWorkingSetMember member);\n\n        /// <summary>\n        /// Signals that a member is active and should be in the working set.\n        /// </summary>\n        void OnActive(IActivationWorkingSetMember member);\n\n        /// <summary>\n        /// Signals that a member has begun to deactivate.\n        /// </summary>\n        /// <param name=\"member\"></param>\n        void OnDeactivating(IActivationWorkingSetMember member);\n\n        /// <summary>\n        /// Signals that a members has deactivated.\n        /// </summary>\n        void OnDeactivated(IActivationWorkingSetMember member);\n    }\n\n    /// <summary>\n    /// Represents an activation from the perspective of <see cref=\"IActivationWorkingSet\"/>.\n    /// </summary>\n    public interface IActivationWorkingSetMember\n    {\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the member is eligible for removal, <see langword=\"false\"/> otherwise.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the member is eligible for removal, <see langword=\"false\"/> otherwise.</returns>\n        /// <remarks>\n        /// If this method returns <see langword=\"true\"/> and <paramref name=\"wouldRemove\"/> is <see langword=\"true\"/>, the member must be removed from the working set and is eligible to be added again via a call to <see cref=\"IActivationWorkingSet.OnActivated(IActivationWorkingSetMember)\"/>.\n        /// </remarks>\n        bool IsCandidateForRemoval(bool wouldRemove);\n    }\n\n    /// <summary>\n    /// An <see cref=\"IActivationWorkingSet\"/> observer.\n    /// </summary>\n    public interface IActivationWorkingSetObserver\n    {\n        /// <summary>\n        /// Called when an activation is added to the working set.\n        /// </summary>\n        void OnAdded(IActivationWorkingSetMember member) { }\n\n        /// <summary>\n        /// Called when an activation becomes active.\n        /// </summary>\n        void OnActive(IActivationWorkingSetMember member) { }\n\n        /// <summary>\n        /// Called when an activation becomes idle.\n        /// </summary>\n        void OnIdle(IActivationWorkingSetMember member) { }\n\n        /// <summary>\n        /// Called when an activation is removed from the working set.\n        /// </summary>\n        void OnEvicted(IActivationWorkingSetMember member) { }\n\n        /// <summary>\n        /// Called when an activation starts deactivating.\n        /// </summary>\n        void OnDeactivating(IActivationWorkingSetMember member) { }\n\n        /// <summary>\n        /// Called when an activation is deactivated.\n        /// </summary>\n        void OnDeactivated(IActivationWorkingSetMember member) { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/Catalog.cs",
    "content": "using System.Runtime.CompilerServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime.GrainDirectory;\nusing System.Diagnostics;\nusing Orleans.Diagnostics;\n\nnamespace Orleans.Runtime\n{\n    internal sealed partial class Catalog : SystemTarget, ICatalog, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly SiloAddress _siloAddress;\n        private readonly ActivationCollector activationCollector;\n        private readonly GrainDirectoryResolver grainDirectoryResolver;\n        private readonly ActivationDirectory activations;\n        private readonly IServiceProvider serviceProvider;\n        private readonly ILogger logger;\n        private readonly GrainContextActivator grainActivator;\n        private ISiloStatusOracle _siloStatusOracle;\n\n        // Lock striping is used for activation creation to reduce contention\n        private const int LockCount = 32; // Must be a power of 2\n        private const int LockMask = LockCount - 1;\n#if NET9_0_OR_GREATER\n        private readonly Lock[] _locks = new Lock[LockCount];\n#else\n        private readonly object[] _locks = new object[LockCount];\n#endif\n\n        public Catalog(\n            ILocalSiloDetails localSiloDetails,\n            GrainDirectoryResolver grainDirectoryResolver,\n            ActivationDirectory activationDirectory,\n            ActivationCollector activationCollector,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            GrainContextActivator grainActivator,\n            SystemTargetShared shared)\n            : base(Constants.CatalogType, shared)\n        {\n            this._siloAddress = localSiloDetails.SiloAddress;\n            this.grainDirectoryResolver = grainDirectoryResolver;\n            this.activations = activationDirectory;\n            this.serviceProvider = serviceProvider;\n            this.grainActivator = grainActivator;\n            this.logger = loggerFactory.CreateLogger<Catalog>();\n            this.activationCollector = activationCollector;\n\n            // Initialize lock striping array\n            for (var i = 0; i < LockCount; i++)\n            {\n                _locks[i] = new();\n            }\n\n            GC.GetTotalMemory(true); // need to call once w/true to ensure false returns OK value\n\n            MessagingProcessingInstruments.RegisterActivationDataAllObserve(() =>\n            {\n                long counter = 0;\n                foreach (var activation in activations)\n                {\n                    if (activation.Value is ActivationData data)\n                    {\n                        counter += data.GetRequestCount();\n                    }\n                }\n\n                return counter;\n            });\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        /// <summary>\n        /// Gets the lock for a specific grain ID using consistent hashing.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID to get the lock for.</param>\n        /// <returns>The lock object for the specified grain ID.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#if NET9_0_OR_GREATER\n        private Lock GetStripedLock(in GrainId grainId)\n#else\n        private object GetStripedLock(in GrainId grainId)\n#endif\n        {\n            var hash = grainId.GetUniformHashCode();\n            var lockIndex = (int)(hash & LockMask);\n            return _locks[lockIndex];\n        }\n\n        /// <summary>\n        /// Unregister message target and stop delivering messages to it\n        /// </summary>\n        /// <param name=\"activation\"></param>\n        public void UnregisterMessageTarget(IGrainContext activation)\n        {\n            if (activations.RemoveTarget(activation))\n            {\n                LogTraceUnregisteredActivation(activation);\n\n                // this should be removed once we've refactored the deactivation code path. For now safe to keep.\n                activationCollector.TryCancelCollection(activation as ICollectibleGrainContext);\n                CatalogInstruments.ActivationsDestroyed.Add(1);\n            }\n        }\n\n        /// <summary>\n        /// FOR TESTING PURPOSES ONLY!!\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        internal int UnregisterGrainForTesting(GrainId grain)\n        {\n            var activation = activations.FindTarget(grain);\n            if (activation is null) return 0;\n\n            UnregisterMessageTarget(activation);\n            return 1;\n        }\n\n        /// <summary>\n        /// If activation already exists, return it.\n        /// Otherwise, creates a new activation, begins rehydrating it and activating it, then returns it.\n        /// </summary>\n        /// <remarks>\n        /// There is no guarantee about the validity of the activation which is returned.\n        /// Activations are responsible for handling any messages which they receive.\n        /// </remarks>\n        /// <param name=\"grainId\">The grain identity.</param>\n        /// <param name=\"requestContextData\">Optional request context data.</param>\n        /// <param name=\"rehydrationContext\">Optional rehydration context.</param>\n        /// <returns></returns>\n        public IGrainContext GetOrCreateActivation(\n            in GrainId grainId,\n            Dictionary<string, object> requestContextData,\n            MigrationContext rehydrationContext)\n        {\n            if (TryGetGrainContext(grainId, out var result))\n            {\n                rehydrationContext?.Dispose();\n                return result;\n            }\n            else if (grainId.IsSystemTarget())\n            {\n                rehydrationContext?.Dispose();\n                return null;\n            }\n\n            lock (GetStripedLock(grainId))\n            {\n                if (TryGetGrainContext(grainId, out result))\n                {\n                    rehydrationContext?.Dispose();\n                    return result;\n                }\n\n                if (_siloStatusOracle.CurrentStatus == SiloStatus.Active)\n                {\n                    var address = new GrainAddress\n                    {\n                        SiloAddress = Silo,\n                        GrainId = grainId,\n                        ActivationId = ActivationId.NewId(),\n                        MembershipVersion = MembershipVersion.MinValue,\n                    };\n\n                    result = this.grainActivator.CreateInstance(address);\n                    activations.RecordNewTarget(result);\n                }\n            } // End lock\n\n            if (result is null)\n            {\n                rehydrationContext?.Dispose();\n                return UnableToCreateActivation(this, grainId);\n            }\n\n            // Start activation span with parent context from request if available\n            var parentContext = requestContextData.TryGetActivityContext();\n            var activationActivity = parentContext.HasValue\n                ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivateGrain, ActivityKind.Internal, parentContext.Value)\n                : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.ActivateGrain, ActivityKind.Internal);\n            if (activationActivity is not null)\n            {\n                activationActivity.SetTag(ActivityTagKeys.GrainId, grainId.ToString());\n                activationActivity.SetTag(ActivityTagKeys.GrainType, grainId.Type.ToString());\n                activationActivity.SetTag(ActivityTagKeys.SiloId, Silo.ToString());\n                activationActivity.SetTag(ActivityTagKeys.ActivationCause, rehydrationContext is null ? \"new\" : \"rehydrate\");\n                if (result is ActivationData act)\n                {\n                    activationActivity.SetTag(ActivityTagKeys.ActivationId, act.ActivationId.ToString());\n                    act.SetActivationActivity(activationActivity);\n                    activationActivity.AddEvent(new ActivityEvent(\"creating\"));\n                }\n            }\n\n            CatalogInstruments.ActivationsCreated.Add(1);\n\n            // Rehydration occurs before activation.\n            if (rehydrationContext is not null)\n            {\n                result.Rehydrate(rehydrationContext);\n            }\n\n            // Initialize the new activation asynchronously.\n            result.Activate(requestContextData);\n            return result;\n\n            [MethodImpl(MethodImplOptions.NoInlining)]\n            static IGrainContext UnableToCreateActivation(Catalog self, GrainId grainId)\n            {\n                // Did not find and did not start placing new\n                var status = self._siloStatusOracle.CurrentStatus;\n                var isTerminating = status.IsTerminating();\n                if (status is not SiloStatus.Active)\n                {\n                    self.LogDebugUnableToCreateActivationWhenNotActive(grainId);\n                }\n                else\n                {\n                    self.LogDebugUnableToCreateActivation(grainId);\n                }\n\n                CatalogInstruments.NonExistentActivations.Add(1);\n\n                var grainLocator = self.serviceProvider.GetRequiredService<GrainLocator>();\n                grainLocator.InvalidateCache(grainId);\n                if (!isTerminating)\n                {\n                    // Unregister the target activation so we don't keep getting spurious messages.\n                    // The time delay (one minute, as of this writing) is to handle the unlikely but possible race where\n                    // this request snuck ahead of another request, with new placement requested, for the same activation.\n                    // If the activation registration request from the new placement somehow sneaks ahead of this deregistration,\n                    // we want to make sure that we don't unregister the activation we just created.\n                    var address = new GrainAddress { SiloAddress = self.Silo, GrainId = grainId };\n                    _ = self.UnregisterNonExistentActivation(address);\n                }\n\n                return null;\n            }\n        }\n\n        private async Task UnregisterNonExistentActivation(GrainAddress address)\n        {\n            try\n            {\n                var grainLocator = serviceProvider.GetRequiredService<GrainLocator>();\n                await grainLocator.Unregister(address, UnregistrationCause.NonexistentActivation);\n            }\n            catch (Exception exc)\n            {\n                LogFailedToUnregisterNonExistingActivation(address, exc);\n            }\n        }\n\n        /// <summary>\n        /// Try to get runtime data for an activation\n        /// </summary>\n        private bool TryGetGrainContext(GrainId grainId, out IGrainContext data)\n        {\n            data = activations.FindTarget(grainId);\n            return data != null;\n        }\n\n        /// <summary>\n        /// Gracefully deactivates activations, waiting for them to complete\n        /// complete and commit outstanding transactions before deleting it.\n        /// To be called not from within Activation context, so can be awaited.\n        /// </summary>\n        internal async Task DeactivateActivations(DeactivationReason reason, List<IGrainContext> list, CancellationToken cancellationToken)\n        {\n            if (list == null || list.Count == 0) return;\n\n            LogDebugDeactivateActivations(list.Count);\n            var options = new ParallelOptions\n            {\n                CancellationToken = CancellationToken.None,\n                MaxDegreeOfParallelism = Environment.ProcessorCount * 512\n            };\n            await Parallel.ForEachAsync(list, options, (activation, _) =>\n            {\n                if (activation.GrainId.Type.IsSystemTarget())\n                {\n                    return ValueTask.CompletedTask;\n                }\n\n                activation.Deactivate(reason, cancellationToken);\n                return new (activation.Deactivated);\n            }).WaitAsync(cancellationToken);\n        }\n\n        public async Task DeactivateAllActivations(CancellationToken cancellationToken)\n        {\n            LogDebugDeactivateAllActivations();\n            LogDebugDeactivateActivations(activations.Count);\n            var reason = new DeactivationReason(DeactivationReasonCode.ShuttingDown, \"This process is terminating.\");\n            var options = new ParallelOptions\n            {\n                CancellationToken = CancellationToken.None,\n                MaxDegreeOfParallelism = Environment.ProcessorCount * 512\n            };\n            await Parallel.ForEachAsync(activations, options, (kv, _) =>\n            {\n                if (kv.Key.IsSystemTarget())\n                {\n                    return ValueTask.CompletedTask;\n                }\n\n                var activation = kv.Value;\n                activation.Deactivate(reason, cancellationToken);\n                return new (activation.Deactivated);\n            }).WaitAsync(cancellationToken);\n        }\n\n        public async Task DeleteActivations(List<GrainAddress> addresses, DeactivationReasonCode reasonCode, string reasonText)\n        {\n            var tasks = new List<Task>(addresses.Count);\n            var deactivationReason = new DeactivationReason(reasonCode, reasonText);\n            await Parallel.ForEachAsync(addresses, (activationAddress, cancellationToken) =>\n            {\n                if (TryGetGrainContext(activationAddress.GrainId, out var grainContext))\n                {\n                    grainContext.Deactivate(deactivationReason);\n                    return new ValueTask(grainContext.Deactivated);\n                }\n\n                return ValueTask.CompletedTask;\n            });\n        }\n\n        // TODO move this logic in the LocalGrainDirectory\n        internal void OnSiloStatusChange(ILocalGrainDirectory directory, SiloAddress updatedSilo, SiloStatus status)\n        {\n            // ignore joining events and also events on myself.\n            if (updatedSilo.Equals(_siloAddress)) return;\n\n            // We deactivate those activations when silo goes either of ShuttingDown/Stopping/Dead states,\n            // since this is what Directory is doing as well. Directory removes a silo based on all those 3 statuses,\n            // thus it will only deliver a \"remove\" notification for a given silo once to us. Therefore, we need to react the fist time we are notified.\n            // We may review the directory behavior in the future and treat ShuttingDown differently (\"drain only\") and then this code will have to change a well.\n            if (!status.IsTerminating()) return;\n            if (status == SiloStatus.Dead)\n            {\n                this.RuntimeClient.BreakOutstandingMessagesToSilo(updatedSilo);\n            }\n\n            var activationsToShutdown = new List<IGrainContext>();\n            try\n            {\n                // scan all activations in activation directory and deactivate the ones that the removed silo is their primary partition owner.\n                // Note: No lock needed here since ActivationDirectory uses ConcurrentDictionary which provides thread-safe enumeration\n                foreach (var activation in activations)\n                {\n                    try\n                    {\n                        var activationData = activation.Value;\n                        var placementStrategy = activationData.GetComponent<PlacementStrategy>();\n                        var isUsingGrainDirectory = placementStrategy is { IsUsingGrainDirectory: true };\n                        if (!isUsingGrainDirectory || !grainDirectoryResolver.IsUsingDefaultDirectory(activationData.GrainId.Type)) continue;\n                        if (!updatedSilo.Equals(directory.GetPrimaryForGrain(activationData.GrainId))) continue;\n\n                        activationsToShutdown.Add(activationData);\n                    }\n                    catch (Exception exc)\n                    {\n                        LogErrorCatalogSiloStatusChangeNotification(new(updatedSilo), exc);\n                    }\n                }\n\n                if (activationsToShutdown.Count > 0)\n                {\n                    LogInfoCatalogSiloStatusChangeNotification(activationsToShutdown.Count, new(updatedSilo));\n                }\n            }\n            finally\n            {\n                // outside the lock.\n                if (activationsToShutdown.Count > 0)\n                {\n                    var reasonText = $\"This activation is being deactivated due to a failure of server {updatedSilo}, since it was responsible for this activation's grain directory registration.\";\n                    var reason = new DeactivationReason(DeactivationReasonCode.DirectoryFailure, reasonText);\n                    StartDeactivatingActivations(reason, activationsToShutdown, CancellationToken.None);\n                }\n            }\n\n            void StartDeactivatingActivations(DeactivationReason reason, List<IGrainContext> list, CancellationToken cancellationToken)\n            {\n                if (list == null || list.Count == 0) return;\n\n                LogDebugDeactivateActivations(list.Count);\n\n                foreach (var activation in list)\n                {\n                    activation.Deactivate(reason, cancellationToken);\n                }\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            // Do nothing, just ensure that this instance is created so that it can register itself in the activation directory.\n            _siloStatusOracle = serviceProvider.GetRequiredService<ISiloStatusOracle>();\n        }\n\n        private readonly struct SiloAddressLogValue(SiloAddress silo)\n        {\n            public override string ToString() => silo.ToStringWithHashCode();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Catalog_SiloStatusChangeNotification_Exception,\n            Message = \"Catalog has thrown an exception while handling removal of silo {Silo}\"\n        )]\n        private partial void LogErrorCatalogSiloStatusChangeNotification(SiloAddressLogValue silo, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.Catalog_SiloStatusChangeNotification,\n            Message = \"Catalog is deactivating {Count} activations due to a failure of silo {Silo}, since it is a primary directory partition to these grain ids.\"\n        )]\n        private partial void LogInfoCatalogSiloStatusChangeNotification(int count, SiloAddressLogValue silo);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Unregistered activation {Activation}\")]\n        private partial void LogTraceUnregisteredActivation(IGrainContext activation);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"DeactivateActivations: {Count} activations.\")]\n        private partial void LogDebugDeactivateActivations(int count);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.Catalog_DeactivateAllActivations,\n            Message = \"DeactivateAllActivations.\"\n        )]\n        private partial void LogDebugDeactivateAllActivations();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unable to create activation for grain {GrainId} because this silo is not active.\")]\n        private partial void LogDebugUnableToCreateActivationWhenNotActive(GrainId grainId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CatalogNonExistingActivation2,\n            Level = LogLevel.Debug,\n            Message = \"Unable to create activation for grain {GrainId}\"\n        )]\n        private partial void LogDebugUnableToCreateActivation(GrainId grainId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Dispatcher_FailedToUnregisterNonExistingAct,\n            Level = LogLevel.Warning,\n            Message = \"Failed to unregister non-existent activation {Address}\"\n        )]\n        private partial void LogFailedToUnregisterNonExistingActivation(GrainAddress address, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/GrainLifecycle.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal class GrainLifecycle(ILogger logger) : LifecycleSubject(logger), IGrainLifecycle\n    {\n        private static readonly ImmutableDictionary<int, string> StageNames = GetStageNames(typeof(GrainLifecycleStage));\n        private List<IGrainMigrationParticipant> _migrationParticipants;\n\n        public IEnumerable<IGrainMigrationParticipant> GetMigrationParticipants() => _migrationParticipants ?? (IEnumerable<IGrainMigrationParticipant>)[];\n\n        public void AddMigrationParticipant(IGrainMigrationParticipant participant)\n        {\n            lock (this)\n            {\n                _migrationParticipants ??= [];\n                _migrationParticipants.Add(participant);\n            }\n        }\n\n        public void RemoveMigrationParticipant(IGrainMigrationParticipant participant)\n        {\n            lock (this)\n            {\n                if (_migrationParticipants is null) return;\n                _migrationParticipants.Remove(participant);\n            }\n        }\n\n        protected override string GetStageName(int stage)\n        {\n            if (StageNames.TryGetValue(stage, out var result)) return result;\n            return base.GetStageName(stage);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/GrainTypeSharedContext.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Functionality which is shared between all instances of a grain type.\n/// </summary>\npublic sealed class GrainTypeSharedContext\n{\n    private readonly IServiceProvider _serviceProvider;\n    private readonly Dictionary<Type, object> _components = new();\n    private InternalGrainRuntime? _internalGrainRuntime;\n\n    public GrainTypeSharedContext(\n        GrainType grainType,\n        IClusterManifestProvider clusterManifestProvider,\n        GrainClassMap grainClassMap,\n        PlacementStrategyResolver placementStrategyResolver,\n        IOptions<SiloMessagingOptions> messagingOptions,\n        IOptions<GrainCollectionOptions> collectionOptions,\n        IOptions<SchedulingOptions> schedulingOptions,\n        IOptions<StatelessWorkerOptions> statelessWorkerOptions,\n        IGrainRuntime grainRuntime,\n        ILoggerFactory loggerFactory,\n        GrainReferenceActivator grainReferenceActivator,\n        IServiceProvider serviceProvider,\n        SerializerSessionPool serializerSessionPool)\n    {\n        if (!grainClassMap.TryGetGrainClass(grainType, out var grainClass))\n        {\n            throw new KeyNotFoundException($\"Could not find corresponding grain class for grain of type {grainType}\");\n        }\n\n        SerializerSessionPool = serializerSessionPool;\n        GrainTypeName = RuntimeTypeNameFormatter.Format(grainClass);\n        Logger = loggerFactory.CreateLogger(\"Orleans.Grain\");\n        MessagingOptions = messagingOptions.Value;\n        GrainReferenceActivator = grainReferenceActivator;\n        _serviceProvider = serviceProvider;\n        MaxWarningRequestProcessingTime = messagingOptions.Value.ResponseTimeout.Multiply(5);\n        MaxRequestProcessingTime = messagingOptions.Value.MaxRequestProcessingTime;\n        PlacementStrategy = placementStrategyResolver.GetPlacementStrategy(grainType);\n        var grainDirectoryResolver = serviceProvider.GetRequiredService<GrainDirectoryResolver>();\n        GrainDirectory = PlacementStrategy.IsUsingGrainDirectory ? grainDirectoryResolver.Resolve(grainType) : null;\n        SchedulingOptions = schedulingOptions.Value;\n        StatelessWorkerOptions = statelessWorkerOptions.Value;\n        Runtime = grainRuntime;\n        MigrationManager = _serviceProvider.GetService<IActivationMigrationManager>();\n\n        CollectionAgeLimit = GetCollectionAgeLimit(\n            grainType,\n            grainClass,\n            clusterManifestProvider.LocalGrainManifest,\n            collectionOptions.Value);\n    }\n\n    /// <summary>\n    /// Gets the grain instance type name, if available.\n    /// </summary>\n    public string? GrainTypeName { get; }\n\n    private static TimeSpan GetCollectionAgeLimit(GrainType grainType, Type grainClass, GrainManifest siloManifest, GrainCollectionOptions collectionOptions)\n    {\n        if (siloManifest.Grains.TryGetValue(grainType, out var properties)\n            && properties.Properties.TryGetValue(WellKnownGrainTypeProperties.IdleDeactivationPeriod, out var idleTimeoutString))\n        {\n            if (string.Equals(idleTimeoutString, WellKnownGrainTypeProperties.IndefiniteIdleDeactivationPeriodValue))\n            {\n                return Timeout.InfiniteTimeSpan;\n            }\n\n            if (TimeSpan.TryParse(idleTimeoutString, out var result))\n            {\n                return result;\n            }\n        }\n\n        if (collectionOptions.ClassSpecificCollectionAge.TryGetValue(grainClass.FullName!, out var specified))\n        {\n            return specified;\n        }\n\n        return collectionOptions.CollectionAge;\n    }\n\n    /// <summary>\n    /// Gets a component.\n    /// </summary>\n    /// <typeparam name=\"TComponent\">The type specified in the corresponding <see cref=\"SetComponent{TComponent}\"/> call.</typeparam>\n    public TComponent? GetComponent<TComponent>()\n    {\n        if (typeof(TComponent) == typeof(PlacementStrategy) && PlacementStrategy is TComponent component)\n        {\n            return component;\n        }\n\n        if (typeof(TComponent) == typeof(ILogger))\n        {\n            return (TComponent)Logger;\n        }\n\n        if (_components is null) return default;\n        _components.TryGetValue(typeof(TComponent), out var resultObj);\n        return (TComponent?)resultObj;\n    }\n\n    /// <summary>\n    /// Gets a component.\n    /// </summary>\n    /// <param name=\"componentType\">The type of the component.</param>\n    /// <returns>The component with the specified type.</returns>\n    public object? GetComponent(Type componentType)\n    {\n        if (componentType == typeof(PlacementStrategy))\n        {\n            return PlacementStrategy;\n        }\n\n        if (componentType == typeof(ILogger))\n        {\n            return Logger;\n        }\n\n        if (_components is null) return default;\n        _components.TryGetValue(componentType, out var resultObj);\n        return resultObj;\n    }\n\n    /// <summary>\n    /// Registers a component.\n    /// </summary>\n    /// <typeparam name=\"TComponent\">The type which can be used as a key to <see cref=\"GetComponent{TComponent}\"/>.</typeparam>\n    public void SetComponent<TComponent>(TComponent? instance)\n    {\n        if (instance == null)\n        {\n            _components.Remove(typeof(TComponent));\n            return;\n        }\n\n        _components[typeof(TComponent)] = instance;\n    }\n\n    /// <summary>\n    /// Gets the duration after which idle grains are eligible for collection.\n    /// </summary>\n    public TimeSpan CollectionAgeLimit { get; }\n\n    /// <summary>\n    /// Gets the logger.\n    /// </summary>\n    public ILogger Logger { get; }\n\n    /// <summary>\n    /// Gets the serializer session pool.\n    /// </summary>\n    public SerializerSessionPool SerializerSessionPool { get; }\n\n    /// <summary>\n    /// Gets the silo messaging options.\n    /// </summary>\n    public SiloMessagingOptions MessagingOptions { get; }\n\n    /// <summary>\n    /// Gets the grain reference activator.\n    /// </summary>\n    public GrainReferenceActivator GrainReferenceActivator { get; }\n\n    /// <summary>\n    /// Gets the maximum amount of time we expect a request to continue processing before it is considered hung.\n    /// </summary>\n    public TimeSpan MaxRequestProcessingTime { get; }\n\n    /// <summary>\n    /// Gets the maximum amount of time we expect a request to continue processing before a warning may be logged.\n    /// </summary>\n    public TimeSpan MaxWarningRequestProcessingTime { get; }\n\n    /// <summary>\n    /// Gets the placement strategy used by grains of this type.\n    /// </summary>\n    public PlacementStrategy PlacementStrategy { get; }\n\n    /// <summary>\n    /// Gets the grain directory used by grains of this type, if this type uses a grain directory.\n    /// </summary>\n    public IGrainDirectory? GrainDirectory { get; }\n\n    /// <summary>\n    /// Gets the scheduling options.\n    /// </summary>\n    public SchedulingOptions SchedulingOptions { get; }\n\n    /// <summary>\n    /// Gets the stateless worker options.\n    /// </summary>\n    public StatelessWorkerOptions StatelessWorkerOptions { get; }\n\n    /// <summary>\n    /// Gets the grain runtime.\n    /// </summary>\n    public IGrainRuntime Runtime { get; }\n\n    /// <summary>\n    /// Gets the local activation migration manager.\n    /// </summary>\n    internal IActivationMigrationManager? MigrationManager { get; }\n\n    /// <summary>\n    /// Gets the internal grain runtime.\n    /// </summary>\n    internal InternalGrainRuntime InternalRuntime => _internalGrainRuntime ??= _serviceProvider.GetRequiredService<InternalGrainRuntime>();\n\n    /// <summary>\n    /// Called on creation of an activation.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain activation.</param>\n    public void OnCreateActivation(IGrainContext grainContext)\n    {\n        GrainInstruments.IncrementGrainCounts(GrainTypeName);\n    }\n\n    /// <summary>\n    /// Called when an activation is disposed.\n    /// </summary>\n    /// <param name=\"grainContext\">The grain activation.</param>\n    public void OnDestroyActivation(IGrainContext grainContext)\n    {\n        GrainInstruments.DecrementGrainCounts(GrainTypeName);\n    }\n}\n\ninternal interface IActivationLifecycleObserver\n{\n    void OnCreateActivation(IGrainContext grainContext);\n    void OnDestroyActivation(IGrainContext grainContext);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/IActivationCollector.cs",
    "content": "﻿namespace Orleans.Runtime\n{\n    internal interface IActivationCollector\n    {\n        /// <summary>\n        /// Schedule collection.\n        /// </summary>\n        /// <param name=\"item\">The activation to be scheduled.</param>\n        /// <returns></returns>\n        void ScheduleCollection(ActivationData item);\n\n        /// <summary>\n        /// Attempt to reschedule collection.\n        /// </summary>\n        /// <param name=\"item\">The activation to be rescheduled.</param>\n        /// <returns></returns>\n        bool TryRescheduleCollection(ActivationData item);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/ICatalog.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Remote interface to grain and activation state\n    /// </summary>\n    internal interface ICatalog : ISystemTarget\n    {\n        /// <summary>\n        /// Delete activations from this silo\n        /// </summary>\n        /// <param name=\"activationAddresses\"></param>\n        /// <param name=\"reasonCode\"></param>\n        /// <param name=\"reasonText\"></param>\n        /// <returns></returns>\n        Task DeleteActivations(List<GrainAddress> activationAddresses, DeactivationReasonCode reasonCode, string reasonText);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/IncomingRequestMonitor.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Monitors currently-active requests and sends status notifications to callers for long-running and blocked requests.\n    /// </summary>\n    internal sealed class IncomingRequestMonitor : ILifecycleParticipant<ISiloLifecycle>, IActivationWorkingSetObserver\n    {\n        private static readonly TimeSpan DefaultAnalysisPeriod = TimeSpan.FromSeconds(10);\n        private static readonly TimeSpan InactiveGrainIdleness = TimeSpan.FromMinutes(1);\n        private readonly IAsyncTimer _scanPeriodTimer;\n        private readonly IServiceProvider _serviceProvider;\n        private readonly MessageFactory _messageFactory;\n        private readonly IOptionsMonitor<SiloMessagingOptions> _messagingOptions;\n        private readonly ConcurrentDictionary<ActivationData, bool> _recentlyUsedActivations = new ConcurrentDictionary<ActivationData, bool>(ReferenceEqualsComparer<ActivationData>.Default);\n        private bool _enabled = true;\n        private Task _runTask;\n\n        public IncomingRequestMonitor(\n            IAsyncTimerFactory asyncTimerFactory,\n            IServiceProvider serviceProvider,\n            MessageFactory messageFactory,\n            IOptionsMonitor<SiloMessagingOptions> siloMessagingOptions)\n        {\n            _scanPeriodTimer = asyncTimerFactory.Create(TimeSpan.FromSeconds(1), nameof(IncomingRequestMonitor));\n            _serviceProvider = serviceProvider;\n            _messageFactory = messageFactory;\n            _messagingOptions = siloMessagingOptions;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void MarkRecentlyUsed(ActivationData activation)\n        {\n            if (!_enabled)\n            {\n                return;\n            }\n            \n            _recentlyUsedActivations.TryAdd(activation, true);\n        }\n\n        public void OnActive(IActivationWorkingSetMember member)\n        {\n            if (member is ActivationData activation)\n            {\n                MarkRecentlyUsed(activation);\n            }\n        }\n\n        public void OnIdle(IActivationWorkingSetMember member)\n        {\n            if (member is ActivationData activation)\n            {\n                _recentlyUsedActivations.TryRemove(activation, out _);\n            }\n        }\n\n        public void OnEvicted(IActivationWorkingSetMember member) => OnIdle(member);\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(IncomingRequestMonitor),\n                ServiceLifecycleStage.BecomeActive,\n                ct =>\n                {\n                    _runTask = Task.Run(this.Run);\n                    return Task.CompletedTask;\n                },\n                async ct =>\n                {\n                    _scanPeriodTimer.Dispose();\n                    if (_runTask is Task task)\n                    {\n                        await task.WaitAsync(ct).SuppressThrowing();\n                    }\n                });\n        }\n\n        private async Task Run()\n        {\n            var options = _messagingOptions.CurrentValue;\n            var optionsPeriod = options.GrainWorkloadAnalysisPeriod;\n            TimeSpan nextDelay = optionsPeriod > TimeSpan.Zero ? optionsPeriod : DefaultAnalysisPeriod;\n            var messageCenter = _serviceProvider.GetRequiredService<MessageCenter>();\n\n            while (await _scanPeriodTimer.NextTick(nextDelay))\n            {\n                options = _messagingOptions.CurrentValue;\n                optionsPeriod = options.GrainWorkloadAnalysisPeriod;\n\n                if (optionsPeriod <= TimeSpan.Zero)\n                {\n                    // Scanning is disabled. Wake up and check again soon.\n                    nextDelay = DefaultAnalysisPeriod;\n                    if (_enabled)\n                    {\n                        _enabled = false;\n                    }\n\n                    _recentlyUsedActivations.Clear();\n                    continue;\n                }\n\n                nextDelay = optionsPeriod;\n                if (!_enabled)\n                {\n                    _enabled = true;\n                }\n\n                var iteration = 0;\n                var now = DateTime.UtcNow;\n                foreach (var activationEntry in _recentlyUsedActivations)\n                {\n                    var activation = activationEntry.Key;\n                    lock (activation)\n                    {\n                        activation.AnalyzeWorkload(now, messageCenter, _messageFactory, options);\n                    }\n\n                    // Yield execution frequently\n                    if (++iteration % 100 == 0)\n                    {\n                        await Task.Yield();\n                        now = DateTime.UtcNow;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/LocalActivationStatusChecker.cs",
    "content": "#nullable enable\n\nnamespace Orleans.Runtime;\n\ninternal sealed class LocalActivationStatusChecker(ActivationDirectory activationDirectory) : ILocalActivationStatusChecker\n{\n    public bool IsLocallyActivated(GrainId grainId) => activationDirectory.FindTarget(grainId) is { } activation && (activation is not ActivationData activationData || activationData.IsValid);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/StatelessWorkerGrainContext.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime;\n\ninternal partial class StatelessWorkerGrainContext : IGrainContext, IAsyncDisposable, IActivationLifecycleObserver\n{\n    private static readonly object CollectIdleWorkersSentinel = new();\n    private readonly GrainTypeSharedContext _shared;\n    private readonly IGrainContextActivator _innerActivator;\n    private readonly int _maxWorkers;\n    private readonly List<ActivationData> _workers = [];\n    private readonly ConcurrentQueue<(WorkItemType Type, object State)> _workItems = new();\n    private readonly SingleWaiterAutoResetEvent _workSignal = new() { RunContinuationsAsynchronously = false };\n\n#pragma warning disable IDE0052 // Remove unread private members\n    /// <summary>\n    /// The <see cref=\"Task\"/> representing the <see cref=\"RunMessageLoop\"/> invocation.\n    /// This is written once but never otherwise accessed. The purpose of retaining this field is for\n    /// debugging, where being able to identify the message loop task corresponding to an activation can\n    /// be useful.\n    /// </summary>\n    private readonly Task _messageLoopTask;\n#pragma warning restore IDE0052 // Remove unread private members\n\n    private GrainReference? _grainReference;\n\n    // Idle worker removal fields\n    private Timer? _inspectionTimer;\n    private double _previousError = 0d;\n    private double _integralTerm = 0d;\n    private int _detectedIdleCyclesCount = 0;\n    private readonly int _minIdleCyclesBeforeRemoval;\n    private readonly bool _isIdleWorkerRemovalStrategy;\n\n    public StatelessWorkerGrainContext(\n        GrainAddress address,\n        GrainTypeSharedContext sharedContext,\n        IGrainContextActivator innerActivator)\n    {\n        Address = address;\n        _shared = sharedContext;\n        _innerActivator = innerActivator;\n\n        var strategy = (StatelessWorkerPlacement)_shared.PlacementStrategy;\n        var options = _shared.StatelessWorkerOptions;\n\n        _isIdleWorkerRemovalStrategy = strategy.RemoveIdleWorkers && options.RemoveIdleWorkers;\n        if (_isIdleWorkerRemovalStrategy)\n        {\n            _minIdleCyclesBeforeRemoval = options.MinIdleCyclesBeforeRemoval > 0 ? options.MinIdleCyclesBeforeRemoval : 1;\n            _inspectionTimer = new Timer(\n                static state => ((StatelessWorkerGrainContext)state!).EnqueueWorkItem(WorkItemType.CollectIdleWorkers, CollectIdleWorkersSentinel),\n                this,\n                options.IdleWorkersInspectionPeriod,\n                options.IdleWorkersInspectionPeriod);\n        }\n\n        _maxWorkers = strategy.MaxLocal;\n        _messageLoopTask = Task.Run(RunMessageLoop);\n    }\n\n    public GrainReference GrainReference => _grainReference ??= _shared.GrainReferenceActivator.CreateReference(GrainId, default);\n\n    public GrainId GrainId => Address.GrainId;\n\n    public object? GrainInstance => null;\n\n    public ActivationId ActivationId => Address.ActivationId;\n\n    public GrainAddress Address { get; }\n\n    public IServiceProvider ActivationServices => throw new NotImplementedException();\n\n    public IGrainLifecycle ObservableLifecycle => throw new NotImplementedException();\n\n    public IWorkItemScheduler Scheduler => throw new NotImplementedException();\n\n    public PlacementStrategy PlacementStrategy => _shared.PlacementStrategy;\n\n    public Task Deactivated\n    {\n        get\n        {\n            var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n            EnqueueWorkItem(WorkItemType.DeactivatedTask, new DeactivatedTaskWorkItemState(completion));\n            return completion.Task;\n        }\n    }\n\n    public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }\n\n    public void ReceiveMessage(object message) => EnqueueWorkItem(WorkItemType.Message, message);\n\n    public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) =>\n        EnqueueWorkItem(WorkItemType.Deactivate, new DeactivateWorkItemState(deactivationReason, cancellationToken));\n\n    public async ValueTask DisposeAsync()\n    {\n        var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        EnqueueWorkItem(WorkItemType.DisposeAsync, new DisposeAsyncWorkItemState(completion));\n        await completion.Task;\n    }\n\n    private void EnqueueWorkItem(WorkItemType type, object state)\n    {\n        _workItems.Enqueue(new(type, state));\n        _workSignal.Signal();\n    }\n\n    public bool Equals([AllowNull] IGrainContext other) => other is not null && ActivationId.Equals(other.ActivationId);\n\n    public object? GetComponent(Type componentType)\n    {\n        if (componentType.IsAssignableFrom(GetType())) return this;\n        return _shared.GetComponent(componentType);\n    }\n\n    public void SetComponent<TComponent>(TComponent? instance) where TComponent : class\n    {\n        if (typeof(TComponent) != typeof(GrainCanInterleave))\n        {\n            throw new ArgumentException($\"Cannot set a component of type '{typeof(TComponent)}' on a {nameof(StatelessWorkerGrainContext)}\");\n        }\n\n        _shared.SetComponent(instance);\n    }\n\n    public object? GetTarget() => throw new NotImplementedException();\n\n    private async Task RunMessageLoop()\n    {\n        while (true)\n        {\n            try\n            {\n                while (_workItems.TryDequeue(out var workItem))\n                {\n                    switch (workItem.Type)\n                    {\n                        case WorkItemType.Message:\n                            ReceiveMessageInternal(workItem.State);\n                            break;\n                        case WorkItemType.Deactivate:\n                            {\n                                var state = (DeactivateWorkItemState)workItem.State;\n                                DeactivateInternal(state.DeactivationReason, state.CancellationToken);\n                                break;\n                            }\n                        case WorkItemType.DeactivatedTask:\n                            {\n                                var state = (DeactivatedTaskWorkItemState)workItem.State;\n                                _ = DeactivatedTaskInternal(state.Completion);\n                                break;\n                            }\n                        case WorkItemType.DisposeAsync:\n                            {\n                                var state = (DisposeAsyncWorkItemState)workItem.State;\n                                _ = DisposeAsyncInternal(state.Completion);\n                                break;\n                            }\n                        case WorkItemType.OnDestroyActivation:\n                            {\n                                var grainContext = (ActivationData)workItem.State;\n                                _workers.Remove(grainContext);\n\n                                if (_workers.Count == 0)\n                                {\n                                    // When the last worker is destroyed, we can consider the stateless worker grain activation to be destroyed as well\n                                    _shared.InternalRuntime.Catalog.UnregisterMessageTarget(this);\n\n                                    if (_isIdleWorkerRemovalStrategy)\n                                    {\n                                        var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n                                        EnqueueWorkItem(WorkItemType.DisposeAsync, new DisposeAsyncWorkItemState(completion));\n\n                                        // DO NOT await this as it would deadlock the work loop!\n                                        _ = completion.Task.ContinueWith(t =>\n                                        {\n                                            if (t.Exception is { } ex)\n                                            {\n                                                LogErrorInMessageLoop(_shared.Logger, ex);\n                                            }\n                                        }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Current);\n                                    }\n                                }\n                                break;\n                            }\n                        case WorkItemType.CollectIdleWorkers:\n                            CollectIdleWorkers();\n                            break;\n                        default:\n                            throw new NotSupportedException($\"Work item of type {workItem.Type} is not supported\");\n                    }\n                }\n\n                await _workSignal.WaitAsync();\n            }\n            catch (Exception exception)\n            {\n                LogErrorInMessageLoop(_shared.Logger, exception);\n            }\n        }\n    }\n\n    private void CollectIdleWorkers()\n    {\n        // These parameter values were tuned using a genetic algorithm, for potential re-tuning see:\n        // https://github.com/ledjon-behluli/Orleans.FullyAdaptiveStatelessWorkerSimulations/blob/main/Orleans.FullyAdaptiveStatelessWorkerSimulations/Program.cs\n\n        // For more info see:\n        // https://www.ledjonbehluli.com/posts/orleans_adaptive_stateless_worker/\n\n        const double Kp = 0.433;\n        const double Ki = 0.468;\n        const double Kd = 0.480;\n\n        var averageWaitingCount = _workers.Count > 0 ? _workers.Average(w => w.WaitingCount) : 0d;\n        var error = -averageWaitingCount; // Our target is 0 waiting count: 0 - avgWC = -avgWC\n\n        _integralTerm += error;\n        var derivativeTerm = error - _previousError;\n        _previousError = error;\n\n        var controlSignal = Kp * error + Ki * _integralTerm + Kd * derivativeTerm;\n\n        _detectedIdleCyclesCount = controlSignal < 0 ? ++_detectedIdleCyclesCount : 0;\n\n        if (_detectedIdleCyclesCount >= _minIdleCyclesBeforeRemoval)\n        {\n            var inactiveWorkers = _workers.Where(w => w.IsInactive).ToImmutableArray();\n            if (inactiveWorkers.Length > 0)\n            {\n                var worker = inactiveWorkers[Random.Shared.Next(inactiveWorkers.Length)];\n                worker.Deactivate(new(DeactivationReasonCode.RuntimeRequested, \"Worker deactivated due to inactivity.\"));\n\n                var antiWindUpFactor = (double)(inactiveWorkers.Length - 1) / inactiveWorkers.Length;\n\n                _integralTerm *= antiWindUpFactor;\n                _detectedIdleCyclesCount = 0;\n            }\n        }\n    }\n\n    private void ReceiveMessageInternal(object message)\n    {\n        try\n        {\n            ActivationData? worker = null;\n            ActivationData? minimumWaitingCountWorker = null;\n            var minimumWaitingCount = int.MaxValue;\n\n            // Make sure there is at least one worker\n            if (_workers.Count == 0)\n            {\n                worker = CreateWorker(message);\n            }\n            else\n            {\n                // Check to see if we have any inactive workers, prioritizing\n                // them in the order they were created to minimize the number\n                // of workers spawned\n                for (var i = 0; i < _workers.Count; i++)\n                {\n                    if (_workers[i].IsInactive)\n                    {\n                        worker = _workers[i];\n                        break;\n                    }\n                    else\n                    {\n                        // Track the worker with the lowest value for WaitingCount,\n                        // this is used if all workers are busy\n                        if (_workers[i].WaitingCount < minimumWaitingCount)\n                        {\n                            minimumWaitingCount = _workers[i].WaitingCount;\n                            minimumWaitingCountWorker = _workers[i];\n                        }\n                    }\n                }\n\n                if (worker is null)\n                {\n                    if (_workers.Count >= _maxWorkers)\n                    {\n                        // Pick the one with the lowest waiting count\n                        worker = minimumWaitingCountWorker;\n                    }\n\n                    // If there are no workers, make one.\n                    worker ??= CreateWorker(message);\n                }\n            }\n\n            worker.ReceiveMessage(message);\n        }\n        catch (Exception exception) when (message is Message msg)\n        {\n            _shared.InternalRuntime.MessageCenter.RejectMessage(\n                msg,\n                Message.RejectionTypes.Transient,\n                exception,\n                \"Exception while creating grain context\");\n        }\n    }\n\n    private ActivationData CreateWorker(object? message)\n    {\n        var address = GrainAddress.GetAddress(Address.SiloAddress, Address.GrainId, ActivationId.NewId());\n        var newWorker = (ActivationData)_innerActivator.CreateContext(address);\n\n        // Observe the create/destroy lifecycle of the activation\n        newWorker.SetComponent<IActivationLifecycleObserver>(this);\n\n        // If this is a new worker and there is a message in scope, try to get the request context and activate the worker\n        var requestContext = (message as Message)?.RequestContextData ?? [];\n        var cancellation = new CancellationTokenSource(_shared.InternalRuntime.CollectionOptions.Value.ActivationTimeout);\n\n        newWorker.Activate(requestContext, cancellation.Token);\n        _workers.Add(newWorker);\n\n        return newWorker;\n    }\n\n    private void DeactivateInternal(DeactivationReason reason, CancellationToken cancellationToken)\n    {\n        foreach (var worker in _workers)\n        {\n            worker.Deactivate(reason, cancellationToken);\n        }\n    }\n\n    private async Task DeactivatedTaskInternal(TaskCompletionSource completion)\n    {\n        try\n        {\n            var tasks = new List<Task>(_workers.Count);\n            foreach (var worker in _workers)\n            {\n                tasks.Add(worker.Deactivated);\n            }\n\n            await Task.WhenAll(tasks);\n            completion.TrySetResult();\n        }\n        catch (Exception exception)\n        {\n            completion.TrySetException(exception);\n        }\n    }\n\n    private async Task DisposeAsyncInternal(TaskCompletionSource completion)\n    {\n        if (_inspectionTimer != null)\n        {\n            await _inspectionTimer.DisposeAsync().AsTask()\n                .ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n            _inspectionTimer = null;\n        }\n\n        try\n        {\n            var tasks = new List<Task>(_workers.Count);\n            var deactivationReason = new DeactivationReason(DeactivationReasonCode.RuntimeRequested, \"Stateless worker grain context is being disposed.\");\n            foreach (var worker in _workers)\n            {\n                try\n                {\n                    worker.Deactivate(deactivationReason);\n                    tasks.Add(worker.Deactivated);\n                }\n                catch (Exception exception)\n                {\n                    tasks.Add(Task.FromException(exception));\n                }\n            }\n\n            await Task.WhenAll(tasks);\n            completion.TrySetResult();\n        }\n        catch (Exception exception)\n        {\n            completion.TrySetException(exception);\n        }\n    }\n\n    public void OnCreateActivation(IGrainContext grainContext)\n    {\n    }\n\n    public void OnDestroyActivation(IGrainContext grainContext) =>\n        EnqueueWorkItem(WorkItemType.OnDestroyActivation, grainContext);\n\n    public void Rehydrate(IRehydrationContext context) =>\n        // Migration is not supported, but we need to dispose of the context if it's provided\n        (context as IDisposable)?.Dispose();\n\n    public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n    {\n        // Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.\n    }\n\n    private enum WorkItemType\n    {\n        Message,\n        Deactivate,\n        DeactivatedTask,\n        DisposeAsync,\n        OnDestroyActivation,\n        CollectIdleWorkers\n    }\n\n    private record ActivateWorkItemState(Dictionary<string, object>? RequestContext, CancellationToken CancellationToken);\n    private record DeactivateWorkItemState(DeactivationReason DeactivationReason, CancellationToken CancellationToken);\n    private record DeactivatedTaskWorkItemState(TaskCompletionSource Completion);\n    private record DisposeAsyncWorkItemState(TaskCompletionSource Completion);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error in stateless worker message loop\"\n    )]\n    private static partial void LogErrorInMessageLoop(ILogger logger, Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/StreamResourceTestControl.cs",
    "content": "﻿namespace Orleans.Runtime\n{\n    internal static class StreamResourceTestControl\n    {\n        internal static bool TestOnlySuppressStreamCleanupOnDeactivate;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Catalog/SystemTargetShared.cs",
    "content": "#nullable enable\nusing System;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainReferences;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Timers;\n\nnamespace Orleans.Runtime;\n\ninternal sealed class SystemTargetShared(\n    InsideRuntimeClient runtimeClient,\n    ILocalSiloDetails localSiloDetails,\n    ILoggerFactory loggerFactory,\n    IOptions<SchedulingOptions> schedulingOptions,\n    GrainReferenceActivator grainReferenceActivator,\n    ITimerRegistry timerRegistry,\n    ActivationDirectory activations)\n{\n    private readonly ILogger<WorkItemGroup> _workItemGroupLogger = loggerFactory.CreateLogger<WorkItemGroup>();\n    private readonly ILogger<ActivationTaskScheduler> _activationTaskSchedulerLogger = loggerFactory.CreateLogger<ActivationTaskScheduler>();\n    public SiloAddress SiloAddress => localSiloDetails.SiloAddress;\n\n    public ILoggerFactory LoggerFactory => loggerFactory;\n    public GrainReferenceActivator GrainReferenceActivator => grainReferenceActivator;\n    public ITimerRegistry TimerRegistry => timerRegistry;\n\n    public RuntimeMessagingTrace MessagingTrace { get; } = new(loggerFactory);\n    public InsideRuntimeClient RuntimeClient => runtimeClient;\n    public ActivationDirectory ActivationDirectory => activations;\n    public WorkItemGroup CreateWorkItemGroup(SystemTarget systemTarget)\n    {\n        ArgumentNullException.ThrowIfNull(systemTarget);\n        return new WorkItemGroup(\n            systemTarget,\n            _workItemGroupLogger,\n            _activationTaskSchedulerLogger,\n            schedulingOptions);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/ActivationCountBasedPlacementOptions.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Settings which regulate the placement of grains across a cluster when using <see cref=\"ActivationCountBasedPlacement\"/>.\n    /// </summary>\n    public class ActivationCountBasedPlacementOptions\n    {\n        /// <summary>\n        /// Gets or sets the number of silos randomly selected for consideration when using activation count placement policy.\n        /// Only used with Activation Count placement policy.\n        /// </summary>\n        public int ChooseOutOf { get; set; } = DEFAULT_ACTIVATION_COUNT_PLACEMENT_CHOOSE_OUT_OF;\n\n        /// <summary>\n        /// The default number of silos to choose from when making placement decisions.\n        /// </summary>\n        public const int DEFAULT_ACTIVATION_COUNT_PLACEMENT_CHOOSE_OUT_OF = 2;\n    }\n\n    /// <summary>\n    /// Validates <see cref=\"ActivationCountBasedPlacementOptions\"/> properties.\n    /// </summary>\n    internal class ActivationCountBasedPlacementOptionsValidator : IConfigurationValidator\n    {\n        private readonly ActivationCountBasedPlacementOptions options;\n\n        public ActivationCountBasedPlacementOptionsValidator(IOptions<ActivationCountBasedPlacementOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if (this.options.ChooseOutOf <= 0)\n            {\n                throw new OrleansConfigurationException(\n                    $\"The value of {nameof(ActivationCountBasedPlacementOptions)}.{nameof(this.options.ChooseOutOf)} must be greater than 0.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/ActivationRebalancerOptions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration;\n\n/// <summary>\n/// Options for configuring activation rebalancing.\n/// </summary>\npublic sealed class ActivationRebalancerOptions\n{\n    /// <summary>\n    /// The due time for the rebalancer to start the very first session.\n    /// </summary>\n    public TimeSpan RebalancerDueTime { get; set; } = DEFAULT_REBALANCER_DUE_TIME;\n\n    /// <summary>\n    /// The default value of <see cref=\"RebalancerDueTime\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_REBALANCER_DUE_TIME = TimeSpan.FromSeconds(60);\n\n    /// <summary>\n    /// The time between two consecutive rebalancing cycles within a session.\n    /// </summary>\n    /// <remarks>It must be greater than 2 x <see cref=\"DeploymentLoadPublisherOptions.DeploymentLoadPublisherRefreshTime\"/>.</remarks>\n    public TimeSpan SessionCyclePeriod { get; set; } = DEFAULT_SESSION_CYCLE_PERIOD;\n\n    /// <summary>\n    /// The default value of <see cref=\"SessionCyclePeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_SESSION_CYCLE_PERIOD = TimeSpan.FromSeconds(15);\n\n    /// <summary>\n    /// The maximum, consecutive number of cycles, yielding no significant improvement to the cluster's entropy.\n    /// </summary>\n    /// <remarks>This value is inclusive, i.e. if this value is 'n', then the 'n+1' cycle will stop the current rebalancing session.</remarks>\n    public int MaxStagnantCycles { get; set; } = DEFAULT_MAX_STAGNANT_CYCLES;\n\n    /// <summary>\n    /// The default value of <see cref=\"MaxStagnantCycles\"/>.\n    /// </summary>\n    public const int DEFAULT_MAX_STAGNANT_CYCLES = 3;\n\n    /// <summary>\n    /// The minimum change in the entropy of the cluster that is considered an improvement.\n    /// When a total of n-consecutive stagnant cycles pass, during which the change in entropy is less than\n    /// the quantum, then the current rebalancing session will stop. The change is a normalized value\n    /// being relative to the maximum possible entropy.\n    /// </summary>\n    /// <remarks>Allowed range: (0-0.1]</remarks>\n    public double EntropyQuantum { get; set; } = DEFAULT_ENTROPY_QUANTUM;\n\n    /// <summary>\n    /// The default value of <see cref=\"EntropyQuantum\"/>.\n    /// </summary>\n    public const double DEFAULT_ENTROPY_QUANTUM = 0.0001d;\n\n    /// <summary>\n    /// Represents the allowed entropy deviation between the cluster's current entropy, against the theoretical maximum.\n    /// Values lower than this are practically considered as \"maximum\", and the current rebalancing session will stop.\n    /// This acts as a base rate if <see cref=\"ScaleAllowedEntropyDeviation\"/> is set to <see langword=\"true\"/>.\n    /// </summary>\n    /// <remarks>Allowed range is: (0-0.1]</remarks>\n    public double AllowedEntropyDeviation { get; set; } = DEFAULT_ALLOWED_ENTROPY_DEVIATION;\n\n    /// <summary>\n    /// The default value of <see cref=\"AllowedEntropyDeviation\"/>.\n    /// </summary>\n    public const double DEFAULT_ALLOWED_ENTROPY_DEVIATION = 0.0001d;\n\n    /// <summary>\n    /// Determines whether <see cref=\"AllowedEntropyDeviation\"/> should be scaled dynamically\n    /// based on the total number of activations. When set to <see langword=\"true\"/>, the allowed entropy\n    /// deviation will increase logarithmically after reaching <see cref=\"ScaledEntropyDeviationActivationThreshold\"/>,\n    /// and will cap at <see cref=\"MAX_SCALED_ENTROPY_DEVIATION\"/>.\n    /// </summary>\n    /// <remarks>This is in place because a deviation of say 10 activations has far lesser\n    /// impact on a total of 100,000 activations than it does for say 1,000 activations.</remarks>\n    public bool ScaleAllowedEntropyDeviation { get; set; } = DEFAULT_SCALE_ALLOWED_ENTROPY_DEVIATION;\n\n    /// <summary>\n    /// The default value of <see cref=\"ScaleAllowedEntropyDeviation\"/>.\n    /// </summary>\n    public const bool DEFAULT_SCALE_ALLOWED_ENTROPY_DEVIATION = true;\n\n    /// <summary>\n    /// The maximum value allowed when <see cref=\"ScaleAllowedEntropyDeviation\"/> is <see langword=\"true\"/>.\n    /// </summary>\n    public const double MAX_SCALED_ENTROPY_DEVIATION = 0.1d;\n\n    /// <summary>\n    /// Determines the number of activations that must be active during any rebalancing cycle, in order for <see cref=\"ScaleAllowedEntropyDeviation\"/>\n    /// (if, and only if, its <see langword=\"true\"/>) to begin scaling the <see cref=\"AllowedEntropyDeviation\"/>.\n    /// </summary>\n    /// <remarks>\n    /// <para>Allowed range: [1000-∞)</para>\n    /// <para><strong>Values lower than the default are discouraged.</strong></para>\n    /// </remarks>\n    public int ScaledEntropyDeviationActivationThreshold { get; set; } = DEFAULT_SCALED_ENTROPY_DEVIATION_ACTIVATION_THRESHOLD;\n\n    /// <summary>\n    /// The default value of <see cref=\"ScaledEntropyDeviationActivationThreshold\"/>.\n    /// </summary>\n    public const int DEFAULT_SCALED_ENTROPY_DEVIATION_ACTIVATION_THRESHOLD = 10_000;\n\n    /// <summary>\n    /// <para>Represents the weight that is given to the number of rebalancing cycles that have passed during a rebalancing session.</para>\n    /// Changing this value has a far greater impact on the migration rate than <see cref=\"SiloNumberWeight\"/>, and is suitable for controlling the session duration.\n    /// <para>Pick higher values if you want a faster migration rate.</para>\n    /// </summary>\n    /// <remarks>Allowed range: (0-1]</remarks>\n    public double CycleNumberWeight { get; set; } = DEFAULT_CYCLE_NUMBER_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"CycleNumberWeight\"/>.\n    /// </summary>\n    public const double DEFAULT_CYCLE_NUMBER_WEIGHT = 0.1d;\n\n    /// <summary>\n    /// <para>Represents the weight that is given to the number of silos in the cluster during a rebalancing session.</para>\n    /// Changing this value has a far lesser impact on the migration rate than <see cref=\"CycleNumberWeight\"/>, and is suitable for fine-tuning.\n    /// <para>Pick lower values if you want a faster migration rate.</para>\n    /// </summary>\n    /// <remarks>Allowed range: [0-1]</remarks>\n    public double SiloNumberWeight { get; set; } = DEFAULT_SILO_NUMBER_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"SiloNumberWeight\"/>.\n    /// </summary>\n    public const double DEFAULT_SILO_NUMBER_WEIGHT = 0.1d;\n\n    /// <summary>\n    /// The maximum allowed number of activations that can be migrated at any given cycle.\n    /// </summary>\n    public int ActivationMigrationCountLimit { get; set; } = DEFAULT_ACTIVATION_MIGRATION_COUNT_LIMIT;\n\n    /// <summary>\n    /// The default value for <see cref=\"ActivationMigrationCountLimit\"/>.\n    /// The default is practically no limit.\n    /// </summary>\n    public const int DEFAULT_ACTIVATION_MIGRATION_COUNT_LIMIT = int.MaxValue;\n}\n\ninternal sealed class ActivationRebalancerOptionsValidator(\n    IOptions<ActivationRebalancerOptions> options,\n    IOptions<DeploymentLoadPublisherOptions> publisherOptions) : IConfigurationValidator\n{\n    private readonly ActivationRebalancerOptions _options = options.Value;\n    private readonly DeploymentLoadPublisherOptions _publisherOptions = publisherOptions.Value;\n\n    public void ValidateConfiguration()\n    {\n        if (_options.SessionCyclePeriod < 2 * _publisherOptions.DeploymentLoadPublisherRefreshTime)\n        {\n            throw new OrleansConfigurationException(\n                $\"{nameof(ActivationRebalancerOptions.SessionCyclePeriod)} must be at least \" +\n                $\"{$\"2 x {nameof(DeploymentLoadPublisherOptions.DeploymentLoadPublisherRefreshTime)}\"}\");\n        }\n\n        if (_options.MaxStagnantCycles <= 0)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.MaxStagnantCycles)} must be greater than 0\");\n        }\n\n        if (_options.EntropyQuantum <= 0d || _options.EntropyQuantum > 0.1d)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.EntropyQuantum)} must be in greater than 0, and less or equal 0.1\");\n        }\n\n        if (_options.AllowedEntropyDeviation <= 0d || _options.AllowedEntropyDeviation > 0.1d)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.AllowedEntropyDeviation)} must be in greater than 0, and less or equal 0.1\");\n        }\n\n        if (_options.CycleNumberWeight <= 0d || _options.CycleNumberWeight > 1d)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.CycleNumberWeight)} must be in greater than 0, and less or equal to 1\");\n        }\n\n        if (_options.SiloNumberWeight < 0d || _options.SiloNumberWeight > 1d)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.SiloNumberWeight)} must be in greater than or equal to 0, and less or equal to 1\");\n        }\n\n        if (_options.ActivationMigrationCountLimit < 1)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.ActivationMigrationCountLimit)} must be greater than 0\");\n        }\n\n        if (_options.ScaledEntropyDeviationActivationThreshold < 1_000)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRebalancerOptions.ScaledEntropyDeviationActivationThreshold)} must be greater than or equal to 1000\");\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/ActivationRepartitionerOptions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration;\n\npublic sealed class ActivationRepartitionerOptions\n{\n    /// <summary>\n    /// <para>\n    /// The maximum number of edges to retain in-memory during a repartitioning round. An edge represents how many calls were made from one grain to another.\n    /// </para>\n    /// <para>\n    /// If this number is N, it does not mean that N activations will be migrated after a repartitioning round.\n    /// It also does not mean that if any activation ranked very high, that it will rank high at the next cycle.\n    /// At the most extreme case, the number of activations that will be migrated, will equal this number, so this should give you some idea as to setting a reasonable value for this.\n    /// </para>\n    /// </summary>\n    /// <remarks>\n    /// In order to preserve memory, the most heaviest links are recorded in a probabilistic way, so there is an inherent error associated with that.\n    /// That error is inversely proportional to this value, so values under 100 are not recommended. If you notice that the system is not converging fast enough, do consider increasing this number.\n    /// </remarks>\n    public int MaxEdgeCount { get; set; } = DEFAULT_MAX_EDGE_COUNT;\n\n    /// <summary>\n    /// The default value of <see cref=\"MaxEdgeCount\"/>.\n    /// </summary>\n    public const int DEFAULT_MAX_EDGE_COUNT = 10_000;\n\n    /// <summary>\n    /// The minimum time between initiating a repartitioning round.\n    /// </summary>\n    /// <remarks>The actual due time is picked randomly between this and <see cref=\"MaxRoundPeriod\"/>.</remarks>\n    public TimeSpan MinRoundPeriod { get; set; } = DEFAULT_MINUMUM_ROUND_PERIOD;\n\n    /// <summary>\n    /// The default value of <see cref=\"MinRoundPeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_MINUMUM_ROUND_PERIOD = TimeSpan.FromMinutes(1);\n\n    /// <summary>\n    /// The maximum time between initiating a repartitioning round.\n    /// </summary>\n    /// <remarks>\n    /// <para>The actual due time is picked randomly between this and <see cref=\"MinRoundPeriod\"/>.</para>\n    /// <para>For optimal results, you should aim to give this an extra 10 seconds multiplied by the maximum anticipated silo count in the cluster.</para>\n    /// </remarks>\n    public TimeSpan MaxRoundPeriod { get; set; } = DEFAULT_MAXIMUM_ROUND_PERIOD;\n\n    /// <summary>\n    /// The default value of <see cref=\"MaxRoundPeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_MAXIMUM_ROUND_PERIOD = TimeSpan.FromMinutes(2);\n\n    /// <summary>\n    /// The minimum time needed for a silo to recover from a previous repartitioning round.\n    /// Until this time has elapsed, this silo will not take part in any repartitioning attempt from another silo.\n    /// </summary>\n    public TimeSpan RecoveryPeriod { get; set; } = DEFAULT_RECOVERY_PERIOD;\n\n    /// <summary>\n    /// The default value of <see cref=\"RecoveryPeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_RECOVERY_PERIOD = TimeSpan.FromMinutes(1);\n\n    /// <summary>\n    /// The maximum number of unprocessed edges to buffer. If this number is exceeded, the oldest edges will be discarded.\n    /// </summary>\n    public int MaxUnprocessedEdges { get; set; } = DEFAULT_MAX_UNPROCESSED_EDGES;\n\n    /// <summary>\n    /// The default value of <see cref=\"MaxUnprocessedEdges\"/>.\n    /// </summary>\n    public const int DEFAULT_MAX_UNPROCESSED_EDGES = 100_000;\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to enable the local vertex filter. This filter tracks which\n    /// vertices are well-partitioned (moving them from the local host would be detrimental) and collapses them\n    /// into a single per-silo vertex to reduce the space required to track edges involving that vertex. The result\n    /// is a reduction in accuracy but a potentially significant increase in effectiveness of the repartitioner, since\n    /// well-partitioned edges will not dominate the top-K data structure, leaving sufficient room to track\n    /// non-well-partitioned vertices. This is enabled by default.\n    /// </summary>\n    public bool AnchoringFilterEnabled { get; set; } = DEFAULT_ANCHORING_FILTER_ENABLED;\n\n    /// <summary>\n    /// The default value of <see cref=\"AnchoringFilterEnabled\"/>.\n    /// </summary>\n    public const bool DEFAULT_ANCHORING_FILTER_ENABLED = true;\n\n    /// <summary>\n    /// The maximum allowed error rate when <see cref=\"AnchoringFilterEnabled\"/> is set to <see langword=\"true\"/>, otherwise this does not apply.\n    /// </summary>\n    /// <remarks>Allowed range: [0.001 - 0.01](0.1% - 1%)</remarks>\n    public double ProbabilisticFilteringMaxAllowedErrorRate { get; set; } = DEFAULT_PROBABILISTIC_FILTERING_MAX_ALLOWED_ERROR;\n\n    /// <summary>\n    /// The default value of <see cref=\"ProbabilisticFilteringMaxAllowedErrorRate\"/>.\n    /// </summary>\n    public const double DEFAULT_PROBABILISTIC_FILTERING_MAX_ALLOWED_ERROR = 0.01d;\n\n    /// <summary>\n    /// <para>\n    /// Determines how long anchoring history is retained. A lower generation count keeps the filter fresher, but might forget anchored grains too quickly.\n    /// A higher generation count retains history longer, but increases the memory usage and the risk of saturation.\n    /// </para>\n    /// <para>\n    /// Because the filter decays exactly once per repartitioning round, the actual time a \"cold\" grain remains anchored is directly tied to \n    /// <see cref=\"MinRoundPeriod\"/> and <see cref=\"MaxRoundPeriod\"/>. \n    /// For example with the default of 3 generations and round periods randomly firing between 1-2 mins, a grain that goes completely \n    /// \"cold\" will be retained in the filter for 4.5 mins (on average) before being dropped.\n    /// </para>\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// Setting this value to 1 effectively disables retention. The filter will be compltely cleared at the start of every \n    /// repartitioning round, meaning a grain must be continuusly active in the exact current cycle to remain anchored.\n    /// This makes the filter highly reactive to current traffic, but prone to forgetting anchored grains during brief idle periods.\n    /// </para>\n    /// </remarks>\n    public int AnchoringFilterGenerations { get; set; } = DEFAULT_ANCHORING_FILTER_GENERATIONS;\n\n    /// <summary>\n    /// The default value of <see cref=\"AnchoringFilterGenerations\"/>.\n    /// </summary>\n    public const int DEFAULT_ANCHORING_FILTER_GENERATIONS = 3;\n}\n\ninternal sealed class ActivationRepartitionerOptionsValidator(IOptions<ActivationRepartitionerOptions> options) : IConfigurationValidator\n{\n    private readonly ActivationRepartitionerOptions _options = options.Value;\n\n    public void ValidateConfiguration()\n    {\n        if (_options.MaxEdgeCount <= 0)\n        {\n            ThrowMustBeGreaterThanZero(nameof(ActivationRepartitionerOptions.MaxEdgeCount));\n        }\n\n        if (_options.MaxUnprocessedEdges <= 0)\n        {\n            ThrowMustBeGreaterThanZero(nameof(ActivationRepartitionerOptions.MaxUnprocessedEdges));\n        }\n\n        if (_options.MinRoundPeriod < TimeSpan.Zero)\n        {\n            ThrowMustBeGreaterThanOrEqualToZero(nameof(ActivationRepartitionerOptions.MinRoundPeriod));\n        }\n\n        if (_options.MaxRoundPeriod <= TimeSpan.Zero)\n        {\n            ThrowMustBeGreaterThanZero(nameof(ActivationRepartitionerOptions.MaxRoundPeriod));\n        }\n\n        if (_options.RecoveryPeriod < TimeSpan.Zero)\n        {\n            ThrowMustBeGreaterThanOrEqualToZero(nameof(ActivationRepartitionerOptions.RecoveryPeriod));\n        }\n\n        if (_options.MaxRoundPeriod < _options.MinRoundPeriod)\n        {\n            ThrowMustBeGreaterThanOrEqualTo(nameof(ActivationRepartitionerOptions.MaxRoundPeriod), nameof(ActivationRepartitionerOptions.MinRoundPeriod));\n        }\n\n        if (_options.MinRoundPeriod < _options.RecoveryPeriod)\n        {\n            ThrowMustBeGreaterThanOrEqualTo(nameof(ActivationRepartitionerOptions.MinRoundPeriod), nameof(ActivationRepartitionerOptions.RecoveryPeriod));\n        }\n\n        if (_options.ProbabilisticFilteringMaxAllowedErrorRate < 0.001d || _options.ProbabilisticFilteringMaxAllowedErrorRate > 0.01d)\n        {\n            throw new OrleansConfigurationException($\"{nameof(ActivationRepartitionerOptions.ProbabilisticFilteringMaxAllowedErrorRate)} must be inclusive between [0.001 - 0.01](0.1% - 1%)\");\n        }\n\n        if (_options.AnchoringFilterGenerations <= 0)\n        {\n            ThrowMustBeGreaterThanZero(nameof(ActivationRepartitionerOptions.AnchoringFilterGenerations));\n        }\n    }\n\n    private static void ThrowMustBeGreaterThanOrEqualToZero(string propertyName)\n        => throw new OrleansConfigurationException($\"{propertyName} must be greater than or equal to 0.\");\n\n    private static void ThrowMustBeGreaterThanZero(string propertyName)\n        => throw new OrleansConfigurationException($\"{propertyName} must be greater than 0.\");\n\n    private static void ThrowMustBeGreaterThanOrEqualTo(string name1, string name2)\n        => throw new OrleansConfigurationException($\"{name1} must be greater than or equal to {name2}.\");\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/ConsistentRingOptions.cs",
    "content": "namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration options for consistent hashing algorithm, used to balance resource allocations across the cluster.\n    /// </summary>\n    public class ConsistentRingOptions\n    {\n        /// <summary>\n        /// Gets or sets the number of registrations a silo maintains in a consistent hash ring.  This affects the probabilistic\n        ///   balancing of resource allocations across the cluster.  More virtual buckets increase the probability of evenly balancing\n        ///   while minimally increasing management cost. \n        /// </summary>\n        public int NumVirtualBucketsConsistentRing { get; set; } = DEFAULT_NUM_VIRTUAL_RING_BUCKETS;\n\n        /// <summary>\n        /// The default number of virtual ring buckets.\n        /// </summary>\n        public const int DEFAULT_NUM_VIRTUAL_RING_BUCKETS = 30;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to enable the use of virtual buckets.\n        /// </summary>\n        public bool UseVirtualBucketsConsistentRing { get; set; } = DEFAULT_USE_VIRTUAL_RING_BUCKETS;\n\n        /// <summary>\n        /// The default value for <see cref=\"UseVirtualBucketsConsistentRing\"/>.\n        /// </summary>\n        public const bool DEFAULT_USE_VIRTUAL_RING_BUCKETS = true;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/DeploymentLoadPublisherOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring deployment load publishing.\n    /// </summary>\n    public class DeploymentLoadPublisherOptions\n    {\n        /// <summary>\n        /// Interval in which deployment statistics are published.\n        /// </summary>\n        public TimeSpan DeploymentLoadPublisherRefreshTime { get; set; } = DEFAULT_DEPLOYMENT_LOAD_PUBLISHER_REFRESH_TIME;\n        public static readonly TimeSpan DEFAULT_DEPLOYMENT_LOAD_PUBLISHER_REFRESH_TIME = TimeSpan.FromSeconds(1);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/GrainCollectionOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Silo options for idle grain collection.\n    /// </summary>\n    public class GrainCollectionOptions\n    {\n        /// <summary>\n        /// Regulates the periodic collection of inactive grains.\n        /// </summary>\n        public TimeSpan CollectionQuantum { get; set; } = DEFAULT_COLLECTION_QUANTUM;\n\n        /// <summary>\n        /// The default value for <see cref=\"CollectionQuantum\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_COLLECTION_QUANTUM = TimeSpan.FromMinutes(1);\n\n        /// <summary>\n        /// Gets or sets the default period of inactivity necessary for a grain to be available for collection and deactivation.\n        /// </summary>\n        public TimeSpan CollectionAge { get; set; } = TimeSpan.FromMinutes(15);\n\n        /// <summary>\n        /// Period of inactivity necessary for a grain to be available for collection and deactivation by grain type.\n        /// </summary>\n        public Dictionary<string, TimeSpan> ClassSpecificCollectionAge { get; set; } = new Dictionary<string, TimeSpan>();\n\n        /// <summary>\n        /// Timeout value before giving up when trying to activate a grain.\n        /// </summary>\n        public TimeSpan ActivationTimeout { get; set; } = DEFAULT_ACTIVATION_TIMEOUT;\n\n        /// <summary>\n        /// The default value for <see cref=\"ActivationTimeout\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_ACTIVATION_TIMEOUT = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Timeout value before giving up when trying to deactivate a grain activation\n        /// (waiting for all timers to stop and calling Grain.OnDeactivate())\n        /// </summary>\n        public TimeSpan DeactivationTimeout { get; set; } = DEFAULT_DEACTIVATION_TIMEOUT;\n\n        /// <summary>\n        /// The default value for <see cref=\"DeactivationTimeout\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_DEACTIVATION_TIMEOUT = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Indicates if memory pressure should trigger grain activation shedding.\n        /// </summary>\n        /// <remarks>\n        /// If set to true, the silo will shed grain activations when memory usage exceeds the specified limits.\n        /// See <see cref=\"MemoryUsageLimitPercentage\"/>, <see cref=\"MemoryUsageTargetPercentage\"/>, and <see cref=\"MemoryUsagePollingPeriod\"/> for configuration.\n        /// </remarks>\n        public bool EnableActivationSheddingOnMemoryPressure { get; set; }\n\n        /// <summary>\n        /// The interval at which memory usage is polled.\n        /// </summary>\n        public TimeSpan MemoryUsagePollingPeriod { get; set; } = TimeSpan.FromSeconds(5);\n\n        /// <summary>\n        /// The memory usage percentage (0–100) at which grain collection is triggered.\n        /// Must be greater than 0 and less than or equal to 100.\n        /// </summary>\n        public double MemoryUsageLimitPercentage { get; set; } = 80;\n\n        /// <summary>\n        /// The target memory usage percentage (0–100) to reach after grain collection.\n        /// Must be greater than 0, less than or equal to 100, and less than <see cref=\"MemoryUsageLimitPercentage\"/>.\n        /// </summary>\n        public double MemoryUsageTargetPercentage { get; set; } = 75;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/GrainDirectoryOptions.cs",
    "content": "\nusing System;\nusing Orleans.Runtime.GrainDirectory;\n\nnamespace Orleans.Configuration\n{\n    public class GrainDirectoryOptions\n    {\n        /// <summary>\n        /// Configuration type that controls the type of the grain directory caching algorithm that silo use.\n        /// </summary>\n        public enum CachingStrategyType\n        {\n            /// <summary>Don't cache.</summary>\n            None,\n            /// <summary>Standard fixed-size LRU.</summary>\n            LRU,\n            /// <summary>Adaptive caching with fixed maximum size and refresh. This option should be used in production.</summary>\n            [Obsolete(\"Adaptive caching is deprecated in favor of LRU and will be removed in a future version. This value is now an alias for LRU.\")]\n            Adaptive,\n            /// <summary>Custom cache implementation, configured by registering an <see cref=\"IGrainDirectoryCache\"/> implementation in the dependency injection container.</summary>\n            Custom\n        }\n\n        /// <summary>\n        /// Gets or sets the caching strategy to use.\n        /// The options are None, which means don't cache directory entries locally;\n        /// LRU, which indicates that a standard fixed-size least recently used strategy should be used; and\n        /// Adaptive, which indicates that an adaptive strategy with a fixed maximum size should be used.\n        /// The LRU strategy is used by default.\n        /// </summary>\n        public CachingStrategyType CachingStrategy { get; set; } = DEFAULT_CACHING_STRATEGY;\n\n        /// <summary>\n        /// The default value for <see cref=\"CachingStrategy\"/>.\n        /// </summary>\n        public const CachingStrategyType DEFAULT_CACHING_STRATEGY = CachingStrategyType.LRU;\n\n        /// <summary>\n        /// Gets or sets the maximum number of grains to cache directory information for.\n        /// </summary>\n        public int CacheSize { get; set; } = DEFAULT_CACHE_SIZE;\n\n        /// <summary>\n        /// The default value for <see cref=\"CacheSize\"/>.\n        /// </summary>\n        public const int DEFAULT_CACHE_SIZE = 1_000_000;\n\n        /// <summary>\n        /// Gets or sets the initial (minimum) time, in seconds, to keep a cache entry before revalidating.\n        /// </summary>\n        [Obsolete(\"InitialCacheTTL is deprecated and will be removed in a future version.\")]\n        public TimeSpan InitialCacheTTL { get; set; } = DEFAULT_INITIAL_CACHE_TTL;\n\n        /// <summary>\n        /// The default value for <see cref=\"InitialCacheTTL\"/>.\n        /// </summary>\n        [Obsolete(\"DEFAULT_INITIAL_CACHE_TTL is deprecated and will be removed in a future version.\")]\n        public static readonly TimeSpan DEFAULT_INITIAL_CACHE_TTL = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Gets or sets the maximum time, in seconds, to keep a cache entry before revalidating.\n        /// </summary>\n        [Obsolete(\"MaximumCacheTTL is deprecated and will be removed in a future version.\")]\n        public TimeSpan MaximumCacheTTL { get; set; } = DEFAULT_MAXIMUM_CACHE_TTL;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaximumCacheTTL\"/>.\n        /// </summary>\n        [Obsolete(\"DEFAULT_MAXIMUM_CACHE_TTL is deprecated and will be removed in a future version.\")]\n        public static readonly TimeSpan DEFAULT_MAXIMUM_CACHE_TTL = TimeSpan.FromSeconds(240);\n\n        /// <summary>\n        /// Gets or sets the factor by which cache entry TTLs should be extended when they are found to be stable.\n        /// </summary>\n        [Obsolete(\"CacheTTLExtensionFactor is deprecated and will be removed in a future version.\")]\n        public double CacheTTLExtensionFactor { get; set; } = DEFAULT_TTL_EXTENSION_FACTOR;\n\n        /// <summary>\n        /// The default value for <see cref=\"CacheTTLExtensionFactor\"/>.\n        /// </summary>\n        [Obsolete(\"DEFAULT_TTL_EXTENSION_FACTOR is deprecated and will be removed in a future version.\")]\n        public const double DEFAULT_TTL_EXTENSION_FACTOR = 2.0;\n\n        /// <summary>\n        /// Gets or sets the time span between when we have added an entry for an activation to the grain directory and when we are allowed\n        /// to conditionally remove that entry. \n        /// Conditional deregistration is used for lazy clean-up of activations whose prompt deregistration failed for some reason (e.g., message failure).\n        /// This should always be at least one minute, since we compare the times on the directory partition, so message delays and clcks skues have\n        /// to be allowed.\n        /// </summary>\n        public TimeSpan LazyDeregistrationDelay { get; set; } = DEFAULT_UNREGISTER_RACE_DELAY;\n\n        /// <summary>\n        /// The default value for <see cref=\"LazyDeregistrationDelay\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_UNREGISTER_RACE_DELAY = TimeSpan.FromMinutes(1);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/OptionsLogger.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal class SiloOptionsLogger : OptionsLogger, ILifecycleParticipant<ISiloLifecycle>\n    {\n        public SiloOptionsLogger(ILogger<SiloOptionsLogger> logger, IServiceProvider services)\n            : base(logger, services)\n        {\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<SiloOptionsLogger>(ServiceLifecycleStage.First, this.OnStart);\n        }\n\n        public Task OnStart(CancellationToken token)\n        {\n            this.LogOptions();\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/ResourceOptimizedPlacementOptions.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration;\n\n/// <summary>\n/// Settings which regulate the placement of grains across a cluster when using <see cref=\"ResourceOptimizedPlacement\"/>.\n/// </summary>\n/// <remarks><i>All 'weight' properties, are relative to each other.</i></remarks>\npublic sealed class ResourceOptimizedPlacementOptions\n{\n    /// <summary>\n    /// The importance of the CPU usage by the silo.\n    /// </summary>\n    /// <remarks><i>\n    /// <para>A <u>higher</u> value results in the placement favoring silos with <u>lower</u> cpu usage.</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int CpuUsageWeight { get; set; } = DEFAULT_CPU_USAGE_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"CpuUsageWeight\"/>.\n    /// </summary>\n    public const int DEFAULT_CPU_USAGE_WEIGHT = 40;\n\n    /// <summary>\n    /// The importance of the memory usage by the silo.\n    /// </summary>\n    /// <remarks><i>\n    /// <para>A <u>higher</u> value results in the placement favoring silos with <u>lower</u> memory usage.</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int MemoryUsageWeight { get; set; } = DEFAULT_MEMORY_USAGE_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"MemoryUsageWeight\"/>.\n    /// </summary>\n    public const int DEFAULT_MEMORY_USAGE_WEIGHT = 20;\n\n    /// <summary>\n    /// The importance of the available memory to the silo.\n    /// </summary>\n    /// <remarks><i>\n    /// <para>A <u>higher</u> values results in the placement favoring silos with <u>higher</u> available memory.</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int AvailableMemoryWeight { get; set; } = DEFAULT_AVAILABLE_MEMORY_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"AvailableMemoryWeight\"/>.\n    /// </summary>\n    public const int DEFAULT_AVAILABLE_MEMORY_WEIGHT = 20;\n\n    /// <summary>\n    /// The importance of the maximum available memory to the silo.\n    /// </summary>\n    /// <remarks><i>\n    /// <para>A <u>higher</u> values results in the placement favoring silos with <u>higher</u> maximum available memory.</para>\n    /// <para>This may have an impact in clusters with resources distributed unevenly across silos.</para>\n    /// <para>This relates strongly to the physical memory in the silo, and the configured memory limit (if it has been configured).</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int MaxAvailableMemoryWeight { get; set; } = DEFAULT_MAX_AVAILABLE_MEMORY_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"MaxAvailableMemoryWeight\"/>.\n    /// </summary>\n    public const int DEFAULT_MAX_AVAILABLE_MEMORY_WEIGHT = 5;\n\n    /// <summary>\n    /// The importance of the current activation count to the silo.\n    /// </summary>\n    /// <remarks><i>\n    /// <para>A <u>higher</u> values results in the placement favoring silos with <u>lower</u> activation count.</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int ActivationCountWeight { get; set; } = DEFAULT_ACTIVATION_COUNT_WEIGHT;\n\n    /// <summary>\n    /// The default value of <see cref=\"ActivationCountWeight\"/>.\n    /// </summary>\n    public const int DEFAULT_ACTIVATION_COUNT_WEIGHT = 15;\n\n    /// <summary>\n    /// The specified margin for which: if two silos (one of them being the local to the current pending activation), have a utilization score that should be considered \"the same\" within this margin.\n    /// <list type=\"bullet\">\n    /// <item><description>When this value is 0, then the policy will always favor the silo with the lower resource utilization, even if that silo is remote to the current pending activation.</description></item>\n    /// <item><description>When this value is 100, then the policy will always favor the local silo, regardless of its relative utilization score. This policy essentially becomes equivalent to <see cref=\"PreferLocalPlacement\"/>.</description></item>\n    /// </list>\n    /// </summary>\n    /// <remarks><i>\n    /// <para>Do favor a lower value for this e.g: 5-10</para>\n    /// <para>Valid range is [0-100]</para>\n    /// </i></remarks>\n    public int LocalSiloPreferenceMargin { get; set; } = DEFAULT_LOCAL_SILO_PREFERENCE_MARGIN;\n\n    /// <summary>\n    /// The default value of <see cref=\"LocalSiloPreferenceMargin\"/>.\n    /// </summary>\n    public const int DEFAULT_LOCAL_SILO_PREFERENCE_MARGIN = 5;\n}\n\ninternal sealed class ResourceOptimizedPlacementOptionsValidator\n    (IOptions<ResourceOptimizedPlacementOptions> options) : IConfigurationValidator\n{\n    private readonly ResourceOptimizedPlacementOptions _options = options.Value;\n\n    public void ValidateConfiguration()\n    {\n        if (_options.CpuUsageWeight < 0 || _options.CpuUsageWeight > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.CpuUsageWeight));\n        }\n\n        if (_options.MemoryUsageWeight < 0 || _options.MemoryUsageWeight > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.MemoryUsageWeight));\n        }\n\n        if (_options.AvailableMemoryWeight < 0 || _options.AvailableMemoryWeight > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.AvailableMemoryWeight));\n        }\n\n        if (_options.MaxAvailableMemoryWeight < 0 || _options.MaxAvailableMemoryWeight > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.MaxAvailableMemoryWeight));\n        }\n\n        if (_options.ActivationCountWeight < 0 || _options.ActivationCountWeight > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.ActivationCountWeight));\n        }\n\n        if (_options.LocalSiloPreferenceMargin < 0 || _options.LocalSiloPreferenceMargin > 100)\n        {\n            ThrowOutOfRange(nameof(ResourceOptimizedPlacementOptions.LocalSiloPreferenceMargin));\n        }\n\n        static void ThrowOutOfRange(string propertyName)\n            => throw new OrleansConfigurationException($\"{propertyName} must be inclusive between [0-100]\");\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/SchedulingOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring scheduler behavior.\n    /// </summary>\n    public class SchedulingOptions\n    {\n        /// <summary>\n        /// Gets or sets the work item queuing delay threshold, at which a warning log message is written.\n        /// That is, if the delay between enqueuing the work item and executing the work item is greater than DelayWarningThreshold, a warning log is written.\n        /// </summary>\n        public TimeSpan DelayWarningThreshold { get; set; } = DEFAULT_DELAY_WARNING_THRESHOLD;\n\n        /// <summary>\n        /// The default value for <see cref=\"DelayWarningThreshold\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_DELAY_WARNING_THRESHOLD = TimeSpan.FromMilliseconds(10000); // 10 seconds\n\n        /// <summary>\n        /// Gets or sets the soft time limit on the duration of activation macro-turn (a number of micro-turns). \n        /// If an activation was running its micro-turns longer than this, we will give up the thread.\n        /// If this is set to zero or a negative number, then the full work queue is drained (MaxWorkItemsPerTurn allowing).\n        /// </summary>\n        public TimeSpan ActivationSchedulingQuantum { get; set; } = DEFAULT_ACTIVATION_SCHEDULING_QUANTUM;\n\n        /// <summary>\n        /// The default value for <see cref=\"ActivationSchedulingQuantum\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_ACTIVATION_SCHEDULING_QUANTUM = TimeSpan.FromMilliseconds(100);\n\n        /// <summary>\n        /// Gets or sets the soft time limit to generate trace warning when the micro-turn executes longer then this period in CPU. \n        /// </summary>\n        public TimeSpan TurnWarningLengthThreshold { get; set; } = DEFAULT_TURN_WARNING_THRESHOLD;\n\n        /// <summary>\n        /// The default value for <see cref=\"TurnWarningLengthThreshold\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_TURN_WARNING_THRESHOLD = TimeSpan.FromMilliseconds(1_000);\n\n        /// <summary>\n        /// Gets or sets the per work group limit of how many items can be queued up before warnings are generated.\n        /// </summary>\n        public int MaxPendingWorkItemsSoftLimit { get; set; } = DEFAULT_MAX_PENDING_ITEMS_SOFT_LIMIT;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxPendingWorkItemsSoftLimit\"/>.\n        /// </summary>\n        public const int DEFAULT_MAX_PENDING_ITEMS_SOFT_LIMIT = 0;\n\n        /// <summary>\n        /// Gets or sets the period of time after which to log errors for tasks scheduled to stopped activations.\n        /// </summary>\n        public TimeSpan StoppedActivationWarningInterval { get; set; } = TimeSpan.FromMinutes(1);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/SiloMessagingOptions.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Specifies global messaging options that are silo related.\n    /// </summary>\n    public class SiloMessagingOptions : MessagingOptions\n    {\n        /// <summary>\n        /// <see cref=\"SystemResponseTimeout\"/>.\n        /// </summary>\n        private TimeSpan systemResponseTimeout = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// Gets or sets the number of parallel queues and attendant threads used by the silo to send outbound\n        /// messages (requests, responses, and notifications) to other silos.\n        /// If this attribute is not specified, then System.Environment.ProcessorCount is used.\n        /// </summary>\n        public int SiloSenderQueues { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of parallel queues and attendant threads used by the silo Gateway to send outbound\n        ///  messages (requests, responses, and notifications) to clients that are connected to it.\n        ///  If this attribute is not specified, then System.Environment.ProcessorCount is used.\n        /// </summary>\n        public int GatewaySenderQueues { get; set; }\n\n        /// <summary>\n        /// Gets or sets the maximal number of times a message is being forwarded from one silo to another.\n        /// Forwarding is used internally by the runtime as a recovery mechanism when silos fail and the membership is unstable.\n        /// In such times the messages might not be routed correctly to destination, and runtime attempts to forward such messages a number of times before rejecting them.\n        /// </summary>\n        public int MaxForwardCount { get; set; } = 2;\n\n        /// <summary>\n        /// Gets or sets the period of time a gateway will wait before dropping a disconnected client.\n        /// </summary>\n        public TimeSpan ClientDropTimeout { get; set; } = Constants.DEFAULT_CLIENT_DROP_TIMEOUT;\n\n        /// <summary>\n        /// Gets or sets the interval in which the list of connected clients is refreshed.\n        /// </summary>\n        public TimeSpan ClientRegistrationRefresh { get; set; } = DEFAULT_CLIENT_REGISTRATION_REFRESH;\n\n        /// <summary>\n        /// The default value for <see cref=\"ClientRegistrationRefresh\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_CLIENT_REGISTRATION_REFRESH = TimeSpan.FromMinutes(5);\n\n        /// <summary>\n        /// Gets or sets the period of time a gateway will wait after notifying connected client before continuing the\n        /// shutdown process\n        /// </summary>\n        public TimeSpan ClientGatewayShutdownNotificationTimeout { get; set; } = DEFAULT_CLIENT_GW_NOTIFICATION_TIMEOUT;\n\n        /// <summary>\n        /// The default value for <see cref=\"ClientGatewayShutdownNotificationTimeout\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_CLIENT_GW_NOTIFICATION_TIMEOUT = TimeSpan.Zero;\n\n        /// <summary>\n        /// Gets or sets the per grain threshold for pending requests.  Generated warning when exceeded.\n        /// </summary>\n        public int MaxEnqueuedRequestsSoftLimit { get; set; } = DEFAULT_MAX_ENQUEUED_REQUESTS_SOFT_LIMIT;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxEnqueuedRequestsSoftLimit\"/>.\n        /// </summary>\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_SOFT_LIMIT = 0;\n\n        /// <summary>\n        /// Gets or sets the per grain threshold for pending requests.  Requests are rejected when exceeded.\n        /// </summary>\n        public int MaxEnqueuedRequestsHardLimit { get; set; } = DEFAULT_MAX_ENQUEUED_REQUESTS_HARD_LIMIT;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxEnqueuedRequestsHardLimit\"/>.\n        /// </summary>\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_HARD_LIMIT = 0;\n\n        /// <summary>\n        /// Gets or sets the per grain threshold for pending requests for stateless workers.  Generated warning when exceeded.\n        /// </summary>\n        public int MaxEnqueuedRequestsSoftLimit_StatelessWorker { get; set; } = DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_SOFT_LIMIT;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxEnqueuedRequestsSoftLimit_StatelessWorker\"/>.\n        /// </summary>\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_SOFT_LIMIT = 0;\n\n        /// <summary>\n        /// Gets or sets the per grain threshold for pending requests for stateless workers.  Requests are rejected when exceeded.\n        /// </summary>\n        public int MaxEnqueuedRequestsHardLimit_StatelessWorker { get; set; } = DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_HARD_LIMIT;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxEnqueuedRequestsHardLimit_StatelessWorker\"/>.\n        /// </summary>\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_HARD_LIMIT = 0;\n\n        /// <summary>\n        /// Gets or sets the maximum time that a request can take before the activation is reported as \"blocked\"\n        /// </summary>\n        public TimeSpan MaxRequestProcessingTime { get; set; } = DEFAULT_MAX_REQUEST_PROCESSING_TIME;\n\n        /// <summary>\n        /// The default value for <see cref=\"MaxRequestProcessingTime\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_MAX_REQUEST_PROCESSING_TIME = TimeSpan.FromHours(2);\n\n        /// <summary>\n        /// Gets or sets a value indicating whether it is assumed that all hosts are identical in terms of the grain interfaces and classes which they support.\n        /// </summary>\n        /// <remarks>\n        /// For testing purposes only.\n        /// </remarks>\n        public bool AssumeHomogenousSilosForTesting { get; set; } = false;\n\n        /// <summary>\n        /// Gets or sets the period of time the silo will wait to reroute queued messages before it continues shutting down. \n        /// </summary>\n        [Obsolete(\"Unused, will be removed in a future version.\")]\n        public TimeSpan ShutdownRerouteTimeout { get; set; } = DEFAULT_SHUTDOWN_REROUTE_TIMEOUT;\n\n        /// <summary>\n        /// The default value for <see cref=\"ShutdownRerouteTimeout\"/>.\n        /// </summary>\n        [Obsolete(\"Unused, will be removed in a future version.\")]\n        public static readonly TimeSpan DEFAULT_SHUTDOWN_REROUTE_TIMEOUT = TimeSpan.Zero;\n\n        /// <summary>\n        /// Gets or sets the default timeout before an internal system request is assumed to have failed.\n        /// </summary>\n        public TimeSpan SystemResponseTimeout\n        {\n            get { return Debugger.IsAttached ? ResponseTimeoutWithDebugger : this.systemResponseTimeout; }\n            set { this.systemResponseTimeout = value; }\n        }\n\n        /// <summary>\n        /// Gets or sets the period of time between analyzing currently executing activation workloads.\n        /// </summary>\n        public TimeSpan GrainWorkloadAnalysisPeriod { get; set; } = TimeSpan.FromSeconds(5);\n\n        /// <summary>\n        /// Gets or sets the period after which a currently executing request is deemed to be slow.\n        /// </summary>\n        /// <remarks>\n        /// This should be set to a value at least <see cref=\"GrainWorkloadAnalysisPeriod\"/> shorter than <see cref=\"MessagingOptions.ResponseTimeout\"/>\n        /// so that there is sufficient time for a long-running request to be detected and a status message to be sent to the client before the client times out.\n        /// </remarks>\n        public TimeSpan RequestProcessingWarningTime { get; set; } = TimeSpan.FromSeconds(20);\n\n        /// <summary>\n        /// Gets or sets the period after which an enqueued request is deemed to be delayed.\n        /// </summary>\n        /// <remarks>\n        /// This should be set to a value at least <see cref=\"GrainWorkloadAnalysisPeriod\"/> shorter than <see cref=\"MessagingOptions.ResponseTimeout\"/>\n        /// so that there is sufficient time for a delayed request to be detected and a status message to be sent to the client before the client times out.\n        /// </remarks>\n        public TimeSpan RequestQueueDelayWarningTime { get; set; } = TimeSpan.FromSeconds(20);\n\n        /// <summary>\n        /// Gets or sets the time to wait for all queued message sent to OutboundMessageQueue before MessageCenter stop and OutboundMessageQueue stop.\n        /// </summary>\n        public TimeSpan WaitForMessageToBeQueuedForOutboundTime { get; set; } = DEFAULT_WAIT_FOR_MESSAGE_TO_BE_QUEUED_FOR_OUTBOUND_TIME;\n\n        /// <summary>\n        /// The default value for <see cref=\"WaitForMessageToBeQueuedForOutboundTime\"/>.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_WAIT_FOR_MESSAGE_TO_BE_QUEUED_FOR_OUTBOUND_TIME = TimeSpan.Zero;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/SiloMessagingOptionsValidator.cs",
    "content": "﻿using Microsoft.Extensions.Options;\n\nnamespace Orleans.Configuration\n{\n    internal class SiloMessagingOptionsValidator : IValidateOptions<SiloMessagingOptions>\n    {\n        public ValidateOptionsResult Validate(string name, SiloMessagingOptions options)\n        {\n            if (options.MaxForwardCount > 255)\n            {\n                return ValidateOptionsResult.Fail($\"Value for {nameof(SiloMessagingOptions)}.{nameof(SiloMessagingOptions.MaxForwardCount)} must not be greater than 255.\");\n            }\n\n            return ValidateOptionsResult.Success;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Options/StatelessWorkerOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration;\n\n/// <summary>\n/// Options that apply globally to stateless worker grains.\n/// </summary>\npublic class StatelessWorkerOptions\n{\n    /// <summary>\n    /// When set to <see langword=\"true\"/>, idle workers will be proactively deactivated by the runtime.\n    /// Otherwise if <see langword=\"false\"/>, than the workers will be deactivated according to <see cref=\"GrainCollectionOptions.CollectionAge\"/>.\n    /// </summary>\n    /// <remarks>You can read more on this <see href=\"https://www.ledjonbehluli.com/posts/orleans_adaptive_stateless_worker/\">here</see></remarks>\n    public bool RemoveIdleWorkers { get; set; } = DEFAULT_REMOVE_IDLE_WORKERS;\n\n    /// <summary>\n    /// The default value for <see cref=\"RemoveIdleWorkers\"/>.\n    /// </summary>\n    public const bool DEFAULT_REMOVE_IDLE_WORKERS = true;\n\n    /// <summary>\n    /// The time to inspect for idle workers.\n    /// </summary>\n    /// <remarks>This setting has no effect if <see cref=\"RemoveIdleWorkers\"/> is <see langword=\"false\"/>.</remarks>\n    public TimeSpan IdleWorkersInspectionPeriod { get; set; } = DEFAULT_IDLE_WORKERS_INSPECTION_PERIOD;\n\n    /// <summary>\n    /// The default value for <see cref=\"IdleWorkersInspectionPeriod\"/>.\n    /// </summary>\n    public static readonly TimeSpan DEFAULT_IDLE_WORKERS_INSPECTION_PERIOD = TimeSpan.FromMilliseconds(500);\n\n    /// <summary>\n    /// The minimum, consecutive number of idle cycles any given worker must exhibit before it is deemed enough to remove the worker.\n    /// </summary>\n    public int MinIdleCyclesBeforeRemoval { get; set; } = DEFAULT_MIN_IDLE_CYCLES_BEFORE_REMOVAL;\n\n    /// <summary>\n    /// The default value for <see cref=\"MinIdleCyclesBeforeRemoval\"/>.\n    /// </summary>\n    public const int DEFAULT_MIN_IDLE_CYCLES_BEFORE_REMOVAL = 1;\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/SiloConnectionOptions.cs",
    "content": "using System;\nusing Microsoft.AspNetCore.Connections;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for configuring silo networking.\n    /// Implements the <see cref=\"Orleans.Configuration.SiloConnectionOptions.ISiloConnectionBuilderOptions\" />\n    /// </summary>\n    /// <seealso cref=\"Orleans.Configuration.SiloConnectionOptions.ISiloConnectionBuilderOptions\" />\n    public class SiloConnectionOptions : SiloConnectionOptions.ISiloConnectionBuilderOptions\n    {\n        private readonly ConnectionBuilderDelegates siloOutboundDelegates = new ConnectionBuilderDelegates();\n        private readonly ConnectionBuilderDelegates siloInboundDelegates = new ConnectionBuilderDelegates();\n        private readonly ConnectionBuilderDelegates gatewayInboundDelegates = new ConnectionBuilderDelegates();\n\n        /// <summary>\n        /// Configures silo outbound connections.\n        /// </summary>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        public void ConfigureSiloOutboundConnection(Action<IConnectionBuilder> configure) => this.siloOutboundDelegates.Add(configure);\n\n        /// <summary>\n        /// Configures silo inbound connections from other silos.\n        /// </summary>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        public void ConfigureSiloInboundConnection(Action<IConnectionBuilder> configure) => this.siloInboundDelegates.Add(configure);\n\n        /// <summary>\n        /// Configures silo inbound connections from clients.\n        /// </summary>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        public void ConfigureGatewayInboundConnection(Action<IConnectionBuilder> configure) => this.gatewayInboundDelegates.Add(configure);\n\n        /// <inheritdoc/>\n        void ISiloConnectionBuilderOptions.ConfigureSiloOutboundBuilder(IConnectionBuilder builder) => this.siloOutboundDelegates.Invoke(builder);\n\n        /// <inheritdoc/>\n        void ISiloConnectionBuilderOptions.ConfigureSiloInboundBuilder(IConnectionBuilder builder) => this.siloInboundDelegates.Invoke(builder);\n\n        /// <inheritdoc/>\n        void ISiloConnectionBuilderOptions.ConfigureGatewayInboundBuilder(IConnectionBuilder builder) => this.gatewayInboundDelegates.Invoke(builder);\n\n        /// <summary>\n        /// Options for silo networking.\n        /// </summary>\n        public interface ISiloConnectionBuilderOptions\n        {\n            /// <summary>\n            /// Configures the silo outbound connection builder.\n            /// </summary>\n            /// <param name=\"builder\">The builder.</param>\n            public void ConfigureSiloOutboundBuilder(IConnectionBuilder builder);\n\n            /// <summary>\n            /// Configures the silo inbound connection builder.\n            /// </summary>\n            /// <param name=\"builder\">The builder.</param>\n            public void ConfigureSiloInboundBuilder(IConnectionBuilder builder);\n\n            /// <summary>\n            /// Configures the silo gateway connection builder.\n            /// </summary>\n            /// <param name=\"builder\">The builder.</param>\n            public void ConfigureGatewayInboundBuilder(IConnectionBuilder builder);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Validators/GrainCollectionOptionsValidator.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    internal class GrainCollectionOptionsValidator : IConfigurationValidator\n    {\n        private readonly GrainCollectionOptions options;\n\n        public GrainCollectionOptionsValidator(IOptions<GrainCollectionOptions> options)\n        {\n            this.options = options.Value;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (this.options.CollectionQuantum <= TimeSpan.Zero)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.CollectionQuantum)} is set to {options.CollectionQuantum}. \" +\n                    $\"{nameof(GrainCollectionOptions.CollectionQuantum)} must be greater than 0\");\n            }\n\n            if (this.options.CollectionAge <= this.options.CollectionQuantum)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.CollectionAge)} is set to {options.CollectionAge}. \" +\n                    $\"{nameof(GrainCollectionOptions.CollectionAge)} must be greater than {nameof(GrainCollectionOptions.CollectionQuantum)}, \" +\n                    $\"which is set to {this.options.CollectionQuantum}\");\n            }\n            foreach(var classSpecificCollectionAge in this.options.ClassSpecificCollectionAge)\n            {\n                if (classSpecificCollectionAge.Value <= this.options.CollectionQuantum)\n                {\n                    throw new OrleansConfigurationException(\n                        $\"{classSpecificCollectionAge.Key} CollectionAgeLimit is set to {classSpecificCollectionAge.Value}. \" +\n                        $\"CollectionAgeLimit must be greater than {nameof(GrainCollectionOptions.CollectionQuantum)}, \" +\n                        $\"which is set to {this.options.CollectionQuantum}\");\n                }\n            }\n\n            ValidateHighMemoryPressureSettings();\n        }\n\n        private void ValidateHighMemoryPressureSettings()\n        {\n            if (!options.EnableActivationSheddingOnMemoryPressure)\n            {\n                return;\n            }\n\n            if (options.MemoryUsagePollingPeriod <= TimeSpan.Zero)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.MemoryUsagePollingPeriod)} is set to {options.MemoryUsagePollingPeriod}. \" +\n                    $\"{nameof(GrainCollectionOptions.MemoryUsagePollingPeriod)} must be greater than 0\");\n            }\n\n            if (options.MemoryUsageLimitPercentage < 0 || options.MemoryUsageLimitPercentage > 100)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageLimitPercentage)} is set to {options.MemoryUsageLimitPercentage}. \" +\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageLimitPercentage)} must be between 0 and 100\");\n            }\n\n            if (options.MemoryUsageTargetPercentage < 0 || options.MemoryUsageTargetPercentage > 100)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageTargetPercentage)} is set to {options.MemoryUsageTargetPercentage}. \" +\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageTargetPercentage)} must be between 0 and 100\");\n            }\n            if (options.MemoryUsageTargetPercentage >= options.MemoryUsageLimitPercentage)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageTargetPercentage)} is set to {options.MemoryUsageTargetPercentage}. \" +\n                    $\"{nameof(GrainCollectionOptions.MemoryUsageTargetPercentage)} must be less than {nameof(GrainCollectionOptions.MemoryUsageLimitPercentage)}, \" +\n                    $\"which is set to {options.MemoryUsageLimitPercentage}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Configuration/Validators/SiloClusteringValidator.cs",
    "content": "using System;\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Validators;\n\nnamespace Orleans.Runtime.Configuration\n{\n    /// <summary>\n    /// Validates basic cluster membership configuration.\n    /// </summary>\n    internal class SiloClusteringValidator : IConfigurationValidator\n    {\n        private readonly IServiceProvider serviceProvider;\n\n        public SiloClusteringValidator(IServiceProvider serviceProvider)\n        {\n            this.serviceProvider = serviceProvider;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            var clusteringTableProvider = this.serviceProvider.GetService<IMembershipTable>();\n            if (clusteringTableProvider == null)\n            {\n                throw new OrleansConfigurationException(ClientClusteringValidator.ClusteringNotConfigured);\n            }\n\n            var clusterMembershipOptions = this.serviceProvider.GetRequiredService<IOptions<ClusterMembershipOptions>>().Value;\n            if (clusterMembershipOptions.LivenessEnabled)\n            {\n                if (clusterMembershipOptions.NumVotesForDeathDeclaration > clusterMembershipOptions.NumProbedSilos)\n                {\n                    throw new OrleansConfigurationException($\"{nameof(ClusterMembershipOptions)}.{nameof(ClusterMembershipOptions.NumVotesForDeathDeclaration)} ({clusterMembershipOptions.NumVotesForDeathDeclaration}) must be less than or equal to {nameof(ClusterMembershipOptions)}.{nameof(ClusterMembershipOptions.NumProbedSilos)} ({clusterMembershipOptions.NumProbedSilos}).\");\n                }\n\n                if (clusterMembershipOptions.NumVotesForDeathDeclaration <= 0)\n                {\n                    throw new OrleansConfigurationException($\"{nameof(ClusterMembershipOptions)}.{nameof(ClusterMembershipOptions.NumVotesForDeathDeclaration)} ({clusterMembershipOptions.NumVotesForDeathDeclaration}) must be greater than 0.\");\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/ConsistentRing/ConsistentRingProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\n\n\nnamespace Orleans.Runtime.ConsistentRing\n{\n    /// <summary>\n    /// We use the 'backward/clockwise' definition to assign responsibilities on the ring. \n    /// E.g. in a ring of nodes {5, 10, 15} the responsible for key 7 is 10 (the node is responsible for its preceding range). \n    /// The backwards/clockwise approach is consistent with many overlays, e.g., Chord, Cassandra, etc.\n    /// Note: MembershipOracle uses 'forward/counter-clockwise' definition to assign responsibilities. \n    /// E.g. in a ring of nodes {5, 10, 15}, the responsible of key 7 is node 5 (the node is responsible for its succeeding range).\n    /// </summary>\n    internal sealed partial class ConsistentRingProvider :\n        IConsistentRingProvider, ISiloStatusListener, IDisposable\n    {\n        // internal, so that unit tests can access them\n        internal SiloAddress MyAddress { get; }\n        private IRingRange myRange;\n\n        /// list of silo members sorted by the hash value of their address\n        private readonly List<SiloAddress> membershipRingList = new();\n        private readonly ILogger log;\n        private bool isRunning;\n        private readonly int myKey;\n        private readonly List<IRingRangeListener> statusListeners = new();\n        private readonly ISiloStatusOracle _siloStatusOracle;\n        private (IRingRange OldRange, IRingRange NewRange, bool Increased) lastNotification;\n\n        public ConsistentRingProvider(SiloAddress siloAddr, ILoggerFactory loggerFactory, ISiloStatusOracle siloStatusOracle)\n        {\n            log = loggerFactory.CreateLogger<ConsistentRingProvider>();\n            MyAddress = siloAddr;\n            _siloStatusOracle = siloStatusOracle;\n            myKey = MyAddress.GetConsistentHashCode();\n\n            myRange = RangeFactory.CreateFullRange(); // i am responsible for the whole range\n            lastNotification = (myRange, myRange, true);\n\n            // add myself to the list of members\n            AddServer(MyAddress);\n            Start();\n            siloStatusOracle.SubscribeToSiloStatusEvents(this);\n        }\n\n        /// <summary>\n        /// Returns the silo that this silo thinks is the primary owner of the key\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <returns></returns>\n        public SiloAddress GetPrimaryTargetSilo(uint key)\n        {\n            return CalculateTargetSilo(key);\n        }\n\n        public IRingRange GetMyRange()\n        {\n            return myRange; // its immutable, so no need to clone\n        }\n\n        private void Start()\n        {\n            isRunning = true;\n        }\n\n        private void Stop()\n        {\n            isRunning = false;\n        }\n\n        internal void AddServer(SiloAddress silo)\n        {\n            lock (membershipRingList)\n            {\n                if (membershipRingList.Contains(silo)) return; // we already have this silo\n\n                int myOldIndex = membershipRingList.IndexOf(MyAddress);\n\n                if (!(membershipRingList.Count == 0 || myOldIndex != -1))\n                    throw new OrleansException(string.Format(\"{0}: Couldn't find my position in the ring {1}.\", MyAddress, Utils.EnumerableToString(membershipRingList)));\n\n                // insert new silo in the sorted order\n                int hash = silo.GetConsistentHashCode();\n\n                // Find the last silo with hash smaller than the new silo, and insert the latter after (this is why we have +1 here) the former.\n                // Notice that FindLastIndex might return -1 if this should be the first silo in the list, but then\n                // 'index' will get 0, as needed.\n                int index = membershipRingList.FindLastIndex(siloAddr => siloAddr.GetConsistentHashCode() < hash) + 1;\n                membershipRingList.Insert(index, silo);\n\n                // relating to triggering handler ... new node took over some of my responsibility\n                if (index == myOldIndex || // new node was inserted in my place\n                    (myOldIndex == 0 && index == membershipRingList.Count - 1)) // I am the first node, and the new server is the last node\n                {\n                    IRingRange oldRange = myRange;\n                    myRange = RangeFactory.CreateRange(unchecked((uint)hash), unchecked((uint)myKey));\n                    NotifyLocalRangeSubscribers(oldRange, myRange, false);\n                }\n\n                LogDebugAddedServer(log, new(silo), this);\n            }\n        }\n\n        public override string ToString()\n        {\n            lock (membershipRingList)\n            {\n                if (membershipRingList.Count == 1)\n                    return $\"[{membershipRingList[0]:H} -> {RangeFactory.CreateFullRange()}]\";\n\n                var sb = new StringBuilder().Append('[');\n                for (int i = 0; i < membershipRingList.Count; i++)\n                {\n                    SiloAddress curr = membershipRingList[i];\n                    SiloAddress next = membershipRingList[(i + 1) % membershipRingList.Count];\n                    IRingRange range = RangeFactory.CreateRange(unchecked((uint)curr.GetConsistentHashCode()), unchecked((uint)next.GetConsistentHashCode()));\n                    sb.Append($\"{curr:H} -> {range},  \");\n                }\n\n                return sb.Append(']').ToString();\n            }\n        }\n\n        internal void RemoveServer(SiloAddress silo)\n        {\n            lock (membershipRingList)\n            {\n                int indexOfFailedSilo = membershipRingList.IndexOf(silo);\n                if (indexOfFailedSilo < 0) return; // we have already removed this silo\n\n                membershipRingList.RemoveAt(indexOfFailedSilo);\n\n                // related to triggering handler\n                int myNewIndex = membershipRingList.IndexOf(MyAddress);\n\n                if (myNewIndex == -1)\n                    throw new OrleansException($\"{MyAddress}: Couldn't find my position in the ring {this}.\");\n\n                bool wasMyPred = ((myNewIndex == indexOfFailedSilo) || (myNewIndex == 0 && indexOfFailedSilo == membershipRingList.Count)); // no need for '- 1'\n                if (wasMyPred) // failed node was our predecessor\n                {\n                    LogDebugFailedServerWasMyPredecessor(log, wasMyPred, this);\n\n                    IRingRange oldRange = myRange;\n                    if (membershipRingList.Count == 1) // i'm the only one left\n                    {\n                        myRange = RangeFactory.CreateFullRange();\n                        NotifyLocalRangeSubscribers(oldRange, myRange, true);\n                    }\n                    else\n                    {\n                        int myNewPredIndex = myNewIndex == 0 ? membershipRingList.Count - 1 : myNewIndex - 1;\n                        int myPredecessorsHash = membershipRingList[myNewPredIndex].GetConsistentHashCode();\n\n                        myRange = RangeFactory.CreateRange(unchecked((uint)myPredecessorsHash), unchecked((uint)myKey));\n                        NotifyLocalRangeSubscribers(oldRange, myRange, true);\n                    }\n                }\n\n                LogDebugRemovedServer(log, silo, new(silo), this);\n            }\n        }\n\n        public bool SubscribeToRangeChangeEvents(IRingRangeListener observer)\n        {\n            (IRingRange OldRange, IRingRange NewRange, bool Increased) notification;\n            lock (statusListeners)\n            {\n                if (statusListeners.Contains(observer)) return false;\n\n                statusListeners.Add(observer);\n                notification = lastNotification;\n            }\n\n            observer.RangeChangeNotification(notification.OldRange, notification.NewRange, notification.Increased);\n            return true;\n        }\n\n        public bool UnSubscribeFromRangeChangeEvents(IRingRangeListener observer)\n        {\n            lock (statusListeners)\n            {\n                return statusListeners.Remove(observer);\n            }\n        }\n\n        private void NotifyLocalRangeSubscribers(IRingRange old, IRingRange now, bool increased)\n        {\n            LogDebugNotifyLocalRangeSubscribers(log, old, now, increased);\n\n            IRingRangeListener[] copy;\n            lock (statusListeners)\n            {\n                lastNotification = (old, now, increased);\n                copy = statusListeners.ToArray();\n            }\n\n            foreach (IRingRangeListener listener in copy)\n            {\n                try\n                {\n                    listener.RangeChangeNotification(old, now, increased);\n                }\n                catch (Exception exc)\n                {\n                    LogWarningErrorNotifyingListener(log, exc, listener.GetType().FullName, increased ? \"expansion\" : \"contraction\", old, now);\n                }\n            }\n        }\n\n        public void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n        {\n            // This silo's status has changed\n            if (updatedSilo.Equals(MyAddress))\n            {\n                if (status.IsTerminating())\n                {\n                    Stop();\n                }\n            }\n            else // Status change for some other silo\n            {\n                if (status.IsTerminating())\n                {\n                    RemoveServer(updatedSilo);\n                }\n                else if (status == SiloStatus.Active)      // do not do anything with SiloStatus.Created or SiloStatus.Joining -- wait until it actually becomes active\n                {\n                    AddServer(updatedSilo);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Finds the silo that owns the given hash value.\n        /// This routine will always return a non-null silo address unless the excludeThisSiloIfStopping parameter is true,\n        /// this is the only silo known, and this silo is stopping.\n        /// </summary>\n        /// <param name=\"hash\"></param>\n        /// <param name=\"excludeThisSiloIfStopping\"></param>\n        /// <returns></returns>\n        private SiloAddress CalculateTargetSilo(uint hash, bool excludeThisSiloIfStopping = true)\n        {\n            SiloAddress siloAddress = null;\n\n            lock (membershipRingList)\n            {\n                // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method.\n                bool excludeMySelf = excludeThisSiloIfStopping && !isRunning;\n\n                if (membershipRingList.Count == 0)\n                {\n                    // If the membership ring is empty, then we're the owner by default unless we're stopping.\n                    return excludeMySelf ? null : MyAddress;\n                }\n\n                // use clockwise ... current code in membershipOracle.CalculateTargetSilo() does counter-clockwise ...\n                // if you want to stick to counter-clockwise, change the responsibility definition in 'In()' method & responsibility defs in OrleansReminderMemory\n                // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes\n\n                for (int index = 0; index < membershipRingList.Count; ++index)\n                {\n                    var siloAddr = membershipRingList[index];\n                    if (IsSiloNextInTheRing(siloAddr, hash, excludeMySelf))\n                    {\n                        siloAddress = siloAddr;\n                        break;\n                    }\n                }\n\n                if (siloAddress == null)\n                {\n                    // if not found in traversal, then first silo should be returned (we are on a ring)\n                    // if you go back to their counter-clockwise policy, then change the 'In()' method in OrleansReminderMemory\n                    siloAddress = membershipRingList[0]; // vs [membershipRingList.Count - 1]; for counter-clockwise policy\n                    // Make sure it's not us...\n                    if (siloAddress.Equals(MyAddress) && excludeMySelf)\n                    {\n                        // vs [membershipRingList.Count - 2]; for counter-clockwise policy\n                        siloAddress = membershipRingList.Count > 1 ? membershipRingList[1] : null;\n                    }\n                }\n            }\n\n            LogTraceCalculatedRingPartitionOwner(log, MyAddress, siloAddress, hash, new(siloAddress));\n            return siloAddress;\n        }\n\n        private bool IsSiloNextInTheRing(SiloAddress siloAddr, uint hash, bool excludeMySelf)\n        {\n            return siloAddr.GetConsistentHashCode() >= hash && (!siloAddr.Equals(MyAddress) || !excludeMySelf);\n        }\n\n        public void Dispose()\n        {\n            _siloStatusOracle.UnSubscribeFromSiloStatusEvents(this);\n        }\n\n        private readonly struct SiloAddressWithHashLogRecord(SiloAddress siloAddress)\n        {\n            public override string ToString() => siloAddress.ToStringWithHashCode();\n        }\n\n        private readonly struct ConsistentHashCodeLogRecord(SiloAddress siloAddress)\n        {\n            public override string ToString() => siloAddress?.GetConsistentHashCode().ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Added Server {SiloAddress}. Current view: {CurrentView}\"\n        )]\n        private static partial void LogDebugAddedServer(ILogger logger, SiloAddressWithHashLogRecord siloAddress, ConsistentRingProvider currentView);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Failed server was my predecessor? {WasPredecessor}, updated view {CurrentView}\"\n        )]\n        private static partial void LogDebugFailedServerWasMyPredecessor(ILogger logger, bool wasPredecessor, ConsistentRingProvider currentView);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Removed Server {SiloAddress} hash {Hash}. Current view {CurrentView}\"\n        )]\n        private static partial void LogDebugRemovedServer(ILogger logger, SiloAddress siloAddress, SiloAddressWithHashLogRecord hash, ConsistentRingProvider currentView);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"NotifyLocalRangeSubscribers about old {OldRange} new {NewRange} increased? {IsIncreased}\"\n        )]\n        private static partial void LogDebugNotifyLocalRangeSubscribers(ILogger logger, IRingRange oldRange, IRingRange newRange, bool isIncreased);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CRP_Local_Subscriber_Exception,\n            Level = LogLevel.Warning,\n            Message = \"Error notifying listener '{ListenerType}' of ring range {AdjustmentKind} from '{OldRange}' to '{NewRange}'.\"\n        )]\n        private static partial void LogWarningErrorNotifyingListener(ILogger logger, Exception exception, string listenerType, string adjustmentKind, IRingRange oldRange, IRingRange newRange);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Silo {SiloAddress} calculated ring partition owner silo {OwnerAddress} for key {Key}: {Key} --> {OwnerHash}\"\n        )]\n        private static partial void LogTraceCalculatedRingPartitionOwner(ILogger logger, SiloAddress siloAddress, SiloAddress ownerAddress, uint key, ConsistentHashCodeLogRecord ownerHash);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/ConsistentRing/IConsistentRingProvider.cs",
    "content": "namespace Orleans.Runtime.ConsistentRing\n{\n    // someday, this will be the only provider for the ring, i.e., directory service will use this\n\n    internal interface IConsistentRingProvider\n    {\n        /// <summary>\n        /// Get the responsibility range of the current silo\n        /// </summary>\n        /// <returns></returns>\n        IRingRange GetMyRange();\n\n        // the following two are similar to the ISiloStatusOracle interface ... this replaces the 'OnRangeChanged' because OnRangeChanged only supports one subscription\n\n        /// <summary>\n        /// Subscribe to receive range change notifications\n        /// </summary>\n        /// <param name=\"observer\">An observer interface to receive range change notifications.</param>\n        /// <returns>bool value indicating that subscription succeeded or not.</returns>\n        bool SubscribeToRangeChangeEvents(IRingRangeListener observer);\n\n        /// <summary>\n        /// Unsubscribe from receiving range change notifications\n        /// </summary>\n        /// <param name=\"observer\">An observer interface to receive range change notifications.</param>\n        /// <returns>bool value indicating that unsubscription succeeded or not</returns>\n        bool UnSubscribeFromRangeChangeEvents(IRingRangeListener observer);\n\n        /// <summary>\n        /// Get the silo responsible for <paramref name=\"key\"/> according to consistent hashing\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <returns></returns>\n        SiloAddress GetPrimaryTargetSilo(uint key);\n    }\n\n    // similar to ISiloStatusListener\n    internal interface IRingRangeListener\n    {\n        void RangeChangeNotification(IRingRange old, IRingRange now, bool increased);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/ConsistentRing/SimpleConsistentRingProvider.cs",
    "content": "using System.Threading;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Aids in the construction of a consistent hash ring by maintaining an up-to-date reference to the next silo in the ring.\n    /// </summary>\n    internal class SimpleConsistentRingProvider\n    {\n        private readonly SiloAddress _localSilo;\n        private readonly IClusterMembershipService _clusterMembershipService;\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private VersionedSuccessor _successor = new VersionedSuccessor(MembershipVersion.MinValue, null);\n\n        public SimpleConsistentRingProvider(ILocalSiloDetails localSiloDetails, IClusterMembershipService clusterMembershipService)\n        {\n            _localSilo = localSiloDetails.SiloAddress;\n            _clusterMembershipService = clusterMembershipService;\n            FindSuccessor(_clusterMembershipService.CurrentSnapshot);\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"SiloAddress\"/> of the active silo with the smallest consistent hash code value which is larger\n        /// than this silo's, or if no such silo exists, then the active silo with the absolute smallest consistent hash code,\n        /// or <see langword=\"null\"/> if there are no other active silos in the cluster.\n        /// </summary>\n        public SiloAddress Successor\n        {\n            get\n            {\n                var snapshot = _clusterMembershipService.CurrentSnapshot;\n                var (successorVersion, successor) = _successor;\n\n                if (successorVersion < snapshot.Version)\n                {\n                    lock (_lockObj)\n                    {\n                        successor = FindSuccessor(snapshot);\n                        _successor = new VersionedSuccessor(snapshot.Version, successor);\n                    }\n                }\n\n                return successor;\n            }\n        }\n\n        private SiloAddress FindSuccessor(ClusterMembershipSnapshot snapshot)\n        {\n            var (successorVersion, successor) = _successor;\n            if (successorVersion >= snapshot.Version)\n            {\n                return successor;\n            }\n\n            // Find the silo with the smallest hashcode which is larger than this silo's.\n            (SiloAddress Silo, int HashCode) firstInRing = (default(SiloAddress), int.MaxValue);\n            (SiloAddress Silo, int HashCode) candidate = (default(SiloAddress), int.MaxValue);\n            var localSiloHashCode = _localSilo.GetConsistentHashCode();\n            foreach (var member in snapshot.Members.Values)\n            {\n                if (member.SiloAddress.Equals(_localSilo))\n                {\n                    continue;\n                }\n\n                if (member.Status != SiloStatus.Active)\n                {\n                    continue;\n                }\n\n                var memberHashCode = member.SiloAddress.GetConsistentHashCode();\n\n                // It is possible that the local silo is last in the ring, therefore we also find the first silo in the ring,\n                // which would be the local silo's successor in that case.\n                if (memberHashCode < firstInRing.HashCode)\n                {\n                    firstInRing = (member.SiloAddress, memberHashCode);\n                }\n\n                // This member comes before this silo in the ring, but is not the first in the ring.\n                if (memberHashCode < localSiloHashCode)\n                {\n                    continue;\n                }\n\n                // This member comes after this silo in the ring, but before the current candidate.\n                // Therefore, this member is the new candidate.\n                if (memberHashCode < candidate.HashCode)\n                {\n                    candidate = (member.SiloAddress, memberHashCode);\n                }\n            }\n\n            // The result is either the silo with the smallest hashcode that is larger than this silo's,\n            // or the first silo in the ring, or null in the case that there are no other active silos.\n            successor = candidate.Silo ?? firstInRing.Silo;\n            return successor;\n        }\n\n        private sealed class VersionedSuccessor\n        {\n            public VersionedSuccessor(MembershipVersion membershipVersion, SiloAddress siloAddress)\n            {\n                MembershipVersion = membershipVersion;\n                SiloAddress = siloAddress;\n            }\n\n            public void Deconstruct(out MembershipVersion version, out SiloAddress siloAddress)\n            {\n                version = MembershipVersion;\n                siloAddress = SiloAddress;\n            }\n\n            public MembershipVersion MembershipVersion { get; }\n            public SiloAddress SiloAddress { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/ConsistentRing/VirtualBucketsRingProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.ConsistentRing\n{\n    /// <summary>\n    /// We use the 'backward/clockwise' definition to assign responsibilities on the ring.\n    /// E.g. in a ring of nodes {5, 10, 15} the responsible for key 7 is 10 (the node is responsible for its preceding range).\n    /// The backwards/clockwise approach is consistent with many overlays, e.g., Chord, Cassandra, etc.\n    /// Note: MembershipOracle uses 'forward/counter-clockwise' definition to assign responsibilities.\n    /// E.g. in a ring of nodes {5, 10, 15}, the responsible of key 7 is node 5 (the node is responsible for its succeeding range).\n    /// </summary>\n    internal sealed partial class VirtualBucketsRingProvider :\n        IConsistentRingProvider, ISiloStatusListener, IDisposable\n    {\n        private readonly List<IRingRangeListener> statusListeners = new();\n        private readonly SortedDictionary<uint, SiloAddress> bucketsMap = new();\n        private (uint Hash, SiloAddress SiloAddress)[] sortedBucketsList; // flattened sorted bucket list for fast lock-free calculation of CalculateTargetSilo\n        private readonly ILogger logger;\n        private readonly SiloAddress myAddress;\n        private readonly int numBucketsPerSilo;\n        private readonly ISiloStatusOracle _siloStatusOracle;\n        private bool running;\n        private IRingRange myRange;\n        private (IRingRange OldRange, IRingRange NewRange, bool Increased) lastNotification;\n\n        internal VirtualBucketsRingProvider(SiloAddress siloAddress, ILoggerFactory loggerFactory, int numVirtualBuckets, ISiloStatusOracle siloStatusOracle)\n        {\n            numBucketsPerSilo = numVirtualBuckets;\n            _siloStatusOracle = siloStatusOracle;\n            if (numBucketsPerSilo <= 0)\n                throw new IndexOutOfRangeException($\"numBucketsPerSilo is out of the range. numBucketsPerSilo = {numBucketsPerSilo}\");\n\n            logger = loggerFactory.CreateLogger<VirtualBucketsRingProvider>();\n\n            myAddress = siloAddress;\n            running = true;\n            myRange = RangeFactory.CreateFullRange();\n            lastNotification = (myRange, myRange, true);\n\n            LogDebugStarting(logger, nameof(VirtualBucketsRingProvider), new(siloAddress));\n\n            ConsistentRingInstruments.RegisterRingSizeObserve(() => GetRingSize());\n            ConsistentRingInstruments.RegisterMyRangeRingPercentageObserve(() => (float)((IRingRangeInternal)myRange).RangePercentage());\n            ConsistentRingInstruments.RegisterAverageRingPercentageObserve(() =>\n            {\n                int size = GetRingSize();\n                return size == 0 ? 0 : ((float)100.0 / size);\n            });\n\n            // add myself to the list of members\n            AddServer(myAddress);\n            siloStatusOracle.SubscribeToSiloStatusEvents(this);\n        }\n\n        private void Stop()\n        {\n            running = false;\n        }\n\n        public IRingRange GetMyRange()\n        {\n            return myRange;\n        }\n\n        private int GetRingSize()\n        {\n            lock (bucketsMap)\n            {\n                return bucketsMap.Values.Distinct().Count();\n            }\n        }\n\n        public bool SubscribeToRangeChangeEvents(IRingRangeListener observer)\n        {\n            (IRingRange OldRange, IRingRange NewRange, bool Increased) notification;\n            lock (statusListeners)\n            {\n                if (statusListeners.Contains(observer)) return false;\n\n                notification = lastNotification;\n                statusListeners.Add(observer);\n            }\n\n            observer.RangeChangeNotification(notification.OldRange, notification.NewRange, notification.Increased);\n            return true;\n        }\n\n        public bool UnSubscribeFromRangeChangeEvents(IRingRangeListener observer)\n        {\n            lock (statusListeners)\n            {\n                return statusListeners.Remove(observer);\n            }\n        }\n\n        private void NotifyLocalRangeSubscribers(IRingRange old, IRingRange now, bool increased)\n        {\n            LogTraceNotifyLocalRangeSubscribers(logger, old, now, increased);\n\n            IRingRangeListener[] copy;\n            lock (statusListeners)\n            {\n                lastNotification = (old, now, increased);\n                copy = statusListeners.ToArray();\n            }\n            foreach (IRingRangeListener listener in copy)\n            {\n                try\n                {\n                    listener.RangeChangeNotification(old, now, increased);\n                }\n                catch (Exception exc)\n                {\n                    LogWarningErrorNotifyingListener(logger, exc, listener.GetType().FullName, increased ? \"expansion\" : \"contraction\", old, now);\n                }\n            }\n        }\n\n        private void AddServer(SiloAddress silo)\n        {\n            var hashes = silo.GetUniformHashCodes(numBucketsPerSilo);\n            lock (bucketsMap)\n            {\n                foreach (var hash in hashes)\n                {\n                    if (bucketsMap.TryGetValue(hash, out var other))\n                    {\n                        // If two silos conflict, take the lesser of the two (usually the older one; that is, the lower epoch)\n                        if (silo.CompareTo(other) > 0) continue;\n                    }\n                    bucketsMap[hash] = silo;\n                }\n\n                var myOldRange = myRange;\n                var myNewRange = UpdateRange();\n                LogTraceAddedServer(logger, new(silo), this);\n\n                NotifyLocalRangeSubscribers(myOldRange, myNewRange, true);\n            }\n        }\n\n        private void RemoveServer(SiloAddress silo)\n        {\n            lock (bucketsMap)\n            {\n                if (!bucketsMap.ContainsValue(silo)) return; // we have already removed this silo\n\n                var hashes = silo.GetUniformHashCodes(numBucketsPerSilo);\n                foreach (var hash in hashes)\n                {\n                    if (bucketsMap.Remove(hash, out var removedSilo) && !removedSilo.Equals(silo))\n                    {\n                        // since hash collisions are very rare, it's better to remove bucket and then retroactively\n                        // add it if silos were different rather than doing 2 lookups (1st for checking if silos are\n                        // equal, then 2nd to remove bucket) each time\n                        bucketsMap[hash] = removedSilo;\n                    }\n                }\n\n                var myOldRange = this.myRange;\n                var myNewRange = UpdateRange();\n\n                LogTraceRemovedServer(logger, new(silo), this);\n\n                NotifyLocalRangeSubscribers(myOldRange, myNewRange, true);\n            }\n        }\n\n        private IRingRange UpdateRange()\n        {\n            var bucketsList = new (uint, SiloAddress)[bucketsMap.Count];\n            var idx = 0;\n            foreach (var pair in bucketsMap) bucketsList[idx++] = (pair.Key, pair.Value);\n            var myNewRange = CalculateRange(bucketsList, myAddress);\n\n            // capture my range and sortedBucketsList for later lock-free access.\n            myRange = myNewRange;\n            sortedBucketsList = bucketsList;\n            return myNewRange;\n        }\n\n        private static IRingRange CalculateRange((uint Hash, SiloAddress SiloAddress)[] list, SiloAddress silo)\n        {\n            var ranges = new List<IRingRange>();\n            for (int i = 0; i < list.Length; i++)\n            {\n                var curr = list[i];\n                var next = list[(i + 1) % list.Length];\n                // 'backward/clockwise' definition to assign responsibilities on the ring.\n                if (next.SiloAddress.Equals(silo))\n                {\n                    IRingRange range = RangeFactory.CreateRange(curr.Hash, next.Hash);\n                    ranges.Add(range);\n                }\n            }\n            return RangeFactory.CreateRange(ranges);\n        }\n\n        // for debugging/logging\n        public override string ToString()\n        {\n            var sortedList = GetRanges();\n            sortedList.Sort((t1, t2) => t1.Value.RangePercentage().CompareTo(t2.Value.RangePercentage()));\n            return Utils.EnumerableToString(sortedList, kv => $\"{kv.Key} -> {kv.Value}\");\n        }\n\n        // Internal: for testing/logging only!\n        internal List<(SiloAddress Key, IRingRangeInternal Value)> GetRanges()\n        {\n            List<SiloAddress> silos;\n            (uint, SiloAddress)[] snapshotBucketsList;\n            lock (bucketsMap)\n            {\n                silos = bucketsMap.Values.Distinct().ToList();\n                snapshotBucketsList = sortedBucketsList;\n            }\n            var ranges = new List<(SiloAddress, IRingRangeInternal)>(silos.Count);\n            foreach (var silo in silos)\n            {\n                var range = (IRingRangeInternal)CalculateRange(snapshotBucketsList, silo);\n                ranges.Add((silo, range));\n            }\n\n            return ranges;\n        }\n\n        public void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n        {\n            // This silo's status has changed\n            if (updatedSilo.Equals(myAddress))\n            {\n                if (status.IsTerminating())\n                {\n                    Stop();\n                }\n            }\n            else // Status change for some other silo\n            {\n                if (status.IsTerminating())\n                {\n                    RemoveServer(updatedSilo);\n                }\n                else if (status == SiloStatus.Active)      // do not do anything with SiloStatus.Created or SiloStatus.Joining -- wait until it actually becomes active\n                {\n                    AddServer(updatedSilo);\n                }\n            }\n        }\n\n        public SiloAddress GetPrimaryTargetSilo(uint key)\n        {\n            return CalculateTargetSilo(key);\n        }\n\n        /// <summary>\n        /// Finds the silo that owns the given hash value.\n        /// This routine will always return a non-null silo address unless the excludeThisSiloIfStopping parameter is true,\n        /// this is the only silo known, and this silo is stopping.\n        /// </summary>\n        /// <param name=\"hash\"></param>\n        /// <param name=\"excludeThisSiloIfStopping\"></param>\n        /// <returns></returns>\n        private SiloAddress CalculateTargetSilo(uint hash, bool excludeThisSiloIfStopping = true)\n        {\n            // put a private reference to point to sortedBucketsList,\n            // so if someone is changing the sortedBucketsList reference, we won't get it changed in the middle of our operation.\n            // The tricks of writing lock-free code!\n            var snapshotBucketsList = sortedBucketsList;\n\n            // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method.\n            bool excludeMySelf = excludeThisSiloIfStopping && !running;\n\n            if (snapshotBucketsList.Length == 0)\n            {\n                // If the membership ring is empty, then we're the owner by default unless we're stopping.\n                return excludeMySelf ? null : myAddress;\n            }\n\n            // use clockwise ... current code in membershipOracle.CalculateTargetSilo() does counter-clockwise ...\n            // if you want to stick to counter-clockwise, change the responsibility definition in 'In()' method & responsibility defs in OrleansReminderMemory\n            // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes\n            (uint Hash, SiloAddress SiloAddress) s = default;\n            foreach (var tuple in snapshotBucketsList)\n            {\n                if (tuple.Hash >= hash && // <= hash for counter-clockwise responsibilities\n                    (!tuple.SiloAddress.Equals(myAddress) || !excludeMySelf))\n                {\n                    s = tuple;\n                    break;\n                }\n            }\n\n            if (s.SiloAddress == null)\n            {\n                // if not found in traversal, then first silo should be returned (we are on a ring)\n                // if you go back to their counter-clockwise policy, then change the 'In()' method in OrleansReminderMemory\n                s = snapshotBucketsList[0]; // vs [membershipRingList.Count - 1]; for counter-clockwise policy\n                // Make sure it's not us...\n                if (s.SiloAddress.Equals(myAddress) && excludeMySelf)\n                {\n                    // vs [membershipRingList.Count - 2]; for counter-clockwise policy\n                    s = snapshotBucketsList.Length > 1 ? snapshotBucketsList[1] : default;\n                }\n            }\n\n            LogTraceCalculatedRingPartitionOwner(logger, s.SiloAddress, hash, s.Hash);\n\n            return s.SiloAddress;\n        }\n\n        public void Dispose()\n        {\n            _siloStatusOracle.UnSubscribeFromSiloStatusEvents(this);\n        }\n\n        private readonly struct SiloAddressLogValue\n        {\n            private readonly SiloAddress _siloAddress;\n\n            public SiloAddressLogValue(SiloAddress siloAddress)\n            {\n                _siloAddress = siloAddress;\n            }\n\n            public override string ToString() => _siloAddress.ToStringWithHashCode();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting {Name} on silo {SiloAddress}.\"\n        )]\n        private static partial void LogDebugStarting(ILogger logger, string name, SiloAddressLogValue siloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CRP_Notify,\n            Level = LogLevel.Trace,\n            Message = \"NotifyLocalRangeSubscribers about old {Old} new {New} increased? {IsIncrease}\"\n        )]\n        private static partial void LogTraceNotifyLocalRangeSubscribers(ILogger logger, IRingRange old, IRingRange @new, bool isIncrease);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CRP_Local_Subscriber_Exception,\n            Level = LogLevel.Warning,\n            Message = \"Error notifying listener '{ListenerType}' of ring range {AdjustmentKind} from '{OldRange}' to '{NewRange}'.\"\n        )]\n        private static partial void LogWarningErrorNotifyingListener(ILogger logger, Exception exception, string listenerType, string adjustmentKind, IRingRange oldRange, IRingRange newRange);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CRP_Added_Silo,\n            Level = LogLevel.Trace,\n            Message = \"Added Server {SiloAddress}. Current view: {CurrentView}\"\n        )]\n        private static partial void LogTraceAddedServer(ILogger logger, SiloAddressLogValue siloAddress, VirtualBucketsRingProvider currentView);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.CRP_Removed_Silo,\n            Level = LogLevel.Trace,\n            Message = \"Removed Server {SiloAddress}. Current view: {CurrentView}\"\n        )]\n        private static partial void LogTraceRemovedServer(ILogger logger, SiloAddressLogValue siloAddress, VirtualBucketsRingProvider currentView);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Calculated ring partition owner silo {Owner} for key {Key}: {Key} --> {OwnerHash}\"\n        )]\n        private static partial void LogTraceCalculatedRingPartitionOwner(ILogger logger, SiloAddress owner, uint key, uint ownerHash);\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/FatalErrorHandler.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing System.Threading;\n\nnamespace Orleans.Runtime\n{\n    internal partial class FatalErrorHandler : IFatalErrorHandler\n    {\n        private readonly ILogger<FatalErrorHandler> log;\n        private readonly ClusterMembershipOptions clusterMembershipOptions;\n\n        public FatalErrorHandler(\n            ILogger<FatalErrorHandler> log,\n            IOptions<ClusterMembershipOptions> clusterMembershipOptions)\n        {\n            this.log = log;\n            this.clusterMembershipOptions = clusterMembershipOptions.Value;\n        }\n\n        public bool IsUnexpected(Exception exception)\n        {\n            return !(exception is ThreadAbortException);\n        }\n\n        public void OnFatalException(object sender, string context, Exception exception)\n        {\n            LogFatalError(this.log, exception, sender, context);\n\n            var msg = @$\"FATAL EXCEPTION from {sender?.ToString() ?? \"null\"}. Context: {context ?? \"null\"\n                }. Exception: {(exception != null ? LogFormatter.PrintException(exception) : \"null\")}.\\nCurrent stack: {Environment.StackTrace}\";\n            Console.Error.WriteLine(msg);\n\n            // Allow some time for loggers to flush.\n            Thread.Sleep(2000);\n\n            if (Debugger.IsAttached) Debugger.Break();\n\n            Environment.FailFast(msg, exception);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Logger_ProcessCrashing,\n            Message = \"Fatal error from {Sender}. Context: {Context}\"\n        )]\n        private static partial void LogFatalError(ILogger logger, Exception exception, object sender, string context);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/GrainRuntime.cs",
    "content": "#nullable enable\nusing System;\nusing Orleans.Core;\nusing Orleans.Timers;\nusing Orleans.Storage;\n\nnamespace Orleans.Runtime;\n\ninternal class GrainRuntime : IGrainRuntime\n{\n    private readonly IServiceProvider _serviceProvider;\n\n    private readonly ITimerRegistry _timerRegistry;\n    private readonly IGrainFactory _grainFactory;\n\n    public GrainRuntime(\n        ILocalSiloDetails localSiloDetails,\n        IGrainFactory grainFactory,\n        ITimerRegistry timerRegistry,\n        IServiceProvider serviceProvider,\n        TimeProvider timeProvider)\n    {\n        SiloAddress = localSiloDetails.SiloAddress;\n        SiloIdentity = SiloAddress.ToString();\n        _grainFactory = grainFactory;\n        _timerRegistry = timerRegistry;\n        _serviceProvider = serviceProvider;\n        TimeProvider = timeProvider;\n    }\n\n    public string SiloIdentity { get; }\n\n    public SiloAddress SiloAddress { get; }\n\n    public IGrainFactory GrainFactory\n    {\n        get\n        {\n            CheckRuntimeContext(RuntimeContext.Current);\n            return _grainFactory;\n        }\n    }\n\n    public ITimerRegistry TimerRegistry\n    {\n        get\n        {\n            CheckRuntimeContext(RuntimeContext.Current);\n            return _timerRegistry;\n        }\n    }\n\n    public IServiceProvider ServiceProvider\n    {\n        get\n        {\n            CheckRuntimeContext(RuntimeContext.Current);\n            return _serviceProvider;\n        }\n    }\n\n    public TimeProvider TimeProvider { get; }\n\n    public void DeactivateOnIdle(IGrainContext grainContext)\n    {\n        CheckRuntimeContext(grainContext);\n        grainContext.Deactivate(new(DeactivationReasonCode.ApplicationRequested, $\"{nameof(DeactivateOnIdle)} was called.\"));\n    }\n\n    public void DelayDeactivation(IGrainContext grainContext, TimeSpan timeSpan)\n    {\n        CheckRuntimeContext(grainContext);\n        if (grainContext is not ICollectibleGrainContext collectibleContext)\n        {\n            throw new NotSupportedException($\"Grain context {grainContext} does not implement {nameof(ICollectibleGrainContext)} and therefore {nameof(DelayDeactivation)} is not supported\");\n        }\n\n        collectibleContext.DelayDeactivation(timeSpan);\n    }\n\n    public IStorage<TGrainState> GetStorage<TGrainState>(IGrainContext grainContext)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext);\n        var grainType = grainContext.GrainInstance?.GetType() ?? throw new ArgumentNullException(nameof(IGrainContext.GrainInstance));\n        IGrainStorage grainStorage = GrainStorageHelpers.GetGrainStorage(grainType, ServiceProvider);\n        return new StateStorageBridge<TGrainState>(\"state\", grainContext, grainStorage);\n    }\n\n    public static void CheckRuntimeContext(IGrainContext? context)\n    {\n        if (context is null)\n        {\n            // Move exceptions into local functions to help inlining this method.\n            ThrowMissingContext();\n            void ThrowMissingContext() => throw new InvalidOperationException(\"Activation access violation. A non-activation thread attempted to access activation services.\");\n        }\n\n        if (context is ActivationData activation && activation.State == ActivationState.Invalid)\n        {\n            // Move exceptions into local functions to help inlining this method.\n            ThrowInvalidActivation(activation);\n            void ThrowInvalidActivation(ActivationData activationData) => throw new InvalidOperationException($\"Attempt to access an invalid activation: {activationData}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/HostedClient.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.GrainReferences;\nusing Orleans.Internal;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// A client which is hosted within a silo.\n    /// </summary>\n    internal sealed partial class HostedClient : IGrainContext, IGrainExtensionBinder, IDisposable, ILifecycleParticipant<ISiloLifecycle>\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock lockObj = new();\n#else\n        private readonly object lockObj = new();\n#endif\n        private readonly Channel<Message> incomingMessages;\n        private readonly IGrainReferenceRuntime grainReferenceRuntime;\n        private readonly InvokableObjectManager invokableObjects;\n        private readonly InsideRuntimeClient runtimeClient;\n        private readonly ILogger logger;\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly MessageCenter siloMessageCenter;\n        private readonly MessagingTrace messagingTrace;\n        private readonly ConcurrentDictionary<Type, (object Implementation, IAddressable Reference)> _extensions = new ConcurrentDictionary<Type, (object, IAddressable)>();\n        private readonly ConcurrentDictionary<Type, object> _components = new();\n        private readonly IServiceScope _serviceProviderScope;\n        private bool disposing;\n        private Task? messagePump;\n\n        public HostedClient(\n            InsideRuntimeClient runtimeClient,\n            ILocalSiloDetails siloDetails,\n            ILogger<HostedClient> logger,\n            IGrainReferenceRuntime grainReferenceRuntime,\n            IInternalGrainFactory grainFactory,\n            MessageCenter messageCenter,\n            MessagingTrace messagingTrace,\n            DeepCopier deepCopier,\n            GrainReferenceActivator referenceActivator,\n            InterfaceToImplementationMappingCache interfaceToImplementationMappingCache)\n        {\n            this.incomingMessages = Channel.CreateUnbounded<Message>(new UnboundedChannelOptions\n            {\n                SingleReader = true,\n                SingleWriter = false,\n                AllowSynchronousContinuations = false,\n            });\n\n            this.runtimeClient = runtimeClient;\n            this.grainReferenceRuntime = grainReferenceRuntime;\n            this.grainFactory = grainFactory;\n            this.invokableObjects = new InvokableObjectManager(\n                this,\n                runtimeClient,\n                deepCopier,\n                messagingTrace,\n                runtimeClient.ServiceProvider.GetRequiredService<DeepCopier<Response>>(),\n                interfaceToImplementationMappingCache,\n                logger);\n            this.siloMessageCenter = messageCenter;\n            this.messagingTrace = messagingTrace;\n            this.logger = logger;\n\n            this.ClientId = CreateHostedClientGrainId(siloDetails.SiloAddress);\n            this.Address = Gateway.GetClientActivationAddress(this.ClientId.GrainId, siloDetails.SiloAddress);\n            this.GrainReference = referenceActivator.CreateReference(this.ClientId.GrainId, default);\n            _serviceProviderScope = runtimeClient.ServiceProvider.CreateScope();\n        }\n\n        public static ClientGrainId CreateHostedClientGrainId(SiloAddress siloAddress) => ClientGrainId.Create($\"hosted-{siloAddress.ToParsableString()}\");\n\n        /// <inheritdoc />\n        public ClientGrainId ClientId { get; }\n\n        public GrainReference GrainReference { get; }\n\n        public GrainId GrainId => this.ClientId.GrainId;\n\n        public object? GrainInstance => null;\n\n        public ActivationId ActivationId => this.Address.ActivationId;\n\n        public GrainAddress Address { get; }\n\n        public IServiceProvider ActivationServices => _serviceProviderScope.ServiceProvider;\n\n        public IGrainLifecycle ObservableLifecycle => throw new NotImplementedException();\n\n        public IWorkItemScheduler Scheduler => throw new NotImplementedException();\n\n        public bool IsExemptFromCollection => true;\n\n        /// <inheritdoc />\n        public override string ToString() => $\"{nameof(HostedClient)}_{this.Address}\";\n\n        /// <inheritdoc />\n        public IAddressable CreateObjectReference(IAddressable obj)\n        {\n            if (obj is GrainReference) throw new ArgumentException(\"Argument obj is already a grain reference.\");\n\n            var observerId = ObserverGrainId.Create(this.ClientId);\n            var grainReference = this.grainFactory.GetGrain(observerId.GrainId);\n            if (!this.invokableObjects.TryRegister(obj, observerId))\n            {\n                throw new ArgumentException(\n                    string.Format(\"Failed to add new observer {0} to localObjects collection.\", grainReference),\n                    nameof(grainReference));\n            }\n\n            return grainReference;\n        }\n\n        /// <inheritdoc />\n        public void DeleteObjectReference(IAddressable obj)\n        {\n            if (obj is not GrainReference reference)\n            {\n                throw new ArgumentException(\"Argument reference is not a grain reference.\");\n            }\n\n            if (!ObserverGrainId.TryParse(reference.GrainId, out var observerId))\n            {\n                throw new ArgumentException($\"Reference {reference.GrainId} is not an observer reference\");\n            }\n\n            if (!invokableObjects.TryDeregister(observerId))\n            {\n                throw new ArgumentException(\"Reference is not associated with a local object.\", \"reference\");\n            }\n        }\n\n        public object? GetComponent(Type componentType)\n        {\n            if (componentType.IsAssignableFrom(GetType())) return this;\n            if (_components.TryGetValue(componentType, out var result))\n            {\n                return result;\n            }\n            else if (componentType == typeof(PlacementStrategy))\n            {\n                return ClientObserversPlacement.Instance;\n            }\n\n            lock (lockObj)\n            {\n                if (ActivationServices.GetService(componentType) is { } activatedComponent)\n                {\n                    return _components.GetOrAdd(componentType, activatedComponent);\n                }\n            }\n\n            return default;\n        }\n\n        public void SetComponent<TComponent>(TComponent? instance) where TComponent : class\n        {\n            if (this is TComponent)\n            {\n                throw new ArgumentException(\"Cannot override a component which is implemented by the client context\");\n            }\n\n            lock (lockObj)\n            {\n                if (instance == null)\n                {\n                    _components.Remove(typeof(TComponent), out _);\n                    return;\n                }\n\n                _components[typeof(TComponent)] = instance;\n            }\n        }\n\n        /// <inheritdoc />\n        public bool TryDispatchToClient(Message message)\n        {\n            if (!ClientGrainId.TryParse(message.TargetGrain, out var targetClient) || !this.ClientId.Equals(targetClient))\n            {\n                return false;\n            }\n\n            if (message.IsExpired)\n            {\n                this.messagingTrace.OnDropExpiredMessage(message, MessagingInstruments.Phase.Receive);\n                return true;\n            }\n\n            this.ReceiveMessage(message);\n            return true;\n        }\n\n        public void ReceiveMessage(object message)\n        {\n            var msg = (Message)message;\n\n            if (msg.Direction == Message.Directions.Response)\n            {\n                // Requests are made through the runtime client, so deliver responses to the runtime client so that the request callback can be executed.\n                this.runtimeClient.ReceiveResponse(msg);\n            }\n            else\n            {\n                // Requests against client objects are scheduled for execution on the client.\n                this.incomingMessages.Writer.TryWrite(msg);\n            }\n        }\n\n        /// <inheritdoc />\n        void IDisposable.Dispose()\n        {\n            if (this.disposing) return;\n            this.disposing = true;\n            _serviceProviderScope.Dispose();\n            Utils.SafeExecute(() => this.siloMessageCenter.SetHostedClient(null));\n            Utils.SafeExecute(() => this.incomingMessages.Writer.TryComplete());\n            Utils.SafeExecute(() => this.messagePump?.GetAwaiter().GetResult());\n        }\n\n        private void Start()\n        {\n            this.messagePump = Task.Run(this.RunClientMessagePump);\n        }\n\n        private async Task RunClientMessagePump()\n        {\n            var reader = this.incomingMessages.Reader;\n            while (true)\n            {\n                try\n                {\n                    var more = await reader.WaitToReadAsync();\n                    if (!more)\n                    {\n                        LogDebugShuttingDown(this.logger);\n                        break;\n                    }\n\n                    while (reader.TryRead(out var message))\n                    {\n                        if (message == null) continue;\n                        switch (message.Direction)\n                        {\n                            case Message.Directions.OneWay:\n                            case Message.Directions.Request:\n                                this.invokableObjects.Dispatch(message);\n                                break;\n                            default:\n                                LogErrorUnsupportedMessage(this.logger, message);\n                                break;\n                        }\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorMessagePumpException(this.logger, exception);\n                }\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\"HostedClient\", ServiceLifecycleStage.RuntimeGrainServices, OnStart, OnStop);\n\n            Task OnStart(CancellationToken cancellation)\n            {\n                if (cancellation.IsCancellationRequested) return Task.CompletedTask;\n\n                // Register with the message center so that we can receive messages.\n                this.siloMessageCenter.SetHostedClient(this);\n\n                // Start pumping messages.\n                this.Start();\n                return Task.CompletedTask;\n            }\n\n            async Task OnStop(CancellationToken cancellation)\n            {\n                this.incomingMessages.Writer.TryComplete();\n\n                if (this.messagePump != null)\n                {\n                    await messagePump.WaitAsync(cancellation).SuppressThrowing();\n                }\n            }\n        }\n\n        public bool Equals(IGrainContext? other) => ReferenceEquals(this, other);\n\n        public (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            (TExtension, TExtensionInterface) result;\n            if (this.TryGetExtension(out result))\n            {\n                return result;\n            }\n\n            lock (this.lockObj)\n            {\n                if (this.TryGetExtension(out result))\n                {\n                    return result;\n                }\n\n                var implementation = newExtensionFunc();\n                var reference = this.grainFactory.CreateObjectReference<TExtensionInterface>(implementation);\n                _extensions[typeof(TExtensionInterface)] = (implementation, reference);\n                result = (implementation, reference);\n                return result;\n            }\n        }\n\n        private bool TryGetExtension<TExtension, TExtensionInterface>(out (TExtension, TExtensionInterface) result)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (_extensions.TryGetValue(typeof(TExtensionInterface), out var existing))\n            {\n                if (existing.Implementation is TExtension typedResult)\n                {\n                    result = (typedResult, existing.Reference.AsReference<TExtensionInterface>());\n                    return true;\n                }\n\n                throw new InvalidCastException($\"Cannot cast existing extension of type {existing.Implementation} to target type {typeof(TExtension)}\");\n            }\n\n            result = default;\n            return false;\n        }\n\n        private bool TryGetExtension<TExtensionInterface>([NotNullWhen(true)] out TExtensionInterface? result)\n            where TExtensionInterface : IGrainExtension\n        {\n            if (_extensions.TryGetValue(typeof(TExtensionInterface), out var existing))\n            {\n                result = (TExtensionInterface)existing.Implementation;\n                return true;\n            }\n\n            result = default;\n            return false;\n        }\n\n        public TExtensionInterface GetExtension<TExtensionInterface>()\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (this.TryGetExtension<TExtensionInterface>(out var result))\n            {\n                return result;\n            }\n\n            lock (this.lockObj)\n            {\n                if (this.TryGetExtension(out result))\n                {\n                    return result;\n                }\n\n                var implementation = this.ActivationServices.GetKeyedService<IGrainExtension>(typeof(TExtensionInterface));\n                if (implementation is null)\n                {\n                    throw new GrainExtensionNotInstalledException($\"No extension of type {typeof(TExtensionInterface)} is installed on this instance and no implementations are registered for automated install\");\n                }\n\n                var reference = this.GrainReference.Cast<TExtensionInterface>();\n                _extensions[typeof(TExtensionInterface)] = (implementation, reference);\n                result = (TExtensionInterface)implementation;\n                return result;\n            }\n        }\n\n        public object? GetTarget() => throw new NotImplementedException();\n        public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }\n        public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }\n        public Task Deactivated => Task.CompletedTask;\n\n        public void Rehydrate(IRehydrationContext context)\n        {\n            // Migration is not supported, but we need to dispose of the context if it's provided\n            (context as IDisposable)?.Dispose();\n        }\n\n        public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n        {\n            // Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(Runtime.HostedClient)} completed processing all messages. Shutting down.\")]\n        private static partial void LogDebugShuttingDown(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100327,\n            Level = LogLevel.Error,\n            Message = \"Message not supported: {Message}\")]\n        private static partial void LogErrorUnsupportedMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100326,\n            Level = LogLevel.Error,\n            Message = \"RunClientMessagePump has thrown an exception. Continuing.\")]\n        private static partial void LogErrorMessagePumpException(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/IFatalErrorHandler.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Interface for controlling how fatal errors (such as a silo being declared defunct) are handled.\n    /// </summary>\n    public interface IFatalErrorHandler\n    {\n        /// <summary>\n        /// Determines whether the specified exception is unexpected.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        /// <returns><see langword=\"true\"/> if the specified exception is unexpected; otherwise, <see langword=\"false\"/>.</returns>\n        bool IsUnexpected(Exception exception);\n\n        /// <summary>\n        /// Called when a fatal exception occurs.\n        /// </summary>\n        /// <param name=\"sender\">The sender.</param>\n        /// <param name=\"context\">The context.</param>\n        /// <param name=\"exception\">The exception.</param>\n        void OnFatalException(object sender = null, string context = null, Exception exception = null);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/IHealthCheckParticipant.cs",
    "content": "namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Interface for health check participants\n    /// </summary>\n    public interface IHealthCheckParticipant : IHealthCheckable\n    {\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/InsideRuntimeClient.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.CodeGeneration;\nusing Orleans.Configuration;\nusing Orleans.Diagnostics;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Storage;\nusing static Orleans.Internal.StandardExtensions;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Internal class for system grains to get access to runtime object\n    /// </summary>\n    internal sealed partial class InsideRuntimeClient : IRuntimeClient, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly ILogger logger;\n        private readonly ILogger invokeExceptionLogger;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly SiloMessagingOptions messagingOptions;\n        private readonly ConcurrentDictionary<(GrainId, CorrelationId), CallbackData> callbacks;\n        private readonly InterfaceToImplementationMappingCache interfaceToImplementationMapping;\n        private readonly SharedCallbackData sharedCallbackData;\n        private readonly SharedCallbackData systemSharedCallbackData;\n        private readonly PeriodicTimer callbackTimer;\n\n        private GrainLocator grainLocator;\n        private MessageCenter messageCenter;\n        private List<IIncomingGrainCallFilter> grainCallFilters;\n        private readonly DeepCopier _deepCopier;\n        private readonly ApplicationRequestInstruments _applicationRequestInstruments;\n        private IGrainCallCancellationManager _cancellationManager;\n        private HostedClient hostedClient;\n\n        private HostedClient HostedClient => this.hostedClient ??= this.ServiceProvider.GetRequiredService<HostedClient>();\n        private readonly MessageFactory messageFactory;\n        private IGrainReferenceRuntime grainReferenceRuntime;\n        private Task callbackTimerTask;\n        private readonly MessagingTrace messagingTrace;\n        private readonly DeepCopier<Response> responseCopier;\n\n        public InsideRuntimeClient(\n            ILocalSiloDetails siloDetails,\n            IServiceProvider serviceProvider,\n            MessageFactory messageFactory,\n            ILoggerFactory loggerFactory,\n            IOptions<SiloMessagingOptions> messagingOptions,\n            MessagingTrace messagingTrace,\n            GrainReferenceActivator referenceActivator,\n            GrainInterfaceTypeResolver interfaceIdResolver,\n            GrainInterfaceTypeToGrainTypeResolver interfaceToTypeResolver,\n            DeepCopier deepCopier,\n            TimeProvider timeProvider,\n            InterfaceToImplementationMappingCache interfaceToImplementationMapping,\n            OrleansInstruments orleansInstruments)\n        {\n            TimeProvider = timeProvider;\n            this.interfaceToImplementationMapping = interfaceToImplementationMapping;\n            this._deepCopier = deepCopier;\n            this._applicationRequestInstruments = new(orleansInstruments);\n            this.ServiceProvider = serviceProvider;\n            this.MySilo = siloDetails.SiloAddress;\n            this.callbacks = new ConcurrentDictionary<(GrainId, CorrelationId), CallbackData>();\n            this.messageFactory = messageFactory;\n            this.ConcreteGrainFactory = new GrainFactory(this, referenceActivator, interfaceIdResolver, interfaceToTypeResolver);\n            this.logger = loggerFactory.CreateLogger<InsideRuntimeClient>();\n            this.invokeExceptionLogger = loggerFactory.CreateLogger($\"{typeof(Grain).FullName}.InvokeException\");\n            this.loggerFactory = loggerFactory;\n            this.messagingOptions = messagingOptions.Value;\n            this.messagingTrace = messagingTrace;\n            this.responseCopier = deepCopier.GetCopier<Response>();\n            var period = Max(TimeSpan.FromMilliseconds(1), Min(this.messagingOptions.ResponseTimeout, TimeSpan.FromSeconds(1)));\n            this.callbackTimer = new PeriodicTimer(period, timeProvider);\n\n            var callbackDataLogger = loggerFactory.CreateLogger<CallbackData>();\n            this.sharedCallbackData = new SharedCallbackData(\n                msg => this.UnregisterCallback(msg.SendingGrain, msg.Id),\n                callbackDataLogger,\n                this.messagingOptions.ResponseTimeout,\n                this.messagingOptions.CancelRequestOnTimeout,\n                this.messagingOptions.WaitForCancellationAcknowledgement,\n                cancellationManager: null);\n\n            this.systemSharedCallbackData = new SharedCallbackData(\n                msg => this.UnregisterCallback(msg.SendingGrain, msg.Id),\n                callbackDataLogger,\n                this.messagingOptions.SystemResponseTimeout,\n                cancelOnTimeout: false,\n                waitForCancellationAcknowledgement: this.messagingOptions.WaitForCancellationAcknowledgement,\n                cancellationManager: null);\n        }\n\n        public IServiceProvider ServiceProvider { get; }\n\n        public IInternalGrainFactory InternalGrainFactory => this.ConcreteGrainFactory;\n\n        private SiloAddress MySilo { get; }\n\n        public GrainFactory ConcreteGrainFactory { get; }\n\n        private GrainLocator GrainLocator\n            => this.grainLocator ?? (this.grainLocator = this.ServiceProvider.GetRequiredService<GrainLocator>());\n\n        private List<IIncomingGrainCallFilter> GrainCallFilters\n            => this.grainCallFilters ??= new List<IIncomingGrainCallFilter>(this.ServiceProvider.GetServices<IIncomingGrainCallFilter>());\n\n        private MessageCenter MessageCenter => this.messageCenter ?? (this.messageCenter = this.ServiceProvider.GetRequiredService<MessageCenter>());\n\n        public IGrainReferenceRuntime GrainReferenceRuntime => this.grainReferenceRuntime ?? (this.grainReferenceRuntime = this.ServiceProvider.GetRequiredService<IGrainReferenceRuntime>());\n\n        public void SendRequest(\n            GrainReference target,\n            IInvokable request,\n            IResponseCompletionSource context,\n            InvokeMethodOptions options)\n        {\n            var cancellationToken = request.GetCancellationToken();\n            cancellationToken.ThrowIfCancellationRequested();\n\n            var message = this.messageFactory.CreateMessage(request, options);\n            message.InterfaceType = target.InterfaceType;\n            message.InterfaceVersion = target.InterfaceVersion;\n\n            // fill in sender\n            if (message.SendingSilo == null)\n                message.SendingSilo = MySilo;\n\n            IGrainContext sendingActivation = RuntimeContext.Current;\n\n            if (sendingActivation == null)\n            {\n                var clientAddress = this.HostedClient.Address;\n                message.SendingGrain = clientAddress.GrainId;\n            }\n            else\n            {\n                message.SendingGrain = sendingActivation.GrainId;\n            }\n\n            // fill in destination\n            var targetGrainId = target.GrainId;\n            message.TargetGrain = targetGrainId;\n            SharedCallbackData sharedData;\n            if (SystemTargetGrainId.TryParse(targetGrainId, out var systemTargetGrainId))\n            {\n                message.TargetSilo = systemTargetGrainId.GetSiloAddress();\n                message.IsSystemMessage = true;\n                sharedData = this.systemSharedCallbackData;\n            }\n            else\n            {\n                sharedData = this.sharedCallbackData;\n            }\n\n            if (this.messagingOptions.DropExpiredMessages && message.IsExpirableMessage())\n            {\n                message.TimeToLive = request.GetDefaultResponseTimeout() ?? sharedData.ResponseTimeout;\n            }\n\n            var oneWay = (options & InvokeMethodOptions.OneWay) != 0;\n            if (!oneWay)\n            {\n                Debug.Assert(context is not null);\n\n                // Register a callback for the request.\n                var callbackData = new CallbackData(sharedData, context, message, _applicationRequestInstruments);\n                callbacks.TryAdd((message.SendingGrain, message.Id), callbackData);\n                callbackData.SubscribeForCancellation(cancellationToken);\n            }\n            else\n            {\n                context?.Complete();\n            }\n\n            this.messagingTrace.OnSendRequest(message);\n            this.MessageCenter.AddressAndSendMessage(message);\n        }\n\n        public void SendResponse(Message request, Response response)\n        {\n            OrleansInsideRuntimeClientEvent.Log.SendResponse(request);\n\n            // Don't process messages that have already timed out\n            if (request.IsExpired)\n            {\n                this.messagingTrace.OnDropExpiredMessage(request, MessagingInstruments.Phase.Respond);\n                return;\n            }\n\n            this.MessageCenter.SendResponse(request, response);\n        }\n\n        /// <summary>\n        /// UnRegister a callback.\n        /// </summary>\n        private void UnregisterCallback(GrainId grainId, CorrelationId correlationId)\n        {\n            callbacks.TryRemove((grainId, correlationId), out _);\n        }\n\n        public void SniffIncomingMessage(Message message)\n        {\n            try\n            {\n                if (message.CacheInvalidationHeader is { } cacheUpdates)\n                {\n                    lock (cacheUpdates)\n                    {\n                        foreach (var update in cacheUpdates)\n                        {\n                            GrainLocator.UpdateCache(update);\n                        }\n                    }\n                }\n\n#if false\n                //// 1:\n                //// Also record sending activation address for responses only in the cache.\n                //// We don't record sending addresses for requests, since it is not clear that this silo ever wants to send messages to the grain sending this request.\n                //// However, it is sure that this silo does send messages to the sender of a reply.\n                //// In most cases it will already have its address cached, unless it had a wrong outdated address cached and now this is a fresher address.\n                //// It is anyway always safe to cache the replier address.\n                //// 2:\n                //// after further thought decided not to do it.\n                //// It seems to better not bother caching the sender of a response at all,\n                //// and instead to take a very occasional hit of a full remote look-up instead of this small but non-zero hit on every response.\n                //if (message.Direction.Equals(Message.Directions.Response) && message.Result.Equals(Message.ResponseTypes.Success))\n                //{\n                //    ActivationAddress sender = message.SendingAddress;\n                //    // just make sure address we are about to cache is OK and cachable.\n                //    if (sender.IsComplete && !sender.Grain.IsClient && !sender.Grain.IsSystemTargetType && !sender.Activation.IsSystemTargetType)\n                //    {\n                //        directory.AddCacheEntry(sender);\n                //    }\n                //}\n#endif\n\n            }\n            catch (Exception exc)\n            {\n                LogWarningSniffIncomingMessage(this.logger, exc);\n            }\n        }\n\n        public async Task Invoke(IGrainContext target, Message message)\n        {\n            try\n            {\n                // Don't process messages that have already timed out\n                if (message.IsExpired)\n                {\n                    this.messagingTrace.OnDropExpiredMessage(message, MessagingInstruments.Phase.Invoke);\n                    return;\n                }\n\n                if (message.RequestContextData is { Count: > 0 })\n                {\n                    RequestContextExtensions.Import(message.RequestContextData);\n                }\n\n                Response response;\n                try\n                {\n                    switch (message.BodyObject)\n                    {\n                        case IInvokable invokable:\n                            {\n                                invokable.SetTarget(target);\n\n                                CancellationSourcesExtension.RegisterCancellationTokens(target, invokable);\n                                if (GrainCallFilters is { Count: > 0 } || target.GrainInstance is IIncomingGrainCallFilter)\n                                {\n                                    var invoker = new GrainMethodInvoker(message, target, invokable, GrainCallFilters, this.interfaceToImplementationMapping, this.responseCopier);\n                                    await invoker.Invoke();\n                                    response = invoker.Response;\n                                }\n                                else\n                                {\n                                    response = await invokable.Invoke();\n                                    response = this.responseCopier.Copy(response);\n                                }\n\n                                invokable.Dispose();\n                                break;\n                            }\n                        default:\n                            throw new NotSupportedException($\"Request {message.BodyObject} of type {message.BodyObject?.GetType()} is not supported\");\n                    }\n                }\n                catch (Exception exc1)\n                {\n                    response = Response.FromException(exc1);\n                }\n\n                if (response.Exception is { } invocationException)\n                {\n                    LogGrainInvokeException(this.invokeExceptionLogger, message.Direction != Message.Directions.OneWay ? LogLevel.Debug : LogLevel.Warning, invocationException, message);\n\n                    // If a grain allowed an inconsistent state exception to escape and the exception originated from\n                    // this activation, then deactivate it.\n                    if (invocationException is InconsistentStateException ise && ise.IsSourceActivation)\n                    {\n                        // Mark the exception so that it doesn't deactivate any other activations.\n                        ise.IsSourceActivation = false;\n\n                        LogDeactivatingInconsistentState(this.invokeExceptionLogger, target, invocationException);\n                        \n                        if (target is ActivationData ad && message.RequestContextData.TryGetActivityContext() is { } ac)\n                        {\n                            ad.Deactivate(new DeactivationReason(DeactivationReasonCode.ApplicationError, LogFormatter.PrintException(invocationException)), ac);\n                        }\n                        else\n                        {\n                            target.Deactivate(new DeactivationReason(DeactivationReasonCode.ApplicationError, LogFormatter.PrintException(invocationException)));\n                        }\n                    }\n                }\n\n                if (message.Direction != Message.Directions.OneWay)\n                {\n                    SafeSendResponse(message, response);\n                }\n\n                return;\n            }\n            catch (Exception exc2)\n            {\n                LogWarningInvokeException(this.logger, exc2, message);\n\n                if (message.Direction != Message.Directions.OneWay)\n                {\n                    SafeSendExceptionResponse(message, exc2);\n                }\n            }\n        }\n\n        private void SafeSendResponse(Message message, Response response)\n        {\n            try\n            {\n                SendResponse(message, (Response)this._deepCopier.Copy(response));\n            }\n            catch (Exception exc)\n            {\n                LogWarningResponseFailed(this.logger, exc);\n                SendResponse(message, Response.FromException(exc));\n            }\n        }\n\n        private void SafeSendExceptionResponse(Message message, Exception ex)\n        {\n            try\n            {\n                SendResponse(message, Response.FromException(ex));\n            }\n            catch (Exception exc1)\n            {\n                try\n                {\n                    LogWarningSendExceptionResponseFailed(this.logger, exc1);\n                    SendResponse(message, Response.FromException(exc1));\n                }\n                catch (Exception exc2)\n                {\n                    LogWarningUnhandledExceptionInInvoke(this.logger, exc2);\n                }\n            }\n        }\n\n        public void ReceiveResponse(Message message)\n        {\n            OrleansInsideRuntimeClientEvent.Log.ReceiveResponse(message);\n            if (message.Result is Message.ResponseTypes.Rejection)\n            {\n                if (!message.TargetSilo.Matches(this.MySilo))\n                {\n                    // gatewayed message - gateway back to sender\n                    LogTraceNoCallbackForRejection(this.logger, message);\n                    this.MessageCenter.AddressAndSendMessage(message);\n                    return;\n                }\n\n                LogHandleMessage(this.logger, message);\n                var rejection = (RejectionResponse)message.BodyObject;\n                switch (rejection.RejectionType)\n                {\n                    case Message.RejectionTypes.Overloaded:\n                        break;\n                    case Message.RejectionTypes.Unrecoverable:\n                    // Fall through & reroute\n                    case Message.RejectionTypes.Transient:\n                        if (message.CacheInvalidationHeader is null)\n                        {\n                            // Remove from local directory cache. Note that SendingGrain is the original target, since message is the rejection response.\n                            // If CacheInvalidationHeader is present, we already did this. Otherwise, we left this code for backward compatibility.\n                            // It should be retired as we move to use CacheMgmtHeader in all relevant places.\n                            this.GrainLocator.InvalidateCache(message.SendingGrain);\n                        }\n                        break;\n                    case Message.RejectionTypes.CacheInvalidation when message.HasCacheInvalidationHeader:\n                        // The message targeted an invalid (eg, defunct) activation and this response serves only to invalidate this silo's activation cache.\n                        return;\n                    default:\n                        LogErrorUnsupportedRejectionType(this.logger, rejection.RejectionType);\n                        break;\n                }\n            }\n            else if (message.Result == Message.ResponseTypes.Status)\n            {\n                var status = (StatusResponse)message.BodyObject;\n                callbacks.TryGetValue((message.TargetGrain, message.Id), out var callback);\n                var request = callback?.Message;\n                if (request is not null)\n                {\n                    callback.OnStatusUpdate(status);\n                    if (status.Diagnostics != null && status.Diagnostics.Count > 0)\n                    {\n                        LogInformationReceivedStatusUpdate(this.logger, request, status.Diagnostics);\n                    }\n                }\n                else\n                {\n                    if (messagingOptions.CancelUnknownRequestOnStatusUpdate)\n                    {\n                        // Cancel the call since the caller has abandoned it.\n                        // Note that the target and sender arguments are swapped because this is a response to the original request.\n                        _cancellationManager.SignalCancellation(\n                            message.SendingSilo,\n                            targetGrainId: message.SendingGrain,\n                            sendingGrainId: message.TargetGrain,\n                            messageId: message.Id);\n                    }\n\n                    if (status.Diagnostics != null && status.Diagnostics.Count > 0 && logger.IsEnabled(LogLevel.Debug))\n                    {\n                        var diagnosticsString = string.Join(\"\\n\", status.Diagnostics);\n                        this.logger.LogDebug(\"Received status update for unknown request. Message: {StatusMessage}. Status: {Diagnostics}\", message, diagnosticsString);\n                    }\n                }\n\n                return;\n            }\n\n            CallbackData callbackData;\n            bool found = callbacks.TryRemove((message.TargetGrain, message.Id), out callbackData);\n            if (found)\n            {\n                // IMPORTANT: we do not schedule the response callback via the scheduler, since the only thing it does\n                // is to resolve/break the resolver. The continuations/waits that are based on this resolution will be scheduled as work items.\n                callbackData.DoCallback(message);\n            }\n            else\n            {\n                LogDebugNoCallbackForResponse(this.logger, message);\n            }\n        }\n\n        public string CurrentActivationIdentity => RuntimeContext.Current?.Address.ToString() ?? this.HostedClient.ToString();\n\n        public TimeProvider TimeProvider { get; }\n\n        /// <inheritdoc />\n        public TimeSpan GetResponseTimeout() => this.sharedCallbackData.ResponseTimeout;\n\n        /// <inheritdoc />\n        public void SetResponseTimeout(TimeSpan timeout) => this.sharedCallbackData.ResponseTimeout = timeout;\n\n        public IAddressable CreateObjectReference(IAddressable obj)\n        {\n            if (RuntimeContext.Current is null) return this.HostedClient.CreateObjectReference(obj);\n            throw new InvalidOperationException(\"Cannot create a local object reference from a grain.\");\n        }\n\n        public void DeleteObjectReference(IAddressable obj)\n        {\n            if (RuntimeContext.Current is null)\n            {\n                this.HostedClient.DeleteObjectReference(obj);\n            }\n            else\n            {\n                throw new InvalidOperationException(\"Cannot delete a local object reference from a grain.\");\n            }\n        }\n\n        private async Task OnRuntimeInitializeStop(CancellationToken tc)\n        {\n            this.callbackTimer.Dispose();\n            if (this.callbackTimerTask is { } task)\n            {\n                await task.WaitAsync(tc);\n            }\n        }\n\n        private Task OnRuntimeInitializeStart(CancellationToken tc)\n        {\n            var stopWatch = ValueStopwatch.StartNew();\n            this.callbackTimerTask = Task.Run(MonitorCallbackExpiry);\n\n            LogDebugSiloStartPerfMeasure(this.logger, new(stopWatch));\n\n            return Task.CompletedTask;\n        }\n\n        private readonly struct ValueStopwatchLogValue(ValueStopwatch stopWatch)\n        {\n            override public string ToString()\n            {\n                stopWatch.Stop();\n                return stopWatch.Elapsed.ToString();\n            }\n        }\n\n        public void BreakOutstandingMessagesToSilo(SiloAddress deadSilo)\n        {\n            foreach (var callback in callbacks)\n            {\n                if (deadSilo.Equals(callback.Value.Message.TargetSilo))\n                {\n                    callback.Value.OnTargetSiloFail();\n                }\n            }\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            _cancellationManager = this.ServiceProvider.GetRequiredService<IGrainCallCancellationManager>();\n            sharedCallbackData.CancellationManager = _cancellationManager;\n            systemSharedCallbackData.CancellationManager = _cancellationManager;\n            lifecycle.Subscribe<InsideRuntimeClient>(ServiceLifecycleStage.RuntimeInitialize, OnRuntimeInitializeStart, OnRuntimeInitializeStop);\n        }\n\n        public int GetRunningRequestsCount(GrainInterfaceType grainInterfaceType)\n            => this.callbacks.Count(c => c.Value.Message.InterfaceType == grainInterfaceType);\n\n        private async Task MonitorCallbackExpiry()\n        {\n            while (await callbackTimer.WaitForNextTickAsync())\n            {\n                try\n                {\n                    var currentStopwatchTicks = ValueStopwatch.GetTimestamp();\n                    foreach (var (_, callback) in callbacks)\n                    {\n                        if (callback.IsCompleted)\n                        {\n                            continue;\n                        }\n\n                        if (callback.IsExpired(currentStopwatchTicks))\n                        {\n                            callback.OnTimeout();\n                        }\n                    }\n                }\n                catch (Exception ex)\n                {\n                    LogWarningWhileProcessingCallbackExpiry(this.logger, ex);\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.IGC_SniffIncomingMessage_Exc,\n            Message = \"SniffIncomingMessage has thrown exception. Ignoring.\")]\n        private static partial void LogWarningSniffIncomingMessage(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GrainInvokeException,\n            Message = \"Exception during Grain method call of message {Message}: \")]\n        private static partial void LogGrainInvokeException(ILogger logger, LogLevel level, Exception exception, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.Runtime_Error_100329,\n            Message = \"Exception during Invoke of message {Message}\")]\n        private static partial void LogWarningInvokeException(ILogger logger, Exception exception, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.IGC_SendResponseFailed,\n            Message = \"Exception trying to send a response\")]\n        private static partial void LogWarningResponseFailed(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.IGC_SendExceptionResponseFailed,\n            Message = \"Exception trying to send an exception response\")]\n        private static partial void LogWarningSendExceptionResponseFailed(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.IGC_UnhandledExceptionInInvoke,\n            Message = \"Exception trying to send an exception. Ignoring and not trying to send again.\")]\n        private static partial void LogWarningUnhandledExceptionInInvoke(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)ErrorCode.Dispatcher_NoCallbackForRejectionResp,\n            Message = \"No callback for rejection response message: {Message}\")]\n        private static partial void LogTraceNoCallbackForRejection(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.Dispatcher_HandleMsg,\n            Message = \"HandleMessage {Message}\")]\n        private static partial void LogHandleMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Deactivating {Target} due to inconsistent state.\")]\n        private static partial void LogDeactivatingInconsistentState(ILogger logger, IGrainContext target, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Dispatcher_InvalidEnum_RejectionType,\n            Message = \"Unsupported rejection type: {RejectionType}\")]\n        private static partial void LogErrorUnsupportedRejectionType(ILogger logger, Message.RejectionTypes rejectionType);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Received status update for pending request, Request: {RequestMessage}. Status: {Diagnostics}\")]\n        private static partial void LogInformationReceivedStatusUpdate(ILogger logger, Message requestMessage, IEnumerable<string> diagnostics);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Received status update for unknown request. Message: {StatusMessage}. Status: {Diagnostics}\")]\n        private static partial void LogInformationReceivedStatusUpdateUnknownRequest(ILogger logger, Message statusMessage, IEnumerable<string> diagnostics);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.Dispatcher_NoCallbackForResp,\n            Message = \"No callback for response message {Message}\")]\n        private static partial void LogDebugNoCallbackForResponse(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Message = \"Start InsideRuntimeClient took {ElapsedMs} milliseconds\"\n        )]\n        private static partial void LogDebugSiloStartPerfMeasure(ILogger logger, ValueStopwatchLogValue elapsedMs);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error while processing callback expiry.\"\n        )]\n        private static partial void LogWarningWhileProcessingCallbackExpiry(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/InternalClusterClient.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Client for communicating with clusters of Orleans silos.\n    /// </summary>\n    internal class InternalClusterClient : IInternalClusterClient\n    {\n        private readonly IRuntimeClient runtimeClient;\n        private readonly IInternalGrainFactory grainFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InternalClusterClient\"/> class.\n        /// </summary>\n        public InternalClusterClient(IRuntimeClient runtimeClient, IInternalGrainFactory grainFactory)\n        {\n            this.runtimeClient = runtimeClient;\n            this.grainFactory = grainFactory;\n        }\n\n        /// <inheritdoc />\n        public IGrainFactory GrainFactory => this.grainFactory;\n\n        /// <inheritdoc />\n        public IServiceProvider ServiceProvider => this.runtimeClient.ServiceProvider;\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerKey\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj)\n            where TGrainObserverInterface : IGrainObserver\n        {\n            return this.grainFactory.CreateObjectReference<TGrainObserverInterface>(obj);\n        }\n\n        /// <inheritdoc />\n        public void DeleteObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver\n        {\n            this.grainFactory.DeleteObjectReference<TGrainObserverInterface>(obj);\n        }\n\n        /// <inheritdoc />\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IAddressable obj)\n            where TGrainObserverInterface : IAddressable\n        {\n            return this.grainFactory.CreateObjectReference<TGrainObserverInterface>(obj);\n        }\n\n        /// <inheritdoc />\n        TGrainInterface IInternalGrainFactory.GetSystemTarget<TGrainInterface>(GrainType grainType, SiloAddress destination)\n        {\n            return this.grainFactory.GetSystemTarget<TGrainInterface>(grainType, destination);\n        }\n\n        /// <inheritdoc />\n        TGrainInterface IInternalGrainFactory.GetSystemTarget<TGrainInterface>(GrainId grainId)\n        {\n            return this.grainFactory.GetSystemTarget<TGrainInterface>(grainId);\n        }\n\n        /// <inheritdoc />\n        TGrainInterface IInternalGrainFactory.Cast<TGrainInterface>(IAddressable grain)\n        {\n            return this.grainFactory.Cast<TGrainInterface>(grain);\n        }\n\n        /// <inheritdoc />\n        object IInternalGrainFactory.Cast(IAddressable grain, Type interfaceType)\n        {\n            return this.grainFactory.Cast(grain, interfaceType);\n        }\n\n        /// <inheritdoc />\n        TGrainInterface IGrainFactory.GetGrain<TGrainInterface>(GrainId grainId)\n        {\n            return this.grainFactory.GetGrain<TGrainInterface>(grainId);\n        }\n\n        /// <inheritdoc />\n        IAddressable IGrainFactory.GetGrain(GrainId grainId)\n        {\n            return this.grainFactory.GetGrain(grainId);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey)\n        {\n            return this.grainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey)\n        {\n            return this.grainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, string grainPrimaryKey)\n        {\n            return this.grainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey, string keyExtension)\n        {\n            return this.grainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n        }\n\n        /// <inheritdoc />\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey, string keyExtension)\n        {\n            return this.grainFactory.GetGrain(grainInterfaceType, grainPrimaryKey);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(GrainId grainId, GrainInterfaceType interfaceId)\n        {\n            return this.grainFactory.GetGrain(grainId, interfaceId);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix)\n        {\n            return this.grainFactory.GetGrain(interfaceType, grainKey, grainClassNamePrefix);\n        }\n\n        /// <inheritdoc />\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey)\n        {\n            return this.grainFactory.GetGrain(interfaceType, grainKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/InternalGrainRuntime.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Versions;\nusing Orleans.Runtime.Versions.Compatibility;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Shared runtime services which grains use.\n    /// </summary>\n    internal class InternalGrainRuntime(\n        MessageCenter messageCenter,\n        Catalog catalog,\n        GrainVersionManifest versionManifest,\n        RuntimeMessagingTrace messagingTrace,\n        GrainLocator grainLocator,\n        CompatibilityDirectorManager compatibilityDirectorManager,\n        IOptions<GrainCollectionOptions> collectionOptions,\n        ILocalGrainDirectory localGrainDirectory,\n        IActivationWorkingSet activationWorkingSet)\n    {\n        public InsideRuntimeClient RuntimeClient { get; } = catalog.RuntimeClient;\n        public MessageCenter MessageCenter { get; } = messageCenter;\n        public Catalog Catalog { get; } = catalog;\n        public GrainVersionManifest GrainVersionManifest { get; } = versionManifest;\n        public RuntimeMessagingTrace MessagingTrace { get; } = messagingTrace;\n        public CompatibilityDirectorManager CompatibilityDirectorManager { get; } = compatibilityDirectorManager;\n        public GrainLocator GrainLocator { get; } = grainLocator;\n        public IOptions<GrainCollectionOptions> CollectionOptions { get; } = collectionOptions;\n        public ILocalGrainDirectory LocalGrainDirectory { get; } = localGrainDirectory;\n        public IActivationWorkingSet ActivationWorkingSet { get; } = activationWorkingSet;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/ManagementGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Metadata;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Providers;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Versions;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Management\n{\n    /// <summary>\n    /// Implementation class for the Orleans management grain.\n    /// </summary>\n    [StatelessWorker, Reentrant]\n    internal partial class ManagementGrain : Grain, IManagementGrain\n    {\n        private readonly IInternalGrainFactory internalGrainFactory;\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly IVersionStore versionStore;\n        private readonly MembershipTableManager membershipTableManager;\n        private readonly GrainManifest siloManifest;\n        private readonly ClusterManifest clusterManifest;\n        private readonly ILogger logger;\n        private readonly Catalog catalog;\n        private readonly GrainLocator grainLocator;\n\n        public ManagementGrain(\n            IInternalGrainFactory internalGrainFactory,\n            ISiloStatusOracle siloStatusOracle,\n            IVersionStore versionStore,\n            ILogger<ManagementGrain> logger,\n            MembershipTableManager membershipTableManager,\n            IClusterManifestProvider clusterManifestProvider,\n            Catalog catalog,\n            GrainLocator grainLocator)\n        {\n            this.membershipTableManager = membershipTableManager;\n            this.siloManifest = clusterManifestProvider.LocalGrainManifest;\n            this.clusterManifest = clusterManifestProvider.Current;\n            this.internalGrainFactory = internalGrainFactory;\n            this.siloStatusOracle = siloStatusOracle;\n            this.versionStore = versionStore;\n            this.logger = logger;\n            this.catalog = catalog;\n            this.grainLocator = grainLocator;\n        }\n\n        public async Task<Dictionary<SiloAddress, SiloStatus>> GetHosts(bool onlyActive = false)\n        {\n            await this.membershipTableManager.Refresh();\n            return this.siloStatusOracle.GetApproximateSiloStatuses(onlyActive);\n        }\n\n        public async Task<MembershipEntry[]> GetDetailedHosts(bool onlyActive = false)\n        {\n            await this.membershipTableManager.Refresh();\n\n            var table = this.membershipTableManager.MembershipTableSnapshot;\n\n            MembershipEntry[] result;\n            if (onlyActive)\n            {\n                result = table.Entries\n                    .Where(item => item.Value.Status == SiloStatus.Active)\n                    .Select(x => x.Value)\n                    .ToArray();\n            }\n            else\n            {\n                result = table.Entries\n                    .Select(x => x.Value)\n                    .ToArray();\n            }\n\n            return result;\n        }\n\n        public Task ForceGarbageCollection(SiloAddress[] siloAddresses)\n        {\n            var silos = GetSiloAddresses(siloAddresses);\n            LogInformationForceGarbageCollection(new(silos));\n            List<Task> actionPromises = PerformPerSiloAction(silos,\n                s => GetSiloControlReference(s).ForceGarbageCollection());\n            return Task.WhenAll(actionPromises);\n        }\n\n        public Task ForceActivationCollection(SiloAddress[] siloAddresses, TimeSpan ageLimit)\n        {\n            var silos = GetSiloAddresses(siloAddresses);\n            return Task.WhenAll(GetSiloAddresses(silos).Select(s =>\n                GetSiloControlReference(s).ForceActivationCollection(ageLimit)));\n        }\n\n        public async Task ForceActivationCollection(TimeSpan ageLimit)\n        {\n            Dictionary<SiloAddress, SiloStatus> hosts = await GetHosts(true);\n            SiloAddress[] silos = hosts.Keys.ToArray();\n            await ForceActivationCollection(silos, ageLimit);\n        }\n\n        public Task ForceRuntimeStatisticsCollection(SiloAddress[] siloAddresses)\n        {\n            var silos = GetSiloAddresses(siloAddresses);\n            LogInformationForceRuntimeStatisticsCollection(new(silos));\n            List<Task> actionPromises = PerformPerSiloAction(\n                silos,\n                s => GetSiloControlReference(s).ForceRuntimeStatisticsCollection());\n            return Task.WhenAll(actionPromises);\n        }\n\n        public Task<SiloRuntimeStatistics[]> GetRuntimeStatistics(SiloAddress[] siloAddresses)\n        {\n            var silos = GetSiloAddresses(siloAddresses);\n            LogDebugGetRuntimeStatistics(new(silos));\n            var promises = new List<Task<SiloRuntimeStatistics>>();\n            foreach (SiloAddress siloAddress in silos)\n                promises.Add(GetSiloControlReference(siloAddress).GetRuntimeStatistics());\n\n            return Task.WhenAll(promises);\n        }\n\n        public async Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics(SiloAddress[] hostsIds)\n\n        {\n            var all = GetSiloAddresses(hostsIds).Select(s =>\n                GetSiloControlReference(s).GetSimpleGrainStatistics()).ToList();\n            await Task.WhenAll(all);\n            return all.SelectMany(s => s.Result).ToArray();\n        }\n\n        public async Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics()\n        {\n            Dictionary<SiloAddress, SiloStatus> hosts = await GetHosts(true);\n            SiloAddress[] silos = hosts.Keys.ToArray();\n            return await GetSimpleGrainStatistics(silos);\n        }\n\n        public async Task<DetailedGrainStatistic[]> GetDetailedGrainStatistics(string[] types = null, SiloAddress[] hostsIds = null)\n        {\n            if (hostsIds == null)\n            {\n                Dictionary<SiloAddress, SiloStatus> hosts = await GetHosts(true);\n                hostsIds = hosts.Keys.ToArray();\n            }\n\n            var all = GetSiloAddresses(hostsIds).Select(s =>\n              GetSiloControlReference(s).GetDetailedGrainStatistics(types)).ToList();\n            await Task.WhenAll(all);\n            return all.SelectMany(s => s.Result).ToArray();\n        }\n\n        public async Task<int> GetGrainActivationCount(GrainReference grainReference)\n        {\n            Dictionary<SiloAddress, SiloStatus> hosts = await GetHosts(true);\n            List<SiloAddress> hostsIds = hosts.Keys.ToList();\n            var tasks = new List<Task<DetailedGrainReport>>();\n            foreach (var silo in hostsIds)\n                tasks.Add(GetSiloControlReference(silo).GetDetailedGrainReport(grainReference.GrainId));\n\n            await Task.WhenAll(tasks);\n            return tasks.Select(s => s.Result).Select(CountActivations).Sum();\n            static int CountActivations(DetailedGrainReport report) => report.LocalActivation is { Length: > 0 } ? 1 : 0;\n        }\n\n        public async Task SetCompatibilityStrategy(CompatibilityStrategy strategy)\n        {\n            await SetStrategy(\n                store => store.SetCompatibilityStrategy(strategy),\n                siloControl => siloControl.SetCompatibilityStrategy(strategy));\n        }\n\n        public async Task SetSelectorStrategy(VersionSelectorStrategy strategy)\n        {\n            await SetStrategy(\n                store => store.SetSelectorStrategy(strategy),\n                siloControl => siloControl.SetSelectorStrategy(strategy));\n        }\n\n        public async Task SetCompatibilityStrategy(GrainInterfaceType interfaceType, CompatibilityStrategy strategy)\n        {\n            CheckIfIsExistingInterface(interfaceType);\n            await SetStrategy(\n                store => store.SetCompatibilityStrategy(interfaceType, strategy),\n                siloControl => siloControl.SetCompatibilityStrategy(interfaceType, strategy));\n        }\n\n        public async Task SetSelectorStrategy(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy)\n        {\n            CheckIfIsExistingInterface(interfaceType);\n            await SetStrategy(\n                store => store.SetSelectorStrategy(interfaceType, strategy),\n                siloControl => siloControl.SetSelectorStrategy(interfaceType, strategy));\n        }\n\n        public async Task<int> GetTotalActivationCount()\n        {\n            Dictionary<SiloAddress, SiloStatus> hosts = await GetHosts(true);\n            List<SiloAddress> silos = hosts.Keys.ToList();\n            var tasks = new List<Task<int>>();\n            foreach (var silo in silos)\n                tasks.Add(GetSiloControlReference(silo).GetActivationCount());\n\n            await Task.WhenAll(tasks);\n            int sum = 0;\n            foreach (Task<int> task in tasks)\n                sum += task.Result;\n\n            return sum;\n        }\n\n        public Task<object[]> SendControlCommandToProvider<T>(string providerName, int command, object arg) where T : IControllable\n        {\n            return ExecutePerSiloCall(isc => isc.SendControlCommandToProvider<T>(providerName, command, arg),\n                $\"SendControlCommandToProvider of type {typeof(T).FullName} and name {providerName} command {command}.\");\n        }\n\n        public ValueTask<SiloAddress> GetActivationAddress(IAddressable reference)\n        {\n            var grainReference = reference as GrainReference;\n            var grainId = grainReference.GrainId;\n\n            GrainProperties grainProperties = default;\n            if (!siloManifest.Grains.TryGetValue(grainId.Type, out grainProperties))\n            {\n                var grainManifest = clusterManifest.AllGrainManifests\n                    .SelectMany(m => m.Grains.Where(g => g.Key == grainId.Type))\n                    .FirstOrDefault();\n                if (grainManifest.Value != null)\n                {\n                    grainProperties = grainManifest.Value;\n                }\n                else\n                {\n                    throw new ArgumentException($\"Unable to find Grain type '{grainId.Type}'. Make sure it is added to the Application Parts Manager at the Silo configuration.\");\n                }\n            }\n\n            if (grainProperties != default &&\n                grainProperties.Properties.TryGetValue(WellKnownGrainTypeProperties.PlacementStrategy, out string placementStrategy))\n            {\n                if (placementStrategy == nameof(StatelessWorkerPlacement))\n                {\n                    throw new InvalidOperationException(\n                        $\"Grain '{grainReference.ToString()}' is a Stateless Worker. This type of grain can't be looked up by this method\"\n                    );\n                }\n            }\n\n            if (grainLocator.TryLookupInCache(grainId, out var result))\n            {\n                return new ValueTask<SiloAddress>(result?.SiloAddress);\n            }\n\n            return LookupAsync(grainId, grainLocator);\n\n            static async ValueTask<SiloAddress> LookupAsync(GrainId grainId, GrainLocator grainLocator)\n            {\n                var result = await grainLocator.Lookup(grainId);\n                return result?.SiloAddress;\n            }\n        }\n\n        private void CheckIfIsExistingInterface(GrainInterfaceType interfaceType)\n        {\n            GrainInterfaceType lookupId;\n            if (GenericGrainInterfaceType.TryParse(interfaceType, out var generic))\n            {\n                lookupId = generic.Value;\n            }\n            else\n            {\n                lookupId = interfaceType;\n            }\n\n            if (!this.siloManifest.Interfaces.TryGetValue(lookupId, out _))\n            {\n                throw new ArgumentException($\"Interface '{interfaceType} not found\", nameof(interfaceType));\n            }\n        }\n\n        private async Task SetStrategy(Func<IVersionStore, Task> storeFunc, Func<ISiloControl, Task> applyFunc)\n        {\n            await storeFunc(versionStore);\n            var silos = GetSiloAddresses(null);\n            var actionPromises = PerformPerSiloAction(\n                silos,\n                s => applyFunc(GetSiloControlReference(s)));\n            try\n            {\n                await Task.WhenAll(actionPromises);\n            }\n            catch (Exception)\n            {\n                // ignored: silos that failed to set the new strategy will reload it from the storage\n                // in the future.\n            }\n        }\n\n        private async Task<object[]> ExecutePerSiloCall(Func<ISiloControl, Task<object>> action, string actionToLog)\n        {\n            var silos = await GetHosts(true);\n\n            LogDebugExecutingAction(actionToLog, new(silos));\n\n            var actionPromises = new List<Task<object>>();\n            foreach (SiloAddress siloAddress in silos.Keys.ToArray())\n                actionPromises.Add(action(GetSiloControlReference(siloAddress)));\n\n            return await Task.WhenAll(actionPromises);\n        }\n\n        private SiloAddress[] GetSiloAddresses(SiloAddress[] silos)\n        {\n            if (silos != null && silos.Length > 0)\n                return silos;\n\n            return this.siloStatusOracle\n                       .GetApproximateSiloStatuses(true).Keys.ToArray();\n        }\n\n        /// <summary>\n        /// Perform an action for each silo.\n        /// </summary>\n        /// <remarks>\n        /// Because SiloControl contains a reference to a system target, each method call using that reference\n        /// will get routed either locally or remotely to the appropriate silo instance auto-magically.\n        /// </remarks>\n        /// <param name=\"siloAddresses\">List of silos to perform the action for</param>\n        /// <param name=\"perSiloAction\">The action function to be performed for each silo</param>\n        /// <returns>Array containing one Task for each silo the action was performed for</returns>\n        private static List<Task> PerformPerSiloAction(SiloAddress[] siloAddresses, Func<SiloAddress, Task> perSiloAction)\n        {\n            var requestsToSilos = new List<Task>();\n            foreach (SiloAddress siloAddress in siloAddresses)\n                requestsToSilos.Add(perSiloAction(siloAddress));\n\n            return requestsToSilos;\n        }\n\n        private ISiloControl GetSiloControlReference(SiloAddress silo)\n        {\n            return this.internalGrainFactory.GetSystemTarget<ISiloControl>(Constants.SiloControlType, silo);\n        }\n\n        public async ValueTask<List<GrainId>> GetActiveGrains(GrainType grainType)\n        {\n            var hosts = await GetHosts(true);\n            var tasks = new List<Task<List<GrainId>>>();\n            foreach (var siloAddress in hosts.Keys)\n            {\n                tasks.Add(GetSiloControlReference(siloAddress).GetActiveGrains(grainType));\n            }\n\n            await Task.WhenAll(tasks);\n            var results = new List<GrainId>();\n            foreach (var promise in tasks)\n            {\n                results.AddRange(await promise);\n            }\n\n            return results;\n        }\n\n        public async Task<List<GrainCallFrequency>> GetGrainCallFrequencies(SiloAddress[] hostsIds = null)\n        {\n            if (hostsIds == null)\n            {\n                var hosts = await GetHosts(true);\n                hostsIds = [.. hosts.Keys];\n            }\n\n            var results = new List<GrainCallFrequency>();\n            foreach (var host in hostsIds)\n            {\n                var siloPartitioner = IActivationRepartitionerSystemTarget.GetReference(internalGrainFactory, host);\n                var frequencies = await siloPartitioner.GetGrainCallFrequencies();\n                foreach (var frequency in frequencies)\n                {\n                    results.Add(new GrainCallFrequency\n                    {\n                        SourceGrain = frequency.Item1.Source.Id,\n                        TargetGrain = frequency.Item1.Target.Id,\n                        SourceHost = frequency.Item1.Source.Silo,\n                        TargetHost = frequency.Item1.Target.Silo,\n                        CallCount = frequency.Item2\n                    });\n                }\n            }\n\n            return results;\n        }\n\n        public async ValueTask ResetGrainCallFrequencies(SiloAddress[] hostsIds = null)\n        {\n            if (hostsIds == null)\n            {\n                var hosts = await GetHosts(true);\n                hostsIds = [.. hosts.Keys];\n            }\n\n            foreach (var host in hostsIds)\n            {\n                var siloBalancer = IActivationRepartitionerSystemTarget.GetReference(internalGrainFactory, host);\n                await siloBalancer.ResetCounters();\n            }\n        }\n\n        private readonly struct SiloAddressesLogValue(SiloAddress[] siloAddresses)\n        {\n            public override string ToString() => Utils.EnumerableToString(siloAddresses);\n        }\n\n        [LoggerMessage(\n            EventId = 0,\n            Level = LogLevel.Information,\n            Message = \"Forcing garbage collection on {SiloAddresses}\")]\n        private partial void LogInformationForceGarbageCollection(SiloAddressesLogValue siloAddresses);\n\n        [LoggerMessage(\n            EventId = 0,\n            Level = LogLevel.Information,\n            Message = \"Forcing runtime statistics collection on {SiloAddresses}\")]\n        private partial void LogInformationForceRuntimeStatisticsCollection(SiloAddressesLogValue siloAddresses);\n\n        [LoggerMessage(\n            EventId = 0,\n            Level = LogLevel.Debug,\n            Message = \"GetRuntimeStatistics on {SiloAddresses}\")]\n        private partial void LogDebugGetRuntimeStatistics(SiloAddressesLogValue siloAddresses);\n\n        private readonly struct SiloAddressesKeysLogValue(Dictionary<SiloAddress, SiloStatus> silos)\n        {\n            public override string ToString() => Utils.EnumerableToString(silos.Keys);\n        }\n\n        [LoggerMessage(\n            EventId = 0,\n            Level = LogLevel.Debug,\n            Message = \"Executing {Action} against {SiloAddresses}\"\n        )]\n        private partial void LogDebugExecutingAction(string action, SiloAddressesKeysLogValue siloAddresses);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/SystemStatus.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// System status values and current register\n    /// </summary>\n    internal sealed class SystemStatus : IEquatable<SystemStatus>\n    {\n        private enum InternalSystemStatus\n        {\n            Unknown = 0,\n            Creating,\n            Created,\n            Starting,\n            Running,\n            Stopping,\n            ShuttingDown,\n            Terminated,\n        };\n\n        /// <summary>Status = Unknown</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Unknown = new SystemStatus(InternalSystemStatus.Unknown);\n\n        /// <summary>Status = Creating</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Creating = new SystemStatus(InternalSystemStatus.Creating);\n\n        /// <summary>Status = Created</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Created = new SystemStatus(InternalSystemStatus.Created);\n\n        /// <summary>Status = Starting</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Starting = new SystemStatus(InternalSystemStatus.Starting);\n        \n        /// <summary>Status = Running</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Running = new SystemStatus(InternalSystemStatus.Running);\n        \n        /// <summary>Status = Stopping</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Stopping = new SystemStatus(InternalSystemStatus.Stopping);\n        \n        /// <summary>Status = ShuttingDown</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus ShuttingDown = new SystemStatus(InternalSystemStatus.ShuttingDown);\n\n        /// <summary>Status = Terminated</summary>\n        [SuppressMessage(\"Microsoft.Security\", \"CA2104:DoNotDeclareReadOnlyMutableReferenceTypes\")]\n        public static readonly SystemStatus Terminated = new SystemStatus(InternalSystemStatus.Terminated);\n\n        private readonly InternalSystemStatus value;\n        private SystemStatus(InternalSystemStatus name) { this.value = name; }\n\n        /// <see cref=\"object.ToString\"/>\n        public override string ToString() { return this.value.ToString(); }\n        /// <see cref=\"object.GetHashCode\"/>\n        public override int GetHashCode() { return this.value.GetHashCode(); }\n        /// <see cref=\"object.Equals(object)\"/>\n        public override bool Equals(object obj) { var ss = obj as SystemStatus; return ss != null && this.Equals(ss); }\n        /// <see cref=\"IEquatable{T}.Equals(T)\"/>\n        public bool Equals(SystemStatus other) { return (other != null) && this.value.Equals(other.value); }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Core/SystemTarget.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Base class for various system services, such as grain directory, reminder service, etc.\n    /// Made public for GrainService to inherit from it.\n    /// Can be turned to internal after a refactoring that would remove the inheritance relation.\n    /// </summary>\n    public abstract partial class SystemTarget : ISystemTarget, ISystemTargetBase, IGrainContext, IGrainExtensionBinder, ISpanFormattable, IDisposable, IGrainTimerRegistry, IGrainCallCancellationExtension\n    {\n        private readonly Func<object?, Task> _handleRequest;\n        private readonly SystemTargetGrainId _id;\n        private readonly SystemTargetShared _shared;\n        private readonly HashSet<IGrainTimer> _timers = [];\n        private readonly Dictionary<Message, Task> _runningRequests = [];\n        private readonly Dictionary<Type, object> _components = [];\n\n\n        /// <summary>Silo address of the system target.</summary>\n        public SiloAddress Silo => _shared.SiloAddress;\n        internal GrainAddress ActivationAddress { get; }\n\n        internal ActivationId ActivationId { get; set; }\n        private readonly ILogger _logger;\n\n        internal InsideRuntimeClient RuntimeClient => _shared.RuntimeClient;\n\n        /// <inheritdoc/>\n        public GrainReference GrainReference { get => field ??= _shared.GrainReferenceActivator.CreateReference(_id.GrainId, default); private set; }\n\n        /// <inheritdoc/>\n        public GrainId GrainId => _id.GrainId;\n\n        /// <inheritdoc/>\n        object IGrainContext.GrainInstance => this;\n\n        /// <inheritdoc/>\n        ActivationId IGrainContext.ActivationId => ActivationId;\n\n        /// <inheritdoc/>\n        GrainAddress IGrainContext.Address => ActivationAddress;\n\n        private RuntimeMessagingTrace MessagingTrace => _shared.MessagingTrace;\n\n        /// <summary>\n        /// Obsolete parameterless constructor for <see cref=\"SystemTarget\"/>.\n        /// <para>\n        /// <b>Breaking change:</b> This constructor is obsolete and will throw a <see cref=\"NotSupportedException\"/> if called.\n        /// It is present only to satisfy certain reflection-based scenarios and should not be used in application code.\n        /// </para>\n        /// <para>\n        /// If you are using reflection or serialization frameworks that require a parameterless constructor,\n        /// update your code to use the constructor with parameters: <see cref=\"SystemTarget(SystemTargetGrainId, SystemTargetShared)\"/>.\n        /// </para>\n        /// </summary>\n        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n        [Obsolete(\"Do not call the empty constructor.\")]\n        protected SystemTarget() => throw new NotSupportedException();\n\n        internal SystemTarget(GrainType grainType, SystemTargetShared shared)\n            : this(SystemTargetGrainId.Create(grainType, shared.SiloAddress), shared)\n        {\n        }\n\n        internal SystemTarget(SystemTargetGrainId grainId, SystemTargetShared shared)\n        {\n            _id = grainId;\n            _shared = shared;\n            _handleRequest = state => this.HandleNewRequest((Message)state!);\n            ActivationId = ActivationId.GetDeterministic(grainId.GrainId);\n            ActivationAddress = GrainAddress.GetAddress(Silo, _id.GrainId, ActivationId);\n            _logger = shared.LoggerFactory.CreateLogger(GetType());\n            WorkItemGroup = _shared.CreateWorkItemGroup(this);\n            if (!Constants.IsSingletonSystemTarget(GrainId.Type))\n            {\n                GrainInstruments.IncrementSystemTargetCounts(Constants.SystemTargetName(GrainId.Type));\n            }\n        }\n\n        internal WorkItemGroup WorkItemGroup { get; }\n\n        /// <inheritdoc />\n        public IServiceProvider ActivationServices => RuntimeClient.ServiceProvider;\n\n        /// <inheritdoc />\n        IGrainLifecycle IGrainContext.ObservableLifecycle => throw new NotImplementedException(\"IGrainContext.ObservableLifecycle is not implemented by SystemTarget\");\n\n        /// <inheritdoc />\n        public IWorkItemScheduler Scheduler => WorkItemGroup;\n\n        /// <summary>\n        /// Gets the component with the specified type.\n        /// </summary>\n        /// <typeparam name=\"TComponent\">The component type.</typeparam>\n        /// <returns>The component with the specified type.</returns>\n        public TComponent? GetComponent<TComponent>()\n        {\n            TComponent? result;\n            if (this is TComponent instanceResult)\n            {\n                result = instanceResult;\n            }\n            else if (_components.TryGetValue(typeof(TComponent), out var resultObj))\n            {\n                result = (TComponent)resultObj;\n            }\n            else if (typeof(TComponent) == typeof(PlacementStrategy))\n            {\n                result = (TComponent)(object)SystemTargetPlacementStrategy.Instance;\n            }\n            else\n            {\n                result = default;\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public void SetComponent<TComponent>(TComponent? instance) where TComponent : class\n        {\n            if (this is TComponent)\n            {\n                throw new ArgumentException(\"Cannot override a component which is implemented by this grain\");\n            }\n\n            if (instance == null)\n            {\n                _components.Remove(typeof(TComponent));\n                return;\n            }\n\n            _components[typeof(TComponent)] = instance;\n        }\n\n        internal async Task HandleNewRequest(Message request)\n        {\n            try\n            {\n                await RuntimeClient.Invoke(this, request);\n            }\n            catch\n            {\n                // Ignore.\n            }\n            finally\n            {\n                lock (_runningRequests)\n                {\n                    _runningRequests.Remove(request);\n                }\n            }\n        }\n\n        internal void HandleResponse(Message response)\n        {\n            RuntimeClient.ReceiveResponse(response);\n        }\n\n        /// <summary>\n        /// Registers a timer to send regular callbacks to this system target.\n        /// </summary>\n        /// <param name=\"callback\">The timer callback, which will fire whenever the timer becomes due.</param>\n        /// <param name=\"state\">The state object passed to the callback.</param>\n        /// <param name=\"dueTime\">\n        /// The amount of time to delay before the <paramref name=\"callback\"/> is invoked.\n        /// Specify <see cref=\"System.Threading.Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n        /// Specify <see cref=\"TimeSpan.Zero\"/> to invoke the callback promptly.\n        /// </param>\n        /// <param name=\"period\">\n        /// The time interval between invocations of <paramref name=\"callback\"/>.\n        /// Specify <see cref=\"System.Threading.Timeout.InfiniteTimeSpan\"/> to disable periodic signaling.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IDisposable\"/> object which will cancel the timer upon disposal.\n        /// </returns>\n        public IGrainTimer RegisterTimer(Func<object?, Task> callback, object? state, TimeSpan dueTime, TimeSpan period)\n        {\n            ArgumentNullException.ThrowIfNull(callback);\n            var timer = _shared.TimerRegistry\n                .RegisterGrainTimer(this, static (state, _) => state.Callback(state.State), (Callback: callback, State: state), new() { DueTime = dueTime, Period = period, Interleave = true });\n            return timer;\n        }\n\n        /// <summary>\n        /// Registers a timer to send regular callbacks to this system target.\n        /// </summary>\n        /// <param name=\"callback\">The timer callback, which will fire whenever the timer becomes due.</param>\n        /// <param name=\"dueTime\">\n        /// The amount of time to delay before the <paramref name=\"callback\"/> is invoked.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n        /// Specify <see cref=\"TimeSpan.Zero\"/> to invoke the callback promptly.\n        /// </param>\n        /// <param name=\"period\">\n        /// The time interval between invocations of <paramref name=\"callback\"/>.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to disable periodic signaling.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IDisposable\"/> object which will cancel the timer upon disposal.\n        /// </returns>\n        public IGrainTimer RegisterGrainTimer(Func<CancellationToken, Task> callback, TimeSpan dueTime, TimeSpan period)\n        {\n            CheckRuntimeContext();\n            ArgumentNullException.ThrowIfNull(callback);\n            var timer = _shared.TimerRegistry\n                .RegisterGrainTimer(this, (state, ct) => state(ct), callback, new() { DueTime = dueTime, Period = period, Interleave = true });\n            return timer;\n        }\n\n        /// <summary>\n        /// Registers a timer to send regular callbacks to this grain.\n        /// This timer will keep the current grain from being deactivated.\n        /// </summary>\n        /// <param name=\"callback\">The timer callback, which will fire whenever the timer becomes due.</param>\n        /// <param name=\"state\">The state object passed to the callback.</param>\n        /// <param name=\"dueTime\">\n        /// The amount of time to delay before the <paramref name=\"callback\"/> is invoked.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to prevent the timer from starting.\n        /// Specify <see cref=\"TimeSpan.Zero\"/> to invoke the callback promptly.\n        /// </param>\n        /// <param name=\"period\">\n        /// The time interval between invocations of <paramref name=\"callback\"/>.\n        /// Specify <see cref=\"Timeout.InfiniteTimeSpan\"/> to disable periodic signaling.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IDisposable\"/> object which will cancel the timer upon disposal.\n        /// </returns>\n        public IGrainTimer RegisterGrainTimer<TState>(Func<TState, CancellationToken, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n        {\n            CheckRuntimeContext();\n            ArgumentNullException.ThrowIfNull(callback);\n            var timer = _shared.TimerRegistry\n                .RegisterGrainTimer(this, callback, state, new() { DueTime = dueTime, Period = period, Interleave = true });\n            return timer;\n        }\n\n        /// <inheritdoc/>\n        public sealed override string ToString() => $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"[SystemTarget: {Silo}/{_id}{ActivationId}]\", out charsWritten);\n\n        /// <summary>Adds details about message currently being processed</summary>\n        internal string ToDetailedString()\n        {\n            lock (_runningRequests)\n            {\n                return $\"{this} CurrentlyExecuting={_runningRequests}\";\n            }\n        }\n\n        /// <inheritdoc/>\n        bool IEquatable<IGrainContext>.Equals(IGrainContext? other) => ReferenceEquals(this, other);\n\n        /// <inheritdoc/>\n        public (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            TExtension implementation;\n            if (GetComponent<TExtensionInterface>() is object existing)\n            {\n                if (existing is TExtension typedResult)\n                {\n                    implementation = typedResult;\n                }\n                else\n                {\n                    throw new InvalidCastException($\"Cannot cast existing extension of type {existing.GetType()} to target type {typeof(TExtension)}\");\n                }\n            }\n            else\n            {\n                implementation = newExtensionFunc();\n                SetComponent<TExtensionInterface>(implementation);\n            }\n\n            var reference = GrainReference.Cast<TExtensionInterface>();\n            return (implementation, reference);\n        }\n\n        /// <inheritdoc/>\n        object? ITargetHolder.GetComponent(Type componentType)\n        {\n            object? result;\n            if (componentType.IsAssignableFrom(GetType()))\n            {\n                result = this;\n            }\n            else if (_components.TryGetValue(componentType, out var resultObj))\n            {\n                result = resultObj;\n            }\n            else if (componentType == typeof(PlacementStrategy))\n            {\n                result = SystemTargetPlacementStrategy.Instance;\n            }\n            else if (typeof(IGrainExtension).IsAssignableFrom(componentType))\n            {\n                var implementation = ActivationServices.GetKeyedService<IGrainExtension>(componentType);\n                if (implementation is null)\n                {\n                    throw new GrainExtensionNotInstalledException($\"No extension of type {componentType} is installed on this instance and no implementations are registered for automated install\");\n                }\n\n                _components[componentType] = implementation;\n                result = implementation;\n            }\n            else\n            {\n                result = default;\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public TExtensionInterface GetExtension<TExtensionInterface>()\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (GetComponent<TExtensionInterface>() is TExtensionInterface result)\n            {\n                return result;\n            }\n\n            var implementation = ActivationServices.GetKeyedService<IGrainExtension>(typeof(TExtensionInterface));\n            if (!(implementation is TExtensionInterface typedResult))\n            {\n                throw new GrainExtensionNotInstalledException($\"No extension of type {typeof(TExtensionInterface)} is installed on this instance and no implementations are registered for automated install\");\n            }\n\n            SetComponent<TExtensionInterface>(typedResult);\n            return typedResult;\n        }\n\n        /// <inheritdoc/>\n        public void ReceiveMessage(object message)\n        {\n            var msg = (Message)message;\n            switch (msg.Direction)\n            {\n                case Message.Directions.Request:\n                case Message.Directions.OneWay:\n                    {\n                        MessagingTrace.OnEnqueueMessageOnActivation(msg, this);\n                        using var suppressExecutionContext = new ExecutionContextSuppressor();\n                        var task = new Task<Task>(_handleRequest, msg);\n                        lock (_runningRequests)\n                        {\n                            _runningRequests[msg] = task;\n                        }\n\n                        task.Start(WorkItemGroup.TaskScheduler);\n                        break;\n                    }\n\n                default:\n                    LogInvalidMessage(_logger, msg);\n                    break;\n            }\n        }\n\n        /// <inheritdoc/>\n        public object? GetTarget() => this;\n\n        /// <inheritdoc/>\n        public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken) { }\n\n        /// <inheritdoc/>\n        public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }\n\n        /// <inheritdoc/>\n        public Task Deactivated => Task.CompletedTask;\n\n        public void Dispose()\n        {\n            if (!Constants.IsSingletonSystemTarget(GrainId.Type))\n            {\n                GrainInstruments.DecrementSystemTargetCounts(Constants.SystemTargetName(GrainId.Type));\n            }\n\n            StopAllTimers();\n        }\n\n        public void Rehydrate(IRehydrationContext context)\n        {\n            // Migration is not supported, but we need to dispose of the context if it's provided\n            (context as IDisposable)?.Dispose();\n        }\n\n        public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken)\n        {\n            // Migration is not supported. Do nothing: the contract is that this method attempts migration, but does not guarantee it will occur.\n        }\n\n        void IGrainTimerRegistry.OnTimerCreated(IGrainTimer timer) { lock (_timers) { _timers.Add(timer); } }\n        void IGrainTimerRegistry.OnTimerDisposed(IGrainTimer timer) { lock (_timers) { _timers.Remove(timer); } }\n        private void StopAllTimers()\n        {\n            List<IGrainTimer> timers;\n            lock (_timers)\n            {\n                timers = [.. _timers];\n                _timers.Clear();\n            }\n\n            foreach (var timer in timers)\n            {\n                timer.Dispose();\n            }\n        }\n\n        internal void CheckRuntimeContext()\n        {\n            var context = RuntimeContext.Current;\n            if (context is null)\n            {\n                ThrowMissingContext();\n                void ThrowMissingContext() => throw new InvalidOperationException($\"Access violation: attempted to access context '{this}' from null context.\");\n            }\n\n            if (!ReferenceEquals(context, this))\n            {\n                ThrowAccessViolation(context);\n                void ThrowAccessViolation(IGrainContext? currentContext) => throw new InvalidOperationException($\"Access violation: attempt to access context '{this}' from different context, '{currentContext}'.\");\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Runtime_Error_100097,\n            Message = \"Invalid message: {Message}\"\n        )]\n        private static partial void LogInvalidMessage(ILogger logger, Message Message);\n\n        ValueTask IGrainCallCancellationExtension.CancelRequestAsync(GrainId senderGrainId, CorrelationId messageId)\n            => this.RunOrQueueTask(static state => state.self.CancelRequestAsyncCore(state.senderGrainId, state.messageId), (self: this, senderGrainId, messageId));\n\n        private ValueTask CancelRequestAsyncCore(GrainId senderGrainId, CorrelationId messageId)\n        {\n            if (!TryCancelRequest())\n            {\n                // The message being canceled may not have arrived yet, so retry a few times.\n                return RetryCancellationAfterDelay();\n            }\n\n            return ValueTask.CompletedTask;\n\n            async ValueTask RetryCancellationAfterDelay()\n            {\n                var attemptsRemaining = 3;\n                do\n                {\n                    await Task.Delay(1_000);\n\n                    if (TryCancelRequest())\n                    {\n                        return;\n                    }\n                } while (--attemptsRemaining > 0);\n            }\n\n            bool TryCancelRequest()\n            {\n                Message? message = null;\n\n                lock (_runningRequests)\n                {\n                    // Check the running requests.\n                    foreach (var runningRequest in _runningRequests.Keys)\n                    {\n                        if (runningRequest.Id == messageId && runningRequest.SendingGrain == senderGrainId)\n                        {\n                            message = runningRequest;\n                            break;\n                        }\n                    }\n                }\n\n                var didCancel = false;\n                if (message is not null)\n                {\n                    if (message.BodyObject is IInvokable invokableRequest)\n                    {\n                        didCancel = TryCancelInvokable(invokableRequest) || !invokableRequest.IsCancellable;\n                    }\n                    else\n                    {\n                        // Assume the request is not cancellable.\n                        didCancel = true;\n                    }\n                }\n\n                return didCancel;\n            }\n\n            bool TryCancelInvokable(IInvokable request)\n            {\n                try\n                {\n                    return request.TryCancel();\n                }\n                catch (Exception exception)\n                {\n                    LogErrorCancellationCallbackFailed(_logger, exception);\n                    return true;\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"One or more cancellation callbacks failed.\"\n        )]\n        private static partial void LogErrorCancellationCallbackFailed(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Development/DevelopmentSiloBuilderExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.LeaseProviders;\n\nnamespace Orleans.Runtime.Development\n{\n    /// <summary>\n    /// <see cref=\"ISiloBuilder\"/> extensions to configure an in-memory lease provider.\n    /// </summary>\n    public static class DevelopmentSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configures silo with test/development features.\n        /// </summary>\n        /// <remarks>\n        /// Not for production use. This is for development and test scenarios only.\n        /// </remarks>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n         public static ISiloBuilder UseInMemoryLeaseProvider(this ISiloBuilder builder)\n        {\n            return builder.ConfigureServices(UseInMemoryLeaseProvider);\n        }\n\n        private static void UseInMemoryLeaseProvider(IServiceCollection services)\n        {\n            services.AddTransient<ILeaseProvider, InMemoryLeaseProvider>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Development/InMemoryLeaseProvider.cs",
    "content": "using Orleans.LeaseProviders;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Development\n{\n    /// <summary>\n    /// In memory lease provider for development and test use.\n    /// This provider stores lease information in memory an can be lost if grain\n    /// becomes inactive or if silo crashes.  This implementation is only intended\n    /// for test or local development purposes - NOT FOR PRODUCTION USE.\n    /// </summary>\n    public class InMemoryLeaseProvider : ILeaseProvider\n    {\n        private readonly IDevelopmentLeaseProviderGrain leaseProvider;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InMemoryLeaseProvider\"/> class.\n        /// </summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        public InMemoryLeaseProvider(IGrainFactory grainFactory)\n        {\n            this.leaseProvider = GetLeaseProviderGrain(grainFactory);\n        }\n\n        /// <inheritdoc/>\n        public async Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests)\n        {\n            try\n            {\n                return await this.leaseProvider.Acquire(category, leaseRequests);\n            } catch (Exception ex)\n            {\n                return leaseRequests.Select(request => new AcquireLeaseResult(new AcquiredLease(request.ResourceKey), ResponseCode.TransientFailure, ex)).ToArray();\n            }\n        }\n\n        /// <inheritdoc/>\n        public Task Release(string category, AcquiredLease[] acquiredLeases)\n        {\n            return this.leaseProvider.Release(category, acquiredLeases);\n        }\n\n        /// <inheritdoc/>\n        public async Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] acquiredLeases)\n        {\n            try\n            {\n                return await this.leaseProvider.Renew(category, acquiredLeases);\n            }\n            catch (Exception ex)\n            {\n                return acquiredLeases.Select(request => new AcquireLeaseResult(new AcquiredLease(request.ResourceKey), ResponseCode.TransientFailure, ex)).ToArray();\n            }\n        }\n\n        private static IDevelopmentLeaseProviderGrain GetLeaseProviderGrain(IGrainFactory grainFactory)\n        {\n            return grainFactory.GetGrain<IDevelopmentLeaseProviderGrain>(0);\n        }\n    }\n\n    internal interface IDevelopmentLeaseProviderGrain : ILeaseProvider, IGrainWithIntegerKey\n    {\n        /// <summary>\n        /// Forgets about all leases.  Used to simulate loss of this grain or to force rebalance of queues\n        /// </summary>\n        /// <returns></returns>\n        Task Reset();\n    }\n\n    /// <summary>\n    /// Grain that stores lease information in memory.\n    /// TODO: Consider making this a stateful grain, as a production viable implementation of lease provider that works with storage\n    /// providers.\n    /// </summary>\n    internal class DevelopmentLeaseProviderGrain : Grain, IDevelopmentLeaseProviderGrain\n    {\n        private readonly Dictionary<Tuple<string, string>, Lease> leases = new Dictionary<Tuple<string, string>, Lease>();\n\n        public Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests)\n        {\n            return Task.FromResult(leaseRequests.Select(request => Acquire(category, request)).ToArray());\n        }\n\n        public Task Release(string category, AcquiredLease[] acquiredLeases)\n        {\n            foreach(AcquiredLease lease in acquiredLeases)\n            {\n                Release(category, lease);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] acquiredLeases)\n        {\n            return Task.FromResult(acquiredLeases.Select(lease => Renew(category, lease)).ToArray());\n        }\n\n        public Task Reset()\n        {\n            this.leases.Clear();\n            return Task.CompletedTask;\n        }\n\n        private AcquireLeaseResult Acquire(string category, LeaseRequest leaseRequest)\n        {\n            DateTime now = DateTime.UtcNow;\n            Lease lease = this.leases.GetValueOrAddNew(Tuple.Create(category, leaseRequest.ResourceKey));\n            if(lease.ExpiredUtc < now)\n            {\n                lease.ExpiredUtc = now + leaseRequest.Duration;\n                return new AcquireLeaseResult(new AcquiredLease(leaseRequest.ResourceKey, leaseRequest.Duration, lease.Token, now), ResponseCode.OK, null);\n            }\n            return new AcquireLeaseResult(new AcquiredLease(leaseRequest.ResourceKey), ResponseCode.LeaseNotAvailable, new OrleansException(\"Lease not available\"));\n        }\n\n        private void Release(string category, AcquiredLease acquiredLease)\n        {\n            Tuple<string,string> leaseKey = Tuple.Create(category, acquiredLease.ResourceKey);\n            if (this.leases.TryGetValue(leaseKey, out Lease lease) && lease.Token == acquiredLease.Token)\n            {\n                leases.Remove(leaseKey);\n            }\n        }\n\n        private AcquireLeaseResult Renew(string category, AcquiredLease acquiredLease)\n        {\n            DateTime now = DateTime.UtcNow;\n            // if lease exists, and we have the right token, and lease has not expired, renew.\n            if (!this.leases.TryGetValue(Tuple.Create(category, acquiredLease.ResourceKey), out Lease lease) || lease.Token != acquiredLease.Token)\n            {\n                return new AcquireLeaseResult(new AcquiredLease(acquiredLease.ResourceKey), ResponseCode.InvalidToken, new OrleansException(\"Invalid token provided, caller is not the owner.\"));\n            }\n            // we don't care if lease has expired or not as long as owner has not changed.\n            lease.ExpiredUtc = now + acquiredLease.Duration;\n            return new AcquireLeaseResult(new AcquiredLease(acquiredLease.ResourceKey, acquiredLease.Duration, lease.Token, now), ResponseCode.OK, null);\n        }\n\n        private class Lease\n        {\n            private DateTime expiredUtc;\n\n            public DateTime ExpiredUtc\n            {\n                get { return expiredUtc; }\n                set\n                {\n                    expiredUtc = value;\n                    Token = Guid.NewGuid().ToString();\n                }\n            }\n            public string Token { get; private set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/GrainConstructorArgumentFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Constructs instances of a grain class using constructor dependency injection.\n    /// </summary>\n    public class GrainConstructorArgumentFactory\n    {\n        private static readonly Type FacetMarkerInterfaceType = typeof(IFacetMetadata);\n        private static readonly MethodInfo GetFactoryMethod = typeof(GrainConstructorArgumentFactory).GetMethod(nameof(GetArgumentFactory), BindingFlags.NonPublic | BindingFlags.Static);\n        private readonly List<Factory<IGrainContext, object>> _argumentFactories;\n\n        /// <summary>\n        /// Initializes a new <see cref=\"GrainConstructorArgumentFactory\"/> instance.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"grainType\">The grain type.</param>\n        public GrainConstructorArgumentFactory(IServiceProvider serviceProvider, Type grainType)\n        {\n            _argumentFactories = new List<Factory<IGrainContext, object>>();\n\n            // Find the constructor - supports only single public constructor.\n            var parameters = grainType.GetConstructors().FirstOrDefault()?.GetParameters() ?? Enumerable.Empty<ParameterInfo>();\n            var types = new List<Type>();\n            foreach (var parameter in parameters)\n            {\n                // Look for attribute with a facet marker interface - supports only single facet attribute\n                var attribute = parameter.GetCustomAttributes()\n                                         .FirstOrDefault(static attribute => FacetMarkerInterfaceType.IsInstanceOfType(attribute));\n\n                if (attribute is null) continue;\n\n                // Since the IAttributeToFactoryMapper is specific to the attribute specialization, we create a generic method to provide a attribute independent call pattern.\n                var getFactory = GetFactoryMethod.MakeGenericMethod(attribute.GetType());\n                var argumentFactory = (Factory<IGrainContext, object>)getFactory.Invoke(this, [serviceProvider, parameter, attribute, grainType]);\n\n                // Record the argument factory\n                _argumentFactories.Add(argumentFactory);\n\n                // Record the argument type\n                types.Add(parameter.ParameterType);\n            }\n\n            ArgumentTypes = types.ToArray();\n        }\n\n        /// <summary>\n        /// Gets the constructor argument types.\n        /// </summary>\n        public Type[] ArgumentTypes { get; }\n\n        /// <summary>\n        /// Creates the arguments for the grain constructor.\n        /// </summary>\n        /// <param name=\"grainContext\">The grain context.</param>\n        /// <returns>The constructor arguments.</returns>\n        public object[] CreateArguments(IGrainContext grainContext)\n        {\n            var i = 0;\n            var results = new object[_argumentFactories.Count];\n            foreach (var argumentFactory in _argumentFactories)\n            {\n                results[i++] = argumentFactory(grainContext);\n            }\n\n            return results;\n        }\n\n        private static Factory<IGrainContext, object> GetArgumentFactory<TMetadata>(IServiceProvider services, ParameterInfo parameter, IFacetMetadata metadata, Type type)\n            where TMetadata : IFacetMetadata\n        {\n            var factoryMapper = services.GetService<IAttributeToFactoryMapper<TMetadata>>();\n            if (factoryMapper is null)\n            {\n                throw new OrleansException($\"Missing attribute mapper for attribute {metadata.GetType()} used in grain constructor for grain type {type}.\");\n            }\n\n            var factory = factoryMapper.GetFactory(parameter, (TMetadata)metadata);\n            if (factory is null)\n            {\n                throw new OrleansException($\"Attribute mapper {factoryMapper.GetType()} failed to create a factory for grain type {type}.\");\n            }\n\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/IAttributeToFactoryMapper.cs",
    "content": "using System.Reflection;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Responsible for mapping a facet metadata to a cachable factory.\n    /// </summary>\n    public interface IAttributeToFactoryMapper<in TMetadata>\n        where TMetadata : IFacetMetadata\n    {\n        /// <summary>\n        /// Responsible for mapping a facet metadata to a cachable factory from the parameter and facet metadata.\n        /// </summary>\n        /// <param name=\"parameter\">The parameter info.</param>\n        /// <param name=\"metadata\">The metadata.</param>\n        /// <returns>The factory used to create facet instances for a grain.</returns>\n        Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, TMetadata metadata);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/IFacetMetadata.cs",
    "content": "﻿\nnamespace Orleans\n{\n    /// <summary>\n    /// Marker interface for facets\n    /// </summary>\n    public interface IFacetMetadata\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/IPersistentState.cs",
    "content": "using Orleans.Core;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Provides access to grain state with functionality to save, clear, and refresh the state.\n    /// </summary>\n    /// <typeparam name=\"TState\">The underlying state type.</typeparam>\n    /// <seealso cref=\"Orleans.Core.IStorage{TState}\" />\n    public interface IPersistentState<TState> : IStorage<TState>\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/IPersistentStateConfiguration.cs",
    "content": "\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Configuration for persistent state.\n    /// </summary>\n    /// <seealso cref=\"IPersistentState{TState}\"/>\n    public interface IPersistentStateConfiguration\n    {\n        /// <summary>\n        /// Gets the name of the state.\n        /// </summary>\n        /// <value>The name of the state.</value>\n        string StateName { get; }\n\n        /// <summary>\n        /// Gets the name of the storage provider.\n        /// </summary>\n        /// <value>The name of the storage provider.</value>\n        string StorageName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/IPersistentStateFactory.cs",
    "content": "\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Factory for constructing <see cref=\"IPersistentState{TState}\"/> instances for a grain.\n    /// </summary>\n    public interface IPersistentStateFactory\n    {\n        /// <summary>\n        /// Creates a persistent state instance for the provided grain.\n        /// </summary>\n        /// <typeparam name=\"TState\">The underlying state type.</typeparam>\n        /// <param name=\"context\">The grain context.</param>\n        /// <param name=\"config\">The state facet configuration.</param>\n        /// <returns>A persistent state instance for the provided grain with the specified configuration.</returns>\n        IPersistentState<TState> Create<TState>(IGrainContext context, IPersistentStateConfiguration config);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/PersistentStateAttribute.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Specifies options for the <see cref=\"IPersistentState{TState}\"/> constructor argument which it is applied to.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    /// <seealso cref=\"Orleans.IFacetMetadata\" />\n    /// <seealso cref=\"Orleans.Runtime.IPersistentStateConfiguration\" />\n    [AttributeUsage(AttributeTargets.Parameter)]\n    public class PersistentStateAttribute : Attribute, IFacetMetadata, IPersistentStateConfiguration\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PersistentStateAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"stateName\">Name of the state.</param>\n        /// <param name=\"storageName\">Name of the storage provider.</param>\n        public PersistentStateAttribute(string stateName, string storageName = null)\n        {\n            ArgumentNullException.ThrowIfNull(stateName);\n            this.StateName = stateName;\n            this.StorageName = storageName;\n        }\n\n        /// <summary>\n        /// Gets the name of the state.\n        /// </summary>\n        /// <value>The name of the state.</value>\n        public string StateName { get; }\n\n        /// <summary>\n        /// Gets the name of the storage provider.\n        /// </summary>\n        /// <value>The name of the storage provider.</value>\n        public string StorageName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/PersistentStateAttributeMapper.cs",
    "content": "using System;\nusing System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Attribute mapper which maps persistent state attributes to a corresponding factory instance.\n    /// </summary>\n    public class PersistentStateAttributeMapper : IAttributeToFactoryMapper<PersistentStateAttribute>\n    {\n        private static readonly MethodInfo CreateMethodInfo = typeof(IPersistentStateFactory).GetMethod(\"Create\");\n\n        /// <inheritdoc/>\n        public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, PersistentStateAttribute attribute)\n        {\n            IPersistentStateConfiguration config = attribute;\n            // set state name to parameter name, if not already specified\n            if (string.IsNullOrEmpty(config.StateName))\n            {\n                config = new PersistentStateConfiguration() { StateName = parameter.Name, StorageName = attribute.StorageName };\n            }\n\n            if (!parameter.ParameterType.IsGenericType || !typeof(IPersistentState<>).Equals(parameter.ParameterType.GetGenericTypeDefinition()))\n            {\n                throw new ArgumentException(\n                    $\"Parameter '{parameter.Name}' on the constructor for '{parameter.Member.DeclaringType}' has an unsupported type, '{parameter.ParameterType}'. \"\n                    + $\"It must be an instance of generic type '{typeof(IPersistentState<>)}' because it has an associated [PersistentState(...)] attribute.\",\n                    parameter.Name);\n            }\n\n            // use generic type args to define collection type.\n            MethodInfo genericCreate = CreateMethodInfo.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());\n            return context => Create(context, genericCreate, config);\n        }\n\n        private static object Create(IGrainContext context, MethodInfo genericCreate, IPersistentStateConfiguration config)\n        {\n            IPersistentStateFactory factory = context.ActivationServices.GetRequiredService<IPersistentStateFactory>();\n            object[] args = [context, config];\n            return genericCreate.Invoke(factory, args);\n        }\n\n        private class PersistentStateConfiguration : IPersistentStateConfiguration\n        {\n            public string StateName { get; set; }\n\n            public string StorageName { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Facet/Persistent/PersistentStateStorageFactory.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Core;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Storage;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Creates <see cref=\"IPersistentState{TState}\"/> instances for grains.\n    /// </summary>\n    /// <seealso cref=\"Orleans.Runtime.IPersistentStateFactory\" />\n    public class PersistentStateFactory : IPersistentStateFactory\n    {\n        /// <inheritdoc/>\n        public IPersistentState<TState> Create<TState>(IGrainContext context, IPersistentStateConfiguration cfg)\n        {\n            var storageProvider = !string.IsNullOrWhiteSpace(cfg.StorageName)\n                ? context.ActivationServices.GetKeyedService<IGrainStorage>(cfg.StorageName)\n                : context.ActivationServices.GetService<IGrainStorage>();\n            if (storageProvider == null)\n            {\n                ThrowMissingProviderException(context, cfg);\n            }\n\n            var fullStateName = GetFullStateName(context, cfg);\n            return new PersistentState<TState>(fullStateName, context, storageProvider);\n        }\n\n        protected virtual string GetFullStateName(IGrainContext context, IPersistentStateConfiguration cfg)\n        {\n            return cfg.StateName;\n        }\n\n        [DoesNotReturn]\n        private static void ThrowMissingProviderException(IGrainContext context, IPersistentStateConfiguration cfg)\n        {\n            string errMsg;\n            if (string.IsNullOrEmpty(cfg.StorageName))\n            {\n                errMsg = $\"No default storage provider found loading grain type {context.GrainId.Type}.\";\n            }\n            else\n            {\n                errMsg = $\"No storage provider named \\\"{cfg.StorageName}\\\" found loading grain type {context.GrainId.Type}.\";\n            }\n\n            throw new BadProviderConfigException(errMsg);\n        }\n    }\n\n    internal sealed class PersistentState<TState> : StateStorageBridge<TState>, IPersistentState<TState>, ILifecycleObserver\n    {\n        public PersistentState(string stateName, IGrainContext context, IGrainStorage storageProvider) : base(stateName, context, storageProvider)\n        {\n            var lifecycle = context.ObservableLifecycle;\n            lifecycle.Subscribe(RuntimeTypeNameFormatter.Format(GetType()), GrainLifecycleStage.SetupState, this);\n            lifecycle.AddMigrationParticipant(this);\n        }\n\n        public Task OnStart(CancellationToken cancellationToken = default) \n        {\n            if (cancellationToken.IsCancellationRequested)\n            {\n                return Task.CompletedTask;\n            }\n\n            // No need to load state if it has been loaded already via rehydration.\n            if (IsStateInitialized)\n            {\n                return Task.CompletedTask;\n            }\n\n            return ReadStateAsync();\n        }\n\n        public Task OnStop(CancellationToken cancellationToken = default) => Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/CachedGrainLocator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Implementation of <see cref=\"IGrainLocator\"/> that uses <see cref=\"IGrainDirectory\"/> stores.\n    /// </summary>\n    internal class CachedGrainLocator : IGrainLocator, ILifecycleParticipant<ISiloLifecycle>, CachedGrainLocator.ITestAccessor\n    {\n        private readonly GrainDirectoryResolver grainDirectoryResolver;\n        private readonly IGrainDirectoryCache cache;\n\n        private readonly CancellationTokenSource shutdownToken = new CancellationTokenSource();\n        private readonly IClusterMembershipService clusterMembershipService;\n\n        private Task listenToClusterChangeTask;\n\n        internal interface ITestAccessor\n        {\n            MembershipVersion LastMembershipVersion { get; set; }\n        }\n\n        MembershipVersion ITestAccessor.LastMembershipVersion { get; set; }\n\n        public CachedGrainLocator(\n            IServiceProvider serviceProvider,\n            GrainDirectoryResolver grainDirectoryResolver,\n            IClusterMembershipService clusterMembershipService,\n            IOptions<GrainDirectoryOptions> grainDirectoryOptions)\n        {\n            this.grainDirectoryResolver = grainDirectoryResolver;\n            this.clusterMembershipService = clusterMembershipService;\n            this.cache = GrainDirectoryCacheFactory.CreateCustomGrainDirectoryCache(serviceProvider, grainDirectoryOptions.Value);\n        }\n\n        public async ValueTask<GrainAddress> Lookup(GrainId grainId)\n        {\n            var grainType = grainId.Type;\n            if (grainType.IsClient() || grainType.IsSystemTarget())\n            {\n                ThrowUnsupportedGrainType(grainId);\n            }\n\n            // Check cache first\n            if (TryLookupInCache(grainId, out var cachedResult))\n            {\n                return cachedResult;\n            }\n\n            var entry = await GetGrainDirectory(grainId.Type).Lookup(grainId);\n\n            // Nothing found\n            if (entry is null)\n            {\n                return null;\n            }\n\n            // Check if the entry is pointing to a dead silo\n            if (IsKnownDeadSilo(entry))\n            {\n                // Remove it from the directory\n                await GetGrainDirectory(grainId.Type).Unregister(entry);\n                entry = null;\n            }\n            else\n            {\n                // Add to the local cache and return it\n                this.cache.AddOrUpdate(entry, 0);\n            }\n\n            return entry;\n        }\n\n        public async Task<GrainAddress> Register(GrainAddress address, GrainAddress previousAddress)\n        {\n            var grainType = address.GrainId.Type;\n            if (grainType.IsClient() || grainType.IsSystemTarget())\n            {\n                ThrowUnsupportedGrainType(address.GrainId);\n            }\n\n            address = new()\n            {\n                GrainId = address.GrainId,\n                ActivationId = address.ActivationId,\n                SiloAddress = address.SiloAddress,\n                MembershipVersion = clusterMembershipService.CurrentSnapshot.Version\n            };\n\n            var result = await GetGrainDirectory(grainType).Register(address, previousAddress);\n\n            if (result is null)\n            {\n                // If the registration failed, we return a null address\n                return null;\n            }\n\n            // Check if the entry point to a dead silo\n            if (IsKnownDeadSilo(result))\n            {\n                // Remove outdated entry and retry to register\n                await GetGrainDirectory(grainType).Unregister(result);\n                result = await GetGrainDirectory(grainType).Register(address, previousAddress);\n            }\n\n            // Cache update\n            this.cache.AddOrUpdate(result, (int)result.MembershipVersion.Value);\n\n            return result;\n\n        }\n\n        public async Task Unregister(GrainAddress address, UnregistrationCause cause)\n        {\n            // Remove from local cache first so we don't return it anymore\n            this.cache.Remove(address);\n\n            // Remove from grain directory which may take significantly longer\n            await GetGrainDirectory(address.GrainId.Type).Unregister(address);\n\n            // There is the potential for a lookup to race with the Unregister and add the bad entry back to the cache.\n            if (this.cache.LookUp(address.GrainId, out var entry, out _) && entry.Equals(address))\n            {\n                this.cache.Remove(address);\n            }\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            Task OnStart(CancellationToken ct)\n            {\n                this.listenToClusterChangeTask = ListenToClusterChange();\n                return Task.CompletedTask;\n            };\n            async Task OnStop(CancellationToken ct)\n            {\n                this.shutdownToken.Cancel();\n                if (listenToClusterChangeTask != default && !ct.IsCancellationRequested)\n                {\n                    await listenToClusterChangeTask.WaitAsync(ct).SuppressThrowing();\n                }\n            };\n            lifecycle.Subscribe(nameof(CachedGrainLocator), ServiceLifecycleStage.RuntimeGrainServices, OnStart, OnStop);\n        }\n\n        private IGrainDirectory GetGrainDirectory(GrainType grainType) => this.grainDirectoryResolver.Resolve(grainType);\n\n        private async Task ListenToClusterChange()\n        {\n            var previousSnapshot = this.clusterMembershipService.CurrentSnapshot;\n\n            ((ITestAccessor)this).LastMembershipVersion = previousSnapshot.Version;\n\n            var updates = this.clusterMembershipService.MembershipUpdates.WithCancellation(this.shutdownToken.Token);\n            await foreach (var snapshot in updates)\n            {\n                // Active filtering: detect silos that went down and try to clean proactively the directory\n                var changes = snapshot.CreateUpdate(previousSnapshot).Changes;\n                var deadSilos = changes\n                    .Where(member => member.Status.IsTerminating())\n                    .Select(member => member.SiloAddress)\n                    .ToList();\n\n                if (deadSilos.Count > 0)\n                {\n                    var tasks = new List<Task>();\n                    foreach (var directory in this.grainDirectoryResolver.Directories)\n                    {\n                        tasks.Add(directory.UnregisterSilos(deadSilos));\n                    }\n                    await Task.WhenAll(tasks).WaitAsync(this.shutdownToken.Token);\n                }\n\n                ((ITestAccessor)this).LastMembershipVersion = snapshot.Version;\n            }\n        }\n\n        private bool IsKnownDeadSilo(GrainAddress grainAddress)\n            => IsKnownDeadSilo(grainAddress.SiloAddress, grainAddress.MembershipVersion);\n\n        private bool IsKnownDeadSilo(SiloAddress siloAddress, MembershipVersion membershipVersion)\n        {\n            var current = this.clusterMembershipService.CurrentSnapshot;\n\n            // Check if the target silo is in the cluster\n            if (current.Members.TryGetValue(siloAddress, out var value))\n            {\n                // It is, check if it's alive\n                return value.Status.IsTerminating();\n            }\n\n            // We didn't find it in the cluster. If the silo entry is too old, it has been cleaned in the membership table: the entry isn't valid anymore.\n            // Otherwise, maybe the membership service isn't up to date yet. The entry should be valid\n            return current.Version > membershipVersion;\n        }\n\n        private static void ThrowUnsupportedGrainType(GrainId grainId) => throw new InvalidOperationException($\"Unsupported grain type for grain {grainId}\");\n\n        public void UpdateCache(GrainId grainId, SiloAddress siloAddress) => cache.AddOrUpdate(new GrainAddress { GrainId = grainId, SiloAddress = siloAddress }, 0);\n        public void InvalidateCache(GrainId grainId) => cache.Remove(grainId);\n        public void InvalidateCache(GrainAddress address) => cache.Remove(address);\n        public bool TryLookupInCache(GrainId grainId, out GrainAddress address)\n        {\n            var grainType = grainId.Type;\n            if (grainType.IsClient() || grainType.IsSystemTarget())\n            {\n                ThrowUnsupportedGrainType(grainId);\n            }\n\n            if (this.cache.LookUp(grainId, out address, out var version))\n            {\n                // If the silo is dead, remove the entry\n                if (IsKnownDeadSilo(address.SiloAddress, new MembershipVersion(version)))\n                {\n                    address = default;\n                    this.cache.Remove(grainId);\n                }\n                else\n                {\n                    // Entry found and valid -> return it\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/ClientDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime.GrainDirectory;\n\n/// <summary>\n/// A directory for routes to clients (external clients and hosted clients).\n/// </summary>\n/// <remarks>\n/// <see cref=\"ClientDirectory\"/> maintains routing information for all known clients and offers consumers the ability to lookup\n/// clients by their <see cref=\"GrainId\"/>.\n/// To accomplish this, <see cref=\"ClientDirectory\"/> monitors locally connected clients and cluster membership changes. In addition,\n/// known routes are periodically shared with remote silos in a ring-fashion. Each silo will push updates to the next silo in the ring.\n/// When a silo receives an update, it incorporates it into its routing table. If the update caused a change in the routing table, then\n/// the silo will propagate its updates routing table to the next silo. This process continues until all silos converge.\n/// Each <see cref=\"ClientDirectory\"/> maintains an internal version number which represents its view of the locally connected clients.\n/// This version number is propagated around the ring during updates and is used to determine when a remote silo's set of locally connected clients\n/// has updated.\n/// The process of removing defunct clients is left to the <see cref=\"IConnectedClientCollection\"/> implementation on each silo.\n/// </remarks>\ninternal sealed partial class ClientDirectory : SystemTarget, ILocalClientDirectory, IRemoteClientDirectory, ILifecycleParticipant<ISiloLifecycle>\n{\n    private readonly SimpleConsistentRingProvider _consistentRing;\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly ILogger<ClientDirectory> _logger;\n    private readonly IAsyncTimer _refreshTimer;\n    private readonly SiloAddress _localSilo;\n    private readonly IClusterMembershipService _clusterMembershipService;\n    private readonly SiloMessagingOptions _messagingOptions;\n    private readonly CancellationTokenSource _shutdownCts = new();\n#if NET9_0_OR_GREATER\n    private readonly Lock _lockObj = new();\n#else\n    private readonly object _lockObj = new();\n#endif\n    private readonly GrainId _localHostedClientId;\n    private readonly IConnectedClientCollection _connectedClients;\n    private Action _schedulePublishUpdate;\n    private Task? _runTask;\n    private MembershipVersion _observedMembershipVersion = MembershipVersion.MinValue;\n    private long _observedConnectedClientsVersion = -1;\n    private long _localVersion = 1;\n    private IRemoteClientDirectory[] _remoteDirectories = Array.Empty<IRemoteClientDirectory>();\n    private ImmutableHashSet<GrainId> _localClients = ImmutableHashSet<GrainId>.Empty;\n    private ImmutableDictionary<GrainId, List<GrainAddress>> _currentSnapshot = ImmutableDictionary<GrainId, List<GrainAddress>>.Empty;\n    private ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)> _table = ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>.Empty;\n\n    // For synchronization with remote silos.\n    private Task? _nextPublishTask;\n    private SiloAddress? _previousSuccessor;\n    private ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>? _publishedTable;\n\n    public ClientDirectory(\n        IInternalGrainFactory grainFactory,\n        ILocalSiloDetails siloDetails,\n        IOptions<SiloMessagingOptions> messagingOptions,\n        ILoggerFactory loggerFactory,\n        IClusterMembershipService clusterMembershipService,\n        IAsyncTimerFactory timerFactory,\n        IConnectedClientCollection connectedClients,\n        SystemTargetShared shared)\n        : base(Constants.ClientDirectoryType, shared)\n    {\n        _consistentRing = new SimpleConsistentRingProvider(siloDetails, clusterMembershipService);\n        _grainFactory = grainFactory;\n        _localSilo = siloDetails.SiloAddress;\n        _clusterMembershipService = clusterMembershipService;\n        _messagingOptions = messagingOptions.Value;\n        _logger = loggerFactory.CreateLogger<ClientDirectory>();\n        _refreshTimer = timerFactory.Create(_messagingOptions.ClientRegistrationRefresh, \"ClientDirectory.RefreshTimer\");\n        _connectedClients = connectedClients;\n        _localHostedClientId = HostedClient.CreateHostedClientGrainId(_localSilo).GrainId;\n        _schedulePublishUpdate = SchedulePublishUpdates;\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    public ValueTask<List<GrainAddress>> Lookup(GrainId grainId)\n    {\n        if (TryLocalLookup(grainId, out var clientRoutes))\n        {\n            return new ValueTask<List<GrainAddress>>(clientRoutes);\n        }\n\n        return LookupClientAsync(grainId);\n\n        async ValueTask<List<GrainAddress>> LookupClientAsync(GrainId grainId)\n        {\n            var seed = Random.Shared.Next();\n            var attemptsRemaining = 5;\n            List<GrainAddress>? result = null;\n            while (attemptsRemaining-- > 0 && _remoteDirectories is var remoteDirectories && remoteDirectories.Length > 0)\n            {\n                try\n                {\n                    // Cycle through remote directories.\n                    var remoteDirectory = remoteDirectories[(ushort)seed++ % remoteDirectories.Length];\n\n                    // Ask the remote directory for updates to our view.\n                    var versionVector = _table.ToImmutableDictionary(e => e.Key, e => e.Value.Version);\n                    var delta = await remoteDirectory.GetClientRoutes(versionVector);\n\n                    // If updates were found, update our view\n                    if (delta is not null && delta.Count > 0)\n                    {\n                        UpdateRoutingTable(delta);\n                    }\n                }\n                catch (Exception exception) when (attemptsRemaining > 0)\n                {\n                    LogErrorCallingRemoteClientDirectory(exception);\n                }\n\n                // Try again to find the requested client's routes.\n                // Note that this occurs whether the remote update call succeeded or failed.\n                if (TryLocalLookup(grainId, out result) && result.Count > 0)\n                {\n                    break;\n                }\n            }\n\n            if (ShouldPublish())\n            {\n                _schedulePublishUpdate();\n            }\n\n            // Try one last time to find the requested client's routes.\n            if (result is null && !TryLocalLookup(grainId, out result))\n            {\n                result = [];\n            }\n\n            return result;\n        }\n    }\n\n    public bool TryLocalLookup(GrainId grainId, [NotNullWhen(true)] out List<GrainAddress>? addresses)\n    {\n        EnsureRefreshed();\n        if (_currentSnapshot.TryGetValue(grainId, out var clientRoutes) && clientRoutes.Count > 0)\n        {\n            addresses = clientRoutes;\n            return true;\n        }\n\n        addresses = null;\n        return false;\n    }\n\n    private void EnsureRefreshed()\n    {\n        if (IsStale())\n        {\n            lock (_lockObj)\n            {\n                if (IsStale())\n                {\n                    UpdateRoutingTable(update: null);\n                }\n            }\n        }\n\n        bool IsStale()\n        {\n            return _observedMembershipVersion < _clusterMembershipService.CurrentSnapshot.Version\n                || _observedConnectedClientsVersion != _connectedClients.Version;\n        }\n    }\n\n    public Task OnUpdateClientRoutes(ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)> update)\n    {\n        UpdateRoutingTable(update);\n        if (ShouldPublish())\n        {\n            LogDebugClientTableUpdated();\n            _schedulePublishUpdate();\n        }\n        else\n        {\n            LogDebugClientTableNotUpdated();\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public Task<ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>> GetClientRoutes(ImmutableDictionary<SiloAddress, long> knownRoutes)\n    {\n        EnsureRefreshed();\n\n        // Return a collection containing all missing or out-dated routes, based on the known-routes version vector provided by the caller.\n        var table = _table;\n        var resultBuilder = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>();\n        foreach (var entry in table)\n        {\n            var silo = entry.Key;\n            var routes = entry.Value;\n            var version = routes.Version;\n            if (!knownRoutes.TryGetValue(silo, out var knownVersion) || knownVersion < version)\n            {\n                resultBuilder[silo] = routes;\n            }\n        }\n\n        return Task.FromResult(resultBuilder.ToImmutable());\n    }\n\n    private void UpdateRoutingTable(ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>? update)\n    {\n        lock (_lockObj)\n        {\n            var membershipSnapshot = _clusterMembershipService.CurrentSnapshot;\n            var table = default(ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>.Builder);\n\n            // Incorporate updates.\n            if (update is not null)\n            {\n                foreach (var pair in update)\n                {\n                    var silo = pair.Key;\n                    var updatedView = pair.Value;\n\n                    // Include only updates for non-defunct silos.\n                    if ((!_table.TryGetValue(silo, out var localView) || localView.Version < updatedView.Version)\n                        && !membershipSnapshot.GetSiloStatus(silo).IsTerminating())\n                    {\n                        table ??= _table.ToBuilder();\n                        table[silo] = updatedView;\n                    }\n                }\n            }\n\n            // Ensure that the remote directories are up-to-date.\n            if (membershipSnapshot.Version > _observedMembershipVersion)\n            {\n                var remotesBuilder = new List<IRemoteClientDirectory>(membershipSnapshot.Members.Count);\n                foreach (var member in membershipSnapshot.Members.Values)\n                {\n                    if (member.SiloAddress.Equals(_localSilo)) continue;\n                    if (member.Status != SiloStatus.Active) continue;\n\n                    remotesBuilder.Add(_grainFactory.GetSystemTarget<IRemoteClientDirectory>(Constants.ClientDirectoryType, member.SiloAddress));\n                }\n\n                _remoteDirectories = remotesBuilder.ToArray();\n            }\n\n            // Remove defunct silos.\n            foreach (var member in membershipSnapshot.Members.Values)\n            {\n                var silo = member.SiloAddress;\n                if (member.Status.IsTerminating())\n                {\n                    // Remove the silo only if it is in the table. This prevents us from rebuilding data structures unnecessarily.\n                    if (_table.ContainsKey(silo))\n                    {\n                        table ??= _table.ToBuilder();\n                        table.Remove(silo);\n                    }\n                }\n                else if (member.Status == SiloStatus.Active)\n                {\n                    // If the silo has just become active and we have not yet received a set of connected clients from it,\n                    // add the hosted client automatically, to expedite the process.\n                    if (!_table.ContainsKey(silo) && (table is null || !table.ContainsKey(silo)))\n                    {\n                        table ??= _table.ToBuilder();\n\n                        // Note that it is added with version 0, which is below the initial version generated by each silo, 1.\n                        table[silo] = (ImmutableHashSet.Create(HostedClient.CreateHostedClientGrainId(silo).GrainId), 0);\n                    }\n                }\n            }\n\n            _observedMembershipVersion = membershipSnapshot.Version;\n\n            // Update locally connected clients.\n            var (clients, version) = GetConnectedClients(_localClients, _localVersion);\n            if (version > _localVersion)\n            {\n                table ??= _table.ToBuilder();\n                table[_localSilo] = (clients, version);\n                _localClients = clients;\n                _localVersion = version;\n            }\n\n            // If there were changes to the routing table then the table and snapshot need to be rebuilt.\n            if (table is not null)\n            {\n                _table = table.ToImmutable();\n                var clientsBuilder = ImmutableDictionary.CreateBuilder<GrainId, List<GrainAddress>>();\n                foreach (var entry in _table)\n                {\n                    foreach (var client in entry.Value.ConnectedClients)\n                    {\n                        if (!clientsBuilder.TryGetValue(client, out var clientRoutes))\n                        {\n                            clientRoutes = clientsBuilder[client] = [];\n                        }\n\n                        clientRoutes.Add(Gateway.GetClientActivationAddress(client, entry.Key));\n                    }\n                }\n\n                _currentSnapshot = clientsBuilder.ToImmutable();\n            }\n        }\n    }\n\n    /// <summary>\n    /// Gets the collection of locally connected clients.\n    /// </summary>\n    private (ImmutableHashSet<GrainId> Clients, long Version) GetConnectedClients(ImmutableHashSet<GrainId> previousClients, long previousVersion)\n    {\n        var connectedClientsVersion = _connectedClients.Version;\n        if (connectedClientsVersion <= _observedConnectedClientsVersion)\n        {\n            return (previousClients, previousVersion);\n        }\n\n        var clients = ImmutableHashSet.CreateBuilder<GrainId>();\n        clients.Add(_localHostedClientId);\n        foreach (var client in _connectedClients.GetConnectedClientIds())\n        {\n            clients.Add(client);\n        }\n\n        // Regardless of whether changes occurred, mark this version as observed.\n        _observedConnectedClientsVersion = connectedClientsVersion;\n\n        // If no changes actually occurred, avoid signaling a change.\n        if (clients.Count == previousClients.Count && previousClients.SetEquals(clients))\n        {\n            return (previousClients, previousVersion);\n        }\n\n        return (clients.ToImmutable(), previousVersion + 1);\n    }\n\n    private async Task Run()\n    {\n        var membershipUpdates = _clusterMembershipService.MembershipUpdates.GetAsyncEnumerator(_shutdownCts.Token);\n\n        Task<bool>? membershipTask = null;\n        Task<bool>? timerTask = _refreshTimer.NextTick(RandomTimeSpan.Next(_messagingOptions.ClientRegistrationRefresh));\n\n        while (!_shutdownCts.IsCancellationRequested)\n        {\n            try\n            {\n                membershipTask ??= membershipUpdates.MoveNextAsync().AsTask();\n                timerTask ??= _refreshTimer.NextTick();\n\n                // Wait for either of the tasks to complete.\n                await Task.WhenAny(membershipTask, timerTask);\n\n                if (timerTask.IsCompleted)\n                {\n                    if (!await timerTask)\n                    {\n                        break;\n                    }\n\n                    timerTask = null;\n                }\n\n                if (membershipTask.IsCompleted)\n                {\n                    if (!await membershipTask)\n                    {\n                        break;\n                    }\n\n                    membershipTask = null;\n                }\n\n                if (ShouldPublish())\n                {\n                    await PublishUpdates();\n                }\n            }\n            catch (OperationCanceledException) when (_shutdownCts.IsCancellationRequested)\n            {\n                // Ignore during shutdown.\n                break;\n            }\n            catch (Exception exception)\n            {\n                LogErrorPublishingClientRoutingTable(exception);\n            }\n        }\n    }\n\n    private bool ShouldPublish()\n    {\n        EnsureRefreshed();\n        lock (_lockObj)\n        {\n            if (_nextPublishTask is Task task && !task.IsCompleted)\n            {\n                return false;\n            }\n\n            if (!ReferenceEquals(_table, _publishedTable))\n            {\n                return true;\n            }\n\n            // If there is no successor, or the successor is equal to the successor the last time the table was published,\n            // then there is no need to publish.\n            var successor = _consistentRing.Successor;\n            if (successor is null || successor.Equals(_previousSuccessor))\n            {\n                return false;\n            }\n\n            return true;\n        }\n    }\n\n    private void SchedulePublishUpdates()\n    {\n        lock (_lockObj)\n        {\n            if (_nextPublishTask is Task task && !task.IsCompleted)\n            {\n                return;\n            }\n\n            _nextPublishTask = this.RunOrQueueTask(PublishUpdates);\n        }\n    }\n\n    private async Task PublishUpdates()\n    {\n        // Publish clients to the next two silos in the ring\n        var successor = _consistentRing.Successor;\n        if (successor is null)\n        {\n            return;\n        }\n\n        if (successor.Equals(_previousSuccessor))\n        {\n            _publishedTable = null;\n        }\n\n        var newRoutes = _table;\n        var previousRoutes = _publishedTable;\n\n        if (ReferenceEquals(previousRoutes, newRoutes))\n        {\n            LogDebugSkippingPublishingRoutes();\n            return;\n        }\n\n        // Try to find the minimum amount of information required to update the successor.\n        var builder = newRoutes.ToBuilder();\n        if (previousRoutes is not null)\n        {\n            foreach (var pair in previousRoutes)\n            {\n                var silo = pair.Key;\n                var (_, version) = pair.Value;\n                if (silo.Equals(successor))\n                {\n                    // No need to publish updates to the silo which originated them.\n                    continue;\n                }\n\n                if (!builder.TryGetValue(silo, out var published))\n                {\n                    continue;\n                }\n\n                if (version == published.Version)\n                {\n                    // The target has already seen the latest version for this silo.\n                    builder.Remove(silo);\n                }\n            }\n        }\n\n        try\n        {\n            LogDebugPublishingRoutes(successor);\n\n            var remote = _grainFactory.GetSystemTarget<IRemoteClientDirectory>(Constants.ClientDirectoryType, successor);\n            await remote.OnUpdateClientRoutes(_table).WaitAsync(_shutdownCts.Token);\n\n            // Record the current lower bound of what the successor knows, so that it can be used to minimize\n            // data transfer next time an update is performed.\n            if (ReferenceEquals(_publishedTable, previousRoutes))\n            {\n                _publishedTable = newRoutes;\n                _previousSuccessor = successor;\n            }\n\n            LogDebugSuccessfullyPublishedRoutes(successor);\n\n            _nextPublishTask = null;\n            if (ShouldPublish())\n            {\n                _schedulePublishUpdate();\n            }\n        }\n        catch (Exception exception)\n        {\n            LogErrorPublishingClientRoutingTableToSilo(exception, successor);\n        }\n    }\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        lifecycle.Subscribe(\n            nameof(ClientDirectory),\n            ServiceLifecycleStage.RuntimeGrainServices,\n            ct =>\n            {\n                this.RunOrQueueTask(() => _runTask = this.Run()).Ignore();\n                return Task.CompletedTask;\n            },\n            async ct =>\n            {\n                _shutdownCts.Cancel();\n                _refreshTimer?.Dispose();\n\n                if (_runTask is Task task)\n                {\n                    await task.WaitAsync(ct).SuppressThrowing();\n                }\n\n                if (_nextPublishTask is Task publishTask)\n                {\n                    await publishTask.WaitAsync(ct).SuppressThrowing();\n                }\n            });\n    }\n\n    internal class TestAccessor(ClientDirectory instance)\n    {\n        public Action SchedulePublishUpdate { get => instance._schedulePublishUpdate; set => instance._schedulePublishUpdate = value; }\n        public long ObservedConnectedClientsVersion { get => instance._observedConnectedClientsVersion; set => instance._observedConnectedClientsVersion = value; }\n        public Task PublishUpdates() => instance.PublishUpdates();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Exception calling remote client directory\"\n    )]\n    private partial void LogErrorCallingRemoteClientDirectory(Exception exception);\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Error,\n        Message = \"Exception publishing client routing table\")]\n    private partial void LogErrorPublishingClientRoutingTable(Exception exception);\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Debug,\n        Message = \"Skipping publishing of routes because target silo already has them\")]\n    private partial void LogDebugSkippingPublishingRoutes();\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Debug,\n        Message = \"Publishing routes to {Silo}\")]\n    private partial void LogDebugPublishingRoutes(SiloAddress silo);\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Debug,\n        Message = \"Successfully published routes to {Silo}\")]\n    private partial void LogDebugSuccessfullyPublishedRoutes(SiloAddress silo);\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Error,\n        Message = \"Exception publishing client routing table to silo {SiloAddress}\")]\n    private partial void LogErrorPublishingClientRoutingTableToSilo(Exception exception, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Debug,\n        Message = \"Client table updated, publishing to successor\"\n    )]\n    private partial void LogDebugClientTableUpdated();\n\n    [LoggerMessage(\n        EventId = 0,\n        Level = LogLevel.Debug,\n        Message = \"Client table not updated\"\n    )]\n    private partial void LogDebugClientTableNotUpdated();\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/ClientGrainLocator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Implementation of <see cref=\"IGrainLocator\"/> that uses the in memory distributed directory of Orleans\n    /// </summary>\n    internal class ClientGrainLocator : IGrainLocator\n    {\n        private readonly SiloAddress _localSiloAddress;\n        private readonly ILocalClientDirectory _clientDirectory;\n\n        public ClientGrainLocator(ILocalSiloDetails localSiloDetails, ILocalClientDirectory clientDirectory)\n        {\n            _localSiloAddress = localSiloDetails.SiloAddress;\n            _clientDirectory = clientDirectory;\n        }\n\n        public async ValueTask<GrainAddress> Lookup(GrainId grainId)\n        {\n            if (!ClientGrainId.TryParse(grainId, out var clientGrainId))\n            {\n                ThrowNotClientGrainId(grainId);\n            }\n\n            var results = await _clientDirectory.Lookup(clientGrainId.GrainId);\n            return SelectAddress(results, grainId);\n        }\n\n        private GrainAddress SelectAddress(List<GrainAddress> results, GrainId grainId)\n        {\n            GrainAddress unadjustedResult = null;\n            if (results is { Count: > 0 })\n            {\n                foreach (var location in results)\n                {\n                    if (location.SiloAddress.Equals(_localSiloAddress))\n                    {\n                        unadjustedResult = location;\n                        break;\n                    }\n                }\n\n                if (unadjustedResult == null)\n                {\n                    unadjustedResult = results[Random.Shared.Next(results.Count)];\n                }\n            }\n\n            if (unadjustedResult is not null)\n            {\n                return GrainAddress.GetAddress(unadjustedResult.SiloAddress, grainId, unadjustedResult.ActivationId);\n            }\n\n            return null;\n        }\n\n        public Task<GrainAddress> Register(GrainAddress address, GrainAddress previousAddress) => throw new InvalidOperationException($\"Cannot register client grain explicitly\");\n\n        public Task Unregister(GrainAddress address, UnregistrationCause cause) => throw new InvalidOperationException($\"Cannot unregister client grain explicitly\");\n\n        private static void ThrowNotClientGrainId(GrainId grainId) => throw new InvalidOperationException($\"{grainId} is not a client id\");\n\n        public void UpdateCache(GrainId grainId, SiloAddress siloAddress) { }\n\n        public void InvalidateCache(GrainId grainId) { }\n\n        public void InvalidateCache(GrainAddress address) { }\n\n        public bool TryLookupInCache(GrainId grainId, out GrainAddress address)\n        {\n            if (!ClientGrainId.TryParse(grainId, out var clientGrainId))\n            {\n                ThrowNotClientGrainId(grainId);\n            }\n\n            if (_clientDirectory.TryLocalLookup(clientGrainId.GrainId, out var addresses))\n            {\n                address = SelectAddress(addresses, grainId);\n                return address is not null;\n            }\n\n            address = null;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/DhtGrainLocator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Implementation of <see cref=\"IGrainLocator\"/> that uses the in memory distributed directory of Orleans\n    /// </summary>\n    internal class DhtGrainLocator : IGrainLocator\n    {\n        private readonly ILocalGrainDirectory _localGrainDirectory;\n        private readonly IGrainContext _grainContext;\n#if NET9_0_OR_GREATER\n        private readonly Lock _initLock = new();\n#else\n        private readonly object _initLock = new();\n#endif\n        private BatchedDeregistrationWorker _forceWorker;\n        private BatchedDeregistrationWorker _neaWorker;\n\n        public DhtGrainLocator(\n            ILocalGrainDirectory localGrainDirectory,\n            IGrainContext grainContext)\n        {\n            _localGrainDirectory = localGrainDirectory;\n            _grainContext = grainContext;\n        }\n\n        public async ValueTask<GrainAddress> Lookup(GrainId grainId) => (await _localGrainDirectory.LookupAsync(grainId)).Address;\n\n        public async Task<GrainAddress> Register(GrainAddress address, GrainAddress previousAddress) => (await _localGrainDirectory.RegisterAsync(address, currentRegistration: previousAddress)).Address;\n\n        public Task Unregister(GrainAddress address, UnregistrationCause cause)\n        {\n            EnsureInitialized();\n\n            // If this ever gets more complicated, we can use a list or internally manage things within a single worker.\n            var worker = cause switch\n            {\n                UnregistrationCause.Force => _forceWorker,\n                UnregistrationCause.NonexistentActivation => _neaWorker,\n                _ => throw new ArgumentOutOfRangeException($\"Deregistration cause {cause} is unknown and is not supported. This is a bug.\"),\n            };\n\n            return worker.Unregister(address);\n            \n            void EnsureInitialized()\n            {\n                // Unfortunately, for now we need to perform this initialization lazily, since a SystemTarget does not become valid\n                // until it's registered with the Catalog (see Catalog.RegisterSystemTarget), which can happen after this instance\n                // is constructed.\n                if (_forceWorker is not null && _neaWorker is not null)\n                {\n                    return;\n                }\n\n                lock (_initLock)\n                {\n                    if (_forceWorker is not null && _neaWorker is not null)\n                    {\n                        return;\n                    }\n\n                    _forceWorker = new BatchedDeregistrationWorker(_localGrainDirectory, _grainContext, UnregistrationCause.Force);\n                    _neaWorker = new BatchedDeregistrationWorker(_localGrainDirectory, _grainContext, UnregistrationCause.NonexistentActivation);\n                }\n            }\n        }\n\n        public static DhtGrainLocator FromLocalGrainDirectory(LocalGrainDirectory localGrainDirectory)\n            => new(localGrainDirectory, localGrainDirectory.RemoteGrainDirectory);\n\n        public void UpdateCache(GrainId grainId, SiloAddress siloAddress) => _localGrainDirectory.AddOrUpdateCacheEntry(grainId, siloAddress);\n        public void InvalidateCache(GrainId grainId) => _localGrainDirectory.InvalidateCacheEntry(grainId);\n        public void InvalidateCache(GrainAddress address) => _localGrainDirectory.InvalidateCacheEntry(address);\n        public bool TryLookupInCache(GrainId grainId, out GrainAddress address) => _localGrainDirectory.TryCachedLookup(grainId, out address);\n\n        private class BatchedDeregistrationWorker\n        {\n            private const int OperationBatchSizeLimit = 2_000;\n            private readonly ILocalGrainDirectory _localGrainDirectory;\n            private readonly IGrainContext _grainContext;\n            private readonly UnregistrationCause _cause;\n            private readonly Channel<(TaskCompletionSource<bool> tcs, GrainAddress address)> _queue;\n#pragma warning disable IDE0052 // Remove unread private members\n            private readonly Task _runTask;\n#pragma warning restore IDE0052 // Remove unread private members\n\n            public BatchedDeregistrationWorker(\n                ILocalGrainDirectory localGrainDirectory,\n                IGrainContext grainContext,\n                UnregistrationCause cause)\n            {\n                _localGrainDirectory = localGrainDirectory;\n                _grainContext = grainContext;\n                _cause = cause;\n                _queue = Channel.CreateUnbounded<(TaskCompletionSource<bool> tcs, GrainAddress address)>(new UnboundedChannelOptions\n                {\n                    SingleReader = true,\n                    SingleWriter = false,\n                    AllowSynchronousContinuations = false\n                });\n                _runTask = _grainContext.RunOrQueueTask(() => ProcessDeregistrationQueue());\n            }\n\n            public Task Unregister(GrainAddress address)\n            {\n                var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n                _queue.Writer.TryWrite((tcs, address));\n                return tcs.Task;\n            }\n\n            private async Task ProcessDeregistrationQueue()\n            {\n                var operations = new List<TaskCompletionSource<bool>>();\n                var addresses = new List<GrainAddress>();\n                var reader = _queue.Reader;\n\n                while (await reader.WaitToReadAsync())\n                {\n                    // Process a batch of work.\n                    try\n                    {\n                        operations.Clear();\n                        addresses.Clear();\n\n                        while (operations.Count < OperationBatchSizeLimit && reader.TryRead(out var op))\n                        {\n                            operations.Add(op.tcs);\n                            addresses.Add(op.address);\n                        }\n\n                        if (operations.Count > 0)\n                        {\n                            await _localGrainDirectory.UnregisterManyAsync(addresses, _cause);\n                            foreach (var op in operations)\n                            {\n                                op.TrySetResult(true);\n                            }\n                        }\n                    }\n                    catch (Exception ex)\n                    {\n                        foreach (var op in operations)\n                        {\n                            op.TrySetException(ex);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/DirectoryMembershipService.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Utilities;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\ninternal sealed partial class DirectoryMembershipService : IAsyncDisposable\n{\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly ILogger _logger;\n    private readonly CancellationTokenSource _shutdownCts = new();\n    private readonly Task _runTask;\n    private readonly AsyncEnumerable<DirectoryMembershipSnapshot> _viewUpdates;\n\n    public DirectoryMembershipSnapshot CurrentView { get; private set; } = DirectoryMembershipSnapshot.Default;\n\n    public IAsyncEnumerable<DirectoryMembershipSnapshot> ViewUpdates => _viewUpdates;\n\n    public ClusterMembershipService ClusterMembershipService { get; }\n\n    public async ValueTask<DirectoryMembershipSnapshot> RefreshViewAsync(MembershipVersion version, CancellationToken cancellationToken)\n    {\n        _ = ClusterMembershipService.Refresh(version, cancellationToken);\n        if (CurrentView.Version <= version)\n        {\n            await foreach (var view in _viewUpdates.WithCancellation(cancellationToken))\n            {\n                if (view.Version >= version)\n                {\n                    break;\n                }\n            }\n        }\n\n        return CurrentView;\n    }\n\n    public DirectoryMembershipService(ClusterMembershipService clusterMembershipService, IInternalGrainFactory grainFactory, ILogger<DirectoryMembershipService> logger)\n    {\n        _viewUpdates = new(\n            DirectoryMembershipSnapshot.Default,\n            (previous, proposed) => proposed.Version >= previous.Version,\n            update => CurrentView = update);\n        ClusterMembershipService = clusterMembershipService;\n        _grainFactory = grainFactory;\n        _logger = logger;\n        using var _ = new ExecutionContextSuppressor();\n        _runTask = Task.Run(ProcessMembershipUpdates);\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        try\n        {\n            while (!_shutdownCts.IsCancellationRequested)\n            {\n                try\n                {\n                    await foreach (var update in ClusterMembershipService.MembershipUpdates.WithCancellation(_shutdownCts.Token))\n                    {\n                        var view = new DirectoryMembershipSnapshot(update, _grainFactory);\n                        _viewUpdates.Publish(view);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    if (!_shutdownCts.IsCancellationRequested)\n                    {\n                        LogErrorProcessingMembershipUpdates(exception);\n                    }\n                }\n            }\n        }\n        finally\n        {\n            _viewUpdates.Dispose();\n        }\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        _shutdownCts.Cancel();\n        await _runTask.SuppressThrowing();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing membership updates.\"\n    )]\n    private partial void LogErrorProcessingMembershipUpdates(Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/DirectoryMembershipSnapshot.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Microsoft.CodeAnalysis;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Utilities;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\ninternal sealed class DirectoryMembershipSnapshot\n{\n    internal const int PartitionsPerSilo = ConsistentRingOptions.DEFAULT_NUM_VIRTUAL_RING_BUCKETS;\n    private readonly ImmutableArray<(uint Start, int MemberIndex, int PartitionIndex)> _ringBoundaries;\n    private readonly RingRangeCollection[] _rangesByMember;\n    private readonly ImmutableArray<ImmutableArray<IGrainDirectoryPartition>> _partitionsByMember;\n    private readonly ImmutableArray<ImmutableArray<RingRange>> _rangesByMemberPartition;\n\n    public DirectoryMembershipSnapshot(ClusterMembershipSnapshot snapshot, IInternalGrainFactory grainFactory) : this(snapshot, grainFactory, static (silo, count) => silo.GetUniformHashCodes(count))\n    {\n    }\n\n    internal DirectoryMembershipSnapshot(ClusterMembershipSnapshot snapshot, IInternalGrainFactory grainFactory, Func<SiloAddress, int, uint[]> getRingBoundaries)\n    {\n        var sortedActiveMembers = ImmutableArray.CreateBuilder<SiloAddress>(snapshot.Members.Count(static m => m.Value.Status == SiloStatus.Active));\n        foreach (var member in snapshot.Members)\n        {\n            // Only active members are part of directory membership.\n            if (member.Value.Status == SiloStatus.Active)\n            {\n                sortedActiveMembers.Add(member.Key);\n            }\n        }\n\n        sortedActiveMembers.Sort(static (left, right) => left.CompareTo(right));\n        var hashIndexPairs = ImmutableArray.CreateBuilder<(uint Hash, int MemberIndex, int PartitionIndex)>(PartitionsPerSilo * sortedActiveMembers.Count);\n        var memberPartitions = ImmutableArray.CreateBuilder<ImmutableArray<IGrainDirectoryPartition>>();\n        for (var memberIndex = 0; memberIndex < sortedActiveMembers.Count; memberIndex++)\n        {\n            var activeMember = sortedActiveMembers[memberIndex];\n            var hashCodes = getRingBoundaries(activeMember, PartitionsPerSilo).ToList();\n            hashCodes.Sort();\n            Debug.Assert(hashCodes.Count == PartitionsPerSilo);\n            var partitionReferences = ImmutableArray.CreateBuilder<IGrainDirectoryPartition>(PartitionsPerSilo);\n            for (var partitionIndex = 0; partitionIndex < hashCodes.Count; partitionIndex++)\n            {\n                var hashCode = hashCodes[partitionIndex];\n                hashIndexPairs.Add((hashCode, memberIndex, partitionIndex));\n                partitionReferences.Add(grainFactory?.GetSystemTarget<IGrainDirectoryPartition>(GrainDirectoryPartition.CreateGrainId(activeMember, partitionIndex).GrainId)!);\n            }\n\n            memberPartitions.Add(partitionReferences.ToImmutable());\n        }\n\n        _partitionsByMember = memberPartitions.ToImmutable();\n\n        hashIndexPairs.Sort(static (left, right) =>\n        {\n            var hashCompare = left.Hash.CompareTo(right.Hash);\n            if (hashCompare != 0)\n            {\n                return hashCompare;\n            }\n\n            var partitionCompare = left.PartitionIndex.CompareTo(right.PartitionIndex);\n            if (partitionCompare != 0)\n            {\n                return partitionCompare;\n            }\n\n            return left.MemberIndex.CompareTo(right.MemberIndex);\n        });\n\n        Dictionary<int, ImmutableArray<RingRange>.Builder> rangesByMemberPartitionBuilders = [];\n        for (var i = 0; i < hashIndexPairs.Count; i++)\n        {\n            var (_, memberIndex, _) = hashIndexPairs[i];\n            ref var builder = ref CollectionsMarshal.GetValueRefOrAddDefault(rangesByMemberPartitionBuilders, memberIndex, out _);\n            builder ??= ImmutableArray.CreateBuilder<RingRange>(PartitionsPerSilo);\n            var (entryStart, _, _) = hashIndexPairs[i];\n            var (nextStart, _, _) = hashIndexPairs[(i + 1) % hashIndexPairs.Count];\n            var range = (entryStart == nextStart) switch\n            {\n                true when hashIndexPairs.Count == 1 => RingRange.Full,\n                true => RingRange.Empty,\n                _ => RingRange.Create(entryStart, nextStart)\n            };\n            builder.Add(range);\n        }\n\n        var rangesByMemberPartition = ImmutableArray.CreateBuilder<ImmutableArray<RingRange>>(sortedActiveMembers.Count);\n        for (var i = 0; i < sortedActiveMembers.Count; i++)\n        {\n            rangesByMemberPartition.Add(rangesByMemberPartitionBuilders[i].ToImmutable());\n        }\n\n        _rangesByMemberPartition = rangesByMemberPartition.ToImmutable();\n\n        // Remove empty ranges.\n        if (hashIndexPairs.Count > 1)\n        {\n            for (var i = 1; i < hashIndexPairs.Count;)\n            {\n                if (hashIndexPairs[i].Hash == hashIndexPairs[i - 1].Hash)\n                {\n                    hashIndexPairs.RemoveAt(i);\n                }\n                else\n                {\n                    i++;\n                }\n            }\n        }\n\n        _ringBoundaries = hashIndexPairs.ToImmutable();\n\n        Members = sortedActiveMembers.ToImmutable();\n\n        _rangesByMember = new RingRangeCollection[Members.Length];\n        ClusterMembershipSnapshot = snapshot;\n    }\n\n    public static DirectoryMembershipSnapshot Default { get; } = new DirectoryMembershipSnapshot(\n        new ClusterMembershipSnapshot(ImmutableDictionary<SiloAddress, ClusterMember>.Empty, MembershipVersion.MinValue), null!);\n\n    public MembershipVersion Version => ClusterMembershipSnapshot.Version;\n\n    public ImmutableArray<SiloAddress> Members { get; }\n\n    public RingRange GetRange(SiloAddress address, int partitionIndex)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThan(partitionIndex, 0);\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(partitionIndex, PartitionsPerSilo - 1);\n\n        var memberIndex = TryGetMemberIndex(address);\n        if (memberIndex < 0)\n        {\n            return RingRange.Empty;\n        }\n\n        var ranges = GetMemberRangesByPartition(memberIndex);\n        if (partitionIndex >= ranges.Length)\n        {\n            return RingRange.Empty;\n        }\n\n        return ranges[partitionIndex];\n    }\n\n    public RingRangeCollection GetMemberRanges(SiloAddress address)\n    {\n        var memberIndex = TryGetMemberIndex(address);\n\n        if (memberIndex < 0)\n        {\n            return RingRangeCollection.Empty;\n        }\n\n        var range = _rangesByMember[memberIndex];\n        if (range.IsDefault)\n        {\n            range = _rangesByMember[memberIndex] = RingRangeCollection.Create(GetMemberRangesByPartition(memberIndex));\n        }\n\n        return range;\n    }\n\n    public ImmutableArray<RingRange> GetMemberRangesByPartition(SiloAddress address)\n    {\n        var memberIndex = TryGetMemberIndex(address);\n\n        if (memberIndex < 0)\n        {\n            return [];\n        }\n\n        return GetMemberRangesByPartition(memberIndex);\n    }\n\n    private ImmutableArray<RingRange> GetMemberRangesByPartition(int memberIndex)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThan(memberIndex, 0);\n        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(memberIndex, _rangesByMemberPartition.Length);\n        return _rangesByMemberPartition[memberIndex];\n    }\n\n    public RangeCollection RangeOwners => new(this);\n\n    public ClusterMembershipSnapshot ClusterMembershipSnapshot { get; }\n\n    private (RingRange Range, int MemberIndex, int PartitionIndex) GetRangeInfo(int index)\n    {\n        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _ringBoundaries.Length);\n        ArgumentOutOfRangeException.ThrowIfLessThan(index, 0);\n\n        var range = GetRangeCore(index);\n        var boundary = _ringBoundaries[index];\n        return (range, boundary.MemberIndex, boundary.PartitionIndex);\n    }\n\n    private RingRange GetRangeCore(int index)\n    {\n        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _ringBoundaries.Length);\n        ArgumentOutOfRangeException.ThrowIfLessThan(index, 0);\n\n        var (entryStart, _, _) = _ringBoundaries[index];\n        var (nextStart, _, _) = _ringBoundaries[(index + 1) % _ringBoundaries.Length];\n        if (entryStart == nextStart)\n        {\n            // Handle hash collisions by making subsequent adjacent ranges empty.\n            if (_ringBoundaries.Length == 1)\n            {\n                return RingRange.Full;\n            }\n            else\n            {\n                // Handle hash collisions by making subsequent adjacent ranges empty.\n                return RingRange.Empty;\n            }\n        }\n\n        return RingRange.Create(entryStart, nextStart);\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private int TryGetMemberIndex(SiloAddress? address)\n    {\n        if (address is null)\n        {\n            return -1;\n        }\n\n        return SearchAlgorithms.BinarySearch(\n            Members.Length,\n            (this, address),\n            static (index, state) =>\n            {\n                var (snapshot, address) = state;\n                var candidate = snapshot.Members[index];\n                return candidate.CompareTo(address);\n            });\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool TryGetOwner(GrainId grainId, [NotNullWhen(true)] out SiloAddress? owner, [NotNullWhen(true)] out IGrainDirectoryPartition? partitionReference) => TryGetOwner(grainId.GetUniformHashCode(), out owner, out partitionReference);\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool TryGetOwner(uint hashCode, [NotNullWhen(true)] out SiloAddress? owner, [NotNullWhen(true)] out IGrainDirectoryPartition? partitionReference)\n    {\n        var index = SearchAlgorithms.RingRangeBinarySearch(\n            _ringBoundaries.Length,\n            this,\n            static (collection, index) => collection.GetRangeCore(index),\n            hashCode);\n        if (index >= 0)\n        {\n            var (_, memberIndex, partitionIndex) = _ringBoundaries[index];\n            owner = Members[memberIndex];\n            partitionReference = _partitionsByMember[memberIndex][partitionIndex];\n            return true;\n        }\n\n        Debug.Assert(Members.Length == 0);\n        owner = null;\n        partitionReference = null;\n        return false;\n    }\n\n    public readonly struct RangeCollection(DirectoryMembershipSnapshot snapshot) : IReadOnlyList<(RingRange Range, int MemberIndex, int PartitionIndex)>\n    {\n        public int Count => snapshot._ringBoundaries.Length;\n\n        public (RingRange Range, int MemberIndex, int PartitionIndex) this[int index] => snapshot.GetRangeInfo(index);\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n        IEnumerator<(RingRange Range, int MemberIndex, int PartitionIndex)> IEnumerable<(RingRange Range, int MemberIndex, int PartitionIndex)>.GetEnumerator() => GetEnumerator();\n        public RangeCollectionEnumerator GetEnumerator() => new(snapshot);\n\n        public struct RangeCollectionEnumerator(DirectoryMembershipSnapshot snapshot) : IEnumerator<(RingRange Range, int MemberIndex, int PartitionIndex)>\n        {\n            private int _index = 0;\n            public readonly (RingRange Range, int MemberIndex, int PartitionIndex) Current => snapshot.GetRangeInfo(_index - 1);\n            readonly (RingRange Range, int MemberIndex, int PartitionIndex) IEnumerator<(RingRange Range, int MemberIndex, int PartitionIndex)>.Current => Current;\n            readonly object IEnumerator.Current => Current;\n\n            public void Dispose() => _index = int.MaxValue;\n            public bool MoveNext()\n            {\n                if (_index >= 0 && _index++ < snapshot._ringBoundaries.Length)\n                {\n                    return true;\n                }\n\n                return false;\n            }\n\n            public void Reset() => _index = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/DirectoryResult.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\n\n#nullable enable\nnamespace Orleans.Runtime;\n\ninternal static class DirectoryResult\n{\n    public static DirectoryResult<T> FromResult<T>(T result, MembershipVersion version) => new DirectoryResult<T>(result, version);\n    public static DirectoryResult<T> RefreshRequired<T>(MembershipVersion version) => new DirectoryResult<T>(default, version);\n}\n\n[GenerateSerializer, Alias(\"DirectoryResult`1\"), Immutable]\ninternal readonly struct DirectoryResult<T>(T? result, MembershipVersion version)\n{\n    [Id(0)]\n    private readonly T? _result = result;\n\n    [Id(1)]\n    public readonly MembershipVersion Version = version;\n\n    public bool TryGetResult(MembershipVersion version, [NotNullWhen(true)] out T? result)\n    {\n        if (Version == version)\n        {\n            result = _result!;\n            return true;\n        }\n\n        result = default;\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/DistributedGrainDirectory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.GrainDirectory;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Scheduler;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n/*\nThe grain directory in Orleans is a key-value store where the key is a grain identifier and the value is a registration entry which points to an active silo which (potentially)\nhosts the grain.\n\nThe directory is partitioned using a consistent hash ring with ranges being assigned to the active silos in the cluster. Grain identifiers are hashed to find the silo which is\nowns the section of the ring corresponding to its hash. Each active silo owns a pre-configured number of ranges, defaulting to 30 ranges per silo. This is similar to the scheme\nused by Amazon Dynamo (see https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) and Apache Cassandra (see\nhttps://docs.datastax.com/en/cassandra-oss/3.0/cassandra/architecture/archDataDistributeVnodesUsing.html), where multiple \"virtual nodes\" (ranges) are created for each node\n(host). The size of a partition is determined by the distance between its hash and the hash of the next partition. Range ownership is determined by cluster membership\nconfiguration. Cluster membership configurations are called \"views\" and each view has a monotonically increasing version number. As silos join and leave the cluster, successive\nviews are created, resulting in changes to range ownership. This is known as a view change. Directory partitions have two modes of operation: normal operation and view change.\nDuring normal operation, directory partitions process requests locally without coordination with other hosts. During a view changes, hosts coordinate with each other to transfer\nownership of directory ranges. Once this transfer is complete, normal operation resumes. The two-phase design of the directory follows the Virtual Synchrony methodology (see\nhttps://www.microsoft.com/en-us/research/publication/virtually-synchronous-methodology-for-dynamic-service-replication/) and has some similarities to Vertical Paxos (see\nhttps://www.microsoft.com/en-us/research/publication/vertical-paxos-and-primary-backup-replication/). Both proceed in two phases: a normal operation phase where a fixed set of\nprocesses handle requests without failures, and a view change phase where state and control are transferred between views during membership changes.\n\nWhen a view change occurs, a partition can either grow or shrink. If a new silo has joined the cluster, then the partition may shrink to make room for the new silo's partition. If\na silo has left the cluster, then the partition may grow to take over the leaving silo's partition. When a partition shrinks, the previous owner seals the lost range and creates a\nsnapshot containing the directory entries in that range. The new range owner (whose partition has grown, potentially from zero) requests the snapshot from the previous owner and\napplies it locally. Once the snapshot has been applied, the new owner can begin servicing requests. The new owner acknowledges the transfer to the previous owner so the previous\nowner can delete the snapshot. The previous owner also deletes the snapshot if it sees that the snapshot transfer has been abandoned.\n\nWhen a host crashes without first handing off its directory partitions, the hosts which subsequently own the partitions previously owned by the crashed silo must perform recovery.\nRecovery involves asking every active silo in the cluster for the grain registrations they own. Registrations for evicted silos do not need to be recovered, since registrations are\nonly valid for active silos. The recovery procedure ensures that there is no data loss and that the directory remains consistent (no duplicate grain activations).\n\nCluster membership guarantees monotonicity, but it does not guarantee that all silos see all membership views: it is possible for silos to skip intermediate membership view, for\nexample if membership changes rapidly. When this happens, snapshot transfers are abandoned and recovery must be performed instead of the normal partition-to-partition hand-over,\nsince the silo does not know with certainty which partition was the previous owner. A future improvement to cluster membership may reduce or eliminate this scenario by ensuring\nthat all views are seen by all silos.\n\nDirectory partitions (implemented in GrainDirectoryPartition) use versioned range locks to prevent invalid access to ranges during view changes. Range locks are created during\nview change and are released when the view change is complete. These locks are analogous to the 'wedges' used in the Virtual Synchrony methodology. It is possible for a range to\nbe split among multiple silos during a view change. This adds some complexity to the view change procedure since each partition must potentially coordinate with multiple other\npartitions to complete the view change.\n\nAll requests to a directory partition include the view number of the caller, and all responses from the directory include the view number of the directory partition. When the\ndirectory partition sees a view number higher than its own, it refreshes its view and initiates view change. Similarly, when a caller sees a response with a higher view number\nthan its own, it refreshes its view and retries the request if necessary. This ensures that all requests are processed by the correct owner of the directory partition.\n*/\ninternal sealed partial class DistributedGrainDirectory : SystemTarget, IGrainDirectory, IGrainDirectoryClient, ILifecycleParticipant<ISiloLifecycle>, DistributedGrainDirectory.ITestHooks\n{\n    private readonly DirectoryMembershipService _membershipService;\n    private readonly ILogger<DistributedGrainDirectory> _logger;\n    private readonly IServiceProvider _serviceProvider;\n    private readonly ImmutableArray<GrainDirectoryPartition> _partitions;\n    private readonly CancellationTokenSource _stoppedCts = new();\n\n    internal CancellationToken OnStoppedToken => _stoppedCts.Token;\n    internal ClusterMembershipSnapshot ClusterMembershipSnapshot => _membershipService.CurrentView.ClusterMembershipSnapshot;\n\n    // The recovery membership value is used to avoid a race between concurrent registration & recovery operations which could lead to lost registrations.\n    // This could occur when a new activation is created and begins registering itself with a host which crashes. Concurrently, the new owner initiates\n    // recovery and asks all silos for their activations. When this silo processes this request, it will have the activation in its internal\n    // 'ActivationDirectory' even though these activations may not yet have completed registration. Therefore, multiple silos may return an entry for the same\n    // grain. By ensuring that any registration occurred at a version at least as high as the recovery version, we avoid this issue. This could be made more\n    // precise by also tracking the sets of ranges which need to be recovered, but that complicates things somewhat since it would require tracking the ranges\n    // for each recovery version.\n    private long _recoveryMembershipVersion;\n    private Task _runTask = Task.CompletedTask;\n    private ActivationDirectory _localActivations;\n    private GrainDirectoryResolver? _grainDirectoryResolver;\n\n    public DistributedGrainDirectory(\n        DirectoryMembershipService membershipService,\n        ILogger<DistributedGrainDirectory> logger,\n        IServiceProvider serviceProvider,\n        IInternalGrainFactory grainFactory,\n        SystemTargetShared shared) : base(Constants.GrainDirectoryType, shared)\n    {\n        _localActivations = shared.ActivationDirectory;\n        _serviceProvider = serviceProvider;\n        _membershipService = membershipService;\n        _logger = logger;\n        var partitions = ImmutableArray.CreateBuilder<GrainDirectoryPartition>(DirectoryMembershipSnapshot.PartitionsPerSilo);\n        for (var i = 0; i < DirectoryMembershipSnapshot.PartitionsPerSilo; i++)\n        {\n            partitions.Add(new GrainDirectoryPartition(i, this, grainFactory, shared));\n        }\n\n        _partitions = partitions.ToImmutable();\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    public async Task<GrainAddress?> Lookup(GrainId grainId) => await InvokeAsync(\n        grainId,\n        static (partition, version, grainId, cancellationToken) => partition.LookupAsync(version, grainId),\n        grainId,\n        CancellationToken.None);\n\n    public async Task<GrainAddress?> Register(GrainAddress address) => await InvokeAsync(\n        address.GrainId,\n        static (partition, version, address, cancellationToken) => partition.RegisterAsync(version, address, null),\n        address,\n        CancellationToken.None);\n\n    public async Task Unregister(GrainAddress address) => await InvokeAsync(\n        address.GrainId,\n        static (partition, version, address, cancellationToken) => partition.DeregisterAsync(version, address),\n        address,\n        CancellationToken.None);\n\n    public async Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress) => await InvokeAsync(\n        address.GrainId,\n        static (partition, version, state, cancellationToken) => partition.RegisterAsync(version, state.Address, state.PreviousAddress),\n        (Address: address, PreviousAddress: previousAddress),\n        CancellationToken.None);\n\n    public Task UnregisterSilos(List<SiloAddress> siloAddresses) => Task.CompletedTask;\n\n    private async Task<TResult> InvokeAsync<TState, TResult>(\n        GrainId grainId,\n        Func<IGrainDirectoryPartition, MembershipVersion, TState, CancellationToken, ValueTask<DirectoryResult<TResult>>> func,\n        TState state,\n        CancellationToken cancellationToken,\n        [CallerMemberName] string operation = \"\")\n    {\n        DirectoryResult<TResult> invokeResult;\n        var view = _membershipService.CurrentView;\n        var attempts = 0;\n        const int MaxAttempts = 10;\n        var delay = TimeSpan.FromMilliseconds(10);\n        while (true)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            var initialRecoveryMembershipVersion = _recoveryMembershipVersion;\n            if (view.Version.Value < initialRecoveryMembershipVersion || !view.TryGetOwner(grainId, out var owner, out var partitionReference))\n            {\n                // If there are no members, bail out with the default return value.\n                if (view.Members.Length == 0 && view.Version.Value > 0)\n                {\n                    return default!;\n                }\n\n                var targetVersion = Math.Max(view.Version.Value + 1, initialRecoveryMembershipVersion);\n                view = await _membershipService.RefreshViewAsync(new(targetVersion), cancellationToken);\n                continue;\n            }\n\n#if false\n            if (logger.IsEnabled(LogLevel.Trace))\n            {\n                logger.LogTrace(\"Invoking '{Operation}' on '{Owner}' for grain '{GrainId}'.\", operation, owner, grainId);\n            }\n#endif\n\n            try\n            {\n                RequestContext.Set(\"gid\", partitionReference.GetGrainId());\n                invokeResult = await func(partitionReference, view.Version, state, cancellationToken);\n            }\n            catch (OrleansMessageRejectionException) when (attempts < MaxAttempts && !cancellationToken.IsCancellationRequested)\n            {\n                // This likely indicates that the target silo has been declared dead.\n                ++attempts;\n                await Task.Delay(delay, cancellationToken);\n                delay *= 1.5;\n                continue;\n            }\n\n            if (initialRecoveryMembershipVersion != _recoveryMembershipVersion)\n            {\n                // If the recovery version changed, perform a view refresh and re-issue the operation.\n                // See the comment on the declaration of '_recoveryMembershipVersionValue' for more details.\n                continue;\n            }\n\n            if (!invokeResult.TryGetResult(view.Version, out var result))\n            {\n                // The remote replica has a newer view of membership and is no longer the owner of the grain specified in the request.\n                // Refresh membership and re-evaluate.\n                view = await _membershipService.RefreshViewAsync(invokeResult.Version, cancellationToken);\n                continue;\n            }\n\n            LogTraceInvokedOperation(_logger, operation, owner, grainId, result);\n\n            return result;\n        }\n    }\n\n    public async ValueTask<Immutable<List<GrainAddress>>> RecoverRegisteredActivations(MembershipVersion membershipVersion, RingRange range, SiloAddress siloAddress, int partitionIndex)\n    {\n        foreach (var partition in _partitions)\n        {\n            partition.OnRecoveringPartition(membershipVersion, range, siloAddress, partitionIndex).Ignore();\n        }\n\n        return await GetRegisteredActivations(membershipVersion, range, false);\n    }\n\n    public async ValueTask<Immutable<List<GrainAddress>>> GetRegisteredActivations(MembershipVersion membershipVersion, RingRange range, bool isValidation)\n    {\n        if (!isValidation)\n        {\n            LogDebugCollectingRegisteredActivations(_logger, range, membershipVersion);\n        }\n\n        var recoveryMembershipVersion = _recoveryMembershipVersion;\n        if (recoveryMembershipVersion < membershipVersion.Value)\n        {\n            // Ensure that the value is immediately visible to any thread registering an activation.\n            Interlocked.CompareExchange(ref _recoveryMembershipVersion, membershipVersion.Value, recoveryMembershipVersion);\n        }\n\n        List<GrainAddress> result = [];\n        List<Task> deactivationTasks = [];\n        var stopwatch = CoarseStopwatch.StartNew();\n        using var cts = new CancellationTokenSource();\n        cts.Cancel();\n\n        foreach (var (grainId, activation) in _localActivations)\n        {\n            var directory = GetGrainDirectory(activation, _grainDirectoryResolver!);\n            if (directory == this)\n            {\n                var address = activation.Address;\n                if (!range.Contains(address.GrainId))\n                {\n                    continue;\n                }\n\n                if (address.MembershipVersion == MembershipVersion.MinValue\n                    || activation is ActivationData activationData && !activationData.IsValid)\n                {\n                    // Validation does not require that the grain is deactivated, skip it instead.\n                    //if (isValidation) continue;\n\n                    try\n                    {\n                        // This activation has not completed registration or is not currently active.\n                        // Abort the activation with a pre-canceled cancellation token so that it skips directory deregistration.\n                        // TODO: Expand validity check to non-ActivationData activations.\n                        //logger.LogWarning(\"Deactivating activation '{Activation}' due to failure of a directory range owner.\", activation);\n                        activation.Deactivate(new DeactivationReason(DeactivationReasonCode.DirectoryFailure, \"This activation's directory partition was salvaged while registration status was in-doubt.\"), cts.Token);\n                        deactivationTasks.Add(activation.Deactivated);\n                    }\n                    catch (Exception exception)\n                    {\n                        LogWarningFailedToDeactivateActivation(_logger, exception, activation);\n                    }\n                }\n                else\n                {\n                    if (!isValidation)\n                    {\n                        LogTraceSendingActivationForRecovery(_logger, activation.GrainId, range, membershipVersion);\n                    }\n\n                    result.Add(activation.Address);\n                }\n            }\n        }\n\n        await Task.WhenAll(deactivationTasks);\n\n        if (!isValidation)\n        {\n            LogDebugSubmittingRegisteredActivations(_logger, result.Count, range, membershipVersion, deactivationTasks.Count, stopwatch.ElapsedMilliseconds);\n        }\n\n        return result.AsImmutable();\n\n        static IGrainDirectory? GetGrainDirectory(IGrainContext grainContext, GrainDirectoryResolver grainDirectoryResolver)\n        {\n            if (grainContext is ActivationData activationData)\n            {\n                return activationData.Shared.GrainDirectory;\n            }\n            else if (grainContext is SystemTarget systemTarget)\n            {\n                return null;\n            }\n            else if (grainContext.GetComponent<PlacementStrategy>() is { IsUsingGrainDirectory: true })\n            {\n                return grainDirectoryResolver.Resolve(grainContext.GrainId.Type);\n            }\n\n            return null;\n        }\n    }\n\n    internal ValueTask<DirectoryMembershipSnapshot> RefreshViewAsync(MembershipVersion version, CancellationToken cancellationToken) => _membershipService.RefreshViewAsync(version, cancellationToken);\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle observer)\n    {\n        _grainDirectoryResolver = _serviceProvider.GetRequiredService<GrainDirectoryResolver>();\n\n        observer.Subscribe(nameof(DistributedGrainDirectory), ServiceLifecycleStage.RuntimeInitialize, OnRuntimeInitializeStart, OnRuntimeInitializeStop);\n\n        // Transition into 'ShuttingDown'/'Stopping' stage, removing ourselves from directory membership, but allow some time for hand-off before transitioning to 'Dead'.\n        observer.Subscribe(nameof(DistributedGrainDirectory), ServiceLifecycleStage.BecomeActive - 1, _ => Task.CompletedTask, OnShuttingDown);\n\n        Task OnRuntimeInitializeStart(CancellationToken cancellationToken)\n        {\n            using var _ = new ExecutionContextSuppressor();\n            WorkItemGroup.QueueAction(() => _runTask = ProcessMembershipUpdates());\n\n            return Task.CompletedTask;\n        }\n\n        async Task OnRuntimeInitializeStop(CancellationToken cancellationToken)\n        {\n            _stoppedCts.Cancel();\n            if (_runTask is { } task)\n            {\n                // Try to wait for hand-off to complete.\n                await this.RunOrQueueTask(async () => await task.WaitAsync(cancellationToken).SuppressThrowing());\n            }\n        }\n\n        async Task OnShuttingDown(CancellationToken token)\n        {\n            var tasks = new List<Task>(_partitions.Length);\n            foreach (var partition in _partitions)\n            {\n                tasks.Add(partition.OnShuttingDown(token));\n            }\n\n            await Task.WhenAll(tasks).SuppressThrowing();\n        }\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        // Ensure all child tasks are completed before exiting, tracking them here.\n        List<Task> tasks = [];\n        var previousUpdate = ClusterMembershipSnapshot.Default;\n        while (!_stoppedCts.IsCancellationRequested)\n        {\n            try\n            {\n                DirectoryMembershipSnapshot previous = _membershipService.CurrentView;\n                var previousRanges = RingRangeCollection.Empty;\n                await foreach (var update in _membershipService.ViewUpdates.WithCancellation(_stoppedCts.Token))\n                {\n                    tasks.RemoveAll(t => t.IsCompleted);\n                    var changes = update.ClusterMembershipSnapshot.CreateUpdate(previousUpdate);\n\n                    foreach (var change in changes.Changes)\n                    {\n                        if (change.Status == SiloStatus.Dead)\n                        {\n                            foreach (var partition in _partitions)\n                            {\n                                tasks.Add(partition.OnSiloRemovedFromClusterAsync(change));\n                            }\n                        }\n                    }\n\n                    var current = update;\n                    var currentRanges = current.GetMemberRanges(Silo);\n\n                    foreach (var partition in _partitions)\n                    {\n                        tasks.Add(partition.ProcessMembershipUpdateAsync(current));\n                    }\n\n                    var deltaSize = currentRanges.SizePercent - previousRanges.SizePercent;\n                    var meanSizePercent = current.Members.Length > 0 ? 100.0 / current.Members.Length : 0f;\n                    var deviationFromMean = Math.Abs(meanSizePercent - currentRanges.SizePercent);\n                    LogDebugUpdatedView(previous.Version, current.Version, currentRanges.SizePercent, deltaSize, deviationFromMean);\n\n                    previousUpdate = update.ClusterMembershipSnapshot;\n                    previous = current;\n                    previousRanges = currentRanges;\n                }\n            }\n            catch (Exception exception)\n            {\n                if (!_stoppedCts.IsCancellationRequested)\n                {\n                    LogErrorProcessingMembershipUpdates(exception);\n                }\n            }\n        }\n\n        await Task.WhenAll(tasks).SuppressThrowing();\n    }\n\n    SiloAddress? ITestHooks.GetPrimaryForGrain(GrainId grainId)\n    {\n        _membershipService.CurrentView.TryGetOwner(grainId, out var owner, out _);\n        return owner;\n    }\n\n    async Task<GrainAddress?> ITestHooks.GetLocalRecord(GrainId grainId)\n    {\n        var view = _membershipService.CurrentView;\n        if (view.TryGetOwner(grainId, out var owner, out var partitionReference) && Silo.Equals(owner))\n        {\n            var result = await partitionReference.LookupAsync(view.Version, grainId);\n            if (result.TryGetResult(view.Version, out var address))\n            {\n                return address;\n            }\n        }\n\n        return null;\n    }\n\n    internal interface ITestHooks\n    {\n        SiloAddress? GetPrimaryForGrain(GrainId grainId);\n        Task<GrainAddress?> GetLocalRecord(GrainId grainId);\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Updated view from '{PreviousVersion}' to '{Version}'. Now responsible for {Range:0.00}% (Δ {DeltaPercent:0.00}%). {DeviationFromMean:0.00}% from ideal share.\"\n    )]\n    private partial void LogDebugUpdatedView(MembershipVersion previousVersion, MembershipVersion version, double range, double deltaPercent, double deviationFromMean);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing membership updates.\"\n    )]\n    private partial void LogErrorProcessingMembershipUpdates(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Invoked '{Operation}' on '{Owner}' for grain '{GrainId}' and received result '{Result}'.\"\n    )]\n    private static partial void LogTraceInvokedOperation(ILogger logger, string operation, SiloAddress owner, GrainId grainId, object result);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Collecting registered activations for range {Range} at version {MembershipVersion}.\"\n    )]\n    private static partial void LogDebugCollectingRegisteredActivations(ILogger logger, RingRange range, MembershipVersion membershipVersion);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to deactivate activation {Activation}\"\n    )]\n    private static partial void LogWarningFailedToDeactivateActivation(ILogger logger, Exception exception, IGrainContext activation);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Sending activation '{Activation}' for recovery because its in the requested range {Range} (version {Version}).\"\n    )]\n    private static partial void LogTraceSendingActivationForRecovery(ILogger logger, GrainId activation, RingRange range, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Submitting {Count} registered activations for range {Range} at version {MembershipVersion}. Deactivated {DeactivationCount} in-doubt registrations. Took {ElapsedMilliseconds}ms\"\n    )]\n    private static partial void LogDebugSubmittingRegisteredActivations(ILogger logger, int count, RingRange range, MembershipVersion membershipVersion, int deactivationCount, long elapsedMilliseconds);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GenericGrainDirectoryResolver.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.GrainDirectory;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal class GenericGrainDirectoryResolver : IGrainDirectoryResolver\n    {\n        private readonly IServiceProvider _services;\n        private GrainDirectoryResolver _resolver;\n\n        public GenericGrainDirectoryResolver(IServiceProvider services)\n        {\n            _services = services;\n        }\n\n        public bool TryResolveGrainDirectory(GrainType grainType, GrainProperties properties, out IGrainDirectory grainDirectory)\n        {\n            if (GenericGrainType.TryParse(grainType, out var constructed) && constructed.IsConstructed)\n            {\n                var generic = constructed.GetUnconstructedGrainType().GrainType;\n                var resolver = GetResolver();\n                if (resolver.TryGetNonDefaultGrainDirectory(generic, out grainDirectory))\n                {\n                    return true;\n                }\n            }\n\n            grainDirectory = default;\n            return false;\n        }\n\n        private GrainDirectoryResolver GetResolver() => _resolver ??= _services.GetRequiredService<GrainDirectoryResolver>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryCacheFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Creates <see cref=\"IGrainDirectoryCache\"/> instances.\n    /// </summary>\n    public static class GrainDirectoryCacheFactory\n    {\n        /// <summary>\n        /// Creates a new grain directory cache instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"options\">The options.</param>\n        /// <returns>The newly created <see cref=\"IGrainDirectoryCache\"/> instance.</returns>\n        public static IGrainDirectoryCache CreateGrainDirectoryCache(IServiceProvider services, GrainDirectoryOptions options)\n        {\n            if (options.CacheSize <= 0)\n                return new NullGrainDirectoryCache();\n\n            switch (options.CachingStrategy)\n            {\n                case GrainDirectoryOptions.CachingStrategyType.None:\n                    return new NullGrainDirectoryCache();\n                case GrainDirectoryOptions.CachingStrategyType.LRU:\n#pragma warning disable CS0618 // Type or member is obsolete\n                case GrainDirectoryOptions.CachingStrategyType.Adaptive:\n#pragma warning restore CS0618 // Type or member is obsolete\n                    return new LruGrainDirectoryCache(options.CacheSize);\n                case GrainDirectoryOptions.CachingStrategyType.Custom:\n                default:\n                    return services.GetRequiredService<IGrainDirectoryCache>();\n            }\n        }\n\n        internal static IGrainDirectoryCache CreateCustomGrainDirectoryCache(IServiceProvider services, GrainDirectoryOptions options)\n        {\n            var grainDirectoryCache = services.GetService<IGrainDirectoryCache>();\n            if (grainDirectoryCache != null)\n            {\n                return grainDirectoryCache;\n            }\n            else\n            {\n                return new LruGrainDirectoryCache(options.CacheSize);\n            }\n        }\n    }\n\n    internal sealed class NullGrainDirectoryCache : IGrainDirectoryCache\n    {\n        public void AddOrUpdate(GrainAddress value, int version)\n        {\n        }\n\n        public bool Remove(GrainId key) => false;\n\n        public bool Remove(GrainAddress key) => false;\n\n        public void Clear()\n        {\n        }\n\n        public bool LookUp(GrainId key, out GrainAddress result, out int version)\n        {\n            result = default;\n            version = default;\n            return false;\n        }\n\n        public IEnumerable<(GrainAddress ActivationAddress, int Version)> KeyValues\n        {\n            get { yield break; }\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryHandoffManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Scheduler;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Most methods of this class are synchronized since they might be called both\n    /// from LocalGrainDirectory on CacheValidator.SchedulingContext and from RemoteGrainDirectory.\n    /// </summary>\n    internal sealed partial class GrainDirectoryHandoffManager\n    {\n        private static readonly TimeSpan RetryDelay = TimeSpan.FromMilliseconds(250);\n        private const int MAX_OPERATION_DEQUEUE = 2;\n        private readonly LocalGrainDirectory localDirectory;\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly ILogger logger;\n        private readonly Factory<LocalGrainDirectoryPartition> createPartion;\n        private readonly Queue<(string name, object state, Func<GrainDirectoryHandoffManager, object, Task> action)> pendingOperations = new();\n        private readonly AsyncLock executorLock = new AsyncLock();\n\n        internal GrainDirectoryHandoffManager(\n            LocalGrainDirectory localDirectory,\n            ISiloStatusOracle siloStatusOracle,\n            IInternalGrainFactory grainFactory,\n            Factory<LocalGrainDirectoryPartition> createPartion,\n            ILoggerFactory loggerFactory)\n        {\n            logger = loggerFactory.CreateLogger<GrainDirectoryHandoffManager>();\n            this.localDirectory = localDirectory;\n            this.siloStatusOracle = siloStatusOracle;\n            this.grainFactory = grainFactory;\n            this.createPartion = createPartion;\n        }\n\n        internal void ProcessSiloAddEvent(SiloAddress addedSilo)\n        {\n            lock (this)\n            {\n                LogDebugProcessingSiloAddEvent(logger, addedSilo);\n\n                // check if this is our immediate successor (i.e., if I should hold this silo's copy)\n                // (if yes, adjust local and/or copied directory partitions by splitting them between old successors and the new one)\n                // NOTE: We need to move part of our local directory to the new silo if it is an immediate successor.\n                var successor = localDirectory.FindSuccessor(localDirectory.MyAddress);\n                if (successor is null || !successor.Equals(addedSilo))\n                {\n                    LogDebugNotImmediateSuccessor(logger, addedSilo);\n                    return;\n                }\n\n                // split my local directory and send to my new immediate successor his share\n                LogDebugSplittingPartition(logger, addedSilo);\n                var splitPartListSingle = localDirectory.DirectoryPartition.Split(\n                    grain =>\n                    {\n                        var s = localDirectory.CalculateGrainDirectoryPartition(grain);\n                        return s != null && !localDirectory.MyAddress.Equals(s);\n                    });\n\n                EnqueueOperation($\"{nameof(ProcessSiloAddEvent)}({addedSilo})\", addedSilo,\n                    (t, state) => t.ProcessAddedSiloAsync((SiloAddress)state, splitPartListSingle));\n            }\n        }\n\n        private async Task ProcessAddedSiloAsync(SiloAddress addedSilo, List<GrainAddress> splitPartListSingle)\n        {\n            if (!this.localDirectory.Running) return;\n\n            if (this.siloStatusOracle.GetApproximateSiloStatus(addedSilo) == SiloStatus.Active)\n            {\n                if (splitPartListSingle.Count > 0)\n                {\n                    LogDebugSendingEntries(logger, splitPartListSingle.Count, addedSilo);\n                }\n\n                await localDirectory.GetDirectoryReference(addedSilo).AcceptSplitPartition(splitPartListSingle);\n            }\n            else\n            {\n                LogWarningSiloNotActive(logger, addedSilo);\n                return;\n            }\n\n            if (splitPartListSingle.Count > 0)\n            {\n                LogDebugRemovingEntries(logger, splitPartListSingle.Count);\n\n                foreach (var activationAddress in splitPartListSingle)\n                {\n                    localDirectory.DirectoryPartition.RemoveGrain(activationAddress.GrainId);\n                }\n            }\n        }\n\n        internal void AcceptExistingRegistrations(List<GrainAddress> singleActivations)\n        {\n            if (singleActivations.Count == 0) return;\n            EnqueueOperation(nameof(AcceptExistingRegistrations), singleActivations,\n                (t, state) => t.AcceptExistingRegistrationsAsync((List<GrainAddress>)state));\n        }\n\n        private async Task AcceptExistingRegistrationsAsync(List<GrainAddress> singleActivations)\n        {\n            if (!this.localDirectory.Running) return;\n\n            LogDebugAcceptingRegistrations(logger, singleActivations.Count);\n\n            var tasks = singleActivations.Select(addr => this.localDirectory.RegisterAsync(addr, previousAddress: null, 1)).ToArray();\n            try\n            {\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception exception)\n            {\n                LogWarningExceptionRegistering(logger, exception);\n                throw;\n            }\n            finally\n            {\n                Dictionary<SiloAddress, List<GrainAddress>>? duplicates = null;\n                for (var i = tasks.Length - 1; i >= 0; i--)\n                {\n                    // Retry failed tasks next time.\n                    if (!tasks[i].IsCompletedSuccessfully) continue;\n\n                    // Record the applications which lost the registration race (duplicate activations).\n                    var winner = tasks[i].Result;\n                    if (winner.Address is not { } winnerAddress || !winnerAddress.Equals(singleActivations[i]))\n                    {\n                        var duplicate = singleActivations[i];\n                        (CollectionsMarshal.GetValueRefOrAddDefault(duplicates ??= new(), duplicate.SiloAddress!, out _) ??= new()).Add(duplicate);\n                    }\n\n                    // Remove tasks which completed.\n                    singleActivations.RemoveAt(i);\n                }\n\n                // Destroy any duplicate activations.\n                DestroyDuplicateActivations(duplicates);\n            }\n        }\n\n        private void DestroyDuplicateActivations(Dictionary<SiloAddress, List<GrainAddress>>? duplicates)\n        {\n            if (duplicates == null || duplicates.Count == 0) return;\n            EnqueueOperation(nameof(DestroyDuplicateActivations), duplicates,\n                (t, state) => t.DestroyDuplicateActivationsAsync((Dictionary<SiloAddress, List<GrainAddress>>)state));\n        }\n\n        private async Task DestroyDuplicateActivationsAsync(Dictionary<SiloAddress, List<GrainAddress>> duplicates)\n        {\n            while (duplicates.Count > 0)\n            {\n                var pair = duplicates.FirstOrDefault();\n                if (this.siloStatusOracle.GetApproximateSiloStatus(pair.Key) == SiloStatus.Active)\n                {\n                    LogDebugDestroyingDuplicates(logger, duplicates.Count, pair.Key, new(pair.Value));\n\n                    var remoteCatalog = this.grainFactory.GetSystemTarget<ICatalog>(Constants.CatalogType, pair.Key);\n                    await remoteCatalog.DeleteActivations(pair.Value, DeactivationReasonCode.DuplicateActivation, \"This grain has been activated elsewhere\");\n                }\n\n                duplicates.Remove(pair.Key);\n            }\n        }\n\n        private void EnqueueOperation(string name, object state, Func<GrainDirectoryHandoffManager, object, Task> action)\n        {\n            lock (this)\n            {\n                this.pendingOperations.Enqueue((name, state, action));\n                if (this.pendingOperations.Count <= 2)\n                {\n                    this.localDirectory.RemoteGrainDirectory.WorkItemGroup.QueueTask(ExecutePendingOperations, localDirectory.RemoteGrainDirectory);\n                }\n            }\n        }\n\n        private async Task ExecutePendingOperations()\n        {\n            using (await executorLock.LockAsync())\n            {\n                var dequeueCount = 0;\n                while (true)\n                {\n                    // Get the next operation, or exit if there are none.\n                    (string Name, object State, Func<GrainDirectoryHandoffManager, object, Task> Action) op;\n                    lock (this)\n                    {\n                        if (this.pendingOperations.Count == 0) break;\n\n                        op = this.pendingOperations.Peek();\n                    }\n\n                    dequeueCount++;\n\n                    try\n                    {\n                        await op.Action(this, op.State);\n                        // Success, reset the dequeue count\n                        dequeueCount = 0;\n                    }\n                    catch (Exception exception)\n                    {\n                        if (dequeueCount < MAX_OPERATION_DEQUEUE)\n                        {\n                            LogWarningOperationFailedRetry(logger, exception, op.Name);\n                            await Task.Delay(RetryDelay);\n                        }\n                        else\n                        {\n                            LogWarningOperationFailedNoRetry(logger, exception, op.Name);\n                        }\n                    }\n                    if (dequeueCount == 0 || dequeueCount >= MAX_OPERATION_DEQUEUE)\n                    {\n                        lock (this)\n                        {\n                            // Remove the operation from the queue if it was a success\n                            // or if we tried too many times\n                            this.pendingOperations.Dequeue();\n                        }\n                    }\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Processing silo add event for {AddedSilo}\"\n        )]\n        private static partial void LogDebugProcessingSiloAddEvent(ILogger logger, SiloAddress addedSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{AddedSilo} is not my immediate successor.\"\n        )]\n        private static partial void LogDebugNotImmediateSuccessor(ILogger logger, SiloAddress addedSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Splitting my partition between me and {AddedSilo}\"\n        )]\n        private static partial void LogDebugSplittingPartition(ILogger logger, SiloAddress addedSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Sending {Count} single activation entries to {AddedSilo}\"\n        )]\n        private static partial void LogDebugSendingEntries(ILogger logger, int count, SiloAddress addedSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Silo {AddedSilo} is no longer active and therefore cannot receive this partition split\"\n        )]\n        private static partial void LogWarningSiloNotActive(ILogger logger, SiloAddress addedSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Removing {Count} single activation after partition split\"\n        )]\n        private static partial void LogDebugRemovingEntries(ILogger logger, int count);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(AcceptExistingRegistrations)}: accepting {{Count}} single-activation registrations\"\n        )]\n        private static partial void LogDebugAcceptingRegistrations(ILogger logger, int count);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = $\"Exception registering activations in {nameof(AcceptExistingRegistrations)}\"\n        )]\n        private static partial void LogWarningExceptionRegistering(ILogger logger, Exception exception);\n\n        private readonly struct GrainAddressesLogValue(List<GrainAddress> grainAddresses)\n        {\n            public override string ToString() => string.Join(\"\\n * \", grainAddresses.Select(_ => _));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = $\"{nameof(DestroyDuplicateActivations)} will destroy {{Count}} duplicate activations on silo {{SiloAddress}}: {{Duplicates}}\"\n        )]\n        private static partial void LogDebugDestroyingDuplicates(ILogger logger, int count, SiloAddress siloAddress, GrainAddressesLogValue duplicates);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"{Operation} failed, will be retried\"\n        )]\n        private static partial void LogWarningOperationFailedRetry(ILogger logger, Exception exception, string operation);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"{Operation} failed, will NOT be retried\"\n        )]\n        private static partial void LogWarningOperationFailedNoRetry(ILogger logger, Exception exception, string operation);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryPartition.Interface.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\n#nullable enable\n\nnamespace Orleans.Runtime.GrainDirectory;\n\ninternal sealed partial class GrainDirectoryPartition\n{\n    async ValueTask<DirectoryResult<GrainAddress>> IGrainDirectoryPartition.RegisterAsync(MembershipVersion version, GrainAddress address, GrainAddress? currentRegistration)\n    {\n        ArgumentNullException.ThrowIfNull(address);\n        LogRegisterAsync(version, address, currentRegistration);\n\n        // Ensure that the current membership version is new enough.\n        await WaitForRange(address.GrainId, version);\n        if (!IsOwner(CurrentView, address.GrainId))\n        {\n            return DirectoryResult.RefreshRequired<GrainAddress>(CurrentView.Version);\n        }\n\n        DebugAssertOwnership(address.GrainId);\n        return DirectoryResult.FromResult(RegisterCore(address, currentRegistration), version);\n    }\n\n    async ValueTask<DirectoryResult<GrainAddress?>> IGrainDirectoryPartition.LookupAsync(MembershipVersion version, GrainId grainId)\n    {\n        LogLookupAsync(version, grainId);\n\n        // Ensure we can serve the request.\n        await WaitForRange(grainId, version);\n        if (!IsOwner(CurrentView, grainId))\n        {\n            return DirectoryResult.RefreshRequired<GrainAddress?>(CurrentView.Version);\n        }\n\n        return DirectoryResult.FromResult(LookupCore(grainId), version);\n    }\n\n    async ValueTask<DirectoryResult<bool>> IGrainDirectoryPartition.DeregisterAsync(MembershipVersion version, GrainAddress address)\n    {\n        ArgumentNullException.ThrowIfNull(address);\n        LogDeregisterAsync(version, address);\n\n        await WaitForRange(address.GrainId, version);\n        if (!IsOwner(CurrentView, address.GrainId))\n        {\n            return DirectoryResult.RefreshRequired<bool>(CurrentView.Version);\n        }\n\n        DebugAssertOwnership(address.GrainId);\n        return DirectoryResult.FromResult(DeregisterCore(address), version);\n    }\n\n    private bool DeregisterCore(GrainAddress address)\n    {\n        if (_directory.TryGetValue(address.GrainId, out var existing) && (existing.Matches(address) || IsSiloDead(existing)))\n        {\n            return _directory.Remove(address.GrainId);\n        }\n\n        return false;\n    }\n\n    internal GrainAddress? LookupCore(GrainId grainId)\n    {\n        if (_directory.TryGetValue(grainId, out var existing) && !IsSiloDead(existing))\n        {\n            return existing;\n        }\n\n        return null;\n    }\n\n    private GrainAddress RegisterCore(GrainAddress newAddress, GrainAddress? existingAddress)\n    {\n        ref var existing = ref CollectionsMarshal.GetValueRefOrAddDefault(_directory, newAddress.GrainId, out _);\n\n        if (existing is null || existing.Matches(existingAddress) || IsSiloDead(existing))\n        {\n            if (newAddress.MembershipVersion != CurrentView.Version)\n            {\n                // Set the membership version to match the view number in which it was registered.\n                newAddress = new()\n                {\n                    GrainId = newAddress.GrainId,\n                    SiloAddress = newAddress.SiloAddress,\n                    ActivationId = newAddress.ActivationId,\n                    MembershipVersion = CurrentView.Version\n                };\n            }\n\n            existing = newAddress;\n        }\n\n        return existing;\n    }\n\n    private bool IsSiloDead(GrainAddress existing) => _owner.ClusterMembershipSnapshot.GetSiloStatus(existing.SiloAddress) == SiloStatus.Dead;\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"RegisterAsync('{Version}', '{Address}', '{ExistingAddress}')\"\n    )]\n    private partial void LogRegisterAsync(MembershipVersion version, GrainAddress address, GrainAddress? existingAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"LookupAsync('{Version}', '{GrainId}')\"\n    )]\n    private partial void LogLookupAsync(MembershipVersion version, GrainId grainId);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"DeregisterAsync('{Version}', '{Address}')\"\n    )]\n    private partial void LogDeregisterAsync(MembershipVersion version, GrainAddress address);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryPartition.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Internal;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Runtime.Utilities;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n/// <summary>\n/// Represents a single contiguous partition of the distributed grain directory.\n/// </summary>\ninternal sealed partial class GrainDirectoryPartition : SystemTarget, IGrainDirectoryPartition, IGrainDirectoryTestHooks\n{\n    internal static SystemTargetGrainId CreateGrainId(SiloAddress siloAddress, int partitionIndex) => SystemTargetGrainId.Create(Constants.GrainDirectoryPartitionType, siloAddress, partitionIndex.ToString(CultureInfo.InvariantCulture));\n    private readonly Dictionary<GrainId, GrainAddress> _directory = [];\n    private readonly int _partitionIndex;\n    private readonly DistributedGrainDirectory _owner;\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly CancellationTokenSource _drainSnapshotsCts = new();\n    private readonly SiloAddress _id;\n    private readonly ILogger<GrainDirectoryPartition> _logger;\n    private readonly TaskCompletionSource _snapshotsDrainedTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n    private readonly AsyncEnumerable<DirectoryMembershipSnapshot> _viewUpdates = new(\n        DirectoryMembershipSnapshot.Default,\n        (previous, proposed) => proposed.Version >= previous.Version,\n        _ => { });\n\n    // Ranges which cannot be served currently, eg because the partition is currently transferring them from a previous owner.\n    // Requests in these ranges must wait for the range to become available.\n    private readonly List<(RingRange Range, MembershipVersion Version, TaskCompletionSource Completion)> _rangeLocks = [];\n\n    // Ranges which were previously at least partially owned by this partition, but which are pending transfer to a new partition.\n    private readonly List<PartitionSnapshotState> _partitionSnapshots = [];\n\n    // Tracked for diagnostic purposes only.\n    private readonly List<Task> _viewChangeTasks = [];\n    private CancellationToken ShutdownToken => _owner.OnStoppedToken;\n\n    private RingRange _currentRange;\n\n    /// <param name=\"partitionIndex\">The index of this partition on this silo. Each silo hosts a fixed number of dynamically sized partitions.</param>\n    public GrainDirectoryPartition(\n        int partitionIndex,\n        DistributedGrainDirectory owner,\n        IInternalGrainFactory grainFactory,\n        SystemTargetShared shared) : base(CreateGrainId(shared.SiloAddress, partitionIndex), shared)\n    {\n        _partitionIndex = partitionIndex;\n        _owner = owner;\n        _grainFactory = grainFactory;\n        _id = shared.SiloAddress;\n        _logger = shared.LoggerFactory.CreateLogger<GrainDirectoryPartition>();\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    // The current directory membership snapshot.\n    public DirectoryMembershipSnapshot CurrentView { get; private set; } = DirectoryMembershipSnapshot.Default;\n\n    public async ValueTask<DirectoryMembershipSnapshot> RefreshViewAsync(MembershipVersion version, CancellationToken cancellationToken)\n    {\n        _ = _owner.RefreshViewAsync(version, cancellationToken);\n        if (CurrentView.Version <= version)\n        {\n            await foreach (var view in _viewUpdates.WithCancellation(cancellationToken))\n            {\n                if (view.Version >= version)\n                {\n                    break;\n                }\n            }\n        }\n\n        return CurrentView;\n    }\n\n    async ValueTask<GrainDirectoryPartitionSnapshot?> IGrainDirectoryPartition.GetSnapshotAsync(MembershipVersion version, MembershipVersion rangeVersion, RingRange range)\n    {\n        LogTraceGetSnapshotAsync(_logger, version, rangeVersion, range);\n\n        // Wait for the range to be unlocked.\n        await WaitForRange(range, version);\n\n        ShutdownToken.ThrowIfCancellationRequested();\n        List<GrainAddress> partitionAddresses = [];\n        foreach (var partitionSnapshot in _partitionSnapshots)\n        {\n            if (partitionSnapshot.DirectoryMembershipVersion != rangeVersion)\n            {\n                continue;\n            }\n\n            // Only include addresses which are in the requested range.\n            foreach (var address in partitionSnapshot.GrainAddresses)\n            {\n                if (range.Contains(address.GrainId))\n                {\n                    partitionAddresses.Add(address);\n                }\n            }\n\n            var rangeSnapshot = new GrainDirectoryPartitionSnapshot(rangeVersion, partitionAddresses);\n            LogDebugTransferringEntries(_logger, partitionAddresses.Count, range, rangeVersion);\n\n            return rangeSnapshot;\n        }\n\n        LogWarningRequestForSnapshot(_logger, version, rangeVersion, range);\n        return null;\n    }\n\n    ValueTask<bool> IGrainDirectoryPartition.AcknowledgeSnapshotTransferAsync(SiloAddress silo, int partitionIndex, MembershipVersion rangeVersion)\n    {\n        RemoveSnapshotTransferPartner(\n            (silo, partitionIndex, rangeVersion),\n            snapshotFilter: (state, snapshot) => snapshot.DirectoryMembershipVersion == state.rangeVersion,\n            partnerFilter: (state, silo, partitionIndex) => silo.Equals(state.silo) && partitionIndex == state.partitionIndex);\n        return new(true);\n    }\n\n    private void RemoveSnapshotTransferPartner<TState>(TState state, Func<TState, PartitionSnapshotState, bool> snapshotFilter, Func<TState, SiloAddress, int, bool> partnerFilter)\n    {\n        for (var i = 0; i < _partitionSnapshots.Count; ++i)\n        {\n            var partitionSnapshot = _partitionSnapshots[i];\n            if (!snapshotFilter(state, partitionSnapshot))\n            {\n                continue;\n            }\n\n            var partners = partitionSnapshot.TransferPartners;\n            partners.RemoveWhere(p => partnerFilter(state, p.SiloAddress, p.PartitionIndex));\n            if (partners.Count == 0)\n            {\n                _partitionSnapshots.RemoveAt(i);\n                --i;\n\n                LogDebugRemovingSnapshot(_logger, partitionSnapshot.DirectoryMembershipVersion, string.Join(\", \", _partitionSnapshots.Select(s => s.DirectoryMembershipVersion)));\n\n                // If shutdown has been requested and there are no more pending snapshots, signal completion.\n                if (_drainSnapshotsCts.IsCancellationRequested && _partitionSnapshots.Count == 0)\n                {\n                    _snapshotsDrainedTcs.TrySetResult();\n                }\n            }\n        }\n    }\n\n    [Conditional(\"DEBUG\")]\n    private void DebugAssertOwnership(GrainId grainId) => DebugAssertOwnership(CurrentView, grainId);\n\n    [Conditional(\"DEBUG\")]\n    private void DebugAssertOwnership(DirectoryMembershipSnapshot view, GrainId grainId)\n    {\n        if (!view.TryGetOwner(grainId, out var owner, out var partitionReference))\n        {\n            Debug.Fail($\"Could not find owner for grain grain '{grainId}' in view '{view}'.\");\n        }\n\n        if (!_id.Equals(owner))\n        {\n            Debug.Fail($\"'{_id}' expected to be the owner of grain '{grainId}', but the owner is '{owner}'.\");\n        }\n\n        if (!GrainId.Equals(partitionReference.GetGrainId()))\n        {\n            Debug.Fail($\"'{GrainId}' expected to be the owner of grain '{grainId}', but the owner is '{partitionReference.GetGrainId()}'.\");\n        }\n    }\n\n    private bool IsOwner(DirectoryMembershipSnapshot view, GrainId grainId) => view.TryGetOwner(grainId, out _, out var partitionReference) && GrainId.Equals(partitionReference.GetGrainId());\n\n    private ValueTask WaitForRange(GrainId grainId, MembershipVersion version) => WaitForRange(RingRange.FromPoint(grainId.GetUniformHashCode()), version);\n\n    private ValueTask WaitForRange(RingRange range, MembershipVersion version)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        Task? completion = null;\n        if (CurrentView.Version < version || TryGetIntersectingLock(range, version, out completion))\n        {\n            return WaitForRangeCore(range, version, completion);\n        }\n\n        return ValueTask.CompletedTask;\n\n        bool TryGetIntersectingLock(RingRange range, MembershipVersion version, [NotNullWhen(true)] out Task? completion)\n        {\n            foreach (var rangeLock in _rangeLocks)\n            {\n                if (rangeLock.Version <= version && range.Intersects(rangeLock.Range))\n                {\n                    completion = rangeLock.Completion.Task;\n                    return true;\n                }\n            }\n\n            completion = null;\n            return false;\n        }\n\n        async ValueTask WaitForRangeCore(RingRange range, MembershipVersion version, Task? task)\n        {\n            if (task is not null)\n            {\n                await task;\n            }\n\n            if (CurrentView.Version < version)\n            {\n                await RefreshViewAsync(version, ShutdownToken);\n            }\n\n            while (TryGetIntersectingLock(range, version, out var completion))\n            {\n                await completion.WaitAsync(ShutdownToken);\n            }\n        }\n    }\n\n    public IGrainDirectoryPartition GetPartitionReference(SiloAddress address, int partitionIndex) => _grainFactory.GetSystemTarget<IGrainDirectoryPartition>(CreateGrainId(address, partitionIndex).GrainId);\n\n    internal async Task OnShuttingDown(CancellationToken token)\n    {\n        await this.RunOrQueueTask(async () =>\n        {\n            _drainSnapshotsCts.Cancel();\n            if (_partitionSnapshots.Count > 0)\n            {\n                await _snapshotsDrainedTcs.Task.WaitAsync(token).SuppressThrowing();\n            }\n        });\n    }\n    internal Task OnSiloRemovedFromClusterAsync(ClusterMember change) =>\n        this.QueueAction(\n            static state => state.Self.OnSiloRemovedFromCluster(state.Change),\n            (Self: this, Change: change),\n            nameof(OnSiloRemovedFromCluster));\n\n    private void OnSiloRemovedFromCluster(ClusterMember change)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        var toRemove = new List<GrainAddress>();\n        foreach (var entry in _directory)\n        {\n            if (change.SiloAddress.Equals(entry.Value.SiloAddress))\n            {\n                toRemove.Add(entry.Value);\n            }\n        }\n\n        if (toRemove.Count > 0)\n        {\n            LogDebugDeletingEntries(_logger, toRemove.Count, change.SiloAddress);\n\n            foreach (var grainAddress in toRemove)\n            {\n                DeregisterCore(grainAddress);\n            }\n        }\n\n        RemoveSnapshotTransferPartner(\n            change.SiloAddress,\n            snapshotFilter: (state, snapshot) => true,\n            partnerFilter: (state, silo, partitionIndex) => silo.Equals(state));\n    }\n\n    internal Task OnRecoveringPartition(MembershipVersion version, RingRange range, SiloAddress siloAddress, int partitionIndex) =>\n        this.QueueTask(\n            async () =>\n            {\n                try\n                {\n                    await WaitForRange(range, version);\n                }\n                catch (Exception exception)\n                {\n                    LogWarningErrorWaitingForRangeToUnlock(_logger, exception);\n                }\n\n                // Remove all snapshots that are associated with the given partition prior or equal to the specified version.\n                RemoveSnapshotTransferPartner(\n                    (Version: version, SiloAddress: siloAddress, PartitionIndex: partitionIndex),\n                    snapshotFilter: (state, snapshot) => snapshot.DirectoryMembershipVersion <= state.Version,\n                    partnerFilter: (state, silo, partitionIndex) => partitionIndex == state.PartitionIndex && silo.Equals(state.SiloAddress));\n            });\n\n    internal Task ProcessMembershipUpdateAsync(DirectoryMembershipSnapshot current) =>\n        this.QueueAction(\n            static state => state.Self.ProcessMembershipUpdate(state.Current),\n            (Self: this, Current: current),\n            nameof(ProcessMembershipUpdate));\n\n    private void ProcessMembershipUpdate(DirectoryMembershipSnapshot current)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n\n        _viewChangeTasks.RemoveAll(task => task.IsCompleted);\n\n        LogTraceObservedMembershipVersion(_logger, current.Version);\n\n        var previous = CurrentView;\n        CurrentView = current;\n\n        var previousRange = previous.GetRange(_id, _partitionIndex);\n        _currentRange = current.GetRange(_id, _partitionIndex);\n\n        var removedRange = previousRange.Difference(_currentRange).SingleOrDefault();\n        var addedRange = _currentRange.Difference(previousRange).SingleOrDefault();\n\n#if DEBUG\n        Debug.Assert(addedRange.IsEmpty ^ removedRange.IsEmpty || addedRange.IsEmpty && removedRange.IsEmpty); // Either the range grew or it shrank, but not both.\n        Debug.Assert(previousRange.Difference(_currentRange).Count() < 2);\n        Debug.Assert(_currentRange.Difference(previousRange).Count() < 2);\n        Debug.Assert(_currentRange.Size == previousRange.Size + addedRange.Size - removedRange.Size);\n        Debug.Assert(!removedRange.Intersects(addedRange));\n        Debug.Assert(!removedRange.Intersects(_currentRange));\n        Debug.Assert(removedRange.IsEmpty || removedRange.Intersects(previousRange));\n        Debug.Assert(!addedRange.Intersects(removedRange));\n        Debug.Assert(addedRange.IsEmpty || addedRange.Intersects(_currentRange));\n        Debug.Assert(!addedRange.Intersects(previousRange));\n        Debug.Assert(previousRange.IsEmpty || _currentRange.IsEmpty || previousRange.Start == _currentRange.Start);\n#endif\n\n        if (!removedRange.IsEmpty)\n        {\n            _viewChangeTasks.Add(ReleaseRangeAsync(previous, current, removedRange));\n        }\n\n        if (!addedRange.IsEmpty)\n        {\n            _viewChangeTasks.Add(AcquireRangeAsync(previous, current, addedRange));\n        }\n\n        _viewUpdates.Publish(current);\n    }\n\n    private async Task ReleaseRangeAsync(DirectoryMembershipSnapshot previous, DirectoryMembershipSnapshot current, RingRange removedRange)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        var (tcs, sw) = LockRange(removedRange, current.Version);\n        LogDebugRelinquishingOwnership(_logger, removedRange, current.Version);\n\n        try\n        {\n            // Snapshot & remove everything not in the current range.\n            // The new owner will have the opportunity to retrieve the snapshot as they take ownership.\n            List<GrainAddress> removedAddresses = [];\n            HashSet<(SiloAddress, int)> transferPartners = [];\n\n            // Wait for the range being removed to become valid.\n            await WaitForRange(removedRange, previous.Version);\n\n            GrainRuntime.CheckRuntimeContext(this);\n\n            foreach (var (range, ownerIndex, partitionIndex) in current.RangeOwners)\n            {\n                if (range.Intersects(removedRange))\n                {\n                    var owner = current.Members[ownerIndex];\n                    Debug.Assert(!_id.Equals(owner));\n                    transferPartners.Add((owner, partitionIndex));\n                }\n            }\n\n            // Collect all addresses that are not in the owned range.\n            foreach (var entry in _directory)\n            {\n                if (removedRange.Contains(entry.Key))\n                {\n                    removedAddresses.Add(entry.Value);\n                }\n            }\n\n            // Remove these addresses from the partition.\n            foreach (var address in removedAddresses)\n            {\n                if (transferPartners.Count > 0)\n                {\n                    LogTraceEvictingEntry(_logger, address);\n                }\n\n                _directory.Remove(address.GrainId);\n            }\n\n            var isContiguous = current.Version.Value == previous.Version.Value + 1;\n            if (!isContiguous)\n            {\n                LogDebugEncounteredNonContiguousUpdate(_logger, previous.Version, current.Version, removedRange);\n                return;\n            }\n\n            if (transferPartners.Count == 0)\n            {\n                LogDebugNoTransferPartners(_logger, removedRange, current.Version);\n                return;\n            }\n\n            _partitionSnapshots.Add(new PartitionSnapshotState(previous.Version, removedAddresses, transferPartners));\n        }\n        finally\n        {\n            UnlockRange(removedRange, current.Version, tcs, sw.Elapsed, \"release\");\n        }\n    }\n\n    private async Task AcquireRangeAsync(DirectoryMembershipSnapshot previous, DirectoryMembershipSnapshot current, RingRange addedRange)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        // Suspend the range and transfer state from the previous owners.\n        // If the predecessor becomes unavailable or membership advances quickly, we will declare data loss and unlock the range.\n        var (tcs, sw) = LockRange(addedRange, current.Version);\n\n        try\n        {\n            CoarseStopwatch stopwatch = default;\n            LogDebugAcquiringRange(_logger, addedRange);\n            stopwatch = CoarseStopwatch.StartNew();\n\n            // The view change is contiguous if the new version is exactly one greater than the previous version.\n            // If not, we have missed some updates, so we must declare a potential data loss event.\n            var isContiguous = current.Version.Value == previous.Version.Value + 1;\n            bool success;\n            if (isContiguous)\n            {\n                // Transfer subranges from previous owners.\n                var tasks = new List<Task<bool>>();\n                foreach (var previousOwner in previous.Members)\n                {\n                    var previousOwnerRanges = previous.GetMemberRangesByPartition(previousOwner);\n                    for (var partitionIndex = 0; partitionIndex < previousOwnerRanges.Length; partitionIndex++)\n                    {\n                        var previousOwnerRange = previousOwnerRanges[partitionIndex];\n                        if (previousOwnerRange.Intersects(addedRange))\n                        {\n                            tasks.Add(TransferSnapshotAsync(current, addedRange, previousOwner, partitionIndex, previous.Version));\n                        }\n                    }\n                }\n\n                // Note: there should be no 'await' points before this point.\n                // An await before this point would result in ranges not being locked synchronously.\n                await Task.WhenAll(tasks).WaitAsync(ShutdownToken).SuppressThrowing();\n                if (ShutdownToken.IsCancellationRequested)\n                {\n                    return;\n                }\n\n                success = tasks.All(t => t.Result);\n            }\n            else\n            {\n                LogDebugNonContiguousViewChange(_logger, previous.Version, current.Version);\n                success = false;\n            }\n\n            var recovered = false;\n            if (!success)\n            {\n                // Wait for previous versions to be unlocked before proceeding.\n                await WaitForRange(addedRange, previous.Version);\n\n                await RecoverPartitionRange(current, addedRange);\n                recovered = true;\n            }\n\n            LogDebugCompletedTransferringEntries(_logger, addedRange, current.Version, stopwatch.ElapsedMilliseconds, recovered);\n        }\n        finally\n        {\n            UnlockRange(addedRange, current.Version, tcs, sw.Elapsed, \"acquire\");\n        }\n    }\n\n    private (TaskCompletionSource Lock, ValueStopwatch Stopwatch) LockRange(RingRange range, MembershipVersion version)\n    {\n        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        _rangeLocks.Add((range, version, tcs));\n        return (tcs, ValueStopwatch.StartNew());\n    }\n\n    private void UnlockRange(RingRange range, MembershipVersion version, TaskCompletionSource tcs, TimeSpan heldDuration, string operationName)\n    {\n        DirectoryInstruments.RangeLockHeldDuration.Record((long)heldDuration.TotalMilliseconds);\n        if (ShutdownToken.IsCancellationRequested)\n        {\n            // If the partition is stopped, the range is never unlocked and the task is cancelled instead.\n            tcs.SetCanceled(ShutdownToken);\n        }\n        else\n        {\n            tcs.SetResult();\n            _rangeLocks.Remove((range, version, tcs));\n        }\n    }\n\n    private async Task<bool> TransferSnapshotAsync(DirectoryMembershipSnapshot current, RingRange addedRange, SiloAddress previousOwner, int partitionIndex, MembershipVersion previousVersion)\n    {\n        try\n        {\n            var stopwatch = ValueStopwatch.StartNew();\n            LogTraceRequestingEntries(_logger, addedRange, previousOwner, previousVersion);\n\n            var partition = GetPartitionReference(previousOwner, partitionIndex);\n\n            // Alternatively, the previous owner could push the snapshot. The pull-based approach is used here because it is simpler.\n            var snapshot = await partition.GetSnapshotAsync(current.Version, previousVersion, addedRange).AsTask().WaitAsync(ShutdownToken);\n\n            if (snapshot is null)\n            {\n                LogWarningExpectedValidSnapshot(_logger, previousOwner, addedRange);\n                return false;\n            }\n\n            // The acknowledgement step lets the previous owner know that the snapshot has been received so that it can proceed.\n            InvokeOnClusterMember(\n                previousOwner,\n                async () => await partition.AcknowledgeSnapshotTransferAsync(_id, _partitionIndex, previousVersion),\n                false,\n                nameof(IGrainDirectoryPartition.AcknowledgeSnapshotTransferAsync)).Ignore();\n\n            // Wait for previous versions to be unlocked before proceeding.\n            await WaitForRange(addedRange, previousVersion);\n\n            // Incorporate the values into the grain directory.\n            foreach (var entry in snapshot.GrainAddresses)\n            {\n                DebugAssertOwnership(current, entry.GrainId);\n\n                LogTraceReceivedEntry(_logger, entry, previousOwner, previousVersion);\n                _directory[entry.GrainId] = entry;\n            }\n\n            LogDebugTransferredEntries(_logger, snapshot.GrainAddresses.Count, addedRange, previousOwner);\n\n            DirectoryInstruments.SnapshotTransferCount.Add(1);\n            DirectoryInstruments.SnapshotTransferDuration.Record((long)stopwatch.Elapsed.TotalMilliseconds);\n\n            return true;\n        }\n        catch (Exception exception)\n        {\n            if (exception is SiloUnavailableException)\n            {\n                LogWarningRemoteHostUnavailable(_logger, addedRange);\n            }\n            else\n            {\n                LogWarningErrorTransferringOwnership(_logger, exception, addedRange);\n            }\n\n            return false;\n        }\n    }\n\n    private async Task RecoverPartitionRange(DirectoryMembershipSnapshot current, RingRange addedRange)\n    {\n        var stopwatch = ValueStopwatch.StartNew();\n        GrainRuntime.CheckRuntimeContext(this);\n        LogDebugRecoveringActivations(_logger, addedRange, current.Version);\n\n        await foreach (var activations in GetRegisteredActivations(current, addedRange, isValidation: false))\n        {\n            GrainRuntime.CheckRuntimeContext(this);\n            foreach (var entry in activations)\n            {\n                DebugAssertOwnership(current, entry.GrainId);\n                LogTraceRecoveredEntry(_logger, entry, current.Version);\n                _directory[entry.GrainId] = entry;\n            }\n        }\n\n        DirectoryInstruments.RangeRecoveryCount.Add(1);\n        DirectoryInstruments.RangeRecoveryDuration.Record((long)stopwatch.Elapsed.TotalMilliseconds);\n        LogDebugCompletedRecoveringActivations(_logger, addedRange, current.Version, stopwatch.Elapsed);\n    }\n\n    private async IAsyncEnumerable<List<GrainAddress>> GetRegisteredActivations(DirectoryMembershipSnapshot current, RingRange range, bool isValidation)\n    {\n        // Membership is guaranteed to be at least as recent as the current view.\n        var clusterMembershipSnapshot = _owner.ClusterMembershipSnapshot;\n        Debug.Assert(clusterMembershipSnapshot.Version >= current.Version);\n\n        var tasks = new List<Task<List<GrainAddress>>>();\n        foreach (var member in clusterMembershipSnapshot.Members.Values)\n        {\n            if (member.Status is not (SiloStatus.Active or SiloStatus.Joining or SiloStatus.ShuttingDown))\n            {\n                continue;\n            }\n\n            tasks.Add(GetRegisteredActivationsFromClusterMember(current.Version, range, member.SiloAddress, isValidation));\n        }\n\n        await Task.WhenAll(tasks).WaitAsync(ShutdownToken).SuppressThrowing();\n        if (ShutdownToken.IsCancellationRequested)\n        {\n            yield break;\n        }\n\n        foreach (var task in tasks)\n        {\n            yield return await task;\n        }\n\n        async Task<List<GrainAddress>> GetRegisteredActivationsFromClusterMember(MembershipVersion version, RingRange range, SiloAddress siloAddress, bool isValidation)\n        {\n            var stopwatch = ValueStopwatch.StartNew();\n            var client = _grainFactory.GetSystemTarget<IGrainDirectoryClient>(Constants.GrainDirectoryType, siloAddress);\n            var result = await InvokeOnClusterMember(\n                siloAddress,\n                async () =>\n                {\n                    var innerSw = ValueStopwatch.StartNew();\n                    Immutable<List<GrainAddress>> result = default;\n                        if (isValidation)\n                        {\n                            result = await client.GetRegisteredActivations(version, range, isValidation: true);\n                        }\n                        else\n                        {\n                            result = await client.RecoverRegisteredActivations(version, range, _id, _partitionIndex);\n                        }\n\n                    return result;\n                },\n                new Immutable<List<GrainAddress>>([]),\n                nameof(GetRegisteredActivations));\n\n            LogDebugRecoveredEntries(_logger, result.Value.Count, siloAddress, range, version, stopwatch.Elapsed.TotalMilliseconds);\n\n            return result.Value;\n        }\n    }\n\n    private async Task<T> InvokeOnClusterMember<T>(SiloAddress siloAddress, Func<Task<T>> func, T defaultValue, string operationName)\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        var clusterMembershipSnapshot = _owner.ClusterMembershipSnapshot;\n        while (!ShutdownToken.IsCancellationRequested)\n        {\n            if (clusterMembershipSnapshot.GetSiloStatus(siloAddress) is not (SiloStatus.Active or SiloStatus.Joining or SiloStatus.ShuttingDown))\n            {\n                break;\n            }\n\n            try\n            {\n                return await func();\n            }\n            catch (Exception ex)\n            {\n                if (ex is not OrleansMessageRejectionException)\n                {\n                    LogErrorErrorInvokingOperation(_logger, ex, operationName, siloAddress);\n                }\n\n                await _owner.RefreshViewAsync(default, CancellationToken.None);\n                if (_owner.ClusterMembershipSnapshot.Version == clusterMembershipSnapshot.Version)\n                {\n                    await Task.Delay(TimeSpan.FromMilliseconds(100));\n                }\n\n                clusterMembershipSnapshot = _owner.ClusterMembershipSnapshot;\n            }\n        }\n\n        ShutdownToken.ThrowIfCancellationRequested();\n        return defaultValue;\n    }\n\n    async ValueTask IGrainDirectoryTestHooks.CheckIntegrityAsync()\n    {\n        GrainRuntime.CheckRuntimeContext(this);\n        var current = CurrentView;\n        var range = _currentRange;\n        Debug.Assert(range.Equals(current.GetRange(_id, _partitionIndex)));\n\n        await WaitForRange(RingRange.Full, current.Version);\n        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        _rangeLocks.Add((RingRange.Full, current.Version, tcs));\n        try\n        {\n            foreach (var entry in _directory)\n            {\n                if (!range.Contains(entry.Key))\n                {\n                    Debug.Fail($\"Invariant violated. This host is not the owner of grain '{entry.Key}'.\");\n                }\n\n                DebugAssertOwnership(current, entry.Key);\n            }\n\n            var missing = 0;\n            var mismatched = 0;\n            var total = 0;\n            await foreach (var activationList in GetRegisteredActivations(current, range, isValidation: true))\n            {\n                total += activationList.Count;\n                foreach (var entry in activationList)\n                {\n                    if (!IsOwner(current, entry.GrainId))\n                    {\n                        // The view has been refreshed since the request for registered activations was made.\n                        if (current.Version <= current.Version)\n                        {\n                            Debug.Fail(\"Invariant violated. This host was sent a registration which it should not have been.\");\n                        }\n\n                        continue;\n                    }\n\n                    if (_directory.TryGetValue(entry.GrainId, out var existingEntry))\n                    {\n                        if (!existingEntry.Equals(entry))\n                        {\n                            ++mismatched;\n                            LogErrorIntegrityViolation(_logger, entry, existingEntry);\n                            Debug.Fail($\"Integrity violation: Recovered entry '{entry}' does not match existing entry '{existingEntry}'.\");\n                        }\n                    }\n                    else\n                    {\n                        ++missing;\n                        LogErrorIntegrityViolation(_logger, entry);\n                        Debug.Fail($\"Integrity violation: Recovered entry '{entry}' not found in directory.\");\n                    }\n                }\n            }\n        }\n        finally\n        {\n            if (ShutdownToken.IsCancellationRequested)\n            {\n                tcs.SetCanceled(ShutdownToken);\n            }\n            else\n            {\n                tcs.SetResult();\n            }\n\n            _rangeLocks.Remove((RingRange.Full, current.Version, tcs));\n        }\n    }\n\n    private sealed record class PartitionSnapshotState(\n        MembershipVersion DirectoryMembershipVersion,\n        List<GrainAddress> GrainAddresses,\n        HashSet<(SiloAddress SiloAddress, int PartitionIndex)> TransferPartners);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"GetSnapshotAsync('{Version}', '{RangeVersion}', '{Range}')\"\n    )]\n    private static partial void LogTraceGetSnapshotAsync(ILogger logger, MembershipVersion version, MembershipVersion rangeVersion, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Transferring '{Count}' entries in range '{Range}' from version '{Version}' snapshot.\"\n    )]\n    private static partial void LogDebugTransferringEntries(ILogger logger, int count, RingRange range, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Received a request for a snapshot which this partition does not have, version '{Version}', range version '{RangeVersion}', range '{Range}'.\"\n    )]\n    private static partial void LogWarningRequestForSnapshot(ILogger logger, MembershipVersion version, MembershipVersion rangeVersion, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Removing version '{Version}' snapshot. Current snapshots: [{CurrentSnapshots}].\"\n    )]\n    private static partial void LogDebugRemovingSnapshot(ILogger logger, MembershipVersion version, string currentSnapshots);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Deleting '{Count}' entries located on now-defunct silo '{SiloAddress}'.\"\n    )]\n    private static partial void LogDebugDeletingEntries(ILogger logger, int count, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error waiting for range to unlock.\"\n    )]\n    private static partial void LogWarningErrorWaitingForRangeToUnlock(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Observed membership version '{Version}'.\"\n    )]\n    private static partial void LogTraceObservedMembershipVersion(ILogger logger, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Relinquishing ownership of range '{Range}' at version '{Version}'.\"\n    )]\n    private static partial void LogDebugRelinquishingOwnership(ILogger logger, RingRange range, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Evicting entry '{Address}' to snapshot.\"\n    )]\n    private static partial void LogTraceEvictingEntry(ILogger logger, GrainAddress address);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Encountered non-contiguous update from '{Previous}' to '{Current}' while releasing range '{Range}'. Dropping snapshot.\"\n    )]\n    private static partial void LogDebugEncounteredNonContiguousUpdate(ILogger logger, MembershipVersion previous, MembershipVersion current, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"No transfer partners for snapshot of range '{Range}' at version '{Version}'. Dropping snapshot.\"\n    )]\n    private static partial void LogDebugNoTransferPartners(ILogger logger, RingRange range, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Acquiring range '{Range}'.\"\n    )]\n    private static partial void LogDebugAcquiringRange(ILogger logger, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Non-contiguous view change detected: '{PreviousVersion}' to '{CurrentVersion}'. Performing recovery.\"\n    )]\n    private static partial void LogDebugNonContiguousViewChange(ILogger logger, MembershipVersion previousVersion, MembershipVersion currentVersion);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Completed transferring entries for range '{Range}' at version '{Version}' took {Elapsed}ms.{Recovered}\"\n    )]\n    private static partial void LogDebugCompletedTransferringEntries(ILogger logger, RingRange range, MembershipVersion version, long elapsed, bool recovered);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Requesting entries for ranges '{Range}' from '{PreviousOwner}' at version '{PreviousVersion}'.\"\n    )]\n    private static partial void LogTraceRequestingEntries(ILogger logger, RingRange range, SiloAddress previousOwner, MembershipVersion previousVersion);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Expected a valid snapshot from previous owner '{PreviousOwner}' for part of ranges '{Range}', but found none.\"\n    )]\n    private static partial void LogWarningExpectedValidSnapshot(ILogger logger, SiloAddress previousOwner, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Received '{Entry}' via snapshot from '{PreviousOwner}' for version '{Version}'.\"\n    )]\n    private static partial void LogTraceReceivedEntry(ILogger logger, GrainAddress entry, SiloAddress previousOwner, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Transferred '{Count}' entries for range '{Range}' from '{PreviousOwner}'.\"\n    )]\n    private static partial void LogDebugTransferredEntries(ILogger logger, int count, RingRange range, SiloAddress previousOwner);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Remote host became unavailable while transferring ownership of range '{Range}'. Recovery will be performed.\"\n    )]\n    private static partial void LogWarningRemoteHostUnavailable(ILogger logger, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Error transferring ownership of range '{Range}'. Recovery will be performed.\"\n    )]\n    private static partial void LogWarningErrorTransferringOwnership(ILogger logger, Exception exception, RingRange range);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Recovering activations from range '{Range}' at version '{Version}'.\"\n    )]\n    private static partial void LogDebugRecoveringActivations(ILogger logger, RingRange range, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"Recovered '{Entry}' for version '{Version}'.\"\n    )]\n    private static partial void LogTraceRecoveredEntry(ILogger logger, GrainAddress entry, MembershipVersion version);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Completed recovering activations from range '{Range}' at version '{Version}' took '{Elapsed}'.\"\n    )]\n    private static partial void LogDebugCompletedRecoveringActivations(ILogger logger, RingRange range, MembershipVersion version, TimeSpan elapsed);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Recovered '{Count}' entries from silo '{SiloAddress}' for ranges '{Range}' at version '{Version}' in {ElapsedMilliseconds}ms.\"\n    )]\n    private static partial void LogDebugRecoveredEntries(ILogger logger, int count, SiloAddress siloAddress, RingRange range, MembershipVersion version, double elapsedMilliseconds);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error invoking operation '{Operation}' on silo '{SiloAddress}'.\"\n    )]\n    private static partial void LogErrorErrorInvokingOperation(ILogger logger, Exception exception, string operation, SiloAddress siloAddress);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Integrity violation: Recovered entry '{RecoveredRecord}' does not match existing entry '{LocalRecord}'.\"\n    )]\n    private static partial void LogErrorIntegrityViolation(ILogger logger, GrainAddress recoveredRecord, GrainAddress localRecord);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Integrity violation: Recovered entry '{RecoveredRecord}' not found in directory.\"\n    )]\n    private static partial void LogErrorIntegrityViolation(ILogger logger, GrainAddress recoveredRecord);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryPartitionSnapshot.cs",
    "content": "using System.Collections.Generic;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n[GenerateSerializer, Alias(nameof(GrainDirectoryPartitionSnapshot)), Immutable]\ninternal sealed class GrainDirectoryPartitionSnapshot(\n    MembershipVersion directoryMembershipVersion,\n    List<GrainAddress> grainAddresses)\n{\n    [Id(0)]\n    public MembershipVersion DirectoryMembershipVersion { get; } = directoryMembershipVersion;\n\n    [Id(1)]\n    public List<GrainAddress> GrainAddresses { get; } = grainAddresses;\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainDirectoryResolver.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.GrainDirectory;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Hosting;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal class GrainDirectoryResolver\n    {\n        private readonly Dictionary<string, IGrainDirectory> directoryPerName = new Dictionary<string, IGrainDirectory>();\n        private readonly ConcurrentDictionary<GrainType, IGrainDirectory> directoryPerType = new();\n        private readonly GrainPropertiesResolver grainPropertiesResolver;\n        private readonly IGrainDirectoryResolver[] resolvers;\n        private readonly Func<GrainType, IGrainDirectory> getGrainDirectoryInternal;\n\n        public GrainDirectoryResolver(\n            IServiceProvider serviceProvider,\n            GrainPropertiesResolver grainPropertiesResolver,\n            IEnumerable<IGrainDirectoryResolver> resolvers)\n        {\n            this.getGrainDirectoryInternal = GetGrainDirectoryPerType;\n            this.resolvers = resolvers.ToArray();\n\n            // Load all registered directories\n            var services = serviceProvider.GetGrainDirectories();\n            foreach (var svc in services)\n            {\n                this.directoryPerName[svc.Name] = serviceProvider.GetRequiredKeyedService<IGrainDirectory>(svc.Name);\n            }\n\n            this.directoryPerName.TryGetValue(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, out var defaultDirectory);\n            this.DefaultGrainDirectory = defaultDirectory;\n            this.grainPropertiesResolver = grainPropertiesResolver;\n        }\n\n        public IReadOnlyCollection<IGrainDirectory> Directories => this.directoryPerName.Values;\n\n        public IGrainDirectory DefaultGrainDirectory { get; }\n\n        public IGrainDirectory Resolve(GrainType grainType) => this.directoryPerType.GetOrAdd(grainType, this.getGrainDirectoryInternal);\n\n        public bool IsUsingDefaultDirectory(GrainType grainType) => Resolve(grainType) == null;\n\n        private IGrainDirectory GetGrainDirectoryPerType(GrainType grainType)\n        {\n            if (this.TryGetNonDefaultGrainDirectory(grainType, out var result))\n            {\n                return result;\n            }\n\n            return this.DefaultGrainDirectory;\n        }\n\n        internal bool TryGetNonDefaultGrainDirectory(GrainType grainType, out IGrainDirectory directory)\n        {\n            this.grainPropertiesResolver.TryGetGrainProperties(grainType, out var properties);\n\n            foreach (var resolver in this.resolvers)\n            {\n                if (resolver.TryResolveGrainDirectory(grainType, properties, out directory))\n                {\n                    return true;\n                }\n            }\n\n            if (properties is not null\n                && properties.Properties.TryGetValue(WellKnownGrainTypeProperties.GrainDirectory, out var directoryName)\n                && !string.IsNullOrWhiteSpace(directoryName))\n            {\n                if (this.directoryPerName.TryGetValue(directoryName, out directory))\n                {\n                    return true;\n                }\n                else\n                {\n                    throw new KeyNotFoundException($\"Could not resolve grain directory {directoryName} for grain type {grainType}\");\n                }\n            }\n\n            directory = null;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainLocator.cs",
    "content": "#nullable enable\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Provides functionality for locating grain activations in a cluster and registering the location of grain activations.\n    /// </summary>\n    internal class GrainLocator\n    {\n        private readonly GrainLocatorResolver _grainLocatorResolver;\n\n        public GrainLocator(GrainLocatorResolver grainLocatorResolver)\n        {\n            _grainLocatorResolver = grainLocatorResolver;\n        }\n\n        public ValueTask<GrainAddress?> Lookup(GrainId grainId) => GetGrainLocator(grainId.Type).Lookup(grainId);\n\n        public Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousRegistration) => GetGrainLocator(address.GrainId.Type).Register(address, previousRegistration);\n\n        public Task Unregister(GrainAddress address, UnregistrationCause cause) => GetGrainLocator(address.GrainId.Type).Unregister(address, cause);\n\n        public bool TryLookupInCache(GrainId grainId, [NotNullWhen(true)] out GrainAddress? address) => GetGrainLocator(grainId.Type).TryLookupInCache(grainId, out address);\n\n        public void InvalidateCache(GrainId grainId) => GetGrainLocator(grainId.Type).InvalidateCache(grainId);\n\n        public void InvalidateCache(GrainAddress address) => GetGrainLocator(address.GrainId.Type).InvalidateCache(address);\n\n        private IGrainLocator GetGrainLocator(GrainType grainType) => _grainLocatorResolver.GetGrainLocator(grainType);\n\n        public void UpdateCache(GrainId grainId, SiloAddress siloAddress) => GetGrainLocator(grainId.Type).UpdateCache(grainId, siloAddress);\n\n        public void UpdateCache(GrainAddressCacheUpdate update)\n        {\n            if (update.ValidGrainAddress is { } validAddress)\n            {\n                Debug.Assert(validAddress.SiloAddress is not null);\n                UpdateCache(validAddress.GrainId, validAddress.SiloAddress);\n            }\n            else\n            {\n                InvalidateCache(update.InvalidGrainAddress);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/GrainLocatorResolver.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal class GrainLocatorResolver\n    {\n        private readonly ConcurrentDictionary<GrainType, IGrainLocator> resolvedLocators = new();\n        private readonly Func<GrainType, IGrainLocator> getLocatorInternal;\n        private readonly IServiceProvider _servicesProvider;\n        private readonly GrainDirectoryResolver grainDirectoryResolver;\n        private readonly CachedGrainLocator cachedGrainLocator;\n        private readonly DhtGrainLocator dhtGrainLocator;\n        private ClientGrainLocator _clientGrainLocator;\n\n        public GrainLocatorResolver(\n            IServiceProvider servicesProvider,\n            GrainDirectoryResolver grainDirectoryResolver,\n            CachedGrainLocator cachedGrainLocator,\n            DhtGrainLocator dhtGrainLocator)\n        {\n            this.getLocatorInternal = GetGrainLocatorInternal;\n            _servicesProvider = servicesProvider;\n            this.grainDirectoryResolver = grainDirectoryResolver;\n            this.cachedGrainLocator = cachedGrainLocator;\n            this.dhtGrainLocator = dhtGrainLocator;\n        }\n\n        public IGrainLocator GetGrainLocator(GrainType grainType) => resolvedLocators.GetOrAdd(grainType, this.getLocatorInternal);\n\n        public IGrainLocator GetGrainLocatorInternal(GrainType grainType)\n        {\n            IGrainLocator result;\n            if (grainType.IsClient())\n            {\n                result = this._clientGrainLocator ??= _servicesProvider.GetRequiredService<ClientGrainLocator>();\n            }\n            else if (this.grainDirectoryResolver.IsUsingDefaultDirectory(grainType))\n            {\n                result = this.dhtGrainLocator;\n            }\n            else\n            {\n                result = this.cachedGrainLocator;\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/IGrainDirectoryCache.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Caches grain directory entries.\n    /// </summary>\n    public interface IGrainDirectoryCache\n    {\n        /// <summary>\n        /// Adds a new entry with the given version into the cache: key (grain) --> value\n        /// The new entry will override any existing entry under the given key, \n        /// regardless of the stored version\n        /// </summary>\n        /// <param name=\"value\">value to add</param>\n        /// <param name=\"version\">version for the value</param>\n        void AddOrUpdate(GrainAddress value, int version);\n\n        /// <summary>\n        /// Removes an entry from the cache given its key\n        /// </summary>\n        /// <param name=\"key\">key to remove</param>\n        /// <returns>True if the entry was in the cache and the removal was successful</returns>\n        bool Remove(GrainId key);\n\n        /// <summary>\n        /// Removes an entry from the cache given its key\n        /// </summary>\n        /// <param name=\"key\">key to remove</param>\n        /// <returns>True if the entry was in the cache and the removal was successful</returns>\n        bool Remove(GrainAddress key);\n        \n        /// <summary>\n        /// Clear the cache, deleting all entries.\n        /// </summary>\n        void Clear();\n\n        /// <summary>\n        /// Looks up the cached value and version by the given key\n        /// </summary>\n        /// <param name=\"key\">key for the lookup</param>\n        /// <param name=\"result\">value if the key is found, undefined otherwise</param>\n        /// <param name=\"version\">version of cached value if the key is found, undefined otherwise</param>\n        /// <returns>true if the given key is in the cache</returns>\n        bool LookUp(GrainId key, out GrainAddress result, out int version);\n\n        /// <summary>\n        /// Returns list of key-value-version tuples stored currently in the cache.\n        /// </summary>\n        IEnumerable<(GrainAddress ActivationAddress, int Version)> KeyValues { get; }\n    }\n\n    internal static class GrainDirectoryCacheExtensions\n    {\n        /// <summary>\n        /// Looks up the cached value by the given key.\n        /// </summary>\n        /// <param name=\"cache\">grain directory cache to look up results from</param>\n        /// <param name=\"key\">key for the lookup</param>\n        /// <param name=\"result\">value if the key is found, undefined otherwise</param>\n        /// <returns>true if the given key is in the cache</returns>\n        public static bool LookUp(this IGrainDirectoryCache cache, GrainId key, out GrainAddress result)\n        {\n            return cache.LookUp(key, out result, out _);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/IGrainDirectoryPartition.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n[Alias(\"IGrainDirectoryPartition\")]\ninternal interface IGrainDirectoryPartition : ISystemTarget\n{\n    [Alias(\"RegisterAsync\")]\n    ValueTask<DirectoryResult<GrainAddress>> RegisterAsync(MembershipVersion version, GrainAddress address, GrainAddress? currentRegistration);\n\n    [Alias(\"LookupAsync\")]\n    ValueTask<DirectoryResult<GrainAddress?>> LookupAsync(MembershipVersion version, GrainId grainId);\n\n    [Alias(\"DeregisterAsync\")]\n    ValueTask<DirectoryResult<bool>> DeregisterAsync(MembershipVersion version, GrainAddress address);\n\n    [Alias(\"GetSnapshotAsync\")]\n    ValueTask<GrainDirectoryPartitionSnapshot?> GetSnapshotAsync(MembershipVersion version, MembershipVersion rangeVersion, RingRange range);\n\n    [Alias(\"AcknowledgeSnapshotTransferAsync\")]\n    ValueTask<bool> AcknowledgeSnapshotTransferAsync(SiloAddress silo, int partitionIndex, MembershipVersion version);\n}\n\n[Alias(\"IGrainDirectoryClient\")]\ninternal interface IGrainDirectoryClient : ISystemTarget\n{\n    [Alias(\"GetRegisteredActivations\")]\n    ValueTask<Immutable<List<GrainAddress>>> GetRegisteredActivations(MembershipVersion membershipVersion, RingRange range, bool isValidation);\n\n    [Alias(\"RecoverRegisteredActivations\")]\n    ValueTask<Immutable<List<GrainAddress>>> RecoverRegisteredActivations(MembershipVersion membershipVersion, RingRange range, SiloAddress siloAddress, int partitionId);\n}\n\n[Alias(\"IGrainDirectoryTestHooks\")]\ninternal interface IGrainDirectoryTestHooks : ISystemTarget\n{\n    [Alias(\"CheckIntegrityAsync\")]\n    ValueTask CheckIntegrityAsync();\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/IGrainDirectoryResolver.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing Orleans.GrainDirectory;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    /// <summary>\n    /// Associates an <see cref=\"IGrainDirectory\"/> instance with a <see cref=\"GrainType\"/>.\n    /// </summary>\n    public interface IGrainDirectoryResolver\n    {\n        /// <summary>\n        /// Gets an <see cref=\"IGrainDirectory\" /> instance for the provided <see cref=\"GrainType\" />.\n        /// </summary>\n        /// <param name=\"grainType\">Type of the grain.</param>\n        /// <param name=\"properties\">The properties.</param>\n        /// <param name=\"grainDirectory\">The grain directory.</param>\n        /// <returns>true if an appropriate grain directory was found, <see langword=\"false\"/> otherwise.</returns>\n        bool TryResolveGrainDirectory(GrainType grainType, GrainProperties properties, [NotNullWhen(true)] out IGrainDirectory grainDirectory);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/ILocalClientDirectory.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal interface ILocalClientDirectory\n    {\n        bool TryLocalLookup(GrainId grainId, out List<GrainAddress> addresses);\n        ValueTask<List<GrainAddress>> Lookup(GrainId grainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/ILocalGrainDirectory.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal interface ILocalGrainDirectory : IDhtGrainDirectory\n    {\n        /// <summary>\n        /// Starts the local portion of the directory service.\n        /// </summary>\n        void Start();\n\n        /// <summary>\n        /// Stops the local portion of the directory service.\n        /// </summary>\n        Task StopAsync();\n\n        RemoteGrainDirectory RemoteGrainDirectory { get; }\n        RemoteGrainDirectory CacheValidator { get; }\n\n        /// <summary>\n        /// Removes the record for an non-existing activation from the directory service.\n        /// This is used when a request is received for an activation that cannot be found, \n        /// to lazily clean up the remote directory.\n        /// The timestamp is used to prevent removing a valid entry in a possible (but unlikely)\n        /// race where a request is received for a new activation before the request that causes the\n        /// new activation to be created.\n        /// Note that this method is a no-op if the global configuration parameter DirectoryLazyDeregistrationDelay\n        /// is a zero or negative TimeSpan.\n        /// <para>This method must be called from a scheduler thread.</para>\n        /// </summary>\n        /// <param name=\"address\">The address of the activation to remove.</param>\n        /// <param name=\"origin\"> the silo from which the message to the non-existing activation was sent</param>\n        Task UnregisterAfterNonexistingActivation(GrainAddress address, SiloAddress origin);\n\n        /// <summary>\n        /// Fetches locally known directory information for a grain.\n        /// If there is no local information, either in the cache or in this node's directory partition,\n        /// then this method will return false and leave the list empty.\n        /// </summary>\n        /// <param name=\"grain\">The ID of the grain to look up.</param>\n        /// <param name=\"addresses\">An output parameter that receives the list of locally-known activations of the grain.</param>\n        /// <returns>True if remote addresses are complete within freshness constraint</returns>\n        bool LocalLookup(GrainId grain, out AddressAndTag addresses);\n\n        /// <summary>\n        /// Invalidates cache entry for the given activation address.\n        /// This method is intended to be called whenever a directory client tries to access \n        /// an activation returned from the previous directory lookup and gets a reject from the target silo \n        /// notifying him that the activation does not exist.\n        /// </summary>\n        /// <param name=\"activation\">The address of the activation that needs to be invalidated in the directory cache for the given grain.</param>\n        void InvalidateCacheEntry(GrainAddress activation);\n\n        /// <summary>\n        /// Invalidates cache entry for the given grain.\n        /// </summary>\n        void InvalidateCacheEntry(GrainId grainId);\n\n        /// <summary>\n        /// Adds or updates a cache entry for the given activation address.\n        /// This method is intended to be called whenever a placement decision is made.\n        /// </summary>\n        void AddOrUpdateCacheEntry(GrainId grainId, SiloAddress siloAddress);\n\n        /// <summary>\n        /// For testing purposes only.\n        /// Returns the silo that this silo thinks is the primary owner of directory information for\n        /// the provided grain ID.\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        /// <returns></returns>\n        SiloAddress? GetPrimaryForGrain(GrainId grain);\n\n        /// <summary>\n        /// Returns the directory information held in a local directory partition for the provided grain ID.\n        /// The result will be null if no information is held.\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        /// <returns></returns>\n        AddressAndTag GetLocalDirectoryData(GrainId grain);\n\n        /// <summary>\n        /// For testing and troubleshooting purposes only.\n        /// Returns the directory information held in a local directory cache for the provided grain ID.\n        /// The result will be null if no information is held.\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        /// <returns></returns>\n        GrainAddress? GetLocalCacheData(GrainId grain);\n\n        /// <summary>\n        /// Attempts to find the specified grain in the directory cache.\n        /// </summary>\n        bool TryCachedLookup(GrainId grainId, [NotNullWhen(true)] out GrainAddress? address);\n\n        /// <summary>\n        /// For determining message forwarding logic, we sometimes check if a silo is part of this cluster or not\n        /// </summary>\n        /// <param name=\"silo\">the address of the silo</param>\n        /// <returns>true if the silo is known to be part of this cluster</returns>\n        bool IsSiloInCluster(SiloAddress silo);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/IRemoteClientDirectory.cs",
    "content": "using System.Collections.Immutable;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal interface IRemoteClientDirectory : ISystemTarget\n    {\n        Task OnUpdateClientRoutes(ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)> update);\n        Task<ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>> GetClientRoutes(ImmutableDictionary<SiloAddress, long> knownRoutes);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/IRemoteGrainDirectory.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Per-silo system interface for managing the distributed, partitioned grain-silo-activation directory.\n    /// </summary>\n    internal interface IRemoteGrainDirectory : ISystemTarget, IDhtGrainDirectory\n    {        \n        /// <summary>\n        /// Records a bunch of new grain activations.\n        /// This method should be called only remotely during handoff.\n        /// </summary>\n        /// <param name=\"addresses\">The addresses of the grains to register</param>\n        /// <returns></returns>\n        Task RegisterMany(List<GrainAddress> addresses);\n\n        /// <summary>\n        /// Fetch the updated information on the given list of grains.\n        /// This method should be called only remotely to refresh directory caches.\n        /// </summary>\n        /// <param name=\"grainAndETagList\">list of grains and generation (version) numbers. The latter denote the versions of \n        /// the lists of activations currently held by the invoker of this method.</param>\n        /// <returns>list of tuples holding a grain, generation number of the list of activations, and the list of activations. \n        /// If the generation number of the invoker matches the number of the destination, the list is null. If the destination does not\n        /// hold the information on the grain, generation counter -1 is returned (and the list of activations is null)</returns>\n        Task<List<AddressAndTag>> LookUpMany(List<(GrainId GrainId, int Version)> grainAndETagList);\n\n        /// <summary>\n        /// Registers activations from a split partition with this directory.\n        /// </summary>\n        /// <param name=\"singleActivations\">The single-activation registrations from the split partition.</param>\n        /// <returns></returns>\n        Task AcceptSplitPartition(List<GrainAddress> singleActivations);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/LocalGrainDirectory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime.Scheduler;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal sealed partial class LocalGrainDirectory : ILocalGrainDirectory, ISiloStatusListener, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly ILogger log;\n        private readonly SiloAddress? seed;\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly IInternalGrainFactory grainFactory;\n#if NET9_0_OR_GREATER\n        private readonly Lock writeLock = new();\n#else\n        private readonly object writeLock = new();\n#endif\n        private readonly IServiceProvider _serviceProvider;\n        private DirectoryMembership directoryMembership = DirectoryMembership.Default;\n\n        // Consider: move these constants into an appropriate place\n        internal const int HOP_LIMIT = 6; // forward a remote request no more than 5 times\n        public static readonly TimeSpan RETRY_DELAY = TimeSpan.FromMilliseconds(200); // Pause 200ms between forwards to let the membership directory settle down\n        internal bool Running;\n        private Catalog? _catalog;\n\n        internal SiloAddress MyAddress { get; }\n\n        internal IGrainDirectoryCache DirectoryCache { get; }\n        internal LocalGrainDirectoryPartition DirectoryPartition { get; }\n\n        public RemoteGrainDirectory RemoteGrainDirectory { get; }\n        public RemoteGrainDirectory CacheValidator { get; }\n\n        internal GrainDirectoryHandoffManager HandoffManager { get; }\n\n        public LocalGrainDirectory(\n            IServiceProvider serviceProvider,\n            ILocalSiloDetails siloDetails,\n            ISiloStatusOracle siloStatusOracle,\n            IInternalGrainFactory grainFactory,\n            Factory<LocalGrainDirectoryPartition> grainDirectoryPartitionFactory,\n            IOptions<DevelopmentClusterMembershipOptions> developmentClusterMembershipOptions,\n            IOptions<GrainDirectoryOptions> grainDirectoryOptions,\n            ILoggerFactory loggerFactory,\n            SystemTargetShared systemTargetShared)\n        {\n            this.log = loggerFactory.CreateLogger<LocalGrainDirectory>();\n\n            MyAddress = siloDetails.SiloAddress;\n\n            this.siloStatusOracle = siloStatusOracle;\n            this.grainFactory = grainFactory;\n\n            DirectoryCache = GrainDirectoryCacheFactory.CreateGrainDirectoryCache(serviceProvider, grainDirectoryOptions.Value);\n\n            var primarySiloEndPoint = developmentClusterMembershipOptions.Value.PrimarySiloEndpoint;\n            if (primarySiloEndPoint != null)\n            {\n                this.seed = this.MyAddress.Endpoint.Equals(primarySiloEndPoint) ? this.MyAddress : SiloAddress.New(primarySiloEndPoint, 0);\n            }\n\n            DirectoryPartition = grainDirectoryPartitionFactory();\n            HandoffManager = new GrainDirectoryHandoffManager(this, siloStatusOracle, grainFactory, grainDirectoryPartitionFactory, loggerFactory);\n\n            RemoteGrainDirectory = new RemoteGrainDirectory(this, Constants.DirectoryServiceType, systemTargetShared);\n            CacheValidator = new RemoteGrainDirectory(this, Constants.DirectoryCacheValidatorType, systemTargetShared);\n\n            // add myself to the list of members\n            AddServer(MyAddress);\n\n            DirectoryInstruments.RegisterDirectoryPartitionSizeObserve(() => DirectoryPartition.Count);\n            DirectoryInstruments.RegisterMyPortionRingDistanceObserve(() => RingDistanceToSuccessor());\n            DirectoryInstruments.RegisterMyPortionRingPercentageObserve(() => (((float)this.RingDistanceToSuccessor()) / ((float)(int.MaxValue * 2L))) * 100);\n            DirectoryInstruments.RegisterMyPortionAverageRingPercentageObserve(() =>\n            {\n                var ring = this.directoryMembership.MembershipRingList;\n                return ring.Count == 0 ? 0 : ((float)100 / (float)ring.Count);\n            });\n            DirectoryInstruments.RegisterRingSizeObserve(() => this.directoryMembership.MembershipRingList.Count);\n            _serviceProvider = serviceProvider;\n        }\n\n        public void Start()\n        {\n            LogDebugStart();\n\n            Running = true;\n\n            siloStatusOracle.SubscribeToSiloStatusEvents(this);\n        }\n\n        // Note that this implementation stops processing directory change requests (Register, Unregister, etc.) when the Stop event is raised.\n        // This means that there may be a short period during which no silo believes that it is the owner of directory information for a set of\n        // grains (for update purposes), which could cause application requests that require a new activation to be created to time out.\n        // The alternative would be to allow the silo to process requests after it has handed off its partition, in which case those changes\n        // would receive successful responses but would not be reflected in the eventual state of the directory.\n        // It's easy to change this, if we think the trade-off is better the other way.\n        public Task StopAsync()\n        {\n            // This will cause remote write requests to be forwarded to the silo that will become the new owner.\n            // Requests might bounce back and forth for a while as membership stabilizes, but they will either be served by the\n            // new owner of the grain, or will wind up failing. In either case, we avoid requests succeeding at this silo after we've\n            // begun stopping, which could cause them to not get handed off to the new owner.\n\n            //mark Running as false will exclude myself from CalculateGrainDirectoryPartition(grainId)\n            Running = false;\n\n            DirectoryPartition.Clear();\n            DirectoryCache.Clear();\n            return Task.CompletedTask;\n        }\n\n        private void AddServer(SiloAddress silo)\n        {\n            lock (this.writeLock)\n            {\n                var existing = this.directoryMembership;\n                if (existing.MembershipCache.Contains(silo))\n                {\n                    // we have already cached this silo\n                    return;\n                }\n\n                // insert new silo in the sorted order\n                long hash = silo.GetConsistentHashCode();\n\n                // Find the last silo with hash smaller than the new silo, and insert the latter after (this is why we have +1 here) the former.\n                // Notice that FindLastIndex might return -1 if this should be the first silo in the list, but then\n                // 'index' will get 0, as needed.\n                int index = existing.MembershipRingList.FindLastIndex(siloAddr => siloAddr.GetConsistentHashCode() < hash) + 1;\n\n                this.directoryMembership = new DirectoryMembership(\n                    existing.MembershipRingList.Insert(index, silo),\n                    existing.MembershipCache.Add(silo));\n\n                HandoffManager.ProcessSiloAddEvent(silo);\n\n                AdjustLocalDirectory(silo, dead: false);\n                AdjustLocalCache(silo, dead: false);\n\n                LogDebugSiloAddedSilo(MyAddress, silo);\n            }\n        }\n\n        private void RemoveServer(SiloAddress silo, SiloStatus status)\n        {\n            lock (this.writeLock)\n            {\n                try\n                {\n                    // Only notify the catalog once. Order is important: call BEFORE updating membershipRingList.\n                    _catalog = _serviceProvider.GetRequiredService<Catalog>();\n                    _catalog.OnSiloStatusChange(this, silo, status);\n                }\n                catch (Exception exc)\n                {\n                    LogErrorCatalogSiloStatusChangeNotificationException(exc, new(silo));\n                }\n\n                var existing = this.directoryMembership;\n                if (!existing.MembershipCache.Contains(silo))\n                {\n                    // we have already removed this silo\n                    return;\n                }\n\n                this.directoryMembership = new DirectoryMembership(\n                    existing.MembershipRingList.Remove(silo),\n                    existing.MembershipCache.Remove(silo));\n\n                AdjustLocalDirectory(silo, dead: true);\n                AdjustLocalCache(silo, dead: true);\n\n                LogDebugSiloRemovedSilo(MyAddress, silo);\n            }\n        }\n\n        /// <summary>\n        /// Adjust local directory following the addition/removal of a silo\n        /// </summary>\n        private void AdjustLocalDirectory(SiloAddress silo, bool dead)\n        {\n            // Determine which activations to remove.\n            var activationsToRemove = new List<(GrainId, ActivationId)>();\n            foreach (var entry in this.DirectoryPartition.GetItems())\n            {\n                if (entry.Value.Activation is { } address)\n                {\n                    // Include any activations from dead silos and from predecessors.\n                    if (dead && address.SiloAddress!.Equals(silo) || address.SiloAddress!.IsPredecessorOf(silo))\n                    {\n                        activationsToRemove.Add((entry.Key, address.ActivationId));\n                    }\n                }\n            }\n\n            // Remove all defunct activations.\n            foreach (var activation in activationsToRemove)\n            {\n                DirectoryPartition.RemoveActivation(activation.Item1, activation.Item2);\n            }\n        }\n\n        /// Adjust local cache following the removal of a silo by dropping:\n        /// 1) entries that point to activations located on the removed silo\n        /// 2) entries for grains that are now owned by this silo (me)\n        /// 3) entries for grains that were owned by this removed silo - we currently do NOT do that.\n        ///     If we did 3, we need to do that BEFORE we change the membershipRingList (based on old Membership).\n        ///     We don't do that since first cache refresh handles that.\n        ///     Second, since Membership events are not guaranteed to be ordered, we may remove a cache entry that does not really point to a failed silo.\n        ///     To do that properly, we need to store for each cache entry who was the directory owner that registered this activation (the original partition owner).\n        private void AdjustLocalCache(SiloAddress silo, bool dead)\n        {\n            // remove all records of activations located on the removed silo\n            foreach (var tuple in DirectoryCache.KeyValues)\n            {\n                var activationAddress = tuple.ActivationAddress;\n\n                // 2) remove entries now owned by me (they should be retrieved from my directory partition)\n                if (MyAddress.Equals(CalculateGrainDirectoryPartition(activationAddress.GrainId)))\n                {\n                    DirectoryCache.Remove(activationAddress.GrainId);\n                    continue;\n                }\n\n                // 1) remove entries that point to activations located on the removed silo\n                // For dead silos, remove any activation registered to that silo or one of its predecessors.\n                // For new silos, remove any activation registered to one of its predecessors.\n                if (activationAddress.SiloAddress!.IsPredecessorOf(silo) || dead && activationAddress.SiloAddress.Equals(silo))\n                {\n                    DirectoryCache.Remove(activationAddress.GrainId);\n                }\n            }\n        }\n\n        internal SiloAddress? FindPredecessor(SiloAddress silo)\n        {\n            var existing = directoryMembership.MembershipRingList;\n            int index = existing.IndexOf(silo);\n            if (index == -1)\n            {\n                LogWarningFindPredecessorSiloNotInList(silo);\n                return null;\n            }\n\n            return existing.Count > 1 ? existing[(index == 0 ? existing.Count : index) - 1] : null;\n        }\n\n        internal SiloAddress? FindSuccessor(SiloAddress silo)\n        {\n            var existing = directoryMembership.MembershipRingList;\n            int index = existing.IndexOf(silo);\n            if (index == -1)\n            {\n                LogWarningFindSuccessorSiloNotInList(silo);\n                return null;\n            }\n\n            return existing.Count > 1 ? existing[(index + 1) % existing.Count] : null;\n        }\n\n        public void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n        {\n            // This silo's status has changed\n            if (!Equals(updatedSilo, MyAddress)) // Status change for some other silo\n            {\n                if (status.IsTerminating())\n                {\n                    // QueueAction up the \"Remove\" to run on a system turn\n                    CacheValidator.WorkItemGroup.QueueAction(() => RemoveServer(updatedSilo, status));\n                }\n                else if (status == SiloStatus.Active)      // do not do anything with SiloStatus.Starting -- wait until it actually becomes active\n                {\n                    // QueueAction up the \"Remove\" to run on a system turn\n                    CacheValidator.WorkItemGroup.QueueAction(() => AddServer(updatedSilo));\n                }\n            }\n        }\n\n        private bool IsValidSilo(SiloAddress? silo) => siloStatusOracle.IsFunctionalDirectory(silo);\n\n        /// <summary>\n        /// Finds the silo that owns the directory information for the given grain ID.\n        /// This method will only be null when I'm the only silo in the cluster and I'm shutting down\n        /// </summary>\n        /// <param name=\"grainId\"></param>\n        /// <returns></returns>\n        public SiloAddress? CalculateGrainDirectoryPartition(GrainId grainId)\n        {\n            // give a special treatment for special grains\n            if (grainId.IsSystemTarget())\n            {\n                if (Constants.SystemMembershipTableType.Equals(grainId.Type))\n                {\n                    if (seed == null)\n                    {\n                        var errorMsg =\n                            $\"Development clustering cannot run without a primary silo. \" +\n                            $\"Please configure {nameof(DevelopmentClusterMembershipOptions)}.{nameof(DevelopmentClusterMembershipOptions.PrimarySiloEndpoint)} \" +\n                            \"or provide a primary silo address to the UseDevelopmentClustering extension. \" +\n                            \"Alternatively, you may want to use reliable membership, such as Azure Table.\";\n                        throw new ArgumentException(errorMsg, \"grainId = \" + grainId);\n                    }\n                }\n\n                LogTraceSystemTargetLookup(MyAddress, grainId, MyAddress);\n\n                // every silo owns its system targets\n                return MyAddress;\n            }\n\n            SiloAddress? siloAddress = null;\n            int hash = unchecked((int)grainId.GetUniformHashCode());\n\n            // excludeMySelf from being a TargetSilo if we're not running and the excludeThisSIloIfStopping flag is true. see the comment in the Stop method.\n            // excludeThisSIloIfStopping flag was removed because we believe that flag complicates things unnecessarily. We can add it back if it turns out that flag\n            // is doing something valuable.\n            bool excludeMySelf = !Running;\n\n            var existing = this.directoryMembership;\n            if (existing.MembershipRingList.Count == 0)\n            {\n                // If the membership ring is empty, then we're the owner by default unless we're stopping.\n                return !Running ? null : MyAddress;\n            }\n\n            // need to implement a binary search, but for now simply traverse the list of silos sorted by their hashes\n            for (var index = existing.MembershipRingList.Count - 1; index >= 0; --index)\n            {\n                var item = existing.MembershipRingList[index];\n                if (IsSiloNextInTheRing(item, hash, excludeMySelf))\n                {\n                    siloAddress = item;\n                    break;\n                }\n            }\n\n            if (siloAddress == null)\n            {\n                // If not found in the traversal, last silo will do (we are on a ring).\n                // We checked above to make sure that the list isn't empty, so this should always be safe.\n                siloAddress = existing.MembershipRingList[existing.MembershipRingList.Count - 1];\n                // Make sure it's not us...\n                if (siloAddress.Equals(MyAddress) && excludeMySelf)\n                {\n                    siloAddress = existing.MembershipRingList.Count > 1 ? existing.MembershipRingList[existing.MembershipRingList.Count - 2] : null;\n                }\n            }\n\n            if (log.IsEnabled(LogLevel.Trace))\n                LogTraceCalculatedDirectoryPartitionOwner(\n                    MyAddress,\n                    siloAddress,\n                    grainId,\n                    hash,\n                    siloAddress?.GetConsistentHashCode());\n            return siloAddress;\n        }\n\n        public SiloAddress? CheckIfShouldForward(GrainId grainId, int hopCount, string operationDescription)\n        {\n            var owner = CalculateGrainDirectoryPartition(grainId);\n\n            if (owner is null || owner.Equals(MyAddress))\n            {\n                // Either we don't know about any other silos and we're stopping, or we are the owner.\n                // Null indicates that the operation should be performed locally.\n                // In the case that this host is terminating, any grain registered to this host must terminate.\n                return null;\n            }\n\n            if (hopCount >= HOP_LIMIT)\n            {\n                // we are not forwarding because there were too many hops already\n                throw new OrleansException($\"Silo {MyAddress} is not owner of {grainId}, cannot forward {operationDescription} to owner {owner} because hop limit is reached\");\n            }\n\n            // forward to the silo that we think is the owner\n            return owner;\n        }\n\n        public Task<AddressAndTag> RegisterAsync(GrainAddress address, int hopCount) => RegisterAsync(address, previousAddress: null, hopCount: hopCount);\n\n        public async Task<AddressAndTag> RegisterAsync(GrainAddress address, GrainAddress? previousAddress, int hopCount)\n        {\n            if (hopCount > 0)\n            {\n                DirectoryInstruments.RegistrationsSingleActRemoteReceived.Add(1);\n            }\n            else\n            {\n                DirectoryInstruments.RegistrationsSingleActIssued.Add(1);\n            }\n\n            // see if the owner is somewhere else (returns null if we are owner)\n            var forwardAddress = this.CheckIfShouldForward(address.GrainId, hopCount, \"RegisterAsync\");\n\n            // on all silos other than first, we insert a retry delay and recheck owner before forwarding\n            if (hopCount > 0 && forwardAddress != null)\n            {\n                await Task.Delay(RETRY_DELAY);\n                forwardAddress = this.CheckIfShouldForward(address.GrainId, hopCount, \"RegisterAsync\");\n                if (forwardAddress is not null)\n                {\n                    int hash = unchecked((int)address.GrainId.GetUniformHashCode());\n                    LogWarningRegisterAsyncNotOwner(\n                        address,\n                        hash,\n                        forwardAddress,\n                        hopCount);\n                }\n            }\n\n            if (forwardAddress == null)\n            {\n                DirectoryInstruments.RegistrationsSingleActLocal.Add(1);\n\n                var result = DirectoryPartition.AddSingleActivation(address, previousAddress);\n\n                // update the cache so next local lookup will find this ActivationAddress in the cache and we will save full lookup.\n                DirectoryCache.AddOrUpdate(result.Address, result.VersionTag);\n                return result;\n            }\n            else\n            {\n                DirectoryInstruments.RegistrationsSingleActRemoteSent.Add(1);\n\n                // otherwise, notify the owner\n                AddressAndTag result = await GetDirectoryReference(forwardAddress).RegisterAsync(address, previousAddress, hopCount + 1);\n\n                // Caching optimization:\n                // cache the result of a successful RegisterSingleActivation call, only if it is not a duplicate activation.\n                // this way next local lookup will find this ActivationAddress in the cache and we will save a full lookup!\n                if (result.Address == null) return result;\n\n                if (!address.Equals(result.Address) || !IsValidSilo(address.SiloAddress)) return result;\n\n                // update the cache so next local lookup will find this ActivationAddress in the cache and we will save full lookup.\n                DirectoryCache.AddOrUpdate(result.Address, result.VersionTag);\n\n                return result;\n            }\n        }\n\n        public Task UnregisterAfterNonexistingActivation(GrainAddress addr, SiloAddress origin)\n        {\n            LogTraceUnregisterAfterNonexistingActivation(addr, origin);\n\n            if (origin == null || this.directoryMembership.MembershipCache.Contains(origin))\n            {\n                // the request originated in this cluster, call unregister here\n                return UnregisterAsync(addr, UnregistrationCause.NonexistentActivation, 0);\n            }\n            else\n            {\n                // the request originated in another cluster, call unregister there\n                var remoteDirectory = GetDirectoryReference(origin);\n                return remoteDirectory.UnregisterAsync(addr, UnregistrationCause.NonexistentActivation);\n            }\n        }\n\n        public async Task UnregisterAsync(GrainAddress address, UnregistrationCause cause, int hopCount)\n        {\n            if (hopCount > 0)\n            {\n                DirectoryInstruments.UnregistrationsRemoteReceived.Add(1);\n            }\n            else\n            {\n                DirectoryInstruments.UnregistrationsIssued.Add(1);\n            }\n\n            if (hopCount == 0)\n                InvalidateCacheEntry(address);\n\n            // see if the owner is somewhere else (returns null if we are owner)\n            var forwardAddress = this.CheckIfShouldForward(address.GrainId, hopCount, \"UnregisterAsync\");\n\n            // on all silos other than first, we insert a retry delay and recheck owner before forwarding\n            if (hopCount > 0 && forwardAddress != null)\n            {\n                await Task.Delay(RETRY_DELAY);\n                forwardAddress = this.CheckIfShouldForward(address.GrainId, hopCount, \"UnregisterAsync\");\n                LogWarningUnregisterAsyncNotOwner(\n                    address,\n                    forwardAddress,\n                    hopCount);\n            }\n\n            if (forwardAddress == null)\n            {\n                // we are the owner\n                DirectoryInstruments.UnregistrationsLocal.Add(1);\n                DirectoryPartition.RemoveActivation(address.GrainId, address.ActivationId, cause);\n            }\n            else\n            {\n                DirectoryInstruments.UnregistrationsRemoteSent.Add(1);\n                // otherwise, notify the owner\n                await GetDirectoryReference(forwardAddress).UnregisterAsync(address, cause, hopCount + 1);\n            }\n        }\n\n        // helper method to avoid code duplication inside UnregisterManyAsync\n        private void UnregisterOrPutInForwardList(List<GrainAddress> addresses, UnregistrationCause cause, int hopCount,\n            ref Dictionary<SiloAddress, List<GrainAddress>>? forward, string context)\n        {\n            foreach (var address in addresses)\n            {\n                // see if the owner is somewhere else (returns null if we are owner)\n                var forwardAddress = this.CheckIfShouldForward(address.GrainId, hopCount, context);\n\n                if (forwardAddress != null)\n                {\n                    forward ??= new();\n                    if (!forward.TryGetValue(forwardAddress, out var list))\n                        forward[forwardAddress] = list = new();\n                    list.Add(address);\n                }\n                else\n                {\n                    // we are the owner\n                    DirectoryInstruments.UnregistrationsLocal.Add(1);\n\n                    DirectoryPartition.RemoveActivation(address.GrainId, address.ActivationId, cause);\n                }\n            }\n        }\n\n\n        public async Task UnregisterManyAsync(List<GrainAddress> addresses, UnregistrationCause cause, int hopCount)\n        {\n            if (hopCount > 0)\n            {\n                DirectoryInstruments.UnregistrationsManyRemoteReceived.Add(1);\n            }\n            else\n            {\n                DirectoryInstruments.UnregistrationsManyIssued.Add(1);\n            }\n\n            Dictionary<SiloAddress, List<GrainAddress>>? forwardlist = null;\n\n            UnregisterOrPutInForwardList(addresses, cause, hopCount, ref forwardlist, \"UnregisterManyAsync\");\n\n            // before forwarding to other silos, we insert a retry delay and re-check destination\n            if (hopCount > 0 && forwardlist != null)\n            {\n                await Task.Delay(RETRY_DELAY);\n                Dictionary<SiloAddress, List<GrainAddress>>? forwardlist2 = null;\n                UnregisterOrPutInForwardList(addresses, cause, hopCount, ref forwardlist2, \"UnregisterManyAsync\");\n                forwardlist = forwardlist2;\n                if (forwardlist != null)\n                {\n                    LogWarningUnregisterManyAsyncNotOwner(\n                        forwardlist.Count,\n                        hopCount);\n                }\n            }\n\n            // forward the requests\n            if (forwardlist != null)\n            {\n                var tasks = new List<Task>();\n                foreach (var kvp in forwardlist)\n                {\n                    DirectoryInstruments.UnregistrationsManyRemoteSent.Add(1);\n                    tasks.Add(GetDirectoryReference(kvp.Key).UnregisterManyAsync(kvp.Value, cause, hopCount + 1));\n                }\n\n                // wait for all the requests to finish\n                await Task.WhenAll(tasks);\n            }\n        }\n\n\n        public bool LocalLookup(GrainId grain, out AddressAndTag result)\n        {\n            DirectoryInstruments.LookupsLocalIssued.Add(1);\n\n            var silo = CalculateGrainDirectoryPartition(grain);\n\n            LogDebugLocalLookupAttempt(\n                MyAddress,\n                grain,\n                silo,\n                new(grain),\n                new(silo));\n\n            //this will only happen if I'm the only silo in the cluster and I'm shutting down\n            if (silo == null)\n            {\n                LogTraceLocalLookupMineNull(grain);\n                result = default;\n                return false;\n            }\n\n            // handle cache\n            DirectoryInstruments.LookupsCacheIssued.Add(1);\n            var address = GetLocalCacheData(grain);\n            if (address != default)\n            {\n                result = new(address, 0);\n\n                LogTraceLocalLookupCache(grain, result.Address);\n                DirectoryInstruments.LookupsCacheSuccesses.Add(1);\n                DirectoryInstruments.LookupsLocalSuccesses.Add(1);\n                return true;\n            }\n\n            // check if we own the grain\n            if (silo.Equals(MyAddress))\n            {\n                DirectoryInstruments.LookupsLocalDirectoryIssued.Add(1);\n                result = GetLocalDirectoryData(grain);\n                if (result.Address == null)\n                {\n                    // it can happen that we cannot find the grain in our partition if there were\n                    // some recent changes in the membership\n                    LogTraceLocalLookupMineNull(grain);\n                    return false;\n                }\n                LogTraceLocalLookupMine(grain, result.Address);\n                DirectoryInstruments.LookupsLocalDirectorySuccesses.Add(1);\n                DirectoryInstruments.LookupsLocalSuccesses.Add(1);\n                return true;\n            }\n\n            LogTraceTryFullLookupElse(grain);\n            result = default;\n            return false;\n        }\n\n        public AddressAndTag GetLocalDirectoryData(GrainId grain) => DirectoryPartition.LookUpActivation(grain);\n\n        public GrainAddress? GetLocalCacheData(GrainId grain) => DirectoryCache.LookUp(grain, out var cache) && IsValidSilo(cache.SiloAddress) ? cache : null;\n\n        public async Task<AddressAndTag> LookupAsync(GrainId grainId, int hopCount = 0)\n        {\n            if (hopCount > 0)\n            {\n                DirectoryInstruments.LookupsRemoteReceived.Add(1);\n            }\n            else\n            {\n                DirectoryInstruments.LookupsFullIssued.Add(1);\n            }\n\n            // see if the owner is somewhere else (returns null if we are owner)\n            var forwardAddress = this.CheckIfShouldForward(grainId, hopCount, \"LookUpAsync\");\n\n            // on all silos other than first, we insert a retry delay and recheck owner before forwarding\n            if (hopCount > 0 && forwardAddress != null)\n            {\n                await Task.Delay(RETRY_DELAY);\n                forwardAddress = this.CheckIfShouldForward(grainId, hopCount, \"LookUpAsync\");\n                if (forwardAddress is not null)\n                {\n                    int hash = unchecked((int)grainId.GetUniformHashCode());\n                    LogWarningLookupAsyncNotOwner(\n                        grainId,\n                        hash,\n                        forwardAddress,\n                        hopCount);\n                }\n            }\n\n            if (forwardAddress == null)\n            {\n                // we are the owner\n                DirectoryInstruments.LookupsLocalDirectoryIssued.Add(1);\n                var localResult = DirectoryPartition.LookUpActivation(grainId);\n                if (localResult.Address == null)\n                {\n                    // it can happen that we cannot find the grain in our partition if there were\n                    // some recent changes in the membership\n                    LogTraceFullLookupMineNone(grainId);\n                    return new(default, GrainInfo.NO_ETAG);\n                }\n\n                LogTraceFullLookupMine(grainId, localResult.Address);\n                DirectoryInstruments.LookupsLocalDirectorySuccesses.Add(1);\n                return localResult;\n            }\n            else\n            {\n                // Just a optimization. Why sending a message to someone we know is not valid.\n                if (!IsValidSilo(forwardAddress))\n                {\n                    throw new OrleansException($\"Current directory at {MyAddress} is not stable to perform the lookup for grainId {grainId} (it maps to {forwardAddress}, which is not a valid silo). Retry later.\");\n                }\n\n                DirectoryInstruments.LookupsRemoteSent.Add(1);\n                var result = await GetDirectoryReference(forwardAddress).LookupAsync(grainId, hopCount + 1);\n\n                // update the cache\n                if (result.Address is { } address && IsValidSilo(address.SiloAddress))\n                {\n                    DirectoryCache.AddOrUpdate(address, result.VersionTag);\n                }\n\n                LogTraceFullLookupRemote(grainId, result.Address);\n\n                return result;\n            }\n        }\n\n        public async Task DeleteGrainAsync(GrainId grainId, int hopCount)\n        {\n            // see if the owner is somewhere else (returns null if we are owner)\n            var forwardAddress = this.CheckIfShouldForward(grainId, hopCount, \"DeleteGrainAsync\");\n\n            // on all silos other than first, we insert a retry delay and recheck owner before forwarding\n            if (hopCount > 0 && forwardAddress != null)\n            {\n                await Task.Delay(RETRY_DELAY);\n                forwardAddress = this.CheckIfShouldForward(grainId, hopCount, \"DeleteGrainAsync\");\n                LogWarningDeleteGrainAsyncNotOwner(\n                    grainId,\n                    forwardAddress,\n                    hopCount);\n            }\n\n            if (forwardAddress == null)\n            {\n                // we are the owner\n                DirectoryPartition.RemoveGrain(grainId);\n            }\n            else\n            {\n                // otherwise, notify the owner\n                DirectoryCache.Remove(grainId);\n                await GetDirectoryReference(forwardAddress).DeleteGrainAsync(grainId, hopCount + 1);\n            }\n        }\n\n        public void InvalidateCacheEntry(GrainId grainId)\n        {\n            DirectoryCache.Remove(grainId);\n        }\n\n        public void InvalidateCacheEntry(GrainAddress activationAddress)\n        {\n            DirectoryCache.Remove(activationAddress);\n        }\n\n        /// <summary>\n        /// For testing purposes only.\n        /// Returns the silo that this silo thinks is the primary owner of directory information for\n        /// the provided grain ID.\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        /// <returns></returns>\n        public SiloAddress? GetPrimaryForGrain(GrainId grain) => CalculateGrainDirectoryPartition(grain);\n\n        private long RingDistanceToSuccessor() => FindSuccessor(MyAddress) is { } successor ? CalcRingDistance(MyAddress, successor) : 0;\n\n        private static long CalcRingDistance(SiloAddress silo1, SiloAddress silo2)\n        {\n            const long ringSize = int.MaxValue * 2L;\n            long hash1 = silo1.GetConsistentHashCode();\n            long hash2 = silo2.GetConsistentHashCode();\n\n            if (hash2 > hash1) return hash2 - hash1;\n            if (hash2 < hash1) return ringSize - (hash1 - hash2);\n\n            return 0;\n        }\n\n        internal IRemoteGrainDirectory GetDirectoryReference(SiloAddress silo)\n        {\n            return this.grainFactory.GetSystemTarget<IRemoteGrainDirectory>(Constants.DirectoryServiceType, silo);\n        }\n\n        private bool IsSiloNextInTheRing(SiloAddress siloAddr, int hash, bool excludeMySelf)\n        {\n            return siloAddr.GetConsistentHashCode() <= hash && (!excludeMySelf || !siloAddr.Equals(MyAddress));\n        }\n\n        public bool IsSiloInCluster(SiloAddress silo)\n        {\n            return this.directoryMembership.MembershipCache.Contains(silo);\n        }\n\n        public void AddOrUpdateCacheEntry(GrainId grainId, SiloAddress siloAddress) => this.DirectoryCache.AddOrUpdate(new GrainAddress { GrainId = grainId, SiloAddress = siloAddress }, 0);\n        public bool TryCachedLookup(GrainId grainId, [NotNullWhen(true)] out GrainAddress? address) => (address = GetLocalCacheData(grainId)) is not null;\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<LocalGrainDirectory>(ServiceLifecycleStage.RuntimeServices, (ct) => Task.Run(() => Start()), (ct) => Task.Run(() => StopAsync()));\n        }\n\n        private readonly struct SiloAddressLogValue(SiloAddress silo)\n        {\n            public override string ToString() => silo.ToStringWithHashCode();\n        }\n\n        private readonly struct GrainHashLogValue(GrainId grain)\n        {\n            public override string ToString() => grain.GetUniformHashCode().ToString();\n        }\n\n        private readonly struct SiloHashLogValue(SiloAddress? silo)\n        {\n            public override string ToString() => silo?.GetConsistentHashCode().ToString() ?? \"null\";\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Start\"\n        )]\n        private partial void LogDebugStart();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo {SiloAddress} added silo {OtherSiloAddress}\"\n        )]\n        private partial void LogDebugSiloAddedSilo(SiloAddress siloAddress, SiloAddress otherSiloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Directory_SiloStatusChangeNotification_Exception,\n            Level = LogLevel.Error,\n            Message = \"CatalogSiloStatusListener.SiloStatusChangeNotification has thrown an exception when notified about removed silo {Silo}.\"\n        )]\n        private partial void LogErrorCatalogSiloStatusChangeNotificationException(Exception exception, SiloAddressLogValue silo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo {LocalSilo} removed silo {OtherSilo}\"\n        )]\n        private partial void LogDebugSiloRemovedSilo(SiloAddress localSilo, SiloAddress otherSilo);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100201,\n            Level = LogLevel.Warning,\n            Message = \"Got request to find predecessors of silo {SiloAddress}, which is not in the list of members\"\n        )]\n        private partial void LogWarningFindPredecessorSiloNotInList(SiloAddress siloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100203,\n            Level = LogLevel.Warning,\n            Message = \"Got request to find successors of silo {SiloAddress}, which is not in the list of members\"\n        )]\n        private partial void LogWarningFindSuccessorSiloNotInList(SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Silo {SiloAddress} looked for a system target {GrainId}, returned {TargetSilo}\"\n        )]\n        private partial void LogTraceSystemTargetLookup(SiloAddress siloAddress, GrainId grainId, SiloAddress targetSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Silo {SiloAddress} calculated directory partition owner silo {OwnerAddress} for grain {GrainId}: {GrainIdHash} --> {OwnerAddressHash}\"\n        )]\n        private partial void LogTraceCalculatedDirectoryPartitionOwner(SiloAddress siloAddress, SiloAddress? ownerAddress, GrainId grainId, int grainIdHash, long? ownerAddressHash);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"RegisterAsync - It seems we are not the owner of activation {Address} (hash: {Hash:X}), trying to forward it to {ForwardAddress} (hopCount={HopCount})\"\n        )]\n        private partial void LogWarningRegisterAsyncNotOwner(GrainAddress address, int hash, SiloAddress forwardAddress, int hopCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"UnregisterAfterNonexistingActivation addr={Address} origin={Origin}\"\n        )]\n        private partial void LogTraceUnregisterAfterNonexistingActivation(GrainAddress address, SiloAddress origin);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"UnregisterAsync - It seems we are not the owner of activation {Address}, trying to forward it to {ForwardAddress} (hopCount={HopCount})\"\n        )]\n        private partial void LogWarningUnregisterAsyncNotOwner(GrainAddress address, SiloAddress? forwardAddress, int hopCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"RegisterAsync - It seems we are not the owner of some activations, trying to forward it to {Count} silos (hopCount={HopCount})\"\n        )]\n        private partial void LogWarningUnregisterManyAsyncNotOwner(int count, int hopCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo {SiloAddress} tries to lookup for {Grain}-->{PartitionOwner} ({GrainHashCode}-->{PartitionOwnerHashCode})\"\n        )]\n        private partial void LogDebugLocalLookupAttempt(SiloAddress siloAddress, GrainId grain, SiloAddress? partitionOwner, GrainHashLogValue grainHashCode, SiloHashLogValue partitionOwnerHashCode);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"LocalLookup mine {GrainId}=null\"\n        )]\n        private partial void LogTraceLocalLookupMineNull(GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"LocalLookup cache {GrainId}={TargetAddress}\"\n        )]\n        private partial void LogTraceLocalLookupCache(GrainId grainId, GrainAddress? targetAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"LocalLookup mine {GrainId}={Address}\"\n        )]\n        private partial void LogTraceLocalLookupMine(GrainId grainId, GrainAddress? address);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"TryFullLookup else {GrainId}=null\"\n        )]\n        private partial void LogTraceTryFullLookupElse(GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"LookupAsync - It seems we are not the owner of grain {GrainId} (hash: {Hash:X}), trying to forward it to {ForwardAddress} (hopCount={HopCount})\"\n        )]\n        private partial void LogWarningLookupAsyncNotOwner(GrainId grainId, int hash, SiloAddress forwardAddress, int hopCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"FullLookup mine {GrainId}=none\"\n        )]\n        private partial void LogTraceFullLookupMineNone(GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"FullLookup mine {GrainId}={Address}\"\n        )]\n        private partial void LogTraceFullLookupMine(GrainId grainId, GrainAddress? address);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"FullLookup remote {GrainId}={Address}\"\n        )]\n        private partial void LogTraceFullLookupRemote(GrainId grainId, GrainAddress? address);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"DeleteGrainAsync - It seems we are not the owner of grain {GrainId}, trying to forward it to {ForwardAddress} (hopCount={HopCount})\"\n        )]\n        private partial void LogWarningDeleteGrainAsyncNotOwner(GrainId grainId, SiloAddress? forwardAddress, int hopCount);\n\n        private class DirectoryMembership\n        {\n            public DirectoryMembership(ImmutableList<SiloAddress> membershipRingList, ImmutableHashSet<SiloAddress> membershipCache)\n            {\n                this.MembershipRingList = membershipRingList;\n                this.MembershipCache = membershipCache;\n            }\n\n            public static DirectoryMembership Default { get; } = new DirectoryMembership(ImmutableList<SiloAddress>.Empty, ImmutableHashSet<SiloAddress>.Empty);\n\n\n            public ImmutableList<SiloAddress> MembershipRingList { get; }\n            public ImmutableHashSet<SiloAddress> MembershipCache { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/LocalGrainDirectoryPartition.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory\n{\n    [Serializable]\n    internal sealed class GrainInfo\n    {\n        public const int NO_ETAG = -1;\n\n        public GrainAddress? Activation { get; private set; }\n\n        public DateTime TimeCreated { get; private set; }\n\n        public int VersionTag { get; private set; }\n\n        public bool OkToRemove(UnregistrationCause cause, TimeSpan lazyDeregistrationDelay)\n        {\n            switch (cause)\n            {\n                case UnregistrationCause.Force:\n                    return true;\n\n                case UnregistrationCause.NonexistentActivation:\n                    {\n                        var delayparameter = lazyDeregistrationDelay;\n                        if (delayparameter <= TimeSpan.Zero)\n                            return false; // no lazy deregistration\n                        else\n                            return (TimeCreated <= DateTime.UtcNow - delayparameter);\n                    }\n\n                default:\n                    throw new OrleansException(\"unhandled case\");\n            }\n        }\n\n        public GrainAddress TryAddSingleActivation(GrainAddress address, GrainAddress? previousAddress)\n        {\n            // If there is an existing address which does not match the 'previousAddress' then we cannot add the new address.\n            if (Activation is { } existing && (previousAddress is null || !previousAddress.Equals(existing)))\n            {\n                return existing;\n            }\n            else\n            {\n                Activation = address;\n                TimeCreated = DateTime.UtcNow;\n                VersionTag = Random.Shared.Next();\n                return address;\n            }\n        }\n\n        public bool RemoveActivation(ActivationId act, UnregistrationCause cause, TimeSpan lazyDeregistrationDelay, out bool wasRemoved)\n        {\n            wasRemoved = false;\n            if (Activation is { } existing && existing.ActivationId.Equals(act) && OkToRemove(cause, lazyDeregistrationDelay))\n            {\n                wasRemoved = true;\n                Activation = null;\n                VersionTag = Random.Shared.Next();\n            }\n\n            return wasRemoved;\n        }\n\n        public GrainAddress? Merge(GrainInfo other)\n        {\n            var otherActivation = other.Activation;\n            if (otherActivation is not null && Activation is null)\n            {\n                Activation = other.Activation;\n                TimeCreated = other.TimeCreated;\n                VersionTag = Random.Shared.Next();\n            }\n            else if (Activation is not null && otherActivation is not null)\n            {\n                // Grain is supposed to be in single activation mode, but we have two activations!!\n                // Eventually we should somehow delegate handling this to the silo, but for now, we'll arbitrarily pick one value.\n                if (Activation.ActivationId.Key.CompareTo(otherActivation.ActivationId.Key) < 0)\n                {\n                    var activationToDrop = Activation;\n                    Activation = otherActivation;\n                    TimeCreated = other.TimeCreated;\n                    VersionTag = Random.Shared.Next();\n                    return activationToDrop;\n                }\n\n                // Keep this activation and destroy the other.\n                return otherActivation;\n            }\n\n            return null;\n        }\n    }\n\n    internal sealed partial class LocalGrainDirectoryPartition\n    {\n        // Should we change this to SortedList<> or SortedDictionary so we can extract chunks better for shipping the full\n        // partition to a follower, or should we leave it as a Dictionary to get O(1) lookups instead of O(log n), figuring we do\n        // a lot more lookups and so can sort periodically?\n        /// <summary>\n        /// contains a map from grain to its list of activations along with the version (etag) counter for the list\n        /// </summary>\n        private Dictionary<GrainId, GrainInfo> partitionData;\n        private readonly object lockable;\n        private readonly ILogger log;\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly IOptions<GrainDirectoryOptions> grainDirectoryOptions;\n\n        internal int Count { get { return partitionData.Count; } }\n\n        public LocalGrainDirectoryPartition(ISiloStatusOracle siloStatusOracle, IOptions<GrainDirectoryOptions> grainDirectoryOptions, ILoggerFactory loggerFactory)\n        {\n            partitionData = new Dictionary<GrainId, GrainInfo>();\n            lockable = new object();\n            log = loggerFactory.CreateLogger<LocalGrainDirectoryPartition>();\n            this.siloStatusOracle = siloStatusOracle;\n            this.grainDirectoryOptions = grainDirectoryOptions;\n        }\n\n        private bool IsValidSilo(SiloAddress? silo) => silo is not null && siloStatusOracle.IsFunctionalDirectory(silo);\n\n        internal void Clear()\n        {\n            lock (lockable)\n            {\n                partitionData.Clear();\n            }\n        }\n\n        /// <summary>\n        /// Returns all entries stored in the partition as an enumerable collection\n        /// </summary>\n        /// <returns></returns>\n        public List<KeyValuePair<GrainId, GrainInfo>> GetItems()\n        {\n            lock (lockable)\n            {\n                return partitionData.ToList();\n            }\n        }\n\n        /// <summary>\n        /// Adds a new activation to the directory partition\n        /// </summary>\n        /// <returns>The registered ActivationAddress and version associated with this directory mapping</returns>\n        internal AddressAndTag AddSingleActivation(GrainAddress address, GrainAddress? previousAddress)\n        {\n            LogTraceAddingSingleActivation(address.SiloAddress, address.GrainId, address.ActivationId);\n\n            if (!IsValidSilo(address.SiloAddress))\n            {\n                var siloStatus = this.siloStatusOracle.GetApproximateSiloStatus(address.SiloAddress);\n                throw new OrleansException($\"Trying to register {address.GrainId} on invalid silo: {address.SiloAddress}. Known status: {siloStatus}\");\n            }\n\n            lock (lockable)\n            {\n                if (!partitionData.TryGetValue(address.GrainId, out var grainInfo))\n                {\n                    partitionData[address.GrainId] = grainInfo = new GrainInfo();\n                }\n                else\n                {\n                    var siloAddress = grainInfo.Activation?.SiloAddress;\n\n                    // If there is an existing entry pointing to an invalid silo then remove it \n                    if (siloAddress != null && !IsValidSilo(siloAddress))\n                    {\n                        partitionData[address.GrainId] = grainInfo = new GrainInfo();\n                    }\n                }\n\n                return new(grainInfo.TryAddSingleActivation(address, previousAddress), grainInfo.VersionTag);\n            }\n        }\n\n        /// <summary>\n        /// Removes an activation of the given grain from the partition\n        /// </summary>\n        /// <param name=\"grain\">the identity of the grain</param>\n        /// <param name=\"activation\">the id of the activation</param>\n        /// <param name=\"cause\">reason for removing the activation</param>\n        internal void RemoveActivation(GrainId grain, ActivationId activation, UnregistrationCause cause = UnregistrationCause.Force)\n        {\n            var wasRemoved = false;\n            lock (lockable)\n            {\n                if (partitionData.TryGetValue(grain, out var value) && value.RemoveActivation(activation, cause, this.grainDirectoryOptions.Value.LazyDeregistrationDelay, out wasRemoved))\n                {\n                    // if the last activation for the grain was removed, we remove the entire grain info \n                    partitionData.Remove(grain);\n                }\n            }\n\n            LogTraceRemovingActivation(grain, cause, wasRemoved);\n        }\n\n        /// <summary>\n        /// Removes the grain (and, effectively, all its activations) from the directory\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        internal void RemoveGrain(GrainId grain)\n        {\n            lock (lockable)\n            {\n                partitionData.Remove(grain);\n            }\n            LogTraceRemovingGrain(grain);\n        }\n\n        internal AddressAndTag LookUpActivation(GrainId grain)\n        {\n            AddressAndTag result;\n            lock (lockable)\n            {\n                if (!partitionData.TryGetValue(grain, out var grainInfo) || grainInfo.Activation is null)\n                {\n                    return default;\n                }\n\n                result = new(grainInfo.Activation, grainInfo.VersionTag);\n            }\n\n            if (!IsValidSilo(result.Address?.SiloAddress))\n            {\n                result = new(null, result.VersionTag);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns the version number of the list of activations for the grain.\n        /// If the grain is not found, -1 is returned.\n        /// </summary>\n        /// <param name=\"grain\"></param>\n        /// <returns></returns>\n        internal int GetGrainETag(GrainId grain)\n        {\n            lock (lockable)\n            {\n                return partitionData.TryGetValue(grain, out var info) ? info.VersionTag : GrainInfo.NO_ETAG;\n            }\n        }\n\n        /// <summary>\n        /// Merges one partition into another, assuming partitions are disjoint.\n        /// This method is supposed to be used by handoff manager to update the partitions when the system view (set of live silos) changes.\n        /// </summary>\n        /// <param name=\"other\"></param>\n        /// <returns>Activations which must be deactivated.</returns>\n        internal Dictionary<SiloAddress, List<GrainAddress>>? Merge(LocalGrainDirectoryPartition other)\n        {\n            Dictionary<SiloAddress, List<GrainAddress>>? activationsToRemove = null;\n            lock (lockable)\n            {\n                foreach (var pair in other.partitionData)\n                {\n                    ref var grainInfo = ref CollectionsMarshal.GetValueRefOrAddDefault(partitionData, pair.Key, out _);\n                    if (grainInfo is { } existing)\n                    {\n                        LogDebugMergingDisjointPartitions(pair.Key);\n\n                        var activationToDrop = existing.Merge(pair.Value);\n                        if (activationToDrop == null) continue;\n                        (CollectionsMarshal.GetValueRefOrAddDefault(activationsToRemove ??= new(), activationToDrop.SiloAddress!, out _) ??= new()).Add(activationToDrop);\n                    }\n                    else\n                    {\n                        grainInfo = pair.Value;\n                    }\n                }\n            }\n\n            return activationsToRemove;\n        }\n\n        /// <summary>\n        /// Runs through all entries in the partition and moves/copies (depending on the given flag) the\n        /// entries satisfying the given predicate into a new partition.\n        /// This method is supposed to be used by handoff manager to update the partitions when the system view (set of live silos) changes.\n        /// </summary>\n        /// <param name=\"predicate\">filter predicate (usually if the given grain is owned by particular silo)</param>\n        /// <returns>Entries satisfying the given predicate</returns>\n        internal List<GrainAddress> Split(Predicate<GrainId> predicate)\n        {\n            var result = new List<GrainAddress>();\n\n            lock (lockable)\n            {\n                foreach (var pair in partitionData)\n                {\n                    if (pair.Value.Activation is { } address && predicate(pair.Key))\n                    {\n                        result.Add(address);\n                    }\n                }\n            }\n\n            for (var i = result.Count - 1; i >= 0; i--)\n            {\n                if (!IsValidSilo(result[i].SiloAddress))\n                {\n                    result.RemoveAt(i);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Sets the internal partition dictionary to the one given as input parameter.\n        /// This method is supposed to be used by handoff manager to update the old partition with a new partition.\n        /// </summary>\n        /// <param name=\"newPartitionData\">new internal partition dictionary</param>\n        internal void Set(Dictionary<GrainId, GrainInfo> newPartitionData)\n        {\n            partitionData = newPartitionData;\n        }\n\n        /// <summary>\n        /// Updates partition with a new delta of changes.\n        /// This method is supposed to be used by handoff manager to update the partition with a set of delta changes.\n        /// </summary>\n        /// <param name=\"newPartitionDelta\">dictionary holding a set of delta updates to this partition.\n        /// If the value for a given key in the delta is valid, then existing entry in the partition is replaced.\n        /// Otherwise, i.e., if the value is null, the corresponding entry is removed.\n        /// </param>\n        internal void Update(Dictionary<GrainId, GrainInfo> newPartitionDelta)\n        {\n            lock (lockable)\n            {\n                foreach (var kv in newPartitionDelta)\n                {\n                    if (kv.Value != null)\n                    {\n                        partitionData[kv.Key] = kv.Value;\n                    }\n                    else\n                    {\n                        partitionData.Remove(kv.Key);\n                    }\n                }\n            }\n        }\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n\n            lock (lockable)\n            {\n                foreach (var grainEntry in partitionData)\n                {\n                    if (grainEntry.Value.Activation is { } activation)\n                    {\n                        sb.Append(\"    \").Append(grainEntry.Key.ToString()).Append(\"[\" + grainEntry.Value.VersionTag + \"]\").\n                            Append(\" => \").Append(activation.GrainId.ToString()).\n                            Append(\" @ \").AppendLine(activation.ToString());\n                    }\n                }\n            }\n\n            return sb.ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Adding single activation for grain {SiloAddress} {GrainId} {ActivationId}\"\n        )]\n        private partial void LogTraceAddingSingleActivation(SiloAddress? siloAddress, GrainId grainId, ActivationId activationId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Removing activation for grain {GrainId} cause={Cause} was_removed={WasRemoved}\"\n        )]\n        private partial void LogTraceRemovingActivation(GrainId grainId, UnregistrationCause cause, bool wasRemoved);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Removing grain {GrainId}\"\n        )]\n        private partial void LogTraceRemovingGrain(GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"While merging two disjoint partitions, same grain {GrainId} was found in both partitions\"\n        )]\n        private partial void LogDebugMergingDisjointPartitions(GrainId grainId);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/LruGrainDirectoryCache.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Caching;\n\nnamespace Orleans.Runtime.GrainDirectory;\n\ninternal sealed class LruGrainDirectoryCache(int maxCacheSize) : ConcurrentLruCache<GrainId, (GrainAddress ActivationAddress, int Version)>(capacity: maxCacheSize), IGrainDirectoryCache\n{\n    private static readonly Func<(GrainAddress Address, int Version), GrainAddress, bool> ActivationAddressesMatch = (value, state) => GrainAddress.MatchesGrainIdAndSilo(state, value.Address);\n\n    public void AddOrUpdate(GrainAddress activationAddress, int version) => AddOrUpdate(activationAddress.GrainId, (activationAddress, version));\n\n    public bool Remove(GrainId key) => TryRemove(key);\n\n    public bool Remove(GrainAddress grainAddress) => TryRemove(grainAddress.GrainId, ActivationAddressesMatch, grainAddress);\n\n    public bool LookUp(GrainId key, out GrainAddress result, out int version)\n    {\n        if (TryGet(key, out var entry))\n        {\n            version = entry.Version;\n            result = entry.ActivationAddress;\n            return true;\n        }\n\n        version = default;\n        result = default;\n        return false;\n    }\n\n    public IEnumerable<(GrainAddress ActivationAddress, int Version)> KeyValues\n    {\n        get\n        {\n            foreach (var entry in this)\n            {\n                yield return (entry.Value.ActivationAddress, entry.Value.Version);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/RemoteGrainDirectory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.GrainDirectory;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory\n{\n    internal sealed partial class RemoteGrainDirectory : SystemTarget, IRemoteGrainDirectory\n    {\n        private readonly LocalGrainDirectory router;\n        private readonly LocalGrainDirectoryPartition partition;\n        private readonly ILogger logger;\n\n        internal RemoteGrainDirectory(LocalGrainDirectory localGrainDirectory, GrainType grainType, SystemTargetShared shared)\n            : base(grainType, shared)\n        {\n            router = localGrainDirectory;\n            partition = localGrainDirectory.DirectoryPartition;\n            logger = shared.LoggerFactory.CreateLogger($\"{typeof(RemoteGrainDirectory).FullName}.CacheValidator\");\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public Task<AddressAndTag> RegisterAsync(GrainAddress address, GrainAddress? previousAddress, int hopCount)\n        {\n            DirectoryInstruments.RegistrationsSingleActRemoteReceived.Add(1);\n\n            return router.RegisterAsync(address, previousAddress, hopCount);\n        }\n\n        public Task RegisterMany(List<GrainAddress> addresses)\n        {\n            if (addresses == null || addresses.Count == 0)\n            {\n                throw new ArgumentException(\"Addresses cannot be an empty list or null\");\n            }\n\n            // validate that this request arrived correctly\n            //logger.Assert(ErrorCode.Runtime_Error_100140, silo.Matches(router.MyAddress), \"destination address != my address\");\n\n            LogRegisterMany(addresses.Count);\n\n            return Task.WhenAll(addresses.Select(addr => router.RegisterAsync(addr, previousAddress: null, 1)));\n        }\n\n        public Task UnregisterAsync(GrainAddress address, UnregistrationCause cause, int hopCount)\n        {\n            return router.UnregisterAsync(address, cause, hopCount);\n        }\n\n        public Task UnregisterManyAsync(List<GrainAddress> addresses, UnregistrationCause cause, int hopCount)\n        {\n            return router.UnregisterManyAsync(addresses, cause, hopCount);\n        }\n\n        public Task DeleteGrainAsync(GrainId grainId, int hopCount)\n        {\n            return router.DeleteGrainAsync(grainId, hopCount);\n        }\n\n        public Task<AddressAndTag> LookupAsync(GrainId grainId, int hopCount)\n        {\n            return router.LookupAsync(grainId, hopCount);\n        }\n\n        public Task<List<AddressAndTag>> LookUpMany(List<(GrainId GrainId, int Version)> grainAndETagList)\n        {\n            DirectoryInstruments.ValidationsCacheReceived.Add(1);\n            LogLookUpMany(grainAndETagList.Count);\n\n            var result = new List<AddressAndTag>();\n\n            foreach (var tuple in grainAndETagList)\n            {\n                int curGen = partition.GetGrainETag(tuple.GrainId);\n                if (curGen == tuple.Version || curGen == GrainInfo.NO_ETAG)\n                {\n                    // the grain entry either does not exist in the local partition (curGen = -1) or has not been updated\n\n                    result.Add(new(GrainAddress.GetAddress(null, tuple.GrainId, default), curGen));\n                }\n                else\n                {\n                    // the grain entry has been updated -- fetch and return its current version\n                    var lookupResult = partition.LookUpActivation(tuple.GrainId);\n                    // validate that the entry is still in the directory (i.e., it was not removed concurrently)\n                    if (lookupResult.Address != null)\n                    {\n                        result.Add(lookupResult);\n                    }\n                    else\n                    {\n                        result.Add(new(GrainAddress.GetAddress(null, tuple.GrainId, default), GrainInfo.NO_ETAG));\n                    }\n                }\n            }\n\n            return Task.FromResult(result);\n        }\n\n        public Task AcceptSplitPartition(List<GrainAddress> singleActivations)\n        {\n            router.HandoffManager.AcceptExistingRegistrations(singleActivations);\n            return Task.CompletedTask;\n        }\n\n        public Task<AddressAndTag> RegisterAsync(GrainAddress address, int hopCount = 0) => router.RegisterAsync(address, hopCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"RegisterMany Count={Count}\"\n        )]\n        private partial void LogRegisterMany(int count);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"LookUpMany for {Count} entries\"\n        )]\n        private partial void LogLookUpMany(int count);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/RingRange.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n/// <summary>\n/// Represents a contiguous range of zero or more values on a ring.\n/// </summary>\n[GenerateSerializer, Immutable, Alias(nameof(RingRange))]\ninternal readonly struct RingRange : IEquatable<RingRange>, ISpanFormattable, IComparable<uint>\n{\n    // The exclusive starting point for the range.\n    //  Note that _start == _end == 1 is used as a special value to represent a full range.\n    [Id(0)]\n    private readonly uint _start;\n\n    // The inclusive ending point for the range.\n    //  Note that _start == _end == 1 is used as a special value to represent a full range.\n    [Id(1)]\n    private readonly uint _end;\n\n    public bool IsEmpty => _start == _end && _start == 0;\n\n    public bool IsFull => _start == _end && _start != 0;\n\n    // Whether the range includes uint.MaxValue.\n    internal bool IsWrapped => _start >= _end && _start != 0;\n\n    public static RingRange Full { get; } = new (1, 1);\n\n    public static RingRange Empty { get; } = new (0, 0);\n\n    public uint Start => IsFull ? 0 : _start;\n\n    public uint End => IsFull ? 0 : _end;\n\n    private RingRange(uint start, uint end)\n    {\n        _start = start == end && start > 1 ? 1 : start;\n        _end = start == end && start > 1 ? 1 : end;\n    }\n\n    // For internal use only.\n    internal static RingRange Create(uint start, uint end) => new (start, end);\n\n    /// <summary>\n    /// Creates a range representing a single point.\n    /// </summary>\n    /// <param name=\"point\">The point which the range will include.</param>\n    /// <returns>A range including only <paramref name=\"point\"/>.</returns>\n    public static RingRange FromPoint(uint point) => new (unchecked(point - 1), point);\n\n    /// <summary>\n    /// Gets the size of the range.\n    /// </summary>\n    public uint Size\n    {\n        get\n        {\n            if (_start == _end)\n            {\n                // Empty\n                if (_start == 0) return 0;\n\n                // Full\n                return uint.MaxValue;\n            }\n\n            // Normal\n            if (_end > _start) return _end - _start;\n\n            // Wrapped\n            return uint.MaxValue - _start + _end;\n        }\n    }\n\n    public int CompareTo(uint point)\n    {\n        if (Contains(point))\n        {\n            return 0;\n        }\n\n        var start = Start;\n        if (IsWrapped)\n        {\n            // Start > End (wrap-around case)\n            if (point <= start)\n            {\n                // Range starts after N (range > N)\n                return -1;\n            }\n\n            // n > _end\n            // Range starts & ends before N (range < N)\n            return 1;\n        }\n\n        if (point <= start)\n        {\n            // Range starts after N (range > N)\n            return 1;\n        }\n\n        // n > _end\n        // Range starts & ends before N (range < N)\n        return -1;\n    }\n\n    /// <summary>\n    /// Checks if n is element of (Start, End], while remembering that the ranges are on a ring\n    /// </summary>\n    /// <returns>true if n is in (Start, End], false otherwise</returns>\n    internal bool Contains(GrainId grainId) => Contains(grainId.GetUniformHashCode());\n\n    /// <summary>\n    /// checks if n is element of (Start, End], while remembering that the ranges are on a ring\n    /// </summary>\n    /// <param name=\"point\"></param>\n    /// <returns>true if n is in (Start, End], false otherwise</returns>\n    public bool Contains(uint point)\n    {\n        if (IsEmpty)\n        {\n            return false;\n        }\n\n        var num = point;\n        if (Start < End)\n        {\n            return num > Start && num <= End;\n        }\n\n        // Start > End\n        return num > Start || num <= End;\n    }\n\n    public float SizePercent => Size * (100.0f / uint.MaxValue);\n\n    public bool Equals(RingRange other) => _start == other._start && _end == other._end;\n\n    public override bool Equals(object? obj) => obj is RingRange other && Equals(other);\n\n    public override int GetHashCode() => HashCode.Combine(_start, _end);\n\n    public override string ToString() => $\"{this}\";\n\n    string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n    bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n    {\n        return IsEmpty\n            ? destination.TryWrite($\"(0, 0) 0.00%\", out charsWritten)\n            : IsFull\n                ? destination.TryWrite($\"(0, 0] (100.00%)\", out charsWritten)\n                : destination.TryWrite($\"(0x{Start:X8}, 0x{End:X8}] ({SizePercent:0.00}%)\", out charsWritten);\n    }\n\n    public bool Intersects(RingRange other) => !IsEmpty && !other.IsEmpty && (Equals(other) || Contains(other.End) || other.Contains(End));\n\n    internal RingRange Complement()\n    {\n        if (IsEmpty)\n        {\n            return Full;\n        }\n\n        if (IsFull)\n        {\n            return Empty;\n        }\n\n        return new RingRange(End, Start);\n    }\n\n    internal IEnumerable<RingRange> Intersections(RingRange other)\n    {\n        if (!Intersects(other))\n        {\n            // No intersections.\n            yield break;\n        }\n\n        if (IsFull)\n        {\n            // One intersection, the other range.\n            yield return other;\n        }\n        else if (other.IsFull)\n        {\n            yield return this;\n        }\n        else if (IsWrapped ^ other.IsWrapped)\n        {\n            var wrapped = IsWrapped ? this : other;\n            var normal = IsWrapped ? other : this;\n            var (normalStart, normalEnd) = (normal.Start, normal.End);\n            var (wrappedStart, wrappedEnd) = (wrapped.Start, wrapped.End);\n\n            // There are possibly two intersections, between the normal and wrapped range.\n            //         low         high\n            // ...---NB====WE----WB====NE----...\n\n            // Intersection at the low side.\n            if (wrappedEnd > normalStart)\n            {\n                // ---NB====WE---\n                yield return new RingRange(normalStart, wrappedEnd);\n            }\n\n            // Intersection at the high side.\n            if (wrappedStart < normalEnd)\n            {\n                // ---WB====NE---\n                yield return new RingRange(wrappedStart, normalEnd);\n            }\n        }\n        else\n        {\n            yield return new RingRange(Math.Max(Start, other.Start), Math.Min(End, other.End));\n        }\n    }\n\n    // Gets the set difference: the sub-ranges which are in this range but are not in the 'other' range.\n    internal IEnumerable<RingRange> Difference(RingRange other)\n    {\n        // Additions are the intersections between this range and the inverse of the previous range.\n        foreach (var addition in Intersections(other.Complement()))\n        {\n            Debug.Assert(!addition.Intersects(other));\n            Debug.Assert(addition.Intersects(this));\n            yield return addition;\n        }\n    }\n\n    public static bool operator ==(RingRange left, RingRange right) => left.Equals(right);\n\n    public static bool operator !=(RingRange left, RingRange right) => !(left == right);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/GrainDirectory/RingRangeCollection.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Linq;\nusing Orleans.Runtime.Utilities;\n\n#nullable enable\nnamespace Orleans.Runtime.GrainDirectory;\n\n// Read-only, sorted collection of non-overlapping ranges.\n[GenerateSerializer, Immutable, Alias(nameof(RingRangeCollection))]\ninternal readonly struct RingRangeCollection : IEquatable<RingRangeCollection>, ISpanFormattable, IEnumerable<RingRange>\n{\n    public RingRangeCollection(ImmutableArray<RingRange> ranges)\n    {\n#if DEBUG\n        Debug.Assert(!ranges.IsDefault);\n\n        // Ranges must be in sorted order and must not overlap with each other.\n        for (var i = 1; i < ranges.Length; i++)\n        {\n            var prev = ranges[i - 1];\n            var curr = ranges[i];\n            Debug.Assert(!curr.IsEmpty);\n            Debug.Assert(!prev.Intersects(curr));\n            Debug.Assert(curr.Start >= prev.Start);\n        }\n\n        if (ranges.Length > 1)\n        {\n            Debug.Assert(!ranges[0].Intersects(ranges[^1]));\n        }\n#endif\n        Ranges = ranges;\n    }\n\n    public static RingRangeCollection Create<TCollection>(TCollection ranges) where TCollection : ICollection<RingRange>\n    {\n        ArgumentNullException.ThrowIfNull(ranges);\n        var result = ImmutableArray.CreateBuilder<RingRange>(ranges.Count);\n        foreach (var range in ranges)\n        {\n            if (range.IsEmpty)\n            {\n                continue;\n            }\n\n            result.AddRange(range);\n        }\n\n        result.Sort((l, r) => l.Start.CompareTo(r.Start));\n        return new(result.ToImmutable());\n    }\n\n    public static RingRangeCollection Empty { get; } = new([]);\n\n    [Id(0)]\n    public ImmutableArray<RingRange> Ranges { get; }\n\n    public bool IsDefault => Ranges.IsDefault;\n\n    public bool IsEmpty => Ranges.Length == 0 || Ranges.All(r => r.IsEmpty);\n\n    public bool IsFull => !IsEmpty && Ranges.Sum(r => r.Size) == uint.MaxValue;\n\n    public uint Size => (uint)Ranges.Sum(static r => r.Size);\n\n    public float SizePercent => Size * (100.0f / uint.MaxValue);\n\n    public bool Contains(GrainId grainId) => Contains(grainId.GetUniformHashCode());\n\n    public bool Contains(uint value)\n    {\n        return SearchAlgorithms.RingRangeBinarySearch(\n            Ranges.Length,\n            Ranges,\n            static (ranges, index) => ranges[index],\n            value) >= 0;\n    }\n\n    public bool Intersects(RingRange other)\n    {\n        if (IsEmpty || other.IsEmpty)\n        {\n            return false;\n        }\n\n        if (Contains(other.End))\n        {\n            return true;\n        }\n\n        foreach (var range in Ranges)\n        {\n            if (other.Contains(range.End))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public bool Intersects(RingRangeCollection other)\n    {\n        if (IsEmpty || other.IsEmpty)\n        {\n            return false;\n        }\n\n        foreach (var range in Ranges)\n        {\n            if (other.Contains(range.End))\n            {\n                return true;\n            }\n        }\n\n        foreach (var otherRange in other.Ranges)\n        {\n            if (Contains(otherRange.End))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public RingRangeCollection Difference(RingRangeCollection previous)\n    {\n        // Ranges in left must not overlap with each other.\n        // Ranges in right must not overlap with each other.\n        // Corresponding ranges in left and right have the same starting points.\n        // The number of ranges in both 'Ranges' or 'previous.Ranges' is either zero or the configured number of ranges,\n        // i.e., if both collections have more than zero ranges, the both have the same number of ranges.\n        if (Ranges.Length == previous.Ranges.Length)\n        {\n            var result = ImmutableArray.CreateBuilder<RingRange>(Ranges.Length);\n            for (var i = 0; i < Ranges.Length; i++)\n            {\n                var c = Ranges[i];\n                var p = previous.Ranges[i];\n                Debug.Assert(c.Start == p.Start);\n                if (c.Size > p.Size)\n                {\n                    result.Add(RingRange.Create(p.End, c.End));\n                }\n            }\n\n            // If the last range wrapped around but its extension does not wrap around, move it to the front.\n            // This preserves sort order.\n            if (result.Count > 1 && result[^1].Start < result[^2].Start)\n            {\n                var last = result[^1];\n                result.RemoveAt(result.Count - 1);\n                result.Insert(0, last);\n            }\n\n            return new(result.ToImmutable());\n        }\n        else\n        {\n            if (Ranges.Length > previous.Ranges.Length)\n            {\n                Debug.Assert(previous.Ranges.Length == 0);\n                return this;\n            }\n            else\n            {\n                Debug.Assert(Ranges.Length == 0 ^ previous.Ranges.Length == 0);\n                return Empty;\n            }\n        }\n    }\n\n    public bool Equals(RingRangeCollection other)\n    {\n        if (IsEmpty && other.IsEmpty)\n        {\n            return true;\n        }\n\n        if (IsEmpty ^ other.IsEmpty)\n        {\n            return false;\n        }\n\n        return Ranges.SequenceEqual(other.Ranges);\n    }\n\n    public static bool operator ==(RingRangeCollection left, RingRangeCollection right) => left.Equals(right);\n\n    public static bool operator !=(RingRangeCollection left, RingRangeCollection right) => !(left == right);\n\n    public override bool Equals(object? obj) => obj is RingRangeCollection range && Equals(range);\n\n    public override int GetHashCode()\n    {\n        var result = new HashCode();\n        result.Add(Ranges.Length);\n        if (!Ranges.IsDefaultOrEmpty)\n        {\n            foreach (var range in Ranges)\n            {\n                result.Add(range);\n            }\n        }\n\n        return result.ToHashCode();\n    }\n\n    public ImmutableArray<RingRange>.Enumerator GetEnumerator() => Ranges.GetEnumerator();\n\n    public override string ToString() => $\"{this}\";\n    string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n    bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        => destination.TryWrite($\"({Ranges.Length} subranges), {SizePercent:0.00}%\", out charsWritten);\n    IEnumerator<RingRange> IEnumerable<RingRange>.GetEnumerator() => ((IEnumerable<RingRange>)Ranges).GetEnumerator();\n    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)Ranges).GetEnumerator();\n}"
  },
  {
    "path": "src/Orleans.Runtime/GrainTypeManager/ClusterManifestSystemTarget.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    internal sealed class ClusterManifestSystemTarget : SystemTarget, IClusterManifestSystemTarget, ISiloManifestSystemTarget, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly GrainManifest _siloManifest;\n        private readonly IClusterMembershipService _clusterMembershipService;\n        private readonly IClusterManifestProvider _clusterManifestProvider;\n        private readonly ClusterManifestUpdate _noUpdate = default;\n        private MembershipVersion _cachedMembershipVersion;\n        private ClusterManifestUpdate _cachedUpdate;\n\n        public ClusterManifestSystemTarget(\n            IClusterMembershipService clusterMembershipService,\n            IClusterManifestProvider clusterManifestProvider,\n            SystemTargetShared shared)\n            : base(Constants.ManifestProviderType, shared)\n        {\n            _siloManifest = clusterManifestProvider.LocalGrainManifest;\n            _clusterMembershipService = clusterMembershipService;\n            _clusterManifestProvider = clusterManifestProvider;\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public ValueTask<ClusterManifest> GetClusterManifest() => new(_clusterManifestProvider.Current);\n        public ValueTask<ClusterManifestUpdate> GetClusterManifestUpdate(MajorMinorVersion version)\n        {\n            var manifest = _clusterManifestProvider.Current;\n\n            // Only return an updated manifest if it is newer than the provided version.\n            if (manifest.Version <= version)\n            {\n                return new (_noUpdate);\n            }\n\n            // Maintain a cache of whether the current manifest contains all active servers so that it\n            // does not need to be recomputed each time.\n            var membershipSnapshot = _clusterMembershipService.CurrentSnapshot;\n            if (_cachedUpdate is null\n                || membershipSnapshot.Version > _cachedMembershipVersion\n                || manifest.Version > _cachedUpdate.Version)\n            {\n                var includesAllActiveServers = true;\n                foreach (var server in membershipSnapshot.Members)\n                {\n                    if (server.Value.Status == SiloStatus.Active)\n                    {\n                        if (!manifest.Silos.ContainsKey(server.Key))\n                        {\n                            includesAllActiveServers = false;\n                        }\n                    }\n                }\n\n                _cachedUpdate = new ClusterManifestUpdate(manifest.Version, manifest.Silos, includesAllActiveServers);\n                _cachedMembershipVersion = membershipSnapshot.Version;\n            }\n\n            return new (_cachedUpdate);\n        }\n\n        public ValueTask<GrainManifest> GetSiloManifest() => new(_siloManifest);\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            // We don't participate in any lifecycle stages: activating this instance is all that is necessary.\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/GrainTypeManager/ISiloManifestSystemTarget.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Metadata;\n\nnamespace Orleans.Runtime\n{\n    internal interface ISiloManifestSystemTarget : ISystemTarget\n    {\n        ValueTask<GrainManifest> GetSiloManifest();\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/ActivationRebalancerExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Configuration.Internal;\nusing Orleans.Placement.Rebalancing;\nusing Orleans.Runtime.Placement.Rebalancing;\n\nnamespace Orleans.Hosting;\n\n#nullable enable\n\n/// <summary>\n/// Extensions for configuring activation rebalancing.\n/// </summary>\npublic static class ActivationRebalancerExtensions\n{\n    /// <summary>\n    /// Enables activation rebalancing for the entire cluster.\n    /// </summary>\n    /// <remarks>\n    /// Activation rebalancing attempts to distribute activations around the cluster in such a\n    /// way that it optimizes both activation count and memory usages across the silos of the cluster.\n    /// <para>You can read more on activation rebalancing <see href=\"https://www.ledjonbehluli.com/posts/orleans_adaptive_rebalancing/\">here</see></para>\n    /// </remarks>\n    [Experimental(\"ORLEANSEXP002\")]\n    public static ISiloBuilder AddActivationRebalancer(this ISiloBuilder builder) =>\n        builder.AddActivationRebalancer<FailedSessionBackoffProvider>();\n\n    /// <inheritdoc cref=\"AddActivationRebalancer(ISiloBuilder)\"/>.\n    /// <typeparam name=\"TProvider\">Custom backoff provider for determining next session after a failed attempt.</typeparam>\n    [Experimental(\"ORLEANSEXP002\")]\n    public static ISiloBuilder AddActivationRebalancer<TProvider>(this ISiloBuilder builder)\n        where TProvider : class, IFailedSessionBackoffProvider =>\n        builder.ConfigureServices(service => service.AddActivationRebalancer<TProvider>());\n\n    private static IServiceCollection AddActivationRebalancer<TProvider>(this IServiceCollection services)\n        where TProvider : class, IFailedSessionBackoffProvider\n    {\n        services.AddSingleton<ActivationRebalancerMonitor>();\n        services.AddFromExisting<IActivationRebalancer, ActivationRebalancerMonitor>();\n        services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ActivationRebalancerMonitor>();\n        services.AddTransient<IConfigurationValidator, ActivationRebalancerOptionsValidator>();\n        \n        services.AddSingleton<TProvider>();\n        services.AddFromExisting<IFailedSessionBackoffProvider, TProvider>();\n        if (typeof(TProvider).IsAssignableTo(typeof(ILifecycleParticipant<ISiloLifecycle>)))\n        {\n            services.AddFromExisting(typeof(ILifecycleParticipant<ISiloLifecycle>), typeof(TProvider));\n        }\n\n        return services;\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/ActivationRepartitioningExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Placement.Repartitioning;\n\nnamespace Orleans.Hosting;\n\n#nullable enable\npublic static class ActivationRepartitioningExtensions\n{\n    /// <summary>\n    /// Enables activation repartitioning for this silo.\n    /// </summary>\n    /// <remarks>\n    /// Activation repartitioning attempts to optimize grain call locality by collocating activations which communicate frequently,\n    /// while keeping the number of activations on each silo approximately equal.\n    /// </remarks>\n    [Experimental(\"ORLEANSEXP001\")]\n    public static ISiloBuilder AddActivationRepartitioner(this ISiloBuilder builder)\n        => builder.AddActivationRepartitioner<RebalancerCompatibleRule>();\n\n    /// <summary>\n    /// Enables activation repartitioning for this silo.\n    /// </summary>\n    /// <remarks>\n    /// Activation repartitioning attempts to optimize grain call locality by collocating activations which communicate frequently,\n    /// while keeping the number of activations on each silo approximately equal.\n    /// </remarks>\n    /// <typeparam name=\"TRule\">The type of the imbalance rule to use.</typeparam>\n    [Experimental(\"ORLEANSEXP001\")]\n    public static ISiloBuilder AddActivationRepartitioner<TRule>(this ISiloBuilder builder) where TRule : class, IImbalanceToleranceRule\n        => builder\n            .ConfigureServices(services => services.AddActivationRepartitioner<TRule>());\n\n    private static IServiceCollection AddActivationRepartitioner<TRule>(this IServiceCollection services) where TRule : class, IImbalanceToleranceRule\n    {\n        services.AddSingleton<ActivationRepartitioner>();\n        services.AddSingleton<IRepartitionerMessageFilter, RepartitionerMessageFilter>();\n        services.AddFromExisting<IMessageStatisticsSink, ActivationRepartitioner>();\n        services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ActivationRepartitioner>();\n        services.AddTransient<IConfigurationValidator, ActivationRepartitionerOptionsValidator>();\n\n        services.AddSingleton<TRule>();\n        services.AddFromExisting<IImbalanceToleranceRule, TRule>();\n        if (typeof(TRule).IsAssignableTo(typeof(ILifecycleParticipant<ISiloLifecycle>)))\n        {\n            services.AddFromExisting(typeof(ILifecycleParticipant<ISiloLifecycle>), typeof(TRule));\n        }\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/CoreHostingExtensions.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for <see cref=\"ISiloBuilder\"/> instances.\n    /// </summary>\n    public static class CoreHostingExtensions\n    {\n        private static readonly ServiceDescriptor DirectoryDescriptor = ServiceDescriptor.Singleton<DistributedGrainDirectory, DistributedGrainDirectory>();\n\n        /// <summary>\n        /// Add <see cref=\"Activity.Current\"/> propagation through grain calls.\n        /// Note: according to <see cref=\"ActivitySource.StartActivity(string, ActivityKind)\"/> activity will be created only when any listener for activity exists <see cref=\"ActivitySource.HasListeners()\"/> and <see cref=\"ActivityListener.Sample\"/> returns <see cref=\"ActivitySamplingResult.PropagationData\"/>.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddActivityPropagation(this ISiloBuilder builder)\n        {\n            builder.Services.TryAddSingleton(DistributedContextPropagator.Current);\n\n            return builder\n                .AddOutgoingGrainCallFilter<ActivityPropagationOutgoingGrainCallFilter>()\n                .AddIncomingGrainCallFilter<ActivityPropagationIncomingGrainCallFilter>();\n        }\n\n        /// <summary>\n        /// Configures the silo to use development-only clustering and listen on localhost.\n        /// </summary>\n        /// <param name=\"builder\">The silo builder.</param>\n        /// <param name=\"siloPort\">The silo port.</param>\n        /// <param name=\"gatewayPort\">The gateway port.</param>\n        /// <param name=\"primarySiloEndpoint\">\n        /// The endpoint of the primary silo, or <see langword=\"null\"/> to use this silo as the primary.\n        /// </param>\n        /// <param name=\"serviceId\">The service id.</param>\n        /// <param name=\"clusterId\">The cluster id.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder UseLocalhostClustering(\n            this ISiloBuilder builder,\n            int siloPort = EndpointOptions.DEFAULT_SILO_PORT,\n            int gatewayPort = EndpointOptions.DEFAULT_GATEWAY_PORT,\n            IPEndPoint? primarySiloEndpoint = null,\n            string serviceId = ClusterOptions.DevelopmentServiceId,\n            string clusterId = ClusterOptions.DevelopmentClusterId)\n        {\n            builder.Configure<EndpointOptions>(options =>\n            {\n                options.AdvertisedIPAddress = IPAddress.Loopback;\n                options.SiloPort = siloPort;\n                options.GatewayPort = gatewayPort;\n            });\n\n            builder.UseDevelopmentClustering(optionsBuilder => ConfigurePrimarySiloEndpoint(optionsBuilder, primarySiloEndpoint));\n            builder.ConfigureServices(services =>\n            {\n                // If the caller did not override service id or cluster id, configure default values as a fallback.\n                if (string.Equals(serviceId, ClusterOptions.DevelopmentServiceId) && string.Equals(clusterId, ClusterOptions.DevelopmentClusterId))\n                {\n                    services.PostConfigure<ClusterOptions>(options =>\n                    {\n                        if (string.IsNullOrWhiteSpace(options.ClusterId)) options.ClusterId = ClusterOptions.DevelopmentClusterId;\n                        if (string.IsNullOrWhiteSpace(options.ServiceId)) options.ServiceId = ClusterOptions.DevelopmentServiceId;\n                    });\n                }\n                else\n                {\n                    services.Configure<ClusterOptions>(options =>\n                    {\n                        options.ServiceId = serviceId;\n                        options.ClusterId = clusterId;\n                    });\n                }\n            });\n\n            return builder;\n        }\n\n        /// <summary>\n        /// Configures the silo to use development-only clustering.\n        /// </summary>\n        /// <param name=\"builder\"></param>\n        /// <param name=\"primarySiloEndpoint\">\n        /// The endpoint of the primary silo, or <see langword=\"null\"/> to use this silo as the primary.\n        /// </param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder UseDevelopmentClustering(this ISiloBuilder builder, IPEndPoint primarySiloEndpoint)\n        {\n            return builder.UseDevelopmentClustering(optionsBuilder => ConfigurePrimarySiloEndpoint(optionsBuilder, primarySiloEndpoint));\n        }\n\n        /// <summary>\n        /// Configures the silo to use development-only clustering.\n        /// </summary>\n        public static ISiloBuilder UseDevelopmentClustering(\n            this ISiloBuilder builder,\n            Action<DevelopmentClusterMembershipOptions> configureOptions)\n        {\n            return builder.UseDevelopmentClustering(options => options.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configures the silo to use development-only clustering.\n        /// </summary>\n        public static ISiloBuilder UseDevelopmentClustering(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<DevelopmentClusterMembershipOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(\n                services =>\n                {\n                    configureOptions?.Invoke(services.AddOptions<DevelopmentClusterMembershipOptions>());\n                    services.ConfigureFormatter<DevelopmentClusterMembershipOptions>();\n                    services\n                        .AddSingleton<SystemTargetBasedMembershipTable>()\n                        .AddFromExisting<IMembershipTable, SystemTargetBasedMembershipTable>();\n                    services\n                        .AddSingleton<MembershipTableSystemTarget>()\n                        .AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, MembershipTableSystemTarget>();\n                });\n        }\n\n        private static void ConfigurePrimarySiloEndpoint(OptionsBuilder<DevelopmentClusterMembershipOptions> optionsBuilder, IPEndPoint? primarySiloEndpoint)\n        {\n            optionsBuilder.Configure((DevelopmentClusterMembershipOptions options, IOptions<EndpointOptions> endpointOptions) =>\n            {\n                if (primarySiloEndpoint is null)\n                {\n                    primarySiloEndpoint = endpointOptions.Value.GetPublicSiloEndpoint();\n                }\n\n                options.PrimarySiloEndpoint = primarySiloEndpoint;\n            });\n        }\n\n        /// <summary>\n        /// Opts-in to the experimental distributed grain directory.\n        /// </summary>\n        /// <param name=\"siloBuilder\">The silo builder to register the directory implementation with.</param>\n        /// <param name=\"name\">The name of the directory to register, or null to register the directory as the default.</param>\n        /// <returns>The provided silo builder.</returns>\n        [Experimental(\"ORLEANSEXP003\")]\n        public static ISiloBuilder AddDistributedGrainDirectory(this ISiloBuilder siloBuilder, string? name = null)\n        {\n            var services = siloBuilder.Services;\n            if (string.IsNullOrEmpty(name))\n            {\n                name = GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY;\n            }\n\n            // Distributed Grain Directory\n            services.TryAddSingleton<DirectoryMembershipService>();\n            if (!services.Contains(DirectoryDescriptor))\n            {\n                services.Add(DirectoryDescriptor);\n                services.AddGrainDirectory<DistributedGrainDirectory>(name, (sp, name) => sp.GetRequiredService<DistributedGrainDirectory>());\n            }\n\n            return siloBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/DefaultSiloServices.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.Configuration.Validators;\nusing Orleans.Core;\nusing Orleans.GrainReferences;\nusing Orleans.Metadata;\nusing Orleans.Networking.Shared;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Configuration;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Metadata;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Placement.Filtering;\nusing Orleans.Runtime.Providers;\nusing Orleans.Runtime.Utilities;\nusing Orleans.Runtime.Versions;\nusing Orleans.Runtime.Versions.Compatibility;\nusing Orleans.Runtime.Versions.Selector;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Internal;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Statistics;\nusing Orleans.Storage;\nusing Orleans.Timers;\nusing Orleans.Timers.Internal;\nusing Orleans.Versions;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Hosting\n{\n    internal static class DefaultSiloServices\n    {\n        private static readonly ServiceDescriptor ServiceDescriptor = new(typeof(ServicesAdded), new ServicesAdded());\n\n        internal static void AddDefaultServices(ISiloBuilder builder)\n        {\n            var services = builder.Services;\n            if (services.Contains(ServiceDescriptor))\n            {\n                return;\n            }\n\n            services.Add(ServiceDescriptor);\n\n            // Common services\n            services.AddLogging();\n            services.AddOptions();\n            services.AddMetrics();\n            services.TryAddSingleton<TimeProvider>(TimeProvider.System);\n            services.TryAddSingleton<OrleansInstruments>();\n\n            services.TryAddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.TryAddSingleton(typeof(IOptionFormatterResolver<>), typeof(DefaultOptionsFormatterResolver<>));\n\n            services.AddSingleton<Silo>();\n            services.AddSingleton<Watchdog>();\n            services.AddHostedService<SiloHostedService>();\n            services.PostConfigure<SiloOptions>(options => options.SiloName ??= $\"Silo_{Guid.NewGuid().ToString(\"N\")[..5]}\");\n            services.TryAddSingleton<ILocalSiloDetails, LocalSiloDetails>();\n            services.TryAddSingleton<SiloLifecycleSubject>();\n            services.TryAddFromExisting<ISiloLifecycleSubject, SiloLifecycleSubject>();\n            services.TryAddFromExisting<ISiloLifecycle, SiloLifecycleSubject>();\n            services.AddSingleton<SiloOptionsLogger>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, SiloOptionsLogger>();\n            services.AddSingleton<SiloControl>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, SiloControl>();\n\n            // Lifecycle\n            services.AddSingleton<ServiceLifecycle<ISiloLifecycle>>();\n            services.TryAddFromExisting<IServiceLifecycle, ServiceLifecycle<ISiloLifecycle>>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ServiceLifecycle<ISiloLifecycle>>();\n\n            // Statistics\n            services.AddSingleton<IEnvironmentStatisticsProvider, EnvironmentStatisticsProvider>();\n#pragma warning disable 618\n            services.AddSingleton<OldEnvironmentStatistics>();\n            services.AddFromExisting<IAppEnvironmentStatistics, OldEnvironmentStatistics>();\n            services.AddFromExisting<IHostEnvironmentStatistics, OldEnvironmentStatistics>();\n#pragma warning restore 618\n\n            services.TryAddSingleton<OverloadDetector>();\n            services.TryAddFromExisting<IOverloadDetector, OverloadDetector>();\n\n            services.AddSingleton<SystemTargetShared>();\n\n            services.TryAddSingleton<ITimerRegistry, TimerRegistry>();\n\n            services.TryAddSingleton<GrainRuntime>();\n            services.TryAddSingleton<IGrainRuntime, GrainRuntime>();\n            services.TryAddSingleton<IGrainCancellationTokenRuntime, GrainCancellationTokenRuntime>();\n            services.AddTransient<CancellationSourcesExtension>();\n            services.AddKeyedTransient<IGrainExtension>(typeof(ICancellationSourcesExtension), (sp, _) => sp.GetRequiredService<CancellationSourcesExtension>());\n            services.TryAddSingleton<GrainFactory>(sp => sp.GetRequiredService<InsideRuntimeClient>().ConcreteGrainFactory);\n            services.TryAddSingleton<InterfaceToImplementationMappingCache>();\n            services.TryAddSingleton<GrainInterfaceTypeToGrainTypeResolver>();\n            services.TryAddFromExisting<IGrainFactory, GrainFactory>();\n            services.TryAddFromExisting<IInternalGrainFactory, GrainFactory>();\n            services.TryAddSingleton<IGrainReferenceRuntime, GrainReferenceRuntime>();\n            services.TryAddSingleton<GrainReferenceActivator>();\n            services.AddSingleton<IGrainReferenceActivatorProvider, GrainReferenceActivatorProvider>();\n            services.AddSingleton<IGrainReferenceActivatorProvider, UntypedGrainReferenceActivatorProvider>();\n            services.AddSingleton<IConfigureGrainContextProvider, MayInterleaveConfiguratorProvider>();\n            services.AddSingleton<IConfigureGrainTypeComponents, ReentrantSharedComponentsConfigurator>();\n            services.TryAddSingleton<RpcProvider>();\n            services.AddSingleton<GrainVersionManifest>();\n            services.TryAddSingleton<GrainBindingsResolver>();\n            services.TryAddSingleton<GrainTypeSharedContextResolver>();\n            services.TryAddSingleton<ActivationDirectory>();\n            services.TryAddSingleton<GrainCountStatistics>();\n            services.AddSingleton<ActivationCollector>();\n            services.AddFromExisting<IActivationWorkingSetObserver, ActivationCollector>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ActivationCollector>();\n\n            services.AddSingleton<ActivationWorkingSet>();\n            services.AddFromExisting<IActivationWorkingSet, ActivationWorkingSet>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ActivationWorkingSet>();\n\n            // Directory\n            services.TryAddSingleton<LocalGrainDirectory>();\n            services.TryAddFromExisting<ILocalGrainDirectory, LocalGrainDirectory>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, LocalGrainDirectory>();\n            services.AddSingleton<GrainLocator>();\n            services.AddSingleton<GrainLocatorResolver>();\n            services.AddSingleton<DhtGrainLocator>(sp => DhtGrainLocator.FromLocalGrainDirectory(sp.GetService<LocalGrainDirectory>()));\n            services.AddSingleton<GrainDirectoryResolver>();\n            services.AddSingleton<IGrainDirectoryResolver, GenericGrainDirectoryResolver>();\n            services.AddSingleton<CachedGrainLocator>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, CachedGrainLocator>();\n            services.AddSingleton<ClientGrainLocator>();\n\n            services.TryAddSingleton<MessageCenter>();\n            services.TryAddFromExisting<IMessageCenter, MessageCenter>();\n            services.TryAddSingleton(FactoryUtility.Create<MessageCenter, Gateway>);\n            services.TryAddSingleton<IConnectedClientCollection>(sp => sp.GetRequiredService<MessageCenter>().Gateway as IConnectedClientCollection ?? new EmptyConnectedClientCollection());\n            services.TryAddSingleton<InternalGrainRuntime>();\n            services.TryAddSingleton<InsideRuntimeClient>();\n            services.TryAddFromExisting<IRuntimeClient, InsideRuntimeClient>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, InsideRuntimeClient>();\n            services.TryAddSingleton<IGrainServiceFactory, GrainServiceFactory>();\n\n            services.TryAddSingleton<IFatalErrorHandler, FatalErrorHandler>();\n\n            services.AddSingleton<DeploymentLoadPublisher>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, DeploymentLoadPublisher>();\n\n            services.AddSingleton<IAsyncTimerFactory, AsyncTimerFactory>();\n            services.AddSingleton<MembershipTableManager>();\n            services.AddFromExisting<IHealthCheckParticipant, MembershipTableManager>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, MembershipTableManager>();\n            services.AddSingleton<MembershipSystemTarget>();\n            services.AddFromExisting<IMembershipService, MembershipSystemTarget>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, MembershipSystemTarget>();\n            services.AddSingleton<IMembershipGossiper, MembershipGossiper>();\n            services.AddSingleton<IRemoteSiloProber, RemoteSiloProber>();\n            services.AddSingleton<SiloStatusOracle>();\n            services.TryAddFromExisting<ISiloStatusOracle, SiloStatusOracle>();\n            services.AddSingleton<ClusterHealthMonitor>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ClusterHealthMonitor>();\n            services.AddFromExisting<IHealthCheckParticipant, ClusterHealthMonitor>();\n            services.AddSingleton<ProbeRequestMonitor>();\n            services.AddSingleton<LocalSiloHealthMonitor>();\n            services.AddFromExisting<ILocalSiloHealthMonitor, LocalSiloHealthMonitor>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, LocalSiloHealthMonitor>();\n            services.AddSingleton<MembershipAgent>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, MembershipAgent>();\n            services.AddFromExisting<IHealthCheckParticipant, MembershipAgent>();\n            services.AddSingleton<MembershipTableCleanupAgent>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, MembershipTableCleanupAgent>();\n            services.AddFromExisting<IHealthCheckParticipant, MembershipTableCleanupAgent>();\n            services.AddSingleton<SiloStatusListenerManager>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, SiloStatusListenerManager>();\n            services.AddSingleton<ClusterMembershipService>();\n            services.TryAddFromExisting<IClusterMembershipService, ClusterMembershipService>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ClusterMembershipService>();\n\n            services.TryAddSingleton<ClientDirectory>();\n            services.AddFromExisting<ILocalClientDirectory, ClientDirectory>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ClientDirectory>();\n\n            services.TryAddSingleton<SiloProviderRuntime>();\n            services.TryAddFromExisting<IProviderRuntime, SiloProviderRuntime>();\n\n            services.TryAddSingleton<MessageFactory>();\n\n            services.TryAddSingleton(FactoryUtility.Create<LocalGrainDirectoryPartition>);\n\n            // Placement\n            services.AddSingleton<IConfigurationValidator, ActivationCountBasedPlacementOptionsValidator>();\n            services.AddSingleton<IConfigurationValidator, ResourceOptimizedPlacementOptionsValidator>();\n            services.AddSingleton<PlacementService>();\n            services.AddSingleton<PlacementStrategyResolver>();\n            services.AddSingleton<PlacementDirectorResolver>();\n            services.AddSingleton<IPlacementStrategyResolver, ClientObserverPlacementStrategyResolver>();\n\n            // Configure the default placement strategy.\n            services.TryAddSingleton<PlacementStrategy, ResourceOptimizedPlacement>();\n\n            // Placement filters\n            services.AddSingleton<PlacementFilterStrategyResolver>();\n            services.AddSingleton<PlacementFilterDirectorResolver>();\n\n            // Placement directors\n            services.AddPlacementDirector<RandomPlacement, RandomPlacementDirector>();\n            services.AddPlacementDirector<PreferLocalPlacement, PreferLocalPlacementDirector>();\n            services.AddPlacementDirector<StatelessWorkerPlacement, StatelessWorkerDirector>(ServiceLifetime.Transient);\n            services.AddPlacementDirector<ActivationCountBasedPlacement, ActivationCountPlacementDirector>();\n            services.AddPlacementDirector<HashBasedPlacement, HashBasedPlacementDirector>();\n            services.AddPlacementDirector<ClientObserversPlacement, ClientObserversPlacementDirector>();\n            services.AddPlacementDirector<SiloRoleBasedPlacement, SiloRoleBasedPlacementDirector>();\n            services.AddPlacementDirector<ResourceOptimizedPlacement, ResourceOptimizedPlacementDirector>();\n\n            // Versioning\n            services.TryAddSingleton<VersionSelectorManager>();\n            services.TryAddSingleton<CachedVersionSelectorManager>();\n            // Version selector strategy\n            if (!services.Any(x => x.ServiceType == typeof(IVersionStore)))\n            {\n                services.AddSingleton<GrainVersionStore>();\n                services.AddFromExisting<IVersionStore, GrainVersionStore>();\n            }\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, GrainVersionStore>();\n            services.AddKeyedSingleton<VersionSelectorStrategy, AllCompatibleVersions>(nameof(AllCompatibleVersions));\n            services.AddKeyedSingleton<VersionSelectorStrategy, LatestVersion>(nameof(LatestVersion));\n            services.AddKeyedSingleton<VersionSelectorStrategy, MinimumVersion>(nameof(MinimumVersion));\n            // Versions selectors\n            services.AddKeyedSingleton<IVersionSelector, MinimumVersionSelector>(typeof(MinimumVersion));\n            services.AddKeyedSingleton<IVersionSelector, LatestVersionSelector>(typeof(LatestVersion));\n            services.AddKeyedSingleton<IVersionSelector, AllCompatibleVersionsSelector>(typeof(AllCompatibleVersions));\n\n            // Compatibility\n            services.AddSingleton<CompatibilityDirectorManager>();\n            // Compatability strategy\n            services.AddKeyedSingleton<CompatibilityStrategy, AllVersionsCompatible>(nameof(AllVersionsCompatible));\n            services.AddKeyedSingleton<CompatibilityStrategy, BackwardCompatible>(nameof(BackwardCompatible));\n            services.AddKeyedSingleton<CompatibilityStrategy, StrictVersionCompatible>(nameof(StrictVersionCompatible));\n            // Compatability directors\n            services.AddKeyedSingleton<ICompatibilityDirector, BackwardCompatilityDirector>(typeof(BackwardCompatible));\n            services.AddKeyedSingleton<ICompatibilityDirector, AllVersionsCompatibilityDirector>(typeof(AllVersionsCompatible));\n            services.AddKeyedSingleton<ICompatibilityDirector, StrictVersionCompatibilityDirector>(typeof(StrictVersionCompatible));\n\n            services.TryAddSingleton<Factory<IGrainRuntime>>(sp => () => sp.GetRequiredService<IGrainRuntime>());\n\n            // Grain activation\n            services.AddSingleton<PlacementService>();\n            services.AddSingleton<Catalog>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, Catalog>();\n            services.AddSingleton<GrainContextActivator>();\n            services.AddSingleton<IConfigureGrainTypeComponents, ConfigureDefaultGrainActivator>();\n            services.AddSingleton<GrainReferenceActivator>();\n            services.AddSingleton<IGrainContextActivatorProvider, ActivationDataActivatorProvider>();\n            services.AddSingleton<IGrainContextAccessor, GrainContextAccessor>();\n            services.AddSingleton<IncomingRequestMonitor>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, IncomingRequestMonitor>();\n            services.AddFromExisting<IActivationWorkingSetObserver, IncomingRequestMonitor>();\n            services.AddSingleton<ILocalActivationStatusChecker, Runtime.LocalActivationStatusChecker>();\n\n            // Scoped to a grain activation\n            services.AddScoped<IGrainContext>(sp => RuntimeContext.Current ?? throw new InvalidOperationException(\"No current grain context available.\"));\n\n            services.TryAddSingleton<IConsistentRingProvider>(\n                sp =>\n                {\n                    // TODO: make this not sux - jbragg\n                    var consistentRingOptions = sp.GetRequiredService<IOptions<ConsistentRingOptions>>().Value;\n                    var siloDetails = sp.GetRequiredService<ILocalSiloDetails>();\n                    var loggerFactory = sp.GetRequiredService<ILoggerFactory>();\n                    var siloStatusOracle = sp.GetRequiredService<ISiloStatusOracle>();\n                    if (consistentRingOptions.UseVirtualBucketsConsistentRing)\n                    {\n                        return new VirtualBucketsRingProvider(siloDetails.SiloAddress, loggerFactory, consistentRingOptions.NumVirtualBucketsConsistentRing, siloStatusOracle);\n                    }\n\n                    return new ConsistentRingProvider(siloDetails.SiloAddress, loggerFactory, siloStatusOracle);\n                });\n\n            services.AddSingleton<IConfigureOptions<GrainTypeOptions>, DefaultGrainTypeOptionsProvider>();\n            services.AddSingleton<IPostConfigureOptions<EndpointOptions>, EndpointOptionsProvider>();\n\n            // Type metadata\n            services.AddSingleton<SiloManifestProvider>();\n            services.AddSingleton<GrainClassMap>(sp => sp.GetRequiredService<SiloManifestProvider>().GrainTypeMap);\n            services.AddSingleton<GrainTypeResolver>();\n            services.AddSingleton<IGrainTypeProvider, AttributeGrainTypeProvider>();\n            services.AddSingleton<GrainPropertiesResolver>();\n            services.AddSingleton<GrainInterfaceTypeResolver>();\n            services.AddSingleton<IGrainInterfaceTypeProvider, AttributeGrainInterfaceTypeProvider>();\n            services.AddSingleton<IGrainInterfacePropertiesProvider, AttributeGrainInterfacePropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, AttributeGrainPropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, AttributeGrainBindingsProvider>();\n            services.AddSingleton<IGrainInterfacePropertiesProvider, TypeNameGrainPropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, TypeNameGrainPropertiesProvider>();\n            services.AddSingleton<IGrainPropertiesProvider, ImplementedInterfaceProvider>();\n            services.AddSingleton<ClusterManifestProvider>();\n            services.AddFromExisting<IClusterManifestProvider, ClusterManifestProvider>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ClusterManifestProvider>();\n            services.AddSingleton<ClusterManifestSystemTarget>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ClusterManifestSystemTarget>();\n\n            //Add default option formatter if none is configured, for options which are required to be configured\n            services.ConfigureFormatter<SiloOptions>();\n            services.ConfigureFormatter<SchedulingOptions>();\n            services.ConfigureFormatter<ConnectionOptions>();\n            services.ConfigureFormatter<SiloMessagingOptions>();\n            services.ConfigureFormatter<ClusterMembershipOptions>();\n            services.ConfigureFormatter<GrainDirectoryOptions>();\n            services.ConfigureFormatter<ActivationCountBasedPlacementOptions>();\n            services.ConfigureFormatter<ResourceOptimizedPlacementOptions>();\n            services.ConfigureFormatter<GrainCollectionOptions>();\n            services.ConfigureFormatter<StatelessWorkerOptions>();\n            services.ConfigureFormatter<GrainVersioningOptions>();\n            services.ConfigureFormatter<ConsistentRingOptions>();\n            services.ConfigureFormatter<LoadSheddingOptions>();\n            services.ConfigureFormatter<EndpointOptions>();\n            services.ConfigureFormatter<ClusterOptions>();\n\n            // This validator needs to construct the IMembershipOracle and the IMembershipTable\n            // so move it in the end so other validator are called first\n            services.AddTransient<IConfigurationValidator, ClusterOptionsValidator>();\n            services.AddTransient<IConfigurationValidator, SiloClusteringValidator>();\n            services.AddTransient<IConfigurationValidator, DevelopmentClusterMembershipOptionsValidator>();\n            services.AddTransient<IConfigurationValidator, GrainTypeOptionsValidator>();\n            services.AddTransient<IValidateOptions<SiloMessagingOptions>, SiloMessagingOptionsValidator>();\n            services.AddTransient<IOptions<MessagingOptions>>(static sp => sp.GetRequiredService<IOptions<SiloMessagingOptions>>());\n\n            // Enable hosted client.\n            services.TryAddSingleton<HostedClient>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, HostedClient>();\n            services.TryAddSingleton<InternalClusterClient>();\n            services.TryAddFromExisting<IInternalClusterClient, InternalClusterClient>();\n            services.TryAddFromExisting<IClusterClient, InternalClusterClient>();\n\n            // Enable collection specific Age limits\n            services.AddOptions<GrainCollectionOptions>()\n                .Configure<IOptions<GrainTypeOptions>>((options, grainTypeOptions) =>\n                {\n                    foreach (var grainClass in grainTypeOptions.Value.Classes)\n                    {\n                        var attr = grainClass.GetCustomAttribute<CollectionAgeLimitAttribute>();\n                        if (attr != null)\n                        {\n                            var className = RuntimeTypeNameFormatter.Format(grainClass);\n                            options.ClassSpecificCollectionAge[className] = attr.AgeLimit;\n                        }\n                    }\n                });\n\n            // Validate all CollectionAgeLimit values for the right configuration.\n            services.AddTransient<IConfigurationValidator, GrainCollectionOptionsValidator>();\n            services.AddTransient<IConfigurationValidator, LoadSheddingValidator>();\n\n            services.TryAddSingleton<ITimerManager, TimerManagerImpl>();\n\n            // persistent state facet support\n            services.TryAddSingleton<IGrainStorageSerializer, JsonGrainStorageSerializer>();\n            services.TryAddSingleton<IPersistentStateFactory, PersistentStateFactory>();\n            services.TryAddSingleton(typeof(IAttributeToFactoryMapper<PersistentStateAttribute>), typeof(PersistentStateAttributeMapper));\n            services.TryAddSingleton<StateStorageBridgeSharedMap>();\n\n            // IAsyncEnumerable support\n            services.AddScoped<IAsyncEnumerableGrainExtension, AsyncEnumerableGrainExtension>();\n            services.AddKeyedTransient<IGrainExtension>(\n                typeof(IAsyncEnumerableGrainExtension),\n                (sp, _) => sp.GetRequiredService<IAsyncEnumerableGrainExtension>());\n\n            // Networking\n            services.TryAddSingleton<IMessageStatisticsSink, NoOpMessageStatisticsSink>();\n            services.TryAddSingleton<ConnectionCommon>();\n            services.TryAddSingleton<ConnectionManager>();\n            services.TryAddSingleton<ConnectionPreambleHelper>();\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, ConnectionManagerLifecycleAdapter<ISiloLifecycle>>();\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, SiloConnectionMaintainer>();\n\n            services.AddKeyedSingleton<IConnectionFactory>(\n                SiloConnectionFactory.ServicesKey,\n                (sp, key) => ActivatorUtilities.CreateInstance<SocketConnectionFactory>(sp));\n            services.AddKeyedSingleton<IConnectionListenerFactory>(\n                SiloConnectionListener.ServicesKey,\n                (sp, key) => ActivatorUtilities.CreateInstance<SocketConnectionListenerFactory>(sp));\n            services.AddKeyedSingleton<IConnectionListenerFactory>(\n                GatewayConnectionListener.ServicesKey,\n                (sp, key) => ActivatorUtilities.CreateInstance<SocketConnectionListenerFactory>(sp));\n\n            services.AddSerializer();\n            services.AddSingleton<ITypeNameFilter, AllowOrleansTypes>();\n            services.AddSingleton<ISpecializableCodec, GrainReferenceCodecProvider>();\n            services.AddSingleton<ISpecializableCopier, GrainReferenceCopierProvider>();\n            services.AddSingleton<OnDeserializedCallbacks>();\n            services.AddTransient<IConfigurationValidator, SerializerConfigurationValidator>();\n            services.AddSingleton<IPostConfigureOptions<OrleansJsonSerializerOptions>, ConfigureOrleansJsonSerializerOptions>();\n            services.AddSingleton<OrleansJsonSerializer>();\n\n            services.TryAddTransient(sp => ActivatorUtilities.CreateInstance<MessageSerializer>(\n                sp,\n                sp.GetRequiredService<IOptions<SiloMessagingOptions>>().Value));\n            services.TryAddSingleton<ConnectionFactory, SiloConnectionFactory>();\n            services.AddSingleton<NetworkingTrace>();\n            services.AddSingleton<RuntimeMessagingTrace>();\n            services.AddFromExisting<MessagingTrace, RuntimeMessagingTrace>();\n\n            // Use Orleans server.\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, SiloConnectionListener>();\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>, GatewayConnectionListener>();\n            services.AddSingleton<SocketSchedulers>();\n            services.AddSingleton<SharedMemoryPool>();\n\n            // Activation migration\n            services.AddSingleton<ActivationMigrationManager>();\n            services.AddFromExisting<IActivationMigrationManager, ActivationMigrationManager>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, ActivationMigrationManager>();\n            services.AddSingleton<GrainMigratabilityChecker>();\n\n            // Cancellation manager\n            services.AddSingleton<GrainCallCancellationManager>();\n            services.AddFromExisting<IGrainCallCancellationManager, GrainCallCancellationManager>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, GrainCallCancellationManager>();\n\n            ApplyConfiguration(builder);\n        }\n\n        private static void ApplyConfiguration(ISiloBuilder builder)\n        {\n            var services = builder.Services;\n            var cfg = builder.Configuration.GetSection(\"Orleans\");\n            var knownProviderTypes = GetRegisteredProviders();\n\n            if (cfg[\"Name\"] is { Length: > 0 } name)\n            {\n                services.Configure<SiloOptions>(siloOptions => siloOptions.SiloName = name);\n            }\n\n            services.Configure<ClusterOptions>(cfg);\n            services.Configure<SiloMessagingOptions>(cfg.GetSection(\"Messaging\"));\n            if (cfg.GetSection(\"Endpoints\") is { } ep && ep.Exists())\n            {\n                services.Configure<EndpointOptions>(o => o.Bind(ep));\n            }\n\n            if (bool.TryParse(cfg[\"EnableDistributedTracing\"], out var enableDistributedTracing) && enableDistributedTracing)\n            {\n                builder.AddActivityPropagation();\n            }\n\n            ApplySubsection(builder, cfg, knownProviderTypes, \"Clustering\");\n            ApplySubsection(builder, cfg, knownProviderTypes, \"Reminders\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"BroadcastChannel\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"Streaming\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"GrainStorage\");\n            ApplyNamedSubsections(builder, cfg, knownProviderTypes, \"GrainDirectory\");\n\n            static void ConfigureProvider(ISiloBuilder builder, Dictionary<(string Kind, string Name), Type> knownProviderTypes, string kind, string? name, IConfigurationSection configurationSection)\n            {\n                var providerType = configurationSection[\"ProviderType\"] ?? \"Default\";\n                var provider = GetRequiredProvider(knownProviderTypes, kind, providerType);\n                provider.Configure(builder, name, configurationSection);\n            }\n\n            static IProviderBuilder<ISiloBuilder> GetRequiredProvider(Dictionary<(string Kind, string Name), Type> knownProviderTypes, string kind, string name)\n            {\n                if (knownProviderTypes.TryGetValue((kind, name), out var type))\n                {\n                    var instance = Activator.CreateInstance(type);\n                    return instance as IProviderBuilder<ISiloBuilder>\n                        ?? throw new InvalidOperationException($\"{kind} provider, '{name}', of type {type}, does not implement {typeof(IProviderBuilder<ISiloBuilder>)}.\");\n                }\n\n                var knownProvidersOfKind = knownProviderTypes\n                    .Where(kvp => string.Equals(kvp.Key.Kind, kind, StringComparison.OrdinalIgnoreCase))\n                    .Select(kvp => kvp.Key.Name)\n                    .OrderBy(n => n)\n                    .ToList();\n\n                var knownProvidersMessage = knownProvidersOfKind.Count > 0\n                    ? $\" Known {kind} providers: {string.Join(\", \", knownProvidersOfKind)}.\"\n                    : string.Empty;\n\n                throw new InvalidOperationException($\"Could not find {kind} provider named '{name}'. This can indicate that either the 'Microsoft.Orleans.Sdk' or the provider's package are not referenced by your application.{knownProvidersMessage}\");\n            }\n\n            static Dictionary<(string Kind, string Name), Type> GetRegisteredProviders()\n            {\n                var result = new Dictionary<(string, string), Type>();\n                foreach (var asm in ReferencedAssemblyProvider.GetRelevantAssemblies())\n                {\n                    foreach (var attr in asm.GetCustomAttributes<RegisterProviderAttribute>())\n                    {\n                        if (string.Equals(attr.Target, \"Silo\"))\n                        {\n                            result[(attr.Kind, attr.Name)] = attr.Type;\n                        }\n                    }\n                }\n\n                return result;\n            }\n\n            static void ApplySubsection(ISiloBuilder builder, IConfigurationSection cfg, Dictionary<(string Kind, string Name), Type> knownProviderTypes, string sectionName)\n            {\n                if (cfg.GetSection(sectionName) is { } section && section.Exists())\n                {\n                    ConfigureProvider(builder, knownProviderTypes, sectionName, name: null, section);\n                }\n            }\n\n            static void ApplyNamedSubsections(ISiloBuilder builder, IConfigurationSection cfg, Dictionary<(string Kind, string Name), Type> knownProviderTypes, string sectionName)\n            {\n                if (cfg.GetSection(sectionName) is { } section && section.Exists())\n                {\n                    foreach (var child in section.GetChildren())\n                    {\n                        ConfigureProvider(builder, knownProviderTypes, sectionName, name: child.Key, child);\n                    }\n                }\n            }\n        }\n\n        private class AllowOrleansTypes : ITypeNameFilter\n        {\n            public bool? IsTypeNameAllowed(string typeName, string assemblyName)\n            {\n                if (assemblyName is { Length: > 0} && assemblyName.Contains(\"Orleans\"))\n                {\n                    return true;\n                }\n\n                return null;\n            }\n        }\n\n        private class ServicesAdded { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/DirectorySiloBuilderExtensions.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.GrainDirectory;\nusing Orleans.Hosting;\n\nnamespace Orleans.Runtime.Hosting\n{\n    public static class DirectorySiloBuilderExtensions\n    {\n        /// <summary>\n        /// Add a grain directory provider implementation to the silo. If the provider type implements <see cref=\"ILifecycleParticipant{ISiloLifecycle}\"/>\n        /// it will automatically participate to the silo lifecycle.\n        /// </summary>\n        /// <typeparam name=\"T\">The concrete implementation type of the grain directory provider.</typeparam>\n        /// <param name=\"builder\">The silo builder.</param>\n        /// <param name=\"name\">The name of the grain directory to add.</param>\n        /// <param name=\"implementationFactory\">Factory to build the grain directory provider.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddGrainDirectory<T>(this ISiloBuilder builder, string name, Func<IServiceProvider, string, T> implementationFactory)\n            where T : class, IGrainDirectory\n        {\n            builder.Services.AddGrainDirectory<T>(name, implementationFactory);\n            return builder;\n        }\n\n        /// <summary>\n        /// Add a grain directory provider implementation to the silo. If the provider type implements <see cref=\"ILifecycleParticipant{ISiloLifecycle}\"/>\n        /// it will automatically participate to the silo lifecycle.\n        /// </summary>\n        /// <typeparam name=\"T\">The concrete implementation type of the grain directory provider.</typeparam>\n        /// <param name=\"collection\">The service collection.</param>\n        /// <param name=\"name\">The name of the grain directory to add.</param>\n        /// <param name=\"implementationFactory\">Factory to build the grain directory provider.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddGrainDirectory<T>(this IServiceCollection collection, string name, Func<IServiceProvider, string, T> implementationFactory)\n            where T : class, IGrainDirectory\n        {\n            // Register the grain directory name so that directories can be enumerated by name.\n            collection.AddSingleton(sp => new NamedService<IGrainDirectory>(name));\n\n            // Register the grain directory implementation.\n            collection.AddKeyedSingleton<IGrainDirectory>(name, (sp, key) => implementationFactory(sp, name));\n            collection.AddSingleton<ILifecycleParticipant<ISiloLifecycle>>(s =>\n                s.GetKeyedService<IGrainDirectory>(name) as ILifecycleParticipant<ISiloLifecycle> ?? NoOpLifecycleParticipant.Instance);\n\n            return collection;\n        }\n\n        internal static IEnumerable<NamedService<IGrainDirectory>> GetGrainDirectories(this IServiceProvider serviceProvider)\n        {\n            return serviceProvider.GetServices<NamedService<IGrainDirectory>>() ?? [];\n        }\n\n        private sealed class NoOpLifecycleParticipant : ILifecycleParticipant<ISiloLifecycle>\n        {\n            public static readonly NoOpLifecycleParticipant Instance = new();\n\n            public void Participate(ISiloLifecycle observer) { }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/EndpointOptions.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configures the Silo endpoint options\n    /// </summary>\n    public class EndpointOptions\n    {\n        private IPAddress advertisedIPAddress;\n        private int siloPort = DEFAULT_SILO_PORT;\n\n        /// <summary>\n        /// The IP address used for clustering.\n        /// </summary>\n        public IPAddress AdvertisedIPAddress\n        {\n            get => advertisedIPAddress;\n            set\n            {\n                if (value is null)\n                {\n                    throw new OrleansConfigurationException(\n                        $\"No listening address specified. Use {nameof(Hosting.ISiloBuilder)}.{nameof(Hosting.EndpointOptionsExtensions.ConfigureEndpoints)}(...) \"\n                        + $\"to configure endpoints and ensure that {nameof(AdvertisedIPAddress)} is set.\");\n                }\n\n                if (value == IPAddress.Any\n                    || value == IPAddress.IPv6Any\n                    || value == IPAddress.None\n                    || value == IPAddress.IPv6None)\n                {\n                    throw new OrleansConfigurationException(\n                        $\"Invalid value specified for {nameof(AdvertisedIPAddress)}. The value was {value}\");\n                }\n\n                advertisedIPAddress = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the port this silo uses for silo-to-silo communication.\n        /// </summary>\n        public int SiloPort\n        {\n            get => siloPort;\n            set\n            {\n                if (value == 0)\n                {\n                    throw new OrleansConfigurationException(\n                        $\"No listening port specified. Use {nameof(Hosting.ISiloBuilder)}.{nameof(Hosting.EndpointOptionsExtensions.ConfigureEndpoints)}(...) \"\n                        + $\"to configure endpoints and ensure that {nameof(SiloPort)} is set.\");\n                }\n\n                siloPort = value;\n            }\n        }\n\n        /// <summary>\n        /// The default value for <see cref=\"SiloPort\"/>.\n        /// </summary>\n        public const int DEFAULT_SILO_PORT = 11111;\n\n        /// <summary>\n        /// Gets or sets the port this silo uses for silo-to-client (gateway) communication. Specify 0 to disable gateway functionality.\n        /// </summary>\n        public int GatewayPort { get; set; } = DEFAULT_GATEWAY_PORT;\n\n        /// <summary>\n        /// The default value for <see cref=\"GatewayPort\"/>.\n        /// </summary>\n        public const int DEFAULT_GATEWAY_PORT = 30000;\n\n        /// <summary>\n        /// Gets or sets the endpoint used to listen for silo to silo communication. \n        /// If not set will default to <see cref=\"AdvertisedIPAddress\"/> + <see cref=\"SiloPort\"/>\n        /// </summary>\n        public IPEndPoint SiloListeningEndpoint { get; set; }\n\n        /// <summary>\n        /// Gets or sets the endpoint used to listen for client to silo communication. \n        /// If not set will default to <see cref=\"AdvertisedIPAddress\"/> + <see cref=\"GatewayPort\"/>\n        /// </summary>\n        public IPEndPoint GatewayListeningEndpoint { get; set; }\n\n        internal IPEndPoint GetPublicSiloEndpoint() => new(AdvertisedIPAddress, SiloPort);\n\n        internal IPEndPoint GetPublicProxyEndpoint()\n        {\n            var gatewayPort = GatewayPort != 0 ? GatewayPort : GatewayListeningEndpoint?.Port ?? 0;\n            return gatewayPort != 0 ? new(AdvertisedIPAddress, gatewayPort) : null;\n        }\n\n        internal IPEndPoint GetListeningSiloEndpoint() => SiloListeningEndpoint ?? GetPublicSiloEndpoint();\n\n        internal IPEndPoint GetListeningProxyEndpoint() => GatewayListeningEndpoint ?? GetPublicProxyEndpoint();\n\n        internal void Bind(IConfiguration cfg)\n        {\n            if (int.TryParse(cfg[nameof(GatewayPort)], out var gwPort))\n            {\n                GatewayPort = gwPort;\n            }\n\n            if (int.TryParse(cfg[nameof(SiloPort)], out var siloPort))\n            {\n                SiloPort = siloPort;\n            }\n\n            if (IPAddress.TryParse(cfg[nameof(AdvertisedIPAddress)], out var aip))\n            {\n                AdvertisedIPAddress = aip;\n            }\n\n            if (IPEndPoint.TryParse(cfg[nameof(SiloListeningEndpoint)], out var sle))\n            {\n                SiloListeningEndpoint = sle;\n            }\n\n            if (IPEndPoint.TryParse(cfg[nameof(GatewayListeningEndpoint)], out var gle))\n            {\n                GatewayListeningEndpoint = gle;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/EndpointOptionsExtensions.cs",
    "content": "using System;\nusing System.Net;\nusing System.Net.Sockets;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Configuration;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for configuring <see cref=\"EndpointOptions\"/>.\n    /// </summary>\n    public static class EndpointOptionsExtensions\n    {\n        /// <summary>\n        /// Configure endpoints for the silo.\n        /// </summary>\n        /// <param name=\"builder\">The host builder to configure.</param>\n        /// <param name=\"advertisedIP\">The IP address to be advertised in membership tables</param>\n        /// <param name=\"siloPort\">The port this silo uses for silo-to-silo communication.</param>\n        /// <param name=\"gatewayPort\">The port this silo uses for client-to-silo (gateway) communication. Specify 0 to disable gateway functionality.</param>\n        /// <param name=\"listenOnAnyHostAddress\">Set to true to listen on all IP addresses of the host instead of just the advertiseIP.</param>\n        /// <returns></returns>\n        public static ISiloBuilder ConfigureEndpoints(\n            this ISiloBuilder builder,\n            IPAddress advertisedIP,\n            int siloPort,\n            int gatewayPort,\n            bool listenOnAnyHostAddress = false)\n        {\n            builder.Configure<EndpointOptions>(options =>\n            {\n                options.AdvertisedIPAddress = advertisedIP;\n                options.GatewayPort = gatewayPort;\n                options.SiloPort = siloPort;\n\n                if (listenOnAnyHostAddress)\n                {\n                    options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, siloPort);\n                    options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, gatewayPort);\n                }\n            });\n            return builder;\n        }\n\n        /// <summary>\n        /// Configure endpoints for the silo.\n        /// </summary>\n        /// <param name=\"builder\">The host builder to configure.</param>\n        /// <param name=\"hostname\">The host name the silo is running on.</param>\n        /// <param name=\"siloPort\">The port this silo uses for silo-to-silo communication.</param>\n        /// <param name=\"gatewayPort\">The port this silo uses for client-to-silo (gateway) communication. Specify 0 to disable gateway functionality.</param>\n        /// <param name=\"addressFamily\">Address family to listen on.  Default IPv4 address family.</param>\n        /// <param name=\"listenOnAnyHostAddress\">Set to true to listen on all IP addresses of the host instead of just the advertiseIP.</param>\n        /// <returns></returns>\n        public static ISiloBuilder ConfigureEndpoints(\n            this ISiloBuilder builder,\n            string hostname,\n            int siloPort,\n            int gatewayPort,\n            AddressFamily addressFamily = AddressFamily.InterNetwork,\n            bool listenOnAnyHostAddress = false)\n        {\n            var ip = ConfigUtilities.ResolveIPAddressOrDefault(hostname, null, addressFamily);\n\n            if (ip == null)\n            {\n                throw new ArgumentException(\"Hostname '\" + hostname + \"' with subnet [] and family \" + addressFamily + \" is not a valid IP address or DNS name\");\n            }            \n\n            return builder.ConfigureEndpoints(ip, siloPort, gatewayPort, listenOnAnyHostAddress);\n        }\n\n        /// <summary>\n        /// Configure endpoints for the silo.\n        /// </summary>\n        /// <param name=\"builder\">The host builder to configure.</param>\n        /// <param name=\"siloPort\">The port this silo uses for silo-to-silo communication.</param>\n        /// <param name=\"gatewayPort\">The port this silo uses for client-to-silo (gateway) communication. Specify 0 to disable gateway functionality.</param>\n        /// <param name=\"addressFamily\">Address family to listen on.  Default IPv4 address family.</param>\n        /// <param name=\"listenOnAnyHostAddress\">Set to true to listen on all IP addresses of the host instead of just the advertiseIP.</param>\n        /// <returns></returns>\n        public static ISiloBuilder ConfigureEndpoints(\n            this ISiloBuilder builder,\n            int siloPort,\n            int gatewayPort,\n            AddressFamily addressFamily = AddressFamily.InterNetwork,\n            bool listenOnAnyHostAddress = false)\n        {\n            return builder.ConfigureEndpoints(null, siloPort, gatewayPort, addressFamily, listenOnAnyHostAddress);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/EndpointOptionsProvider.cs",
    "content": "using System;\nusing System.Net;\nusing System.Net.Sockets;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime.Configuration;\n\nnamespace Orleans.Configuration\n{\n    internal partial class EndpointOptionsProvider : IPostConfigureOptions<EndpointOptions>\n    {\n        private readonly ILogger<EndpointOptionsProvider> logger;\n\n        public EndpointOptionsProvider(ILogger<EndpointOptionsProvider> logger)\n        {\n            this.logger = logger;\n        }\n\n        public void PostConfigure(string name, EndpointOptions options)\n        {\n            if (options.AdvertisedIPAddress is null)\n            {\n                var advertisedIPAddress = IPAddress.Loopback;\n\n                try\n                {\n                    var resolvedIP = ConfigUtilities.ResolveIPAddressOrDefault(null, AddressFamily.InterNetwork);\n\n                    if (resolvedIP is null)\n                    {\n                        LogWarningUnableToFindSuitableCandidate(logger, nameof(EndpointOptions), nameof(options.AdvertisedIPAddress), nameof(IPAddress.Loopback), advertisedIPAddress);\n                    }\n                    else\n                    {\n                        advertisedIPAddress = resolvedIP;\n                    }\n                }\n                catch (Exception ex)\n                {\n                    LogErrorUnableToFindSuitableCandidate(logger, ex, nameof(EndpointOptions), nameof(options.AdvertisedIPAddress), nameof(IPAddress.Loopback), advertisedIPAddress);\n                }\n\n                options.AdvertisedIPAddress = advertisedIPAddress;\n            }\n        }\n\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Unable to find a suitable candidate for {OptionName}.{PropertyName}. Falling back to {Fallback} ({AdvertisedIPAddress})\"\n        )]\n        private static partial void LogWarningUnableToFindSuitableCandidate(ILogger logger, string optionName, string propertyName, string fallback, IPAddress advertisedIPAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unable to find a suitable candidate for {OptionName}.{PropertyName}. Falling back to {Fallback} ({AdvertisedIPAddress})\"\n        )]\n        private static partial void LogErrorUnableToFindSuitableCandidate(ILogger logger, Exception exception, string optionName, string propertyName, string fallback, IPAddress advertisedIPAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/GrainCallFilterExtensions.cs",
    "content": "namespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for configuring <see cref=\"IIncomingGrainCallFilter\"/> and <see cref=\"IOutgoingGrainCallFilter\"/> implementations.\n    /// </summary>\n    public static class GrainCallFilterSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddIncomingGrainCallFilter(this ISiloBuilder builder, IIncomingGrainCallFilter filter)\n        {\n            return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddIncomingGrainCallFilter<TImplementation>(this ISiloBuilder builder)\n            where TImplementation : class, IIncomingGrainCallFilter\n        {\n            return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter<TImplementation>());\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IIncomingGrainCallFilter\"/> to the filter pipeline via a delegate.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddIncomingGrainCallFilter(this ISiloBuilder builder, IncomingGrainCallFilterDelegate filter)\n        {\n            return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddOutgoingGrainCallFilter(this ISiloBuilder builder, IOutgoingGrainCallFilter filter)\n        {\n            return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline.\n        /// </summary>\n        /// <typeparam name=\"TImplementation\">The filter implementation type.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddOutgoingGrainCallFilter<TImplementation>(this ISiloBuilder builder)\n            where TImplementation : class, IOutgoingGrainCallFilter\n        {\n            return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter<TImplementation>());\n        }\n\n        /// <summary>\n        /// Adds an <see cref=\"IOutgoingGrainCallFilter\"/> to the filter pipeline via a delegate.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"filter\">The filter.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddOutgoingGrainCallFilter(this ISiloBuilder builder, OutgoingGrainCallFilterDelegate filter)\n        {\n            return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/HostingGrainExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Methods for configuring <see cref=\"IGrainExtension\"/>s on a silo.\n    /// </summary>\n    public static class HostingGrainExtensions\n    {\n        /// <summary>\n        /// Registers a grain extension implementation for the specified interface.\n        /// </summary>\n        /// <typeparam name=\"TExtensionInterface\">The <see cref=\"IGrainExtension\"/> interface being registered.</typeparam>\n        /// <typeparam name=\"TExtension\">The implementation of <typeparamref name=\"TExtensionInterface\"/>.</typeparam>\n        public static ISiloBuilder AddGrainExtension<TExtensionInterface, TExtension>(this ISiloBuilder builder)\n            where TExtensionInterface : class, IGrainExtension\n            where TExtension : class, TExtensionInterface\n        {\n            return builder.ConfigureServices(services => services.AddKeyedTransient<IGrainExtension, TExtension>(typeof(TExtensionInterface)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/ISiloBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Builder for configuring an Orleans server.\n    /// </summary>\n    public interface ISiloBuilder\n    {\n        /// <summary>\n        /// The services shared by the silo and host.\n        /// </summary>\n        IServiceCollection Services { get; }\n\n        /// <summary>\n        /// Gets the configuration.\n        /// </summary>\n        IConfiguration Configuration { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/NamedService.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime.Hosting\n{\n    internal class NamedService<TService>(string name)\n    {\n        public string Name { get; } = name;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/OrleansSiloGenericHostExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\n\nnamespace Microsoft.Extensions.Hosting\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IHostBuilder\"/>.\n    /// </summary>\n    public static class OrleansSiloGenericHostExtensions\n    {\n        private static readonly Type MarkerType = typeof(OrleansBuilderMarker);\n\n        /// <summary>\n        /// Configures the host app builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IHostApplicationBuilder\"/> instance will result in one silo being configured.\n        /// </remarks>\n        public static IHostApplicationBuilder UseOrleans(\n            this IHostApplicationBuilder hostAppBuilder)\n            => hostAppBuilder.UseOrleans(_ => { });\n\n        /// <summary>\n        /// Configures the host app builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"HostApplicationBuilder\"/> instance will result in one silo being configured.\n        /// </remarks>\n        public static HostApplicationBuilder UseOrleans(\n            this HostApplicationBuilder hostAppBuilder)\n            => hostAppBuilder.UseOrleans(_ => { });\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the silo.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IHostApplicationBuilder\"/> instance will result in one silo being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// </remarks>\n        public static IHostApplicationBuilder UseOrleans(\n            this IHostApplicationBuilder hostAppBuilder,\n            Action<ISiloBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostAppBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            configureDelegate(AddOrleansCore(hostAppBuilder.Services, hostAppBuilder.Configuration));\n\n            return hostAppBuilder;\n        }\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostAppBuilder\">The host app builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the silo.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"HostApplicationBuilder\"/> instance will result in one silo being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// </remarks>\n        public static HostApplicationBuilder UseOrleans(\n            this HostApplicationBuilder hostAppBuilder,\n            Action<ISiloBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostAppBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            configureDelegate(AddOrleansCore(hostAppBuilder.Services, hostAppBuilder.Configuration));\n\n            return hostAppBuilder;\n        }\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the silo.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IHostBuilder\"/> instance will result in one silo being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// </remarks>\n        public static IHostBuilder UseOrleans(\n            this IHostBuilder hostBuilder,\n            Action<ISiloBuilder> configureDelegate) => hostBuilder.UseOrleans((_, siloBuilder) => configureDelegate(siloBuilder));\n\n        /// <summary>\n        /// Configures the host builder to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the silo.</param>\n        /// <returns>The host builder.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IHostBuilder\"/> instance will result in one silo being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// </remarks>\n        public static IHostBuilder UseOrleans(\n            this IHostBuilder hostBuilder,\n            Action<HostBuilderContext, ISiloBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(hostBuilder);\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            if (hostBuilder.Properties.ContainsKey(\"HasOrleansClientBuilder\"))\n            {\n                throw GetOrleansClientAddedException();\n            }\n\n            hostBuilder.Properties[\"HasOrleansSiloBuilder\"] = \"true\";\n\n            return hostBuilder.ConfigureServices((context, services) => configureDelegate(context, AddOrleansCore(services, context.Configuration)));\n        }\n\n        /// <summary>\n        /// Configures the service collection to host an Orleans silo.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"configureDelegate\">The delegate used to configure the silo.</param>\n        /// <returns>The service collection.</returns>\n        /// <remarks>\n        /// Calling this method multiple times on the same <see cref=\"IHostBuilder\"/> instance will result in one silo being configured.\n        /// However, the effects of <paramref name=\"configureDelegate\"/> will be applied once for each call.\n        /// </remarks>\n        public static IServiceCollection AddOrleans(\n            this IServiceCollection services,\n            Action<ISiloBuilder> configureDelegate)\n        {\n            ArgumentNullException.ThrowIfNull(configureDelegate);\n\n            var builder = AddOrleansCore(services, null);\n\n            configureDelegate(builder);\n\n            return services;\n        }\n\n        private static ISiloBuilder AddOrleansCore(IServiceCollection services, IConfiguration configuration)\n        {\n            ISiloBuilder builder = default;\n            configuration ??= new ConfigurationBuilder().Build();\n            foreach (var descriptor in services.Where(d => d.ServiceType.Equals(MarkerType)))\n            {\n                var marker = (OrleansBuilderMarker)descriptor.ImplementationInstance;\n                builder = marker.BuilderInstance switch\n                {\n                    ISiloBuilder existingBuilder => existingBuilder,\n                    _ => throw GetOrleansClientAddedException()\n                };\n            }\n\n            if (builder is null)\n            {\n                builder = new SiloBuilder(services, configuration);\n                services.AddSingleton(new OrleansBuilderMarker(builder));\n            }\n\n            return builder;\n        }\n\n        private static OrleansConfigurationException GetOrleansClientAddedException() =>\n            new(\"Do not call both UseOrleansClient/AddOrleansClient with UseOrleans/AddOrleans. If you want a client and server in the same process, only UseOrleans/AddOrleans is necessary and the UseOrleansClient/AddOrleansClient call can be removed.\");\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/PlacementStrategyExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for configuring grain placement.\n    /// </summary>\n    public static class PlacementStrategyExtensions\n    {\n        /// <summary>\n        /// Configures a <typeparamref name=\"TDirector\"/> as the placement director for placement strategy <typeparamref name=\"TStrategy\"/>.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <typeparam name=\"TDirector\">The placement director.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddPlacementDirector<TStrategy, TDirector>(this ISiloBuilder builder)\n            where TStrategy : PlacementStrategy, new()\n            where TDirector : class, IPlacementDirector\n        {\n            return builder.ConfigureServices(services => services.AddPlacementDirector<TStrategy, TDirector>());\n        }\n\n        /// <summary>\n        /// Adds a placement director.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"createDirector\">The delegate used to create the placement director.</param>\n        /// <returns>The builder.</returns>\n        public static ISiloBuilder AddPlacementDirector<TStrategy>(this ISiloBuilder builder, Func<IServiceProvider, IPlacementDirector> createDirector)\n            where TStrategy : PlacementStrategy, new()\n        {\n            return builder.ConfigureServices(services => services.AddPlacementDirector<TStrategy>(createDirector));\n        }\n\n        /// <summary>\n        /// Configures a <typeparamref name=\"TDirector\"/> as the placement director for placement strategy <typeparamref name=\"TStrategy\"/>.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <typeparam name=\"TDirector\">The placement director.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The service collection.</returns>\n        public static void AddPlacementDirector<TStrategy, TDirector>(this IServiceCollection services)\n            where TStrategy : PlacementStrategy, new()\n            where TDirector : class, IPlacementDirector => services.AddPlacementDirector<TStrategy, TDirector>(ServiceLifetime.Singleton);\n\n        /// <summary>\n        /// Configures a <typeparamref name=\"TDirector\"/> as the placement director for placement strategy <typeparamref name=\"TStrategy\"/>.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <typeparam name=\"TDirector\">The placement director.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"strategyLifetime\">The lifetime of the placement strategy.</param>\n        /// <returns>The service collection.</returns>\n        public static void AddPlacementDirector<TStrategy, TDirector>(this IServiceCollection services, ServiceLifetime strategyLifetime)\n            where TStrategy : PlacementStrategy, new()\n            where TDirector : class, IPlacementDirector\n        {\n            services.Add(ServiceDescriptor.DescribeKeyed(typeof(PlacementStrategy), typeof(TStrategy).Name, typeof(TStrategy), strategyLifetime));\n            services.AddKeyedSingleton<IPlacementDirector, TDirector>(typeof(TStrategy));\n        }\n\n        /// <summary>\n        /// Adds a placement director.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"createDirector\">The delegate used to create the placement director.</param>\n        /// <returns>The service collection.</returns>\n        public static void AddPlacementDirector<TStrategy>(this IServiceCollection services, Func<IServiceProvider, IPlacementDirector> createDirector)\n            where TStrategy : PlacementStrategy, new() => services.AddPlacementDirector<TStrategy>(createDirector, ServiceLifetime.Singleton);\n\n        /// <summary>\n        /// Adds a placement director.\n        /// </summary>\n        /// <typeparam name=\"TStrategy\">The placement strategy.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"createDirector\">The delegate used to create the placement director.</param>\n        /// <param name=\"strategyLifetime\">The lifetime of the placement strategy.</param>\n        /// <returns>The service collection.</returns>\n        public static void AddPlacementDirector<TStrategy>(this IServiceCollection services, Func<IServiceProvider, IPlacementDirector> createDirector, ServiceLifetime strategyLifetime)\n            where TStrategy : PlacementStrategy, new()\n        {\n            services.Add(ServiceDescriptor.DescribeKeyed(typeof(PlacementStrategy), typeof(TStrategy).Name, typeof(TStrategy), strategyLifetime));\n            services.AddKeyedSingleton<IPlacementDirector>(typeof(TStrategy), (sp, type) => createDirector(sp));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/ProviderConfiguration/DevelopmentClusteringProvider.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Runtime.Hosting.ProviderConfiguration;\n\n[assembly: RegisterProvider(\"Development\", \"Clustering\", \"Silo\", typeof(DevelopmentClusteringProvider))]\n\nnamespace Orleans.Runtime.Hosting.ProviderConfiguration;\n\ninternal sealed class DevelopmentClusteringProvider : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        IPEndPoint primarySiloEndPoint = null;\n        if (configurationSection[\"PrimarySiloEndPoint\"] is { Length: > 0 } primarySiloEndPointValue && !IPEndPoint.TryParse(primarySiloEndPointValue, out primarySiloEndPoint))\n        {\n            throw new OrleansConfigurationException($\"Unable to parse configuration value at path {configurationSection.Path}:PrimarySiloEndPoint as an IPEndPoint. Value: '{primarySiloEndPointValue}'.\");\n        }\n\n        builder.UseDevelopmentClustering(primarySiloEndPoint);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/SiloBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Builder for configuring an Orleans server.\n    /// </summary>\n    internal class SiloBuilder : ISiloBuilder\n    {\n        public SiloBuilder(IServiceCollection services, IConfiguration configuration)\n        {\n            Services = services;\n            Configuration = configuration;\n            DefaultSiloServices.AddDefaultServices(this);\n        }\n\n        public IServiceCollection Services { get; }\n        public IConfiguration Configuration { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/SiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for <see cref=\"ISiloBuilder\"/> instances.\n    /// </summary>\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Adds services to the container. This can be called multiple times and the results will be additive.\n        /// </summary>\n        /// <param name=\"builder\">The <see cref=\"ISiloBuilder\" /> to configure.</param>\n        /// <param name=\"configureDelegate\"></param>\n        /// <returns>The same instance of the <see cref=\"ISiloBuilder\"/> for chaining.</returns>\n        public static ISiloBuilder ConfigureServices(this ISiloBuilder builder, Action<IServiceCollection> configureDelegate)\n        {\n            if (configureDelegate == null) throw new ArgumentNullException(nameof(configureDelegate));\n            configureDelegate(builder.Services);\n            return builder;\n        }\n\n        /// <summary>\n        /// Registers an action used to configure a particular type of options.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type to be configured.</typeparam>\n        /// <param name=\"builder\">The silo builder.</param>\n        /// <param name=\"configureOptions\">The action used to configure the options.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder Configure<TOptions>(this ISiloBuilder builder, Action<TOptions> configureOptions) where TOptions : class\n        {\n            return builder.ConfigureServices(services => services.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Registers a configuration instance which <typeparamref name=\"TOptions\"/> will bind against.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The options type to be configured.</typeparam>\n        /// <param name=\"builder\">The silo builder.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder Configure<TOptions>(this ISiloBuilder builder, IConfiguration configuration) where TOptions : class\n        {\n            return builder.ConfigureServices(services => services.AddOptions<TOptions>().Bind(configuration));\n        }\n\n        /// <summary>\n        /// Adds a delegate for configuring the provided <see cref=\"ILoggingBuilder\"/>. This may be called multiple times.\n        /// </summary>\n        /// <param name=\"builder\">The <see cref=\"ISiloBuilder\" /> to configure.</param>\n        /// <param name=\"configureLogging\">The delegate that configures the <see cref=\"ILoggingBuilder\"/>.</param>\n        /// <returns>The same instance of the <see cref=\"ISiloBuilder\"/> for chaining.</returns>\n        public static ISiloBuilder ConfigureLogging(this ISiloBuilder builder, Action<ILoggingBuilder> configureLogging)\n        {\n            return builder.ConfigureServices(collection => collection.AddLogging(configureLogging));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/SiloBuilderStartupExtensions.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nusing Microsoft.Extensions.DependencyInjection;\n\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// The silo builder startup extensions.\n    /// </summary>\n    public static class SiloBuilderStartupExtensions\n    {\n        /// <summary>\n        /// Adds a startup task to be executed when the silo has started.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"stage\">\n        /// The stage to execute the startup task, see values in <see cref=\"ServiceLifecycleStage\"/>.\n        /// </param>\n        /// <typeparam name=\"TStartup\">\n        /// The startup task type.\n        /// </typeparam>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder AddStartupTask<TStartup>(\n            this ISiloBuilder builder,\n            int stage = ServiceLifecycleStage.Active)\n            where TStartup : class, IStartupTask\n        {\n            return builder.AddStartupTask((sp, ct) => ActivatorUtilities.GetServiceOrCreateInstance<TStartup>(sp).Execute(ct), stage);\n        }\n\n        /// <summary>\n        /// Adds a startup task to be executed when the silo has started.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"startupTask\">\n        /// The startup task.\n        /// </param>\n        /// <param name=\"stage\">\n        /// The stage to execute the startup task, see values in <see cref=\"ServiceLifecycleStage\"/>.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder AddStartupTask(\n            this ISiloBuilder builder,\n            IStartupTask startupTask,\n            int stage = ServiceLifecycleStage.Active)\n        {\n            return builder.AddStartupTask((sp, ct) => startupTask.Execute(ct), stage);\n        }\n\n        /// <summary>\n        /// Adds a startup task to be executed when the silo has started.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"startupTask\">\n        /// The startup task.\n        /// </param>\n        /// <param name=\"stage\">\n        /// The stage to execute the startup task, see values in <see cref=\"ServiceLifecycleStage\"/>.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>.\n        /// </returns>\n        public static ISiloBuilder AddStartupTask(\n            this ISiloBuilder builder,\n            Func<IServiceProvider, CancellationToken, Task> startupTask,\n            int stage = ServiceLifecycleStage.Active)\n        {\n            builder.ConfigureServices(services =>\n                services.AddTransient<ILifecycleParticipant<ISiloLifecycle>>(sp =>\n                    new StartupTask(\n                        sp,\n                        startupTask,\n                        stage)));\n            return builder;\n        }\n\n        /// <inheritdoc />\n        private class StartupTask : ILifecycleParticipant<ISiloLifecycle>\n        {\n            private readonly IServiceProvider serviceProvider;\n            private readonly Func<IServiceProvider, CancellationToken, Task> startupTask;\n\n            private readonly int stage;\n\n            public StartupTask(\n                IServiceProvider serviceProvider,\n                Func<IServiceProvider, CancellationToken, Task> startupTask,\n                int stage)\n            {\n                this.serviceProvider = serviceProvider;\n                this.startupTask = startupTask;\n                this.stage = stage;\n            }\n\n            /// <inheritdoc />\n            public void Participate(ISiloLifecycle lifecycle)\n            {\n                lifecycle.Subscribe<StartupTask>(\n                    this.stage,\n                    cancellation => this.startupTask(this.serviceProvider, cancellation));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/SiloHostedService.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Hosting\n{\n    internal partial class SiloHostedService : IHostedService\n    {\n        private readonly ILogger logger;\n        private readonly Silo silo;\n\n        public SiloHostedService(\n            Silo silo,\n            IEnumerable<IConfigurationValidator> configurationValidators,\n            ILogger<SiloHostedService> logger)\n        {\n            ValidateSystemConfiguration(configurationValidators);\n            this.silo = silo;\n            this.logger = logger;\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            LogInformationStartingSilo(logger);\n            await this.silo.StartAsync(cancellationToken).ConfigureAwait(false);\n            LogInformationSiloStarted(logger);\n        }\n\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            LogInformationStoppingSilo(logger);\n            await this.silo.StopAsync(cancellationToken).ConfigureAwait(false);\n            LogInformationSiloStopped(logger);\n        }\n\n        private static void ValidateSystemConfiguration(IEnumerable<IConfigurationValidator> configurationValidators)\n        {\n            foreach (var validator in configurationValidators)\n            {\n                validator.ValidateConfiguration();\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Starting Orleans Silo.\"\n        )]\n        private static partial void LogInformationStartingSilo(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Orleans Silo started.\"\n        )]\n        private static partial void LogInformationSiloStarted(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Stopping Orleans Silo\"\n        )]\n        private static partial void LogInformationStoppingSilo(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Orleans Silo stopped.\"\n        )]\n        private static partial void LogInformationSiloStopped(ILogger logger);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Hosting/StorageProviderHostExtensions.cs",
    "content": "using System;\nusing Orleans.Storage;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Providers;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\nnamespace Orleans.Runtime.Hosting\n{\n    public static class StorageProviderExtensions\n    {\n        /// <summary>\n        /// Add a grain storage provider implementation to the silo. If the provider type implements <see cref=\"ILifecycleParticipant{ISiloLifecycle}\"/>\n        /// it will automatically participate to the silo lifecycle.\n        /// </summary>\n        /// <typeparam name=\"T\">The concrete implementation type of the grain storage provider.</typeparam>\n        /// <param name=\"collection\">The service collection.</param>\n        /// <param name=\"name\">The name of the storage to add.</param>\n        /// <param name=\"implementationFactory\">Factory to build the storage provider.</param>\n        /// <returns>The service provider.</returns>\n        public static IServiceCollection AddGrainStorage<T>(this IServiceCollection collection, string name, Func<IServiceProvider, string, T> implementationFactory)\n            where T : IGrainStorage\n        {\n            collection.AddKeyedSingleton<IGrainStorage>(name, (sp, key) => implementationFactory(sp, key as string));\n\n            // Check if it is the default implementation\n            if (string.Equals(name, ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, StringComparison.Ordinal))\n            {\n                collection.TryAddSingleton(sp => sp.GetKeyedService<IGrainStorage>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n            }\n\n            // Check if the grain storage implements ILifecycleParticipant<ISiloLifecycle>\n            if (typeof(ILifecycleParticipant<ISiloLifecycle>).IsAssignableFrom(typeof(T)))\n            {\n                collection.AddSingleton(s => (ILifecycleParticipant<ISiloLifecycle>)s.GetRequiredKeyedService<IGrainStorage>(name));\n            }\n\n            return collection;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Lifecycle/ISiloLifecycle.cs",
    "content": "\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// The observable silo lifecycle.\n    /// </summary>\n    /// <remarks>\n    /// This type is usually used as the generic parameter in <see cref=\"ILifecycleParticipant{ISiloLifecycle}\"/> as\n    /// a means of participating in the lifecycle stages of a silo.\n    /// </remarks>\n    /// <seealso cref=\"Orleans.ILifecycleObservable\" />\n    public interface ISiloLifecycle : ILifecycleObservable\n    {\n        /// <summary>\n        /// The highest lifecycle stage which has completed starting.\n        /// </summary>\n        int HighestCompletedStage { get; }\n\n        /// <summary>\n        /// The lowest lifecycle stage which has completed stopping.\n        /// </summary>\n        int LowestStoppedStage { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Lifecycle/ISiloLifecycleSubject.cs",
    "content": "﻿\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Observable silo lifecycle and observer.\n    /// </summary>\n    public interface ISiloLifecycleSubject : ISiloLifecycle, ILifecycleObserver\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Lifecycle/IStartupTask.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Defines an action to be taken after silo startup.\n    /// </summary>\n    public interface IStartupTask\n    {\n        /// <summary>\n        /// Called after the silo has started.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token which is canceled when the method must abort.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        Task Execute(CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Lifecycle/SiloLifecycleSubject.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Decorator over lifecycle subject for silo.  Adds some logging and monitoring\n    /// </summary>\n    public partial class SiloLifecycleSubject : LifecycleSubject, ISiloLifecycleSubject\n    {\n        private static readonly ImmutableDictionary<int, string> StageNames = GetStageNames(typeof(ServiceLifecycleStage));\n        private readonly List<MonitoredObserver> observers;\n        private int highestCompletedStage;\n        private int lowestStoppedStage;\n\n        /// <inheritdoc />\n        public int HighestCompletedStage => this.highestCompletedStage;\n\n        /// <inheritdoc />\n        public int LowestStoppedStage => this.lowestStoppedStage;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloLifecycleSubject\"/> class.\n        /// </summary>\n        /// <param name=\"logger\">The logger.</param>\n        public SiloLifecycleSubject(ILogger<SiloLifecycleSubject> logger) : base(logger)\n        {\n            this.observers = new List<MonitoredObserver>();\n            this.highestCompletedStage = int.MinValue;\n            this.lowestStoppedStage = int.MaxValue;\n        }\n\n        /// <inheritdoc />\n        public override Task OnStart(CancellationToken cancellationToken = default)\n        {\n            foreach (var stage in this.observers.GroupBy(o => o.Stage).OrderBy(s => s.Key))\n            {\n                LogDebugLifecycleStagesReport(stage.Key, string.Join(\", \", stage.Select(o => o.Name)));\n            }\n\n            return base.OnStart(cancellationToken);\n        }\n\n        /// <inheritdoc />\n        protected override void OnStartStageCompleted(int stage)\n        {\n            Interlocked.Exchange(ref this.highestCompletedStage, stage);\n            base.OnStartStageCompleted(stage);\n        }\n\n        /// <inheritdoc />\n        protected override void OnStopStageCompleted(int stage)\n        {\n            Interlocked.Exchange(ref this.lowestStoppedStage, stage);\n            base.OnStopStageCompleted(stage);\n        }\n\n        /// <inheritdoc />\n        protected override string GetStageName(int stage)\n        {\n            if (StageNames.TryGetValue(stage, out var result)) return result;\n            return base.GetStageName(stage);\n        }\n\n        /// <inheritdoc />\n        protected override void PerfMeasureOnStop(int stage, TimeSpan elapsed)\n        {\n            LogDebugStoppingLifecycleStage(this.GetStageName(stage), elapsed);\n        }\n\n        /// <inheritdoc />\n        protected override void PerfMeasureOnStart(int stage, TimeSpan elapsed)\n        {\n            LogDebugStartingLifecycleStage(this.GetStageName(stage), elapsed);\n        }\n\n        /// <inheritdoc />\n        public override IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer)\n        {\n            var monitoredObserver = new MonitoredObserver(observerName, stage, this.GetStageName(stage), observer, this.Logger);\n            this.observers.Add(monitoredObserver);\n            return base.Subscribe(observerName, stage, monitoredObserver);\n        }\n\n        private partial class MonitoredObserver : ILifecycleObserver\n        {\n            private readonly ILifecycleObserver observer;\n            private readonly ILogger logger;\n\n            public MonitoredObserver(string name, int stage, string stageName, ILifecycleObserver observer, ILogger logger)\n            {\n                this.Name = name;\n                this.Stage = stage;\n                this.StageName = stageName;\n                this.observer = observer;\n                this.logger = logger;\n            }\n\n            public string Name { get; }\n            public int Stage { get; }\n            public string StageName { get; }\n\n            public async Task OnStart(CancellationToken ct)\n            {\n                try\n                {\n                    var stopwatch = ValueStopwatch.StartNew();\n                    await this.observer.OnStart(ct);\n                    stopwatch.Stop();\n                    LogDebugObserverStarted(this.Name, this.StageName, stopwatch.Elapsed);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorObserverStartFailure(exception, this.Name, this.StageName);\n                    throw;\n                }\n            }\n\n            public async Task OnStop(CancellationToken cancellationToken = default)\n            {\n                var stopwatch = ValueStopwatch.StartNew();\n                try\n                {\n                    LogDebugObserverStopping(this.Name, this.StageName);\n\n                    await this.observer.OnStop(cancellationToken);\n                    stopwatch.Stop();\n                    if (stopwatch.Elapsed > TimeSpan.FromSeconds(1))\n                    {\n                        LogObserverStopped(LogLevel.Warning, this.Name, this.StageName, stopwatch.Elapsed);\n                    }\n                    else\n                    {\n                        LogObserverStopped(LogLevel.Debug, this.Name, this.StageName, stopwatch.Elapsed);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorObserverStopFailure(exception, this.Name, this.StageName, stopwatch.Elapsed);\n                    throw;\n                }\n            }\n\n            [LoggerMessage(\n                EventId = (int)ErrorCode.SiloStartPerfMeasure,\n                Level = LogLevel.Debug,\n                Message = \"'{Name}' started in stage '{Stage}' in '{Elapsed}'.\"\n            )]\n            private partial void LogDebugObserverStarted(string name, string stage, TimeSpan elapsed);\n\n            [LoggerMessage(\n                EventId = (int)ErrorCode.LifecycleStartFailure,\n                Level = LogLevel.Error,\n                Message = \"'{Name}' failed to start due to errors at stage '{Stage}'.\"\n            )]\n            private partial void LogErrorObserverStartFailure(Exception exception, string name, string stage);\n\n            [LoggerMessage(\n                EventId = (int)ErrorCode.SiloStartPerfMeasure,\n                Level = LogLevel.Debug,\n                Message = \"'{Name}' stopping in stage '{Stage}'.\"\n            )]\n            private partial void LogDebugObserverStopping(string name, string stage);\n\n            [LoggerMessage(\n                EventId = (int)ErrorCode.SiloStartPerfMeasure,\n                Message = \"'{Name}' stopped in stage '{Stage}' in '{Elapsed}'.\"\n            )]\n            private partial void LogObserverStopped(LogLevel logLevel, string name, string stage, TimeSpan elapsed);\n\n            [LoggerMessage(\n                EventId = (int)ErrorCode.LifecycleStartFailure,\n                Level = LogLevel.Error,\n                Message = \"'{Name}' failed to stop due to errors at stage '{Stage}' after '{Elapsed}'.\"\n            )]\n            private partial void LogErrorObserverStopFailure(Exception exception, string name, string stage, TimeSpan elapsed);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.LifecycleStagesReport,\n            Level = LogLevel.Debug,\n            Message = \"Stage {Stage}: {Observers}\"\n        )]\n        private partial void LogDebugLifecycleStagesReport(int stage, string observers);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Level = LogLevel.Debug,\n            Message = \"Stopping lifecycle stage '{Stage}' took '{Elapsed}'.\"\n        )]\n        private partial void LogDebugStoppingLifecycleStage(string stage, TimeSpan elapsed);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Level = LogLevel.Debug,\n            Message = \"Starting lifecycle stage '{Stage}' took '{Elapsed}'\"\n        )]\n        private partial void LogDebugStartingLifecycleStage(string stage, TimeSpan elapsed);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Manifest/ClusterManifestProvider.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Utilities;\n\nnamespace Orleans.Runtime.Metadata\n{\n    internal partial class ClusterManifestProvider : IClusterManifestProvider, IAsyncDisposable, IDisposable, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly SiloAddress _localSiloAddress;\n        private readonly ILogger<ClusterManifestProvider> _logger;\n        private readonly IServiceProvider _services;\n        private readonly IClusterMembershipService _clusterMembershipService;\n        private readonly IFatalErrorHandler _fatalErrorHandler;\n        private readonly CancellationTokenSource _shutdownCts = new();\n        private readonly AsyncEnumerable<ClusterManifest> _updates;\n        private ClusterManifest _current;\n        private IInternalGrainFactory? _grainFactory;\n        private Task? _runTask;\n\n        public ClusterManifestProvider(\n            ILocalSiloDetails localSiloDetails,\n            SiloManifestProvider siloManifestProvider,\n            ClusterMembershipService clusterMembershipService,\n            IFatalErrorHandler fatalErrorHandler,\n            ILogger<ClusterManifestProvider> logger,\n            IServiceProvider services)\n        {\n            _localSiloAddress = localSiloDetails.SiloAddress;\n            _logger = logger;\n            _services = services;\n            _clusterMembershipService = clusterMembershipService;\n            _fatalErrorHandler = fatalErrorHandler;\n            LocalGrainManifest = siloManifestProvider.SiloManifest;\n            _current = new ClusterManifest(\n                MajorMinorVersion.Zero,\n                ImmutableDictionary.CreateRange([new KeyValuePair<SiloAddress, GrainManifest>(localSiloDetails.SiloAddress, LocalGrainManifest)]));\n            _updates = new AsyncEnumerable<ClusterManifest>(\n                initialValue: _current,\n                updateValidator: (previous, proposed) => proposed.Version > previous.Version,\n                onPublished: update => Interlocked.Exchange(ref _current, update));\n        }\n\n        public ClusterManifest Current => _current;\n\n        public IAsyncEnumerable<ClusterManifest> Updates => _updates;\n\n        public GrainManifest LocalGrainManifest { get; }\n\n        private async Task ProcessMembershipUpdates()\n        {\n            try\n            {\n                LogDebugStartingToProcessMembershipUpdates();\n\n                var cancellation = _shutdownCts.Token;\n                await foreach (var _ in _clusterMembershipService.MembershipUpdates.WithCancellation(cancellation))\n                {\n                    while (true)\n                    {\n                        var membershipSnapshot = _clusterMembershipService.CurrentSnapshot;\n\n                        var success = await UpdateManifest(membershipSnapshot);\n\n                        if (success || cancellation.IsCancellationRequested)\n                        {\n                            break;\n                        }\n\n                        await Task.Delay(TimeSpan.FromSeconds(5), cancellation);\n                    }\n                }\n            }\n            catch (OperationCanceledException) when (_shutdownCts.IsCancellationRequested)\n            {\n                // Ignore during shutdown.\n            }\n            catch (Exception exception) when (_fatalErrorHandler.IsUnexpected(exception))\n            {\n                _fatalErrorHandler.OnFatalException(this, nameof(ProcessMembershipUpdates), exception);\n            }\n            finally\n            {\n                LogDebugStoppedProcessingMembershipUpdates();\n            }\n        }\n\n        private async Task<bool> UpdateManifest(ClusterMembershipSnapshot clusterMembership)\n        {\n            var existingManifest = _current;\n            var builder = existingManifest.Silos.ToBuilder();\n            var modified = false;\n\n            // First, remove defunct entries.\n            foreach (var entry in existingManifest.Silos)\n            {\n                var address = entry.Key;\n                var status = clusterMembership.GetSiloStatus(address);\n\n                if (address.Equals(_localSiloAddress))\n                {\n                    // The local silo is always present in the manifest.\n                    continue;\n                }\n\n                if (status == SiloStatus.None || status == SiloStatus.Dead)\n                {\n                    builder.Remove(address);\n                    modified = true;\n                }\n            }\n\n            // Next, fill missing entries.\n            var tasks = new List<Task<(SiloAddress Key, GrainManifest? Value, Exception? Exception)>>();\n            foreach (var entry in clusterMembership.Members)\n            {\n                var member = entry.Value;\n\n                if (member.SiloAddress.Equals(_localSiloAddress))\n                {\n                    // The local silo is always present in the manifest.\n                    continue;\n                }\n\n                if (existingManifest.Silos.ContainsKey(member.SiloAddress))\n                {\n                    // Manifest has already been retrieved for the cluster member.\n                    continue;\n                }\n\n                if (member.Status != SiloStatus.Active)\n                {\n                    // If the member is not yet active, it may not be ready to process requests.\n                    continue;\n                }\n\n                tasks.Add(GetManifest(member.SiloAddress));\n\n                async Task<(SiloAddress, GrainManifest?, Exception?)> GetManifest(SiloAddress siloAddress)\n                {\n                    try\n                    {\n                        // Get the manifest from the remote silo.\n                        var remoteManifestProvider = _grainFactory!.GetSystemTarget<ISiloManifestSystemTarget>(Constants.ManifestProviderType, member.SiloAddress);\n                        var manifest = await remoteManifestProvider.GetSiloManifest().AsTask().WaitAsync(_shutdownCts.Token);\n                        return (siloAddress, manifest, null);\n                    }\n                    catch (Exception exception)\n                    {\n                        return (siloAddress, null, exception);\n                    }\n                }\n            }\n\n            var fetchSuccess = true;\n            await Task.WhenAll(tasks);\n            foreach (var task in tasks)\n            {\n                var result = await task;\n                if (result.Exception is Exception exception)\n                {\n                    fetchSuccess = false;\n                    if (exception is not OperationCanceledException)\n                    {\n                        LogWarningErrorRetrievingSiloManifest(exception, result.Key);\n                    }\n                }\n                else\n                {\n                    modified = true;\n                    if (result.Value is not null)\n                    {\n                        builder[result.Key] = result.Value;\n                    }\n                }\n            }\n\n            // Regardless of success or failure, update the manifest if it has been modified.\n            var version = new MajorMinorVersion(clusterMembership.Version.Value, existingManifest.Version.Minor + 1);\n            if (modified)\n            {\n                return _updates.TryPublish(new ClusterManifest(version, builder.ToImmutable())) && fetchSuccess;\n            }\n\n            return fetchSuccess;\n        }\n\n        [MemberNotNull(nameof(_runTask))]\n        private Task StartAsync(CancellationToken cancellationToken)\n        {\n            Debug.Assert(_grainFactory is not null);\n            _runTask = Task.Run(ProcessMembershipUpdates);\n            return Task.CompletedTask;\n        }\n\n        [MemberNotNull(nameof(_grainFactory))]\n        private Task Initialize(CancellationToken cancellationToken)\n        {\n            _grainFactory = _services.GetRequiredService<IInternalGrainFactory>();\n            return Task.CompletedTask;\n        }\n\n        private async Task StopAsync(CancellationToken cancellationToken)\n        {\n            _shutdownCts.Cancel();\n            if (_runTask is Task task)\n            {\n                await task.WaitAsync(cancellationToken).SuppressThrowing();\n            }\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(\n                nameof(ClusterManifestProvider),\n                ServiceLifecycleStage.RuntimeServices,\n                Initialize,\n                _ => Task.CompletedTask);\n\n            lifecycle.Subscribe(\n                nameof(ClusterManifestProvider),\n                ServiceLifecycleStage.RuntimeGrainServices,\n                StartAsync,\n                StopAsync);\n        }\n\n        public async ValueTask DisposeAsync()\n        {\n            if (_shutdownCts.IsCancellationRequested)\n            {\n                return;\n            }\n\n            await StopAsync(CancellationToken.None);\n        }\n\n        public void Dispose()\n        {\n            DisposeAsync().AsTask().GetAwaiter().GetResult();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error retrieving silo manifest for silo {SiloAddress}\"\n        )]\n        private partial void LogWarningErrorRetrievingSiloManifest(Exception exception, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting to process membership updates\"\n        )]\n        private partial void LogDebugStartingToProcessMembershipUpdates();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopped processing membership updates\"\n        )]\n        private partial void LogDebugStoppedProcessingMembershipUpdates();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Manifest/GrainClassMap.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Mapping between <see cref=\"GrainType\"/> and implementing <see cref=\"Type\"/>.\n    /// </summary>\n    public class GrainClassMap\n    {\n        private readonly TypeConverter _typeConverter;\n        private readonly ImmutableDictionary<GrainType, Type> _types;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GrainClassMap\"/> class.\n        /// </summary>\n        /// <param name=\"typeConverter\">The type converter.</param>\n        /// <param name=\"classes\">The grain classes.</param>\n        public GrainClassMap(TypeConverter typeConverter, ImmutableDictionary<GrainType, Type> classes)\n        {\n            _typeConverter = typeConverter;\n            _types = classes;\n        }\n\n        /// <summary>\n        /// Returns the grain class type corresponding to the provided grain type.\n        /// </summary>\n        /// <param name=\"grainType\">Type of the grain.</param>\n        /// <param name=\"grainClass\">The grain class.</param>\n        /// <returns><see langword=\"true\"/> if a corresponding grain class was found, <see langword=\"false\"/> otherwise.</returns>\n        public bool TryGetGrainClass(GrainType grainType, [NotNullWhen(true)] out Type grainClass)\n        {\n            GrainType lookupType;\n            Type[] args;\n            if (GenericGrainType.TryParse(grainType, out var genericId))\n            {\n                lookupType = genericId.GetUnconstructedGrainType().GrainType;\n                args = genericId.GetArguments(_typeConverter);\n            }\n            else\n            {\n                lookupType = grainType;\n                args = default;\n            }\n\n            if (!_types.TryGetValue(lookupType, out grainClass))\n            {\n                return false;\n            }\n\n            if (args is not null)\n            {\n                grainClass = grainClass.MakeGenericType(args);\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Manifest/SiloManifestProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Metadata\n{\n    /// <summary>\n    /// Creates a <see cref=\"SiloManifest\"/> for this silo.\n    /// </summary>\n    internal class SiloManifestProvider\n    {\n        public SiloManifestProvider(\n            IEnumerable<IGrainPropertiesProvider> grainPropertiesProviders,\n            IEnumerable<IGrainInterfacePropertiesProvider> grainInterfacePropertiesProviders,\n            IOptions<GrainTypeOptions> grainTypeOptions,\n            GrainTypeResolver typeProvider,\n            GrainInterfaceTypeResolver interfaceIdProvider,\n            TypeConverter typeConverter)\n        {\n            var (grainProperties, grainTypes) = CreateGrainManifest(grainPropertiesProviders, grainTypeOptions, typeProvider);\n            var interfaces = CreateInterfaceManifest(grainInterfacePropertiesProviders, grainTypeOptions, interfaceIdProvider);\n            this.SiloManifest = new GrainManifest(grainProperties, interfaces);\n            this.GrainTypeMap = new GrainClassMap(typeConverter, grainTypes);\n        }\n\n        public GrainManifest SiloManifest { get; }\n\n        public GrainClassMap GrainTypeMap { get; }\n\n        private static ImmutableDictionary<GrainInterfaceType, GrainInterfaceProperties> CreateInterfaceManifest(\n            IEnumerable<IGrainInterfacePropertiesProvider> propertyProviders,\n            IOptions<GrainTypeOptions> grainTypeOptions,\n            GrainInterfaceTypeResolver grainInterfaceIdProvider)\n        {\n            var builder = ImmutableDictionary.CreateBuilder<GrainInterfaceType, GrainInterfaceProperties>();\n            foreach (var grainInterface in grainTypeOptions.Value.Interfaces)\n            {\n                var interfaceId = grainInterfaceIdProvider.GetGrainInterfaceType(grainInterface);\n                var properties = new Dictionary<string, string>();\n                foreach (var provider in propertyProviders)\n                {\n                    provider.Populate(grainInterface, interfaceId, properties);\n                }\n\n                var result = new GrainInterfaceProperties(properties.ToImmutableDictionary());\n                if (builder.TryGetValue(interfaceId, out var graintInterfaceProperty))\n                {\n                    throw new InvalidOperationException($\"An entry with the key {interfaceId} is already present.\"\n                        + $\"\\nExisting: {graintInterfaceProperty.ToDetailedString()}\\nTrying to add: {result.ToDetailedString()}\"\n                        + \"\\nConsider using the [GrainInterfaceType(\\\"name\\\")] attribute to give these interfaces unique names.\");\n                }\n\n                builder.Add(interfaceId, result);\n            }\n\n            return builder.ToImmutable();\n        }\n\n        private static (ImmutableDictionary<GrainType, GrainProperties>, ImmutableDictionary<GrainType, Type>) CreateGrainManifest(\n            IEnumerable<IGrainPropertiesProvider> grainMetadataProviders,\n            IOptions<GrainTypeOptions> grainTypeOptions,\n            GrainTypeResolver grainTypeProvider)\n        {\n            var propertiesMap = ImmutableDictionary.CreateBuilder<GrainType, GrainProperties>();\n            var typeMap = ImmutableDictionary.CreateBuilder<GrainType, Type>();\n            foreach (var grainClass in grainTypeOptions.Value.Classes)\n            {\n                var grainType = grainTypeProvider.GetGrainType(grainClass);\n                var properties = new Dictionary<string, string>();\n                foreach (var provider in grainMetadataProviders)\n                {\n                    provider.Populate(grainClass, grainType, properties);\n                }\n\n                var result = new GrainProperties(properties.ToImmutableDictionary());\n                if (propertiesMap.TryGetValue(grainType, out var grainProperty))\n                {\n                    throw new InvalidOperationException($\"An entry with the key {grainType} is already present.\"\n                        + $\"\\nExisting: {grainProperty.ToDetailedString()}\\nTrying to add: {result.ToDetailedString()}\"\n                        + \"\\nConsider using the [GrainType(\\\"name\\\")] attribute to give these classes unique names.\");\n                }\n\n                propertiesMap.Add(grainType, result);\n                typeMap.Add(grainType, grainClass);\n            }\n\n            return (propertiesMap.ToImmutable(), typeMap.ToImmutable());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ClusterHealthMonitor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing static Orleans.Runtime.MembershipService.SiloHealthMonitor;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Responsible for ensuring that this silo monitors other silos in the cluster.\n    /// </summary>\n    internal partial class ClusterHealthMonitor : IHealthCheckParticipant, ILifecycleParticipant<ISiloLifecycle>, ClusterHealthMonitor.ITestAccessor, IDisposable, IAsyncDisposable\n    {\n        private readonly CancellationTokenSource shutdownCancellation = new CancellationTokenSource();\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly IServiceProvider serviceProvider;\n        private readonly MembershipTableManager membershipService;\n        private readonly ILogger<ClusterHealthMonitor> log;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly IOptionsMonitor<ClusterMembershipOptions> clusterMembershipOptions;\n        private ImmutableDictionary<SiloAddress, SiloHealthMonitor> monitoredSilos = ImmutableDictionary<SiloAddress, SiloHealthMonitor>.Empty;\n        private MembershipVersion observedMembershipVersion;\n        private Func<SiloAddress, SiloHealthMonitor> createMonitor;\n        private Func<SiloHealthMonitor, ProbeResult, Task> onProbeResult;\n\n        /// <summary>\n        /// Exposes private members of <see cref=\"ClusterHealthMonitor\"/> for test purposes.\n        /// </summary>\n        internal interface ITestAccessor\n        {\n            ImmutableDictionary<SiloAddress, SiloHealthMonitor> MonitoredSilos { get; set; }\n            Func<SiloAddress, SiloHealthMonitor> CreateMonitor { get; set; }\n            MembershipVersion ObservedVersion { get; }\n            Func<SiloHealthMonitor, ProbeResult, Task> OnProbeResult { get; set; }\n        }\n\n        public ClusterHealthMonitor(\n            ILocalSiloDetails localSiloDetails,\n            MembershipTableManager membershipService,\n            ILogger<ClusterHealthMonitor> log,\n            IOptionsMonitor<ClusterMembershipOptions> clusterMembershipOptions,\n            IFatalErrorHandler fatalErrorHandler,\n            IServiceProvider serviceProvider)\n        {\n            this.localSiloDetails = localSiloDetails;\n            this.serviceProvider = serviceProvider;\n            this.membershipService = membershipService;\n            this.log = log;\n            this.fatalErrorHandler = fatalErrorHandler;\n            this.clusterMembershipOptions = clusterMembershipOptions;\n            this.onProbeResult = this.OnProbeResultInternal;\n            Func<SiloHealthMonitor, ProbeResult, Task> onProbeResultFunc = (siloHealthMonitor, probeResult) => this.onProbeResult(siloHealthMonitor, probeResult);\n            this.createMonitor = silo => ActivatorUtilities.CreateInstance<SiloHealthMonitor>(serviceProvider, silo, onProbeResultFunc);\n        }\n\n        ImmutableDictionary<SiloAddress, SiloHealthMonitor> ITestAccessor.MonitoredSilos { get => this.monitoredSilos; set => this.monitoredSilos = value; }\n        Func<SiloAddress, SiloHealthMonitor> ITestAccessor.CreateMonitor { get => this.createMonitor; set => this.createMonitor = value; }\n        MembershipVersion ITestAccessor.ObservedVersion => this.observedMembershipVersion;\n        Func<SiloHealthMonitor, ProbeResult, Task> ITestAccessor.OnProbeResult { get => this.onProbeResult; set => this.onProbeResult = value; }\n\n        /// <summary>\n        /// Gets the collection of monitored silos.\n        /// </summary>\n        public ImmutableDictionary<SiloAddress, SiloHealthMonitor> SiloMonitors => this.monitoredSilos;\n\n        private async Task ProcessMembershipUpdates()\n        {\n            try\n            {\n                LogDebugStartingToProcessMembershipUpdates(log);\n                await foreach (var tableSnapshot in this.membershipService.MembershipTableUpdates.WithCancellation(this.shutdownCancellation.Token))\n                {\n                    var utcNow = DateTime.UtcNow;\n\n                    var newMonitoredSilos = this.UpdateMonitoredSilos(tableSnapshot, this.monitoredSilos, utcNow);\n\n                    if (this.clusterMembershipOptions.CurrentValue.EvictWhenMaxJoinAttemptTimeExceeded)\n                    {\n                        await this.EvictStaleStateSilos(tableSnapshot, utcNow);\n                    }\n\n                    foreach (var pair in this.monitoredSilos)\n                    {\n                        if (!newMonitoredSilos.ContainsKey(pair.Key))\n                        {\n                            using var cancellation = new CancellationTokenSource(this.clusterMembershipOptions.CurrentValue.ProbeTimeout);\n                            await pair.Value.StopAsync(cancellation.Token);\n                        }\n                    }\n\n                    this.monitoredSilos = newMonitoredSilos;\n                    this.observedMembershipVersion = tableSnapshot.Version;\n                }\n            }\n            catch (OperationCanceledException) when (shutdownCancellation.IsCancellationRequested)\n            {\n                // Ignore and continue shutting down.\n            }\n            catch (Exception exception) when (this.fatalErrorHandler.IsUnexpected(exception))\n            {\n                this.fatalErrorHandler.OnFatalException(this, nameof(ProcessMembershipUpdates), exception);\n            }\n            finally\n            {\n                LogDebugStoppedProcessingMembershipUpdates(log);\n            }\n        }\n\n        private async Task EvictStaleStateSilos(\n            MembershipTableSnapshot membership,\n            DateTime utcNow)\n        {\n            foreach (var member in membership.Entries)\n            {\n                if (IsCreatedOrJoining(member.Value.Status)\n                    && HasExceededMaxJoinTime(\n                        startTime: member.Value.StartTime,\n                        now: utcNow,\n                        maxJoinTime: this.clusterMembershipOptions.CurrentValue.MaxJoinAttemptTime))\n                {\n                    try\n                    {\n                        LogDebugStaleSiloFound(log);\n                        await this.membershipService.TryToSuspectOrKill(member.Key);\n                    }\n                    catch(Exception exception)\n                    {\n                        LogErrorTryToSuspectOrKillFailed(log, exception, member.Value.SiloAddress, member.Value.Status);\n                    }\n                }\n            }\n\n            static bool IsCreatedOrJoining(SiloStatus status)\n            {\n                return status == SiloStatus.Created || status == SiloStatus.Joining;\n            }\n\n            static bool HasExceededMaxJoinTime(DateTime startTime, DateTime now, TimeSpan maxJoinTime)\n            {\n                return now > startTime.Add(maxJoinTime);\n            }\n        }\n\n        [Pure]\n        private ImmutableDictionary<SiloAddress, SiloHealthMonitor> UpdateMonitoredSilos(\n            MembershipTableSnapshot membership,\n            ImmutableDictionary<SiloAddress, SiloHealthMonitor> monitoredSilos,\n            DateTime now)\n        {\n            // If I am still not fully functional, I should not be probing others.\n            if (!membership.Entries.TryGetValue(this.localSiloDetails.SiloAddress, out var self) || !IsFunctionalForMembership(self.Status))\n            {\n                return ImmutableDictionary<SiloAddress, SiloHealthMonitor>.Empty;\n            }\n\n            var options = clusterMembershipOptions.CurrentValue;\n            var numProbedSilos = options.NumProbedSilos;\n\n            // Go over every node excluding this one.\n            // Find up to NumProbedSilos silos after me, which are not suspected by anyone and add them to the probedSilos,\n            // In addition, every suspected silo you encounter on the way, add it to the probedSilos.\n            var silosToWatch = new List<SiloAddress>();\n            var additionalSilos = new List<SiloAddress>();\n\n            var tmpList = new List<(SiloAddress SiloAddress, int HashCode)>();\n            foreach (var (candidate, entry) in membership.Entries)\n            {\n                // Watch shutting-down silos as well, so we can properly ensure they become dead.\n                if (!IsFunctionalForMembership(entry.Status))\n                {\n                    continue;\n                }\n\n                tmpList.Add((candidate, 0));\n\n                // Ignore the local silo.\n                if (candidate.IsSameLogicalSilo(this.localSiloDetails.SiloAddress))\n                {\n                    continue;\n                }\n\n                // Monitor all suspected and stale silos.\n                if (entry.GetFreshVotes(now, options.DeathVoteExpirationTimeout).Count > 0\n                    || entry.HasMissedIAmAlives(options, now))\n                {\n                    additionalSilos.Add(candidate);\n                }\n            }\n\n            // Each silo monitors up to NumProbedSilos other silos.\n            // Monitoring is determined using multiple hash rings, each generated with a different seeded hash function.\n            // For each hash ring:\n            // 1. The hash values of all silos are updated based on the ring's seed and sorted to determine their positions.\n            // 2. The local silo finds its position in the sorted list and iterates over subsequent silos, wrapping around at the ends.\n            // 3. The first silo not already being monitored is selected and added to the monitoring set.\n            //\n            // This approach probabilistically constructs an Expander Graph (https://en.wikipedia.org/wiki/Expander_graph).\n            // Expander graphs improve fault detection time when there are multiple concurrent failures by minimizing overlap\n            // in monitoring sets between any two silos and reducing dependency chains (e.g., avoiding cases where one failed\n            // silo must be evicted before another failed silo can be detected).\n            // The idea to use an expander graph is taken from \"Stable and Consistent Membership at Scale with Rapid\" by Lalith Suresh et al:\n            // https://www.usenix.org/conference/atc18/presentation/suresh\n            for (var ringNum = 0; ringNum < numProbedSilos; ++ringNum)\n            {\n                // Update hash values with the current ring number.\n                for (var i = 0; i < tmpList.Count; i++)\n                {\n                    var siloAddress = tmpList[i].SiloAddress;\n                    tmpList[i] = (siloAddress, siloAddress.GetConsistentHashCode(ringNum));\n                }\n\n                // Sort the candidates based on their updated hash values.\n                tmpList.Sort((x, y) => x.HashCode.CompareTo(y.HashCode));\n\n                var myIndex = tmpList.FindIndex(el => el.SiloAddress.Equals(self.SiloAddress));\n                if (myIndex < 0)\n                {\n                    LogErrorSiloNotInLocalList(log, self.SiloAddress, self.Status);\n                    throw new OrleansMissingMembershipEntryException(\n                        $\"This silo {self.SiloAddress} status {self.Status} is not in its own local silo list! This is a bug!\");\n                }\n\n                // Starting at the local silo's index, find the first non-monitored silo and add it to the list.\n                for (var i = 0; i < tmpList.Count - 1; i++)\n                {\n                    var candidate = tmpList[(myIndex + i + 1) % tmpList.Count].SiloAddress;\n                    if (!silosToWatch.Contains(candidate))\n                    {\n                        Debug.Assert(!candidate.IsSameLogicalSilo(this.localSiloDetails.SiloAddress));\n                        silosToWatch.Add(candidate);\n                        break;\n                    }\n                }\n            }\n\n            // Take new watched silos, but leave the probe counters for the old ones.\n            var newProbedSilos = ImmutableDictionary.CreateBuilder<SiloAddress, SiloHealthMonitor>();\n            foreach (var silo in silosToWatch.Union(additionalSilos))\n            {\n                SiloHealthMonitor monitor;\n                if (!monitoredSilos.TryGetValue(silo, out monitor))\n                {\n                    monitor = this.createMonitor(silo);\n                    monitor.Start();\n                }\n\n                newProbedSilos[silo] = monitor;\n            }\n\n            var result = newProbedSilos.ToImmutable();\n            if (!AreTheSame(monitoredSilos, result))\n            {\n                LogInformationWillWatchActivelyPing(log, newProbedSilos.Count, new(newProbedSilos.Keys));\n            }\n\n            return result;\n\n            static bool AreTheSame<T>(ImmutableDictionary<SiloAddress, T> first, ImmutableDictionary<SiloAddress, T> second)\n                => first.Count == second.Count && first.Count == first.Keys.Intersect(second.Keys).Count();\n\n            static bool IsFunctionalForMembership(SiloStatus status)\n                => status is SiloStatus.Active or SiloStatus.ShuttingDown or SiloStatus.Stopping;\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            var tasks = new List<Task>();\n\n            lifecycle.Subscribe(nameof(ClusterHealthMonitor), ServiceLifecycleStage.Active, OnActiveStart, OnActiveStop);\n\n            Task OnActiveStart(CancellationToken ct)\n            {\n                tasks.Add(Task.Run(() => this.ProcessMembershipUpdates()));\n                return Task.CompletedTask;\n            }\n\n            async Task OnActiveStop(CancellationToken ct)\n            {\n                this.shutdownCancellation.Cancel(throwOnFirstException: false);\n\n                foreach (var monitor in this.monitoredSilos.Values)\n                {\n                    tasks.Add(monitor.StopAsync(ct));\n                }\n\n                this.monitoredSilos = ImmutableDictionary<SiloAddress, SiloHealthMonitor>.Empty;\n\n                // Allow some minimum time for graceful shutdown.\n                var shutdownGracePeriod = Task.WhenAll(Task.Delay(ClusterMembershipOptions.ClusteringShutdownGracePeriod), ct.WhenCancelled());\n                await Task.WhenAny(shutdownGracePeriod, Task.WhenAll(tasks));\n            }\n        }\n\n        /// <summary>\n        /// Performs the default action when a new probe result is created.\n        /// </summary>\n        private async Task OnProbeResultInternal(SiloHealthMonitor monitor, ProbeResult probeResult)\n        {\n            // Do not act on probe results if shutdown is in progress.\n            if (this.shutdownCancellation.IsCancellationRequested)\n            {\n                return;\n            }\n\n            if (probeResult.IsDirectProbe)\n            {\n                if (probeResult.Status == ProbeResultStatus.Failed && probeResult.FailedProbeCount >= this.clusterMembershipOptions.CurrentValue.NumMissedProbesLimit)\n                {\n                    await this.membershipService.TryToSuspectOrKill(monitor.TargetSiloAddress).ConfigureAwait(false);\n                }\n            }\n            else if (probeResult.Status == ProbeResultStatus.Failed)\n            {\n                await this.membershipService.TryToSuspectOrKill(monitor.TargetSiloAddress, probeResult.Intermediary).ConfigureAwait(false);\n            }\n        }\n\n        bool IHealthCheckable.CheckHealth(DateTime lastCheckTime, out string reason)\n        {\n            var ok = true;\n            reason = default;\n            foreach (var monitor in this.monitoredSilos.Values)\n            {\n                ok &= monitor.CheckHealth(lastCheckTime, out var monitorReason);\n                if (!string.IsNullOrWhiteSpace(monitorReason))\n                {\n                    var siloReason = $\"Monitor for {monitor.TargetSiloAddress} is degraded with: {monitorReason}.\";\n                    if (string.IsNullOrWhiteSpace(reason))\n                    {\n                        reason = siloReason;\n                    }\n                    else\n                    {\n                        reason = reason + \" \" + siloReason;\n                    }\n                }\n            }\n\n            return ok;\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                shutdownCancellation.Cancel();\n            }\n            catch (Exception exception)\n            {\n                LogErrorCancellingShutdownToken(log, exception);\n            }\n\n            foreach (var monitor in monitoredSilos.Values)\n            {\n                try\n                {\n                    monitor.Dispose();\n                }\n                catch (Exception exception)\n                {\n                    LogErrorDisposingMonitorForSilo(log, exception, monitor.TargetSiloAddress);\n                }\n            }\n        }\n\n        public async ValueTask DisposeAsync()\n        {\n            try\n            {\n                shutdownCancellation.Cancel();\n            }\n            catch (Exception exception)\n            {\n                LogErrorCancellingShutdownToken(log, exception);\n            }\n\n            var tasks = new List<Task>();\n            foreach (var monitor in monitoredSilos.Values)\n            {\n                try\n                {\n                    tasks.Add(monitor.DisposeAsync().AsTask());\n                }\n                catch (Exception exception)\n                {\n                    LogErrorDisposingMonitorForSilo(log, exception, monitor.TargetSiloAddress);\n                }\n            }\n\n            await Task.WhenAll(tasks).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n        }\n\n        // --- Logging methods ---\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting to process membership updates\"\n        )]\n        private static partial void LogDebugStartingToProcessMembershipUpdates(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopped processing membership updates\"\n        )]\n        private static partial void LogDebugStoppedProcessingMembershipUpdates(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stale silo with a joining or created state found, calling 'TryToSuspectOrKill'\"\n        )]\n        private static partial void LogDebugStaleSiloFound(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Silo {SuspectAddress} has had the status '{SiloStatus}' for longer than 'MaxJoinAttemptTime' but a call to 'TryToSuspectOrKill' has failed\"\n        )]\n        private static partial void LogErrorTryToSuspectOrKillFailed(ILogger logger, Exception exception, SiloAddress suspectAddress, SiloStatus siloStatus);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100305,\n            Level = LogLevel.Error,\n            Message = \"This silo {SiloAddress} status {Status} is not in its own local silo list! This is a bug!\"\n        )]\n        private static partial void LogErrorSiloNotInLocalList(ILogger logger, SiloAddress siloAddress, SiloStatus status);\n\n        private readonly struct ProbedSilosLogRecord(IEnumerable<SiloAddress> probedSilos)\n        {\n            public override string ToString() => Utils.EnumerableToString(probedSilos);\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipWatchList,\n            Level = LogLevel.Information,\n            Message = \"Will watch (actively ping) {ProbedSiloCount} silos: {ProbedSilos}\"\n        )]\n        private static partial void LogInformationWillWatchActivelyPing(ILogger logger, int probedSiloCount, ProbedSilosLogRecord probedSilos);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error cancelling shutdown token.\"\n        )]\n        private static partial void LogErrorCancellingShutdownToken(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error disposing monitor for {SiloAddress}.\"\n        )]\n        private static partial void LogErrorDisposingMonitorForSilo(ILogger logger, Exception exception, SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ClusterMember.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a cluster member.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class ClusterMember : IEquatable<ClusterMember>\n    {                \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterMember\"/> class.\n        /// </summary>                \n        /// <param name=\"siloAddress\">\n        /// The silo address.\n        /// </param>\n        /// <param name=\"status\">\n        /// The silo status.\n        /// </param>\n        /// <param name=\"name\">\n        /// The silo name.\n        /// </param>\n        public ClusterMember(SiloAddress siloAddress, SiloStatus status, string name)\n        {\n            this.SiloAddress = siloAddress ?? throw new ArgumentNullException(nameof(siloAddress));\n            this.Status = status;\n            this.Name = name;\n        }\n\n        /// <summary>\n        /// Gets the silo address.\n        /// </summary>\n        /// <value>The silo address.</value>\n        [Id(0)]\n        public SiloAddress SiloAddress { get; }\n\n        /// <summary>\n        /// Gets the silo status.\n        /// </summary>\n        /// <value>The silo status.</value>\n        [Id(1)]\n        public SiloStatus Status { get; }\n\n        /// <summary>\n        /// Gets the silo name.\n        /// </summary>\n        /// <value>The silo name.</value>\n        [Id(2)]\n        public string Name { get; }\n\n        /// <inheritdoc/>\n        public override bool Equals(object obj) => this.Equals(obj as ClusterMember);\n\n        /// <inheritdoc/>\n        public bool Equals(ClusterMember other) => other != null\n            && this.SiloAddress.Equals(other.SiloAddress)\n            && this.Status == other.Status\n            && string.Equals(this.Name, other.Name, StringComparison.Ordinal);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.SiloAddress.GetConsistentHashCode();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{this.SiloAddress}/{this.Name}/{this.Status}\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ClusterMembershipService.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Runtime.Utilities;\n\nnamespace Orleans.Runtime\n{\n    internal partial class ClusterMembershipService : IClusterMembershipService, ILifecycleParticipant<ISiloLifecycle>, IDisposable\n    {\n        private readonly AsyncEnumerable<ClusterMembershipSnapshot> updates;\n        private readonly MembershipTableManager membershipTableManager;\n        private readonly ILogger<ClusterMembershipService> log;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private ClusterMembershipSnapshot snapshot;\n\n        public ClusterMembershipService(\n            MembershipTableManager membershipTableManager,\n            ILogger<ClusterMembershipService> log,\n            IFatalErrorHandler fatalErrorHandler)\n        {\n            this.snapshot = membershipTableManager.MembershipTableSnapshot.CreateClusterMembershipSnapshot();\n            this.updates = new AsyncEnumerable<ClusterMembershipSnapshot>(\n                initialValue: this.snapshot,\n                updateValidator: (previous, proposed) => proposed.Version > previous.Version,\n                onPublished: update => Interlocked.Exchange(ref this.snapshot, update));\n            this.membershipTableManager = membershipTableManager;\n            this.log = log;\n            this.fatalErrorHandler = fatalErrorHandler;\n        }\n\n        public ClusterMembershipSnapshot CurrentSnapshot\n        {\n            get\n            {\n                var tableSnapshot = this.membershipTableManager.MembershipTableSnapshot;\n                if (this.snapshot.Version == tableSnapshot.Version)\n                {\n                    return this.snapshot;\n                }\n\n                this.updates.TryPublish(tableSnapshot.CreateClusterMembershipSnapshot());\n                return this.snapshot;\n            }\n        }\n\n        public IAsyncEnumerable<ClusterMembershipSnapshot> MembershipUpdates => this.updates;\n\n        public ValueTask Refresh(MembershipVersion targetVersion) => Refresh(targetVersion, CancellationToken.None);\n        public ValueTask Refresh(MembershipVersion targetVersion, CancellationToken cancellationToken)\n        {\n            if (targetVersion != default && targetVersion != MembershipVersion.MinValue && this.snapshot.Version >= targetVersion)\n                return default;\n\n            return RefreshAsync(targetVersion, cancellationToken);\n\n            async ValueTask RefreshAsync(MembershipVersion v, CancellationToken cancellationToken)\n            {\n                var didRefresh = false;\n                do\n                {\n                    cancellationToken.ThrowIfCancellationRequested();\n                    if (!didRefresh || this.membershipTableManager.MembershipTableSnapshot.Version < v)\n                    {\n                        await this.membershipTableManager.Refresh();\n                        didRefresh = true;\n                    }\n\n                    await Task.Delay(TimeSpan.FromMilliseconds(10), cancellationToken);\n                } while (this.snapshot.Version < v || this.snapshot.Version < this.membershipTableManager.MembershipTableSnapshot.Version);\n            }\n        }\n\n        public async Task<bool> TryKill(SiloAddress siloAddress) => await this.membershipTableManager.TryKill(siloAddress);\n\n        private async Task ProcessMembershipUpdates(CancellationToken ct)\n        {\n            try\n            {\n                LogDebugStartingToProcessMembershipUpdates(log);\n                await foreach (var tableSnapshot in this.membershipTableManager.MembershipTableUpdates.WithCancellation(ct))\n                {\n                    this.updates.TryPublish(tableSnapshot.CreateClusterMembershipSnapshot());\n                }\n            }\n            catch (OperationCanceledException) when (ct.IsCancellationRequested)\n            {\n                // Ignore and continue shutting down.\n            }\n            catch (Exception exception) when (this.fatalErrorHandler.IsUnexpected(exception))\n            {\n                LogErrorProcessingMembershipUpdates(log, exception);\n                this.fatalErrorHandler.OnFatalException(this, nameof(ProcessMembershipUpdates), exception);\n            }\n            finally\n            {\n                LogDebugStoppingMembershipUpdateProcessor(log);\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            var tasks = new List<Task>(1);\n            var cancellation = new CancellationTokenSource();\n            Task OnRuntimeInitializeStart(CancellationToken _)\n            {\n                tasks.Add(Task.Run(() => this.ProcessMembershipUpdates(cancellation.Token)));\n                return Task.CompletedTask;\n            }\n\n            async Task OnRuntimeInitializeStop(CancellationToken ct)\n            {\n                cancellation.Cancel(throwOnFirstException: false);\n                var shutdownGracePeriod = Task.WhenAll(Task.Delay(ClusterMembershipOptions.ClusteringShutdownGracePeriod), ct.WhenCancelled());\n                await Task.WhenAny(shutdownGracePeriod, Task.WhenAll(tasks));\n            }\n\n            lifecycle.Subscribe(\n                nameof(ClusterMembershipService),\n                ServiceLifecycleStage.RuntimeInitialize,\n                OnRuntimeInitializeStart,\n                OnRuntimeInitializeStop);\n        }\n\n        void IDisposable.Dispose()\n        {\n            this.updates.Dispose();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting to process membership updates\"\n        )]\n        private static partial void LogDebugStartingToProcessMembershipUpdates(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error processing membership updates\"\n        )]\n        private static partial void LogErrorProcessingMembershipUpdates(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopping membership update processor\"\n        )]\n        private static partial void LogDebugStoppingMembershipUpdateProcessor(ILogger logger);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ClusterMembershipSnapshot.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Text;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a snapshot of cluster membership.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class ClusterMembershipSnapshot\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterMembershipSnapshot\"/> class.\n        /// </summary>\n        /// <param name=\"members\">The cluster members.</param>\n        /// <param name=\"version\">The cluster membership version.</param>\n        public ClusterMembershipSnapshot(ImmutableDictionary<SiloAddress, ClusterMember> members, MembershipVersion version)\n        {\n            this.Members = members;\n            this.Version = version;\n        }\n\n        internal static ClusterMembershipSnapshot Default => new(ImmutableDictionary<SiloAddress, ClusterMember>.Empty, MembershipVersion.MinValue);\n\n        /// <summary>\n        /// Gets the cluster members.\n        /// </summary>\n        /// <value>The cluster members.</value>\n        [Id(0)]\n        public ImmutableDictionary<SiloAddress, ClusterMember> Members { get; }\n\n        /// <summary>\n        /// Gets the cluster membership version.\n        /// </summary>\n        /// <value>The cluster membership version.</value>\n        [Id(1)]\n        public MembershipVersion Version { get; }\n\n        /// <summary>\n        /// Gets status of the specified silo.\n        /// </summary>\n        /// <param name=\"silo\">The silo.</param>\n        /// <returns>The status of the specified silo.</returns>\n        public SiloStatus GetSiloStatus(SiloAddress silo)\n        {\n            var status = this.Members.TryGetValue(silo, out var entry) ? entry.Status : SiloStatus.None;\n            if (status == SiloStatus.None)\n            {\n                foreach (var member in this.Members)\n                {\n                    if (member.Key.IsSuccessorOf(silo))\n                    {\n                        status = SiloStatus.Dead;\n                        break;\n                    }\n                }\n            }\n\n            return status;\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"ClusterMembershipUpdate\"/> which represents this instance.\n        /// </summary>\n        /// <returns>A <see cref=\"ClusterMembershipUpdate\"/> which represents this instance.</returns>\n        public ClusterMembershipUpdate AsUpdate() => new ClusterMembershipUpdate(this, this.Members.Values.ToImmutableArray());\n        \n        /// <summary>\n        /// Returns a <see cref=\"ClusterMembershipUpdate\"/> which represents the change in cluster membership from the provided snapshot to this instance.\n        /// </summary>\n        /// <returns>A <see cref=\"ClusterMembershipUpdate\"/> which represents the change in cluster membership from the provided snapshot to this instance.</returns>\n        public ClusterMembershipUpdate CreateUpdate(ClusterMembershipSnapshot previous)\n        {\n            if (previous is null) throw new ArgumentNullException(nameof(previous));\n            if (this.Version < previous.Version)\n            {\n                throw new ArgumentException($\"Argument must have a previous version to the current instance. Expected <= {this.Version}, encountered {previous.Version}\", nameof(previous));\n            }\n\n            if (this.Version == previous.Version)\n            {\n                return new ClusterMembershipUpdate(this, ImmutableArray<ClusterMember>.Empty);\n            }\n\n            var changes = ImmutableHashSet.CreateBuilder<ClusterMember>();\n            foreach (var entry in this.Members)\n            {\n                // Include any entry which is new or has changed state.\n                if (!previous.Members.TryGetValue(entry.Key, out var previousEntry) || previousEntry.Status != entry.Value.Status)\n                {\n                    changes.Add(entry.Value);\n                }\n            }\n\n            // Handle entries which were removed entirely.\n            foreach (var entry in previous.Members)\n            {\n                if (!this.Members.TryGetValue(entry.Key, out _))\n                {\n                    changes.Add(new ClusterMember(entry.Key, SiloStatus.Dead, entry.Value.Name));\n                }\n            }\n\n            return new ClusterMembershipUpdate(this, changes.ToImmutableArray());\n        }\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n            sb.Append($\"ClusterMembershipSnapshot {{ Version = {this.Version}, Members.Count = {this.Members.Count}, Members = [\");\n            var first = true;\n            foreach (var member in this.Members)\n            {\n                if (first)\n                {\n                    first = false;\n                }\n                else\n                {\n                    sb.Append(\", \");\n                }\n\n                sb.Append(member.Value);\n            }\n\n            sb.Append(\"] }}\");\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ClusterMembershipUpdate.cs",
    "content": "using System;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a cluster membership snapshot and changes from a previous snapshot.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class ClusterMembershipUpdate\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterMembershipUpdate\"/> class.\n        /// </summary>\n        /// <param name=\"snapshot\">The snapshot.</param>\n        /// <param name=\"changes\">The changes.</param>\n        public ClusterMembershipUpdate(ClusterMembershipSnapshot snapshot, ImmutableArray<ClusterMember> changes)\n        {\n            this.Snapshot = snapshot;\n            this.Changes = changes;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has changes.\n        /// </summary>\n        /// <value><see langword=\"true\"/> if this instance has changes; otherwise, <see langword=\"false\"/>.</value>\n        public bool HasChanges => !this.Changes.IsDefaultOrEmpty;\n\n        /// <summary>\n        /// Gets the changes.\n        /// </summary>\n        /// <value>The changes.</value>\n        [Id(0)]\n        public ImmutableArray<ClusterMember> Changes { get; }\n\n        /// <summary>\n        /// Gets the snapshot.\n        /// </summary>\n        /// <value>The snapshot.</value>\n        [Id(1)]\n        public ClusterMembershipSnapshot Snapshot { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/DevelopmentClusterMembershipOptions.cs",
    "content": "using System.Net;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>Configures development clustering options</summary>\n    public class DevelopmentClusterMembershipOptions\n    {\n        /// <summary>\n        /// Gets or sets the seed node to find the membership system grain.\n        /// </summary>\n        public IPEndPoint PrimarySiloEndpoint { get; set; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/DevelopmentClusterMembershipOptionsValidator.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Configuration\n{\n    internal class DevelopmentClusterMembershipOptionsValidator : IConfigurationValidator\n    {\n        private readonly DevelopmentClusterMembershipOptions options;\n        private readonly IMembershipTable membershipTable;\n\n        public DevelopmentClusterMembershipOptionsValidator(IOptions<DevelopmentClusterMembershipOptions> options, IServiceProvider serviceProvider)\n        {\n            this.options = options.Value;\n            this.membershipTable = serviceProvider.GetService<IMembershipTable>();\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (this.membershipTable is SystemTargetBasedMembershipTable && this.options.PrimarySiloEndpoint is null)\n            {\n                throw new OrleansConfigurationException(\"Development clustering is enabled but no value is specified \");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/IClusterMembershipService.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Functionality for querying and interacting with cluster membership.\n    /// </summary>\n    public interface IClusterMembershipService\n    {\n        /// <summary>\n        /// Gets the most recent cluster membership snapshot.\n        /// </summary>\n        /// <value>The current snapshot.</value>\n        ClusterMembershipSnapshot CurrentSnapshot { get; }\n\n        /// <summary>\n        /// Gets an enumerable collection of membership updates.\n        /// </summary>\n        /// <value>The membership updates.</value>\n        IAsyncEnumerable<ClusterMembershipSnapshot> MembershipUpdates { get; }\n\n        /// <summary>\n        /// Refreshes cluster membership if it is not at or above the specified minimum version.\n        /// </summary>\n        /// <param name=\"minimumVersion\">The minimum version.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>A <see cref=\"ValueTask\"/> representing the work performed.</returns>\n        ValueTask Refresh(MembershipVersion minimumVersion = default, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Unilaterally declares the specified silo defunct.\n        /// </summary>\n        /// <param name=\"siloAddress\">The silo address which is being declared defunct.</param>\n        /// <returns><see langword=\"true\"/> if the silo has been evicted, <see langword=\"false\"/> otherwise.</returns>\n        Task<bool> TryKill(SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/IMembershipGossiper.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal interface IMembershipGossiper\n    {\n        Task GossipToRemoteSilos(\n            List<SiloAddress> gossipPartners,\n            MembershipTableSnapshot snapshot,\n            SiloAddress updatedSilo,\n            SiloStatus updatedStatus);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/IRemoteSiloProber.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Responsible for probing remote silos for responsiveness.\n    /// </summary>\n    internal interface IRemoteSiloProber\n    {\n        /// <summary>\n        /// Probes the specified <paramref name=\"silo\"/> for responsiveness.\n        /// </summary>\n        /// <param name=\"silo\">The silo to probe.</param>\n        /// <param name=\"probeNumber\">The probe identifier for diagnostic purposes.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns>\n        /// A <see cref=\"Task\"/> which completes when the probe returns successfully and faults when the probe fails.\n        /// </returns>\n        Task Probe(SiloAddress silo, int probeNumber, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Probes the specified <paramref name=\"target\"/> indirectly, via <paramref name=\"intermediary\"/>.\n        /// </summary>\n        /// <param name=\"intermediary\">The silo which will perform a direct probe.</param>\n        /// <param name=\"target\">The silo which will be probed.</param>\n        /// <param name=\"probeTimeout\">The timeout which the <paramref name=\"intermediary\" /> should apply to the probe.</param>\n        /// <param name=\"probeNumber\">The probe number for diagnostic purposes.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        Task<IndirectProbeResponse> ProbeIndirectly(SiloAddress intermediary, SiloAddress target, TimeSpan probeTimeout, int probeNumber, CancellationToken cancellationToken = default);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ISiloStatusListener.cs",
    "content": "﻿namespace Orleans.Runtime\n{\n    /// <summary>\n    /// Interface for types which listen to silo status change notifications.\n    /// </summary>\n    /// <remarks>\n    /// To be implemented by different in-silo runtime components that are interested in silo status notifications from ISiloStatusOracle.\n    /// </remarks>\n    public interface ISiloStatusListener\n    {\n        /// <summary>\n        /// Receive notifications about silo status events. \n        /// </summary>\n        /// <param name=\"updatedSilo\">A silo to update about.</param>\n        /// <param name=\"status\">The status of a silo.</param>\n        void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/ISiloStatusOracle.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Authoritative local, per-silo source for information about the status of other silos.\n    /// </summary>\n    public interface ISiloStatusOracle\n    {\n        /// <summary>\n        /// Gets the current status of this silo.\n        /// </summary>\n        SiloStatus CurrentStatus { get; }\n\n        /// <summary>\n        /// Gets the name of this silo.\n        /// </summary>\n        string SiloName { get; }\n\n        /// <summary>\n        /// Gets the address of this silo.\n        /// </summary>\n        SiloAddress SiloAddress { get; }\n\n        /// <summary>\n        /// Gets the currently active silos.\n        /// </summary>\n        ImmutableArray<SiloAddress> GetActiveSilos();\n\n        /// <summary>\n        /// Gets the status of a given silo. \n        /// This method returns an approximate view on the status of a given silo. \n        /// In particular, this oracle may think the given silo is alive, while it may already have failed.\n        /// If this oracle thinks the given silo is dead, it has been authoritatively told so by ISiloDirectory.\n        /// </summary>\n        /// <param name=\"siloAddress\">A silo whose status we are interested in.</param>\n        /// <returns>The status of a given silo.</returns>\n        SiloStatus GetApproximateSiloStatus(SiloAddress siloAddress);\n\n        /// <summary>\n        /// Gets the statuses of all silo. \n        /// This method returns an approximate view on the statuses of all silo.\n        /// </summary>\n        /// <param name=\"onlyActive\">Include only silo who are currently considered to be active. If false, include all.</param>\n        /// <returns>A list of silo statuses.</returns>\n        Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false);\n\n        /// <summary>\n        /// Gets the name of a silo. \n        /// Silo name is assumed to be static and does not change across restarts of the same silo.\n        /// </summary>\n        /// <param name=\"siloAddress\">A silo whose name we are interested in.</param>\n        /// <param name=\"siloName\">A silo name.</param>\n        /// <returns>TTrue if could return the requested name, false otherwise.</returns>\n        bool TryGetSiloName(SiloAddress siloAddress, out string siloName);\n\n        /// <summary>\n        /// Gets a value indicating whether the current silo is valid for creating new activations on or for directory lookups.\n        /// </summary>\n        /// <returns>The silo so ask about.</returns>\n        bool IsFunctionalDirectory(SiloAddress siloAddress);\n\n        /// <summary>\n        /// Gets a value indicating whether the current silo is dead.\n        /// </summary>\n        /// <returns>The silo so ask about.</returns>\n        bool IsDeadSilo(SiloAddress silo);\n\n        /// <summary>\n        /// Subscribe to status events about all silos. \n        /// </summary>\n        /// <param name=\"observer\">An observer async interface to receive silo status notifications.</param>\n        /// <returns>A value indicating whether subscription succeeded or not.</returns>\n        bool SubscribeToSiloStatusEvents(ISiloStatusListener observer);\n\n        /// <summary>\n        /// UnSubscribe from status events about all silos. \n        /// </summary>\n        /// <returns>A value indicating whether subscription succeeded or not.</returns>\n        bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener observer);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/InMemoryMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal class InMemoryMembershipTable\n    {\n        private readonly Dictionary<SiloAddress, Tuple<MembershipEntry, string>> siloTable;\n        private TableVersion tableVersion;\n        private long lastETagCounter;\n\n        [NonSerialized]\n        private readonly DeepCopier deepCopier;\n\n        public InMemoryMembershipTable(DeepCopier deepCopier)\n        {\n            this.deepCopier = deepCopier;\n            siloTable = new Dictionary<SiloAddress, Tuple<MembershipEntry, string>>();\n            lastETagCounter = 0;\n            tableVersion = new TableVersion(0, NewETag());\n        }\n\n        public MembershipTableData Read(SiloAddress key)\n        {\n            return siloTable.TryGetValue(key, out var data) ?\n                new MembershipTableData(this.deepCopier.Copy(data), tableVersion)\n                : new MembershipTableData(tableVersion);\n        }\n\n        public MembershipTableData ReadAll()\n        {\n            return new MembershipTableData(siloTable.Values.Select(tuple =>\n                new Tuple<MembershipEntry, string>(this.deepCopier.Copy(tuple.Item1), tuple.Item2)).ToList(), tableVersion);\n        }\n\n        public TableVersion ReadTableVersion()\n        {\n            return tableVersion;\n        }\n\n        public bool Insert(MembershipEntry entry, TableVersion version)\n        {\n            Tuple<MembershipEntry, string> data;\n            siloTable.TryGetValue(entry.SiloAddress, out data);\n            if (data != null) return false;\n            if (!tableVersion.VersionEtag.Equals(version.VersionEtag)) return false;\n\n            siloTable[entry.SiloAddress] = new Tuple<MembershipEntry, string>(\n                entry, lastETagCounter++.ToString(CultureInfo.InvariantCulture));\n            tableVersion = new TableVersion(version.Version, NewETag());\n            return true;\n        }\n\n        public bool Update(MembershipEntry entry, string etag, TableVersion version)\n        {\n            Tuple<MembershipEntry, string> data;\n            siloTable.TryGetValue(entry.SiloAddress, out data);\n            if (data == null) return false;\n            if (!data.Item2.Equals(etag) || !tableVersion.VersionEtag.Equals(version.VersionEtag)) return false;\n\n            siloTable[entry.SiloAddress] = new Tuple<MembershipEntry, string>(\n                entry, lastETagCounter++.ToString(CultureInfo.InvariantCulture));\n            tableVersion = new TableVersion(version.Version, NewETag());\n            return true;\n        }\n\n        public void UpdateIAmAlive(MembershipEntry entry)\n        {\n            Tuple<MembershipEntry, string> data;\n            siloTable.TryGetValue(entry.SiloAddress, out data);\n            if (data == null) return;\n\n            data.Item1.IAmAliveTime = entry.IAmAliveTime;\n            siloTable[entry.SiloAddress] = new Tuple<MembershipEntry, string>(data.Item1, NewETag());\n        }\n\n        public override string ToString() => $\"Table = {ReadAll()}, ETagCounter={lastETagCounter}\";\n\n        private string NewETag()\n        {\n            return lastETagCounter++.ToString(CultureInfo.InvariantCulture);\n        }\n\n        public void CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            var removedEnties = new List<SiloAddress>();\n            foreach (var (key, (value, etag)) in siloTable)\n            {\n                if (value.Status == SiloStatus.Dead\n                    && new DateTime(Math.Max(value.IAmAliveTime.Ticks, value.StartTime.Ticks), DateTimeKind.Utc) < beforeDate)\n                {\n                    removedEnties.Add(key);\n                }\n            }\n\n            foreach (var removedEntry in removedEnties)\n            {\n                siloTable.Remove(removedEntry);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/LocalSiloHealthMonitor.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal interface ILocalSiloHealthMonitor\n    {\n        /// <summary>\n        /// Returns the local health degradation score, which is a value between 0 (healthy) and <see cref=\"LocalSiloHealthMonitor.MaxScore\"/> (unhealthy).\n        /// </summary>\n        /// <param name=\"checkTime\">The time which the check is taking place.</param>\n        /// <returns>The local health degradation score, which is a value between 0 (healthy) and <see cref=\"LocalSiloHealthMonitor.MaxScore\"/> (unhealthy).</returns>\n        int GetLocalHealthDegradationScore(DateTime checkTime);\n\n        /// <summary>\n        /// The most recent list of detected health issues.\n        /// </summary>\n        ImmutableArray<string> Complaints { get; }\n    }\n\n    /// <summary>\n    /// Monitors the health of the local node using a combination of heuristics to create a health degradation score which\n    /// is exposed as a boolean value: whether or not the local node's health is degraded.\n    /// </summary>\n    /// <remarks>\n    /// The primary goal of this functionality is to passify degraded nodes so that they do not evict healthy nodes.\n    /// This functionality is inspired by the Lifeguard paper (https://arxiv.org/abs/1707.00788), which is a set of extensions\n    /// to the SWIM membership algorithm (https://research.cs.cornell.edu/projects/Quicksilver/public_pdfs/SWIM.pdf). Orleans\n    /// uses a strong consistency membership algorithm, and not all of the Lifeguard extensions to SWIM apply to Orleans'\n    /// membership algorithm (refutation, for example).\n    /// The monitor implements the following heuristics:\n    /// <list type=\"bullet\">\n    ///   <item><description>Check that this silos is marked as active in membership.</description></item>\n    ///   <item><description>Check that no other silo suspects this silo.</description></item>\n    ///   <item><description>Check for recently received successful ping responses.</description></item>\n    ///   <item><description>Check for recently received ping requests.</description></item>\n    ///   <item><description>Check that the .NET Thread Pool is able to process work items within one second.</description></item>\n    ///   <item><description>Check that local async timers have been firing on-time (within 3 seconds of their due time).</description></item>\n    /// </list>\n    /// </remarks>\n    internal partial class LocalSiloHealthMonitor : ILifecycleParticipant<ISiloLifecycle>, ILifecycleObserver, ILocalSiloHealthMonitor\n    {\n        private const int MaxScore = 8;\n        private readonly List<IHealthCheckParticipant> _healthCheckParticipants;\n        private readonly MembershipTableManager _membershipTableManager;\n        private readonly ClusterHealthMonitor _clusterHealthMonitor;\n        private readonly ILocalSiloDetails _localSiloDetails;\n        private readonly ILogger<LocalSiloHealthMonitor> _lo;\n        private readonly ClusterMembershipOptions _clusterMembershipOptions;\n        private readonly IAsyncTimer _degradationCheckTimer;\n        private readonly ThreadPoolMonitor _threadPoolMonitor;\n        private readonly ProbeRequestMonitor _probeRequestMonitor;\n        private ValueStopwatch _clusteredDuration;\n        private Task? _runTask;\n        private bool _isActive;\n        private DateTime _lastHealthCheckTime;\n\n        public LocalSiloHealthMonitor(\n            IEnumerable<IHealthCheckParticipant> healthCheckParticipants,\n            MembershipTableManager membershipTableManager,\n            ConnectionManager connectionManager,\n            ClusterHealthMonitor clusterHealthMonitor,\n            ILocalSiloDetails localSiloDetails,\n            ILogger<LocalSiloHealthMonitor> log,\n            IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n            IAsyncTimerFactory timerFactory,\n            ILoggerFactory loggerFactory,\n            ProbeRequestMonitor probeRequestMonitor)\n        {\n            _healthCheckParticipants = healthCheckParticipants.ToList();\n            _membershipTableManager = membershipTableManager;\n            _clusterHealthMonitor = clusterHealthMonitor;\n            _localSiloDetails = localSiloDetails;\n            _lo = log;\n            _probeRequestMonitor = probeRequestMonitor;\n            _clusterMembershipOptions = clusterMembershipOptions.Value;\n            _degradationCheckTimer = timerFactory.Create(\n                _clusterMembershipOptions.LocalHealthDegradationMonitoringPeriod,\n                nameof(LocalSiloHealthMonitor));\n            _threadPoolMonitor = new ThreadPoolMonitor(loggerFactory.CreateLogger<ThreadPoolMonitor>());\n        }\n\n        /// <inheritdoc />\n        public ImmutableArray<string> Complaints { get; private set; } = ImmutableArray<string>.Empty;\n\n        /// <inheritdoc />\n        public int GetLocalHealthDegradationScore(DateTime checkTime) => GetLocalHealthDegradationScore(checkTime, null);\n\n        /// <summary>\n        /// Returns the local health degradation score, which is a value between 0 (healthy) and <see cref=\"MaxScore\"/> (unhealthy).\n        /// </summary>\n        /// <param name=\"checkTime\">The time which the check is taking place.</param>\n        /// <param name=\"complaints\">If not null, will be populated with the current set of detected health issues.</param>\n        /// <returns>The local health degradation score, which is a value between 0 (healthy) and <see cref=\"MaxScore\"/> (unhealthy).</returns>\n        public int GetLocalHealthDegradationScore(DateTime checkTime, List<string>? complaints)\n        {\n            var score = 0;\n            score += CheckSuspectingNodes(checkTime, complaints);\n            score += CheckLocalHealthCheckParticipants(checkTime, complaints);\n            score += CheckThreadPoolQueueDelay(checkTime, complaints);\n\n            if (_isActive)\n            {\n                var membershipSnapshot = _membershipTableManager.MembershipTableSnapshot;\n                if (membershipSnapshot.ActiveNodeCount <= 1)\n                {\n                    _clusteredDuration.Reset();\n                }\n                else if (!_clusteredDuration.IsRunning)\n                {\n                    _clusteredDuration.Restart();\n                }\n\n                // Only consider certain checks if the silo has been a member of a multi-silo cluster for a certain period.\n                var recencyWindow = _clusterMembershipOptions.ProbeTimeout.Multiply(_clusterMembershipOptions.NumMissedProbesLimit);\n                if (_clusteredDuration.Elapsed > recencyWindow)\n                {\n                    score += CheckReceivedProbeResponses(checkTime, complaints);\n                    score += CheckReceivedProbeRequests(checkTime, complaints);\n                }\n            }\n\n            // Clamp the score between 0 and the maximum allowed score.\n            score = Math.Max(0, Math.Min(MaxScore, score));\n            return score;\n        }\n\n        private int CheckThreadPoolQueueDelay(DateTime checkTime, List<string>? complaints)\n        {\n            var threadPoolDelaySeconds = _threadPoolMonitor.MeasureQueueDelay().TotalSeconds;\n\n            if ((int)threadPoolDelaySeconds >= 1)\n            {\n                // Log as an error if the delay is massive.\n                var logLevel = (int)threadPoolDelaySeconds >= 10 ? LogLevel.Error : LogLevel.Warning;\n                LogThreadPoolDelay(logLevel, threadPoolDelaySeconds);\n\n                complaints?.Add(\n                    $\".NET Thread Pool is exhibiting delays of {threadPoolDelaySeconds}s. This can indicate .NET Thread Pool starvation, very long .NET GC pauses, or other runtime or machine pauses.\");\n            }\n\n            // Each second of delay contributes to the score.\n            return (int)threadPoolDelaySeconds;\n        }\n\n        private int CheckSuspectingNodes(DateTime now, List<string>? complaints)\n        {\n            var score = 0;\n            var membershipSnapshot = _membershipTableManager.MembershipTableSnapshot;\n            if (membershipSnapshot.Entries.TryGetValue(_localSiloDetails.SiloAddress, out var membershipEntry))\n            {\n                if (membershipEntry.Status != SiloStatus.Active)\n                {\n                    LogSiloNotActive(membershipEntry.Status);\n                    complaints?.Add($\"This silo is not active (Status: {membershipEntry.Status}) and is therefore not healthy.\");\n\n                    score = MaxScore;\n                }\n\n                // Check if there are valid votes against this node.\n                var expiration = _clusterMembershipOptions.DeathVoteExpirationTimeout;\n                var freshVotes = membershipEntry.GetFreshVotes(now, expiration);\n                foreach (var vote in freshVotes)\n                {\n                    if (membershipSnapshot.GetSiloStatus(vote.Item1) == SiloStatus.Active)\n                    {\n                        LogSiloSuspected(vote.Item1, vote.Item2);\n                        complaints?.Add($\"Silo {vote.Item1} recently suspected this silo is dead at {vote.Item2}.\");\n\n                        ++score;\n                    }\n                }\n            }\n            else\n            {\n                LogMembershipEntryNotFound();\n                complaints?.Add(\"Could not find a membership entry for this silo\");\n\n                score = MaxScore;\n            }\n\n            return score;\n        }\n\n        private int CheckReceivedProbeRequests(DateTime now, List<string>? complaints)\n        {\n            // Have we received ping REQUESTS from other nodes?\n            var score = 0;\n            var membershipSnapshot = _membershipTableManager.MembershipTableSnapshot;\n\n            // Only consider recency of the last received probe request if there is more than one other node.\n            // Otherwise, it may fail to vote another node dead in a one or two node cluster.\n            if (membershipSnapshot.ActiveNodeCount > 2)\n            {\n                var sinceLastProbeRequest = _probeRequestMonitor.ElapsedSinceLastProbeRequest;\n                var recencyWindow = _clusterMembershipOptions.ProbeTimeout.Multiply(_clusterMembershipOptions.NumMissedProbesLimit);\n                if (!sinceLastProbeRequest.HasValue)\n                {\n                    LogNoProbeRequests();\n                    complaints?.Add(\"This silo has not received any probe requests\");\n                    ++score;\n                }\n                else if (sinceLastProbeRequest.Value > recencyWindow)\n                {\n                    // This node has not received a successful ping response since the window began.\n                    var lastRequestTime = now - sinceLastProbeRequest.Value;\n                    LogNoRecentProbeRequest(lastRequestTime);\n                    complaints?.Add($\"This silo has not received a probe request since {lastRequestTime}\");\n                    ++score;\n                }\n            }\n\n            return score;\n        }\n\n        private int CheckReceivedProbeResponses(DateTime now, List<string>? complaints)\n        {\n            // Determine how recently the latest successful ping response was received.\n            var siloMonitors = _clusterHealthMonitor.SiloMonitors;\n            var elapsedSinceLastResponse = default(TimeSpan?);\n            foreach (var monitor in siloMonitors.Values)\n            {\n                var current = monitor.ElapsedSinceLastResponse;\n                if (current.HasValue && (!elapsedSinceLastResponse.HasValue || current.Value < elapsedSinceLastResponse.Value))\n                {\n                    elapsedSinceLastResponse = current.Value;\n                }\n            }\n\n            // Only consider recency of the last successful ping if this node is monitoring more than one other node.\n            // Otherwise, it may fail to vote another node dead in a one or two node cluster.\n            int score = 0;\n            if (siloMonitors.Count > 1)\n            {\n                var recencyWindow = _clusterMembershipOptions.ProbeTimeout.Multiply(_clusterMembershipOptions.NumMissedProbesLimit);\n                if (!elapsedSinceLastResponse.HasValue)\n                {\n                    LogNoProbeResponses();\n                    complaints?.Add(\"This silo has not received any successful probe responses\");\n                    ++score;\n                }\n                else if (elapsedSinceLastResponse.Value > recencyWindow)\n                {\n                    // This node has not received a successful ping response since the window began.\n                    LogNoRecentProbeResponse(elapsedSinceLastResponse.Value);\n                    complaints?.Add($\"This silo has not received a successful probe response since {elapsedSinceLastResponse.Value}\");\n                    ++score;\n                }\n            }\n\n            return score;\n        }\n\n        private int CheckLocalHealthCheckParticipants(DateTime now, List<string>? complaints)\n        {\n            // Check for execution delays and other local health warning signs.\n            var score = 0;\n            foreach (var participant in _healthCheckParticipants)\n            {\n                try\n                {\n                    if (!participant.CheckHealth(_lastHealthCheckTime, out var reason))\n                    {\n                        LogHealthCheckParticipantUnhealthy(participant.GetType(), reason);\n                        complaints?.Add($\"Health check participant {participant.GetType()} is reporting that it is unhealthy with complaint: {reason}\");\n\n                        ++score;\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogHealthCheckParticipantError(exception, participant.GetType());\n                    complaints?.Add($\"Error checking health for participant {participant.GetType()}: {LogFormatter.PrintException(exception)}\");\n\n                    ++score;\n                }\n            }\n\n            _lastHealthCheckTime = now;\n            return score;\n        }\n\n        private async Task Run()\n        {\n            while (await _degradationCheckTimer.NextTick())\n            {\n                try\n                {\n                    var complaints = new List<string>();\n                    var now = DateTime.UtcNow;\n                    var score = GetLocalHealthDegradationScore(now, complaints);\n                    if (score > 0)\n                    {\n                        var complaintsString = string.Join(\"\\n\", complaints);\n                        LogSelfMonitoringDegraded(score, MaxScore, complaintsString);\n                    }\n\n                    this.Complaints = ImmutableArray.CreateRange(complaints);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorMonitoringLocalSiloHealth(exception);\n                }\n            }\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(ServiceLifecycleStage.Active, this);\n        }\n\n        public Task OnStart(CancellationToken ct)\n        {\n            _runTask = Task.Run(this.Run);\n            _isActive = true;\n            return Task.CompletedTask;\n        }\n\n        public async Task OnStop(CancellationToken ct)\n        {\n            _degradationCheckTimer.Dispose();\n            _isActive = false;\n\n            if (_runTask is Task task)\n            {\n                await task.WaitAsync(ct).SuppressThrowing();\n            }\n        }\n\n        /// <summary>\n        /// Measures queue delay on the .NET <see cref=\"ThreadPool\"/>.\n        /// </summary>\n        private class ThreadPoolMonitor\n        {\n            private static readonly WaitCallback Callback = state => ((ThreadPoolMonitor)state!).Execute();\n#if NET9_0_OR_GREATER\n            private readonly Lock _lockObj = new();\n#else\n            private readonly object _lockObj = new();\n#endif\n            private readonly ILogger<ThreadPoolMonitor> _log;\n            private bool _scheduled;\n            private TimeSpan _lastQueueDelay;\n            private ValueStopwatch _queueDelay;\n\n            public ThreadPoolMonitor(ILogger<ThreadPoolMonitor> log)\n            {\n                _log = log;\n            }\n\n            public TimeSpan MeasureQueueDelay()\n            {\n                bool shouldSchedule;\n                TimeSpan delay;\n                lock (_lockObj)\n                {\n                    var currentQueueDelay = _queueDelay.Elapsed;\n                    delay = currentQueueDelay > _lastQueueDelay ? currentQueueDelay : _lastQueueDelay;\n\n                    if (!_scheduled)\n                    {\n                        _scheduled = true;\n                        shouldSchedule = true;\n                        _queueDelay.Restart();\n                    }\n                    else\n                    {\n                        shouldSchedule = false;\n                    }\n                }\n\n                if (shouldSchedule)\n                {\n                    _ = ThreadPool.UnsafeQueueUserWorkItem(Callback, this);\n                }\n\n                return delay;\n            }\n\n            private void Execute()\n            {\n                try\n                {\n                    lock (_lockObj)\n                    {\n                        _scheduled = false;\n                        _queueDelay.Stop();\n                        _lastQueueDelay = _queueDelay.Elapsed;\n                    }\n                }\n                catch (Exception exception)\n                {\n                    _log.LogError(exception, \"Exception monitoring .NET thread pool delay\");\n                }\n            }\n        }\n\n        [LoggerMessage(\n            Message = \".NET Thread Pool is exhibiting delays of {ThreadPoolQueueDelaySeconds}s. This can indicate .NET Thread Pool starvation, very long .NET GC pauses, or other runtime or machine pauses.\"\n        )]\n        private partial void LogThreadPoolDelay(LogLevel logLevel, double threadPoolQueueDelaySeconds);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"This silo is not active (Status: {Status}) and is therefore not healthy.\"\n        )]\n        private partial void LogSiloNotActive(SiloStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Silo {Silo} recently suspected this silo is dead at {SuspectingTime}.\"\n        )]\n        private partial void LogSiloSuspected(SiloAddress silo, DateTime suspectingTime);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Could not find a membership entry for this silo\"\n        )]\n        private partial void LogMembershipEntryNotFound();\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"This silo has not received any probe requests\"\n        )]\n        private partial void LogNoProbeRequests();\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"This silo has not received a probe request since {LastProbeRequest}\"\n        )]\n        private partial void LogNoRecentProbeRequest(DateTime lastProbeRequest);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"This silo has not received any successful probe responses\"\n        )]\n        private partial void LogNoProbeResponses();\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"This silo has not received a successful probe response since {LastSuccessfulResponse}\"\n        )]\n        private partial void LogNoRecentProbeResponse(TimeSpan lastSuccessfulResponse);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Health check participant {Participant} is reporting that it is unhealthy with complaint: {Reason}\"\n        )]\n        private partial void LogHealthCheckParticipantUnhealthy(Type participant, string reason);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error checking health for {Participant}\"\n        )]\n        private partial void LogHealthCheckParticipantError(Exception exception, Type participant);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Self-monitoring determined that local health is degraded. Degradation score is {Score}/{MaxScore} (lower is better). Complaints: {Complaints}\"\n        )]\n        private partial void LogSelfMonitoringDegraded(int score, int maxScore, string complaints);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error while monitoring local silo health\"\n        )]\n        private partial void LogErrorMonitoringLocalSiloHealth(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipAgent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing System.Threading.Tasks;\nusing System.Threading;\nusing Microsoft.Extensions.Options;\nusing System.Linq;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Responsible for updating membership table with details about the local silo.\n    /// </summary>\n    internal partial class MembershipAgent : IHealthCheckParticipant, ILifecycleParticipant<ISiloLifecycle>, IDisposable, MembershipAgent.ITestAccessor\n    {\n        private static readonly TimeSpan EXP_BACKOFF_CONTENTION_MIN = TimeSpan.FromMilliseconds(200);\n        private static readonly TimeSpan EXP_BACKOFF_CONTENTION_MAX = TimeSpan.FromMinutes(2);\n        private static readonly TimeSpan EXP_BACKOFF_STEP = TimeSpan.FromMilliseconds(1000);\n        private readonly CancellationTokenSource cancellation = new CancellationTokenSource();\n        private readonly MembershipTableManager tableManager;\n        private readonly ILocalSiloDetails localSilo;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly ClusterMembershipOptions clusterMembershipOptions;\n        private readonly ILogger<MembershipAgent> log;\n        private readonly IRemoteSiloProber siloProber;\n        private readonly IAsyncTimer iAmAliveTimer;\n        private Func<DateTime> getUtcDateTime = () => DateTime.UtcNow;\n\n        public MembershipAgent(\n            MembershipTableManager tableManager,\n            ILocalSiloDetails localSilo,\n            IFatalErrorHandler fatalErrorHandler,\n            IOptions<ClusterMembershipOptions> options,\n            ILogger<MembershipAgent> log,\n            IAsyncTimerFactory timerFactory,\n            IRemoteSiloProber siloProber)\n        {\n            this.tableManager = tableManager;\n            this.localSilo = localSilo;\n            this.fatalErrorHandler = fatalErrorHandler;\n            this.clusterMembershipOptions = options.Value;\n            this.log = log;\n            this.siloProber = siloProber;\n            this.iAmAliveTimer = timerFactory.Create(\n                this.clusterMembershipOptions.IAmAliveTablePublishTimeout,\n                nameof(UpdateIAmAlive));\n        }\n\n        internal interface ITestAccessor\n        {\n            Action OnUpdateIAmAlive { get; set; }\n            Func<DateTime> GetDateTime { get; set; }\n        }\n\n        Action ITestAccessor.OnUpdateIAmAlive { get; set; }\n        Func<DateTime> ITestAccessor.GetDateTime { get => this.getUtcDateTime; set => this.getUtcDateTime = value ?? throw new ArgumentNullException(nameof(value)); }\n\n        private async Task UpdateIAmAlive()\n        {\n            LogDebugStartingPeriodicMembershipLivenessTimestampUpdates();\n            try\n            {\n                // jitter for initial\n                TimeSpan? overrideDelayPeriod = RandomTimeSpan.Next(this.clusterMembershipOptions.IAmAliveTablePublishTimeout);\n                var exponentialBackoff = new ExponentialBackoff(EXP_BACKOFF_CONTENTION_MIN, EXP_BACKOFF_CONTENTION_MAX, EXP_BACKOFF_STEP);\n                var runningFailures = 0;\n                while (await this.iAmAliveTimer.NextTick(overrideDelayPeriod) && !this.tableManager.CurrentStatus.IsTerminating())\n                {\n                    try\n                    {\n                        var stopwatch = ValueStopwatch.StartNew();\n                        ((ITestAccessor)this).OnUpdateIAmAlive?.Invoke();\n                        await this.tableManager.UpdateIAmAlive();\n                        LogTraceUpdatingIAmAliveTook(stopwatch.Elapsed);\n                        overrideDelayPeriod = default;\n                        runningFailures = 0;\n                    }\n                    catch (Exception exception)\n                    {\n                        runningFailures += 1;\n                        LogWarningFailedToUpdateTableEntryForThisSilo(exception);\n                        // Retry quickly and then exponentially back off\n                        overrideDelayPeriod = exponentialBackoff.Next(runningFailures);\n                    }\n                }\n            }\n            catch (Exception exception) when (this.fatalErrorHandler.IsUnexpected(exception))\n            {\n                LogErrorErrorUpdatingLivenessTimestamp(exception);\n                this.fatalErrorHandler.OnFatalException(this, nameof(UpdateIAmAlive), exception);\n            }\n            finally\n            {\n                LogDebugStoppingPeriodicMembershipLivenessTimestampUpdates();\n            }\n        }\n\n        private async Task BecomeActive()\n        {\n            LogInformationBecomeActive();\n            await this.ValidateInitialConnectivity();\n\n            try\n            {\n                await this.UpdateStatus(SiloStatus.Active);\n                LogInformationFinishedBecomeActive();\n            }\n            catch (Exception exception)\n            {\n                LogInformationBecomeActiveFailed(exception);\n                throw;\n            }\n        }\n\n        private async Task ValidateInitialConnectivity()\n        {\n            // Continue attempting to validate connectivity until some reasonable timeout.\n            var maxAttemptTime = this.clusterMembershipOptions.MaxJoinAttemptTime;\n            var attemptNumber = 1;\n            var now = this.getUtcDateTime();\n            var attemptUntil = now + maxAttemptTime;\n            var canContinue = true;\n\n            while (true)\n            {\n                try\n                {\n                    var activeSilos = new List<SiloAddress>();\n                    foreach (var item in this.tableManager.MembershipTableSnapshot.Entries)\n                    {\n                        var entry = item.Value;\n                        if (entry.Status != SiloStatus.Active) continue;\n                        if (entry.SiloAddress.IsSameLogicalSilo(this.localSilo.SiloAddress)) continue;\n                        if (entry.HasMissedIAmAlives(this.clusterMembershipOptions, now) != default) continue;\n\n                        activeSilos.Add(entry.SiloAddress);\n                    }\n\n                    var failedSilos = await CheckClusterConnectivity(activeSilos.ToArray());\n                    var successfulSilos = activeSilos.Where(s => !failedSilos.Contains(s)).ToList();\n\n                    // If there were no failures, terminate the loop and return without error.\n                    if (failedSilos.Count == 0) break;\n\n                    LogErrorFailedToGetPingResponses(failedSilos.Count, activeSilos.Count, new(successfulSilos), new(failedSilos), attemptUntil, attemptNumber);\n\n                    if (now + TimeSpan.FromSeconds(5) > attemptUntil)\n                    {\n                        canContinue = false;\n                        var msg = $\"Failed to get ping responses from {failedSilos.Count} of {activeSilos.Count} active silos. \"\n                            + \"Newly joining silos validate connectivity with all active silos that have recently updated their 'I Am Alive' value before joining the cluster. \"\n                            + $\"Successfully contacted: {Utils.EnumerableToString(successfulSilos)}. Failed to get response from: {Utils.EnumerableToString(failedSilos)}\";\n                        throw new OrleansClusterConnectivityCheckFailedException(msg);\n                    }\n\n                    // Refresh membership after some delay and retry.\n                    await Task.Delay(TimeSpan.FromSeconds(5));\n                    await this.tableManager.Refresh();\n                }\n                catch (Exception exception) when (canContinue)\n                {\n                    LogErrorFailedToValidateInitialClusterConnectivity(exception);\n                    await Task.Delay(TimeSpan.FromSeconds(1));\n                }\n\n                ++attemptNumber;\n                now = this.getUtcDateTime();\n            }\n\n            async Task<List<SiloAddress>> CheckClusterConnectivity(SiloAddress[] members)\n            {\n                if (members.Length == 0) return new List<SiloAddress>();\n\n                var tasks = new List<Task<bool>>(members.Length);\n\n                LogInformationAboutToSendPings(members.Length, new EnumerableToStringLogValue<SiloAddress>(members));\n\n                var timeout = this.clusterMembershipOptions.ProbeTimeout;\n                foreach (var silo in members)\n                {\n                    tasks.Add(ProbeSilo(this.siloProber, silo, timeout, this.log));\n                }\n\n                try\n                {\n                    await Task.WhenAll(tasks);\n                }\n                catch\n                {\n                    // Ignore exceptions for now.\n                }\n\n                var failed = new List<SiloAddress>();\n                for (var i = 0; i < tasks.Count; i++)\n                {\n                    if (tasks[i].Status != TaskStatus.RanToCompletion || !tasks[i].GetAwaiter().GetResult())\n                    {\n                        failed.Add(members[i]);\n                    }\n                }\n\n                return failed;\n            }\n\n            static async Task<bool> ProbeSilo(IRemoteSiloProber siloProber, SiloAddress silo, TimeSpan timeout, ILogger log)\n            {\n                Exception exception;\n                try\n                {\n                    await siloProber.Probe(silo, 0).WaitAsync(timeout);\n                    return true;\n                }\n                catch (Exception ex)\n                {\n                    exception = ex;\n                }\n\n                LogWarningDidNotReceiveProbeResponse(log, exception, silo, timeout);\n                return false;\n            }\n        }\n\n        private async Task BecomeJoining()\n        {\n            LogInformationJoining();\n            try\n            {\n                await this.UpdateStatus(SiloStatus.Joining);\n            }\n            catch (Exception exc)\n            {\n                LogErrorErrorUpdatingStatusToJoining(exc);\n                throw;\n            }\n        }\n\n        private async Task BecomeShuttingDown()\n        {\n            LogDebugShutdown();\n\n            try\n            {\n                await this.UpdateStatus(SiloStatus.ShuttingDown);\n            }\n            catch (Exception exc)\n            {\n                LogErrorErrorUpdatingStatusToShuttingDown(exc);\n                throw;\n            }\n        }\n\n        private async Task BecomeStopping()\n        {\n            LogDebugStop();\n\n            try\n            {\n                await this.UpdateStatus(SiloStatus.Stopping);\n            }\n            catch (Exception exc)\n            {\n                LogErrorErrorUpdatingStatusToStopping(exc);\n                throw;\n            }\n        }\n\n        private async Task BecomeDead()\n        {\n            LogDebugUpdatingStatusToDead();\n\n            try\n            {\n                await this.UpdateStatus(SiloStatus.Dead);\n            }\n            catch (Exception exception)\n            {\n                LogErrorFailureUpdatingStatusToDead(exception);\n                throw;\n            }\n        }\n\n        private async Task UpdateStatus(SiloStatus status)\n        {\n            await this.tableManager.UpdateStatus(status);\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            {\n                Task OnRuntimeInitializeStart(CancellationToken ct) => Task.CompletedTask;\n\n                async Task OnRuntimeInitializeStop(CancellationToken ct)\n                {\n                    this.iAmAliveTimer.Dispose();\n                    this.cancellation.Cancel();\n                    await Task.WhenAny(\n                        Task.Run(() => this.BecomeDead()),\n                        Task.Delay(TimeSpan.FromMinutes(1)));\n                }\n\n                lifecycle.Subscribe(\n                    nameof(MembershipAgent),\n                    ServiceLifecycleStage.RuntimeInitialize + 1, // Gossip before the outbound queue gets closed\n                    OnRuntimeInitializeStart,\n                    OnRuntimeInitializeStop);\n            }\n\n            {\n                async Task AfterRuntimeGrainServicesStart(CancellationToken ct)\n                {\n                    await Task.Run(() => this.BecomeJoining());\n                }\n\n                Task AfterRuntimeGrainServicesStop(CancellationToken ct) => Task.CompletedTask;\n\n                lifecycle.Subscribe(\n                    nameof(MembershipAgent),\n                    ServiceLifecycleStage.AfterRuntimeGrainServices,\n                    AfterRuntimeGrainServicesStart,\n                    AfterRuntimeGrainServicesStop);\n            }\n\n            {\n                var tasks = new List<Task>();\n\n                async Task OnBecomeActiveStart(CancellationToken ct)\n                {\n                    await Task.Run(() => this.BecomeActive());\n                    tasks.Add(Task.Run(() => this.UpdateIAmAlive()));\n                }\n\n                async Task OnBecomeActiveStop(CancellationToken ct)\n                {\n                    this.iAmAliveTimer.Dispose();\n                    this.cancellation.Cancel(throwOnFirstException: false);\n                    var cancellationTask = ct.WhenCancelled();\n\n                    if (ct.IsCancellationRequested)\n                    {\n                        await Task.Run(() => this.BecomeStopping());\n                    }\n                    else\n                    {\n                        // Allow some minimum time for graceful shutdown.\n                        var gracePeriod = Task.WhenAll(Task.Delay(ClusterMembershipOptions.ClusteringShutdownGracePeriod), cancellationTask);\n                        var task = await Task.WhenAny(gracePeriod, this.BecomeShuttingDown());\n                        if (ReferenceEquals(task, gracePeriod))\n                        {\n                            this.log.LogWarning(\"Graceful shutdown aborted: starting ungraceful shutdown\");\n                            await Task.Run(() => this.BecomeStopping());\n                        }\n                        else\n                        {\n                            await Task.WhenAny(gracePeriod, Task.WhenAll(tasks));\n                        }\n                    }\n                }\n\n                lifecycle.Subscribe(\n                    nameof(MembershipAgent),\n                    ServiceLifecycleStage.BecomeActive,\n                    OnBecomeActiveStart,\n                    OnBecomeActiveStop);\n            }\n        }\n\n        public void Dispose()\n        {\n            this.iAmAliveTimer.Dispose();\n        }\n\n        bool IHealthCheckable.CheckHealth(DateTime lastCheckTime, out string reason) => this.iAmAliveTimer.CheckHealth(lastCheckTime, out reason);\n\n        private readonly struct EnumerableToStringLogValue<T>(IEnumerable<T> enumerable)\n        {\n            public override string ToString() => Utils.EnumerableToString(enumerable);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting periodic membership liveness timestamp updates\"\n        )]\n        private partial void LogDebugStartingPeriodicMembershipLivenessTimestampUpdates();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Updating IAmAlive took {Elapsed}\"\n        )]\n        private partial void LogTraceUpdatingIAmAliveTook(TimeSpan elapsed);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipUpdateIAmAliveFailure,\n            Level = LogLevel.Warning,\n            Message = \"Failed to update table entry for this silo, will retry shortly\"\n        )]\n        private partial void LogWarningFailedToUpdateTableEntryForThisSilo(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopping periodic membership liveness timestamp updates\"\n        )]\n        private partial void LogDebugStoppingPeriodicMembershipLivenessTimestampUpdates();\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error updating liveness timestamp\"\n        )]\n        private partial void LogErrorErrorUpdatingLivenessTimestamp(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipBecomeActive,\n            Level = LogLevel.Information,\n            Message = \"-BecomeActive\"\n        )]\n        private partial void LogInformationBecomeActive();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFinishBecomeActive,\n            Level = LogLevel.Information,\n            Message = \"-Finished BecomeActive.\"\n        )]\n        private partial void LogInformationFinishedBecomeActive();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToBecomeActive,\n            Level = LogLevel.Information,\n            Message = \"BecomeActive failed\"\n        )]\n        private partial void LogInformationBecomeActiveFailed(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipJoiningPreconditionFailure,\n            Level = LogLevel.Error,\n            Message = \"Failed to get ping responses from {FailedCount} of {ActiveCount} active silos. \" +\n                      \"Newly joining silos validate connectivity with all active silos that have recently updated their 'I Am Alive' value before joining the cluster. \" +\n                      \"Successfully contacted: {SuccessfulSilos}. Silos which did not respond successfully are: {FailedSilos}. \" +\n                      \"Will continue attempting to validate connectivity until {Timeout}. Attempt #{Attempt}\"\n        )]\n        private partial void LogErrorFailedToGetPingResponses(int failedCount, int activeCount, EnumerableToStringLogValue<SiloAddress> successfulSilos, EnumerableToStringLogValue<SiloAddress> failedSilos, DateTime timeout, int attempt);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to validate initial cluster connectivity\"\n        )]\n        private partial void LogErrorFailedToValidateInitialClusterConnectivity(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipSendingPreJoinPing,\n            Level = LogLevel.Information,\n            Message = \"About to send pings to {Count} nodes in order to validate communication in the Joining state. Pinged nodes = {Nodes}\"\n        )]\n        private partial void LogInformationAboutToSendPings(int count, EnumerableToStringLogValue<SiloAddress> nodes);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Did not receive a probe response from silo {SiloAddress} in timeout {Timeout}\"\n        )]\n        private static partial void LogWarningDidNotReceiveProbeResponse(ILogger logger, Exception exception, SiloAddress siloAddress, TimeSpan timeout);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipJoining,\n            Level = LogLevel.Information,\n            Message = \"Joining\"\n        )]\n        private partial void LogInformationJoining();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToJoin,\n            Level = LogLevel.Error,\n            Message = \"Error updating status to Joining\"\n        )]\n        private partial void LogErrorErrorUpdatingStatusToJoining(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipShutDown,\n            Level = LogLevel.Debug,\n            Message = \"-Shutdown\"\n        )]\n        private partial void LogDebugShutdown();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToShutdown,\n            Level = LogLevel.Error,\n            Message = \"Error updating status to ShuttingDown\"\n        )]\n        private partial void LogErrorErrorUpdatingStatusToShuttingDown(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipStop,\n            Level = LogLevel.Debug,\n            Message = \"-Stop\"\n        )]\n        private partial void LogDebugStop();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToStop,\n            Level = LogLevel.Error,\n            Message = \"Error updating status to Stopping\"\n        )]\n        private partial void LogErrorErrorUpdatingStatusToStopping(Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipKillMyself,\n            Level = LogLevel.Debug,\n            Message = \"Updating status to Dead\"\n        )]\n        private partial void LogDebugUpdatingStatusToDead();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToKillMyself,\n            Level = LogLevel.Error,\n            Message = \"Failure updating status to Dead\"\n        )]\n        private partial void LogErrorFailureUpdatingStatusToDead(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipGossiper.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.MembershipService;\n\ninternal partial class MembershipGossiper(IServiceProvider serviceProvider, ILogger<MembershipGossiper> logger) : IMembershipGossiper\n{\n    private MembershipSystemTarget? _membershipSystemTarget;\n\n    public Task GossipToRemoteSilos(\n        List<SiloAddress> gossipPartners,\n        MembershipTableSnapshot snapshot,\n        SiloAddress updatedSilo,\n        SiloStatus updatedStatus)\n    {\n        if (gossipPartners.Count == 0) return Task.CompletedTask;\n\n        LogDebugGossipingStatusToPartners(logger, updatedSilo, updatedStatus, gossipPartners.Count);\n\n        var systemTarget = _membershipSystemTarget ??= serviceProvider.GetRequiredService<MembershipSystemTarget>();\n        return systemTarget.GossipToRemoteSilos(gossipPartners, snapshot, updatedSilo, updatedStatus);\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Gossiping {Silo} status {Status} to {NumPartners} partners\"\n    )]\n    private static partial void LogDebugGossipingStatusToPartners(ILogger logger, SiloAddress silo, SiloStatus status, int numPartners);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipSystemTarget.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Scheduler;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal sealed partial class MembershipSystemTarget : SystemTarget, IMembershipService, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly MembershipTableManager membershipTableManager;\n        private readonly ILogger<MembershipSystemTarget> log;\n        private readonly IInternalGrainFactory grainFactory;\n\n        public MembershipSystemTarget(\n            MembershipTableManager membershipTableManager,\n            ILogger<MembershipSystemTarget> log,\n            IInternalGrainFactory grainFactory,\n            SystemTargetShared shared)\n            : base(Constants.MembershipServiceType, shared)\n        {\n            this.membershipTableManager = membershipTableManager;\n            this.log = log;\n            this.grainFactory = grainFactory;\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public Task Ping(int pingNumber) => Task.CompletedTask;\n\n        public async Task MembershipChangeNotification(MembershipTableSnapshot snapshot)\n        {\n            if (snapshot.Version != MembershipVersion.MinValue)\n            {\n                await this.membershipTableManager.RefreshFromSnapshot(snapshot);\n            }\n            else\n            {\n                LogTraceReceivedGossipMembershipChangeNotificationWithMinValue(this.log);\n                await ReadTable();\n            }\n        }\n\n        /// <summary>\n        /// Send a ping to a remote silo. This is intended to be called from a <see cref=\"SiloHealthMonitor\"/>\n        /// in order to initiate the call from the <see cref=\"MembershipSystemTarget\"/>'s context\n        /// </summary>\n        /// <param name=\"remoteSilo\">The remote silo to ping.</param>\n        /// <param name=\"probeNumber\">The probe number, for diagnostic purposes.</param>\n        /// <returns>The result of pinging the remote silo.</returns>\n        public Task ProbeRemoteSilo(SiloAddress remoteSilo, int probeNumber) => this.RunOrQueueTask(() => ProbeInternal(remoteSilo, probeNumber));\n\n        /// <summary>\n        /// Send a ping to a remote silo via an intermediary silo. This is intended to be called from a <see cref=\"SiloHealthMonitor\"/>\n        /// in order to initiate the call from the <see cref=\"MembershipSystemTarget\"/>'s context\n        /// </summary>\n        /// <param name=\"intermediary\">The intermediary which will directly probe the target.</param>\n        /// <param name=\"target\">The target which will be probed.</param>\n        /// <param name=\"probeTimeout\">The timeout for the eventual direct probe request.</param>\n        /// <param name=\"probeNumber\">The probe number, for diagnostic purposes.</param>\n        /// <returns>The result of pinging the remote silo.</returns>\n        public Task<IndirectProbeResponse> ProbeRemoteSiloIndirectly(SiloAddress intermediary, SiloAddress target, TimeSpan probeTimeout, int probeNumber)\n        {\n            Task<IndirectProbeResponse> ProbeIndirectly()\n            {\n                var remoteOracle = this.grainFactory.GetSystemTarget<IMembershipService>(Constants.MembershipServiceType, intermediary);\n                return remoteOracle.ProbeIndirectly(target, probeTimeout, probeNumber);\n            }\n\n            var workItem = new AsyncClosureWorkItem<IndirectProbeResponse>(ProbeIndirectly, this);\n            WorkItemGroup.QueueWorkItem(workItem);\n            return workItem.Task;\n        }\n\n        public async Task<IndirectProbeResponse> ProbeIndirectly(SiloAddress target, TimeSpan probeTimeout, int probeNumber)\n        {\n            IndirectProbeResponse result;\n            var healthScore = this.ActivationServices.GetRequiredService<LocalSiloHealthMonitor>().GetLocalHealthDegradationScore(DateTime.UtcNow);\n            var probeResponseTimer = ValueStopwatch.StartNew();\n            try\n            {\n                var probeTask = this.ProbeInternal(target, probeNumber);\n                try\n                {\n                    await probeTask.WaitAsync(probeTimeout);\n                }\n                catch (TimeoutException exception)\n                {\n                    LogWarningRequestedProbeTimeoutExceeded(this.log, exception, probeTimeout);\n                    throw;\n                }\n\n                result = new IndirectProbeResponse\n                {\n                    Succeeded = true,\n                    IntermediaryHealthScore = healthScore,\n                    ProbeResponseTime = probeResponseTimer.Elapsed,\n                };\n            }\n            catch (Exception exception)\n            {\n                result = new IndirectProbeResponse\n                {\n                    Succeeded = false,\n                    IntermediaryHealthScore = healthScore,\n                    FailureMessage = $\"Encountered exception {LogFormatter.PrintException(exception)}\",\n                    ProbeResponseTime = probeResponseTimer.Elapsed,\n                };\n            }\n\n            return result;\n        }\n\n        public Task GossipToRemoteSilos(\n            List<SiloAddress> gossipPartners,\n            MembershipTableSnapshot snapshot,\n            SiloAddress updatedSilo,\n            SiloStatus updatedStatus)\n        {\n            async Task Gossip()\n            {\n                var tasks = new List<Task>(gossipPartners.Count);\n                foreach (var silo in gossipPartners)\n                {\n                    tasks.Add(this.GossipToRemoteSilo(silo, snapshot, updatedSilo, updatedStatus));\n                }\n\n                await Task.WhenAll(tasks);\n            }\n\n            return this.RunOrQueueTask(Gossip);\n        }\n\n        private async Task GossipToRemoteSilo(\n            SiloAddress silo,\n            MembershipTableSnapshot snapshot,\n            SiloAddress updatedSilo,\n            SiloStatus updatedStatus)\n        {\n            LogTraceSendingStatusUpdateGossipNotification(this.log, updatedSilo, updatedStatus, silo);\n\n            try\n            {\n                var remoteOracle = this.grainFactory.GetSystemTarget<IMembershipService>(Constants.MembershipServiceType, silo);\n                await remoteOracle.MembershipChangeNotification(snapshot);\n            }\n            catch (Exception exception)\n            {\n                LogWarningErrorSendingGossipNotificationToRemoteSilo(this.log, exception, silo);\n            }\n        }\n\n        private async Task ReadTable()\n        {\n            try\n            {\n                await this.membershipTableManager.Refresh();\n            }\n            catch (Exception exception)\n            {\n                LogErrorErrorRefreshingMembershipTable(this.log, exception);\n            }\n        }\n\n        private Task ProbeInternal(SiloAddress remoteSilo, int probeNumber)\n        {\n            Task task;\n            try\n            {\n                RequestContext.Set(RequestContext.PING_APPLICATION_HEADER, true);\n                var remoteOracle = this.grainFactory.GetSystemTarget<IMembershipService>(Constants.MembershipServiceType, remoteSilo);\n                task = remoteOracle.Ping(probeNumber);\n\n                // Update stats counter. Only count Pings that were successfully sent, but not necessarily replied to.\n                MessagingInstruments.OnPingSend(remoteSilo);\n            }\n            finally\n            {\n                RequestContext.Remove(RequestContext.PING_APPLICATION_HEADER);\n            }\n\n            return task;\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle observer)\n        {\n            // No-op, just ensure this instance is created at start-up.\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"-Received GOSSIP MembershipChangeNotification with MembershipVersion.MinValue. Going to read the table\"\n        )]\n        private static partial void LogTraceReceivedGossipMembershipChangeNotificationWithMinValue(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Requested probe timeout {ProbeTimeout} exceeded\"\n        )]\n        private static partial void LogWarningRequestedProbeTimeoutExceeded(ILogger logger, Exception exception, TimeSpan probeTimeout);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"-Sending status update GOSSIP notification about silo {UpdatedSilo}, status {UpdatedStatus}, to silo {RemoteSilo}\"\n        )]\n        private static partial void LogTraceSendingStatusUpdateGossipNotification(ILogger logger, SiloAddress updatedSilo, SiloStatus updatedStatus, SiloAddress remoteSilo);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipGossipSendFailure,\n            Level = LogLevel.Warning,\n            Message = \"Error sending gossip notification to remote silo '{Silo}'.\"\n        )]\n        private static partial void LogWarningErrorSendingGossipNotificationToRemoteSilo(ILogger logger, Exception exception, SiloAddress silo);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipGossipProcessingFailure,\n            Level = LogLevel.Error,\n            Message = \"Error refreshing membership table.\"\n        )]\n        private static partial void LogErrorErrorRefreshingMembershipTable(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipTableCleanupAgent.cs",
    "content": "#nullable enable\nusing System;\nusing Orleans.Configuration;\nusing System.Threading.Tasks;\nusing System.Threading;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Responsible for cleaning up dead membership table entries.\n    /// </summary>\n    internal partial class MembershipTableCleanupAgent : IHealthCheckParticipant, ILifecycleParticipant<ISiloLifecycle>, IDisposable\n    {\n        private readonly ClusterMembershipOptions _clusterMembershipOptions;\n        private readonly IMembershipTable _membershipTableProvider;\n        private readonly ILogger<MembershipTableCleanupAgent> _logger;\n        private readonly IAsyncTimer? _cleanupDefunctSilosTimer;\n\n        public MembershipTableCleanupAgent(\n            IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n            IMembershipTable membershipTableProvider,\n            ILogger<MembershipTableCleanupAgent> log,\n            IAsyncTimerFactory timerFactory)\n        {\n            _clusterMembershipOptions = clusterMembershipOptions.Value;\n            _membershipTableProvider = membershipTableProvider;\n            _logger = log;\n            if (_clusterMembershipOptions.DefunctSiloCleanupPeriod.HasValue)\n            {\n                _cleanupDefunctSilosTimer = timerFactory.Create(\n                    _clusterMembershipOptions.DefunctSiloCleanupPeriod.Value,\n                    nameof(CleanupDefunctSilos));\n            }\n        }\n\n        public void Dispose()\n        {\n            _cleanupDefunctSilosTimer?.Dispose();\n        }\n\n        private async Task CleanupDefunctSilos()\n        {\n            if (!_clusterMembershipOptions.DefunctSiloCleanupPeriod.HasValue)\n            {\n                LogDebugMembershipTableCleanupDisabled(_logger);\n                return;\n            }\n\n            Debug.Assert(_cleanupDefunctSilosTimer is not null);\n            LogDebugStartingMembershipTableCleanupAgent(_logger);\n            try\n            {\n                var period = _clusterMembershipOptions.DefunctSiloCleanupPeriod.Value;\n\n                // The first cleanup should be scheduled for shortly after silo startup.\n                var delay = RandomTimeSpan.Next(TimeSpan.FromMinutes(2), TimeSpan.FromMinutes(10));\n                while (await _cleanupDefunctSilosTimer.NextTick(delay))\n                {\n                    // Select a random time within the next window.\n                    // The purpose of this is to add jitter to a process which could be affected by contention with other silos.\n                    delay = RandomTimeSpan.Next(period, period + TimeSpan.FromMinutes(5));\n                    try\n                    {\n                        var dateLimit = DateTime.UtcNow - _clusterMembershipOptions.DefunctSiloExpiration;\n                        await _membershipTableProvider.CleanupDefunctSiloEntries(dateLimit);\n                    }\n                    catch (Exception exception) when (exception is NotImplementedException or MissingMethodException)\n                    {\n                        _cleanupDefunctSilosTimer.Dispose();\n                        LogWarningCleanupDefunctSiloEntriesNotSupported(_logger);\n                        return;\n                    }\n                    catch (Exception exception)\n                    {\n                        LogErrorFailedToCleanUpDefunctMembershipTableEntries(_logger, exception);\n                    }\n                }\n            }\n            finally\n            {\n                LogDebugStoppedMembershipTableCleanupAgent(_logger);\n            }\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            Task? task = null;\n            lifecycle.Subscribe(nameof(MembershipTableCleanupAgent), ServiceLifecycleStage.Active, OnStart, OnStop);\n\n            Task OnStart(CancellationToken ct)\n            {\n                task = Task.Run(CleanupDefunctSilos);\n                return Task.CompletedTask;\n            }\n\n            async Task OnStop(CancellationToken ct)\n            {\n                _cleanupDefunctSilosTimer?.Dispose();\n                if (task is { })\n                {\n                    await task.WaitAsync(ct).SuppressThrowing();\n                }\n            }\n        }\n\n        bool IHealthCheckable.CheckHealth(DateTime lastCheckTime, [NotNullWhen(false)] out string? reason)\n        {\n            if (_cleanupDefunctSilosTimer is IAsyncTimer timer)\n            {\n                return timer.CheckHealth(lastCheckTime, out reason);\n            }\n\n            reason = default;\n            return true;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Membership table cleanup is disabled due to ClusterMembershipOptions.DefunctSiloCleanupPeriod not being specified\"\n        )]\n        private static partial void LogDebugMembershipTableCleanupDisabled(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting membership table cleanup agent\"\n        )]\n        private static partial void LogDebugStartingMembershipTableCleanupAgent(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"IMembershipTable.CleanupDefunctSiloEntries operation is not supported by the current implementation of IMembershipTable. Disabling the timer now.\"\n        )]\n        private static partial void LogWarningCleanupDefunctSiloEntriesNotSupported(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to clean up defunct membership table entries\"\n        )]\n        private static partial void LogErrorFailedToCleanUpDefunctMembershipTableEntries(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopped membership table cleanup agent\"\n        )]\n        private static partial void LogDebugStoppedMembershipTableCleanupAgent(ILogger logger);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipTableEntryExtensions.cs",
    "content": "using System;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.MembershipService;\n\ninternal static class MembershipTableEntryExtensions\n{\n    public static bool HasMissedIAmAlives(this MembershipEntry entry, ClusterMembershipOptions options, DateTime time)\n        => time - entry.EffectiveIAmAliveTime > options.AllowedIAmAliveMissPeriod;\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipTableManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Utilities;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal partial class MembershipTableManager : IHealthCheckParticipant, ILifecycleParticipant<ISiloLifecycle>, IDisposable\n    {\n        private const int NUM_CONDITIONAL_WRITE_CONTENTION_ATTEMPTS = -1; // unlimited\n        private const int NUM_CONDITIONAL_WRITE_ERROR_ATTEMPTS = -1;\n        private static readonly TimeSpan EXP_BACKOFF_ERROR_MIN = TimeSpan.FromMilliseconds(1000);\n        private static readonly TimeSpan EXP_BACKOFF_CONTENTION_MIN = TimeSpan.FromMilliseconds(100);\n        private static readonly TimeSpan EXP_BACKOFF_ERROR_MAX = TimeSpan.FromMinutes(1);\n        private static readonly TimeSpan EXP_BACKOFF_CONTENTION_MAX = TimeSpan.FromMinutes(1);\n        private static readonly TimeSpan EXP_BACKOFF_STEP = TimeSpan.FromMilliseconds(1000);\n        private static readonly TimeSpan GossipTimeout = TimeSpan.FromMilliseconds(3000);\n        private static readonly string RoleName = CachedTypeResolver.GetName(Assembly.GetEntryAssembly() ?? typeof(MembershipTableManager).Assembly);\n\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly IMembershipGossiper gossiper;\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly IMembershipTable membershipTableProvider;\n        private readonly ILogger log;\n        private readonly ISiloLifecycle siloLifecycle;\n        private readonly ClusterMembershipOptions clusterMembershipOptions;\n        private readonly DateTime siloStartTime = DateTime.UtcNow;\n        private readonly SiloAddress myAddress;\n        private readonly AsyncEnumerable<MembershipTableSnapshot> updates;\n        private readonly IAsyncTimer membershipUpdateTimer;\n        private readonly CancellationTokenSource _shutdownCts = new();\n\n        private readonly Task _suspectOrKillsListTask;\n        private readonly Channel<SuspectOrKillRequest> _trySuspectOrKillChannel = Channel.CreateBounded<SuspectOrKillRequest>(new BoundedChannelOptions(100) { FullMode = BoundedChannelFullMode.DropOldest });\n\n        // For testing.\n        internal AutoResetEvent TestingSuspectOrKillIdle = new(false);\n\n        private MembershipTableSnapshot snapshot;\n\n        public MembershipTableManager(\n            ILocalSiloDetails localSiloDetails,\n            IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n            IMembershipTable membershipTable,\n            IFatalErrorHandler fatalErrorHandler,\n            IMembershipGossiper gossiper,\n            ILogger<MembershipTableManager> log,\n            IAsyncTimerFactory timerFactory,\n            ISiloLifecycle siloLifecycle)\n        {\n            this.localSiloDetails = localSiloDetails;\n            this.membershipTableProvider = membershipTable;\n            this.fatalErrorHandler = fatalErrorHandler;\n            this.gossiper = gossiper;\n            this.clusterMembershipOptions = clusterMembershipOptions.Value;\n            this.myAddress = this.localSiloDetails.SiloAddress;\n            this.log = log;\n            this.siloLifecycle = siloLifecycle;\n            var initialEntries = ImmutableDictionary<SiloAddress, MembershipEntry>.Empty.SetItem(this.myAddress, this.CreateLocalSiloEntry(this.CurrentStatus));\n            this.snapshot = new MembershipTableSnapshot(\n                    MembershipVersion.MinValue,\n                    initialEntries);\n            this.updates = new AsyncEnumerable<MembershipTableSnapshot>(\n                initialValue: this.snapshot,\n                updateValidator: (previous, proposed) => proposed.IsSuccessorTo(previous),\n                onPublished: update => Interlocked.Exchange(ref this.snapshot, update));\n\n            this.membershipUpdateTimer = timerFactory.Create(\n                this.clusterMembershipOptions.TableRefreshTimeout,\n                nameof(PeriodicallyRefreshMembershipTable));\n\n            _suspectOrKillsListTask = Task.Run(ProcessSuspectOrKillLists);\n        }\n\n        internal Func<DateTime> GetDateTimeUtcNow { get; set; } = () => DateTime.UtcNow;\n\n        public MembershipTableSnapshot MembershipTableSnapshot => this.snapshot;\n\n        public IAsyncEnumerable<MembershipTableSnapshot> MembershipTableUpdates => this.updates;\n\n        public SiloStatus CurrentStatus { get; private set; } = SiloStatus.Created;\n\n        private bool IsStopping => this.siloLifecycle.LowestStoppedStage <= ServiceLifecycleStage.Active;\n\n        private Task pendingRefresh;\n\n        public async Task Refresh()\n        {\n            var pending = this.pendingRefresh;\n            if (pending == null || pending.IsCompleted)\n            {\n                pending = this.pendingRefresh = this.RefreshInternal(requireCleanup: false);\n            }\n\n            await pending;\n        }\n\n        public async Task RefreshFromSnapshot(MembershipTableSnapshot snapshot)\n        {\n            if (snapshot.Version == MembershipVersion.MinValue)\n                throw new ArgumentException(\"Cannot call RefreshFromSnapshot with Version == MembershipVersion.MinValue\");\n\n            // Check if a refresh is underway\n            var pending = this.pendingRefresh;\n            if (pending != null && !pending.IsCompleted)\n            {\n                await pending;\n            }\n\n            LogInformationReceivedClusterMembershipSnapshot(this.log, snapshot);\n\n            if (snapshot.Entries.TryGetValue(this.myAddress, out var localSiloEntry))\n            {\n                if (localSiloEntry.Status == SiloStatus.Dead && this.CurrentStatus != SiloStatus.Dead)\n                {\n                    LogWarningFoundMyselfDeadInRefreshFromSnapshot(this.log, localSiloEntry.ToFullString());\n                    this.KillMyselfLocally($\"I should be Dead according to membership table (in RefreshFromSnapshot). Local entry: {(localSiloEntry.ToFullString())}.\");\n                }\n            }\n\n            this.updates.TryPublish(MembershipTableSnapshot.Update, snapshot);\n        }\n\n        private async Task<bool> RefreshInternal(bool requireCleanup)\n        {\n            var table = await this.membershipTableProvider.ReadAll();\n            this.ProcessTableUpdate(table, \"Refresh\");\n\n            bool success;\n            try\n            {\n                success = await this.CleanupMyTableEntries(table);\n            }\n            catch (Exception exception) when (!requireCleanup)\n            {\n                success = false;\n                LogWarningExceptionWhileCleaningUpTableEntries(this.log, exception);\n            }\n\n            // If cleanup was not required then the cleanup result is ignored.\n            return !requireCleanup || success;\n        }\n\n        private async Task Start()\n        {\n            try\n            {\n                LogInformationMembershipStarting(this.log, this.localSiloDetails.DnsHostName, this.myAddress, LogFormatter.PrintDate(this.siloStartTime));\n\n                // Init the membership table.\n                await this.membershipTableProvider.InitializeMembershipTable(true);\n\n                // Perform an initial table read\n                var refreshed = await AsyncExecutorWithRetries.ExecuteWithRetries(\n                    function: _ => this.RefreshInternal(requireCleanup: true),\n                    maxNumSuccessTries: NUM_CONDITIONAL_WRITE_CONTENTION_ATTEMPTS,\n                    maxNumErrorTries: NUM_CONDITIONAL_WRITE_ERROR_ATTEMPTS,\n                    retryValueFilter: (value, i) => !value,\n                    retryExceptionFilter: (exc, i) => true,\n                    maxExecutionTime: this.clusterMembershipOptions.MaxJoinAttemptTime,\n                    onSuccessBackOff: new ExponentialBackoff(EXP_BACKOFF_CONTENTION_MIN, EXP_BACKOFF_CONTENTION_MAX, EXP_BACKOFF_STEP),\n                    onErrorBackOff: new ExponentialBackoff(EXP_BACKOFF_ERROR_MIN, EXP_BACKOFF_ERROR_MAX, EXP_BACKOFF_STEP));\n\n                if (!refreshed)\n                {\n                    throw new OrleansException(\"Failed to perform initial membership refresh and cleanup.\");\n                }\n\n                // read the table and look for my node migration occurrences\n                DetectNodeMigration(this.snapshot, this.localSiloDetails.DnsHostName);\n            }\n            catch (Exception exception)\n            {\n                LogErrorMembershipFailedToStart(this.log, exception);\n                throw;\n            }\n        }\n\n        public async Task UpdateIAmAlive()\n        {\n            var entry = new MembershipEntry\n            {\n                SiloAddress = myAddress,\n                IAmAliveTime = GetDateTimeUtcNow()\n            };\n\n            await this.membershipTableProvider.UpdateIAmAlive(entry);\n        }\n\n        private void DetectNodeMigration(MembershipTableSnapshot snapshot, string myHostname)\n        {\n            string mySiloName = this.localSiloDetails.Name;\n            MembershipEntry mostRecentPreviousEntry = null;\n            // look for silo instances that are same as me, find most recent with Generation before me.\n            foreach (var entry in snapshot.Entries.Select(entry => entry.Value).Where(data => mySiloName.Equals(data.SiloName)))\n            {\n                bool iAmLater = myAddress.Generation.CompareTo(entry.SiloAddress.Generation) > 0;\n                // more recent\n                if (iAmLater && (mostRecentPreviousEntry == null || entry.SiloAddress.Generation.CompareTo(mostRecentPreviousEntry.SiloAddress.Generation) > 0))\n                    mostRecentPreviousEntry = entry;\n            }\n\n            if (mostRecentPreviousEntry != null)\n            {\n                bool physicalHostChanged = !myHostname.Equals(mostRecentPreviousEntry.HostName) || !myAddress.Endpoint.Equals(mostRecentPreviousEntry.SiloAddress.Endpoint);\n                if (physicalHostChanged)\n                {\n                    LogWarningNodeMigrated(this.log, mySiloName, myHostname, myAddress, mostRecentPreviousEntry.HostName, mostRecentPreviousEntry.SiloAddress);\n                }\n                else\n                {\n                    LogWarningNodeRestarted(this.log, mySiloName, myHostname, myAddress, mostRecentPreviousEntry.SiloAddress);\n                }\n            }\n        }\n\n        private async Task PeriodicallyRefreshMembershipTable()\n        {\n            LogDebugStartingPeriodicMembershipTableRefreshes(this.log);\n            try\n            {\n                // jitter for initial\n                TimeSpan? overrideDelayPeriod = RandomTimeSpan.Next(this.clusterMembershipOptions.TableRefreshTimeout);\n                var exponentialBackoff = new ExponentialBackoff(EXP_BACKOFF_CONTENTION_MIN, EXP_BACKOFF_CONTENTION_MAX, EXP_BACKOFF_STEP);\n                var runningFailures = 0;\n                while (await this.membershipUpdateTimer.NextTick(overrideDelayPeriod))\n                {\n                    try\n                    {\n                        var stopwatch = ValueStopwatch.StartNew();\n\n                        await this.Refresh();\n                        LogTraceRefreshingMembershipTableTook(this.log, stopwatch.Elapsed);\n                        // reset to allow normal refresh period after success\n                        overrideDelayPeriod = default;\n                        runningFailures = 0;\n                    }\n                    catch (Exception exception)\n                    {\n                        runningFailures += 1;\n                        LogWarningFailedToRefreshMembershipTable(this.log, exception, runningFailures);\n\n                        // Retry quickly and then exponentially back off\n                        overrideDelayPeriod = exponentialBackoff.Next(runningFailures);\n                    }\n                }\n            }\n            catch (Exception exception) when (this.fatalErrorHandler.IsUnexpected(exception))\n            {\n                LogWarningErrorRefreshingMembershipTable(this.log, exception);\n                this.fatalErrorHandler.OnFatalException(this, nameof(PeriodicallyRefreshMembershipTable), exception);\n            }\n            finally\n            {\n                LogDebugStoppingPeriodicMembershipTableRefreshes(this.log);\n            }\n        }\n\n        private static Task<bool> MembershipExecuteWithRetries(\n            Func<int, Task<bool>> taskFunction,\n            TimeSpan timeout)\n        {\n            return MembershipExecuteWithRetries(taskFunction, timeout, (result, i) => result == false);\n        }\n\n        private static Task<T> MembershipExecuteWithRetries<T>(\n            Func<int, Task<T>> taskFunction,\n            TimeSpan timeout,\n            Func<T, int, bool> retryValueFilter)\n        {\n            return AsyncExecutorWithRetries.ExecuteWithRetries(\n                    taskFunction,\n                    NUM_CONDITIONAL_WRITE_CONTENTION_ATTEMPTS,\n                    NUM_CONDITIONAL_WRITE_ERROR_ATTEMPTS,\n                    retryValueFilter,   // if failed to Update on contention - retry\n                    (exc, i) => true,            // Retry on errors.\n                    timeout,\n                    new ExponentialBackoff(EXP_BACKOFF_CONTENTION_MIN, EXP_BACKOFF_CONTENTION_MAX, EXP_BACKOFF_STEP), // how long to wait between successful retries\n                    new ExponentialBackoff(EXP_BACKOFF_ERROR_MIN, EXP_BACKOFF_ERROR_MAX, EXP_BACKOFF_STEP)  // how long to wait between error retries\n            );\n        }\n\n        public async Task UpdateStatus(SiloStatus status)\n        {\n            bool wasThrownLocally = false;\n            int numCalls = 0;\n\n            try\n            {\n                async Task<bool> UpdateMyStatusTask(int counter)\n                {\n                    numCalls++;\n                    LogDebugGoingToTryToUpdateMyStatusGlobalOnce(this.log, counter);\n                    return await TryUpdateMyStatusGlobalOnce(status);  // function to retry\n                }\n\n                if (status.IsTerminating() && this.membershipTableProvider is SystemTargetBasedMembershipTable)\n                {\n                    // SystemTarget-based membership may not be accessible at this stage, so allow for one quick attempt to update\n                    // the status before continuing regardless of the outcome.\n                    var updateTask = UpdateMyStatusTask(0);\n                    updateTask.Ignore();\n                    await Task.WhenAny(Task.Delay(TimeSpan.FromMilliseconds(500)), updateTask);\n\n                    var gossipTask = this.GossipToOthers(this.myAddress, status);\n                    gossipTask.Ignore();\n                    await Task.WhenAny(Task.Delay(TimeSpan.FromMilliseconds(500)), gossipTask);\n\n                    this.CurrentStatus = status;\n                    return;\n                }\n\n                bool ok = await MembershipExecuteWithRetries(UpdateMyStatusTask, this.clusterMembershipOptions.MaxJoinAttemptTime);\n\n                if (ok)\n                {\n                    LogDebugSuccessfullyUpdatedMyStatus(this.log, myAddress, status);\n\n                    var gossipTask = this.GossipToOthers(this.myAddress, status);\n                    gossipTask.Ignore();\n                    using var cancellation = new CancellationTokenSource();\n                    var timeoutTask = Task.Delay(GossipTimeout, cancellation.Token);\n                    var task = await Task.WhenAny(gossipTask, timeoutTask);\n                    if (ReferenceEquals(task, timeoutTask))\n                    {\n                        if (status.IsTerminating())\n                        {\n                            LogWarningTimedOutWhileGossipingStatus(this.log, GossipTimeout);\n                        }\n                        else\n                        {\n                            LogDebugTimedOutWhileGossipingStatus(this.log, GossipTimeout);\n                        }\n                    }\n                    else\n                    {\n                        cancellation.Cancel();\n                    }\n                }\n                else\n                {\n                    wasThrownLocally = true;\n                    LogInformationFailedToUpdateMyStatusDueToWriteContention(this.log, myAddress, status, numCalls);\n                    throw new OrleansException($\"Silo {myAddress} failed to update its status to {status} in the membership table due to write contention on the table after {numCalls} attempts.\");\n                }\n            }\n            catch (Exception exc)  when (!wasThrownLocally)\n            {\n                LogWarningFailedToUpdateMyStatusDueToFailures(this.log, exc, myAddress, status, numCalls);\n                throw new OrleansException($\"Silo {myAddress} failed to update its status to {status} in the table due to failures (socket failures or table read/write failures) after {numCalls} attempts\", exc);\n            }\n        }\n\n        // read the table\n        // find all currently active nodes and test pings to all of them\n        //      try to ping all\n        //      if all pings succeeded\n        //             try to change my status to Active and in the same write transaction update Membership version row, conditioned on both etags\n        //      if failed (on ping or on write exception or on etag) - retry the whole AttemptToJoinActiveNodes\n        private async Task<bool> TryUpdateMyStatusGlobalOnce(SiloStatus newStatus)\n        {\n            var table = await membershipTableProvider.ReadAll();\n\n            LogDebugTryUpdateMyStatusGlobalOnce(this.log, newStatus.Equals(SiloStatus.Active) ? \"All\" : \" my entry from\", table.ToString());\n            LogMissedIAmAlives(table);\n            var (myEntry, myEtag) = this.GetOrCreateLocalSiloEntry(table, newStatus);\n\n            if (myEntry.Status == SiloStatus.Dead && myEntry.Status != newStatus)\n            {\n                LogWarningFoundMyselfDead1(this.log, myEntry.ToFullString());\n                this.KillMyselfLocally($\"I should be Dead according to membership table (in TryUpdateMyStatusGlobalOnce): Entry = {(myEntry.ToFullString())}.\");\n                return true;\n            }\n\n            var now = GetDateTimeUtcNow();\n            if (newStatus == SiloStatus.Dead)\n                myEntry.AddSuspector(myAddress, now); // add the killer (myself) to the suspect list, for easier diagnostics later on.\n\n            myEntry.Status = newStatus;\n            myEntry.IAmAliveTime = now;\n\n            bool ok;\n            TableVersion next = table.Version.Next();\n            if (myEtag != null) // no previous etag for my entry -> its the first write to this entry, so insert instead of update.\n            {\n                ok = await membershipTableProvider.UpdateRow(myEntry, myEtag, next);\n            }\n            else\n            {\n                ok = await membershipTableProvider.InsertRow(myEntry, next);\n            }\n\n            if (ok)\n            {\n                this.CurrentStatus = newStatus;\n                var entries = table.Members.ToDictionary(e => e.Item1.SiloAddress, e => e);\n                entries[myEntry.SiloAddress] = Tuple.Create(myEntry, myEtag);\n                var updatedTable = new MembershipTableData(entries.Values.ToList(), next);\n                this.ProcessTableUpdate(updatedTable, nameof(TryUpdateMyStatusGlobalOnce));\n            }\n\n            return ok;\n        }\n\n        private (MembershipEntry Entry, string ETag) GetOrCreateLocalSiloEntry(MembershipTableData table, SiloStatus currentStatus)\n        {\n            if (table.TryGet(myAddress) is { } myTuple)\n            {\n                return (myTuple.Item1.Copy(), myTuple.Item2);\n            }\n\n            var result = CreateLocalSiloEntry(currentStatus);\n            return (result, null);\n        }\n\n        private MembershipEntry CreateLocalSiloEntry(SiloStatus currentStatus)\n        {\n            return new MembershipEntry\n            {\n                SiloAddress = this.localSiloDetails.SiloAddress,\n\n                HostName = this.localSiloDetails.DnsHostName,\n                SiloName = this.localSiloDetails.Name,\n\n                Status = currentStatus,\n                ProxyPort = this.localSiloDetails.GatewayAddress?.Endpoint?.Port ?? 0,\n\n                RoleName = RoleName,\n\n                SuspectTimes = new List<Tuple<SiloAddress, DateTime>>(),\n                StartTime = this.siloStartTime,\n                IAmAliveTime = GetDateTimeUtcNow()\n            };\n        }\n\n        private void ProcessTableUpdate(MembershipTableData table, string caller)\n        {\n            if (table is null) throw new ArgumentNullException(nameof(table));\n            LogDebugProcessTableUpdate(this.log, caller, table);\n\n            if (this.updates.TryPublish(MembershipTableSnapshot.Update, table))\n            {\n                this.LogMissedIAmAlives(table);\n\n                LogDebugProcessTableUpdateWithTable(this.log, caller, new(table));\n            }\n        }\n\n        private void LogMissedIAmAlives(MembershipTableData table)\n        {\n            foreach (var pair in table.Members)\n            {\n                var entry = pair.Item1;\n                if (entry.SiloAddress.Equals(myAddress)) continue;\n                if (entry.Status != SiloStatus.Active) continue;\n\n                var now = GetDateTimeUtcNow();\n                if (entry.HasMissedIAmAlives(this.clusterMembershipOptions, now))\n                {\n                    var missedSince = entry.EffectiveIAmAliveTime;\n                    LogWarningMissedIAmAliveTableUpdate(this.log, entry.SiloAddress, missedSince, now, now - missedSince, clusterMembershipOptions.AllowedIAmAliveMissPeriod);\n                }\n            }\n        }\n\n        private async Task<bool> CleanupMyTableEntries(MembershipTableData table)\n        {\n            if (this.IsStopping) return true;\n\n            var silosToDeclareDead = new List<Tuple<MembershipEntry, string>>();\n            foreach (var tuple in table.Members.Where(\n                tuple => tuple.Item1.SiloAddress.Endpoint.Equals(myAddress.Endpoint)))\n            {\n                var entry = tuple.Item1;\n                var siloAddress = entry.SiloAddress;\n\n                if (siloAddress.Generation.Equals(myAddress.Generation))\n                {\n                    if (entry.Status == SiloStatus.Dead)\n                    {\n                        LogWarningFoundMyselfDead2(this.log, entry.ToFullString());\n                        KillMyselfLocally($\"I should be Dead according to membership table (in CleanupTableEntries): entry = {(entry.ToFullString())}.\");\n                    }\n                    continue;\n                }\n\n                if (entry.Status == SiloStatus.Dead)\n                {\n                    LogTraceSkippingOldDeadEntry(this.log, entry.ToFullString());\n                    continue;\n                }\n\n                LogDebugTemporalAnomalyDetected(this.log, myAddress, siloAddress);\n\n                // Temporal paradox - There is an older clone of this silo in the membership table\n                if (siloAddress.Generation < myAddress.Generation)\n                {\n                    LogWarningDetectedOlder(this.log, myAddress, siloAddress, entry.ToString());\n                    // Declare older clone of me as Dead.\n                    silosToDeclareDead.Add(tuple);   //return DeclareDead(entry, eTag, tableVersion);\n                }\n                else if (siloAddress.Generation > myAddress.Generation)\n                {\n                    // I am the older clone - Newer version of me should survive - I need to kill myself\n                    LogWarningDetectedNewer(this.log, myAddress, siloAddress, entry.ToString());\n                    await this.UpdateStatus(SiloStatus.Dead);\n                    KillMyselfLocally($\"Detected newer version of myself - I am the older clone so I will stop -- Current Me={myAddress} Newer Me={siloAddress}, Current entry={entry}\");\n                    return true; // No point continuing!\n                }\n            }\n\n            if (silosToDeclareDead.Count == 0) return true;\n\n            LogDebugCleanupTableEntriesAboutToDeclareDead(this.log, silosToDeclareDead.Count, Utils.EnumerableToString(silosToDeclareDead.Select(tuple => tuple.Item1)));\n\n            foreach (var siloData in silosToDeclareDead)\n            {\n                await _trySuspectOrKillChannel.Writer.WriteAsync(\n                    SuspectOrKillRequest.CreateKillRequest(siloData.Item1.SiloAddress));\n            }\n\n            return true;\n        }\n\n        private void KillMyselfLocally(string reason)\n        {\n            LogErrorKillMyselfLocally(this.log, reason);\n            this.CurrentStatus = SiloStatus.Dead;\n            this.fatalErrorHandler.OnFatalException(this, $\"I have been told I am dead, so this silo will stop! Reason: {reason}\", null);\n        }\n\n        private async Task GossipToOthers(SiloAddress updatedSilo, SiloStatus updatedStatus)\n        {\n            if (!this.clusterMembershipOptions.UseLivenessGossip) return;\n\n            var now = GetDateTimeUtcNow();\n            var gossipPartners = new List<SiloAddress>();\n            foreach (var item in this.MembershipTableSnapshot.Entries)\n            {\n                var entry = item.Value;\n                if (entry.SiloAddress.IsSameLogicalSilo(this.myAddress)) continue;\n                if (!IsFunctionalForMembership(entry.Status)) continue;\n                if (entry.HasMissedIAmAlives(this.clusterMembershipOptions, now)) continue;\n\n                gossipPartners.Add(entry.SiloAddress);\n\n                bool IsFunctionalForMembership(SiloStatus status)\n                {\n                    return status == SiloStatus.Active || status == SiloStatus.ShuttingDown || status == SiloStatus.Stopping;\n                }\n            }\n\n            try\n            {\n                await this.gossiper.GossipToRemoteSilos(gossipPartners, MembershipTableSnapshot, updatedSilo, updatedStatus);\n            }\n            catch (Exception exception)\n            {\n                LogWarningErrorWhileGossipingStatus(this.log, exception);\n            }\n        }\n\n        private class SuspectOrKillRequest\n        {\n            public SiloAddress SiloAddress { get; set; }\n            public SiloAddress OtherSilo { get; set; }\n            public RequestType Type { get; set; }\n\n            public enum RequestType\n            {\n                Unknown = 0,\n                SuspectOrKill,\n                Kill\n            }\n\n            public static SuspectOrKillRequest CreateKillRequest(SiloAddress silo)\n            {\n                return new SuspectOrKillRequest\n                {\n                    SiloAddress = silo,\n                    OtherSilo = null,\n                    Type = RequestType.Kill\n                };\n            }\n\n            public static SuspectOrKillRequest CreateSuspectOrKillRequest(SiloAddress silo, SiloAddress otherSilo)\n            {\n                return new SuspectOrKillRequest\n                {\n                    SiloAddress = silo,\n                    OtherSilo = otherSilo,\n                    Type = RequestType.SuspectOrKill\n                };\n            }\n        }\n\n        public async Task<bool> TryKill(SiloAddress silo)\n        {\n            await _trySuspectOrKillChannel.Writer.WriteAsync(SuspectOrKillRequest.CreateKillRequest(silo));\n            return true;\n        }\n\n        public async Task ProcessSuspectOrKillLists()\n        {\n            var backoff = new ExponentialBackoff(EXP_BACKOFF_ERROR_MIN, EXP_BACKOFF_ERROR_MAX,\n                EXP_BACKOFF_STEP);\n            var runningFailureCount = 0;\n            var reader = _trySuspectOrKillChannel.Reader;\n            while (await reader.WaitToReadAsync(_shutdownCts.Token))\n            {\n                while (reader.TryRead(out var request))\n                {\n                    await Task.Delay(backoff.Next(runningFailureCount), _shutdownCts.Token);\n\n                    try\n                    {\n                        switch (request.Type)\n                        {\n                            case SuspectOrKillRequest.RequestType.Kill:\n                                await InnerTryKill(request.SiloAddress, _shutdownCts.Token);\n                                break;\n                            case SuspectOrKillRequest.RequestType.SuspectOrKill:\n                                await InnerTryToSuspectOrKill(request.SiloAddress, request.OtherSilo, _shutdownCts.Token);\n                                break;\n                        }\n                        runningFailureCount = 0;\n                    }\n                    catch (Exception ex)\n                    {\n                        runningFailureCount += 1;\n                        LogErrorProcessingSuspectOrKillLists(this.log, ex, runningFailureCount);\n                        await _trySuspectOrKillChannel.Writer.WriteAsync(request, _shutdownCts.Token);\n                    }\n\n                    if (!reader.TryPeek(out _))\n                    {\n                        TestingSuspectOrKillIdle.Set();\n                    }\n                }\n            }\n        }\n\n        private async Task<bool> InnerTryKill(SiloAddress silo, CancellationToken cancellationToken)\n        {\n            var table = await membershipTableProvider.ReadAll().WaitAsync(cancellationToken);\n\n            LogDebugTryKillReadMembershipTable(this.log, table.ToString());\n\n            if (this.IsStopping)\n            {\n                LogInformationIgnoringCallToTryKill(this.log, silo);\n                return true;\n            }\n\n            var (localSiloEntry, _) = this.GetOrCreateLocalSiloEntry(table, this.CurrentStatus);\n            if (localSiloEntry.Status == SiloStatus.Dead)\n            {\n                var msg = string.Format(\"I should be Dead according to membership table (in TryKill): entry = {0}.\", localSiloEntry.ToFullString());\n                LogWarningFoundMyselfDead3(this.log, msg);\n                KillMyselfLocally(msg);\n                return true;\n            }\n\n            if (table.TryGet(silo) is not { } tuple)\n            {\n                var str = $\"Could not find silo entry for silo {silo} in the table.\";\n                LogErrorCouldNotFindSiloEntry(this.log, str);\n                throw new KeyNotFoundException(str);\n            }\n\n            var entry = tuple.Item1.Copy();\n            string eTag = tuple.Item2;\n\n            // Check if the table already knows that this silo is dead\n            if (entry.Status == SiloStatus.Dead)\n            {\n                this.ProcessTableUpdate(table, \"TryKill\");\n                return true;\n            }\n\n            LogInformationMarkingSiloAsDead(this.log, entry.SiloAddress);\n            return await DeclareDead(entry, eTag, table.Version, GetDateTimeUtcNow()).WaitAsync(cancellationToken);\n        }\n\n        public async Task<bool> TryToSuspectOrKill(SiloAddress silo, SiloAddress indirectProbingSilo = null)\n        {\n            await _trySuspectOrKillChannel.Writer.WriteAsync(SuspectOrKillRequest.CreateSuspectOrKillRequest(silo, indirectProbingSilo));\n            return true;\n        }\n\n        private async Task<bool> InnerTryToSuspectOrKill(SiloAddress silo, SiloAddress indirectProbingSilo, CancellationToken cancellationToken)\n        {\n            var table = await membershipTableProvider.ReadAll().WaitAsync(cancellationToken);\n            var now = GetDateTimeUtcNow();\n\n            LogDebugTryToSuspectOrKillReadMembershipTable(this.log, table.ToString());\n\n            if (this.IsStopping)\n            {\n                LogInformationIgnoringCallToTrySuspectOrKill(this.log, silo);\n                return true;\n            }\n\n            var (localSiloEntry, _) = this.GetOrCreateLocalSiloEntry(table, this.CurrentStatus);\n            if (localSiloEntry.Status == SiloStatus.Dead)\n            {\n                var localSiloEntryDetails = localSiloEntry.ToFullString();\n                LogWarningFoundMyselfDead3(this.log, $\"I should be Dead according to membership table (in TryToSuspectOrKill): entry = {localSiloEntryDetails}.\");\n                KillMyselfLocally($\"I should be Dead according to membership table (in TryToSuspectOrKill): entry = {localSiloEntryDetails}.\");\n                return true;\n            }\n\n            if (table.TryGet(silo) is not { } tuple)\n            {\n                LogErrorCouldNotFindSiloEntry(this.log, $\"Could not find silo entry for silo {silo} in the table.\");\n                return false;\n            }\n\n            var entry = tuple.Item1.Copy();\n            string eTag = tuple.Item2;\n            LogDebugTryToSuspectOrKillCurrentStatus(this.log, entry.SiloAddress, entry.Status, entry.ToString());\n\n            // Check if the table already knows that this silo is dead\n            if (entry.Status == SiloStatus.Dead)\n            {\n                this.ProcessTableUpdate(table, \"TrySuspectOrKill\");\n                return true;\n            }\n\n            // Get all valid (non-expired) votes\n            var freshVotes = entry.GetFreshVotes(now, this.clusterMembershipOptions.DeathVoteExpirationTimeout);\n            LogTraceCurrentNumberOfFreshVoters(this.log, silo, freshVotes.Count.ToString());\n\n            if (freshVotes.Count >= this.clusterMembershipOptions.NumVotesForDeathDeclaration)\n            {\n                LogErrorSiloIsSuspectedButNotMarkedAsDead(this.log, entry.SiloAddress, freshVotes.Count.ToString(), this.clusterMembershipOptions.NumVotesForDeathDeclaration.ToString());\n                KillMyselfLocally(\"Found a bug! Will stop.\");\n                return false;\n            }\n\n            // Try to add our vote to the list and tally the fresh votes again.\n            var prevList = entry.SuspectTimes?.ToList() ?? new List<Tuple<SiloAddress, DateTime>>();\n            entry.AddOrUpdateSuspector(myAddress, now, clusterMembershipOptions.NumVotesForDeathDeclaration);\n\n            // Include the indirect probe silo's vote as well, if it exists.\n            if (indirectProbingSilo is not null)\n            {\n                entry.AddOrUpdateSuspector(indirectProbingSilo, now, clusterMembershipOptions.NumVotesForDeathDeclaration);\n            }\n\n            freshVotes = entry.GetFreshVotes(now, this.clusterMembershipOptions.DeathVoteExpirationTimeout);\n\n            // Determine if there are enough votes to evict the silo.\n            // Handle the corner case when the number of active silos is very small (then my only vote is enough)\n            int activeNonStaleSilos = table.Members.Count(kv =>\n                kv.Item1.Status == SiloStatus.Active &&\n                !kv.Item1.HasMissedIAmAlives(clusterMembershipOptions, now));\n            var numVotesRequiredToEvict = Math.Min(clusterMembershipOptions.NumVotesForDeathDeclaration, (activeNonStaleSilos + 1) / 2);\n            if (freshVotes.Count >= numVotesRequiredToEvict)\n            {\n                LogInformationEvictingSilo(this.log, entry.SiloAddress, freshVotes.Count, this.clusterMembershipOptions.NumVotesForDeathDeclaration, activeNonStaleSilos, PrintSuspectList(entry.SuspectTimes));\n                return await DeclareDead(entry, eTag, table.Version, now).WaitAsync(cancellationToken);\n            }\n\n            LogInformationVotingToEvictSilo(this.log, entry.SiloAddress, PrintSuspectList(prevList), PrintSuspectList(entry.SuspectTimes), eTag, PrintSuspectList(freshVotes));\n\n            // If we fail to update here we will retry later.\n            var ok = await membershipTableProvider.UpdateRow(entry, eTag, table.Version.Next()).WaitAsync(cancellationToken);\n            if (ok)\n            {\n                table = await membershipTableProvider.ReadAll().WaitAsync(cancellationToken);\n                this.ProcessTableUpdate(table, \"TrySuspectOrKill\");\n\n                // Gossip using the local silo status, since this is just informational to propagate the suspicion vote.\n                GossipToOthers(localSiloEntry.SiloAddress, localSiloEntry.Status).Ignore();\n            }\n\n            return ok;\n\n            string PrintSuspectList(IEnumerable<Tuple<SiloAddress, DateTime>> list)\n            {\n                return Utils.EnumerableToString(list, t => $\"<{t.Item1}, {LogFormatter.PrintDate(t.Item2)}>\");\n            }\n        }\n\n        private async Task<bool> DeclareDead(MembershipEntry entry, string etag, TableVersion tableVersion, DateTime time)\n        {\n            if (this.clusterMembershipOptions.LivenessEnabled)\n            {\n                entry = entry.Copy();\n\n                // Add the killer (myself) to the suspect list, for easier diagnosis later on.\n                entry.AddSuspector(myAddress, time);\n\n                LogDebugGoingToDeclareDead(this.log, entry.SiloAddress, entry.ToString());\n                entry.Status = SiloStatus.Dead;\n                bool ok = await membershipTableProvider.UpdateRow(entry, etag, tableVersion.Next());\n                if (ok)\n                {\n                    LogDebugSuccessfullyUpdatedStatusToDead(this.log, entry.SiloAddress);\n\n                    var table = await membershipTableProvider.ReadAll();\n                    this.ProcessTableUpdate(table, \"DeclareDead\");\n                    GossipToOthers(entry.SiloAddress, entry.Status).Ignore();\n                    return true;\n                }\n\n                LogInformationFailedToUpdateStatusToDead(this.log, entry.SiloAddress);\n                return false;\n            }\n\n            LogInformationLivenessDisabled(this.log, entry.SiloAddress);\n            return true;\n        }\n\n        bool IHealthCheckable.CheckHealth(DateTime lastCheckTime, out string reason) => this.membershipUpdateTimer.CheckHealth(lastCheckTime, out reason);\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            var tasks = new List<Task>(1);\n            lifecycle.Subscribe(\n                nameof(MembershipTableManager),\n                ServiceLifecycleStage.RuntimeGrainServices,\n                OnRuntimeGrainServicesStart,\n                OnRuntimeGrainServicesStop);\n\n            async Task OnRuntimeGrainServicesStart(CancellationToken ct)\n            {\n                await Task.Run(() => this.Start());\n                tasks.Add(Task.Run(() => this.PeriodicallyRefreshMembershipTable()));\n            }\n\n            async Task OnRuntimeGrainServicesStop(CancellationToken ct)\n            {\n                tasks.Add(_suspectOrKillsListTask);\n                _trySuspectOrKillChannel.Writer.TryComplete();\n                this.membershipUpdateTimer.Dispose();\n                _shutdownCts.Cancel();\n\n                // Allow some minimum time for graceful shutdown.\n                var gracePeriod = Task.WhenAll(Task.Delay(ClusterMembershipOptions.ClusteringShutdownGracePeriod), ct.WhenCancelled());\n                await Task.WhenAny(gracePeriod, Task.WhenAll(tasks)).SuppressThrowing();\n            }\n        }\n\n        public void Dispose()\n        {\n            this.updates.Dispose();\n            this.membershipUpdateTimer.Dispose();\n            _shutdownCts.Dispose();\n        }\n\n        private readonly struct WithoutDuplicateDeadsLogValue(MembershipTableData table)\n        {\n            public override string ToString() => table.WithoutDuplicateDeads().ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Received cluster membership snapshot via gossip: {Snapshot}\"\n        )]\n        private static partial void LogInformationReceivedClusterMembershipSnapshot(ILogger logger, MembershipTableSnapshot snapshot);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipStarting,\n            Level = LogLevel.Information,\n            Message = \"MembershipOracle starting on host {HostName} with SiloAddress {SiloAddress} at {StartTime}\"\n        )]\n        private static partial void LogInformationMembershipStarting(ILogger logger, string hostName, SiloAddress siloAddress, string startTime);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead1,\n            Level = LogLevel.Warning,\n            Message = \"I should be Dead according to membership table (in RefreshFromSnapshot). Local entry: {Entry}.\"\n        )]\n        private static partial void LogWarningFoundMyselfDeadInRefreshFromSnapshot(ILogger logger, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception while trying to clean up my table entries\"\n        )]\n        private static partial void LogWarningExceptionWhileCleaningUpTableEntries(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Refreshing membership table took {Elapsed}\"\n        )]\n        private static partial void LogTraceRefreshingMembershipTableTook(ILogger logger, TimeSpan elapsed);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipUpdateIAmAliveFailure,\n            Level = LogLevel.Warning,\n            Message = \"Failed to refresh membership table, will retry shortly. Retry attempt {retries}\"\n        )]\n        private static partial void LogWarningFailedToRefreshMembershipTable(ILogger logger, Exception exception, int retries);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error refreshing membership table\"\n        )]\n        private static partial void LogWarningErrorRefreshingMembershipTable(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Stopping periodic membership table refreshes\"\n        )]\n        private static partial void LogDebugStoppingPeriodicMembershipTableRefreshes(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting periodic membership table refreshes\"\n        )]\n        private static partial void LogDebugStartingPeriodicMembershipTableRefreshes(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{Caller} membership table {Table}\"\n        )]\n        private static partial void LogDebugProcessTableUpdate(ILogger logger, string caller, MembershipTableData table);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipReadAll_2,\n            Level = LogLevel.Debug,\n            Message = \"{Caller} membership table: {Table}\"\n        )]\n        private static partial void LogDebugProcessTableUpdateWithTable(ILogger logger, string caller, WithoutDuplicateDeadsLogValue table);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipMissedIAmAliveTableUpdate,\n            Level = LogLevel.Warning,\n            Message = \"Noticed that silo {SiloAddress} has not updated it's IAmAliveTime table column recently.\"\n                + \" Last update was at {LastUpdateTime}, now is {CurrentTime}, no update for {SinceUpdate}, which is more than {AllowedIAmAliveMissPeriod}.\"\n        )]\n        private static partial void LogWarningMissedIAmAliveTableUpdate(ILogger logger, SiloAddress siloAddress, DateTime lastUpdateTime, DateTime currentTime, TimeSpan sinceUpdate, TimeSpan allowedIAmAliveMissPeriod);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead2,\n            Level = LogLevel.Warning,\n            Message = \"I should be Dead according to membership table (in CleanupTableEntries): entry = {Entry}.\"\n        )]\n        private static partial void LogWarningFoundMyselfDead2(ILogger logger, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Skipping my previous old Dead entry in membership table: {Entry}\"\n        )]\n        private static partial void LogTraceSkippingOldDeadEntry(ILogger logger, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Temporal anomaly detected in membership table -- Me={SiloAddress} Other me={OtherSiloAddress}\"\n        )]\n        private static partial void LogDebugTemporalAnomalyDetected(ILogger logger, SiloAddress siloAddress, SiloAddress otherSiloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipDetectedOlder,\n            Level = LogLevel.Warning,\n            Message = \"Detected older version of myself - Marking other older clone as Dead -- Current Me={LocalSiloAddress} Older Me={OlderSiloAddress}, Old entry={Entry}\"\n        )]\n        private static partial void LogWarningDetectedOlder(ILogger logger, SiloAddress localSiloAddress, SiloAddress olderSiloAddress, string entry);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipDetectedNewer,\n            Level = LogLevel.Warning,\n            Message = \"Detected newer version of myself - I am the older clone so I will stop -- Current Me={LocalSiloAddress} Newer Me={NewerSiloAddress}, Current entry={Entry}\"\n        )]\n        private static partial void LogWarningDetectedNewer(ILogger logger, SiloAddress localSiloAddress, SiloAddress newerSiloAddress, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"CleanupTableEntries: About to DeclareDead {Count} outdated silos in the table: {Silos}\"\n        )]\n        private static partial void LogDebugCleanupTableEntriesAboutToDeclareDead(ILogger logger, int count, string silos);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipKillMyselfLocally,\n            Level = LogLevel.Error,\n            Message = \"I have been told I am dead, so this silo will stop! Reason: {Reason}\"\n        )]\n        private static partial void LogErrorKillMyselfLocally(ILogger logger, string reason);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error while gossiping status to other silos\"\n        )]\n        private static partial void LogWarningErrorWhileGossipingStatus(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Going to try to TryUpdateMyStatusGlobalOnce #{Attempt}\"\n        )]\n        private static partial void LogDebugGoingToTryToUpdateMyStatusGlobalOnce(ILogger logger, int attempt);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo {SiloAddress} Successfully updated my Status in the membership table to {Status}\"\n        )]\n        private static partial void LogDebugSuccessfullyUpdatedMyStatus(ILogger logger, SiloAddress siloAddress, SiloStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Timed out while gossiping status to other silos after {Timeout}\"\n        )]\n        private static partial void LogWarningTimedOutWhileGossipingStatus(ILogger logger, TimeSpan timeout);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Timed out while gossiping status to other silos after {Timeout}\"\n        )]\n        private static partial void LogDebugTimedOutWhileGossipingStatus(ILogger logger, TimeSpan timeout);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToWriteConditional,\n            Level = LogLevel.Information,\n            Message = \"Silo {MyAddress} failed to update its status to {Status} in the membership table due to write contention on the table after {NumCalls} attempts.\"\n        )]\n        private static partial void LogInformationFailedToUpdateMyStatusDueToWriteContention(ILogger logger, SiloAddress myAddress, SiloStatus status, int numCalls);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToWrite,\n            Level = LogLevel.Warning,\n            Message = \"Silo {MyAddress} failed to update its status to {Status} in the table due to failures (socket failures or table read/write failures) after {NumCalls} attempts\"\n        )]\n        private static partial void LogWarningFailedToUpdateMyStatusDueToFailures(ILogger logger, Exception exception, SiloAddress myAddress, SiloStatus status, int numCalls);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryUpdateMyStatusGlobalOnce: Read{Selection} Membership table {Table}\"\n        )]\n        private static partial void LogDebugTryUpdateMyStatusGlobalOnce(ILogger logger, string selection, string table);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead1,\n            Level = LogLevel.Warning,\n            Message = \"I should be Dead according to membership table (in TryUpdateMyStatusGlobalOnce): Entry = {Entry}.\"\n        )]\n        private static partial void LogWarningFoundMyselfDead1(ILogger logger, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryKill: Read Membership table {Table}\"\n        )]\n        private static partial void LogDebugTryKillReadMembershipTable(ILogger logger, string table);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead3,\n            Level = LogLevel.Information,\n            Message = \"Ignoring call to TryKill for silo {Silo} since the local silo is stopping\"\n        )]\n        private static partial void LogInformationIgnoringCallToTryKill(ILogger logger, SiloAddress silo);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead3,\n            Level = LogLevel.Warning,\n            Message = \"{Message}\"\n        )]\n        private static partial void LogWarningFoundMyselfDead3(ILogger logger, string message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToReadSilo,\n            Level = LogLevel.Error,\n            Message = \"{Message}\"\n        )]\n        private static partial void LogErrorCouldNotFindSiloEntry(ILogger logger, string message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipMarkingAsDead,\n            Level = LogLevel.Information,\n            Message = \"Going to mark silo {SiloAddress} dead as a result of a call to TryKill\"\n        )]\n        private static partial void LogInformationMarkingSiloAsDead(ILogger logger, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryToSuspectOrKill: Read Membership table {Table}\"\n        )]\n        private static partial void LogDebugTryToSuspectOrKillReadMembershipTable(ILogger logger, string table);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFoundMyselfDead3,\n            Level = LogLevel.Information,\n            Message = \"Ignoring call to TrySuspectOrKill for silo {Silo} since the local silo is dead\"\n        )]\n        private static partial void LogInformationIgnoringCallToTrySuspectOrKill(ILogger logger, SiloAddress silo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryToSuspectOrKill {SiloAddress}: The current status of {SiloAddress} in the table is {Status}, its entry is {Entry}\"\n        )]\n        private static partial void LogDebugTryToSuspectOrKillCurrentStatus(ILogger logger, SiloAddress siloAddress, SiloStatus status, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Current number of fresh voters for '{SiloAddress}' is '{FreshVotes}'.\"\n        )]\n        private static partial void LogTraceCurrentNumberOfFreshVoters(ILogger logger, SiloAddress siloAddress, string freshVotes);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100053,\n            Level = LogLevel.Error,\n            Message = \"Silo '{SiloAddress}' is suspected by '{SuspecterCount}' which is greater than or equal to '{NumVotesForDeathDeclaration}', but is not marked as dead. This is a bug!\"\n        )]\n        private static partial void LogErrorSiloIsSuspectedButNotMarkedAsDead(ILogger logger, SiloAddress siloAddress, string suspecterCount, string numVotesForDeathDeclaration);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipMarkingAsDead,\n            Level = LogLevel.Information,\n            Message = \"Evicting '{SiloAddress}'. Fresh vote count: '{FreshVotes}', votes required to evict: '{NumVotesRequiredToEvict}', non-stale silo count: '{NonStaleSiloCount}', suspecters: '{SuspectingSilos}'\"\n        )]\n        private static partial void LogInformationEvictingSilo(ILogger logger, SiloAddress siloAddress, int freshVotes, int numVotesRequiredToEvict, int nonStaleSiloCount, string suspectingSilos);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipVotingForKill,\n            Level = LogLevel.Information,\n            Message = \"Voting to evict '{SiloAddress}'. Previous suspect list is '{PreviousSuspecters}', trying to update to '{Suspecters}', ETag: '{ETag}', Fresh vote count: '{FreshVotes}'\"\n        )]\n        private static partial void LogInformationVotingToEvictSilo(ILogger logger, SiloAddress siloAddress, string previousSuspecters, string suspecters, string eTag, string freshVotes);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Going to DeclareDead silo {SiloAddress} in the table. About to write entry {Entry}.\"\n        )]\n        private static partial void LogDebugGoingToDeclareDead(ILogger logger, SiloAddress siloAddress, string entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Successfully updated {SiloAddress} status to Dead in the membership table.\"\n        )]\n        private static partial void LogDebugSuccessfullyUpdatedStatusToDead(ILogger logger, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipMarkDeadWriteFailed,\n            Level = LogLevel.Information,\n            Message = \"Failed to update {SiloAddress} status to Dead in the membership table, due to write conflicts. Will retry.\"\n        )]\n        private static partial void LogInformationFailedToUpdateStatusToDead(ILogger logger, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipCantWriteLivenessDisabled,\n            Level = LogLevel.Information,\n            Message = \"Want to mark silo {SiloAddress} as DEAD, but will ignore because Liveness is Disabled.\"\n        )]\n        private static partial void LogInformationLivenessDisabled(ILogger logger, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error while processing suspect or kill lists. '{FailureCount}' consecutive failures.\"\n        )]\n        private static partial void LogErrorProcessingSuspectOrKillLists(ILogger logger, Exception exception, int failureCount);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipNodeMigrated,\n            Level = LogLevel.Warning,\n            Message = \"Silo {SiloName} migrated to host {HostName} silo address {SiloAddress} from host {PreviousHostName} silo address {PreviousSiloAddress}.\"\n        )]\n        private static partial void LogWarningNodeMigrated(ILogger logger, string siloName, string hostName, SiloAddress siloAddress, string previousHostName, SiloAddress previousSiloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipNodeRestarted,\n            Level = LogLevel.Warning,\n            Message = \"Silo {SiloName} restarted on same host {HostName} with silo address = {SiloAddress} Previous silo address = {PreviousSiloAddress}\"\n        )]\n        private static partial void LogWarningNodeRestarted(ILogger logger, string siloName, string hostName, SiloAddress siloAddress, SiloAddress previousSiloAddress);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFailedToStart,\n            Level = LogLevel.Error,\n            Message = \"Membership failed to start\"\n        )]\n        private static partial void LogErrorMembershipFailedToStart(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/MembershipTableSnapshotExtensions.cs",
    "content": "using System.Collections.Immutable;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal static class MembershipTableSnapshotExtensions\n    {\n        internal static ClusterMembershipSnapshot CreateClusterMembershipSnapshot(this MembershipTableSnapshot membership)\n        {\n            var memberBuilder = ImmutableDictionary.CreateBuilder<SiloAddress, ClusterMember>();\n            foreach (var member in membership.Entries)\n            {\n                var entry = member.Value;\n                memberBuilder[entry.SiloAddress] = new ClusterMember(entry.SiloAddress, entry.Status, entry.SiloName);\n            }\n\n            return new ClusterMembershipSnapshot(memberBuilder.ToImmutable(), membership.Version);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/OrleansClusterConnectivityCheckFailedException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Exception used to indicate that a cluster connectivity check failed.\n    /// </summary>\n    /// <seealso cref=\"Orleans.Runtime.OrleansException\" />\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansClusterConnectivityCheckFailedException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansClusterConnectivityCheckFailedException\"/> class.\n        /// </summary>\n        public OrleansClusterConnectivityCheckFailedException() : base(\"Failed to verify connectivity with active cluster nodes.\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansClusterConnectivityCheckFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public OrleansClusterConnectivityCheckFailedException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansClusterConnectivityCheckFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public OrleansClusterConnectivityCheckFailedException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansClusterConnectivityCheckFailedException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private OrleansClusterConnectivityCheckFailedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/OrleansMissingMembershipEntryException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Exception used to indicate that a cluster membership entry which was expected to be present.\n    /// </summary>\n    /// <seealso cref=\"Orleans.Runtime.OrleansException\" />\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansMissingMembershipEntryException : OrleansException\n    {\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMissingMembershipEntryException\"/> class.\n        /// </summary>\n        public OrleansMissingMembershipEntryException() : base(\"Membership table does not contain information an entry for this silo.\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMissingMembershipEntryException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public OrleansMissingMembershipEntryException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMissingMembershipEntryException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public OrleansMissingMembershipEntryException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansMissingMembershipEntryException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private OrleansMissingMembershipEntryException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/RemoteSiloProber.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime.MembershipService;\n\n/// <inheritdoc />\ninternal class RemoteSiloProber(IServiceProvider serviceProvider) : IRemoteSiloProber\n{\n    /// <inheritdoc />\n    public async Task Probe(SiloAddress remoteSilo, int probeNumber, CancellationToken cancellationToken)\n    {\n        var systemTarget = serviceProvider.GetRequiredService<MembershipSystemTarget>();\n        await systemTarget.ProbeRemoteSilo(remoteSilo, probeNumber).WaitAsync(cancellationToken);\n    }\n\n    /// <inheritdoc />\n    public async Task<IndirectProbeResponse> ProbeIndirectly(SiloAddress intermediary, SiloAddress target, TimeSpan probeTimeout, int probeNumber, CancellationToken cancellationToken)\n    {\n        var systemTarget = serviceProvider.GetRequiredService<MembershipSystemTarget>();\n        return await systemTarget.ProbeRemoteSiloIndirectly(intermediary, target, probeTimeout, probeNumber).WaitAsync(cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloHealthMonitor.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Internal;\nusing static Orleans.Runtime.MembershipService.SiloHealthMonitor;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    /// <summary>\n    /// Responsible for monitoring an individual remote silo.\n    /// </summary>\n    internal partial class SiloHealthMonitor : ITestAccessor, IHealthCheckable, IDisposable, IAsyncDisposable\n    {\n        private readonly ILogger _log;\n        private readonly IOptionsMonitor<ClusterMembershipOptions> _clusterMembershipOptions;\n        private readonly IRemoteSiloProber _prober;\n        private readonly ILocalSiloHealthMonitor _localSiloHealthMonitor;\n        private readonly MembershipTableManager _membershipService;\n        private readonly ILocalSiloDetails _localSiloDetails;\n        private readonly CancellationTokenSource _stoppingCancellation = new();\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly IAsyncTimer _pingTimer;\n        private ValueStopwatch _elapsedSinceLastSuccessfulResponse;\n        private readonly Func<SiloHealthMonitor, ProbeResult, Task> _onProbeResult;\n        private Task? _runTask;\n\n        /// <summary>\n        /// The id of the next probe.\n        /// </summary>\n        private int _nextProbeId;\n\n        /// <summary>\n        /// The number of failed probes since the last successful probe.\n        /// </summary>\n        private int _failedProbes;\n\n        /// <summary>\n        /// The time since the last ping response was received from either the node being monitored or an intermediary.\n        /// </summary>\n        public TimeSpan? ElapsedSinceLastResponse => _elapsedSinceLastSuccessfulResponse.IsRunning ? (TimeSpan?)_elapsedSinceLastSuccessfulResponse.Elapsed : null;\n\n        /// <summary>\n        /// The duration of time measured from just prior to sending the last probe which received a response until just after receiving and processing the response.\n        /// </summary>\n        public TimeSpan LastRoundTripTime { get; private set; }\n\n        public SiloHealthMonitor(\n            SiloAddress siloAddress,\n            Func<SiloHealthMonitor, ProbeResult, Task> onProbeResult,\n            IOptionsMonitor<ClusterMembershipOptions> clusterMembershipOptions,\n            ILoggerFactory loggerFactory,\n            IRemoteSiloProber remoteSiloProber,\n            IAsyncTimerFactory asyncTimerFactory,\n            ILocalSiloHealthMonitor localSiloHealthMonitor,\n            MembershipTableManager membershipService,\n            ILocalSiloDetails localSiloDetails)\n        {\n            TargetSiloAddress = siloAddress;\n            _clusterMembershipOptions = clusterMembershipOptions;\n            _prober = remoteSiloProber;\n            _localSiloHealthMonitor = localSiloHealthMonitor;\n            _membershipService = membershipService;\n            _localSiloDetails = localSiloDetails;\n            _log = loggerFactory.CreateLogger<SiloHealthMonitor>();\n            _pingTimer = asyncTimerFactory.Create(\n                _clusterMembershipOptions.CurrentValue.ProbeTimeout,\n                nameof(SiloHealthMonitor));\n            _onProbeResult = onProbeResult;\n            _elapsedSinceLastSuccessfulResponse = ValueStopwatch.StartNew();\n        }\n\n        internal interface ITestAccessor\n        {\n            int MissedProbes { get; }\n        }\n\n        /// <summary>\n        /// The silo which this instance is responsible for.\n        /// </summary>\n        public SiloAddress TargetSiloAddress { get; }\n\n        /// <summary>\n        /// Whether or not this monitor is canceled.\n        /// </summary>\n        public bool IsCanceled => _stoppingCancellation.IsCancellationRequested;\n\n        int ITestAccessor.MissedProbes => _failedProbes;\n\n        /// <summary>\n        /// Start the monitor.\n        /// </summary>\n        public void Start()\n        {\n            using var suppressExecutionContext = new ExecutionContextSuppressor();\n            lock (_lockObj)\n            {\n                if (_stoppingCancellation.IsCancellationRequested)\n                {\n                    throw new InvalidOperationException(\"This instance has already been stopped and cannot be started again\");\n                }\n\n                if (_runTask is not null)\n                {\n                    throw new InvalidOperationException(\"This instance has already been started\");\n                }\n\n                _runTask = Task.Run(Run);\n            }\n        }\n\n        /// <summary>\n        /// Stop the monitor.\n        /// </summary>\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            Dispose();\n\n            if (_runTask is Task task)\n            {\n                await task.WaitAsync(cancellationToken).SuppressThrowing();\n            }\n        }\n\n        public void Dispose()\n        {\n            lock (_lockObj)\n            {\n                if (_stoppingCancellation.IsCancellationRequested)\n                {\n                    return;\n                }\n\n                _stoppingCancellation.Cancel();\n                _pingTimer.Dispose();\n            }\n        }\n\n        public async ValueTask DisposeAsync()\n        {\n            Dispose();\n            if (_runTask is Task task)\n            {\n                await task.SuppressThrowing();\n            }\n        }\n\n        private async Task Run()\n        {\n            MembershipTableSnapshot? activeMembersSnapshot = default;\n            SiloAddress[]? otherNodes = default;\n            var options = _clusterMembershipOptions.CurrentValue;\n            TimeSpan? overrideDelay = RandomTimeSpan.Next(options.ProbeTimeout);\n            while (await _pingTimer.NextTick(overrideDelay))\n            {\n                ProbeResult probeResult;\n                overrideDelay = default;\n                var now = DateTime.UtcNow;\n\n                try\n                {\n                    // Discover the other active nodes in the cluster, if there are any.\n                    var membershipSnapshot = _membershipService.MembershipTableSnapshot;\n                    if (otherNodes is null || !ReferenceEquals(activeMembersSnapshot, membershipSnapshot))\n                    {\n                        activeMembersSnapshot = membershipSnapshot;\n                        otherNodes = membershipSnapshot.Entries.Values\n                            .Where(v => v.Status == SiloStatus.Active\n                                && !v.SiloAddress.Equals(TargetSiloAddress)\n                                && !v.SiloAddress.Equals(_localSiloDetails.SiloAddress)\n                                && !v.HasMissedIAmAlives(options, now))\n                            .Select(s => s.SiloAddress)\n                            .ToArray();\n                    }\n\n                    var isDirectProbe = !options.EnableIndirectProbes || _failedProbes < options.NumMissedProbesLimit - 1 || otherNodes.Length == 0;\n                    var timeout = GetTimeout(isDirectProbe);\n                    using var cancellation = new CancellationTokenSource(timeout);\n\n                    if (isDirectProbe)\n                    {\n                        // Probe the silo directly.\n                        probeResult = await this.ProbeDirectly(cancellation.Token).ConfigureAwait(false);\n                    }\n                    else\n                    {\n                        // Pick a random other node and probe the target indirectly, using the selected node as an intermediary.\n                        var intermediary = otherNodes[Random.Shared.Next(otherNodes.Length)];\n\n                        // Select a timeout which will allow the intermediary node to attempt to probe the target node and still respond to this node\n                        // if the remote node does not respond in time.\n                        // Attempt to account for local health degradation by extending the timeout period.\n                        probeResult = await this.ProbeIndirectly(intermediary, timeout, cancellation.Token).ConfigureAwait(false);\n\n                        // If the intermediary is not entirely healthy, remove it from consideration and continue to probe.\n                        // Note that all recused silos will be included in the consideration set the next time cluster membership changes.\n                        if (probeResult.Status != ProbeResultStatus.Succeeded && probeResult.IntermediaryHealthDegradationScore > 0)\n                        {\n                            LogInformationRecusingUnhealthyIntermediary(_log, intermediary);\n                            otherNodes = [.. otherNodes.Where(node => !node.Equals(intermediary))];\n                            overrideDelay = TimeSpan.FromMilliseconds(250);\n                        }\n                    }\n\n                    if (!_stoppingCancellation.IsCancellationRequested)\n                    {\n                        await _onProbeResult(this, probeResult).ConfigureAwait(false);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorExceptionMonitoringSilo(_log, exception, TargetSiloAddress);\n                }\n            }\n\n            TimeSpan GetTimeout(bool isDirectProbe)\n            {\n                var additionalTimeout = 0;\n\n                if (options.ExtendProbeTimeoutDuringDegradation)\n                {\n                    // Attempt to account for local health degradation by extending the timeout period.\n                    var localDegradationScore = _localSiloHealthMonitor.GetLocalHealthDegradationScore(DateTime.UtcNow);\n                    additionalTimeout += localDegradationScore;\n                }\n\n                if (!isDirectProbe)\n                {\n                    // Indirect probes need extra time to account for the additional hop.\n                    additionalTimeout += 1;\n                }\n\n                // When the debugger is attached, extend probe times so that silos are not terminated\n                // due to debugging pauses.\n                if (Debugger.IsAttached)\n                {\n                    additionalTimeout += 25;\n                }\n\n                return options.ProbeTimeout.Multiply(1 + additionalTimeout);\n            }\n        }\n\n        /// <summary>\n        /// Probes the remote silo.\n        /// </summary>\n        /// <param name=\"cancellation\">A token to cancel and fail the probe attempt.</param>\n        /// <returns>The number of failed probes since the last successful probe.</returns>\n        private async Task<ProbeResult> ProbeDirectly(CancellationToken cancellation)\n        {\n            var id = ++_nextProbeId;\n            LogTraceGoingToSendPing(_log, id, TargetSiloAddress);\n\n            var roundTripTimer = ValueStopwatch.StartNew();\n            ProbeResult probeResult;\n            Exception? failureException;\n            try\n            {\n                await _prober.Probe(TargetSiloAddress, id, cancellation).WaitAsync(cancellation);\n                failureException = null;\n            }\n            catch (OperationCanceledException exception)\n            {\n                failureException = new OperationCanceledException($\"The ping attempt was cancelled after {roundTripTimer.Elapsed}. Ping #{id}\", exception);\n            }\n            catch (Exception exception)\n            {\n                failureException = exception;\n            }\n            finally\n            {\n                roundTripTimer.Stop();\n            }\n\n            if (failureException is null)\n            {\n                MessagingInstruments.OnPingReplyReceived(TargetSiloAddress);\n\n                LogTraceGotSuccessfulPingResponse(_log, id, TargetSiloAddress, roundTripTimer.Elapsed);\n\n                _failedProbes = 0;\n                _elapsedSinceLastSuccessfulResponse.Restart();\n                LastRoundTripTime = roundTripTimer.Elapsed;\n                probeResult = ProbeResult.CreateDirect(0, ProbeResultStatus.Succeeded);\n            }\n            else\n            {\n                MessagingInstruments.OnPingReplyMissed(TargetSiloAddress);\n\n                var failedProbes = ++_failedProbes;\n                LogWarningDidNotGetResponseForProbe(_log, failureException, id, TargetSiloAddress, roundTripTimer.Elapsed, failedProbes);\n\n                probeResult = ProbeResult.CreateDirect(failedProbes, ProbeResultStatus.Failed);\n            }\n\n            return probeResult;\n        }\n\n        /// <summary>\n        /// Probes the remote node via an intermediary silo.\n        /// </summary>\n        /// <param name=\"intermediary\">The node to probe the target with.</param>\n        /// <param name=\"directProbeTimeout\">The amount of time which the intermediary should allow for the target to respond.</param>\n        /// <param name=\"cancellation\">A token to cancel and fail the probe attempt.</param>\n        /// <returns>The number of failed probes since the last successful probe.</returns>\n        private async Task<ProbeResult> ProbeIndirectly(SiloAddress intermediary, TimeSpan directProbeTimeout, CancellationToken cancellation)\n        {\n            var id = ++_nextProbeId;\n            LogTraceGoingToSendIndirectPing(_log, id, TargetSiloAddress, intermediary);\n\n            var roundTripTimer = ValueStopwatch.StartNew();\n            ProbeResult probeResult;\n            try\n            {\n                using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellation, _stoppingCancellation.Token);\n                var indirectResult = await _prober.ProbeIndirectly(intermediary, TargetSiloAddress, directProbeTimeout, id, cancellationSource.Token).WaitAsync(cancellationSource.Token);\n                roundTripTimer.Stop();\n                var roundTripTime = roundTripTimer.Elapsed - indirectResult.ProbeResponseTime;\n\n                // Record timing regardless of the result.\n                _elapsedSinceLastSuccessfulResponse.Restart();\n                LastRoundTripTime = roundTripTime;\n\n                if (indirectResult.Succeeded)\n                {\n                    LogInformationIndirectProbeSucceeded(_log, id, TargetSiloAddress, intermediary, roundTripTimer.Elapsed, indirectResult.ProbeResponseTime);\n\n                    MessagingInstruments.OnPingReplyReceived(TargetSiloAddress);\n\n                    _failedProbes = 0;\n                    probeResult = ProbeResult.CreateIndirect(0, ProbeResultStatus.Succeeded, indirectResult, intermediary);\n                }\n                else\n                {\n                    MessagingInstruments.OnPingReplyMissed(TargetSiloAddress);\n\n                    if (indirectResult.IntermediaryHealthScore > 0)\n                    {\n                        LogInformationIgnoringFailureResultForPing(_log, id, TargetSiloAddress, indirectResult.IntermediaryHealthScore);\n                        probeResult = ProbeResult.CreateIndirect(_failedProbes, ProbeResultStatus.Unknown, indirectResult, intermediary);\n                    }\n                    else\n                    {\n                        LogWarningIndirectProbeFailed(_log, id, TargetSiloAddress, intermediary, roundTripTimer.Elapsed, indirectResult.ProbeResponseTime, indirectResult.FailureMessage, indirectResult.IntermediaryHealthScore);\n\n                        var missed = ++_failedProbes;\n                        probeResult = ProbeResult.CreateIndirect(missed, ProbeResultStatus.Failed, indirectResult, intermediary);\n                    }\n                }\n            }\n            catch (Exception exception)\n            {\n                MessagingInstruments.OnPingReplyMissed(TargetSiloAddress);\n                LogWarningIndirectProbeRequestFailed(_log, exception);\n                probeResult = ProbeResult.CreateIndirect(_failedProbes, ProbeResultStatus.Unknown, default, intermediary);\n            }\n\n            return probeResult;\n        }\n\n        /// <inheritdoc />\n        public bool CheckHealth(DateTime lastCheckTime, out string reason) => _pingTimer.CheckHealth(lastCheckTime, out reason);\n\n        /// <summary>\n        /// Represents the result of probing a silo.\n        /// </summary>\n        [StructLayout(LayoutKind.Auto)]\n        public readonly struct ProbeResult\n        {\n            private ProbeResult(int failedProbeCount, ProbeResultStatus status, bool isDirectProbe, int intermediaryHealthDegradationScore, SiloAddress? intermediary)\n            {\n                FailedProbeCount = failedProbeCount;\n                Status = status;\n                IsDirectProbe = isDirectProbe;\n                IntermediaryHealthDegradationScore = intermediaryHealthDegradationScore;\n                Intermediary = intermediary;\n            }\n\n            public static ProbeResult CreateDirect(int failedProbeCount, ProbeResultStatus status)\n                => new(failedProbeCount, status, isDirectProbe: true, 0, null);\n\n            public static ProbeResult CreateIndirect(int failedProbeCount, ProbeResultStatus status, IndirectProbeResponse indirectProbeResponse, SiloAddress? intermediary)\n                => new(failedProbeCount, status, isDirectProbe: false, indirectProbeResponse.IntermediaryHealthScore, intermediary);\n\n            public int FailedProbeCount { get; }\n\n            public ProbeResultStatus Status { get; }\n\n            public bool IsDirectProbe { get; }\n\n            public int IntermediaryHealthDegradationScore { get; }\n\n            public SiloAddress? Intermediary { get; }\n        }\n\n        public enum ProbeResultStatus\n        {\n            Unknown,\n            Failed,\n            Succeeded\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Going to send Ping #{Id} to probe silo {Silo}\"\n        )]\n        private static partial void LogTraceGoingToSendPing(ILogger logger, int id, SiloAddress silo);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Got successful ping response for ping #{Id} from {Silo} with round trip time of {RoundTripTime}\"\n        )]\n        private static partial void LogTraceGotSuccessfulPingResponse(ILogger logger, int id, SiloAddress silo, TimeSpan roundTripTime);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.MembershipMissedPing,\n            Message = \"Did not get response for probe #{Id} to silo {Silo} after {Elapsed}. Current number of consecutive failed probes is {FailedProbeCount}\"\n        )]\n        private static partial void LogWarningDidNotGetResponseForProbe(ILogger logger, Exception exception, int id, SiloAddress silo, TimeSpan elapsed, int failedProbeCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Going to send indirect ping #{Id} to probe silo {Silo} via {Intermediary}\"\n        )]\n        private static partial void LogTraceGoingToSendIndirectPing(ILogger logger, int id, SiloAddress silo, SiloAddress intermediary);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Indirect probe request #{Id} to silo {SiloAddress} via silo {IntermediarySiloAddress} succeeded after {RoundTripTime} with a direct probe response time of {ProbeResponseTime}.\"\n        )]\n        private static partial void LogInformationIndirectProbeSucceeded(ILogger logger, int id, SiloAddress siloAddress, SiloAddress intermediarySiloAddress, TimeSpan roundTripTime, TimeSpan probeResponseTime);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Ignoring failure result for ping #{Id} from {Silo} since the intermediary used to probe the silo is not healthy. Intermediary health degradation score: {IntermediaryHealthScore}.\"\n        )]\n        private static partial void LogInformationIgnoringFailureResultForPing(ILogger logger, int id, SiloAddress silo, int intermediaryHealthScore);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Indirect probe request #{Id} to silo {SiloAddress} via silo {IntermediarySiloAddress} failed after {RoundTripTime} with a direct probe response time of {ProbeResponseTime}. Failure message: {FailureMessage}. Intermediary health score: {IntermediaryHealthScore}.\"\n        )]\n        private static partial void LogWarningIndirectProbeFailed(ILogger logger, int id, SiloAddress siloAddress, SiloAddress intermediarySiloAddress, TimeSpan roundTripTime, TimeSpan probeResponseTime, string failureMessage, int intermediaryHealthScore);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Indirect probe request failed.\"\n        )]\n        private static partial void LogWarningIndirectProbeRequestFailed(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Recusing unhealthy intermediary '{Intermediary}' and trying again with remaining nodes\"\n        )]\n        private static partial void LogInformationRecusingUnhealthyIntermediary(ILogger logger, SiloAddress intermediary);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Exception monitoring silo {SiloAddress}\"\n        )]\n        private static partial void LogErrorExceptionMonitoringSilo(ILogger logger, Exception exception, SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/ISiloMetadataCache.cs",
    "content": "#nullable enable\n\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\npublic interface ISiloMetadataCache\n{\n    SiloMetadata GetSiloMetadata(SiloAddress siloAddress);\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/ISiloMetadataClient.cs",
    "content": "using System.Threading.Tasks;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\ninternal interface ISiloMetadataClient\n{\n    Task<SiloMetadata> GetSiloMetadata(SiloAddress siloAddress);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/ISiloMetadataSystemTarget.cs",
    "content": "using System.Threading.Tasks;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\n[Alias(\"Orleans.Runtime.MembershipService.SiloMetadata.ISiloMetadataSystemTarget\")]\ninternal interface ISiloMetadataSystemTarget : ISystemTarget\n{\n    [Alias(\"GetSiloMetadata\")]\n    Task<SiloMetadata> GetSiloMetadata();\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/SiloMetadaCache.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\ninternal partial class SiloMetadataCache(\n    ISiloMetadataClient siloMetadataClient,\n    MembershipTableManager membershipTableManager,\n    IOptions<ClusterMembershipOptions> clusterMembershipOptions,\n    ILogger<SiloMetadataCache> logger)\n    : ISiloMetadataCache, ILifecycleParticipant<ISiloLifecycle>, IDisposable\n{\n    private readonly ConcurrentDictionary<SiloAddress, SiloMetadata> _metadata = new();\n    private readonly Dictionary<SiloAddress, DateTime> _negativeCache = new();\n    private readonly CancellationTokenSource _cts = new();\n    private TimeSpan negativeCachePeriod;\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        Task? task = null;\n        Task OnStart(CancellationToken _)\n        {\n            // This gives time for the cluster to be voted Dead and for membership updates to propagate that out\n            negativeCachePeriod = clusterMembershipOptions.Value.ProbeTimeout * clusterMembershipOptions.Value.NumMissedProbesLimit\n                                  + (2 * clusterMembershipOptions.Value.TableRefreshTimeout);\n            task = Task.Run(() => this.ProcessMembershipUpdates(_cts.Token));\n            return Task.CompletedTask;\n        }\n\n        async Task OnStop(CancellationToken ct)\n        {\n            await _cts.CancelAsync().ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n            if (task is not null)\n            {\n                await task.WaitAsync(ct).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n            }\n        }\n\n        lifecycle.Subscribe(\n            nameof(ClusterMembershipService),\n            ServiceLifecycleStage.RuntimeServices,\n            OnStart,\n            OnStop);\n    }\n\n    private async Task ProcessMembershipUpdates(CancellationToken ct)\n    {\n        try\n        {\n            LogDebugStartProcessingMembershipUpdates(logger);\n            await foreach (var update in membershipTableManager.MembershipTableUpdates.WithCancellation(ct))\n            {\n                // Add entries for members that aren't already in the cache\n                var now = DateTime.UtcNow;\n                var recentlyActiveSilos = update.Entries\n                    .Where(e => e.Value.Status is SiloStatus.Active or SiloStatus.Joining)\n                    .Where(e => !e.Value.HasMissedIAmAlives(clusterMembershipOptions.Value, now));\n                foreach (var membershipEntry in recentlyActiveSilos)\n                {\n                    if (!_metadata.ContainsKey(membershipEntry.Key))\n                    {\n                        if (_negativeCache.TryGetValue(membershipEntry.Key, out var expiration) && expiration > now)\n                        {\n                            continue;\n                        }\n                        try\n                        {\n                            var metadata = await siloMetadataClient.GetSiloMetadata(membershipEntry.Key).WaitAsync(ct);\n                            _metadata.TryAdd(membershipEntry.Key, metadata);\n                            _negativeCache.Remove(membershipEntry.Key, out _);\n                        }\n                        catch(Exception exception)\n                        {\n                            _negativeCache.TryAdd(membershipEntry.Key, now + negativeCachePeriod);\n                            LogErrorFetchingSiloMetadata(logger, exception, membershipEntry.Key);\n                        }\n                    }\n                }\n\n                // Remove entries for members that are now dead\n                var deadSilos = update.Entries\n                    .Where(e => e.Value.Status == SiloStatus.Dead);\n                foreach (var membershipEntry in deadSilos)\n                {\n                    _metadata.TryRemove(membershipEntry.Key, out _);\n                    _negativeCache.Remove(membershipEntry.Key, out _);\n                }\n\n                // Remove entries for members that are no longer in the table\n                foreach (var silo in _metadata.Keys.ToList())\n                {\n                    if (!update.Entries.ContainsKey(silo))\n                    {\n                        _metadata.TryRemove(silo, out _);\n                        _negativeCache.Remove(silo, out _);\n                    }\n                }\n            }\n        }\n        catch (OperationCanceledException) when (ct.IsCancellationRequested)\n        {\n            // Ignore and continue shutting down.\n        }\n        catch (Exception exception)\n        {\n            LogErrorProcessingMembershipUpdates(logger, exception);\n        }\n        finally\n        {\n            LogDebugStoppingMembershipProcessor(logger);\n        }\n    }\n\n    public SiloMetadata GetSiloMetadata(SiloAddress siloAddress) => _metadata.GetValueOrDefault(siloAddress) ?? SiloMetadata.Empty;\n\n    public void SetMetadata(SiloAddress siloAddress, SiloMetadata metadata) => _metadata.TryAdd(siloAddress, metadata);\n\n    public void Dispose() => _cts.Cancel();\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Starting to process membership updates.\")]\n    private static partial void LogDebugStartProcessingMembershipUpdates(ILogger logger);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error fetching metadata for silo {Silo}\")]\n    private static partial void LogErrorFetchingSiloMetadata(ILogger logger, Exception exception, SiloAddress silo);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing membership updates\")]\n    private static partial void LogErrorProcessingMembershipUpdates(ILogger logger, Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Stopping membership update processor\")]\n    private static partial void LogDebugStoppingMembershipProcessor(ILogger logger);\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/SiloMetadata.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\n[GenerateSerializer]\n[Alias(\"Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata\")]\npublic record SiloMetadata\n{\n    public static SiloMetadata Empty { get; } = new SiloMetadata();\n\n    [Id(0)]\n    public ImmutableDictionary<string, string> Metadata { get; private set; } = ImmutableDictionary<string, string>.Empty;\n\n    internal void AddMetadata(IEnumerable<KeyValuePair<string, string>> metadata) => Metadata = Metadata.SetItems(metadata);\n    internal void AddMetadata(string key, string value) => Metadata = Metadata.SetItem(key, value);\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/SiloMetadataClient.cs",
    "content": "using System.Threading.Tasks;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\ninternal sealed class SiloMetadataClient(IInternalGrainFactory grainFactory) : ISiloMetadataClient\n{\n    public async Task<SiloMetadata> GetSiloMetadata(SiloAddress siloAddress)\n    {\n        var metadataSystemTarget = grainFactory.GetSystemTarget<ISiloMetadataSystemTarget>(Constants.SiloMetadataType, siloAddress);\n        var metadata = await metadataSystemTarget.GetSiloMetadata();\n        return metadata;\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/SiloMetadataHostingExtensions.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration.Internal;\nusing Orleans.Hosting;\nusing Orleans.Placement;\nusing Orleans.Runtime.Placement.Filtering;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\npublic static class SiloMetadataHostingExtensions\n{\n    /// <summary>\n    /// Configure silo metadata from the builder configuration.\n    /// </summary>\n    /// <param name=\"builder\">Silo builder</param>\n    /// <remarks>\n    /// Get the ORLEANS__METADATA section from config\n    /// Key/value pairs in configuration as a <see cref=\"Dictionary{TKey,TValue}\"/> will look like this as environment variables:\n    /// ORLEANS__METADATA__key1=value1\n    /// </remarks>\n    /// <returns></returns>\n    public static ISiloBuilder UseSiloMetadata(this ISiloBuilder builder) => builder.UseSiloMetadata(builder.Configuration);\n\n    /// <summary>\n    /// Configure silo metadata from configuration.\n    /// </summary>\n    /// <param name=\"builder\">Silo builder</param>\n    /// <param name=\"configuration\">Configuration to pull from</param>\n    /// <remarks>\n    /// Get the ORLEANS__METADATA section from config\n    /// Key/value pairs in configuration as a <see cref=\"Dictionary{TKey,TValue}\"/> will look like this as environment variables:\n    /// ORLEANS__METADATA__key1=value1\n    /// </remarks>\n    /// <returns></returns>\n    public static ISiloBuilder UseSiloMetadata(this ISiloBuilder builder, IConfiguration configuration)\n    {\n\n        var metadataConfigSection = configuration.GetSection(\"Orleans\").GetSection(\"Metadata\");\n\n        return builder.UseSiloMetadata(metadataConfigSection);\n    }\n\n    /// <summary>\n    /// Configure silo metadata from configuration section.\n    /// </summary>\n    /// <param name=\"builder\">Silo builder</param>\n    /// <param name=\"configurationSection\">Configuration section to pull from</param>\n    /// <remarks>\n    /// Get the ORLEANS__METADATA section from config section\n    /// Key/value pairs in configuration as a <see cref=\"Dictionary{TKey,TValue}\"/> will look like this as environment variables:\n    /// ORLEANS__METADATA__key1=value1\n    /// </remarks>\n    /// <returns></returns>\n    public static ISiloBuilder UseSiloMetadata(this ISiloBuilder builder, IConfigurationSection configurationSection)\n    {\n        var dictionary = configurationSection.Get<Dictionary<string, string>>();\n\n        return builder.UseSiloMetadata(dictionary ?? []);\n    }\n\n    /// <summary>\n    /// Configure silo metadata from configuration section.\n    /// </summary>\n    /// <param name=\"builder\">Silo builder</param>\n    /// <param name=\"metadata\">Metadata to add</param>\n    /// <returns></returns>\n    public static ISiloBuilder UseSiloMetadata(this ISiloBuilder builder, Dictionary<string, string> metadata)\n    {\n        builder.ConfigureServices(services =>\n        {\n            services\n                .AddOptionsWithValidateOnStart<SiloMetadata>()\n                .Configure(m => m.AddMetadata(metadata));\n\n            services.AddSingleton<SiloMetadataSystemTarget>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, SiloMetadataSystemTarget>();\n            services.AddSingleton<SiloMetadataCache>();\n            services.AddFromExisting<ISiloMetadataCache, SiloMetadataCache>();\n            services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, SiloMetadataCache>();\n            services.AddSingleton<ISiloMetadataClient, SiloMetadataClient>();\n\n            // Placement filters\n            services.AddPlacementFilter<PreferredMatchSiloMetadataPlacementFilterStrategy, PreferredMatchSiloMetadataPlacementFilterDirector>(ServiceLifetime.Transient);\n            services.AddPlacementFilter<RequiredMatchSiloMetadataPlacementFilterStrategy, RequiredMatchSiloMetadataPlacementFilterDirector>(ServiceLifetime.Transient);\n        });\n        return builder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloMetadata/SiloMetadataSystemTarget.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\n#nullable enable\nnamespace Orleans.Runtime.MembershipService.SiloMetadata;\n\ninternal sealed class SiloMetadataSystemTarget : SystemTarget, ISiloMetadataSystemTarget, ILifecycleParticipant<ISiloLifecycle>\n{\n    private readonly SiloMetadata _siloMetadata;\n\n    public SiloMetadataSystemTarget(\n        IOptions<SiloMetadata> siloMetadata,\n        SystemTargetShared shared) : base(Constants.SiloMetadataType, shared)\n    {\n        _siloMetadata = siloMetadata.Value;\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    public Task<SiloMetadata> GetSiloMetadata() => Task.FromResult(_siloMetadata);\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        // We don't participate in any lifecycle stages: activating this instance is all that is necessary.\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloStatusListenerManager.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing System.Threading.Tasks;\nusing System.Threading;\nusing System.Collections.Immutable;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.MembershipService;\n\n/// <summary>\n/// Manages <see cref=\"ISiloStatusListener\"/> instances.\n/// </summary>\ninternal partial class SiloStatusListenerManager : ILifecycleParticipant<ISiloLifecycle>\n{\n#if NET9_0_OR_GREATER\n    private readonly Lock _listenersLock = new();\n#else\n    private readonly object _listenersLock = new();\n#endif\n    private readonly CancellationTokenSource _cancellation = new();\n    private readonly MembershipTableManager _membershipTableManager;\n    private readonly ILogger<SiloStatusListenerManager> _logger;\n    private readonly IFatalErrorHandler _fatalErrorHandler;\n    private ImmutableList<WeakReference<ISiloStatusListener>> _listeners = [];\n\n    public SiloStatusListenerManager(\n        MembershipTableManager membershipTableManager,\n        ILogger<SiloStatusListenerManager> log,\n        IFatalErrorHandler fatalErrorHandler)\n    {\n        _membershipTableManager = membershipTableManager;\n        _logger = log;\n        _fatalErrorHandler = fatalErrorHandler;\n    }\n\n    public bool Subscribe(ISiloStatusListener listener)\n    {\n        lock (_listenersLock)\n        {\n            foreach (var reference in _listeners)\n            {\n                if (!reference.TryGetTarget(out var existing))\n                {\n                    continue;\n                }\n\n                if (ReferenceEquals(existing, listener)) return false;\n            }\n\n            _listeners = _listeners.Add(new WeakReference<ISiloStatusListener>(listener));\n            return true;\n        }\n    }\n\n    public bool Unsubscribe(ISiloStatusListener listener)\n    {\n        lock (_listenersLock)\n        {\n            for (var i = 0; i < _listeners.Count; i++)\n            {\n                if (!_listeners[i].TryGetTarget(out var existing))\n                {\n                    continue;\n                }\n\n                if (ReferenceEquals(existing, listener))\n                {\n                    _listeners = _listeners.RemoveAt(i);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n\n    private async Task ProcessMembershipUpdates()\n    {\n        ClusterMembershipSnapshot? previous = default;\n        try\n        {\n            LogDebugStartingToProcessMembershipUpdates();\n            await foreach (var tableSnapshot in _membershipTableManager.MembershipTableUpdates.WithCancellation(_cancellation.Token))\n            {\n                var snapshot = tableSnapshot.CreateClusterMembershipSnapshot();\n\n                var update = (previous is null || snapshot.Version == MembershipVersion.MinValue) ? snapshot.AsUpdate() : snapshot.CreateUpdate(previous);\n                NotifyObservers(update);\n                previous = snapshot;\n            }\n        }\n        catch (OperationCanceledException) when (_cancellation.IsCancellationRequested)\n        {\n            // Ignore and continue shutting down.\n        }\n        catch (Exception exception) when (_fatalErrorHandler.IsUnexpected(exception))\n        {\n            LogErrorProcessingMembershipUpdates(exception);\n            _fatalErrorHandler.OnFatalException(this, nameof(ProcessMembershipUpdates), exception);\n        }\n        finally\n        {\n            LogDebugStoppingMembershipUpdateProcessor();\n        }\n    }\n\n    private void NotifyObservers(ClusterMembershipUpdate update)\n    {\n        if (!update.HasChanges) return;\n\n        List<WeakReference<ISiloStatusListener>>? toRemove = null;\n        var subscribers = _listeners;\n        foreach (var change in update.Changes)\n        {\n            for (var i = 0; i < subscribers.Count; ++i)\n            {\n                if (!subscribers[i].TryGetTarget(out var listener))\n                {\n                    if (toRemove is null) toRemove = new List<WeakReference<ISiloStatusListener>>();\n                    toRemove.Add(subscribers[i]);\n                    continue;\n                }\n\n                try\n                {\n                    listener.SiloStatusChangeNotification(change.SiloAddress, change.Status);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorCallingSiloStatusChangeNotification(exception, listener);\n                }\n            }\n        }\n\n        if (toRemove != null)\n        {\n            lock (_listenersLock)\n            {\n                var builder = _listeners.ToBuilder();\n                foreach (var entry in toRemove) builder.Remove(entry);\n                _listeners = builder.ToImmutable();\n            }\n        }\n    }\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        Task? task = null;\n\n        lifecycle.Subscribe(nameof(SiloStatusListenerManager), ServiceLifecycleStage.AfterRuntimeGrainServices, OnStart, _ => Task.CompletedTask);\n        lifecycle.Subscribe(nameof(SiloStatusListenerManager), ServiceLifecycleStage.RuntimeInitialize, _ => Task.CompletedTask, OnStop);\n\n        Task OnStart(CancellationToken ct)\n        {\n            task = Task.Run(ProcessMembershipUpdates);\n            return Task.CompletedTask;\n        }\n\n        async Task OnStop(CancellationToken ct)\n        {\n            _cancellation.Cancel(throwOnFirstException: false);\n            if (task is not null)\n            {\n                await task.WaitAsync(ct).SuppressThrowing();\n            }\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Starting to process membership updates.\"\n    )]\n    private partial void LogDebugStartingToProcessMembershipUpdates();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error processing membership updates.\"\n    )]\n    private partial void LogErrorProcessingMembershipUpdates(Exception exception);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Stopping membership update processor.\"\n    )]\n    private partial void LogDebugStoppingMembershipUpdateProcessor();\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Exception while calling \" + nameof(ISiloStatusListener.SiloStatusChangeNotification) + \" on listener '{Listener}'.\"\n    )]\n    private partial void LogErrorCallingSiloStatusChangeNotification(Exception exception, ISiloStatusListener listener);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SiloStatusOracle.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal partial class SiloStatusOracle : ISiloStatusOracle\n    {\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly MembershipTableManager membershipTableManager;\n        private readonly SiloStatusListenerManager listenerManager;\n        private readonly ILogger log;\n#if NET9_0_OR_GREATER\n        private readonly Lock cacheUpdateLock = new();\n#else\n        private readonly object cacheUpdateLock = new();\n#endif\n        private MembershipTableSnapshot cachedSnapshot;\n        private Dictionary<SiloAddress, SiloStatus> siloStatusCache = new Dictionary<SiloAddress, SiloStatus>();\n        private Dictionary<SiloAddress, SiloStatus> siloStatusCacheOnlyActive = new Dictionary<SiloAddress, SiloStatus>();\n        private ImmutableArray<SiloAddress> _activeSilos = [];\n\n        public SiloStatusOracle(\n            ILocalSiloDetails localSiloDetails,\n            MembershipTableManager membershipTableManager,\n            ILogger<SiloStatusOracle> logger,\n            SiloStatusListenerManager listenerManager)\n        {\n            this.localSiloDetails = localSiloDetails;\n            this.membershipTableManager = membershipTableManager;\n            this.listenerManager = listenerManager;\n            this.log = logger;\n        }\n\n        public SiloStatus CurrentStatus => this.membershipTableManager.CurrentStatus;\n        public string SiloName => this.localSiloDetails.Name;\n        public SiloAddress SiloAddress => this.localSiloDetails.SiloAddress;\n        \n        public SiloStatus GetApproximateSiloStatus(SiloAddress silo)\n        {\n            var status = this.membershipTableManager.MembershipTableSnapshot.GetSiloStatus(silo);\n\n            if (status == SiloStatus.None)\n            {\n                if (this.CurrentStatus == SiloStatus.Active)\n                {\n                    LogSiloAddressNotRegistered(this.log, silo);\n                }\n            }\n\n            return status;\n        }\n\n        public ImmutableArray<SiloAddress> GetActiveSilos()\n        {\n            EnsureFreshCache();\n            return _activeSilos;\n        }\n\n        public Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false)\n        {\n            EnsureFreshCache();\n            return onlyActive ? this.siloStatusCacheOnlyActive : this.siloStatusCache;\n        }\n\n        private void EnsureFreshCache()\n        {\n            var currentMembership = this.membershipTableManager.MembershipTableSnapshot;\n            if (ReferenceEquals(this.cachedSnapshot, currentMembership))\n            {\n                return;\n            }\n\n            lock (this.cacheUpdateLock)\n            {\n                currentMembership = this.membershipTableManager.MembershipTableSnapshot;\n                if (ReferenceEquals(this.cachedSnapshot, currentMembership))\n                {\n                    return;\n                }\n\n                var newSiloStatusCache = new Dictionary<SiloAddress, SiloStatus>();\n                var newSiloStatusCacheOnlyActive = new Dictionary<SiloAddress, SiloStatus>();\n                var newActiveSilos = ImmutableArray.CreateBuilder<SiloAddress>();\n                foreach (var entry in currentMembership.Entries)\n                {\n                    var silo = entry.Key;\n                    var status = entry.Value.Status;\n                    newSiloStatusCache[silo] = status;\n                    if (status == SiloStatus.Active)\n                    {\n                        newSiloStatusCacheOnlyActive[silo] = status;\n                        newActiveSilos.Add(silo);\n                    }\n                }\n\n                Interlocked.Exchange(ref this.cachedSnapshot, currentMembership);\n                this.siloStatusCache = newSiloStatusCache;\n                this.siloStatusCacheOnlyActive = newSiloStatusCacheOnlyActive;\n                _activeSilos = newActiveSilos.ToImmutable();\n            }\n        }\n\n        public bool IsDeadSilo(SiloAddress silo)\n        {\n            if (silo.Equals(this.SiloAddress)) return false;\n\n            var status = this.GetApproximateSiloStatus(silo);\n            \n            return status == SiloStatus.Dead;\n        }\n\n        public bool IsFunctionalDirectory(SiloAddress silo)\n        {\n            if (silo.Equals(this.SiloAddress)) return true;\n\n            var status = this.GetApproximateSiloStatus(silo);\n            return !status.IsTerminating();\n        }\n\n        public bool TryGetSiloName(SiloAddress siloAddress, out string siloName)\n        {\n            var snapshot = this.membershipTableManager.MembershipTableSnapshot.Entries;\n            if (snapshot.TryGetValue(siloAddress, out var entry))\n            {\n                siloName = entry.SiloName;\n                return true;\n            }\n\n            siloName = default;\n            return false;\n        }\n\n        public bool SubscribeToSiloStatusEvents(ISiloStatusListener listener) => this.listenerManager.Subscribe(listener);\n\n        public bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener listener) => this.listenerManager.Unsubscribe(listener);\n    \n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.Runtime_Error_100209,\n            Message = \"The given SiloAddress {SiloAddress} is not registered in this MembershipOracle.\"\n        )]\n        private static partial void LogSiloAddressNotRegistered(ILogger logger, SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/MembershipService/SystemTargetBasedMembershipTable.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Configuration;\nusing Orleans.Serialization;\n\nnamespace Orleans.Runtime.MembershipService\n{\n    internal partial class SystemTargetBasedMembershipTable : IMembershipTable\n    {\n        private readonly IServiceProvider serviceProvider;\n        private readonly ILogger logger;\n        private IMembershipTableSystemTarget grain;\n\n        public SystemTargetBasedMembershipTable(IServiceProvider serviceProvider, ILogger<SystemTargetBasedMembershipTable> logger)\n        {\n            this.serviceProvider = serviceProvider;\n            this.logger = logger;\n        }\n        public async Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            this.grain = await GetMembershipTable();\n        }\n\n        private async Task<IMembershipTableSystemTarget> GetMembershipTable()\n        {\n            var options = this.serviceProvider.GetRequiredService<IOptions<DevelopmentClusterMembershipOptions>>().Value;\n            if (options.PrimarySiloEndpoint == null)\n            {\n                throw new OrleansConfigurationException(\n                    $\"{nameof(DevelopmentClusterMembershipOptions)}.{nameof(options.PrimarySiloEndpoint)} must be set when using development clustering.\");\n            }\n\n            var siloDetails = this.serviceProvider.GetService<ILocalSiloDetails>();\n            bool isPrimarySilo = siloDetails.SiloAddress.Endpoint.Equals(options.PrimarySiloEndpoint);\n            var grainFactory = this.serviceProvider.GetRequiredService<IInternalGrainFactory>();\n            var result = grainFactory.GetSystemTarget<IMembershipTableSystemTarget>(Constants.SystemMembershipTableType, SiloAddress.New(options.PrimarySiloEndpoint, 0));\n            if (isPrimarySilo)\n            {\n                await this.WaitForTableGrainToInit(result);\n            }\n\n            return result;\n        }\n\n        // Only used with MembershipTableGrain to wait for primary to start.\n        private async Task WaitForTableGrainToInit(IMembershipTableSystemTarget membershipTableSystemTarget)\n        {\n            var timespan = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(5);\n            // This is a quick temporary solution to enable primary node to start fully before secondaries.\n            // Secondary silos waits untill GrainBasedMembershipTable is created.\n            for (int i = 0; i < 100; i++)\n            {\n                try\n                {\n                    await membershipTableSystemTarget.ReadAll().WaitAsync(timespan);\n                    LogInformationConnectedToMembershipTableProvider(logger);\n                    return;\n                }\n                catch (Exception exc)\n                {\n                    var type = exc.GetBaseException().GetType();\n                    if (type == typeof(TimeoutException) || type == typeof(OrleansException))\n                    {\n                        LogInformationWaitingForMembershipTableProvider(logger, timespan);\n                    }\n                    else\n                    {\n                        LogInformationMembershipTableProviderFailedToInitialize(logger);\n                        throw;\n                    }\n                }\n\n                await Task.Delay(timespan);\n            }\n        }\n\n        public Task DeleteMembershipTableEntries(string clusterId) => this.grain.DeleteMembershipTableEntries(clusterId);\n\n        public Task<MembershipTableData> ReadRow(SiloAddress key) => this.grain.ReadRow(key);\n\n        public Task<MembershipTableData> ReadAll() => this.grain.ReadAll();\n\n        public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion) => this.grain.InsertRow(entry, tableVersion);\n\n        public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) => this.grain.UpdateRow(entry, etag, tableVersion);\n\n        public Task UpdateIAmAlive(MembershipEntry entry) => this.grain.UpdateIAmAlive(entry);\n\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate) => this.grain.CleanupDefunctSiloEntries(beforeDate);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipFactory1,\n            Level = LogLevel.Information,\n            Message = \"Creating in-memory membership table\"\n        )]\n        private static partial void LogInformationCreatingInMemoryMembershipTable(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipTableGrainInit2,\n            Level = LogLevel.Information,\n            Message = \"Connected to membership table provider.\"\n        )]\n        private static partial void LogInformationConnectedToMembershipTableProvider(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipTableGrainInit3,\n            Level = LogLevel.Information,\n            Message = \"Waiting for membership table provider to initialize. Going to sleep for {Duration} and re-try to reconnect.\"\n        )]\n        private static partial void LogInformationWaitingForMembershipTableProvider(ILogger logger, TimeSpan duration);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipTableGrainInit4,\n            Level = LogLevel.Information,\n            Message = \"Membership table provider failed to initialize. Giving up.\"\n        )]\n        private static partial void LogInformationMembershipTableProviderFailedToInitialize(ILogger logger);\n    }\n\n    [Reentrant]\n    internal sealed partial class MembershipTableSystemTarget : SystemTarget, IMembershipTableSystemTarget, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private InMemoryMembershipTable table;\n        private readonly ILogger logger;\n\n        public MembershipTableSystemTarget(\n            ILogger<MembershipTableSystemTarget> logger,\n            DeepCopier deepCopier,\n            SystemTargetShared shared)\n            : base(CreateId(shared.SiloAddress), shared)\n        {\n            this.logger = logger;\n            table = new InMemoryMembershipTable(deepCopier);\n            LogInformationGrainBasedMembershipTableActivated(logger);\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        private static SystemTargetGrainId CreateId(SiloAddress siloAddress)\n        {\n            return SystemTargetGrainId.Create(Constants.SystemMembershipTableType, SiloAddress.New(siloAddress.Endpoint, 0));\n        }\n\n        public Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            LogInformationInitializeMembershipTable(logger, tryInitTableVersion);\n            return Task.CompletedTask;\n        }\n\n        public Task DeleteMembershipTableEntries(string clusterId)\n        {\n            LogInformationDeleteMembershipTableEntries(logger, clusterId);\n            table = null;\n            return Task.CompletedTask;\n        }\n\n        public Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            return Task.FromResult(table.Read(key));\n        }\n\n        public Task<MembershipTableData> ReadAll()\n        {\n            var t = table.ReadAll();\n            return Task.FromResult(t);\n        }\n\n        public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            LogDebugInsertRow(logger, entry, tableVersion);\n            bool result = table.Insert(entry, tableVersion);\n            if (result == false)\n                LogInformationInsertRowFailed(logger, entry, tableVersion, table.ReadAll());\n\n            return Task.FromResult(result);\n        }\n\n        public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            LogDebugUpdateRow(logger, entry, etag, tableVersion);\n            bool result = table.Update(entry, etag, tableVersion);\n            if (result == false)\n                LogInformationUpdateRowFailed(logger, entry, etag, tableVersion, table.ReadAll());\n\n            return Task.FromResult(result);\n        }\n\n        public Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            LogDebugUpdateIAmAlive(logger, entry);\n            table.UpdateIAmAlive(entry);\n            return Task.CompletedTask;\n        }\n\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            table.CleanupDefunctSiloEntries(beforeDate);\n            return Task.CompletedTask;\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            // Do nothing, just ensure that this instance is created so that it can register itself in the catalog.\n        }\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipGrainBasedTable1,\n            Level = LogLevel.Information,\n            Message = \"GrainBasedMembershipTable Activated.\"\n        )]\n        private static partial void LogInformationGrainBasedMembershipTableActivated(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"InitializeMembershipTable {TryInitTableVersion}.\"\n        )]\n        private static partial void LogInformationInitializeMembershipTable(ILogger logger, bool tryInitTableVersion);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"DeleteMembershipTableEntries {ClusterId}\"\n        )]\n        private static partial void LogInformationDeleteMembershipTableEntries(ILogger logger, string clusterId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"InsertRow entry = {Entry}, table version = {Version}\"\n        )]\n        private static partial void LogDebugInsertRow(ILogger logger, MembershipEntry entry, TableVersion version);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipGrainBasedTable2,\n            Level = LogLevel.Information,\n            Message = \"Insert of {Entry} and table version {Version} failed. Table now is {Table}\"\n        )]\n        private static partial void LogInformationInsertRowFailed(ILogger logger, MembershipEntry entry, TableVersion version, MembershipTableData table);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpdateRow entry = {Entry}, etag = {ETag}, table version = {Version}\"\n        )]\n        private static partial void LogDebugUpdateRow(ILogger logger, MembershipEntry entry, string etag, TableVersion version);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MembershipGrainBasedTable3,\n            Level = LogLevel.Information,\n            Message = \"Update of {Entry}, eTag {ETag}, table version {Version} failed. Table now is {Table}\"\n        )]\n        private static partial void LogInformationUpdateRowFailed(ILogger logger, MembershipEntry entry, string etag, TableVersion version, MembershipTableData table);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpdateIAmAlive entry = {Entry}\"\n        )]\n        private static partial void LogDebugUpdateIAmAlive(ILogger logger, MembershipEntry entry);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Messaging/Gateway.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.ClientObservers;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed partial class Gateway : IConnectedClientCollection\n    {\n        // clients is the main authorative collection of all connected clients.\n        // Any client currently in the system appears in this collection.\n        // In addition, we use clientConnections collection for fast retrival of ClientState.\n        // Anything that appears in those 2 collections should also appear in the main clients collection.\n        private readonly ConcurrentDictionary<ClientGrainId, ClientState> clients = new();\n        private readonly Dictionary<GatewayInboundConnection, ClientState> clientConnections = new();\n        private readonly SiloAddress gatewayAddress;\n        private readonly IAsyncTimer gatewayMaintenanceTimer;\n        private readonly Task gatewayMaintenanceTask;\n\n        private readonly ClientsReplyRoutingCache clientsReplyRoutingCache;\n        private readonly MessageCenter messageCenter;\n\n        private readonly ILogger logger;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly SiloMessagingOptions messagingOptions;\n        private long clientsCollectionVersion = 0;\n        private readonly TimeSpan clientDropTimeout;\n\n        public Gateway(\n            MessageCenter messageCenter,\n            ILocalSiloDetails siloDetails,\n            ILoggerFactory loggerFactory,\n            IOptions<SiloMessagingOptions> options,\n            IAsyncTimerFactory timerFactory)\n        {\n            this.messageCenter = messageCenter;\n            this.messagingOptions = options.Value;\n            this.loggerFactory = loggerFactory;\n            this.logger = this.loggerFactory.CreateLogger<Gateway>();\n            this.clientDropTimeout = messagingOptions.ClientDropTimeout;\n            clientsReplyRoutingCache = new ClientsReplyRoutingCache(messagingOptions.ResponseTimeout);\n            this.gatewayAddress = siloDetails.GatewayAddress;\n            this.gatewayMaintenanceTimer = timerFactory.Create(messagingOptions.ClientDropTimeout, nameof(PerformGatewayMaintenance));\n            this.gatewayMaintenanceTask = Task.Run(PerformGatewayMaintenance);\n        }\n\n        public static GrainAddress GetClientActivationAddress(GrainId clientId, SiloAddress siloAddress)\n        {\n            // Need to pick a unique deterministic ActivationId for this client.\n            // We store it in the grain directory and there for every GrainId we use ActivationId as a key\n            // so every GW needs to behave as a different \"activation\" with a different ActivationId (its not enough that they have different SiloAddress)\n\n            Span<byte> bytes = stackalloc byte[16];\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes, clientId.Type.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[4..], clientId.Key.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[8..], (uint)siloAddress.GetConsistentHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[12..], (uint)siloAddress.Generation);\n            var activationId = new ActivationId(new Guid(bytes));\n            return GrainAddress.GetAddress(siloAddress, clientId, activationId);\n        }\n\n        private async Task PerformGatewayMaintenance()\n        {\n            while (await gatewayMaintenanceTimer.NextTick())\n            {\n                try\n                {\n                    DropDisconnectedClients();\n                    DropExpiredRoutingCachedEntries();\n                }\n                catch (Exception exception)\n                {\n                    LogErrorGatewayMaintenanceError(logger, exception);\n                }\n            }\n        }\n\n        internal async Task SendStopSendMessages(IInternalGrainFactory grainFactory, CancellationToken cancellationToken = default)\n        {\n            lock (clients)\n            {\n                foreach (var client in clients)\n                {\n                    if (client.Value.IsConnected)\n                    {\n                        var observer = ClientGatewayObserver.GetObserver(grainFactory, client.Key);\n                        observer.StopSendingToGateway(this.gatewayAddress);\n                    }\n                }\n            }\n\n            await Task.Delay(this.messagingOptions.ClientGatewayShutdownNotificationTimeout, cancellationToken);\n        }\n\n        internal async Task StopAsync()\n        {\n            gatewayMaintenanceTimer.Dispose();\n            await gatewayMaintenanceTask.ConfigureAwait(false);\n        }\n\n        long IConnectedClientCollection.Version => Interlocked.Read(ref clientsCollectionVersion);\n\n        List<GrainId> IConnectedClientCollection.GetConnectedClientIds()\n        {\n            var result = new List<GrainId>();\n            foreach (var pair in clients)\n            {\n                result.Add(pair.Key.GrainId);\n            }\n\n            return result;\n        }\n\n        internal void RecordOpenedConnection(GatewayInboundConnection connection, ClientGrainId clientId)\n        {\n            LogInformationGatewayClientOpenedSocket(logger, connection.RemoteEndPoint, clientId);\n            lock (clients)\n            {\n                if (clients.TryGetValue(clientId, out var clientState))\n                {\n                    var oldSocket = clientState.Connection;\n                    if (oldSocket != null)\n                    {\n                        // The old socket will be closed by itself later.\n                        clientConnections.Remove(oldSocket);\n                    }\n                }\n                else\n                {\n                    clientState = new ClientState(this, clientId);\n                    clients[clientId] = clientState;\n                    MessagingInstruments.ConnectedClient.Add(1);\n                }\n                clientState.RecordConnection(connection);\n                clientConnections[connection] = clientState;\n                clientsCollectionVersion++;\n            }\n        }\n\n        internal void RecordClosedConnection(GatewayInboundConnection connection)\n        {\n            if (connection == null) return;\n\n            ClientState clientState;\n            lock (clients)\n            {\n                if (!clientConnections.Remove(connection, out clientState)) return;\n\n                clientState.RecordDisconnection();\n                clientsCollectionVersion++;\n            }\n\n            LogInformationGatewayClientClosedSocket(logger, connection.RemoteEndPoint?.ToString() ?? \"null\", clientState.Id);\n        }\n\n        internal SiloAddress TryToReroute(Message msg)\n        {\n            // ** Special routing rule for system target here **\n            // When a client make a request/response to/from a SystemTarget, the TargetSilo can be set to either\n            //  - the GatewayAddress of the target silo (for example, when the client want get the cluster typemap)\n            //  - the \"internal\" Silo-to-Silo address, if the client want to send a message to a specific SystemTarget\n            //    activation that is on a silo on which there is no gateway available (or if the client is not\n            //    connected to that gateway)\n            // So, if the TargetGrain is a SystemTarget we always trust the value from Message.TargetSilo and forward\n            // it to this address...\n            // EXCEPT if the value is equal to the current GatewayAddress: in this case we will return\n            // null and the local dispatcher will forward the Message to a local SystemTarget activation\n            if (msg.TargetGrain.IsSystemTarget() && !IsTargetingLocalGateway(msg.TargetSilo))\n            {\n                return msg.TargetSilo;\n            }\n\n            // for responses from ClientAddressableObject to ClientGrain try to use clientsReplyRoutingCache for sending replies directly back.\n            if (!msg.SendingGrain.IsClient() || !msg.TargetGrain.IsClient())\n            {\n                return null;\n            }\n\n            if (msg.Direction != Message.Directions.Response)\n            {\n                return null;\n            }\n\n            if (clientsReplyRoutingCache.TryFindClientRoute(msg.TargetGrain, out var gateway))\n            {\n                return gateway;\n            }\n\n            return null;\n        }\n\n        internal void DropExpiredRoutingCachedEntries()\n        {\n            lock (clients)\n            {\n                clientsReplyRoutingCache.DropExpiredEntries();\n            }\n        }\n\n        private bool IsTargetingLocalGateway(SiloAddress siloAddress)\n        {\n            // Special case if the address used by the client was loopback\n            return this.gatewayAddress.Matches(siloAddress)\n                || (IPAddress.IsLoopback(siloAddress.Endpoint.Address)\n                    && siloAddress.Endpoint.Port == this.gatewayAddress.Endpoint.Port\n                    && siloAddress.Generation == this.gatewayAddress.Generation);\n        }\n\n        // There is NO need to acquire individual ClientState lock, since we only close an older socket.\n        internal void DropDisconnectedClients()\n        {\n            foreach (var kv in clients)\n            {\n                if (kv.Value.ReadyToDrop())\n                {\n                    lock (clients)\n                    {\n                        if (clients.TryGetValue(kv.Key, out var client) && client.ReadyToDrop())\n                        {\n                            LogInformationGatewayDroppingClient(logger, kv.Key, client.DisconnectedSince);\n\n                            if (clients.TryRemove(kv.Key, out _))\n                            {\n                                // Reject all pending messages from the client.\n                                client.Drop();\n                            }\n\n                            clientsCollectionVersion++;\n                            MessagingInstruments.ConnectedClient.Add(-1);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// See if this message is intended for a grain we're proxying, and queue it for delivery if so.\n        /// </summary>\n        /// <param name=\"msg\"></param>\n        /// <returns>true if the message should be delivered to a proxied grain, false if not.</returns>\n        internal bool TryDeliverToProxy(Message msg)\n        {\n            // See if it's a grain we're proxying.\n            var targetGrain = msg.TargetGrain;\n            if (!ClientGrainId.TryParse(targetGrain, out var clientId))\n            {\n                return false;\n            }\n\n            if (!clients.TryGetValue(clientId, out var client))\n            {\n                return false;\n            }\n\n            // when this Gateway receives a message from client X to client addressable object Y\n            // it needs to record the original Gateway address through which this message came from (the address of the Gateway that X is connected to)\n            // it will use this Gateway to re-route the REPLY from Y back to X.\n            if (msg.SendingGrain.IsClient())\n            {\n                clientsReplyRoutingCache.RecordClientRoute(msg.SendingGrain, msg.SendingSilo);\n            }\n\n            msg.TargetSilo = null;\n            msg.SendingSilo ??= gatewayAddress;\n\n            client.Send(msg);\n            return true;\n        }\n\n        private class ClientState\n        {\n            private readonly Gateway _gateway;\n            private readonly Task _messageLoop;\n            private readonly ConcurrentQueue<Message> _pendingToSend = new();\n            private readonly SingleWaiterAutoResetEvent _signal = new()\n            {\n                RunContinuationsAsynchronously = true\n            };\n\n            private GatewayInboundConnection _connection;\n            private int _dropped;\n            private CoarseStopwatch _disconnectedSince;\n\n            internal ClientState(Gateway gateway, ClientGrainId id)\n            {\n                // Ensure that the client does not capture any AsyncLocal state, etc\n                using var suppressExecutionContext = new ExecutionContextSuppressor();\n\n                _gateway = gateway;\n                Id = id;\n                _disconnectedSince.Restart();\n                _messageLoop = Task.Run(RunMessageLoop);\n            }\n\n            public bool IsConnected => Connection != null;\n\n            private bool IsDropped => Volatile.Read(ref _dropped) == 1;\n\n            public GatewayInboundConnection Connection => _connection;\n\n            public TimeSpan DisconnectedSince => _disconnectedSince.Elapsed;\n\n            public ClientGrainId Id { get; }\n\n            public void RecordDisconnection()\n            {\n                var connection = Interlocked.Exchange(ref _connection, null);\n                if (connection is null)\n                {\n                    return;\n                }\n\n                _disconnectedSince.Restart();\n                _signal.Signal();\n            }\n\n            public void RecordConnection(GatewayInboundConnection connection)\n            {\n                var existing = Interlocked.Exchange(ref _connection, connection);\n                if (existing is not null)\n                {\n                    LogWarningGatewayClientReceivedNewConnectionBeforePreviousConnectionRemoved(_gateway.logger, Id, connection, existing);\n                }\n\n                _disconnectedSince.Reset();\n                _signal.Signal();\n            }\n\n            public bool ReadyToDrop()\n            {\n                if (IsConnected) return false;\n                if (_disconnectedSince.Elapsed < _gateway.clientDropTimeout)\n                {\n                    return false;\n                }\n\n                return true;\n            }\n\n            public void Drop()\n            {\n                Interlocked.Exchange(ref _dropped, 1);\n                RejectDroppedClientMessages();\n                _signal.Signal();\n            }\n\n            public void Send(Message msg)\n            {\n                _pendingToSend.Enqueue(msg);\n                _signal.Signal();\n                LogTraceQueuedMessage(_gateway.logger, msg, msg.TargetGrain);\n            }\n\n            private async Task RunMessageLoop()\n            {\n                while (true)\n                {\n                    try\n                    {\n                        await _signal.WaitAsync();\n\n                        if (IsDropped)\n                        {\n                            RejectDroppedClientMessages();\n                            continue;\n                        }\n\n                        var connection = Volatile.Read(ref _connection);\n                        if (connection is null)\n                        {\n                            continue;\n                        }\n\n                        // Send all pending messages.\n                        while (_pendingToSend.TryDequeue(out var message))\n                        {\n                            if (TrySend(connection, message))\n                            {\n                                LogTraceSentQueuedMessage(_gateway.logger, message, Id);\n                            }\n                            else\n                            {\n                                // Re-enqueue the message. It's ok that it is at the end of the queue: message ordering is not guaranteed.\n                                _pendingToSend.Enqueue(message);\n                                return;\n                            }\n                        }\n                    }\n                    catch (Exception exception)\n                    {\n                        LogWarningGatewayClientMessageLoopException(_gateway.logger, exception, Id);\n                    }\n                }\n            }\n\n            private void RejectDroppedClientMessages()\n            {\n                ClientNotAvailableException exception = null;\n                while (_pendingToSend.TryDequeue(out var message))\n                {\n                    exception ??= new ClientNotAvailableException(Id.GrainId);\n                    _gateway.messageCenter.RejectMessage(message, Message.RejectionTypes.Transient, exc: exception, rejectInfo: \"Client dropped\");\n                }\n            }\n\n            private bool TrySend(GatewayInboundConnection connection, Message message)\n            {\n                if (connection is null)\n                {\n                    return false;\n                }\n\n                try\n                {\n                    connection.Send(message);\n                    GatewayInstruments.GatewaySent.Add(1);\n                    return true;\n                }\n                catch (Exception exception)\n                {\n                    _gateway.RecordClosedConnection(connection);\n                    connection.CloseAsync(new ConnectionAbortedException(\"Exception posting a message to sender. See InnerException for details.\", exception)).Ignore();\n                    return false;\n                }\n            }\n        }\n\n        // this cache is used to record the addresses of Gateways from which clients connected to.\n        // it is used to route replies to clients from client addressable objects\n        // without this cache this Gateway will not know how to route the reply back to the client\n        // (since clients are not registered in the directory and this Gateway may not be proxying for the client for whom the reply is destined).\n        private class ClientsReplyRoutingCache\n        {\n            // for every client: the Gateway to use to route replies back to it plus the last time that client connected via this Gateway.\n            private readonly ConcurrentDictionary<GrainId, Tuple<SiloAddress, DateTime>> clientRoutes = new();\n            private readonly TimeSpan TIME_BEFORE_ROUTE_CACHED_ENTRY_EXPIRES;\n\n            internal ClientsReplyRoutingCache(TimeSpan responseTimeout)\n            {\n                TIME_BEFORE_ROUTE_CACHED_ENTRY_EXPIRES = responseTimeout.Multiply(5);\n            }\n\n            internal void RecordClientRoute(GrainId client, SiloAddress gateway)\n            {\n                clientRoutes[client] = new(gateway, DateTime.UtcNow);\n            }\n\n            internal bool TryFindClientRoute(GrainId client, out SiloAddress gateway)\n            {\n                if (clientRoutes.TryGetValue(client, out var tuple))\n                {\n                    gateway = tuple.Item1;\n                    return true;\n                }\n\n                gateway = null;\n                return false;\n            }\n\n            internal void DropExpiredEntries()\n            {\n                var expiredTime = DateTime.UtcNow - TIME_BEFORE_ROUTE_CACHED_ENTRY_EXPIRES;\n                foreach (var client in clientRoutes)\n                {\n                    if (client.Value.Item2 < expiredTime)\n                    {\n                        clientRoutes.TryRemove(client.Key, out _);\n                    }\n                }\n            }\n        }\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error performing gateway maintenance\"\n        )]\n        private static partial void LogErrorGatewayMaintenanceError(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayClientOpenedSocket,\n            Level = LogLevel.Information,\n            Message = \"Recorded opened connection from endpoint {EndPoint}, client ID {ClientId}.\"\n        )]\n        private static partial void LogInformationGatewayClientOpenedSocket(ILogger logger, EndPoint endPoint, ClientGrainId clientId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayClientClosedSocket,\n            Level = LogLevel.Information,\n            Message = \"Recorded closed socket from endpoint {Endpoint}, client ID {ClientId}.\"\n        )]\n        private static partial void LogInformationGatewayClientClosedSocket(ILogger logger, string endpoint, ClientGrainId clientId);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.GatewayDroppingClient,\n            Level = LogLevel.Information,\n            Message = \"Dropping client {ClientId}, {IdleDuration} after disconnect with no reconnect\"\n        )]\n        private static partial void LogInformationGatewayDroppingClient(ILogger logger, ClientGrainId clientId, TimeSpan idleDuration);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Client {ClientId} received new connection ({NewConnection}) before the previous connection ({PreviousConnection}) had been removed\"\n        )]\n        private static partial void LogWarningGatewayClientReceivedNewConnectionBeforePreviousConnectionRemoved(ILogger logger, ClientGrainId clientId, GatewayInboundConnection newConnection, GatewayInboundConnection previousConnection);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Queued message {Message} for client {TargetGrain}\"\n        )]\n        private static partial void LogTraceQueuedMessage(ILogger logger, object message, GrainId targetGrain);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Sent queued message {Message} to client {ClientId}\"\n        )]\n        private static partial void LogTraceSentQueuedMessage(ILogger logger, object message, ClientGrainId clientId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception in message loop for client {ClientId}\"\n        )]\n        private static partial void LogWarningGatewayClientMessageLoopException(ILogger logger, Exception exception, ClientGrainId clientId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Messaging/IConnectedClientCollection.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents the collection of clients which are currently connected to this gateway.\n    /// </summary>\n    internal interface IConnectedClientCollection\n    {\n        /// <summary>\n        /// The monotonically increasing version of the collection, which can be used for change notification.\n        /// </summary>\n        long Version { get; }\n\n        /// <summary>\n        /// Gets the collection of ids for the connected clients.\n        /// </summary>\n        List<GrainId> GetConnectedClientIds();\n    }\n\n    internal sealed class EmptyConnectedClientCollection : IConnectedClientCollection\n    {\n        public long Version => 0;\n\n        public List<GrainId> GetConnectedClientIds() => new List<GrainId>(0);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Messaging/MessageCenter.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal partial class MessageCenter : IMessageCenter, IAsyncDisposable\n    {\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly MessageFactory messageFactory;\n        private readonly ConnectionManager connectionManager;\n        private readonly RuntimeMessagingTrace messagingTrace;\n        private readonly SiloAddress _siloAddress;\n        private readonly SiloMessagingOptions messagingOptions;\n        private readonly PlacementService placementService;\n        private readonly GrainLocator _grainLocator;\n        private readonly Action<Message>? _messageObserver;\n        private readonly ILogger log;\n        private readonly Catalog catalog;\n        private bool stopped;\n        private HostedClient? hostedClient;\n        private Action<Message>? sniffIncomingMessageHandler;\n\n        public MessageCenter(\n            ILocalSiloDetails siloDetails,\n            MessageFactory messageFactory,\n            Catalog catalog,\n            Factory<MessageCenter, Gateway> gatewayFactory,\n            ILogger<MessageCenter> logger,\n            ISiloStatusOracle siloStatusOracle,\n            ConnectionManager senderManager,\n            RuntimeMessagingTrace messagingTrace,\n            IOptions<SiloMessagingOptions> messagingOptions,\n            PlacementService placementService,\n            GrainLocator grainLocator,\n            IMessageStatisticsSink messageStatisticsSink)\n        {\n            this.catalog = catalog;\n            this.messagingOptions = messagingOptions.Value;\n            this.siloStatusOracle = siloStatusOracle;\n            this.connectionManager = senderManager;\n            this.messagingTrace = messagingTrace;\n            this.placementService = placementService;\n            _grainLocator = grainLocator;\n            _messageObserver = messageStatisticsSink.GetMessageObserver();\n            this.log = logger;\n            this.messageFactory = messageFactory;\n            this._siloAddress = siloDetails.SiloAddress;\n\n            if (siloDetails.GatewayAddress != null)\n            {\n                Gateway = gatewayFactory(this);\n            }\n        }\n\n        public Gateway? Gateway { get; }\n\n        internal bool IsBlockingApplicationMessages { get; private set; }\n\n        public void SetHostedClient(HostedClient? client) => this.hostedClient = client;\n\n        public bool TryDeliverToProxy(Message msg)\n        {\n            if (!msg.TargetGrain.IsClient()) return false;\n            if (this.Gateway is Gateway gateway && gateway.TryDeliverToProxy(msg)\n                || this.hostedClient is HostedClient client && client.TryDispatchToClient(msg))\n            {\n                _messageObserver?.Invoke(msg);\n                return true;\n            }\n\n            return false;\n        }\n\n        public async Task StopAsync()\n        {\n            BlockApplicationMessages();\n            await StopAcceptingClientMessages();\n            stopped = true;\n        }\n\n        /// <summary>\n        /// Indicates that application messages should be blocked from being sent or received.\n        /// This method is used by the \"fast stop\" process.\n        /// <para>\n        /// Specifically, all outbound application messages are dropped, except for rejections and messages to the membership table grain.\n        /// Inbound application requests are rejected, and other inbound application messages are dropped.\n        /// </para>\n        /// </summary>\n        public void BlockApplicationMessages()\n        {\n            LogDebugBlockApplicationMessages(log);\n            IsBlockingApplicationMessages = true;\n        }\n\n        public async Task StopAcceptingClientMessages()\n        {\n            LogDebugStopClientMessages(log);\n\n            try\n            {\n                if (Gateway is { } gateway)\n                {\n                    await gateway.StopAsync();\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorStopFailed(log, exc);\n            }\n        }\n\n        public Action<Message>? SniffIncomingMessage\n        {\n            set\n            {\n                if (this.sniffIncomingMessageHandler != null)\n                {\n                    throw new InvalidOperationException(\"MessageCenter.SniffIncomingMessage already set\");\n                }\n\n                this.sniffIncomingMessageHandler = value;\n            }\n\n            get => this.sniffIncomingMessageHandler;\n        }\n\n        public void SendMessage(Message msg)\n        {\n            Debug.Assert(!msg.IsLocalOnly);\n\n            // Note that if we identify or add other grains that are required for proper stopping, we will need to treat them as we do the membership table grain here.\n            if (IsBlockingApplicationMessages && !msg.IsSystemMessage && msg.Result is not Message.ResponseTypes.Rejection && !Constants.SystemMembershipTableType.Equals(msg.TargetGrain))\n            {\n                // Drop the message on the floor if it's an application message that isn't a rejection\n                this.messagingTrace.OnDropBlockedApplicationMessage(msg);\n            }\n            else\n            {\n                msg.SendingSilo ??= _siloAddress;\n\n                if (stopped)\n                {\n                    LogInformationMessageQueuedAfterStop(log, msg);\n                    SendRejection(msg, Message.RejectionTypes.Unrecoverable, \"Message was queued for sending after outbound queue was stopped\");\n                    return;\n                }\n\n                // Don't process messages that have already timed out\n                if (msg.IsExpired)\n                {\n                    this.messagingTrace.OnDropExpiredMessage(msg, MessagingInstruments.Phase.Send);\n                    return;\n                }\n\n                // First check to see if it's really destined for a proxied client, instead of a local grain.\n                if (TryDeliverToProxy(msg))\n                {\n                    // Message was successfully delivered to the proxy.\n                    return;\n                }\n\n                if (msg.TargetSilo is not { } targetSilo)\n                {\n                    LogErrorMessageNoTargetSilo(log, msg, new());\n                    SendRejection(msg, Message.RejectionTypes.Unrecoverable, \"Message to be sent does not have a target silo.\");\n                    return;\n                }\n\n                messagingTrace.OnSendMessage(msg);\n\n                if (targetSilo.Matches(_siloAddress))\n                {\n                    LogTraceMessageLoopedBack(log, msg);\n\n                    MessagingInstruments.LocalMessagesSentCounterAggregator.Add(1);\n\n                    this.ReceiveMessage(msg);\n                }\n                else\n                {\n                    if (this.connectionManager.TryGetConnection(targetSilo, out var existingConnection))\n                    {\n                        existingConnection.Send(msg);\n                        return;\n                    }\n                    else if (this.siloStatusOracle.IsDeadSilo(targetSilo))\n                    {\n                        // Do not try to establish\n                        if (msg.Direction is Message.Directions.Request or Message.Directions.OneWay)\n                        {\n                            this.messagingTrace.OnRejectSendMessageToDeadSilo(_siloAddress, msg);\n                            this.SendRejection(msg, Message.RejectionTypes.Transient, \"Target silo is known to be dead\", new SiloUnavailableException());\n                        }\n\n                        return;\n                    }\n                    else\n                    {\n                        var connectionTask = this.connectionManager.GetConnection(targetSilo);\n                        if (connectionTask.IsCompletedSuccessfully)\n                        {\n                            var sender = connectionTask.Result;\n                            sender.Send(msg);\n                        }\n                        else\n                        {\n                            _ = SendAsync(this, connectionTask, msg);\n\n                            static async Task SendAsync(MessageCenter messageCenter, ValueTask<Connection> connectionTask, Message msg)\n                            {\n                                try\n                                {\n                                    var sender = await connectionTask;\n                                    sender.Send(msg);\n                                }\n                                catch (Exception exception)\n                                {\n                                    messageCenter.SendRejection(msg, Message.RejectionTypes.Transient, $\"Exception while sending message: {exception}\");\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        public void DispatchLocalMessage(Message message) => ReceiveMessage(message);\n\n        public void RejectMessage(\n            Message message,\n            Message.RejectionTypes rejectionType,\n            Exception? exc,\n            string? rejectInfo = null)\n        {\n            if (message.Direction == Message.Directions.Request\n                || (message.Direction == Message.Directions.OneWay && message.HasCacheInvalidationHeader))\n            {\n                this.messagingTrace.OnDispatcherRejectMessage(message, rejectionType, rejectInfo, exc);\n\n                var str = $\"{rejectInfo} {exc}\";\n                var rejection = this.messageFactory.CreateRejectionResponse(message, rejectionType, str, exc);\n                SendMessage(rejection);\n            }\n            else\n            {\n                this.messagingTrace.OnDispatcherDiscardedRejection(message, rejectionType, rejectInfo, exc);\n            }\n        }\n\n        internal void ProcessRequestsToInvalidActivation(\n            List<Message> messages,\n            GrainAddress? oldAddress,\n            SiloAddress? forwardingAddress,\n            string? failedOperation = null,\n            Exception? exc = null,\n            bool rejectMessages = false)\n        {\n            if (rejectMessages)\n            {\n                GrainAddress? validAddress = forwardingAddress switch\n                {\n                    null => null,\n                    _ => new()\n                    {\n                        GrainId = oldAddress?.GrainId ?? default,\n                        SiloAddress = forwardingAddress,\n                    }\n                };\n\n                foreach (var message in messages)\n                {\n                    Debug.Assert(!message.IsLocalOnly);\n\n                    if (oldAddress != null)\n                    {\n                        message.AddToCacheInvalidationHeader(oldAddress, validAddress: validAddress);\n                    }\n\n                    RejectMessage(message, Message.RejectionTypes.Transient, exc, failedOperation);\n                }\n            }\n            else\n            {\n                this.messagingTrace.OnDispatcherForwardingMultiple(messages.Count, oldAddress, forwardingAddress, failedOperation, exc);\n                GrainAddress? destination = forwardingAddress switch\n                {\n                    null => null,\n                    _ => new()\n                    {\n                        GrainId = oldAddress?.GrainId ?? default,\n                        SiloAddress = forwardingAddress,\n                    }\n                };\n\n                foreach (var message in messages)\n                {\n                    TryForwardRequest(message, oldAddress, destination, failedOperation, exc);\n                }\n            }\n        }\n\n        private void ProcessRequestToInvalidActivation(\n            Message message,\n            GrainAddress? oldAddress,\n            SiloAddress? forwardingAddress,\n            string failedOperation,\n            Exception? exc = null,\n            bool rejectMessages = false)\n        {\n            Debug.Assert(!message.IsLocalOnly);\n\n            // Just use this opportunity to invalidate local Cache Entry as well.\n            if (oldAddress != null)\n            {\n                _grainLocator.InvalidateCache(oldAddress);\n            }\n\n            // IMPORTANT: do not do anything on activation context anymore, since this activation is invalid already.\n            if (rejectMessages)\n            {\n                this.RejectMessage(message, Message.RejectionTypes.Transient, exc, failedOperation);\n            }\n            else\n            {\n                GrainAddress? destination = forwardingAddress switch\n                {\n                    null => null,\n                    _ => new()\n                    {\n                        GrainId = oldAddress?.GrainId ?? default,\n                        SiloAddress = forwardingAddress,\n                    }\n                };\n                this.TryForwardRequest(message, oldAddress, destination, failedOperation, exc);\n            }\n        }\n\n        private void TryForwardRequest(Message message, GrainAddress? oldAddress, GrainAddress? destination, string? failedOperation = null, Exception? exc = null)\n        {\n            Debug.Assert(!message.IsLocalOnly);\n\n            bool forwardingSucceeded = false;\n            var forwardingAddress = destination?.SiloAddress;\n            try\n            {\n                this.messagingTrace.OnDispatcherForwarding(message, oldAddress, forwardingAddress, failedOperation, exc);\n\n                if (oldAddress != null)\n                {\n                    message.AddToCacheInvalidationHeader(oldAddress, validAddress: destination);\n                }\n\n                LogDebugForwarding(log, exc, message, forwardingAddress, failedOperation);\n                forwardingSucceeded = this.TryForwardMessage(message, forwardingAddress);\n            }\n            catch (Exception exc2)\n            {\n                forwardingSucceeded = false;\n                exc = exc2;\n            }\n            finally\n            {\n                var sentRejection = false;\n\n                // If the message was a one-way message, send a cache invalidation response even if the message was successfully forwarded.\n                if (message.Direction == Message.Directions.OneWay)\n                {\n                    this.RejectMessage(\n                        message,\n                        Message.RejectionTypes.CacheInvalidation,\n                        exc,\n                        \"OneWay message sent to invalid activation\");\n                    sentRejection = true;\n                }\n\n                if (!forwardingSucceeded)\n                {\n                    this.messagingTrace.OnDispatcherForwardingFailed(message, oldAddress, forwardingAddress, failedOperation, exc);\n                    if (!sentRejection)\n                    {\n                        var str = $\"Forwarding failed: tried to forward message {message} for {message.ForwardCount} times after \\\"{failedOperation}\\\" to invalid activation. Rejecting now.\";\n                        RejectMessage(message, Message.RejectionTypes.Transient, exc, str);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Reroute a message coming in through a gateway\n        /// </summary>\n        /// <param name=\"message\"></param>\n        internal void RerouteMessage(Message message)\n        {\n            ResendMessageImpl(message);\n        }\n\n        private bool TryForwardMessage(Message message, SiloAddress? forwardingAddress)\n        {\n            if (!MayForward(message, this.messagingOptions)) return false;\n\n            message.ForwardCount = message.ForwardCount + 1;\n            MessagingProcessingInstruments.OnDispatcherMessageForwared(message);\n\n            ResendMessageImpl(message, forwardingAddress);\n            return true;\n        }\n\n        private void ResendMessageImpl(Message message, SiloAddress? forwardingAddress = null)\n        {\n            LogDebugResend(log, message);\n\n            if (message.TargetGrain.IsSystemTarget())\n            {\n                message.IsSystemMessage = true;\n                SendMessage(message);\n            }\n            else if (forwardingAddress != null)\n            {\n                message.TargetSilo = forwardingAddress;\n                SendMessage(message);\n            }\n            else\n            {\n                message.TargetSilo = null;\n                _ = AddressAndSendMessage(message);\n            }\n        }\n\n        // Forwarding is used by the receiver, usually when it cannot process the message and forwards it to another silo to perform the processing\n        // (got here due to duplicate activation, outdated cache, silo is shutting down/overloaded, ...).\n        private static bool MayForward(Message message, SiloMessagingOptions messagingOptions)\n        {\n            return message.ForwardCount < messagingOptions.MaxForwardCount;\n        }\n\n        /// <summary>\n        /// Send an outgoing message, may complete synchronously\n        /// - may buffer for transaction completion / commit if it ends a transaction\n        /// - choose target placement address, maintaining send order\n        /// - add ordering info and maintain send order\n        ///\n        /// </summary>\n        internal Task AddressAndSendMessage(Message message)\n        {\n            try\n            {\n                var messageAddressingTask = placementService.AddressMessage(message);\n                if (messageAddressingTask.Status != TaskStatus.RanToCompletion)\n                {\n                    return SendMessageAsync(messageAddressingTask, message);\n                }\n\n                SendMessage(message);\n            }\n            catch (Exception ex)\n            {\n                OnAddressingFailure(message, ex);\n            }\n\n            return Task.CompletedTask;\n\n            async Task SendMessageAsync(Task addressMessageTask, Message m)\n            {\n                try\n                {\n                    await addressMessageTask;\n                }\n                catch (Exception ex)\n                {\n                    OnAddressingFailure(m, ex);\n                    return;\n                }\n\n                SendMessage(m);\n            }\n\n            void OnAddressingFailure(Message m, Exception ex)\n            {\n                this.messagingTrace.OnDispatcherSelectTargetFailed(m, ex);\n                RejectMessage(m, Message.RejectionTypes.Unrecoverable, ex);\n            }\n        }\n\n        internal void SendResponse(Message request, Response response)\n        {\n            // create the response\n            var message = this.messageFactory.CreateResponseMessage(request);\n            message.BodyObject = response;\n\n            if (message.TargetGrain.IsSystemTarget())\n            {\n                message.IsSystemMessage = true;\n            }\n\n            SendMessage(message);\n        }\n\n        public void ReceiveMessage(Message msg)\n        {\n            Debug.Assert(!msg.IsLocalOnly);\n            try\n            {\n                this.messagingTrace.OnIncomingMessageAgentReceiveMessage(msg);\n                if (TryDeliverToProxy(msg))\n                {\n                    return;\n                }\n                else if (msg.Direction == Message.Directions.Response)\n                {\n                    this.catalog.RuntimeClient.ReceiveResponse(msg);\n                }\n                else\n                {\n                    var targetActivation = catalog.GetOrCreateActivation(\n                        msg.TargetGrain,\n                        msg.RequestContextData,\n                        rehydrationContext: null);\n\n                    if (targetActivation is null)\n                    {\n                        ProcessMessageToNonExistentActivation(msg);\n                        return;\n                    }\n\n                    targetActivation.ReceiveMessage(msg);\n                    _messageObserver?.Invoke(msg);\n                }\n            }\n            catch (Exception ex)\n            {\n                HandleReceiveFailure(msg, ex);\n            }\n\n            void HandleReceiveFailure(Message msg, Exception ex)\n            {\n                MessagingProcessingInstruments.OnDispatcherMessageProcessedError(msg);\n                LogErrorCreatingActivation(log, ex, msg.TargetGrain, msg.InterfaceType, msg);\n\n                this.RejectMessage(msg, Message.RejectionTypes.Transient, ex);\n            }\n        }\n\n        private void ProcessMessageToNonExistentActivation(Message msg)\n        {\n            var target = msg.TargetGrain;\n            if (target.IsSystemTarget())\n            {\n                MessagingInstruments.OnRejectedMessage(msg);\n                LogWarningUnknownSystemTarget(log, msg, msg.TargetGrain);\n\n                // Send a rejection only on a request\n                if (msg.Direction == Message.Directions.Request)\n                {\n                    var response = this.messageFactory.CreateRejectionResponse(\n                        msg,\n                        Message.RejectionTypes.Unrecoverable,\n                        $\"SystemTarget {msg.TargetGrain} not active on this silo. Msg={msg}\");\n\n                    SendMessage(response);\n                }\n            }\n            else\n            {\n                // Activation does not exists and is not a new placement.\n                LogDebugUnableToCreateActivation(log, msg);\n\n                var partialAddress = new GrainAddress { SiloAddress = msg.TargetSilo, GrainId = msg.TargetGrain };\n                ProcessRequestToInvalidActivation(msg, partialAddress, null, \"Unable to create local activation\");\n            }\n        }\n\n        internal void SendRejection(Message msg, Message.RejectionTypes rejectionType, string reason, Exception? exception = null)\n        {\n            MessagingInstruments.OnRejectedMessage(msg);\n\n            if (msg.Direction is Message.Directions.Response && msg.Result is Message.ResponseTypes.Rejection)\n            {\n                // Do not send reject a rejection locally, it will create a stack overflow\n                MessagingInstruments.OnDroppedSentMessage(msg);\n                LogDebugDroppingRejection(log, msg);\n            }\n            else\n            {\n                if (string.IsNullOrEmpty(reason)) reason = $\"Rejection from silo {this._siloAddress} - Unknown reason.\";\n                var error = this.messageFactory.CreateRejectionResponse(msg, rejectionType, reason, exception);\n                // rejection msgs are always originated in the local silo, they are never remote.\n                this.ReceiveMessage(error);\n            }\n        }\n\n        public async ValueTask DisposeAsync()\n        {\n            await StopAsync();\n        }\n\n        private readonly struct StackTraceLogValue()\n        {\n            public override string ToString() => Utils.GetStackTrace(1);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BlockApplicationMessages\"\n        )]\n        private static partial void LogDebugBlockApplicationMessages(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"StopClientMessages\"\n        )]\n        private static partial void LogDebugStopClientMessages(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100109,\n            Level = LogLevel.Error,\n            Message = \"Stop failed\"\n        )]\n        private static partial void LogErrorStopFailed(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100115,\n            Level = LogLevel.Information,\n            Message = \"Message was queued for sending after outbound queue was stopped: {Message}\"\n        )]\n        private static partial void LogInformationMessageQueuedAfterStop(ILogger logger, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Runtime_Error_100113,\n            Level = LogLevel.Error,\n            Message = \"Message does not have a target silo: '{Message}'. Call stack: {StackTrace}\"\n        )]\n        private static partial void LogErrorMessageNoTargetSilo(ILogger logger, Message message, StackTraceLogValue stackTrace);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Message has been looped back to this silo: {Message}\"\n        )]\n        private static partial void LogTraceMessageLoopedBack(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Forwarding {Message} to '{ForwardingAddress}' after '{FailedOperation}'\"\n        )]\n        private static partial void LogDebugForwarding(ILogger logger, Exception? exc, Message message, SiloAddress? forwardingAddress, string? failedOperation);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Resend {Message}\"\n        )]\n        private static partial void LogDebugResend(ILogger logger, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Dispatcher_ErrorCreatingActivation,\n            Level = LogLevel.Error,\n            Message = \"Error creating activation for grain {TargetGrain} (interface: {InterfaceType}). Message {Message}\"\n        )]\n        private static partial void LogErrorCreatingActivation(ILogger logger, Exception ex, GrainId targetGrain, GrainInterfaceType interfaceType, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MessagingMessageFromUnknownActivation,\n            Level = LogLevel.Warning,\n            Message = \"Received a message {Message} for an unknown SystemTarget: {Target}\"\n        )]\n        private static partial void LogWarningUnknownSystemTarget(ILogger logger, Message message, GrainId target);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Dispatcher_Intermediate_GetOrCreateActivation,\n            Level = LogLevel.Debug,\n            Message = \"Unable to create local activation for message {Message}.\"\n        )]\n        private static partial void LogDebugUnableToCreateActivation(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Dropping rejection {Message}\"\n        )]\n        private static partial void LogDebugDroppingRejection(ILogger logger, Message message);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Messaging/OverloadDetector.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Core.Messaging;\nusing Orleans.Statistics;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// Determines whether or not the process is overloaded.\n    /// </summary>\n    public interface IOverloadDetector\n    {\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if this process is overloaded, <see langword=\"false\"/> otherwise.\n        /// </summary>\n        bool IsOverloaded { get; }\n    }\n\n    /// <summary>\n    /// Determines whether or not the process is overloaded.\n    /// </summary>\n    internal class OverloadDetector : IOverloadDetector\n    {\n        private const int RefreshIntervalMilliseconds = 1_000;\n        private readonly IEnvironmentStatisticsProvider _environmentStatisticsProvider;\n        private readonly LoadSheddingOptions _options;\n        private CoarseStopwatch _refreshStopwatch;\n        private bool? _isOverloaded;\n\n        public OverloadDetector(IEnvironmentStatisticsProvider environmentStatisticsProvider, IOptions<LoadSheddingOptions> loadSheddingOptions)\n        {\n            _environmentStatisticsProvider = environmentStatisticsProvider;\n            _options = loadSheddingOptions.Value;\n\n            Enabled = _options.LoadSheddingEnabled;\n\n            _refreshStopwatch = CoarseStopwatch.StartNew();\n        }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether overload detection is enabled.\n        /// </summary>\n        public bool Enabled { get; set; }\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if this process is overloaded, <see langword=\"false\"/> otherwise.\n        /// </summary>\n        public bool IsOverloaded\n        {\n            get\n            {\n                if (!Enabled)\n                {\n                    return false;\n                }\n\n                if (!_isOverloaded.HasValue || _refreshStopwatch.ElapsedMilliseconds >= RefreshIntervalMilliseconds)\n                {\n                    var stats = _environmentStatisticsProvider.GetEnvironmentStatistics();\n                    _isOverloaded = OverloadDetectionLogic.IsOverloaded(ref stats, _options);\n                    _refreshStopwatch.Restart();\n                }\n\n                return _isOverloaded.Value;\n            }\n        }\n\n        // Exposed only for testing purposes\n        internal void ForceRefresh()\n        {\n            _isOverloaded = null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Messaging/RuntimeMessagingTrace.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal sealed class RuntimeMessagingTrace : MessagingTrace\n    {\n        public const string DispatcherReceiveInvalidActivationEventName = Category + \".Dispatcher.InvalidActivation\";\n        public const string DispatcherDetectedDeadlockEventName = Category + \".Dispatcher.DetectedDeadlock\";\n        public const string DispatcherDiscardedRejectionEventName = Category + \".Dispatcher.DiscardedRejection\";\n        public const string DispatcherRejectedMessageEventName = Category + \".Dispatcher.Rejected\";\n        public const string DispatcherForwardingEventName = Category + \".Dispatcher.Forwarding\";\n        public const string DispatcherForwardingMultipleEventName = Category + \".Dispatcher.ForwardingMultiple\";\n        public const string DispatcherForwardingFailedEventName = Category + \".Dispatcher.ForwardingFailed\";\n        public const string DispatcherSelectTargetFailedEventName = Category + \".Dispatcher.SelectTargetFailed\";\n\n        private static readonly Action<ILogger, ActivationState, Message, Exception> LogDispatcherReceiveInvalidActivation =\n            LoggerMessage.Define<ActivationState, Message>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Dispatcher_Receive_InvalidActivation, DispatcherReceiveInvalidActivationEventName),\n                \"Invalid activation in state {State} for message {Message}\");\n\n        private static readonly Action<ILogger, Message, ActivationData, Exception> LogDispatcherDetectedDeadlock =\n            LoggerMessage.Define<Message, ActivationData>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Dispatcher_DetectedDeadlock, DispatcherDetectedDeadlockEventName),\n                \"Detected application deadlock on message {Message} and activation {Activation}\");\n\n        private static readonly Action<ILogger, Message, string, Message.RejectionTypes, Exception> LogDispatcherDiscardedRejection =\n            LoggerMessage.Define<Message, string, Message.RejectionTypes>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Messaging_Dispatcher_DiscardRejection, DispatcherDiscardedRejectionEventName),\n                \"Discarding rejection of message {Message} with reason '{Reason}' ({RejectionType})\");\n\n        private static readonly Action<ILogger, Message, string, Message.RejectionTypes, Exception> LogDispatcherRejectedMessage =\n            LoggerMessage.Define<Message, string, Message.RejectionTypes>(\n                LogLevel.Debug,\n                new EventId((int)ErrorCode.Messaging_Dispatcher_Rejected, DispatcherRejectedMessageEventName),\n                \"Rejected message {Message} with reason '{Reason}' ({RejectionType})\");\n\n        private static readonly Action<ILogger, Message, GrainAddress, SiloAddress, string, int, Exception> LogDispatcherForwarding =\n            LoggerMessage.Define<Message, GrainAddress, SiloAddress, string, int>(\n                LogLevel.Debug,\n                new EventId((int)ErrorCode.Messaging_Dispatcher_TryForward, DispatcherForwardingEventName),\n                \"Trying to forward {Message} from {OldAddress} to {ForwardingAddress} after {FailedOperation}. Attempt {ForwardCount}\");\n\n        private static readonly Action<ILogger, Message, GrainAddress, SiloAddress, string, int, Exception> LogDispatcherForwardingFailed =\n            LoggerMessage.Define<Message, GrainAddress, SiloAddress, string, int>(\n                LogLevel.Warning,\n                new EventId((int)ErrorCode.Messaging_Dispatcher_TryForwardFailed, DispatcherForwardingFailedEventName),\n                \"Failed to forward message {Message} from {OldAddress} to {ForwardingAddress} after {FailedOperation}. Attempt {ForwardCount}\");\n\n        private static readonly Action<ILogger, int, GrainAddress, SiloAddress, string, Exception> LogDispatcherForwardingMultiple =\n            LoggerMessage.Define<int, GrainAddress, SiloAddress, string>(\n                LogLevel.Debug,\n                new EventId((int)ErrorCode.Messaging_Dispatcher_ForwardingRequests, DispatcherForwardingMultipleEventName),\n                \"Forwarding {MessageCount} requests destined for address {OldAddress} to address {ForwardingAddress} after {FailedOperation}\");\n\n        private static readonly Action<ILogger, Message, Exception> LogDispatcherSelectTargetFailed =\n            LoggerMessage.Define<Message>(\n                LogLevel.Error,\n                new EventId((int)ErrorCode.Dispatcher_SelectTarget_Failed, DispatcherSelectTargetFailedEventName),\n                \"Failed to address message {Message}\");\n\n        public RuntimeMessagingTrace(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        internal void OnDispatcherReceiveInvalidActivation(Message message, ActivationState activationState)\n        {\n            if (this.IsEnabled(DispatcherReceiveInvalidActivationEventName))\n            {\n                this.Write(DispatcherReceiveInvalidActivationEventName, new { Message = message, ActivationState = activationState });\n            }\n\n            MessagingProcessingInstruments.OnDispatcherMessageProcessedError(message);\n            LogDispatcherReceiveInvalidActivation(this, activationState, message, null);\n        }\n\n        internal void OnDispatcherDiscardedRejection(Message message, Message.RejectionTypes rejectionType, string reason, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherDiscardedRejectionEventName))\n            {\n                this.Write(DispatcherDiscardedRejectionEventName, new { Message = message, RejectionType = rejectionType, Reason = reason, Exception = exception });\n            }\n\n            LogDispatcherDiscardedRejection(this, message, reason, rejectionType, exception);\n        }\n\n        internal void OnDispatcherRejectMessage(Message message, Message.RejectionTypes rejectionType, string reason, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherRejectedMessageEventName))\n            {\n                this.Write(DispatcherRejectedMessageEventName, new { Message = message, RejectionType = rejectionType, Reason = reason, Exception = exception });\n            }\n\n            MessagingInstruments.OnRejectedMessage(message);\n\n            if (this.IsEnabled(LogLevel.Debug))\n            {\n                LogDispatcherRejectedMessage(this, message, reason, rejectionType, exception);\n            }\n        }\n\n        internal void OnDispatcherForwarding(Message message, GrainAddress oldAddress, SiloAddress forwardingAddress, string failedOperation, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherForwardingEventName))\n            {\n                this.Write(DispatcherForwardingEventName, new { Message = message, OldAddress = oldAddress, ForwardingAddress = forwardingAddress, FailedOperation = failedOperation, Exception = exception });\n            }\n\n            if (this.IsEnabled(LogLevel.Debug))\n            {\n                LogDispatcherForwarding(this, message, oldAddress, forwardingAddress, failedOperation, message.ForwardCount, exception);\n            }\n\n            MessagingProcessingInstruments.OnDispatcherMessageForwared(message);\n        }\n\n        internal void OnDispatcherForwardingFailed(Message message, GrainAddress oldAddress, SiloAddress forwardingAddress, string failedOperation, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherForwardingFailedEventName))\n            {\n                this.Write(DispatcherForwardingFailedEventName, new { Message = message, OldAddress = oldAddress, ForwardingAddress = forwardingAddress, FailedOperation = failedOperation, Exception = exception });\n            }\n\n            LogDispatcherForwardingFailed(this, message, oldAddress, forwardingAddress, failedOperation, message.ForwardCount, exception);\n        }\n\n        internal void OnDispatcherForwardingMultiple(int messageCount, GrainAddress oldAddress, SiloAddress forwardingAddress, string failedOperation, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherForwardingMultipleEventName))\n            {\n                this.Write(DispatcherForwardingMultipleEventName, new { MessageCount = messageCount, OldAddress = oldAddress, ForwardingAddress = forwardingAddress, FailedOperation = failedOperation, Exception = exception });\n            }\n\n            if (this.IsEnabled(LogLevel.Debug))\n            {\n                LogDispatcherForwardingMultiple(this, messageCount, oldAddress, forwardingAddress, failedOperation, exception);\n            }\n        }\n\n        internal void OnDispatcherSelectTargetFailed(Message message, Exception exception)\n        {\n            if (this.IsEnabled(DispatcherSelectTargetFailedEventName))\n            {\n                this.Write(DispatcherSelectTargetFailedEventName, new { Message = message, Exception = exception });\n            }\n\n            if (ShouldLogError(exception))\n            {\n                LogDispatcherSelectTargetFailed(this, message, exception);\n            }\n\n            MessagingProcessingInstruments.OnDispatcherMessageProcessedError(message);\n\n            static bool ShouldLogError(Exception ex)\n            {\n                return !(ex.GetBaseException() is KeyNotFoundException) &&\n                       !(ex.GetBaseException() is ClientNotAvailableException);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/ConnectionListener.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal abstract partial class ConnectionListener\n    {\n        private readonly IConnectionListenerFactory listenerFactory;\n        private readonly ConnectionManager connectionManager;\n        protected readonly ConcurrentDictionary<Connection, object> connections = new(ReferenceEqualsComparer.Default);\n        private readonly ConnectionCommon connectionShared;\n        private Task acceptLoopTask;\n        private IConnectionListener listener;\n        private ConnectionDelegate connectionDelegate;\n\n        protected ConnectionListener(\n            IConnectionListenerFactory listenerFactory,\n            IOptions<ConnectionOptions> connectionOptions,\n            ConnectionManager connectionManager,\n            ConnectionCommon connectionShared)\n        {\n            this.listenerFactory = listenerFactory;\n            this.connectionManager = connectionManager;\n            this.ConnectionOptions = connectionOptions.Value;\n            this.connectionShared = connectionShared;\n        }\n\n        public abstract EndPoint Endpoint { get; }\n\n        protected IServiceProvider ServiceProvider => this.connectionShared.ServiceProvider;\n\n        protected NetworkingTrace NetworkingTrace => this.connectionShared.NetworkingTrace;\n\n        protected ConnectionOptions ConnectionOptions { get; }\n\n        protected abstract Connection CreateConnection(ConnectionContext context);\n\n        protected ConnectionDelegate ConnectionDelegate\n        {\n            get\n            {\n                if (this.connectionDelegate != null) return this.connectionDelegate;\n\n                lock (this)\n                {\n                    if (this.connectionDelegate != null) return this.connectionDelegate;\n\n                    // Configure the connection builder using the user-defined options.\n                    var connectionBuilder = new ConnectionBuilder(this.ServiceProvider);\n                    connectionBuilder.Use(next =>\n                    {\n                        return context =>\n                        {\n                            context.Features.Set<IUnderlyingTransportFeature>(new UnderlyingConnectionTransportFeature { Transport = context.Transport });\n                            return next(context);\n                        };\n                    });\n                    this.ConfigureConnectionBuilder(connectionBuilder);\n                    Connection.ConfigureBuilder(connectionBuilder);\n                    return this.connectionDelegate = connectionBuilder.Build();\n                }\n            }\n        }\n\n        protected virtual void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder) { }\n\n        protected async Task BindAsync()\n        {\n            this.listener = await this.listenerFactory.BindAsync(this.Endpoint);\n        }\n\n        protected void Start()\n        {\n            if (this.listener is null) throw new InvalidOperationException(\"Listener is not bound\");\n            acceptLoopTask = RunAcceptLoop();\n        }\n\n        private async Task RunAcceptLoop()\n        {\n            await Task.Yield();\n            try\n            {\n                while (true)\n                {\n                    var context = await this.listener.AcceptAsync();\n                    if (context == null) break;\n\n                    var connection = this.CreateConnection(context);\n                    this.StartConnection(connection);\n                }\n            }\n            catch (Exception exception)\n            {\n                LogCriticalExceptionInAcceptAsync(this.NetworkingTrace, exception);\n            }\n        }\n\n        protected async Task StopAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                await listener.UnbindAsync(cancellationToken);\n\n                if (acceptLoopTask is not null)\n                {\n                    await acceptLoopTask;\n                }\n\n                var closeTasks = new List<Task>();\n                foreach (var kv in connections)\n                {\n                    closeTasks.Add(kv.Key.CloseAsync(exception: null));\n                }\n\n                if (closeTasks.Count > 0)\n                {\n                    await Task.WhenAll(closeTasks).WaitAsync(cancellationToken).SuppressThrowing();\n                }\n\n                await this.connectionManager.Closed;\n                await this.listener.DisposeAsync();\n            }\n            catch (Exception exception)\n            {\n                LogWarningExceptionDuringShutdown(this.NetworkingTrace, exception);\n            }\n        }\n\n        private void StartConnection(Connection connection)\n        {\n            connections.TryAdd(connection, null);\n\n            ThreadPool.UnsafeQueueUserWorkItem(state =>\n            {\n                var (t, connection) = ((ConnectionListener, Connection))state;\n                t.RunConnectionAsync(connection).Ignore();\n            }, (this, connection));\n        }\n\n        private async Task RunConnectionAsync(Connection connection)\n        {\n            using (this.BeginConnectionScope(connection))\n            {\n                try\n                {\n                    await connection.Run();\n                    LogInformationConnectionTerminated(this.NetworkingTrace, connection);\n                }\n                catch (Exception exception)\n                {\n                    LogInformationConnectionTerminatedWithException(this.NetworkingTrace, exception, connection);\n                }\n                finally\n                {\n                    this.connections.TryRemove(connection, out _);\n                }\n            }\n        }\n\n        private IDisposable BeginConnectionScope(Connection connection)\n        {\n            if (this.NetworkingTrace.IsEnabled(LogLevel.Critical))\n            {\n                return this.NetworkingTrace.BeginScope(new ConnectionLogScope(connection));\n            }\n\n            return null;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Critical,\n            Message = \"Exception in AcceptAsync\"\n        )]\n        private static partial void LogCriticalExceptionInAcceptAsync(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception during shutdown\"\n        )]\n        private static partial void LogWarningExceptionDuringShutdown(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Connection {Connection} terminated\"\n        )]\n        private static partial void LogInformationConnectionTerminated(ILogger logger, Connection connection);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Connection {Connection} terminated with an exception\"\n        )]\n        private static partial void LogInformationConnectionTerminatedWithException(ILogger logger, Exception exception, Connection connection);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Networking/GatewayConnectionListener.cs",
    "content": "using System;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class GatewayConnectionListener : ConnectionListener, ILifecycleParticipant<ISiloLifecycle>, ILifecycleObserver\n    {\n        internal static readonly object ServicesKey = new object();\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly MessageCenter messageCenter;\n        private readonly ConnectionCommon connectionShared;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n        private readonly ILogger<GatewayConnectionListener> logger;\n        private readonly EndpointOptions endpointOptions;\n        private readonly SiloConnectionOptions siloConnectionOptions;\n        private readonly OverloadDetector overloadDetector;\n        private readonly Gateway gateway;\n\n        public GatewayConnectionListener(\n            IServiceProvider serviceProvider,\n            IOptions<ConnectionOptions> connectionOptions,\n            IOptions<SiloConnectionOptions> siloConnectionOptions,\n            OverloadDetector overloadDetector,\n            ILocalSiloDetails localSiloDetails,\n            IOptions<EndpointOptions> endpointOptions,\n            MessageCenter messageCenter,\n            ConnectionManager connectionManager,\n            ConnectionCommon connectionShared,\n            ConnectionPreambleHelper connectionPreambleHelper,\n            ILogger<GatewayConnectionListener> logger)\n            : base(serviceProvider.GetRequiredKeyedService<IConnectionListenerFactory>(ServicesKey), connectionOptions, connectionManager, connectionShared)\n        {\n            this.siloConnectionOptions = siloConnectionOptions.Value;\n            this.overloadDetector = overloadDetector;\n            this.gateway = messageCenter.Gateway;\n            this.localSiloDetails = localSiloDetails;\n            this.messageCenter = messageCenter;\n            this.connectionShared = connectionShared;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n            this.logger = logger;\n            this.endpointOptions = endpointOptions.Value;\n        }\n\n        public override EndPoint Endpoint => this.endpointOptions.GetListeningProxyEndpoint();\n\n        protected override Connection CreateConnection(ConnectionContext context)\n        {\n            return new GatewayInboundConnection(\n                context,\n                this.ConnectionDelegate,\n                this.gateway,\n                this.overloadDetector,\n                this.localSiloDetails,\n                this.ConnectionOptions,\n                this.messageCenter,\n                this.connectionShared,\n                this.connectionPreambleHelper);\n        }\n\n        protected override void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder)\n        {\n            var configureDelegate = (SiloConnectionOptions.ISiloConnectionBuilderOptions)this.siloConnectionOptions;\n            configureDelegate.ConfigureGatewayInboundBuilder(connectionBuilder);\n            base.ConfigureConnectionBuilder(connectionBuilder);\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            if (this.Endpoint is null) return;\n\n            lifecycle.Subscribe(nameof(GatewayConnectionListener), ServiceLifecycleStage.RuntimeInitialize - 1, this);\n            lifecycle.Subscribe(nameof(GatewayConnectionListener), ServiceLifecycleStage.Active, _ => Task.Run(Start));\n        }\n\n        Task ILifecycleObserver.OnStart(CancellationToken ct) => Task.Run(BindAsync);\n        Task ILifecycleObserver.OnStop(CancellationToken ct) => Task.Run(() => StopAsync(ct));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/GatewayInboundConnection.cs",
    "content": "using System;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed partial class GatewayInboundConnection : Connection\n    {\n        private readonly MessageCenter messageCenter;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n        private readonly ConnectionOptions connectionOptions;\n        private readonly Gateway gateway;\n        private readonly OverloadDetector overloadDetector;\n        private readonly SiloAddress myAddress;\n        private readonly string myClusterId;\n\n        public GatewayInboundConnection(\n            ConnectionContext connection,\n            ConnectionDelegate middleware,\n            Gateway gateway,\n            OverloadDetector overloadDetector,\n            ILocalSiloDetails siloDetails,\n            ConnectionOptions connectionOptions,\n            MessageCenter messageCenter,\n            ConnectionCommon connectionShared,\n            ConnectionPreambleHelper connectionPreambleHelper)\n            : base(connection, middleware, connectionShared)\n        {\n            this.connectionOptions = connectionOptions;\n            this.gateway = gateway;\n            this.overloadDetector = overloadDetector;\n            this.messageCenter = messageCenter;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n            this.myAddress = siloDetails.SiloAddress;\n            this.myClusterId = siloDetails.ClusterId;\n        }\n\n        protected override ConnectionDirection ConnectionDirection => ConnectionDirection.GatewayToClient;\n\n        protected override IMessageCenter MessageCenter => this.messageCenter;\n\n        protected override void RecordMessageReceive(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageReceive(msg, numTotalBytes, headerBytes, ConnectionDirection);\n            GatewayInstruments.GatewayReceived.Add(1);\n        }\n\n        protected override void RecordMessageSend(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageSend(msg, numTotalBytes, headerBytes, ConnectionDirection);\n            GatewayInstruments.GatewaySent.Add(1);\n        }\n\n        protected override void OnReceivedMessage(Message msg)\n        {\n            // Don't process messages that have already timed out\n            if (msg.IsExpired)\n            {\n                this.MessagingTrace.OnDropExpiredMessage(msg, MessagingInstruments.Phase.Receive);\n                return;\n            }\n\n            // Are we overloaded?\n            if (this.overloadDetector.IsOverloaded)\n            {\n                MessagingInstruments.OnRejectedMessage(msg);\n                Message rejection = this.MessageFactory.CreateRejectionResponse(msg, Message.RejectionTypes.GatewayTooBusy, \"Shedding load\");\n                this.messageCenter.TryDeliverToProxy(rejection);\n                LogRejectingRequestDueToOverloading(this.Log, msg);\n                GatewayInstruments.GatewayLoadShedding.Add(1);\n                return;\n            }\n\n            SiloAddress targetAddress = this.gateway.TryToReroute(msg);\n            msg.SendingSilo = this.myAddress;\n            if (targetAddress is null)\n            {\n                // reroute via Dispatcher\n                msg.TargetSilo = null;\n\n                if (SystemTargetGrainId.TryParse(msg.TargetGrain, out var systemTargetId))\n                {\n                    msg.TargetSilo = this.myAddress;\n                    msg.TargetGrain = systemTargetId.WithSiloAddress(this.myAddress).GrainId;\n                }\n\n                MessagingInstruments.OnMessageReRoute(msg);\n                this.messageCenter.RerouteMessage(msg);\n            }\n            else\n            {\n                // send directly\n                msg.TargetSilo = targetAddress;\n\n                if (SystemTargetGrainId.TryParse(msg.TargetGrain, out var systemTargetId))\n                {\n                    msg.TargetGrain = systemTargetId.WithSiloAddress(targetAddress).GrainId;\n                }\n\n                this.messageCenter.SendMessage(msg);\n            }\n        }\n\n        protected override async Task RunInternal()\n        {\n            var preamble = await connectionPreambleHelper.Read(this.Context);\n\n            await connectionPreambleHelper.Write(\n                this.Context,\n                new ConnectionPreamble\n                {\n                    NodeIdentity = Constants.SiloDirectConnectionId,\n                    NetworkProtocolVersion = this.connectionOptions.ProtocolVersion,\n                    SiloAddress = this.myAddress,\n                    ClusterId = this.myClusterId\n                });\n\n            if (!ClientGrainId.TryParse(preamble.NodeIdentity, out var clientId))\n            {\n                throw new InvalidOperationException($\"Unexpected connection id {preamble.NodeIdentity} on proxy endpoint from {preamble.SiloAddress?.ToString() ?? \"unknown silo\"}\");\n            }\n\n            if (preamble.ClusterId != this.myClusterId)\n            {\n                throw new InvalidOperationException($@\"Unexpected cluster id \"\"{preamble.ClusterId}\"\", expected \"\"{this.myClusterId}\"\"\");\n            }\n\n            try\n            {\n                this.gateway.RecordOpenedConnection(this, clientId);\n                await base.RunInternal();\n            }\n            finally\n            {\n                this.gateway.RecordClosedConnection(this);\n            }\n        }\n\n        protected override bool PrepareMessageForSend(Message msg)\n        {\n            // Don't send messages that have already timed out\n            if (msg.IsExpired)\n            {\n                this.MessagingTrace.OnDropExpiredMessage(msg, MessagingInstruments.Phase.Send);\n                return false;\n            }\n\n            // Fill in the outbound message with our silo address, if it's not already set\n            msg.SendingSilo ??= this.myAddress;\n\n            return true;\n        }\n\n        public void FailMessage(Message msg, string reason)\n        {\n            MessagingInstruments.OnFailedSentMessage(msg);\n            if (msg.Direction == Message.Directions.Request)\n            {\n                LogSiloRejectingMessage(this.Log, this.myAddress, msg, reason);\n\n                // Done retrying, send back an error instead\n                this.messageCenter.SendRejection(\n                    msg,\n                    Message.RejectionTypes.Transient,\n                    $\"Silo {this.myAddress} is rejecting message: {msg}. Reason = {reason}\",\n                    new SiloUnavailableException());\n            }\n            else\n            {\n                LogSiloDroppingMessage(this.Log, this.myAddress, msg, reason);\n                MessagingInstruments.OnDroppedSentMessage(msg);\n            }\n        }\n\n        protected override void RetryMessage(Message msg, Exception ex = null)\n        {\n            if (msg == null) return;\n\n            if (msg.RetryCount < MessagingOptions.DEFAULT_MAX_MESSAGE_SEND_RETRIES)\n            {\n                msg.RetryCount++;\n                this.messageCenter.SendMessage(msg);\n            }\n            else\n            {\n                var reason = new StringBuilder(\"Retry count exceeded. \");\n                if (ex != null)\n                {\n                    reason.Append(\"Original exception is: \").Append(ex.ToString());\n                }\n\n                reason.Append(\"Msg is: \").Append(msg);\n                FailMessage(msg, reason.ToString());\n            }\n        }\n\n        protected override void OnSendMessageFailure(Message message, string error)\n        {\n            this.FailMessage(message, error);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Rejecting a request due to overloading: {Message}\"\n        )]\n        private static partial void LogRejectingRequestDueToOverloading(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.MessagingSendingRejection,\n            Message = \"Silo {SiloAddress} is rejecting message: {Message}. Reason = {Reason}\"\n        )]\n        private static partial void LogSiloRejectingMessage(ILogger logger, SiloAddress siloAddress, Message message, string reason);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.Messaging_OutgoingMS_DroppingMessage,\n            Message = \"Silo {SiloAddress} is dropping message: {Message}. Reason = {Reason}\"\n        )]\n        private static partial void LogSiloDroppingMessage(ILogger logger, SiloAddress siloAddress, Message message, string reason);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/ProbeRequestMonitor.cs",
    "content": "using System;\nusing System.Threading;\n\nnamespace Orleans.Runtime.Messaging\n{\n    /// <summary>\n    /// Monitors incoming cluster health probe requests\n    /// </summary>\n    internal sealed class ProbeRequestMonitor\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lock = new();\n#else\n        private readonly object _lock = new();\n#endif\n        private ValueStopwatch _probeRequestStopwatch;\n\n        /// <summary>\n        /// Called when this silo receives a health probe request.\n        /// </summary>\n        public void OnReceivedProbeRequest()\n        {\n            lock (_lock)\n            {\n                _probeRequestStopwatch.Restart();\n            }\n        }\n\n        /// <summary>\n        /// The duration which has elapsed since the most recently received health probe request.\n        /// </summary>\n        public TimeSpan? ElapsedSinceLastProbeRequest => _probeRequestStopwatch.IsRunning ? (Nullable<TimeSpan>)_probeRequestStopwatch.Elapsed : null;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/SiloConnection.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed partial class SiloConnection : Connection\n    {\n        private static readonly Response PingResponse = Response.Completed;\n        private readonly MessageCenter messageCenter;\n        private readonly ConnectionManager connectionManager;\n        private readonly ConnectionOptions connectionOptions;\n        private readonly ProbeRequestMonitor probeMonitor;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n\n        public SiloConnection(\n            SiloAddress remoteSiloAddress,\n            ConnectionContext connection,\n            ConnectionDelegate middleware,\n            MessageCenter messageCenter,\n            ILocalSiloDetails localSiloDetails,\n            ConnectionManager connectionManager,\n            ConnectionOptions connectionOptions,\n            ConnectionCommon connectionShared,\n            ProbeRequestMonitor probeMonitor,\n            ConnectionPreambleHelper connectionPreambleHelper)\n            : base(connection, middleware, connectionShared)\n        {\n            this.messageCenter = messageCenter;\n            this.connectionManager = connectionManager;\n            this.connectionOptions = connectionOptions;\n            this.probeMonitor = probeMonitor;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n            this.LocalSiloAddress = localSiloDetails.SiloAddress;\n            this.LocalClusterId = localSiloDetails.ClusterId;\n            this.RemoteSiloAddress = remoteSiloAddress;\n        }\n\n        public SiloAddress RemoteSiloAddress { get; private set; }\n\n        public SiloAddress LocalSiloAddress { get; }\n\n        public string LocalClusterId { get; }\n\n        protected override ConnectionDirection ConnectionDirection => ConnectionDirection.SiloToSilo;\n\n        protected override IMessageCenter MessageCenter => this.messageCenter;\n\n        protected override void RecordMessageReceive(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageReceive(msg, numTotalBytes, headerBytes, ConnectionDirection, RemoteSiloAddress);\n        }\n\n        protected override void RecordMessageSend(Message msg, int numTotalBytes, int headerBytes)\n        {\n            MessagingInstruments.OnMessageSend(msg, numTotalBytes, headerBytes, ConnectionDirection, RemoteSiloAddress);\n        }\n\n        protected override void OnReceivedMessage(Message msg)\n        {\n            // See it's a Ping message, and if so, short-circuit it\n            if (msg.IsPing())\n            {\n                this.HandlePingMessage(msg);\n                return;\n            }\n\n            // sniff message headers for directory cache management\n            this.messageCenter.SniffIncomingMessage?.Invoke(msg);\n\n            // Don't process messages that have already timed out\n            if (msg.IsExpired)\n            {\n                this.MessagingTrace.OnDropExpiredMessage(msg, MessagingInstruments.Phase.Receive);\n                return;\n            }\n\n            // If we've stopped application message processing, then filter those out now\n            // Note that if we identify or add other grains that are required for proper stopping, we will need to treat them as we do the membership table grain here.\n            if (messageCenter.IsBlockingApplicationMessages && !msg.IsSystemMessage)\n            {\n                // We reject new requests, and drop all other messages\n                if (msg.Direction != Message.Directions.Request)\n                {\n                    this.MessagingTrace.OnDropBlockedApplicationMessage(msg);\n                    return;\n                }\n\n                MessagingInstruments.OnRejectedMessage(msg);\n                var rejection = this.MessageFactory.CreateRejectionResponse(msg, Message.RejectionTypes.Unrecoverable, \"Silo stopping\", new SiloUnavailableException());\n                this.Send(rejection);\n                return;\n            }\n\n            // Make sure the message is for us. Note that some control messages may have no target\n            // information, so a null target silo is OK.\n            if (msg.TargetSilo == null || msg.TargetSilo.Matches(this.LocalSiloAddress))\n            {\n                messageCenter.ReceiveMessage(msg);\n                return;\n            }\n\n            if (!msg.TargetSilo.Endpoint.Equals(this.LocalSiloAddress.Endpoint))\n            {\n                // If the message is for some other silo altogether, then we need to forward it.\n                LogTraceForwardingMessage(this.Log, msg.Id, msg.SendingSilo!, msg.TargetSilo);\n                messageCenter.SendMessage(msg);\n                return;\n            }\n\n            // If the message was for this endpoint but an older epoch, then reject the message\n            // (if it was a request), or drop it on the floor if it was a response or one-way.\n            if (msg.Direction == Message.Directions.Request)\n            {\n                MessagingInstruments.OnRejectedMessage(msg);\n                var rejection = this.MessageFactory.CreateRejectionResponse(\n                    msg,\n                    Message.RejectionTypes.Transient,\n                    $\"The target silo is no longer active: target was {msg.TargetSilo}, but this silo is {LocalSiloAddress}. The rejected message is {msg}.\");\n\n                // Invalidate the remote caller's activation cache entry.\n                if (msg.TargetSilo != null)\n                {\n                    rejection.AddToCacheInvalidationHeader(new GrainAddress { GrainId = msg.TargetGrain, SiloAddress = msg.TargetSilo }, validAddress: null);\n                }\n\n                this.Send(rejection);\n\n                LogDebugRejectingObsoleteRequest(this.Log, msg.TargetSilo?.ToString() ?? \"null\", this.LocalSiloAddress.ToString(), msg);\n            }\n        }\n\n        private void HandlePingMessage(Message msg)\n        {\n            MessagingInstruments.OnPingReceive(msg.SendingSilo);\n\n            var objectId = RuntimeHelpers.GetHashCode(msg);\n            LogTraceRespondingToPing(this.Log, msg.SendingSilo!, objectId, msg);\n\n            if (!this.LocalSiloAddress.Equals(msg.TargetSilo))\n            {\n                // Got ping that is not destined to me. For example, got a ping to my older incarnation.\n                MessagingInstruments.OnRejectedMessage(msg);\n                Message rejection = this.MessageFactory.CreateRejectionResponse(msg, Message.RejectionTypes.Unrecoverable,\n                    $\"The target silo is no longer active: target was {msg.TargetSilo}, but this silo is {LocalSiloAddress}. The rejected ping message is {msg}.\");\n                this.Send(rejection);\n            }\n            else\n            {\n                this.probeMonitor.OnReceivedProbeRequest();\n                var response = this.MessageFactory.CreateResponseMessage(msg);\n                response.BodyObject = PingResponse;\n                this.Send(response);\n            }\n        }\n\n        protected override void OnSendMessageFailure(Message message, string error)\n        {\n            if (message.IsPing())\n            {\n                LogWarningFailedToSendPingMessage(this.Log, message);\n            }\n\n            this.FailMessage(message, error);\n        }\n\n        protected override async Task RunInternal()\n        {\n            Exception? error = default;\n            try\n            {\n                await Task.WhenAll(ReadPreamble(), WritePreamble());\n                await base.RunInternal();\n            }\n            catch (Exception exception) when ((error = exception) is null)\n            {\n                Debug.Fail(\"Execution should not be able to reach this point.\");\n            }\n            finally\n            {\n                if (this.RemoteSiloAddress is not null)\n                {\n                    this.connectionManager.OnConnectionTerminated(this.RemoteSiloAddress, this, error);\n                }\n            }\n\n            async Task WritePreamble()\n            {\n                await connectionPreambleHelper.Write(\n                    this.Context,\n                    new ConnectionPreamble\n                    {\n                        NodeIdentity = Constants.SiloDirectConnectionId,\n                        NetworkProtocolVersion = this.connectionOptions.ProtocolVersion,\n                        SiloAddress = this.LocalSiloAddress,\n                        ClusterId = this.LocalClusterId\n                    });\n            }\n\n            async Task ReadPreamble()\n            {\n                var preamble = await connectionPreambleHelper.Read(this.Context);\n\n                if (!preamble.NodeIdentity.Equals(Constants.SiloDirectConnectionId))\n                {\n                    throw new InvalidOperationException(\"Unexpected client connection on silo endpoint.\");\n                }\n\n                if (preamble.ClusterId != LocalClusterId)\n                {\n                    throw new InvalidOperationException($@\"Unexpected cluster id \"\"{preamble.ClusterId}\"\", expected \"\"{LocalClusterId}\"\"\");\n                }\n\n                if (preamble.SiloAddress is not null)\n                {\n                    this.RemoteSiloAddress = preamble.SiloAddress;\n                    this.connectionManager.OnConnected(preamble.SiloAddress, this);\n                }\n            }\n        }\n\n        protected override bool PrepareMessageForSend(Message msg)\n        {\n            // Don't send messages that have already timed out\n            if (msg.IsExpired)\n            {\n                this.MessagingTrace.OnDropExpiredMessage(msg, MessagingInstruments.Phase.Send);\n\n                if (msg.IsPing())\n                {\n                    LogWarningDroppingExpiredPingMessage(this.Log, msg);\n                }\n\n                return false;\n            }\n\n            // Fill in the outbound message with our silo address, if it's not already set\n            msg.SendingSilo ??= this.LocalSiloAddress;\n\n            if (msg.IsPing())\n            {\n                LogDebugSendingPingMessage(this.Log, msg);\n            }\n\n            if (this.RemoteSiloAddress is not null && msg.TargetSilo is not null && !this.RemoteSiloAddress.Matches(msg.TargetSilo))\n            {\n                LogWarningAttemptingToSendMessageToWrongConnection(this.Log, msg.TargetSilo, this.RemoteSiloAddress, msg);\n            }\n\n            return true;\n        }\n\n        public void FailMessage(Message msg, string reason)\n        {\n            if (msg.IsPing())\n            {\n                LogWarningFailedPingMessage(this.Log, msg);\n            }\n\n            MessagingInstruments.OnFailedSentMessage(msg);\n            if (msg.Direction == Message.Directions.Request)\n            {\n                LogDebugSiloRejectingMessage(this.Log, this.LocalSiloAddress, msg, reason);\n\n                // Done retrying, send back an error instead\n                this.messageCenter.SendRejection(\n                    msg,\n                    Message.RejectionTypes.Transient,\n                    $\"Silo {this.LocalSiloAddress} is rejecting message: {msg}. Reason = {reason}\",\n                    new SiloUnavailableException());\n            }\n            else\n            {\n                this.MessagingTrace.OnSiloDropSendingMessage(this.LocalSiloAddress, msg, reason);\n            }\n        }\n\n        protected override void RetryMessage(Message msg, Exception? ex = null)\n        {\n            if (msg.IsPing())\n            {\n                LogWarningRetryingPingMessage(this.Log, msg);\n            }\n\n            if (msg.RetryCount < MessagingOptions.DEFAULT_MAX_MESSAGE_SEND_RETRIES)\n            {\n                ++msg.RetryCount;\n                this.messageCenter.SendMessage(msg);\n            }\n            else\n            {\n                var reason = new StringBuilder(\"Retry count exceeded. \");\n                if (ex != null)\n                {\n                    reason.Append(\"Original exception is: \").Append(ex.ToString());\n                }\n                reason.Append(\"Msg is: \").Append(msg);\n                FailMessage(msg, reason.ToString());\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Forwarding message {MessageId} from {SendingSilo} to silo {TargetSilo}\"\n        )]\n        private static partial void LogTraceForwardingMessage(ILogger logger, CorrelationId messageId, SiloAddress sendingSilo, SiloAddress targetSilo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Rejecting an obsolete request; target was {TargetSilo}, but this silo is {SiloAddress}. The rejected message is {Message}.\"\n        )]\n        private static partial void LogDebugRejectingObsoleteRequest(ILogger logger, string targetSilo, string siloAddress, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Responding to Ping from {Silo} with object id {ObjectId}. Message {Message}\"\n        )]\n        private static partial void LogTraceRespondingToPing(ILogger logger, SiloAddress silo, int objectId, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to send ping message {Message}\"\n        )]\n        private static partial void LogWarningFailedToSendPingMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Dropping expired ping message {Message}\"\n        )]\n        private static partial void LogWarningDroppingExpiredPingMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Sending ping message {Message}\"\n        )]\n        private static partial void LogDebugSendingPingMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Attempting to send message addressed to {TargetSilo} to connection with {RemoteSiloAddress}. Message {Message}\"\n        )]\n        private static partial void LogWarningAttemptingToSendMessageToWrongConnection(ILogger logger, SiloAddress targetSilo, SiloAddress remoteSiloAddress, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed ping message {Message}\"\n        )]\n        private static partial void LogWarningFailedPingMessage(ILogger logger, Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.MessagingSendingRejection,\n            Level = LogLevel.Debug,\n            Message = \"Silo {SiloAddress} is rejecting message: {Message}. Reason = {Reason}\"\n        )]\n        private static partial void LogDebugSiloRejectingMessage(ILogger logger, SiloAddress siloAddress, Message message, string reason);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Retrying ping message {Message}\"\n        )]\n        private static partial void LogWarningRetryingPingMessage(ILogger logger, Message message);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/SiloConnectionFactory.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class SiloConnectionFactory : ConnectionFactory\n    {\n        internal static readonly object ServicesKey = new object();\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly ConnectionCommon connectionShared;\n        private readonly ProbeRequestMonitor probeRequestMonitor;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n        private readonly IServiceProvider serviceProvider;\n        private readonly SiloConnectionOptions siloConnectionOptions;\n#if NET9_0_OR_GREATER\n        private readonly Lock initializationLock = new();\n#else\n        private readonly object initializationLock = new();\n#endif\n        private bool isInitialized;\n        private ConnectionManager connectionManager;\n        private MessageCenter messageCenter;\n        private ISiloStatusOracle siloStatusOracle;\n\n        public SiloConnectionFactory(\n            IServiceProvider serviceProvider,\n            IOptions<ConnectionOptions> connectionOptions,\n            IOptions<SiloConnectionOptions> siloConnectionOptions,\n            ILocalSiloDetails localSiloDetails,\n            ConnectionCommon connectionShared,\n            ProbeRequestMonitor probeRequestMonitor,\n            ConnectionPreambleHelper connectionPreambleHelper)\n            : base(serviceProvider.GetRequiredKeyedService<IConnectionFactory>(ServicesKey), serviceProvider, connectionOptions)\n        {\n            this.serviceProvider = serviceProvider;\n            this.siloConnectionOptions = siloConnectionOptions.Value;\n            this.localSiloDetails = localSiloDetails;\n            this.connectionShared = connectionShared;\n            this.probeRequestMonitor = probeRequestMonitor;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n        }\n\n        public override ValueTask<Connection> ConnectAsync(SiloAddress address, CancellationToken cancellationToken)\n        {\n            EnsureInitialized();\n\n            if (this.siloStatusOracle.IsDeadSilo(address))\n            {\n                throw new ConnectionAbortedException($\"Denying connection to known-dead silo {address}\");\n            }\n\n            return base.ConnectAsync(address, cancellationToken);\n        }\n\n        protected override Connection CreateConnection(SiloAddress address, ConnectionContext context)\n        {\n            EnsureInitialized();\n\n            return new SiloConnection(\n                address,\n                context,\n                this.ConnectionDelegate,\n                this.messageCenter,\n                this.localSiloDetails,\n                this.connectionManager,\n                this.ConnectionOptions,\n                this.connectionShared,\n                this.probeRequestMonitor,\n                this.connectionPreambleHelper);\n        }\n\n        protected override void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder)\n        {\n            var configureDelegate = (SiloConnectionOptions.ISiloConnectionBuilderOptions)this.siloConnectionOptions;\n            configureDelegate.ConfigureSiloOutboundBuilder(connectionBuilder);\n            base.ConfigureConnectionBuilder(connectionBuilder);\n        }\n\n        private void EnsureInitialized()\n        {\n            if (!isInitialized)\n            {\n                lock (this.initializationLock)\n                {\n                    if (!isInitialized)\n                    {\n                        this.messageCenter = this.serviceProvider.GetRequiredService<MessageCenter>();\n                        this.connectionManager = this.serviceProvider.GetRequiredService<ConnectionManager>();\n                        this.siloStatusOracle = this.serviceProvider.GetRequiredService<ISiloStatusOracle>();\n                        this.isInitialized = true;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/SiloConnectionListener.cs",
    "content": "using System;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal sealed class SiloConnectionListener : ConnectionListener, ILifecycleParticipant<ISiloLifecycle>, ILifecycleObserver\n    {\n        internal static readonly object ServicesKey = new object();\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly SiloConnectionOptions siloConnectionOptions;\n        private readonly MessageCenter messageCenter;\n        private readonly EndpointOptions endpointOptions;\n        private readonly ConnectionManager connectionManager;\n        private readonly ConnectionCommon connectionShared;\n        private readonly ProbeRequestMonitor probeRequestMonitor;\n        private readonly ConnectionPreambleHelper connectionPreambleHelper;\n\n        public SiloConnectionListener(\n            IServiceProvider serviceProvider,\n            IOptions<ConnectionOptions> connectionOptions,\n            IOptions<SiloConnectionOptions> siloConnectionOptions,\n            MessageCenter messageCenter,\n            IOptions<EndpointOptions> endpointOptions,\n            ILocalSiloDetails localSiloDetails,\n            ConnectionManager connectionManager,\n            ConnectionCommon connectionShared,\n            ProbeRequestMonitor probeRequestMonitor,\n            ConnectionPreambleHelper connectionPreambleHelper)\n            : base(serviceProvider.GetRequiredKeyedService<IConnectionListenerFactory>(ServicesKey), connectionOptions, connectionManager, connectionShared)\n        {\n            this.siloConnectionOptions = siloConnectionOptions.Value;\n            this.messageCenter = messageCenter;\n            this.localSiloDetails = localSiloDetails;\n            this.connectionManager = connectionManager;\n            this.connectionShared = connectionShared;\n            this.probeRequestMonitor = probeRequestMonitor;\n            this.connectionPreambleHelper = connectionPreambleHelper;\n            this.endpointOptions = endpointOptions.Value;\n        }\n\n        public override EndPoint Endpoint => this.endpointOptions.GetListeningSiloEndpoint();\n\n        protected override Connection CreateConnection(ConnectionContext context)\n        {\n            return new SiloConnection(\n                default,\n                context,\n                this.ConnectionDelegate,\n                this.messageCenter,\n                this.localSiloDetails,\n                this.connectionManager,\n                this.ConnectionOptions,\n                this.connectionShared,\n                this.probeRequestMonitor,\n                this.connectionPreambleHelper);\n        }\n\n        protected override void ConfigureConnectionBuilder(IConnectionBuilder connectionBuilder)\n        {\n            var configureDelegate = (SiloConnectionOptions.ISiloConnectionBuilderOptions)this.siloConnectionOptions;\n            configureDelegate.ConfigureSiloInboundBuilder(connectionBuilder);\n            base.ConfigureConnectionBuilder(connectionBuilder);\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            if (this.Endpoint is null) return;\n\n            lifecycle.Subscribe(nameof(SiloConnectionListener), ServiceLifecycleStage.RuntimeInitialize - 1, this);\n        }\n\n        Task ILifecycleObserver.OnStart(CancellationToken ct) => Task.Run(async () =>\n        {\n            await BindAsync();\n            // Start accepting connections immediately.\n            Start();\n        });\n\n        Task ILifecycleObserver.OnStop(CancellationToken ct) => Task.Run(() => StopAsync(ct));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Networking/SiloConnectionMaintainer.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.Messaging\n{\n    internal partial class SiloConnectionMaintainer : ILifecycleParticipant<ISiloLifecycle>, ISiloStatusListener, ILifecycleObserver\n    {\n        private readonly ConnectionManager connectionManager;\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly ILogger<SiloConnectionMaintainer> log;\n\n        public SiloConnectionMaintainer(\n            ConnectionManager connectionManager,\n            ISiloStatusOracle siloStatusOracle,\n            ILogger<SiloConnectionMaintainer> log)\n        {\n            this.connectionManager = connectionManager;\n            this.siloStatusOracle = siloStatusOracle;\n            this.log = log;\n        }\n\n        public Task OnStart(CancellationToken ct)\n        {\n            this.siloStatusOracle.SubscribeToSiloStatusEvents(this);\n            return Task.CompletedTask;\n        }\n\n        public Task OnStop(CancellationToken ct)\n        {\n            this.siloStatusOracle.UnSubscribeFromSiloStatusEvents(this);\n            return Task.CompletedTask;\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(nameof(SiloConnectionMaintainer), ServiceLifecycleStage.RuntimeInitialize, this);\n        }\n\n        public void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n        {\n            if (status == SiloStatus.Dead && updatedSilo != siloStatusOracle.SiloAddress)\n            {\n                _ = Task.Run(() => this.CloseConnectionAsync(updatedSilo));\n            }\n        }\n\n        private async Task CloseConnectionAsync(SiloAddress silo)\n        {\n            try\n            {\n                // Allow a short grace period to complete sending pending messages (eg, gossip responses)\n                await Task.Delay(TimeSpan.FromSeconds(10));\n\n                await this.connectionManager.CloseAsync(silo);\n            }\n            catch (Exception exception)\n            {\n                LogExceptionWhileClosingConnections(this.log, silo, exception);\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = 1001,\n            Message = \"Exception while closing connections to defunct silo {SiloAddress}\"\n        )]\n        private static partial void LogExceptionWhileClosingConnections(ILogger logger, SiloAddress siloAddress, Exception exception);\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Orleans.Runtime.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Runtime</PackageId>\n    <Title>Microsoft Orleans Runtime</Title>\n    <Description>Core runtime library of Microsoft Orleans that hosts and executes grains within a silo.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\\\Orleans.Core\\Orleans.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Diagnostics\\\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Benchmarks\" />\n    <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" />\n    <InternalsVisibleTo Include=\"LoadTestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DurableJobs\" />\n    <InternalsVisibleTo Include=\"Orleans.GrainDirectory.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Journaling\" />\n    <InternalsVisibleTo Include=\"Orleans.Placement.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Reminders\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.TestingHost\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/ActivationCountPlacementDirector.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Placement\n{\n\n    internal class ActivationCountPlacementDirector : RandomPlacementDirector, ISiloStatisticsChangeListener, IPlacementDirector\n    {\n        private class CachedLocalStat\n        {\n            private int _activationCount;\n\n            internal CachedLocalStat(SiloRuntimeStatistics siloStats) => SiloStats = siloStats;\n\n            public SiloRuntimeStatistics SiloStats { get; }\n            public int ActivationCount => _activationCount;\n            public void IncrementActivationCount(int delta) => Interlocked.Add(ref _activationCount, delta);\n        }\n        \n        // Track created activations on this silo between statistic intervals.\n        private readonly ConcurrentDictionary<SiloAddress, CachedLocalStat> _localCache = new();\n        private readonly SiloAddress _localAddress;\n        private readonly int _chooseHowMany;\n\n        public ActivationCountPlacementDirector(\n            ILocalSiloDetails localSiloDetails,\n            DeploymentLoadPublisher deploymentLoadPublisher, \n            IOptions<ActivationCountBasedPlacementOptions> options)\n        {\n            _localAddress = localSiloDetails.SiloAddress;\n            _chooseHowMany = options.Value.ChooseOutOf;\n            if (_chooseHowMany <= 0) throw new ArgumentException($\"{nameof(ActivationCountBasedPlacementOptions)}.{nameof(ActivationCountBasedPlacementOptions.ChooseOutOf)} is {_chooseHowMany}. It must be greater than zero.\");\n            deploymentLoadPublisher?.SubscribeToStatisticsChangeEvents(this);\n        }\n\n        private SiloAddress SelectSiloPowerOfK(SiloAddress[] silos)\n        {\n            if (silos.Length == 0)\n            {\n                throw new SiloUnavailableException(\"Unable to select a candidate because there are no compatible silos.\");\n            }\n\n            // Exclude overloaded and non-compatible silos\n            var relevantSilos = new List<KeyValuePair<SiloAddress, CachedLocalStat>>();\n            var totalSilos = _localCache.Count;\n            var compatibleSilosWithoutStats = 0;\n            SiloAddress sampledCompatibleSiloWithoutStats = default;\n            foreach (var silo in silos)\n            {\n                if (!_localCache.TryGetValue(silo, out var localSiloStat))\n                {\n                    compatibleSilosWithoutStats++;\n                    if (compatibleSilosWithoutStats == 1 || Random.Shared.Next(compatibleSilosWithoutStats) == 0)\n                    {\n                        sampledCompatibleSiloWithoutStats = silo;\n                    }\n\n                    continue;\n                }\n\n                if (localSiloStat.SiloStats.IsOverloaded) continue;\n\n                relevantSilos.Add(new(silo, localSiloStat));\n            }\n\n            if (relevantSilos.Count > 0)\n            {\n                int chooseFrom = Math.Min(relevantSilos.Count, _chooseHowMany);\n                var chooseFromThoseSilos = new List<KeyValuePair<SiloAddress, CachedLocalStat>>(chooseFrom);\n                while (chooseFromThoseSilos.Count < chooseFrom)\n                {\n                    int index = Random.Shared.Next(relevantSilos.Count);\n                    var pickedSilo = relevantSilos[index];\n                    relevantSilos.RemoveAt(index);\n                    chooseFromThoseSilos.Add(pickedSilo);\n                }\n\n                KeyValuePair<SiloAddress, CachedLocalStat> minLoadedSilo = default;\n                var minLoad = int.MaxValue;\n                foreach (var s in chooseFromThoseSilos)\n                {\n                    var load = s.Value.ActivationCount + s.Value.SiloStats.RecentlyUsedActivationCount;\n                    if (load < minLoad)\n                    {\n                        minLoadedSilo = s;\n                        minLoad = load;\n                    }\n                }\n\n                // Increment placement by number of silos instead of by one.\n                // This is our trick to get more balanced placement, accounting to the probable\n                // case when multiple silos place on the same silo at the same time, before stats are refreshed.\n                minLoadedSilo.Value.IncrementActivationCount(totalSilos);\n\n                return minLoadedSilo.Key;\n            }\n\n            // Some compatible silos might not have published statistics yet.\n            if (compatibleSilosWithoutStats > 0)\n            {\n                return sampledCompatibleSiloWithoutStats;\n            }\n\n            // All compatible silos have published stats and are overloaded.\n            var allSiloStats = _localCache.ToList();\n            throw new SiloUnavailableException(\n                $\"Unable to select a candidate from {silos.Length} compatible silos (all are overloaded). All silo stats: {Utils.EnumerableToString(allSiloStats, kvp => $\"SiloAddress = {kvp.Key} -> IsOverloaded = {kvp.Value.SiloStats.IsOverloaded}, ActivationCount = {kvp.Value.ActivationCount}, RecentlyUsedActivationCount = {kvp.Value.SiloStats.RecentlyUsedActivationCount}\")}\");\n        }\n\n        public override Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context) => Task.FromResult(OnAddActivationInternal(target, context));\n\n        private SiloAddress OnAddActivationInternal(PlacementTarget target, IPlacementContext context)\n        {\n            var compatibleSilos = context.GetCompatibleSilos(target);\n\n            // If a valid placement hint was specified, use it.\n            if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint)\n            {\n                return placementHint;\n            }\n\n            // If the cache was not populated, place locally only if this silo is compatible.\n            if (_localCache.IsEmpty)\n            {\n                if (compatibleSilos.Contains(_localAddress))\n                {\n                    return _localAddress;\n                }\n\n                return SelectSiloPowerOfK(compatibleSilos);\n            }\n\n            return SelectSiloPowerOfK(compatibleSilos);\n        }\n\n        public void SiloStatisticsChangeNotification(SiloAddress updatedSilo, SiloRuntimeStatistics newSiloStats)\n        {\n            // just create a new empty CachedLocalStat and throw the old one.\n            _localCache[updatedSilo] = new(newSiloStats);\n        }\n\n        public void RemoveSilo(SiloAddress removedSilo)\n        {\n            _localCache.TryRemove(removedSilo, out _);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/ClientObserverPlacementStrategyResolver.cs",
    "content": "using Orleans.Metadata;\n\nnamespace Orleans.Runtime.Placement\n{\n    internal class ClientObserverPlacementStrategyResolver : IPlacementStrategyResolver\n    {\n        private readonly ClientObserversPlacement _strategy = new ClientObserversPlacement();\n\n        public bool TryResolvePlacementStrategy(GrainType grainType, GrainProperties properties, out PlacementStrategy result)\n        {\n            if (grainType.IsClient())\n            {\n                result = _strategy;\n                return true;\n            }\n\n            result = default;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/ClientObserversPlacementDirector.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// ClientObserversPlacementDirector is used to prevent placement of client observer activations.\n    /// </summary>\n    internal class ClientObserversPlacementDirector : IPlacementDirector\n    {\n        public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context) => throw new ClientNotAvailableException(target.GrainIdentity);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/DeploymentLoadPublisher.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Statistics;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// This class collects runtime statistics for all silos in the current deployment for use by placement.\n    /// </summary>\n    internal sealed partial class DeploymentLoadPublisher : SystemTarget, IDeploymentLoadPublisher, ISiloStatusListener, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly ILocalSiloDetails _siloDetails;\n        private readonly ISiloStatusOracle _siloStatusOracle;\n        private readonly IInternalGrainFactory _grainFactory;\n        private readonly ActivationDirectory _activationDirectory;\n        private readonly IActivationWorkingSet _activationWorkingSet;\n        private readonly IEnvironmentStatisticsProvider _environmentStatisticsProvider;\n        private readonly IOptions<LoadSheddingOptions> _loadSheddingOptions;\n        private readonly ConcurrentDictionary<SiloAddress, SiloRuntimeStatistics> _periodicStats;\n        private readonly TimeSpan _statisticsRefreshTime;\n        private readonly List<ISiloStatisticsChangeListener> _siloStatisticsChangeListeners;\n        private readonly ILogger _logger;\n\n        private long _lastUpdateDateTimeTicks;\n        private IDisposable _publishTimer;\n\n        public ConcurrentDictionary<SiloAddress, SiloRuntimeStatistics> PeriodicStatistics => _periodicStats;\n\n        public SiloRuntimeStatistics LocalRuntimeStatistics { get; private set; }\n\n        public DeploymentLoadPublisher(\n            ILocalSiloDetails siloDetails,\n            ISiloStatusOracle siloStatusOracle,\n            IOptions<DeploymentLoadPublisherOptions> options,\n            IInternalGrainFactory grainFactory,\n            ILoggerFactory loggerFactory,\n            ActivationDirectory activationDirectory,\n            IActivationWorkingSet activationWorkingSet,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            SystemTargetShared shared)\n            : base(Constants.DeploymentLoadPublisherSystemTargetType, shared)\n        {\n            _logger = loggerFactory.CreateLogger<DeploymentLoadPublisher>();\n            _siloDetails = siloDetails;\n            _siloStatusOracle = siloStatusOracle;\n            _grainFactory = grainFactory;\n            _activationDirectory = activationDirectory;\n            _activationWorkingSet = activationWorkingSet;\n            _environmentStatisticsProvider = environmentStatisticsProvider;\n            _loadSheddingOptions = loadSheddingOptions;\n            _statisticsRefreshTime = options.Value.DeploymentLoadPublisherRefreshTime;\n            _periodicStats = new ConcurrentDictionary<SiloAddress, SiloRuntimeStatistics>();\n            _siloStatisticsChangeListeners = new List<ISiloStatisticsChangeListener>();\n            siloStatusOracle.SubscribeToSiloStatusEvents(this);\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        private async Task StartAsync(CancellationToken cancellationToken)\n        {\n            LogDebugStartingDeploymentLoadPublisher(_logger);\n\n            if (_statisticsRefreshTime > TimeSpan.Zero)\n            {\n                // Randomize PublishStatistics timer,\n                // but also upon start publish my stats to everyone and take everyone's stats for me to start with something.\n                var randomTimerOffset = RandomTimeSpan.Next(_statisticsRefreshTime);\n                _publishTimer = RegisterTimer(\n                    static state => ((DeploymentLoadPublisher)state).PublishStatistics(),\n                    this,\n                    randomTimerOffset,\n                    _statisticsRefreshTime);\n            }\n\n            await RefreshClusterStatistics();\n            await PublishStatistics();\n            LogDebugStartedDeploymentLoadPublisher(_logger);\n        }\n\n        private async Task PublishStatistics()\n        {\n            try\n            {\n                LogTracePublishStatistics(_logger);\n\n                // Ensure that our timestamp is monotonically increasing.\n                var ticks = _lastUpdateDateTimeTicks = Math.Max(_lastUpdateDateTimeTicks + 1, DateTime.UtcNow.Ticks);\n\n                var myStats = new SiloRuntimeStatistics(\n                    _activationDirectory.Count,\n                    _activationWorkingSet.Count,\n                    _environmentStatisticsProvider,\n                    _loadSheddingOptions,\n                    new DateTime(ticks, DateTimeKind.Utc));\n\n                // Update statistics locally.\n                LocalRuntimeStatistics = myStats;\n                UpdateRuntimeStatisticsInternal(_siloDetails.SiloAddress, myStats);\n\n                // Inform other cluster members about our refreshed statistics.\n                var members = _siloStatusOracle.GetApproximateSiloStatuses(true).Keys;\n                var tasks = new List<Task>(members.Count);\n                foreach (var siloAddress in members)\n                {\n                    // No need to make a grain call to ourselves.\n                    if (siloAddress == _siloDetails.SiloAddress)\n                    {\n                        continue;\n                    }\n\n                    try\n                    {\n                        var deploymentLoadPublisher = _grainFactory.GetSystemTarget<IDeploymentLoadPublisher>(Constants.DeploymentLoadPublisherSystemTargetType, siloAddress);\n                        tasks.Add(deploymentLoadPublisher.UpdateRuntimeStatistics(_siloDetails.SiloAddress, myStats));\n                    }\n                    catch (Exception exception)\n                    {\n                        LogWarningRuntimeStatisticsUpdateFailure1(_logger, exception);\n                    }\n                }\n\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception exc)\n            {\n                LogWarningRuntimeStatisticsUpdateFailure2(_logger, exc);\n            }\n        }\n\n        public Task UpdateRuntimeStatistics(SiloAddress siloAddress, SiloRuntimeStatistics siloStats)\n        {\n            UpdateRuntimeStatisticsInternal(siloAddress, siloStats);\n            return Task.CompletedTask;\n        }\n\n        private void UpdateRuntimeStatisticsInternal(SiloAddress siloAddress, SiloRuntimeStatistics siloStats)\n        {\n            LogTraceUpdateRuntimeStatistics(_logger, siloAddress);\n            if (_siloStatusOracle.GetApproximateSiloStatus(siloAddress) != SiloStatus.Active)\n            {\n                return;\n            }\n\n            // Take only if newer.\n            if (_periodicStats.TryGetValue(siloAddress, out var old) && old.DateTime > siloStats.DateTime)\n            {\n                return;\n            }\n\n            _periodicStats[siloAddress] = siloStats;\n            NotifyAllStatisticsChangeEventsSubscribers(siloAddress, siloStats);\n        }\n\n        internal async Task RefreshClusterStatistics()\n        {\n            LogTraceRefreshStatistics(_logger);\n            await this.RunOrQueueTask(() =>\n                {\n                    var members = _siloStatusOracle.GetApproximateSiloStatuses(true).Keys;\n                    var tasks = new List<Task>(members.Count);\n                    foreach (var siloAddress in members)\n                    {\n                        tasks.Add(RefreshSiloStatistics(siloAddress));\n                    }\n\n                    return Task.WhenAll(tasks);\n                });\n        }\n\n        private async Task RefreshSiloStatistics(SiloAddress silo)\n        {\n            try\n            {\n                var statistics = await _grainFactory.GetSystemTarget<ISiloControl>(Constants.SiloControlType, silo).GetRuntimeStatistics();\n                UpdateRuntimeStatisticsInternal(silo, statistics);\n            }\n            catch (Exception exception)\n            {\n                LogWarningRuntimeStatisticsUpdateFailure3(_logger, exception, silo);\n            }\n        }\n\n        public bool SubscribeToStatisticsChangeEvents(ISiloStatisticsChangeListener observer)\n        {\n            lock (_siloStatisticsChangeListeners)\n            {\n                if (_siloStatisticsChangeListeners.Contains(observer)) return false;\n\n                _siloStatisticsChangeListeners.Add(observer);\n                return true;\n            }\n        }\n\n        public bool UnsubscribeStatisticsChangeEvents(ISiloStatisticsChangeListener observer)\n        {\n            lock (_siloStatisticsChangeListeners)\n            {\n                return _siloStatisticsChangeListeners.Remove(observer);\n            }\n        }\n\n        private void NotifyAllStatisticsChangeEventsSubscribers(SiloAddress silo, SiloRuntimeStatistics stats)\n        {\n            lock (_siloStatisticsChangeListeners)\n            {\n                foreach (var subscriber in _siloStatisticsChangeListeners)\n                {\n                    if (stats == null)\n                    {\n                        subscriber.RemoveSilo(silo);\n                    }\n                    else\n                    {\n                        subscriber.SiloStatisticsChangeNotification(silo, stats);\n                    }\n                }\n            }\n        }\n\n        public void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n        {\n            WorkItemGroup.QueueAction(() =>\n            {\n                Utils.SafeExecute(() => OnSiloStatusChange(updatedSilo, status), _logger);\n            });\n        }\n\n        private void OnSiloStatusChange(SiloAddress updatedSilo, SiloStatus status)\n        {\n            if (!status.IsTerminating()) return;\n\n            _periodicStats.TryRemove(updatedSilo, out _);\n            NotifyAllStatisticsChangeEventsSubscribers(updatedSilo, null);\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle observer)\n        {\n            observer.Subscribe(\n                nameof(DeploymentLoadPublisher),\n                ServiceLifecycleStage.RuntimeGrainServices,\n                StartAsync,\n                ct =>\n            {\n                _publishTimer.Dispose();\n                return Task.CompletedTask;\n            });\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting DeploymentLoadPublisher\"\n        )]\n        private static partial void LogDebugStartingDeploymentLoadPublisher(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Started DeploymentLoadPublisher\"\n        )]\n        private static partial void LogDebugStartedDeploymentLoadPublisher(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"PublishStatistics\"\n        )]\n        private static partial void LogTracePublishStatistics(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Placement_RuntimeStatisticsUpdateFailure_1,\n            Level = LogLevel.Warning,\n            Message = \"An unexpected exception was thrown by PublishStatistics.UpdateRuntimeStatistics(). Ignored\"\n        )]\n        private static partial void LogWarningRuntimeStatisticsUpdateFailure1(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Placement_RuntimeStatisticsUpdateFailure_2,\n            Level = LogLevel.Warning,\n            Message = \"An exception was thrown by PublishStatistics.UpdateRuntimeStatistics(). Ignoring\"\n        )]\n        private static partial void LogWarningRuntimeStatisticsUpdateFailure2(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"UpdateRuntimeStatistics from {Server}\"\n        )]\n        private static partial void LogTraceUpdateRuntimeStatistics(ILogger logger, SiloAddress server);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"RefreshStatistics\"\n        )]\n        private static partial void LogTraceRefreshStatistics(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Placement_RuntimeStatisticsUpdateFailure_3,\n            Level = LogLevel.Warning,\n            Message = \"An unexpected exception was thrown from RefreshStatistics by ISiloControl.GetRuntimeStatistics({SiloAddress}). Will keep using stale statistics.\"\n        )]\n        private static partial void LogWarningRuntimeStatisticsUpdateFailure3(ILogger logger, Exception exception, SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/PlacementFilterDirectorResolver.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\n/// <summary>\n/// Responsible for resolving an <see cref=\"IPlacementFilterDirector\"/> for a <see cref=\"PlacementFilterStrategy\"/>.\n/// </summary>\npublic sealed class PlacementFilterDirectorResolver(IServiceProvider services)\n{\n    public IPlacementFilterDirector GetFilterDirector(PlacementFilterStrategy placementFilterStrategy) => services.GetRequiredKeyedService<IPlacementFilterDirector>(placementFilterStrategy.GetType());\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/PlacementFilterStrategyResolver.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Metadata;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\n/// <summary>\n/// Responsible for resolving an <see cref=\"PlacementFilterStrategy\"/> for a <see cref=\"GrainType\"/>.\n/// </summary>\npublic sealed class PlacementFilterStrategyResolver\n{\n    private readonly ConcurrentDictionary<GrainType, PlacementFilterStrategy[]> _resolvedFilters = new();\n    private readonly Func<GrainType, PlacementFilterStrategy[]> _getFiltersInternal;\n    private readonly GrainPropertiesResolver _grainPropertiesResolver;\n    private readonly IServiceProvider _services;\n\n    /// <summary>\n    /// Create a <see cref=\"PlacementFilterStrategyResolver\"/> instance.\n    /// </summary>\n    public PlacementFilterStrategyResolver(\n        IServiceProvider services,\n        GrainPropertiesResolver grainPropertiesResolver)\n    {\n        _services = services;\n        _getFiltersInternal = GetPlacementFilterStrategyInternal;\n        _grainPropertiesResolver = grainPropertiesResolver;\n    }\n\n    /// <summary>\n    /// Gets the placement filter strategy associated with the provided grain type.\n    /// </summary>\n    public PlacementFilterStrategy[] GetPlacementFilterStrategies(GrainType grainType) => _resolvedFilters.GetOrAdd(grainType, _getFiltersInternal);\n\n    private PlacementFilterStrategy[] GetPlacementFilterStrategyInternal(GrainType grainType)\n    {\n        _grainPropertiesResolver.TryGetGrainProperties(grainType, out var properties);\n\n        if (properties is not null\n            && properties.Properties.TryGetValue(WellKnownGrainTypeProperties.PlacementFilter, out var placementFilterIds)\n            && !string.IsNullOrWhiteSpace(placementFilterIds))\n        {\n            var filterList = new List<PlacementFilterStrategy>();\n            foreach (var filterId in placementFilterIds.Split(\",\"))\n            {\n                var filter = _services.GetKeyedService<PlacementFilterStrategy>(filterId);\n                if (filter is not null)\n                {\n                    filter.Initialize(properties);\n                    filterList.Add(filter);\n                }\n                else\n                {\n                    throw new KeyNotFoundException($\"Could not resolve placement filter strategy {filterId} for grain type {grainType}. Ensure that dependencies for that filter have been configured in the Container. This is often through a .Use* extension method provided by the implementation.\");\n                }\n            }\n\n            var orderedFilters = filterList.OrderBy(f => f.Order).ToArray();\n            // check that the order is unique\n            if (orderedFilters.Select(f => f.Order).Distinct().Count() != orderedFilters.Length)\n            {\n                throw new InvalidOperationException($\"Placement filters for grain type {grainType} have duplicate order values. Order values must be specified if more than one filter is applied and must be unique.\");\n            }\n            return orderedFilters;\n        }\n\n        return [];\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/PreferredMatchSiloMetadataPlacementFilterAttribute.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\n/// <summary>\n/// Attribute to specify the preferred match silo metadata placement filter that preferentially filters down to silos where the metadata matches the local (calling) silo metadata.\n/// </summary>\n/// <param name=\"orderedMetadataKeys\">Ordered set of metadata keys to try to match. The earlier entries are considered less important and will be dropped to find a less-specific match if sufficient more-specific matches do not have enough results.</param>\n/// <param name=\"minCandidates\">The minimum desired candidates to filter. This is to balance meeting the metadata preferences with not overloading a single or small set of silos with activations. Set this to 1 if you only want the best matches, even if there's only one silo that is currently the best match.</param>\n/// <remarks>Example: If keys [\"first\",\"second\"] are specified, then it will attempt to return only silos where both keys match the local silo's metadata values. If there are not sufficient silos matching both, then it will also include silos matching only the second key. Finally, if there are still fewer than minCandidates results then it will include all silos.</remarks>\n[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n[Experimental(\"ORLEANSEXP004\")]\npublic class PreferredMatchSiloMetadataPlacementFilterAttribute(string[] orderedMetadataKeys, int minCandidates = 2, int order = 0)\n    : PlacementFilterAttribute(new PreferredMatchSiloMetadataPlacementFilterStrategy(orderedMetadataKeys, minCandidates, order));"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/PreferredMatchSiloMetadataPlacementFilterDirector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Placement;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\ninternal class PreferredMatchSiloMetadataPlacementFilterDirector(\n    ILocalSiloDetails localSiloDetails,\n    ISiloMetadataCache siloMetadataCache)\n    : IPlacementFilterDirector\n{\n    public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n    {\n        var preferredMatchSiloMetadataPlacementFilterStrategy = filterStrategy as PreferredMatchSiloMetadataPlacementFilterStrategy;\n        var minCandidates = preferredMatchSiloMetadataPlacementFilterStrategy?.MinCandidates ?? 1;\n        var orderedMetadataKeys = preferredMatchSiloMetadataPlacementFilterStrategy?.OrderedMetadataKeys ?? [];\n        \n        var localSiloMetadata = siloMetadataCache.GetSiloMetadata(localSiloDetails.SiloAddress).Metadata;\n\n        if (localSiloMetadata.Count == 0)\n        {\n            return silos;\n        }\n\n        var siloList = silos.ToList();\n        if (siloList.Count <= minCandidates)\n        {\n            return siloList;\n        }\n\n        // return the list of silos that match the most metadata keys. The first key in the list is the least important.\n        // This means that the last key in the list is the most important.\n        // If no silos match any metadata keys, return the original list of silos.\n        var maxScore = 0;\n        var siloScores = new int[siloList.Count];\n        var scoreCounts = new int[orderedMetadataKeys.Length+1];\n        for (var i = 0; i < siloList.Count; i++)\n        {\n            var siloMetadata = siloMetadataCache.GetSiloMetadata(siloList[i]).Metadata;\n            var siloScore = 0;\n            for (var j = orderedMetadataKeys.Length - 1; j >= 0; --j)\n            {\n                if (siloMetadata.TryGetValue(orderedMetadataKeys[j], out var siloMetadataValue) &&\n                    localSiloMetadata.TryGetValue(orderedMetadataKeys[j], out var localSiloMetadataValue) &&\n                    siloMetadataValue == localSiloMetadataValue)\n                {\n                    siloScore = ++siloScores[i];\n                    maxScore = Math.Max(maxScore, siloScore);\n                }\n                else\n                {\n                    break;\n                }\n            }\n            scoreCounts[siloScore]++;\n        }\n\n        if (maxScore == 0)\n        {\n            return siloList;\n        }\n\n        var candidateCount = 0;\n        var scoreCutOff = orderedMetadataKeys.Length;\n        for (var i = scoreCounts.Length-1; i >= 0; i--)\n        {\n            candidateCount += scoreCounts[i];\n            if (candidateCount >= minCandidates)\n            {\n                scoreCutOff = i;\n                break;\n            }\n        }\n\n        return siloList.Where((_, i) => siloScores[i] >= scoreCutOff);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/PreferredMatchSiloMetadataPlacementFilterStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing Orleans.Metadata;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\npublic class PreferredMatchSiloMetadataPlacementFilterStrategy(string[] orderedMetadataKeys, int minCandidates, int order)\n    : PlacementFilterStrategy(order)\n{\n    public string[] OrderedMetadataKeys { get; set; } = orderedMetadataKeys;\n    public int MinCandidates { get; set; } = minCandidates;\n\n    public PreferredMatchSiloMetadataPlacementFilterStrategy() : this([], 2, 0)\n    {\n    }\n\n    public override void AdditionalInitialize(GrainProperties properties)\n    {\n        var placementFilterGrainProperty = GetPlacementFilterGrainProperty(\"ordered-metadata-keys\", properties);\n        if (placementFilterGrainProperty is null)\n        {\n            throw new ArgumentException(\"Invalid ordered-metadata-keys property value.\");\n        }\n\n        OrderedMetadataKeys = placementFilterGrainProperty.Split(\",\");\n        var minCandidatesProperty = GetPlacementFilterGrainProperty(\"min-candidates\", properties);\n        if (!int.TryParse(minCandidatesProperty, out var parsedMinCandidates))\n        {\n            throw new ArgumentException(\"Invalid min-candidates property value.\");\n        }\n\n        MinCandidates = parsedMinCandidates;\n    }\n\n    protected override IEnumerable<KeyValuePair<string, string>> GetAdditionalGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType,\n        IReadOnlyDictionary<string, string> existingProperties)\n    {\n        yield return new KeyValuePair<string, string>(\"ordered-metadata-keys\", string.Join(\",\", OrderedMetadataKeys));\n        yield return new KeyValuePair<string, string>(\"min-candidates\", MinCandidates.ToString(CultureInfo.InvariantCulture));\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/RequiredMatchSiloMetadataPlacementFilterAttribute.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\n/// <summary>\n/// Attribute to specify that a silo must have a specific metadata key-value pair matching the local (calling) silo to be considered for placement.\n/// </summary>\n/// <param name=\"metadataKeys\"></param>\n[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n[Experimental(\"ORLEANSEXP004\")]\npublic class RequiredMatchSiloMetadataPlacementFilterAttribute(string[] metadataKeys, int order = 0)\n    : PlacementFilterAttribute(new RequiredMatchSiloMetadataPlacementFilterStrategy(metadataKeys, order));"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/RequiredMatchSiloMetadataPlacementFilterDirector.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Placement;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\ninternal class RequiredMatchSiloMetadataPlacementFilterDirector(ILocalSiloDetails localSiloDetails, ISiloMetadataCache siloMetadataCache)\n    : IPlacementFilterDirector\n{\n    public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n    {\n        var metadataKeys = (filterStrategy as RequiredMatchSiloMetadataPlacementFilterStrategy)?.MetadataKeys ?? [];\n\n        // yield return all silos if no silos match any metadata keys\n        if (metadataKeys.Length == 0)\n        {\n            return silos;\n        }\n\n        var localMetadata = siloMetadataCache.GetSiloMetadata(localSiloDetails.SiloAddress);\n        var localRequiredMetadata = GetMetadata(localMetadata, metadataKeys);\n\n        return silos.Where(silo =>\n        {\n            var remoteMetadata = siloMetadataCache.GetSiloMetadata(silo);\n            return DoesMetadataMatch(localRequiredMetadata, remoteMetadata, metadataKeys);\n        });\n    }\n\n    private static bool DoesMetadataMatch(string?[] localMetadata, SiloMetadata siloMetadata, string[] metadataKeys)\n    {\n        for (var i = 0; i < metadataKeys.Length; i++)\n        {\n            if (localMetadata[i] != siloMetadata.Metadata.GetValueOrDefault(metadataKeys[i]))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n    private static string?[] GetMetadata(SiloMetadata siloMetadata, string[] metadataKeys)\n    {\n        var result = new string?[metadataKeys.Length];\n        for (var i = 0; i < metadataKeys.Length; i++)\n        {\n            result[i] = siloMetadata.Metadata.GetValueOrDefault(metadataKeys[i]);\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Filtering/RequiredMatchSiloMetadataPlacementFilterStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Metadata;\nusing Orleans.Placement;\n\n#nullable enable\nnamespace Orleans.Runtime.Placement.Filtering;\n\npublic class RequiredMatchSiloMetadataPlacementFilterStrategy(string[] metadataKeys, int order)\n    : PlacementFilterStrategy(order)\n{\n    public string[] MetadataKeys { get; private set; } = metadataKeys;\n\n    public RequiredMatchSiloMetadataPlacementFilterStrategy() : this([], 0)\n    {\n    }\n\n    public override void AdditionalInitialize(GrainProperties properties)\n    {\n        var placementFilterGrainProperty = GetPlacementFilterGrainProperty(\"metadata-keys\", properties);\n        if (placementFilterGrainProperty is null)\n        {\n            throw new ArgumentException(\"Invalid metadata-keys property value.\");\n        }\n        MetadataKeys = placementFilterGrainProperty.Split(\",\");\n    }\n\n    protected override IEnumerable<KeyValuePair<string, string>> GetAdditionalGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType,\n        IReadOnlyDictionary<string, string> existingProperties)\n    {\n        yield return new KeyValuePair<string, string>(\"metadata-keys\", String.Join(\",\", MetadataKeys));\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/GrainMigratabilityChecker.cs",
    "content": "using Orleans.Metadata;\nusing Orleans.Placement;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Frozen;\nusing System.Runtime.CompilerServices;\n\n#nullable enable\n\nnamespace Orleans.Runtime.Placement;\n\ninternal sealed class GrainMigratabilityChecker(\n    PlacementStrategyResolver strategyResolver,\n    IClusterManifestProvider clusterManifestProvider,\n    TimeProvider timeProvider)\n{\n    // We override equality and hashcode as this type is used as the dictionary key,\n    // and record structs use default equality comparer, which for an enum is not that great for performance.\n    private readonly record struct StatusKey(GrainType Type, ImmovableKind Kind) : IEquatable<StatusKey>\n    {\n        public bool Equals(StatusKey other) => Type == other.Type && Kind == other.Kind;\n        public override int GetHashCode() => HashCode.Combine(Type.GetUniformHashCode(), Kind);\n    }\n\n    private readonly GrainManifest _localManifest = clusterManifestProvider.LocalGrainManifest;\n    private readonly PlacementStrategyResolver _strategyResolver = strategyResolver;\n    private readonly TimeProvider _timeProvider = timeProvider;\n    private readonly ConcurrentDictionary<StatusKey, bool> _migratableStatuses = new();\n    private FrozenDictionary<StatusKey, bool>? _migratableStatusesCache;\n    private long _lastRegeneratedCacheTimestamp = timeProvider.GetTimestamp();\n\n    public bool IsMigratable(GrainType grainType, ImmovableKind expectedKind)\n    {\n        var statusKey = new StatusKey(grainType, expectedKind);\n        if (_migratableStatusesCache is { } cache && cache.TryGetValue(statusKey, out var isMigratable))\n        {\n            return isMigratable;\n        }\n\n        return IsMigratableRare(grainType, statusKey);\n\n        bool IsMigratableRare(GrainType grainType, StatusKey statusKey)\n        {\n            // _migratableStatuses holds statuses for each grain type if its migratable type or not, so we can make fast lookups.\n            // since we don't anticipate a huge number of grain *types*, i think its just fine to have this in place as fast-check.\n            if (!_migratableStatuses.TryGetValue(statusKey, out var isMigratable))\n            {\n                isMigratable = !(grainType.IsClient() || grainType.IsSystemTarget() || grainType.IsGrainService() || IsStatelessWorker(grainType) || IsImmovable(grainType));\n                _migratableStatuses.TryAdd(statusKey, isMigratable);\n            }\n\n            // Regenerate the cache periodically.\n            var currentTimestamp = _timeProvider.GetTimestamp();\n            if (_timeProvider.GetElapsedTime(_lastRegeneratedCacheTimestamp, currentTimestamp) > TimeSpan.FromSeconds(5))\n            {\n                _migratableStatusesCache = _migratableStatuses.ToFrozenDictionary();\n                _lastRegeneratedCacheTimestamp = currentTimestamp;\n            }\n\n            return isMigratable;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        bool IsStatelessWorker(GrainType grainType) =>\n            _strategyResolver.GetPlacementStrategy(grainType).GetType() == typeof(StatelessWorkerPlacement);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        bool IsImmovable(GrainType grainType)\n        {\n            if (_localManifest.Grains.TryGetValue(grainType, out var props))\n            {\n                // If there is no 'Immovable' property, it is not immovable.\n                if (!props.Properties.TryGetValue(WellKnownGrainTypeProperties.Immovable, out var value))\n                {\n                    return false;\n                }\n\n                // If the value fails to parse, assume it's immovable.\n                if (!byte.TryParse(value, out var actualKindValue))\n                {\n                    return true;\n                }\n\n                // It is immovable, but does the kind match with the parameter.\n                return ((ImmovableKind)actualKindValue & expectedKind) == expectedKind;\n            }\n\n            // Assume unknown grains are immovable.\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/HashBasedPlacementDirector.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    internal class HashBasedPlacementDirector : IPlacementDirector\n    {\n        public virtual Task<SiloAddress> OnAddActivation(\n            PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            var compatibleSilos = context.GetCompatibleSilos(target);\n\n            // If a valid placement hint was specified, use it.\n            if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint)\n            {\n                return Task.FromResult(placementHint);\n            }\n\n            var sortedSilos = compatibleSilos.OrderBy(s => s).ToArray(); // need to sort the list, so that the outcome is deterministic\n            int hash = (int) (target.GrainIdentity.GetUniformHashCode() & 0x7fffffff); // reset highest order bit to avoid negative ints\n\n            return Task.FromResult(sortedSilos[hash % sortedSilos.Length]);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/IPlacementStrategyResolver.cs",
    "content": "using Orleans.Metadata;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Associates a <see cref=\"PlacementStrategy\"/> with a <see cref=\"GrainType\"/>.\n    /// </summary>\n    public interface IPlacementStrategyResolver\n    {\n        /// <summary>\n        /// Gets the placement strategy associated with the provided grain type.\n        /// </summary>\n        bool TryResolvePlacementStrategy(GrainType grainType, GrainProperties properties, out PlacementStrategy result);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/ISiloStatisticsChangeListener.cs",
    "content": "﻿namespace Orleans.Runtime\n{\n    internal interface ISiloStatisticsChangeListener\n    {\n        /// <summary>\n        /// Receive notification when new statistics data arrives.\n        /// </summary>\n        /// <param name=\"updatedSilo\">Updated silo.</param>\n        /// <param name=\"newStats\">New Silo statistics.</param>\n        void SiloStatisticsChangeNotification(SiloAddress updatedSilo, SiloRuntimeStatistics newStats);\n\n        void RemoveSilo(SiloAddress removedSilo);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/PlacementDirectorResolver.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Responsible for resolving an <see cref=\"IPlacementDirector\"/> for a <see cref=\"PlacementStrategy\"/>.\n    /// </summary>\n    public sealed class PlacementDirectorResolver\n    {\n        private readonly IServiceProvider _services;\n\n        public PlacementDirectorResolver(IServiceProvider services)\n        {\n            _services = services;\n        }\n\n        public IPlacementDirector GetPlacementDirector(PlacementStrategy placementStrategy) => _services.GetRequiredKeyedService<IPlacementDirector>(placementStrategy.GetType());\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/PlacementService.cs",
    "content": "using System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Diagnostics;\nusing Orleans.Placement;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Internal;\nusing Orleans.Runtime.Placement.Filtering;\nusing Orleans.Runtime.Versions;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Central point for placement decisions.\n    /// </summary>\n    internal partial class PlacementService : IPlacementContext\n    {\n        private const int PlacementWorkerCount = 16;\n        private readonly PlacementStrategyResolver _strategyResolver;\n        private readonly PlacementDirectorResolver _directorResolver;\n        private readonly ILogger<PlacementService> _logger;\n        private readonly GrainLocator _grainLocator;\n        private readonly GrainVersionManifest _grainInterfaceVersions;\n        private readonly CachedVersionSelectorManager _versionSelectorManager;\n        private readonly ISiloStatusOracle _siloStatusOracle;\n        private readonly bool _assumeHomogeneousSilosForTesting;\n        private readonly PlacementWorker[] _workers;\n        private readonly PlacementFilterStrategyResolver _filterStrategyResolver;\n        private readonly PlacementFilterDirectorResolver _placementFilterDirectoryResolver;\n\n        /// <summary>\n        /// Create a <see cref=\"PlacementService\"/> instance.\n        /// </summary>\n        public PlacementService(\n            IOptionsMonitor<SiloMessagingOptions> siloMessagingOptions,\n            ILocalSiloDetails localSiloDetails,\n            ISiloStatusOracle siloStatusOracle,\n            ILogger<PlacementService> logger,\n            GrainLocator grainLocator,\n            GrainVersionManifest grainInterfaceVersions,\n            CachedVersionSelectorManager versionSelectorManager,\n            PlacementDirectorResolver directorResolver,\n            PlacementStrategyResolver strategyResolver,\n            PlacementFilterStrategyResolver filterStrategyResolver,\n            PlacementFilterDirectorResolver placementFilterDirectoryResolver)\n        {\n            LocalSilo = localSiloDetails.SiloAddress;\n            _strategyResolver = strategyResolver;\n            _directorResolver = directorResolver;\n            _filterStrategyResolver = filterStrategyResolver;\n            _placementFilterDirectoryResolver = placementFilterDirectoryResolver;\n            _logger = logger;\n            _grainLocator = grainLocator;\n            _grainInterfaceVersions = grainInterfaceVersions;\n            _versionSelectorManager = versionSelectorManager;\n            _siloStatusOracle = siloStatusOracle;\n            _assumeHomogeneousSilosForTesting = siloMessagingOptions.CurrentValue.AssumeHomogenousSilosForTesting;\n            _workers = new PlacementWorker[PlacementWorkerCount];\n            for (var i = 0; i < PlacementWorkerCount; i++)\n            {\n                _workers[i] = new(this);\n            }\n        }\n\n        public SiloAddress LocalSilo { get; }\n\n        public SiloStatus LocalSiloStatus => _siloStatusOracle.CurrentStatus;\n\n        /// <summary>\n        /// Gets or places an activation.\n        /// </summary>\n        public Task AddressMessage(Message message)\n        {\n            if (message.IsTargetFullyAddressed) return Task.CompletedTask;\n            if (message.TargetGrain.IsDefault) ThrowMissingAddress();\n\n            var grainId = message.TargetGrain;\n            if (_grainLocator.TryLookupInCache(grainId, out var result) && CachedAddressIsValid(message, result))\n            {\n                LogDebugFoundAddress(result, grainId, message);\n                SetMessageTargetPlacement(message, result.SiloAddress);\n                return Task.CompletedTask;\n            }\n\n            LogDebugLookingUpAddress(grainId, message);\n            var worker = _workers[grainId.GetUniformHashCode() % PlacementWorkerCount];\n            return worker.AddressMessage(message);\n\n            static void ThrowMissingAddress() => throw new InvalidOperationException(\"Cannot address a message without a target\");\n        }\n\n        private void SetMessageTargetPlacement(Message message, SiloAddress targetSilo)\n        {\n            message.TargetSilo = targetSilo;\n            LogTraceAddressMessageSelectTarget(message);\n        }\n\n        public SiloAddress[] GetCompatibleSilos(PlacementTarget target)\n        {\n            // For test only: if we have silos that are not yet in the Cluster TypeMap, we assume that they are compatible\n            // with the current silo\n            if (_assumeHomogeneousSilosForTesting)\n            {\n                return AllActiveSilos;\n            }\n\n            var grainType = target.GrainIdentity.Type;\n            var silos = target.InterfaceVersion > 0\n                ? _versionSelectorManager.GetSuitableSilos(grainType, target.InterfaceType, target.InterfaceVersion).SuitableSilos\n                : _grainInterfaceVersions.GetSupportedSilos(grainType).Result;\n\n            var compatibleSilos = silos.Intersect(AllActiveSilos).ToArray();\n\n            var filters = _filterStrategyResolver.GetPlacementFilterStrategies(grainType);\n            if (filters.Length > 0)\n            {\n                // Capture the parent activity context now so each filter span is parented to the\n                // current activity (e.g. PlaceGrain) rather than to sibling filter spans that may\n                // be active during deferred enumeration.\n                var parentActivityContext = Activity.Current?.Context;\n\n                IEnumerable<SiloAddress> filteredSilos = compatibleSilos;\n                foreach (var placementFilter in filters)\n                {\n                    var director = _placementFilterDirectoryResolver.GetFilterDirector(placementFilter);\n                    filteredSilos = InstrumentFilteredSilos(\n                        director.Filter(placementFilter, target, filteredSilos),\n                        placementFilter,\n                        grainType,\n                        parentActivityContext);\n                }\n\n                compatibleSilos = filteredSilos.ToArray();\n            }\n\n            if (compatibleSilos.Length == 0)\n            {\n                var allWithType = _grainInterfaceVersions.GetSupportedSilos(grainType).Result;\n                var versions = _grainInterfaceVersions.GetSupportedSilos(target.InterfaceType, target.InterfaceVersion).Result;\n                var allWithTypeString = string.Join(\", \", allWithType.Select(s => s.ToString())) is string withGrain && !string.IsNullOrWhiteSpace(withGrain) ? withGrain : \"none\";\n                var allWithInterfaceString = string.Join(\", \", versions.Select(s => s.ToString())) is string withIface && !string.IsNullOrWhiteSpace(withIface) ? withIface : \"none\";\n                throw new OrleansException(\n                    $\"No active nodes are compatible with grain {grainType} and interface {target.InterfaceType} version {target.InterfaceVersion}. \"\n                    + $\"Known nodes with grain type: {allWithTypeString}. \"\n                    + $\"All known nodes compatible with interface version: {allWithInterfaceString}\");\n            }\n\n            return compatibleSilos;\n        }\n\n        public SiloAddress[] AllActiveSilos\n        {\n            get\n            {\n                var result = _siloStatusOracle.GetApproximateSiloStatuses(true).Keys.ToArray();\n                if (result.Length > 0) return result;\n\n                LogWarningAllActiveSilos();\n                return new SiloAddress[] { LocalSilo };\n            }\n        }\n\n        public IReadOnlyDictionary<ushort, SiloAddress[]> GetCompatibleSilosWithVersions(PlacementTarget target)\n        {\n            if (target.InterfaceVersion == 0)\n            {\n                throw new ArgumentException(\"Interface version not provided\", nameof(target));\n            }\n\n            var grainType = target.GrainIdentity.Type;\n            var silos = _versionSelectorManager\n                .GetSuitableSilos(grainType, target.InterfaceType, target.InterfaceVersion)\n                .SuitableSilosByVersion;\n\n            return silos;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private bool CachedAddressIsValid(Message message, GrainAddress cachedAddress)\n        {\n            // Verify that the result from the cache has not been invalidated by the message being addressed.\n            if (message.CacheInvalidationHeader is { } cacheUpdates)\n            {\n                lock (cacheUpdates)\n                {\n                    return CachedAddressIsValidCore(message, cachedAddress, cacheUpdates);\n                }\n            }\n\n            return true;\n\n            [MethodImpl(MethodImplOptions.NoInlining)]\n            bool CachedAddressIsValidCore(Message message, GrainAddress cachedAddress, List<GrainAddressCacheUpdate> cacheUpdates)\n            {\n                var resultIsValid = true;\n                LogDebugInvalidatingCachedEntries(cacheUpdates.Count, message);\n\n                foreach (var update in cacheUpdates)\n                {\n                    // Invalidate/update cache entries while we are examining them.\n                    var invalidAddress = update.InvalidGrainAddress;\n                    var validAddress = update.ValidGrainAddress;\n                    _grainLocator.UpdateCache(update);\n\n                    if (cachedAddress.Matches(validAddress))\n                    {\n                        resultIsValid = true;\n                    }\n                    else if (cachedAddress.Matches(invalidAddress))\n                    {\n                        resultIsValid = false;\n                    }\n                }\n\n                return resultIsValid;\n            }\n        }\n\n        /// <summary>\n        /// Places a grain without considering the grain's existing location, if any.\n        /// </summary>\n        /// <param name=\"grainId\">The grain id of the grain being placed.</param>\n        /// <param name=\"requestContextData\">The request context, which will be available to the placement strategy.</param>\n        /// <param name=\"placementStrategy\">The placement strategy to use.</param>\n        /// <returns>A location for the new activation.</returns>\n        public async Task<SiloAddress> PlaceGrainAsync(GrainId grainId, Dictionary<string, object> requestContextData, PlacementStrategy placementStrategy)\n        {\n            using var _ = TryRestoreActivityContext(requestContextData, ActivityNames.PlaceGrain);\n            var target = new PlacementTarget(grainId, requestContextData, default, 0);\n            var director = _directorResolver.GetPlacementDirector(placementStrategy);\n            return await director.OnAddActivation(placementStrategy, target, this);\n        }\n\n        private class PlacementWorker\n        {\n            private readonly Dictionary<GrainId, GrainPlacementWorkItem> _inProgress = new();\n            private readonly SingleWaiterAutoResetEvent _workSignal = new() { RunContinuationsAsynchronously = true };\n            private readonly ILogger _logger;\n#pragma warning disable IDE0052 // Remove unread private members. Justification: retained for debugging purposes\n            private readonly Task _processLoopTask;\n#pragma warning restore IDE0052 // Remove unread private members\n#if NET9_0_OR_GREATER\n            private readonly Lock _lockObj = new();\n#else\n            private readonly object _lockObj = new();\n#endif\n            private readonly PlacementService _placementService;\n            private List<(Message Message, TaskCompletionSource Completion)> _messages = new();\n\n            public PlacementWorker(PlacementService placementService)\n            {\n                _logger = placementService._logger;\n                _placementService = placementService;\n\n                using var _ = new ExecutionContextSuppressor();\n                _processLoopTask = Task.Run(ProcessLoop);\n            }\n\n            public Task AddressMessage(Message message)\n            {\n                var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n                lock (_lockObj)\n                {\n                    _messages ??= new();\n                    _messages.Add((message, completion));\n                }\n\n                _workSignal.Signal();\n                return completion.Task;\n            }\n\n            private List<(Message Message, TaskCompletionSource Completion)> GetMessages()\n            {\n                lock (_lockObj)\n                {\n                    if (_messages is { Count: > 0 } result)\n                    {\n                        _messages = null;\n                        return result;\n                    }\n\n                    return null;\n                }\n            }\n\n            private async Task ProcessLoop()\n            {\n                Action signalWaiter = _workSignal.Signal;\n                while (true)\n                {\n                    try\n                    {\n                        // Start processing new requests\n                        var messages = GetMessages();\n                        if (messages is not null)\n                        {\n                            foreach (var message in messages)\n                            {\n                                var target = message.Message.TargetGrain;\n                                var workItem = GetOrAddWorkItem(target);\n                                workItem.Messages.Add(message);\n                                if (workItem.Result is null)\n                                {\n                                    // Note that the first message is used as the target to place the message,\n                                    // so if subsequent messages do not agree with the first message's interface\n                                    // type or version, then they may be sent to an incompatible silo, which is\n                                    // fine since the remote silo will handle that incompatibility.\n                                    workItem.Result = GetOrPlaceActivationAsync(message.Message);\n\n                                    // Wake up this processing loop when the task completes\n                                    workItem.Result.GetAwaiter().UnsafeOnCompleted(signalWaiter);\n                                }\n                            }\n                        }\n\n                        // Complete processing any completed request\n                        foreach (var pair in _inProgress)\n                        {\n                            var workItem = pair.Value;\n                            if (workItem.Result.IsCompleted)\n                            {\n                                AddressWaitingMessages(workItem);\n                                _inProgress.Remove(pair.Key);\n                            }\n                        }\n                    }\n                    catch (Exception exception)\n                    {\n                        LogWarnInPlacementWorker(_logger, exception);\n                    }\n\n                    await _workSignal.WaitAsync();\n                }\n\n                GrainPlacementWorkItem GetOrAddWorkItem(GrainId target)\n                {\n                    ref var workItem = ref CollectionsMarshal.GetValueRefOrAddDefault(_inProgress, target, out _);\n                    workItem ??= new();\n                    return workItem;\n                }\n            }\n\n            private void AddressWaitingMessages(GrainPlacementWorkItem completedWorkItem)\n            {\n                var resultTask = completedWorkItem.Result;\n                var messages = completedWorkItem.Messages;\n\n                try\n                {\n                    var siloAddress = resultTask.GetAwaiter().GetResult();\n                    foreach (var message in messages)\n                    {\n                        _placementService.SetMessageTargetPlacement(message.Message, siloAddress);\n                        message.Completion.TrySetResult();\n                    }\n                }\n                catch (Exception exception)\n                {\n                    var originalException = exception switch\n                    {\n                        AggregateException ae when ae.InnerExceptions.Count == 1 => ae.InnerException,\n                        _ => exception,\n                    };\n\n                    foreach (var message in messages)\n                    {\n                        message.Completion.TrySetException(originalException);\n                    }\n                }\n\n                messages.Clear();\n            }\n\n            private async Task<SiloAddress> GetOrPlaceActivationAsync(Message firstMessage)\n            {\n                await Task.Yield();\n\n                // InnerGetOrPlaceActivationAsync may set a new activity as current from the RequestContextData,\n                // so we need to save and restore the current activity.\n                var currentActivity = Activity.Current;\n                var activationLocation = await InnerGetOrPlaceActivationAsync();\n                Activity.Current = currentActivity;\n\n                return activationLocation;\n\n                async Task<SiloAddress> InnerGetOrPlaceActivationAsync()\n                {\n                    // Restore activity context from the message's request context data\n                    // This ensures directory lookups are properly traced as children of the original request\n                    using var restoredActivity = TryRestoreActivityContext(firstMessage.RequestContextData, ActivityNames.PlaceGrain);\n\n                    var target = new PlacementTarget(\n                        firstMessage.TargetGrain,\n                        firstMessage.RequestContextData,\n                        firstMessage.InterfaceType,\n                        firstMessage.InterfaceVersion);\n\n                    var targetGrain = target.GrainIdentity;\n                    var result = await _placementService._grainLocator.Lookup(targetGrain);\n                    if (result is not null)\n                    {\n                        return result.SiloAddress;\n                    }\n\n                    var strategy = _placementService._strategyResolver.GetPlacementStrategy(target.GrainIdentity.Type);\n                    var director = _placementService._directorResolver.GetPlacementDirector(strategy);\n                    var siloAddress = await director.OnAddActivation(strategy, target, _placementService);\n\n                    // Give the grain locator one last chance to tell us that the grain has already been placed\n                    if (_placementService._grainLocator.TryLookupInCache(targetGrain, out result) && _placementService.CachedAddressIsValid(firstMessage, result))\n                    {\n                        return result.SiloAddress;\n                    }\n\n                    _placementService._grainLocator.InvalidateCache(targetGrain);\n                    _placementService._grainLocator.UpdateCache(targetGrain, siloAddress);\n                    return siloAddress;\n                }\n            }\n\n            private class GrainPlacementWorkItem\n            {\n                public List<(Message Message, TaskCompletionSource Completion)> Messages { get; } = new();\n\n                public Task<SiloAddress> Result { get; set; }\n            }\n        }\n\n        /// <summary>\n        /// Wraps a filter's output enumerable so that an Activity span is created when the\n        /// sequence is actually enumerated, not when the filter is composed. This avoids\n        /// per-filter array materialization while still giving accurate span timings.\n        /// </summary>\n        private static IEnumerable<SiloAddress> InstrumentFilteredSilos(\n            IEnumerable<SiloAddress> silos,\n            PlacementFilterStrategy filter,\n            GrainType grainType,\n            ActivityContext? parentActivityContext)\n        {\n            using var filterSpan = parentActivityContext is { } parentContext\n                ? ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.FilterPlacementCandidates, ActivityKind.Internal, parentContext)\n                : ActivitySources.LifecycleGrainSource.StartActivity(ActivityNames.FilterPlacementCandidates);\n            filterSpan?.SetTag(ActivityTagKeys.PlacementFilterType, filter.GetType().Name);\n            filterSpan?.SetTag(ActivityTagKeys.GrainType, grainType.ToString());\n\n            foreach (var silo in silos)\n            {\n                yield return silo;\n            }\n        }\n\n        /// <summary>\n        /// Attempts to restore the parent activity context from request context data.\n        /// </summary>\n        private static Activity TryRestoreActivityContext(Dictionary<string, object> requestContextData, string operationName)\n        {\n            if (requestContextData is null)\n            {\n                return null;\n            }\n\n            var activityContext = requestContextData.TryGetActivityContext();\n\n            if (activityContext is {} parentContext)\n            {\n                // Start the activity from the Catalog's ActivitySource to properly associate it with activation tracing\n                return ActivitySources.LifecycleGrainSource.StartActivity(operationName, ActivityKind.Internal, parentContext);\n            }\n\n            return null;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Found address {Address} for grain {GrainId} in cache for message {Message}\"\n        )]\n        private partial void LogDebugFoundAddress(GrainAddress address, GrainId grainId, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Looking up address for grain {GrainId} for message {Message}\"\n        )]\n        private partial void LogDebugLookingUpAddress(GrainId grainId, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"AddressMessage Placement SelectTarget {Message}\"\n        )]\n        private partial void LogTraceAddressMessageSelectTarget(Message message);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Catalog_GetApproximateSiloStatuses,\n            Level = LogLevel.Warning,\n            Message = \"AllActiveSilos SiloStatusOracle.GetApproximateSiloStatuses empty\"\n        )]\n        private partial void LogWarningAllActiveSilos();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Invalidating {Count} cached entries for message {Message}\"\n        )]\n        private partial void LogDebugInvalidatingCachedEntries(int count, Message message);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error in placement worker.\"\n        )]\n        private static partial void LogWarnInPlacementWorker(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/PlacementStrategyResolver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Linq;\nusing Orleans.Metadata;\nusing System.Collections.Immutable;\nusing System.Collections.Concurrent;\nusing Orleans.Runtime.Hosting;\nusing System.Collections.Frozen;\nusing Orleans.GrainDirectory;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// Responsible for resolving an <see cref=\"PlacementStrategy\"/> for a <see cref=\"GrainType\"/>.\n    /// </summary>\n    public sealed class PlacementStrategyResolver\n    {\n        private readonly ConcurrentDictionary<GrainType, PlacementStrategy> _resolvedStrategies = new();\n        private readonly Func<GrainType, PlacementStrategy> _getStrategyInternal;\n        private readonly IPlacementStrategyResolver[] _resolvers;\n        private readonly GrainPropertiesResolver _grainPropertiesResolver;\n        private readonly PlacementStrategy _defaultPlacementStrategy;\n        private readonly IServiceProvider _services;\n\n        /// <summary>\n        /// Create a <see cref=\"PlacementStrategyResolver\"/> instance.\n        /// </summary>\n        public PlacementStrategyResolver(\n            IServiceProvider services,\n            IEnumerable<IPlacementStrategyResolver> resolvers,\n            GrainPropertiesResolver grainPropertiesResolver)\n        {\n            _services = services;\n            _getStrategyInternal = GetPlacementStrategyInternal;\n            _resolvers = resolvers.ToArray();\n            _grainPropertiesResolver = grainPropertiesResolver;\n            _defaultPlacementStrategy = services.GetService<PlacementStrategy>();\n        }\n\n        /// <summary>\n        /// Gets the placement strategy associated with the provided grain type.\n        /// </summary>\n        public PlacementStrategy GetPlacementStrategy(GrainType grainType) => _resolvedStrategies.GetOrAdd(grainType, _getStrategyInternal);\n\n        private bool TryGetNonDefaultPlacementStrategy(GrainType grainType, out PlacementStrategy strategy)\n        {\n            _grainPropertiesResolver.TryGetGrainProperties(grainType, out var properties);\n\n            foreach (var resolver in _resolvers)\n            {\n                if (resolver.TryResolvePlacementStrategy(grainType, properties, out strategy))\n                {\n                    return true;\n                }\n            }\n\n            if (properties is not null\n                && properties.Properties.TryGetValue(WellKnownGrainTypeProperties.PlacementStrategy, out var placementStrategyId)\n                && !string.IsNullOrWhiteSpace(placementStrategyId))\n            {\n                strategy = _services.GetKeyedService<PlacementStrategy>(placementStrategyId);\n                if (strategy is not null)\n                {\n                    strategy.Initialize(properties);\n                    return true;\n                }\n                else\n                {\n                    throw new KeyNotFoundException($\"Could not resolve placement strategy {placementStrategyId} for grain type {grainType}.\");\n                }\n            }\n\n            strategy = default;\n            return false;\n        }\n\n        private PlacementStrategy GetPlacementStrategyInternal(GrainType grainType)\n        {\n            if (TryGetNonDefaultPlacementStrategy(grainType, out var result))\n            {\n                return result;\n            }\n\n            return _defaultPlacementStrategy;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/PreferLocalPlacementDirector.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    /// <summary>\n    /// PreferLocalPlacementDirector is a single activation placement.\n    /// It is similar to RandomPlacementDirector except for how new activations are placed.\n    /// When activation is requested (OnSelectActivation), it uses the same algorithm as RandomPlacementDirector to pick one if one already exists.\n    /// That is, it checks with the Distributed Directory.\n    /// If none exits, it prefers to place a new one in the local silo. If there are no races (only one silo at a time tries to activate this grain),\n    /// the local silo wins. In the case of concurrent activations of the first activation of this grain, only one silo wins.\n    /// </summary>\n    internal class PreferLocalPlacementDirector : RandomPlacementDirector, IPlacementDirector\n    {\n        private Task<SiloAddress> _cachedLocalSilo;\n\n        public override Task<SiloAddress> \n            OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            // if local silo is not active or does not support this type of grain, revert to random placement\n            if (context.LocalSiloStatus != SiloStatus.Active || !context.GetCompatibleSilos(target).Contains(context.LocalSilo))\n            {\n                return base.OnAddActivation(strategy, target, context);\n            }\n\n            return _cachedLocalSilo ??= Task.FromResult(context.LocalSilo);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/RandomPlacementDirector.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    internal class RandomPlacementDirector : IPlacementDirector\n    {\n        public virtual Task<SiloAddress> OnAddActivation(\n            PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            var compatibleSilos = context.GetCompatibleSilos(target);\n\n            // If a valid placement hint was specified, use it.\n            if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint)\n            {\n                return Task.FromResult(placementHint);\n            }\n\n            return Task.FromResult(compatibleSilos[Random.Shared.Next(compatibleSilos.Length)]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Rebalancing/ActivationRebalancerMonitor.cs",
    "content": "using System;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing System.Threading.Tasks;\nusing Orleans.Placement.Rebalancing;\nusing System.Collections.Immutable;\nusing Microsoft.Extensions.Logging;\nusing System.Collections.Generic;\nusing System.Threading;\nusing Orleans.Runtime.Scheduler;\n\n#nullable enable\n\nnamespace Orleans.Runtime.Placement.Rebalancing;\n\ninternal sealed partial class ActivationRebalancerMonitor : SystemTarget, IActivationRebalancerMonitor, ILifecycleParticipant<ISiloLifecycle>\n{\n    private IGrainTimer? _monitorTimer;\n    private RebalancingReport _latestReport;\n    private long _lastHeartbeatTimestamp;\n\n    private readonly TimeProvider _timeProvider;\n    private readonly ActivationDirectory _activationDirectory;\n    private readonly IActivationRebalancerWorker _rebalancerGrain;\n    private readonly ILogger<ActivationRebalancerMonitor> _logger;\n    private readonly List<IActivationRebalancerReportListener> _statusListeners = [];\n\n    // Check on the worker with double the period the worker reports to me.\n    private readonly static TimeSpan TimerPeriod = 2 * IActivationRebalancerMonitor.WorkerReportPeriod;\n\n    public ActivationRebalancerMonitor(\n        TimeProvider timeProvider,\n        ActivationDirectory activationDirectory,\n        ILoggerFactory loggerFactory,\n        IGrainFactory grainFactory,\n        SystemTargetShared shared)\n        : base(Constants.ActivationRebalancerMonitorType, shared)\n    {\n        _timeProvider = timeProvider;\n        _activationDirectory = activationDirectory;\n        _logger = loggerFactory.CreateLogger<ActivationRebalancerMonitor>();\n        _rebalancerGrain = grainFactory.GetGrain<IActivationRebalancerWorker>(0);\n        _lastHeartbeatTimestamp = _timeProvider.GetTimestamp();\n\n        _latestReport = new()\n        {\n            ClusterImbalance = 1,\n            Host = SiloAddress.Zero,\n            Status = RebalancerStatus.Suspended,\n            SuspensionDuration = Timeout.InfiniteTimeSpan,\n            Statistics = []\n        };\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    public void Participate(ISiloLifecycle observer)\n    {\n        observer.Subscribe(\n           nameof(ActivationRepartitioner),\n           ServiceLifecycleStage.Active,\n           OnStart,\n           _ => Task.CompletedTask);\n\n        observer.Subscribe(\n           nameof(ActivationRepartitioner),\n           ServiceLifecycleStage.ApplicationServices,\n           _ => Task.CompletedTask,\n           OnStop);\n    }\n\n    private async Task OnStart(CancellationToken cancellationToken)\n    {\n        await this.RunOrQueueTask(() =>\n        {\n            _monitorTimer = RegisterGrainTimer(async ct =>\n            {\n                var elapsedSinceHeartbeat = _timeProvider.GetElapsedTime(_lastHeartbeatTimestamp);\n                var shouldFetchReport = _latestReport.Host == SiloAddress.Zero\n                    || elapsedSinceHeartbeat >= IActivationRebalancerMonitor.WorkerReportPeriod;\n                if (shouldFetchReport)\n                {\n                    LogStartingRebalancer(elapsedSinceHeartbeat, IActivationRebalancerMonitor.WorkerReportPeriod);\n                    _latestReport = await _rebalancerGrain.GetReport().AsTask().WaitAsync(ct);\n                }\n\n            }, TimeSpan.Zero, TimerPeriod);\n\n            return Task.CompletedTask;\n        });\n    }\n\n    private async Task OnStop(CancellationToken cancellationToken)\n    {\n        await this.RunOrQueueTask(() =>\n        {\n            if (_latestReport is { } report && Silo.IsSameLogicalSilo(report.Host))\n            {\n                if (_activationDirectory.FindTarget(_rebalancerGrain.GetGrainId()) is { } activation)\n                {\n                    LogMigratingRebalancer(Silo);\n                    activation.Migrate(null, cancellationToken); // migrate it anywhere else\n                }\n            }\n\n            _monitorTimer?.Dispose();\n            return Task.CompletedTask;\n        });\n    }\n\n    public Task ResumeRebalancing() => _rebalancerGrain.ResumeRebalancing();\n    public Task SuspendRebalancing(TimeSpan? duration) => _rebalancerGrain.SuspendRebalancing(duration);\n\n    public async ValueTask<RebalancingReport> GetRebalancingReport(bool force = false)\n    {\n        if (force)\n        {\n            _latestReport = await _rebalancerGrain.GetReport();\n        }\n\n        return _latestReport;\n    }\n\n    public Task Report(RebalancingReport report)\n    {\n        _latestReport = report;\n        _lastHeartbeatTimestamp = _timeProvider.GetTimestamp();\n\n        foreach (var listener in _statusListeners)\n        {\n            try\n            {\n                listener.OnReport(report);\n            }\n            catch (Exception ex)\n            {\n                LogErrorWhileNotifyingListener(ex);\n            }\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public void SubscribeToReports(IActivationRebalancerReportListener listener)\n    {\n        if (!_statusListeners.Contains(listener))\n        {\n            _statusListeners.Add(listener);\n        }\n    }\n\n    public void UnsubscribeFromReports(IActivationRebalancerReportListener listener) =>\n        _statusListeners.Remove(listener);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"I have not received a report from the activation rebalancer for the last {Duration} which is more than the \" +\n        \"allowed interval {Period}. I will now try to wake it up with the assumption that it has has been stopped ungracefully.\"\n    )]\n    private partial void LogStartingRebalancer(TimeSpan duration, TimeSpan period);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"My silo '{Silo}' is stopping now, and I am the host of the activation rebalancer. \" +\n        \"I will attempt to migrate the rebalancer to another silo.\"\n    )]\n    private partial void LogMigratingRebalancer(SiloAddress silo);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"An unexpected error occurred while notifying rebalancer listener.\"\n    )]\n    private partial void LogErrorWhileNotifyingListener(Exception exception);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Rebalancing/ActivationRebalancerWorker.Log.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Statistics;\n\nnamespace Orleans.Runtime.Placement.Rebalancing;\n\ninternal partial class ActivationRebalancerWorker\n{\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Activation rebalancer has been scheduled to start after {DueTime}.\")]\n    private partial void LogScheduledToStart(TimeSpan dueTime);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"I have started a new rebalancing session.\")]\n    private partial void LogSessionStarted();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"I have stopped my current rebalancing session.\")]\n    private partial void LogSessionStopped();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"I have been told to suspend rebalancing indefinitely.\")]\n    private partial void LogSuspended();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"I have been told to suspend rebalancing for {Duration}.\")]\n    private partial void LogSuspendedFor(TimeSpan duration);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Can not continue with rebalancing because there are less than 2 silos.\")]\n    private partial void LogNotEnoughSilos();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Can not continue with rebalancing because I have statistics information for less than 2 silos.\")]\n    private partial void LogNotEnoughStatistics();\n\n    [LoggerMessage(Level = LogLevel.Warning, Message =\n        \"Can not continue with rebalancing because at least one of the silos is reporting 0 memory usage. \" +\n        $\"This can indicate that there is no implementation of {nameof(IEnvironmentStatisticsProvider)}.\")]\n    private partial void LogInvalidSiloMemory();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"The current rebalancing session has stopped due to {StagnantCycles} stagnant cycles having passed, which is the maximum allowed.\")]\n    private partial void LogMaxStagnantCyclesReached(int stagnantCycles);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message =\n        \"The current rebalancing session has stopped due to a {EntropyDeviation} \" +\n        \"entropy deviation between the current {CurrentEntropy} and maximum possible {MaximumEntropy}. \" +\n        \"The difference is less than the required {AllowedEntropyDeviation} deviation.\")]\n    private partial void LogMaxEntropyDeviationReached(double entropyDeviation, double currentEntropy, double maximumEntropy, double allowedEntropyDeviation);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message =\n        \"The relative change in entropy {EntropyChange} is less than the quantum {EntropyQuantum}. \" +\n        \"This is practically not considered an improvement, therefore this cycle will be marked as stagnant.\")]\n    private partial void LogInsufficientEntropyQuantum(double entropyChange, double entropyQuantum);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Stagnant cycle count has been reset as we are improving now.\")]\n    private partial void LogStagnantCyclesReset();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Failed session count has been reset as we are improving now.\")]\n    private partial void LogFailedSessionsReset();\n\n    [LoggerMessage(Level = LogLevel.Trace, Message =\n        \"I have decided to migrate {Delta} activations.\\n\" +\n        \"Adjusted activations for {LowSilo} will be [{LowSiloPreActivations} -> {LowSiloPostActivations}].\\n\" +\n        \"Adjusted activations for {HighSilo} will be [{HighSiloPreActivations} -> {HighSiloPostActivations}].\")]\n    private partial void LogSiloMigrations(int delta,\n        SiloAddress lowSilo, int lowSiloPreActivations, int lowSiloPostActivations,\n        SiloAddress highSilo, int highSiloPreActivations, int highSiloPostActivations);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message =\n        \"Rebalancing cycle {RebalancingCycle} has finished. \" +\n        \"[ Stagnant Cycles: {StagnantCycles} | Previous Entropy: {PreviousEntropy} | \" +\n        \"Current Entropy: {CurrentEntropy} | Maximum Entropy: {MaximumEntropy} | Entropy Deviation: {EntropyDeviation} ]\")]\n    private partial void LogCycleOutcome(\n        int rebalancingCycle, int stagnantCycles, double previousEntropy,\n        double currentEntropy, double maximumEntropy, double entropyDeviation);\n}"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Rebalancing/ActivationRebalancerWorker.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Placement;\nusing Orleans.Placement.Rebalancing;\n\n#nullable enable\n\nnamespace Orleans.Runtime.Placement.Rebalancing;\n\n// See: https://www.ledjonbehluli.com/posts/orleans_adaptive_rebalancing/\n\n[KeepAlive, Immovable]\ninternal sealed partial class ActivationRebalancerWorker(\n    DeploymentLoadPublisher loadPublisher,\n    ILoggerFactory loggerFactory,\n    ISiloStatusOracle siloStatusOracle,\n    IInternalGrainFactory grainFactory,\n    ILocalSiloDetails localSiloDetails,\n    IOptions<ActivationRebalancerOptions> options,\n    IFailedSessionBackoffProvider backoffProvider)\n        : Grain, IActivationRebalancerWorker, ISiloStatisticsChangeListener, IGrainMigrationParticipant\n{\n    private readonly record struct ResourceStatistics(long MemoryUsage, int ActivationCount);\n\n    [GenerateSerializer, Immutable, Alias(\"RebalancerState\")]\n    internal readonly record struct RebalancerState(\n        int StagnantCycles, int FailedSessions,\n        int RebalancingCycle, double LatestEntropy, double EntropyDeviation,\n        TimeSpan? SuspensionDuration, ImmutableArray<RebalancingStatistics> Statistics);\n\n    private enum StopReason\n    {\n        /// <summary>\n        /// A new session is about to start.\n        /// </summary>\n        SessionStarting,\n        /// <summary>\n        /// Current session has stagnated.\n        /// </summary>\n        SessionStagnated,\n        /// <summary>\n        /// Current session has completed successfully till end\n        /// </summary>\n        SessionCompleted,\n        /// <summary>\n        /// Rebalancer was asked to suspend activity.\n        /// </summary>\n        RebalancerSuspended\n    }\n\n    private const string StateKey = \"REBALANCER_STATE\";\n\n    private int _stagnantCycles;\n    private int _failedSessions;\n    private int _rebalancingCycle;\n    private double _previousEntropy;\n    private double _entropyDeviation;\n    private long _suspendedUntilTs;\n    private IGrainTimer? _sessionTimer;\n    private IGrainTimer? _triggerTimer;\n    private IGrainTimer? _monitorTimer;\n\n    private readonly ActivationRebalancerOptions _options = options.Value;\n    private readonly Dictionary<SiloAddress, ResourceStatistics> _siloStatistics = [];\n    private readonly Dictionary<SiloAddress, RebalancingStatistics> _rebalancingStatistics = [];\n    private readonly ILogger<ActivationRebalancerWorker> _logger = loggerFactory.CreateLogger<ActivationRebalancerWorker>();\n\n    private TimeSpan? RemainingSuspensionDuration => Runtime.TimeProvider.GetElapsedTime(Runtime.TimeProvider.GetTimestamp(), _suspendedUntilTs) switch\n    {\n        { } result when result > TimeSpan.Zero => result,\n        _ => null\n    };\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        _monitorTimer = this.RegisterGrainTimer(ReportAllMonitors, new()\n        {\n            DueTime = TimeSpan.Zero,\n            Period = IActivationRebalancerMonitor.WorkerReportPeriod,\n        });\n\n        _triggerTimer = this.RegisterGrainTimer(TriggerRebalancing, new()\n        {\n            Interleave = true,\n            Period = 0.5 * _options.SessionCyclePeriod, // Make trigger-period half that of the session cycle-period.\n            DueTime = _options.RebalancerDueTime\n        });\n\n        LogScheduledToStart(_options.RebalancerDueTime);\n\n        loadPublisher.SubscribeToStatisticsChangeEvents(this);\n\n        return Task.CompletedTask;\n    }\n\n    public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n    {\n        loadPublisher.UnsubscribeStatisticsChangeEvents(this);\n        return Task.CompletedTask;\n    }\n\n    public void OnDehydrate(IDehydrationContext context)\n    {\n        context.TryAddValue<RebalancerState>(StateKey,\n            new(_stagnantCycles, _failedSessions, _rebalancingCycle,\n                _previousEntropy, _entropyDeviation, RemainingSuspensionDuration, [.. _rebalancingStatistics.Values]));\n    }\n    \n    public void OnRehydrate(IRehydrationContext context)\n    {\n        if (context.TryGetValue<RebalancerState>(StateKey, out var rebalancerState) &&\n            rebalancerState is { } state)\n        {\n            _rebalancingCycle = state.RebalancingCycle;\n            _stagnantCycles = state.StagnantCycles;\n            _failedSessions = state.FailedSessions;\n            _previousEntropy = state.LatestEntropy;\n            _entropyDeviation = state.EntropyDeviation;\n\n            foreach (var statistics in state.Statistics)\n            {\n                if (siloStatusOracle.IsDeadSilo(statistics.SiloAddress))\n                {\n                    continue;\n                }\n\n                _rebalancingStatistics.TryAdd(statistics.SiloAddress, statistics);\n            }\n\n            if (state.SuspensionDuration is { } value)\n            {\n                SuspendFor(value);\n            }\n        }\n    }\n\n    void ISiloStatisticsChangeListener.RemoveSilo(SiloAddress silo)\n    {\n        GrainContext.Scheduler.QueueAction(() =>\n        {\n            _siloStatistics.Remove(silo);\n            _rebalancingStatistics.Remove(silo); // Remove that silo's rebalancing stats, as it has been removed.\n        });\n    }\n\n    void ISiloStatisticsChangeListener.SiloStatisticsChangeNotification(SiloAddress address, SiloRuntimeStatistics statistics)\n    {\n        GrainContext.Scheduler.QueueAction(()\n            => _siloStatistics[address] = new(statistics.EnvironmentStatistics.FilteredMemoryUsageBytes, statistics.ActivationCount));\n    }\n\n    public ValueTask<RebalancingReport> GetReport() => new(BuildReport());\n\n    public async Task ResumeRebalancing()\n    {\n        StartSession();\n        await ReportAllMonitors(CancellationToken.None);\n    }\n\n    public async Task SuspendRebalancing(TimeSpan? duration)\n    {\n        StopSession(StopReason.RebalancerSuspended, duration);\n        \n        if (duration.HasValue)\n        {\n            LogSuspendedFor(duration.Value);\n        }\n        else\n        {\n            LogSuspended();\n        }\n\n        await ReportAllMonitors(CancellationToken.None);\n    }\n\n    private async Task ReportAllMonitors(CancellationToken cancellationToken)\n    {\n        var tasks = new List<Task>();\n        var report = BuildReport();\n       \n        foreach (var silo in siloStatusOracle.GetActiveSilos())\n        {\n            tasks.Add(grainFactory.GetSystemTarget<IActivationRebalancerMonitor>\n                (Constants.ActivationRebalancerMonitorType, silo).Report(report));\n        }\n\n        await Task.WhenAll(tasks).WaitAsync(cancellationToken);\n    }\n\n    private RebalancingReport BuildReport()\n    {\n        var suspensionRemaining = RemainingSuspensionDuration;\n\n        return new RebalancingReport()\n        {\n            Host = localSiloDetails.SiloAddress,\n            Status = suspensionRemaining is { } ? RebalancerStatus.Suspended : RebalancerStatus.Executing,\n            SuspensionDuration = suspensionRemaining,\n            ClusterImbalance = _entropyDeviation,\n            Statistics = [.. _rebalancingStatistics.Values]\n        };\n    }\n\n    private Task TriggerRebalancing()\n    {\n        if (_sessionTimer != null) \n        {\n            return Task.CompletedTask;\n        }\n\n        if (RemainingSuspensionDuration.HasValue)\n        {\n            return Task.CompletedTask;\n        }\n\n        StartSession();\n        return Task.CompletedTask;\n    }\n\n    private async Task RunRebalancingCycle(CancellationToken cancellationToken)\n    {\n        var siloCount = siloStatusOracle.GetActiveSilos().Length;\n        if (siloCount < 2)\n        {\n            LogNotEnoughSilos();\n            return;\n        }\n\n        var snapshot = _siloStatistics.ToDictionary();\n        if (snapshot.Count < 2)\n        {\n            LogNotEnoughStatistics();\n            return;\n        }\n\n        if (snapshot.Any(x => x.Value.MemoryUsage == 0))\n        {\n            LogInvalidSiloMemory();\n            return;\n        }\n\n        _rebalancingCycle++;\n\n        if (_stagnantCycles >= _options.MaxStagnantCycles)\n        {\n            LogMaxStagnantCyclesReached(_stagnantCycles);\n            StopSession(StopReason.SessionStagnated);\n\n            return;\n        }\n\n        var totalActivations = snapshot.Sum(x => x.Value.ActivationCount);\n        var meanMemoryUsage = ComputeHarmonicMean(snapshot.Values);\n        var maximumEntropy = Math.Log(siloCount);\n        var currentEntropy = ComputeEntropy(snapshot.Values, totalActivations, meanMemoryUsage);\n        var allowedDeviation = ComputeAllowedEntropyDeviation(totalActivations);\n        var entropyDeviation = (maximumEntropy - currentEntropy) / maximumEntropy;\n\n        _entropyDeviation = entropyDeviation;\n\n        if (entropyDeviation < allowedDeviation)\n        {\n            // The deviation from maximum is practically considered \"0\" i.e: we've reached maximum.\n            LogMaxEntropyDeviationReached(entropyDeviation, currentEntropy, maximumEntropy, allowedDeviation);\n            StopSession(StopReason.SessionCompleted);\n\n            return;\n        }\n\n        // We use the normalized, absolute entropy change, because it is more useful for understanding how significant\n        // the change is, relative to the maximum possible. Values closer to 1 reflect higher significance than those closer to 0.\n        // Since max entropy is a function of the natural log of the cluster's size, this value is very robust against changes\n        // in silo number within the cluster.\n\n        var entropyChange = Math.Abs((currentEntropy - _previousEntropy) / maximumEntropy);\n        Debug.Assert(entropyChange is >= 0 and <= 1);\n\n        if (entropyChange < _options.EntropyQuantum)\n        {\n            // Entropy change is too low to be considered an improvement, chances are we are reaching the maximum, or the system\n            // is dynamically changing too fast i.e. new activations are being created at a high rate with an imbalanced distribution,\n            // we need to start \"cooling-down\". As a matter of fact, entropy could also become negative if the current entropy is less\n            // than the previous, due to many activation changes happening during this and the previous cycle.\n\n            LogInsufficientEntropyQuantum(entropyChange, _options.EntropyQuantum);\n\n            _stagnantCycles++;\n            _previousEntropy = currentEntropy;\n\n            return;\n        }\n\n        if (_stagnantCycles > 0)\n        {\n            _stagnantCycles = 0;\n            LogStagnantCyclesReset();\n        }\n\n        if (_failedSessions > 0)\n        {\n            _failedSessions = 0;\n            LogFailedSessionsReset();\n        }\n\n        var idealDistributions = snapshot.Select(x => new ValueTuple<SiloAddress, double>\n            // n_i = (N / S) * (M_m / m_i)\n            (x.Key, ((double)totalActivations / siloCount) * (meanMemoryUsage / x.Value.MemoryUsage)))\n            .ToDictionary();\n\n        var alpha = currentEntropy / maximumEntropy;\n        var scalingFactor = ComputeAdaptiveScaling(siloCount, _rebalancingCycle);\n        var addressPairs = FormSiloPairs(snapshot);\n        var migrationTasks = new List<Task>();\n\n        for (var i = 0; i < addressPairs.Count; i++)\n        {\n            (var lowSilo, var highSilo) = addressPairs[i];\n\n            var difference = Math.Abs(\n                (snapshot[lowSilo].ActivationCount - idealDistributions[lowSilo]) -\n                (snapshot[highSilo].ActivationCount - idealDistributions[highSilo]));\n\n            var delta = (int)(alpha * scalingFactor * (difference / 2));\n            if (delta == 0)\n            {\n                continue;\n            }\n\n            var lowCount = snapshot[lowSilo].ActivationCount;\n            var highCount = snapshot[highSilo].ActivationCount;\n\n            if (delta > highCount)\n            {\n                delta = highCount;\n            }\n\n            if (delta > _options.ActivationMigrationCountLimit)\n            {\n                delta = _options.ActivationMigrationCountLimit;\n            }\n\n            migrationTasks.Add(grainFactory\n                .GetSystemTarget<ISiloControl>(Constants.SiloControlType, highSilo)\n                .MigrateRandomActivations(lowSilo, delta));\n\n            UpdateStatistics(lowSilo, highSilo, delta);\n            LogSiloMigrations(delta, lowSilo, lowCount, lowCount + delta, highSilo, highCount, highCount - delta);\n        }\n\n        if (migrationTasks.Count > 0)\n        {\n            await Task.WhenAll(migrationTasks).WaitAsync(cancellationToken);\n        }\n\n        LogCycleOutcome(_rebalancingCycle, _stagnantCycles, _previousEntropy, currentEntropy, maximumEntropy, entropyDeviation);\n        _previousEntropy = currentEntropy;\n    }\n\n    private void UpdateStatistics(SiloAddress lowSilo, SiloAddress highSilo, int delta)\n    {\n        Debug.Assert(delta > 0);\n        var now = Runtime.TimeProvider.GetUtcNow().DateTime;\n\n        ref var lowStats = ref CollectionsMarshal.GetValueRefOrAddDefault(_rebalancingStatistics, lowSilo, out _);\n        lowStats = new()\n        {\n            TimeStamp = now,\n            SiloAddress = lowSilo,\n            DispersedActivations = lowStats.DispersedActivations,\n            AcquiredActivations = lowStats.AcquiredActivations + (ulong)delta\n        };\n\n        ref var highStats = ref CollectionsMarshal.GetValueRefOrAddDefault(_rebalancingStatistics, highSilo, out _);\n        highStats = new()\n        {\n            TimeStamp = now,\n            SiloAddress = highSilo,\n            DispersedActivations = highStats.DispersedActivations + (ulong)delta,\n            AcquiredActivations = highStats.AcquiredActivations\n        };\n    }\n\n    private static double ComputeEntropy(\n        Dictionary<SiloAddress, ResourceStatistics>.ValueCollection values,\n        int totalActivations, double meanMemoryUsage)\n    {\n        Debug.Assert(totalActivations > 0);\n        Debug.Assert(meanMemoryUsage > 0);\n\n        var ratios = values.Select(x =>\n            // p_i = (n_i / N) * (m_i / M_m)\n            ((double)x.ActivationCount / totalActivations) * (x.MemoryUsage / meanMemoryUsage));\n\n        var ratiosSum = ratios.Sum();\n        var normalizedRatios = ratios.Select(r => r / ratiosSum);\n\n        const double epsilon = 1e-10d;\n\n        var entropy = -normalizedRatios.Sum(p =>\n        {\n            var value = Math.Max(p, epsilon);  // Avoid log(0)\n            return value * Math.Log(value);    // - sum(p_i * log(p_i))\n        });\n\n        Debug.Assert(entropy > 0);\n\n        return entropy;\n    }\n\n    private static double ComputeHarmonicMean(Dictionary<SiloAddress, ResourceStatistics>.ValueCollection values)\n    {\n        var result = 0d;\n\n        foreach (var value in values)\n        {\n            var count = value.ActivationCount;\n            Debug.Assert(count > 0);\n            result += 1.0 / count;\n        }\n\n        return values.Count / result;\n    }\n\n    private double ComputeAllowedEntropyDeviation(int totalActivations)\n    {\n        if (!_options.ScaleAllowedEntropyDeviation || totalActivations < _options.ScaledEntropyDeviationActivationThreshold)\n        {\n            return _options.AllowedEntropyDeviation;\n        }\n\n        Debug.Assert(totalActivations > 0);\n\n        var logFactor = (int)Math.Log10(totalActivations / _options.ScaledEntropyDeviationActivationThreshold);\n        var adjustedDeviation = _options.AllowedEntropyDeviation * Math.Pow(10, logFactor);\n\n        return Math.Min(adjustedDeviation, ActivationRebalancerOptions.MAX_SCALED_ENTROPY_DEVIATION);\n    }\n\n    private double ComputeAdaptiveScaling(int siloCount, int rebalancingCycle)\n    {\n        Debug.Assert(rebalancingCycle > 0);\n\n        var cycleFactor = 1 - Math.Exp(-_options.CycleNumberWeight * rebalancingCycle);\n        var siloFactor = 1 / (1 + _options.SiloNumberWeight * (siloCount - 1));\n\n        return (double)(cycleFactor * siloFactor);\n    }\n\n    private static List<(SiloAddress, SiloAddress)> FormSiloPairs(\n        Dictionary<SiloAddress, ResourceStatistics> statistics)\n    {\n        var pairs = new List<(SiloAddress, SiloAddress)>();\n        var sorted = statistics.OrderBy(x => x.Value.ActivationCount).ToList();\n\n        var left = 0;\n        var right = sorted.Count - 1;\n\n        while (left < right)\n        {\n            pairs.Add((sorted[left].Key, sorted[right].Key));\n\n            left++;\n            right--;\n        }\n\n        return pairs;\n    }\n\n    private void StartSession()\n    {\n        StopSession(StopReason.SessionStarting);\n\n        _sessionTimer = this.RegisterGrainTimer(RunRebalancingCycle, new()\n        {\n            DueTime = TimeSpan.Zero,\n            Period = _options.SessionCyclePeriod\n        });\n\n        LogSessionStarted();\n    }\n\n    private void StopSession(StopReason reason, TimeSpan? duration = null)\n    {\n        _previousEntropy = 0;\n        _rebalancingCycle = 0;\n        _stagnantCycles = 0;\n        _sessionTimer?.Dispose();\n        _sessionTimer = null;\n\n        switch (reason)\n        {\n            case StopReason.SessionStarting:\n                {\n                    _failedSessions = 0;\n                    _suspendedUntilTs = 0;\n                }\n                break;\n            case StopReason.SessionStagnated:\n                {\n                    _failedSessions++;\n                    SuspendFor(backoffProvider.Next(_failedSessions));\n                }\n                break;\n            case StopReason.SessionCompleted:\n                {\n                    _failedSessions = 0;\n                    SuspendFor(_options.SessionCyclePeriod);\n                }\n                break;\n            case StopReason.RebalancerSuspended:\n                {\n                    _failedSessions = 0;\n                    if (duration.HasValue)\n                    {\n                        SuspendFor(duration.Value);\n                    }\n                    else\n                    {\n                        _suspendedUntilTs = long.MaxValue;\n                    }\n                }\n                break;\n        }\n\n        LogSessionStopped();\n    }\n\n    private void SuspendFor(TimeSpan duration)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThan(duration, TimeSpan.Zero);\n        var now = Runtime.TimeProvider.GetTimestamp();\n        var suspendUntil = now + (long)(Runtime.TimeProvider.TimestampFrequency * duration.TotalSeconds);\n        if (suspendUntil < now)\n        {\n            // Clamp overflow at max value.\n            suspendUntil = long.MaxValue;\n        }\n\n        _suspendedUntilTs = Math.Max(_suspendedUntilTs, suspendUntil);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Rebalancing/FailedSessionBackoffProvider.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Placement.Rebalancing;\n\nnamespace Orleans.Runtime.Placement.Rebalancing;\n\ninternal sealed class FailedSessionBackoffProvider(IOptions<ActivationRebalancerOptions> options)\n    : FixedBackoff(options.Value.SessionCyclePeriod), IFailedSessionBackoffProvider;"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/ActivationRepartitioner.Log.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\ninternal partial class ActivationRepartitioner\n{\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"I will periodically initiate the exchange protocol every {MinPeriod} to {MaxPeriod} starting in {DueTime}.\")]\n    private partial void LogPeriodicallyInvokeProtocol(TimeSpan minPeriod, TimeSpan maxPeriod, TimeSpan dueTime);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Activation repartitioning is enabled, but the cluster contains only one silo. Waiting for at least another silo to join the cluster to proceed.\")]\n    private partial void LogSingleSiloCluster();\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Exchange set for candidate silo {CandidateSilo} is empty. I will try the next best candidate (if one is available), otherwise I will wait for my next period to come.\")]\n    private partial void LogExchangeSetIsEmpty(SiloAddress candidateSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Beginning exchange protocol between {ThisSilo} and {CandidateSilo}.\")]\n    private partial void LogBeginningProtocol(SiloAddress thisSilo, SiloAddress candidateSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"I got an exchange request from {SendingSilo}, but I have been recently involved in another exchange {LastExchangeDuration} ago. My recovery period is {RecoveryPeriod}\")]\n    private partial void LogExchangedRecently(SiloAddress sendingSilo, TimeSpan lastExchangeDuration, TimeSpan recoveryPeriod);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Exchange request from {ThisSilo} rejected: {CandidateSilo} was recently involved in another exchange. Attempting the next best candidate (if one is available) or waiting for my next period to come.\")]\n    private partial void LogExchangedRecentlyResponse(SiloAddress thisSilo, SiloAddress candidateSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Rejecting exchange request from {SendingSilo} since we are already exchanging with that host.\")]\n    private partial void LogMutualExchangeAttempt(SiloAddress sendingSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Exchange request from {ThisSilo} superseded by a mutual exchange attempt with {CandidateSilo}.\")]\n    private partial void LogMutualExchangeAttemptResponse(SiloAddress thisSilo, SiloAddress candidateSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Finalized exchange protocol: migrating {GivingActivationCount} activations, receiving {TakingActivationCount} activations.\")]\n    private partial void LogProtocolFinalized(int givingActivationCount, int takingActivationCount);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Finalized exchange protocol: migrating [{GivingActivations}], receiving [{TakingActivations}].\")]\n    private partial void LogProtocolFinalizedTrace(string givingActivations, string takingActivations);\n\n    [LoggerMessage(Level = LogLevel.Warning, Message = \"Error performing exchange request from {ThisSilo} to {CandidateSilo}. I will try the next best candidate (if one is available), otherwise I will wait for my next period to come.\")]\n    private partial void LogErrorOnProtocolExecution(Exception exception, SiloAddress thisSilo, SiloAddress candidateSilo);\n\n    [LoggerMessage(Level = LogLevel.Warning, Message = \"Error migrating exchange set.\")]\n    private partial void LogErrorOnMigratingActivations(Exception exception);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Received AcceptExchangeRequest from {SendingSilo}, offering to send {ExchangeSetCount} activations from a total of {ActivationCount} activations.\")]\n    private partial void LogReceivedExchangeRequest(SiloAddress sendingSilo, int exchangeSetCount, int activationCount);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Imbalance is {Imbalance} (remote: {RemoteCount} vs local {LocalCount})\")]\n    private partial void LogImbalance(int imbalance, int remoteCount, int localCount);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Computing transfer set took {Elapsed}. Anticipated imbalance after transfer is {AnticipatedImbalance}.\")]\n    private partial void LogTransferSetComputed(TimeSpan elapsed, int anticipatedImbalance);\n\n    [LoggerMessage(Level = LogLevel.Warning, Message = \"Error accepting exchange request from {SendingSilo}.\")]\n    private partial void LogErrorAcceptingExchangeRequest(Exception exception, SiloAddress sendingSilo);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Waiting an additional {CoolDown} to cool down before initiating the exchange protocol.\")]\n    private partial void LogCoolingDown(TimeSpan coolDown);\n\n    [LoggerMessage(Level = LogLevel.Debug, Message = \"Adding {NewlyAnchoredGrains} newly anchored grains to set on host {Silo}. EdgeWeights contains {EdgeWeightCount} elements.\")]\n    private partial void LogAddingAnchoredGrains(int newlyAnchoredGrains, SiloAddress silo, int edgeWeightCount);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Candidate sets computed in {Elapsed}.\")]\n    private partial void LogComputedCandidateSets(TimeSpan elapsed);\n\n    [LoggerMessage(Level = LogLevel.Trace, Message = \"Candidate heaps created in {Elapsed}.\")]\n    private partial void LogComputedCandidateHeaps(TimeSpan elapsed);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/ActivationRepartitioner.MessageSink.cs",
    "content": "#nullable enable\nusing System.Runtime.CompilerServices;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\ninternal sealed partial class ActivationRepartitioner : IMessageStatisticsSink\n{\n    private readonly CancellationTokenSource _shutdownCts = new();\n\n    // This filter contains grain ids which will are anchored to the current silo.\n    // Ids are inserted when a grain is found to have a negative transfer score.\n    private readonly AnchoredGrainsFilter? _anchoredFilter;\n    private Task? _processPendingEdgesTask;\n\n    public void StartProcessingEdges()\n    {\n        using var _ = new ExecutionContextSuppressor();\n        _processPendingEdgesTask = ProcessPendingEdges(_shutdownCts.Token);\n\n        LogTraceServiceStarted(_logger, nameof(ActivationRepartitioner));\n    }\n\n    public async Task StopProcessingEdgesAsync(CancellationToken cancellationToken)\n    {\n        _shutdownCts.Cancel();\n        if (_processPendingEdgesTask is null)\n        {\n            return;\n        }\n\n        _pendingMessageEvent.Signal();\n        await _processPendingEdgesTask.WaitAsync(cancellationToken).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n        LogTraceServiceStopped(_logger, nameof(ActivationRepartitioner));\n    }\n\n    private async Task ProcessPendingEdges(CancellationToken cancellationToken)\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n        var drainBuffer = new Message[128];\n        var iteration = 0;\n        const int MaxIterationsPerYield = 128;\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            var count = _pendingMessages.DrainTo(drainBuffer);\n            if (count > 0)\n            {\n                foreach (var message in drainBuffer[..count])\n                {\n                    if (!IsFullyAddressed(message) || // The silo addresses (likely the target) is set null some time later (after the message is recorded), this can lead to a NRE\n                        !_messageFilter.IsAcceptable(message, out var isSenderMigratable, out var isTargetMigratable))\n                    {\n                        continue;\n                    }\n\n                    EdgeVertex sourceVertex;\n                    if (_anchoredFilter != null && _anchoredFilter.Contains(message.SendingGrain) && Silo.Equals(message.SendingSilo))\n                    {\n                        sourceVertex = new(GrainId, Silo, isMigratable: false);\n                    }\n                    else\n                    {\n                        sourceVertex = new(message.SendingGrain, message.SendingSilo, isSenderMigratable);\n                    }\n\n                    EdgeVertex destinationVertex;\n                    if (_anchoredFilter != null && _anchoredFilter.Contains(message.TargetGrain) && Silo.Equals(message.TargetSilo))\n                    {\n                        destinationVertex = new(GrainId, Silo, isMigratable: false);\n                    }\n                    else\n                    {\n                        destinationVertex = new(message.TargetGrain, message.TargetSilo, isTargetMigratable);\n                    }\n\n                    if (!sourceVertex.IsMigratable && !destinationVertex.IsMigratable)\n                    {\n                        // Ignore edges between two non-migratable grains.\n                        continue;\n                    }\n\n                    Edge edge = new(sourceVertex, destinationVertex);\n                    _edgeWeights.Add(edge);\n                }\n\n                if (++iteration >= MaxIterationsPerYield)\n                {\n                    iteration = 0;\n                    await Task.Delay(TimeSpan.FromTicks(TimeSpan.TicksPerMillisecond), CancellationToken.None);\n                }\n            }\n            else\n            {\n                iteration = 0;\n                await _pendingMessageEvent.WaitAsync();\n            }\n        }\n    }\n\n    public Action<Message>? GetMessageObserver() => RecordMessage;\n\n    private void RecordMessage(Message message)\n    {\n        if (!_enableMessageSampling || message.IsSystemMessage)\n        {\n            return;\n        }\n\n        // It must have a direction, and must not be a 'response' as it would skew analysis.\n        if (message.Direction is Message.Directions.None or Message.Directions.Response)\n        {\n            return;\n        }\n\n        // Sender and target need to be fully addressable to know where to move to or towards.\n        if (!IsFullyAddressed(message))\n        {\n            return;\n        }\n\n        if (_pendingMessages.TryAdd(message) == Utilities.BufferStatus.Success)\n        {\n            _pendingMessageEvent.Signal();\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static bool IsFullyAddressed(Message message) =>\n        message.IsSenderFullyAddressed && message.IsTargetFullyAddressed;\n\n    async ValueTask IActivationRepartitionerSystemTarget.FlushBuffers()\n    {\n        while (_pendingMessages.Count > 0)\n        {\n            await Task.Delay(TimeSpan.FromMilliseconds(30));\n        }\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"{Service} has started.\"\n    )]\n    private static partial void LogTraceServiceStarted(ILogger logger, string service);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"{Service} has stopped.\"\n    )]\n    private static partial void LogTraceServiceStopped(ILogger logger, string service);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/ActivationRepartitioner.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing System.Runtime.CompilerServices;\nusing System.Diagnostics;\nusing System.Collections.Immutable;\nusing System.Data;\nusing Orleans.Internal;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Utilities;\nusing System.Runtime.InteropServices;\nusing System.Diagnostics.CodeAnalysis;\nusing Microsoft.CodeAnalysis;\nusing Orleans.Placement.Repartitioning;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\n// See: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/06/eurosys16loca_camera_ready-1.pdf\ninternal sealed partial class ActivationRepartitioner : SystemTarget, IActivationRepartitionerSystemTarget, ILifecycleParticipant<ISiloLifecycle>, IDisposable, ISiloStatusListener\n{\n    private readonly ILogger _logger;\n    private readonly ISiloStatusOracle _siloStatusOracle;\n    private readonly IInternalGrainFactory _grainFactory;\n    private readonly IRepartitionerMessageFilter _messageFilter;\n    private readonly IImbalanceToleranceRule _toleranceRule;\n    private readonly IActivationMigrationManager _migrationManager;\n    private readonly ActivationDirectory _activationDirectory;\n    private readonly TimeProvider _timeProvider;\n    private readonly ActivationRepartitionerOptions _options;\n    private readonly StripedMpscBuffer<Message> _pendingMessages;\n    private readonly SingleWaiterAutoResetEvent _pendingMessageEvent = new() { RunContinuationsAsynchronously = true };\n    private readonly FrequentEdgeCounter _edgeWeights;\n    private readonly IGrainTimer _timer;\n    private SiloAddress? _currentExchangeSilo;\n    private CoarseStopwatch _lastExchangedStopwatch;\n    private int _activationCountOffset;\n    private bool _enableMessageSampling;\n\n    public ActivationRepartitioner(\n        ISiloStatusOracle siloStatusOracle,\n        ILoggerFactory loggerFactory,\n        IInternalGrainFactory internalGrainFactory,\n        IRepartitionerMessageFilter messageFilter,\n        IImbalanceToleranceRule toleranceRule,\n        IActivationMigrationManager migrationManager,\n        ActivationDirectory activationDirectory,\n        IOptions<ActivationRepartitionerOptions> options,\n        TimeProvider timeProvider,\n        SystemTargetShared shared)\n        : base(Constants.ActivationRepartitionerType, shared)\n    {\n        _logger = loggerFactory.CreateLogger<ActivationRepartitioner>();\n        _options = options.Value;\n        _siloStatusOracle = siloStatusOracle;\n        _grainFactory = internalGrainFactory;\n        _messageFilter = messageFilter;\n        _toleranceRule = toleranceRule;\n        _migrationManager = migrationManager;\n        _activationDirectory = activationDirectory;\n        _timeProvider = timeProvider;\n        _edgeWeights = new(options.Value.MaxEdgeCount);\n        _lastExchangedStopwatch = CoarseStopwatch.StartNew();\n        _pendingMessages = new StripedMpscBuffer<Message>(Environment.ProcessorCount, options.Value.MaxUnprocessedEdges / Environment.ProcessorCount);\n        shared.ActivationDirectory.RecordNewTarget(this);\n        _siloStatusOracle.SubscribeToSiloStatusEvents(this);\n        _timer = RegisterTimer(_ => TriggerExchangeRequest().AsTask(), null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);\n\n        if (options.Value.AnchoringFilterEnabled)\n        {\n            _anchoredFilter = new AnchoredGrainsFilter(100_000, options.Value.ProbabilisticFilteringMaxAllowedErrorRate, options.Value.AnchoringFilterGenerations);\n        }\n    }\n\n    private Task OnActiveStart(CancellationToken cancellationToken)\n    {\n        Scheduler.QueueAction(() =>\n        {\n            // Schedule the first timer tick.\n            UpdateTimer();\n            StartProcessingEdges();\n        });\n\n        return Task.CompletedTask;\n    }\n\n    public ValueTask ResetCounters()\n    {\n        _pendingMessages.Clear();\n        _edgeWeights.Clear();\n        _anchoredFilter?.Reset();\n        return ValueTask.CompletedTask;\n    }\n\n    ValueTask<int> IActivationRepartitionerSystemTarget.GetActivationCount() => new(_activationDirectory.Count);\n    ValueTask IActivationRepartitionerSystemTarget.SetActivationCountOffset(int activationCountOffset)\n    {\n        _activationCountOffset = activationCountOffset;\n        return ValueTask.CompletedTask;\n    }\n\n    private void UpdateTimer() => UpdateTimer(RandomTimeSpan.Next(_options.MinRoundPeriod, _options.MaxRoundPeriod));\n    private void UpdateTimer(TimeSpan dueTime)\n    {\n        _timer.Change(dueTime, dueTime);\n        LogPeriodicallyInvokeProtocol(_options.MinRoundPeriod, _options.MaxRoundPeriod, dueTime);\n    }\n\n    public async ValueTask TriggerExchangeRequest()\n    {\n        if (_anchoredFilter is { } filter)\n        {\n            filter.Rotate();\n        }\n\n        var coolDown = _options.RecoveryPeriod - _lastExchangedStopwatch.Elapsed;\n        if (coolDown > TimeSpan.Zero)\n        {\n            LogCoolingDown(coolDown);\n            await Task.Delay(coolDown, _timeProvider);\n        }\n\n        // Schedule the next timer tick.\n        UpdateTimer();\n\n        if (_currentExchangeSilo is not null)\n        {\n            // Skip this round if we are already in the process of exchanging with another silo.\n            return;\n        }\n\n        var silos = _siloStatusOracle.GetActiveSilos();\n        if (silos.Length == 1)\n        {\n            LogSingleSiloCluster();\n            return;\n        }\n        else if (!_enableMessageSampling)\n        {\n            return;\n        }\n\n        var sw = ValueStopwatch.StartNew();\n        var migrationCandidates = GetMigrationCandidates();\n        var sets = CreateCandidateSets(migrationCandidates, silos);\n        var anchoredSet = ComputeAnchoredGrains(migrationCandidates);\n        LogComputedCandidateSets(sw.Elapsed);\n        foreach ((var candidateSilo, var offeredGrains, var _) in sets)\n        {\n            if (offeredGrains.Count == 0)\n            {\n                LogExchangeSetIsEmpty(candidateSilo);\n                continue;\n            }\n\n            try\n            {\n                // Set the exchange partner for the duration of the operation.\n                // This prevents other requests from interleaving.\n                _currentExchangeSilo = candidateSilo;\n\n                LogBeginningProtocol(Silo, candidateSilo);\n                var remoteRef = IActivationRepartitionerSystemTarget.GetReference(_grainFactory, candidateSilo);\n                var response = await remoteRef.AcceptExchangeRequest(new(Silo, [.. offeredGrains], GetLocalActivationCount()));\n\n                switch (response.Type)\n                {\n                    case AcceptExchangeResponse.ResponseType.Success:\n                        // Exchange was successful, no need to iterate over another candidate.\n                        await FinalizeProtocol(response.AcceptedGrainIds, response.GivenGrainIds, candidateSilo, anchoredSet);\n                        return;\n                    case AcceptExchangeResponse.ResponseType.ExchangedRecently:\n                        // The remote silo has been recently involved in another exchange, try the next best candidate.\n                        LogExchangedRecentlyResponse(Silo, candidateSilo);\n                        continue;\n                    case AcceptExchangeResponse.ResponseType.MutualExchangeAttempt:\n                        // The remote silo is exchanging with this silo already and the exchange the remote silo initiated\n                        // took precedence over the one this silo is initiating.\n                        LogMutualExchangeAttemptResponse(Silo, candidateSilo);\n                        return;\n                }\n            }\n            catch (Exception ex)\n            {\n                LogErrorOnProtocolExecution(ex, Silo, candidateSilo);\n                continue; // there was some problem, try the next best candidate\n            }\n            finally\n            {\n                _currentExchangeSilo = null;\n            }\n        }\n    }\n\n    private int GetLocalActivationCount() => _activationDirectory.Count + _activationCountOffset;\n\n    public async ValueTask<AcceptExchangeResponse> AcceptExchangeRequest(AcceptExchangeRequest request)\n    {\n        LogReceivedExchangeRequest(request.SendingSilo, request.ExchangeSet.Length, request.ActivationCountSnapshot);\n        if (request.SendingSilo.Equals(_currentExchangeSilo) && Silo.CompareTo(request.SendingSilo) <= 0)\n        {\n            // Reject the request, as we are already in the process of exchanging with the sending silo.\n            // The '<=' comparison here is used to break the tie in case both silos are exchanging with each other.\n\n            // We pick some random time between 'min' and 'max' and than subtract from it 'min'. We do this so this silo doesn't have to wait for 'min + random',\n            // as it did the very first time this was started. It is guaranteed that 'random - min' >= 0; as 'random' will be at the least equal to 'min'.\n            UpdateTimer(RandomTimeSpan.Next(_options.MinRoundPeriod, _options.MaxRoundPeriod) - _options.MinRoundPeriod);\n            LogMutualExchangeAttempt(request.SendingSilo);\n\n            return AcceptExchangeResponse.CachedMutualExchangeAttempt;\n        }\n\n        var lastExchangeElapsed = _lastExchangedStopwatch.Elapsed;\n        if (lastExchangeElapsed < _options.RecoveryPeriod)\n        {\n            LogExchangedRecently(request.SendingSilo, lastExchangeElapsed, _options.RecoveryPeriod);\n            return AcceptExchangeResponse.CachedExchangedRecently;\n        }\n\n        // Set the exchange silo for the duration of the request.\n        // This prevents other requests from interleaving.\n        _currentExchangeSilo = request.SendingSilo;\n\n        try\n        {\n            var acceptedGrains = ImmutableArray.CreateBuilder<GrainId>();\n            var givingGrains = ImmutableArray.CreateBuilder<GrainId>();\n            var remoteSet = request.ExchangeSet;\n            var migrationCandidates = GetMigrationCandidates();\n            var localSet = GetCandidatesForSilo(migrationCandidates, request.SendingSilo);\n            var anchoredSet = ComputeAnchoredGrains(migrationCandidates);\n\n            // We need to determine 2 subsets:\n            // - One that originates from sending silo (request.ExchangeSet) and will be (partially) accepted from this silo.\n            // - One that originates from this silo (candidateSet) and will be (fully) accepted from the sending silo.\n            var remoteActivations = request.ActivationCountSnapshot;\n            var localActivations = GetLocalActivationCount();\n\n            var initialImbalance = CalculateImbalance(remoteActivations, localActivations);\n            int imbalance = initialImbalance;\n            LogImbalance(imbalance, remoteActivations, localActivations);\n\n            var stopwatch = ValueStopwatch.StartNew();\n            var (localHeap, remoteHeap) = CreateCandidateHeaps(localSet, remoteSet);\n            LogComputedCandidateHeaps(stopwatch.Elapsed);\n            stopwatch.Restart();\n\n            var iterations = 0;\n            var yieldStopwatch = CoarseStopwatch.StartNew();\n            while (true)\n            {\n                if (++iterations % 128 == 0 && yieldStopwatch.ElapsedMilliseconds > 25)\n                {\n                    // Give other tasks a chance to execute periodically.\n                    yieldStopwatch.Restart();\n                    await Task.Delay(1);\n                }\n\n                // If more is gained by giving grains to the remote silo than taking from it, we will try giving first.\n                var localScore = localHeap.FirstOrDefault()?.AccumulatedTransferScore ?? 0;\n                var remoteScore = remoteHeap.FirstOrDefault()?.AccumulatedTransferScore ?? 0;\n                if (localScore > remoteScore || localScore == remoteScore && localActivations > remoteActivations)\n                {\n                    if (TryMigrateLocalToRemote()) continue;\n                    if (TryMigrateRemoteToLocal()) continue;\n                }\n                else\n                {\n                    if (TryMigrateRemoteToLocal()) continue;\n                    if (TryMigrateLocalToRemote()) continue;\n                }\n\n                // No more migrations can be made, so the candidate set has been calculated.\n                break;\n            }\n\n            LogTransferSetComputed(stopwatch.Elapsed, imbalance);\n            var giving = givingGrains.ToImmutable();\n            var accepting = acceptedGrains.ToImmutable();\n            await FinalizeProtocol(giving, accepting, request.SendingSilo, anchoredSet);\n\n            return new(AcceptExchangeResponse.ResponseType.Success, accepting, giving);\n\n            bool TryMigrateLocalToRemote()\n            {\n                if (!TryMigrateCore(localHeap, localDelta: -1, remoteDelta: 1, out var chosenVertex))\n                {\n                    return false;\n                }\n\n                givingGrains.Add(chosenVertex.Id);\n                foreach (var (connectedVertex, transferScore) in chosenVertex.ConnectedVertices)\n                {\n                    switch (connectedVertex.Location)\n                    {\n                        case VertexLocation.Local:\n                            // Add the transfer score as these two vectors will now be remote to each other.\n                            connectedVertex.AccumulatedTransferScore += transferScore;\n                            localHeap.OnIncreaseElementPriority(connectedVertex);\n                            break;\n                        case VertexLocation.Remote:\n                            // Subtract the transfer score as these two vectors will now be local to each other.\n                            connectedVertex.AccumulatedTransferScore -= transferScore;\n                            remoteHeap.OnDecreaseElementPriority(connectedVertex);\n                            break;\n                    }\n                }\n\n                // We will perform any future operations assuming the vector is remote.\n                chosenVertex.Location = VertexLocation.Remote;\n                Debug.Assert(((IHeapElement<CandidateVertexHeapElement>)chosenVertex).HeapIndex == -1);\n\n                return true;\n            }\n\n            bool TryMigrateRemoteToLocal()\n            {\n                if (!TryMigrateCore(remoteHeap, localDelta: 1, remoteDelta: -1, out var chosenVertex))\n                {\n                    return false;\n                }\n\n                acceptedGrains.Add(chosenVertex.Id);\n                foreach (var (connectedVertex, transferScore) in chosenVertex.ConnectedVertices)\n                {\n                    switch (connectedVertex.Location)\n                    {\n                        case VertexLocation.Local:\n                            // Subtract the transfer score as these two vectors will now be local to each other.\n                            connectedVertex.AccumulatedTransferScore -= transferScore;\n                            localHeap.OnDecreaseElementPriority(connectedVertex);\n                            break;\n                        case VertexLocation.Remote:\n                            // Add the transfer score as these two vectors will now be remote to each other.\n                            connectedVertex.AccumulatedTransferScore += transferScore;\n                            remoteHeap.OnIncreaseElementPriority(connectedVertex);\n                            break;\n                    }\n                }\n\n                // We will perform any future operations assuming the vector is local.\n                chosenVertex.Location = VertexLocation.Local;\n\n                return true;\n            }\n\n            bool TryMigrateCore(MaxHeap<CandidateVertexHeapElement> sourceHeap, int localDelta, int remoteDelta, [NotNullWhen(true)] out CandidateVertexHeapElement? chosenVertex)\n            {\n                var anticipatedImbalance = CalculateImbalance(localActivations + localDelta, remoteActivations + remoteDelta);\n                if (anticipatedImbalance >= imbalance && !_toleranceRule.IsSatisfiedBy((uint)anticipatedImbalance))\n                {\n                    // Taking from this heap would not improve imbalance.\n                    chosenVertex = null;\n                    return false;\n                }\n\n                if (!sourceHeap.TryPop(out chosenVertex))\n                {\n                    // Heap is empty.\n                    return false;\n                }\n\n                if (chosenVertex.AccumulatedTransferScore <= 0)\n                {\n                    // If it got affected by a previous run, and the score is zero or negative, simply pop and ignore it.\n                    return false;\n                }\n\n                localActivations += localDelta;\n                remoteActivations += remoteDelta;\n                imbalance = anticipatedImbalance;\n                return true;\n            }\n\n        }\n        catch (Exception exception)\n        {\n            LogErrorAcceptingExchangeRequest(exception, request.SendingSilo);\n            throw;\n        }\n        finally\n        {\n            _currentExchangeSilo = null;\n        }\n    }\n\n    private static int CalculateImbalance(int left, int right) => Math.Abs(Math.Abs(left) - Math.Abs(right));\n    private static (MaxHeap<CandidateVertexHeapElement> Local, MaxHeap<CandidateVertexHeapElement> Remote) CreateCandidateHeaps(List<CandidateVertex> local, ImmutableArray<CandidateVertex> remote)\n    {\n        Dictionary<GrainId, CandidateVertex> sourceIndex = new(local.Count + remote.Length);\n        foreach (var element in local)\n        {\n            sourceIndex[element.Id] = element;\n        }\n\n        foreach (var element in remote)\n        {\n            sourceIndex[element.Id] = element;\n        }\n\n        Dictionary<GrainId, CandidateVertexHeapElement> heapIndex = [];\n        List<CandidateVertexHeapElement> localVertexList = new(local.Count);\n        foreach (var element in local)\n        {\n            var vertex = CreateVertex(sourceIndex, heapIndex, element);\n            vertex.Location = VertexLocation.Local;\n            localVertexList.Add(vertex);\n        }\n\n        List<CandidateVertexHeapElement> remoteVertexList = new(remote.Length);\n        foreach (var element in remote)\n        {\n            var vertex = CreateVertex(sourceIndex, heapIndex, element);\n            if (vertex.Location is not VertexLocation.Unknown)\n            {\n                // This vertex is already part of the local set, so assume that the vertex is local and ignore the remote vertex.\n                continue;\n            }\n\n            vertex.Location = VertexLocation.Remote;\n            remoteVertexList.Add(vertex);\n        }\n\n        var localHeap = new MaxHeap<CandidateVertexHeapElement>(localVertexList);\n        var remoteHeap = new MaxHeap<CandidateVertexHeapElement>(remoteVertexList);\n        return (localHeap, remoteHeap);\n\n        static CandidateVertexHeapElement CreateVertex(Dictionary<GrainId, CandidateVertex> sourceIndex, Dictionary<GrainId, CandidateVertexHeapElement> index, CandidateVertex element)\n        {\n            var vertex = GetOrAddVertex(index, element);\n            foreach (var connectedVertex in element.ConnectedVertices)\n            {\n                if (sourceIndex.TryGetValue(connectedVertex.Id, out var connected))\n                {\n                    vertex.ConnectedVertices.Add((GetOrAddVertex(index, connected), connectedVertex.TransferScore));\n                }\n                else\n                {\n                    // The connected vertex is not part of either migration candidate set, so we will ignore it.\n                }\n            }\n\n            return vertex;\n\n            static CandidateVertexHeapElement GetOrAddVertex(Dictionary<GrainId, CandidateVertexHeapElement> index, CandidateVertex element)\n            {\n                ref var vertex = ref CollectionsMarshal.GetValueRefOrAddDefault(index, element.Id, out var exists);\n                vertex ??= new(element);\n                return vertex;\n            }\n        }\n    }\n\n    /// <summary>\n    /// <list type=\"number\">\n    /// <item>Initiates the actual migration process of <paramref name=\"giving\"/> to 'this' silo.</item>\n    /// <item>Updates the affected counters within <see cref=\"_edgeWeights\"/> to reflect all <paramref name=\"accepting\"/>.</item>\n    /// </list>\n    /// </summary>\n    /// <param name=\"giving\">The grain ids to migrate to the remote host.</param>\n    /// <param name=\"accepting\">The grain ids to which are migrating to the local host.</param>\n    private async Task FinalizeProtocol(ImmutableArray<GrainId> giving, ImmutableArray<GrainId> accepting, SiloAddress targetSilo, HashSet<GrainId> newlyAnchoredGrains)\n    {\n        // The protocol concluded that 'this' silo should take on 'set', so we hint to the director accordingly.\n        try\n        {\n            Dictionary<string, object> migrationRequestContext = new() { [IPlacementDirector.PlacementHintKey] = targetSilo };\n            var deactivationTasks = new List<Task>();\n            foreach (var grainId in giving)\n            {\n                if (_activationDirectory.FindTarget(grainId) is { } localActivation)\n                {\n                    localActivation.Migrate(migrationRequestContext);\n                    deactivationTasks.Add(localActivation.Deactivated);\n                }\n            }\n\n            await Task.WhenAll(deactivationTasks);\n        }\n        catch (Exception exception)\n        {\n            // This should happen rarely, but at this point we cant really do much, as its out of our control.\n            // Even if some fail, the algorithm will eventually run again, so activations will have more chances to migrate.\n            LogErrorOnMigratingActivations(exception);\n        }\n\n        // Avoid mutating the source while enumerating it.\n        var iterations = 0;\n        var toRemove = new List<Edge>();\n        var affected = new HashSet<GrainId>(giving.Length + accepting.Length);\n\n        if (_anchoredFilter is { } filter)\n        {\n            LogAddingAnchoredGrains(newlyAnchoredGrains.Count, Silo, _edgeWeights.Count);\n            foreach (var id in newlyAnchoredGrains)\n            {\n                filter.Add(id);\n            }\n        }\n\n        foreach (var id in accepting)\n        {\n            affected.Add(id);\n        }\n\n        foreach (var id in giving)\n        {\n            affected.Add(id);\n        }\n\n        var yieldStopwatch = CoarseStopwatch.StartNew();\n        if (affected.Count > 0)\n        {\n            foreach (var (edge, _, _) in _edgeWeights.Elements)\n            {\n                if (affected.Contains(edge.Source.Id) || affected.Contains(edge.Target.Id) || _anchoredFilter is not null && (_anchoredFilter.Contains(edge.Source.Id) || _anchoredFilter.Contains(edge.Target.Id)))\n                {\n                    toRemove.Add(edge);\n                }\n            }\n\n            foreach (var edge in toRemove)\n            {\n                if (++iterations % 128 == 0 && yieldStopwatch.ElapsedMilliseconds > 25)\n                {\n                    // Give other tasks a chance to execute periodically.\n                    yieldStopwatch.Restart();\n                    await Task.Delay(1);\n                }\n\n                // Totally remove this counter, as one or both vertices has migrated. By not doing this it would skew results for the next protocol cycle.\n                // We remove only the affected counters, as there could be other counters that 'this' silo has connections with another silo (which is not part of this exchange cycle).\n                _edgeWeights.Remove(edge);\n            }\n        }\n\n        // Stamp this silos exchange for a potential next pair exchange request.\n        _lastExchangedStopwatch.Restart();\n        if (_logger.IsEnabled(LogLevel.Trace))\n        {\n            LogProtocolFinalizedTrace(string.Join(\", \", giving), string.Join(\", \", accepting));\n        }\n        else if (_logger.IsEnabled(LogLevel.Debug))\n        {\n            LogProtocolFinalized(giving.Length, accepting.Length);\n        }\n    }\n\n    private List<(SiloAddress Silo, List<CandidateVertex> Candidates, long TransferScore)> CreateCandidateSets(List<IGrouping<GrainId, VertexEdge>> migrationCandidates, ImmutableArray<SiloAddress> silos)\n    {\n        List<(SiloAddress Silo, List<CandidateVertex> Candidates, long TransferScore)> candidateSets = new(silos.Length - 1);\n\n        foreach (var siloAddress in silos)\n        {\n            if (siloAddress.Equals(Silo))\n            {\n                // We aren't going to exchange anything with ourselves, so skip this silo.\n                continue;\n            }\n\n            var candidatesForRemote = GetCandidatesForSilo(migrationCandidates, siloAddress);\n            var totalAccTransferScore = candidatesForRemote.Sum(x => x.AccumulatedTransferScore);\n\n            candidateSets.Add(new(siloAddress, [.. candidatesForRemote], totalAccTransferScore));\n        }\n\n        // Order them by the highest accumulated transfer score\n        candidateSets.Sort(static (a, b) => -a.TransferScore.CompareTo(b.TransferScore));\n\n        return candidateSets;\n    }\n\n    private List<CandidateVertex> GetCandidatesForSilo(List<IGrouping<GrainId, VertexEdge>> migrationCandidates, SiloAddress otherSilo)\n    {\n        Debug.Assert(!otherSilo.Equals(Silo));\n\n        List<CandidateVertex> result = [];\n\n        // We skip types that cant be migrated. Instead the same edge will be recorded from the receiver, so its hosting silo will add it as a candidate to be migrated (over here).\n        // We are sure that the receiver is an migratable grain, because the gateway forbids edges that have non-migratable vertices on both sides.\n        foreach (var grainEdges in migrationCandidates)\n        {\n            var accLocalScore = 0L;\n            var accRemoteScore = 0L;\n\n            foreach (var edge in grainEdges)\n            {\n                if (edge.Direction is Direction.LocalToLocal)\n                {\n                    // Since its L2L, it means the partner silo will be 'this' silo, so we don't need to filter by the partner silo.\n                    accLocalScore += edge.Weight;\n                }\n                else if (edge.PartnerSilo.Equals(otherSilo))\n                {\n                    Debug.Assert(edge.Direction is Direction.RemoteToLocal or Direction.LocalToRemote);\n\n                    // We need to filter here by 'otherSilo' since any L2R or R2L edge can be between the current vertex and a vertex in a silo that is not in 'otherSilo'.\n                    accRemoteScore += edge.Weight;\n                }\n            }\n\n            if (accLocalScore >= accRemoteScore)\n            {\n                // We skip vertices for which local calls outweigh the remote ones.\n                continue;\n            }\n\n            var totalAccScore = accRemoteScore - accLocalScore;\n            var connVertices = ImmutableArray.CreateBuilder<CandidateConnectedVertex>();\n            foreach (var edge in grainEdges)\n            {\n                // Note that the connected vertices can be of types which are not migratable, it is important to keep them,\n                // as they too impact the migration cost of the current candidate vertex, especially if they are local to the candidate\n                // as those calls would be potentially converted to remote calls, after the migration of the current candidate.\n                // 'Weight' here represent the weight of a single edge, not the accumulated like above.\n                connVertices.Add(new CandidateConnectedVertex(edge.TargetId, edge.Weight));\n            }\n\n            CandidateVertex candidate = new()\n            {\n                Id = grainEdges.Key,\n                AccumulatedTransferScore = totalAccScore,\n                ConnectedVertices = connVertices.ToImmutable()\n            };\n\n            result.Add(candidate);\n        }\n\n        return result;\n    }\n\n    private static HashSet<GrainId> ComputeAnchoredGrains(List<IGrouping<GrainId, VertexEdge>> migrationCandidates)\n    {\n        HashSet<GrainId> anchoredGrains = [];\n        foreach (var grainEdges in migrationCandidates)\n        {\n            var accLocalScore = 0L;\n            var accRemoteScore = 0L;\n\n            foreach (var edge in grainEdges)\n            {\n                if (edge.Direction is Direction.LocalToLocal)\n                {\n                    accLocalScore += edge.Weight;\n                }\n                else\n                {\n                    Debug.Assert(edge.Direction is Direction.RemoteToLocal or Direction.LocalToRemote);\n                    accRemoteScore += edge.Weight;\n                }\n            }\n\n            if (accLocalScore > accRemoteScore)\n            {\n                anchoredGrains.Add(grainEdges.Key);\n            }\n        }\n\n        return anchoredGrains;\n    }\n\n    private List<IGrouping<GrainId, VertexEdge>> GetMigrationCandidates() => CreateLocalVertexEdges().Where(x => x.IsMigratable).GroupBy(x => x.SourceId).ToList();\n\n    /// <summary>\n    /// Creates a collection of 'local' vertex edges. Multiple entries can have the same Id.\n    /// </summary>\n    /// <remarks>The <see cref=\"VertexEdge.SourceId\"/> is guaranteed to belong to a grain that is local to this silo, while <see cref=\"VertexEdge.TargetId\"/> might belong to a local or remote silo.</remarks>\n    private IEnumerable<VertexEdge> CreateLocalVertexEdges()\n    {\n        foreach (var (edge, count, error) in _edgeWeights.Elements)\n        {\n            if (count == 0)\n            {\n                continue;\n            }\n\n            var vertexEdge = CreateVertexEdge(edge, count);\n            if (vertexEdge.Direction is Direction.Unspecified)\n            {\n                // This can occur when a message is re-routed via this silo.\n                continue;\n            }\n\n            yield return vertexEdge;\n\n            if (vertexEdge.Direction == Direction.LocalToLocal)\n            {\n                // The reason we do this flipping is because when the edge is Local-to-Local, we have 2 grains that are linked via an communication edge.\n                // Once an edge exists it means 2 grains are temporally linked, this means that there is a cost associated to potentially move either one of them.\n                // Since the construction of the candidate set takes into account also local connection (which increases the cost of migration), we need\n                // to take into account the edge not only from a source's perspective, but also the target's one, as it too will take part on the candidate set.\n                var flippedEdge = CreateVertexEdge(edge.Flip(), count);\n                yield return flippedEdge;\n            }\n        }\n\n        VertexEdge CreateVertexEdge(in Edge edge, long weight)\n        {\n            return (IsSourceLocal(edge), IsTargetLocal(edge)) switch\n            {\n                (true, true) => new(\n                   SourceId: edge.Source.Id,                // 'local' vertex was the 'source' of the communication\n                   TargetId: edge.Target.Id,\n                   IsMigratable: edge.Source.IsMigratable,\n                   PartnerSilo: Silo,                       // the partner was 'local' (note: this.Silo = Source.Silo = Target.Silo)\n                   Direction: Direction.LocalToLocal,\n                   Weight: weight),\n                (true, false) => new(\n                    SourceId: edge.Source.Id,               // 'local' vertex was the 'source' of the communication\n                    TargetId: edge.Target.Id,\n                    IsMigratable: edge.Source.IsMigratable,\n                    PartnerSilo: edge.Target.Silo,          // the partner was 'remote'\n                    Direction: Direction.LocalToRemote,\n                    Weight: weight),\n                (false, true) => new(\n                    SourceId: edge.Target.Id,               // 'local' vertex was the 'target' of the communication\n                    TargetId: edge.Source.Id,\n                    IsMigratable: edge.Target.IsMigratable,\n                    PartnerSilo: edge.Source.Silo,          // the partner was 'remote'\n                    Direction: Direction.RemoteToLocal,\n                    Weight: weight),\n                _ => default\n            };\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        bool IsSourceLocal(in Edge edge) => edge.Source.Silo.Equals(Silo);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        bool IsTargetLocal(in Edge edge) => edge.Target.Silo.Equals(Silo);\n    }\n\n    public void Participate(ISiloLifecycle observer)\n    {\n        // Start when the silo becomes active.\n        observer.Subscribe(\n            nameof(ActivationRepartitioner),\n            ServiceLifecycleStage.Active,\n            OnActiveStart,\n            ct => Task.CompletedTask);\n\n        // Stop when the silo stops application services.\n        observer.Subscribe(\n            nameof(ActivationRepartitioner),\n            ServiceLifecycleStage.ApplicationServices,\n            ct => Task.CompletedTask,\n            StopProcessingEdgesAsync);\n    }\n\n    void IDisposable.Dispose()\n    {\n        base.Dispose();\n        _enableMessageSampling = false;\n        _siloStatusOracle.UnSubscribeFromSiloStatusEvents(this);\n        _shutdownCts.Cancel();\n    }\n\n    void ISiloStatusListener.SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status)\n    {\n        _enableMessageSampling = _siloStatusOracle.GetActiveSilos().Length > 1;\n    }\n\n    public ValueTask<ImmutableArray<(Edge, ulong)>> GetGrainCallFrequencies()\n    {\n        var result = ImmutableArray.CreateBuilder<(Edge, ulong)>(_edgeWeights.Count);\n        foreach (var (edge, count, _) in _edgeWeights.Elements)\n        {\n            result.Add((edge, count));\n        }\n\n        return new(result.ToImmutable());\n    }\n\n    private enum Direction : byte\n    {\n        Unspecified,\n        LocalToLocal,\n        LocalToRemote,\n        RemoteToLocal\n    }\n\n    /// <summary>\n    /// Represents a connection between 2 vertices.\n    /// </summary>\n    /// <param name=\"SourceId\">The id of the grain it represents.</param>\n    /// <param name=\"TargetId\">The id of the connected vertex (the one the communication took place with).</param>\n    /// <param name=\"IsMigratable\">Specifies if the vertex with <paramref name=\"SourceId\"/> is a migratable type.</param>\n    /// <param name=\"PartnerSilo\">The silo partner which interacted with the silo of vertex with <paramref name=\"SourceId\"/>.</param>\n    /// <param name=\"Direction\">The edge's direction</param>\n    /// <param name=\"Weight\">The number of estimated messages exchanged between <paramref name=\"SourceId\"/> and <paramref name=\"TargetId\"/>.</param>\n    private readonly record struct VertexEdge(GrainId SourceId, GrainId TargetId, bool IsMigratable, SiloAddress PartnerSilo, Direction Direction, long Weight);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/BlockedBloomFilter.cs",
    "content": "using System.Diagnostics;\nusing System.IO.Hashing;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\n#nullable enable\n\n/// <summary>\n/// A tuned version of a blocked bloom filter implementation.\n/// </summary>\n/// <remarks><i>\n/// <para>This is a tuned version of BBF in order to meet the required FP rate.\n/// Tuning takes a lot of time so this filter can accept FP rates in the rage of [0.1% - 1%]\n/// Any value with the range, at any precision is supported as the FP rate is regressed via polynomial regression</para>\n/// <para>More information can be read from Section 3: https://www.cs.amherst.edu/~ccmcgeoch/cs34/papers/cacheefficientbloomfilters-jea.pdf</para>\n/// </i></remarks>\ninternal sealed class BlockedBloomFilter\n{\n    private const int BlockSize = 32; // higher value yields better speed, but at a high cost of space\n    private const double Ln2Squared = 0.4804530139182014246671025263266649717305529515945455;\n    private const double MinFpRate = 0.001; // 0.1%\n    private const double MaxFpRate = 0.01;  // 1%\n\n    private readonly int _blocks;\n    private readonly int[] _filter;\n\n    // Regression coefficients (derived via polynomial regression) to match 'fpRate' as the actual deviates significantly with lower and lower 'fpRate'\n    // Eg, see https://gist.github.com/ledjon-behluli/d339cbd54568ceb5464d3a947ac8f08e\n    private static readonly double[] Coefficients =\n    [\n         4.0102253166524500e-003,\n        -1.6272682781603145e+001,\n         2.7169897602930665e+004,\n        -2.4527698904812500e+007,\n         1.3273846004698063e+010,\n        -4.4943809759769805e+012,\n         9.5588839677303638e+014,\n        -1.2081452101930328e+017,\n         6.8958853188430172e+018,\n         2.6889929911921561e+020,\n        -7.1061179529975569e+022,\n         4.4109449793357217e+024,\n        -9.8041203512310751e+025\n    ];\n\n    /// <param name=\"capacity\">The estimated population size.</param>\n    /// <param name=\"fpRate\">Bounded within [<see cref=\"MinFpRate\"/> - <see cref=\"MaxFpRate\"/>]</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\"/>\n    public BlockedBloomFilter(int capacity, double fpRate)\n    {\n        if (fpRate is < MinFpRate or > MaxFpRate)\n        {\n            throw new ArgumentOutOfRangeException($\"False positive rate '{fpRate}', is outside of the allowed range '{MinFpRate} - {MaxFpRate}'\");\n        }\n\n        var adjFpRate = RegressFpRate(fpRate);\n        Debug.Assert(adjFpRate < fpRate);\n        var bits = (int)(-1 * capacity * Math.Log(adjFpRate) / Ln2Squared);\n\n        _blocks = bits / BlockSize;\n        _filter = new int[_blocks + 1];\n    }\n\n    private static double RegressFpRate(double fpRate)\n    {\n        double temp = 1;\n        double result = 0;\n\n        foreach (var coefficient in Coefficients)\n        {\n            result += coefficient * temp;\n            temp *= fpRate;\n        }\n\n        return Math.Abs(result);\n    }\n\n    public void Add(GrainId id)\n    {\n        var hash = XxHash3.HashToUInt64(id.Key.AsSpan(), id.GetUniformHashCode());\n        var index = GetBlockIndex(hash, _blocks); // important to get index before rotating the hash\n\n        hash ^= BitOperations.RotateLeft(hash, 32);\n\n        // We use 2 masks to distribute the bits of the hash value across multiple positions in the filter\n        var mask1 = ComputeMask1(hash);\n        var mask2 = ComputeMask2(hash);\n\n        // We set the bits across 2 blocks so that the bits from a single hash value, are spread out more evenly across the filter.\n        _filter[index] |= mask1;\n        _filter[index + 1] |= mask2;\n    }\n\n    public bool Contains(GrainId id)\n    {\n        var hash = XxHash3.HashToUInt64(id.Key.AsSpan(), id.GetUniformHashCode());\n        var index = GetBlockIndex(hash, _blocks); // important to get index before rotating the hash\n\n        hash ^= BitOperations.RotateLeft(hash, 32);\n\n        var block1 = _filter[index];\n        var block2 = _filter[index + 1];\n\n        var mask1 = ComputeMask1(hash);\n        var mask2 = ComputeMask2(hash);\n\n        return (mask1 & block1) == mask1 && (mask2 & block2) == mask2;\n    }\n\n    public void Reset() => Array.Clear(_filter);\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static int GetBlockIndex(ulong hash, int buckets) => (int)(((int)hash & 0xffffffffL) * buckets >> 32);\n\n    /// <summary>\n    /// Sets the bits of <paramref name=\"hash\"/> corresponding to the lower-order bits, and the bits shifted by 6 positions to the right\n    /// </summary>\n    /// <param name=\"hash\">The rotated hash</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static int ComputeMask1(ulong hash) => (1 << (int)hash) | (1 << ((int)hash >> 6));\n\n    /// <summary>\n    /// Sets the bits of <paramref name=\"hash\"/>, and the bits shifted by 12 and 18 positions to the right\n    /// </summary>\n    /// <param name=\"hash\">The rotated hash</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static int ComputeMask2(ulong hash) => (1 << ((int)hash >> 12)) | (1 << ((int)hash >> 18));\n}\n\n/// <summary>\n/// Implemented as a set of <see cref=\"BlockedBloomFilter\"/>(s) that rotate anchored grains.\n/// If a grain is \"hot\" it will likely survive multiple cycles, otherwise it gets dropped out.\n/// </summary>\ninternal sealed class AnchoredGrainsFilter\n{\n    // Index 0 is the \"active\" filter.\n    // Indexes 1 through N-1 are the \"retiring\" filters.\n    private readonly BlockedBloomFilter[] _filters;\n\n    public AnchoredGrainsFilter(int capacity, double fpRate, int generations)\n    {\n        if (generations < 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(generations), \"Must have at least 1 generation.\");\n        }\n\n        _filters = new BlockedBloomFilter[generations];\n\n        for (var i = 0; i < generations; i++)\n        {\n            _filters[i] = new BlockedBloomFilter(capacity, fpRate);\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Add(GrainId id) => _filters[0].Add(id);\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool Contains(GrainId id)\n    {\n        for (var i = 0; i < _filters.Length; i++)\n        {\n            if (_filters[i].Contains(id))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public void Rotate()\n    {\n        // Idea is to rotate the inner filters to implement a sort of sliding window.\n        // The previous active (index 0) shifts down, remaining \"checkable\" for n-1 more cycles, then fades unless re-added.\n        // This ensures \"cold\" grains eventually drop out, while \"hot\" ones stay anchored.\n\n        var length = _filters.Length;\n\n        // We grab the oldest filter and reset it so it becomes the new active one.\n        var nextActive = _filters[length - 1];\n        nextActive.Reset();\n\n        // Need to shift all existing generations down by 1. We iterate backwards\n        // so we dont overwrite elements we havent shifted yet.\n\n        for (var i = length - 1; i > 0; i--)\n        {\n            _filters[i] = _filters[i - 1];\n        }\n\n        // The newly reset filter goes at the front.\n        _filters[0] = nextActive;\n    }\n\n    public void Reset()\n    {\n        var filters = _filters;\n\n        for (var i = 0; i < filters.Length; i++)\n        {\n            filters[i].Reset();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/FrequentItemCollection.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing Orleans.Placement.Repartitioning;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\ninternal sealed class FrequentEdgeCounter(int capacity) : FrequentItemCollection<ulong, Edge>(capacity)\n{\n    protected override ulong GetKey(in Edge element) => ((ulong)element.Source.Id.GetUniformHashCode()) << 32 | element.Target.Id.GetUniformHashCode();\n    public void Clear() => ClearCore();\n    public void Remove(in Edge element) => RemoveCore(GetKey(element));\n}\n\n// This is Implementation of \"Filtered Space-Saving\" from \"Finding top-k elements in data streams\"\n// by Nuno Homem &amp; Joao Paulo Carvalho (https://www.hlt.inesc-id.pt/~fmmb/references/misnis.ref0a.pdf). \n// In turn, this is a modification of the \"Space-Saving\" algorithm by Metwally, Agrawal, and Abbadi,\n// Described in \"Efficient Computation of Frequent and Top-k Elements in Data Streams\" (https://www.cs.emory.edu/~cheung/Courses/584/Syllabus/papers/Frequency-count/2005-Metwally-Top-k-elements.pdf).\n// This is implemented using an in-lined version of .NET's PriorityQueue which has been modified\n// to support incrementing a value and with an index mapping key hashes to heap indexes.\ninternal abstract class FrequentItemCollection<TKey, TElement>(int capacity) where TElement : notnull where TKey : notnull\n{\n    /// <summary>\n    /// Represents an implicit heap-ordered complete d-ary tree, stored as an array.\n    /// </summary>\n    private Counter[] _heap = [];\n\n    /// <summary>\n    /// A dictionary that maps the hash of a key to its index in the heap.\n    /// </summary>\n    private readonly Dictionary<TKey, int> _heapIndex = [];\n\n    /// <summary>\n    /// The number of nodes in the heap.\n    /// </summary>\n    private int _heapSize;\n\n    /// <summary>\n    /// Specifies the arity of the d-ary heap, which here is quaternary.\n    /// It is assumed that this value is a power of 2.\n    /// </summary>\n    private const int Arity = 4;\n\n    /// <summary>\n    /// The binary logarithm of <see cref=\"Arity\" />.\n    /// </summary>\n    private const int Log2Arity = 2;\n\n    /// <summary>\n    /// Contains count estimates for keys that are not being tracked, indexed by the hash of the key.\n    /// Collisions are expected.\n    /// </summary>\n    private readonly uint[] _sketch = new uint[GetSketchSize(capacity)];\n\n    /// <summary>\n    /// Gets the number of elements contained in the <see cref=\"FrequentItemCollection{TKey,TElement}\"/>.\n    /// </summary>\n    public int Count => _heapSize;\n\n    /// <summary>\n    /// Gets the number of elements which the <see cref=\"FrequentItemCollection{TKey, TElement}\"/> will track.\n    /// </summary>\n    public int Capacity { get; } = capacity;\n\n#if DEBUG\n    static FrequentItemCollection()\n    {\n        Debug.Assert(Log2Arity > 0 && Math.Pow(2, Log2Arity) == Arity);\n    }\n#endif\n\n    /// <summary>\n    /// Returns a collection of up to <see cref=\"Capacity\"/> keys, along with their count estimates, in unspecified order.\n    /// </summary>\n    public ElementEnumerator Elements => new(this);\n\n    protected abstract TKey GetKey(in TElement element);\n\n    public void Add(in TElement element)\n    {\n        const int Increment = 1;\n        var nodeIndexHash = GetKey(element);\n\n        // Increase count of a key that is already being tracked.\n        // There is a minute chance of a hash collision, which is deemed acceptable and ignored.\n        if (_heapIndex.TryGetValue(nodeIndexHash, out var index))\n        {\n            ref var counter = ref _heap[index];\n            counter.Count += Increment;\n            MoveUpHeap(counter, index, nodeIndexHash);\n            return;\n        }\n\n        // Key is not being tracked, but can fit in the top K, so add it.\n        if (Count < Capacity)\n        {\n            InsertHeap(new Counter(element, Increment, error: 0), nodeIndexHash);\n            return;\n        }\n\n        var min = _heap[0];\n\n        // Filter out values which are estimated to have appeared less frequently than the minimum.\n        var sketchMask = _sketch.Length - 1;\n        var sketchHash = nodeIndexHash.GetHashCode();\n        var countEstimate = _sketch[sketchHash & sketchMask];\n        if (countEstimate + Increment < min.Count)\n        {\n            // Increase the count estimate.\n            _sketch[sketchHash & sketchMask] += Increment;\n            return;\n        }\n\n        // Remove the minimum element from the hash index.\n        var minIndexHash = GetKey(min.Element);\n        _heapIndex.Remove(minIndexHash);\n\n        // While evicting the minimum element, update its counter in the sketch to improve the chance of it\n        // passing the filter in the future.\n        var minHash = minIndexHash.GetHashCode();\n        _sketch[minHash & sketchMask] = min.Count;\n\n        // Push the new element in place of the last and move it down until it's in position.\n        MoveDownHeap(new Counter(element, countEstimate + Increment, error: countEstimate), 0, nodeIndexHash);\n    }\n\n    /// <summary>\n    /// Removes the counter corresponding to the specified hash.\n    /// </summary>\n    /// <param name=\"key\">The key of the value to remove.</param>\n    /// <returns><see langword=\"true\"/> if matching entry was found and removed, <see langword=\"false\"/> otherwise.</returns>\n    protected bool RemoveCore(TKey key)\n    {\n        // Remove the element from the sketch\n        var sketchMask = _sketch.Length - 1;\n        var sketchHash = key.GetHashCode();\n        _sketch[sketchHash & sketchMask] = 0;\n\n        // Remove the element from the heap index\n        if (!_heapIndex.Remove(key, out var index))\n        {\n            return false;\n        }\n\n        // Remove the element from the heap\n        var nodes = _heap;\n        var newSize = --_heapSize;\n        if (index < newSize)\n        {\n            // We're removing an element from the middle of the heap.\n            // Pop the last element in the collection and sift downward from the removed index.\n            var lastNode = nodes[newSize];\n\n            MoveDownHeap(lastNode, index, GetKey(lastNode.Element));\n        }\n\n        nodes[newSize] = default;\n\n        return true;\n    }\n\n    protected void ClearCore()\n    {\n        Array.Clear(_heap, 0, _heapSize);\n        _heapIndex.Clear();\n        Array.Clear(_sketch);\n        _heapSize = 0;\n    }\n\n    private static int GetSketchSize(int capacity)\n    {\n        // Suggested constants in the paper \"Finding top-k elements in data streams\", chap 6. equation (24)\n        // Round to nearest power of 2 for cheaper binning without modulo\n        const int SketchEntriesPerHeapEntry = 6;\n\n        return 1 << 32 - int.LeadingZeroCount(capacity * SketchEntriesPerHeapEntry);\n    }\n\n    /// <summary>\n    ///  Adds the specified element to the <see cref=\"FrequentItemCollection{TKey, TElement}\"/>.\n    /// </summary>\n    /// <param name=\"element\">The element to add.</param>\n    private void InsertHeap(Counter element, TKey key)\n    {\n        // Virtually add the node at the end of the underlying array.\n        // Note that the node being enqueued does not need to be physically placed\n        // there at this point, as such an assignment would be redundant.\n\n        var currentSize = _heapSize;\n\n        if (_heap.Length == currentSize)\n        {\n            GrowHeap(currentSize + 1);\n        }\n\n        _heapSize = currentSize + 1;\n\n        MoveUpHeap(element, currentSize, key);\n    }\n\n    /// <summary>\n    /// Grows the priority queue to match the specified min capacity.\n    /// </summary>\n    private void GrowHeap(int minCapacity)\n    {\n        Debug.Assert(_heap.Length < minCapacity);\n\n        const int GrowFactor = 2;\n        const int MinimumGrow = 4;\n\n        var newCapacity = GrowFactor * _heap.Length;\n\n        // Allow the queue to grow to maximum possible capacity (~2G elements) before encountering overflow.\n        // Note that this check works even when _nodes.Length overflowed thanks to the (uint) cast\n        if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength;\n\n        // Ensure minimum growth is respected.\n        newCapacity = Math.Max(newCapacity, _heap.Length + MinimumGrow);\n\n        // If the computed capacity is still less than specified, set to the original argument.\n        // Capacities exceeding Array.MaxLength will be surfaced as OutOfMemoryException by Array.Resize.\n        if (newCapacity < minCapacity) newCapacity = minCapacity;\n\n        Array.Resize(ref _heap, newCapacity);\n    }\n\n    /// <summary>\n    /// Gets the index of an element's parent.\n    /// </summary>\n    private static int GetParentIndex(int index) => index - 1 >> Log2Arity;\n\n    /// <summary>\n    /// Gets the index of the first child of an element.\n    /// </summary>\n    private static int GetFirstChildIndex(int index) => (index << Log2Arity) + 1;\n\n    /// <summary>\n    /// Moves a node up in the tree to restore heap order.\n    /// </summary>\n    private void MoveUpHeap(Counter node, int nodeIndex, TKey nodeKey)\n    {\n        // Instead of swapping items all the way to the root, we will perform\n        // a similar optimization as in the insertion sort.\n\n        Debug.Assert(0 <= nodeIndex && nodeIndex < _heapSize);\n\n        var nodes = _heap;\n        var hashIndex = _heapIndex;\n\n        while (nodeIndex > 0)\n        {\n            var parentIndex = GetParentIndex(nodeIndex);\n            var parent = nodes[parentIndex];\n\n            if (node.CompareTo(parent) < 0)\n            {\n                nodes[nodeIndex] = parent;\n                hashIndex[GetKey(parent.Element)] = nodeIndex;\n                nodeIndex = parentIndex;\n            }\n            else\n            {\n                break;\n            }\n        }\n\n        nodes[nodeIndex] = node;\n        hashIndex[nodeKey] = nodeIndex;\n    }\n\n    /// <summary>\n    /// Moves a node down in the tree to restore heap order.\n    /// </summary>\n    private void MoveDownHeap(Counter node, int nodeIndex, TKey nodeKey)\n    {\n        // The node to move down will not actually be swapped every time.\n        // Rather, values on the affected path will be moved up, thus leaving a free spot\n        // for this value to drop in. Similar optimization as in the insertion sort.\n\n        Debug.Assert(0 <= nodeIndex && nodeIndex < _heapSize);\n\n        var nodes = _heap;\n        var size = _heapSize;\n        var hashIndex = _heapIndex;\n\n        int i;\n        while ((i = GetFirstChildIndex(nodeIndex)) < size)\n        {\n            // Find the child node with the minimal priority\n            var minChild = nodes[i];\n            var minChildIndex = i;\n\n            var childIndexUpperBound = Math.Min(i + Arity, size);\n            while (++i < childIndexUpperBound)\n            {\n                var nextChild = nodes[i];\n                if (nextChild.CompareTo(minChild) < 0)\n                {\n                    minChild = nextChild;\n                    minChildIndex = i;\n                }\n            }\n\n            // Heap property is satisfied; insert node in this location.\n            if (node.CompareTo(minChild) <= 0)\n            {\n                break;\n            }\n\n            // Move the minimal child up by one node and continue recursively from its location.\n            nodes[nodeIndex] = minChild;\n            hashIndex[GetKey(minChild.Element)] = nodeIndex;\n            nodeIndex = minChildIndex;\n        }\n\n        hashIndex[nodeKey] = nodeIndex;\n        nodes[nodeIndex] = node;\n    }\n\n    private struct Counter(TElement element, uint count, uint error) : IComparable<Counter>\n    {\n        public readonly TElement Element = element;\n        public uint Count = count;\n        public uint Error = error;\n\n        public readonly int CompareTo(Counter other) => ((ulong)Count << 32 | uint.MaxValue - Error).CompareTo((ulong)other.Count << 32 | uint.MaxValue - other.Error);\n\n        public override readonly string ToString() => $\"{Element}: Count: {Count} Error: {Error}\";\n    }\n\n    /// <summary>\n    ///  Enumerates the element and priority pairs of a <see cref=\"FrequentItemCollection{TKey, TElement}\"/>,\n    ///  without any ordering guarantees.\n    /// </summary>\n    public struct ElementEnumerator : IEnumerator<(TElement Element, uint Count, uint Error)>, IEnumerable<(TElement Element, uint Count, uint Error)>\n    {\n        private readonly FrequentItemCollection<TKey, TElement> _heap;\n        private int _index;\n        private Counter _current;\n\n        internal ElementEnumerator(FrequentItemCollection<TKey, TElement> heap)\n        {\n            _heap = heap;\n            _index = 0;\n            _current = default;\n        }\n\n        /// <summary>\n        /// Releases all resources used by the <see cref=\"ElementEnumerator\"/>.\n        /// </summary>\n        public readonly void Dispose() { }\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the heap.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            var localHeap = _heap;\n\n            if ((uint)_index < (uint)localHeap._heapSize)\n            {\n                _current = localHeap._heap[_index];\n                _index++;\n                return true;\n            }\n\n            return MoveNextRare();\n        }\n\n        private bool MoveNextRare()\n        {\n            _index = _heap._heapSize + 1;\n            _current = default;\n            return false;\n        }\n\n        /// <summary>\n        /// Gets the element at the current position of the enumerator.\n        /// </summary>\n        public readonly (TElement Element, uint Count, uint Error) Current => (_current.Element, _current.Count, _current.Error);\n\n        readonly object IEnumerator.Current => _current;\n\n        void IEnumerator.Reset()\n        {\n            _index = 0;\n            _current = default;\n        }\n\n        public readonly ElementEnumerator GetEnumerator() => this;\n        readonly IEnumerator<(TElement Element, uint Count, uint Error)> IEnumerable<(TElement Element, uint Count, uint Error)>.GetEnumerator() => this;\n        readonly IEnumerator IEnumerable.GetEnumerator() => this;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/MaxHeap.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing Orleans.Placement.Repartitioning;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\ninternal enum VertexLocation\n{\n    Unknown,\n    Local,\n    Remote\n}\n\n[DebuggerDisplay(\"{Vertex} @ {Location}\")]\ninternal sealed class CandidateVertexHeapElement(CandidateVertex value) : IHeapElement<CandidateVertexHeapElement>\n{\n    public CandidateVertex Vertex { get; } = value;\n    public List<(CandidateVertexHeapElement Element, long TransferScore)> ConnectedVertices { get; } = [];\n    public GrainId Id => Vertex.Id;\n    public long AccumulatedTransferScore { get => Vertex.AccumulatedTransferScore; set => Vertex.AccumulatedTransferScore = value; }\n    public VertexLocation Location { get; set; }\n    int IHeapElement<CandidateVertexHeapElement>.HeapIndex { get; set; } = -1;\n    int IHeapElement<CandidateVertexHeapElement>.CompareTo(CandidateVertexHeapElement other) => AccumulatedTransferScore.CompareTo(other.AccumulatedTransferScore);\n}\n\ninternal interface IHeapElement<TElement> where TElement : notnull\n{\n    int HeapIndex { get; set; }\n    int CompareTo(TElement other);\n}\n\n/// <summary>\n///  Represents a max heap.\n/// </summary>\n/// <typeparam name=\"TElement\">Specifies the type of elements in the heap.</typeparam>\n/// <remarks>\n///  Implements an array-backed quaternary max-heap.\n///  Elements with the lowest priority get removed first.\n///  Note: this is based on .NET's PriorityQueue: https://github.com/dotnet/runtime/blob/e78b72b1fdf43d9678877400bcfe801b38c14681/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs\n/// </remarks>\n[DebuggerDisplay(\"Count = {Count}\")]\ninternal sealed class MaxHeap<TElement> where TElement : notnull, IHeapElement<TElement>\n{\n    /// <summary>\n    /// Represents an implicit heap-ordered complete d-ary tree, stored as an array.\n    /// </summary>\n    private readonly TElement?[] _nodes;\n\n    /// <summary>\n    /// The number of nodes in the heap.\n    /// </summary>\n    private int _size;\n\n    /// <summary>\n    /// Specifies the arity of the d-ary heap, which here is quaternary.\n    /// It is assumed that this value is a power of 2.\n    /// </summary>\n    private const int Arity = 4;\n\n    /// <summary>\n    /// The binary logarithm of <see cref=\"Arity\" />.\n    /// </summary>\n    private const int Log2Arity = 2;\n\n#if DEBUG\n    static MaxHeap()\n    {\n        Debug.Assert(Log2Arity > 0 && Math.Pow(2, Log2Arity) == Arity);\n    }\n#endif\n\n    /// <summary>\n    ///  Initializes a new instance of the <see cref=\"MaxHeap{TElement}\"/> class\n    ///  that is populated with the specified elements and priorities.\n    /// </summary>\n    /// <param name=\"items\">The pairs of elements and priorities with which to populate the queue.</param>\n    /// <exception cref=\"ArgumentNullException\">\n    ///  The specified <paramref name=\"items\"/> argument was <see langword=\"null\"/>.\n    /// </exception>\n    /// <remarks>\n    ///  Constructs the heap using a heapify operation,\n    ///  which is generally faster than enqueuing individual elements sequentially.\n    /// </remarks>\n    public MaxHeap(List<TElement> items)\n    {\n        ArgumentNullException.ThrowIfNull(items);\n\n        _size = items.Count;\n        var nodes = new TElement[_size];\n\n        var i = 0;\n        foreach (var item in items)\n        {\n            nodes[i] = item;\n            Debug.Assert(item.HeapIndex == -1);\n            item.HeapIndex = i;\n            i++;\n        }\n\n        _nodes = nodes;\n        if (_size > 1)\n        {\n            Heapify();\n        }\n        else if (_size == 1)\n        {\n            _nodes[0]!.HeapIndex = 0;\n        }\n    }\n\n    /// <summary>\n    ///  Gets the number of elements contained in the <see cref=\"MaxHeap{TElement}\"/>.\n    /// </summary>\n    public int Count => _size;\n\n    public TElement? FirstOrDefault() => _size > 0 ? _nodes[0] : default;\n\n    public bool TryPeek([NotNullWhen(true)] out TElement value)\n    {\n        if (_size > 0)\n        {\n            value = _nodes[0]!;\n            return true;\n        }\n\n        value = default!;\n        return false;\n    }\n\n    /// <summary>\n    ///  Returns the maximal element from the <see cref=\"MaxHeap{TElement}\"/> without removing it.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">The <see cref=\"MaxHeap{TElement}\"/> is empty.</exception>\n    /// <returns>The maximal element of the <see cref=\"MaxHeap{TElement}\"/>.</returns>\n    public TElement Peek()\n    {\n        if (_size == 0)\n        {\n            throw new InvalidOperationException(\"Collection is empty.\");\n        }\n\n        return _nodes[0]!;\n    }\n\n    public bool TryPop([NotNullWhen(true)] out TElement value)\n    {\n        if (_size > 0)\n        {\n            value = Pop();\n            return true;\n        }\n\n        value = default!;\n        return false;\n    }\n\n    /// <summary>\n    ///  Removes and returns the maximal element from the <see cref=\"MaxHeap{TElement}\"/>.\n    /// </summary>\n    /// <exception cref=\"InvalidOperationException\">The queue is empty.</exception>\n    /// <returns>The maximal element of the <see cref=\"MaxHeap{TElement}\"/>.</returns>\n    public TElement Pop()\n    {\n        if (_size == 0)\n        {\n            throw new InvalidOperationException(\"Collection is empty.\");\n        }\n\n        var element = _nodes[0]!;\n        RemoveRootNode();\n        element.HeapIndex = -1;\n        return element;\n\n        void RemoveRootNode()\n        {\n            var lastNodeIndex = --_size;\n\n            if (lastNodeIndex > 0)\n            {\n                var lastNode = _nodes[lastNodeIndex]!;\n                MoveDown(lastNode, 0);\n            }\n\n            if (RuntimeHelpers.IsReferenceOrContainsReferences<TElement>())\n            {\n                _nodes[lastNodeIndex] = default!;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Gets the index of an element's parent.\n    /// </summary>\n    private static int GetParentIndex(int index) => (index - 1) >> Log2Arity;\n\n    /// <summary>\n    /// Gets the index of the first child of an element.\n    /// </summary>\n    private static int GetFirstChildIndex(int index) => (index << Log2Arity) + 1;\n\n    public void OnDecreaseElementPriority(TElement element)\n    {\n        // If the element has already been removed from the heap, this is a no-op.\n        if (element.HeapIndex < 0)\n        {\n            return;\n        }\n\n        // The element's priority has decreased, so move it down as necessary to restore the heap property.\n        MoveDown(element, element.HeapIndex);\n    }\n\n    public void OnIncreaseElementPriority(TElement element)\n    {\n        // If the element has already been removed from the heap, this is a no-op.\n        if (element.HeapIndex <= 0)\n        {\n            return;\n        }\n\n        // The element's priority has increased, so move it down as necessary to restore the heap property.\n        MoveUp(element, element.HeapIndex);\n    }\n\n    /// <summary>\n    /// Converts an unordered list into a heap.\n    /// </summary>\n    public void Heapify()\n    {\n        // Leaves of the tree are in fact 1-element heaps, for which there\n        // is no need to correct them. The heap property needs to be restored\n        // only for higher nodes, starting from the first node that has children.\n        // It is the parent of the very last element in the array.\n\n        var nodes = _nodes;\n        var lastParentWithChildren = GetParentIndex(_size - 1);\n        for (var index = lastParentWithChildren; index >= 0; --index)\n        {\n            MoveDown(nodes[index]!, index);\n        }\n    }\n\n    /// <summary>\n    /// Gets the elements in this collection with specified order.\n    /// </summary>\n    public UnorderedElementEnumerable UnorderedElements => new(this);\n\n    /// <summary>\n    /// Moves a node up in the tree to restore heap order.\n    /// </summary>\n    private void MoveUp(TElement node, int nodeIndex)\n    {\n        Debug.Assert(0 <= nodeIndex && nodeIndex < _size);\n\n        var nodes = _nodes;\n\n        while (nodeIndex > 0)\n        {\n            var parentIndex = GetParentIndex(nodeIndex);\n            var parentNode = nodes[parentIndex]!;\n\n            if (node.CompareTo(parentNode) <= 0)\n            {\n                // The parent is more larger than the current node.\n                break;\n            }\n\n            nodes[nodeIndex] = parentNode;\n            parentNode.HeapIndex = nodeIndex;\n            nodeIndex = parentIndex;\n        }\n\n        nodes[nodeIndex] = node;\n        node.HeapIndex = nodeIndex;\n    }\n\n    /// <summary>\n    /// Moves a node down in the tree to restore heap order.\n    /// </summary>\n    private void MoveDown(TElement node, int nodeIndex)\n    {\n        // The node to move down will not actually be swapped every time.\n        // Rather, values on the affected path will be moved up, thus leaving a free spot\n        // for this value to drop in. Similar optimization as in the insertion sort.\n\n        Debug.Assert(0 <= nodeIndex && nodeIndex < _size);\n\n        var nodes = _nodes;\n        var size = _size;\n\n        int i;\n        while ((i = GetFirstChildIndex(nodeIndex)) < size)\n        {\n            // Find the child node with the maximal priority\n            var maxChild = nodes[i]!;\n            var maxChildIndex = i;\n\n            var childIndexUpperBound = Math.Min(i + Arity, size);\n            while (++i < childIndexUpperBound)\n            {\n                var nextChild = nodes[i]!;\n                if (nextChild.CompareTo(maxChild) > 0)\n                {\n                    maxChild = nextChild;\n                    maxChildIndex = i;\n                }\n            }\n\n            // Heap property is satisfied; insert node in this location.\n            if (node.CompareTo(maxChild) >= 0)\n            {\n                break;\n            }\n\n            // Move the maximal child up by one node and\n            // continue recursively from its location.\n            nodes[nodeIndex] = maxChild;\n            maxChild.HeapIndex = nodeIndex;\n            nodeIndex = maxChildIndex;\n        }\n\n        nodes[nodeIndex] = node;\n        node.HeapIndex = nodeIndex;\n    }\n\n    /// <summary>\n    ///  Enumerates the element and priority pairs of a <see cref=\"MaxHeap{TElement}\"/>\n    ///  without any ordering guarantees.\n    /// </summary>\n    public struct UnorderedElementEnumerable : IEnumerator<TElement>, IEnumerable<TElement>\n    {\n        private readonly MaxHeap<TElement> _heap;\n        private int _index;\n        private TElement? _current;\n\n        internal UnorderedElementEnumerable(MaxHeap<TElement> heap)\n        {\n            _heap = heap;\n            _index = 0;\n            _current = default;\n        }\n\n        /// <summary>\n        /// Releases all resources used by the <see cref=\"UnorderedElementEnumerable\"/>.\n        /// </summary>\n        public readonly void Dispose() { }\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the heap.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            var localHeap = _heap;\n\n            if ((uint)_index < (uint)localHeap._size)\n            {\n                _current = localHeap._nodes[_index];\n                _index++;\n                return true;\n            }\n\n            return MoveNextRare();\n        }\n\n        private bool MoveNextRare()\n        {\n            _index = _heap._size + 1;\n            _current = default;\n            return false;\n        }\n\n        /// <summary>\n        /// Gets the element at the current position of the enumerator.\n        /// </summary>\n        public readonly TElement Current => _current ?? throw new InvalidOperationException(\"Current element is not valid.\");\n\n        readonly object IEnumerator.Current => Current;\n\n        public readonly UnorderedElementEnumerable GetEnumerator() => this;\n        readonly IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator() => this;\n        void IEnumerator.Reset()\n        {\n            _index = 0;\n            _current = default;\n        }\n\n        readonly IEnumerator IEnumerable.GetEnumerator() => this;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/RebalancerCompatibleRule.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Threading;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Placement.Rebalancing;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\n#nullable enable\n\n/// <summary>\n/// Tolerance rule which is aware of the cluster size, and if rebalancer is enabled, it scales with the clusters imbalance.\n/// </summary>\n/// <remarks>https://www.ledjonbehluli.com/posts/orleans_repartioner_rebalancer_coexistence/</remarks>\ninternal class RebalancerCompatibleRule(IServiceProvider provider) :\n    IImbalanceToleranceRule, ILifecycleParticipant<ISiloLifecycle>,\n    ILifecycleObserver, ISiloStatusListener, IActivationRebalancerReportListener\n{\n#if NET9_0_OR_GREATER\n    private readonly Lock _lock = new();\n#else\n    private readonly object _lock = new();\n#endif\n    private readonly Dictionary<SiloAddress, SiloStatus> _silos = [];\n\n    private uint _pairwiseImbalance;\n    private double _clusterImbalance; // If rebalancer is not registered this has no effect on computing the tolerance.\n\n    private readonly ISiloStatusOracle _oracle = provider.GetRequiredService<ISiloStatusOracle>();\n    private readonly IActivationRebalancer? _rebalancer = provider.GetService<IActivationRebalancer>();\n\n    public bool IsSatisfiedBy(uint imbalance) => imbalance <= Volatile.Read(ref _pairwiseImbalance);\n\n    public void SiloStatusChangeNotification(SiloAddress silo, SiloStatus status)\n    {\n        lock (_lock)\n        {\n            ref var statusRef = ref CollectionsMarshal.GetValueRefOrAddDefault(_silos, silo, out _);\n            statusRef = status;\n            UpdatePairwiseImbalance();\n        }\n    }\n\n    public void Participate(ISiloLifecycle lifecycle)\n        => lifecycle.Subscribe(nameof(RebalancerCompatibleRule),\n               ServiceLifecycleStage.ApplicationServices, this);\n\n    public void OnReport(RebalancingReport report)\n    {\n        lock (_lock)\n        {\n            _clusterImbalance = report.ClusterImbalance;\n            UpdatePairwiseImbalance();\n        }\n    }\n\n    private void UpdatePairwiseImbalance()\n    {\n        var activeSilos = _silos.Count(s => s.Value == SiloStatus.Active);\n        var percentageOfBaseline = 100d / (1 + Math.Exp(0.07d * activeSilos - 4.8d));\n\n        if (percentageOfBaseline < 10d) percentageOfBaseline = 10d;\n\n        var pairwiseImbalance = (uint)Math.Round(10.1d * percentageOfBaseline, 0);\n        var toleranceFactor = Math.Cos(Math.PI * _clusterImbalance / 2);  // This will always be 1 if rebalancer is not registered.\n\n        _pairwiseImbalance = (uint)Math.Max(pairwiseImbalance * toleranceFactor, 0);\n    }\n\n    public Task OnStart(CancellationToken cancellationToken)\n    {\n        _oracle.SubscribeToSiloStatusEvents(this);\n        _rebalancer?.SubscribeToReports(this);\n\n        return Task.CompletedTask;\n    }\n\n    public Task OnStop(CancellationToken cancellationToken)\n    {\n        _oracle.UnSubscribeFromSiloStatusEvents(this);\n        _rebalancer?.UnsubscribeFromReports(this);\n\n        return Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/Repartitioning/RepartitionerMessageFilter.cs",
    "content": "#nullable enable\n\nusing Orleans.Placement;\n\nnamespace Orleans.Runtime.Placement.Repartitioning;\n\ninternal interface IRepartitionerMessageFilter\n{\n    bool IsAcceptable(Message message, out bool isSenderMigratable, out bool isTargetMigratable);\n}\n\ninternal sealed class RepartitionerMessageFilter(GrainMigratabilityChecker checker) : IRepartitionerMessageFilter\n{\n    public bool IsAcceptable(Message message, out bool isSenderMigratable, out bool isTargetMigratable)\n    {\n        isSenderMigratable = false;\n        isTargetMigratable = false;\n\n        // There are some edge cases when this can happen i.e. a grain invoking another one of its methods via AsReference<>, but we still exclude it\n        // as wherever this grain would be located in the cluster, it would always be a local call (since it targets itself), this would add negative transfer cost\n        // which would skew a potential relocation of this grain, while it shouldn't, because whenever this grain is located, it would still make local calls to itself.\n        if (message.SendingGrain == message.TargetGrain)\n        {\n            return false;\n        }\n\n        isSenderMigratable = checker.IsMigratable(message.SendingGrain.Type, ImmovableKind.Repartitioner);\n        isTargetMigratable = checker.IsMigratable(message.TargetGrain.Type, ImmovableKind.Repartitioner);\n\n        // If both are not migratable types we ignore this. But if one of them is not, then we allow passing, as we wish to move grains closer to them, as with any type of grain.\n        return isSenderMigratable || isTargetMigratable;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/ResourceOptimizedPlacementDirector.cs",
    "content": "#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Placement;\n\n// See: https://www.ledjonbehluli.com/posts/orleans_resource_placement_kalman/\ninternal sealed class ResourceOptimizedPlacementDirector : IPlacementDirector, ISiloStatisticsChangeListener\n{\n    private const int FourKiloByte = 4096;\n    private readonly SiloAddress _localSilo;\n    private readonly NormalizedWeights _weights;\n    private readonly float _localSiloPreferenceMargin;\n    private readonly ConcurrentDictionary<SiloAddress, ResourceStatistics> _siloStatistics = [];\n    private readonly Task<SiloAddress> _cachedLocalSilo;\n\n    public ResourceOptimizedPlacementDirector(\n        ILocalSiloDetails localSiloDetails,\n        DeploymentLoadPublisher deploymentLoadPublisher,\n        IOptions<ResourceOptimizedPlacementOptions> options)\n    {\n        _localSilo = localSiloDetails.SiloAddress;\n        _cachedLocalSilo = Task.FromResult(_localSilo);\n        _weights = NormalizeWeights(options.Value);\n        _localSiloPreferenceMargin = (float)options.Value.LocalSiloPreferenceMargin / 100;\n        deploymentLoadPublisher.SubscribeToStatisticsChangeEvents(this);\n    }\n\n    private static NormalizedWeights NormalizeWeights(ResourceOptimizedPlacementOptions input)\n    {\n        int totalWeight = input.CpuUsageWeight + input.MemoryUsageWeight + input.AvailableMemoryWeight + input.MaxAvailableMemoryWeight + input.ActivationCountWeight;\n\n        return totalWeight == 0 ? new(0f, 0f, 0f, 0f, 0f) :\n            new(\n                CpuUsageWeight: (float)input.CpuUsageWeight / totalWeight,\n                MemoryUsageWeight: (float)input.MemoryUsageWeight / totalWeight,\n                AvailableMemoryWeight: (float)input.AvailableMemoryWeight / totalWeight,\n                MaxAvailableMemoryWeight: (float)input.MaxAvailableMemoryWeight / totalWeight,\n                ActivationCountWeight: (float)input.ActivationCountWeight / totalWeight);\n    }\n\n    public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n    {\n        var compatibleSilos = context.GetCompatibleSilos(target);\n\n        if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint)\n        {\n            return Task.FromResult(placementHint);\n        }\n\n        if (compatibleSilos.Length == 0)\n        {\n            throw new SiloUnavailableException($\"Cannot place grain '{target.GrainIdentity}' because there are no compatible silos.\");\n        }\n\n        if (compatibleSilos.Length == 1)\n        {\n            return Task.FromResult(compatibleSilos[0]);\n        }\n\n        if (_siloStatistics.IsEmpty)\n        {\n            return Task.FromResult(compatibleSilos[Random.Shared.Next(compatibleSilos.Length)]);\n        }\n\n        // It is good practice not to allocate more than 1[KB] on the stack\n        // but the size of ValueTuple<int, ResourceStatistics> = 24 bytes, by increasing\n        // the limit to 4[KB] we can stackalloc for up to 4096 / 24 ~= 170 silos in a cluster.\n        (int Index, float Score, float? LocalSiloScore) pick;\n        int compatibleSilosCount = compatibleSilos.Length;\n        if (compatibleSilosCount * Unsafe.SizeOf<(int, ResourceStatistics)>() <= FourKiloByte)\n        {\n            pick = MakePick(stackalloc (int, ResourceStatistics)[compatibleSilosCount]);\n        }\n        else\n        {\n            var relevantSilos = ArrayPool<(int, ResourceStatistics)>.Shared.Rent(compatibleSilosCount);\n            pick = MakePick(relevantSilos.AsSpan());\n            ArrayPool<(int, ResourceStatistics)>.Shared.Return(relevantSilos);\n        }\n\n        var localSiloScore = pick.LocalSiloScore;\n        if (!localSiloScore.HasValue || context.LocalSiloStatus != SiloStatus.Active || localSiloScore.Value - _localSiloPreferenceMargin > pick.Score)\n        {\n            var bestCandidate = compatibleSilos[pick.Index];\n            return Task.FromResult(bestCandidate);\n        }\n\n        return _cachedLocalSilo;\n\n        (int PickIndex, float PickScore, float? LocalSiloScore) MakePick(scoped Span<(int, ResourceStatistics)> relevantSilos)\n        {\n            // Get all compatible silos which aren't overloaded\n            int relevantSilosCount = 0;\n            float maxMaxAvailableMemory = 0;\n            int maxActivationCount = 0;\n            ResourceStatistics? localSiloStatistics = null;\n            for (var i = 0; i < compatibleSilos.Length; ++i)\n            {\n                var silo = compatibleSilos[i];\n                if (_siloStatistics.TryGetValue(silo, out var stats))\n                {\n                    if (!stats.IsOverloaded)\n                    {\n                        relevantSilos[relevantSilosCount++] = new(i, stats);\n                    }\n\n                    if (stats.MaxAvailableMemory > maxMaxAvailableMemory)\n                    {\n                        maxMaxAvailableMemory = stats.MaxAvailableMemory;\n                    }\n\n                    if (stats.ActivationCount > maxActivationCount)\n                    {\n                        maxActivationCount = stats.ActivationCount;\n                    }\n\n                    if (silo.Equals(_localSilo))\n                    {\n                        localSiloStatistics = stats;\n                    }\n                }\n            }\n\n            // Limit to the number of candidates added.\n            relevantSilos = relevantSilos[0..relevantSilosCount];\n            Debug.Assert(relevantSilos.Length == relevantSilosCount);\n\n            // Pick K silos from the list of compatible silos, where K is equal to the square root of the number of silos.\n            // Eg, from 10 silos, we choose from 4.\n            int candidateCount = (int)Math.Ceiling(Math.Sqrt(relevantSilosCount));\n            ShufflePrefix(relevantSilos, candidateCount);\n            var candidates = relevantSilos[0..candidateCount];\n\n            (int Index, float Score) pick = (0, 1f);\n\n            foreach (var (index, statistics) in candidates)\n            {\n                float score = CalculateScore(in statistics, maxMaxAvailableMemory, maxActivationCount);\n\n                // It's very unlikely, but there could be more than 1 silo that has the same score,\n                // so we apply some jittering to avoid pick the first one in the short-list.\n                float scoreJitter = Random.Shared.NextSingle() / 100_000f;\n\n                if (score + scoreJitter < pick.Score)\n                {\n                    pick = (index, score);\n                }\n            }\n\n            float? localSiloScore = null;\n            if (localSiloStatistics.HasValue && !localSiloStatistics.Value.IsOverloaded)\n            {\n                var localStats = localSiloStatistics.Value;\n                localSiloScore = CalculateScore(in localStats, maxMaxAvailableMemory, maxActivationCount);\n            }\n\n            return (pick.Index, pick.Score, localSiloScore);\n        }\n\n        // Variant of the Modern Fisher-Yates shuffle which stops after shuffling the first `prefixLength` elements,\n        // which are the only elements we are interested in.\n        // See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle\n        static void ShufflePrefix(Span<(int SiloIndex, ResourceStatistics SiloStatistics)> values, int prefixLength)\n        {\n            Debug.Assert(prefixLength >= 0 && prefixLength <= values.Length);\n\n            var max = values.Length;\n            for (var i = 0; i < prefixLength; i++)\n            {\n                var chosen = Random.Shared.Next(i, max);\n                if (chosen != i)\n                {\n                    (values[chosen], values[i]) = (values[i], values[chosen]);\n                }\n            }\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private float CalculateScore(ref readonly ResourceStatistics stats, float maxMaxAvailableMemory, int maxActivationCount)\n    {\n        float normalizedCpuUsage = stats.CpuUsage / 100f;\n        Debug.Assert(normalizedCpuUsage >= 0f && normalizedCpuUsage <= 1.01f, \"CPU usage should be normalized to [0, 1] range\");\n        float score = _weights.CpuUsageWeight * normalizedCpuUsage;\n\n        if (stats.MaxAvailableMemory > 0)\n        {\n            float normalizedMemoryUsage = stats.NormalizedMemoryUsage;\n            Debug.Assert(normalizedMemoryUsage >= 0f && normalizedMemoryUsage <= 1.01f, \"Memory usage should be normalized to [0, 1] range\");\n            float normalizedAvailableMemory = stats.NormalizedAvailableMemory;\n            Debug.Assert(normalizedAvailableMemory >= 0f && normalizedAvailableMemory <= 1.01f, \"Available memory should be normalized to [0, 1] range\");\n            float normalizedMaxAvailableMemory = stats.MaxAvailableMemory / maxMaxAvailableMemory;\n            Debug.Assert(normalizedMaxAvailableMemory >= 0f && normalizedMaxAvailableMemory <= 1.01f, \"Max available memory should be normalized to [0, 1] range\");\n\n            score += _weights.MemoryUsageWeight * normalizedMemoryUsage +\n                     _weights.AvailableMemoryWeight * (1 - normalizedAvailableMemory) +\n                     _weights.MaxAvailableMemoryWeight * (1 - normalizedMaxAvailableMemory);\n        }\n\n        var normalizedActivationCount = stats.ActivationCount / (float)maxActivationCount;\n        Debug.Assert(normalizedActivationCount >= 0f && normalizedActivationCount <= 1.01f, \"Activation count should be normalized to [0, 1] range\");\n        score += _weights.ActivationCountWeight * normalizedActivationCount;\n\n        Debug.Assert(score >= 0f && score <= 1.01f, \"Score should be normalized to [0, 1] range\");\n\n        return score;\n    }\n\n    public void RemoveSilo(SiloAddress address)\n         => _siloStatistics.TryRemove(address, out _);\n\n    public void SiloStatisticsChangeNotification(SiloAddress address, SiloRuntimeStatistics statistics)\n        => _siloStatistics.AddOrUpdate(\n            key: address,\n            factoryArgument: statistics,\n            addValueFactory: static (_, statistics) => ResourceStatistics.FromRuntime(statistics),\n            updateValueFactory: static (_, _, statistics) => ResourceStatistics.FromRuntime(statistics));\n\n    private record NormalizedWeights(float CpuUsageWeight, float MemoryUsageWeight, float AvailableMemoryWeight, float MaxAvailableMemoryWeight, float ActivationCountWeight);\n    private readonly record struct ResourceStatistics(bool IsOverloaded, float CpuUsage, float NormalizedMemoryUsage, float NormalizedAvailableMemory, float MaxAvailableMemory, int ActivationCount)\n    {\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ResourceStatistics FromRuntime(SiloRuntimeStatistics statistics)\n            => new(\n                IsOverloaded: statistics.IsOverloaded,\n                CpuUsage: statistics.EnvironmentStatistics.FilteredCpuUsagePercentage,\n                NormalizedMemoryUsage: statistics.EnvironmentStatistics.NormalizedFilteredMemoryUsage,\n                NormalizedAvailableMemory: statistics.EnvironmentStatistics.NormalizedFilteredAvailableMemory,\n                MaxAvailableMemory: statistics.EnvironmentStatistics.MaximumAvailableMemoryBytes,\n                ActivationCount: statistics.ActivationCount);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/SiloRoleBasedPlacementDirector.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime.MembershipService;\n\nnamespace Orleans.Runtime.Placement\n{\n    internal class SiloRoleBasedPlacementDirector : IPlacementDirector\n    {\n        private readonly MembershipTableManager membershipTableManager;\n\n        public SiloRoleBasedPlacementDirector(MembershipTableManager membershipTableManager)\n        {\n            this.membershipTableManager = membershipTableManager;\n        }\n\n        public virtual Task<SiloAddress> OnAddActivation(\n            PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            var siloRole = target.GrainIdentity.Key.ToString();\n\n            var compatibleSilos = membershipTableManager.MembershipTableSnapshot.Entries\n                .Where(s => s.Value.Status == SiloStatus.Active && s.Value.RoleName == siloRole)\n                .Select(s => s.Key)\n                .Intersect(context.GetCompatibleSilos(target))\n                .ToArray();\n\n            if (compatibleSilos == null || compatibleSilos.Length == 0)\n            {\n                throw new OrleansException($\"Cannot place grain with RoleName {siloRole}. Either Role name is invalid or there are no active silos with type {siloRole} in MembershipTableSnapshot registered yet.\");\n            }\n\n            // If a valid placement hint was specified, use it.\n            if (IPlacementDirector.GetPlacementHint(target.RequestContextData, compatibleSilos) is { } placementHint)\n            {\n                return Task.FromResult(placementHint);\n            }\n\n            return Task.FromResult(compatibleSilos[Random.Shared.Next(compatibleSilos.Length)]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Placement/StatelessWorkerDirector.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Placement\n{\n    internal class StatelessWorkerDirector : IPlacementDirector\n    {\n        public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            var compatibleSilos = context.GetCompatibleSilos(target);\n\n            // If the current silo is not shutting down, place locally if we are compatible\n            if (!context.LocalSiloStatus.IsTerminating())\n            {\n                foreach (var silo in compatibleSilos)\n                {\n                    if (silo.Equals(context.LocalSilo))\n                    {\n                        return Task.FromResult(context.LocalSilo);\n                    }\n                }\n            }\n\n            // otherwise, place somewhere else\n            return Task.FromResult(compatibleSilos[Random.Shared.Next(compatibleSilos.Length)]);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "src/Orleans.Runtime/README.md",
    "content": "# Microsoft Orleans Runtime\n\n## Introduction\nMicrosoft Orleans Runtime is the core server-side component of Orleans. It hosts and executes grains, manages grain lifecycles, and provides all the runtime services necessary for a functioning Orleans server (silo).\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Runtime\n```\n\nThis package is automatically included when you reference the Orleans Server metapackage.\n\n## Example - Configuring a Silo\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering();\n    });\n\nawait builder.Build().RunAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Server configuration](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/server-configuration)\n- [Silo lifecycle](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/silo-lifecycle)\n- [Clustering](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/ActivationTaskScheduler.cs",
    "content": "#nullable enable\n\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    /// <summary>\n    /// A single-concurrency, in-order task scheduler for per-activation work scheduling.\n    /// </summary>\n    [DebuggerDisplay(\"ActivationTaskScheduler RunQueue={workerGroup.ExternalWorkItemCount} GrainContext={workerGroup.GrainContext}\")]\n    internal sealed partial class ActivationTaskScheduler : TaskScheduler\n    {\n        private readonly ILogger logger;\n\n        private static long idCounter;\n        private readonly long myId;\n        private readonly WorkItemGroup workerGroup;\n#if EXTRA_STATS\n        private readonly CounterStatistic turnsExecutedStatistic;\n#endif\n\n        internal ActivationTaskScheduler(WorkItemGroup workGroup, ILogger<ActivationTaskScheduler> logger)\n        {\n            this.logger = logger;\n            myId = Interlocked.Increment(ref idCounter);\n            workerGroup = workGroup;\n#if EXTRA_STATS\n            turnsExecutedStatistic = CounterStatistic.FindOrCreate(name + \".TasksExecuted\");\n#endif\n            LogCreatedTaskScheduler(this, workerGroup.GrainContext);\n        }\n\n        /// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>\n        /// <returns>An enumerable of the tasks currently scheduled.</returns>\n        protected override IEnumerable<Task> GetScheduledTasks() => this.workerGroup.GetScheduledTasks();\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal void RunTaskFromWorkItemGroup(Task task)\n        {\n            bool done = TryExecuteTask(task);\n            if (!done)\n            {\n#if DEBUG\n                LogWarnTryExecuteTaskNotDone(task.Id, task.Status);\n#endif\n            }\n        }\n\n        /// <summary>Queues a task to the scheduler.</summary>\n        /// <param name=\"task\">The task to be queued.</param>\n        protected override void QueueTask(Task task)\n        {\n#if DEBUG\n            LogTraceQueueTask(myId, task.Id);\n#endif\n            workerGroup.EnqueueTask(task);\n        }\n\n        /// <summary>\n        /// Determines whether the provided <see cref=\"T:System.Threading.Tasks.Task\"/> can be executed synchronously in this call, and if it can, executes it.\n        /// </summary>\n        /// <returns>\n        /// A Boolean value indicating whether the task was executed inline.\n        /// </returns>\n        /// <param name=\"task\">The <see cref=\"T:System.Threading.Tasks.Task\"/> to be executed.</param>\n        /// <param name=\"taskWasPreviouslyQueued\">A Boolean denoting whether or not task has previously been queued. If this parameter is True, then the task may have been previously queued (scheduled); if False, then the task is known not to have been queued, and this call is being made in order to execute the task inline without queuing it.</param>\n        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)\n        {\n            var canExecuteInline = !taskWasPreviouslyQueued && Equals(RuntimeContext.Current, workerGroup.GrainContext);\n\n#if DEBUG\n            LogTraceTryExecuteTaskInline(\n                myId,\n                task.Id,\n                task.Status,\n                taskWasPreviouslyQueued,\n                canExecuteInline,\n                workerGroup.ExternalWorkItemCount);\n#endif\n            if (!canExecuteInline)\n            {\n#if DEBUG\n                LogTraceTryExecuteTaskInlineNotDone(myId, task.Id, task.Status);\n#endif\n                return false;\n            }\n\n#if EXTRA_STATS\n            turnsExecutedStatistic.Increment();\n#endif\n#if DEBUG\n            LogTraceTryExecuteTaskInlineYes(myId, task.Id, System.Environment.CurrentManagedThreadId);\n#endif\n            // Try to run the task.\n            bool done = TryExecuteTask(task);\n#if DEBUG\n            if (!done)\n            {\n                LogWarnTryExecuteTaskNotDone(task.Id, task.Status);\n            }\n\n            LogTraceTryExecuteTaskInlineCompleted(myId, task.Id, System.Environment.CurrentManagedThreadId, done);\n#endif\n            return done;\n        }\n\n        public override string ToString() => $\"{GetType().Name}-{myId}:Queued={workerGroup.ExternalWorkItemCount}\";\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Created {TaskScheduler} with GrainContext={GrainContext}\"\n        )]\n        private partial void LogCreatedTaskScheduler(ActivationTaskScheduler taskScheduler, IGrainContext grainContext);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.SchedulerTaskExecuteIncomplete4,\n            Message = \"RunTask: Incomplete base.TryExecuteTask for Task Id={TaskId} with Status={TaskStatus}\"\n        )]\n        private partial void LogWarnTryExecuteTaskNotDone(int taskId, TaskStatus taskStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TaskScheduler} QueueTask Task Id={TaskId}\"\n        )]\n        private partial void LogTraceQueueTask(long taskScheduler, int taskId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message =  \"{TaskScheduler} TryExecuteTaskInline Task Id={TaskId} Status={Status} PreviouslyQueued={PreviouslyQueued} CanExecute={CanExecute} Queued={Queued}\"\n        )]\n        private partial void LogTraceTryExecuteTaskInline(long taskScheduler, int taskId, TaskStatus status, bool previouslyQueued, bool canExecute, int queued);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TaskScheduler} Completed TryExecuteTaskInline Task Id={TaskId} Status={Status} Execute=No\"\n        )]\n        private partial void LogTraceTryExecuteTaskInlineNotDone(long taskScheduler, int taskId, TaskStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TaskScheduler} TryExecuteTaskInline Task Id={TaskId} Thread={Thread} Execute=Yes\"\n        )]\n        private partial void LogTraceTryExecuteTaskInlineYes(long taskScheduler, int taskId, int thread);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TaskScheduler} Completed TryExecuteTaskInline Task Id={TaskId} Thread={Thread} Execute=Done Ok={Ok}\"\n        )]\n        private partial void LogTraceTryExecuteTaskInlineCompleted(long taskScheduler, int taskId, int thread, bool ok);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/ClosureWorkItem.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    internal sealed class AsyncClosureWorkItem : WorkItemBase\n    {\n        private readonly TaskCompletionSource<bool> completion = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly Func<Task> continuation;\n        private readonly string? name;\n\n        public override string Name => this.name ?? GetMethodName(this.continuation);\n        public Task Task => this.completion.Task;\n\n        public AsyncClosureWorkItem(Func<Task> closure, string name, IGrainContext grainContext)\n        {\n            this.continuation = closure;\n            this.name = name;\n            this.GrainContext = grainContext;\n        }\n\n        public AsyncClosureWorkItem(Func<Task> closure, IGrainContext grainContext)\n        {\n            this.continuation = closure;\n            this.GrainContext = grainContext;\n        }\n\n        public override async void Execute()\n        {\n            try\n            {\n                RequestContext.Clear();\n                await this.continuation();\n                this.completion.TrySetResult(true);\n            }\n            catch (Exception exception)\n            {\n                this.completion.TrySetException(exception);\n            }\n        }\n\n        public override IGrainContext GrainContext { get; }\n\n        internal static string GetMethodName(Delegate action) => $\"{action.Target}->{action.Method}\";\n    }\n\n    internal sealed class AsyncClosureWorkItem<T> : WorkItemBase\n    {\n        private readonly TaskCompletionSource<T> completion = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly Func<Task<T>> continuation;\n        private readonly string? name;\n\n        public override string Name => this.name ?? AsyncClosureWorkItem.GetMethodName(this.continuation);\n        public Task<T> Task => this.completion.Task;\n\n        public AsyncClosureWorkItem(Func<Task<T>> closure, string name, IGrainContext grainContext)\n        {\n            this.continuation = closure;\n            this.name = name;\n            this.GrainContext = grainContext;\n        }\n\n        public AsyncClosureWorkItem(Func<Task<T>> closure, IGrainContext grainContext)\n        {\n            this.continuation = closure;\n            this.GrainContext = grainContext;\n        }\n\n        public override async void Execute()\n        {\n            try\n            {\n                RequestContext.Clear();\n                var result = await this.continuation();\n                this.completion.TrySetResult(result);\n            }\n            catch (Exception exception)\n            {\n                this.completion.TrySetException(exception);\n            }\n        }\n\n        public override IGrainContext GrainContext { get; }\n    }\n\n    internal sealed class ClosureWorkItem<TState>(Action<TState> closure, TState state, string? name, IGrainContext grainContext) : WorkItemBase\n    {\n        private readonly TaskCompletionSource<bool> _completion = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        public override string Name => name ?? AsyncClosureWorkItem.GetMethodName(closure);\n        public Task Task => _completion.Task;\n\n        public override void Execute()\n        {\n            try\n            {\n                RequestContext.Clear();\n                closure(state);\n                _completion.TrySetResult(true);\n            }\n            catch (Exception exception)\n            {\n                _completion.TrySetException(exception);\n            }\n        }\n\n        public override IGrainContext GrainContext { get; } = grainContext;\n    }\n\n    internal sealed class StatefulAsyncClosureWorkItem<TState> : WorkItemBase\n    {\n        private readonly TaskCompletionSource<bool> _completion = new(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly Func<TState, ValueTask> _continuation;\n        private readonly TState _state;\n        private readonly string? _name;\n\n        public override string Name => _name ?? AsyncClosureWorkItem.GetMethodName(_continuation);\n        public Task Task => _completion.Task;\n\n        public StatefulAsyncClosureWorkItem(Func<TState, ValueTask> closure, TState state, IGrainContext grainContext)\n        {\n            _continuation = closure;\n            _state = state;\n            GrainContext = grainContext;\n        }\n\n        public StatefulAsyncClosureWorkItem(Func<TState, ValueTask> closure, TState state, string name, IGrainContext grainContext)\n        {\n            _continuation = closure;\n            _state = state;\n            _name = name;\n            GrainContext = grainContext;\n        }\n\n        public override async void Execute()\n        {\n            try\n            {\n                RequestContext.Clear();\n                await _continuation(_state);\n                _completion.TrySetResult(true);\n            }\n            catch (Exception exception)\n            {\n                _completion.TrySetException(exception);\n            }\n        }\n\n        public override IGrainContext GrainContext { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/IWorkItem.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    internal interface IWorkItem\n    {\n        string Name { get; }\n        IGrainContext GrainContext { get; }\n        void Execute();\n\n        internal static readonly Action<object> ExecuteWorkItem = state => ((IWorkItem)state).Execute();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/SchedulerExtensions.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    internal static class SchedulerExtensions\n    {\n        internal static Task QueueTask(this IGrainContext targetContext, Func<Task> taskFunc)\n        {\n            var workItem = new AsyncClosureWorkItem(taskFunc, targetContext);\n            targetContext.Scheduler.QueueWorkItem(workItem);\n            return workItem.Task;\n        }\n\n        internal static Task QueueTask(this WorkItemGroup scheduler, Func<Task> taskFunc, IGrainContext targetContext)\n        {\n            var workItem = new AsyncClosureWorkItem(taskFunc, targetContext);\n            scheduler.QueueWorkItem(workItem);\n            return workItem.Task;\n        }\n\n        internal static Task QueueAction<TState>(this IGrainContext targetContext, Action<TState> action, TState state, string? name = null)\n        {\n            var workItem = new ClosureWorkItem<TState>(action, state, name, targetContext);\n            targetContext.Scheduler.QueueWorkItem(workItem);\n            return workItem.Task;\n        }\n\n        internal static Task RunOrQueueTask(this IGrainContext targetContext, Func<Task> taskFunc)\n        {\n            var currentContext = RuntimeContext.Current;\n            if (currentContext != null && currentContext.Equals(targetContext))\n            {\n                try\n                {\n                    return taskFunc();\n                }\n                catch (Exception exc)\n                {\n                    return Task.FromResult(exc);\n                }\n            }\n\n            var workItem = new AsyncClosureWorkItem(taskFunc, targetContext);\n            targetContext.Scheduler.QueueWorkItem(workItem);\n            return workItem.Task;\n        }\n\n        internal static ValueTask RunOrQueueTask<TState>(this IGrainContext targetContext, Func<TState, ValueTask> taskFunc, TState state)\n        {\n            var currentContext = RuntimeContext.Current;\n            if (currentContext != null && currentContext.Equals(targetContext))\n            {\n                try\n                {\n                    return taskFunc(state);\n                }\n                catch (Exception exc)\n                {\n                    return new(Task.FromException(exc));\n                }\n            }\n\n            var workItem = new StatefulAsyncClosureWorkItem<TState>(taskFunc, state, targetContext);\n            targetContext.Scheduler.QueueWorkItem(workItem);\n            return new(workItem.Task);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/TaskSchedulerUtils.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    internal static class TaskSchedulerUtils\n    {\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void QueueAction(this ActivationTaskScheduler taskScheduler, Action action)\n        {\n            using var suppressExecutionContext = new ExecutionContextSuppressor();\n\n            var task = new Task(action);\n            task.Start(taskScheduler);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void QueueAction(this ActivationTaskScheduler taskScheduler, Action<object> action, object state)\n        {\n            using var suppressExecutionContext = new ExecutionContextSuppressor();\n\n            var task = new Task(action, state);\n            task.Start(taskScheduler);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void QueueWorkItem(this WorkItemGroup scheduler, IWorkItem workItem)\n        {\n            QueueAction(scheduler.TaskScheduler, IWorkItem.ExecuteWorkItem, workItem);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void QueueWorkItem(this IWorkItemScheduler scheduler, IWorkItem workItem)\n        {\n            scheduler.QueueAction(IWorkItem.ExecuteWorkItem, workItem);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/WorkItemBase.cs",
    "content": "using System;\n\nnamespace Orleans.Runtime.Scheduler\n{\n    internal abstract class WorkItemBase : IWorkItem, ISpanFormattable\n    {\n        public abstract IGrainContext GrainContext { get; }\n\n        public abstract string Name { get; }\n\n        public abstract void Execute();\n\n        public sealed override string ToString() => $\"{this}\";\n\n        string IFormattable.ToString(string format, IFormatProvider formatProvider) => ToString();\n\n        public virtual bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)\n            => destination.TryWrite($\"[{GetType().Name} WorkItem Name={Name}, Ctx={GrainContext}{(GrainContext != null ? null : \"null\")}]\", out charsWritten);\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Scheduler/WorkItemGroup.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime.Scheduler;\n\n[DebuggerDisplay(\"WorkItemGroup Context={GrainContext} State={_state}\")]\ninternal sealed class WorkItemGroup : IThreadPoolWorkItem, IWorkItemScheduler\n{\n    private enum WorkGroupStatus : byte\n    {\n        Waiting = 0,\n        Runnable = 1,\n        Running = 2\n    }\n\n    private readonly ILogger _log;\n#if NET9_0_OR_GREATER\n    private readonly Lock _lockObj = new();\n#else\n    private readonly object _lockObj = new();\n#endif\n    private readonly Queue<Task> _workItems = new();\n    private readonly SchedulingOptions _schedulingOptions;\n\n    private long _totalItemsEnqueued;\n    private long _totalItemsProcessed;\n    private long _lastLongQueueWarningTimestamp;\n\n    private WorkGroupStatus _state;\n    private Task? _currentTask;\n    private long _currentTaskStarted;\n\n    internal ActivationTaskScheduler TaskScheduler { get; }\n\n    public IGrainContext GrainContext { get; set; }\n\n    internal int ExternalWorkItemCount\n    {\n        get { lock (_lockObj) { return _workItems.Count; } }\n    }\n\n    public WorkItemGroup(\n        IGrainContext grainContext,\n        ILogger<WorkItemGroup> logger,\n        ILogger<ActivationTaskScheduler> activationTaskSchedulerLogger,\n        IOptions<SchedulingOptions> schedulingOptions)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext);\n        GrainContext = grainContext;\n        _schedulingOptions = schedulingOptions.Value;\n        _state = WorkGroupStatus.Waiting;\n        _log = logger;\n        TaskScheduler = new ActivationTaskScheduler(this, activationTaskSchedulerLogger);\n    }\n\n    /// <summary>\n    /// Adds a task to this activation.\n    /// If we're adding it to the run list and we used to be waiting, now we're runnable.\n    /// </summary>\n    /// <param name=\"task\">The work item to add.</param>\n    public void EnqueueTask(Task task)\n    {\n#if DEBUG\n        if (_log.IsEnabled(LogLevel.Trace))\n        {\n            _log.LogTrace(\n                \"EnqueueWorkItem {Task} into {GrainContext} when TaskScheduler.Current={TaskScheduler}\",\n                task,\n                GrainContext,\n                System.Threading.Tasks.TaskScheduler.Current);\n        }\n#endif\n\n        lock (_lockObj)\n        {\n            long thisSequenceNumber = _totalItemsEnqueued++;\n            int count = _workItems.Count;\n\n            _workItems.Enqueue(task);\n            int maxPendingItemsLimit = _schedulingOptions.MaxPendingWorkItemsSoftLimit;\n            if (maxPendingItemsLimit > 0 && count > maxPendingItemsLimit)\n            {\n                var now = Environment.TickCount64;\n                if (now > _lastLongQueueWarningTimestamp + 10_000)\n                {\n                    LogTooManyTasksInQueue(count, maxPendingItemsLimit);\n                }\n\n                _lastLongQueueWarningTimestamp = now;\n            }\n\n            if (_state != WorkGroupStatus.Waiting)\n            {\n                return;\n            }\n\n            _state = WorkGroupStatus.Runnable;\n#if DEBUG\n            if (_log.IsEnabled(LogLevel.Trace))\n            {\n                _log.LogTrace(\n                    \"Add to RunQueue {Task}, #{SequenceNumber}, onto {GrainContext}\",\n                    task,\n                    thisSequenceNumber,\n                    GrainContext);\n            }\n#endif\n            ScheduleExecution(this);\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private void LogTooManyTasksInQueue(int count, int maxPendingItemsLimit)\n    {\n        _log.LogWarning(\n            (int)ErrorCode.SchedulerTooManyPendingItems,\n            \"{PendingWorkItemCount} pending work items for group {WorkGroupName}, exceeding the warning threshold of {WarningThreshold}\",\n            count,\n            GrainContext?.ToString() ?? \"Unknown\",\n            maxPendingItemsLimit);\n    }\n\n    /// <summary>\n    /// For debugger purposes only.\n    /// </summary>\n    internal IEnumerable<Task> GetScheduledTasks()\n    {\n        foreach (var task in _workItems)\n        {\n            yield return task;\n        }\n    }\n\n    // Execute one or more turns for this activation.\n    // This method is always called in a single-threaded environment -- that is, no more than one\n    // thread will be in this method at once -- but other async threads may still be queueing tasks, etc.\n    public void Execute()\n    {\n        RuntimeContext.SetExecutionContext(GrainContext, out var originalContext);\n        var turnWarningDurationMs = (long)Math.Ceiling(_schedulingOptions.TurnWarningLengthThreshold.TotalMilliseconds);\n        var activationSchedulingQuantumMs = (long)_schedulingOptions.ActivationSchedulingQuantum.TotalMilliseconds;\n        try\n        {\n\n            // Process multiple items -- drain the queue (up to max items) for this activation\n            long loopStart, taskStart, taskEnd;\n            loopStart = taskStart = taskEnd = Environment.TickCount64;\n            do\n            {\n                Task task;\n                lock (_lockObj)\n                {\n                    _state = WorkGroupStatus.Running;\n\n                    // Get the first Work Item on the list\n                    if (_workItems.Count > 0)\n                    {\n                        _currentTask = task = _workItems.Dequeue();\n                        _currentTaskStarted = taskStart;\n                    }\n                    else\n                    {\n                        // If the list is empty, then we're done\n                        break;\n                    }\n                }\n\n#if DEBUG\n                LogTaskStart(task);\n#endif\n                try\n                {\n                    TaskScheduler.RunTaskFromWorkItemGroup(task);\n                }\n                finally\n                {\n                    _totalItemsProcessed++;\n                    taskEnd = Environment.TickCount64;\n                    var taskDurationMs = taskEnd - taskStart;\n                    taskStart = taskEnd;\n                    if (taskDurationMs > turnWarningDurationMs)\n                    {\n                        SchedulerInstruments.LongRunningTurnsCounter.Add(1);\n                        LogLongRunningTurn(task, taskDurationMs);\n                    }\n\n                    _currentTask = null;\n                }\n            }\n            while (activationSchedulingQuantumMs <= 0 || taskEnd - loopStart < activationSchedulingQuantumMs);\n        }\n        catch (Exception ex)\n        {\n            LogTaskLoopError(ex);\n        }\n        finally\n        {\n            // Now we're not Running anymore.\n            // If we left work items on our run list, we're Runnable, and need to go back on the silo run queue;\n            // If our run list is empty, then we're waiting.\n            lock (_lockObj)\n            {\n                if (_workItems.Count > 0)\n                {\n                    _state = WorkGroupStatus.Runnable;\n                    ScheduleExecution(this);\n                }\n                else\n                {\n                    _state = WorkGroupStatus.Waiting;\n                }\n            }\n\n            RuntimeContext.ResetExecutionContext(originalContext);\n        }\n    }\n\n#if DEBUG\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private void LogTaskStart(Task task)\n    {\n        if (_log.IsEnabled(LogLevel.Trace))\n        {\n            _log.LogTrace(\n            \"About to execute task '{Task}' in GrainContext={GrainContext}\",\n            task,\n            GrainContext);\n        }\n    }\n#endif\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private void LogTaskLoopError(Exception ex)\n    {\n        _log.LogError(\n            (int)ErrorCode.Runtime_Error_100032,\n            ex,\n            \"Worker thread {Thread} caught an exception thrown from IWorkItem.Execute\",\n            Environment.CurrentManagedThreadId);\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private void LogLongRunningTurn(Task task, long taskDurationMs)\n    {\n        if (Debugger.IsAttached)\n        {\n            return;\n        }\n\n        var taskDuration = TimeSpan.FromMilliseconds(taskDurationMs);\n        _log.LogWarning(\n            (int)ErrorCode.SchedulerTurnTooLong3,\n            \"Task {Task} in WorkGroup {GrainContext} took elapsed time {Duration} for execution, which is longer than {TurnWarningLengthThreshold}. Running on thread {Thread}\",\n            task.AsyncState ?? task,\n            GrainContext.ToString(),\n            taskDuration.ToString(\"g\"),\n            _schedulingOptions.TurnWarningLengthThreshold,\n            Environment.CurrentManagedThreadId.ToString());\n    }\n\n    public override string ToString() => $\"{(GrainContext is SystemTarget ? \"System*\" : \"\")}WorkItemGroup:Name={GrainContext?.ToString() ?? \"Unknown\"},WorkGroupStatus={_state}\";\n\n    public string DumpStatus()\n    {\n        lock (_lockObj)\n        {\n            var sb = new StringBuilder();\n            sb.Append(this);\n            sb.AppendFormat(\". Currently QueuedWorkItems={0}; Total Enqueued={1}; Total processed={2}; \",\n                _workItems.Count, _totalItemsEnqueued, _totalItemsProcessed);\n            if (_currentTask is Task task)\n            {\n                sb.AppendFormat(\" Executing Task Id={0} Status={1} for {2}.\",\n                    task.Id, task.Status, TimeSpan.FromMilliseconds(Environment.TickCount64 - _currentTaskStarted));\n            }\n\n            sb.AppendFormat(\"TaskRunner={0}; \", TaskScheduler);\n            if (GrainContext != null)\n            {\n                var detailedStatus = GrainContext switch\n                {\n                    ActivationData activationData => activationData.ToDetailedString(includeExtraDetails: true),\n                    SystemTarget systemTarget => systemTarget.ToDetailedString(),\n                    object obj => obj.ToString(),\n                    _ => \"None\"\n                };\n                sb.AppendFormat(\"Detailed context=<{0}>\", detailedStatus);\n            }\n            return sb.ToString();\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void ScheduleExecution(WorkItemGroup workItem) => ThreadPool.UnsafeQueueUserWorkItem(workItem, preferLocal: true);\n\n    public void QueueAction(Action action) => TaskScheduler.QueueAction(action);\n    public void QueueAction(Action<object> action, object state) => TaskScheduler.QueueAction(action, state);\n    public void QueueTask(Task task) => task.Start(TaskScheduler);\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Services/GrainService.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Services;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>Base class for implementing a grain-like partitioned service with per silo instances of it automatically instantiated and started by silo runtime</summary>\n    public abstract partial class GrainService : SystemTarget, IRingRangeListener, IGrainService\n    {\n        private readonly IConsistentRingProvider ring;\n        private readonly string typeName;\n        private GrainServiceStatus status;\n\n        private readonly ILogger Logger;\n\n        /// <summary>Gets the token for signaling cancellation upon stopping of grain service</summary>\n        protected CancellationTokenSource StoppedCancellationTokenSource { get; }\n\n        /// <summary>Gets the monotonically increasing serial number of the version of the ring range owned by the grain service instance</summary>\n        protected int RangeSerialNumber { get; private set; }\n\n        /// <summary>Gets the range of the partitioning ring currently owned by the grain service instance</summary>\n        protected IRingRange RingRange { get; private set; }\n\n        /// <summary>Gets the status of the grain service instance</summary>\n        protected GrainServiceStatus Status\n        {\n            get { return status; }\n            set\n            {\n                OnStatusChange(status, value);\n                status = value;\n            }\n        }\n\n        /// <summary>Only to make Reflection happy. Do not use it in your implementation</summary>\n        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n        [Obsolete(\"Do not call the empty constructor.\")]\n        protected GrainService() : base()\n        {\n            throw new Exception(\"This should not be constructed by client code.\");\n        }\n\n        /// <summary>Constructor to use for grain services</summary>\n        internal GrainService(GrainId grainId, IConsistentRingProvider ringProvider, SystemTargetShared shared)\n            : base(SystemTargetGrainId.Create(grainId.Type, shared.SiloAddress), shared)\n        {\n            typeName = this.GetType().FullName;\n            Logger = shared.LoggerFactory.CreateLogger(typeName);\n\n            ring = ringProvider;\n            StoppedCancellationTokenSource = new CancellationTokenSource();\n        }\n\n        /// <summary>Constructor to use for grain services</summary>\n        protected GrainService(GrainId grainId, Silo silo, ILoggerFactory loggerFactory)\n            : this(grainId, silo.RingProvider, silo.Services.GetRequiredService<SystemTargetShared>())\n        {\n        }\n\n        /// <summary>\n        /// Invoked upon initialization of the service\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        public virtual Task Init(IServiceProvider serviceProvider)\n        {\n            return Task.CompletedTask;\n        }\n\n        private void OnStatusChange(GrainServiceStatus oldStatus, GrainServiceStatus newStatus)\n        {\n            if (oldStatus != GrainServiceStatus.Started && newStatus == GrainServiceStatus.Started)\n            {\n                ring.SubscribeToRangeChangeEvents(this);\n            }\n            if (oldStatus != GrainServiceStatus.Stopped && newStatus == GrainServiceStatus.Stopped)\n            {\n                ring.UnSubscribeFromRangeChangeEvents(this);\n            }\n        }\n\n        /// <summary>Invoked when service is being started</summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        public virtual Task Start()\n        {\n            RingRange = ring.GetMyRange();\n            LogInformationServiceStarting(Logger, this.typeName, Silo, new(Silo), RingRange);\n            StartInBackground().Ignore();\n\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Deferred part of initialization that executes after the service is already started (to speed up startup).\n        /// Sets Status to Started.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        protected virtual Task StartInBackground()\n        {\n            Status = GrainServiceStatus.Started;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>Invoked when service is being stopped</summary>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        public virtual Task Stop()\n        {\n            StoppedCancellationTokenSource.Cancel();\n\n            LogInformationServiceStopping(Logger, typeName);\n            Status = GrainServiceStatus.Stopped;\n\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc/>\n        void IRingRangeListener.RangeChangeNotification(IRingRange oldRange, IRingRange newRange, bool increased)\n        {\n            this.WorkItemGroup.QueueTask(() => OnRangeChange(oldRange, newRange, increased), this).Ignore();\n        }\n\n        /// <summary>\n        /// Invoked when the ring range owned by the service instance changes because of a change in the cluster state\n        /// </summary>\n        /// <param name=\"oldRange\">The old range.</param>\n        /// <param name=\"newRange\">The new range.</param>\n        /// <param name=\"increased\">A value indicating whether the range has increased.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the work performed.</returns>\n        public virtual Task OnRangeChange(IRingRange oldRange, IRingRange newRange, bool increased)\n        {\n            LogInformationRangeChanged(Logger, oldRange, newRange, increased);\n            RingRange = newRange;\n            RangeSerialNumber++;\n\n            return Task.CompletedTask;\n        }\n\n        private readonly struct SiloAddressHashCodeLogValue(SiloAddress silo)\n        {\n            public override string ToString() => silo.GetConsistentHashCode().ToString(\"X8\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.RS_ServiceStarting,\n            Message = \"Starting {TypeName} grain service on: {Silo} x{HashCode}, with range {RingRange}\"\n        )]\n        private static partial void LogInformationServiceStarting(ILogger logger, string typeName, SiloAddress silo, SiloAddressHashCodeLogValue hashCode, IRingRange ringRange);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.RS_ServiceStopping,\n            Message = \"Stopping {TypeName} grain service\"\n        )]\n        private static partial void LogInformationServiceStopping(ILogger logger, string typeName);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.RS_RangeChanged,\n            Message = \"My range changed from {OldRange} to {NewRange} increased = {Increased}\"\n        )]\n        private static partial void LogInformationRangeChanged(ILogger logger, IRingRange oldRange, IRingRange newRange, bool increased);\n\n        /// <summary>Possible statuses of a grain service</summary>\n        protected enum GrainServiceStatus\n        {\n            /// <summary>Initialization is in progress</summary>\n            Booting = 0,\n            /// <summary>Service successfully started</summary>\n            Started,\n            /// <summary>Service has been stopped</summary>\n            Stopped,\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Services/GrainServiceClient.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGeneration;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Services;\n\nnamespace Orleans.Runtime.Services\n{\n    /// <summary>\n    /// Proxies requests to the appropriate GrainService based on the appropriate Ring partitioning strategy.\n    /// </summary>\n    /// <typeparam name=\"TGrainService\"></typeparam>\n    public abstract class GrainServiceClient<TGrainService> : IGrainServiceClient<TGrainService> where TGrainService : IGrainService\n    {\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly IConsistentRingProvider ringProvider;\n        private readonly GrainType grainType;\n\n        /// <summary>\n        /// Currently we only support a single GrainService per Silo, when multiple are supported we will request the number of GrainServices to partition per silo here.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        protected GrainServiceClient(IServiceProvider serviceProvider)\n        {\n            grainFactory = serviceProvider.GetRequiredService<IInternalGrainFactory>();\n            ringProvider = serviceProvider.GetRequiredService<IConsistentRingProvider>();\n\n            // GrainInterfaceMap only holds IGrain types, not ISystemTarget types, so resolved via Orleans.CodeGeneration.\n            // Resolve this before merge.\n            var grainTypeCode = GrainInterfaceUtils.GetGrainClassTypeCode(typeof(TGrainService));\n            grainType = SystemTargetGrainId.CreateGrainServiceGrainType(grainTypeCode, null);\n        }\n\n        /// <summary>\n        /// Gets a reference to the the currently executing grain.\n        /// </summary>\n        protected GrainReference CurrentGrainReference => RuntimeContext.Current?.GrainReference;\n\n        /// <summary>\n        /// Get a reference to the <see cref=\"GrainService\"/> responsible for actioning the request based on the <paramref name=\"callingGrainId\"/>.\n        /// </summary>\n        protected TGrainService GetGrainService(GrainId callingGrainId)\n        {\n            return GetGrainService(callingGrainId.GetUniformHashCode());\n        }\n\n        /// <summary>\n        /// Get a reference to the <see cref=\"GrainService\"/> responsible for actioning the request based on the <paramref name=\"key\"/>.\n        /// </summary>\n        protected TGrainService GetGrainService(uint key)\n        {\n            return GetGrainService(ringProvider.GetPrimaryTargetSilo(key));\n        }\n\n        /// <summary>\n        /// Get a reference to the <see cref=\"GrainService\"/> responsible for actioning the request based on the <paramref name=\"destination\"/>.\n        /// </summary>\n        protected TGrainService GetGrainService(SiloAddress destination)\n        {\n            var grainId = SystemTargetGrainId.CreateGrainServiceGrainId(grainType, destination);\n            var grainService = grainFactory.GetSystemTarget<TGrainService>(grainId);\n\n            return grainService;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Services/GrainServiceFactory.cs",
    "content": "using Orleans.Services;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Functionality for interacting with grain services.\n    /// </summary>\n    public interface IGrainServiceFactory\n    {\n        /// <summary>\n        /// Casts a grain reference to a typed grain service reference.\n        /// Used by grain indexing.\n        /// </summary>\n        /// <typeparam name=\"T\">The grain service interface.</typeparam>\n        /// <param name=\"grainReference\">The grain reference.</param>\n        /// <returns>A reference to the specified grain service.</returns>\n        T CastToGrainServiceReference<T>(GrainReference grainReference) where T : IGrainService;\n    }\n\n    internal class GrainServiceFactory : IGrainServiceFactory\n    {\n        private readonly IRuntimeClient runtimeClient;\n\n        public GrainServiceFactory(IRuntimeClient runtimeClient)\n        {\n            this.runtimeClient = runtimeClient;\n        }\n\n        public T CastToGrainServiceReference<T>(GrainReference grainReference) where T : IGrainService\n            => this.runtimeClient.InternalGrainFactory.GetSystemTarget<T>(grainReference.GrainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Services/GrainServicesSiloBuilderExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGeneration;\nusing Orleans.Runtime;\nusing Orleans.Services;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for registering grain services.\n    /// </summary>\n    public static class GrainServicesSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Registers an application grain service to be started with the silo.\n        /// </summary>\n        /// <typeparam name=\"T\">The grain service implementation type.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddGrainService<T>(this ISiloBuilder builder)\n            where T : GrainService\n        {\n            return builder.ConfigureServices(services => services.AddGrainService<T>());\n        }\n\n        private static IGrainService GrainServiceFactory(Type serviceType, IServiceProvider services)\n        {\n            var grainServiceInterfaceType = Array.Find(serviceType.GetInterfaces(), x => x.GetInterfaces().Contains(typeof(IGrainService)));\n            if (grainServiceInterfaceType is null)\n            {\n                throw new InvalidOperationException(string.Format($\"Cannot find an interface on {serviceType.FullName} which implements IGrainService\"));\n            }\n\n            var typeCode = GrainInterfaceUtils.GetGrainClassTypeCode(grainServiceInterfaceType);\n            var grainId = SystemTargetGrainId.CreateGrainServiceGrainId(typeCode, null, SiloAddress.Zero);\n            var grainService = (IGrainService)ActivatorUtilities.CreateInstance(services, serviceType, grainId);\n            return grainService;\n        }\n\n        /// <summary>\n        /// Registers an application grain service to be started with the silo.\n        /// </summary>\n        /// <typeparam name=\"T\">The grain service implementation type.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddGrainService<T>(this IServiceCollection services)\n        {\n            return services.AddGrainService(typeof(T));\n        }\n\n        /// <summary>\n        /// Registers an application grain service to be started with the silo.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"grainServiceType\">The grain service implementation type.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddGrainService(this IServiceCollection services, Type grainServiceType)\n        {\n            return services.AddSingleton<IGrainService>(sp => GrainServiceFactory(grainServiceType, sp));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/LocalSiloDetails.cs",
    "content": "using System;\nusing System.Net;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime\n{\n    internal class LocalSiloDetails : ILocalSiloDetails\n    {\n        private readonly Lazy<SiloAddress> siloAddressLazy;\n        private readonly Lazy<SiloAddress> gatewayAddressLazy;\n\n        public LocalSiloDetails(\n            IOptions<SiloOptions> siloOptions,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<EndpointOptions> siloEndpointOptions)\n        {\n            this.Name = siloOptions.Value.SiloName;\n            this.ClusterId = clusterOptions.Value.ClusterId;\n            this.DnsHostName = Dns.GetHostName();\n\n            var endpointOptions = siloEndpointOptions.Value;\n            this.siloAddressLazy = new Lazy<SiloAddress>(() => SiloAddress.New(endpointOptions.AdvertisedIPAddress, endpointOptions.SiloPort, SiloAddress.AllocateNewGeneration()));\n            this.gatewayAddressLazy = new Lazy<SiloAddress>(() =>\n            {\n                var publicProxyEndpoint = endpointOptions.GetPublicProxyEndpoint();\n                return publicProxyEndpoint != null\n                        ? SiloAddress.New(publicProxyEndpoint, 0)\n                        : null;\n            });\n        }\n\n        /// <inheritdoc />\n        public string Name { get; }\n\n        /// <inheritdoc />\n        public string ClusterId { get; }\n\n        /// <inheritdoc />\n        public string DnsHostName { get; }\n\n        /// <inheritdoc />\n        public SiloAddress SiloAddress => this.siloAddressLazy.Value;\n\n        /// <inheritdoc />\n        public SiloAddress GatewayAddress => this.gatewayAddressLazy.Value;\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Silo/Silo.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Services;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing System.Net;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Orleans silo.\n    /// </summary>\n    public sealed partial class Silo : IAsyncDisposable, IDisposable\n    {\n        /// <summary>Standard name for Primary silo. </summary>\n        public const string PrimarySiloName = \"Primary\";\n        private readonly ILocalSiloDetails siloDetails;\n        private readonly MessageCenter messageCenter;\n        private readonly ILogger logger;\n        private readonly TaskCompletionSource<int> siloTerminatedTask = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);\n        private readonly InsideRuntimeClient runtimeClient;\n        private readonly Watchdog platformWatchdog;\n        private readonly TimeSpan waitForMessageToBeQueuedForOutbound;\n        private readonly TimeSpan initTimeout;\n#if NET9_0_OR_GREATER\n        private readonly Lock lockable = new();\n#else\n        private readonly object lockable = new();\n#endif\n        private readonly GrainFactory grainFactory;\n        private readonly ISiloLifecycleSubject siloLifecycle;\n        private readonly List<GrainService> grainServices = new List<GrainService>();\n        private readonly ILoggerFactory loggerFactory;\n\n        internal IConsistentRingProvider RingProvider { get; }\n\n        internal SystemStatus SystemStatus { get; set; }\n\n        internal IServiceProvider Services { get; }\n\n        /// <summary>Gets the address of this silo.</summary>\n        public SiloAddress SiloAddress => this.siloDetails.SiloAddress;\n\n        /// <summary>\n        /// Gets a <see cref=\"Task\"/> which completes once the silo has terminated.\n        /// </summary>\n        public Task SiloTerminated { get { return this.siloTerminatedTask.Task; } } // one event for all types of termination (shutdown, stop and fast kill).\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Silo\"/> class.\n        /// </summary>\n        /// <param name=\"siloDetails\">The silo initialization parameters</param>\n        /// <param name=\"services\">Dependency Injection container</param>\n        [Obsolete(\"This constructor is obsolete and may be removed in a future release. Use SiloHostBuilder to create an instance of ISiloHost instead.\")]\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Reliability\", \"CA2000:Dispose objects before losing scope\",\n            Justification = \"Should not Dispose of messageCenter in this method because it continues to run / exist after this point.\")]\n        public Silo(ILocalSiloDetails siloDetails, IServiceProvider services)\n        {\n            SystemStatus = SystemStatus.Creating;\n            Services = services;\n            RingProvider = services.GetRequiredService<IConsistentRingProvider>();\n            platformWatchdog = services.GetRequiredService<Watchdog>();\n            this.siloDetails = siloDetails;\n\n            IOptions<ClusterMembershipOptions> clusterMembershipOptions = services.GetRequiredService<IOptions<ClusterMembershipOptions>>();\n            initTimeout = clusterMembershipOptions.Value.MaxJoinAttemptTime;\n            if (Debugger.IsAttached)\n            {\n                initTimeout = StandardExtensions.Max(TimeSpan.FromMinutes(10), clusterMembershipOptions.Value.MaxJoinAttemptTime);\n            }\n\n            var localEndpoint = this.siloDetails.SiloAddress.Endpoint;\n\n            //set PropagateActivityId flag from node config\n            IOptions<SiloMessagingOptions> messagingOptions = services.GetRequiredService<IOptions<SiloMessagingOptions>>();\n            this.waitForMessageToBeQueuedForOutbound = messagingOptions.Value.WaitForMessageToBeQueuedForOutboundTime;\n\n            this.loggerFactory = this.Services.GetRequiredService<ILoggerFactory>();\n            logger = this.loggerFactory.CreateLogger<Silo>();\n\n            LogSiloStartingWithGC(logger, GCSettings.IsServerGC, GCSettings.LatencyMode);\n            if (!GCSettings.IsServerGC)\n            {\n                LogWarningSiloGcNotRunningWithServerGC(logger);\n                LogWarningSiloGcMultiCoreSystem(logger);\n            }\n\n            if (logger.IsEnabled(LogLevel.Debug))\n            {\n                var highestLogLevel = logger.IsEnabled(LogLevel.Trace) ? nameof(LogLevel.Trace) : nameof(LogLevel.Debug);\n                LogWarningSiloGcVerboseLOggingConfigured(logger, highestLogLevel);\n            }\n\n            LogInfoSiloInitializing(logger, siloDetails.DnsHostName, Environment.MachineName, localEndpoint, siloDetails.SiloAddress.Generation);\n            LogInfoSiloInitConfig(logger, siloDetails.Name);\n\n            try\n            {\n                grainFactory = Services.GetRequiredService<GrainFactory>();\n            }\n            catch (InvalidOperationException exc)\n            {\n                LogErrorSiloStartGrainFactoryNotRegistered(logger, exc);\n                throw;\n            }\n\n            runtimeClient = Services.GetRequiredService<InsideRuntimeClient>();\n\n            // Initialize the message center\n            messageCenter = Services.GetRequiredService<MessageCenter>();\n            messageCenter.SniffIncomingMessage = runtimeClient.SniffIncomingMessage;\n\n            this.SystemStatus = SystemStatus.Created;\n\n            this.siloLifecycle = this.Services.GetRequiredService<ISiloLifecycleSubject>();\n            // register all lifecycle participants\n            IEnumerable<ILifecycleParticipant<ISiloLifecycle>> lifecycleParticipants = this.Services.GetServices<ILifecycleParticipant<ISiloLifecycle>>();\n            foreach (ILifecycleParticipant<ISiloLifecycle> participant in lifecycleParticipants)\n            {\n                participant?.Participate(this.siloLifecycle);\n            }\n\n            // add self to lifecycle\n            this.Participate(this.siloLifecycle);\n\n            LogInfoSiloInitializingFinished(logger, SiloAddress, new(SiloAddress));\n        }\n\n        /// <summary>\n        /// Starts the silo.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token which can be used to cancel the operation.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                await Task.Run(() => this.siloLifecycle.OnStart(cancellationToken), cancellationToken);\n            }\n            catch (Exception exc)\n            {\n                LogErrorSiloStart(logger, exc);\n                throw;\n            }\n        }\n\n        private Task OnRuntimeInitializeStart(CancellationToken ct)\n        {\n            lock (lockable)\n            {\n                if (!this.SystemStatus.Equals(SystemStatus.Created))\n                    throw new InvalidOperationException(string.Format(\"Calling Silo.Start() on a silo which is not in the Created state. This silo is in the {0} state.\", this.SystemStatus));\n\n                this.SystemStatus = SystemStatus.Starting;\n            }\n\n            LogInfoSiloStarting(logger);\n            return Task.CompletedTask;\n        }\n\n        private void StartTaskWithPerfAnalysis(string taskName, Action task, Stopwatch stopWatch)\n        {\n            stopWatch.Restart();\n            task.Invoke();\n            stopWatch.Stop();\n\n            LogInfoSiloStartPerfMeasure(logger, taskName, stopWatch.ElapsedMilliseconds);\n        }\n\n        private async Task StartAsyncTaskWithPerfAnalysis(string taskName, Func<Task> task, Stopwatch stopWatch)\n        {\n            stopWatch.Restart();\n            await task.Invoke();\n            stopWatch.Stop();\n\n            LogInfoSiloStartPerfMeasure(logger, taskName, stopWatch.ElapsedMilliseconds);\n        }\n\n        private Task OnRuntimeServicesStart(CancellationToken ct)\n        {\n            return Task.CompletedTask;\n        }\n\n        private async Task OnRuntimeGrainServicesStart(CancellationToken ct)\n        {\n            var stopWatch = Stopwatch.StartNew();\n\n            // Load and init grain services before silo becomes active.\n            await StartAsyncTaskWithPerfAnalysis(\"Init grain services\",\n                () => CreateGrainServices(), stopWatch);\n\n            try\n            {\n                // Start background timer tick to watch for platform execution stalls, such as when GC kicks in\n                this.platformWatchdog.Start();\n            }\n            catch (Exception exc)\n            {\n                LogErrorStartingSiloGoingToFastKill(logger, exc, SiloAddress);\n                throw;\n            }\n\n            LogDebugSiloStartComplete(logger, this.SystemStatus);\n        }\n\n        private Task OnBecomeActiveStart(CancellationToken ct)\n        {\n            this.SystemStatus = SystemStatus.Running;\n            return Task.CompletedTask;\n        }\n\n        private async Task OnActiveStart(CancellationToken ct)\n        {\n            foreach (var grainService in grainServices)\n            {\n                await StartGrainService(grainService);\n            }\n        }\n\n        private async Task CreateGrainServices()\n        {\n            var grainServices = this.Services.GetServices<IGrainService>();\n            foreach (var grainService in grainServices)\n            {\n                await RegisterGrainService(grainService);\n            }\n        }\n\n        private async Task RegisterGrainService(IGrainService service)\n        {\n            var grainService = (GrainService)service;\n            var activationDirectory = this.Services.GetRequiredService<ActivationDirectory>();\n            activationDirectory.RecordNewTarget(grainService);\n            grainServices.Add(grainService);\n\n            try\n            {\n                await grainService.QueueTask(() => grainService.Init(Services)).WaitAsync(this.initTimeout);\n            }\n            catch (TimeoutException exception)\n            {\n                LogErrorGrainInitializationTimeout(logger, exception, initTimeout);\n                throw;\n            }\n\n            LogInfoGrainServiceRegistered(logger, service.GetType().FullName);\n        }\n\n        private async Task StartGrainService(IGrainService service)\n        {\n            var grainService = (GrainService)service;\n\n            try\n            {\n                await grainService.QueueTask(grainService.Start).WaitAsync(this.initTimeout);\n            }\n            catch (TimeoutException exception)\n            {\n                LogErrorGrainStartupTimeout(logger, exception, initTimeout);\n                throw;\n            }\n\n            LogInfoGrainServiceStarted(logger, service.GetType().FullName);\n        }\n\n        /// <summary>\n        /// Gracefully stop the run time system only, but not the application.\n        /// Applications requests would be abruptly terminated, while the internal system state gracefully stopped and saved as much as possible.\n        /// Grains are not deactivated.\n        /// </summary>\n        public void Stop()\n        {\n        }\n\n        /// <summary>\n        /// Gracefully stop the run time system only, but not the application.\n        /// Applications requests would be abruptly terminated, while the internal system state gracefully stopped and saved as much as possible.\n        /// </summary>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token which can be used to promptly terminate the silo.\n        /// </param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            bool gracefully = !cancellationToken.IsCancellationRequested;\n            bool stopAlreadyInProgress = false;\n            lock (lockable)\n            {\n                if (this.SystemStatus.Equals(SystemStatus.Stopping) ||\n                    this.SystemStatus.Equals(SystemStatus.ShuttingDown) ||\n                    this.SystemStatus.Equals(SystemStatus.Terminated))\n                {\n                    stopAlreadyInProgress = true;\n                    // Drop through to wait below\n                }\n                else if (!this.SystemStatus.Equals(SystemStatus.Running))\n                {\n                    throw new InvalidOperationException($\"Attempted to shutdown a silo which is not in the {nameof(SystemStatus.Running)} state. This silo is in the {this.SystemStatus} state.\");\n                }\n                else\n                {\n                    if (gracefully)\n                        this.SystemStatus = SystemStatus.ShuttingDown;\n                    else\n                        this.SystemStatus = SystemStatus.Stopping;\n                }\n            }\n\n            if (stopAlreadyInProgress)\n            {\n                LogDebugSiloStopInProgress(logger);\n                var pause = TimeSpan.FromSeconds(1);\n\n                while (!this.SystemStatus.Equals(SystemStatus.Terminated))\n                {\n                    LogDebugSiloStopStillInProgress(logger);\n                    await Task.Delay(pause).ConfigureAwait(false);\n                }\n\n                await this.SiloTerminated.ConfigureAwait(false);\n                return;\n            }\n\n            if (gracefully)\n            {\n                LogSiloShuttingDown(logger, LogLevel.Debug, \"graceful\");\n            }\n            else\n            {\n                LogSiloShuttingDown(logger, LogLevel.Debug, \"non-graceful\");\n            }\n\n            try\n            {\n                await Task.Run(() => this.siloLifecycle.OnStop(cancellationToken), CancellationToken.None).ConfigureAwait(false);\n            }\n            finally\n            {\n                // log final status\n                if (gracefully)\n                {\n                    LogSiloShutDown(logger, LogLevel.Debug, \"graceful\");\n                }\n                else\n                {\n                    LogSiloShutDown(logger, LogLevel.Warning, \"non-graceful\");\n                }\n\n                // signal to all awaiters that the silo has terminated.\n                await Task.Run(() => this.siloTerminatedTask.TrySetResult(0)).ConfigureAwait(false);\n            }\n        }\n\n        private Task OnRuntimeServicesStop(CancellationToken ct)\n        {\n            // Start rejecting all silo to silo application messages\n            messageCenter.BlockApplicationMessages();\n\n            return Task.CompletedTask;\n        }\n\n        private async Task OnRuntimeInitializeStop(CancellationToken ct)\n        {\n            try\n            {\n                await messageCenter.StopAsync();\n            }\n            catch (Exception exception)\n            {\n                LogErrorStoppingMessageCenter(logger, exception);\n            }\n\n            SystemStatus = SystemStatus.Terminated;\n        }\n\n        private async Task OnBecomeActiveStop(CancellationToken ct)\n        {\n            try\n            {\n                try\n                {\n                    var catalog = this.Services.GetRequiredService<Catalog>();\n                    await catalog.DeactivateAllActivations(ct);\n                }\n                catch (Exception exception)\n                {\n                    if (!ct.IsCancellationRequested)\n                    {\n                        LogErrorDeactivatingActivations(logger, exception);\n                    }\n                    else\n                    {\n                        LogWarningSomeGrainsFailedToDeactivate(logger);\n                    }\n                }\n\n                // Wait for all queued message sent to OutboundMessageQueue before MessageCenter stop and OutboundMessageQueue stop.\n                await Task.Delay(waitForMessageToBeQueuedForOutbound, ct).SuppressThrowing();\n            }\n            catch (Exception exc)\n            {\n                LogErrorSiloFailedToStopMembership(logger, exc);\n            }\n\n            // Stop the gateway\n            await messageCenter.StopAcceptingClientMessages();\n        }\n\n        private async Task OnActiveStop(CancellationToken ct)\n        {\n            if (ct.IsCancellationRequested)\n                return;\n\n            if (this.messageCenter.Gateway != null)\n            {\n                try\n                {\n                    await Task.Run(() => this.messageCenter.Gateway.SendStopSendMessages(this.grainFactory, ct), CancellationToken.None).WaitAsync(ct);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorSendingDisconnectRequests(logger, exception);\n                    if (!ct.IsCancellationRequested)\n                    {\n                        throw;\n                    }\n                }\n            }\n\n            foreach (var grainService in grainServices)\n            {\n                try\n                {\n                    await grainService\n                        .QueueTask(grainService.Stop)\n                        .WaitAsync(ct);\n                }\n                catch (Exception exception)\n                {\n                    LogErrorStoppingGrainService(logger, grainService, exception);\n                    if (!ct.IsCancellationRequested)\n                    {\n                        throw;\n                    }\n                }\n\n                LogDebugGrainServiceStopped(logger, grainService.GetType().FullName, grainService.GetGrainId());\n            }\n        }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"Silo: {SiloAddress}\";\n\n        private void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<Silo>(ServiceLifecycleStage.RuntimeInitialize, (ct) => Task.Run(() => OnRuntimeInitializeStart(ct)), (ct) => Task.Run(() => OnRuntimeInitializeStop(ct)));\n            lifecycle.Subscribe<Silo>(ServiceLifecycleStage.RuntimeServices, (ct) => Task.Run(() => OnRuntimeServicesStart(ct)), (ct) => Task.Run(() => OnRuntimeServicesStop(ct)));\n            lifecycle.Subscribe<Silo>(ServiceLifecycleStage.RuntimeGrainServices, (ct) => Task.Run(() => OnRuntimeGrainServicesStart(ct)));\n            lifecycle.Subscribe<Silo>(ServiceLifecycleStage.BecomeActive, (ct) => Task.Run(() => OnBecomeActiveStart(ct)), (ct) => Task.Run(() => OnBecomeActiveStop(ct)));\n            lifecycle.Subscribe<Silo>(ServiceLifecycleStage.Active, (ct) => Task.Run(() => OnActiveStart(ct)), (ct) => Task.Run(() => OnActiveStop(ct)));\n        }\n\n        public async ValueTask DisposeAsync()\n        {\n            using var cts = new CancellationTokenSource();\n            cts.Cancel();\n            await StopAsync(cts.Token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                using var cts = new CancellationTokenSource();\n                cts.Cancel();\n                StopAsync(cts.Token).Wait();\n            }\n            catch\n            {\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Silo starting with GC settings: ServerGC={ServerGC} GCLatencyMode={GCLatencyMode}\"\n        )]\n        private static partial void LogSiloStartingWithGC(ILogger logger, bool serverGC, GCLatencyMode gcLatencyMode);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.SiloGcWarning,\n            Message = \"Note: Silo not running with ServerGC turned on - recommend checking app config : <configuration>-<runtime>-<gcServer enabled=\\\"true\\\">\"\n        )]\n        private static partial void LogWarningSiloGcNotRunningWithServerGC(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.SiloGcWarning,\n            Message = \"Note: ServerGC only kicks in on multi-core systems (settings enabling ServerGC have no effect on single-core machines).\"\n        )]\n        private static partial void LogWarningSiloGcMultiCoreSystem(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.SiloGcWarning,\n            Message = $\"A verbose logging level ({{HighestLogLevel}}) is configured. This will impact performance. The recommended log level is {nameof(LogLevel.Information)}.\"\n        )]\n        private static partial void LogWarningSiloGcVerboseLOggingConfigured(ILogger logger, string highestLogLevel);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.SiloInitializing,\n            Message = \"-------------- Initializing silo on host {HostName} MachineName {MachineName} at {LocalEndpoint}, gen {Generation} --------------\"\n        )]\n        private static partial void LogInfoSiloInitializing(ILogger logger, string hostName, string machineName, IPEndPoint localEndpoint, int generation);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.SiloInitConfig,\n            Message = \"Starting silo {SiloName}\"\n        )]\n        private static partial void LogInfoSiloInitConfig(ILogger logger, string siloName);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.SiloStartError,\n            Message = \"Exception during Silo.Start, GrainFactory was not registered in Dependency Injection container\"\n        )]\n        private static partial void LogErrorSiloStartGrainFactoryNotRegistered(ILogger logger, Exception exc);\n\n        private readonly struct SiloAddressConsistentHashCodeLogValue(SiloAddress siloAddress)\n        {\n            public override string ToString() => siloAddress.GetConsistentHashCode().ToString(\"X\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.SiloInitializingFinished,\n            Message = \"-------------- Started silo {SiloAddress}, ConsistentHashCode {HashCode} --------------\"\n        )]\n        private static partial void LogInfoSiloInitializingFinished(ILogger logger, SiloAddress siloAddress, SiloAddressConsistentHashCodeLogValue hashCode);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.SiloStartError,\n            Message = \"Exception during Silo.Start\"\n        )]\n        private static partial void LogErrorSiloStart(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.SiloStarting,\n            Message = \"Silo Start()\"\n        )]\n        private static partial void LogInfoSiloStarting(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.SiloStartPerfMeasure,\n            Message = \"{TaskName} took {ElapsedMilliseconds} milliseconds to finish\"\n        )]\n        private static partial void LogInfoSiloStartPerfMeasure(ILogger logger, string taskName, long elapsedMilliseconds);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Runtime_Error_100330,\n            Message = \"Error starting silo {SiloAddress}. Going to FastKill().\"\n        )]\n        private static partial void LogErrorStartingSiloGoingToFastKill(ILogger logger, Exception exc, SiloAddress siloAddress);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo.Start complete: System status = {SystemStatus}\"\n        )]\n        private static partial void LogDebugSiloStartComplete(ILogger logger, SystemStatus systemStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"GrainService initialization timed out after '{Timeout}'.\"\n        )]\n        private static partial void LogErrorGrainInitializationTimeout(ILogger logger, Exception exception, TimeSpan timeout);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Grain Service {GrainServiceType} registered successfully.\"\n        )]\n        private static partial void LogInfoGrainServiceRegistered(ILogger logger, string grainServiceType);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"GrainService startup timed out after '{Timeout}'.\"\n        )]\n        private static partial void LogErrorGrainStartupTimeout(ILogger logger, Exception exception, TimeSpan timeout);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Grain Service {GrainServiceType} started successfully.\"\n        )]\n        private static partial void LogInfoGrainServiceStarted(ILogger logger, string grainServiceType);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.SiloStopInProgress,\n            Message = \"Silo shutdown in progress. Waiting for shutdown to be completed.\"\n        )]\n        private static partial void LogDebugSiloStopInProgress(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.SiloStopInProgress,\n            Message = \"Silo shutdown still in progress.\"\n        )]\n        private static partial void LogDebugSiloStopStillInProgress(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloShuttingDown,\n            Message = \"Silo shutdown initiated ({Gracefully}).\"\n        )]\n        private static partial void LogSiloShuttingDown(ILogger logger, LogLevel logLevel, string gracefully);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloShutDown,\n            Message = \"Silo shutdown completed ({Gracefully}).\"\n        )]\n        private static partial void LogSiloShutDown(ILogger logger, LogLevel logLevel, string gracefully);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error stopping message center.\"\n        )]\n        private static partial void LogErrorStoppingMessageCenter(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error deactivating activations.\"\n        )]\n        private static partial void LogErrorDeactivatingActivations(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Some grains failed to deactivate promptly.\"\n        )]\n        private static partial void LogWarningSomeGrainsFailedToDeactivate(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to stop gracefully. About to terminate ungracefully.\"\n        )]\n        private static partial void LogErrorSiloFailedToStopMembership(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error sending disconnect requests to connected clients.\"\n        )]\n        private static partial void LogErrorSendingDisconnectRequests(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Stopping GrainService '{GrainService}' failed.\"\n        )]\n        private static partial void LogErrorStoppingGrainService(ILogger logger, GrainService grainService, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{GrainServiceType} Grain Service with Id {GrainServiceId} stopped successfully.\"\n        )]\n        private static partial void LogDebugGrainServiceStopped(ILogger logger, string grainServiceType, GrainId grainServiceId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/SiloControl.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.Metadata;\nusing Orleans.Placement;\nusing Orleans.Providers;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Versions;\nusing Orleans.Runtime.Versions.Compatibility;\nusing Orleans.Runtime.Versions.Selector;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Statistics;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime\n{\n    internal sealed partial class SiloControl : SystemTarget, ISiloControl, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly ILogger logger;\n        private readonly ILocalSiloDetails localSiloDetails;\n\n        private readonly DeploymentLoadPublisher deploymentLoadPublisher;\n        private readonly CachedVersionSelectorManager cachedVersionSelectorManager;\n        private readonly CompatibilityDirectorManager compatibilityDirectorManager;\n        private readonly VersionSelectorManager selectorManager;\n        private readonly IServiceProvider services;\n        private readonly ActivationCollector _activationCollector;\n        private readonly ActivationDirectory activationDirectory;\n\n        private readonly IActivationWorkingSet activationWorkingSet;\n\n        private readonly IEnvironmentStatisticsProvider environmentStatisticsProvider;\n\n        private readonly IOptions<LoadSheddingOptions> loadSheddingOptions;\n        private readonly GrainCountStatistics _grainCountStatistics;\n        private readonly GrainPropertiesResolver grainPropertiesResolver;\n        private readonly GrainMigratabilityChecker _migratabilityChecker;\n\n        public SiloControl(\n            ILocalSiloDetails localSiloDetails,\n            DeploymentLoadPublisher deploymentLoadPublisher,\n            CachedVersionSelectorManager cachedVersionSelectorManager,\n            CompatibilityDirectorManager compatibilityDirectorManager,\n            VersionSelectorManager selectorManager,\n            IServiceProvider services,\n            ILoggerFactory loggerFactory,\n            IMessageCenter messageCenter,\n            ActivationCollector activationCollector,\n            ActivationDirectory activationDirectory,\n            IActivationWorkingSet activationWorkingSet,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            GrainCountStatistics grainCountStatistics,\n            GrainPropertiesResolver grainPropertiesResolver,\n            GrainMigratabilityChecker migratabilityChecker,\n            SystemTargetShared shared)\n            : base(Constants.SiloControlType, shared)\n        {\n            this.localSiloDetails = localSiloDetails;\n\n            this.logger = loggerFactory.CreateLogger<SiloControl>();\n            this.deploymentLoadPublisher = deploymentLoadPublisher;\n            this.cachedVersionSelectorManager = cachedVersionSelectorManager;\n            this.compatibilityDirectorManager = compatibilityDirectorManager;\n            this.selectorManager = selectorManager;\n            this.services = services;\n            _activationCollector = activationCollector;\n            this.activationDirectory = activationDirectory;\n            this.activationWorkingSet = activationWorkingSet;\n            this.environmentStatisticsProvider = environmentStatisticsProvider;\n            this.loadSheddingOptions = loadSheddingOptions;\n            _grainCountStatistics = grainCountStatistics;\n            this.grainPropertiesResolver = grainPropertiesResolver;\n            _migratabilityChecker = migratabilityChecker;\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public Task Ping(string message)\n        {\n            LogInformationPing();\n            return Task.CompletedTask;\n        }\n\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Microsoft.Reliability\", \"CA2001:AvoidCallingProblematicMethods\", MessageId = \"System.GC.Collect\")]\n        public Task ForceGarbageCollection()\n        {\n            LogInformationForceGarbageCollection();\n            GC.Collect();\n            return Task.CompletedTask;\n        }\n\n        public Task ForceActivationCollection(TimeSpan ageLimit)\n        {\n            LogInformationForceActivationCollection();\n            return _activationCollector.CollectActivations(ageLimit, CancellationToken.None);\n        }\n\n        public Task ForceRuntimeStatisticsCollection()\n        {\n            LogDebugForceRuntimeStatisticsCollection();\n            return this.deploymentLoadPublisher.RefreshClusterStatistics();\n        }\n\n        public Task<SiloRuntimeStatistics> GetRuntimeStatistics()\n        {\n            LogDebugGetRuntimeStatistics();\n            var activationCount = this.activationDirectory.Count;\n            var stats = new SiloRuntimeStatistics(\n                activationCount,\n                activationWorkingSet.Count,\n                this.environmentStatisticsProvider,\n                this.loadSheddingOptions,\n                DateTime.UtcNow);\n            return Task.FromResult(stats);\n        }\n\n        public Task<List<Tuple<GrainId, string, int>>> GetGrainStatistics()\n        {\n            LogInformationGetGrainStatistics();\n            var counts = new Dictionary<string, Dictionary<GrainId, int>>();\n            lock (activationDirectory)\n            {\n                foreach (var activation in activationDirectory)\n                {\n                    var data = activation.Value;\n                    if (data == null || data.GrainInstance == null) continue;\n\n                    // TODO: generic type expansion\n                    var grainTypeName = RuntimeTypeNameFormatter.Format(data.GrainInstance.GetType());\n\n                    Dictionary<GrainId, int>? grains;\n                    int n;\n                    if (!counts.TryGetValue(grainTypeName, out grains))\n                    {\n                        counts.Add(grainTypeName, new Dictionary<GrainId, int> { { data.GrainId, 1 } });\n                    }\n                    else if (!grains.TryGetValue(data.GrainId, out n))\n                        grains[data.GrainId] = 1;\n                    else\n                        grains[data.GrainId] = n + 1;\n                }\n            }\n\n            return Task.FromResult(counts\n                .SelectMany(p => p.Value.Select(p2 => Tuple.Create(p2.Key, p.Key, p2.Value)))\n                .ToList());\n        }\n\n        public Task<List<DetailedGrainStatistic>> GetDetailedGrainStatistics(string[]? types = null)\n        {\n            var stats = GetDetailedGrainStatisticsCore(types);\n            return Task.FromResult(stats);\n        }\n\n        public Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics()\n        {\n            return Task.FromResult(_grainCountStatistics.GetSimpleGrainStatistics().Select(p =>\n                new SimpleGrainStatistic { SiloAddress = this.localSiloDetails.SiloAddress, GrainType = p.Key, ActivationCount = (int)p.Value }).ToArray());\n        }\n\n        public async Task<DetailedGrainReport> GetDetailedGrainReport(GrainId grainId)\n        {\n            string? grainClassName;\n            try\n            {\n                var properties = this.grainPropertiesResolver.GetGrainProperties(grainId.Type);\n                properties.Properties.TryGetValue(WellKnownGrainTypeProperties.TypeName, out grainClassName);\n            }\n            catch (Exception exc)\n            {\n                grainClassName = exc.ToString();\n            }\n\n            var activation = activationDirectory.FindTarget(grainId) switch\n            {\n                ActivationData data => data.ToDetailedString(),\n                var a => a?.ToString()\n            };\n\n            var resolver = services.GetRequiredService<GrainDirectoryResolver>();\n            var defaultDirectory = services.GetService<IGrainDirectory>();\n            var dir = resolver.Resolve(grainId.Type) ?? defaultDirectory;\n            GrainAddress? localCacheActivationAddress = null;\n            GrainAddress? localDirectoryActivationAddress = null;\n            SiloAddress? primaryForGrain = null;\n            if (dir is DistributedGrainDirectory distributedGrainDirectory)\n            {\n                var grainLocator = services.GetRequiredService<GrainLocator>();\n                grainLocator.TryLookupInCache(grainId, out localCacheActivationAddress);\n                localDirectoryActivationAddress = await ((DistributedGrainDirectory.ITestHooks)distributedGrainDirectory).GetLocalRecord(grainId);\n                primaryForGrain = ((DistributedGrainDirectory.ITestHooks)distributedGrainDirectory).GetPrimaryForGrain(grainId);\n            }\n            else if (dir is null && services.GetService<ILocalGrainDirectory>() is { } localGrainDirectory)\n            {\n                localCacheActivationAddress = localGrainDirectory.GetLocalCacheData(grainId);\n                localDirectoryActivationAddress = localGrainDirectory.GetLocalDirectoryData(grainId).Address;\n                primaryForGrain = localGrainDirectory.GetPrimaryForGrain(grainId);\n            }\n\n            var report = new DetailedGrainReport()\n            {\n                Grain = grainId,\n                SiloAddress = localSiloDetails.SiloAddress,\n                SiloName = localSiloDetails.Name,\n                LocalCacheActivationAddress = localCacheActivationAddress,\n                LocalDirectoryActivationAddress = localDirectoryActivationAddress,\n                PrimaryForGrain = primaryForGrain,\n                GrainClassTypeName = grainClassName,\n                LocalActivation = activation,\n            };\n\n            return report;\n        }\n\n        public Task<int> GetActivationCount()\n        {\n            return Task.FromResult(this.activationDirectory.Count);\n        }\n\n        public Task<object> SendControlCommandToProvider<T>(string providerName, int command, object arg) where T : IControllable\n        {\n            var t = services\n                    .GetKeyedServices<IControllable>(providerName);\n            var controllable = services\n                    .GetKeyedServices<IControllable>(providerName)\n                    .FirstOrDefault(svc => svc.GetType() == typeof(T));\n\n            if (controllable == null)\n            {\n                LogErrorProviderNotFound(typeof(IControllable).FullName!, providerName);\n                throw new ArgumentException($\"Could not find a controllable service for type {typeof(IControllable).FullName} and name {providerName}.\");\n            }\n\n            return controllable.ExecuteCommand(command, arg);\n        }\n\n        public Task SetCompatibilityStrategy(CompatibilityStrategy strategy)\n        {\n            this.compatibilityDirectorManager.SetStrategy(strategy);\n            this.cachedVersionSelectorManager.ResetCache();\n            return Task.CompletedTask;\n        }\n\n        public Task SetSelectorStrategy(VersionSelectorStrategy strategy)\n        {\n            this.selectorManager.SetSelector(strategy);\n            this.cachedVersionSelectorManager.ResetCache();\n            return Task.CompletedTask;\n        }\n\n        public Task SetCompatibilityStrategy(GrainInterfaceType interfaceId, CompatibilityStrategy strategy)\n        {\n            this.compatibilityDirectorManager.SetStrategy(interfaceId, strategy);\n            this.cachedVersionSelectorManager.ResetCache();\n            return Task.CompletedTask;\n        }\n\n        public Task SetSelectorStrategy(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy)\n        {\n            this.selectorManager.SetSelector(interfaceType, strategy);\n            this.cachedVersionSelectorManager.ResetCache();\n            return Task.CompletedTask;\n        }\n\n        public Task<List<GrainId>> GetActiveGrains(GrainType grainType)\n        {\n            var results = new List<GrainId>();\n            foreach (var pair in activationDirectory)\n            {\n                if (grainType.Equals(pair.Key.Type))\n                {\n                    results.Add(pair.Key);\n                }\n            }\n            return Task.FromResult(results);\n        }\n\n        public Task MigrateRandomActivations(SiloAddress target, int count)\n        {\n            ArgumentNullException.ThrowIfNull(target);\n            ArgumentOutOfRangeException.ThrowIfNegative(count);\n            var migrationContext = new Dictionary<string, object>()\n            {\n                [IPlacementDirector.PlacementHintKey] = target\n            };\n\n            // Loop until we've migrated the desired count of activations or run out of activations to try.\n            // Note that we have a weak pseudorandom enumeration here, and lossy counting: this is not a precise\n            // or deterministic operation.\n            var remainingCount = count;\n            foreach (var (grainId, grainContext) in activationDirectory)\n            {\n                if (!_migratabilityChecker.IsMigratable(grainId.Type, ImmovableKind.Rebalancer))\n                {\n                    continue;\n                }\n\n                if (--remainingCount <= 0)\n                {\n                    break;\n                }\n\n                grainContext.Migrate(migrationContext);\n            }\n\n            return Task.CompletedTask;\n        }\n\n        private List<DetailedGrainStatistic> GetDetailedGrainStatisticsCore(string[]? types = null)\n        {\n            var stats = new List<DetailedGrainStatistic>();\n            lock (activationDirectory)\n            {\n                foreach (var activation in activationDirectory)\n                {\n                    var data = activation.Value;\n                    if (data == null || data.GrainInstance == null) continue;\n\n                    var grainType = RuntimeTypeNameFormatter.Format(data.GrainInstance.GetType());\n                    if (types == null || types.Contains(grainType))\n                    {\n                        stats.Add(new DetailedGrainStatistic()\n                        {\n                            GrainType = grainType,\n                            GrainId = data.GrainId,\n                            SiloAddress = Silo\n                        });\n                    }\n                }\n            }\n            return stats;\n        }\n\n        void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n        {\n            // Do nothing, just ensure that this instance is created so that it can register itself in the activation directory.\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Ping\"\n        )]\n        private partial void LogInformationPing();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"ForceGarbageCollection\"\n        )]\n        private partial void LogInformationForceGarbageCollection();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"ForceActivationCollection\"\n        )]\n        private partial void LogInformationForceActivationCollection();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"ForceRuntimeStatisticsCollection\"\n        )]\n        private partial void LogDebugForceRuntimeStatisticsCollection();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"GetRuntimeStatistics\"\n        )]\n        private partial void LogDebugGetRuntimeStatistics();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"GetGrainStatistics\"\n        )]\n        private partial void LogInformationGetGrainStatistics();\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Provider_ProviderNotFound,\n            Level = LogLevel.Error,\n            Message = \"Could not find a controllable service for type {ProviderTypeFullName} and name {ProviderName}.\"\n        )]\n        private partial void LogErrorProviderNotFound(string providerTypeFullName, string providerName);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/SiloOptions.cs",
    "content": "namespace Orleans.Configuration\n{\n    /// <summary>\n    /// Silo configuration options.\n    /// </summary>\n    public class SiloOptions\n    {\n        /// <summary>\n        /// Gets or sets the silo name.\n        /// </summary>\n        public string SiloName { get; set; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Silo/SiloProviderRuntime.cs",
    "content": "using System;\nusing Orleans.Providers;\n\nnamespace Orleans.Runtime.Providers\n{\n    internal class SiloProviderRuntime : IProviderRuntime\n    {\n        private readonly IGrainContextAccessor _grainContextAccessor;\n\n        public SiloProviderRuntime(\n            IGrainContextAccessor grainContextAccessor,\n            IGrainFactory grainFactory,\n            IServiceProvider serviceProvider)\n        {\n            _grainContextAccessor = grainContextAccessor;\n            GrainFactory = grainFactory;\n            ServiceProvider = serviceProvider;\n        }\n\n        public IGrainFactory GrainFactory { get; }\n\n        public IServiceProvider ServiceProvider { get; }\n\n        public (TExtension, TExtensionInterface) BindExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            return _grainContextAccessor.GrainContext.GetComponent<IGrainExtensionBinder>().GetOrSetExtension<TExtension, TExtensionInterface>(newExtensionFunc);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/TestHooks/ITestHooksSystemTarget.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime.TestHooks\n{\n    internal interface ITestHooks\n    {\n        Task<SiloAddress> GetConsistentRingPrimaryTargetSilo(uint key);\n        Task<string> GetConsistentRingProviderDiagnosticInfo();\n        Task<string> GetServiceId();\n        Task<bool> HasStorageProvider(string providerName);\n        Task<bool> HasStreamProvider(string providerName);\n        Task<int> UnregisterGrainForTesting(GrainId grain);\n        Task<Dictionary<SiloAddress, SiloStatus>> GetApproximateSiloStatuses();\n    }\n\n    internal interface ITestHooksSystemTarget : ITestHooks, ISystemTarget\n    {\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/TestHooks/TestHooksSystemTarget.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Storage;\nusing Orleans.Statistics;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.Runtime.TestHooks\n{\n    /// <summary>\n    /// A fake, test-only implementation of <see cref=\"IEnvironmentStatisticsProvider\"/>.\n    /// </summary>\n    internal class TestHooksEnvironmentStatisticsProvider : IEnvironmentStatisticsProvider\n    {\n        private static EnvironmentStatisticsProvider _realStatisticsProvider = new();\n\n        private EnvironmentStatistics? _currentStats = null;\n\n        public EnvironmentStatistics GetEnvironmentStatistics()\n        {\n            var stats = _currentStats ?? new();\n            if (!stats.IsValid())\n            {\n                stats = _realStatisticsProvider.GetEnvironmentStatistics();\n            }\n\n            return stats;\n        }\n\n        public void LatchHardwareStatistics(EnvironmentStatistics stats) => _currentStats = stats;\n        public void UnlatchHardwareStatistics() => _currentStats = null;\n    }\n\n    /// <summary>\n    /// Test hook functions for white box testing implemented as a SystemTarget\n    /// </summary>\n    internal sealed class TestHooksSystemTarget : SystemTarget, ITestHooksSystemTarget\n    {\n        private readonly IServiceProvider serviceProvider;\n        private readonly ISiloStatusOracle siloStatusOracle;\n\n        private readonly IConsistentRingProvider consistentRingProvider;\n\n        public TestHooksSystemTarget(\n            IServiceProvider serviceProvider,\n            ISiloStatusOracle siloStatusOracle,\n            SystemTargetShared shared)\n            : base(Constants.TestHooksSystemTargetType, shared)\n        {\n            this.serviceProvider = serviceProvider;\n            this.siloStatusOracle = siloStatusOracle;\n            this.consistentRingProvider = this.serviceProvider.GetRequiredService<IConsistentRingProvider>();\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public void Initialize()\n        {\n            // No-op\n        }\n\n        public Task<SiloAddress> GetConsistentRingPrimaryTargetSilo(uint key)\n        {\n            return Task.FromResult(consistentRingProvider.GetPrimaryTargetSilo(key));\n        }\n\n        public Task<string> GetConsistentRingProviderDiagnosticInfo()\n        {\n            return Task.FromResult(consistentRingProvider.ToString()); \n        }\n        \n        public Task<string> GetServiceId() => Task.FromResult(this.serviceProvider.GetRequiredService<IOptions<ClusterOptions>>().Value.ServiceId);\n\n        public Task<bool> HasStorageProvider(string providerName)\n        {\n            return Task.FromResult(this.serviceProvider.GetKeyedService<IGrainStorage>(providerName) != null);\n        }\n\n        public Task<bool> HasStreamProvider(string providerName)\n        {\n            return Task.FromResult(this.serviceProvider.GetKeyedService<IGrainStorage>(providerName) != null);\n        }\n\n        public Task<int> UnregisterGrainForTesting(GrainId grain) => Task.FromResult(this.serviceProvider.GetRequiredService<Catalog>().UnregisterGrainForTesting(grain));\n\n        public Task<Dictionary<SiloAddress, SiloStatus>> GetApproximateSiloStatuses() => Task.FromResult(this.siloStatusOracle.GetApproximateSiloStatuses());\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Silo/Watchdog.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Monitors runtime and component health periodically, reporting complaints.\n    /// </summary>\n    internal partial class Watchdog(IOptions<ClusterMembershipOptions> clusterMembershipOptions, IEnumerable<IHealthCheckParticipant> participants, ILogger<Watchdog> logger) : IDisposable\n    {\n        private static readonly TimeSpan PlatformWatchdogHeartbeatPeriod = TimeSpan.FromMilliseconds(1000);\n        private readonly CancellationTokenSource _cancellation = new();\n        private readonly TimeSpan _componentHealthCheckPeriod = clusterMembershipOptions.Value.LocalHealthDegradationMonitoringPeriod;\n        private readonly List<IHealthCheckParticipant> _participants = participants.ToList();\n        private readonly ILogger _logger = logger;\n        private ValueStopwatch _platformWatchdogStopwatch;\n        private ValueStopwatch _componentWatchdogStopwatch;\n\n        // GC pause duration since process start.\n        private TimeSpan _cumulativeGCPauseDuration;\n\n        private DateTime _lastComponentHealthCheckTime;\n        private Thread? _platformWatchdogThread;\n        private Thread? _componentWatchdogThread;\n\n        public void Start()\n        {\n            LogDebugStartingSiloWatchdog(_logger);\n\n            if (_platformWatchdogThread is not null)\n            {\n                throw new InvalidOperationException(\"Watchdog.Start may not be called more than once\");\n            }\n\n            var now = DateTime.UtcNow;\n            _platformWatchdogStopwatch = ValueStopwatch.StartNew();\n            _cumulativeGCPauseDuration = GC.GetTotalPauseDuration();\n\n            _platformWatchdogThread = new Thread(RunPlatformWatchdog)\n            {\n                IsBackground = true,\n                Name = \"Orleans.Runtime.Watchdog.Platform\",\n            };\n            _platformWatchdogThread.Start();\n\n            _componentWatchdogStopwatch = ValueStopwatch.StartNew();\n            _lastComponentHealthCheckTime = DateTime.UtcNow;\n\n            _componentWatchdogThread = new Thread(RunComponentWatchdog)\n            {\n                IsBackground = true,\n                Name = \"Orleans.Runtime.Watchdog.Component\",\n            };\n\n            _componentWatchdogThread.Start();\n\n            LogDebugSiloWatchdogStartedSuccessfully(_logger);\n        }\n\n        public void Stop()\n        {\n            Dispose();\n        }\n\n        protected void RunPlatformWatchdog()\n        {\n            while (!_cancellation.IsCancellationRequested)\n            {\n                try\n                {\n                    CheckRuntimeHealth();\n                }\n                catch (Exception exc)\n                {\n                    LogErrorPlatformWatchdogInternalError(_logger, exc);\n                }\n\n                _platformWatchdogStopwatch.Restart();\n                _cumulativeGCPauseDuration = GC.GetTotalPauseDuration();\n                _cancellation.Token.WaitHandle.WaitOne(PlatformWatchdogHeartbeatPeriod);\n            }\n        }\n\n        private void CheckRuntimeHealth()\n        {\n            if (Debugger.IsAttached)\n            {\n                return;\n            }\n\n            var pauseDurationSinceLastTick = GC.GetTotalPauseDuration() - _cumulativeGCPauseDuration;\n            var timeSinceLastTick = _platformWatchdogStopwatch.Elapsed;\n            if (timeSinceLastTick > PlatformWatchdogHeartbeatPeriod.Multiply(2))\n            {\n                var gc = new[] { GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2) };\n                LogWarningSiloHeartbeatTimerStalled(_logger, timeSinceLastTick, pauseDurationSinceLastTick, GC.GetTotalMemory(false) / (1024 * 1024), gc[0], gc[1], gc[2]);\n            }\n\n            var timeSinceLastParticipantCheck = _componentWatchdogStopwatch.Elapsed;\n            if (timeSinceLastParticipantCheck > _componentHealthCheckPeriod.Multiply(2))\n            {\n                LogWarningParticipantCheckThreadStalled(_logger, timeSinceLastParticipantCheck);\n            }\n        }\n\n        protected void RunComponentWatchdog()\n        {\n            while (!_cancellation.IsCancellationRequested)\n            {\n                try\n                {\n                    CheckComponentHealth();\n                }\n                catch (Exception exc)\n                {\n                    LogErrorComponentHealthCheckInternalError(_logger, exc);\n                }\n\n                _componentWatchdogStopwatch.Restart();\n                _cancellation.Token.WaitHandle.WaitOne(_componentHealthCheckPeriod);\n            }\n        }\n\n        private void CheckComponentHealth()\n        {\n            WatchdogInstruments.HealthChecks.Add(1);\n            var numFailedChecks = 0;\n            StringBuilder? complaints = null;\n\n            // Restart the timer before the check to reduce false positives for the stall checker.\n            _componentWatchdogStopwatch.Restart();\n            foreach (var participant in _participants)\n            {\n                try\n                {\n                    var ok = participant.CheckHealth(_lastComponentHealthCheckTime, out var complaint);\n                    if (!ok)\n                    {\n                        complaints ??= new StringBuilder();\n                        if (complaints.Length > 0)\n                        {\n                            complaints.Append(' ');\n                        }\n\n                        complaints.Append($\"{participant.GetType()} failed health check with complaint \\\"{complaint}\\\".\");\n                        ++numFailedChecks;\n                    }\n                }\n                catch (Exception exc)\n                {\n                    LogWarningHealthCheckParticipantException(_logger, exc, participant.GetType());\n                }\n            }\n\n            if (complaints != null)\n            {\n                WatchdogInstruments.FailedHealthChecks.Add(1);\n                LogWarningHealthCheckFailure(_logger, numFailedChecks, _participants.Count, complaints);\n            }\n\n            _lastComponentHealthCheckTime = DateTime.UtcNow;\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                _cancellation.Cancel();\n            }\n            catch\n            {\n                // Ignore.\n            }\n\n            try\n            {\n                _componentWatchdogThread?.Join();\n            }\n            catch\n            {\n                // Ignore.\n            }\n\n            try\n            {\n                _platformWatchdogThread?.Join();\n            }\n            catch\n            {\n                // Ignore.\n            }\n        }\n\n        private readonly struct ParticipantTypeLogValue(Type participantType)\n        {\n            public override string ToString() => participantType.ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Starting silo watchdog\"\n        )]\n        private static partial void LogDebugStartingSiloWatchdog(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Silo watchdog started successfully.\"\n        )]\n        private static partial void LogDebugSiloWatchdogStartedSuccessfully(ILogger logger);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Watchdog_InternalError,\n            Level = LogLevel.Error,\n            Message = \"Platform watchdog encountered an internal error\"\n        )]\n        private static partial void LogErrorPlatformWatchdogInternalError(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloHeartbeatTimerStalled,\n            Level = LogLevel.Warning,\n            Message = \".NET Runtime Platform stalled for {TimeSinceLastTick}. Total GC Pause duration during that period: {PauseDurationSinceLastTick}. We are now using a total of {TotalMemory}MB memory. Collection counts per generation: 0: {GCGen0Count}, 1: {GCGen1Count}, 2: {GCGen2Count}\"\n        )]\n        private static partial void LogWarningSiloHeartbeatTimerStalled(ILogger logger, TimeSpan timeSinceLastTick, TimeSpan pauseDurationSinceLastTick, long totalMemory, int gcGen0Count, int gcGen1Count, int gcGen2Count);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.SiloHeartbeatTimerStalled,\n            Level = LogLevel.Warning,\n            Message = \"Participant check thread has not completed for {TimeSinceLastTick}, potentially indicating lock contention or deadlock, CPU starvation, or another execution anomaly.\"\n        )]\n        private static partial void LogWarningParticipantCheckThreadStalled(ILogger logger, TimeSpan timeSinceLastTick);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Watchdog_InternalError,\n            Level = LogLevel.Error,\n            Message = \"Component health check encountered an internal error\"\n        )]\n        private static partial void LogErrorComponentHealthCheckInternalError(ILogger logger, Exception exc);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Watchdog_ParticipantThrownException,\n            Level = LogLevel.Warning,\n            Message = \"Health check participant {Participant} has thrown an exception from its CheckHealth method.\"\n        )]\n        private static partial void LogWarningHealthCheckParticipantException(ILogger logger, Exception exc, Type participant);\n\n        [LoggerMessage(\n            EventId = (int)ErrorCode.Watchdog_HealthCheckFailure,\n            Level = LogLevel.Warning,\n            Message = \"{FailedChecks} of {ParticipantCount} components reported issues. Complaints: {Complaints}\"\n        )]\n        private static partial void LogWarningHealthCheckFailure(ILogger logger, int failedChecks, int participantCount, StringBuilder complaints);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Storage/StateStorageBridge.cs",
    "content": "#nullable enable\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.ExceptionServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Diagnostics;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage;\n\nnamespace Orleans.Core\n{\n    /// <summary>\n    /// Provides functionality for operating on grain state.\n    /// Implements the <see cref=\"IStorage{TState}\" />\n    /// </summary>\n    /// <typeparam name=\"TState\">The underlying state type.</typeparam>\n    /// <seealso cref=\"IStorage{TState}\" />\n    public partial class StateStorageBridge<TState> : IStorage<TState>, IGrainMigrationParticipant\n    {\n        private readonly IGrainContext _grainContext;\n        private readonly StateStorageBridgeShared<TState> _shared;\n        private GrainState<TState>? _grainState;\n\n        /// <inheritdoc/>\n        public TState State\n        {\n            get\n            {\n                GrainRuntime.CheckRuntimeContext(RuntimeContext.Current);\n                if (_grainState is { } grainState)\n                {\n                    return grainState.State;\n                }\n\n                return default!;\n            }\n\n            set\n            {\n                GrainRuntime.CheckRuntimeContext(RuntimeContext.Current);\n                GrainState.State = value;\n            }\n        }\n\n        private GrainState<TState> GrainState => _grainState ??= new GrainState<TState>(_shared.Activator.Create());\n        internal bool IsStateInitialized { get; private set; }\n\n        internal string Name => _shared.Name;\n\n        /// <inheritdoc/>\n        public string? Etag { get => _grainState?.ETag; set => GrainState.ETag = value; }\n\n        /// <inheritdoc/>\n        public bool RecordExists => IsStateInitialized switch\n        {\n            true => GrainState.RecordExists,\n            _ => throw new InvalidOperationException(\"State has not yet been loaded\")\n        };\n\n        [Obsolete(\"Use StateStorageBridge(string, IGrainContext, IGrainStorage) instead.\")]\n        public StateStorageBridge(string name, IGrainContext grainContext, IGrainStorage store, ILoggerFactory loggerFactory, IActivatorProvider activatorProvider) : this(name, grainContext, store)\n        { }\n\n        public StateStorageBridge(string name, IGrainContext grainContext, IGrainStorage store)\n        {\n            ArgumentNullException.ThrowIfNull(name);\n            ArgumentNullException.ThrowIfNull(grainContext);\n            ArgumentNullException.ThrowIfNull(store);\n\n            _grainContext = grainContext;\n            var sharedInstances = ActivatorUtilities.GetServiceOrCreateInstance<StateStorageBridgeSharedMap>(grainContext.ActivationServices);\n            _shared = sharedInstances.Get<TState>(name, store);\n        }\n\n        /// <inheritdoc />\n        public async Task ReadStateAsync()\n        {\n            try\n            {\n                GrainRuntime.CheckRuntimeContext(RuntimeContext.Current);\n\n                // Try to get the parent activity context from the current activity or from the activation's stored activity\n                var parentContext = Activity.Current?.Context;\n                if (parentContext is null && _grainContext is ActivationData activationData)\n                {\n                    // If we're in activation context and there's an activation activity, use it as parent\n                    parentContext = activationData.GetActivationActivityContext();\n                }\n\n                using var activity = parentContext.HasValue\n                    ? ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageRead, ActivityKind.Client, parentContext.Value)\n                    : ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageRead, ActivityKind.Client);\n                activity?.SetTag(ActivityTagKeys.GrainId, _grainContext.GrainId.ToString());\n                activity?.SetTag(ActivityTagKeys.StorageProvider, _shared.ProviderTypeName);\n                activity?.SetTag(ActivityTagKeys.StorageStateName, _shared.Name);\n                activity?.SetTag(ActivityTagKeys.StorageStateType, _shared.StateTypeName);\n\n                var sw = ValueStopwatch.StartNew();\n                await _shared.Store.ReadStateAsync(_shared.Name, _grainContext.GrainId, GrainState);\n                IsStateInitialized = true;\n                StorageInstruments.OnStorageRead(sw.Elapsed, _shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n            }\n            catch (Exception exc)\n            {\n                StorageInstruments.OnStorageReadError(_shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n                OnError(exc, ErrorCode.StorageProvider_ReadFailed, nameof(ReadStateAsync));\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task WriteStateAsync()\n        {\n            try\n            {\n                GrainRuntime.CheckRuntimeContext(RuntimeContext.Current);\n\n                // Try to get the parent activity context from the current activity or from the activation's stored activity\n                var parentContext = Activity.Current?.Context;\n                if (parentContext is null && _grainContext is ActivationData activationData)\n                {\n                    parentContext = activationData.GetActivationActivityContext();\n                }\n\n                using var activity = parentContext.HasValue\n                    ? ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageWrite, ActivityKind.Client, parentContext.Value)\n                    : ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageWrite, ActivityKind.Client);\n                activity?.SetTag(ActivityTagKeys.GrainId, _grainContext.GrainId.ToString());\n                activity?.SetTag(ActivityTagKeys.StorageProvider, _shared.ProviderTypeName);\n                activity?.SetTag(ActivityTagKeys.StorageStateName, _shared.Name);\n                activity?.SetTag(ActivityTagKeys.StorageStateType, _shared.StateTypeName);\n\n                var sw = ValueStopwatch.StartNew();\n                await _shared.Store.WriteStateAsync(_shared.Name, _grainContext.GrainId, GrainState);\n                StorageInstruments.OnStorageWrite(sw.Elapsed, _shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n            }\n            catch (Exception exc)\n            {\n                StorageInstruments.OnStorageWriteError(_shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n                OnError(exc, ErrorCode.StorageProvider_WriteFailed, nameof(WriteStateAsync));\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task ClearStateAsync()\n        {\n            try\n            {\n                GrainRuntime.CheckRuntimeContext(RuntimeContext.Current);\n\n                // Try to get the parent activity context from the current activity or from the activation's stored activity\n                var parentContext = Activity.Current?.Context;\n                if (parentContext is null && _grainContext is ActivationData activationData)\n                {\n                    parentContext = activationData.GetActivationActivityContext();\n                }\n\n                using var activity = parentContext.HasValue\n                    ? ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageClear, ActivityKind.Client, parentContext.Value)\n                    : ActivitySources.StorageGrainSource.StartActivity(ActivityNames.StorageClear, ActivityKind.Client);\n                activity?.SetTag(ActivityTagKeys.GrainId, _grainContext.GrainId.ToString());\n                activity?.SetTag(ActivityTagKeys.StorageProvider, _shared.ProviderTypeName);\n                activity?.SetTag(ActivityTagKeys.StorageStateName, _shared.Name);\n                activity?.SetTag(ActivityTagKeys.StorageStateType, _shared.StateTypeName);\n\n                var sw = ValueStopwatch.StartNew();\n\n                // Clear state in external storage\n                await _shared.Store.ClearStateAsync(_shared.Name, _grainContext.GrainId, GrainState);\n                sw.Stop();\n\n                // Update counters\n                StorageInstruments.OnStorageDelete(sw.Elapsed, _shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n            }\n            catch (Exception exc)\n            {\n                StorageInstruments.OnStorageDeleteError(_shared.ProviderTypeName, _shared.Name, _shared.StateTypeName);\n                OnError(exc, ErrorCode.StorageProvider_DeleteFailed, nameof(ClearStateAsync));\n            }\n        }\n\n        /// <inheritdoc />\n        public void OnDehydrate(IDehydrationContext dehydrationContext)\n        {\n            try\n            {\n                dehydrationContext.TryAddValue(_shared.MigrationContextKey, _grainState);\n            }\n            catch (Exception exception)\n            {\n                LogErrorOnDehydrate(_shared.Logger, exception, _shared.Name, _grainContext.GrainId);\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public void OnRehydrate(IRehydrationContext rehydrationContext)\n        {\n            try\n            {\n                if (rehydrationContext.TryGetValue<GrainState<TState>>(_shared.MigrationContextKey, out var grainState))\n                {\n                    _grainState = grainState;\n                    IsStateInitialized = true;\n                }\n            }\n            catch (Exception exception)\n            {\n                LogErrorOnRehydrate(_shared.Logger, exception, _shared.Name, _grainContext.GrainId);\n            }\n        }\n\n        [DoesNotReturn]\n        private void OnError(Exception exception, ErrorCode id, string operation)\n        {\n            string? errorCode = null;\n            (_shared.Store as IRestExceptionDecoder)?.DecodeException(exception, out _, out errorCode, true);\n            var errorString = errorCode is { Length: > 0 } ? $\" Error: {errorCode}\" : null;\n\n            var grainId = _grainContext.GrainId;\n            // TODO: pending on https://github.com/dotnet/runtime/issues/110570\n            _shared.Logger.LogError((int)id, exception, \"Error from storage provider {ProviderName}.{StateName} during {Operation} for grain {GrainId}{ErrorCode}\", _shared.ProviderTypeName, _shared.Name, operation, grainId, errorString);\n\n            // If error is not specialization of OrleansException, wrap it\n            if (exception is not OrleansException)\n            {\n                var errMsg = $\"Error from storage provider {_shared.ProviderTypeName}.{_shared.Name} during {operation} for grain {grainId}{errorString}{Environment.NewLine} {LogFormatter.PrintException(exception)}\";\n                throw new OrleansException(errMsg, exception);\n            }\n\n            ExceptionDispatchInfo.Throw(exception);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to dehydrate state named {StateName} for grain {GrainId}\"\n        )]\n        private static partial void LogErrorOnDehydrate(ILogger logger, Exception exception, string stateName, GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to rehydrate state named {StateName} for grain {GrainId}\"\n        )]\n        private static partial void LogErrorOnRehydrate(ILogger logger, Exception exception, string stateName, GrainId grainId);\n    }\n\n    internal sealed class StateStorageBridgeSharedMap(ILoggerFactory loggerFactory, IActivatorProvider activatorProvider)\n    {\n        private readonly ConcurrentDictionary<(string Name, IGrainStorage Store, Type StateType), object> _instances = new();\n        private readonly ILoggerFactory _loggerFactory = loggerFactory;\n        private readonly IActivatorProvider _activatorProvider = activatorProvider;\n\n        public StateStorageBridgeShared<TState> Get<TState>(string name, IGrainStorage store)\n            => (StateStorageBridgeShared<TState>)_instances.GetOrAdd(\n                (name, store, typeof(TState)),\n                static (key, self) => new StateStorageBridgeShared<TState>(\n                    key.Name,\n                    key.Store,\n                    self._loggerFactory.CreateLogger(key.Store.GetType()),\n                    self._activatorProvider.GetActivator<TState>()),\n                this);\n    }\n\n    internal sealed class StateStorageBridgeShared<TState>(string name, IGrainStorage store, ILogger logger, IActivator<TState> activator)\n    {\n        private string? _migrationContextKey;\n\n        public readonly string Name = name;\n        public readonly string ProviderTypeName = store.GetType().Name;\n        public readonly string StateTypeName = typeof(TState).Name;\n        public readonly IGrainStorage Store = store;\n        public readonly ILogger Logger = logger;\n        public readonly IActivator<TState> Activator = activator;\n        public string MigrationContextKey => _migrationContextKey ??= $\"state.{Name}\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/AsyncTimer.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal partial class AsyncTimer : IAsyncTimer\n    {\n        /// <summary>\n        /// Timers can fire up to 3 seconds late before a warning is emitted and the instance is deemed unhealthy.\n        /// </summary>\n        private static readonly TimeSpan TimerDelaySlack = TimeSpan.FromSeconds(3);\n\n        private readonly CancellationTokenSource cancellation = new CancellationTokenSource();\n        private readonly TimeSpan period;\n        private readonly string name;\n        private readonly ILogger log;\n        private DateTime lastFired = DateTime.MinValue;\n        private DateTime expected;\n\n        public AsyncTimer(TimeSpan period, string name, ILogger log)\n        {\n            this.log = log;\n            this.period = period;\n            this.name = name;\n        }\n\n        /// <summary>\n        /// Returns a task which completes after the required delay.\n        /// </summary>\n        /// <param name=\"overrideDelay\">An optional override to this timer's configured period.</param>\n        /// <returns><see langword=\"true\"/> if the timer completed or <see langword=\"false\"/> if the timer was cancelled</returns>\n        public async Task<bool> NextTick(TimeSpan? overrideDelay = default)\n        {\n            if (cancellation.IsCancellationRequested) return false;\n\n            var start = DateTime.UtcNow;\n            var delay = overrideDelay switch\n            {\n                { } value => value,\n                _ when lastFired == DateTime.MinValue => period,\n                _ => lastFired.Add(period).Subtract(start)\n            };\n\n            if (delay < TimeSpan.Zero) delay = TimeSpan.Zero;\n\n            var dueTime = start.Add(delay);\n            this.expected = dueTime;\n            if (delay > TimeSpan.Zero)\n            {\n                // for backwards compatibility, support timers with periods up to ReminderRegistry.MaxSupportedTimeout\n                var maxDelay = TimeSpan.FromMilliseconds(int.MaxValue);\n                while (delay > maxDelay)\n                {\n                    delay -= maxDelay;\n                    var task2 = await Task.WhenAny(Task.Delay(maxDelay, cancellation.Token)).ConfigureAwait(false);\n                    if (task2.IsCanceled)\n                    {\n                        await Task.Yield();\n                        expected = default;\n                        return false;\n                    }\n                }\n\n                var task = await Task.WhenAny(Task.Delay(delay, cancellation.Token)).ConfigureAwait(false);\n                if (task.IsCanceled)\n                {\n                    await Task.Yield();\n                    expected = default;\n                    return false;\n                }\n            }\n\n            var now = this.lastFired = DateTime.UtcNow;\n            var overshoot = GetOvershootDelay(now, dueTime);\n            if (overshoot > TimeSpan.Zero)\n            {\n                if (!Debugger.IsAttached)\n                {\n                    LogTimerOvershoot(this.log, dueTime, now, overshoot);\n                }\n            }\n\n            expected = default;\n            return true;\n        }\n\n        private static TimeSpan GetOvershootDelay(DateTime now, DateTime dueTime)\n        {\n            if (dueTime == default) return TimeSpan.Zero;\n            if (dueTime > now) return TimeSpan.Zero;\n\n            var overshoot = now.Subtract(dueTime);\n            if (overshoot > TimerDelaySlack) return overshoot;\n\n            return TimeSpan.Zero;\n        }\n\n        public bool CheckHealth(DateTime lastCheckTime, out string reason)\n        {\n            var now = DateTime.UtcNow;\n            var due = this.expected;\n            var overshoot = GetOvershootDelay(now, due);\n            if (overshoot > TimeSpan.Zero && !Debugger.IsAttached)\n            {\n                reason = $\"{this.name} timer should have fired at {due}, which is {overshoot} ago\";\n                return false;\n            }\n\n            reason = default;\n            return true;\n        }\n\n        public void Dispose()\n        {\n            this.expected = default;\n            this.cancellation.Cancel();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Timer should have fired at {DueTime} but fired at {CurrentTime}, which is {Overshoot} longer than expected\"\n        )]\n        private static partial void LogTimerOvershoot(ILogger logger, DateTime dueTime, DateTime currentTime, TimeSpan overshoot);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/AsyncTimerFactory.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Runtime\n{\n    internal class AsyncTimerFactory : IAsyncTimerFactory\n    {\n        private readonly ILoggerFactory loggerFactory;\n        public AsyncTimerFactory(ILoggerFactory loggerFactory)\n        {\n            this.loggerFactory = loggerFactory;\n        }\n\n        public IAsyncTimer Create(TimeSpan period, string name)\n        {\n            var log = this.loggerFactory.CreateLogger($\"{typeof(AsyncTimer).FullName}.{name}\");\n            return new AsyncTimer(period, name, log);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/GrainTimer.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.CodeGeneration;\nusing Orleans.Runtime.Internal;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Timers;\n\nnamespace Orleans.Runtime;\n\ninternal abstract partial class GrainTimer : IGrainTimer\n{\n    protected static readonly GrainInterfaceType InvokableInterfaceType = GrainInterfaceType.Create(\"Orleans.Runtime.IGrainTimerInvoker\");\n    protected static readonly TimerCallback TimerCallback = (state) => ((GrainTimer)state!).ScheduleTickOnActivation();\n    protected static readonly MethodInfo InvokableMethodInfo = typeof(IGrainTimerInvoker).GetMethod(nameof(IGrainTimerInvoker.InvokeCallbackAsync), BindingFlags.Instance | BindingFlags.Public)!;\n    private readonly CancellationTokenSource _cts = new();\n    private readonly ITimer _timer;\n    private readonly IGrainContext _grainContext;\n    private readonly TimerRegistry _shared;\n    private readonly bool _interleave;\n    private readonly bool _keepAlive;\n    private readonly TimerTickInvoker _invoker;\n    private bool _changed;\n    private bool _firing;\n    private TimeSpan _dueTime;\n    private TimeSpan _period;\n\n    public GrainTimer(TimerRegistry shared, IGrainContext grainContext, bool interleave, bool keepAlive)\n    {\n        ArgumentNullException.ThrowIfNull(shared);\n        ArgumentNullException.ThrowIfNull(grainContext);\n\n        _interleave = interleave;\n        _keepAlive = keepAlive;\n        _shared = shared;\n        _grainContext = grainContext;\n        _dueTime = Timeout.InfiniteTimeSpan;\n        _period = Timeout.InfiniteTimeSpan;\n        _invoker = new(this);\n\n        // Avoid capturing async locals.\n        using (new ExecutionContextSuppressor())\n        {\n            _timer = shared.TimeProvider.CreateTimer(TimerCallback, this, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);\n        }\n    }\n\n    protected IGrainContext GrainContext => _grainContext;\n\n    private ILogger Logger => _shared.TimerLogger;\n\n    [DoesNotReturn]\n    private static void ThrowIncorrectGrainContext() => throw new InvalidOperationException(\"Current grain context differs from specified grain context.\");\n\n    [DoesNotReturn]\n    private static void ThrowInvalidSchedulingContext()\n    {\n        throw new InvalidSchedulingContextException(\n            \"Current grain context is null. \"\n             + \"Please make sure you are not trying to create a Timer from outside Orleans Task Scheduler, \"\n             + \"which will be the case if you create it inside Task.Run.\");\n    }\n\n    protected void ScheduleTickOnActivation()\n    {\n        try\n        {\n            // Indicate that the timer is firing so that the effect of the next change call is deferred until after the tick completes.\n            _firing = true;\n\n            // Note: this does not execute on the activation's execution context.\n            var msg = _shared.MessageFactory.CreateMessage(body: _invoker, options: InvokeMethodOptions.OneWay);\n            msg.SetInfiniteTimeToLive();\n            msg.SendingGrain = _grainContext.GrainId;\n            msg.TargetGrain = _grainContext.GrainId;\n            msg.SendingSilo = _shared.LocalSiloDetails.SiloAddress;\n            msg.TargetSilo = _shared.LocalSiloDetails.SiloAddress;\n            msg.InterfaceType = InvokableInterfaceType;\n            msg.IsKeepAlive = _keepAlive;\n            msg.IsAlwaysInterleave = _interleave;\n\n            // Prevent the message from being forwarded in the case of deactivation.\n            msg.IsLocalOnly = true;\n\n            _grainContext.ReceiveMessage(msg);\n        }\n        catch (Exception exception)\n        {\n            try\n            {\n                LogErrorScheduleTickOnActivation(Logger, exception, this);\n            }\n            catch\n            {\n                // Ignore.\n                // Allowing an exception to escape here would crash the process.\n            }\n        }\n    }\n\n    protected abstract Task InvokeCallbackAsync(CancellationToken cancellationToken);\n\n    private ValueTask<Response> InvokeGrainTimerCallbackAsync()\n    {\n        try\n        {\n            LogTraceBeforeCallback(Logger, this);\n\n            _changed = false;\n            var task = InvokeCallbackAsync(_cts.Token);\n\n            // If the task is not completed, we need to await the tick asynchronously.\n            if (task is { IsCompletedSuccessfully: false })\n            {\n                // Complete asynchronously.\n                return AwaitCallbackTask(task);\n            }\n            else\n            {\n                // Complete synchronously.\n                LogTraceAfterCallback(Logger, this);\n\n                OnTickCompleted();\n                return new(Response.Completed);\n            }\n        }\n        catch (Exception exc)\n        {\n            OnTickCompleted();\n            return new(OnCallbackException(exc));\n        }\n    }\n\n    private void OnTickCompleted()\n    {\n        // Schedule the next tick.\n        try\n        {\n            if (_cts.IsCancellationRequested)\n            {\n                // The instance has been disposed. No further ticks should be fired.\n                return;\n            }\n\n            if (!_changed)\n            {\n                // If the timer was not modified during the tick, schedule the next tick based on the period.\n                _timer.Change(_period, Timeout.InfiniteTimeSpan);\n            }\n            else\n            {\n                // If the timer was modified during the tick, schedule the next tick based on the new due time.\n                _timer.Change(_dueTime, Timeout.InfiniteTimeSpan);\n            }\n        }\n        catch (ObjectDisposedException)\n        {\n        }\n        finally\n        {\n            _firing = false;\n        }\n    }\n\n    private Response OnCallbackException(Exception exc)\n    {\n        LogWarningCallbackException(Logger, exc, this);\n        return Response.FromException(exc);\n    }\n\n    private async ValueTask<Response> AwaitCallbackTask(Task task)\n    {\n        try\n        {\n            await task;\n\n            LogTraceAfterCallback(Logger, this);\n\n            return Response.Completed;\n        }\n        catch (Exception exc)\n        {\n            return OnCallbackException(exc);\n        }\n        finally\n        {\n            OnTickCompleted();\n        }\n    }\n\n    public void Change(TimeSpan dueTime, TimeSpan period)\n    {\n        ValidateArguments(dueTime, period);\n\n        _changed = true;\n        _dueTime = dueTime;\n        _period = period;\n\n        // If the timer is currently firing, the change will be deferred until after the tick completes.\n        // Otherwise, perform the change now.\n        if (!_firing)\n        {\n            try\n            {\n                // This method resets the timer, so the next tick will be scheduled at the new due time and subsequent\n                // ticks will be scheduled after the specified period.\n                _timer.Change(dueTime, Timeout.InfiniteTimeSpan);\n            }\n            catch (ObjectDisposedException)\n            {\n            }\n        }\n    }\n\n    private static void ValidateArguments(TimeSpan dueTime, TimeSpan period)\n    {\n        // See https://github.com/dotnet/runtime/blob/78b5f40a60d9e095abb2b0aabd8c062b171fb9ab/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs#L824-L825\n        const uint MaxSupportedTimeout = 0xfffffffe;\n\n        // See https://github.com/dotnet/runtime/blob/78b5f40a60d9e095abb2b0aabd8c062b171fb9ab/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs#L927-L930\n        long dueTm = (long)dueTime.TotalMilliseconds;\n        ArgumentOutOfRangeException.ThrowIfLessThan(dueTm, -1, nameof(dueTime));\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(dueTm, MaxSupportedTimeout, nameof(dueTime));\n\n        long periodTm = (long)period.TotalMilliseconds;\n        ArgumentOutOfRangeException.ThrowIfLessThan(periodTm, -1, nameof(period));\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(periodTm, MaxSupportedTimeout, nameof(period));\n    }\n\n    public void Dispose()\n    {\n        try\n        {\n            _cts.Cancel();\n        }\n        catch (Exception exception)\n        {\n            LogErrorCancellingCallback(Logger, exception);\n        }\n\n        _timer.Dispose();\n        var timerRegistry = _grainContext.GetComponent<IGrainTimerRegistry>();\n        timerRegistry?.OnTimerDisposed(this);\n    }\n\n    public override string ToString() => $\"[{GetType()}] Grain: '{_grainContext}'\";\n\n    private sealed class TimerTickInvoker(GrainTimer timer) : IInvokable, IGrainTimerInvoker\n    {\n        public object? GetTarget() => this;\n\n        public void SetTarget(ITargetHolder holder)\n        {\n            if (timer._grainContext != holder)\n            {\n                throw new InvalidOperationException($\"Invalid target holder. Expected {timer._grainContext}, received {holder}.\");\n            }\n        }\n\n        public ValueTask<Response> Invoke() => timer.InvokeGrainTimerCallbackAsync();\n\n        // This method is declared for the sake of IGrainTimerCore, but it is not intended to be called directly.\n        // It exists for grain call interceptors which inspect the implementation method.\n        Task IGrainTimerInvoker.InvokeCallbackAsync() => throw new InvalidOperationException();\n\n        public int GetArgumentCount() => 0;\n\n        public object? GetArgument(int index) => throw new InvalidOperationException();\n\n        public void SetArgument(int index, object? value) => throw new InvalidOperationException();\n\n        public string GetMethodName() => nameof(IGrainTimerInvoker.InvokeCallbackAsync);\n\n        public string GetInterfaceName() => nameof(IGrainTimerInvoker);\n\n        public string GetActivityName() => $\"{nameof(IGrainTimerInvoker)}/{nameof(IGrainTimerInvoker.InvokeCallbackAsync)}\";\n\n        public MethodInfo GetMethod() => InvokableMethodInfo;\n\n        public Type GetInterfaceType() => typeof(IGrainTimerInvoker);\n\n        public TimeSpan? GetDefaultResponseTimeout() => null;\n\n        public void Dispose()\n        {\n            // Do nothing. Instances are disposed after invocation, but this instance will be reused for the lifetime of the timer.\n        }\n\n        public override string ToString() => timer.ToString();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error invoking timer tick for timer '{Timer}'.\"\n    )]\n    private static partial void LogErrorScheduleTickOnActivation(ILogger logger, Exception exception, GrainTimer timer);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.TimerBeforeCallback,\n        Level = LogLevel.Trace,\n        Message = \"About to invoke callback for timer {Timer}\"\n    )]\n    private static partial void LogTraceBeforeCallback(ILogger logger, GrainTimer timer);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.TimerAfterCallback,\n        Level = LogLevel.Trace,\n        Message = \"Completed timer callback for timer '{Timer}'.\"\n    )]\n    private static partial void LogTraceAfterCallback(ILogger logger, GrainTimer timer);\n\n    [LoggerMessage(\n        EventId = (int)ErrorCode.Timer_GrainTimerCallbackError,\n        Level = LogLevel.Warning,\n        Message = \"Caught and ignored exception thrown from timer callback for timer '{Timer}'.\"\n    )]\n    private static partial void LogWarningCallbackException(ILogger logger, Exception exception, GrainTimer timer);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Error cancelling timer callback.\"\n    )]\n    private static partial void LogErrorCancellingCallback(ILogger logger, Exception exception);\n}\n\ninternal sealed class GrainTimer<T> : GrainTimer\n{\n    private readonly Func<T, CancellationToken, Task> _callback;\n    private readonly T _state;\n\n    public GrainTimer(\n        TimerRegistry shared,\n        IGrainContext grainContext,\n        Func<T, CancellationToken, Task> callback,\n        T state,\n        bool interleave,\n        bool keepAlive)\n        : base(\n            shared,\n            grainContext,\n            interleave,\n            keepAlive)\n    {\n        ArgumentNullException.ThrowIfNull(callback);\n        _callback = callback;\n        _state = state;\n    }\n\n    protected override Task InvokeCallbackAsync(CancellationToken cancellationToken) => _callback(_state, cancellationToken);\n\n    public override string ToString() => $\"{base.ToString()} Callback: '{_callback?.Target}.{_callback?.Method}'. State: '{_state}'\";\n}\n\ninternal sealed class InterleavingGrainTimer : GrainTimer\n{\n    private readonly Func<object?, Task> _callback;\n    private readonly object? _state;\n\n    public InterleavingGrainTimer(\n        TimerRegistry shared,\n        IGrainContext grainContext,\n        Func<object?, Task> callback,\n        object? state)\n        : base(\n            shared,\n            grainContext,\n            interleave: true,\n            keepAlive: false)\n    {\n        ArgumentNullException.ThrowIfNull(callback);\n        _callback = callback;\n        _state = state;\n    }\n\n    protected override Task InvokeCallbackAsync(CancellationToken cancellationToken) => _callback(_state);\n\n    public override string ToString() => $\"{base.ToString()} Callback: '{_callback?.Target}.{_callback?.Method}'. State: '{_state}'\";\n}\n\n// This interface exists for the IInvokable implementation, so that call filters behave as intended.\ninternal interface IGrainTimerInvoker : IAddressable\n{\n    /// <summary>\n    /// Invokes the callback.\n    /// </summary>\n    Task InvokeCallbackAsync();\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/IAsyncTimer.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Runtime\n{\n    internal interface IAsyncTimer : IDisposable, IHealthCheckable\n    {\n        Task<bool> NextTick(TimeSpan? overrideDelay = default);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/IAsyncTimerFactory.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Runtime\n{\n    internal interface IAsyncTimerFactory\n    {\n        IAsyncTimer Create(TimeSpan period, string name);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/IGrainTimerRegistry.cs",
    "content": "#nullable enable\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Provides functionality to record the creation and deletion of grain timers.\n/// </summary>\ninternal interface IGrainTimerRegistry\n{\n    /// <summary>\n    /// Signals to the registry that a timer was created.\n    /// </summary>\n    /// <param name=\"timer\">\n    /// The timer.\n    /// </param>\n    void OnTimerCreated(IGrainTimer timer);\n\n    /// <summary>\n    /// Signals to the registry that a timer was disposed.\n    /// </summary>\n    /// <param name=\"timer\">\n    /// The timer.\n    /// </param>\n    void OnTimerDisposed(IGrainTimer timer);\n}\n\n"
  },
  {
    "path": "src/Orleans.Runtime/Timers/TimerRegistry.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Timers;\n\ninternal class TimerRegistry(ILoggerFactory loggerFactory, TimeProvider timeProvider, MessageFactory messageFactory, ILocalSiloDetails localSiloDetails) : ITimerRegistry\n{\n    public ILogger TimerLogger { get; } = loggerFactory.CreateLogger<GrainTimer>();\n    public TimeProvider TimeProvider { get; } = timeProvider;\n    public MessageFactory MessageFactory { get; } = messageFactory;\n    public ILocalSiloDetails LocalSiloDetails { get; } = localSiloDetails;\n\n    public IDisposable RegisterTimer(IGrainContext grainContext, Func<object?, Task> callback, object? state, TimeSpan dueTime, TimeSpan period)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext);\n        ArgumentNullException.ThrowIfNull(callback);\n        var timer = new InterleavingGrainTimer(this, grainContext, callback, state);\n        grainContext.GetComponent<IGrainTimerRegistry>()?.OnTimerCreated(timer);\n        timer.Change(dueTime, period);\n        return timer;\n    }\n\n    public IGrainTimer RegisterGrainTimer<T>(IGrainContext grainContext, Func<T, CancellationToken, Task> callback, T state, GrainTimerCreationOptions options)\n    {\n        ArgumentNullException.ThrowIfNull(grainContext);\n        ArgumentNullException.ThrowIfNull(callback);\n        var timer = new GrainTimer<T>(this, grainContext, callback, state, options.Interleave, options.KeepAlive);\n        grainContext.GetComponent<IGrainTimerRegistry>()?.OnTimerCreated(timer);\n        timer.Change(options.DueTime, options.Period);\n        return timer;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Utilities/FactoryUtility.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime.Utilities\n{\n    /// <summary>\n    /// Utility methods for creating factories which construct instances of objects using an <see cref=\"IServiceProvider\"/>.\n    /// </summary>\n    internal static class FactoryUtility\n    {\n        private static readonly object[] EmptyArguments = new object[0];\n\n        /// <summary>\n        /// Creates a factory returning a new <typeparamref name=\"TInstance\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <returns>A new factory.</returns>\n        public static Factory<TInstance> Create<TInstance>(IServiceProvider serviceProvider)\n        {\n            var factory = ActivatorUtilities.CreateFactory(typeof(TInstance), Type.EmptyTypes);\n            return () => (TInstance)factory(serviceProvider, EmptyArguments);\n        }\n\n        /// <summary>\n        /// Creates a factory returning a new <typeparamref name=\"TInstance\"/> given an argument of type <typeparamref name=\"TParam1\"/>.\n        /// </summary>\n        /// <typeparam name=\"TParam1\">The type of the parameter to the factory.</typeparam>\n        /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <returns>A new factory.</returns>\n        public static Factory<TParam1, TInstance> Create<TParam1, TInstance>(IServiceProvider serviceProvider)\n        {\n            var factory = ActivatorUtilities.CreateFactory(typeof(TInstance), new[] { typeof(TParam1) });\n            return arg1 => (TInstance)factory(serviceProvider, new object[] { arg1 });\n        }\n\n        /// <summary>\n        /// Creates a factory returning a new <typeparamref name=\"TInstance\"/> given arguments of the specified types.\n        /// </summary>\n        /// <typeparam name=\"TParam1\">The type of the 1st parameter to the factory.</typeparam>\n        /// <typeparam name=\"TParam2\">The type of the 2nd parameter to the factory.</typeparam>\n        /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <returns>A new factory.</returns>\n        public static Factory<TParam1, TParam2, TInstance> Create<TParam1, TParam2, TInstance>(IServiceProvider serviceProvider)\n        {\n            var factory = ActivatorUtilities.CreateFactory(typeof(TInstance), new[] { typeof(TParam1), typeof(TParam2) });\n            return (arg1, arg2) => (TInstance)factory(serviceProvider, new object[] { arg1, arg2 });\n        }\n        /// <summary>\n        /// Creates a factory returning a new <typeparamref name=\"TInstance\"/> given arguments of the specified types.\n        /// </summary>\n        /// <typeparam name=\"TParam1\">The type of the 1st parameter to the factory.</typeparam>\n        /// <typeparam name=\"TParam2\">The type of the 2nd parameter to the factory.</typeparam>\n        /// <typeparam name=\"TParam3\">The type of the 3rd parameter to the factory.</typeparam>\n        /// <typeparam name=\"TInstance\">The instance type.</typeparam>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <returns>A new factory.</returns>\n        public static Factory<TParam1, TParam2, TParam3, TInstance> Create<TParam1, TParam2, TParam3, TInstance>(IServiceProvider serviceProvider)\n        {\n            var factory = ActivatorUtilities.CreateFactory(typeof(TInstance), new[] { typeof(TParam1), typeof(TParam2), typeof(TParam3) });\n            return (arg1, arg2, arg3) => (TInstance)factory(serviceProvider, new object[] { arg1, arg2, arg3 });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Utilities/OrleansDebuggerHelper.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Runtime.Utilities\n{\n    /// <summary>\n    /// Utility methods for aiding debugger sessions.\n    /// </summary>\n    public static class OrleansDebuggerHelper\n    {\n        /// <summary>\n        /// Returns the grain instance corresponding to the provided <paramref name=\"grainReference\"/> if it is activated on current silo.\n        /// </summary>\n        /// <param name=\"grainReference\">The grain reference.</param>\n        /// <returns>\n        /// The grain instance corresponding to the provided <paramref name=\"grainReference\"/> if it is activated on current silo, or <see langword=\"null\"/> otherwise.\n        /// </returns>\n        public static object GetGrainInstance(object grainReference)\n        {\n            switch (grainReference)\n            {\n                case Grain:\n                case IGrainBase:\n                case ISystemTargetBase:\n                    return grainReference;\n                case GrainReference reference:\n                    {\n                        var runtime = (reference.Runtime as GrainReferenceRuntime)?.RuntimeClient;\n                        var activations = runtime?.ServiceProvider.GetService<ActivationDirectory>();\n                        var grains = activations?.FindTarget(reference.GrainId);\n                        return grains?.GrainInstance;\n                    }\n                default:\n                    return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Utilities/SearchAlgorithms.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Runtime.Utilities;\n\ninternal static class SearchAlgorithms\n{\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static int BinarySearch<TState>(int length, TState state, Func<int, TState, int> comparer)\n    {\n        var left = 0;\n        var right = length - 1;\n\n        while (left <= right)\n        {\n            var mid = left + (right - left) / 2;\n            var comparison = comparer(mid, state);\n\n            if (comparison == 0)\n            {\n                return mid;\n            }\n            else if (comparison < 0)\n            {\n                left = mid + 1;\n            }\n            else\n            {\n                right = mid - 1;\n            }\n        }\n\n        return -1;\n    }\n\n    // Binary search for collections of ranges along a ring (eg, a consistent hash ring), sorted by the starting point of each range.\n    // This differs from a standard binary search in that the search can wrap around from the start to the last element in the collection.\n    // This is accommodated by checking the last element in the collection before returning a negative result, to handle the case where a\n    // range wraps around from end to start. See RingRange\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static int RingRangeBinarySearch<TCollection, TElement, TKey>(\n        int length,\n        TCollection collection,\n        Func<TCollection, int, TElement> getEntry,\n        TKey key) where TElement : IComparable<TKey>\n    {\n        if (length == 0) return -1;\n\n        var left = 0;\n        var right = length - 1;\n\n        TElement entry;\n        while (left <= right)\n        {\n            var mid = left + (right - left) / 2;\n            entry = getEntry(collection, mid);\n            var comparison = entry.CompareTo(key);\n\n            if (comparison == 0)\n            {\n                return mid;\n            }\n            else if (comparison < 0)\n            {\n                // Go right.\n                left = mid + 1;\n            }\n            else\n            {\n                // Go left.\n                right = mid - 1;\n            }\n        }\n\n        // Try the last element.\n        entry = getEntry(collection, length - 1);\n        if (entry.CompareTo(key) == 0)\n        {\n            return length - 1;\n        }\n\n#if DEBUG\n        // Try the first element.\n        entry = getEntry(collection, 0);\n        if (entry.CompareTo(key) == 0)\n        {\n            Debug.Fail(\"Sort order invariant violated.\");\n        }\n#endif\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Utilities/StripedMpscBuffer.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Runtime.Utilities;\n\n/// <summary>\n/// Provides a striped bounded buffer. Add operations use thread ID to index into\n/// the underlying array of buffers, and if TryAdd is contended the thread ID is\n/// rehashed to select a different buffer to retry up to 3 times. Using this approach\n/// writes scale linearly with number of concurrent threads.\n/// </summary>\n/// <remarks>\n/// Derived from BitFaster.Caching by Alex Peck: https://github.com/bitfaster/BitFaster.Caching/blob/275b9b072c0218e20f549b769cd183df1374e2ee/BitFaster.Caching/Buffers/StripedMpscBuffer.cs\n/// </remarks>\n[DebuggerDisplay(\"Count = {Count}/{Capacity}\")]\ninternal sealed class StripedMpscBuffer<T> where T : class\n{\n    private const int MaxAttempts = 3;\n\n    private readonly MpscBoundedBuffer<T>[] _buffers;\n\n    /// <summary>\n    /// Initializes a new instance of the StripedMpscBuffer class with the specified stripe count and buffer size.\n    /// </summary>\n    /// <param name=\"stripeCount\">The stripe count.</param>\n    /// <param name=\"bufferSize\">The buffer size.</param>\n    public StripedMpscBuffer(int stripeCount, int bufferSize)\n    {\n        _buffers = new MpscBoundedBuffer<T>[stripeCount];\n\n        for (var i = 0; i < stripeCount; i++)\n        {\n            _buffers[i] = new MpscBoundedBuffer<T>(bufferSize);\n        }\n    }\n\n    /// <summary>\n    /// Gets the number of items contained in the buffer.\n    /// </summary>\n    public int Count => _buffers.Sum(b => b.Count);\n\n    /// <summary>\n    /// The bounded capacity.\n    /// </summary>\n    public int Capacity => _buffers.Length * _buffers[0].Capacity;\n\n    /// <summary>\n    /// Drains the buffer into the specified array.\n    /// </summary>\n    /// <param name=\"outputBuffer\">The output buffer</param>\n    /// <returns>The number of items written to the output buffer.</returns>\n    /// <remarks>\n    /// Thread safe for single try take/drain + multiple try add.\n    /// </remarks>\n    public int DrainTo(T[] outputBuffer) => DrainTo(outputBuffer.AsSpan());\n\n    /// <summary>\n    /// Drains the buffer into the specified span.\n    /// </summary>\n    /// <param name=\"outputBuffer\">The output buffer</param>\n    /// <returns>The number of items written to the output buffer.</returns>\n    /// <remarks>\n    /// Thread safe for single try take/drain + multiple try add.\n    /// </remarks>\n    public int DrainTo(Span<T> outputBuffer)\n    {\n        var count = 0;\n\n        for (var i = 0; i < _buffers.Length; i++)\n        {\n            if (count == outputBuffer.Length)\n            {\n                break;\n            }\n\n            var segment = outputBuffer[count..];\n\n            count += _buffers[i].DrainTo(segment);\n        }\n\n        return count;\n    }\n\n    /// <summary>\n    /// Tries to add the specified item.\n    /// </summary>\n    /// <param name=\"item\">The item to be added.</param>\n    /// <returns>A BufferStatus value indicating whether the operation succeeded.</returns>\n    /// <remarks>\n    /// Thread safe.\n    /// </remarks>\n    public BufferStatus TryAdd(T item)\n    {\n        var z = BitOps.Mix64((ulong)Environment.CurrentManagedThreadId);\n        var inc = (int)(z >> 32) | 1;\n        var h = (int)z;\n\n        var mask = _buffers.Length - 1;\n\n        var result = BufferStatus.Empty;\n\n        for (var i = 0; i < MaxAttempts; i++)\n        {\n            result = _buffers[h & mask].TryAdd(item);\n\n            if (result == BufferStatus.Success)\n            {\n                break;\n            }\n\n            h += inc;\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    /// Removes all values from the buffer.\n    /// </summary>\n    /// <remarks>\n    /// Not thread safe.\n    /// </remarks>\n    public void Clear()\n    {\n        for (var i = 0; i < _buffers.Length; i++)\n        {\n            _buffers[i].Clear();\n        }\n    }\n}\n\n/// <summary>\n/// Provides a multi-producer, single-consumer thread-safe ring buffer. When the buffer is full,\n/// TryAdd fails and returns false. When the buffer is empty, TryTake fails and returns false.\n/// </summary>\n/// Based on the BoundedBuffer class in the Caffeine library by ben.manes@gmail.com (Ben Manes).\n[DebuggerDisplay(\"Count = {Count}/{Capacity}\")]\ninternal sealed class MpscBoundedBuffer<T> where T : class\n{\n    private T[] _buffer;\n    private readonly int _mask;\n    private PaddedHeadAndTail _headAndTail; // mutable struct, don't mark readonly\n\n    /// <summary>\n    /// Initializes a new instance of the MpscBoundedBuffer class with the specified bounded capacity.\n    /// </summary>\n    /// <param name=\"boundedLength\">The bounded length.</param>\n    /// <exception cref=\"ArgumentOutOfRangeException\"></exception>\n    public MpscBoundedBuffer(int boundedLength)\n    {\n        ArgumentOutOfRangeException.ThrowIfLessThan(boundedLength, 0);\n\n        // must be power of 2 to use & slotsMask instead of %\n        boundedLength = BitOps.CeilingPowerOfTwo(boundedLength);\n\n        _buffer = new T[boundedLength];\n        _mask = boundedLength - 1;\n    }\n\n    /// <summary>\n    /// The bounded capacity.\n    /// </summary>\n    public int Capacity => _buffer.Length;\n\n    /// <summary>\n    /// Gets the number of items contained in the buffer.\n    /// </summary>\n    public int Count\n    {\n        get\n        {\n            var spinner = new SpinWait();\n            while (true)\n            {\n                var headNow = Volatile.Read(ref _headAndTail.Head);\n                var tailNow = Volatile.Read(ref _headAndTail.Tail);\n\n                if (headNow == Volatile.Read(ref _headAndTail.Head) &&\n                    tailNow == Volatile.Read(ref _headAndTail.Tail))\n                {\n                    return GetCount(headNow, tailNow);\n                }\n\n                spinner.SpinOnce();\n            }\n        }\n    }\n\n    private int GetCount(int head, int tail)\n    {\n        if (head != tail)\n        {\n            head &= _mask;\n            tail &= _mask;\n\n            return head < tail ? tail - head : _buffer.Length - head + tail;\n        }\n        return 0;\n    }\n\n    /// <summary>\n    /// Tries to add the specified item.\n    /// </summary>\n    /// <param name=\"item\">The item to be added.</param>\n    /// <returns>A BufferStatus value indicating whether the operation succeeded.</returns>\n    /// <remarks>\n    /// Thread safe.\n    /// </remarks>\n    public BufferStatus TryAdd(T item)\n    {\n        int head = Volatile.Read(ref _headAndTail.Head);\n        int tail = _headAndTail.Tail;\n        int size = tail - head;\n\n        if (size >= _buffer.Length)\n        {\n            return BufferStatus.Full;\n        }\n\n        if (Interlocked.CompareExchange(ref _headAndTail.Tail, tail + 1, tail) == tail)\n        {\n            int index = tail & _mask;\n            Volatile.Write(ref _buffer[index], item);\n\n            return BufferStatus.Success;\n        }\n\n        return BufferStatus.Contended;\n    }\n\n\n    /// <summary>\n    /// Tries to remove an item.\n    /// </summary>\n    /// <param name=\"item\">The item to be removed.</param>\n    /// <returns>A BufferStatus value indicating whether the operation succeeded.</returns>\n    /// <remarks>\n    /// Thread safe for single try take/drain + multiple try add.\n    /// </remarks>\n    public BufferStatus TryTake(out T item)\n    {\n        int head = Volatile.Read(ref _headAndTail.Head);\n        int tail = _headAndTail.Tail;\n        int size = tail - head;\n\n        if (size == 0)\n        {\n            item = default;\n            return BufferStatus.Empty;\n        }\n\n        int index = head & _mask;\n\n        item = Volatile.Read(ref _buffer[index]);\n\n        if (item == null)\n        {\n            // not published yet\n            return BufferStatus.Contended;\n        }\n\n        _buffer[index] = null;\n        Volatile.Write(ref _headAndTail.Head, ++head);\n        return BufferStatus.Success;\n    }\n\n    /// <summary>\n    /// Drains the buffer into the specified array segment.\n    /// </summary>\n    /// <param name=\"output\">The output buffer</param>\n    /// <returns>The number of items written to the output buffer.</returns>\n    /// <remarks>\n    /// Thread safe for single try take/drain + multiple try add.\n    /// </remarks>\n    public int DrainTo(ArraySegment<T> output) => DrainTo(output.AsSpan());\n\n    /// <summary>\n    /// Drains the buffer into the specified span.\n    /// </summary>\n    /// <param name=\"output\">The output buffer</param>\n    /// <returns>The number of items written to the output buffer.</returns>\n    /// <remarks>\n    /// Thread safe for single try take/drain + multiple try add.\n    /// </remarks>\n    public int DrainTo(Span<T> output) => DrainToImpl(output);\n\n    // use an outer wrapper method to force the JIT to inline the inner adaptor methods\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private int DrainToImpl(Span<T> output)\n    {\n        int head = Volatile.Read(ref _headAndTail.Head);\n        int tail = _headAndTail.Tail;\n        int size = tail - head;\n\n        if (size == 0)\n        {\n            return 0;\n        }\n\n        var localBuffer = _buffer.AsSpan();\n\n        int outCount = 0;\n\n        do\n        {\n            int index = head & _mask;\n\n            T item = Volatile.Read(ref localBuffer[index]);\n\n            if (item == null)\n            {\n                // not published yet\n                break;\n            }\n\n            localBuffer[index] = null;\n            Write(output, outCount++, item);\n            head++;\n        }\n        while (head != tail && outCount < Length(output));\n\n        _headAndTail.Head = head;\n\n        return outCount;\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static void Write(Span<T> output, int index, T item) => output[index] = item;\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static int Length(Span<T> output) => output.Length;\n\n    /// <summary>\n    /// Removes all values from the buffer.\n    /// </summary>\n    /// <remarks>\n    /// Not thread safe.\n    /// </remarks>\n    public void Clear()\n    {\n        _buffer = new T[_buffer.Length];\n        _headAndTail = new PaddedHeadAndTail();\n    }\n}\n\n/// <summary>\n/// Specifies the status of buffer operations.\n/// </summary>\ninternal enum BufferStatus\n{\n    /// <summary>\n    /// The buffer is full.\n    /// </summary>\n    Full,\n\n    /// <summary>\n    /// The buffer is empty.\n    /// </summary>\n    Empty,\n\n    /// <summary>\n    /// The buffer operation succeeded.\n    /// </summary>\n    Success,\n\n    /// <summary>\n    /// The buffer operation was contended.\n    /// </summary>\n    Contended,\n}\n\n/// <summary>\n/// Provides utility methods for bit-twiddling operations.\n/// </summary>\ninternal static class BitOps\n{\n    /// <summary>\n    /// Calculate the smallest power of 2 greater than the input parameter.\n    /// </summary>\n    /// <param name=\"x\">The input parameter.</param>\n    /// <returns>Smallest power of two greater than or equal to x.</returns>\n    public static int CeilingPowerOfTwo(int x) => (int)CeilingPowerOfTwo((uint)x);\n\n    /// <summary>\n    /// Calculate the smallest power of 2 greater than the input parameter.\n    /// </summary>\n    /// <param name=\"x\">The input parameter.</param>\n    /// <returns>Smallest power of two greater than or equal to x.</returns>\n    public static uint CeilingPowerOfTwo(uint x) => 1u << -BitOperations.LeadingZeroCount(x - 1);\n\n    /// <summary>\n    /// Computes Stafford variant 13 of 64-bit mix function.\n    /// </summary>\n    /// <param name=\"z\">The input parameter.</param>\n    /// <returns>A bit mix of the input parameter.</returns>\n    /// <remarks>\n    /// See http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html\n    /// </remarks>\n    public static ulong Mix64(ulong z)\n    {\n        z = (z ^ z >> 30) * 0xbf58476d1ce4e5b9L;\n        z = (z ^ z >> 27) * 0x94d049bb133111ebL;\n        return z ^ z >> 31;\n    }\n}\n\n[DebuggerDisplay(\"Head = {Head}, Tail = {Tail}\")]\n[StructLayout(LayoutKind.Explicit, Size = 3 * Padding.CACHE_LINE_SIZE)] // padding before/between/after fields\ninternal struct PaddedHeadAndTail\n{\n    [FieldOffset(1 * Padding.CACHE_LINE_SIZE)] public int Head;\n    [FieldOffset(2 * Padding.CACHE_LINE_SIZE)] public int Tail;\n}\n\ninternal static class Padding\n{\n#if TARGET_ARM64 || TARGET_LOONGARCH64\n        internal const int CACHE_LINE_SIZE = 128;\n#else\n    internal const int CACHE_LINE_SIZE = 64;\n#endif\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/CachedVersionSelectorManager.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Metadata;\nusing Orleans.Runtime.Versions.Compatibility;\nusing Orleans.Runtime.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions\n{\n    internal class CachedVersionSelectorManager\n    {\n        private readonly ConcurrentDictionary<(GrainType Type, GrainInterfaceType Interface, ushort Version), CachedEntry> suitableSilosCache;\n        private readonly GrainVersionManifest grainInterfaceVersions;\n\n        public CachedVersionSelectorManager(GrainVersionManifest grainInterfaceVersions, VersionSelectorManager versionSelectorManager, CompatibilityDirectorManager compatibilityDirectorManager)\n        {\n            this.grainInterfaceVersions = grainInterfaceVersions;\n            this.VersionSelectorManager = versionSelectorManager;\n            this.CompatibilityDirectorManager = compatibilityDirectorManager;\n            this.suitableSilosCache = new ConcurrentDictionary<(GrainType Type, GrainInterfaceType Interface, ushort Version), CachedEntry>();\n        }\n\n        public VersionSelectorManager VersionSelectorManager { get; }\n\n        public CompatibilityDirectorManager CompatibilityDirectorManager { get; }\n\n        public CachedEntry GetSuitableSilos(GrainType grainType, GrainInterfaceType interfaceId, ushort requestedVersion)\n        {\n            var key = ValueTuple.Create(grainType, interfaceId, requestedVersion);\n            if (!suitableSilosCache.TryGetValue(key, out var entry) || entry.Version < this.grainInterfaceVersions.LatestVersion)\n            {\n                entry = suitableSilosCache[key] = GetSuitableSilosImpl(key);\n            }\n\n            return entry;\n        }\n\n        public void ResetCache()\n        {\n            this.suitableSilosCache.Clear();\n        }\n\n        private CachedEntry GetSuitableSilosImpl((GrainType Type, GrainInterfaceType Interface, ushort Version) key)\n        {\n            var grainType = key.Type;\n            var interfaceType = key.Interface;\n            var requestedVersion = key.Version;\n\n            var versionSelector = this.VersionSelectorManager.GetSelector(interfaceType);\n            var compatibilityDirector = this.CompatibilityDirectorManager.GetDirector(interfaceType);\n            (var version, var available) = this.grainInterfaceVersions.GetAvailableVersions(interfaceType);\n            var versions = versionSelector.GetSuitableVersion(\n                requestedVersion, \n                available, \n                compatibilityDirector);\n\n            (_, var result) = this.grainInterfaceVersions.GetSupportedSilos(grainType, interfaceType, versions);\n\n            return new CachedEntry\n            {\n                Version = version,\n                SuitableSilos = result.SelectMany(sv => sv.Value).Distinct().OrderBy(addr => addr).ToArray(),\n                SuitableSilosByVersion = result,\n            };\n        }\n\n        internal struct CachedEntry\n        {\n            public MajorMinorVersion Version { get; set; }\n\n            public SiloAddress[] SuitableSilos { get; set; }\n\n            public Dictionary<ushort, SiloAddress[]> SuitableSilosByVersion { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Compatibility/AllVersionsCompatibilityDirector.cs",
    "content": "using Orleans.Versions.Compatibility;\n\nnamespace Orleans.Runtime.Versions.Compatibility\n{\n    internal class AllVersionsCompatibilityDirector : ICompatibilityDirector\n    {\n        public bool IsCompatible(ushort requestedVersion, ushort currentVersion)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Compatibility/BackwardCompatilityDirector.cs",
    "content": "using Orleans.Versions.Compatibility;\n\nnamespace Orleans.Runtime.Versions.Compatibility\n{\n    internal class BackwardCompatilityDirector : ICompatibilityDirector\n    {\n        public bool IsCompatible(ushort requestedVersion, ushort currentVersion)\n        {\n            return requestedVersion <= currentVersion;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Compatibility/CompatibilityDirectorManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Versions.Compatibility;\n\nnamespace Orleans.Runtime.Versions.Compatibility\n{\n    internal class CompatibilityDirectorManager\n    {\n        private readonly CompatibilityStrategy strategyFromConfig;\n        private readonly IServiceProvider serviceProvider;\n        private readonly Dictionary<GrainInterfaceType, ICompatibilityDirector> compatibilityDirectors;\n\n        public ICompatibilityDirector Default { get; private set; }\n\n\n        public CompatibilityDirectorManager(IServiceProvider serviceProvider, IOptions<GrainVersioningOptions> options)\n        {\n            this.serviceProvider = serviceProvider;\n            this.strategyFromConfig = serviceProvider.GetRequiredKeyedService<CompatibilityStrategy>(options.Value.DefaultCompatibilityStrategy);\n            this.compatibilityDirectors = new Dictionary<GrainInterfaceType, ICompatibilityDirector>();\n            Default = ResolveVersionDirector(serviceProvider, this.strategyFromConfig);\n        }\n\n        public ICompatibilityDirector GetDirector(GrainInterfaceType interfaceType)\n        {\n            ICompatibilityDirector director;\n            return compatibilityDirectors.TryGetValue(interfaceType, out director) \n                ? director \n                : Default;\n        }\n        public void SetStrategy(CompatibilityStrategy strategy)\n        {\n            var director = ResolveVersionDirector(this.serviceProvider, strategy ?? this.strategyFromConfig);\n            Default = director;\n        }\n\n        public void SetStrategy(GrainInterfaceType interfaceType, CompatibilityStrategy strategy)\n        {\n            if (strategy == null)\n            {\n                compatibilityDirectors.Remove(interfaceType);\n            }\n            else\n            {\n                var selector = ResolveVersionDirector(this.serviceProvider, strategy);\n                compatibilityDirectors[interfaceType] = selector;\n            }\n        }\n\n        private static ICompatibilityDirector ResolveVersionDirector(IServiceProvider serviceProvider,\n            CompatibilityStrategy compatibilityStrategy)\n        {\n            var strategyType = compatibilityStrategy.GetType();\n            return serviceProvider.GetRequiredKeyedService<ICompatibilityDirector>(strategyType);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Compatibility/StrictVersionCompatibilityDirector.cs",
    "content": "using Orleans.Versions.Compatibility;\n\nnamespace Orleans.Runtime.Versions.Compatibility\n{\n    internal class StrictVersionCompatibilityDirector : ICompatibilityDirector\n    {\n        public bool IsCompatible(ushort requestedVersion, ushort currentVersion)\n        {\n            return requestedVersion == currentVersion;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Versions/GrainVersionStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Storage;\nusing Orleans.Versions;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Threading;\n\nnamespace Orleans.Runtime.Versions\n{\n    internal class GrainVersionStore : IVersionStore, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly IServiceProvider services;\n        private readonly string clusterId;\n        private IVersionStoreGrain StoreGrain => this.grainFactory.GetGrain<IVersionStoreGrain>(this.clusterId);\n\n        public bool IsEnabled { get; private set; }\n\n        public GrainVersionStore(IInternalGrainFactory grainFactory, ILocalSiloDetails siloDetails, IServiceProvider services)\n        {\n            this.grainFactory = grainFactory;\n            this.services = services;\n            this.clusterId = siloDetails.ClusterId;\n            this.IsEnabled = false;\n        }\n\n        public async Task SetCompatibilityStrategy(CompatibilityStrategy strategy)\n        {\n            ThrowIfNotEnabled();\n            await StoreGrain.SetCompatibilityStrategy(strategy);\n        }\n\n        public async Task SetSelectorStrategy(VersionSelectorStrategy strategy)\n        {\n            ThrowIfNotEnabled();\n            await StoreGrain.SetSelectorStrategy(strategy);\n        }\n\n        public async Task SetCompatibilityStrategy(GrainInterfaceType interfaceType, CompatibilityStrategy strategy)\n        {\n            ThrowIfNotEnabled();\n            await StoreGrain.SetCompatibilityStrategy(interfaceType, strategy);\n        }\n\n        public async Task SetSelectorStrategy(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy)\n        {\n            ThrowIfNotEnabled();\n            await StoreGrain.SetSelectorStrategy(interfaceType, strategy);\n        }\n\n        public async Task<Dictionary<GrainInterfaceType, CompatibilityStrategy>> GetCompatibilityStrategies()\n        {\n            ThrowIfNotEnabled();\n            return await StoreGrain.GetCompatibilityStrategies();\n        }\n\n        public async Task<Dictionary<GrainInterfaceType, VersionSelectorStrategy>> GetSelectorStrategies()\n        {\n            ThrowIfNotEnabled();\n            return await StoreGrain.GetSelectorStrategies();\n        }\n\n        public async Task<CompatibilityStrategy> GetCompatibilityStrategy()\n        {\n            ThrowIfNotEnabled();\n            return await StoreGrain.GetCompatibilityStrategy();\n        }\n\n        public async Task<VersionSelectorStrategy> GetSelectorStrategy()\n        {\n            ThrowIfNotEnabled();\n            return await StoreGrain.GetSelectorStrategy();\n        }\n\n        private void ThrowIfNotEnabled()\n        {\n            if (!IsEnabled) ThrowDisabled();\n\n            static void ThrowDisabled() => throw new OrleansException(\"Version store not enabled, make sure the store is configured\");\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<GrainVersionStore>(ServiceLifecycleStage.ApplicationServices, this.OnStart);\n        }\n\n        private Task OnStart(CancellationToken token)\n        {\n            this.IsEnabled = this.services.GetService<IGrainStorage>() != null;\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Selector/AllCompatibleVersionsSelector.cs",
    "content": "using System.Linq;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions.Selector\n{\n    internal class AllCompatibleVersionsSelector : IVersionSelector\n    {\n        public ushort[] GetSuitableVersion(ushort requestedVersion, ushort[] availableVersions, ICompatibilityDirector compatibilityDirector)\n        {\n            return availableVersions.Where(v => compatibilityDirector.IsCompatible(requestedVersion, v)).ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Selector/LatestVersionDirector.cs",
    "content": "using System;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions.Selector\n{\n    internal sealed class LatestVersionSelector : IVersionSelector\n    {\n        public ushort[] GetSuitableVersion(ushort requestedVersion, ushort[] availableVersions, ICompatibilityDirector compatibilityDirector)\n        {\n            var max = int.MinValue;\n            foreach (var version in availableVersions)\n            {\n                if (compatibilityDirector.IsCompatible(requestedVersion, version) && version > max)\n                {\n                    max = version;\n                }\n            }\n\n            if (max < 0) return Array.Empty<ushort>();\n\n            return new[] { (ushort)max };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Selector/MinimumVersionSelector.cs",
    "content": "using System.Linq;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions.Selector\n{\n    internal sealed class MinimumVersionSelector : IVersionSelector\n    {\n        public ushort[] GetSuitableVersion(ushort requestedVersion, ushort[] availableVersions, ICompatibilityDirector compatibilityDirector)\n        {\n            return new[]\n            {\n                availableVersions.Where(v => compatibilityDirector.IsCompatible(requestedVersion, v)).Min()\n            };\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Versions/Selector/VersionDirectorManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions.Selector\n{\n    internal class VersionSelectorManager\n    {\n        private readonly VersionSelectorStrategy strategyFromConfig;\n        private readonly IServiceProvider serviceProvider;\n        private readonly Dictionary<GrainInterfaceType, IVersionSelector> versionSelectors;\n\n        public IVersionSelector Default { get; set; }\n\n        public VersionSelectorManager(IServiceProvider serviceProvider, IOptions<GrainVersioningOptions> options)\n        {\n            this.serviceProvider = serviceProvider;\n            this.strategyFromConfig = serviceProvider.GetRequiredKeyedService<VersionSelectorStrategy>(options.Value.DefaultVersionSelectorStrategy);\n            Default = ResolveVersionSelector(serviceProvider, this.strategyFromConfig);\n            versionSelectors = new Dictionary<GrainInterfaceType, IVersionSelector>();\n        }\n\n        public IVersionSelector GetSelector(GrainInterfaceType interfaceType)\n        {\n            IVersionSelector selector;\n            return this.versionSelectors.TryGetValue(interfaceType, out selector)\n                ? selector\n                : Default;\n        }\n\n        public void SetSelector(VersionSelectorStrategy strategy)\n        {\n            var selector = ResolveVersionSelector(this.serviceProvider, strategy ?? this.strategyFromConfig);\n            Default = selector;\n        }\n\n        public void SetSelector(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy)\n        {\n            if (strategy == null)\n            {\n                versionSelectors.Remove(interfaceType);\n            }\n            else\n            {\n                var selector = ResolveVersionSelector(this.serviceProvider, strategy);\n                versionSelectors[interfaceType] = selector;\n            }\n        }\n\n        private static IVersionSelector ResolveVersionSelector(IServiceProvider serviceProvider, VersionSelectorStrategy strategy)\n        {\n            var policyType = strategy.GetType();\n            return serviceProvider.GetRequiredKeyedService<IVersionSelector>(policyType);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Runtime/Versions/SingleWaiterAutoResetEvent.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Threading.Tasks.Sources;\n\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Represents a synchronization event that, when signaled, resets automatically after releasing a single waiter.\n    /// This type supports concurrent signalers but only a single waiter.\n    /// </summary>\n    internal sealed class SingleWaiterAutoResetEvent : IValueTaskSource\n    {\n        // Signaled indicates that the event has been signaled and not yet reset.\n        private const uint SignaledFlag = 1;\n\n        // Waiting indicates that a waiter is present and waiting for the event to be signaled.\n        private const uint WaitingFlag = 1 << 1;\n\n        // ResetMask is used to clear both status flags.\n        private const uint ResetMask = ~SignaledFlag & ~WaitingFlag;\n\n        private ManualResetValueTaskSourceCore<bool> _waitSource;\n        private volatile uint _status;\n\n        public bool RunContinuationsAsynchronously\n        {\n            get => _waitSource.RunContinuationsAsynchronously;\n            set => _waitSource.RunContinuationsAsynchronously = value;\n        }\n\n        ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) => _waitSource.GetStatus(token);\n\n        void IValueTaskSource.OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _waitSource.OnCompleted(continuation, state, token, flags);\n\n        void IValueTaskSource.GetResult(short token)\n        {\n            // Reset the wait source.\n            _waitSource.GetResult(token);\n            _waitSource.Reset();\n\n            // Reset the status.\n            ResetStatus();\n        }\n\n        /// <summary>\n        /// Signal the waiter.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Signal()\n        {\n            if ((_status & SignaledFlag) == SignaledFlag)\n            {\n                // The event is already signaled.\n                return;\n            }\n\n            // Set the signaled flag.\n            var status = Interlocked.Or(ref _status, SignaledFlag);\n\n            // If there was a waiter and the signaled flag was unset, wake the waiter now.\n            if ((status & SignaledFlag) != SignaledFlag && (status & WaitingFlag) == WaitingFlag)\n            {\n                // Note that in this assert we are checking the volatile _status field.\n                // This is a sanity check to ensure that the signaling conditions are true:\n                // that \"Signaled\" and \"Waiting\" flags are both set.\n                Debug.Assert((_status & (SignaledFlag | WaitingFlag)) == (SignaledFlag | WaitingFlag));\n                _waitSource.SetResult(true);\n            }\n        }\n\n        /// <summary>\n        /// Wait for the event to be signaled.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public ValueTask WaitAsync()\n        {\n            // Indicate that there is a waiter.\n            var status = Interlocked.Or(ref _status, WaitingFlag);\n\n            // If there was already a waiter, that is an error since this class is designed for use with a single waiter.\n            if ((status & WaitingFlag) == WaitingFlag)\n            {\n                ThrowConcurrentWaitersNotSupported();\n            }\n\n            // If the event was already signaled, immediately wake the waiter.\n            if ((status & SignaledFlag) == SignaledFlag)\n            {\n                // Reset just the status because the _waitSource has not been set.\n                // We know that _waitSource has not been set because _waitSource is only set when\n                // Signal() observes that the \"Waiting\" flag had been set but not the \"Signaled\" flag.\n                ResetStatus();\n                return default;\n            }\n\n            return new(this, _waitSource.Version);\n        }\n\n        /// <summary>\n        /// Called when a waiter handles the event signal.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private void ResetStatus()\n        {\n            // The event is being handled, so clear the \"Signaled\" flag now.\n            // The waiter is no longer waiting, so clear the \"Waiting\" flag, too.\n            var status = Interlocked.And(ref _status, ResetMask);\n\n            // If both the \"Waiting\" and \"Signaled\" flags were not already set, something has gone catastrophically wrong.\n            Debug.Assert((status & (WaitingFlag | SignaledFlag)) == (WaitingFlag | SignaledFlag));\n        }\n\n        private static void ThrowConcurrentWaitersNotSupported() => throw new InvalidOperationException(\"Concurrent waiters are not supported\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Runtime/Versions/VersionStoreGrain.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Providers;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\n\nnamespace Orleans.Runtime.Versions\n{\n    internal interface IVersionStoreGrain : IGrainWithStringKey\n    {\n        Task<Dictionary<GrainInterfaceType, CompatibilityStrategy>> GetCompatibilityStrategies();\n        Task<Dictionary<GrainInterfaceType, VersionSelectorStrategy>> GetSelectorStrategies();\n        Task<CompatibilityStrategy> GetCompatibilityStrategy();\n        Task<VersionSelectorStrategy> GetSelectorStrategy();\n        Task SetCompatibilityStrategy(CompatibilityStrategy strategy);\n        Task SetSelectorStrategy(VersionSelectorStrategy strategy);\n        Task SetCompatibilityStrategy(GrainInterfaceType interfaceType, CompatibilityStrategy strategy);\n        Task SetSelectorStrategy(GrainInterfaceType interfaceType, VersionSelectorStrategy strategy);\n    }\n\n    [GenerateSerializer]\n    internal sealed class VersionStoreGrainState\n    {\n        [Id(0)]\n        public readonly Dictionary<GrainInterfaceType, CompatibilityStrategy> CompatibilityStrategies = new();\n        [Id(1)]\n        public readonly Dictionary<GrainInterfaceType, VersionSelectorStrategy> VersionSelectorStrategies = new();\n        [Id(2)]\n        public VersionSelectorStrategy SelectorOverride;\n        [Id(3)]\n        public CompatibilityStrategy CompatibilityOverride;\n    }\n\n    [StorageProvider(ProviderName = ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME)]\n    internal class VersionStoreGrain : Grain<VersionStoreGrainState>, IVersionStoreGrain\n    {\n        public async Task SetCompatibilityStrategy(CompatibilityStrategy strategy)\n        {\n            this.State.CompatibilityOverride = strategy;\n            await this.WriteStateAsync();\n        }\n\n        public async Task SetSelectorStrategy(VersionSelectorStrategy strategy)\n        {\n            this.State.SelectorOverride = strategy;\n            await this.WriteStateAsync();\n        }\n\n        public async Task SetCompatibilityStrategy(GrainInterfaceType ifaceId, CompatibilityStrategy strategy)\n        {\n            this.State.CompatibilityStrategies[ifaceId] = strategy;\n            await this.WriteStateAsync();\n        }\n\n        public async Task SetSelectorStrategy(GrainInterfaceType ifaceId, VersionSelectorStrategy strategy)\n        {\n            this.State.VersionSelectorStrategies[ifaceId] = strategy;\n            await this.WriteStateAsync();\n        }\n\n        public bool IsEnabled { get; }\n\n        public Task<Dictionary<GrainInterfaceType, CompatibilityStrategy>> GetCompatibilityStrategies()\n        {\n            return Task.FromResult(this.State.CompatibilityStrategies);\n        }\n\n        public Task<Dictionary<GrainInterfaceType, VersionSelectorStrategy>> GetSelectorStrategies()\n        {\n            return Task.FromResult(this.State.VersionSelectorStrategies);\n        }\n\n        public Task<CompatibilityStrategy> GetCompatibilityStrategy()\n        {\n            return Task.FromResult(this.State.CompatibilityOverride);\n        }\n\n        public Task<VersionSelectorStrategy> GetSelectorStrategy()\n        {\n            return Task.FromResult(this.State.SelectorOverride);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Sdk/Orleans.Sdk.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Sdk</PackageId>\n    <Description>Microsoft Orleans meta package to bring in the base Orleans packages for all project types.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <NoPackageAnalysis>true</NoPackageAnalysis>\n    <IncludeSymbols>false</IncludeSymbols>\n    <IncludeSource>false</IncludeSource>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <NoWarn>MSB3277</NoWarn>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\"buildTransitive\\Microsoft.Orleans.Sdk.targets\">\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n      <Pack>true</Pack>\n    </Content>\n    <Content Include=\"build\\Microsoft.Orleans.Sdk.targets\">\n      <Pack>true</Pack>\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n    </Content>\n    <Content Include=\"buildMultiTargeting\\Microsoft.Orleans.Sdk.targets\">\n      <Pack>true</Pack>\n      <PackagePath>%(Identity)</PackagePath>\n      <Visible>true</Visible>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Analyzers\\Orleans.Analyzers.csproj\" PrivateAssets=\"None\" />\n    <ProjectReference Include=\"..\\Orleans.CodeGenerator\\Orleans.CodeGenerator.csproj\" PrivateAssets=\"None\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Sdk/README.md",
    "content": "# Microsoft Orleans SDK\n\n## Introduction\nMicrosoft Orleans SDK is a metapackage that includes all the necessary components to build Orleans applications. It provides both client and server functionality, making it easy to get started with Orleans without having to reference individual packages.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Sdk\n```\n\n## Example - Creating a Grain Interface and Implementation\n\n```csharp\n// Define a grain interface\npublic interface IHelloGrain : IGrainWithStringKey\n{\n    Task<string> SayHello(string greeting);\n}\n\n// Implement the grain interface\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"Hello, {greeting}!\");\n    }\n}\n```\n\n## Example - Configuring an Orleans Application\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\nnamespace ExampleGrains;\n\n// Create the host\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering();\n    });\n\n// Start the host\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"World\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Getting started with Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/tutorials-and-samples/tutorial-1)\n- [Grains](https://learn.microsoft.com/en-us/dotnet/orleans/grains/)\n- [Hosting Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/host/)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Sdk/build/Microsoft.Orleans.Sdk.targets",
    "content": "<Project>\n\n  <ItemGroup Condition=\"'$(ImplicitUsings)' == 'enable' or '$(ImplicitUsings)' == 'true'\">\n    <Using Include=\"Orleans\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Sdk/buildMultiTargeting/Microsoft.Orleans.Sdk.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Sdk.targets\" />\n</Project>"
  },
  {
    "path": "src/Orleans.Sdk/buildTransitive/Microsoft.Orleans.Sdk.targets",
    "content": "<Project>\n  <Import Project=\"..\\build\\Microsoft.Orleans.Sdk.targets\" />\n</Project>"
  },
  {
    "path": "src/Orleans.Serialization/Activators/DefaultActivator.cs",
    "content": "using System;\nusing System.Reflection.Emit;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Activators\n{\n    internal abstract class DefaultActivator<T> : IActivator<T>\n    {\n        private static readonly Func<T> DefaultConstructorFunction = Init();\n        protected readonly Func<T> Constructor = DefaultConstructorFunction;\n        protected readonly Type Type = typeof(T);\n\n        private static Func<T> Init()\n        {\n            var ctor = typeof(T).GetConstructor(Type.EmptyTypes);\n            if (ctor is null)\n                return null;\n\n            var method = new DynamicMethod(nameof(DefaultActivator<T>), typeof(T), new[] { typeof(object) });\n            var il = method.GetILGenerator();\n            il.Emit(OpCodes.Newobj, ctor);\n            il.Emit(OpCodes.Ret);\n            return (Func<T>)method.CreateDelegate(typeof(Func<T>));\n        }\n\n        public abstract T Create();\n    }\n\n    internal sealed class DefaultReferenceTypeActivator<T> : DefaultActivator<T> where T : class\n    {\n        public override T Create()\n            => Constructor is { } ctor\n                ? ctor()\n                : Unsafe.As<T>(RuntimeHelpers.GetUninitializedObject(Type));\n    }\n\n    internal sealed class DefaultValueTypeActivator<T> : DefaultActivator<T> where T : struct\n    {\n        public override T Create()\n            => Constructor is { } ctor\n                ? ctor()\n                : (T)RuntimeHelpers.GetUninitializedObject(Type);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Activators/IActivator.cs",
    "content": "\nnamespace Orleans.Serialization.Activators\n{\n    /// <summary>\n    /// Functionality for creating object instances.\n    /// </summary>\n    /// <typeparam name=\"T\">The instance type which this implementation creates.</typeparam>\n    public interface IActivator<T>\n    {\n        /// <summary>\n        /// Creates an instance of type <typeparamref name=\"T\"/>.\n        /// </summary>\n        /// <returns>An instance of type <typeparamref name=\"T\"/>.</returns>\n        T Create();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/ArrayStreamBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.IO;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// An implementation of <see cref=\"IBufferWriter{T}\"/> which writes to a <see cref=\"Stream\"/>, using an array as an intermediate buffer.\n    /// </summary>\n    public struct ArrayStreamBufferWriter : IBufferWriter<byte>\n    {\n        public const int DefaultInitialBufferSize = 256;\n        private readonly Stream _stream;\n        private byte[] _buffer;\n        private int _index;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArrayStreamBufferWriter\"/> struct.\n        /// </summary>\n        /// <param name=\"stream\">The stream.</param>\n        /// <param name=\"sizeHint\">The size hint.</param>\n        public ArrayStreamBufferWriter(Stream stream, int sizeHint = 0)\n        {\n            if (sizeHint == 0)\n            {\n                sizeHint = DefaultInitialBufferSize;\n            }\n\n            _stream = stream;\n            _buffer = new byte[sizeHint];\n            _index = 0;\n        }\n\n        /// <inheritdoc />\n        public void Advance(int count)\n        {\n            if (count < 0)\n            {\n                ThrowNegativeAdvanceCount();\n                return;\n            }\n\n            if (_index > _buffer.Length - count)\n            {\n                ThrowAdvancePastCapacity();\n                return;\n            }\n\n            _index += count;\n            _stream.Write(_buffer, 0, _index);\n            _index = 0;\n        }\n\n        /// <inheritdoc />\n        public Memory<byte> GetMemory(int sizeHint = 0)\n        {\n            CheckAndResizeBuffer(sizeHint);\n            return _buffer.AsMemory(_index);\n        }\n\n        /// <inheritdoc />\n        public Span<byte> GetSpan(int sizeHint = 0)\n        {\n            CheckAndResizeBuffer(sizeHint);\n            return _buffer.AsSpan(_index);\n        }\n\n        private void CheckAndResizeBuffer(int sizeHint)\n        {\n            if (sizeHint < 0)\n            {\n                ThrowNegativeSizeHint();\n                return;\n            }\n\n            if (sizeHint == 0)\n            {\n                sizeHint = 1;\n            }\n\n            if (sizeHint > _buffer.Length - _index)\n            {\n                int growBy = Math.Max(sizeHint, _buffer.Length);\n\n                if (_buffer.Length == 0)\n                {\n                    growBy = Math.Max(growBy, DefaultInitialBufferSize);\n                }\n\n                int newSize = checked(_buffer.Length + growBy);\n\n                Array.Resize(ref _buffer, newSize);\n            }\n        }\n\n        private static void ThrowNegativeSizeHint() => throw new ArgumentException(\"Negative values are not supported\", \"sizeHint\");\n\n        private static void ThrowNegativeAdvanceCount() => throw new ArgumentException(\"Negative values are not supported\", \"count\");\n\n        private static void ThrowAdvancePastCapacity() => throw new InvalidOperationException(\"Cannod advance past the end of the current capacity\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/BufferSliceReaderInput.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing static Orleans.Serialization.Buffers.PooledBuffer;\n\nnamespace Orleans.Serialization.Buffers.Adaptors;\n\n/// <summary>\n/// Input type for <see cref=\"Reader{TInput}\"/> to support <see cref=\"BufferSlice\"/> buffers.\n/// </summary>\npublic struct BufferSliceReaderInput\n{\n    private static readonly SequenceSegment InitialSegmentSentinel = new();\n    private static readonly SequenceSegment FinalSegmentSentinel = new();\n    private readonly BufferSlice _slice;\n    private SequenceSegment _segment;\n    private int _position;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"BufferSliceReaderInput\"/> type.\n    /// </summary>\n    /// <param name=\"slice\">The underlying buffer.</param>\n    public BufferSliceReaderInput(in BufferSlice slice)\n    {\n        _slice = slice;\n        _segment = InitialSegmentSentinel;\n    }\n\n    internal readonly PooledBuffer Buffer => _slice._buffer;\n    internal readonly int Position => _position;\n    internal readonly int Offset => _slice._offset;\n    internal readonly int Length => _slice._length;\n    internal long PreviousBuffersSize;\n\n    internal readonly BufferSliceReaderInput ForkFrom(int position)\n    {\n        var sliced = _slice.Slice(position);\n        return new BufferSliceReaderInput(in sliced);\n    }\n\n    internal ReadOnlySpan<byte> GetNext()\n    {\n        if (ReferenceEquals(_segment, InitialSegmentSentinel))\n        {\n            _segment = _slice._buffer.First;\n        }\n\n        var endPosition = Offset + Length;\n        while (_segment != null && _segment != FinalSegmentSentinel)\n        {\n            var segment = _segment.CommittedMemory.Span;\n\n            // Find the starting segment and the offset to copy from.\n            int segmentOffset;\n            if (_position < Offset)\n            {\n                if (_position + segment.Length <= Offset)\n                {\n                    // Start is in a subsequent segment\n                    _position += segment.Length;\n                    _segment = _segment.Next as SequenceSegment;\n                    continue;\n                }\n                else\n                {\n                    // Start is in this segment\n                    segmentOffset = Offset - _position;\n                }\n            }\n            else\n            {\n                segmentOffset = 0;\n            }\n\n            var segmentLength = Math.Min(segment.Length - segmentOffset, endPosition - (_position + segmentOffset));\n            if (segmentLength == 0)\n            {\n                ThrowInsufficientData();\n                return default;\n            }\n\n            var result = segment.Slice(segmentOffset, segmentLength);\n            _position += segmentOffset + segmentLength;\n            _segment = _segment.Next as SequenceSegment;\n            return result;\n        }\n\n        if (_segment != FinalSegmentSentinel && Buffer.CurrentPosition > 0 && Buffer.WriteHead is { } head && _position < endPosition)\n        {\n            var finalOffset = Math.Max(Offset - _position, 0);\n            var finalLength = Math.Min(Buffer.CurrentPosition, endPosition - (_position + finalOffset));\n            if (finalLength == 0)\n            {\n                ThrowInsufficientData();\n                return default;\n            }\n\n            var result = head.Array.AsSpan(finalOffset, finalLength);\n            _position += finalOffset + finalLength;\n            Debug.Assert(_position == endPosition);\n            _segment = FinalSegmentSentinel;\n            return result;\n        }\n\n        ThrowInsufficientData();\n        return default;\n    }\n\n    [DoesNotReturn]\n    private static void ThrowInsufficientData() => throw new InvalidOperationException(\"Insufficient data present in buffer.\");\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/BufferWriterBox.cs",
    "content": "using System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// A <see cref=\"IBufferWriter{T}\"/> implementation which boxes another buffer writer.\n    /// </summary>\n    public class BufferWriterBox<TBufferWriter> : IBufferWriter<byte> where TBufferWriter : struct, IBufferWriter<byte>\n    {\n        private TBufferWriter _bufferWriter;\n\n        public BufferWriterBox(TBufferWriter bufferWriter)\n        {\n            _bufferWriter = bufferWriter;\n        }\n\n        /// <summary>\n        /// Gets a reference to the underlying buffer writer.\n        /// </summary>\n        public ref TBufferWriter Value => ref _bufferWriter;\n\n        /// <inheritdoc/>\n        public void Advance(int count) => _bufferWriter.Advance(count);\n\n        /// <inheritdoc/>\n        public Memory<byte> GetMemory(int sizeHint = 0) => _bufferWriter.GetMemory(sizeHint);\n\n        /// <inheritdoc/>\n        public Span<byte> GetSpan(int sizeHint = 0) => _bufferWriter.GetSpan(sizeHint);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/BufferWriterExtensions.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Buffers.Adaptors;\n\ninternal static class BufferWriterExtensions\n{\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void Write<TBufferWriter>(ref TBufferWriter writer, ReadOnlySpan<byte> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        var destination = writer.GetSpan();\n\n        // Fast path, try copying to the available memory directly\n        if (value.Length <= destination.Length)\n        {\n            value.CopyTo(destination);\n            writer.Advance(value.Length);\n        }\n        else\n        {\n            WriteMultiSegment(ref writer, value, destination);\n        }\n    }\n\n    private static void WriteMultiSegment<TBufferWriter>(ref TBufferWriter writer, in ReadOnlySpan<byte> source, Span<byte> destination) where TBufferWriter : IBufferWriter<byte>\n    {\n        var input = source;\n        while (true)\n        {\n            var writeSize = Math.Min(destination.Length, input.Length);\n            input[..writeSize].CopyTo(destination);\n            writer.Advance(writeSize);\n            input = input[writeSize..];\n            if (input.Length > 0)\n            {\n                destination = writer.GetSpan();\n\n                continue;\n            }\n\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/MemoryBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// A <see cref=\"IBufferWriter{T}\"/> implementation for <see cref=\"Memory{T}\"/>\n    /// </summary>\n    public struct MemoryBufferWriter : IBufferWriter<byte>\n    {\n        private readonly Memory<byte> _buffer;\n        private int _bytesWritten;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryBufferWriter\"/> struct.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        internal MemoryBufferWriter(Memory<byte> buffer)\n        {\n            _buffer = buffer;\n            _bytesWritten = 0;\n        }\n\n        /// <summary>\n        /// Gets the number of bytes written.\n        /// </summary>\n        /// <value>The number of bytes written.</value>\n        public readonly int BytesWritten => _bytesWritten;\n\n        /// <inheritdoc />\n        public void Advance(int count)\n        {\n            if (_bytesWritten > _buffer.Length)\n            {\n                ThrowInvalidCount();\n\n                static void ThrowInvalidCount() => throw new InvalidOperationException(\"Cannot advance past the end of the buffer\");\n            }\n\n            _bytesWritten += count;\n        }\n\n        /// <inheritdoc />\n        public Memory<byte> GetMemory(int sizeHint = 0)\n        {\n            if (_bytesWritten + sizeHint >= _buffer.Length)\n            {\n                ThrowInsufficientCapacity(sizeHint);\n            }\n\n            return _buffer[_bytesWritten..];\n        }\n\n        /// <inheritdoc />\n        public Span<byte> GetSpan(int sizeHint = 0)\n        {\n            if (_bytesWritten + sizeHint >= _buffer.Length)\n            {\n                ThrowInsufficientCapacity(sizeHint);\n            }\n\n            return _buffer.Span[_bytesWritten..];\n        }\n\n        private void ThrowInsufficientCapacity(int sizeHint) => throw new InvalidOperationException($\"Insufficient capacity to perform the requested operation. Buffer size is {_buffer.Length}. Current length is {_bytesWritten} and requested size increase is {sizeHint}\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/MemoryStreamBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.IO;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// An implementation of <see cref=\"IBufferWriter{T}\"/> which writes to a <see cref=\"MemoryStream\"/>.\n    /// </summary>\n    public readonly struct MemoryStreamBufferWriter : IBufferWriter<byte>\n    {\n        private readonly MemoryStream _stream;\n        private const int MinRequestSize = 256;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryStreamBufferWriter\"/> struct.\n        /// </summary>\n        /// <param name=\"stream\">The stream.</param>\n        public MemoryStreamBufferWriter(MemoryStream stream)\n        {\n            _stream = stream;\n        }\n\n        /// <inheritdoc />\n        public void Advance(int count)\n        {\n            _stream.Position += count;\n        }\n\n        /// <inheritdoc />\n        public Memory<byte> GetMemory(int sizeHint = 0)\n        {\n            if (sizeHint < MinRequestSize)\n            {\n                sizeHint = MinRequestSize;\n            }\n\n            if (_stream.Capacity - _stream.Position < sizeHint)\n            {\n                _stream.Capacity += sizeHint;\n                _stream.SetLength(_stream.Capacity);\n            }\n\n            return _stream.GetBuffer().AsMemory((int)_stream.Position);\n        }\n\n        /// <inheritdoc />\n        public Span<byte> GetSpan(int sizeHint = 0)\n        {\n            if (sizeHint < MinRequestSize)\n            {\n                sizeHint = MinRequestSize;\n            }\n\n            if (_stream.Capacity - _stream.Position < sizeHint)\n            {\n                _stream.Capacity += sizeHint;\n                _stream.SetLength(_stream.Capacity);\n            }\n\n            return _stream.GetBuffer().AsSpan((int)_stream.Position);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/PooledBufferStream.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.IO;\nusing Microsoft.Extensions.ObjectPool;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// A <see cref=\"IBufferWriter{T}\"/> implementation which boxes another buffer writer.\n    /// </summary>\n    public sealed class PooledBufferStream : Stream\n    {\n        private static readonly ObjectPool<PooledBufferStream> StreamPool = ObjectPool.Create(new PooledStreamPolicy());\n        private static readonly ArrayPool<byte> Pool = ArrayPool<byte>.Shared;\n        private readonly List<byte[]> _segments;\n        private readonly int _minAllocationSize;\n        private long _length;\n        private long _capacity;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PooledBufferStream\"/> class.\n        /// </summary>\n        public PooledBufferStream() : this(0)\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PooledBufferStream\"/> class.\n        /// </summary>\n        /// <param name=\"minAllocationSize\">Minimum size of the allocation.</param>\n        public PooledBufferStream(int minAllocationSize = 0)\n        {\n            _segments = new();\n            _length = 0;\n            _minAllocationSize = minAllocationSize > 0 ? minAllocationSize : 4096;\n        }\n\n        /// <summary>\n        /// Gets an object from the pool if one is available, otherwise creates one.\n        /// </summary>\n        /// <returns>A <see cref=\"PooledBufferStream\"/>.</returns>\n        public static PooledBufferStream Rent() => StreamPool.Get();\n\n        /// <summary>\n        /// Return an object to the pool.\n        /// </summary>\n        public static void Return(PooledBufferStream stream)\n        {\n#if NET5_0_OR_GREATER\n            ArgumentNullException.ThrowIfNull(stream);\n#else\n            if (stream is null)\n            {\n                throw new ArgumentNullException(nameof(stream));\n            }\n#endif\n            StreamPool.Return(stream);\n        }\n\n        /// <summary>Gets the total length which has been written.</summary>\n        public override long Length => _length;\n\n        /// <summary>\n        /// Returns the data which has been written as an array.\n        /// </summary>\n        /// <returns>The data which has been written.</returns>\n        public byte[] ToArray()\n        {\n            var result = new byte[_length];\n            var resultSpan = result.AsSpan();\n            var remaining = _length;\n            foreach (var buffer in _segments)\n            {\n                var copyLength = (int)Math.Min(buffer.Length, remaining);\n                buffer.AsSpan(0, copyLength).CopyTo(resultSpan);\n                resultSpan = resultSpan[copyLength..];\n                remaining -= copyLength;\n            }\n\n            return result;\n        }\n\n        /// <summary>Copies the contents of this writer to another writer.</summary>\n        public void CopyTo<TBufferWriter>(ref Writer<TBufferWriter> writer) where TBufferWriter : IBufferWriter<byte>\n        {\n            var remaining = _length;\n            foreach (var buffer in _segments)\n            {\n                var copyLength = (int)Math.Min(buffer.Length, remaining);\n                writer.Write(buffer.AsSpan(0, copyLength));\n                remaining -= copyLength;\n            }\n        }\n\n        public void Reset()\n        {\n            foreach (var buffer in _segments)\n            {\n                Pool.Return(buffer);\n            }\n\n            _segments.Clear();\n            _length = 0;\n            _capacity = 0;\n            Position = 0;\n        }\n\n        /// <summary>\n        /// Returns a new <see cref=\"ReadOnlySequence{T}\"/> which must be used and returned before resetting this instance via the <see cref=\"ReturnReadOnlySequence\"/> method.\n        /// </summary>\n        public ReadOnlySequence<byte> RentReadOnlySequence()\n        {\n            if (_length == 0)\n            {\n                return ReadOnlySequence<byte>.Empty;\n            }\n\n            if (_segments.Count == 1)\n            {\n                var buffer = _segments[0];\n                return new ReadOnlySequence<byte>(buffer, 0, (int)Math.Min(buffer.Length, _length));\n            }\n\n            var runningIndex = 0L;\n            var firstSegment = default(BufferSegment);\n            var previousSegment = default(BufferSegment);\n            var remaining = _length;\n            foreach (var buffer in _segments)\n            {\n                var segment = BufferSegment.Pool.Get();\n                var segmentLength = Math.Min(buffer.Length, remaining);\n\n                segment.Initialize(new ReadOnlyMemory<byte>(buffer, 0, (int)segmentLength), runningIndex);\n\n                runningIndex += segmentLength;\n                remaining -= segmentLength;\n\n                previousSegment?.SetNext(segment);\n\n                firstSegment ??= segment;\n                previousSegment = segment;\n            }\n\n            return new ReadOnlySequence<byte>(firstSegment, 0, previousSegment, previousSegment.Memory.Length);\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"ReadOnlySequence{T}\"/> previously rented by <see cref=\"RentReadOnlySequence\"/>;\n        /// </summary>\n        public void ReturnReadOnlySequence(in ReadOnlySequence<byte> sequence)\n        {\n            if (sequence.Start.GetObject() is not BufferSegment segment)\n            {\n                return;\n            }\n\n            while (segment is not null)\n            {\n                var next = segment.Next as BufferSegment;\n                BufferSegment.Pool.Return(segment);\n                segment = next;\n            }\n        }\n\n        public override bool CanRead => true;\n\n        public override bool CanSeek => true;\n\n        public override bool CanWrite => true;\n\n        public override long Position { get; set; }\n\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            var newPosition = origin switch\n            {\n                SeekOrigin.Begin => offset,\n                SeekOrigin.Current => Position + offset,\n                SeekOrigin.End => Length - offset,\n                _ => throw new ArgumentOutOfRangeException(nameof(origin))\n            };\n\n            if (newPosition < 0) throw new InvalidOperationException(\"Attempted to seek past beginning of stream\");\n            if (newPosition > Length) throw new InvalidOperationException(\"Attempted to seek past end of stream\");\n\n            Position = newPosition;\n\n            return newPosition;\n        }\n\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n#if NET5_0_OR_GREATER\n            ArgumentNullException.ThrowIfNull(buffer);\n#else\n            if (buffer is null)\n            {\n                throw new ArgumentNullException(nameof(buffer));\n            }\n#endif\n            var destination = buffer.AsSpan(offset, count);\n            FindCurrentSegment(out var segmentIndex, out var indexIntoSegment);\n            if (segmentIndex < 0)\n            {\n                return 0;\n            }\n\n            var totalRead = 0;\n            var remaining = (int)Math.Min(count, _length - Position);\n\n            while (remaining > 0 && segmentIndex < _segments.Count)\n            {\n                var segment = _segments[segmentIndex];\n                var readLength = Math.Min(remaining, Math.Min(segment.Length - indexIntoSegment, destination.Length));\n                segment.AsSpan(indexIntoSegment, readLength).CopyTo(destination);\n\n                destination = destination[readLength..];\n                remaining -= readLength;\n                totalRead += readLength;\n\n                ++segmentIndex;\n                indexIntoSegment = 0;\n            }\n\n            Position += totalRead;\n            return totalRead;\n        }\n\n        public override void SetLength(long value)\n        {\n            if (value == Length)\n            {\n                // Do nothing\n                return;\n            }\n            else if (value == 0)\n            {\n                Reset();\n            }\n            else\n            {\n                if (value < Length)\n                {\n                    // Truncate/remove already-written buffers\n                    var excess = Length - value;\n                    while (excess > 0)\n                    {\n                        var lastSegment = _segments[^1];\n                        if (excess >= lastSegment.Length)\n                        {\n                            // Remove the entire segment.\n                            excess -= lastSegment.Length;\n                            _segments.RemoveAt(_segments.Count - 1);\n                            _capacity -= lastSegment.Length;\n                            Pool.Return(lastSegment);\n                        }\n                        else\n                        {\n                            // Partially truncate the last segment - we don't need to do anything \n                            // since we're just reducing the logical length, not the physical buffer\n                            break;\n                        }\n                    }\n                }\n                else\n                {\n                    // Append empty buffers\n                    var deficit = value - Length;\n                    while (deficit > 0)\n                    {\n                        var array = Grow();\n                        var length = Math.Min(deficit, array.Length);\n                        deficit -= length;\n                    }\n                }\n\n                _length = value;\n                Position = Math.Min(Position, Length);\n            }\n        }\n\n        private byte[] Grow()\n        {\n            var array = Pool.Rent(_minAllocationSize);\n            _segments.Add(array);\n            _capacity += array.Length;\n            return array;\n        }\n\n        public override void Write(byte[] buffer, int offset, int count)\n        {\n#if NET5_0_OR_GREATER\n            ArgumentNullException.ThrowIfNull(buffer);\n#else\n            if (buffer is null)\n            {\n                throw new ArgumentNullException(nameof(buffer));\n            }\n#endif\n            var data = new ReadOnlyMemory<byte>(buffer, offset, count);\n\n            if (Position < Length)\n            {\n                FindCurrentSegment(out var segmentIndex, out var indexIntoSegment);\n\n                while (Position < Length && data.Length > 0)\n                {\n                    var writeHead = _segments[segmentIndex].AsMemory(indexIntoSegment);\n                    var writeLength = Math.Min(writeHead.Length, data.Length);\n\n                    // Copy the data and update the input\n                    data[..writeLength].CopyTo(writeHead);\n                    data = data[writeLength..];\n\n                    // Update the cursor\n                    Position += writeLength;\n\n                    // Advance to the next segment;\n                    ++segmentIndex;\n                    indexIntoSegment = 0;\n                }\n            }\n\n            // Append any remaining data.\n            Append(ref data);\n        }\n\n        private void FindCurrentSegment(out int segmentIndex, out int indexIntoSegment)\n        {\n            segmentIndex = -1;\n            indexIntoSegment = -1;\n            var segmentStartPos = 0;\n            for (var i = 0; i < _segments.Count; i++)\n            {\n                var currentSegment = _segments[i];\n\n                // Check if this segment contains the current position.\n                if (segmentStartPos + currentSegment.Length > Position)\n                {\n                    segmentIndex = i;\n                    indexIntoSegment = (int)(Position - segmentStartPos);\n                    break;\n                }\n\n                segmentStartPos += currentSegment.Length;\n            }\n        }\n\n        private void Append(ref ReadOnlyMemory<byte> data)\n        {\n            while (data.Length > 0)\n            {\n                if (_length == _capacity)\n                {\n                    Grow();\n                }\n\n                var writeHead = GetWriteHead();\n                var writeLength = Math.Min(writeHead.Length, data.Length);\n                data[..writeLength].CopyTo(writeHead);\n                data = data[writeLength..];\n                _length += writeLength;\n            }\n\n            Position = _length;\n        }\n\n        public override void Flush() { }\n\n        private Memory<byte> GetWriteHead() => _segments[^1].AsMemory((int)(_segments[^1].Length - (_capacity - _length)));\n\n        private sealed class PooledStreamPolicy : PooledObjectPolicy<PooledBufferStream>\n        {\n            public override PooledBufferStream Create() => new();\n            public override bool Return(PooledBufferStream obj)\n            {\n                obj.Reset();\n                return true;\n            }\n        }\n\n        // Internal for testing purposes only.\n        internal sealed class BufferSegment : ReadOnlySequenceSegment<byte>\n        {\n            public static readonly ObjectPool<BufferSegment> Pool = ObjectPool.Create(new SegmentPoolPolicy());\n\n            public void Initialize(ReadOnlyMemory<byte> memory, long runningIndex)\n            {\n                Memory = memory;\n                RunningIndex = runningIndex;\n            }\n\n            public void SetNext(BufferSegment next) => Next = next;\n\n            public void Reset()\n            {\n                Memory = default;\n                RunningIndex = default;\n                Next = default;\n            }\n\n            private sealed class SegmentPoolPolicy : PooledObjectPolicy<BufferSegment>\n            {\n                public override BufferSegment Create() => new();\n\n                public override bool Return(BufferSegment obj)\n                {\n                    obj.Reset();\n                    return true;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/PoolingStreamBufferWriter.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// An implementation of <see cref=\"IBufferWriter{T}\"/> for writing to a <see cref=\"Stream\"/>, using pooled arrays as an intermediate buffer.\n    /// </summary>\n    public struct PoolingStreamBufferWriter : IBufferWriter<byte>, IDisposable\n    {\n        private readonly Stream _stream;\n        private byte[] _buffer;\n        private const int MinRequestSize = 256;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PoolingStreamBufferWriter\"/> struct.\n        /// </summary>\n        /// <param name=\"stream\">The stream.</param>\n        /// <param name=\"sizeHint\">The size hint.</param>\n        internal PoolingStreamBufferWriter(Stream stream, int sizeHint)\n        {\n            _stream = stream;\n            _buffer = ArrayPool<byte>.Shared.Rent(Math.Max(sizeHint, MinRequestSize));\n        }\n\n        /// <inheritdoc />\n        public void Advance(int count) => _stream.Write(_buffer, 0, count);\n\n        /// <inheritdoc />\n        public Memory<byte> GetMemory(int sizeHint = 0) => sizeHint <= _buffer.Length ? _buffer : Resize(sizeHint);\n\n        /// <inheritdoc />\n        public Span<byte> GetSpan(int sizeHint = 0) => sizeHint <= _buffer.Length ? _buffer : Resize(sizeHint);\n\n        private byte[] Resize(int sizeHint)\n        {\n            var newBuffer = ArrayPool<byte>.Shared.Rent(sizeHint);\n            ArrayPool<byte>.Shared.Return(_buffer);\n            return _buffer = newBuffer;\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            if (_buffer is { } buf)\n            {\n                _buffer = null;\n                ArrayPool<byte>.Shared.Return(buf);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Adaptors/SpanBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    /// <summary>\n    /// A special-purpose <see cref=\"IBufferWriter{T}\"/> implementation for supporting <see cref=\"Span{T}\"/> in <see cref=\"Writer{TBufferWriter}\"/>.\n    /// </summary>\n    public struct SpanBufferWriter : IBufferWriter<byte>\n    {\n        private readonly int _maxLength;\n        private int _bytesWritten;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SpanBufferWriter\"/> struct.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        internal SpanBufferWriter(Span<byte> buffer)\n        {\n            _maxLength = buffer.Length;\n            _bytesWritten = 0;\n        }\n\n        /// <summary>\n        /// Gets the number of bytes written.\n        /// </summary>\n        /// <value>The number of bytes written.</value>\n        public readonly int BytesWritten => _bytesWritten;\n\n        /// <inheritdoc />\n        public void Advance(int count) => _bytesWritten += count;\n\n        /// <inheritdoc />\n        public readonly Memory<byte> GetMemory(int sizeHint = 0) => throw GetException(sizeHint);\n\n        /// <inheritdoc />\n        public readonly Span<byte> GetSpan(int sizeHint = 0) => throw GetException(sizeHint);\n\n        private readonly Exception GetException(int sizeHint)\n        {\n            return _bytesWritten + sizeHint > _maxLength\n                ? new InvalidOperationException($\"Insufficient capacity to perform the requested operation. Buffer size is {_maxLength}. Current length is {_bytesWritten} and requested size increase is {sizeHint}\")\n                : new NotSupportedException(\"Method is not supported on this instance\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/ArcBufferWriter.cs",
    "content": "#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Collections.Generic;\nusing System.Collections;\n\n#if NET6_0_OR_GREATER\nusing System.Numerics;\n#else\nusing Orleans.Serialization.Utilities;\n#endif\n\nnamespace Orleans.Serialization.Buffers;\n\n/// <summary>\n/// A <see cref=\"IBufferWriter{T}\"/> implementation implemented using pooled arrays which is specialized for creating <see cref=\"ReadOnlySequence{T}\"/> instances.\n/// </summary>\n[StructLayout(LayoutKind.Auto)]\n[Immutable]\npublic sealed class ArcBufferWriter : IBufferWriter<byte>, IDisposable\n{\n    // The first page. This is the page which consumers will consume from.\n    // This may be equal to the current page, or it may be a previous page.\n    private ArcBufferPage _readPage;\n\n    // The current page. This is the page which will be written to when the next write occurs.\n    private ArcBufferPage _writePage;\n\n    // The current page. This is the last page which was allocated. In the linked list formed by the pages, _first <= _current <= _tail.\n    private ArcBufferPage _tail;\n\n    // The offset into the first page which has been consumed already. When this reaches the end of the page, the page can be unpinned.\n    private int _readIndex;\n\n    // The total length of the buffer.\n    private int _totalLength;\n\n    // Indicates whether the writer has been disposed.\n    private bool _disposed;\n\n    /// <summary>\n    /// Gets the minimum page size.\n    /// </summary>\n    public const int MinimumPageSize = ArcBufferPagePool.MinimumPageSize;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ArcBufferWriter\"/> struct.\n    /// </summary>\n    public ArcBufferWriter()\n    {\n        _readPage = _writePage = _tail = ArcBufferPagePool.Shared.Rent();\n        Debug.Assert(_readPage.ReferenceCount == 0);\n        _readPage.Pin(_readPage.Version);\n    }\n\n    /// <summary>\n    /// Gets the number of unconsumed bytes.\n    /// </summary>\n    public int Length\n    {\n        get\n        {\n            ThrowIfDisposed();\n            return _totalLength - _readIndex;\n        }\n    }\n\n    /// <summary>\n    /// Adds additional buffers to the destination list until the list has reached its capacity.\n    /// </summary>\n    /// <param name=\"buffers\">The destination to add buffers to.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void ReplenishBuffers(List<ArraySegment<byte>> buffers)\n    {\n        ThrowIfDisposed();\n\n        // Skip half-full pages in an attempt to minimize the number of buffers added to the destination\n        // at the expense of under-utilized memory. This could be tweaked up to increase page utilization.\n        const int MinimumUsablePageSize = MinimumPageSize / 2;\n\n        while (buffers.Count < buffers.Capacity)\n        {\n            // Only use the current page if it is greater than the minimum \"usable\" page size.\n            if (_tail.WriteCapacity > MinimumUsablePageSize)\n            {\n                buffers.Add(_tail.WritableArraySegment);\n            }\n\n            // Allocate a new page.\n            AllocatePage(0);\n        }\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    void IBufferWriter<byte>.Advance(int count) => AdvanceWriter(count);\n\n    /// <summary>\n    /// Advances the writer by the specified number of bytes.\n    /// </summary>\n    /// <param name=\"count\">The numbers of bytes to advance the writer by.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void AdvanceWriter(int count)\n    {\n        ThrowIfDisposed();\n\n#if NET5_0_OR_GREATER\n        ArgumentOutOfRangeException.ThrowIfLessThan(count, 0);\n#else\n        if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), \"Length must be greater than or equal to 0.\");\n#endif\n        _totalLength += count;\n        while (true)\n        {\n            var amount = Math.Min(_writePage.WriteCapacity, count);\n            _writePage.Advance(amount);\n            count -= amount;\n\n            if (count == 0)\n            {\n                break;\n            }\n\n            var next = _writePage.Next;\n            Debug.Assert(next is not null);\n            _writePage = next;\n        }\n    }\n\n    /// <summary>\n    /// Resets this instance, returning all memory.\n    /// </summary>\n    public void Reset()\n    {\n        ThrowIfDisposed();\n\n        UnpinAll();\n        _totalLength = _readIndex = 0;\n        _readPage = _writePage = _tail = ArcBufferPagePool.Shared.Rent();\n        Debug.Assert(_readPage.ReferenceCount == 0);\n        _readPage.Pin(_readPage.Version);\n    }\n\n    /// <inheritdoc/>\n    public void Dispose()\n    {\n        if (_disposed) return;\n\n        UnpinAll();\n        _totalLength = _readIndex = 0;\n        _readPage = _writePage = _tail = null!;\n        _disposed = true;\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public Memory<byte> GetMemory(int sizeHint = 0)\n    {\n        ThrowIfDisposed();\n\n        if (sizeHint >= _writePage.WriteCapacity)\n        {\n            return GetMemorySlow(sizeHint);\n        }\n\n        return _writePage.WritableMemory;\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public Span<byte> GetSpan(int sizeHint = 0)\n    {\n        ThrowIfDisposed();\n\n        if (sizeHint >= _writePage.WriteCapacity)\n        {\n            return GetSpanSlow(sizeHint);\n        }\n\n        return _writePage.WritableSpan;\n    }\n\n    /// <summary>\n    /// Attempts to read the provided number of bytes from the buffer.\n    /// </summary>\n    /// <param name=\"destination\">The destination, which may be used to hold the requested data if the data needs to be copied.</param>\n    /// <returns>A span of either zero length, if the data is unavailable, or at least the requested length if the data is available.</returns>\n    public ReadOnlySpan<byte> Peek(scoped in Span<byte> destination)\n    {\n        ThrowIfDisposed();\n\n        // Single span.\n        var firstSpan = _readPage.AsSpan(_readIndex, _readPage.Length - _readIndex);\n        if (firstSpan.Length >= destination.Length)\n        {\n            return firstSpan;\n        }\n\n        // Multiple spans. Create a slice without pinning it, since we would be immediately unpinning it.\n        Peek(destination);\n        return destination;\n    }\n\n    /// <summary>Copies the contents of this writer to a span.</summary>\n    /// <remarks>This method does not advance the read cursor.</remarks>\n    public int Peek(Span<byte> output)\n    {\n        ThrowIfDisposed();\n\n        var bytesCopied = 0;\n        var current = _readPage;\n        var offset = _readIndex;\n        while (output.Length > 0 && current != null)\n        {\n            var segment = current.AsSpan(offset, current.Length - offset);\n            var copyLength = Math.Min(segment.Length, output.Length);\n            bytesCopied += copyLength;\n            var slice = segment[..copyLength];\n            slice.CopyTo(output);\n            output = output[slice.Length..];\n            current = current.Next;\n            offset = 0;\n        }\n\n        return bytesCopied;\n    }\n\n    /// <summary>\n    /// Writes the provided sequence to this buffer.\n    /// </summary>\n    /// <param name=\"input\">The data to write.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Write(ReadOnlySequence<byte> input)\n    {\n        ThrowIfDisposed();\n\n        foreach (var segment in input)\n        {\n            Write(segment.Span);\n        }\n    }\n\n    /// <summary>\n    /// Writes the provided value to this buffer.\n    /// </summary>\n    /// <param name=\"value\">The data to write.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Write(ReadOnlySpan<byte> value)\n    {\n        ThrowIfDisposed();\n\n        var destination = GetSpan();\n\n        // Fast path, try copying to the available memory directly\n        if (value.Length <= destination.Length)\n        {\n            value.CopyTo(destination);\n            AdvanceWriter(value.Length);\n        }\n        else\n        {\n            WriteMultiSegment(value, destination);\n        }\n    }\n\n    private void WriteMultiSegment(in ReadOnlySpan<byte> source, Span<byte> destination)\n    {\n        var input = source;\n        while (true)\n        {\n            var writeSize = Math.Min(destination.Length, input.Length);\n            input[..writeSize].CopyTo(destination);\n            AdvanceWriter(writeSize);\n            input = input[writeSize..];\n            if (input.Length > 0)\n            {\n                destination = GetSpan();\n\n                continue;\n            }\n\n            return;\n        }\n    }\n\n    /// <summary>\n    /// Unpins all pages.\n    /// </summary>\n    private void UnpinAll()\n    {\n        var current = _readPage;\n        while (current != null)\n        {\n            var previous = current;\n            current = previous.Next;\n            previous.Unpin(previous.Version);\n        }\n    }\n\n    /// <summary>\n    /// Returns a slice of the provided length without marking the data referred to it as consumed.\n    /// </summary>\n    /// <param name=\"count\">The number of bytes to consume.</param>\n    /// <returns>A slice of unconsumed data.</returns>\n    public ArcBuffer PeekSlice(int count)\n    {\n        ThrowIfDisposed();\n\n#if NET6_0_OR_GREATER\n        ArgumentOutOfRangeException.ThrowIfLessThan(count, 0);\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(count, Length);\n#else\n        if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), \"Length must be greater than or equal to 0.\");\n        if (count > Length) throw new ArgumentOutOfRangeException(nameof(count), \"Length must be less than or equal to the unconsumed length of the buffer.\");\n#endif\n        Debug.Assert(count >= 0);\n        Debug.Assert(count <= Length);\n\n        var result = new ArcBuffer(_readPage, token: _readPage.Version, offset: _readIndex, count);\n        result.Pin();\n        return result;\n    }\n\n    /// <summary>\n    /// Consumes a slice of the provided length.\n    /// </summary>\n    /// <param name=\"count\">The number of bytes to consume.</param>\n    /// <returns>A buffer representing the consumed data.</returns>\n    public ArcBuffer ConsumeSlice(int count)\n    {\n        ThrowIfDisposed();\n\n        var result = PeekSlice(count);\n\n        // Advance the cursor so that subsequent slice calls will return the next slice.\n        AdvanceReader(count);\n\n        return result;\n    }\n\n    /// <summary>\n    /// Advances the reader by the specified number of bytes.\n    /// </summary>\n    /// <param name=\"count\">The number of bytes to advance the reader.</param>\n    public void AdvanceReader(int count)\n    {\n        ThrowIfDisposed();\n\n        Debug.Assert(count >= 0);\n        Debug.Assert(count <= Length);\n\n        _readIndex += count;\n\n        // If this call would consume the entire first page and the page is not the current write page, unpin it.\n        while (_readIndex >= _readPage.Length && _writePage != _readPage)\n        {\n            // Advance the consumed length.\n            var current = _readPage;\n            _readIndex -= current.Length;\n            _totalLength -= current.Length;\n\n            // Advance to the next page\n            Debug.Assert(current.Next is not null);\n            _readPage = current.Next!;\n\n            // Unpin the page.\n            current.Unpin(current.Version);\n        }\n\n        Debug.Assert(_readPage is not null);\n        Debug.Assert(_readIndex <= _readPage.Length);\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private Span<byte> GetSpanSlow(int sizeHint) => AdvanceWritePage(sizeHint).Array;\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private Memory<byte> GetMemorySlow(int sizeHint) => AdvanceWritePage(sizeHint).AsMemory(0);\n\n    private ArcBufferPage AllocatePage(int sizeHint)\n    {\n        Debug.Assert(_tail.Next is null);\n\n        var newBuffer = ArcBufferPagePool.Shared.Rent(sizeHint);\n        Debug.Assert(newBuffer.ReferenceCount == 0);\n        newBuffer.Pin(newBuffer.Version);\n        _tail.SetNext(newBuffer, _tail.Version);\n        return _tail = newBuffer;\n    }\n\n    private ArcBufferPage AdvanceWritePage(int sizeHint)\n    {\n        var next = _writePage.Next;\n        if (next is null)\n        {\n            next = AllocatePage(sizeHint);\n        }\n\n        _writePage = next;\n        return next;\n    }\n\n    private void ThrowIfDisposed()\n    {\n        if (_disposed)\n            throw new ObjectDisposedException(nameof(ArcBufferWriter));\n    }\n}\n\ninternal sealed class ArcBufferPagePool\n{\n    public static ArcBufferPagePool Shared { get; } = new();\n    public const int MinimumPageSize = 16 * 1024;\n    private readonly ConcurrentQueue<ArcBufferPage> _pages = new();\n    private readonly ConcurrentQueue<ArcBufferPage> _largePages = new();\n\n    private ArcBufferPagePool() { }\n\n    public ArcBufferPage Rent(int size = -1)\n    {\n        ArcBufferPage? block;\n        if (size <= MinimumPageSize)\n        {\n            if (!_pages.TryDequeue(out block))\n            {\n                block = new ArcBufferPage(size);\n            }\n        }\n        else if (_largePages.TryDequeue(out block))\n        {\n            block.ResizeLargeSegment(size);\n            return block;\n        }\n\n        return block ?? new ArcBufferPage(size);\n    }\n\n    internal void Return(ArcBufferPage block)\n    {\n        Debug.Assert(block.IsValid);\n        if (block.IsMinimumSize)\n        {\n            _pages.Enqueue(block);\n        }\n        else\n        {\n            _largePages.Enqueue(block);\n        }\n    }\n}\n\n/// <summary>\n/// A page of data.\n/// </summary>\npublic sealed class ArcBufferPage\n{\n    // The current version of the page. Each time the page is return to the pool, the version is incremented.\n    // This helps to ensure that the page is not consumed after it has been returned to the pool.\n    // This is a guard against certain programming bugs.\n    private int _version;\n\n    // The current reference count. This is used to ensure that a page is not returned to the pool while it is still in use.\n    private int _refCount;\n\n    internal ArcBufferPage()\n    {\n        Array = [];\n    }\n\n    internal ArcBufferPage(int length)\n    {\n#if !NET6_0_OR_GREATER\n        Array = null!;\n#endif\n        InitializeArray(length);\n    }\n\n    public void ResizeLargeSegment(int length)\n    {\n        Debug.Assert(length > ArcBufferPagePool.MinimumPageSize);\n        InitializeArray(length);\n    }\n\n#if NET6_0_OR_GREATER\n    [MemberNotNull(nameof(Array))]\n#endif\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private void InitializeArray(int length)\n    {\n        if (length <= ArcBufferPagePool.MinimumPageSize)\n        {\n            Debug.Assert(Array is null);\n#if NET6_0_OR_GREATER\n            var array = GC.AllocateUninitializedArray<byte>(ArcBufferPagePool.MinimumPageSize, pinned: true);\n#else\n                var array = new byte[ArcBufferPagePool.MinimumPageSize];\n#endif\n            Array = array;\n        }\n        else\n        {\n            // Round up to a power of two.\n            length = (int)BitOperations.RoundUpToPowerOf2((uint)length);\n\n            if (Array is not null)\n            {\n                // The segment has an appropriate size already.\n                if (Array.Length == length)\n                {\n                    return;\n                }\n\n                // The segment is being resized.\n                ArrayPool<byte>.Shared.Return(Array);\n            }\n\n            Array = ArrayPool<byte>.Shared.Rent(length);\n        }\n    }\n\n    /// <summary>\n    /// Gets the array underpinning the page.\n    /// </summary>\n    public byte[] Array { get; private set; }\n\n    /// <summary>\n    /// Gets the number of bytes which have been written to the page.\n    /// </summary>\n    public int Length { get; private set; }\n\n    /// <summary>\n    /// A <see cref=\"ReadOnlySpan{T}\"/> containing the readable bytes from this page.\n    /// </summary>\n    public ReadOnlySpan<byte> ReadableSpan => Array.AsSpan(0, Length);\n\n    /// <summary>\n    /// A <see cref=\"ReadOnlyMemory{T}\"/> containing the readable bytes from this page.\n    /// </summary>\n    public ReadOnlyMemory<byte> ReadableMemory => AsMemory(0, Length);\n\n    /// <summary>\n    /// An <see cref=\"ArraySegment{T}\"/> containing the readable bytes from this page.\n    /// </summary>\n    public ArraySegment<byte> ReadableArraySegment => new(Array, 0, Length);\n\n    /// <summary>\n    /// An <see cref=\"ArraySegment{T}\"/> containing the writable bytes from this page.\n    /// </summary>\n    public ArraySegment<byte> WritableArraySegment => new(Array, Length, Array.Length - Length);\n\n    /// <summary>\n    /// Gets the next node.\n    /// </summary>\n    public ArcBufferPage? Next { get; protected set; }\n\n    /// <summary>\n    /// Gets the current page version.\n    /// </summary>\n    public int Version => _version;\n\n    /// <summary>\n    /// Gets a value indicating whether this page is valid.\n    /// </summary>\n    public bool IsValid => Array is { Length: > 0 };\n\n    /// <summary>\n    /// Gets a value indicating whether this page is equal to the minimum page size.\n    /// </summary>\n    public bool IsMinimumSize => Array.Length == ArcBufferPagePool.MinimumPageSize;\n\n    /// <summary>\n    /// Gets the number of bytes in the page which are available for writing.\n    /// </summary>\n    public int WriteCapacity => Array.Length - Length;\n\n    /// <summary>\n    /// Gets the writable memory in the page.\n    /// </summary>\n    public Memory<byte> WritableMemory => AsMemory(Length);\n\n    /// <summary>\n    /// Gets a span representing the writable memory in the page.\n    /// </summary>\n    public Span<byte> WritableSpan => AsSpan(Length);\n\n    /// <summary>\n    /// Gets the current page reference count.\n    /// </summary>\n    internal int ReferenceCount => _refCount;\n\n    /// <summary>\n    /// Creates a new memory region over the portion of the target page beginning at a specified position.\n    /// </summary>\n    /// <param name=\"offset\">The offset into the array to return memory from.</param>\n    /// <returns>The memory region.</returns>\n    public Memory<byte> AsMemory(int offset)\n    {\n#if NET6_0_OR_GREATER\n        if (IsMinimumSize)\n        {\n            return MemoryMarshal.CreateFromPinnedArray(Array, offset, Array.Length - offset);\n        }\n#endif\n\n        return Array.AsMemory(offset);\n    }\n\n    /// <summary>\n    /// Creates a new memory region over the portion of the target page beginning at a specified position with a specified length.\n    /// </summary>\n    /// <param name=\"offset\">The offset into the array that the memory region starts from.</param>\n    /// <param name=\"length\">The length of the memory region.</param>\n    /// <returns>The memory region.</returns>\n    public Memory<byte> AsMemory(int offset, int length)\n    {\n#if NET6_0_OR_GREATER\n        if (IsMinimumSize)\n        {\n            return MemoryMarshal.CreateFromPinnedArray(Array, offset, length);\n        }\n#endif\n\n        return Array.AsMemory(offset, length);\n    }\n\n    /// <summary>\n    /// Returns an array segment pointing to the underlying array, starting from the provided offset, and having the provided length.\n    /// </summary>\n    /// <param name=\"offset\">The offset into the array that the array segment starts from.</param>\n    /// <param name=\"length\">The length of the array segment.</param>\n    /// <returns>The array segment.</returns>\n    public ArraySegment<byte> AsArraySegment(int offset, int length) => new(Array, offset, length);\n\n    /// <summary>\n    /// Gets a span pointing to the underlying array, starting from the provided offset.\n    /// </summary>\n    /// <param name=\"offset\">The offset.</param>\n    /// <returns>The span.</returns>\n    public Span<byte> AsSpan(int offset) => Array.AsSpan(offset);\n\n    /// <summary>\n    /// Gets a span pointing to the underlying array, starting from the provided offset.\n    /// </summary>\n    /// <param name=\"offset\">The offset.</param>\n    /// <param name=\"length\">The length.</param>\n    /// <returns>The span.</returns>\n    public Span<byte> AsSpan(int offset, int length) => Array.AsSpan(offset, length);\n\n    /// <summary>\n    /// Increases the number of bytes written to the page by the provided amount.\n    /// </summary>\n    /// <param name=\"bytes\">The number of bytes to increase the length of this page by.</param>\n    public void Advance(int bytes)\n    {\n        Debug.Assert(bytes >= 0, \"Advance called with negative bytes\");\n        Length += bytes;\n        Debug.Assert(Length <= Array.Length);\n    }\n\n    /// <summary>\n    /// Sets the next page in the sequence.\n    /// </summary>\n    /// <param name=\"next\">The next page in the sequence.</param>\n    /// <param name=\"token\">The token, which must match the page's <see cref=\"Version\"/> for this operation to be allowed.</param>\n    public void SetNext(ArcBufferPage next, int token)\n    {\n        Debug.Assert(Next is null);\n        CheckValidity(token);\n        Debug.Assert(next is not null, \"SetNext called with null next page\");\n        Debug.Assert(next != this, \"SetNext called with self as next page\");\n        Next = next;\n    }\n\n    /// <summary>\n    /// Pins this page to prevent it from being returned to the page pool.\n    /// </summary>\n    /// <param name=\"token\">The token, which must match the page's <see cref=\"Version\"/> for this operation to be allowed.</param>\n    public void Pin(int token)\n    {\n        if (token != _version)\n        {\n            ThrowInvalidVersion();\n        }\n\n        Interlocked.Increment(ref _refCount);\n    }\n\n    /// <summary>\n    /// Unpins this page, allowing it to be returned to the page pool.\n    /// </summary>\n    /// <param name=\"token\">The token, which must match the page's <see cref=\"Version\"/> for this operation to be allowed.</param>\n    public void Unpin(int token)\n    {\n        CheckValidity(token);\n        if (Interlocked.Decrement(ref _refCount) == 0)\n        {\n            Return();\n        }\n    }\n\n    private void Return()\n    {\n        Debug.Assert(_refCount == 0);\n        Length = 0;\n        Next = default;\n        Interlocked.Increment(ref _version);\n        ArcBufferPagePool.Shared.Return(this);\n    }\n\n    /// <summary>\n    /// Throws if the provided <paramref name=\"token\"/> does not match the page's <see cref=\"Version\"/>.\n    /// </summary>\n    /// <param name=\"token\">The token, which must match the page's <see cref=\"Version\"/>.</param>\n    public void CheckValidity(int token)\n    {\n        if (token != _version)\n        {\n            ThrowInvalidVersion();\n        }\n\n        if (_refCount <= 0)\n        {\n            ThrowAccessViolation();\n        }\n    }\n\n    [DoesNotReturn]\n    private static void ThrowInvalidVersion() => throw new InvalidOperationException(\"An invalid token was provided when attempting to perform an operation on this page.\");\n\n    [DoesNotReturn]\n    private static void ThrowAccessViolation() => throw new InvalidOperationException(\"An attempt was made to access a page with an invalid reference count.\");\n}\n\n/// <summary>\n/// Provides reader access to an <see cref=\"ArcBufferWriter\"/>.\n/// </summary>\n/// <param name=\"writer\">The writer.</param>\npublic readonly struct ArcBufferReader(ArcBufferWriter writer)\n{\n    /// <summary>\n    /// Gets the number of unconsumed bytes.\n    /// </summary>\n    public int Length\n    {\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        get => writer.Length;\n    }\n\n    /// <summary>\n    /// Attempts to read the provided number of bytes from the buffer.\n    /// </summary>\n    /// <param name=\"destination\">The destination, which may be used to hold the requested data if the data needs to be copied.</param>\n    /// <returns>A span of either zero length, if the data is unavailable, or the requested length if the data is available.</returns>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public ReadOnlySpan<byte> Peek(scoped in Span<byte> destination) => writer.Peek(in destination);\n\n    /// <summary>\n    /// Returns a slice of the provided length without marking the data referred to it as consumed.\n    /// </summary>\n    /// <param name=\"count\">The number of bytes to consume.</param>\n    /// <returns>A slice of unconsumed data.</returns>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public ArcBuffer PeekSlice(int count) => writer.PeekSlice(count);\n\n    /// <summary>\n    /// Consumes a slice of the provided length.\n    /// </summary>\n    /// <param name=\"count\">The number of bytes to consume.</param>\n    /// <returns>A buffer representing the consumed data.</returns>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public ArcBuffer ConsumeSlice(int count) => writer.ConsumeSlice(count);\n\n    /// <summary>\n    /// Consumes the amount of data present in the span.\n    /// </summary>\n    /// <param name=\"output\"></param>\n    public void Consume(Span<byte> output)\n    {\n        var count = writer.Peek(output);\n        if (count != output.Length)\n        {\n            throw new InvalidOperationException(\"Attempted to consume more data than is available.\");\n        }\n\n        writer.AdvanceReader(count);\n    }\n\n    public void Skip(int count)\n    {\n        writer.AdvanceReader(count);\n    }\n}\n\n/// <summary>\n/// Represents a slice of a <see cref=\"ArcBufferWriter\"/>.\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"ArcBuffer\"/> type.\n/// </remarks>\n/// <param name=\"first\">The first page in the sequence.</param>\n/// <param name=\"token\">The token of the first page in the sequence.</param>\n/// <param name=\"offset\">The offset into the buffer at which this slice begins.</param>\n/// <param name=\"length\">The length of this slice.</param>\npublic struct ArcBuffer(ArcBufferPage first, int token, int offset, int length) : IDisposable\n{\n    /// <summary>\n    /// Gets the token of the first page pointed to by this slice.\n    /// </summary>\n    private int _firstPageToken = token;\n\n    /// <summary>\n    /// Gets the first page.\n    /// </summary>\n    public readonly ArcBufferPage First = first;\n\n    /// <summary>\n    /// Gets the offset into the first page at which this slice begins.\n    /// </summary>\n    public readonly int Offset = offset;\n\n    /// <summary>\n    /// Gets the length of this sequence.\n    /// </summary>\n    public readonly int Length = length;\n\n    /// <summary>Copies the contents of this writer to a span.</summary>\n    public readonly int CopyTo(Span<byte> output)\n    {\n        CheckValidity();\n        if (output.Length < Length)\n        {\n            throw new ArgumentException(\"Destination span is not large enough to hold the buffer contents.\", nameof(output));\n        }\n\n        var copied = 0;\n        foreach (var span in this)\n        {\n            var slice = span[..Math.Min(span.Length, output.Length)];\n            slice.CopyTo(output);\n            output = output[slice.Length..];\n            copied += slice.Length;\n        }\n\n        return copied;\n    }\n\n    /// <summary>Copies the contents of this writer to a pooled buffer.</summary>\n    public readonly void CopyTo(ArcBufferWriter output)\n    {\n        CheckValidity();\n        foreach (var span in this)\n        {\n            output.Write(span);\n        }\n    }\n\n    /// <summary>Copies the contents of this writer to a buffer writer.</summary>\n    public readonly void CopyTo<TBufferWriter>(ref TBufferWriter output) where TBufferWriter : IBufferWriter<byte>\n    {\n        CheckValidity();\n        foreach (var span in this)\n        {\n            Write(ref output, span);\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static void Write<TBufferWriter>(ref TBufferWriter writer, ReadOnlySpan<byte> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        var destination = writer.GetSpan();\n\n        // Fast path, try copying to the available memory directly\n        if (value.Length <= destination.Length)\n        {\n            value.CopyTo(destination);\n            writer.Advance(value.Length);\n        }\n        else\n        {\n            WriteMultiSegment(ref writer, value, destination);\n        }\n    }\n\n    private static void WriteMultiSegment<TBufferWriter>(ref TBufferWriter writer, in ReadOnlySpan<byte> source, Span<byte> destination) where TBufferWriter : IBufferWriter<byte>\n    {\n        var input = source;\n        while (true)\n        {\n            var writeSize = Math.Min(destination.Length, input.Length);\n            input[..writeSize].CopyTo(destination);\n            writer.Advance(writeSize);\n            input = input[writeSize..];\n            if (input.Length > 0)\n            {\n                destination = writer.GetSpan();\n\n                if (destination.IsEmpty)\n                {\n                    ThrowInsufficientSpaceException();\n                }\n\n                continue;\n            }\n\n            return;\n        }\n    }\n\n    [DoesNotReturn]\n    private static void ThrowInsufficientSpaceException() => throw new InvalidOperationException(\"Insufficient capacity in provided buffer\");\n\n    /// <summary>\n    /// Returns a new <see cref=\"ReadOnlySequence{T}\"/> which must not be accessed after disposing this instance.\n    /// </summary>\n    public readonly ReadOnlySequence<byte> AsReadOnlySequence()\n    {\n        var runningIndex = 0L;\n        ReadOnlySequenceSegment? first = null;\n        ReadOnlySequenceSegment? previous = null;\n        var endIndex = 0;\n        foreach (var memory in MemorySegments)\n        {\n            var current = new ReadOnlySequenceSegment(memory, runningIndex);\n            first ??= current;\n            endIndex = memory.Length;\n            runningIndex += endIndex;\n            previous?.SetNext(current);\n            previous = current;\n        }\n\n        if (first is null)\n        {\n            return ReadOnlySequence<byte>.Empty;\n        }\n\n        Debug.Assert(first is not null);\n        Debug.Assert(previous is not null);\n        if (previous == first)\n        {\n            return new ReadOnlySequence<byte>(first.Memory);\n        }\n\n        return new ReadOnlySequence<byte>(first, 0, previous, endIndex);\n    }\n\n    /// <summary>\n    /// Returns the data which has been written as an array.\n    /// </summary>\n    /// <returns>The data which has been written.</returns>\n    public readonly byte[] ToArray()\n    {\n        CheckValidity();\n        var result = new byte[Length];\n        CopyTo(result);\n        return result;\n    }\n\n    /// <summary>\n    /// Throws if the buffer it no longer valid.\n    /// </summary>\n    private readonly void CheckValidity() => First.CheckValidity(_firstPageToken);\n\n    public readonly ArcBuffer Slice(int offset) => Slice(offset, Length - offset);\n\n    public readonly ArcBuffer Slice(int offset, int length)\n    {\n        var result = UnsafeSlice(offset, length);\n        result.Pin();\n        return result;\n    }\n\n    public readonly ArcBuffer UnsafeSlice(int offset, int length)\n    {\n#if NET6_0_OR_GREATER\n        ArgumentOutOfRangeException.ThrowIfLessThan(length, 0);\n        ArgumentOutOfRangeException.ThrowIfLessThan(offset, 0);\n        ArgumentOutOfRangeException.ThrowIfGreaterThan(length + offset, Length);\n#else\n        if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), \"Length must be greater than or equal to 0.\");\n        if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), \"Offset must be greater than or equal to 0.\");\n        if (length + offset > Length) throw new ArgumentOutOfRangeException($\"{nameof(length)} + {nameof(offset)}\", \"Length plus offset must be less than or equal to the length of the buffer.\");\n#endif\n\n        CheckValidity();\n        Debug.Assert(offset >= 0);\n        Debug.Assert(length >= 0); \n        Debug.Assert(offset + length <= Length);\n        ArcBuffer result;\n\n        // Navigate to the offset page & calculate the offset into the page.\n        if (Offset + offset < First.Length || length == 0)\n        {\n            // The slice starts within this page.\n            result = new ArcBuffer(First, token: _firstPageToken, Offset + offset, length);\n        }\n        else\n        {\n            // The slice starts within a subsequent page.\n            // Account for the first page, then navigate to the page which the offset falls in.\n            offset -= First.Length - Offset;\n            var page = First.Next;\n            Debug.Assert(page is not null);\n\n            while (offset >= page.Length)\n            {\n                offset -= page.Length;\n                page = page.Next;\n                Debug.Assert(page is not null);\n            }\n\n            result = new ArcBuffer(page, token: page.Version, offset, length);\n        }\n\n        return result;\n    }\n\n    /// <summary>\n    /// Pins this slice, preventing the referenced pages from being returned to the pool.\n    /// </summary>\n    public readonly void Pin()\n    {\n        CheckValidity();\n        var pageEnumerator = Pages.GetEnumerator();\n        if (pageEnumerator.MoveNext())\n        {\n            var page = pageEnumerator.Current!;\n            page.Pin(_firstPageToken);\n        }\n\n        while (pageEnumerator.MoveNext())\n        {\n            var page = pageEnumerator.Current!;\n            page.Pin(page.Version);\n        }\n    }\n\n    /// <summary>\n    /// Unpins this slice, allowing the referenced pages to be returned to the pool.\n    /// </summary>\n    public void Unpin()\n    {\n        var pageEnumerator = Pages.GetEnumerator();\n        if (pageEnumerator.MoveNext())\n        {\n            var page = pageEnumerator.Current!;\n            page.Unpin(_firstPageToken);\n        }\n\n        while (pageEnumerator.MoveNext())\n        {\n            var page = pageEnumerator.Current!;\n            page.Unpin(page.Version);\n        }\n\n        _firstPageToken = -1;\n    }\n\n    /// <inheritdoc/>\n    public void Dispose()\n    {\n        if (_firstPageToken == -1)\n        {\n            // Already disposed.\n            return;\n        }\n\n        Unpin();\n    }\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the span segments referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public readonly SpanEnumerator GetEnumerator() => new(this);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the pages referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    internal readonly PageEnumerator Pages => new(this);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the pages referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    internal readonly PageSegmentEnumerator PageSegments => new(this);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the span segments referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public readonly SpanEnumerator SpanSegments => new(this);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the memory segments referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public readonly MemoryEnumerator MemorySegments => new(this);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the array segments referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public readonly ArraySegmentEnumerator ArraySegments => new(this);\n\n    /// <summary>\n    /// Defines a region of data within a page.\n    /// </summary>\n    public readonly struct PageSegment(ArcBufferPage page, int offset, int length)\n    {\n        /// <summary>\n        /// Gets the page which this segment refers to.\n        /// </summary>\n        public readonly ArcBufferPage Page = page;\n\n        /// <summary>\n        /// Gets the offset into the page at which this region begins.\n        /// </summary>\n        public readonly int Offset = offset;\n\n        /// <summary>\n        /// Gets the length of this region.\n        /// </summary>\n        public readonly int Length = length;\n\n        /// <summary>\n        /// Gets a <see cref=\"ReadOnlySpan{T}\"/> representation of this region.\n        /// </summary>\n        public readonly ReadOnlySpan<byte> Span => Page.AsSpan(Offset, Length);\n\n        /// <summary>\n        /// Gets a <see cref=\"ReadOnlyMemory{T}\"/> representation of this region.\n        /// </summary>\n        public readonly ReadOnlyMemory<byte> Memory => Page.AsMemory(Offset, Length);\n\n        /// <summary>\n        /// Gets an <see cref=\"ArraySegment{T}\"/> representation of this region.\n        /// </summary>\n        public readonly ArraySegment<byte> ArraySegment => Page.AsArraySegment(Offset, Length);\n    }\n\n    /// <summary>\n    /// Enumerates over page segments in a <see cref=\"ArcBuffer\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"PageSegmentEnumerator\"/> type.\n    /// </remarks>\n    /// <param name=\"slice\">The buffer to enumerate.</param>\n    internal struct PageSegmentEnumerator(ArcBuffer slice) : IEnumerable<PageSegment>, IEnumerator<PageSegment>\n    {\n        internal readonly ArcBuffer Slice = slice;\n        private int _position;\n        private ArcBufferPage? _page = slice.Length > 0 ? slice.First : null;\n\n        internal readonly ArcBufferPage First => Slice.First;\n        internal readonly int Offset => Slice.Offset;\n        internal readonly int Length => Slice.Length;\n\n        /// <summary>\n        /// Gets this instance as an enumerator.\n        /// </summary>\n        /// <returns>This instance.</returns>\n        public readonly PageSegmentEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public PageSegment Current { get; private set; }\n\n        /// <inheritdoc/>\n        readonly object? IEnumerator.Current => Current;\n\n        /// <summary>\n        /// Gets a value indicating whether enumeration has completed.\n        /// </summary>\n        public readonly bool IsCompleted => _page is null || _position == Length;\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            Debug.Assert(_position <= Length, \"Enumerator position exceeds slice length\");\n            if (_page is null || _position == Length)\n            {\n                Current = default;\n                Debug.Assert(_position == Length, \"Enumerator ended before reaching full length\");\n                return false;\n            }\n\n            if (_page == First)\n            {\n                Debug.Assert(_position == 0);\n                Slice.CheckValidity();\n                var offset = Offset;\n                var length = Math.Min(Length, _page.Length - offset);\n                Debug.Assert(length >= 0, \"Calculated negative length for first segment\");\n                _position += length;\n                Current = new PageSegment(_page, offset, length);\n                _page = _page.Next;\n                return true;\n            }\n\n            {\n                var length = Math.Min(Length - _position, _page.Length);\n                Debug.Assert(length >= 0, \"Calculated negative length for subsequent segment\");\n                _position += length;\n                Current = new PageSegment(_page, 0, length);\n                _page = _page.Next;\n                return true;\n            }\n        }\n\n        /// <inheritdoc/>\n        readonly IEnumerator<PageSegment> IEnumerable<PageSegment>.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        void IEnumerator.Reset()\n        {\n            _position = 0;\n            _page = Slice.Length > 0 ? Slice.First : null;\n            Current = default;\n        }\n\n        /// <inheritdoc/>\n        readonly void IDisposable.Dispose() { }\n    }\n\n    /// <summary>\n    /// Enumerates over pages in a <see cref=\"ArcBuffer\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"PageEnumerator\"/> type.\n    /// </remarks>\n    /// <param name=\"slice\">The slice to enumerate.</param>\n    internal struct PageEnumerator(ArcBuffer slice) : IEnumerable<ArcBufferPage>, IEnumerator<ArcBufferPage?>\n    {\n        private PageSegmentEnumerator _enumerator = slice.PageSegments;\n\n        /// <summary>\n        /// Gets this instance as an enumerator.\n        /// </summary>\n        /// <returns>This instance.</returns>\n        public readonly PageEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public ArcBufferPage? Current { get; private set; }\n\n        /// <inheritdoc/>\n        readonly object? IEnumerator.Current => Current;\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (_enumerator.MoveNext())\n            {\n                Current = _enumerator.Current.Page;\n                return true;\n            }\n\n            Current = default;\n            return false;\n        }\n\n        /// <inheritdoc/>\n        readonly IEnumerator<ArcBufferPage> IEnumerable<ArcBufferPage>.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        void IEnumerator.Reset()\n        {\n            _enumerator = _enumerator.Slice.PageSegments;\n            Current = default;\n        }\n\n        /// <inheritdoc/>\n        readonly void IDisposable.Dispose() { }\n    }\n\n    /// <summary>\n    /// Enumerates over spans of bytes in a <see cref=\"ArcBuffer\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"SpanEnumerator\"/> type.\n    /// </remarks>\n    /// <param name=\"slice\">The slice to enumerate.</param>\n    public ref struct SpanEnumerator(ArcBuffer slice)\n    {\n        private PageSegmentEnumerator _enumerator = slice.PageSegments;\n\n        /// <summary>\n        /// Gets this instance as an enumerator.\n        /// </summary>\n        /// <returns>This instance.</returns>\n        public readonly SpanEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public ReadOnlySpan<byte> Current { get; private set; }\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (_enumerator.MoveNext())\n            {\n                Current = _enumerator.Current.Span;\n                return true;\n            }\n\n            Current = default;\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Enumerates over sequences of bytes in a <see cref=\"ArcBuffer\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"MemoryEnumerator\"/> type.\n    /// </remarks>\n    /// <param name=\"slice\">The slice to enumerate.</param>\n    public struct MemoryEnumerator(ArcBuffer slice) : IEnumerable<ReadOnlyMemory<byte>>, IEnumerator<ReadOnlyMemory<byte>>\n    {\n        private PageSegmentEnumerator _enumerator = slice.PageSegments;\n\n        /// <summary>\n        /// Gets this instance as an enumerator.\n        /// </summary>\n        /// <returns>This instance.</returns>\n        public readonly MemoryEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public ReadOnlyMemory<byte> Current { get; private set; }\n\n        /// <inheritdoc/>\n        readonly object? IEnumerator.Current => Current;\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (_enumerator.MoveNext())\n            {\n                Current = _enumerator.Current.Memory;\n                return true;\n            }\n\n            Current = default;\n            return false;\n        }\n\n        /// <inheritdoc/>\n        readonly IEnumerator<ReadOnlyMemory<byte>> IEnumerable<ReadOnlyMemory<byte>>.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        void IEnumerator.Reset()\n        {\n            _enumerator = _enumerator.Slice.PageSegments;\n            Current = default;\n        }\n\n        /// <inheritdoc/>\n        readonly void IDisposable.Dispose() { }\n    }\n\n    /// <summary>\n    /// Enumerates over array segments in a <see cref=\"ArcBuffer\"/>.\n    /// </summary>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"ArraySegmentEnumerator\"/> type.\n    /// </remarks>\n    /// <param name=\"slice\">The slice to enumerate.</param>\n    public struct ArraySegmentEnumerator(ArcBuffer slice) : IEnumerable<ArraySegment<byte>>, IEnumerator<ArraySegment<byte>>\n    {\n        private PageSegmentEnumerator _enumerator = slice.PageSegments;\n\n        /// <summary>\n        /// Gets this instance as an enumerator.\n        /// </summary>\n        /// <returns>This instance.</returns>\n        public readonly ArraySegmentEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public ArraySegment<byte> Current { get; private set; }\n\n        /// <inheritdoc/>\n        readonly object? IEnumerator.Current => Current;\n\n        /// <summary>\n        /// Gets a value indicating whether enumeration has completed.\n        /// </summary>\n        public readonly bool IsCompleted => _enumerator.IsCompleted;\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (_enumerator.MoveNext())\n            {\n                Current = _enumerator.Current.ArraySegment;\n                return true;\n            }\n\n            Current = default;\n            return false;\n        }\n\n        /// <inheritdoc/>\n        readonly IEnumerator<ArraySegment<byte>> IEnumerable<ArraySegment<byte>>.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc/>\n        void IEnumerator.Reset()\n        {\n            _enumerator = _enumerator.Slice.PageSegments;\n            Current = default;\n        }\n\n        /// <inheritdoc/>\n        readonly void IDisposable.Dispose() { }\n    }\n\n    private sealed class ReadOnlySequenceSegment : ReadOnlySequenceSegment<byte>\n    {\n        public ReadOnlySequenceSegment(ReadOnlyMemory<byte> memory, long runningIndex)\n        {\n            Memory = memory;\n            RunningIndex = runningIndex;\n        }\n\n        public void SetNext(ReadOnlySequenceSegment next)\n        {\n            Debug.Assert(Next is null);\n            Next = next;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/BufferWriterExtensions.cs",
    "content": "using Orleans.Serialization.Session;\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Buffers\n{\n    /// <summary>\n    /// Extensions for working with <see cref=\"IBufferWriter{Byte}\"/> implementations.\n    /// </summary>\n    public static class BufferWriterExtensions\n    {\n        /// <summary>\n        /// Creates a <see cref=\"Writer{TBufferWriter}\"/> instance for the provided buffer.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The type of the buffer writer.</typeparam>\n        /// <param name=\"buffer\">The buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new writer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<TBufferWriter> CreateWriter<TBufferWriter>(this TBufferWriter buffer, SerializerSession session) where TBufferWriter : IBufferWriter<byte>\n        {\n#if NET6_0_OR_GREATER\n            ArgumentNullException.ThrowIfNull(session);\n#else\n            if (session is null) throw new ArgumentNullException(nameof(session));\n#endif\n            return Writer.Create(buffer, session);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/PooledBuffer.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n#if NET6_0_OR_GREATER\nusing System.Numerics;\n#else\nusing Orleans.Serialization.Utilities;\n#endif\n\nnamespace Orleans.Serialization.Buffers;\n\n/// <summary>\n/// A <see cref=\"IBufferWriter{T}\"/> implementation implemented using pooled arrays which is specialized for creating <see cref=\"ReadOnlySequence{T}\"/> instances.\n/// </summary>\n[StructLayout(LayoutKind.Auto)]\n[Immutable]\npublic partial struct PooledBuffer : IBufferWriter<byte>, IDisposable\n{\n    internal SequenceSegment First;\n    internal SequenceSegment Last;\n    internal SequenceSegment WriteHead;\n    internal int TotalLength;\n    internal int CurrentPosition;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"PooledBuffer\"/> struct.\n    /// </summary>\n    public PooledBuffer()\n    {\n        First = Last = null;\n        WriteHead = null;\n        TotalLength = 0;\n        CurrentPosition = 0;\n    }\n\n    /// <summary>Gets the total length which has been written.</summary>\n    public readonly int Length => TotalLength + CurrentPosition;\n\n    /// <summary>\n    /// Returns the data which has been written as an array.\n    /// </summary>\n    /// <returns>The data which has been written.</returns>\n    public readonly byte[] ToArray()\n    {\n        var result = new byte[Length];\n        var resultSpan = result.AsSpan();\n        var current = First;\n        while (current != null)\n        {\n            var span = current.CommittedMemory.Span;\n            span.CopyTo(resultSpan);\n            resultSpan = resultSpan.Slice(span.Length);\n            current = current.Next as SequenceSegment;\n        }\n\n        if (CurrentPosition > 0)\n        {\n            WriteHead.Array.AsSpan(0, CurrentPosition).CopyTo(resultSpan);\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Advance(int bytes)\n    {\n        if (WriteHead is null || CurrentPosition + bytes > WriteHead.Array.Length)\n        {\n            ThrowInvalidOperation();\n        }\n\n        CurrentPosition += bytes;\n\n        static void ThrowInvalidOperation() => throw new InvalidOperationException(\"Attempted to advance past the end of a buffer.\");\n    }\n\n    /// <summary>\n    /// Resets this instance, returning all memory.\n    /// </summary>\n    public void Reset()\n    {\n        var current = First;\n        while (current != null)\n        {\n            var previous = current;\n            current = previous.Next as SequenceSegment;\n            previous.Return();\n            Debug.Assert(current == null || current != WriteHead);\n        }\n\n        WriteHead?.Return();\n\n        First = Last = WriteHead = null;\n        CurrentPosition = TotalLength = 0;\n    }\n\n    /// <inheritdoc/>\n    public void Dispose() => Reset();\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public Memory<byte> GetMemory(int sizeHint = 0)\n    {\n        if (WriteHead is null || sizeHint >= WriteHead.Array.Length - CurrentPosition)\n        {\n            return GetMemorySlow(sizeHint);\n        }\n\n        return WriteHead.AsMemory(CurrentPosition);\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public Span<byte> GetSpan(int sizeHint = 0)\n    {\n        if (WriteHead is { Array: var head } && sizeHint < head.Length - CurrentPosition)\n        {\n            return head.AsSpan(CurrentPosition);\n        }\n\n        return GetSpanSlow(sizeHint);\n    }\n\n    /// <summary>Copies the contents of this writer to a span.</summary>\n    public readonly void CopyTo(Span<byte> output)\n    {\n        var current = First;\n        while (output.Length > 0 && current != null)\n        {\n            var segment = current.CommittedMemory.Span;\n            var slice = segment[..Math.Min(segment.Length, output.Length)];\n            slice.CopyTo(output);\n            output = output[slice.Length..];\n            current = current.Next as SequenceSegment;\n        }\n\n        if (output.Length > 0 && CurrentPosition > 0)\n        {\n            var span = WriteHead.Array.AsSpan(0, Math.Min(output.Length, CurrentPosition));\n            span.CopyTo(output);\n        }\n    }\n\n    /// <summary>Copies the contents of this writer to another writer.</summary>\n    public readonly void CopyTo<TBufferWriter>(ref Writer<TBufferWriter> writer) where TBufferWriter : IBufferWriter<byte>\n    {\n        var current = First;\n        while (current != null)\n        {\n            var span = current.CommittedMemory.Span;\n            writer.Write(span);\n            current = current.Next as SequenceSegment;\n        }\n\n        if (CurrentPosition > 0)\n        {\n            writer.Write(WriteHead.Array.AsSpan(0, CurrentPosition));\n        }\n    }\n\n    /// <summary>Copies the contents of this writer to another writer.</summary>\n    public readonly void CopyTo<TBufferWriter>(ref TBufferWriter writer) where TBufferWriter : IBufferWriter<byte>\n    {\n        var current = First;\n        while (current != null)\n        {\n            var span = current.CommittedMemory.Span;\n            Adaptors.BufferWriterExtensions.Write(ref writer, span);\n            current = current.Next as SequenceSegment;\n        }\n\n        if (CurrentPosition > 0)\n        {\n            Adaptors.BufferWriterExtensions.Write(ref writer, WriteHead.Array.AsSpan(0, CurrentPosition));\n        }\n    }\n\n    /// <summary>\n    /// Returns a new <see cref=\"ReadOnlySequence{T}\"/> which must not be accessed after disposing this instance.\n    /// </summary>\n    public ReadOnlySequence<byte> AsReadOnlySequence()\n    {\n        if (Length == 0)\n        {\n            return ReadOnlySequence<byte>.Empty;\n        }\n\n        Commit();\n        if (First == Last)\n        {\n            return new ReadOnlySequence<byte>(First!.CommittedMemory);\n        }\n\n        return new ReadOnlySequence<byte>(First!, 0, Last!, Last!.CommittedMemory.Length);\n    }\n\n    /// <summary>\n    /// Returns a <see cref=\"BufferSlice\"/> covering this entire buffer.\n    /// </summary>\n    /// <remarks>\n    /// The lifetime of the returned <see cref=\"BufferSlice\"/> must be shorter than the lifetime of this instance.\n    /// </remarks>\n    /// <returns>A <see cref=\"BufferSlice\"/> covering this entire buffer.</returns>\n    public readonly BufferSlice Slice() => new(this, 0, Length);\n\n    /// <summary>\n    /// Returns a slice of this buffer, beginning at the specified offset.\n    /// </summary>\n    /// <remarks>\n    /// The lifetime of the returned <see cref=\"BufferSlice\"/> must be shorter than the lifetime of this instance.\n    /// </remarks>\n    /// <returns>A slice representing a subset of this instance, beginning at the specified offset.</returns>\n    public readonly BufferSlice Slice(int offset) => new(this, offset, Length - offset);\n\n    /// <summary>\n    /// Returns a slice of this buffer, beginning at the specified offset and having the specified length.\n    /// </summary>\n    /// <remarks>\n    /// The lifetime of the returned <see cref=\"BufferSlice\"/> must be shorter than the lifetime of this instance.\n    /// </remarks>\n    /// <returns>A slice representing a subset of this instance, beginning at the specified offset.</returns>\n    public readonly BufferSlice Slice(int offset, int length) => new(this, offset, length);\n\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public readonly MemoryEnumerator MemorySegments => new(this);\n\n    /// <summary>\n    /// Writes the provided sequence to this buffer.\n    /// </summary>\n    /// <param name=\"input\">The data to write.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Write(ReadOnlySequence<byte> input)\n    {\n        foreach (var segment in input)\n        {\n            Write(segment.Span);\n        }\n    }\n\n    /// <summary>\n    /// Writes the provided value to this buffer.\n    /// </summary>\n    /// <param name=\"value\">The data to write.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Write(ReadOnlySpan<byte> value)\n    {\n        // Fast path, try copying to the available memory directly\n        if (WriteHead is { Array: { } head })\n        {\n            var destination = head.AsSpan(CurrentPosition);\n            if ((uint)value.Length <= (uint)destination.Length)\n            {\n                value.CopyTo(destination);\n                CurrentPosition += value.Length;\n                return;\n            }\n        }\n\n        WriteMultiSegment(value);\n    }\n\n    private void WriteMultiSegment(in ReadOnlySpan<byte> source)\n    {\n        var input = source;\n        while (true)\n        {\n            var destination = GetSpan();\n            var writeSize = Math.Min(destination.Length, input.Length);\n            input[..writeSize].CopyTo(destination);\n            CurrentPosition += writeSize;\n            input = input.Slice(writeSize);\n            if (input.Length > 0)\n            {\n                continue;\n            }\n\n            return;\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private Span<byte> GetSpanSlow(int sizeHint) => Grow(sizeHint).Array;\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private Memory<byte> GetMemorySlow(int sizeHint) => Grow(sizeHint).AsMemory(0);\n\n    private SequenceSegment Grow(int sizeHint)\n    {\n        Commit();\n        var newBuffer = SequenceSegmentPool.Shared.Rent(sizeHint);\n        return WriteHead = newBuffer;\n    }\n\n    private void Commit()\n    {\n        if (CurrentPosition == 0 || WriteHead is null)\n        {\n            return;\n        }\n\n        WriteHead.Commit(TotalLength, CurrentPosition);\n        TotalLength += CurrentPosition;\n        if (First is null)\n        {\n            First = WriteHead;\n        }\n        else\n        {\n            Debug.Assert(Last is not null);\n            Last.SetNext(WriteHead);\n        }\n\n        Last = WriteHead;\n        WriteHead = null;\n        CurrentPosition = 0;\n    }\n\n    /// <summary>\n    /// Enumerates over sequences of bytes in a <see cref=\"PooledBuffer\"/>.\n    /// </summary>\n    public struct MemoryEnumerator\n    {\n        private static readonly SequenceSegment InitialSegmentSentinel = new();\n        private static readonly SequenceSegment FinalSegmentSentinel = new();\n        private readonly PooledBuffer _buffer;\n        private int _position;\n        private SequenceSegment _segment;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryEnumerator\"/> type.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer to enumerate.</param>\n        public MemoryEnumerator(PooledBuffer buffer)\n        {\n            _buffer = buffer;\n            _segment = InitialSegmentSentinel;\n            CurrentMemory = ReadOnlyMemory<byte>.Empty;\n        }\n\n        /// <summary>\n        /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n        /// </summary>\n        /// <returns>An enumerator for the data contained in this instance.</returns>\n        public readonly MemoryEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public readonly ReadOnlyMemory<byte> Current => CurrentMemory;\n        public ReadOnlyMemory<byte> CurrentMemory;\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (ReferenceEquals(_segment, InitialSegmentSentinel))\n            {\n                _segment = _buffer.First;\n            }\n\n            var endPosition = _buffer.Length;\n            while (_segment != null && _segment != FinalSegmentSentinel)\n            {\n                var segment = _segment.CommittedMemory;\n\n                // Find the starting segment and the offset to copy from.\n                var segmentLength = segment.Length;\n                if (segmentLength == 0)\n                {\n                    CurrentMemory = ReadOnlyMemory<byte>.Empty;\n                    _segment = FinalSegmentSentinel;\n                    return false;\n                }\n\n                CurrentMemory = segment[..segmentLength];\n                _position += segmentLength;\n                _segment = _segment.Next as SequenceSegment;\n                return true;\n            }\n\n            // Account for the uncommitted data at the end of the buffer.\n            // The write head is only linked to the previous buffers when Commit() is called and it is set to null afterwards,\n            // meaning that if the write head is not null, the other buffers are not linked to it and it therefore has not been enumerated.\n            if (_segment != FinalSegmentSentinel && _buffer.CurrentPosition > 0 && _buffer.WriteHead is { } head)\n            {\n                var finalLength = _buffer.CurrentPosition;\n                if (finalLength == 0)\n                {\n                    CurrentMemory = ReadOnlyMemory<byte>.Empty;\n                    _segment = FinalSegmentSentinel;\n                    return false;\n                }\n\n                CurrentMemory = head.Array.AsMemory(0, finalLength);\n                _position += finalLength;\n                Debug.Assert(_position == _buffer.Length);\n                _segment = FinalSegmentSentinel;\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Enumerates over sequences of bytes in a <see cref=\"PooledBuffer\"/>.\n    /// </summary>\n    public ref struct SpanEnumerator\n    {\n        private static readonly SequenceSegment InitialSegmentSentinel = new();\n        private static readonly SequenceSegment FinalSegmentSentinel = new();\n        private readonly\n#if NET8_0_OR_GREATER\n            ref readonly \n#endif\n            PooledBuffer _buffer;\n        private int _position;\n        private SequenceSegment _segment;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SpanEnumerator\"/> type.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer to enumerate.</param>\n        public SpanEnumerator(ref PooledBuffer buffer)\n        {\n            _buffer =\n#if NET8_0_OR_GREATER\n                ref\n#endif\n                buffer;\n            _segment = InitialSegmentSentinel;\n            Current = ReadOnlySpan<byte>.Empty;\n        }\n\n        /// <summary>\n        /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n        /// </summary>\n        /// <returns>An enumerator for the data contained in this instance.</returns>\n        public readonly SpanEnumerator GetEnumerator() => this;\n\n        /// <summary>\n        /// Gets the element in the collection at the current position of the enumerator.\n        /// </summary>\n        public ReadOnlySpan<byte> Current { get; private set; }\n\n        /// <summary>\n        /// Advances the enumerator to the next element of the collection.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n        public bool MoveNext()\n        {\n            if (ReferenceEquals(_segment, InitialSegmentSentinel))\n            {\n                _segment = _buffer.First;\n            }\n\n            var endPosition = _buffer.Length;\n            while (_segment != null && _segment != FinalSegmentSentinel)\n            {\n                var segment = _segment.CommittedMemory;\n\n                // Find the starting segment and the offset to copy from.\n                var segmentLength = Math.Min(segment.Length, endPosition - _position);\n                if (segmentLength == 0)\n                {\n                    Current = ReadOnlySpan<byte>.Empty;\n                    _segment = FinalSegmentSentinel;\n                    return false;\n                }\n\n                Current = segment.Span[..segmentLength];\n                _position += segmentLength;\n                _segment = _segment.Next as SequenceSegment;\n                return true;\n            }\n\n            // Account for the uncommitted data at the end of the buffer.\n            // The write head is only linked to the previous buffers when Commit() is called and it is set to null afterwards,\n            // meaning that if the write head is not null, the other buffers are not linked to it and it therefore has not been enumerated.\n            if (_segment != FinalSegmentSentinel && _buffer.CurrentPosition > 0 && _buffer.WriteHead is { } head && _position < endPosition)\n            {\n                var finalLength = Math.Min(_buffer.CurrentPosition, endPosition - _position);\n                if (finalLength == 0)\n                {\n                    Current = ReadOnlySpan<byte>.Empty;\n                    _segment = FinalSegmentSentinel;\n                    return false;\n                }\n\n                Current = head.Array.AsSpan(0, finalLength);\n                _position += finalLength;\n                Debug.Assert(_position == endPosition);\n                _segment = FinalSegmentSentinel;\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Represents a slice of a <see cref=\"PooledBuffer\"/>.\n    /// </summary>\n    public readonly struct BufferSlice\n    {\n#pragma warning disable IDE1006 // Naming Styles\n        internal readonly PooledBuffer _buffer;\n        internal readonly int _offset;\n        internal readonly int _length;\n#pragma warning restore IDE1006 // Naming Styles\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BufferSlice\"/> type.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        /// <param name=\"offset\">The offset into the buffer at which this slice begins.</param>\n        /// <param name=\"length\">The length of this slice.</param>\n        public BufferSlice(in PooledBuffer buffer, int offset, int length)\n        {\n            _buffer = buffer;\n            _offset = offset;\n            _length = length;\n        }\n\n        /// <summary>\n        /// Gets the underlying <see cref=\"PooledBuffer\"/>.\n        /// </summary>\n        public readonly PooledBuffer Buffer => _buffer;\n\n        /// <summary>\n        /// Gets the offset into the underlying buffer at which this slice begins.\n        /// </summary>\n        public readonly int Offset => _offset;\n\n        /// <summary>\n        /// Gets the length of this slice.\n        /// </summary>\n        public readonly int Length => _length;\n\n        /// <summary>\n        /// Forms a slice out of this instance, beginning at the specified offset into this slice.\n        /// </summary>\n        /// <param name=\"offset\">The offset into this slice where the newly formed slice will begin.</param>\n        /// <returns>A slice instance.</returns>\n        public readonly BufferSlice Slice(int offset) => new(in _buffer, _offset + offset, _length - offset);\n\n        /// <summary>\n        /// Forms a slice out of this instance, beginning at the specified offset into this slice and having the specified length.\n        /// </summary>\n        /// <param name=\"offset\">The offset into this slice where the newly formed slice will begin.</param>\n        /// <param name=\"length\">The length of the new slice.</param>\n        /// <returns>A slice instance.</returns>\n        public readonly BufferSlice Slice(int offset, int length) => new(in _buffer, _offset + offset, length);\n\n        /// <summary>Copies the contents of this writer to a span.</summary>\n        public readonly int CopyTo(Span<byte> output)\n        {\n            var copied = 0;\n            foreach (var span in this)\n            {\n                var slice = span[..Math.Min(span.Length, output.Length)];\n                slice.CopyTo(output);\n                output = output[slice.Length..];\n                copied += slice.Length;\n            }\n\n            return copied;\n        }\n\n        /// <summary>Copies the contents of this writer to a pooled buffer.</summary>\n        public readonly void CopyTo(ref PooledBuffer output)\n        {\n            foreach (var span in this)\n            {\n                output.Write(span);\n            }\n        }\n\n        /// <summary>Copies the contents of this writer to a buffer writer.</summary>\n        public readonly void CopyTo<TBufferWriter>(ref TBufferWriter output) where TBufferWriter : struct, IBufferWriter<byte>\n        {\n            foreach (var span in this)\n            {\n                Adaptors.BufferWriterExtensions.Write(ref output, span);\n            }\n        }\n\n        /// <summary>\n        /// Returns the data which has been written as an array.\n        /// </summary>\n        /// <returns>The data which has been written.</returns>\n        public readonly byte[] ToArray()\n        {\n            var result = new byte[_length];\n            CopyTo(result);\n            return result;\n        }\n\n        /// <summary>\n        /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n        /// </summary>\n        /// <returns>An enumerator for the data contained in this instance.</returns>\n        public readonly SpanEnumerator GetEnumerator() => new(this);\n\n        /// <summary>\n        /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n        /// </summary>\n        /// <returns>An enumerator for the data contained in this instance.</returns>\n        public readonly MemoryEnumerator MemorySegments => new(this);\n\n        /// <summary>\n        /// Enumerates over spans of bytes in a <see cref=\"BufferSlice\"/>.\n        /// </summary>\n        public ref struct SpanEnumerator\n        {\n            private static readonly SequenceSegment InitialSegmentSentinel = new();\n            private static readonly SequenceSegment FinalSegmentSentinel = new();\n            private readonly BufferSlice _slice;\n            private int _position;\n            private SequenceSegment _segment;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"SpanEnumerator\"/> type.\n            /// </summary>\n            /// <param name=\"slice\">The slice to enumerate.</param>\n            public SpanEnumerator(BufferSlice slice)\n            {\n                _slice = slice;\n                _segment = InitialSegmentSentinel;\n                Current = Span<byte>.Empty;\n            }\n\n            internal readonly PooledBuffer Buffer => _slice._buffer;\n            internal readonly int Offset => _slice._offset;\n            internal readonly int Length => _slice._length;\n\n            /// <summary>\n            /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n            /// </summary>\n            /// <returns>An enumerator for the data contained in this instance.</returns>\n            public readonly SpanEnumerator GetEnumerator() => this;\n\n            /// <summary>\n            /// Gets the element in the collection at the current position of the enumerator.\n            /// </summary>\n            public ReadOnlySpan<byte> Current { get; private set; }\n\n            /// <summary>\n            /// Advances the enumerator to the next element of the collection.\n            /// </summary>\n            /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n            public bool MoveNext()\n            {\n                if (ReferenceEquals(_segment, InitialSegmentSentinel))\n                {\n                    _segment = Buffer.First;\n                }\n\n                var endPosition = Offset + Length;\n                while (_segment != null && _segment != FinalSegmentSentinel)\n                {\n                    var segment = _segment.CommittedMemory.Span;\n\n                    // Find the starting segment and the offset to copy from.\n                    int segmentOffset;\n                    if (_position < Offset)\n                    {\n                        if (_position + segment.Length <= Offset)\n                        {\n                            // Start is in a subsequent segment\n                            _position += segment.Length;\n                            _segment = _segment.Next as SequenceSegment;\n                            continue;\n                        }\n                        else\n                        {\n                            // Start is in this segment\n                            segmentOffset = Offset - _position;\n                        }\n                    }\n                    else\n                    {\n                        segmentOffset = 0;\n                    }\n\n                    var segmentLength = Math.Min(segment.Length - segmentOffset, endPosition - (_position + segmentOffset));\n                    if (segmentLength == 0)\n                    {\n                        Current = Span<byte>.Empty;\n                        _segment = FinalSegmentSentinel;\n                        return false;\n                    }\n\n                    Current = segment.Slice(segmentOffset, segmentLength);\n                    _position += segmentOffset + segmentLength;\n                    _segment = _segment.Next as SequenceSegment;\n                    return true;\n                }\n\n                // Account for the uncommitted data at the end of the buffer.\n                // The write head is only linked to the previous buffers when Commit() is called and it is set to null afterwards,\n                // meaning that if the write head is not null, the other buffers are not linked to it and it therefore has not been enumerated.\n                if (_segment != FinalSegmentSentinel && Buffer.CurrentPosition > 0 && Buffer.WriteHead is { } head && _position < endPosition)\n                {\n                    var finalOffset = Math.Max(Offset - _position, 0);\n                    var finalLength = Math.Min(Buffer.CurrentPosition, endPosition - (_position + finalOffset));\n                    if (finalLength == 0)\n                    {\n                        Current = Span<byte>.Empty;\n                        _segment = FinalSegmentSentinel;\n                        return false;\n                    }\n\n                    Current = head.Array.AsSpan(finalOffset, finalLength);\n                    _position += finalOffset + finalLength;\n                    Debug.Assert(_position == endPosition);\n                    _segment = FinalSegmentSentinel;\n                    return true;\n                }\n\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Enumerates over sequences of bytes in a <see cref=\"BufferSlice\"/>.\n        /// </summary>\n        public struct MemoryEnumerator\n        {\n            private static readonly SequenceSegment InitialSegmentSentinel = new();\n            private static readonly SequenceSegment FinalSegmentSentinel = new();\n            private readonly BufferSlice _slice;\n            private int _position;\n            private SequenceSegment _segment;\n\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"MemoryEnumerator\"/> type.\n            /// </summary>\n            /// <param name=\"slice\">The slice to enumerate.</param>\n            public MemoryEnumerator(BufferSlice slice)\n            {\n                _slice = slice;\n                _segment = InitialSegmentSentinel;\n                Current = ReadOnlyMemory<byte>.Empty;\n            }\n\n            internal readonly PooledBuffer Buffer => _slice._buffer;\n            internal readonly int Offset => _slice._offset;\n            internal readonly int Length => _slice._length;\n\n            /// <summary>\n            /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n            /// </summary>\n            /// <returns>An enumerator for the data contained in this instance.</returns>\n            public readonly MemoryEnumerator GetEnumerator() => this;\n\n            /// <summary>\n            /// Gets the element in the collection at the current position of the enumerator.\n            /// </summary>\n            public ReadOnlyMemory<byte> Current { get; private set; }\n\n            /// <summary>\n            /// Advances the enumerator to the next element of the collection.\n            /// </summary>\n            /// <returns><see langword=\"true\"/> if the enumerator was successfully advanced to the next element; <see langword=\"false\"/> if the enumerator has passed the end of the collection.</returns>\n            public bool MoveNext()\n            {\n                if (ReferenceEquals(_segment, InitialSegmentSentinel))\n                {\n                    _segment = Buffer.First;\n                }\n\n                var endPosition = Offset + Length;\n                while (_segment != null && _segment != FinalSegmentSentinel)\n                {\n                    var segment = _segment.CommittedMemory;\n\n                    // Find the starting segment and the offset to copy from.\n                    int segmentOffset;\n                    if (_position < Offset)\n                    {\n                        if (_position + segment.Length <= Offset)\n                        {\n                            // Start is in a subsequent segment\n                            _position += segment.Length;\n                            _segment = _segment.Next as SequenceSegment;\n                            continue;\n                        }\n                        else\n                        {\n                            // Start is in this segment\n                            segmentOffset = Offset - _position;\n                        }\n                    }\n                    else\n                    {\n                        segmentOffset = 0;\n                    }\n\n                    var segmentLength = Math.Min(segment.Length - segmentOffset, endPosition - (_position + segmentOffset));\n                    if (segmentLength == 0)\n                    {\n                        Current = ReadOnlyMemory<byte>.Empty;\n                        _segment = FinalSegmentSentinel;\n                        return false;\n                    }\n\n                    Current = segment.Slice(segmentOffset, segmentLength);\n                    _position += segmentOffset + segmentLength;\n                    _segment = _segment.Next as SequenceSegment;\n                    return true;\n                }\n\n                // Account for the uncommitted data at the end of the buffer.\n                // The write head is only linked to the previous buffers when Commit() is called and it is set to null afterwards,\n                // meaning that if the write head is not null, the other buffers are not linked to it and it therefore has not been enumerated.\n                if (_segment != FinalSegmentSentinel && Buffer.CurrentPosition > 0 && Buffer.WriteHead is { } head && _position < endPosition)\n                {\n                    var finalOffset = Math.Max(Offset - _position, 0);\n                    var finalLength = Math.Min(Buffer.CurrentPosition, endPosition - (_position + finalOffset));\n                    if (finalLength == 0)\n                    {\n                        Current = ReadOnlyMemory<byte>.Empty;\n                        _segment = FinalSegmentSentinel;\n                        return false;\n                    }\n\n                    Current = head.Array.AsMemory(finalOffset, finalLength);\n                    _position += finalOffset + finalLength;\n                    Debug.Assert(_position == endPosition);\n                    _segment = FinalSegmentSentinel;\n                    return true;\n                }\n\n                return false;\n            }\n        }\n    }\n\n    private sealed class SequenceSegmentPool\n    {\n        public static SequenceSegmentPool Shared { get; } = new();\n        public const int MinimumBlockSize = 4 * 1024;\n        private readonly ConcurrentQueue<SequenceSegment> _blocks = new();\n        private readonly ConcurrentQueue<SequenceSegment> _largeBlocks = new();\n\n        private SequenceSegmentPool() { }\n\n        public SequenceSegment Rent(int size = -1)\n        {\n            SequenceSegment block;\n            if (size <= MinimumBlockSize)\n            {\n                return _blocks.TryDequeue(out block) ? block : new(large: false);\n            }\n\n            if (!_largeBlocks.TryDequeue(out block))\n            {\n                block = new(large: true);\n            }\n            block.ResizeLargeSegment(size);\n            return block;\n        }\n\n        internal void Return(SequenceSegment block)\n        {\n            Debug.Assert(block.IsValid);\n            (block.IsMinimumSize ? _blocks : _largeBlocks).Enqueue(block);\n        }\n    }\n\n    internal sealed class SequenceSegment : ReadOnlySequenceSegment<byte>\n    {\n        internal SequenceSegment()\n        {\n            Array = System.Array.Empty<byte>();\n        }\n\n        internal SequenceSegment(bool large)\n        {\n            if (!large)\n            {\n#if NET6_0_OR_GREATER\n                Array = GC.AllocateUninitializedArray<byte>(SequenceSegmentPool.MinimumBlockSize, pinned: true);\n#else\n                Array = new byte[SequenceSegmentPool.MinimumBlockSize];\n#endif\n            }\n        }\n\n        public void ResizeLargeSegment(int length)\n        {\n            Debug.Assert(length > SequenceSegmentPool.MinimumBlockSize);\n            // Round up to a power of two.\n            length = (int)BitOperations.RoundUpToPowerOf2((uint)length);\n\n            if (Array is { } array)\n            {\n                // The segment has an appropriate size already.\n                if (array.Length == length)\n                {\n                    return;\n                }\n\n                // The segment is being resized.\n                Array = null;\n                ArrayPool<byte>.Shared.Return(array);\n            }\n\n            Array = ArrayPool<byte>.Shared.Rent(length);\n        }\n\n        public byte[] Array { get; private set; }\n\n        public ReadOnlyMemory<byte> CommittedMemory => Memory;\n\n        public bool IsValid => Array is { Length: > 0 };\n        public bool IsMinimumSize => Array.Length == SequenceSegmentPool.MinimumBlockSize;\n\n        public Memory<byte> AsMemory(int offset)\n        {\n#if NET6_0_OR_GREATER\n            if (IsMinimumSize)\n            {\n                return MemoryMarshal.CreateFromPinnedArray(Array, offset, Array.Length - offset);\n            }\n#endif\n\n            return Array.AsMemory(offset);\n        }\n\n        public Memory<byte> AsMemory(int offset, int length)\n        {\n#if NET6_0_OR_GREATER\n            if (IsMinimumSize)\n            {\n                return MemoryMarshal.CreateFromPinnedArray(Array, offset, length);\n            }\n#endif\n\n            return Array.AsMemory(offset, length);\n        }\n\n        public void Commit(long runningIndex, int length)\n        {\n            RunningIndex = runningIndex;\n            Memory = AsMemory(0, length);\n        }\n\n        public void SetNext(SequenceSegment next) => Next = next;\n\n        public void Return()\n        {\n            RunningIndex = default;\n            Next = default;\n            Memory = default;\n\n            SequenceSegmentPool.Shared.Return(this);\n        }\n    }\n}\n\n/// <summary>\n/// Extensions for <see cref=\"PooledBuffer\"/>.\n/// </summary>\npublic static class PooledBufferExtensions\n{\n    /// <summary>\n    /// Returns an enumerator which can be used to enumerate the data referenced by this instance.\n    /// </summary>\n    /// <returns>An enumerator for the data contained in this instance.</returns>\n    public static PooledBuffer.SpanEnumerator GetEnumerator(this ref PooledBuffer buffer) => new(ref buffer);\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Reader.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Binary;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\n#if NETCOREAPP3_1_OR_GREATER\nusing System.Numerics;\n#endif\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Session;\nusing static Orleans.Serialization.Buffers.PooledBuffer;\n#if !NETCOREAPP3_1_OR_GREATER\nusing Orleans.Serialization.Utilities;\n#endif\n\nnamespace Orleans.Serialization.Buffers\n{\n    /// <summary>\n    /// Functionality for reading binary data.\n    /// </summary>\n    public abstract class ReaderInput\n    {\n        /// <summary>\n        /// Gets the position.\n        /// </summary>\n        /// <value>The position.</value>\n        public abstract long Position { get; }\n\n        /// <summary>\n        /// Gets the length.\n        /// </summary>\n        /// <value>The length.</value>\n        public abstract long Length { get; }\n\n        /// <summary>\n        /// Skips the specified number of bytes.\n        /// </summary>\n        /// <param name=\"count\">The number of bytes to skip.</param>\n        public abstract void Skip(long count);\n\n        /// <summary>\n        /// Seeks to the specified position.\n        /// </summary>\n        /// <param name=\"position\">The position.</param>\n        public abstract void Seek(long position);\n\n        /// <summary>\n        /// Reads a byte from the input.\n        /// </summary>\n        /// <returns>The byte which was read.</returns>\n        public abstract byte ReadByte();\n\n        /// <summary>\n        /// Reads a <see cref=\"uint\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"uint\"/> which was read.</returns>\n        public abstract uint ReadUInt32();\n\n        /// <summary>\n        /// Reads a <see cref=\"ulong\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"ulong\"/> which was read.</returns>\n        public abstract ulong ReadUInt64();\n\n        /// <summary>\n        /// Fills the destination span with data from the input.\n        /// </summary>\n        /// <param name=\"destination\">The destination.</param>\n        public abstract void ReadBytes(Span<byte> destination);\n\n        /// <summary>\n        /// Reads bytes from the input into the destination array.\n        /// </summary>\n        /// <param name=\"destination\">The destination array.</param>\n        /// <param name=\"offset\">The offset into the destination to start writing bytes.</param>\n        /// <param name=\"length\">The number of bytes to copy into destination.</param>\n        public abstract void ReadBytes(byte[] destination, int offset, int length);\n\n        /// <summary>\n        /// Tries to read the specified number of bytes from the input.\n        /// </summary>\n        /// <param name=\"length\">The number of bytes to read..</param>\n        /// <param name=\"bytes\">The bytes which were read..</param>\n        /// <returns><see langword=\"true\"/> if the number of bytes were successfully read, <see langword=\"false\"/> otherwise.</returns>\n        public abstract bool TryReadBytes(int length, out ReadOnlySpan<byte> bytes);\n    }\n\n    internal sealed class StreamReaderInput : ReaderInput\n    {\n        [ThreadStatic]\n        private static byte[] Scratch;\n\n        private readonly Stream _stream;\n        private readonly ArrayPool<byte> _memoryPool;\n\n        public override long Position => _stream.Position;\n        public override long Length => _stream.Length;\n\n        public StreamReaderInput(Stream stream, ArrayPool<byte> memoryPool)\n        {\n            _stream = stream;\n            _memoryPool = memoryPool;\n        }\n\n        public override byte ReadByte()\n        {\n            var c = _stream.ReadByte();\n            if (c < 0)\n            {\n                ThrowInsufficientData();\n            }\n\n            return (byte)c;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public override void ReadBytes(Span<byte> destination)\n        {\n            var count = _stream.Read(destination);\n            if (count < destination.Length)\n            {\n                ThrowInsufficientData();\n            }\n        }\n\n        public override void ReadBytes(byte[] destination, int offset, int length)\n        {\n            var count = _stream.Read(destination, offset, length);\n            if (count < length)\n            {\n                ThrowInsufficientData();\n            }\n        }\n\n#if NET5_0_OR_GREATER\n        [SkipLocalsInit]\n#endif\n        public override uint ReadUInt32()\n        {\n            Span<byte> buffer = stackalloc byte[sizeof(uint)];\n            ReadBytes(buffer);\n            return BinaryPrimitives.ReadUInt32LittleEndian(buffer);\n        }\n\n#if NET5_0_OR_GREATER\n        [SkipLocalsInit]\n#endif\n        public override ulong ReadUInt64()\n        {\n            Span<byte> buffer = stackalloc byte[sizeof(ulong)];\n            ReadBytes(buffer);\n            return BinaryPrimitives.ReadUInt64LittleEndian(buffer);\n        }\n\n        public override void Skip(long count) => _ = _stream.Seek(count, SeekOrigin.Current);\n\n        public override void Seek(long position) => _ = _stream.Seek(position, SeekOrigin.Begin);\n\n        public override bool TryReadBytes(int length, out ReadOnlySpan<byte> destination)\n        {\n            // Cannot get a span pointing to a stream's internal buffer.\n            destination = default;\n            return false;\n        }\n\n        private static void ThrowInsufficientData() => throw new InvalidOperationException(\"Insufficient data present in buffer.\");\n\n        private static byte[] GetScratchBuffer() => Scratch ??= new byte[1024];\n    }\n\n    /// <summary>\n    /// Helper methods for <see cref=\"Reader{TInput}\"/>.\n    /// </summary>\n    public static class Reader\n    {\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<BufferSliceReaderInput> Create(PooledBuffer input, SerializerSession session) => Create(input.Slice(), session);\n\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<BufferSliceReaderInput> Create(BufferSlice input, SerializerSession session) => new(new BufferSliceReaderInput(in input), session, 0);\n\n        /// <summary>\n        /// Creates a reader for the provided input stream.\n        /// </summary>\n        /// <param name=\"stream\">The stream.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<ReaderInput> Create(Stream stream, SerializerSession session) => new(new StreamReaderInput(stream, ArrayPool<byte>.Shared), session, 0);\n\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"sequence\">The buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<ReadOnlySequenceInput> Create(ReadOnlySequence<byte> sequence, SerializerSession session) => new(new ReadOnlySequenceInput { Sequence = sequence }, session, 0);\n\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<SpanReaderInput> Create(ReadOnlySpan<byte> buffer, SerializerSession session) => new(buffer, session, 0);\n\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<SpanReaderInput> Create(byte[] buffer, SerializerSession session) => new(buffer, session, 0);\n\n        /// <summary>\n        /// Creates a reader for the provided buffer.\n        /// </summary>\n        /// <param name=\"buffer\">The buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Reader{TInput}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Reader<SpanReaderInput> Create(ReadOnlyMemory<byte> buffer, SerializerSession session) => new(buffer.Span, session, 0);\n    }\n\n    /// <summary>\n    /// Marker type for <see cref=\"Reader{TInput}\"/> objects which operate over <see cref=\"ReadOnlySpan{Byte}\"/> buffers.\n    /// </summary>\n    public readonly struct SpanReaderInput\n    {\n    }\n\n    /// <summary>\n    /// Input type for <see cref=\"Reader{TInput}\"/> to support <see cref=\"ReadOnlySequence{Byte}\"/> buffers.\n    /// </summary>\n    public struct ReadOnlySequenceInput\n    {\n        internal ReadOnlySequence<byte> Sequence;\n        internal SequencePosition NextSequencePosition;\n        internal long PreviousBuffersSize;\n    }\n\n    /// <summary>\n    /// Provides functionality for parsing data from binary input.\n    /// </summary>\n    /// <typeparam name=\"TInput\">The underlying buffer reader type.</typeparam>\n    public ref struct Reader<TInput>\n    {\n        private readonly static bool IsSpanInput = typeof(TInput) == typeof(SpanReaderInput);\n        private readonly static bool IsReadOnlySequenceInput = typeof(TInput) == typeof(ReadOnlySequenceInput);\n        private readonly static bool IsReaderInput = typeof(ReaderInput).IsAssignableFrom(typeof(TInput));\n        private readonly static bool IsBufferSliceInput = typeof(TInput) == typeof(BufferSliceReaderInput);\n\n        private ReadOnlySpan<byte> _currentSpan;\n        private int _bufferPos;\n        private int _bufferSize;\n        private readonly long _sequenceOffset;\n        private TInput _input;\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal Reader(TInput input, SerializerSession session, long globalOffset)\n        {\n            if (IsReadOnlySequenceInput)\n            {\n                ref var typedInput = ref Unsafe.As<TInput, ReadOnlySequenceInput>(ref input);\n                var sequence = typedInput.Sequence;\n                typedInput.NextSequencePosition = sequence.Start;\n                _input = input;\n                _currentSpan = sequence.First.Span;\n                _bufferPos = 0;\n                _bufferSize = _currentSpan.Length;\n                _sequenceOffset = globalOffset;\n            }\n            else if (IsBufferSliceInput)\n            {\n                _input = input;\n                ref var slice = ref Unsafe.As<TInput, BufferSliceReaderInput>(ref _input);\n                _currentSpan = slice.GetNext();\n                _bufferPos = 0;\n                _bufferSize = _currentSpan.Length;\n                _sequenceOffset = globalOffset;\n            }\n            else if (IsReaderInput)\n            {\n                _input = input;\n                _currentSpan = default;\n                _bufferPos = 0;\n                _bufferSize = default;\n                _sequenceOffset = globalOffset;\n            }\n            else\n            {\n                throw new NotSupportedException($\"Type {typeof(TInput)} is not supported by this constructor\");\n            }\n\n            Session = session;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal Reader(ReadOnlySpan<byte> input, SerializerSession session, long globalOffset)\n        {\n            if (IsSpanInput)\n            {\n                _input = default;\n                _currentSpan = input;\n                _bufferPos = 0;\n                _bufferSize = _currentSpan.Length;\n                _sequenceOffset = globalOffset;\n            }\n            else\n            {\n                throw new NotSupportedException($\"Type {typeof(TInput)} is not supported by this constructor\");\n            }\n\n            Session = session;\n        }\n\n        /// <summary>\n        /// Gets the serializer session.\n        /// </summary>\n        /// <value>The serializer session.</value>\n        public SerializerSession Session { get; }\n\n        /// <summary>\n        /// Gets the current reader position.\n        /// </summary>\n        /// <value>The current position.</value>\n        public long Position\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get\n            {\n                if (IsReadOnlySequenceInput)\n                {\n                    var previousBuffersSize = Unsafe.As<TInput, ReadOnlySequenceInput>(ref _input).PreviousBuffersSize;\n                    return _sequenceOffset + previousBuffersSize + _bufferPos;\n                }\n                else if (IsBufferSliceInput)\n                {\n                    var previousBuffersSize = Unsafe.As<TInput, BufferSliceReaderInput>(ref _input).PreviousBuffersSize;\n                    return _sequenceOffset + previousBuffersSize + _bufferPos;\n                }\n                else if (IsSpanInput)\n                {\n                    return _sequenceOffset + _bufferPos;\n                }\n                else if (_input is ReaderInput readerInput)\n                {\n                    return readerInput.Position;\n                }\n                else\n                {\n                    return ThrowNotSupportedInput<long>();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets the input length.\n        /// </summary>\n        /// <value>The input length.</value>\n        public long Length\n        {\n            get\n            {\n                if (IsReadOnlySequenceInput)\n                {\n                    return Unsafe.As<TInput, ReadOnlySequenceInput>(ref _input).Sequence.Length;\n                }\n                else if (IsBufferSliceInput)\n                {\n                    return Unsafe.As<TInput, BufferSliceReaderInput>(ref _input).Length;\n                }\n                else if (IsSpanInput)\n                {\n                    return _currentSpan.Length;\n                }\n                else if (_input is ReaderInput readerInput)\n                {\n                    return readerInput.Length;\n                }\n                else\n                {\n                    return ThrowNotSupportedInput<long>();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Skips the specified number of bytes.\n        /// </summary>\n        /// <param name=\"count\">The number of bytes to skip.</param>\n        public void Skip(long count)\n        {\n            if (IsReadOnlySequenceInput)\n            {\n                var end = Position + count;\n                while (Position < end)\n                {\n                    var previousBuffersSize = Unsafe.As<TInput, ReadOnlySequenceInput>(ref _input).PreviousBuffersSize;\n                    if (end - previousBuffersSize <= _bufferSize)\n                    {\n                        _bufferPos = (int)(end - previousBuffersSize);\n                    }\n                    else\n                    {\n                        MoveNext();\n                    }\n                }\n            }\n            else if (IsBufferSliceInput)\n            {\n                var end = Position + count;\n                while (Position < end)\n                {\n                    var previousBuffersSize = Unsafe.As<TInput, BufferSliceReaderInput>(ref _input).PreviousBuffersSize;\n                    if (end - previousBuffersSize <= _bufferSize)\n                    {\n                        _bufferPos = (int)(end - previousBuffersSize);\n                    }\n                    else\n                    {\n                        MoveNext();\n                    }\n                }\n            }\n            else if (IsSpanInput)\n            {\n                _bufferPos += (int)count;\n                if (_bufferPos > _currentSpan.Length || count > int.MaxValue)\n                {\n                    ThrowInsufficientData();\n                }\n            }\n            else if (_input is ReaderInput input)\n            {\n                input.Skip(count);\n            }\n            else\n            {\n                ThrowNotSupportedInput();\n            }\n        }\n\n        /// <summary>\n        /// Creates a new reader beginning at the specified position.\n        /// </summary>        \n        /// <param name=\"position\">\n        /// The position in the input stream to fork from.\n        /// </param>        \n        /// <param name=\"forked\">\n        /// The forked reader instance.\n        /// </param>        \n        public void ForkFrom(long position, out Reader<TInput> forked)\n        {\n            if (IsReadOnlySequenceInput)\n            {\n                ref var typedInput = ref Unsafe.As<TInput, ReadOnlySequenceInput>(ref _input);\n                var slicedSequence = typedInput.Sequence.Slice(position - _sequenceOffset);\n                var newInput = new ReadOnlySequenceInput\n                {\n                    Sequence = slicedSequence\n                };\n                forked = new Reader<TInput>(Unsafe.As<ReadOnlySequenceInput, TInput>(ref newInput), Session, position);\n\n                if (forked.Position != position)\n                {\n                    ThrowInvalidPosition(position, forked.Position);\n                }\n            }\n            else if (IsBufferSliceInput)\n            {\n                ref var input = ref Unsafe.As<TInput, BufferSliceReaderInput>(ref _input);\n                var newInput = input.ForkFrom(checked((int)position));\n                forked = new Reader<TInput>(Unsafe.As<BufferSliceReaderInput, TInput>(ref newInput), Session, position);\n\n                if (forked.Position != position)\n                {\n                    ThrowInvalidPosition(position, forked.Position);\n                }\n            }\n            else if (IsSpanInput)\n            {\n                forked = new Reader<TInput>(_currentSpan[(int)position..], Session, position);\n                if (forked.Position != position || position > int.MaxValue)\n                {\n                    ThrowInvalidPosition(position, forked.Position);\n                }\n            }\n            else if (_input is ReaderInput input)\n            {\n                input.Seek(position);\n                forked = new Reader<TInput>(_input, Session, 0);\n\n                if (forked.Position != position)\n                {\n                    ThrowInvalidPosition(position, forked.Position);\n                }\n            }\n            else\n            {\n                throw new NotSupportedException($\"Type {typeof(TInput)} is not supported\");\n            }\n\n            static void ThrowInvalidPosition(long expectedPosition, long actualPosition)\n            {\n                throw new InvalidOperationException($\"Expected to arrive at position {expectedPosition} after ForkFrom, but resulting position is {actualPosition}\");\n            }\n        }\n\n        /// <summary>\n        /// Resumes the reader from the specified position after forked readers are no longer in use.\n        /// </summary>\n        /// <param name=\"position\">\n        /// The position to resume reading from.\n        /// </param>\n        public void ResumeFrom(long position)\n        {\n            if (IsReadOnlySequenceInput)\n            {\n                // Nothing is required.\n            }\n            else if (IsBufferSliceInput)\n            {\n                // Nothing is required.\n            }\n            else if (IsSpanInput)\n            {\n                // Nothing is required.\n            }\n            else if (_input is ReaderInput input)\n            {\n                // Seek the input stream.\n                input.Seek(Position);\n            }\n            else\n            {\n                throw new NotSupportedException($\"Type {typeof(TInput)} is not supported\");\n            }\n\n            if (position != Position)\n            {\n                ThrowInvalidPosition(position, Position);\n            }\n\n            static void ThrowInvalidPosition(long expectedPosition, long actualPosition)\n            {\n                throw new InvalidOperationException($\"Expected to arrive at position {expectedPosition} after ResumeFrom, but resulting position is {actualPosition}\");\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void MoveNext()\n        {\n            if (IsReadOnlySequenceInput)\n            {\n                ref var typedInput = ref Unsafe.As<TInput, ReadOnlySequenceInput>(ref _input);\n                typedInput.PreviousBuffersSize += _bufferSize;\n\n                // If this is the first call to MoveNext then nextSequencePosition is invalid and must be moved to the second position.\n                if (typedInput.NextSequencePosition.Equals(typedInput.Sequence.Start))\n                {\n                    _ = typedInput.Sequence.TryGet(ref typedInput.NextSequencePosition, out _);\n                }\n\n                if (!typedInput.Sequence.TryGet(ref typedInput.NextSequencePosition, out var memory))\n                {\n                    _currentSpan = memory.Span;\n                    ThrowInsufficientData();\n                }\n\n                _currentSpan = memory.Span;\n                _bufferPos = 0;\n                _bufferSize = _currentSpan.Length;\n            }\n            else if (IsBufferSliceInput)\n            {\n                ref var slice = ref Unsafe.As<TInput, BufferSliceReaderInput>(ref _input);\n                slice.PreviousBuffersSize += _bufferSize;\n                _currentSpan = slice.GetNext();\n                _bufferPos = 0;\n                _bufferSize = _currentSpan.Length;\n            }\n            else if (IsSpanInput)\n            {\n                ThrowInsufficientData();\n            }\n            else\n            {\n                ThrowNotSupportedInput();\n            }\n        }\n\n        /// <summary>\n        /// Reads a byte from the input.\n        /// </summary>\n        /// <returns>The byte which was read.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public byte ReadByte()\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                var pos = _bufferPos;\n                if ((uint)pos < (uint)_currentSpan.Length)\n                {\n                    // https://github.com/dotnet/runtime/issues/72004\n                    var result = Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), (uint)pos);\n                    _bufferPos = pos + 1;\n                    return result;\n                }\n\n                return ReadByteSlow(ref this);\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                return readerInput.ReadByte();\n            }\n            else\n            {\n                return ThrowNotSupportedInput<byte>();\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static byte ReadByteSlow(ref Reader<TInput> reader)\n        {\n            reader.MoveNext();\n            return reader._currentSpan[reader._bufferPos++];\n        }\n\n        /// <summary>\n        /// Reads an <see cref=\"int\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"int\"/> which was read.</returns>\n        public int ReadInt32() => (int)ReadUInt32();\n\n        /// <summary>\n        /// Reads a <see cref=\"uint\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"uint\"/> which was read.</returns>\n        public uint ReadUInt32()\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                const int width = 4;\n                if (_bufferPos + width > _bufferSize)\n                {\n                    return ReadSlower(ref this);\n                }\n\n                var result = BinaryPrimitives.ReadUInt32LittleEndian(_currentSpan.Slice(_bufferPos, width));\n                _bufferPos += width;\n                return result;\n\n                static uint ReadSlower(ref Reader<TInput> r)\n                {\n                    uint b1 = r.ReadByte();\n                    uint b2 = r.ReadByte();\n                    uint b3 = r.ReadByte();\n                    uint b4 = r.ReadByte();\n\n                    return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);\n                }\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                return readerInput.ReadUInt32();\n            }\n            else\n            {\n                return ThrowNotSupportedInput<uint>();\n            }\n        }\n\n        /// <summary>\n        /// Reads a <see cref=\"long\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"long\"/> which was read.</returns>\n        public long ReadInt64() => (long)ReadUInt64();\n\n        /// <summary>\n        /// Reads a <see cref=\"ulong\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"ulong\"/> which was read.</returns>\n        public ulong ReadUInt64()\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                const int width = 8;\n                if (_bufferPos + width > _bufferSize)\n                {\n                    return ReadSlower(ref this);\n                }\n\n                var result = BinaryPrimitives.ReadUInt64LittleEndian(_currentSpan.Slice(_bufferPos, width));\n                _bufferPos += width;\n                return result;\n\n                static ulong ReadSlower(ref Reader<TInput> r)\n                {\n                    ulong b1 = r.ReadByte();\n                    ulong b2 = r.ReadByte();\n                    ulong b3 = r.ReadByte();\n                    ulong b4 = r.ReadByte();\n                    ulong b5 = r.ReadByte();\n                    ulong b6 = r.ReadByte();\n                    ulong b7 = r.ReadByte();\n                    ulong b8 = r.ReadByte();\n\n                    return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)\n                           | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);\n                }\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                return readerInput.ReadUInt64();\n            }\n            else\n            {\n                return ThrowNotSupportedInput<uint>();\n            }\n        }\n\n        [DoesNotReturn]\n        private static void ThrowInsufficientData() => throw new InvalidOperationException(\"Insufficient data present in buffer.\");\n\n        /// <summary>\n        /// Reads the specified number of bytes into the provided writer.\n        /// </summary>\n        public void ReadBytes<TBufferWriter>(scoped ref TBufferWriter writer, int count) where TBufferWriter : IBufferWriter<byte>\n        {\n            int chunkSize;\n            for (var remaining = count; remaining > 0; remaining -= chunkSize)\n            {\n                var span = writer.GetSpan();\n                if (span.Length > remaining)\n                {\n                    span = span[..remaining];\n                }\n\n                ReadBytes(span);\n                chunkSize = span.Length;\n                writer.Advance(chunkSize);\n            }\n        }\n\n        /// <summary>\n        /// Reads an array of bytes from the input.\n        /// </summary>\n        /// <param name=\"count\">The length of the array to read.</param>\n        /// <returns>The array wihch was read.</returns>\n        public byte[] ReadBytes(uint count)\n        {\n            if (count == 0)\n            {\n                return Array.Empty<byte>();\n            }\n\n            if (count > 10240 && count > Length)\n            {\n                ThrowInvalidSizeException(count);\n            }\n\n            var bytes = new byte[count];\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                var destination = new Span<byte>(bytes);\n                ReadBytes(destination);\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                readerInput.ReadBytes(bytes, 0, (int)count);\n            }\n\n            return bytes;\n        }\n\n        /// <summary>\n        /// Fills <paramref name=\"destination\"/> with bytes read from the input.\n        /// </summary>\n        /// <param name=\"destination\">The destination.</param>\n        public void ReadBytes(scoped Span<byte> destination)\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                if (_bufferPos + destination.Length <= _bufferSize)\n                {\n                    _currentSpan.Slice(_bufferPos, destination.Length).CopyTo(destination);\n                    _bufferPos += destination.Length;\n                    return;\n                }\n\n                ReadBytesMultiSegment(destination);\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                readerInput.ReadBytes(destination);\n            }\n            else\n            {\n                ThrowNotSupportedInput();\n            }\n        }\n\n        private void ReadBytesMultiSegment(scoped Span<byte> dest)\n        {\n            while (true)\n            {\n                var writeSize = Math.Min(dest.Length, _currentSpan.Length - _bufferPos);\n                _currentSpan.Slice(_bufferPos, writeSize).CopyTo(dest);\n                _bufferPos += writeSize;\n                dest = dest[writeSize..];\n\n                if (dest.Length == 0)\n                {\n                    break;\n                }\n\n                MoveNext();\n            }\n        }\n\n        /// <summary>\n        /// Tries the read the specified number of bytes from the input.\n        /// </summary>\n        /// <param name=\"length\">The length.</param>\n        /// <param name=\"bytes\">The bytes which were read.</param>\n        /// <returns><see langword=\"true\"/> if the specified number of bytes were read from the input, <see langword=\"false\"/> otherwise.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool TryReadBytes(int length, out ReadOnlySpan<byte> bytes)\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                if (_bufferPos + length <= _bufferSize)\n                {\n                    bytes = _currentSpan.Slice(_bufferPos, length);\n                    _bufferPos += length;\n                    return true;\n                }\n\n                bytes = default;\n                return false;\n            }\n            else if (_input is ReaderInput readerInput)\n            {\n                return readerInput.TryReadBytes(length, out bytes);\n            }\n            else\n            {\n                bytes = default;\n                return ThrowNotSupportedInput<bool>();\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        internal uint ReadVarUInt32NoInlining() => ReadVarUInt32();\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"uint\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"uint\"/> which was read.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public unsafe uint ReadVarUInt32()\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                var pos = _bufferPos;\n\n                if (!BitConverter.IsLittleEndian || pos + 8 > _currentSpan.Length)\n                {\n                    return ReadVarUInt32Slow();\n                }\n\n                // The number of zeros in the msb position dictates the number of bytes to be read.\n                // Up to a maximum of 5 for a 32bit integer.\n                ref byte readHead = ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos);\n\n                ulong result = Unsafe.ReadUnaligned<ulong>(ref readHead);\n                var bytesNeeded = BitOperations.TrailingZeroCount((uint)result) + 1;\n                if (bytesNeeded > 5) ThrowOverflowException();\n                _bufferPos = pos + bytesNeeded;\n                result &= (1UL << (bytesNeeded * 8)) - 1;\n                result >>= bytesNeeded;\n                return checked((uint)result);\n            }\n            else\n            {\n                return ReadVarUInt32Slow();\n            }\n        }\n\n        private static void ThrowOverflowException() => throw new OverflowException();\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private uint ReadVarUInt32Slow()\n        {\n            var header = ReadByte();\n            var numBytes = BitOperations.TrailingZeroCount(0x0100U | header) + 1;\n\n            // Widen to a ulong for the 5-byte case\n            ulong result = header;\n\n            // Read additional bytes as needed\n            var shiftBy = 8;\n            var i = numBytes;\n            while (--i > 0)\n            {\n                result |= (ulong)ReadByte() << shiftBy;\n                shiftBy += 8;\n            }\n\n            result >>= numBytes;\n            return checked((uint)result);\n        }\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"ulong\"/> from the input.\n        /// </summary>\n        /// <returns>The <see cref=\"ulong\"/> which was read.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public ulong ReadVarUInt64()\n        {\n            if (IsReadOnlySequenceInput || IsSpanInput || IsBufferSliceInput)\n            {\n                var pos = _bufferPos;\n\n                if (!BitConverter.IsLittleEndian || pos + 10 > _currentSpan.Length)\n                {\n                    return ReadVarUInt64Slow();\n                }\n\n                // The number of zeros in the msb position dictates the number of bytes to be read.\n                // Up to a maximum of 5 for a 32bit integer.\n                ref byte readHead = ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos);\n\n                ulong result = Unsafe.ReadUnaligned<ulong>(ref readHead);\n\n                var bytesNeeded = BitOperations.TrailingZeroCount(result) + 1;\n                result >>= bytesNeeded;\n                _bufferPos += bytesNeeded;\n\n                ushort upper = Unsafe.ReadUnaligned<ushort>(ref Unsafe.Add(ref readHead, sizeof(ulong)));\n                result |= ((ulong)upper) << (64 - bytesNeeded);\n\n                // Mask off invalid data\n                var fullWidthReadMask = ~((ulong)bytesNeeded - 10 + 1);\n                var mask = ((1UL << (bytesNeeded * 7)) - 1) | fullWidthReadMask;\n                result &= mask;\n\n                return result;\n            }\n            else\n            {\n                return ReadVarUInt64Slow();\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private ulong ReadVarUInt64Slow()\n        {\n            var header = ReadByte();\n            var numBytes = BitOperations.TrailingZeroCount(0x0100U | header) + 1;\n\n            // Widen to a ulong for the 5-byte case\n            ulong result = header;\n\n            // Read additional bytes as needed\n            if (numBytes < 9)\n            {\n                var shiftBy = 8;\n                var i = numBytes;\n                while (--i > 0)\n                {\n                    result |= (ulong)ReadByte() << shiftBy;\n                    shiftBy += 8;\n                }\n\n                result >>= numBytes;\n                return result;\n            }\n            else\n            {\n                result |= (ulong)ReadByte() << 8;\n\n                // If there was more than one byte worth of trailing zeros, read again now that we have more data.\n                numBytes = BitOperations.TrailingZeroCount(result) + 1;\n\n                if (numBytes == 9)\n                {\n                    result |= (ulong)ReadByte() << 16;\n                    result |= (ulong)ReadByte() << 24;\n                    result |= (ulong)ReadByte() << 32;\n\n                    result |= (ulong)ReadByte() << 40;\n                    result |= (ulong)ReadByte() << 48;\n                    result |= (ulong)ReadByte() << 56;\n                    result >>= 9;\n\n                    var upper = (ushort)ReadByte();\n                    result |= ((ulong)upper) << (64 - 9);\n                    return result;\n                }\n                else if (numBytes == 10)\n                {\n                    result |= (ulong)ReadByte() << 16;\n                    result |= (ulong)ReadByte() << 24;\n                    result |= (ulong)ReadByte() << 32;\n\n                    result |= (ulong)ReadByte() << 40;\n                    result |= (ulong)ReadByte() << 48;\n                    result |= (ulong)ReadByte() << 56;\n                    result >>= 10;\n\n                    var upper = (ushort)(ReadByte() | (ushort)(ReadByte() << 8));\n                    result |= ((ulong)upper) << (64 - 10);\n                    return result;\n                }\n            }\n\n            return ExceptionHelper.ThrowArgumentOutOfRange<ulong>(\"value\");\n        }\n\n        private static T ThrowNotSupportedInput<T>() => throw new NotSupportedException($\"Type {typeof(TInput)} is not supported\");\n\n        private static void ThrowNotSupportedInput() => throw new NotSupportedException($\"Type {typeof(TInput)} is not supported\");\n\n        private static void ThrowInvalidSizeException(uint length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(byte[])}, {length}, is greater than total length of input.\");\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Writer.FieldHeader.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Buffers\n{\n    public ref partial struct Writer<TBufferWriter>\n    {\n        /// <summary>\n        /// Writes the field header.\n        /// </summary>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteFieldHeader(uint fieldId, Type expectedType, Type actualType, WireType wireType)\n        {\n            var embeddedFieldId = fieldId > Tag.MaxEmbeddedFieldIdDelta ? Tag.FieldIdCompleteMask : fieldId;\n            var tag = (uint)wireType | embeddedFieldId;\n\n            if (actualType is null || actualType == expectedType)\n            {\n                WriteByte((byte)tag); // SchemaType.Expected=0\n                if (fieldId > Tag.MaxEmbeddedFieldIdDelta)\n                {\n                    WriteVarUInt32(fieldId);\n                }\n                return;\n            }\n\n            uint typeOrReferenceId;\n            if (Session.WellKnownTypes.TryGetWellKnownTypeId(actualType, out var typeId))\n            {\n                typeOrReferenceId = typeId;\n                tag |= (byte)SchemaType.WellKnown;\n            }\n            else if ((typeOrReferenceId = Session.ReferencedTypes.GetOrAddTypeReference(actualType)) != 0)\n            {\n                tag |= (byte)SchemaType.Referenced;\n            }\n            else\n            {\n                WriteFieldHeaderEncodeType(fieldId, actualType, tag);\n                return;\n            }\n\n            WriteByte((byte)tag);\n            if (fieldId > Tag.MaxEmbeddedFieldIdDelta)\n                WriteVarUInt32(fieldId);\n\n            WriteVarUInt32(typeOrReferenceId);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteFieldHeaderEncodeType(uint fieldId, Type actualType, uint tag)\n        {\n            WriteByte((byte)(tag | (byte)SchemaType.Encoded));\n            if (fieldId > Tag.MaxEmbeddedFieldIdDelta)\n                WriteVarUInt32(fieldId);\n\n            Session.TypeCodec.WriteEncodedType(ref this, actualType);\n        }\n\n        /// <summary>\n        /// Writes an expected field header value.\n        /// </summary>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        /// <param name=\"wireType\">The wire type of the field.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteFieldHeaderExpected(uint fieldId, WireType wireType)\n        {\n            var embeddedFieldId = fieldId > Tag.MaxEmbeddedFieldIdDelta ? Tag.FieldIdCompleteMask : fieldId;\n            WriteByte((byte)((uint)wireType | embeddedFieldId));\n\n            if (fieldId > Tag.MaxEmbeddedFieldIdDelta)\n                WriteVarUInt32(fieldId);\n        }\n    }\n}\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Codec for operating with the wire format.\n    /// </summary>\n    public static class FieldHeaderCodec\n    {\n        /// <summary>\n        /// Reads a field header.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field header.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void ReadFieldHeader<TInput>(ref this Reader<TInput> reader, scoped ref Field field)\n        {\n            var tag = (uint)reader.ReadByte();\n            field.Tag = new(tag);\n            // If the id or schema type are required and were not encoded into the tag, read the extended header data.\n            if (tag < (byte)WireType.Extended && (tag & (Tag.FieldIdCompleteMask | Tag.SchemaTypeMask)) >= Tag.FieldIdCompleteMask)\n            {\n                ReadExtendedFieldHeader(ref reader, ref field);\n            }\n            else\n            {\n                field.FieldIdDeltaRaw = tag & Tag.FieldIdMask;\n                field.FieldTypeRaw = default;\n            }\n        }\n\n        /// <summary>\n        /// Reads a field header.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The field header.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Field ReadFieldHeader<TInput>(ref this Reader<TInput> reader)\n        {\n            Unsafe.SkipInit(out Field field);\n            var tag = (uint)reader.ReadByte();\n            field.Tag = new(tag);\n            // If the id or schema type are required and were not encoded into the tag, read the extended header data.\n            if (tag < (byte)WireType.Extended && (tag & (Tag.FieldIdCompleteMask | Tag.SchemaTypeMask)) >= Tag.FieldIdCompleteMask)\n            {\n                ReadExtendedFieldHeader(ref reader, ref field);\n            }\n            else\n            {\n                field.FieldIdDeltaRaw = tag & Tag.FieldIdMask;\n                field.FieldTypeRaw = default;\n            }\n\n            return field;\n        }\n\n        /// <summary>\n        /// Reads an extended field header.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static void ReadExtendedFieldHeader<TInput>(ref this Reader<TInput> reader, scoped ref Field field)\n        {\n            var fieldId = field.Tag.FieldIdDelta;\n            if (fieldId == Tag.FieldIdCompleteMask)\n            {\n                field.FieldIdDeltaRaw = reader.ReadVarUInt32NoInlining();\n            }\n            else\n            {\n                field.FieldIdDeltaRaw = fieldId;\n            }\n\n            // If schema type is valid, read the type.\n            var schemaType = field.Tag.SchemaType;\n            if (schemaType != SchemaType.Expected)\n            {\n                field.FieldTypeRaw = reader.ReadType(schemaType);\n            }\n            else\n            {\n                field.FieldTypeRaw = default;\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static Type ReadType<TInput>(this ref Reader<TInput> reader, SchemaType schemaType)\n        {\n            switch (schemaType)\n            {\n                case SchemaType.WellKnown:\n                    var typeId = reader.ReadVarUInt32();\n                    return reader.Session.WellKnownTypes.GetWellKnownType(typeId);\n                case SchemaType.Encoded:\n                    var encoded = reader.Session.TypeCodec.TryRead(ref reader);\n                    reader.Session.ReferencedTypes.RecordReferencedType(encoded);\n                    return encoded;\n                case SchemaType.Referenced:\n                    var reference = reader.ReadVarUInt32();\n                    return reader.Session.ReferencedTypes.GetReferencedType(reference);\n                default:\n                    return ExceptionHelper.ThrowArgumentOutOfRange<Type>(nameof(SchemaType));\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static (Type type, string typeName) ReadTypeForAnalysis<TInput>(this ref Reader<TInput> reader, SchemaType schemaType)\n        {\n            switch (schemaType)\n            {\n                case SchemaType.WellKnown:\n                    { \n                        var typeId = reader.ReadVarUInt32();\n                        var found = reader.Session.WellKnownTypes.TryGetWellKnownType(typeId, out var type);\n                        return (type, $\"WellKnown {typeId} ({(found ? type is null ? \"null\" : RuntimeTypeNameFormatter.Format(type) : \"unknown\")})\");\n                    }\n                case SchemaType.Encoded:\n                    {\n                        var found = reader.Session.TypeCodec.TryReadForAnalysis(ref reader, out Type encoded, out var typeString);\n                        reader.Session.ReferencedTypes.RecordReferencedType(encoded);\n                        return (encoded, $\"Encoded \\\"{typeString}\\\" ({(found ? encoded is null ? \"null\" : RuntimeTypeNameFormatter.Format(encoded) : \"not found\")})\");\n                    }\n                case SchemaType.Referenced:\n                    {\n                        var reference = reader.ReadVarUInt32();\n                        var found = reader.Session.ReferencedTypes.TryGetReferencedType(reference, out var type);\n                        return (type, $\"Referenced {reference} ({(found ? type is null ? \"null\" : RuntimeTypeNameFormatter.Format(type) : \"not found\")})\");\n                    }\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(schemaType));\n            }\n        }\n\n        /// <summary>\n        /// Reads a field header for diagnostic purposes.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value which was read.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static (Field Field, string Type) ReadFieldHeaderForAnalysis<TInput>(ref this Reader<TInput> reader)\n        {\n            Unsafe.SkipInit(out Field field);\n            string type = default;\n            var tag = (uint)reader.ReadByte();\n            field.Tag = new(tag);\n            if (tag < (byte)WireType.Extended && ((tag & Tag.FieldIdCompleteMask) == Tag.FieldIdCompleteMask || (tag & Tag.SchemaTypeMask) != (byte)SchemaType.Expected))\n            {\n                ReadFieldHeaderForAnalysisSlow(ref reader, ref field, ref type);\n            }\n            else\n            {\n                field.FieldIdDeltaRaw = tag & Tag.FieldIdMask;\n                field.FieldTypeRaw = default;\n                type = \"Expected\";\n            }\n\n            return (field, type);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static void ReadFieldHeaderForAnalysisSlow<TInput>(ref this Reader<TInput> reader, scoped ref Field field, scoped ref string type)\n        {\n            var fieldId = field.Tag.FieldIdDelta;\n            if (fieldId == Tag.FieldIdCompleteMask)\n            {\n                field.FieldIdDeltaRaw = reader.ReadVarUInt32NoInlining();\n            }\n            else\n            {\n                field.FieldIdDeltaRaw = fieldId;\n            }\n\n            // If schema type is valid, read the type.\n            var schemaType = field.Tag.SchemaType;\n            if (schemaType != SchemaType.Expected)\n            {\n                (field.FieldTypeRaw, type) = reader.ReadTypeForAnalysis(schemaType);\n            }\n            else\n            {\n                field.FieldTypeRaw = default;\n                type = \"Expected\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Writer.TagDelimitedField.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Buffers\n{\n    public ref partial struct Writer<TBufferWriter>\n    {\n        /// <summary>\n        /// Writes the start object tag.\n        /// </summary>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteStartObject(uint fieldId, Type expectedType, Type actualType) => WriteFieldHeader(fieldId, expectedType, actualType, WireType.TagDelimited);\n\n        /// <summary>\n        /// Writes the end object tag.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteEndObject() => WriteByte((byte)WireType.Extended | (byte)ExtendedWireType.EndTagDelimited);\n\n        /// <summary>\n        /// Writes the end base tag.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteEndBase() => WriteByte((byte)WireType.Extended | (byte)ExtendedWireType.EndBaseFields);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Writer.VarInt.cs",
    "content": "using System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Buffers\n{\n    public ref partial struct Writer<TBufferWriter>\n    {\n        /// <summary>\n        /// Writes a variable-width <see cref=\"sbyte\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarInt8(sbyte value) => WriteVarUInt28(ZigZagEncode(value));\n\n        /// <summary>\n        /// Writes a variable-width <see cref=\"short\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarInt16(short value) => WriteVarUInt28(ZigZagEncode(value));\n\n        /// <summary>\n        /// Writes a variable-width <see cref=\"int\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarInt32(int value) => WriteVarUInt32(ZigZagEncode(value));\n\n        /// <summary>\n        /// Writes a variable-width <see cref=\"long\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarInt64(long value) => WriteVarUInt64(ZigZagEncode(value));\n\n        /// <summary>\n        /// Writes a variable-width <see cref=\"byte\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarUInt8(byte value) => WriteVarUInt28(value);\n\n        /// <summary>\n        /// Writes a variable-width <see cref=\"ushort\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarUInt16(ushort value) => WriteVarUInt28(value);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static uint ZigZagEncode(int value) => (uint)((value << 1) ^ (value >> 31));\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static ulong ZigZagEncode(long value) => (ulong)((value << 1) ^ (value >> 63));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Buffers/Writer.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Binary;\nusing System.Diagnostics;\nusing System.IO;\n#if NETCOREAPP3_1_OR_GREATER\nusing System.Numerics;\n#else\nusing Orleans.Serialization.Utilities;\n#endif\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Session;\n\nnamespace Orleans.Serialization.Buffers\n{\n    /// <summary>\n    /// Helper methods for creating <see cref=\"Writer{TBufferWriter}\"/> instances.\n    /// </summary>\n    public static class Writer\n    {\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer output type.</typeparam>\n        /// <param name=\"destination\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<TBufferWriter> Create<TBufferWriter>(TBufferWriter destination, SerializerSession session) where TBufferWriter : IBufferWriter<byte> => new(destination, session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"destination\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<MemoryStreamBufferWriter> Create(MemoryStream destination, SerializerSession session) => new(new MemoryStreamBufferWriter(destination), session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"destination\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <param name=\"sizeHint\">The size hint.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<PoolingStreamBufferWriter> CreatePooled(Stream destination, SerializerSession session, int sizeHint = 0) => new(new PoolingStreamBufferWriter(destination, sizeHint), session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"destination\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <param name=\"sizeHint\">The size hint.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<ArrayStreamBufferWriter> Create(Stream destination, SerializerSession session, int sizeHint = 0) => new(new ArrayStreamBufferWriter(destination, sizeHint), session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"output\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<SpanBufferWriter> Create(byte[] output, SerializerSession session) => Create(output.AsSpan(), session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"output\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<MemoryBufferWriter> Create(Memory<byte> output, SerializerSession session) => new(new MemoryBufferWriter(output), session);\n\n        /// <summary>\n        /// Creates a writer which writes to the specified destination.\n        /// </summary>\n        /// <param name=\"output\">The destination.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<SpanBufferWriter> Create(Span<byte> output, SerializerSession session) => new(new SpanBufferWriter(output), output, session);\n\n        /// <summary>\n        /// Creates a writer which writes to a pooled buffer.\n        /// </summary>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>A new <see cref=\"Writer{TBufferWriter}\"/>.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Writer<PooledBuffer> CreatePooled(SerializerSession session) => new(new PooledBuffer(), session);\n    }\n\n    /// <summary>\n    /// Provides functionality for writing to an output stream.\n    /// </summary>\n    /// <typeparam name=\"TBufferWriter\">The underlying buffer writer type.</typeparam>\n    public ref partial struct Writer<TBufferWriter> where TBufferWriter : IBufferWriter<byte>\n    {\n        /// <summary>\n        /// The output buffer writer.\n        /// </summary>\n        /// <remarks>\n        /// Modifying the output directly may corrupt the state of the writer.\n        /// </remarks>\n        public TBufferWriter Output;\n\n        /// <summary>\n        /// The current write span.\n        /// </summary>\n        private Span<byte> _currentSpan;\n\n        /// <summary>\n        /// The buffer position within the current span.\n        /// </summary>\n        private int _bufferPos;\n\n        /// <summary>\n        /// The previous buffer's size.\n        /// </summary>\n        private int _previousBuffersSize;\n\n        /// <summary>\n        /// Max segment buffer size hint (1MB)\n        /// </summary>\n        internal const int MaxMultiSegmentSizeHint = 1024 * 1024;\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal Writer(TBufferWriter output, SerializerSession session)\n        {\n            Debug.Assert(output is not SpanBufferWriter);\n            Output = output;\n            Session = session;\n            _currentSpan = Output.GetSpan();\n            _bufferPos = default;\n            _previousBuffersSize = default;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal Writer(TBufferWriter output, Span<byte> span, SerializerSession session)\n        {\n            Debug.Assert(output is SpanBufferWriter);\n            Output = output;\n            Session = session;\n            _currentSpan = span;\n            _bufferPos = default;\n            _previousBuffersSize = default;\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Dispose()\n        {\n            // Avoid boxing the struct, for better perf and codegen.\n            if (typeof(TBufferWriter).IsValueType)\n            {\n                if (Output is IDisposable)\n                {\n                    ((IDisposable)Output).Dispose();\n                }\n            }\n            else\n            {\n                (Output as IDisposable)?.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Gets the serializer session.\n        /// </summary>\n        /// <value>The serializer session.</value>\n        public SerializerSession Session { get; }\n\n        /// <summary>\n        /// Gets the position.\n        /// </summary>\n        /// <value>The position.</value>\n        public readonly int Position => _previousBuffersSize + _bufferPos;\n\n        /// <summary>\n        /// Gets the current writable span.\n        /// </summary>\n        /// <value>The current writable span.</value>\n        public readonly Span<byte> WritableSpan\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => _currentSpan[_bufferPos..];\n        }\n\n        /// <summary>\n        /// Advance the write position in the current span.\n        /// </summary>\n        /// <param name=\"length\">The number of bytes to advance wirte position by.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void AdvanceSpan(int length) => _bufferPos += length;\n\n        /// <summary>\n        /// Commit the currently written buffers.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Commit()\n        {\n            Output.Advance(_bufferPos);\n\n            if (!typeof(TBufferWriter).IsValueType || typeof(TBufferWriter) != typeof(SpanBufferWriter))\n            {\n                _previousBuffersSize += _bufferPos;\n                _currentSpan = default;\n                _bufferPos = default;\n            }\n        }\n\n        /// <summary>\n        /// Ensures that there are at least <paramref name=\"length\"/> contiguous bytes available to be written.\n        /// </summary>\n        /// <param name=\"length\">The number of contiguous bytes to ensure.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void EnsureContiguous(int length)\n        {\n            // The current buffer is adequate.\n            if (_bufferPos + length <= _currentSpan.Length)\n            {\n                return;\n            }\n\n            // The current buffer is inadequate, allocate another.\n            Allocate(length);\n#if DEBUG\n            // Throw if the allocation does not satisfy the request.\n            if (_currentSpan.Length < length)\n                throw new InvalidOperationException($\"Requested buffer length {length} cannot be satisfied by the writer.\");\n#endif\n        }\n\n        /// <summary>\n        /// Allocates buffer space for the specified number of bytes.\n        /// </summary>\n        /// <param name=\"sizeHint\">The number of bytes to reserve.</param>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public void Allocate(int sizeHint)\n        {\n            // Commit the bytes which have been written.\n            Output.Advance(_bufferPos);\n\n            // Request a new buffer with at least the requested number of available bytes.\n            _currentSpan = Output.GetSpan(sizeHint);\n\n            // Update internal state for the new buffer.\n            _previousBuffersSize += _bufferPos;\n            _bufferPos = 0;\n        }\n\n        /// <summary>\n        /// Writes the specified value.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Write(scoped ReadOnlySpan<byte> value)\n        {\n            // Fast path, try copying to the current buffer.\n            var destination = WritableSpan;\n            if ((uint)value.Length <= (uint)destination.Length)\n            {\n                value.CopyTo(destination);\n                _bufferPos += value.Length;\n            }\n            else\n            {\n                WriteMultiSegment(value);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteMultiSegment(scoped ReadOnlySpan<byte> input)\n        {\n            while (true)\n            {\n                // Write as much as possible/necessary into the current segment.\n                var span = WritableSpan;\n                var writeSize = Math.Min(span.Length, input.Length);\n                input[..writeSize].CopyTo(span);\n                _bufferPos += writeSize;\n\n                input = input[writeSize..];\n\n                if (input.Length == 0)\n                {\n                    return;\n                }\n\n                // The current segment is full but there is more to write.\n                Allocate(Math.Min(input.Length, MaxMultiSegmentSizeHint));\n            }\n        }\n\n        /// <summary>\n        /// Writes the provided <see cref=\"byte\"/> to the output buffer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteByte(byte value)\n        {\n            nuint bufferPos = (uint)_bufferPos;\n            if ((uint)bufferPos < (uint)_currentSpan.Length)\n            {\n                // https://github.com/dotnet/runtime/issues/72004\n                Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), bufferPos) = value;\n                _bufferPos = (int)(uint)bufferPos + 1;\n            }\n            else\n            {\n                WriteByteSlow(value);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteByteSlow(byte value)\n        {\n            Allocate(1);\n            _currentSpan[0] = value;\n            _bufferPos = 1;\n        }\n\n        /// <summary>\n        /// Writes the provided <see cref=\"int\"/> to the output buffer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteInt32(int value) => WriteUInt32((uint)value);\n\n        /// <summary>\n        /// Writes the provided <see cref=\"long\"/> to the output buffer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteInt64(long value) => WriteUInt64((ulong)value);\n\n        /// <summary>\n        /// Writes the provided <see cref=\"uint\"/> to the output buffer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteUInt32(uint value)\n        {\n            nuint pos = (uint)_bufferPos;\n            int newPos = (int)(uint)pos + sizeof(uint);\n            if ((uint)newPos <= (uint)_currentSpan.Length)\n            {\n                _bufferPos = newPos;\n                if (!BitConverter.IsLittleEndian) value = BinaryPrimitives.ReverseEndianness(value);\n                Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos), value);\n            }\n            else\n            {\n                WriteUInt32Slow(value);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteUInt32Slow(uint value)\n        {\n            Allocate(sizeof(uint));\n            BinaryPrimitives.WriteUInt32LittleEndian(_currentSpan, value);\n            _bufferPos = sizeof(uint);\n        }\n\n        /// <summary>\n        /// Writes the provided <see cref=\"ulong\"/> to the output buffer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteUInt64(ulong value)\n        {\n            nuint pos = (uint)_bufferPos;\n            int newPos = (int)(uint)pos + sizeof(ulong);\n            if ((uint)newPos <= (uint)_currentSpan.Length)\n            {\n                _bufferPos = newPos;\n                if (!BitConverter.IsLittleEndian) value = BinaryPrimitives.ReverseEndianness(value);\n                Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos), value);\n            }\n            else\n            {\n                WriteUInt64Slow(value);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteUInt64Slow(ulong value)\n        {\n            Allocate(sizeof(ulong));\n            BinaryPrimitives.WriteUInt64LittleEndian(_currentSpan, value);\n            _bufferPos = sizeof(ulong);\n        }\n\n        /// <summary>\n        /// Writes a 7-bit unsigned value as a variable-width integer.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal void WriteVarUInt7(uint value)\n        {\n            Debug.Assert(value < 1 << 7);\n            WriteByte((byte)((value << 1) + 1));\n        }\n\n        /// <summary>\n        /// Writes a 28-bit unsigned value as a variable-width integer.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal void WriteVarUInt28(uint value)\n        {\n            Debug.Assert(value < 1 << 28);\n\n            var neededBytes = (int)((uint)BitOperations.Log2(value) / 7);\n\n            uint lower = ((value << 1) + 1) << neededBytes;\n\n            nuint pos = (uint)_bufferPos;\n            if ((uint)pos + sizeof(uint) <= (uint)_currentSpan.Length)\n            {\n                _bufferPos = (int)(uint)pos + neededBytes + 1;\n                if (!BitConverter.IsLittleEndian) lower = BinaryPrimitives.ReverseEndianness(lower);\n                Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos), lower);\n            }\n            else\n            {\n                WriteVarUInt28Slow(lower);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteVarUInt28Slow(uint lower)\n        {\n            Allocate(sizeof(uint));\n\n            var neededBytes = BitOperations.TrailingZeroCount(lower) + 1;\n            BinaryPrimitives.WriteUInt32LittleEndian(_currentSpan, lower);\n            _bufferPos = neededBytes;\n        }\n\n        /// <summary>\n        /// Writes the provided <see cref=\"uint\"/> to the output buffer as a variable-width integer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarUInt32(uint value)\n        {\n            var neededBytes = (int)((uint)BitOperations.Log2(value) / 7);\n\n            ulong lower = (((ulong)value << 1) + 1) << neededBytes;\n\n            nuint pos = (uint)_bufferPos;\n            if ((uint)pos + sizeof(ulong) <= (uint)_currentSpan.Length)\n            {\n                _bufferPos = (int)(uint)pos + neededBytes + 1;\n                if (!BitConverter.IsLittleEndian) lower = BinaryPrimitives.ReverseEndianness(lower);\n                Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos), lower);\n            }\n            else\n            {\n                WriteVarUInt56Slow(lower);\n            }\n        }\n\n        /// <summary>\n        /// Writes a 56-bit unsigned value as a variable-width integer.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal void WriteVarUInt56(ulong value)\n        {\n            Debug.Assert(value < 1UL << 56);\n\n            var neededBytes = (int)((uint)BitOperations.Log2(value) / 7);\n\n            ulong lower = ((value << 1) + 1) << neededBytes;\n\n            nuint pos = (uint)_bufferPos;\n            if ((uint)pos + sizeof(ulong) <= (uint)_currentSpan.Length)\n            {\n                _bufferPos = (int)(uint)pos + neededBytes + 1;\n                if (!BitConverter.IsLittleEndian) lower = BinaryPrimitives.ReverseEndianness(lower);\n                Unsafe.WriteUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos), lower);\n            }\n            else\n            {\n                WriteVarUInt56Slow(lower);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteVarUInt56Slow(ulong lower)\n        {\n            Allocate(sizeof(ulong));\n\n            var neededBytes = BitOperations.TrailingZeroCount((uint)lower) + 1;\n            BinaryPrimitives.WriteUInt64LittleEndian(_currentSpan, lower);\n            _bufferPos = neededBytes;\n        }\n\n        /// <summary>\n        /// Writes the provided <see cref=\"ulong\"/> to the output buffer as a variable-width integer.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteVarUInt64(ulong value)\n        {\n            nuint pos = (uint)_bufferPos;\n            // Since this method writes a ulong plus a ushort worth of bytes unconditionally, ensure that there is sufficient space.\n            if ((uint)pos + sizeof(ulong) + sizeof(ushort) <= (uint)_currentSpan.Length)\n            {\n                var neededBytes = (int)((uint)BitOperations.Log2(value) / 7);\n                _bufferPos = (int)(uint)pos + neededBytes + 1;\n\n                ulong lower = ((value << 1) + 1) << neededBytes;\n\n                ref var writeHead = ref Unsafe.Add(ref MemoryMarshal.GetReference(_currentSpan), pos);\n                if (!BitConverter.IsLittleEndian) lower = BinaryPrimitives.ReverseEndianness(lower);\n                Unsafe.WriteUnaligned(ref writeHead, lower);\n\n                // Write the 2 byte overflow unconditionally\n                var upper = value >> (63 - neededBytes);\n                writeHead = ref Unsafe.Add(ref writeHead, sizeof(ulong));\n                if (!BitConverter.IsLittleEndian) upper = BinaryPrimitives.ReverseEndianness((ushort)upper);\n                Unsafe.WriteUnaligned(ref writeHead, (ushort)upper);\n            }\n            else\n            {\n                WriteVarUInt64Slow(value);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void WriteVarUInt64Slow(ulong value)\n        {\n            Allocate(sizeof(ulong) + sizeof(ushort));\n\n            var neededBytes = (int)((uint)BitOperations.Log2(value) / 7);\n            _bufferPos = neededBytes + 1;\n\n            ulong lower = ((value << 1) + 1) << neededBytes;\n            BinaryPrimitives.WriteUInt64LittleEndian(_currentSpan, lower);\n\n            // Write the 2 byte overflow unconditionally\n            var upper = value >> (63 - neededBytes);\n            BinaryPrimitives.WriteUInt16LittleEndian(_currentSpan[sizeof(ulong)..], (ushort)upper);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Cloning/IDeepCopier.cs",
    "content": "﻿#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Specialized;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Net;\nusing System.Reflection;\nusing System.Threading;\nusing Microsoft.Extensions.ObjectPool;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities;\n\nnamespace Orleans.Serialization.Cloning\n{\n    /// <summary>\n    /// Provides <see cref=\"IDeepCopier{T}\"/> instances.\n    /// </summary>\n    public interface IDeepCopierProvider\n    {\n        /// <summary>\n        /// Gets a deep copier capable of copying instances of type <typeparamref name=\"T\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The type supported by the copier.</typeparam>\n        /// <returns>A deep copier capable of copying instances of type <typeparamref name=\"T\"/>.</returns>\n        IDeepCopier<T> GetDeepCopier<T>();\n\n        /// <summary>\n        /// Gets a deep copier capable of copying instances of type <typeparamref name=\"T\"/>, or returns <see langword=\"null\"/> if an appropriate copier was not found.\n        /// </summary>\n        /// <typeparam name=\"T\">The type supported by the copier.</typeparam>\n        /// <returns>A deep copier capable of copying instances of type <typeparamref name=\"T\"/>, or <see langword=\"null\"/> if an appropriate copier was not found.</returns>\n        IDeepCopier<T>? TryGetDeepCopier<T>();\n\n        /// <summary>\n        /// Gets a deep copier capable of copying instances of type <paramref name=\"type\"/>.\n        /// </summary>\n        /// <param name=\"type\">\n        /// The type supported by the returned copier.\n        /// </param>\n        /// <returns>A deep copier capable of copying instances of type <paramref name=\"type\"/>.</returns>\n        IDeepCopier GetDeepCopier(Type type);\n\n        /// <summary>\n        /// Gets a deep copier capable of copying instances of type <paramref name=\"type\"/>, or returns <see langword=\"null\"/> if an appropriate copier was not found.\n        /// </summary>\n        /// <param name=\"type\">\n        /// The type supported by the returned copier.\n        /// </param>\n        /// <returns>A deep copier capable of copying instances of type <paramref name=\"type\"/>, or <see langword=\"null\"/> if an appropriate copier was not found.</returns>\n        IDeepCopier? TryGetDeepCopier(Type type);\n\n        /// <summary>\n        /// Gets a base type copier capable of copying instances of type <typeparamref name=\"T\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The type supported by the returned copier.\n        /// </typeparam>\n        /// <returns>A base type copier capable of copying instances of type <typeparamref name=\"T\"/>.</returns>\n        IBaseCopier<T> GetBaseCopier<T>() where T : class;\n    }\n\n    /// <summary>\n    /// Marker type for deep copiers.\n    /// </summary>\n    public interface IDeepCopier\n    {\n        /// <summary>\n        /// Creates a deep copy of the provided untyped input. The type must still match the copier instance!\n        /// </summary>\n        object? DeepCopy(object? input, CopyContext context);\n    }\n\n    /// <summary>\n    /// Marker interface for deep copiers of types that could optionally be shallow-copyable.\n    /// </summary>\n    public interface IOptionalDeepCopier : IDeepCopier\n    {\n        /// <summary>\n        /// Returns true if the type is shallow-copyable.\n        /// </summary>\n        bool IsShallowCopyable();\n    }\n\n    internal sealed class ShallowCopier : IOptionalDeepCopier\n    {\n        public static readonly ShallowCopier Instance = new();\n\n        public bool IsShallowCopyable() => true;\n        public object? DeepCopy(object? input, CopyContext _) => input;\n    }\n\n    /// <summary>\n    /// Base type for deep copiers of types that are actually shallow-copyable.\n    /// </summary>\n    public class ShallowCopier<T> : IOptionalDeepCopier, IDeepCopier<T>\n    {\n        public bool IsShallowCopyable() => true;\n\n        /// <summary>Returns the input value.</summary>\n        public T DeepCopy(T input, CopyContext _) => input;\n\n        /// <summary>Returns the input value.</summary>\n        public object? DeepCopy(object? input, CopyContext _) => input;\n    }\n\n    /// <summary>\n    /// Provides functionality for creating clones of objects of type <typeparamref name=\"T\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of objects which this instance can copy.</typeparam>\n    /// <seealso cref=\"Orleans.Serialization.Cloning.IDeepCopier\" />\n    public interface IDeepCopier<T> : IDeepCopier\n    {\n        /// <summary>\n        /// Creates a deep copy of the provided input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"context\">The context.</param>\n        /// <returns>A copy of <paramref name=\"input\"/>.</returns>\n        T DeepCopy(T input, CopyContext context);\n\n        object? IDeepCopier.DeepCopy(object? input, CopyContext context) => input is null ? null : DeepCopy((T)input, context);\n    }\n\n    /// <summary>\n    /// Marker type for base type copiers.\n    /// </summary>\n    public interface IBaseCopier\n    {\n    }\n\n    /// <summary>\n    /// Provides functionality for copying members from one object to another.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of objects which this instance can copy.</typeparam>\n    /// <seealso cref=\"Orleans.Serialization.Cloning.IBaseCopier\" />\n    public interface IBaseCopier<T> : IBaseCopier where T : class\n    {\n        /// <summary>\n        /// Clones members from <paramref name=\"input\"/> and copies them to <paramref name=\"output\"/>.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"output\">The output.</param>\n        /// <param name=\"context\">The context.</param>\n        void DeepCopy(T input, T output, CopyContext context);\n    }\n\n    /// <summary>\n    /// Indicates that an <see cref=\"IDeepCopier\"/> implementation generalizes over all sub-types.\n    /// </summary>\n    public interface IDerivedTypeCopier : IDeepCopier\n    {\n    }\n\n    /// <summary>\n    /// Provides functionality for copying objects of multiple types.\n    /// </summary>\n    public interface IGeneralizedCopier : IDeepCopier\n    {\n        /// <summary>\n        /// Returns a value indicating whether the provided type is supported by this implementation.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\"/> if the type is supported type by this implementation; otherwise, <see langword=\"false\"/>.</returns>\n        bool IsSupportedType(Type type);\n    }\n\n    /// <summary>\n    /// Provides functionality for creating <see cref=\"IDeepCopier\"/> instances which support a given type.\n    /// </summary>\n    public interface ISpecializableCopier\n    {\n        /// <summary>\n        /// Returns a value indicating whether the provided type is supported by this implementation.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\"/> if the type is supported type by this implementation; otherwise, <see langword=\"false\"/>.</returns>\n        bool IsSupportedType(Type type);\n\n        /// <summary>\n        /// Gets an <see cref=\"IDeepCopier\"/> implementation which supports the specified type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>An <see cref=\"IDeepCopier\"/> implementation which supports the specified type.</returns>\n        IDeepCopier GetSpecializedCopier(Type type);\n    }\n\n    /// <summary>\n    /// Provides context for a copy operation.\n    /// </summary>\n    /// <seealso cref=\"System.IDisposable\" />\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"CopyContext\"/> class.\n    /// </remarks>\n    /// <param name=\"codecProvider\">The codec provider.</param>\n    /// <param name=\"onDisposed\">The action to call when this context is disposed.</param>\n    public sealed class CopyContext(CodecProvider codecProvider, Action<CopyContext> onDisposed) : IDisposable\n    {\n        private readonly Dictionary<object, object> _copies = new(ReferenceEqualsComparer.Default);\n        private readonly CodecProvider _copierProvider = codecProvider;\n        private readonly Action<CopyContext> _onDisposed = onDisposed;\n\n        /// <summary>\n        /// Returns the previously recorded copy of the provided object, if it exists.\n        /// </summary>\n        /// <typeparam name=\"T\">The object type.</typeparam>\n        /// <param name=\"original\">The original object.</param>\n        /// <param name=\"result\">The previously recorded copy of <paramref name=\"original\"/>.</param>\n        /// <returns><see langword=\"true\"/> if a copy of <paramref name=\"original\"/> has been recorded, <see langword=\"false\"/> otherwise.</returns>\n        public bool TryGetCopy<T>(object? original, out T? result) where T : class\n        {\n            if (original is null)\n            {\n                result = null;\n                return true;\n            }\n\n            if (_copies.TryGetValue(original, out var existing))\n            {\n                result = existing as T;\n                return true;\n            }\n\n            result = null;\n            return false;\n        }\n\n        /// <summary>\n        /// Records a copy of an object.\n        /// </summary>\n        /// <param name=\"original\">The original value.</param>\n        /// <param name=\"copy\">The copy of <paramref name=\"original\"/>.</param>\n        public void RecordCopy(object original, object copy)\n        {\n            _copies[original] = copy;\n        }\n\n        /// <summary>\n        /// Resets this instance.\n        /// </summary>\n        public void Reset() => _copies.Clear();\n\n        /// <summary>\n        /// Copies the provided value.\n        /// </summary>\n        /// <typeparam name=\"T\">The value type.</typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>A copy of the provided value.</returns>\n        public T? DeepCopy<T>(T? value)\n        {\n            if (!typeof(T).IsValueType)\n            {\n                if (value is null) return default;\n            }\n\n            var copier = _copierProvider.GetDeepCopier(value!.GetType());\n            return (T?)copier.DeepCopy(value, this);\n        }\n\n        /// <inheritdoc/>\n        public void Dispose() => _onDisposed?.Invoke(this);\n    }\n\n    internal static class ShallowCopyableTypes\n    {\n        private static readonly ConcurrentDictionary<Type, bool> Types = new()\n        {\n            [typeof(decimal)] = true,\n            [typeof(DateTime)] = true,\n#if NET6_0_OR_GREATER\n            [typeof(DateOnly)] = true,\n            [typeof(TimeOnly)] = true,\n#endif\n            [typeof(DateTimeOffset)] = true,\n            [typeof(TimeSpan)] = true,\n            [typeof(IPAddress)] = true,\n            [typeof(IPEndPoint)] = true,\n            [typeof(string)] = true,\n            [typeof(CancellationToken)] = true,\n            [typeof(Guid)] = true,\n            [typeof(BitVector32)] = true,\n            [typeof(CompareInfo)] = true,\n            [typeof(CultureInfo)] = true,\n            [typeof(Version)] = true,\n            [typeof(Uri)] = true,\n#if NET7_0_OR_GREATER\n            [typeof(UInt128)] = true,\n            [typeof(Int128)] = true,\n#endif\n            [typeof(System.Numerics.BigInteger)] = true,\n#if NET5_0_OR_GREATER\n            [typeof(Half)] = true,\n#endif\n        };\n\n        public static bool Contains(Type type)\n        {\n            if (Types.TryGetValue(type, out var result))\n            {\n                return result;\n            }\n\n            return Types.GetOrAdd(type, IsShallowCopyableInternal(type));\n        }\n\n        private static bool IsShallowCopyableInternal(Type type)\n        {\n            if (type.IsPrimitive || type.IsEnum)\n            {\n                return true;\n            }\n\n            if (type.IsSealed && type.IsDefined(typeof(ImmutableAttribute), false))\n            {\n                return true;\n            }\n\n            if (type.IsConstructedGenericType)\n            {\n                var def = type.GetGenericTypeDefinition();\n\n                if (def == typeof(Nullable<>)\n                    || def == typeof(Tuple<>)\n                    || def == typeof(Tuple<,>)\n                    || def == typeof(Tuple<,,>)\n                    || def == typeof(Tuple<,,,>)\n                    || def == typeof(Tuple<,,,,>)\n                    || def == typeof(Tuple<,,,,,>)\n                    || def == typeof(Tuple<,,,,,,>)\n                    || def == typeof(Tuple<,,,,,,,>))\n                {\n                    return Array.TrueForAll(type.GenericTypeArguments, a => Contains(a));\n                }\n            }\n\n            if (type.IsValueType && !type.IsGenericTypeDefinition)\n            {\n                return Array.TrueForAll(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), f => Contains(f.FieldType));\n            }\n\n            if (typeof(Exception).IsAssignableFrom(type))\n                return true;\n\n            if (typeof(Type).IsAssignableFrom(type))\n                return true;\n\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Converts an untyped copier into a strongly-typed copier.\n    /// </summary>\n    internal sealed class UntypedCopierWrapper<T>(IDeepCopier copier) : IDeepCopier<T>\n    {\n        private readonly IDeepCopier _copier = copier;\n\n        public T DeepCopy(T original, CopyContext context) => (T)_copier.DeepCopy(original, context)!;\n\n        public object? DeepCopy(object? original, CopyContext context) => _copier.DeepCopy(original, context);\n    }\n\n    /// <summary>\n    /// Object pool for <see cref=\"CopyContext\"/> instances.\n    /// </summary>\n    public sealed class CopyContextPool\n    {\n        private readonly ConcurrentObjectPool<CopyContext, PoolPolicy> _pool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CopyContextPool\"/> class.\n        /// </summary>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        public CopyContextPool(CodecProvider codecProvider)\n        {\n            var sessionPoolPolicy = new PoolPolicy(codecProvider, Return);\n            _pool = new ConcurrentObjectPool<CopyContext, PoolPolicy>(sessionPoolPolicy);\n        }\n\n        /// <summary>\n        /// Gets a <see cref=\"CopyContext\"/>.\n        /// </summary>\n        /// <returns>A <see cref=\"CopyContext\"/>.</returns>\n        public CopyContext GetContext() => _pool.Get();\n\n        /// <summary>\n        /// Returns the specified copy context to the pool.\n        /// </summary>\n        /// <param name=\"context\">The context.</param>\n        private void Return(CopyContext context) => _pool.Return(context);\n\n        private readonly struct PoolPolicy(CodecProvider codecProvider, Action<CopyContext> onDisposed) : IPooledObjectPolicy<CopyContext>\n        {\n            private readonly CodecProvider _codecProvider = codecProvider;\n            private readonly Action<CopyContext> _onDisposed = onDisposed;\n\n            public CopyContext Create() => new(_codecProvider, _onDisposed);\n\n            public bool Return(CopyContext obj)\n            {\n                obj.Reset();\n                return true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ArrayCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for arrays of rank 1.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ArrayCodec<T> : IFieldCodec<T[]>\n    {\n        private readonly IFieldCodec<T> _fieldCodec;\n        private readonly Type CodecElementType = typeof(T);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArrayCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public ArrayCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, T[] value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            if (value.Length > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 0, (uint)value.Length);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                    innerFieldIdDelta = 0;\n                }\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public T[] ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<T[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            T[] result = null;\n            uint fieldId = 0;\n            var length = 0;\n            var index = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = new T[length];\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        if (index >= length)\n                        {\n                            ThrowIndexOutOfRangeException(length);\n                        }\n\n                        result[index] = _fieldCodec.ReadValue(ref reader, header);\n                        ++index;\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            if (result is null)\n            {\n                result = Array.Empty<T>();\n                ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            }\n\n            return result;\n        }\n\n        private static void ThrowIndexOutOfRangeException(int length) => throw new IndexOutOfRangeException(\n            $\"Encountered too many elements in array of type {typeof(T[])} with declared length {length}.\");\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(T[])}, {length}, is greater than total length of input.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n    }\n\n    /// <summary>\n    /// Copier for arrays of rank 1.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ArrayCopier<T> : IDeepCopier<T[]>\n    {\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArrayCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public ArrayCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = OrleansGeneratedCodeHelper.UnwrapService(this, elementCopier);\n        }\n\n        /// <inheritdoc/>\n        public T[] DeepCopy(T[] input, CopyContext context)\n        {\n            if (context.TryGetCopy<T[]>(input, out var result))\n            {\n                return result;\n            }\n\n            result = new T[input.Length];\n            context.RecordCopy(input, result);\n            for (var i = 0; i < input.Length; i++)\n            {\n                result[i] = _elementCopier.DeepCopy(input[i], context);\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ReadOnlyMemory{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ReadOnlyMemoryCodec<T> : IFieldCodec<ReadOnlyMemory<T>>\n    {\n        private readonly Type CodecType = typeof(ReadOnlyMemory<T>);\n        private readonly Type CodecElementType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReadOnlyMemoryCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public ReadOnlyMemoryCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ReadOnlyMemory<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!MemoryMarshal.TryGetArray(value, out var segment) || segment.Array.Length != value.Length)\n            {\n                ReferenceCodec.MarkValueField(writer.Session);\n            }\n            else if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, CodecType, segment.Array))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, CodecType, WireType.TagDelimited);\n\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Length);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value.Span)\n            {\n                _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                innerFieldIdDelta = 0;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public ReadOnlyMemory<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<T[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            T[] result = null;\n            uint fieldId = 0;\n            var length = 0;\n            var index = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = new T[length];\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        if (index >= length)\n                        {\n                            ThrowIndexOutOfRangeException(length);\n                        }\n\n                        result[index] = _fieldCodec.ReadValue(ref reader, header);\n                        ++index;\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n\n        private static void ThrowIndexOutOfRangeException(int length) => throw new IndexOutOfRangeException(\n            $\"Encountered too many elements in array of type {typeof(T[])} with declared length {length}.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(ReadOnlyMemory<T>)}, {length}, is greater than total length of input.\");\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ReadOnlyMemory{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ReadOnlyMemoryCopier<T> : IDeepCopier<ReadOnlyMemory<T>>\n    {\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReadOnlyMemoryCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public ReadOnlyMemoryCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = OrleansGeneratedCodeHelper.UnwrapService(this, elementCopier);\n        }\n\n        /// <inheritdoc/>\n        public ReadOnlyMemory<T> DeepCopy(ReadOnlyMemory<T> input, CopyContext context)\n        {\n            if (input.IsEmpty)\n            {\n                return input;\n            }\n\n            var inputSpan = input.Span;\n            var result = new T[inputSpan.Length];\n\n            // Note that there is a possibility for unbounded recursion if the underlying object in the input is\n            // able to take part in a cyclic reference. If we could get that object then we could prevent that cycle.\n            // It is also possible that an IMemoryOwner<T> is the backing object, in which case this will not work.\n            if (MemoryMarshal.TryGetArray(input, out var segment) && segment.Array.Length == result.Length)\n            {\n                if (context.TryGetCopy(segment.Array, out T[] existing))\n                    return existing;\n\n                context.RecordCopy(segment.Array, result);\n            }\n\n            for (var i = 0; i < inputSpan.Length; i++)\n            {\n                result[i] = _elementCopier.DeepCopy(inputSpan[i], context);\n            }\n\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Serializer for <see cref=\"Memory{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class MemoryCodec<T> : IFieldCodec<Memory<T>>\n    {\n        private readonly Type CodecType = typeof(Memory<T>);\n        private readonly Type CodecElementType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public MemoryCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Memory<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!MemoryMarshal.TryGetArray<T>(value, out var segment) || segment.Array.Length != value.Length)\n            {\n                ReferenceCodec.MarkValueField(writer.Session);\n            }\n            else if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, CodecType, segment.Array))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, CodecType, WireType.TagDelimited);\n\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Length);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value.Span)\n            {\n                _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                innerFieldIdDelta = 0;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public Memory<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<T[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            T[] result = null;\n            uint fieldId = 0;\n            var length = 0;\n            var index = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = new T[length];\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        if (index >= length)\n                        {\n                            ThrowIndexOutOfRangeException(length);\n                        }\n\n                        result[index] = _fieldCodec.ReadValue(ref reader, header);\n                        ++index;\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n\n        private static void ThrowIndexOutOfRangeException(int length) => throw new IndexOutOfRangeException(\n            $\"Encountered too many elements in array of type {typeof(T[])} with declared length {length}.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(Memory<T>)}, {length}, is greater than total length of input.\");\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Memory{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class MemoryCopier<T> : IDeepCopier<Memory<T>>\n    {\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public MemoryCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = OrleansGeneratedCodeHelper.UnwrapService(this, elementCopier);\n        }\n\n        /// <inheritdoc/>\n        public Memory<T> DeepCopy(Memory<T> input, CopyContext context)\n        {\n            if (input.IsEmpty)\n            {\n                return input;\n            }\n\n            var inputSpan = input.Span;\n            var result = new T[inputSpan.Length];\n\n            // Note that there is a possibility for unbounded recursion if the underlying object in the input is\n            // able to take part in a cyclic reference. If we could get that object then we could prevent that cycle.\n            // It is also possible that an IMemoryOwner<T> is the backing object, in which case this will not work.\n            if (MemoryMarshal.TryGetArray<T>(input, out var segment) && segment.Array.Length == result.Length)\n            {\n                if (context.TryGetCopy(segment.Array, out T[] existing))\n                    return existing;\n\n                context.RecordCopy(segment.Array, result);\n            }\n\n            for (var i = 0; i < inputSpan.Length; i++)\n            {\n                result[i] = _elementCopier.DeepCopy(inputSpan[i], context);\n            }\n\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Serializer for <see cref=\"ArraySegment{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ArraySegmentCodec<T> : IFieldCodec<ArraySegment<T>>\n    {\n        private readonly Type CodecType = typeof(ArraySegment<T>);\n        private readonly Type CodecElementType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArraySegmentCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public ArraySegmentCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ArraySegment<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value.Array?.Length != value.Count)\n            {\n                ReferenceCodec.MarkValueField(writer.Session);\n            }\n            else if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, CodecType, value.Array))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, CodecType, WireType.TagDelimited);\n\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value.AsSpan())\n                {\n                    _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                    innerFieldIdDelta = 0;\n                }\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public ArraySegment<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<T[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            T[] result = null;\n            uint fieldId = 0;\n            var length = 0;\n            var index = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = new T[length];\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        if (index >= length)\n                        {\n                            ThrowIndexOutOfRangeException(length);\n                        }\n\n                        result[index] = _fieldCodec.ReadValue(ref reader, header);\n                        ++index;\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n\n        private static void ThrowIndexOutOfRangeException(int length) => throw new IndexOutOfRangeException(\n            $\"Encountered too many elements in array of type {typeof(T[])} with declared length {length}.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(ArraySegment<T>)}, {length}, is greater than total length of input.\");\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ArraySegment{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ArraySegmentCopier<T> : IDeepCopier<ArraySegment<T>>\n    {\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArraySegmentCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public ArraySegmentCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = OrleansGeneratedCodeHelper.UnwrapService(this, elementCopier);\n        }\n\n        /// <inheritdoc/>\n        public ArraySegment<T> DeepCopy(ArraySegment<T> input, CopyContext context)\n        {\n            if (input.Array is null)\n            {\n                return input;\n            }\n\n            var inputSpan = input.AsSpan();\n            var result = new T[inputSpan.Length];\n            context.RecordCopy(input.Array, result);\n            for (var i = 0; i < inputSpan.Length; i++)\n            {\n                result[i] = _elementCopier.DeepCopy(inputSpan[i], context);\n            }\n\n            return new ArraySegment<T>(result);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ArrayListCodec.cs",
    "content": "using System.Collections;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ArrayList\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ArrayListCodec : GeneralizedReferenceTypeSurrogateCodec<ArrayList, ArrayListSurrogate>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArrayListCodec\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ArrayListCodec(IValueSerializer<ArrayListSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ArrayList ConvertFromSurrogate(ref ArrayListSurrogate surrogate) => new(surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ArrayList value, ref ArrayListSurrogate surrogate) => surrogate.Values = value.ToArray();\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ArrayListCodec\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    public struct ArrayListSurrogate\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public object[] Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ArrayList\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ArrayListCopier : IDeepCopier<ArrayList>, IBaseCopier<ArrayList>\n    {\n        /// <inheritdoc/>\n        public ArrayList DeepCopy(ArrayList input, CopyContext context)\n        {\n            if (context.TryGetCopy<ArrayList>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() != typeof(ArrayList))\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new ArrayList(input.Count);\n            context.RecordCopy(input, result);\n            foreach (var item in input)\n            {\n                result.Add(ObjectCopier.DeepCopy(item, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(ArrayList input, ArrayList output, CopyContext context)\n        {\n            foreach (var item in input)\n            {\n                output.Add(ObjectCopier.DeepCopy(item, context));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/BigIntegerCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Serializer for <see cref=\"BigInteger\"/>.\n/// </summary>\n[RegisterSerializer]\npublic sealed class BigIntegerCodec : IFieldCodec<BigInteger>\n{\n    /// <inheritdoc/>\n    void IFieldCodec<BigInteger>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta,\n        Type expectedType, BigInteger value)\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(BigInteger), WireType.LengthPrefixed);\n\n        WriteField(ref writer, value);\n    }\n\n    /// <summary>\n    /// Writes a field without type info (expected type is statically known).\n    /// </summary>\n    /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n    /// <param name=\"writer\">The writer.</param>\n    /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n    /// <param name=\"value\">The value.</param>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, BigInteger value) where TBufferWriter : IBufferWriter<byte>\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n\n        WriteField(ref writer, value);\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, BigInteger value)\n        where TBufferWriter : IBufferWriter<byte>\n    {\n        var byteCount = value.GetByteCount();\n        writer.WriteVarUInt32((uint)byteCount);\n\n        writer.EnsureContiguous(byteCount);\n        if (value.TryWriteBytes(writer.WritableSpan, out var bytesWritten))\n        {\n            writer.AdvanceSpan(bytesWritten);\n        }\n        else\n        {\n            writer.Write(value.ToByteArray());\n        }\n    }\n\n    /// <inheritdoc/>\n    BigInteger IFieldCodec<BigInteger>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n    /// <summary>\n    /// Reads a value.\n    /// </summary>\n    /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n    /// <param name=\"reader\">The reader.</param>\n    /// <param name=\"field\">The field.</param>\n    /// <returns>The value.</returns>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static BigInteger ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        ReferenceCodec.MarkValueField(reader.Session);\n\n        if (field.WireType != WireType.LengthPrefixed)\n        {\n            throw new UnexpectedLengthPrefixValueException(nameof(BigInteger), 0, 0);\n        }\n\n        var length = reader.ReadVarUInt32();\n        var bytes = reader.ReadBytes(length);\n        return new BigInteger(bytes);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/BitVector32Codec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Specialized;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"BitVector32\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class BitVector32Codec : IFieldCodec<BitVector32>\n    {\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, BitVector32 value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(BitVector32), WireType.Fixed32);\n            writer.WriteInt32(value.Data);  // BitVector32.Data gets the value of the BitVector32 as an Int32\n        }\n\n        /// <inheritdoc/>\n        public BitVector32 ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            field.EnsureWireType(WireType.Fixed32);\n            return new BitVector32(reader.ReadInt32());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ByteArrayCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"BitArray\"/> arrays.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed partial class BitArrayCodec : IFieldCodec<BitArray>\n    {\n#if NET10_0_OR_GREATER\n#elif NET8_0_OR_GREATER\n        [UnsafeAccessor(UnsafeAccessorKind.Field, Name = \"m_array\")]\n        extern static ref int[] GetSetArray(BitArray bitArray);\n#else\n        private static int[] GetSetArray(BitArray bitArray) => typeof(BitArray).GetField(\"m_array\", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(bitArray) as int[];\n#endif\n\n        BitArray IFieldCodec<BitArray>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static BitArray ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<BitArray, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var numBytes = reader.ReadVarUInt32();\n            var result = new BitArray((int)numBytes * 8, false);\n#if NET10_0_OR_GREATER\n            reader.ReadBytes(CollectionsMarshal.AsBytes(result)[..(int)numBytes]);\n#else\n            var resultArray = GetSetArray(result);\n            reader.ReadBytes(MemoryMarshal.AsBytes(resultArray.AsSpan()).Slice(0, (int)numBytes));\n#endif\n\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        void IFieldCodec<BitArray>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, BitArray value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(BitArray), WireType.LengthPrefixed);\n\n#if NET10_0_OR_GREATER\n            var bytes = CollectionsMarshal.AsBytes(value);\n            writer.WriteVarUInt32((uint)bytes.Length);\n            writer.Write(bytes);\n#else\n            var numBytes = GetByteArrayLengthFromBitLength(value.Length);\n            writer.WriteVarUInt32((uint)numBytes);\n            writer.Write(MemoryMarshal.AsBytes(GetSetArray(value).AsSpan()).Slice(0, numBytes));\n#endif\n\n#if !NET10_0_OR_GREATER\n            static int GetByteArrayLengthFromBitLength(int n)\n            {\n                const int BitShiftPerByte = 3;\n                Debug.Assert(n >= 0);\n                return (int)((uint)(n - 1 + (1 << BitShiftPerByte)) >> BitShiftPerByte);\n            }\n#endif\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"byte\"/> arrays.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class BitArrayCopier : IDeepCopier<BitArray>\n    {\n        /// <inheritdoc/>\n        BitArray IDeepCopier<BitArray>.DeepCopy(BitArray input, CopyContext context) => DeepCopy(input, context);\n\n        /// <summary>\n        /// Creates a deep copy of the provided input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"context\">The context.</param>\n        /// <returns>A copy of <paramref name=\"input\" />.</returns>\n        public static BitArray DeepCopy(BitArray input, CopyContext context)\n        {\n            if (context.TryGetCopy<BitArray>(input, out var result))\n            {\n                return result;\n            }\n\n            result = new(input);\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"byte\"/> arrays.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ByteArrayCodec : IFieldCodec<byte[]>\n    {\n        byte[] IFieldCodec<byte[]>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static byte[] ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<byte[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var length = reader.ReadVarUInt32();\n            var result = reader.ReadBytes(length);\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        void IFieldCodec<byte[]>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, byte[] value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(byte[]), WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)value.Length);\n            writer.Write(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, byte[] value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)value.Length);\n            writer.Write(value);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"byte\"/> arrays.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ByteArrayCopier : IDeepCopier<byte[]>\n    {\n        /// <inheritdoc/>\n        byte[] IDeepCopier<byte[]>.DeepCopy(byte[] input, CopyContext context) => DeepCopy(input, context);\n\n        /// <summary>\n        /// Creates a deep copy of the provided input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"context\">The context.</param>\n        /// <returns>A copy of <paramref name=\"input\" />.</returns>\n        public static byte[] DeepCopy(byte[] input, CopyContext context)\n        {\n            if (context.TryGetCopy<byte[]>(input, out var result))\n            {\n                return result;\n            }\n\n            result = new byte[input.Length];\n            context.RecordCopy(input, result);\n            input.CopyTo(result.AsSpan());\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ReadOnlyMemory{Byte}\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ReadOnlyMemoryOfByteCodec : IFieldCodec<ReadOnlyMemory<byte>>\n    {\n        /// <inheritdoc/>\n        ReadOnlyMemory<byte> IFieldCodec<ReadOnlyMemory<byte>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static byte[] ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<byte[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var length = reader.ReadVarUInt32();\n            var result = reader.ReadBytes(length);\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        void IFieldCodec<ReadOnlyMemory<byte>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ReadOnlyMemory<byte> value) => WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, ReadOnlyMemory<byte> value) where TBufferWriter : IBufferWriter<byte>\n            => WriteField(ref writer, fieldIdDelta, typeof(ReadOnlyMemory<byte>), value);\n\n        private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ReadOnlyMemory<byte> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(ReadOnlyMemory<byte>), WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)value.Length);\n            writer.Write(value.Span);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ReadOnlyMemory{Byte}\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ReadOnlyMemoryOfByteCopier : IDeepCopier<ReadOnlyMemory<byte>>\n    {\n        /// <inheritdoc/>\n        ReadOnlyMemory<byte> IDeepCopier<ReadOnlyMemory<byte>>.DeepCopy(ReadOnlyMemory<byte> input, CopyContext _) => DeepCopy(input, _);\n\n        /// <summary>\n        /// Copies the input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"copyContext\">The copy context.</param>\n        /// <returns>A copy of the input.</returns>\n        public static ReadOnlyMemory<byte> DeepCopy(ReadOnlyMemory<byte> input, CopyContext copyContext)\n        {\n            if (input.IsEmpty)\n            {\n                return default;\n            }\n\n            return input.ToArray();\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ArraySegment{Byte}\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ArraySegmentOfByteCopier : IDeepCopier<ArraySegment<byte>>\n    {\n        /// <inheritdoc/>\n        ArraySegment<byte> IDeepCopier<ArraySegment<byte>>.DeepCopy(ArraySegment<byte> input, CopyContext _) => DeepCopy(input, _);\n\n        /// <summary>\n        /// Copies the input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"copyContext\">The copy context.</param>\n        /// <returns>A copy of the input.</returns>\n        public static ArraySegment<byte> DeepCopy(ArraySegment<byte> input, CopyContext copyContext)\n        {\n            if (input.Array is null)\n            {\n                return default;\n            }\n\n            return input.AsSpan().ToArray();\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Memory{Byte}\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class MemoryOfByteCodec : IFieldCodec<Memory<byte>>\n    {\n        /// <inheritdoc/>\n        Memory<byte> IFieldCodec<Memory<byte>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static Memory<byte> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<byte[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var length = reader.ReadVarUInt32();\n            var result = reader.ReadBytes(length);\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        void IFieldCodec<Memory<byte>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Memory<byte> value) => WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Memory<byte> value) where TBufferWriter : IBufferWriter<byte>\n            => WriteField(ref writer, fieldIdDelta, typeof(Memory<byte>), value);\n\n        private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Memory<byte> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(Memory<byte>), WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)value.Length);\n            writer.Write(value.Span);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Memory{T}\"/> of <see cref=\"byte\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class MemoryOfByteCopier : IDeepCopier<Memory<byte>>\n    {\n        /// <inheritdoc/>\n        Memory<byte> IDeepCopier<Memory<byte>>.DeepCopy(Memory<byte> input, CopyContext _) => DeepCopy(input, _);\n\n        /// <summary>\n        /// Copies the input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"copyContext\">The copy context.</param>\n        /// <returns>A copy of the input.</returns>\n        public static Memory<byte> DeepCopy(Memory<byte> input, CopyContext copyContext)\n        {\n            if (input.IsEmpty)\n            {\n                return default;\n            }\n\n            return input.ToArray();\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"PooledBuffer\"/> instances.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class PooledBufferCodec : IFieldCodec<PooledBuffer>\n    {\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, PooledBuffer value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(PooledBuffer), WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)value.Length);\n            value.CopyTo(ref writer);\n\n            // Dispose of the value after sending it.\n            // PooledBuffer is special in this sense.\n            // Senders must not use the value after sending.\n            // Receivers must dispose of the value after use.\n            value.Reset();\n        }\n\n        public PooledBuffer ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var value = new PooledBuffer();\n            const int MaxSpanLength = 4096;\n            var length = (int)reader.ReadVarUInt32();\n            while (length > 0)\n            {\n                var copied = Math.Min(length, MaxSpanLength);\n                var span = value.GetSpan(copied)[..copied];\n                reader.ReadBytes(span);\n                value.Advance(copied);\n                length -= copied;\n            }\n\n            Debug.Assert(length == 0);\n            return value;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"PooledBuffer\"/> instances, which are assumed to be immutable.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class PooledBufferCopier : IDeepCopier<PooledBuffer>, IOptionalDeepCopier\n    {\n        public PooledBuffer DeepCopy(PooledBuffer input, CopyContext context) => input;\n        public bool IsShallowCopyable() => true;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/CollectionCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Serializer for <see cref=\"Collection{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterSerializer]\npublic sealed class CollectionCodec<T> : IFieldCodec<Collection<T>>, IBaseCodec<Collection<T>>\n{\n    private readonly Type CodecElementType = typeof(T);\n\n    private readonly IFieldCodec<T> _fieldCodec;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CollectionCodec{T}\"/> class.\n    /// </summary>\n    /// <param name=\"fieldCodec\">The field codec.</param>\n    public CollectionCodec(IFieldCodec<T> fieldCodec)\n    {\n        _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Collection<T> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n        Serialize(ref writer, value);\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    public Collection<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<Collection<T>, TInput>(ref reader, field);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        Collection<T> result = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                    if (length > 10240 && length > reader.Length)\n                    {\n                        ThrowInvalidSizeException(length);\n                    }\n\n                    result = new Collection<T>(new List<T>(length));\n                    ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                    break;\n                case 1:\n                    if (result is null)\n                    {\n                        ThrowLengthFieldMissing();\n                    }\n\n                    result.Add(_fieldCodec.ReadValue(ref reader, header));\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        if (result is null)\n        {\n            result = new();\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        }\n\n        return result;\n    }\n\n    private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n        $\"Declared length of {typeof(Collection<T>)}, {length}, is greater than total length of input.\");\n\n    private void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n\n    public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, Collection<T> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (value.Count > 0)\n        {\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value)\n            {\n                _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                innerFieldIdDelta = 0;\n            }\n        }\n    }\n\n    public void Deserialize<TInput>(ref Reader<TInput> reader, Collection<T> value)\n    {\n        // If the value has some values added by the constructor, clear them.\n        // If those values are in the serialized payload, they will be added below.\n        value.Clear();\n\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                    if (length > 10240 && length > reader.Length)\n                    {\n                        ThrowInvalidSizeException(length);\n                    }\n\n                    break;\n                case 1:\n                    value.Add(_fieldCodec.ReadValue(ref reader, header));\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n    }\n}\n\n/// <summary>\n/// Copier for <see cref=\"Collection{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterCopier]\npublic sealed class CollectionCopier<T> : IDeepCopier<Collection<T>>, IBaseCopier<Collection<T>>\n{\n    private readonly IDeepCopier<T> _copier;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CollectionCopier{T}\"/> class.\n    /// </summary>\n    /// <param name=\"valueCopier\">The value copier.</param>\n    public CollectionCopier(IDeepCopier<T> valueCopier)\n    {\n        _copier = valueCopier;\n    }\n\n    /// <inheritdoc/>\n    public Collection<T> DeepCopy(Collection<T> input, CopyContext context)\n    {\n        if (context.TryGetCopy<Collection<T>>(input, out var result))\n        {\n            return result;\n        }\n\n        if (input.GetType() != typeof(Collection<T>))\n        {\n            return context.DeepCopy(input);\n        }\n\n        result = new Collection<T>(new List<T>(input.Count));\n        context.RecordCopy(input, result);\n        foreach (var item in input)\n        {\n            result.Add(_copier.DeepCopy(item, context));\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    public void DeepCopy(Collection<T> input, Collection<T> output, CopyContext context)\n    {\n        output.Clear();\n\n        foreach (var item in input)\n        {\n            output.Add(_copier.DeepCopy(item, context));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/CommonCodecTypeFilter.cs",
    "content": "using System;\nusing System.CodeDom.Compiler;\nusing System.Linq;\nusing System.Reflection;\n\nusing Orleans.Metadata;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Defines common type filtering operations.\n/// </summary>\npublic class CommonCodecTypeFilter\n{\n    /// <summary>\n    /// Returns true if the provided type is a framework or abstract type.\n    /// </summary>\n    /// <param name=\"type\">The type to check.</param>\n    /// <returns><see langword=\"true\"/> if the type is a framework or abstract type, otherwise <see langword=\"false\"/>.</returns>\n    public static bool IsAbstractOrFrameworkType(Type type)\n    {\n        if (type.IsAbstract\n            || type.GetCustomAttributes<GeneratedCodeAttribute>().Any(a => a.Tool.Equals(\"OrleansCodeGen\"))\n            || type.Assembly.GetCustomAttribute<FrameworkPartAttribute>() is not null)\n        {\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/CompareInfoCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Globalization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"CompareInfo\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class CompareInfoCodec : IFieldCodec<CompareInfo>\n    {\n        /// <inheritdoc/>\n        public CompareInfo ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<CompareInfo, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            uint fieldId = 0;\n            string name = null;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        name = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = CompareInfo.GetCompareInfo(name);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, CompareInfo value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n            StringCodec.WriteField(ref writer, 0, value.Name);\n            writer.WriteEndObject();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ConcurrentDictionaryCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ConcurrentDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the t key.</typeparam>\n    /// <typeparam name=\"TValue\">The type of the t value.</typeparam>\n    [RegisterSerializer]\n    public sealed class ConcurrentDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<ConcurrentDictionary<TKey, TValue>, ConcurrentDictionarySurrogate<TKey, TValue>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConcurrentDictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ConcurrentDictionaryCodec(IValueSerializer<ConcurrentDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ConcurrentDictionary<TKey, TValue> ConvertFromSurrogate(ref ConcurrentDictionarySurrogate<TKey, TValue> surrogate)\n            => new(surrogate.Values, surrogate.Values.Comparer);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ConcurrentDictionary<TKey, TValue> value, ref ConcurrentDictionarySurrogate<TKey, TValue> surrogate)\n#if NET6_0_OR_GREATER\n            => surrogate.Values = new(value, value.Comparer);\n#else\n            => surrogate.Values = new(value);\n#endif\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ConcurrentDictionaryCodec{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [GenerateSerializer]\n    public struct ConcurrentDictionarySurrogate<TKey, TValue>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public Dictionary<TKey, TValue> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ConcurrentDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the t key.</typeparam>\n    /// <typeparam name=\"TValue\">The type of the t value.</typeparam>\n    [RegisterCopier]\n    public sealed class ConcurrentDictionaryCopier<TKey, TValue> : IDeepCopier<ConcurrentDictionary<TKey, TValue>>, IBaseCopier<ConcurrentDictionary<TKey, TValue>>\n    {\n        private readonly Type _fieldType = typeof(ConcurrentDictionary<TKey, TValue>);\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConcurrentDictionaryCopier{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCopier\">The key copier.</param>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public ConcurrentDictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n        }\n\n        /// <inheritdoc/>\n        public ConcurrentDictionary<TKey, TValue> DeepCopy(ConcurrentDictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ConcurrentDictionary<TKey, TValue>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n#if NET6_0_OR_GREATER\n            result = new(input.Comparer);\n#else\n            result = new();\n#endif\n            context.RecordCopy(input, result);\n            foreach (var pair in input)\n            {\n                result[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(ConcurrentDictionary<TKey, TValue> input, ConcurrentDictionary<TKey, TValue> output, CopyContext context)\n        {\n            foreach (var pair in input)\n            {\n                output[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ConcurrentQueueCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ConcurrentQueue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ConcurrentQueueCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ConcurrentQueue<T>, ConcurrentQueueSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConcurrentQueueCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ConcurrentQueueCodec(IValueSerializer<ConcurrentQueueSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n        \n        /// <inheritdoc/>\n        public override ConcurrentQueue<T> ConvertFromSurrogate(ref ConcurrentQueueSurrogate<T> surrogate) => new(surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ConcurrentQueue<T> value, ref ConcurrentQueueSurrogate<T> surrogate) => surrogate.Values = new(value);\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ConcurrentQueueCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ConcurrentQueueSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public Queue<T> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ConcurrentQueue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    [RegisterCopier]\n    public sealed class ConcurrentQueueCopier<T> : IDeepCopier<ConcurrentQueue<T>>, IBaseCopier<ConcurrentQueue<T>>\n    {\n        private readonly Type _fieldType = typeof(ConcurrentQueue<T>);\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConcurrentQueueCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public ConcurrentQueueCopier(IDeepCopier<T> valueCopier)\n        {\n            _copier = valueCopier;\n        }\n\n        /// <inheritdoc/>\n        public ConcurrentQueue<T> DeepCopy(ConcurrentQueue<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ConcurrentQueue<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new ConcurrentQueue<T>();\n            context.RecordCopy(input, result);\n            foreach (var item in input)\n            {\n                result.Enqueue(_copier.DeepCopy(item, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(ConcurrentQueue<T> input, ConcurrentQueue<T> output, CopyContext context)\n        {\n            foreach (var item in input)\n            {\n                output.Enqueue(_copier.DeepCopy(item, context));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ConsumeFieldExtension.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Extension methods for consuming unknown fields.\n    /// </summary>\n    public static class ConsumeFieldExtension\n    {\n        /// <summary>\n        /// Consumes an unknown field.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        public static void ConsumeUnknownField<TInput>(this ref Reader<TInput> reader, Field field) => ConsumeUnknownField(ref reader, ref field);\n\n        /// <summary>\n        /// Consumes an unknown field.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        public static void ConsumeUnknownField<TInput>(this ref Reader<TInput> reader, scoped ref Field field)\n        {\n            // References cannot themselves be referenced.\n            if (field.WireType == WireType.Reference)\n            {\n                ReferenceCodec.MarkValueField(reader.Session);\n                _ = reader.ReadVarUInt32();\n                return;\n            }\n\n            // Record a placeholder so that this field can later be correctly deserialized if it is referenced.\n            ReferenceCodec.RecordObject(reader.Session, new UnknownFieldMarker(field, reader.Position));\n\n            switch (field.WireType)\n            {\n                case WireType.VarInt:\n                    _ = reader.ReadVarUInt64();\n                    break;\n                case WireType.TagDelimited:\n                    // Since tag delimited fields can be comprised of other fields, recursively consume those, too.\n                    reader.ConsumeTagDelimitedField();\n                    break;\n                case WireType.LengthPrefixed:\n                    SkipFieldExtension.SkipLengthPrefixedField(ref reader);\n                    break;\n                case WireType.Fixed32:\n                    reader.Skip(4);\n                    break;\n                case WireType.Fixed64:\n                    reader.Skip(8);\n                    break;\n                case WireType.Extended:\n                    SkipFieldExtension.ThrowUnexpectedExtendedWireType(field);\n                    break;\n                default:\n                    SkipFieldExtension.ThrowUnexpectedWireType(field);\n                    break;\n            }\n        }\n\n        /// <summary>\n        /// Consumes a tag-delimited field.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        private static void ConsumeTagDelimitedField<TInput>(this ref Reader<TInput> reader)\n        {\n            while (true)\n            {\n                var field = reader.ReadFieldHeader();\n                if (field.IsEndObject)\n                {\n                    break;\n                }\n\n                if (field.IsEndBaseFields)\n                {\n                    continue;\n                }\n\n                reader.ConsumeUnknownField(field);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/CultureInfoCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System.Globalization;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"CultureInfo\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class CultureInfoCodec : GeneralizedReferenceTypeSurrogateCodec<CultureInfo, CultureInfoSurrogate>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CultureInfoCodec\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public CultureInfoCodec(IValueSerializer<CultureInfoSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override CultureInfo ConvertFromSurrogate(ref CultureInfoSurrogate surrogate) => new(surrogate.Name);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(CultureInfo value, ref CultureInfoSurrogate surrogate) => surrogate.Name = value.Name;\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"CultureInfoCodec\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    public struct CultureInfoSurrogate\n    {\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>The name.</value>\n        [Id(0)]\n        public string Name;\n    }\n\n    [RegisterCopier]\n    internal sealed class CultureInfoCopier : ShallowCopier<CultureInfo>, IDerivedTypeCopier { }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/DateOnlyCodec.cs",
    "content": "#if NET6_0_OR_GREATER\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Serializer for <see cref=\"DateOnly\"/>.\n/// </summary>\n[RegisterSerializer]\npublic sealed class DateOnlyCodec : IFieldCodec<DateOnly>\n{\n    void IFieldCodec<DateOnly>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, DateOnly value)\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(DateOnly), WireType.Fixed32);\n        writer.WriteInt32(value.DayNumber);\n    }\n\n    /// <summary>\n    /// Writes a field without type info (expected type is statically known).\n    /// </summary>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, DateOnly value) where TBufferWriter : IBufferWriter<byte>\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed32);\n        writer.WriteInt32(value.DayNumber);\n    }\n\n    /// <inheritdoc/>\n    DateOnly IFieldCodec<DateOnly>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n    /// <summary>\n    /// Reads a <see cref=\"DateOnly\"/> value.\n    /// </summary>\n    /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n    /// <param name=\"reader\">The reader.</param>\n    /// <param name=\"field\">The field.</param>\n    /// <returns>The <see cref=\"DateOnly\"/> value.</returns>\n    public static DateOnly ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        ReferenceCodec.MarkValueField(reader.Session);\n        field.EnsureWireType(WireType.Fixed32);\n        return DateOnly.FromDayNumber(reader.ReadInt32());\n    }\n}\n#endif"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/DateTimeCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"DateTime\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class DateTimeCodec : IFieldCodec<DateTime>\n    {\n        void IFieldCodec<DateTime>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, DateTime value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(DateTime), WireType.Fixed64);\n            writer.WriteInt64(value.ToBinary());\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, DateTime value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed64);\n            writer.WriteInt64(value.ToBinary());\n        }\n\n        /// <inheritdoc/>\n        DateTime IFieldCodec<DateTime>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a <see cref=\"DateTime\"/> value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The <see cref=\"DateTime\"/> value.</returns>\n        public static DateTime ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            field.EnsureWireType(WireType.Fixed64);\n            return DateTime.FromBinary(reader.ReadInt64());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/DateTimeOffsetCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"DateTimeOffset\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class DateTimeOffsetCodec : IFieldCodec<DateTimeOffset>\n    {\n        void IFieldCodec<DateTimeOffset>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, DateTimeOffset value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(DateTimeOffset), WireType.TagDelimited);\n            DateTimeCodec.WriteField(ref writer, 0, value.DateTime);\n            TimeSpanCodec.WriteField(ref writer, 1, value.Offset);\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, DateTimeOffset value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.TagDelimited);\n            DateTimeCodec.WriteField(ref writer, 0, value.DateTime);\n            TimeSpanCodec.WriteField(ref writer, 1, value.Offset);\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        DateTimeOffset IFieldCodec<DateTimeOffset>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <inheritdoc/>\n        public static DateTimeOffset ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            field.EnsureWireTypeTagDelimited();\n\n            uint fieldId = 0;\n            TimeSpan offset = default;\n            DateTime dateTime = default;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        dateTime = DateTimeCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        offset = TimeSpanCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return new DateTimeOffset(dateTime, offset);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/DictionaryCodec.cs",
    "content": "﻿#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Dictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class DictionaryCodec<TKey, TValue> : IFieldCodec<Dictionary<TKey, TValue>> where TKey : notnull\n    {\n        private readonly Type _keyFieldType = typeof(TKey);\n        private readonly Type _valueFieldType = typeof(TValue);\n\n        private readonly IFieldCodec<TKey> _keyCodec;\n        private readonly IFieldCodec<TValue> _valueCodec;\n        private readonly IFieldCodec<IEqualityComparer<TKey>> _comparerCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCodec\">The key codec.</param>\n        /// <param name=\"valueCodec\">The value codec.</param>\n        /// <param name=\"comparerCodec\">The comparer codec.</param>\n        public DictionaryCodec(\n            IFieldCodec<TKey> keyCodec,\n            IFieldCodec<TValue> valueCodec,\n            IFieldCodec<IEqualityComparer<TKey>> comparerCodec)\n        {\n            _keyCodec = OrleansGeneratedCodeHelper.UnwrapService(this, keyCodec);\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n            _comparerCodec = OrleansGeneratedCodeHelper.UnwrapService(this, comparerCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Dictionary<TKey, TValue> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            if (value.Comparer is var comparer && comparer != EqualityComparer<TKey>.Default)\n            {\n                _comparerCodec.WriteField(ref writer, 0, null, comparer);\n            }\n\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 1, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _keyCodec.WriteField(ref writer, innerFieldIdDelta, _keyFieldType, element.Key);\n                    _valueCodec.WriteField(ref writer, 0, _valueFieldType, element.Value);\n                    innerFieldIdDelta = 0;\n                }\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public Dictionary<TKey, TValue> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Dictionary<TKey, TValue>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            TKey? key = default;\n            var valueExpected = false;\n            Dictionary<TKey, TValue>? result = null;\n            IEqualityComparer<TKey>? comparer = null;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        comparer = _comparerCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = CreateInstance(length, comparer, reader.Session, placeholderReferenceId);\n                        break;\n                    case 2:\n                        if (result is null)\n                            ThrowLengthFieldMissing();\n\n                        if (!valueExpected)\n                        {\n                            key = _keyCodec.ReadValue(ref reader, header);\n                            valueExpected = true;\n                        }\n                        else\n                        {\n                            result!.Add(key!, _valueCodec.ReadValue(ref reader, header));\n                            valueExpected = false;\n                        }\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            result ??= CreateInstance(0, comparer, reader.Session, placeholderReferenceId);\n            return result;\n        }\n\n        private Dictionary<TKey, TValue> CreateInstance(int length, IEqualityComparer<TKey>? comparer, SerializerSession session, uint placeholderReferenceId)\n        {\n            var result = new Dictionary<TKey, TValue>(length, comparer);\n            ReferenceCodec.RecordObject(session, result, placeholderReferenceId);\n            return result;\n        }\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(Dictionary<TKey, TValue>)}, {length}, is greater than total length of input.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized dictionary is missing its length field.\");\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Dictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the t key.</typeparam>\n    /// <typeparam name=\"TValue\">The type of the t value.</typeparam>\n    [RegisterCopier]\n    public sealed class DictionaryCopier<TKey, TValue> : IDeepCopier<Dictionary<TKey, TValue>>, IBaseCopier<Dictionary<TKey, TValue>> where TKey : notnull\n    {\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n        private readonly ConstructorInfo _baseConstructor;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DictionaryCopier{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCopier\">The key copier.</param>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public DictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n            _baseConstructor = typeof(Dictionary<TKey, TValue>).GetConstructor([typeof(int), typeof(IEqualityComparer<TKey>)])!;\n        }\n\n        /// <inheritdoc/>\n        public Dictionary<TKey, TValue> DeepCopy(Dictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<Dictionary<TKey, TValue>>(input, out var result))\n            {\n                return result!;\n            }\n\n            if (input.GetType() != typeof(Dictionary<TKey, TValue>))\n            {\n                return context.DeepCopy(input)!;\n            }\n\n            result = new Dictionary<TKey, TValue>(input.Count, input.Comparer);\n            context.RecordCopy(input, result);\n            foreach (var pair in input)\n            {\n                result[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(Dictionary<TKey, TValue> input, Dictionary<TKey, TValue> output, CopyContext context)\n        {\n            output.Clear();\n            if (input.Comparer != EqualityComparer<TKey>.Default)\n            {\n                _baseConstructor.Invoke(output, [input.Count, input.Comparer]);\n            }\n            else\n            {\n                output.EnsureCapacity(input.Count);\n            }\n\n            foreach (var pair in input)\n            {\n                output[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Dictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class DictionaryBaseCodec<TKey, TValue> : IBaseCodec<Dictionary<TKey, TValue>> where TKey : notnull\n    {\n        private readonly Type _keyFieldType = typeof(TKey);\n        private readonly Type _valueFieldType = typeof(TValue);\n\n        private readonly IFieldCodec<TKey> _keyCodec;\n        private readonly IFieldCodec<TValue> _valueCodec;\n        private readonly IFieldCodec<IEqualityComparer<TKey>> _comparerCodec;\n        private readonly ConstructorInfo _baseConstructor;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCodec\">The key codec.</param>\n        /// <param name=\"valueCodec\">The value codec.</param>\n        /// <param name=\"comparerCodec\">The comparer codec.</param>\n        public DictionaryBaseCodec(\n            IFieldCodec<TKey> keyCodec,\n            IFieldCodec<TValue> valueCodec,\n            IFieldCodec<IEqualityComparer<TKey>> comparerCodec)\n        {\n            _keyCodec = OrleansGeneratedCodeHelper.UnwrapService(this, keyCodec);\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n            _comparerCodec = OrleansGeneratedCodeHelper.UnwrapService(this, comparerCodec);\n            _baseConstructor = typeof(Dictionary<TKey, TValue>).GetConstructor([typeof(int), typeof(IEqualityComparer<TKey>)])!;\n        }\n\n        void IBaseCodec<Dictionary<TKey, TValue>>.Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, Dictionary<TKey, TValue> value)\n        {\n            if (value.Comparer is var comparer && comparer != EqualityComparer<TKey>.Default)\n            {\n                _comparerCodec.WriteField(ref writer, 0, null, comparer);\n            }\n\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 1, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _keyCodec.WriteField(ref writer, innerFieldIdDelta, _keyFieldType, element.Key);\n                    _valueCodec.WriteField(ref writer, 0, _valueFieldType, element.Value);\n                    innerFieldIdDelta = 0;\n                }\n            }\n        }\n\n        void IBaseCodec<Dictionary<TKey, TValue>>.Deserialize<TInput>(ref Reader<TInput> reader, Dictionary<TKey, TValue> value)\n        {\n            // If the dictionary has some values added by the default constructor, clear them.\n            // If those values are in the serialized payload, they will be added below.\n            value.Clear();\n\n            TKey? key = default;\n            var valueExpected = false;\n            IEqualityComparer<TKey>? comparer = null;\n            uint fieldId = 0;\n            bool hasLengthField = false;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        comparer = _comparerCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        hasLengthField = true;\n                        if (comparer is not null)\n                        {\n                            _baseConstructor.Invoke(value, [length, comparer]);\n                        }\n                        else\n                        {\n                            value.EnsureCapacity(length);\n                        }\n\n                        break;\n                    case 2:\n                        if (!hasLengthField)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        if (!valueExpected)\n                        {\n                            key = _keyCodec.ReadValue(ref reader, header);\n                            valueExpected = true;\n                        }\n                        else\n                        {\n                            value.Add(key!, _valueCodec.ReadValue(ref reader, header));\n                            valueExpected = false;\n                        }\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n        }\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(Dictionary<TKey, TValue>)}, {length}, is greater than total length of input.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized dictionary is missing its length field.\");\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/Enum32BaseCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for enum types with a 32-bit base.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <seealso cref=\"Orleans.Serialization.Codecs.IFieldCodec{T}\" />\n    public abstract class Enum32BaseCodec<T> : IFieldCodec<T> where T : unmanaged, Enum\n    {\n        private readonly Type CodecFieldType = typeof(T);\n\n        /// <inheritdoc/>\n        public unsafe void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, T value) where TBufferWriter : IBufferWriter<byte>\n        {\n            HolderStruct holder;\n            holder.Value = value;\n            var intValue = *(int*)&holder;\n            Int32Codec.WriteField(ref writer, fieldIdDelta, expectedType, intValue, CodecFieldType);\n        }\n\n        /// <inheritdoc/>\n        public unsafe T ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            var intValue = Int32Codec.ReadValue(ref reader, field);\n            return *(T*)&intValue;\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        private struct HolderStruct\n        {\n            public T Value;\n            public int Padding;\n        }\n    }\n\n    /// <summary>\n    /// Serializer and copier for <see cref=\"DateTimeKind\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    internal sealed class DateTimeKindCodec : Enum32BaseCodec<DateTimeKind> { }\n\n    /// <summary>\n    /// Serializer and copier for <see cref=\"DayOfWeek\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    internal sealed class DayOfWeekCodec : Enum32BaseCodec<DayOfWeek> { }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/FloatCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"float\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class FloatCodec : IFieldCodec<float>\n    {\n        void IFieldCodec<float>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, float value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(float), WireType.Fixed32);\n#if NET6_0_OR_GREATER\n            writer.WriteUInt32(BitConverter.SingleToUInt32Bits(value));\n#else\n            writer.WriteUInt32((uint)BitConverter.SingleToInt32Bits(value));\n#endif\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, float value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed32);\n#if NET6_0_OR_GREATER\n            writer.WriteUInt32(BitConverter.SingleToUInt32Bits(value));\n#else\n            writer.WriteUInt32((uint)BitConverter.SingleToInt32Bits(value));\n#endif\n        }\n\n        /// <inheritdoc/>\n        float IFieldCodec<float>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static float ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            switch (field.WireType)\n            {\n                case WireType.Fixed32:\n                    return ReadFloatRaw(ref reader);\n                case WireType.Fixed64:\n                    {\n                        var value = DoubleCodec.ReadDoubleRaw(ref reader);\n                        if ((value > float.MaxValue || value < float.MinValue) && !double.IsInfinity(value) && !double.IsNaN(value))\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (float)value;\n                    }\n\n                case WireType.LengthPrefixed:\n                    return (float)DecimalCodec.ReadDecimalRaw(ref reader);\n#if NET6_0_OR_GREATER\n                case WireType.VarInt:\n                    return (float)HalfCodec.ReadHalfRaw(ref reader);\n#endif\n                default:\n                    ThrowWireTypeOutOfRange(field.WireType);\n                    return 0;\n            }\n        }\n\n        /// <summary>\n        /// Reads a value without any protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#if NET6_0_OR_GREATER\n        public static float ReadFloatRaw<TInput>(ref Reader<TInput> reader) => BitConverter.UInt32BitsToSingle(reader.ReadUInt32());\n#else\n        public static float ReadFloatRaw<TInput>(ref Reader<TInput> reader) => BitConverter.Int32BitsToSingle((int)reader.ReadUInt32());\n#endif\n\n        private static void ThrowWireTypeOutOfRange(WireType wireType) => throw new UnsupportedWireTypeException(\n            $\"WireType {wireType} is not supported by this codec.\");\n\n        private static void ThrowValueOutOfRange<T>(T value) => throw new OverflowException(\n            $\"The {typeof(T)} value has a magnitude too high {value} to be converted to {typeof(float)}.\");\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"double\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class DoubleCodec : IFieldCodec<double>\n    {\n        void IFieldCodec<double>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, double value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(double), WireType.Fixed64);\n#if NET6_0_OR_GREATER\n            writer.WriteUInt64(BitConverter.DoubleToUInt64Bits(value));\n#else\n            writer.WriteUInt64((ulong)BitConverter.DoubleToInt64Bits(value));\n#endif\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, double value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed64);\n#if NET6_0_OR_GREATER\n            writer.WriteUInt64(BitConverter.DoubleToUInt64Bits(value));\n#else\n            writer.WriteUInt64((ulong)BitConverter.DoubleToInt64Bits(value));\n#endif\n        }\n\n        /// <inheritdoc/>\n        double IFieldCodec<double>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static double ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            switch (field.WireType)\n            {\n                case WireType.Fixed32:\n                    return FloatCodec.ReadFloatRaw(ref reader);\n                case WireType.Fixed64:\n                    return ReadDoubleRaw(ref reader);\n                case WireType.LengthPrefixed:\n                    return (double)DecimalCodec.ReadDecimalRaw(ref reader);\n#if NET6_0_OR_GREATER\n                case WireType.VarInt:\n                    return (double)HalfCodec.ReadHalfRaw(ref reader);\n#endif\n                default:\n                    ThrowWireTypeOutOfRange(field.WireType);\n                    return 0;\n            }\n        }\n\n        /// <summary>\n        /// Reads a value without any protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#if NET6_0_OR_GREATER\n        public static double ReadDoubleRaw<TInput>(ref Reader<TInput> reader) => BitConverter.UInt64BitsToDouble(reader.ReadUInt64());\n#else\n        public static double ReadDoubleRaw<TInput>(ref Reader<TInput> reader) => BitConverter.Int64BitsToDouble((long)reader.ReadUInt64());\n#endif\n\n        private static void ThrowWireTypeOutOfRange(WireType wireType) => throw new UnsupportedWireTypeException(\n            $\"WireType {wireType} is not supported by this codec.\");\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"decimal\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class DecimalCodec : IFieldCodec<decimal>\n    {\n        private const int Width = 16;\n\n        void IFieldCodec<decimal>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, decimal value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(decimal), WireType.LengthPrefixed);\n            WriteRaw(ref writer, ref value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, decimal value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n            WriteRaw(ref writer, ref value);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, ref decimal value) where TBufferWriter : IBufferWriter<byte>\n        {\n            writer.WriteVarUInt7(Width);\n\n#if NET6_0_OR_GREATER\n            if (BitConverter.IsLittleEndian)\n            {\n                writer.Write(MemoryMarshal.AsBytes(new Span<decimal>(ref value)));\n                return;\n            }\n#endif\n\n            ref var holder = ref Unsafe.As<decimal, DecimalConverter>(ref value);\n            writer.WriteUInt32(holder.Flags);\n            writer.WriteUInt32(holder.Hi32);\n            writer.WriteUInt64(holder.Lo64);\n        }\n\n        /// <inheritdoc/>\n        decimal IFieldCodec<decimal>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static decimal ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            switch (field.WireType)\n            {\n                case WireType.Fixed32:\n                    {\n                        var value = FloatCodec.ReadFloatRaw(ref reader);\n                        if (value > (float)decimal.MaxValue || value < (float)decimal.MinValue)\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (decimal)value;\n                    }\n                case WireType.Fixed64:\n                    {\n                        var value = DoubleCodec.ReadDoubleRaw(ref reader);\n                        if (value > (double)decimal.MaxValue || value < (double)decimal.MinValue)\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (decimal)value;\n                    }\n                case WireType.LengthPrefixed:\n                    return ReadDecimalRaw(ref reader);\n#if NET6_0_OR_GREATER\n                case WireType.VarInt:\n                    return (decimal)HalfCodec.ReadHalfRaw(ref reader);\n#endif\n                default:\n                    ThrowWireTypeOutOfRange(field.WireType);\n                    return 0;\n            }\n        }\n\n        /// <summary>\n        /// Reads a value without protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        public static decimal ReadDecimalRaw<TInput>(ref Reader<TInput> reader)\n        {\n            var length = reader.ReadVarUInt32();\n            if (length != Width)\n            {\n                throw new UnexpectedLengthPrefixValueException(\"decimal\", Width, length);\n            }\n\n#if NET6_0_OR_GREATER\n            if (BitConverter.IsLittleEndian)\n            {\n                Unsafe.SkipInit(out decimal res);\n                reader.ReadBytes(MemoryMarshal.AsBytes(new Span<decimal>(ref res)));\n                return res;\n            }\n#endif\n\n            DecimalConverter holder;\n            holder.Flags = reader.ReadUInt32();\n            holder.Hi32 = reader.ReadUInt32();\n            holder.Lo64 = reader.ReadUInt64();\n            return Unsafe.As<DecimalConverter, decimal>(ref holder);\n        }\n\n        private struct DecimalConverter\n        {\n            public uint Flags;\n            public uint Hi32;\n            public ulong Lo64;\n        }\n\n        private static void ThrowWireTypeOutOfRange(WireType wireType) => throw new UnsupportedWireTypeException(\n            $\"WireType {wireType} is not supported by this codec.\");\n\n        private static void ThrowValueOutOfRange<T>(T value) => throw new OverflowException(\n            $\"The {typeof(T)} value has a magnitude too high {value} to be converted to {typeof(decimal)}.\");\n    }\n\n#if NET6_0_OR_GREATER\n    /// <summary>\n    /// Serializer for <see cref=\"Half\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class HalfCodec : IFieldCodec<Half>\n    {\n        void IFieldCodec<Half>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Half value)\n        {\n            var asUShort = BitConverter.HalfToUInt16Bits(value);\n            UInt16Codec.WriteField(ref writer, fieldIdDelta, expectedType, asUShort, typeof(Half));\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Half value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var asUShort = BitConverter.HalfToUInt16Bits(value);\n            UInt16Codec.WriteField(ref writer, fieldIdDelta, asUShort);\n        }\n\n        /// <inheritdoc/>\n        Half IFieldCodec<Half>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static Half ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            switch (field.WireType)\n            {\n                case WireType.VarInt:\n                    return ReadHalfRaw(ref reader);\n                case WireType.Fixed32:\n                    {\n                        var value = FloatCodec.ReadFloatRaw(ref reader);\n                        if ((value > (float)Half.MaxValue || value < (float)Half.MinValue) && !float.IsInfinity(value) && !float.IsNaN(value))\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (Half)value;\n                    }\n                case WireType.Fixed64:\n                    {\n                        var value = DoubleCodec.ReadDoubleRaw(ref reader);\n                        if ((value > (double)Half.MaxValue || value < (double)Half.MinValue) && !double.IsInfinity(value) && !double.IsNaN(value))\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (Half)value;\n                    }\n\n                case WireType.LengthPrefixed:\n                    {\n                        var value = DecimalCodec.ReadDecimalRaw(ref reader);\n                        if (value > (decimal)Half.MaxValue || value < (decimal)Half.MinValue)\n                        {\n                            ThrowValueOutOfRange(value);\n                        }\n\n                        return (Half)value;\n                    }\n                default:\n                    ThrowWireTypeOutOfRange(field.WireType);\n                    return default;\n            }\n        }\n\n        /// <summary>\n        /// Reads a value without protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        internal static Half ReadHalfRaw<TInput>(ref Reader<TInput> reader) => BitConverter.UInt16BitsToHalf(reader.ReadVarUInt16());\n\n        [DoesNotReturn]\n        private static void ThrowWireTypeOutOfRange(WireType wireType) => throw new UnsupportedWireTypeException(\n            $\"WireType {wireType} is not supported by this codec.\");\n\n        [DoesNotReturn]\n        private static void ThrowValueOutOfRange<T>(T value) => throw new OverflowException(\n            $\"The {typeof(T)} value has a magnitude too high {value} to be converted to {typeof(Half)}.\");\n    }\n#endif\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/GeneralizedReferenceTypeSurrogateCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Surrogate serializer for <typeparamref name=\"TField\"/> and all sub-types.\n    /// </summary>\n    /// <typeparam name=\"TField\">The type which the implementation of this class supports.</typeparam>\n    /// <typeparam name=\"TSurrogate\">The surrogate type serialized in place of <typeparamref name=\"TField\"/>.</typeparam>\n    public abstract class GeneralizedReferenceTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField>, IDerivedTypeCodec where TField : class where TSurrogate : struct\n    {\n        private readonly Type CodecFieldType = typeof(TField);\n        private readonly IValueSerializer<TSurrogate> _surrogateSerializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GeneralizedReferenceTypeSurrogateCodec{TField, TSurrogate}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        protected GeneralizedReferenceTypeSurrogateCodec(IValueSerializer<TSurrogate> surrogateSerializer)\n        {\n            _surrogateSerializer = surrogateSerializer;\n        }\n\n        /// <inheritdoc/>\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<TField, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            TSurrogate surrogate = default;\n            _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n            var result = ConvertFromSurrogate(ref surrogate);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, CodecFieldType, value))\n            {\n                return;\n            }\n\n            writer.WriteStartObject(fieldIdDelta, expectedType, CodecFieldType);\n            TSurrogate surrogate = default;\n            ConvertToSurrogate(value, ref surrogate);\n            _surrogateSerializer.Serialize(ref writer, ref surrogate);\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Converts a value from the surrogate type to the field type.\n        /// </summary>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        /// <returns>The value.</returns>\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n\n        /// <summary>\n        /// Converts a value to the surrogate type.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/GeneralizedValueTypeSurrogateCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Surrogate serializer for <typeparamref name=\"TField\"/> and all sub-types.\n    /// </summary>\n    /// <typeparam name=\"TField\">The type which the implementation of this class supports.</typeparam>\n    /// <typeparam name=\"TSurrogate\">The surrogate type serialized in place of <typeparamref name=\"TField\"/>.</typeparam>\n    public abstract class GeneralizedValueTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField> where TField : struct where TSurrogate : struct\n    {\n        private readonly Type CodecFieldType = typeof(TField);\n        private readonly IValueSerializer<TSurrogate> _surrogateSerializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GeneralizedValueTypeSurrogateCodec{TField, TSurrogate}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        protected GeneralizedValueTypeSurrogateCodec(IValueSerializer<TSurrogate> surrogateSerializer)\n        {\n            _surrogateSerializer = surrogateSerializer;\n        }\n\n        /// <inheritdoc/>\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            TSurrogate surrogate = default;\n            _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n            var result = ConvertFromSurrogate(ref surrogate);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, CodecFieldType);\n            TSurrogate surrogate = default;\n            ConvertToSurrogate(value, ref surrogate);\n            _surrogateSerializer.Serialize(ref writer, ref surrogate);\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Converts a value from the surrogate type to the field type.\n        /// </summary>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        /// <returns>The value.</returns>\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n\n        /// <summary>\n        /// Converts a value to the surrogate type.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/GuidCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Guid\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class GuidCodec : IFieldCodec<Guid>\n    {\n        private const int Width = 16;\n\n        void IFieldCodec<Guid>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Guid value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(Guid), WireType.LengthPrefixed);\n            writer.WriteVarUInt7(Width);\n            WriteRaw(ref writer, value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Guid value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n            writer.WriteVarUInt7(Width);\n            WriteRaw(ref writer, value);\n        }\n\n        /// <inheritdoc/>\n        Guid IFieldCodec<Guid>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static Guid ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n\n            uint length = reader.ReadVarUInt32();\n            if (length != Width)\n            {\n                throw new UnexpectedLengthPrefixValueException(nameof(Guid), Width, length);\n            }\n\n            return ReadRaw(ref reader);\n        }\n\n        /// <summary>\n        /// Writes the raw GUID content.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, Guid value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (BitConverter.IsLittleEndian)\n            {\n#if NET7_0_OR_GREATER\n                writer.Write(MemoryMarshal.AsBytes(new Span<Guid>(ref value)));\n#else\n                writer.EnsureContiguous(Width);\n                if (value.TryWriteBytes(writer.WritableSpan))\n                {\n                    writer.AdvanceSpan(Width);\n                    return;\n                }\n                writer.Write(value.ToByteArray());\n#endif\n            }\n            else\n            {\n                writer.EnsureContiguous(Width);\n                var done = value.TryWriteBytes(writer.WritableSpan);\n                Debug.Assert(done);\n                writer.AdvanceSpan(Width);\n            }\n        }\n\n        /// <summary>\n        /// Reads the raw GUID content.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Guid ReadRaw<TInput>(ref Reader<TInput> reader)\n        {\n#if NET7_0_OR_GREATER\n            Unsafe.SkipInit(out Guid res);\n            var bytes = MemoryMarshal.AsBytes(new Span<Guid>(ref res));\n            reader.ReadBytes(bytes);\n\n            if (BitConverter.IsLittleEndian)\n                return res;\n\n            return new Guid(bytes);\n#else\n            if (reader.TryReadBytes(Width, out var readOnly))\n            {\n                return new Guid(readOnly);\n            }\n\n            Span<byte> bytes = stackalloc byte[Width];\n            reader.ReadBytes(bytes);\n\n            return new Guid(bytes);\n#endif\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/HashSetCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"HashSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class HashSetCodec<T> : IFieldCodec<HashSet<T>>, IBaseCodec<HashSet<T>>\n    {\n        private readonly Type CodecElementType = typeof(T);\n        private readonly Type _comparerType = typeof(IEqualityComparer<T>);\n        private readonly ConstructorInfo _baseConstructor;\n\n        private readonly IFieldCodec<T> _fieldCodec;\n        private readonly IFieldCodec<IEqualityComparer<T>> _comparerCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"HashSetCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        /// <param name=\"comparerCodec\">The comparer codec.</param>\n        public HashSetCodec(IFieldCodec<T> fieldCodec, IFieldCodec<IEqualityComparer<T>> comparerCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n            _comparerCodec = OrleansGeneratedCodeHelper.UnwrapService(this, comparerCodec);\n            _baseConstructor = typeof(HashSet<T>).GetConstructor([typeof(int), typeof(IEqualityComparer<T>)])!;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, HashSet<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            Serialize(ref writer, value);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public HashSet<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<HashSet<T>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            HashSet<T> result = null;\n            IEqualityComparer<T> comparer = null;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        comparer = _comparerCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = CreateInstance(length, comparer, reader.Session, placeholderReferenceId);\n                        break;\n                    case 2:\n                        if (result is null)\n                            ThrowLengthFieldMissing();\n\n                        result.Add(_fieldCodec.ReadValue(ref reader, header));\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            result ??= CreateInstance(0, comparer, reader.Session, placeholderReferenceId);\n            return result;\n        }\n\n        private static HashSet<T> CreateInstance(int length, IEqualityComparer<T> comparer, SerializerSession session, uint placeholderReferenceId)\n        {\n            var result = new HashSet<T>(length, comparer);\n            ReferenceCodec.RecordObject(session, result, placeholderReferenceId);\n            return result;\n        }\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(HashSet<T>)}, {length}, is greater than total length of input.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized set is missing its length field.\");\n\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, HashSet<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value.Comparer != EqualityComparer<T>.Default)\n            {\n                _comparerCodec.WriteField(ref writer, 0, _comparerType, value.Comparer);\n            }\n\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 1, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                    innerFieldIdDelta = 0;\n                }\n            }\n        }\n\n        void IBaseCodec<HashSet<T>>.Deserialize<TInput>(ref Reader<TInput> reader, HashSet<T> value)\n        {\n            // If the value has some values added by the constructor, clear them.\n            // If those values are in the serialized payload, they will be added below.\n            value.Clear();\n\n            IEqualityComparer<T> comparer = null;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        comparer = _comparerCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        // Re-initialize the class by calling the constructor.\n                        if (comparer is not null)\n                        {\n                            _baseConstructor.Invoke(value, [length, comparer]);\n                        }\n                        else\n                        {\n                            value.EnsureCapacity(length);\n                        }\n\n                        break;\n                    case 2:\n                        value.Add(_fieldCodec.ReadValue(ref reader, header));\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"HashSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <remarks>\n    /// Initializes a new instance of the <see cref=\"HashSetCopier{T}\"/> class.\n    /// </remarks>\n    /// <param name=\"valueCopier\">The value copier.</param>\n    [RegisterCopier]\n    public sealed class HashSetCopier<T>(IDeepCopier<T> valueCopier) : IDeepCopier<HashSet<T>>, IBaseCopier<HashSet<T>>\n    {\n        private readonly Type _fieldType = typeof(HashSet<T>);\n        private readonly IDeepCopier<T> _copier = valueCopier;\n        private readonly ConstructorInfo _baseConstructor = typeof(HashSet<T>).GetConstructor([typeof(int), typeof(IEqualityComparer<T>)])!;\n\n        /// <inheritdoc/>\n        public HashSet<T> DeepCopy(HashSet<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<HashSet<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new(input.Count, input.Comparer);\n            context.RecordCopy(input, result);\n            foreach (var item in input)\n            {\n                result.Add(_copier.DeepCopy(item, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(HashSet<T> input, HashSet<T> output, CopyContext context)\n        {\n            // If the value has some values added by the constructor, clear them.\n            // If those values are in the serialized payload, they will be added below.\n            output.Clear();\n            if (input.Comparer != EqualityComparer<T>.Default)\n            {\n                _baseConstructor.Invoke(output, [input.Count, input.Comparer]);\n            }\n            else\n            {\n                output.EnsureCapacity(input.Count);\n            }\n\n            foreach (var item in input)\n            {\n                output.Add(_copier.DeepCopy(item, context));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/IFieldCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Marker type for field codecs.\n    /// </summary>\n    public interface IFieldCodec\n    {\n        /// <summary>\n        /// Writes a field using the provided untyped value. The type must still match the codec instance!\n        /// </summary>\n        void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>;\n\n        /// <summary>\n        /// Reads a value and returns it untyped. The type must still match the codec instance!\n        /// </summary>\n        object ReadValue<TInput>(ref Reader<TInput> reader, Field field);\n    }\n\n    /// <summary>\n    /// Provides functionality for reading and writing values of a specified type.\n    /// Implements the <see cref=\"Orleans.Serialization.Codecs.IFieldCodec\" />\n    /// </summary>\n    /// <typeparam name=\"T\">The type which this implementation can read and write.</typeparam>\n    /// <seealso cref=\"Orleans.Serialization.Codecs.IFieldCodec\" />\n    public interface IFieldCodec<T> : IFieldCodec\n    {\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, T value) where TBufferWriter : IBufferWriter<byte>;\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        new T ReadValue<TInput>(ref Reader<TInput> reader, Field field);\n\n        void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n            => WriteField(ref writer, fieldIdDelta, expectedType, (T)value);\n\n        object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n    }\n\n    /// <summary>\n    /// Marker interface for codecs which directly support serializing all derived types of their specified type.\n    /// </summary>\n    public interface IDerivedTypeCodec : IFieldCodec\n    {\n    }\n\n    /// <summary>\n    /// Hooks for stages in serialization and copying.\n    /// </summary>\n    /// <typeparam name=\"T\">The underlying value type.</typeparam>\n    public interface ISerializationCallbacks<T>\n    {\n        /// <summary>\n        /// Called when serializing.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        void OnSerializing(T value);\n\n        /// <summary>\n        /// Called when a value has been serialized.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        void OnSerialized(T value);\n\n        /// <summary>\n        /// Called when deserializing.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        void OnDeserializing(T value);\n\n        /// <summary>\n        /// Called when a value has been deserialized.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        void OnDeserialized(T value);\n\n        /// <summary>\n        /// Called when copying.\n        /// </summary>\n        /// <param name=\"original\">The original value.</param>\n        /// <param name=\"result\">The copy.</param>\n        void OnCopying(T original, T result);\n\n        /// <summary>\n        /// Called when a value has been copied.\n        /// </summary>\n        /// <param name=\"original\">The original value.</param>\n        /// <param name=\"result\">The copy.</param>\n        void OnCopied(T original, T result);\n    }\n\n    internal sealed class UntypedCodecWrapper<TField> : IFieldCodec<TField>\n    {\n        private readonly IFieldCodec _codec;\n\n        public UntypedCodecWrapper(IFieldCodec codec) => _codec = codec;\n\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n            => _codec.WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n            => _codec.WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field) => (TField)_codec.ReadValue(ref reader, field);\n\n        object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => _codec.ReadValue(ref reader, field);\n    }\n\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/IPAddressCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Net;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"IPAddress\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class IPAddressCodec : IFieldCodec<IPAddress>, IDerivedTypeCodec\n    {\n        IPAddress IFieldCodec<IPAddress>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static IPAddress ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n            {\n                return ReferenceCodec.ReadReference<IPAddress, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var result = ReadRaw(ref reader);\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        /// <summary>\n        /// Reads the raw length prefixed IP address value.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static IPAddress ReadRaw<TInput>(ref Buffers.Reader<TInput> reader)\n        {\n            var length = reader.ReadVarUInt32();\n#if NET5_0_OR_GREATER\n            if (reader.TryReadBytes((int)length, out var bytes))\n                return new(bytes);\n#endif\n            return new(reader.ReadBytes(length));\n        }\n\n        void IFieldCodec<IPAddress>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, IPAddress value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, typeof(IPAddress), value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(IPAddress), WireType.LengthPrefixed);\n            WriteRaw(ref writer, value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, IPAddress value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n            WriteRaw(ref writer, value);\n        }\n\n        /// <summary>\n        /// Writes the raw length prefixed IP address value.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteRaw<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, IPAddress value) where TBufferWriter : IBufferWriter<byte>\n        {\n            writer.EnsureContiguous(1 + 16);\n            var span = writer.WritableSpan;\n            if (!value.TryWriteBytes(span[1..], out var length)) ThrowNotSupported();\n            span[0] = (byte)(length * 2 + 1); // VarInt length\n            writer.AdvanceSpan(1 + length);\n        }\n\n        private static void ThrowNotSupported() => throw new NotSupportedException();\n    }\n\n    [RegisterCopier]\n    internal sealed class IPAddressCopier : ShallowCopier<IPAddress>, IDerivedTypeCopier { }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/IPEndPointCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.Net;\n\n#nullable enable\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"IPEndPoint\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class IPEndPointCodec : IFieldCodec<IPEndPoint>, IDerivedTypeCodec\n    {\n        IPEndPoint IFieldCodec<IPEndPoint>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static IPEndPoint ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n            {\n                return ReferenceCodec.ReadReference<IPEndPoint, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var referencePlaceholder = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            Field header = default;\n            var port = 0;\n\n            reader.ReadFieldHeader(ref header);\n            if (!header.HasFieldId || header.FieldIdDelta != 0) throw new RequiredFieldMissingException(\"Serialized IPEndPoint is missing its address field.\");\n            var address = IPAddressCodec.ReadValue(ref reader, header);\n\n            reader.ReadFieldHeader(ref header);\n            if (header.HasFieldId && header.FieldIdDelta == 1)\n            {\n                port = UInt16Codec.ReadValue(ref reader, header);\n                reader.ReadFieldHeader(ref header);\n            }\n\n            reader.ConsumeEndBaseOrEndObject(ref header);\n\n            var result = new IPEndPoint(address, port);\n            ReferenceCodec.RecordObject(reader.Session, result, referencePlaceholder);\n            return result;\n        }\n\n        void IFieldCodec<IPEndPoint>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, IPEndPoint value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, typeof(IPEndPoint), value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(IPEndPoint), WireType.TagDelimited);\n            IPAddressCodec.WriteField(ref writer, 0, value.Address);\n            if (value.Port != 0) UInt16Codec.WriteField(ref writer, 1, (ushort)value.Port);\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, IPEndPoint value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.TagDelimited);\n            IPAddressCodec.WriteField(ref writer, 0, value.Address);\n            if (value.Port != 0) UInt16Codec.WriteField(ref writer, 1, (ushort)value.Port);\n            writer.WriteEndObject();\n        }\n    }\n\n    [RegisterCopier]\n    internal sealed class EndPointCopier : ShallowCopier<EndPoint>, IDerivedTypeCopier { }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableArrayCodec.cs",
    "content": "using System.Collections.Immutable;\nusing System.Linq;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableArray{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableArrayCodec<T> : GeneralizedValueTypeSurrogateCodec<ImmutableArray<T>, ImmutableArraySurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableArrayCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableArrayCodec(IValueSerializer<ImmutableArraySurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableArray<T> ConvertFromSurrogate(ref ImmutableArraySurrogate<T> surrogate)\n            => surrogate.Values is { } v ? ImmutableArray.Create(v) : default;\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableArray<T> value, ref ImmutableArraySurrogate<T> surrogate)\n            => surrogate.Values = value.IsDefault ? null : value.ToArray();\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableArrayCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableArraySurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public T[] Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableArray{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableArrayCopier<T> : IDeepCopier<ImmutableArray<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableArrayCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context)\n        {\n            if (_copier is null)\n                return input;\n\n            var array = (ImmutableArray<T>)input;\n            return array.IsDefaultOrEmpty ? input : DeepCopy(array, context);\n        }\n\n        /// <inheritdoc/>\n        public ImmutableArray<T> DeepCopy(ImmutableArray<T> input, CopyContext context)\n            => _copier is null || input.IsDefaultOrEmpty ? input : ImmutableArray.CreateRange(input, (i, s) => s._copier.DeepCopy(i, s.context), (_copier, context));\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableDictionaryCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<ImmutableDictionary<TKey, TValue>, ImmutableDictionarySurrogate<TKey, TValue>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableDictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableDictionaryCodec(IValueSerializer<ImmutableDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableDictionary<TKey, TValue> ConvertFromSurrogate(ref ImmutableDictionarySurrogate<TKey, TValue> surrogate)\n            => ImmutableDictionary.CreateRange(surrogate.Values.Comparer, surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableDictionary<TKey, TValue> value, ref ImmutableDictionarySurrogate<TKey, TValue> surrogate)\n            => surrogate.Values = new(value, value.KeyComparer);\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableDictionaryCodec{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableDictionarySurrogate<TKey, TValue>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public Dictionary<TKey, TValue> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableDictionaryCopier<TKey, TValue> : IDeepCopier<ImmutableDictionary<TKey, TValue>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        public ImmutableDictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(keyCopier);\n            _valueCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(valueCopier);\n        }\n\n        public bool IsShallowCopyable() => _keyCopier is null && _valueCopier is null;\n\n        /// <inheritdoc/>\n        public ImmutableDictionary<TKey, TValue> DeepCopy(ImmutableDictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableDictionary<TKey, TValue>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _keyCopier is null && _valueCopier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<KeyValuePair<TKey, TValue>>(input.Count);\n            foreach (var item in input)\n                items.Add(new(_keyCopier is null ? item.Key : _keyCopier.DeepCopy(item.Key, context),\n                    _valueCopier is null ? item.Value : _valueCopier.DeepCopy(item.Value, context)));\n\n            var res = ImmutableDictionary.CreateRange(input.KeyComparer, input.ValueComparer, items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableHashSetCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableHashSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableHashSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ImmutableHashSet<T>, ImmutableHashSetSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableHashSetCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableHashSetCodec(IValueSerializer<ImmutableHashSetSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableHashSet<T> ConvertFromSurrogate(ref ImmutableHashSetSurrogate<T> surrogate)\n            => ImmutableHashSet.CreateRange(surrogate.KeyComparer, surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableHashSet<T> value, ref ImmutableHashSetSurrogate<T> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.KeyComparer = value.KeyComparer != EqualityComparer<T>.Default ? value.KeyComparer : null;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableHashSetCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableHashSetSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n\n        /// <summary>\n        /// Gets or sets the key comparer.\n        /// </summary>\n        /// <value>The key comparer.</value>\n        [Id(1)]\n        public IEqualityComparer<T> KeyComparer;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableHashSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableHashSetCopier<T> : IDeepCopier<ImmutableHashSet<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableHashSetCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc/>\n        public ImmutableHashSet<T> DeepCopy(ImmutableHashSet<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableHashSet<T>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _copier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<T>(input.Count);\n            foreach (var item in input)\n                items.Add(_copier.DeepCopy(item, context));\n\n            var res = ImmutableHashSet.CreateRange(input.KeyComparer, items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableListCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableList{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableListCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ImmutableList<T>, ImmutableListSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableListCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableListCodec(IValueSerializer<ImmutableListSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableList<T> ConvertFromSurrogate(ref ImmutableListSurrogate<T> surrogate) => ImmutableList.CreateRange(surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableList<T> value, ref ImmutableListSurrogate<T> surrogate) => surrogate.Values = new(value);\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableListCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableListSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableList{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableListCopier<T> : IDeepCopier<ImmutableList<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableListCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc/>\n        public ImmutableList<T> DeepCopy(ImmutableList<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableList<T>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _copier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<T>(input.Count);\n            foreach (var item in input)\n                items.Add(_copier.DeepCopy(item, context));\n\n            var res = ImmutableList.CreateRange(items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableQueueCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableQueue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableQueueCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ImmutableQueue<T>, ImmutableQueueSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableQueueCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableQueueCodec(IValueSerializer<ImmutableQueueSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableQueue<T> ConvertFromSurrogate(ref ImmutableQueueSurrogate<T> surrogate) => ImmutableQueue.CreateRange(surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableQueue<T> value, ref ImmutableQueueSurrogate<T> surrogate) => surrogate.Values = new(value);\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableListCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableQueueSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableQueue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableQueueCopier<T> : IDeepCopier<ImmutableQueue<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableQueueCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc/>\n        public ImmutableQueue<T> DeepCopy(ImmutableQueue<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableQueue<T>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _copier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<T>();\n            foreach (var item in input)\n                items.Add(_copier.DeepCopy(item, context));\n\n            var res = ImmutableQueue.CreateRange(items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableSortedDictionaryCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableSortedDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableSortedDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<ImmutableSortedDictionary<TKey, TValue>, ImmutableSortedDictionarySurrogate<TKey, TValue>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableSortedDictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableSortedDictionaryCodec(IValueSerializer<ImmutableSortedDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableSortedDictionary<TKey, TValue> ConvertFromSurrogate(ref ImmutableSortedDictionarySurrogate<TKey, TValue> surrogate)\n            => ImmutableSortedDictionary.CreateRange(surrogate.KeyComparer, surrogate.ValueComparer, surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableSortedDictionary<TKey, TValue> value, ref ImmutableSortedDictionarySurrogate<TKey, TValue> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.KeyComparer = value.KeyComparer != Comparer<TKey>.Default ? value.KeyComparer : null;\n            surrogate.ValueComparer = value.ValueComparer != EqualityComparer<TValue>.Default ? value.ValueComparer : null;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableSortedDictionaryCodec{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableSortedDictionarySurrogate<TKey, TValue>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<KeyValuePair<TKey, TValue>> Values;\n\n        /// <summary>\n        /// Gets or sets the key comparer.\n        /// </summary>\n        /// <value>The key comparer.</value>\n        [Id(1)]\n        public IComparer<TKey> KeyComparer;\n\n        /// <summary>\n        /// Gets or sets the value comparer.\n        /// </summary>\n        [Id(2)]\n        public IEqualityComparer<TValue> ValueComparer;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableSortedDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableSortedDictionaryCopier<TKey, TValue> : IDeepCopier<ImmutableSortedDictionary<TKey, TValue>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        public ImmutableSortedDictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(keyCopier);\n            _valueCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(valueCopier);\n        }\n\n        public bool IsShallowCopyable() => _keyCopier is null && _valueCopier is null;\n\n        /// <inheritdoc/>\n        public ImmutableSortedDictionary<TKey, TValue> DeepCopy(ImmutableSortedDictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableSortedDictionary<TKey, TValue>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _keyCopier is null && _valueCopier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<KeyValuePair<TKey, TValue>>(input.Count);\n            foreach (var item in input)\n                items.Add(new(_keyCopier is null ? item.Key : _keyCopier.DeepCopy(item.Key, context),\n                    _valueCopier is null ? item.Value : _valueCopier.DeepCopy(item.Value, context)));\n\n            var res = ImmutableSortedDictionary.CreateRange(input.KeyComparer, input.ValueComparer, items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableSortedSetCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableSortedSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableSortedSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ImmutableSortedSet<T>, ImmutableSortedSetSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableSortedSetCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableSortedSetCodec(IValueSerializer<ImmutableSortedSetSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableSortedSet<T> ConvertFromSurrogate(ref ImmutableSortedSetSurrogate<T> surrogate)\n            => ImmutableSortedSet.CreateRange(surrogate.KeyComparer, surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableSortedSet<T> value, ref ImmutableSortedSetSurrogate<T> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.KeyComparer = value.KeyComparer != Comparer<T>.Default ? value.KeyComparer : null;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ImmutableSortedSetCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableSortedSetSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n\n        /// <summary>\n        /// Gets or sets the key comparer.\n        /// </summary>\n        /// <value>The key comparer.</value>\n        [Id(1)]\n        public IComparer<T> KeyComparer;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableSortedSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableSortedSetCopier<T> : IDeepCopier<ImmutableSortedSet<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableSortedSetCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc/>\n        public ImmutableSortedSet<T> DeepCopy(ImmutableSortedSet<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableSortedSet<T>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _copier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<T>(input.Count);\n            foreach (var item in input)\n                items.Add(_copier.DeepCopy(item, context));\n\n            var res = ImmutableSortedSet.CreateRange(input.KeyComparer, items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ImmutableStackCodec.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ImmutableStack{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ImmutableStackCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ImmutableStack<T>, ImmutableStackSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ImmutableStackCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ImmutableStackCodec(IValueSerializer<ImmutableStackSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ImmutableStack<T> ConvertFromSurrogate(ref ImmutableStackSurrogate<T> surrogate) => ImmutableStack.CreateRange(Enumerable.Reverse(surrogate.Values));\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ImmutableStack<T> value, ref ImmutableStackSurrogate<T> surrogate) => surrogate.Values = new(value);\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"ImmutableStackCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ImmutableStackSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ImmutableStack{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ImmutableStackCopier<T> : IDeepCopier<ImmutableStack<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        public ImmutableStackCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc/>\n        public ImmutableStack<T> DeepCopy(ImmutableStack<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ImmutableStack<T>>(input, out var result))\n                return result;\n\n            if (input.IsEmpty || _copier is null)\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var items = new List<T>();\n            foreach (var item in input)\n                items.Add(_copier.DeepCopy(item, context));\n\n            var res = ImmutableStack.CreateRange(items);\n            context.RecordCopy(input, res);\n            return res;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/IntegerCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"bool\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class BoolCodec : IFieldCodec<bool>\n    {\n        void IFieldCodec<bool>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, bool value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(bool), WireType.VarInt);\n            writer.WriteByte(value ? (byte)3 : (byte)1); // writer.WriteVarUInt32(value ? 1U : 0U);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, bool value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteByte(value ? (byte)3 : (byte)1); // writer.WriteVarUInt32(value ? 1U : 0U);\n        }\n\n        /// <inheritdoc/>\n        bool IFieldCodec<bool>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadUInt8(field.WireType) != 0;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"char\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class CharCodec : IFieldCodec<char>\n    {\n        void IFieldCodec<char>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, char value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(char), WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, char value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <inheritdoc/>\n        char IFieldCodec<char>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static char ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return (char)reader.ReadUInt16(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"byte\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ByteCodec : IFieldCodec<byte>\n    {\n        void IFieldCodec<byte>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, byte value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(byte), WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, byte value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, byte value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n            => UInt16Codec.WriteField(ref writer, fieldIdDelta, expectedType, value, actualType);\n\n        /// <inheritdoc/>\n        byte IFieldCodec<byte>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static byte ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadUInt8(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"sbyte\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class SByteCodec : IFieldCodec<sbyte>\n    {\n        void IFieldCodec<sbyte>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, sbyte value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(sbyte), WireType.VarInt);\n            writer.WriteVarInt8(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, sbyte value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteVarInt8(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, sbyte value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n            => Int16Codec.WriteField(ref writer, fieldIdDelta, expectedType, value, actualType);\n\n        /// <inheritdoc/>\n        sbyte IFieldCodec<sbyte>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static sbyte ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadInt8(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ushort\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class UInt16Codec : IFieldCodec<ushort>\n    {\n        /// <inheritdoc/>\n        ushort IFieldCodec<ushort>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ushort ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadUInt16(field.WireType);\n        }\n\n        void IFieldCodec<ushort>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ushort value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(ushort), WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, ushort value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ushort value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, WireType.VarInt);\n            writer.WriteVarUInt28(value);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"short\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class Int16Codec : IFieldCodec<short>\n    {\n        void IFieldCodec<short>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, short value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(short), WireType.VarInt);\n            writer.WriteVarInt16(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, short value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.VarInt);\n            writer.WriteVarInt16(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, short value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, WireType.VarInt);\n            writer.WriteVarInt16(value);\n        }\n\n        /// <inheritdoc/>\n        short IFieldCodec<short>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static short ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadInt16(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serialzier for <see cref=\"uint\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class UInt32Codec : IFieldCodec<uint>\n    {\n        void IFieldCodec<uint>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, uint value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(uint), value < 1 << 21 ? WireType.VarInt : WireType.Fixed32);\n\n            if (value < 1 << 21) writer.WriteVarUInt28(value);\n            else writer.WriteUInt32(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, uint value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, value < 1 << 21 ? WireType.VarInt : WireType.Fixed32);\n\n            if (value < 1 << 21) writer.WriteVarUInt28(value);\n            else writer.WriteUInt32(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, uint value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, value < 1 << 21 ? WireType.VarInt : WireType.Fixed32);\n\n            if (value < 1 << 21) writer.WriteVarUInt28(value);\n            else writer.WriteUInt32(value);\n        }\n\n        /// <inheritdoc/>\n        uint IFieldCodec<uint>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static uint ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadUInt32(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"int\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class Int32Codec : IFieldCodec<int>\n    {\n        void IFieldCodec<int>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, int value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value < 1 << 20 && value > -1 << 20 ? WireType.VarInt : WireType.Fixed32;\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(int), wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt28(Writer<TBufferWriter>.ZigZagEncode(value));\n            else writer.WriteInt32(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, int value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value < 1 << 20 && value > -1 << 20 ? WireType.VarInt : WireType.Fixed32;\n            writer.WriteFieldHeaderExpected(fieldIdDelta, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt28(Writer<TBufferWriter>.ZigZagEncode(value));\n            else writer.WriteInt32(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, int value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value < 1 << 20 && value > -1 << 20 ? WireType.VarInt : WireType.Fixed32;\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt28(Writer<TBufferWriter>.ZigZagEncode(value));\n            else writer.WriteInt32(value);\n        }\n\n        /// <inheritdoc/>\n        int IFieldCodec<int>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadInt32(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"long\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class Int64Codec : IFieldCodec<long>\n    {\n        void IFieldCodec<long>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, long value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 20 and > -1 << 20 => WireType.VarInt,\n                <= int.MaxValue and >= int.MinValue => WireType.Fixed32,\n                < 1L << 48 and > -1L << 48 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(long), wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(Writer<TBufferWriter>.ZigZagEncode(value));\n            else if (wireType == WireType.Fixed32) writer.WriteInt32((int)value);\n            else writer.WriteInt64(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, long value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 20 and > -1 << 20 => WireType.VarInt,\n                <= int.MaxValue and >= int.MinValue => WireType.Fixed32,\n                < 1L << 48 and > -1L << 48 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeaderExpected(fieldIdDelta, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(Writer<TBufferWriter>.ZigZagEncode(value));\n            else if (wireType == WireType.Fixed32) writer.WriteInt32((int)value);\n            else writer.WriteInt64(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, long value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 20 and > -1 << 20 => WireType.VarInt,\n                <= int.MaxValue and >= int.MinValue => WireType.Fixed32,\n                < 1L << 48 and > -1L << 48 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(Writer<TBufferWriter>.ZigZagEncode(value));\n            else if (wireType == WireType.Fixed32) writer.WriteInt32((int)value);\n            else writer.WriteInt64(value);\n        }\n\n        /// <inheritdoc/>\n        long IFieldCodec<long>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static long ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadInt64(field.WireType);\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"long\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class UInt64Codec : IFieldCodec<ulong>\n    {\n        void IFieldCodec<ulong>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ulong value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 21 => WireType.VarInt,\n                <= uint.MaxValue => WireType.Fixed32,\n                < 1UL << 49 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(ulong), wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(value);\n            else if (wireType == WireType.Fixed32) writer.WriteUInt32((uint)value);\n            else writer.WriteUInt64(value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, ulong value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 21 => WireType.VarInt,\n                <= uint.MaxValue => WireType.Fixed32,\n                < 1UL << 49 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeaderExpected(fieldIdDelta, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(value);\n            else if (wireType == WireType.Fixed32) writer.WriteUInt32((uint)value);\n            else writer.WriteUInt64(value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ulong value, Type actualType) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            var wireType = value switch\n            {\n                < 1 << 21 => WireType.VarInt,\n                <= uint.MaxValue => WireType.Fixed32,\n                < 1UL << 49 => WireType.VarInt,\n                _ => WireType.Fixed64,\n            };\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, actualType, wireType);\n\n            if (wireType == WireType.VarInt) writer.WriteVarUInt56(value);\n            else if (wireType == WireType.Fixed32) writer.WriteUInt32((uint)value);\n            else writer.WriteUInt64(value);\n        }\n\n        /// <inheritdoc/>\n        ulong IFieldCodec<ulong>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ulong ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            return reader.ReadUInt64(field.WireType);\n        }\n    }\n\n#if NET7_0_OR_GREATER\n    /// <summary>\n    /// Serializer for <see cref=\"Int128\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class Int128Codec : IFieldCodec<Int128>\n    {\n        /// <inheritdoc/>\n        void IFieldCodec<Int128>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Int128 value) => WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Int128 value) where TBufferWriter : IBufferWriter<byte>\n            => WriteField(ref writer, fieldIdDelta, typeof(Int128), value);\n\n        private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Int128 value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value <= (Int128)long.MaxValue && value >= (Int128)long.MinValue)\n            {\n                Int64Codec.WriteField(ref writer, fieldIdDelta, expectedType, (long)value, typeof(Int128));\n            }\n            else\n            {\n                ReferenceCodec.MarkValueField(writer.Session);\n                const int byteCount = 128 / 8;\n                writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(Int128), WireType.LengthPrefixed);\n                writer.WriteVarUInt7(byteCount);\n                if (BitConverter.IsLittleEndian)\n                {\n                    writer.Write(MemoryMarshal.AsBytes(new Span<Int128>(ref value)));\n                }\n                else\n                {\n                    writer.EnsureContiguous(byteCount);\n                    ((IBinaryInteger<Int128>)value).TryWriteLittleEndian(writer.WritableSpan, out var bytesWritten);\n                    Debug.Assert(bytesWritten == byteCount);\n                    writer.AdvanceSpan(byteCount);\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        Int128 IFieldCodec<Int128>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Int128 ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType != WireType.LengthPrefixed)\n            {\n                return Int64Codec.ReadValue(ref reader, field);\n            }\n\n            ReferenceCodec.MarkValueField(reader.Session);\n            return ReadRaw(ref reader);\n        }\n\n        /// <summary>\n        /// Reads a value without protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        internal static Int128 ReadRaw<TInput>(ref Reader<TInput> reader)\n        {\n            var byteCount = reader.ReadVarUInt32();\n            if (byteCount != 128 / 8) throw new UnexpectedLengthPrefixValueException(nameof(Int128), 128 / 8, byteCount);\n            Unsafe.SkipInit(out Int128 res);\n            var bytes = MemoryMarshal.AsBytes(new Span<Int128>(ref res));\n            reader.ReadBytes(bytes);\n\n            if (BitConverter.IsLittleEndian)\n                return res;\n\n            var done = TryReadLittleEndian<Int128>(bytes, out var value);\n            Debug.Assert(done);\n            return value;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static bool TryReadLittleEndian<T>(ReadOnlySpan<byte> source, out T value) where T : IBinaryInteger<T> => T.TryReadLittleEndian(source, isUnsigned: false, out value);\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"UInt128\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class UInt128Codec : IFieldCodec<UInt128>\n    {\n        /// <inheritdoc/>\n        void IFieldCodec<UInt128>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, UInt128 value) => WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, UInt128 value) where TBufferWriter : IBufferWriter<byte>\n            => WriteField(ref writer, fieldIdDelta, typeof(UInt128), value);\n\n        private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, UInt128 value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value <= (UInt128)ulong.MaxValue)\n            {\n                UInt64Codec.WriteField(ref writer, fieldIdDelta, expectedType, (ulong)value, typeof(UInt128));\n            }\n            else\n            {\n                ReferenceCodec.MarkValueField(writer.Session);\n                const int byteCount = 128 / 8;\n                writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(UInt128), WireType.LengthPrefixed);\n                writer.WriteVarUInt7(byteCount);\n                if (BitConverter.IsLittleEndian)\n                {\n                    writer.Write(MemoryMarshal.AsBytes(new Span<UInt128>(ref value)));\n                }\n                else\n                {\n                    writer.EnsureContiguous(byteCount);\n                    ((IBinaryInteger<UInt128>)value).TryWriteLittleEndian(writer.WritableSpan, out var bytesWritten);\n                    Debug.Assert(bytesWritten == byteCount);\n                    writer.AdvanceSpan(byteCount);\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        UInt128 IFieldCodec<UInt128>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static UInt128 ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType != WireType.LengthPrefixed)\n            {\n                return UInt64Codec.ReadValue(ref reader, field);\n            }\n\n            ReferenceCodec.MarkValueField(reader.Session);\n            return ReadRaw(ref reader);\n        }\n\n        /// <summary>\n        /// Reads a value without protocol framing.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The value.</returns>\n        internal static UInt128 ReadRaw<TInput>(ref Reader<TInput> reader)\n        {\n            var byteCount = reader.ReadVarUInt32();\n            if (byteCount != 128 / 8) throw new UnexpectedLengthPrefixValueException(nameof(UInt128), 128 / 8, byteCount);\n            Unsafe.SkipInit(out UInt128 res);\n            var bytes = MemoryMarshal.AsBytes(new Span<UInt128>(ref res));\n            reader.ReadBytes(bytes);\n\n            if (BitConverter.IsLittleEndian)\n                return res;\n\n            var done = TryReadLittleEndian<UInt128>(bytes, out var value);\n            Debug.Assert(done);\n            return value;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static bool TryReadLittleEndian<T>(ReadOnlySpan<byte> source, out T value) where T : IBinaryInteger<T> => T.TryReadLittleEndian(source, isUnsigned: true, out value);\n    }\n#endif\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/KeyValuePairCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"KeyValuePair{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class KeyValuePairCodec<TKey, TValue> : IFieldCodec<KeyValuePair<TKey, TValue>>\n    {\n        private readonly IFieldCodec<TKey> _keyCodec;\n        private readonly IFieldCodec<TValue> _valueCodec;\n        private readonly Type CodecKeyType = typeof(TKey);\n        private readonly Type CodecValueType = typeof(TValue);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"KeyValuePairCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCodec\">The key codec.</param>\n        /// <param name=\"valueCodec\">The value codec.</param>\n        public KeyValuePairCodec(IFieldCodec<TKey> keyCodec, IFieldCodec<TValue> valueCodec)\n        {\n            _keyCodec = OrleansGeneratedCodeHelper.UnwrapService(this, keyCodec);\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            KeyValuePair<TKey, TValue> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _keyCodec.WriteField(ref writer, 0, CodecKeyType, value.Key);\n            _valueCodec.WriteField(ref writer, 1, CodecValueType, value.Value);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public KeyValuePair<TKey, TValue> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            var key = default(TKey);\n            var value = default(TValue);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        key = _keyCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        value = _valueCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return new KeyValuePair<TKey, TValue>(key, value);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"KeyValuePair{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterCopier]\n    public sealed class KeyValuePairCopier<TKey, TValue> : IDeepCopier<KeyValuePair<TKey, TValue>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"KeyValuePairCopier{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCopier\">The key copier.</param>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public KeyValuePairCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(keyCopier);\n            _valueCopier = OrleansGeneratedCodeHelper.GetOptionalCopier(valueCopier);\n        }\n\n        public bool IsShallowCopyable() => _keyCopier is null && _valueCopier is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy((KeyValuePair<TKey, TValue>)input, context);\n\n        /// <inheritdoc/>\n        public KeyValuePair<TKey, TValue> DeepCopy(KeyValuePair<TKey, TValue> input, CopyContext context)\n        {\n            return new(_keyCopier is null ? input.Key : _keyCopier.DeepCopy(input.Key, context),\n                _valueCopier is null ? input.Value : _valueCopier.DeepCopy(input.Value, context));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ListCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"List{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ListCodec<T> : IFieldCodec<List<T>>, IBaseCodec<List<T>>\n    {\n        private readonly Type CodecElementType = typeof(T);\n\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ListCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public ListCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, List<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            Serialize(ref writer, value);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public List<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<List<T>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            List<T> result = null;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n                        result = new(length);\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ListCodec<T>.ThrowLengthFieldMissing();\n                        }\n\n                        result.Add(_fieldCodec.ReadValue(ref reader, header));\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            if (result is null)\n            {\n                result = new();\n                ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            }\n\n            return result;\n        }\n\n        private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n            $\"Declared length of {typeof(List<T>)}, {length}, is greater than total length of input.\");\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its length field.\");\n\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, List<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                    innerFieldIdDelta = 0;\n                }\n            }\n        }\n\n        public void Deserialize<TInput>(ref Reader<TInput> reader, List<T> value)\n        {\n            // If the value has some values added by the constructor, clear them.\n            // If those values are in the serialized payload, they will be added below.\n            value.Clear();\n\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        if (length > 10240 && length > reader.Length)\n                        {\n                            ThrowInvalidSizeException(length);\n                        }\n\n#if NET6_0_OR_GREATER\n                        value.EnsureCapacity(length);\n#endif\n                        break;\n                    case 1:\n                        value.Add(_fieldCodec.ReadValue(ref reader, header));\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"List{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ListCopier<T> : IDeepCopier<List<T>>, IBaseCopier<List<T>>\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ListCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public ListCopier(IDeepCopier<T> valueCopier)\n        {\n            _copier = valueCopier;\n        }\n\n        /// <inheritdoc/>\n        public List<T> DeepCopy(List<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<List<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() != typeof(List<T>))\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new List<T>(input.Count);\n            context.RecordCopy(input, result);\n            foreach (var item in input)\n            {\n                result.Add(_copier.DeepCopy(item, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(List<T> input, List<T> output, CopyContext context)\n        {\n            output.Clear();\n\n#if NET6_0_OR_GREATER\n            output.EnsureCapacity(input.Count);\n#endif\n            foreach (var item in input)\n            {\n                output.Add(_copier.DeepCopy(item, context));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/MultiDimensionalArrayCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for multi-dimensional arrays.\n    /// </summary>\n    /// <typeparam name=\"T\">The array element type.</typeparam>\n    internal sealed class MultiDimensionalArrayCodec<T> : IGeneralizedCodec\n    {\n        private readonly Type DimensionFieldType = typeof(int[]);\n        private readonly Type CodecElementType = typeof(T);\n\n        private readonly IFieldCodec<int[]> _intArrayCodec;\n        private readonly IFieldCodec<T> _elementCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MultiDimensionalArrayCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"intArrayCodec\">The int array codec.</param>\n        /// <param name=\"elementCodec\">The element codec.</param>\n        public MultiDimensionalArrayCodec(IFieldCodec<int[]> intArrayCodec, IFieldCodec<T> elementCodec)\n        {\n            _intArrayCodec = OrleansGeneratedCodeHelper.UnwrapService(this, intArrayCodec);\n            _elementCodec = OrleansGeneratedCodeHelper.UnwrapService(this, elementCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            var array = (Array)value;\n            var rank = array.Rank;\n\n            var lengths = new int[rank];\n            var indices = new int[rank];\n\n            // Write array lengths.\n            for (var i = 0; i < rank; i++)\n            {\n                lengths[i] = array.GetLength(i);\n            }\n\n            _intArrayCodec.WriteField(ref writer, 0, DimensionFieldType, lengths);\n\n            var remaining = array.Length;\n            uint innerFieldIdDelta = 1;\n            while (remaining-- > 0)\n            {\n                var element = array.GetValue(indices);\n                _elementCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, (T)element);\n                innerFieldIdDelta = 0;\n\n                // Increment the indices array by 1.\n                if (remaining > 0)\n                {\n                    var idx = rank - 1;\n                    while (idx >= 0 && ++indices[idx] >= lengths[idx])\n                    {\n                        indices[idx] = 0;\n                        --idx;\n                        if (idx < 0)\n                        {\n                            ThrowIndexOutOfRangeException(lengths);\n                        }\n                    }\n                }\n            }\n\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<T[], TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            Array result = null;\n            uint fieldId = 0;\n            int[] lengths = null;\n            int[] indices = null;\n            var rank = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        {\n                            lengths = _intArrayCodec.ReadValue(ref reader, header);\n                            rank = lengths.Length;\n\n                            // Multi-dimensional arrays must be indexed using indexing arrays, so create one now.\n                            indices = new int[rank];\n                            result = Array.CreateInstance(CodecElementType, lengths);\n                            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                            break;\n                        }\n                    case 1:\n                        {\n                            if (result is null || indices is null || lengths is null)\n                            {\n                                ThrowLengthsFieldMissing();\n                            }\n\n                            var element = _elementCodec.ReadValue(ref reader, header);\n                            result.SetValue(element, indices);\n\n                            // Increment the indices array by 1.\n                            var idx = rank - 1;\n                            while (idx >= 0 && ++indices[idx] >= lengths[idx])\n                            {\n                                indices[idx] = 0;\n                                --idx;\n                            }\n\n                            break;\n                        }\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public bool IsSupportedType(Type type) => type.IsArray && !type.IsSZArray;\n\n        private void ThrowIndexOutOfRangeException(int[] lengths) => throw new IndexOutOfRangeException(\n            $\"Encountered too many elements in array of type {CodecElementType} with declared lengths {string.Join(\", \", lengths)}.\");\n\n        private static void ThrowLengthsFieldMissing() => throw new RequiredFieldMissingException(\"Serialized array is missing its lengths field.\");\n    }\n\n    /// <summary>\n    /// Copier for multi-dimensional arrays.\n    /// </summary>\n    /// <typeparam name=\"T\">The array element type.</typeparam>\n    internal sealed class MultiDimensionalArrayCopier<T> : IGeneralizedCopier\n    {\n        /// <inheritdoc/>\n        public object DeepCopy(object original, CopyContext context)\n        {\n            if (context.TryGetCopy<Array>(original, out var result))\n            {\n                return result;\n            }\n\n            var type = original.GetType();\n            var originalArray = (Array)original;\n            var elementType = type.GetElementType();\n            if (ShallowCopyableTypes.Contains(elementType))\n            {\n                return originalArray.Clone();\n            }\n\n            // We assume that all arrays have lower bound 0. In .NET 4.0, it's hard to create an array with a non-zero lower bound.\n            var rank = originalArray.Rank;\n            var lengths = new int[rank];\n            for (var i = 0; i < rank; i++)\n            {\n                lengths[i] = originalArray.GetLength(i);\n            }\n\n            result = Array.CreateInstance(elementType, lengths);\n            context.RecordCopy(original, result); \n\n            if (rank == 1)\n            {\n                for (var i = 0; i < lengths[0]; i++)\n                {\n                    result.SetValue(ObjectCopier.DeepCopy(originalArray.GetValue(i), context), i);\n                }\n            }\n            else if (rank == 2)\n            {\n                for (var i = 0; i < lengths[0]; i++)\n                {\n                    for (var j = 0; j < lengths[1]; j++)\n                    {\n                        result.SetValue(ObjectCopier.DeepCopy(originalArray.GetValue(i, j), context), i, j);\n                    }\n                }\n            }\n            else\n            {\n                var index = new int[rank];\n                var sizes = new int[rank];\n                sizes[rank - 1] = 1;\n                for (var k = rank - 2; k >= 0; k--)\n                {\n                    sizes[k] = sizes[k + 1] * lengths[k + 1];\n                }\n\n                for (var i = 0; i < originalArray.Length; i++)\n                {\n                    int k = i;\n                    for (int n = 0; n < rank; n++)\n                    {\n                        int offset = k / sizes[n];\n                        k -= offset * sizes[n];\n                        index[n] = offset;\n                    }\n\n                    result.SetValue(ObjectCopier.DeepCopy(originalArray.GetValue(index), context), index);\n                }\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public bool IsSupportedType(Type type) => type.IsArray && !type.IsSZArray;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/NameValueCollectionCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System.Collections.Generic;\nusing System.Collections.Specialized;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"NameValueCollection\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class NameValueCollectionCodec : GeneralizedReferenceTypeSurrogateCodec<NameValueCollection, NameValueCollectionSurrogate>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NameValueCollectionCodec\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public NameValueCollectionCodec(IValueSerializer<NameValueCollectionSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override NameValueCollection ConvertFromSurrogate(ref NameValueCollectionSurrogate surrogate)\n        {\n            var result = new NameValueCollection(surrogate.Values.Count);\n            foreach (var value in surrogate.Values)\n            {\n                result.Add(value.Key, value.Value);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(NameValueCollection value, ref NameValueCollectionSurrogate surrogate)\n        {\n            var result = new Dictionary<string, string>(value.Count);\n            for (var i = 0; i < value.Count; i++)\n            {\n                result.Add(value.GetKey(i), value.Get(i));\n            }\n\n            surrogate.Values = result;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type used by <see cref=\"NameValueCollectionCodec\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    public struct NameValueCollectionSurrogate\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public Dictionary<string, string> Values;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"NameValueCollection\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class NameValueCollectionCopier : IDeepCopier<NameValueCollection>\n    {\n        /// <inheritdoc/>\n        public NameValueCollection DeepCopy(NameValueCollection input, CopyContext context)\n        {\n            if (context.TryGetCopy<NameValueCollection>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() != typeof(NameValueCollection))\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new NameValueCollection(input.Count);\n            context.RecordCopy(input, result);\n            for (var i = 0; i < input.Count; i++)\n            {\n                result.Add(input.GetKey(i), input.Get(i));\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/NullableCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Nullable{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class NullableCodec<T> : IFieldCodec<T?> where T : struct\n    {\n        private readonly Type CodecFieldType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NullableCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public NullableCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, T? value) where TBufferWriter : IBufferWriter<byte>\n        {\n            // If the value is null, write it as the null reference.\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            // The value is not null.\n            _fieldCodec.WriteField(ref writer, fieldIdDelta, CodecFieldType, value.GetValueOrDefault());\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public T? ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            // This will only be true if the value is null.\n            if (field.WireType == WireType.Reference)\n            {\n                ReferenceCodec.MarkValueField(reader.Session);\n                var reference = reader.ReadVarUInt32();\n                if (reference != 0) ThrowInvalidReference(reference);\n                return null;\n            }\n\n            // Read the non-null value.\n            return _fieldCodec.ReadValue(ref reader, field);\n        }\n\n        private static void ThrowInvalidReference(uint reference) => throw new ReferenceNotFoundException(typeof(T?), reference);\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Nullable{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class NullableCopier<T> : IDeepCopier<T?>, IOptionalDeepCopier where T : struct\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NullableCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"copier\">The copier.</param>\n        public NullableCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => input is null || _copier is null ? input : _copier.DeepCopy(input, context);\n\n        /// <inheritdoc/>\n        public T? DeepCopy(T? input, CopyContext context) => input is null || _copier is null ? input : _copier.DeepCopy(input.GetValueOrDefault(), context);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ObjectCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"object\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ObjectCodec : IFieldCodec<object>\n    {\n        /// <inheritdoc/>\n        object IFieldCodec<object>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n            {\n                return ReferenceCodec.ReadReference(ref reader, field.FieldType ?? typeof(object));\n            }\n\n            if (field.FieldType is null || field.FieldType == typeof(object))\n                return ReadObject(ref reader, field);\n\n            var specificSerializer = reader.Session.CodecProvider.GetCodec(field.FieldType);\n            return specificSerializer.ReadValue(ref reader, field);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static object ReadObject<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireType(WireType.LengthPrefixed);\n\n            var length = reader.ReadVarUInt32();\n            if (length != 0) throw new UnexpectedLengthPrefixValueException(nameof(Object), 0, length);\n\n            var result = new object();\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        void IFieldCodec<object>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) => WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            var specificSerializer = writer.Session.CodecProvider.GetCodec(value.GetType());\n            specificSerializer.WriteField(ref writer, fieldIdDelta, expectedType, value);\n        }\n\n        /// <summary>\n        /// Writes a field.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, object value) where TBufferWriter : IBufferWriter<byte>\n            => WriteField(ref writer, fieldIdDelta, null, value);\n\n        void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n        {\n            // only the untyped writer will need to support actual object type values\n            if (value is null || value.GetType() == typeof(object))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n                {\n                    return;\n                }\n\n                writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(object), WireType.LengthPrefixed);\n                writer.WriteVarUInt7(0U);\n                return;\n            }\n\n            var specificSerializer = writer.Session.CodecProvider.GetCodec(value.GetType());\n            specificSerializer.WriteField(ref writer, fieldIdDelta, expectedType, value);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"object\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ObjectCopier : IDeepCopier<object>\n    {\n        /// <summary>\n        /// Creates a deep copy of the provided input.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"context\">The context.</param>\n        /// <returns>A copy of <paramref name=\"input\" />.</returns>\n        public static object DeepCopy(object input, CopyContext context)\n        {\n            return context.TryGetCopy<object>(input, out var result) ? result\n                : input.GetType() == typeof(object) ? input : context.DeepCopy(input);\n        }\n\n        object IDeepCopier<object>.DeepCopy(object input, CopyContext context)\n        {\n            return context.TryGetCopy<object>(input, out var result) ? result\n                : input.GetType() == typeof(object) ? input : context.DeepCopy(input);\n        }\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context)\n            => input is null || input.GetType() == typeof(object) ? input : context.DeepCopy(input);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/QueueCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Queue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class QueueCodec<T> : IFieldCodec<Queue<T>>\n    {\n        private readonly Type CodecElementType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"fieldCodec\">The field codec.</param>\n        public QueueCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Queue<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            if (value.Count > 0)\n            {\n                UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n                uint innerFieldIdDelta = 1;\n                foreach (var element in value)\n                {\n                    _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                    innerFieldIdDelta = 0;\n                }\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public Queue<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Queue<T>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            Queue<T> result = null;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                        result = new Queue<T>(length);\n                        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                        break;\n                    case 1:\n                        if (result is null)\n                        {\n                            ThrowLengthFieldMissing();\n                        }\n\n                        result.Enqueue(_fieldCodec.ReadValue(ref reader, header));\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            if (result is null)\n            {\n                result = new();\n                ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            }\n\n            return result;\n        }\n\n        private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized queue is missing its length field.\");\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Queue{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class QueueCopier<T> : IDeepCopier<Queue<T>>, IBaseCopier<Queue<T>>\n    {\n        private readonly Type _fieldType = typeof(Queue<T>);\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public QueueCopier(IDeepCopier<T> valueCopier)\n        {\n            _copier = valueCopier;\n        }\n\n        /// <inheritdoc/>\n        public Queue<T> DeepCopy(Queue<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<Queue<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new Queue<T>(input.Count);\n            context.RecordCopy(input, result);\n            foreach (var item in input)\n            {\n                result.Enqueue(_copier.DeepCopy(item, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void DeepCopy(Queue<T> input, Queue<T> output, CopyContext context)\n        {\n            foreach (var item in input)\n            {\n                output.Enqueue(_copier.DeepCopy(item, context));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ReadOnlyCollectionCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Surrogate type used by <see cref=\"ReadOnlyCollectionCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct ReadOnlyCollectionSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ReadOnlyCollection{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ReadOnlyCollectionCodec<T> : GeneralizedReferenceTypeSurrogateCodec<ReadOnlyCollection<T>, ReadOnlyCollectionSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReadOnlyCollectionCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public ReadOnlyCollectionCodec(IValueSerializer<ReadOnlyCollectionSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc/>\n        public override ReadOnlyCollection<T> ConvertFromSurrogate(ref ReadOnlyCollectionSurrogate<T> surrogate) => new(surrogate.Values);\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(ReadOnlyCollection<T> value, ref ReadOnlyCollectionSurrogate<T> surrogate) => surrogate.Values = new(value);\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ReadOnlyCollection{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ReadOnlyCollectionCopier<T> : IDeepCopier<ReadOnlyCollection<T>>\n    {\n        private readonly Type _fieldType = typeof(ReadOnlyCollection<T>);\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReadOnlyCollectionCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public ReadOnlyCollectionCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = elementCopier;\n        }\n\n        /// <inheritdoc />\n        public ReadOnlyCollection<T> DeepCopy(ReadOnlyCollection<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ReadOnlyCollection<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var tempResult = new T[input.Count];\n            for (var i = 0; i < tempResult.Length; i++)\n            {\n                tempResult[i] = _elementCopier.DeepCopy(input[i], context);\n            }\n\n            result = new ReadOnlyCollection<T>(tempResult);\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ReadOnlyDictionaryCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\n\nnamespace Orleans.Serialization.Codecs\n{\n    [RegisterSerializer]\n    public sealed class ReadOnlyDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<ReadOnlyDictionary<TKey, TValue>, ReadOnlyDictionarySurrogate<TKey, TValue>>\n    {\n        public ReadOnlyDictionaryCodec(IValueSerializer<ReadOnlyDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override ReadOnlyDictionary<TKey, TValue> ConvertFromSurrogate(ref ReadOnlyDictionarySurrogate<TKey, TValue> surrogate) => new(surrogate.Values);\n\n        public override void ConvertToSurrogate(ReadOnlyDictionary<TKey, TValue> value, ref ReadOnlyDictionarySurrogate<TKey, TValue> surrogate) => surrogate.Values = new(value);\n    }\n\n    [GenerateSerializer]\n    public struct ReadOnlyDictionarySurrogate<TKey, TValue>\n    {\n        [Id(0)]\n        public Dictionary<TKey, TValue> Values;\n    }\n\n    [RegisterCopier]\n    public sealed class ReadOnlyDictionaryCopier<TKey, TValue> : IDeepCopier<ReadOnlyDictionary<TKey, TValue>>\n    {\n        private readonly Type _fieldType = typeof(ReadOnlyDictionary<TKey, TValue>);\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        public ReadOnlyDictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n        }\n\n        public ReadOnlyDictionary<TKey, TValue> DeepCopy(ReadOnlyDictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<ReadOnlyDictionary<TKey, TValue>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            // There is a possibility for infinite recursion here if any value in the input collection is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var temp = new Dictionary<TKey, TValue>(input.Count);\n            foreach (var pair in input)\n            {\n                temp[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n\n            result = new ReadOnlyDictionary<TKey, TValue>(temp);\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ReferenceCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Functionality for reading and writing object references.\n    /// </summary>\n    public static class ReferenceCodec\n    {\n        /// <summary>\n        /// Indicates that the field being serialized or deserialized is a value type.\n        /// </summary>\n        /// <param name=\"session\">The serializer session.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void MarkValueField(SerializerSession session) => session.ReferencedObjects.MarkValueField();\n\n        /// <summary>\n        /// Write an object reference if <paramref name=\"value\"/> has already been written.\n        /// This overload is suitable only for static codecs where expected type is statically known.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static bool TryWriteReferenceFieldExpected<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldId, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!writer.Session.ReferencedObjects.GetOrAddReference(value, out var reference))\n            {\n                return false;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldId, WireType.Reference);\n            writer.WriteVarUInt32(reference);\n            return true;\n        }\n\n        /// <summary>\n        /// Write an object reference if <paramref name=\"value\"/> has already been written and has been tracked via <see cref=\"RecordObject(SerializerSession, object)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <returns><see langword=\"true\" /> if a reference was written, <see langword=\"false\" /> otherwise.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool TryWriteReferenceField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldId,\n            Type expectedType,\n            object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!writer.Session.ReferencedObjects.GetOrAddReference(value, out var reference))\n            {\n                return false;\n            }\n\n            writer.WriteFieldHeader(fieldId, expectedType, value?.GetType(), WireType.Reference);\n            writer.WriteVarUInt32(reference);\n            return true;\n        }\n\n        /// <summary>\n        /// Write an object reference if <paramref name=\"value\"/> has already been written and has been tracked via <see cref=\"RecordObject(SerializerSession, object)\"/>.        /// \n        /// </summary>\n        /// <remarks>This overload allows specifying a fixed reference type for codecs that implement <see cref=\"IDerivedTypeCodec\"/>.</remarks>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"actualType\">The actual type.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <returns><see langword=\"true\" /> if a reference was written, <see langword=\"false\" /> otherwise.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool TryWriteReferenceField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldId,\n            Type expectedType,\n            Type actualType,\n            object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!writer.Session.ReferencedObjects.GetOrAddReference(value, out var reference))\n            {\n                return false;\n            }\n\n            writer.WriteFieldHeader(fieldId, expectedType, value is null ? null : actualType, WireType.Reference);\n            writer.WriteVarUInt32(reference);\n            return true;\n        }\n\n        /// <summary>\n        /// Writes the null reference.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldId\">The field identifier.</param>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public static void WriteNullReference<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldId) where TBufferWriter : IBufferWriter<byte>\n        {\n            writer.Session.ReferencedObjects.MarkValueField();\n            writer.WriteFieldHeaderExpected(fieldId, WireType.Reference);\n            writer.WriteByte(1); // writer.WriteVarUInt32(0U);\n        }\n\n        /// <summary>\n        /// Reads a referenced value.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the referenced object.</typeparam>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The referenced value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T ReadReference<T, TInput>(ref Reader<TInput> reader, Field field) => (T)ReadReference(ref reader, field.FieldType ?? typeof(T));\n\n        /// <summary>\n        /// Reads the reference.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"fieldType\">The field type.</param>\n        /// <returns>The referenced value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static object ReadReference<TInput>(ref Reader<TInput> reader, Type fieldType)\n        {\n            MarkValueField(reader.Session);\n            var reference = reader.ReadVarUInt32();\n            if (reference == 0)\n                return null;\n\n            return ReadReference(ref reader, fieldType, reference);\n        }\n\n        private static object ReadReference<TInput>(ref Reader<TInput> reader, Type fieldType, uint reference)\n        {\n            var value = reader.Session.ReferencedObjects.TryGetReferencedObject(reference);\n            if (value is null) throw new ReferenceNotFoundException(fieldType, reference);\n\n            return value switch\n            {\n                UnknownFieldMarker marker => DeserializeFromMarker(ref reader, fieldType, marker, reference),\n                _ => value,\n            };\n        }\n\n        private static object DeserializeFromMarker<TInput>(\n            ref Reader<TInput> reader,\n            Type fieldType,\n            UnknownFieldMarker marker,\n            uint reference)\n        {\n            // Capture state from the reader and session.\n            var session = reader.Session;\n            var originalPosition = reader.Position;\n            var referencedObjects = session.ReferencedObjects;\n            var originalCurrentReferenceId = referencedObjects.CurrentReferenceId;\n            var originalReferenceToObjectCount = referencedObjects.ReferenceToObjectCount;\n\n            // Deserialize the object, replacing the marker in the session.\n            try\n            {\n                // Create a reader at the position specified by the marker.\n                reader.ForkFrom(marker.Position, out var referencedReader);\n\n                // Determine the correct type for the field.\n                fieldType = marker.Field.FieldType ?? fieldType;\n\n                // Get a serializer for that type.\n                var specificSerializer = session.CodecProvider.GetCodec(fieldType);\n\n                // Reset the session's reference id so that the deserialized objects overwrite the placeholder markers.\n                referencedObjects.CurrentReferenceId = reference - 1;\n                referencedObjects.ReferenceToObjectCount = referencedObjects.GetReferenceIndex(marker);\n                return specificSerializer.ReadValue(ref referencedReader, marker.Field);\n            }\n            finally\n            {\n                // Revert the reference id.\n                referencedObjects.CurrentReferenceId = originalCurrentReferenceId;\n                referencedObjects.ReferenceToObjectCount = originalReferenceToObjectCount;\n                reader.ResumeFrom(originalPosition);\n            }\n        }\n\n        /// <summary>\n        /// Records that an object was read or written.\n        /// </summary>\n        /// <param name=\"session\">The session.</param>\n        /// <param name=\"value\">The value.</param>\n        public static void RecordObject(SerializerSession session, object value) => session.ReferencedObjects.RecordReferenceField(value);\n\n        /// <summary>\n        /// Records that an object was read or written.\n        /// </summary>\n        /// <param name=\"session\">The session.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"referenceId\">The reference identifier.</param>\n        public static void RecordObject(SerializerSession session, object value, uint referenceId) => session.ReferencedObjects.RecordReferenceField(value, referenceId);\n\n        /// <summary>\n        /// Records and returns a placeholder reference id for objects which cannot be immediately deserialized.\n        /// </summary>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The placeholder reference id.</returns>\n        public static uint CreateRecordPlaceholder(SerializerSession session) => session.ReferencedObjects.CreateRecordPlaceholder();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ReferenceTypeSurrogateCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Surrogate serializer for <typeparamref name=\"TField\"/>.\n    /// </summary>\n    /// <typeparam name=\"TField\">The type which the implementation of this class supports.</typeparam>\n    /// <typeparam name=\"TSurrogate\">The surrogate type serialized in place of <typeparamref name=\"TField\"/>.</typeparam>\n    public abstract class ReferenceTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField> where TSurrogate : struct\n    {\n        private readonly Type CodecFieldType = typeof(TField);\n        private readonly IValueSerializer<TSurrogate> _surrogateSerializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceTypeSurrogateCodec{TField, TSurrogate}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        protected ReferenceTypeSurrogateCodec(IValueSerializer<TSurrogate> surrogateSerializer)\n        {\n            _surrogateSerializer = surrogateSerializer;\n        }\n\n        /// <inheritdoc/>\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<TField, TInput>(ref reader, field);\n            }\n\n            var fieldType = field.FieldType;\n            if (fieldType is null || fieldType == CodecFieldType)\n            {\n                field.EnsureWireTypeTagDelimited();\n                var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n                TSurrogate surrogate = default;\n                _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n                var result = ConvertFromSurrogate(ref surrogate);\n                ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                return result;\n            }\n\n            // The type is a descendant, not an exact match, so get the specific serializer for it.\n            var specificSerializer = reader.Session.CodecProvider.GetCodec(fieldType);\n            return (TField)specificSerializer.ReadValue(ref reader, field);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            var fieldType = value.GetType();\n            if (fieldType == CodecFieldType)\n            {\n                writer.WriteStartObject(fieldIdDelta, expectedType, fieldType);\n                TSurrogate surrogate = default;\n                ConvertToSurrogate(value, ref surrogate);\n                _surrogateSerializer.Serialize(ref writer, ref surrogate);\n                writer.WriteEndObject();\n            }\n            else\n            {\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, value);\n            }\n        }\n\n        /// <summary>\n        /// Converts a surrogate value to the field type.\n        /// </summary>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        /// <returns>The value.</returns>\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n\n        /// <summary>\n        /// Converts a value to the surrogate type.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate); \n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/SkipFieldExtension.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// A serializer which skips all fields which it encounters.\n    /// </summary>\n    public class SkipFieldCodec : IFieldCodec\n    {\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            throw new NotImplementedException();\n        }\n\n        /// <inheritdoc />\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            reader.SkipField(field);\n            return null;\n        }\n    }\n\n    /// <summary>\n    /// Extension methods for <see cref=\"Reader{TInput}\"/> to skip fields.\n    /// </summary>\n    public static class SkipFieldExtension\n    {\n        /// <summary>\n        /// Skips the current field.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        public static void SkipField<TInput>(this ref Reader<TInput> reader, Field field)\n        {\n            switch (field.WireType)\n            {\n                case WireType.Reference:\n                case WireType.VarInt:\n                    reader.Session.ReferencedObjects.MarkValueField();\n                    _ = reader.ReadVarUInt64();\n                    break;\n                case WireType.TagDelimited:\n                    reader.Session.ReferencedObjects.MarkValueField();\n                    SkipTagDelimitedField(ref reader);\n                    break;\n                case WireType.LengthPrefixed:\n                    reader.Session.ReferencedObjects.MarkValueField();\n                    SkipLengthPrefixedField(ref reader);\n                    break;\n                case WireType.Fixed32:\n                    reader.Session.ReferencedObjects.MarkValueField();\n                    reader.Skip(4);\n                    break;\n                case WireType.Fixed64:\n                    reader.Session.ReferencedObjects.MarkValueField();\n                    reader.Skip(8);\n                    break;\n                case WireType.Extended:\n                    if (!field.IsEndBaseOrEndObject)\n                    {\n                        ThrowUnexpectedExtendedWireType(field);\n                    }\n\n                    break;\n                default:\n                    ThrowUnexpectedWireType(field);\n                    break;\n            }\n        }\n\n        internal static void ThrowUnexpectedExtendedWireType(Field field) => throw new ArgumentOutOfRangeException(\n                $\"Unexpected {nameof(ExtendedWireType)} value [{field.ExtendedWireType}] in field {field} while skipping field.\");\n\n        internal static void ThrowUnexpectedWireType(Field field) => throw new ArgumentOutOfRangeException(\n                $\"Unexpected {nameof(WireType)} value [{field.WireType}] in field {field} while skipping field.\");\n\n        internal static void SkipLengthPrefixedField<TInput>(ref Reader<TInput> reader)\n        {\n            var length = reader.ReadVarUInt32();\n            reader.Skip(length);\n        }\n\n        private static void SkipTagDelimitedField<TInput>(ref Reader<TInput> reader)\n        {\n            while (true)\n            {\n                var field = reader.ReadFieldHeader();\n                if (field.IsEndObject)\n                {\n                    break;\n                }\n\n                reader.SkipField(field);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/SortedDictionaryCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"SortedDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class SortedDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<SortedDictionary<TKey, TValue>, SortedDictionarySurrogate<TKey, TValue>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedDictionaryCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public SortedDictionaryCodec(IValueSerializer<SortedDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc />\n        public override SortedDictionary<TKey, TValue> ConvertFromSurrogate(ref SortedDictionarySurrogate<TKey, TValue> surrogate)\n        {\n            var result = new SortedDictionary<TKey, TValue>(surrogate.Comparer);\n            foreach (var kvp in surrogate.Values)\n            {\n                result.Add(kvp.Key, kvp.Value);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public override void ConvertToSurrogate(SortedDictionary<TKey, TValue> value, ref SortedDictionarySurrogate<TKey, TValue> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.Comparer = value.Comparer == Comparer<TKey>.Default ? null : value.Comparer;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"SortedDictionaryCodec{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [GenerateSerializer]\n    public struct SortedDictionarySurrogate<TKey, TValue>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<KeyValuePair<TKey, TValue>> Values;\n\n        /// <summary>\n        /// Gets or sets the comparer.\n        /// </summary>\n        /// <value>The comparer.</value>\n        [Id(1)]\n        public IComparer<TKey> Comparer;\n    }\n\n    /// <summary>\n    /// Copier  for <see cref=\"SortedDictionary{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterCopier]\n    public sealed class SortedDictionaryCopier<TKey, TValue> : IDeepCopier<SortedDictionary<TKey, TValue>>, IBaseCopier<SortedDictionary<TKey, TValue>>\n    {\n        private readonly Type _fieldType = typeof(SortedDictionary<TKey, TValue>);\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedDictionaryCopier{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCopier\">The key copier.</param>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public SortedDictionaryCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n        }\n\n        /// <inheritdoc />\n        public SortedDictionary<TKey, TValue> DeepCopy(SortedDictionary<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<SortedDictionary<TKey, TValue>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new SortedDictionary<TKey, TValue>(input.Comparer);\n            context.RecordCopy(input, result);\n            foreach (var pair in input)\n            {\n                result[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public void DeepCopy(SortedDictionary<TKey, TValue> input, SortedDictionary<TKey, TValue> output, CopyContext context)\n        {\n            foreach (var pair in input)\n            {\n                output[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/SortedListCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"SortedList{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterSerializer]\n    public sealed class SortedListCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<SortedList<TKey, TValue>, SortedListSurrogate<TKey, TValue>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedListCodec{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public SortedListCodec(IValueSerializer<SortedListSurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc />\n        public override SortedList<TKey, TValue> ConvertFromSurrogate(ref SortedListSurrogate<TKey, TValue> surrogate)\n        {\n            if (surrogate.Values is null)\n            {\n                return null;\n            }\n            else\n            {\n                var result = new SortedList<TKey, TValue>(surrogate.Values.Count, surrogate.Comparer);\n                foreach (var kvp in surrogate.Values)\n                {\n                    result.Add(kvp.Key, kvp.Value);\n                }\n\n                return result;\n            }\n        }\n\n        /// <inheritdoc />\n        public override void ConvertToSurrogate(SortedList<TKey, TValue> value, ref SortedListSurrogate<TKey, TValue> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.Comparer = value.Comparer == Comparer<TKey>.Default ? null : value.Comparer;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"SortedListCodec{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [GenerateSerializer]\n    public struct SortedListSurrogate<TKey, TValue>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<KeyValuePair<TKey, TValue>> Values;\n\n        /// <summary>\n        /// Gets or sets the comparer.\n        /// </summary>\n        /// <value>The comparer.</value>\n        [Id(1)]\n        public IComparer<TKey> Comparer;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"SortedList{TKey, TValue}\"/>.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The key type.</typeparam>\n    /// <typeparam name=\"TValue\">The value type.</typeparam>\n    [RegisterCopier]\n    public sealed class SortedListCopier<TKey, TValue> : IDeepCopier<SortedList<TKey, TValue>>, IBaseCopier<SortedList<TKey, TValue>>\n    {\n        private readonly Type _fieldType = typeof(SortedList<TKey, TValue>);\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedListCopier{TKey, TValue}\"/> class.\n        /// </summary>\n        /// <param name=\"keyCopier\">The key copier.</param>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public SortedListCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n        }\n\n        /// <inheritdoc />\n        public SortedList<TKey, TValue> DeepCopy(SortedList<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<SortedList<TKey, TValue>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new SortedList<TKey, TValue>(input.Comparer);\n            context.RecordCopy(input, result);\n            foreach (var pair in input)\n            {\n                result[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public void DeepCopy(SortedList<TKey, TValue> input, SortedList<TKey, TValue> output, CopyContext context)\n        {\n            foreach (var pair in input)\n            {\n                output[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/SortedSetCodec.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"SortedSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class SortedSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<SortedSet<T>, SortedSetSurrogate<T>>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedSetCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public SortedSetCodec(IValueSerializer<SortedSetSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc />\n        public override SortedSet<T> ConvertFromSurrogate(ref SortedSetSurrogate<T> surrogate) => new(surrogate.Values, surrogate.Comparer);\n\n        /// <inheritdoc />\n        public override void ConvertToSurrogate(SortedSet<T> value, ref SortedSetSurrogate<T> surrogate)\n        {\n            surrogate.Values = new(value);\n            surrogate.Comparer = value.Comparer == Comparer<T>.Default ? null : value.Comparer;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"SortedSetCodec{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [GenerateSerializer]\n    public struct SortedSetSurrogate<T>\n    {\n        /// <summary>\n        /// Gets or sets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        [Id(0)]\n        public List<T> Values;\n\n        /// <summary>\n        /// Gets or sets the comparer.\n        /// </summary>\n        /// <value>The comparer.</value>\n        [Id(1)]\n        public IComparer<T> Comparer;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"SortedSet{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class SortedSetCopier<T> : IDeepCopier<SortedSet<T>>, IBaseCopier<SortedSet<T>>\n    {\n        private readonly Type _fieldType = typeof(SortedSet<T>);\n        private readonly IDeepCopier<T> _elementCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SortedSetCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"elementCopier\">The element copier.</param>\n        public SortedSetCopier(IDeepCopier<T> elementCopier)\n        {\n            _elementCopier = elementCopier;\n        }\n\n        /// <inheritdoc />\n        public SortedSet<T> DeepCopy(SortedSet<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<SortedSet<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            if (input.GetType() as object != _fieldType as object)\n            {\n                return context.DeepCopy(input);\n            }\n\n            result = new SortedSet<T>(input.Comparer);\n            context.RecordCopy(input, result);\n            foreach (var element in input)\n            {\n                result.Add(_elementCopier.DeepCopy(element, context));\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public void DeepCopy(SortedSet<T> input, SortedSet<T> output, CopyContext context)\n        {\n            foreach (var element in input)\n            {\n                output.Add(_elementCopier.DeepCopy(element, context));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/StackCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Serializer for <see cref=\"Stack{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterSerializer]\npublic sealed class StackCodec<T> : IFieldCodec<Stack<T>>\n{\n    private readonly Type CodecElementType = typeof(T);\n\n    private readonly IFieldCodec<T> _fieldCodec;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"StackCodec{T}\"/> class.\n    /// </summary>\n    /// <param name=\"fieldCodec\">The field codec.</param>\n    public StackCodec(IFieldCodec<T> fieldCodec)\n    {\n        _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Stack<T> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n        if (value.Count > 0)\n        {\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value)\n            {\n                _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                innerFieldIdDelta = 0;\n            }\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    public Stack<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<Stack<T>, TInput>(ref reader, field);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        T[] array = null;\n        var i = 0;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                    if (length > 10240 && length > reader.Length)\n                    {\n                        ThrowInvalidSizeException(length);\n                    }\n\n                    array = new T[length];\n                    i = length - 1;\n                    break;\n                case 1:\n                    if (array is null)\n                    {\n                        ThrowLengthFieldMissing();\n                    }\n\n                    array[i--] = _fieldCodec.ReadValue(ref reader, header);\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        array ??= [];\n        var result = new Stack<T>(array);\n        ReferenceCodec.RecordObject(reader.Session, array, placeholderReferenceId);\n        return result;\n    }\n\n    private void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n        $\"Declared length of {typeof(Stack<T>)}, {length}, is greater than total length of input.\");\n\n    private void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized stack is missing its length field.\");\n}\n\n/// <summary>\n/// Copier for <see cref=\"Stack{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterCopier]\npublic sealed class StackCopier<T> : IDeepCopier<Stack<T>>, IBaseCopier<Stack<T>>\n{\n    private readonly Type _fieldType = typeof(Stack<T>);\n    private readonly IDeepCopier<T> _copier;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"StackCopier{T}\"/> class.\n    /// </summary>\n    /// <param name=\"valueCopier\">The value copier.</param>\n    public StackCopier(IDeepCopier<T> valueCopier)\n    {\n        _copier = valueCopier;\n    }\n\n    /// <inheritdoc/>\n    public Stack<T> DeepCopy(Stack<T> input, CopyContext context)\n    {\n        if (context.TryGetCopy<Stack<T>>(input, out var result))\n        {\n            return result;\n        }\n\n        if (input.GetType() != _fieldType)\n        {\n            return context.DeepCopy(input);\n        }\n\n        result = new Stack<T>(input.Count);\n        context.RecordCopy(input, result);\n        var array = new T[input.Count];\n        input.CopyTo(array, 0);\n        for (var i = array.Length - 1; i >= 0; --i)\n        {\n            result.Push(_copier.DeepCopy(array[i], context));\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    public void DeepCopy(Stack<T> input, Stack<T> output, CopyContext context)\n    {\n        var array = new T[input.Count];\n        input.CopyTo(array, 0);\n        for (var i = array.Length - 1; i >= 0; --i)\n        {\n            output.Push(_copier.DeepCopy(array[i], context));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/StringCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"string\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class StringCodec : IFieldCodec<string>\n    {\n        /// <inheritdoc />\n        string IFieldCodec<string>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<string, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireType(WireType.LengthPrefixed);\n            var result = ReadRaw(ref reader, reader.ReadVarUInt32());\n            ReferenceCodec.RecordObject(reader.Session, result);\n            return result;\n        }\n\n        /// <summary>\n        /// Reads the raw string content.\n        /// </summary>\n        /// <param name=\"numBytes\">Encoded string length in bytes.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string ReadRaw<TInput>(ref Reader<TInput> reader, uint numBytes)\n        {\n            if (reader.TryReadBytes((int)numBytes, out var span))\n                return Encoding.UTF8.GetString(span);\n\n            return ReadMultiSegment(ref reader, numBytes);\n        }\n\n        private static string ReadMultiSegment<TInput>(ref Reader<TInput> reader, uint numBytes)\n        {\n            var array = ArrayPool<byte>.Shared.Rent((int)numBytes);\n            var span = array.AsSpan(0, (int)numBytes);\n            reader.ReadBytes(span);\n            var res = Encoding.UTF8.GetString(span);\n            ArrayPool<byte>.Shared.Return(array);\n            return res;\n        }\n\n        void IFieldCodec<string>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, string value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n                return;\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(string), WireType.LengthPrefixed);\n            var numBytes = Encoding.UTF8.GetByteCount(value);\n            writer.WriteVarUInt32((uint)numBytes);\n            WriteRaw(ref writer, value, numBytes);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, string value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.LengthPrefixed);\n            var numBytes = Encoding.UTF8.GetByteCount(value);\n            writer.WriteVarUInt32((uint)numBytes);\n            WriteRaw(ref writer, value, numBytes);\n        }\n\n        /// <summary>\n        /// Writes the raw string content.\n        /// </summary>\n        /// <param name=\"value\">String to be encoded.</param>\n        /// <param name=\"numBytes\">Encoded string length in bytes.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, string value, int numBytes) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (numBytes < 512)\n            {\n                writer.EnsureContiguous(numBytes);\n            }\n\n            var currentSpan = writer.WritableSpan;\n\n            // If there is enough room in the current span for the encoded data,\n            // then encode directly into the output buffer.\n            if (numBytes <= currentSpan.Length)\n            {\n                writer.AdvanceSpan(Encoding.UTF8.GetBytes(value, currentSpan));\n            }\n            else\n            {\n                WriteMultiSegment(ref writer, value, numBytes);\n            }\n        }\n\n        private static void WriteMultiSegment<TBufferWriter>(ref Writer<TBufferWriter> writer, string value, int remainingBytes) where TBufferWriter : IBufferWriter<byte>\n        {\n            var encoder = Encoding.UTF8.GetEncoder();\n            var input = value.AsSpan();\n\n            while (true)\n            {\n                encoder.Convert(input, writer.WritableSpan, true, out var charsUsed, out var bytesWritten, out var completed);\n                writer.AdvanceSpan(bytesWritten);\n\n                if (completed)\n                {\n                    Debug.Assert(charsUsed == input.Length && bytesWritten == remainingBytes);\n                    break;\n                }\n\n                remainingBytes -= bytesWritten;\n                input = input[charsUsed..];\n\n                writer.Allocate(Math.Min(remainingBytes, Writer<TBufferWriter>.MaxMultiSegmentSizeHint));\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/TimeOnlyCodec.cs",
    "content": "#if NET6_0_OR_GREATER\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs;\n\n/// <summary>\n/// Serializer for <see cref=\"TimeOnly\"/>.\n/// </summary>\n[RegisterSerializer]\npublic sealed class TimeOnlyCodec : IFieldCodec<TimeOnly>\n{\n    void IFieldCodec<TimeOnly>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TimeOnly value)\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(TimeOnly), WireType.Fixed64);\n        writer.WriteInt64(value.Ticks);\n    }\n\n    /// <summary>\n    /// Writes a field without type info (expected type is statically known).\n    /// </summary>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, TimeOnly value) where TBufferWriter : IBufferWriter<byte>\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed64);\n        writer.WriteInt64(value.Ticks);\n    }\n\n    /// <inheritdoc/>\n    TimeOnly IFieldCodec<TimeOnly>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n    /// <summary>\n    /// Reads a <see cref=\"TimeOnly\"/> value.\n    /// </summary>\n    /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n    /// <param name=\"reader\">The reader.</param>\n    /// <param name=\"field\">The field.</param>\n    /// <returns>The <see cref=\"TimeOnly\"/> value.</returns>\n    public static TimeOnly ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        ReferenceCodec.MarkValueField(reader.Session);\n        field.EnsureWireType(WireType.Fixed64);\n        return new TimeOnly(reader.ReadInt64());\n    }\n}\n#endif"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/TimeSpanCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"TimeSpan\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class TimeSpanCodec : IFieldCodec<TimeSpan>\n    {\n        void IFieldCodec<TimeSpan>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TimeSpan value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(TimeSpan), WireType.Fixed64);\n            writer.WriteInt64(value.Ticks);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, TimeSpan value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.Fixed64);\n            writer.WriteInt64(value.Ticks);\n        }\n\n        /// <inheritdoc />\n        TimeSpan IFieldCodec<TimeSpan>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static TimeSpan ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            field.EnsureWireType(WireType.Fixed64);\n            return TimeSpan.FromTicks(reader.ReadInt64());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/TupleCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T> : IFieldCodec<Tuple<T>>\n    {\n        private readonly Type CodecElementType = typeof(T);\n\n        private readonly IFieldCodec<T> _valueCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCodec\">The value codec.</param>\n        public TupleCodec(IFieldCodec<T> valueCodec)\n        {\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Tuple<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _valueCodec.WriteField(ref writer, 1, CodecElementType, value.Item1);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _valueCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T>(item1);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T> : IDeepCopier<Tuple<T>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T>);\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"copier\">The copier.</param>\n        public TupleCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        public bool IsShallowCopyable() => _copier is null;\n\n        /// <inheritdoc />\n        public Tuple<T> DeepCopy(Tuple<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(_copier is null ? input.Item1 : _copier.DeepCopy(input.Item1, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2> : IFieldCodec<Tuple<T1, T2>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Tuple<T1, T2> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2>(item1, item2);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2}\"/>\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2> : IDeepCopier<Tuple<T1, T2>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The copier for <typeparamref name=\"T1\"/>.</param>\n        /// <param name=\"copier2\">The copier for <typeparamref name=\"T2\"/>.</param>\n        public TupleCopier(IDeepCopier<T1> copier1, IDeepCopier<T2> copier2)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null;\n\n        public Tuple<T1, T2> DeepCopy(Tuple<T1, T2> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3> : IFieldCodec<Tuple<T1, T2, T3>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Tuple<T1, T2, T3> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3>(item1, item2, item3);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3> : IDeepCopier<Tuple<T1, T2, T3>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3> DeepCopy(Tuple<T1, T2, T3> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3, T4}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3, T4> : IFieldCodec<Tuple<T1, T2, T3, T4>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3, T4}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Tuple<T1, T2, T3, T4> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3, T4>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            var item4 = default(T4);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        item4 = _item4Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3, T4}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3, T4> : IDeepCopier<Tuple<T1, T2, T3, T4>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3, T4>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3, T4}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4> DeepCopy(Tuple<T1, T2, T3, T4> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3, T4> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context),\n                _copier4 is null ? input.Item4 : _copier4.DeepCopy(input.Item4, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3, T4, T5}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3, T4, T5> : IFieldCodec<Tuple<T1, T2, T3, T4, T5>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3, T4, T5}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            Tuple<T1, T2, T3, T4, T5> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3, T4, T5>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            var item4 = default(T4);\n            var item5 = default(T5);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        item4 = _item4Codec.ReadValue(ref reader, header);\n                        break;\n                    case 5:\n                        item5 = _item5Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3, T4, T5}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3, T4, T5> : IDeepCopier<Tuple<T1, T2, T3, T4, T5>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3, T4, T5>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3, T4, T5}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5> DeepCopy(Tuple<T1, T2, T3, T4, T5> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3, T4, T5> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context),\n                _copier4 is null ? input.Item4 : _copier4.DeepCopy(input.Item4, context),\n                _copier5 is null ? input.Item5 : _copier5.DeepCopy(input.Item5, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3, T4, T5, T6> : IFieldCodec<Tuple<T1, T2, T3, T4, T5, T6>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3, T4, T5, T6}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            Tuple<T1, T2, T3, T4, T5, T6> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3, T4, T5, T6>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            var item4 = default(T4);\n            var item5 = default(T5);\n            var item6 = default(T6);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        item4 = _item4Codec.ReadValue(ref reader, header);\n                        break;\n                    case 5:\n                        item5 = _item5Codec.ReadValue(ref reader, header);\n                        break;\n                    case 6:\n                        item6 = _item6Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3, T4, T5, T6> : IDeepCopier<Tuple<T1, T2, T3, T4, T5, T6>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3, T4, T5, T6>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3, T4, T5, T6}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6> DeepCopy(Tuple<T1, T2, T3, T4, T5, T6> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3, T4, T5, T6> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context),\n                _copier4 is null ? input.Item4 : _copier4.DeepCopy(input.Item4, context),\n                _copier5 is null ? input.Item5 : _copier5.DeepCopy(input.Item5, context),\n                _copier6 is null ? input.Item6 : _copier6.DeepCopy(input.Item6, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6, T7}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3, T4, T5, T6, T7> : IFieldCodec<Tuple<T1, T2, T3, T4, T5, T6, T7>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n        private readonly Type ElementType7 = typeof(T7);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n        private readonly IFieldCodec<T7> _item7Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3, T4, T5, T6, T7}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        /// <param name=\"item7Codec\">The <typeparamref name=\"T7\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec,\n            IFieldCodec<T7> item7Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n            _item7Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item7Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            Tuple<T1, T2, T3, T4, T5, T6, T7> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n            _item7Codec.WriteField(ref writer, 1, ElementType7, value.Item7);\n\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6, T7> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3, T4, T5, T6, T7>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            var item4 = default(T4);\n            var item5 = default(T5);\n            var item6 = default(T6);\n            var item7 = default(T7);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        item4 = _item4Codec.ReadValue(ref reader, header);\n                        break;\n                    case 5:\n                        item5 = _item5Codec.ReadValue(ref reader, header);\n                        break;\n                    case 6:\n                        item6 = _item6Codec.ReadValue(ref reader, header);\n                        break;\n                    case 7:\n                        item7 = _item7Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6, T7}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3, T4, T5, T6, T7> : IDeepCopier<Tuple<T1, T2, T3, T4, T5, T6, T7>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3, T4, T5, T6, T7>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n        private readonly IDeepCopier<T7> _copier7;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3, T4, T5, T6, T7}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        /// <param name=\"copier7\">The <typeparamref name=\"T7\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6,\n            IDeepCopier<T7> copier7)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n            _copier7 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier7);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null && _copier7 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6, T7> DeepCopy(Tuple<T1, T2, T3, T4, T5, T6, T7> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3, T4, T5, T6, T7> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = Tuple.Create(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context),\n                _copier4 is null ? input.Item4 : _copier4.DeepCopy(input.Item4, context),\n                _copier5 is null ? input.Item5 : _copier5.DeepCopy(input.Item5, context),\n                _copier6 is null ? input.Item6 : _copier6.DeepCopy(input.Item6, context),\n                _copier7 is null ? input.Item7 : _copier7.DeepCopy(input.Item7, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6, T7, T8}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    /// <typeparam name=\"T8\">The type of the tuple's eighth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class TupleCodec<T1, T2, T3, T4, T5, T6, T7, T8> : IFieldCodec<Tuple<T1, T2, T3, T4, T5, T6, T7, T8>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n        private readonly Type ElementType7 = typeof(T7);\n        private readonly Type ElementType8 = typeof(T8);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n        private readonly IFieldCodec<T7> _item7Codec;\n        private readonly IFieldCodec<T8> _item8Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCodec{T1, T2, T3, T4, T5, T6, T7, T8}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        /// <param name=\"item7Codec\">The <typeparamref name=\"T7\"/> codec.</param>\n        /// <param name=\"item8Codec\">The <typeparamref name=\"T8\"/> codec.</param>\n        public TupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec,\n            IFieldCodec<T7> item7Codec,\n            IFieldCodec<T8> item8Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n            _item7Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item7Codec);\n            _item8Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item8Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            Tuple<T1, T2, T3, T4, T5, T6, T7, T8> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n            _item7Codec.WriteField(ref writer, 1, ElementType7, value.Item7);\n            _item8Codec.WriteField(ref writer, 1, ElementType8, value.Rest);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6, T7, T8> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Tuple<T1, T2, T3, T4, T5, T6, T7, T8>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var item1 = default(T1);\n            var item2 = default(T2);\n            var item3 = default(T3);\n            var item4 = default(T4);\n            var item5 = default(T5);\n            var item6 = default(T6);\n            var item7 = default(T7);\n            var item8 = default(T8);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _item1Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        item2 = _item2Codec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        item3 = _item3Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        item4 = _item4Codec.ReadValue(ref reader, header);\n                        break;\n                    case 5:\n                        item5 = _item5Codec.ReadValue(ref reader, header);\n                        break;\n                    case 6:\n                        item6 = _item6Codec.ReadValue(ref reader, header);\n                        break;\n                    case 7:\n                        item7 = _item7Codec.ReadValue(ref reader, header);\n                        break;\n                    case 8:\n                        item8 = _item8Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            var result = new Tuple<T1, T2, T3, T4, T5, T6, T7, T8>(item1, item2, item3, item4, item5, item6, item7, item8);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    /// <summary>\n    /// Copier for <see cref=\"Tuple{T1, T2, T3, T4, T5, T6, T7, T8}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    /// <typeparam name=\"T8\">The type of the tuple's eighth component.</typeparam>\n    [RegisterCopier]\n    public sealed class TupleCopier<T1, T2, T3, T4, T5, T6, T7, T8> : IDeepCopier<Tuple<T1, T2, T3, T4, T5, T6, T7, T8>>, IOptionalDeepCopier\n    {\n        private readonly Type _fieldType = typeof(Tuple<T1, T2, T3, T4, T5, T6, T7, T8>);\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n        private readonly IDeepCopier<T7> _copier7;\n        private readonly IDeepCopier<T8> _copier8;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleCopier{T1, T2, T3, T4, T5, T6, T7, T8}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        /// <param name=\"copier7\">The <typeparamref name=\"T7\"/> copier.</param>\n        /// <param name=\"copier8\">The <typeparamref name=\"T8\"/> copier.</param>\n        public TupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6,\n            IDeepCopier<T7> copier7,\n            IDeepCopier<T8> copier8)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n            _copier7 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier7);\n            _copier8 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier8);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null && _copier7 is null && _copier8 is null;\n\n        /// <inheritdoc />\n        public Tuple<T1, T2, T3, T4, T5, T6, T7, T8> DeepCopy(Tuple<T1, T2, T3, T4, T5, T6, T7, T8> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out Tuple<T1, T2, T3, T4, T5, T6, T7, T8> existing))\n                return existing;\n\n            if (input.GetType() as object != _fieldType as object)\n                return context.DeepCopy(input);\n\n            if (IsShallowCopyable())\n                return input;\n\n            // There is a possibility for infinite recursion here if any value in the input tuple is able to take part in a cyclic reference.\n            // Mitigate that by returning a shallow-copy in such a case.\n            context.RecordCopy(input, input);\n\n            var result = new Tuple<T1, T2, T3, T4, T5, T6, T7, T8>(\n                _copier1 is null ? input.Item1 : _copier1.DeepCopy(input.Item1, context),\n                _copier2 is null ? input.Item2 : _copier2.DeepCopy(input.Item2, context),\n                _copier3 is null ? input.Item3 : _copier3.DeepCopy(input.Item3, context),\n                _copier4 is null ? input.Item4 : _copier4.DeepCopy(input.Item4, context),\n                _copier5 is null ? input.Item5 : _copier5.DeepCopy(input.Item5, context),\n                _copier6 is null ? input.Item6 : _copier6.DeepCopy(input.Item6, context),\n                _copier7 is null ? input.Item7 : _copier7.DeepCopy(input.Item7, context),\n                _copier8 is null ? input.Rest : _copier8.DeepCopy(input.Rest, context));\n            context.RecordCopy(input, result);\n            return result;\n        }\n    } \n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/TypeSerializerCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serialzier for <see cref=\"Type\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class TypeSerializerCodec : IFieldCodec<Type>, IDerivedTypeCodec\n    {\n        void IFieldCodec<Type>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Type value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, typeof(Type), value))\n            {\n                return;\n            }\n\n            writer.WriteStartObject(fieldIdDelta, expectedType, typeof(Type));\n            WriteField(ref writer, value);\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.TagDelimited);\n            WriteField(ref writer, value);\n        }\n\n        private static void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, Type value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var schemaType = writer.Session.WellKnownTypes.TryGetWellKnownTypeId(value, out var id) ? SchemaType.WellKnown\n                : writer.Session.ReferencedTypes.TryGetTypeReference(value, out id) ? SchemaType.Referenced\n                : SchemaType.Encoded;\n\n            // Write the encoding type.\n            ByteCodec.WriteField(ref writer, 0, (byte)schemaType);\n\n            if (schemaType == SchemaType.Encoded)\n            {\n                // If the type is encoded, write the length-prefixed bytes.\n                ReferenceCodec.MarkValueField(writer.Session);\n                writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);\n                writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value);\n            }\n            else\n            {\n                // If the type is referenced or well-known, write it as a varint.\n                UInt32Codec.WriteField(ref writer, 2, id);\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        Type IFieldCodec<Type>.ReadValue<TInput>(ref Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        public static Type ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Type, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            uint fieldId = 0;\n            var schemaType = default(SchemaType);\n            uint id = 0;\n            Type result = null;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref field);\n                if (field.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += field.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        schemaType = (SchemaType)ByteCodec.ReadValue(ref reader, field);\n                        break;\n                    case 1:\n                        ReferenceCodec.MarkValueField(reader.Session);\n                        result = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                        break;\n                    case 2:\n                        id = UInt32Codec.ReadValue(ref reader, field);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(field);\n                        break;\n                }\n            }\n\n            switch (schemaType)\n            {\n                case SchemaType.Referenced:\n                    result = reader.Session.ReferencedTypes.GetReferencedType(id);\n                    break;\n\n                case SchemaType.WellKnown:\n                    if (!reader.Session.WellKnownTypes.TryGetWellKnownType(id, out result))\n                        ThrowUnknownWellKnownType(id);\n                    break;\n\n                case SchemaType.Encoded:\n                    // Type codec should not update the type reference map, otherwise unknown-field deserialization could be broken\n                    break;\n\n                default:\n                    ThrowInvalidSchemaType(schemaType);\n                    break;\n            }\n\n            if (result is null) ThrowMissingType();\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n\n        private static void ThrowInvalidSchemaType(SchemaType schemaType) => throw new NotSupportedException(\n            $\"SchemaType {schemaType} is not supported by {nameof(TypeSerializerCodec)}.\");\n\n        private static void ThrowUnknownWellKnownType(uint id) => throw new UnknownWellKnownTypeException(id);\n        private static void ThrowMissingType() => throw new TypeMissingException();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/UnknownFieldMarker.cs",
    "content": "using Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Marker object used to denote an unknown field and its position into a stream of data.\n    /// </summary>\n    public sealed class UnknownFieldMarker\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnknownFieldMarker\"/> class.\n        /// </summary>\n        /// <param name=\"field\">The field.</param>\n        /// <param name=\"position\">The position.</param>\n        public UnknownFieldMarker(Field field, long position)\n        {\n            Field = field;\n            Position = position;\n        }\n\n        /// <summary>\n        /// The position into the stream at which this field occurs.\n        /// </summary>\n        public long Position { get; }\n\n        /// <summary>\n        /// The field header.\n        /// </summary>\n        public Field Field { get; }\n\n        /// <inheritdoc />\n        public override string ToString() => $\"{nameof(Position)}: 0x{Position:X}, {nameof(Field)}: {Field}\";\n\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/UriCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Uri\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class UriCodec : IFieldCodec<Uri>, IDerivedTypeCodec\n    {\n        Uri IFieldCodec<Uri>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field) => ReadValue(ref reader, field);\n\n        /// <summary>\n        /// Reads a value.\n        /// </summary>\n        public static Uri ReadValue<TInput>(ref Buffers.Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n                return ReferenceCodec.ReadReference<Uri, TInput>(ref reader, field);\n\n            field.EnsureWireTypeTagDelimited();\n            var referencePlaceholder = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n\n            reader.ReadFieldHeader(ref field);\n            if (!field.HasFieldId || field.FieldIdDelta != 0) throw new RequiredFieldMissingException(\"Serialized Uri is missing its value.\");\n            var uriString = StringCodec.ReadValue(ref reader, field);\n            reader.ReadFieldHeader(ref field);\n            reader.ConsumeEndBaseOrEndObject(ref field);\n\n            var result = new Uri(uriString, UriKind.RelativeOrAbsolute);\n            ReferenceCodec.RecordObject(reader.Session, result, referencePlaceholder);\n            return result;\n        }\n\n        void IFieldCodec<Uri>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Uri value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, typeof(Uri), value))\n                return;\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(Uri), WireType.TagDelimited);\n            StringCodec.WriteField(ref writer, 0, value.OriginalString);\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Writes a field without type info (expected type is statically known).\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, Uri value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceFieldExpected(ref writer, fieldIdDelta, value))\n                return;\n\n            writer.WriteFieldHeaderExpected(fieldIdDelta, WireType.TagDelimited);\n            StringCodec.WriteField(ref writer, 0, value.OriginalString);\n            writer.WriteEndObject();\n        }\n    }\n\n    [RegisterCopier]\n    internal sealed class UriCopier : ShallowCopier<Uri>, IDerivedTypeCopier { }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/ValueTupleCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec : IFieldCodec<ValueTuple>\n    {\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ValueTuple value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.VarInt);\n            writer.WriteVarUInt7(0);\n        }\n\n        /// <inheritdoc />\n        public ValueTuple ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireType(WireType.VarInt);\n\n            ReferenceCodec.MarkValueField(reader.Session);\n            var length = reader.ReadVarUInt32();\n            if (length != 0) throw new UnexpectedLengthPrefixValueException(nameof(ValueTuple), 0, length);\n\n            return default;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T> : IFieldCodec<ValueTuple<T>>\n    {\n        private readonly Type ElementType1 = typeof(T);\n\n        private readonly IFieldCodec<T> _valueCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCodec\">The value codec.</param>\n        public ValueTupleCodec(IFieldCodec<T> valueCodec)\n        {\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            ValueTuple<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _valueCodec.WriteField(ref writer, 1, ElementType1, value.Item1);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public ValueTuple<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            var item1 = default(T);\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1:\n                        item1 = _valueCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return new ValueTuple<T>(item1);\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple\"/>.\n    /// </summary>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier : IDeepCopier<ValueTuple>, IOptionalDeepCopier\n    {\n        /// <inheritdoc />\n        public bool IsShallowCopyable() => true;\n\n        /// <inheritdoc />\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => input;\n\n        /// <inheritdoc />\n        public ValueTuple DeepCopy(ValueTuple input, CopyContext context) => input;\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T> : IDeepCopier<ValueTuple<T>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T> _copier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"copier\">The copier.</param>\n        public ValueTupleCopier(IDeepCopier<T> copier) => _copier = OrleansGeneratedCodeHelper.GetOptionalCopier(copier);\n\n        /// <inheritdoc />\n        public bool IsShallowCopyable() => _copier is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy((ValueTuple<T>)input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T> DeepCopy(ValueTuple<T> input, CopyContext context)\n        {\n            if (_copier != null) input.Item1 = _copier.DeepCopy(input.Item1, context);\n            return input;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2}\"/>\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2> : IFieldCodec<ValueTuple<T1, T2>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2) ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2}\"/>\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2> : IDeepCopier<ValueTuple<T1, T2>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The copier for <typeparamref name=\"T1\"/>.</param>\n        /// <param name=\"copier2\">The copier for <typeparamref name=\"T2\"/>.</param>\n        public ValueTupleCopier(IDeepCopier<T1> copier1, IDeepCopier<T2> copier2)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2> DeepCopy(ValueTuple<T1, T2> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            return input;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3> : IFieldCodec<ValueTuple<T1, T2, T3>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2, T3) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2, T3) ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2, T3) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3> : IDeepCopier<ValueTuple<T1, T2, T3>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2, T3))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3> DeepCopy(ValueTuple<T1, T2, T3> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            return input;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3, T4}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3, T4> : IFieldCodec<ValueTuple<T1, T2, T3, T4>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3, T4}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2, T3, T4) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2, T3, T4) ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2, T3, T4) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    case 4: res.Item4 = _item4Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3, T4}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3, T4> : IDeepCopier<ValueTuple<T1, T2, T3, T4>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3, T4}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2, T3, T4))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4> DeepCopy(ValueTuple<T1, T2, T3, T4> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            if (_copier4 != null) input.Item4 = _copier4.DeepCopy(input.Item4, context);\n            return input;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3, T4, T5}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3, T4, T5> : IFieldCodec<ValueTuple<T1, T2, T3, T4, T5>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3, T4, T5}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2, T3, T4, T5) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2, T3, T4, T5) ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2, T3, T4, T5) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    case 4: res.Item4 = _item4Codec.ReadValue(ref reader, header); break;\n                    case 5: res.Item5 = _item5Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3, T4, T5}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3, T4, T5> : IDeepCopier<ValueTuple<T1, T2, T3, T4, T5>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3, T4, T5}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2, T3, T4, T5))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4, T5> DeepCopy(ValueTuple<T1, T2, T3, T4, T5> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            if (_copier4 != null) input.Item4 = _copier4.DeepCopy(input.Item4, context);\n            if (_copier5 != null) input.Item5 = _copier5.DeepCopy(input.Item5, context);\n            return input;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3, T4, T5, T6> : IFieldCodec<ValueTuple<T1, T2, T3, T4, T5, T6>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3, T4, T5, T6}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2, T3, T4, T5, T6) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2, T3, T4, T5, T6) ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2, T3, T4, T5, T6) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    case 4: res.Item4 = _item4Codec.ReadValue(ref reader, header); break;\n                    case 5: res.Item5 = _item5Codec.ReadValue(ref reader, header); break;\n                    case 6: res.Item6 = _item6Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n    \n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3, T4, T5, T6> : IDeepCopier<ValueTuple<T1, T2, T3, T4, T5, T6>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3, T4, T5, T6}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2, T3, T4, T5, T6))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4, T5, T6> DeepCopy(ValueTuple<T1, T2, T3, T4, T5, T6> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            if (_copier4 != null) input.Item4 = _copier4.DeepCopy(input.Item4, context);\n            if (_copier5 != null) input.Item5 = _copier5.DeepCopy(input.Item5, context);\n            if (_copier6 != null) input.Item6 = _copier6.DeepCopy(input.Item6, context);\n            return input;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6, T7}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3, T4, T5, T6, T7> : IFieldCodec<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n        private readonly Type ElementType7 = typeof(T7);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n        private readonly IFieldCodec<T7> _item7Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3, T4, T5, T6, T7}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        /// <param name=\"item7Codec\">The <typeparamref name=\"T7\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec,\n            IFieldCodec<T7> item7Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n            _item7Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item7Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            (T1, T2, T3, T4, T5, T6, T7) value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n            _item7Codec.WriteField(ref writer, 1, ElementType7, value.Item7);\n\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public (T1, T2, T3, T4, T5, T6, T7) ReadValue<TInput>(\n            ref Reader<TInput> reader,\n            Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            (T1, T2, T3, T4, T5, T6, T7) res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    case 4: res.Item4 = _item4Codec.ReadValue(ref reader, header); break;\n                    case 5: res.Item5 = _item5Codec.ReadValue(ref reader, header); break;\n                    case 6: res.Item6 = _item6Codec.ReadValue(ref reader, header); break;\n                    case 7: res.Item7 = _item7Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6, T7}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3, T4, T5, T6, T7> : IDeepCopier<ValueTuple<T1, T2, T3, T4, T5, T6, T7>>, IOptionalDeepCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n        private readonly IDeepCopier<T7> _copier7;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3, T4, T5, T6, T7}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        /// <param name=\"copier7\">The <typeparamref name=\"T7\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6,\n            IDeepCopier<T7> copier7)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n            _copier7 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier7);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null && _copier7 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy(((T1, T2, T3, T4, T5, T6, T7))input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4, T5, T6, T7> DeepCopy(ValueTuple<T1, T2, T3, T4, T5, T6, T7> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            if (_copier4 != null) input.Item4 = _copier4.DeepCopy(input.Item4, context);\n            if (_copier5 != null) input.Item5 = _copier5.DeepCopy(input.Item5, context);\n            if (_copier6 != null) input.Item6 = _copier6.DeepCopy(input.Item6, context);\n            if (_copier7 != null) input.Item7 = _copier7.DeepCopy(input.Item7, context);\n            return input;\n        }\n    } \n\n    /// <summary>\n    /// Serializer for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6, T7, T8}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    /// <typeparam name=\"T8\">The type of the tuple's eighth component.</typeparam>\n    [RegisterSerializer]\n    public sealed class ValueTupleCodec<T1, T2, T3, T4, T5, T6, T7, T8> : IFieldCodec<ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8>> where T8 : struct\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n        private readonly Type ElementType7 = typeof(T7);\n        private readonly Type ElementType8 = typeof(T8);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n        private readonly IFieldCodec<T7> _item7Codec;\n        private readonly IFieldCodec<T8> _item8Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCodec{T1, T2, T3, T4, T5, T6, T7, T8}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The <typeparamref name=\"T1\"/> codec.</param>\n        /// <param name=\"item2Codec\">The <typeparamref name=\"T2\"/> codec.</param>\n        /// <param name=\"item3Codec\">The <typeparamref name=\"T3\"/> codec.</param>\n        /// <param name=\"item4Codec\">The <typeparamref name=\"T4\"/> codec.</param>\n        /// <param name=\"item5Codec\">The <typeparamref name=\"T5\"/> codec.</param>\n        /// <param name=\"item6Codec\">The <typeparamref name=\"T6\"/> codec.</param>\n        /// <param name=\"item7Codec\">The <typeparamref name=\"T7\"/> codec.</param>\n        /// <param name=\"item8Codec\">The <typeparamref name=\"T8\"/> codec.</param>\n        public ValueTupleCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec,\n            IFieldCodec<T7> item7Codec,\n            IFieldCodec<T8> item8Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n            _item7Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item7Codec);\n            _item8Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item8Codec);\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(\n            ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n            _item1Codec.WriteField(ref writer, 1, ElementType1, value.Item1);\n            _item2Codec.WriteField(ref writer, 1, ElementType2, value.Item2);\n            _item3Codec.WriteField(ref writer, 1, ElementType3, value.Item3);\n            _item4Codec.WriteField(ref writer, 1, ElementType4, value.Item4);\n            _item5Codec.WriteField(ref writer, 1, ElementType5, value.Item5);\n            _item6Codec.WriteField(ref writer, 1, ElementType6, value.Item6);\n            _item7Codec.WriteField(ref writer, 1, ElementType7, value.Item7);\n            _item8Codec.WriteField(ref writer, 1, ElementType8, value.Rest);\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> ReadValue<TInput>(ref Reader<TInput> reader,\n            Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> res = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: res.Item1 = _item1Codec.ReadValue(ref reader, header); break;\n                    case 2: res.Item2 = _item2Codec.ReadValue(ref reader, header); break;\n                    case 3: res.Item3 = _item3Codec.ReadValue(ref reader, header); break;\n                    case 4: res.Item4 = _item4Codec.ReadValue(ref reader, header); break;\n                    case 5: res.Item5 = _item5Codec.ReadValue(ref reader, header); break;\n                    case 6: res.Item6 = _item6Codec.ReadValue(ref reader, header); break;\n                    case 7: res.Item7 = _item7Codec.ReadValue(ref reader, header); break;\n                    case 8: res.Rest = _item8Codec.ReadValue(ref reader, header); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return res;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"ValueTuple{T1, T2, T3, T4, T5, T6, T7, T8}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T1\">The type of the tuple's first component.</typeparam>\n    /// <typeparam name=\"T2\">The type of the tuple's second component.</typeparam>\n    /// <typeparam name=\"T3\">The type of the tuple's third component.</typeparam>\n    /// <typeparam name=\"T4\">The type of the tuple's fourth component.</typeparam>\n    /// <typeparam name=\"T5\">The type of the tuple's fifth component.</typeparam>\n    /// <typeparam name=\"T6\">The type of the tuple's sixth component.</typeparam>\n    /// <typeparam name=\"T7\">The type of the tuple's seventh component.</typeparam>\n    /// <typeparam name=\"T8\">The type of the tuple's eighth component.</typeparam>\n    [RegisterCopier]\n    public sealed class ValueTupleCopier<T1, T2, T3, T4, T5, T6, T7, T8> : IDeepCopier<ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8>>, IOptionalDeepCopier where T8 : struct\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n        private readonly IDeepCopier<T7> _copier7;\n        private readonly IDeepCopier<T8> _copier8;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueTupleCopier{T1, T2, T3, T4, T5, T6, T7, T8}\"/> class.\n        /// </summary>\n        /// <param name=\"copier1\">The <typeparamref name=\"T1\"/> copier.</param>\n        /// <param name=\"copier2\">The <typeparamref name=\"T2\"/> copier.</param>\n        /// <param name=\"copier3\">The <typeparamref name=\"T3\"/> copier.</param>\n        /// <param name=\"copier4\">The <typeparamref name=\"T4\"/> copier.</param>\n        /// <param name=\"copier5\">The <typeparamref name=\"T5\"/> copier.</param>\n        /// <param name=\"copier6\">The <typeparamref name=\"T6\"/> copier.</param>\n        /// <param name=\"copier7\">The <typeparamref name=\"T7\"/> copier.</param>\n        /// <param name=\"copier8\">The <typeparamref name=\"T8\"/> copier.</param>\n        public ValueTupleCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6,\n            IDeepCopier<T7> copier7,\n            IDeepCopier<T8> copier8)\n        {\n            _copier1 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier1);\n            _copier2 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier2);\n            _copier3 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier3);\n            _copier4 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier4);\n            _copier5 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier5);\n            _copier6 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier6);\n            _copier7 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier7);\n            _copier8 = OrleansGeneratedCodeHelper.GetOptionalCopier(copier8);\n        }\n\n        public bool IsShallowCopyable() => _copier1 is null && _copier2 is null && _copier3 is null && _copier4 is null && _copier5 is null && _copier6 is null && _copier7 is null && _copier8 is null;\n\n        object IDeepCopier.DeepCopy(object input, CopyContext context) => IsShallowCopyable() ? input : DeepCopy((ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8>)input, context);\n\n        /// <inheritdoc />\n        public ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> DeepCopy(ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> input, CopyContext context)\n        {\n            if (_copier1 != null) input.Item1 = _copier1.DeepCopy(input.Item1, context);\n            if (_copier2 != null) input.Item2 = _copier2.DeepCopy(input.Item2, context);\n            if (_copier3 != null) input.Item3 = _copier3.DeepCopy(input.Item3, context);\n            if (_copier4 != null) input.Item4 = _copier4.DeepCopy(input.Item4, context);\n            if (_copier5 != null) input.Item5 = _copier5.DeepCopy(input.Item5, context);\n            if (_copier6 != null) input.Item6 = _copier6.DeepCopy(input.Item6, context);\n            if (_copier7 != null) input.Item7 = _copier7.DeepCopy(input.Item7, context);\n            if (_copier8 != null) input.Rest = _copier8.DeepCopy(input.Rest, context);\n            return input;\n        }\n    } \n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/VersionCodec.cs",
    "content": "using Orleans.Serialization.Serializers;\nusing System;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Version\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class VersionCodec : GeneralizedReferenceTypeSurrogateCodec<Version, VersionSurrogate>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"VersionCodec\"/> class.\n        /// </summary>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public VersionCodec(IValueSerializer<VersionSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        /// <inheritdoc />\n        public override Version ConvertFromSurrogate(ref VersionSurrogate surrogate)\n        {\n            int revision = surrogate.Revision;\n            int build = surrogate.Build;\n\n            // ArgumentOutOfRangeException is thrown if any argument is less than zero\n            // Build and Revision are -1 if they are not defined during construction\n            if (revision != -1)\n            {\n                return new Version(surrogate.Major, surrogate.Minor, build, revision);\n            }\n            else if (build != -1)\n            {\n                return new Version(surrogate.Major, surrogate.Minor, build);\n            }\n            else\n            {\n                return new Version(surrogate.Major, surrogate.Minor);\n            }\n        }\n\n        /// <inheritdoc />\n        public override void ConvertToSurrogate(Version value, ref VersionSurrogate surrogate)\n        {\n            surrogate.Major = value.Major;\n            surrogate.Minor = value.Minor;\n            surrogate.Build = value.Build;\n            surrogate.Revision = value.Revision;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"VersionCodec\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    public struct VersionSurrogate\n    {\n        /// <summary>\n        /// Gets or sets the major version component.\n        /// </summary>\n        /// <value>The major version component.</value>\n        [Id(0)]\n        public int Major;\n\n        /// <summary>\n        /// Gets or sets the minor version component.\n        /// </summary>\n        /// <value>The minor version component.</value>\n        [Id(1)]\n        public int Minor;\n\n        /// <summary>\n        /// Gets or sets the build number.\n        /// </summary>\n        /// <value>The build number.</value>\n        [Id(2)]\n        public int Build;\n\n        /// <summary>\n        /// Gets or sets the revision.\n        /// </summary>\n        /// <value>The revision.</value>\n        [Id(3)]\n        public int Revision;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/VoidCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for unknown types.\n    /// </summary>\n    internal sealed class VoidCodec : IFieldCodec\n    {\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (!ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                ThrowNotNullException(value);\n            }\n        }\n\n        /// <inheritdoc />\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireType(WireType.Reference);\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        private static void ThrowNotNullException(object value) => throw new InvalidOperationException(\n            $\"Expected a value of null, but encountered a value of '{value}'.\");\n    }\n\n    /// <summary>\n    /// Copier for unknown types.\n    /// </summary>\n    internal sealed class VoidCopier : IDeepCopier\n    {\n        public object DeepCopy(object input, CopyContext context)\n        {\n            if (context.TryGetCopy<object>(input, out var result))\n            {\n                return result;\n            }\n\n            ThrowNotNullException(input);\n            return null;\n        }\n\n        private static void ThrowNotNullException(object value) => throw new InvalidOperationException($\"Expected a value of null, but encountered a value of type '{value.GetType()}'.\");\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Codecs/WellKnownStringComparerCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\n#if !NET6_0_OR_GREATER\nusing System.Runtime.Serialization;\n#endif\n\nnamespace Orleans.Serialization.Codecs\n{\n    /// <summary>\n    /// Serializer for well-known <see cref=\"StringComparer\"/> types.\n    /// </summary>\n    [Alias(\"StringComparer\")]\n    public sealed class WellKnownStringComparerCodec : IGeneralizedCodec\n    {\n        private static readonly Type CodecType = typeof(WellKnownStringComparerCodec);\n        private readonly StringComparer _ordinalComparer;\n        private readonly StringComparer _ordinalIgnoreCaseComparer;\n        private readonly EqualityComparer<string> _defaultEqualityComparer;\n        private readonly Type _ordinalType;\n        private readonly Type _ordinalIgnoreCaseType;\n        private readonly Type _defaultEqualityType;\n#if !NET6_0_OR_GREATER\n        private readonly StreamingContext _streamingContext;\n        private readonly FormatterConverter _formatterConverter;\n#endif\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"WellKnownStringComparerCodec\"/> class.\n        /// </summary>\n        public WellKnownStringComparerCodec()\n        {\n            _ordinalComparer = StringComparer.Ordinal;\n            _ordinalIgnoreCaseComparer = StringComparer.OrdinalIgnoreCase;\n            _defaultEqualityComparer = EqualityComparer<string>.Default;\n\n            _ordinalType = _ordinalComparer.GetType();\n            _ordinalIgnoreCaseType = _ordinalIgnoreCaseComparer.GetType();\n            _defaultEqualityType = _defaultEqualityComparer.GetType();\n#if !NET6_0_OR_GREATER\n            _streamingContext = new StreamingContext(StreamingContextStates.All);\n            _formatterConverter = new FormatterConverter();\n#endif\n        }\n\n        /// <inheritdoc />\n        public bool IsSupportedType(Type type) =>\n            type == CodecType\n            || type == _ordinalType\n            || type == _ordinalIgnoreCaseType\n            || type == _defaultEqualityType\n            || !type.IsAbstract && typeof(IEqualityComparer<string>).IsAssignableFrom(type) && type.Assembly.Equals(typeof(IEqualityComparer<string>).Assembly);\n\n        /// <inheritdoc />\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            uint type = default;\n            CompareOptions options = default;\n            int lcid = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        type = UInt32Codec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        options = (CompareOptions)UInt32Codec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        lcid = Int32Codec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            if (type == 0)\n            {\n                return null;\n            }\n            else if (type == 1)\n            {\n                if (options.HasFlag(CompareOptions.IgnoreCase))\n                {\n                    return StringComparer.OrdinalIgnoreCase;\n                }\n                else\n                {\n                    return StringComparer.Ordinal;\n                }\n            }\n            else if (type == 2)\n            {\n                if (lcid == CultureInfo.InvariantCulture.LCID)\n                {\n                    if (options == CompareOptions.None)\n                    {\n                        return StringComparer.InvariantCulture;\n                    }\n                    else if (options == CompareOptions.IgnoreCase)\n                    {\n                        return StringComparer.InvariantCultureIgnoreCase;\n                    }\n\n                    // Otherwise, perhaps some other options were specified, in which case we fall-through to create a new comparer.\n                }\n\n                var cultureInfo = CultureInfo.GetCultureInfo(lcid);\n                var result = StringComparer.Create(cultureInfo, options);\n                return result;\n            }\n\n            ThrowNotSupported(field, type);\n            return null;\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            uint type;\n            CompareOptions compareOptions = default;\n            CompareInfo compareInfo = default;\n            if (value is null)\n            {\n                type = 0;\n            }\n            else\n            {\n#if NET6_0_OR_GREATER\n                var comparer = (IEqualityComparer<string>)value;\n                if (StringComparer.IsWellKnownOrdinalComparer(comparer, out var ignoreCase))\n                {\n                    // Ordinal. This also handles EqualityComparer<string>.Default.\n                    type = 1;\n                    if (ignoreCase)\n                    {\n                        compareOptions = CompareOptions.IgnoreCase;\n                    }\n                }\n                else if (StringComparer.IsWellKnownCultureAwareComparer(comparer, out compareInfo, out compareOptions))\n                {\n                    type = 2;\n                }\n                else\n                {\n                    ThrowNotSupported(value.GetType());\n                    return;\n                }\n#else\n                var isOrdinal = _ordinalComparer.Equals(value) || _defaultEqualityComparer.Equals(value);\n                var isOrdinalIgnoreCase = _ordinalIgnoreCaseComparer.Equals(value);\n                if (isOrdinal)\n                {\n                    type = 1;\n                }\n                else if (isOrdinalIgnoreCase)\n                {\n                    type = 1;\n                    compareOptions = CompareOptions.IgnoreCase;\n                }\n                else if (TryGetWellKnownCultureAwareComparerInfo(value, out compareInfo, out compareOptions, out var ignoreCase))\n                {\n                    type = 2;\n                    if (ignoreCase)\n                    {\n                        compareOptions |= CompareOptions.IgnoreCase;\n                    }\n                }\n                else\n                {\n                    ThrowNotSupported(value.GetType());\n                    return;\n                }\n#endif\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(WellKnownStringComparerCodec), WireType.TagDelimited);\n\n            UInt32Codec.WriteField(ref writer, 0, type);\n            UInt32Codec.WriteField(ref writer, 1, (uint)compareOptions);\n\n            if (compareInfo is not null)\n            {\n                Int32Codec.WriteField(ref writer, 1, compareInfo.LCID);\n            }\n\n            writer.WriteEndObject();\n        }\n\n#if !NET6_0_OR_GREATER\n        private bool TryGetWellKnownCultureAwareComparerInfo(object value, out CompareInfo compareInfo, out CompareOptions compareOptions, out bool ignoreCase)\n        {\n            compareInfo = default;\n            compareOptions = default;\n            ignoreCase = default;\n            if (value is ISerializable serializable)\n            {\n                var info = new SerializationInfo(value.GetType(), _formatterConverter);\n                serializable.GetObjectData(info, _streamingContext);\n                foreach (var entry in info)\n                {\n                    switch (entry.Name)\n                    {\n                        case \"_compareInfo\":\n                            compareInfo = entry.Value as CompareInfo;\n                            break;\n                        case \"_options\":\n                            compareOptions = (CompareOptions)entry.Value;\n                            break;\n                        case \"_ignoreCase\":\n                            ignoreCase = (bool)entry.Value;\n                            break;\n                    }\n                }\n\n                return compareInfo is not null;\n            }\n\n            return false;\n        }\n#endif\n\n        [DoesNotReturn]\n        private static void ThrowNotSupported(Field field, uint value) => throw new NotSupportedException($\"Values of type {field.FieldType} are not supported. Value: {value}\");\n\n        [DoesNotReturn]\n        private static void ThrowNotSupported(Type type) => throw new NotSupportedException($\"Values of type {type} are not supported\");\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"EqualityComparer{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    [RegisterSerializer]\n    internal sealed class EqualityComparerBaseCodec<T> : IBaseCodec<EqualityComparer<T>>, IBaseCopier<EqualityComparer<T>>\n    {\n        /// <inheritdoc />\n        public void DeepCopy(EqualityComparer<T> input, EqualityComparer<T> output, CopyContext context) { }\n\n        /// <inheritdoc />\n        public void Deserialize<TInput>(ref Reader<TInput> reader, EqualityComparer<T> value) => reader.ConsumeEndBaseOrEndObject();\n\n        /// <inheritdoc />\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, EqualityComparer<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"Comparer{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The element type.</typeparam>\n    [RegisterCopier]\n    [RegisterSerializer]\n    internal sealed class ComparerBaseCodec<T> : IBaseCodec<Comparer<T>>, IBaseCopier<Comparer<T>>\n    {\n        /// <inheritdoc />\n        public void DeepCopy(Comparer<T> input, Comparer<T> output, CopyContext context) { }\n\n        /// <inheritdoc />\n        public void Deserialize<TInput>(ref Reader<TInput> reader, Comparer<T> value) => reader.ConsumeEndBaseOrEndObject();\n\n        /// <inheritdoc />\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, Comparer<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Configuration/DefaultTypeManifestProvider.cs",
    "content": "using System;\nusing System.Net;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Invocation;\n\nnamespace Orleans.Serialization.Configuration\n{\n    internal class DefaultTypeManifestProvider : TypeManifestProviderBase, IPostConfigureOptions<TypeManifestOptions>\n    {\n        public void PostConfigure(string name, TypeManifestOptions options)\n        {\n            // Clean up the options bookkeeping.\n            options.TypeManifestProviders.Clear();\n        }\n\n        protected override void ConfigureInner(TypeManifestOptions typeManifest)\n        {\n            var wellKnownTypes = typeManifest.WellKnownTypeIds;\n            wellKnownTypes[0] = typeof(void); // Represents the type of null\n            wellKnownTypes[1] = typeof(int);\n            wellKnownTypes[2] = typeof(string);\n            wellKnownTypes[3] = typeof(bool);\n            wellKnownTypes[4] = typeof(short);\n            wellKnownTypes[5] = typeof(long);\n            wellKnownTypes[6] = typeof(sbyte);\n            wellKnownTypes[7] = typeof(uint);\n            wellKnownTypes[8] = typeof(ushort);\n            wellKnownTypes[9] = typeof(ulong);\n            wellKnownTypes[10] = typeof(byte);\n            wellKnownTypes[11] = typeof(float);\n            wellKnownTypes[12] = typeof(double);\n            wellKnownTypes[13] = typeof(decimal);\n            wellKnownTypes[14] = typeof(char);\n            wellKnownTypes[15] = typeof(Guid);\n            wellKnownTypes[16] = typeof(DateTime);\n            wellKnownTypes[17] = typeof(TimeSpan);\n            wellKnownTypes[18] = typeof(DateTimeOffset);\n            wellKnownTypes[19] = typeof(object);\n            wellKnownTypes[20] = typeof(DotNetSerializableCodec);\n            wellKnownTypes[21] = typeof(ExceptionCodec);\n            wellKnownTypes[22] = typeof(byte[]);\n            wellKnownTypes[23] = typeof(object[]);\n            wellKnownTypes[24] = typeof(char[]);\n            wellKnownTypes[25] = typeof(int[]);\n            wellKnownTypes[26] = typeof(string[]);\n            wellKnownTypes[27] = typeof(Type);\n#if NET6_0_OR_GREATER\n            wellKnownTypes[28] = typeof(DateOnly);\n            wellKnownTypes[29] = typeof(TimeOnly);\n#endif\n            wellKnownTypes[30] = typeof(DayOfWeek);\n            wellKnownTypes[31] = typeof(Uri);\n            wellKnownTypes[32] = typeof(Version);\n            wellKnownTypes[33] = typeof(IPAddress);\n            wellKnownTypes[34] = typeof(IPEndPoint);\n            wellKnownTypes[35] = typeof(ExceptionResponse);\n            wellKnownTypes[36] = typeof(CompletedResponse);\n#if NET7_0_OR_GREATER\n            wellKnownTypes[37] = typeof(Int128);\n            wellKnownTypes[38] = typeof(UInt128);\n#endif\n#if NET5_0_OR_GREATER\n            wellKnownTypes[39] = typeof(Half);\n#endif\n\n            var allowedTypes = typeManifest.AllowedTypes;\n            allowedTypes.Add(\"System.Globalization.CompareOptions\");\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Configuration/ITypeManifestProvider.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Orleans.Serialization.Configuration\n{\n    /// <summary>\n    /// Provides type manifest information.\n    /// </summary>\n    public interface ITypeManifestProvider : IConfigureOptions<TypeManifestOptions>\n    {\n    }\n\n    /// <summary>\n    /// Base class for generated type manifest providers.\n    /// </summary>\n    public abstract class TypeManifestProviderBase : ITypeManifestProvider\n    {\n        /// <inheritdoc/>\n        void IConfigureOptions<TypeManifestOptions>.Configure(TypeManifestOptions options)\n        {\n            if (options.TypeManifestProviders.Add(Key))\n            {\n                ConfigureInner(options);\n            }\n        }\n\n        /// <summary>\n        /// Gets the unique identifier for this type manifest provider.\n        /// </summary>\n        public virtual object Key => GetType();\n\n        /// <summary>\n        /// Configures the provided type manifest options.\n        /// </summary>\n        /// <param name=\"options\">The type manifest options.</param>\n        protected abstract void ConfigureInner(TypeManifestOptions options);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Configuration/TypeManifestOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Serialization.Configuration\n{\n    /// <summary>\n    /// Configuration of all types which are known to the code generator.\n    /// </summary>\n    public sealed class TypeManifestOptions\n    {\n        /// <summary>\n        /// Gets or sets a value indicating whether <see cref=\"SerializerConfigurationAnalyzer\"/> should be enabled.\n        /// </summary>\n        /// <remarks>\n        /// This property does not cause <see cref=\"SerializerConfigurationAnalyzer\"/> to be invoked.\n        /// That is the responsibility of the consuming framework.\n        /// </remarks>\n        public bool? EnableConfigurationAnalysis { get; set; }\n\n        /// <summary>\n        /// Gets the set of known activators, which are responsible for creating instances of a given type.\n        /// </summary>\n        public HashSet<Type> Activators { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of known field codecs, which are responsible for serializing and deserializing fields of a given type.\n        /// </summary>\n        public HashSet<Type> FieldCodecs { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of known serializers, which are responsible for serializing and deserializing a given type.\n        /// </summary>\n        public HashSet<Type> Serializers { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of copiers, which are responsible for creating deep copies of a given type.\n        /// </summary>\n        public HashSet<Type> Copiers { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of converters, which are responsible for converting from one type to another.\n        /// </summary>\n        public HashSet<Type> Converters { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of known interfaces, which are interfaces that have corresponding proxies in the <see cref=\"InterfaceProxies\"/> collection.\n        /// </summary>\n        public HashSet<Type> Interfaces { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of known interface proxies, which capture method invocations which can be serialized, deserialized, and invoked against an implementation of this interface.\n        /// </summary>\n        /// <remarks>\n        /// This allows decoupling the caller and target, so that remote procedure calls can be implemented by capturing an invocation, transmitting it, and later invoking it against a target object.\n        /// </remarks>\n        public HashSet<Type> InterfaceProxies { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the set of interface implementations, which are implementations of the interfaces present in <see cref=\"Interfaces\"/>.\n        /// </summary>\n        public HashSet<Type> InterfaceImplementations { get; } = new HashSet<Type>();\n\n        /// <summary>\n        /// Gets the mapping of well-known type identifiers to their corresponding type.\n        /// </summary>\n        public Dictionary<uint, Type> WellKnownTypeIds { get; } = new Dictionary<uint, Type>();\n\n        /// <summary>\n        /// Gets the mapping of well-known type aliases to their corresponding type.\n        /// </summary>\n        public Dictionary<string, Type> WellKnownTypeAliases { get; } = new Dictionary<string, Type>();\n\n        /// <summary>\n        /// Gets the mapping of allowed type names.\n        /// </summary>\n        public HashSet<string> AllowedTypes { get; } = new HashSet<string>(StringComparer.Ordinal);\n\n        /// <summary>\n        /// Gets the mapping from compound type aliases to types.\n        /// </summary>\n        public CompoundTypeAliasTree CompoundTypeAliases { get; } = CompoundTypeAliasTree.Create();\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to allow all types by default.\n        /// Default: <see langword=\"false\"/>.\n        /// </summary>\n        public bool AllowAllTypes { get; set; }\n\n        /// <summary>\n        /// Gets the set of type manifest providers which have configured this instance.\n        /// </summary>\n        internal HashSet<object> TypeManifestProviders { get; } = new();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Configuration/TypeManifestProviderAttribute.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization.Configuration\n{\n    /// <summary>\n    /// Defines a metadata provider for this assembly.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed class TypeManifestProviderAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypeManifestProviderAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"providerType\">The metadata provider type.</param>\n        public TypeManifestProviderAttribute(Type providerType)\n        {\n            if (providerType is null)\n            {\n                throw new ArgumentNullException(nameof(providerType));\n            }\n\n            if (!typeof(ITypeManifestProvider).IsAssignableFrom(providerType))\n            {\n                throw new ArgumentException($\"Provided type {providerType} must implement {typeof(ITypeManifestProvider)}\", nameof(providerType));\n            }\n\n            ProviderType = providerType;\n        }\n\n        /// <summary>\n        /// Gets the manifest provider type.\n        /// </summary>\n        public Type ProviderType { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Exceptions.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Serialization\n{\n    internal static class ExceptionHelper\n    {\n        public static T ThrowArgumentOutOfRange<T>(string argument) => throw new ArgumentOutOfRangeException(argument);\n    }\n\n    /// <summary>\n    /// Base exception for any serializer exception.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class SerializerException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerException\"/> class.\n        /// </summary>\n        public SerializerException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public SerializerException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception, or a null reference (<see langword=\"Nothing\" /> in Visual Basic) if no inner exception is specified.</param>\n        public SerializerException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        protected SerializerException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// An field identifier was expected but not present.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class FieldIdNotPresentException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldIdNotPresentException\"/> class.\n        /// </summary>\n        public FieldIdNotPresentException() : base(\"Attempted to access the field id from a tag which cannot have a field id.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldIdNotPresentException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private FieldIdNotPresentException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// The schema type is invalid.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class SchemaTypeInvalidException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SchemaTypeInvalidException\"/> class.\n        /// </summary>\n        public SchemaTypeInvalidException() : base(\"Attempted to access the schema type from a tag which cannot have a schema type.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SchemaTypeInvalidException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private SchemaTypeInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// The field type is invalid.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class FieldTypeInvalidException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldTypeInvalidException\"/> class.\n        /// </summary>\n        public FieldTypeInvalidException() : base(\"Attempted to access the schema type from a tag which cannot have a schema type.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldTypeInvalidException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private FieldTypeInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// A field type was expected but not present.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class FieldTypeMissingException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldTypeMissingException\"/> class.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        public FieldTypeMissingException(Type type) : base($\"Attempted to deserialize an instance of abstract type {type}. No concrete type was provided.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldTypeMissingException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private FieldTypeMissingException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// The extended wire type is invalid.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ExtendedWireTypeInvalidException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExtendedWireTypeInvalidException\"/> class.\n        /// </summary>\n        public ExtendedWireTypeInvalidException() : base(\n            \"Attempted to access the extended wire type from a tag which does not have an extended wire type.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExtendedWireTypeInvalidException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private ExtendedWireTypeInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// The wire type is unsupported.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class UnsupportedWireTypeException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnsupportedWireTypeException\"/> class.\n        /// </summary>\n        public UnsupportedWireTypeException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnsupportedWireTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public UnsupportedWireTypeException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnsupportedWireTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private UnsupportedWireTypeException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// A referenced value was not found.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ReferenceNotFoundException : SerializerException\n    {\n        /// <summary>\n        /// Gets the target reference.\n        /// </summary>\n        /// <value>The target reference.</value>\n        [Id(0)]\n        public uint TargetReference { get; }\n\n        /// <summary>\n        /// Gets the type of the target reference.\n        /// </summary>\n        /// <value>The type of the target reference.</value>\n        [Id(1)]\n        public Type TargetReferenceType { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceNotFoundException\"/> class.\n        /// </summary>\n        /// <param name=\"targetType\">Type of the target.</param>\n        /// <param name=\"targetId\">The target identifier.</param>\n        public ReferenceNotFoundException(Type targetType, uint targetId) : base(\n            $\"Reference with id {targetId} and type {targetType} not found.\")\n        {\n            TargetReference = targetId;\n            TargetReferenceType = targetType;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceNotFoundException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private ReferenceNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            TargetReference = info.GetUInt32(nameof(TargetReference));\n            TargetReferenceType = (Type)info.GetValue(nameof(TargetReferenceType), typeof(Type));\n        }\n\n        /// <inheritdoc/>\n        #if NET8_0_OR_GREATER\n        [Obsolete]\n        #endif\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(TargetReference), TargetReference);\n            info.AddValue(nameof(TargetReferenceType), TargetReferenceType);\n        }\n    }\n\n    /// <summary>\n    /// A referenced type was not found.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class UnknownReferencedTypeException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnknownReferencedTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"reference\">The reference.</param>\n        public UnknownReferencedTypeException(uint reference) : base($\"Unknown referenced type {reference}.\")\n        {\n            Reference = reference;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnknownReferencedTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private UnknownReferencedTypeException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            info.AddValue(nameof(Reference), Reference);\n        }\n\n        /// <summary>\n        /// Gets or sets the reference.\n        /// </summary>\n        /// <value>The reference.</value>\n        [Id(0)]\n        public uint Reference { get; set; }\n\n        /// <inheritdoc/>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            Reference = info.GetUInt32(nameof(Reference));\n        }\n    }\n\n    /// <summary>\n    /// A reference to a value is not supported here.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ReferenceFieldNotSupportedException : SerializerException\n    {\n        /// <summary>\n        /// Gets the type of the target reference.\n        /// </summary>\n        /// <value>The type of the target reference.</value>\n        [Id(0)]\n        public Type TargetReferenceType { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceFieldNotSupportedException\"/> class.\n        /// </summary>\n        /// <param name=\"targetType\">Type of the target.</param>\n        public ReferenceFieldNotSupportedException(Type targetType) : base(\n            $\"Reference with type {targetType} not allowed here.\")\n        {\n            TargetReferenceType = targetType;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceFieldNotSupportedException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private ReferenceFieldNotSupportedException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            TargetReferenceType = (Type)info.GetValue(nameof(TargetReferenceType), typeof(Type));\n        }\n\n        /// <inheritdoc/>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(TargetReferenceType), TargetReferenceType);\n        }\n    }\n\n    /// <summary>\n    /// A well-known type was not known.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class UnknownWellKnownTypeException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnknownWellKnownTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"id\">The identifier.</param>\n        public UnknownWellKnownTypeException(uint id) : base($\"Unknown well-known type {id}.\")\n        {\n            Id = id;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnknownWellKnownTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private UnknownWellKnownTypeException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            info.AddValue(nameof(Id), Id);\n        }\n\n        /// <summary>\n        /// Gets or sets the identifier.\n        /// </summary>\n        /// <value>The identifier.</value>\n        [Id(0)]\n        public uint Id { get; set; }\n\n        /// <inheritdoc />\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            Id = info.GetUInt32(nameof(Id));\n        }\n    }\n\n    /// <summary>\n    /// A specified type is not allowed.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class IllegalTypeException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IllegalTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"typeName\">Name of the type.</param>\n        public IllegalTypeException(string typeName) : base($\"Type \\\"{typeName}\\\" is not allowed.\")\n        {\n            TypeName = typeName;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IllegalTypeException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private IllegalTypeException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            TypeName = info.GetString(nameof(TypeName));\n        }\n\n        /// <summary>\n        /// Gets the name of the type.\n        /// </summary>\n        /// <value>The name of the type.</value>\n        [Id(0)]\n        public string TypeName { get; }\n\n        /// <inheritdoc/>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(TypeName), TypeName);\n        }\n    }\n\n    /// <summary>\n    /// A type was expected but not found.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class TypeMissingException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypeMissingException\"/> class.\n        /// </summary>\n        public TypeMissingException() : base(\"Expected a type but none were encountered.\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypeMissingException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private TypeMissingException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// A required field was not present.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class RequiredFieldMissingException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RequiredFieldMissingException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public RequiredFieldMissingException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RequiredFieldMissingException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private RequiredFieldMissingException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// No suitable serializer codec was found for a specified type.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class CodecNotFoundException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CodecNotFoundException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public CodecNotFoundException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CodecNotFoundException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private CodecNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// A length encoded field which is expected to have a length\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class UnexpectedLengthPrefixValueException : SerializerException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnexpectedLengthPrefixValueException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public UnexpectedLengthPrefixValueException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnexpectedLengthPrefixValueException\"/> class.\n        /// </summary>\n        /// <param name=\"typeName\">Name of the type.</param>\n        /// <param name=\"expectedLength\">The expected length.</param>\n        /// <param name=\"actualLength\">The actual length.</param>\n        public UnexpectedLengthPrefixValueException(string typeName, uint expectedLength, uint actualLength)\n            : base($\"VarInt length specified in header for {typeName} should be {expectedLength} but is instead {actualLength}\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnexpectedLengthPrefixValueException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        private UnexpectedLengthPrefixValueException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/GeneratedCodeHelpers/OrleansGeneratedCodeHelper.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.GeneratedCodeHelpers\n{\n    /// <summary>\n    /// Utilities for use by generated code.\n    /// </summary>\n    public static class OrleansGeneratedCodeHelper\n    {\n        private static readonly ThreadLocal<RecursiveServiceResolutionState> ResolutionState = new ThreadLocal<RecursiveServiceResolutionState>(() => new RecursiveServiceResolutionState());\n\n        private sealed class RecursiveServiceResolutionState\n        {\n            private int _depth;\n\n            public List<object> Callers { get; } = new List<object>();\n\n            public void Enter(object caller)\n            {\n                ++_depth;\n                if (caller is not null)\n                {\n                    Callers.Add(caller);\n                }\n            }\n\n            public void Exit()\n            {\n                if (--_depth <= 0)\n                {\n                    Callers.Clear();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Unwraps the provided service if it was wrapped.\n        /// </summary>\n        /// <typeparam name=\"TService\">The service type.</typeparam>\n        /// <param name=\"caller\">The caller.</param>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        /// <returns>The unwrapped service.</returns>\n        public static TService GetService<TService>(object caller, ICodecProvider codecProvider)\n        {\n            var state = ResolutionState.Value;\n\n            try\n            {\n                state.Enter(caller);\n\n\n                foreach (var c in state.Callers)\n                {\n                    if (c is TService s && !(c is IServiceHolder<TService>))\n                    {\n                        return s;\n                    }\n                }\n\n                var val = ActivatorUtilities.GetServiceOrCreateInstance<TService>(codecProvider.Services);\n                while (val is IServiceHolder<TService> wrapping)\n                {\n                    val = wrapping.Value;\n                }\n\n                return val;\n            }\n            finally\n            {\n                state.Exit();\n            }\n        }\n\n        /// <summary>\n        /// Unwraps the provided service if it was wrapped.\n        /// </summary>\n        /// <typeparam name=\"TService\">The service type.</typeparam>\n        /// <param name=\"caller\">The caller.</param>\n        /// <param name=\"service\">The service.</param>\n        /// <returns>The unwrapped service.</returns>\n        public static TService UnwrapService<TService>(object caller, TService service)\n        {\n            var state = ResolutionState.Value;\n\n            try\n            {\n                state.Enter(caller);\n\n                foreach (var c in state.Callers)\n                {\n                    if (c is TService s and not IServiceHolder<TService>)\n                    {\n                        return s;\n                    }\n                }\n\n                return Unwrap(service);\n            }\n            finally\n            {\n                state.Exit();\n            }\n\n            static TService Unwrap(TService val)\n            {\n                while (val is IServiceHolder<TService> wrapping)\n                {\n                    val = wrapping.Value;\n                }\n\n                return val;\n            }\n        }\n\n        internal static object TryGetService(Type serviceType)\n        {\n            var state = ResolutionState.Value;\n            foreach (var c in state.Callers)\n            {\n                var type = c?.GetType();\n                if (serviceType == type)\n                {\n                    return c;\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Returns the provided copier if it's not shallow-copyable.\n        /// </summary>\n        public static IDeepCopier<T> GetOptionalCopier<T>(IDeepCopier<T> copier) => copier is IOptionalDeepCopier o && o.IsShallowCopyable() ? null : copier;\n\n        /// <summary>        \n        /// Generated code helper method which throws an <see cref=\"ArgumentOutOfRangeException\"/>.\n        /// </summary>                \n        public static object InvokableThrowArgumentOutOfRange(int index, int maxArgs)\n            => throw new ArgumentOutOfRangeException(message: $\"The argument index value {index} must be between 0 and {maxArgs}\", null);\n\n        /// <summary>\n        /// Expects empty content (a single field header of either <see cref=\"ExtendedWireType.EndBaseFields\"/> or <see cref=\"ExtendedWireType.EndTagDelimited\"/>),\n        /// but will consume any unexpected fields also.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void ConsumeEndBaseOrEndObject<TInput>(this ref Reader<TInput> reader)\n        {\n            Unsafe.SkipInit(out Field field);\n            reader.ReadFieldHeader(ref field);\n            reader.ConsumeEndBaseOrEndObject(ref field);\n        }\n\n        /// <summary>\n        /// Expects empty content (a single field header of either <see cref=\"ExtendedWireType.EndBaseFields\"/> or <see cref=\"ExtendedWireType.EndTagDelimited\"/>),\n        /// but will consume any unexpected fields also.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void ConsumeEndBaseOrEndObject<TInput>(this ref Reader<TInput> reader, scoped ref Field field)\n        {\n            if (!field.IsEndBaseOrEndObject)\n                ConsumeUnexpectedContent(ref reader, ref field);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static void ConsumeUnexpectedContent<TInput>(this ref Reader<TInput> reader, scoped ref Field field)\n        {\n            do\n            {\n                reader.ConsumeUnknownField(ref field);\n                reader.ReadFieldHeader(ref field);\n            } while (!field.IsEndBaseOrEndObject);\n        }\n\n        /// <summary>\n        /// Serializes an unexpected value.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"fieldIdDelta\">The field identifier delta.</param>\n        /// <param name=\"expectedType\">The expected type.</param>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public static void SerializeUnexpectedType<TBufferWriter>(this ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var specificSerializer = writer.Session.CodecProvider.GetCodec(value.GetType());\n            specificSerializer.WriteField(ref writer, fieldIdDelta, expectedType, value);\n        }\n\n        /// <summary>\n        /// Deserializes an unexpected value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <typeparam name=\"TField\">The value type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"field\">The field.</param>\n        /// <returns>The value.</returns>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public static TField DeserializeUnexpectedType<TInput, TField>(this ref Reader<TInput> reader, scoped ref Field field) where TField : class\n        {\n            var specificSerializer = reader.Session.CodecProvider.GetCodec(field.FieldType);\n            return (TField)specificSerializer.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"MethodInfo\"/> matching the provided values.\n        /// </summary>\n        /// <param name=\"interfaceType\">Type of the interface.</param>\n        /// <param name=\"methodName\">Name of the method.</param>\n        /// <param name=\"methodTypeParameters\">The method type parameters.</param>\n        /// <param name=\"parameterTypes\">The parameter types.</param>\n        /// <returns>The corresponding <see cref=\"MethodInfo\"/>.</returns>\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        public static MethodInfo GetMethodInfoOrDefault(Type interfaceType, string methodName, Type[] methodTypeParameters, Type[] parameterTypes)\n        {\n            if (interfaceType is null)\n            {\n                return null;\n            }\n\n            foreach (var method in interfaceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))\n            {\n                var current = method;\n                if (current.Name != methodName)\n                {\n                    continue;\n                }\n\n                if (current.ContainsGenericParameters != methodTypeParameters is { Length: > 0 })\n                {\n                    continue;\n                }\n\n                if (methodTypeParameters is { Length: > 0 })\n                {\n                    if (methodTypeParameters.Length != current.GetGenericArguments().Length)\n                    {\n                        continue;\n                    }\n\n                    current = current.MakeGenericMethod(methodTypeParameters);\n                }\n\n                var parameters = current.GetParameters();\n                if (parameters.Length != (parameterTypes?.Length ?? 0))\n                {\n                    continue;\n                }\n\n                var isMatch = true;\n                for (int i = 0; i < parameters.Length; i++)\n                {\n                    if (!parameters[i].ParameterType.Equals(parameterTypes[i]))\n                    {\n                        isMatch = false;\n                        break;\n                    }\n                }\n\n                if (!isMatch)\n                {\n                    continue;\n                }\n\n                return current;\n            }\n\n            foreach (var implemented in interfaceType.GetInterfaces())\n            {\n                if (GetMethodInfoOrDefault(implemented, methodName, methodTypeParameters, parameterTypes) is { } method)\n                {\n                    return method;\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Default copier implementation for (rarely copied) exception classes\n        /// </summary>\n        public abstract class ExceptionCopier<T, B> : IDeepCopier<T>, IBaseCopier<T> where T : B where B : Exception\n        {\n            private readonly Type _fieldType = typeof(T);\n            private readonly IActivator<T> _activator;\n            private readonly IBaseCopier<B> _baseTypeCopier;\n\n            protected ExceptionCopier(ICodecProvider codecProvider)\n            {\n                _activator = GetService<IActivator<T>>(this, codecProvider);\n                _baseTypeCopier = GetService<IBaseCopier<B>>(this, codecProvider);\n            }\n\n            public T DeepCopy(T original, CopyContext context)\n            {\n                if (original is null)\n                {\n                    return null;\n                }\n\n                if (original.GetType() != _fieldType)\n                {\n                    return context.DeepCopy(original);\n                }\n\n                var result = _activator.Create();\n                DeepCopy(original, result, context);\n                return result;\n            }\n\n            public virtual void DeepCopy(T input, T output, CopyContext context) => _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Hosting/ISerializerBuilder.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Builder interface for configuring serialization.\n    /// </summary>\n    public interface ISerializerBuilder\n    {\n        /// <summary>\n        /// Gets the service collection.\n        /// </summary>\n        IServiceCollection Services { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Hosting/ReferencedAssemblyProvider.cs",
    "content": "using Microsoft.Extensions.DependencyModel;\nusing System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\n#if NETCOREAPP3_1_OR_GREATER\nusing System.Runtime.Loader;\n#endif\n\nnamespace Orleans.Serialization.Internal\n{\n    public static class ReferencedAssemblyProvider\n    {\n        public static IEnumerable<Assembly> GetRelevantAssemblies()\n        {\n            var parts = new HashSet<Assembly>();\n\n            AddFromDependencyContext(parts);\n\n#if NETCOREAPP3_1_OR_GREATER\n            AddFromAssemblyLoadContext(parts);\n#endif\n\n            foreach (var loadedAsm in AppDomain.CurrentDomain.GetAssemblies())\n            {\n                AddAssembly(parts, loadedAsm);\n            }\n\n            return parts;\n        }\n\n        public static void AddAssembly(HashSet<Assembly> parts, Assembly assembly)\n        {\n            if (assembly == null)\n            {\n                throw new ArgumentNullException(nameof(assembly));\n            }\n\n            if (!assembly.IsDefined(typeof(ApplicationPartAttribute)))\n            {\n                return;\n            }\n\n            if (!parts.Add(assembly))\n            {\n                return;\n            }\n\n            AddAssembly(parts, assembly);\n\n            // Add all referenced application parts.\n            foreach (var referencedAsm in GetApplicationPartAssemblies(assembly))\n            {\n                AddAssembly(parts, referencedAsm);\n            }\n        }\n\n#if NETCOREAPP3_1_OR_GREATER\n        public static void AddFromAssemblyLoadContext(HashSet<Assembly> parts, AssemblyLoadContext context)\n        {\n            if (context is null)\n            {\n                throw new ArgumentNullException(nameof(context));\n            }\n\n            foreach (var asm in context.Assemblies)\n            {\n                AddAssembly(parts, asm);\n            }\n        }\n\n        public static void AddFromAssemblyLoadContext(HashSet<Assembly> parts, Assembly assembly = null)\n        {\n            assembly ??= typeof(ReferencedAssemblyProvider).Assembly;\n            var assemblies = new HashSet<Assembly>();\n            var context = AssemblyLoadContext.GetLoadContext(assembly);\n            foreach (var asm in context.Assemblies)\n            {\n                // Skip assemblies which have not had code generation executed against them and already-seen assemblies.\n                if (!asm.IsDefined(typeof(ApplicationPartAttribute)) || !assemblies.Add(asm))\n                {\n                    continue;\n                }\n\n                AddAssembly(parts, asm);\n            }\n        }\n#endif\n\n        public static void AddFromDependencyContext(HashSet<Assembly> parts, Assembly assembly = null)\n        {\n            assembly ??= Assembly.GetEntryAssembly();\n            DependencyContext dependencyContext;\n            if (assembly is null || assembly.IsDynamic)\n            {\n                dependencyContext = DependencyContext.Default;\n            }\n            else\n            {\n                dependencyContext = DependencyContext.Load(assembly);\n            }\n\n            var assemblies = new HashSet<Assembly>();\n            if (assembly != null && assembly.IsDefined(typeof(ApplicationPartAttribute)))\n            {\n                AddAssembly(parts, assembly);\n                assemblies.Add(assembly);\n            }\n\n            if (dependencyContext == null)\n            {\n                return;\n            }\n\n#if NETCOREAPP3_1_OR_GREATER\n            var assemblyContext = assembly is not null\n                ? AssemblyLoadContext.GetLoadContext(assembly) ?? AssemblyLoadContext.Default\n                : AssemblyLoadContext.Default;\n#endif\n\n            foreach (var lib in dependencyContext.RuntimeLibraries)\n            {\n                if (!lib.Name.Contains(\"Orleans.Serialization\", StringComparison.Ordinal) && !lib.Dependencies.Any(dep => dep.Name.Contains(\"Orleans.Serialization\", StringComparison.Ordinal)))\n                {\n                    continue;\n                }\n\n                try\n                {\n#if NET5_0_OR_GREATER\n                    var name = lib.GetRuntimeAssemblyNames(dependencyContext, System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier).FirstOrDefault();\n                    if (name is null)\n                    {\n                        continue;\n                    }\n\n                    var asm = assemblyContext.LoadFromAssemblyName(name);\n#else\n                    var name = lib.GetRuntimeAssemblyNames(dependencyContext, Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier()).FirstOrDefault();\n                    if (name is null)\n                    {\n                        continue;\n                    }\n\n#if NETCOREAPP3_1_OR_GREATER\n                    var asm = assemblyContext.LoadFromAssemblyName(name);\n#else\n                    var asm = Assembly.Load(name);\n#endif\n#endif\n                    if (asm.IsDefined(typeof(ApplicationPartAttribute)) && assemblies.Add(asm))\n                    {\n                        AddAssembly(parts, asm);\n                    }\n                }\n                catch\n                {\n                    // Ignore any exceptions thrown during non-explicit assembly loading.\n                }\n            }\n        }\n\n        private static IEnumerable<Assembly> GetApplicationPartAssemblies(Assembly assembly)\n        {\n            if (!assembly.IsDefined(typeof(ApplicationPartAttribute)))\n            {\n                return Array.Empty<Assembly>();\n            }\n\n#if NETCOREAPP3_1_OR_GREATER\n            var assemblyContext = AssemblyLoadContext.GetLoadContext(assembly) ?? AssemblyLoadContext.Default; \n#endif\n\n            return ExpandApplicationParts(\n                new[] { assembly }.Concat(assembly.GetCustomAttributes<ApplicationPartAttribute>()\n                    .Select(name =>\n#if NETCOREAPP3_1_OR_GREATER\n                        assemblyContext.LoadFromAssemblyName(new AssemblyName(name.AssemblyName))\n#else\n                        Assembly.Load(new AssemblyName(name.AssemblyName))\n#endif\n                    )));\n\n            static IEnumerable<Assembly> ExpandApplicationParts(IEnumerable<Assembly> assemblies)\n            {\n                if (assemblies == null)\n                {\n                    throw new ArgumentNullException(nameof(assemblies));\n                }\n\n                var relatedAssemblies = new HashSet<Assembly>();\n                foreach (var assembly in assemblies)\n                {\n                    if (relatedAssemblies.Add(assembly))\n                    {\n                        ExpandAssembly(relatedAssemblies, assembly);\n                    }\n                }\n\n                return relatedAssemblies.OrderBy(assembly => assembly.FullName, StringComparer.Ordinal);\n\n                static void ExpandAssembly(HashSet<Assembly> assemblies, Assembly assembly)\n                {\n                    var attributes = assembly.GetCustomAttributes<ApplicationPartAttribute>().ToArray();\n                    if (attributes.Length == 0)\n                    {\n                        return;\n                    }\n\n#if NETCOREAPP3_1_OR_GREATER\n                    var assemblyContext = AssemblyLoadContext.GetLoadContext(assembly) ?? AssemblyLoadContext.Default; \n#endif\n\n                    foreach (var attribute in attributes)\n                    {\n                        var assemblyName = new AssemblyName(attribute.AssemblyName);\n#if NETCOREAPP3_1_OR_GREATER\n                        var referenced = assemblyContext.LoadFromAssemblyName(assemblyName);\n#else\n                        var referenced = Assembly.Load(assemblyName);\n#endif\n                        if (assemblies.Add(referenced))\n                        {\n                            ExpandAssembly(assemblies, referenced);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Hosting/SerializerBuilderExtensions.cs",
    "content": "using Orleans.Serialization.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Reflection;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Extensions for <see cref=\"ISerializerBuilder\"/>.\n    /// </summary>\n    public static class SerializerBuilderExtensions\n    {\n        private static readonly object _assembliesKey = new();\n\n        /// <summary>\n        /// Configures the serialization builder.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"factory\">The factory.</param>\n        /// <returns>The serialization builder</returns>\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, Func<IServiceProvider, IConfigureOptions<TypeManifestOptions>> factory)\n        {\n            builder.Services.AddSingleton<IConfigureOptions<TypeManifestOptions>>(factory);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configures the serialization builder.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The serialization builder</returns>\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, IConfigureOptions<TypeManifestOptions> configure)\n        {\n            builder.Services.AddSingleton<IConfigureOptions<TypeManifestOptions>>(configure);\n            return builder;\n        }\n\n        /// <summary>\n        /// Configures the serialization builder.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The serialization builder</returns>\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, Action<TypeManifestOptions> configure)\n        {\n            builder.Services.Configure(configure);\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds an assembly to the builder.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"assembly\">The assembly.</param>\n        /// <returns>The serialization builder</returns>\n        public static ISerializerBuilder AddAssembly(this ISerializerBuilder builder, Assembly assembly)\n        {\n            var attrs = assembly.GetCustomAttributes<TypeManifestProviderAttribute>();\n\n            foreach (var attr in attrs)\n            {\n                _ = builder.Services.AddSingleton(typeof(IConfigureOptions<TypeManifestOptions>), attr.ProviderType);\n            }\n\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Hosting/SerializerConfigurationAnalyzer.cs",
    "content": "using Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Analyzes serializer configuration to find likely configuration issues.\n    /// </summary>\n    public static class SerializerConfigurationAnalyzer\n    {\n        /// <summary>\n        /// Analyzes grain interface methods to find parameter types and return types which are not serializable.\n        /// </summary>\n        /// <param name=\"codecProvider\">\n        /// The codec provider.\n        /// </param>\n        /// <param name=\"options\">\n        /// The type manifest options.\n        /// </param>\n        /// <returns>\n        /// A collection of types which have serializability issues.\n        /// </returns>\n        public static Dictionary<Type, SerializerConfigurationComplaint> AnalyzeSerializerAvailability(ICodecProvider codecProvider, TypeManifestOptions options)\n        {\n            var allComplaints = new Dictionary<Type, SerializerConfigurationComplaint>();\n            foreach (var @interface in options.Interfaces)\n            {\n                foreach (var method in @interface.GetMethods(BindingFlags.Instance | BindingFlags.Public))\n                {\n                    if (typeof(Task).IsAssignableFrom(method.ReturnType))\n                    {\n                        if (method.ReturnType.IsConstructedGenericType && typeof(Task<>).IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition()))\n                        {\n                            VisitType(method.ReturnType.GetGenericArguments()[0], method);\n                        }\n                    }\n\n                    if (method.ReturnType.IsConstructedGenericType && typeof(ValueTask<>).IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition()))\n                    {\n                        VisitType(method.ReturnType.GetGenericArguments()[0], method);\n                    }\n\n                    foreach (var param in method.GetParameters())\n                    {\n                        VisitType(param.ParameterType, method);\n                    }\n                }\n            }\n\n            return allComplaints;\n\n            void VisitType(Type type, MethodInfo methodInfo)\n            {\n                if (!IsEligibleType(type))\n                {\n                    return;\n                }\n\n                var hasCodec = codecProvider.TryGetCodec(type) is not null;\n                var hasCopier = codecProvider.TryGetDeepCopier(type) is not null;\n                if (!hasCodec || !hasCopier)\n                {\n                    if (!allComplaints.TryGetValue(type, out var complaint))\n                    {\n                        complaint = allComplaints[type] = new()\n                        {\n                            HasSerializer = hasCodec,\n                            HasCopier = hasCopier,\n                        };\n                    }\n\n                    if (!complaint.Methods.TryGetValue(methodInfo.DeclaringType, out var methodList))\n                    {\n                        methodList = complaint.Methods[methodInfo.DeclaringType] = new HashSet<MethodInfo>();\n                    }\n\n                    methodList.Add(methodInfo);\n                }\n            }\n\n            bool IsEligibleType(Type type)\n            {\n                if (type.IsGenericTypeParameter || type.IsGenericMethodParameter || type.ContainsGenericParameters || type.Equals(typeof(CancellationToken)))\n                {\n                    return false;\n                }\n\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Represents a configuration issue regarding the serializability of a type used in interface methods.\n        /// </summary>\n        public class SerializerConfigurationComplaint\n        {\n            /// <summary>\n            /// Gets a collection of interface types which reference the type this complaint represents.\n            /// </summary>\n            public Dictionary<Type, HashSet<MethodInfo>> Methods { get; } = new ();\n\n            /// <summary>\n            /// Gets or sets a value indicating whether a serializer is available for this type.\n            /// </summary>\n            public bool HasSerializer { get; set; }\n\n            /// <summary>\n            /// Gets or sets a value indicating whether a copier is available for this type.\n            /// </summary>\n            public bool HasCopier { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs",
    "content": "using System;\nusing System.Buffers;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Internal;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    /// <summary>\n    /// Extensions for <see cref=\"IServiceCollection\"/>.\n    /// </summary>\n    public static class ServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Adds serializer support.\n        /// </summary>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddSerializer(this IServiceCollection services, Action<ISerializerBuilder> configure = null)\n        {\n            // Only add the services once.\n            var context = GetFromServices<ConfigurationContext>(services);\n            if (context is null)\n            {\n                context = new ConfigurationContext(services);\n                foreach (var asm in ReferencedAssemblyProvider.GetRelevantAssemblies())\n                {\n                    context.Builder.AddAssembly(asm);\n                }\n\n                services.Add(context.CreateServiceDescriptor());\n                services.AddOptions();\n                services.AddSingleton<IConfigureOptions<TypeManifestOptions>, DefaultTypeManifestProvider>();\n                services.AddSingleton<IPostConfigureOptions<TypeManifestOptions>, DefaultTypeManifestProvider>();\n                services.AddSingleton<TypeResolver, CachedTypeResolver>();\n                services.AddSingleton<TypeConverter>();\n                services.TryAddSingleton<CodecProvider>();\n                services.TryAddSingleton<ICodecProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton<IDeepCopierProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton<IFieldCodecProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton<IBaseCodecProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton<IValueSerializerProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton<IActivatorProvider>(sp => sp.GetRequiredService<CodecProvider>());\n                services.TryAddSingleton(typeof(IFieldCodec<>), typeof(FieldCodecHolder<>));\n                services.TryAddSingleton(typeof(IBaseCodec<>), typeof(BaseCodecHolder<>));\n                services.TryAddSingleton(typeof(IValueSerializer<>), typeof(ValueSerializerHolder<>));\n                services.TryAddSingleton(typeof(IActivator<>), typeof(ActivatorHolder<>));\n                services.TryAddSingleton<WellKnownTypeCollection>();\n                services.TryAddSingleton<TypeCodec>();\n                services.TryAddSingleton(typeof(IDeepCopier<>), typeof(CopierHolder<>));\n                services.TryAddSingleton(typeof(IBaseCopier<>), typeof(BaseCopierHolder<>));\n\n                // Type filtering\n                services.AddSingleton<ITypeNameFilter, DefaultTypeFilter>();\n\n                // Session\n                services.TryAddSingleton<SerializerSessionPool>();\n                services.TryAddSingleton<CopyContextPool>();\n\n                services.AddSingleton<IGeneralizedCodec, WellKnownStringComparerCodec>();\n\n                services.AddSingleton<ExceptionCodec>();\n                services.AddSingleton<IGeneralizedCodec>(sp => sp.GetRequiredService<ExceptionCodec>());\n                services.AddSingleton<IGeneralizedBaseCodec>(sp => sp.GetRequiredService<ExceptionCodec>());\n\n                // Serializer\n                services.TryAddSingleton<ObjectSerializer>();\n                services.TryAddSingleton<Serializer>();\n                services.TryAddSingleton(typeof(Serializer<>));\n                services.TryAddSingleton(typeof(ValueSerializer<>));\n                services.TryAddSingleton<DeepCopier>();\n                services.TryAddSingleton(typeof(DeepCopier<>));\n            }\n\n            configure?.Invoke(context.Builder);\n\n            return services;\n        }\n\n        private static T GetFromServices<T>(IServiceCollection services)\n        {\n            foreach (var service in services)\n            {\n                if (service.ServiceType == typeof(T))\n                {\n                    return (T)service.ImplementationInstance;\n                }\n            }\n\n            return default;\n        }\n\n        private sealed class ConfigurationContext\n        {\n            public ConfigurationContext(IServiceCollection services) => Builder = new SerializerBuilder(services);\n\n            public ServiceDescriptor CreateServiceDescriptor() => new ServiceDescriptor(typeof(ConfigurationContext), this);\n\n            public ISerializerBuilder Builder { get; }\n        }\n\n        private class SerializerBuilder : ISerializerBuilder\n        {\n            public SerializerBuilder(IServiceCollection services) => Services = services;\n\n            public IServiceCollection Services { get; }\n        }\n\n        private sealed class ActivatorHolder<T> : IActivator<T>, IServiceHolder<IActivator<T>>\n        {\n            private readonly IActivatorProvider _activatorProvider;\n            private IActivator<T> _activator;\n\n            public ActivatorHolder(IActivatorProvider codecProvider)\n            {\n                _activatorProvider = codecProvider;\n            }\n\n            public IActivator<T> Value => _activator ??= _activatorProvider.GetActivator<T>();\n\n            public T Create() => Value.Create();\n        }\n\n        private sealed class FieldCodecHolder<TField> : IFieldCodec<TField>, IServiceHolder<IFieldCodec<TField>>\n        {\n            private readonly IFieldCodecProvider _codecProvider;\n            private IFieldCodec<TField> _codec;\n\n            public FieldCodecHolder(IFieldCodecProvider codecProvider)\n            {\n                _codecProvider = codecProvider;\n            }\n\n            public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte> => Value.WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n            public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field) => Value.ReadValue(ref reader, field);\n\n            public IFieldCodec<TField> Value => _codec ??= _codecProvider.GetCodec<TField>();\n        }\n\n        private sealed class BaseCodecHolder<TField> : IBaseCodec<TField>, IServiceHolder<IBaseCodec<TField>> where TField : class\n        {\n            private readonly IBaseCodecProvider _provider;\n            private IBaseCodec<TField> _baseCodec;\n\n            public BaseCodecHolder(IBaseCodecProvider provider)\n            {\n                _provider = provider;\n            }\n\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, TField value) where TBufferWriter : IBufferWriter<byte> => Value.Serialize(ref writer, value);\n\n            public void Deserialize<TInput>(ref Reader<TInput> reader, TField value) => Value.Deserialize(ref reader, value);\n\n            public IBaseCodec<TField> Value => _baseCodec ??= _provider.GetBaseCodec<TField>();\n        }\n\n        private sealed class ValueSerializerHolder<TField> : IValueSerializer<TField>, IServiceHolder<IValueSerializer<TField>> where TField : struct\n        {\n            private readonly IValueSerializerProvider _provider;\n            private IValueSerializer<TField> _serializer;\n\n            public ValueSerializerHolder(IValueSerializerProvider provider)\n            {\n                _provider = provider;\n            }\n\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, scoped ref TField value) where TBufferWriter : IBufferWriter<byte> => Value.Serialize(ref writer, ref value);\n\n            public void Deserialize<TInput>(ref Reader<TInput> reader, scoped ref TField value) => Value.Deserialize(ref reader, ref value);\n\n            public IValueSerializer<TField> Value => _serializer ??= _provider.GetValueSerializer<TField>();\n        }\n\n        private sealed class CopierHolder<T> : IDeepCopier<T>, IServiceHolder<IDeepCopier<T>>, IOptionalDeepCopier\n        {\n            private readonly IDeepCopierProvider _codecProvider;\n            private IDeepCopier<T> _copier;\n\n            public CopierHolder(IDeepCopierProvider codecProvider)\n            {\n                _codecProvider = codecProvider;\n            }\n\n            public T DeepCopy(T original, CopyContext context) => Value.DeepCopy(original, context);\n\n            public object DeepCopy(object original, CopyContext context) => Value.DeepCopy(original, context);\n\n            public bool IsShallowCopyable() => (Value as IOptionalDeepCopier)?.IsShallowCopyable() ?? false;\n\n            public IDeepCopier<T> Value => _copier ??= _codecProvider.GetDeepCopier<T>();\n        }\n\n        private sealed class BaseCopierHolder<T> : IBaseCopier<T>, IServiceHolder<IBaseCopier<T>> where T : class\n        {\n            private readonly IDeepCopierProvider _codecProvider;\n            private IBaseCopier<T> _copier;\n\n            public BaseCopierHolder(IDeepCopierProvider codecProvider)\n            {\n                _codecProvider = codecProvider;\n            }\n\n            public void DeepCopy(T original, T copy, CopyContext context) => Value.DeepCopy(original, copy, context);\n\n            public IBaseCopier<T> Value => _copier ??= _codecProvider.GetBaseCopier<T>();\n        }\n    }\n\n    /// <summary>\n    /// Holds a reference to a service.\n    /// </summary>\n    /// <typeparam name=\"T\">The service type.</typeparam>\n    internal interface IServiceHolder<T>\n    {\n        /// <summary>\n        /// Gets the service.\n        /// </summary>\n        /// <value>The service.</value>\n        T Value { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/DotNetSerializableCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Serializer for types which implement the <see cref=\"ISerializable\"/> pattern.\n    /// </summary>\n    [Alias(\"ISerializable\")]\n    public class DotNetSerializableCodec : IGeneralizedCodec\n    {\n        public static readonly Type CodecType = typeof(DotNetSerializableCodec);\n        private static readonly Type SerializableType = typeof(ISerializable);\n        private readonly SerializationCallbacksFactory _serializationCallbacks;\n        private readonly Func<Type, Action<object, SerializationInfo, StreamingContext>> _createConstructorDelegate;\n        private readonly ConcurrentDictionary<Type, Action<object, SerializationInfo, StreamingContext>> _constructors = new();\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n        private readonly IFormatterConverter _formatterConverter;\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n        private readonly StreamingContext _streamingContext;\n        private readonly SerializationEntryCodec _entrySerializer;\n        private readonly TypeConverter _typeConverter;\n        private readonly ValueTypeSerializerFactory _valueTypeSerializerFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DotNetSerializableCodec\"/> class.\n        /// </summary>\n        /// <param name=\"typeResolver\">The type resolver.</param>\n        public DotNetSerializableCodec(TypeConverter typeResolver)\n        {\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            _streamingContext = new StreamingContext(StreamingContextStates.All);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            _typeConverter = typeResolver;\n            _entrySerializer = new SerializationEntryCodec();\n            _serializationCallbacks = new SerializationCallbacksFactory();\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            _formatterConverter = new FormatterConverter();\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            var constructorFactory = new SerializationConstructorFactory();\n            _createConstructorDelegate = constructorFactory.GetSerializationConstructorDelegate;\n\n            _valueTypeSerializerFactory = new ValueTypeSerializerFactory(\n                _entrySerializer,\n                constructorFactory,\n                _serializationCallbacks,\n                _formatterConverter,\n                _streamingContext);\n        }\n\n        /// <inheritdoc />\n        [SecurityCritical]\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            var type = value.GetType();\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, CodecType, WireType.TagDelimited);\n            if (type.IsValueType)\n            {\n                var serializer = _valueTypeSerializerFactory.GetSerializer(type);\n                serializer.WriteValue(ref writer, value);\n            }\n            else\n            {\n                WriteObject(ref writer, type, value);\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc />\n        [SecurityCritical]\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n            {\n                return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            Type type;\n            var header = reader.ReadFieldHeader();\n            if (header.FieldIdDelta == 1)\n            {\n                // This is an exception type, so deserialize it as an exception.\n                var typeName = StringCodec.ReadValue(ref reader, header);\n                if (!_typeConverter.TryParse(typeName, out type))\n                {\n                    return ReadFallbackException(ref reader, typeName, placeholderReferenceId);\n                }\n            }\n            else\n            {\n                type = TypeSerializerCodec.ReadValue(ref reader, header);\n\n                if (type.IsValueType)\n                {\n                    var serializer = _valueTypeSerializerFactory.GetSerializer(type);\n                    return serializer.ReadValue(ref reader, type);\n                }\n            }\n\n            return ReadObject(ref reader, type, placeholderReferenceId);\n        }\n\n        private object ReadFallbackException<TInput>(ref Reader<TInput> reader, string typeName, uint placeholderReferenceId)\n        {\n            // Deserialize into a fallback type for unknown exceptions. This means that missing fields will not be represented.\n            var result = (UnavailableExceptionFallbackException)ReadObject(ref reader, typeof(UnavailableExceptionFallbackException), placeholderReferenceId);\n            result.ExceptionType = typeName;\n            return result;\n        }\n\n        private object ReadObject<TInput>(ref Reader<TInput> reader, Type type, uint placeholderReferenceId)\n        {\n            var callbacks = _serializationCallbacks.GetReferenceTypeCallbacks(type);\n\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(type, _formatterConverter);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            var result = RuntimeHelpers.GetUninitializedObject(type);\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            callbacks.OnDeserializing?.Invoke(result, _streamingContext);\n\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                if (fieldId == 1)\n                {\n                    var entry = _entrySerializer.ReadValue(ref reader, header);\n                    if (entry.ObjectType is { } entryType)\n                    {\n                        info.AddValue(entry.Name, entry.Value, entryType);\n                    }\n                    else\n                    {\n                        info.AddValue(entry.Name, entry.Value);\n                    }\n                }\n                else\n                {\n                    reader.ConsumeUnknownField(header);\n                }\n            }\n\n            var constructor = _constructors.GetOrAdd(info.ObjectType, _createConstructorDelegate);\n            constructor(result, info, _streamingContext);\n            callbacks.OnDeserialized?.Invoke(result, _streamingContext);\n            if (result is IDeserializationCallback callback)\n            {\n                callback.OnDeserialization(_streamingContext.Context);\n            }\n\n            return result;\n        }\n\n        private void WriteObject<TBufferWriter>(ref Writer<TBufferWriter> writer, Type type, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            var callbacks = _serializationCallbacks.GetReferenceTypeCallbacks(type);\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(type, _formatterConverter);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n\n            // Serialize the type name according to the value populated in the SerializationInfo.\n            if (value is Exception)\n            {\n                // For exceptions, the type is serialized as a string to facilitate safe deserialization.\n                var typeName = _typeConverter.Format(info.ObjectType);\n                StringCodec.WriteField(ref writer, 1, typeName);\n            }\n            else\n            {\n                TypeSerializerCodec.WriteField(ref writer, 0, info.ObjectType);\n            }\n\n            callbacks.OnSerializing?.Invoke(value, _streamingContext);\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            ((ISerializable)value).GetObjectData(info, _streamingContext);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n\n            var first = true;\n            foreach (var field in info)\n            {\n                var surrogate = new SerializationEntrySurrogate\n                {\n                    Name = field.Name,\n                    Value = field.Value,\n                    ObjectType = field.ObjectType\n                };\n\n                _entrySerializer.WriteField(ref writer, first ? 1 : (uint)0, typeof(SerializationEntrySurrogate), surrogate);\n                if (first)\n                {\n                    first = false;\n                }\n            }\n\n            callbacks.OnSerialized?.Invoke(value, _streamingContext);\n        }\n\n        /// <inheritdoc />\n        [SecurityCritical]\n        public bool IsSupportedType(Type type) =>\n            type == CodecType || typeof(Exception).IsAssignableFrom(type) || SerializableType.IsAssignableFrom(type) && SerializationConstructorFactory.HasSerializationConstructor(type);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/ExceptionCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.ExceptionServices;\nusing System.Runtime.Serialization;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Exception\"/> types.\n    /// </summary>\n    [RegisterSerializer]\n    [RegisterCopier]\n    [Alias(\"Exception\")]\n    public sealed class ExceptionCodec : IFieldCodec<Exception>, IBaseCodec<Exception>, IGeneralizedCodec, IGeneralizedBaseCodec, IBaseCopier<Exception>\n    {\n        private readonly StreamingContext _streamingContext;\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n        private readonly FormatterConverter _formatterConverter;\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n        private readonly Action<object, SerializationInfo, StreamingContext> _baseExceptionConstructor;\n        private readonly TypeConverter _typeConverter;\n        private readonly IFieldCodec<Dictionary<object, object>> _dictionaryCodec;\n        private readonly IDeepCopier<Dictionary<object, object>> _dictionaryCopier;\n        private readonly IDeepCopier<Exception> _exceptionCopier;\n        private readonly ExceptionSerializationOptions _options;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExceptionCodec\"/> class.\n        /// </summary>\n        /// <param name=\"typeConverter\">The type converter.</param>\n        /// <param name=\"dictionaryCodec\">The dictionary codec.</param>\n        /// <param name=\"dictionaryCopier\">The dictionary copier.</param>\n        /// <param name=\"exceptionCopier\">The exception copier.</param>\n        /// <param name=\"exceptionSerializationOptions\">The exception serialization options.</param>\n        public ExceptionCodec(\n            TypeConverter typeConverter,\n            IFieldCodec<Dictionary<object, object>> dictionaryCodec,\n            IDeepCopier<Dictionary<object, object>> dictionaryCopier,\n            IDeepCopier<Exception> exceptionCopier,\n            IOptions<ExceptionSerializationOptions> exceptionSerializationOptions)\n        {\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            _streamingContext = new StreamingContext(StreamingContextStates.All);\n            _formatterConverter = new FormatterConverter();\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            _baseExceptionConstructor = new SerializationConstructorFactory().GetSerializationConstructorDelegate(typeof(Exception));\n            _typeConverter = typeConverter;\n            _dictionaryCodec = dictionaryCodec;\n            _dictionaryCopier = dictionaryCopier;\n            _exceptionCopier = exceptionCopier;\n            _options = exceptionSerializationOptions.Value;\n        }\n\n        /// <inheritdoc />\n        public void Deserialize<TInput>(ref Reader<TInput> reader, Exception value)\n        {\n            uint fieldId = 0;\n            string message = null;\n            string stackTrace = null;\n            Exception innerException = null;\n            Dictionary<object, object> data = null;\n            int hResult = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        message = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        stackTrace = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        innerException = ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        hResult = Int32Codec.ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        data = _dictionaryCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            SetBaseProperties(value, message, stackTrace, innerException, hResult, data);\n        }\n\n        /// <summary>\n        /// Gets the object data from the provided exception.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>A populated <see cref=\"SerializationInfo\"/> value.</returns>\n        public SerializationInfo GetObjectData(Exception value)\n        {\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(value.GetType(), _formatterConverter);\n#pragma warning disable SYSLIB0051 // Type or member is obsolete\n            value.GetObjectData(info, _streamingContext);\n#pragma warning restore SYSLIB0051 // Type or member is obsolete\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            return info;\n        }\n\n        /// <summary>\n        /// Sets base properties on the provided exception.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"stackTrace\">The stack trace.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        /// <param name=\"hResult\">The HResult.</param>\n        /// <param name=\"data\">The data.</param>\n        public void SetBaseProperties(Exception value, string message, string stackTrace, Exception innerException, int hResult, Dictionary<object, object> data)\n        {\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(typeof(Exception), _formatterConverter);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            info.AddValue(\"Message\", message, typeof(string));\n            info.AddValue(\"StackTraceString\", null, typeof(string));\n            info.AddValue(\"InnerException\", innerException, typeof(Exception));\n            info.AddValue(\"ClassName\", value.GetType().ToString(), typeof(string));\n            info.AddValue(\"Data\", null, typeof(IDictionary));\n            info.AddValue(\"HelpURL\", null, typeof(string));\n#if NET6_0_OR_GREATER\n            info.AddValue(\"RemoteStackTraceString\", null, typeof(string));\n#else\n            info.AddValue(\"RemoteStackTraceString\", stackTrace, typeof(string));\n#endif\n            info.AddValue(\"RemoteStackIndex\", 0, typeof(int));\n            info.AddValue(\"ExceptionMethod\", null, typeof(string));\n            info.AddValue(\"HResult\", hResult);\n            info.AddValue(\"Source\", null, typeof(string));\n            info.AddValue(\"WatsonBuckets\", null, typeof(byte[]));\n\n            _baseExceptionConstructor(value, info, _streamingContext);\n            if (data is { })\n            {\n                foreach (var pair in data)\n                {\n                    value.Data[pair.Key] = pair.Value;\n                }\n            }\n\n#if NET6_0_OR_GREATER\n            if (stackTrace is not null)\n            {\n                ExceptionDispatchInfo.SetRemoteStackTrace(value, stackTrace);\n            }\n#endif\n        }\n\n        /// <summary>\n        /// Gets the data property from the provided exception.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        /// <returns>The provided exception's <see cref=\"Exception.Data\"/> property.</returns>\n        public Dictionary<object, object> GetDataProperty(Exception exception)\n        {\n            if (exception.Data is null or { Count: 0 })\n            {\n                return null;\n            }\n\n            var tmp = new Dictionary<object, object>(exception.Data.Count);\n            var enumerator = exception.Data.GetEnumerator();\n            while (enumerator.MoveNext())\n            {\n                var entry = enumerator.Entry;\n                tmp[entry.Key] = entry.Value;\n            }\n\n            return tmp;\n        }\n\n        /// <inheritdoc />\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, Exception value) where TBufferWriter : IBufferWriter<byte>\n        {\n            StringCodec.WriteField(ref writer, 0, value.Message);\n            StringCodec.WriteField(ref writer, 1, value.StackTrace);\n            WriteField(ref writer, 1, typeof(Exception), value.InnerException);\n            Int32Codec.WriteField(ref writer, 1, value.HResult);\n            if (GetDataProperty(value) is { } dataDictionary)\n            {\n                _dictionaryCodec.WriteField(ref writer, 1, typeof(Dictionary<object, object>), dataDictionary);\n            }\n        }\n\n        /// <inheritdoc />\n        public void SerializeException<TBufferWriter>(ref Writer<TBufferWriter> writer, Exception value) where TBufferWriter : IBufferWriter<byte>\n        {\n            StringCodec.WriteField(ref writer, 0, _typeConverter.Format(value.GetType()));\n            StringCodec.WriteField(ref writer, 1, value.Message);\n            StringCodec.WriteField(ref writer, 1, value.StackTrace);\n            WriteField(ref writer, 1, typeof(Exception), value.InnerException);\n            Int32Codec.WriteField(ref writer, 1, value.HResult);\n            if (GetDataProperty(value) is { } dataDictionary)\n            {\n                _dictionaryCodec.WriteField(ref writer, 1, typeof(Dictionary<object, object>), dataDictionary);\n            }\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Exception value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            if (value.GetType() == typeof(Exception))\n            {\n                // Exceptions are never written as references. This ensures that reference cycles in exceptions are not possible and is a security precaution.\n                ReferenceCodec.MarkValueField(writer.Session);\n                writer.WriteStartObject(fieldIdDelta, expectedType, typeof(ExceptionCodec));\n                SerializeException(ref writer, value);\n                writer.WriteEndObject();\n            }\n            else\n            {\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, value);\n            }\n        }\n\n        /// <inheritdoc />\n        public bool IsSupportedType(Type type)\n        {\n            if (type == typeof(ExceptionCodec))\n            {\n                return true;\n            }\n\n            if (type == typeof(AggregateException))\n            {\n                return false;\n            }\n\n            if (typeof(Exception).IsAssignableFrom(type) && type.Namespace is { } ns)\n            {\n                if (_options.SupportedExceptionTypeFilter is { } filter && filter(type))\n                {\n                    return true;\n                }\n\n                foreach (var prefix in _options.SupportedNamespacePrefixes)\n                {\n                    if (ns.StartsWith(prefix))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc />\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, typeof(ExceptionCodec));\n            SerializeException(ref writer, (Exception)value);\n            writer.WriteEndObject();\n       }\n\n        /// <inheritdoc />\n        public Exception ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            // In order to handle null values.\n            if (field.WireType == WireType.Reference)\n            {\n                var referencedException = ReferenceCodec.ReadReference<Exception, TInput>(ref reader, field);\n\n                // We do not allow exceptions to participate in reference cycles because cycles involving InnerException are not allowed by .NET\n                // Exceptions must never form cyclic graphs via their well-known properties/fields (eg, InnerException).\n                if (referencedException is not null)\n                {\n                    throw new ReferenceFieldNotSupportedException(field.FieldType);\n                }\n\n                return null;\n            }\n\n            Type valueType = field.FieldType;\n            if (valueType is null || valueType == typeof(Exception))\n            {\n                return DeserializeException(ref reader, field);\n            }\n\n            return reader.DeserializeUnexpectedType<TInput, Exception>(ref field);\n        }\n\n        /// <inheritdoc />\n        object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<Exception, TInput>(ref reader, field);\n            }\n\n            return DeserializeException(ref reader, field);\n        }\n\n        public Exception DeserializeException<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n\n            uint fieldId = 0;\n            string typeName = null;\n            string message = null;\n            string stackTrace = null;\n            Exception innerException = null;\n            Dictionary<object, object> data = null;\n            int hResult = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        typeName = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        message = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        stackTrace = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 3:\n                        innerException = ReadValue(ref reader, header);\n                        break;\n                    case 4:\n                        hResult = Int32Codec.ReadValue(ref reader, header);\n                        break;\n                    case 5:\n                        data = _dictionaryCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            Exception result;\n            if (!_typeConverter.TryParse(typeName, out var type))\n            {\n                result = new UnavailableExceptionFallbackException\n                {\n                    ExceptionType = typeName\n                };\n            }\n            else if (typeof(Exception).IsAssignableFrom(type))\n            {\n                try\n                {\n                    if (type.GetConstructor(Array.Empty<Type>()) is not null)\n                    {\n                        result = (Exception)Activator.CreateInstance(type);\n                    }\n                    else\n                    {\n                        result = (Exception)RuntimeHelpers.GetUninitializedObject(type);\n                    }\n                }\n                catch (Exception constructorException)\n                {\n                    result = new UnavailableExceptionFallbackException($\"Failed to construct exception of type \\\"{type}\\\"\", constructorException)\n                    {\n                        ExceptionType = typeName\n                    };\n                }\n            }\n            else\n            {\n                throw new NotSupportedException($\"Type {type} is not supported\");\n            }\n\n            SetBaseProperties(result, message, stackTrace, innerException, hResult, data);\n            return result;\n        }\n\n        /// <inheritdoc />\n        public void DeepCopy(Exception input, Exception output, CopyContext context)\n        {\n            var info = GetObjectData(input);\n            SetBaseProperties(\n                output,\n                // Get the message from object data in case the property is overridden as it is with AggregateException\n                info.GetString(\"Message\"),\n                input.StackTrace,\n                _exceptionCopier.DeepCopy(input.InnerException, context),\n                input.HResult,\n                _dictionaryCopier.DeepCopy(GetDataProperty(input), context));\n        }\n\n        /// <inheritdoc />\n        public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, object value) where TBufferWriter : IBufferWriter<byte> => Serialize(ref writer, (Exception)value);\n\n        /// <inheritdoc />\n        public void Deserialize<TInput>(ref Reader<TInput> reader, object value) => Deserialize(ref reader, (Exception)value);\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"AggregateException\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    internal sealed class AggregateExceptionCodec : GeneralizedReferenceTypeSurrogateCodec<AggregateException, AggregateExceptionSurrogate>\n    {\n        private readonly ExceptionCodec _baseCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AggregateExceptionCodec\"/> class.\n        /// </summary>\n        /// <param name=\"baseCodec\">The base codec.</param>\n        /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n        public AggregateExceptionCodec(ExceptionCodec baseCodec, IValueSerializer<AggregateExceptionSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n            _baseCodec = baseCodec;\n        }\n\n        /// <inheritdoc/>\n        public override AggregateException ConvertFromSurrogate(ref AggregateExceptionSurrogate surrogate)\n        {\n            var result = new AggregateException(surrogate.InnerExceptions);\n            var innerException = surrogate.InnerExceptions is { Count: > 0 } innerExceptions ? innerExceptions[0] : null;\n            _baseCodec.SetBaseProperties(result, surrogate.Message, surrogate.StackTrace, innerException, surrogate.HResult, surrogate.Data);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public override void ConvertToSurrogate(AggregateException value, ref AggregateExceptionSurrogate surrogate)\n        {\n            var info = _baseCodec.GetObjectData(value);\n            surrogate.Message = info.GetString(\"Message\");\n            surrogate.StackTrace = value.StackTrace;\n            surrogate.HResult = value.HResult;\n            var data = info.GetValue(\"Data\", typeof(IDictionary));\n            if (data is { })\n            {\n                surrogate.Data = _baseCodec.GetDataProperty(value);\n            }\n\n            surrogate.InnerExceptions = value.InnerExceptions;\n        }\n    }\n\n    /// <summary>\n    /// Surrogate type for <see cref=\"AggregateExceptionCodec\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    internal struct AggregateExceptionSurrogate\n    {\n        [Id(0)]\n        public string Message;\n\n        [Id(1)]\n        public string StackTrace;\n\n        [Id(2)]\n        public Dictionary<object, object> Data;\n\n        [Id(3)]\n        public int HResult;\n\n        [Id(4)]\n        public ReadOnlyCollection<Exception> InnerExceptions;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/ExceptionSerializationOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Options for exception serialization.\n    /// </summary>\n    public class ExceptionSerializationOptions\n    {\n        /// <summary>\n        /// Gets the collection of supported namespace prefixes for the exception serializer.\n        /// Any exception type which has a namespace with one of these prefixes will be serialized using the exception serializer.\n        /// </summary>\n        public HashSet<string> SupportedNamespacePrefixes { get; } = new HashSet<string>(StringComparer.Ordinal) { \"Microsoft\", \"System\", \"Azure\" };\n\n        /// <summary>\n        /// Gets or sets the predicate used to enable serialization for an exception type.\n        /// </summary>\n        public Func<Type, bool> SupportedExceptionTypeFilter { get; set; } = _ => false;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/SerializationCallbacksFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Creates delegates for calling methods marked with serialization attributes.\n    /// </summary>\n    internal sealed class SerializationCallbacksFactory\n    {\n        private readonly ConcurrentDictionary<Type, object> _cache = new();\n        private readonly Func<Type, object> _factory = t => CreateTypedCallbacks<Action<object, StreamingContext>>(t, typeof(object));\n\n        /// <summary>\n        /// Gets serialization callbacks for reference types.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>Serialization callbacks.</returns>\n        [SecurityCritical]\n        public SerializationCallbacks<Action<object, StreamingContext>> GetReferenceTypeCallbacks(Type type) => (\n            SerializationCallbacks<Action<object, StreamingContext>>)_cache.GetOrAdd(type, _factory);\n\n        /// <summary>\n        /// Gets serialization callbacks for value types.\n        /// </summary>\n        /// <typeparam name=\"TOwner\">The declaring type.</typeparam>\n        /// <typeparam name=\"TDelegate\">The delegate type.</typeparam>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>Serialization callbacks.</returns>\n        [SecurityCritical]\n        public SerializationCallbacks<TDelegate> GetValueTypeCallbacks<TOwner, TDelegate>(Type type) where TOwner : struct where TDelegate : Delegate\n            => GetValueTypeCallbacks<TDelegate>(type, typeof(TOwner));\n\n        private SerializationCallbacks<TDelegate> GetValueTypeCallbacks<TDelegate>(Type type, Type owner) where TDelegate : Delegate\n            => (SerializationCallbacks<TDelegate>)_cache.GetOrAdd(type, CreateTypedCallbacks<TDelegate>, owner);\n\n        [SecurityCritical]\n        private static SerializationCallbacks<TDelegate> CreateTypedCallbacks<TDelegate>(Type type, Type owner) where TDelegate : Delegate\n        {\n            var onDeserializing = default(TDelegate);\n            var onDeserialized = default(TDelegate);\n            var onSerializing = default(TDelegate);\n            var onSerialized = default(TDelegate);\n            foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))\n            {\n                var parameterInfos = method.GetParameters();\n                if (parameterInfos.Length != 1)\n                {\n                    continue;\n                }\n\n                if (parameterInfos[0].ParameterType != typeof(StreamingContext))\n                {\n                    continue;\n                }\n\n                if (method.IsDefined(typeof(OnDeserializingAttribute), false))\n                {\n                    onDeserializing = (TDelegate)GetSerializationMethod(type, method, owner).CreateDelegate(typeof(TDelegate));\n                }\n\n                if (method.IsDefined(typeof(OnDeserializedAttribute), false))\n                {\n                    onDeserialized = (TDelegate)GetSerializationMethod(type, method, owner).CreateDelegate(typeof(TDelegate));\n                }\n\n                if (method.IsDefined(typeof(OnSerializingAttribute), false))\n                {\n                    onSerializing = (TDelegate)GetSerializationMethod(type, method, owner).CreateDelegate(typeof(TDelegate));\n                }\n\n                if (method.IsDefined(typeof(OnSerializedAttribute), false))\n                {\n                    onSerialized = (TDelegate)GetSerializationMethod(type, method, owner).CreateDelegate(typeof(TDelegate));\n                }\n            }\n\n            return new SerializationCallbacks<TDelegate>(onDeserializing, onDeserialized, onSerializing, onSerialized);\n        }\n\n        [SecurityCritical]\n        private static DynamicMethod GetSerializationMethod(Type type, MethodInfo callbackMethod, Type owner)\n        {\n            Type[] callbackParameterTypes;\n            if (owner.IsValueType)\n            {\n                callbackParameterTypes = new[] { typeof(object), owner.MakeByRefType(), typeof(StreamingContext) };\n            }\n            else\n            {\n                callbackParameterTypes = new[] { typeof(object), typeof(object), typeof(StreamingContext) };\n            }\n\n            var method = new DynamicMethod($\"{callbackMethod.Name}_Trampoline\", null, callbackParameterTypes, type, skipVisibility: true);\n            var il = method.GetILGenerator();\n\n            // arg0 is unused for better delegate performance (avoids argument shuffling thunk)\n            il.Emit(OpCodes.Ldarg_1);\n            if (type != owner)\n            {\n                il.Emit(OpCodes.Castclass, type);\n            }\n\n            il.Emit(OpCodes.Ldarg_2);\n            il.Emit(OpCodes.Callvirt, callbackMethod);\n            il.Emit(OpCodes.Ret);\n\n            return method;\n        }\n\n        /// <summary>\n        /// Serialization callbacks.\n        /// </summary>\n        /// <typeparam name=\"TDelegate\">The delegate type for each callback.</typeparam>\n        public sealed class SerializationCallbacks<TDelegate>\n        {\n            /// <summary>\n            /// Initializes a new instance of the <see cref=\"SerializationCallbacks{TDelegate}\"/> class.\n            /// </summary>\n            /// <param name=\"onDeserializing\">The callback invoked during deserialization.</param>\n            /// <param name=\"onDeserialized\">The callback invoked once a value is deserialized.</param>\n            /// <param name=\"onSerializing\">The callback invoked during serialization.</param>\n            /// <param name=\"onSerialized\">The callback invoked once a value is serialized.</param>\n            public SerializationCallbacks(\n                TDelegate onDeserializing,\n                TDelegate onDeserialized,\n                TDelegate onSerializing,\n                TDelegate onSerialized)\n            {\n                OnDeserializing = onDeserializing;\n                OnDeserialized = onDeserialized;\n                OnSerializing = onSerializing;\n                OnSerialized = onSerialized;\n            }\n\n            /// <summary>\n            /// Gets the callback invoked while deserializing.\n            /// </summary>\n            public readonly TDelegate OnDeserializing;\n\n            /// <summary>\n            /// Gets the callback invoked once a value has been deserialized.\n            /// </summary>\n            public readonly TDelegate OnDeserialized;\n\n            /// <summary>\n            /// Gets the callback invoked during serialization.\n            /// </summary>\n            /// <value>The on serializing.</value>\n            public readonly TDelegate OnSerializing;\n\n            /// <summary>\n            /// Gets the callback invoked once a value has been serialized.\n            /// </summary>\n            public readonly TDelegate OnSerialized;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/SerializationConstructorFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Creates delegates for calling ISerializable-conformant constructors.\n    /// </summary>\n    internal sealed class SerializationConstructorFactory\n    {\n        private static readonly Type[] SerializationConstructorParameterTypes = { typeof(SerializationInfo), typeof(StreamingContext) };\n        private readonly Func<Type, object> _createConstructorDelegate = t => GetSerializationConstructorInvoker(t, typeof(object), typeof(Action<object, SerializationInfo, StreamingContext>));\n        private readonly ConcurrentDictionary<Type, object> _constructors = new();\n\n        /// <summary>\n        /// Determines whether the provided type has a serialization constructor.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the provided type has a serialization constructor; otherwise, <see langword=\"false\" />.</returns>\n        [SecurityCritical]\n        public static bool HasSerializationConstructor(Type type) => GetSerializationConstructor(type) != null;\n\n        [SecurityCritical]\n        public Action<object, SerializationInfo, StreamingContext> GetSerializationConstructorDelegate(Type type)\n            => (Action<object, SerializationInfo, StreamingContext>)_constructors.GetOrAdd(type, _createConstructorDelegate);\n\n        [SecurityCritical]\n        public TConstructor GetSerializationConstructorDelegate<TOwner, TConstructor>() where TConstructor : Delegate\n            => (TConstructor)GetSerializationConstructorDelegate(typeof(TOwner), typeof(TConstructor));\n\n        private object GetSerializationConstructorDelegate(Type owner, Type delegateType)\n            => _constructors.GetOrAdd(owner, (t, d) => GetSerializationConstructorInvoker(t, t, d), delegateType);\n\n        [SecurityCritical]\n        private static ConstructorInfo GetSerializationConstructor(Type type) => type.GetConstructor(\n                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,\n                null,\n                SerializationConstructorParameterTypes,\n                null);\n\n        [SecurityCritical]\n        private static Delegate GetSerializationConstructorInvoker(Type type, Type owner, Type delegateType)\n        {\n            var constructor = GetSerializationConstructor(type) ?? (typeof(Exception).IsAssignableFrom(type) ? GetSerializationConstructor(typeof(Exception)) : null);\n            if (constructor is null)\n            {\n                throw new SerializationException($\"{nameof(ISerializable)} constructor not found on type {type}.\");\n            }\n\n            Type[] parameterTypes;\n            if (owner.IsValueType)\n            {\n                parameterTypes = new[] { typeof(object), owner.MakeByRefType(), typeof(SerializationInfo), typeof(StreamingContext) };\n            }\n            else\n            {\n                parameterTypes = new[] { typeof(object), typeof(object), typeof(SerializationInfo), typeof(StreamingContext) };\n            }\n\n            var method = new DynamicMethod($\"{type}_serialization_ctor\", null, parameterTypes, type, skipVisibility: true);\n            var il = method.GetILGenerator();\n\n            // arg0 is unused for better delegate performance (avoids argument shuffling thunk)\n            il.Emit(OpCodes.Ldarg_1);\n            if (type != owner)\n            {\n                il.Emit(OpCodes.Castclass, type);\n            }\n\n            il.Emit(OpCodes.Ldarg_2);\n            il.Emit(OpCodes.Ldarg_3);\n            il.Emit(OpCodes.Call, constructor);\n            il.Emit(OpCodes.Ret);\n\n            return method.CreateDelegate(delegateType);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/SerializationConstructorNotFoundException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Thrown when a type has no serialization constructor.\n    /// </summary>\n    [Serializable]\n    public class SerializationConstructorNotFoundException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializationConstructorNotFoundException\"/> class.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        [SecurityCritical]\n        public SerializationConstructorNotFoundException(Type type) : base(\n            (string)$\"Could not find a suitable serialization constructor on type {type.FullName}\")\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializationConstructorNotFoundException\" /> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization information.</param>\n        /// <param name=\"context\">The context.</param>\n        [SecurityCritical]\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        protected SerializationConstructorNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/SerializationEntryCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    internal sealed class SerializationEntryCodec : IFieldCodec<SerializationEntrySurrogate>\n    {\n        [SecurityCritical]\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer,\n            uint fieldIdDelta,\n            Type expectedType,\n            SerializationEntrySurrogate value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(SerializationEntrySurrogate), WireType.TagDelimited);\n            StringCodec.WriteField(ref writer, 0, value.Name);\n            ObjectCodec.WriteField(ref writer, 1, value.Value);\n            if (value.ObjectType is { } objectType)\n            {\n                TypeSerializerCodec.WriteField(ref writer, 1, objectType);\n            }\n\n            writer.WriteEndObject();\n        }\n\n        [SecurityCritical]\n        public SerializationEntrySurrogate ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            var result = new SerializationEntrySurrogate();\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        result.Name = StringCodec.ReadValue(ref reader, header);\n                        break;\n                    case 1:\n                        result.Value = ObjectCodec.ReadValue(ref reader, header);\n                        break;\n                    case 2:\n                        result.ObjectType = TypeSerializerCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/SerializationEntrySurrogate.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization\n{\n    [GenerateSerializer]\n    internal struct SerializationEntrySurrogate\n    {\n        [Id(0)]\n        public string Name;\n\n        [Id(1)]\n        public object Value;\n\n        [Id(2)]\n        public Type ObjectType;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/UnavailableExceptionFallbackException.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Represents an exception which has a type which is unavailable during deserialization.\n    /// </summary>\n    [DebuggerDisplay(\"{\" + nameof(GetDebuggerDisplay) + \"(),nq}\")]\n    public sealed class UnavailableExceptionFallbackException : Exception\n    {\n        /// <inheritdoc />\n        public UnavailableExceptionFallbackException()\n        {\n        }\n\n        /// <inheritdoc />\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public UnavailableExceptionFallbackException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n            foreach (var pair in info)\n            {\n                Properties[pair.Name] = pair.Value;\n            }\n        }\n\n        /// <inheritdoc />\n        public UnavailableExceptionFallbackException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Gets the serialized properties of the exception.\n        /// </summary>\n        public Dictionary<string, object> Properties { get; } = new();\n\n        /// <summary>\n        /// Gets the exception type name.\n        /// </summary>\n        public string ExceptionType { get; internal set; }\n\n        /// <inheritdoc />\n        public override string ToString() => string.IsNullOrWhiteSpace(ExceptionType) ? $\"Unknown exception: {base.ToString()}\" : $\"Unknown exception of type {ExceptionType}: {base.ToString()}\";\n\n        private string GetDebuggerDisplay() => ToString();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/ValueTypeSerializer.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing System;\nusing System.Buffers;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    internal abstract class ValueTypeSerializer\n    {\n        public abstract void WriteValue<TBufferWriter>(ref Writer<TBufferWriter> writer, object value) where TBufferWriter : IBufferWriter<byte>;\n        public abstract object ReadValue<TInput>(ref Reader<TInput> reader, Type type);\n    }\n\n    /// <summary>\n    /// Serializer for ISerializable value types.\n    /// </summary>\n    /// <typeparam name=\"T\">The type which this serializer can serialize.</typeparam>\n    internal class ValueTypeSerializer<T> : ValueTypeSerializer where T : struct\n    {\n        public delegate void ValueConstructor(ref T value, SerializationInfo info, StreamingContext context);\n\n        public delegate void SerializationCallback(ref T value, StreamingContext context);\n\n        private static readonly Type Type = typeof(T);\n\n        private readonly ValueConstructor _constructor;\n        private readonly SerializationCallbacksFactory.SerializationCallbacks<SerializationCallback> _callbacks;\n\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n        private readonly IFormatterConverter _formatterConverter;\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n        private readonly StreamingContext _streamingContext;\n        private readonly SerializationEntryCodec _entrySerializer;\n\n        [SecurityCritical]\n        public ValueTypeSerializer(\n            ValueConstructor constructor,\n            SerializationCallbacksFactory.SerializationCallbacks<SerializationCallback> callbacks,\n            SerializationEntryCodec entrySerializer,\n            StreamingContext streamingContext,\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            IFormatterConverter formatterConverter)\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n        {\n            _constructor = constructor;\n            _callbacks = callbacks;\n            _entrySerializer = entrySerializer;\n            _streamingContext = streamingContext;\n            _formatterConverter = formatterConverter;\n        }\n\n        [SecurityCritical]\n        public override void WriteValue<TBufferWriter>(ref Writer<TBufferWriter> writer, object value)\n        {\n            var item = (T)value;\n            _callbacks.OnSerializing?.Invoke(ref item, _streamingContext);\n\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(Type, _formatterConverter);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            ((ISerializable)value).GetObjectData(info, _streamingContext);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n\n            TypeSerializerCodec.WriteField(ref writer, 0, info.ObjectType);\n\n            var first = true;\n            foreach (var field in info)\n            {\n                var surrogate = new SerializationEntrySurrogate\n                {\n                    Name = field.Name,\n                    Value = field.Value,\n                    ObjectType = field.ObjectType\n                };\n\n                _entrySerializer.WriteField(ref writer, first ? 1 : (uint)0, typeof(SerializationEntrySurrogate), surrogate);\n                if (first)\n                {\n                    first = false;\n                }\n            }\n\n            _callbacks.OnSerialized?.Invoke(ref item, _streamingContext);\n        }\n\n        [SecurityCritical]\n        public override object ReadValue<TInput>(ref Reader<TInput> reader, Type type)\n        {\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            var info = new SerializationInfo(Type, _formatterConverter);\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            T result = default;\n\n            _callbacks.OnDeserializing?.Invoke(ref result, _streamingContext);\n\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                if (fieldId == 1)\n                {\n                    var entry = _entrySerializer.ReadValue(ref reader, header);\n                    if (entry.ObjectType is { } entryType)\n                    {\n                        info.AddValue(entry.Name, entry.Value, entryType);\n                    }\n                    else\n                    {\n                        info.AddValue(entry.Name, entry.Value);\n                    }\n                }\n                else\n                {\n                    reader.ConsumeUnknownField(header);\n                }\n            }\n\n            _constructor(ref result, info, _streamingContext);\n            _callbacks.OnDeserialized?.Invoke(ref result, _streamingContext);\n            if (result is IDeserializationCallback callback)\n            {\n                callback.OnDeserialization(_streamingContext.Context);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/ISerializableSerializer/ValueTypeSerializerFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing System.Security;\n\nnamespace Orleans.Serialization\n{\n    internal class ValueTypeSerializerFactory\n    {\n        private readonly SerializationConstructorFactory _constructorFactory;\n        private readonly SerializationCallbacksFactory _callbacksFactory;\n        private readonly SerializationEntryCodec _entrySerializer;\n        private readonly StreamingContext _streamingContext;\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n        private readonly IFormatterConverter _formatterConverter;\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n        private readonly Func<Type, ValueTypeSerializer> _createSerializerDelegate;\n\n        private readonly ConcurrentDictionary<Type, ValueTypeSerializer> _serializers = new();\n\n        private readonly MethodInfo _createTypedSerializerMethodInfo = typeof(ValueTypeSerializerFactory).GetMethod(\n            nameof(CreateTypedSerializer),\n            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n\n        [SecurityCritical]\n        public ValueTypeSerializerFactory(\n            SerializationEntryCodec entrySerializer,\n            SerializationConstructorFactory constructorFactory,\n            SerializationCallbacksFactory callbacksFactory,\n#pragma warning disable SYSLIB0050 // Type or member is obsolete\n            IFormatterConverter formatterConverter,\n#pragma warning restore SYSLIB0050 // Type or member is obsolete\n            StreamingContext streamingContext)\n        {\n            _constructorFactory = constructorFactory;\n            _callbacksFactory = callbacksFactory;\n            _entrySerializer = entrySerializer;\n            _streamingContext = streamingContext;\n            _formatterConverter = formatterConverter;\n            _createSerializerDelegate = type => (ValueTypeSerializer)_createTypedSerializerMethodInfo.MakeGenericMethod(type).Invoke(this, null);\n        }\n\n        [SecurityCritical]\n        public ValueTypeSerializer GetSerializer(Type type) => _serializers.GetOrAdd(type, _createSerializerDelegate);\n\n        [SecurityCritical]\n        private ValueTypeSerializer CreateTypedSerializer<T>() where T : struct\n        {\n            var constructor = _constructorFactory.GetSerializationConstructorDelegate<T, ValueTypeSerializer<T>.ValueConstructor>();\n            var callbacks =\n                _callbacksFactory.GetValueTypeCallbacks<T, ValueTypeSerializer<T>.SerializationCallback>(typeof(T));\n            var serializer = new ValueTypeSerializer<T>(constructor, callbacks, _entrySerializer, _streamingContext, _formatterConverter);\n            return serializer;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/IInvokable.cs",
    "content": "#nullable enable\nusing System;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Represents an object which can be invoked asynchronously.\n    /// </summary>\n    public interface IInvokable : IDisposable\n    {\n        /// <summary>\n        /// Gets the invocation target.\n        /// </summary>\n        /// <returns>The invocation target.</returns>\n        object? GetTarget();\n\n        /// <summary>\n        /// Sets the invocation target from an instance of <see cref=\"ITargetHolder\"/>.\n        /// </summary>\n        /// <param name=\"holder\">The invocation target.</param>\n        void SetTarget(ITargetHolder holder);\n\n        /// <summary>\n        /// Invoke the object.\n        /// </summary>\n        ValueTask<Response> Invoke();\n\n        /// <summary>\n        /// Gets the number of arguments.\n        /// </summary>\n        int GetArgumentCount();\n\n        /// <summary>\n        /// Gets the argument at the specified index.\n        /// </summary>\n        /// <param name=\"index\">The argument index.</param>\n        /// <returns>The argument at the specified index.</returns>\n        object? GetArgument(int index);\n\n        /// <summary>\n        /// Sets the argument at the specified index.\n        /// </summary>\n        /// <param name=\"index\">The argument index.</param>\n        /// <param name=\"value\">The argument value</param>\n        void SetArgument(int index, object value);\n\n        /// <summary>\n        /// Gets the method name.\n        /// </summary>\n        string GetMethodName();\n\n        /// <summary>\n        /// Gets the full interface name.\n        /// </summary>\n        string GetInterfaceName();\n\n        /// <summary>\n        /// Gets the activity name, which refers to both the interface name and method name.\n        /// </summary>\n        string GetActivityName();\n\n        /// <summary>\n        /// Gets the method info object, which may be <see langword=\"null\"/>.\n        /// </summary>\n        MethodInfo GetMethod();\n\n        /// <summary>\n        /// Gets the interface type.\n        /// </summary>\n        Type GetInterfaceType();\n\n        /// <summary>\n        /// Gets the default response timeout.\n        /// </summary>\n        TimeSpan? GetDefaultResponseTimeout() => default;\n\n        /// <summary>\n        /// Gets the cancellation token for this request. If the request does not accept a cancellation token, this will be <see cref=\"CancellationToken.None\"/>.\n        /// </summary>\n        /// <returns>The cancellation token for this request.</returns>\n        CancellationToken GetCancellationToken() => default;\n\n        /// <summary>\n        /// Tries to cancel the invocation.\n        /// </summary>\n        /// <remarks>This is only valid after <see cref=\"SetTarget(ITargetHolder)\"/> has been called, and only has an effect for requests which support cancellation.</remarks>\n        /// <returns><see langword=\"true\"/> if cancellation was requested, otherwise <see langword=\"false\"/>.</returns>\n        bool TryCancel() => false;\n\n        /// <summary>\n        /// <see langword=\"true\"/> if this request supports cancellation; <see langword=\"false\"/> otherwise.\n        /// </summary>\n        bool IsCancellable => false;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/IResponseCompletionSource.cs",
    "content": "namespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Represents a fulfillable promise for a response to a request.\n    /// </summary>\n    public interface IResponseCompletionSource\n    {\n        /// <summary>\n        /// Sets the result.\n        /// </summary>\n        /// <param name=\"value\">The result value.</param>\n        void Complete(Response value);\n\n        /// <summary>\n        /// Sets the result to the default value.\n        /// </summary>\n        void Complete(); \n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/ITargetHolder.cs",
    "content": "#nullable enable\nusing System;\n\nnamespace Orleans.Serialization.Invocation;\n\n/// <summary>\n/// Represents an object which holds an invocation target as well as target extensions.\n/// </summary>\npublic interface ITargetHolder\n{\n    /// <summary>\n    /// Gets the target instance.\n    /// </summary>\n    /// <returns>The target.</returns>\n    object? GetTarget();\n\n    /// <summary>\n    /// Gets the component with the specified type.\n    /// </summary>\n    /// <param name=\"componentType\">The component type.</param>\n    /// <returns>The component with the specified type.</returns>\n    object? GetComponent(Type componentType);\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Pools/ConcurrentObjectPool.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading;\nusing Microsoft.Extensions.ObjectPool;\n\nnamespace Orleans.Serialization.Invocation\n{\n    internal sealed class ConcurrentObjectPool<T> : ConcurrentObjectPool<T, DefaultConcurrentObjectPoolPolicy<T>> where T : class, new()\n    {\n        public ConcurrentObjectPool() : base(new())\n        {\n        }\n    }\n\n    internal class ConcurrentObjectPool<T, TPoolPolicy> : ObjectPool<T> where T : class where TPoolPolicy : IPooledObjectPolicy<T>\n    {\n        private readonly ThreadLocal<Stack<T>> _objects = new(() => new());\n\n        private readonly TPoolPolicy _policy;\n\n        public ConcurrentObjectPool(TPoolPolicy policy) => _policy = policy;\n\n        public int MaxPoolSize { get; set; } = int.MaxValue;\n\n        public override T Get()\n        {\n            var stack = _objects.Value;\n            if (stack.TryPop(out var result))\n            {\n                return result;\n            }\n\n            return _policy.Create();\n        }\n\n        public override void Return(T obj)\n        {\n            if (_policy.Return(obj))\n            {\n                var stack = _objects.Value;\n                if (stack.Count < MaxPoolSize)\n                {\n                    stack.Push(obj);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Pools/DefaultConcurrentObjectPoolPolicy.cs",
    "content": "using Microsoft.Extensions.ObjectPool;\n\nnamespace Orleans.Serialization.Invocation\n{\n    internal readonly struct DefaultConcurrentObjectPoolPolicy<T> : IPooledObjectPolicy<T> where T : class, new()\n    {\n        public T Create() => new();\n\n        public bool Return(T obj) => true;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Pools/InvokablePool.cs",
    "content": "namespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Object pool for <see cref=\"IInvokable\"/> implementations.\n    /// </summary>\n    public static class InvokablePool\n    {\n        /// <summary>\n        /// Gets a value from the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the value.</typeparam>\n        /// <returns>A value from the pool.</returns>\n        public static T Get<T>() where T : class, IInvokable, new() => TypedPool<T>.Pool.Get();\n\n        /// <summary>\n        /// Returns a value to the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the value.</typeparam>\n        /// <param name=\"obj\">The value to return.</param>\n        public static void Return<T>(T obj) where T : class, IInvokable, new() => TypedPool<T>.Pool.Return(obj);\n\n        private static class TypedPool<T> where T : class, IInvokable, new()\n        {\n            public static readonly ConcurrentObjectPool<T> Pool = new();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Pools/ResponseCompletionSourcePool.cs",
    "content": "namespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Object pool for <see cref=\"ResponseCompletionSource\"/> and <see cref=\"ResponseCompletionSource{TResult}\"/>.\n    /// </summary>\n    public static class ResponseCompletionSourcePool\n    {\n        internal static readonly ConcurrentObjectPool<ResponseCompletionSource, DefaultConcurrentObjectPoolPolicy<ResponseCompletionSource>> UntypedPool = new(new());\n\n        /// <summary>\n        /// Gets a value from the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying result type.</typeparam>\n        /// <returns>A value from the pool.</returns>\n        public static ResponseCompletionSource<T> Get<T>() => TypedPool<T>.Pool.Get();\n\n        /// <summary>\n        /// Returns a value to the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying result type.</typeparam>\n        /// <param name=\"obj\">The value to return to the pool</param>\n        public static void Return<T>(ResponseCompletionSource<T> obj) => TypedPool<T>.Pool.Return(obj);\n\n        /// <summary>\n        /// Gets a value from the pool.\n        /// </summary>\n        /// <returns>A value from the pool.</returns>\n        public static ResponseCompletionSource Get() => UntypedPool.Get();\n\n        /// <summary>\n        /// Returns a value to the pool.\n        /// </summary>\n        /// <param name=\"obj\">The value to return to the pool</param>\n        public static void Return(ResponseCompletionSource obj) => UntypedPool.Return(obj);\n\n        private static class TypedPool<T>\n        {\n            public static readonly ConcurrentObjectPool<ResponseCompletionSource<T>, DefaultConcurrentObjectPoolPolicy<ResponseCompletionSource<T>>> Pool = new(new());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Pools/ResponsePool.cs",
    "content": "namespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Object pool for <see cref=\"Response{TResult}\"/> values.\n    /// </summary>\n    public static class ResponsePool\n    {\n        /// <summary>\n        /// Gets a value from the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying response type.</typeparam>\n        /// <returns>A value from the pool.</returns>\n        public static Response<T> Get<T>() => TypedPool<T>.Pool.Get();\n\n        /// <summary>\n        /// Returns a value to the pool.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying response type.</typeparam>\n        /// <param name=\"obj\">The value to return to the pool.</param>\n        public static void Return<T>(Response<T> obj) => TypedPool<T>.Pool.Return(obj);\n\n        private static class TypedPool<T>\n        {\n            public static readonly ConcurrentObjectPool<Response<T>> Pool = new();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/Response.cs",
    "content": "#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.ExceptionServices;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// Represents the result of a method invocation.\n    /// </summary>\n    [SerializerTransparent]\n    public abstract class Response : IDisposable\n    {\n        /// <summary>\n        /// Creates a new response representing an exception.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        /// <returns>A new response.</returns>\n        public static Response FromException(Exception exception) => new ExceptionResponse { Exception = exception };\n\n        /// <summary>\n        /// Creates a new response object which has been fulfilled with the provided value.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The underlying result type.</typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>A new response.</returns>\n        public static Response FromResult<TResult>(TResult value)\n        {\n            var result = ResponsePool.Get<TResult>();\n            result.TypedResult = value;\n            return result;\n        }\n\n        /// <summary>\n        /// Gets a completed response.\n        /// </summary>\n        public static Response Completed => CompletedResponse.Instance;\n\n        /// <inheritdoc />\n        public abstract object? Result { get; set; }\n\n        public virtual Type? GetSimpleResultType() => null;\n\n        /// <inheritdoc />\n        public abstract Exception? Exception { get; set; }\n\n        /// <inheritdoc />\n        public abstract T GetResult<T>();\n\n        /// <inheritdoc />\n        public abstract void Dispose();\n\n        /// <inheritdoc />\n        public override string ToString() => Exception is { } ex ? ex.ToString() : Result?.ToString() ?? \"[null]\";\n    }\n\n    /// <summary>\n    /// Represents a completed <see cref=\"Response\"/>.\n    /// </summary>\n    [GenerateSerializer, Immutable, UseActivator, SuppressReferenceTracking]\n    public sealed class CompletedResponse : Response\n    {\n        /// <summary>\n        /// Gets the singleton instance of this class.\n        /// </summary>\n        public static CompletedResponse Instance { get; } = new CompletedResponse();\n\n        /// <inheritdoc/>\n        public override object? Result { get => null; set => throw new InvalidOperationException($\"Type {nameof(CompletedResponse)} is read-only\"); }\n\n        /// <inheritdoc/>\n        public override Exception? Exception { get => null; set => throw new InvalidOperationException($\"Type {nameof(CompletedResponse)} is read-only\"); }\n\n        /// <inheritdoc/>\n        public override T GetResult<T>() => default!;\n\n        /// <inheritdoc/>\n        public override void Dispose() { }\n\n        /// <inheritdoc/>\n        public override string ToString() => \"[Completed]\";\n    }\n\n    /// <summary>\n    /// Activator for <see cref=\"CompletedResponse\"/>.\n    /// </summary>\n    [RegisterActivator]\n    internal sealed class CompletedResponseActivator : IActivator<CompletedResponse>\n    {\n        /// <inheritdoc/>\n        public CompletedResponse Create() => CompletedResponse.Instance;\n    }\n\n    /// <summary>\n    /// A <see cref=\"Response\"/> which represents an exception, a broken promise.\n    /// </summary>\n    [GenerateSerializer, Immutable]\n    public sealed class ExceptionResponse : Response\n    {\n        /// <inheritdoc/>\n        public override object? Result\n        {\n            get\n            {\n                ExceptionDispatchInfo.Capture(Exception!).Throw();\n                return null;\n            }\n\n            set => throw new InvalidOperationException($\"Cannot set result property on response of type {nameof(ExceptionResponse)}\");\n        }\n\n        /// <inheritdoc/>\n        [Id(0)]\n        public override Exception? Exception { get; set; }\n\n        /// <inheritdoc/>\n        public override T GetResult<T>()\n        {\n            ExceptionDispatchInfo.Capture(Exception!).Throw();\n            return default;\n        }\n\n        /// <inheritdoc/>\n        public override void Dispose() { }\n\n        /// <inheritdoc/>\n        public override string ToString() => Exception?.ToString() ?? \"[null]\";\n    }\n\n    /// <summary>\n    /// A <see cref=\"Response\"/> which represents a typed value.\n    /// </summary>\n    /// <typeparam name=\"TResult\">The underlying result type.</typeparam>\n    [UseActivator, SuppressReferenceTracking]\n    public sealed class Response<TResult> : Response\n    {\n        [Id(0)]\n        private TResult? _result;\n\n        public TResult? TypedResult { get => _result; set => _result = value; }\n\n        public override Exception? Exception\n        {\n            get => null;\n            set => throw new InvalidOperationException($\"Cannot set {nameof(Exception)} property for type {nameof(Response<TResult>)}\");\n        }\n\n        public override object? Result\n        {\n            get => _result;\n            set => _result = (TResult?)value;\n        }\n\n        public override Type GetSimpleResultType() => typeof(TResult);\n\n        public override T GetResult<T>()\n        {\n            if (typeof(TResult).IsValueType && typeof(T).IsValueType && typeof(T) == typeof(TResult))\n                return Unsafe.As<TResult, T>(ref _result!);\n\n            return (T)(object)_result!;\n        }\n\n        public override void Dispose()\n        {\n            _result = default;\n            ResponsePool.Return(this);\n        }\n\n        public override string ToString() => _result?.ToString() ?? \"[null]\";\n    }\n\n    /// <summary>\n    /// Supports raw serialization of <see cref=\"Response{TResult}\"/> values.\n    /// </summary>\n    public abstract class ResponseCodec\n    {\n        public abstract void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, object value) where TBufferWriter : IBufferWriter<byte>;\n        public abstract object ReadRaw<TInput>(ref Reader<TInput> reader, scoped ref Field field);\n    }\n\n    [RegisterSerializer]\n    internal sealed class PooledResponseCodec<TResult> : ResponseCodec, IFieldCodec<Response<TResult>>\n    {\n        private readonly Type _codecFieldType = typeof(Response<TResult>);\n        private readonly Type _resultType = typeof(TResult);\n        private readonly IFieldCodec<TResult> _codec;\n\n        public PooledResponseCodec(ICodecProvider codecProvider)\n            => _codec = OrleansGeneratedCodeHelper.GetService<IFieldCodec<TResult>>(this, codecProvider);\n\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Response<TResult> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            if (value.TypedResult is not null)\n                _codec.WriteField(ref writer, 0, _resultType, value.TypedResult);\n            writer.WriteEndObject();\n        }\n\n        public Response<TResult> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<Response<TResult>, TInput>(ref reader, field);\n\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            var result = ResponsePool.Get<TResult>();\n            reader.ReadFieldHeader(ref field);\n            if (!field.IsEndBaseOrEndObject)\n            {\n                result.TypedResult = _codec.ReadValue(ref reader, field);\n                reader.ReadFieldHeader(ref field);\n                reader.ConsumeEndBaseOrEndObject(ref field);\n            }\n            return result;\n        }\n\n        public override void WriteRaw<TBufferWriter>(ref Writer<TBufferWriter> writer, object value)\n        {\n            writer.WriteStartObject(0, null, _resultType);\n            var holder = (Response<TResult>)value;\n            if (holder.TypedResult is not null)\n                _codec.WriteField(ref writer, 0, _resultType, holder.TypedResult);\n            writer.WriteEndObject();\n        }\n\n        public override object ReadRaw<TInput>(ref Reader<TInput> reader, scoped ref Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            var result = ResponsePool.Get<TResult>();\n            reader.ReadFieldHeader(ref field);\n            if (!field.IsEndBaseOrEndObject)\n            {\n                result.TypedResult = _codec.ReadValue(ref reader, field);\n                reader.ReadFieldHeader(ref field);\n                reader.ConsumeEndBaseOrEndObject(ref field);\n            }\n            return result;\n        }\n    }\n\n    [RegisterCopier]\n    internal sealed class PooledResponseCopier<TResult> : IDeepCopier<Response<TResult>>\n    {\n        private readonly IDeepCopier<TResult> _copier;\n\n        public PooledResponseCopier(ICodecProvider codecProvider)\n            => _copier = OrleansGeneratedCodeHelper.GetService<IDeepCopier<TResult>>(this, codecProvider);\n\n        public Response<TResult> DeepCopy(Response<TResult>? input, CopyContext context)\n        {\n            if (input is null)\n                return null!;\n\n            var result = ResponsePool.Get<TResult>();\n            result.TypedResult = _copier.DeepCopy(input.TypedResult!, context);\n            return result;\n        }\n    }\n\n    [RegisterActivator]\n    internal sealed class PooledResponseActivator<TResult> : IActivator<Response<TResult>>\n    {\n        public Response<TResult> Create() => ResponsePool.Get<TResult>();\n    }\n\n    public static class ResponseExtensions\n    {\n        public static void ThrowIfExceptionResponse(this Response response)\n        {\n            if (response.Exception is { } exception)\n            {\n                ExceptionDispatchInfo.Capture(exception).Throw();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/ResponseCompletionSource.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing System.Threading.Tasks.Sources;\n\nnamespace Orleans.Serialization.Invocation\n{\n    /// <summary>\n    /// A fulfillable promise.\n    /// </summary>\n    public sealed class ResponseCompletionSource : IResponseCompletionSource, IValueTaskSource<Response>, IValueTaskSource\n    {\n        private ManualResetValueTaskSourceCore<Response> _core = new() { RunContinuationsAsynchronously = true };\n\n        /// <summary>\n        /// Returns this instance as a <see cref=\"ValueTask{Response}\"/>.\n        /// </summary>\n        /// <returns>This instance, as a <see cref=\"ValueTask{Response}\"/>.</returns>\n        public ValueTask<Response> AsValueTask() => new(this, _core.Version);\n\n        /// <summary>\n        /// Returns this instance as a <see cref=\"ValueTask\"/>.\n        /// </summary>\n        /// <returns>This instance, as a <see cref=\"ValueTask\"/>.</returns>\n        public ValueTask AsVoidValueTask() => new(this, _core.Version);\n\n        /// <inheritdoc/>\n        public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);\n\n        /// <inheritdoc/>\n        public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags);\n\n        /// <summary>\n        /// Resets this instance.\n        /// </summary>\n        public void Reset()\n        {\n            _core.Reset();\n            ResponseCompletionSourcePool.Return(this);\n        }\n\n        /// <summary>\n        /// Completes this instance with an exception.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        public void SetException(Exception exception) => _core.SetException(exception);\n\n        /// <summary>\n        /// Completes this instance with a result.\n        /// </summary>\n        /// <param name=\"result\">The result.</param>\n        public void SetResult(Response result)\n        {\n            if (result.Exception is not { } exception)\n            {\n                _core.SetResult(result);\n            }\n            else\n            {\n                _core.SetException(exception);\n            }\n        }\n\n        /// <summary>\n        /// Completes this instance with a result.\n        /// </summary>\n        /// <param name=\"value\">The result value.</param>\n        public void Complete(Response value) => SetResult(value);\n\n        /// <summary>\n        /// Completes this instance with the default result.\n        /// </summary>\n        public void Complete() => SetResult(Response.Completed);\n\n        /// <inheritdoc />\n        public Response GetResult(short token)\n        {\n            bool isValid = token == _core.Version;\n            try\n            {\n                return _core.GetResult(token);\n            }\n            finally\n            {\n                if (isValid)\n                {\n                    Reset();\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        void IValueTaskSource.GetResult(short token)\n        {\n            bool isValid = token == _core.Version;\n            try\n            {\n                _ = _core.GetResult(token);\n            }\n            finally\n            {\n                if (isValid)\n                {\n                    Reset();\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// A fulfillable promise.\n    /// </summary>\n    /// <typeparam name=\"TResult\">The underlying result type.</typeparam>\n    public sealed class ResponseCompletionSource<TResult> : IResponseCompletionSource, IValueTaskSource<TResult>, IValueTaskSource\n    {\n        private ManualResetValueTaskSourceCore<TResult> _core = new() { RunContinuationsAsynchronously = true };\n\n        /// <summary>\n        /// Returns this instance as a <see cref=\"ValueTask{Response}\"/>.\n        /// </summary>\n        /// <returns>This instance, as a <see cref=\"ValueTask{Response}\"/>.</returns>\n        public ValueTask<TResult> AsValueTask() => new(this, _core.Version);\n\n        /// <summary>\n        /// Returns this instance as a <see cref=\"ValueTask\"/>.\n        /// </summary>\n        /// <returns>This instance, as a <see cref=\"ValueTask\"/>.</returns>\n        public ValueTask AsVoidValueTask() => new(this, _core.Version);\n\n        /// <inheritdoc/>\n        public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);\n\n        /// <inheritdoc/>\n        public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags);\n\n        /// <summary>\n        /// Resets this instance.\n        /// </summary>\n        public void Reset()\n        {\n            _core.Reset();\n            ResponseCompletionSourcePool.Return(this);\n        }\n\n        /// <summary>\n        /// Completes this instance with an exception.\n        /// </summary>\n        /// <param name=\"exception\">The exception.</param>\n        public void SetException(Exception exception) => _core.SetException(exception);\n\n        /// <summary>\n        /// Completes this instance with a result.\n        /// </summary>\n        /// <param name=\"result\">The result.</param>\n        public void SetResult(TResult result) => _core.SetResult(result);\n\n        /// <inheritdoc/>\n        public void Complete(Response value)\n        {\n            if (value is Response<TResult> typed)\n            {\n                Complete(typed);\n            }\n            else if (value.Exception is { } exception)\n            {\n                SetException(exception);\n            }\n            else\n            {\n                var result = value.Result;\n                if (result is null)\n                {\n                    SetResult(default);\n                }\n                else if (result is TResult typedResult)\n                {\n                    SetResult(typedResult);\n                }\n                else\n                {\n                    SetInvalidCastException(result);\n                }\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void SetInvalidCastException(object result)\n        {\n            var exception = new InvalidCastException($\"Cannot cast object of type {result.GetType()} to {typeof(TResult)}\");\n#if NET5_0_OR_GREATER\n            System.Runtime.ExceptionServices.ExceptionDispatchInfo.SetCurrentStackTrace(exception);\n            SetException(exception);\n#else\n            try\n            {\n                throw exception;\n            }\n            catch (Exception ex)\n            {\n                SetException(ex);\n            }\n#endif\n        }\n\n        /// <summary>\n        /// Completes this instance with a result.\n        /// </summary>\n        /// <param name=\"value\">The result value.</param>\n        public void Complete(Response<TResult> value)\n        {\n            if (value.Exception is { } exception)\n            {\n                SetException(exception);\n            }\n            else\n            {\n                SetResult(value.TypedResult);\n            }\n        }\n\n        /// <inheritdoc/>\n        public void Complete() => SetResult(default);\n\n        /// <inheritdoc/>\n        public TResult GetResult(short token)\n        {\n            bool isValid = token == _core.Version;\n            try\n            {\n                return _core.GetResult(token);\n            }\n            finally\n            {\n                if (isValid)\n                {\n                    Reset();\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        void IValueTaskSource.GetResult(short token)\n        {\n            bool isValid = token == _core.Version;\n            try\n            {\n                _ = _core.GetResult(token);\n            }\n            finally\n            {\n                if (isValid)\n                {\n                    Reset();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Invocation/TargetHolderExtensions.cs",
    "content": "#nullable enable\nusing Orleans.Serialization.Invocation;\nnamespace Orleans.Runtime;\n\n/// <summary>\n/// Extension methods for <see cref=\"ITargetHolder\"/>.\n/// </summary>\npublic static class TargetHolderExtensions\n{\n    /// <summary>\n    /// Gets the component with the specified type.\n    /// </summary>\n    /// <typeparam name=\"TComponent\">The component type.</typeparam>\n    /// <param name=\"targetHolder\">The target holder from which to retrieve the component.</param>\n    /// <returns>The component with the specified type.</returns>\n    public static TComponent? GetComponent<TComponent>(this ITargetHolder targetHolder) where TComponent : class => targetHolder.GetComponent(typeof(TComponent)) as TComponent;\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Orleans.Serialization.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Serialization</PackageId>\n    <PackageDescription>Fast, flexible, and version-tolerant serializer for .NET</PackageDescription>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyModel\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options\" />\n    <PackageReference Include=\"Microsoft.Extensions.ObjectPool\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Common\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Workspaces.Common\" />\n    <PackageReference Include=\"System.IO.Hashing\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'netstandard2.1'\">\n    <PackageReference Include=\"System.Collections.Immutable\" />\n    <PackageReference Include=\"Microsoft.DotNet.PlatformAbstractions\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.Abstractions\\Orleans.Serialization.Abstractions.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Serialization.UnitTests\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "src/Orleans.Serialization/README.md",
    "content": "# Microsoft Orleans Serialization\n\n## Introduction\nMicrosoft Orleans Serialization is a fast, flexible, and version-tolerant serializer for .NET. It provides the core serialization capabilities for Orleans, enabling efficient serialization and deserialization of data across the network and for storage.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization\n```\n\nThis package is automatically included when you reference the Orleans SDK or the Orleans client/server metapackages.\n\n## Example\n\n```csharp\n// Creating a serializer\nvar services = new ServiceCollection();\nservices.AddSerializer();\nvar serviceProvider = services.BuildServiceProvider();\nvar serializer = serviceProvider.GetRequiredService<Serializer>();\n\n// Serializing an object\nvar bytes = serializer.SerializeToArray(myObject);\n\n// Deserializing an object\nvar deserializedObject = serializer.Deserialize<MyType>(bytes);\n```\n\n## Supporting your own Types\n\nTo make your types serializable in Orleans, mark them with the `[GenerateSerializer]` attribute and mark each field/property which should be serialized with the `[Id(int)]` attribute:\n\n```csharp\n[GenerateSerializer]\npublic class MyClass\n{\n    [Id(0)]\n    public string Name { get; set; }\n    \n    [Id(1)]\n    public int Value { get; set; }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Serialization in Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [Orleans type serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization-attributes)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization/Serializer.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing System;\nusing System.Buffers;\nusing System.IO;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Serializes and deserializes values.\n    /// </summary>\n    public sealed class Serializer \n    {\n        private readonly SerializerSessionPool _sessionPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Serializer\"/> class.\n        /// </summary>\n        /// <param name=\"sessionPool\">The session pool.</param>\n        public Serializer(SerializerSessionPool sessionPool) => _sessionPool = sessionPool;\n\n        /// <summary>\n        /// Gets the serializer session pool.\n        /// </summary>\n        public SerializerSessionPool SessionPool => _sessionPool;\n\n        /// <summary>\n        /// Returns a serializer which is specialized to the provided type parameter.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying type for the returned serializer.</typeparam>\n        public Serializer<T> GetSerializer<T>() => new(_sessionPool);\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided type, <typeparamref name=\"T\"/>, can be serialized, and <see langword=\"false\"/> otherwise.\n        /// </summary>\n        public bool CanSerialize<T>() => _sessionPool.CodecProvider.TryGetCodec(typeof(T)) is { };\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided type, <paramref name=\"type\"/>, can be serialized, and <see langword=\"false\"/> otherwise.\n        /// </summary>\n        public bool CanSerialize(Type type) => _sessionPool.CodecProvider.TryGetCodec(type) is { };\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into a new array.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <returns>A byte array containing the serialized value.</returns>\n        public byte[] SerializeToArray<T>(T value)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(session);\n            try\n            {\n                var codec = session.CodecProvider.GetCodec<T>();\n                codec.WriteField(ref writer, 0, typeof(T), value);\n                writer.Commit();\n                return writer.Output.ToArray();\n            }\n            finally\n            {\n                writer.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize<T>(T value, ref Memory<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize<T>(T value, ref Memory<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize<T>(T value, Stream destination, int sizeHint = 0)\n        {\n            using var session = _sessionPool.GetSession();\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                var codec = session.CodecProvider.GetCodec<T>();\n                codec.WriteField(ref writer, 0, typeof(T), value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    var codec = session.CodecProvider.GetCodec<T>();\n                    codec.WriteField(ref writer, 0, typeof(T), value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize<T>(T value, Stream destination, SerializerSession session, int sizeHint = 0)\n        {\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                var codec = session.CodecProvider.GetCodec<T>();\n                codec.WriteField(ref writer, 0, typeof(T), value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    var codec = session.CodecProvider.GetCodec<T>();\n                    codec.WriteField(ref writer, 0, typeof(T), value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<T, TBufferWriter>(T value, TBufferWriter destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        public void Serialize<T, TBufferWriter>(T value, TBufferWriter destination, SerializerSession session) where TBufferWriter : IBufferWriter<byte>\n        {\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<T, TBufferWriter>(T value, ref Writer<TBufferWriter> destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            var codec = destination.Session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref destination, 0, typeof(T), value);\n            destination.Commit();\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize<T>(T value, ref Span<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize<T>(T value, ref Span<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize<T>(T value, byte[] destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize<T>(T value, ArraySegment<byte> destination)\n        {\n            var destinationSpan = destination.AsSpan();\n            Serialize(value, ref destinationSpan);\n            return destinationSpan.Length;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize<T>(T value, ArraySegment<byte> destination, SerializerSession session)\n        {\n            var destinationSpan = destination.AsSpan();\n            Serialize(value, ref destinationSpan, session);\n            return destinationSpan.Length;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The expected type of <paramref name=\"value\"/>.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize<T>(T value, byte[] destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            codec.WriteField(ref writer, 0, typeof(T), value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(Stream source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(Stream source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlySequence<byte> source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlySequence<byte> source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(PooledBuffer.BufferSlice source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(PooledBuffer.BufferSlice source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlySpan<byte> source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlySpan<byte> source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec<T>();\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(byte[] source) => Deserialize<T>(source.AsSpan());\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(byte[] source, SerializerSession session) => Deserialize<T>(source.AsSpan(), session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlyMemory<byte> source) => Deserialize<T>(source.Span);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ReadOnlyMemory<byte> source, SerializerSession session) => Deserialize<T>(source.Span, session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ArraySegment<byte> source) => Deserialize<T>(source.AsSpan());\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T>(ArraySegment<byte> source, SerializerSession session) => Deserialize<T>(source.AsSpan(), session);\n        \n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The serialized type.</typeparam>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<T, TInput>(ref Reader<TInput> source)\n        {\n            var codec = source.Session.CodecProvider.GetCodec<T>();\n            var field = source.ReadFieldHeader();\n            return codec.ReadValue(ref source, field);\n        }\n    }\n\n    /// <summary>\n    /// Serializes and deserializes values.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of value which this instance serializes and deserializes.</typeparam>\n    public sealed class Serializer<T>\n    {\n        private readonly IFieldCodec<T> _codec;\n        private readonly SerializerSessionPool _sessionPool;\n        private readonly Type _expectedType = typeof(T);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Serializer{T}\"/> class.\n        /// </summary>\n        /// <param name=\"sessionPool\">The session pool.</param>\n        public Serializer(SerializerSessionPool sessionPool) : this(OrleansGeneratedCodeHelper.UnwrapService(null, sessionPool.CodecProvider.GetCodec<T>()), sessionPool)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Serializer{T}\"/> class.\n        /// </summary>\n        /// <param name=\"codec\">The codec.</param>\n        /// <param name=\"sessionPool\">The session pool.</param>\n        public Serializer(IFieldCodec<T> codec, SerializerSessionPool sessionPool)\n        {\n            _codec = codec;\n            _sessionPool = sessionPool;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<TBufferWriter>(T value, ref Writer<TBufferWriter> destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            _codec.WriteField(ref destination, 0, _expectedType, value);\n            destination.Commit();\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<TBufferWriter>(T value, TBufferWriter destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        public void Serialize<TBufferWriter>(T value, TBufferWriter destination, SerializerSession session) where TBufferWriter : IBufferWriter<byte>\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into a new array.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <returns>A byte array containing the serialized value.</returns>\n        public byte[] SerializeToArray(T value)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(session);\n            try\n            {\n                _codec.WriteField(ref writer, 0, _expectedType, value);\n                writer.Commit();\n                return writer.Output.ToArray();\n            }\n            finally\n            {\n                writer.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(T value, ref Memory<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(T value, ref Memory<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(T value, ref Span<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(T value, ref Span<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(T value, byte[] destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(T value, byte[] destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.WriteField(ref writer, 0, _expectedType, value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(T value, Stream destination, int sizeHint = 0)\n        {\n            using var session = _sessionPool.GetSession();\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                _codec.WriteField(ref writer, 0, _expectedType, value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    _codec.WriteField(ref writer, 0, _expectedType, value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(T value, Stream destination, SerializerSession session, int sizeHint = 0)\n        {\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                _codec.WriteField(ref writer, 0, _expectedType, value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    _codec.WriteField(ref writer, 0, _expectedType, value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize<TInput>(ref Reader<TInput> source)\n        {\n            var field = source.ReadFieldHeader();\n            return _codec.ReadValue(ref source, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(Stream source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(Stream source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlySequence<byte> source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ArraySegment<byte> source) => Deserialize(source.AsSpan());\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlySequence<byte> source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(PooledBuffer.BufferSlice source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(PooledBuffer.BufferSlice source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlySpan<byte> source)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlySpan<byte> source, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            var field = reader.ReadFieldHeader();\n            return _codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(byte[] source) => Deserialize(source.AsSpan());\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(byte[] source, SerializerSession session) => Deserialize(source.AsSpan(), session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlyMemory<byte> source) => Deserialize(source.Span);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ReadOnlyMemory<byte> source, SerializerSession session) => Deserialize(source.Span, session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public T Deserialize(ArraySegment<byte> source, SerializerSession session) => Deserialize(source.AsSpan(), session);\n    }\n\n    /// <summary>\n    /// Serializes and deserializes value types.\n    /// </summary>\n    /// <typeparam name=\"T\">The type which this instance operates on.</typeparam>\n    public sealed class ValueSerializer<T> where T : struct\n    {\n        private readonly IValueSerializer<T> _codec;\n        private readonly SerializerSessionPool _sessionPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueSerializer{T}\"/> class.\n        /// </summary>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        /// <param name=\"sessionPool\">The session pool.</param>\n        public ValueSerializer(IValueSerializerProvider codecProvider, SerializerSessionPool sessionPool)\n        {\n            _sessionPool = sessionPool;\n            _codec = OrleansGeneratedCodeHelper.UnwrapService(null, codecProvider.GetValueSerializer<T>());\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<TBufferWriter>(scoped ref T value, ref Writer<TBufferWriter> destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            _codec.Serialize(ref destination, ref value);\n            destination.WriteEndObject();\n            destination.Commit();\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        public void Serialize<TBufferWriter>(scoped ref T value, TBufferWriter destination) where TBufferWriter : IBufferWriter<byte>\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        public void Serialize<TBufferWriter>(scoped ref T value, TBufferWriter destination, SerializerSession session) where TBufferWriter : IBufferWriter<byte>\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into a new array.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <returns>A byte array containing the serialized value.</returns>\n        public byte[] SerializeToArray(scoped ref T value)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(session);\n            try\n            {\n                _codec.Serialize(ref writer, ref value);\n                writer.WriteEndObject();\n                writer.Commit();\n                return writer.Output.ToArray();\n            }\n            finally\n            {\n                writer.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(scoped ref T value, ArraySegment<byte> destination)\n        {\n            var destinationSpan = destination.AsSpan();\n            Serialize(ref value, ref destinationSpan);\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(scoped ref T value, ref Memory<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(scoped ref T value, ref Memory<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(scoped ref T value, ref Span<byte> destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(scoped ref T value, ref Span<byte> destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(scoped ref T value, byte[] destination)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(scoped ref T value, byte[] destination, SerializerSession session)\n        {\n            var writer = Writer.Create(destination, session);\n            _codec.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(scoped ref T value, Stream destination, int sizeHint = 0)\n        {\n            using var session = _sessionPool.GetSession();\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                _codec.Serialize(ref writer, ref value);\n                writer.WriteEndObject();\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    _codec.Serialize(ref writer, ref value);\n                    writer.WriteEndObject();\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(scoped ref T value, Stream destination, SerializerSession session, int sizeHint = 0)\n        {\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                _codec.Serialize(ref writer, ref value);\n                writer.WriteEndObject();\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    _codec.Serialize(ref writer, ref value);\n                    writer.WriteEndObject();\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize<TInput>(ref Reader<TInput> source, scoped ref T result)\n        {\n            _codec.Deserialize(ref source, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(Stream source, scoped ref T result)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(Stream source, scoped ref T result, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlySequence<byte> source, scoped ref T result)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlySequence<byte> source, scoped ref T result, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ArraySegment<byte> source, scoped ref T result, SerializerSession session) => Deserialize(source.AsSpan(), ref result, session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlySpan<byte> source, scoped ref T result)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlySpan<byte> source, scoped ref T result, SerializerSession session)\n        {\n            var reader = Reader.Create(source, session);\n            _codec.Deserialize(ref reader, ref result);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(byte[] source, scoped ref T result) => Deserialize(source.AsSpan(), ref result);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(byte[] source, scoped ref T result, SerializerSession session) => Deserialize(source.AsSpan(), ref result, session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlyMemory<byte> source, scoped ref T result) => Deserialize(source.Span, ref result);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ReadOnlyMemory<byte> source, scoped ref T result, SerializerSession session) => Deserialize(source.Span, ref result, session);\n\n        /// <summary>\n        /// Deserialize a value of type <typeparamref name=\"T\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"result\">The deserialized value.</param>\n        /// <returns>The deserialized value.</returns>\n        public void Deserialize(ArraySegment<byte> source, scoped ref T result) => Deserialize(source.AsSpan(), ref result);\n    }\n\n    /// <summary>\n    /// Provides methods for serializing and deserializing values which have types which are not statically known.\n    /// </summary>\n    public sealed class ObjectSerializer \n    {\n        private readonly SerializerSessionPool _sessionPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ObjectSerializer\"/> class.\n        /// </summary>\n        /// <param name=\"sessionPool\">The session pool.</param>\n        public ObjectSerializer(SerializerSessionPool sessionPool) => _sessionPool = sessionPool;\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the provided type, <paramref name=\"type\"/>, can be serialized, and <see langword=\"false\"/> otherwise.\n        /// </summary>\n        public bool CanSerialize(Type type) => _sessionPool.CodecProvider.TryGetCodec(type) is { };\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(object value, ref Memory<byte> destination, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(object value, ref Memory<byte> destination, SerializerSession session, Type type)\n        {\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(object value, Stream destination, Type type, int sizeHint = 0)\n        {\n            using var session = _sessionPool.GetSession();\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                ObjectCodec.WriteField(ref writer, 0, type, value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    ObjectCodec.WriteField(ref writer, 0, type, value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <param name=\"sizeHint\">The estimated upper bound for the length of the serialized data.</param>\n        /// <remarks>The destination stream will not be flushed by this method.</remarks>\n        public void Serialize(object value, Stream destination, SerializerSession session, Type type, int sizeHint = 0)\n        {\n            if (destination is MemoryStream memoryStream)\n            {\n                var writer = Writer.Create(memoryStream, session);\n                ObjectCodec.WriteField(ref writer, 0, type, value);\n                writer.Commit();\n            }\n            else\n            {\n                var writer = Writer.CreatePooled(destination, session, sizeHint);\n                try\n                {\n                    ObjectCodec.WriteField(ref writer, 0, type, value);\n                    writer.Commit();\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        public void Serialize<TBufferWriter>(object value, TBufferWriter destination, Type type) where TBufferWriter : IBufferWriter<byte>\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        public void Serialize<TBufferWriter>(object value, TBufferWriter destination, SerializerSession session, Type type) where TBufferWriter : IBufferWriter<byte>\n        {\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n\n            // Do not dispose, since the buffer writer is not owned by the method.\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The output buffer writer.</typeparam>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        public void Serialize<TBufferWriter>(object value, ref Writer<TBufferWriter> destination, Type type) where TBufferWriter : IBufferWriter<byte>\n        {\n            ObjectCodec.WriteField(ref destination, 0, type, value);\n            destination.Commit();\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(object value, ref Span<byte> destination, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <remarks>This method slices the <paramref name=\"destination\"/> to the serialized data length.</remarks>\n        public void Serialize(object value, ref Span<byte> destination, SerializerSession session, Type type)\n        {\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            destination = destination[..writer.Position];\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(object value, byte[] destination, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(object value, ArraySegment<byte> destination, Type type)\n        {\n            var destinationSpan = destination.AsSpan();\n            Serialize(value, ref destinationSpan, type);\n            return destinationSpan.Length;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(object value, ArraySegment<byte> destination, SerializerSession session, Type type)\n        {\n            var destinationSpan = destination.AsSpan();\n            Serialize(value, ref destinationSpan, session, type);\n            return destinationSpan.Length;\n        }\n\n        /// <summary>\n        /// Serializes the provided <paramref name=\"value\"/> into <paramref name=\"destination\"/>.\n        /// </summary>\n        /// <param name=\"value\">The value to serialize.</param>\n        /// <param name=\"destination\">The destination where serialized data will be written.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The length of the serialized data.</returns>\n        public int Serialize(object value, byte[] destination, SerializerSession session, Type type)\n        {\n            var writer = Writer.Create(destination, session);\n            ObjectCodec.WriteField(ref writer, 0, type, value);\n            writer.Commit();\n            return writer.Position;\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(Stream source, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(Stream source, SerializerSession session, Type type)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlySequence<byte> source, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlySequence<byte> source, SerializerSession session, Type type)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlySpan<byte> source, Type type)\n        {\n            using var session = _sessionPool.GetSession();\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlySpan<byte> source, SerializerSession session, Type type)\n        {\n            var reader = Reader.Create(source, session);\n            var codec = session.CodecProvider.GetCodec(type);\n            var field = reader.ReadFieldHeader();\n            return codec.ReadValue(ref reader, field);\n        }\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(byte[] source, Type type) => Deserialize(source.AsSpan(), type);\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(byte[] source, SerializerSession session, Type type) => Deserialize(source.AsSpan(), session, type);\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlyMemory<byte> source, Type type) => Deserialize(source.Span, type);\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ReadOnlyMemory<byte> source, SerializerSession session, Type type) => Deserialize(source.Span, session, type);\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ArraySegment<byte> source, Type type) => Deserialize(source.AsSpan(), type);\n\n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"session\">The serializer session.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize(ArraySegment<byte> source, SerializerSession session, Type type) => Deserialize(source.AsSpan(), session, type);\n        \n        /// <summary>\n        /// Deserialize a value of type <paramref name=\"type\"/> from <paramref name=\"source\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"source\">The source buffer.</param>\n        /// <param name=\"type\">The expected type of the value.</param>\n        /// <returns>The deserialized value.</returns>\n        public object Deserialize<TInput>(ref Reader<TInput> source, Type type)\n        {\n            var codec = source.Session.CodecProvider.GetCodec(type);\n            var field = source.ReadFieldHeader();\n            return codec.ReadValue(ref source, field);\n        }\n    }\n\n    /// <summary>\n    /// Provides functionality for copying object and values.\n    /// </summary>\n    public sealed class DeepCopier\n    {\n        private readonly CodecProvider _codecProvider;\n        private readonly CopyContextPool _contextPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DeepCopier\"/> class.\n        /// </summary>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        /// <param name=\"contextPool\">The context pool.</param>\n        public DeepCopier(CodecProvider codecProvider, CopyContextPool contextPool)\n        {\n            _codecProvider = codecProvider;\n            _contextPool = contextPool;\n        }\n\n        /// <summary>\n        /// Returns a copier which is specialized to the provided type parameter.\n        /// </summary>\n        /// <typeparam name=\"T\">The underlying type for the returned copier.</typeparam>\n        public DeepCopier<T> GetCopier<T>() => new(_codecProvider.GetDeepCopier<T>(), _contextPool);\n\n        /// <summary>\n        /// Creates a copy of the provided value.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the value to copy.</typeparam>\n        /// <param name=\"value\">The value to copy.</param>\n        /// <returns>A copy of the provided value.</returns>\n        public T Copy<T>(T value)\n        {\n            using var context = _contextPool.GetContext();\n            return context.DeepCopy(value);\n        }\n    }\n\n    /// <summary>\n    /// Provides functionality for copying objects and values.\n    /// </summary>\n    public sealed class DeepCopier<T>\n    {\n        private readonly IDeepCopier<T> _copier;\n        private readonly CopyContextPool _contextPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DeepCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"copier\">The copier.</param>\n        /// <param name=\"contextPool\">The context pool.</param>\n        public DeepCopier(IDeepCopier<T> copier, CopyContextPool contextPool)\n        {\n            _copier = copier;\n            _contextPool = contextPool;\n        }\n\n        /// <summary>\n        /// Creates a copy of the provided value.\n        /// </summary>\n        /// <param name=\"value\">The value to copy.</param>\n        /// <returns>A copy of the provided value.</returns>\n        public T Copy(T value)\n        {\n            using var context = _contextPool.GetContext();\n            return _copier.DeepCopy(value, context);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/AbstractTypeSerializer.cs",
    "content": "using System;\nusing System.Buffers;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Serializer for types which are abstract and therefore cannot be instantiated themselves, such as abstract classes and interface types.\n    /// </summary>\n    public class AbstractTypeSerializer<TField> : AbstractTypeSerializer, IFieldCodec<TField>, IBaseCodec<TField> where TField : class\n    {\n        protected AbstractTypeSerializer() : base(typeof(TField)) { }\n\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n            => base.WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        public new TField ReadValue<TInput>(ref Reader<TInput> reader, Field field) => (TField)base.ReadValue(ref reader, field);\n\n        public virtual void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, TField instance) where TBufferWriter : IBufferWriter<byte> { }\n\n        public virtual void Deserialize<TReaderInput>(ref Reader<TReaderInput> reader, TField instance) => reader.ConsumeEndBaseOrEndObject();\n    }\n\n    // without the class type constraint\n    internal sealed class AbstractTypeSerializerWrapper<TField> : AbstractTypeSerializer, IFieldCodec<TField>\n    {\n        public AbstractTypeSerializerWrapper() : base(typeof(TField)) { }\n\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n            => base.WriteField(ref writer, fieldIdDelta, expectedType, value);\n\n        public new TField ReadValue<TInput>(ref Reader<TInput> reader, Field field) => (TField)base.ReadValue(ref reader, field);\n    }\n\n    public class AbstractTypeSerializer : IFieldCodec\n    {\n        private readonly Type _fieldType;\n\n        protected internal AbstractTypeSerializer(Type fieldType) => _fieldType = fieldType;\n\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            var specificSerializer = writer.Session.CodecProvider.GetCodec(value.GetType());\n            specificSerializer.WriteField(ref writer, fieldIdDelta, expectedType, value);\n        }\n\n        public object ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference(ref reader, field.FieldType ?? _fieldType);\n\n            var fieldType = field.FieldType;\n            if (fieldType is null)\n                ThrowMissingFieldType();\n\n            var specificSerializer = reader.Session.CodecProvider.GetCodec(fieldType);\n            return specificSerializer.ReadValue(ref reader, field);\n        }\n\n        private void ThrowMissingFieldType() => throw new FieldTypeMissingException(_fieldType);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/CodecProvider.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.GeneratedCodeHelpers;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides access to serializers and related objects.\n    /// </summary>\n    public sealed class CodecProvider : ICodecProvider\n    {\n        private static readonly Type ObjectType = typeof(object);\n\n#if NET9_0_OR_GREATER\n        private readonly Lock _initializationLock = new();\n#else\n        private readonly object _initializationLock = new();\n#endif\n\n        private readonly ConcurrentDictionary<Type, IFieldCodec> _untypedCodecs = new();\n        private readonly ConcurrentDictionary<Type, IFieldCodec> _typedCodecs = new();\n        private readonly ConcurrentDictionary<Type, IBaseCodec> _typedBaseCodecs = new();\n        private readonly ConcurrentDictionary<Type, IDeepCopier> _untypedCopiers = new();\n        private readonly ConcurrentDictionary<Type, IDeepCopier> _typedCopiers = new();\n\n        private readonly ConcurrentDictionary<Type, object> _instantiatedBaseCopiers = new();\n        private readonly ConcurrentDictionary<Type, object> _instantiatedValueSerializers = new();\n        private readonly ConcurrentDictionary<Type, object> _instantiatedActivators = new();\n        private readonly Dictionary<Type, Type> _baseCodecs = new();\n        private readonly Dictionary<Type, Type> _valueSerializers = new();\n        private readonly Dictionary<Type, Type> _fieldCodecs = new();\n        private readonly Dictionary<Type, Type> _copiers = new();\n        private readonly Dictionary<Type, Type> _converters = new();\n        private readonly Dictionary<Type, Type> _baseCopiers = new();\n        private readonly Dictionary<Type, Type> _activators = new();\n        private readonly List<IGeneralizedCodec> _generalizedCodecs = new();\n        private readonly List<ISpecializableCodec> _specializableCodecs = new();\n        private readonly List<IGeneralizedBaseCodec> _generalizedBaseCodecs = new();\n        private readonly List<ISpecializableBaseCodec> _specializableBaseCodecs = new();\n        private readonly List<IGeneralizedCopier> _generalizedCopiers = new();\n        private readonly List<ISpecializableCopier> _specializableCopiers = new();\n        private readonly ObjectCodec _objectCodec = new();\n        private readonly VoidCodec _voidCodec = new();\n        private readonly ObjectCopier _objectCopier = new();\n        private readonly IServiceProvider _serviceProvider;\n        private readonly VoidCopier _voidCopier = new();\n        private bool _initialized;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CodecProvider\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"codecConfiguration\">The codec configuration.</param>\n        public CodecProvider(IServiceProvider serviceProvider, IOptions<TypeManifestOptions> codecConfiguration)\n        {\n            _serviceProvider = serviceProvider;\n\n            ConsumeMetadata(codecConfiguration);\n        }\n\n        /// <inheritdoc/>\n        public IServiceProvider Services => _serviceProvider;\n\n        private void Initialize()\n        {\n            lock (_initializationLock)\n            {\n                if (_initialized)\n                {\n                    return;\n                }\n\n                _generalizedCodecs.AddRange(_serviceProvider.GetServices<IGeneralizedCodec>());\n                _generalizedBaseCodecs.AddRange(_serviceProvider.GetServices<IGeneralizedBaseCodec>());\n                _generalizedCopiers.AddRange(_serviceProvider.GetServices<IGeneralizedCopier>());\n\n                _specializableCodecs.AddRange(_serviceProvider.GetServices<ISpecializableCodec>());\n                _specializableCopiers.AddRange(_serviceProvider.GetServices<ISpecializableCopier>());\n                _specializableBaseCodecs.AddRange(_serviceProvider.GetServices<ISpecializableBaseCodec>());\n\n                _initialized = true;\n            }\n        }\n\n        private void ConsumeMetadata(IOptions<TypeManifestOptions> codecConfiguration)\n        {\n            var metadata = codecConfiguration.Value;\n            AddFromMetadata(_baseCodecs, metadata.Serializers, typeof(IBaseCodec<>));\n            AddFromMetadata(_valueSerializers, metadata.Serializers, typeof(IValueSerializer<>));\n            AddFromMetadata(_fieldCodecs, metadata.Serializers, typeof(IFieldCodec<>));\n            AddFromMetadata(_fieldCodecs, metadata.FieldCodecs, typeof(IFieldCodec<>));\n            AddFromMetadata(_activators, metadata.Activators, typeof(IActivator<>));\n            AddFromMetadata(_copiers, metadata.Copiers, typeof(IDeepCopier<>));\n            AddFromMetadata(_converters, metadata.Converters, typeof(IConverter<,>));\n            AddFromMetadata(_baseCopiers, metadata.Copiers, typeof(IBaseCopier<>));\n\n            static void AddFromMetadata(Dictionary<Type, Type> resultCollection, HashSet<Type> metadataCollection, Type genericType)\n            {\n                Debug.Assert(genericType.GetGenericArguments().Length >= 1);\n\n                foreach (var type in metadataCollection)\n                {\n                    var interfaces = type.GetInterfaces();\n                    foreach (var @interface in interfaces)\n                    {\n                        if (!@interface.IsGenericType)\n                        {\n                            continue;\n                        }\n\n                        if (genericType != @interface.GetGenericTypeDefinition())\n                        {\n                            continue;\n                        }\n\n                        var genericArgument = @interface.GetGenericArguments()[0];\n                        if (typeof(object) == genericArgument)\n                        {\n                            continue;\n                        }\n\n                        if (genericArgument.IsConstructedGenericType && Array.Exists(genericArgument.GenericTypeArguments, arg => arg.IsGenericParameter))\n                        {\n                            genericArgument = genericArgument.GetGenericTypeDefinition();\n                        }\n\n                        resultCollection[genericArgument] = type;\n                    }\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public IFieldCodec<TField> TryGetCodec<TField>()\n        {\n            var fieldType = typeof(TField);\n            if (_typedCodecs.TryGetValue(fieldType, out var existing))\n                return (IFieldCodec<TField>)existing;\n\n            if (TryGetCodec(fieldType) is not { } untypedResult)\n                return null;\n\n            var typedResult = untypedResult switch\n            {\n                IFieldCodec<TField> typed => typed,\n                _ when untypedResult.GetType() == typeof(AbstractTypeSerializer) => new AbstractTypeSerializerWrapper<TField>(),\n                _ => new UntypedCodecWrapper<TField>(untypedResult)\n            };\n\n            return (IFieldCodec<TField>)_typedCodecs.GetOrAdd(fieldType, typedResult);\n        }\n\n        /// <inheritdoc/>\n        public IFieldCodec GetCodec(Type fieldType)\n        {\n            var res = TryGetCodec(fieldType);\n            if (res is null) ThrowCodecNotFound(fieldType);\n            return res;\n        }\n\n        /// <inheritdoc/>\n        public IFieldCodec TryGetCodec(Type fieldType)\n        {\n            // If the field type is unavailable, return the void codec which can at least handle references.\n            return fieldType is null ? _voidCodec\n                : _untypedCodecs.TryGetValue(fieldType, out var existing) ? existing\n                : TryCreateCodec(fieldType) is { } res ? _untypedCodecs.GetOrAdd(fieldType, res) : null;\n        }\n\n        private IFieldCodec TryCreateCodec(Type fieldType)\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(fieldType);\n\n            if (CreateCodecInstance(fieldType, fieldType.IsConstructedGenericType ? fieldType.GetGenericTypeDefinition() : fieldType) is { } res)\n                return res;\n\n            foreach (var specializableCodec in _specializableCodecs)\n            {\n                if (specializableCodec.IsSupportedType(fieldType))\n                    return specializableCodec.GetSpecializedCodec(fieldType);\n            }\n\n            foreach (var dynamicCodec in _generalizedCodecs)\n            {\n                if (dynamicCodec.IsSupportedType(fieldType))\n                    return dynamicCodec;\n            }\n\n            return fieldType.IsInterface || fieldType.IsAbstract ? new AbstractTypeSerializer(fieldType) : null;\n        }\n\n        /// <inheritdoc/>\n        public IFieldCodec<TField> GetCodec<TField>()\n        {\n            var res = TryGetCodec<TField>();\n            if (res is null) ThrowCodecNotFound(typeof(TField));\n            return res;\n        }\n\n        /// <inheritdoc/>\n        public IActivator<T> GetActivator<T>()\n        {\n            var type = typeof(T);\n            var searchType = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : type;\n\n            var res = GetActivatorInner(type, searchType);\n            if (res is null) ThrowActivatorNotFound(type);\n            return (IActivator<T>)res;\n        }\n\n        private IBaseCodec<TField> TryCreateBaseCodec<TField>(Type fieldType) where TField : class\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(fieldType);\n\n            // Try to find the codec from the configured codecs.\n            var untypedResult = CreateBaseCodecInstance(fieldType, fieldType.IsConstructedGenericType ? fieldType.GetGenericTypeDefinition() : fieldType);\n\n            if (untypedResult is null)\n            {\n                foreach (var specializableCodec in _specializableBaseCodecs)\n                {\n                    if (specializableCodec.IsSupportedType(fieldType))\n                    {\n                        untypedResult = specializableCodec.GetSpecializedCodec(fieldType);\n                        break;\n                    }\n                }\n\n                if (untypedResult is null)\n                {\n                    foreach (var dynamicCodec in _generalizedBaseCodecs)\n                    {\n                        if (dynamicCodec.IsSupportedType(fieldType))\n                        {\n                            untypedResult = dynamicCodec;\n                            break;\n                        }\n                    }\n\n                    if (untypedResult is null)\n                        return null;\n                }\n            }\n\n            if (untypedResult is not IBaseCodec<TField> typedResult)\n                ThrowCannotConvert(untypedResult);\n\n            return (IBaseCodec<TField>)_typedBaseCodecs.GetOrAdd(fieldType, typedResult);\n\n            static void ThrowCannotConvert(object rawCodec) => throw new InvalidOperationException($\"Cannot convert codec of type {rawCodec.GetType()} to codec of type {typeof(IBaseCodec<TField>)}.\");\n        }\n\n        /// <inheritdoc/>\n        public IBaseCodec<TField> GetBaseCodec<TField>() where TField : class\n        {\n            var type = typeof(TField);\n            if (_typedBaseCodecs.TryGetValue(type, out var existing))\n                return (IBaseCodec<TField>)existing;\n\n            var result = TryCreateBaseCodec<TField>(type);\n            if (result is null) ThrowBaseCodecNotFound(type);\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public IValueSerializer<TField> GetValueSerializer<TField>() where TField : struct\n        {\n            var type = typeof(TField);\n            var searchType = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : type;\n\n            var res = GetValueSerializerInner(type, searchType);\n            if (res is null) ThrowValueSerializerNotFound(type);\n            return (IValueSerializer<TField>)res;\n        }\n\n        /// <inheritdoc/>\n        public IBaseCopier<TField> GetBaseCopier<TField>() where TField : class\n        {\n            var type = typeof(TField);\n            var searchType = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : type;\n\n            var res = GetBaseCopierInner(type, searchType);\n            if (res is null) ThrowBaseCopierNotFound(type);\n            return (IBaseCopier<TField>)res;\n        }\n\n        /// <inheritdoc/>\n        public IDeepCopier<T> GetDeepCopier<T>()\n        {\n            var res = TryGetDeepCopier<T>();\n            if (res is null) ThrowCopierNotFound(typeof(T));\n            return res;\n        }\n\n        /// <inheritdoc/>\n        public IDeepCopier<T> TryGetDeepCopier<T>()\n        {\n            var type = typeof(T);\n            if (_typedCopiers.TryGetValue(type, out var existing))\n                return (IDeepCopier<T>)existing;\n\n            if (TryGetDeepCopier(type) is not { } untypedResult)\n                return null;\n\n            var typedResult = untypedResult switch\n            {\n                IDeepCopier<T> typed => typed,\n                IOptionalDeepCopier optional when optional.IsShallowCopyable() => new ShallowCopier<T>(),\n                _ => new UntypedCopierWrapper<T>(untypedResult)\n            };\n\n            return (IDeepCopier<T>)_typedCopiers.GetOrAdd(type, typedResult);\n        }\n\n        /// <inheritdoc/>\n        public IDeepCopier GetDeepCopier(Type fieldType)\n        {\n            var res = TryGetDeepCopier(fieldType);\n            if (res is null) ThrowCopierNotFound(fieldType);\n            return res;\n        }\n\n        /// <inheritdoc/>\n        public IDeepCopier TryGetDeepCopier(Type fieldType)\n        {\n            // If the field type is unavailable, return the void copier which can at least handle references.\n            return fieldType is null ? _voidCopier\n                : _untypedCopiers.TryGetValue(fieldType, out var existing) ? existing\n                : TryCreateCopier(fieldType) is { } res ? _untypedCopiers.GetOrAdd(fieldType, res)\n                : null;\n        }\n\n        private IDeepCopier TryCreateCopier(Type fieldType)\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(fieldType);\n\n            if (CreateCopierInstance(fieldType, fieldType.IsConstructedGenericType ? fieldType.GetGenericTypeDefinition() : fieldType) is { } res)\n                return res;\n\n            foreach (var specializableCopier in _specializableCopiers)\n            {\n                if (specializableCopier.IsSupportedType(fieldType))\n                    return specializableCopier.GetSpecializedCopier(fieldType);\n            }\n\n            foreach (var dynamicCopier in _generalizedCopiers)\n            {\n                if (dynamicCopier.IsSupportedType(fieldType))\n                    return dynamicCopier;\n            }\n\n            return fieldType.IsInterface || fieldType.IsAbstract ? _objectCopier : null;\n        }\n\n        private object GetValueSerializerInner(Type concreteType, Type searchType)\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(concreteType);\n\n            object[] constructorArguments = null;\n            if (_valueSerializers.TryGetValue(searchType, out var serializerType))\n            {\n                if (serializerType.IsGenericTypeDefinition)\n                {\n                    serializerType = serializerType.MakeGenericType(concreteType.GetGenericArguments());\n                }\n            }\n            else if (TryGetSurrogateCodec(concreteType, searchType, out var surrogateCodecType, out constructorArguments) && typeof(IValueSerializer).IsAssignableFrom(surrogateCodecType))\n            {\n                serializerType = surrogateCodecType;\n            }\n            else\n            {\n                return null;\n            }\n\n            if (!_instantiatedValueSerializers.TryGetValue(serializerType, out var result))\n            {\n                result = _instantiatedValueSerializers.GetOrAdd(serializerType, GetServiceOrCreateInstance(serializerType, constructorArguments));\n            }\n\n            return result;\n        }\n\n        private object GetBaseCopierInner(Type concreteType, Type searchType)\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(concreteType);\n\n            object[] constructorArguments = null;\n            if (_baseCopiers.TryGetValue(searchType, out var copierType))\n            {\n               // Use the detected copier type. \n                if (copierType.IsGenericTypeDefinition)\n                {\n                    copierType = copierType.MakeGenericType(concreteType.GetGenericArguments());\n                }\n            }\n            else if (TryGetSurrogateCodec(concreteType, searchType, out var surrogateCodecType, out constructorArguments) && typeof(IBaseCopier).IsAssignableFrom(surrogateCodecType))\n            {\n                copierType = surrogateCodecType;\n            }\n            else\n            {\n                return null;\n            }\n\n            if (!_instantiatedBaseCopiers.TryGetValue(copierType, out var result))\n            {\n                result = _instantiatedBaseCopiers.GetOrAdd(copierType, GetServiceOrCreateInstance(copierType, constructorArguments));\n            }\n\n            return result;\n        }\n\n        private object GetActivatorInner(Type concreteType, Type searchType)\n        {\n            if (!_initialized) Initialize();\n\n            ThrowIfUnsupportedType(concreteType);\n\n            if (!_activators.TryGetValue(searchType, out var activatorType))\n            {\n                if (searchType.IsValueType)\n                {\n                    activatorType = typeof(DefaultValueTypeActivator<>).MakeGenericType(concreteType);\n                }\n                else\n                {\n                    activatorType = typeof(DefaultReferenceTypeActivator<>).MakeGenericType(concreteType);\n                }\n            }\n            else if (activatorType.IsGenericTypeDefinition)\n            {\n                activatorType = activatorType.MakeGenericType(concreteType.GetGenericArguments());\n            }\n\n            if (!_instantiatedActivators.TryGetValue(activatorType, out var result))\n            {\n                result = _instantiatedActivators.GetOrAdd(activatorType, GetServiceOrCreateInstance(activatorType));\n            }\n\n            return result;\n        }\n\n        private static void ThrowIfUnsupportedType(Type fieldType)\n        {\n            if (fieldType.IsGenericTypeDefinition)\n            {\n                ThrowGenericTypeDefinition(fieldType);\n            }\n\n            if (fieldType.IsPointer)\n            {\n                ThrowPointerType(fieldType);\n            }\n\n            if (fieldType.IsByRef)\n            {\n                ThrowByRefType(fieldType);\n            }\n        }\n\n        private object GetServiceOrCreateInstance(Type type, object[] constructorArguments = null)\n        {\n            var result = OrleansGeneratedCodeHelper.TryGetService(type);\n            if (result != null)\n            {\n                return result;\n            }\n\n            result = _serviceProvider.GetService(type);\n            if (result != null)\n            {\n                return result;\n            }\n\n            result = ActivatorUtilities.CreateInstance(_serviceProvider, type, constructorArguments ?? Array.Empty<object>());\n            return result;\n        }\n\n        private IFieldCodec CreateCodecInstance(Type fieldType, Type searchType)\n        {\n            if (searchType == ObjectType)\n                return _objectCodec;\n\n            object[] constructorArguments = null;\n            if (_fieldCodecs.TryGetValue(searchType, out var codecType))\n            {\n                if (codecType.IsGenericTypeDefinition)\n                {\n                    codecType = codecType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n            }\n            else if (_baseCodecs.TryGetValue(searchType, out var baseCodecType))\n            {\n                if (baseCodecType.IsGenericTypeDefinition)\n                {\n                    baseCodecType = baseCodecType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n\n                // If there is a base type serializer for this type, create a codec which will then accept that base type serializer.\n                codecType = typeof(ConcreteTypeSerializer<,>).MakeGenericType(fieldType, baseCodecType);\n                constructorArguments = new[] { GetServiceOrCreateInstance(baseCodecType) };\n            }\n            else if (_valueSerializers.TryGetValue(searchType, out var valueSerializerType))\n            {\n                if (valueSerializerType.IsGenericTypeDefinition)\n                {\n                    valueSerializerType = valueSerializerType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n\n                // If there is a value serializer for this type, create a codec which will then accept that value serializer.\n                codecType = typeof(ValueSerializer<,>).MakeGenericType(fieldType, valueSerializerType);\n                constructorArguments = new[] { GetServiceOrCreateInstance(valueSerializerType) };\n            }\n            else if (fieldType.IsArray)\n            {\n                // Depending on the type of the array, select the base array codec or the multi-dimensional codec.\n                var arrayCodecType = fieldType.IsSZArray ? typeof(ArrayCodec<>) : typeof(MultiDimensionalArrayCodec<>);\n                codecType = arrayCodecType.MakeGenericType(fieldType.GetElementType());\n            }\n            else if (fieldType.IsEnum)\n            {\n                return CreateCodecInstance(fieldType, fieldType.GetEnumUnderlyingType());\n            }\n            else if (TryGetSurrogateCodec(fieldType, searchType, out var surrogateCodecType, out constructorArguments))\n            {\n                // Use the converter\n                codecType = surrogateCodecType;\n            }\n            else if (searchType.BaseType is object\n                && CreateCodecInstance(\n                    fieldType.BaseType,\n                    searchType.BaseType switch\n                    {\n                        { IsConstructedGenericType: true } => searchType.BaseType.GetGenericTypeDefinition(),\n                        _ => searchType.BaseType\n                    }) is IDerivedTypeCodec fieldCodec)\n            {\n                // Find codecs which generalize over all subtypes.\n                return fieldCodec;\n            }\n\n            return codecType != null ? (IFieldCodec)GetServiceOrCreateInstance(codecType, constructorArguments) : null;\n        }\n\n        private bool TryGetSurrogateCodec(Type fieldType, Type searchType, out Type surrogateCodecType, out object[] constructorArguments)\n        {\n            if (_converters.TryGetValue(searchType, out var converterType))\n            {\n                if (converterType.IsGenericTypeDefinition)\n                {\n                    converterType = converterType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n\n                var converterInterfaceArgs = Array.Empty<Type>();\n                foreach (var @interface in converterType.GetInterfaces())\n                {\n                    if (@interface.IsConstructedGenericType && @interface.GetGenericTypeDefinition() == typeof(IConverter<,>)\n                        && @interface.GenericTypeArguments[0] == fieldType)\n                    {\n                        converterInterfaceArgs = @interface.GetGenericArguments();\n                    }\n                }\n\n                if (converterInterfaceArgs is { Length: 0 })\n                {\n                    throw new InvalidOperationException($\"A registered type converter {converterType} does not implement {typeof(IConverter<,>)}\");\n                }\n\n                var typeArgs = new Type[3] { converterInterfaceArgs[0], converterInterfaceArgs[1], converterType };\n                constructorArguments = new object[] { GetServiceOrCreateInstance(converterType) };\n                if (typeArgs[0].IsValueType)\n                {\n                    surrogateCodecType = typeof(ValueTypeSurrogateCodec<,,>).MakeGenericType(typeArgs);\n                }\n                else\n                {\n                    surrogateCodecType = typeof(SurrogateCodec<,,>).MakeGenericType(typeArgs);\n                }\n\n                return true;\n            }\n\n            surrogateCodecType = null;\n            constructorArguments = null;\n            return false;\n        }\n\n        private IBaseCodec CreateBaseCodecInstance(Type fieldType, Type searchType)\n        {\n            object[] constructorArguments = null;\n            if (_baseCodecs.TryGetValue(searchType, out var codecType))\n            {\n                if (codecType.IsGenericTypeDefinition)\n                {\n                    codecType = codecType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n            }\n            else if (TryGetSurrogateCodec(fieldType, searchType, out var surrogateCodecType, out constructorArguments) && typeof(IBaseCodec).IsAssignableFrom(surrogateCodecType))\n            {\n                codecType = surrogateCodecType;\n            }\n\n            return codecType != null ? (IBaseCodec)GetServiceOrCreateInstance(codecType, constructorArguments) : null;\n        }\n\n        private IDeepCopier CreateCopierInstance(Type fieldType, Type searchType)\n        {\n            if (searchType == ObjectType)\n                return _objectCopier;\n\n            object[] constructorArguments = null;\n            if (_copiers.TryGetValue(searchType, out var copierType))\n            {\n                if (copierType.IsGenericTypeDefinition)\n                {\n                    copierType = copierType.MakeGenericType(fieldType.GetGenericArguments());\n                }\n            }\n            else if (ShallowCopyableTypes.Contains(fieldType))\n            {\n                return ShallowCopier.Instance;\n            }\n            else if (fieldType.IsArray)\n            {\n                // Depending on the type of the array, select the base array copier or the multi-dimensional copier.\n                var arrayCopierType = fieldType.IsSZArray ? typeof(ArrayCopier<>) : typeof(MultiDimensionalArrayCopier<>);\n                copierType = arrayCopierType.MakeGenericType(fieldType.GetElementType());\n            }\n            else if (TryGetSurrogateCodec(fieldType, searchType, out var surrogateCodecType, out constructorArguments))\n            {\n                copierType = surrogateCodecType;\n            }\n            else if (searchType.BaseType is { } baseType)\n            {\n                // Find copiers which generalize over all subtypes.\n                if (CreateCopierInstance(fieldType, baseType) is IDerivedTypeCopier baseCopier)\n                {\n                    return baseCopier;\n                }\n                else if (baseType.IsGenericType\n                    && baseType.IsConstructedGenericType\n                    && CreateCopierInstance(fieldType, baseType.GetGenericTypeDefinition()) is IDerivedTypeCopier genericBaseCopier)\n                {\n                    return genericBaseCopier;\n                }\n            }\n\n            return copierType != null ? (IDeepCopier)GetServiceOrCreateInstance(copierType, constructorArguments) : null;\n        }\n\n        private static void ThrowPointerType(Type fieldType) => throw new NotSupportedException($\"Type {fieldType} is a pointer type and is therefore not supported.\");\n\n        private static void ThrowByRefType(Type fieldType) => throw new NotSupportedException($\"Type {fieldType} is a by-ref type and is therefore not supported.\");\n\n        private static void ThrowGenericTypeDefinition(Type fieldType) => throw new InvalidOperationException($\"Type {fieldType} is a non-constructed generic type and is therefore unsupported.\");\n\n        private static void ThrowCodecNotFound(Type fieldType) => throw new CodecNotFoundException($\"Could not find a codec for type {fieldType}.\");\n\n        private static void ThrowCopierNotFound(Type type) => throw new CodecNotFoundException($\"Could not find a copier for type {type}.\");\n\n        private static void ThrowBaseCodecNotFound(Type fieldType) => throw new KeyNotFoundException($\"Could not find a base type serializer for type {fieldType}.\");\n\n        private static void ThrowValueSerializerNotFound(Type fieldType) => throw new KeyNotFoundException($\"Could not find a value serializer for type {fieldType}.\");\n\n        private static void ThrowActivatorNotFound(Type type) => throw new KeyNotFoundException($\"Could not find an activator for type {type}.\");\n\n        private static void ThrowBaseCopierNotFound(Type type) => throw new KeyNotFoundException($\"Could not find a base type copier for type {type}.\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/ConcreteTypeSerializer.cs",
    "content": "using Orleans.Serialization.Activators;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Serializer for reference types which can be instantiated.\n    /// </summary>\n    /// <typeparam name=\"TField\">The field type.</typeparam>\n    /// <typeparam name=\"TBaseCodec\">The partial serializer implementation type.</typeparam>\n    public sealed class ConcreteTypeSerializer<TField, TBaseCodec> : IFieldCodec<TField> where TField : class where TBaseCodec : IBaseCodec<TField>\n    {\n        private readonly Type CodecFieldType = typeof(TField);\n        private readonly IActivator<TField> _activator;\n        private readonly TBaseCodec _serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConcreteTypeSerializer{TField, TBaseCodec}\"/> class.\n        /// </summary>\n        /// <param name=\"activator\">The activator.</param>\n        /// <param name=\"serializer\">The serializer.</param>\n        public ConcreteTypeSerializer(IActivator<TField> activator, TBaseCodec serializer)\n        {\n            _activator = activator;\n            _serializer = serializer;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (value is null || value.GetType() as object == CodecFieldType as object)\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n                {\n                    return;\n                }\n\n                writer.WriteStartObject(fieldIdDelta, expectedType, CodecFieldType);\n                _serializer.Serialize(ref writer, value);\n                writer.WriteEndObject();\n            }\n            else\n            {\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, value);\n            }\n        }\n\n        /// <inheritdoc/>\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<TField, TInput>(ref reader, field);\n            }\n\n            var fieldType = field.FieldType;\n            if (fieldType is null || fieldType == CodecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                _serializer.Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TInput, TField>(ref field);\n        }\n\n        public TField ReadValueSealed<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<TField, TInput>(ref reader, field);\n            }\n\n            var result = _activator.Create();\n            ReferenceCodec.RecordObject(reader.Session, result);\n            _serializer.Deserialize(ref reader, result);\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IActivatorProvider.cs",
    "content": "using Orleans.Serialization.Activators;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides activators.\n    /// </summary>\n    public interface IActivatorProvider\n    {\n        /// <summary>\n        /// Gets an activator for the specified type.\n        /// </summary>\n        /// <typeparam name=\"T\">The type.</typeparam>\n        /// <returns>The activator.</returns>\n        IActivator<T> GetActivator<T>();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IBaseCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Functionality for serializing and deserializing members in a type hierarchy.\n    /// </summary>\n    /// <typeparam name=\"T\">The type supported by this codec.</typeparam>\n    public interface IBaseCodec<in T> : IBaseCodec where T : class\n    {\n        /// <summary>\n        /// Serializes the provided value.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"value\">The value.</param>\n        void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, T value) where TBufferWriter : IBufferWriter<byte>;\n\n        /// <summary>\n        /// Deserializes into the provided value.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"value\">The value.</param>\n        void Deserialize<TInput>(ref Reader<TInput> reader, T value);\n    }\n\n    /// <summary>\n    /// Marker interface for base serializers.\n    /// </summary>\n    public interface IBaseCodec\n    {\n    }\n\n    /// <summary>\n    /// A base type serializer which supports multiple types.\n    /// </summary>\n    public interface IGeneralizedBaseCodec : IBaseCodec<object>\n    {\n        /// <summary>\n        /// Determines whether the specified type is supported by this instance.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the specified type is supported; otherwise, <see langword=\"false\" />.</returns>\n        bool IsSupportedType(Type type);\n    }\n\n    /// <summary>\n    /// Provides functionality for creating <see cref=\"IBaseCodec\"/> instances which support a given type.\n    /// </summary>\n    public interface ISpecializableBaseCodec\n    {\n        /// <summary>\n        /// Determines whether the specified type is supported by this instance.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the specified type is supported; otherwise, <see langword=\"false\" />.</returns>\n        bool IsSupportedType(Type type);\n\n        /// <summary>\n        /// Gets an <see cref=\"IBaseCodec\"/> implementation which supports the specified type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>An <see cref=\"IBaseCodec\"/> implementation which supports the specified type.</returns>\n        IBaseCodec GetSpecializedCodec(Type type);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IBaseCodecProvider.cs",
    "content": "namespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides access to <see cref=\"IBaseCodec{T}\"/> implementations.\n    /// </summary>\n    public interface IBaseCodecProvider\n    {\n        /// <summary>\n        /// Gets a base codec for the specified type.\n        /// </summary>\n        /// <typeparam name=\"TField\">The underlying field type.</typeparam>\n        /// <returns>A base codec.</returns>\n        IBaseCodec<TField> GetBaseCodec<TField>() where TField : class;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/ICodecProvider.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing System;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides functionality for accessing codecs, activators, and copiers.\n    /// </summary>\n    public interface ICodecProvider :\n        IFieldCodecProvider,\n        IBaseCodecProvider,\n        IValueSerializerProvider,\n        IActivatorProvider,\n        IDeepCopierProvider\n    {\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        /// <value>The service provider.</value>\n        IServiceProvider Services { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/ICodecSelector.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization.Serializers;\n\n/// <summary>\n/// Functionality used by general-purpose codecs (such as a JSON codec) to allow types to opt-in to using them.\n/// </summary>\npublic interface ICodecSelector\n{\n    /// <summary>\n    /// The well-known codec name, used to match an instance with a codec.\n    /// </summary>\n    public string CodecName { get; }\n\n    /// <summary>\n    /// Returns true if the specified codec should be used for this type.\n    /// </summary>\n    public bool IsSupportedType(Type type);\n}\n\n/// <summary>\n/// Functionality used by general-purpose copiers (such as a JSON copier) to allow types to opt-in to using them.\n/// </summary>\npublic interface ICopierSelector\n{\n    /// <summary>\n    /// The well-known copier name, used to match an instance with a copier.\n    /// </summary>\n    public string CopierName { get; }\n\n    /// <summary>\n    /// Returns true if the specified copier should be used for this type.\n    /// </summary>\n    public bool IsSupportedType(Type type);\n}\n\n/// <summary>\n/// Implementation of <see cref=\"ICodecSelector\"/> which uses a delegate.\n/// </summary>\npublic sealed class DelegateCodecSelector : ICodecSelector\n{\n    public string CodecName { get; init; }\n\n    public Func<Type, bool> IsSupportedTypeDelegate { get; init; }\n\n    public bool IsSupportedType(Type type) => IsSupportedTypeDelegate(type);\n}\n\n/// <summary>\n/// Implementation of <see cref=\"ICopierSelector\"/> which uses a delegate.\n/// </summary>\npublic sealed class DelegateCopierSelector : ICopierSelector\n{\n    public string CopierName { get; init; }\n\n    public Func<Type, bool> IsSupportedTypeDelegate { get; init; }\n\n    public bool IsSupportedType(Type type) => IsSupportedTypeDelegate(type);\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IFieldCodecProvider.cs",
    "content": "#nullable enable\nusing Orleans.Serialization.Codecs;\nusing System;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides access to field codecs.\n    /// </summary>\n    public interface IFieldCodecProvider\n    {\n        /// <summary>\n        /// Gets a codec for the specified type.\n        /// </summary>\n        /// <typeparam name=\"TField\">The field type.</typeparam>\n        /// <returns>A codec.</returns>\n        IFieldCodec<TField> GetCodec<TField>();\n\n        /// <summary>\n        /// Gets a codec for the specific type, or <see langword=\"null\"/> if no appropriate codec was found.\n        /// </summary>\n        /// <typeparam name=\"TField\">The field type.</typeparam>\n        /// <returns>A codec.</returns>\n        IFieldCodec<TField> TryGetCodec<TField>();\n\n        /// <summary>\n        /// Gets a codec for the specific type.\n        /// </summary>\n        /// <param name=\"fieldType\">\n        /// The field type.\n        /// </param>\n        /// <returns>A codec.</returns>\n        IFieldCodec GetCodec(Type fieldType);\n\n        /// <summary>\n        /// Gets a codec for the specific type, or <see langword=\"null\"/> if no appropriate codec was found.\n        /// </summary>\n        /// <param name=\"fieldType\">\n        /// The field type.\n        /// </param>\n        /// <returns>A codec.</returns>\n        IFieldCodec TryGetCodec(Type fieldType);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IGeneralizedCodec.cs",
    "content": "using System;\nusing Orleans.Serialization.Codecs;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// A codec which supports multiple types.\n    /// </summary>\n    public interface IGeneralizedCodec : IFieldCodec\n    {\n        /// <summary>\n        /// Determines whether the specified type is supported by this instance.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the specified type is supported; otherwise, <see langword=\"false\" />.</returns>\n        bool IsSupportedType(Type type);\n    }\n\n    /// <summary>\n    /// Provides access to codecs for multiple types.\n    /// </summary>\n    public interface ISpecializableCodec\n    {\n        /// <summary>\n        /// Determines whether the specified type is supported by this instance.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the specified type is supported; otherwise, <see langword=\"false\" />.</returns>\n        bool IsSupportedType(Type type);\n\n        /// <summary>\n        /// Gets an <see cref=\"IFieldCodec\"/> implementation which supports the specified type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>An <see cref=\"IFieldCodec\"/> implementation which supports the specified type.</returns>\n        IFieldCodec GetSpecializedCodec(Type type);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IValueSerializer.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Functionality for serializing a value type.\n    /// </summary>\n    /// <typeparam name=\"T\">The value type.</typeparam>\n    public interface IValueSerializer<T> : IValueSerializer where T : struct\n    {\n        /// <summary>\n        /// Serializes the provided value.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"value\">The value.</param>\n        void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, scoped ref T value) where TBufferWriter : IBufferWriter<byte>;\n\n        /// <summary>\n        /// Deserializes the specified type.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"value\">The value.</param>\n        void Deserialize<TInput>(ref Reader<TInput> reader, scoped ref T value);\n    }\n\n    /// <summary>\n    /// Marker interface for value type serializers.\n    /// </summary>\n    public interface IValueSerializer\n    {\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/IValueSerializerProvider.cs",
    "content": "namespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Provides access to value type serializers.\n    /// </summary>\n    public interface IValueSerializerProvider\n    {\n        /// <summary>\n        /// Gets the value serializer for the specified type.\n        /// </summary>\n        /// <typeparam name=\"TField\">The value type.</typeparam>\n        /// <returns>A value serializer for the specified type.</returns>\n        IValueSerializer<TField> GetValueSerializer<TField>() where TField : struct;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/SurrogateCodec.cs",
    "content": "﻿#nullable enable\nusing System;\nusing System.Buffers;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization.Serializers;\n\n/// <summary>\n/// Surrogate serializer for <typeparamref name=\"TField\"/>.\n/// </summary>\n/// <typeparam name=\"TField\">The type which the implementation of this class supports.</typeparam>\n/// <typeparam name=\"TSurrogate\">The surrogate type serialized in place of <typeparamref name=\"TField\"/>.</typeparam>\n/// <typeparam name=\"TConverter\">The converter type which converts between <typeparamref name=\"TField\"/> and <typeparamref name=\"TSurrogate\"/>.</typeparam>\npublic sealed class SurrogateCodec<TField, TSurrogate, TConverter>\n    : IFieldCodec<TField>, IDeepCopier<TField>, IBaseCodec<TField>, IBaseCopier<TField>\n    where TField : class\n    where TSurrogate : struct\n    where TConverter : IConverter<TField, TSurrogate>\n{\n    private readonly Type _fieldType = typeof(TField);\n    private readonly IValueSerializer<TSurrogate> _surrogateSerializer;\n    private readonly IDeepCopier<TSurrogate> _surrogateCopier;\n    private readonly IPopulator<TField, TSurrogate>? _populator;\n    private readonly TConverter _converter;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"SurrogateCodec{TField, TSurrogate, TConverter}\"/> class.\n    /// </summary>\n    /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n    /// <param name=\"surrogateCopier\">The surrogate copier.</param>\n    /// <param name=\"converter\">The surrogate converter.</param>\n    public SurrogateCodec(\n        IValueSerializer<TSurrogate> surrogateSerializer,\n        IDeepCopier<TSurrogate> surrogateCopier,\n        TConverter converter)\n    {\n        _surrogateSerializer = surrogateSerializer;\n        _surrogateCopier = surrogateCopier;\n        _converter = converter;\n        _populator = converter as IPopulator<TField, TSurrogate>;\n    }\n\n    /// <inheritdoc/>\n    public TField DeepCopy(TField input, CopyContext context)\n    {\n        if (context.TryGetCopy<TField>(input, out var result))\n        {\n            return result!;\n        }\n\n        var surrogate = _converter.ConvertToSurrogate(in input);\n        var copy = _surrogateCopier.DeepCopy(surrogate, context);\n        result = _converter.ConvertFromSurrogate(in copy);\n\n        context.RecordCopy(input, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<TField, TInput>(ref reader, field);\n        }\n\n        if (field.FieldType is null || field.FieldType == _fieldType)\n        {\n            field.EnsureWireTypeTagDelimited();\n\n            uint placeholderReferenceId = default;\n            if (IsReferenceTrackingSupported)\n            {\n                placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            }\n\n            TSurrogate surrogate = default;\n            _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n            var result = _converter.ConvertFromSurrogate(in surrogate);\n\n            if (IsReferenceTrackingSupported)\n            {\n                ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            }\n\n            return result;\n        }\n\n        return reader.DeserializeUnexpectedType<TInput, TField>(ref field);\n    }\n\n    /// <inheritdoc/>\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (IsReferenceTrackingSupported && ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        if (value.GetType() as object == _fieldType as object)\n        {\n            writer.WriteStartObject(fieldIdDelta, expectedType, _fieldType);\n            var surrogate = _converter.ConvertToSurrogate(in value);\n            _surrogateSerializer.Serialize(ref writer, ref surrogate);\n            writer.WriteEndObject();\n        }\n        else\n        {\n            writer.SerializeUnexpectedType(fieldIdDelta, expectedType, value);\n        }\n    }\n\n    private bool IsReferenceTrackingSupported => typeof(TField) != typeof(Exception) && !typeof(TField).IsSubclassOf(typeof(Exception));\n\n    /// <inheritdoc/>\n    public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, TField value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (_populator is null) ThrowNoPopulatorException();\n\n        var surrogate = _converter.ConvertToSurrogate(in value);\n        _surrogateSerializer.Serialize(ref writer, ref surrogate);\n    }\n\n    /// <inheritdoc/>\n    public void Deserialize<TInput>(ref Reader<TInput> reader, TField value)\n    {\n        if (_populator is null) ThrowNoPopulatorException();\n\n        TSurrogate surrogate = default;\n        _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n        _populator.Populate(surrogate, value);\n    }\n\n    /// <inheritdoc/>\n    public void DeepCopy(TField input, TField output, CopyContext context)\n    {\n        if (_populator is null) ThrowNoPopulatorException();\n\n        var surrogate = _converter.ConvertToSurrogate(in input);\n        var copy = _surrogateCopier.DeepCopy(surrogate, context);\n        _populator.Populate(copy, output);\n    }\n\n    [DoesNotReturn]\n    private void ThrowNoPopulatorException() => throw new NotSupportedException($\"Surrogate type {typeof(TConverter)} does not implement {typeof(IPopulator<TField, TSurrogate>)} and therefore cannot be used in an inheritance hierarchy.\");\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/ValueSerializer.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\n\nnamespace Orleans.Serialization.Serializers\n{\n    /// <summary>\n    /// Serializer for value types.\n    /// </summary>\n    /// <typeparam name=\"TField\">The field type.</typeparam>\n    /// <typeparam name=\"TValueSerializer\">The value-type serializer implementation type.</typeparam>\n    public sealed class ValueSerializer<TField, TValueSerializer> : IFieldCodec<TField> where TField : struct where TValueSerializer : IValueSerializer<TField>\n    {\n        private readonly Type CodecFieldType = typeof(TField);\n        private readonly TValueSerializer _serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ValueSerializer{TField, TValueSerializer}\"/> class.\n        /// </summary>\n        /// <param name=\"serializer\">The serializer.</param>\n        public ValueSerializer(TValueSerializer serializer)\n        {\n            _serializer = serializer;\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, CodecFieldType);\n            _serializer.Serialize(ref writer, ref value);\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            ReferenceCodec.MarkValueField(reader.Session);\n            var value = default(TField);\n            _serializer.Deserialize(ref reader, ref value);\n            return value;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Serializers/ValueTypeSurrogateCodec.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Serializers;\n\n/// <summary>\n/// Surrogate serializer for <typeparamref name=\"TField\"/>.\n/// </summary>\n/// <typeparam name=\"TField\">The type which the implementation of this class supports.</typeparam>\n/// <typeparam name=\"TSurrogate\">The surrogate type serialized in place of <typeparamref name=\"TField\"/>.</typeparam>\n/// <typeparam name=\"TConverter\">The converter type which converts between <typeparamref name=\"TField\"/> and <typeparamref name=\"TSurrogate\"/>.</typeparam>\npublic sealed class ValueTypeSurrogateCodec<TField, TSurrogate, TConverter>\n    : IFieldCodec<TField>, IDeepCopier<TField>, IValueSerializer<TField>\n    where TField : struct\n    where TSurrogate : struct\n    where TConverter : IConverter<TField, TSurrogate>\n{\n    private readonly IValueSerializer<TSurrogate> _surrogateSerializer;\n    private readonly IDeepCopier<TSurrogate> _surrogateCopier;\n    private readonly TConverter _converter;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ValueTypeSurrogateCodec{TField, TSurrogate, TConverter}\"/> class.\n    /// </summary>\n    /// <param name=\"surrogateSerializer\">The surrogate serializer.</param>\n    /// <param name=\"surrogateCopier\">The surrogate copier.</param>\n    /// <param name=\"converter\">The surrogate converter.</param>\n    public ValueTypeSurrogateCodec(\n        IValueSerializer<TSurrogate> surrogateSerializer,\n        IDeepCopier<TSurrogate> surrogateCopier,\n        TConverter converter)\n    {\n        _surrogateSerializer = surrogateSerializer;\n        _surrogateCopier = surrogateCopier;\n        _converter = converter;\n    }\n\n    /// <inheritdoc/>\n    public TField DeepCopy(TField input, CopyContext context)\n    {\n        var surrogate = _converter.ConvertToSurrogate(in input);\n        var copy = _surrogateCopier.DeepCopy(surrogate, context);\n        var result = _converter.ConvertFromSurrogate(in copy);\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Deserialize<TInput>(ref Reader<TInput> reader, scoped ref TField value)\n    {\n        TSurrogate surrogate = default;\n        _surrogateSerializer.Deserialize(ref reader, ref surrogate);\n        value = _converter.ConvertFromSurrogate(in surrogate);\n    }\n\n    /// <inheritdoc/>\n    public TField ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        field.EnsureWireTypeTagDelimited();\n        ReferenceCodec.MarkValueField(reader.Session);\n        TField result = default;\n        Deserialize(ref reader, ref result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, scoped ref TField value) where TBufferWriter : IBufferWriter<byte>\n    {\n        var surrogate = _converter.ConvertToSurrogate(in value);\n        _surrogateSerializer.Serialize(ref writer, ref surrogate);\n    }\n\n    /// <inheritdoc/>\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, TField value) where TBufferWriter : IBufferWriter<byte>\n    {\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteStartObject(fieldIdDelta, expectedType, typeof(TField));\n        Serialize(ref writer, ref value);\n        writer.WriteEndObject();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/Session/ReferencedObjectCollection.cs",
    "content": "using Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Utilities;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\n#if NET6_0_OR_GREATER\nusing System.Reflection.Metadata;\n#endif\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Serialization.Session\n{\n    /// <summary>\n    /// A collection of objects which are referenced while serializing, deserializing, or copying.\n    /// </summary>\n    public sealed class ReferencedObjectCollection\n    {\n        private struct ReferencePair\n        {\n            public ReferencePair(uint id, object @object)\n            {\n                Id = id;\n                Object = @object;\n            }\n\n            public uint Id;\n            public object Object;\n        }\n\n        /// <summary>\n        /// Gets or sets the reference to object count.\n        /// </summary>\n        /// <value>The reference to object count.</value>\n        internal int ReferenceToObjectCount;\n        private readonly ReferencePair[] _referenceToObject = new ReferencePair[64];\n\n        private int _objectToReferenceCount;\n        private readonly ReferencePair[] _objectToReference = new ReferencePair[64];\n\n        private Dictionary<uint, object> _referenceToObjectOverflow;\n        private Dictionary<object, uint> _objectToReferenceOverflow;\n        private uint _currentReferenceId;\n\n        /// <summary>\n        /// Tries to get the referenced object with the specified id.\n        /// </summary>\n        /// <param name=\"reference\">The reference.</param>\n        /// <returns>The referenced object with the specified id if found, <see langword=\"null\" /> otherwise.</returns>\n        public object TryGetReferencedObject(uint reference)\n        {\n            var refs = _referenceToObject.AsSpan(0, ReferenceToObjectCount);\n            for (int i = 0; i < refs.Length; ++i)\n            {\n                if (refs[i].Id == reference)\n                    return refs[i].Object;\n            }\n\n            if (_referenceToObjectOverflow is { } overflow && overflow.TryGetValue(reference, out var value))\n                return value;\n\n            return null;\n        }\n\n        /// <summary>\n        /// Marks a value field.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void MarkValueField() => ++_currentReferenceId;\n\n        internal uint CreateRecordPlaceholder() => ++_currentReferenceId;\n\n        /// <summary>\n        /// Gets or adds a reference.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"reference\">The reference.</param>\n        /// <returns><see langword=\"true\" /> if a reference already existed, <see langword=\"false\" /> otherwise.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool GetOrAddReference(object value, out uint reference)\n        {\n            // Unconditionally bump the reference counter since a call to this method signifies a potential reference.\n            var nextReference = ++_currentReferenceId;\n\n            // Null is always at reference 0\n            if (value is null)\n            {\n                reference = 0;\n                return true;\n            }\n\n            var objects = _objectToReference.AsSpan(0, _objectToReferenceCount);\n            for (int i = 0; i < objects.Length; ++i)\n            {\n                if (objects[i].Object == value)\n                {\n                    reference = objects[i].Id;\n                    return true;\n                }\n            }\n\n            if (_objectToReferenceOverflow is { } overflow)\n            {\n#if NET6_0_OR_GREATER\n                ref var refValue = ref CollectionsMarshal.GetValueRefOrAddDefault(overflow, value, out var exists);\n                if (exists)\n                {\n                    reference = refValue;\n                    return true;\n                }\n\n                refValue = nextReference;\n                Unsafe.SkipInit(out reference);\n                return false;\n#else\n                if (overflow.TryGetValue(value, out var existing))\n                {\n                    reference = existing;\n                    return true;\n                }\n                else\n                {\n                    overflow[value] = nextReference;\n                    Unsafe.SkipInit(out reference);\n                    return false;\n                }\n#endif\n            }\n\n            // Add the reference.\n            var objectsArray = _objectToReference;\n            var objectsCount = _objectToReferenceCount;\n            if ((uint)objectsCount < (uint)objectsArray.Length)\n            {\n                _objectToReferenceCount = objectsCount + 1;\n                objectsArray[objectsCount].Id = nextReference;\n                objectsArray[objectsCount].Object = value;\n            }\n            else\n            {\n                CreateObjectToReferenceOverflow(value);\n            }\n\n            Unsafe.SkipInit(out reference);\n            return false;\n        }\n\n        /// <summary>\n        /// Gets the index of the reference, or <c>-1</c> if the object has not been encountered before.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The index of the reference, or <c>-1</c> if the object has not been encountered before.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public int GetReferenceIndex(object value)\n        {\n            if (value is null)\n            {\n                return -1;\n            }\n\n            var refs = _referenceToObject.AsSpan(0, ReferenceToObjectCount);\n            for (int i = 0; i < refs.Length; ++i)\n            {\n                if (refs[i].Object == value)\n                {\n                    return i;\n                }\n            }\n\n            return -1;\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void CreateObjectToReferenceOverflow(object value)\n        {\n            var result = new Dictionary<object, uint>(_objectToReferenceCount * 2, ReferenceEqualsComparer.Default);\n            var objects = _objectToReference;\n            for (var i = 0; i < objects.Length; i++)\n            {\n                var record = objects[i];\n                result[record.Object] = record.Id;\n                objects[i] = default;\n            }\n\n            result[value] = _currentReferenceId;\n\n            _objectToReferenceCount = 0;\n            _objectToReferenceOverflow = result;\n        }\n\n        private void AddToReferences(object value, uint reference)\n        {\n            if (_referenceToObjectOverflow is { } overflow)\n            {\n#if NET6_0_OR_GREATER\n                ref var refValue = ref CollectionsMarshal.GetValueRefOrAddDefault(overflow, reference, out var exists);\n                if (exists && value is not UnknownFieldMarker && refValue is not UnknownFieldMarker)\n                {\n                    // Unknown field markers can be replaced once the type is known.\n                    ThrowReferenceExistsException(reference);\n                }\n\n                refValue = value;\n#else\n                if (overflow.TryGetValue(reference, out var existing) && value is not UnknownFieldMarker && existing is not UnknownFieldMarker)\n                {\n                    // Unknown field markers can be replaced once the type is known.\n                    ThrowReferenceExistsException(reference);\n                }\n\n                overflow[reference] = value;\n#endif\n            }\n            else\n            {\n                var refs = _referenceToObject.AsSpan(0, ReferenceToObjectCount);\n                for (var i = 0; i < refs.Length; i++)\n                {\n                    if (refs[i].Id == reference)\n                    {\n                        if (value is not UnknownFieldMarker && refs[i].Object is not UnknownFieldMarker)\n                        {\n                            // Unknown field markers can be replaced once the type is known.\n                            ThrowReferenceExistsException(reference);\n                        }\n                        refs[i].Object = value;\n                        return;\n                    }\n                }\n\n                _referenceToObject[ReferenceToObjectCount++] = new ReferencePair(reference, value);\n\n                if (ReferenceToObjectCount >= _referenceToObject.Length)\n                {\n                    CreateReferenceToObjectOverflow();\n                }\n            }\n\n            [MethodImpl(MethodImplOptions.NoInlining)]\n            void CreateReferenceToObjectOverflow()\n            {\n                var result = new Dictionary<uint, object>(ReferenceToObjectCount * 2);\n                var refs = _referenceToObject.AsSpan(0, ReferenceToObjectCount);\n                for (var i = 0; i < refs.Length; i++)\n                {\n                    var record = refs[i];\n                    result[record.Id] = record.Object;\n                    refs[i] = default;\n                }\n\n                ReferenceToObjectCount = 0;\n                _referenceToObjectOverflow = result;\n            }\n        }\n\n        [DoesNotReturn]\n        private static void ThrowReferenceExistsException(uint reference) => throw new InvalidOperationException($\"Reference {reference} already exists\");\n\n        /// <summary>\n        /// Records a reference field.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void RecordReferenceField(object value) => RecordReferenceField(value, ++_currentReferenceId);\n\n        /// <summary>\n        /// Records a reference field with the specified identifier.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"referenceId\">The reference identifier.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void RecordReferenceField(object value, uint referenceId)\n        {\n            if (value is null)\n            {\n                return;\n            }\n\n            AddToReferences(value, referenceId);\n        }\n\n        /// <summary>\n        /// Copies the reference table.\n        /// </summary>\n        /// <returns>A copy of the reference table.</returns>\n        public Dictionary<uint, object> CopyReferenceTable() => _referenceToObject.Take(ReferenceToObjectCount).ToDictionary(r => r.Id, r => r.Object);\n\n        /// <summary>\n        /// Copies the identifier table.\n        /// </summary>\n        /// <returns>A copy of the identifier table.</returns>\n        public Dictionary<object, uint> CopyIdTable() => _objectToReference.Take(_objectToReferenceCount).ToDictionary(r => r.Object, r => r.Id);\n\n        /// <summary>\n        /// Gets or sets the current reference identifier.\n        /// </summary>\n        /// <value>The current reference identifier.</value>\n        public uint CurrentReferenceId { get => _currentReferenceId; set => _currentReferenceId = value; }\n\n        /// <summary>\n        /// Resets this instance.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Reset()\n        {\n            _referenceToObject.AsSpan(0, ReferenceToObjectCount).Clear();\n            _objectToReference.AsSpan(0, _objectToReferenceCount).Clear();\n\n            ReferenceToObjectCount = 0;\n            _objectToReferenceCount = 0;\n            CurrentReferenceId = 0;\n\n            _referenceToObjectOverflow = null;\n            _objectToReferenceOverflow = null;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Session/ReferencedTypeCollection.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Serialization.Session\n{\n    /// <summary>\n    /// Collection of referenced <see cref=\"Type\"/> instances.\n    /// </summary>\n    public sealed class ReferencedTypeCollection\n    {\n        private readonly Dictionary<uint, Type> _referencedTypes = new();\n        private readonly Dictionary<Type, uint> _referencedTypeToIdMap = new();\n\n        private uint _currentReferenceId;\n\n        /// <summary>\n        /// Gets the type with the specified reference id.\n        /// </summary>\n        /// <param name=\"reference\">The reference id.</param>\n        /// <returns>The referenced type.</returns>\n        public Type GetReferencedType(uint reference)\n        {\n            if (!_referencedTypes.TryGetValue(reference, out var type))\n                ThrowUnknownReferencedType(reference);\n            return type;\n        }\n\n        private static void ThrowUnknownReferencedType(uint id) => throw new UnknownReferencedTypeException(id);\n\n        /// <summary>\n        /// Gets the type with the specified reference id.\n        /// </summary>\n        /// <param name=\"reference\">The reference id.</param>\n        /// <param name=\"type\">The referenced type.</param>\n        /// <returns><see langword=\"true\" /> if the referenced type was found, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryGetReferencedType(uint reference, out Type type) => _referencedTypes.TryGetValue(reference, out type);\n\n        /// <summary>\n        /// Records a type with the specified identifier.\n        /// </summary>\n        public void RecordReferencedType(Type type) => _referencedTypes.Add(++_currentReferenceId, type);\n\n        /// <summary>\n        /// Gets the identifier for the specified type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"reference\">The reference.</param>\n        /// <returns><see langword=\"true\" /> if the type has been previoulsy referenced, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryGetTypeReference(Type type, out uint reference) => _referencedTypeToIdMap.TryGetValue(type, out reference);\n\n        /// <summary>\n        /// Gets or adds the identifier for the specified type.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public uint GetOrAddTypeReference(Type type)\n        {\n#if NET6_0_OR_GREATER\n            ref var refValue = ref CollectionsMarshal.GetValueRefOrAddDefault(_referencedTypeToIdMap, type, out var exists);\n            if (exists)\n                return refValue;\n\n            refValue = ++_currentReferenceId;\n#else\n            if (_referencedTypeToIdMap.TryGetValue(type, out var existing))\n            {\n                return existing;\n            }\n            else\n            {\n                _referencedTypeToIdMap[type] = ++_currentReferenceId;\n            }\n#endif\n            return 0;\n        }\n\n        /// <summary>\n        /// Resets this instance.\n        /// </summary>\n        public void Reset()\n        {\n            _currentReferenceId = 0;\n            _referencedTypes.Clear();\n            _referencedTypeToIdMap.Clear();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Session/SerializerSession.cs",
    "content": "using Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing System;\n\nnamespace Orleans.Serialization.Session\n{\n    /// <summary>\n    /// Contextual information for a serializer operation.\n    /// </summary>\n    public sealed class SerializerSession : IDisposable\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerSession\"/> class.\n        /// </summary>\n        /// <param name=\"typeCodec\">The type codec.</param>\n        /// <param name=\"wellKnownTypes\">The well known types.</param>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        public SerializerSession(TypeCodec typeCodec, WellKnownTypeCollection wellKnownTypes, CodecProvider codecProvider)\n        {\n            TypeCodec = typeCodec;\n            WellKnownTypes = wellKnownTypes;\n            CodecProvider = codecProvider;\n        }\n\n        /// <summary>\n        /// Gets the type codec.\n        /// </summary>\n        /// <value>The type codec.</value>\n        public TypeCodec TypeCodec { get; }\n\n        /// <summary>\n        /// Gets the well known types collection.\n        /// </summary>\n        /// <value>The well known types collection.</value>\n        public WellKnownTypeCollection WellKnownTypes { get; }\n\n        /// <summary>\n        /// Gets the referenced type collection.\n        /// </summary>\n        /// <value>The referenced type collection.</value>\n        public ReferencedTypeCollection ReferencedTypes { get; } = new ReferencedTypeCollection();\n\n        /// <summary>\n        /// Gets the referenced object collection.\n        /// </summary>\n        /// <value>The referenced object collection.</value>\n        public ReferencedObjectCollection ReferencedObjects { get; } = new ReferencedObjectCollection();\n\n        /// <summary>\n        /// Gets the codec provider.\n        /// </summary>\n        /// <value>The codec provider.</value>\n        public CodecProvider CodecProvider { get; }\n\n        internal Action<SerializerSession> OnDisposed { get; set; }\n\n        /// <summary>\n        /// Resets the referenced objects collection.\n        /// </summary>\n        public void PartialReset() => ReferencedObjects.Reset();\n\n        /// <summary>\n        /// Performs a full reset.\n        /// </summary>\n        public void Reset()\n        {\n            ReferencedObjects.Reset();\n            ReferencedTypes.Reset();\n        }\n\n        public void Dispose() => OnDisposed?.Invoke(this);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Session/SerializerSessionPool.cs",
    "content": "using Microsoft.Extensions.ObjectPool;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing System;\n\nnamespace Orleans.Serialization.Session\n{\n    /// <summary>\n    /// Pool for <see cref=\"SerializerSession\"/> objects.\n    /// </summary>\n    public sealed class SerializerSessionPool\n    {\n        private readonly ObjectPool<SerializerSession> _sessionPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SerializerSessionPool\"/> class.\n        /// </summary>\n        /// <param name=\"typeCodec\">The type codec.</param>\n        /// <param name=\"wellKnownTypes\">The well known type collection.</param>\n        /// <param name=\"codecProvider\">The codec provider.</param>\n        public SerializerSessionPool(TypeCodec typeCodec, WellKnownTypeCollection wellKnownTypes, CodecProvider codecProvider)\n        {\n            CodecProvider = codecProvider;\n            var sessionPoolPolicy = new SerializerSessionPoolPolicy(typeCodec, wellKnownTypes, codecProvider, ReturnSession);\n            _sessionPool = new ConcurrentObjectPool<SerializerSession, SerializerSessionPoolPolicy>(sessionPoolPolicy);\n        }\n\n        /// <summary>\n        /// Gets the codec provider.\n        /// </summary>\n        public CodecProvider CodecProvider { get; }\n\n        /// <summary>\n        /// Gets a serializer session from the pool.\n        /// </summary>\n        /// <returns>A serializer session.</returns>\n        public SerializerSession GetSession() => _sessionPool.Get();\n\n        /// <summary>\n        /// Returns a session to the pool.\n        /// </summary>\n        /// <param name=\"session\">The session.</param>\n        private void ReturnSession(SerializerSession session) => _sessionPool.Return(session);\n\n        private readonly struct SerializerSessionPoolPolicy : IPooledObjectPolicy<SerializerSession>\n        {\n            private readonly TypeCodec _typeCodec;\n            private readonly WellKnownTypeCollection _wellKnownTypes;\n            private readonly CodecProvider _codecProvider;\n            private readonly Action<SerializerSession> _onSessionDisposed;\n\n            public SerializerSessionPoolPolicy(TypeCodec typeCodec, WellKnownTypeCollection wellKnownTypes, CodecProvider codecProvider, Action<SerializerSession> onSessionDisposed)\n            {\n                _typeCodec = typeCodec;\n                _wellKnownTypes = wellKnownTypes;\n                _codecProvider = codecProvider;\n                _onSessionDisposed = onSessionDisposed;\n            }\n\n            public SerializerSession Create()\n            {\n                return new SerializerSession(_typeCodec, _wellKnownTypes, _codecProvider)\n                {\n                    OnDisposed = _onSessionDisposed\n                };\n            }\n\n            public bool Return(SerializerSession obj)\n            {\n                obj.Reset();\n                return true;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Session/WellKnownTypeCollection.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Serialization.Configuration;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Serialization.Session\n{\n    /// <summary>\n    /// Collection of well-known types.\n    /// </summary>\n    public sealed class WellKnownTypeCollection\n    {\n        private readonly Dictionary<uint, Type> _wellKnownTypes;\n        private readonly Dictionary<Type, uint> _wellKnownTypeToIdMap;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"WellKnownTypeCollection\"/> class.\n        /// </summary>\n        /// <param name=\"config\">The configuration.</param>\n        public WellKnownTypeCollection(IOptions<TypeManifestOptions> config)\n        {\n            _wellKnownTypes = config?.Value.WellKnownTypeIds ?? throw new ArgumentNullException(nameof(config));\n            _wellKnownTypeToIdMap = new Dictionary<Type, uint>(_wellKnownTypes.Count);\n            foreach (var item in _wellKnownTypes)\n            {\n                _wellKnownTypeToIdMap[item.Value] = item.Key;\n            }\n        }\n\n        /// <summary>\n        /// Gets the type corresponding to the provided type identifier.\n        /// </summary>\n        /// <param name=\"typeId\">The type identifier.</param>\n        /// <returns>A type.</returns>\n        public Type GetWellKnownType(uint typeId)\n        {\n            if (typeId == 0)\n            {\n                return null;\n            }\n\n            return _wellKnownTypes[typeId];\n        }\n\n        /// <summary>\n        /// Tries to get the type corresponding to the provided type identifier.\n        /// </summary>\n        /// <param name=\"typeId\">The type identifier.</param>\n        /// <param name=\"type\">The type.</param>\n        /// <returns><see langword=\"true\" /> if the corresponding type was found, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryGetWellKnownType(uint typeId, [NotNullWhen(true)] out Type type)\n        {\n            if (typeId == 0)\n            {\n                type = null;\n                return true;\n            }\n\n            return _wellKnownTypes.TryGetValue(typeId, out type);\n        }\n\n        /// <summary>\n        /// Tries the get the type identifier corresponding to the provided type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"typeId\">The type identifier.</param>\n        /// <returns><see langword=\"true\" /> if the type has a well-known identifier, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryGetWellKnownTypeId(Type type, out uint typeId) => _wellKnownTypeToIdMap.TryGetValue(type, out typeId);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/CachedTypeResolver.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Reflection;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Type resolver which caches results.\n    /// </summary>\n    public sealed class CachedTypeResolver : TypeResolver\n    {\n        private readonly ConcurrentDictionary<string, Type> _typeCache = new();\n        private readonly ConcurrentDictionary<string, Assembly> _assemblyCache = new();\n        private static readonly ConcurrentDictionary<Assembly, string> _assemblyNameCache = new();\n\n        /// <summary>\n        /// Gets the cached assembly name.\n        /// </summary>\n        public static string GetName(Assembly assembly) => _assemblyNameCache.GetOrAdd(assembly, a => a.GetName().Name);\n\n        /// <inheritdoc />\n        public override Type ResolveType(string name)\n        {\n            if (TryResolveType(name, out var result))\n            {\n                return result;\n            }\n\n            throw new TypeAccessException($\"Unable to find a type named {name}\");\n        }\n\n        /// <inheritdoc />\n        public override bool TryResolveType(string name, out Type type)\n        {\n            if (string.IsNullOrWhiteSpace(name))\n            {\n                throw new ArgumentException(\"A FullName must not be null nor consist of only whitespace.\", nameof(name));\n            }\n\n            if (TryGetCachedType(name, out type))\n            {\n                return true;\n            }\n\n            if (!TryPerformUncachedTypeResolution(name, out type))\n            {\n                return false;\n            }\n\n            AddTypeToCache(name, type);\n            return true;\n        }\n\n        private bool TryPerformUncachedTypeResolution(string name, out Type type)\n        {\n            var assemblies = AppDomain.CurrentDomain.GetAssemblies();\n            if (!TryPerformUncachedTypeResolution(name, out type, assemblies))\n            {\n                return false;\n            }\n\n            if (type.Assembly.ReflectionOnly)\n            {\n                throw new InvalidOperationException($\"Type resolution for {name} yielded reflection-only type.\");\n            }\n\n            return true;\n        }\n\n        private bool TryGetCachedType(string name, out Type result)\n        {\n            if (string.IsNullOrWhiteSpace(name))\n            {\n                throw new ArgumentException(\"type name was null or whitespace\");\n            }\n\n            return _typeCache.TryGetValue(name, out result);\n        }\n\n        private void AddTypeToCache(string name, Type type)\n        {\n            var entry = _typeCache.GetOrAdd(name, type);\n            if (!ReferenceEquals(entry, type))\n            {\n                throw new InvalidOperationException(\"inconsistent type name association\");\n            }\n        }\n\n        private bool TryPerformUncachedTypeResolution(string fullName, out Type type, Assembly[] assemblies)\n        {\n            if (null == assemblies)\n            {\n                throw new ArgumentNullException(nameof(assemblies));\n            }\n\n            if (string.IsNullOrWhiteSpace(fullName))\n            {\n                throw new ArgumentException(\"A type name must not be null nor consist of only whitespace.\", nameof(fullName));\n            }\n\n            foreach (var assembly in assemblies)\n            {\n                type = assembly.GetType(fullName, false);\n                if (type != null)\n                {\n                    return true;\n                }\n            }\n\n            type = Type.GetType(fullName, throwOnError: false);\n            if (type is null)\n            { \n                type = Type.GetType(\n                       fullName,\n                       ResolveAssembly,\n                       ResolveType,\n                       false);\n            }\n\n            return type != null;\n\n            Assembly ResolveAssembly(AssemblyName assemblyName)\n            {\n                var fullAssemblyName = assemblyName.FullName;\n                if (_assemblyCache.TryGetValue(fullAssemblyName, out var result))\n                {\n                    return result;\n                }\n\n                foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())\n                {\n                    _assemblyCache[assembly.FullName] = assembly;\n                    _assemblyCache[GetName(assembly)] = assembly;\n                }\n\n                if (_assemblyCache.TryGetValue(fullAssemblyName, out result))\n                {\n                    return result;\n                }\n\n                try\n                {\n                    result = Assembly.Load(assemblyName);\n                }\n                catch(Exception ex)\n                {\n                    throw new TypeLoadException($\"Unable to load {fullName} from assembly {fullAssemblyName}\", ex);\n                }\n                \n                _assemblyCache[GetName(result)] = result;\n                _assemblyCache[result.FullName] = result;\n\n                return result;\n            }\n\n            static Type ResolveType(Assembly asm, string name, bool ignoreCase)\n            {\n                return asm?.GetType(name, throwOnError: false, ignoreCase: ignoreCase) ?? Type.GetType(name, throwOnError: false, ignoreCase: ignoreCase);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/CompoundTypeAliasTree.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.TypeSystem;\n\n/// <summary>\n/// Represents a compound type aliases as a prefix tree.\n/// </summary>\npublic class CompoundTypeAliasTree\n{\n    private Dictionary<object, CompoundTypeAliasTree>? _children;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"CompoundTypeAliasTree\"/> class.\n    /// </summary>\n    private CompoundTypeAliasTree(object? key, Type? value)\n    {\n        Key = key;\n        Value = value;\n    }\n\n    /// <summary>\n    /// Gets the key for this node.\n    /// </summary>\n    public object? Key { get; }\n\n    /// <summary>\n    /// Gets the value for this node.\n    /// </summary>\n    public Type? Value { get; private set; }\n\n    /// <summary>\n    /// Creates a new tree with a root node which has no key or value.\n    /// </summary>\n    public static CompoundTypeAliasTree Create() => new(default, default);\n\n    internal CompoundTypeAliasTree? GetChildOrDefault(object key)\n    {\n        TryGetChild(key, out var result);\n        return result;\n    }\n\n    internal bool TryGetChild(object key, out CompoundTypeAliasTree? result)\n    {\n        if (_children is { } children)\n        {\n            return children.TryGetValue(key, out result);\n        }\n\n        result = default;\n        return false;\n    }\n\n    /// <summary>\n    /// Adds a node to the tree.\n    /// </summary>\n    /// <param name=\"key\">The key for the new node.</param>\n    public CompoundTypeAliasTree Add(Type key) => AddInternal(key);\n\n    /// <summary>\n    /// Adds a node to the tree.\n    /// </summary>\n    /// <param name=\"key\">The key for the new node.</param>\n    public CompoundTypeAliasTree Add(string key) => AddInternal(key);\n\n    /// <summary>\n    /// Adds a node to the tree.\n    /// </summary>\n    /// <param name=\"key\">The key for the new node.</param>\n    /// <param name=\"value\">The value for the new node.</param>\n    public CompoundTypeAliasTree Add(string key, Type value) => AddInternal(key, value);\n\n    /// <summary>\n    /// Adds a node to the tree.\n    /// </summary>\n    /// <param name=\"key\">The key for the new node.</param>\n    /// <param name=\"value\">The value for the new node.</param>\n    public CompoundTypeAliasTree Add(Type key, Type value) => AddInternal(key, value);\n\n    private CompoundTypeAliasTree AddInternal(object key) => AddInternal(key, default);\n    private CompoundTypeAliasTree AddInternal(object key, Type? value)\n    {\n#if NET6_0_OR_GREATER\n        ArgumentNullException.ThrowIfNull(key, nameof(key));\n#else\n        if (key is null) throw new ArgumentNullException(nameof(key));\n#endif\n        _children ??= new();\n\n        if (_children.TryGetValue(key, out var existing))\n        {\n            if (value is not null && existing.Value is { } type && type != value)\n            {\n                // When the same grain interface is used across multiple assemblies which don't have cross references,\n                // code-gen will generate code for both because it works in isolation, yet at startup they are combined.\n\n                // In this case, if the key is present, and the value is the same as the one being added,\n                // and due to them being logically the same, we can just return the existing CompoundTypeAliasTree.\n\n                // The first one is allowed to win in this case.\n                return existing;\n            }\n\n            existing.Value = value;\n            return existing;\n        }\n        else\n        {\n            return _children[key] = new CompoundTypeAliasTree(key, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/DefaultTypeFilter.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Type which allows any exception type to be resolved.\n    /// </summary>\n    public sealed class DefaultTypeFilter : ITypeNameFilter\n    {\n        /// <inheritdoc/>\n        public bool? IsTypeNameAllowed(string typeName, string assemblyName)\n        {\n            if (assemblyName is { } && assemblyName.Contains(\"Orleans.Serialization\", StringComparison.Ordinal))\n            {\n                return true;\n            }\n\n            if (typeName.EndsWith(nameof(Exception), StringComparison.Ordinal))\n            {\n                return true;\n            }\n\n            if (typeName.StartsWith(\"System.\", StringComparison.Ordinal))\n            {\n                if (typeName.EndsWith(\"Comparer\", StringComparison.Ordinal))\n                {\n                    return true;\n                }\n\n                if (typeName.StartsWith(\"System.Collections.\", StringComparison.Ordinal))\n                {\n                    return true;\n                }\n\n                if (typeName.StartsWith(\"System.Net.IP\", StringComparison.Ordinal))\n                {\n                    return true;\n                }\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/ITypeConverter.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Converts between <see cref=\"Type\"/> and <see cref=\"string\"/> representations.\n    /// </summary>\n    public interface ITypeConverter\n    {\n        /// <summary>\n        /// Formats the provided type as a string.\n        /// </summary>\n        bool TryFormat(Type type, out string formatted);\n\n        /// <summary>\n        /// Parses the provided type.\n        /// </summary>\n        bool TryParse(string formatted, out Type type);\n    }\n\n    /// <summary>\n    /// Functionality for allowing types to be loaded and to participate in serialization, deserialization, etcetera.\n    /// </summary>\n    public interface ITypeNameFilter\n    {\n        /// <summary>\n        /// Determines whether the specified type name corresponds to a type which is allowed to be loaded, serialized, deserialized, etcetera.\n        /// </summary>\n        /// <param name=\"typeName\">Name of the type.</param>\n        /// <param name=\"assemblyName\">Name of the assembly.</param>\n        /// <returns><see langword=\"true\" /> if the specified type is allowed; <see langword=\"false\" /> if the type is not allowed; <see langword=\"null\" /> if the type is unknown by this filter.</returns>\n        bool? IsTypeNameAllowed(string typeName, string assemblyName);\n    }\n\n    /// <summary>\n    /// Functionality for allowing types to be loaded and to participate in serialization, deserialization, etcetera.\n    /// </summary>\n    public interface ITypeFilter\n    {\n        /// <summary>\n        /// Determines whether the specified type is allowed to be serialized, deserialized, etcetera.\n        /// </summary>\n        /// <param name=\"type\">The type</param>\n        /// <returns><see langword=\"true\" /> if the specified type is allowed; <see langword=\"false\" /> if the type is not allowed; <see langword=\"null\" /> if the type is unknown by this filter.</returns>\n        bool? IsTypeAllowed(Type type);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/ITypeResolver.cs",
    "content": "using System;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Provides methods for resolving a <see cref=\"Type\"/> from a string.\n    /// </summary>\n    public abstract class TypeResolver\n    {\n        /// <summary>\n        /// Returns the <see cref=\"Type\"/> corresponding to the provided <paramref name=\"name\"/>, throwing an exception if resolution fails.\n        /// </summary>\n        /// <param name=\"name\">The type name.</param>\n        /// <returns>The <see cref=\"Type\"/> corresponding to the provided <paramref name=\"name\"/>.</returns>\n        public abstract Type ResolveType(string name);\n\n        /// <summary>\n        /// Resolves the <see cref=\"Type\"/> corresponding to the provided <paramref name=\"name\" />, returning true if resolution succeeded and false otherwise.\n        /// </summary>\n        /// <param name=\"name\">The type name.</param>\n        /// <param name=\"type\">The resolved type.</param>\n        /// <returns><see langword=\"true\"/> if resolution succeeded; <see langword=\"false\"/> otherwise.</returns>\n        public abstract bool TryResolveType(string name, out Type type);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/QualifiedType.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Represents an assembly-qualifies type.\n    /// </summary>\n    public readonly struct QualifiedType\n    {\n        /// <summary>\n        /// Gets the equality comparer.\n        /// </summary>\n        /// <value>The equality comparer.</value>\n        public static QualifiedTypeEqualityComparer EqualityComparer { get; } = new QualifiedTypeEqualityComparer();\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QualifiedType\"/> struct.\n        /// </summary>\n        /// <param name=\"assembly\">The assembly.</param>\n        /// <param name=\"type\">The type.</param>\n        public QualifiedType(string? assembly, string type)\n        {\n            Assembly = assembly;\n            Type = type;\n        }\n\n        /// <summary>\n        /// Gets the assembly.\n        /// </summary>\n        /// <value>The assembly.</value>\n        public string? Assembly { get; }\n\n        /// <summary>\n        /// Gets the type.\n        /// </summary>\n        /// <value>The type.</value>\n        public string Type { get; }\n\n        /// <summary>\n        /// Deconstructs this instance.\n        /// </summary>\n        /// <param name=\"assembly\">The assembly.</param>\n        /// <param name=\"type\">The type.</param>\n        public void Deconstruct(out string? assembly, out string type)\n        {\n            assembly = Assembly;\n            type = Type;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is QualifiedType type && string.Equals(Assembly, type.Assembly, StringComparison.Ordinal) && string.Equals(Type, type.Type, StringComparison.Ordinal);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => HashCode.Combine(Assembly, Type);\n\n        /// <summary>\n        /// Performs an implicit conversion from <see cref=\"System.ValueTuple{T1, T2}\"/> to <see cref=\"QualifiedType\"/>.\n        /// </summary>\n        /// <param name=\"args\">The arguments.</param>\n        /// <returns>The result of the conversion.</returns>\n        public static implicit operator QualifiedType((string Assembly, string Type) args) => new(args.Assembly, args.Type);\n\n        /// <summary>\n        /// Compares two values for equality.\n        /// </summary>\n        /// <param name=\"left\">The left.</param>\n        /// <param name=\"right\">The right.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator ==(QualifiedType left, QualifiedType right)\n        {\n            return left.Equals(right);\n        }\n\n        /// <summary>\n        /// Compares two values for inequality.\n        /// </summary>\n        /// <param name=\"left\">The left.</param>\n        /// <param name=\"right\">The right.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator !=(QualifiedType left, QualifiedType right)\n        {\n            return !(left == right);\n        }\n\n        /// <summary>\n        /// Equality comparer for <see cref=\"QualifiedType\"/>.\n        /// </summary>\n        public sealed class QualifiedTypeEqualityComparer : IEqualityComparer<QualifiedType>\n        {\n            /// <inheritdoc/>\n            public bool Equals(QualifiedType x, QualifiedType y) => x == y;\n\n            /// <inheritdoc/>\n            public int GetHashCode(QualifiedType obj) => obj.GetHashCode();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/RuntimeTypeNameFormatter.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\n\nnamespace Orleans.Serialization.TypeSystem;\n\n/// <summary>\n/// Utility methods for formatting <see cref=\"Type\"/> and <see cref=\"TypeInfo\"/> instances in a way which can be parsed by\n/// <see cref=\"Type.GetType(string)\"/>.\n/// </summary>\npublic static class RuntimeTypeNameFormatter\n{\n    private static readonly Assembly SystemAssembly = typeof(int).Assembly;\n\n    private static readonly ConcurrentDictionary<Type, string> Cache = new();\n\n    /// <summary>\n    /// Returns a <see cref=\"string\"/> form of <paramref name=\"type\"/> which can be parsed by <see cref=\"Type.GetType(string)\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type to format.</param>\n    /// <returns>\n    /// A <see cref=\"string\"/> form of <paramref name=\"type\"/> which can be parsed by <see cref=\"Type.GetType(string)\"/>.\n    /// </returns>\n    public static string Format(Type type)\n    {\n        if (type is null)\n        {\n            ThrowTypeArgumentNull();\n        }\n\n        return Cache.GetOrAdd(type, static t =>\n        {\n            var builder = new StringBuilder();\n            Format(builder, t, isElementType: false);\n            return builder.ToString();\n        });\n    }\n\n    [DoesNotReturn]\n    private static void ThrowTypeArgumentNull() => throw new ArgumentNullException(\"type\");\n\n    internal static string FormatInternalNoCache(Type type, bool allowAliases)\n    {\n        var builder = new StringBuilder();\n        Format(builder, type, isElementType: false, allowAliases: allowAliases);\n        return builder.ToString();\n    }\n\n    private static CompoundTypeAliasAttribute? GetCompoundTypeAlias(Type type)\n    {\n        var candidateValue = ulong.MaxValue;\n        CompoundTypeAliasAttribute? candidate = null;\n        foreach (var alias in type.GetCustomAttributes<CompoundTypeAliasAttribute>())\n        {\n            if (alias.Components[^1] is string str && ulong.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))\n            {\n                // For numeric aliases, arbitrarily pick the one with the lowest value.\n                if (candidate is null || result < candidateValue)\n                {\n                    candidate = alias;\n                    candidateValue = result;\n                }\n            }\n            else\n            {\n                // If the value is not numeric, then prefer this alias over any numeric ones.\n                return alias;\n            }\n        }\n\n        return candidate;\n    }\n\n    private static void Format(StringBuilder builder, Type type, bool isElementType, bool allowAliases = true)\n    {\n        if (allowAliases && GetCompoundTypeAlias(type) is { } compoundAlias)\n        {\n            AddCompoundTypeAlias(builder, type, compoundAlias.Components);\n            AddGenericParameters(builder, type);\n            return;\n        }\n\n        // Arrays, pointers, and by-ref types are all element types and need to be formatted with their own adornments.\n        if (type.HasElementType)\n        {\n            // Format the element type.\n            Format(builder, type.GetElementType()!, isElementType: true);\n\n            // Format this type's adornments to the element type.\n            AddArrayRank(builder, type);\n            AddPointerSymbol(builder, type);\n            AddByRefSymbol(builder, type);\n        }\n        else\n        {\n            AddNamespace(builder, type);\n            AddClassName(builder, type);\n            AddGenericParameters(builder, type);\n        }\n\n        // Types which are used as elements are not formatted with their assembly name, since that is added after the\n        // element type's adornments.\n        if (!isElementType)\n        {\n            AddAssembly(builder, type);\n        }\n    }\n\n    private static void AddCompoundTypeAlias(StringBuilder builder, Type type, object[] components)\n    {\n        // Start\n        builder.Append('(');\n        for (var i = 0; i < components.Length; ++i)\n        {\n            var component = components[i];\n            if (i > 0)\n            {\n                builder.Append(',');\n            }\n\n            // Append the component\n            if (component is string s)\n            {\n                builder.Append($\"\\\"{s}\\\"\");\n            }\n            else if (component is Type t)\n            {\n                if (t == type)\n                {\n                    throw new ArgumentException($\"Element {i} of argument array, {component}, is equal to the attached type {type}, which is not supported\");\n                }\n\n                builder.Append('[');\n                Format(builder, t, isElementType: false);\n                builder.Append(']');\n            }\n            else\n            {\n                throw new ArgumentException($\"Element {i} of argument array, {component}, must be a Type or string but is an {component?.GetType().ToString() ?? \"null\"}\");\n            }\n        }\n\n        // End\n        builder.Append(')');\n        if (type.IsGenericType)\n        {\n            int parameterCount = type.IsConstructedGenericType switch\n            {\n                true => type.GenericTypeArguments.Length,\n                false => type.GetTypeInfo().GenericTypeParameters.Length\n            };\n            builder.Append($\"`{parameterCount}\");\n        }\n    }\n\n    private static void AddNamespace(StringBuilder builder, Type type)\n    {\n        if (string.IsNullOrWhiteSpace(type.Namespace))\n        {\n            return;\n        }\n\n        _ = builder.Append(type.Namespace);\n        _ = builder.Append('.');\n    }\n\n    private static void AddClassName(StringBuilder builder, Type type)\n    {\n        // Format the declaring type.\n        if (type.IsNested)\n        {\n            AddClassName(builder, type.DeclaringType!);\n            _ = builder.Append('+');\n        }\n\n        // Format the simple type name.\n        var name = type.Name.AsSpan();\n        var index = name.IndexOfAny(\"`*[&\");\n        _ = builder.Append(index > 0 ? name[..index] : name);\n\n        // Format this type's generic arity.\n        AddGenericArity(builder, type);\n    }\n\n    private static void AddGenericParameters(StringBuilder builder, Type type)\n    {\n        // Generic type definitions (eg, List<> without parameters) and non-generic types do not include any\n        // parameters in their formatting.\n        if (!type.IsConstructedGenericType)\n        {\n            return;\n        }\n\n        var args = type.GetGenericArguments();\n        _ = builder.Append('[');\n        for (var i = 0; i < args.Length; i++)\n        {\n            _ = builder.Append('[');\n            Format(builder, args[i], isElementType: false);\n            _ = builder.Append(']');\n            if (i + 1 < args.Length)\n            {\n                _ = builder.Append(',');\n            }\n        }\n\n        _ = builder.Append(']');\n    }\n\n    private static void AddGenericArity(StringBuilder builder, Type type)\n    {\n        if (!type.IsGenericType)\n        {\n            return;\n        }\n\n        // The arity is the number of generic parameters minus the number of generic parameters in the declaring types.\n        var baseTypeParameterCount =\n            type.IsNested ? type.DeclaringType!.GetGenericArguments().Length : 0;\n        var arity = type.GetGenericArguments().Length - baseTypeParameterCount;\n\n        // If all of the generic parameters are in the declaring types then this type has no parameters of its own.\n        if (arity == 0)\n        {\n            return;\n        }\n\n        _ = builder.Append('`');\n        _ = builder.Append(arity);\n    }\n\n    private static void AddPointerSymbol(StringBuilder builder, Type type)\n    {\n        if (!type.IsPointer)\n        {\n            return;\n        }\n\n        _ = builder.Append('*');\n    }\n\n    private static void AddByRefSymbol(StringBuilder builder, Type type)\n    {\n        if (!type.IsByRef)\n        {\n            return;\n        }\n\n        _ = builder.Append('&');\n    }\n\n    private static void AddArrayRank(StringBuilder builder, Type type)\n    {\n        if (!type.IsArray)\n        {\n            return;\n        }\n\n        _ = builder.Append('[');\n        _ = builder.Append(',', type.GetArrayRank() - 1);\n        _ = builder.Append(']');\n    }\n\n    private static void AddAssembly(StringBuilder builder, Type type)\n    {\n        // Do not include the assembly name for the system assembly.\n        var assembly = type.Assembly;\n        if (SystemAssembly.Equals(assembly))\n        {\n            return;\n        }\n\n        _ = builder.Append(',');\n        _ = builder.Append(CachedTypeResolver.GetName(assembly));\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/RuntimeTypeNameParser.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace Orleans.Serialization.TypeSystem;\n\n/// <summary>\n/// Utility class for parsing type names, as formatted by <see cref=\"RuntimeTypeNameFormatter\"/>.\n/// </summary>\npublic static class RuntimeTypeNameParser\n{\n    internal const int MaxAllowedGenericArity = 64;\n    internal const char CompoundAliasStartIndicator = '(';\n    internal const char CompoundAliasEndIndicator = ')';\n    internal const char CompoundAliasElementSeparator = ',';\n    internal const char LiteralDelimiter = '\"';\n    internal const char PointerIndicator = '*';\n    internal const char ReferenceIndicator = '&';\n    internal const char ArrayStartIndicator = '[';\n    internal const char ArrayDimensionIndicator = ',';\n    internal const char ArrayEndIndicator = ']';\n    internal const char ParameterSeparator = ',';\n    internal const char GenericTypeIndicator = '`';\n    internal const char NestedTypeIndicator = '+';\n    internal const char AssemblyIndicator = ',';\n    internal static ReadOnlySpan<char> LiteralDelimiters => new[] { LiteralDelimiter };\n    internal static ReadOnlySpan<char> TupleDelimiters => new[] { CompoundAliasElementSeparator, CompoundAliasEndIndicator };\n    internal static ReadOnlySpan<char> AssemblyDelimiters => new[] { ArrayEndIndicator, CompoundAliasElementSeparator, CompoundAliasEndIndicator };\n    internal static ReadOnlySpan<char> TypeNameDelimiters => new[] { ArrayStartIndicator, ArrayEndIndicator, PointerIndicator, ReferenceIndicator, AssemblyIndicator, GenericTypeIndicator, NestedTypeIndicator };\n\n    /// <summary>\n    /// Parse the provided value as a type name.\n    /// </summary>\n    /// <param name=\"input\">The input.</param>\n    /// <returns>A parsed type specification.</returns>\n    public static TypeSpec Parse(string input) => Parse(input.AsSpan());\n\n    /// <summary>\n    /// Parse the provided value as a type name.\n    /// </summary>\n    /// <param name=\"input\">The input.</param>\n    /// <returns>A parsed type specification.</returns>\n    public static TypeSpec Parse(ReadOnlySpan<char> input) => ParseInternal(ref input);\n\n    private static TypeSpec ParseInternal(ref ReadOnlySpan<char> input)\n    {\n        BufferReader s = default;\n        s.Input = input;\n        var result = ParseInternal(ref s);\n        input = s.Remaining;\n        return result;\n    }\n\n    private static TypeSpec ParseInternal(ref BufferReader input)\n    {\n        TypeSpec result;\n        char c;\n        var arity = 0;\n\n        TypeSpec coreType = null;\n\n        // Read tuple\n        if (input.TryPeek(out c) && c == CompoundAliasStartIndicator)\n        {\n            input.ConsumeCharacter(CompoundAliasStartIndicator);\n            var elements = new List<TypeSpec>();\n            while (input.TryPeek(out c) && c != CompoundAliasEndIndicator)\n            {\n                if (c == CompoundAliasElementSeparator)\n                {\n                    input.ConsumeCharacter(CompoundAliasElementSeparator);\n                }\n\n                input.ConsumeWhitespace();\n\n                var element = ParseCompoundTypeAliasElement(ref input);\n                elements.Add(element);\n            }\n\n            input.ConsumeCharacter(CompoundAliasEndIndicator);\n\n            var genericArityStart = -1;\n            while (input.TryPeek(out c))\n            {\n                if (genericArityStart < 0 && c == GenericTypeIndicator)\n                {\n                    genericArityStart = input.Index + 1;\n                }\n                else if (genericArityStart < 0 || !char.IsDigit(c))\n                {\n                    break;\n                }\n\n                input.ConsumeCharacter(c);\n            }\n\n            if (genericArityStart >= 0)\n            {\n                var aritySlice = input.Input[genericArityStart..input.Index];\n#if NETCOREAPP3_1_OR_GREATER\n                arity = int.Parse(aritySlice);\n#else\n                arity = int.Parse(aritySlice.ToString());\n#endif\n                input.TotalGenericArity += arity;\n                if (input.TotalGenericArity > MaxAllowedGenericArity)\n                {\n                    ThrowGenericArityTooLarge(input.TotalGenericArity);\n                }\n            }\n\n            coreType = new TupleTypeSpec([.. elements], input.TotalGenericArity);\n        }\n        else\n        {\n            // Read namespace and class name, including generic arity, which is a part of the class name.\n            NamedTypeSpec named = null;\n            while (true)\n            {\n                var typeName = ParseTypeName(ref input);\n                named = new NamedTypeSpec(named, typeName.ToString(), input.TotalGenericArity);\n                arity = named.Arity;\n\n                if (input.TryPeek(out c) && c == NestedTypeIndicator)\n                {\n                    // Consume the nested type indicator, then loop to parse the nested type.\n                    input.ConsumeCharacter(NestedTypeIndicator);\n                    continue;\n                }\n\n                break;\n            }\n\n            coreType = named;\n        }\n\n        // Parse generic type parameters\n        if (input.TotalGenericArity > 0 && input.TryPeek(out c, out var d) && c == ArrayStartIndicator && d == ArrayStartIndicator)\n        {\n            input.ConsumeCharacter(ArrayStartIndicator);\n            var arguments = new TypeSpec[input.TotalGenericArity];\n            for (var i = 0; i < input.TotalGenericArity; i++)\n            {\n                if (i > 0)\n                {\n                    input.ConsumeCharacter(ParameterSeparator);\n                }\n\n                // Parse the argument type\n                input.ConsumeCharacter(ArrayStartIndicator);\n                var remaining = input.Remaining;\n                arguments[i] = ParseInternal(ref remaining);\n                var consumed = input.Remaining.Length - remaining.Length;\n                input.Consume(consumed);\n                input.ConsumeCharacter(ArrayEndIndicator);\n            }\n\n            input.ConsumeCharacter(ArrayEndIndicator);\n            result = new ConstructedGenericTypeSpec(coreType, arity, arguments);\n        }\n        else\n        {\n            // This is not a constructed generic type\n            result = coreType;\n        }\n\n        // Parse modifiers\n        bool hadModifier;\n        do\n        {\n            hadModifier = false;\n\n            if (!input.TryPeek(out c))\n            {\n                break;\n            }\n\n            switch (c)\n            {\n                case ArrayStartIndicator:\n                    var dimensions = ParseArraySpecifier(ref input);\n                    result = new ArrayTypeSpec(result, dimensions);\n                    hadModifier = true;\n                    break;\n                case PointerIndicator:\n                    result = new PointerTypeSpec(result);\n                    input.ConsumeCharacter(PointerIndicator);\n                    hadModifier = true;\n                    break;\n                case ReferenceIndicator:\n                    result = new ReferenceTypeSpec(result);\n                    input.ConsumeCharacter(ReferenceIndicator);\n                    hadModifier = true;\n                    break;\n            }\n        } while (hadModifier);\n\n        // Extract the assembly, if specified.\n        if (input.TryPeek(out c) && c == AssemblyIndicator)\n        {\n            input.ConsumeCharacter(AssemblyIndicator);\n            var assembly = ExtractAssemblySpec(ref input);\n            result = new AssemblyQualifiedTypeSpec(result, assembly.ToString());\n        }\n\n        return result;\n    }\n\n    private static ReadOnlySpan<char> ParseTypeName(ref BufferReader s)\n    {\n        var start = s.Index;\n        var typeName = ParseSpan(ref s, TypeNameDelimiters);\n        var genericArityStart = -1;\n        while (s.TryPeek(out char c))\n        {\n            if (genericArityStart < 0 && c == GenericTypeIndicator)\n            {\n                genericArityStart = s.Index + 1;\n            }\n            else if (genericArityStart < 0 || !char.IsDigit(c))\n            {\n                break;\n            }\n\n            s.ConsumeCharacter(c);\n        }\n\n        if (genericArityStart >= 0)\n        {\n            // The generic arity is additive, so that a generic class nested in a generic class has an arity\n            // equal to the sum of specified arity values. For example, \"C`1+N`2\" has an arity of 3.\n            var aritySlice = s.Input[genericArityStart..s.Index];\n#if NETCOREAPP3_1_OR_GREATER\n            var arity = int.Parse(aritySlice);\n#else\n            var arity = int.Parse(aritySlice.ToString());\n#endif\n            s.TotalGenericArity += arity;\n            if (s.TotalGenericArity > MaxAllowedGenericArity)\n            {\n                ThrowGenericArityTooLarge(s.TotalGenericArity);\n            }\n\n            // Include the generic arity in the type name.\n            typeName = s.Input[start..s.Index];\n        }\n\n        return typeName;\n    }\n\n    private static int ParseArraySpecifier(ref BufferReader s)\n    {\n        s.ConsumeCharacter(ArrayStartIndicator);\n        var dimensions = 1;\n\n        while (s.TryPeek(out var c) && c != ArrayEndIndicator)\n        {\n            s.ConsumeCharacter(ArrayDimensionIndicator);\n            ++dimensions;\n        }\n\n        s.ConsumeCharacter(ArrayEndIndicator);\n        return dimensions;\n    }\n\n    private static ReadOnlySpan<char> ExtractAssemblySpec(ref BufferReader s)\n    {\n        s.ConsumeWhitespace();\n        return ParseSpan(ref s, AssemblyDelimiters);\n    }\n\n    private static ReadOnlySpan<char> ParseSpan(ref BufferReader s, ReadOnlySpan<char> delimiters)\n    {\n        ReadOnlySpan<char> result;\n        if (s.Remaining.IndexOfAny(delimiters) is int index && index > 0)\n        {\n            result = s.Remaining[..index];\n        }\n        else\n        {\n            result = s.Remaining;\n        }\n\n        s.Consume(result.Length);\n        return result;\n    }\n\n    private static TypeSpec ParseCompoundTypeAliasElement(ref BufferReader input)\n    {\n        char c;\n\n        // Read literal value\n        if (input.TryPeek(out c))\n        {\n            if (c == LiteralDelimiter)\n            {\n                input.ConsumeCharacter(LiteralDelimiter);\n                var literalSpan = ParseSpan(ref input, LiteralDelimiters);\n                input.ConsumeCharacter(LiteralDelimiter);\n                return new LiteralTypeSpec(new string(literalSpan));\n            }\n            else if (c == ArrayStartIndicator)\n            {\n                // Parse the argument type\n                input.ConsumeCharacter(ArrayStartIndicator);\n                var remaining = input.Remaining;\n                var result = ParseInternal(ref remaining);\n                var consumed = input.Remaining.Length - remaining.Length;\n                input.Consume(consumed);\n                input.ConsumeCharacter(ArrayEndIndicator);\n                return result;\n            }\n\n            throw new ArgumentException($\"Unexpected token '{c}' when reading compound type alias element.\", nameof(input));\n        }\n        else\n        {\n            throw new IndexOutOfRangeException(\"Attempted to read past the end of the input buffer.\");\n        }\n    }\n\n    private static void ThrowGenericArityTooLarge(int arity) => throw new NotSupportedException($\"An arity of {arity} is not supported.\");\n\n    private ref struct BufferReader\n    {\n        public ReadOnlySpan<char> Input;\n        public int Index;\n        public int TotalGenericArity;\n\n        public readonly ReadOnlySpan<char> Remaining => Input[Index..];\n\n        public readonly bool TryPeek(out char c)\n        {\n            if (Index < Input.Length)\n            {\n                c = Input[Index];\n                return true;\n            }\n\n            c = default;\n            return false;\n        }\n\n        public readonly bool TryPeek(out char c, out char d)\n        {\n            var result = TryPeek(out c);\n            result &= TryPeek(Index + 1, out d);\n            return result;\n        }\n\n        public readonly bool TryPeek(int index, out char c)\n        {\n            if (index < Input.Length)\n            {\n                c = Input[index];\n                return true;\n            }\n\n            c = default;\n            return false;\n        }\n\n        public void Consume(int chars)\n        {\n            if (Index < Input.Length)\n            {\n                Index += chars;\n                return;\n            }\n\n            ThrowEndOfInput();\n        }\n\n        public void ConsumeCharacter(char assertChar)\n        {\n            if (Index < Input.Length)\n            {\n                var c = Input[Index];\n                if (assertChar != c)\n                {\n                    ThrowUnexpectedCharacter(Input, Index, assertChar, c);\n                }\n\n                ++Index;\n                return;\n            }\n\n            ThrowEndOfInput();\n        }\n\n        public void ConsumeWhitespace()\n        {\n            while (char.IsWhiteSpace(Input[Index]))\n            {\n                ++Index;\n            }\n        }\n\n        private static void ThrowUnexpectedCharacter(ReadOnlySpan<char> value, int position, char expected, char actual)\n        {\n            var valueString = new string(value);\n            var posString = position > 0 ? new string(' ', position) : \"\";\n            var message = $\"Encountered unexpected character. Expected '{expected}', actual '{actual}' in string:\\n> {valueString}\\n> {posString}^\";\n            throw new InvalidOperationException(message);\n        }\n\n        private static void ThrowEndOfInput() => throw new InvalidOperationException(\"Tried to read past the end of the input\");\n\n        public override readonly string ToString()\n        {\n            var result = new StringBuilder();\n            var i = 0;\n            foreach (var c in Input)\n            {\n                if (i == Index)\n                {\n                    result.Append(\"^^^\");\n                }\n\n                result.Append(c);\n\n                if (i == Index)\n                {\n                    result.Append(\"^^^\");\n                }\n\n                ++i;\n            }\n\n            return result.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/RuntimeTypeNameRewriter.cs",
    "content": "#nullable enable\n\nusing System;\n\nnamespace Orleans.Serialization.TypeSystem;\n\n/// <summary>\n/// Rewrites <see cref=\"TypeSpec\"/> graphs.\n/// </summary>\ninternal static class RuntimeTypeNameRewriter\n{\n    /// <summary>\n    /// Signature for a delegate which rewrites a <see cref=\"QualifiedType\"/>.\n    /// </summary>\n    /// <param name=\"input\">The input.</param>\n    /// <param name=\"state\">The state provided to the rewriter method.</param>\n    /// <returns>The rewritten qualified type.</returns>\n    public delegate QualifiedType Rewriter<TState>(in QualifiedType input, ref TState state);\n\n    /// <summary>\n    /// Signature for a delegate which resolves a compound type alias.\n    /// </summary>\n    /// <param name=\"input\">The input.</param>\n    /// <param name=\"state\">The state provided to the resolve method.</param>\n    /// <returns>The resolved type type.</returns>\n    public delegate TypeSpec CompoundAliasResolver<TState>(TupleTypeSpec input, ref TState state);\n\n    /// <summary>\n    /// Rewrites a <see cref=\"TypeSpec\"/> using the provided rewriter delegate.\n    /// </summary>\n    public static TypeSpec Rewrite<TState>(TypeSpec input, Rewriter<TState> rewriter, ref TState state)\n    {\n        var instance = new TypeRewriter<TState>(rewriter, null, ref state);\n        var result = instance.Rewrite(input);\n        state = instance._userState;\n        return result;\n    }\n\n    /// <summary>\n    /// Rewrites a <see cref=\"TypeSpec\"/> using the provided rewriter delegate.\n    /// </summary>\n    public static TypeSpec Rewrite<TState>(TypeSpec input, Rewriter<TState> rewriter, CompoundAliasResolver<TState>? compoundAliasRewriter, ref TState state)\n    {\n        var instance = new TypeRewriter<TState>(rewriter, compoundAliasRewriter, ref state);\n        var result = instance.Rewrite(input);\n        state = instance._userState;\n        return result;\n    }\n\n    private struct TypeRewriter<TState>\n    {\n        private readonly Rewriter<TState> _nameRewriter { get; }\n        private readonly CompoundAliasResolver<TState>? _compoundTypeRewriter { get; }\n        public TState _userState;\n\n        public TypeRewriter(Rewriter<TState> nameRewriter, CompoundAliasResolver<TState>? compoundTypeRewriter, ref TState initialUserState)\n        {\n            _nameRewriter = nameRewriter;\n            _compoundTypeRewriter = compoundTypeRewriter;\n            _userState = initialUserState;\n        }\n\n        public TypeSpec Rewrite(TypeSpec input)\n        {\n            var result = ApplyInner(input, null);\n            if (result.Assembly is not null)\n            {\n                // If the rewriter bubbled up an assembly, add it here. \n                return new AssemblyQualifiedTypeSpec(result.Type, result.Assembly);\n            }\n\n            return result.Type;\n        }\n\n        private (TypeSpec Type, string? Assembly) ApplyInner(TypeSpec input, string? assemblyName) =>\n        // A type's assembly is passed downwards through the graph, and modifications to the assembly (from the user-provided delegate) flow upwards.\n        input switch\n        {\n            ConstructedGenericTypeSpec type => HandleGeneric(type, assemblyName),\n            NamedTypeSpec type => HandleNamedType(type, assemblyName),\n            AssemblyQualifiedTypeSpec type => HandleAssembly(type, assemblyName),\n            ArrayTypeSpec type => HandleArray(type, assemblyName),\n            PointerTypeSpec type => HandlePointer(type, assemblyName),\n            ReferenceTypeSpec type => HandleReference(type, assemblyName),\n            TupleTypeSpec type => HandleCompoundType(type, assemblyName),\n            LiteralTypeSpec type => (type, assemblyName),\n            null => throw new ArgumentNullException(nameof(input)),\n            _ => throw new NotSupportedException($\"Argument of type {input.GetType()} is nut supported\"),\n        };\n\n        private (TypeSpec Type, string? Assembly) HandleGeneric(ConstructedGenericTypeSpec type, string? assemblyName)\n        {\n            var (unconstructed, replacementAssembly) = ApplyInner(type.UnconstructedType, assemblyName);\n            if (unconstructed is AssemblyQualifiedTypeSpec assemblyQualified)\n            {\n                unconstructed = assemblyQualified.Type;\n                replacementAssembly = assemblyQualified.Assembly;\n            }\n\n            var newArguments = new TypeSpec[type.Arguments.Length];\n            var didChange = false;\n            for (var i = 0; i < type.Arguments.Length; i++)\n            {\n                // Generic type parameters do not inherit the assembly of the generic type.\n                var args = ApplyInner(type.Arguments[i], null);\n\n                if (args.Assembly is not null)\n                {\n                    newArguments[i] = new AssemblyQualifiedTypeSpec(args.Type, args.Assembly);\n                }\n                else\n                {\n                    newArguments[i] = args.Type;\n                }\n\n                didChange |= !ReferenceEquals(newArguments[i], type.Arguments[i]);\n            }\n\n            if (ReferenceEquals(type.UnconstructedType, unconstructed) && !didChange)\n            {\n                return (type, replacementAssembly);\n            }\n\n            return (new ConstructedGenericTypeSpec(unconstructed, newArguments.Length, newArguments), replacementAssembly);\n        }\n\n        private (TypeSpec Type, string? Assembly) HandleNamedType(NamedTypeSpec type, string? assemblyName)\n        {\n            var nsQualified = type.GetNamespaceQualifiedName();\n            var replacementName = _nameRewriter(new QualifiedType(assembly: assemblyName, type: nsQualified), ref _userState);\n\n            if (!string.Equals(nsQualified, replacementName.Type, StringComparison.Ordinal))\n            {\n                // Change the type name and potentially the assembly.\n                var resultType = RuntimeTypeNameParser.Parse(replacementName.Type);\n                if (!(resultType is NamedTypeSpec))\n                {\n                    throw new InvalidOperationException($\"Replacement type name, \\\"{replacementName.Type}\\\", can not deviate from the original type structure of the input, \\\"{nsQualified}\\\"\");\n                }\n\n                return (resultType, replacementName.Assembly);\n            }\n            else if (!string.Equals(assemblyName, replacementName.Assembly, StringComparison.Ordinal))\n            {\n                // Only change the assembly;\n                return (type, replacementName.Assembly);\n            }\n            else if (type.ContainingType is not null)\n            {\n                // Give the user an opportunity to change the parent, including the assembly.\n                var replacementParent = ApplyInner(type.ContainingType, assemblyName);\n                if (ReferenceEquals(replacementParent.Type, type.ContainingType))\n                {\n                    // No change to the type.\n                    return (type, replacementParent.Assembly);\n                }\n\n                // The parent type changed.\n                var typedReplacement = (NamedTypeSpec)replacementParent.Type;\n                return (new NamedTypeSpec(typedReplacement, type.Name, type.Arity), replacementParent.Assembly);\n            }\n            else\n            {\n                return (type, replacementName.Assembly);\n            }\n        }\n\n        private (TypeSpec Type, string? Assembly) HandleAssembly(AssemblyQualifiedTypeSpec type, string? assemblyName)\n        {\n            var replacement = ApplyInner(type.Type, type.Assembly);\n\n            // Assembly name changes never bubble up past the assembly qualifier node.\n            if (string.IsNullOrWhiteSpace(replacement.Assembly))\n            {\n                // Remove the assembly qualification\n                return (replacement.Type, assemblyName);\n            }\n            else if (!string.Equals(replacement.Assembly, type.Assembly) || !ReferenceEquals(replacement.Type, type.Type))\n            {\n                // Update the assembly or the type.\n                return (new AssemblyQualifiedTypeSpec(replacement.Type, replacement.Assembly), assemblyName);\n            }\n\n            // No update.\n            return (type, assemblyName);\n        }\n\n        private (TypeSpec Type, string? Assembly) HandleArray(ArrayTypeSpec type, string? assemblyName)\n        {\n            var element = ApplyInner(type.ElementType, assemblyName);\n            if (ReferenceEquals(element.Type, type.ElementType))\n            {\n                return (type, element.Assembly);\n            }\n\n            return (new ArrayTypeSpec(element.Type, type.Dimensions), element.Assembly);\n        }\n\n        private (TypeSpec Type, string? Assembly) HandleReference(ReferenceTypeSpec type, string? assemblyName)\n        {\n            var element = ApplyInner(type.ElementType, assemblyName);\n            if (ReferenceEquals(element.Type, type.ElementType))\n            {\n                return (type, element.Assembly);\n            }\n\n            return (new ReferenceTypeSpec(element.Type), element.Assembly);\n        }\n\n        private (TypeSpec Type, string? Assembly) HandlePointer(PointerTypeSpec type, string? assemblyName)\n        {\n            var element = ApplyInner(type.ElementType, assemblyName);\n            if (ReferenceEquals(element.Type, type.ElementType))\n            {\n                return (type, element.Assembly);\n            }\n\n            return (new PointerTypeSpec(element.Type), element.Assembly);\n        }\n\n        private (TypeSpec Type, string? Assembly) HandleCompoundType(TupleTypeSpec type, string? assemblyName)\n        {\n            var elements = new TypeSpec[type.Elements.Length];\n            for (var i = 0; i < type.Elements.Length; i++)\n            {\n                (elements[i], _) = ApplyInner(type.Elements[i], assemblyName);\n            }\n\n            // Resolve the compound type alias after first trying to resolve each of the individual elements.\n            var replacementTypeSpec = new TupleTypeSpec(elements, type.Arity);\n            if (_compoundTypeRewriter is { } rewriter)\n            {\n                var resolved = rewriter(replacementTypeSpec, ref _userState);\n                if (resolved is TupleTypeSpec)\n                {\n                    throw new InvalidOperationException($\"Compound type alias resolver resolved {type} into {resolved} which is also an alias type.\");\n                }\n\n                // Give the rewriter a chance to rewrite the resolved name.\n                return ApplyInner(resolved, assemblyName); \n            }\n\n            return (replacementTypeSpec, assemblyName);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/TypeCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Buffers.Binary;\nusing System.Collections.Concurrent;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO.Hashing;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Orleans.Serialization.Buffers;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Functionality for serializing and deserializing types.\n    /// </summary>\n    public sealed class TypeCodec\n    {\n        private const byte Version1 = 1;\n        private readonly ConcurrentDictionary<Type, TypeKey> _typeCache = new ConcurrentDictionary<Type, TypeKey>();\n        private readonly ConcurrentDictionary<int, (TypeKey Key, Type Type)> _typeKeyCache = new ConcurrentDictionary<int, (TypeKey, Type)>();\n        private readonly TypeConverter _typeConverter;\n        private readonly Func<Type, TypeKey> _getTypeKey;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypeCodec\"/> class.\n        /// </summary>\n        /// <param name=\"typeConverter\">The type converter.</param>\n        public TypeCodec(TypeConverter typeConverter)\n        {\n            _typeConverter = typeConverter;\n            _getTypeKey = type => new TypeKey(Encoding.UTF8.GetBytes(_typeConverter.Format(type)));\n        }\n\n        /// <summary>\n        /// Writes a type with a length-prefix.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"type\">The type.</param>\n        public void WriteLengthPrefixed<TBufferWriter>(ref Writer<TBufferWriter> writer, Type type) where TBufferWriter : IBufferWriter<byte>\n        {\n            var key = _typeCache.GetOrAdd(type, _getTypeKey);\n            writer.WriteVarUInt32((uint)key.TypeName.Length);\n            writer.Write(key.TypeName);\n        }\n\n        /// <summary>\n        /// Writes a type.\n        /// </summary>\n        /// <typeparam name=\"TBufferWriter\">The buffer writer type.</typeparam>\n        /// <param name=\"writer\">The writer.</param>\n        /// <param name=\"type\">The type.</param>\n        public void WriteEncodedType<TBufferWriter>(ref Writer<TBufferWriter> writer, Type type) where TBufferWriter : IBufferWriter<byte>\n        {\n            var key = _typeCache.GetOrAdd(type, _getTypeKey);\n            writer.WriteByte(Version1);\n            writer.WriteInt32(key.HashCode);\n            writer.WriteVarUInt32((uint)key.TypeName.Length);\n            writer.Write(key.TypeName);\n        }\n\n        /// <summary>\n        /// Reads a type.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The type if it was successfully read, <see langword=\"null\" /> otherwise.</returns>\n        public unsafe Type TryRead<TInput>(ref Reader<TInput> reader)\n        {\n            var version = reader.ReadByte();\n            if (version != Version1)\n            {\n                ThrowUnsupportedVersion(version);\n            }\n\n            var hashCode = reader.ReadInt32();\n            var count = (int)reader.ReadVarUInt32();\n\n            if (!reader.TryReadBytes(count, out var typeName))\n            {\n                typeName = reader.ReadBytes((uint)count);\n            }\n\n            // Search through \n            var candidateHashCode = hashCode;\n            while (_typeKeyCache.TryGetValue(candidateHashCode, out var entry))\n            {\n                var existingKey = entry.Key;\n                if (existingKey.HashCode != hashCode)\n                {\n                    break;\n                }\n\n                if (existingKey.TypeName.AsSpan().SequenceEqual(typeName))\n                {\n                    return entry.Type;\n                }\n\n                // Try the next entry.\n                ++candidateHashCode;\n            }\n\n            // Allocate a string for the type name.\n            string typeNameString;\n            fixed (byte* typeNameBytes = typeName)\n            {\n                typeNameString = Encoding.UTF8.GetString(typeNameBytes, typeName.Length);\n            }\n\n            if (_typeConverter.TryParse(typeNameString, out var type))\n            {\n                var key = new TypeKey(hashCode, typeName.ToArray());\n                while (!_typeKeyCache.TryAdd(candidateHashCode++, (key, type)))\n                {\n                    // Insert the type at the first available position.\n                }\n            }\n\n            return type;\n        }\n\n        /// <summary>\n        /// Reads a length-prefixed type.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>Type.</returns>\n        public unsafe Type ReadLengthPrefixed<TInput>(ref Reader<TInput> reader)\n        {\n            var count = (int)reader.ReadVarUInt32();\n\n            if (!reader.TryReadBytes(count, out var typeName))\n            {\n                typeName = reader.ReadBytes((uint)count);\n            }\n\n            // Allocate a string for the type name.\n            string typeNameString;\n            fixed (byte* typeNameBytes = typeName)\n            {\n                typeNameString = Encoding.UTF8.GetString(typeNameBytes, typeName.Length);\n            }\n\n            var type = _typeConverter.Parse(typeNameString);\n            return type;\n        }\n\n        /// <summary>\n        /// Tries to read a type for diagnostics purposes.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"typeString\">The type name as a string.</param>\n        /// <returns><see langword=\"true\" /> if a type was successfully read, <see langword=\"false\" /> otherwise.</returns>\n        public unsafe bool TryReadForAnalysis<TInput>(ref Reader<TInput> reader, [NotNullWhen(true)] out Type type, out string typeString)\n        {\n            var version = reader.ReadByte();\n            var hashCode = reader.ReadInt32();\n            var count = (int)reader.ReadVarUInt32();\n\n            if (!reader.TryReadBytes(count, out var typeName))\n            {\n                typeName = reader.ReadBytes((uint)count);\n            }\n\n            // Allocate a string for the type name.\n            string typeNameString;\n            fixed (byte* typeNameBytes = typeName)\n            {\n                typeNameString = Encoding.UTF8.GetString(typeNameBytes, count);\n            }\n\n            _ = _typeConverter.TryParse(typeNameString, out type);\n            var key = new TypeKey(hashCode, typeName.ToArray());\n            typeString = key.ToString();\n            return type is not null; \n        }\n\n        [DoesNotReturn]\n        private static void ThrowUnsupportedVersion(byte version) => throw new NotSupportedException($\"Type encoding version {version} is not supported\");\n\n        /// <summary>\n        /// Represents a named type for the purposes of serialization.\n        /// </summary>\n        internal readonly struct TypeKey\n        {\n            public readonly int HashCode;\n\n            public readonly byte[] TypeName;\n\n            public TypeKey(int hashCode, byte[] key)\n            {\n                HashCode = hashCode;\n                TypeName = key;\n            }\n\n            public TypeKey(byte[] key)\n            {\n                TypeName = key;\n                Unsafe.SkipInit(out int hash);\n                XxHash32.TryHash(key, MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref hash, 1)), out _);\n                HashCode = BitConverter.IsLittleEndian ? hash : BinaryPrimitives.ReverseEndianness(hash);\n            }\n\n            public bool Equals(in TypeKey other)\n            {\n                if (HashCode != other.HashCode)\n                {\n                    return false;\n                }\n\n                var a = TypeName;\n                var b = other.TypeName;\n                return ReferenceEquals(a, b) || a.AsSpan().SequenceEqual(b);\n            }\n\n            public override bool Equals(object obj) => obj is TypeKey key && Equals(key);\n\n            public override int GetHashCode() => HashCode;\n\n            public override string ToString() => $\"TypeName \\\"{Encoding.UTF8.GetString(TypeName)}\\\" (hash {HashCode:X8})\";\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/TypeConverter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Activators;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Formats and parses <see cref=\"Type\"/> instances using configured rules.\n    /// </summary>\n    public class TypeConverter\n    {\n        private readonly ITypeConverter[] _converters;\n        private readonly ITypeNameFilter[] _typeNameFilters;\n        private readonly ITypeFilter[] _typeFilters;\n        private readonly bool _allowAllTypes;\n        private readonly CompoundTypeAliasTree _compoundTypeAliases;\n        private readonly TypeResolver _resolver;\n        private readonly RuntimeTypeNameRewriter.Rewriter<ValidationResult> _convertToDisplayName;\n        private readonly RuntimeTypeNameRewriter.Rewriter<ValidationResult> _convertFromDisplayName;\n        private readonly RuntimeTypeNameRewriter.CompoundAliasResolver<ValidationResult> _compoundAliasResolver;\n        private readonly Dictionary<QualifiedType, QualifiedType> _wellKnownAliasToType;\n        private readonly Dictionary<QualifiedType, QualifiedType> _wellKnownTypeToAlias;\n        private readonly ConcurrentDictionary<QualifiedType, bool> _allowedTypes;\n        private readonly HashSet<string> _allowedTypesConfiguration;\n        private static readonly List<(string DisplayName, string RuntimeName)> WellKnownTypeAliases = new()\n        {\n            (\"object\", \"System.Object\"),\n            (\"string\", \"System.String\"),\n            (\"char\", \"System.Char\"),\n            (\"sbyte\", \"System.SByte\"),\n            (\"byte\", \"System.Byte\"),\n            (\"bool\", \"System.Boolean\"),\n            (\"short\", \"System.Int16\"),\n            (\"ushort\", \"System.UInt16\"),\n            (\"int\", \"System.Int32\"),\n            (\"uint\", \"System.UInt32\"),\n            (\"long\", \"System.Int64\"),\n            (\"ulong\", \"System.UInt64\"),\n            (\"float\", \"System.Single\"),\n            (\"double\", \"System.Double\"),\n            (\"decimal\", \"System.Decimal\"),\n            (\"Guid\", \"System.Guid\"),\n            (\"TimeSpan\", \"System.TimeSpan\"),\n            (\"DateTime\", \"System.DateTime\"),\n            (\"DateTimeOffset\", \"System.DateTimeOffset\"),\n            (\"Type\", \"System.Type\"),\n        };\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TypeConverter\"/> class.\n        /// </summary>\n        /// <param name=\"formatters\">The type name formatters.</param>\n        /// <param name=\"typeNameFilters\">The type name filters.</param>\n        /// <param name=\"typeFilters\">The type filters.</param>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"typeResolver\">The type resolver.</param>\n        public TypeConverter(\n            IEnumerable<ITypeConverter> formatters,\n            IEnumerable<ITypeNameFilter> typeNameFilters,\n            IEnumerable<ITypeFilter> typeFilters,\n            IOptions<TypeManifestOptions> options,\n            TypeResolver typeResolver)\n        {\n            _resolver = typeResolver;\n            _converters = formatters.ToArray();\n            _typeNameFilters = typeNameFilters.ToArray();\n            _typeFilters = typeFilters.ToArray();\n            _allowAllTypes = options.Value.AllowAllTypes;\n            _compoundTypeAliases = options.Value.CompoundTypeAliases;\n            _convertToDisplayName = ConvertToDisplayName;\n            _convertFromDisplayName = ConvertFromDisplayName;\n            _compoundAliasResolver = ResolveCompoundAliasType;\n\n            _wellKnownAliasToType = new Dictionary<QualifiedType, QualifiedType>();\n            _wellKnownTypeToAlias = new Dictionary<QualifiedType, QualifiedType>();\n\n            _allowedTypes = new ConcurrentDictionary<QualifiedType, bool>(QualifiedType.EqualityComparer);\n            _allowedTypesConfiguration = new(StringComparer.Ordinal);\n\n            if (!_allowAllTypes)\n            {\n                foreach (var t in options.Value.AllowedTypes)\n                {\n                    _allowedTypesConfiguration.Add(t);\n                }\n\n                ConsumeMetadata(options.Value);\n            }\n\n            var aliases = options.Value.WellKnownTypeAliases;\n            foreach (var item in aliases)\n            {\n                var alias = new QualifiedType(null, item.Key);\n                var spec = RuntimeTypeNameParser.Parse(RuntimeTypeNameFormatter.Format(item.Value));\n                string asmName = null;\n                if (spec is AssemblyQualifiedTypeSpec asm)\n                {\n                    asmName = asm.Assembly;\n                    spec = asm.Type;\n                }\n\n                var originalQualifiedType = new QualifiedType(asmName, spec.Format());\n                _wellKnownTypeToAlias[originalQualifiedType] = alias;\n                if (asmName is { Length: > 0 })\n                {\n                    _wellKnownTypeToAlias[new QualifiedType(null, spec.Format())] = alias;\n                }\n\n                _wellKnownAliasToType[alias] = originalQualifiedType;\n            }\n        }\n\n        private void ConsumeMetadata(TypeManifestOptions metadata)\n        {\n            AddFromMetadata(metadata.Serializers, typeof(IBaseCodec<>));\n            AddFromMetadata(metadata.Serializers, typeof(IValueSerializer<>));\n            AddFromMetadata(metadata.Serializers, typeof(IFieldCodec<>));\n            AddFromMetadata(metadata.FieldCodecs, typeof(IFieldCodec<>));\n            AddFromMetadata(metadata.Activators, typeof(IActivator<>));\n            AddFromMetadata(metadata.Copiers, typeof(IDeepCopier<>));\n            AddFromMetadata(metadata.Converters, typeof(IConverter<,>));\n            foreach (var type in metadata.InterfaceProxies)\n            {\n                AddAllowedType(type switch\n                {\n                    { IsGenericType: true } => type.GetGenericTypeDefinition(),\n                    _ => type\n                });\n            }\n\n            void AddFromMetadata(HashSet<Type> metadataCollection, Type genericType)\n            {\n                Debug.Assert(genericType.GetGenericArguments().Length >= 1);\n\n                foreach (var type in metadataCollection)\n                {\n                    var interfaces = type.GetInterfaces();\n                    foreach (var @interface in interfaces)\n                    {\n                        if (!@interface.IsGenericType)\n                        {\n                            continue;\n                        }\n\n                        if (genericType != @interface.GetGenericTypeDefinition())\n                        {\n                            continue;\n                        }\n\n                        foreach (var genericArgument in @interface.GetGenericArguments())\n                        {\n                            InspectGenericArgument(genericArgument);\n                        }\n                    }\n                }\n            }\n\n            void InspectGenericArgument(Type genericArgument)\n            {\n                if (typeof(object) == genericArgument)\n                {\n                    return;\n                }\n\n                if (genericArgument.IsConstructedGenericType && Array.Exists(genericArgument.GenericTypeArguments, arg => arg.IsGenericParameter))\n                {\n                    genericArgument = genericArgument.GetGenericTypeDefinition();\n                }\n\n                if (genericArgument.IsGenericParameter || genericArgument.IsArray)\n                {\n                    return;\n                }\n\n                AddAllowedType(genericArgument);\n            }\n\n            void AddAllowedType(Type type)\n            {\n                FormatAndAddAllowedType(type);\n\n                if (type.DeclaringType is { } declaring)\n                {\n                    AddAllowedType(declaring);\n                }\n\n                foreach (var @interface in type.GetInterfaces())\n                {\n                    FormatAndAddAllowedType(@interface);\n                }\n            }\n\n            void FormatAndAddAllowedType(Type type)\n            {\n                var formatted = RuntimeTypeNameFormatter.Format(type);\n                var parsed = RuntimeTypeNameParser.Parse(formatted);\n\n                // Use the type name rewriter to visit every component of the type.\n                var converter = this;\n                _ = RuntimeTypeNameRewriter.Rewrite(parsed, AddQualifiedType, ResolveCompoundAliasType, ref converter);\n                static QualifiedType AddQualifiedType(in QualifiedType type, ref TypeConverter self)\n                {\n                    self._allowedTypes[type] = true;\n                    return type;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Formats the provided type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"allowAllTypes\">Whether all types are allowed or not.</param>\n        /// <returns>The formatted type name.</returns>\n        public string Format(Type type, bool allowAllTypes = false) => FormatInternal(type);\n\n        /// <summary>\n        /// Formats the provided type, rewriting elements using the provided delegate.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"rewriter\">A delegate used to rewrite the type.</param>\n        /// <param name=\"allowAllTypes\">Whether all types are allowed or not.</param>\n        /// <returns>The formatted type name.</returns>\n        public string Format(Type type, Func<TypeSpec, TypeSpec> rewriter, bool allowAllTypes = false) => FormatInternal(type, rewriter);\n\n        /// <summary>\n        /// Parses the provided type string.\n        /// </summary>\n        /// <param name=\"formatted\">The formatted type name.</param>\n        /// <returns>The parsed type.</returns>\n        /// <exception cref=\"TypeLoadException\">Unable to load the resulting type.</exception>\n        public Type Parse(string formatted)\n        {\n            if (ParseInternal(formatted, out var type))\n            {\n                return type;\n            }\n\n            throw new TypeLoadException($\"Unable to parse or load type \\\"{formatted}\\\"\");\n        }\n\n        /// <summary>\n        /// Parses the provided type string.\n        /// </summary>\n        /// <param name=\"formatted\">The formatted type name.</param>\n        /// <param name=\"result\">The result.</param>\n        /// <returns><see langword=\"true\"/> if the type was parsed and loaded; otherwise <see langword=\"false\"/>.</returns>\n        public bool TryParse(string formatted, [NotNullWhen(true)] out Type result)\n        {\n            return ParseInternal(formatted, out result);\n        }\n\n        private string FormatInternal(Type type, Func<TypeSpec, TypeSpec> rewriter = null)\n        {\n            string runtimeType = null;\n            foreach (var converter in _converters)\n            {\n                if (converter.TryFormat(type, out var value))\n                {\n                    runtimeType = value;\n                    break;\n                }\n            }\n\n            if (string.IsNullOrWhiteSpace(runtimeType))\n            {\n                runtimeType = RuntimeTypeNameFormatter.Format(type);\n            }\n\n            var runtimeTypeSpec = RuntimeTypeNameParser.Parse(runtimeType);\n            ValidationResult validationState = default;\n            var displayTypeSpec = RuntimeTypeNameRewriter.Rewrite(runtimeTypeSpec, _convertToDisplayName, compoundAliasRewriter: null, ref validationState);\n            if (rewriter is not null)\n            {\n                displayTypeSpec = rewriter(displayTypeSpec);\n            }\n\n            var formatted = displayTypeSpec.Format();\n\n            if (validationState.IsTypeNameAllowed == false)\n            {\n                ThrowTypeNotAllowed(formatted, validationState.ErrorTypes);\n            }\n\n            if (!_allowAllTypes && validationState.IsTypeNameAllowed != true)\n            {\n                if (InspectType(_typeFilters, type) == false)\n                {\n                    ThrowTypeNotAllowed(type);\n                }\n            }\n\n            return formatted;\n        }\n\n        private bool ParseInternal(string formatted, out Type type)\n        {\n            var parsed = RuntimeTypeNameParser.Parse(formatted);\n            return ParseInternal(parsed, out type);\n        }\n\n        private bool ParseInternal(TypeSpec parsed, out Type type)\n        {\n            ValidationResult validationState = default;\n            var runtimeTypeSpec = RuntimeTypeNameRewriter.Rewrite(parsed, _convertFromDisplayName, _compoundAliasResolver, ref validationState);\n            var runtimeType = runtimeTypeSpec.Format();\n\n            if (validationState.IsTypeNameAllowed == false)\n            {\n                ThrowTypeNotAllowed(parsed.Format(), validationState.ErrorTypes);\n            }\n\n            foreach (var converter in _converters)\n            {\n                if (converter.TryParse(runtimeType, out type))\n                {\n                    return true;\n                }\n            }\n\n            if (_resolver.TryResolveType(runtimeType, out type))\n            {\n                if (!_allowAllTypes && validationState.IsTypeNameAllowed != true)\n                {\n                    if (InspectType(_typeFilters, type) == false)\n                    {\n                        ThrowTypeNotAllowed(type);\n                    }\n                }\n\n                return true;\n            }\n\n            return false;\n        }\n\n        private bool? IsNameTypeAllowed(in QualifiedType type)\n        {\n            if (_allowAllTypes)\n            {\n                return true;\n            }\n\n            if (_allowedTypes.TryGetValue(type, out var allowed))\n            {\n                return allowed;\n            }\n\n            foreach (var (displayName, runtimeName) in WellKnownTypeAliases)\n            {\n                if (displayName.Equals(type.Type) || runtimeName.Equals(type.Type))\n                {\n                    return true;\n                }\n            }\n\n            if (_allowedTypesConfiguration.Contains(type.Type))\n            {\n                return true;\n            }\n\n            foreach (var filter in _typeNameFilters)\n            {\n                var isAllowed = filter.IsTypeNameAllowed(type.Type, type.Assembly);\n                if (isAllowed.HasValue)\n                {\n                    allowed = _allowedTypes[type] = isAllowed.Value;\n                    return allowed;\n                }\n            }\n\n            return null;\n        }\n\n        private QualifiedType ConvertToDisplayName(in QualifiedType input, ref ValidationResult state)\n        {\n            state = UpdateValidationResult(input, state);\n\n            foreach (var (displayName, runtimeName) in WellKnownTypeAliases)\n            {\n                if (string.Equals(input.Type, runtimeName, StringComparison.OrdinalIgnoreCase))\n                {\n                    return new QualifiedType(null, displayName);\n                }\n            }\n\n            if (_wellKnownTypeToAlias.TryGetValue(input, out var alias))\n            {\n                return alias;\n            }\n\n            return input;\n        }\n\n        private QualifiedType ConvertFromDisplayName(in QualifiedType input, ref ValidationResult state)\n        {\n            state = UpdateValidationResult(input, state);\n\n            foreach (var (displayName, runtimeName) in WellKnownTypeAliases)\n            {\n                if (string.Equals(input.Type, displayName, StringComparison.OrdinalIgnoreCase))\n                {\n                    return new QualifiedType(null, runtimeName);\n                }\n            }\n\n            if (_wellKnownAliasToType.TryGetValue(input, out var type))\n            {\n                return type;\n            }\n\n            return input;\n        }\n\n        private ValidationResult UpdateValidationResult(QualifiedType input, ValidationResult state)\n        {\n            // If there has not been an error yet, inspect this type to ensure it is allowed.\n            if (IsNameTypeAllowed(input) is bool allowed)\n            {\n                var newAllowed = allowed && (state.IsTypeNameAllowed ?? true);\n                var newErrorList = state.ErrorTypes ?? new List<QualifiedType>();\n                if (!allowed)\n                {\n                    newErrorList.Add(input);\n                }\n\n                return new(newAllowed, newErrorList);\n            }\n\n            return state;\n        }\n\n        [DoesNotReturn]\n        private static void ThrowTypeNotAllowed(string fullTypeName, List<QualifiedType> errors)\n        {\n            if (errors is { Count: 1 })\n            {\n                var value = errors[0];\n\n                if (!string.IsNullOrWhiteSpace(value.Assembly))\n                {\n                    throw new InvalidOperationException($\"Type \\\"{value.Type}\\\" from assembly \\\"{value.Assembly}\\\" is not allowed. To allow it, add it to {nameof(TypeManifestOptions)}.{nameof(TypeManifestOptions.AllowedTypes)} or register an {nameof(ITypeNameFilter)} instance which allows it.\");\n                }\n                else\n                {\n                    throw new InvalidOperationException($\"Type \\\"{value.Type}\\\" is not allowed. To allow it, add it to {nameof(TypeManifestOptions)}.{nameof(TypeManifestOptions.AllowedTypes)} or register an {nameof(ITypeNameFilter)} instance which allows it.\");\n                }\n            }\n\n            StringBuilder message = new($\"Some types in the type string \\\"{fullTypeName}\\\" are not allowed by configuration. To allow them, add them to {nameof(TypeManifestOptions)}.{nameof(TypeManifestOptions.AllowedTypes)} or register an {nameof(ITypeNameFilter)} instance which allows them.\");\n            foreach (var value in errors)\n            {\n                if (!string.IsNullOrWhiteSpace(value.Assembly))\n                {\n                    message.AppendLine($\"Type \\\"{value.Type}\\\" from assembly \\\"{value.Assembly}\\\"\");\n                }\n                else\n                {\n                    message.AppendLine($\"Type \\\"{value.Type}\\\"\");\n                }\n            }\n\n            throw new InvalidOperationException(message.ToString());\n        }\n\n        [DoesNotReturn]\n        private static void ThrowTypeNotAllowed(Type value)\n        {\n            var message = $\"Type \\\"{value.FullName}\\\" is not allowed. To allow it, add it to {nameof(TypeManifestOptions)}.{nameof(TypeManifestOptions.AllowedTypes)} or register an {nameof(ITypeNameFilter)} or {nameof(ITypeFilter)} instance which allows it.\";\n            throw new InvalidOperationException(message);\n        }\n\n        private readonly struct ValidationResult\n        {\n            public ValidationResult(bool? isTypeNameAllowed, List<QualifiedType> errorTypes)\n            {\n                IsTypeNameAllowed = isTypeNameAllowed;\n                ErrorTypes = errorTypes;\n            }\n\n            public bool? IsTypeNameAllowed { get; }\n            public List<QualifiedType> ErrorTypes { get; }\n        }\n\n        private static bool? InspectType(ITypeFilter[] filters, Type type)\n        {\n            bool? result = null;\n            if (type.HasElementType)\n            {\n                result = Combine(result, InspectType(filters, type.GetElementType()));\n                return result;\n            }\n\n            foreach (var filter in filters)\n            {\n                result = Combine(result, filter.IsTypeAllowed(type));\n                if (result == false)\n                {\n                    return false;\n                }\n            }\n\n            if (type.IsConstructedGenericType)\n            {\n                foreach (var parameter in type.GenericTypeArguments)\n                {\n                    result = Combine(result, InspectType(filters, parameter));\n                    if (result == false)\n                    {\n                        return false;\n                    }\n                }\n            }\n\n            return result;\n\n            static bool? Combine(bool? left, bool? right)\n            {\n                if (left == false || right == false)\n                {\n                    return false;\n                }\n                else if (left == true || right == true)\n                {\n                    return true;\n                }\n\n                return null;\n            }\n        }\n\n        private TypeSpec ResolveCompoundAliasType<TState>(TupleTypeSpec input, ref TState state)\n        {\n            var resolvedElements = new object[input.Elements.Length];\n            for (var i = 0; i < input.Elements.Length; i++)\n            {\n                var inputElement = input.Elements[i];\n                if (inputElement is LiteralTypeSpec literal)\n                {\n                    resolvedElements[i] = literal.Value;\n                }\n                else\n                {\n                    if (!ParseInternal(inputElement, out var type))\n                    {\n                        throw new TypeLoadException($\"Unable to parse or load type \\\"{inputElement.Format()}\\\".\");\n                    }\n\n                    resolvedElements[i] = type;\n                }\n            }\n\n            var tree = _compoundTypeAliases;\n            foreach (var element in resolvedElements)\n            {\n                tree = tree?.GetChildOrDefault(element);\n                if (tree is null) break;\n            }\n\n            var resultType = tree?.Value;\n            if (resultType is null)\n            {\n                throw new TypeLoadException($\"Unable to resolve type alias \\\"{input.Format()}\\\".\");\n            }\n\n            var formatted = RuntimeTypeNameFormatter.FormatInternalNoCache(resultType, allowAliases: false);\n            var parsed = RuntimeTypeNameParser.Parse(formatted);\n            return parsed;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/TypeSystem/TypeSpec.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Linq;\nusing System.Text;\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    /// <summary>\n    /// Represents a type.\n    /// </summary>\n    public abstract class TypeSpec\n    {\n        /// <summary>\n        /// Formats this instance in a way that can be parsed by <see cref=\"RuntimeTypeNameParser\"/>.\n        /// </summary>\n        public abstract string Format();\n    }\n\n    /// <summary>\n    /// Represents a pointer (*) type.\n    /// </summary>\n    public class PointerTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PointerTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"elementType\">The element type.</param>\n        public PointerTypeSpec(TypeSpec elementType)\n        {\n            if (elementType is null)\n            {\n                throw new ArgumentNullException(nameof(elementType));\n            }\n\n            ElementType = elementType;\n        }\n\n        /// <summary>\n        /// Gets the element type.\n        /// </summary>\n        public TypeSpec ElementType { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{ElementType}*\";\n    }\n\n    /// <summary>\n    /// Represents a reference (&amp;) type.\n    /// </summary>\n    public class ReferenceTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReferenceTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"elementType\">The element type.</param>\n        public ReferenceTypeSpec(TypeSpec elementType)\n        {\n            if (elementType is null)\n            {\n                throw new ArgumentNullException(nameof(elementType));\n            }\n\n            ElementType = elementType;\n        }\n\n        /// <summary>\n        /// Gets the element type.\n        /// </summary>\n        public TypeSpec ElementType { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{ElementType}&\";\n    }\n\n    /// <summary>\n    /// Represents an array type.\n    /// </summary>\n    public class ArrayTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ArrayTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"elementType\">The array element type.</param>\n        /// <param name=\"dimensions\">The number of dimensions for the array.</param>\n        public ArrayTypeSpec(TypeSpec elementType, int dimensions)\n        {\n            if (elementType is null)\n            {\n                throw new ArgumentNullException(nameof(elementType));\n            }\n\n            if (dimensions <= 0)\n            {\n                throw new ArgumentOutOfRangeException($\"An array cannot have a dimension count of {dimensions}\");\n            }\n\n            ElementType = elementType;\n            Dimensions = dimensions;\n        }\n\n        /// <summary>\n        /// Gets the number of array dimensions.\n        /// </summary>\n        public int Dimensions { get; }\n\n        /// <summary>\n        /// Gets the element type.\n        /// </summary>\n        public TypeSpec ElementType { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{ElementType}[{new string(',', Dimensions - 1)}]\";\n    }\n\n    /// <summary>\n    /// Represents an constructed generic type.\n    /// </summary>\n    public class ConstructedGenericTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConstructedGenericTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"unconstructedType\">The unconstructed type.</param>\n        /// <param name=\"arity\">The expected number of type arguments.</param>\n        /// <param name=\"arguments\">The generic type arguments.</param>\n        public ConstructedGenericTypeSpec(TypeSpec unconstructedType, int arity, TypeSpec[] arguments)\n        {\n            if (unconstructedType is AssemblyQualifiedTypeSpec)\n            {\n                throw new InvalidOperationException();\n            }\n\n            if (unconstructedType is null)\n            {\n                throw new ArgumentNullException(nameof(unconstructedType));\n            }\n\n            if (arguments is null)\n            {\n                throw new ArgumentNullException(nameof(arguments));\n            }\n\n            if (arity != arguments.Length)\n            {\n                throw new ArgumentException($\"Invalid number of arguments {arguments.Length} provided while constructing generic type of arity {arity}: {unconstructedType}\", nameof(arguments));\n            }\n\n            foreach (var arg in arguments)\n            {\n                if (arg is null)\n                {\n                    throw new ArgumentNullException(nameof(arguments), \"Cannot construct a generic type using a null argument\");\n                }\n            }\n\n            UnconstructedType = unconstructedType;\n            Arguments = arguments;\n        }\n\n        /// <summary>\n        /// Gets the unconstructed type.\n        /// </summary>\n        public TypeSpec UnconstructedType { get; }\n\n        /// <summary>\n        /// Gets the type arguments.\n        /// </summary>\n        public TypeSpec[] Arguments { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{UnconstructedType}[{string.Join(\",\", Arguments.Select(a => $\"[{a}]\"))}]\";\n    }\n\n    /// <summary>\n    /// Represents a named type, which may be an unconstructed generic type.\n    /// </summary>\n    public class NamedTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NamedTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"containingType\">The containing type.</param>\n        /// <param name=\"name\">The type name.</param>\n        /// <param name=\"arity\">The generic arity of the type, which must be greater than or equal to the generic arity of the containing type.</param>\n        public NamedTypeSpec(NamedTypeSpec containingType, string name, int arity)\n        {\n            ContainingType = containingType;\n            Name = name;\n            if (containingType is NamedTypeSpec c && c.Arity > arity)\n            {\n                throw new ArgumentException(\"A named type cannot have an arity less than that of its containing type\", nameof(arity));\n            }\n\n            if (arity < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(arity), \"A type cannot have a negative arity\");\n            }\n\n            Arity = arity;\n        }\n\n        /// <summary>\n        /// Gets the number of generic parameters which this type requires.\n        /// </summary>\n        public int Arity { get; }\n\n        /// <summary>\n        /// Gets the type name, which includes the namespace if this is not a nested type.\n        /// </summary>\n        public string Name { get; }\n\n        /// <summary>\n        /// Gets the containing type.\n        /// </summary>\n        public NamedTypeSpec? ContainingType { get; }\n\n        /// <summary>\n        /// Gets the namespace-qualified type name, including containing types (for nested types).\n        /// </summary>\n        /// <returns>The namespace-qualified type name.</returns>\n        public string GetNamespaceQualifiedName()\n        {\n            var builder = new StringBuilder();\n            GetQualifiedNameInternal(this, builder);\n            return builder.ToString();\n\n            static void GetQualifiedNameInternal(NamedTypeSpec n, StringBuilder b)\n            {\n                if (n.ContainingType is not null)\n                {\n                    GetQualifiedNameInternal(n.ContainingType, b);\n                    _ = b.Append('+');\n                }\n\n                _ = b.Append(n.Name);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => ContainingType is not null ? $\"{ContainingType}+{Name}\" : Name;\n    }\n\n    /// <summary>\n    /// Represents an assembly-qualified type.\n    /// </summary>\n    public class AssemblyQualifiedTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AssemblyQualifiedTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"assembly\">The assembly.</param>\n        public AssemblyQualifiedTypeSpec(TypeSpec type, string? assembly)\n        {\n            if (type is null)\n            {\n                throw new ArgumentNullException(nameof(type));\n            }\n\n            if (string.IsNullOrWhiteSpace(assembly))\n            {\n                throw new ArgumentNullException(nameof(assembly));\n            }\n\n            Type = type;\n            Assembly = assembly;\n        }\n\n        /// <summary>\n        /// Gets the assembly specification.\n        /// </summary>\n        public string? Assembly { get; }\n\n        /// <summary>\n        /// Gets the qualified type.\n        /// </summary>\n        public TypeSpec Type { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => Assembly switch\n        {\n            { Length: > 0 } => $\"{Type},{Assembly!}\",\n            _ => $\"{Type}\"\n        };\n    }\n\n    /// <summary>\n    /// Represents a type function.\n    /// </summary>\n    public class TupleTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TupleTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"elements\">The tuple elements.</param>\n        /// <param name=\"arity\">The number of generic type parameters which the type accepts.</param>\n        public TupleTypeSpec(TypeSpec[] elements, int arity)\n        {\n            if (elements is null)\n            {\n                throw new ArgumentNullException(nameof(elements));\n            }\n\n            if (elements is { Length: 0 })\n            {\n                throw new ArgumentNullException(nameof(elements));\n            }\n\n            if (arity < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(arity), \"A type cannot have a negative arity\");\n            }\n\n            Arity = arity;\n\n            Elements = elements;\n        }\n\n        /// <summary>\n        /// Gets the number of generic parameters which this type requires.\n        /// </summary>\n        public int Arity { get; }\n\n        /// <summary>\n        /// Gets the tuple elements.\n        /// </summary>\n        public TypeSpec[] Elements { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            var elements = string.Join(\",\", Elements.Select(element => element switch\n            {\n                LiteralTypeSpec => element.ToString(),\n                _ => $\"[{element}]\"\n            }));\n\n            return Arity switch\n            {\n                > 0 => $\"({elements})`{Arity}\",\n                _ => $\"({elements})\"\n            };\n        }\n    }\n\n    /// <summary>\n    /// Represents a literal.\n    /// </summary>\n    public class LiteralTypeSpec : TypeSpec\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiteralTypeSpec\"/> class.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        public LiteralTypeSpec(string value)\n        {\n            if (string.IsNullOrWhiteSpace(value))\n            {\n                throw new ArgumentNullException(nameof(value));\n            }\n\n            Value = value;\n        }\n\n        /// <summary>\n        /// Gets the value.\n        /// </summary>\n        public string Value { get; }\n\n        /// <inheritdoc/>\n        public override string Format() => ToString();\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"\\\"{Value}\\\"\";\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/BitOperations.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Serialization.Utilities\n{\n#if NETCOREAPP3_1_OR_GREATER\n#else\n    /// <summary>\n    /// BitOperations polyfill.\n    /// </summary>\n    // Extracted from https://github.com/dotnet/runtime/blob/e13871cb275b9f53fa82285b2a81ada28a859b50/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs\n    internal static class BitOperations\n    {\n        private static ReadOnlySpan<byte> TrailingZeroCountDeBruijn => new byte[32]\n        {\n            00, 01, 28, 02, 29, 14, 24, 03,\n            30, 22, 20, 15, 25, 17, 04, 08,\n            31, 27, 13, 23, 21, 19, 16, 07,\n            26, 12, 18, 06, 11, 05, 10, 09\n        };\n\n        private static ReadOnlySpan<byte> Log2DeBruijn => new byte[32]\n        {\n            00, 09, 01, 10, 13, 21, 02, 29,\n            11, 14, 16, 18, 22, 25, 03, 30,\n            08, 12, 20, 28, 15, 17, 24, 07,\n            19, 27, 23, 06, 26, 05, 04, 31\n        };\n\n        /// <summary>\n        /// Returns the integer (floor) log of the specified value, base 2.\n        /// Note that by convention, input value 0 returns 0 since log(0) is undefined.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static int Log2(uint value)\n        {\n            // The 0->0 contract is fulfilled by setting the LSB to 1.\n            // Log(1) is 0, and setting the LSB for values > 1 does not change the log2 result.\n            value |= 1;\n\n            // Fallback contract is 0->0\n            return Log2SoftwareFallback(value);\n        }\n\n        /// <summary>\n        /// Returns the integer (floor) log of the specified value, base 2.\n        /// Note that by convention, input value 0 returns 0 since log(0) is undefined.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal static int Log2(ulong value)\n        {\n            value |= 1;\n\n            uint hi = (uint)(value >> 32);\n\n            if (hi == 0)\n            {\n                return Log2((uint)value);\n            }\n\n            return 32 + Log2(hi);\n        }\n\n        /// <summary>\n        /// Returns the integer (floor) log of the specified value, base 2.\n        /// Note that by convention, input value 0 returns 0 since Log(0) is undefined.\n        /// Does not directly use any hardware intrinsics, nor does it incur branching.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        private static int Log2SoftwareFallback(uint value)\n        {\n            // No AggressiveInlining due to large method size\n            // Has conventional contract 0->0 (Log(0) is undefined)\n\n            // Fill trailing zeros with ones, eg 00010010 becomes 00011111\n            value |= value >> 01;\n            value |= value >> 02;\n            value |= value >> 04;\n            value |= value >> 08;\n            value |= value >> 16;\n\n            // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check\n            return Unsafe.AddByteOffset(\n                // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u\n                ref MemoryMarshal.GetReference(Log2DeBruijn),\n                // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here\n                (IntPtr)(int)((value * 0x07C4ACDDu) >> 27));\n        }\n\n        /// <summary>\n        /// Count the number of trailing zero bits in an integer value.\n        /// Similar in behavior to the x86 instruction TZCNT.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int TrailingZeroCount(uint value)\n        {\n            // Unguarded fallback contract is 0->0, BSF contract is 0->undefined\n            if (value == 0)\n            {\n                return 32;\n            }\n\n            // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check\n            return Unsafe.AddByteOffset(\n                // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_0111_1100_1011_0101_0011_0001u\n                ref MemoryMarshal.GetReference(TrailingZeroCountDeBruijn),\n                // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here\n                (IntPtr)(int)(((value & (uint)-(int)value) * 0x077CB531u) >> 27)); // Multi-cast mitigates redundant conv.u8\n        }\n\n        /// <summary>\n        /// Count the number of trailing zero bits in a mask.\n        /// Similar in behavior to the x86 instruction TZCNT.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int TrailingZeroCount(ulong value)\n        {\n            uint lo = (uint)value;\n\n            if (lo == 0)\n            {\n                return 32 + TrailingZeroCount((uint)(value >> 32));\n            }\n\n            return TrailingZeroCount(lo);\n        }\n\n        /// <summary>Round the given integral value up to a power of 2.</summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>\n        /// The smallest power of 2 which is greater than or equal to <paramref name=\"value\"/>.\n        /// If <paramref name=\"value\"/> is 0 or the result overflows, returns 0.\n        /// </returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static uint RoundUpToPowerOf2(uint value)\n        {\n            // Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2\n            --value;\n            value |= value >> 1;\n            value |= value >> 2;\n            value |= value >> 4;\n            value |= value >> 8;\n            value |= value >> 16;\n            return value + 1;\n        }\n    }\n#endif\n}"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/BitStreamFormatter.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Buffers;\nusing System.IO;\nusing System.Text;\n\nnamespace Orleans.Serialization.Utilities\n{\n    /// <summary>\n    /// Utilities for formatting an encoded bitstream in a textual manner.\n    /// </summary>\n    public static class BitStreamFormatter\n    {\n        /// <summary>\n        /// Formats the provided buffer.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format<TInput>(ref Reader<TInput> reader)\n        {\n            var res = new StringBuilder();\n            Format(ref reader, res);\n            return res.ToString();\n        }\n\n        /// <summary>\n        /// Formats the specified array.\n        /// </summary>\n        /// <param name=\"slice\">The array.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(PooledBuffer.BufferSlice slice, SerializerSession session)\n        {\n            var reader = Reader.Create(slice, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified array.\n        /// </summary>\n        /// <param name=\"array\">The array.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(byte[] array, SerializerSession session)\n        {\n            var reader = Reader.Create(array, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified buffer.\n        /// </summary>\n        /// <param name=\"input\">The input buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(ReadOnlySpan<byte> input, SerializerSession session)\n        {\n            var reader = Reader.Create(input, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified buffer.\n        /// </summary>\n        /// <param name=\"input\">The input buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(ReadOnlyMemory<byte> input, SerializerSession session)\n        {\n            var reader = Reader.Create(input, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified buffer.\n        /// </summary>\n        /// <param name=\"input\">The input buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(ReadOnlySequence<byte> input, SerializerSession session)\n        {\n            var reader = Reader.Create(input, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified buffer.\n        /// </summary>\n        /// <param name=\"input\">The input buffer.</param>\n        /// <param name=\"session\">The session.</param>\n        /// <returns>The formatted input.</returns>\n        public static string Format(Stream input, SerializerSession session)\n        {\n            var reader = Reader.Create(input, session);\n            return Format(ref reader);\n        }\n\n        /// <summary>\n        /// Formats the specified buffer.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"result\">The destination string builder.</param>\n        public static void Format<TInput>(ref Reader<TInput> reader, StringBuilder result)\n        {\n            var (field, type) = reader.ReadFieldHeaderForAnalysis();\n            FormatField(ref reader, field, type, field.FieldIdDelta, result, indentation: 0);\n        }\n\n        private static void FormatField<TInput>(ref Reader<TInput> reader, Field field, string typeName, uint id, StringBuilder res, int indentation)\n        {\n            var indentString = new string(' ', indentation);\n            AppendAddress(ref reader, res);\n            res.Append(indentString);\n\n            // References cannot themselves be referenced.\n            if (field.WireType == WireType.Reference)\n            {\n                ReferenceCodec.MarkValueField(reader.Session);\n                var refId = reader.ReadVarUInt32();\n                res.Append('[');\n                FormatFieldHeader(res, reader.Session, field, id, typeName);\n                if (refId == 0)\n                {\n                    res.Append($\" Reference: 0\");\n                }\n                else\n                {\n                    var refd = reader.Session.ReferencedObjects.TryGetReferencedObject(refId);\n                    res.Append($\" Reference: {refId} ({refd}{(refd is null ? \"unknown\" : null)})\");\n                }\n                res.Append(']');\n                return;\n            }\n\n            // Record a placeholder so that this field can later be correctly deserialized if it is referenced.\n            ReferenceCodec.RecordObject(reader.Session, new UnknownFieldMarker(field, reader.Position));\n            res.Append('[');\n            FormatFieldHeader(res, reader.Session, field, id, typeName);\n            res.Append(']');\n            res.Append(\" Value: \");\n\n            switch (field.WireType)\n            {\n                case WireType.VarInt:\n                    {\n                        var a = reader.ReadVarUInt64();\n                        if (a < 10240)\n                        {\n                            res.Append($\"{a} (0x{a:X})\");\n                        }\n                        else\n                        {\n                            res.Append($\"0x{a:X}\");\n                        }\n                    }\n                    break;\n                case WireType.TagDelimited:\n                    // Since tag delimited fields can be comprised of other fields, recursively consume those, too.\n\n                    res.Append($\"{{\\n\");\n                    reader.FormatTagDelimitedField(res, indentation + 1);\n                    res.AppendLine();\n                    AppendAddress(ref reader, res);\n                    res.Append($\"{indentString}}}\");\n                    break;\n                case WireType.LengthPrefixed:\n                    {\n                        var length = reader.ReadVarUInt32();\n                        res.Append($\"(length: {length}b) [\");\n                        var a = reader.ReadBytes(length);\n                        FormatByteArray(res, a);\n                        res.Append(']');\n                    }\n                    break;\n                case WireType.Fixed32:\n                    {\n                        var a = reader.ReadUInt32();\n                        if (a < 10240)\n                        {\n                            res.Append($\"{a} (0x{a:X})\");\n                        }\n                        else\n                        {\n                            res.Append($\"0x{a:X}\");\n                        }\n                    }\n                    break;\n                case WireType.Fixed64:\n                    {\n                        var a = reader.ReadUInt64();\n                        if (a < 10240)\n                        {\n                            res.Append($\"{a} (0x{a:X})\");\n                        }\n                        else\n                        {\n                            res.Append($\"0x{a:X}\");\n                        }\n                    }\n                    break;\n                case WireType.Extended:\n                    SkipFieldExtension.ThrowUnexpectedExtendedWireType(field);\n                    break;\n                default:\n                    SkipFieldExtension.ThrowUnexpectedWireType(field);\n                    break;\n            }\n        }\n\n        private static void FormatByteArray(StringBuilder res, byte[] a)\n        {\n            var isAscii = true;\n            foreach (var b in a)\n            {\n                if (b >= 0x7F)\n                {\n                    isAscii = false;\n                }\n            }\n\n            if (isAscii)\n            {\n                res.Append('\"');\n                res.Append(Encoding.ASCII.GetString(a));\n                res.Append('\"');\n            }\n            else\n            {\n                bool first = true;\n                foreach (var b in a)\n                {\n                    if (!first)\n                    {\n                        res.Append(' ');\n                    }\n                    else\n                    {\n                        first = false;\n                    }\n\n                    res.Append($\"{b:X2}\");\n                }\n            }\n        }\n\n        private static void FormatFieldHeader(StringBuilder res, SerializerSession session, Field field, uint id, string typeName)\n        {\n            _ = res\n                .Append($\"#{session.ReferencedObjects.CurrentReferenceId} \")\n                .Append((string)field.WireType.ToString());\n            if (field.HasFieldId)\n            {\n                _ = res.Append($\" Id: {id}\");\n            }\n\n            if (field.IsSchemaTypeValid)\n            {\n                _ = res.Append($\" SchemaType: {field.SchemaType}\");\n            }\n\n            if (field.HasExtendedSchemaType)\n            {\n                _ = res.Append($\" RuntimeType: {field.FieldType} (name: {typeName})\");\n            }\n\n            if (field.WireType == WireType.Extended)\n            {\n                _ = res.Append($\": {field.ExtendedWireType}\");\n            }\n        }\n\n        /// <summary>\n        /// Consumes a tag-delimited field.\n        /// </summary>\n        private static void FormatTagDelimitedField<TInput>(this ref Reader<TInput> reader, StringBuilder res, int indentation)\n        {\n            var id = 0U;\n            var first = true;\n            while (true)\n            {\n                var (field, type) = reader.ReadFieldHeaderForAnalysis();\n                if (field.IsEndObject)\n                {\n                    break;\n                }\n\n                if (field.IsEndBaseFields)\n                {\n                    res.AppendLine();\n                    AppendAddress(ref reader, res);\n                    res.Append($\"{new string(' ', indentation)}- End of base type fields -\");\n                    if (first)\n                    {\n                        first = false;\n                    }\n\n                    id = 0U;\n                    continue;\n                }\n\n                id += field.FieldIdDelta;\n                if (!first)\n                {\n                    res.AppendLine();\n                }\n                else\n                {\n                    first = false;\n                }\n\n                FormatField(ref reader, field, type, id, res, indentation);\n            }\n        }\n\n        private static void AppendAddress<TInput>(ref Reader<TInput> reader, StringBuilder res)\n        {\n            res.Append($\"0x{reader.Position:X4} \");\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/FieldAccessor.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace Orleans.Serialization.Utilities\n{\n    /// <summary>\n    /// The delegate used to set fields in value types.\n    /// </summary>\n    /// <typeparam name=\"TDeclaring\">The declaring type of the field.</typeparam>\n    /// <typeparam name=\"TField\">The field type.</typeparam>\n    /// <param name=\"instance\">The instance having its field set.</param>\n    public delegate TField ValueTypeGetter<TDeclaring, out TField>(ref TDeclaring instance) where TDeclaring : struct;\n\n    /// <summary>\n    /// The delegate used to set fields in value types.\n    /// </summary>\n    /// <typeparam name=\"TDeclaring\">The declaring type of the field.</typeparam>\n    /// <typeparam name=\"TField\">The field type.</typeparam>\n    /// <param name=\"instance\">The instance having its field set.</param>\n    /// <param name=\"value\">The value being set.</param>\n    public delegate void ValueTypeSetter<TDeclaring, in TField>(ref TDeclaring instance, TField value) where TDeclaring : struct;\n\n    /// <summary>\n    /// Functionality for accessing fields.\n    /// </summary>\n    public static class FieldAccessor\n    {\n        /// <summary>\n        /// Returns a delegate to get the value of a specified field.\n        /// </summary>\n        /// <returns>A delegate to get the value of a specified field.</returns>\n        public static Delegate GetGetter(Type declaringType, string fieldName) => GetGetter(declaringType, fieldName, false);\n\n        /// <summary>\n        /// Returns a delegate to get the value of a specified field.\n        /// </summary>\n        /// <returns>A delegate to get the value of a specified field.</returns>\n        public static Delegate GetValueGetter(Type declaringType, string fieldName) => GetGetter(declaringType, fieldName, true);\n\n        private static Delegate GetGetter(Type declaringType, string fieldName, bool byref)\n        {\n            var field = declaringType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n            var parameterTypes = new[] { typeof(object), byref ? declaringType.MakeByRefType() : declaringType };\n\n            var method = new DynamicMethod(fieldName + \"Get\", field.FieldType, parameterTypes, typeof(FieldAccessor).Module, true);\n\n            var emitter = method.GetILGenerator();\n            // arg0 is unused for better delegate performance (avoids argument shuffling thunk)\n            emitter.Emit(OpCodes.Ldarg_1);\n            emitter.Emit(OpCodes.Ldfld, field);\n            emitter.Emit(OpCodes.Ret);\n\n            return method.CreateDelegate((byref ? typeof(ValueTypeGetter<,>) : typeof(Func<,>)).MakeGenericType(declaringType, field.FieldType));\n        }\n\n        /// <summary>\n        /// Returns a delegate to set the value of this field for an instance.\n        /// </summary>\n        /// <returns>A delegate to set the value of this field for an instance.</returns>\n        public static Delegate GetReferenceSetter(Type declaringType, string fieldName) => GetSetter(declaringType, fieldName, false);\n\n        /// <summary>\n        /// Returns a delegate to set the value of this field for an instance.\n        /// </summary>\n        /// <returns>A delegate to set the value of this field for an instance.</returns>\n        public static Delegate GetValueSetter(Type declaringType, string fieldName) => GetSetter(declaringType, fieldName, true);\n\n        private static Delegate GetSetter(Type declaringType, string fieldName, bool byref)\n        {\n            var field = declaringType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n            var parameterTypes = new[] { typeof(object), byref ? declaringType.MakeByRefType() : declaringType, field.FieldType };\n\n            var method = new DynamicMethod(fieldName + \"Set\", null, parameterTypes, typeof(FieldAccessor).Module, true);\n\n            var emitter = method.GetILGenerator();\n            // arg0 is unused for better delegate performance (avoids argument shuffling thunk)\n            emitter.Emit(OpCodes.Ldarg_1);\n            emitter.Emit(OpCodes.Ldarg_2);\n            emitter.Emit(OpCodes.Stfld, field);\n            emitter.Emit(OpCodes.Ret);\n\n            return method.CreateDelegate((byref ? typeof(ValueTypeSetter<,>) : typeof(Action<,>)).MakeGenericType(declaringType, field.FieldType));\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/ReferenceEqualsComparer.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Utilities\n{\n    internal sealed class ReferenceEqualsComparer : IEqualityComparer<object>, IEqualityComparer\n    {\n        public static ReferenceEqualsComparer Default { get; } = new();\n\n        public new bool Equals(object x, object y) => ReferenceEquals(x, y);\n\n        public int GetHashCode(object obj) => obj is null ? 0 : RuntimeHelpers.GetHashCode(obj);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/ServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Serialization.Utilities.Internal;\n\n/// <summary>\n/// Extension methods for configuring dependency injection.\n/// </summary>\npublic static class InternalServiceCollectionExtensions\n{\n    /// <summary>\n    /// Registers an existing registration of <typeparamref name=\"TImplementation\"/> as a provider of service type <typeparamref name=\"TService\"/>.\n    /// </summary>\n    /// <typeparam name=\"TService\">The service type being provided.</typeparam>\n    /// <typeparam name=\"TImplementation\">The implementation of <typeparamref name=\"TService\"/>.</typeparam>\n    /// <param name=\"services\">The service collection.</param>\n    public static void AddFromExisting<TService, TImplementation>(this IServiceCollection services) where TImplementation : TService\n    {\n        services.AddFromExisting(typeof(TService), typeof(TImplementation));\n    }\n\n    /// <summary>\n    /// Registers an existing registration of <paramref name=\"implementation\"/> as a provider of service type <paramref name=\"service\"/>.\n    /// </summary>\n    /// <param name=\"services\">The service collection.</param>\n    /// <param name=\"service\">The service type being provided.</param>\n    /// <param name=\"implementation\">The implementation of <paramref name=\"service\"/>.</param>\n    public static void AddFromExisting(this IServiceCollection services, Type service, Type implementation)\n    {\n        ServiceDescriptor registration = null;\n        foreach (var descriptor in services)\n        {\n            if (descriptor.ServiceType == implementation)\n            {\n                registration = descriptor;\n                break;\n            }\n        }\n\n        if (registration is null)\n        {\n            throw new ArgumentNullException(nameof(implementation), $\"Unable to find previously registered ServiceType of '{implementation.FullName}'\");\n        }\n\n        var newRegistration = new ServiceDescriptor(\n            service,\n            sp => sp.GetRequiredService(implementation),\n            registration.Lifetime);\n        services.Add(newRegistration);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/Utilities/VarIntReaderExtensions.cs",
    "content": "using Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\nusing System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.Buffers\n{\n    /// <summary>\n    /// Extension method for working with variable-width integers.\n    /// </summary>\n    public static class VarIntReaderExtensions\n    {\n        /// <summary>\n        /// Reads a variable-width <see cref=\"sbyte\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static sbyte ReadVarInt8<TInput>(this ref Reader<TInput> reader) => ZigZagDecode(checked((byte)reader.ReadVarUInt32()));\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"ushort\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static short ReadVarInt16<TInput>(this ref Reader<TInput> reader) => ZigZagDecode(checked((ushort)reader.ReadVarUInt32()));\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"byte\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static byte ReadVarUInt8<TInput>(this ref Reader<TInput> reader) => checked((byte)reader.ReadVarUInt32());\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"ushort\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ushort ReadVarUInt16<TInput>(this ref Reader<TInput> reader) => checked((ushort)reader.ReadVarUInt32());\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"int\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int ReadVarInt32<TInput>(this ref Reader<TInput> reader) => ZigZagDecode(reader.ReadVarUInt32());\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"long\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static long ReadVarInt64<TInput>(this ref Reader<TInput> reader) => ZigZagDecode(reader.ReadVarUInt64());\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"byte\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static byte ReadUInt8<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarUInt8(),\n            WireType.Fixed32 => checked((byte)reader.ReadUInt32()),\n            WireType.Fixed64 => checked((byte)reader.ReadUInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((byte)UInt128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<byte>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"ushort\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ushort ReadUInt16<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarUInt16(),\n            WireType.Fixed32 => checked((ushort)reader.ReadUInt32()),\n            WireType.Fixed64 => checked((ushort)reader.ReadUInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((ushort)UInt128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<ushort>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"uint\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static uint ReadUInt32<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarUInt32(),\n            WireType.Fixed32 => reader.ReadUInt32(),\n            WireType.Fixed64 => checked((uint)reader.ReadUInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((uint)UInt128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<uint>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"ulong\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static ulong ReadUInt64<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarUInt64(),\n            WireType.Fixed32 => reader.ReadUInt32(),\n            WireType.Fixed64 => reader.ReadUInt64(),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((ulong)UInt128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<ulong>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"sbyte\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static sbyte ReadInt8<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarInt8(),\n            WireType.Fixed32 => checked((sbyte)reader.ReadInt32()),\n            WireType.Fixed64 => checked((sbyte)reader.ReadInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((sbyte)Int128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<sbyte>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"short\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static short ReadInt16<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarInt16(),\n            WireType.Fixed32 => checked((short)reader.ReadInt32()),\n            WireType.Fixed64 => checked((short)reader.ReadInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((short)Int128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<short>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"int\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int ReadInt32<TInput>(this ref Reader<TInput> reader, WireType wireType)\n        {\n            if (wireType == WireType.VarInt)\n            {\n                return reader.ReadVarInt32();\n            }\n\n            return ReadInt32Slower(ref reader, wireType);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private static int ReadInt32Slower<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.Fixed32 => reader.ReadInt32(),\n            WireType.Fixed64 => checked((int)reader.ReadInt64()),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((int)Int128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<int>(nameof(wireType)),\n        };\n\n        /// <summary>\n        /// Reads a variable-width <see cref=\"long\"/>.\n        /// </summary>\n        /// <typeparam name=\"TInput\">The reader input type.</typeparam>\n        /// <param name=\"reader\">The reader.</param>\n        /// <param name=\"wireType\">The wire type.</param>\n        /// <returns>A variable-width integer.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static long ReadInt64<TInput>(this ref Reader<TInput> reader, WireType wireType) => wireType switch\n        {\n            WireType.VarInt => reader.ReadVarInt64(),\n            WireType.Fixed32 => reader.ReadInt32(),\n            WireType.Fixed64 => reader.ReadInt64(),\n#if NET7_0_OR_GREATER\n            WireType.LengthPrefixed => checked((long)Int128Codec.ReadRaw(ref reader)),\n#endif\n            _ => ExceptionHelper.ThrowArgumentOutOfRange<long>(nameof(wireType)),\n        };\n\n        private const sbyte Int8Msb = unchecked((sbyte)0x80);\n        private const short Int16Msb = unchecked((short)0x8000);\n        private const int Int32Msb = unchecked((int)0x80000000);\n        private const long Int64Msb = unchecked((long)0x8000000000000000);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static sbyte ZigZagDecode(byte encoded)\n        {\n            var value = (sbyte)encoded;\n            return (sbyte)(-(value & 0x01) ^ ((sbyte)(value >> 1) & ~Int8Msb));\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static short ZigZagDecode(ushort encoded)\n        {\n            var value = (short)encoded;\n            return (short)(-(value & 0x01) ^ ((short)(value >> 1) & ~Int16Msb));\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static int ZigZagDecode(uint encoded)\n        {\n            var value = (int)encoded;\n            return -(value & 0x01) ^ ((value >> 1) & ~Int32Msb);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static long ZigZagDecode(ulong encoded)\n        {\n            var value = (long)encoded;\n            return -(value & 0x01L) ^ ((value >> 1) & ~Int64Msb);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/WireProtocol/ExtendedWireType.cs",
    "content": "namespace Orleans.Serialization.WireProtocol\n{\n    /// <summary>\n    /// Represents an extended wire type\n    /// </summary>\n    public enum ExtendedWireType : uint\n    {        \n        /// <summary>\n        /// Marks the end of a tag-delimited field.\n        /// </summary>\n        EndTagDelimited = 0b00 << 3,\n\n        /// <summary>\n        /// Marks the end of base-type fields in a tag-delimited object.\n        /// </summary>\n        EndBaseFields = 0b01 << 3,\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/WireProtocol/Field.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Text;\n\nnamespace Orleans.Serialization.WireProtocol\n{\n    /// <summary>\n    /// Represents a field header.\n    /// </summary>\n    public struct Field\n    {\n        /// <summary>\n        /// The tag byte.\n        /// </summary>\n        public Tag Tag;\n\n        /// <summary>\n        /// The raw field identifier delta.\n        /// </summary>\n        public uint FieldIdDeltaRaw;\n\n        /// <summary>\n        /// The raw field type.\n        /// </summary>\n        public Type FieldTypeRaw;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Field\"/> struct.\n        /// </summary>\n        /// <param name=\"tag\">The tag.</param>\n        public Field(Tag tag)\n        {\n            Tag = tag;\n            FieldIdDeltaRaw = tag.FieldIdDelta;\n            FieldTypeRaw = null;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Field\"/> struct.\n        /// </summary>\n        /// <param name=\"tag\">The tag.</param>\n        /// <param name=\"extendedFieldIdDelta\">The extended field identifier delta.</param>\n        /// <param name=\"type\">The type.</param>\n        public Field(Tag tag, uint extendedFieldIdDelta, Type type)\n        {\n            Tag = tag;\n            FieldIdDeltaRaw = extendedFieldIdDelta;\n            FieldTypeRaw = type;\n        }\n\n        /// <summary>\n        /// Gets or sets the field identifier delta.\n        /// </summary>\n        /// <value>The field identifier delta.</value>\n        public uint FieldIdDelta\n        {\n            // If the embedded field id delta is valid, return it, otherwise return the extended field id delta.\n            // The extended field id might not be valid if this field has the Extended wire type.\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            readonly get\n            {\n#if DEBUG\n                if (!HasFieldId) throw new FieldIdNotPresentException();\n#endif\n                return FieldIdDeltaRaw;\n            }\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set\n            {\n                // If the field id delta can fit into the tag, embed it there, otherwise invalidate the embedded field id delta and set the full field id delta.\n                if (value <= Tag.MaxEmbeddedFieldIdDelta)\n                {\n                    Tag.FieldIdDelta = value;\n                }\n                else\n                {\n                    Tag.SetFieldIdInvalid();\n                }\n                FieldIdDeltaRaw = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the type of the field.\n        /// </summary>\n        /// <value>The type of the field.</value>\n        public Type FieldType\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            readonly get\n            {\n#if DEBUG\n                if (!IsSchemaTypeValid)\n                {\n                    throw new FieldTypeInvalidException();\n                }\n#endif\n                return FieldTypeRaw;\n            }\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set\n            {\n#if DEBUG\n                if (!IsSchemaTypeValid)\n                {\n                    throw new FieldTypeInvalidException();\n                }\n#endif\n                FieldTypeRaw = value;\n            }\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has a field identifier.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance has a field identifier; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool HasFieldId\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => !Tag.HasExtendedWireType;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has an extended field identifier.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance has an extended field identifier; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool HasExtendedFieldId\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => Tag.HasExtendedFieldId;\n        }\n\n        /// <summary>\n        /// Gets or sets the wire type.\n        /// </summary>\n        /// <value>The wire type.</value>\n        public WireType WireType\n        { readonly get => Tag.WireType;\n            set => Tag.WireType = value;\n        }\n\n        /// <summary>\n        /// Gets or sets the schema type.\n        /// </summary>\n        /// <value>The schema type.</value>\n        public SchemaType SchemaType\n        {\n            readonly get\n            {\n#if DEBUG\n                if (!IsSchemaTypeValid)\n                {\n                    throw new SchemaTypeInvalidException();\n                }\n#endif\n\n                return Tag.SchemaType;\n            }\n\n            set => Tag.SchemaType = value;\n        }\n\n        /// <summary>\n        /// Gets or sets the extended wire type.\n        /// </summary>\n        /// <value>The extended wire type.</value>\n        public ExtendedWireType ExtendedWireType\n        {\n            readonly get\n            {\n#if DEBUG\n                if (WireType != WireType.Extended)\n                {\n                    throw new ExtendedWireTypeInvalidException();\n                }\n#endif\n                return Tag.ExtendedWireType;\n            }\n            set => Tag.ExtendedWireType = value;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has a valid schema type.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance has a valid schema; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool IsSchemaTypeValid => Tag.IsSchemaTypeValid;\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has an extended schema type.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance has an extended schema type; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool HasExtendedSchemaType => Tag.IsSchemaTypeValid && Tag.SchemaType != SchemaType.Expected;\n\n        /// <summary>\n        /// Gets a value indicating whether this instance represents the end of base fields in a tag-delimited structure.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance represents end of base fields in a tag-delimited structure; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool IsEndBaseFields => Tag.IsEndBaseFields;\n\n        /// <summary>\n        /// Gets a value indicating whether this instance represents the end of a tag-delimited structure.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance represents end of a tag-delimited structure; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool IsEndObject => Tag.IsEndObject;\n\n        /// <summary>\n        /// Gets a value indicating whether this instance represents the end of a tag-delimited structure or the end of base fields in a tag-delimited structure.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance represents the end of a tag-delimited structure or the end of base fields in a tag-delimited structure; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool IsEndBaseOrEndObject\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => Tag.HasExtendedWireType/* && Tag.ExtendedWireType <= ExtendedWireType.EndBaseFields*/;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has a wire type of <see cref=\"WireType.Reference\"/>.\n        /// </summary>\n        public readonly bool IsReference => Tag.WireType == WireType.Reference;\n\n        /// <summary>\n        /// Ensures that the wire type is <see cref=\"WireType.TagDelimited\"/>.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void EnsureWireTypeTagDelimited()\n        {\n            if (Tag.WireType != WireType.TagDelimited)\n                UnsupportedWireType();\n        }\n\n        private void UnsupportedWireType() => throw new UnsupportedWireTypeException($\"A WireType value of {nameof(WireType.TagDelimited)} is expected by this codec. {this}\");\n\n        /// <summary>\n        /// Ensures that the wire type is supported.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void EnsureWireType(WireType expectedType)\n        {\n            if (Tag.WireType != expectedType)\n                UnsupportedWireType(expectedType);\n        }\n\n        private void UnsupportedWireType(WireType expectedType) => throw new UnsupportedWireTypeException($\"A WireType value of {expectedType} is expected by this codec. {this}\");\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n#if NET6_0_OR_GREATER\n            var builder = new DefaultInterpolatedStringHandler(0, 0);\n            builder.AppendLiteral(\"[\");\n            builder.AppendFormatted(WireType);\n\n            if (HasFieldId)\n            {\n                builder.AppendLiteral(\", IdDelta:\");\n                builder.AppendFormatted(FieldIdDelta);\n            }\n\n            if (IsSchemaTypeValid)\n            {\n                builder.AppendLiteral(\", SchemaType:\");\n                builder.AppendFormatted(SchemaType);\n            }\n\n            if (HasExtendedSchemaType)\n            {\n                builder.AppendLiteral(\", RuntimeType:\");\n                builder.AppendFormatted(FieldType);\n            }\n\n            if (Tag.HasExtendedWireType)\n            {\n                builder.AppendLiteral(\": \");\n                builder.AppendFormatted(ExtendedWireType);\n            }\n\n            builder.AppendLiteral(\"]\");\n            return builder.ToStringAndClear();\n#else\n            var builder = new StringBuilder();\n            builder.Append('[');\n            builder.Append(WireType);\n\n            if (HasFieldId)\n            {\n                builder.Append(\", IdDelta:\");\n                builder.Append(FieldIdDelta);\n            }\n\n            if (IsSchemaTypeValid)\n            {\n                builder.Append(\", SchemaType:\");\n                builder.Append(SchemaType);\n            }\n\n            if (HasExtendedSchemaType)\n            {\n                builder.Append(\", RuntimeType:\");\n                builder.Append(FieldType);\n            }\n\n            if (WireType == WireType.Extended)\n            {\n                builder.Append(\": \");\n                builder.Append(ExtendedWireType);\n            }\n\n            builder.Append(']');\n            return builder.ToString();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/WireProtocol/SchemaType.cs",
    "content": "namespace Orleans.Serialization.WireProtocol\n{\n    /// <summary>\n    /// Identifies the runtime type (schema type) of a field.\n    /// </summary>\n    public enum SchemaType : uint\n    {\n        /// <summary>\n        /// Indicates that the runtime type is the exact type expected by the current schema.\n        /// </summary>\n        Expected = 0b00 << 3,\n\n        /// <summary>\n        /// Indicates that the runtime type is an instance of a well-known type. Followed by a VarInt type id.\n        /// </summary>\n        WellKnown = 0b01 << 3,\n\n        /// <summary>\n        /// Indicates that the runtime type is encoded as a named type. Followed by an encoded type name.\n        /// </summary>\n        Encoded = 0b10 << 3,\n\n        /// <summary>\n        /// Indicates that the runtime type is a type which was previously specified. Followed by a VarInt indicating which previous type is being reused.\n        /// </summary>\n        Referenced = 0b11 << 3,\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/WireProtocol/Tag.cs",
    "content": "using System.Runtime.CompilerServices;\n\nnamespace Orleans.Serialization.WireProtocol\n{\n    /// <summary>\n    /// A serialization tag, which is always exactly a single byte. This acts as a part of the field header for all serialized fields.\n    /// </summary>\n    /// <remarks>\n    /// The typical form for a tag byte is <c>[W W W] [S S] [F F F]</c>, where each is a bit.\n    /// W is a <see cref=\"WireType\"/>, S is a <see cref=\"SchemaType\"/> bit, and F is a field identifier bit.\n    /// </remarks>\n    public struct Tag\n    {\n        /// <summary>\n        /// The wire type mask.\n        /// </summary>\n        public const byte WireTypeMask = 0b1110_0000; // The first 3 bits are dedicated to the wire type.\n\n        /// <summary>\n        /// The schema type mask.\n        /// </summary>\n        public const byte SchemaTypeMask = 0b0001_1000; // The next 2 bits are dedicated to the schema type specifier, if the schema type is expected.\n\n        /// <summary>\n        /// The field identifier mask.\n        /// </summary>\n        public const byte FieldIdMask = 0b0000_0111; // The final 3 bits are used for the field id delta, if the delta is expected.\n\n        /// <summary>\n        /// The field identifier complete mask.\n        /// </summary>\n        public const byte FieldIdCompleteMask = FieldIdMask;\n\n        /// <summary>\n        /// The extended wire type mask.\n        /// </summary>\n        public const byte ExtendedWireTypeMask = 0b0001_1000;\n\n        /// <summary>\n        /// The maximum embedded field identifier delta.\n        /// </summary>\n        public const int MaxEmbeddedFieldIdDelta = 6;\n\n        private uint _tag;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Tag\"/> struct.\n        /// </summary>\n        /// <param name=\"tag\">The tag byte.</param>\n        public Tag(byte tag) => _tag = tag;\n\n        internal Tag(uint tag) => _tag = tag;\n\n        /// <summary>\n        /// Performs an implicit conversion from <see cref=\"byte\"/> to <see cref=\"Tag\"/>.\n        /// </summary>\n        /// <param name=\"tag\">The tag.</param>\n        /// <returns>The result of the conversion.</returns>\n        public static implicit operator Tag(byte tag) => new(tag);\n\n        /// <summary>\n        /// Performs an implicit conversion from <see cref=\"Tag\"/> to <see cref=\"byte\"/>.\n        /// </summary>\n        /// <param name=\"tag\">The tag.</param>\n        /// <returns>The result of the conversion.</returns>\n        public static implicit operator byte(Tag tag) => (byte)tag._tag;\n\n        /// <summary>\n        /// Gets or sets the wire type of the data following this tag.\n        /// </summary>\n        public WireType WireType\n        {\n            readonly get => (WireType)(_tag & WireTypeMask);\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set => _tag = (_tag & ~(uint)WireTypeMask) | ((uint)value & WireTypeMask);\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance has an extended wire type.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if this instance has an extended wire type; otherwise, <see langword=\"false\" />.</value>\n        public readonly bool HasExtendedWireType\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => _tag >= (byte)WireType.Extended; //(this.tag & (byte) WireType.Extended) == (byte) WireType.Extended;\n        }\n\n        /// <summary>\n        /// Gets or sets the extended wire type of the data following this tag.\n        /// </summary>\n        public ExtendedWireType ExtendedWireType\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            readonly get => (ExtendedWireType)(_tag & ExtendedWireTypeMask);\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set => _tag = (_tag & ~(uint)ExtendedWireTypeMask) | ((uint)value & ExtendedWireTypeMask);\n        }\n\n        internal readonly bool IsEndBaseFields => _tag == ((byte)WireType.Extended | (byte)ExtendedWireType.EndBaseFields);\n\n        internal readonly bool IsEndObject => _tag == ((byte)WireType.Extended | (byte)ExtendedWireType.EndTagDelimited);\n\n        /// <summary>\n        /// Gets or sets the schema type.\n        /// </summary>\n        public SchemaType SchemaType\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            readonly get => (SchemaType)(_tag & SchemaTypeMask);\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set => _tag = (_tag & ~(uint)SchemaTypeMask) | ((uint)value & SchemaTypeMask);\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether the <see cref=\"SchemaType\" /> property is valid.\n        /// </summary>\n        /// <value><see langword=\"true\"/> if the <see cref=\"SchemaType\"/> is valid, <see langword=\"false\"/> otherwise.</value>\n        public readonly bool IsSchemaTypeValid\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => !HasExtendedWireType; //(this.tag & (byte) WireType.Extended) != (byte) WireType.Extended;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"FieldIdDelta\"/> of the field represented by this tag.\n        /// </summary>\n        /// <remarks>\n        /// If <see cref=\"IsFieldIdValid\"/> is <see langword=\"false\"/>, this value is not a complete field id delta.\n        /// </remarks>\n        public uint FieldIdDelta\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            readonly get => _tag & FieldIdMask;\n\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            set => _tag = (_tag & ~(uint)FieldIdMask) | (value & FieldIdMask);\n        }\n\n        /// <summary>\n        /// Invalidates <see cref=\"FieldIdDelta\"/>.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void SetFieldIdInvalid() => _tag |= FieldIdCompleteMask;\n\n        /// <summary>\n        /// Gets a value indicating whether the <see cref=\"FieldIdDelta\"/> property is valid.\n        /// </summary>\n        /// <value>\n        /// <see langword=\"true\"/> if the <see cref=\"FieldIdDelta\"/> represents a complete id, <see langword=\"false\"/> if more data is required.\n        /// </value>\n        /// <remarks>\n        /// If all bits are set in the field id portion of the tag, this field id is not valid and this tag must be followed by a field id.\n        /// Therefore, field ids 0-6 can be represented without additional bytes.\n        /// </remarks>\n        public readonly bool IsFieldIdValid\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => (_tag & FieldIdCompleteMask) != FieldIdCompleteMask && !HasExtendedWireType;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether the tag is followed by an extended field id.\n        /// </summary>\n        public readonly bool HasExtendedFieldId\n        {\n            [MethodImpl(MethodImplOptions.AggressiveInlining)]\n            get => (_tag & FieldIdCompleteMask) == FieldIdCompleteMask && !HasExtendedWireType;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization/WireProtocol/WireType.cs",
    "content": "namespace Orleans.Serialization.WireProtocol\n{\n    /// <summary>\n    /// Represents a 3-bit wire type, shifted into position \n    /// </summary>\n    public enum WireType : uint\n    {\n        /// <summary>\n        /// A variable-length integer vlaue.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by a variable-length integer. \n        /// </remarks>        \n        VarInt = 0b000 << 5,\n\n        /// <summary>\n        /// A compound value comprised of a collection of tag-delimited fields.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by field specifiers, then an <see cref=\"WireType.Extended\"/> tag with <see cref=\"ExtendedWireType.EndTagDelimited\"/> as the extended wire type. \n        /// </remarks>        \n        TagDelimited = 0b001 << 5,\n\n        /// <summary>\n        /// A length-prefixed value.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by VarInt length representing the number of bytes which follow. \n        /// </remarks>        \n        LengthPrefixed = 0b010 << 5,\n\n        /// <summary>\n        /// A 32-bit value.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by 4 bytes.\n        /// </remarks>        \n        Fixed32 = 0b011 << 5,\n\n        /// <summary>\n        /// A 64-bit value.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by 8 bytes.\n        /// </remarks>        \n        Fixed64 = 0b100 << 5,\n\n        /// <summary>\n        /// A reference to a previously encoded value.\n        /// </summary>\n        /// <remarks>        \n        /// Followed by 8 bytes.\n        /// </remarks>        \n        Reference = 0b110 << 5, // Followed by a VarInt reference to a previously defined object. Note that the SchemaType and type specification must still be included.\n        Extended = 0b111 << 5, // This is a control tag. The schema type and embedded field id are invalid. The remaining 5 bits are used for control information.\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/Annotations.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// When applied to a type, specifies that the type is intended to be serialized and that serialization code should be generated for the type.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]\n    public sealed class GenerateSerializerAttribute : Attribute\n    {\n        /// <summary>\n        /// Get or sets if primary constructor parameters should automatically be included as Serializable fields.\n        /// Defaults to <see langword=\"true\"/> for <see langword=\"record\"/> types, <see langword=\"false\"/> otherwise.\n        /// </summary>\n        public bool IncludePrimaryConstructorParameters { get; init; }\n\n        /// <summary>\n        /// Get or sets when Orleans should auto-assign field ids. The default behavior is to not auto-assign field ids.\n        /// </summary>\n        public GenerateFieldIds GenerateFieldIds { get; init; } = GenerateFieldIds.None;\n    }\n\n    /// <summary>\n    /// When applied to an interface, specifies that support code should be generated to allow remoting of interface calls.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed class GenerateMethodSerializersAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GenerateMethodSerializersAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"proxyBase\">The proxy base type.</param>\n        /// <param name=\"isExtension\">if set to <see langword=\"true\"/>, this is an extension interface.</param>\n        public GenerateMethodSerializersAttribute(Type proxyBase, bool isExtension = false)\n        {\n            ProxyBase = proxyBase;\n            IsExtension = isExtension;\n        }\n\n        /// <summary>\n        /// Gets the base type which the source generator will use for generated proxy classes.\n        /// </summary>\n        /// <value>The proxy base type.</value>\n        public Type ProxyBase { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this interface is an extension interface.\n        /// </summary>\n        /// <value>true if this instance is extension; otherwise, false.</value>\n        public bool IsExtension { get; }\n    }\n\n    /// <summary>\n    /// Applied to method attributes on invokable interfaces to specify the name of the method on the base type to call when submitting a request.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class InvokeMethodNameAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvokeMethodNameAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"invokeMethodName\">Name of the invoke method.</param>\n        public InvokeMethodNameAttribute(string invokeMethodName)\n        {\n            InvokeMethodName = invokeMethodName;\n        }\n\n        /// <summary>\n        /// Gets the name of the invoke method.\n        /// </summary>\n        /// <value>The name of the invoke method.</value>\n        public string InvokeMethodName { get; }\n    }\n\n    /// <summary>\n    /// Applied to proxy base types and to attribute types used on invokable interface methods to specify the base type for the invokable object which represents a method call.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public sealed class DefaultInvokeMethodNameAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultInvokeMethodNameAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"returnType\">Type of the return.</param>\n        /// <param name=\"methodName\">Name of the method.</param>\n        public DefaultInvokeMethodNameAttribute(Type returnType, string methodName)\n        {\n            ReturnType = returnType;\n            MethodName = methodName;\n        }\n\n        /// <summary>\n        /// Gets the interface method return type which this attribute applies to.\n        /// </summary>\n        public Type ReturnType { get; }\n\n        /// <summary>\n        /// Gets the name of the method on the proxy base type to call when methods are invoked.\n        /// </summary>\n        public string MethodName { get; }\n    }\n\n    /// <summary>\n    /// Applied to interface method attribute types to specify a method to be called on invokable objects which are created when invoking that interface method.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public sealed class InvokableCustomInitializerAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvokableCustomInitializerAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"methodName\">Name of the method.</param>\n        /// <param name=\"methodArgumentValue\">The method argument value.</param>\n        public InvokableCustomInitializerAttribute(string methodName, object methodArgumentValue)\n        {\n            MethodName = methodName;\n            MethodArgumentValue = methodArgumentValue;\n            AttributeArgumentIndex = -1;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvokableCustomInitializerAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"methodName\">Name of the method.</param>\n        public InvokableCustomInitializerAttribute(string methodName)\n        {\n            MethodName = methodName;\n            MethodArgumentValue = null;\n            AttributeArgumentIndex = 0;\n        }\n\n        /// <summary>\n        /// Gets the name of the method.\n        /// </summary>\n        public string MethodName { get; }\n\n        /// <summary>\n        /// Gets or sets the index of the attribute argument to propagate to the custom initializer method.\n        /// </summary>\n        public int AttributeArgumentIndex { get; init; }\n\n        /// <summary>\n        /// Gets or sets the name of the attribute argument to propagate to the custom initializer method.\n        /// </summary>\n        public int AttributeArgumentName { get; init; }\n\n        /// <summary>\n        /// Gets or sets the value to pass to the custom initializer method.\n        /// </summary>\n        public object MethodArgumentValue { get; }\n    }\n\n    /// <summary>\n    /// Applied to proxy base types and to attribute types used on invokable interface methods to specify the base type for the invokable object which represents a method call.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public sealed class DefaultInvokableBaseTypeAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultInvokableBaseTypeAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"returnType\">The return type of methods which this attribute applies to.</param>\n        /// <param name=\"invokableBaseType\">Type of the invokable base.</param>\n        public DefaultInvokableBaseTypeAttribute(Type returnType, Type invokableBaseType)\n        {\n            ReturnType = returnType;\n            InvokableBaseType = invokableBaseType;\n        }\n\n        /// <summary>\n        /// Gets the return type of methods which this attribute applies to.\n        /// </summary>\n        public Type ReturnType { get; }\n\n        /// <summary>\n        /// Gets the base type for the invokable object class which will be used to represent method calls to methods which this attribute applies to.\n        /// </summary>\n        public Type InvokableBaseType { get; }\n\n        /// <summary>\n        /// Gets or sets the name of the method on the proxy object which is used to invoke this method.\n        /// </summary>\n        public string ProxyInvokeMethodName { get; init; }\n    }\n\n    /// <summary>\n    /// Applied to attribute types used on invokable interface methods to specify the base type for the invokable object which represents a method call.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed class InvokableBaseTypeAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvokableBaseTypeAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"proxyBaseClass\">The proxy base class.</param>\n        /// <param name=\"returnType\">The return type of methods which this attribute applies to.</param>\n        /// <param name=\"invokableBaseType\">Type of the invokable base.</param>\n        public InvokableBaseTypeAttribute(Type proxyBaseClass, Type returnType, Type invokableBaseType)\n        {\n            ProxyBaseClass = proxyBaseClass;\n            ReturnType = returnType;\n            InvokableBaseType = invokableBaseType;\n        }\n\n        /// <summary>\n        /// Gets the proxy base class which this attribute applies to.\n        /// </summary>\n        public Type ProxyBaseClass { get; }\n\n        /// <summary>\n        /// Gets the method return type which this attribute applies to.\n        /// </summary>\n        public Type ReturnType { get; }\n\n        /// <summary>\n        /// Gets the base type to use for the generated invokable object.\n        /// </summary>\n        public Type InvokableBaseType { get; }\n\n        /// <summary>\n        /// Gets or sets the name of the method on the proxy object to invoke when this method is called.\n        /// </summary>\n        public string ProxyInvokeMethodName { get; init; }\n    }\n\n    /// <summary>\n    /// Applied to method attributes on invokable interfaces to specify the name of the method to call to get a completion source which is submitted to the submit method and eventually returned to the caller.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class GetCompletionSourceMethodNameAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GetCompletionSourceMethodNameAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"methodName\">The name of the method used to get a completion source for requests submitted to the runtime.</param>\n        public GetCompletionSourceMethodNameAttribute(string methodName)\n        {\n            MethodName = methodName;\n        }\n\n        /// <summary>\n        /// Gets the name of the method used to get a completion source for requests submitted to the runtime.\n        /// </summary>\n        public string MethodName { get; }\n    }\n\n    /// <summary>\n    /// Specifies the unique identity of a member.\n    /// </summary>\n    /// <remarks>\n    /// Every serializable member in a type which has <see cref=\"GenerateSerializerAttribute\"/> applied to it must have one <see cref=\"IdAttribute\"/> attribute applied with a unique <see cref=\"IdAttribute.Id\"/> value.\n    /// </remarks>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(\n        AttributeTargets.Field\n        | AttributeTargets.Property\n        | AttributeTargets.Class\n        | AttributeTargets.Struct\n        | AttributeTargets.Enum\n        | AttributeTargets.Method)]\n    public sealed class IdAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"id\">The identifier.</param>\n        public IdAttribute(uint id)\n        {\n            Id = id;\n        }\n\n        /// <summary>\n        /// Gets the identifier.\n        /// </summary>\n        /// <value>The identifier.</value>\n        public uint Id { get; }\n    }\n\n    /// <summary>\n    /// Specifies the constructor the serializer should use when creating new instances from serialized data.\n    /// </summary>\n    /// <remarks>\n    /// At most one constructor can be annotated with this attribute. If multiple constructors are annotated, the presence of this attribute is ignored.\n    /// </remarks>\n    /// <seealso cref=\"ActivatorUtilitiesConstructorAttribute\" />\n    [AttributeUsage(AttributeTargets.Constructor)]\n    [Obsolete(\"Use GeneratedActivatorConstructorAttribute instead. This attribute is not recognized by Orleans.\")]\n    public sealed class OrleansConstructorAttribute : ActivatorUtilitiesConstructorAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrleansConstructorAttribute\"/> class.\n        /// </summary>\n        public OrleansConstructorAttribute()\n        {\n        }\n    }\n\n    /// <summary>\n    /// When applied to a type or method, specifies a well-known name which can be used to identify that type or method.\n    /// </summary>\n    /// <remarks>\n    /// In the case of a type, the alias must be globally unique. In the case of a method, the alias must be unique to the declaring type.\n    /// </remarks>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(\n        AttributeTargets.Class\n        | AttributeTargets.Interface\n        | AttributeTargets.Struct\n        | AttributeTargets.Enum\n        | AttributeTargets.Method,\n        AllowMultiple = true)]\n    public sealed class AliasAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AliasAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"alias\">The alias.</param>\n        /// <remarks>\n        /// In the case of a type, the alias must be globally unique. In the case of a method, the alias must be unique to the declaring type.\n        /// </remarks>\n        public AliasAttribute(string alias)\n        {\n            Alias = alias;\n        }\n\n        /// <summary>\n        /// Gets the alias.\n        /// </summary>\n        /// <remarks>\n        /// In the case of a type, the alias must be globally unique. In the case of a method, the alias must be unique to the declaring type.\n        /// </remarks>\n        public string Alias { get; }\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type should be encoded as a relation from a specified type.\n    /// </summary>\n    /// <seealso cref=\"Attribute\" />\n    [AttributeUsage(\n        AttributeTargets.Class\n        | AttributeTargets.Interface\n        | AttributeTargets.Struct\n        | AttributeTargets.Enum,\n        AllowMultiple = true)]\n    public sealed class CompoundTypeAliasAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CompoundTypeAliasAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"components\">The alias components, each of which must be a <see cref=\"Components\"/> or a <see cref=\"string\"/>.</param>\n        public CompoundTypeAliasAttribute(params object[] components)\n        {\n            Components = components;\n        }\n\n        /// <summary>\n        /// Gets the alias components.\n        /// </summary>\n        public object[] Components { get; }\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type is a provider and that it should be automatically registered.\n    /// </summary>\n    /// <param name=\"name\">The provider name, for example, <c>\"AzureTableStorage\"</c>.</param>\n    /// <param name=\"kind\">The kind of provider, for example, <c>\"Clustering\"</c>, <c>\"Reminders\"</c>.</param>\n    /// <param name=\"target\">The intended target of the provider, for example, <c>\"Server\"</c>, <c>\"Client\"</c>.</param>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed class RegisterProviderAttribute(\n        string name,\n        string kind,\n        string target,\n#if NET5_0_OR_GREATER\n        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]\n#endif\n        Type type) : Attribute\n    {\n        /// <summary>\n        /// Gets the provider name, for example, <c>\"AzureTableStorage\"</c>.\n        /// </summary>\n        public string Name { get; } = name;\n\n        /// <summary>\n        /// Gets the kind of the provider, for example, <c>\"Clustering\"</c>, <c>\"Reminders\"</c>.\n        /// </summary>\n        public string Kind { get; } = kind;\n\n        /// <summary>\n        /// Gets the type used to configure the provider, for example, <c>\"Server\"</c>, <c>\"Client\"</c>.\n        /// </summary>\n        public string Target { get; } = target;\n\n        /// <summary>\n        /// Gets the type used to configure the provider.\n        /// </summary>\n        public Type Type { get; } = type;\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type is a serializer and that it should be automatically registered.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class RegisterSerializerAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type is an activator and that it should be automatically registered.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class RegisterActivatorAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type is an copier and that it should be automatically registered.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class RegisterCopierAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type is a converter and that it should be automatically registered.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class RegisterConverterAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that the type should be activated using a registered activator rather than via its constructor or another mechanism.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class UseActivatorAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that generated serializers for the type should not track references to the type.\n    /// </summary>\n    /// <remarks>\n    /// Reference tracking allows a serializable type to participate in a cyclic object graph.\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class SuppressReferenceTrackingAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// When applied to a type, indicates that generated serializers for the type should avoid serializing members if the member value is equal to its default value.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class OmitDefaultMemberValuesAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// Indicates that the type, type member, parameter, or return value which it is applied to should be treated as immutable and therefore that defensive copies are never required.\n    /// When applied to non-sealed classes, derived types are not guaranteed to be immutable.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]\n    public sealed class ImmutableAttribute : Attribute\n    {\n    }\n\n    /// <summary>\n    /// Indicates that the specific type is invisible for serialization purposes.\n    /// Usable only on abstract types with no serialized fields and effectively removes it from the inheritance hierarchy.\n    /// Adding/removing this attribute from a type will cause serialization protocol level incompatibility (like type hierarchy changes).\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, Inherited = false)]\n    public sealed class SerializerTransparentAttribute : Attribute { }\n\n    /// <summary>\n    /// Specifies an assembly to be added as an application part.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed class ApplicationPartAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"ApplicationPartAttribute\" />.\n        /// </summary>\n        /// <param name=\"assemblyName\">The assembly name.</param>\n        public ApplicationPartAttribute(string assemblyName)\n        {\n            AssemblyName = assemblyName ?? throw new ArgumentNullException(nameof(assemblyName));\n        }\n\n        /// <summary>\n        /// Gets the assembly name.\n        /// </summary>\n        public string AssemblyName { get; }\n    }\n\n    /// <summary>\n    /// Specifies a type to be instantiated and invoked when performing serialization operations on instances of the type which this attribute is attached to.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n    public sealed class SerializationCallbacksAttribute : Attribute\n    {\n        /// <summary>\n        /// Instantiates a new <see cref=\"SerializationCallbacksAttribute\"/> instance.\n        /// </summary>\n        /// <param name=\"hookType\">The type of the object used to invoke serialization hooks.</param>\n        public SerializationCallbacksAttribute(Type hookType)\n        {\n            HookType = hookType;\n        }\n\n        /// <summary>\n        /// The type of the hook class.\n        /// </summary>\n        /// <remarks>\n        /// This value is used to get the hooks implementation from an <see cref=\"IServiceProvider\"/>.\n        /// </remarks>\n        public Type HookType { get; }\n    }\n\n    /// <summary>\n    /// When applied to a constructor, indicates that generated activator implementations should use that constructor when activating instances.\n    /// </summary>\n    /// <remarks>\n    /// This attribute can be used to call constructors which require injected dependencies.\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Constructor)]\n    public sealed class GeneratedActivatorConstructorAttribute : ActivatorUtilitiesConstructorAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GeneratedActivatorConstructorAttribute\"/> class.\n        /// </summary>\n        public GeneratedActivatorConstructorAttribute()\n        {\n        }\n    }\n\n    /// <summary>\n    /// Indicates that the source generator should also inspect and generate code for the assembly containing the specified type.\n    /// </summary>\n    /// <seealso cref=\"System.Attribute\" />\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed class GenerateCodeForDeclaringAssemblyAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GenerateCodeForDeclaringAssemblyAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"type\">Any type in the assembly which the source generator should inspect and generate source for.</param>\n        public GenerateCodeForDeclaringAssemblyAttribute(Type type)\n        {\n            Type = type;\n        }\n\n        /// <summary>\n        /// Gets a type in the assembly which the source generator should inspect and generate source for.\n        /// </summary>\n        /// <value>The type.</value>\n        public Type Type { get; }\n    }\n\n    /// <summary>\n    /// Specifies the response timeout for the interface method which it is specified on.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Method)]\n    public sealed class ResponseTimeoutAttribute : Attribute\n    {\n        /// <summary>\n        /// Specifies the response timeout for the interface method which it is specified on.\n        /// </summary>\n        /// <param name=\"timeout\">The response timeout, using <see cref=\"TimeSpan.Parse(string)\"/> syntax.</param>\n        public ResponseTimeoutAttribute(string timeout) => Timeout = TimeSpan.Parse(timeout);\n\n        /// <summary>\n        /// Gets or sets the response timeout for this method.\n        /// </summary>\n        public TimeSpan? Timeout { get; init; }\n    }\n\n    /// <summary>\n    /// Functionality for converting between two types.\n    /// </summary>\n    public interface IConverter<TValue, TSurrogate> where TSurrogate : struct\n    {\n        /// <summary>\n        /// Converts a surrogate value to the value type.\n        /// </summary>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        /// <returns>The value.</returns>\n        TValue ConvertFromSurrogate(in TSurrogate surrogate);\n\n        /// <summary>\n        /// Converts a value to the value type.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The surrogate.</returns>\n        TSurrogate ConvertToSurrogate(in TValue value);\n    }\n\n    /// <summary>\n    /// Functionality for populating one type from another.\n    /// </summary>\n    public interface IPopulator<TValue, TSurrogate> where TSurrogate : struct where TValue : class\n    {\n        /// <summary>\n        /// Populates <paramref name=\"value\"/> with values from <paramref name=\"surrogate\"/>.\n        /// </summary>\n        /// <param name=\"surrogate\">The surrogate.</param>\n        /// <param name=\"value\">The value.</param>\n        void Populate(in TSurrogate surrogate, TValue value);\n    }\n}\n\nnamespace Orleans.Invocation\n{\n    /// <summary>\n    /// Applied to invokable base types (see TaskRequest) to indicate that instances of derived types should be returned directly from generated proxy methods rather than being passed to\n    /// the runtime for invocation. This is used to support calling patterns other than request-response, such as streaming.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class ReturnValueProxyAttribute : Attribute\n    {\n        public ReturnValueProxyAttribute(string initializerMethodName)\n        {\n            InitializerMethodName = initializerMethodName;\n        }\n\n        /// <summary>\n        /// The name of the method to \n        /// </summary>\n        public string InitializerMethodName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/FrameworkPartAttribute.cs",
    "content": "using System;\nusing System.ComponentModel;\n\nnamespace Orleans.Metadata;\n\n/// <summary>\n/// Specifies that an assembly does not contain application code.\n/// </summary>\n[AttributeUsage(AttributeTargets.Assembly)]\n[EditorBrowsable(EditorBrowsableState.Never)]\npublic sealed class FrameworkPartAttribute : Attribute\n{\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/GenerateFieldIds.cs",
    "content": "namespace Orleans;\n\n/// <summary>\n/// This enum provides options for controlling the field id generation logic.\n/// </summary>\npublic enum GenerateFieldIds\n{\n    /// <summary>\n    /// Only members explicitly annotated with a field id will be serialized. This is the default.\n    /// </summary>\n    None,\n    /// <summary>\n    /// Field ids will be automatically assigned to eligible public properties. To qualify, a property must have an accessible getter, and either an accessible setter or a corresponding constructor parameter.\n    /// </summary>\n    /// <remarks>\n    /// The presence of an explicit field id annotation on any member of a type will automatically disable automatic field id generation for that type.\n    /// </remarks>\n    PublicProperties\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Serialization.Abstractions</PackageId>\n    <Title>Microsoft Orleans Serialization Abstractions</Title>\n    <Description>Serialization abstractions for Microsoft Orleans</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks);$(CompatibilityTargetFrameworks)</TargetFrameworks>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <RootNamespace>Orleans</RootNamespace>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "src/Orleans.Serialization.Abstractions/README.md",
    "content": "# Microsoft Orleans Serialization Abstractions\n\n## Introduction\nOrleans Serialization Abstractions package provides the core interfaces and attributes needed for Orleans serialization. This package contains the definitions used for serialization but not the serialization implementation itself.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.Abstractions\n```\n\nThis package is automatically included when you reference the Orleans Serialization package or Orleans SDK.\n\n## Example\n\n```csharp\nusing Orleans.Serialization;\n\n// Define a serializable class\n[GenerateSerializer]\npublic class MyData\n{\n    [Id(0)]\n    public string Name { get; set; }\n    \n    [Id(1)]\n    public int Age { get; set; }\n    \n    [Id(2)]\n    public List<string> Tags { get; set; }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Serialization in Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [Orleans type serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization-attributes)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.FSharp/FSharpCodecs.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.FSharp.Collections;\nusing Microsoft.FSharp.Core;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization\n{\n    /// <summary>\n    /// Serializer for <see cref=\"Unit\"/>\n    /// </summary>\n    [RegisterSerializer]\n    public sealed class FSharpUnitCodec : IFieldCodec<Unit>\n    {\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, Unit value) where TBufferWriter : IBufferWriter<byte> =>\n            ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n\n        public Unit ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireType(WireType.Reference);\n            ReferenceCodec.MarkValueField(reader.Session);\n            var reference = reader.ReadVarUInt32();\n            if (reference != 0) throw new ReferenceNotFoundException(typeof(Unit), reference);\n            return null;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"Unit\"/>\n    /// </summary>\n    [RegisterCopier]\n    public sealed class FSharpUnitCopier : ShallowCopier<Unit>;\n\n    /// <summary>\n    /// Serializer for <see cref=\"FSharpOption{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The underlying type.</typeparam>\n    [RegisterSerializer]\n    public sealed class FSharpOptionCodec<T> : IFieldCodec<FSharpOption<T>>\n    {\n        private readonly Type CodecType = typeof(FSharpOption<T>);\n        private readonly Type CodecFieldType = typeof(T);\n        private readonly IFieldCodec<T> _fieldCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FSharpOptionCodec{T}\"/> class.\n        /// </summary>\n        public FSharpOptionCodec(IFieldCodec<T> fieldCodec)\n        {\n            _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n        }\n\n        /// <inheritdoc/>\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpOption<T> value) where TBufferWriter : IBufferWriter<byte>\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n                return;\n\n            writer.WriteStartObject(fieldIdDelta, expectedType, CodecType);\n            if (FSharpOption<T>.get_IsSome(value))\n            {\n                _fieldCodec.WriteField(ref writer, 0, CodecFieldType, value.Value);\n            }\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        public FSharpOption<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n                return ReferenceCodec.ReadReference<FSharpOption<T>, TInput>(ref reader, field);\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            var result = FSharpOption<T>.None;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        result = _fieldCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier implementation for <see cref=\"FSharpOption{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The underlying value type of the option type.</typeparam>\n    [RegisterCopier]\n    public sealed class FSharpOptionCopier<T> : IDeepCopier<FSharpOption<T>>\n    {\n        private readonly IDeepCopier<T> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FSharpOptionCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public FSharpOptionCopier(IDeepCopier<T> valueCopier)\n        {\n            _valueCopier = OrleansGeneratedCodeHelper.UnwrapService(this, valueCopier);\n        }\n\n        /// <inheritdoc/>\n        public FSharpOption<T> DeepCopy(FSharpOption<T> input, CopyContext context)\n        {\n            if (input is null || FSharpOption<T>.get_IsNone(input))\n            {\n                return input;\n            }\n\n            if (context.TryGetCopy<FSharpOption<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            result = _valueCopier.DeepCopy(input.Value, context);\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"FSharpValueOption{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    [RegisterSerializer]\n    public class FSharpValueOptionCodec<T> : IFieldCodec<FSharpValueOption<T>>\n    {\n        private readonly IFieldCodec<T> _valueCodec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FSharpValueOptionCodec{T}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The item codec.</param>\n        public FSharpValueOptionCodec(IFieldCodec<T> item1Codec)\n        {\n            _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n        }\n\n        /// <inheritdoc/>\n        void IFieldCodec<FSharpValueOption<T>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpValueOption<T> value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpValueOption<T>), WireType.TagDelimited);\n            if (value.IsSome)\n            {\n                _valueCodec.WriteField(ref writer, 0, typeof(T), value.Value);\n            }\n\n            writer.WriteEndObject();\n        }\n\n        /// <inheritdoc/>\n        FSharpValueOption<T> IFieldCodec<FSharpValueOption<T>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            var result = FSharpValueOption<T>.None;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 0:\n                        result = _valueCodec.ReadValue(ref reader, header);\n                        break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Copier for <see cref=\"FSharpValueOption{T}\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">The underlying value type.</typeparam>\n    [RegisterCopier]\n    public sealed class FSharpValueOptionCopier<T> : IDeepCopier<FSharpValueOption<T>>\n    {\n        private readonly IDeepCopier<T> _valueCopier;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FSharpValueOptionCopier{T}\"/> class.\n        /// </summary>\n        /// <param name=\"valueCopier\">The value copier.</param>\n        public FSharpValueOptionCopier(IDeepCopier<T> valueCopier)\n        {\n            _valueCopier = OrleansGeneratedCodeHelper.UnwrapService(this, valueCopier);\n        }\n\n        /// <inheritdoc/>\n        public FSharpValueOption<T> DeepCopy(FSharpValueOption<T> input, CopyContext context)\n        {\n            if (input.IsNone)\n            {\n                return input;\n            }\n            else\n            {\n                return FSharpValueOption<T>.Some(_valueCopier.DeepCopy(input.Value, context));\n            }\n        }\n    }\n\n    /// <summary>\n    /// Serializer for <see cref=\"FSharpChoice{T1, T2}\"/>.\n    /// </summary>\n    [RegisterSerializer]\n    public class FSharpChoiceCodec<T1, T2> : IFieldCodec<FSharpChoice<T1, T2>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FSharpChoiceCodec{T1, T2}\"/> class.\n        /// </summary>\n        /// <param name=\"item1Codec\">The codec for <typeparamref name=\"T1\"/>.</param>\n        /// <param name=\"item2Codec\">The codec for <typeparamref name=\"T2\"/>.</param>\n        public FSharpChoiceCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n        }\n\n        /// <inheritdoc/>\n        void IFieldCodec<FSharpChoice<T1, T2>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpChoice<T1, T2> value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpChoice<T1, T2>), WireType.TagDelimited);\n\n            switch (value)\n            {\n                case FSharpChoice<T1, T2>.Choice1Of2 c1: _item1Codec.WriteField(ref writer, 1, ElementType1, c1.Item); break;\n                case FSharpChoice<T1, T2>.Choice2Of2 c2: _item2Codec.WriteField(ref writer, 2, ElementType2, c2.Item); break;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpChoice<T1, T2> IFieldCodec<FSharpChoice<T1, T2>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<FSharpChoice<T1, T2>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            FSharpChoice<T1, T2> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpChoice<T1, T2>.NewChoice1Of2(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpChoice<T1, T2>.NewChoice2Of2(_item2Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpChoiceCopier<T1, T2> : IDeepCopier<FSharpChoice<T1, T2>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n\n        public FSharpChoiceCopier(IDeepCopier<T1> copier1, IDeepCopier<T2> copier2)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n        }\n\n        public FSharpChoice<T1, T2> DeepCopy(FSharpChoice<T1, T2> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out FSharpChoice<T1, T2> result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                FSharpChoice<T1, T2>.Choice1Of2 c1 => FSharpChoice<T1, T2>.NewChoice1Of2(_copier1.DeepCopy(c1.Item, context)),\n                FSharpChoice<T1, T2>.Choice2Of2 c2 => FSharpChoice<T1, T2>.NewChoice2Of2(_copier2.DeepCopy(c2.Item, context)),\n                _ => throw new NotSupportedException($\"Type {input.GetType()} is not supported\"),\n            };\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpChoiceCodec<T1, T2, T3> : IFieldCodec<FSharpChoice<T1, T2, T3>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n\n        public FSharpChoiceCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n        }\n\n        void IFieldCodec<FSharpChoice<T1, T2, T3>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpChoice<T1, T2, T3> value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpChoice<T1, T2, T3>), WireType.TagDelimited);\n\n            switch (value)\n            {\n                case FSharpChoice<T1, T2, T3>.Choice1Of3 c1: _item1Codec.WriteField(ref writer, 1, ElementType1, c1.Item); break;\n                case FSharpChoice<T1, T2, T3>.Choice2Of3 c2: _item2Codec.WriteField(ref writer, 2, ElementType2, c2.Item); break;\n                case FSharpChoice<T1, T2, T3>.Choice3Of3 c3: _item3Codec.WriteField(ref writer, 3, ElementType3, c3.Item); break;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpChoice<T1, T2, T3> IFieldCodec<FSharpChoice<T1, T2, T3>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<FSharpChoice<T1, T2, T3>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            FSharpChoice<T1, T2, T3> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpChoice<T1, T2, T3>.NewChoice1Of3(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpChoice<T1, T2, T3>.NewChoice2Of3(_item2Codec.ReadValue(ref reader, header)); break;\n                    case 3: result = FSharpChoice<T1, T2, T3>.NewChoice3Of3(_item3Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpChoiceCopier<T1, T2, T3> : IDeepCopier<FSharpChoice<T1, T2, T3>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n\n        public FSharpChoiceCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n            _copier3 = copier3;\n        }\n\n        public FSharpChoice<T1, T2, T3> DeepCopy(FSharpChoice<T1, T2, T3> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out FSharpChoice<T1, T2, T3> result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                FSharpChoice<T1, T2, T3>.Choice1Of3 c1 => FSharpChoice<T1, T2, T3>.NewChoice1Of3(_copier1.DeepCopy(c1.Item, context)),\n                FSharpChoice<T1, T2, T3>.Choice2Of3 c2 => FSharpChoice<T1, T2, T3>.NewChoice2Of3(_copier2.DeepCopy(c2.Item, context)),\n                FSharpChoice<T1, T2, T3>.Choice3Of3 c3 => FSharpChoice<T1, T2, T3>.NewChoice3Of3(_copier3.DeepCopy(c3.Item, context)),\n                _ => throw new NotSupportedException($\"Type {input.GetType()} is not supported\"),\n            };\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpChoiceCodec<T1, T2, T3, T4> : IFieldCodec<FSharpChoice<T1, T2, T3, T4>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n\n        public FSharpChoiceCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n        }\n\n        void IFieldCodec<FSharpChoice<T1, T2, T3, T4>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpChoice<T1, T2, T3, T4> value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpChoice<T1, T2, T3, T4>), WireType.TagDelimited);\n\n            switch (value)\n            {\n                case FSharpChoice<T1, T2, T3, T4>.Choice1Of4 c1: _item1Codec.WriteField(ref writer, 1, ElementType1, c1.Item); break;\n                case FSharpChoice<T1, T2, T3, T4>.Choice2Of4 c2: _item2Codec.WriteField(ref writer, 2, ElementType2, c2.Item); break;\n                case FSharpChoice<T1, T2, T3, T4>.Choice3Of4 c3: _item3Codec.WriteField(ref writer, 3, ElementType3, c3.Item); break;\n                case FSharpChoice<T1, T2, T3, T4>.Choice4Of4 c4: _item4Codec.WriteField(ref writer, 4, ElementType4, c4.Item); break;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpChoice<T1, T2, T3, T4> IFieldCodec<FSharpChoice<T1, T2, T3, T4>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<FSharpChoice<T1, T2, T3, T4>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            FSharpChoice<T1, T2, T3, T4> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpChoice<T1, T2, T3, T4>.NewChoice1Of4(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpChoice<T1, T2, T3, T4>.NewChoice2Of4(_item2Codec.ReadValue(ref reader, header)); break;\n                    case 3: result = FSharpChoice<T1, T2, T3, T4>.NewChoice3Of4(_item3Codec.ReadValue(ref reader, header)); break;\n                    case 4: result = FSharpChoice<T1, T2, T3, T4>.NewChoice4Of4(_item4Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpChoiceCopier<T1, T2, T3, T4> : IDeepCopier<FSharpChoice<T1, T2, T3, T4>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n\n        public FSharpChoiceCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n            _copier3 = copier3;\n            _copier4 = copier4;\n        }\n\n        public FSharpChoice<T1, T2, T3, T4> DeepCopy(FSharpChoice<T1, T2, T3, T4> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out FSharpChoice<T1, T2, T3, T4> result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                FSharpChoice<T1, T2, T3, T4>.Choice1Of4 c1 => FSharpChoice<T1, T2, T3, T4>.NewChoice1Of4(_copier1.DeepCopy(c1.Item, context)),\n                FSharpChoice<T1, T2, T3, T4>.Choice2Of4 c2 => FSharpChoice<T1, T2, T3, T4>.NewChoice2Of4(_copier2.DeepCopy(c2.Item, context)),\n                FSharpChoice<T1, T2, T3, T4>.Choice3Of4 c3 => FSharpChoice<T1, T2, T3, T4>.NewChoice3Of4(_copier3.DeepCopy(c3.Item, context)),\n                FSharpChoice<T1, T2, T3, T4>.Choice4Of4 c4 => FSharpChoice<T1, T2, T3, T4>.NewChoice4Of4(_copier4.DeepCopy(c4.Item, context)),\n                _ => throw new NotSupportedException($\"Type {input.GetType()} is not supported\"),\n            };\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpChoiceCodec<T1, T2, T3, T4, T5> : IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n\n        public FSharpChoiceCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n        }\n\n        void IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpChoice<T1, T2, T3, T4, T5> value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpChoice<T1, T2, T3, T4, T5>), WireType.TagDelimited);\n\n            switch (value)\n            {\n                case FSharpChoice<T1, T2, T3, T4, T5>.Choice1Of5 c1: _item1Codec.WriteField(ref writer, 1, ElementType1, c1.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5>.Choice2Of5 c2: _item2Codec.WriteField(ref writer, 2, ElementType2, c2.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5>.Choice3Of5 c3: _item3Codec.WriteField(ref writer, 3, ElementType3, c3.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5>.Choice4Of5 c4: _item4Codec.WriteField(ref writer, 4, ElementType4, c4.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5>.Choice5Of5 c5: _item5Codec.WriteField(ref writer, 5, ElementType5, c5.Item); break;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpChoice<T1, T2, T3, T4, T5> IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<FSharpChoice<T1, T2, T3, T4, T5>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            FSharpChoice<T1, T2, T3, T4, T5> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpChoice<T1, T2, T3, T4, T5>.NewChoice1Of5(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpChoice<T1, T2, T3, T4, T5>.NewChoice2Of5(_item2Codec.ReadValue(ref reader, header)); break;\n                    case 3: result = FSharpChoice<T1, T2, T3, T4, T5>.NewChoice3Of5(_item3Codec.ReadValue(ref reader, header)); break;\n                    case 4: result = FSharpChoice<T1, T2, T3, T4, T5>.NewChoice4Of5(_item4Codec.ReadValue(ref reader, header)); break;\n                    case 5: result = FSharpChoice<T1, T2, T3, T4, T5>.NewChoice5Of5(_item5Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpChoiceCopier<T1, T2, T3, T4, T5> : IDeepCopier<FSharpChoice<T1, T2, T3, T4, T5>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n\n        public FSharpChoiceCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n            _copier3 = copier3;\n            _copier4 = copier4;\n            _copier5 = copier5;\n        }\n\n        public FSharpChoice<T1, T2, T3, T4, T5> DeepCopy(FSharpChoice<T1, T2, T3, T4, T5> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out FSharpChoice<T1, T2, T3, T4, T5> result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                FSharpChoice<T1, T2, T3, T4, T5>.Choice1Of5 c1 => FSharpChoice<T1, T2, T3, T4, T5>.NewChoice1Of5(_copier1.DeepCopy(c1.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5>.Choice2Of5 c2 => FSharpChoice<T1, T2, T3, T4, T5>.NewChoice2Of5(_copier2.DeepCopy(c2.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5>.Choice3Of5 c3 => FSharpChoice<T1, T2, T3, T4, T5>.NewChoice3Of5(_copier3.DeepCopy(c3.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5>.Choice4Of5 c4 => FSharpChoice<T1, T2, T3, T4, T5>.NewChoice4Of5(_copier4.DeepCopy(c4.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5>.Choice5Of5 c5 => FSharpChoice<T1, T2, T3, T4, T5>.NewChoice5Of5(_copier5.DeepCopy(c5.Item, context)),\n                _ => throw new NotSupportedException($\"Type {input.GetType()} is not supported\"),\n            };\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpChoiceCodec<T1, T2, T3, T4, T5, T6> : IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5, T6>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T1);\n        private readonly Type ElementType2 = typeof(T2);\n        private readonly Type ElementType3 = typeof(T3);\n        private readonly Type ElementType4 = typeof(T4);\n        private readonly Type ElementType5 = typeof(T5);\n        private readonly Type ElementType6 = typeof(T6);\n\n        private readonly IFieldCodec<T1> _item1Codec;\n        private readonly IFieldCodec<T2> _item2Codec;\n        private readonly IFieldCodec<T3> _item3Codec;\n        private readonly IFieldCodec<T4> _item4Codec;\n        private readonly IFieldCodec<T5> _item5Codec;\n        private readonly IFieldCodec<T6> _item6Codec;\n\n        public FSharpChoiceCodec(\n            IFieldCodec<T1> item1Codec,\n            IFieldCodec<T2> item2Codec,\n            IFieldCodec<T3> item3Codec,\n            IFieldCodec<T4> item4Codec,\n            IFieldCodec<T5> item5Codec,\n            IFieldCodec<T6> item6Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n            _item3Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item3Codec);\n            _item4Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item4Codec);\n            _item5Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item5Codec);\n            _item6Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item6Codec);\n        }\n\n        void IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5, T6>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpChoice<T1, T2, T3, T4, T5, T6> value)\n        {\n            if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n            {\n                return;\n            }\n\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpChoice<T1, T2, T3, T4, T5, T6>), WireType.TagDelimited);\n\n            switch (value)\n            {\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice1Of6 c1: _item1Codec.WriteField(ref writer, 1, ElementType1, c1.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice2Of6 c2: _item2Codec.WriteField(ref writer, 2, ElementType2, c2.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice3Of6 c3: _item3Codec.WriteField(ref writer, 3, ElementType3, c3.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice4Of6 c4: _item4Codec.WriteField(ref writer, 4, ElementType4, c4.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice5Of6 c5: _item5Codec.WriteField(ref writer, 5, ElementType5, c5.Item); break;\n                case FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice6Of6 c6: _item6Codec.WriteField(ref writer, 6, ElementType6, c6.Item); break;\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpChoice<T1, T2, T3, T4, T5, T6> IFieldCodec<FSharpChoice<T1, T2, T3, T4, T5, T6>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            if (field.WireType == WireType.Reference)\n            {\n                return ReferenceCodec.ReadReference<FSharpChoice<T1, T2, T3, T4, T5, T6>, TInput>(ref reader, field);\n            }\n\n            field.EnsureWireTypeTagDelimited();\n\n            var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n            FSharpChoice<T1, T2, T3, T4, T5, T6> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice1Of6(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice2Of6(_item2Codec.ReadValue(ref reader, header)); break;\n                    case 3: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice3Of6(_item3Codec.ReadValue(ref reader, header)); break;\n                    case 4: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice4Of6(_item4Codec.ReadValue(ref reader, header)); break;\n                    case 5: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice5Of6(_item5Codec.ReadValue(ref reader, header)); break;\n                    case 6: result = FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice6Of6(_item6Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpChoiceCopier<T1, T2, T3, T4, T5, T6> : IDeepCopier<FSharpChoice<T1, T2, T3, T4, T5, T6>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T1> _copier1;\n        private readonly IDeepCopier<T2> _copier2;\n        private readonly IDeepCopier<T3> _copier3;\n        private readonly IDeepCopier<T4> _copier4;\n        private readonly IDeepCopier<T5> _copier5;\n        private readonly IDeepCopier<T6> _copier6;\n\n        public FSharpChoiceCopier(\n            IDeepCopier<T1> copier1,\n            IDeepCopier<T2> copier2,\n            IDeepCopier<T3> copier3,\n            IDeepCopier<T4> copier4,\n            IDeepCopier<T5> copier5,\n            IDeepCopier<T6> copier6)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n            _copier3 = copier3;\n            _copier4 = copier4;\n            _copier5 = copier5;\n            _copier6 = copier6;\n        }\n\n        public FSharpChoice<T1, T2, T3, T4, T5, T6> DeepCopy(FSharpChoice<T1, T2, T3, T4, T5, T6> input, CopyContext context)\n        {\n            if (context.TryGetCopy(input, out FSharpChoice<T1, T2, T3, T4, T5, T6> result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice1Of6 c1 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice1Of6(_copier1.DeepCopy(c1.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice2Of6 c2 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice2Of6(_copier2.DeepCopy(c2.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice3Of6 c3 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice3Of6(_copier3.DeepCopy(c3.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice4Of6 c4 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice4Of6(_copier4.DeepCopy(c4.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice5Of6 c5 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice5Of6(_copier5.DeepCopy(c5.Item, context)),\n                FSharpChoice<T1, T2, T3, T4, T5, T6>.Choice6Of6 c6 => FSharpChoice<T1, T2, T3, T4, T5, T6>.NewChoice6Of6(_copier6.DeepCopy(c6.Item, context)),\n                _ => throw new NotSupportedException($\"Type {input.GetType()} is not supported\"),\n            };\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpRefCodec<T> : GeneralizedReferenceTypeSurrogateCodec<FSharpRef<T>, FSharpRefSurrogate<T>>\n    {\n        public FSharpRefCodec(IValueSerializer<FSharpRefSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override FSharpRef<T> ConvertFromSurrogate(ref FSharpRefSurrogate<T> surrogate)\n        {\n            return new FSharpRef<T>(surrogate.Value);\n        }\n\n        public override void ConvertToSurrogate(FSharpRef<T> value, ref FSharpRefSurrogate<T> surrogate)\n        {\n            surrogate.Value = value.Value;\n        }\n    }\n\n    [GenerateSerializer]\n    public struct FSharpRefSurrogate<T>\n    {\n        [Id(0)]\n        public T Value { get; set; }\n    }\n\n    [RegisterCopier]\n    public class FSharpRefCopier<T> : IDeepCopier<FSharpRef<T>>\n    {\n        private readonly IDeepCopier<T> _copier;\n        public FSharpRefCopier(IDeepCopier<T> copier) => _copier = copier;\n        public FSharpRef<T> DeepCopy(FSharpRef<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<FSharpRef<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            result = input switch\n            {\n                not null => new FSharpRef<T>(_copier.DeepCopy(input.Value, context)),\n                null => null\n            };\n\n            context.RecordCopy(input, result);\n            return result;\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpListCodec<T> : GeneralizedReferenceTypeSurrogateCodec<FSharpList<T>, FSharpListSurrogate<T>>\n    {\n        public FSharpListCodec(IValueSerializer<FSharpListSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override FSharpList<T> ConvertFromSurrogate(ref FSharpListSurrogate<T> surrogate)\n        {\n            if (surrogate.Value is null) return null;\n\n            return ListModule.OfSeq(surrogate.Value);\n        }\n\n        public override void ConvertToSurrogate(FSharpList<T> value, ref FSharpListSurrogate<T> surrogate)\n        {\n            if (value is null) return;\n\n            surrogate.Value = new(ListModule.ToSeq(value));\n        }\n    }\n\n    [GenerateSerializer]\n    public struct FSharpListSurrogate<T>\n    {\n        [Id(0)]\n        public List<T> Value { get; set; }\n    }\n\n    [RegisterCopier]\n    public class FSharpListCopier<T> : IDeepCopier<FSharpList<T>>\n    {\n        private readonly IDeepCopier<T> _copier;\n        public FSharpListCopier(IDeepCopier<T> copier) => _copier = copier;\n\n        public FSharpList<T> DeepCopy(FSharpList<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<FSharpList<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            result = ListModule.OfSeq(CopyElements(input, context));\n            context.RecordCopy(input, result);\n            return result;\n\n            IEnumerable<T> CopyElements(FSharpList<T> list, CopyContext context)\n            {\n                foreach (var element in list)\n                {\n                    yield return _copier.DeepCopy(element, context);\n                }\n            }\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<FSharpSet<T>, FSharpSetSurrogate<T>>\n    {\n        public FSharpSetCodec(IValueSerializer<FSharpSetSurrogate<T>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override FSharpSet<T> ConvertFromSurrogate(ref FSharpSetSurrogate<T> surrogate)\n        {\n            if (surrogate.Value is null) return null;\n            return new FSharpSet<T>(surrogate.Value);\n        }\n\n        public override void ConvertToSurrogate(FSharpSet<T> value, ref FSharpSetSurrogate<T> surrogate)\n        {\n            if (value is null) return;\n            surrogate.Value = value.ToList();\n        }\n    }\n\n    [GenerateSerializer]\n    public struct FSharpSetSurrogate<T>\n    {\n        [Id(0)]\n        public List<T> Value { get; set; }\n    }\n\n    [RegisterCopier]\n    public class FSharpSetCopier<T> : IDeepCopier<FSharpSet<T>>\n    {\n        private readonly IDeepCopier<T> _copier;\n        public FSharpSetCopier(IDeepCopier<T> copier) => _copier = copier;\n\n        public FSharpSet<T> DeepCopy(FSharpSet<T> input, CopyContext context)\n        {\n            if (context.TryGetCopy<FSharpSet<T>>(input, out var result))\n            {\n                return result;\n            }\n\n            result = SetModule.OfSeq(CopyElements(input, context));\n            context.RecordCopy(input, result);\n            return result;\n\n            IEnumerable<T> CopyElements(FSharpSet<T> vals, CopyContext context)\n            {\n                foreach (var element in vals)\n                {\n                    yield return _copier.DeepCopy(element, context);\n                }\n            }\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpMapCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<FSharpMap<TKey, TValue>, FSharpMapSurrogate<TKey, TValue>>\n    {\n        public FSharpMapCodec(IValueSerializer<FSharpMapSurrogate<TKey, TValue>> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override FSharpMap<TKey, TValue> ConvertFromSurrogate(ref FSharpMapSurrogate<TKey, TValue> surrogate)\n        {\n            if (surrogate.Value is null) return null;\n\n            return new FSharpMap<TKey, TValue>(surrogate.Value);\n        }\n\n        public override void ConvertToSurrogate(FSharpMap<TKey, TValue> value, ref FSharpMapSurrogate<TKey, TValue> surrogate)\n        {\n            if (value is null) return;\n\n            surrogate.Value = new(value.Count);\n            surrogate.Value.AddRange(MapModule.ToSeq(value));\n        }\n    }\n\n    [GenerateSerializer]\n    public struct FSharpMapSurrogate<TKey, TValue>\n    {\n        [Id(0)]\n        public List<Tuple<TKey, TValue>> Value { get; set; }\n    }\n\n    [RegisterCopier]\n    public class FSharpMapCopier<TKey, TValue> : IDeepCopier<FSharpMap<TKey, TValue>>\n    {\n        private readonly IDeepCopier<TKey> _keyCopier;\n        private readonly IDeepCopier<TValue> _valueCopier;\n\n        public FSharpMapCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n        {\n            _keyCopier = keyCopier;\n            _valueCopier = valueCopier;\n        }\n\n        public FSharpMap<TKey, TValue> DeepCopy(FSharpMap<TKey, TValue> input, CopyContext context)\n        {\n            if (context.TryGetCopy<FSharpMap<TKey, TValue>>(input, out var result))\n            {\n                return result;\n            }\n\n            result = MapModule.OfSeq(CopyElements(input, context));\n            context.RecordCopy(input, result);\n            return result;\n\n            IEnumerable<Tuple<TKey, TValue>> CopyElements(FSharpMap<TKey, TValue> vals, CopyContext context)\n            {\n                foreach (var element in vals)\n                {\n                    yield return Tuple.Create(_keyCopier.DeepCopy(element.Key, context), _valueCopier.DeepCopy(element.Value, context));\n                }\n            }\n        }\n    }\n\n    [RegisterSerializer]\n    public class FSharpResultCodec<T, TError> : IFieldCodec<FSharpResult<T, TError>>, IDerivedTypeCodec\n    {\n        private readonly Type ElementType1 = typeof(T);\n        private readonly Type ElementType2 = typeof(TError);\n\n        private readonly IFieldCodec<T> _item1Codec;\n        private readonly IFieldCodec<TError> _item2Codec;\n\n        public FSharpResultCodec(IFieldCodec<T> item1Codec, IFieldCodec<TError> item2Codec)\n        {\n            _item1Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item1Codec);\n            _item2Codec = OrleansGeneratedCodeHelper.UnwrapService(this, item2Codec);\n        }\n\n        void IFieldCodec<FSharpResult<T, TError>>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, FSharpResult<T, TError> value)\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(FSharpResult<T, TError>), WireType.TagDelimited);\n\n            if (value.IsError)\n            {\n                _item2Codec.WriteField(ref writer, 2, ElementType2, value.ErrorValue);\n            }\n            else\n            {\n                _item1Codec.WriteField(ref writer, 1, ElementType1, value.ResultValue);\n            }\n\n            writer.WriteEndObject();\n        }\n\n        FSharpResult<T, TError> IFieldCodec<FSharpResult<T, TError>>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            ReferenceCodec.MarkValueField(reader.Session);\n            FSharpResult<T, TError> result = default;\n            uint fieldId = 0;\n            while (true)\n            {\n                var header = reader.ReadFieldHeader();\n                if (header.IsEndBaseOrEndObject)\n                {\n                    break;\n                }\n\n                fieldId += header.FieldIdDelta;\n                switch (fieldId)\n                {\n                    case 1: result = FSharpResult<T, TError>.NewOk(_item1Codec.ReadValue(ref reader, header)); break;\n                    case 2: result = FSharpResult<T, TError>.NewError(_item2Codec.ReadValue(ref reader, header)); break;\n                    default:\n                        reader.ConsumeUnknownField(header);\n                        break;\n                }\n            }\n\n            return result;\n        }\n    }\n    \n    [RegisterCopier]\n    public class FSharpResultCopier<T, TError> : IDeepCopier<FSharpResult<T, TError>>, IDerivedTypeCopier\n    {\n        private readonly IDeepCopier<T> _copier1;\n        private readonly IDeepCopier<TError> _copier2;\n\n        public FSharpResultCopier(IDeepCopier<T> copier1, IDeepCopier<TError> copier2)\n        {\n            _copier1 = copier1;\n            _copier2 = copier2;\n        }\n\n        public FSharpResult<T, TError> DeepCopy(FSharpResult<T, TError> input, CopyContext context)\n        {\n            if (input.IsError)\n            {\n                return FSharpResult<T, TError>.NewError(_copier2.DeepCopy(input.ErrorValue, context));\n            }\n            else\n            {\n                return FSharpResult<T, TError>.NewOk(_copier1.DeepCopy(input.ResultValue, context));\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/Orleans.Serialization.FSharp/Orleans.Serialization.FSharp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.FSharp</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>F# core type support for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FSharp.Core\" />\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.FSharp/README.md",
    "content": "# Microsoft Orleans Serialization for F#\n\n## Introduction\nMicrosoft Orleans Serialization for F# provides serialization support for F# specific types in Microsoft Orleans. This package enables seamless integration of F# types like discriminated unions, records, and other F# specific constructs with Orleans serialization system.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.FSharp\n```\n\n## Example - Configuring F# Serialization\n```fsharp\nopen Microsoft.Extensions.Hosting\nopen Orleans.Hosting\n\nlet builder = \n    Host.CreateApplicationBuilder(args)\n        .UseOrleans(fun siloBuilder ->\n            siloBuilder\n                .UseLocalhostClustering()\n                // F# serialization is automatically configured when the package is referenced\n                |> ignore)\n\n// Run the host\nawait builder.RunAsync()\n```\n\n## Example - Using F# Types with Orleans\n```fsharp\n// Define F# discriminated union and record types\n[<Orleans.GenerateSerializer>]\ntype UserRole =\n    | [<Id(0u)>] Admin\n    | [<Id(1u)>] Moderator\n    | [<Id(2u)>] User of level:int\n\n[<Orleans.GenerateSerializer>]\ntype UserRecord = {\n    [<Id(0u)>] Id: string\n    [<Id(1u)>] Name: string\n    [<Id(2u)>] Role: UserRole\n    [<Id(3u)>] Tags: string list\n}\n\n// Define a grain interface\ntype IFSharpGrain =\n    inherit Orleans.IGrainWithStringKey\n    abstract member GetUser: unit -> Task<UserRecord>\n    abstract member UpdateUser: UserRecord -> Task\n\n// Grain implementation\ntype FSharpGrain() =\n    inherit Orleans.Grain()\n    let mutable userData = Unchecked.defaultof<UserRecord>\n\n    interface IFSharpGrain with\n        member this.GetUser() =\n            Task.FromResult(userData)\n            \n        member this.UpdateUser(user) =\n            userData <- user\n            Task.CompletedTask\n```\n\n## Example - Client Code Using F# Grain\n```fsharp\n// Client-side code\nlet client = clientBuilder.Build()\nlet grain = client.GetGrain<IFSharpGrain>(\"user1\")\n\n// Create an F# record with discriminated union\nlet user = {\n    Id = \"user1\"\n    Name = \"F# User\"\n    Role = UserRole.Admin\n    Tags = [\"functional\"; \"programming\"]\n}\n\n// Call the grain with F# types\ngrain.UpdateUser(user) |> Async.AwaitTask |> ignore\nlet retrievedUser = grain.GetUser() |> Async.AwaitTask |> Async.RunSynchronously\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [F# Documentation](https://learn.microsoft.com/en-us/dotnet/fsharp/)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.MemoryPack/MemoryPackCodec.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Reflection;\nusing MemoryPack;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// A serialization codec which uses <see cref=\"MemoryPackSerializer\"/>.\n/// </summary>\n/// <remarks>\n/// MemoryPack codec performs slightly worse than default Orleans serializer, if performance is critical for your application, consider using default serialization.\n/// </remarks>\n[Alias(WellKnownAlias)]\npublic class MemoryPackCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter\n{\n    private static readonly ConcurrentDictionary<Type, bool> SupportedTypes = new();\n    private static readonly Type SelfType = typeof(MemoryPackCodec);\n\n    private readonly ICodecSelector[] _serializableTypeSelectors;\n    private readonly ICopierSelector[] _copyableTypeSelectors;\n    private readonly MemoryPackCodecOptions _options;\n\n    /// <summary>\n    /// The well-known type alias for this codec.\n    /// </summary>\n    public const string WellKnownAlias = \"memorypack\";\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"MemoryPackCodec\"/> class.\n    /// </summary>\n    /// /// <param name=\"serializableTypeSelectors\">Filters used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"copyableTypeSelectors\">Filters used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"options\">The MemoryPack codec options.</param>\n    public MemoryPackCodec(\n        IEnumerable<ICodecSelector> serializableTypeSelectors,\n        IEnumerable<ICopierSelector> copyableTypeSelectors,\n        IOptions<MemoryPackCodecOptions> options)\n    {\n        _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _options = options.Value;\n    }\n\n    /// <inheritdoc/>\n    void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        // The schema type when serializing the field is the type of the codec.\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);\n\n        // Write the type name\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);\n        writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());\n\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n        try\n        {\n            MemoryPackSerializer.Serialize(value.GetType(), bufferWriter, value, _options.SerializerOptions);\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)bufferWriter.Value.Length);\n            bufferWriter.Value.CopyTo(ref writer);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.IsReference)\n        {\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        object result = null;\n        Type type = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                    break;\n                case 1:\n                    if (type is null)\n                    {\n                        ThrowTypeFieldMissing();\n                    }\n\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    var length = reader.ReadVarUInt32();\n\n                    var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n                    try\n                    {\n                        reader.ReadBytes(ref bufferWriter, (int)length);\n                        result = MemoryPackSerializer.Deserialize(type, bufferWriter.Value.AsReadOnlySequence(), _options.SerializerOptions);\n                    }\n                    finally\n                    {\n                        bufferWriter.Value.Dispose();\n                    }\n\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCodec.IsSupportedType(Type type)\n    {\n        if (type == SelfType)\n        {\n            return true;\n        }\n\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _serializableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsSerializableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return IsMemoryPackContract(type);\n    }\n\n    /// <inheritdoc/>\n    object IDeepCopier.DeepCopy(object input, CopyContext context)\n    {\n        if (context.TryGetCopy(input, out object result))\n        {\n            return result;\n        }\n\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n        try\n        {\n            MemoryPackSerializer.Serialize(input.GetType(), bufferWriter, input, _options.SerializerOptions);\n\n            var sequence = bufferWriter.Value.AsReadOnlySequence();\n            result = MemoryPackSerializer.Deserialize(input.GetType(), sequence, _options.SerializerOptions);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        context.RecordCopy(input, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCopier.IsSupportedType(Type type)\n    {\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _copyableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsCopyableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return IsMemoryPackContract(type);\n    }\n\n    /// <inheritdoc/>\n    bool? ITypeFilter.IsTypeAllowed(Type type) => (((IGeneralizedCopier)this).IsSupportedType(type) || ((IGeneralizedCodec)this).IsSupportedType(type)) ? true : null;\n\n    private static bool IsMemoryPackContract(Type type)\n    {\n        if (SupportedTypes.TryGetValue(type, out bool isMemoryPackContract))\n        {\n            return isMemoryPackContract;\n        }\n\n        isMemoryPackContract = type.GetCustomAttribute<MemoryPackableAttribute>() is not null;\n\n        SupportedTypes.TryAdd(type, isMemoryPackContract);\n        return isMemoryPackContract;\n    }\n\n    private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException(\"Serialized value is missing its type field.\");\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.MemoryPack/MemoryPackCodecOptions.cs",
    "content": "using System;\nusing MemoryPack;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Options for <see cref=\"MemoryPackCodec\"/>.\n/// </summary>\npublic class MemoryPackCodecOptions\n{\n    /// <summary>\n    /// Gets or sets the <see cref=\"MemoryPackSerializerOptions\"/>.\n    /// </summary>\n    public MemoryPackSerializerOptions SerializerOptions { get; set; } = MemoryPackSerializerOptions.Default;\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the MemoryPack serializer for serialization and deserialization.\n    /// </summary>\n    public Func<Type, bool?> IsSerializableType { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the MemoryPack serializer for copying.\n    /// </summary>\n    public Func<Type, bool?> IsCopyableType { get; set; }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.MemoryPack</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>MemoryPack integration for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MemoryPack\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.MemoryPack/README.md",
    "content": "# Microsoft Orleans Serialization for MemoryPack\n\n## Introduction\nMicrosoft Orleans Serialization for MemoryPack provides MemoryPack serialization support for Microsoft Orleans using the MemoryPack format. This high-performance binary serialization format is ideal for scenarios requiring efficient serialization and deserialization.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.MemoryPack\n```\n\n## Example - Configuring MemoryPack Serialization\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure MemoryPack as a serializer\n            .AddSerializer(serializerBuilder => serializerBuilder.AddMemoryPackSerializer());\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using MemoryPack with a Custom Type\n```csharp\nusing Orleans;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\nusing MemoryPack;\nnamespace ExampleGrains;\n\n// Define a class with MemoryPack attributes\n[MemoryPackable]\npublic partial class MyMemoryPackClass\n{\n    public string Name { get; set; }\n    public int Age { get; set; }\n    public List<string> Tags { get; set; }\n}\n\n// You can use it directly in your grain interfaces and implementation\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<MyMemoryPackClass> GetData();\n    Task SetData(MyMemoryPackClass data);\n}\n\npublic class MyGrain : Grain, IMyGrain\n{\n    private MyMemoryPackClass _data;\n\n    public Task<MyMemoryPackClass> GetData()\n    {\n        return Task.FromResult(_data);\n    }\n\n    public Task SetData(MyMemoryPackClass data)\n    {\n        _data = data;\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [MemoryPack for C#](https://github.com/Cysharp/MemoryPack)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Orleans.Serialization.MemoryPack/SerializationHostingExtensions.cs",
    "content": "using System;\nusing MemoryPack;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities.Internal;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Extension method for <see cref=\"ISerializerBuilder\"/>.\n/// </summary>\npublic static class SerializationHostingExtensions\n{\n    private static readonly ServiceDescriptor ServiceDescriptor = new(typeof(MemoryPackCodec), typeof(MemoryPackCodec));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"MemoryPackSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"memoryPackSerializerOptions\">The MemoryPack serializer options.</param>\n    public static ISerializerBuilder AddMemoryPackSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable = null,\n        Func<Type, bool> isCopyable = null,\n        MemoryPackSerializerOptions memoryPackSerializerOptions = null)\n    {\n        return serializerBuilder.AddMemoryPackSerializer(\n            isSerializable,\n            isCopyable,\n            optionsBuilder => optionsBuilder.Configure(options =>\n            {\n                if (memoryPackSerializerOptions is not null)\n                {\n                    options.SerializerOptions = memoryPackSerializerOptions;\n                }\n            })\n        );\n    }\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"MemoryPackSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the options for the MemoryPack codec.</param>\n    public static ISerializerBuilder AddMemoryPackSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable,\n        Func<Type, bool> isCopyable,\n        Action<OptionsBuilder<MemoryPackCodecOptions>> configureOptions = null)\n    {\n        var services = serializerBuilder.Services;\n        if (configureOptions != null)\n        {\n            configureOptions(services.AddOptions<MemoryPackCodecOptions>());\n        }\n\n        if (isSerializable != null)\n        {\n            services.AddSingleton<ICodecSelector>(new DelegateCodecSelector\n            {\n                CodecName = MemoryPackCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isSerializable\n            });\n        }\n\n        if (isCopyable != null)\n        {\n            services.AddSingleton<ICopierSelector>(new DelegateCopierSelector\n            {\n                CopierName = MemoryPackCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isCopyable\n            });\n        }\n\n        if (!services.Contains(ServiceDescriptor))\n        {\n            services.AddSingleton<MemoryPackCodec>();\n            services.AddFromExisting<IGeneralizedCodec, MemoryPackCodec>();\n            services.AddFromExisting<IGeneralizedCopier, MemoryPackCodec>();\n            services.AddFromExisting<ITypeFilter, MemoryPackCodec>();\n            serializerBuilder.Configure(options => options.WellKnownTypeAliases[MemoryPackCodec.WellKnownAlias] = typeof(MemoryPackCodec));\n        }\n\n        return serializerBuilder;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.MessagePack/MessagePackCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing MessagePack;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// A serialization codec which uses <see cref=\"MessagePackSerializer\"/>.\n/// </summary>\n/// <remarks>\n/// MessagePack codec performs slightly worse than default Orleans serializer, if performance is critical for your application, consider using default serialization.\n/// </remarks>\n[Alias(WellKnownAlias)]\npublic class MessagePackCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter\n{\n    private static readonly ConcurrentDictionary<Type, bool> SupportedTypes = new();\n\n    private static readonly Type SelfType = typeof(MessagePackCodec);\n\n    private readonly ICodecSelector[] _serializableTypeSelectors;\n    private readonly ICopierSelector[] _copyableTypeSelectors;\n    private readonly MessagePackCodecOptions _options;\n\n    /// <summary>\n    /// The well-known type alias for this codec.\n    /// </summary>\n    public const string WellKnownAlias = \"msgpack\";\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"MessagePackCodec\"/> class.\n    /// </summary>\n    /// /// <param name=\"serializableTypeSelectors\">Filters used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"copyableTypeSelectors\">Filters used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"options\">The MessagePack codec options.</param>\n    public MessagePackCodec(\n        IEnumerable<ICodecSelector> serializableTypeSelectors,\n        IEnumerable<ICopierSelector> copyableTypeSelectors,\n        IOptions<MessagePackCodecOptions> options)\n    {\n        _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _options = options.Value;\n    }\n\n    /// <inheritdoc/>\n    void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        // The schema type when serializing the field is the type of the codec.\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);\n\n        // Write the type name\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);\n        writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());\n\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n        try\n        {\n\n            var msgPackWriter = new MessagePackWriter(bufferWriter);\n            MessagePackSerializer.Serialize(value.GetType(), ref msgPackWriter, value, _options.SerializerOptions);\n            msgPackWriter.Flush();\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)bufferWriter.Value.Length);\n            bufferWriter.Value.CopyTo(ref writer);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.IsReference)\n        {\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        object result = null;\n        Type type = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                    break;\n                case 1:\n                    if (type is null)\n                    {\n                        ThrowTypeFieldMissing();\n                    }\n\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    var length = reader.ReadVarUInt32();\n\n                    var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n                    try\n                    {\n                        reader.ReadBytes(ref bufferWriter, (int)length);\n                        result = MessagePackSerializer.Deserialize(type, bufferWriter.Value.AsReadOnlySequence(), _options.SerializerOptions);\n                    }\n                    finally\n                    {\n                        bufferWriter.Value.Dispose();\n                    }\n\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCodec.IsSupportedType(Type type)\n    {\n        if (type == SelfType)\n        {\n            return true;\n        }\n\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _serializableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsSerializableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return IsMessagePackContract(type, _options.AllowDataContractAttributes);\n    }\n\n    /// <inheritdoc/>\n    object IDeepCopier.DeepCopy(object input, CopyContext context)\n    {\n        if (context.TryGetCopy(input, out object result))\n        {\n            return result;\n        }\n\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new());\n        try\n        {\n            var msgPackWriter = new MessagePackWriter(bufferWriter);\n            MessagePackSerializer.Serialize(input.GetType(), ref msgPackWriter, input, _options.SerializerOptions);\n            msgPackWriter.Flush();\n\n            var sequence = bufferWriter.Value.AsReadOnlySequence();\n            result = MessagePackSerializer.Deserialize(input.GetType(), sequence, _options.SerializerOptions);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        context.RecordCopy(input, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCopier.IsSupportedType(Type type)\n    {\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _copyableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsCopyableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return IsMessagePackContract(type, _options.AllowDataContractAttributes);\n    }\n\n    /// <inheritdoc/>\n    bool? ITypeFilter.IsTypeAllowed(Type type) => (((IGeneralizedCopier)this).IsSupportedType(type) || ((IGeneralizedCodec)this).IsSupportedType(type)) ? true : null;\n\n    private static bool IsMessagePackContract(Type type, bool allowDataContractAttribute)\n    {\n        if (SupportedTypes.TryGetValue(type, out bool isMsgPackContract))\n        {\n            return isMsgPackContract;\n        }\n\n        isMsgPackContract = type.GetCustomAttribute<MessagePackObjectAttribute>() is not null;\n\n        if (!isMsgPackContract && allowDataContractAttribute)\n        {\n            isMsgPackContract = type.GetCustomAttribute<DataContractAttribute>() is DataContractAttribute;\n        }\n\n        SupportedTypes.TryAdd(type, isMsgPackContract);\n        return isMsgPackContract;\n    }\n\n    private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException(\"Serialized value is missing its type field.\");\n}"
  },
  {
    "path": "src/Orleans.Serialization.MessagePack/MessagePackCodecOptions.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing MessagePack;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Options for <see cref=\"MessagePackCodec\"/>.\n/// </summary>\npublic class MessagePackCodecOptions\n{\n    /// <summary>\n    /// Gets or sets the <see cref=\"MessagePackSerializerOptions\"/>.\n    /// </summary>\n    public MessagePackSerializerOptions SerializerOptions { get; set; } = MessagePackSerializerOptions.Standard;\n\n    /// <summary>\n    /// Get or sets flag that allows the use of <see cref=\"DataContractAttribute\"/> marked contracts for MessagePackSerializer.\n    /// </summary>\n    public bool AllowDataContractAttributes { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the MessagePack serializer for serialization and deserialization.\n    /// </summary>\n    public Func<Type, bool?> IsSerializableType { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the MessagePack serializer for copying.\n    /// </summary>\n    public Func<Type, bool?> IsCopyableType { get; set; }\n}"
  },
  {
    "path": "src/Orleans.Serialization.MessagePack/Orleans.Serialization.MessagePack.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.MessagePack</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>MessagePack integration for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MessagePack\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.MessagePack/README.md",
    "content": "# Microsoft Orleans Serialization for MessagePack\n\n## Introduction\nMicrosoft Orleans Serialization for MessagePack provides MessagePack serialization support for Microsoft Orleans using the MessagePack format. This high-performance binary serialization format is ideal for scenarios requiring efficient serialization and deserialization.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.MessagePack\n```\n\n## Example - Configuring MessagePack Serialization\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure MessagePack as a serializer\n            .AddSerializer(serializerBuilder => serializerBuilder.AddMessagePackSerializer());\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using MessagePack with a Custom Type\n```csharp\nusing Orleans;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Serializers;\nusing MessagePack;\nnamespace ExampleGrains;\n\n// Define a class with MessagePack attributes\n[MessagePackObject]\npublic class MyMessagePackClass\n{\n    [Key(0)]\n    public string Name { get; set; }\n    \n    [Key(1)]\n    public int Age { get; set; }\n    \n    [Key(2)]\n    public List<string> Tags { get; set; }\n}\n\n// You can use it directly in your grain interfaces and implementation\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<MyMessagePackClass> GetData();\n    Task SetData(MyMessagePackClass data);\n}\n\npublic class MyGrain : Grain, IMyGrain\n{\n    private MyMessagePackClass _data;\n\n    public Task<MyMessagePackClass> GetData()\n    {\n        return Task.FromResult(_data);\n    }\n\n    public Task SetData(MyMessagePackClass data)\n    {\n        _data = data;\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [MessagePack for C#](https://github.com/neuecc/MessagePack-CSharp)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.MessagePack/SerializationHostingExtensions.cs",
    "content": "using System;\nusing MessagePack;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities.Internal;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Extension method for <see cref=\"ISerializerBuilder\"/>.\n/// </summary>\npublic static class SerializationHostingExtensions\n{\n    private static readonly ServiceDescriptor ServiceDescriptor = new (typeof(MessagePackCodec), typeof(MessagePackCodec));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"MessagePackSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"messagePackSerializerOptions\">The MessagePack serializer options.</param>\n    public static ISerializerBuilder AddMessagePackSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable = null,\n        Func<Type, bool> isCopyable = null,\n        MessagePackSerializerOptions messagePackSerializerOptions = null)\n    {\n        return serializerBuilder.AddMessagePackSerializer(\n            isSerializable,\n            isCopyable,\n            optionsBuilder => optionsBuilder.Configure(options =>\n            {\n                if (messagePackSerializerOptions is not null)\n                {\n                    options.SerializerOptions = messagePackSerializerOptions;\n                }\n            })\n        );\n    }\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"MessagePackSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the options for the MessagePack codec.</param>\n    public static ISerializerBuilder AddMessagePackSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable,\n        Func<Type, bool> isCopyable,\n        Action<OptionsBuilder<MessagePackCodecOptions>> configureOptions = null)\n    {\n        var services = serializerBuilder.Services;\n        if (configureOptions != null)\n        {\n            configureOptions(services.AddOptions<MessagePackCodecOptions>());\n        }\n\n        if (isSerializable != null)\n        {\n            services.AddSingleton<ICodecSelector>(new DelegateCodecSelector\n            {\n                CodecName = MessagePackCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isSerializable\n            });\n        }\n\n        if (isCopyable != null)\n        {\n            services.AddSingleton<ICopierSelector>(new DelegateCopierSelector\n            {\n                CopierName = MessagePackCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isCopyable\n            });\n        }\n\n        if (!services.Contains(ServiceDescriptor))\n        {\n            services.AddSingleton<MessagePackCodec>();\n            services.AddFromExisting<IGeneralizedCodec, MessagePackCodec>();\n            services.AddFromExisting<IGeneralizedCopier, MessagePackCodec>();\n            services.AddFromExisting<ITypeFilter, MessagePackCodec>();\n            serializerBuilder.Configure(options => options.WellKnownTypeAliases[MessagePackCodec.WellKnownAlias] = typeof(MessagePackCodec));\n        }\n\n        return serializerBuilder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.NewtonsoftJson/NewtonsoftJsonCodec.cs",
    "content": "using System;\nusing System.CodeDom.Compiler;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Metadata;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n[Alias(WellKnownAlias)]\npublic class NewtonsoftJsonCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter\n{\n    private static readonly Type SelfType = typeof(NewtonsoftJsonCodec);\n    private readonly NewtonsoftJsonCodecOptions _options;\n    private readonly ICodecSelector[] _serializableTypeSelectors;\n    private readonly ICopierSelector[] _copyableTypeSelectors;\n    private readonly JsonSerializer _serializer;\n\n    /// <summary>\n    /// The well-known type alias for this codec.\n    /// </summary>\n    public const string WellKnownAlias = \"json.net\";\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"NewtonsoftJsonCodec\"/> class.\n    /// </summary>\n    /// <param name=\"serializableTypeSelectors\">Filters used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"copyableTypeSelectors\">Filters used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"options\">The JSON codec options.</param>\n    public NewtonsoftJsonCodec(\n        IEnumerable<ICodecSelector> serializableTypeSelectors,\n        IEnumerable<ICopierSelector> copyableTypeSelectors,\n        IOptions<NewtonsoftJsonCodecOptions> options)\n    {\n        _options = options.Value;\n        _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _serializer = JsonSerializer.Create(_options.SerializerSettings);\n    }\n\n    void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        // The schema type when serializing the field is the type of the codec.\n        // In practice it could be any unique type as long as this codec is registered as the handler.\n        // By checking against the codec type in IsSupportedType, the codec could also just be registered as an IGenericCodec.\n        // Note that the codec is responsible for serializing the type of the value itself.\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);\n\n        // Write the type name\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);\n        writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());\n\n        // Write the serialized payload\n        var serializedValue = JsonConvert.SerializeObject(value, _options.SerializerSettings);\n        StringCodec.WriteField(ref writer, 1, serializedValue);\n\n        writer.WriteEndObject();\n    }\n\n    object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.IsReference)\n        {\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        object result = null;\n        Type type = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                    break;\n                case 1:\n                    if (type is null)\n                    {\n                        ThrowTypeFieldMissing();\n                    }\n\n                    // To possibly improve efficiency, this could be converted to read a ReadOnlySequence<byte> instead of a byte array.\n                    var serializedValue = StringCodec.ReadValue(ref reader, header);\n                    result = JsonConvert.DeserializeObject(serializedValue, type, _options.SerializerSettings);\n                    ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        return result;\n    }\n\n    bool IGeneralizedCodec.IsSupportedType(Type type)\n    {\n        if (type == SelfType)\n        {\n            return true;\n        }\n\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        if (IsNativelySupportedType(type))\n        {\n            return true;\n        }\n\n        foreach (var selector in _serializableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsSerializableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return false;\n    }\n\n    /// <inheritdoc/>\n    object IDeepCopier.DeepCopy(object input, CopyContext context)\n    {\n        if (context.TryGetCopy(input, out object result))\n            return result;\n\n        var stream = PooledBufferStream.Rent();\n        try\n        {\n            var type = input.GetType();\n            var streamWriter = new StreamWriter(stream);\n            using (var textWriter = new JsonTextWriter(streamWriter) { CloseOutput = false })\n                _serializer.Serialize(textWriter, input, type);\n            streamWriter.Flush();\n\n            stream.Position = 0;\n\n            var streamReader = new StreamReader(stream);\n            using var jsonReader = new JsonTextReader(streamReader);\n            result = _serializer.Deserialize(jsonReader, type);\n        }\n        finally\n        {\n            PooledBufferStream.Return(stream);\n        }\n\n        context.RecordCopy(input, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCopier.IsSupportedType(Type type)\n    {\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        if (IsNativelySupportedType(type))\n        {\n            return true;\n        }\n\n        foreach (var selector in _copyableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsCopyableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return false;\n    }\n\n    private static bool IsNativelySupportedType(Type type)\n    {\n        return type == typeof(JObject)\n                    || type == typeof(JArray)\n                    || type == typeof(JProperty)\n                    || type == typeof(JRaw)\n                    || type == typeof(JValue)\n                    || type == typeof(JConstructor)\n                    || typeof(JContainer).IsAssignableFrom(type)\n                    || typeof(JToken).IsAssignableFrom(type);\n    }\n\n    private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException(\"Serialized value is missing its type field.\");\n\n    private bool IsSupportedType(Type type) => ((IGeneralizedCodec)this).IsSupportedType(type) || ((IGeneralizedCopier)this).IsSupportedType(type);\n    bool? ITypeFilter.IsTypeAllowed(Type type) => IsSupportedType(type) ? true : null;\n}"
  },
  {
    "path": "src/Orleans.Serialization.NewtonsoftJson/NewtonsoftJsonCodecOptions.cs",
    "content": "﻿using Newtonsoft.Json;\nusing System;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Options for <see cref=\"NewtonsoftJsonCodec\"/>.\n/// </summary>\npublic class NewtonsoftJsonCodecOptions\n{\n    /// <summary>\n    /// Gets or sets the <see cref=\"JsonSerializerSettings\"/>.\n    /// </summary>\n    public JsonSerializerSettings SerializerSettings { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the JSON serializer for serialization and deserialization.\n    /// </summary>\n    public Func<Type, bool?> IsSerializableType { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the JSON serializer for copying.\n    /// </summary>\n    public Func<Type, bool?> IsCopyableType { get; set; }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.NewtonsoftJson/Orleans.Serialization.NewtonsoftJson.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.NewtonsoftJson</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>Newtonsoft.Json integration for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.NewtonsoftJson/README.md",
    "content": "# Microsoft Orleans Serialization for Newtonsoft.Json\n\n## Introduction\nMicrosoft Orleans Serialization for Newtonsoft.Json provides JSON serialization support for Microsoft Orleans using the popular Newtonsoft.Json library. This allows you to use the comprehensive JSON features of Newtonsoft.Json within your Orleans application.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.NewtonsoftJson\n```\n\n## Example - Configuring Newtonsoft.Json Serialization\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Newtonsoft.Json as a serializer\n            .AddSerializer(serializerBuilder => serializerBuilder.AddNewtonsoftJsonSerializer(type => type.Namespace.StartsWith(\"ExampleGrains\")));\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Newtonsoft.Json with a Custom Type\n```csharp\nusing Orleans;\nusing Newtonsoft.Json;\nnamespace ExampleGrains;\n\n// Define a class with Newtonsoft.Json attributes\npublic class MyJsonClass\n{\n    [JsonProperty(\"full_name\")]\n    public string Name { get; set; }\n    \n    [JsonProperty(\"age\")]\n    public int Age { get; set; }\n    \n    [JsonProperty(\"tags\")]\n    public List<string> Tags { get; set; }\n    \n    [JsonIgnore]\n    public string SecretData { get; set; }\n}\n\n// You can use it directly in your grain interfaces and implementation\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<MyJsonClass> GetData();\n    Task SetData(MyJsonClass data);\n}\n\npublic class MyGrain : Grain, IMyGrain\n{\n    private MyJsonClass _data;\n\n    public Task<MyJsonClass> GetData()\n    {\n        return Task.FromResult(_data);\n    }\n\n    public Task SetData(MyJsonClass data)\n    {\n        _data = data;\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [Newtonsoft.Json Documentation](https://www.newtonsoft.com/json/help/html/Introduction.htm)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.NewtonsoftJson/SerializationHostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities.Internal;\nusing System;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Extension method for <see cref=\"ISerializerBuilder\"/>.\n/// </summary>\npublic static class SerializationHostingExtensions\n{\n    private static readonly ServiceDescriptor ServiceDescriptor = new (typeof(NewtonsoftJsonCodec), typeof(NewtonsoftJsonCodec));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"JsonSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSupported\">A delegate used to indicate which types should be serialized and copied by this codec.</param>\n    /// <param name=\"jsonSerializerSettings\">The JSON serializer settings.</param>\n    public static ISerializerBuilder AddNewtonsoftJsonSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSupported,\n        JsonSerializerSettings jsonSerializerSettings = null)\n        => serializerBuilder.AddNewtonsoftJsonSerializer(\n            isSupported,\n            optionsBuilder => optionsBuilder.Configure(options =>\n            {\n                if (jsonSerializerSettings is not null)\n                {\n                    options.SerializerSettings = jsonSerializerSettings;\n                }\n            }));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"JsonSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSupported\">A delegate used to indicate which types should be serialized and copied by this codec.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the options for the JSON serializer.</param>\n    public static ISerializerBuilder AddNewtonsoftJsonSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSupported,\n        Action<OptionsBuilder<NewtonsoftJsonCodecOptions>> configureOptions)\n        => serializerBuilder.AddNewtonsoftJsonSerializer(\n            isSupported,\n            isSupported,\n            configureOptions);\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"JsonSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the options for the JSON serializer.</param>\n    public static ISerializerBuilder AddNewtonsoftJsonSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable,\n        Func<Type, bool> isCopyable,\n        Action<OptionsBuilder<NewtonsoftJsonCodecOptions>> configureOptions)\n    {\n        var services = serializerBuilder.Services;\n        if (configureOptions != null)\n        {\n            configureOptions(services.AddOptions<NewtonsoftJsonCodecOptions>());\n        }\n\n        if (isSerializable != null)\n        {\n            services.AddSingleton<ICodecSelector>(new DelegateCodecSelector\n            {\n                CodecName = NewtonsoftJsonCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isSerializable\n            });\n        }\n\n        if (isCopyable != null)\n        {\n            services.AddSingleton<ICopierSelector>(new DelegateCopierSelector\n            {\n                CopierName = NewtonsoftJsonCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isCopyable\n            });\n        }\n\n        if (!services.Contains(ServiceDescriptor))\n        {\n            services.AddSingleton<NewtonsoftJsonCodec>();\n            services.AddFromExisting<IGeneralizedCodec, NewtonsoftJsonCodec>();\n            services.AddFromExisting<IGeneralizedCopier, NewtonsoftJsonCodec>();\n            services.AddFromExisting<ITypeFilter, NewtonsoftJsonCodec>();\n            serializerBuilder.Configure(options => options.WellKnownTypeAliases[NewtonsoftJsonCodec.WellKnownAlias] = typeof(NewtonsoftJsonCodec));\n        }\n\n        return serializerBuilder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.SystemTextJson/JsonCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text.Json;\nusing System.Text.Json.Nodes;\nusing Microsoft.Extensions.Options;\nusing Orleans.Metadata;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// A serialization codec which uses <see cref=\"JsonSerializer\"/>.\n/// </summary>\n[Alias(WellKnownAlias)]\npublic class JsonCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter\n{\n    private static readonly Type SelfType = typeof(JsonCodec);\n    private readonly ICodecSelector[] _serializableTypeSelectors;\n    private readonly ICopierSelector[] _copyableTypeSelectors;\n    private readonly JsonCodecOptions _options;\n\n    /// <summary>\n    /// The well-known type alias for this codec.\n    /// </summary>\n    public const string WellKnownAlias = \"json\";\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"JsonCodec\"/> class.\n    /// </summary>\n    /// <param name=\"serializableTypeSelectors\">Filters used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"copyableTypeSelectors\">Filters used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"options\">The JSON codec options.</param>\n    public JsonCodec(\n        IEnumerable<ICodecSelector> serializableTypeSelectors,\n        IEnumerable<ICopierSelector> copyableTypeSelectors,\n        IOptions<JsonCodecOptions> options)\n    {\n        _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _options = options.Value;\n    }\n\n    /// <inheritdoc/>\n    void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        // The schema type when serializing the field is the type of the codec.\n        // In practice it could be any unique type as long as this codec is registered as the handler.\n        // By checking against the codec type in IsSupportedType, the codec could also just be registered as an IGenericCodec.\n        // Note that the codec is responsible for serializing the type of the value itself.\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);\n\n        // Write the type name\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);\n        writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());\n\n        // Write the serialized payload\n        // Note that the Utf8JsonWriter and PooledBuffer could be pooled as long as they're correctly\n        // reset at the end of each use.\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new PooledBuffer());\n        try\n        {\n            var jsonWriter = new Utf8JsonWriter(bufferWriter, _options.WriterOptions);\n            JsonSerializer.Serialize(jsonWriter, value, _options.SerializerOptions);\n            jsonWriter.Flush();\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);\n            writer.WriteVarUInt32((uint)bufferWriter.Value.Length);\n            bufferWriter.Value.CopyTo(ref writer);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.IsReference)\n        {\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        object result = null;\n        Type type = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                    break;\n                case 1:\n                    if (type is null)\n                    {\n                        ThrowTypeFieldMissing();\n                    }\n\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    var length = reader.ReadVarUInt32();\n\n                    // To possibly improve efficiency, this could be converted to read a ReadOnlySequence<byte> instead of a byte array.\n                    var tempBuffer = new PooledBuffer();\n                    try\n                    {\n                        reader.ReadBytes(ref tempBuffer, (int)length);\n                        var sequence = tempBuffer.AsReadOnlySequence();\n                        var jsonReader = new Utf8JsonReader(sequence, _options.ReaderOptions);\n                        if (typeof(JsonNode).IsAssignableFrom(type))\n                        {\n                            result = JsonNode.Parse(ref jsonReader);\n                        }\n                        else\n                        {\n                            result = JsonSerializer.Deserialize(ref jsonReader, type, _options.SerializerOptions);\n                        }\n                    }\n                    finally\n                    {\n                        tempBuffer.Dispose();\n                    }\n\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCodec.IsSupportedType(Type type)\n    {\n        if (type == SelfType)\n        {\n            return true;\n        }\n\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        if (IsNativelySupportedType(type))\n        {\n            return true;\n        }\n\n        foreach (var selector in _serializableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsSerializableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return false;\n    }\n\n    private static bool IsNativelySupportedType(Type type)\n    {\n        // Add types natively supported by System.Text.Json\n        // From https://github.com/dotnet/runtime/blob/2c4d0df3b146f8322f676b83a53ca21a065bdfc7/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs#L1792-L1797\n        return type == typeof(JsonElement)\n            || type == typeof(JsonDocument)\n            || type == typeof(JsonArray)\n            || type == typeof(JsonObject)\n            || type == typeof(JsonValue)\n            || typeof(JsonNode).IsAssignableFrom(type);\n    }\n\n    /// <inheritdoc/>\n    object IDeepCopier.DeepCopy(object input, CopyContext context)\n    {\n        if (context.TryGetCopy(input, out object result))\n        {\n            return result;\n        }\n\n        if (input is JsonNode jsonNode)\n        {\n            var copy = jsonNode.DeepClone();\n            context.RecordCopy(input, copy);\n            return copy;\n        }\n\n        var bufferWriter = new BufferWriterBox<PooledBuffer>(new PooledBuffer());\n        try\n        {\n            var jsonWriter = new Utf8JsonWriter(bufferWriter, _options.WriterOptions);\n            JsonSerializer.Serialize(jsonWriter, input, _options.SerializerOptions);\n            jsonWriter.Flush();\n\n            var sequence = bufferWriter.Value.AsReadOnlySequence();\n            var jsonReader = new Utf8JsonReader(sequence, _options.ReaderOptions);\n            result = JsonSerializer.Deserialize(ref jsonReader, input.GetType(), _options.SerializerOptions);\n        }\n        finally\n        {\n            bufferWriter.Value.Dispose();\n        }\n\n        context.RecordCopy(input, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCopier.IsSupportedType(Type type)\n    {\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        if (IsNativelySupportedType(type))\n        {\n            return true;\n        }\n\n        foreach (var selector in _copyableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return true;\n            }\n        }\n\n        if (_options.IsCopyableType?.Invoke(type) is bool value)\n        {\n            return value;\n        }\n\n        return false;\n    }\n\n    /// <inheritdoc/>\n    bool? ITypeFilter.IsTypeAllowed(Type type) => (((IGeneralizedCopier)this).IsSupportedType(type) || ((IGeneralizedCodec)this).IsSupportedType(type)) ? true : null;\n\n    private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException(\"Serialized value is missing its type field.\");\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.SystemTextJson/JsonCodecOptions.cs",
    "content": "using System;\nusing System.Text.Json;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Options for <see cref=\"JsonCodec\"/>.\n/// </summary>\npublic class JsonCodecOptions\n{\n    /// <summary>\n    /// Gets or sets the <see cref=\"JsonSerializerOptions\"/>.\n    /// </summary>\n    public JsonSerializerOptions SerializerOptions { get; set; } = new();\n\n    /// <summary>\n    /// Gets or sets the <see cref=\"JsonReaderOptions\"/>.\n    /// </summary>\n    public JsonReaderOptions ReaderOptions { get; set; }\n\n    /// <summary>\n    /// Gets or sets the <see cref=\"JsonWriterOptions\"/>.\n    /// </summary>\n    public JsonWriterOptions WriterOptions { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the JSON serializer for serialization and deserialization.\n    /// </summary>\n    public Func<Type, bool?> IsSerializableType { get; set; }\n\n    /// <summary>\n    /// Gets or sets a delegate used to determine if a type is supported by the JSON serializer for copying.\n    /// </summary>\n    public Func<Type, bool?> IsCopyableType { get; set; }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.SystemTextJson/Orleans.Serialization.SystemTextJson.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.SystemTextJson</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>System.Text.Json integration for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.SystemTextJson/README.md",
    "content": "# Microsoft Orleans Serialization for System.Text.Json\n\n## Introduction\nMicrosoft Orleans Serialization for System.Text.Json provides JSON serialization support for Microsoft Orleans using the modern System.Text.Json library. This allows you to use the high-performance JSON serialization capabilities from the .NET runtime within your Orleans application.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.SystemTextJson\n```\n\n## Example - Configuring System.Text.Json Serialization\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure System.Text.Json as a serializer\n            .AddSerializer(serializerBuilder => serializerBuilder.AddSystemTextJsonSerializer(type => type.Namespace.StartsWith(\"ExampleGrains\")));\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using System.Text.Json with a Custom Type\n```csharp\nusing Orleans;\nusing System.Text.Json.Serialization;\nnamespace ExampleGrains;\n\n// Define a class with System.Text.Json attributes\npublic class MyJsonClass\n{\n    [JsonPropertyName(\"full_name\")]\n    public string Name { get; set; }\n    \n    [JsonPropertyName(\"age\")]\n    public int Age { get; set; }\n    \n    [JsonPropertyName(\"tags\")]\n    public List<string> Tags { get; set; }\n    \n    [JsonIgnore]\n    public string SecretData { get; set; }\n}\n\n// You can use it directly in your grain interfaces and implementation\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<MyJsonClass> GetData();\n    Task SetData(MyJsonClass data);\n}\n\npublic class MyGrain : Grain, IMyGrain\n{\n    private MyJsonClass _data;\n\n    public Task<MyJsonClass> GetData()\n    {\n        return Task.FromResult(_data);\n    }\n\n    public Task SetData(MyJsonClass data)\n    {\n        _data = data;\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [System.Text.Json Documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/overview)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.SystemTextJson/SerializationHostingExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities.Internal;\nusing System;\nusing System.Text.Json;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Extension method for <see cref=\"ISerializerBuilder\"/>.\n/// </summary>\npublic static class SerializationHostingExtensions\n{\n    private static readonly ServiceDescriptor ServiceDescriptor = new (typeof(JsonCodec), typeof(JsonCodec));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"JsonSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSupported\">A delegate used to indicate which types should be serialized and copied by this codec.</param>\n    /// <param name=\"jsonSerializerOptions\">The JSON serializer options.</param>\n    public static ISerializerBuilder AddJsonSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSupported,\n        JsonSerializerOptions jsonSerializerOptions = null)\n        => serializerBuilder.AddJsonSerializer(\n            isSupported,\n            isSupported,\n            optionsBuilder => optionsBuilder.Configure(options =>\n            {\n                if (jsonSerializerOptions is not null)\n                {\n                    options.SerializerOptions = jsonSerializerOptions;\n                }\n            }));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing values using <see cref=\"JsonSerializer\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    /// <param name=\"configureOptions\">A delegate used to configure the options for the JSON serializer.</param>\n    public static ISerializerBuilder AddJsonSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable,\n        Func<Type, bool> isCopyable,\n        Action<OptionsBuilder<JsonCodecOptions>> configureOptions = null)\n    {\n        var services = serializerBuilder.Services;\n        if (configureOptions != null)\n        {\n            configureOptions(services.AddOptions<JsonCodecOptions>());\n        }\n\n        if (isSerializable != null)\n        {\n            services.AddSingleton<ICodecSelector>(new DelegateCodecSelector\n            {\n                CodecName = JsonCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isSerializable\n            });\n        }\n\n        if (isCopyable != null)\n        {\n            services.AddSingleton<ICopierSelector>(new DelegateCopierSelector\n            {\n                CopierName = JsonCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isCopyable\n            });\n        }\n\n        if (!services.Contains(ServiceDescriptor))\n        {\n            services.AddSingleton<JsonCodec>();\n            services.AddFromExisting<IGeneralizedCodec, JsonCodec>();\n            services.AddFromExisting<IGeneralizedCopier, JsonCodec>();\n            services.AddFromExisting<ITypeFilter, JsonCodec>();\n            serializerBuilder.Configure(options => options.WellKnownTypeAliases[JsonCodec.WellKnownAlias] = typeof(JsonCodec));\n        }\n\n        return serializerBuilder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/BufferTestHelper.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Serialization.TestKit\n{\n    /// <summary>\n    /// Helper for testing buffer types.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    internal static class BufferTestHelper<TValue>\n    {\n        public static IBufferTestSerializer[] GetTestSerializers(IServiceProvider serviceProvider, int[] maxSizes)\n        {\n            var result = new List<IBufferTestSerializer>();\n            foreach (var size in maxSizes)\n            {\n                result.Add(ActivatorUtilities.CreateInstance<MultiSegmentBufferWriterTester>(serviceProvider, new MultiSegmentBufferWriterTester.Options { MaxAllocationSize = size }));\n            }\n\n            result.Add(ActivatorUtilities.CreateInstance<StructBufferWriterTester>(serviceProvider));\n            result.Add(ActivatorUtilities.CreateInstance<PooledBufferWriterTester>(serviceProvider));\n            return result.ToArray();\n        }\n\n        public interface IBufferTestSerializer\n        {\n            IOutputBuffer Serialize(TValue input);\n            void Deserialize(ReadOnlySequence<byte> buffer, out TValue output);\n        }\n\n        [ExcludeFromCodeCoverage]\n        private abstract class BufferTester<TBufferWriter> : IBufferTestSerializer where TBufferWriter : IBufferWriter<byte>, IOutputBuffer\n        {\n            private readonly SerializerSessionPool _sessionPool;\n            private readonly Serializer<TValue> _serializer;\n\n            protected BufferTester(IServiceProvider serviceProvider)\n            {\n                _sessionPool = serviceProvider.GetRequiredService<SerializerSessionPool>();\n                _serializer = serviceProvider.GetRequiredService<Serializer<TValue>>();\n            }\n\n            protected abstract TBufferWriter CreateBufferWriter();\n\n            public IOutputBuffer Serialize(TValue input)\n            {\n                using var session = _sessionPool.GetSession();\n                var writer = Writer.Create(CreateBufferWriter(), session);\n                _serializer.Serialize(input, ref writer);\n                return writer.Output;\n            }\n\n            public void Deserialize(ReadOnlySequence<byte> buffer, out TValue output)\n            {\n                using var session = _sessionPool.GetSession();\n                var reader = Reader.Create(buffer, session);\n                output = _serializer.Deserialize(ref reader);\n            }\n        }\n\n        [ExcludeFromCodeCoverage]\n        private class MultiSegmentBufferWriterTester : BufferTester<TestMultiSegmentBufferWriter>\n        {\n            private readonly Options _options;\n\n            public MultiSegmentBufferWriterTester(IServiceProvider serviceProvider, Options options) : base(serviceProvider)\n            {\n                _options = options;\n            }\n\n            public class Options\n            {\n                public int MaxAllocationSize { get; set; }\n            }\n\n            protected override TestMultiSegmentBufferWriter CreateBufferWriter() => new(_options.MaxAllocationSize);\n\n            public override string ToString() => $\"{nameof(TestMultiSegmentBufferWriter)} {nameof(_options.MaxAllocationSize)}: {_options.MaxAllocationSize}\";\n        }\n\n        [ExcludeFromCodeCoverage]\n        private class StructBufferWriterTester : BufferTester<TestBufferWriterStruct>\n        {\n            protected override TestBufferWriterStruct CreateBufferWriter() => new(new byte[102400]);\n\n            public StructBufferWriterTester(IServiceProvider serviceProvider) : base(serviceProvider)\n            {\n            }\n\n            public override string ToString() => $\"{nameof(TestBufferWriterStruct)}\";\n        }\n\n        private struct PooledOutputBuffer : IBufferWriter<byte>, IOutputBuffer, IDisposable\n        {\n            private PooledBuffer _buffer;\n\n            public PooledOutputBuffer()\n            {\n                _buffer = new();\n            }\n\n            public void Advance(int count) => _buffer.Advance(count);\n            public void Dispose() => _buffer.Dispose();\n            public Memory<byte> GetMemory(int sizeHint = 0) => _buffer.GetMemory(sizeHint);\n            public ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize) => _buffer.AsReadOnlySequence();\n            public Span<byte> GetSpan(int sizeHint = 0) => _buffer.GetSpan(sizeHint);\n        }\n\n        [ExcludeFromCodeCoverage]\n        private class PooledBufferWriterTester : BufferTester<PooledOutputBuffer>\n        {\n            public PooledBufferWriterTester(IServiceProvider serviceProvider) : base(serviceProvider)\n            {\n            }\n\n            protected override PooledOutputBuffer CreateBufferWriter() => new();\n\n            public override string ToString() => $\"{nameof(PooledBufferWriterTester)}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/CopierTester.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing Xunit;\nusing Xunit.Abstractions;\nusing System.Linq;\n\nnamespace Orleans.Serialization.TestKit\n{\n    /// <summary>\n    /// Test methods for copiers.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    [ExcludeFromCodeCoverage]\n    public abstract class CopierTester<TValue, TCopier> where TCopier : class, IDeepCopier<TValue>\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly CodecProvider _codecProvider;\n\n        /// <summary>\n        /// Initializes a new <see cref=\"CopierTester{TValue, TCopier}\"/> instance.\n        /// </summary>\n        protected CopierTester(ITestOutputHelper output)\n        {\n#if NET6_0_OR_GREATER\n            var seed = Random.Shared.Next();\n#else\n            var seed = new Random().Next();\n#endif\n            output.WriteLine($\"Random seed: {seed}\");\n            Random = new(seed);\n            var services = new ServiceCollection();\n            _ = services.AddSerializer(builder => builder.Configure(config => config.Copiers.Add(typeof(TCopier))));\n\n            if (!typeof(TCopier).IsAbstract && !typeof(TCopier).IsInterface)\n            {\n                _ = services.AddSingleton<TCopier>();\n            }\n\n            _ = services.AddSerializer(Configure);\n\n            _serviceProvider = services.BuildServiceProvider();\n            _codecProvider = _serviceProvider.GetRequiredService<CodecProvider>();\n        }\n\n        /// <summary>\n        /// Gets the random number generator.\n        /// </summary>\n        protected Random Random { get; }\n\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        protected IServiceProvider ServiceProvider => _serviceProvider;\n\n        /// <summary>\n        /// Gets a value indicating whether the type copied by this codec is immutable.\n        /// </summary>\n        protected virtual bool IsImmutable => false;\n\n        /// <summary>\n        /// Gets a value indicating whether the type copied by this codec is pooled.\n        /// </summary>\n        protected virtual bool IsPooled => false;\n\n        /// <summary>\n        /// Configures the serializer.\n        /// </summary>\n        protected virtual void Configure(ISerializerBuilder builder)\n        {\n        }\n\n        /// <summary>\n        /// Creates a copier instance for testing.\n        /// </summary>\n        protected virtual TCopier CreateCopier() => _serviceProvider.GetRequiredService<TCopier>();\n\n        /// <summary>\n        /// Creates a value to copy.\n        /// </summary>\n        protected abstract TValue CreateValue();\n\n        /// <summary>\n        /// Gets an array of test values.\n        /// </summary>\n        protected abstract TValue[] TestValues { get; }\n\n        /// <summary>\n        /// Compares two values and returns <see langword=\"true\"/> if they are equal, or <see langword=\"false\"/> if they are not equal.\n        /// </summary>\n        protected virtual bool Equals(TValue left, TValue right) => EqualityComparer<TValue>.Default.Equals(left, right);\n\n        /// <summary>\n        /// Gets a value provider delegate.\n        /// </summary>\n        protected virtual Action<Action<TValue>> ValueProvider { get; }\n\n        /// <summary>\n        /// Checks if copied values are equal.\n        /// </summary>\n        [Fact]\n        public void CopiedValuesAreEqual()\n        {\n            var copier = CreateCopier();\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var output = copier.DeepCopy(original, new CopyContext(_codecProvider, _ => { }));\n                var isEqual = Equals(original, output);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Copy value \\\"{output}\\\" must equal original value \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks if references are added to the copy context.\n        /// </summary>\n        [Fact]\n        public void ReferencesAreAddedToCopyContext()\n        {\n            if (typeof(TValue).IsValueType || IsPooled)\n            {\n                return;\n            }\n\n            var value = CreateValue();\n            var array = new TValue[] { value, value };\n            var arrayCopier = _serviceProvider.GetRequiredService<DeepCopier<TValue[]>>();\n            var arrayCopy = arrayCopier.Copy(array);\n            Assert.Same(arrayCopy[0], arrayCopy[1]);\n\n            if (IsImmutable)\n            {\n                Assert.Same(value, arrayCopy[0]);\n            }\n            else\n            {\n                Assert.NotSame(value, arrayCopy[0]);\n            }\n        }\n\n        /// <summary>\n        /// Checks if strongly-typed tuples containing the field type can be copied.\n        /// </summary>\n        [Fact]\n        public void CanCopyTupleViaSerializer()\n        {\n            var copier = _serviceProvider.GetRequiredService<DeepCopier<(string, TValue, TValue, string)>>();\n\n            var original = (Guid.NewGuid().ToString(), CreateValue(), CreateValue(), Guid.NewGuid().ToString());\n\n            var copy = copier.Copy(original);\n\n            var isEqual = Equals(original.Item1, copy.Item1);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 1, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n            isEqual = Equals(original.Item2, copy.Item2);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 2, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n            isEqual = Equals(original.Item3, copy.Item3);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 3, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n            isEqual = Equals(original.Item4, copy.Item4);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 4, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n        }\n\n        /// <summary>\n        /// Checks if object-typed tuples containing the field type can be copied.\n        /// </summary>\n        [Fact]\n        public void CanCopyUntypedTupleViaSerializer()\n        {\n            var copier = _serviceProvider.GetRequiredService<DeepCopier<(string, object, object, string)>>();\n            var value = ((IEnumerable<TValue>)TestValues).Reverse().Concat(new[] { CreateValue(), CreateValue() }).Take(2).ToArray();\n\n            var original = (Guid.NewGuid().ToString(), (object)value[0], (object)value[1], Guid.NewGuid().ToString());\n\n            var copy = copier.Copy(original);\n\n            var isEqual = Equals(original.Item1, copy.Item1);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 1, \\\"{copy.Item1}\\\", must equal original value, \\\"{original.Item1}\\\"\");\n            isEqual = Equals((TValue)original.Item2, (TValue)copy.Item2);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 2, \\\"{copy.Item2}\\\", must equal original value, \\\"{original.Item2}\\\"\");\n            isEqual = Equals((TValue)original.Item3, (TValue)copy.Item3);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 3, \\\"{copy.Item3}\\\", must equal original value, \\\"{original.Item3}\\\"\");\n            isEqual = Equals(original.Item4, copy.Item4);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Copied value for item 4, \\\"{copy.Item4}\\\", must equal original value, \\\"{original.Item4}\\\"\");\n        }\n\n        /// <summary>\n        /// Checks if values can be round-tripped when used as an element in a strongly-typed list.\n        /// </summary>\n        [Fact]\n        public void CanCopyCollectionViaSerializer()\n        {\n            var copier = _serviceProvider.GetRequiredService<DeepCopier<List<TValue>>>();\n\n            var original = new List<TValue>();\n            original.AddRange(TestValues);\n            for (var i = 0; i < 5; i++)\n            {\n                original.Add(CreateValue());\n            }\n\n            var copy = copier.Copy(original);\n\n            Assert.Equal(original.Count, copy.Count);\n            for (var i = 0; i < original.Count; ++i)\n            {\n                var isEqual = Equals(original[i], copy[i]);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Copied value at index {i}, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks if values can be round-tripped when used as an element in a list of object.\n        /// </summary>\n        [Fact]\n        public void CanCopyCollectionViaUntypedSerializer()\n        {\n            var copier = _serviceProvider.GetRequiredService<DeepCopier<List<object>>>();\n\n            var original = new List<object>();\n            foreach (var value in TestValues)\n            {\n                original.Add(value);\n            }\n\n            for (var i = 0; i < 5; i++)\n            {\n                original.Add(CreateValue());\n            }\n\n            var copy = copier.Copy(original);\n\n            Assert.Equal(original.Count, copy.Count);\n            for (var i = 0; i < original.Count; ++i)\n            {\n                var isEqual = Equals((TValue)original[i], (TValue)copy[i]);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Copied value at index {i}, \\\"{copy}\\\", must equal original value, \\\"{original}\\\"\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/FieldCodecTester.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.IO.Pipelines;\nusing System.Linq;\nusing System.Text;\nusing Xunit;\nusing Orleans.Serialization.Serializers;\nusing Xunit.Abstractions;\nusing Orleans.Serialization.GeneratedCodeHelpers;\n\nnamespace Orleans.Serialization.TestKit\n{\n    /// <summary>\n    /// Methods for testing field codecs.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    [ExcludeFromCodeCoverage]\n    public abstract class FieldCodecTester<TValue, TCodec> : IDisposable where TCodec : class, IFieldCodec<TValue>\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly SerializerSessionPool _sessionPool;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FieldCodecTester{TValue, TCodec}\"/> class.\n        /// </summary>\n        protected FieldCodecTester(ITestOutputHelper output)\n        {\n#if NET6_0_OR_GREATER\n            var seed = Random.Shared.Next();\n#else\n            var seed = new Random().Next();\n#endif\n            output.WriteLine($\"Random seed: {seed}\");\n            Random = new(seed);\n            var services = new ServiceCollection();\n            _ = services.AddSerializer(builder => builder.Configure(config => config.FieldCodecs.Add(typeof(TCodec))));\n\n            if (!typeof(TCodec).IsAbstract && !typeof(TCodec).IsInterface)\n            {\n                _ = services.AddSingleton<TCodec>();\n            }\n\n            _ = services.AddSerializer(Configure);\n\n            _serviceProvider = services.BuildServiceProvider();\n            _sessionPool = _serviceProvider.GetService<SerializerSessionPool>();\n        }\n\n        /// <summary>\n        /// Gets the random number generator.\n        /// </summary>\n        protected Random Random { get; }\n\n        /// <summary>\n        /// Gets the service provider.\n        /// </summary>\n        protected IServiceProvider ServiceProvider => _serviceProvider;\n\n        /// <summary>\n        /// Gets the session pool.\n        /// </summary>\n        protected SerializerSessionPool SessionPool => _sessionPool;\n\n        /// <summary>\n        /// Gets the maximum segment sizes for buffer testing.\n        /// </summary>\n        protected virtual int[] MaxSegmentSizes => [16];\n\n        /// <summary>\n        /// Configures the serializer.\n        /// </summary>\n        protected virtual void Configure(ISerializerBuilder builder)\n        {\n        }\n\n        /// <summary>\n        /// Creates a codec.\n        /// </summary>\n        protected virtual TCodec CreateCodec() => _serviceProvider.GetRequiredService<TCodec>();\n\n        /// <summary>\n        /// Creates a value.\n        /// </summary>\n        protected abstract TValue CreateValue();\n\n        /// <summary>\n        /// Gets test values.\n        /// </summary>\n        protected abstract TValue[] TestValues { get; }\n\n        /// <summary>\n        /// Compares two values for equality.\n        /// </summary>\n        protected virtual bool Equals(TValue left, TValue right) => EqualityComparer<TValue>.Default.Equals(left, right);\n\n        /// <summary>\n        /// Gets a value provider delegate.\n        /// </summary>\n        protected virtual Action<Action<TValue>> ValueProvider { get; }\n\n        /// <inheritdoc/>\n        void IDisposable.Dispose() => (_serviceProvider as IDisposable)?.Dispose();\n\n        protected virtual TValue GetWriteCopy(TValue input) => input;\n\n        /// <summary>\n        /// Checks whether the codec correctly advances the reference counter when writing to a stream and reading from a stream.\n        /// </summary>\n        [Fact]\n        public void CorrectlyAdvancesReferenceCounterStream()\n        {\n            var stream = new MemoryStream();\n            using var writerSession = _sessionPool.GetSession();\n            using var readerSession = _sessionPool.GetSession();\n            var writer = Writer.Create(stream, writerSession);\n            var writerCodec = CreateCodec();\n\n            // Write the field. This should involve marking at least one reference in the session.\n            Assert.Equal(0, writer.Position);\n\n            foreach (var value in TestValues)\n            {\n                var beforeReference = writer.Session.ReferencedObjects.CurrentReferenceId;\n                writerCodec.WriteField(ref writer, 0, typeof(TValue), value);\n                Assert.True(writer.Position > 0);\n\n                writer.Commit();\n                var afterReference = writer.Session.ReferencedObjects.CurrentReferenceId;\n                Assert.True(beforeReference < afterReference, $\"Writing a field should result in at least one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n                if (value is null)\n                {\n                    Assert.True(beforeReference + 1 == afterReference, $\"Writing a null field should result in exactly one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n                }\n\n                stream.Flush();\n\n                stream.Position = 0;\n                var reader = Reader.Create(stream, readerSession);\n\n                var previousPos = reader.Position;\n                Assert.Equal(0, previousPos);\n                var readerCodec = CreateCodec();\n                var readField = reader.ReadFieldHeader();\n\n                Assert.True(reader.Position > previousPos);\n                previousPos = reader.Position;\n\n                beforeReference = reader.Session.ReferencedObjects.CurrentReferenceId;\n                var readValue = readerCodec.ReadValue(ref reader, readField);\n\n                Assert.True(reader.Position > previousPos);\n\n                afterReference = reader.Session.ReferencedObjects.CurrentReferenceId;\n                Assert.True(beforeReference < afterReference, $\"Reading a field should result in at least one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n                if (readValue is null)\n                {\n                    Assert.True(beforeReference + 1 == afterReference, $\"Reading a null field should result in at exactly one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n                }\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly advances the reference counter when writing to a pipe and reading from a pipe.\n        /// </summary>\n        [Fact]\n        public void CorrectlyAdvancesReferenceCounter()\n        {\n            var pipe = new Pipe();\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n            var writerCodec = CreateCodec();\n            var beforeReference = writer.Session.ReferencedObjects.CurrentReferenceId;\n\n            // Write the field. This should involve marking at least one reference in the session.\n            Assert.Equal(0, writer.Position);\n\n            writerCodec.WriteField(ref writer, 0, typeof(TValue), CreateValue());\n            Assert.True(writer.Position > 0);\n\n            writer.Commit();\n            var afterReference = writer.Session.ReferencedObjects.CurrentReferenceId;\n            Assert.True(beforeReference < afterReference, $\"Writing a field should result in at least one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = _sessionPool.GetSession();\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n\n            var previousPos = reader.Position;\n            Assert.Equal(0, previousPos);\n            var readerCodec = CreateCodec();\n            var readField = reader.ReadFieldHeader();\n\n            Assert.True(reader.Position > previousPos);\n            previousPos = reader.Position;\n\n            beforeReference = reader.Session.ReferencedObjects.CurrentReferenceId;\n            _ = readerCodec.ReadValue(ref reader, readField);\n\n            Assert.True(reader.Position > previousPos);\n\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n            afterReference = reader.Session.ReferencedObjects.CurrentReferenceId;\n            Assert.True(beforeReference < afterReference, $\"Reading a field should result in at least one reference being marked in the session. Before: {beforeReference}, After: {afterReference}\");\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when using a pooled stream.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_StreamPooled()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var toWrite = GetWriteCopy(original);\n                var buffer = new MemoryStream();\n\n                var writer = Writer.CreatePooled(buffer, _sessionPool.GetSession());\n                serializer.Serialize(toWrite, ref writer);\n                buffer.Flush();\n                writer.Dispose();\n\n                buffer.Position = 0;\n                var reader = Reader.Create(buffer, _sessionPool.GetSession());\n                var deserialized = serializer.Deserialize(ref reader);\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when writing to a span.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_Span()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var buffer = new byte[8096].AsSpan();\n                var toWrite = GetWriteCopy(original);\n\n                var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                serializer.Serialize(toWrite, ref writer);\n\n                var reader = Reader.Create(buffer, _sessionPool.GetSession());\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when writing to an array.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_Array()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var buffer = new byte[8096];\n                var toWrite = GetWriteCopy(original);\n\n                var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                serializer.Serialize(toWrite, ref writer);\n\n                var reader = Reader.Create(buffer, _sessionPool.GetSession());\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when writing to a memory slice.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_Memory()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var buffer = (new byte[8096]).AsMemory();\n                var toWrite = GetWriteCopy(original);\n\n                var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                serializer.Serialize(toWrite, ref writer);\n\n                var reader = Reader.Create(buffer, _sessionPool.GetSession());\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when writing to a memory stream.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_MemoryStream()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var toWrite = GetWriteCopy(original);\n                var buffer = new MemoryStream();\n                using var writerSession = _sessionPool.GetSession();\n                var writer = Writer.Create(buffer, writerSession);\n                serializer.Serialize(toWrite, ref writer);\n                writer.Commit();\n                buffer.Flush();\n                buffer.SetLength(buffer.Position);\n\n                buffer.Position = 0;\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(buffer, readerSession);\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                Assert.Equal(writer.Position, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec correctly round-trips values when reading byte-by-byte, simulating fragmented reads.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer_ReadByteByByte()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var toWrite = GetWriteCopy(original);\n                var buffer = new TestMultiSegmentBufferWriter(maxAllocationSize: 1024);\n                using var writerSession = _sessionPool.GetSession();\n                var writer = Writer.Create(buffer, writerSession);\n                serializer.Serialize(toWrite, ref writer);\n                writer.Commit();\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(buffer.GetReadOnlySequence(maxSegmentSize: 1), readerSession);\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                Assert.Equal(writer.Position, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the codec produces a valid bit stream.\n        /// </summary>\n        [Fact]\n        public void ProducesValidBitStream()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n            foreach (var value in TestValues)\n            {\n                Test(value);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue value)\n            {\n                var array = serializer.SerializeToArray(value);\n                var session = _sessionPool.GetSession();\n                var reader = Reader.Create(array, session);\n                var formatted = new StringBuilder();\n                try\n                {\n                    BitStreamFormatter.Format(ref reader, formatted);\n                    Assert.True(formatted.ToString() is string { Length: > 0 });\n                }\n                catch (Exception exception)\n                {\n                    Assert.True(false, $\"Formatting failed with exception: {exception} and partial result: \\\"{formatted}\\\"\");\n                }\n            }\n        }\n\n        /// <summary>\n        /// Checks whether various buffer writers produce bit-wise identical results.\n        /// </summary>\n        [Fact]\n        public void WritersProduceSameResults()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                byte[] expected;\n\n                {\n                    var buffer = new TestMultiSegmentBufferWriter(1024);\n                    var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    expected = buffer.GetReadOnlySequence(0).ToArray();\n                }\n\n                {\n                    var buffer = new MemoryStream();\n                    var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    buffer.Flush();\n                    buffer.SetLength(buffer.Position);\n                    buffer.Position = 0;\n                    var result = buffer.ToArray();\n                    Assert.Equal(expected, result);\n                }\n\n                {\n                    var writer = Writer.CreatePooled(_sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    var result = writer.Output.ToArray();\n                    Assert.Equal(expected, result);\n                }\n\n                var bytes = new byte[10240];\n\n                {\n                    var buffer = bytes.AsMemory();\n                    var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    var result = buffer[..writer.Output.BytesWritten].ToArray();\n                    Assert.Equal(expected, result);\n                }\n\n                bytes.AsSpan().Clear();\n\n                {\n                    var buffer = bytes.AsSpan();\n                    var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    var result = buffer[..writer.Output.BytesWritten].ToArray();\n                    Assert.Equal(expected, result);\n                }\n\n                bytes.AsSpan().Clear();\n\n                {\n                    var buffer = bytes;\n                    var writer = Writer.Create(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    var result = buffer.AsSpan(0, writer.Output.BytesWritten).ToArray();\n                    Assert.Equal(expected, result);\n                }\n\n                bytes.AsSpan().Clear();\n\n                {\n                    var buffer = new MemoryStream(bytes);\n                    var writer = Writer.CreatePooled(buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    buffer.Flush();\n                    buffer.SetLength(buffer.Position);\n                    buffer.Position = 0;\n                    var result = buffer.ToArray();\n                    writer.Dispose();\n                    Assert.Equal(expected, result);\n                }\n\n                bytes.AsSpan().Clear();\n\n                {\n                    var buffer = new MemoryStream(bytes);\n                    var writer = Writer.Create((Stream)buffer, _sessionPool.GetSession());\n                    serializer.Serialize(GetWriteCopy(original), ref writer);\n                    buffer.Flush();\n                    buffer.SetLength(buffer.Position);\n                    buffer.Position = 0;\n                    var result = buffer.ToArray();\n                    Assert.Equal(expected, result);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Checks whether a strongly typed collection of values can be round-tripped.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripCollectionViaSerializer()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<List<TValue>>>();\n\n            var original = new List<TValue>();\n            var originalCopy = new List<TValue>();\n            original.AddRange(TestValues);\n            foreach (var value in original)\n            {\n                originalCopy.Add(GetWriteCopy(value));\n            }\n\n            for (var i = 0; i < 5; i++)\n            {\n                var o = CreateValue();\n                var c = GetWriteCopy(o);\n                original.Add(o);\n                originalCopy.Add(c);\n            }\n\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(writerSession);\n            serializer.Serialize(originalCopy, ref writer);\n            using var readerSession = _sessionPool.GetSession();\n            var reader = Reader.Create(writer.Output, readerSession);\n            var deserialized = serializer.Deserialize(ref reader);\n\n            Assert.Equal(original.Count, deserialized.Count);\n            for (var i = 0; i < original.Count; ++i)\n            {\n                var isEqual = Equals(original[i], deserialized[i]);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value at index {i}, \\\"{deserialized[i]}\\\", must equal original value, \\\"{original[i]}\\\"\");\n            }\n\n            Assert.Equal(writer.Position, reader.Position);\n            Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n        }\n\n        /// <summary>\n        /// Checks whether a strongly typed collection of values can be round-tripped.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripWeaklyTypedCollectionViaSerializer()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<List<object>>>();\n\n            var original = new List<object>();\n            var originalCopy = new List<object>();\n            foreach (var value in TestValues)\n            {\n                var o = value;\n                var c = GetWriteCopy(o);\n                original.Add(o);\n                originalCopy.Add(c);\n            }\n\n            for (var i = 0; i < 5; i++)\n            {\n                var o = CreateValue();\n                var c = GetWriteCopy(o);\n                original.Add(o);\n                originalCopy.Add(c);\n            }\n\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(writerSession);\n            serializer.Serialize(originalCopy, ref writer);\n            using var readerSession = _sessionPool.GetSession();\n            var reader = Reader.Create(writer.Output, readerSession);\n            var deserialized = serializer.Deserialize(ref reader);\n\n            Assert.Equal(original.Count, deserialized.Count);\n            for (var i = 0; i < original.Count; ++i)\n            {\n                var left = (TValue)original[i];\n                var right = (TValue)deserialized[i];\n                var isEqual = Equals(left, right);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value at index {i}, \\\"{right}\\\", must equal original value, \\\"{left}\\\"\");\n            }\n\n            Assert.Equal(writer.Position, reader.Position);\n            Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n        }\n\n        /// <summary>\n        /// Checks if values can be round-tripped when used as a field in a tuple.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripTupleViaSerializer()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<(string, TValue, TValue, string)>>();\n\n            var original = (Guid.NewGuid().ToString(), CreateValue(), CreateValue(), Guid.NewGuid().ToString());\n            var originalCopy = (original.Item1, GetWriteCopy(original.Item2), GetWriteCopy(original.Item3), original.Item4);\n\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.CreatePooled(writerSession);\n            serializer.Serialize(originalCopy, ref writer);\n            using var readerSession = _sessionPool.GetSession();\n            var reader = Reader.Create(writer.Output, readerSession);\n            var deserialized = serializer.Deserialize(ref reader);\n\n            var isEqual = Equals(original.Item1, deserialized.Item1);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value for item 1, \\\"{deserialized.Item1}\\\", must equal original value, \\\"{original.Item1}\\\"\");\n            isEqual = Equals(original.Item2, deserialized.Item2);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value for item 2, \\\"{deserialized.Item2}\\\", must equal original value, \\\"{original.Item2}\\\"\");\n            isEqual = Equals(original.Item3, deserialized.Item3);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value for item 3, \\\"{deserialized.Item3}\\\", must equal original value, \\\"{original.Item3}\\\"\");\n            isEqual = Equals(original.Item4, deserialized.Item4);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value for item 4, \\\"{deserialized.Item4}\\\", must equal original value, \\\"{original.Item4}\\\"\");\n\n            Assert.Equal(writer.Position, reader.Position);\n            Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n        }\n\n        /// <summary>\n        /// Checks if values can be round-tripped through <see cref=\"Serializer{T}\"/> when using <typeparamref name=\"TValue\"/> as the type parameter.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaSerializer()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<TValue>>();\n\n            foreach (var original in TestValues)\n            {\n                Test(original);\n            }\n\n            if (ValueProvider is { } valueProvider)\n            {\n                valueProvider(Test);\n            }\n\n            void Test(TValue original)\n            {\n                var toWrite = GetWriteCopy(original);\n                var buffer = new TestMultiSegmentBufferWriter(1024);\n                using var writerSession = _sessionPool.GetSession();\n                var writer = Writer.Create(buffer, writerSession);\n                serializer.Serialize(toWrite, ref writer);\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(buffer.GetReadOnlySequence(0), readerSession);\n                var deserialized = serializer.Deserialize(ref reader);\n\n                var isEqual = Equals(original, deserialized);\n                Assert.True(\n                    isEqual,\n                    isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                Assert.Equal(writer.Position, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n        }\n\n        /// <summary>\n        /// Checks if values can be round-tripped through <see cref=\"Serializer{T}\"/> when using <see cref=\"object\"/> as the type parameter.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripViaObjectSerializer()\n        {\n            var serializer = _serviceProvider.GetRequiredService<Serializer<object>>();\n\n            var buffer = new byte[10240];\n\n            foreach (var original in TestValues)\n            {\n                buffer.AsSpan().Clear();\n                var toWrite = GetWriteCopy(original);\n                using var writerSession = _sessionPool.GetSession();\n                var writer = Writer.Create(buffer, writerSession);\n                serializer.Serialize(toWrite, ref writer);\n\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(buffer, readerSession);\n                var deserializedObject = serializer.Deserialize(ref reader);\n                if (original != null && !typeof(TValue).IsEnum)\n                {\n                    var deserialized = Assert.IsAssignableFrom<TValue>(deserializedObject);\n                    var isEqual = Equals(original, deserialized);\n                    Assert.True(\n                        isEqual,\n                        isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                }\n                else if (typeof(TValue).IsEnum)\n                {\n                    var deserialized = (TValue)deserializedObject;\n                    var isEqual = Equals(original, deserialized);\n                    Assert.True(\n                        isEqual,\n                        isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                }\n                else\n                {\n                    Assert.Null(deserializedObject);\n                }\n\n                Assert.Equal(writer.Position, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n        }\n\n        /// <summary>\n        /// Checks if round-tripped values are equal.\n        /// </summary>\n        [Fact]\n        public void RoundTrippedValuesEqual() => TestRoundTrippedValue(CreateValue());\n\n        /// <summary>\n        /// Checks if round-tripped default values are equal.\n        /// </summary>\n        [Fact]\n        public void CanRoundTripDefaultValueViaCodec() => TestRoundTrippedValue(default);\n\n        /// <summary>\n        /// Checks if values can be skipped over.\n        /// </summary>\n        [Fact]\n        public void CanSkipValue() => CanBeSkipped(default);\n\n        /// <summary>\n        /// Checks if default values can be skipped over.\n        /// </summary>\n        [Fact]\n        public void CanSkipDefaultValue() => CanBeSkipped(default);\n\n        /// <summary>\n        /// Checks if buffers are handled correctly.\n        /// </summary>\n        [Fact]\n        public void CorrectlyHandlesBuffers()\n        {\n            var testers = BufferTestHelper<TValue>.GetTestSerializers(_serviceProvider, MaxSegmentSizes);\n\n            foreach (var tester in testers)\n            {\n                foreach (var maxSegmentSize in MaxSegmentSizes)\n                {\n                    foreach (var value in TestValues)\n                    {\n                        var toWrite = GetWriteCopy(value);\n                        var buffer = tester.Serialize(toWrite);\n                        var sequence = buffer.GetReadOnlySequence(maxSegmentSize);\n                        tester.Deserialize(sequence, out var output);\n                        var bufferWriterType = tester.GetType().BaseType?.GenericTypeArguments[1];\n                        var isEqual = Equals(value, output);\n                        Assert.True(isEqual,\n                            isEqual ? string.Empty : $\"Deserialized value {output} must be equal to serialized value {value}. \" +\n                            $\"IBufferWriter<> type: {bufferWriterType}, Max Read Segment Size: {maxSegmentSize}. \" +\n                            $\"Buffer: 0x{string.Join(\" \", sequence.ToArray().Select(b => $\"{b:X2}\"))}\");\n                    }\n                }\n            }\n        }\n\n        private void CanBeSkipped(TValue original)\n        {\n            var pipe = new Pipe();\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n            var writerCodec = CreateCodec();\n            var toWrite = GetWriteCopy(original);\n            writerCodec.WriteField(ref writer, 0, typeof(TValue), toWrite);\n            var expectedLength = writer.Position;\n            writer.Commit();\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n\n            {\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var readField = reader.ReadFieldHeader();\n                reader.SkipField(readField);\n                Assert.Equal(expectedLength, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n\n            {\n                var codec = new SkipFieldCodec();\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var readField = reader.ReadFieldHeader();\n                var shouldBeNull = codec.ReadValue(ref reader, readField);\n                Assert.Null(shouldBeNull);\n                Assert.Equal(expectedLength, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n\n            {\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var readField = reader.ReadFieldHeader();\n                reader.ConsumeUnknownField(readField);\n                Assert.Equal(expectedLength, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n            }\n\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n        }\n\n        private void TestRoundTrippedValue(TValue original)\n        {\n            var pipe = new Pipe();\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n            var writerCodec = CreateCodec();\n            writerCodec.WriteField(ref writer, 0, typeof(TValue), GetWriteCopy(original));\n            writer.Commit();\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = _sessionPool.GetSession();\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n            var readerCodec = CreateCodec();\n            var readField = reader.ReadFieldHeader();\n            var deserialized = readerCodec.ReadValue(ref reader, readField);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n            var isEqual = Equals(original, deserialized);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n        }\n\n        /// <summary>\n        /// Round-trips a value through the codec.\n        /// </summary>\n        protected T RoundTripThroughCodec<T>(T original)\n        {\n            T result;\n            using (var readerSession = SessionPool.GetSession())\n            using (var writeSession = SessionPool.GetSession())\n            {\n                var writer = Writer.CreatePooled(writeSession);\n                try\n                {\n                    var codec = ServiceProvider.GetRequiredService<ICodecProvider>().GetCodec<T>();\n                    codec.WriteField(\n                        ref writer,\n                        0,\n                        null,\n                        original);\n                    writer.Commit();\n\n                    var output = writer.Output.AsReadOnlySequence();\n                    var reader = Reader.Create(output, readerSession);\n\n                    var previousPos = reader.Position;\n                    var initialHeader = reader.ReadFieldHeader();\n                    Assert.True(reader.Position > previousPos);\n\n                    result = codec.ReadValue(ref reader, initialHeader);\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Round-trips a value through an untyped serializer.\n        /// </summary>\n        protected object RoundTripThroughUntypedSerializer(object original, out string formattedBitStream)\n        {\n            object result;\n            using (var readerSession = SessionPool.GetSession())\n            using (var writeSession = SessionPool.GetSession())\n            {\n                var writer = Writer.CreatePooled(writeSession);\n                try\n                {\n                    var serializer = ServiceProvider.GetService<Serializer<object>>();\n                    serializer.Serialize(original, ref writer);\n\n                    using var analyzerSession = SessionPool.GetSession();\n                    var output = writer.Output.Slice();\n                    formattedBitStream = BitStreamFormatter.Format(output, analyzerSession);\n\n                    var reader = Reader.Create(output, readerSession);\n\n                    result = serializer.Deserialize(ref reader);\n                }\n                finally\n                {\n                    writer.Dispose();\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/IOutputBuffer.cs",
    "content": "using System.Buffers;\n\nnamespace Orleans.Serialization.TestKit\n{\n    public interface IOutputBuffer\n    {\n        ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize);\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/Orleans.Serialization.TestKit.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.TestKit</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>Test kit for projects using Orleans.Serialization</PackageDescription>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <IsTestProject>false</IsTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" />\n    <PackageReference Include=\"System.IO.Pipelines\" />\n    <PackageReference Include=\"xunit.assert\" />\n    <PackageReference Include=\"xunit.core\" />\n    <PackageReference Include=\"xunit.extensibility.core\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'netstandard2.1'\">\n    <PackageReference Update=\"xunit.assert\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.core\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.extensibility.core\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.extensibility.execution\" VersionOverride=\"2.4.2\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/README.md",
    "content": "# Microsoft Orleans Serialization Test Kit\n\n## Introduction\nMicrosoft Orleans Serialization Test Kit provides tools and utilities to help test serialization functionality in Orleans applications. This package simplifies writing tests that verify serialization and deserialization of your custom types work correctly.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.TestKit\n```\n\nYou'll typically add this package to a test project.\n\n## Example - Testing Serialization \n```csharp\nusing Orleans.Serialization.TestKit;\nusing Xunit.Abstractions;\n\npublic class TimeSpanTests(ITestOutputHelper output) : FieldCodecTester<TimeSpan>(output)\n{\n    protected override TimeSpan CreateValue() => TimeSpan.FromMilliseconds(Guid.NewGuid().GetHashCode());\n    protected override TimeSpan[] TestValues => [TimeSpan.MinValue, TimeSpan.MaxValue, TimeSpan.Zero, TimeSpan.FromSeconds(12345)];\n    protected override Action<Action<TimeSpan>> ValueProvider => Gen.TimeSpan.ToValueProvider();\n}\n\npublic class TimeSpanCopierTests(ITestOutputHelper output) : CopierTester<TimeSpan, IDeepCopier<TimeSpan>>(output)\n{\n    protected override TimeSpan CreateValue() => TimeSpan.FromMilliseconds(Guid.NewGuid().GetHashCode());\n    protected override TimeSpan[] TestValues => [TimeSpan.MinValue, TimeSpan.MaxValue, TimeSpan.Zero, TimeSpan.FromSeconds(12345)];\n    protected override Action<Action<TimeSpan>> ValueProvider => Gen.TimeSpan.ToValueProvider();\n}\n\npublic class DateTimeOffsetTests(ITestOutputHelper output) : FieldCodecTester<DateTimeOffset, DateTimeOffsetCodec>(output)\n{\n    protected override DateTimeOffset CreateValue() => DateTime.UtcNow;\n    protected override DateTimeOffset[] TestValues =>\n    [\n        DateTimeOffset.MinValue,\n        DateTimeOffset.MaxValue,\n        new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(11.5)),\n        new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(-11.5)),\n    ];\n\n    protected override Action<Action<DateTimeOffset>> ValueProvider => Gen.DateTimeOffset.ToValueProvider();\n}\n\npublic class DateTimeOffsetCopierTests(ITestOutputHelper output) : CopierTester<DateTimeOffset, IDeepCopier<DateTimeOffset>>(output)\n{\n    protected override DateTimeOffset CreateValue() => DateTime.UtcNow;\n    protected override DateTimeOffset[] TestValues =>\n    [\n        DateTimeOffset.MinValue,\n        DateTimeOffset.MaxValue,\n        new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(11.5)),\n        new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(-11.5)),\n    ];\n\n    protected override Action<Action<DateTimeOffset>> ValueProvider => Gen.DateTimeOffset.ToValueProvider();\n}\n```\n\n## Additional Testing Features\nThe TestKit provides several utilities for testing serialization and allows you to focus on testing specific serialization components:\n\n```csharp\n// Using a specific serializer\nvar specificSerializer = services.GetRequiredService<Serializer<MyCustomType>>();\nbyte[] bytes = specificSerializer.SerializeToArray(original);\nvar deserialized = specificSerializer.Deserialize(bytes);\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n- [Testing Orleans Applications](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/testing)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/ReadOnlySequenceHelper.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\n\nnamespace Orleans.Serialization.TestKit\n{\n    [ExcludeFromCodeCoverage]\n    public static class ReadOnlySequenceHelper\n    {\n        public static IEnumerable<byte[]> Batch(this IEnumerable<byte> sequence, int batchSize)\n        {\n            var batch = new List<byte>(batchSize);\n            foreach (var item in sequence)\n            {\n                batch.Add(item);\n\n                if (batch.Count >= batchSize)\n                {\n                    yield return batch.ToArray();\n                    batch = new List<byte>(batchSize);\n                }\n            }\n\n            if (batch.Count > 0)\n            {\n                yield return batch.ToArray();\n            }\n        }\n\n        public static ReadOnlySequence<byte> ToReadOnlySequence(this IEnumerable<byte[]> buffers) => CreateReadOnlySequence(buffers.ToArray());\n\n        public static ReadOnlySequence<byte> ToReadOnlySequence(this IEnumerable<Memory<byte>> buffers) => ReadOnlyBufferSegment.Create(buffers);\n\n        public static ReadOnlySequence<byte> CreateReadOnlySequence(params byte[][] buffers)\n        {\n            if (buffers.Length == 1)\n            {\n                return new ReadOnlySequence<byte>(buffers[0]);\n            }\n\n            var list = new List<Memory<byte>>();\n            foreach (var buffer in buffers)\n            {\n                list.Add(buffer);\n            }\n\n            return ToReadOnlySequence(list);\n        }\n\n        private class ReadOnlyBufferSegment : ReadOnlySequenceSegment<byte>\n        {\n            public static ReadOnlySequence<byte> Create(IEnumerable<Memory<byte>> buffers)\n            {\n                ReadOnlyBufferSegment segment = null;\n                ReadOnlyBufferSegment first = null;\n                foreach (var buffer in buffers)\n                {\n                    var newSegment = new ReadOnlyBufferSegment\n                    {\n                        Memory = buffer,\n                    };\n\n                    if (segment != null)\n                    {\n                        segment.Next = newSegment;\n                        newSegment.RunningIndex = segment.RunningIndex + segment.Memory.Length;\n                    }\n                    else\n                    {\n                        first = newSegment;\n                    }\n\n                    segment = newSegment;\n                }\n\n                if (first is null)\n                {\n                    first = segment = new ReadOnlyBufferSegment();\n                }\n\n                return new ReadOnlySequence<byte>(first, 0, segment, segment.Memory.Length);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/TestBufferWriterStruct.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\n\nnamespace Orleans.Serialization.TestKit\n{\n    [ExcludeFromCodeCoverage]\n    public struct TestBufferWriterStruct : IBufferWriter<byte>, IOutputBuffer\n    {\n        private readonly byte[] _buffer;\n        private int _written;\n\n        public TestBufferWriterStruct(byte[] buffer)\n        {\n            _buffer = buffer;\n            _written = 0;\n        }\n\n        public void Advance(int bytes) => _written += bytes;\n\n        [Pure]\n        public readonly Memory<byte> GetMemory(int sizeHint = 0) => _buffer.AsMemory()[_written..];\n\n        [Pure]\n        public readonly Span<byte> GetSpan(int sizeHint) => _buffer.AsSpan()[_written..];\n\n        [Pure]\n        public readonly ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize) => _buffer.Take(_written).Batch(maxSegmentSize).ToReadOnlySequence();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/TestMultiSegmentBufferWriter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\n\nnamespace Orleans.Serialization.TestKit\n{\n    [ExcludeFromCodeCoverage]\n    public class TestMultiSegmentBufferWriter : IBufferWriter<byte>, IOutputBuffer\n    {\n        private readonly List<byte[]> _committed = new();\n        private readonly int _maxAllocationSize;\n        private byte[] _current = Array.Empty<byte>();\n\n        public TestMultiSegmentBufferWriter(int maxAllocationSize)\n        {\n            _maxAllocationSize = maxAllocationSize;\n        }\n\n        public void Advance(int bytes)\n        {\n            if (bytes == 0)\n            {\n                return;\n            }\n\n            _committed.Add(_current.AsSpan(0, bytes).ToArray());\n            _current = Array.Empty<byte>();\n        }\n\n        public Memory<byte> GetMemory(int sizeHint = 0)\n        {\n            if (sizeHint == 0)\n            {\n                sizeHint = _current.Length + 1;\n            }\n\n            if (sizeHint < _current.Length)\n            {\n                throw new InvalidOperationException(\"Attempted to allocate a new buffer when the existing buffer has sufficient free space.\");\n            }\n\n            var newBuffer = new byte[Math.Min(sizeHint, _maxAllocationSize)];\n            _current.CopyTo(newBuffer.AsSpan());\n            _current = newBuffer;\n            return _current;\n        }\n\n        public Span<byte> GetSpan(int sizeHint)\n        {\n            if (sizeHint == 0)\n            {\n                sizeHint = _current.Length + 1;\n            }\n\n            if (sizeHint < _current.Length)\n            {\n                throw new InvalidOperationException(\"Attempted to allocate a new buffer when the existing buffer has sufficient free space.\");\n            }\n\n            var newBuffer = new byte[Math.Min(sizeHint, _maxAllocationSize)];\n            _current.CopyTo(newBuffer.AsSpan());\n            _current = newBuffer;\n            return _current;\n        }\n\n        [Pure]\n        public ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize) => _committed.SelectMany(b => b).Batch(maxSegmentSize).ToReadOnlySequence();\n\n        public ReadOnlySequence<byte> PeekAllBuffers() => _committed.Concat(new[] { _current }).ToReadOnlySequence();\n    }\n}"
  },
  {
    "path": "src/Orleans.Serialization.TestKit/ValueTypeFieldCodecTester.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.IO.Pipelines;\nusing Xunit;\nusing Orleans.Serialization.Serializers;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.TestKit\n{\n    public abstract class ValueTypeFieldCodecTester<TField, TCodec> : FieldCodecTester<TField, TCodec> where TField : struct where TCodec : class, IFieldCodec<TField>\n    {\n        protected ValueTypeFieldCodecTester(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        [Fact]\n        public void ValueSerializerRoundTrip()\n        {\n            var serializer = ServiceProvider.GetRequiredService<ValueSerializer<TField>>();\n            foreach (var value in TestValues)\n            {\n                var valueCopy = value;\n                var serialized = serializer.SerializeToArray(ref valueCopy);\n                var deserializedValue = default(TField);\n                serializer.Deserialize(serialized, ref deserializedValue);\n                Assert.Equal(value, deserializedValue);\n            }\n        }\n\n        [Fact]\n        public void DirectAccessValueSerializerRoundTrip()\n        {\n            foreach (var value in TestValues)\n            {\n                var valueLocal = value;\n                TestRoundTrippedValueViaValueSerializer(ref valueLocal);\n            }\n        }\n\n        private void TestRoundTrippedValueViaValueSerializer(ref TField original)\n        {\n            var codecProvider = ServiceProvider.GetRequiredService<IValueSerializerProvider>();\n            var serializer = codecProvider.GetValueSerializer<TField>();\n\n            var pipe = new Pipe();\n            using var writerSession = SessionPool.GetSession();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n            var writerCodec = serializer;\n            writerCodec.Serialize(ref writer, ref original);\n            writer.WriteEndObject();\n            writer.Commit();\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = SessionPool.GetSession();\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n            var readerCodec = serializer;\n            TField deserialized = default;\n            readerCodec.Deserialize(ref reader, ref deserialized);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n            var isEqual = Equals(original, deserialized);\n            Assert.True(\n                isEqual,\n                isEqual ? string.Empty : $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n            Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Server/Orleans.Server.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Server</PackageId>\n    <Title>Microsoft Orleans Server Libraries</Title>\n    <Description>Collection of Microsoft Orleans libraries and files needed on the server.</Description>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <NoPackageAnalysis>true</NoPackageAnalysis>\n    <IncludeSymbols>false</IncludeSymbols>\n    <IncludeSource>false</IncludeSource>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Persistence.Memory\\Orleans.Persistence.Memory.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Server/README.md",
    "content": "# Microsoft Orleans Server\n\n## Introduction\nMicrosoft Orleans Server is a metapackage that includes all the necessary components to run an Orleans silo (server). It simplifies the process of setting up an Orleans server by providing a single package reference rather than requiring you to reference multiple packages individually.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Server\n```\n\n## Example - Creating an Orleans Silo Host\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n// Define a grain interface\nnamespace MyGrainNamespace;\n\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<string> DoSomething();\n}\n\n// Implement the grain interface\npublic class MyGrain : Grain, IMyGrain\n{\n    public Task<string> DoSomething()\n    {\n        return Task.FromResult(\"Done something!\");\n    }\n}\n\n\n// Create the host\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering();\n    });\n\n// Start the host\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IMyGrain>(\"my-grain-id\");\nvar result = await grain.DoSomething();\n\n// Print the result\nConsole.WriteLine($\"Result: {result}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans server (silo) configuration](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/server-configuration)\n- [Hosting Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/host/generic-host)\n- [Grain persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Orleans.Streaming/Common/EventSequenceToken.cs",
    "content": "using System;\nusing System.Globalization;\nusing Orleans.Streams;\nusing Newtonsoft.Json;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Stream sequence token that tracks sequence number and event index\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventSequenceToken : StreamSequenceToken\n    {\n        /// <summary>\n        /// Gets the number of event batches in stream prior to this event batch\n        /// </summary>\n        [Id(0)]\n        [JsonProperty]\n        public override long SequenceNumber { get; protected set; }\n\n        /// <summary>\n        /// Gets the number of events in batch prior to this event\n        /// </summary>\n        [Id(1)]\n        [JsonProperty]\n        public override int EventIndex { get; protected set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceToken\"/> class.\n        /// </summary>\n        /// <param name=\"sequenceNumber\">The sequence number.</param>\n        public EventSequenceToken(long sequenceNumber)\n        {\n            SequenceNumber = sequenceNumber;\n            EventIndex = 0;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceToken\" /> class.\n        /// </summary>\n        /// <param name=\"sequenceNumber\">The sequence number.</param>\n        /// <param name=\"eventIndex\">The event index, for events which are part of a batch.</param>\n        public EventSequenceToken(long sequenceNumber, int eventIndex)\n        {\n            SequenceNumber = sequenceNumber;\n            EventIndex = eventIndex;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceToken\" /> class.\n        /// </summary>\n        /// <remarks>\n        /// This constructor is exposed for serializer use only.\n        /// </remarks>\n        [JsonConstructor]\n        public EventSequenceToken()\n        { }\n\n        /// <summary>\n        /// Creates a sequence token for a specific event in the current batch.\n        /// </summary>\n        /// <param name=\"eventInd\">The event index, for events which are part of a batch.</param>\n        /// <returns>The sequence token.</returns>\n        public EventSequenceToken CreateSequenceTokenForEvent(int eventInd)\n        {\n            return new EventSequenceToken(SequenceNumber, eventInd);\n        }\n\n        /// <inheritdoc />\n        public override bool Equals(object obj)\n        {\n            return Equals(obj as EventSequenceToken);\n        }\n\n        /// <inheritdoc />\n        public override bool Equals(StreamSequenceToken other)\n        {\n            var token = other as EventSequenceToken;\n            return token != null && (token.SequenceNumber == SequenceNumber &&\n                                     token.EventIndex == EventIndex);\n        }\n\n        /// <inheritdoc />\n        public override int CompareTo(StreamSequenceToken other)\n        {\n            if (other == null)\n                return 1;\n            \n            var token = other as EventSequenceToken;\n            if (token == null)\n                throw new ArgumentOutOfRangeException(nameof(other));\n            \n            int difference = SequenceNumber.CompareTo(token.SequenceNumber);\n            return difference != 0 ? difference : EventIndex.CompareTo(token.EventIndex);\n        }\n\n        /// <inheritdoc />\n        public override int GetHashCode() => HashCode.Combine(SequenceNumber, EventIndex);\n\n        /// <inheritdoc />\n        public override string ToString()\n        {\n            return string.Format(CultureInfo.InvariantCulture, \"[EventSequenceToken: SeqNum={0}, EventIndex={1}]\", SequenceNumber, EventIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/EventSequenceTokenV2.cs",
    "content": "using System;\nusing System.Globalization;\nusing Newtonsoft.Json;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Stream sequence token that tracks sequence number and event index\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class EventSequenceTokenV2 : StreamSequenceToken\n    {\n        /// <summary>\n        /// Gets the number of event batches in stream prior to this event batch\n        /// </summary>\n        [Id(0)]\n        [JsonProperty]\n        public override long SequenceNumber { get; protected set; }\n\n        /// <summary>\n        /// Gets the number of events in batch prior to this event\n        /// </summary>\n        [Id(1)]\n        [JsonProperty]\n        public override int EventIndex { get; protected set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceTokenV2\"/> class.\n        /// </summary>\n        /// <param name=\"seqNumber\">The sequence number.</param>\n        public EventSequenceTokenV2(long seqNumber)\n        {\n            SequenceNumber = seqNumber;\n            EventIndex = 0;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceTokenV2\"/> class.\n        /// </summary>\n        /// <param name=\"seqNumber\">The sequence number.</param>\n        /// <param name=\"eventInd\">The event index, for events which are part of a batch of events.</param>\n        public EventSequenceTokenV2(long seqNumber, int eventInd)\n        {\n            SequenceNumber = seqNumber;\n            EventIndex = eventInd;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EventSequenceTokenV2\"/> class.\n        /// </summary>\n        /// <remarks>\n        /// This constructor is for serializer use only.\n        /// </remarks>\n        public EventSequenceTokenV2()\n        {\n        }\n\n        /// <summary>\n        /// Creates a sequence token for a specific event in the current batch\n        /// </summary>\n        /// <param name=\"eventInd\">The event index.</param>\n        /// <returns>A new sequence token.</returns>\n        public EventSequenceTokenV2 CreateSequenceTokenForEvent(int eventInd)\n        {\n            return new EventSequenceTokenV2(SequenceNumber, eventInd);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object obj)\n        {\n            return Equals(obj as EventSequenceTokenV2);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(StreamSequenceToken other)\n        {\n            var token = other as EventSequenceTokenV2;\n            return token != null && (token.SequenceNumber == SequenceNumber &&\n                                     token.EventIndex == EventIndex);\n        }\n\n        /// <inheritdoc/>\n        public override int CompareTo(StreamSequenceToken other)\n        {\n            if (other == null)\n                return 1;\n\n            var token = other as EventSequenceTokenV2;\n            if (token == null)\n                throw new ArgumentOutOfRangeException(nameof(other));\n\n            int difference = SequenceNumber.CompareTo(token.SequenceNumber);\n            return difference != 0 ? difference : EventIndex.CompareTo(token.EventIndex);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => HashCode.Combine(SequenceNumber, EventIndex);\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            return string.Format(CultureInfo.InvariantCulture, \"[EventSequenceTokenV2: SeqNum={0}, EventIndex={1}]\", SequenceNumber, EventIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/DefaultBlockPoolMonitor.cs",
    "content": "using Orleans.Runtime;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Block pool monitor used as a default option in GeneratorStreamProvider and MemoryStreamProvider.\n    /// </summary>\n    public class DefaultBlockPoolMonitor : IBlockPoolMonitor\n    {\n        protected KeyValuePair<string, object>[] _dimensions;\n        private readonly ObservableCounter<long> _totalMemoryCounter;\n        private readonly ObservableCounter<long> _availableMemoryCounter;\n        private readonly ObservableCounter<long> _claimedMemoryCounter;\n        private readonly ObservableCounter<long> _releasedMemoryCounter;\n        private readonly ObservableCounter<long> _allocatedMemoryCounter;\n        private long _totalMemory;\n        private long _availableMemory;\n        private long _claimedMemory;\n        private long _releasedMemory;\n        private long _allocatedMemory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultBlockPoolMonitor\"/> class.\n        /// </summary>\n        protected DefaultBlockPoolMonitor(KeyValuePair<string, object>[] dimensions)\n        {\n            _dimensions = dimensions;\n            _totalMemoryCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_BLOCK_POOL_TOTAL_MEMORY, GetTotalMemory, unit: \"bytes\");\n            _availableMemoryCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_BLOCK_POOL_AVAILABLE_MEMORY, GetAvailableMemory, unit: \"bytes\");\n            _claimedMemoryCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_BLOCK_POOL_CLAIMED_MEMORY, GetClaimedMemory, unit: \"bytes\");\n            _releasedMemoryCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_BLOCK_POOL_RELEASED_MEMORY, GetReleasedMemory, unit: \"bytes\");\n            _allocatedMemoryCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_BLOCK_POOL_ALLOCATED_MEMORY, GetAllocatedMemory, unit: \"bytes\");\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultBlockPoolMonitor\"/> class.\n        /// </summary>\n        /// <param name=\"dimensions\">The dimensions.</param>\n        public DefaultBlockPoolMonitor(BlockPoolMonitorDimensions dimensions) : this(new KeyValuePair<string, object>[] { new (\"BlockPoolId\", dimensions.BlockPoolId) })\n        {\n        }\n\n        private Measurement<long> GetTotalMemory() => new(_totalMemory, _dimensions);\n        private Measurement<long> GetAvailableMemory() => new(_availableMemory, _dimensions);\n        private Measurement<long> GetClaimedMemory() => new(_claimedMemory, _dimensions);\n        private Measurement<long> GetReleasedMemory() => new(_releasedMemory, _dimensions);\n        private Measurement<long> GetAllocatedMemory() => new(_allocatedMemory, _dimensions);\n\n        /// <inheritdoc />\n        public void Report(long totalMemoryInByte, long availableMemoryInByte, long claimedMemoryInByte)\n        {\n            _totalMemory = totalMemoryInByte;\n            _availableMemory = availableMemoryInByte;\n            _claimedMemory = claimedMemoryInByte;\n        }\n\n        /// <inheritdoc />\n        public void TrackMemoryReleased(long releasedMemoryInByte)\n        {\n            Interlocked.Add(ref _releasedMemory, releasedMemoryInByte);\n        }\n\n        /// <inheritdoc />\n        public void TrackMemoryAllocated(long allocatedMemoryInByte)\n        {\n            Interlocked.Add(ref _allocatedMemory, allocatedMemoryInByte);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/DefaultCacheMonitor.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// cache monitor used as a default option in GeneratorStreamprovider and MemoryStreamProvider\n    /// </summary>\n    public class DefaultCacheMonitor : ICacheMonitor\n    {\n        private readonly KeyValuePair<string, object>[] _dimensions;\n        private readonly ObservableCounter<long> _queueCacheSizeCounter;\n        private readonly ObservableCounter<long> _queueCacheMessagesAddedCounter;\n        private readonly ObservableCounter<long> _queueCacheMessagesPurgedCounter;\n        private readonly ObservableCounter<long> _queueCacheMemoryAllocatedCounter;\n        private readonly ObservableCounter<long> _queueCacheMemoryReleasedCounter;\n        private readonly ObservableGauge<long> _oldestMessageReadEnqueueTimeToNowCounter;\n        private readonly ObservableGauge<long> _newestMessageReadEnqueueTimeToNowCounter;\n        private readonly ObservableGauge<double> _currentPressureCounter;\n        private readonly ObservableGauge<int> _underPressureCounter;\n        private readonly ObservableGauge<double> _pressureContributionCounter;\n        private readonly ObservableCounter<long> _queueCacheMessageCountCounter;\n        private readonly ConcurrentDictionary<string, PressureMonitorStatistics> _pressureMonitors = new();\n        private long _messagesPurged;\n        private long _messagesAdded;\n        private long _memoryReleased;\n        private long _memoryAllocated;\n        private long _totalCacheSize;\n        private long _messageCount;\n        private ValueStopwatch _oldestMessageDequeueAgo;\n        private ValueStopwatch _oldestToNewestAge;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultCacheMonitor\"/> class.\n        /// </summary>\n        protected DefaultCacheMonitor(KeyValuePair<string, object>[] dimensions)\n        {\n            _dimensions = dimensions;\n            _queueCacheSizeCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_SIZE, () => new(_totalCacheSize, _dimensions), unit: \"bytes\");\n            _queueCacheMessageCountCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_LENGTH, () => new(_messageCount, _dimensions), unit: \"messages\");\n            _queueCacheMessagesAddedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_MESSAGES_ADDED, () => new(_messagesAdded, _dimensions));\n            _queueCacheMessagesPurgedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_MESSAGES_PURGED, () => new(_messagesPurged, _dimensions));\n            _queueCacheMemoryAllocatedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_MEMORY_ALLOCATED, () => new(_memoryAllocated, _dimensions));\n            _queueCacheMemoryReleasedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_CACHE_MEMORY_RELEASED, () => new(_memoryReleased, _dimensions));\n            _oldestMessageReadEnqueueTimeToNowCounter = Instruments.Meter.CreateObservableGauge<long>(InstrumentNames.STREAMS_QUEUE_CACHE_OLDEST_TO_NEWEST_DURATION, GetOldestToNewestAge);\n            _newestMessageReadEnqueueTimeToNowCounter = Instruments.Meter.CreateObservableGauge<long>(InstrumentNames.STREAMS_QUEUE_CACHE_OLDEST_AGE, GetOldestAge);\n            _currentPressureCounter = Instruments.Meter.CreateObservableGauge<double>(InstrumentNames.STREAMS_QUEUE_CACHE_PRESSURE, () => GetPressureMonitorMeasurement(monitor => monitor.CurrentPressure));\n            _underPressureCounter = Instruments.Meter.CreateObservableGauge<int>(InstrumentNames.STREAMS_QUEUE_CACHE_UNDER_PRESSURE, () => GetPressureMonitorMeasurement(monitor => monitor.UnderPressure));\n            _pressureContributionCounter = Instruments.Meter.CreateObservableGauge<double>(InstrumentNames.STREAMS_QUEUE_CACHE_PRESSURE_CONTRIBUTION_COUNT, () => GetPressureMonitorMeasurement(monitor => monitor.PressureContributionCount));\n            IEnumerable<Measurement<T>> GetPressureMonitorMeasurement<T>(Func<PressureMonitorStatistics, T> selector) where T : struct\n            {\n                foreach (var monitor in _pressureMonitors)\n                {\n                    yield return new Measurement<T>(selector(monitor.Value), monitor.Value.Dimensions);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultCacheMonitor\"/> class.\n        /// </summary>\n        /// <param name=\"dimensions\">The dimensions.</param>\n        public DefaultCacheMonitor(CacheMonitorDimensions dimensions) : this(new KeyValuePair<string, object>[] { new(\"QueueId\", dimensions.QueueId) })\n        {\n        }\n\n        private Measurement<long> GetOldestToNewestAge() => new(_oldestToNewestAge.ElapsedTicks, _dimensions);\n        private Measurement<long> GetOldestAge() => new(_oldestMessageDequeueAgo.ElapsedTicks, _dimensions);\n\n        /// <inheritdoc />\n        public void TrackCachePressureMonitorStatusChange(\n            string pressureMonitorType,\n            bool underPressure,\n            double? cachePressureContributionCount,\n            double? currentPressure,\n            double? flowControlThreshold)\n        {\n            var monitor = _pressureMonitors.GetOrAdd(pressureMonitorType, static (key, dimensions) => new PressureMonitorStatistics(key, dimensions), _dimensions);\n            monitor.UnderPressure = underPressure ? 1 : 0;\n            if (cachePressureContributionCount.HasValue)\n            {\n                monitor.PressureContributionCount = cachePressureContributionCount.Value;\n            }\n\n            if (currentPressure.HasValue)\n            {\n                monitor.CurrentPressure = currentPressure.Value;\n            }\n\n        }\n\n        /// <inheritdoc />\n        public void ReportCacheSize(long totalCacheSizeInByte) => _totalCacheSize = totalCacheSizeInByte;\n\n        /// <inheritdoc />\n        public void ReportMessageStatistics(DateTime? oldestMessageEnqueueTimeUtc, DateTime? oldestMessageDequeueTimeUtc, DateTime? newestMessageEnqueueTimeUtc, long totalMessageCount)\n        {\n            if (oldestMessageEnqueueTimeUtc.HasValue && newestMessageEnqueueTimeUtc.HasValue)\n            {\n                _oldestToNewestAge = ValueStopwatch.StartNew(newestMessageEnqueueTimeUtc.Value - oldestMessageEnqueueTimeUtc.Value);\n            }\n\n            if (oldestMessageDequeueTimeUtc.HasValue)\n            {\n                _oldestMessageDequeueAgo = ValueStopwatch.StartNew(DateTime.UtcNow - oldestMessageDequeueTimeUtc.Value);\n            }\n\n            _messageCount = totalMessageCount;\n        }\n\n        /// <inheritdoc />\n        public void TrackMemoryAllocated(int memoryInByte) => Interlocked.Add(ref _memoryAllocated, memoryInByte);\n\n        /// <inheritdoc />\n        public void TrackMemoryReleased(int memoryInByte) => Interlocked.Add(ref _memoryReleased, memoryInByte);\n\n        /// <inheritdoc />\n        public void TrackMessagesAdded(long messageAdded) => Interlocked.Add(ref _messagesAdded, messageAdded);\n\n        /// <inheritdoc />\n        public void TrackMessagesPurged(long messagePurged) => Interlocked.Add(ref _messagesPurged, messagePurged);\n\n        private sealed class PressureMonitorStatistics\n        {\n            public PressureMonitorStatistics(string type, KeyValuePair<string, object>[] dimensions)\n            {\n                Dimensions = new KeyValuePair<string, object>[dimensions.Length + 1];\n                dimensions.CopyTo(Dimensions, 0);\n                Dimensions[^1] = new KeyValuePair<string, object>(\"PressureMonitorType\", type);\n            }\n\n            public KeyValuePair<string, object>[] Dimensions { get; }\n            public double PressureContributionCount { get; set; }\n            public double CurrentPressure { get; set; }\n            public int UnderPressure { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/DefaultQueueAdapterReceiverMonitor.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.Threading;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Queue adapter receiver monitor used as a default option in GeneratorStreamprovider and MemoryStreamProvider\n    /// </summary>\n    public class DefaultQueueAdapterReceiverMonitor : IQueueAdapterReceiverMonitor\n    {\n        private readonly Counter<long> _initializationFailureCounter;\n        private readonly Counter<long> _initializationCallTimeCounter;\n        private readonly Counter<long> _initializationExceptionCounter;\n        private readonly Counter<long> _readFailureCounter;\n        private readonly Counter<long> _readCallTimeCounter;\n        private readonly Counter<long> _readExceptionCounter;\n        private readonly Counter<long> _shutdownFailureCounter;\n        private readonly Counter<long> _shutdownCallTimeCounter;\n        private readonly Counter<long> _shutdownExceptionCounter;\n        private readonly ObservableCounter<long> _messagesReceivedCounter;\n        private readonly ObservableGauge<long> _oldestMessageReadEnqueueTimeToNowCounter;\n        private readonly ObservableGauge<long> _newestMessageReadEnqueueTimeToNowCounter;\n        private readonly KeyValuePair<string, object>[] _dimensions;\n        private ValueStopwatch _oldestMessageReadEnqueueAge;\n        private ValueStopwatch _newestMessageReadEnqueueAge;\n        private long _messagesReceived;\n\n        protected DefaultQueueAdapterReceiverMonitor(KeyValuePair<string,object>[] dimensions)\n        {\n            _dimensions = dimensions;\n            _initializationFailureCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_INITIALIZATION_FAILURES);\n            _initializationCallTimeCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_INITIALIZATION_DURATION);\n            _initializationExceptionCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_INITIALIZATION_EXCEPTIONS);\n\n            _readFailureCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_READ_FAILURES);\n            _readCallTimeCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_READ_DURATION);\n            _readExceptionCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_READ_EXCEPTIONS);\n\n            _shutdownFailureCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_SHUTDOWN_FAILURES);\n            _shutdownCallTimeCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_SHUTDOWN_DURATION);\n            _shutdownExceptionCounter = Instruments.Meter.CreateCounter<long>(InstrumentNames.STREAMS_QUEUE_SHUTDOWN_EXCEPTIONS);\n\n            _messagesReceivedCounter = Instruments.Meter.CreateObservableCounter<long>(InstrumentNames.STREAMS_QUEUE_MESSAGES_RECEIVED, GetMessagesReceivedCount);\n            _oldestMessageReadEnqueueTimeToNowCounter = Instruments.Meter.CreateObservableGauge<long>(InstrumentNames.STREAMS_QUEUE_OLDEST_MESSAGE_ENQUEUE_AGE, GetOldestMessageReadEnqueueAge);\n            _newestMessageReadEnqueueTimeToNowCounter = Instruments.Meter.CreateObservableGauge<long>(InstrumentNames.STREAMS_QUEUE_NEWEST_MESSAGE_ENQUEUE_AGE, GetNewestMessageReadEnqueueAge);\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultQueueAdapterReceiverMonitor\"/> class.\n        /// </summary>\n        /// <param name=\"dimensions\">The dimensions.</param>\n        public DefaultQueueAdapterReceiverMonitor(ReceiverMonitorDimensions dimensions) : this(new KeyValuePair<string,object>[] { new(\"QueueId\", dimensions.QueueId) })\n        {\n        }\n\n        private Measurement<long> GetOldestMessageReadEnqueueAge() => new(_oldestMessageReadEnqueueAge.ElapsedTicks, _dimensions);\n        private Measurement<long> GetNewestMessageReadEnqueueAge() => new(_newestMessageReadEnqueueAge.ElapsedTicks, _dimensions);\n        private Measurement<long> GetMessagesReceivedCount() => new(_messagesReceived, _dimensions);\n\n        /// <inheritdoc />\n        public void TrackInitialization(bool success, TimeSpan callTime, Exception exception)\n        {\n            _initializationFailureCounter.Add(success ? 0 : 1, _dimensions);\n            _initializationCallTimeCounter.Add(callTime.Ticks, _dimensions);\n            _initializationExceptionCounter.Add(exception is null ? 0 : 1, _dimensions);\n        }\n\n        /// <inheritdoc />\n        public void TrackRead(bool success, TimeSpan callTime, Exception exception)\n        {\n            _readFailureCounter.Add(success ? 0 : 1, _dimensions);\n            _readCallTimeCounter.Add(callTime.Ticks, _dimensions);\n            _readExceptionCounter.Add(exception is null ? 0 : 1, _dimensions);\n        }\n\n        /// <inheritdoc />\n        public void TrackMessagesReceived(long count, DateTime? oldestMessageEnqueueTimeUtc, DateTime? newestMessageEnqueueTimeUtc)\n        {\n            var now = DateTime.UtcNow;\n            Interlocked.Add(ref _messagesReceived, count);\n            if (oldestMessageEnqueueTimeUtc.HasValue)\n            {\n                var delta = now - oldestMessageEnqueueTimeUtc.Value;\n                _oldestMessageReadEnqueueAge = ValueStopwatch.StartNew(delta);\n            }\n\n            if (newestMessageEnqueueTimeUtc.HasValue)\n            {\n                var delta = now - newestMessageEnqueueTimeUtc.Value;\n                _newestMessageReadEnqueueAge = ValueStopwatch.StartNew(delta);\n            }\n        }\n\n        /// <inheritdoc />\n        public void TrackShutdown(bool success, TimeSpan callTime, Exception exception)\n        {\n            _shutdownFailureCounter.Add(success ? 0 : 1, _dimensions);\n            _shutdownCallTimeCounter.Add(callTime.Ticks, _dimensions);\n            _shutdownExceptionCounter.Add(exception is null ? 0 : 1, _dimensions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/IBlockPoolMonitor.cs",
    "content": "namespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Monitor track block pool related metrics. Block pool is used in cache system for memory management \n    /// </summary>\n    public interface IBlockPoolMonitor\n    {\n        /// <summary>\n        /// Called when memory is newly allocated by the cache.\n        /// </summary>\n        /// <param name=\"allocatedMemoryInBytes\">The allocated memory, in bytes.</param>\n        void TrackMemoryAllocated(long allocatedMemoryInBytes);\n\n        /// <summary>\n        /// Called when memory is released by the cache.\n        /// </summary>\n        /// <param name=\"releasedMemoryInBytes\">The released memory, in bytes.</param>\n        void TrackMemoryReleased(long releasedMemoryInBytes);\n\n        /// <summary>\n        /// Periodically report block pool status\n        /// </summary>\n        /// <param name=\"totalSizeInByte\">Total memory this block pool allocated.</param>\n        /// <param name=\"availableMemoryInByte\">Memory which is available for allocating to caches.</param>\n        /// <param name=\"claimedMemoryInByte\">Memory in use by caches.</param>\n        void Report(long totalSizeInByte, long availableMemoryInByte, long claimedMemoryInByte);\n    }\n\n    /// <summary>\n    /// ObjectPoolMonitor report metrics for ObjectPool, which are based on object count. BlockPoolMonitor report metrics for BlockPool, which are based on memory size. \n    /// These two monitor converge in orleans cache infrastructure, where ObjectPool is used as block pool to allocate memory, where each object represent a block of memory\n    /// which has a size. ObjectPoolMonitorBridge is the bridge between these two monitors in cache infrastructure. When ObjectPoolMonitor is reporting a metric, \n    /// the user configured BlockPoolMonitor will call its counterpart method and reporting metric based on the math: memoryInByte = objectCount*objectSizeInByte\n    /// </summary>\n    public class ObjectPoolMonitorBridge : IObjectPoolMonitor\n    {\n        private readonly IBlockPoolMonitor blockPoolMonitor;\n        private readonly int blockSizeInBytes;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ObjectPoolMonitorBridge\"/> class.\n        /// </summary>\n        /// <param name=\"blockPoolMonitor\">The block pool monitor.</param>\n        /// <param name=\"blockSizeInBytes\">The block size in bytes.</param>\n        public ObjectPoolMonitorBridge(IBlockPoolMonitor blockPoolMonitor, int blockSizeInBytes)\n        {\n            this.blockPoolMonitor = blockPoolMonitor;\n            this.blockSizeInBytes = blockSizeInBytes;\n        }\n\n        /// <inheritdoc />\n        public void TrackObjectAllocated()\n        {\n            long memoryAllocatedInByte = blockSizeInBytes;\n            this.blockPoolMonitor.TrackMemoryAllocated(memoryAllocatedInByte);\n        }\n\n        /// <inheritdoc />\n        public void TrackObjectReleased()\n        {\n            long memoryReleasedInByte = blockSizeInBytes;\n            this.blockPoolMonitor.TrackMemoryReleased(memoryReleasedInByte);\n        }\n\n        /// <inheritdoc />\n        public void Report(long totalObjects, long availableObjects, long claimedObjects)\n        {\n            var totalMemoryInByte = totalObjects * this.blockSizeInBytes;\n            var availableMemoryInByte = availableObjects * this.blockSizeInBytes;\n            var claimedMemoryInByte = claimedObjects * this.blockSizeInBytes;\n            this.blockPoolMonitor.Report(totalMemoryInByte, availableMemoryInByte, claimedMemoryInByte);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/ICacheMonitor.cs",
    "content": "using System;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Responsible for monitoring cache related metrics.\n    /// </summary>\n    public interface ICacheMonitor\n    {\n        /// <summary>\n        /// Called when the cache pressure monitor encounter a status change.\n        /// </summary>\n        /// <param name=\"pressureMonitorType\">Type of the pressure monitor.</param>\n        /// <param name=\"underPressure\">if set to <see langword=\"true\" />, the cache is under pressure.</param>\n        /// <param name=\"cachePressureContributionCount\">The cache pressure contribution count.</param>\n        /// <param name=\"currentPressure\">The current pressure.</param>\n        /// <param name=\"flowControlThreshold\">The flow control threshold.</param>\n        void TrackCachePressureMonitorStatusChange(string pressureMonitorType, bool underPressure, double? cachePressureContributionCount, double? currentPressure, \n            double? flowControlThreshold);\n\n        /// <summary>\n        /// Called when messages are added to the cache.\n        /// </summary>\n        /// <param name=\"messagesAdded\">The number of messages added.</param>\n        void TrackMessagesAdded(long messagesAdded);\n\n        /// <summary>\n        /// Called when messages are purged from the cache.\n        /// </summary>\n        /// <param name=\"messagesPurged\">The number of messages purged.</param>\n        void TrackMessagesPurged(long messagesPurged);\n\n        /// <summary>\n        /// Called when new memory is allocated by the cache.\n        /// </summary>\n        /// <param name=\"memoryInBytes\">The memory in bytes.</param>\n        void TrackMemoryAllocated(int memoryInBytes);\n\n        /// <summary>\n        /// Called when memory returned to block pool.\n        /// </summary>\n        /// <param name=\"memoryInBytes\">The memory in bytes.</param>\n        void TrackMemoryReleased(int memoryInBytes);\n\n        /// <summary>\n        /// Called to report cache status metrics.\n        /// </summary>\n        /// <param name=\"oldestMessageEnqueueTimeUtc\">The time in UTC when the oldest message was enqueued to the queue.</param>\n        /// <param name=\"oldestMessageDequeueTimeUtc\">The time in UTC when the oldest message was read from the queue and put in the cache.</param>\n        /// <param name=\"newestMessageEnqueueTimeUtc\">The time in UTC when the newest message was enqueued to the queue.</param>\n        /// <param name=\"totalMessageCount\">The total message count.</param>\n        void ReportMessageStatistics(DateTime? oldestMessageEnqueueTimeUtc, DateTime? oldestMessageDequeueTimeUtc, DateTime? newestMessageEnqueueTimeUtc, \n            long totalMessageCount);\n\n        /// <summary>\n        /// Called to report the total cache size.\n        /// </summary>\n        /// <param name=\"totalCacheSizeInBytes\">The total cache size in bytes.</param>\n        void ReportCacheSize(long totalCacheSizeInBytes);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/IObjectPoolMonitor.cs",
    "content": "namespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Monitor track object pool related metrics\n    /// </summary>\n    public interface IObjectPoolMonitor\n    {\n        /// <summary>\n        /// Called every time when an object is allocated.\n        /// </summary>\n        void TrackObjectAllocated();\n\n        /// <summary>\n        /// Called every time an object was released back to the pool.\n        /// </summary>\n        void TrackObjectReleased();\n\n        /// <summary>\n        /// Called to report object pool status.\n        /// </summary>\n        /// <param name=\"totalObjects\">Total size of object pool.</param>\n        /// <param name=\"availableObjects\">Count for objects in the pool which is available for allocating.</param>\n        /// <param name=\"claimedObjects\">Count for objects which are claimed, hence not available.</param>\n        void Report(long totalObjects, long availableObjects, long claimedObjects);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/IQueueAdapterReceiverMonitor.cs",
    "content": "using System;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Responsible for monitoring receiver performance metrics.\n    /// </summary>\n    public interface IQueueAdapterReceiverMonitor\n    {\n        /// <summary>\n        /// Track attempts to initialize the receiver.\n        /// </summary>\n        /// <param name=\"success\">True if read succeeded, false if read failed.</param>\n        /// <param name=\"callTime\">Init operation time.</param>\n        /// <param name=\"exception\">Exception caught if initialize fail.</param>\n        void TrackInitialization(bool success, TimeSpan callTime, Exception exception);\n\n        /// <summary>\n        /// Track attempts to read from the partition.    Tracked per partition read operation.\n        /// </summary>\n        /// <param name=\"success\">True if read succeeded, false if read failed.</param>\n        /// <param name=\"callTime\">Time spent in read operation.</param>\n        /// <param name=\"exception\">The exception caught if read failed.</param>\n        void TrackRead(bool success, TimeSpan callTime, Exception exception);\n        \n        /// <summary>\n        /// Tracks messages read and time taken per successful read.  Tracked per successful partition read operation.\n        /// </summary>\n        /// <param name=\"count\">Messages read.</param>\n        /// <param name=\"oldestMessageEnqueueTimeUtc\">The oldest message enqueue time (UTC).</param>\n        /// <param name=\"newestMessageEnqueueTimeUtc\">The newest message enqueue time (UTC).</param>\n        void TrackMessagesReceived(long count, DateTime? oldestMessageEnqueueTimeUtc, DateTime? newestMessageEnqueueTimeUtc);\n\n        /// <summary>\n        /// Track attempts to shutdown the receiver.\n        /// </summary>\n        /// <param name=\"success\">True if read succeeded, false if read failed.</param>\n        /// <param name=\"callTime\">Shutdown operation time.</param>\n        /// <param name=\"exception\">Exception caught if shutdown fail.</param>\n        void TrackShutdown(bool success, TimeSpan callTime, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/Monitors/MonitorAggregationDimensions.cs",
    "content": "namespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Aggregation dimensions for receiver monitor.\n    /// </summary>\n    public class ReceiverMonitorDimensions\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReceiverMonitorDimensions\"/> class.\n        /// </summary>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        public ReceiverMonitorDimensions(string queueId)\n        {\n            this.QueueId = queueId;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReceiverMonitorDimensions\"/> class.\n        /// </summary>\n        public ReceiverMonitorDimensions()\n        {\n        }\n\n        /// <summary>\n        /// Gets the queue identifier.\n        /// </summary>\n        public string QueueId { get; set; }\n    }\n\n    /// <summary>\n    /// Aggregation dimensions for cache monitor.\n    /// </summary>\n    public class CacheMonitorDimensions : ReceiverMonitorDimensions\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CacheMonitorDimensions\"/> class.\n        /// </summary>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"blockPoolId\">The block pool identifier.</param>\n        public CacheMonitorDimensions(string queueId, string blockPoolId)\n            :base(queueId)\n        {\n            this.BlockPoolId = blockPoolId;\n        }\n\n        /// <summary>\n        /// Gets or sets the block pool identifier.\n        /// </summary>\n        /// <value>The block pool identifier.</value>\n        public string BlockPoolId { get; set; }\n    }\n\n    /// <summary>\n    /// Aggregation dimensions for block pool monitors.\n    /// </summary>\n    public class BlockPoolMonitorDimensions\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BlockPoolMonitorDimensions\"/> class.\n        /// </summary>\n        /// <param name=\"blockPoolId\">The block pool identifier.</param>\n        public BlockPoolMonitorDimensions(string blockPoolId)\n        {\n            this.BlockPoolId = blockPoolId;\n        }\n\n        /// <summary>\n        /// Gets or sets the block pool identifier.\n        /// </summary>\n        /// <value>The block pool identifier.</value>\n        public string BlockPoolId { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/CachedMessage.cs",
    "content": "\nusing System;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// This is a tightly packed cached structure containing a queue message.\n    /// It should only contain value types.\n    /// </summary>\n    public struct CachedMessage\n    {\n        /// <summary>\n        /// Identity of the stream this message is a part of.\n        /// </summary>\n        public StreamId StreamId;\n\n        /// <summary>\n        /// Sequence number. Position of event in queue.\n        /// </summary>\n        public long SequenceNumber;\n\n        /// <summary>\n        /// Event index. Index in batch.\n        /// </summary>\n        public int EventIndex;\n\n        /// <summary>\n        /// Time event was written to the queuing system.\n        /// </summary>\n        public DateTime EnqueueTimeUtc;\n\n        /// <summary>\n        /// Time event was read from the queuing system into this cache.\n        /// </summary>\n        public DateTime DequeueTimeUtc;\n\n        /// <summary>\n        /// Segment containing the serialized event data.\n        /// </summary>\n        public ArraySegment<byte> Segment;\n    }\n\n    /// <summary>\n    /// Extensions for <see cref=\"CachedMessage\"/>.\n    /// </summary>\n    public static class CachedMessageExtensions\n    {\n        /// <summary>\n        /// Compares the specified cached message.\n        /// </summary>\n        /// <param name=\"cachedMessage\">The cached message.</param>\n        /// <param name=\"token\">The token.</param>\n        /// <returns>A value indicating the relative order of the token to the cached message.</returns>\n        public static int Compare(this ref CachedMessage cachedMessage, StreamSequenceToken token)\n        {\n            return cachedMessage.SequenceNumber != token.SequenceNumber\n                ? (int)(cachedMessage.SequenceNumber - token.SequenceNumber)\n                : cachedMessage.EventIndex - token.EventIndex;\n        }\n\n        /// <summary>\n        /// Compares the stream identifier of a cached message.\n        /// </summary>\n        /// <param name=\"cachedMessage\">The cached message.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns><see langword=\"true\"/> if streamId is equal to the <see cref=\"CachedMessage.StreamId\"/> value; otherwise <see langword=\"false\"/>.</returns>\n        public static bool CompareStreamId(this ref CachedMessage cachedMessage, StreamId streamId) => cachedMessage.StreamId.Equals(streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/CachedMessageBlock.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// CachedMessageBlock is a block of tightly packed structures containing tracking data for cached messages.  This data is \n    ///   tightly packed to reduced GC pressure.  The tracking data is used by the queue cache to walk the cache serving ordered\n    ///   queue messages by stream.\n    /// </summary>\n    public class CachedMessageBlock : PooledResource<CachedMessageBlock>\n    {\n        private const int OneKb = 1024;\n        private const int DefaultCachedMessagesPerBlock = 16 * OneKb; // 16kb\n\n        private readonly CachedMessage[] cachedMessages;\n        private readonly int blockSize;\n        private int writeIndex;\n        private int readIndex;\n\n        /// <summary>\n        /// Linked list node, so this message block can be kept in a linked list.\n        /// </summary>\n        public LinkedListNode<CachedMessageBlock> Node { get; private set; }\n\n        /// <summary>\n        /// Gets a value indicating whether more messages can be added to the block.\n        /// </summary>\n        public bool HasCapacity => writeIndex < blockSize;\n\n        /// <summary>\n        /// Gets a value indicating whether this block is empty.\n        /// </summary>\n        public bool IsEmpty => readIndex >= writeIndex;\n\n        /// <summary>\n        /// Gets the index of most recent message added to the block.\n        /// </summary>\n        public int NewestMessageIndex => writeIndex - 1;\n\n        /// <summary>\n        /// Gets the index of the oldest message in this block.\n        /// </summary>\n        public int OldestMessageIndex => readIndex;\n\n        /// <summary>\n        /// Gets the oldest message in the block.\n        /// </summary>\n        public CachedMessage OldestMessage => cachedMessages[OldestMessageIndex];\n\n        /// <summary>\n        /// Gets the newest message in this block.\n        /// </summary>\n        public CachedMessage NewestMessage => cachedMessages[NewestMessageIndex];\n\n        /// <summary>\n        /// Gets the number of messages in this block.\n        /// </summary>\n        public int ItemCount { get\n            {\n                int count = writeIndex - readIndex;\n                return count >= 0 ? count : 0;\n            }  \n        }\n\n        /// <summary>\n        /// Block of cached messages.\n        /// </summary>\n        /// <param name=\"blockSize\">The block size, expressed as a number of messages.</param>\n        public CachedMessageBlock(int blockSize = DefaultCachedMessagesPerBlock)\n        {\n            this.blockSize = blockSize;\n            cachedMessages = new CachedMessage[blockSize];\n            writeIndex = 0;\n            readIndex = 0;\n            Node = new LinkedListNode<CachedMessageBlock>(this);\n        }\n\n        /// <summary>\n        /// Removes a message from the start of the block (oldest data).\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if there are more items remaining; otherwise <see langword=\"false\"/>.</returns>\n        public bool Remove()\n        {\n            if (readIndex < writeIndex)\n            {\n                readIndex++;\n                return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Add a message from the queue to the block.\n        /// Converts the queue message to a cached message and stores it at the end of the block.\n        /// </summary>        \n        /// <param name=\"message\">\n        /// The message to add to this block.\n        /// </param>\n        public void Add(CachedMessage message)\n        {\n            if (!HasCapacity)\n            {\n                throw new InvalidOperationException(\"Block is full\");\n            }\n\n            int index = writeIndex++;\n            cachedMessages[index] = message;\n        }\n\n        /// <summary>\n        /// Access the cached message at the provided index.\n        /// </summary>\n        /// <param name=\"index\">The index to access.</param>\n        /// <returns>The message at the specified index.</returns>\n        public CachedMessage this[int index]\n        {\n            get\n            {\n                if (index >= writeIndex || index < readIndex)\n                {\n                    throw new ArgumentOutOfRangeException(nameof(index));\n                }\n                return cachedMessages[index];\n            }\n        }\n\n        /// <summary>\n        /// Gets the sequence token of the cached message a the provided index\n        /// </summary>\n        /// <param name=\"index\">The index of the message to access.</param>\n        /// <param name=\"dataAdapter\">The data adapter.</param>\n        /// <returns>The sequence token.</returns>\n        public StreamSequenceToken GetSequenceToken(int index, ICacheDataAdapter dataAdapter)\n        {\n            if (index >= writeIndex || index < readIndex)\n            {\n                throw new ArgumentOutOfRangeException(nameof(index));\n            }\n            return dataAdapter.GetSequenceToken(ref cachedMessages[index]);\n        }\n\n        /// <summary>\n        /// Gets the sequence token of the newest message in this block\n        /// </summary>\n        /// <param name=\"dataAdapter\">The data adapter.</param>\n        /// <returns>The sequence token of the newest message in this block.</returns>\n        public StreamSequenceToken GetNewestSequenceToken(ICacheDataAdapter dataAdapter)\n        {\n            return GetSequenceToken(NewestMessageIndex, dataAdapter);\n        }\n\n        /// <summary>\n        /// Gets the sequence token of the oldest message in this block\n        /// </summary>\n        /// <param name=\"dataAdapter\">The data adapter.</param>\n        /// <returns>The sequence token of the oldest message in this block.</returns>\n        public StreamSequenceToken GetOldestSequenceToken(ICacheDataAdapter dataAdapter)\n        {\n            return GetSequenceToken(OldestMessageIndex, dataAdapter);\n        }\n        \n        /// <summary>\n        /// Gets the index of the first message in this block that has a sequence token at or before the provided token\n        /// </summary>\n        /// <param name=\"token\">The sequence token.</param>\n        /// <returns>The index of the first message in this block that has a sequence token equal to or before the provided token.</returns>\n        public int GetIndexOfFirstMessageLessThanOrEqualTo(StreamSequenceToken token)\n        {\n            for (int i = writeIndex - 1; i >= readIndex; i--)\n            {\n                if (cachedMessages[i].Compare(token) <= 0)\n                {\n                    return i;\n                }\n            }\n            throw new ArgumentOutOfRangeException(nameof(token));\n        }\n\n        /// <summary>\n        /// Tries to find the first message in the block that is part of the provided stream.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"dataAdapter\">The data adapter.</param>\n        /// <param name=\"index\">The index.</param>\n        /// <returns><see langword=\"true\" /> if the message was found, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryFindFirstMessage(StreamId streamId, ICacheDataAdapter dataAdapter, out int index)\n        {\n            return TryFindNextMessage(readIndex, streamId, dataAdapter, out index);\n        }\n\n        /// <summary>\n        /// Tries to get the next message from the provided stream, starting at the start index.\n        /// </summary>        \n        /// <param name=\"start\">The start index.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"dataAdapter\">The data adapter.</param>\n        /// <param name=\"index\">The index.</param>\n        /// <returns><see langword=\"true\" /> if the message was found, <see langword=\"false\" /> otherwise.</returns>\n        public bool TryFindNextMessage(int start, StreamId streamId, ICacheDataAdapter dataAdapter, out int index)\n        {\n            if (start < readIndex)\n            {\n                throw new ArgumentOutOfRangeException(nameof(start));\n            }\n\n            for (int i = start; i < writeIndex; i++)\n            {\n                if (cachedMessages[i].CompareStreamId(streamId))\n                {\n                    index = i;\n                    return true;\n                }\n            }\n\n            index = writeIndex - 1;\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public override void OnResetState()\n        {\n            writeIndex = 0;\n            readIndex = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/CachedMessagePool.cs",
    "content": "\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Pool of tightly packed cached messages that are kept in large blocks to reduce GC pressure.\n    /// </summary>\n    internal class CachedMessagePool\n    {\n        private readonly IObjectPool<CachedMessageBlock> messagePool;\n        private CachedMessageBlock currentMessageBlock;\n\n        /// <summary>\n        /// Allocates a pool of cached message blocks.\n        /// </summary>\n        /// <param name=\"cacheDataAdapter\">The cache data adapter.</param>\n        public CachedMessagePool(ICacheDataAdapter cacheDataAdapter)\n        {\n            messagePool = new ObjectPool<CachedMessageBlock>(\n                () => new CachedMessageBlock());\n        }\n\n        /// <summary>\n        /// Allocates a message in a block and returns the block the message is in.\n        /// </summary>\n        /// <returns>The cached message block which the message was allocated in.</returns>\n        public CachedMessageBlock AllocateMessage(CachedMessage message)\n        {\n            CachedMessageBlock returnBlock = currentMessageBlock ?? (currentMessageBlock = messagePool.Allocate());\n            returnBlock.Add(message);\n\n            // blocks at capacity are eligable for purge, so we don't want to be holding on to them.\n            if (!currentMessageBlock.HasCapacity)\n            {\n                currentMessageBlock = messagePool.Allocate();\n            }\n\n            return returnBlock;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/ChronologicalEvictionStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Eviction strategy that evicts data based off of age.\n    /// </summary>\n    public partial class ChronologicalEvictionStrategy : IEvictionStrategy\n    {\n        private readonly ILogger logger;\n        private readonly TimePurgePredicate timePurge;\n\n        /// <summary>\n        /// Buffers which are currently in use in the cache\n        /// Protected for test purposes\n        /// </summary>\n        protected readonly Queue<FixedSizeBuffer> inUseBuffers;\n        private FixedSizeBuffer currentBuffer;\n        private readonly ICacheMonitor cacheMonitor;\n        private readonly PeriodicAction periodicMonitoring;\n        private long cacheSizeInByte;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChronologicalEvictionStrategy\"/> class.\n        /// </summary>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"timePurage\">The time-based purge predicate.</param>\n        /// <param name=\"cacheMonitor\">The cache monitor.</param>\n        /// <param name=\"monitorWriteInterval\">\"Interval to write periodic statistics. Only triggered for active caches.</param>\n        public ChronologicalEvictionStrategy(ILogger logger, TimePurgePredicate timePurage, ICacheMonitor cacheMonitor, TimeSpan? monitorWriteInterval)\n        {\n            if (logger == null) throw new ArgumentException(nameof(logger));\n            if (timePurage == null) throw new ArgumentException(nameof(timePurage));\n            this.logger = logger;\n            this.timePurge = timePurage;\n            this.inUseBuffers = new Queue<FixedSizeBuffer>();\n\n            // monitoring\n            this.cacheMonitor = cacheMonitor;\n            if (this.cacheMonitor != null && monitorWriteInterval.HasValue)\n            {\n                this.periodicMonitoring = new PeriodicAction(monitorWriteInterval.Value, this.ReportCacheSize);\n            }\n\n            this.cacheSizeInByte = 0;\n        }\n\n        private void ReportCacheSize()\n        {\n            this.cacheMonitor.ReportCacheSize(this.cacheSizeInByte);\n        }\n\n        /// <inheritdoc />\n        public IPurgeObservable PurgeObservable { private get; set; }\n\n        /// <inheritdoc />\n        public Action<CachedMessage?, CachedMessage?> OnPurged { get; set; }\n\n        /// <inheritdoc />\n        public void OnBlockAllocated(FixedSizeBuffer newBlock)\n        {\n            if (this.PurgeObservable.IsEmpty && this.currentBuffer != null\n                && this.inUseBuffers.Contains(this.currentBuffer) && this.inUseBuffers.Count == 1)\n            {\n                this.inUseBuffers.Dequeue().Dispose();\n            }\n            this.inUseBuffers.Enqueue(newBlock);\n            this.currentBuffer = newBlock;\n            //report metrics\n            this.cacheSizeInByte += newBlock.SizeInByte;\n            this.cacheMonitor?.TrackMemoryAllocated(newBlock.SizeInByte);\n        }\n\n        /// <inheritdoc />\n        public void PerformPurge(DateTime nowUtc)\n        {\n            PerformPurgeInternal(nowUtc);\n            this.periodicMonitoring?.TryAction(nowUtc);\n        }\n\n        /// <summary>\n        /// Given a cached message, indicates whether it should be purged from the cache.\n        /// </summary>\n        /// <param name=\"cachedMessage\">The cached message.</param>\n        /// <param name=\"newestCachedMessage\">The newest cached message.</param>\n        /// <param name=\"nowUtc\">The current time (UTC).</param>\n        /// <returns><see langword=\"true\" /> if the message should be purged, <see langword=\"false\" /> otherwise.</returns>\n        protected virtual bool ShouldPurge(ref CachedMessage cachedMessage, ref CachedMessage newestCachedMessage, DateTime nowUtc)\n        {\n            TimeSpan timeInCache = nowUtc - cachedMessage.DequeueTimeUtc;\n            // age of message relative to the most recent event in the cache.\n            TimeSpan relativeAge = newestCachedMessage.EnqueueTimeUtc - cachedMessage.EnqueueTimeUtc;\n\n            return timePurge.ShouldPurgeFromTime(timeInCache, relativeAge);\n        }\n\n        private void PerformPurgeInternal(DateTime nowUtc)\n        {\n            //if the cache is empty, then nothing to purge, return\n            if (this.PurgeObservable.IsEmpty)\n                return;\n            int itemsPurged = 0;\n            CachedMessage neweswtMessageInCache = this.PurgeObservable.Newest.Value;\n            CachedMessage? lastMessagePurged = null;\n            while (!this.PurgeObservable.IsEmpty)\n            {\n                var oldestMessageInCache = this.PurgeObservable.Oldest.Value;\n                if (!ShouldPurge(ref oldestMessageInCache, ref neweswtMessageInCache, nowUtc))\n                {\n                    break;\n                }\n                lastMessagePurged = oldestMessageInCache;\n                itemsPurged++;\n                this.PurgeObservable.RemoveOldestMessage();\n            }\n            //if nothing got purged, return\n            if (itemsPurged == 0)\n                return;\n\n            //items got purged, time to conduct follow up actions\n            this.cacheMonitor?.TrackMessagesPurged(itemsPurged);\n            OnPurged?.Invoke(lastMessagePurged, this.PurgeObservable.Newest);\n            FreePurgedBuffers(lastMessagePurged, this.PurgeObservable.Oldest);\n            ReportPurge(this.logger, this.PurgeObservable, itemsPurged);\n        }\n\n        private void FreePurgedBuffers(CachedMessage? lastMessagePurged, CachedMessage? oldestMessageInCache)\n        {\n            if (this.inUseBuffers.Count <= 0 || !lastMessagePurged.HasValue)\n                return;\n            int memoryReleasedInByte = 0;\n            object IdOfLastPurgedBufferId = lastMessagePurged?.Segment.Array;\n            // IdOfLastBufferInCache will be null if cache is empty after purge\n            object IdOfLastBufferInCacheId = oldestMessageInCache?.Segment.Array;\n            //all buffers older than LastPurgedBuffer should be purged\n            while (this.inUseBuffers.Peek().Id != IdOfLastPurgedBufferId)\n            {\n                var purgedBuffer = this.inUseBuffers.Dequeue();\n                memoryReleasedInByte += purgedBuffer.SizeInByte;\n                purgedBuffer.Dispose();\n            }\n            // if last purged message does not share buffer with remaining messages in cache and cache is not empty\n            //then last purged buffer should be purged too\n            if (IdOfLastBufferInCacheId != null && IdOfLastPurgedBufferId != IdOfLastBufferInCacheId)\n            {\n                var purgedBuffer = this.inUseBuffers.Dequeue();\n                memoryReleasedInByte += purgedBuffer.SizeInByte;\n                purgedBuffer.Dispose();\n            }\n            //report metrics\n            if (memoryReleasedInByte > 0)\n            {\n                this.cacheSizeInByte -= memoryReleasedInByte;\n                this.cacheMonitor?.TrackMemoryReleased(memoryReleasedInByte);\n            }\n        }\n\n        /// <summary>\n        /// Logs cache purge activity\n        /// </summary>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"purgeObservable\">The purge observable.</param>\n        /// <param name=\"itemsPurged\">The items purged.</param>\n        private static void ReportPurge(ILogger logger, IPurgeObservable purgeObservable, int itemsPurged)\n        {\n            if (!logger.IsEnabled(LogLevel.Debug))\n                return;\n            int itemCountAfterPurge = purgeObservable.ItemCount;\n            var itemCountBeforePurge = itemCountAfterPurge + itemsPurged;\n            if (itemCountAfterPurge == 0)\n            {\n                LogBlockPurgedCacheEmpty(logger);\n            }\n            else\n            {\n                LogBlockPurged(logger, itemCountBeforePurge - itemCountAfterPurge, itemCountAfterPurge);\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BlockPurged: cache empty\"\n        )]\n        private static partial void LogBlockPurgedCacheEmpty(ILogger logger);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BlockPurged: PurgeCount: {PurgeCount}, CacheSize: {ItemCountAfterPurge}\"\n        )]\n        private static partial void LogBlockPurged(ILogger logger, int purgeCount, int itemCountAfterPurge);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/FixedSizeBuffer.cs",
    "content": "\nusing System;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Manages a contiguous block of memory.\n    /// Calls purge action with itself as the purge request when it's signaled to purge.\n    /// </summary>\n    public class FixedSizeBuffer : PooledResource<FixedSizeBuffer>\n    {\n        private readonly byte[] buffer;\n        private int count;\n\n        /// <summary>\n        /// Buffer size in bytes.\n        /// </summary>\n        public readonly int SizeInByte;\n\n        /// <summary>\n        /// Unique identifier of this buffer.\n        /// </summary>\n        public object Id => buffer;\n\n        /// <summary>\n        /// Manages access to a fixed size byte buffer.\n        /// </summary>\n        /// <param name=\"blockSizeInByte\">The block size, in bytes.</param>\n        public FixedSizeBuffer(int blockSizeInByte)\n        {\n            if (blockSizeInByte < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(blockSizeInByte), \"blockSize must be positive value.\");\n            }\n            count = 0;\n            this.SizeInByte = blockSizeInByte;\n            buffer = new byte[this.SizeInByte];\n        }\n\n        /// <summary>\n        /// Try to get a segment with a buffer of the specified size from this block.\n        /// Fail if there is not enough space available\n        /// </summary>\n        /// <param name=\"size\">The size.</param>\n        /// <param name=\"value\">The segment.</param>\n        /// <returns><see langword=\"true\"/> if the segment was retrieved; otherwise <see langword=\"false\"/>.</returns>\n        public bool TryGetSegment(int size, out ArraySegment<byte> value)\n        {\n            value = default;\n            if (size > this.SizeInByte - count)\n            {\n                return false;\n            }\n            value = new ArraySegment<byte>(buffer, count, size);\n            count += size;\n            return true;\n        }\n\n        /// <inheritdoc />\n        public override void OnResetState()\n        {\n            count = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/ICacheDataAdapter.cs",
    "content": "using Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Pooled queue cache stores data in tightly packed structures that need to be transformed to various\n    ///   other formats quickly.  Since the data formats may change by queue type and data format,\n    ///   this interface allows adapter developers to build custom data transforms appropriate for \n    ///   the various types of queue data.\n    /// </summary>\n    public interface ICacheDataAdapter\n    {\n        /// <summary>\n        /// Converts a cached message to a batch container for delivery\n        /// </summary>\n        /// <param name=\"cachedMessage\">The cached message.</param>\n        /// <returns>The batch container.</returns>\n        IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage);\n\n        /// <summary>\n        /// Gets the stream sequence token from a cached message.\n        /// </summary>\n        /// <param name=\"cachedMessage\">The cached message.</param>\n        /// <returns>The sequence token.</returns>\n        StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/IEvictionStrategy.cs",
    "content": "using System;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Eviction strategy for the PooledQueueCache\n    /// </summary>\n    public interface IEvictionStrategy\n    {\n        /// <summary>\n        /// Gets the <see cref=\"IPurgeObservable\"/>, which is implemented by the cache to do purge related actions and invoked by the eviction strategy.\n        /// </summary>\n        IPurgeObservable PurgeObservable { set; }\n\n        /// <summary>\n        /// Gets or sets the method which will be called when purge is finished.\n        /// </summary>\n        Action<CachedMessage?, CachedMessage?> OnPurged { get; set; }\n\n        /// <summary>\n        /// Method which should be called when pulling agent try to do a purge on the cache\n        /// </summary>\n        /// <param name=\"utcNow\">The current time (UTC)</param>\n        void PerformPurge(DateTime utcNow);\n\n        /// <summary>\n        /// Method which should be called when data adapter allocated a new block\n        /// </summary>\n        /// <param name=\"newBlock\">The new block.</param>\n        void OnBlockAllocated(FixedSizeBuffer newBlock);\n    }\n\n    /// <summary>\n    /// Functionality for purge-related actions.\n    /// </summary>\n    public interface IPurgeObservable\n    {\n        /// <summary>\n        /// Removes oldest message in the cache.\n        /// </summary>\n        void RemoveOldestMessage();\n\n        /// <summary>\n        /// Gets the newest message in the cache.\n        /// </summary>\n        CachedMessage? Newest { get; }\n\n        /// <summary>\n        /// Gets the oldest message in the cache.\n        /// </summary>\n        CachedMessage? Oldest { get; }\n\n        /// <summary>\n        /// Gets the message count.\n        /// </summary>\n        int ItemCount { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is empty.\n        /// </summary>\n        bool IsEmpty { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/IObjectPool.cs",
    "content": "\nusing System;\nusing System.Threading;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Simple object pool Interface.\n    /// Objects allocated should be returned to the pool when disposed.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface IObjectPool<T>\n        where T : IDisposable\n    {\n        /// <summary>\n        /// Allocates a pooled resource\n        /// </summary>\n        /// <returns></returns>\n        T Allocate();\n\n        /// <summary>\n        /// Returns a resource to the pool\n        /// </summary>\n        /// <param name=\"resource\"></param>\n        void Free(T resource);\n    }\n\n    /// <summary>\n    /// Utility class to support pooled objects by allowing them to track the pool they came from and return to it when disposed\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public abstract class PooledResource<T> : IDisposable\n        where T : PooledResource<T>, IDisposable\n    {\n        private IObjectPool<T> pool;\n\n        /// <summary>\n        /// Gets the pool to return this resource to upon disposal.\n        /// A pool must set this property upon resource allocation.\n        /// </summary>\n        public IObjectPool<T> Pool { set { pool = value; } }\n\n        /// <summary>\n        /// If this object is to be used in a fixed size object pool, this call should be\n        ///   overridden with the purge implementation that returns the object to the pool.\n        /// </summary>\n        public virtual void SignalPurge()\n        {\n            Dispose();\n        }\n\n        /// <summary>\n        /// Returns item to pool.\n        /// </summary>\n        public void Dispose()\n        {\n            IObjectPool<T> localPool = Interlocked.Exchange(ref pool, null);\n            if (localPool != null)\n            {\n                OnResetState();\n                localPool.Free((T)this);\n            }\n        }\n\n        /// <summary>\n        /// Notifies the object that it has been purged, so it can reset itself to\n        ///   the state of a newly allocated object.\n        /// </summary>\n        public virtual void OnResetState()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/ObjectPool.cs",
    "content": "\nusing System;\nusing System.Threading;\nusing System.Collections.Concurrent;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Simple object pool that uses a stack to store available objects.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public class ObjectPool<T> : IObjectPool<T>\n        where T : PooledResource<T>\n    {\n        private const int DefaultPoolCapacity = 1 << 10; // 1k\n        private readonly ConcurrentStack<T> pool;\n        private readonly Func<T> factoryFunc;\n        private long totalObjects;\n\n        /// <summary>\n        /// monitor to report statistics for current object pool\n        /// </summary>\n        private readonly IObjectPoolMonitor monitor;\n        private readonly PeriodicAction periodicMonitoring;\n\n        /// <summary>\n        /// Simple object pool\n        /// </summary>\n        /// <param name=\"factoryFunc\">Function used to create new resources of type T</param>\n        /// <param name=\"monitor\">monitor to report statistics for object pool</param>\n        /// <param name=\"monitorWriteInterval\"></param>\n        public ObjectPool(Func<T> factoryFunc, IObjectPoolMonitor monitor = null, TimeSpan? monitorWriteInterval = null)\n        {\n            if (factoryFunc == null)\n            {\n                throw new ArgumentNullException(nameof(factoryFunc));\n            }\n\n            this.factoryFunc = factoryFunc;\n            pool = new ConcurrentStack<T>();\n\n            // monitoring\n            this.monitor = monitor;\n            if (this.monitor != null && monitorWriteInterval.HasValue)\n            {\n                this.periodicMonitoring = new PeriodicAction(monitorWriteInterval.Value, this.ReportObjectPoolStatistics);\n            }\n\n            this.totalObjects = 0;\n        }\n\n        /// <summary>\n        /// Allocates a pooled resource\n        /// </summary>\n        /// <returns></returns>\n        public virtual T Allocate()\n        {\n            T resource;\n            //if couldn't pop a resource from the pool, create a new resource using factoryFunc from outside of the pool\n            if (!pool.TryPop(out resource))\n            {\n                resource = factoryFunc();\n                Interlocked.Increment(ref this.totalObjects);\n            }\n            this.monitor?.TrackObjectAllocated();\n            this.periodicMonitoring?.TryAction(DateTime.UtcNow);\n            resource.Pool = this;\n            return resource;\n        }\n\n        /// <summary>\n        /// Returns a resource to the pool\n        /// </summary>\n        /// <param name=\"resource\"></param>\n        public virtual void Free(T resource)\n        {\n            this.monitor?.TrackObjectReleased();\n            this.periodicMonitoring?.TryAction(DateTime.UtcNow);\n            pool.Push(resource);\n        }\n\n        private void ReportObjectPoolStatistics()\n        {\n            var availableObjects = this.pool.Count;\n            long claimedObjects = this.totalObjects - availableObjects;\n            this.monitor.Report(this.totalObjects, availableObjects, claimedObjects);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/PooledQueueCache.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// The PooledQueueCache is a cache that is intended to serve as a message cache in an IQueueCache.\n    /// It is capable of storing large numbers of messages (gigs worth of messages) for extended periods\n    ///   of time (minutes to indefinite), while incurring a minimal performance hit due to garbage collection.\n    /// This pooled cache allocates memory and never releases it. It keeps freed resources available in pools \n    ///   that remain in application use through the life of the service. This means these objects go to gen2,\n    ///   are compacted, and then stay there. This is relatively cheap, as the only cost they now incur is\n    ///   the cost of checking to see if they should be freed in each collection cycle. Since this cache uses\n    ///   small numbers of large objects with relatively simple object graphs, they are less costly to check\n    ///   then large numbers of smaller objects with more complex object graphs.\n    /// For performance reasons this cache is designed to more closely align with queue specific data.  This is,\n    ///   in part, why, unlike the SimpleQueueCache, this cache does not implement IQueueCache.  It is intended\n    ///   to be used in queue specific implementations of IQueueCache.\n    /// </summary>\n    public class PooledQueueCache: IPurgeObservable\n    {\n        // linked list of message bocks.  First is newest.\n        private readonly LinkedList<CachedMessageBlock> messageBlocks;\n        private readonly CachedMessagePool pool;\n        private readonly ICacheDataAdapter cacheDataAdapter;\n        private readonly ILogger logger;\n        private readonly ICacheMonitor cacheMonitor;\n        private readonly TimeSpan purgeMetadataInterval;\n        private readonly PeriodicAction periodicMonitoring;\n        private readonly PeriodicAction periodicMetadaPurging;\n\n        private readonly Dictionary<StreamId, (DateTime TimeStamp, StreamSequenceToken Token)> lastPurgedToken = new Dictionary<StreamId, (DateTime TimeStamp, StreamSequenceToken Token)>();\n\n        /// <summary>\n        /// Gets the cached message most recently added.\n        /// </summary>\n        public CachedMessage? Newest\n        {\n            get\n            {\n                if (IsEmpty)\n                    return null;\n                return messageBlocks.First.Value.NewestMessage;\n            }\n        }\n\n        /// <summary>\n        /// Gets the oldest message in cache.\n        /// </summary>\n        public CachedMessage? Oldest\n        {\n            get\n            {\n                if (IsEmpty)\n                    return null;\n                return messageBlocks.Last.Value.OldestMessage;\n            }\n        }\n\n        /// <summary>\n        /// Gets the cached message count.\n        /// </summary>\n        public int ItemCount { get; private set; }\n\n        /// <summary>\n        /// Pooled queue cache is a cache of message that obtains resource from a pool\n        /// </summary>\n        /// <param name=\"cacheDataAdapter\">The cache data adapter.</param>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"cacheMonitor\">The cache monitor.</param>\n        /// <param name=\"cacheMonitorWriteInterval\">The cache monitor write interval. Only triggered for active caches.</param>\n        /// <param name=\"purgeMetadataInterval\">The interval after which to purge cache metadata.</param>\n        public PooledQueueCache(\n            ICacheDataAdapter cacheDataAdapter,\n            ILogger logger,\n            ICacheMonitor cacheMonitor,\n            TimeSpan? cacheMonitorWriteInterval,\n            TimeSpan? purgeMetadataInterval = null)\n        {\n            this.cacheDataAdapter = cacheDataAdapter ?? throw new ArgumentNullException(nameof(cacheDataAdapter));\n            this.logger = logger ?? throw new ArgumentNullException(nameof(logger));\n            this.ItemCount = 0;\n            pool = new CachedMessagePool(cacheDataAdapter);\n            messageBlocks = new LinkedList<CachedMessageBlock>();\n            this.cacheMonitor = cacheMonitor;\n            if (this.cacheMonitor != null && cacheMonitorWriteInterval.HasValue)\n            {\n                this.periodicMonitoring = new PeriodicAction(cacheMonitorWriteInterval.Value, this.ReportCacheMessageStatistics);\n            }\n\n            if (purgeMetadataInterval.HasValue)\n            {\n                this.purgeMetadataInterval = purgeMetadataInterval.Value;\n                this.periodicMetadaPurging = new PeriodicAction(purgeMetadataInterval.Value.Divide(5), this.PurgeMetadata);\n            }\n        }\n\n        /// <summary>\n        /// Indicates whether the cache is empty\n        /// </summary>\n        public bool IsEmpty => messageBlocks.Count == 0 || (messageBlocks.Count == 1 && messageBlocks.First.Value.IsEmpty);\n\n        /// <summary>\n        /// Acquires a cursor to enumerate through the messages in the cache at the provided sequenceToken, \n        ///   filtered on the specified stream.\n        /// </summary>\n        /// <param name=\"streamId\">stream identity</param>\n        /// <param name=\"sequenceToken\"></param>\n        /// <returns></returns>\n        public object GetCursor(StreamId streamId, StreamSequenceToken sequenceToken)\n        {\n            var cursor = new Cursor(streamId);\n            SetCursor(cursor, sequenceToken);\n            return cursor;\n        }\n\n        private void ReportCacheMessageStatistics()\n        {\n            if (this.IsEmpty)\n            {\n                this.cacheMonitor.ReportMessageStatistics(null, null, null, this.ItemCount);\n            }\n            else\n            {\n                var newestMessage = this.Newest.Value;\n                var oldestMessage = this.Oldest.Value;\n                var newestMessageEnqueueTime = newestMessage.EnqueueTimeUtc;\n                var oldestMessageEnqueueTime = oldestMessage.EnqueueTimeUtc;\n                var oldestMessageDequeueTime = oldestMessage.DequeueTimeUtc;\n                this.cacheMonitor.ReportMessageStatistics(oldestMessageEnqueueTime, oldestMessageDequeueTime, newestMessageEnqueueTime, this.ItemCount);\n            }\n        }\n\n        private void PurgeMetadata()\n        {\n            var now = DateTime.UtcNow;\n\n            // Get all keys older than this.purgeMetadataInterval\n            foreach (var kvp in this.lastPurgedToken)\n            {\n                if (kvp.Value.TimeStamp + this.purgeMetadataInterval < now)\n                {\n                    lastPurgedToken.Remove(kvp.Key);\n                }\n            }\n        }\n\n        private void TrackAndPurgeMetadata(CachedMessage messageToRemove)\n        {\n            // If tracking of evicted message metadata is disabled, do nothing\n            if (this.periodicMetadaPurging == null)\n                return;\n\n            var now = DateTime.UtcNow;\n            var streamId = messageToRemove.StreamId;\n            var token = this.cacheDataAdapter.GetSequenceToken(ref messageToRemove);\n            this.lastPurgedToken[streamId] = (now, token);\n\n            this.periodicMetadaPurging.TryAction(now);\n        }\n\n        private void SetCursor(Cursor cursor, StreamSequenceToken sequenceToken)\n        {\n            // If nothing in cache, unset token, and wait for more data.\n            if (messageBlocks.Count == 0)\n            {\n                cursor.State = CursorStates.Unset;\n                cursor.SequenceToken = sequenceToken;\n                return;\n            }\n\n            LinkedListNode<CachedMessageBlock> newestBlock = messageBlocks.First;\n\n            // if sequenceToken is null, iterate from newest message in cache\n            if (sequenceToken == null)\n            {\n                cursor.State = CursorStates.Idle;\n                cursor.CurrentBlock = newestBlock;\n                cursor.Index = newestBlock.Value.NewestMessageIndex;\n                cursor.SequenceToken = newestBlock.Value.GetNewestSequenceToken(cacheDataAdapter);\n                return;\n            }\n\n            // If sequenceToken is too new to be in cache, unset token, and wait for more data.\n            CachedMessage newestMessage = newestBlock.Value.NewestMessage;\n            if (newestMessage.Compare(sequenceToken) < 0) \n            {\n                cursor.State = CursorStates.Unset;\n                cursor.SequenceToken = sequenceToken;\n                return;\n            }\n\n            // Check to see if sequenceToken is too old to be in cache\n            var oldestBlock = messageBlocks.Last;\n            var oldestMessage = oldestBlock.Value.OldestMessage;\n            if (oldestMessage.Compare(sequenceToken) > 0)\n            {\n                // Check if we missed an event since we last purged the cache\n                if (this.lastPurgedToken.TryGetValue(cursor.StreamId, out var entry) && sequenceToken.CompareTo(entry.Token) >= 0)\n                {\n                    // If the token is more recent than the last purged token, then we didn't lose anything. Start from the oldest message in cache\n                    cursor.State = CursorStates.Set;\n                    cursor.CurrentBlock = oldestBlock;\n                    cursor.Index = oldestBlock.Value.OldestMessageIndex;\n                    cursor.SequenceToken = oldestBlock.Value.GetOldestSequenceToken(cacheDataAdapter);\n                    return;\n                }\n                else\n                {\n                    throw new QueueCacheMissException(sequenceToken,\n                        messageBlocks.Last.Value.GetOldestSequenceToken(cacheDataAdapter),\n                        messageBlocks.First.Value.GetNewestSequenceToken(cacheDataAdapter));\n                }\n            }\n\n            // Find block containing sequence number, starting from the newest and working back to oldest\n            LinkedListNode<CachedMessageBlock> node = messageBlocks.First;\n            while (true)\n            {\n                CachedMessage oldestMessageInBlock = node.Value.OldestMessage;\n                if (oldestMessageInBlock.Compare(sequenceToken) <= 0)\n                {\n                    break;\n                }\n                node = node.Next;\n            }\n\n            // return cursor from start.\n            cursor.CurrentBlock = node;\n            cursor.Index = node.Value.GetIndexOfFirstMessageLessThanOrEqualTo(sequenceToken);\n            // if cursor has been idle, move to next message after message specified by sequenceToken  \n            if(cursor.State == CursorStates.Idle)\n            {\n                // if there are more messages in this block, move to next message\n                if (!cursor.IsNewestInBlock)\n                {\n                    cursor.Index++;\n                }\n                // if this is the newest message in this block, move to oldest message in newer block\n                else if (node.Previous != null)\n                {\n                    cursor.CurrentBlock = node.Previous;\n                    cursor.Index = cursor.CurrentBlock.Value.OldestMessageIndex;\n                }\n                else\n                {\n                    cursor.State = CursorStates.Idle;\n                    return;\n                }\n            }\n            cursor.SequenceToken = cursor.CurrentBlock.Value.GetSequenceToken(cursor.Index, cacheDataAdapter);\n            cursor.State = CursorStates.Set;\n        }\n\n        /// <summary>\n        /// Acquires the next message in the cache at the provided cursor\n        /// </summary>\n        /// <param name=\"cursorObj\"></param>\n        /// <param name=\"message\"></param>\n        /// <returns></returns>\n        public bool TryGetNextMessage(object cursorObj, out IBatchContainer message)\n        {\n            message = null;\n\n            if (cursorObj == null)\n            {\n                throw new ArgumentNullException(nameof(cursorObj));\n            }\n\n            var cursor = cursorObj as Cursor;\n            if (cursor == null)\n            {\n                throw new ArgumentOutOfRangeException(nameof(cursorObj), \"Cursor is bad\");\n            }\n\n            if (cursor.State != CursorStates.Set)\n            {\n                SetCursor(cursor, cursor.SequenceToken);\n                if (cursor.State != CursorStates.Set)\n                {\n                    return false;\n                }\n            }\n\n            // has this message been purged\n            CachedMessage oldestMessage = messageBlocks.Last.Value.OldestMessage;\n            if (oldestMessage.Compare(cursor.SequenceToken) > 0)\n            {\n                throw new QueueCacheMissException(cursor.SequenceToken,\n                    messageBlocks.Last.Value.GetOldestSequenceToken(cacheDataAdapter),\n                    messageBlocks.First.Value.GetNewestSequenceToken(cacheDataAdapter));\n            }\n\n            // Iterate forward (in time) in the cache until we find a message on the stream or run out of cached messages.\n            // Note that we get the message from the current cursor location, then move it forward.  This means that if we return true, the cursor\n            //   will point to the next message after the one we're returning.\n            while (cursor.State == CursorStates.Set)\n            {\n                CachedMessage currentMessage = cursor.Message;\n\n                // Have we caught up to the newest event, if so set cursor to idle.\n                if (cursor.CurrentBlock == messageBlocks.First && cursor.IsNewestInBlock)\n                {\n                    cursor.State = CursorStates.Idle;\n                    cursor.SequenceToken = messageBlocks.First.Value.GetNewestSequenceToken(cacheDataAdapter);\n                }\n                else // move to next\n                {\n                    int index;\n                    if (cursor.IsNewestInBlock)\n                    {\n                        cursor.CurrentBlock = cursor.CurrentBlock.Previous;\n                        cursor.CurrentBlock.Value.TryFindFirstMessage(cursor.StreamId, this.cacheDataAdapter, out index);\n                    }\n                    else\n                    {\n                        cursor.CurrentBlock.Value.TryFindNextMessage(cursor.Index + 1, cursor.StreamId, this.cacheDataAdapter, out index);\n                    }\n                    cursor.Index = index;\n                }\n\n                // check if this message is in the cursor's stream\n                if (currentMessage.CompareStreamId(cursor.StreamId))\n                {\n                    message = cacheDataAdapter.GetBatchContainer(ref currentMessage);\n                    cursor.SequenceToken = cursor.CurrentBlock.Value.GetSequenceToken(cursor.Index, cacheDataAdapter);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Add a list of queue message to the cache \n        /// </summary>\n        /// <param name=\"messages\"></param>\n        /// <param name=\"dequeueTime\"></param>\n        /// <returns></returns>\n        public void Add(List<CachedMessage> messages, DateTime dequeueTime)\n        {\n            foreach (var message in messages)\n            {\n                this.Add(message);\n            }\n            this.cacheMonitor?.TrackMessagesAdded(messages.Count);\n            periodicMonitoring?.TryAction(dequeueTime);\n        }\n\n        private void Add(CachedMessage message)\n        {\n            // allocate message from pool\n            CachedMessageBlock block = pool.AllocateMessage(message);\n\n            // If new block, add message block to linked list\n            if (block != messageBlocks.FirstOrDefault())\n                messageBlocks.AddFirst(block.Node);\n            ItemCount++;\n        }\n\n        /// <summary>\n        /// Remove oldest message in the cache, remove oldest block too if the block is empty\n        /// </summary>\n        public void RemoveOldestMessage()\n        {\n            TrackAndPurgeMetadata(this.messageBlocks.Last.Value.OldestMessage);\n\n            this.messageBlocks.Last.Value.Remove();\n            this.ItemCount--;\n            CachedMessageBlock lastCachedMessageBlock = this.messageBlocks.Last.Value;\n            // if block is currently empty, but all capacity has been exausted, remove\n            if (lastCachedMessageBlock.IsEmpty && !lastCachedMessageBlock.HasCapacity)\n            {\n                lastCachedMessageBlock.Dispose();\n                this.messageBlocks.RemoveLast();\n            }\n        }\n\n        private enum CursorStates\n        {\n            Unset, // Not yet set, or points to some data in the future.\n            Set, // Points to a message in the cache\n            Idle, // Has iterated over all relevant events in the cache and is waiting for more data on the stream.\n        }\n\n        private class Cursor\n        {\n            public readonly StreamId StreamId;\n\n            public Cursor(StreamId streamId)\n            {\n                StreamId = streamId;\n                State = CursorStates.Unset;\n            }\n\n            public CursorStates State;\n\n            // current sequence token\n            public StreamSequenceToken SequenceToken;\n\n            // reference into cache\n            public LinkedListNode<CachedMessageBlock> CurrentBlock;\n            public int Index;\n\n            // utilities\n            public bool IsNewestInBlock => Index == CurrentBlock.Value.NewestMessageIndex;\n            public CachedMessage Message => CurrentBlock.Value[Index];\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/PooledCache/TimePurgePredicate.cs",
    "content": "\nusing System;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Determines if data should be purged based off time.\n    /// </summary>\n    public class TimePurgePredicate\n    {\n        private readonly TimeSpan minTimeInCache;\n        private readonly TimeSpan maxRelativeMessageAge;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"TimePurgePredicate\"/> class.\n        /// </summary>\n        /// <param name=\"minTimeInCache\">The minimum time data should be kept in cache, unless purged due to data size.</param>\n        /// <param name=\"maxRelativeMessageAge\">The maximum age of data to keep in the cache.</param>\n        public TimePurgePredicate(TimeSpan minTimeInCache, TimeSpan maxRelativeMessageAge)\n        {\n            this.minTimeInCache = minTimeInCache;\n            this.maxRelativeMessageAge = maxRelativeMessageAge;\n        }\n\n        /// <summary>\n        /// Checks to see if the message should be purged.\n        /// Message should be purged if its relative age is greater than <c>maxRelativeMessageAge</c> and has been in the cache longer than the minTimeInCache.\n        /// </summary>\n        /// <param name=\"timeInCache\">The amount of time message has been in this cache</param>\n        /// <param name=\"relativeAge\">The age of message relative to the most recent events read</param>\n        /// <returns><see langword=\"true\"/> if the message should be purged; otherwise <see langword=\"false\"/>.</returns>\n        public virtual bool ShouldPurgeFromTime(TimeSpan timeInCache, TimeSpan relativeAge)\n        {\n            // if time in cache exceeds the minimum and age of data is greater than max allowed, purge\n            return timeInCache > minTimeInCache && relativeAge > maxRelativeMessageAge;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/RecoverableStreamConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo-specific configuration builder for recoverable streams.\n    /// </summary>\n    public interface ISiloRecoverableStreamConfigurator : ISiloPersistentStreamConfigurator {}\n\n    /// <summary>\n    /// Extension methods for <see cref=\"ISiloRecoverableStreamConfigurator\"/>.\n    /// </summary>\n    public static class SiloRecoverableStreamConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures statistics options for a reliable stream provider.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigureStatistics(this ISiloRecoverableStreamConfigurator configurator, Action<OptionsBuilder<StreamStatisticOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        /// <summary>\n        /// Configures cache eviction options for a reliable stream provider.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigureCacheEviction(this ISiloRecoverableStreamConfigurator configurator, Action<OptionsBuilder<StreamCacheEvictionOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n    }\n\n    /// <summary>\n    /// Configures reliable streams.\n    /// </summary>\n    public class SiloRecoverableStreamConfigurator : SiloPersistentStreamConfigurator, ISiloRecoverableStreamConfigurator\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloRecoverableStreamConfigurator\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configureDelegate\">The configuration delegate.</param>\n        /// <param name=\"adapterFactory\">The adapter factory.</param>\n        public SiloRecoverableStreamConfigurator(\n            string name,\n            Action<Action<IServiceCollection>> configureDelegate,\n            Func<IServiceProvider, string, IQueueAdapterFactory> adapterFactory)\n            : base(name, configureDelegate, adapterFactory)\n        {\n            this.ConfigureDelegate(services => services\n                .ConfigureNamedOptionForLogging<StreamStatisticOptions>(name)\n                .ConfigureNamedOptionForLogging<StreamCacheEvictionOptions>(name));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/RecoverableStreamOptions.cs",
    "content": "using System;\nusing Orleans.Streams;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration options for stream cache eviction.\n    /// </summary>\n    public class StreamCacheEvictionOptions\n    {\n        /// <summary>\n        /// Gets or sets the minimum time a message will stay in cache before it is available for time based purge.\n        /// </summary>\n        public TimeSpan DataMinTimeInCache { get; set; } = DefaultDataMinTimeInCache;\n\n        /// <summary>\n        /// The default value for <see cref=\"DataMinTimeInCache\"/>.\n        /// </summary>\n        public static readonly TimeSpan DefaultDataMinTimeInCache = TimeSpan.FromMinutes(5);\n\n        /// <summary>\n        /// Gets or sets the difference in time between the newest and oldest messages in the cache.  Any messages older than this will be purged from the cache.\n        /// </summary>\n        public TimeSpan DataMaxAgeInCache { get; set; } = DefaultDataMaxAgeInCache;\n\n        /// <summary>\n        /// The default value for <see cref=\"DataMaxAgeInCache\"/>\n        /// </summary>\n        public static readonly TimeSpan DefaultDataMaxAgeInCache = TimeSpan.FromMinutes(30);\n\n        /// <summary>\n        /// Gets or sets the minimum time that message metadata (<see cref=\"StreamSequenceToken\"/>) will stay in cache before it is available for time based purge.\n        /// Used to avoid cache miss if the full message was purged.\n        /// Set to <see langword=\"null\"/> to disable this tracking.\n        /// </summary>\n        public TimeSpan? MetadataMinTimeInCache { get; set; } = DefaultMetadataMinTimeInCache;\n\n        /// <summary>\n        /// The default value for <see cref=\"MetadataMinTimeInCache\"/>.\n        /// </summary>\n        public static readonly TimeSpan DefaultMetadataMinTimeInCache = DefaultDataMinTimeInCache.Multiply(2);\n    }\n\n    /// <summary>\n    /// Configuration options for stream statistics.\n    /// </summary>\n    public class StreamStatisticOptions\n    {\n        /// <summary>\n        /// Gets or sets the statistic monitor write interval.\n        /// Statistics generation is triggered by activity. Interval will be ignored when streams are inactive.\n        /// </summary>\n        public TimeSpan StatisticMonitorWriteInterval { get; set; } = DefaultStatisticMonitorWriteInterval;\n\n        /// <summary>\n        /// The default value for <see cref=\"StatisticMonitorWriteInterval\"/>.\n        /// </summary>\n        public static readonly TimeSpan DefaultStatisticMonitorWriteInterval = TimeSpan.FromMinutes(5);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/SegmentBuilder.cs",
    "content": "\nusing System;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Utility class for encoding data into an ArraySegment.\n    /// </summary>\n    public static class SegmentBuilder\n    {\n        /// <summary>\n        /// Calculates how much space will be needed to append the provided bytes into the segment.\n        /// </summary>\n        public static int CalculateAppendSize(ReadOnlySpan<byte> memory) => memory.Length + sizeof(int);\n\n        /// <summary>\n        /// Calculates how much space will be needed to append the provided string into the segment.\n        /// </summary>\n        /// <param name=\"str\"></param>\n        /// <returns></returns>\n        public static int CalculateAppendSize(string str) => str is null ? sizeof(int) : str.Length * sizeof(char) + sizeof(int);\n\n        /// <summary>\n        /// Appends a <see cref=\"ReadOnlyMemory{T}\"/> of bytes to the end of the segment\n        /// </summary>\n        /// <param name=\"writerOffset\"></param>\n        /// <param name=\"bytes\"></param>\n        /// <param name=\"segment\"></param>\n        public static void Append(ArraySegment<byte> segment, ref int writerOffset, ReadOnlySpan<byte> bytes)\n        {\n            if (segment.Array == null)\n            {\n                throw new ArgumentNullException(nameof(segment));\n            }\n\n            var length = bytes.Length;\n            MemoryMarshal.Write(segment.AsSpan(writerOffset), in length);\n            writerOffset += sizeof(int);\n\n            if (bytes.Length > 0)\n            {\n                bytes.CopyTo(segment.AsSpan(writerOffset));\n                writerOffset += bytes.Length;\n            }\n        }\n\n        /// <summary>\n        /// Appends a string to the end of the segment\n        /// </summary>\n        /// <param name=\"writerOffset\"></param>\n        /// <param name=\"str\"></param>\n        /// <param name=\"segment\"></param>\n        public static void Append(ArraySegment<byte> segment, ref int writerOffset, string str)\n        {\n            if (segment.Array == null)\n            {\n                throw new ArgumentNullException(nameof(segment));\n            }\n            if (str == null)\n            {\n                var length = -1;\n                MemoryMarshal.Write(segment.AsSpan(writerOffset), in length);\n                writerOffset += sizeof(int);\n            }\n            else\n            {\n                Append(segment, ref writerOffset, MemoryMarshal.AsBytes(str.AsSpan()));\n            }\n        }\n\n        /// <summary>\n        /// Reads the next item in the segment as a byte array.  For performance, this is returned as a sub-segment of the original segment.\n        /// </summary>\n        /// <returns></returns>\n        public static ArraySegment<byte> ReadNextBytes(ArraySegment<byte> segment, ref int readerOffset)\n        {\n            if (segment.Array == null)\n            {\n                throw new ArgumentNullException(nameof(segment));\n            }\n            int size = BitConverter.ToInt32(segment.Array, segment.Offset + readerOffset);\n            readerOffset += sizeof(int);\n            var seg = new ArraySegment<byte>(segment.Array, segment.Offset + readerOffset, size);\n            readerOffset += size;\n            return seg;\n        }\n\n        /// <summary>\n        /// Reads the next item in the segment as a string.\n        /// </summary>\n        /// <returns></returns>\n        public static string ReadNextString(ArraySegment<byte> segment, ref int readerOffset)\n        {\n            if (segment.Array == null)\n            {\n                throw new ArgumentNullException(nameof(segment));\n            }\n            int size = BitConverter.ToInt32(segment.Array, segment.Offset + readerOffset);\n            readerOffset += sizeof(int);\n            if (size < 0)\n            {\n                return null;\n            }\n            if (size == 0)\n            {\n                return string.Empty;\n            }\n            var chars = segment.AsSpan(readerOffset, size);\n            readerOffset += size;\n            return new string(MemoryMarshal.Cast<byte, char>(chars));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/SimpleCache/SimpleQueueAdapterCache.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Adapter for simple queue caches.\n    /// </summary>\n    public class SimpleQueueAdapterCache : IQueueAdapterCache\n    {\n        /// <summary>\n        /// Cache size property name for configuration\n        /// </summary>\n        public const string CacheSizePropertyName = \"CacheSize\";\n\n        private readonly int cacheSize;\n        private readonly string providerName;\n        private readonly ILoggerFactory loggerFactory;\n\n        /// <summary>\n        /// Adapter for simple queue caches.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"providerName\">The stream provider name.</param>\n        /// <param name=\"loggerFactory\">The logger factory.</param>\n        public SimpleQueueAdapterCache(SimpleQueueCacheOptions options, string providerName, ILoggerFactory loggerFactory)\n        {\n            this.cacheSize = options.CacheSize;\n            this.loggerFactory = loggerFactory;\n            this.providerName = providerName;\n        }\n\n        /// <inheritdoc />\n        public IQueueCache CreateQueueCache(QueueId queueId)\n        {\n            return new SimpleQueueCache(cacheSize, this.loggerFactory.CreateLogger($\"{typeof(SimpleQueueCache).FullName}.{providerName}.{queueId}\"));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/SimpleCache/SimpleQueueCache.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    internal class CacheBucket\n    {\n        // For backpressure detection we maintain a histogram of 10 buckets.\n        // Every bucket records how many items are in the cache in that bucket\n        // and how many cursors are poinmting to an item in that bucket.\n        // We update the NumCurrentItems when we add and remove cache item (potentially opening or removing a bucket)\n        // We update NumCurrentCursors every time we move a cursor\n        // If the first (most outdated bucket) has at least one cursor pointing to it, we say we are under back pressure (in a full cache).\n        internal int NumCurrentItems { get; private set; }\n        internal int NumCurrentCursors { get; private set; }\n\n        internal void UpdateNumItems(int val)\n        {\n            NumCurrentItems = NumCurrentItems + val;\n        }\n        internal void UpdateNumCursors(int val)\n        {\n            NumCurrentCursors = NumCurrentCursors + val;\n        }\n    }\n\n    internal class SimpleQueueCacheItem\n    {\n        internal IBatchContainer Batch;\n        internal bool DeliveryFailure;\n        internal StreamSequenceToken SequenceToken;\n        internal CacheBucket CacheBucket;\n    }\n\n    /// <summary>\n    /// A queue cache that keeps items in memory.\n    /// </summary>\n    public partial class SimpleQueueCache : IQueueCache\n    {\n        private readonly LinkedList<SimpleQueueCacheItem> cachedMessages;\n        private readonly int maxCacheSize;\n        private readonly ILogger logger;\n        private readonly List<CacheBucket> cacheCursorHistogram; // for backpressure detection\n        private const int NUM_CACHE_HISTOGRAM_BUCKETS = 10;\n        private readonly int CACHE_HISTOGRAM_MAX_BUCKET_SIZE;\n\n        /// <summary>\n        /// Gets the number of items in the cache.\n        /// </summary>\n        public int Size => cachedMessages.Count;\n\n        /// <inheritdoc />\n        public int GetMaxAddCount()\n        {\n            return CACHE_HISTOGRAM_MAX_BUCKET_SIZE;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SimpleQueueCache\"/> class.\n        /// </summary>\n        /// <param name=\"cacheSize\">Size of the cache.</param>\n        /// <param name=\"logger\">The logger.</param>\n        public SimpleQueueCache(int cacheSize, ILogger logger)\n        {\n            cachedMessages = new LinkedList<SimpleQueueCacheItem>();\n            maxCacheSize = cacheSize;\n\n            this.logger = logger;\n            cacheCursorHistogram = new List<CacheBucket>();\n            CACHE_HISTOGRAM_MAX_BUCKET_SIZE = Math.Max(cacheSize / NUM_CACHE_HISTOGRAM_BUCKETS, 1); // we have 10 buckets\n        }\n\n        /// <inheritdoc />\n        public virtual bool IsUnderPressure()\n        {\n            return cacheCursorHistogram.Count >= NUM_CACHE_HISTOGRAM_BUCKETS;\n        }\n\n\n        /// <inheritdoc />\n        public virtual bool TryPurgeFromCache(out IList<IBatchContainer> purgedItems)\n        {\n            purgedItems = null;\n            if (cachedMessages.Count == 0) return false; // empty cache\n            if (cacheCursorHistogram.Count == 0) return false;  // no cursors yet - zero consumers basically yet.\n            if (cacheCursorHistogram[0].NumCurrentCursors > 0) return false; // consumers are still active in the oldest bucket - fast path\n\n            var allItems = new List<IBatchContainer>();\n            while (cacheCursorHistogram.Count > 0 && cacheCursorHistogram[0].NumCurrentCursors == 0)\n            {\n                List<IBatchContainer> items = DrainBucket(cacheCursorHistogram[0]);\n                allItems.AddRange(items);\n                cacheCursorHistogram.RemoveAt(0); // remove the last bucket\n            }\n            purgedItems = allItems;\n\n            LogDebugTryPurgeFromCache(allItems.Count);\n\n            return true;\n        }\n\n        private List<IBatchContainer> DrainBucket(CacheBucket bucket)\n        {\n            var itemsToRelease = new List<IBatchContainer>(bucket.NumCurrentItems);\n            // walk all items in the cache starting from last\n            // and remove from the cache the oness that reside in the given bucket until we jump to a next bucket\n            while (bucket.NumCurrentItems > 0)\n            {\n                SimpleQueueCacheItem item = cachedMessages.Last.Value;\n                if (item.CacheBucket.Equals(bucket))\n                {\n                    if (!item.DeliveryFailure)\n                    {\n                        itemsToRelease.Add(item.Batch);\n                    }\n                    bucket.UpdateNumItems(-1);\n                    cachedMessages.RemoveLast();\n                }\n                else\n                {\n                    // this item already points into the next bucket, so stop.\n                    break;\n                }\n            }\n            return itemsToRelease;\n        }\n\n        /// <inheritdoc />\n        public virtual void AddToCache(IList<IBatchContainer> msgs)\n        {\n            if (msgs == null) throw new ArgumentNullException(nameof(msgs));\n\n            LogDebugAddToCache(msgs.Count);\n            foreach (var message in msgs)\n            {\n                Add(message, message.SequenceToken);\n            }\n        }\n\n        /// <inheritdoc />\n        public virtual IQueueCacheCursor GetCacheCursor(StreamId streamId, StreamSequenceToken token)\n        {\n            var cursor = new SimpleQueueCacheCursor(this, streamId, logger);\n            InitializeCursor(cursor, token);\n            return cursor;\n        }\n\n        internal void InitializeCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken)\n        {\n            LogDebugInitializeCursor(cursor, sequenceToken);\n\n            // Nothing in cache, unset token, and wait for more data.\n            if (cachedMessages.Count == 0)\n            {\n                UnsetCursor(cursor, sequenceToken);\n                return;\n            }\n\n            // if no token is provided, set token to item at end of cache\n            sequenceToken = sequenceToken ?? cachedMessages.First?.Value?.SequenceToken;\n\n            // If sequenceToken is too new to be in cache, unset token, and wait for more data.\n            if (sequenceToken.Newer(cachedMessages.First.Value.SequenceToken))\n            {\n                UnsetCursor(cursor, sequenceToken);\n                return;\n            }\n\n            LinkedListNode<SimpleQueueCacheItem> lastMessage = cachedMessages.Last;\n            // Check to see if offset is too old to be in cache\n            if (sequenceToken.Older(lastMessage.Value.SequenceToken))\n            {\n                throw new QueueCacheMissException(sequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);\n            }\n\n            // Now the requested sequenceToken is set and is also within the limits of the cache.\n\n            // Find first message at or below offset\n            // Events are ordered from newest to oldest, so iterate from start of list until we hit a node at a previous offset, or the end.\n            LinkedListNode<SimpleQueueCacheItem> node = cachedMessages.First;\n            while (node != null && node.Value.SequenceToken.Newer(sequenceToken))\n            {\n                // did we get to the end?\n                if (node.Next == null) // node is the last message\n                    break;\n\n                // if sequenceId is between the two, take the higher\n                if (node.Next.Value.SequenceToken.Older(sequenceToken))\n                    break;\n\n                node = node.Next;\n            }\n\n            // return cursor from start.\n            SetCursor(cursor, node);\n        }\n\n        internal void RefreshCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken)\n        {\n            LogDebugRefreshCursor(cursor, sequenceToken);\n\n            // set if unset\n            if (!cursor.IsSet)\n            {\n                InitializeCursor(cursor, cursor.SequenceToken ?? sequenceToken);\n            }\n        }\n\n        /// <summary>\n        /// Acquires the next message in the cache at the provided cursor\n        /// </summary>\n        /// <param name=\"cursor\"></param>\n        /// <param name=\"batch\"></param>\n        /// <returns></returns>\n        internal bool TryGetNextMessage(SimpleQueueCacheCursor cursor, out IBatchContainer batch)\n        {\n            LogDebugTryGetNextMessage(cursor);\n\n            batch = null;\n            if (!cursor.IsSet) return false;\n\n            // If we are at the end of the cache unset cursor and move offset one forward\n            if (cursor.Element == cachedMessages.First)\n            {\n                UnsetCursor(cursor, null);\n            }\n            else // Advance to next:\n            {\n                AdvanceCursor(cursor, cursor.Element.Previous);\n            }\n\n            batch = cursor.Element?.Value.Batch;\n            return (batch != null);\n        }\n\n        private void AdvanceCursor(SimpleQueueCacheCursor cursor, LinkedListNode<SimpleQueueCacheItem> item)\n        {\n            LogDebugUpdateCursor(cursor, item.Value.Batch);\n\n            cursor.Element.Value.CacheBucket.UpdateNumCursors(-1); // remove from prev bucket\n            cursor.Set(item);\n            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket\n        }\n\n        internal void SetCursor(SimpleQueueCacheCursor cursor, LinkedListNode<SimpleQueueCacheItem> item)\n        {\n            LogDebugSetCursor(cursor, item.Value.Batch);\n\n            cursor.Set(item);\n            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket\n        }\n\n        internal void UnsetCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken token)\n        {\n            LogDebugUnsetCursor(cursor);\n\n            if (cursor.IsSet)\n            {\n                cursor.Element.Value.CacheBucket.UpdateNumCursors(-1);\n            }\n            cursor.UnSet(token);\n        }\n\n        private void Add(IBatchContainer batch, StreamSequenceToken sequenceToken)\n        {\n            if (batch == null) throw new ArgumentNullException(nameof(batch));\n            // this should never happen, but just in case\n            if (Size >= maxCacheSize) throw new CacheFullException();\n\n            CacheBucket cacheBucket;\n            if (cacheCursorHistogram.Count == 0)\n            {\n                cacheBucket = new CacheBucket();\n                cacheCursorHistogram.Add(cacheBucket);\n            }\n            else\n            {\n                cacheBucket = cacheCursorHistogram[cacheCursorHistogram.Count - 1]; // last one\n            }\n\n            if (cacheBucket.NumCurrentItems == CACHE_HISTOGRAM_MAX_BUCKET_SIZE) // last bucket is full, open a new one\n            {\n                cacheBucket = new CacheBucket();\n                cacheCursorHistogram.Add(cacheBucket);\n            }\n\n            // Add message to linked list\n            var item = new SimpleQueueCacheItem\n            {\n                Batch = batch,\n                SequenceToken = sequenceToken,\n                CacheBucket = cacheBucket\n            };\n\n            cachedMessages.AddFirst(new LinkedListNode<SimpleQueueCacheItem>(item));\n            cacheBucket.UpdateNumItems(1);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryPurgeFromCache: purged {PurgedItemsCount} items from cache.\"\n        )]\n        private partial void LogDebugTryPurgeFromCache(int purgedItemsCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"AddToCache: added {ItemCount} items to cache.\"\n        )]\n        private partial void LogDebugAddToCache(int itemCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"InitializeCursor: {Cursor} to sequenceToken {SequenceToken}\"\n        )]\n        private partial void LogDebugInitializeCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"RefreshCursor: {RefreshCursor} to sequenceToken {SequenceToken}\"\n        )]\n        private partial void LogDebugRefreshCursor(SimpleQueueCacheCursor refreshCursor, StreamSequenceToken sequenceToken);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"TryGetNextMessage: {Cursor}\"\n        )]\n        private partial void LogDebugTryGetNextMessage(SimpleQueueCacheCursor cursor);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpdateCursor: {Cursor} to item {Item}\"\n        )]\n        private partial void LogDebugUpdateCursor(SimpleQueueCacheCursor cursor, IBatchContainer item);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"SetCursor: {Cursor} to item {Item}\"\n        )]\n        private partial void LogDebugSetCursor(SimpleQueueCacheCursor cursor, IBatchContainer item);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UnsetCursor: {Cursor}\"\n        )]\n        private partial void LogDebugUnsetCursor(SimpleQueueCacheCursor cursor);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/SimpleCache/SimpleQueueCacheCursor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Cursor into a simple queue cache.\n    /// </summary>\n    public partial class SimpleQueueCacheCursor : IQueueCacheCursor\n    {\n        private readonly StreamId streamId;\n        private readonly SimpleQueueCache cache;\n        private readonly ILogger logger;\n        private IBatchContainer current; // this is a pointer to the current element in the cache. It is what will be returned by GetCurrent().\n\n        // This is also a pointer to the current element in the cache. It differs from current, in\n        // that current is just the batch, and is null before the first call to MoveNext after\n        // construction. (Or after refreshing if we had previously run out of batches). Upon MoveNext\n        // being called in that situation, current gets set to the batch included in Element. That is\n        // needed to implement the Enumerator pattern properly, since in that pattern MoveNext gets called\n        // before the first access of (Get)Current.\n\n        internal LinkedListNode<SimpleQueueCacheItem> Element { get; private set; }\n        internal StreamSequenceToken SequenceToken { get; private set; }\n\n        internal bool IsSet => Element != null;\n\n        internal void Set(LinkedListNode<SimpleQueueCacheItem> item)\n        {\n            if (item == null) throw new NullReferenceException(nameof(item));\n            Element = item;\n            SequenceToken = item.Value.SequenceToken;\n        }\n\n        internal void UnSet(StreamSequenceToken token)\n        {\n            Element = null;\n            SequenceToken = token;\n        }\n\n        /// <summary>\n        /// Cursor into a simple queue cache\n        /// </summary>\n        /// <param name=\"cache\">The cache instance.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"logger\">The logger.</param>\n        public SimpleQueueCacheCursor(SimpleQueueCache cache, StreamId streamId, ILogger logger)\n        {\n            if (cache == null)\n            {\n                throw new ArgumentNullException(nameof(cache));\n            }\n\n            this.cache = cache;\n            this.streamId = streamId;\n            this.logger = logger;\n            current = null;\n            LogDebugNewCursor(streamId);\n        }\n\n        /// <inheritdoc />\n        public virtual IBatchContainer GetCurrent(out Exception exception)\n        {\n            LogDebugGetCurrent(current);\n\n            exception = null;\n            return current;\n        }\n\n        /// <inheritdoc />\n        public virtual bool MoveNext()\n        {\n            if (current == null && IsSet && IsInStream(Element.Value.Batch))\n            {\n                current = Element.Value.Batch;\n                return true;\n            }\n\n            IBatchContainer next;\n            while (cache.TryGetNextMessage(this, out next))\n            {\n                if(IsInStream(next))\n                    break;\n            }\n            current = next;\n            if (!IsInStream(next))\n                return false;\n\n            return true;\n        }\n\n        /// <inheritdoc />\n        public virtual void Refresh(StreamSequenceToken sequenceToken)\n        {\n            if (!IsSet)\n            {\n                cache.RefreshCursor(this, sequenceToken);\n            }\n        }\n\n        /// <inheritdoc />\n        public void RecordDeliveryFailure()\n        {\n            if (IsSet && current != null)\n            {\n                Element.Value.DeliveryFailure = true;\n            }\n        }\n\n        private bool IsInStream(IBatchContainer batchContainer)\n        {\n            return batchContainer != null &&\n                    batchContainer.StreamId.Equals(this.streamId);\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            Dispose(true);\n        }\n\n        /// <summary>\n        /// Clean up cache data when done\n        /// </summary>\n        /// <param name=\"disposing\"><see langword=\"true\"/> if the instance is being disposed; <see langword=\"false\"/> if it is being called from a finalizer.</param>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                cache.UnsetCursor(this, null);\n                current = null;\n            }\n        }\n\n        /// <inheritdoc />\n        public override string ToString()\n        {\n            return $\"<SimpleQueueCacheCursor: Element={Element?.Value.Batch.ToString() ?? \"null\"}, SequenceToken={SequenceToken?.ToString() ?? \"null\"}>\";\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"SimpleQueueCacheCursor New Cursor for {StreamId}\"\n        )]\n        private partial void LogDebugNewCursor(StreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"SimpleQueueCacheCursor.GetCurrent: {Current}\"\n        )]\n        private partial void LogDebugGetCurrent(IBatchContainer current);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Common/SimpleCache/SimpleQueueCacheOptions.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration options for the simple queue cache.\n    /// </summary>\n    public class SimpleQueueCacheOptions\n    {\n        /// <summary>\n        /// Gets or sets the size of the cache.\n        /// </summary>\n        /// <value>The size of the cache.</value>\n        public int CacheSize { get; set; } = DEFAULT_CACHE_SIZE;\n\n        /// <summary>\n        /// The default value of <see cref=\"CacheSize\"/>.\n        /// </summary>\n        public const int DEFAULT_CACHE_SIZE = 4096;\n    }\n\n    /// <summary>\n    /// Validates <see cref=\"SimpleQueueCacheOptions\"/>.\n    /// </summary>\n    public class SimpleQueueCacheOptionsValidator : IConfigurationValidator\n    {\n        private readonly SimpleQueueCacheOptions options;\n        private readonly string name;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SimpleQueueCacheOptionsValidator\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"name\">The name.</param>\n        private SimpleQueueCacheOptionsValidator(SimpleQueueCacheOptions options, string name)\n        {\n            this.options = options;\n            this.name = name;\n        }\n\n        /// <inheritdoc />\n        public void ValidateConfiguration()\n        {\n            if(options.CacheSize <= 0)\n                throw new OrleansConfigurationException($\"{nameof(SimpleQueueCacheOptions)} on stream provider {this.name} is invalid. {nameof(SimpleQueueCacheOptions.CacheSize)} must be larger than zero\");\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"SimpleQueueCacheOptionsValidator\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>A new <see cref=\"SimpleQueueCacheOptionsValidator\"/> instance.</returns>\n        public static IConfigurationValidator Create(IServiceProvider services, string name)\n        {\n            SimpleQueueCacheOptions queueCacheOptions = services.GetOptionsByName<SimpleQueueCacheOptions>(name);\n            return new SimpleQueueCacheOptionsValidator(queueCacheOptions, name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/DefaultStreamIdMapper.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\n#nullable enable\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// The default <see cref=\"IStreamIdMapper\"/> implementation.\n    /// </summary>\n    public sealed class DefaultStreamIdMapper : IStreamIdMapper\n    {\n        /// <summary>\n        /// The name of this stream identity mapper.\n        /// </summary>\n        public const string Name = \"default\";\n\n        /// <inheritdoc />\n        public IdSpan GetGrainKeyId(GrainBindings grainBindings, StreamId streamId)\n        {\n            string? keyType = null;\n            bool includeNamespaceInGrainId = false;\n\n            foreach (var grainBinding in grainBindings.Bindings)\n            {\n                if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BindingTypeKey, out var type)\n                        || !string.Equals(type, WellKnownGrainTypeProperties.StreamBindingTypeValue, StringComparison.Ordinal))\n                {\n                    continue;\n                }\n\n                if (grainBinding.TryGetValue(WellKnownGrainTypeProperties.LegacyGrainKeyType, out keyType))\n                {\n                    if (grainBinding.TryGetValue(WellKnownGrainTypeProperties.StreamBindingIncludeNamespaceKey, out var value)\n                        && string.Equals(value, \"true\", StringComparison.OrdinalIgnoreCase))\n                    {\n                        includeNamespaceInGrainId = true;\n                    }\n                }\n            }\n\n            return keyType switch\n            {\n                nameof(Guid) => GetGuidKey(streamId, includeNamespaceInGrainId),\n                nameof(Int64) => GetIntegerKey(streamId, includeNamespaceInGrainId),\n                _ => streamId.GetKeyIdSpan(), // null or string\n            };\n        }\n\n        private static IdSpan GetGuidKey(StreamId streamId, bool includeNamespaceInGrainId)\n        {\n            var key = streamId.Key.Span;\n            if (!Utf8Parser.TryParse(key, out Guid guidKey, out var len, 'N') || len < key.Length) throw new ArgumentException(nameof(streamId));\n\n            if (!includeNamespaceInGrainId)\n                return streamId.GetKeyIdSpan();\n\n            var ns = streamId.Namespace.Span;\n            return ns.IsEmpty ? streamId.GetKeyIdSpan() : GrainIdKeyExtensions.CreateGuidKey(guidKey, ns);\n        }\n\n        private static IdSpan GetIntegerKey(StreamId streamId, bool includeNamespaceInGrainId)\n        {\n            var key = streamId.Key.Span;\n            if (!Utf8Parser.TryParse(key, out long intKey, out var len) || len < key.Length) throw new ArgumentException(nameof(streamId));\n\n            return includeNamespaceInGrainId\n                ? GrainIdKeyExtensions.CreateIntegerKey(intKey, streamId.Namespace.Span)\n                : GrainIdKeyExtensions.CreateIntegerKey(intKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncBatchObservable.cs",
    "content": "#nullable enable\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This interface generalizes the IAsyncObserver interface to allow production and consumption of batches of items.\n    /// <para>\n    /// Note that this interface is implemented by item consumers and invoked (used) by item producers.\n    /// This means that the consumer endpoint of a stream implements this interface.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object consumed by the observer.</typeparam>\n    public interface IAsyncBatchObservable<T>\n    {\n        /// <summary>\n        /// Subscribe a consumer to this batch observable.\n        /// </summary>\n        /// <param name=\"observer\">The asynchronous batch observer to subscribe.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> observer);\n\n        /// <summary>\n        /// Subscribe a consumer to this batch observable.\n        /// </summary>\n        /// <param name=\"observer\">The asynchronous batch observer to subscribe.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> observer, StreamSequenceToken? token);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncBatchObserver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Represents a stream item within a sequence.\n    /// </summary>\n    /// <typeparam name=\"T\">The item type.</typeparam>\n    public class SequentialItem<T>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SequentialItem{T}\"/> class.\n        /// </summary>\n        /// <param name=\"item\">The item.</param>\n        /// <param name=\"token\">The token.</param>\n        public SequentialItem(T item, StreamSequenceToken token)\n        {\n            this.Item = item;\n            this.Token = token;\n        }\n\n        /// <summary>\n        /// Gets the item.\n        /// </summary>\n        /// <value>The item.</value>\n        public T Item { get; }\n\n        /// <summary>\n        /// Gets the token.\n        /// </summary>\n        /// <value>The token.</value>\n        public StreamSequenceToken Token { get; }\n    }\n\n    /// <summary>\n    /// This interface generalizes the IAsyncObserver interface to allow production and consumption of batches of items.\n    /// <para>\n    /// Note that this interface is implemented by item consumers and invoked (used) by item producers.\n    /// This means that the consumer endpoint of a stream implements this interface.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object consumed by the observer.</typeparam>\n    public interface IAsyncBatchObserver<T>\n    {\n        /// <summary>\n        /// Passes the next batch of items to the consumer.\n        /// <para>\n        /// The Task returned from this method should be completed when the items' processing has been\n        /// sufficiently processed by the consumer to meet any behavioral guarantees.\n        /// </para>\n        /// <para>\n        /// When the consumer is the (producer endpoint of) a stream, the Task is completed when the stream implementation\n        /// has accepted responsibility for the items and is assured of meeting its delivery guarantees.\n        /// For instance, a stream based on a durable queue would complete the Task when the items have been durably saved.\n        /// A stream that provides best-effort at most once delivery would return a Task that is already complete.\n        /// </para>\n        /// <para>\n        /// When the producer is the (consumer endpoint of) a stream, the Task should be completed by the consumer code\n        /// when it has accepted responsibility for the items. \n        /// In particular, if the stream provider guarantees at-least-once delivery, then the items should not be considered\n        /// delivered until the Task returned by the consumer has been completed.\n        /// </para>\n        /// </summary>\n        /// <param name=\"items\">The item to be passed.</param>\n        /// <returns>A Task that is completed when the item has been accepted.</returns>\n        Task OnNextAsync(IList<SequentialItem<T>> items);\n\n        /// <summary>\n        /// Notifies the consumer that the stream was completed.\n        /// <para>\n        /// The Task returned from this method should be completed when the consumer is done processing the stream closure.\n        /// </para>\n        /// </summary>\n        /// <returns>A Task that is completed when the stream-complete operation has been accepted.</returns>\n        Task OnCompletedAsync() => Task.CompletedTask;\n\n        /// <summary>\n        /// Notifies the consumer that the stream had an error.\n        /// <para>\n        /// The Task returned from this method should be completed when the consumer is done processing the stream closure.\n        /// </para>\n        /// </summary>\n        /// <param name=\"ex\">An Exception that describes the error that occurred on the stream.</param>\n        /// <returns>A Task that is completed when the close has been accepted.</returns>\n        Task OnErrorAsync(Exception ex);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncBatchProducer.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This interface generalizes the IAsyncObserver interface to allow production of batches of items.\n    /// <para>\n    /// Note that this interface is invoked (used) by item producers.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object consumed by the observer.</typeparam>\n    public interface IAsyncBatchProducer<T> : IAsyncObserver<T>\n    {\n        /// <summary>\n        /// Passes the next batch of items to the consumer.\n        /// <para>\n        /// The Task returned from this method should be completed when all items in the batch have been\n        /// sufficiently processed by the consumer to meet any behavioral guarantees.\n        /// </para>\n        /// <para>\n        /// That is, the semantics of the returned Task is the same as for <see cref=\"IAsyncObserver{T}.OnNextAsync\" />,\n        /// extended for all items in the batch.\n        /// </para>\n        /// </summary>\n        /// <param name=\"batch\">The items to be passed.</param>\n        /// <param name=\"token\">The stream sequence token of this item.</param>\n        /// <returns>A Task that is completed when the batch has been accepted.</returns>\n        Task OnNextBatchAsync(IEnumerable<T> batch, StreamSequenceToken token = null);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncObservable.cs",
    "content": "#nullable enable\n\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This interface generalizes the standard .NET IObserveable interface to allow asynchronous consumption of items.\n    /// Asynchronous here means that the consumer can process items asynchronously and signal item completion to the \n    /// producer by completing the returned Task.\n    /// <para>\n    /// Note that this interface is invoked (used) by item consumers and implemented by item producers.\n    /// This means that the producer endpoint of a stream implements this interface.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n    public interface IAsyncObservable<T>\n    {\n        /// <summary>\n        /// Subscribe a consumer to this observable.\n        /// </summary>\n        /// <param name=\"observer\">The asynchronous observer to subscribe.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer);\n\n        /// <summary>\n        /// Subscribe a consumer to this observable.\n        /// </summary>\n        /// <param name=\"observer\">The asynchronous observer to subscribe.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <param name=\"filterData\">Data object that will be passed in to the filter.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer, StreamSequenceToken? token, string? filterData = null);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncObserver.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This interface generalizes the standard .NET IObserver interface to allow asynchronous production of items.\n    /// <para>\n    /// Note that this interface is implemented by item consumers and invoked (used) by item producers.\n    /// This means that the consumer endpoint of a stream implements this interface.\n    /// </para>\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object consumed by the observer.</typeparam>\n    public interface IAsyncObserver<in T>\n    {\n        /// <summary>\n        /// Passes the next item to the consumer.\n        /// <para>\n        /// The Task returned from this method should be completed when the item's processing has been\n        /// sufficiently processed by the consumer to meet any behavioral guarantees.\n        /// </para>\n        /// <para>\n        /// When the consumer is the (producer endpoint of) a stream, the Task is completed when the stream implementation\n        /// has accepted responsibility for the item and is assured of meeting its delivery guarantees.\n        /// For instance, a stream based on a durable queue would complete the Task when the item has been durably saved.\n        /// A stream that provides best-effort at most once delivery would return a Task that is already complete.\n        /// </para>\n        /// <para>\n        /// When the producer is the (consumer endpoint of) a stream, the Task should be completed by the consumer code\n        /// when it has accepted responsibility for the item. \n        /// In particular, if the stream provider guarantees at-least-once delivery, then the item should not be considered\n        /// delivered until the Task returned by the consumer has been completed.\n        /// </para>\n        /// </summary>\n        /// <param name=\"item\">The item to be passed.</param>\n        /// <param name=\"token\">The stream sequence token of this item.</param>\n        /// <returns>A Task that is completed when the item has been accepted.</returns>\n        Task OnNextAsync(T item, StreamSequenceToken? token = null);\n\n        /// <summary>\n        /// Notifies the consumer that the stream was completed.\n        /// <para>\n        /// The Task returned from this method should be completed when the consumer is done processing the stream closure.\n        /// </para>\n        /// </summary>\n        /// <returns>A Task that is completed when the stream-complete operation has been accepted.</returns>\n        Task OnCompletedAsync() => Task.CompletedTask;\n\n        /// <summary>\n        /// Notifies the consumer that the stream had an error.\n        /// <para>\n        /// The Task returned from this method should be completed when the consumer is done processing the stream closure.\n        /// </para>\n        /// </summary>\n        /// <param name=\"ex\">An Exception that describes the error that occurred on the stream.</param>\n        /// <returns>A Task that is completed when the close has been accepted.</returns>\n        Task OnErrorAsync(Exception ex);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IAsyncStream.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This interface represents an object that serves as a distributed rendezvous between producers and consumers.\n    /// It is similar to a Reactive Framework <code>Subject</code> and implements\n    /// <code>IObserver</code> nor <code>IObservable</code> interfaces.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object that flows through the stream.</typeparam>\n    public interface IAsyncStream<T> :\n        IAsyncStream,\n        IEquatable<IAsyncStream<T>>, IComparable<IAsyncStream<T>>, // comparison\n        IAsyncObservable<T>, IAsyncBatchObservable<T>, // observables\n        IAsyncBatchProducer<T> // observers\n    {\n        /// <summary>\n        /// Retrieves a list of all active subscriptions created by the caller for this stream.\n        /// </summary>\n        /// <returns></returns>\n        Task<IList<StreamSubscriptionHandle<T>>> GetAllSubscriptionHandles();\n    }\n\n    /// <summary>\n    /// This interface represents an object that serves as a distributed rendezvous between producers and consumers.\n    /// It is similar to a Reactive Framework <code>Subject</code> and implements\n    /// <code>IObserver</code> nor <code>IObservable</code> interfaces.\n    /// </summary>\n    public interface IAsyncStream\n    {\n        /// <summary>\n        /// Gets a value indicating whether this is a rewindable stream - supports subscribing from previous point in time.\n        /// </summary>\n        /// <returns>True if this is a rewindable stream, false otherwise.</returns>\n        bool IsRewindable { get; }\n\n        /// <summary>\n        /// Gets the name of the provider.\n        /// </summary>\n        /// <value>The name of the provider.</value>\n        string ProviderName { get; }\n\n        /// <summary>\n        /// Gets the stream identifier.\n        /// </summary>\n        /// <value>The stream identifier.</value>\n        StreamId StreamId { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamIdMapper.cs",
    "content": "using Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Common interface for components that map a <see cref=\"StreamId\"/> to a <see cref=\"GrainId.Key\"/>\n    /// </summary>\n    public interface IStreamIdMapper\n    {\n        /// <summary>\n        /// Gets the <see cref=\"GrainId.Key\" /> which maps to the provided <see cref=\"StreamId\" />\n        /// </summary>\n        /// <param name=\"grainBindings\">The grain bindings.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>The <see cref=\"GrainId.Key\"/> component.</returns>\n        IdSpan GetGrainKeyId(GrainBindings grainBindings, StreamId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamIdentity.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Uniquely identifies a stream.\n    /// </summary>\n    /// <remarks>\n    /// Use <see cref=\"StreamId\"/> instead, where possible.\n    /// </remarks>\n    public interface IStreamIdentity\n    {\n        /// <summary>\n        /// Gets the unique identifier.\n        /// </summary>\n        /// <value>The unique identifier.</value>\n        Guid Guid { get; }\n\n        /// <summary>\n        /// Gets the namespace.\n        /// </summary>\n        /// <value>The namespace.</value>\n        string Namespace { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamSubscriptionHandleFactory.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// Functionality for creating a stream subscription handle for a particular stream and subscription.\n    /// </summary>\n    public interface IStreamSubscriptionHandleFactory\n    {\n        /// <summary>\n        /// Gets the stream identifier.\n        /// </summary>\n        /// <value>The stream identifier.</value>\n        StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets the name of the provider.\n        /// </summary>\n        /// <value>The name of the provider.</value>\n        string ProviderName { get; }\n\n        /// <summary>\n        /// Gets the subscription identifier.\n        /// </summary>\n        /// <value>The subscription identifier.</value>\n        GuidId SubscriptionId { get; }\n\n        /// <summary>\n        /// Creates a stream subscription handle for the stream and subscription identified by this instance.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <returns>The new stream subscription handle.</returns>\n        StreamSubscriptionHandle<T> Create<T>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamSubscriptionManager.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// Functionality for managing stream subscriptions.\n    /// </summary>\n    public interface IStreamSubscriptionManager\n    {\n        /// <summary>\n        /// Subscribes the specified grain to a stream.\n        /// </summary>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"grainRef\">The grain reference.</param>\n        /// <returns>The stream subscription.</returns>\n        Task<StreamSubscription> AddSubscription(string streamProviderName, StreamId streamId, GrainReference grainRef);\n\n        /// <summary>\n        /// Unsubscribes a grain from a stream.\n        /// </summary>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"subscriptionId\">The subscription identifier.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task RemoveSubscription(string streamProviderName, StreamId streamId, Guid subscriptionId);\n\n        /// <summary>\n        /// Gets the subscriptions for a stream.\n        /// </summary>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>The subscriptions.</returns>\n        Task<IEnumerable<StreamSubscription>> GetSubscriptions(string streamProviderName, StreamId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamSubscriptionManagerAdmin.cs",
    "content": "namespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// Functionality for retrieving a <see cref=\"IStreamSubscriptionManager\"/> instance.\n    /// </summary>\n    public interface IStreamSubscriptionManagerAdmin\n    {\n        /// <summary>\n        /// Gets the stream subscription manager.\n        /// </summary>\n        /// <param name=\"managerType\">Type of the manager.</param>\n        /// <returns>The <see cref=\"IStreamSubscriptionManager\"/>.</returns>\n        IStreamSubscriptionManager GetStreamSubscriptionManager(string managerType);\n    }\n\n    /// <summary>\n    /// Constants for <see cref=\"IStreamSubscriptionManagerAdmin.GetStreamSubscriptionManager(string)\"/>.\n    /// </summary>\n    public static class StreamSubscriptionManagerType\n    {\n        /// <summary>\n        /// The explicit subscription manager.\n        /// </summary>\n        public const string ExplicitSubscribeOnly = \"ExplicitSubscribeOnly\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamSubscriptionManagerRetriever.cs",
    "content": "namespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// Provides functionality for retrieving an <see cref=\"IStreamSubscriptionManager\"/> instance.\n    /// </summary>\n    public interface IStreamSubscriptionManagerRetriever\n    {\n        /// <summary>\n        /// Gets the stream subscription manager.\n        /// </summary>\n        /// <returns>The <see cref=\"IStreamSubscriptionManager\"/>.</returns>\n        IStreamSubscriptionManager GetStreamSubscriptionManager();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/IStreamSubscriptionObserver.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// When implemented by a grain, notifies the grain of any new or resuming subscriptions.\n    /// </summary>\n    public interface IStreamSubscriptionObserver\n    {\n        /// <summary>\n        /// Called when this grain receives a message for a stream which it has not yet explicitly subscribed to or resumed.\n        /// </summary>\n        /// <param name=\"handleFactory\">The handle factory.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/ImplicitConsumerGrainExtensions.cs",
    "content": "﻿namespace Orleans.Streams\n{\n    /// <summary>\n    /// Extension methods for grains implicitly subscribed to streams.\n    /// </summary>\n    public static class ImplicitConsumerGrainExtensions\n    {\n        /// <summary>\n        /// Constructs <see cref=\"StreamIdentity\"/> of the stream that the grain is implicitly subscribed to.\n        /// </summary>\n        /// <param name=\"grain\">The implicitly subscribed grain.</param>\n        /// <returns>The stream identity (key + namespace).</returns>\n        public static StreamIdentity GetImplicitStreamIdentity(this IGrainWithGuidCompoundKey grain)\n        {\n            string keyExtension;\n            var key = grain.GetPrimaryKey(out keyExtension);\n            return new StreamIdentity(key, keyExtension);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamIdentity.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream identity contains the public stream information use to uniquely identify a stream.\n    /// Stream identities are only unique per stream provider.\n    /// </summary>\n    /// <remarks>\n    /// Use <see cref=\"StreamId\"/> where possible, instead.\n    /// </remarks>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class StreamIdentity : IStreamIdentity\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamIdentity\"/> class.\n        /// </summary>\n        /// <param name=\"streamGuid\">The stream unique identifier.</param>\n        /// <param name=\"streamNamespace\">The stream namespace.</param>\n        public StreamIdentity(Guid streamGuid, string streamNamespace)\n        {\n            Guid = streamGuid;\n            Namespace = streamNamespace;\n        }\n\n        /// <summary>\n        /// Gets the stream identifier.\n        /// </summary>\n        [Id(0)]\n        public Guid Guid { get; }\n\n        /// <summary>\n        /// Gets the stream namespace.\n        /// </summary>\n        [Id(1)]\n        public string Namespace { get; }\n\n        /// <inheritdoc />\n        public override bool Equals(object obj) => obj is StreamIdentity identity && this.Guid.Equals(identity.Guid) && this.Namespace == identity.Namespace;\n\n        /// <inheritdoc />\n        public override int GetHashCode() => HashCode.Combine(Guid, Namespace);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamSequenceToken.cs",
    "content": "using System;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Handle representing stream sequence number/token.\n    /// Consumer may subscribe to the stream while specifying the start of the subscription sequence token.\n    /// That means that the stream infrastructure will deliver stream events starting from this sequence token.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class StreamSequenceToken : IEquatable<StreamSequenceToken>, IComparable<StreamSequenceToken>\n    {\n        /// <summary>\n        /// Gets the number of event batches in stream prior to this event batch\n        /// </summary>\n        public abstract long SequenceNumber { get; protected set;  }\n\n        /// <summary>\n        /// Gets the number of events in batch prior to this event\n        /// </summary>\n        public abstract int EventIndex { get; protected set; }\n\n        /// <inheritdoc/>\n        public abstract bool Equals(StreamSequenceToken other);\n\n        /// <inheritdoc/>\n        public abstract int CompareTo(StreamSequenceToken other);\n    }\n\n    /// <summary>\n    /// Utilities for comparing <see cref=\"StreamSequenceToken\"/> instances.\n    /// </summary>\n    public static class StreamSequenceTokenUtilities\n    {\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the first token is newer than the second token.\n        /// </summary>\n        /// <param name=\"me\">The first token</param>\n        /// <param name=\"other\">The second token.</param>\n        /// <returns><see langword=\"true\" /> if the first token is newer than the second token, <see langword=\"false\" /> otherwise.</returns>\n        static public bool Newer(this StreamSequenceToken me, StreamSequenceToken other)\n        {\n            return me.CompareTo(other) > 0;\n        }\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if the first token is older than the second token.\n        /// </summary>\n        /// <param name=\"me\">The first token</param>\n        /// <param name=\"other\">The second token.</param>\n        /// <returns><see langword=\"true\" /> if the first token is older than the second token, <see langword=\"false\" /> otherwise.</returns>\n        static public bool Older(this StreamSequenceToken me, StreamSequenceToken other)\n        {\n            return me.CompareTo(other) < 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamSubscription.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams.Core\n{\n    /// <summary>\n    /// Represents a subscription to a stream.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class StreamSubscription\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamSubscription\"/> class.\n        /// </summary>\n        /// <param name=\"subscriptionId\">The subscription identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        public StreamSubscription(Guid subscriptionId, string streamProviderName, StreamId streamId, GrainId grainId)\n        {\n            this.SubscriptionId = subscriptionId;\n            this.StreamProviderName = streamProviderName;\n            this.StreamId = streamId;\n            this.GrainId = grainId;\n        }\n\n        /// <summary>\n        /// Gets or sets the subscription identifier.\n        /// </summary>\n        /// <value>The subscription identifier.</value>\n        [Id(0)]\n        public Guid SubscriptionId { get; }\n\n        /// <summary>\n        /// Gets or sets the name of the stream provider.\n        /// </summary>\n        /// <value>The name of the stream provider.</value>\n        [Id(1)]\n        public string StreamProviderName { get; }\n\n        /// <summary>\n        /// Gets or sets the stream identifier.\n        /// </summary>\n        /// <value>The stream identifier.</value>\n        [Id(2)]\n        public StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets or sets the grain identifier.\n        /// </summary>\n        /// <value>The grain identifier.</value>\n        [Id(3)]\n        public GrainId GrainId { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamSubscriptionHandle.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Handle representing this subscription.\n    /// Consumer may serialize and store the handle in order to unsubscribe later, for example\n    /// in another activation on this grain.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class StreamSubscriptionHandle<T> : IEquatable<StreamSubscriptionHandle<T>>\n    {\n        /// <summary>\n        /// Gets the stream identifier.\n        /// </summary>\n        /// <value>The stream identifier.</value>\n        public abstract StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets the name of the provider.\n        /// </summary>\n        /// <value>The name of the provider.</value>\n        public abstract string ProviderName { get; }\n\n        /// <summary>\n        /// Gets the unique identifier for this StreamSubscriptionHandle\n        /// </summary>\n        public abstract Guid HandleId { get; }\n\n        /// <summary>\n        /// Unsubscribe a stream consumer from this observable.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"Task\"/> representing the operation.\n        /// </returns>\n        public abstract Task UnsubscribeAsync();\n\n        /// <summary>\n        /// Resumed consumption from a subscription to a stream.\n        /// </summary>\n        /// <param name=\"observer\">The observer object.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>\n        /// The new stream subscription handle.\n        /// </returns>\n        public abstract Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncObserver<T> observer, StreamSequenceToken token = null);\n\n        /// <summary>\n        /// Resume batch consumption from a subscription to a stream.\n        /// </summary>\n        /// <param name=\"observer\">The batcj bserver object.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>\n        /// The new stream subscription handle.\n        /// </returns>\n        public abstract Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncBatchObserver<T> observer, StreamSequenceToken token = null);\n\n        /// <inheritdoc/>\n        public abstract bool Equals(StreamSubscriptionHandle<T> other);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamSubscriptionManager.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams.Core\n{\n    internal class StreamSubscriptionManager: IStreamSubscriptionManager\n    {\n        private readonly string type;\n        private readonly IStreamPubSub streamPubSub;\n\n        public StreamSubscriptionManager(IStreamPubSub streamPubSub, string managerType)\n        {\n            this.streamPubSub = streamPubSub;\n            this.type = managerType;\n        }\n\n        public async Task<StreamSubscription> AddSubscription(string streamProviderName, StreamId streamId, GrainReference grainRef)\n        {\n            var consumer = grainRef.GrainId;\n            var internalStreamId = new QualifiedStreamId(streamProviderName, streamId);\n            var subscriptionId = streamPubSub.CreateSubscriptionId(internalStreamId, consumer);\n            await streamPubSub.RegisterConsumer(subscriptionId, internalStreamId, consumer, null);\n            var newSub = new StreamSubscription(subscriptionId.Guid, streamProviderName, streamId, grainRef.GrainId);\n            return newSub;\n        }\n\n        public async Task RemoveSubscription(string streamProviderName, StreamId streamId, Guid subscriptionId)\n        {\n            var internalStreamId = new QualifiedStreamId(streamProviderName, streamId);\n            await streamPubSub.UnregisterConsumer(GuidId.GetGuidId(subscriptionId), internalStreamId);\n        }\n\n        public Task<IEnumerable<StreamSubscription>> GetSubscriptions(string streamProviderName, StreamId streamId)\n        {\n            var internalStreamId = new QualifiedStreamId(streamProviderName, streamId);\n            return streamPubSub.GetAllSubscriptions(internalStreamId).ContinueWith(subs => subs.Result.AsEnumerable());\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "src/Orleans.Streaming/Core/StreamSubscriptionManagerAdmin.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Streams.Core\n{\n    internal class StreamSubscriptionManagerAdmin : IStreamSubscriptionManagerAdmin\n    {\n        private readonly StreamSubscriptionManager _explicitStreamSubscriptionManager;\n\n        public StreamSubscriptionManagerAdmin(IStreamProviderRuntime providerRuntime)\n        {\n            // using ExplicitGrainBasedAndImplicit pubsub here, so if StreamSubscriptionManager.Add(Remove)Subscription called on a implicit subscribed\n            // consumer grain, its subscription will be handled by ImplicitPubsub, and will not be messed into GrainBasedPubsub \n            _explicitStreamSubscriptionManager = new StreamSubscriptionManager(providerRuntime.PubSub(StreamPubSubType.ExplicitGrainBasedAndImplicit), \n                StreamSubscriptionManagerType.ExplicitSubscribeOnly);\n        }\n\n        public IStreamSubscriptionManager GetStreamSubscriptionManager(string managerType)\n        {\n            return managerType switch\n            {\n                StreamSubscriptionManagerType.ExplicitSubscribeOnly => _explicitStreamSubscriptionManager,\n                _ => throw new KeyNotFoundException($\"Cannot find StreamSubscriptionManager with type {managerType}.\")\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Extensions/AsyncBatchObservableExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IAsyncBatchObservable{T}\"/>.\n    /// </summary>\n    public static class AsyncBatchObservableExtensions\n    {\n        private static readonly Func<Exception, Task> DefaultOnError = _ => Task.CompletedTask;\n        private static readonly Func<Task> DefaultOnCompleted = () => Task.CompletedTask;\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncBatchObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncBatchObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncBatchObserver.OnErrorAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncBatchObserver.OnCompletedAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           Func<Task> onCompletedAsync)\n        {\n            var genericObserver = new GenericAsyncBatchObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync);\n            return obs.SubscribeAsync(genericObserver);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncBatchObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncBatchObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncBatchObserver.OnErrorAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, onErrorAsync, DefaultOnCompleted);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncBatchObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncBatchObserver.OnNextAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncBatchObserver.OnCompletedAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Task> onCompletedAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, onCompletedAsync);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncBatchObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncBatchObserver.OnNextAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, DefaultOnCompleted);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Extensions/AsyncObservableExtensions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IAsyncObservable{T}\"/>.\n    /// </summary>\n    public static class AsyncObservableExtensions\n    {\n        private static readonly Func<Exception, Task> DefaultOnError = _ => Task.CompletedTask;\n        private static readonly Func<Task> DefaultOnCompleted = () => Task.CompletedTask;\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           Func<Task> onCompletedAsync)\n        {\n            var genericObserver = new GenericAsyncObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync);\n            return obs.SubscribeAsync(genericObserver);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, onErrorAsync, DefaultOnCompleted);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Task> onCompletedAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, onCompletedAsync);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.</returns>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, DefaultOnCompleted);\n        }\n\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token)\n        {\n            var genericObserver = new GenericAsyncObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync);\n            return obs.SubscribeAsync(genericObserver, token);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           StreamSequenceToken token)\n        {\n            return obs.SubscribeAsync(onNextAsync, onErrorAsync, DefaultOnCompleted, token);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, onCompletedAsync, token);\n        }\n\n        /// <summary>\n        /// Subscribe a consumer to this observable using delegates.\n        /// This method is a helper for the IAsyncObservable.SubscribeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"obs\">The Observable object.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        public static Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           StreamSequenceToken token)\n        {\n            return obs.SubscribeAsync(onNextAsync, DefaultOnError, DefaultOnCompleted, token);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Extensions/GenericAsyncObserver.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Class used by the IAsyncObservable extension methods to allow observation via delegate.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n    internal class GenericAsyncObserver<T> : IAsyncObserver<T>\n    {\n        private readonly Func<T, StreamSequenceToken, Task> onNextAsync;\n        private readonly Func<Exception, Task> onErrorAsync;\n        private readonly Func<Task> onCompletedAsync;\n\n        public GenericAsyncObserver(Func<T, StreamSequenceToken, Task> onNextAsync, Func<Exception, Task> onErrorAsync, Func<Task> onCompletedAsync)\n        {\n            if (onNextAsync == null) throw new ArgumentNullException(nameof(onNextAsync));\n            if (onErrorAsync == null) throw new ArgumentNullException(nameof(onErrorAsync));\n            if (onCompletedAsync == null) throw new ArgumentNullException(nameof(onCompletedAsync));\n\n            this.onNextAsync = onNextAsync;\n            this.onErrorAsync = onErrorAsync;\n            this.onCompletedAsync = onCompletedAsync;\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken token = null)\n        {\n            return onNextAsync(item, token);\n        }\n\n        public Task OnCompletedAsync()\n        {\n            return onCompletedAsync();\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            return onErrorAsync(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Extensions/GenericBatchAsyncObserver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Class used by the IAsyncBatchObservable extension methods to allow observation via delegate.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n    internal class GenericAsyncBatchObserver<T> : IAsyncBatchObserver<T>\n    {\n        private readonly Func<IList<SequentialItem<T>>, Task> onNextAsync;\n        private readonly Func<Exception, Task> onErrorAsync;\n        private readonly Func<Task> onCompletedAsync;\n\n        public GenericAsyncBatchObserver(Func<IList<SequentialItem<T>>, Task> onNextAsync, Func<Exception, Task> onErrorAsync, Func<Task> onCompletedAsync)\n        {\n            this.onNextAsync = onNextAsync ?? throw new ArgumentNullException(nameof(onNextAsync));\n            this.onErrorAsync = onErrorAsync ?? throw new ArgumentNullException(nameof(onErrorAsync));\n            this.onCompletedAsync = onCompletedAsync ?? throw new ArgumentNullException(nameof(onCompletedAsync));\n        }\n\n        public Task OnNextAsync(IList<SequentialItem<T>> items)\n        {\n            return this.onNextAsync(items);\n        }\n\n        public Task OnCompletedAsync()\n        {\n            return this.onCompletedAsync();\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            return this.onErrorAsync(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Extensions/StreamSubscriptionHandleExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"StreamSubscriptionHandle{T}\"/>.\n    /// </summary>\n    public static class StreamSubscriptionHandleExtensions\n    {\n        private static readonly Func<Exception, Task> DefaultOnError = _ => Task.CompletedTask;\n        private static readonly Func<Task> DefaultOnCompleted = () => Task.CompletedTask;\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            var genericObserver = new GenericAsyncObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync);\n            return handle.ResumeAsync(genericObserver, token);\n        }\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, onErrorAsync, DefaultOnCompleted, token);\n        }\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, DefaultOnError, onCompletedAsync, token);\n        }\n\n        /// <summary>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<T, StreamSequenceToken, Task> onNextAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, DefaultOnError, DefaultOnCompleted, token);\n        }\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            var genericObserver = new GenericAsyncBatchObserver<T>(onNextAsync, onErrorAsync, onCompletedAsync);\n            return handle.ResumeAsync(genericObserver, token);\n        }\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onErrorAsync\">Delegate that is called for IAsyncObserver.OnErrorAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Exception, Task> onErrorAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, onErrorAsync, DefaultOnCompleted, token);\n        }\n\n        /// <summary>\n        /// Resumes consumption of a stream using delegates.\n        /// This method is a helper for the StreamSubscriptionHandle.ResumeAsync allowing the subscribing class to inline the \n        /// handler methods instead of requiring an instance of IAsyncBatchObserver.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"onCompletedAsync\">Delegate that is called for IAsyncObserver.OnCompletedAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           Func<Task> onCompletedAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, DefaultOnError, onCompletedAsync, token);\n        }\n\n        /// <summary>\n        /// <exception cref=\"ArgumentException\">Thrown if the supplied stream filter function is not suitable. \n        /// Usually this is because it is not a static method. </exception>\n        /// </summary>\n        /// <typeparam name=\"T\">The type of object produced by the observable.</typeparam>\n        /// <param name=\"handle\">The subscription handle.</param>\n        /// <param name=\"onNextAsync\">Delegate that is called for IAsyncObserver.OnNextAsync.</param>\n        /// <param name=\"token\">The stream sequence to be used as an offset to start the subscription from.</param>\n        /// <returns>A promise for a StreamSubscriptionHandle that represents the subscription.\n        /// The consumer may unsubscribe by using this handle.\n        /// The subscription remains active for as long as it is not explicitly unsubscribed.\n        /// </returns>\n        public static Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle,\n                                                                           Func<IList<SequentialItem<T>>, Task> onNextAsync,\n                                                                           StreamSequenceToken token = null)\n        {\n            return handle.ResumeAsync(onNextAsync, DefaultOnError, DefaultOnCompleted, token);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Filtering/IStreamFilter.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans.Streams.Filtering\n{\n    /// <summary>\n    /// Functionality for filtering streams.\n    /// </summary>\n    public interface IStreamFilter\n    {\n        /// <summary>\n        /// Returns a value indicating if the specified stream item should be delivered.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"item\">The stream item.</param>\n        /// <param name=\"filterData\">The filter data.</param>\n        /// <returns><see langword=\"true\" /> if the stream item should be delivered, <see langword=\"false\" /> otherwise.</returns>\n        bool ShouldDeliver(StreamId streamId, object item, string filterData);\n    }\n\n    internal sealed class NoOpStreamFilter : IStreamFilter\n    {\n        public bool ShouldDeliver(StreamId streamId, object item, string filterData) => true;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/GeneratorAdapterFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// Stream generator commands\n    /// </summary>\n    public enum StreamGeneratorCommand\n    {\n        /// <summary>\n        /// Command to configure the generator\n        /// </summary>\n        Configure = PersistentStreamProviderCommand.AdapterFactoryCommandStartRange\n    }\n\n    /// <summary>\n    /// Adapter factory for stream generator stream provider.\n    /// This factory acts as the adapter and the adapter factory.  It creates receivers that use configurable generator\n    ///   to generate event streams, rather than reading them from storage.\n    /// </summary>\n    public partial class GeneratorAdapterFactory : IQueueAdapterFactory, IQueueAdapter, IQueueAdapterCache, IControllable\n    {\n        /// <summary>\n        /// Configuration property name for generator configuration type\n        /// </summary>\n        private readonly HashRingStreamQueueMapperOptions queueMapperOptions;\n        private readonly StreamStatisticOptions statisticOptions;\n        private readonly IServiceProvider serviceProvider;\n        private readonly Serialization.Serializer serializer;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ILogger<GeneratorAdapterFactory> logger;\n        private IStreamGeneratorConfig generatorConfig;\n        private IStreamQueueMapper streamQueueMapper;\n        private IStreamFailureHandler streamFailureHandler;\n        private ConcurrentDictionary<QueueId, Receiver> receivers;\n        private IObjectPool<FixedSizeBuffer> bufferPool;\n        private BlockPoolMonitorDimensions blockPoolMonitorDimensions;\n\n        /// <inheritdoc />\n        public bool IsRewindable => true;\n\n        /// <inheritdoc />\n        public StreamProviderDirection Direction => StreamProviderDirection.ReadOnly;\n\n        /// <inheritdoc />\n        public string Name { get; }\n\n        /// <summary>\n        /// Create a cache monitor to report cache related metrics\n        /// Return a ICacheMonitor\n        /// </summary>\n        protected Func<CacheMonitorDimensions, ICacheMonitor> CacheMonitorFactory;\n\n        /// <summary>\n        /// Create a block pool monitor to monitor block pool related metrics\n        /// Return a IBlockPoolMonitor\n        /// </summary>\n        protected Func<BlockPoolMonitorDimensions, IBlockPoolMonitor> BlockPoolMonitorFactory;\n\n        /// <summary>\n        /// Create a monitor to monitor QueueAdapterReceiver related metrics\n        /// Return a IQueueAdapterReceiverMonitor\n        /// </summary>\n        protected Func<ReceiverMonitorDimensions, IQueueAdapterReceiverMonitor> ReceiverMonitorFactory;\n\n        public GeneratorAdapterFactory(\n            string providerName,\n            HashRingStreamQueueMapperOptions queueMapperOptions,\n            StreamStatisticOptions statisticOptions,\n            IServiceProvider serviceProvider,\n            Serialization.Serializer serializer,\n            ILoggerFactory loggerFactory)\n        {\n            this.Name = providerName;\n            this.queueMapperOptions = queueMapperOptions ?? throw new ArgumentNullException(nameof(queueMapperOptions));\n            this.statisticOptions = statisticOptions ?? throw new ArgumentNullException(nameof(statisticOptions));\n            this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));\n            this.serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.logger = loggerFactory.CreateLogger<GeneratorAdapterFactory>();\n        }\n\n        /// <summary>\n        /// Initializes the factory.\n        /// </summary>\n        public void Init()\n        {\n            this.receivers = new ConcurrentDictionary<QueueId, Receiver>();\n            if (CacheMonitorFactory == null)\n                this.CacheMonitorFactory = (dimensions) => new DefaultCacheMonitor(dimensions);\n            if (this.BlockPoolMonitorFactory == null)\n                this.BlockPoolMonitorFactory = (dimensions) => new DefaultBlockPoolMonitor(dimensions);\n            if (this.ReceiverMonitorFactory == null)\n                this.ReceiverMonitorFactory = (dimensions) => new DefaultQueueAdapterReceiverMonitor(dimensions);\n            generatorConfig = this.serviceProvider.GetKeyedService<IStreamGeneratorConfig>(this.Name);\n            if(generatorConfig == null)\n            {\n                LogInfoNoGeneratorConfigurationFound(this.Name);\n            }\n        }\n\n        private void CreateBufferPoolIfNotCreatedYet()\n        {\n            if (this.bufferPool == null)\n            {\n                // 1 meg block size pool\n                this.blockPoolMonitorDimensions = new BlockPoolMonitorDimensions($\"BlockPool-{Guid.NewGuid()}\");\n                var oneMb = 1 << 20;\n                var objectPoolMonitor = new ObjectPoolMonitorBridge(this.BlockPoolMonitorFactory(blockPoolMonitorDimensions), oneMb);\n                this.bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(oneMb), objectPoolMonitor, this.statisticOptions.StatisticMonitorWriteInterval);\n            }\n        }\n\n        /// <inheritdoc />\n        public Task<IQueueAdapter> CreateAdapter()\n        {\n            return Task.FromResult<IQueueAdapter>(this);\n        }\n\n        /// <inheritdoc />\n        public IQueueAdapterCache GetQueueAdapterCache()\n        {\n            return this;\n        }\n\n        /// <inheritdoc />\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            return streamQueueMapper ?? (streamQueueMapper = new HashRingBasedStreamQueueMapper(this.queueMapperOptions, this.Name));\n        }\n\n        /// <inheritdoc />\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            return Task.FromResult(streamFailureHandler ?? (streamFailureHandler = new NoOpStreamDeliveryFailureHandler()));\n        }\n\n        /// <inheritdoc />\n        public Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token,\n            Dictionary<string, object> requestContext)\n        {\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n        {\n            if (!receivers.TryGetValue(queueId, out var receiver))\n            {\n                var dimensions = new ReceiverMonitorDimensions(queueId.ToString());\n                var receiverMonitor = this.ReceiverMonitorFactory(dimensions);\n                receiver = receivers.GetOrAdd(queueId, new Receiver(receiverMonitor));\n            }\n            SetGeneratorOnReceiver(receiver);\n            return receiver;\n        }\n\n        /// <inheritdoc />\n        public Task<object> ExecuteCommand(int command, object arg)\n        {\n            if (arg == null)\n            {\n                throw new ArgumentNullException(nameof(arg));\n            }\n            generatorConfig = arg as IStreamGeneratorConfig;\n            if (generatorConfig == null)\n            {\n                throw new ArgumentOutOfRangeException(nameof(arg), \"Arg must by of type IStreamGeneratorConfig\");\n            }\n\n            // update generator on receivers\n            foreach (var receiver in receivers)\n            {\n                SetGeneratorOnReceiver(receiver.Value);\n            }\n\n            return Task.FromResult<object>(true);\n        }\n\n        private class Receiver : IQueueAdapterReceiver\n        {\n            private const int MaxDelayMs = 20;\n            private readonly IQueueAdapterReceiverMonitor receiverMonitor;\n            public IStreamGenerator QueueGenerator { private get; set; }\n\n            public Receiver(IQueueAdapterReceiverMonitor receiverMonitor)\n            {\n                this.receiverMonitor = receiverMonitor;\n            }\n\n            public Task Initialize(TimeSpan timeout)\n            {\n                this.receiverMonitor?.TrackInitialization(true, TimeSpan.MinValue, null);\n                return Task.CompletedTask;\n            }\n\n            public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n            {\n                var watch = Stopwatch.StartNew();\n                await Task.Delay(Random.Shared.Next(1,MaxDelayMs));\n                List<IBatchContainer> batches;\n                if (QueueGenerator == null || !QueueGenerator.TryReadEvents(DateTime.UtcNow, maxCount, out batches))\n                {\n                    return new List<IBatchContainer>();\n                }\n                watch.Stop();\n                this.receiverMonitor?.TrackRead(true, watch.Elapsed, null);\n                if (batches.Count > 0)\n                {\n                    var oldestMessage = batches[0] as GeneratedBatchContainer;\n                    var newestMessage = batches[batches.Count - 1] as GeneratedBatchContainer;\n                    this.receiverMonitor?.TrackMessagesReceived(batches.Count, oldestMessage?.EnqueueTimeUtc, newestMessage?.EnqueueTimeUtc);\n                }\n                return batches;\n            }\n\n            public Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n            {\n                return Task.CompletedTask;\n            }\n\n            public Task Shutdown(TimeSpan timeout)\n            {\n                this.receiverMonitor?.TrackShutdown(true, TimeSpan.MinValue, null);\n                return Task.CompletedTask;\n            }\n        }\n\n        private void SetGeneratorOnReceiver(Receiver receiver)\n        {\n            // if we don't have generator configuration, don't set generator\n            if (generatorConfig == null)\n            {\n                return;\n            }\n\n            var generator = (IStreamGenerator)(serviceProvider?.GetService(generatorConfig.StreamGeneratorType) ?? Activator.CreateInstance(generatorConfig.StreamGeneratorType));\n            if (generator == null)\n            {\n                throw new OrleansException($\"StreamGenerator type not supported: {generatorConfig.StreamGeneratorType}\");\n            }\n            generator.Configure(serviceProvider, generatorConfig);\n            receiver.QueueGenerator = generator;\n        }\n\n        /// <inheritdoc />\n        public IQueueCache CreateQueueCache(QueueId queueId)\n        {\n            //move block pool creation from init method to here, to avoid unnecessary block pool creation when stream provider is initialized in client side.\n            CreateBufferPoolIfNotCreatedYet();\n            var dimensions = new CacheMonitorDimensions(queueId.ToString(), this.blockPoolMonitorDimensions.BlockPoolId);\n            var cacheMonitor = this.CacheMonitorFactory(dimensions);\n            return new GeneratorPooledCache(\n                bufferPool,\n                this.loggerFactory.CreateLogger($\"{typeof(GeneratorPooledCache).FullName}.{this.Name}.{queueId}\"),\n                serializer,\n                cacheMonitor,\n                this.statisticOptions.StatisticMonitorWriteInterval);\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"GeneratorAdapterFactory\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>The newly created <see cref=\"GeneratorAdapterFactory\"/> instance.</returns>\n        public static GeneratorAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var queueMapperOptions = services.GetOptionsByName<HashRingStreamQueueMapperOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            var factory = ActivatorUtilities.CreateInstance<GeneratorAdapterFactory>(services, name, queueMapperOptions, statisticOptions);\n            factory.Init();\n            return factory;\n        }\n\n        // \"No generator configuration found for stream provider {StreamProvider}.  Inactive until provided with configuration by command.\"\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"No generator configuration found for stream provider {StreamProvider}.  Inactive until provided with configuration by command.\"\n        )]\n        private partial void LogInfoNoGeneratorConfigurationFound(string streamProvider);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/GeneratorPooledCache.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// Pooled cache for generator stream provider.\n    /// </summary>\n    public class GeneratorPooledCache : IQueueCache, ICacheDataAdapter\n    {\n        private readonly IObjectPool<FixedSizeBuffer> bufferPool;\n        private readonly Serialization.Serializer serializer;\n        private readonly IEvictionStrategy evictionStrategy;\n        private readonly PooledQueueCache cache;\n\n        private FixedSizeBuffer currentBuffer;\n\n        /// <summary>\n        /// Pooled cache for generator stream provider.\n        /// </summary>\n        /// <param name=\"bufferPool\">The buffer pool.</param>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"serializer\">The serializer.</param>\n        /// <param name=\"cacheMonitor\">The cache monitor.</param>\n        /// <param name=\"monitorWriteInterval\">The monitor write interval. Only triggered for active caches</param>\n        public GeneratorPooledCache(IObjectPool<FixedSizeBuffer> bufferPool, ILogger logger, Serialization.Serializer serializer, ICacheMonitor cacheMonitor, TimeSpan? monitorWriteInterval)\n        {\n            this.bufferPool = bufferPool;\n            this.serializer = serializer;\n            cache = new PooledQueueCache(this, logger, cacheMonitor, monitorWriteInterval);\n            TimePurgePredicate purgePredicate = new TimePurgePredicate(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10));\n            this.evictionStrategy = new ChronologicalEvictionStrategy(logger, purgePredicate, cacheMonitor, monitorWriteInterval) {PurgeObservable = cache};\n        }\n\n        /// <inheritdoc />\n        public IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage)\n        {\n            //Deserialize payload\n            int readOffset = 0;\n            ArraySegment<byte> payload = SegmentBuilder.ReadNextBytes(cachedMessage.Segment, ref readOffset);\n            object payloadObject = this.serializer.Deserialize<object>(payload);\n            return new GeneratedBatchContainer(cachedMessage.StreamId,\n                payloadObject, new EventSequenceTokenV2(cachedMessage.SequenceNumber));\n        }\n\n        /// <inheritdoc />\n        public StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n        {\n            return new EventSequenceTokenV2(cachedMessage.SequenceNumber);\n        }\n\n        private CachedMessage QueueMessageToCachedMessage(GeneratedBatchContainer queueMessage, DateTime dequeueTimeUtc)\n        {\n            StreamPosition streamPosition = GetStreamPosition(queueMessage);\n            return new CachedMessage()\n            {\n                StreamId = streamPosition.StreamId,\n                SequenceNumber = queueMessage.RealToken.SequenceNumber,\n                EnqueueTimeUtc = queueMessage.EnqueueTimeUtc,\n                DequeueTimeUtc = dequeueTimeUtc,\n                Segment = SerializeMessageIntoPooledSegment(queueMessage)\n            };\n        }\n\n        // Placed object message payload into a segment from a buffer pool.  When this get's too big, older blocks will be purged\n        private ArraySegment<byte> SerializeMessageIntoPooledSegment(GeneratedBatchContainer queueMessage)\n        {\n            byte[] serializedPayload = this.serializer.SerializeToArray(queueMessage.Payload);\n\n            // get size of namespace, offset, partitionkey, properties, and payload\n            int size = SegmentBuilder.CalculateAppendSize(serializedPayload);\n\n            // get segment\n            ArraySegment<byte> segment;\n            if (currentBuffer == null || !currentBuffer.TryGetSegment(size, out segment))\n            {\n                // no block or block full, get new block and try again\n                currentBuffer = bufferPool.Allocate();\n                //call EvictionStrategy's OnBlockAllocated method\n                this.evictionStrategy.OnBlockAllocated(currentBuffer);\n                // if this fails with clean block, then requested size is too big\n                if (!currentBuffer.TryGetSegment(size, out segment))\n                {\n                    string errmsg = $\"Message size is to big. MessageSize: {size}\";\n                    throw new ArgumentOutOfRangeException(nameof(queueMessage), errmsg);\n                }\n            }\n\n            // encode namespace, offset, partitionkey, properties and payload into segment\n            int writeOffset = 0;\n            SegmentBuilder.Append(segment, ref writeOffset, serializedPayload);\n\n            return segment;\n        }\n\n        private static StreamPosition GetStreamPosition(GeneratedBatchContainer queueMessage)\n        {\n            return new StreamPosition(queueMessage.StreamId, queueMessage.RealToken);\n        }\n\n        private class Cursor : IQueueCacheCursor\n        {\n            private readonly PooledQueueCache cache;\n            private readonly object cursor;\n            private IBatchContainer current;\n\n            public Cursor(PooledQueueCache cache, StreamId streamId, StreamSequenceToken token)\n            {\n                this.cache = cache;\n                cursor = cache.GetCursor(streamId, token);\n            }\n\n            public void Dispose()\n            {\n            }\n\n            public IBatchContainer GetCurrent(out Exception exception)\n            {\n                exception = null;\n                return current;\n            }\n\n            public bool MoveNext()\n            {\n                IBatchContainer next;\n                if (!cache.TryGetNextMessage(cursor, out next))\n                {\n                    return false;\n                }\n\n                current = next;\n                return true;\n            }\n\n            public void Refresh(StreamSequenceToken token)\n            {\n            }\n\n            public void RecordDeliveryFailure()\n            {\n            }\n        }\n\n        /// <inheritdoc />\n        public int GetMaxAddCount() { return 100; }\n\n        /// <inheritdoc />\n        public void AddToCache(IList<IBatchContainer> messages)\n        {\n            DateTime utcNow = DateTime.UtcNow;\n            List<CachedMessage> generatedMessages = messages\n                .Cast<GeneratedBatchContainer>()\n                .Select(batch => QueueMessageToCachedMessage(batch, utcNow))\n                .ToList();\n            cache.Add(generatedMessages, utcNow);\n        }\n\n        /// <inheritdoc />\n        public bool TryPurgeFromCache(out IList<IBatchContainer> purgedItems)\n        {\n            purgedItems = null;\n            this.evictionStrategy.PerformPurge(DateTime.UtcNow);\n            return false;\n        }\n\n        /// <inheritdoc />\n        public IQueueCacheCursor GetCacheCursor(StreamId streamId, StreamSequenceToken token)\n        {\n            return new Cursor(cache, streamId, token);\n        }\n\n        /// <inheritdoc />\n        public bool IsUnderPressure()\n        {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/Generators/GeneratedBatchContainer.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// <see cref=\"IBatchContainer\"/> implementation for generated event payloads.\n    /// </summary>\n    [GenerateSerializer]\n    public sealed class GeneratedBatchContainer : IBatchContainer\n    {\n        /// <inheritdoc />\n        [Id(0)]\n        public StreamId StreamId { get; }\n\n        /// <inheritdoc />\n        public StreamSequenceToken SequenceToken => RealToken;\n\n        /// <summary>\n        /// Gets the real token.\n        /// </summary>\n        /// <value>The real token.</value>\n        [Id(1)]\n        public EventSequenceTokenV2 RealToken { get;  }\n\n        /// <summary>\n        /// Gets the enqueue time (UTC).\n        /// </summary>\n        /// <value>The enqueue time (UTC).</value>\n        [Id(2)]\n        public DateTime EnqueueTimeUtc { get; }\n\n        /// <summary>\n        /// Gets the payload.\n        /// </summary>\n        /// <value>The payload.</value>\n        [Id(3)]\n        public object Payload { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GeneratedBatchContainer\"/> class.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"payload\">The payload.</param>\n        /// <param name=\"token\">The token.</param>\n        public GeneratedBatchContainer(StreamId streamId, object payload, EventSequenceTokenV2 token)\n        {\n            StreamId = streamId;\n            EnqueueTimeUtc = DateTime.UtcNow;\n            this.Payload = payload;\n            this.RealToken = token;\n        }\n\n        /// <inheritdoc />\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return new[] { Tuple.Create((T)Payload, SequenceToken) };\n        }\n\n        /// <inheritdoc />\n        public bool ImportRequestContext()\n        {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/Generators/GeneratedEvent.cs",
    "content": "using System;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// Event use in generated streams\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class GeneratedEvent\n    {\n        /// <summary>\n        /// Generated event type\n        /// </summary>\n        public enum GeneratedEventType\n        {\n            /// <summary>\n            /// Filler event\n            /// </summary>\n            Fill,\n\n            /// <summary>\n            /// Event that should trigger reporting\n            /// </summary>\n            Report\n        }\n\n        /// <summary>\n        /// Gets or sets the event type.\n        /// </summary>\n        [Id(0)]\n        public GeneratedEventType EventType { get; set; }\n\n        /// <summary>\n        /// Gets or sets the payload.\n        /// </summary>\n        [Id(1)]\n        public int[] Payload { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/Generators/SimpleGenerator.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing Orleans.Hosting;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// Simple Generator\n    /// Generates a single stream of a configurable number of events.  One event per poll.\n    /// </summary>\n    internal class SimpleGenerator : IStreamGenerator\n    {\n        private SimpleGeneratorOptions options;\n        private StreamId streamId;\n        private int sequenceId;\n\n        /// <inheritdoc />\n        public void Configure(IServiceProvider serviceProvider, IStreamGeneratorConfig generatorConfig)\n        {\n            var cfg = generatorConfig as SimpleGeneratorOptions;\n            if (cfg == null)\n            {\n                throw new ArgumentOutOfRangeException(nameof(generatorConfig));\n            }\n            options = cfg;\n            sequenceId = 0;\n            streamId = StreamId.Create(options.StreamNamespace, Guid.NewGuid());\n        }\n\n        /// <summary>\n        /// Until we've generated the configured number of events, return a single generated event\n        /// </summary>\n        public bool TryReadEvents(DateTime utcNow, int maxCount, out List<IBatchContainer> events)\n        {\n            events = new List<IBatchContainer>();\n            if (sequenceId >= this.options.EventsInStream)\n            {\n                return false;\n            }\n\n            for(int i=0; i< maxCount; i++)\n            {\n                if (!TryGenerateBatch(out GeneratedBatchContainer batch))\n                    break;\n                events.Add(batch);\n            }\n\n            return true;\n        }\n        \n        private bool TryGenerateBatch(out GeneratedBatchContainer batch)\n        {\n            batch = null;\n            if (sequenceId >= this.options.EventsInStream)\n            {\n                return false;\n            }\n            sequenceId++;\n            var evt = new GeneratedEvent\n            {\n                // If this is the last event generated, mark it as such, so test grains know to report results.\n                EventType = (sequenceId != this.options.EventsInStream)\n                        ? GeneratedEvent.GeneratedEventType.Fill\n                        : GeneratedEvent.GeneratedEventType.Report\n            };\n            batch = new GeneratedBatchContainer(streamId, evt, new EventSequenceTokenV2(sequenceId));\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/Generators/SimpleGeneratorConfig.cs",
    "content": "\nusing System;\nusing Orleans.Providers.Streams.Generator;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Simple generator configuration class.\n    /// This class is used to configure a generator stream provider to generate streams using the SimpleGenerator\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class SimpleGeneratorOptions : IStreamGeneratorConfig\n    {\n        /// <summary>\n        /// Gets or sets the stream namespace.\n        /// </summary>\n        /// <value>The stream namespace.</value>\n        [Id(0)]\n        public string StreamNamespace { get; set; }\n\n        /// <summary>\n        /// Gets the stream generator type\n        /// </summary>\n        /// <value>The type of the stream generator.</value>\n        public Type StreamGeneratorType => typeof (SimpleGenerator);\n\n        /// <summary>\n        /// Gets or sets the number of events to generate.\n        /// </summary>\n        /// <value>The number of events to generate.</value>\n        [Id(1)]\n        public int EventsInStream { get; set; } = DEFAULT_EVENTS_IN_STREAM;\n\n        /// <summary>\n        /// The default number of events to generate.\n        /// </summary>\n        public const int DEFAULT_EVENTS_IN_STREAM = 100;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Generator/IStreamGenerator.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    /// <summary>\n    /// Interface of generators used by the GeneratorStreamProvider.  Any method of generating events\n    ///  must conform to this interface to be used by the GeneratorStreamProvider.\n    /// </summary>\n    public interface IStreamGenerator\n    {\n        /// <summary>\n        /// Tries to get an event, if the generator is configured to generate any at this time\n        /// </summary>\n        /// <param name=\"utcNow\">The current UTC time.</param>\n        /// <param name=\"maxCount\">The maximum number of events to read.</param>\n        /// <param name=\"events\">The events.</param>\n        /// <returns><see langword=\"true\" /> if events were read, <see langword=\"false\" /> otherwise.</returns>\n        bool TryReadEvents(DateTime utcNow, int maxCount, out List<IBatchContainer> events);\n\n        /// <summary>\n        /// Configures the stream generator.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <param name=\"generatorConfig\">The generator configuration.</param>\n        void Configure(IServiceProvider serviceProvider, IStreamGeneratorConfig generatorConfig);\n    }\n\n    /// <summary>\n    /// Interface of configuration for generators used by the GeneratorStreamProvider.  This interface covers\n    ///   the minimal set of information the stream provider needs to configure a generator to generate data.  Generators should\n    ///   add any additional configuration information needed to it's implementation of this interface.\n    /// </summary>\n    public interface IStreamGeneratorConfig\n    {\n        /// <summary>\n        /// Gets the stream generator type\n        /// </summary>\n        Type StreamGeneratorType { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/GrainStreamingExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// Extension methods for accessing stream providers from a <see cref=\"Grain\"/> or <see cref=\"IGrainBase\"/> implementation.\n    /// </summary>\n    public static class GrainStreamingExtensions\n    {\n        /// <summary>\n        /// Gets the stream provider with the specified <paramref name=\"name\"/>.\n        /// </summary>\n        /// <param name=\"grain\">The grain.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>The stream provider.</returns>\n        public static IStreamProvider GetStreamProvider(this Grain grain, string name)\n            => GetStreamProvider((IGrainBase)grain, name);\n\n        /// <summary>\n        /// Gets the stream provider with the specified <paramref name=\"name\"/>.\n        /// </summary>\n        /// <param name=\"grain\">The grain.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>The stream provider.</returns>\n        public static IStreamProvider GetStreamProvider(this IGrainBase grain, string name)\n        {\n            if (string.IsNullOrWhiteSpace(name))\n            {\n                throw new ArgumentNullException(nameof(name));\n            }\n\n            try\n            {\n                return grain.GrainContext.ActivationServices.GetRequiredKeyedService<IStreamProvider>(name);\n            }\n            catch (InvalidOperationException ex)\n            {\n                // We used to throw KeyNotFoundException before, keep it like this for backward compatibility\n                throw new KeyNotFoundException($\"Stream provider '{name}' not found\", ex);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Extension methods for accessing stream providers from a client.\n    /// </summary>\n    public static class ClientStreamingExtensions\n    {\n        /// <summary>\n        /// Gets the stream provider with the specified <paramref name=\"name\"/>.\n        /// </summary>\n        /// <param name=\"client\">The client.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>The stream provider.</returns>\n        public static IStreamProvider GetStreamProvider(this IClusterClient client, string name)\n        {\n            if (string.IsNullOrWhiteSpace(name))\n            {\n                throw new ArgumentNullException(nameof(name));\n            }\n\n            try\n            {\n                return client.ServiceProvider.GetRequiredKeyedService<IStreamProvider>(name);\n            }\n            catch (InvalidOperationException ex)\n            {\n                // We used to throw KeyNotFoundException before, keep it like this for backward compatibility\n                throw new KeyNotFoundException($\"Stream provider '{name}' not found\", ex);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Hosting/ClientBuilderStreamingExtensions.cs",
    "content": "using System;\nusing Orleans.Providers;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    public static class ClientBuilderStreamingExtensions\n    {\n        /// <summary>\n        /// Adds support for streaming to this client.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder AddStreaming(this IClientBuilder builder) => builder.ConfigureServices(services => services.AddClientStreaming());\n\n        /// <summary>\n        /// Adds a new in-memory stream provider to the client, using the default message serializer\n        /// (<see cref=\"DefaultMemoryMessageBodySerializer\"/>).\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder AddMemoryStreams(\n            this IClientBuilder builder,\n            string name,\n            Action<IClusterClientMemoryStreamConfigurator> configure = null)\n        {\n            return AddMemoryStreams<DefaultMemoryMessageBodySerializer>(builder, name, configure);\n        }\n\n        /// <summary>\n        /// Adds a new in-memory stream provider to the client.\n        /// </summary>\n        /// <typeparam name=\"TSerializer\">The type of the t serializer.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder AddMemoryStreams<TSerializer>(\n            this IClientBuilder builder,\n            string name,\n            Action<IClusterClientMemoryStreamConfigurator> configure = null)\n            where TSerializer : class, IMemoryMessageBodySerializer\n        {\n            //the constructor wire up DI with all default components of the streams , so need to be called regardless of configureStream null or not\n            var memoryStreamConfigurator = new ClusterClientMemoryStreamConfigurator<TSerializer>(name, builder);\n            configure?.Invoke(memoryStreamConfigurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds a new persistent streams provider to the client.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"adapterFactory\">The adapter factory.</param>\n        /// <param name=\"configureStream\">The configuration delegate.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder AddPersistentStreams(\n            this IClientBuilder builder,\n            string name,\n            Func<IServiceProvider, string, IQueueAdapterFactory> adapterFactory,\n            Action<IClusterClientPersistentStreamConfigurator> configureStream)\n        {\n            //the constructor wire up DI with all default components of the streams , so need to be called regardless of configureStream null or not\n            var streamConfigurator = new ClusterClientPersistentStreamConfigurator(name, builder, adapterFactory);\n            configureStream?.Invoke(streamConfigurator);\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Hosting/ClusterClientPersistentStreamConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Configuration builder for persistent streams.\n    /// </summary>\n    public interface IPersistentStreamConfigurator : INamedServiceConfigurator { }\n\n    /// <summary>\n    /// Extension methods for <see cref=\"IPersistentStreamConfigurator\"/>.\n    /// </summary>\n    public static class PersistentStreamConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures the stream pub/sub type.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"pubsubType\">The stream pub/sub type to use.</param>\n        public static void ConfigureStreamPubSub(this IPersistentStreamConfigurator configurator, StreamPubSubType pubsubType = StreamPubSubOptions.DEFAULT_STREAM_PUBSUB_TYPE)\n        {\n            configurator.Configure<StreamPubSubOptions>(ob => ob.Configure(options => options.PubSubType = pubsubType));\n        }\n    }\n\n    /// <summary>\n    /// Client-specific configuration builder for persistent stream.\n    /// </summary>\n    public interface IClusterClientPersistentStreamConfigurator : IPersistentStreamConfigurator { }\n\n    /// <summary>\n    /// Extension methods for <see cref=\"IClusterClientPersistentStreamConfigurator\"/>.\n    /// </summary>\n    public static class ClusterClientPersistentStreamConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures the <see cref=\"StreamLifecycleOptions\"/>.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigureLifecycle(this IClusterClientPersistentStreamConfigurator configurator, Action<OptionsBuilder<StreamLifecycleOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n    }\n\n    /// <summary>\n    /// Client-side configuration provider for persistent streams.\n    /// </summary>\n    public class ClusterClientPersistentStreamConfigurator : NamedServiceConfigurator, IClusterClientPersistentStreamConfigurator\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterClientPersistentStreamConfigurator\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"clientBuilder\">The client builder.</param>\n        /// <param name=\"adapterFactory\">The adapter factory.</param>\n        public ClusterClientPersistentStreamConfigurator(string name, IClientBuilder clientBuilder, Func<IServiceProvider, string, IQueueAdapterFactory> adapterFactory)\n            : base(name, configureDelegate => clientBuilder.ConfigureServices(configureDelegate))\n        {\n            clientBuilder.AddStreaming();\n            this.ConfigureComponent(PersistentStreamProvider.Create);\n            this.ConfigureDelegate(services => services.AddSingleton(sp => PersistentStreamProvider.ParticipateIn<IClusterClientLifecycle>(sp, this.Name)));\n            this.ConfigureComponent(adapterFactory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Hosting/SiloBuilderMemoryStreamExtensions.cs",
    "content": "using System;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"ISiloBuilder\"/> extension methods for configuring in-memory streams. \n    /// </summary>\n    public static class SiloBuilderMemoryStreamExtensions\n    {\n\n        /// <summary>\n        /// Configure silo to use memory streams, using the default message serializer\n        /// (<see cref=\"DefaultMemoryMessageBodySerializer\"/>).\n        /// </summary>\n        /// using the default built-in serializer\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryStreams(this ISiloBuilder builder, string name,\n                Action<ISiloMemoryStreamConfigurator> configure = null)\n        {\n            return AddMemoryStreams<DefaultMemoryMessageBodySerializer>(builder, name, configure);\n        }\n\n        /// <summary>\n        /// Configure silo to use memory streams.\n        /// </summary>\n        /// <typeparam name=\"TSerializer\">The message serializer type, which must implement <see cref=\"IMemoryMessageBodySerializer\"/>.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configure\">The configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddMemoryStreams<TSerializer>(this ISiloBuilder builder, string name,\n            Action<ISiloMemoryStreamConfigurator> configure = null)\n             where TSerializer : class, IMemoryMessageBodySerializer\n        {\n            //the constructor wire up DI with all default components of the streams , so need to be called regardless of configureStream null or not\n            var memoryStreamConfiguretor = new SiloMemoryStreamConfigurator<TSerializer>(name,\n                configureDelegate => builder.ConfigureServices(configureDelegate)\n            );\n            configure?.Invoke(memoryStreamConfiguretor);\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Hosting/SiloBuilderStreamingExtensions.cs",
    "content": "using System;\nusing Orleans.Streams;\nusing Orleans.Streams.Filtering;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for configuring streaming on silos.\n    /// </summary>\n    public static class SiloBuilderStreamingExtensions\n    {\n        /// <summary>\n        /// Add support for streaming to this application.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddStreaming(this ISiloBuilder builder) => builder.ConfigureServices(services => services.AddSiloStreaming());\n\n        /// <summary>\n        /// Configures the silo to use persistent streams.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <param name=\"adapterFactory\">The provider adapter factory.</param>\n        /// <param name=\"configureStream\">The stream provider configuration delegate.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddPersistentStreams(\n            this ISiloBuilder builder,\n            string name,\n            Func<IServiceProvider, string, IQueueAdapterFactory> adapterFactory,\n            Action<ISiloPersistentStreamConfigurator> configureStream)\n        {\n            //the constructor wire up DI with all default components of the streams , so need to be called regardless of configureStream null or not\n            var streamConfigurator = new SiloPersistentStreamConfigurator(name, configureDelegate => builder.ConfigureServices(configureDelegate), adapterFactory);\n            configureStream?.Invoke(streamConfigurator);\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds a stream filter. \n        /// </summary>\n        /// <typeparam name=\"T\">The stream filter type.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream filter name.</param>\n        /// <returns>The silo builder.</returns>\n        public static ISiloBuilder AddStreamFilter<T>(this ISiloBuilder builder, string name) where T : class, IStreamFilter\n        {\n            return builder.ConfigureServices(svc => svc.AddStreamFilter<T>(name));\n        }\n\n        /// <summary>\n        /// Adds a stream filter. \n        /// </summary>\n        /// <typeparam name=\"T\">The stream filter type.</typeparam>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The stream filter name.</param>\n        /// <returns>The client builder.</returns>\n        public static IClientBuilder AddStreamFilter<T>(this IClientBuilder builder, string name) where T : class, IStreamFilter\n        {\n            return builder.ConfigureServices(svc => svc.AddStreamFilter<T>(name));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Hosting/StreamingServiceCollectionExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration.Internal;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Providers;\nusing Orleans.Serialization;\nusing Orleans.Streaming.JsonConverters;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\nusing Orleans.Streams.Filtering;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for configuring streaming on silos.\n    /// </summary>\n    public static class StreamingServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Add support for streaming to this silo.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        public static void AddSiloStreaming(this IServiceCollection services)\n        {\n            if (services.Any(service => service.ServiceType.Equals(typeof(SiloStreamProviderRuntime))))\n            {\n                return;\n            }\n\n            services.AddSingleton<PubSubGrainStateStorageFactory>();\n            services.AddSingleton<SiloStreamProviderRuntime>();\n            services.AddFromExisting<IStreamProviderRuntime, SiloStreamProviderRuntime>();\n            services.AddSingleton<ImplicitStreamSubscriberTable>();\n            services.AddSingleton<IConfigureGrainContext, StreamConsumerGrainContextAction>();\n            services.AddSingleton<IStreamNamespacePredicateProvider, DefaultStreamNamespacePredicateProvider>();\n            services.AddSingleton<IStreamNamespacePredicateProvider, ConstructorStreamNamespacePredicateProvider>();\n            services.AddKeyedSingleton<IStreamIdMapper, DefaultStreamIdMapper>(DefaultStreamIdMapper.Name);\n            services.AddKeyedTransient<IGrainExtension>(typeof(IStreamConsumerExtension), (sp, _) =>\n            {\n                var runtime = sp.GetRequiredService<IStreamProviderRuntime>();\n                var grainContextAccessor = sp.GetRequiredService<IGrainContextAccessor>();\n                return new StreamConsumerExtension(runtime, grainContextAccessor.GrainContext?.GrainInstance as IStreamSubscriptionObserver);\n            });\n            services.AddSingleton<IStreamSubscriptionManagerAdmin>(sp =>\n                new StreamSubscriptionManagerAdmin(sp.GetRequiredService<IStreamProviderRuntime>()));\n            services.AddTransient<IStreamQueueBalancer, ConsistentRingQueueBalancer>();\n            services.AddSingleton<IPostConfigureOptions<OrleansJsonSerializerOptions>, StreamingConverterConfigurator>();\n\n            // One stream directory per activation\n            services.AddScoped<StreamDirectory>();\n        }\n\n        /// <summary>\n        /// Add support for streaming to this client.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        public static void AddClientStreaming(this IServiceCollection services)\n        {\n            if (services.Any(service => service.ServiceType.Equals(typeof(ClientStreamingProviderRuntime))))\n            {\n                return;\n            }\n\n            services.AddSingleton<ClientStreamingProviderRuntime>();\n            services.AddFromExisting<IStreamProviderRuntime, ClientStreamingProviderRuntime>();\n            services.AddSingleton<IStreamSubscriptionManagerAdmin, StreamSubscriptionManagerAdmin>();\n            services.AddSingleton<ImplicitStreamSubscriberTable>();\n            services.AddSingleton<IStreamNamespacePredicateProvider, DefaultStreamNamespacePredicateProvider>();\n            services.AddSingleton<IStreamNamespacePredicateProvider, ConstructorStreamNamespacePredicateProvider>();\n            services.AddKeyedSingleton<IStreamIdMapper, DefaultStreamIdMapper>(DefaultStreamIdMapper.Name);\n            services.AddFromExisting<ILifecycleParticipant<IClusterClientLifecycle>, ClientStreamingProviderRuntime>();\n            services.AddSingleton<IPostConfigureOptions<OrleansJsonSerializerOptions>, StreamingConverterConfigurator>();\n        }\n\n        /// <summary>\n        /// Adds a stream filter. \n        /// </summary>\n        /// <typeparam name=\"T\">The stream filter type.</typeparam>\n        /// <param name=\"services\">The service collection.</param>\n        /// <param name=\"name\">The stream filter name.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddStreamFilter<T>(this IServiceCollection services, string name) where T : class, IStreamFilter\n        {\n            return services.AddKeyedSingleton<IStreamFilter, T>(name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/ISiloPersistentStreamConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime.Providers;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Functionality for configuring persistent streams.\n    /// </summary>\n    public interface ISiloPersistentStreamConfigurator : IPersistentStreamConfigurator { }\n\n    /// <summary>\n    /// Extensions for <see cref=\"ISiloPersistentStreamConfigurator\"/>.\n    /// </summary>\n    public static class SiloPersistentStreamConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures the pulling agent.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigurePullingAgent(this ISiloPersistentStreamConfigurator configurator, Action<OptionsBuilder<StreamPullingAgentOptions>> configureOptions = null)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        /// <summary>\n        /// Configures the lifecycle.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigureLifecycle(this ISiloPersistentStreamConfigurator configurator, Action<OptionsBuilder<StreamLifecycleOptions>> configureOptions)\n        {\n            configurator.Configure(configureOptions);\n        }\n\n        /// <summary>\n        /// Configures partition balancing.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"factory\">The partition balancer factory.</param>\n        public static void ConfigurePartitionBalancing(this ISiloPersistentStreamConfigurator configurator, Func<IServiceProvider, string, IStreamQueueBalancer> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n\n        /// <summary>\n        /// Configures the pulling agents' message delivery backoff provider.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"factory\">The message delivery backoff factory.</param>\n        public static void ConfigureBackoffProvider(this ISiloPersistentStreamConfigurator configurator, Func<IServiceProvider, string, IMessageDeliveryBackoffProvider> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n\n        /// <summary>\n        /// Configures the pulling agents' queue reader backoff provider.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"factory\">The queue reader backoff factory.</param>\n        public static void ConfigureBackoffProvider(this ISiloPersistentStreamConfigurator configurator, Func<IServiceProvider, string, IQueueReaderBackoffProvider> factory)\n        {\n            configurator.ConfigureComponent(factory);\n        }\n\n        /// <summary>\n        /// Configures partition balancing.\n        /// </summary>\n        /// <typeparam name=\"TOptions\">The partition balancer options.</typeparam>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"factory\">The partition balancer factory.</param>\n        /// <param name=\"configureOptions\">The configuration delegate.</param>\n        public static void ConfigurePartitionBalancing<TOptions>(\n            this ISiloPersistentStreamConfigurator configurator,\n            Func<IServiceProvider, string, IStreamQueueBalancer> factory,\n            Action<OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new()\n        {\n            configurator.ConfigureComponent(factory, configureOptions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/IInternalAsyncObservable.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    internal interface IInternalAsyncObservable<T> : IAsyncObservable<T>, IAsyncBatchObservable<T>\n    {\n        Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncObserver<T> observer,\n            StreamSequenceToken token = null);\n\n        Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncBatchObserver<T> observer,\n            StreamSequenceToken token = null);\n\n        Task UnsubscribeAsync(StreamSubscriptionHandle<T> handle);\n\n        Task<IList<StreamSubscriptionHandle<T>>> GetAllSubscriptions();\n\n        Task Cleanup();\n    }\n\n        \n    internal interface IInternalAsyncBatchObserver<T> : IAsyncBatchProducer<T>\n    {\n        Task Cleanup();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/IInternalStreamProvider.cs",
    "content": "namespace Orleans.Streams\n{\n    internal interface IInternalStreamProvider\n    {\n        IInternalAsyncBatchObserver<T> GetProducerInterface<T>(IAsyncStream<T> streamId);\n        IInternalAsyncObservable<T> GetConsumerInterface<T>(IAsyncStream<T> streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/IStreamControl.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream control interface to allow stream runtime to perform management operations on streams \n    /// without needing to worry about concrete generic types used by this stream\n    /// </summary>\n    internal interface IStreamControl\n    {\n        /// <summary>\n        /// Perform cleanup functions for this stream.\n        /// </summary>\n        /// <returns>Completion promise for the cleanup operations for this stream.</returns>\n        Task Cleanup(bool cleanupProducers, bool cleanupConsumers);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/IStreamGrainExtensions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    // This is the extension interface for stream consumers\n    internal interface IStreamConsumerExtension : IGrainExtension\n    {\n        Task<StreamHandshakeToken> DeliverImmutable(GuidId subscriptionId, QualifiedStreamId streamId, [Immutable] object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken);\n        Task<StreamHandshakeToken> DeliverMutable(GuidId subscriptionId, QualifiedStreamId streamId, object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken);\n        Task<StreamHandshakeToken> DeliverBatch(GuidId subscriptionId, QualifiedStreamId streamId, [Immutable] IBatchContainer item, StreamHandshakeToken handshakeToken);\n        Task CompleteStream(GuidId subscriptionId);\n        Task ErrorInStream(GuidId subscriptionId, Exception exc);\n        Task<StreamHandshakeToken> GetSequenceToken(GuidId subscriptionId);\n    }\n\n    // This is the extension interface for stream producers\n    internal interface IStreamProducerExtension : IGrainExtension\n    {\n        [AlwaysInterleave]\n        Task AddSubscriber(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData);\n\n        [AlwaysInterleave]\n        Task RemoveSubscriber(GuidId subscriptionId, QualifiedStreamId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/PeriodicAction.cs",
    "content": "using System;\n\nnamespace Orleans\n{\n    internal class PeriodicAction\n    {\n        private readonly Action action;\n        private readonly TimeSpan period;\n        private DateTime nextUtc;\n\n        public PeriodicAction(TimeSpan period, Action action, DateTime? start = null)\n        {\n            this.period = period;\n            this.nextUtc = start ?? DateTime.UtcNow + period;\n            this.action = action;\n        }\n\n        public bool TryAction(DateTime nowUtc)\n        {\n            if (nowUtc < this.nextUtc) return false;\n            this.nextUtc = nowUtc + this.period;\n            this.action();\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamConsumer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal partial class StreamConsumer<T> : IInternalAsyncObservable<T>\n    {\n        internal bool                               IsRewindable { get; private set; }\n\n        private readonly StreamImpl<T>              stream;\n        private readonly string                     streamProviderName;\n        [NonSerialized]\n        private readonly IStreamProviderRuntime     providerRuntime;\n        [NonSerialized]\n        private readonly IStreamPubSub              pubSub;\n        private StreamConsumerExtension             myExtension;\n        private IStreamConsumerExtension            myGrainReference;\n        [NonSerialized]\n        private readonly AsyncLock                  bindExtLock;\n        [NonSerialized]\n        private readonly ILogger logger;\n\n        public StreamConsumer(\n            StreamImpl<T> stream,\n            string streamProviderName,\n            IStreamProviderRuntime runtime,\n            IStreamPubSub pubSub,\n            ILogger logger,\n            bool isRewindable)\n        {\n            if (stream == null) throw new ArgumentNullException(nameof(stream));\n            if (runtime == null) throw new ArgumentNullException(nameof(runtime));\n            if (pubSub == null) throw new ArgumentNullException(nameof(pubSub));\n            if (logger == null) throw new ArgumentNullException(nameof(logger));\n\n            this.logger = logger;\n            this.stream = stream;\n            this.streamProviderName = streamProviderName;\n            this.providerRuntime = runtime;\n            this.pubSub = pubSub;\n            this.IsRewindable = isRewindable;\n            this.myExtension = null;\n            this.myGrainReference = null;\n            this.bindExtLock = new AsyncLock();\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer)\n        {\n            return SubscribeAsyncImpl(observer, null, null);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(\n            IAsyncObserver<T> observer,\n            StreamSequenceToken token,\n            string filterData = null)\n        {\n            return SubscribeAsyncImpl(observer, null, token, filterData);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> batchObserver)\n        {\n            return SubscribeAsyncImpl(null, batchObserver, null);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> batchObserver, StreamSequenceToken token)\n        {\n            return SubscribeAsyncImpl(null, batchObserver, token);\n        }\n\n        private async Task<StreamSubscriptionHandle<T>> SubscribeAsyncImpl(\n            IAsyncObserver<T> observer,\n            IAsyncBatchObserver<T> batchObserver,\n            StreamSequenceToken token,\n            string filterData = null)\n        {\n            if (token != null && !IsRewindable)\n                throw new ArgumentNullException(nameof(token), \"Passing a non-null token to a non-rewindable IAsyncObservable.\");\n            if (observer is GrainReference)\n                throw new ArgumentException(\"On-behalf subscription via grain references is not supported. Only passing of object references is allowed.\", nameof(observer));\n            if (batchObserver is GrainReference)\n                throw new ArgumentException(\"On-behalf subscription via grain references is not supported. Only passing of object references is allowed.\", nameof(batchObserver));\n\n            using var _ = RequestContext.SuppressCallChainReentrancy();\n\n            LogDebugSubscribeToken(token);\n            await BindExtensionLazy();\n\n            LogDebugSubscribeRendezvous(pubSub, myGrainReference, token);\n\n            GuidId subscriptionId = pubSub.CreateSubscriptionId(stream.InternalStreamId, myGrainReference.GetGrainId());\n\n            // Optimistic Concurrency:\n            // In general, we should first register the subsription with the pubsub (pubSub.RegisterConsumer)\n            // and only if it succeeds store it locally (myExtension.SetObserver).\n            // Basicaly, those 2 operations should be done as one atomic transaction - either both or none and isolated from concurrent reads.\n            // BUT: there is a distributed race here: the first msg may arrive before the call is awaited\n            // (since the pubsub notifies the producer that may immideately produce)\n            // and will thus not find the subriptionHandle in the extension, basically violating \"isolation\".\n            // Therefore, we employ Optimistic Concurrency Control here to guarantee isolation:\n            // we optimisticaly store subscriptionId in the handle first before calling pubSub.RegisterConsumer\n            // and undo it in the case of failure.\n            // There is no problem with that we call myExtension.SetObserver too early before the handle is registered in pub sub,\n            // since this subscriptionId is unique (random Guid) and no one knows it anyway, unless successfully subscribed in the pubsub.\n            var subriptionHandle = myExtension.SetObserver(subscriptionId, stream, observer, batchObserver, token, filterData);\n            try\n            {\n                await pubSub.RegisterConsumer(subscriptionId, stream.InternalStreamId, myGrainReference.GetGrainId(), filterData);\n                return subriptionHandle;\n            }\n            catch (Exception)\n            {\n                // Undo the previous call myExtension.SetObserver.\n                myExtension.RemoveObserver(subscriptionId);\n                throw;\n            }\n        }\n\n        public Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncObserver<T> observer,\n            StreamSequenceToken token = null)\n        {\n            return ResumeAsyncImpl(handle, observer, null, token);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncBatchObserver<T> batchObserver,\n            StreamSequenceToken token = null)\n        {\n            return ResumeAsyncImpl(handle, null, batchObserver, token);\n        }\n\n        private async Task<StreamSubscriptionHandle<T>> ResumeAsyncImpl(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncObserver<T> observer,\n            IAsyncBatchObserver<T> batchObserver,\n            StreamSequenceToken token = null)\n        {\n            using var _ = RequestContext.SuppressCallChainReentrancy();\n\n            StreamSubscriptionHandleImpl<T> oldHandleImpl = CheckHandleValidity(handle);\n\n            if (token != null && !IsRewindable)\n                throw new ArgumentNullException(nameof(token), \"Passing a non-null token to a non-rewindable IAsyncObservable.\");\n\n            LogDebugResumeToken(token);\n            await BindExtensionLazy();\n\n            LogDebugResumeRendezvous(pubSub, myGrainReference, token);\n\n            StreamSubscriptionHandle<T> newHandle = myExtension.SetObserver(oldHandleImpl.SubscriptionId, stream, observer, batchObserver, token, null);\n\n            // On failure caller should be able to retry using the original handle, so invalidate old handle only if everything succeeded.\n            oldHandleImpl.Invalidate();\n\n            return newHandle;\n        }\n\n        public async Task UnsubscribeAsync(StreamSubscriptionHandle<T> handle)\n        {\n            using var _ = RequestContext.SuppressCallChainReentrancy();\n\n            await BindExtensionLazy();\n\n            StreamSubscriptionHandleImpl<T> handleImpl = CheckHandleValidity(handle);\n\n            LogDebugUnsubscribe(handle);\n\n            myExtension.RemoveObserver(handleImpl.SubscriptionId);\n            // UnregisterConsumer from pubsub even if does not have this handle locally, to allow UnsubscribeAsync retries.\n\n            LogDebugUnsubscribeRendezvous(pubSub, myGrainReference);\n\n            await pubSub.UnregisterConsumer(handleImpl.SubscriptionId, stream.InternalStreamId);\n\n            handleImpl.Invalidate();\n        }\n\n        public async Task<IList<StreamSubscriptionHandle<T>>> GetAllSubscriptions()\n        {\n            using var _ = RequestContext.SuppressCallChainReentrancy();\n\n            await BindExtensionLazy();\n\n            List<StreamSubscription> subscriptions= await pubSub.GetAllSubscriptions(stream.InternalStreamId, myGrainReference.GetGrainId());\n            return subscriptions.Select(sub => new StreamSubscriptionHandleImpl<T>(GuidId.GetGuidId(sub.SubscriptionId), stream))\n                                  .ToList<StreamSubscriptionHandle<T>>();\n        }\n\n        public async Task Cleanup()\n        {\n            using var _ = RequestContext.SuppressCallChainReentrancy();\n\n            LogDebugCleanup();\n            if (myExtension == null)\n                return;\n\n            var allHandles = myExtension.GetAllStreamHandles<T>();\n            var tasks = new List<Task>();\n            foreach (var handle in allHandles)\n            {\n                myExtension.RemoveObserver(handle.SubscriptionId);\n                tasks.Add(pubSub.UnregisterConsumer(handle.SubscriptionId, stream.InternalStreamId));\n            }\n            try\n            {\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception exc)\n            {\n                LogWarningUnregisterConsumer(exc);\n            }\n            myExtension = null;\n        }\n\n        // Used in test.\n        internal bool InternalRemoveObserver(StreamSubscriptionHandle<T> handle)\n        {\n            return myExtension != null && myExtension.RemoveObserver(((StreamSubscriptionHandleImpl<T>)handle).SubscriptionId);\n        }\n\n        internal Task<int> DiagGetConsumerObserversCount()\n        {\n            return Task.FromResult(myExtension.DiagCountStreamObservers<T>(stream.InternalStreamId));\n        }\n\n        private async Task BindExtensionLazy()\n        {\n            if (myExtension == null)\n            {\n                using (await bindExtLock.LockAsync())\n                {\n                    if (myExtension == null)\n                    {\n                        LogDebugBindExtensionLazy(providerRuntime);\n                        (myExtension, myGrainReference) = providerRuntime.BindExtension<StreamConsumerExtension, IStreamConsumerExtension>(() => new StreamConsumerExtension(providerRuntime));\n                        LogDebugBindExtension(myExtension, myGrainReference);\n                    }\n                }\n            }\n        }\n\n        private StreamSubscriptionHandleImpl<T> CheckHandleValidity(StreamSubscriptionHandle<T> handle)\n        {\n            if (handle == null)\n                throw new ArgumentNullException(nameof(handle));\n            if (!handle.StreamId.Equals(stream.StreamId))\n                throw new ArgumentException(\"Handle is not for this stream.\", nameof(handle));\n            var handleImpl = handle as StreamSubscriptionHandleImpl<T>;\n            if (handleImpl == null)\n                throw new ArgumentException(\"Handle type not supported.\", nameof(handle));\n            if (!handleImpl.IsValid)\n                throw new ArgumentException(\"Handle is no longer valid.  It has been used to unsubscribe or resume.\", nameof(handle));\n            return handleImpl;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Subscribe Token={Token}\"\n        )]\n        private partial void LogDebugSubscribeToken(StreamSequenceToken token);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Subscribe - Connecting to Rendezvous {PubSub} My GrainRef={GrainReference} Token={Token}\"\n        )]\n        private partial void LogDebugSubscribeRendezvous(IStreamPubSub pubSub, IStreamConsumerExtension grainReference, StreamSequenceToken token);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Resume Token={Token}\"\n        )]\n        private partial void LogDebugResumeToken(StreamSequenceToken token);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Resume - Connecting to Rendezvous {PubSub} My GrainRef={GrainReference} Token={Token}\"\n        )]\n        private partial void LogDebugResumeRendezvous(IStreamPubSub pubSub, IStreamConsumerExtension grainReference, StreamSequenceToken token);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unsubscribe StreamSubscriptionHandle={Handle}\"\n        )]\n        private partial void LogDebugUnsubscribe(StreamSubscriptionHandle<T> handle);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unsubscribe - Disconnecting from Rendezvous {PubSub} My GrainRef={GrainReference}\"\n        )]\n        private partial void LogDebugUnsubscribeRendezvous(IStreamPubSub pubSub, IStreamConsumerExtension grainReference);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Cleanup() called\"\n        )]\n        private partial void LogDebugCleanup();\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.StreamProvider_ConsumerFailedToUnregister,\n            Message = \"Ignoring unhandled exception during PubSub.UnregisterConsumer\"\n        )]\n        private partial void LogWarningUnregisterConsumer(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BindExtensionLazy - Binding local extension to stream runtime={ProviderRuntime}\"\n        )]\n        private partial void LogDebugBindExtensionLazy(IStreamProviderRuntime providerRuntime);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BindExtensionLazy - Connected Extension={Extension} GrainRef={GrainReference}\"\n        )]\n        private partial void LogDebugBindExtension(IStreamConsumerExtension extension, IStreamConsumerExtension grainReference);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamConsumerExtension.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal interface IStreamSubscriptionHandle\n    {\n        Task<StreamHandshakeToken> DeliverItem(object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken);\n        Task<StreamHandshakeToken> DeliverBatch(IBatchContainer item, StreamHandshakeToken handshakeToken);\n        Task CompleteStream();\n        Task ErrorInStream(Exception exc);\n        StreamHandshakeToken GetSequenceToken();\n    }\n\n    /// <summary>\n    /// The extension multiplexes all stream related messages to this grain between different streams and their stream observers.\n    ///\n    /// On the silo, we have one extension object per activation and this extension multiplexes all streams on this activation\n    ///     (streams of all types and ids: different stream ids and different stream providers).\n    /// On the client, we have one extension per stream (we bind an extension for every StreamConsumer, therefore every stream has its own extension).\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed partial class StreamConsumerExtension : IStreamConsumerExtension\n    {\n        [Id(0)]\n        private readonly IStreamProviderRuntime providerRuntime;\n        [Id(1)]\n        private readonly ConcurrentDictionary<GuidId, IStreamSubscriptionHandle> allStreamObservers = new(); // map to different ObserversCollection<T> of different Ts.\n        [Id(2)]\n        private readonly ILogger logger;\n        private const int MAXIMUM_ITEM_STRING_LOG_LENGTH = 128;\n        // if this extension is attached to a cosnumer grain which implements IOnSubscriptionActioner,\n        // then this will be not null, otherwise, it will be null\n        [NonSerialized]\n        private readonly IStreamSubscriptionObserver streamSubscriptionObserver;\n\n        internal StreamConsumerExtension(IStreamProviderRuntime providerRt, IStreamSubscriptionObserver streamSubscriptionObserver = null)\n        {\n            this.streamSubscriptionObserver = streamSubscriptionObserver;\n            providerRuntime = providerRt;\n            logger = providerRt.ServiceProvider.GetRequiredService<ILogger<StreamConsumerExtension>>();\n        }\n\n        internal StreamSubscriptionHandleImpl<T> SetObserver<T>(\n            GuidId subscriptionId,\n            StreamImpl<T> stream,\n            IAsyncObserver<T> observer,\n            IAsyncBatchObserver<T> batchObserver,\n            StreamSequenceToken token,\n            string filterData)\n        {\n            if (null == stream) throw new ArgumentNullException(nameof(stream));\n\n            try\n            {\n                LogDebugAddObserver(providerRuntime.ExecutingEntityIdentity(), stream.InternalStreamId);\n\n                // Note: The caller [StreamConsumer] already handles locking for Add/Remove operations, so we don't need to repeat here.\n                var handle = new StreamSubscriptionHandleImpl<T>(subscriptionId, observer, batchObserver, stream, token, filterData);\n                allStreamObservers[subscriptionId] = handle;\n                return handle;\n            }\n            catch (Exception exc)\n            {\n                LogErrorAddObserver(providerRuntime.ExecutingEntityIdentity(), stream.InternalStreamId, exc);\n                throw;\n            }\n        }\n\n        public bool RemoveObserver(GuidId subscriptionId)\n        {\n            return allStreamObservers.TryRemove(subscriptionId, out _);\n        }\n\n        public Task<StreamHandshakeToken> DeliverImmutable(GuidId subscriptionId, QualifiedStreamId streamId, object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)\n        {\n            return DeliverMutable(subscriptionId, streamId, item, currentToken, handshakeToken);\n        }\n\n        public async Task<StreamHandshakeToken> DeliverMutable(GuidId subscriptionId, QualifiedStreamId streamId, object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)\n        {\n            LogTraceDeliverItem(new(item), subscriptionId);\n            IStreamSubscriptionHandle observer;\n            if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n            {\n                return await observer.DeliverItem(item, currentToken, handshakeToken);\n            }\n            else if(this.streamSubscriptionObserver != null)\n            {\n                var streamProvider = this.providerRuntime.ServiceProvider.GetKeyedService<IStreamProvider>(streamId.ProviderName);\n                if(streamProvider != null)\n                {\n                    var subscriptionHandlerFactory = new StreamSubscriptionHandlerFactory(streamProvider, streamId, streamId.ProviderName, subscriptionId);\n                    await this.streamSubscriptionObserver.OnSubscribed(subscriptionHandlerFactory);\n                    //check if an observer were attached after handling the new subscription, deliver on it if attached\n                    if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n                    {\n                        return await observer.DeliverItem(item, currentToken, handshakeToken);\n                    }\n                }\n            }\n\n            LogWarningNoStreamForItem(\n                providerRuntime.ExecutingEntityIdentity(),\n                subscriptionId);\n\n            // We got an item when we don't think we're the subscriber. This is a normal race condition.\n            // We can drop the item on the floor, or pass it to the rendezvous, or ...\n            return default;\n        }\n\n        public async Task<StreamHandshakeToken> DeliverBatch(GuidId subscriptionId, QualifiedStreamId streamId, IBatchContainer batch, StreamHandshakeToken handshakeToken)\n        {\n            LogTraceDeliverBatch(batch, subscriptionId);\n\n            IStreamSubscriptionHandle observer;\n            if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n            {\n                return await observer.DeliverBatch(batch, handshakeToken);\n            }\n            else if(this.streamSubscriptionObserver != null)\n            {\n                var streamProvider = this.providerRuntime.ServiceProvider.GetKeyedService<IStreamProvider>(streamId.ProviderName);\n                if (streamProvider != null)\n                {\n                    var subscriptionHandlerFactory = new StreamSubscriptionHandlerFactory(streamProvider, streamId, streamId.ProviderName, subscriptionId);\n                    await this.streamSubscriptionObserver.OnSubscribed(subscriptionHandlerFactory);\n                    // check if an observer were attached after handling the new subscription, deliver on it if attached\n                    if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n                    {\n                        return await observer.DeliverBatch(batch, handshakeToken);\n                    }\n                }\n            }\n\n            LogWarningNoStreamForBatch(\n                providerRuntime.ExecutingEntityIdentity(),\n                subscriptionId);\n\n            // We got an item when we don't think we're the subscriber. This is a normal race condition.\n            // We can drop the item on the floor, or pass it to the rendezvous, or ...\n            return default;\n        }\n\n        public Task CompleteStream(GuidId subscriptionId)\n        {\n            LogTraceCompleteStream(subscriptionId);\n\n            IStreamSubscriptionHandle observer;\n            if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n                return observer.CompleteStream();\n\n            LogWarningNoStreamForComplete(\n                providerRuntime.ExecutingEntityIdentity(),\n                subscriptionId);\n\n            // We got an item when we don't think we're the subscriber. This is a normal race condition.\n            // We can drop the item on the floor, or pass it to the rendezvous, or ...\n            return Task.CompletedTask;\n        }\n\n        public Task ErrorInStream(GuidId subscriptionId, Exception exc)\n        {\n            LogTraceErrorInStream(subscriptionId, exc);\n\n            IStreamSubscriptionHandle observer;\n            if (allStreamObservers.TryGetValue(subscriptionId, out observer))\n                return observer.ErrorInStream(exc);\n\n            LogWarningNoStreamForError(\n                providerRuntime.ExecutingEntityIdentity(),\n                subscriptionId,\n                exc);\n\n            // We got an item when we don't think we're the subscriber. This is a normal race condition.\n            // We can drop the item on the floor, or pass it to the rendezvous, or ...\n            return Task.CompletedTask;\n        }\n\n        public Task<StreamHandshakeToken> GetSequenceToken(GuidId subscriptionId)\n        {\n            IStreamSubscriptionHandle observer;\n            return Task.FromResult(allStreamObservers.TryGetValue(subscriptionId, out observer) ? observer.GetSequenceToken() : null);\n        }\n\n        internal int DiagCountStreamObservers<T>(QualifiedStreamId streamId)\n        {\n            return allStreamObservers.Count(o => o.Value is StreamSubscriptionHandleImpl<T> i && i.SameStreamId(streamId));\n        }\n\n        internal List<StreamSubscriptionHandleImpl<T>> GetAllStreamHandles<T>()\n        {\n            var ls = new List<StreamSubscriptionHandleImpl<T>>();\n            foreach (var o in allStreamObservers)\n            {\n                if (o.Value is StreamSubscriptionHandleImpl<T> i) ls.Add(i);\n            }\n            return ls;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{Grain} AddObserver for stream {StreamId}\")]\n        private partial void LogDebugAddObserver(string grain, StreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.StreamProvider_AddObserverException,\n            Message = \"{Grain} StreamConsumerExtension.AddObserver({StreamId}) caught exception.\"\n        )]\n        private partial void LogErrorAddObserver(string grain, StreamId streamId, Exception exception);\n\n        private struct ItemWithMaxLength(object item)\n        {\n            public override string ToString()\n            {\n                var itemString = item.ToString();\n                return (itemString.Length > MAXIMUM_ITEM_STRING_LOG_LENGTH) ? itemString[..MAXIMUM_ITEM_STRING_LOG_LENGTH] + \"...\" : itemString;\n            }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"DeliverItem {Item} for subscription {Subscription}\")]\n        private partial void LogTraceDeliverItem(ItemWithMaxLength item, GuidId subscription);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.StreamProvider_NoStreamForItem,\n            Message = \"{Grain} got an item for subscription {Subscription}, but I don't have any subscriber for that stream. Dropping on the floor.\")]\n        private partial void LogWarningNoStreamForItem(string grain, GuidId subscription);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"DeliverBatch {Batch} for subscription {Subscription}\")]\n        private partial void LogTraceDeliverBatch(IBatchContainer batch, GuidId subscription);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.StreamProvider_NoStreamForBatch,\n            Message = \"{Grain} got an item for subscription {Subscription}, but I don't have any subscriber for that stream. Dropping on the floor.\")]\n        private partial void LogWarningNoStreamForBatch(string grain, GuidId subscription);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"CompleteStream for subscription {SubscriptionId}\")]\n        private partial void LogTraceCompleteStream(GuidId subscriptionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.StreamProvider_NoStreamForItem,\n            Message = \"{Grain} got a Complete for subscription {Subscription}, but I don't have any subscriber for that stream. Dropping on the floor.\")]\n        private partial void LogWarningNoStreamForComplete(string grain, GuidId subscription);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Error in stream for subscription {Subscription}\")]\n        private partial void LogTraceErrorInStream(GuidId subscription, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.StreamProvider_NoStreamForItem,\n            Message = \"{Grain} got an error for subscription {Subscription}, but I don't have any subscriber for that stream. Dropping on the floor.\")]\n        private partial void LogWarningNoStreamForError(string grain, GuidId subscription, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamDirectory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stores all streams associated with a specific silo\n    /// </summary>\n    internal class StreamDirectory : IAsyncDisposable\n    {\n        private readonly ConcurrentDictionary<QualifiedStreamId, object> allStreams = new ConcurrentDictionary<QualifiedStreamId, object>();\n\n        internal IAsyncStream<T> GetOrAddStream<T>(QualifiedStreamId streamId, Func<IAsyncStream<T>> streamCreator)\n        {\n            var stream = allStreams.GetOrAdd(streamId, (_, streamCreator) => streamCreator(), streamCreator);\n            var streamOfT = stream as IAsyncStream<T>;\n            if (streamOfT == null)\n            {\n                throw new Runtime.OrleansException($\"Stream type mismatch. A stream can only support a single type of data. The generic type of the stream requested ({typeof(T)}) does not match the previously requested type ({stream.GetType().GetGenericArguments().FirstOrDefault()}).\");\n            }\n\n            return streamOfT;\n        }\n\n        internal async Task Cleanup(bool cleanupProducers, bool cleanupConsumers)\n        {\n            if (StreamResourceTestControl.TestOnlySuppressStreamCleanupOnDeactivate)\n            {\n                return;\n            }\n\n            var promises = new List<Task>();\n            List<QualifiedStreamId> streamIds = GetUsedStreamIds();\n            foreach (QualifiedStreamId s in streamIds)\n            {\n                IStreamControl streamControl = GetStreamControl(s);\n                if (streamControl != null)\n                    promises.Add(streamControl.Cleanup(cleanupProducers, cleanupConsumers));\n            }\n\n            await Task.WhenAll(promises);\n        }\n\n        internal void Clear()\n        {\n            // This is a quick temporary solution to unblock testing for resource leakages for streams.\n            allStreams.Clear();\n        }\n\n        private IStreamControl GetStreamControl(QualifiedStreamId streamId)\n        {\n            object streamObj;\n            bool ok = allStreams.TryGetValue(streamId, out streamObj);\n            return ok ? streamObj as IStreamControl : null;\n        }\n\n        private List<QualifiedStreamId> GetUsedStreamIds()\n        {\n            return allStreams.Select(kv => kv.Key).ToList();\n        }\n\n        public async ValueTask DisposeAsync() => await this.Cleanup(cleanupProducers: true, cleanupConsumers: false).ConfigureAwait(false);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamHandshakeToken.cs",
    "content": "using System;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [GenerateSerializer]\n    internal abstract class StreamHandshakeToken : IEquatable<StreamHandshakeToken>\n    {\n        [Id(0)]\n        public StreamSequenceToken Token { get; private set; }\n        \n        public static StreamHandshakeToken CreateStartToken(StreamSequenceToken token)\n        {\n            if (token == null) return default;\n            return new StartToken {Token = token};\n        }\n\n        public static StreamHandshakeToken CreateDeliveyToken(StreamSequenceToken token)\n        {\n            if (token == null) return default;\n            return new DeliveryToken {Token = token};\n        }\n\n        public bool Equals(StreamHandshakeToken other)\n        {\n            if (ReferenceEquals(null, other)) return false;\n            if (ReferenceEquals(this, other)) return true;\n            if (other.GetType() != GetType()) return false;\n            return Equals(Token, other.Token);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            if (ReferenceEquals(this, obj)) return true;\n            if (obj.GetType() != GetType()) return false;\n            return Equals((StreamHandshakeToken)obj);\n        }\n\n        public override int GetHashCode() => HashCode.Combine(GetType(), Token);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class StartToken : StreamHandshakeToken { }\n    \n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class DeliveryToken : StreamHandshakeToken { }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamImpl.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [Immutable]\n    [GenerateSerializer]\n    [SerializationCallbacks(typeof(OnDeserializedCallbacks))]\n    internal sealed class StreamImpl<T> : IAsyncStream<T>, IStreamControl, IOnDeserialized\n    {\n        [Id(0)]\n        private readonly QualifiedStreamId                        streamId;\n\n        [Id(1)]\n        private readonly bool                                    isRewindable;\n\n        [NonSerialized]\n        private IInternalStreamProvider?                         provider;\n\n        [NonSerialized]\n        private volatile IInternalAsyncBatchObserver<T>?         producerInterface;\n\n        [NonSerialized]\n        private volatile IInternalAsyncObservable<T>?            consumerInterface;\n\n#if NET9_0_OR_GREATER\n        [NonSerialized]\n        private readonly Lock initLock = new();\n#else\n        [NonSerialized]\n        private readonly object initLock = new();\n#endif\n\n        [NonSerialized]\n        private IRuntimeClient?                                  runtimeClient;\n\n        internal QualifiedStreamId InternalStreamId { get { return streamId; } }\n        public StreamId StreamId => streamId;\n\n        public bool IsRewindable => isRewindable;\n        public string ProviderName => streamId.ProviderName;\n\n        // Constructor for Orleans serialization, otherwise initLock is null\n        public StreamImpl()\n        {\n        }\n\n        public StreamImpl(QualifiedStreamId streamId, IInternalStreamProvider provider, bool isRewindable, IRuntimeClient runtimeClient)\n        {\n            this.streamId = streamId;\n            this.provider = provider ?? throw new ArgumentNullException(nameof(provider));\n            this.runtimeClient = runtimeClient ?? throw new ArgumentNullException(nameof(runtimeClient));\n            producerInterface = null;\n            consumerInterface = null;\n            this.isRewindable = isRewindable;\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer)\n        {\n            return GetConsumerInterface().SubscribeAsync(observer, null);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer, StreamSequenceToken? token, string? filterData = null)\n        {\n            return GetConsumerInterface().SubscribeAsync(observer, token, filterData);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> batchObserver)\n        {\n            return GetConsumerInterface().SubscribeAsync(batchObserver);\n        }\n\n        public Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> batchObserver, StreamSequenceToken? token)\n        {\n            return GetConsumerInterface().SubscribeAsync(batchObserver, token);\n        }\n\n        public async Task Cleanup(bool cleanupProducers, bool cleanupConsumers)\n        {\n            // Cleanup producers\n            if (cleanupProducers && producerInterface != null)\n            {\n                await producerInterface.Cleanup();\n                producerInterface = null;\n            }\n\n            // Cleanup consumers\n            if (cleanupConsumers && consumerInterface != null)\n            {\n                await consumerInterface.Cleanup();\n                consumerInterface = null;\n            }\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken? token = null)\n        {\n            return GetProducerInterface().OnNextAsync(item, token);\n        }\n\n        public Task OnNextBatchAsync(IEnumerable<T> batch, StreamSequenceToken token)\n        {\n            return GetProducerInterface().OnNextBatchAsync(batch, token);\n        }\n\n        public Task OnCompletedAsync()\n        {\n            IInternalAsyncBatchObserver<T> producerInterface = GetProducerInterface();\n            return producerInterface.OnCompletedAsync();\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            IInternalAsyncBatchObserver<T> producerInterface = GetProducerInterface();\n            return producerInterface.OnErrorAsync(ex);\n        }\n\n        internal Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncObserver<T> observer,\n            StreamSequenceToken token)\n        {\n            return GetConsumerInterface().ResumeAsync(handle, observer, token);\n        }\n\n        internal Task<StreamSubscriptionHandle<T>> ResumeAsync(\n            StreamSubscriptionHandle<T> handle,\n            IAsyncBatchObserver<T> observer,\n            StreamSequenceToken token)\n        {\n            return GetConsumerInterface().ResumeAsync(handle, observer, token);\n        }\n\n        public Task<IList<StreamSubscriptionHandle<T>>> GetAllSubscriptionHandles()\n        {\n            return GetConsumerInterface().GetAllSubscriptions();\n        }\n\n        internal Task UnsubscribeAsync(StreamSubscriptionHandle<T> handle)\n        {\n            return GetConsumerInterface().UnsubscribeAsync(handle);\n        }\n\n        internal IInternalAsyncBatchObserver<T> GetProducerInterface()\n        {\n            if (producerInterface != null) return producerInterface;\n\n            lock (initLock)\n            {\n                if (producerInterface != null) \n                    return producerInterface;\n\n                if (provider == null)\n                    provider = GetStreamProvider();\n                \n                producerInterface = provider!.GetProducerInterface(this);\n            }\n            return producerInterface;\n        }\n\n        internal IInternalAsyncObservable<T> GetConsumerInterface()\n        {\n            if (consumerInterface == null)\n            {\n                lock (initLock)\n                {\n                    if (consumerInterface == null)\n                    {\n                        if (provider == null)\n                            provider = GetStreamProvider();\n                        \n                        consumerInterface = provider!.GetConsumerInterface(this);\n                    }\n                }\n            }\n            return consumerInterface;\n        }\n\n        private IInternalStreamProvider? GetStreamProvider()\n        {\n            return this.runtimeClient?.ServiceProvider.GetRequiredKeyedService<IStreamProvider>(streamId.ProviderName) as IInternalStreamProvider;\n        }\n\n        public int CompareTo(IAsyncStream<T>? other)\n        {\n            var o = other as StreamImpl<T>;\n            return o == null ? 1 : streamId.CompareTo(o.streamId);\n        }\n\n        public bool Equals(IAsyncStream<T>? other)\n        {\n            var o = other as StreamImpl<T>;\n            return o != null && streamId.Equals(o.streamId);\n        }\n\n        public override bool Equals(object? obj)\n        {\n            var o = obj as StreamImpl<T>;\n            return o != null && streamId.Equals(o.streamId);\n        }\n\n        public override int GetHashCode()\n        {\n            return streamId.GetHashCode();\n        }\n\n        public override string ToString()\n        {\n            return streamId.ToString();\n        }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext  context)\n        {\n            this.runtimeClient = context?.RuntimeClient as IRuntimeClient;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamSubscriptionHandleImpl.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [GenerateSerializer]\n    internal class StreamSubscriptionHandleImpl<T> : StreamSubscriptionHandle<T>, IStreamSubscriptionHandle \n    {\n        [Id(0)]\n        [JsonProperty]\n        private StreamImpl<T> streamImpl;\n        [Id(1)]\n        [JsonProperty]\n        private readonly string filterData;\n        [Id(2)]\n        [JsonProperty]\n        private readonly GuidId subscriptionId;\n        [Id(3)]\n        private readonly bool isRewindable;\n\n        [NonSerialized]\n        private IAsyncObserver<T> observer;\n        [NonSerialized]\n        private IAsyncBatchObserver<T> batchObserver;\n        [NonSerialized]\n        private StreamHandshakeToken expectedToken;\n        internal bool IsValid { get { return streamImpl != null; } }\n        internal GuidId SubscriptionId { get { return subscriptionId; } }\n        internal bool IsRewindable { get { return isRewindable; } }\n\n        public override string ProviderName { get { return this.streamImpl.ProviderName; } }\n        public override StreamId StreamId { get { return streamImpl.StreamId; } }\n        public override Guid HandleId { get { return subscriptionId.Guid; } }\n\n\n        [JsonConstructor]\n        public StreamSubscriptionHandleImpl(GuidId subscriptionId, StreamImpl<T> streamImpl, string filterData)\n            : this(subscriptionId, null, null, streamImpl, null, filterData)\n        {\n        }\n\n        public StreamSubscriptionHandleImpl(GuidId subscriptionId, StreamImpl<T> streamImpl)\n            : this(subscriptionId, null, null, streamImpl, null, null)\n        {\n        }\n\n        public StreamSubscriptionHandleImpl(\n            GuidId subscriptionId,\n            IAsyncObserver<T> observer,\n            IAsyncBatchObserver<T> batchObserver,\n            StreamImpl<T> streamImpl,\n            StreamSequenceToken token,\n            string filterData)\n        {\n            this.subscriptionId = subscriptionId ?? throw new ArgumentNullException(nameof(subscriptionId));\n            this.observer = observer;\n            this.batchObserver = batchObserver;\n            this.streamImpl = streamImpl ?? throw new ArgumentNullException(nameof(streamImpl));\n            this.filterData = filterData;\n            this.isRewindable = streamImpl.IsRewindable;\n            if (IsRewindable)\n            {\n                expectedToken = StreamHandshakeToken.CreateStartToken(token);\n            }\n        }\n\n        public void Invalidate()\n        {\n            this.streamImpl = null;\n            this.observer = null;\n            this.batchObserver = null;\n        }\n\n        public StreamHandshakeToken GetSequenceToken()\n        {\n            return this.expectedToken;\n        }\n\n        public override Task UnsubscribeAsync()\n        {\n            if (!IsValid) throw new InvalidOperationException(\"Handle is no longer valid. It has been used to unsubscribe or resume.\");\n            return this.streamImpl.UnsubscribeAsync(this);\n        }\n\n        public override Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncObserver<T> obs, StreamSequenceToken token = null)\n        {\n            if (!IsValid) throw new InvalidOperationException(\"Handle is no longer valid. It has been used to unsubscribe or resume.\");\n            return this.streamImpl.ResumeAsync(this, obs, token);\n        }\n\n\n        public override Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncBatchObserver<T> observer, StreamSequenceToken token = null)\n        {\n            if (!IsValid) throw new InvalidOperationException(\"Handle is no longer valid. It has been used to unsubscribe or resume.\");\n            return this.streamImpl.ResumeAsync(this, observer, token);\n        }\n\n        public async Task<StreamHandshakeToken> DeliverBatch(IBatchContainer batch, StreamHandshakeToken handshakeToken)\n        {\n            // we validate expectedToken only for ordered (rewindable) streams\n            if (this.expectedToken != null)\n            {\n                if (!this.expectedToken.Equals(handshakeToken))\n                    return this.expectedToken;\n\n                // Check if this even already has been delivered\n                if (IsRewindable)\n                {\n                    var currentToken = StreamHandshakeToken.CreateDeliveyToken(batch.SequenceToken);\n                    if (this.expectedToken.Equals(currentToken))\n                        return this.expectedToken;\n                }\n            }\n\n            if (batch is IBatchContainerBatch)\n            {\n                var batchContainerBatch = batch as IBatchContainerBatch;\n                await NextBatch(batchContainerBatch);\n            }\n            else\n            {\n                if (this.observer != null)\n                {\n                    foreach (var itemTuple in batch.GetEvents<T>())\n                    {\n                        await NextItem(itemTuple.Item1, itemTuple.Item2);\n                    }\n                } else\n                {\n                    await NextItems(batch.GetEvents<T>());\n                }\n            }\n\n            if (IsRewindable)\n            {\n                this.expectedToken = StreamHandshakeToken.CreateDeliveyToken(batch.SequenceToken);\n            }\n\n            return null;\n        }\n\n        public async Task<StreamHandshakeToken> DeliverItem(object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)\n        {\n            if (this.expectedToken != null)\n            {\n                if (!this.expectedToken.Equals(handshakeToken))\n                    return this.expectedToken;\n\n                // Check if this even already has been delivered\n                if (IsRewindable)\n                {\n                    if (this.expectedToken.Equals(currentToken))\n                        return this.expectedToken;\n                }\n            }\n\n            T typedItem;\n            try\n            {\n                typedItem = (T)item;\n            }\n            catch (InvalidCastException)\n            {\n                // We got an illegal item on the stream -- close it with a Cast exception\n                throw new InvalidCastException(\"Received an item of type \" + item.GetType().Name + \", expected \" + typeof(T).FullName);\n            }\n\n            await ((this.observer != null)\n                ? NextItem(typedItem, currentToken)\n                : NextItems(new[] { Tuple.Create(typedItem, currentToken) }));\n\n            // check again, in case the expectedToken was changed indiretly via ResumeAsync()\n            if (this.expectedToken != null)\n            {\n                if (!this.expectedToken.Equals(handshakeToken))\n                    return this.expectedToken;\n            }\n            if (IsRewindable)\n            {\n                this.expectedToken = StreamHandshakeToken.CreateDeliveyToken(currentToken);\n            }\n            return null;\n        }\n\n        public async Task NextBatch(IBatchContainerBatch batchContainerBatch)\n        {\n            if (this.observer != null)\n            {\n                foreach (var batchContainer in batchContainerBatch.BatchContainers)\n                {\n                    bool isRequestContextSet = batchContainer.ImportRequestContext();\n                    try\n                    {\n                        foreach (var itemTuple in batchContainer.GetEvents<T>())\n                        {\n                            await NextItem(itemTuple.Item1, itemTuple.Item2);\n                        }\n                    }\n                    finally\n                    {\n                        if (isRequestContextSet)\n                        {\n                            RequestContext.Clear();\n                        }\n                    }\n                }\n            }\n            else\n            {\n                await NextItems(batchContainerBatch.BatchContainers.SelectMany(batch => batch.GetEvents<T>()));\n            }\n        }\n\n        private Task NextItem(T item, StreamSequenceToken token)\n        {\n            // This method could potentially be invoked after Dispose() has been called, \n            // so we have to ignore the request or we risk breaking unit tests AQ_01 - AQ_04.\n            if (this.observer == null || !IsValid)\n                return Task.CompletedTask;\n\n            return this.observer.OnNextAsync(item, token);\n        }\n\n        private Task NextItems(IEnumerable<Tuple<T, StreamSequenceToken>> items)\n        {\n            // This method could potentially be invoked after Dispose() has been called, \n            // so we have to ignore the request or we risk breaking unit tests AQ_01 - AQ_04.\n            if (this.batchObserver == null || !IsValid)\n                return Task.CompletedTask;\n\n            IList<SequentialItem<T>> batch = items\n                .Select(item => new SequentialItem<T>(item.Item1, item.Item2))\n                .ToList();\n\n            return batch.Count != 0 ? this.batchObserver.OnNextAsync(batch) : Task.CompletedTask;\n        }\n\n        public Task CompleteStream()\n        {\n            return this.observer is null\n                ? this.batchObserver is null\n                    ? Task.CompletedTask\n                    : this.batchObserver.OnCompletedAsync()\n                : this.observer.OnCompletedAsync();\n        }\n\n        public Task ErrorInStream(Exception ex)\n        {\n            return this.observer is null\n                ? this.batchObserver is null\n                    ? Task.CompletedTask\n                    : this.batchObserver.OnErrorAsync(ex)\n                : this.observer.OnErrorAsync(ex);\n        }\n\n        internal bool SameStreamId(QualifiedStreamId streamId)\n        {\n            return IsValid && streamImpl.InternalStreamId.Equals(streamId);\n        }\n\n        public override bool Equals(StreamSubscriptionHandle<T> other)\n        {\n            var o = other as StreamSubscriptionHandleImpl<T>;\n            return o != null && SubscriptionId.Equals(o.SubscriptionId);\n        }\n\n        public override bool Equals(object obj)\n        {\n            return Equals(obj as StreamSubscriptionHandle<T>);\n        }\n\n        public override int GetHashCode()\n        {\n            return SubscriptionId.GetHashCode();\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"StreamSubscriptionHandleImpl:Stream={0},HandleId={1}\", IsValid ? streamImpl.InternalStreamId.ToString() : \"null\", HandleId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Internal/StreamSubsriptionHandlerFactory.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Factory for creating <see cref=\"StreamSubscriptionHandle{T}\"/> instances.\n    /// </summary>\n    public class StreamSubscriptionHandlerFactory : IStreamSubscriptionHandleFactory\n    {\n        private readonly IStreamProvider streamProvider;\n        \n        /// <inheritdoc />\n        public StreamId StreamId { get; }\n\n        /// <inheritdoc />\n        public string ProviderName { get; }\n\n        /// <inheritdoc />\n        public GuidId SubscriptionId { get; }\n                        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamSubscriptionHandlerFactory\"/> class.\n        /// </summary>        \n        /// <param name=\"streamProvider\">\n        /// The stream provider.\n        /// </param>\n        /// <param name=\"streamId\">\n        /// The stream identity.\n        /// </param>\n        /// <param name=\"providerName\">\n        /// The stream provider name.\n        /// </param>\n        /// <param name=\"subscriptionId\">\n        /// The subscription identity.\n        /// </param>\n        public StreamSubscriptionHandlerFactory(IStreamProvider streamProvider, StreamId streamId, string providerName, GuidId subscriptionId)\n        {\n            this.streamProvider = streamProvider ?? throw new ArgumentNullException(nameof(streamProvider));\n            this.StreamId = streamId;\n            this.ProviderName = providerName;\n            this.SubscriptionId = subscriptionId;\n        }\n\n        /// <inheritdoc />\n        public StreamSubscriptionHandle<T> Create<T>()\n        {\n            var stream = this.streamProvider.GetStream<T>(StreamId) as StreamImpl<T>;\n            return new StreamSubscriptionHandleImpl<T>(SubscriptionId, stream);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/InternalStreamId.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    [Immutable]\n    [Serializable]\n    [GenerateSerializer]\n    public readonly struct QualifiedStreamId : IEquatable<QualifiedStreamId>, IComparable<QualifiedStreamId>, ISerializable, ISpanFormattable\n    {\n        [Id(0)]\n        public readonly StreamId StreamId;\n\n        [Id(1)]\n        public readonly string ProviderName;\n\n        public QualifiedStreamId(string providerName, StreamId streamId)\n        {\n            ProviderName = providerName;\n            StreamId = streamId;\n        }\n\n        private QualifiedStreamId(SerializationInfo info, StreamingContext context)\n        {\n            ProviderName = info.GetString(\"pvn\")!;\n            StreamId = (StreamId)info.GetValue(\"sid\", typeof(StreamId))!;\n        }\n\n        public static implicit operator StreamId(QualifiedStreamId internalStreamId) => internalStreamId.StreamId;\n\n        public bool Equals(QualifiedStreamId other) => StreamId.Equals(other) && ProviderName.Equals(other.ProviderName);\n\n        public override bool Equals(object? obj) => obj is QualifiedStreamId other ? this.Equals(other) : false;\n\n        public static bool operator ==(QualifiedStreamId s1, QualifiedStreamId s2) => s1.Equals(s2);\n\n        public static bool operator !=(QualifiedStreamId s1, QualifiedStreamId s2) => !s2.Equals(s1);\n\n        public int CompareTo(QualifiedStreamId other) => StreamId.CompareTo(other.StreamId);\n\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"pvn\", ProviderName);\n            info.AddValue(\"sid\", StreamId, typeof(StreamId));\n        }\n\n        public override int GetHashCode() => HashCode.Combine(ProviderName, StreamId);\n\n        public override string ToString() => $\"{ProviderName}/{StreamId}\";\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n            => destination.TryWrite($\"{ProviderName}/{StreamId}\", out charsWritten);\n\n        internal string? GetNamespace() => StreamId.GetNamespace();\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/JsonConverters/StreamImplConverter.cs",
    "content": "#nullable enable\n\nusing System;\nusing System.Runtime.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.JsonConverters\n{\n    internal class StreamImplConverter : JsonConverter\n    {\n        private readonly IRuntimeClient _runtimeClient;\n\n        public StreamImplConverter(IRuntimeClient runtimeClient)\n        {\n            _runtimeClient = runtimeClient;\n        }\n\n        public override bool CanConvert(Type objectType)\n            => objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(StreamImpl<>) || objectType.GetGenericTypeDefinition() == typeof(IAsyncStream<>));\n\n        public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)\n        {\n            var jo = JObject.Load(reader);\n            if (jo != null)\n            {\n                var itemType = objectType.GetGenericArguments()[0];\n                var fullType = typeof(StreamImpl<>).MakeGenericType(itemType);\n\n                var streamId = jo[\"streamId\"]?.ToObject<StreamId>();\n                var providerName = jo[\"providerName\"]?.Value<string>();\n                var isRewindable = jo[\"isRewindable\"]?.ToObject<bool>();\n\n                if (streamId.HasValue && isRewindable.HasValue && !string.IsNullOrWhiteSpace(providerName))\n                {\n                    var provider = _runtimeClient.ServiceProvider.GetRequiredKeyedService<IStreamProvider>(providerName) as IInternalStreamProvider;\n                    return Activator.CreateInstance(fullType, new QualifiedStreamId(providerName, streamId.Value), provider, isRewindable.Value, _runtimeClient);\n                }\n            }\n            throw new SerializationException();\n        }\n\n        public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)\n        {\n            writer.WriteStartObject();\n            if (value is IAsyncStream target)\n            {\n                writer.WritePropertyName(\"streamId\");\n                serializer.Serialize(writer, target.StreamId);\n                writer.WritePropertyName(\"providerName\");\n                serializer.Serialize(writer, target.ProviderName);\n                writer.WritePropertyName(\"isRewindable\");\n                writer.WriteValue(target.IsRewindable);\n            }\n            writer.WriteEndObject();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/JsonConverters/StreamingConverterConfigurator.cs",
    "content": "#nullable enable\n\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streaming.JsonConverters\n{\n    internal class StreamingConverterConfigurator : IPostConfigureOptions<OrleansJsonSerializerOptions>\n    {\n        private readonly IRuntimeClient _runtimeClient;\n\n        public StreamingConverterConfigurator(IRuntimeClient runtimeClient)\n        {\n            _runtimeClient = runtimeClient;\n        }\n\n        public void PostConfigure(string? name, OrleansJsonSerializerOptions options)\n        {\n            options.JsonSerializerSettings.Converters.Add(new StreamImplConverter(_runtimeClient));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/LoadShedQueueFlowController.cs",
    "content": "\nusing System;\nusing Orleans.Configuration;\nusing Orleans.Statistics;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Flow control triggered by silo load shedding.\n    /// This is an all-or-nothing trigger which will request <see cref=\"int.MaxValue\"/>, or <c>0</c>.\n    /// </summary>\n    public class LoadShedQueueFlowController : IQueueFlowController\n    {\n        private readonly LoadSheddingOptions options;\n        private readonly double loadSheddingLimit;\n        private readonly IEnvironmentStatisticsProvider environmentStatisticsProvider;\n\n        /// <summary>\n        /// Creates a flow controller triggered when the CPU reaches a percentage of the cluster load shedding limit.\n        /// This is intended to reduce queue read rate prior to causing the silo to shed load.\n        /// Note:  Triggered only when load shedding is enabled.\n        /// </summary>\n        /// <param name=\"options\">The silo statistics options.</param>\n        /// <param name=\"percentOfSiloSheddingLimit\">Percentage of load shed limit which triggers a reduction of queue read rate.</param>\n        /// <param name=\"environmentStatisticsProvider\">The silo environment statistics.</param>\n        /// <returns>The flow controller.</returns>\n        public static IQueueFlowController CreateAsPercentOfLoadSheddingLimit(LoadSheddingOptions options, IEnvironmentStatisticsProvider environmentStatisticsProvider, int percentOfSiloSheddingLimit = LoadSheddingOptions.DefaultCpuThreshold)\n        {\n            if (percentOfSiloSheddingLimit < 0.0 || percentOfSiloSheddingLimit > 100.0) throw new ArgumentOutOfRangeException(nameof(percentOfSiloSheddingLimit), \"Percent value must be between 0-100\");\n            // Start shedding before silo reaches shedding limit.\n            return new LoadShedQueueFlowController((int)(options.CpuThreshold * (percentOfSiloSheddingLimit / 100.0)), options, environmentStatisticsProvider);\n        }\n\n        /// <summary>\n        /// Creates a flow controller triggered when the CPU reaches the specified limit.\n        /// Note:  Triggered only when load shedding is enabled.\n        /// </summary>\n        /// <param name=\"loadSheddingLimit\">Percentage of CPU which triggers queue read rate reduction</param>\n        /// <param name=\"options\">The silo statistics options.</param>\n        /// <param name=\"environmentStatisticsProvider\">The silo environment statistics.</param>\n        /// <returns>The flow controller.</returns>\n        public static IQueueFlowController CreateAsPercentageOfCPU(int loadSheddingLimit, LoadSheddingOptions options, IEnvironmentStatisticsProvider environmentStatisticsProvider)\n        {\n            if (loadSheddingLimit < 0 || loadSheddingLimit > 100) throw new ArgumentOutOfRangeException(nameof(loadSheddingLimit), \"Value must be between 0-100\");\n            return new LoadShedQueueFlowController(loadSheddingLimit, options, environmentStatisticsProvider);\n        }\n\n        private LoadShedQueueFlowController(int loadSheddingLimit, LoadSheddingOptions options, IEnvironmentStatisticsProvider environmentStatisticsProvider)\n        {\n            this.options = options;\n            if (loadSheddingLimit < 0 || loadSheddingLimit > 100) throw new ArgumentOutOfRangeException(nameof(loadSheddingLimit), \"Value must be between 0-100\");\n            this.loadSheddingLimit = loadSheddingLimit != 0 ? loadSheddingLimit : int.MaxValue;\n            this.environmentStatisticsProvider = environmentStatisticsProvider;\n        }\n\n        /// <inheritdoc/>\n        public int GetMaxAddCount()\n        {\n            return options.LoadSheddingEnabled && environmentStatisticsProvider.GetEnvironmentStatistics().FilteredCpuUsagePercentage > loadSheddingLimit ? 0 : int.MaxValue;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/IMemoryStreamQueueGrain.cs",
    "content": "\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Interface for In-memory stream queue grain.\n    /// </summary>\n    public interface IMemoryStreamQueueGrain : IGrainWithGuidKey\n    {\n        /// <summary>\n        /// Enqueues an event.\n        /// </summary>\n        /// <param name=\"data\">The data.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Enqueue(MemoryMessageData data);\n\n        /// <summary>\n        /// Dequeues up to <paramref name=\"maxCount\"/> events.\n        /// </summary>\n        /// <param name=\"maxCount\">\n        /// The maximum number of events to dequeue.\n        /// </param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task<List<MemoryMessageData>> Dequeue(int maxCount);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryAdapterFactory.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.IO.Hashing;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Adapter factory for in memory stream provider.\n    /// This factory acts as the adapter and the adapter factory.  The events are stored in an in-memory grain that \n    /// behaves as an event queue, this provider adapter is primarily used for testing\n    /// </summary>\n    public partial class MemoryAdapterFactory<TSerializer> : IQueueAdapterFactory, IQueueAdapter, IQueueAdapterCache\n        where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        private readonly StreamCacheEvictionOptions cacheOptions;\n        private readonly StreamStatisticOptions statisticOptions;\n        private readonly HashRingStreamQueueMapperOptions queueMapperOptions;\n        private readonly IGrainFactory grainFactory;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ILogger logger;\n        private readonly TSerializer serializer;\n        private readonly ulong _nameHash;\n        private IStreamQueueMapper streamQueueMapper;\n        private ConcurrentDictionary<QueueId, IMemoryStreamQueueGrain> queueGrains;\n        private IObjectPool<FixedSizeBuffer> bufferPool;\n        private BlockPoolMonitorDimensions blockPoolMonitorDimensions;\n        private IStreamFailureHandler streamFailureHandler;\n        private TimePurgePredicate purgePredicate;\n\n        /// <inheritdoc />\n        public string Name { get; }\n\n        /// <inheritdoc />\n        public bool IsRewindable => true;\n\n        /// <inheritdoc />\n        public StreamProviderDirection Direction => StreamProviderDirection.ReadWrite;\n\n        /// <summary>\n        /// Creates a failure handler for a partition.\n        /// </summary>\n        protected Func<string, Task<IStreamFailureHandler>> StreamFailureHandlerFactory { get; set; }\n\n        /// <summary>\n        /// Create a cache monitor to report cache related metrics\n        /// Return a ICacheMonitor\n        /// </summary>\n        protected Func<CacheMonitorDimensions, ICacheMonitor> CacheMonitorFactory;\n\n        /// <summary>\n        /// Create a block pool monitor to monitor block pool related metrics\n        /// Return a IBlockPoolMonitor\n        /// </summary>\n        protected Func<BlockPoolMonitorDimensions, IBlockPoolMonitor> BlockPoolMonitorFactory;\n\n        /// <summary>\n        /// Create a monitor to monitor QueueAdapterReceiver related metrics\n        /// Return a IQueueAdapterReceiverMonitor\n        /// </summary>\n        protected Func<ReceiverMonitorDimensions, IQueueAdapterReceiverMonitor> ReceiverMonitorFactory;\n\n        public MemoryAdapterFactory(\n            string providerName,\n            StreamCacheEvictionOptions cacheOptions,\n            StreamStatisticOptions statisticOptions,\n            HashRingStreamQueueMapperOptions queueMapperOptions,\n            IServiceProvider serviceProvider,\n            IGrainFactory grainFactory,\n            ILoggerFactory loggerFactory)\n        {\n            this.Name = providerName;\n            this.queueMapperOptions = queueMapperOptions ?? throw new ArgumentNullException(nameof(queueMapperOptions));\n            this.cacheOptions = cacheOptions ?? throw new ArgumentNullException(nameof(cacheOptions));\n            this.statisticOptions = statisticOptions ?? throw new ArgumentException(nameof(statisticOptions));\n            this.grainFactory = grainFactory ?? throw new ArgumentNullException(nameof(grainFactory));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.logger = loggerFactory.CreateLogger<ILogger<MemoryAdapterFactory<TSerializer>>>();\n            this.serializer = MemoryMessageBodySerializerFactory<TSerializer>.GetOrCreateSerializer(serviceProvider);\n\n            var nameBytes = BitConverter.IsLittleEndian ? MemoryMarshal.AsBytes(Name.AsSpan()) : Encoding.Unicode.GetBytes(Name);\n            XxHash64.Hash(nameBytes, MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref _nameHash, 1)));\n        }\n\n        /// <summary>\n        /// Initializes this instance.\n        /// </summary>\n        public void Init()\n        {\n            this.queueGrains = new ConcurrentDictionary<QueueId, IMemoryStreamQueueGrain>();\n            if (CacheMonitorFactory == null)\n                this.CacheMonitorFactory = (dimensions) => new DefaultCacheMonitor(dimensions);\n            if (this.BlockPoolMonitorFactory == null)\n                this.BlockPoolMonitorFactory = (dimensions) => new DefaultBlockPoolMonitor(dimensions);\n            if (this.ReceiverMonitorFactory == null)\n                this.ReceiverMonitorFactory = (dimensions) => new DefaultQueueAdapterReceiverMonitor(dimensions);\n            this.purgePredicate = new TimePurgePredicate(this.cacheOptions.DataMinTimeInCache, this.cacheOptions.DataMaxAgeInCache);\n            this.streamQueueMapper = new HashRingBasedStreamQueueMapper(this.queueMapperOptions, this.Name);\n        }\n\n        private void CreateBufferPoolIfNotCreatedYet()\n        {\n            if (this.bufferPool == null)\n            {\n                // 1 meg block size pool\n                this.blockPoolMonitorDimensions = new BlockPoolMonitorDimensions($\"BlockPool-{Guid.NewGuid()}\");\n                var oneMb = 1 << 20;\n                var objectPoolMonitor = new ObjectPoolMonitorBridge(this.BlockPoolMonitorFactory(blockPoolMonitorDimensions), oneMb);\n                this.bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(oneMb), objectPoolMonitor, this.statisticOptions.StatisticMonitorWriteInterval);\n            }\n        }\n\n        /// <inheritdoc />\n        public Task<IQueueAdapter> CreateAdapter()\n        {\n            return Task.FromResult<IQueueAdapter>(this);\n        }\n\n        /// <inheritdoc />\n        public IQueueAdapterCache GetQueueAdapterCache()\n        {\n            return this;\n        }\n\n        /// <inheritdoc />\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            return streamQueueMapper;\n        }\n\n        /// <inheritdoc />\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n        {\n            var dimensions = new ReceiverMonitorDimensions(queueId.ToString());\n            var receiverLogger = this.loggerFactory.CreateLogger($\"{typeof(MemoryAdapterReceiver<TSerializer>).FullName}.{this.Name}.{queueId}\");\n            var receiverMonitor = this.ReceiverMonitorFactory(dimensions);\n            IQueueAdapterReceiver receiver = new MemoryAdapterReceiver<TSerializer>(GetQueueGrain(queueId), receiverLogger, this.serializer, receiverMonitor);\n            return receiver;\n        }\n\n        /// <inheritdoc />\n        public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            try\n            {\n                var queueId = streamQueueMapper.GetQueueForStream(streamId);\n                ArraySegment<byte> bodyBytes = serializer.Serialize(new MemoryMessageBody(events.Cast<object>(), requestContext));\n                var messageData = MemoryMessageData.Create(streamId, bodyBytes);\n                IMemoryStreamQueueGrain queueGrain = GetQueueGrain(queueId);\n                await queueGrain.Enqueue(messageData);\n            }\n            catch (Exception exc)\n            {\n                LogErrorQueueMessageBatchAsync(exc);\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public IQueueCache CreateQueueCache(QueueId queueId)\n        {\n            //move block pool creation from init method to here, to avoid unnecessary block pool creation when stream provider is initialized in client side. \n            CreateBufferPoolIfNotCreatedYet();\n            var logger = this.loggerFactory.CreateLogger($\"{typeof(MemoryPooledCache<TSerializer>).FullName}.{this.Name}.{queueId}\");\n            var monitor = this.CacheMonitorFactory(new CacheMonitorDimensions(queueId.ToString(), this.blockPoolMonitorDimensions.BlockPoolId));\n            return new MemoryPooledCache<TSerializer>(bufferPool, purgePredicate, logger, this.serializer, monitor, this.statisticOptions.StatisticMonitorWriteInterval, this.cacheOptions.MetadataMinTimeInCache);\n        }\n\n        /// <inheritdoc />\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            return Task.FromResult(streamFailureHandler ?? (streamFailureHandler = new NoOpStreamDeliveryFailureHandler()));\n        }\n\n        /// <summary>\n        /// Generate a deterministic Guid from a queue Id. \n        /// </summary>\n        private Guid GenerateDeterministicGuid(QueueId queueId)\n        {\n            Span<byte> bytes = stackalloc byte[16];\n            MemoryMarshal.Write(bytes, in _nameHash);\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[8..], queueId.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[12..], queueId.GetNumericId());\n            return new(bytes);\n        }\n\n        /// <summary>\n        /// Get a MemoryStreamQueueGrain instance by queue Id. \n        /// </summary>\n        private IMemoryStreamQueueGrain GetQueueGrain(QueueId queueId)\n        {\n            return queueGrains.GetOrAdd(queueId, (id, arg) => arg.grainFactory.GetGrain<IMemoryStreamQueueGrain>(arg.instance.GenerateDeterministicGuid(id)), (instance: this, grainFactory));\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"MemoryAdapterFactory{TSerializer}\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The provider name.</param>\n        /// <returns>A mew <see cref=\"MemoryAdapterFactory{TSerializer}\"/> instance.</returns>\n        public static MemoryAdapterFactory<TSerializer> Create(IServiceProvider services, string name)\n        {\n            var cachePurgeOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            var queueMapperOptions = services.GetOptionsByName<HashRingStreamQueueMapperOptions>(name);\n            var factory = ActivatorUtilities.CreateInstance<MemoryAdapterFactory<TSerializer>>(services, name, cachePurgeOptions, statisticOptions, queueMapperOptions);\n            factory.Init();\n            return factory;\n        }\n\n        [LoggerMessage(\n            EventId = (int)ProviderErrorCode.MemoryStreamProviderBase_QueueMessageBatchAsync,\n            Level = LogLevel.Error,\n            Message = \"Exception thrown in MemoryAdapterFactory.QueueMessageBatchAsync.\"\n        )]\n        private partial void LogErrorQueueMessageBatchAsync(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryAdapterReceiver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers\n{\n    internal partial class MemoryAdapterReceiver<TSerializer> : IQueueAdapterReceiver\n        where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        private readonly IMemoryStreamQueueGrain queueGrain;\n        private readonly List<Task> awaitingTasks;\n        private readonly ILogger logger;\n        private readonly TSerializer serializer;\n        private readonly IQueueAdapterReceiverMonitor receiverMonitor;\n\n        public MemoryAdapterReceiver(IMemoryStreamQueueGrain queueGrain, ILogger logger, TSerializer serializer, IQueueAdapterReceiverMonitor receiverMonitor)\n        {\n            this.queueGrain = queueGrain;\n            this.logger = logger;\n            this.serializer = serializer;\n            awaitingTasks = new List<Task>();\n            this.receiverMonitor = receiverMonitor;\n        }\n\n        public Task Initialize(TimeSpan timeout)\n        {\n            this.receiverMonitor?.TrackInitialization(true, TimeSpan.MinValue, null);\n            return Task.CompletedTask;\n        }\n\n        public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n        {\n            var watch = Stopwatch.StartNew();\n            List<IBatchContainer> batches;\n            Task<List<MemoryMessageData>> task = null;\n            try\n            {\n                task = queueGrain.Dequeue(maxCount);\n                awaitingTasks.Add(task);\n                var eventData = await task;\n                batches = eventData.Select(data => new MemoryBatchContainer<TSerializer>(data, this.serializer)).ToList<IBatchContainer>();\n                watch.Stop();\n                this.receiverMonitor?.TrackRead(true, watch.Elapsed, null);\n                if (eventData.Count > 0)\n                {\n                    var oldestMessage = eventData[0];\n                    var newestMessage = eventData[eventData.Count - 1];\n                    this.receiverMonitor?.TrackMessagesReceived(eventData.Count, oldestMessage.EnqueueTimeUtc, newestMessage.EnqueueTimeUtc);\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorGetQueueMessagesAsync(exc);\n                watch.Stop();\n                this.receiverMonitor?.TrackRead(true, watch.Elapsed, exc);\n                throw;\n            }\n            finally\n            {\n                awaitingTasks.Remove(task);\n            }\n            return batches;\n        }\n\n        public Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task Shutdown(TimeSpan timeout)\n        {\n            var watch = Stopwatch.StartNew();\n            try\n            {\n                if (awaitingTasks.Count != 0)\n                {\n                    await Task.WhenAll(awaitingTasks);\n                }\n                watch.Stop();\n                this.receiverMonitor?.TrackShutdown(true, watch.Elapsed, null);\n            }\n            catch (Exception ex)\n            {\n                watch.Stop();\n                this.receiverMonitor?.TrackShutdown(false, watch.Elapsed, ex);\n            }\n        }\n\n        [LoggerMessage(\n            EventId = (int)ProviderErrorCode.MemoryStreamProviderBase_GetQueueMessagesAsync,\n            Level = LogLevel.Error,\n            Message = \"Exception thrown in MemoryAdapterFactory.GetQueueMessagesAsync.\"\n        )]\n        private partial void LogErrorGetQueueMessagesAsync(Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryBatchContainer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers\n{\n    [Serializable]\n    [GenerateSerializer]\n    [SerializationCallbacks(typeof(OnDeserializedCallbacks))]\n    internal sealed class MemoryBatchContainer<TSerializer> : IBatchContainer, IOnDeserialized\n        where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        [NonSerialized]\n        private TSerializer serializer;\n        [Id(0)]\n        private readonly EventSequenceToken realToken;\n\n        public StreamId StreamId => MessageData.StreamId;\n        public StreamSequenceToken SequenceToken => realToken;\n\n        [Id(1)]\n        public MemoryMessageData MessageData { get; set; }\n        public long SequenceNumber => realToken.SequenceNumber;\n\n        // Payload is local cache of deserialized payloadBytes.  Should never be serialized as part of batch container.  During batch container serialization raw payloadBytes will always be used.\n        [NonSerialized] private MemoryMessageBody payload;\n         \n        private MemoryMessageBody Payload()\n        {\n            return payload ?? (payload = serializer.Deserialize(MessageData.Payload));\n        }\n        \n        public MemoryBatchContainer(MemoryMessageData messageData, TSerializer serializer)\n        {\n            this.serializer = serializer;\n            MessageData = messageData;\n            realToken = new EventSequenceToken(messageData.SequenceNumber);\n        }\n\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return Payload().Events.Cast<T>().Select((e, i) => Tuple.Create<T, StreamSequenceToken>(e, realToken.CreateSequenceTokenForEvent(i)));\n        }\n\n        public bool ImportRequestContext()\n        {\n            var context = Payload().RequestContext;\n            if (context != null)\n            {\n                RequestContextExtensions.Import(context);\n                return true;\n            }\n            return false;\n        }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            this.serializer = MemoryMessageBodySerializerFactory<TSerializer>.GetOrCreateSerializer(context.ServiceProvider);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryMessageBody.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Implementations of this interface are responsible for serializing MemoryMessageBody objects\n    /// </summary>\n    public interface IMemoryMessageBodySerializer\n    {\n        /// <summary>\n        /// Serialize <see cref=\"MemoryMessageBody\"/> to an array segment of bytes.\n        /// </summary>\n        /// <param name=\"body\">The body.</param>\n        /// <returns>The serialized data.</returns>\n        ArraySegment<byte> Serialize(MemoryMessageBody body);\n\n        /// <summary>\n        /// Deserialize an array segment into a <see cref=\"MemoryMessageBody\"/>\n        /// </summary>\n        /// <param name=\"bodyBytes\">The body bytes.</param>\n        /// <returns>The deserialized message body.</returns>\n        MemoryMessageBody Deserialize(ArraySegment<byte> bodyBytes);\n    }\n\n    /// <summary>\n    /// Default <see cref=\"IMemoryMessageBodySerializer\"/> implementation.\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    [SerializationCallbacks(typeof(Runtime.OnDeserializedCallbacks))]\n    public sealed class DefaultMemoryMessageBodySerializer : IMemoryMessageBodySerializer, IOnDeserialized\n    {\n        [NonSerialized]\n        private Serializer<MemoryMessageBody> serializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DefaultMemoryMessageBodySerializer\" /> class.\n        /// </summary>\n        /// <param name=\"serializer\">The serializer.</param>\n        public DefaultMemoryMessageBodySerializer(Serializer<MemoryMessageBody> serializer)\n        {\n            this.serializer = serializer;\n        }\n\n        /// <inheritdoc />\n        public ArraySegment<byte> Serialize(MemoryMessageBody body)\n        {\n            return new ArraySegment<byte>(serializer.SerializeToArray(body));\n        }\n\n        /// <inheritdoc />\n        public MemoryMessageBody Deserialize(ArraySegment<byte> bodyBytes)\n        {\n            return serializer.Deserialize(bodyBytes.ToArray());\n        }\n\n        /// <inheritdoc />\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            this.serializer = context.ServiceProvider.GetRequiredService<Serializer<MemoryMessageBody>>();\n        }\n    }\n\n    /// <summary>\n    /// Message body used by the in-memory stream provider.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class MemoryMessageBody\n    {        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MemoryMessageBody\"/> class.\n        /// </summary>\n        /// <param name=\"events\">Events that are part of this message.</param>\n        /// <param name=\"requestContext\">Context in which this message was sent.</param>        \n        public MemoryMessageBody(IEnumerable<object> events, Dictionary<string, object> requestContext)\n        {\n            if (events == null) throw new ArgumentNullException(nameof(events));\n            Events = events.ToList();\n            RequestContext = requestContext;\n        }\n\n        /// <summary>\n        /// Gets the events in the message.\n        /// </summary>\n        [Id(0)]\n        public List<object> Events { get; }\n\n        /// <summary>\n        /// Gets the message request context.\n        /// </summary>\n        [Id(1)]\n        public Dictionary<string, object> RequestContext { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryMessageBodySerializerFactory.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Providers\n{\n    internal static class MemoryMessageBodySerializerFactory<TSerializer>\n        where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        private static readonly Lazy<ObjectFactory> ObjectFactory = new Lazy<ObjectFactory>(\n            () => ActivatorUtilities.CreateFactory(\n                typeof(TSerializer),\n                Type.EmptyTypes));\n\n        public static TSerializer GetOrCreateSerializer(IServiceProvider serviceProvider)\n        {\n            return serviceProvider.GetService<TSerializer>() ??\n                   (TSerializer) ObjectFactory.Value(serviceProvider, null);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryMessageData.cs",
    "content": "\nusing System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Represents the event sent and received from an In-Memory queue grain. \n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public struct MemoryMessageData\n    {\n        /// <summary>\n        /// The stream identifier.\n        /// </summary>\n        [Id(0)]\n        public StreamId StreamId;\n\n        /// <summary>\n        /// The position of the event in the stream.\n        /// </summary>\n        [Id(1)]\n        public long SequenceNumber;\n\n        /// <summary>\n        /// The time this message was read from the message queue.\n        /// </summary>\n        [Id(2)]\n        public DateTime DequeueTimeUtc;\n\n        /// <summary>\n        /// The time message was written to the message queue.\n        /// </summary>\n        [Id(3)]\n        public DateTime EnqueueTimeUtc;\n\n        /// <summary>\n        /// The serialized event data.\n        /// </summary>\n        [Id(4)]\n        public ArraySegment<byte> Payload;\n\n        internal static MemoryMessageData Create(StreamId streamId, ArraySegment<byte> arraySegment)\n        {\n            return new MemoryMessageData\n            {\n                StreamId = streamId,\n                EnqueueTimeUtc = DateTime.UtcNow,\n                Payload = arraySegment\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryPooledCache.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Pooled cache for memory stream provider\n    /// </summary>\n    public class MemoryPooledCache<TSerializer> : IQueueCache, ICacheDataAdapter\n        where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        private readonly IObjectPool<FixedSizeBuffer> bufferPool;\n        private readonly TSerializer serializer;\n        private readonly IEvictionStrategy evictionStrategy;\n        private readonly PooledQueueCache cache;\n\n        private FixedSizeBuffer currentBuffer;\n\n        /// <summary>\n        /// Pooled cache for memory stream provider.\n        /// </summary>\n        /// <param name=\"bufferPool\">The buffer pool.</param>\n        /// <param name=\"purgePredicate\">The purge predicate.</param>\n        /// <param name=\"logger\">The logger.</param>\n        /// <param name=\"serializer\">The serializer.</param>\n        /// <param name=\"cacheMonitor\">The cache monitor.</param>\n        /// <param name=\"monitorWriteInterval\">The monitor write interval.</param>\n        public MemoryPooledCache(\n            IObjectPool<FixedSizeBuffer> bufferPool,\n            TimePurgePredicate purgePredicate,\n            ILogger logger,\n            TSerializer serializer,\n            ICacheMonitor cacheMonitor,\n            TimeSpan? monitorWriteInterval,\n            TimeSpan? purgeMetadataInterval)\n        {\n            this.bufferPool = bufferPool;\n            this.serializer = serializer;\n            this.cache = new PooledQueueCache(this, logger, cacheMonitor, monitorWriteInterval, purgeMetadataInterval);\n            this.evictionStrategy = new ChronologicalEvictionStrategy(logger, purgePredicate, cacheMonitor, monitorWriteInterval) {PurgeObservable = cache};\n        }\n\n        private CachedMessage QueueMessageToCachedMessage(MemoryMessageData queueMessage, DateTime dequeueTimeUtc)\n        {\n            StreamPosition streamPosition = GetStreamPosition(queueMessage);\n            return new CachedMessage()\n            {\n                StreamId = streamPosition.StreamId,\n                SequenceNumber = queueMessage.SequenceNumber,\n                EnqueueTimeUtc = queueMessage.EnqueueTimeUtc,\n                DequeueTimeUtc = dequeueTimeUtc,\n                Segment = SerializeMessageIntoPooledSegment(queueMessage)\n            };\n        }\n\n        // Placed object message payload into a segment from a buffer pool.  When this get's too big, older blocks will be purged\n        private ArraySegment<byte> SerializeMessageIntoPooledSegment(MemoryMessageData queueMessage)\n        {\n            // serialize payload\n            int size = SegmentBuilder.CalculateAppendSize(queueMessage.Payload);\n\n            // get segment from current block\n            ArraySegment<byte> segment;\n            if (currentBuffer == null || !currentBuffer.TryGetSegment(size, out segment))\n            {\n                // no block or block full, get new block and try again\n                currentBuffer = bufferPool.Allocate();\n                //call EvictionStrategy's OnBlockAllocated method\n                this.evictionStrategy.OnBlockAllocated(currentBuffer);\n                // if this fails with clean block, then requested size is too big\n                if (!currentBuffer.TryGetSegment(size, out segment))\n                {\n                    string errmsg = string.Format(CultureInfo.InvariantCulture,\n                        \"Message size is too big. MessageSize: {0}\", size);\n                    throw new ArgumentOutOfRangeException(nameof(queueMessage), errmsg);\n                }\n            }\n            // encode namespace, offset, partitionkey, properties and payload into segment\n            int writeOffset = 0;\n            SegmentBuilder.Append(segment, ref writeOffset, queueMessage.Payload);\n            return segment;\n        }\n\n        private static StreamPosition GetStreamPosition(MemoryMessageData queueMessage)\n        {\n            return new StreamPosition(queueMessage.StreamId,\n                new EventSequenceTokenV2(queueMessage.SequenceNumber));\n        }\n\n        private class Cursor : IQueueCacheCursor\n        {\n            private readonly PooledQueueCache cache;\n            private readonly object cursor;\n            private IBatchContainer current;\n\n            public Cursor(PooledQueueCache cache, StreamId streamId,\n                StreamSequenceToken token)\n            {\n                this.cache = cache;\n                cursor = cache.GetCursor(streamId, token);\n            }\n\n            public void Dispose()\n            {\n            }\n\n            public IBatchContainer GetCurrent(out Exception exception)\n            {\n                exception = null;\n                return current;\n            }\n\n            public bool MoveNext()\n            {\n                IBatchContainer next;\n                if (!cache.TryGetNextMessage(cursor, out next))\n                {\n                    return false;\n                }\n\n                current = next;\n                return true;\n            }\n\n            public void Refresh(StreamSequenceToken token)\n            {\n            }\n\n            public void RecordDeliveryFailure()\n            {\n            }\n        }\n\n        /// <inheritdoc/>\n        public int GetMaxAddCount()\n        {\n            return 100;\n        }\n\n        /// <inheritdoc/>\n        public void AddToCache(IList<IBatchContainer> messages)\n        {\n            DateTime utcNow = DateTime.UtcNow;\n            List<CachedMessage> memoryMessages = messages\n                .Cast<MemoryBatchContainer<TSerializer>>()\n                .Select(container => container.MessageData)\n                .Select(batch => QueueMessageToCachedMessage(batch, utcNow))\n                .ToList();\n            cache.Add(memoryMessages, DateTime.UtcNow);\n        }\n\n        /// <inheritdoc/>\n        public bool TryPurgeFromCache(out IList<IBatchContainer> purgedItems)\n        {\n            purgedItems = null;\n            this.evictionStrategy.PerformPurge(DateTime.UtcNow);\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public IQueueCacheCursor GetCacheCursor(StreamId streamId, StreamSequenceToken token)\n        {\n            return new Cursor(cache, streamId, token);\n        }\n\n        /// <inheritdoc/>\n        public bool IsUnderPressure()\n        {\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage)\n        {\n            //Deserialize payload\n            int readOffset = 0;\n            ArraySegment<byte> payload = SegmentBuilder.ReadNextBytes(cachedMessage.Segment, ref readOffset);\n            MemoryMessageData message = MemoryMessageData.Create(cachedMessage.StreamId, new ArraySegment<byte>(payload.ToArray()));\n            message.SequenceNumber = cachedMessage.SequenceNumber;\n            return new MemoryBatchContainer<TSerializer>(message, this.serializer);\n        }\n\n        /// <inheritdoc/>\n        public StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n        {\n            return new EventSequenceToken(cachedMessage.SequenceNumber);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryStreamBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Configuration builder for memory streams.\n    /// </summary>\n    public interface IMemoryStreamConfigurator : INamedServiceConfigurator { }\n\n    /// <summary>\n    /// Configuration extensions for memory streams.\n    /// </summary>\n    public static class MemoryStreamConfiguratorExtensions\n    {\n        /// <summary>\n        /// Configures partitioning for memory streams.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"numOfQueues\">The number of queues.</param>\n        public static void ConfigurePartitioning(this IMemoryStreamConfigurator configurator, int numOfQueues = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n        {\n            configurator.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = numOfQueues));\n        }\n    }\n\n    /// <summary>\n    /// Silo-specific configuration builder for memory streams.\n    /// </summary>\n    public interface ISiloMemoryStreamConfigurator : IMemoryStreamConfigurator, ISiloRecoverableStreamConfigurator { }\n\n    /// <summary>\n    /// Configures memory streams.\n    /// </summary>\n    /// <typeparam name=\"TSerializer\">The message body serializer type, which must implement <see cref=\"IMemoryMessageBodySerializer\"/>.</typeparam>\n    public class SiloMemoryStreamConfigurator<TSerializer> : SiloRecoverableStreamConfigurator, ISiloMemoryStreamConfigurator\n          where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloMemoryStreamConfigurator{TSerializer}\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configureServicesDelegate\">The services configuration delegate.</param>\n        public SiloMemoryStreamConfigurator(\n            string name, Action<Action<IServiceCollection>> configureServicesDelegate)\n            : base(name, configureServicesDelegate, MemoryAdapterFactory<TSerializer>.Create)\n        {\n            this.ConfigureDelegate(services => services.ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name));\n        }\n    }\n\n    /// <summary>\n    /// Client-specific configuration builder for memory streams.\n    /// </summary>\n    public interface IClusterClientMemoryStreamConfigurator : IMemoryStreamConfigurator, IClusterClientPersistentStreamConfigurator { }\n\n    /// <summary>\n    /// Configures memory streams.\n    /// </summary>\n    /// <typeparam name=\"TSerializer\">The message body serializer type, which must implement <see cref=\"IMemoryMessageBodySerializer\"/>.</typeparam>\n    public class ClusterClientMemoryStreamConfigurator<TSerializer> : ClusterClientPersistentStreamConfigurator, IClusterClientMemoryStreamConfigurator\n          where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ClusterClientMemoryStreamConfigurator{TSerializer}\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"builder\">The builder.</param>\n        public ClusterClientMemoryStreamConfigurator(string name, IClientBuilder builder)\n         : base(name, builder, MemoryAdapterFactory<TSerializer>.Create)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryStreamProviderBuilder.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Providers;\n\n[assembly: RegisterProvider(\"Memory\", \"Streaming\", \"Client\", typeof(MemoryStreamProviderBuilder))]\n[assembly: RegisterProvider(\"Memory\", \"Streaming\", \"Silo\", typeof(MemoryStreamProviderBuilder))]\nnamespace Orleans.Providers;\n\ninternal sealed class MemoryStreamProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddMemoryStreams(name);\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddMemoryStreams(name);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/MemoryStreams/MemoryStreamQueueGrain.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Providers\n{\n    /// <summary>\n    /// Memory stream queue grain. This grain works as a storage queue of event data. Enqueue and Dequeue operations are supported.\n    /// the max event count sets the max storage limit to the queue.\n    /// </summary>\n    public class MemoryStreamQueueGrain : Grain, IMemoryStreamQueueGrain, IGrainMigrationParticipant\n    {\n        private Queue<MemoryMessageData> _eventQueue = new Queue<MemoryMessageData>();\n        private long sequenceNumber = DateTime.UtcNow.Ticks;\n\n        /// <summary>\n        /// The maximum event count. \n        /// </summary>\n        private const int MaxEventCount = 16384;\n\n        /// <summary>\n        /// Enqueues an event data. If the current total count reaches the max limit. throws an exception.\n        /// </summary>\n        /// <param name=\"data\"></param>\n        /// <returns></returns>\n        public Task Enqueue(MemoryMessageData data)\n        {\n            if (_eventQueue.Count >= MaxEventCount)\n            {\n                throw new InvalidOperationException($\"Can not enqueue since the count has reached its maximum of {MaxEventCount}\");\n            }\n            data.SequenceNumber = sequenceNumber++;\n            _eventQueue.Enqueue(data);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Dequeues up to a max amount of maxCount event data from the queue.\n        /// </summary>\n        /// <param name=\"maxCount\"></param>\n        /// <returns></returns>\n        public Task<List<MemoryMessageData>> Dequeue(int maxCount)\n        {\n            List<MemoryMessageData> list = new List<MemoryMessageData>();\n\n            for (int i = 0; i < maxCount && _eventQueue.Count > 0; ++i)\n            {\n                list.Add(_eventQueue.Dequeue());\n            }\n\n            return Task.FromResult(list);\n        }\n\n        void IGrainMigrationParticipant.OnDehydrate(IDehydrationContext dehydrationContext)\n        {\n            dehydrationContext.TryAddValue(\"queue\", _eventQueue);\n        }\n\n        void IGrainMigrationParticipant.OnRehydrate(IRehydrationContext rehydrationContext)\n        {\n            if (rehydrationContext.TryGetValue(\"queue\", out Queue<MemoryMessageData> value))\n            {\n                _eventQueue = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Orleans.Streaming.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Streaming</PackageId>\n    <Title>Microsoft Orleans Streaming Library</Title>\n    <Description>Streaming library for Microsoft Orleans used both on the client and server.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"LoadTestGrains\" />\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.Tests\" />\n    <InternalsVisibleTo Include=\"TestExtensions\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IDeploymentConfiguration.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Interface for accessing the deployment configuration.\n    /// </summary>\n    public interface IDeploymentConfiguration\n    {\n        /// <summary>\n        /// Get the silo instance names for all configured silos.\n        /// </summary>\n        /// <returns>The list of silo names.</returns>\n        IList<string> GetAllSiloNames();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IPersistentStreamPullingAgent.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streams\n{\n    internal interface IPersistentStreamPullingAgent : ISystemTarget, IStreamProducerExtension\n    {\n        Task Initialize();\n        Task Shutdown();\n    }\n\n    internal interface IPersistentStreamPullingManager : ISystemTarget\n    {\n        Task Initialize();\n        Task Stop();\n        Task StartAgents();\n        Task StopAgents();\n        Task<object> ExecuteCommand(PersistentStreamProviderCommand command, object arg);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IQueueDataAdapter.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Converts event data to queue message\n    /// </summary>\n    public interface IQueueDataAdapter<TQueueMessage>\n    {\n        /// <summary>\n        /// Creates a cloud queue message from stream event data.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream event type.</typeparam>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"events\">The events.</param>\n        /// <param name=\"token\">The token.</param>\n        /// <param name=\"requestContext\">The request context.</param>\n        /// <returns>A new queue message.</returns>\n        TQueueMessage ToQueueMessage<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext);\n    }\n\n    /// <summary>\n    /// Converts event data to and from queue message\n    /// </summary>\n    /// <typeparam name=\"TQueueMessage\">The type of the queue message.</typeparam>\n    /// <typeparam name=\"TMessageBatch\">The type of the message batch.</typeparam>\n    public interface IQueueDataAdapter<TQueueMessage, TMessageBatch> : IQueueDataAdapter<TQueueMessage>\n    {\n        /// <summary>\n        /// Creates a batch container from a cloud queue message\n        /// </summary>\n        /// <param name=\"queueMessage\">The queue message.</param>\n        /// <param name=\"sequenceId\">The sequence identifier.</param>\n        /// <returns>The message batch.</returns>\n        TMessageBatch FromQueueMessage(TQueueMessage queueMessage, long sequenceId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IStreamFailureHandler.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Functionality for handling stream failures.\n    /// </summary>\n    public interface IStreamFailureHandler\n    {\n        /// <summary>\n        /// Gets a value indicating whether the subscription should fault when there is an error.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if the subscription should fault when there is an error; otherwise, <see langword=\"false\" />.</value>\n        bool ShouldFaultSubsriptionOnError { get; }\n\n        /// <summary>\n        /// Called once all measures to deliver an event to a consumer have been exhausted.\n        /// </summary>\n        /// <param name=\"subscriptionId\">The subscription identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamIdentity\">The stream identity.</param>\n        /// <param name=\"sequenceToken\">The sequence token.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task OnDeliveryFailure(GuidId subscriptionId, string streamProviderName, StreamId streamIdentity, StreamSequenceToken sequenceToken);\n\n        /// <summary>\n        /// Should be called when establishing a subscription failed.\n        /// </summary>\n        /// <param name=\"subscriptionId\">The subscription identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"streamIdentity\">The stream identity.</param>\n        /// <param name=\"sequenceToken\">The sequence token.</param>\n        /// <returns>A <see cref=\"Task\" /> representing the operation.</returns>\n        Task OnSubscriptionFailure(GuidId subscriptionId, string streamProviderName, StreamId streamIdentity, StreamSequenceToken sequenceToken);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IStreamQueueBalancer.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// The stream queue balancer is responsible for load balancing queues across all other related queue balancers.  It\n    /// notifies any listeners (<code>IStreamQueueBalanceListener</code>) of changes to the distribution of queues.\n    /// Method GetMyQueues, SubscribeToQueueDistributionChangeEvents, and UnSubscribeFromQueueDistributionChangeEvents will \n    /// likely be called in the IStreamQueueBalanceListener's thread so they need to be thread safe\n    /// </summary>\n    public interface IStreamQueueBalancer\n    {\n        /// <summary>\n        /// Initializes this instance.\n        /// </summary>\n        /// <param name=\"queueMapper\">The queue mapper.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Initialize(IStreamQueueMapper queueMapper);\n\n        /// <summary>\n        /// Shutdown the queue balancer.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Shutdown();\n\n        /// <summary>\n        /// Retrieves the latest queue distribution for this balancer.\n        /// </summary>\n        /// <returns>Queue allocated to this balancer.</returns>\n        IEnumerable<QueueId> GetMyQueues();\n\n        /// <summary>\n        /// Subscribes to receive queue distribution change notifications\n        /// </summary>\n        /// <param name=\"observer\">An observer interface to receive queue distribution change notifications.</param>\n        /// <returns>A value indicating whether subscription succeeded or not.</returns>\n        bool SubscribeToQueueDistributionChangeEvents(IStreamQueueBalanceListener observer);\n\n        /// <summary>\n        /// Unsubscribes from receiving queue distribution notifications.\n        /// </summary>\n        /// <param name=\"observer\">An observer interface to receive queue distribution change notifications.</param>\n        /// <returns>A value indicating whether teh unsubscription succeeded or not</returns>\n        bool UnSubscribeFromQueueDistributionChangeEvents(IStreamQueueBalanceListener observer);\n    }\n\n    /// <summary>\n    /// The stream queue balancer listener receives notifications from a stream queue balancer (<code>IStreamQueueBalancer</code>)\n    /// indicating that the balance of queues has changed.\n    /// It should be implemented by components interested in stream queue load balancing.\n    /// When change notification is received, listener should request updated list of queues from the queue balancer.\n    /// </summary>\n    public interface IStreamQueueBalanceListener\n    {\n        /// <summary>\n        /// Called when adapter queue responsibility changes. \n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task QueueDistributionChangeNotification();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/IStreamQueueCheckpointer.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Factory for creating <see cref=\"IStreamQueueCheckpointer{TCheckpoint}\"/> instances.\n    /// </summary>\n    public interface IStreamQueueCheckpointerFactory\n    {\n        /// <summary>\n        /// Creates a stream checkpointer for the specified partition.\n        /// </summary>\n        /// <param name=\"partition\">The partition.</param>\n        /// <returns>The stream checkpointer.</returns>\n        Task<IStreamQueueCheckpointer<string>> Create(string partition);\n    }\n\n    /// <summary>\n    /// Functionality for checkpointing a stream.\n    /// </summary>\n    /// <typeparam name=\"TCheckpoint\">The checkpoint type.</typeparam>\n    public interface IStreamQueueCheckpointer<TCheckpoint>\n    {\n        /// <summary>\n        /// Gets a value indicating whether a checkpoint exists.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if checkpoint exists; otherwise, <see langword=\"false\" />.</value>\n        bool CheckpointExists { get; }\n\n        /// <summary>\n        /// Loads the checkpoint.\n        /// </summary>\n        /// <returns>The checkpoint.</returns>\n        Task<TCheckpoint> Load();\n\n        /// <summary>\n        /// Updates the checkpoint.\n        /// </summary>\n        /// <param name=\"offset\">The offset.</param>\n        /// <param name=\"utcNow\">The current UTC time.</param>\n        void Update(TCheckpoint offset, DateTime utcNow);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/NoOpStreamFailureHandler.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// <see cref=\"IStreamFailureHandler\"/> which does nothing in response to failures.\n    /// </summary>\n    public class NoOpStreamDeliveryFailureHandler : IStreamFailureHandler\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NoOpStreamDeliveryFailureHandler\"/> class.\n        /// </summary>\n        public NoOpStreamDeliveryFailureHandler()\n            : this(false)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NoOpStreamDeliveryFailureHandler\"/> class.\n        /// </summary>\n        /// <param name=\"faultOnError\">The value used for <see cref=\"ShouldFaultSubsriptionOnError\"/>.</param>\n        public NoOpStreamDeliveryFailureHandler(bool faultOnError)\n        {\n            ShouldFaultSubsriptionOnError = faultOnError;\n        }\n\n        /// <inheritdoc/>\n        public bool ShouldFaultSubsriptionOnError { get; }\n\n        /// <inheritdoc/>\n        public Task OnDeliveryFailure(GuidId subscriptionId, string streamProviderName, StreamId streamId,\n            StreamSequenceToken sequenceToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc/>\n        public Task OnSubscriptionFailure(GuidId subscriptionId, string streamProviderName, StreamId streamId,\n            StreamSequenceToken sequenceToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/Options/PersistentStreamProviderOptions.cs",
    "content": "\nusing System;\nusing Orleans.Streams;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for managing stream system lifecycle.\n    /// </summary>\n    public class StreamLifecycleOptions\n    {\n        /// <summary>\n        /// Identifies well-known points in the lifecycle of the streaming system.\n        /// </summary>\n        [Serializable]\n        public enum RunState\n        {\n            /// <summary>\n            /// Not running.\n            /// </summary>\n            None,\n\n            /// <summary>\n            /// Streaming has initialized.\n            /// </summary>\n            Initialized,\n\n            /// <summary>\n            /// The agents have started.\n            /// </summary>\n            AgentsStarted,\n\n            /// <summary>\n            /// The agents have stopped.\n            /// </summary>\n            AgentsStopped,\n        }\n\n        /// <summary>\n        /// If set to <see cref=\"RunState.AgentsStarted\"/>, stream pulling agents will be started during initialization.\n        /// </summary>\n        public RunState StartupState { get; set; } = DEFAULT_STARTUP_STATE;\n\n        public const RunState DEFAULT_STARTUP_STATE = RunState.AgentsStarted;\n\n        /// <summary>\n        /// Gets or sets the lifecycle stage at which to initialize the stream runtime.\n        /// </summary>\n        /// <value>The initialization stage.</value>\n        public int InitStage { get; set; } = DEFAULT_INIT_STAGE;\n        public const int DEFAULT_INIT_STAGE = ServiceLifecycleStage.ApplicationServices;\n\n        /// <summary>\n        /// Gets or sets the lifecycle stage at which to start the stream runtime.\n        /// </summary>\n        /// <value>The startup stage.</value>\n        public int StartStage { get; set; } = DEFAULT_START_STAGE;\n        public const int DEFAULT_START_STAGE = ServiceLifecycleStage.Active;\n    }\n\n    /// <summary>\n    /// Options for configuring stream pub/sub.\n    /// </summary>\n    public class StreamPubSubOptions\n    {\n        /// <summary>\n        /// Gets or sets the pub sub type.\n        /// </summary>\n        /// <value>The type of the pub sub.</value>\n        public StreamPubSubType PubSubType { get; set; } = DEFAULT_STREAM_PUBSUB_TYPE;\n        public const StreamPubSubType DEFAULT_STREAM_PUBSUB_TYPE = StreamPubSubType.ExplicitGrainBasedAndImplicit;\n    }\n\n    /// <summary>\n    /// Options for stream pulling agents.\n    /// </summary>\n    public class StreamPullingAgentOptions\n    {\n        /// <summary>\n        /// Gets or sets the size of each batch container batch.\n        /// </summary>\n        /// <value>The size of each batch container batch.</value>\n        public int BatchContainerBatchSize { get; set; } = DEFAULT_BATCH_CONTAINER_BATCH_SIZE;\n\n        /// <summary>\n        /// The default batch container batch size.\n        /// </summary>\n        public static readonly int DEFAULT_BATCH_CONTAINER_BATCH_SIZE = 1;\n\n        /// <summary>\n        /// Gets or sets the period between polling for queue messages.\n        /// </summary>\n        public TimeSpan GetQueueMsgsTimerPeriod { get; set; } = DEFAULT_GET_QUEUE_MESSAGES_TIMER_PERIOD;\n\n        /// <summary>\n        /// The default period between polling for queue messages.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_GET_QUEUE_MESSAGES_TIMER_PERIOD = TimeSpan.FromMilliseconds(100);\n\n        /// <summary>\n        /// Gets or sets the queue initialization timeout.\n        /// </summary>\n        /// <value>The queue initialization timeout.</value>\n        public TimeSpan InitQueueTimeout { get; set; } = DEFAULT_INIT_QUEUE_TIMEOUT;\n\n        /// <summary>\n        /// The default queue initialization timeout\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_INIT_QUEUE_TIMEOUT = TimeSpan.FromSeconds(5);\n\n        /// <summary>\n        /// Gets or sets the maximum event delivery time.\n        /// </summary>\n        /// <value>The maximum event delivery time.</value>\n        public TimeSpan MaxEventDeliveryTime { get; set; } = DEFAULT_MAX_EVENT_DELIVERY_TIME;\n\n        /// <summary>\n        /// The default maximum event delivery time.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_MAX_EVENT_DELIVERY_TIME = TimeSpan.FromMinutes(1);\n\n        /// <summary>\n        /// Gets or sets the stream inactivity period.\n        /// </summary>\n        /// <value>The stream inactivity period.</value>\n        public TimeSpan StreamInactivityPeriod { get; set; } = DEFAULT_STREAM_INACTIVITY_PERIOD;\n\n        /// <summary>\n        /// The default stream inactivity period.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_STREAM_INACTIVITY_PERIOD = TimeSpan.FromMinutes(30);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/PersistentStreamProducer.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Collections.Generic;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streams\n{\n    internal partial class PersistentStreamProducer<T> : IInternalAsyncBatchObserver<T>\n    {\n        private readonly StreamImpl<T> stream;\n        private readonly IQueueAdapter queueAdapter;\n        private readonly DeepCopier deepCopier;\n\n        internal bool IsRewindable { get; private set; }\n\n        internal PersistentStreamProducer(StreamImpl<T> stream, IStreamProviderRuntime providerUtilities, IQueueAdapter queueAdapter, bool isRewindable, DeepCopier deepCopier)\n        {\n            this.stream = stream;\n            this.queueAdapter = queueAdapter;\n            this.deepCopier = deepCopier;\n            IsRewindable = isRewindable;\n            var logger = providerUtilities.ServiceProvider.GetRequiredService<ILogger<PersistentStreamProducer<T>>>();\n            LogCreatedPersistentStreamProducer(logger, stream, typeof(T), this.queueAdapter.Name);\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken token)\n        {\n            return this.queueAdapter.QueueMessageAsync(this.stream.StreamId, item, token, RequestContextExtensions.Export(this.deepCopier));\n        }\n\n        public Task OnNextBatchAsync(IEnumerable<T> batch, StreamSequenceToken token)\n        {\n            return this.queueAdapter.QueueMessageBatchAsync(this.stream.StreamId, batch, token, RequestContextExtensions.Export(this.deepCopier));\n\n        }\n\n        public Task OnCompletedAsync()\n        {\n            // Maybe send a close message to the rendezvous?\n            throw new NotImplementedException(\"OnCompletedAsync is not implemented for now.\");\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            // Maybe send a close message to the rendezvous?\n            throw new NotImplementedException(\"OnErrorAsync is not implemented for now.\");\n        }\n\n        public Task Cleanup()\n        {\n            return Task.CompletedTask;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Created PersistentStreamProducer for stream {StreamId}, of type {ElementType}, and with Adapter: {QueueAdapterName}.\"\n        )]\n        private static partial void LogCreatedPersistentStreamProducer(ILogger logger, StreamImpl<T> streamId, Type elementType, string queueAdapterName);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/PersistentStreamProvider.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Providers.Streams.Common\n{\n    /// <summary>\n    /// Commands which can be handled by the <see cref=\"PersistentStreamProvider\" />.\n    /// </summary>\n    /// <seealso cref=\"IControllable\"/>\n    [Serializable]\n    public enum PersistentStreamProviderCommand\n    {\n        None,\n\n        /// <summary>\n        /// Starts the agents.\n        /// </summary>\n        StartAgents,\n\n        /// <summary>\n        /// Stops the agents.\n        /// </summary>\n        StopAgents,\n\n        /// <summary>\n        /// Retrieves agent state.\n        /// </summary>\n        GetAgentsState,\n\n        /// <summary>\n        /// Gets the number of running agents.\n        /// </summary>\n        GetNumberRunningAgents,\n\n        /// <summary>\n        /// The command start range for custom adapters.\n        /// </summary>\n        AdapterCommandStartRange = 10000,\n\n        /// <summary>\n        /// The command end range for custom adapters.\n        /// </summary>\n        AdapterCommandEndRange = AdapterCommandStartRange + 9999,\n\n        /// <summary>\n        /// The command start range for custom adapter factories.\n        /// </summary>\n        AdapterFactoryCommandStartRange = AdapterCommandEndRange + 1,\n\n        /// <summary>\n        /// The command end range for custom adapter factories.\n        /// </summary>\n        AdapterFactoryCommandEndRange = AdapterFactoryCommandStartRange + 9999,\n    }\n\n    /// <summary>\n    /// Persistent stream provider that uses an adapter for persistence\n    /// </summary>\n    public partial class PersistentStreamProvider : IStreamProvider, IInternalStreamProvider, IControllable, IStreamSubscriptionManagerRetriever, ILifecycleParticipant<ILifecycleObservable>\n    {\n        private readonly ILogger logger;\n        private readonly IStreamProviderRuntime runtime;\n        private readonly DeepCopier deepCopier;\n        private readonly IRuntimeClient runtimeClient;\n        private readonly ProviderStateManager stateManager = new ProviderStateManager();\n        private IQueueAdapterFactory    adapterFactory;\n        private IQueueAdapter           queueAdapter;\n        private IPersistentStreamPullingManager pullingAgentManager;\n        private IStreamSubscriptionManager streamSubscriptionManager;\n        private readonly StreamPubSubOptions pubsubOptions;\n        private readonly StreamLifecycleOptions lifeCycleOptions;\n        public string Name { get; private set; }\n        public bool IsRewindable { get { return queueAdapter.IsRewindable; } }\n\n        public PersistentStreamProvider(\n            string name,\n            StreamPubSubOptions pubsubOptions,\n            StreamLifecycleOptions lifeCycleOptions,\n            IProviderRuntime runtime,\n            DeepCopier deepCopier,\n            ILogger<PersistentStreamProvider> logger)\n        {\n            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));\n            if (runtime == null) throw new ArgumentNullException(nameof(runtime));\n            this.pubsubOptions = pubsubOptions ?? throw new ArgumentNullException(nameof(pubsubOptions));\n            this.Name = name;\n            this.lifeCycleOptions = lifeCycleOptions ?? throw new ArgumentNullException(nameof(lifeCycleOptions));\n            this.runtime = runtime.ServiceProvider.GetRequiredService<IStreamProviderRuntime>();\n            this.runtimeClient = runtime.ServiceProvider.GetRequiredService<IRuntimeClient>();\n            this.deepCopier = deepCopier ?? throw new ArgumentNullException(nameof(deepCopier));\n            this.logger = logger ?? throw new ArgumentNullException(nameof(logger));\n        }\n\n        private async Task Init(CancellationToken token)\n        {\n            if(!this.stateManager.PresetState(ProviderState.Initialized)) return;\n            this.adapterFactory = this.runtime.ServiceProvider.GetRequiredKeyedService<IQueueAdapterFactory>(this.Name);\n            this.queueAdapter = await adapterFactory.CreateAdapter();\n\n            if (this.pubsubOptions.PubSubType == StreamPubSubType.ExplicitGrainBasedAndImplicit\n                || this.pubsubOptions.PubSubType == StreamPubSubType.ExplicitGrainBasedOnly)\n            {\n                this.streamSubscriptionManager = this.runtime.ServiceProvider\n                    .GetService<IStreamSubscriptionManagerAdmin>().GetStreamSubscriptionManager(StreamSubscriptionManagerType.ExplicitSubscribeOnly);\n            }\n            this.stateManager.CommitState();\n        }\n\n        private async Task Start(CancellationToken token)\n        {\n            if (!this.stateManager.PresetState(ProviderState.Started)) return;\n            if (this.queueAdapter.Direction.Equals(StreamProviderDirection.ReadOnly) ||\n                this.queueAdapter.Direction.Equals(StreamProviderDirection.ReadWrite))\n            {\n                var siloRuntime = this.runtime as ISiloSideStreamProviderRuntime;\n                if (siloRuntime != null)\n                {\n                    this.pullingAgentManager = await siloRuntime.InitializePullingAgents(this.Name, this.adapterFactory, this.queueAdapter);\n\n                    // TODO: No support yet for DeliveryDisabled, only Stopped and Started\n                    if (this.lifeCycleOptions.StartupState == StreamLifecycleOptions.RunState.AgentsStarted)\n                        await pullingAgentManager.StartAgents();\n                }\n            }\n            stateManager.CommitState();\n        }\n\n        public IStreamSubscriptionManager GetStreamSubscriptionManager()\n        {\n            return this.streamSubscriptionManager;\n        }\n\n        private async Task Close(CancellationToken token)\n        {\n            if (!stateManager.PresetState(ProviderState.Closed)) return;\n\n            var manager = this.pullingAgentManager;\n            if (manager != null)\n            {\n                await manager.Stop();\n            }\n\n            stateManager.CommitState();\n        }\n\n        public IAsyncStream<T> GetStream<T>(StreamId streamId)\n        {\n            var id = new QualifiedStreamId(Name, streamId);\n            return this.runtime.GetStreamDirectory().GetOrAddStream<T>(\n                id, () => new StreamImpl<T>(id, this, IsRewindable, this.runtimeClient));\n        }\n\n        IInternalAsyncBatchObserver<T> IInternalStreamProvider.GetProducerInterface<T>(IAsyncStream<T> stream)\n        {\n            if (queueAdapter.Direction == StreamProviderDirection.ReadOnly)\n            {\n                throw new InvalidOperationException($\"Stream provider {queueAdapter.Name} is ReadOnly.\");\n            }\n            return new PersistentStreamProducer<T>((StreamImpl<T>)stream, this.runtime, queueAdapter, IsRewindable, this.deepCopier);\n        }\n\n        IInternalAsyncObservable<T> IInternalStreamProvider.GetConsumerInterface<T>(IAsyncStream<T> streamId)\n        {\n            return GetConsumerInterfaceImpl(streamId);\n        }\n\n        private IInternalAsyncObservable<T> GetConsumerInterfaceImpl<T>(IAsyncStream<T> stream)\n        {\n            return new StreamConsumer<T>((StreamImpl<T>)stream, Name, this.runtime, this.runtime.PubSub(this.pubsubOptions.PubSubType), this.logger, IsRewindable);\n        }\n\n        public Task<object> ExecuteCommand(int command, object arg)\n        {\n            if (command >= (int)PersistentStreamProviderCommand.AdapterCommandStartRange &&\n                command <= (int)PersistentStreamProviderCommand.AdapterCommandEndRange &&\n                queueAdapter is IControllable)\n            {\n                return ((IControllable)queueAdapter).ExecuteCommand(command, arg);\n            }\n\n            if (command >= (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange &&\n                command <= (int)PersistentStreamProviderCommand.AdapterFactoryCommandEndRange &&\n                adapterFactory is IControllable)\n            {\n                return ((IControllable)adapterFactory).ExecuteCommand(command, arg);\n            }\n\n            if (pullingAgentManager != null)\n            {\n                return pullingAgentManager.ExecuteCommand((PersistentStreamProviderCommand)command, arg);\n            }\n\n            LogWarningGotCommand(\n                (PersistentStreamProviderCommand)command,\n                arg);\n            throw new ArgumentException(\"PullingAgentManager is not initialized yet.\");\n        }\n\n        public void Participate(ILifecycleObservable lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<PersistentStreamProvider>(this.Name), this.lifeCycleOptions.InitStage, Init);\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<PersistentStreamProvider>(this.Name), this.lifeCycleOptions.StartStage, Start, Close);\n        }\n\n        public static IStreamProvider Create(IServiceProvider services, string name)\n        {\n            var pubsubOptions = services.GetRequiredService<IOptionsMonitor<StreamPubSubOptions>>().Get(name);\n            var initOptions = services.GetRequiredService<IOptionsMonitor<StreamLifecycleOptions>>().Get(name);\n            return ActivatorUtilities.CreateInstance<PersistentStreamProvider>(services, name, pubsubOptions, initOptions);\n        }\n\n        public static ILifecycleParticipant<TLifecycle> ParticipateIn<TLifecycle>(IServiceProvider serviceProvider, string name)\n            where TLifecycle : ILifecycleObservable\n        {\n            var provider = (PersistentStreamProvider)serviceProvider.GetRequiredKeyedService<IStreamProvider>(name);\n            return provider.ParticipateIn<TLifecycle>();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Got command {Command} with arg {Argument}, but PullingAgentManager is not initialized yet. Ignoring the command.\"\n        )]\n        private partial void LogWarningGotCommand(PersistentStreamProviderCommand command, object argument);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/PersistentStreamPullingAgent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Metrics;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Internal;\nusing Orleans.Streams.Filtering;\n\nnamespace Orleans.Streams\n{\n    internal sealed partial class PersistentStreamPullingAgent : SystemTarget, IPersistentStreamPullingAgent\n    {\n        private const int ReadLoopRetryMax = 6;\n        private const int StreamInactivityCheckFrequency = 10;\n        private readonly IBackoffProvider deliveryBackoffProvider;\n        private readonly IBackoffProvider queueReaderBackoffProvider;\n        private readonly string streamProviderName;\n        private readonly IStreamPubSub pubSub;\n        private readonly IStreamFilter streamFilter;\n        private readonly Dictionary<QualifiedStreamId, StreamConsumerCollection> pubSubCache;\n        private readonly StreamPullingAgentOptions options;\n        private readonly ILogger logger;\n        private readonly IQueueAdapterCache queueAdapterCache;\n        private readonly IQueueAdapter queueAdapter;\n        private readonly IStreamFailureHandler streamFailureHandler;\n        internal readonly QueueId QueueId;\n\n        private int numMessages;\n        private IQueueCache queueCache;\n        private IQueueAdapterReceiver receiver;\n        private DateTime lastTimeCleanedPubSubCache;\n        private IGrainTimer timer;\n\n        private Task receiverInitTask;\n        private bool IsShutdown => timer == null;\n        private string StatisticUniquePostfix => $\"{streamProviderName}.{QueueId}\";\n\n        internal PersistentStreamPullingAgent(\n            SystemTargetGrainId id,\n            string strProviderName,\n            IStreamPubSub streamPubSub,\n            IStreamFilter streamFilter,\n            QueueId queueId,\n            StreamPullingAgentOptions options,\n            IQueueAdapter queueAdapter,\n            IQueueAdapterCache queueAdapterCache,\n            IStreamFailureHandler streamFailureHandler,\n            IBackoffProvider deliveryBackoffProvider,\n            IBackoffProvider queueReaderBackoffProvider,\n            SystemTargetShared shared)\n            : base(id, shared)\n        {\n            if (strProviderName == null) throw new ArgumentNullException(\"runtime\", \"PersistentStreamPullingAgent: strProviderName should not be null\");\n\n            QueueId = queueId;\n            streamProviderName = strProviderName;\n            pubSub = streamPubSub;\n            this.streamFilter = streamFilter;\n            pubSubCache = new Dictionary<QualifiedStreamId, StreamConsumerCollection>();\n            this.options = options;\n            this.queueAdapter = queueAdapter ?? throw new ArgumentNullException(nameof(queueAdapter));\n            this.streamFailureHandler = streamFailureHandler ?? throw new ArgumentNullException(nameof(streamFailureHandler));\n            this.queueAdapterCache = queueAdapterCache;\n            this.deliveryBackoffProvider = deliveryBackoffProvider;\n            this.queueReaderBackoffProvider = queueReaderBackoffProvider;\n            numMessages = 0;\n\n            logger = shared.LoggerFactory.CreateLogger($\"{this.GetType().Namespace}.{streamProviderName}\");\n            LogInfoCreated(GetType().Name, GrainId, strProviderName, Silo, new(QueueId));\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        /// <summary>\n        /// Take responsibility for a new queues that was assigned to me via a new range.\n        /// We first store the new queue in our internal data structure, try to initialize it and start a pumping timer.\n        /// ERROR HANDLING:\n        ///     The responsibility to handle initialization and shutdown failures is inside the INewQueueAdapterReceiver code.\n        ///     The agent will call Initialize once and log an error. It will not call initialize again.\n        ///     The receiver itself may attempt later to recover from this error and do initialization again.\n        ///     The agent will assume initialization has succeeded and will subsequently start calling pumping receive.\n        ///     Same applies to shutdown.\n        /// </summary>\n        /// <returns></returns>\n        public Task Initialize()\n        {\n            LogInfoInit(GetType().Name, GrainId, Silo, new(QueueId));\n\n            lastTimeCleanedPubSubCache = DateTime.UtcNow;\n\n            try\n            {\n                if (queueAdapterCache != null)\n                {\n                    using var _ = new ExecutionContextSuppressor();\n                    queueCache = queueAdapterCache.CreateQueueCache(QueueId);\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorCreatingQueueCache(exc);\n                throw;\n            }\n\n            try\n            {\n                using var _ = new ExecutionContextSuppressor();\n                receiver = queueAdapter.CreateReceiver(QueueId);\n            }\n            catch (Exception exc)\n            {\n                LogErrorCreatingReceiver(exc);\n                throw;\n            }\n\n            try\n            {\n                using var _ = new ExecutionContextSuppressor();\n                receiverInitTask = OrleansTaskExtentions.SafeExecute(() => receiver.Initialize(this.options.InitQueueTimeout))\n                    .LogException(logger, ErrorCode.PersistentStreamPullingAgent_03, $\"QueueAdapterReceiver {QueueId:H} failed to Initialize.\");\n                receiverInitTask.Ignore();\n            }\n            catch (Exception exception)\n            {\n                LogErrorReceiverInit(new(QueueId), exception);\n\n                // Just ignore this exception and proceed as if Initialize has succeeded.\n                // We already logged individual exceptions for individual calls to Initialize. No need to log again.\n            }\n\n            // Setup a reader for a new receiver.\n            // Even if the receiver failed to initialize, treat it as OK and start pumping it. It's receiver responsibility to retry initialization.\n            var randomTimerOffset = RandomTimeSpan.Next(this.options.GetQueueMsgsTimerPeriod);\n            timer = RegisterGrainTimer(AsyncTimerCallback, QueueId, randomTimerOffset, this.options.GetQueueMsgsTimerPeriod);\n\n            StreamInstruments.RegisterPersistentStreamPubSubCacheSizeObserve(() => new Measurement<int>(pubSubCache.Count, new KeyValuePair<string, object>(\"name\", StatisticUniquePostfix)));\n\n            LogInfoTakingQueue(new(QueueId));\n            return Task.CompletedTask;\n        }\n\n        public async Task Shutdown()\n        {\n            // Stop pulling from queues that are not in my range anymore.\n            LogInfoShutdown(GetType().Name, new(QueueId));\n\n            var asyncTimer = timer;\n            timer = null;\n            asyncTimer.Dispose();\n\n            this.queueCache = null;\n\n            Task localReceiverInitTask = receiverInitTask;\n            if (localReceiverInitTask != null)\n            {\n                await localReceiverInitTask.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n                receiverInitTask = null;\n            }\n\n            try\n            {\n                IQueueAdapterReceiver localReceiver = this.receiver;\n                this.receiver = null;\n                if (localReceiver != null)\n                {\n                    var task = OrleansTaskExtentions.SafeExecute(() => localReceiver.Shutdown(this.options.InitQueueTimeout));\n                    task = task.LogException(logger, ErrorCode.PersistentStreamPullingAgent_07,\n                        $\"QueueAdapterReceiver {QueueId} failed to Shutdown.\");\n                    await task;\n                }\n            }\n            catch\n            {\n                // Just ignore this exception and proceed as if Shutdown has succeeded.\n                // We already logged individual exceptions for individual calls to Shutdown. No need to log again.\n            }\n\n            var unregisterTasks = new List<Task>();\n            foreach (var tuple in pubSubCache)\n            {\n                tuple.Value.DisposeAll(logger);\n                var streamId = tuple.Key;\n                LogInfoUnregisterProducer(streamId);\n                unregisterTasks.Add(pubSub.UnregisterProducer(streamId, GrainId));\n            }\n\n            try\n            {\n                await Task.WhenAll(unregisterTasks);\n            }\n            catch (Exception exc)\n            {\n                LogWarningUnregisterProducer(exc);\n            }\n            pubSubCache.Clear();\n        }\n\n        public Task AddSubscriber(\n            GuidId subscriptionId,\n            QualifiedStreamId streamId,\n            GrainId streamConsumer,\n            string filterData)\n        {\n            LogDebugAddSubscriber(streamId, streamConsumer);\n            // cannot await here because explicit consumers trigger this call, so it could cause a deadlock.\n            AddSubscriber_Impl(subscriptionId, streamId, streamConsumer, filterData, null)\n                .LogException(logger, ErrorCode.PersistentStreamPullingAgent_26,\n                    $\"Failed to add subscription for stream {streamId}.\")\n                .Ignore();\n            return Task.CompletedTask;\n        }\n\n        // Called by rendezvous when new remote subscriber subscribes to this stream.\n        private async Task AddSubscriber_Impl(\n            GuidId subscriptionId,\n            QualifiedStreamId streamId,\n            GrainId streamConsumer,\n            string filterData,\n            StreamSequenceToken cacheToken)\n        {\n            if (IsShutdown) return;\n\n            StreamConsumerCollection streamDataCollection;\n            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))\n            {\n                // If stream is not in pubsub cache, then we've received no events on this stream, and will aquire the subscriptions from pubsub when we do.\n                return;\n            }\n\n            StreamConsumerData data;\n            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))\n            {\n                var consumerReference = this.RuntimeClient.InternalGrainFactory\n                    .GetGrain(streamConsumer)\n                    .AsReference<IStreamConsumerExtension>();\n                data = streamDataCollection.AddConsumer(subscriptionId, streamId, consumerReference, filterData);\n            }\n\n            if (await DoHandshakeWithConsumer(data, cacheToken))\n            {\n                data.PendingStartToken = null;\n                data.IsRegistered = true;\n                if (data.State == StreamConsumerDataState.Inactive)\n                    RunConsumerCursor(data).Ignore(); // Start delivering events if not actively doing so\n            }\n        }\n\n        private async Task<bool> DoHandshakeWithConsumer(\n            StreamConsumerData consumerData,\n            StreamSequenceToken cacheToken)\n        {\n            StreamHandshakeToken requestedHandshakeToken = null;\n            // if not cache, then we can't get cursor and there is no reason to ask consumer for token.\n            if (queueCache != null)\n            {\n                Exception exceptionOccured = null;\n                try\n                {\n                    requestedHandshakeToken = await AsyncExecutorWithRetries.ExecuteWithRetries(\n                         i => consumerData.StreamConsumer.GetSequenceToken(consumerData.SubscriptionId),\n                         AsyncExecutorWithRetries.INFINITE_RETRIES,\n                         // Do not retry if the agent is shutting down, or if the exception is ClientNotAvailableException\n                         (exception, i) => exception is not ClientNotAvailableException && !IsShutdown,\n                         this.options.MaxEventDeliveryTime,\n                         deliveryBackoffProvider);\n\n                    var requestedToken = requestedHandshakeToken?.Token;\n                    if (requestedToken != null)\n                    {\n                        consumerData.SafeDisposeCursor(logger);\n                        consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, requestedToken);\n                    }\n                    else\n                    {\n                        var registrationToken = cacheToken ?? consumerData.PendingStartToken;\n                        if (consumerData.Cursor == null) // if the consumer did not ask for a specific token and we already have a cursor, just keep using it.\n                            consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, registrationToken);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    exceptionOccured = exception;\n                }\n                if (exceptionOccured != null)\n                {\n                    // If we are shutting down, ignore the error\n                    if (IsShutdown) return false;\n\n                    bool faultedSubscription = await ErrorProtocol(consumerData, exceptionOccured, false, null, requestedHandshakeToken?.Token);\n                    if (faultedSubscription) return false;\n                }\n            }\n            consumerData.LastToken = requestedHandshakeToken; // use what ever the consumer asked for as LastToken for next handshake (even if he asked for null).\n            // if we don't yet have a cursor (had errors in the handshake or data not available exc), get a cursor at the event that triggered that consumer subscription.\n            if (consumerData.Cursor == null && queueCache != null)\n            {\n                try\n                {\n                    var registrationToken = cacheToken ?? consumerData.PendingStartToken;\n                    consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, registrationToken);\n                }\n                catch (Exception)\n                {\n                    consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, null); // just in case last GetCacheCursor failed.\n                }\n            }\n            return true;\n        }\n\n        public Task RemoveSubscriber(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            RemoveSubscriber_Impl(subscriptionId, streamId);\n            return Task.CompletedTask;\n        }\n\n        public void RemoveSubscriber_Impl(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            if (IsShutdown) return;\n\n            StreamConsumerCollection streamData;\n            if (!pubSubCache.TryGetValue(streamId, out streamData)) return;\n\n            // remove consumer\n            bool removed = streamData.RemoveConsumer(subscriptionId, logger);\n            if (removed)\n                LogDebugRemovedConsumer(subscriptionId, streamId);\n\n            if (streamData.Count == 0)\n                pubSubCache.Remove(streamId);\n        }\n\n        private Task AsyncTimerCallback(QueueId queueId, CancellationToken cancellationToken)\n        {\n            using var _ = new ExecutionContextSuppressor();\n            return PumpQueue(queueId, cancellationToken);\n        }\n\n        private async Task PumpQueue(QueueId queueId, CancellationToken cancellationToken)\n        {\n            try\n            {\n                Task localReceiverInitTask = receiverInitTask;\n                if (localReceiverInitTask != null)\n                {\n                    await localReceiverInitTask;\n                    receiverInitTask = null;\n                }\n\n                if (IsShutdown || cancellationToken.IsCancellationRequested) return; // timer was already removed, last tick\n\n                // loop through the queue until it is empty.\n                while (!IsShutdown && !cancellationToken.IsCancellationRequested) // timer will be set to null when we are asked to shutdown.\n                {\n                    int maxCacheAddCount = queueCache?.GetMaxAddCount() ?? QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG;\n                    if (maxCacheAddCount != QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG && maxCacheAddCount <= 0)\n                        return;\n\n                    // If read succeeds and there is more data, we continue reading.\n                    // If read succeeds and there is no more data, we break out of loop\n                    // If read fails, we retry 6 more times, with backoff policy.\n                    //    we log each failure as warnings. After 6 times retry if still fail, we break out of loop and log an error\n                    bool moreData = await AsyncExecutorWithRetries.ExecuteWithRetries(\n                        i => ReadFromQueue(queueId, receiver, maxCacheAddCount),\n                        ReadLoopRetryMax,\n                        ReadLoopRetryExceptionFilter,\n                        Timeout.InfiniteTimeSpan,\n                        queueReaderBackoffProvider,\n                        cancellationToken: cancellationToken);\n                    if (!moreData)\n                        return;\n                }\n            }\n            catch (Exception exc)\n            {\n                receiverInitTask = null;\n                LogErrorGivingUpReading(new(queueId), ReadLoopRetryMax, exc);\n            }\n\n            bool ReadLoopRetryExceptionFilter(Exception e, int retryCounter)\n            {\n                LogErrorRetrying(retryCounter, new(queueId), e);\n                return !cancellationToken.IsCancellationRequested && !IsShutdown;\n            }\n        }\n\n        /// <summary>\n        /// Read from queue.\n        /// Returns true, if data was read, false if it was not\n        /// </summary>\n        /// <param name=\"myQueueId\"></param>\n        /// <param name=\"rcvr\"></param>\n        /// <param name=\"maxCacheAddCount\"></param>\n        /// <returns></returns>\n        private async Task<bool> ReadFromQueue(QueueId myQueueId, IQueueAdapterReceiver rcvr, int maxCacheAddCount)\n        {\n            if (rcvr == null)\n            {\n                return false;\n            }\n\n            var now = DateTime.UtcNow;\n            // Try to cleanup the pubsub cache at the cadence of 10 times in the configurable StreamInactivityPeriod.\n            if ((now - lastTimeCleanedPubSubCache) >= this.options.StreamInactivityPeriod.Divide(StreamInactivityCheckFrequency))\n            {\n                lastTimeCleanedPubSubCache = now;\n                CleanupPubSubCache(now);\n            }\n\n            if (queueCache != null)\n            {\n                IList<IBatchContainer> purgedItems;\n                if (queueCache.TryPurgeFromCache(out purgedItems))\n                {\n                    try\n                    {\n                        await rcvr.MessagesDeliveredAsync(purgedItems);\n                    }\n                    catch (Exception exc)\n                    {\n                        LogWarningMessagesDeliveredAsync(new(myQueueId), exc);\n                    }\n                }\n            }\n\n            if (queueCache != null && queueCache.IsUnderPressure())\n            {\n                // Under back pressure. Exit the loop. Will attempt again in the next timer callback.\n                LogInfoStreamCacheUnderPressure();\n                return false;\n            }\n\n            // Retrieve one multiBatch from the queue. Every multiBatch has an IEnumerable of IBatchContainers, each IBatchContainer may have multiple events.\n            IList<IBatchContainer> multiBatch = await rcvr.GetQueueMessagesAsync(maxCacheAddCount);\n\n            if (multiBatch == null || multiBatch.Count == 0) return false; // queue is empty. Exit the loop. Will attempt again in the next timer callback.\n\n            queueCache?.AddToCache(multiBatch);\n            numMessages += multiBatch.Count;\n            StreamInstruments.PersistentStreamReadMessages.Add(multiBatch.Count);\n\n            LogTraceGotMessages(multiBatch.Count, new(myQueueId), numMessages);\n\n            foreach (var group in\n                multiBatch\n                .Where(m => m != null)\n                .GroupBy(container => container.StreamId))\n            {\n                var streamId = new QualifiedStreamId(queueAdapter.Name, group.Key);\n                StreamSequenceToken startToken = group.First().SequenceToken;\n                StreamConsumerCollection streamData;\n                if (pubSubCache.TryGetValue(streamId, out streamData))\n                {\n                    streamData.RefreshActivity(now);\n                    StartInactiveCursors(streamData, startToken);\n\n                }\n                else\n                {\n                    RegisterStream(streamId, startToken, now).Ignore(); // if this is a new stream register as producer of stream in pub sub system\n                }\n            }\n            return true;\n        }\n\n        private void CleanupPubSubCache(DateTime now)\n        {\n            foreach (var tuple in pubSubCache)\n            {\n                if (tuple.Value.IsInactive(now, options.StreamInactivityPeriod))\n                {\n                    pubSubCache.Remove(tuple.Key);\n                    tuple.Value.DisposeAll(logger);\n                }\n            }\n        }\n\n        private async Task RegisterStream(QualifiedStreamId streamId, StreamSequenceToken firstToken, DateTime now)\n        {\n            var streamData = new StreamConsumerCollection(now);\n            pubSubCache.Add(streamId, streamData);\n            // Create a fake cursor to point into a cache.\n            // That way we will not purge the event from the cache, until we talk to pub sub.\n            // This will help ensure the \"casual consistency\" between pre-existing subscripton (of a potentially new already subscribed consumer)\n            // and later production.\n            var pinCursor = queueCache?.GetCacheCursor(streamId, firstToken);\n\n            try\n            {\n                await RegisterAsStreamProducer(streamId, firstToken);\n                streamData.StreamRegistered = true;\n            }\n            finally\n            {\n                // Cleanup the fake pinning cursor.\n                pinCursor?.Dispose();\n            }\n        }\n\n        private void StartInactiveCursors(StreamConsumerCollection streamData, StreamSequenceToken startToken)\n        {\n            foreach (StreamConsumerData consumerData in streamData.AllConsumers())\n            {\n                // Some consumer might not be fully registered yet\n                if (consumerData.IsRegistered)\n                {\n                    consumerData.Cursor?.Refresh(startToken);\n                    if (consumerData.State == StreamConsumerDataState.Inactive)\n                    {\n                        // wake up inactive consumers\n                        RunConsumerCursor(consumerData).Ignore();\n                    }\n                }\n                else\n                {\n                    if (consumerData.PendingStartToken is null || startToken.Older(consumerData.PendingStartToken))\n                    {\n                        consumerData.PendingStartToken = startToken;\n                    }\n                    LogDebugPulledNewMessages(consumerData.StreamId);\n                }\n            }\n        }\n\n        private async Task RunConsumerCursor(StreamConsumerData consumerData)\n        {\n            try\n            {\n                // double check in case of interleaving\n                if (consumerData.State == StreamConsumerDataState.Active ||\n                    consumerData.Cursor == null) return;\n\n                consumerData.State = StreamConsumerDataState.Active;\n                while (consumerData.Cursor != null)\n                {\n                    IBatchContainer batch = null;\n                    Exception exceptionOccured = null;\n                    try\n                    {\n                        batch = GetBatchForConsumer(consumerData.Cursor, consumerData.StreamId, consumerData.FilterData);\n                        if (batch == null)\n                        {\n                            break;\n                        }\n                    }\n                    catch (Exception exc)\n                    {\n                        exceptionOccured = exc;\n                        consumerData.SafeDisposeCursor(logger);\n                        consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, null);\n                    }\n\n                    if (batch != null)\n                    {\n                        if (!ShouldDeliverBatch(consumerData.StreamId, batch, consumerData.FilterData))\n                            continue;\n                    }\n\n                    try\n                    {\n                        StreamInstruments.PersistentStreamSentMessages.Add(1);\n                        if (batch != null)\n                        {\n                            StreamHandshakeToken newToken = await AsyncExecutorWithRetries.ExecuteWithRetries(\n                                i => DeliverBatchToConsumer(consumerData, batch),\n                                AsyncExecutorWithRetries.INFINITE_RETRIES,\n                                // Do not retry if the agent is shutting down, or if the exception is ClientNotAvailableException\n                                (exception, i) => exception is not ClientNotAvailableException && !IsShutdown,\n                                this.options.MaxEventDeliveryTime,\n                                deliveryBackoffProvider);\n                            if (newToken != null)\n                            {\n                                consumerData.LastToken = newToken;\n                                IQueueCacheCursor newCursor = queueCache.GetCacheCursor(consumerData.StreamId, newToken.Token);\n                                // The handshake token points to an already processed event, we need to advance the cursor to\n                                // the next event.\n                                newCursor.MoveNext();\n                                consumerData.SafeDisposeCursor(logger);\n                                consumerData.Cursor = newCursor;\n                            }\n                        }\n                    }\n                    catch (Exception exc)\n                    {\n                        consumerData.Cursor?.RecordDeliveryFailure();\n                        LogErrorDeliveringMessages(consumerData.StreamId, exc);\n\n                        exceptionOccured = exc is ClientNotAvailableException\n                            ? exc\n                            : new StreamEventDeliveryFailureException(consumerData.StreamId);\n                    }\n                    // if we failed to deliver a batch\n                    if (exceptionOccured != null)\n                    {\n                        bool faultedSubscription = await ErrorProtocol(consumerData, exceptionOccured, true, batch, batch?.SequenceToken);\n                        if (faultedSubscription) return;\n                    }\n                }\n                consumerData.State = StreamConsumerDataState.Inactive;\n            }\n            catch (Exception exc)\n            {\n                // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception\n                LogErrorRunConsumerCursor(exc);\n                consumerData.State = StreamConsumerDataState.Inactive;\n                throw;\n            }\n        }\n\n        private IBatchContainer GetBatchForConsumer(IQueueCacheCursor cursor, StreamId streamId, string filterData)\n        {\n            if (this.options.BatchContainerBatchSize <= 1)\n            {\n                if (!cursor.MoveNext())\n                {\n                    return null;\n                }\n\n                return cursor.GetCurrent(out _);\n            }\n            else if (this.options.BatchContainerBatchSize > 1)\n            {\n                int i = 0;\n                var batchContainers = new List<IBatchContainer>();\n\n                while (i < this.options.BatchContainerBatchSize)\n                {\n                    if (!cursor.MoveNext())\n                    {\n                        break;\n                    }\n\n                    var batchContainer = cursor.GetCurrent(out _);\n\n                    if (!ShouldDeliverBatch(streamId, batchContainer, filterData))\n                        continue;\n\n                    batchContainers.Add(batchContainer);\n                    i++;\n                }\n\n                if (i == 0)\n                {\n                    return null;\n                }\n\n                return new BatchContainerBatch(batchContainers);\n            }\n\n            return null;\n        }\n\n        private async Task<StreamHandshakeToken> DeliverBatchToConsumer(StreamConsumerData consumerData, IBatchContainer batch)\n        {\n            try\n            {\n                StreamHandshakeToken newToken = await ContextualizedDeliverBatchToConsumer(consumerData, batch);\n                consumerData.LastToken = StreamHandshakeToken.CreateDeliveyToken(batch.SequenceToken); // this is the currently delivered token\n                return newToken;\n            }\n            catch (Exception ex)\n            {\n                LogWarningFailedToDeliverMessage(consumerData.SubscriptionId, consumerData.StreamId, ex);\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Add call context for batch delivery call, then clear context immediately, without giving up turn.\n        /// </summary>\n        private static Task<StreamHandshakeToken> ContextualizedDeliverBatchToConsumer(StreamConsumerData consumerData, IBatchContainer batch)\n        {\n            bool isRequestContextSet = batch.ImportRequestContext();\n            try\n            {\n                return consumerData.StreamConsumer.DeliverBatch(consumerData.SubscriptionId, consumerData.StreamId, batch, consumerData.LastToken);\n            }\n            finally\n            {\n                if (isRequestContextSet)\n                {\n                    // clear RequestContext before await!\n                    RequestContext.Clear();\n                }\n            }\n        }\n\n\n        private static async Task DeliverErrorToConsumer(StreamConsumerData consumerData, Exception exc, IBatchContainer batch)\n        {\n            Task errorDeliveryTask;\n            bool isRequestContextSet = batch != null && batch.ImportRequestContext();\n            try\n            {\n                errorDeliveryTask = consumerData.StreamConsumer.ErrorInStream(consumerData.SubscriptionId, exc);\n            }\n            finally\n            {\n                if (isRequestContextSet)\n                {\n                    RequestContext.Clear(); // clear RequestContext before await!\n                }\n            }\n            await errorDeliveryTask;\n        }\n\n        private async Task<bool> ErrorProtocol(StreamConsumerData consumerData, Exception exceptionOccured, bool isDeliveryError, IBatchContainer batch, StreamSequenceToken token)\n        {\n            // for loss of client, we just remove the subscription\n            if (exceptionOccured is ClientNotAvailableException)\n            {\n                LogWarningConsumerIsDead(consumerData.StreamConsumer, consumerData.StreamId);\n                pubSub.UnregisterConsumer(consumerData.SubscriptionId, consumerData.StreamId).Ignore();\n                return true;\n            }\n\n            // notify consumer about the error or that the data is not available.\n            await DeliverErrorToConsumer(consumerData, exceptionOccured, batch).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n            // record that there was a delivery failure\n            if (isDeliveryError)\n            {\n                await streamFailureHandler.OnDeliveryFailure(\n                        consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n            }\n            else\n            {\n                await streamFailureHandler.OnSubscriptionFailure(\n                    consumerData.SubscriptionId, streamProviderName, consumerData.StreamId, token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n            }\n\n            // if configured to fault on delivery failure and this is not an implicit subscription, fault and remove the subscription\n            if (streamFailureHandler.ShouldFaultSubsriptionOnError && !SubscriptionMarker.IsImplicitSubscription(consumerData.SubscriptionId.Guid))\n            {\n                try\n                {\n                    // notify consumer of faulted subscription, if we can.\n                    await DeliverErrorToConsumer(\n                        consumerData, new FaultedSubscriptionException(consumerData.SubscriptionId, consumerData.StreamId), batch).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n\n                    // mark subscription as faulted.\n                    await pubSub.FaultSubscription(consumerData.StreamId, consumerData.SubscriptionId);\n                }\n                finally\n                {\n                    // remove subscription\n                    RemoveSubscriber_Impl(consumerData.SubscriptionId, consumerData.StreamId);\n                }\n                return true;\n            }\n            return false;\n        }\n\n        private static async Task<ISet<PubSubSubscriptionState>> PubsubRegisterProducer(IStreamPubSub pubSub, QualifiedStreamId streamId,\n            GrainId meAsStreamProducer, ILogger logger)\n        {\n            try\n            {\n                var streamData = await pubSub.RegisterProducer(streamId, meAsStreamProducer);\n                return streamData;\n            }\n            catch (Exception e)\n            {\n                LogErrorRegisterAsStreamProducer(logger, e);\n                throw;\n            }\n        }\n\n        private async Task RegisterAsStreamProducer(QualifiedStreamId streamId, StreamSequenceToken streamStartToken)\n        {\n            try\n            {\n                if (pubSub == null) throw new NullReferenceException(\"Found pubSub reference not set up correctly in RetrieveNewStream\");\n\n                ISet<PubSubSubscriptionState> streamData = null;\n                await AsyncExecutorWithRetries.ExecuteWithRetries(\n                                async i => { streamData =\n                                    await PubsubRegisterProducer(pubSub, streamId, GrainId, logger); },\n                                AsyncExecutorWithRetries.INFINITE_RETRIES,\n                                (exception, i) => !IsShutdown,\n                                Timeout.InfiniteTimeSpan,\n                                deliveryBackoffProvider);\n\n                LogDebugGotBackSubscribers(streamData.Count, streamId);\n\n                var addSubscriptionTasks = new List<Task>(streamData.Count);\n                foreach (PubSubSubscriptionState item in streamData)\n                {\n                    addSubscriptionTasks.Add(AddSubscriber_Impl(item.SubscriptionId, item.Stream, item.Consumer, item.FilterData, streamStartToken));\n                }\n                await Task.WhenAll(addSubscriptionTasks);\n            }\n            catch (Exception exc)\n            {\n                // RegisterAsStreamProducer is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception\n                LogErrorIgnoredRegisterAsStreamProducer(exc);\n                throw;\n            }\n        }\n\n        private bool ShouldDeliverBatch(StreamId streamId, IBatchContainer batchContainer, string filterData)\n        {\n            if (this.streamFilter is NoOpStreamFilter)\n                return true;\n\n            try\n            {\n                foreach (var evt in batchContainer.GetEvents<object>())\n                {\n                    if (this.streamFilter.ShouldDeliver(streamId, evt.Item1, filterData))\n                        return true;\n                }\n                return false;\n            }\n            catch (Exception exc)\n            {\n                LogWarningFilterEvaluation(streamFilter.GetType().Name, filterData, streamId, exc);\n            }\n            return true;\n        }\n\n        private readonly struct QueueIdLogRecord(QueueId queueId)\n        {\n            public override string ToString() => queueId.ToStringWithHashCode();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_01,\n            Message = \"Created {Name} {Id} for Stream Provider {StreamProvider} on silo {Silo} for Queue {Queue}.\"\n        )]\n        private partial void LogInfoCreated(string name, GrainId id, string streamProvider, SiloAddress silo, QueueIdLogRecord queue);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_02,\n            Message = \"Init of {Name} {Id} on silo {Silo} for queue {Queue}.\"\n        )]\n        private partial void LogInfoInit(string name, GrainId id, SiloAddress silo, QueueIdLogRecord queue);\n\n        [LoggerMessage(\n\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_23,\n            Message = \"Exception while calling IQueueAdapterCache.CreateQueueCache.\"\n        )]\n        private partial void LogErrorCreatingQueueCache(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_02,\n            Message = \"Exception while calling IQueueAdapter.CreateNewReceiver.\"\n        )]\n        private partial void LogErrorCreatingReceiver(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_03,\n            Message = \"QueueAdapterReceiver {QueueId} failed to Initialize.\"\n        )]\n        private partial void LogErrorReceiverInit(QueueIdLogRecord queueId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_04,\n            Message = \"Taking queue {Queue} under my responsibility.\"\n        )]\n        private partial void LogInfoTakingQueue(QueueIdLogRecord queue);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_05,\n            Message = \"Shutdown of {Name} responsible for queue: {Queue}\"\n        )]\n        private partial void LogInfoShutdown(string name, QueueIdLogRecord queue);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_06,\n            Message = \"Unregister PersistentStreamPullingAgent Producer for stream {StreamId}.\"\n        )]\n        private partial void LogInfoUnregisterProducer(QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_07,\n            Message = \"Failed to unregister myself as stream producer to some streams that used to be in my responsibility.\"\n        )]\n        private partial void LogWarningUnregisterProducer(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_09,\n            Message = \"AddSubscriber: Stream={StreamId} Subscriber={SubscriberId}.\"\n        )]\n        private partial void LogDebugAddSubscriber(QualifiedStreamId streamId, GrainId subscriberId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_10,\n            Message = \"Removed consumer: subscription {SubscriptionId}, for stream {StreamId}.\"\n        )]\n        private partial void LogDebugRemovedConsumer(GuidId subscriptionId, QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_12,\n            Message = \"Giving up reading from queue {QueueId} after retry attempts {ReadLoopRetryMax}\"\n        )]\n        private partial void LogErrorGivingUpReading(QueueIdLogRecord queueId, int readLoopRetryMax, Exception exception);\n\n        [LoggerMessage(\n\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_12,\n            Message = \"Exception while retrying the {RetryCounter}th time reading from queue {QueueId}\"\n        )]\n        private partial void LogErrorRetrying(int retryCounter, QueueIdLogRecord queueId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_27,\n            Message = \"Exception calling MessagesDeliveredAsync on queue {MyQueueId}. Ignoring.\"\n        )]\n        private partial void LogWarningMessagesDeliveredAsync(QueueIdLogRecord myQueueId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_24,\n            Message = \"Stream cache is under pressure. Backing off.\"\n        )]\n        private partial void LogInfoStreamCacheUnderPressure();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_11,\n            Message = \"Got {ReceivedCount} messages from queue {Queue}. So far {MessageCount} messages from this queue.\"\n        )]\n        private partial void LogTraceGotMessages(int receivedCount, QueueIdLogRecord queue, int messageCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Pulled new messages in stream {StreamId} from the queue, but the subscriber isn't fully registered yet. The pulling agent will start deliver on this stream after registration is complete.\"\n        )]\n        private partial void LogDebugPulledNewMessages(QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_14,\n            Message = \"Exception while trying to deliver msgs to stream {StreamId} in PersistentStreamPullingAgentGrain.RunConsumerCursor\"\n        )]\n        private partial void LogErrorDeliveringMessages(QualifiedStreamId streamId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_15,\n            Message = \"Ignored RunConsumerCursor error\"\n        )]\n        private partial void LogErrorRunConsumerCursor(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to deliver message to consumer on {SubscriptionId} for stream {StreamId}, may retry.\"\n        )]\n        private partial void LogWarningFailedToDeliverMessage(GuidId subscriptionId, QualifiedStreamId streamId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.Stream_ConsumerIsDead,\n            Message = \"Consumer {Consumer} on stream {StreamId} is no longer active - permanently removing Consumer.\"\n        )]\n        private partial void LogWarningConsumerIsDead(IStreamConsumerExtension consumer, QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_17,\n            Message = \"RegisterAsStreamProducer failed\"\n        )]\n        private static partial void LogErrorRegisterAsStreamProducer(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_16,\n            Message = \"Got back {Count} subscribers for stream {StreamId}.\"\n        )]\n        private partial void LogDebugGotBackSubscribers(int count, QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_17,\n            Message = \"Ignored RegisterAsStreamProducer error\"\n        )]\n        private partial void LogErrorIgnoredRegisterAsStreamProducer(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.PersistentStreamPullingAgent_13,\n            Message = \"Ignoring exception while trying to evaluate subscription filter '{Filter}' with data '{FilterData}' on stream {StreamId}\"\n        )]\n        private partial void LogWarningFilterEvaluation(string filter, string filterData, StreamId streamId, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/PersistentStreamPullingManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Configuration;\nusing RunState = Orleans.Configuration.StreamLifecycleOptions.RunState;\nusing Orleans.Internal;\nusing System.Threading;\nusing Orleans.Streams.Filtering;\nusing Orleans.Runtime.Scheduler;\nusing System.Diagnostics.Metrics;\n\nnamespace Orleans.Streams\n{\n    internal sealed partial class PersistentStreamPullingManager : SystemTarget, IPersistentStreamPullingManager, IStreamQueueBalanceListener\n    {\n        private static readonly TimeSpan QUEUES_PRINT_PERIOD = TimeSpan.FromMinutes(5);\n\n        private readonly Dictionary<QueueId, PersistentStreamPullingAgent> queuesToAgentsMap;\n        private readonly Dictionary<QueueId, PersistentStreamPullingAgent> deactivatedAgents = new();\n        private readonly string streamProviderName;\n        private readonly IStreamPubSub pubSub;\n        private readonly SystemTargetShared _systemTargetShared;\n\n        private readonly StreamPullingAgentOptions options;\n        private readonly AsyncSerialExecutor nonReentrancyGuarantor; // for non-reentrant execution of queue change notifications.\n        private readonly ILogger logger;\n        private int latestRingNotificationSequenceNumber;\n        private int latestCommandNumber;\n        private readonly IQueueAdapter queueAdapter;\n        private readonly IBackoffProvider _deliveryBackoffProvider;\n        private readonly IBackoffProvider _queueReaderBackoffProvider;\n        private readonly IQueueAdapterCache queueAdapterCache;\n        private IStreamQueueBalancer queueBalancer;\n        private readonly IStreamFilter streamFilter;\n        private readonly IQueueAdapterFactory adapterFactory;\n        private RunState managerState;\n        private IDisposable queuePrintTimer;\n        private int nextAgentId;\n        private int NumberRunningAgents { get { return queuesToAgentsMap.Count; } }\n\n\n        internal PersistentStreamPullingManager(\n            SystemTargetGrainId managerId,\n            string strProviderName,\n            IStreamPubSub streamPubSub,\n            IQueueAdapterFactory adapterFactory,\n            IStreamQueueBalancer streamQueueBalancer,\n            IStreamFilter streamFilter,\n            StreamPullingAgentOptions options,\n            IQueueAdapter queueAdapter,\n            IBackoffProvider deliveryBackoffProvider,\n            IBackoffProvider queueReaderBackoffProvider,\n            SystemTargetShared shared)\n            : base(managerId, shared)\n        {\n            if (string.IsNullOrWhiteSpace(strProviderName))\n            {\n                throw new ArgumentNullException(nameof(strProviderName));\n            }\n\n            if (streamPubSub == null)\n            {\n                throw new ArgumentNullException(nameof(streamPubSub), \"StreamPubSub reference should not be null\");\n            }\n\n            if (streamQueueBalancer == null)\n            {\n                throw new ArgumentNullException(nameof(streamQueueBalancer), \"IStreamQueueBalancer streamQueueBalancer reference should not be null\");\n            }\n\n            queuesToAgentsMap = new Dictionary<QueueId, PersistentStreamPullingAgent>();\n            streamProviderName = strProviderName;\n            pubSub = streamPubSub;\n            this.options = options;\n            nonReentrancyGuarantor = new AsyncSerialExecutor();\n            latestRingNotificationSequenceNumber = 0;\n            latestCommandNumber = 0;\n            queueBalancer = streamQueueBalancer;\n            this.streamFilter = streamFilter;\n            this.adapterFactory = adapterFactory;\n            this.queueAdapter = queueAdapter ?? throw new ArgumentNullException(nameof(queueAdapter));\n            _deliveryBackoffProvider = deliveryBackoffProvider;\n            _queueReaderBackoffProvider = queueReaderBackoffProvider;\n            _systemTargetShared = shared;\n            queueAdapterCache = adapterFactory.GetQueueAdapterCache();\n            logger = shared.LoggerFactory.CreateLogger($\"{GetType().FullName}.{streamProviderName}\");\n            LogInfoCreated(GetType().Name, streamProviderName);\n            StreamInstruments.RegisterPersistentStreamPullingAgentsObserve(() => new Measurement<int>(queuesToAgentsMap.Count, new KeyValuePair<string, object>(\"name\", streamProviderName)));\n            shared.ActivationDirectory.RecordNewTarget(this);\n        }\n\n        public async Task Initialize()\n        {\n            LogInfoInit();\n\n            await this.queueBalancer.Initialize(this.adapterFactory.GetStreamQueueMapper());\n            queueBalancer.SubscribeToQueueDistributionChangeEvents(this);\n\n            List<QueueId> myQueues = queueBalancer.GetMyQueues().ToList();\n            LogInfoInitialized(myQueues.Count, new(myQueues));\n\n            queuePrintTimer = this.RegisterTimer(AsyncTimerCallback, null, QUEUES_PRINT_PERIOD, QUEUES_PRINT_PERIOD);\n            managerState = RunState.Initialized;\n        }\n\n        public async Task Stop()\n        {\n            await StopAgents();\n            if (queuePrintTimer != null)\n            {\n                queuePrintTimer.Dispose();\n                this.queuePrintTimer = null;\n            }\n            await this.queueBalancer.Shutdown();\n            this.queueBalancer = null;\n        }\n\n        public async Task StartAgents()\n        {\n            managerState = RunState.AgentsStarted;\n            List<QueueId> myQueues = queueBalancer.GetMyQueues().ToList();\n\n            LogInfoStarting(myQueues.Count, new(myQueues));\n            await AddNewQueues(myQueues, true);\n            LogInfoStarted();\n        }\n\n        public async Task StopAgents()\n        {\n            managerState = RunState.AgentsStopped;\n            List<QueueId> queuesToRemove = queuesToAgentsMap.Keys.ToList();\n            LogInfoStopping(queuesToRemove.Count, new(queuesToRemove));\n            await RemoveQueues(queuesToRemove);\n            LogInfoStopped();\n        }\n\n        /// <summary>\n        /// Actions to take when the queue distribution changes due to a failure or a join.\n        /// Since this pulling manager is system target and queue distribution change notifications\n        /// are delivered to it as grain method calls, notifications are not reentrant. To simplify\n        /// notification handling we execute them serially, in a non-reentrant way.  We also suppress\n        /// and don't execute an older notification if a newer one was already delivered.\n        /// </summary>\n        public Task QueueDistributionChangeNotification()\n        {\n            return this.RunOrQueueTask(() => this.HandleQueueDistributionChangeNotification());\n        }\n\n        public Task HandleQueueDistributionChangeNotification()\n        {\n            latestRingNotificationSequenceNumber++;\n            int notificationSeqNumber = latestRingNotificationSequenceNumber;\n            LogInfoGotQueueChangeNotification(notificationSeqNumber, managerState);\n            if (managerState == RunState.AgentsStopped)\n            {\n                return Task.CompletedTask; // if agents not running, no need to rebalance the queues among them.\n            }\n\n            return nonReentrancyGuarantor.AddNext(() =>\n            {\n                // skip execution of an older/previous notification since already got a newer range update notification.\n                if (notificationSeqNumber < latestRingNotificationSequenceNumber)\n                {\n                    LogInfoSkipQueueChangeNotification(notificationSeqNumber, latestRingNotificationSequenceNumber);\n                    return Task.CompletedTask;\n                }\n                if (managerState == RunState.AgentsStopped)\n                {\n                    return Task.CompletedTask; // if agents not running, no need to rebalance the queues among them.\n                }\n                return QueueDistributionChangeNotification(notificationSeqNumber);\n            });\n        }\n\n        private async Task QueueDistributionChangeNotification(int notificationSeqNumber)\n        {\n            HashSet<QueueId> currentQueues = queueBalancer.GetMyQueues().ToSet();\n            LogInfoExecutingQueueChangeNotification(\n                notificationSeqNumber,\n                currentQueues.Count,\n                new(currentQueues));\n\n            try\n            {\n                Task t1 = AddNewQueues(currentQueues, false);\n\n                List<QueueId> queuesToRemove = queuesToAgentsMap.Keys.Where(queueId => !currentQueues.Contains(queueId)).ToList();\n                Task t2 = RemoveQueues(queuesToRemove);\n\n                await Task.WhenAll(t1, t2);\n            }\n            finally\n            {\n                LogInfoDoneExecutingQueueChangeNotification(\n                    notificationSeqNumber,\n                    NumberRunningAgents,\n                    new(queuesToAgentsMap.Keys));\n            }\n        }\n\n        /// <summary>\n        /// Take responsibility for a set of new queues that were assigned to me via a new range.\n        /// We first create one pulling agent for every new queue and store them in our internal data structure, then try to initialize the agents.\n        /// ERROR HANDLING:\n        ///     The responsibility to handle initialization and shutdown failures is inside the Agents code.\n        ///     The manager will call Initialize once and log an error. It will not call initialize again and will assume initialization has succeeded.\n        ///     Same applies to shutdown.\n        /// </summary>\n        /// <param name=\"myQueues\"></param>\n        /// <param name=\"failOnInit\"></param>\n        /// <returns></returns>\n        private async Task AddNewQueues(IEnumerable<QueueId> myQueues, bool failOnInit)\n        {\n            // Create agents for queues in range that we don't yet have.\n            // First create them and store in local queuesToAgentsMap.\n            // Only after that Initialize them all.\n            var agents = new List<PersistentStreamPullingAgent>();\n            foreach (var queueId in myQueues)\n            {\n                if (queuesToAgentsMap.ContainsKey(queueId))\n                {\n                    continue;\n                }\n                else if (deactivatedAgents.Remove(queueId, out var agent))\n                {\n                    queuesToAgentsMap[queueId] = agent;\n                    agents.Add(agent);\n                }\n                else\n                {\n                    // Create a new agent.\n                    try\n                    {\n                        var agentIdNumber = Interlocked.Increment(ref nextAgentId);\n                        var agentId = SystemTargetGrainId.Create(Constants.StreamPullingAgentType, this.Silo, $\"{streamProviderName}_{agentIdNumber}_{queueId:H}\");\n                        IStreamFailureHandler deliveryFailureHandler = await adapterFactory.GetDeliveryFailureHandler(queueId);\n                        agent = new PersistentStreamPullingAgent(\n                            agentId,\n                            streamProviderName,\n                            pubSub,\n                            streamFilter,\n                            queueId,\n                            this.options,\n                            queueAdapter,\n                            queueAdapterCache,\n                            deliveryFailureHandler,\n                            _deliveryBackoffProvider,\n                            _queueReaderBackoffProvider,\n                            _systemTargetShared);\n                        queuesToAgentsMap.Add(queueId, agent);\n                        agents.Add(agent);\n                    }\n                    catch (Exception exc)\n                    {\n                        LogErrorCreatingAgent(exc);\n                        // What should we do? This error is not recoverable and considered a bug. But we don't want to bring the silo down.\n                        // If this is when silo is starting and agent is initializing, fail the silo startup. Otherwise, just swallow to limit impact on other receivers.\n                        if (failOnInit) throw;\n                    }\n                }\n            }\n\n            try\n            {\n                var initTasks = new List<Task>();\n                foreach (var agent in agents)\n                {\n                    initTasks.Add(InitAgent(agent));\n                }\n                await Task.WhenAll(initTasks);\n            }\n            catch\n            {\n                // Just ignore this exception and proceed as if Initialize has succeeded.\n                // We already logged individual exceptions for individual calls to Initialize. No need to log again.\n            }\n            if (agents.Count > 0)\n            {\n                LogInfoAddedQueues(\n                    agents.Count,\n                    new(agents),\n                    NumberRunningAgents,\n                    new(queuesToAgentsMap.Keys));\n            }\n        }\n\n        private async Task InitAgent(PersistentStreamPullingAgent agent)\n        {\n            // Init the agent only after it was registered locally.\n            var agentGrainRef = agent.AsReference<IPersistentStreamPullingAgent>();\n\n            // Need to call it as a grain reference.\n            try\n            {\n                await agentGrainRef.Initialize();\n            }\n            catch (Exception exc)\n            {\n                LogErrorInitializingAgent(agent.QueueId, exc);\n            }\n        }\n\n        private async Task RemoveQueues(List<QueueId> queuesToRemove)\n        {\n            if (queuesToRemove.Count == 0)\n            {\n                return;\n            }\n            // Stop the agents that for queues that are not in my range anymore.\n            LogInfoRemovingAgents(queuesToRemove.Count, new(queuesToRemove));\n            var agents = new List<PersistentStreamPullingAgent>(queuesToRemove.Count);\n            var removeTasks = new List<Task>();\n            foreach (var queueId in queuesToRemove)\n            {\n                if (!queuesToAgentsMap.Remove(queueId, out var agent))\n                {\n                    continue;\n                }\n\n                agents.Add(agent);\n                deactivatedAgents[queueId] = agent;\n                var agentGrainRef = agent.AsReference<IPersistentStreamPullingAgent>();\n                var task = OrleansTaskExtentions.SafeExecute(agentGrainRef.Shutdown);\n                task = task.LogException(logger, ErrorCode.PersistentStreamPullingManager_11,\n                    $\"PersistentStreamPullingAgent {agent.QueueId} failed to Shutdown.\");\n                removeTasks.Add(task);\n            }\n            try\n            {\n                await Task.WhenAll(removeTasks);\n            }\n            catch\n            {\n                // Just ignore this exception and proceed as if Initialize has succeeded.\n                // We already logged individual exceptions for individual calls to Shutdown. No need to log again.\n            }\n\n            if (agents.Count > 0)\n            {\n                LogInfoRemovedQueues(\n                    agents.Count,\n                    new(agents),\n                    NumberRunningAgents,\n                    new(queuesToAgentsMap.Keys));\n            }\n        }\n\n        public async Task<object> ExecuteCommand(PersistentStreamProviderCommand command, object arg)\n        {\n            latestCommandNumber++;\n            int commandSeqNumber = latestCommandNumber;\n\n            try\n            {\n                LogInfoGotCommand(\n                    command,\n                    arg != null ? \" with arg \" + arg : string.Empty,\n                    commandSeqNumber,\n                    managerState);\n\n                switch (command)\n                {\n                    case PersistentStreamProviderCommand.StartAgents:\n                    case PersistentStreamProviderCommand.StopAgents:\n                        await QueueCommandForExecution(command, commandSeqNumber);\n                        return null;\n                    case PersistentStreamProviderCommand.GetAgentsState:\n                        return managerState;\n                    case PersistentStreamProviderCommand.GetNumberRunningAgents:\n                        return NumberRunningAgents;\n                    default:\n                        throw new OrleansException($\"PullingAgentManager does not support command {command}.\");\n                }\n            }\n            finally\n            {\n                LogInfoDoneExecutingCommand(\n                    command,\n                    commandSeqNumber,\n                    managerState,\n                    NumberRunningAgents);\n            }\n        }\n\n        // Start and Stop commands are composite commands that take multiple turns.\n        // Ee don't wnat them to interleave with other concurrent Start/Stop commands, as well as not with QueueDistributionChangeNotification.\n        // Therefore, we serialize them all via the same nonReentrancyGuarantor.\n        private Task QueueCommandForExecution(PersistentStreamProviderCommand command, int commandSeqNumber)\n        {\n            return nonReentrancyGuarantor.AddNext(() =>\n            {\n                // skip execution of an older/previous command since already got a newer command.\n                if (commandSeqNumber < latestCommandNumber)\n                {\n                    LogInfoSkipCommandExecution(\n                        commandSeqNumber,\n                        latestCommandNumber);\n                    return Task.CompletedTask;\n                }\n                switch (command)\n                {\n                    case PersistentStreamProviderCommand.StartAgents:\n                        return StartAgents();\n                    case PersistentStreamProviderCommand.StopAgents:\n                        return StopAgents();\n                    default:\n                        throw new OrleansException($\"PullingAgentManager got unsupported command {command}\");\n                }\n            });\n        }\n\n        private static string PrintQueues(ICollection<QueueId> myQueues) => Utils.EnumerableToString(myQueues);\n\n        // Just print our queue assignment periodicaly, for easy monitoring.\n        private Task AsyncTimerCallback(object state)\n        {\n            LogInfoPeriodicPrint(NumberRunningAgents, streamProviderName, new(queuesToAgentsMap.Keys));\n            return Task.CompletedTask;\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_01,\n            Message = \"Created {Name} for Stream Provider {StreamProvider}.\"\n        )]\n        private partial void LogInfoCreated(string name, string streamProvider);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_02,\n            Message = \"Init.\"\n        )]\n        private partial void LogInfoInit();\n\n        private readonly struct QueueIdsLogRecord(ICollection<QueueId> queues)\n        {\n            public override string ToString() => PrintQueues(queues);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_03,\n            Message = \"Initialize: I am now responsible for {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoInitialized(int queueCount, QueueIdsLogRecord queues);\n\n        //\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_Starting,\n            Message = \"Starting agents for {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoStarting(int queueCount, QueueIdsLogRecord queues);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_Started,\n            Message = \"Started agents.\"\n        )]\n        private partial void LogInfoStarted();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_Stopping,\n            Message = \"Stopping agents for {RemovedCount} queues: {RemovedQueues}.\"\n        )]\n        private partial void LogInfoStopping(int removedCount, QueueIdsLogRecord removedQueues);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_Stopped,\n            Message = \"Stopped agents.\"\n        )]\n        private partial void LogInfoStopped();\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_04,\n            Message = \"Got QueueChangeNotification number {NotificationSequenceNumber} from the queue balancer. managerState = {ManagerState}.\"\n        )]\n        private partial void LogInfoGotQueueChangeNotification(int notificationSequenceNumber, RunState managerState);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_05,\n            Message = \"Skipping execution of QueueChangeNotification number {NotificationSequenceNumber} from the queue allocator since already received a later notification (already have notification number {LatestNotificationNumber}).\"\n        )]\n        private partial void LogInfoSkipQueueChangeNotification(int notificationSequenceNumber, int latestNotificationNumber);\n\n        //  \"Executing QueueChangeNotification number {NotificationSequenceNumber}. Queue balancer says I should now own {QueueCount} queues: {Queues}\"\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_06,\n            Message = \"Executing QueueChangeNotification number {NotificationSequenceNumber}. Queue balancer says I should now own {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoExecutingQueueChangeNotification(int notificationSequenceNumber, int queueCount, QueueIdsLogRecord queues);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_16,\n            Message = \"Done Executing QueueChangeNotification number {NotificationSequenceNumber}. I now own {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoDoneExecutingQueueChangeNotification(int notificationSequenceNumber, int queueCount, QueueIdsLogRecord queues);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_07,\n            Message = \"Exception while creating PersistentStreamPullingAgent.\"\n        )]\n        private partial void LogErrorCreatingAgent(Exception exc);\n\n        private readonly struct AgentsLogRecord(List<PersistentStreamPullingAgent> agents)\n        {\n            public override string ToString() => Utils.EnumerableToString(agents, agent => agent.QueueId.ToString());\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_08,\n            Message = \"Added {AddedCount} new queues: {AddedQueues}. Now own total of {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoAddedQueues(int addedCount, AgentsLogRecord addedQueues, int queueCount, QueueIdsLogRecord queues);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_09,\n            Message = \"PersistentStreamPullingAgent {QueueId} failed to Initialize.\"\n        )]\n        private partial void LogErrorInitializingAgent(QueueId queueId, Exception exc);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_10,\n            Message = \"About to remove {RemovedCount} agents from my responsibility: {RemovedQueues}.\"\n        )]\n        private partial void LogInfoRemovingAgents(int removedCount, QueueIdsLogRecord removedQueues);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_10,\n            Message = \"Removed {RemovedCount} queues: {RemovedQueues}. Now own total of {QueueCount} queues: {Queues}.\"\n        )]\n        private partial void LogInfoRemovedQueues(int removedCount, AgentsLogRecord removedQueues, int queueCount, QueueIdsLogRecord queues);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_13,\n            Message = \"Got command {Command}{ArgString}: commandSeqNumber = {CommandSequenceNumber}, managerState = {ManagerState}.\"\n        )]\n        private partial void LogInfoGotCommand(PersistentStreamProviderCommand command, string argString, int commandSequenceNumber, RunState managerState);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_15,\n            Message = \"Done executing command {Command}: commandSeqNumber = {CommandSequenceNumber}, managerState = {ManagerState}, num running agents = {NumRunningAgents}.\"\n        )]\n        private partial void LogInfoDoneExecutingCommand(PersistentStreamProviderCommand command, int commandSequenceNumber, RunState managerState, int numRunningAgents);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_15,\n            Message = \"Skipping execution of command number {CommandNumber} since already received a later command (already have command number {LatestCommandNumber}).\"\n        )]\n        private partial void LogInfoSkipCommandExecution(int commandNumber, int latestCommandNumber);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            EventId = (int)ErrorCode.PersistentStreamPullingManager_PeriodicPrint,\n            Message = \"I am responsible for a total of {QueueCount} queues on stream provider {StreamProviderName}: {Queues}.\"\n        )]\n        private partial void LogInfoPeriodicPrint(int queueCount, string streamProviderName, QueueIdsLogRecord queues);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/QueueStreamDataStructures.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\n#nullable enable\nnamespace Orleans.Streams\n{\n    [Serializable]\n    internal enum StreamConsumerDataState\n    {\n        Active, // Indicates that events are activly being delivered to this consumer.\n        Inactive, // Indicates that events are not activly being delivered to this consumers.  If adapter produces any events on this consumers stream, the agent will need begin delivering events\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class StreamConsumerData\n    {\n        [Id(0)]\n        public GuidId SubscriptionId;\n        [Id(1)]\n        public QualifiedStreamId StreamId;\n        [Id(2)]\n        public IStreamConsumerExtension StreamConsumer;\n        [Id(3)]\n        public StreamConsumerDataState State = StreamConsumerDataState.Inactive;\n        [Id(4)]\n        public IQueueCacheCursor? Cursor;\n        [Id(5)]\n        public StreamHandshakeToken? LastToken;\n        [Id(6)]\n        public string FilterData;\n\n        [NonSerialized]\n        public bool IsRegistered = false;\n        [NonSerialized]\n        public StreamSequenceToken? PendingStartToken;\n\n        public StreamConsumerData(GuidId subscriptionId, QualifiedStreamId streamId, IStreamConsumerExtension streamConsumer, string filterData)\n        {\n            SubscriptionId = subscriptionId;\n            StreamId = streamId;\n            StreamConsumer = streamConsumer;\n            FilterData = filterData;\n        }\n\n        internal void SafeDisposeCursor(ILogger logger)\n        {\n            if (Cursor is { } cursor)\n            {\n                Cursor = null;\n                // kill cursor activity and ensure it does not start again on this consumer data.\n                try\n                {\n                    cursor.Dispose();\n                }\n                catch (Exception ex)\n                {\n                    string? caller = null;\n                    try\n                    {\n                        caller = $\"Cursor.Dispose on stream {StreamId}, StreamConsumer {StreamConsumer} has thrown exception.\";\n                    }\n                    catch { }\n                    Utils.LogIgnoredException(logger, ex, caller);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/StreamConsumerCollection.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class StreamConsumerCollection\n    {\n        [Id(0)]\n        private readonly Dictionary<GuidId, StreamConsumerData> queueData; // map of consumers for one stream: from Guid ConsumerId to StreamConsumerData\n        [Id(1)]\n        private DateTime lastActivityTime;\n\n        [Id(2)]\n        public bool StreamRegistered { get; set; }\n\n        public StreamConsumerCollection(DateTime now)\n        {\n            queueData = new Dictionary<GuidId, StreamConsumerData>();\n            lastActivityTime = now;\n        }\n\n        public StreamConsumerData AddConsumer(GuidId subscriptionId, QualifiedStreamId streamId, IStreamConsumerExtension streamConsumer, string filterData)\n        {\n            var consumerData = new StreamConsumerData(subscriptionId, streamId, streamConsumer, filterData);\n            queueData.Add(subscriptionId, consumerData);\n            lastActivityTime = DateTime.UtcNow;\n            return consumerData;\n        }\n\n        public bool RemoveConsumer(GuidId subscriptionId, ILogger logger)\n        {\n            if (!queueData.Remove(subscriptionId, out var consumer)) return false;\n\n            consumer.SafeDisposeCursor(logger);\n            return true;\n        }\n\n        public bool Contains(GuidId subscriptionId)\n        {\n            return queueData.ContainsKey(subscriptionId);\n        }\n\n        public bool TryGetConsumer(GuidId subscriptionId, out StreamConsumerData data)\n        {\n            return queueData.TryGetValue(subscriptionId, out data);\n        }\n\n        public IEnumerable<StreamConsumerData> AllConsumers()\n        {\n            return queueData.Values;\n        }\n\n        public void DisposeAll(ILogger logger)\n        {\n            foreach (StreamConsumerData consumer in queueData.Values)\n            {\n                consumer.SafeDisposeCursor(logger);\n            }\n            queueData.Clear();\n        }\n\n\n        public int Count\n        {\n            get { return queueData.Count; }\n        }\n\n        public void RefreshActivity(DateTime now)\n        {\n            lastActivityTime = now;\n        }\n\n        public bool IsInactive(DateTime now, TimeSpan inactivityPeriod)\n        {\n            // Consider stream inactive (with all its consumers) from the pulling agent perspective if:\n            // 1) There were no new events received for that stream in the last inactivityPeriod\n            // 2) All consumer for that stream are currently inactive (that is, all cursors are inactive) - \n            //    meaning there is nothing for those consumers in the adapter cache.\n            if (now - lastActivityTime < inactivityPeriod) return false;\n            return !queueData.Values.Any(data => data.State.Equals(StreamConsumerDataState.Active));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/StreamEventDeliveryFailureException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This exception indicates that a stream event was not successfully delivered to the consumer.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class StreamEventDeliveryFailureException : OrleansException\n    {\n        private const string ErrorStringFormat =\n            \"Stream provider failed to deliver an event.  StreamProvider:{0}  Stream:{1}\";\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamEventDeliveryFailureException\"/> class.\n        /// </summary>\n        public StreamEventDeliveryFailureException() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamEventDeliveryFailureException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public StreamEventDeliveryFailureException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamEventDeliveryFailureException\"/> class.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        internal StreamEventDeliveryFailureException(QualifiedStreamId streamId)\n            : base(string.Format(ErrorStringFormat, streamId.GetNamespace(), streamId.StreamId)) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamEventDeliveryFailureException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public StreamEventDeliveryFailureException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamEventDeliveryFailureException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        public StreamEventDeliveryFailureException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PersistentStreams/StreamPosition.cs",
    "content": "\nusing System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream position uniquely identifies the position of an event in a stream.\n    /// If acquiring a stream position for a batch of events, the stream position will be of the first event in the batch.\n    /// </summary>\n    public class StreamPosition\n    {\n        /// <summary>\n        /// Stream position consists of the stream identity and the sequence token\n        /// </summary>\n        /// <param name=\"streamId\">The stream identity.</param>\n        /// <param name=\"sequenceToken\">The stream sequence token.</param>\n        public StreamPosition(StreamId streamId, StreamSequenceToken sequenceToken)\n        {\n            if (sequenceToken == null)\n            {\n                throw new ArgumentNullException(nameof(sequenceToken));\n            }\n            StreamId = streamId;\n            SequenceToken = sequenceToken;\n        }\n\n        /// <summary>\n        /// Gets the identity of the stream\n        /// </summary>\n        public StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets the position in the stream\n        /// </summary>\n        public StreamSequenceToken SequenceToken { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Predicates/AllStreamNamespacesPredicate.cs",
    "content": "namespace Orleans.Streams\n{\n    /// <summary>\n    /// A stream namespace predicate which matches all namespaces.\n    /// </summary>\n    internal class AllStreamNamespacesPredicate : IStreamNamespacePredicate\n    {\n        /// <inheritdoc/>\n        public string PredicatePattern => \"*\";\n\n        /// <inheritdoc/>\n        public bool IsMatch(string streamNamespace)\n        {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Predicates/ExactMatchStreamNamespacePredicate.cs",
    "content": "using System;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream namespace predicate which matches exactly one, specified\n    /// </summary>\n    [Serializable, GenerateSerializer, Immutable]\n    internal sealed class ExactMatchStreamNamespacePredicate : IStreamNamespacePredicate\n    {\n        internal const string Prefix = \"namespace:\";\n\n        [Id(0)]\n        private readonly string targetStreamNamespace;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExactMatchStreamNamespacePredicate\"/> class.\n        /// </summary>\n        /// <param name=\"targetStreamNamespace\">The target stream namespace.</param>\n        public ExactMatchStreamNamespacePredicate(string targetStreamNamespace)\n        {\n            this.targetStreamNamespace = targetStreamNamespace;\n        }\n\n        /// <inheritdoc/>\n        public string PredicatePattern => $\"{Prefix}{this.targetStreamNamespace}\";\n\n        /// <inheritdoc/>\n        public bool IsMatch(string streamNamespace)\n        {\n            return string.Equals(targetStreamNamespace, streamNamespace?.Trim());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Predicates/IStreamNamespacePredicate.cs",
    "content": "namespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream namespace predicate used for filtering implicit subscriptions using \n    /// <see cref=\"ImplicitStreamSubscriptionAttribute\"/>.\n    /// </summary>\n    /// <remarks>All implementations must be serializable.</remarks>\n    public interface IStreamNamespacePredicate\n    {\n        /// <summary>\n        /// Defines if the consumer grain should subscribe to the specified namespace.\n        /// </summary>\n        /// <param name=\"streamNamespace\">The target stream namespace to check.</param>\n        /// <returns><c>true</c>, if the grain should subscribe to the specified namespace; <c>false</c>, otherwise.\n        /// </returns>\n        bool IsMatch(string streamNamespace);\n\n        /// <summary>\n        /// Gets a pattern to describe this predicate. This value is passed to instances of <see cref=\"IStreamNamespacePredicateProvider\"/> to recreate this predicate.\n        /// </summary>\n        string PredicatePattern { get; }\n    }\n\n    /// <summary>\n    /// Converts predicate pattern strings to <see cref=\"IStreamNamespacePredicate\"/> instances.\n    /// </summary>\n    /// <seealso cref=\"IStreamNamespacePredicate.PredicatePattern\"/>\n    public interface IStreamNamespacePredicateProvider\n    {\n        /// <summary>\n        /// Get the predicate matching the provided pattern. Returns <see langword=\"false\"/> if this provider cannot match the predicate.\n        /// </summary>\n        bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate);\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Predicates/RegexStreamNamespacePredicate.cs",
    "content": "using System;\nusing System.Text.RegularExpressions;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// <see cref=\"IStreamNamespacePredicate\"/> implementation allowing to filter stream namespaces by regular\n    /// expression.\n    /// </summary>\n    public class RegexStreamNamespacePredicate : IStreamNamespacePredicate\n    {\n        internal const string Prefix = \"regex:\";\n        private readonly Regex regex;\n\n        /// <summary>\n        /// Returns a pattern used to describe this instance. The pattern will be parsed by an <see cref=\"IStreamNamespacePredicateProvider\"/> instance on each node.\n        /// </summary>\n        public string PredicatePattern => $\"{Prefix}{regex}\";\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"RegexStreamNamespacePredicate\"/> with the specified regular expression.\n        /// </summary>\n        /// <param name=\"regex\">The stream namespace regular expression.</param>\n        public RegexStreamNamespacePredicate(string regex)\n        {\n            ArgumentNullException.ThrowIfNull(regex);\n            this.regex = new Regex(regex, RegexOptions.Compiled);\n        }\n\n        /// <inheritdoc />\n        public bool IsMatch(string streamNameSpace)\n        {\n            return regex.IsMatch(streamNameSpace);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/Predicates/StreamSubscriptionAttributes.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// The [Orleans.ImplicitStreamSubscription] attribute is used to mark grains as implicit stream subscriptions.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public class ImplicitStreamSubscriptionAttribute : Attribute, IGrainBindingsProviderAttribute\n    {\n        /// <summary>\n        /// Gets the stream namespace filter predicate.\n        /// </summary>\n        public IStreamNamespacePredicate Predicate { get; }\n\n        /// <summary>\n        /// Gets the name of the stream identifier mapper.\n        /// </summary>\n        /// <value>The name of the stream identifier mapper.</value>\n        /// <remarks>\n        /// This value is the name used to resolve the <see cref=\"IStreamIdMapper\"/> registered in the dependency injection container.\n        /// </remarks>\n        public string StreamIdMapper { get; init; }\n\n        /// <summary>\n        /// Used to subscribe to all stream namespaces.\n        /// </summary>\n        public ImplicitStreamSubscriptionAttribute()\n        {\n            Predicate = new AllStreamNamespacesPredicate();\n        }\n\n        /// <summary>\n        /// Used to subscribe to the specified stream namespace.\n        /// </summary>\n        /// <param name=\"streamNamespace\">The stream namespace to subscribe.</param>\n        /// <param name=\"streamIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitStreamSubscriptionAttribute(string streamNamespace, string streamIdMapper = null)\n        {\n            Predicate = new ExactMatchStreamNamespacePredicate(streamNamespace.Trim());\n            StreamIdMapper = streamIdMapper;\n        }\n\n        /// <summary>\n        /// Allows to pass an arbitrary predicate type to filter stream namespaces to subscribe. The predicate type \n        /// must have a constructor without parameters.\n        /// </summary>\n        /// <param name=\"predicateType\">The stream namespace predicate type.</param>\n        /// <param name=\"streamIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitStreamSubscriptionAttribute(Type predicateType, string streamIdMapper = null)\n        {\n            Predicate = (IStreamNamespacePredicate) Activator.CreateInstance(predicateType);\n            StreamIdMapper = streamIdMapper;\n        }\n\n        /// <summary>\n        /// Allows to pass an instance of the stream namespace predicate. To be used mainly as an extensibility point\n        /// via inheriting attributes.\n        /// </summary>\n        /// <param name=\"predicate\">The stream namespace predicate.</param>\n        /// <param name=\"streamIdMapper\">The name of the stream identity mapper.</param>\n        public ImplicitStreamSubscriptionAttribute(IStreamNamespacePredicate predicate, string streamIdMapper = null)\n        {\n            Predicate = predicate;\n            StreamIdMapper = streamIdMapper;\n        }\n\n        /// <inheritdoc />\n        public IEnumerable<Dictionary<string, string>> GetBindings(IServiceProvider services, Type grainClass, GrainType grainType)\n        {\n            var binding = new Dictionary<string, string>\n            {\n                [WellKnownGrainTypeProperties.BindingTypeKey] = WellKnownGrainTypeProperties.StreamBindingTypeValue,\n                [WellKnownGrainTypeProperties.StreamBindingPatternKey] = this.Predicate.PredicatePattern,\n                [WellKnownGrainTypeProperties.StreamIdMapperKey] = this.StreamIdMapper,\n            };\n\n            if (LegacyGrainId.IsLegacyGrainType(grainClass))\n            {\n                string keyType;\n\n                if (typeof(IGrainWithGuidKey).IsAssignableFrom(grainClass) || typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(grainClass))\n                    keyType = nameof(Guid);\n                else if (typeof(IGrainWithIntegerKey).IsAssignableFrom(grainClass) || typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(grainClass))\n                    keyType = nameof(Int64);\n                else // fallback to string\n                    keyType = nameof(String);\n\n                binding[WellKnownGrainTypeProperties.LegacyGrainKeyType] = keyType;\n            }\n\n            if (LegacyGrainId.IsLegacyKeyExtGrainType(grainClass))\n            {\n                binding[WellKnownGrainTypeProperties.StreamBindingIncludeNamespaceKey] = \"true\";\n            }\n\n            yield return binding;\n        }\n    }\n\n    /// <summary>\n    /// The [Orleans.RegexImplicitStreamSubscription] attribute is used to mark grains as implicit stream\n    /// subscriptions by filtering stream namespaces to subscribe using a regular expression.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\n    public sealed class RegexImplicitStreamSubscriptionAttribute : ImplicitStreamSubscriptionAttribute\n    {\n        /// <summary>\n        /// Allows to pass a regular expression to filter stream namespaces to subscribe to.\n        /// </summary>\n        /// <param name=\"pattern\">The stream namespace regular expression filter.</param>\n        public RegexImplicitStreamSubscriptionAttribute([StringSyntax(StringSyntaxAttribute.Regex)] string pattern)\n            : base(new RegexStreamNamespacePredicate(pattern))\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/ProviderErrorCode.cs",
    "content": "namespace Orleans.Providers\n{\n    internal enum ProviderErrorCode\n    {\n        ProvidersBase = 200000,\n\n        MemoryStreamProviderBase                    = ProvidersBase + 400,\n        MemoryStreamProviderBase_QueueMessageBatchAsync = MemoryStreamProviderBase + 1,\n        MemoryStreamProviderBase_GetQueueMessagesAsync = MemoryStreamProviderBase + 2,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/ClientStreamingProviderRuntime.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Providers\n{\n    internal class ClientStreamingProviderRuntime : IStreamProviderRuntime, ILifecycleParticipant<IClusterClientLifecycle>\n    {\n        private readonly IStreamPubSub grainBasedPubSub;\n        private readonly IStreamPubSub implicitPubSub;\n        private readonly IStreamPubSub combinedGrainBasedAndImplicitPubSub;\n        private StreamDirectory streamDirectory;\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly ImplicitStreamSubscriberTable implicitSubscriberTable;\n        private readonly ClientGrainContext clientContext;\n        private readonly IRuntimeClient runtimeClient;\n\n        public ClientStreamingProviderRuntime(\n            IInternalGrainFactory grainFactory,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            ImplicitStreamSubscriberTable implicitSubscriberTable,\n            ClientGrainContext clientContext)\n        {\n            this.grainFactory = grainFactory;\n            this.ServiceProvider = serviceProvider;\n            this.implicitSubscriberTable = implicitSubscriberTable;\n            this.clientContext = clientContext;\n            this.runtimeClient = serviceProvider.GetService<IRuntimeClient>();\n            grainBasedPubSub = new GrainBasedPubSubRuntime(GrainFactory);\n            var tmp = new ImplicitStreamPubSub(this.grainFactory, this.implicitSubscriberTable);\n            implicitPubSub = tmp;\n            combinedGrainBasedAndImplicitPubSub = new StreamPubSubImpl(grainBasedPubSub, tmp);\n            streamDirectory = new StreamDirectory();\n        }\n\n        public IGrainFactory GrainFactory => this.grainFactory;\n\n        public IServiceProvider ServiceProvider { get; }\n\n        public StreamDirectory GetStreamDirectory()\n        {\n            return streamDirectory;\n        }\n\n        public async Task Reset(bool cleanup = true)\n        {\n            if (streamDirectory != null)\n            {\n                var tmp = streamDirectory;\n                streamDirectory = null; // null streamDirectory now, just to make sure we call cleanup only once, in all cases.\n                if (cleanup)\n                {\n                    await tmp.Cleanup(true, true);\n                }\n            }\n        }\n\n        public string ExecutingEntityIdentity()\n        {\n            return this.runtimeClient.CurrentActivationIdentity;\n        }\n\n        public (TExtension, TExtensionInterface) BindExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            return this.clientContext.GetOrSetExtension<TExtension, TExtensionInterface>(newExtensionFunc);\n        }\n\n        public IStreamPubSub PubSub(StreamPubSubType pubSubType)\n        {\n            switch (pubSubType)\n            {\n                case StreamPubSubType.ExplicitGrainBasedAndImplicit:\n                    return combinedGrainBasedAndImplicitPubSub;\n                case StreamPubSubType.ExplicitGrainBasedOnly:\n                    return grainBasedPubSub;\n                case StreamPubSubType.ImplicitOnly:\n                    return implicitPubSub;\n                default:\n                    return null;\n            }\n        }\n\n        public void Participate(IClusterClientLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<ClientStreamingProviderRuntime>(ServiceLifecycleStage.RuntimeInitialize,\n                ct => Task.CompletedTask,\n                async ct => await this.Reset(!ct.IsCancellationRequested));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/IBackoffProviders.cs",
    "content": "using Orleans.Internal;\nusing Orleans.Streams;\n\nnamespace Orleans.Runtime.Providers;\n\n/// <summary>\n/// Functionality for determining how long the <see cref=\"IPersistentStreamPullingAgent\"/> will wait between successive attempts to deliver a message.\n/// </summary>\npublic interface IMessageDeliveryBackoffProvider : IBackoffProvider { }\n\n/// <summary>\n/// Functionality for determining how long the <see cref=\"IPersistentStreamPullingAgent\"/> will wait between successive attempts to read a message from a queue.\n/// </summary>\npublic interface IQueueReaderBackoffProvider : IBackoffProvider { }\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/IStreamProvider.cs",
    "content": "using Orleans.Runtime;\nusing System;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Functionality for providing streams to consumers and producers.\n    /// </summary>\n    public interface IStreamProvider\n    {\n        /// <summary>\n        /// Gets the name of the stream provider.\n        /// </summary>\n        /// <value>The name.</value>\n        string Name { get; }\n\n        /// <summary>\n        /// Gets the stream with the specified identity.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>The stream.</returns>\n        IAsyncStream<T> GetStream<T>(StreamId streamId);\n        /// <summary>\n        /// Gets a value indicating whether this is a rewindable provider - supports creating rewindable streams \n        /// (streams that allow subscribing from previous point in time).\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if this is a rewindable provider, <see langword=\"false\"/> otherwise.</returns>\n        bool IsRewindable { get; }\n    }\n\n    /// <summary>\n    /// Extensions for <see cref=\"IStreamProvider\"/>.\n    /// </summary>\n    public static class StreamProviderExtensions\n    {\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, Guid id) => streamProvider.GetStream<T>(StreamId.Create(null, id));\n\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, Guid id) => streamProvider.GetStream<T>(StreamId.Create(ns, id));\n\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string id) => streamProvider.GetStream<T>(StreamId.Create(null, id));\n\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, string id) => streamProvider.GetStream<T>(StreamId.Create(ns, id));\n\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, long id) => streamProvider.GetStream<T>(StreamId.Create(null, id));\n\n        /// <summary>\n        /// Gets the stream with the specified identity and namespace.\n        /// </summary>\n        /// <typeparam name=\"T\">The stream element type.</typeparam>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <returns>The stream.</returns>\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, long id) => streamProvider.GetStream<T>(StreamId.Create(ns, id));\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/IStreamProviderRuntime.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Provider-facing interface for manager of streaming providers\n    /// </summary>\n    internal interface IStreamProviderRuntime : IProviderRuntime\n    {\n        /// <summary>\n        /// Retrieves the opaque identity of currently executing grain or client object. \n        /// </summary>\n        /// <remarks>Exposed for logging purposes.</remarks>\n        string ExecutingEntityIdentity();\n\n        /// <summary>\n        /// Returns the stream directory.\n        /// </summary>\n        /// <returns>The stream directory.</returns>\n        StreamDirectory GetStreamDirectory();\n\n        /// <summary>\n        /// A Pub Sub runtime interface.\n        /// </summary>\n        /// <returns></returns>\n        IStreamPubSub PubSub(StreamPubSubType pubSubType);\n    }\n\n    /// <summary>\n    /// Provider-facing interface for manager of streaming providers\n    /// </summary>\n    internal interface ISiloSideStreamProviderRuntime : IStreamProviderRuntime\n    {\n        /// <summary>Start the pulling agents for a given persistent stream provider.</summary>\n        Task<IPersistentStreamPullingManager> InitializePullingAgents(\n            string streamProviderName,\n            IQueueAdapterFactory adapterFactory,\n            IQueueAdapter queueAdapter);\n    }\n\n    /// <summary>\n    /// Identifies the publish/subscribe system types which stream providers can use.\n    /// </summary>\n    public enum StreamPubSubType\n    {        \n        /// <summary>\n        /// Explicit and implicit pub/sub.\n        /// </summary>\n        ExplicitGrainBasedAndImplicit,\n\n        /// <summary>\n        /// Explicit pub/sub.\n        /// </summary>\n        ExplicitGrainBasedOnly,\n\n        /// <summary>\n        /// Implicit pub/sub.\n        /// </summary>\n        ImplicitOnly,\n    }\n\n    public interface IStreamPubSub // Compare with: IPubSubRendezvousGrain\n    {\n        Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer);\n\n        Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer);\n\n        Task RegisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData);\n\n        Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId);\n\n        Task<int> ProducerCount(QualifiedStreamId streamId);\n\n        Task<int> ConsumerCount(QualifiedStreamId streamId);\n\n        Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer = default);\n\n        GuidId CreateSubscriptionId(QualifiedStreamId streamId, GrainId streamConsumer);\n\n        Task<bool> FaultSubscription(QualifiedStreamId streamId, GuidId subscriptionId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/ProviderStartException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Exception thrown whenever a provider has failed to be started.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class ProviderStartException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderStartException\"/> class.\n        /// </summary>\n        public ProviderStartException()\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderStartException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public ProviderStartException(string message)\n            : base(message)\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderStartException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public ProviderStartException(string message, Exception innerException)\n            : base(message, innerException)\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProviderStartException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private ProviderStartException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/SiloStreamProviderRuntime.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Streams;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Streams.Filtering;\nusing Orleans.Internal;\n\nnamespace Orleans.Runtime.Providers\n{\n    internal partial class SiloStreamProviderRuntime : ISiloSideStreamProviderRuntime\n    {\n        private readonly IConsistentRingProvider consistentRingProvider;\n        private readonly InsideRuntimeClient runtimeClient;\n        private readonly IStreamPubSub grainBasedPubSub;\n        private readonly IStreamPubSub implictPubSub;\n        private readonly IStreamPubSub combinedGrainBasedAndImplicitPubSub;\n        private readonly ILoggerFactory loggerFactory;\n        private readonly ILocalSiloDetails siloDetails;\n        private readonly IGrainContextAccessor grainContextAccessor;\n        private readonly ILogger logger;\n        private readonly StreamDirectory hostedClientStreamDirectory = new StreamDirectory();\n\n        public IGrainFactory GrainFactory => this.runtimeClient.InternalGrainFactory;\n        public IServiceProvider ServiceProvider => this.runtimeClient.ServiceProvider;\n\n        public SiloStreamProviderRuntime(\n            IConsistentRingProvider consistentRingProvider,\n            InsideRuntimeClient runtimeClient,\n            ImplicitStreamSubscriberTable implicitStreamSubscriberTable,\n            ILoggerFactory loggerFactory,\n            ILocalSiloDetails siloDetails,\n            IGrainContextAccessor grainContextAccessor)\n        {\n            this.loggerFactory = loggerFactory;\n            this.siloDetails = siloDetails;\n            this.grainContextAccessor = grainContextAccessor;\n            this.consistentRingProvider = consistentRingProvider;\n            this.runtimeClient = runtimeClient;\n            this.logger = this.loggerFactory.CreateLogger<SiloProviderRuntime>();\n            this.grainBasedPubSub = new GrainBasedPubSubRuntime(this.GrainFactory);\n            var tmp = new ImplicitStreamPubSub(this.runtimeClient.InternalGrainFactory, implicitStreamSubscriberTable);\n            this.implictPubSub = tmp;\n            this.combinedGrainBasedAndImplicitPubSub = new StreamPubSubImpl(this.grainBasedPubSub, tmp);\n        }\n\n        public IStreamPubSub PubSub(StreamPubSubType pubSubType)\n        {\n            switch (pubSubType)\n            {\n                case StreamPubSubType.ExplicitGrainBasedAndImplicit:\n                    return combinedGrainBasedAndImplicitPubSub;\n                case StreamPubSubType.ExplicitGrainBasedOnly:\n                    return grainBasedPubSub;\n                case StreamPubSubType.ImplicitOnly:\n                    return implictPubSub;\n                default:\n                    return null;\n            }\n        }\n\n        public async Task<IPersistentStreamPullingManager> InitializePullingAgents(\n            string streamProviderName,\n            IQueueAdapterFactory adapterFactory,\n            IQueueAdapter queueAdapter)\n        {\n            IStreamQueueBalancer queueBalancer = CreateQueueBalancer(streamProviderName);\n            (var deliveryProvider, var queueReaderProvider) = CreateBackoffProviders(streamProviderName);\n            var managerId = SystemTargetGrainId.Create(Constants.StreamPullingAgentManagerType, this.siloDetails.SiloAddress, streamProviderName);\n            var pubsubOptions = this.ServiceProvider.GetOptionsByName<StreamPubSubOptions>(streamProviderName);\n            var pullingAgentOptions = this.ServiceProvider.GetOptionsByName<StreamPullingAgentOptions>(streamProviderName);\n            var filter = this.ServiceProvider.GetKeyedService<IStreamFilter>(streamProviderName) ?? new NoOpStreamFilter();\n            var manager = new PersistentStreamPullingManager(\n                managerId,\n                streamProviderName,\n                this.PubSub(pubsubOptions.PubSubType),\n                adapterFactory,\n                queueBalancer,\n                filter,\n                pullingAgentOptions,\n                queueAdapter,\n                deliveryProvider,\n                queueReaderProvider,\n                ServiceProvider.GetRequiredService<SystemTargetShared>());\n\n            // Init the manager only after it was registered locally.\n            var pullingAgentManager = manager.AsReference<IPersistentStreamPullingManager>();\n\n            // Need to call it as a grain reference though.\n            await pullingAgentManager.Initialize();\n            return pullingAgentManager;\n        }\n\n        private (IBackoffProvider, IBackoffProvider) CreateBackoffProviders(string streamProviderName)\n        {\n            var deliveryProvider = (IBackoffProvider)ServiceProvider.GetKeyedService<IMessageDeliveryBackoffProvider>(streamProviderName) ??\n                new ExponentialBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(1));\n\n            var queueReaderProvider = (IBackoffProvider)ServiceProvider.GetKeyedService<IQueueReaderBackoffProvider>(streamProviderName) ??\n                new ExponentialBackoff(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(1));\n\n            return new(deliveryProvider, queueReaderProvider);\n        }\n\n        private IStreamQueueBalancer CreateQueueBalancer(string streamProviderName)\n        {\n            try\n            {\n                var balancer = this.ServiceProvider.GetKeyedService<IStreamQueueBalancer>(streamProviderName) ??this.ServiceProvider.GetService<IStreamQueueBalancer>();\n                if (balancer == null)\n                    throw new ArgumentOutOfRangeException(\"balancerType\", $\"Cannot create stream queue balancer for StreamProvider: {streamProviderName}.Please configure your stream provider with a queue balancer.\");\n                LogInfoSuccessfullyCreatedQueueBalancer(balancer.GetType(), streamProviderName);\n                return balancer;\n            }\n            catch (Exception e)\n            {\n                string error = $\"Cannot create stream queue balancer for StreamProvider: {streamProviderName}, Exception: {e}. Please configure your stream provider with a queue balancer.\";\n                throw new ArgumentOutOfRangeException(\"balancerType\", error);\n            }\n        }\n\n        /// <inheritdoc />\n        public string ExecutingEntityIdentity() => runtimeClient.CurrentActivationIdentity;\n\n        /// <inheritdoc />\n        public StreamDirectory GetStreamDirectory()\n        {\n            if (RuntimeContext.Current is { } activation)\n            {\n                var directory = activation.GetComponent<StreamDirectory>();\n                if (directory is null)\n                {\n                    directory = activation.ActivationServices.GetRequiredService<StreamDirectory>();\n                    activation.SetComponent(directory);\n                }\n\n                return directory;\n            }\n\n            return this.hostedClientStreamDirectory;\n        }\n\n        public (TExtension, TExtensionInterface) BindExtension<TExtension, TExtensionInterface>(Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface\n            where TExtensionInterface : class, IGrainExtension\n        {\n            if (this.grainContextAccessor.GrainContext is ActivationData activationData && activationData.IsStatelessWorker)\n            {\n                throw new InvalidOperationException($\"The extension { typeof(TExtension) } cannot be bound to a Stateless Worker.\");\n            }\n\n            return this.grainContextAccessor.GrainContext.GetComponent<IGrainExtensionBinder>().GetOrSetExtension<TExtension, TExtensionInterface>(newExtensionFunc);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Successfully created queue balancer of type {BalancerType} for stream provider {StreamProviderName}\"\n        )]\n        private partial void LogInfoSuccessfullyCreatedQueueBalancer(Type balancerType, string streamProviderName);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/Providers/StreamProviderDirection.cs",
    "content": "namespace Orleans.Streams\n{    \n    /// <summary>\n    /// Identifies whether a stream provider is read-only, read-write, or write-only.\n    /// </summary>\n    public enum StreamProviderDirection\n    {\n        /// <summary>\n        /// None.\n        /// </summary>\n        None,\n\n        /// <summary>\n        /// This provider can receive messages but cannot send them.\n        /// </summary>\n        ReadOnly,\n\n        /// <summary>\n        /// This provider can send messages but cannot receive them.\n        /// </summary>\n        WriteOnly,\n\n        /// <summary>\n        /// This provider can both send and receive messages.\n        /// </summary>\n        ReadWrite\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/DefaultStreamNamespacePredicateProvider.cs",
    "content": "using System;\nusing Orleans.Serialization.TypeSystem;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Default implementation of <see cref=\"IStreamNamespacePredicateProvider\"/> for internally supported stream predicates.\n    /// </summary>\n    public class DefaultStreamNamespacePredicateProvider : IStreamNamespacePredicateProvider\n    {  \n        /// <inheritdoc/>\n        public bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate)\n        {\n            switch (predicatePattern)\n            {\n                case \"*\":\n                    predicate = new AllStreamNamespacesPredicate();\n                    return true;\n                case var regex when regex.StartsWith(RegexStreamNamespacePredicate.Prefix, StringComparison.Ordinal):\n                    predicate = new RegexStreamNamespacePredicate(regex[RegexStreamNamespacePredicate.Prefix.Length..]);\n                    return true;\n                case var ns when ns.StartsWith(ExactMatchStreamNamespacePredicate.Prefix, StringComparison.Ordinal):\n                    predicate = new ExactMatchStreamNamespacePredicate(ns[ExactMatchStreamNamespacePredicate.Prefix.Length..]);\n                    return true;\n            }\n\n            predicate = null;\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Stream namespace predicate provider which supports objects which can be constructed and optionally accept a string as a constructor argument.\n    /// </summary>\n    public class ConstructorStreamNamespacePredicateProvider : IStreamNamespacePredicateProvider\n    {\n        /// <summary>\n        /// The prefix used to identify this predicate provider.\n        /// </summary>\n        public const string Prefix = \"ctor\";\n\n        /// <summary>\n        /// Formats a stream namespace predicate which indicates a concrete <see cref=\"IStreamNamespacePredicate\"/> type to be constructed, along with an optional argument.\n        /// </summary>\n        public static string FormatPattern(Type predicateType, string constructorArgument)\n        {\n            if (constructorArgument is null)\n            {\n                return $\"{Prefix}:{RuntimeTypeNameFormatter.Format(predicateType)}\";\n            }\n\n            return $\"{Prefix}:{RuntimeTypeNameFormatter.Format(predicateType)}:{constructorArgument}\";\n        }\n\n        /// <inheritdoc/>\n        public bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate)\n        {\n            if (!predicatePattern.StartsWith(Prefix, StringComparison.Ordinal))\n            {\n                predicate = null;\n                return false;\n            }\n\n            var start = Prefix.Length + 1;\n            string typeName;\n            string arg;\n            var index = predicatePattern.IndexOf(':', start);\n            if (index < 0)\n            {\n                typeName = predicatePattern[start..];\n                arg = null;\n            }\n            else\n            {\n                typeName = predicatePattern[start..index];\n                arg = predicatePattern[(index + 1)..];\n            }\n\n            var type = Type.GetType(typeName, throwOnError: true);\n            if (string.IsNullOrEmpty(arg))\n            {\n                predicate = (IStreamNamespacePredicate)Activator.CreateInstance(type);\n            }\n            else\n            {\n                predicate = (IStreamNamespacePredicate)Activator.CreateInstance(type, arg);\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/FaultedSubscriptionException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// This exception indicates that an error has occurred on a stream subscription that has placed the subscription into\n    ///  a faulted state.  Work on faulted subscriptions should be abandoned.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class FaultedSubscriptionException : OrleansException\n    {\n        private const string ErrorStringFormat =\n            \"Subscription is in a Faulted state.  Subscription:{0}, Stream:{1}\";\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FaultedSubscriptionException\"/> class.\n        /// </summary>\n        public FaultedSubscriptionException() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FaultedSubscriptionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public FaultedSubscriptionException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FaultedSubscriptionException\"/> class.\n        /// </summary>\n        /// <param name=\"subscriptionId\">The subscription identifier.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        internal FaultedSubscriptionException(GuidId subscriptionId, QualifiedStreamId streamId)\n            : base(string.Format(ErrorStringFormat, subscriptionId.Guid, streamId)) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FaultedSubscriptionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public FaultedSubscriptionException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FaultedSubscriptionException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private FaultedSubscriptionException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/GrainBasedPubSubRuntime.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal class GrainBasedPubSubRuntime : IStreamPubSub\n    {\n        private readonly IGrainFactory grainFactory;\n\n        public GrainBasedPubSubRuntime(IGrainFactory grainFactory)\n        {\n            this.grainFactory = grainFactory;\n        }\n\n        public Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.RegisterProducer(streamId, streamProducer);\n        }\n\n        public Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.UnregisterProducer(streamId, streamProducer);\n        }\n\n        public Task RegisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.RegisterConsumer(subscriptionId, streamId, streamConsumer, filterData);\n        }\n\n        public Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.UnregisterConsumer(subscriptionId, streamId);\n        }\n\n        public Task<int> ProducerCount(QualifiedStreamId streamId)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.ProducerCount(streamId);\n        }\n\n        public Task<int> ConsumerCount(QualifiedStreamId streamId)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.ConsumerCount(streamId);\n        }\n\n        public Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer = default)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            return streamRendezvous.GetAllSubscriptions(streamId, streamConsumer);\n        }\n\n        private IPubSubRendezvousGrain GetRendezvousGrain(QualifiedStreamId streamId)\n        {\n            return grainFactory.GetGrain<IPubSubRendezvousGrain>(streamId.ToString());\n        }\n\n        public GuidId CreateSubscriptionId(QualifiedStreamId streamId, GrainId streamConsumer)\n        {\n            Guid subscriptionId = SubscriptionMarker.MarkAsExplicitSubscriptionId(Guid.NewGuid());\n            return GuidId.GetGuidId(subscriptionId);\n        }\n\n        public async Task<bool> FaultSubscription(QualifiedStreamId streamId, GuidId subscriptionId)\n        {\n            var streamRendezvous = GetRendezvousGrain(streamId);\n            await streamRendezvous.FaultSubscription(subscriptionId);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/IPubSubRendezvousGrain.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal interface IPubSubRendezvousGrain : IGrainWithStringKey\n    {\n        Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer);\n\n        Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer);\n\n        Task RegisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData);\n\n        Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId);\n\n        Task<int> ProducerCount(QualifiedStreamId streamId);\n\n        Task<int> ConsumerCount(QualifiedStreamId streamId);\n\n        Task<PubSubSubscriptionState[]> DiagGetConsumers(QualifiedStreamId streamId);\n\n        Task Validate();\n\n        Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer = default);\n\n        Task FaultSubscription(GuidId subscriptionId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/ImplicitStreamPubSub.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal class ImplicitStreamPubSub : IStreamPubSub\n    {\n        private readonly IInternalGrainFactory grainFactory;\n        private readonly ImplicitStreamSubscriberTable implicitTable;\n\n        public ImplicitStreamPubSub(IInternalGrainFactory grainFactory, ImplicitStreamSubscriberTable implicitPubSubTable)\n        {\n            if (implicitPubSubTable == null)\n            {\n                throw new ArgumentNullException(nameof(implicitPubSubTable));\n            }\n\n            this.grainFactory = grainFactory;\n            this.implicitTable = implicitPubSubTable;\n        }\n\n        public Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            ISet<PubSubSubscriptionState> result = new HashSet<PubSubSubscriptionState>();\n            if (!ImplicitStreamSubscriberTable.IsImplicitSubscribeEligibleNameSpace(streamId.GetNamespace())) return Task.FromResult(result);\n\n            IDictionary<Guid, GrainId> implicitSubscriptions = implicitTable.GetImplicitSubscribers(streamId, this.grainFactory);\n            foreach (var kvp in implicitSubscriptions)\n            {\n                GuidId subscriptionId = GuidId.GetGuidId(kvp.Key);\n                result.Add(new PubSubSubscriptionState(subscriptionId, streamId, kvp.Value));\n            }\n            return Task.FromResult(result);\n        }\n\n        public Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task RegisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData)\n        {\n            // TODO BPETIT filter data?\n            if (!IsImplicitSubscriber(streamConsumer, streamId))\n            {\n                throw new ArgumentOutOfRangeException(streamId.ToString(), \"Only implicit subscriptions are supported.\");\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            if (!IsImplicitSubscriber(subscriptionId, streamId))\n            {\n                throw new ArgumentOutOfRangeException(streamId.ToString(), \"Only implicit subscriptions are supported.\");\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task<int> ProducerCount(QualifiedStreamId streamId)\n        {\n            return Task.FromResult(0);\n        }\n\n        public Task<int> ConsumerCount(QualifiedStreamId streamId)\n        {\n            return Task.FromResult(0);\n        }\n\n        public Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer = default)\n        {\n            if (!ImplicitStreamSubscriberTable.IsImplicitSubscribeEligibleNameSpace(streamId.GetNamespace()))\n                return Task.FromResult(new List<StreamSubscription>());\n\n            if (streamConsumer != default)\n            {\n                var subscriptionId = CreateSubscriptionId(streamId, streamConsumer);\n                return Task.FromResult(new List<StreamSubscription>\n                { new StreamSubscription(subscriptionId.Guid, streamId.ProviderName, streamId, streamConsumer) });\n            }\n            else\n            {\n                var implicitConsumers = this.implicitTable.GetImplicitSubscribers(streamId, grainFactory);\n                var subscriptions = implicitConsumers.Select(consumer =>\n                {\n                    var grainId = consumer.Value;\n                    var subId = consumer.Key;\n                    return new StreamSubscription(subId, streamId.ProviderName, streamId, grainId);\n                }).ToList();\n                return Task.FromResult(subscriptions);\n            }\n        }\n\n        internal bool IsImplicitSubscriber(GrainId grainId, QualifiedStreamId streamId)\n        {\n            return implicitTable.IsImplicitSubscriber(grainId, streamId);\n        }\n\n        internal bool IsImplicitSubscriber(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            return SubscriptionMarker.IsImplicitSubscription(subscriptionId.Guid);\n        }\n\n        public GuidId CreateSubscriptionId(QualifiedStreamId streamId, GrainId grainId)\n        {\n            Guid subscriptionGuid;\n            if (!implicitTable.TryGetImplicitSubscriptionGuid(grainId, streamId, out subscriptionGuid))\n            {\n                throw new ArgumentOutOfRangeException(streamId.ToString(), \"Only implicit subscriptions are supported.\");\n            }\n            return GuidId.GetGuidId(subscriptionGuid);\n        }\n\n        public Task<bool> FaultSubscription(QualifiedStreamId streamId, GuidId subscriptionId)\n        {\n            return Task.FromResult(false);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/ImplicitStreamSubscriberTable.cs",
    "content": "using System;\nusing System.Buffers.Binary;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    internal class ImplicitStreamSubscriberTable\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lockObj = new();\n#else\n        private readonly object _lockObj = new();\n#endif\n        private readonly GrainBindingsResolver _bindings;\n        private readonly IStreamNamespacePredicateProvider[] _providers;\n        private readonly IServiceProvider _serviceProvider;\n        private Cache _cache;\n\n        public ImplicitStreamSubscriberTable(\n            GrainBindingsResolver bindings,\n            IEnumerable<IStreamNamespacePredicateProvider> providers,\n            IServiceProvider serviceProvider)\n        {\n            _bindings = bindings;\n            var initialBindings = bindings.GetAllBindings();\n            _providers = providers.ToArray();\n            _serviceProvider = serviceProvider;\n            _cache = BuildCache(initialBindings.Version, initialBindings.Bindings);\n        }\n\n        private Cache GetCache()\n        {\n            var cache = _cache;\n            var bindings = _bindings.GetAllBindings();\n            if (bindings.Version == cache.Version)\n            {\n                return cache;\n            }\n\n            lock (_lockObj)\n            {\n                bindings = _bindings.GetAllBindings();\n                if (bindings.Version == cache.Version)\n                {\n                    return cache;\n                }\n\n                return _cache = BuildCache(bindings.Version, bindings.Bindings);\n            }\n        }\n\n        private Cache BuildCache(MajorMinorVersion version, ImmutableDictionary<GrainType, GrainBindings> bindings)\n        {\n            var newPredicates = new List<StreamSubscriberPredicate>();\n\n            foreach (var binding in bindings.Values)\n            {\n                foreach (var grainBinding in binding.Bindings)\n                {\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BindingTypeKey, out var type)\n                        || type != WellKnownGrainTypeProperties.StreamBindingTypeValue)\n                    {\n                        continue;\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.StreamBindingPatternKey, out var pattern))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Stream binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.StreamBindingPatternKey}\\\" value\");\n                    }\n\n                    IStreamNamespacePredicate predicate = null;\n                    foreach (var provider in _providers)\n                    {\n                        if (provider.TryGetPredicate(pattern, out predicate)) break;\n                    }\n\n                    if (predicate is null)\n                    {\n                        throw new KeyNotFoundException(\n                            $\"Could not find an {nameof(IStreamNamespacePredicate)} for the pattern \\\"{pattern}\\\".\"\n                            + $\" Ensure that a corresponding {nameof(IStreamNamespacePredicateProvider)} is registered\");\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.StreamIdMapperKey, out var mapperName))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Stream binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.StreamIdMapperKey}\\\" value\");\n                    }\n\n                    var streamIdMapper = _serviceProvider.GetKeyedService<IStreamIdMapper>(string.IsNullOrWhiteSpace(mapperName) ? DefaultStreamIdMapper.Name : mapperName);\n                    var subscriber = new StreamSubscriber(binding, streamIdMapper);\n                    newPredicates.Add(new StreamSubscriberPredicate(subscriber, predicate));\n                }\n            }\n\n            return new Cache(version, newPredicates);\n        }\n\n        /// <summary>\n        /// Retrieve a map of implicit subscriptionsIds to implicit subscribers, given a stream ID. This method throws an exception if there's no namespace associated with the stream ID.\n        /// </summary>\n        /// <param name=\"streamId\">A stream ID.</param>\n        /// <param name=\"grainFactory\">The grain factory used to get consumer references.</param>\n        /// <returns>A set of GrainId that are implicitly subscribed grains. They are expected to support the streaming consumer extension.</returns>\n        /// <exception cref=\"System.ArgumentException\">The stream ID doesn't have an associated namespace.</exception>\n        /// <exception cref=\"System.InvalidOperationException\">Internal invariant violation.</exception>\n        internal Dictionary<Guid, GrainId> GetImplicitSubscribers(QualifiedStreamId streamId, IInternalGrainFactory grainFactory) \n        {\n            var streamNamespace = streamId.GetNamespace();\n            if (!IsImplicitSubscribeEligibleNameSpace(streamNamespace))\n            {\n                throw new ArgumentException(\"The stream ID doesn't have an associated namespace.\", nameof(streamId));\n            }\n\n            var entries = GetOrAddImplicitSubscribers(streamNamespace);\n\n            var result = new Dictionary<Guid, GrainId>();\n            foreach (var entry in entries)\n            {\n                var grainId = entry.GetGrainId(streamId);\n                Guid subscriptionGuid = MakeSubscriptionGuid(entry.GrainType, streamId);\n                CollectionsMarshal.GetValueRefOrAddDefault(result, subscriptionGuid, out var duplicate) = grainId;\n                if (duplicate)\n                {\n                    throw new InvalidOperationException(\n                        $\"Internal invariant violation: generated duplicate subscriber reference: {grainId}, subscriptionId: {subscriptionGuid}\");\n                }\n            }\n            return result;\n        }\n\n        private HashSet<StreamSubscriber> GetOrAddImplicitSubscribers(string streamNamespace)\n        {\n            var cache = GetCache();\n            if (cache.Namespaces.TryGetValue(streamNamespace, out var result))\n            {\n                return result;\n            }\n\n            return cache.Namespaces.GetOrAdd(streamNamespace, FindImplicitSubscribers(streamNamespace, cache.Predicates));\n        }\n\n        /// <summary>\n        /// Determines whether the specified grain is an implicit subscriber of a given stream.\n        /// </summary>\n        /// <param name=\"grainId\">The grain identifier.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>true if the grain id describes an implicit subscriber of the stream described by the stream id.</returns>\n        internal bool IsImplicitSubscriber(GrainId grainId, QualifiedStreamId streamId)\n        {\n            var streamNamespace = streamId.GetNamespace();\n            if (!IsImplicitSubscribeEligibleNameSpace(streamNamespace))\n            {\n                return false;\n            }\n\n            foreach (var entry in GetOrAddImplicitSubscribers(streamNamespace))\n            {\n                if (entry.GrainType == grainId.Type)\n                    return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Try to get the implicit subscriptionId.\n        /// If an implicit subscription exists, return a subscription Id that is unique per grain type, grainId, namespace combination.\n        /// </summary>\n        /// <param name=\"grainId\"></param>\n        /// <param name=\"streamId\"></param>\n        /// <param name=\"subscriptionId\"></param>\n        /// <returns></returns>\n        internal bool TryGetImplicitSubscriptionGuid(GrainId grainId, QualifiedStreamId streamId, out Guid subscriptionId)\n        {\n            if (!IsImplicitSubscriber(grainId, streamId))\n            {\n                subscriptionId = default;\n                return false;\n            }\n\n            subscriptionId = MakeSubscriptionGuid(grainId.Type, streamId);\n            return true;\n        }\n\n        /// <summary>\n        /// Create a subscriptionId that is unique per grainId, grainType, namespace combination.\n        /// </summary>\n        private Guid MakeSubscriptionGuid(GrainType grainType, QualifiedStreamId streamId)\n        {\n            Span<byte> bytes = stackalloc byte[16];\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes, grainType.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[4..], streamId.StreamId.GetUniformHashCode());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[8..], streamId.StreamId.GetKeyIndex());\n            BinaryPrimitives.WriteUInt32LittleEndian(bytes[12..], StableHash.ComputeHash(streamId.ProviderName));\n            return SubscriptionMarker.MarkAsImplictSubscriptionId(new(bytes));\n        }\n\n        internal static bool IsImplicitSubscribeEligibleNameSpace(string streamNameSpace)\n        {\n            return !string.IsNullOrWhiteSpace(streamNameSpace);\n        }\n\n        /// <summary>\n        /// Finds all implicit subscribers for the given stream namespace.\n        /// </summary>\n        private static HashSet<StreamSubscriber> FindImplicitSubscribers(string streamNamespace, List<StreamSubscriberPredicate> predicates)\n        {\n            var result = new HashSet<StreamSubscriber>();\n            foreach (var predicate in predicates)\n            {\n                if (predicate.Predicate.IsMatch(streamNamespace))\n                {\n                    result.Add(predicate.Subscriber);\n                }\n            }\n\n            return result;\n        }\n\n        private class StreamSubscriberPredicate\n        {\n            public StreamSubscriberPredicate(StreamSubscriber subscriber, IStreamNamespacePredicate predicate)\n            {\n                this.Subscriber = subscriber;\n                this.Predicate = predicate;\n            }\n\n            public StreamSubscriber Subscriber { get; }\n            public IStreamNamespacePredicate Predicate { get; }\n        }\n\n        private sealed class StreamSubscriber : IEquatable<StreamSubscriber>\n        {\n            public StreamSubscriber(GrainBindings grainBindings, IStreamIdMapper streamIdMapper)\n            {\n                this.GrainBindings = grainBindings;\n                this.streamIdMapper = streamIdMapper;\n            }\n\n            public GrainType GrainType => this.GrainBindings.GrainType;\n\n            private GrainBindings GrainBindings { get; }\n\n            private IStreamIdMapper streamIdMapper { get; }\n\n            public override bool Equals(object obj) => Equals(obj as StreamSubscriber);\n\n            public bool Equals(StreamSubscriber other) => other != null && GrainType.Equals(other.GrainType);\n\n            public override int GetHashCode() => GrainType.GetHashCode();\n\n            internal GrainId GetGrainId(QualifiedStreamId streamId)\n            {\n                var grainKeyId = this.streamIdMapper.GetGrainKeyId(this.GrainBindings, streamId);\n                return GrainId.Create(this.GrainType, grainKeyId);\n            }\n        }\n\n        private class Cache\n        {\n            public Cache(MajorMinorVersion version, List<StreamSubscriberPredicate> predicates)\n            {\n                this.Version = version;\n                this.Predicates = predicates;\n                this.Namespaces = new ConcurrentDictionary<string, HashSet<StreamSubscriber>>();\n            }\n\n            public MajorMinorVersion Version { get; }\n            public ConcurrentDictionary<string, HashSet<StreamSubscriber>> Namespaces { get; }\n            public List<StreamSubscriberPredicate> Predicates { get; }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/PubSubPublisherState.cs",
    "content": "using System;\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [JsonObject(MemberSerialization.OptIn)]\n    [GenerateSerializer]\n    internal sealed class PubSubPublisherState : IEquatable<PubSubPublisherState>\n    {\n        // IMPORTANT!!!!!\n        // These fields have to be public non-readonly for JsonSerialization to work!\n        // Implement ISerializable if changing any of them to readonly\n        [JsonProperty]\n        [Id(0)]\n        public QualifiedStreamId Stream;\n\n        [JsonProperty]\n        [Id(1)]\n        public GrainId Producer; // the field needs to be of a public type, otherwise we will not generate an Orleans serializer for that class.\n\n        // This constructor has to be public for JsonSerialization to work!\n        // Implement ISerializable if changing it to non-public\n        public PubSubPublisherState(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            Stream = streamId;\n            Producer = streamProducer;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            // Note: Can't use the 'as' operator on PubSubPublisherState because it is a struct.\n            return obj is PubSubPublisherState && Equals((PubSubPublisherState)obj);\n        }\n        public bool Equals(PubSubPublisherState other)\n        {\n            // Note: PubSubPublisherState is a struct, so 'other' can never be null.\n            return Equals(other.Stream, other.Producer);\n        }\n        public bool Equals(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            if (Stream == default) return false;\n            return Stream.Equals(streamId) && Producer.Equals(streamProducer);\n        }\n\n        public static bool operator ==(PubSubPublisherState left, PubSubPublisherState right)\n        {\n            return left.Equals(right);\n        }\n        public static bool operator !=(PubSubPublisherState left, PubSubPublisherState right)\n        {\n            return !left.Equals(right);\n        }\n        public override int GetHashCode() => HashCode.Combine(Stream, Producer);\n\n        public override string ToString()\n        {\n            return string.Format(\"PubSubPublisherState:StreamId={0},Producer={1}.\", Stream, Producer);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/PubSubRendezvousGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.ExceptionServices;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Core;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage;\nusing Orleans.Streams.Core;\n\n#nullable enable\nnamespace Orleans.Streams\n{\n    internal sealed partial class PubSubGrainStateStorageFactory\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly ILogger<PubSubGrainStateStorageFactory> _logger;\n\n        public PubSubGrainStateStorageFactory(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)\n        {\n            _serviceProvider = serviceProvider;\n            _logger = loggerFactory.CreateLogger<PubSubGrainStateStorageFactory>();\n        }\n\n        public StateStorageBridge<PubSubGrainState> GetStorage(PubSubRendezvousGrain grain)\n        {\n            var span = grain.GrainId.Key.AsSpan();\n            var i = span.IndexOf((byte)'/');\n            if (i < 0)\n            {\n                throw new ArgumentException($\"Unable to parse \\\"{grain.GrainId.Key}\\\" as a stream id\");\n            }\n\n            var providerName = Encoding.UTF8.GetString(span[..i]);\n\n            LogDebugTryingToFindStorageProvider(providerName);\n\n            var storage = _serviceProvider.GetKeyedService<IGrainStorage>(providerName);\n            if (storage == null)\n            {\n                LogDebugFallbackToStorageProvider(ProviderConstants.DEFAULT_PUBSUB_PROVIDER_NAME);\n\n                storage = _serviceProvider.GetRequiredKeyedService<IGrainStorage>(ProviderConstants.DEFAULT_PUBSUB_PROVIDER_NAME);\n            }\n\n            return new(nameof(PubSubRendezvousGrain), grain.GrainContext, storage);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Trying to find storage provider {ProviderName}\"\n        )]\n        private partial void LogDebugTryingToFindStorageProvider(string providerName);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Fallback to storage provider {ProviderName}\"\n        )]\n        private partial void LogDebugFallbackToStorageProvider(string providerName);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    internal sealed class PubSubGrainState\n    {\n        [Id(0)]\n        public HashSet<PubSubPublisherState> Producers { get; set; } = new HashSet<PubSubPublisherState>();\n        [Id(1)]\n        public HashSet<PubSubSubscriptionState> Consumers { get; set; } = new HashSet<PubSubSubscriptionState>();\n    }\n\n    [GrainType(\"pubsubrendezvous\")]\n    internal sealed partial class PubSubRendezvousGrain : Grain, IPubSubRendezvousGrain, IGrainMigrationParticipant\n    {\n        private readonly ILogger _logger;\n        private const bool DEBUG_PUB_SUB = false;\n\n        private readonly PubSubGrainStateStorageFactory _storageFactory;\n        private readonly StateStorageBridge<PubSubGrainState> _storage;\n\n        private PubSubGrainState State => _storage.State;\n\n        public PubSubRendezvousGrain(PubSubGrainStateStorageFactory storageFactory, ILogger<PubSubRendezvousGrain> logger)\n        {\n            _storageFactory = storageFactory;\n            _logger = logger;\n            _storage = _storageFactory.GetStorage(this);\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await ReadStateAsync();\n            LogPubSubCounts(\"OnActivateAsync\");\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            LogPubSubCounts(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            StreamInstruments.PubSubProducersAdded.Add(1);\n\n            try\n            {\n                var publisherState = new PubSubPublisherState(streamId, streamProducer);\n                State.Producers.Add(publisherState);\n                LogPubSubCounts(\"RegisterProducer {0}\", streamProducer);\n                await WriteStateAsync();\n                StreamInstruments.PubSubProducersTotal.Add(1);\n            }\n            catch (Exception exc)\n            {\n                LogErrorRegisterProducer(streamId, streamProducer, exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n            return State.Consumers.Where(c => !c.IsFaulted).ToSet();\n        }\n\n        public async Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            StreamInstruments.PubSubProducersRemoved.Add(1);\n            try\n            {\n                int numRemoved = State.Producers.RemoveWhere(s => s.Equals(streamId, streamProducer));\n                LogPubSubCounts(\"UnregisterProducer {0} NumRemoved={1}\", streamProducer, numRemoved);\n\n                if (numRemoved > 0)\n                {\n                    Task updateStorageTask = State.Producers.Count == 0 && State.Consumers.Count == 0\n                        ? ClearStateAsync() //State contains no producers or consumers, remove it from storage\n                        : WriteStateAsync();\n                    await updateStorageTask;\n                }\n                StreamInstruments.PubSubProducersTotal.Add(-numRemoved);\n            }\n            catch (Exception exc)\n            {\n                LogErrorUnregisterProducer(streamId, streamProducer, exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n            if (State.Producers.Count == 0 && State.Consumers.Count == 0)\n            {\n                DeactivateOnIdle(); // No producers or consumers left now, so flag ourselves to expedite Deactivation\n            }\n        }\n\n        public async Task RegisterConsumer(\n            GuidId subscriptionId,\n            QualifiedStreamId streamId,\n            GrainId streamConsumer,\n            string filterData)\n        {\n            StreamInstruments.PubSubConsumersAdded.Add(1);\n            var pubSubState = State.Consumers.FirstOrDefault(s => s.Equals(subscriptionId));\n            if (pubSubState != null && pubSubState.IsFaulted)\n                throw new FaultedSubscriptionException(subscriptionId, streamId);\n            try\n            {\n                if (pubSubState == null)\n                {\n                    pubSubState = new PubSubSubscriptionState(subscriptionId, streamId, streamConsumer);\n                    State.Consumers.Add(pubSubState);\n                }\n\n                if (!string.IsNullOrWhiteSpace(filterData))\n                    pubSubState.AddFilter(filterData);\n\n                LogPubSubCounts(\"RegisterConsumer {0}\", streamConsumer);\n                await WriteStateAsync();\n                StreamInstruments.PubSubConsumersTotal.Add(1);\n            }\n            catch (Exception exc)\n            {\n                LogErrorRegisterConsumer(streamId, subscriptionId, streamConsumer, exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n\n            int numProducers = State.Producers.Count;\n            if (numProducers <= 0)\n                return;\n\n            LogDebugNotifyProducersOfNewConsumer(numProducers, streamConsumer, new(State.Producers));\n\n            // Notify producers about a new streamConsumer.\n            var tasks = new List<Task>();\n            var producers = State.Producers.ToList();\n            int initialProducerCount = producers.Count;\n            try\n            {\n                foreach (PubSubPublisherState producerState in producers)\n                {\n                    tasks.Add(ExecuteProducerTask(producerState, p => p.AddSubscriber(subscriptionId, streamId, streamConsumer, filterData)));\n                }\n\n                Exception? exception = null;\n                try\n                {\n                    await Task.WhenAll(tasks);\n                }\n                catch (Exception exc)\n                {\n                    exception = exc;\n                }\n\n                // if the number of producers has been changed, resave state.\n                if (State.Producers.Count != initialProducerCount)\n                {\n                    await WriteStateAsync();\n                    StreamInstruments.PubSubConsumersTotal.Add(-(initialProducerCount - State.Producers.Count));\n                }\n\n                if (exception != null)\n                {\n                    ExceptionDispatchInfo.Capture(exception).Throw();\n                }\n            }\n            catch (Exception exc)\n            {\n                LogErrorRegisterConsumerFailed(\n                    streamId,\n                    subscriptionId,\n                    streamConsumer,\n                    exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n        }\n\n        private void RemoveProducer(PubSubPublisherState producer)\n        {\n            LogWarningProducerIsDead(producer, producer.Stream);\n\n            State.Producers.Remove(producer);\n        }\n\n        public async Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            StreamInstruments.PubSubConsumersRemoved.Add(1);\n\n            try\n            {\n                int numRemoved = State.Consumers.RemoveWhere(c => c.Equals(subscriptionId));\n\n                LogPubSubCounts(\"UnregisterSubscription {0} NumRemoved={1}\", subscriptionId, numRemoved);\n\n                if (await TryClearState())\n                {\n                    // If state was cleared expedite Deactivation\n                    DeactivateOnIdle();\n                }\n                else\n                {\n                    if (numRemoved != 0)\n                    {\n                        await WriteStateAsync();\n                    }\n                    await NotifyProducersOfRemovedSubscription(subscriptionId, streamId);\n                }\n                StreamInstruments.PubSubConsumersTotal.Add(-numRemoved);\n            }\n            catch (Exception exc)\n            {\n                LogErrorUnregisterConsumer(streamId, subscriptionId, exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n        }\n\n        public Task<int> ProducerCount(QualifiedStreamId streamId)\n        {\n            return Task.FromResult(State.Producers.Count);\n        }\n\n        public Task<int> ConsumerCount(QualifiedStreamId streamId)\n        {\n            return Task.FromResult(GetConsumersForStream(streamId).Length);\n        }\n\n        public Task<PubSubSubscriptionState[]> DiagGetConsumers(QualifiedStreamId streamId)\n        {\n            return Task.FromResult(GetConsumersForStream(streamId));\n        }\n\n        private PubSubSubscriptionState[] GetConsumersForStream(QualifiedStreamId streamId)\n        {\n            return State.Consumers.Where(c => !c.IsFaulted && c.Stream.Equals(streamId)).ToArray();\n        }\n\n        private void LogPubSubCounts(string fmt, params object[] args)\n        {\n            if (_logger.IsEnabled(LogLevel.Debug) || DEBUG_PUB_SUB)\n            {\n                int numProducers = 0;\n                int numConsumers = 0;\n                if (State?.Producers != null)\n                    numProducers = State.Producers.Count;\n                if (State?.Consumers != null)\n                    numConsumers = State.Consumers.Count;\n\n                string when = args != null && args.Length != 0 ? string.Format(fmt, args) : fmt;\n                _logger.LogDebug(\"{When}. Now have total of {ProducerCount} producers and {ConsumerCount} consumers. All Consumers = {Consumers}, All Producers = {Producers}\",\n                    when, numProducers, numConsumers, Utils.EnumerableToString(State?.Consumers), Utils.EnumerableToString(State?.Producers));\n            }\n        }\n\n        // Check that what we have cached locally matches what is in the persistent table.\n        public async Task Validate()\n        {\n            var captureProducers = State.Producers;\n            var captureConsumers = State.Consumers;\n\n            await ReadStateAsync();\n\n            if (captureProducers.Count != State.Producers.Count)\n            {\n                throw new OrleansException(\n                    $\"State mismatch between PubSubRendezvousGrain and its persistent state. captureProducers.Count={captureProducers.Count}, State.Producers.Count={State.Producers.Count}\");\n            }\n\n            if (captureProducers.Any(producer => !State.Producers.Contains(producer)))\n            {\n                throw new OrleansException(\n                    $\"State mismatch between PubSubRendezvousGrain and its persistent state. captureProducers={Utils.EnumerableToString(captureProducers)}, State.Producers={Utils.EnumerableToString(State.Producers)}\");\n            }\n\n            if (captureConsumers.Count != State.Consumers.Count)\n            {\n                LogPubSubCounts(\"Validate: Consumer count mismatch\");\n                throw new OrleansException(\n                    $\"State mismatch between PubSubRendezvousGrain and its persistent state. captureConsumers.Count={captureConsumers.Count}, State.Consumers.Count={State.Consumers.Count}\");\n            }\n\n            if (captureConsumers.Any(consumer => !State.Consumers.Contains(consumer)))\n            {\n                throw new OrleansException(\n                    $\"State mismatch between PubSubRendezvousGrain and its persistent state. captureConsumers={Utils.EnumerableToString(captureConsumers)}, State.Consumers={Utils.EnumerableToString(State.Consumers)}\");\n            }\n        }\n\n        public Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer)\n        {\n            if (streamConsumer != default)\n            {\n                List<StreamSubscription> subscriptions =\n                    State.Consumers.Where(c => !c.IsFaulted && c.Consumer.Equals(streamConsumer))\n                        .Select(\n                            c =>\n                                new StreamSubscription(c.SubscriptionId.Guid, streamId.ProviderName, streamId,\n                                    streamConsumer)).ToList();\n                return Task.FromResult(subscriptions);\n            }\n            else\n            {\n                List<StreamSubscription> subscriptions =\n                    State.Consumers.Where(c => !c.IsFaulted)\n                        .Select(\n                            c =>\n                                new StreamSubscription(c.SubscriptionId.Guid, streamId.ProviderName, streamId,\n                                    c.Consumer)).ToList();\n                return Task.FromResult(subscriptions);\n            }\n\n        }\n\n        public async Task FaultSubscription(GuidId subscriptionId)\n        {\n            var pubSubState = State.Consumers.FirstOrDefault(s => s.Equals(subscriptionId));\n            if (pubSubState == null)\n            {\n                return;\n            }\n            try\n            {\n                pubSubState.Fault();\n                LogDebugSettingSubscriptionToFaulted(subscriptionId);\n\n                await WriteStateAsync();\n                await NotifyProducersOfRemovedSubscription(pubSubState.SubscriptionId, pubSubState.Stream);\n            }\n            catch (Exception exc)\n            {\n                LogErrorSetSubscriptionToFaulted(subscriptionId, exc);\n\n                // Corrupted state, deactivate grain.\n                DeactivateOnIdle();\n                throw;\n            }\n        }\n\n        private async Task NotifyProducersOfRemovedSubscription(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            int numProducersBeforeNotify = State.Producers.Count;\n            if (numProducersBeforeNotify > 0)\n            {\n                LogDebugNotifyProducersOfRemovedConsumer(numProducersBeforeNotify);\n\n                // Notify producers about unregistered consumer.\n                List<Task> tasks = State.Producers\n                    .Select(producerState => ExecuteProducerTask(producerState, p => p.RemoveSubscriber(subscriptionId, streamId)))\n                    .ToList();\n                await Task.WhenAll(tasks);\n                //if producers got removed\n                if (State.Producers.Count < numProducersBeforeNotify)\n                    await WriteStateAsync();\n            }\n        }\n\n        /// <summary>\n        /// Try clear state will only clear the state if there are no producers or consumers.\n        /// </summary>\n        /// <returns></returns>\n        private async Task<bool> TryClearState()\n        {\n            if (State.Producers.Count == 0 && State.Consumers.Count == 0) // + we already know that numProducers == 0 from previous if-clause\n            {\n                await ClearStateAsync(); //State contains no producers or consumers, remove it from storage\n                return true;\n            }\n            return false;\n        }\n\n        private async Task ExecuteProducerTask(PubSubPublisherState producer, Func<IStreamProducerExtension, Task> producerTask)\n        {\n            try\n            {\n                var extension = GrainFactory.GetGrain<IStreamProducerExtension>(producer.Producer);\n                await producerTask(extension);\n            }\n            catch (GrainExtensionNotInstalledException)\n            {\n                RemoveProducer(producer);\n            }\n            catch (ClientNotAvailableException)\n            {\n                RemoveProducer(producer);\n            }\n            catch (OrleansMessageRejectionException)\n            {\n                // if producer is a system target on and unavailable silo, remove it.\n                if (producer.Producer.IsSystemTarget())\n                {\n                    RemoveProducer(producer);\n                }\n                else // otherwise, throw\n                {\n                    throw;\n                }\n            }\n        }\n\n        private Task ReadStateAsync() => _storage.ReadStateAsync();\n        private Task WriteStateAsync() => _storage.WriteStateAsync();\n        private Task ClearStateAsync() => _storage.ClearStateAsync();\n        void IGrainMigrationParticipant.OnDehydrate(IDehydrationContext dehydrationContext) => _storage.OnDehydrate(dehydrationContext);\n        void IGrainMigrationParticipant.OnRehydrate(IRehydrationContext rehydrationContext) => _storage.OnRehydrate(rehydrationContext);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_RegisterProducerFailed,\n            Message = \"Failed to register a stream producer. Stream: {StreamId}, Producer: {StreamProducer}\"\n        )]\n        private partial void LogErrorRegisterProducer(QualifiedStreamId streamId, GrainId streamProducer, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_UnregisterProducerFailed,\n            Message = \"Failed to unregister a stream producer. Stream: {StreamId}, Producer: {StreamProducer}\"\n        )]\n        private partial void LogErrorUnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_RegisterConsumerFailed,\n            Message = \"Failed to register a stream consumer. Stream: {StreamId}, SubscriptionId {SubscriptionId}, Consumer: {StreamConsumer}\"\n        )]\n        private partial void LogErrorRegisterConsumer(QualifiedStreamId streamId, GuidId subscriptionId, GrainId streamConsumer, Exception exception);\n\n        private readonly struct ProducersLogRecord(HashSet<PubSubPublisherState> producers)\n        {\n            public override string ToString() => Utils.EnumerableToString(producers);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Notifying {ProducerCount} existing producer(s) about new consumer {Consumer}. Producers={Producers}\"\n        )]\n        private partial void LogDebugNotifyProducersOfNewConsumer(int producerCount, GrainId consumer, ProducersLogRecord producers);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_RegisterConsumerFailed,\n            Message = \"Failed to update producers while registering a stream consumer. Stream: {StreamId}, SubscriptionId {SubscriptionId}, Consumer: {StreamConsumer}\"\n        )]\n        private partial void LogErrorRegisterConsumerFailed(QualifiedStreamId streamId, GuidId subscriptionId, GrainId streamConsumer, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = (int)ErrorCode.Stream_ProducerIsDead,\n            Message = \"Producer {Producer} on stream {StreamId} is no longer active - permanently removing producer.\"\n        )]\n        private partial void LogWarningProducerIsDead(PubSubPublisherState producer, QualifiedStreamId streamId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_UnregisterConsumerFailed,\n            Message = \"Failed to unregister a stream consumer. Stream: {StreamId}, SubscriptionId {SubscriptionId}\"\n        )]\n        private partial void LogErrorUnregisterConsumer(QualifiedStreamId streamId, GuidId subscriptionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Setting subscription {SubscriptionId} to a faulted state.\"\n        )]\n        private partial void LogDebugSettingSubscriptionToFaulted(GuidId subscriptionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = (int)ErrorCode.Stream_SetSubscriptionToFaultedFailed,\n            Message = \"Failed to set subscription state to faulted. SubscriptionId {SubscriptionId}\"\n        )]\n        private partial void LogErrorSetSubscriptionToFaulted(GuidId subscriptionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Notifying {ProducerCountBeforeNotify} existing producers about unregistered consumer.\"\n        )]\n        private partial void LogDebugNotifyProducersOfRemovedConsumer(int producerCountBeforeNotify);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/PubSubSubscriptionState.cs",
    "content": "using System;\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    [Serializable]\n    [JsonObject(MemberSerialization.OptIn)]\n    [GenerateSerializer]\n    public sealed class PubSubSubscriptionState : IEquatable<PubSubSubscriptionState>\n    {\n        public enum SubscriptionStates\n        {\n            Active,\n            Faulted,\n        }\n\n        // IMPORTANT!!!!!\n        // These fields have to be public non-readonly for JSonSerialization to work!\n        // Implement ISerializable if changing any of them to readonly\n        [JsonProperty]\n        [Id(0)]\n        public GuidId SubscriptionId;\n\n        [JsonProperty]\n        [Id(1)]\n        public QualifiedStreamId Stream;\n\n        [JsonProperty]\n        [Id(2)]\n        public GrainId Consumer; // the field needs to be of a public type, otherwise we will not generate an Orleans serializer for that class.\n\n        [JsonProperty]\n        [Id(3)]\n        public string FilterData; // Serialized func info\n\n        [JsonProperty]\n        [Id(4)]\n        public SubscriptionStates state;\n\n        [JsonIgnore]\n        public bool IsFaulted { get { return state == SubscriptionStates.Faulted; } }\n\n        // This constructor has to be public for JSonSerialization to work!\n        // Implement ISerializable if changing it to non-public\n        public PubSubSubscriptionState(\n            GuidId subscriptionId,\n            QualifiedStreamId streamId,\n            GrainId streamConsumer)\n        {\n            SubscriptionId = subscriptionId;\n            Stream = streamId;\n            Consumer = streamConsumer;\n            state = SubscriptionStates.Active;\n        }\n\n        public void AddFilter(string filterData)\n        {\n            this.FilterData = filterData;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            // Note: Can't use the 'as' operator on PubSubSubscriptionState because it is a struct.\n            return obj is PubSubSubscriptionState && Equals((PubSubSubscriptionState) obj);\n        }\n\n        public bool Equals(PubSubSubscriptionState other)\n        {\n            if ((object)other == null)\n                return false;\n            // Note: PubSubSubscriptionState is a struct, so 'other' can never be null.\n            return Equals(other.SubscriptionId);\n        }\n\n        public bool Equals(GuidId subscriptionId)\n        {\n            if (ReferenceEquals(null, subscriptionId)) return false;\n            return SubscriptionId.Equals(subscriptionId);\n        }\n\n        public override int GetHashCode()\n        {\n            return SubscriptionId.GetHashCode();\n        }\n\n        public static bool operator ==(PubSubSubscriptionState left, PubSubSubscriptionState right)\n        {\n            if ((object)left == null && (object)right == null)\n                return true;\n            if ((object)left != null)\n            {\n                return left.Equals(right);\n            }\n            return false;\n        }\n\n        public static bool operator !=(PubSubSubscriptionState left, PubSubSubscriptionState right)\n        {\n            return !(left == right);\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"PubSubSubscriptionState:SubscriptionId={0},StreamId={1},Consumer={2}.\",\n                SubscriptionId, Stream, Consumer);\n        }\n\n        public void Fault()\n        {\n            state = SubscriptionStates.Faulted;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/StreamPubSubImpl.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    internal class StreamPubSubImpl : IStreamPubSub\n    {\n        private readonly IStreamPubSub explicitPubSub;\n        private readonly ImplicitStreamPubSub implicitPubSub;\n\n        public StreamPubSubImpl(IStreamPubSub explicitPubSub, ImplicitStreamPubSub implicitPubSub)\n        {\n            if (explicitPubSub == null)\n            {\n                throw new ArgumentNullException(nameof(explicitPubSub));\n            }\n\n            if (implicitPubSub == null)\n            {\n                throw new ArgumentNullException(nameof(implicitPubSub));\n            }\n\n            this.explicitPubSub = explicitPubSub;\n            this.implicitPubSub = implicitPubSub;\n        }\n\n        public async Task<ISet<PubSubSubscriptionState>> RegisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            ISet<PubSubSubscriptionState> explicitRes = await explicitPubSub.RegisterProducer(streamId, streamProducer);\n            ISet<PubSubSubscriptionState> implicitRes = await implicitPubSub.RegisterProducer(streamId, streamProducer);\n            explicitRes.UnionWith(implicitRes);\n            return explicitRes;\n        }\n\n        public Task UnregisterProducer(QualifiedStreamId streamId, GrainId streamProducer)\n        {\n            return explicitPubSub.UnregisterProducer(streamId, streamProducer);\n        }\n\n        public Task RegisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData)\n        {\n            return implicitPubSub.IsImplicitSubscriber(streamConsumer, streamId)\n                ? implicitPubSub.RegisterConsumer(subscriptionId, streamId, streamConsumer, filterData)\n                : explicitPubSub.RegisterConsumer(subscriptionId, streamId, streamConsumer, filterData);\n        }\n\n        public Task UnregisterConsumer(GuidId subscriptionId, QualifiedStreamId streamId)\n        {\n            return implicitPubSub.IsImplicitSubscriber(subscriptionId, streamId)\n                ? implicitPubSub.UnregisterConsumer(subscriptionId, streamId)\n                : explicitPubSub.UnregisterConsumer(subscriptionId, streamId);\n        }\n\n        public Task<int> ProducerCount(QualifiedStreamId streamId)\n        {\n            return explicitPubSub.ProducerCount(streamId); \n        }\n\n        public Task<int> ConsumerCount(QualifiedStreamId streamId)\n        {\n            return explicitPubSub.ConsumerCount(streamId); \n        }\n\n        public async Task<List<StreamSubscription>> GetAllSubscriptions(QualifiedStreamId streamId, GrainId streamConsumer)\n        {\n            if (streamConsumer != default)\n            {\n                return implicitPubSub.IsImplicitSubscriber(streamConsumer, streamId)\n                    ? await implicitPubSub.GetAllSubscriptions(streamId, streamConsumer)\n                    : await explicitPubSub.GetAllSubscriptions(streamId, streamConsumer);\n            }\n            else\n            {\n                var implicitSubs = await implicitPubSub.GetAllSubscriptions(streamId);\n                var explicitSubs = await explicitPubSub.GetAllSubscriptions(streamId);\n                return implicitSubs.Concat(explicitSubs).ToList();\n            }\n        }\n\n        public GuidId CreateSubscriptionId(QualifiedStreamId streamId, GrainId streamConsumer)\n        {\n            return implicitPubSub.IsImplicitSubscriber(streamConsumer, streamId)\n               ? implicitPubSub.CreateSubscriptionId(streamId, streamConsumer)\n               : explicitPubSub.CreateSubscriptionId(streamId, streamConsumer);\n        }\n\n        public Task<bool> FaultSubscription(QualifiedStreamId streamId, GuidId subscriptionId)\n        {\n            return implicitPubSub.IsImplicitSubscriber(subscriptionId, streamId)\n                ? implicitPubSub.FaultSubscription(streamId, subscriptionId)\n                : explicitPubSub.FaultSubscription(streamId, subscriptionId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/StreamSubscriptionManagerExtensions.cs",
    "content": "using Orleans.Streams.Core;\nusing System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams.PubSub\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IStreamSubscriptionManager\"/>.\n    /// </summary>\n    public static class StreamSubscriptionManagerExtensions\n    {\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">The grain interface type.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"grainId\">The grain to subscribe.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            GrainId grainId)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            var grainRef = grainFactory.GetGrain(grainId) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">An interface which the grain is the primary implementation of.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"primaryKey\">The grain's primary key.</param>\n        /// <param name=\"grainClassNamePrefix\">The grain class name prefix.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            Guid primaryKey,\n            string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            var grainRef = grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">An interface which the grain is the primary implementation of.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"primaryKey\">The grain's primary key.</param>\n        /// <param name=\"grainClassNamePrefix\">The grain class name prefix.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            long primaryKey,\n            string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerKey\n        {\n            var grainRef = grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">An interface which the grain is the primary implementation of.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"primaryKey\">The grain's primary key.</param>\n        /// <param name=\"grainClassNamePrefix\">The grain class name prefix.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            string primaryKey,\n            string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey\n        {\n            var grainRef = grainFactory.GetGrain<TGrainInterface>(primaryKey, grainClassNamePrefix) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">An interface which the grain is the primary implementation of.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"primaryKey\">The grain's primary key.</param>\n        /// <param name=\"keyExtension\">The grain's key extension.</param>\n        /// <param name=\"grainClassNamePrefix\">The grain class name prefix.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            Guid primaryKey,\n            string keyExtension,\n            string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey\n        {\n            var grainRef = grainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Subscribes the specified grain to the specified stream.\n        /// </summary>\n        /// <typeparam name=\"TGrainInterface\">An interface which the grain is the primary implementation of.</typeparam>\n        /// <param name=\"manager\">The manager.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        /// <param name=\"primaryKey\">The grain's primary key.</param>\n        /// <param name=\"keyExtension\">The grain's key extension.</param>\n        /// <param name=\"grainClassNamePrefix\">The grain class name prefix.</param>\n        /// <returns>The newly added subscription.</returns>\n        public static Task<StreamSubscription> AddSubscription<TGrainInterface>(\n            this IStreamSubscriptionManager manager,\n            IGrainFactory grainFactory,\n            StreamId streamId,\n            string streamProviderName,\n            long primaryKey,\n            string keyExtension,\n            string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey\n        {\n            var grainRef = grainFactory.GetGrain<TGrainInterface>(primaryKey, keyExtension, grainClassNamePrefix) as GrainReference;\n            return manager.AddSubscription(streamProviderName, streamId, grainRef);\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"IStreamSubscriptionManager\"/> for the provided stream provider.\n        /// </summary>\n        /// <param name=\"streamProvider\">The stream provider.</param>\n        /// <param name=\"manager\">The manager.</param>\n        /// <returns><see langword=\"true\" /> if the stream subscription manager could be retrieved, <see langword=\"false\" /> otherwise.</returns>\n        public static bool TryGetStreamSubscriptionManager(this IStreamProvider streamProvider, out IStreamSubscriptionManager manager)\n        {\n            manager = null;\n            if (streamProvider is IStreamSubscriptionManagerRetriever)\n            {\n                var streamSubManagerRetriever = streamProvider as IStreamSubscriptionManagerRetriever;\n                manager = streamSubManagerRetriever.GetStreamSubscriptionManager();\n                //implicit only stream provider don't have a subscription manager configured \n                //so manager can be null;\n                return manager != null;\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/PubSub/SubscriptionMarker.cs",
    "content": "using System;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Mark a subscriptionId as either an implicit subscription Id, or an explicit subscription Id.\n    /// high bit of last byte in guild is the subscription type flag.\n    /// 1: implicit subscription\n    /// 0: explicit subscription\n    /// </summary>\n    internal static class SubscriptionMarker\n    {\n        internal static Guid MarkAsExplicitSubscriptionId(Guid subscriptionGuid)\n        {\n            return MarkSubscriptionGuid(subscriptionGuid, false);\n        }\n\n        internal static Guid MarkAsImplictSubscriptionId(Guid subscriptionGuid)\n        {\n            return MarkSubscriptionGuid(subscriptionGuid, true);\n        }\n\n        internal static bool IsImplicitSubscription(Guid subscriptionGuid)\n        {\n            Span<byte> guidBytes = stackalloc byte[16];\n            subscriptionGuid.TryWriteBytes(guidBytes);\n            // return true if high bit of last byte is set\n            return (guidBytes[15] & 0x80) != 0;\n        }\n\n        private static Guid MarkSubscriptionGuid(Guid subscriptionGuid, bool isImplicitSubscription)\n        {\n            Span<byte> guidBytes = stackalloc byte[16];\n            subscriptionGuid.TryWriteBytes(guidBytes);\n            if (isImplicitSubscription)\n            {\n                // set high bit of last byte\n                guidBytes[15] |= 0x80;\n            }\n            else\n            {\n                // clear high bit of last byte\n                guidBytes[15] &= 0x7f;\n            }\n\n            return new Guid(guidBytes);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/AggregatedQueueFlowController.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// A <see cref=\"IQueueFlowController\"/> which aggregates multiple other <see cref=\"IQueueFlowController\"/> values.\n    /// </summary>\n    public class AggregatedQueueFlowController : List<IQueueFlowController>, IQueueFlowController\n    {\n        private readonly int defaultMaxAddCount;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AggregatedQueueFlowController\"/> class.\n        /// </summary>\n        /// <param name=\"defaultMaxAddCount\">The default maximum add count, see <see cref=\"IQueueFlowController.GetMaxAddCount\"/>.</param>\n        public AggregatedQueueFlowController(int defaultMaxAddCount)\n        {\n            this.defaultMaxAddCount = defaultMaxAddCount;\n        }\n\n        /// <inheritdoc/>\n        public int GetMaxAddCount()\n        {\n            return this.Aggregate(defaultMaxAddCount, (count, fc) => Math.Min(count, fc.GetMaxAddCount()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/BatchContainerBatch.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// A batch of batch containers, that if configured (see StreamPullingAgentOptions), will be the data pulled by the\n    /// PersistenStreamPullingAgent from it's underlying cache\n    /// </summary>\n    [GenerateSerializer]\n    public sealed class BatchContainerBatch : IBatchContainerBatch\n    {\n        /// <summary>\n        /// Gets the stream identifier for the stream this batch is part of.\n        /// Derived from the first batch container in the batch.\n        /// </summary>\n        [Id(0)]\n        public StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets the stream Sequence Token for the start of this batch.\n        /// Derived from the first batch container in the batch.\n        /// </summary>\n        [Id(1)]\n        public StreamSequenceToken SequenceToken { get; }\n\n        /// <summary>\n        /// Gets the batch containers comprising this batch\n        /// </summary>\n        [Id(2)]\n        public List<IBatchContainer> BatchContainers { get; }\n                \n        public BatchContainerBatch(List<IBatchContainer> batchContainers)\n        {\n            if ((batchContainers == null) || !batchContainers.Any())\n            {\n                throw new ArgumentNullException(nameof(batchContainers));\n            }\n\n            this.BatchContainers = batchContainers;\n\n            var containerDelegate = this.BatchContainers[0];\n            this.SequenceToken = containerDelegate.SequenceToken;\n            this.StreamId = containerDelegate.StreamId;\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n        {\n            return this.BatchContainers.SelectMany(batchContainer => batchContainer.GetEvents<T>());\n        }\n\n        /// <inheritdoc/>\n        public bool ImportRequestContext()\n        {\n            return this.BatchContainers[0].ImportRequestContext();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/DataNotAvailableException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Exception indicates that the requested data is not available.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class DataNotAvailableException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataNotAvailableException\"/> class.\n        /// </summary>\n        public DataNotAvailableException() : this(\"Data not found\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public DataNotAvailableException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"inner\">The inner.</param>\n        public DataNotAvailableException(string message, Exception inner) : base(message, inner) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataNotAvailableException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        protected DataNotAvailableException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Indicates that the queue message cache is full.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class CacheFullException : OrleansException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CacheFullException\"/> class.\n        /// </summary>\n        public CacheFullException() : this(\"Queue message cache is full\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CacheFullException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public CacheFullException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CacheFullException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"inner\">The inner.</param>\n        public CacheFullException(string message, Exception inner) : base(message, inner) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"CacheFullException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private CacheFullException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/HashRing.cs",
    "content": "using System;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams;\n\ninternal readonly struct HashRing\n{\n    private readonly QueueId[] _ring;\n\n    public HashRing(QueueId[] ring)\n    {\n        Array.Sort(ring, (x, y) => x.GetUniformHashCode().CompareTo(y.GetUniformHashCode()));\n        _ring = ring;\n    }\n\n    public QueueId[] GetAllRingMembers() => _ring;\n\n    public QueueId CalculateResponsible(uint uniformHashCode)\n    {\n        // use clockwise ... current code in membershipOracle.CalculateTargetSilo() does counter-clockwise ...\n        var index = _ring.AsSpan().BinarySearch(new Searcher(uniformHashCode));\n        if (index < 0)\n        {\n            index = ~index;\n            // if not found in traversal, then first element should be returned (we are on a ring)\n            if (index == _ring.Length) index = 0;\n        }\n        return _ring[index];\n    }\n\n    private readonly struct Searcher : IComparable<QueueId>\n    {\n        private readonly uint _value;\n        public Searcher(uint value) => _value = value;\n        public int CompareTo(QueueId other) => _value.CompareTo(other.GetUniformHashCode());\n    }\n\n    public override string ToString()\n        => $\"All QueueIds:{Environment.NewLine}{(Utils.EnumerableToString(_ring, elem => $\"{elem}/x{elem.GetUniformHashCode():X8}\", Environment.NewLine, false))}\";\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/HashRingBasedStreamQueueMapper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// A <see cref=\"IConsistentRingStreamQueueMapper\"/> and hence <see cref=\"IStreamQueueMapper\"/> which balances queues by mapping them onto a hash ring consisting of silos.\n    /// </summary>\n    public class HashRingBasedStreamQueueMapper : IConsistentRingStreamQueueMapper\n    {\n        private readonly HashRing hashRing;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"HashRingBasedStreamQueueMapper\"/> class.\n        /// </summary>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"queueNamePrefix\">The queue name prefix.</param>\n        public HashRingBasedStreamQueueMapper(HashRingStreamQueueMapperOptions options, string queueNamePrefix) : this(options.TotalQueueCount, queueNamePrefix) { }\n\n        internal HashRingBasedStreamQueueMapper(int numQueues, string queueNamePrefix)\n        {\n            if (numQueues < 1) throw new ArgumentException(\"TotalQueueCount must be at least 1\");\n            var queueIds = new QueueId[numQueues];\n            if (numQueues == 1)\n            {\n                queueIds[0] = QueueId.GetQueueId(queueNamePrefix, 0, 0);\n            }\n            else\n            {\n                uint portion = checked((uint)(RangeFactory.RING_SIZE / numQueues + 1));\n                for (uint i = 0; i < numQueues; i++)\n                {\n                    uint uniformHashCode = checked(portion * i);\n                    queueIds[i] = QueueId.GetQueueId(queueNamePrefix, i, uniformHashCode);\n                }\n            }\n\n            this.hashRing = new(queueIds);\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<QueueId> GetQueuesForRange(IRingRange range)\n        {\n            var ls = new List<QueueId>();\n            foreach (QueueId queueId in hashRing.GetAllRingMembers())\n            {\n                if (range.InRange(queueId.GetUniformHashCode()))\n                {\n                    ls.Add(queueId);\n                }\n            }\n\n            return ls;\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<QueueId> GetAllQueues() => hashRing.GetAllRingMembers();\n\n        /// <inheritdoc/>\n        public QueueId GetQueueForStream(StreamId streamId) => hashRing.CalculateResponsible((uint)streamId.GetHashCode());\n\n        /// <inheritdoc/>\n        public override string ToString() => hashRing.ToString();\n    }\n\n    /// <summary>\n    /// Queue mapper that tracks which partition was mapped to which QueueId\n    /// </summary>\n    public sealed class HashRingBasedPartitionedStreamQueueMapper : HashRingBasedStreamQueueMapper\n    {\n        private readonly Dictionary<QueueId, string> _partitions;\n\n        /// <summary>\n        /// Queue mapper that tracks which partition was mapped to which QueueId\n        /// </summary>\n        /// <param name=\"partitionIds\">List of partitions</param>\n        /// <param name=\"queueNamePrefix\">Prefix for QueueIds.  Must be unique per stream provider</param>\n        public HashRingBasedPartitionedStreamQueueMapper(IReadOnlyList<string> partitionIds, string queueNamePrefix)\n            : base(partitionIds.Count, queueNamePrefix)\n        {\n            var queues = (QueueId[])GetAllQueues();\n            _partitions = new(queues.Length);\n            for (var i = 0; i < queues.Length; i++)\n                _partitions.Add(queues[i], partitionIds[i]);\n        }\n\n        /// <summary>\n        /// Gets the partition by QueueId\n        /// </summary>\n        /// <param name=\"queue\"></param>\n        /// <returns></returns>\n        public string QueueToPartition(QueueId queue) => _partitions.TryGetValue(queue, out var p) ? p : throw new ArgumentOutOfRangeException($\"Queue {queue:H}\");\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/HashRingStreamQueueMapperOptions.cs",
    "content": "using Orleans.Streams;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for <see cref=\"HashRingBasedStreamQueueMapper\"/>.\n    /// </summary>\n    public class HashRingStreamQueueMapperOptions\n    {\n        /// <summary>\n        /// Gets or sets the total queue count.\n        /// </summary>\n        /// <value>The total queue count.</value>\n        public int TotalQueueCount { get; set; } = DEFAULT_NUM_QUEUES;\n\n        /// <summary>\n        /// The default number queues, which should be a power of two.\n        /// </summary>\n        public const int DEFAULT_NUM_QUEUES = 8;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IBatchContainer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Each queue message is allowed to be a heterogeneous, ordered set of events.\n    /// <see cref=\"IBatchContainer\"/> contains these events and allows users to query the batch for a specific type of event.\n    /// </summary>\n    public interface IBatchContainer\n    {\n        /// <summary>\n        /// Ges the stream identifier for the stream this batch is part of.\n        /// </summary>\n        StreamId StreamId { get; }\n\n        /// <summary>\n        /// Gets events of a specific type from the batch.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        IEnumerable<Tuple<T,StreamSequenceToken>> GetEvents<T>();\n\n        /// <summary>\n        /// Ges the stream sequence token for the start of this batch.\n        /// </summary>\n        StreamSequenceToken SequenceToken { get; }\n\n        /// <summary>\n        /// Gives an opportunity to <see cref=\"IBatchContainer\"/> to set any data in the <see cref=\"RequestContext\"/> before this <see cref=\"IBatchContainer\"/> is sent to consumers.\n        /// It can be the data that was set at the time event was generated and enqueued into the persistent provider or any other data.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"RequestContext\"/> was indeed modified, <see langword=\"false\"/> otherwise.</returns>\n        bool ImportRequestContext();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IBatchContainerBatch.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// A batch of queue messages (see IBatchContainer for description of batch contents)\n    /// </summary>\n    public interface IBatchContainerBatch : IBatchContainer\n    {\n        /// <summary>\n        /// Gets the batch containers comprising this batch\n        /// </summary>\n        List<IBatchContainer> BatchContainers { get; }\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IConsistentRingStreamQueueMapper.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\n\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// The stream queue mapper is responsible for mapping ring ranges from the load balancing ring provider to stream queues.\n    /// Implementation must be thread safe.\n    /// </summary>\n    public interface IConsistentRingStreamQueueMapper : IStreamQueueMapper\n    {\n        /// <summary>\n        /// Gets the queues which map to the specified range.\n        /// </summary>\n        /// <param name=\"range\">The range.</param>\n        /// <returns>The queues which map to the specified range.</returns>\n        IEnumerable<QueueId> GetQueuesForRange(IRingRange range);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueAdapter.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Stream queue storage adapter.  This is an abstraction layer that hides the implementation details of the underlying queuing system.\n    /// </summary>\n    public interface IQueueAdapter\n    {\n        /// <summary>\n        /// Gets the name of the adapter. Primarily for logging purposes\n        /// </summary>\n        string Name { get; }\n\n        /// <summary>\n        /// Writes a set of events to the queue as a single batch associated with the provided streamId.\n        /// </summary>\n        /// <typeparam name=\"T\">The queue element type.</typeparam>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"events\">The events.</param>\n        /// <param name=\"token\">The token.</param>\n        /// <param name=\"requestContext\">The request context.</param>\n        /// <returns>Task.</returns>\n        Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token, Dictionary<string, object> requestContext);\n\n        /// <summary>\n        /// Creates a queue receiver for the specified queueId\n        /// </summary>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <returns>The receiver.</returns>\n        IQueueAdapterReceiver CreateReceiver(QueueId queueId);\n\n        /// <summary>\n        /// Gets a value indicating whether this is a rewindable stream adapter - supports subscribing from previous point in time.\n        /// </summary>\n        /// <returns>True if this is a rewindable stream adapter, false otherwise.</returns>\n        bool IsRewindable { get; }\n\n        /// <summary>\n        /// Gets the direction of this queue adapter: <see cref=\"StreamProviderDirection.ReadOnly\"/>, <see cref=\"StreamProviderDirection.WriteOnly\"/>, or <see cref=\"StreamProviderDirection.ReadWrite\"/>.\n        /// </summary>\n        /// <returns>The direction in which this adapter provides data.</returns>\n        StreamProviderDirection Direction { get; }\n    }\n\n    /// <summary>\n    /// Extension methods for <see cref=\"IQueueAdapter\"/>\n    /// </summary>\n    public static class QueueAdapterExtensions\n    {\n        /// <summary>\n        /// Writes a set of events to the queue as a single batch associated with the provided <paramref name=\"streamId\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The queue element type.</typeparam>\n        /// <param name=\"adapter\">The adapter.</param>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"evt\">The event.</param>\n        /// <param name=\"token\">The token.</param>\n        /// <param name=\"requestContext\">The request context.</param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        public static Task QueueMessageAsync<T>(this IQueueAdapter adapter, StreamId streamId, T evt, StreamSequenceToken token, Dictionary<string, object> requestContext)\n        {\n            return adapter.QueueMessageBatchAsync(streamId, new[] { evt }, token, requestContext);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueAdapterCache.cs",
    "content": "namespace Orleans.Streams\n{\n    /// <summary>\n    /// Functionality for creating an <see cref=\"IQueueCache\"/> for a given queue.\n    /// </summary>\n    public interface IQueueAdapterCache\n    {\n        /// <summary>\n        /// Create a cache for a given queue id\n        /// </summary>\n        /// <param name=\"queueId\">The queue id.</param>\n        /// <returns>The queue cache..</returns>\n        IQueueCache CreateQueueCache(QueueId queueId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueAdapterFactory.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Adapter factory. This should create an adapter from the stream provider configuration\n    /// </summary>\n    public interface IQueueAdapterFactory\n    {\n        /// <summary>\n        /// Creates a queue adapter.\n        /// </summary>\n        /// <returns>The queue adapter</returns>\n        Task<IQueueAdapter> CreateAdapter();\n\n        /// <summary>\n        /// Creates queue message cache adapter.\n        /// </summary>\n        /// <returns>The queue adapter cache.</returns>\n        IQueueAdapterCache GetQueueAdapterCache();\n\n        /// <summary>\n        /// Creates a queue mapper.\n        /// </summary>\n        /// <returns>The queue mapper.</returns>\n        IStreamQueueMapper GetStreamQueueMapper();\n\n        /// <summary>\n        /// Acquire delivery failure handler for a queue\n        /// </summary>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <returns>The stream failure handler.</returns>\n        Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueAdapterReceiver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Receives batches of messages from a single partition of a message queue.  \n    /// </summary>\n    public interface IQueueAdapterReceiver\n    {\n        /// <summary>\n        /// Initializes this receiver.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Initialize(TimeSpan timeout);\n\n        /// <summary>\n        /// Retrieves batches from a message queue.\n        /// </summary>\n        /// <param name=\"maxCount\">\n        /// The maximum number of message batches to retrieve.\n        /// </param>\n        /// <returns>The message batches.</returns>\n        Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount);\n\n        /// <summary>\n        /// Notifies the adapter receiver that the messages were delivered to all consumers,\n        /// so the receiver can take an appropriate action (e.g., delete the messages from a message queue).\n        /// </summary>\n        /// <param name=\"messages\">\n        /// The message batches.\n        /// </param>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task MessagesDeliveredAsync(IList<IBatchContainer> messages);\n\n        /// <summary>\n        /// Receiver is no longer used. Shutdown and clean up.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the operation.</returns>\n        Task Shutdown(TimeSpan timeout);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueCache.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    public interface IQueueCache : IQueueFlowController\n    {\n        /// <summary>\n        /// Adds messages to the cache.\n        /// </summary>\n        /// <param name=\"messages\">The message batches.</param>\n        void AddToCache(IList<IBatchContainer> messages);\n\n        /// <summary>\n        /// Requests that the cache purge any items that can be purged.\n        /// </summary>\n        /// <param name=\"purgedItems\">The purged items.</param>\n        /// <returns><see langword=\"true\" /> if items were successfully purged from the cache., <see langword=\"false\" /> otherwise.</returns>\n        bool TryPurgeFromCache(out IList<IBatchContainer> purgedItems);\n\n        /// <summary>\n        /// Acquire a stream message cursor.  This can be used to retrieve messages from the\n        /// cache starting at the location indicated by the provided token.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <param name=\"token\">The token.</param>\n        /// <returns>The queue cache cursor.</returns>\n        IQueueCacheCursor GetCacheCursor(StreamId streamId, StreamSequenceToken token);\n\n        /// <summary>\n        /// Returns <see langword=\"true\" /> if this cache is under pressure, <see langword=\"false\" /> otherwise.\n        /// </summary>\n        /// <returns><see langword=\"true\" /> if this cache is under pressure; otherwise, <see langword=\"false\" />.</returns>\n        bool IsUnderPressure();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueCacheCursor.cs",
    "content": "using System;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Enumerates the messages in a stream.\n    /// </summary>\n    public interface IQueueCacheCursor : IDisposable\n    {\n        /// <summary>\n        /// Get the current value.\n        /// </summary>\n        /// <param name=\"exception\">The resulting exception.</param>\n        /// <returns>\n        /// Returns the current batch container.\n        /// If null then the stream has completed or there was a stream error.  \n        /// If there was a stream error, an error exception will be provided in the output.\n        /// </returns>\n        IBatchContainer GetCurrent(out Exception exception);\n\n        /// <summary>\n        /// Move to next message in the stream.\n        /// If it returns false, there are no more messages.  The enumerator is still\n        ///  valid however and can be called again when more data has come in on this\n        ///  stream.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if there are more items, <see langword=\"false\"/> otherwise</returns>\n        bool MoveNext();\n\n        /// <summary>\n        /// Refreshes the cache cursor. Called when new data is added into a cache.\n        /// </summary>\n        /// <param name=\"token\">The token.</param>\n        void Refresh(StreamSequenceToken token);\n\n        /// <summary>\n        /// Records that delivery of the current event has failed\n        /// </summary>\n        void RecordDeliveryFailure();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IQueueFlowController.cs",
    "content": "\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Functionality for controlling the flow of retrieved queue items.\n    /// </summary>\n    public interface IQueueFlowController\n    {\n        /// <summary>\n        /// Gets the maximum number of items that can be added.\n        /// </summary>\n        /// <returns>\n        /// The maximum number of items that can be added.\n        /// </returns>\n        int GetMaxAddCount();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/IStreamQueueMapper.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// The stream queue mapper returns a list of all queues and is also responsible for mapping streams to queues.\n    /// Implementation must be thread safe.\n    /// </summary>\n    public interface IStreamQueueMapper\n    {\n        /// <summary>\n        /// Gets all queues.\n        /// </summary>\n        /// <returns>All queues.</returns>\n        IEnumerable<QueueId> GetAllQueues();\n\n        /// <summary>\n        /// Gets the queue for the specified stream.\n        /// </summary>\n        /// <param name=\"streamId\">The stream identifier.</param>\n        /// <returns>The queue responsible for the specified stream.</returns>\n        QueueId GetQueueForStream(StreamId streamId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/QueueAdapterConstants.cs",
    "content": "namespace Orleans.Streams\n{\n    /// <summary>\n    /// Constants for queue adapters.\n    /// </summary>\n    public static class QueueAdapterConstants\n    {\n        /// <summary>\n        /// The value used to indicate an unlimited number of messages can be retrieved, when returned by <see cref=\"IQueueFlowController.GetMaxAddCount\"/>.\n        /// </summary>\n        public const int UNLIMITED_GET_QUEUE_MSG = -1;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueAdapters/QueueCacheMissException.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Exception indicates that the requested message is not in the queue cache.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class QueueCacheMissException : DataNotAvailableException\n    {\n        private const string MESSAGE_FORMAT = \"Item not found in cache.  Requested: {0}, Low: {1}, High: {2}\";\n\n        /// <summary>\n        /// Gets the requested sequence token.\n        /// </summary>\n        /// <value>The requested sequence token.</value>\n        [Id(0)]\n        public string Requested { get; private set; }\n\n        /// <summary>\n        /// Gets the earliest available sequence token.\n        /// </summary>\n        [Id(1)]\n        public string Low { get; private set; }\n\n        /// <summary>\n        /// Gets the latest available sequence token.\n        /// </summary>\n        [Id(2)]\n        public string High { get; private set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        public QueueCacheMissException() : this(\"Item no longer in cache\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        public QueueCacheMissException(string message) : base(message) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public QueueCacheMissException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        /// <param name=\"requested\">The requested sequence token.</param>\n        /// <param name=\"low\">The earliest available sequence token.</param>\n        /// <param name=\"high\">The latest available sequence token.</param>\n        public QueueCacheMissException(StreamSequenceToken requested, StreamSequenceToken low, StreamSequenceToken high)\n            : this(requested.ToString(), low.ToString(), high.ToString())\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        /// <param name=\"requested\">The requested sequence token.</param>\n        /// <param name=\"low\">The earliest available sequence token.</param>\n        /// <param name=\"high\">The latest available sequence token.</param>\n        public QueueCacheMissException(string requested, string low, string high)\n            : this(string.Format(CultureInfo.InvariantCulture, MESSAGE_FORMAT, requested, low, high))\n        {\n            Requested = requested;\n            Low = low;\n            High = high;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueCacheMissException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private QueueCacheMissException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            Requested = info.GetString(\"Requested\");\n            Low = info.GetString(\"Low\");\n            High = info.GetString(\"High\");\n        }\n\n        /// <inheritdoc/>\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"Requested\", Requested);\n            info.AddValue(\"Low\", Low);\n            info.AddValue(\"High\", High);\n            base.GetObjectData(info, context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/BestFitBalancer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Best fit balancer keeps each active bucket responsible for its ideal set of resources, and redistributes\n    /// resources from inactive buckets evenly over active buckets.  If there are large numbers of inactive buckets,\n    /// this can lead to quite a bit of shuffling of resources from inactive buckets as buckets come back online.\n    /// Requirements:\n    /// - Even distribution of resources across buckets\n    /// - Must be consistent results for same inputs regardless of input order.\n    /// - Minimize movement of resources when rebalancing from changes in active buckets.\n    /// - Must be deterministic independent of previous distribution state.\n    /// Algorithm:\n    /// - On creation generate an ideal distribution of resources across all buckets, that is, each bucket has no more than 1 resource more\n    ///    than any other bucket.\n    /// - When requesting new resource distribution for a list of active buckets:\n    ///     1) Initialize the new distribution of each active bucket with the ideal resources for that bucket.  This prevents\n    ///        these resources from ever being assigned to another bucket unless a bucket becomes inactive.\n    ///     2) Build a list of inactive buckets.\n    ///     3) For each inactive bucket, add its ideal resource allocation to the list of resources to be reallocated.\n    ///     4) Order the active buckets by the number of resources allocated to each and begin assigning them more resources\n    ///        from the list of resources to be reallocated.\n    ///         i) Continue iterating over the active buckets assigning resources until there are no more resources that need\n    ///            reallocated.\n    /// </summary>\n    /// <typeparam name=\"TBucket\">Type of bucket upon which resources will be distributed among</typeparam>\n    /// <typeparam name=\"TResource\">Type of resources being distributed</typeparam>\n    internal class BestFitBalancer<TBucket, TResource>\n        where TBucket : IEquatable<TBucket>, IComparable<TBucket>\n        where TResource : IEquatable<TResource>, IComparable<TResource>\n    {\n        private readonly Dictionary<TBucket, List<TResource>> idealDistribution;\n\n        public Dictionary<TBucket, List<TResource>> IdealDistribution { get { return idealDistribution; } }\n\n        /// <summary>\n        /// Constructor.\n        /// Initializes an ideal distribution to be used to aid in resource to bucket affinity.\n        /// </summary>\n        /// <param name=\"buckets\">Buckets among which to distribute resources.</param>\n        /// <param name=\"resources\">Resources to be distributed.</param>\n        public BestFitBalancer(IEnumerable<TBucket> buckets, IEnumerable<TResource> resources)\n        {\n            if (buckets == null)\n            {\n                throw new ArgumentNullException(nameof(buckets));\n            }\n\n            if (resources == null)\n            {\n                throw new ArgumentNullException(nameof(resources));\n            }\n\n            idealDistribution = BuildIdealDistribution(buckets, resources);\n        }\n\n        /// <summary>\n        /// Gets a distribution for the active buckets.\n        /// Any active buckets keep their ideal distribution.  Resources from inactive buckets are redistributed evenly\n        /// among the active buckets, starting with those with the fewest allocated resources.\n        /// </summary>\n        /// <param name=\"activeBuckets\">currently active buckets</param>\n        /// <returns></returns>\n        public Dictionary<TBucket, List<TResource>> GetDistribution(IEnumerable<TBucket> activeBuckets)\n        {\n            if (activeBuckets == null)\n            {\n                throw new ArgumentNullException(nameof(activeBuckets));\n            }\n\n            // sanitize active buckets.  Remove duplicates, ensure all buckets are valid\n            HashSet<TBucket> activeBucketsSet = new HashSet<TBucket>(activeBuckets);\n            foreach (var bucket in activeBucketsSet)\n            {\n                if (!idealDistribution.ContainsKey(bucket))\n                {\n                    throw new ArgumentOutOfRangeException(nameof(activeBuckets), string.Format(\"Active buckets contain a bucket {0} not in the master list.\", bucket));\n                }\n            }\n\n            var newDistribution = new Dictionary<TBucket, List<TResource>>();\n            // if no buckets, return empty resource distribution\n            if (activeBucketsSet.Count == 0)\n            {\n                return newDistribution;\n            }\n\n            // setup ideal distribution for active buckets and build list of all resources that need redistributed from inactive buckets\n            var resourcesToRedistribute = new List<TResource>();\n            foreach (var kv in idealDistribution)\n            {\n                if (activeBucketsSet.Contains(kv.Key))\n                    newDistribution.Add(kv.Key, kv.Value);\n                else\n                    resourcesToRedistribute.AddRange(kv.Value);\n            }\n\n            // redistribute remaining resources across the resource lists of the active buckets, resource lists with the fewest reasources first\n            IOrderedEnumerable<List<TResource>> sortedResourceLists = newDistribution.Values.OrderBy(resources => resources.Count);\n            IEnumerator<List<TResource>> resourceListenumerator = sortedResourceLists.GetEnumerator();\n            foreach (TResource resource in resourcesToRedistribute)\n            {\n                // if we reach the end, start over\n                if (!resourceListenumerator.MoveNext())\n                {\n                    resourceListenumerator = sortedResourceLists.GetEnumerator();\n                    resourceListenumerator.MoveNext();\n                }\n                resourceListenumerator.Current.Add(resource);\n            }\n\n            return newDistribution;\n        }\n\n        /// <summary>\n        /// Distribute resources evenly among buckets in a deterministic way.\n        /// - Must distribute resources evenly regardless off order of inputs.\n        /// </summary>\n        /// <param name=\"buckets\">Buckets among which to distribute resources.</param>\n        /// <param name=\"resources\">Resources to be distributed.</param>\n        /// <returns>Dictionary of resources evenly distributed among the buckets</returns>\n        private static Dictionary<TBucket, List<TResource>> BuildIdealDistribution(IEnumerable<TBucket> buckets, IEnumerable<TResource> resources)\n        {\n            var idealDistribution = new Dictionary<TBucket, List<TResource>>();\n\n            // Sanitize buckets.  Remove duplicates and sort\n            List<TBucket> bucketList = buckets.Distinct().ToList();\n            if (bucketList.Count == 0)\n            {\n                return idealDistribution;\n            }\n            bucketList.Sort();\n\n            // Sanitize resources.  Removed duplicates and sort\n            List<TResource> resourceList = resources.Distinct().ToList();\n            resourceList.Sort();\n\n            // Distribute resources evenly among buckets\n            var upperResourceCountPerBucket = (int)Math.Ceiling((double)resourceList.Count / bucketList.Count);\n            var lowerResourceCountPerBucket = upperResourceCountPerBucket - 1;\n            List<TResource>.Enumerator resourceEnumerator = resourceList.GetEnumerator();\n            int bucketsToFillWithUpperResource = resourceList.Count % bucketList.Count;\n            // a bucketsToFillWithUpperResource of 0 indicates resources are evenly devisible, so fill them all with upper resource count\n            if (bucketsToFillWithUpperResource == 0)\n            {\n                bucketsToFillWithUpperResource = bucketList.Count;\n            }\n            int bucketsFilledCount = 0;\n            foreach (TBucket bucket in bucketList)\n            {\n                // if we've filled the first bucketsToFillWithUpperResource buckets with upperResourceCountPerBucket\n                //   resources, fill the rest with lowerResourceCountPerBucket\n                int resourcesToAddToBucket = bucketsFilledCount < bucketsToFillWithUpperResource\n                    ? upperResourceCountPerBucket\n                    : lowerResourceCountPerBucket;\n                var bucketResources = new List<TResource>();\n                idealDistribution.Add(bucket, bucketResources);\n                while (resourceEnumerator.MoveNext())\n                {\n                    bucketResources.Add(resourceEnumerator.Current);\n                    if (bucketResources.Count >= resourcesToAddToBucket)\n                    {\n                        break;\n                    }\n                }\n                bucketsFilledCount++;\n            }\n            return idealDistribution;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/ConsistentRingQueueBalancer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Runtime.ConsistentRing;\n\nnamespace Orleans.Streams\n{\n    internal class ConsistentRingQueueBalancer : QueueBalancerBase, IStreamQueueBalancer, IRingRangeListener\n    {\n        private IConsistentRingStreamQueueMapper _streamQueueMapper;\n        private IRingRange _myRange;\n\n        public static IStreamQueueBalancer Create(IServiceProvider services, string name)\n        {\n            return ActivatorUtilities.CreateInstance<ConsistentRingQueueBalancer>(services);\n        }\n\n        public ConsistentRingQueueBalancer(IConsistentRingProvider consistentRingProvider, ILoggerFactory loggerFactory, IServiceProvider services, ILogger<ConsistentRingQueueBalancer> logger)\n            : base(services, logger)\n        {\n            if (consistentRingProvider == null)\n            {\n                throw new ArgumentNullException(\"streamProviderRuntime\");\n            }\n\n            _myRange = consistentRingProvider.GetMyRange();\n            consistentRingProvider.SubscribeToRangeChangeEvents(this);\n        }\n\n        public override Task Initialize(IStreamQueueMapper queueMapper)\n        {\n            if (queueMapper == null)\n            {\n                throw new ArgumentNullException(nameof(queueMapper));\n            }\n\n            if (queueMapper is not IConsistentRingStreamQueueMapper streamQueueMapper)\n            {\n                throw new ArgumentException(\"IStreamQueueMapper for ConsistentRingQueueBalancer should implement IConsistentRingStreamQueueMapper\", nameof(queueMapper));\n            }\n\n            _streamQueueMapper = streamQueueMapper;\n            return base.Initialize(queueMapper);\n        }\n\n        public override IEnumerable<QueueId> GetMyQueues()\n        {\n            return _streamQueueMapper.GetQueuesForRange(_myRange);\n        }\n\n        protected override void OnClusterMembershipChange(HashSet<SiloAddress> activeSilos)\n        {\n        }\n\n        public void RangeChangeNotification(IRingRange old, IRingRange now, bool increased)\n        {\n            _myRange = now;\n            base.NotifyListeners().Ignore();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/DeploymentBasedQueueBalancer.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// DeploymentBasedQueueBalancer is a stream queue balancer that uses deployment information to\n    /// help balance queue distribution.\n    /// DeploymentBasedQueueBalancer uses the deployment configuration to determine how many silos\n    /// to expect and uses a silo status oracle to determine which of the silos are available.  With\n    /// this information it tries to balance the queues using a best fit resource balancing algorithm.\n    /// </summary>\n    public class DeploymentBasedQueueBalancer : QueueBalancerBase, IStreamQueueBalancer\n    {\n        private readonly ISiloStatusOracle siloStatusOracle;\n        private readonly IDeploymentConfiguration deploymentConfig;\n        private readonly DeploymentBasedQueueBalancerOptions options;\n        private readonly ConcurrentDictionary<SiloAddress, bool> immatureSilos;\n        private List<QueueId> allQueues;\n        private bool isStarting;\n        \n        public DeploymentBasedQueueBalancer(\n            ISiloStatusOracle siloStatusOracle,\n            IDeploymentConfiguration deploymentConfig,\n            DeploymentBasedQueueBalancerOptions options,\n            IServiceProvider services,\n            ILogger<DeploymentBasedQueueBalancer> logger)\n            : base (services, logger)\n        {\n            this.siloStatusOracle = siloStatusOracle ?? throw new ArgumentNullException(nameof(siloStatusOracle));\n            this.deploymentConfig = deploymentConfig ?? throw new ArgumentNullException(nameof(deploymentConfig));\n            this.options = options;\n\n            isStarting = true;\n\n            // record all already active silos as already mature. \n            // Even if they are not yet, they will be mature by the time I mature myself (after I become !isStarting).\n            immatureSilos = new ConcurrentDictionary<SiloAddress, bool>(\n                from s in siloStatusOracle.GetApproximateSiloStatuses(true).Keys\n                where !s.Equals(siloStatusOracle.SiloAddress)\n                select new KeyValuePair<SiloAddress, bool>(s, false));\n        }\n\n        public static IStreamQueueBalancer Create(IServiceProvider services, string name, IDeploymentConfiguration deploymentConfiguration)\n        {\n            var options = services.GetRequiredService<IOptionsMonitor<DeploymentBasedQueueBalancerOptions>>().Get(name);\n            return ActivatorUtilities.CreateInstance<DeploymentBasedQueueBalancer>(services, options, deploymentConfiguration);\n        }\n\n        public override Task Initialize(IStreamQueueMapper queueMapper)\n        {\n            if (queueMapper == null)\n            {\n                throw new ArgumentNullException(nameof(queueMapper));\n            }\n            this.allQueues = queueMapper.GetAllQueues().ToList();\n            NotifyAfterStart().Ignore();\n            return base.Initialize(queueMapper);\n        }\n        \n        private async Task NotifyAfterStart()\n        {\n            await Task.Delay(this.options.SiloMaturityPeriod);\n            isStarting = false;\n            await NotifyListeners();\n        }\n\n        private async Task RecordImmatureSilo(SiloAddress updatedSilo)\n        {\n            immatureSilos[updatedSilo] = true;      // record as immature\n            await Task.Delay(this.options.SiloMaturityPeriod);\n            immatureSilos[updatedSilo] = false;     // record as mature\n        }\n\n        public override IEnumerable<QueueId> GetMyQueues()\n        {\n            BestFitBalancer<string, QueueId> balancer = GetBalancer();\n            bool useIdealDistribution = this.options.IsFixed || isStarting;\n            Dictionary<string, List<QueueId>> distribution = useIdealDistribution\n                ? balancer.IdealDistribution\n                : balancer.GetDistribution(GetActiveSilos(siloStatusOracle, immatureSilos));\n\n            List<QueueId> myQueues;\n            if (distribution.TryGetValue(siloStatusOracle.SiloName, out myQueues))\n            {\n                if (!useIdealDistribution)\n                {\n                    HashSet<QueueId> queuesOfImmatureSilos = GetQueuesOfImmatureSilos(siloStatusOracle, immatureSilos, balancer.IdealDistribution);\n                    // filter queues that belong to immature silos\n                    myQueues.RemoveAll(queue => queuesOfImmatureSilos.Contains(queue));\n                }\n                return myQueues;\n            }\n            return Enumerable.Empty<QueueId>();\n        }\n\n        private static List<string> GetActiveSilos(ISiloStatusOracle siloStatusOracle, ConcurrentDictionary<SiloAddress, bool> immatureSilos)\n        {\n            var activeSiloNames = new List<string>();\n            foreach (var kvp in siloStatusOracle.GetApproximateSiloStatuses(true))\n            {\n                bool immatureBit;\n                if (!(immatureSilos.TryGetValue(kvp.Key, out immatureBit) && immatureBit)) // if not immature now or any more\n                {\n                    string siloName;\n                    if (siloStatusOracle.TryGetSiloName(kvp.Key, out siloName))\n                    {\n                        activeSiloNames.Add(siloName);\n                    }\n                }\n            }\n            return activeSiloNames;\n        }\n\n        /// <summary>\n        /// Checks to see if deployment configuration has changed, by adding or removing silos.\n        /// If so, it updates the list of all silo names and creates a new resource balancer.\n        /// This should occur rarely.\n        /// </summary>\n        private BestFitBalancer<string, QueueId> GetBalancer()\n        {\n            var allSiloNames = deploymentConfig.GetAllSiloNames();\n            // rebuild balancer with new list of instance names\n            return new BestFitBalancer<string, QueueId>(allSiloNames, allQueues);\n        }\n\n        private static HashSet<QueueId> GetQueuesOfImmatureSilos(ISiloStatusOracle siloStatusOracle, \n            ConcurrentDictionary<SiloAddress, bool> immatureSilos, \n            Dictionary<string, List<QueueId>> idealDistribution)\n        {\n            HashSet<QueueId> queuesOfImmatureSilos = new HashSet<QueueId>();\n            foreach (var silo in immatureSilos.Where(s => s.Value)) // take only those from immature set that have their immature status bit set\n            {\n                string siloName;\n                if (siloStatusOracle.TryGetSiloName(silo.Key, out siloName))\n                {\n                    List<QueueId> queues;\n                    if (idealDistribution.TryGetValue(siloName, out queues))\n                    {\n                        queuesOfImmatureSilos.UnionWith(queues);\n                    }\n                }\n            }\n            return queuesOfImmatureSilos;\n        }\n\n        protected override void OnClusterMembershipChange(HashSet<SiloAddress> activeSilos)\n        {\n            SignalClusterChange(activeSilos).Ignore();\n        }\n\n        private async Task SignalClusterChange(HashSet<SiloAddress> activeSilos)\n        {\n            List<Task> tasks = new List<Task>();\n            // look at all currently active silos not including myself\n            foreach (var silo in activeSilos)\n            {\n                if (!silo.Equals(siloStatusOracle.SiloAddress) && !immatureSilos.ContainsKey(silo))\n                {\n                    tasks.Add(RecordImmatureSilo(silo));\n                }\n            }\n            if (!isStarting)\n            {\n                // notify, uncoditionaly, and deal with changes in GetMyQueues()\n                await NotifyListeners();\n            }\n            if (tasks.Count > 0)\n            {\n                await Task.WhenAll(tasks);\n                await this.NotifyListeners(); // notify, uncoditionaly, and deal with changes it in GetMyQueues()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/DeploymentBasedQueueBalancerOptions.cs",
    "content": "using System;\nusing Orleans.Streams;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Options for <see cref=\"DeploymentBasedQueueBalancer\"/>.\n    /// </summary>\n    public class DeploymentBasedQueueBalancerOptions\n    {\n        /// <summary>\n        /// Gets or sets the silo maturity period, which is the period of time to allow a silo to remain active for before rebalancing queues.\n        /// </summary>\n        /// <value>The silo maturity period.</value>\n        public TimeSpan SiloMaturityPeriod { get; set; } = DEFAULT_SILO_MATURITY_PERIOD;\n\n        /// <summary>\n        /// The default silo maturity period.\n        /// </summary>\n        public static readonly TimeSpan DEFAULT_SILO_MATURITY_PERIOD = TimeSpan.FromMinutes(2);\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to presume a static (fixed) cluster.\n        /// </summary>\n        public bool IsFixed { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/IResourceSelector.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// IResourceSelector selects a certain amount of resources from a resource list\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    internal interface IResourceSelector<T>\n    {\n        /// <summary>\n        /// Number of resources\n        /// </summary>\n        int Count { get; }\n\n        /// <summary>\n        /// Try to select certain count of resources from resource list, which doesn't overlap with existing selection\n        /// </summary>\n        /// <param name=\"newSelectionCount\"></param>\n        /// <param name=\"existingSelection\"></param>\n        /// <returns></returns>\n        List<T> NextSelection(int newSelectionCount, List<T> existingSelection);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/LeaseBasedQueueBalancer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.LeaseProviders;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Streams;\n\n/// <summary>\n/// LeaseBasedQueueBalancer. This balancer supports queue balancing in cluster auto-scale scenarios,\n/// unexpected server failure scenarios, and tries to support ideal distribution as much as possible.\n/// </summary>\n/// <remarks>\n/// Initializes a new instance of the <see cref=\"LeaseBasedQueueBalancer\"/> class.\n/// </remarks>\n/// <param name=\"name\">The name.</param>\n/// <param name=\"options\">The options.</param>\n/// <param name=\"leaseProvider\">The lease provider.</param>\n/// <param name=\"services\">The services.</param>\n/// <param name=\"loggerFactory\">The logger factory.</param>\npublic partial class LeaseBasedQueueBalancer(\n    string name,\n    LeaseBasedQueueBalancerOptions options,\n    ILeaseProvider leaseProvider,\n    IServiceProvider services,\n    ILoggerFactory loggerFactory,\n    TimeProvider timeProvider) : QueueBalancerBase(services, loggerFactory.CreateLogger($\"{typeof(LeaseBasedQueueBalancer).FullName}.{name}\")), IStreamQueueBalancer\n{\n    private sealed class AcquiredQueue(int order, QueueId queueId, AcquiredLease lease)\n    {\n        public int LeaseOrder { get; set; } = order;\n        public QueueId QueueId { get; set; } = queueId;\n        public AcquiredLease AcquiredLease { get; set; } = lease;\n    }\n\n    private readonly LeaseBasedQueueBalancerOptions _options = options;\n    private readonly ILeaseProvider _leaseProvider = leaseProvider;\n    private readonly AsyncSerialExecutor _executor = new();\n    private readonly List<AcquiredQueue> _myQueues = [];\n    private readonly PeriodicTimer _leaseMaintenanceTimer = new(Timeout.InfiniteTimeSpan, timeProvider);\n    private readonly PeriodicTimer _leaseAcquisitionTimer = new(Timeout.InfiniteTimeSpan, timeProvider);\n    private Task _leaseMaintenanceTimerTask = Task.CompletedTask;\n    private Task _leaseAcquisitionTimerTask = Task.CompletedTask;\n    private RoundRobinSelector<QueueId> _queueSelector;\n    private int _allQueuesCount;\n    private int _responsibility;\n    private int _leaseOrder;\n\n    /// <summary>\n    /// Creates a new <see cref=\"LeaseBasedQueueBalancer\"/> instance.\n    /// </summary>\n    /// <param name=\"services\">The services.</param>\n    /// <param name=\"name\">The name.</param>\n    /// <returns>The new <see cref=\"LeaseBasedQueueBalancer\"/> instance.</returns>\n    public static IStreamQueueBalancer Create(IServiceProvider services, string name)\n    {\n        var options = services.GetOptionsByName<LeaseBasedQueueBalancerOptions>(name);\n        var leaseProvider = services.GetKeyedService<ILeaseProvider>(name)\n            ?? services.GetService<ILeaseProvider>()\n            ?? throw new InvalidOperationException($\"No lease provider found for queue balancer '{name}'. Register an implementation of {nameof(ILeaseProvider)}.\");\n        return ActivatorUtilities.CreateInstance<LeaseBasedQueueBalancer>(services, name, options, leaseProvider);\n    }\n\n    /// <inheritdoc/>\n    public override async Task Initialize(IStreamQueueMapper queueMapper)\n    {\n        if (Cancellation.IsCancellationRequested)\n        {\n            throw new InvalidOperationException(\"Cannot initialize a terminated balancer.\");\n        }\n\n        ArgumentNullException.ThrowIfNull(queueMapper);\n        var allQueues = queueMapper.GetAllQueues().ToList();\n        _allQueuesCount = allQueues.Count;\n\n        // Selector default to round robin selector now, but we can make a further change to make selector configurable if needed. Selector algorithm could\n        // be affecting queue balancing stabilization time in cluster initializing and auto-scaling\n        _queueSelector = new RoundRobinSelector<QueueId>(allQueues);\n        await base.Initialize(queueMapper);\n        StartMaintenanceTasks();\n\n        void StartMaintenanceTasks()\n        {\n            using var _ = new ExecutionContextSuppressor();\n            _leaseAcquisitionTimerTask = PeriodicallyAcquireLeasesToMeetResponsibility();\n            _leaseMaintenanceTimerTask = PeriodicallyMaintainLeases();\n        }\n    }\n\n    /// <inheritdoc/>\n    public override async Task Shutdown()\n    {\n        if (Cancellation.IsCancellationRequested) return;\n\n        // Stop acquiring and renewing leases.\n        _leaseMaintenanceTimer.Dispose();\n        _leaseAcquisitionTimer.Dispose();\n        await Task.WhenAll(_leaseMaintenanceTimerTask, _leaseAcquisitionTimerTask);\n\n        // Release all owned leases.\n        var shutdownTask = _executor.AddNext(async () =>\n        {\n            _responsibility = 0;\n            await ReleaseLeasesToMeetResponsibility();\n        });\n\n        // Signal shutdown.\n        await base.Shutdown();\n    }\n\n    /// <inheritdoc/>\n    public override IEnumerable<QueueId> GetMyQueues()\n    {\n        if (Cancellation.IsCancellationRequested)\n        {\n            throw new InvalidOperationException(\"Cannot acquire queues from a terminated balancer.\");\n        }\n\n        return _myQueues.Select(queue => queue.QueueId);\n    }\n\n    private async Task PeriodicallyMaintainLeases()\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n        while (await _leaseMaintenanceTimer.WaitForNextTickAsync())\n        {\n            try\n            {\n                await _executor.AddNext(MaintainLeases);\n            }\n            catch (Exception ex)\n            {\n                Logger.LogError(ex, \"Error maintaining leases.\");\n            }\n        }\n\n        async Task MaintainLeases()\n        {\n            if (Cancellation.IsCancellationRequested) return;\n            var oldQueues = new HashSet<QueueId>(_myQueues.Select(queue => queue.QueueId));\n            try\n            {\n                bool allLeasesRenewed = await RenewLeases();\n\n                // If we lost some leases during renew after leaseAcquisitionTimer stopped, restart it.\n                if (!allLeasesRenewed)\n                {\n                    // Make the acquisition timer fire immediately.\n                    _leaseAcquisitionTimer.Period = TimeSpan.FromMilliseconds(1);\n                }\n            }\n            finally\n            {\n                await NotifyOnChange(oldQueues);\n            }\n        }\n    }\n\n    private async Task PeriodicallyAcquireLeasesToMeetResponsibility()\n    {\n        await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n        while (await _leaseAcquisitionTimer.WaitForNextTickAsync())\n        {\n            // Set the period for the next round.\n            // It may be mutated by another method, but not concurrently.\n            _leaseAcquisitionTimer.Period = _options.LeaseAcquisitionPeriod;\n\n            try\n            {\n                await _executor.AddNext(AcquireLeasesToMeetResponsibility);\n            }\n            catch (Exception ex)\n            {\n                Logger.LogError(ex, \"Error acquiring leases.\");\n            }\n        }\n    }\n\n    private async Task AcquireLeasesToMeetResponsibility()\n    {\n        if (Cancellation.IsCancellationRequested) return;\n        var oldQueues = new HashSet<QueueId>(_myQueues.Select(queue => queue.QueueId));\n        try\n        {\n            if (_myQueues.Count < _responsibility)\n            {\n                await AcquireLeasesToMeetExpectation(_responsibility, _options.LeaseLength.Divide(10));\n            }\n            else if (_myQueues.Count > _responsibility)\n            {\n                await ReleaseLeasesToMeetResponsibility();\n            }\n        }\n        finally\n        {\n            await NotifyOnChange(oldQueues);\n            if (_myQueues.Count == _responsibility)\n            {\n                // Stop the acquisition timer.\n                _leaseAcquisitionTimer.Period = Timeout.InfiniteTimeSpan;\n            }\n        }\n    }\n\n    private async Task ReleaseLeasesToMeetResponsibility()\n    {\n        if (Cancellation.IsCancellationRequested) return;\n        LogTraceReleaseLeasesToMeetResponsibility(Logger, _myQueues.Count, _responsibility);\n\n        var queueCountToRelease = _myQueues.Count - _responsibility;\n        if (queueCountToRelease <= 0)\n        {\n            return;\n        }\n\n        // Remove oldest acquired queues first, this provides max recovery time for the queues being moved.\n        AcquiredLease[] queuesToGiveUp = _myQueues\n            .OrderBy(queue => queue.LeaseOrder)\n            .Take(queueCountToRelease)\n            .Select(queue => queue.AcquiredLease)\n            .ToArray();\n\n        // Remove queues from list even if release fails, since we can let the lease expire.\n        // TODO: mark for removal instead so we don't renew, and only remove leases that have not expired. - jbragg\n        for (int index = _myQueues.Count - 1; index >= 0; index--)\n        {\n            if (queuesToGiveUp.Contains(_myQueues[index].AcquiredLease))\n            {\n                _myQueues.RemoveAt(index);\n            }\n        }\n\n        await _leaseProvider.Release(_options.LeaseCategory, queuesToGiveUp);\n\n        // Remove queuesToGiveUp from myQueue list after the balancer released the leases on them.\n        LogDebugReleasedLeases(Logger, queueCountToRelease, _myQueues.Count, _responsibility);\n    }\n\n    private async Task AcquireLeasesToMeetExpectation(int expectedTotalLeaseCount, TimeSpan timeout)\n    {\n        if (Cancellation.IsCancellationRequested) return;\n        LogTraceAcquireLeasesToMeetExpectation(Logger, _myQueues.Count, expectedTotalLeaseCount);\n\n        var leasesToAcquire = expectedTotalLeaseCount - _myQueues.Count;\n        if (leasesToAcquire <= 0)\n        {\n            return;\n        }\n\n        // tracks how many remaining possible leases there are.\n        var possibleLeaseCount = _queueSelector.Count - _myQueues.Count;\n        LogDebugHoldingLeased(Logger, _myQueues.Count, leasesToAcquire, expectedTotalLeaseCount, possibleLeaseCount);\n\n        // Try to acquire leases until we have no more to acquire or no more possible\n        var sw = ValueStopwatch.StartNew();\n        while (!Cancellation.IsCancellationRequested && leasesToAcquire > 0 && possibleLeaseCount > 0)\n        {\n            // Select new queues to acquire\n            List<QueueId> expectedQueues = _queueSelector.NextSelection(leasesToAcquire, _myQueues.Select(queue => queue.QueueId).ToList());\n\n            // Build lease request from each queue\n            LeaseRequest[] leaseRequests = expectedQueues\n                .Select(queue => new LeaseRequest(queue.ToString(), _options.LeaseLength))\n                .ToArray();\n\n            // Add successfully acquired queue to myQueues list\n            AcquireLeaseResult[] results = await _leaseProvider.Acquire(_options.LeaseCategory, leaseRequests);\n            for (var i = 0; i < results.Length; i++)\n            {\n                AcquireLeaseResult result = results[i];\n                switch (result.StatusCode)\n                {\n                    case ResponseCode.OK:\n                        {\n                            _myQueues.Add(new AcquiredQueue(_leaseOrder++, expectedQueues[i], result.AcquiredLease));\n                            break;\n                        }\n                    case ResponseCode.TransientFailure:\n                        {\n                            LogWarningFailedToAcquireLeaseTransient(Logger, result.FailureException, result.AcquiredLease.ResourceKey);\n                            break;\n                        }\n                    // This is expected much of the time.\n                    case ResponseCode.LeaseNotAvailable:\n                        {\n                            LogDebugFailedToAcquireLeaseNotAvailable(Logger, result.FailureException, result.AcquiredLease.ResourceKey, result.StatusCode);\n                            break;\n                        }\n                    // An acquire call should not return this code, so log as error\n                    case ResponseCode.InvalidToken:\n                        {\n                            LogErrorFailedToAcquireLeaseInvalidToken(Logger, result.FailureException, result.AcquiredLease.ResourceKey);\n                            break;\n                        }\n                    default:\n                        {\n                            LogErrorUnexpectedAcquireLease(Logger, result.FailureException, result.AcquiredLease.ResourceKey, result.StatusCode);\n                            break;\n                        }\n                }\n            }\n\n            possibleLeaseCount -= expectedQueues.Count;\n            leasesToAcquire = expectedTotalLeaseCount - _myQueues.Count;\n            LogDebugHoldingLeased(Logger, _myQueues.Count, leasesToAcquire, expectedTotalLeaseCount, possibleLeaseCount);\n\n            if (sw.Elapsed > timeout)\n            {\n                // blown our allotted time, try again next period\n                break;\n            }\n        }\n\n        LogDebugHoldingLeases(Logger, _myQueues.Count, _responsibility);\n    }\n\n    /// <summary>\n    /// Renew leases\n    /// </summary>\n    /// <returns>bool - false if we failed to renew all leases</returns>\n    private async Task<bool> RenewLeases()\n    {\n        bool allRenewed = true;\n        if (Cancellation.IsCancellationRequested) return false;\n        LogTraceRenewLeases(Logger, _myQueues.Count);\n\n        if (_myQueues.Count <= 0)\n        {\n            return allRenewed;\n        }\n\n        var results = await _leaseProvider.Renew(_options.LeaseCategory, _myQueues.Select(queue => queue.AcquiredLease).ToArray());\n\n        // Update myQueues list with successfully renewed leases.\n        for (var i = results.Length - 1; i >= 0; i--)\n        {\n            AcquireLeaseResult result = results[i];\n            switch (result.StatusCode)\n            {\n                case ResponseCode.OK:\n                    {\n                        _myQueues[i].AcquiredLease = result.AcquiredLease;\n                        break;\n                    }\n                case ResponseCode.TransientFailure:\n                    {\n                        _myQueues.RemoveAt(i);\n                        allRenewed = false;\n                        LogWarningFailedToRenewLeaseTransient(Logger, result.FailureException, result.AcquiredLease.ResourceKey);\n                        break;\n                    }\n                // These can occur if lease has expired and/or someone else has taken it.\n                case ResponseCode.InvalidToken:\n                case ResponseCode.LeaseNotAvailable:\n                    {\n                        _myQueues.RemoveAt(i);\n                        allRenewed = false;\n                        LogWarningFailedToRenewLeaseReason(Logger, result.FailureException, result.AcquiredLease.ResourceKey, result.StatusCode);\n                        break;\n                    }\n                default:\n                    {\n                        _myQueues.RemoveAt(i);\n                        allRenewed = false;\n                        LogErrorUnexpectedRenewLease(Logger, result.FailureException, result.AcquiredLease.ResourceKey, result.StatusCode);\n                        break;\n                    }\n            }\n        }\n\n        LogDebugRenewedLeases(Logger, _myQueues.Count);\n\n        return allRenewed;\n    }\n\n    private Task NotifyOnChange(HashSet<QueueId> oldQueues)\n    {\n        if (Cancellation.IsCancellationRequested) return Task.CompletedTask;\n        var newQueues = new HashSet<QueueId>(_myQueues.Select(queue => queue.QueueId));\n\n        // If queue changed, notify listeners.\n        return !oldQueues.SetEquals(newQueues)\n            ? NotifyListeners()\n            : Task.CompletedTask;\n    }\n\n    /// <inheritdoc/>\n    protected override void OnClusterMembershipChange(HashSet<SiloAddress> activeSilos)\n    {\n        if (Cancellation.IsCancellationRequested) return;\n        ScheduleUpdateResponsibilities(activeSilos).Ignore();\n    }\n\n    private async Task ScheduleUpdateResponsibilities(HashSet<SiloAddress> activeSilos)\n    {\n        if (Cancellation.IsCancellationRequested) return;\n\n        try\n        {\n            await _executor.AddNext(() => UpdateResponsibilities(activeSilos));\n        }\n        catch (Exception ex)\n        {\n            Logger.LogError(ex, \"Error updating lease responsibilities.\");\n        }\n    }\n\n    /// <summary>\n    /// Checks to see if this balancer should be greedy, which means it attempts to grab one\n    ///   more queue than the non-greedy balancers.\n    /// </summary>\n    /// <param name=\"overflow\">number of free queues, assuming all balancers meet their minimum responsibilities</param>\n    /// <param name=\"activeSilos\">number of active silos hosting queues</param>\n    /// <returns>bool - true indicates that the balancer should try to acquire one\n    ///   more queue than the non-greedy balancers</returns>\n    private bool ShouldBeGreedy(int overflow, HashSet<SiloAddress> activeSilos)\n    {\n        // If using multiple stream providers, this will select the same silos to be greedy for\n        //   all providers, aggravating imbalance as stream provider count increases.\n        return activeSilos.OrderBy(silo => silo)\n                          .Take(overflow)\n                          .Contains(SiloAddress);\n    }\n\n    private async Task UpdateResponsibilities(HashSet<SiloAddress> activeSilos)\n    {\n        if (Cancellation.IsCancellationRequested) return;\n        var activeSiloCount = Math.Max(1, activeSilos.Count);\n        _responsibility = _allQueuesCount / activeSiloCount;\n        var overflow = _allQueuesCount % activeSiloCount;\n        if (overflow != 0 && ShouldBeGreedy(overflow, activeSilos))\n        {\n            _responsibility++;\n        }\n\n        LogDebugUpdatingResponsibilities(Logger, _allQueuesCount, activeSiloCount, _responsibility, _myQueues.Count);\n\n        if (_myQueues.Count < _responsibility && _leaseAcquisitionTimer.Period == Timeout.InfiniteTimeSpan)\n        {\n            // Ensure the acquisition timer is running.\n            _leaseAcquisitionTimer.Period = _options.LeaseAcquisitionPeriod;\n        }\n\n        _leaseMaintenanceTimer.Period = _options.LeaseRenewPeriod;\n        await AcquireLeasesToMeetResponsibility();\n    }\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"ReleaseLeasesToMeetResponsibility. QueueCount: {QueueCount}, Responsibility: {Responsibility}\"\n    )]\n    private static partial void LogTraceReleaseLeasesToMeetResponsibility(ILogger logger, int queueCount, int responsibility);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Released leases for {QueueCount} queues. Holding leases for {HoldingQueueCount} of an expected {MinQueueCount} queues.\"\n    )]\n    private static partial void LogDebugReleasedLeases(ILogger logger, int queueCount, int holdingQueueCount, int minQueueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"AcquireLeasesToMeetExpectation. QueueCount: {QueueCount}, ExpectedTotalLeaseCount: {ExpectedTotalLeaseCount}\"\n    )]\n    private static partial void LogTraceAcquireLeasesToMeetExpectation(ILogger logger, int queueCount, int expectedTotalLeaseCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Holding leased for {QueueCount} queues. Trying to acquire {acquireQueueCount} queues to reach {TargetQueueCount} of a possible {PossibleLeaseCount}\"\n    )]\n    private static partial void LogDebugHoldingLeased(ILogger logger, int queueCount, int acquireQueueCount, int targetQueueCount, int possibleLeaseCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to acquire lease {LeaseKey} due to transient error.\"\n    )]\n    private static partial void LogWarningFailedToAcquireLeaseTransient(ILogger logger, Exception exception, string leaseKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Failed to acquire lease {LeaseKey} due to {Reason}.\"\n    )]\n    private static partial void LogDebugFailedToAcquireLeaseNotAvailable(ILogger logger, Exception exception, string leaseKey, ResponseCode reason);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Failed to acquire acquire {LeaseKey} unexpected invalid token.\"\n    )]\n    private static partial void LogErrorFailedToAcquireLeaseInvalidToken(ILogger logger, Exception exception, string leaseKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Unexpected response to acquire request of lease {LeaseKey}. StatusCode {StatusCode}.\"\n    )]\n    private static partial void LogErrorUnexpectedAcquireLease(ILogger logger, Exception exception, string leaseKey, ResponseCode statusCode);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Holding leased for {QueueCount} queues. Trying to acquire {acquireQueueCount} queues to reach {TargetQueueCount} of a possible {PossibleLeaseCount} lease\"\n    )]\n    private static partial void LogDebugHoldingLeasedAgain(ILogger logger, int queueCount, int acquireQueueCount, int targetQueueCount, int possibleLeaseCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Holding leases for {QueueCount} of an expected {MinQueueCount} queues.\"\n    )]\n    private static partial void LogDebugHoldingLeases(ILogger logger, int queueCount, int minQueueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Trace,\n        Message = \"RenewLeases. QueueCount: {QueueCount}\"\n    )]\n    private static partial void LogTraceRenewLeases(ILogger logger, int queueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to renew lease {LeaseKey} due to transient error.\"\n    )]\n    private static partial void LogWarningFailedToRenewLeaseTransient(ILogger logger, Exception exception, string leaseKey);\n\n    [LoggerMessage(\n        Level = LogLevel.Warning,\n        Message = \"Failed to renew lease {LeaseKey} due to {Reason}.\"\n    )]\n    private static partial void LogWarningFailedToRenewLeaseReason(ILogger logger, Exception exception, string leaseKey, ResponseCode reason);\n\n    [LoggerMessage(\n        Level = LogLevel.Error,\n        Message = \"Unexpected response to renew of lease {LeaseKey}. StatusCode {StatusCode}.\"\n    )]\n    private static partial void LogErrorUnexpectedRenewLease(ILogger logger, Exception exception, string leaseKey, ResponseCode statusCode);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Renewed leases for {QueueCount} queues.\"\n    )]\n    private static partial void LogDebugRenewedLeases(ILogger logger, int queueCount);\n\n    [LoggerMessage(\n        Level = LogLevel.Debug,\n        Message = \"Updating Responsibilities for {QueueCount} queue over {SiloCount} silos. Need {MinQueueCount} queues, have {MyQueueCount}\"\n    )]\n    private static partial void LogDebugUpdatingResponsibilities(ILogger logger, int queueCount, int siloCount, int minQueueCount, int myQueueCount);\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/LeaseBasedQueueBalancerOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Config for LeaseBasedQueueBalancer. User need to configure this option in order to use LeaseBasedQueueBalancer in the\n    ///   stream provider.  Per stream provider options can be configured as named options using the same name as the provider.\n    /// </summary>\n    public class LeaseBasedQueueBalancerOptions\n    {\n        /// <summary>\n        /// Gets or sets the length of the lease.\n        /// </summary>\n        /// <value>The length of the lease.</value>\n        public TimeSpan LeaseLength { get; set; } = DefaultLeaseLength;\n\n        /// <summary>\n        /// The default lease length.\n        /// </summary>\n        public static readonly TimeSpan DefaultLeaseLength = TimeSpan.FromSeconds(60);\n\n        /// <summary>\n        /// Gets or sets the lease renew period.\n        /// </summary>\n        /// <value>The lease renew period.</value>\n        public TimeSpan LeaseRenewPeriod { get; set; } = DefaultLeaseRenewPeriod;\n\n        /// <summary>\n        /// The default lease renew period\n        /// </summary>\n        /// <remarks>\n        /// <see cref=\"DefaultLeaseRenewPeriod\"/> set to (<see cref=\"DefaultLeaseLength\"/>/2 - 1) to allow time for at least 2 renew calls before we lose the lease.        \n        /// </remarks>\n        public static readonly TimeSpan DefaultLeaseRenewPeriod = TimeSpan.FromSeconds(29); \n\n        /// <summary>\n        /// Gets or sets how often balancer attempts to acquire leases.\n        /// </summary>\n        public TimeSpan LeaseAcquisitionPeriod { get; set; } = DefaultMinLeaseAcquisitionPeriod;\n\n        /// <summary>\n        /// Gets or sets how often balancer attempts to acquire leases.\n        /// </summary>\n        [Obsolete($\"Use {nameof(LeaseAcquisitionPeriod)} instead.\", error: true)]\n        public TimeSpan LeaseAquisitionPeriod { get => LeaseAcquisitionPeriod; set => LeaseAcquisitionPeriod = value; }\n\n        /// <summary>\n        /// The default minimum lease acquisition period.\n        /// </summary>\n        public static readonly TimeSpan DefaultMinLeaseAcquisitionPeriod = TimeSpan.FromSeconds(30);\n\n        /// <summary>\n        /// The default minimum lease acquisition period.\n        /// </summary>\n        [Obsolete($\"Use {nameof(DefaultMinLeaseAcquisitionPeriod)} instead.\", error: true)]\n        public static readonly TimeSpan DefaultMinLeaseAquisitionPeriod = DefaultMinLeaseAcquisitionPeriod;\n\n        /// <summary>\n        /// Gets or sets the lease category, allows for more fine grain partitioning of leases.\n        /// </summary>\n        public string LeaseCategory { get; set; } = DefaultLeaseCategory;\n\n        /// <summary>\n        /// The default lease category\n        /// </summary>\n        public const string DefaultLeaseCategory = \"QueueBalancer\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/PersistentStreamConfiguratorExtension.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"ISiloPersistentStreamConfigurator\"/>.\n    /// </summary>\n    public static class SiloPersistentStreamConfiguratorExtension\n    {\n        /// <summary>\n        /// Configures the stream provider to use the consistent ring queue balancer.\n        /// </summary>\n        /// <param name=\"configurator\">The confiurator.</param>\n        public static void UseConsistentRingQueueBalancer(this ISiloPersistentStreamConfigurator configurator)\n        {\n            configurator.ConfigurePartitionBalancing(ConsistentRingQueueBalancer.Create);\n        }\n\n        /// <summary>\n        /// Configures the stream provider to use the static cluster configuration deployment balancer.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"siloMaturityPeriod\">The silo maturity period.</param>\n        public static void UseStaticClusterConfigDeploymentBalancer(\n            this ISiloPersistentStreamConfigurator configurator, \n            TimeSpan? siloMaturityPeriod = null)\n        {\n            configurator.ConfigurePartitionBalancing<DeploymentBasedQueueBalancerOptions>(\n                (s, n) => DeploymentBasedQueueBalancer.Create(s, n, s.GetRequiredService<IOptions<StaticClusterDeploymentOptions>>().Value),\n                options => options.Configure(op =>\n                {\n                    op.IsFixed = true;\n                    if (siloMaturityPeriod.HasValue)\n                        op.SiloMaturityPeriod = siloMaturityPeriod.Value;\n                }));\n        }\n\n        /// <summary>\n        /// Configures the stream provider to use the dynamic cluster configuration deployment balancer.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"siloMaturityPeriod\">The silo maturity period.</param>\n        public static void UseDynamicClusterConfigDeploymentBalancer(\n            this ISiloPersistentStreamConfigurator configurator,\n            TimeSpan? siloMaturityPeriod = null)\n        {\n            configurator.ConfigurePartitionBalancing<DeploymentBasedQueueBalancerOptions>(\n                (s, n) => DeploymentBasedQueueBalancer.Create(s, n, s.GetRequiredService<IOptions<StaticClusterDeploymentOptions>>().Value),\n                options => options.Configure(op =>\n                {\n                    op.IsFixed = false;\n                    if (siloMaturityPeriod.HasValue)\n                        op.SiloMaturityPeriod = siloMaturityPeriod.Value;\n                }));\n        }\n\n        /// <summary>\n        /// Configures the stream provider to use the lease based queue balancer.\n        /// </summary>\n        /// <param name=\"configurator\">The configuration builder.</param>\n        /// <param name=\"configureOptions\">The configure options.</param>\n        public static void UseLeaseBasedQueueBalancer(this ISiloPersistentStreamConfigurator configurator, \n            Action<OptionsBuilder<LeaseBasedQueueBalancerOptions>> configureOptions = null)\n        {\n            configurator.ConfigurePartitionBalancing((s, n) => LeaseBasedQueueBalancer.Create(s, n),\n                configureOptions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/QueueBalancerBase.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Internal;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Base class for StreamQueueBalancer\n    /// </summary>\n    public abstract partial class QueueBalancerBase : IStreamQueueBalancer\n    {\n        private readonly IAsyncEnumerable<ClusterMembershipSnapshot> clusterMembershipUpdates;\n        private readonly List<IStreamQueueBalanceListener> queueBalanceListeners;\n        private readonly CancellationTokenSource cts;\n        private Task _listenForClusterChangesTask;\n\n        protected CancellationToken Cancellation => this.cts.Token;\n\n        protected SiloAddress SiloAddress { get; }\n\n        protected ILogger Logger { get; }\n\n        protected QueueBalancerBase(IServiceProvider sp, ILogger logger)\n            : this(sp.GetRequiredService<IClusterMembershipService>(), sp.GetRequiredService<ILocalSiloDetails>(), logger)\n        {\n        }\n\n        /// <summary>\n        /// This should be primary constructor once IAsyncEnumerable is released\n        /// </summary>\n        private QueueBalancerBase(IClusterMembershipService clusterMembership, ILocalSiloDetails localSiloDetails, ILogger logger)\n        {\n            this.clusterMembershipUpdates = clusterMembership.MembershipUpdates;\n            this.SiloAddress = localSiloDetails.SiloAddress;\n            this.Logger = logger;\n            this.queueBalanceListeners = new List<IStreamQueueBalanceListener>();\n            this.cts = new CancellationTokenSource();\n        }\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<QueueId> GetMyQueues();\n\n        /// <inheritdoc/>\n        public virtual Task Initialize(IStreamQueueMapper queueMapper)\n        {\n            using var _ = new ExecutionContextSuppressor();\n            _listenForClusterChangesTask = ListenForClusterChanges();\n            return Task.CompletedTask;\n        }\n\n        public virtual async Task Shutdown()\n        {\n            try\n            {\n                this.cts.Cancel(throwOnFirstException: false);\n            }\n            catch (Exception exc)\n            {\n                LogErrorSignalingShutdownToken(Logger, exc);\n            }\n\n            await _listenForClusterChangesTask.SuppressThrowing();\n        }\n\n        /// <inheritdoc/>\n        public bool SubscribeToQueueDistributionChangeEvents(IStreamQueueBalanceListener observer)\n        {\n            ArgumentNullException.ThrowIfNull(observer);\n            lock (this.queueBalanceListeners)\n            {\n                if (this.queueBalanceListeners.Contains(observer))\n                {\n                    return false;\n                }\n                this.queueBalanceListeners.Add(observer);\n                return true;\n            }\n        }\n        /// <inheritdoc/>\n        public bool UnSubscribeFromQueueDistributionChangeEvents(IStreamQueueBalanceListener observer)\n        {\n            ArgumentNullException.ThrowIfNull(observer);\n            lock (this.queueBalanceListeners)\n            {\n                return this.queueBalanceListeners.Remove(observer);\n            }\n        }\n\n        protected Task NotifyListeners()\n        {\n            if (this.Cancellation.IsCancellationRequested) return Task.CompletedTask;\n            List<IStreamQueueBalanceListener> queueBalanceListenersCopy;\n            lock (queueBalanceListeners)\n            {\n                queueBalanceListenersCopy = queueBalanceListeners.ToList(); // make copy\n            }\n            return Task.WhenAll(queueBalanceListenersCopy.Select(listener => listener.QueueDistributionChangeNotification()));\n        }\n\n        private async Task ListenForClusterChanges()\n        {\n            await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n            var current = new HashSet<SiloAddress>();\n            await foreach (var membershipSnapshot in this.clusterMembershipUpdates.WithCancellation(this.Cancellation))\n            {\n                try\n                {\n                    // Get active members.\n                    var update = new HashSet<SiloAddress>(membershipSnapshot.Members.Values\n                        .Where(member => member.Status == SiloStatus.Active)\n                        .Select(member => member.SiloAddress));\n\n                    // If active list has changed, track new list and notify.\n                    if (!current.SetEquals(update))\n                    {\n                        current = update;\n                        OnClusterMembershipChange(current);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogErrorProcessingClusterMembershipUpdate(Logger, exception);\n                }\n            }\n        }\n\n        protected abstract void OnClusterMembershipChange(HashSet<SiloAddress> activeSilos);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error signaling shutdown token.\"\n        )]\n        private static partial void LogErrorSignalingShutdownToken(ILogger logger, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Error processing cluster membership update.\"\n        )]\n        private static partial void LogErrorProcessingClusterMembershipUpdate(ILogger logger, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/RoundRobinSelector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Selector using round robin algorithm\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    internal sealed class RoundRobinSelector<T> : IResourceSelector<T>\n    {\n        private readonly List<T> resources;\n        private int lastSelection;\n        public RoundRobinSelector(IEnumerable<T> resources)\n        {\n            // distinct randomly ordered readonly collection\n            this.resources = resources.Distinct().OrderBy(_ => Random.Shared.Next()).ToList();\n            this.lastSelection = Random.Shared.Next(this.resources.Count);\n        }\n\n        public int Count => this.resources.Count;\n\n        /// <summary>\n        /// Try to select certain count of resources from resource list, which doesn't overlap with existing resources\n        /// </summary>\n        /// <param name=\"newSelectionCount\"></param>\n        /// <param name=\"existingSelection\"></param>\n        /// <returns></returns>\n        public List<T> NextSelection(int newSelectionCount, List<T> existingSelection)\n        {\n            var selection = new List<T>(Math.Min(newSelectionCount, this.resources.Count));\n            int tries = 0;\n            while (selection.Count < newSelectionCount && tries++ < this.resources.Count)\n            {\n                this.lastSelection = (++this.lastSelection) % (this.resources.Count);\n                if (!existingSelection.Contains(this.resources[this.lastSelection]))\n                    selection.Add(this.resources[this.lastSelection]);\n            }\n            return selection;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueBalancer/StaticClusterDeploymentConfiguration.cs",
    "content": "using System.Collections.Generic;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Deployment configuration that reads from orleans cluster configuration\n    /// </summary>\n    public class StaticClusterDeploymentOptions : IDeploymentConfiguration\n    {\n        /// <summary>\n        /// Gets or sets the silo names.\n        /// </summary>\n        /// <value>The silo names.</value>\n        public IList<string> SiloNames { get; set; } = new List<string>();\n\n        /// <inheritdoc/>\n        IList<string> IDeploymentConfiguration.GetAllSiloNames()\n        {\n            return this.SiloNames;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/QueueId.cs",
    "content": "using System;\n\n#nullable enable\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Identifier of a durable queue.\n    /// Used by Orleans streaming extensions.\n    /// </summary>\n    [Serializable]\n    [Immutable]\n    [GenerateSerializer]\n    public readonly struct QueueId : IEquatable<QueueId>, IComparable<QueueId>, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly string queueNamePrefix;\n        [Id(1)]\n        private readonly uint queueId;\n        [Id(2)]\n        private readonly uint uniformHashCache;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"QueueId\"/> class.\n        /// </summary>\n        /// <param name=\"queuePrefix\">The queue prefix.</param>\n        /// <param name=\"id\">The identifier.</param>\n        /// <param name=\"hash\">The hash.</param>\n        private QueueId(string queuePrefix, uint id, uint hash)\n        {\n            queueNamePrefix = queuePrefix ?? throw new ArgumentNullException(nameof(queuePrefix));\n            queueId = id;\n            uniformHashCache = hash;\n        }\n\n        /// <summary>\n        /// Gets the queue identifier.\n        /// </summary>\n        /// <param name=\"queueName\">Name of the queue.</param>\n        /// <param name=\"queueId\">The queue identifier.</param>\n        /// <param name=\"hash\">The hash.</param>\n        /// <returns>The queue identifier.</returns>\n        public static QueueId GetQueueId(string queueName, uint queueId, uint hash) => new(queueName, queueId, hash);\n\n        /// <summary>\n        /// Gets the queue name prefix.\n        /// </summary>\n        /// <returns>The queue name prefix.</returns>\n        public string GetStringNamePrefix() => queueNamePrefix;\n\n        /// <summary>\n        /// Gets the numeric identifier.\n        /// </summary>\n        /// <returns>The numeric identifier.</returns>\n        public uint GetNumericId() => queueId;\n\n        /// <inheritdoc/>\n        public uint GetUniformHashCode() => uniformHashCache;\n\n        /// <summary>\n        /// Gets a value indicating whether the instance is the default instance.\n        /// </summary>\n        public bool IsDefault => queueNamePrefix is null;\n\n        /// <inheritdoc/>\n        public int CompareTo(QueueId other)\n        {\n            if (queueId != other.queueId)\n                return queueId.CompareTo(other.queueId);\n\n            var cmp = string.CompareOrdinal(queueNamePrefix, other.queueNamePrefix);\n            if (cmp != 0) return cmp;\n\n            return uniformHashCache.CompareTo(other.uniformHashCache);\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(QueueId other) => queueId == other.queueId && uniformHashCache == other.uniformHashCache && queueNamePrefix == other.queueNamePrefix;\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is QueueId queueId && Equals(queueId);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => HashCode.Combine(queueId, uniformHashCache, queueNamePrefix);\n\n        public static bool operator ==(QueueId left, QueueId right) => left.Equals(right);\n\n        public static bool operator !=(QueueId left, QueueId right) => !(left == right);\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{this}\";\n\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            var len = queueNamePrefix.AsSpan().ToLowerInvariant(destination);\n            if (len >= 0 && destination[len..].TryWrite($\"-{queueId}\", out var len2))\n            {\n                len += len2;\n\n                if (format.Length == 1 && format[0] == 'H')\n                {\n                    if (!destination[len..].TryWrite($\"-0x{uniformHashCache:X8}\", out len2))\n                    {\n                        charsWritten = 0;\n                        return false;\n                    }\n                    len += len2;\n                }\n\n                charsWritten = len;\n                return true;\n            }\n\n            charsWritten = 0;\n            return false;\n        }\n\n        /// <summary>\n        /// Returns a string representation of this instance which includes its uniform hash code.\n        /// </summary>\n        /// <returns>A string representation of this instance which includes its uniform hash code.</returns>\n        public string ToStringWithHashCode() => $\"{this:H}\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/SiloPersistentStreamConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.Streams;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Validates <see cref=\"StreamPubSubOptions\"/>.\n    /// </summary>\n    public class PersistentStreamStorageConfigurationValidator : IConfigurationValidator\n    {\n        private readonly IServiceProvider services;\n        private readonly string streamProviderName;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"PersistentStreamStorageConfigurationValidator\"/> class.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"streamProviderName\">Name of the stream provider.</param>\n        private PersistentStreamStorageConfigurationValidator(IServiceProvider services, string streamProviderName)\n        {\n            this.services = services;\n            this.streamProviderName = streamProviderName;\n        }\n\n        /// <inheritdoc/>\n        public void ValidateConfiguration()\n        {\n            var pubsubOptions = services.GetOptionsByName<StreamPubSubOptions>(this.streamProviderName);\n            if (pubsubOptions.PubSubType == StreamPubSubType.ExplicitGrainBasedAndImplicit || pubsubOptions.PubSubType == StreamPubSubType.ExplicitGrainBasedOnly)\n            {\n                var pubsubStore = services.GetKeyedService<IGrainStorage>(this.streamProviderName) ?? services.GetKeyedService<IGrainStorage>(ProviderConstants.DEFAULT_PUBSUB_PROVIDER_NAME);\n                if (pubsubStore == null)\n                    throw new OrleansConfigurationException(\n                        $\" Streams with pubsub type {StreamPubSubType.ExplicitGrainBasedAndImplicit} and {StreamPubSubType.ExplicitGrainBasedOnly} requires a grain storage named \" +\n                        $\"{ProviderConstants.DEFAULT_PUBSUB_PROVIDER_NAME} or {this.streamProviderName} to be configured with silo. Please configure one for your stream {streamProviderName}.\");\n            }\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"PersistentStreamStorageConfigurationValidator\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The name.</param>\n        /// <returns>The newly created instance.</returns>\n        public static IConfigurationValidator Create(IServiceProvider services, string name)\n        {\n            return new PersistentStreamStorageConfigurationValidator(services, name);\n        }\n    }\n\n    /// <summary>\n    /// Configures persistent streams.\n    /// </summary>\n    public class SiloPersistentStreamConfigurator : NamedServiceConfigurator, ISiloPersistentStreamConfigurator\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SiloPersistentStreamConfigurator\"/> class.\n        /// </summary>\n        /// <param name=\"name\">The stream provider name.</param>\n        /// <param name=\"configureDelegate\">The configuration delegate.</param>\n        /// <param name=\"adapterFactory\">The adapter factory.</param>\n        public SiloPersistentStreamConfigurator(string name, Action<Action<IServiceCollection>> configureDelegate, Func<IServiceProvider, string, IQueueAdapterFactory> adapterFactory)\n            : base(name, configureDelegate)\n        {\n            this.ConfigureDelegate(services => services.AddSiloStreaming());\n            this.ConfigureComponent(PersistentStreamProvider.Create);\n            this.ConfigureComponent((s,n) => s.GetRequiredKeyedService<IStreamProvider>(n) as IControllable);\n            this.ConfigureDelegate(services => services.AddSingleton(sp => PersistentStreamProvider.ParticipateIn<ISiloLifecycle>(sp, this.Name)));\n            this.ConfigureComponent(adapterFactory);\n            this.ConfigureDelegate(services => services.AddSingleton(sp => PersistentStreamStorageConfigurationValidator.Create(sp, this.Name)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/StreamConsumerGrainContextAction.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams.Core;\n\nnamespace Orleans.Streams\n{\n    /// <summary>\n    /// Installs an <see cref=\"IStreamConsumerExtension\"/> extension on a <see cref=\"IGrainContext\"/> for grains which implement <see cref=\"IStreamSubscriptionObserver\"/>.\n    /// </summary>\n    internal class StreamConsumerGrainContextAction : IConfigureGrainContext\n    {\n        private readonly IStreamProviderRuntime _streamProviderRuntime;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamConsumerGrainContextAction\"/> class.\n        /// </summary>\n        /// <param name=\"streamProviderRuntime\">The stream provider runtime.</param>\n        public StreamConsumerGrainContextAction(IStreamProviderRuntime streamProviderRuntime)\n        {\n            _streamProviderRuntime = streamProviderRuntime;\n        }\n\n        /// <inheritdoc/>\n        public void Configure(IGrainContext context)\n        {\n            if (context.GrainInstance is IStreamSubscriptionObserver observer)\n            {\n                InstallStreamConsumerExtension(context, observer as IStreamSubscriptionObserver);\n            }\n        }\n\n        private void InstallStreamConsumerExtension(IGrainContext context, IStreamSubscriptionObserver observer)\n        {\n            _streamProviderRuntime.BindExtension<StreamConsumerExtension, IStreamConsumerExtension>(() => new StreamConsumerExtension(_streamProviderRuntime, observer));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming/StreamId.cs",
    "content": "using System;\nusing System.Buffers.Text;\nusing System.Diagnostics;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing Orleans.Streams;\n\n#nullable enable\nnamespace Orleans.Runtime\n{\n    /// <summary>\n    /// Identifies a Stream within a provider\n    /// </summary>\n    [Immutable]\n    [Serializable]\n    [GenerateSerializer]\n    public readonly struct StreamId : IEquatable<StreamId>, IComparable<StreamId>, ISerializable, ISpanFormattable\n    {\n        [Id(0)]\n        private readonly byte[] fullKey;\n\n        [Id(1)]\n        private readonly ushort keyIndex;\n\n        [Id(2)]\n        private readonly int hash;\n\n        /// <summary>\n        /// Gets the full key.\n        /// </summary>\n        /// <value>The full key.</value>\n        public ReadOnlyMemory<byte> FullKey => fullKey;\n\n        /// <summary>\n        /// Gets the namespace.\n        /// </summary>\n        /// <value>The namespace.</value>\n        public ReadOnlyMemory<byte> Namespace => fullKey.AsMemory(0, this.keyIndex);\n\n        /// <summary>\n        /// Gets the key.\n        /// </summary>\n        /// <value>The key.</value>\n        public ReadOnlyMemory<byte> Key => fullKey.AsMemory(this.keyIndex);\n\n        private StreamId(byte[] fullKey, ushort keyIndex, int hash)\n        {\n            this.fullKey = fullKey;\n            this.keyIndex = keyIndex;\n            this.hash = hash;\n        }\n\n        internal StreamId(byte[] fullKey, ushort keyIndex)\n            : this(fullKey, keyIndex, (int)StableHash.ComputeHash(fullKey))\n        {\n        }\n\n        private StreamId(SerializationInfo info, StreamingContext context)\n        {\n            fullKey = (byte[])info.GetValue(\"fk\", typeof(byte[]))!;\n            this.keyIndex = info.GetUInt16(\"ki\");\n            this.hash = info.GetInt32(\"fh\");\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static StreamId Create(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> key)\n        {\n            if (key.IsEmpty)\n                throw new ArgumentNullException(nameof(key));\n\n            if (!ns.IsEmpty)\n            {\n                var fullKeysBytes = new byte[ns.Length + key.Length];\n                ns.CopyTo(fullKeysBytes.AsSpan());\n                key.CopyTo(fullKeysBytes.AsSpan(ns.Length));\n                return new(fullKeysBytes, (ushort)ns.Length);\n            }\n            else\n            {\n                return new(key.ToArray(), 0);\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static StreamId Create(string ns, Guid key)\n        {\n            if (ns is null)\n            {\n                var buf = new byte[32];\n                Utf8Formatter.TryFormat(key, buf, out var len, 'N');\n                Debug.Assert(len == 32);\n                return new StreamId(buf, 0);\n            }\n            else\n            {\n                var nsLen = Encoding.UTF8.GetByteCount(ns);\n                var buf = new byte[nsLen + 32];\n                Encoding.UTF8.GetBytes(ns, 0, ns.Length, buf, 0);\n                Utf8Formatter.TryFormat(key, buf.AsSpan(nsLen), out var len, 'N');\n                Debug.Assert(len == 32);\n                return new StreamId(buf, (ushort)nsLen);\n            }\n        }\n        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static StreamId Create(string ns, long key) => Create(ns, key.ToString());\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamId\"/> struct.\n        /// </summary>\n        /// <param name=\"ns\">The namespace.</param>\n        /// <param name=\"key\">The key.</param>\n        public static StreamId Create(string ns, string key)\n        {\n            if (ns is null)\n                return new StreamId(Encoding.UTF8.GetBytes(key), 0);\n\n            var nsLen = Encoding.UTF8.GetByteCount(ns);\n            var keyLen = Encoding.UTF8.GetByteCount(key);\n            var buf = new byte[nsLen + keyLen];\n            Encoding.UTF8.GetBytes(ns, 0, ns.Length, buf, 0);\n            Encoding.UTF8.GetBytes(key, 0, key.Length, buf, nsLen);\n            return new StreamId(buf, (ushort)nsLen);\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"StreamId\"/> struct.\n        /// </summary>\n        /// <param name=\"streamIdentity\">The stream identity.</param>\n        public static StreamId Create(IStreamIdentity streamIdentity) => Create(streamIdentity.Namespace, streamIdentity.Guid);\n\n        /// <inheritdoc/>\n        public int CompareTo(StreamId other) => fullKey.AsSpan().SequenceCompareTo(other.fullKey);\n\n        /// <inheritdoc/>\n        public bool Equals(StreamId other) => fullKey.AsSpan().SequenceEqual(other.fullKey);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is StreamId other ? this.Equals(other) : false;\n\n        /// <summary>\n        /// Compares two <see cref=\"StreamId\"/> instances for equality.\n        /// </summary>\n        /// <param name=\"s1\">The first stream identity.</param>\n        /// <param name=\"s2\">The second stream identity.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator ==(StreamId s1, StreamId s2) => s1.Equals(s2);\n\n        /// <summary>\n        /// Compares two <see cref=\"StreamId\"/> instances for equality.\n        /// </summary>\n        /// <param name=\"s1\">The first stream identity.</param>\n        /// <param name=\"s2\">The second stream identity.</param>\n        /// <returns>The result of the operator.</returns>\n        public static bool operator !=(StreamId s1, StreamId s2) => !s2.Equals(s1);\n\n        /// <inheritdoc/>\n        public void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            info.AddValue(\"fk\", fullKey);\n            info.AddValue(\"ki\", this.keyIndex);\n            info.AddValue(\"fh\", this.hash);\n        }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{this}\";\n        string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString();\n\n        bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)\n        {\n            var len = Encoding.UTF8.GetCharCount(fullKey);\n            if (keyIndex == 0)\n            {\n                if (destination.Length >= len + 5)\n                {\n                    \"null/\".CopyTo(destination);\n                    charsWritten = Encoding.UTF8.GetChars(fullKey, destination[5..]) + 5;\n                    return true;\n                }\n            }\n            else if (destination.Length > len)\n            {\n                len = Encoding.UTF8.GetChars(fullKey.AsSpan(0, keyIndex), destination);\n                destination[len++] = '/';\n                charsWritten = Encoding.UTF8.GetChars(fullKey.AsSpan(keyIndex), destination[len..]) + len;\n                return true;\n            }\n\n            charsWritten = 0;\n            return false;\n        }\n\n        /// <summary>\n        /// Parses a <see cref=\"StreamId\"/> instance from a <see cref=\"string\"/>.\n        /// </summary>\n        /// <param name=\"value\">The UTF-8 encoded value.</param>\n        /// <returns>The parsed stream identity.</returns>\n        public static StreamId Parse(ReadOnlySpan<byte> value)\n        {\n            var i = value.IndexOf((byte)'/');\n            if (i < 0)\n            {\n                throw new ArgumentException($\"Unable to parse \\\"{Encoding.UTF8.GetString(value)}\\\" as a stream id\");\n            }\n\n            return Create(value[..i], value[(i + 1)..]);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => this.hash;\n\n        internal uint GetUniformHashCode() => (uint)hash;\n\n        internal uint GetKeyIndex() => keyIndex;\n\n        /// <summary>\n        /// Returns the <see cref=\"Key\"/> component of this instance as a string.\n        /// </summary>\n        /// <returns>The key component of this instance.</returns>\n        public string GetKeyAsString() => Encoding.UTF8.GetString(fullKey, keyIndex, fullKey.Length - keyIndex);\n\n        /// <summary>\n        /// Returns the <see cref=\"Namespace\"/> component of this instance as a string.\n        /// </summary>\n        /// <returns>The namespace component of this instance.</returns>\n        public string? GetNamespace() => keyIndex == 0 ? null : Encoding.UTF8.GetString(fullKey, 0, keyIndex);\n\n        internal IdSpan GetKeyIdSpan() => keyIndex == 0 ? IdSpan.UnsafeCreate(fullKey, hash) : new(fullKey.AsSpan(keyIndex).ToArray());\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.Abstractions/Orleans.Streaming.Abstractions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Streaming.Abstractions</PackageId>\n    <Title>Microsoft Orleans Streaming Abstractions</Title>\n    <Description>Streaming abstractions library for Microsoft Orleans</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <RootNamespace>Orleans</RootNamespace>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Streaming.Abstractions/Properties/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Hosting/ClientBuilderExtensions.cs",
    "content": "using System;\nusing Orleans.Hosting;\nusing Orleans.Streaming.NATS.Hosting;\n\nnamespace Orleans.Streaming.NATS.Hosting;\n\npublic static class ClientBuilderExtensions\n{\n    /// <summary>\n    /// Configure cluster client to use NATS persistent streams with default settings\n    /// </summary>\n    public static IClientBuilder AddNatsStreams(this IClientBuilder builder, string name,\n        Action<NatsOptions> configureOptions)\n    {\n        builder.AddNatsStreams(name, b =>\n            b.ConfigureNats(ob => ob.Configure(configureOptions)));\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure cluster client to use NATS persistent streams.\n    /// </summary>\n    public static IClientBuilder AddNatsStreams(this IClientBuilder builder, string name,\n        Action<ClusterClientNatsStreamConfigurator>? configure)\n    {\n        var configurator = new ClusterClientNatsStreamConfigurator(name, builder);\n        configure?.Invoke(configurator);\n        return builder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Hosting/NatsStreamConfigurator.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Configuration;\n\nnamespace Orleans.Streaming.NATS.Hosting;\n\npublic class SiloNatsStreamConfigurator : SiloPersistentStreamConfigurator\n{\n    public SiloNatsStreamConfigurator(string name, Action<Action<IServiceCollection>> configureServicesDelegate)\n        : base(name, configureServicesDelegate, NatsAdapterFactory.Create)\n    {\n        this.ConfigureDelegate(services =>\n        {\n            services\n                .ConfigureNamedOptionForLogging<NatsOptions>(name)\n                .ConfigureNamedOptionForLogging<SimpleQueueCacheOptions>(name)\n                .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name)\n                .AddTransient<IConfigurationValidator>(sp => new NatsStreamOptionsValidator(sp.GetRequiredService<IOptionsMonitor<NatsOptions>>().Get(name), name));\n        });\n    }\n\n    public SiloNatsStreamConfigurator ConfigureNats(Action<OptionsBuilder<NatsOptions>> configureOptions)\n    {\n        this.Configure(configureOptions);\n        return this;\n    }\n\n    public SiloNatsStreamConfigurator ConfigureCache(int cacheSize = SimpleQueueCacheOptions.DEFAULT_CACHE_SIZE)\n    {\n        this.Configure<SimpleQueueCacheOptions>(ob => ob.Configure(options => options.CacheSize = cacheSize));\n        return this;\n    }\n\n    public SiloNatsStreamConfigurator ConfigurePartitioning(\n        int numOfparitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n    {\n        this.Configure<HashRingStreamQueueMapperOptions>(ob =>\n            ob.Configure(options => options.TotalQueueCount = numOfparitions));\n        return this;\n    }\n}\n\npublic class ClusterClientNatsStreamConfigurator : ClusterClientPersistentStreamConfigurator\n{\n    public ClusterClientNatsStreamConfigurator(string name, IClientBuilder builder)\n        : base(name, builder, NatsAdapterFactory.Create)\n    {\n        builder\n            .ConfigureServices(services =>\n            {\n                services\n                    .ConfigureNamedOptionForLogging<NatsOptions>(name)\n                    .ConfigureNamedOptionForLogging<HashRingStreamQueueMapperOptions>(name)\n                    .AddTransient<IConfigurationValidator>(sp => new NatsStreamOptionsValidator(sp.GetRequiredService<IOptionsMonitor<NatsOptions>>().Get(name), name));\n            });\n    }\n\n    public ClusterClientNatsStreamConfigurator ConfigureNats(Action<OptionsBuilder<NatsOptions>> configureOptions)\n    {\n        this.Configure(configureOptions);\n        return this;\n    }\n\n    public ClusterClientNatsStreamConfigurator ConfigurePartitioning(\n        int numOfparitions = HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES)\n    {\n        this.Configure<HashRingStreamQueueMapperOptions>(ob =>\n            ob.Configure(options => options.TotalQueueCount = numOfparitions));\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Hosting/SiloBuilderExtensions.cs",
    "content": "using System;\nusing Orleans.Hosting;\n\nnamespace Orleans.Streaming.NATS.Hosting;\n\npublic static class SiloBuilderExtensions\n{\n    /// <summary>\n    /// Configure silo to use NATS persistent streams.\n    /// </summary>\n    public static ISiloBuilder AddNatsStreams(this ISiloBuilder builder, string name,\n        Action<NatsOptions> configureOptions)\n    {\n        builder.AddNatsStreams(name, b =>\n            b.ConfigureNats(ob => ob.Configure(configureOptions)));\n        return builder;\n    }\n\n    /// <summary>\n    /// Configure silo to use NATS persistent streams.\n    /// </summary>\n    public static ISiloBuilder AddNatsStreams(this ISiloBuilder builder, string name,\n        Action<SiloNatsStreamConfigurator>? configure)\n    {\n        var configurator = new SiloNatsStreamConfigurator(name,\n            configureServicesDelegate => builder.ConfigureServices(configureServicesDelegate));\n        configure?.Invoke(configurator);\n        return builder;\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming.NATS/NatsOptions.cs",
    "content": "﻿using System.Text.Json;\nusing Orleans.Runtime;\nusing NATS.Client.Core;\n\nnamespace Orleans.Streaming.NATS;\n\n/// <summary>\n/// Configuration options for the NATS JetStream stream provider\n/// </summary>\npublic class NatsOptions\n{\n    /// <summary>\n    /// The NATS JetStream stream name\n    /// </summary>\n    public string StreamName { get; set; } = default!;\n\n    /// <summary>\n    /// Configuration options for the NATS client.\n    /// If not provided, a default client will be created with the name Orleans-{providerName}\n    /// and will connect to the NATS server at localhost:4222\n    /// </summary>\n    public NatsOpts? NatsClientOptions { get; set; }\n\n    /// <summary>\n    /// The maximum number of messages to fetch in a single batch.\n    /// Defaults to 100.\n    /// </summary>\n    public int BatchSize { get; set; } = 100;\n\n    /// <summary>\n    /// The number of partitions in the stream.\n    /// This determines the number of pooling agents that will be created on this Orleans Cluster.\n    /// This is mapped to a deterministic partitioning scheme of the NATS JetStream stream.\n    /// The partitions are mapped from <remarks>\"[Provider-Name].*.*\"</remarks> to <remarks>\"[Provider-Name].{{partition([PartitionCount],1,2)}}.{{wildcard(1)}}.{{wildcard(2)}}\"</remarks>.\n    /// For details on how partitioning works in NATS JetStream, see <see ref=\"https://docs.nats.io/nats-concepts/subject_mapping#deterministic-subject-token-partitioning\"/>\n    /// Defaults to 8. Increase it if you need more parallelism.\n    /// <remarks>\n    /// Deterministic partition scheme is a NATS server construct.\n    /// This provider when started at the first time will create the stream with the partition scheme.\n    /// If you need to change the partition count, you need to modify the value of this property and, you need to manually modify it on NATS Server first since the provider will not make updates to the JetStream stream definition.\n    /// </remarks>\n    /// </summary>\n    public int PartitionCount { get; set; } = 8;\n\n    /// <summary>\n    /// The number of connections used to send stream messages to NATS JetStream.\n    /// </summary>\n    public int ProducerCount { get; set; } = 8;\n\n    /// <summary>\n    /// System.Text.Json serializer options to be used by the NATS provider.\n    /// </summary>\n    public JsonSerializerOptions? JsonSerializerOptions { get; set; }\n}\n\npublic class NatsStreamOptionsValidator(NatsOptions options, string? name = null) : IConfigurationValidator\n{\n    public void ValidateConfiguration()\n    {\n        if (string.IsNullOrWhiteSpace(options.StreamName))\n        {\n            throw new OrleansConfigurationException(\n                $\"The {nameof(NatsOptions.StreamName)} is required for the NATS stream provider '{name}'.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Orleans.Streaming.NATS.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Streaming.NATS</PackageId>\n    <Title>Microsoft Orleans NATS Streaming Provider</Title>\n    <Description>Microsoft Orleans streaming provider backed by NATS</Description>\n    <PackageTags>$(PackageTags) NATS</PackageTags>\n    <DefineConstants>$(DefineConstants);ORLEANS_NATS</DefineConstants>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Streaming.NATS</AssemblyName>\n    <RootNamespace>Orleans.Streaming.NATS</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <Nullable>enable</Nullable>\n    <VersionSuffix Condition=\"$(VersionSuffix) != ''\">$(VersionSuffix).alpha.1</VersionSuffix>\n    <VersionSuffix Condition=\"$(VersionSuffix) == ''\">alpha.1</VersionSuffix>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <PackageReference Include=\"NATS.Net\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Streaming.NATS.Tests\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsAdapter.cs",
    "content": "using System.Linq;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streaming.NATS;\n\ninternal sealed class NatsAdapter(\n    string providerName,\n    NatsOptions options,\n    ILoggerFactory loggerFactory,\n    Serializer serializer,\n    NatsConnectionManager natsConnectionManager) : IQueueAdapter\n{\n    public string Name => providerName;\n    public bool IsRewindable => false; // We will make it rewindable later\n    public StreamProviderDirection Direction => StreamProviderDirection.ReadWrite;\n\n    public IQueueAdapterReceiver CreateReceiver(QueueId queueId) =>\n        NatsQueueAdapterReceiver.Create(providerName, loggerFactory, natsConnectionManager, queueId.GetNumericId(),\n            options, serializer);\n\n    public async Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token,\n        Dictionary<string, object> requestContext)\n    {\n        var batchContainer = new NatsBatchContainer(streamId, events.Cast<object>().ToArray(), requestContext);\n        var raw = serializer.GetSerializer<NatsBatchContainer>().SerializeToArray(batchContainer);\n\n        await natsConnectionManager.EnqueueMessage(new NatsStreamMessage\n        {\n            StreamId = streamId, Payload = raw, RequestContext = requestContext\n        });\n    }\n}"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsAdapterFactory.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Streams;\nusing Orleans.Configuration;\nusing Orleans.Serialization;\nusing Orleans.Configuration.Overrides;\nusing Orleans.Providers.Streams.Common;\n\nnamespace Orleans.Streaming.NATS;\n\ninternal class NatsAdapterFactory : IQueueAdapterFactory\n{\n    private readonly string providerName;\n    private readonly NatsOptions natsOptions;\n    private readonly Serializer serializer;\n    private readonly ILoggerFactory loggerFactory;\n    private readonly HashRingBasedStreamQueueMapper streamQueueMapper;\n    private readonly IQueueAdapterCache adapterCache;\n\n    /// <summary>\n    /// Application level failure handler override.\n    /// </summary>\n    protected Func<QueueId, Task<IStreamFailureHandler>> StreamFailureHandlerFactory { private get; set; } = default!;\n\n    public NatsAdapterFactory(\n        string name,\n        NatsOptions natsOptions,\n        HashRingStreamQueueMapperOptions queueMapperOptions,\n        SimpleQueueCacheOptions cacheOptions,\n        IOptions<ClusterOptions> clusterOptions,\n        Serializer serializer,\n        ILoggerFactory loggerFactory)\n    {\n        this.providerName = name;\n        this.natsOptions = natsOptions;\n        this.serializer = serializer;\n        this.loggerFactory = loggerFactory;\n        streamQueueMapper = new HashRingBasedStreamQueueMapper(queueMapperOptions, this.providerName);\n        adapterCache = new SimpleQueueAdapterCache(cacheOptions, this.providerName, this.loggerFactory);\n    }\n\n    /// <summary> Init the factory.</summary>\n    public virtual void Init()\n    {\n        if (StreamFailureHandlerFactory == null)\n        {\n            StreamFailureHandlerFactory =\n                qid => Task.FromResult<IStreamFailureHandler>(new NoOpStreamDeliveryFailureHandler());\n        }\n    }\n\n    /// <summary>Creates the NATS based adapter.</summary>\n    public virtual async Task<IQueueAdapter> CreateAdapter()\n    {\n        var connectionManager = new NatsConnectionManager(this.providerName, this.loggerFactory, this.natsOptions);\n        await connectionManager.Initialize();\n\n        var adapter = new NatsAdapter(this.providerName, this.natsOptions, this.loggerFactory, this.serializer, connectionManager);\n\n        return adapter;\n    }\n\n    /// <summary>Creates the adapter cache.</summary>\n    public virtual IQueueAdapterCache GetQueueAdapterCache()\n    {\n        return adapterCache;\n    }\n\n    /// <summary>Creates the factory stream queue mapper.</summary>\n    public IStreamQueueMapper GetStreamQueueMapper()\n    {\n        return streamQueueMapper;\n    }\n\n    /// <summary>\n    /// Creates a delivery failure handler for the specified queue.\n    /// </summary>\n    /// <param name=\"queueId\"></param>\n    /// <returns></returns>\n    public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n    {\n        return StreamFailureHandlerFactory(queueId);\n    }\n\n    public static NatsAdapterFactory Create(IServiceProvider services, string name)\n    {\n        var natsOptions = services.GetOptionsByName<NatsOptions>(name);\n        var cacheOptions = services.GetOptionsByName<SimpleQueueCacheOptions>(name);\n        var queueMapperOptions = services.GetOptionsByName<HashRingStreamQueueMapperOptions>(name);\n        IOptions<ClusterOptions> clusterOptions = services.GetProviderClusterOptions(name);\n        var factory = ActivatorUtilities.CreateInstance<NatsAdapterFactory>(services, name, natsOptions, cacheOptions,\n            queueMapperOptions, clusterOptions);\n        factory.Init();\n        return factory;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsBatchContainer.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Text.Json.Serialization;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Orleans.Streaming.NATS;\n\n[Serializable]\n[GenerateSerializer]\n[method: JsonConstructor]\ninternal class NatsBatchContainer(\n    StreamId streamId,\n    object[] events,\n    Dictionary<string, object>? requestContext,\n    string? replyTo = null,\n    EventSequenceTokenV2 sequenceToken = default!)\n    : IBatchContainer\n{\n    [Id(0)]\n    [field: JsonPropertyName(\"sid\")]\n    public StreamId StreamId { get; } = streamId;\n\n    [Id(1)]\n    [field: JsonPropertyName(\"stk\")]\n    public StreamSequenceToken SequenceToken { get; set; } = sequenceToken;\n\n    [Id(2)]\n    [field: JsonPropertyName(\"evts\")]\n    public object[] Events { get; } = events;\n\n    [Id(3)]\n    [field: JsonPropertyName(\"ctx\")]\n    public Dictionary<string, object>? RequestContext { get; } = requestContext;\n\n    [Id(4)]\n    [field: JsonPropertyName(\"rpt\")]\n    public string? ReplyTo { get; set; } = replyTo;\n\n    public bool ImportRequestContext()\n    {\n        if (this.RequestContext is not null)\n        {\n            RequestContextExtensions.Import(this.RequestContext);\n            return true;\n        }\n\n        return false;\n    }\n\n    public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>() =>\n        this.Events.OfType<T>().Select((e, i) => Tuple.Create(e, this.SequenceToken));\n\n    public override string ToString() => $\"[NatsBatchContainer:Stream={StreamId},#Items={Events.Length}]\";\n}"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsConnectionManager.cs",
    "content": "using System;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing NATS.Client.Core;\nusing NATS.Client.JetStream;\nusing NATS.Client.JetStream.Models;\nusing NATS.Client.Serializers.Json;\n\nnamespace Orleans.Streaming.NATS;\n\n/// <summary>\n/// Wrapper around NATS and JetStream APIs\n/// </summary>\ninternal sealed class NatsConnectionManager\n{\n    private static readonly byte[] AckPayload = \"+ACK\"u8.ToArray();\n    private readonly string _providerName;\n    private readonly NatsOpts _natsClientOptions;\n    private readonly NatsConnection _natsConnection;\n    private readonly ILogger _logger;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly NatsOptions _options;\n    private readonly NatsJSContext[] _producerNatsContexts;\n    private readonly NatsJSContext _natsContext;\n\n    [GeneratedActivatorConstructor]\n    public NatsConnectionManager(string providerName, ILoggerFactory loggerFactory, NatsOptions options)\n    {\n        this._providerName = providerName;\n        this._loggerFactory = loggerFactory;\n        this._logger = this._loggerFactory.CreateLogger<NatsConnectionManager>();\n        this._options = options;\n        this._options.JsonSerializerOptions ??= new();\n        this._options.JsonSerializerOptions.TypeInfoResolverChain.Add(NatsSerializerContext.Default);\n\n        if (this._options.NatsClientOptions is null)\n        {\n            this._options.NatsClientOptions = NatsOpts.Default with\n            {\n                Name = $\"Orleans-{this._providerName}\",\n                SerializerRegistry =\n                new NatsJsonContextOptionsSerializerRegistry(this._options.JsonSerializerOptions)\n            };\n        }\n        else\n        {\n            this._options.NatsClientOptions = this._options.NatsClientOptions with\n            {\n                Name = string.IsNullOrWhiteSpace(this._options.NatsClientOptions.Name)\n                    ? $\"Orleans-{this._providerName}\"\n                    : this._options.NatsClientOptions.Name,\n                SerializerRegistry = new NatsJsonContextOptionsSerializerRegistry(this._options.JsonSerializerOptions)\n            };\n        }\n\n        this._natsClientOptions = this._options.NatsClientOptions;\n        this._natsConnection = new NatsConnection(this._natsClientOptions);\n        this._natsContext = new NatsJSContext(this._natsConnection);\n\n        this._producerNatsContexts = new NatsJSContext[this._options.ProducerCount];\n\n        for (var i = 0; i < this._options.ProducerCount; i++)\n        {\n            var producerOptions = this._natsClientOptions with { Name = $\"Orleans-{this._providerName}-Producer-{i}\" };\n            var producerConnection = new NatsConnection(producerOptions);\n            this._producerNatsContexts[i] = new NatsJSContext(producerConnection);\n        }\n    }\n\n    /// <summary>\n    /// Initialize the connection to the NATS server and check if JetStream is available\n    /// </summary>\n    public async Task Initialize(CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            await this._natsConnection.ConnectAsync();\n\n            if (this._natsConnection.ConnectionState != NatsConnectionState.Open)\n            {\n                this._logger.LogError(\"Unable to connect to NATS server {NatsServer}\", this._natsClientOptions.Url);\n                return;\n            }\n\n            if (!this._natsConnection.ServerInfo!.JetStreamAvailable)\n            {\n                this._logger.LogError(\n                    \"Unable to use {NatsServer} for Orleans Stream Provider {ProviderName}: NATS JetStream is not available\",\n                    this._natsClientOptions.Url, this._providerName);\n                return;\n            }\n\n            foreach (var producerContext in this._producerNatsContexts)\n            {\n                await producerContext.Connection.ConnectAsync();\n\n                if (producerContext.Connection.ConnectionState != NatsConnectionState.Open)\n                {\n                    this._logger.LogError(\"Unable to connect to NATS server {NatsServer}\",\n                        producerContext.Connection.Opts.Url);\n                    return;\n                }\n            }\n\n            this._logger.LogTrace(\"Connected to NATS server {NatsServer}\", this._natsClientOptions.Url);\n\n            try\n            {\n                var streamConfig = new StreamConfig(this._options.StreamName, [$\"{this._providerName}.>\"])\n                {\n                    Retention = StreamConfigRetention.Workqueue,\n                    SubjectTransform = new SubjectTransform\n                    {\n                        Src = $\"{this._providerName}.*.*\",\n                        Dest =\n                            @$\"{this._providerName}.{{{{partition({this._options.PartitionCount},1,2)}}}}.{{{{wildcard(1)}}}}.{{{{wildcard(2)}}}}\"\n                    }\n                };\n\n                await this._natsContext.CreateStreamAsync(streamConfig, cancellationToken);\n            }\n            catch (NatsJSApiException e) when (e.Error.ErrCode == 10065)\n            {\n                // ignore, stream already exists\n            }\n\n            this._logger.LogTrace(\n                \"Initialized to NATS JetStream stream {Stream} on server {NatsServer}\",\n                this._options.StreamName,\n                this._natsClientOptions.Url);\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Error initializing NATS JetStream Connection Manager\");\n            throw;\n        }\n    }\n\n    /// <summary>\n    /// Enqueue a message to NATS JetStream stream\n    /// </summary>\n    /// <param name=\"message\">The message</param>\n    /// <param name=\"cancellationToken\">Cancellation token</param>\n    public async Task EnqueueMessage(NatsStreamMessage message, CancellationToken cancellationToken = default)\n    {\n        if (this._natsContext is null)\n        {\n            this._logger.LogError(\"Unable to enqueue message: NATS context is not initialized\");\n            throw new InvalidOperationException(\"Unable to enqueue message: NATS context is not initialized\");\n        }\n\n        var ns = message.StreamId.Namespace.IsEmpty ? \"null\" : Encoding.UTF8.GetString(message.StreamId.Namespace.Span);\n        var id = Encoding.UTF8.GetString(message.StreamId.Key.Span);\n\n        var subject = $\"{this._providerName}.{ns}.{id}\";\n\n        var context = this._producerNatsContexts[Math.Abs(id.GetHashCode()) % this._producerNatsContexts.Length];\n\n        var ack = await context.TryPublishAsync(\n            subject,\n            message,\n            this._natsClientOptions.SerializerRegistry.GetSerializer<NatsStreamMessage>(),\n            cancellationToken: cancellationToken);\n\n        if (ack.Success)\n        {\n            _logger.LogTrace(\"Enqueued NATS message to subject {Subject}\", subject);\n        }\n        else\n        {\n            this._logger.LogError(ack.Error, \"Failed to enqueue NATS message to {Subject}\", subject);\n        }\n    }\n\n    /// <summary>\n    /// Create a NATS JetStream consumer\n    /// </summary>\n    /// <param name=\"partition\">The partition number</param>\n    /// <returns>A wrapper to a durable NATS JetStream stream consumer</returns>\n    public NatsStreamConsumer CreateConsumer(uint partition) =>\n        new(this._loggerFactory,\n            this._natsContext,\n            this._providerName,\n            this._options.StreamName,\n            partition,\n            this._options.BatchSize,\n            this._natsClientOptions.SerializerRegistry.GetDeserializer<NatsStreamMessage>());\n\n    /// <summary>\n    /// Acknowledge messages on a subject in a NATS JetStream stream\n    /// </summary>\n    /// <param name=\"subject\">The ReplyTo subject</param>\n    public async Task AcknowledgeMessages(string subject)\n    {\n        await this._natsConnection\n            .PublishAsync(subject, AckPayload, serializer: NatsRawSerializer<byte[]>.Default);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsQueueAdapterReceiver.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Buffers;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streams;\nusing Orleans.Serialization;\n\nnamespace Orleans.Streaming.NATS;\n\ninternal sealed class NatsQueueAdapterReceiver : IQueueAdapterReceiver\n{\n    private readonly ILogger _logger;\n    private readonly uint _partition;\n    private readonly string _providerName;\n    private readonly Serializer _serializer;\n    private long lastReadMessage;\n    private NatsConnectionManager? _nats;\n    private NatsStreamConsumer? _consumer;\n    private Task? _outstandingTask;\n\n    public static IQueueAdapterReceiver Create(string providerName, ILoggerFactory loggerFactory,\n        NatsConnectionManager connectionManager, uint partition,\n        NatsOptions options, Serializer serializer)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(providerName);\n        ArgumentNullException.ThrowIfNull(loggerFactory);\n        ArgumentNullException.ThrowIfNull(options);\n\n        return new NatsQueueAdapterReceiver(providerName, loggerFactory, partition, connectionManager, serializer);\n    }\n\n    private NatsQueueAdapterReceiver(string providerName, ILoggerFactory loggerFactory, uint partition,\n        NatsConnectionManager nats, Serializer serializer)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(providerName);\n        ArgumentNullException.ThrowIfNull(loggerFactory);\n        ArgumentNullException.ThrowIfNull(nats);\n\n        this._logger = loggerFactory.CreateLogger<NatsQueueAdapterReceiver>();\n        this._nats = nats;\n        this._partition = partition;\n        this._providerName = providerName;\n        this._serializer = serializer;\n    }\n\n    public async Task Initialize(TimeSpan timeout)\n    {\n        // If it is null, then we are shutting down\n        if (this._nats is null) return;\n\n        using var cts = new CancellationTokenSource(timeout);\n\n        this._consumer = this._nats.CreateConsumer(this._partition);\n        if (this._consumer is null)\n        {\n            this._logger.LogError(\"Unable to create consumer for partition {Partition}\", this._partition);\n            return;\n        }\n\n        await this._consumer.Initialize(cts.Token);\n    }\n\n    public async Task Shutdown(TimeSpan timeout)\n    {\n        try\n        {\n            if (this._outstandingTask is not null)\n            {\n                await this._outstandingTask;\n            }\n        }\n        finally\n        {\n            this._consumer = null;\n            this._nats = null;\n        }\n    }\n\n    public async Task<IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount)\n    {\n        try\n        {\n            if (this._nats is null || this._consumer is null)\n            {\n                this._logger.LogWarning(\n                    \"NATS provider is not initialized. Unable to get messages. If we are shutting down it is fine. Otherwise, we have a problem with initialization of the NATS stream provider {Provider} for partition {Partition}.\",\n                    this._providerName, this._partition);\n                return [];\n            }\n\n            var task = this._consumer.GetMessages(maxCount);\n            this._outstandingTask = task;\n            var (messages, messageCount) = await task;\n\n            var containers = new List<IBatchContainer>();\n\n            for (var i = 0; i < messageCount; i++)\n            {\n                var natsMessage = messages[i];\n                var container = this._serializer.Deserialize<NatsBatchContainer>(natsMessage.Payload);\n                container.SequenceToken = new EventSequenceTokenV2(lastReadMessage++);\n                container.ReplyTo = natsMessage.ReplyTo;\n\n                containers.Add(container);\n            }\n\n            ArrayPool<NatsStreamMessage?>.Shared.Return(messages);\n\n            return containers;\n        }\n        finally\n        {\n            this._outstandingTask = null;\n        }\n    }\n\n    public async Task MessagesDeliveredAsync(IList<IBatchContainer> messages)\n    {\n        if (this._nats is null || this._consumer is null)\n        {\n            this._logger.LogWarning(\n                \"NATS provider is not initialized. Unable to deliver messages. If we are shutting down it is fine. Otherwise, we have a problem with initialization of the NATS stream provider {Provider} for partition {Partition}.\",\n                this._providerName, this._partition);\n            return;\n        }\n\n        if (messages.Count == 0) return;\n\n        var tasks = new List<Task>();\n\n        foreach (var message in messages)\n        {\n            if (message is NatsBatchContainer natsMessage && !string.IsNullOrWhiteSpace(natsMessage.ReplyTo))\n            {\n                tasks.Add(this._nats.AcknowledgeMessages(natsMessage.ReplyTo));\n            }\n        }\n\n        await Task.WhenAll(tasks);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsStreamConsumer.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing NATS.Client.Core;\nusing NATS.Client.JetStream;\nusing NATS.Client.JetStream.Models;\n\nnamespace Orleans.Streaming.NATS;\n\n/// <summary>\n/// Wrapper around a NATS JetStream consumer\n/// </summary>\ninternal sealed class NatsStreamConsumer(\n    ILoggerFactory loggerFactory,\n    NatsJSContext context,\n    string provider,\n    string stream,\n    uint partition,\n    int batchSize,\n    INatsDeserialize<NatsStreamMessage> serializer)\n{\n    private readonly ILogger _logger = loggerFactory.CreateLogger<NatsStreamConsumer>();\n\n    private readonly ConsumerConfig _config = new($\"orleans-{provider}-{stream}-{partition}\")\n    {\n        FilterSubject = $\"{provider}.{partition}.>\",\n        MaxBatch = batchSize,\n        DeliverPolicy = ConsumerConfigDeliverPolicy.All,\n        MaxAckPending = batchSize\n    };\n\n    private INatsJSConsumer? _consumer;\n\n    public async Task<(NatsStreamMessage[] Messages, int Count)> GetMessages(int messageCount = 0,\n        CancellationToken cancellationToken = default)\n    {\n        if (this._consumer is null)\n        {\n            this._logger.LogError(\n                \"Internal NATS Consumer is not initialized. Provider: {Provider} | Stream: {Stream} | Partition: {Partition}.\",\n                provider, stream, partition);\n            return ([], 0);\n        }\n\n        var batchCount = messageCount > 0 && messageCount < batchSize ? messageCount : batchSize;\n        var messages = ArrayPool<NatsStreamMessage>.Shared.Rent(batchCount);\n\n        var i = 0;\n\n        await foreach (var msg in this._consumer.FetchNoWaitAsync(\n                               new NatsJSFetchOpts { MaxMsgs = batchCount, Expires = TimeSpan.FromSeconds(10) },\n                               serializer: serializer)\n                           .WithCancellation(cancellationToken))\n        {\n            var streamMessage = msg.Data;\n            if (streamMessage is null)\n            {\n                this._logger.LogWarning(\"Unable to deserialize NATS message for subject {Subject}. Ignoring...\",\n                    msg.Subject);\n                continue;\n            }\n\n            messages[i] = streamMessage;\n            messages[i].ReplyTo = msg.ReplyTo;\n            i++;\n        }\n\n        return (messages, i);\n    }\n\n    public async Task Initialize(CancellationToken cancellationToken = default)\n    {\n        var consumer =\n            await context.CreateOrUpdateConsumerAsync(stream, this._config, cancellationToken);\n\n        this._consumer = consumer;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/NatsStreamMessage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Text.Json.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streaming.NATS;\n\n[Serializable]\n[GenerateSerializer]\ninternal class NatsStreamMessage\n{\n    [Id(0)]\n    [JsonConverter(typeof(StreamIdJsonConverter))]\n    [JsonPropertyName(\"sid\")]\n    public StreamId StreamId { get; set; }\n\n    [Id(1)]\n    [JsonPropertyName(\"ctx\")]\n    public Dictionary<string, object>? RequestContext { get; set; }\n\n    [Id(2)]\n    [JsonPropertyName(\"p\")]\n    public required byte[] Payload { get; set; }\n\n    [Id(3)]\n    [JsonPropertyName(\"rpt\")]\n    public string? ReplyTo { get; set; }\n}\n\n[JsonSerializable(typeof(NatsStreamMessage))]\n[JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, WriteIndented = false)]\ninternal partial class NatsSerializerContext : JsonSerializerContext;"
  },
  {
    "path": "src/Orleans.Streaming.NATS/Providers/StreamIdJsonConverter.cs",
    "content": "using System;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Orleans.Runtime;\n\nnamespace Orleans.Streaming.NATS;\n\ninternal class StreamIdJsonConverter : JsonConverter<StreamId>\n{\n    public override StreamId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType != JsonTokenType.String)\n        {\n            throw new JsonException(\"StreamId is not a string\");\n        }\n\n        var str = reader.GetString();\n\n        if (string.IsNullOrWhiteSpace(str))\n        {\n            throw new JsonException(\"StreamId is empty\");\n        }\n\n        return StreamId.Parse(Encoding.UTF8.GetBytes(str));\n    }\n\n    public override void Write(Utf8JsonWriter writer, StreamId value, JsonSerializerOptions options) =>\n        writer.WriteStringValue(value.ToString());\n}"
  },
  {
    "path": "src/Orleans.Streaming.NATS/README.md",
    "content": "# Microsoft Orleans Stream Provider for NATS\n\n## Introduction\nMicrosoft Orleans Stream Provider for NATS enables Orleans applications to leverage NATS JetStream for reliable, scalable event processing. This provider allows you to use NATS JetStream as a streaming backbone for your Orleans application to both produce and consume streams of events.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Streaming.NATS\n```\n\n## Example - Configuring NATS Stream Provider\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Streaming.NATS.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure NATS JetStream as a stream provider\n            .AddNatsStreams(\n                \"NatsStreamProvider\",\n                options =>\n                {\n                    options.StreamName = \"orleans-stream\";\n                    // Optional: Configure NATS client options\n                    // options.NatsClientOptions = new NatsOpts { Url = \"nats://localhost:4222\" };\n                    // Optional: Configure batch size (default: 100)\n                    // options.BatchSize = 100;\n                    // Optional: Configure partition count (default: 8)\n                    // options.PartitionCount = 8;\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Configuring NATS Streams on Client\n\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Streaming.NATS.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(clientBuilder =>\n    {\n        clientBuilder\n            .UseLocalhostClustering()\n            .AddNatsStreams(\n                \"NatsStreamProvider\",\n                options =>\n                {\n                    options.StreamName = \"orleans-stream\";\n                });\n    });\n\nawait builder.RunAsync();\n```\n\n## Example - Using NATS Streams in a Grain\n\n```csharp\nusing Orleans;\nusing Orleans.Streams;\n\n// Grain interface\npublic interface IStreamProcessingGrain : IGrainWithGuidKey\n{\n    Task StartProcessing();\n    Task SendEvent(MyEvent evt);\n}\n\n// Grain implementation\npublic class StreamProcessingGrain : Grain, IStreamProcessingGrain\n{\n    private IStreamProvider _streamProvider;\n    private IAsyncStream<MyEvent> _stream;\n    private StreamSubscriptionHandle<MyEvent> _subscription;\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        // Get the stream provider\n        _streamProvider = this.GetStreamProvider(\"NatsStreamProvider\");\n        \n        // Get a reference to a specific stream\n        _stream = _streamProvider.GetStream<MyEvent>(\n            StreamId.Create(\"MyStreamNamespace\", this.GetPrimaryKey()));\n        \n        await base.OnActivateAsync(cancellationToken);\n    }\n\n    public async Task StartProcessing()\n    {\n        // Subscribe to the stream to process events\n        _subscription = await _stream.SubscribeAsync(OnNextAsync);\n    }\n\n    private Task OnNextAsync(MyEvent evt, StreamSequenceToken token)\n    {\n        Console.WriteLine($\"Received event: {evt.Data}\");\n        return Task.CompletedTask;\n    }\n\n    // Produce an event to the stream\n    public Task SendEvent(MyEvent evt)\n    {\n        return _stream.OnNextAsync(evt);\n    }\n}\n\n// Event class\npublic class MyEvent\n{\n    public string Data { get; set; }\n}\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Streams](https://learn.microsoft.com/en-us/dotnet/orleans/streaming/)\n- [NATS JetStream Documentation](https://docs.nats.io/nats-concepts/jetstream)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)\n"
  },
  {
    "path": "src/Orleans.TestingHost/ClientExtensions.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Runtime.TestHooks;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IClusterClient\"/>.\n    /// </summary>\n    internal static class ClientExtensions\n    {\n        /// <summary>\n        /// Returns test hooks for the specified silo.\n        /// </summary>\n        /// <param name=\"client\">The client.</param>\n        /// <param name=\"silo\">The silo.</param>\n        /// <returns>Test hooks for the specified silo.</returns>\n        public static ITestHooks GetTestHooks(this IClusterClient client, SiloHandle silo)\n        {\n            // Use the siloAddress here, not the gateway address, since we may be targeting a silo on which we are not \n            // connected to the gateway\n            var internalClient = (IInternalClusterClient) client;\n            return internalClient.GetSystemTarget<ITestHooksSystemTarget>(Constants.TestHooksSystemTargetType, silo.SiloAddress);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/ConfigureDistributedGrainDirectory.cs",
    "content": "using Orleans.Hosting;\n\nnamespace Orleans.TestingHost;\n\ninternal class ConfigureDistributedGrainDirectory : ISiloConfigurator\n{\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n    public void Configure(ISiloBuilder siloBuilder) => siloBuilder.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n}"
  },
  {
    "path": "src/Orleans.TestingHost/IClientBuilderConfigurator.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Hosting;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Allows implementations to configure the client builder when starting up each silo in the test cluster.\n    /// </summary>\n    public interface IClientBuilderConfigurator\n    {\n        /// <summary>\n        /// Configures the client builder.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <param name=\"clientBuilder\">The client builder.</param>\n        void Configure(IConfiguration configuration, IClientBuilder clientBuilder);\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/IHostConfigurator.cs",
    "content": "using Microsoft.Extensions.Hosting;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Allows implementations to configure the host builder when starting up each silo in the test cluster.\n    /// </summary>\n    public interface IHostConfigurator\n    {\n        /// <summary>\n        /// Configures the host builder.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        void Configure(IHostBuilder hostBuilder);\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/IPortAllocator.cs",
    "content": "using System;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Functionality for finding unused ports.\n    /// </summary>\n    public interface ITestClusterPortAllocator : IDisposable\n    {\n        /// <summary>\n        /// Allocates consecutive port pairs.\n        /// </summary>\n        /// <param name=\"numPorts\">The number of consecutive ports to allocate.</param>\n        /// <returns>Base ports for silo and gateway endpoints.</returns>\n        ValueTuple<int, int> AllocateConsecutivePortPairs(int numPorts);\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/ISiloConfigurator.cs",
    "content": "using Orleans.Hosting;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Allows implementations to configure the silo builder when starting up each silo in the test cluster.\n    /// </summary>\n    public interface ISiloConfigurator\n    {\n        /// <summary>\n        /// Configures the silo builder.\n        /// </summary>\n        /// <param name=\"siloBuilder\">The silo builder.</param>\n        void Configure(ISiloBuilder siloBuilder);\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/InMemoryTransport/InMemoryTransportConnection.cs",
    "content": "#nullable enable\nusing System.Buffers;\nusing System.IO.Pipelines;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Networking.Shared;\n\nnamespace Orleans.TestingHost.InMemoryTransport;\n\ninternal class InMemoryTransportConnection : TransportConnection\n{\n    private readonly CancellationTokenSource _connectionClosedTokenSource = new();\n    private readonly ILogger _logger;\n    private bool _isClosed;\n    private readonly TaskCompletionSource<bool> _waitForCloseTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n    private InMemoryTransportConnection(MemoryPool<byte> memoryPool, ILogger logger, DuplexPipe.DuplexPipePair pair, EndPoint localEndPoint, EndPoint remoteEndPoint)\n    {\n        MemoryPool = memoryPool;\n        _logger = logger;\n\n        LocalEndPoint = localEndPoint;\n        RemoteEndPoint = remoteEndPoint;\n\n        Application = pair.Application;\n        Transport = pair.Transport;\n\n        ConnectionClosed = _connectionClosedTokenSource.Token;\n    }\n\n    public static InMemoryTransportConnection Create(MemoryPool<byte> memoryPool, ILogger logger, EndPoint localEndPoint, EndPoint remoteEndPoint)\n    {\n        var pair = DuplexPipe.CreateConnectionPair(\n                new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, useSynchronizationContext: false),\n                new PipeOptions(memoryPool, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));\n        return new InMemoryTransportConnection(memoryPool, logger, pair, localEndPoint, remoteEndPoint);\n    }\n\n    public static InMemoryTransportConnection Create(MemoryPool<byte> memoryPool, ILogger logger, InMemoryTransportConnection other, EndPoint localEndPoint)\n    {\n        // Swap the application & tranport pipes since we're going in the other direction.\n        var pair = new DuplexPipe.DuplexPipePair(transport: other.Application, application: other.Transport);\n        var remoteEndPoint = other.LocalEndPoint;\n        return new InMemoryTransportConnection(memoryPool, logger, pair, localEndPoint, remoteEndPoint);\n    }\n\n    public override MemoryPool<byte> MemoryPool { get; }\n\n    public Task WaitForCloseTask => _waitForCloseTcs.Task;\n\n    public override void Abort(ConnectionAbortedException? abortReason)\n    {\n        _logger.LogDebug(@\"Connection id \"\"{ConnectionId}\"\" closing because: \"\"{Message}\"\"\", ConnectionId, abortReason?.Message);\n\n        Transport.Input.CancelPendingRead();\n        Transport.Output.CancelPendingFlush();\n\n        OnClosed();\n    }\n\n    public void OnClosed()\n    {\n        if (_isClosed)\n        {\n            return;\n        }\n\n        _isClosed = true;\n\n        ThreadPool.UnsafeQueueUserWorkItem(state =>\n        {\n            state._connectionClosedTokenSource.Cancel();\n\n            state._waitForCloseTcs.TrySetResult(true);\n        },\n        this,\n        preferLocal: false);\n    }\n\n    public override async ValueTask DisposeAsync()\n    {\n        Abort(null);\n        await _waitForCloseTcs.Task;\n\n        _connectionClosedTokenSource.Dispose();\n    }\n\n    public override string ToString() => $\"InMem({LocalEndPoint}<->{RemoteEndPoint})\";\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InMemoryTransport/InMemoryTransportListenerFactory.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Hosting;\nusing Orleans.Networking.Shared;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.TestingHost.InMemoryTransport;\n\ninternal static class InMemoryTransportExtensions\n{\n    public static ISiloBuilder UseInMemoryConnectionTransport(this ISiloBuilder siloBuilder, InMemoryTransportConnectionHub hub)\n    {\n        siloBuilder.ConfigureServices(services =>\n        {\n            services.AddKeyedSingleton<IConnectionFactory>(SiloConnectionFactory.ServicesKey, CreateInMemoryConnectionFactory(hub));\n            services.AddKeyedSingleton<IConnectionListenerFactory>(SiloConnectionListener.ServicesKey, CreateInMemoryConnectionListenerFactory(hub));\n            services.AddKeyedSingleton<IConnectionListenerFactory>(GatewayConnectionListener.ServicesKey, CreateInMemoryConnectionListenerFactory(hub));\n        });\n\n        return siloBuilder;\n    }\n\n    public static IClientBuilder UseInMemoryConnectionTransport(this IClientBuilder clientBuilder, InMemoryTransportConnectionHub hub)\n    {\n        clientBuilder.ConfigureServices(services =>\n        {\n            services.AddKeyedSingleton<IConnectionFactory>(ClientOutboundConnectionFactory.ServicesKey, CreateInMemoryConnectionFactory(hub));\n        });\n\n        return clientBuilder;\n    }\n\n    private static Func<IServiceProvider, object, IConnectionFactory> CreateInMemoryConnectionFactory(InMemoryTransportConnectionHub hub)\n    {\n        return (IServiceProvider sp, object key) =>\n        {\n            var loggerFactory = sp.GetRequiredService<ILoggerFactory>();\n            var sharedMemoryPool = sp.GetRequiredService<SharedMemoryPool>();\n            return new InMemoryTransportConnectionFactory(hub, loggerFactory, sharedMemoryPool);\n        };\n    }\n\n    private static Func<IServiceProvider, object, IConnectionListenerFactory> CreateInMemoryConnectionListenerFactory(InMemoryTransportConnectionHub hub)\n    {\n        return (IServiceProvider sp, object key) =>\n        {\n            var loggerFactory = sp.GetRequiredService<ILoggerFactory>();\n            var sharedMemoryPool = sp.GetRequiredService<SharedMemoryPool>();\n            return new InMemoryTransportListener(hub, loggerFactory, sharedMemoryPool);\n        };\n    }\n}\n\ninternal class InMemoryTransportListener : IConnectionListenerFactory, IConnectionListener\n{\n    private readonly Channel<(InMemoryTransportConnection Connection, TaskCompletionSource<bool> ConnectionAcceptedTcs)> _acceptQueue = Channel.CreateUnbounded<(InMemoryTransportConnection, TaskCompletionSource<bool>)>();\n    private readonly InMemoryTransportConnectionHub _hub;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly SharedMemoryPool _memoryPool;\n    private readonly CancellationTokenSource _disposedCts = new();\n\n    public InMemoryTransportListener(InMemoryTransportConnectionHub hub, ILoggerFactory loggerFactory, SharedMemoryPool memoryPool)\n    {\n        _hub = hub;\n        _loggerFactory = loggerFactory;\n        _memoryPool = memoryPool;\n    }\n\n    public CancellationToken OnDisposed => _disposedCts.Token;\n\n    public EndPoint EndPoint { get; set; }\n\n    public async Task ConnectAsync(InMemoryTransportConnection connection)\n    {\n        var completion = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n        if (_acceptQueue.Writer.TryWrite((connection, completion)))\n        {\n            var connected = await completion.Task;\n            if (connected)\n            {\n                return;\n            }\n        }\n\n        throw new ConnectionFailedException($\"Unable to connect to {EndPoint} because its listener has terminated.\");\n    }\n\n    public async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default)\n    {\n        if (await _acceptQueue.Reader.WaitToReadAsync(cancellationToken))\n        {\n            if (_acceptQueue.Reader.TryRead(out var item))\n            {\n                var remoteConnectionContext = item.Connection;\n                var localConnectionContext = InMemoryTransportConnection.Create(\n                    _memoryPool.Pool,\n                    _loggerFactory.CreateLogger<InMemoryTransportConnection>(),\n                    other: remoteConnectionContext,\n                    localEndPoint: EndPoint);\n\n                // Set the result to true to indicate that the connection was accepted.\n                item.ConnectionAcceptedTcs.TrySetResult(true);\n\n                return localConnectionContext;\n            }\n        }\n\n        return null;\n    }\n\n    public ValueTask<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default)\n    {\n        EndPoint = endpoint;\n        _hub.RegisterConnectionListenerFactory(endpoint, this);\n        return new ValueTask<IConnectionListener>(this);\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        return UnbindAsync(default);\n    }\n\n    public ValueTask UnbindAsync(CancellationToken cancellationToken = default)\n    {\n        _acceptQueue.Writer.TryComplete();\n        while (_acceptQueue.Reader.TryRead(out var item))\n        {\n            // Set the result to false to indicate that the listener has terminated.\n            item.ConnectionAcceptedTcs.TrySetResult(false);\n        }\n\n        _disposedCts.Cancel();\n        return default;\n    }\n}\n\ninternal class InMemoryTransportConnectionHub\n{\n    private readonly ConcurrentDictionary<EndPoint, InMemoryTransportListener> _listeners = new();\n\n    public static InMemoryTransportConnectionHub Instance { get; } = new();\n\n    public void RegisterConnectionListenerFactory(EndPoint endPoint, InMemoryTransportListener listener)\n    {\n        _listeners[endPoint] = listener;\n        listener.OnDisposed.Register(() =>\n        {\n            ((IDictionary<EndPoint, InMemoryTransportListener>)_listeners).Remove(new KeyValuePair<EndPoint, InMemoryTransportListener>(endPoint, listener));\n        });\n    }\n\n    public InMemoryTransportListener GetConnectionListenerFactory(EndPoint endPoint)\n    {\n        _listeners.TryGetValue(endPoint, out var listener);\n        return listener;\n    }\n}\n\ninternal class InMemoryTransportConnectionFactory : IConnectionFactory\n{\n    private readonly InMemoryTransportConnectionHub _hub;\n    private readonly ILoggerFactory _loggerFactory;\n    private readonly SharedMemoryPool _memoryPool;\n    private readonly IPEndPoint _localEndpoint;\n\n    public InMemoryTransportConnectionFactory(InMemoryTransportConnectionHub hub, ILoggerFactory loggerFactory, SharedMemoryPool memoryPool)\n    {\n        _hub = hub;\n        _loggerFactory = loggerFactory;\n        _memoryPool = memoryPool;\n        _localEndpoint = new IPEndPoint(IPAddress.Loopback, Random.Shared.Next(1024, ushort.MaxValue - 1024));\n    }\n\n    public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)\n    {\n        var listener = _hub.GetConnectionListenerFactory(endpoint);\n        if (listener is null)\n        {\n            throw new ConnectionFailedException($\"Unable to connect to endpoint {endpoint} because no such endpoint is currently registered.\");\n        }\n\n        var connectionContext = InMemoryTransportConnection.Create(\n            _memoryPool.Pool,\n            _loggerFactory.CreateLogger<InMemoryTransportConnection>(),\n            _localEndpoint,\n            endpoint);\n        await listener.ConnectAsync(connectionContext).WaitAsync(cancellationToken);\n        return connectionContext;\n    }\n}\n\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcTestCluster.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost.InMemoryTransport;\nusing System.Net;\nusing Orleans.Statistics;\nusing Orleans.TestingHost.InProcess;\nusing Orleans.Runtime.Hosting;\nusing Orleans.GrainDirectory;\nusing Orleans.Messaging;\nusing Orleans.Hosting;\nusing Orleans.Runtime.TestHooks;\nusing Orleans.Configuration.Internal;\nusing Orleans.TestingHost.Logging;\n\nnamespace Orleans.TestingHost;\n\n/// <summary>\n/// A host class for local testing with Orleans using in-process silos. \n/// </summary>\npublic sealed class InProcessTestCluster : IDisposable, IAsyncDisposable\n{\n    private readonly List<InProcessSiloHandle> _silos = [];\n    private readonly StringBuilder _log = new();\n    private readonly InMemoryTransportConnectionHub _transportHub = new();\n    private readonly InProcessGrainDirectory _grainDirectory;\n    private readonly InProcessMembershipTable _membershipTable;\n    private bool _disposed;\n    private int _startedInstances;\n\n    /// <summary>\n    /// Collection of all known silos.\n    /// </summary>\n    public ReadOnlyCollection<InProcessSiloHandle> Silos\n    {\n        get\n        {\n            lock (_silos)\n            {\n                return new List<InProcessSiloHandle>(_silos).AsReadOnly();\n            }\n        }\n    }\n\n    /// <summary>\n    /// Options used to configure the test cluster.\n    /// </summary>\n    /// <remarks>This is the options you configured your test cluster with, or the default one. \n    /// If the cluster is being configured via ClusterConfiguration, then this object may not reflect the true settings.\n    /// </remarks>\n    public InProcessTestClusterOptions Options { get; }\n\n    /// <summary>\n    /// The internal client interface.\n    /// </summary>\n    internal IHost ClientHost { get; private set; }\n\n    /// <summary>\n    /// The internal client interface.\n    /// </summary>\n    internal IInternalClusterClient InternalClient => ClientHost?.Services.GetRequiredService<IInternalClusterClient>();\n\n    /// <summary>\n    /// The client.\n    /// </summary>\n    public IClusterClient Client => ClientHost?.Services.GetRequiredService<IInternalClusterClient>();\n\n    /// <summary>\n    /// The port allocator.\n    /// </summary>\n    public ITestClusterPortAllocator PortAllocator { get; }\n\n    /// <summary>\n    /// Configures the test cluster plus client in-process.\n    /// </summary>\n    public InProcessTestCluster(\n        InProcessTestClusterOptions options,\n        ITestClusterPortAllocator portAllocator)\n    {\n        Options = options;\n        PortAllocator = portAllocator;\n        _membershipTable = new(options.ClusterId);\n        _grainDirectory = new(_membershipTable.GetSiloStatus);\n    }\n\n    /// <summary>\n    /// Returns the <see cref=\"IServiceProvider\"/> associated with the given <paramref name=\"silo\"/>.\n    /// </summary>\n    /// <param name=\"silo\">The silo process to the the service provider for.</param>\n    /// <remarks>If <paramref name=\"silo\"/> is <see langword=\"null\"/> one of the existing silos will be picked randomly.</remarks>\n    public IServiceProvider GetSiloServiceProvider(SiloAddress silo = null)\n    {\n        if (silo != null)\n        {\n            var handle = Silos.FirstOrDefault(x => x.SiloAddress.Equals(silo));\n            return handle != null ? handle.SiloHost.Services :\n                throw new ArgumentException($\"The provided silo address '{silo}' is unknown.\");\n        }\n        else\n        {\n            var index = Random.Shared.Next(Silos.Count);\n            return Silos[index].SiloHost.Services;\n        }\n    }\n\n    /// <summary>\n    /// Deploys the cluster using the specified configuration and starts the client in-process.\n    /// </summary>\n    public async Task DeployAsync()\n    {\n        if (_silos.Count > 0) throw new InvalidOperationException(\"Cluster host already deployed.\");\n\n        AppDomain.CurrentDomain.UnhandledException += ReportUnobservedException;\n\n        try\n        {\n            string startMsg = \"----------------------------- STARTING NEW UNIT TEST SILO HOST: \" + GetType().FullName + \" -------------------------------------\";\n            WriteLog(startMsg);\n            await InitializeAsync();\n\n            if (Options.InitializeClientOnDeploy)\n            {\n                await WaitForInitialStabilization();\n            }\n        }\n        catch (TimeoutException te)\n        {\n            FlushLogToConsole();\n            throw new TimeoutException(\"Timeout during test initialization\", te);\n        }\n        catch (Exception ex)\n        {\n            await StopAllSilosAsync();\n\n            Exception baseExc = ex.GetBaseException();\n            FlushLogToConsole();\n\n            if (baseExc is TimeoutException)\n            {\n                throw new TimeoutException(\"Timeout during test initialization\", ex);\n            }\n\n            // IMPORTANT:\n            // Do NOT re-throw the original exception here, also not as an internal exception inside AggregateException\n            // Due to the way MS tests works, if the original exception is an Orleans exception,\n            // it's assembly might not be loaded yet in this phase of the test.\n            // As a result, we will get \"MSTest: Unit Test Adapter threw exception: Type is not resolved for member XXX\"\n            // and will loose the original exception. This makes debugging tests super hard!\n            // The root cause has to do with us initializing our tests from Test constructor and not from TestInitialize method.\n            // More details: http://dobrzanski.net/2010/09/20/mstest-unit-test-adapter-threw-exception-type-is-not-resolved-for-member/\n            //throw new Exception(\n            //    string.Format(\"Exception during test initialization: {0}\",\n            //        LogFormatter.PrintException(baseExc)));\n            throw;\n        }\n    }\n\n    private async Task WaitForInitialStabilization()\n    {\n        // Poll each silo to check that it knows the expected number of active silos.\n        // If any silo does not have the expected number of active silos in its cluster membership oracle, try again.\n        // If the cluster membership has not stabilized after a certain period of time, give up and continue anyway.\n        var totalWait = Stopwatch.StartNew();\n        while (true)\n        {\n            var silos = Silos;\n            var expectedCount = silos.Count;\n            var remainingSilos = expectedCount;\n\n            foreach (var silo in silos)\n            {\n                var hooks = InternalClient.GetTestHooks(silo);\n                var statuses = await hooks.GetApproximateSiloStatuses();\n                var activeCount = statuses.Count(s => s.Value == SiloStatus.Active);\n                if (activeCount != expectedCount) break;\n                remainingSilos--;\n            }\n\n            if (remainingSilos == 0)\n            {\n                totalWait.Stop();\n                break;\n            }\n\n            WriteLog($\"{remainingSilos} silos do not have a consistent cluster view, waiting until stabilization.\");\n            await Task.Delay(TimeSpan.FromMilliseconds(100));\n\n            if (totalWait.Elapsed < TimeSpan.FromSeconds(60))\n            {\n                WriteLog($\"Warning! {remainingSilos} silos do not have a consistent cluster view after {totalWait.ElapsedMilliseconds}ms, continuing without stabilization.\");\n                break;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Get the list of current active silos.\n    /// </summary>\n    /// <returns>List of current silos.</returns>\n    public IEnumerable<InProcessSiloHandle> GetActiveSilos()\n    {\n        var additional = new List<InProcessSiloHandle>();\n        lock (_silos)\n        {\n            additional.AddRange(_silos);\n        }\n\n        WriteLog(\"GetActiveSilos: {0} Silos={1}\",\n            additional.Count, Runtime.Utils.EnumerableToString(additional));\n\n        if (additional.Count > 0)\n            foreach (var s in additional)\n                if (s?.IsActive == true)\n                    yield return s;\n    }\n\n    /// <summary>\n    /// Find the silo handle for the specified silo address.\n    /// </summary>\n    /// <param name=\"siloAddress\">Silo address to be found.</param>\n    /// <returns>SiloHandle of the appropriate silo, or <c>null</c> if not found.</returns>\n    public InProcessSiloHandle GetSiloForAddress(SiloAddress siloAddress)\n    {\n        var activeSilos = GetActiveSilos().ToList();\n        var ret = activeSilos.Find(s => s.SiloAddress.Equals(siloAddress));\n        return ret;\n    }\n\n    /// <summary>\n    /// Wait for the silo liveness sub-system to detect and act on any recent cluster membership changes.\n    /// </summary>\n    /// <param name=\"didKill\">Whether recent membership changes we done by graceful Stop.</param>\n    public async Task WaitForLivenessToStabilizeAsync(bool didKill = false)\n    {\n        var clusterMembershipOptions = Client.ServiceProvider.GetRequiredService<IOptions<ClusterMembershipOptions>>().Value;\n        TimeSpan stabilizationTime = GetLivenessStabilizationTime(clusterMembershipOptions, didKill);\n        WriteLog(Environment.NewLine + Environment.NewLine + \"WaitForLivenessToStabilize is about to sleep for {0}\", stabilizationTime);\n        await Task.Delay(stabilizationTime);\n        WriteLog(\"WaitForLivenessToStabilize is done sleeping\");\n    }\n\n    /// <summary>\n    /// Get the timeout value to use to wait for the silo liveness sub-system to detect and act on any recent cluster membership changes.\n    /// <seealso cref=\"WaitForLivenessToStabilizeAsync\"/>\n    /// </summary>\n    public static TimeSpan GetLivenessStabilizationTime(ClusterMembershipOptions clusterMembershipOptions, bool didKill = false)\n    {\n        TimeSpan stabilizationTime = TimeSpan.Zero;\n        if (didKill)\n        {\n            // in case of hard kill (kill and not Stop), we should give silos time to detect failures first.\n            stabilizationTime = TestingUtils.Multiply(clusterMembershipOptions.ProbeTimeout, clusterMembershipOptions.NumMissedProbesLimit);\n        }\n        if (clusterMembershipOptions.UseLivenessGossip)\n        {\n            stabilizationTime += TimeSpan.FromSeconds(5);\n        }\n        else\n        {\n            stabilizationTime += TestingUtils.Multiply(clusterMembershipOptions.TableRefreshTimeout, 2);\n        }\n\n        return stabilizationTime;\n    }\n\n    /// <summary>\n    /// Start an additional silo, so that it joins the existing cluster.\n    /// </summary>\n    /// <returns>SiloHandle for the newly started silo.</returns>\n    public InProcessSiloHandle StartAdditionalSilo()\n    {\n        return StartAdditionalSiloAsync().GetAwaiter().GetResult();\n    }\n\n    /// <summary>\n    /// Start an additional silo, so that it joins the existing cluster.\n    /// </summary>\n    /// <returns>SiloHandle for the newly started silo.</returns>\n    public async Task<InProcessSiloHandle> StartAdditionalSiloAsync()\n    {\n        return (await StartSilosAsync(1)).Single();\n    }\n\n    /// <summary>\n    /// Start an additional silo, so that it joins the existing cluster.\n    /// </summary>\n    /// <returns>SiloHandle for the newly started silo.</returns>\n    [Obsolete(\"Use overload which does not have a 'startAdditionalSiloOnNewPort' parameter.\")]\n    public InProcessSiloHandle StartAdditionalSilo(bool startAdditionalSiloOnNewPort)\n    {\n        return StartAdditionalSiloAsync(startAdditionalSiloOnNewPort).GetAwaiter().GetResult();\n    }\n\n    /// <summary>\n    /// Start an additional silo, so that it joins the existing cluster.\n    /// </summary>\n    /// <returns>SiloHandle for the newly started silo.</returns>\n    public async Task<InProcessSiloHandle> StartAdditionalSiloAsync(bool startAdditionalSiloOnNewPort)\n    {\n        return (await StartSilosAsync(1)).Single();\n    }\n\n    /// <summary>\n    /// Start a number of additional silo, so that they join the existing cluster.\n    /// </summary>\n    /// <param name=\"silosToStart\">Number of silos to start.</param>\n    /// <param name=\"startAdditionalSiloOnNewPort\"></param>\n    /// <returns>List of SiloHandles for the newly started silos.</returns>\n    [Obsolete(\"Use overload which does not have a 'startAdditionalSiloOnNewPort' parameter.\")]\n    public async Task<List<InProcessSiloHandle>> StartSilosAsync(int silosToStart, bool startAdditionalSiloOnNewPort)\n    {\n        return await StartSilosAsync(silosToStart);\n    }\n\n    /// <summary>\n    /// Start a number of additional silo, so that they join the existing cluster.\n    /// </summary>\n    /// <param name=\"silosToStart\">Number of silos to start.</param>\n    /// <returns>List of SiloHandles for the newly started silos.</returns>\n    public async Task<List<InProcessSiloHandle>> StartSilosAsync(int silosToStart)\n    {\n        var instances = new List<InProcessSiloHandle>();\n        if (silosToStart > 0)\n        {\n            var siloStartTasks = Enumerable.Range(_startedInstances, silosToStart)\n                .Select(instanceNumber => Task.Run(() => StartSiloAsync((short)instanceNumber, Options))).ToArray();\n\n            try\n            {\n                await Task.WhenAll(siloStartTasks);\n            }\n            catch (Exception)\n            {\n                lock (_silos)\n                {\n                    _silos.AddRange(siloStartTasks.Where(t => t.Exception == null).Select(t => t.Result));\n                }\n\n                throw;\n            }\n\n            instances.AddRange(siloStartTasks.Select(t => t.Result));\n            lock (_silos)\n            {\n                _silos.AddRange(instances);\n            }\n        }\n\n        return instances;\n    }\n\n    /// <summary>\n    /// Stop all silos.\n    /// </summary>\n    public async Task StopSilosAsync()\n    {\n        foreach (var instance in _silos.ToList())\n        {\n            await StopSiloAsync(instance);\n        }\n    }\n\n    /// <summary>\n    /// Stop cluster client as an asynchronous operation.\n    /// </summary>\n    /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation.</returns>\n    public async Task StopClusterClientAsync()\n    {\n        var client = ClientHost;\n        try\n        {\n            if (client is not null)\n            {\n                await client.StopAsync().ConfigureAwait(false);\n            }\n        }\n        catch (Exception exc)\n        {\n            WriteLog(\"Exception stopping client: {0}\", exc);\n        }\n        finally\n        {\n            await DisposeAsync(client).ConfigureAwait(false);\n            ClientHost = null;\n        }\n    }\n\n    /// <summary>\n    /// Stop all current silos.\n    /// </summary>\n    public void StopAllSilos()\n    {\n        StopAllSilosAsync().GetAwaiter().GetResult();\n    }\n\n    /// <summary>\n    /// Stop all current silos.\n    /// </summary>\n    public async Task StopAllSilosAsync()\n    {\n        await StopClusterClientAsync();\n        await StopSilosAsync();\n        AppDomain.CurrentDomain.UnhandledException -= ReportUnobservedException;\n    }\n\n    /// <summary>\n    /// Do a semi-graceful Stop of the specified silo.\n    /// </summary>\n    /// <param name=\"instance\">Silo to be stopped.</param>\n    public async Task StopSiloAsync(InProcessSiloHandle instance)\n    {\n        if (instance != null)\n        {\n            await StopSiloAsync(instance, true);\n            lock (_silos)\n            {\n                _silos.Remove(instance);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Do an immediate Kill of the specified silo.\n    /// </summary>\n    /// <param name=\"instance\">Silo to be killed.</param>\n    public async Task KillSiloAsync(InProcessSiloHandle instance)\n    {\n        if (instance != null)\n        {\n            // do NOT stop, just kill directly, to simulate crash.\n            await StopSiloAsync(instance, false);\n            lock (_silos)\n            {\n                _silos.Remove(instance);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Performs a hard kill on client.  Client will not cleanup resources.\n    /// </summary>\n    public async Task KillClientAsync()\n    {\n        var client = ClientHost;\n        if (client != null)\n        {\n            var cancelled = new CancellationTokenSource();\n            cancelled.Cancel();\n            try\n            {\n                await client.StopAsync(cancelled.Token).ConfigureAwait(false);\n            }\n            finally\n            {\n                await DisposeAsync(client);\n                ClientHost = null;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Do a Stop or Kill of the specified silo, followed by a restart.\n    /// </summary>\n    /// <param name=\"instance\">Silo to be restarted.</param>\n    public async Task<InProcessSiloHandle> RestartSiloAsync(InProcessSiloHandle instance)\n    {\n        if (instance != null)\n        {\n            var instanceNumber = instance.InstanceNumber;\n            await StopSiloAsync(instance);\n            var newInstance = await StartSiloAsync(instanceNumber, Options);\n            lock (_silos)\n            {\n                _silos.Add(newInstance);\n            }\n\n            return newInstance;\n        }\n\n        return null;\n    }\n\n    /// <summary>\n    /// Restart a previously stopped.\n    /// </summary>\n    /// <param name=\"siloName\">Silo to be restarted.</param>\n    public async Task<InProcessSiloHandle> RestartStoppedSecondarySiloAsync(string siloName)\n    {\n        if (siloName == null) throw new ArgumentNullException(nameof(siloName));\n        var siloHandle = Silos.Single(s => s.Name.Equals(siloName, StringComparison.Ordinal));\n        var newInstance = await StartSiloAsync(Silos.IndexOf(siloHandle), Options);\n        lock (_silos)\n        {\n            _silos.Add(newInstance);\n        }\n        return newInstance;\n    }\n\n    /// <summary>\n    /// Initialize the grain client. This should be already done by <see cref=\"DeployAsync\"/>\n    /// </summary>\n    public async Task InitializeClientAsync()\n    {\n        WriteLog(\"Initializing Cluster Client\");\n\n        if (ClientHost is not null)\n        {\n            await StopClusterClientAsync();\n        }\n\n        var hostBuilder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings\n        {\n            EnvironmentName = Environments.Development,\n            ApplicationName = \"TestClusterClient\",\n            DisableDefaults = true,\n        });\n\n        foreach (var hostDelegate in Options.ClientHostConfigurationDelegates)\n        {\n            hostDelegate(hostBuilder);\n        }\n\n        hostBuilder.UseOrleansClient(clientBuilder =>\n        {\n            clientBuilder.Configure<ClusterOptions>(o =>\n            {\n                o.ClusterId = Options.ClusterId;\n                o.ServiceId = Options.ServiceId;\n            });\n\n            if (Options.UseTestClusterMembership)\n            {\n                clientBuilder.Services.AddSingleton<IGatewayListProvider>(_membershipTable);\n            }\n\n            clientBuilder.UseInMemoryConnectionTransport(_transportHub);\n        });\n\n        TryConfigureFileLogging(Options, hostBuilder.Services, \"TestClusterClient\");\n\n        ClientHost = hostBuilder.Build();\n        await ClientHost.StartAsync();\n    }\n\n    private async Task InitializeAsync()\n    {\n        var silosToStart = Options.InitialSilosCount;\n\n        if (silosToStart > 0)\n        {\n            await StartSilosAsync(silosToStart);\n        }\n\n        WriteLog(\"Done initializing cluster\");\n\n        if (Options.InitializeClientOnDeploy)\n        {\n            await InitializeClientAsync();\n        }\n    }\n\n    public async Task<InProcessSiloHandle> CreateSiloAsync(InProcessTestSiloSpecificOptions siloOptions)\n    {\n        var host = await Task.Run(async () =>\n        {\n            var siloName = siloOptions.SiloName;\n\n            var appBuilder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings\n            {\n                ApplicationName = siloName,\n                EnvironmentName = Environments.Development,\n                DisableDefaults = true\n            });\n\n            var services = appBuilder.Services;\n            TryConfigureFileLogging(Options, services, siloName);\n\n            if (Debugger.IsAttached)\n            {\n                // Test is running inside debugger - Make timeout ~= infinite\n                services.Configure<SiloMessagingOptions>(op => op.ResponseTimeout = TimeSpan.FromMilliseconds(1000000));\n            }\n\n            foreach (var hostDelegate in Options.SiloHostConfigurationDelegates)\n            {\n                hostDelegate(siloOptions, appBuilder);\n            }\n\n            appBuilder.UseOrleans(siloBuilder =>\n            {\n                siloBuilder.Configure<ClusterOptions>(o =>\n                {\n                    o.ClusterId = Options.ClusterId;\n                    o.ServiceId = Options.ServiceId;\n                });\n\n                siloBuilder.Configure<SiloOptions>(o =>\n                {\n                    o.SiloName = siloOptions.SiloName;\n                });\n\n                siloBuilder.Configure<EndpointOptions>(o =>\n                {\n                    o.AdvertisedIPAddress = IPAddress.Loopback;\n                    o.SiloPort = siloOptions.SiloPort;\n                    o.GatewayPort = siloOptions.GatewayPort;\n                });\n\n                siloBuilder.Services\n                    .Configure<HostOptions>(options => options.ShutdownTimeout = TimeSpan.FromSeconds(30));\n\n                if (Options.UseTestClusterMembership)\n                {\n                    services.AddSingleton<IMembershipTable>(_membershipTable);\n                    siloBuilder.AddGrainDirectory(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, (_, _) => _grainDirectory);\n                }\n\n                siloBuilder.UseInMemoryConnectionTransport(_transportHub);\n\n                services.AddSingleton<TestHooksEnvironmentStatisticsProvider>();\n                services.AddSingleton<TestHooksSystemTarget>();\n                if (!Options.UseRealEnvironmentStatistics)\n                {\n                    services.AddFromExisting<IEnvironmentStatisticsProvider, TestHooksEnvironmentStatisticsProvider>();\n                }\n            });\n\n            var host = appBuilder.Build();\n            InitializeTestHooksSystemTarget(host);\n            await host.StartAsync();\n            return host;\n        });\n\n        return new InProcessSiloHandle\n        {\n            Name = siloOptions.SiloName,\n            SiloHost = host,\n            SiloAddress = host.Services.GetRequiredService<ILocalSiloDetails>().SiloAddress,\n            GatewayAddress = host.Services.GetRequiredService<ILocalSiloDetails>().GatewayAddress,\n        };\n    }\n\n    /// <summary>\n    /// Start a new silo in the target cluster\n    /// </summary>\n    /// <param name=\"cluster\">The InProcessTestCluster in which the silo should be deployed</param>\n    /// <param name=\"instanceNumber\">The instance number to deploy</param>\n    /// <param name=\"clusterOptions\">The options to use.</param>\n    /// <returns>A handle to the silo deployed</returns>\n    public static async Task<InProcessSiloHandle> StartSiloAsync(InProcessTestCluster cluster, int instanceNumber, InProcessTestClusterOptions clusterOptions)\n    {\n        if (cluster == null) throw new ArgumentNullException(nameof(cluster));\n        return await cluster.StartSiloAsync(instanceNumber, clusterOptions);\n    }\n\n    /// <summary>\n    /// Start a new silo in the target cluster\n    /// </summary>\n    /// <param name=\"cluster\">The InProcessTestCluster in which the silo should be deployed</param>\n    /// <param name=\"instanceNumber\">The instance number to deploy</param>\n    /// <param name=\"clusterOptions\">The options to use.</param>\n    /// <param name=\"configurationOverrides\">Configuration overrides.</param>\n    /// <param name=\"startSiloOnNewPort\">Whether we start this silo on a new port, instead of the default one</param>\n    /// <returns>A handle to the silo deployed</returns>\n    [Obsolete(\"Use the overload which does not have a 'startSiloOnNewPort' parameter.\")]\n    public static async Task<InProcessSiloHandle> StartSiloAsync(InProcessTestCluster cluster, int instanceNumber, InProcessTestClusterOptions clusterOptions, IReadOnlyList<IConfigurationSource> configurationOverrides, bool startSiloOnNewPort)\n    {\n        if (cluster == null) throw new ArgumentNullException(nameof(cluster));\n        return await cluster.StartSiloAsync(instanceNumber, clusterOptions, configurationOverrides, startSiloOnNewPort);\n    }\n\n    /// <summary>\n    /// Starts a new silo.\n    /// </summary>\n    /// <param name=\"instanceNumber\">The instance number to deploy</param>\n    /// <param name=\"clusterOptions\">The options to use.</param>\n    /// <returns>A handle to the deployed silo.</returns>\n    public async Task<InProcessSiloHandle> StartSiloAsync(int instanceNumber, InProcessTestClusterOptions clusterOptions)\n    {\n        var siloOptions = InProcessTestSiloSpecificOptions.Create(this, clusterOptions, instanceNumber, assignNewPort: true);\n        var handle = await CreateSiloAsync(siloOptions);\n        handle.InstanceNumber = (short)instanceNumber;\n        Interlocked.Increment(ref _startedInstances);\n        return handle;\n    }\n\n    /// <summary>\n    /// Starts a new silo.\n    /// </summary>\n    /// <param name=\"instanceNumber\">The instance number to deploy</param>\n    /// <param name=\"clusterOptions\">The options to use.</param>\n    /// <param name=\"configurationOverrides\">Configuration overrides.</param>\n    /// <param name=\"startSiloOnNewPort\">Whether we start this silo on a new port, instead of the default one</param>\n    /// <returns>A handle to the deployed silo.</returns>\n    [Obsolete(\"Use the overload which does not have a 'startSiloOnNewPort' parameter.\")]\n    public async Task<InProcessSiloHandle> StartSiloAsync(int instanceNumber, InProcessTestClusterOptions clusterOptions, IReadOnlyList<IConfigurationSource> configurationOverrides, bool startSiloOnNewPort)\n    {\n        return await StartSiloAsync(instanceNumber, clusterOptions);\n    }\n\n    private async Task StopSiloAsync(InProcessSiloHandle instance, bool stopGracefully)\n    {\n        try\n        {\n            await instance.StopSiloAsync(stopGracefully).ConfigureAwait(false);\n        }\n        finally\n        {\n            await DisposeAsync(instance).ConfigureAwait(false);\n\n            Interlocked.Decrement(ref _startedInstances);\n        }\n    }\n\n    /// <summary>\n    /// Gets the log.\n    /// </summary>\n    /// <returns>The log contents.</returns>\n    public string GetLog()\n    {\n        return _log.ToString();\n    }\n\n    private void ReportUnobservedException(object sender, UnhandledExceptionEventArgs eventArgs)\n    {\n        Exception exception = (Exception)eventArgs.ExceptionObject;\n        WriteLog(\"Unobserved exception: {0}\", exception);\n    }\n\n    private void WriteLog(string format, params object[] args)\n    {\n        _log.AppendFormat(format + Environment.NewLine, args);\n    }\n\n    private void FlushLogToConsole()\n    {\n        Console.WriteLine(GetLog());\n    }\n\n    /// <inheritdoc/>\n    public async ValueTask DisposeAsync()\n    {\n        if (_disposed)\n        {\n            return;\n        }\n\n        await Task.Run(async () =>\n        {\n            foreach (var handle in Silos)\n            {\n                await DisposeAsync(handle).ConfigureAwait(false);\n            }\n\n            await DisposeAsync(ClientHost).ConfigureAwait(false);\n            ClientHost = null;\n\n            PortAllocator?.Dispose();\n        });\n\n        _disposed = true;\n    }\n\n    /// <inheritdoc/>\n    public void Dispose()\n    {\n        if (_disposed)\n        {\n            return;\n        }\n\n        foreach (var handle in Silos)\n        {\n            handle.Dispose();\n        }\n\n        ClientHost?.Dispose();\n        PortAllocator?.Dispose();\n\n        _disposed = true;\n    }\n\n    private static async Task DisposeAsync(IDisposable value)\n    {\n        if (value is IAsyncDisposable asyncDisposable)\n        {\n            await asyncDisposable.DisposeAsync().ConfigureAwait(false);\n        }\n        else if (value is IDisposable disposable)\n        {\n            disposable.Dispose();\n        }\n\n    }\n    private static void TryConfigureFileLogging(InProcessTestClusterOptions options, IServiceCollection services, string name)\n    {\n        if (options.ConfigureFileLogging)\n        {\n            var fileName = TestingUtils.CreateTraceFileName(name, options.ClusterId);\n            services.AddLogging(loggingBuilder => loggingBuilder.AddFile(fileName));\n        }\n    }\n\n    private static void InitializeTestHooksSystemTarget(IHost host)\n    {\n        _ = host.Services.GetRequiredService<TestHooksSystemTarget>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcTestClusterBuilder.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost;\n\n/// <summary>Configuration builder for starting a <see cref=\"InProcessTestCluster\"/>.</summary>\npublic sealed class InProcessTestClusterBuilder\n{\n    /// <summary>\n    /// Initializes a new instance of <see cref=\"InProcessTestClusterBuilder\"/> using the default options.\n    /// </summary>\n    public InProcessTestClusterBuilder()\n        : this(2)\n    {\n    }\n\n    /// <summary>\n    /// Initializes a new instance of <see cref=\"InProcessTestClusterBuilder\"/> overriding the initial silos count.\n    /// </summary>\n    /// <param name=\"initialSilosCount\">The number of initial silos to deploy.</param>\n    public InProcessTestClusterBuilder(short initialSilosCount)\n    {\n        Options = new InProcessTestClusterOptions\n        {\n            InitialSilosCount = initialSilosCount,\n            ClusterId = CreateClusterId(),\n            ServiceId = Guid.NewGuid().ToString(\"N\"),\n            UseTestClusterMembership = true,\n            InitializeClientOnDeploy = true,\n            ConfigureFileLogging = true,\n            AssumeHomogenousSilosForTesting = true\n        };\n    }\n\n    /// <summary>\n    /// Gets the options.\n    /// </summary>\n    /// <value>The options.</value>\n    public InProcessTestClusterOptions Options { get; }\n\n    /// <summary>\n    /// The port allocator.\n    /// </summary>\n    public ITestClusterPortAllocator PortAllocator { get; } = new TestClusterPortAllocator();\n\n    /// <summary>\n    /// Adds a delegate for configuring silo and client hosts.\n    /// </summary>\n    public InProcessTestClusterBuilder ConfigureHost(Action<IHostApplicationBuilder> configureDelegate)\n    {\n        Options.SiloHostConfigurationDelegates.Add((_, hostBuilder) => configureDelegate(hostBuilder));\n        Options.ClientHostConfigurationDelegates.Add(configureDelegate);\n        return this;\n    }\n\n    /// <summary>\n    /// Adds a delegate to configure silos.\n    /// </summary>\n    /// <returns>The builder.</returns>\n    public InProcessTestClusterBuilder ConfigureSilo(Action<InProcessTestSiloSpecificOptions, ISiloBuilder> configureSiloDelegate)\n    {\n        Options.SiloHostConfigurationDelegates.Add((options, hostBuilder) => hostBuilder.UseOrleans(siloBuilder => configureSiloDelegate(options, siloBuilder)));\n        return this;\n    }\n\n    /// <summary>\n    /// Adds a delegate to configure silo hosts.\n    /// </summary>\n    /// <returns>The builder.</returns>\n    public InProcessTestClusterBuilder ConfigureSiloHost(Action<InProcessTestSiloSpecificOptions, IHostApplicationBuilder> configureSiloHostDelegate)\n    {\n        Options.SiloHostConfigurationDelegates.Add(configureSiloHostDelegate);\n        return this;\n    }\n\n    /// <summary>\n    /// Adds a delegate to configure clients.\n    /// </summary>\n    /// <returns>The builder.</returns>\n    public InProcessTestClusterBuilder ConfigureClient(Action<IClientBuilder> configureClientDelegate)\n    {\n        Options.ClientHostConfigurationDelegates.Add(hostBuilder => hostBuilder.UseOrleansClient(clientBuilder => configureClientDelegate(clientBuilder)));\n        return this;\n    }\n\n    /// <summary>\n    /// Adds a delegate to configure clients hosts.\n    /// </summary>\n    /// <returns>The builder.</returns>\n    public InProcessTestClusterBuilder ConfigureClientHost(Action<IHostApplicationBuilder> configureHostDelegate)\n    {\n        Options.ClientHostConfigurationDelegates.Add(hostBuilder => configureHostDelegate(hostBuilder));\n        return this;\n    }\n\n    /// <summary>\n    /// Builds this instance.\n    /// </summary>\n    /// <returns>InProcessTestCluster.</returns>\n    public InProcessTestCluster Build()\n    {\n        var portAllocator = PortAllocator;\n\n        ConfigureDefaultPorts();\n\n        var testCluster = new InProcessTestCluster(Options, portAllocator);\n        return testCluster;\n    }\n\n    /// <summary>\n    /// Creates a cluster identifier.\n    /// </summary>\n    /// <returns>A new cluster identifier.</returns>\n    public static string CreateClusterId()\n    {\n        string prefix = \"testcluster-\";\n        int randomSuffix = Random.Shared.Next(1000);\n        DateTime now = DateTime.UtcNow;\n        string DateTimeFormat = @\"yyyy-MM-dd\\tHH-mm-ss\";\n        return $\"{prefix}{now.ToString(DateTimeFormat, CultureInfo.InvariantCulture)}-{randomSuffix}\";\n    }\n\n    private void ConfigureDefaultPorts()\n    {\n        // Set base ports if none are currently set.\n        (int baseSiloPort, int baseGatewayPort) = PortAllocator.AllocateConsecutivePortPairs(Options.InitialSilosCount + 3);\n        if (Options.BaseSiloPort == 0) Options.BaseSiloPort = baseSiloPort;\n        if (Options.BaseGatewayPort == 0) Options.BaseGatewayPort = baseGatewayPort;\n    }\n\n    internal class ConfigureStaticClusterDeploymentOptions : IHostConfigurator\n    {\n        public void Configure(IHostBuilder hostBuilder)\n        {\n            hostBuilder.ConfigureServices((context, services) =>\n            {\n                var initialSilos = int.Parse(context.Configuration[nameof(InProcessTestClusterOptions.InitialSilosCount)]);\n                var siloNames = Enumerable.Range(0, initialSilos).Select(GetSiloName).ToList();\n                services.Configure<StaticClusterDeploymentOptions>(options => options.SiloNames = siloNames);\n            });\n        }\n\n        private static string GetSiloName(int instanceNumber)\n        {\n            return instanceNumber == 0 ? Silo.PrimarySiloName : $\"Secondary_{instanceNumber}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/InProcTestClusterOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nnamespace Orleans.TestingHost;\n\n/// <summary>\n/// Configuration options for test clusters.\n/// </summary>\npublic sealed class InProcessTestClusterOptions\n{\n    /// <summary>\n    /// Gets or sets the cluster identifier.\n    /// </summary>\n    /// <seealso cref=\"ClusterOptions.ClusterId\"/>\n    /// <value>The cluster identifier.</value>\n    public string ClusterId { get; set; }\n\n    /// <summary>\n    /// Gets or sets the service identifier.\n    /// </summary>\n    /// <seealso cref=\"ClusterOptions.ServiceId\"/>\n    /// <value>The service identifier.</value>\n    public string ServiceId { get; set; }\n\n    /// <summary>\n    /// Gets or sets the base silo port, which is the port for the first silo. Other silos will use subsequent ports.\n    /// </summary>\n    /// <value>The base silo port.</value>\n    internal int BaseSiloPort { get; set; }\n\n    /// <summary>\n    /// Gets or sets the base gateway port, which is the gateway port for the first silo. Other silos will use subsequent ports.\n    /// </summary>\n    /// <value>The base gateway port.</value>\n    internal int BaseGatewayPort { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to use test cluster membership.\n    /// </summary>\n    /// <value><see langword=\"true\" /> if test cluster membership should be used; otherwise, <see langword=\"false\" />.</value>\n    internal bool UseTestClusterMembership { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to use the real environment statistics.\n    /// </summary>\n    public bool UseRealEnvironmentStatistics { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to initialize the client immediately on deployment.\n    /// </summary>\n    /// <value><see langword=\"true\" /> if the client should be initialized immediately on deployment; otherwise, <see langword=\"false\" />.</value>\n    public bool InitializeClientOnDeploy { get; set; }\n\n    /// <summary>\n    /// Gets or sets the initial silos count.\n    /// </summary>\n    /// <value>The initial silos count.</value>\n    public short InitialSilosCount { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to configure file logging.\n    /// </summary>\n    /// <value><see langword=\"true\" /> if file logging should be configured; otherwise, <see langword=\"false\" />.</value>\n    public bool ConfigureFileLogging { get; set; } = true;\n\n    /// <summary>\n    /// Gets or sets a value indicating whether to assume homogeneous silos for testing purposes.\n    /// </summary>\n    /// <value><see langword=\"true\" /> if the cluster should assume homogeneous silos; otherwise, <see langword=\"false\" />.</value>\n    public bool AssumeHomogenousSilosForTesting { get; set; }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether each silo should host a gateway.\n    /// </summary>\n    /// <value><see langword=\"true\" /> if each silo should host a gateway; otherwise, <see langword=\"false\" />.</value>\n    public bool GatewayPerSilo { get; set; } = true;\n\n    /// <summary>\n    /// Gets the silo host configuration delegates.\n    /// </summary>\n    /// <value>The silo host configuration delegates.</value>\n    public List<Action<InProcessTestSiloSpecificOptions, IHostApplicationBuilder>> SiloHostConfigurationDelegates { get; } = [];\n\n    /// <summary>\n    /// Gets the client host configuration delegates.\n    /// </summary>\n    /// <value>The client host configuration delegates.</value>\n    public List<Action<IHostApplicationBuilder>> ClientHostConfigurationDelegates { get; } = [];\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcTestSiloSpecificOptions.cs",
    "content": "namespace Orleans.TestingHost;\n\n/// <summary>\n/// Configuration overrides for individual silos.\n/// </summary>\npublic sealed class InProcessTestSiloSpecificOptions\n{\n    /// <summary>\n    /// Gets or sets the silo port.\n    /// </summary>\n    /// <value>The silo port.</value>\n    public int SiloPort { get; set; }\n\n    /// <summary>\n    /// Gets or sets the gateway port.\n    /// </summary>\n    /// <value>The gateway port.</value>\n    public int GatewayPort { get; set; }\n\n    /// <summary>\n    /// Gets or sets the name of the silo.\n    /// </summary>\n    /// <value>The name of the silo.</value>\n    public string SiloName { get; set; }\n\n    /// <summary>\n    /// Creates an instance of the <see cref=\"TestSiloSpecificOptions\"/> class.\n    /// </summary>\n    /// <param name=\"testCluster\">The test cluster.</param>\n    /// <param name=\"testClusterOptions\">The test cluster options.</param>\n    /// <param name=\"instanceNumber\">The instance number.</param>\n    /// <param name=\"assignNewPort\">if set to <see langword=\"true\" />, assign a new port for the silo.</param>\n    /// <returns>The options.</returns>\n    public static InProcessTestSiloSpecificOptions Create(InProcessTestCluster testCluster, InProcessTestClusterOptions testClusterOptions, int instanceNumber, bool assignNewPort = false)\n    {\n        var result = new InProcessTestSiloSpecificOptions\n        {\n            SiloName = $\"Silo_{instanceNumber}\",\n        };\n\n        if (assignNewPort)\n        {\n            var (siloPort, gatewayPort) = testCluster.PortAllocator.AllocateConsecutivePortPairs(1);\n            result.SiloPort = siloPort;\n            result.GatewayPort = (instanceNumber == 0 || testClusterOptions.GatewayPerSilo) ? gatewayPort : 0;\n        }\n        else\n        {\n            result.SiloPort = testClusterOptions.BaseSiloPort + instanceNumber;\n            result.GatewayPort = (instanceNumber == 0 || testClusterOptions.GatewayPerSilo) ? testClusterOptions.BaseGatewayPort + instanceNumber : 0;\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcess/InProcessGrainDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost.InProcess;\ninternal sealed class InProcessGrainDirectory(Func<SiloAddress, SiloStatus> getSiloStatus) : IGrainDirectory\n{\n    private readonly ConcurrentDictionary<GrainId, GrainAddress> _entries = [];\n\n    public Task<GrainAddress?> Lookup(GrainId grainId)\n    {\n        if (_entries.TryGetValue(grainId, out var result) && !IsSiloDead(result))\n        {\n            return Task.FromResult<GrainAddress?>(result); \n        }\n\n        return Task.FromResult<GrainAddress?>(null);\n    }\n\n    public Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress)\n    {\n        ArgumentNullException.ThrowIfNull(address);\n\n        var result = _entries.AddOrUpdate(\n            address.GrainId,\n            static (grainId, state) => state.Address,\n            static (grainId, existing, state) =>\n            {\n                if (existing is null || state.PreviousAddress is { } prev && existing.Matches(prev) || state.Self.IsSiloDead(existing))\n                {\n                    return state.Address;\n                }\n\n                return existing;\n            },\n            (Self: this, Address: address, PreviousAddress: previousAddress));\n\n        if (result is null || IsSiloDead(result))\n        {\n            return Task.FromResult<GrainAddress?>(null);\n        }\n\n        return Task.FromResult<GrainAddress?>(result);\n    }\n\n    public Task<GrainAddress?> Register(GrainAddress address) => Register(address, null);\n\n    public Task Unregister(GrainAddress address)\n    {\n        if (!((IDictionary<GrainId, GrainAddress>)_entries).Remove(KeyValuePair.Create(address.GrainId, address)))\n        {\n            if (_entries.TryGetValue(address.GrainId, out var existing) && (existing.Matches(address) || IsSiloDead(existing)))\n            {\n                ((IDictionary<GrainId, GrainAddress>)_entries).Remove(KeyValuePair.Create(existing.GrainId, existing));\n            }\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public Task UnregisterSilos(List<SiloAddress> siloAddresses)\n    {\n        foreach (var entry in _entries)\n        {\n            foreach (var silo in siloAddresses)\n            {\n                if (silo.Equals(entry.Value.SiloAddress))\n                {\n                    ((IDictionary<GrainId, GrainAddress>)_entries).Remove(entry);\n                }\n            }\n        }\n\n        return Task.CompletedTask;\n    }\n\n    private bool IsSiloDead(GrainAddress existing) => existing.SiloAddress is not { } address || getSiloStatus(address) is SiloStatus.Dead or SiloStatus.None;\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcess/InProcessMembershipTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Orleans.Runtime;\nusing System.Globalization;\nusing System.Threading.Tasks;\nusing Orleans.Messaging;\n\nnamespace Orleans.TestingHost.InProcess;\n\n/// <summary>\n/// An in-memory implementation of <see cref=\"IMembershipTable\"/> for testing purposes.\n/// </summary>\ninternal sealed class InProcessMembershipTable(string clusterId) : IMembershipTable, IGatewayListProvider\n{\n    private readonly Table _table = new();\n    private readonly string _clusterId = clusterId;\n\n    public TimeSpan MaxStaleness => TimeSpan.Zero;\n    public bool IsUpdatable => true;\n\n    public Task InitializeMembershipTable(bool tryInitTableVersion) => Task.CompletedTask;\n\n    public Task DeleteMembershipTableEntries(string clusterId)\n    {\n        if (string.Equals(_clusterId, clusterId, StringComparison.Ordinal))\n        {\n            _table.Clear();\n        }\n\n        return Task.CompletedTask;\n    }\n\n    public Task<MembershipTableData> ReadRow(SiloAddress key) => Task.FromResult(_table.Read(key));\n\n    public Task<MembershipTableData> ReadAll() => Task.FromResult(_table.ReadAll());\n\n    public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion) => Task.FromResult(_table.Insert(entry, tableVersion));\n\n    public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) => Task.FromResult(_table.Update(entry, etag, tableVersion));\n\n    public Task UpdateIAmAlive(MembershipEntry entry)\n    {\n        _table.UpdateIAmAlive(entry);\n        return Task.CompletedTask;\n    }\n\n    public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n    {\n        _table.CleanupDefunctSiloEntries(beforeDate);\n        return Task.CompletedTask;\n    }\n\n    public Task InitializeGatewayListProvider() => Task.CompletedTask;\n\n    public Task<IList<Uri>> GetGateways()\n    {\n        var table = _table.ReadAll();\n        var result = table.Members\n           .Where(x => x.Item1.Status == SiloStatus.Active && x.Item1.ProxyPort != 0)\n           .Select(x =>\n            {\n                var entry = x.Item1;\n                return SiloAddress.New(entry.SiloAddress.Endpoint.Address, entry.ProxyPort, entry.SiloAddress.Generation).ToGatewayUri();\n            }).ToList();\n        return Task.FromResult<IList<Uri>>(result);\n    }\n\n    public SiloStatus GetSiloStatus(SiloAddress address) => _table.GetSiloStatus(address);\n\n    private sealed class Table\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock _lock = new();\n#else\n        private readonly object _lock = new();\n#endif\n        private readonly Dictionary<SiloAddress, (MembershipEntry Entry, string ETag)> _table = [];\n        private TableVersion _tableVersion;\n        private long _lastETagCounter;\n\n        public Table()\n        {\n            _tableVersion = new TableVersion(0, NewETag());\n        }\n        public SiloStatus GetSiloStatus(SiloAddress key)\n        {\n            lock (_lock)\n            {\n                return _table.TryGetValue(key, out var data) ? data.Entry.Status : SiloStatus.None;\n            }\n        }\n\n        public MembershipTableData Read(SiloAddress key)\n        {\n            lock (_lock)\n            {\n                return _table.TryGetValue(key, out var data) ?\n                    new MembershipTableData(Tuple.Create(data.Entry.Copy(), data.ETag), _tableVersion)\n                    : new MembershipTableData(_tableVersion);\n            }\n        }\n\n        public MembershipTableData ReadAll()\n        {\n            lock (_lock)\n            {\n                return new MembershipTableData(_table.Values.Select(data => Tuple.Create(data.Entry.Copy(), data.ETag)).ToList(), _tableVersion);\n            }\n        }\n\n        public TableVersion ReadTableVersion() => _tableVersion;\n\n        public bool Insert(MembershipEntry entry, TableVersion version)\n        {\n            lock (_lock)\n            {\n                if (_table.TryGetValue(entry.SiloAddress, out var data))\n                {\n                    return false;\n                }\n\n                if (!_tableVersion.VersionEtag.Equals(version.VersionEtag))\n                {\n                    return false;\n                }\n\n                _table[entry.SiloAddress] = (entry.Copy(), _lastETagCounter++.ToString(CultureInfo.InvariantCulture));\n                _tableVersion = new TableVersion(version.Version, NewETag());\n                return true;\n            }\n        }\n\n        public bool Update(MembershipEntry entry, string etag, TableVersion version)\n        {\n            lock (_lock)\n            {\n                if (!_table.TryGetValue(entry.SiloAddress, out var data))\n                {\n                    return false;\n                }\n\n                if (!data.ETag.Equals(etag) || !_tableVersion.VersionEtag.Equals(version.VersionEtag))\n                {\n                    return false;\n                }\n\n                _table[entry.SiloAddress] = (entry.Copy(), _lastETagCounter++.ToString(CultureInfo.InvariantCulture));\n                _tableVersion = new TableVersion(version.Version, NewETag());\n                return true;\n            }\n        }\n\n        public void UpdateIAmAlive(MembershipEntry entry)\n        {\n            lock (_lock)\n            {\n                if (!_table.TryGetValue(entry.SiloAddress, out var data))\n                {\n                    return;\n                }\n\n                data.Entry.IAmAliveTime = entry.IAmAliveTime;\n                _table[entry.SiloAddress] = (data.Entry, NewETag());\n            }\n        }\n\n        public void CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            lock (_lock)\n            {\n                var entries = _table.Values.ToList();\n                foreach (var (entry, _) in entries)\n                {\n                    if (entry.Status == SiloStatus.Dead\n                        && new DateTime(Math.Max(entry.IAmAliveTime.Ticks, entry.StartTime.Ticks), DateTimeKind.Utc) < beforeDate)\n                    {\n                        _table.Remove(entry.SiloAddress, out _);\n                        continue;\n                    }\n                }\n            }\n        }\n\n        internal void Clear()\n        {\n            lock (_lock)\n            {\n                _table.Clear();\n            }\n        }\n\n        public override string ToString() => $\"Table = {ReadAll()}, ETagCounter={_lastETagCounter}\";\n\n        private string NewETag() => _lastETagCounter++.ToString(CultureInfo.InvariantCulture);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/InProcessSiloHandle.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Represents a handle to a silo that is deployed in the same process and AppDomain.\n    /// </summary>\n    public class InProcessSiloHandle : SiloHandle\n    {\n        private bool isActive = true;\n        \n        /// <summary>Gets a reference to the silo host.</summary>\n        public IHost SiloHost { get; init; }\n\n        /// <summary>\n        /// Gets the silo's service provider.\n        /// </summary>\n        public IServiceProvider ServiceProvider => SiloHost.Services;\n\n        /// <inheritdoc />\n        public override bool IsActive => isActive;\n\n        /// <summary>\n        /// Create a silo handle.\n        /// </summary>\n        /// <param name=\"siloName\">Name of the silo.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <param name=\"postConfigureHostBuilder\">An optional delegate which is invoked just prior to building the host builder.</param>\n        /// <returns>The silo handle.</returns>\n        public static async Task<InProcessSiloHandle> CreateAsync(\n            string siloName,\n            IConfiguration configuration,\n            Action<IHostBuilder> postConfigureHostBuilder = null)\n        {\n            var host = await Task.Run(async () =>\n            {\n                var result = TestClusterHostFactory.CreateSiloHost(siloName, configuration, postConfigureHostBuilder);\n                await result.StartAsync();\n                return result;\n            });\n\n            var retValue = new InProcessSiloHandle\n            {\n                Name = siloName,\n                SiloHost = host,\n                SiloAddress = host.Services.GetRequiredService<ILocalSiloDetails>().SiloAddress,\n                GatewayAddress = host.Services.GetRequiredService<ILocalSiloDetails>().GatewayAddress,\n            };\n\n            return retValue;\n        }\n\n        /// <inheritdoc />\n        public override async Task StopSiloAsync(bool stopGracefully)\n        {\n            using var cancellation = new CancellationTokenSource();\n            var ct = cancellation.Token;\n\n            if (!stopGracefully)\n                cancellation.Cancel();\n\n            await StopSiloAsync(ct);\n        }\n\n        /// <inheritdoc />\n        public override async Task StopSiloAsync(CancellationToken ct)\n        {\n            if (!IsActive) return;\n\n            try\n            {\n                await Task.Run(() => this.SiloHost.StopAsync(ct));\n            }\n            catch (Exception exc)\n            {\n                WriteLog(exc);\n                throw;\n            }\n            finally\n            {\n                this.isActive = false;\n            }\n        }\n\n        /// <inheritdoc />\n        protected override void Dispose(bool disposing)\n        {\n            if (!this.IsActive) return;\n\n            if (disposing)\n            {\n                try\n                {\n                    StopSiloAsync(true).GetAwaiter().GetResult();\n                }\n                catch\n                {\n                }\n\n                this.SiloHost?.Dispose();\n            }\n        }\n\n        /// <inheritdoc />\n        public override async ValueTask DisposeAsync()\n        {\n            if (!this.IsActive) return;\n\n            try\n            {\n                await StopSiloAsync(true).ConfigureAwait(false);\n            }\n            finally\n            {\n                if (this.SiloHost is IAsyncDisposable asyncDisposable)\n                {\n                    await asyncDisposable.DisposeAsync().ConfigureAwait(false);\n                }\n            }\n        }\n\n        private static void WriteLog(object value)\n        {\n            Console.WriteLine(value?.ToString());\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/Logging/FileLogger.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing System.Threading;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost.Logging\n{\n    /// <summary>\n    /// The log output which all <see cref=\"FileLogger\"/> share to log messages to \n    /// </summary>\n    public class FileLoggingOutput : IDisposable\n    {\n        private static readonly ConcurrentDictionary<FileLoggingOutput, object> Instances = new();\n        private readonly TimeSpan flushInterval = Debugger.IsAttached ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromSeconds(1);\n#if NET9_0_OR_GREATER\n        private readonly Lock lockObj = new();\n#else\n        private readonly object lockObj = new();\n#endif\n        private readonly string logFileName;\n        private DateTime lastFlush = DateTime.UtcNow;\n        private StreamWriter logOutput;\n\n        /// <summary>\n        /// Initializes static members of the <see cref=\"FileLoggingOutput\"/> class.\n        /// </summary>\n        static FileLoggingOutput()\n        {\n            AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;\n\n            static void CurrentDomain_ProcessExit(object sender, EventArgs args)\n            {\n                foreach (var instance in Instances)\n                {\n                    instance.Key.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FileLoggingOutput\"/> class.\n        /// </summary>\n        /// <param name=\"fileName\">Name of the log file.</param>\n        public FileLoggingOutput(string fileName)\n        {\n            this.logFileName = fileName;\n            logOutput = new StreamWriter(File.Open(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite), Encoding.UTF8);\n            Instances[this] = null;\n        }\n\n        /// <summary>\n        /// Logs a message.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of <paramref name=\"state\"/>.</typeparam>\n        /// <param name=\"logLevel\">The log level.</param>\n        /// <param name=\"eventId\">The event identifier.</param>\n        /// <param name=\"state\">The state.</param>\n        /// <param name=\"exception\">The exception.</param>\n        /// <param name=\"formatter\">The formatter.</param>\n        /// <param name=\"category\">The category.</param>\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,\n            Func<TState, Exception, string> formatter, string category)\n        {\n            var logMessage = FormatMessage(DateTime.UtcNow, logLevel, category, formatter(state, exception), exception, eventId);\n            lock (this.lockObj)\n            {\n                if (this.logOutput == null) return;\n\n                this.logOutput.WriteLine(logMessage);\n                var now = DateTime.UtcNow;\n                if (now - this.lastFlush > flushInterval)\n                {\n                    this.lastFlush = now;\n                    this.logOutput.Flush();\n                }\n            }\n        }\n\n        private static string FormatMessage(\n            DateTime timestamp,\n            LogLevel logLevel,\n            string caller,\n            string message,\n            Exception exception,\n            EventId errorCode)\n        {\n            if (logLevel == LogLevel.Error)\n                message = \"!!!!!!!!!! \" + message;\n\n            var exc = LogFormatter.PrintException(exception);\n            var msg = string.Format(\"[{0} {1}\\t{2}\\t{3}\\t{4}]\\t{5}\\t{6}\",\n                LogFormatter.PrintDate(timestamp),           //0\n                Environment.CurrentManagedThreadId,   //1\n                logLevel.ToString(),    //2\n                errorCode.ToString(),                              //3\n                caller,                                 //4\n                message,                                //5\n                exc);      //6\n\n            return msg;\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            Dispose(true);\n        }\n\n        private void Dispose(bool disposing)\n        {\n            try\n            {\n                lock (this.lockObj)\n                {\n                    if (this.logOutput is StreamWriter output)\n                    {\n                        this.logOutput = null;\n                        _ = Instances.TryRemove(this, out _);\n\n                        // Dispose the output, which will flush all buffers.\n                        output.Dispose();\n                    }\n                }\n            }\n            catch (Exception exc)\n            {\n                var msg = string.Format(\"Ignoring error closing log file {0} - {1}\", this.logFileName,\n                    LogFormatter.PrintException(exc));\n                Console.WriteLine(msg);\n            }\n        }\n    }\n\n    /// <summary>\n    /// File logger, which logs messages to a file.\n    /// </summary>\n    public class FileLogger : ILogger\n    {\n        private readonly FileLoggingOutput output;\n        private readonly string category;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FileLogger\"/> class.\n        /// </summary>\n        /// <param name=\"output\">The output logger.</param>\n        /// <param name=\"category\">The category.</param>\n        public FileLogger(FileLoggingOutput output, string category)\n        {\n            this.category = category;\n            this.output = output;\n        }\n\n        /// <inheritdoc />\n        public IDisposable BeginScope<TState>(TState state)\n        {\n            return NullScope.Instance;\n        }\n\n        /// <inheritdoc />\n        public bool IsEnabled(LogLevel logLevel)\n        {\n            return true;\n        }\n\n        /// <inheritdoc />\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n        {\n            this.output.Log(logLevel, eventId, state, exception, formatter, this.category);\n\n        }\n\n        private class NullScope : IDisposable\n        {\n            public static NullScope Instance { get; } = new NullScope();\n\n            private NullScope()\n            {\n            }\n\n            public void Dispose()\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/Logging/FileLoggerProvider.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.TestingHost.Logging\n{\n    /// <summary>\n    /// <see cref=\"ILoggerProvider\"/> which outputs to a log file.\n    /// </summary>\n    public class FileLoggerProvider : ILoggerProvider\n    {\n        private readonly FileLoggingOutput output;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FileLoggerProvider\"/> class.\n        /// </summary>\n        /// <param name=\"filePath\">The log file path.</param>\n        public FileLoggerProvider(string filePath)\n        {\n            this.output = new FileLoggingOutput(filePath);\n        }\n\n        /// <inheritdoc />\n        public ILogger CreateLogger(string categoryName)\n        {\n            return new FileLogger(this.output, categoryName);\n        }\n\n        /// <inheritdoc />\n        public void Dispose()\n        {\n            this.output.Dispose();\n        }\n    }\n\n    /// <summary>\n    /// Extension methods to configure ILoggingBuilder with FileLoggerProvider\n    /// </summary>\n    public static class FileLoggerProviderExtensions\n    {\n        /// <summary>\n        /// Add <see cref=\"FileLoggerProvider\"/> to <paramref name=\"builder\"/>\n        /// </summary>\n        /// <param name=\"builder\">The logging builder.</param>\n        /// <param name=\"filePathName\">The log file path</param>\n        /// <returns>The logging builder.</returns>\n        public static ILoggingBuilder AddFile(\n            this ILoggingBuilder builder,\n            string filePathName)\n        {\n            if (builder == null)\n                throw new ArgumentNullException(nameof(builder));\n            builder.AddProvider(new FileLoggerProvider(filePathName));\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/Orleans.TestingHost.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.TestingHost</PackageId>\n    <Title>Microsoft Orleans Testing Host Library</Title>\n    <Description>Microsoft Orleans library for hosting a silo in a testing project.</Description>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <!-- DurableJobs is pre-release, so we are suppressing NU5104 -->\n    <NoWarn>$(NoWarn);NU5104</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Persistence.Memory\\Orleans.Persistence.Memory.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.DurableJobs\\Orleans.DurableJobs.csproj\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.GrainDirectory.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Placement.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.TestingHost/SiloHandle.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Represents a handle to a silo that is remotely deployed\n    /// </summary>\n    public abstract class SiloHandle : IDisposable, IAsyncDisposable\n    {\n        /// <summary> Get or set configuration of the cluster </summary>\n        public TestClusterOptions ClusterOptions { get; set; }\n\n        /// <summary> Gets or sets the instance number within the cluster.</summary>\n        public short InstanceNumber { get; set; }\n\n        /// <summary> Get or set the name of the silo </summary>\n        public string Name { get; set; }\n\n        /// <summary>Get or set the address of the silo</summary>\n        public SiloAddress SiloAddress { get; set; }\n\n        ///// <summary>Get the proxy address of the silo</summary>\n        public SiloAddress GatewayAddress { get; set; }\n\n        /// <summary>Gets whether the remote silo is expected to be active</summary>\n        public abstract bool IsActive { get; }\n\n        /// <summary>Stop the remote silo</summary>\n        /// <param name=\"stopGracefully\">Specifies whether the silo should be stopped gracefully or abruptly.</param>\n        public abstract Task StopSiloAsync(bool stopGracefully);\n\n        /// <summary>Stop the remote silo. This method cannot be use with AppDomain</summary>\n        /// <param name=\"ct\">Specifies the cancellation token to use for the shutdown sequence</param>\n        public abstract Task StopSiloAsync(CancellationToken ct);\n\n        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>\n        public void Dispose()\n        {\n            this.Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (!this.IsActive) return;\n\n            // Do not attempt to perform expensive blocking operations in the finalizer thread.\n            // Concrete SiloHandle implementations can do have their own cleanup functionality\n            if (disposing)\n            {\n                StopSiloAsync(true).GetAwaiter().GetResult();\n            }\n        }\n\n        /// <inheritdoc />\n        public abstract ValueTask DisposeAsync();\n\n        /// <inheritdoc />\n        ~SiloHandle()\n        {\n            Dispose(false);\n        }\n\n        /// <inheritdoc />\n        public override string ToString()\n        {\n            return SiloAddress.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/StandaloneSiloHandle.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// A silo handle and factory which spawns a separate process for each silo.\n    /// </summary>\n    public class StandaloneSiloHandle : SiloHandle\n    {\n        private readonly StringBuilder _outputBuilder;\n        private readonly TaskCompletionSource<bool> _startedEvent;\n        private readonly TaskCompletionSource<bool> _outputCloseEvent;\n        private readonly StringBuilder _errorBuilder;\n        private readonly TaskCompletionSource<bool> _errorCloseEvent;\n        private readonly EventHandler _processExitHandler;\n        private bool isActive = true;\n        private Task _runTask;\n\n        /// <summary>\n        /// The configuration key used to identify the process to launch.\n        /// </summary>\n        public const string ExecutablePathConfigKey = \"ExecutablePath\";\n\n        /// <summary>Gets a reference to the silo host.</summary>\n        private Process Process { get; set; }\n\n        /// <inheritdoc />\n        public override bool IsActive => isActive;\n        \n        public StandaloneSiloHandle(string siloName, IConfiguration configuration, string executablePath)\n        {\n            if (string.IsNullOrWhiteSpace(executablePath) || !File.Exists(executablePath))\n            {\n                throw new ArgumentException(\"Must provide at least one assembly path\");\n            }\n\n            Name = siloName;\n\n            // If the debugger is attached to this process, give it an opportunity to attach to the remote process.\n            if (Debugger.IsAttached)\n            {\n                configuration[\"AttachDebugger\"] = \"true\";\n            }\n\n            var serializedConfiguration = TestClusterHostFactory.SerializeConfiguration(configuration);\n\n            Process = new Process();\n            Process.StartInfo = new ProcessStartInfo(executablePath)\n            {\n                ArgumentList = { Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), serializedConfiguration },\n                CreateNoWindow = true,\n                RedirectStandardError = true,\n                RedirectStandardOutput = true,\n                RedirectStandardInput = true,\n                WorkingDirectory = new FileInfo(executablePath).Directory.FullName,\n                UseShellExecute = false,\n            };\n\n            _outputBuilder = new StringBuilder();\n            _outputCloseEvent = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n            _startedEvent = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            Process.OutputDataReceived += (s, e) =>\n            {\n                if (e.Data == null)\n                {\n                    _outputCloseEvent.SetResult(true);\n                }\n                else\n                {\n                    // Read standard output from the process for status updates.\n                    if (!_startedEvent.Task.IsCompleted)\n                    {\n                        if (e.Data.StartsWith(StandaloneSiloHost.SiloAddressLog, StringComparison.Ordinal))\n                        {\n                            SiloAddress = Orleans.Runtime.SiloAddress.FromParsableString(e.Data[StandaloneSiloHost.SiloAddressLog.Length..]);\n                        }\n                        else if (e.Data.StartsWith(StandaloneSiloHost.GatewayAddressLog, StringComparison.Ordinal))\n                        {\n                            GatewayAddress = Orleans.Runtime.SiloAddress.FromParsableString(e.Data[StandaloneSiloHost.GatewayAddressLog.Length..]);\n                        }\n                        else if (e.Data.StartsWith(StandaloneSiloHost.StartedLog, StringComparison.Ordinal))\n                        {\n                            _startedEvent.TrySetResult(true);\n                        }\n                    }\n\n                    lock (_outputBuilder)\n                    {\n                        _outputBuilder.AppendLine(e.Data);\n                    }\n                }\n            };\n\n            _errorBuilder = new StringBuilder();\n            _errorCloseEvent = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n           Process.ErrorDataReceived += (s, e) =>\n           {\n                if (e.Data == null)\n                {\n                    _errorCloseEvent.SetResult(true);\n                }\n                else\n                {\n                   lock (_errorBuilder)\n                   {\n                       _errorBuilder.AppendLine(e.Data);\n                   }\n                }\n           };\n\n            var selfReference = new WeakReference<StandaloneSiloHandle>(this);\n            _processExitHandler = (o, e) =>\n            {\n                if (selfReference.TryGetTarget(out var target))\n                {\n                    try\n                    {\n                        target.Process.Kill(entireProcessTree: true);\n                    }\n                    catch\n                    {\n\n                    }\n                }\n            };\n            AppDomain.CurrentDomain.ProcessExit += _processExitHandler;\n        }\n\n        /// <summary>\n        /// Spawns a new process to host a silo, using the executable provided in the configuration's \"ExecutablePath\" property as the entry point.\n        /// </summary>\n        public static async Task<SiloHandle> Create(\n            string siloName,\n            IConfiguration configuration)\n        {\n            var executablePath = configuration[ExecutablePathConfigKey];\n            var result = new StandaloneSiloHandle(siloName, configuration, executablePath);\n            await result.StartAsync();\n            return result;\n        }\n\n        /// <summary>\n        /// Creates a delegate which spawns a silo in a new process, using the provided executable as the entry point for that silo.\n        /// </summary>\n        /// <param name=\"executablePath\">The entry point for spawned silos.</param>\n        public static Func<string, IConfiguration, Task<SiloHandle>> CreateDelegate(string executablePath)\n        {\n            return async (siloName, configuration) =>\n            {\n                var result = new StandaloneSiloHandle(siloName, configuration, executablePath);\n                await result.StartAsync();\n                return result;\n            };\n        }\n\n        /// <summary>\n        /// Creates a delegate which spawns a silo in a new process, with the provided assembly (or its executable counterpart, if it is a library) being the entry point for that silo.\n        /// </summary>\n        /// <param name=\"assembly\">The entry point for spawned silos. If the provided assembly is a library (dll), then its executable sibling assembly will be invoked instead.</param>\n        public static Func<string, IConfiguration, Task<SiloHandle>> CreateForAssembly(Assembly assembly)\n        {\n            var executablePath = assembly.Location;\n            var originalFileInfo = new FileInfo(executablePath);\n            if (!originalFileInfo.Exists)\n            {\n                throw new FileNotFoundException($\"Cannot find assembly location for assembly {assembly}. Location property returned \\\"{executablePath}\\\"\");\n            }\n\n            FileInfo target;\n            if (string.Equals(\".dll\", originalFileInfo.Extension))\n            {\n                if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                {\n                    target = new FileInfo(Path.GetFileNameWithoutExtension(originalFileInfo.FullName) + \".exe\");\n                }\n                else\n                {\n                    // On unix-like operating systems, executables generally do not have an extension.\n                    target = new FileInfo(Path.GetFileNameWithoutExtension(originalFileInfo.FullName));\n                }\n            }\n            else\n            {\n                target = originalFileInfo;\n            }\n\n            if (!target.Exists)\n            {\n                throw new FileNotFoundException($\"Target assembly \\\"{target.FullName}\\\" does not exist\");\n            }\n\n            return CreateDelegate(target.FullName);\n        }\n\n        private async Task StartAsync()\n        {\n            try\n            {\n                if (!Process.Start())\n                {\n                    throw new InvalidOperationException(\"No process was started\");\n                }\n            }\n            catch (Exception)\n            {\n                isActive = false;\n                throw;\n            }\n\n            _runTask = Task.Run(async () =>\n            {\n                try\n                {\n                    Process.BeginOutputReadLine();\n                    Process.BeginErrorReadLine();\n\n                    var waitForExit = Task.Factory.StartNew(\n                        process => ((Process)process).WaitForExit(-1),\n                        Process,\n                        CancellationToken.None,\n                        TaskCreationOptions.LongRunning | TaskCreationOptions.RunContinuationsAsynchronously,\n                        TaskScheduler.Default);\n                    await Task.WhenAll(waitForExit, _outputCloseEvent.Task, _errorCloseEvent.Task);\n\n                    if (!await waitForExit)\n                    {\n                        try\n                        {\n                            Process.Kill();\n                        }\n                        catch\n                        {\n                        }\n                    }\n                }\n                catch (Exception exception)\n                {\n                    _startedEvent.TrySetException(exception);\n                }\n            });\n\n            var task = await Task.WhenAny(_startedEvent.Task, _outputCloseEvent.Task, _errorCloseEvent.Task);\n            if (!ReferenceEquals(task, _startedEvent.Task))\n            {\n                string output;\n                lock (_outputBuilder)\n                {\n                    output = _outputBuilder.ToString();\n                }\n\n                string error;\n                lock (_errorBuilder)\n                {\n                    error = _errorBuilder.ToString();\n                }\n\n                throw new Exception($\"Process failed to start correctly.\\nOutput:\\n{output}\\nError:\\n{error}\");\n            }\n        }\n\n        /// <inheritdoc />\n        public override async Task StopSiloAsync(bool stopGracefully)\n        {\n            using var cancellation = new CancellationTokenSource();\n            var ct = cancellation.Token;\n\n            if (!stopGracefully) cancellation.Cancel();\n\n            await StopSiloAsync(ct);\n        }\n\n        /// <inheritdoc />\n        public override async Task StopSiloAsync(CancellationToken ct)\n        {\n            if (!IsActive) return;\n\n            try\n            {\n                if (ct.IsCancellationRequested)\n                {\n                    this.Process?.Kill();\n                }\n                else\n                {\n                    using var registration = ct.Register(() =>\n                    {\n                        var process = this.Process;\n                        if (process is not null)\n                        {\n                            process.Kill();\n                        }\n                    });\n\n                    await this.Process.StandardInput.WriteLineAsync(StandaloneSiloHost.ShutdownCommand);\n                    using var linkedCts = new CancellationTokenSource();\n                    await Task.WhenAny(_runTask, Task.Delay(TimeSpan.FromMinutes(2), linkedCts.Token));\n                }\n            }\n            finally\n            {\n                this.isActive = false;\n            }\n        }\n\n        /// <inheritdoc />\n        protected override void Dispose(bool disposing)\n        {\n            if (!this.IsActive) return;\n\n            if (disposing)\n            {\n                try\n                {\n                    StopSiloAsync(true).GetAwaiter().GetResult();\n                }\n                catch\n                {\n                }\n\n                this.Process?.Dispose();\n            }\n\n            AppDomain.CurrentDomain.ProcessExit -= _processExitHandler;\n        }\n\n        /// <inheritdoc />\n        public override async ValueTask DisposeAsync()\n        {\n            if (!this.IsActive) return;\n\n            await StopSiloAsync(true).ConfigureAwait(false);\n            this.Process?.Dispose();\n            AppDomain.CurrentDomain.ProcessExit -= _processExitHandler;\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/StandaloneSiloHost.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// The entry point for standalone silo processes. See <see cref=\"StandaloneSiloHandle\" />.\n    /// </summary>\n    public static class StandaloneSiloHost\n    {\n        public const string SiloAddressLog = \"#### SILO \";\n        public const string GatewayAddressLog = \"#### GATEWAY \";\n        public const string StartedLog = \"#### STARTED\";\n        public const string ShutdownCommand = \"#### SHUTDOWN\";\n\n        public static async Task Main(string[] args)\n        {\n            if (args.Length < 2)\n            {\n                Console.Error.WriteLine(\"Expected JSON-serialized configuration to be provided as an argument\");\n            }\n\n            var monitorProcessId = int.Parse(args[0], NumberStyles.Integer, CultureInfo.InvariantCulture);\n            var serializedConfiguration = args[1];\n            var configuration = TestClusterHostFactory.DeserializeConfiguration(serializedConfiguration);\n            if (string.Equals(configuration[\"AttachDebugger\"], \"true\", StringComparison.OrdinalIgnoreCase))\n            {\n                Debugger.Launch();\n            }\n\n            var name = configuration[\"SiloName\"];\n            using var host = TestClusterHostFactory.CreateSiloHost(name, configuration);\n            try\n            {\n                var cts = new CancellationTokenSource();\n                Console.CancelKeyPress += (sender, eventArgs) => cts.Cancel();\n\n                ListenForShutdownCommand(cts);\n                MonitorParentProcess(monitorProcessId);\n\n                await host.StartAsync(cts.Token);\n\n                // This is a special marker line.\n                var localSiloDetails = (ILocalSiloDetails)host.Services.GetService(typeof(ILocalSiloDetails));\n                Console.WriteLine($\"{SiloAddressLog}{localSiloDetails.SiloAddress.ToParsableString()}\");\n                Console.WriteLine($\"{GatewayAddressLog}{localSiloDetails.GatewayAddress.ToParsableString()}\");\n                Console.WriteLine(StartedLog);\n\n                await cts.Token.WhenCancelled();\n\n                await host.StopAsync(CancellationToken.None);\n            }\n            finally\n            {\n                if (host is IAsyncDisposable asyncDisposable)\n                {\n                    await asyncDisposable.DisposeAsync();\n                }\n                else\n                {\n                    host.Dispose();\n                }\n            }\n        }\n\n        private static void MonitorParentProcess(int monitorProcessId)\n        {\n            if (monitorProcessId > 0)\n            {\n                Console.WriteLine($\"Monitoring parent process {monitorProcessId}\");\n                Process.GetProcessById(monitorProcessId).Exited += (o, a) =>\n                {\n                    Console.Error.WriteLine($\"Parent process {monitorProcessId} has exited\");\n                    Environment.Exit(0);\n                };\n\n                _ = Task.Factory.StartNew(async _ =>\n                {\n                    try\n                    {\n                        while (true)\n                        {\n                            await Task.Delay(5000);\n                            if (!Array.Exists(Process.GetProcesses(), p => p.Id == monitorProcessId))\n                            {\n                                Console.Error.WriteLine($\"Parent process {monitorProcessId} has exited\");\n                                Environment.Exit(0);\n                            }\n                        }\n                    }\n                    catch\n                    {\n                        // Ignore all errors.\n                    }\n                },\n                null,\n                CancellationToken.None,\n                TaskCreationOptions.LongRunning,\n                TaskScheduler.Default);\n            }\n        }\n\n        private static void ListenForShutdownCommand(CancellationTokenSource cts)\n        {\n            // Start a thread to monitor for the shutdown command from standard input.\n            _ = Task.Factory.StartNew(_ =>\n            {\n                try\n                {\n                    while (true)\n                    {\n                        var text = Console.ReadLine();\n                        if (string.Equals(text, ShutdownCommand, StringComparison.Ordinal))\n                        {\n                            Console.WriteLine(\"Shutdown requested\");\n                            cts.Cancel();\n                            return;\n                        }\n                    }\n                }\n                catch\n                {\n                    // Ignore all errors.\n                }\n            },\n            null,\n            CancellationToken.None,\n            TaskCreationOptions.LongRunning,\n            TaskScheduler.Default);\n        }\n\n        private static Task WhenCancelled(this CancellationToken token)\n        {\n            if (token.IsCancellationRequested)\n            {\n                return Task.CompletedTask;\n            }\n\n            var waitForCancellation = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);\n            token.Register(obj =>\n            {\n                var tcs = (TaskCompletionSource<object>)obj;\n                tcs.TrySetResult(null);\n            }, waitForCancellation);\n\n            return waitForCancellation.Task;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestCluster.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Configuration.Memory;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost.InMemoryTransport;\nusing Orleans.TestingHost.UnixSocketTransport;\nusing System.Net;\nusing Orleans.Statistics;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// A host class for local testing with Orleans using in-process silos. \n    /// Runs a Primary and optionally secondary silos in separate app domains, and client in the main app domain.\n    /// Additional silos can also be started in-process on demand if required for particular test cases.\n    /// </summary>\n    /// <remarks>\n    /// Make sure that your test project references your test grains and test grain interfaces \n    /// projects, and has CopyLocal=True set on those references [which should be the default].\n    /// </remarks>\n    public class TestCluster : IDisposable, IAsyncDisposable\n    {\n        private readonly List<SiloHandle> additionalSilos = new List<SiloHandle>();\n        private readonly TestClusterOptions options;\n        private readonly StringBuilder log = new StringBuilder();\n        private readonly InMemoryTransportConnectionHub _transportHub = new();\n        private bool _disposed;\n        private int startedInstances;\n\n        /// <summary>\n        /// Primary silo handle, if applicable.\n        /// </summary>\n        /// <remarks>This handle is valid only when using Grain-based membership.</remarks>\n        public SiloHandle Primary { get; private set; }\n\n        /// <summary>\n        /// List of handles to the secondary silos.\n        /// </summary>\n        public IReadOnlyList<SiloHandle> SecondarySilos\n        {\n            get\n            {\n                lock (this.additionalSilos)\n                {\n                    return new List<SiloHandle>(this.additionalSilos);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Collection of all known silos.\n        /// </summary>\n        public ReadOnlyCollection<SiloHandle> Silos\n        {\n            get\n            {\n                var result = new List<SiloHandle>();\n                if (this.Primary != null)\n                {\n                    result.Add(this.Primary);\n                }\n\n                lock (this.additionalSilos)\n                {\n                    result.AddRange(this.additionalSilos);\n                }\n\n                return result.AsReadOnly();\n            }\n        }\n\n        /// <summary>\n        /// Options used to configure the test cluster.\n        /// </summary>\n        /// <remarks>This is the options you configured your test cluster with, or the default one. \n        /// If the cluster is being configured via ClusterConfiguration, then this object may not reflect the true settings.\n        /// </remarks>\n        public TestClusterOptions Options => this.options;\n\n        /// <summary>\n        /// The internal client interface.\n        /// </summary>\n        internal IHost ClientHost { get; private set; }\n\n        /// <summary>\n        /// The internal client interface.\n        /// </summary>\n        internal IInternalClusterClient InternalClient => ClientHost?.Services.GetRequiredService<IInternalClusterClient>();\n\n        /// <summary>\n        /// The client.\n        /// </summary>\n        public IClusterClient Client => this.InternalClient;\n\n        /// <summary>\n        /// GrainFactory to use in the tests\n        /// </summary>\n        public IGrainFactory GrainFactory => this.Client;\n\n        /// <summary>\n        /// GrainFactory to use in the tests\n        /// </summary>\n        internal IInternalGrainFactory InternalGrainFactory => this.InternalClient;\n\n        /// <summary>\n        /// Client-side <see cref=\"IServiceProvider\"/> to use in the tests.\n        /// </summary>\n        public IServiceProvider ServiceProvider => this.Client.ServiceProvider;\n\n        /// <summary>\n        /// Delegate used to create and start an individual silo.\n        /// </summary>\n        public Func<string, IConfiguration, Task<SiloHandle>> CreateSiloAsync { private get; set; }\n\n        /// <summary>\n        /// The port allocator.\n        /// </summary>\n        public ITestClusterPortAllocator PortAllocator { get; }\n        \n        /// <summary>\n        /// Configures the test cluster plus client in-process.\n        /// </summary>\n        public TestCluster(\n            TestClusterOptions options,\n            IReadOnlyList<IConfigurationSource> configurationSources,\n            ITestClusterPortAllocator portAllocator)\n        {\n            this.options = options;\n            this.ConfigurationSources = configurationSources.ToArray();\n            this.PortAllocator = portAllocator;\n            this.CreateSiloAsync = DefaultCreateSiloAsync;\n        }\n\n        /// <summary>\n        /// Returns the <see cref=\"IServiceProvider\"/> associated with the given <paramref name=\"silo\"/>.\n        /// </summary>\n        /// <param name=\"silo\">The silo process to the the service provider for.</param>\n        /// <remarks>If <paramref name=\"silo\"/> is <see langword=\"null\"/> one of the existing silos will be picked randomly.</remarks>\n        public IServiceProvider GetSiloServiceProvider(SiloAddress silo = null)\n        {\n            if (silo != null)\n            {\n                var handle = Silos.FirstOrDefault(x => x.SiloAddress.Equals(silo));\n                return handle != null ? ((InProcessSiloHandle)handle).SiloHost.Services :\n                    throw new ArgumentException($\"The provided silo address '{silo}' is unknown.\");\n            }\n            else\n            {\n                var index = Random.Shared.Next(Silos.Count);\n                return ((InProcessSiloHandle)Silos[index]).SiloHost.Services;\n            }\n        }\n\n        /// <summary>\n        /// Deploys the cluster using the specified configuration and starts the client in-process.\n        /// It will start the number of silos defined in <see cref=\"TestClusterOptions.InitialSilosCount\"/>.\n        /// </summary>\n        public void Deploy()\n        {\n            this.DeployAsync().GetAwaiter().GetResult();\n        }\n\n        /// <summary>\n        /// Deploys the cluster using the specified configuration and starts the client in-process.\n        /// </summary>\n        public async Task DeployAsync()\n        {\n            if (this.Primary != null || this.additionalSilos.Count > 0) throw new InvalidOperationException(\"Cluster host already deployed.\");\n\n            AppDomain.CurrentDomain.UnhandledException += ReportUnobservedException;\n\n            try\n            {\n                string startMsg = \"----------------------------- STARTING NEW UNIT TEST SILO HOST: \" + GetType().FullName + \" -------------------------------------\";\n                WriteLog(startMsg);\n                await InitializeAsync();\n\n                if (this.options.InitializeClientOnDeploy)\n                {\n                    await WaitForInitialStabilization();\n                }\n            }\n            catch (TimeoutException te)\n            {\n                FlushLogToConsole();\n                throw new TimeoutException(\"Timeout during test initialization\", te);\n            }\n            catch (Exception ex)\n            {\n                await StopAllSilosAsync();\n\n                Exception baseExc = ex.GetBaseException();\n                FlushLogToConsole();\n\n                if (baseExc is TimeoutException)\n                {\n                    throw new TimeoutException(\"Timeout during test initialization\", ex);\n                }\n\n                // IMPORTANT:\n                // Do NOT re-throw the original exception here, also not as an internal exception inside AggregateException\n                // Due to the way MS tests works, if the original exception is an Orleans exception,\n                // it's assembly might not be loaded yet in this phase of the test.\n                // As a result, we will get \"MSTest: Unit Test Adapter threw exception: Type is not resolved for member XXX\"\n                // and will loose the original exception. This makes debugging tests super hard!\n                // The root cause has to do with us initializing our tests from Test constructor and not from TestInitialize method.\n                // More details: http://dobrzanski.net/2010/09/20/mstest-unit-test-adapter-threw-exception-type-is-not-resolved-for-member/\n                //throw new Exception(\n                //    string.Format(\"Exception during test initialization: {0}\",\n                //        LogFormatter.PrintException(baseExc)));\n                throw;\n            }\n        }\n\n        private async Task WaitForInitialStabilization()\n        {\n            // Poll each silo to check that it knows the expected number of active silos.\n            // If any silo does not have the expected number of active silos in its cluster membership oracle, try again.\n            // If the cluster membership has not stabilized after a certain period of time, give up and continue anyway.\n            var totalWait = Stopwatch.StartNew();\n            while (true)\n            {\n                var silos = this.Silos;\n                var expectedCount = silos.Count;\n                var remainingSilos = expectedCount;\n\n                foreach (var silo in silos)\n                {\n                    var hooks = this.InternalClient.GetTestHooks(silo);\n                    var statuses = await hooks.GetApproximateSiloStatuses();\n                    var activeCount = statuses.Count(s => s.Value == SiloStatus.Active);\n                    if (activeCount != expectedCount) break;\n                    remainingSilos--;\n                }\n\n                if (remainingSilos == 0)\n                {\n                    totalWait.Stop();\n                    break;\n                }\n\n                WriteLog($\"{remainingSilos} silos do not have a consistent cluster view, waiting until stabilization.\");\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n\n                if (totalWait.Elapsed < TimeSpan.FromSeconds(60))\n                {\n                    WriteLog($\"Warning! {remainingSilos} silos do not have a consistent cluster view after {totalWait.ElapsedMilliseconds}ms, continuing without stabilization.\");\n                    break;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get the list of current active silos.\n        /// </summary>\n        /// <returns>List of current silos.</returns>\n        public IEnumerable<SiloHandle> GetActiveSilos()\n        {\n            var additional = new List<SiloHandle>();\n            lock (additionalSilos)\n            {\n                additional.AddRange(additionalSilos);\n            }\n\n            WriteLog(\"GetActiveSilos: Primary={0} + {1} Additional={2}\",\n                Primary, additional.Count, Runtime.Utils.EnumerableToString(additional));\n\n            if (Primary?.IsActive == true) yield return Primary;\n            \n\n            if (additional.Count > 0)\n            foreach (var s in additional)\n                if (s?.IsActive == true)\n                    yield return s;\n        }\n\n        /// <summary>\n        /// Find the silo handle for the specified silo address.\n        /// </summary>\n        /// <param name=\"siloAddress\">Silo address to be found.</param>\n        /// <returns>SiloHandle of the appropriate silo, or <c>null</c> if not found.</returns>\n        public SiloHandle GetSiloForAddress(SiloAddress siloAddress)\n        {\n            var activeSilos = GetActiveSilos().ToList();\n            var ret = activeSilos.Find(s => s.SiloAddress.Equals(siloAddress));\n            return ret;\n        }\n\n        /// <summary>\n        /// Wait for the silo liveness sub-system to detect and act on any recent cluster membership changes.\n        /// </summary>\n        /// <param name=\"didKill\">Whether recent membership changes we done by graceful Stop.</param>\n        public async Task WaitForLivenessToStabilizeAsync(bool didKill = false)\n        {\n            var clusterMembershipOptions = this.ServiceProvider.GetRequiredService<IOptions<ClusterMembershipOptions>>().Value;\n            TimeSpan stabilizationTime = GetLivenessStabilizationTime(clusterMembershipOptions, didKill);\n            WriteLog(Environment.NewLine + Environment.NewLine + \"WaitForLivenessToStabilize is about to sleep for {0}\", stabilizationTime);\n            await Task.Delay(stabilizationTime);\n            WriteLog(\"WaitForLivenessToStabilize is done sleeping\");\n        }\n\n        /// <summary>\n        /// Get the timeout value to use to wait for the silo liveness sub-system to detect and act on any recent cluster membership changes.\n        /// <seealso cref=\"WaitForLivenessToStabilizeAsync\"/>\n        /// </summary>\n        public static TimeSpan GetLivenessStabilizationTime(ClusterMembershipOptions clusterMembershipOptions, bool didKill = false)\n        {\n            TimeSpan stabilizationTime = TimeSpan.Zero;\n            if (didKill)\n            {\n                // in case of hard kill (kill and not Stop), we should give silos time to detect failures first.\n                stabilizationTime = TestingUtils.Multiply(clusterMembershipOptions.ProbeTimeout, clusterMembershipOptions.NumMissedProbesLimit);\n            }\n            if (clusterMembershipOptions.UseLivenessGossip)\n            {\n                stabilizationTime += TimeSpan.FromSeconds(5);\n            }\n            else\n            {\n                stabilizationTime += TestingUtils.Multiply(clusterMembershipOptions.TableRefreshTimeout, 2);\n            }\n            return stabilizationTime;\n        }\n\n        /// <summary>\n        /// Start an additional silo, so that it joins the existing cluster.\n        /// </summary>\n        /// <returns>SiloHandle for the newly started silo.</returns>\n        public SiloHandle StartAdditionalSilo(bool startAdditionalSiloOnNewPort = false)\n        {\n            return StartAdditionalSiloAsync(startAdditionalSiloOnNewPort).GetAwaiter().GetResult();\n        }\n\n        /// <summary>\n        /// Start an additional silo, so that it joins the existing cluster.\n        /// </summary>\n        /// <returns>SiloHandle for the newly started silo.</returns>\n        public async Task<SiloHandle> StartAdditionalSiloAsync(bool startAdditionalSiloOnNewPort = false)\n        {\n            return (await this.StartAdditionalSilosAsync(1, startAdditionalSiloOnNewPort)).Single();\n        }\n\n        /// <summary>\n        /// Start a number of additional silo, so that they join the existing cluster.\n        /// </summary>\n        /// <param name=\"silosToStart\">Number of silos to start.</param>\n        /// <param name=\"startAdditionalSiloOnNewPort\"></param>\n        /// <returns>List of SiloHandles for the newly started silos.</returns>\n        public async Task<List<SiloHandle>> StartAdditionalSilosAsync(int silosToStart, bool startAdditionalSiloOnNewPort = false)\n        {\n            var instances = new List<SiloHandle>();\n            if (silosToStart > 0)\n            {\n                var siloStartTasks = Enumerable.Range(this.startedInstances, silosToStart)\n                    .Select(instanceNumber => Task.Run(() => StartSiloAsync((short)instanceNumber, this.options, startSiloOnNewPort: startAdditionalSiloOnNewPort))).ToArray();\n\n                try\n                {\n                    await Task.WhenAll(siloStartTasks);\n                }\n                catch (Exception)\n                {\n                    lock (additionalSilos)\n                    {\n                        this.additionalSilos.AddRange(siloStartTasks.Where(t => t.Exception == null).Select(t => t.Result));\n                    }\n\n                    throw;\n                }\n\n                instances.AddRange(siloStartTasks.Select(t => t.Result));\n                lock (additionalSilos)\n                {\n                    this.additionalSilos.AddRange(instances);\n                }\n            }\n\n            return instances;\n        }\n\n        /// <summary>\n        /// Stop any additional silos, not including the default Primary silo.\n        /// </summary>\n        public async Task StopSecondarySilosAsync()\n        {\n            foreach (var instance in this.additionalSilos.ToList())\n            {\n                await StopSiloAsync(instance);\n            }\n        }\n\n        /// <summary>\n        /// Stops the default Primary silo.\n        /// </summary>\n        public async Task StopPrimarySiloAsync()\n        {\n            if (Primary == null) throw new InvalidOperationException(\"There is no primary silo\");\n            await StopClusterClientAsync();\n            await StopSiloAsync(Primary);\n        }\n\n        /// <summary>\n        /// Stop cluster client as an asynchronous operation.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> representing the asynchronous operation.</returns>\n        public async Task StopClusterClientAsync()\n        {\n            var client = this.ClientHost;\n            try\n            {\n                if (client is not null)\n                {\n                    await client.StopAsync().ConfigureAwait(false);\n                }                \n            }\n            catch (Exception exc)\n            {\n                WriteLog(\"Exception stopping client: {0}\", exc);\n            }\n            finally\n            {\n                await DisposeAsync(client).ConfigureAwait(false);\n                ClientHost = null;\n            }\n        }\n\n        /// <summary>\n        /// Stop all current silos.\n        /// </summary>\n        public void StopAllSilos()\n        {\n            StopAllSilosAsync().GetAwaiter().GetResult();\n        }\n\n        /// <summary>\n        /// Stop all current silos.\n        /// </summary>\n        public async Task StopAllSilosAsync()\n        {\n            await StopClusterClientAsync();\n            await StopSecondarySilosAsync();\n            if (Primary != null)\n            {\n                await StopPrimarySiloAsync();\n            }\n            AppDomain.CurrentDomain.UnhandledException -= ReportUnobservedException;\n        }\n\n        /// <summary>\n        /// Do a semi-graceful Stop of the specified silo.\n        /// </summary>\n        /// <param name=\"instance\">Silo to be stopped.</param>\n        public async Task StopSiloAsync(SiloHandle instance)\n        {\n            if (instance != null)\n            {\n                await StopSiloAsync(instance, true);\n                if (Primary == instance)\n                {\n                    Primary = null;\n                }\n                else\n                {\n                    lock (additionalSilos)\n                    {\n                        additionalSilos.Remove(instance);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Do an immediate Kill of the specified silo.\n        /// </summary>\n        /// <param name=\"instance\">Silo to be killed.</param>\n        public async Task KillSiloAsync(SiloHandle instance)\n        {\n            if (instance != null)\n            {\n                // do NOT stop, just kill directly, to simulate crash.\n                await StopSiloAsync(instance, false);\n                if (Primary == instance)\n                {\n                    Primary = null;\n                }\n                else\n                {\n                    lock (additionalSilos)\n                    {\n                        additionalSilos.Remove(instance);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Performs a hard kill on client.  Client will not cleanup resources.\n        /// </summary>\n        public async Task KillClientAsync()\n        {\n            var client = ClientHost;\n            if (client != null)\n            {\n                using var cancelled = new CancellationTokenSource();\n                cancelled.Cancel();\n                try\n                {\n                    await client.StopAsync(cancelled.Token).ConfigureAwait(false);\n                }\n                finally\n                {\n                    await DisposeAsync(client);\n                    ClientHost = null;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Do a Stop or Kill of the specified silo, followed by a restart.\n        /// </summary>\n        /// <param name=\"instance\">Silo to be restarted.</param>\n        public async Task<SiloHandle> RestartSiloAsync(SiloHandle instance)\n        {\n            if (instance != null)\n            {\n                var instanceNumber = instance.InstanceNumber;\n                var siloName = instance.Name;\n                await StopSiloAsync(instance);\n                var newInstance = await StartSiloAsync(instanceNumber, this.options);\n\n                if (siloName == Silo.PrimarySiloName)\n                {\n                    Primary = newInstance;\n                }\n                else\n                {\n                    lock (additionalSilos)\n                    {\n                        additionalSilos.Add(newInstance);\n                    }\n                }\n\n                return newInstance;\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Restart a previously stopped.\n        /// </summary>\n        /// <param name=\"siloName\">Silo to be restarted.</param>\n        public async Task<SiloHandle> RestartStoppedSecondarySiloAsync(string siloName)\n        {\n            if (siloName == null) throw new ArgumentNullException(nameof(siloName));\n            var siloHandle = this.Silos.Single(s => s.Name.Equals(siloName, StringComparison.Ordinal));\n            var newInstance = await this.StartSiloAsync(this.Silos.IndexOf(siloHandle), this.options);\n            lock (additionalSilos)\n            {\n                additionalSilos.Add(newInstance);\n            }\n            return newInstance;\n        }\n\n        /// <summary>\n        /// Initialize the grain client. This should be already done by <see cref=\"Deploy()\"/> or <see cref=\"DeployAsync\"/>\n        /// </summary>\n        public async Task InitializeClientAsync()\n        {\n            WriteLog(\"Initializing Cluster Client\");\n\n            if (ClientHost is not null)\n            {\n                await StopClusterClientAsync();\n            }\n\n            var configurationBuilder = new ConfigurationBuilder();\n            foreach (var source in ConfigurationSources)\n            {\n                configurationBuilder.Add(source);\n            }\n            if (options.UseTestClusterMembership)\n            {\n                var gateways = new List<IPEndPoint>();\n                if (options.GatewayPerSilo)\n                {\n                    gateways.AddRange(Enumerable.Range(options.BaseGatewayPort, options.InitialSilosCount).Select(port => new IPEndPoint(IPAddress.Loopback, port)));\n                }\n                else\n                {\n                    gateways.Add(new IPEndPoint(IPAddress.Loopback, options.BaseGatewayPort));\n                }\n\n                var clustering = new Dictionary<string, string>();\n                var i = 0;\n                foreach (var v in gateways)\n                {\n                    clustering[$\"Orleans:Clustering:Gateways:{i++}\"] = v.ToString();\n                }\n\n                clustering[\"Orleans:Clustering:ProviderType\"] = \"Development\";\n                configurationBuilder.AddInMemoryCollection(clustering);\n            }\n\n            var configuration = configurationBuilder.Build();\n\n            this.ClientHost = TestClusterHostFactory.CreateClusterClient(\n                \"MainClient\",\n                configuration,\n                hostBuilder =>\n                {\n                    hostBuilder.UseOrleansClient((context, clientBuilder) =>\n                    {\n                        Enum.TryParse<ConnectionTransportType>(context.Configuration[nameof(TestClusterOptions.ConnectionTransport)], out var transport);\n                        switch (transport)\n                        {\n                            case ConnectionTransportType.TcpSocket:\n                                break;\n                            case ConnectionTransportType.InMemory:\n                                clientBuilder.UseInMemoryConnectionTransport(_transportHub);\n                                break;\n                            case ConnectionTransportType.UnixSocket:\n                                clientBuilder.UseUnixSocketConnection();\n                                break;\n                            default:\n                                throw new ArgumentException($\"Unsupported {nameof(ConnectionTransportType)}: {transport}\");\n                        }\n                    });\n                });\n            await this.ClientHost.StartAsync();\n        }\n\n        /// <summary>\n        /// Gets the configuration sources.\n        /// </summary>\n        /// <value>The configuration sources.</value>\n        public IReadOnlyList<IConfigurationSource> ConfigurationSources { get; }\n\n        private async Task InitializeAsync()\n        {\n            short silosToStart = this.options.InitialSilosCount;\n\n            if (this.options.UseTestClusterMembership)\n            {\n                this.Primary = await StartSiloAsync(this.startedInstances, this.options);\n                silosToStart--;\n            }\n\n            if (silosToStart > 0)\n            {\n                await this.StartAdditionalSilosAsync(silosToStart);\n            }\n\n            WriteLog(\"Done initializing cluster\");\n\n            if (this.options.InitializeClientOnDeploy)\n            {\n                await InitializeClientAsync();\n            }\n        }\n\n        /// <summary>\n        /// Default value for <see cref=\"CreateSiloAsync\"/>, which creates a new silo handle.\n        /// </summary>\n        /// <param name=\"siloName\">Name of the silo.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <returns>The silo handle.</returns>\n        public async Task<SiloHandle> DefaultCreateSiloAsync(string siloName, IConfiguration configuration)\n        {\n            return await InProcessSiloHandle.CreateAsync(siloName, configuration, hostBuilder =>\n            {\n                hostBuilder.UseOrleans((context, siloBuilder) =>\n                {\n                    Enum.TryParse<ConnectionTransportType>(context.Configuration[nameof(TestClusterOptions.ConnectionTransport)], out var transport);\n                    switch (transport)\n                    {\n                        case ConnectionTransportType.TcpSocket:\n                            break;\n                        case ConnectionTransportType.InMemory:\n                            siloBuilder.UseInMemoryConnectionTransport(_transportHub);\n                            break;\n                        case ConnectionTransportType.UnixSocket:\n                            siloBuilder.UseUnixSocketConnection();\n                            break;\n                        default:\n                            throw new ArgumentException($\"Unsupported {nameof(ConnectionTransportType)}: {transport}\");\n                    }\n\n                    if (options.UseRealEnvironmentStatistics)\n                    {\n                        var descriptor = siloBuilder.Services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(IEnvironmentStatisticsProvider));\n                        if (descriptor != null)\n                        {\n                            siloBuilder.Services.Remove(descriptor);\n                            siloBuilder.Services.AddSingleton<IEnvironmentStatisticsProvider, EnvironmentStatisticsProvider>();\n                        }\n                    }\n                });\n            });\n        }\n\n        /// <summary>\n        /// Start a new silo in the target cluster\n        /// </summary>\n        /// <param name=\"cluster\">The TestCluster in which the silo should be deployed</param>\n        /// <param name=\"instanceNumber\">The instance number to deploy</param>\n        /// <param name=\"clusterOptions\">The options to use.</param>\n        /// <param name=\"configurationOverrides\">Configuration overrides.</param>\n        /// <param name=\"startSiloOnNewPort\">Whether we start this silo on a new port, instead of the default one</param>\n        /// <returns>A handle to the silo deployed</returns>\n        public static async Task<SiloHandle> StartSiloAsync(TestCluster cluster, int instanceNumber, TestClusterOptions clusterOptions, IReadOnlyList<IConfigurationSource> configurationOverrides = null, bool startSiloOnNewPort = false)\n        {\n            if (cluster == null) throw new ArgumentNullException(nameof(cluster));\n            return await cluster.StartSiloAsync(instanceNumber, clusterOptions, configurationOverrides, startSiloOnNewPort);\n        }\n\n        /// <summary>\n        /// Starts a new silo.\n        /// </summary>\n        /// <param name=\"instanceNumber\">The instance number to deploy</param>\n        /// <param name=\"clusterOptions\">The options to use.</param>\n        /// <param name=\"configurationOverrides\">Configuration overrides.</param>\n        /// <param name=\"startSiloOnNewPort\">Whether we start this silo on a new port, instead of the default one</param>\n        /// <returns>A handle to the deployed silo.</returns>\n        public async Task<SiloHandle> StartSiloAsync(int instanceNumber, TestClusterOptions clusterOptions, IReadOnlyList<IConfigurationSource> configurationOverrides = null, bool startSiloOnNewPort = false)\n        {\n            var configurationSources = this.ConfigurationSources.ToList();\n\n            // Add overrides.\n            if (configurationOverrides != null) configurationSources.AddRange(configurationOverrides);\n            var siloSpecificOptions = TestSiloSpecificOptions.Create(this, clusterOptions, instanceNumber, startSiloOnNewPort);\n            configurationSources.Add(new MemoryConfigurationSource\n            {\n                InitialData = siloSpecificOptions.ToDictionary()\n            });\n\n            var configurationBuilder = new ConfigurationBuilder();\n            foreach (var source in configurationSources)\n            {\n                configurationBuilder.Add(source);\n            }\n            var configuration = configurationBuilder.Build();\n            var handle = await this.CreateSiloAsync(siloSpecificOptions.SiloName, configuration);\n            handle.InstanceNumber = (short)instanceNumber;\n            Interlocked.Increment(ref this.startedInstances);\n            return handle;\n        }\n\n        private async Task StopSiloAsync(SiloHandle instance, bool stopGracefully)\n        {\n            try\n            {\n                await instance.StopSiloAsync(stopGracefully).ConfigureAwait(false);\n            }\n            finally\n            {\n                await DisposeAsync(instance).ConfigureAwait(false);\n\n                Interlocked.Decrement(ref this.startedInstances);\n            }\n        }\n\n        /// <summary>\n        /// Gets the log.\n        /// </summary>\n        /// <returns>The log contents.</returns>\n        public string GetLog()\n        {\n            return this.log.ToString();\n        }\n\n        private void ReportUnobservedException(object sender, UnhandledExceptionEventArgs eventArgs)\n        {\n            Exception exception = (Exception)eventArgs.ExceptionObject;\n            this.WriteLog(\"Unobserved exception: {0}\", exception);\n        }\n\n        private void WriteLog(string format, params object[] args)\n        {\n            log.AppendFormat(format + Environment.NewLine, args);\n        }\n\n        private void FlushLogToConsole()\n        {\n            Console.WriteLine(GetLog());\n        }\n\n        /// <inheritdoc/>\n        public async ValueTask DisposeAsync()\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            await Task.Run(async () =>\n            {\n                await DisposeAsync(ClientHost).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n\n                foreach (var handle in SecondarySilos)\n                {\n                    await DisposeAsync(handle).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n                }\n\n                if (Primary is not null)\n                {\n                    await DisposeAsync(Primary).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n                }\n                ClientHost = null;\n\n                PortAllocator?.Dispose();\n            });\n\n            _disposed = true;\n        }\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            DisposeAsync().AsTask().Wait();\n        }\n\n        private static async Task DisposeAsync(IDisposable value)\n        {\n            if (value is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync().AsTask().ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n            }\n            else if (value is IDisposable disposable)\n            {\n                disposable.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestClusterBuilder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>Configuration builder for starting a <see cref=\"TestCluster\"/>.</summary>\n    public class TestClusterBuilder\n    {\n        private readonly List<Action<IConfigurationBuilder>> configureHostConfigActions = new List<Action<IConfigurationBuilder>>();\n        private readonly List<Action> configureBuilderActions = new List<Action>();\n        private Func<string, IConfiguration, Task<SiloHandle>> _createSiloAsync;\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"TestClusterBuilder\"/> using the default options.\n        /// </summary>\n        public TestClusterBuilder()\n            : this(2)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"TestClusterBuilder\"/> overriding the initial silos count.\n        /// </summary>\n        /// <param name=\"initialSilosCount\">The number of initial silos to deploy.</param>\n        public TestClusterBuilder(short initialSilosCount)\n        {\n            this.Options = new TestClusterOptions\n            {\n                InitialSilosCount = initialSilosCount,\n                ClusterId = CreateClusterId(),\n                ServiceId = Guid.NewGuid().ToString(\"N\"),\n                UseTestClusterMembership = true,\n                InitializeClientOnDeploy = true,\n                ConfigureFileLogging = true,\n                AssumeHomogenousSilosForTesting = true\n            };\n\n            AddSiloBuilderConfigurator<ConfigureDistributedGrainDirectory>();\n            this.AddSiloBuilderConfigurator<ConfigureStaticClusterDeploymentOptions>();\n            this.ConfigureBuilder(ConfigureDefaultPorts);\n        }\n\n        /// <summary>\n        /// Gets or sets the port allocator used to allocate consecutive silo ports.\n        /// </summary>\n        public ITestClusterPortAllocator PortAllocator { get; set; } = new TestClusterPortAllocator();\n\n        /// <summary>\n        /// Configuration values which will be provided to the silos and clients created by this builder.\n        /// </summary>\n        public Dictionary<string, string> Properties { get; } = new Dictionary<string, string>();\n\n        /// <summary>\n        /// Gets the options.\n        /// </summary>\n        /// <value>The options.</value>\n        public TestClusterOptions Options { get; }\n\n        /// <summary>\n        /// Gets or sets the delegate used to create and start an individual silo.\n        /// </summary>\n        public Func<string, IConfiguration, Task<SiloHandle>> CreateSiloAsync\n        {\n            private get => _createSiloAsync;\n            set\n            {\n                _createSiloAsync = value;\n\n                // The custom builder does not have access to the in-memory transport.\n                Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n            }\n        }\n\n        /// <summary>\n        /// Adds a configuration delegate to the builder\n        /// </summary>        \n        /// <param name=\"configureDelegate\">The configuration delegate.</param>\n        public TestClusterBuilder ConfigureBuilder(Action configureDelegate)\n        {\n            this.configureBuilderActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));\n            return this;\n        }\n\n        /// <summary>\n        /// Set up the configuration for the builder itself. This will be used as a base to initialize each silo host\n        /// for use later in the build process. This can be called multiple times and the results will be additive.\n        /// </summary>\n        /// <param name=\"configureDelegate\">The delegate for configuring the <see cref=\"IConfigurationBuilder\"/> that will be used\n        /// to construct the <see cref=\"IConfiguration\"/> for the host.</param>\n        /// <returns>The same instance of the host builder for chaining.</returns>\n        public TestClusterBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)\n        {\n            this.configureHostConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));\n            return this;\n        }\n\n        /// <summary>\n        /// Adds an implementation of <see cref=\"ISiloConfigurator\"/> or <see cref=\"IHostConfigurator\"/> to configure silos created by the test cluster.\n        /// </summary>\n        /// <typeparam name=\"T\">The configurator type.</typeparam>\n        /// <returns>The builder.</returns>\n        public TestClusterBuilder AddSiloBuilderConfigurator<T>() where T : new()\n        {\n            if (!typeof(ISiloConfigurator).IsAssignableFrom(typeof(T)) && !typeof(IHostConfigurator).IsAssignableFrom(typeof(T)))\n            {\n                throw new ArgumentException($\"The type {typeof(T)} is not assignable to either {nameof(ISiloConfigurator)} or {nameof(IHostConfigurator)}\");\n            }\n\n            this.Options.SiloBuilderConfiguratorTypes.Add(typeof(T).AssemblyQualifiedName);\n            return this;\n        }\n\n        /// <summary>\n        /// Adds an implementation of <see cref=\"IClientBuilderConfigurator\"/> or <see cref=\"IHostConfigurator\"/> to configure the client created for the test cluster\n        /// </summary>\n        /// <typeparam name=\"T\">The client builder type</typeparam>\n        /// <returns>The builder.</returns>\n        public TestClusterBuilder AddClientBuilderConfigurator<T>() where T : new()\n        {\n            if (!typeof(IClientBuilderConfigurator).IsAssignableFrom(typeof(T)) && !typeof(IHostConfigurator).IsAssignableFrom(typeof(T)))\n            {\n                throw new ArgumentException($\"The type {typeof(T)} is not assignable to either {nameof(IClientBuilderConfigurator)} or {nameof(IHostConfigurator)}\");\n            }\n\n            this.Options.ClientBuilderConfiguratorTypes.Add(typeof(T).AssemblyQualifiedName);\n            return this;\n        }\n\n        /// <summary>\n        /// Builds this instance.\n        /// </summary>\n        /// <returns>TestCluster.</returns>\n        public TestCluster Build()\n        {\n            var portAllocator = this.PortAllocator;\n            var configBuilder = new ConfigurationBuilder();\n\n            foreach (var action in configureBuilderActions)\n            {\n                action();\n            }\n\n            configBuilder.AddInMemoryCollection(this.Properties);\n            configBuilder.AddInMemoryCollection(this.Options.ToDictionary());\n            foreach (var buildAction in this.configureHostConfigActions)\n            {\n                buildAction(configBuilder);\n            }\n\n            var configuration = configBuilder.Build();\n            var finalOptions = new TestClusterOptions();\n            configuration.Bind(finalOptions);\n\n            // Since the ClusterId & ServiceId properties are nested under the 'Orleans' section in the config,\n            // we bind the 'Orleans' section here to bind them to the options.\n            configuration.GetSection(\"Orleans\").Bind(finalOptions);\n\n            var configSources = new ReadOnlyCollection<IConfigurationSource>(configBuilder.Sources);\n            var testCluster = new TestCluster(finalOptions, configSources, portAllocator);\n            if (CreateSiloAsync != null) testCluster.CreateSiloAsync = CreateSiloAsync;\n            return testCluster;\n        }\n\n        /// <summary>\n        /// Creates a cluster identifier.\n        /// </summary>\n        /// <returns>A new cluster identifier.</returns>\n        public static string CreateClusterId()\n        {\n            string prefix = \"testcluster-\";\n            int randomSuffix = Random.Shared.Next(1000);\n            DateTime now = DateTime.UtcNow;\n            string DateTimeFormat = @\"yyyy-MM-dd-HH-mm-ss\";\n            return $\"{prefix}{now.ToString(DateTimeFormat, CultureInfo.InvariantCulture)}-{randomSuffix}\";\n        }\n\n        private void ConfigureDefaultPorts()\n        {\n            // Set base ports if none are currently set.\n            (int baseSiloPort, int baseGatewayPort) = this.PortAllocator.AllocateConsecutivePortPairs(this.Options.InitialSilosCount + 3);\n            if (this.Options.BaseSiloPort == 0) this.Options.BaseSiloPort = baseSiloPort;\n            if (this.Options.BaseGatewayPort == 0) this.Options.BaseGatewayPort = baseGatewayPort;\n        }\n\n        internal class ConfigureStaticClusterDeploymentOptions : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                hostBuilder.ConfigureServices((context, services) =>\n                {\n                    var initialSilos = int.Parse(context.Configuration[nameof(TestClusterOptions.InitialSilosCount)]);\n                    var siloNames = Enumerable.Range(0, initialSilos).Select(GetSiloName).ToList();\n                    services.Configure<StaticClusterDeploymentOptions>(options => options.SiloNames = siloNames);\n                });\n            }\n\n            private static string GetSiloName(int instanceNumber)\n            {\n                return instanceNumber == 0 ? Silo.PrimarySiloName : $\"Secondary_{instanceNumber}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/TestClusterExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Extension methods for test clusters.\n    /// </summary>\n    public static class TestClusterExtensions\n    {        \n        /// <summary>\n        /// Gets the configuration from the specified host builder.\n        /// </summary>        \n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        public static IConfiguration GetConfiguration(this IHostBuilder builder)\n        {\n            if (builder.Properties.TryGetValue(\"Configuration\", out var configObject) && configObject is IConfiguration config)\n            {\n                return config;\n            }\n\n            throw new InvalidOperationException(\n                $\"Expected configuration object in \\\"Configuration\\\" property of type {nameof(IConfiguration)} on {nameof(ISiloBuilder)}.\");\n        }\n\n        /// <summary>\n        /// Gets a configuration value.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <param name=\"key\">The key.</param>\n        /// <returns>The configuration value.</returns>\n        public static string GetConfigurationValue(this IHostBuilder hostBuilder, string key)\n        {\n            return hostBuilder.GetConfiguration()[key];\n        }\n\n        /// <summary>\n        /// Gets the test cluster options.\n        /// </summary>\n        /// <param name=\"hostBuilder\">The host builder.</param>\n        /// <returns>The test cluster options.</returns>\n        public static TestClusterOptions GetTestClusterOptions(this IHostBuilder hostBuilder)\n        {\n            return hostBuilder.GetConfiguration().GetTestClusterOptions();\n        }\n\n        /// <summary>\n        /// Gets the test cluster options.\n        /// </summary>\n        /// <param name=\"config\">The configuration.</param>\n        /// <returns>The test cluster options.</returns>\n        public static TestClusterOptions GetTestClusterOptions(this IConfiguration config)\n        {\n            var result = new TestClusterOptions();\n            config.Bind(result);\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestClusterHostFactory.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Newtonsoft.Json;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.Hosting;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Runtime.TestHooks;\nusing Orleans.Statistics;\nusing Orleans.TestingHost.Logging;\nusing Orleans.TestingHost.Utils;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Utility for creating silos given a name and collection of configuration sources.\n    /// </summary>\n    public class TestClusterHostFactory\n    {\n        /// <summary>\n        /// Creates an returns a new silo.\n        /// </summary>\n        /// <param name=\"hostName\">The silo name if it is not already specified in the configuration.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <param name=\"postConfigureHostBuilder\">An optional delegate which can be used to configure the host builder just prior to a host being built.</param>\n        /// <returns>A new silo.</returns>\n        public static IHost CreateSiloHost(string hostName, IConfiguration configuration, Action<IHostBuilder> postConfigureHostBuilder = null)\n        {\n            string siloName = configuration[\"Name\"] ?? hostName;\n\n            var hostBuilder = new HostBuilder();\n            hostBuilder.UseEnvironment(Environments.Development);\n            hostBuilder.Properties[\"Configuration\"] = configuration;\n            hostBuilder.ConfigureHostConfiguration(cb => cb.AddConfiguration(configuration));\n\n            hostBuilder.UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder.Services\n                    .Configure<HostOptions>(options => options.ShutdownTimeout = TimeSpan.FromSeconds(30));\n            });\n\n            ConfigureAppServices(configuration, hostBuilder);\n\n            hostBuilder.ConfigureServices((context, services) =>\n            {\n                services.AddSingleton<TestHooksEnvironmentStatisticsProvider>();\n                services.AddFromExisting<IEnvironmentStatisticsProvider, TestHooksEnvironmentStatisticsProvider>();\n                services.AddSingleton<TestHooksSystemTarget>();\n\n                TryConfigureFileLogging(configuration, services, siloName);\n\n                if (Debugger.IsAttached)\n                {\n                    // Test is running inside debugger - Make timeout ~= infinite\n                    services.Configure<SiloMessagingOptions>(op => op.ResponseTimeout = TimeSpan.FromMilliseconds(1000000));\n                }\n            });\n\n            postConfigureHostBuilder?.Invoke(hostBuilder);\n            var host = hostBuilder.Build();\n            InitializeTestHooksSystemTarget(host);\n            return host;\n        }\n\n        /// <summary>\n        /// Creates the cluster client.\n        /// </summary>\n        /// <param name=\"hostName\">Name of the host.</param>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <param name=\"postConfigureHostBuilder\">An optional delegate which can be used to configure the host builder just prior to a host being built.</param>\n        /// <returns>The cluster client host.</returns>\n        public static IHost CreateClusterClient(string hostName, IConfiguration configuration, Action<IHostBuilder> postConfigureHostBuilder = null)\n        {\n            var hostBuilder = new HostBuilder();\n            hostBuilder.UseEnvironment(Environments.Development);\n            hostBuilder.Properties[\"Configuration\"] = configuration;\n            hostBuilder.ConfigureHostConfiguration(cb => cb.AddConfiguration(configuration));\n\n            hostBuilder.UseOrleansClient();\n\n            ConfigureClientAppServices(configuration, hostBuilder);\n\n            hostBuilder\n                .ConfigureServices(services =>\n                {\n                    //TryConfigureClientMembership(configuration, services);\n                    TryConfigureFileLogging(configuration, services, hostName);\n                });\n\n            postConfigureHostBuilder?.Invoke(hostBuilder);\n            var host = hostBuilder.Build();\n\n            return host;\n        }\n\n        /// <summary>\n        /// Serializes configuration to a string.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <returns>The serialized configuration.</returns>\n        public static string SerializeConfiguration(IConfiguration configuration)\n        {\n            var settings = new JsonSerializerSettings();\n\n            KeyValuePair<string, string>[] enumerated = configuration.AsEnumerable().ToArray();\n            return JsonConvert.SerializeObject(enumerated, settings);\n        }\n\n        /// <summary>\n        /// Deserializes a configuration string.\n        /// </summary>\n        /// <param name=\"serializedSources\">The serialized sources.</param>\n        /// <returns>The deserialized configuration.</returns>\n        public static IConfiguration DeserializeConfiguration(string serializedSources)\n        {\n            var settings = new JsonSerializerSettings();\n\n            var builder = new ConfigurationBuilder();\n            var enumerated = JsonConvert.DeserializeObject<KeyValuePair<string, string>[]>(serializedSources, settings);\n            builder.AddInMemoryCollection(enumerated);\n            return builder.Build();\n        }\n\n        private static void ConfigureAppServices(IConfiguration configuration, IHostBuilder hostBuilder)\n        {\n            var builderConfiguratorTypes = configuration.GetSection(nameof(TestClusterOptions.SiloBuilderConfiguratorTypes))?.Get<string[]>();\n            if (builderConfiguratorTypes == null) return;\n\n            foreach (var builderConfiguratorType in builderConfiguratorTypes)\n            {\n                if (!string.IsNullOrWhiteSpace(builderConfiguratorType))\n                {\n                    var configurator = Activator.CreateInstance(Type.GetType(builderConfiguratorType, true));\n\n                    (configurator as IHostConfigurator)?.Configure(hostBuilder);\n                    hostBuilder.UseOrleans((ctx, siloBuilder) => (configurator as ISiloConfigurator)?.Configure(siloBuilder));\n                }\n            }\n        }\n\n        private static void ConfigureClientAppServices(IConfiguration configuration, IHostBuilder hostBuilder)\n        {\n            var builderConfiguratorTypes = configuration.GetSection(nameof(TestClusterOptions.ClientBuilderConfiguratorTypes))?.Get<string[]>();\n            if (builderConfiguratorTypes == null) return;\n\n            foreach (var builderConfiguratorType in builderConfiguratorTypes)\n            {\n                if (!string.IsNullOrWhiteSpace(builderConfiguratorType))\n                {\n                    var builderConfigurator = Activator.CreateInstance(Type.GetType(builderConfiguratorType, true));\n\n                    (builderConfigurator as IHostConfigurator)?.Configure(hostBuilder);\n\n                    if (builderConfigurator is IClientBuilderConfigurator clientBuilderConfigurator)\n                    {\n                        hostBuilder.UseOrleansClient(clientBuilder => clientBuilderConfigurator.Configure(configuration, clientBuilder));\n                    }\n                }\n            }\n        }\n\n        private static void TryConfigureFileLogging(IConfiguration configuration, IServiceCollection services, string name)\n        {\n            bool.TryParse(configuration[nameof(TestClusterOptions.ConfigureFileLogging)], out bool configureFileLogging);\n            if (configureFileLogging)\n            {\n                var fileName = TestingUtils.CreateTraceFileName(name, configuration[\"Orleans:ClusterId\"]);\n                services.AddLogging(loggingBuilder => loggingBuilder.AddFile(fileName));\n            }\n        }\n\n        private static void InitializeTestHooksSystemTarget(IHost host)\n        {\n            _ = host.Services.GetRequiredService<TestHooksSystemTarget>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestClusterOptions.cs",
    "content": "using System.Collections.Generic;\nusing System.Net;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Configuration options for test clusters.\n    /// </summary>\n    public class TestClusterOptions\n    {\n        /// <summary>\n        /// Gets or sets the cluster identifier.\n        /// </summary>\n        /// <seealso cref=\"ClusterOptions.ClusterId\"/>\n        /// <value>The cluster identifier.</value>\n        public string ClusterId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the service identifier.\n        /// </summary>\n        /// <seealso cref=\"ClusterOptions.ServiceId\"/>\n        /// <value>The service identifier.</value>\n        public string ServiceId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the base silo port, which is the port for the first silo. Other silos will use subsequent ports.\n        /// </summary>\n        /// <value>The base silo port.</value>\n        public int BaseSiloPort{ get; set; }\n\n        /// <summary>\n        /// Gets or sets the base gateway port, which is the gateway port for the first silo. Other silos will use subsequent ports.\n        /// </summary>\n        /// <value>The base gateway port.</value>\n        public int BaseGatewayPort { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to use test cluster membership.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if test cluster membership should be used; otherwise, <see langword=\"false\" />.</value>\n        public bool UseTestClusterMembership { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to use the real environment statistics.\n        /// </summary>\n        public bool UseRealEnvironmentStatistics { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to initialize the client immediately on deployment.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if the client should be initialized immediately on deployment; otherwise, <see langword=\"false\" />.</value>\n        public bool InitializeClientOnDeploy { get; set; }\n\n        /// <summary>\n        /// Gets or sets the initial silos count.\n        /// </summary>\n        /// <value>The initial silos count.</value>\n        public short InitialSilosCount { get; set; }\n\n        /// <summary>\n        /// Gets or sets the application base directory.\n        /// </summary>\n        /// <value>The application base directory.</value>\n        public string ApplicationBaseDirectory { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to configure file logging.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if file logging should be configured; otherwise, <see langword=\"false\" />.</value>\n        public bool ConfigureFileLogging { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets a value indicating whether to assume homogeneous silos for testing purposes.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if the cluster should assume homogeneous silos; otherwise, <see langword=\"false\" />.</value>\n        public bool AssumeHomogenousSilosForTesting { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether each silo should host a gateway.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if each silo should host a gateway; otherwise, <see langword=\"false\" />.</value>\n        public bool GatewayPerSilo { get; set; } = true;\n\n        /// <summary>\n        /// Gets the silo builder configurator types.\n        /// </summary>\n        /// <value>The silo builder configurator types.</value>\n        public List<string> SiloBuilderConfiguratorTypes { get; } = new List<string>();\n\n        /// <summary>\n        /// Gets the client builder configurator types.\n        /// </summary>\n        /// <value>The client builder configurator types.</value>\n        public List<string> ClientBuilderConfiguratorTypes { get; } = new List<string>();\n\n        /// <summary>\n        /// Gets or sets a value indicating what transport to use for connecting silos and clients.\n        /// </summary>\n        /// <remarks>\n        /// Defaults to InMemory.\n        /// </remarks>\n        public ConnectionTransportType ConnectionTransport { get; set; } = ConnectionTransportType.InMemory;\n\n        /// <summary>\n        /// Converts these options into a dictionary.\n        /// </summary>\n        /// <returns>The options dictionary.</returns>\n        public Dictionary<string, string> ToDictionary()\n        {\n            var result = new Dictionary<string, string>\n            {\n                [$\"Orleans:{nameof(ClusterId)}\"] = this.ClusterId,\n                [$\"Orleans:{nameof(ServiceId)}\"] = this.ServiceId,\n                [nameof(BaseSiloPort)] = this.BaseSiloPort.ToString(),\n                [nameof(BaseGatewayPort)] = this.BaseGatewayPort.ToString(),\n                [nameof(UseTestClusterMembership)] = this.UseTestClusterMembership.ToString(),\n                [nameof(UseRealEnvironmentStatistics)] = this.UseRealEnvironmentStatistics.ToString(),\n                [nameof(InitializeClientOnDeploy)] = this.InitializeClientOnDeploy.ToString(),\n                [nameof(InitialSilosCount)] = this.InitialSilosCount.ToString(),\n                [nameof(ApplicationBaseDirectory)] = this.ApplicationBaseDirectory,\n                [nameof(ConfigureFileLogging)] = this.ConfigureFileLogging.ToString(),\n                [nameof(AssumeHomogenousSilosForTesting)] = this.AssumeHomogenousSilosForTesting.ToString(),\n                [nameof(GatewayPerSilo)] = this.GatewayPerSilo.ToString(),\n                [nameof(ConnectionTransport)] = this.ConnectionTransport.ToString(),\n            };\n\n            if (UseTestClusterMembership)\n            {\n                result[\"Orleans:Clustering:ProviderType\"] = \"Development\";\n            }\n\n            result[\"UseRealEnvironmentStatistics\"] = UseRealEnvironmentStatistics ? \"True\" : \"False\";\n            \n            if (this.SiloBuilderConfiguratorTypes != null)\n            {\n                for (int i = 0; i < this.SiloBuilderConfiguratorTypes.Count; i++)\n                {\n                    result[$\"{nameof(SiloBuilderConfiguratorTypes)}:{i}\"] = this.SiloBuilderConfiguratorTypes[i];\n                }\n            }\n\n            if (this.ClientBuilderConfiguratorTypes != null)\n            {\n                for (int i = 0; i < this.ClientBuilderConfiguratorTypes.Count; i++)\n                {\n                    result[$\"{nameof(ClientBuilderConfiguratorTypes)}:{i}\"] = this.ClientBuilderConfiguratorTypes[i];\n                }\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Configuration overrides for individual silos.\n    /// </summary>\n    public class TestSiloSpecificOptions\n    {\n        /// <summary>\n        /// Gets or sets the silo port.\n        /// </summary>\n        /// <value>The silo port.</value>\n        public int SiloPort { get; set; }\n\n        /// <summary>\n        /// Gets or sets the gateway port.\n        /// </summary>\n        /// <value>The gateway port.</value>\n        public int GatewayPort { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the silo.\n        /// </summary>\n        /// <value>The name of the silo.</value>\n        public string SiloName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the primary silo port.\n        /// </summary>\n        /// <value>The primary silo port.</value>\n        public IPEndPoint PrimarySiloEndPoint { get; set; }\n\n        /// <summary>\n        /// Creates an instance of the <see cref=\"TestSiloSpecificOptions\"/> class.\n        /// </summary>\n        /// <param name=\"testCluster\">The test cluster.</param>\n        /// <param name=\"testClusterOptions\">The test cluster options.</param>\n        /// <param name=\"instanceNumber\">The instance number.</param>\n        /// <param name=\"assignNewPort\">if set to <see langword=\"true\" />, assign a new port for the silo.</param>\n        /// <returns>The options.</returns>\n        public static TestSiloSpecificOptions Create(TestCluster testCluster, TestClusterOptions testClusterOptions, int instanceNumber, bool assignNewPort = false)\n        {\n            var result = new TestSiloSpecificOptions\n            {\n                SiloName = testClusterOptions.UseTestClusterMembership && instanceNumber == 0 ? Silo.PrimarySiloName : $\"Secondary_{instanceNumber}\",\n                PrimarySiloEndPoint = testClusterOptions.UseTestClusterMembership ? new IPEndPoint(IPAddress.Loopback, testClusterOptions.BaseSiloPort) : null,\n            };\n\n            if (assignNewPort)\n            {\n                var (siloPort, gatewayPort) = testCluster.PortAllocator.AllocateConsecutivePortPairs(1);\n                result.SiloPort = siloPort;\n                result.GatewayPort = (instanceNumber == 0 || testClusterOptions.GatewayPerSilo) ? gatewayPort : 0;\n            }\n            else\n            {\n                result.SiloPort = testClusterOptions.BaseSiloPort + instanceNumber;\n                result.GatewayPort = (instanceNumber == 0 || testClusterOptions.GatewayPerSilo) ? testClusterOptions.BaseGatewayPort + instanceNumber : 0;\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Converts these options into a dictionary.\n        /// </summary>\n        /// <returns>The options dictionary.</returns>\n        public Dictionary<string, string> ToDictionary()\n        {\n            var result = new Dictionary<string, string>\n            {\n                [$\"Orleans:Endpoints:AdvertisedIPAddress\"] = IPAddress.Loopback.ToString(),\n                [$\"Orleans:Endpoints:{nameof(SiloPort)}\"] = this.SiloPort.ToString(),\n                [$\"Orleans:EndPoints:{nameof(GatewayPort)}\"] = this.GatewayPort.ToString(),\n                [\"Orleans:Name\"] = this.SiloName,\n            };\n\n            if (PrimarySiloEndPoint != null)\n            {\n                result[$\"Orleans:Clustering:{nameof(PrimarySiloEndPoint)}\"] = this.PrimarySiloEndPoint.ToString();\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Describe a transport method\n    /// </summary>\n    public enum ConnectionTransportType\n    {\n        /// <summary>\n        /// Uses real TCP socket.\n        /// </summary>\n        TcpSocket = 0,\n\n        /// <summary>\n        /// Uses in memory socket.\n        /// </summary>\n        InMemory = 1,\n\n        /// <summary>\n        /// Uses in Unix socket.\n        /// </summary>\n        UnixSocket = 2,\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestClusterPortAllocator.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Net;\nusing System.Net.NetworkInformation;\nusing System.Net.Sockets;\nusing System.Threading;\n\nnamespace Orleans.TestingHost;\n\n/// <summary>\n/// Default <see cref=\"ITestClusterPortAllocator\"/> implementation, which tries to allocate unused ports.\n/// </summary>\npublic class TestClusterPortAllocator : ITestClusterPortAllocator\n{\n    private bool _disposed;\n#if NET9_0_OR_GREATER\n    private readonly Lock _lockObj = new();\n#else\n    private readonly object _lockObj = new();\n#endif\n    private readonly Dictionary<int, string> _allocatedPorts = [];\n\n    /// <inheritdoc />\n    public (int, int) AllocateConsecutivePortPairs(int numPorts = 5)\n    {\n        // Evaluate current system tcp connections\n        var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();\n        var tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();\n\n        // each returned port in the pair will have to have at least this amount of available ports following it\n\n        return (GetAvailableConsecutiveServerPorts(tcpConnInfoArray, 22300, 30000, numPorts),\n            GetAvailableConsecutiveServerPorts(tcpConnInfoArray, 40000, 50000, numPorts));\n    }\n\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    /// <summary>\n    /// Releases unmanaged and - optionally - managed resources.\n    /// </summary>\n    /// <param name=\"disposing\"><see langword=\"true\" /> to release both managed and unmanaged resources; <see langword=\"false\" /> to release only unmanaged resources.</param>\n    protected virtual void Dispose(bool disposing)\n    {\n        if (_disposed)\n        {\n            return;\n        }\n\n        lock (_lockObj)\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            foreach (var pair in _allocatedPorts)\n            {\n                MutexManager.Instance.SignalRelease(pair.Value);\n            }\n\n            _allocatedPorts.Clear();\n            _disposed = true;\n        }\n    }\n\n    /// <summary>\n    /// Finalizes an instance of the <see cref=\"TestClusterPortAllocator\"/> class.\n    /// </summary>\n    ~TestClusterPortAllocator()\n    {\n        Dispose(false);\n    }\n\n    private int GetAvailableConsecutiveServerPorts(IPEndPoint[] tcpConnInfoArray, int portStartRange, int portEndRange, int consecutivePortsToCheck)\n    {\n        const int MaxAttempts = 100;\n\n        var allocations = new List<(int Port, string Mutex)>();\n\n        for (var attempts = 0; attempts < MaxAttempts; attempts++)\n        {\n            var basePort = Random.Shared.Next(portStartRange, portEndRange);\n\n            // get ports in buckets, so we don't interfere with parallel runs of this same function\n            basePort = basePort - basePort % consecutivePortsToCheck;\n            var endPort = basePort + consecutivePortsToCheck;\n\n            // make sure none of the ports in the sub range are in use\n            if (tcpConnInfoArray.All(endpoint => endpoint.Port < basePort || endpoint.Port >= endPort))\n            {\n                var portsAvailable = true;\n                for (var i = 0; i < consecutivePortsToCheck; i++)\n                {\n                    var port = basePort + i;\n                    try\n                    {\n                        using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);\n                        socket.Bind(new IPEndPoint(IPAddress.Loopback, port));\n                    }\n                    catch (SocketException)\n                    {\n                        portsAvailable = false;\n                        break;\n                    }\n                }\n\n                if (!portsAvailable)\n                {\n                    continue;\n                }\n\n                for (var i = 0; i < consecutivePortsToCheck; i++)\n                {\n                    var port = basePort + i;\n                    var name = $\"Global.TestCluster.{port.ToString(CultureInfo.InvariantCulture)}\";\n                    if (MutexManager.Instance.Acquire(name))\n                    {\n                        allocations.Add((port, name));\n                    }\n                    else\n                    {\n                        foreach (var allocation in allocations)\n                        {\n                            MutexManager.Instance.SignalRelease(allocation.Mutex);\n                        }\n\n                        allocations.Clear();\n                        break;\n                    }\n                }\n\n                if (allocations.Count == 0)\n                {\n                    // Try a different range.\n                    continue;\n                }\n\n                lock (_lockObj)\n                {\n                    foreach (var allocation in allocations)\n                    {\n                        _allocatedPorts[allocation.Port] = allocation.Mutex;\n                    }\n                }\n\n                return basePort;\n            }\n        }\n\n        throw new InvalidOperationException(\"Cannot find enough free ports to spin up a cluster\");\n    }\n\n    private class MutexManager\n    {\n        private readonly Dictionary<string, Mutex> _mutexes = [];\n        private readonly BlockingCollection<Action> _workItems = [];\n        private readonly Thread _thread;\n\n        public static MutexManager Instance { get; } = new MutexManager();\n\n        private MutexManager()\n        {\n            _thread = new Thread(Run)\n            {\n                Name = \"MutexManager.Worker\",\n                IsBackground = true,\n            };\n            _thread.Start();\n            AppDomain.CurrentDomain.DomainUnload += this.OnAppDomainUnload;\n        }\n\n        private void OnAppDomainUnload(object sender, EventArgs e) => Shutdown();\n\n        private void Shutdown()\n        {\n            _workItems.CompleteAdding();\n            _thread.Join();\n        }\n\n        public bool Acquire(string name)\n        {\n            var result = new [] { 0 };\n            var signal = new ManualResetEventSlim(initialState: false);\n            _workItems.Add(() =>\n            {\n                try\n                {\n                    if (!_mutexes.TryGetValue(name, out var mutex))\n                    {\n                        mutex = new Mutex(false, name);\n                        if (mutex.WaitOne(500))\n                        {\n                            // Acquired\n                            _mutexes[name] = mutex;\n                            Interlocked.Increment(ref result[0]);\n                            return;\n                        }\n\n                        // Failed to acquire: the mutex is already held by another process.\n                        try\n                        {\n                            mutex.ReleaseMutex();\n                        }\n                        finally\n                        {\n                            mutex.Close();\n                        }\n                    }\n\n                    // Failed to acquire: the mutex is already held by this process.\n                }\n                finally\n                {\n                    signal.Set();\n                }\n            });\n\n            if (!signal.Wait(TimeSpan.FromSeconds(10)))\n            {\n                throw new TimeoutException(\"Timed out while waiting for MutexManager to acquire mutex.\");\n            }\n\n            return result[0] == 1;\n        }\n\n        public void SignalRelease(string name)\n        {\n            if (_workItems.IsAddingCompleted) return;\n\n            try\n            {\n                _workItems.Add(() =>\n                {\n                    if (_mutexes.Remove(name, out var value))\n                    {\n                        value.ReleaseMutex();\n                        value.Close();\n                    }\n                });\n            }\n            catch\n            {\n            }\n        }\n\n        private void Run()\n        {\n            try\n            {\n                foreach (var action in _workItems.GetConsumingEnumerable())\n                {\n                    try\n                    {\n                        action();\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n            catch\n            {\n            }\n            finally\n            {\n                foreach (var mutex in _mutexes.Values)\n                {\n                    try\n                    {\n                        mutex.ReleaseMutex();\n                    }\n                    catch { }\n                    finally\n                    {\n                        mutex.Close();\n                    }\n                }\n\n                _mutexes.Clear();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/FaultInjectionStorageProvider.cs",
    "content": "\nusing System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Options for fault injection grain storage\n    /// </summary>\n    public class FaultInjectionGrainStorageOptions\n    {\n        /// <summary>\n        /// The default latency.\n        /// </summary>\n        public static TimeSpan DEFAULT_LATENCY = TimeSpan.FromMilliseconds(10);\n\n        /// <summary>\n        /// Gets or sets the latency applied on storage operations.\n        /// </summary>\n        public TimeSpan Latency { get; set; } = DEFAULT_LATENCY;\n    }\n\n    /// <summary>\n    /// Fault injection decorator for storage providers.  This allows users to inject storage exceptions to test error handling scenarios.\n    /// </summary>\n    public class FaultInjectionGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly IGrainStorage realStorageProvider;\n        private readonly IGrainFactory grainFactory;\n        private readonly ILogger logger;\n        private readonly FaultInjectionGrainStorageOptions options;\n\n        /// <summary>\n        /// Default constructor which creates the decorated storage provider.\n        /// </summary>\n        /// <param name=\"realStorageProvider\">The real storage provider.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"loggerFactory\">The logger factory.</param>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"faultInjectionOptions\">The fault injection options.</param>\n        public FaultInjectionGrainStorage(IGrainStorage realStorageProvider, string name, ILoggerFactory loggerFactory, \n            IGrainFactory grainFactory, FaultInjectionGrainStorageOptions faultInjectionOptions)\n        {\n            this.realStorageProvider = realStorageProvider;\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().FullName}.{name}\");\n            this.grainFactory = grainFactory;\n            this.options = faultInjectionOptions;\n        }\n\n        private Task InsertDelay()\n        {\n            return Task.Delay(this.options.Latency);\n        }\n           \n        /// <summary>Faults if exception is provided, otherwise calls through to  decorated storage provider.</summary>\n        /// <returns>Completion promise for the Read operation on the specified grain.</returns>\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            IStorageFaultGrain faultGrain = grainFactory.GetGrain<IStorageFaultGrain>(grainType);\n            try\n            {\n                await InsertDelay();\n                await faultGrain.OnRead(grainId);\n            }\n            catch (Exception)\n            {\n                logger.LogInformation(\n                    \"Fault injected for ReadState for grain {GrainId} of type {GrainType}\",\n                    grainId,\n                    grainType);\n                throw;\n            }\n            logger.LogInformation(\n                \"ReadState for grain {GrainId} of type {GrainType}\",\n                grainId,\n                grainType);\n            await realStorageProvider.ReadStateAsync(grainType, grainId, grainState);\n        }\n\n        /// <summary>Faults if exception is provided, otherwise calls through to  decorated storage provider.</summary>\n        /// <returns>Completion promise for the Write operation on the specified grain.</returns>\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            IStorageFaultGrain faultGrain = grainFactory.GetGrain<IStorageFaultGrain>(grainType);\n            try\n            {\n                await InsertDelay();\n                await faultGrain.OnWrite(grainId);\n            }\n            catch (Exception)\n            {\n                logger.LogInformation(\n                    \"Fault injected for WriteState for grain {GrainId} of type {GrainType}\",\n                    grainId,\n                    grainType);\n                throw;\n            }\n            logger.LogInformation(\n                \"WriteState for grain {GrainId} of type {GrainType}\",\n                grainId,\n                grainType);\n            await realStorageProvider.WriteStateAsync(grainType, grainId, grainState);\n        }\n\n        /// <summary>Faults if exception is provided, otherwise calls through to  decorated storage provider.</summary>\n        /// <returns>Completion promise for the Delete operation on the specified grain.</returns>\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            IStorageFaultGrain faultGrain = grainFactory.GetGrain<IStorageFaultGrain>(grainType);\n            try\n            {\n                await InsertDelay();\n                await faultGrain.OnClear(grainId);\n            }\n            catch (Exception)\n            {\n                logger.LogInformation(\n                    \"Fault injected for ClearState for grain {GrainId} of type {GrainType}\",\n                    grainId,\n                    grainType);\n                throw;\n            }\n\n            logger.LogInformation(\n                \"ClearState for grain {GrainId} of type {GrainType}\",\n                grainId,\n                grainType);\n            await realStorageProvider.ClearStateAsync(grainType, grainId, grainState);\n        }\n\n        /// <inheritdoc />\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            (realStorageProvider as ILifecycleParticipant<ISiloLifecycle>)?.Participate(lifecycle);\n        }\n    }\n\n    /// <summary>\n    /// Factory to create FaultInjectionGrainStorage\n    /// </summary>\n    public static class FaultInjectionGrainStorageFactory\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"FaultInjectionGrainStorage\"/> instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"injectedGrainStorageFactory\">The injected grain storage factory.</param>\n        /// <returns>The new instance.</returns>\n        public static IGrainStorage Create(IServiceProvider services, string name, Func<IServiceProvider, string, IGrainStorage> injectedGrainStorageFactory)\n        {\n            return new FaultInjectionGrainStorage(injectedGrainStorageFactory(services,name), name, services.GetRequiredService<ILoggerFactory>(), services.GetRequiredService<IGrainFactory>(),\n                services.GetRequiredService<IOptionsMonitor<FaultInjectionGrainStorageOptions>>().Get(name));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/FaultInjectionStorageServiceCollectionExtensions.cs",
    "content": "\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"IServiceCollection\"/>.\n    /// </summary>\n    public static class FaultInjectionStorageServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configures a silo to use <see cref=\"FaultInjectionGrainStorage\" />.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"configureOptions\">The memory storage configuration delegate.</param>\n        /// <param name=\"configureFaultInjectionOptions\">The fault injection provider configuration delegate.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddFaultInjectionMemoryStorage(\n            this IServiceCollection services,\n            string name,\n            Action<MemoryGrainStorageOptions> configureOptions,\n            Action<FaultInjectionGrainStorageOptions> configureFaultInjectionOptions)\n        {\n            return services.AddFaultInjectionMemoryStorage(name,\n                ob => ob.Configure(configureOptions), faultOb => faultOb.Configure(configureFaultInjectionOptions));\n        }\n\n        /// <summary>\n        /// Configures a silo to use <see cref=\"FaultInjectionGrainStorage\" />.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"configureOptions\">The memory storage configuration delegate.</param>\n        /// <param name=\"configureFaultInjectionOptions\">The fault injection provider configuration delegate.</param>\n        /// <returns>The service collection.</returns>\n        public static IServiceCollection AddFaultInjectionMemoryStorage(\n            this IServiceCollection services,\n            string name,\n            Action<OptionsBuilder<MemoryGrainStorageOptions>> configureOptions = null,\n            Action<OptionsBuilder<FaultInjectionGrainStorageOptions>> configureFaultInjectionOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<MemoryGrainStorageOptions>(name));\n            configureFaultInjectionOptions?.Invoke(services.AddOptions<FaultInjectionGrainStorageOptions>(name));\n            services.ConfigureNamedOptionForLogging<MemoryGrainStorageOptions>(name);\n            services.ConfigureNamedOptionForLogging<FaultInjectionGrainStorageOptions>(name);\n            services.AddKeyedSingleton<IGrainStorage>(name, (svc, n) => FaultInjectionGrainStorageFactory.Create(svc, n as string, MemoryGrainStorageFactory.Create))\n                .AddKeyedSingleton<ILifecycleParticipant<ISiloLifecycle>>(name, (s, n) => (ILifecycleParticipant<ISiloLifecycle>)s.GetRequiredKeyedService<IGrainStorage>(n));\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/FaultyMemoryStorage.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"ISiloBuilder\"/>.\n    /// </summary>\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configures a silo to use <see cref=\"FaultInjectionGrainStorage\" />.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"configureOptions\">The memory storage configuration delegate.</param>\n        /// <param name=\"configureFaultInjectionOptions\">The fault injection provider configuration delegate.</param>\n        /// <returns>The silo builder</returns>\n        public static ISiloBuilder AddFaultInjectionMemoryStorage(\n            this ISiloBuilder builder,\n            string name,\n            Action<MemoryGrainStorageOptions> configureOptions,\n            Action<FaultInjectionGrainStorageOptions> configureFaultInjectionOptions)\n        {\n            return builder.ConfigureServices(services => services.AddFaultInjectionMemoryStorage(name,\n                ob => ob.Configure(configureOptions), faultOb => faultOb.Configure(configureFaultInjectionOptions)));\n        }\n\n        /// <summary>\n        /// Configures a silo to use <see cref=\"FaultInjectionGrainStorage\" />.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"name\">The storage provider name.</param>\n        /// <param name=\"configureOptions\">The memory storage configuration delegate.</param>\n        /// <param name=\"configureFaultInjectionOptions\">The fault injection provider configuration delegate.</param>\n        /// <returns>The silo builder</returns>\n        public static ISiloBuilder AddFaultInjectionMemoryStorage(\n            this ISiloBuilder builder,\n            string name,\n            Action<OptionsBuilder<MemoryGrainStorageOptions>> configureOptions = null,\n            Action<OptionsBuilder<FaultInjectionGrainStorageOptions>> configureFaultInjectionOptions = null)\n        {\n            return builder.ConfigureServices(services => services.AddFaultInjectionMemoryStorage(name,\n               configureOptions, configureFaultInjectionOptions));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/IStorageFaultGrain.cs",
    "content": "\nusing System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Grain that tracks storage exceptions to be injected.\n    /// </summary>\n    public interface IStorageFaultGrain : IGrainWithStringKey\n    {\n        /// <summary>\n        /// Adds a storage exception to be thrown when the referenced grain reads state from a storage provider\n        /// </summary>\n        /// <returns>Task.</returns>\n        Task AddFaultOnRead(GrainId grainId, Exception exception);\n\n        /// <summary>\n        /// Adds a storage exception to be thrown when the referenced grain writes state to a storage provider\n        /// </summary>\n        /// <returns>Task.</returns>\n        Task AddFaultOnWrite(GrainId grainId, Exception exception);\n\n        /// <summary>\n        /// Adds a storage exception to be thrown when the referenced grain clears state in a storage provider\n        /// </summary>\n        /// <returns>Task.</returns>\n        Task AddFaultOnClear(GrainId grainId, Exception exception);\n\n        /// <summary>\n        /// Throws a storage exception if one has been added for the grain reference for reading.\n        /// </summary>\n        Task OnRead(GrainId grainId);\n\n        /// <summary>\n        /// Throws a storage exception if one has been added for the grain reference for writing.\n        /// </summary>\n        Task OnWrite(GrainId grainId);\n\n        /// <summary>\n        /// Throws a storage exception if one has been added for the grain reference for clearing state.\n        /// </summary>\n        Task OnClear(GrainId grainId);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/RandomlyInjectedStorageException.cs",
    "content": "using Orleans.Storage;\nusing System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Represents a randomly injected storage exception.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class RandomlyInjectedStorageException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RandomlyInjectedStorageException\"/> class.\n        /// </summary>\n        public RandomlyInjectedStorageException() : base(\"injected fault\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RandomlyInjectedStorageException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The <see cref=\"T:System.Runtime.Serialization.SerializationInfo\" /> that holds the serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The <see cref=\"T:System.Runtime.Serialization.StreamingContext\" /> that contains contextual information about the source or destination.</param>\n        [Obsolete]\n        private RandomlyInjectedStorageException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Represents a randomly injected <see cref=\"InconsistentStateException\"/>.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class RandomlyInjectedInconsistentStateException : InconsistentStateException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RandomlyInjectedInconsistentStateException\"/> class.\n        /// </summary>\n        public RandomlyInjectedInconsistentStateException() : base(\"injected fault\") { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RandomlyInjectedInconsistentStateException\"/> class.\n        /// </summary>\n        /// <param name=\"info\">The serialization info.</param>\n        /// <param name=\"context\">The context.</param>\n        [Obsolete]\n        private RandomlyInjectedInconsistentStateException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/TestStorageProviders/StorageFaultGrain.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Threading;\n\nnamespace Orleans.TestingHost\n{\n    /// <summary>\n    /// Grain that tracks storage exceptions to be injected.\n    /// </summary>\n    public class StorageFaultGrain : Grain, IStorageFaultGrain\n    {\n        private ILogger logger;\n        private Dictionary<GrainId, Exception> readFaults;\n        private Dictionary<GrainId, Exception> writeFaults;\n        private Dictionary<GrainId, Exception> clearfaults;\n\n        /// <inheritdoc />\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await base.OnActivateAsync(cancellationToken);\n            logger = this.ServiceProvider.GetService<ILoggerFactory>().CreateLogger($\"{typeof (StorageFaultGrain).FullName}-{IdentityString}-{RuntimeIdentity}\");\n            readFaults = new();\n            writeFaults = new();\n            clearfaults = new();\n            logger.LogInformation(\"Activate.\");\n        }\n\n        /// <inheritdoc />\n        public Task AddFaultOnRead(GrainId grainId, Exception exception)\n        {\n            readFaults.Add(grainId, exception);\n            logger.LogInformation(\"Added ReadState fault for {GrainId}.\", GrainId);\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public Task AddFaultOnWrite(GrainId grainId, Exception exception)\n        {\n            writeFaults.Add(grainId, exception);\n            logger.LogInformation(\"Added WriteState fault for {GrainId}.\", GrainId);\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public Task AddFaultOnClear(GrainId grainId, Exception exception)\n        {\n            clearfaults.Add(grainId, exception);\n            logger.LogInformation(\"Added ClearState fault for {GrainId}.\", GrainId);\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public Task OnRead(GrainId grainId)\n        {\n            if (readFaults.Remove(grainId, out var exception))\n            {\n                throw exception;\n            }\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public Task OnWrite(GrainId grainId)\n        {\n            if (writeFaults.Remove(grainId, out var exception))\n            {\n                throw exception;\n            }\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public Task OnClear(GrainId grainId)\n        {\n            if (clearfaults.Remove(grainId, out var exception))\n            {\n                throw exception;\n            }\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/UnixSocketTransport/UnixSocketConnectionExtensions.cs",
    "content": "using System;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\n\nnamespace Orleans.TestingHost.UnixSocketTransport;\n\npublic static class UnixSocketConnectionExtensions\n{\n    public static ISiloBuilder UseUnixSocketConnection(this ISiloBuilder siloBuilder)\n    {\n        siloBuilder.ConfigureServices(services =>\n        {\n            services.AddKeyedSingleton<object, IConnectionFactory>(SiloConnectionFactory.ServicesKey, CreateUnixSocketConnectionFactory());\n            services.AddKeyedSingleton<object, IConnectionListenerFactory>(SiloConnectionListener.ServicesKey, CreateUnixSocketConnectionListenerFactory());\n            services.AddKeyedSingleton<object, IConnectionListenerFactory>(GatewayConnectionListener.ServicesKey, CreateUnixSocketConnectionListenerFactory());\n        });\n\n        return siloBuilder;\n    }\n\n    public static IClientBuilder UseUnixSocketConnection(this IClientBuilder clientBuilder)\n    {\n        clientBuilder.ConfigureServices(services =>\n        {\n            services.AddKeyedSingleton<object, IConnectionFactory>(ClientOutboundConnectionFactory.ServicesKey, CreateUnixSocketConnectionFactory());\n        });\n\n        return clientBuilder;\n    }\n\n    private static Func<IServiceProvider, object, IConnectionFactory> CreateUnixSocketConnectionFactory()\n    {\n        return (IServiceProvider sp, object key) => ActivatorUtilities.CreateInstance<UnixSocketConnectionFactory>(sp);\n    }\n\n    private static Func<IServiceProvider, object, IConnectionListenerFactory> CreateUnixSocketConnectionListenerFactory()\n    {\n        return (IServiceProvider sp, object key) => ActivatorUtilities.CreateInstance<UnixSocketConnectionListenerFactory>(sp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/UnixSocketTransport/UnixSocketConnectionFactory.cs",
    "content": "using System.Buffers;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Networking.Shared;\n\nnamespace Orleans.TestingHost.UnixSocketTransport;\n\ninternal class UnixSocketConnectionFactory : IConnectionFactory\n{\n    private readonly SocketsTrace trace;\n    private readonly UnixSocketConnectionOptions socketConnectionOptions;\n    private readonly SocketSchedulers schedulers;\n    private readonly MemoryPool<byte> memoryPool;\n\n    public UnixSocketConnectionFactory(\n        ILoggerFactory loggerFactory,\n        IOptions<UnixSocketConnectionOptions> options,\n        SocketSchedulers schedulers,\n        SharedMemoryPool memoryPool)\n    {\n        var logger = loggerFactory.CreateLogger(\"Orleans.UnixSocket\");\n        this.trace = new SocketsTrace(logger);\n        this.socketConnectionOptions = options.Value;\n        this.schedulers = schedulers;\n        this.memoryPool = memoryPool.Pool;\n    }\n\n    public async ValueTask<ConnectionContext> ConnectAsync(EndPoint endpoint, CancellationToken cancellationToken = default)\n    {\n        var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);\n        var unixEndpoint = new UnixDomainSocketEndPoint(socketConnectionOptions.ConvertEndpointToPath(endpoint));\n        await socket.ConnectAsync(unixEndpoint);\n        var scheduler = this.schedulers.GetScheduler();\n        var connection = new SocketConnection(socket, memoryPool, scheduler, trace);\n        connection.Start();\n        return connection;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/UnixSocketTransport/UnixSocketConnectionListener.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Orleans.Networking.Shared;\n\nnamespace Orleans.TestingHost.UnixSocketTransport;\n\ninternal class UnixSocketConnectionListener : IConnectionListener\n{\n    private readonly UnixDomainSocketEndPoint _unixEndpoint;\n    private readonly EndPoint _endpoint;\n    private readonly UnixSocketConnectionOptions _socketConnectionOptions;\n    private readonly SocketsTrace _trace;\n    private readonly SocketSchedulers _schedulers;\n    private readonly MemoryPool<byte> _memoryPool;\n    private Socket _listenSocket;\n\n    public UnixSocketConnectionListener(UnixDomainSocketEndPoint unixEndpoint, EndPoint endpoint, UnixSocketConnectionOptions socketConnectionOptions, SocketsTrace trace, SocketSchedulers schedulers)\n    {\n        _unixEndpoint = unixEndpoint;\n        _endpoint = endpoint;\n        _socketConnectionOptions = socketConnectionOptions;\n        _trace = trace;\n        _schedulers = schedulers;\n        _memoryPool = socketConnectionOptions.MemoryPoolFactory();\n    }\n\n    public EndPoint EndPoint => _endpoint;\n\n    public void Bind()\n    {\n        _listenSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);\n        _listenSocket.Bind(_unixEndpoint);\n        _listenSocket.Listen(512);\n    }\n\n    public async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default)\n    {\n        while (true)\n        {\n            try\n            {\n                var acceptSocket = await _listenSocket.AcceptAsync();\n\n                var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers.GetScheduler(), _trace);\n\n                connection.Start();\n\n                return connection;\n            }\n            catch (ObjectDisposedException)\n            {\n                // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done\n                return null;\n            }\n            catch (SocketException e) when (e.SocketErrorCode == SocketError.OperationAborted)\n            {\n                // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done\n                return null;\n            }\n            catch (SocketException)\n            {\n                // The connection got reset while it was in the backlog, so we try again.\n                _trace.ConnectionReset(connectionId: \"(null)\");\n            }\n        }\n    }\n\n    public ValueTask DisposeAsync()\n    {\n        _listenSocket?.Dispose();\n        return default;\n    }\n\n    public ValueTask UnbindAsync(CancellationToken cancellationToken = default)\n    {\n        _listenSocket?.Dispose();\n        _memoryPool?.Dispose();\n        return default;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/UnixSocketTransport/UnixSocketConnectionListenerFactory.cs",
    "content": "using System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Connections;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Networking.Shared;\n\nnamespace Orleans.TestingHost.UnixSocketTransport;\n\ninternal class UnixSocketConnectionListenerFactory : IConnectionListenerFactory\n{\n    private readonly UnixSocketConnectionOptions socketConnectionOptions;\n    private readonly SocketsTrace trace;\n    private readonly SocketSchedulers schedulers;\n\n    public UnixSocketConnectionListenerFactory(\n        ILoggerFactory loggerFactory,\n        IOptions<UnixSocketConnectionOptions> socketConnectionOptions,\n        SocketSchedulers schedulers)\n    {\n        this.socketConnectionOptions = socketConnectionOptions.Value;\n        var logger = loggerFactory.CreateLogger(\"Orleans.UnixSockets\");\n        this.trace = new SocketsTrace(logger);\n        this.schedulers = schedulers;\n    }\n\n    public ValueTask<IConnectionListener> BindAsync(EndPoint endpoint, CancellationToken cancellationToken = default)\n    {\n        var unixEndpoint = new UnixDomainSocketEndPoint(socketConnectionOptions.ConvertEndpointToPath(endpoint));\n\n        var listener = new UnixSocketConnectionListener(unixEndpoint, endpoint, this.socketConnectionOptions, this.trace, this.schedulers);\n        listener.Bind();\n        return new ValueTask<IConnectionListener>(listener);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/UnixSocketTransport/UnixSocketConnectionOptions.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.IO;\nusing System.Net;\nusing System.Text.RegularExpressions;\nusing Orleans.Networking.Shared;\n\nnamespace Orleans.TestingHost.UnixSocketTransport;\n\npublic partial class UnixSocketConnectionOptions\n{\n    /// <summary>\n    /// Get or sets to function used to get a filename given an endpoint\n    /// </summary>\n    public Func<EndPoint, string> ConvertEndpointToPath { get; set; } = DefaultConvertEndpointToPath;\n\n    /// <summary>\n    /// Gets or sets the memory pool factory.\n    /// </summary>\n    internal Func<MemoryPool<byte>> MemoryPoolFactory { get; set; } = () => KestrelMemoryPool.Create();\n\n    [GeneratedRegex(\"[^a-zA-Z0-9]\")]\n    private static partial Regex ConvertEndpointRegex();\n\n    private static string DefaultConvertEndpointToPath(EndPoint endPoint) => Path.Combine(Path.GetTempPath(), ConvertEndpointRegex().Replace(endPoint.ToString(), \"_\"));\n}"
  },
  {
    "path": "src/Orleans.TestingHost/Utils/AsyncResultHandle.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.TestingHost.Utils\n{\n    /// <summary>\n    /// This class is for internal testing use only.\n    /// </summary>\n    public class AsyncResultHandle\n    {\n        private bool done = false;\n        private bool continueFlag = false;\n\n        /// <summary> Reset the current result handle </summary>\n        public virtual void Reset()\n        {\n            Exception = null;\n            Result = null;\n            done = false;\n            continueFlag = false;\n        }\n\n        /// <summary> Get or set the Done flag </summary>\n        public bool Done\n        {\n            get { return done; }\n            set { done = value; }\n        }\n\n        /// <summary> Get or set the Continue flag </summary>\n        public bool Continue\n        {\n            get { return continueFlag; }\n            set { continueFlag = value; }\n        }\n\n        /// <summary> Get or set the exception of the result handle </summary>\n        public Exception Exception { get; set; }\n\n        /// <summary> Get or set the value of the result handle </summary>\n        public object Result { get; set; }\n\n        /// <summary>\n        /// </summary>\n        /// <param name=\"timeout\"></param>\n        /// <returns>Returns <c>true</c> if operation completes before timeout</returns>\n        public Task<bool> WaitForFinished(TimeSpan timeout)\n        {\n            return WaitFor(timeout, () => done);\n        }\n\n        /// <summary>\n        /// </summary>\n        /// <param name=\"timeout\"></param>\n        /// <returns>Returns <c>true</c> if operation completes before timeout</returns>\n        public Task<bool> WaitForContinue(TimeSpan timeout)\n        {\n            return WaitFor(timeout, () => continueFlag);\n        }\n\n        /// <summary>\n        /// </summary>\n        /// <param name=\"timeout\"></param>\n        /// <param name=\"checkFlag\"></param>\n        /// <returns>Returns <c>true</c> if operation completes before timeout</returns>\n        public async Task<bool> WaitFor(TimeSpan timeout, Func<bool> checkFlag)\n        {\n            double remaining = timeout.TotalMilliseconds;\n            while (!checkFlag())\n            {\n                if (remaining < 0)\n                {\n                    //throw new TimeoutException(\"Timeout waiting for result for \" + timeout);\n                    return false;\n                }\n\n                await Task.Delay(TimeSpan.FromMilliseconds(200));\n                remaining -= 200;\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/Utils/StorageEmulator.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\nnamespace Orleans.TestingHost.Utils\n{\n    /// <summary>\n    /// A wrapper on Azure Storage Emulator.\n    /// </summary>\n    /// <remarks>It might be tricky to implement this as a <see cref=\"IDisposable\">IDisposable</see>, isolated, autonomous instance, \n    /// see at <see href=\"http://azure.microsoft.com/en-us/documentation/articles/storage-use-emulator/\">Use the Azure Storage Emulator for Development and Testing</see>\n    /// for pointers.</remarks>\n    public static class StorageEmulator\n    {\n        /// <summary>\n        /// The storage emulator process name. One way to enumerate running process names is\n        /// Get-Process | Format-Table Id, ProcessName -autosize. If there were multiple storage emulator\n        /// processes running, they would named WASTOR~1, WASTOR~2, ... WASTOR~n.\n        /// </summary>\n        private static readonly string[] storageEmulatorProcessNames = new[]\n        {\n            \"AzureStorageEmulator\", // newest\n            \"Windows Azure Storage Emulator Service\", // >= 2.7\n            \"WAStorageEmulator\", // < 2.7\n        };\n\n        //The file names aren't the same as process names.\n        private static readonly string[] storageEmulatorFilenames = new[]\n        {\n            \"AzureStorageEmulator.exe\", // >= 2.7\n            \"WAStorageEmulator.exe\", // < 2.7\n        };\n\n        /// <summary>\n        /// Is the storage emulator already started.\n        /// </summary>\n        /// <returns><see langword=\"true\" /> if this instance is started; otherwise, <see langword=\"false\" />.</returns>\n        public static bool IsStarted()\n        {\n            return GetStorageEmulatorProcess();\n        }\n\n\n        /// <summary>\n        /// Checks if the storage emulator exists, i.e. is installed.\n        /// </summary>\n        /// <value><see langword=\"true\" /> if the storage emulator exists; otherwise, <see langword=\"false\" />.</value>\n        public static bool Exists\n        {\n            get\n            {\n                return GetStorageEmulatorPath() != null;\n            }\n        }\n\n        /// <summary>\n        /// Storage Emulator help.\n        /// </summary>\n        /// <returns>Storage emulator help.</returns>\n        public static string Help()\n        {\n            if (!IsStarted()) return \"Error happened. Has StorageEmulator.Start() been called?\";\n\n            try\n            {\n                //This process handle returns immediately.\n                using(var process = Process.Start(CreateProcessArguments(\"help\")))\n                {\n                    process.WaitForExit();\n                    StringBuilder help = new();\n                    while(!process.StandardOutput.EndOfStream)\n                    {\n                        help.Append(process.StandardOutput.ReadLine());\n                    }\n\n                    return help.ToString();\n                }\n            }\n            catch (Exception exc)\n            {\n                return exc.ToString();\n            }\n        }\n\n        /// <summary>\n        /// Tries to start the storage emulator.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the process was started successfully; <see langword=\"false\"/> otherwise.</returns>\n        public static bool TryStart()\n        {\n            if (!StorageEmulator.Exists)\n                return false;\n\n            return Start();\n        }\n\n        /// <summary>\n        /// Starts the storage emulator if not already started.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the process was started successfully; <see langword=\"false\"/> otherwise.</returns>\n        public static bool Start()\n        {\n            if (IsStarted()) return true;\n\n            try\n            {\n                //This process handle returns immediately.\n                using(var process = Process.Start(CreateProcessArguments(\"start\")))\n                {\n                    if (process == null) return false;\n                    process.WaitForExit();\n                    return process.ExitCode == 0;\n                }\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Stops the storage emulator if started.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the process was stopped successfully or was already stopped; <see langword=\"false\"/> otherwise.</returns>\n        public static bool Stop()\n        {\n            if (!IsStarted()) return false;\n\n            try\n            {\n                //This process handle returns immediately.\n                using(var process = Process.Start(CreateProcessArguments(\"stop\")))\n                {\n                    process.WaitForExit();\n                    return process.ExitCode == 0;\n                }\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"ProcessStartInfo\">ProcessStartInfo</see> to be used as an argument\n        /// to other operations in this class.\n        /// </summary>\n        /// <param name=\"arguments\">The arguments.</param>\n        /// <returns>A new <see cref=\"ProcessStartInfo\"/> that has the given arguments.</returns>\n        private static ProcessStartInfo CreateProcessArguments(string arguments)\n        {\n#pragma warning disable CA1416 // Validate platform compatibility\n            return new ProcessStartInfo(GetStorageEmulatorPath())\n            {\n                WindowStyle = ProcessWindowStyle.Hidden,\n                ErrorDialog = true,\n                LoadUserProfile = true,\n                CreateNoWindow = true,\n                UseShellExecute = false,\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n                Arguments = arguments\n            };\n#pragma warning restore CA1416\n        }\n\n        /// <summary>\n        /// Queries the storage emulator process from the system.\n        /// </summary>\n        /// <returns><see langword=\"true\" /> if the storage emulator process was found, <see langword=\"false\" /> otherwise.</returns>\n        private static bool GetStorageEmulatorProcess()\n        {\n            foreach (var name in storageEmulatorProcessNames)\n            {\n                var ps = Process.GetProcessesByName(name);\n                if (ps.Length != 0)\n                {\n                    foreach (var p in ps)\n                        p.Dispose();\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Returns a full path to the storage emulator executable, including the executable name and file extension.\n        /// </summary>\n        /// <returns>A full path to the storage emulator executable, or null if not found.</returns>\n        private static string GetStorageEmulatorPath()\n        {\n            //Try to take the newest known emulator path. If it does not exist, try an older one.\n            string exeBasePath = Path.Combine(GetProgramFilesBasePath(), @\"Microsoft SDKs\\Azure\\Storage Emulator\\\");\n\n            return storageEmulatorFilenames\n                .Select(filename => Path.Combine(exeBasePath, filename))\n                .FirstOrDefault(File.Exists);\n        }\n\n\n        /// <summary>\n        /// Determines the Program Files base directory.\n        /// </summary>\n        /// <returns>The Program files base directory.</returns>\n        private static string GetProgramFilesBasePath()\n        {\n            return Environment.Is64BitOperatingSystem ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.TestingHost/Utils/TestingUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost.Logging;\n\nnamespace Orleans.TestingHost.Utils\n{\n    /// <summary> Collection of test utilities </summary>\n    public static class TestingUtils\n    {\n        private static long uniquifier = Stopwatch.GetTimestamp();\n\n        /// <summary>\n        /// Configure <paramref name=\"builder\" /> with a <see cref=\"FileLoggerProvider\" /> which logs to <paramref name=\"filePath\" />\n        /// by default;\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"filePath\">The file path.</param>\n        public static void ConfigureDefaultLoggingBuilder(ILoggingBuilder builder, string filePath)\n        {\n            builder.AddFile(filePath);\n        }\n\n        /// <summary>\n        /// Create trace file name for a specific node or client in a specific deployment\n        /// </summary>\n        /// <param name=\"nodeName\">Name of the node.</param>\n        /// <param name=\"clusterId\">The cluster identifier.</param>\n        /// <returns>The new trace file name.</returns>\n        public static string CreateTraceFileName(string nodeName, string clusterId)\n        {\n            const string traceFileFolder = \"logs\";\n\n            if (!Directory.Exists(traceFileFolder))\n            {\n                Directory.CreateDirectory(traceFileFolder);\n            }\n\n            var traceFileName = Path.Combine(traceFileFolder, $\"{clusterId}_{Interlocked.Increment(ref uniquifier):X}_{nodeName}.log\");\n\n            return traceFileName;\n        }\n\n        /// <summary>\n        /// Create the default logger factory, which would configure logger factory with a <see cref=\"FileLoggerProvider\" /> that writes logs to <paramref name=\"filePath\" /> and console.\n        /// by default;\n        /// </summary>\n        /// <param name=\"filePath\">The file path.</param>\n        /// <returns>ILoggerFactory.</returns>\n        public static ILoggerFactory CreateDefaultLoggerFactory(string filePath)\n        {\n            return CreateDefaultLoggerFactory(filePath, new LoggerFilterOptions());\n        }\n\n        /// <summary>\n        /// Create the default logger factory, which would configure logger factory with a <see cref=\"FileLoggerProvider\"/> that writes logs to <paramref name=\"filePath\"/> and console.\n        /// by default;\n        /// </summary>\n        /// <param name=\"filePath\">the logger file path</param>\n        /// <param name=\"filters\">log filters you want to configure your logging with</param>\n        /// <returns></returns>\n        public static ILoggerFactory CreateDefaultLoggerFactory(string filePath, LoggerFilterOptions filters)\n        {\n            var factory = new LoggerFactory(new List<ILoggerProvider>(), filters);\n            factory.AddProvider(new FileLoggerProvider(filePath));\n            return factory;\n        }\n\n        /// <summary> Run the predicate until it succeed or times out </summary>\n        /// <param name=\"predicate\">The predicate to run</param>\n        /// <param name=\"timeout\">The timeout value</param>\n        /// <param name=\"delayOnFail\">The time to delay next call upon failure</param>\n        /// <returns>True if the predicate succeed, false otherwise</returns>\n        public static async Task WaitUntilAsync(Func<bool,Task<bool>> predicate, TimeSpan timeout, TimeSpan? delayOnFail = null)\n        {\n            delayOnFail = delayOnFail ?? TimeSpan.FromSeconds(1);\n            var keepGoing = new[] { true };\n            async Task loop()\n            {\n                bool passed;\n                do\n                {\n                    // need to wait a bit to before re-checking the condition.\n                    await Task.Delay(delayOnFail.Value);\n                    passed = await predicate(false);\n                }\n                while (!passed && keepGoing[0]);\n                if (!passed)\n                    await predicate(true);\n            }\n\n            var task = loop();\n            try\n            {\n                await Task.WhenAny(task, Task.Delay(timeout));\n            }\n            finally\n            {\n                keepGoing[0] = false;\n            }\n\n            await task;\n        }\n\n        /// <summary>\n        /// Multiply a timeout by a value\n        /// </summary>\n        /// <param name=\"time\">The time.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The resulting time span value.</returns>\n        public static TimeSpan Multiply(TimeSpan time, double value)\n        {\n            double ticksD = checked(time.Ticks * value);\n            long ticks = checked((long)ticksD);\n            return TimeSpan.FromTicks(ticks);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/Extensions/TransactionalStateExtensions.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public static class TransactionalStateExtensions\n    {\n        /// <summary>\n        /// Performs an update operation, without returning any result.\n        /// </summary>\n        /// <param name=\"transactionalState\">Transactional state to perform update upon.</param>\n        /// <param name=\"updateAction\">An action that updates the state.</param>\n        public static Task PerformUpdate<TState>(this ITransactionalState<TState> transactionalState, Action<TState> updateAction)\n            where TState : class, new()\n        {\n            return transactionalState.PerformUpdate<bool>(state => { updateAction(state); return true; });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/INamedTransactionalStateStorageFactory.cs",
    "content": "﻿\nnamespace Orleans.Transactions.Abstractions\n{\n    /// <summary>\n    /// Factory which creates an ITransactionalStateStorage by name.\n    /// </summary>\n    public interface INamedTransactionalStateStorageFactory\n    {\n        /// <summary>\n        /// Create an ITransactionalStateStorage by name.\n        /// </summary>\n        /// <typeparam name=\"TState\"></typeparam>\n        /// <param name=\"storageName\">Name of transaction state storage to create.</param>\n        /// <param name=\"stateName\">Name of transaction state.</param>\n        /// <returns>ITransactionalStateStorage, null if not found.</returns>\n        ITransactionalStateStorage<TState> Create<TState>(string storageName, string stateName) where TState : class, new();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionAgentStatistics.cs",
    "content": "﻿\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionAgentStatistics\n    {\n        void TrackTransactionStarted();\n        long TransactionsStarted { get; }\n\n        void TrackTransactionSucceeded();\n        long TransactionsSucceeded { get; }\n\n        void TrackTransactionFailed();\n        long TransactionsFailed { get; }\n\n        void TrackTransactionThrottled();\n        long TransactionsThrottled { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionCommitter.cs",
    "content": "﻿\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionCommitOperation<TService>\n        where TService : class\n    {\n        Task<bool> Commit(Guid transactionId, TService service);\n    }\n\n    public interface ITransactionCommitter<TService>\n        where TService : class\n    {\n        Task OnCommit(ITransactionCommitOperation<TService> operation);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionCommitterConfiguration.cs",
    "content": "﻿\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionCommitterConfiguration\n    {\n        string ServiceName { get; }\n        string StorageName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionCommitterFactory.cs",
    "content": "﻿namespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionCommitterFactory\n    {\n        ITransactionCommitter<TService> Create<TService>(ITransactionCommitterConfiguration config) where TService : class;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionDataCopier.cs",
    "content": "﻿\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionDataCopier<TData>\n    {\n        TData DeepCopy(TData original);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionManager.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionManager\n    {\n        /// <summary>\n        /// Request sent by TA to TM. The TM responds after committing or aborting the transaction.\n        /// </summary>\n        /// <param name=\"transactionId\">the id of the transaction to prepare</param>\n        /// <param name=\"accessCount\">number of reads/writes performed on this participant by this transaction</param>\n        /// <param name=\"timeStamp\">the commit timestamp for this transaction</param>\n        /// <param name=\"writerResources\">the participants who wrote during the transaction</param>\n        /// <param name=\"totalParticipants\">the total number of participants in the transaction</param>\n        /// <returns>the status of the transaction</returns>\n        Task<TransactionalStatus> PrepareAndCommit(Guid transactionId, AccessCounter accessCount, DateTime timeStamp,\n            List<ParticipantId> writerResources, int totalParticipants);\n\n        /// <summary>\n        /// One-way message sent by a participant to the TM after it (successfully or unsuccessfully) prepares.\n        /// </summary>\n        /// <param name=\"transactionId\">The id of the transaction</param>\n        /// <param name=\"timeStamp\">The commit timestamp of the transaction</param>\n        /// <param name=\"resource\">The participant sending the message</param>\n        /// <param name=\"status\">The outcome of the prepare</param>\n        /// <returns></returns>\n        Task Prepared(Guid transactionId, DateTime timeStamp, ParticipantId resource, TransactionalStatus status);\n\n        /// <summary>\n        /// One-way message sent by participants to TM, to let TM know they are still waiting to hear about\n        /// the fate of a transaction.\n        /// </summary>\n        /// <param name=\"transactionId\">The id of the transaction</param>\n        /// <param name=\"timeStamp\">The commit timestamp of the transaction</param>\n        /// <param name=\"resource\">The participant sending the message</param>\n        Task Ping(Guid transactionId, DateTime timeStamp, ParticipantId resource);\n    }\n\n    /// <summary>\n    /// Counts read and write accesses on a transaction participant.\n    /// </summary>\n    [GenerateSerializer]\n    [Serializable]\n    public struct AccessCounter\n    {\n        [Id(0)]\n        public int Reads;\n        [Id(1)]\n        public int Writes;\n\n        public static AccessCounter operator +(AccessCounter c1, AccessCounter c2)\n        {\n            return new AccessCounter { Reads = c1.Reads + c2.Reads, Writes = c1.Writes + c2.Writes };\n        }\n    }\n}\n\n  \n   \n\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionManagerExtension.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionManagerExtension : IGrainExtension\n    {\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        Task<TransactionalStatus> PrepareAndCommit(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp, List<ParticipantId> writeResources, int totalParticipants);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [OneWay]\n        Task Prepared(string resourceId, Guid transactionId, DateTime timestamp, ParticipantId resource, TransactionalStatus status);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [OneWay]\n        Task Ping(string resourceId, Guid transactionId, DateTime timeStamp, ParticipantId resource);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalResource.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    /// <summary>\n    /// Interface that allows a component to be a transaction participant.\n    /// </summary>\n    public interface ITransactionalResource\n    {\n        /// <summary>\n        /// Request sent by TA to all participants of a read-only transaction (one-phase commit). \n        /// Participants respond after committing or aborting the read.\n        /// </summary>\n        /// <param name=\"transactionId\">the id of the transaction to prepare</param>\n        /// <param name=\"accessCount\">number of reads/writes performed on this participant by this transaction</param>\n        /// <param name=\"timeStamp\">the commit timestamp for this transaction</param>\n        /// <returns></returns>\n        Task<TransactionalStatus> CommitReadOnly(Guid transactionId, AccessCounter accessCount, DateTime timeStamp);\n\n        /// <summary>\n        /// One-way message sent by TA to all participants except TM.  \n        /// </summary>\n        /// <param name=\"transactionId\">the id of the transaction to prepare</param>\n        /// <param name=\"accessCount\">number of reads/writes performed on this participant by this transaction</param>\n        /// <param name=\"timeStamp\">the commit timestamp for this transaction</param>\n        /// <param name=\"transactionManager\">the transaction manager for this transaction</param>\n        /// <returns></returns>\n        Task Prepare(Guid transactionId, AccessCounter accessCount,\n            DateTime timeStamp, ParticipantId transactionManager);\n\n        /// <summary>\n        /// One-way message sent by TA to participants to let them know a transaction has aborted.\n        /// </summary>\n        /// <param name=\"transactionId\">The id of the aborted transaction</param>\n        Task Abort(Guid transactionId);\n\n        /// <summary>\n        /// One-way message sent by TM to participants to let them know a transaction has aborted.\n        /// </summary>\n        /// <param name=\"transactionId\">The id of the aborted transaction</param>\n        /// <param name=\"timeStamp\">The commit timestamp of the aborted transaction</param>\n        /// <param name=\"status\">Reason for abort</param>\n        Task Cancel(Guid transactionId, DateTime timeStamp, TransactionalStatus status);\n\n        /// <summary>\n        /// Request sent by TM to participants to let them know a transaction has committed.\n        /// Participants respond after cleaning up all prepare records.\n        /// </summary>\n        /// <param name=\"transactionId\">The id of the committed transaction</param>\n        /// <param name=\"timeStamp\">The commit timestamp of the committed transaction</param>\n        Task Confirm(Guid transactionId, DateTime timeStamp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalResourceExtension.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionalResourceExtension : IGrainExtension\n    {\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        Task<TransactionalStatus> CommitReadOnly(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        Task Abort(string resourceId, Guid transactionId);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        Task Cancel(string resourceId, Guid transactionId, DateTime timeStamp, TransactionalStatus status);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        Task Confirm(string resourceId, Guid transactionId, DateTime timeStamp);\n\n        [AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [OneWay]\n        Task Prepare(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp, ParticipantId transactionManager);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalState.cs",
    "content": "﻿\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    /// <summary>\n    /// State that respects Orleans transaction semantics, and allows\n    /// read/write locking\n    /// </summary>\n    /// <typeparam name=\"TState\">The type of the state</typeparam>\n    public interface ITransactionalState<TState>  \n        where TState : class, new()\n    {\n        /// <summary>\n        /// Performs a read operation and returns the result, without modifying the state.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type of the return value</typeparam>\n        /// <param name=\"readFunction\">A function that reads the state and returns the result. MUST NOT modify the state.</param>\n        Task<TResult> PerformRead<TResult>(Func<TState, TResult> readFunction);\n\n        /// <summary>\n        /// Performs an update operation and returns the result.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type of the return value</typeparam>\n        /// <param name=\"updateFunction\">A function that can read and update the state, and return a result</param>\n        Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateFunction);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalStateConfiguration.cs",
    "content": "﻿\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionalStateConfiguration\n    {\n        string StateName { get; }\n        string StorageName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalStateFactory.cs",
    "content": "namespace Orleans.Transactions.Abstractions\n{\n    public class TransactionalStateConfiguration : ITransactionalStateConfiguration\n    {\n        private readonly string name;\n        private readonly string storage;\n        public TransactionalStateConfiguration(ITransactionalStateConfiguration config, ParticipantId.Role supportedRoles = ParticipantId.Role.Resource | ParticipantId.Role.Manager)\n        {\n            this.name = config.StateName;\n            this.storage = config.StorageName;\n            this.SupportedRoles = supportedRoles;\n        }\n        public string StateName => this.name;\n\n        public string StorageName => this.storage;\n\n        public ParticipantId.Role SupportedRoles { get; }\n    }\n\n    public interface ITransactionalStateFactory\n    {\n        ITransactionalState<TState> Create<TState>(TransactionalStateConfiguration config) where TState : class, new();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalStateStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    /// <summary>\n    /// Storage interface for transactional state\n    /// </summary>\n    /// <typeparam name=\"TState\">the type of the state</typeparam>\n    public interface ITransactionalStateStorage<TState>\n        where TState : class, new()\n    {\n        Task<TransactionalStorageLoadResponse<TState>> Load();\n\n        Task<string> Store(\n\n            string expectedETag,\n            TransactionalStateMetaData metadata,\n\n            // a list of transactions to prepare.\n            List<PendingTransactionState<TState>> statesToPrepare,\n\n            // if non-null, commit all pending transaction up to and including this sequence number.\n            long? commitUpTo,\n\n            // if non-null, abort all pending transactions with sequence numbers strictly larger than this one.\n            long? abortAfter\n        );\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class PendingTransactionState<TState>\n        where TState : class, new()\n    {\n        /// <summary>\n        /// Transactions are given dense local sequence numbers 1,2,3,4...\n        /// If a new transaction is prepared with the same sequence number as a \n        /// previously prepared transaction, it replaces it.\n        /// </summary>\n        [Id(0)]\n        public long SequenceId { get; set; }\n\n        /// <summary>\n        /// A globally unique identifier of the transaction. \n        /// </summary>\n        [Id(1)]\n        public string TransactionId { get; set; }\n\n        /// <summary>\n        /// The logical timestamp of the transaction.\n        /// Timestamps are guaranteed to be monotonically increasing.\n        /// </summary>\n        [Id(2)]\n        public DateTime TimeStamp { get; set; }\n\n        /// <summary>\n        /// The transaction manager that knows about the status of this prepared transaction,\n        /// or null if this is the transaction manager.\n        /// Used during recovery to inquire about the fate of the transaction.\n        /// </summary>\n        [Id(3)]\n        public ParticipantId TransactionManager { get; set; }\n\n        /// <summary>\n        /// A snapshot of the state after this transaction executed\n        /// </summary>\n        [Id(4)]\n        public TState State { get; set; }\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class TransactionalStorageLoadResponse<TState>\n        where TState : class, new()\n    {\n        public TransactionalStorageLoadResponse() : this(null, new TState(), 0, new TransactionalStateMetaData(), Array.Empty<PendingTransactionState<TState>>()) { }\n\n        public TransactionalStorageLoadResponse(string etag, TState committedState, long committedSequenceId, TransactionalStateMetaData metadata, IReadOnlyList<PendingTransactionState<TState>> pendingStates)\n        {\n            this.ETag = etag;\n            this.CommittedState = committedState;\n            this.CommittedSequenceId = committedSequenceId;\n            this.Metadata = metadata;\n            this.PendingStates = pendingStates;\n        }\n\n        [Id(0)]\n        public string ETag { get; set; }\n\n        [Id(1)]\n        public TState CommittedState { get; set; }\n\n        /// <summary>\n        /// The local sequence id of the last committed transaction, or zero if none\n        /// </summary>\n        [Id(2)]\n        public long CommittedSequenceId { get; set; }\n\n        /// <summary>\n        /// Additional state maintained by the transaction algorithm, such as commit records\n        /// </summary>\n        [Id(3)]\n        public TransactionalStateMetaData Metadata { get; set; }\n\n        /// <summary>\n        /// List of pending states, ordered by sequence id\n        /// </summary>\n        [Id(4)]\n        public IReadOnlyList<PendingTransactionState<TState>> PendingStates { get; set; }\n    }\n\n    /// <summary>\n    /// Metadata is stored in storage, as a JSON object\n    /// </summary>\n    [GenerateSerializer]\n    [Serializable]\n    public sealed class TransactionalStateMetaData\n    {\n        [Id(0)]\n        public DateTime TimeStamp { get; set; } = default;\n\n        [Id(1)]\n        public Dictionary<Guid, CommitRecord> CommitRecords { get; set; } = new Dictionary<Guid, CommitRecord>();\n    }\n\n    [Serializable, GenerateSerializer, Immutable]\n    public sealed class CommitRecord\n    {\n        [Id(0)]\n        public DateTime Timestamp { get; set; }\n\n        [Id(1)]\n        public List<ParticipantId> WriteParticipants { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/ITransactionalStateStorageFactory.cs",
    "content": "﻿\nusing Orleans.Runtime;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    public interface ITransactionalStateStorageFactory\n    {\n        ITransactionalStateStorage<TState> Create<TState>(string stateName, IGrainContext context) where TState : class, new();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/TransactionCommitterAttribute.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    [AttributeUsage(AttributeTargets.Parameter)]\n    public class TransactionCommitterAttribute : Attribute, IFacetMetadata, ITransactionCommitterConfiguration\n    {\n        public string ServiceName { get; }\n        public string StorageName { get; }\n\n        public TransactionCommitterAttribute(string serviceName, string storageName = null)\n        {\n            this.ServiceName = serviceName;\n            this.StorageName = storageName;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Abstractions/TransactionalStateAttribute.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions.Abstractions\n{\n    [AttributeUsage(AttributeTargets.Parameter)]\n    public class TransactionalStateAttribute : Attribute, IFacetMetadata, ITransactionalStateConfiguration\n    {\n        public string StateName { get; }\n        public string StorageName { get; }\n\n        public TransactionalStateAttribute(string stateName, string storageName = null)\n        {\n            this.StateName = stateName;\n            this.StorageName = storageName;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DisabledTransactionAgent.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions\n{\n    internal class DisabledTransactionAgent : ITransactionAgent\n    {\n        public Task Abort(TransactionInfo transactionInfo)\n        {\n            throw new OrleansTransactionsDisabledException();\n        }\n\n        public Task<(TransactionalStatus Status, Exception exception)> Resolve(TransactionInfo transactionInfo)\n        {\n            throw new OrleansTransactionsDisabledException();\n        }\n\n        public Task<TransactionInfo> StartTransaction(bool readOnly, TimeSpan timeout)\n        {\n            throw new OrleansStartTransactionFailedException(new OrleansTransactionsDisabledException());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/ContextResourceFactoryExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Orleans.Runtime;\n\nnamespace Orleans.Transactions\n{\n    internal class ResourceFactoryRegistry<T> : Dictionary<string, Func<T>> { };\n\n    internal static class ContextResourceFactoryExtensions\n    {\n        public static void RegisterResourceFactory<T>(this IGrainContext context, string name, Func<T> factory)\n        {\n            ResourceFactoryRegistry<T> registry = context.GetResourceFactoryRegistry<T>(true);\n            registry[name] = factory;\n        }\n\n        public static ResourceFactoryRegistry<T> GetResourceFactoryRegistry<T>(this IGrainContext context, bool createIfNotExists = false)\n        {\n            ResourceFactoryRegistry<T> result = context.GetComponent<ResourceFactoryRegistry<T>>();\n            if (createIfNotExists && result == null)\n            {\n                result = new ResourceFactoryRegistry<T>();\n                context.SetComponent(result);\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/ParticipantId.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    [Serializable, GenerateSerializer, Immutable]\n    public readonly struct ParticipantId\n    {\n        public static readonly IEqualityComparer<ParticipantId> Comparer = new IdComparer();\n\n        [GenerateSerializer]\n        [Flags]\n        public enum Role\n        {\n            Resource = 1 << 0,\n            Manager = 1 << 1,\n            PriorityManager = 1 << 2\n        }\n\n        [Id(0)]\n        public string Name { get; }\n\n        [Id(1)]\n        public GrainReference Reference { get; }\n\n        [Id(2)]\n        public Role SupportedRoles { get; }\n\n        public ParticipantId(string name, GrainReference reference, Role supportedRoles)\n        {\n            this.Name = name;\n            this.Reference = reference;\n            this.SupportedRoles = supportedRoles;\n        }\n\n        public override string ToString()\n        {\n            return $\"ParticipantId.{Name}.{Reference}\";\n        }\n\n        [GenerateSerializer, Immutable]\n        public sealed class IdComparer : IEqualityComparer<ParticipantId>\n        {\n            public bool Equals(ParticipantId x, ParticipantId y)\n            {\n                return string.CompareOrdinal(x.Name, y.Name) == 0 && Equals(x.Reference, y.Reference);\n            }\n\n            public int GetHashCode(ParticipantId obj) => HashCode.Combine(obj.Name, obj.Reference);\n        }\n    }\n\n    public static class ParticipantRoleExtensions\n    {\n        public static bool SupportsRoles(this ParticipantId participant, ParticipantId.Role role)\n        {\n            return (participant.SupportedRoles & role) != 0;\n        }\n\n        public static bool IsResource(this ParticipantId participant)\n        {\n            return participant.SupportsRoles(ParticipantId.Role.Resource);\n        }\n\n        public static bool IsManager(this ParticipantId participant)\n        {\n            return participant.SupportsRoles(ParticipantId.Role.Manager);\n        }\n\n        public static bool IsPriorityManager(this ParticipantId participant)\n        {\n            return participant.SupportsRoles(ParticipantId.Role.PriorityManager);\n        }\n\n        public static IEnumerable<KeyValuePair<ParticipantId,AccessCounter>> SelectResources(this IEnumerable<KeyValuePair<ParticipantId, AccessCounter>> participants)\n        {\n            return participants.Where(p => p.Key.IsResource());\n        }\n\n        public static IEnumerable<KeyValuePair<ParticipantId, AccessCounter>> SelectManagers(this IEnumerable<KeyValuePair<ParticipantId, AccessCounter>> participants)\n        {\n            return participants.Where(p => p.Key.IsManager());\n        }\n\n        public static IEnumerable<ParticipantId> SelectPriorityManagers(this IEnumerable<ParticipantId> participants)\n        {\n            return participants.Where(p => p.IsPriorityManager());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionAgent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\nusing System.Linq;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    internal partial class TransactionAgent : ITransactionAgent\n    {\n        private readonly ILogger logger;\n        private readonly Stopwatch stopwatch = Stopwatch.StartNew();\n        private readonly CausalClock clock;\n        private readonly ITransactionAgentStatistics statistics;\n        private readonly ITransactionOverloadDetector overloadDetector;\n\n        public TransactionAgent(IClock clock, ILogger<TransactionAgent> logger, ITransactionAgentStatistics statistics, ITransactionOverloadDetector overloadDetector)\n        {\n            this.clock = new CausalClock(clock);\n            this.logger = logger;\n            this.statistics = statistics;\n            this.overloadDetector = overloadDetector;\n        }\n\n        public Task<TransactionInfo> StartTransaction(bool readOnly, TimeSpan timeout)\n        {\n            if (overloadDetector.IsOverloaded())\n            {\n                this.statistics.TrackTransactionThrottled();\n                throw new OrleansStartTransactionFailedException(new OrleansTransactionOverloadException());\n            }\n\n            var guid = Guid.NewGuid();\n            DateTime ts = this.clock.UtcNow();\n\n            LogTraceStartTransaction(new(stopwatch), guid, new(ts));\n            this.statistics.TrackTransactionStarted();\n            return Task.FromResult<TransactionInfo>(new TransactionInfo(guid, ts, ts, readOnly));\n        }\n\n        public async Task<(TransactionalStatus, Exception)> Resolve(TransactionInfo transactionInfo)\n        {\n            transactionInfo.TimeStamp = this.clock.MergeUtcNow(transactionInfo.TimeStamp);\n\n            LogTracePrepareTransaction(new(stopwatch), transactionInfo);\n            if (transactionInfo.Participants.Count == 0)\n            {\n                this.statistics.TrackTransactionSucceeded();\n                return (TransactionalStatus.Ok, null);\n            }\n\n            KeyValuePair<ParticipantId, AccessCounter>? manager;\n\n            List<ParticipantId> writeParticipants;\n            List<KeyValuePair<ParticipantId, AccessCounter>> resources;\n            CollateParticipants(transactionInfo.Participants, out writeParticipants, out resources, out manager);\n            try\n            {\n                var (status, exception) = (writeParticipants == null)\n                    ? await CommitReadOnlyTransaction(transactionInfo, resources)\n                    : await CommitReadWriteTransaction(transactionInfo, writeParticipants, resources, manager.Value);\n                if (status == TransactionalStatus.Ok)\n                    this.statistics.TrackTransactionSucceeded();\n                else\n                    this.statistics.TrackTransactionFailed();\n                return (status, exception);\n            }\n            catch (Exception)\n            {\n                this.statistics.TrackTransactionFailed();\n                throw;\n            }\n        }\n\n        private async Task<(TransactionalStatus, Exception)> CommitReadOnlyTransaction(TransactionInfo transactionInfo, List<KeyValuePair<ParticipantId, AccessCounter>> resources)\n        {\n            TransactionalStatus status = TransactionalStatus.Ok;\n            Exception exception;\n\n            var tasks = new List<Task<TransactionalStatus>>();\n            try\n            {\n                foreach (KeyValuePair<ParticipantId, AccessCounter> resource in resources)\n                {\n                    tasks.Add(resource.Key.Reference.AsReference<ITransactionalResourceExtension>()\n                                   .CommitReadOnly(resource.Key.Name, transactionInfo.TransactionId, resource.Value, transactionInfo.TimeStamp));\n                }\n\n                // wait for all responses\n                TransactionalStatus[] results = await Task.WhenAll(tasks);\n\n                // examine the return status\n                foreach (var s in results)\n                {\n                    if (s != TransactionalStatus.Ok)\n                    {\n                        status = s;\n                        LogDebugPrepareTransactionFailure(new(stopwatch), transactionInfo.TransactionId, status);\n                        break;\n                    }\n                }\n\n                exception = null;\n            }\n            catch (TimeoutException ex)\n            {\n                LogDebugCommitReadOnlyTimeout(new(stopwatch), transactionInfo.TransactionId);\n                status = TransactionalStatus.ParticipantResponseTimeout;\n                exception = ex;\n            }\n            catch (Exception ex)\n            {\n                LogDebugCommitReadOnlyFailure(new(stopwatch), transactionInfo.TransactionId);\n                LogWarnCommitReadOnlyFailure(transactionInfo.TransactionId, ex);\n                status = TransactionalStatus.PresumedAbort;\n                exception = ex;\n            }\n\n            if (status != TransactionalStatus.Ok)\n            {\n                try\n                {\n                    await Task.WhenAll(resources.Select(r => r.Key.Reference.AsReference<ITransactionalResourceExtension>()\n                                .Abort(r.Key.Name, transactionInfo.TransactionId)));\n                }\n                catch (Exception ex)\n                {\n                    LogDebugCommitReadOnlyFailureAborting(new(stopwatch), transactionInfo.TransactionId, ex);\n                    LogWarnFailAbortReadonlyTransaction(transactionInfo.TransactionId, ex);\n                }\n            }\n\n            LogTraceFinishReadOnlyTransaction(new(stopwatch), transactionInfo.TransactionId);\n            return (status, exception);\n        }\n\n        private async Task<(TransactionalStatus, Exception)> CommitReadWriteTransaction(TransactionInfo transactionInfo, List<ParticipantId> writeResources, List<KeyValuePair<ParticipantId, AccessCounter>> resources, KeyValuePair<ParticipantId, AccessCounter> manager)\n        {\n            TransactionalStatus status = TransactionalStatus.Ok;\n            Exception exception;\n\n            try\n            {\n                foreach (var p in resources)\n                {\n                    if (p.Key.Equals(manager.Key))\n                        continue;\n                    // one-way prepare message\n                    p.Key.Reference.AsReference<ITransactionalResourceExtension>()\n                            .Prepare(p.Key.Name, transactionInfo.TransactionId, p.Value, transactionInfo.TimeStamp, manager.Key)\n                            .Ignore();\n                }\n\n                // wait for the TM to commit the transaction\n                status = await manager.Key.Reference.AsReference<ITransactionManagerExtension>()\n                    .PrepareAndCommit(manager.Key.Name, transactionInfo.TransactionId, manager.Value, transactionInfo.TimeStamp, writeResources, resources.Count);\n                exception = null;\n            }\n            catch (TimeoutException ex)\n            {\n                LogDebugCommitReadWriteTimeout(new(stopwatch), transactionInfo.TransactionId);\n                status = TransactionalStatus.TMResponseTimeout;\n                exception = ex;\n            }\n            catch (Exception ex)\n            {\n                LogDebugCommitReadWriteFailure(new(stopwatch), transactionInfo.TransactionId);\n                LogWarnCommitTransactionFailure(transactionInfo.TransactionId, ex);\n                status = TransactionalStatus.PresumedAbort;\n                exception = ex;\n            }\n\n            if (status != TransactionalStatus.Ok)\n            {\n                try\n                {\n                    LogDebugCommitTransactionFailure(new(stopwatch), transactionInfo.TransactionId, status);\n\n                    // notify participants\n                    if (status.DefinitelyAborted())\n                    {\n                        await Task.WhenAll(writeResources\n                            .Where(p => !p.Equals(manager.Key))\n                            .Select(p => p.Reference.AsReference<ITransactionalResourceExtension>()\n                                    .Cancel(p.Name, transactionInfo.TransactionId, transactionInfo.TimeStamp, status)));\n                    }\n                }\n                catch (Exception ex)\n                {\n                    LogDebugCommitReadWriteFailureAborting(new(stopwatch), transactionInfo.TransactionId, ex);\n                    LogWarnFailAbortTransaction(transactionInfo.TransactionId, ex);\n                }\n            }\n\n            LogTraceFinishTransaction(new(stopwatch), transactionInfo.TransactionId);\n            return (status, exception);\n        }\n\n        public async Task Abort(TransactionInfo transactionInfo)\n        {\n            this.statistics.TrackTransactionFailed();\n\n            List<ParticipantId> participants = transactionInfo.Participants.Keys.ToList();\n            LogTraceAbortTransaction(transactionInfo, new(participants));\n\n            // send one-way abort messages to release the locks and roll back any updates\n            await Task.WhenAll(participants.Select(p => p.Reference.AsReference<ITransactionalResourceExtension>()\n                 .Abort(p.Name, transactionInfo.TransactionId)));\n        }\n\n        private void CollateParticipants(Dictionary<ParticipantId, AccessCounter> participants, out List<ParticipantId> writers, out List<KeyValuePair<ParticipantId, AccessCounter>> resources, out KeyValuePair<ParticipantId, AccessCounter>? manager)\n        {\n            writers = null;\n            resources = null;\n            manager = null;\n            KeyValuePair<ParticipantId, AccessCounter>? priorityManager = null;\n            foreach (KeyValuePair<ParticipantId, AccessCounter> participant in participants)\n            {\n                ParticipantId id = participant.Key;\n                // priority manager\n                if (id.IsPriorityManager())\n                {\n                    manager = priorityManager = (priorityManager == null)\n                        ? participant\n                        : throw new ArgumentOutOfRangeException(nameof(participants), \"Only one priority transaction manager allowed in transaction\");\n                }\n                // resource\n                if(id.IsResource())\n                {\n                    if(resources == null)\n                    {\n                        resources = new List<KeyValuePair<ParticipantId, AccessCounter>>();\n                    }\n                    resources.Add(participant);\n                    if(participant.Value.Writes > 0)\n                    {\n                        if (writers == null)\n                        {\n                            writers = new List<ParticipantId>();\n                        }\n                        writers.Add(id);\n                    }\n                }\n                // manager\n                if (manager == null && id.IsManager() && participant.Value.Writes > 0)\n                {\n                    manager = participant;\n                }\n            }\n        }\n\n        private readonly struct StopwatchLogRecord(Stopwatch stopwatch)\n        {\n            public override string ToString() => stopwatch.Elapsed.TotalMilliseconds.ToString(\"f2\");\n        }\n\n        private readonly struct DateTimeLogRecord(DateTime ts)\n        {\n            public override string ToString() => ts.ToString(\"o\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TotalMilliseconds} start transaction {TransactionId} at {TimeStamp}\"\n        )]\n        private partial void LogTraceStartTransaction(StopwatchLogRecord totalMilliseconds, Guid transactionId, DateTimeLogRecord timeStamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{ElapsedMilliseconds} prepare {TransactionInfo}\"\n        )]\n        private partial void LogTracePrepareTransaction(StopwatchLogRecord elapsedMilliseconds, TransactionInfo transactionInfo);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} fail {TransactionId} prepare response status={Status}\"\n        )]\n        private partial void LogDebugPrepareTransactionFailure(StopwatchLogRecord totalMilliseconds, Guid transactionId, TransactionalStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} timeout {TransactionId} on CommitReadOnly\"\n        )]\n        private partial void LogDebugCommitReadOnlyTimeout(StopwatchLogRecord totalMilliseconds, Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} failure {TransactionId} CommitReadOnly\"\n        )]\n        private partial void LogDebugCommitReadOnlyFailure(StopwatchLogRecord totalMilliseconds, Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Unknown error while commiting readonly transaction {TransactionId}\"\n        )]\n        private partial void LogWarnCommitReadOnlyFailure(Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} failure aborting {TransactionId} CommitReadOnly\"\n        )]\n        private partial void LogDebugCommitReadOnlyFailureAborting(StopwatchLogRecord totalMilliseconds, Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to abort readonly transaction {TransactionId}\"\n        )]\n        private partial void LogWarnFailAbortReadonlyTransaction(Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{ElapsedMilliseconds} finish (reads only) {TransactionId}\"\n        )]\n        private partial void LogTraceFinishReadOnlyTransaction(StopwatchLogRecord elapsedMilliseconds, Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} timeout {TransactionId} on CommitReadWriteTransaction\"\n        )]\n        private partial void LogDebugCommitReadWriteTimeout(StopwatchLogRecord totalMilliseconds, Guid transactionId);\n\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} failure {TransactionId} CommitReadWriteTransaction\"\n        )]\n        private partial void LogDebugCommitReadWriteFailure(StopwatchLogRecord totalMilliseconds, Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Unknown error while committing transaction {TransactionId}\"\n        )]\n        private partial void LogWarnCommitTransactionFailure(Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} failed {TransactionId} with status={Status}\"\n        )]\n        private partial void LogDebugCommitTransactionFailure(StopwatchLogRecord totalMilliseconds, Guid transactionId, TransactionalStatus status);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"{TotalMilliseconds} failure aborting {TransactionId} CommitReadWriteTransaction\"\n        )]\n        private partial void LogDebugCommitReadWriteFailureAborting(StopwatchLogRecord totalMilliseconds, Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to abort transaction {TransactionId}\"\n        )]\n        private partial void LogWarnFailAbortTransaction(Guid transactionId, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{TotalMilliseconds} finish {TransactionId}\"\n        )]\n        private partial void LogTraceFinishTransaction(StopwatchLogRecord totalMilliseconds, Guid transactionId);\n\n        private readonly struct ParticipantsLogRecord(List<ParticipantId> participants)\n        {\n            public override string ToString() => string.Join(\",\", participants.Select(p => p.ToString()));\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Abort {TransactionInfo} {Participants}\"\n        )]\n        private partial void LogTraceAbortTransaction(TransactionInfo transactionInfo, ParticipantsLogRecord participants);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionAgentStatistics.cs",
    "content": "using System.Diagnostics.Metrics;\nusing System.Threading;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionAgentStatistics : ITransactionAgentStatistics\n    {\n        private static readonly Meter Meter = new(\"Orleans\");\n\n        private const string TRANSACTIONS_STARTED = \"orleans-transactions-started\";\n        private const string TRANSACTIONS_SUCCESSFUL = \"orleans-transactions-successful\";\n        private const string TRANSACTIONS_FAILED = \"orleans-transactions-failed\";\n        private const string TRANSACTIONS_THROTTLED = \"orleans-transactions-throttled\";\n        private readonly ObservableCounter<long> _transactionsStartedCounter;\n        private readonly ObservableCounter<long> _transactionsSuccessfulCounter;\n        private readonly ObservableCounter<long> _transactionsFailedCounter;\n        private readonly ObservableCounter<long> _transactionsThrottledCounter;\n\n        private long _transactionsStarted;\n        private long _transactionsSucceeded;\n        private long _transactionsFailed;\n        private long _transactionsThrottled;\n\n        public TransactionAgentStatistics()\n        {\n            _transactionsStartedCounter = Meter.CreateObservableCounter<long>(TRANSACTIONS_STARTED, () => new(TransactionsStarted));\n            _transactionsSuccessfulCounter = Meter.CreateObservableCounter<long>(TRANSACTIONS_SUCCESSFUL, () => new(TransactionsSucceeded));\n            _transactionsFailedCounter = Meter.CreateObservableCounter<long>(TRANSACTIONS_FAILED, () => new(TransactionsFailed));\n            _transactionsThrottledCounter = Meter.CreateObservableCounter<long>(TRANSACTIONS_THROTTLED, () => new(TransactionsThrottled));\n        }\n\n        public long TransactionsStarted => _transactionsStarted;\n        public long TransactionsSucceeded => _transactionsSucceeded;\n        public long TransactionsFailed => _transactionsFailed;\n        public long TransactionsThrottled => _transactionsThrottled;\n\n        public void TrackTransactionStarted()\n        {\n            Interlocked.Increment(ref _transactionsStarted);\n        }\n\n        public void TrackTransactionSucceeded()\n        {\n            Interlocked.Increment(ref _transactionsSucceeded);\n        }\n\n        public void TrackTransactionFailed()\n        {\n            Interlocked.Increment(ref _transactionsFailed);\n        }\n\n        public void TrackTransactionThrottled()\n        {\n            Interlocked.Increment(ref _transactionsThrottled);\n        }\n\n        public static ITransactionAgentStatistics Copy(ITransactionAgentStatistics initialStatistics)\n        {\n            return new TransactionAgentStatistics\n            {\n                _transactionsStarted = initialStatistics.TransactionsStarted,\n                _transactionsSucceeded = initialStatistics.TransactionsSucceeded,\n                _transactionsFailed = initialStatistics.TransactionsFailed,\n                _transactionsThrottled = initialStatistics.TransactionsThrottled\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionClient.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.ExceptionServices;\nusing System.Threading.Tasks;\n\nusing Orleans.Serialization;\n\nnamespace Orleans.Transactions;\n\ninternal class TransactionClient : ITransactionClient\n{\n    private readonly ITransactionAgent _transactionAgent;\n    private readonly Serializer<OrleansTransactionAbortedException> _serializer;\n\n    public TransactionClient(ITransactionAgent transactionAgent, Serializer<OrleansTransactionAbortedException> serializer)\n    {\n        _transactionAgent = transactionAgent;\n        _serializer = serializer;\n    }\n\n    public async Task RunTransaction(TransactionOption transactionOption, Func<Task> transactionDelegate)\n    {\n        if (transactionDelegate is null)\n        {\n            throw new ArgumentNullException(nameof(transactionDelegate));\n        }\n\n        await RunTransaction(transactionOption, async () =>\n        {\n            await transactionDelegate();\n            return true;\n        });\n    }\n\n    public async Task RunTransaction(TransactionOption transactionOption, Func<Task<bool>> transactionDelegate)\n    {\n        if (transactionDelegate is null)\n        {\n            throw new ArgumentNullException(nameof(transactionDelegate));\n        }\n\n        // Pick up ambient transaction context\n        var ambientTransactionInfo = TransactionContext.GetTransactionInfo();\n\n        if (ambientTransactionInfo is not null && transactionOption == TransactionOption.Suppress)\n        {\n            throw new NotSupportedException(\"Delegate cannot be executed within a transaction.\");\n        }\n\n        if (ambientTransactionInfo is null && transactionOption == TransactionOption.Join)\n        {\n            throw new NotSupportedException(\"Delegate cannot be executed outside of a transaction.\");\n        }\n\n        try\n        {\n            switch (transactionOption)\n            {\n                case TransactionOption.Create:\n                    await RunDelegateWithTransaction(null, transactionDelegate);\n                    break;\n                case TransactionOption.Join:\n                    await RunDelegateWithTransaction(ambientTransactionInfo, transactionDelegate);\n                    break;\n                case TransactionOption.CreateOrJoin:\n                    await RunDelegateWithTransaction(ambientTransactionInfo, transactionDelegate);\n                    break;\n                case TransactionOption.Suppress:\n                    await RunDelegateWithSupressedTransaction(ambientTransactionInfo, transactionDelegate);\n                    break;\n                case TransactionOption.Supported:\n                    await RunDelegateWithSupportedTransaction(ambientTransactionInfo, transactionDelegate);\n                    break;\n                case TransactionOption.NotAllowed:\n                    await RunDelegateWithDisallowedTransaction(ambientTransactionInfo, transactionDelegate);\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(transactionOption), $\"{transactionOption} is not supported\");\n            }\n        }\n        finally\n        {\n            // Restore ambient transaction context, if any\n            TransactionContext.SetTransactionInfo(ambientTransactionInfo);\n        }\n    }\n\n    private static async Task RunDelegateWithDisallowedTransaction(TransactionInfo ambientTransactionInfo, Func<Task<bool>> transactionDelegate)\n    {\n        if (ambientTransactionInfo is not null)\n        {\n            // No transaction is allowed within delegate\n            throw new NotSupportedException(\"Delegate cannot be executed within a transaction.\");\n        }\n\n        // Run delegate\n        _ = await transactionDelegate();\n    }\n\n    private static async Task RunDelegateWithSupportedTransaction(TransactionInfo ambientTransactionInfo, Func<Task<bool>> transactionDelegate)\n    {\n        if (ambientTransactionInfo is null)\n        {\n            // Run delegate\n            _ = await transactionDelegate();\n        }\n        else\n        {\n            // Run delegate\n            ambientTransactionInfo.TryToCommit = await transactionDelegate();\n        }\n    }\n\n    private static async Task RunDelegateWithSupressedTransaction(TransactionInfo ambientTransactionInfo, Func<Task<bool>> transactionDelegate)\n    {\n        // Clear transaction context\n        TransactionContext.Clear();\n\n        if (ambientTransactionInfo is null)\n        {\n            // Run delegate\n            _ = await transactionDelegate();\n        }\n        else\n        {\n            // Run delegate\n            ambientTransactionInfo.TryToCommit = await transactionDelegate();\n        }\n    }\n\n    private async Task RunDelegateWithTransaction(TransactionInfo ambientTransactionInfo, Func<Task<bool>> transactionDelegate)\n    {\n        TransactionInfo transactionInfo;\n\n        if (ambientTransactionInfo is null)\n        {\n            // TODO: this should be a configurable parameter\n            var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10);\n\n            // Start transaction\n            transactionInfo = await _transactionAgent.StartTransaction(readOnly: false, transactionTimeout);\n        }\n        else\n        {\n            // Fork ambient transaction\n            transactionInfo = ambientTransactionInfo.Fork();\n        }\n\n        // Set transaction context\n        TransactionContext.SetTransactionInfo(transactionInfo);\n\n        try\n        {\n            // Run delegate\n            transactionInfo.TryToCommit = await transactionDelegate();\n        }\n        catch (Exception exception)\n        {\n            // Record exception with transaction\n            transactionInfo.RecordException(exception, _serializer);\n        }\n\n        // Gather pending actions into transaction\n        transactionInfo.ReconcilePending();\n\n        if (ambientTransactionInfo is null)\n        {\n            // Finalize transaction since there is no ambient transaction to join\n            await FinalizeTransaction(transactionInfo);\n        }\n        else\n        {   // Join transaction with ambient transaction\n            ambientTransactionInfo.Join(transactionInfo);\n        }\n    }\n\n    private async Task FinalizeTransaction(TransactionInfo transactionInfo)\n    {\n        // Prepare for exception, if any\n        OrleansTransactionException transactionException;\n\n        // Check if transaction is pending for abort\n        transactionException = transactionInfo.MustAbort(_serializer);\n\n        if (transactionException is not null || transactionInfo.TryToCommit is false)\n        {\n            // Transaction is pending for abort\n            await _transactionAgent.Abort(transactionInfo);\n        }\n        else\n        {\n            // Try to resolve transaction\n            var (status, exception) = await _transactionAgent.Resolve(transactionInfo);\n\n            if (status != TransactionalStatus.Ok)\n            {\n                // Resolving transaction failed\n                transactionException = status.ConvertToUserException(transactionInfo.Id, exception);\n                ExceptionDispatchInfo.SetCurrentStackTrace(transactionException);\n            }\n        }\n\n        if (transactionException != null)\n        {\n            // Transaction failed - bubble up exception\n            ExceptionDispatchInfo.Throw(transactionException);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionInfo.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Orleans.Serialization;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    [GenerateSerializer]\n    public sealed class TransactionInfo\n    {\n        public TransactionInfo()\n        {\n            this.Participants = new Dictionary<ParticipantId, AccessCounter>(ParticipantId.Comparer);\n            this.joined = new ConcurrentQueue<TransactionInfo>();\n        }\n\n        public TransactionInfo(Guid id, DateTime timeStamp, DateTime priority, bool readOnly = false) : this()\n        {\n            this.TransactionId = id;\n            this.IsReadOnly = readOnly;\n            this.TimeStamp = timeStamp;\n            this.Priority = priority;\n        }\n\n        /// <summary>\n        /// Constructor used when TransactionInfo is transferred to a request\n        /// </summary>\n        /// <param name=\"other\"></param>\n        public TransactionInfo(TransactionInfo other) : this()\n        {\n            this.TransactionId = other.TransactionId;\n            this.TryToCommit = other.TryToCommit;\n            this.IsReadOnly = other.IsReadOnly;\n            this.TimeStamp = other.TimeStamp;\n            this.Priority = other.Priority;\n        }\n\n        public string Id => TransactionId.ToString();\n\n        [Id(0)]\n        public Guid TransactionId { get; }\n\n        [Id(1)]\n        public DateTime TimeStamp { get; set; }\n\n        [Id(2)]\n        public DateTime Priority { get; set; }\n\n        [Id(3)]\n        public bool IsReadOnly { get; }\n\n        [Id(4)]\n        public byte[] OriginalException { get; set; }\n\n        // counts how many writes were done per each accessed resource\n        // zero means the resource was only read\n        [Id(5)]\n        public Dictionary<ParticipantId, AccessCounter> Participants { get; }\n\n        [Id(6)]\n        public bool TryToCommit { get; internal set; } = true;\n\n        [NonSerialized]\n        public int PendingCalls;\n\n        [NonSerialized]\n        private readonly ConcurrentQueue<TransactionInfo> joined;\n\n        public TransactionInfo Fork()\n        {\n            Interlocked.Increment(ref PendingCalls);\n            return new TransactionInfo(this);\n        }\n\n        public void Join(TransactionInfo x)\n        {\n            joined.Enqueue(x);\n        }\n\n        public OrleansTransactionAbortedException MustAbort(Serializer<OrleansTransactionAbortedException> serializer)\n        {\n            if (OriginalException != null)\n            {\n                return serializer.Deserialize(OriginalException);\n            }\n            else if (PendingCalls != 0)\n            {\n                return new OrleansOrphanCallException(TransactionId.ToString(), PendingCalls);\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        public void RecordException(Exception e, Serializer<OrleansTransactionAbortedException> sm)\n        {\n            if (OriginalException == null)\n            {\n                var exception = (e as OrleansTransactionAbortedException)\n                    ?? new OrleansTransactionAbortedException(TransactionId.ToString(), e);\n\n                OriginalException = sm.SerializeToArray(exception);\n            }\n        }\n\n        /// <summary>\n        /// Reconciles all pending calls that have join the transaction.\n        /// </summary>\n        /// <returns>true if there are no orphans, false otherwise</returns>\n        public void ReconcilePending()\n        {\n            TransactionInfo transactionInfo;\n            while (this.joined.TryDequeue(out transactionInfo))\n            {\n                Union(transactionInfo);\n                PendingCalls--;\n            }\n        }\n\n        private void Union(TransactionInfo other)\n        {\n            if (OriginalException == null)\n            {\n                OriginalException = other.OriginalException;\n            }\n\n            // Take sum of write counts\n            foreach (KeyValuePair<ParticipantId, AccessCounter> participant in other.Participants)\n            {\n                if (!this.Participants.TryGetValue(participant.Key, out var existing))\n                {\n                    this.Participants[participant.Key] = participant.Value;\n                }\n                else\n                {\n                    this.Participants[participant.Key] = existing + participant.Value;\n                }\n            }\n\n            // take max of timestamp\n            if (TimeStamp < other.TimeStamp)\n                TimeStamp = other.TimeStamp;\n\n            // take commit pending flag\n            if (TryToCommit)\n                TryToCommit = other.TryToCommit;\n        }\n\n        public void RecordRead(ParticipantId id, DateTime minTime)\n        {\n            this.Participants.TryGetValue(id, out AccessCounter count);\n\n            count.Reads++;\n\n            this.Participants[id] = count;\n\n            if (minTime > TimeStamp)\n            {\n                TimeStamp = minTime;\n            }\n        }\n\n        public void RecordWrite(ParticipantId id, DateTime minTime)\n        {\n            this.Participants.TryGetValue(id, out AccessCounter count);\n\n            count.Writes++;\n\n            this.Participants[id] = count;\n\n            if (minTime > TimeStamp)\n            {\n                TimeStamp = minTime;\n            }\n        }\n\n        /// <summary>\n        /// For verbose tracing and debugging.\n        /// </summary>\n        public override string ToString()\n        {\n            return string.Join(\"\",\n                $\"{TransactionId} {TimeStamp:o}\",\n                (IsReadOnly ? \" RO\" : \"\"),\n                (TryToCommit ? \" Committing\" : \"\"),\n                (OriginalException != null ? \" Aborting\" : \"\"),\n                $\" {{{string.Join(\" \", this.Participants.Select(kvp => $\"{kvp.Key}:{kvp.Value.Reads},{kvp.Value.Writes}\"))}}}\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionManagerExtension.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionManagerExtension : ITransactionManagerExtension\n    {\n        private readonly ResourceFactoryRegistry<ITransactionManager> factories;\n        private readonly Dictionary<string, ITransactionManager> managers;\n\n        public TransactionManagerExtension(IGrainContextAccessor contextAccessor)\n        {\n            this.factories = contextAccessor.GrainContext.GetResourceFactoryRegistry<ITransactionManager>();\n            this.managers = new Dictionary<string, ITransactionManager>();\n        }\n\n        public Task Ping(string resourceId, Guid transactionId, DateTime timeStamp, ParticipantId resource)\n        {\n            return GetManager(resourceId).Ping(transactionId, timeStamp, resource);\n        }\n\n        public Task<TransactionalStatus> PrepareAndCommit(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp, List<ParticipantId> writeResources, int totalResources)\n        {\n            return GetManager(resourceId).PrepareAndCommit(transactionId, accessCount, timeStamp, writeResources, totalResources);\n        }\n\n        public Task Prepared(string resourceId, Guid transactionId, DateTime timestamp, ParticipantId resource, TransactionalStatus status)\n        {\n            return GetManager(resourceId).Prepared(transactionId, timestamp, resource, status);\n        }\n\n        private ITransactionManager GetManager(string resourceId)\n        {\n            if (!this.managers.TryGetValue(resourceId, out ITransactionManager manager))\n            {\n                this.managers[resourceId] = manager = this.factories[resourceId].Invoke();\n            }\n            return manager;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionOverloadDetector.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Internal.Trasactions;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public interface ITransactionOverloadDetector\n    {\n        bool IsOverloaded();\n    }\n\n    /// <summary>\n    /// Options for load shedding based on transaction rate \n    /// </summary>\n    public class TransactionRateLoadSheddingOptions\n    {\n        /// <summary>\n        /// whether to turn on transaction load shedding. Default to false;\n        /// </summary>\n        public bool Enabled { get; set; }\n\n        /// <summary>\n        /// Default load shedding limit\n        /// </summary>\n        public const double DEFAULT_LIMIT = 700;\n        /// <summary>\n        /// Load shedding limit for transaction\n        /// </summary>\n        public double Limit { get; set; } = DEFAULT_LIMIT;\n    }\n\n    public class TransactionOverloadDetector : ITransactionOverloadDetector\n    {\n        private readonly ITransactionAgentStatistics statistics;\n        private readonly TransactionRateLoadSheddingOptions options;\n        private readonly PeriodicAction monitor;\n        private ITransactionAgentStatistics lastStatistics;\n        private double transactionStartedPerSecond;\n        private DateTime lastCheckTime;\n        private static readonly TimeSpan MetricsCheck = TimeSpan.FromSeconds(15);\n        public TransactionOverloadDetector(ITransactionAgentStatistics statistics, IOptions<TransactionRateLoadSheddingOptions> options)\n        {\n            this.statistics = statistics;\n            this.options = options.Value;\n            this.monitor = new PeriodicAction(MetricsCheck, this.RecordStatistics);\n            this.lastStatistics = TransactionAgentStatistics.Copy(statistics);\n            this.lastCheckTime = DateTime.UtcNow;\n        }\n\n        private void RecordStatistics()\n        {\n            ITransactionAgentStatistics current = TransactionAgentStatistics.Copy(this.statistics);\n            DateTime now = DateTime.UtcNow;\n\n            this.transactionStartedPerSecond = CalculateTps(this.lastStatistics.TransactionsStarted, this.lastCheckTime, current.TransactionsStarted, now);\n            this.lastStatistics = current;\n            this.lastCheckTime = now;\n        }\n\n        public bool IsOverloaded()\n        {\n            if (!this.options.Enabled)\n                return false;\n\n            DateTime now = DateTime.UtcNow;\n            this.monitor.TryAction(now);\n            double txPerSecondCurrently = CalculateTps(this.lastStatistics.TransactionsStarted, this.lastCheckTime, this.statistics.TransactionsStarted, now);\n            //decaying utilization for tx per second\n            var aggregratedTxPerSecond = (this.transactionStartedPerSecond + (2.0 * txPerSecondCurrently)) / 3.0;\n            \n            return aggregratedTxPerSecond > this.options.Limit;\n        }\n\n        private static double CalculateTps(long startCounter, DateTime startTimeUtc, long currentCounter, DateTime curentTimeUtc)\n        {\n            TimeSpan deltaTime = curentTimeUtc - startTimeUtc;\n            long deltaCounter = currentCounter - startCounter;\n            return (deltaTime.TotalMilliseconds < 1000)\n                ? deltaCounter\n                : (deltaCounter * 1000.0) / deltaTime.TotalMilliseconds;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionRecord.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// Each participant plays a particular role in the commit protocol\n    /// </summary>\n    internal enum CommitRole\n    {\n        NotYetDetermined,  // role is known only when prepare message is received from TA\n        ReadOnly,          // this participant has not written\n        RemoteCommit,      // this participant has written, but is not the TM\n        LocalCommit,       // this participant has written, and is the TM\n    }\n\n    /// <summary>\n    /// Record that is kept for each transaction at each participant\n    /// </summary>\n    /// <typeparam name=\"TState\">The type of state</typeparam>\n    internal class TransactionRecord<TState>\n    {\n        public TransactionRecord()\n        {\n        }\n\n        // a unique identifier for this transaction\n        public Guid TransactionId;\n\n        // the time at which this transaction was started on the TA\n        public DateTime Priority;\n\n        // a deadline for the transaction to complete successfully, set by the TA\n        public DateTime Deadline;\n\n        // the transaction timestamp as computed by the algorithm\n        public DateTime Timestamp;\n\n        // the number of reads and writes that this transaction has performed on this transactional participant\n        public int NumberReads;\n        public int NumberWrites;\n\n        // the state for this transaction, and the sequence number of this state\n        public TState State;\n        public long SequenceNumber;\n        public bool HasCopiedState;\n\n        public void AddRead()\n        {\n            NumberReads++;\n        }\n        public void AddWrite()\n        {\n            NumberWrites++;\n        }\n\n        public CommitRole Role;\n\n        // used for readonly and local commit\n        public TaskCompletionSource<TransactionalStatus> PromiseForTA;\n\n        // used for local and remote commit\n        public ParticipantId TransactionManager;\n\n        // used for local commit\n        public List<ParticipantId> WriteParticipants;\n        public int WaitCount;\n        public DateTime WaitingSince;\n\n        // used for remote commit\n        public DateTime? LastSent;\n        public bool PrepareIsPersisted;\n        public TaskCompletionSource<bool> ConfirmationResponsePromise;\n\n\n        /// <summary>\n        /// Indicates whether a transaction record is ready to commit\n        /// </summary>\n        public bool ReadyToCommit\n        {\n            get\n            {\n                switch (Role)\n                {\n                    case CommitRole.ReadOnly:\n                        return true;\n\n                    case CommitRole.LocalCommit:\n                        return WaitCount == 0; // received all \"Prepared\" messages\n\n                    case CommitRole.RemoteCommit:\n                        return\n                            (ConfirmationResponsePromise != null)  // TM has sent confirm and is waiting for response\n                         || (NumberWrites == 0 && LastSent.HasValue);  // this participant did not write and finished prepare\n\n                    default:\n                        throw new NotSupportedException($\"{Role} is not a supported CommitRole.\");\n                }\n            }\n        }\n\n        public bool IsReadOnly\n        {\n            get\n            {\n                switch (Role)\n                {\n                    case CommitRole.ReadOnly:\n                        return true;\n                    case CommitRole.LocalCommit:\n                        return false;\n                    case CommitRole.RemoteCommit:\n                        return NumberWrites == 0;\n                    default:\n                        throw new NotSupportedException($\"{Role} is not a supported CommitRole.\");\n                }\n            }\n        }\n\n        public bool Batchable\n        {\n            get\n            {\n                switch (Role)\n                {\n                    case CommitRole.ReadOnly:\n                    case CommitRole.LocalCommit:\n                        return true;\n                    case CommitRole.RemoteCommit:\n                        return NumberWrites == 0;\n                    default:\n                        throw new NotImplementedException();\n                }\n            }\n        }\n\n        // formatted for debugging commit queue contents\n        public override string ToString()\n        {\n            switch (Role)\n            {\n                case CommitRole.NotYetDetermined:\n                    return $\"ND tid={TransactionId} v{SequenceNumber}\";\n\n                case CommitRole.ReadOnly:\n                    return $\"RE tid={TransactionId} v{SequenceNumber}\";\n\n                case CommitRole.LocalCommit:\n                    return $\"LCE tid={TransactionId} v{SequenceNumber} wc={WaitCount} rtb={ReadyToCommit}\";\n\n                case CommitRole.RemoteCommit:\n                    return $\"RCE tid={TransactionId} v{SequenceNumber} pip={PrepareIsPersisted} ls={LastSent.HasValue} ro={IsReadOnly} rtb={ReadyToCommit} tm={TransactionManager}\";\n\n                default:\n                    throw new NotSupportedException($\"{Role} is not a supported CommitRole.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Transactions/DistributedTM/TransactionalResourceExtension.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionalResourceExtension : ITransactionalResourceExtension\n    {\n        private readonly ResourceFactoryRegistry<ITransactionalResource> factories;\n        private readonly Dictionary<string, ITransactionalResource> resources;\n\n        public TransactionalResourceExtension(IGrainContextAccessor contextAccessor)\n        {\n            this.factories = contextAccessor.GrainContext.GetResourceFactoryRegistry<ITransactionalResource>();\n            this.resources = new Dictionary<string, ITransactionalResource>();\n        }\n\n        public Task<TransactionalStatus> CommitReadOnly(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp)\n        {\n            return GetResource(resourceId).CommitReadOnly(transactionId, accessCount, timeStamp);\n        }\n\n        public Task Abort(string resourceId, Guid transactionId)\n        {\n            return GetResource(resourceId).Abort(transactionId);\n        }\n\n        public Task Cancel(string resourceId, Guid transactionId, DateTime timeStamp, TransactionalStatus status)\n        {\n            return GetResource(resourceId).Cancel(transactionId, timeStamp, status);\n        }\n\n        public Task Confirm(string resourceId, Guid transactionId, DateTime timeStamp)\n        {\n            return GetResource(resourceId).Confirm(transactionId, timeStamp);\n        }\n\n        public Task Prepare(string resourceId, Guid transactionId, AccessCounter accessCount, DateTime timeStamp, ParticipantId transactionManager)\n        {\n            return GetResource(resourceId).Prepare(transactionId, accessCount, timeStamp, transactionManager);\n        }\n\n        private ITransactionalResource GetResource(string resourceId)\n        {\n            if (!this.resources.TryGetValue(resourceId, out ITransactionalResource resource))\n            {\n                this.resources[resourceId] = resource = this.factories[resourceId].Invoke();\n            }\n            return resource;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/ErrorCodes.cs",
    "content": "﻿\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// Orleans Transactions error codes\n    /// </summary>\n    internal enum OrleansTransactionsErrorCode\n    {\n        /// <summary>\n        /// Start of orleans transactions error codes\n        /// </summary>\n        OrleansTransactions = 1 << 17,\n        // TODO - jbragg - add error codes for transaction errors\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/ClientBuilderExtensions.cs",
    "content": "namespace Orleans.Hosting\n{\n    public static class ClientBuilderExtensions\n    {\n        public static IClientBuilder UseTransactions(this IClientBuilder builder)\n            => builder.ConfigureServices(services => services.UseTransactionsWithClient());\n    }\n}"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/DefaultTransactionDataCopier.cs",
    "content": "using Orleans.Serialization;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class DefaultTransactionDataCopier<TData> : ITransactionDataCopier<TData>\n    {\n        private readonly DeepCopier<TData> deepCopier;\n\n        public DefaultTransactionDataCopier(DeepCopier<TData> deepCopier)\n        {\n            this.deepCopier = deepCopier;\n        }\n\n        public TData DeepCopy(TData original)\n        {\n            return (TData)this.deepCopier.Copy(original);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/SiloBuilderExtensions.cs",
    "content": "using Orleans.Transactions;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Hosting;\n\npublic static class SiloBuilderExtensions\n{\n    /// <summary>\n    /// Configure cluster to use the distributed TM algorithm\n    /// </summary>\n    /// <param name=\"builder\">Silo host builder</param>\n    /// <returns>The silo builder.</returns>\n    public static ISiloBuilder UseTransactions(this ISiloBuilder builder)\n    {\n        return builder.ConfigureServices(services => services.UseTransactionsWithSilo())\n                      .AddGrainExtension<ITransactionManagerExtension, TransactionManagerExtension>()\n                      .AddGrainExtension<ITransactionalResourceExtension, TransactionalResourceExtension>();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/TransactionCommitterAttributeMapper.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing System.Reflection;\n\nnamespace Orleans.Transactions\n{\n    internal class TransactionCommitterAttributeMapper : IAttributeToFactoryMapper<TransactionCommitterAttribute>\n    {\n        private static readonly MethodInfo create = typeof(ITransactionCommitterFactory).GetMethod(\"Create\");\n\n        public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, TransactionCommitterAttribute attribute)\n        {\n            TransactionCommitterAttribute config = attribute;\n            // use generic type args to define collection type.\n            MethodInfo genericCreate = create.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());\n            object[] args = new object[] { config };\n            return context => Create(context, genericCreate, args);\n        }\n\n        private static object Create(IGrainContext context, MethodInfo genericCreate, object[] args)\n        {\n            ITransactionCommitterFactory factory = context.ActivationServices.GetRequiredService<ITransactionCommitterFactory>();\n            return genericCreate.Invoke(factory, args);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/TransactionalStateAttributeMapper.cs",
    "content": "using System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionalStateAttributeMapper : TransactionalStateAttributeMapper<TransactionalStateAttribute>\n    {\n        protected override TransactionalStateConfiguration AttributeToConfig(TransactionalStateAttribute attribute)\n        {\n            return new TransactionalStateConfiguration(attribute);\n        }\n    }\n\n    public abstract class TransactionalStateAttributeMapper<TAttribute> : IAttributeToFactoryMapper<TAttribute>\n        where TAttribute : IFacetMetadata, ITransactionalStateConfiguration\n    {\n        private static readonly MethodInfo create = typeof(ITransactionalStateFactory).GetMethod(\"Create\");\n\n        public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, TAttribute attribute)\n        {\n            TransactionalStateConfiguration config = AttributeToConfig(attribute);\n            // use generic type args to define collection type.\n            MethodInfo genericCreate = create.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());\n            object[] args = new object[] { config };\n            return context => Create(context, genericCreate, args);\n        }\n\n        private object Create(IGrainContext context, MethodInfo genericCreate, object[] args)\n        {\n            ITransactionalStateFactory factory = context.ActivationServices.GetRequiredService<ITransactionalStateFactory>();\n            return genericCreate.Invoke(factory, args);\n        }\n\n        protected abstract TransactionalStateConfiguration AttributeToConfig(TAttribute attribute);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Hosting/TransactionsServiceCollectionExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection.Extensions;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class TransactionsServiceCollectionExtensions\n    {\n        internal static IServiceCollection UseTransactionsWithSilo(this IServiceCollection services)\n        {\n            services.AddTransactionsBaseline();\n            services.TryAddSingleton(typeof(ITransactionDataCopier<>), typeof(DefaultTransactionDataCopier<>));\n            services.AddSingleton<IAttributeToFactoryMapper<TransactionalStateAttribute>, TransactionalStateAttributeMapper>();\n            services.TryAddTransient<ITransactionalStateFactory, TransactionalStateFactory>();\n            services.AddSingleton<IAttributeToFactoryMapper<TransactionCommitterAttribute>, TransactionCommitterAttributeMapper>();\n            services.TryAddTransient<ITransactionCommitterFactory, TransactionCommitterFactory>();\n            services.TryAddTransient<INamedTransactionalStateStorageFactory, NamedTransactionalStateStorageFactory>();\n            services.AddTransient(typeof(ITransactionalState<>), typeof(TransactionalState<>));\n            return services;\n        }\n\n        internal static IServiceCollection UseTransactionsWithClient(this IServiceCollection services) => services.AddTransactionsBaseline();\n\n        internal static IServiceCollection AddTransactionsBaseline(this IServiceCollection services)\n        {\n            services.TryAddSingleton<IClock, Clock>();\n            services.AddSingleton<ITransactionAgent, TransactionAgent>();\n            services.AddSingleton<ITransactionClient, TransactionClient>();\n            services.TryAddSingleton<ITransactionAgentStatistics, TransactionAgentStatistics>();\n            services.TryAddSingleton<ITransactionOverloadDetector, TransactionOverloadDetector>();\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/ITransactionAgent.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// The Transaction Agent it is used by the silo and activations to\n    /// interact with the transactions system.\n    /// </summary>\n    /// <remarks>\n    /// There is one Transaction Agent per silo.\n    /// TODO: does this belong in Runtime instead?\n    /// </remarks>\n    public interface ITransactionAgent\n    {\n        /// <summary>\n        /// Starts a new transaction\n        /// </summary>\n        /// <param name=\"readOnly\">Whether it is a read-only transaction</param>\n        /// <param name=\"timeout\">Transaction is automatically aborted if it does not complete within this time</param>\n        /// <returns>Info of the new transaction</returns>\n        Task<TransactionInfo> StartTransaction(bool readOnly, TimeSpan timeout);\n\n        /// <summary>\n        /// Attempt to Resolve a transaction.  Will commit or abort transaction\n        /// </summary>\n        /// <param name=\"transactionInfo\">transaction info</param>\n        /// <returns>null if the transaction committed successfully, or an exception otherwise.\n        /// If the exception is OrleansTransactionInDoubtException, it means the outcome of the Commit cannot be determined; otherwise,\n        /// the transaction is guaranteed to not have taken effect.</returns>\n        Task<(TransactionalStatus Status, Exception exception)> Resolve(TransactionInfo transactionInfo);\n\n        /// <summary>\n        /// Abort a transaction.\n        /// </summary>\n        /// <param name=\"transactionInfo\"></param>\n        /// <returns>None.</returns>\n        /// <remarks>This method is exception-free</remarks>\n        Task Abort(TransactionInfo transactionInfo);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/ITransactionClient.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nnamespace Orleans;\n\npublic interface ITransactionClient\n{\n    /// <summary>\n    /// Run transaction delegate\n    /// </summary>\n    /// <param name=\"transactionOption\"></param>\n    /// <param name=\"transactionDelegate\"></param>\n    /// <returns><see cref=\"Task\"/></returns>\n    /// <remarks>Transaction always commit, unless an exception is thrown from the delegate and depending on <paramref name=\"transactionOption\"/></remarks>\n    Task RunTransaction(TransactionOption transactionOption, Func<Task> transactionDelegate);\n\n    /// <summary>\n    /// Run transaction delegate\n    /// </summary>\n    /// <param name=\"transactionOption\"></param>\n    /// <param name=\"transactionDelegate\"></param>\n    /// <returns>True if the transaction should commit</returns>\n    Task RunTransaction(TransactionOption transactionOption, Func<Task<bool>> transactionDelegate);\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Orleans.Transactions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Transactions</PackageId>\n    <Title>Microsoft Orleans Transactions support</Title>\n    <Description>Core Transaction library of Microsoft Orleans used on the server.</Description>\n    <PackageTags>$(PackageTags) Transactions</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <AssemblyName>Orleans.Transactions</AssemblyName>\n    <RootNamespace>Orleans.Transactions</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Transactions.TestKit.Base\" />\n    <InternalsVisibleTo Include=\"Orleans.Transactions.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Orleans.Transactions/OrleansTransactionException.cs",
    "content": "using Orleans.Runtime;\nusing System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// Base class for all transaction exceptions\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class OrleansTransactionException : OrleansException\n    {\n        public OrleansTransactionException() : base(\"Orleans transaction error.\") { }\n\n        public OrleansTransactionException(string message) : base(message) { }\n\n        public OrleansTransactionException(string message, Exception innerException) : base(message, innerException) { }\n\n        [Obsolete]\n        protected OrleansTransactionException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Orleans transactions are disabled.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionsDisabledException : OrleansTransactionException\n    {\n        public OrleansTransactionsDisabledException()\n            : base(\"Orleans transactions have not been enabled. Transactions are disabled by default and must be configured to be used.\")\n        {\n        }\n\n        [Obsolete]\n        private OrleansTransactionsDisabledException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the runtime was unable to start a transaction.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansStartTransactionFailedException : OrleansTransactionException\n    {\n        public OrleansStartTransactionFailedException(Exception innerException)\n            : base(\"Failed to start transaction. Check InnerException for details\", innerException)\n        {\n        }\n\n        [Obsolete]\n        private OrleansStartTransactionFailedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that transaction runtime is overloaded\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionOverloadException : OrleansTransactionException\n    {\n        public OrleansTransactionOverloadException()\n            : base(\"Transaction is overloaded on current silo, please try again later.\")\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the runtime is unable to determine whether a transaction\n    /// has committed.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionInDoubtException : OrleansTransactionException\n    {\n        [Id(0)]\n        public string TransactionId { get; private set; }\n\n        public OrleansTransactionInDoubtException(string transactionId) : base(string.Format(\"Transaction {0} is InDoubt\", transactionId))\n        {\n            this.TransactionId = transactionId;\n        }\n\n        public OrleansTransactionInDoubtException(string transactionId, Exception exc) : base(string.Format(\"Transaction {0} is InDoubt\", transactionId), exc)\n        {\n            this.TransactionId = transactionId;\n        }\n\n        public OrleansTransactionInDoubtException(string transactionId, string msg, Exception innerException) : base(string.Format(\"Transaction {0} is InDoubt: {1}\", transactionId, msg), innerException)\n        {\n            this.TransactionId = transactionId;\n        }\n\n        [Obsolete]\n        private OrleansTransactionInDoubtException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.TransactionId = info.GetString(nameof(this.TransactionId));\n        }\n\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(this.TransactionId), this.TransactionId);\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class OrleansTransactionAbortedException : OrleansTransactionException\n    {\n        /// <summary>\n        /// The unique identifier of the aborted transaction.\n        /// </summary>\n        [Id(0)]\n        public string TransactionId { get; private set; }\n \n        public OrleansTransactionAbortedException(string transactionId, string msg, Exception innerException) : base(msg, innerException)\n        {\n            this.TransactionId = transactionId;\n        }\n\n        public OrleansTransactionAbortedException(string transactionId, string msg) : base(msg)\n        {\n            this.TransactionId = transactionId;\n        }\n\n        public OrleansTransactionAbortedException(string transactionId, Exception innerException)\n            : base($\"Transaction {transactionId} Aborted because of an unhandled exception in a grain method call. See InnerException for details.\", innerException)\n        {\n            TransactionId = transactionId;\n        }\n\n        [Obsolete]\n        protected OrleansTransactionAbortedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.TransactionId = info.GetString(nameof(this.TransactionId));\n        }\n\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(this.TransactionId), this.TransactionId);\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because a dependent transaction aborted.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansCascadingAbortException : OrleansTransactionTransientFailureException\n    {\n        [Id(0)]\n        public string DependentTransactionId { get; private set; }\n\n        public OrleansCascadingAbortException(string transactionId, string dependentId)\n            : base(transactionId, string.Format(\"Transaction {0} aborted because its dependent transaction {1} aborted\", transactionId, dependentId))\n        {\n            this.DependentTransactionId = dependentId;\n        }\n\n        public OrleansCascadingAbortException(string transactionId)\n            : base(transactionId, string.Format(\"Transaction {0} aborted because a dependent transaction aborted\", transactionId))\n        {\n        }\n\n        public OrleansCascadingAbortException(string transactionId, Exception innerException)\n            : base(transactionId, string.Format(\"Transaction {0} aborted because a dependent transaction aborted\", transactionId), innerException)\n        {\n        }\n\n        [Obsolete]\n        private OrleansCascadingAbortException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n            this.DependentTransactionId = info.GetString(nameof(this.DependentTransactionId));\n        }\n\n        [Obsolete]\n        public override void GetObjectData(SerializationInfo info, StreamingContext context)\n        {\n            base.GetObjectData(info, context);\n            info.AddValue(nameof(this.DependentTransactionId), this.DependentTransactionId);\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because a method did not await all its pending calls.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansOrphanCallException : OrleansTransactionAbortedException\n    {\n        public OrleansOrphanCallException(string transactionId, int pendingCalls)\n            : base(\n                transactionId,\n                $\"Transaction {transactionId} aborted because method did not await all its outstanding calls ({pendingCalls})\")\n        {\n        }\n\n        [Obsolete]\n        private OrleansOrphanCallException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing read-only transaction has aborted because it attempted to write to a grain.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansReadOnlyViolatedException : OrleansTransactionAbortedException\n    {\n        public OrleansReadOnlyViolatedException(string transactionId)\n            : base(transactionId, string.Format(\"Transaction {0} aborted because it attempted to write a grain\", transactionId))\n        {\n        }\n\n        [Obsolete]\n        private OrleansReadOnlyViolatedException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionServiceNotAvailableException : OrleansTransactionException\n    {\n        public OrleansTransactionServiceNotAvailableException() : base(\"Transaction service not available\")\n        {\n        }\n\n        [Obsolete]\n        private OrleansTransactionServiceNotAvailableException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because its execution lock was broken\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansBrokenTransactionLockException : OrleansTransactionTransientFailureException\n    {\n        public OrleansBrokenTransactionLockException(string transactionId, string situation)\n            : base(transactionId, $\"Transaction {transactionId} aborted because a broken lock was detected, {situation}\")\n        {\n        }\n\n        public OrleansBrokenTransactionLockException(string transactionId, string situation, Exception innerException)\n            : base(transactionId, $\"Transaction {transactionId} aborted because a broken lock was detected, {situation}\", innerException)\n        {\n        }\n\n        [Obsolete]\n        private OrleansBrokenTransactionLockException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because it could not upgrade some lock\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionLockUpgradeException : OrleansTransactionTransientFailureException\n    {\n        public OrleansTransactionLockUpgradeException(string transactionId) :\n            base(transactionId, $\"Transaction {transactionId} Aborted because it could not upgrade a lock, because of a higher-priority conflicting transaction\")\n        {\n        }\n\n        [Obsolete]\n        private OrleansTransactionLockUpgradeException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because the TM did not receive all prepared messages in time\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class OrleansTransactionPrepareTimeoutException : OrleansTransactionTransientFailureException\n    {\n        public OrleansTransactionPrepareTimeoutException(string transactionId, Exception innerException)\n            : base(transactionId, $\"Transaction {transactionId} Aborted because the prepare phase did not complete within the timeout limit\", innerException)\n        {\n        }\n\n        [Obsolete]\n        private OrleansTransactionPrepareTimeoutException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Signifies that the executing transaction has aborted because some possibly transient problem, such as internal\n    /// timeouts for locks or protocol responses, or speculation failures.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class OrleansTransactionTransientFailureException : OrleansTransactionAbortedException\n    {\n        public OrleansTransactionTransientFailureException(string transactionId, string msg, Exception innerException)\n            : base(transactionId, msg, innerException)\n        {\n        }\n\n        public OrleansTransactionTransientFailureException(string transactionId, string msg)\n            : base(transactionId, msg)\n        {\n        }\n\n        [Obsolete]\n        protected OrleansTransactionTransientFailureException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/ActivationLifetime.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\n\nnamespace Orleans.Transactions.State\n{\n    internal class ActivationLifetime : IActivationLifetime, ILifecycleObserver\n    {\n        private readonly CancellationTokenSource onDeactivating = new CancellationTokenSource();\n\n        private int pendingDeactivationLocks;\n\n        public ActivationLifetime(IGrainContext activationContext)\n        {\n            activationContext.ObservableLifecycle.Subscribe(GrainLifecycleStage.First, this);\n            activationContext.ObservableLifecycle.Subscribe(GrainLifecycleStage.Last, this);\n        }\n\n        public CancellationToken OnDeactivating => this.onDeactivating.Token;\n\n        public Task OnStart(CancellationToken ct) => Task.CompletedTask;\n\n        public Task OnStop(CancellationToken ct)\n        {\n            this.onDeactivating.Cancel(throwOnFirstException: false);\n\n            if (!ct.IsCancellationRequested && pendingDeactivationLocks > 0)\n            {\n                return OnStopAsync(ct);\n            }\n\n            return Task.CompletedTask;\n        }\n\n        private async Task OnStopAsync(CancellationToken ct)\n        {\n            var startTime = DateTime.UtcNow;\n            var maxTime = TimeSpan.FromSeconds(5);\n            while (!ct.IsCancellationRequested && pendingDeactivationLocks > 0 && DateTime.UtcNow - startTime < maxTime)\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(10));\n            }\n        }\n\n        public IDisposable BlockDeactivation() => new BlockDeactivationDisposable(this);\n\n        private class BlockDeactivationDisposable : IDisposable\n        {\n            private readonly ActivationLifetime owner;\n\n            public BlockDeactivationDisposable(ActivationLifetime owner)\n            {\n                this.owner = owner;\n                Interlocked.Increment(ref owner.pendingDeactivationLocks);\n            }\n\n            public void Dispose()\n            {\n                Interlocked.Decrement(ref owner.pendingDeactivationLocks);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/ConfirmationWorker.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Timers.Internal;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.State\n{\n    internal partial class ConfirmationWorker<TState>\n        where TState : class, new()\n    {\n        private readonly TransactionalStateOptions options;\n        private readonly ParticipantId me;\n        private readonly BatchWorker storageWorker;\n        private readonly Func<StorageBatch<TState>> getStorageBatch;\n        private readonly ILogger logger;\n        private readonly ITimerManager timerManager;\n        private readonly IActivationLifetime activationLifetime;\n        private readonly HashSet<Guid> pending;\n\n        public ConfirmationWorker(\n            IOptions<TransactionalStateOptions> options,\n            ParticipantId me,\n            BatchWorker storageWorker,\n            Func<StorageBatch<TState>> getStorageBatch,\n            ILogger logger,\n            ITimerManager timerManager,\n            IActivationLifetime activationLifetime)\n        {\n            this.options = options.Value;\n            this.me = me;\n            this.storageWorker = storageWorker;\n            this.getStorageBatch = getStorageBatch;\n            this.logger = logger;\n            this.timerManager = timerManager;\n            this.activationLifetime = activationLifetime;\n            this.pending = new HashSet<Guid>();\n        }\n\n        public void Add(Guid transactionId, DateTime timestamp, List<ParticipantId> participants)\n        {\n            if (!IsConfirmed(transactionId))\n            {\n                this.pending.Add(transactionId);\n                SendConfirmation(transactionId, timestamp, participants).Ignore();\n            }\n        }\n\n        public bool IsConfirmed(Guid transactionId)\n        {\n            return this.pending.Contains(transactionId);\n        }\n\n        private async Task SendConfirmation(Guid transactionId, DateTime timestamp, List<ParticipantId> participants)\n        {\n            await NotifyAll(transactionId, timestamp, participants);\n            await Collect(transactionId);\n        }\n\n        private async Task NotifyAll(Guid transactionId, DateTime timestamp, List<ParticipantId> participants)\n        {\n            List<Confirmation> confirmations = participants\n                    .Where(p => !p.Equals(this.me))\n                    .Select(p => new Confirmation(\n                        p,\n                        transactionId,\n                        timestamp,\n                        () => p.Reference.AsReference<ITransactionalResourceExtension>()\n                            .Confirm(p.Name, transactionId, timestamp),\n                        this.logger))\n                    .ToList();\n\n            if (confirmations.Count == 0) return;\n\n            // attempts to confirm all, will retry every ConfirmationRetryDelay until all succeed\n            var ct = this.activationLifetime.OnDeactivating;\n\n            bool hasPendingConfirmations = true;\n            while (!ct.IsCancellationRequested && hasPendingConfirmations)\n            {\n                using (this.activationLifetime.BlockDeactivation())\n                {\n                    var confirmationResults = await Task.WhenAll(confirmations.Select(c => c.Confirmed()));\n                    hasPendingConfirmations = false;\n                    foreach (var confirmed in confirmationResults)\n                    {\n                        if (!confirmed)\n                        {\n                            hasPendingConfirmations = true;\n                            await this.timerManager.Delay(this.options.ConfirmationRetryDelay, ct);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        // retries collect until it succeeds\n        private async Task Collect(Guid transactionId)\n        {\n            var ct = this.activationLifetime.OnDeactivating;\n            while (!ct.IsCancellationRequested)\n            {\n                using (this.activationLifetime.BlockDeactivation())\n                {\n                    if (await TryCollect(transactionId)) break;\n\n                    await this.timerManager.Delay(this.options.ConfirmationRetryDelay, ct);\n                }\n            }\n        }\n\n        // attempt to clear transaction from commit log\n        private async Task<bool> TryCollect(Guid transactionId)\n        {\n            try\n            {\n                var storeComplete = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n                // Now we can remove the commit record.\n                StorageBatch<TState> storageBatch = getStorageBatch();\n                storageBatch.Collect(transactionId);\n                storageBatch.FollowUpAction(() =>\n                {\n                    LogTraceCollectionCompleted(transactionId);\n                    this.pending.Remove(transactionId);\n                    storeComplete.TrySetResult(true);\n                });\n\n                storageWorker.Notify();\n\n                // wait for storage call, so we don't free spin\n                return await storeComplete.Task;\n            }\n            catch(Exception ex)\n            {\n                LogWarnCollectingTransaction(transactionId, ex);\n            }\n\n            return false;\n        }\n\n        // Tracks the effort to notify a participant, will not call again once it succeeds.\n        private struct Confirmation\n        {\n            private readonly ParticipantId participant;\n            private readonly Guid transactionId;\n            private readonly DateTime timestamp;\n            private readonly Func<Task> call;\n            private readonly ILogger logger;\n            private Task pending;\n            private bool complete;\n\n            public Confirmation(ParticipantId paricipant, Guid transactionId, DateTime timestamp, Func<Task> call, ILogger logger)\n            {\n                this.participant = paricipant;\n                this.transactionId = transactionId;\n                this.timestamp = timestamp;\n                this.call = call;\n                this.logger = logger;\n                this.pending = null;\n                this.complete = false;\n            }\n\n            public async Task<bool> Confirmed()\n            {\n                if (this.complete) return this.complete;\n                this.pending = this.pending ?? call();\n                try\n                {\n                    await this.pending;\n                    this.complete = true;\n                }\n                catch (Exception ex)\n                {\n                    this.pending = null;\n                    LogWarningConfirmationFailed(this.logger, this.transactionId, this.timestamp, this.participant, ex);\n                }\n                return this.complete;\n            }\n\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Collection completed. TransactionId:{TransactionId}\"\n        )]\n        private partial void LogTraceCollectionCompleted(Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Error occured while cleaning up transaction {TransactionId} from commit log.  Will retry.\"\n        )]\n        private partial void LogWarnCollectingTransaction(Guid transactionId, Exception ex);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Confirmation of transaction {TransactionId} with timestamp {Timestamp} to participant {Participant} failed.  Retrying\"\n        )]\n        private static partial void LogWarningConfirmationFailed(ILogger logger, Guid transactionId, DateTime timestamp, ParticipantId participant, Exception ex);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/IActivationLifetime.cs",
    "content": "using System;\nusing System.Threading;\n\nnamespace Orleans.Transactions.State\n{\n    internal interface IActivationLifetime\n    {\n        CancellationToken OnDeactivating { get; }\n\n        IDisposable BlockDeactivation();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/NamedTransactionalStateStorageFactory.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Storage;\n\nnamespace Orleans.Transactions\n{\n    public class NamedTransactionalStateStorageFactory : INamedTransactionalStateStorageFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n\n        [Obsolete(\"Use the NamedTransactionalStateStorageFactory(IGrainContextAccessor contextAccessor) constructor.\")]\n        public NamedTransactionalStateStorageFactory(IGrainContextAccessor contextAccessor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : this(contextAccessor)\n        {\n        }\n\n        public NamedTransactionalStateStorageFactory(IGrainContextAccessor contextAccessor)\n        {\n            this.contextAccessor = contextAccessor;\n        }\n\n        public ITransactionalStateStorage<TState> Create<TState>(string storageName, string stateName)\n            where TState : class, new()\n        {\n            var currentContext = this.contextAccessor.GrainContext;\n\n            // Try to get ITransactionalStateStorage from factory\n            ITransactionalStateStorageFactory factory = string.IsNullOrEmpty(storageName)\n                ? currentContext.ActivationServices.GetService<ITransactionalStateStorageFactory>()\n                : currentContext.ActivationServices.GetKeyedService<ITransactionalStateStorageFactory>(storageName);\n            if (factory != null) return factory.Create<TState>(stateName, currentContext);\n\n            // Else try to get storage provider and wrap it\n            IGrainStorage grainStorage = string.IsNullOrEmpty(storageName)\n                ? currentContext.ActivationServices.GetService<IGrainStorage>()\n                : currentContext.ActivationServices.GetKeyedService<IGrainStorage>(storageName);\n\n            if (grainStorage != null)\n            {\n                return new TransactionalStateStorageProviderWrapper<TState>(grainStorage, stateName, currentContext);\n            }\n\n            throw (string.IsNullOrEmpty(storageName))\n                ? new InvalidOperationException($\"No default {nameof(ITransactionalStateStorageFactory)} nor {nameof(IGrainStorage)} was found while attempting to create transactional state storage.\")\n                : new InvalidOperationException($\"No {nameof(ITransactionalStateStorageFactory)} nor {nameof(IGrainStorage)} with the name {storageName} was found while attempting to create transactional state storage.\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/ReaderWriterLock.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.State\n{\n    internal partial class ReadWriteLock<TState>\n       where TState : class, new()\n    {\n        private readonly TransactionalStateOptions options;\n        private readonly TransactionQueue<TState> queue;\n        private readonly BatchWorker lockWorker;\n        private readonly BatchWorker storageWorker;\n        private readonly ILogger logger;\n        private readonly IActivationLifetime activationLifetime;\n\n        // the linked list of lock groups\n        // the head is the group that is currently holding the lock\n        private LockGroup currentGroup = null;\n\n        // cache the last known minimum so we don't have to recompute it as much\n        private DateTime cachedMin = DateTime.MaxValue;\n        private Guid cachedMinId;\n\n        // group of non-conflicting transactions collectively acquiring/releasing the lock\n        private class LockGroup : Dictionary<Guid, TransactionRecord<TState>>\n        {\n            public int FillCount;\n            public List<Action> Tasks; // the tasks for executing the waiting operations\n            public LockGroup Next; // queued-up transactions waiting to acquire lock\n            public DateTime? Deadline;\n            public void Reset()\n            {\n                FillCount = 0;\n                Tasks = null;\n                Deadline = null;\n                Clear();\n            }\n        }\n\n        public ReadWriteLock(\n            IOptions<TransactionalStateOptions> options,\n            TransactionQueue<TState> queue,\n            BatchWorker storageWorker,\n            ILogger logger,\n            IActivationLifetime activationLifetime)\n        {\n            this.options = options.Value;\n            this.queue = queue;\n            this.storageWorker = storageWorker;\n            this.logger = logger;\n            this.activationLifetime = activationLifetime;\n            this.lockWorker = new BatchWorkerFromDelegate(LockWork, this.activationLifetime.OnDeactivating);\n        }\n\n        public async Task<TResult> EnterLock<TResult>(Guid transactionId, DateTime priority,\n                                   AccessCounter counter, bool isRead, Func<TResult> task)\n        {\n            bool rollbacksOccurred = false;\n            List<Task> cleanup = new List<Task>();\n\n            await this.queue.Ready();\n\n            // search active transactions\n            if (Find(transactionId, isRead, out var group, out var record))\n            {\n                // check if we lost some reads or writes already\n                if (counter.Reads > record.NumberReads || counter.Writes > record.NumberWrites)\n                {\n                    throw new OrleansBrokenTransactionLockException(transactionId.ToString(), \"when re-entering lock\");\n                }\n\n                // check if the operation conflicts with other transactions in the group\n                if (HasConflict(isRead, priority, transactionId, group, out var resolvable))\n                {\n                    if (!resolvable)\n                    {\n                        throw new OrleansTransactionLockUpgradeException(transactionId.ToString());\n                    }\n                    else\n                    {\n                        // rollback all conflicts\n                        var conflicts = Conflicts(transactionId, group).ToList();\n\n                        if (conflicts.Count > 0)\n                        {\n                            foreach (var r in conflicts)\n                            {\n                                cleanup.Add(Rollback(r, true));\n                                rollbacksOccurred = true;\n                            }\n                        }\n                    }\n                }\n            }\n            else\n            {\n                // check if we were supposed to already hold this lock\n                if (counter.Reads + counter.Writes > 0)\n                {\n                    throw new OrleansBrokenTransactionLockException(transactionId.ToString(), \"when trying to re-enter lock\");\n                }\n\n                // update the lock deadline\n                if (group == currentGroup)\n                {\n                    group.Deadline = DateTime.UtcNow + this.options.LockTimeout;\n                    LogTraceSetLockExpiration(new(group.Deadline));\n                }\n\n                // create a new record for this transaction\n                record = new TransactionRecord<TState>()\n                {\n                    TransactionId = transactionId,\n                    Priority = priority,\n                    Deadline = DateTime.UtcNow + this.options.LockAcquireTimeout\n                };\n\n                group.Add(transactionId, record);\n                group.FillCount++;\n\n                if (group == currentGroup)\n                    LogTraceEnterLock(transactionId, group.FillCount);\n                else\n                    LogTraceEnterLockQueue(transactionId, group.FillCount);\n            }\n\n            var result =\n                new TaskCompletionSource<TResult>(TaskCreationOptions.RunContinuationsAsynchronously);\n            void completion()\n            {\n                try\n                {\n                    result.TrySetResult(task());\n                }\n                catch (Exception exception)\n                {\n                    result.TrySetException(exception);\n                }\n            }\n\n            if (group != currentGroup)\n            {\n                // task will be executed once its group acquires the lock\n\n                if (group.Tasks == null)\n                    group.Tasks = new List<Action>();\n\n                group.Tasks.Add(completion);\n            }\n            else\n            {\n                // execute task right now\n                completion();\n            }\n\n            if (isRead)\n            {\n                record.AddRead();\n            }\n            else\n            {\n                record.AddWrite();\n            }\n\n            if (rollbacksOccurred)\n            {\n                lockWorker.Notify();\n            }\n            else if (group.Deadline.HasValue)\n            {\n                lockWorker.Notify(group.Deadline.Value);\n            }\n\n            await Task.WhenAll(cleanup);\n            return await result.Task;\n        }\n\n        public async Task<(TransactionalStatus Status, TransactionRecord<TState> State)> ValidateLock(Guid transactionId, AccessCounter accessCount)\n        {\n            if (currentGroup == null || !currentGroup.TryGetValue(transactionId, out TransactionRecord<TState> record))\n            {\n                return (TransactionalStatus.BrokenLock, new TransactionRecord<TState>());\n            }\n            else if (record.NumberReads != accessCount.Reads\n                   || record.NumberWrites != accessCount.Writes)\n            {\n                await Rollback(transactionId, true);\n                return (TransactionalStatus.LockValidationFailed, record);\n            }\n            else\n            {\n                return (TransactionalStatus.Ok, record);\n            }\n        }\n\n        public void Notify()\n        {\n            this.lockWorker.Notify();\n        }\n\n        public bool TryGetRecord(Guid transactionId, out TransactionRecord<TState> record)\n        {\n            return this.currentGroup.TryGetValue(transactionId, out record);\n        }\n\n        public Task AbortExecutingTransactions(Exception exception)\n        {\n            if (currentGroup != null)\n            {\n                Task[] pending = currentGroup.Select(g => BreakLock(g.Key, g.Value, exception)).ToArray();\n                currentGroup.Reset();\n                return Task.WhenAll(pending);\n            }\n            return Task.CompletedTask;\n        }\n\n        private Task BreakLock(Guid transactionId, TransactionRecord<TState> entry, Exception exception)\n        {\n            LogTraceBreakLock(transactionId);\n            return this.queue.NotifyOfAbort(entry, TransactionalStatus.BrokenLock, exception);\n        }\n\n        public void AbortQueuedTransactions()\n        {\n            var pos = currentGroup?.Next;\n            while (pos != null)\n            {\n                if (pos.Tasks != null)\n                {\n                    foreach (var t in pos.Tasks)\n                    {\n                        // running the task will abort the transaction because it is not in currentGroup\n                        t();\n                    }\n                }\n                pos.Clear();\n                pos = pos.Next;\n            }\n            if (currentGroup != null)\n                currentGroup.Next = null;\n        }\n\n        public void Rollback(Guid guid) => currentGroup?.Remove(guid);\n\n        public Task Rollback(Guid guid, bool notify)\n        {\n            // no-op if the transaction never happened or already rolled back\n            if (currentGroup == null || !currentGroup.Remove(guid, out var record))\n            {\n                return Task.CompletedTask;\n            }\n\n            // notify remote listeners\n            return notify ? queue.NotifyOfAbort(record, TransactionalStatus.BrokenLock, exception: null) : Task.CompletedTask;\n        }\n\n        private async Task LockWork()\n        {\n            // Stop pumping lock work if this activation is stopping/stopped.\n            if (this.activationLifetime.OnDeactivating.IsCancellationRequested) return;\n            using (this.activationLifetime.BlockDeactivation())\n            {\n                var now = DateTime.UtcNow;\n\n                if (currentGroup != null)\n                {\n                    // check if there are any group members that are ready to exit the lock\n                    if (currentGroup.Count > 0)\n                    {\n                        if (LockExits(out var single, out var multiple))\n                        {\n                            if (single != null)\n                            {\n                                await this.queue.EnqueueCommit(single);\n                            }\n                            else if (multiple != null)\n                            {\n                                foreach (var r in multiple)\n                                {\n                                    await this.queue.EnqueueCommit(r);\n                                }\n                            }\n\n                            lockWorker.Notify();\n                            storageWorker.Notify();\n                        }\n\n                        else if (currentGroup.Deadline.HasValue)\n                        {\n                            if (currentGroup.Deadline.Value < now)\n                            {\n                                // the lock group has timed out.\n                                TimeSpan late = now - currentGroup.Deadline.Value;\n                                LogTraceBreakLockTimeout(new(currentGroup.Keys), Math.Floor(late.TotalMilliseconds));\n                                await AbortExecutingTransactions(exception: null);\n                                lockWorker.Notify();\n                            }\n                            else\n                            {\n                                LogTraceRecheckLockExpiration(new(currentGroup.Deadline));\n\n                                // check again when the group expires\n                                lockWorker.Notify(currentGroup.Deadline.Value);\n                            }\n                        }\n                        else\n                        {\n                            LogWarningDeadlineNotSet(new(currentGroup.Keys));\n                        }\n                    }\n\n                    else\n                    {\n                        // the lock is empty, a new group can enter\n                        currentGroup = currentGroup.Next;\n\n                        if (currentGroup != null)\n                        {\n                            currentGroup.Deadline = now + this.options.LockTimeout;\n\n                            // discard expired waiters that have no chance to succeed\n                            // because they have been waiting for the lock for a longer timespan than the\n                            // total transaction timeout\n                            foreach (var kvp in currentGroup)\n                            {\n                                if (now > kvp.Value.Deadline)\n                                {\n                                    currentGroup.Remove(kvp.Key);\n                                    LogTraceExpireLockWaiter(kvp.Key);\n                                }\n                            }\n\n                            LogTraceLockGroupSize(currentGroup.Count, new(currentGroup.Deadline));\n                            if (logger.IsEnabled(LogLevel.Trace))\n                            {\n                                foreach (var kvp in currentGroup)\n                                    LogTraceEnterLockKey(kvp.Key);\n                            }\n\n                            // execute all the read and update tasks\n                            if (currentGroup.Tasks != null)\n                            {\n                                foreach (var t in currentGroup.Tasks)\n                                {\n                                    t();\n                                }\n                            }\n\n                            lockWorker.Notify();\n                        }\n                    }\n                }\n            }\n        }\n\n        private bool Find(Guid guid, bool isRead, out LockGroup group, out TransactionRecord<TState> record)\n        {\n            if (currentGroup == null)\n            {\n                group = currentGroup = new LockGroup();\n                record = null;\n                return false;\n            }\n            else\n            {\n                group = null;\n                var pos = currentGroup;\n\n                while (true)\n                {\n                    if (pos.TryGetValue(guid, out record))\n                    {\n                        group = pos;\n                        return true;\n                    }\n\n                    // if we have not found a place to insert this op yet, and there is room, and no conflicts, use this one\n                    if (group == null\n                        && pos.FillCount < this.options.MaxLockGroupSize\n                        && !HasConflict(isRead, DateTime.MaxValue, guid, pos, out _))\n                    {\n                        group = pos;\n                    }\n\n                    if (pos.Next == null) // we did not find this tx.\n                    {\n                        // add a new empty group to insert this tx, if we have not found one yet\n                        if (group == null)\n                        {\n                            group = pos.Next = new LockGroup();\n                        }\n\n                        return false;\n                    }\n\n                    pos = pos.Next;\n                }\n            }\n        }\n\n        private static bool HasConflict(bool isRead, DateTime priority, Guid transactionId, LockGroup group, out bool resolvable)\n        {\n            bool foundResolvableConflicts = false;\n\n            foreach (var kvp in group)\n            {\n                if (kvp.Key != transactionId)\n                {\n                    if (isRead && kvp.Value.NumberWrites == 0)\n                    {\n                        continue;\n                    }\n                    else\n                    {\n                        if (priority > kvp.Value.Priority)\n                        {\n                            resolvable = false;\n                            return true;\n                        }\n                        else\n                        {\n                            foundResolvableConflicts = true;\n                        }\n                    }\n                }\n            }\n\n            resolvable = foundResolvableConflicts;\n            return foundResolvableConflicts;\n        }\n\n        private static IEnumerable<Guid> Conflicts(Guid transactionId, LockGroup group)\n        {\n            foreach (var kvp in group)\n            {\n                if (kvp.Key != transactionId)\n                {\n                    yield return kvp.Key;\n                }\n            }\n        }\n\n        private bool LockExits(out TransactionRecord<TState> single, out List<TransactionRecord<TState>> multiple)\n        {\n            single = null;\n            multiple = null;\n\n            // fast-path the one-element case\n            if (currentGroup.Count == 1)\n            {\n                var kvp = currentGroup.First();\n                if (kvp.Value.Role == CommitRole.NotYetDetermined) // has not received commit from TA\n                {\n                    return false;\n                }\n                else\n                {\n                    single = kvp.Value;\n\n                    currentGroup.Remove(single.TransactionId);\n                    LogDebugExitLock(single.TransactionId, new(single.Timestamp));\n                    return true;\n                }\n            }\n            else\n            {\n                // find the current minimum, if we don't have a valid cache of it\n                if (cachedMin == DateTime.MaxValue\n                    || !currentGroup.TryGetValue(cachedMinId, out var record)\n                    || record.Role != CommitRole.NotYetDetermined\n                    || record.Timestamp != cachedMin)\n                {\n                    cachedMin = DateTime.MaxValue;\n                    foreach (var kvp in currentGroup)\n                    {\n                        if (kvp.Value.Role == CommitRole.NotYetDetermined) // has not received commit from TA\n                        {\n                            if (cachedMin > kvp.Value.Timestamp)\n                            {\n                                cachedMin = kvp.Value.Timestamp;\n                                cachedMinId = kvp.Key;\n                            }\n                        }\n                    }\n                }\n\n                // find released entries\n                foreach (var kvp in currentGroup)\n                {\n                    if (kvp.Value.Role != CommitRole.NotYetDetermined) // ready to commit\n                    {\n                        if (kvp.Value.Timestamp < cachedMin)\n                        {\n                            if (multiple == null)\n                            {\n                                multiple = new List<TransactionRecord<TState>>();\n                            }\n                            multiple.Add(kvp.Value);\n                        }\n                    }\n                }\n\n                if (multiple == null)\n                {\n                    return false;\n                }\n                else\n                {\n                    multiple.Sort(Comparer);\n\n                    for (int i = 0; i < multiple.Count; i++)\n                    {\n                        currentGroup.Remove(multiple[i].TransactionId);\n                        LogDebugExitLockProgress(i, multiple.Count, multiple[i].TransactionId, new(multiple[i].Timestamp));\n                    }\n\n                    return true;\n                }\n            }\n        }\n\n        private static int Comparer(TransactionRecord<TState> a, TransactionRecord<TState> b)\n        {\n            return a.Timestamp.CompareTo(b.Timestamp);\n        }\n\n        private readonly struct DateTimeLogRecord(DateTime? ts)\n        {\n            public override string ToString() => ts?.ToString(\"o\") ?? \"none\";\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Set lock expiration at {Deadline}\"\n        )]\n        private partial void LogTraceSetLockExpiration(DateTimeLogRecord deadline);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Enter-lock {TransactionId} Fill count={FillCount}\"\n        )]\n        private partial void LogTraceEnterLock(Guid transactionId, int fillCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Enter-lock-queue {TransactionId} Fill count={FillCount}\"\n        )]\n        private partial void LogTraceEnterLockQueue(Guid transactionId, int fillCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Break-lock for transaction {TransactionId}\"\n        )]\n        private partial void LogTraceBreakLock(Guid transactionId);\n\n        private readonly struct TransactionIdsLogRecord(IEnumerable<Guid> guids)\n        {\n            public override string ToString() => string.Join(\",\", guids);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Break-lock timeout for transactions {TransactionIds}. {Late}ms late\"\n        )]\n        private partial void LogTraceBreakLockTimeout(TransactionIdsLogRecord transactionIds, double late);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Recheck lock expiration at {Deadline}\"\n        )]\n        private partial void LogTraceRecheckLockExpiration(DateTimeLogRecord deadline);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Deadline not set for transactions {TransactionIds}\"\n        )]\n        private partial void LogWarningDeadlineNotSet(TransactionIdsLogRecord transactionIds);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Expire-lock-waiter {Key}\"\n        )]\n        private partial void LogTraceExpireLockWaiter(Guid key);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Lock group size={Count} deadline={Deadline}\"\n        )]\n        private partial void LogTraceLockGroupSize(int count, DateTimeLogRecord deadline);\n\n        // \"Enter-lock {Key}\"\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Enter-lock {Key}\"\n        )]\n        private partial void LogTraceEnterLockKey(Guid key);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Exit-lock {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogDebugExitLock(Guid transactionId, DateTimeLogRecord timestamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Exit-lock ({Current}/{Count}) {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogDebugExitLockProgress(int current, int count, Guid transactionId, DateTimeLogRecord timestamp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/StorageBatch.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// Events streamed to storage. \n    /// </summary>\n    public interface ITransactionalStateStorageEvents<TState> where TState : class, new()\n    {\n        void Prepare(long sequenceNumber, Guid transactionId, DateTime timestamp, ParticipantId transactionManager, TState state);\n\n        void Read(DateTime timestamp);\n\n        void Cancel(long sequenceNumber);\n\n        void Confirm(long sequenceNumber);\n\n        void Commit(Guid transactionId, DateTime timestamp, List<ParticipantId> writeResources);\n\n        void Collect(Guid transactionId);\n    }\n\n    /// <summary>\n    /// Accumulates storage events, for submitting them to storage as a batch.\n    /// </summary>\n    /// <typeparam name=\"TState\"></typeparam>\n    internal class StorageBatch<TState> : ITransactionalStateStorageEvents<TState>\n        where TState : class, new()\n    {\n        // watermarks for commit, prepare, abort\n        private long confirmUpTo;\n        private long cancelAbove;\n        private readonly long cancelAboveStart;\n\n        // prepare records\n        private readonly SortedDictionary<long, PendingTransactionState<TState>> prepares;\n\n        // follow-up actions, to be executed after storing this batch\n        private readonly List<Action> followUpActions;\n        private readonly List<Func<Task<bool>>> storeConditions;\n        \n        // counters for each type of event\n        private int total = 0;\n        private int prepare = 0;\n        private int read = 0;\n        private int commit = 0;\n        private int confirm = 0;\n        private int collect = 0;\n        private int cancel = 0;\n\n        public TransactionalStateMetaData MetaData { get; private set; }\n\n        public string ETag { get; set; }\n\n        public int BatchSize => total;\n        public override string ToString()\n        {\n            return $\"batchsize={total} [{read}r {prepare}p {commit}c {confirm}cf {collect}cl {cancel}cc]\";\n        }\n\n        public StorageBatch(TransactionalStateMetaData metaData, string etag, long confirmUpTo, long cancelAbove)\n        {\n            this.MetaData = metaData ?? throw new ArgumentNullException(nameof(metaData));\n            this.ETag = etag;\n            this.confirmUpTo = confirmUpTo;\n            this.cancelAbove = cancelAbove;\n            this.cancelAboveStart = cancelAbove;\n            this.followUpActions = new List<Action>();\n            this.storeConditions = new List<Func<Task<bool>>>();\n            this.prepares = new SortedDictionary<long, PendingTransactionState<TState>>();\n        }\n\n        public StorageBatch(StorageBatch<TState> previous)\n            : this(previous.MetaData, previous.ETag, previous.confirmUpTo, previous.cancelAbove)\n        {\n        }\n\n        public StorageBatch(TransactionalStorageLoadResponse<TState> loadresponse)\n            : this(loadresponse.Metadata, loadresponse.ETag, loadresponse.CommittedSequenceId, loadresponse.PendingStates.LastOrDefault()?.SequenceId ?? loadresponse.CommittedSequenceId)\n        {\n        }\n\n        public async Task<string> Store(ITransactionalStateStorage<TState> storage)\n        {\n            List<PendingTransactionState<TState>> list = this.prepares.Values.ToList();\n            return await storage.Store(ETag, this.MetaData, list,\n                (confirm > 0) ? confirmUpTo : (long?)null,\n                (cancelAbove < cancelAboveStart) ? cancelAbove : (long?)null);\n        }\n\n        public void RunFollowUpActions()\n        {\n            foreach (var action in followUpActions)\n            {\n                action();\n            }\n        }\n\n        public void Read(DateTime timestamp)\n        {\n            read++;\n            total++;\n\n            if (MetaData.TimeStamp < timestamp)\n            {\n                MetaData.TimeStamp = timestamp;\n            }\n        }\n\n        public void Prepare(long sequenceNumber, Guid transactionId, DateTime timestamp,\n          ParticipantId transactionManager, TState state)\n        {\n            prepare++;\n            total++;\n\n            if (MetaData.TimeStamp < timestamp)\n                MetaData.TimeStamp = timestamp;\n\n            this.prepares[sequenceNumber] = new PendingTransactionState<TState>\n            {\n                SequenceId = sequenceNumber,\n                TransactionId = transactionId.ToString(),\n                TimeStamp = timestamp,\n                TransactionManager = transactionManager,\n                State = state\n            };\n\n            if (cancelAbove < sequenceNumber)\n            {\n                cancelAbove = sequenceNumber;\n            }\n        }\n\n        public void Cancel(long sequenceNumber)\n        {\n            cancel++;\n            total++;\n\n            this.prepares.Remove(sequenceNumber);\n\n            if (cancelAbove > sequenceNumber - 1)\n            {\n                cancelAbove = sequenceNumber - 1;\n            }\n        }\n\n        public void Confirm(long sequenceNumber)\n        {\n            confirm++;\n            total++;\n\n            confirmUpTo = sequenceNumber;\n\n            // remove all redundant prepare records that are superseded by a later confirmed state\n            while (true)\n            {\n                long? first = this.prepares.Values.FirstOrDefault()?.SequenceId;\n\n                if (first.HasValue && first < confirmUpTo)\n                {\n                    this.prepares.Remove(first.Value);\n                }\n                else\n                {\n                    break;\n                }\n            }\n        }\n\n        public void Commit(Guid transactionId, DateTime timestamp, List<ParticipantId> WriteParticipants)\n        {\n            commit++;\n            total++;\n\n            MetaData.CommitRecords.Add(transactionId, new CommitRecord()\n            {\n                Timestamp = timestamp,\n                WriteParticipants = WriteParticipants\n            });\n        }\n\n        public void Collect(Guid transactionId)\n        {\n            collect++;\n            total++;\n\n            MetaData.CommitRecords.Remove(transactionId);\n        }\n\n        public void FollowUpAction(Action action)\n        {\n            followUpActions.Add(action);\n        }\n\n        public void AddStorePreCondition(Func<Task<bool>> action)\n        {\n            this.storeConditions.Add(action);\n        }\n\n        public async Task<bool> CheckStorePreConditions()\n        {\n            if (this.storeConditions.Count == 0)\n                return true;\n\n            bool[] results = await Task.WhenAll(this.storeConditions.Select(a => a.Invoke()));\n            return results.All(b => b);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.State\n{\n    internal class TransactionManager<TState> : ITransactionManager\n               where TState : class, new()\n    {\n        private readonly TransactionQueue<TState> queue;\n\n        public TransactionManager(TransactionQueue<TState> queue)\n        {\n            this.queue = queue ?? throw new ArgumentNullException(nameof(queue));\n        }\n\n        public async Task<TransactionalStatus> PrepareAndCommit(Guid transactionId, AccessCounter accessCount, DateTime timeStamp, List<ParticipantId> writeResources, int totalResources)\n        {\n            // validate the lock\n            var (status, record) = await this.queue.RWLock.ValidateLock(transactionId, accessCount);\n            var valid = status == TransactionalStatus.Ok;\n\n            record.Timestamp = timeStamp;\n            record.Role = CommitRole.LocalCommit; // we are the TM\n            record.WaitCount = totalResources - 1;\n            record.WaitingSince = DateTime.UtcNow;\n            record.WriteParticipants = writeResources;\n            record.PromiseForTA = new TaskCompletionSource<TransactionalStatus>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            if (!valid)\n            {\n                await this.queue.NotifyOfAbort(record, status, exception: null);\n            }\n            else\n            {\n                this.queue.Clock.Merge(record.Timestamp);\n            }\n\n            this.queue.RWLock.Notify();\n            return await record.PromiseForTA.Task;\n        }\n\n        public Task Prepared(Guid transactionId, DateTime timeStamp, ParticipantId resource, TransactionalStatus status)\n        {\n            return this.queue.NotifyOfPrepared(transactionId, timeStamp, status);\n        }\n\n        public async Task Ping(Guid transactionId, DateTime timeStamp, ParticipantId resource)\n        {\n            await this.queue.Ready();\n            await this.queue.NotifyOfPing(transactionId, timeStamp, resource);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionQueue.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Storage;\nusing Orleans.Configuration;\nusing Orleans.Timers.Internal;\n\nnamespace Orleans.Transactions.State\n{\n    internal partial class TransactionQueue<TState>\n        where TState : class, new()\n    {\n        private readonly TransactionalStateOptions options;\n        private readonly ParticipantId resource;\n        private readonly Action deactivate;\n        private readonly ITransactionalStateStorage<TState> storage;\n        private readonly BatchWorker storageWorker;\n        protected readonly ILogger logger;\n        private readonly IActivationLifetime activationLifetime;\n        private readonly ConfirmationWorker<TState> confirmationWorker;\n        private CommitQueue<TState> commitQueue;\n        private Task readyTask;\n\n        protected StorageBatch<TState> storageBatch;\n\n        private int failCounter;\n\n        // collection tasks\n        private readonly Dictionary<DateTime, PreparedMessages> unprocessedPreparedMessages;\n        private class PreparedMessages\n        {\n            public PreparedMessages(TransactionalStatus status)\n            {\n                this.Status = status;\n            }\n            public int Count;\n            public TransactionalStatus Status;\n        }\n\n        private TState stableState;\n        private long stableSequenceNumber;\n        public ReadWriteLock<TState> RWLock { get; }\n        public CausalClock Clock { get; }\n\n        public TransactionQueue(\n            IOptions<TransactionalStateOptions> options,\n            ParticipantId resource,\n            Action deactivate,\n            ITransactionalStateStorage<TState> storage,\n            IClock clock,\n            ILogger logger,\n            ITimerManager timerManager,\n            IActivationLifetime activationLifetime)\n        {\n            this.options = options.Value;\n            this.resource = resource;\n            this.deactivate = deactivate;\n            this.storage = storage;\n            this.Clock = new CausalClock(clock);\n            this.logger = logger;\n            this.activationLifetime = activationLifetime;\n            this.storageWorker = new BatchWorkerFromDelegate(StorageWork, this.activationLifetime.OnDeactivating);\n            this.RWLock = new ReadWriteLock<TState>(options, this, this.storageWorker, logger, activationLifetime);\n            this.confirmationWorker = new ConfirmationWorker<TState>(options, this.resource, this.storageWorker, () => this.storageBatch, this.logger, timerManager, activationLifetime);\n            this.unprocessedPreparedMessages = new Dictionary<DateTime, PreparedMessages>();\n            this.commitQueue = new CommitQueue<TState>();\n            this.readyTask = Task.CompletedTask;\n        }\n\n        public async Task EnqueueCommit(TransactionRecord<TState> record)\n        {\n            try\n            {\n                LogTraceStartTwoPhaseCommit(record.TransactionId, new(record.Timestamp));\n                commitQueue.Add(record);\n\n                // additional actions for each commit type\n                switch (record.Role)\n                {\n                    case CommitRole.ReadOnly:\n                        {\n                            // no extra actions needed\n                            break;\n                        }\n\n                    case CommitRole.LocalCommit:\n                        {\n                            // process prepared messages received ahead of time\n                            if (unprocessedPreparedMessages.TryGetValue(record.Timestamp, out PreparedMessages info))\n                            {\n                                if (info.Status == TransactionalStatus.Ok)\n                                {\n                                    record.WaitCount -= info.Count;\n                                }\n                                else\n                                {\n                                    await AbortCommits(info.Status, commitQueue.Count - 1);\n\n                                    this.RWLock.Notify();\n                                }\n                                unprocessedPreparedMessages.Remove(record.Timestamp);\n                            }\n                            break;\n                        }\n\n                    case CommitRole.RemoteCommit:\n                        {\n\n                            // optimization: can immediately proceed if dependency is implied\n                            bool behindRemoteEntryBySameTM = false;\n                                /* disabled - jbragg - TODO - revisit\n                                commitQueue.Count >= 2\n                                && commitQueue[commitQueue.Count - 2] is TransactionRecord<TState> rce\n                                && rce.Role == CommitRole.RemoteCommit\n                                && rce.TransactionManager.Equals(record.TransactionManager);\n                                */\n\n                            if (record.NumberWrites > 0)\n                            {\n                                this.storageBatch.Prepare(record.SequenceNumber, record.TransactionId, record.Timestamp, record.TransactionManager, record.State);\n                            }\n                            else\n                            {\n                                this.storageBatch.Read(record.Timestamp);\n                            }\n\n                            this.storageBatch.FollowUpAction(() =>\n                            {\n                                LogTracePersisted(record);\n                                record.PrepareIsPersisted = true;\n\n                                if (behindRemoteEntryBySameTM)\n                                {\n                                    LogTraceSendingImmediatePrepared(record);\n                                    // can send prepared message immediately after persisting prepare record\n                                    record.TransactionManager.Reference.AsReference<ITransactionManagerExtension>()\n                                          .Prepared(record.TransactionManager.Name, record.TransactionId, record.Timestamp, this.resource, TransactionalStatus.Ok)\n                                          .Ignore();\n                                    record.LastSent = DateTime.UtcNow;\n                                }\n                            });\n                            break;\n                        }\n\n                    default:\n                        {\n                            LogErrorImpossibleCase(record.Role);\n                            throw new NotSupportedException($\"{record.Role} is not a supported CommitRole.\");\n                        }\n                }\n            }\n            catch (Exception exception)\n            {\n                LogErrorTransactionAbortInternalError(exception);\n                await NotifyOfAbort(record, TransactionalStatus.UnknownException, exception);\n            }\n        }\n\n        public async Task NotifyOfPrepared(Guid transactionId, DateTime timeStamp, TransactionalStatus status)\n        {\n            var pos = commitQueue.Find(transactionId, timeStamp);\n            LogTraceNotifyOfPrepared(transactionId, new(timeStamp), status);\n            if (pos != -1)\n            {\n\n                var localEntry = commitQueue[pos];\n\n                if (localEntry.Role != CommitRole.LocalCommit)\n                {\n                    LogErrorTransactionAbortWrongCommitType();\n                    throw new InvalidOperationException($\"Wrong commit type: {localEntry.Role}\");\n                }\n\n                if (status == TransactionalStatus.Ok)\n                {\n                    localEntry.WaitCount--;\n\n                    storageWorker.Notify();\n                }\n                else\n                {\n                    await AbortCommits(status, pos);\n\n                    this.RWLock.Notify();\n                }\n            }\n            else\n            {\n                // this message has arrived ahead of the commit request - we need to remember it\n                if (!this.unprocessedPreparedMessages.TryGetValue(timeStamp, out PreparedMessages info))\n                {\n                    this.unprocessedPreparedMessages[timeStamp] = info = new PreparedMessages(status);\n                }\n                if (status == TransactionalStatus.Ok)\n                {\n                    info.Count++;\n                }\n                else\n                {\n                    info.Status = status;\n                }\n\n                // TODO fix memory leak if corresponding commit messages never arrive\n            }\n        }\n\n        public async Task NotifyOfPrepare(Guid transactionId, AccessCounter accessCount, DateTime timeStamp, ParticipantId transactionManager)\n        {\n            var locked = await this.RWLock.ValidateLock(transactionId, accessCount);\n            var status = locked.Item1;\n            var record = locked.Item2;\n            var valid = status == TransactionalStatus.Ok;\n\n            record.Timestamp = timeStamp;\n            record.Role = CommitRole.RemoteCommit; // we are not the TM\n            record.TransactionManager = transactionManager;\n            record.LastSent = null;\n            record.PrepareIsPersisted = false;\n\n            if (!valid)\n            {\n                await this.NotifyOfAbort(record, status, exception: null);\n            }\n            else\n            {\n                this.Clock.Merge(record.Timestamp);\n            }\n\n            this.RWLock.Notify();\n        }\n\n        public async Task NotifyOfAbort(TransactionRecord<TState> entry, TransactionalStatus status, Exception exception)\n        {\n            switch (entry.Role)\n            {\n                case CommitRole.NotYetDetermined:\n                    {\n                        // cannot notify anyone. TA will detect broken lock during prepare.\n                        break;\n                    }\n                case CommitRole.RemoteCommit:\n                    {\n                        LogTraceAborting(status, entry);\n\n                        entry.ConfirmationResponsePromise?.TrySetException(new OrleansException($\"Confirm failed: Status {status}\"));\n\n                        if (entry.LastSent.HasValue)\n                            return; // cannot abort anymore if we already sent prepare-ok message\n\n                        LogTraceAbortingViaPrepared(status, entry);\n                        entry.TransactionManager.Reference.AsReference<ITransactionManagerExtension>()\n                             .Prepared(entry.TransactionManager.Name, entry.TransactionId, entry.Timestamp, resource, status)\n                             .Ignore();\n                        break;\n                    }\n                case CommitRole.LocalCommit:\n                    {\n                        LogTraceAborting(status, entry);\n                        try\n                        {\n                            // tell remote participants\n                            await Task.WhenAll(entry.WriteParticipants\n                                .Where(p => !p.Equals(resource))\n                                .Select(p => p.Reference.AsReference<ITransactionalResourceExtension>()\n                                     .Cancel(p.Name, entry.TransactionId, entry.Timestamp, status)));\n                        }\n                        catch(Exception ex)\n                        {\n                            LogWarningFailedToNotifyAllTransactionParticipantsOfCancellation(entry.TransactionId, new(entry.Timestamp), status, ex);\n                        }\n\n                        // reply to transaction agent\n                        if (exception is not null)\n                        {\n                            entry.PromiseForTA.TrySetException(exception);\n                        }\n                        else\n                        {\n                            entry.PromiseForTA.TrySetResult(status);\n                        }\n\n                        break;\n                    }\n                case CommitRole.ReadOnly:\n                    {\n                        LogTraceAborting(status, entry);\n\n                        // reply to transaction agent\n                        if (exception is not null)\n                        {\n                            entry.PromiseForTA.TrySetException(exception);\n                        }\n                        else\n                        {\n                            entry.PromiseForTA.TrySetResult(status);\n                        }\n\n                        break;\n                    }\n                default:\n                    {\n                        LogErrorImpossibleCase(entry.Role);\n                        throw new NotSupportedException($\"{entry.Role} is not a supported CommitRole.\");\n                    }\n            }\n        }\n\n        public async Task NotifyOfPing(Guid transactionId, DateTime timeStamp, ParticipantId resource)\n        {\n            if (this.commitQueue.Find(transactionId, timeStamp) != -1)\n            {\n                // no need to take special action now - the transaction is still\n                // in the commit queue and its status is not yet determined.\n                // confirmation or cancellation will be sent after committing or aborting.\n\n                LogTraceReceivedPingIrrelevant(transactionId);\n                this.storageWorker.Notify(); // just in case the worker fell asleep or something\n            }\n            else\n            {\n                if (!this.confirmationWorker.IsConfirmed(transactionId))\n                {\n                    LogTraceReceivedPingUnknown(transactionId);\n\n                    // we never heard of this transaction - so it must have aborted\n                    await resource.Reference.AsReference<ITransactionalResourceExtension>()\n                            .Cancel(resource.Name, transactionId, timeStamp, TransactionalStatus.PresumedAbort);\n                }\n            }\n        }\n\n        public async Task NotifyOfConfirm(Guid transactionId, DateTime timeStamp)\n        {\n            LogTraceNotifyOfConfirm(transactionId, new(timeStamp));\n\n            // find in queue\n            var pos = commitQueue.Find(transactionId, timeStamp);\n\n            if (pos == -1)\n                return; // must have already been confirmed\n\n            var remoteEntry = commitQueue[pos];\n\n            if (remoteEntry.Role != CommitRole.RemoteCommit)\n            {\n                LogErrorInternalErrorNotifyOfConfirmWrongCommitType();\n                throw new InvalidOperationException($\"Wrong commit type: {remoteEntry.Role}\");\n            }\n\n            // setting this field makes this entry ready for batching\n\n            remoteEntry.ConfirmationResponsePromise = remoteEntry.ConfirmationResponsePromise ?? new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            storageWorker.Notify();\n\n            // now we wait for the batch to finish\n\n            await remoteEntry.ConfirmationResponsePromise.Task;\n        }\n\n        public async Task NotifyOfCancel(Guid transactionId, DateTime timeStamp, TransactionalStatus status)\n        {\n            LogTraceNotifyOfCancel(nameof(NotifyOfCancel), transactionId, new(timeStamp), status);\n            // find in queue\n            var pos = commitQueue.Find(transactionId, timeStamp);\n\n            if (pos == -1)\n                return;\n\n            this.storageBatch.Cancel(commitQueue[pos].SequenceNumber);\n\n            await AbortCommits(status, pos);\n\n            storageWorker.Notify();\n\n            this.RWLock.Notify();\n        }\n\n        /// <summary>\n        /// called on activation, and when recovering from storage conflicts or other exceptions.\n        /// </summary>\n        public async Task NotifyOfRestore()\n        {\n            try\n            {\n                await Ready();\n            }\n            finally\n            {\n                this.readyTask = Restore();\n            }\n            await this.readyTask;\n        }\n\n        /// <summary>\n        /// Ensures queue is ready to process requests.\n        /// </summary>\n        /// <returns></returns>\n        public Task Ready()\n        {\n            if (this.readyTask.Status == TaskStatus.RanToCompletion)\n            {\n                return readyTask;\n            }\n            return ReadyAsync();\n            async Task ReadyAsync()\n            {\n                try\n                {\n                    await readyTask;\n                }\n                catch (Exception exception)\n                {\n                    LogWarningExceptionInTransactionQueue(exception);\n                    await AbortAndRestore(TransactionalStatus.UnknownException, exception);\n                }\n            }\n        }\n\n        private async Task Restore()\n        {\n            TransactionalStorageLoadResponse<TState> loadresponse = await storage.Load();\n\n            this.storageBatch = new StorageBatch<TState>(loadresponse);\n\n            this.stableState = loadresponse.CommittedState;\n            this.stableSequenceNumber = loadresponse.CommittedSequenceId;\n\n            LogDebugLoad(stableSequenceNumber, loadresponse.PendingStates.Count, storageBatch.MetaData.CommitRecords.Count);\n\n            // ensure clock is consistent with loaded state\n            this.Clock.Merge(storageBatch.MetaData.TimeStamp);\n\n            // resume prepared transactions (not TM)\n            foreach (var pr in loadresponse.PendingStates.OrderBy(ps => ps.TimeStamp))\n            {\n                if (pr.SequenceId > loadresponse.CommittedSequenceId && pr.TransactionManager.Reference != null)\n                {\n                    LogDebugRecoverTwoPhaseCommit(pr.TransactionId);\n                    ParticipantId tm = pr.TransactionManager;\n\n                    commitQueue.Add(new TransactionRecord<TState>()\n                    {\n                        Role = CommitRole.RemoteCommit,\n                        TransactionId = Guid.Parse(pr.TransactionId),\n                        Timestamp = pr.TimeStamp,\n                        State = pr.State,\n                        SequenceNumber = pr.SequenceId,\n                        TransactionManager = tm,\n                        PrepareIsPersisted = true,\n                        LastSent = default(DateTime),\n                        ConfirmationResponsePromise = null,\n                        NumberWrites = 1 // was a writing transaction\n                    });\n                    this.stableSequenceNumber = pr.SequenceId;\n                }\n            }\n\n            // resume committed transactions (on TM)\n            foreach (var kvp in storageBatch.MetaData.CommitRecords)\n            {\n                LogDebugRecoverCommitConfirmation(kvp.Key);\n                this.confirmationWorker.Add(kvp.Key, kvp.Value.Timestamp, kvp.Value.WriteParticipants);\n            }\n\n            // check for work\n            this.storageWorker.Notify();\n            this.RWLock.Notify();\n        }\n\n        public void GetMostRecentState(out TState state, out long sequenceNumber)\n        {\n            if (commitQueue.Count == 0)\n            {\n                state = this.stableState;\n                sequenceNumber = this.stableSequenceNumber;\n            }\n            else\n            {\n                var record = commitQueue.Last;\n                state = record.State;\n                sequenceNumber = record.SequenceNumber;\n            }\n        }\n\n        public int BatchableOperationsCount()\n        {\n            int count = 0;\n            int pos = commitQueue.Count - 1;\n            while (pos >= 0 && commitQueue[pos].Batchable)\n            {\n                pos--;\n                count++;\n            }\n            return count;\n        }\n\n        private async Task StorageWork()\n        {\n            // Stop if this activation is stopping/stopped.\n            if (this.activationLifetime.OnDeactivating.IsCancellationRequested) return;\n\n            using (this.activationLifetime.BlockDeactivation())\n            {\n                try\n                {\n                    // count committable entries at the bottom of the commit queue\n                    int committableEntries = 0;\n                    while (committableEntries < commitQueue.Count && commitQueue[committableEntries].ReadyToCommit)\n                    {\n                        committableEntries++;\n                    }\n\n                    // process all committable entries, assembling a storage batch\n                    if (committableEntries > 0)\n                    {\n                        // process all committable entries, adding storage events to the storage batch\n                        CollectEventsForBatch(committableEntries);\n                        LogDebugBatchCommit(committableEntries, commitQueue.Count - committableEntries, new(commitQueue, committableEntries));\n                    }\n                    else\n                    {\n                        // send or re-send messages and detect timeouts\n                        await CheckProgressOfCommitQueue();\n                    }\n\n                    // store the current storage batch, if it is not empty\n                    StorageBatch<TState> batchBeingSentToStorage = null;\n                    if (this.storageBatch.BatchSize > 0)\n                    {\n                        // get the next batch in place so it can be filled while we store the old one\n                        batchBeingSentToStorage = this.storageBatch;\n                        this.storageBatch = new StorageBatch<TState>(batchBeingSentToStorage);\n\n                        try\n                        {\n                            if (await batchBeingSentToStorage.CheckStorePreConditions())\n                            {\n                                // perform the actual store, and record the e-tag\n                                this.storageBatch.ETag = await batchBeingSentToStorage.Store(storage);\n                                failCounter = 0;\n                            }\n                            else\n                            {\n                                LogWarningStorePreConditionsNotMet();\n                                await AbortAndRestore(TransactionalStatus.CommitFailure, exception: null);\n                                return;\n                            }\n                        }\n                        catch (InconsistentStateException exception)\n                        {\n                            LogWarningReloadFromStorageTriggeredByETagMismatch(exception);\n                            await AbortAndRestore(TransactionalStatus.StorageConflict, exception, true);\n                            return;\n                        }\n                        catch (Exception exception)\n                        {\n                            LogWarningStorageExceptionInStorageWorker(exception);\n                            await AbortAndRestore(TransactionalStatus.UnknownException, exception);\n                            return;\n                        }\n                    }\n\n                    if (committableEntries > 0)\n                    {\n                        // update stable state\n                        var lastCommittedEntry = commitQueue[committableEntries - 1];\n                        this.stableState = lastCommittedEntry.State;\n                        this.stableSequenceNumber = lastCommittedEntry.SequenceNumber;\n                        LogTraceStableStateVersion(stableSequenceNumber);\n\n                        // remove committed entries from commit queue\n                        commitQueue.RemoveFromFront(committableEntries);\n                        storageWorker.Notify();  // we have to re-check for work\n                    }\n\n                    if (batchBeingSentToStorage != null)\n                    {\n                        batchBeingSentToStorage.RunFollowUpActions();\n                        storageWorker.Notify();  // we have to re-check for work\n                    }\n                }\n                catch (Exception exception)\n                {\n                    LogWarningExceptionInStorageWorker(failCounter, exception);\n                    await AbortAndRestore(TransactionalStatus.UnknownException, exception);\n                }\n            }\n        }\n\n        private Task AbortAndRestore(TransactionalStatus status, Exception exception, bool force = false)\n        {\n            this.readyTask = Bail(status, exception, force);\n            return this.readyTask;\n        }\n\n        private async Task Bail(TransactionalStatus status, Exception exception, bool force = false)\n        {\n            List<Task> pending = new List<Task>();\n            pending.Add(RWLock.AbortExecutingTransactions(exception));\n            this.RWLock.AbortQueuedTransactions();\n\n            // abort all entries in the commit queue\n            foreach (var entry in commitQueue.Elements)\n            {\n                pending.Add(NotifyOfAbort(entry, status, exception: exception));\n            }\n\n            commitQueue.Clear();\n\n            await Task.WhenAll(pending);\n            if (++failCounter >= 10 || force)\n            {\n                LogDebugStorageWorkerTriggeringGrainDeactivation();\n                this.deactivate();\n            }\n            await this.Restore();\n        }\n\n        private async Task CheckProgressOfCommitQueue()\n        {\n            if (commitQueue.Count > 0)\n            {\n                var bottom = commitQueue[0];\n                var now = DateTime.UtcNow;\n\n                LogTraceCommitQueueSize(commitQueue.Count, bottom);\n                switch (bottom.Role)\n                {\n                    case CommitRole.LocalCommit:\n                        {\n                            // check for timeout periodically\n                            if (bottom.WaitingSince + this.options.PrepareTimeout <= now)\n                            {\n                                await AbortCommits(TransactionalStatus.PrepareTimeout);\n                                this.RWLock.Notify();\n                            }\n                            else\n                            {\n                                storageWorker.Notify(bottom.WaitingSince + this.options.PrepareTimeout);\n                            }\n                            break;\n                        }\n\n                    case CommitRole.RemoteCommit:\n                        {\n                            if (bottom.PrepareIsPersisted && !bottom.LastSent.HasValue)\n                            {\n                                // send PreparedMessage to remote TM\n                                bottom.TransactionManager.Reference.AsReference<ITransactionManagerExtension>()\n                                      .Prepared(bottom.TransactionManager.Name, bottom.TransactionId, bottom.Timestamp, resource, TransactionalStatus.Ok)\n                                      .Ignore();\n\n                                bottom.LastSent = now;\n\n                                LogTraceSentPrepared(bottom);\n\n                                if (bottom.IsReadOnly)\n                                {\n                                    storageWorker.Notify(); // we are ready to batch now\n                                }\n                                else\n                                {\n                                    storageWorker.Notify(bottom.LastSent.Value + this.options.RemoteTransactionPingFrequency);\n                                }\n                            }\n                            else if (!bottom.IsReadOnly && bottom.LastSent.HasValue)\n                            {\n                                // send ping messages periodically to reactivate crashed TMs\n\n                                if (bottom.LastSent + this.options.RemoteTransactionPingFrequency <= now)\n                                {\n                                    LogTraceSentPing(bottom);\n                                    bottom.TransactionManager.Reference.AsReference<ITransactionManagerExtension>()\n                                          .Ping(bottom.TransactionManager.Name, bottom.TransactionId, bottom.Timestamp, resource).Ignore();\n                                    bottom.LastSent = now;\n                                }\n                                storageWorker.Notify(bottom.LastSent.Value + this.options.RemoteTransactionPingFrequency);\n                            }\n\n                            break;\n                        }\n\n                    default:\n                        {\n                            LogErrorImpossibleCase(bottom.Role);\n                            throw new NotSupportedException($\"{bottom.Role} is not a supported CommitRole.\");\n                        }\n                }\n            }\n        }\n\n        private void CollectEventsForBatch(int batchsize)\n        {\n            // collect events for batch\n            for (int i = 0; i < batchsize; i++)\n            {\n                TransactionRecord<TState> entry = commitQueue[i];\n                LogTraceCommitting(entry);\n\n                switch (entry.Role)\n                {\n                    case CommitRole.LocalCommit:\n                        {\n                            OnLocalCommit(entry);\n                            break;\n                        }\n\n                    case CommitRole.RemoteCommit:\n                        {\n                            if (entry.ConfirmationResponsePromise == null)\n                            {\n                                // this is a read-only participant that has sent\n                                // its prepared message.\n                                // So we are really done and need not store or do anything.\n                            }\n                            else\n                            {\n                                // we must confirm in storage, and then respond to TM so it can collect\n                                this.storageBatch.Confirm(entry.SequenceNumber);\n                                this.storageBatch.FollowUpAction(() =>\n                                {\n                                    entry.ConfirmationResponsePromise.TrySetResult(true);\n                                    LogTraceConfirmedRemoteCommit(entry.SequenceNumber, entry.TransactionId, new(entry.Timestamp), entry.TransactionManager);\n                                });\n                            }\n\n                            break;\n                        }\n\n                    case CommitRole.ReadOnly:\n                        {\n                            // we are a participant of a read-only transaction. Must store timestamp and then respond.\n                            this.storageBatch.Read(entry.Timestamp);\n                            this.storageBatch.FollowUpAction(() =>\n                            {\n                                entry.PromiseForTA.TrySetResult(TransactionalStatus.Ok);\n                            });\n\n                            break;\n                        }\n\n                    default:\n                        {\n                            LogErrorImpossibleCase(entry.Role);\n                            throw new NotSupportedException($\"{entry.Role} is not a supported CommitRole.\");\n                        }\n                }\n            }\n        }\n\n        protected virtual void OnLocalCommit(TransactionRecord<TState> entry)\n        {\n            this.storageBatch.Prepare(entry.SequenceNumber, entry.TransactionId, entry.Timestamp, entry.TransactionManager, entry.State);\n            this.storageBatch.Commit(entry.TransactionId, entry.Timestamp, entry.WriteParticipants);\n            this.storageBatch.Confirm(entry.SequenceNumber);\n\n            // after store, send response back to TA\n            this.storageBatch.FollowUpAction(() =>\n            {\n                LogTraceLocallyCommitted(entry.TransactionId, new(entry.Timestamp));\n                entry.PromiseForTA.TrySetResult(TransactionalStatus.Ok);\n            });\n\n            if (entry.WriteParticipants.Count > 1)\n            {\n                // after committing, we need to run a task to confirm and collect\n                this.storageBatch.FollowUpAction(() =>\n                {\n                    LogTraceAddingConfirmationToWorker(entry.TransactionId, new(entry.Timestamp));\n                    this.confirmationWorker.Add(entry.TransactionId, entry.Timestamp, entry.WriteParticipants);\n                });\n            }\n            else\n            {\n                // there are no remote write participants to notify, so we can finish it all in one shot\n                this.storageBatch.Collect(entry.TransactionId);\n            }\n        }\n\n        private async Task AbortCommits(TransactionalStatus status, int from = 0)\n        {\n            List<Task> pending = new List<Task>();\n            // emtpy the back of the commit queue, starting at specified position\n            for (int i = from; i < commitQueue.Count; i++)\n            {\n                pending.Add(NotifyOfAbort(commitQueue[i], i == from ? status : TransactionalStatus.CascadingAbort, exception: null));\n            }\n            commitQueue.RemoveFromBack(commitQueue.Count - from);\n\n            pending.Add(this.RWLock.AbortExecutingTransactions(exception: null));\n            await Task.WhenAll(pending);\n        }\n\n        private readonly struct DateTimeLogRecord(DateTime ts)\n        {\n            public override string ToString() => ts.ToString(\"O\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Start two-phase-commit {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogTraceStartTwoPhaseCommit(Guid transactionId, DateTimeLogRecord timeStamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Persisted {Record}\"\n        )]\n        private partial void LogTracePersisted(TransactionRecord<TState> record);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Sending immediate prepared {Record}\"\n        )]\n        private partial void LogTraceSendingImmediatePrepared(TransactionRecord<TState> record);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            EventId = 777,\n            Message = \"Internal error: impossible case {CommitRole}\"\n        )]\n        private partial void LogErrorImpossibleCase(CommitRole commitRole);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = $\"Transaction abort due to internal error in {nameof(EnqueueCommit)}\"\n        )]\n        private partial void LogErrorTransactionAbortInternalError(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"NotifyOfPrepared - TransactionId:{TransactionId} Timestamp:{Timestamp}, TransactionalStatus{TransactionalStatus}\"\n        )]\n        private partial void LogTraceNotifyOfPrepared(Guid transactionId, DateTimeLogRecord timeStamp, TransactionalStatus transactionalStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = $\"Transaction abort due to internal error in {nameof(NotifyOfPrepared)}: Wrong commit type\"\n        )]\n        private partial void LogErrorTransactionAbortWrongCommitType();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Aborting status={Status} {Entry}\"\n        )]\n        private partial void LogTraceAborting(TransactionalStatus status, TransactionRecord<TState> entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Aborting via Prepared. Status={Status} Entry={Entry}\"\n        )]\n        private partial void LogTraceAbortingViaPrepared(TransactionalStatus status, TransactionRecord<TState> entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Failed to notify all transaction participants of cancellation. TransactionId: {TransactionId}, Timestamp: {Timestamp}, Status: {Status}\"\n        )]\n        private partial void LogWarningFailedToNotifyAllTransactionParticipantsOfCancellation(Guid transactionId, DateTimeLogRecord timeStamp, TransactionalStatus status, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Received ping for {TransactionId}, irrelevant (still processing)\"\n        )]\n        private partial void LogTraceReceivedPingIrrelevant(Guid transactionId);\n\n        //\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Received ping for {TransactionId}, unknown - presumed abort\"\n        )]\n        private partial void LogTraceReceivedPingUnknown(Guid transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"NotifyOfConfirm: {TransactionId} {TimeStamp}\"\n        )]\n        private partial void LogTraceNotifyOfConfirm(Guid transactionId, DateTimeLogRecord timeStamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = $\"Internal error in {nameof(NotifyOfConfirm)}: wrong commit type\"\n        )]\n        private partial void LogErrorInternalErrorNotifyOfConfirmWrongCommitType();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{MethodName}. TransactionId: {TransactionId}, TimeStamp: {TimeStamp} Status: {TransactionalStatus}\"\n        )]\n        private partial void LogTraceNotifyOfCancel(string methodName, Guid transactionId, DateTimeLogRecord timeStamp, TransactionalStatus transactionalStatus);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Exception in TransactionQueue\"\n        )]\n        private partial void LogWarningExceptionInTransactionQueue(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Load v{StableSequenceNumber} {PendingStatesCount}p {CommitRecordsCount}c\"\n        )]\n        private partial void LogDebugLoad(long stableSequenceNumber, int pendingStatesCount, int commitRecordsCount);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Recover two-phase-commit {TransactionId}\"\n        )]\n        private partial void LogDebugRecoverTwoPhaseCommit(string transactionId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Recover commit confirmation {Key}\"\n        )]\n        private partial void LogDebugRecoverCommitConfirmation(Guid key);\n\n        private readonly struct CommitQueueLogRecord(CommitQueue<TState> state, int committableEntries)\n        {\n            public override string ToString() => state.Count > committableEntries ? state[committableEntries].ToString() : \"\";\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"BatchCommit: {CommittableEntries} Leave: {UncommittableEntries}, Record: {Record}\"\n        )]\n        private partial void LogDebugBatchCommit(int committableEntries, int uncommittableEntries, CommitQueueLogRecord record);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Store pre conditions not met.\"\n        )]\n        private partial void LogWarningStorePreConditionsNotMet();\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = 888,\n            Message = \"Reload from storage triggered by e-tag mismatch.\"\n        )]\n        private partial void LogWarningReloadFromStorageTriggeredByETagMismatch(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            Message = \"Storage exception in storage worker.\"\n        )]\n        private partial void LogWarningStorageExceptionInStorageWorker(Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Stable state version: {StableSequenceNumber}\"\n        )]\n        private partial void LogTraceStableStateVersion(long stableSequenceNumber);\n\n        [LoggerMessage(\n            Level = LogLevel.Warning,\n            EventId = 888,\n            Message = \"Exception in storageWorker. Retry {FailCounter}\"\n        )]\n        private partial void LogWarningExceptionInStorageWorker(int failCounter, Exception exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"StorageWorker triggering grain Deactivation\"\n        )]\n        private partial void LogDebugStorageWorkerTriggeringGrainDeactivation();\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"{CommitQueueSize} entries in queue waiting for bottom: {BottomEntry}\"\n        )]\n        private partial void LogTraceCommitQueueSize(int commitQueueSize, TransactionRecord<TState> bottomEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Sent Prepared {BottomEntry}\"\n        )]\n        private partial void LogTraceSentPrepared(TransactionRecord<TState> bottomEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Sent ping {BottomEntry}\"\n        )]\n        private partial void LogTraceSentPing(TransactionRecord<TState> bottomEntry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Committing {Entry}\"\n        )]\n        private partial void LogTraceCommitting(TransactionRecord<TState> entry);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Confirmed remote commit v{SequenceNumber}. TransactionId:{TransactionId} Timestamp:{Timestamp} TransactionManager:{TransactionManager}\"\n        )]\n        private partial void LogTraceConfirmedRemoteCommit(long sequenceNumber, Guid transactionId, DateTimeLogRecord timeStamp, ParticipantId transactionManager);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Locally committed {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogTraceLocallyCommitted(Guid transactionId, DateTimeLogRecord timeStamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"Adding confirmation to worker for {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogTraceAddingConfirmationToWorker(Guid transactionId, DateTimeLogRecord timeStamp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionalResource.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.State\n{\n    internal class TransactionalResource<TState> : ITransactionalResource\n               where TState : class, new()\n    {\n        private readonly TransactionQueue<TState> queue;\n\n        public TransactionalResource(TransactionQueue<TState> queue)\n        {\n            this.queue = queue;\n        }\n\n        public async Task<TransactionalStatus> CommitReadOnly(Guid transactionId, AccessCounter accessCount, DateTime timeStamp)\n        {\n            // validate the lock\n            var (status, record) = await this.queue.RWLock.ValidateLock(transactionId, accessCount);\n            var valid = status == TransactionalStatus.Ok;\n\n            record.Timestamp = timeStamp;\n            record.Role = CommitRole.ReadOnly;\n            record.PromiseForTA = new TaskCompletionSource<TransactionalStatus>(TaskCreationOptions.RunContinuationsAsynchronously);\n\n            if (!valid)\n            {\n                await this.queue.NotifyOfAbort(record, status, exception: null);\n            }\n            else\n            {\n                this.queue.Clock.Merge(record.Timestamp);\n            }\n\n            this.queue.RWLock.Notify();\n            return await record.PromiseForTA.Task;\n        }\n\n        public async Task Abort(Guid transactionId)\n        {\n            await this.queue.Ready();\n            // release the lock\n            this.queue.RWLock.Rollback(transactionId);\n\n            this.queue.RWLock.Notify();\n        }\n\n        public async Task Cancel(Guid transactionId, DateTime timeStamp, TransactionalStatus status)\n        {\n            await this.queue.Ready();\n            await this.queue.NotifyOfCancel(transactionId, timeStamp, status);\n        }\n\n        public async Task Confirm(Guid transactionId, DateTime timeStamp)\n        {\n            await this.queue.Ready();\n            await this.queue.NotifyOfConfirm(transactionId, timeStamp);\n        }\n\n        public async Task Prepare(Guid transactionId, AccessCounter accessCount, DateTime timeStamp, ParticipantId transactionManager)\n        {\n            await this.queue.NotifyOfPrepare(transactionId, accessCount, timeStamp, transactionManager);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionalState.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.State;\nusing Orleans.Configuration;\nusing Orleans.Timers.Internal;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// Stateful facet that respects Orleans transaction semantics\n    /// </summary>\n    public partial class TransactionalState<TState> : ITransactionalState<TState>, ILifecycleParticipant<IGrainLifecycle>\n        where TState : class, new()\n    {\n        private readonly TransactionalStateConfiguration config;\n        private readonly IGrainContext context;\n        private readonly ITransactionDataCopier<TState> copier;\n        private readonly Dictionary<Type,object> copiers;\n        private readonly IGrainRuntime grainRuntime;\n        private readonly ILogger logger;\n        private readonly ActivationLifetime activationLifetime;\n        private ParticipantId participantId;\n        private TransactionQueue<TState> queue;\n\n        public string CurrentTransactionId => TransactionContext.GetRequiredTransactionInfo().Id;\n\n        private bool detectReentrancy;\n\n        public TransactionalState(\n            TransactionalStateConfiguration transactionalStateConfiguration,\n            IGrainContextAccessor contextAccessor,\n            ITransactionDataCopier<TState> copier,\n            IGrainRuntime grainRuntime,\n            ILogger<TransactionalState<TState>> logger)\n        {\n            this.config = transactionalStateConfiguration;\n            this.context = contextAccessor.GrainContext;\n            this.copier = copier;\n            this.grainRuntime = grainRuntime;\n            this.logger = logger;\n            this.copiers = new Dictionary<Type, object>();\n            this.copiers.Add(typeof(TState), copier);\n            this.activationLifetime = new ActivationLifetime(this.context);\n        }\n\n        /// <summary>\n        /// Read the current state.\n        /// </summary>\n        public Task<TResult> PerformRead<TResult>(Func<TState, TResult> operation)\n        {\n            if (detectReentrancy)\n            {\n                throw new LockRecursionException(\"Cannot perform a read operation from within another operation\");\n            }\n\n            var info = TransactionContext.GetRequiredTransactionInfo();\n            LogTraceStartRead(info);\n\n            info.Participants.TryGetValue(this.participantId, out var recordedaccesses);\n\n            // schedule read access to happen under the lock\n            return this.queue.RWLock.EnterLock<TResult>(info.TransactionId, info.Priority, recordedaccesses, true,\n                () =>\n                {\n                    // check if our record is gone because we expired while waiting\n                    if (!this.queue.RWLock.TryGetRecord(info.TransactionId, out TransactionRecord<TState> record))\n                    {\n                        throw new OrleansCascadingAbortException(info.TransactionId.ToString());\n                    }\n\n                    // merge the current clock into the transaction time stamp\n                    record.Timestamp = this.queue.Clock.MergeUtcNow(info.TimeStamp);\n\n                    if (record.State == null)\n                    {\n                        this.queue.GetMostRecentState(out record.State, out record.SequenceNumber);\n                    }\n\n                    LogDebugUpdateLockRead(record.SequenceNumber, record.TransactionId, new(record.Timestamp));\n\n                    // record this read in the transaction info data structure\n                    info.RecordRead(this.participantId, record.Timestamp);\n\n                    // perform the read\n                    TResult result = default;\n                    try\n                    {\n                        detectReentrancy = true;\n\n                        result = CopyResult(operation(record.State));\n                    }\n                    finally\n                    {\n                        LogTraceEndRead(info, result, record.State);\n                        detectReentrancy = false;\n                    }\n\n                    return result;\n                });\n        }\n\n        /// <inheritdoc/>\n        public Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateAction)\n        {\n            if (updateAction == null) throw new ArgumentNullException(nameof(updateAction));\n            if (detectReentrancy)\n            {\n                throw new LockRecursionException(\"Cannot perform an update operation from within another operation\");\n            }\n\n            var info = TransactionContext.GetRequiredTransactionInfo();\n\n            LogTraceStartWrite(info);\n\n            if (info.IsReadOnly)\n            {\n                throw new OrleansReadOnlyViolatedException(info.Id);\n            }\n\n            info.Participants.TryGetValue(this.participantId, out var recordedaccesses);\n\n            return this.queue.RWLock.EnterLock<TResult>(info.TransactionId, info.Priority, recordedaccesses, false,\n                () =>\n                {\n                    // check if we expired while waiting\n                    if (!this.queue.RWLock.TryGetRecord(info.TransactionId, out TransactionRecord<TState> record))\n                    {\n                        throw new OrleansCascadingAbortException(info.TransactionId.ToString());\n                    }\n\n                    // merge the current clock into the transaction time stamp\n                    record.Timestamp = this.queue.Clock.MergeUtcNow(info.TimeStamp);\n\n                    // link to the latest state\n                    if (record.State == null)\n                    {\n                        this.queue.GetMostRecentState(out record.State, out record.SequenceNumber);\n                    }\n\n                    // if this is the first write, make a deep copy of the state\n                    if (!record.HasCopiedState)\n                    {\n                        record.State = this.copier.DeepCopy(record.State);\n                        record.SequenceNumber++;\n                        record.HasCopiedState = true;\n                    }\n\n                    LogDebugUpdateLockWrite(record.SequenceNumber, record.TransactionId, new(record.Timestamp));\n\n                    // record this write in the transaction info data structure\n                    info.RecordWrite(this.participantId, record.Timestamp);\n\n                    // perform the write\n                    try\n                    {\n                        detectReentrancy = true;\n\n                        return CopyResult(updateAction(record.State));\n                    }\n                    finally\n                    {\n                        LogTraceEndWrite(info, record.TransactionId, new(record.Timestamp));\n                        detectReentrancy = false;\n                    }\n                }\n            );\n        }\n\n        public void Participate(IGrainLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<TransactionalState<TState>>(GrainLifecycleStage.SetupState, (ct) => OnSetupState(SetupResourceFactory, ct));\n        }\n\n        private static void SetupResourceFactory(IGrainContext context, string stateName, TransactionQueue<TState> queue)\n        {\n            // Add resources factory to the grain context\n            context.RegisterResourceFactory<ITransactionalResource>(stateName, () => new TransactionalResource<TState>(queue));\n\n            // Add tm factory to the grain context\n            context.RegisterResourceFactory<ITransactionManager>(stateName, () => new TransactionManager<TState>(queue));\n        }\n\n        internal async Task OnSetupState(Action<IGrainContext, string, TransactionQueue<TState>> setupResourceFactory, CancellationToken ct)\n        {\n            if (ct.IsCancellationRequested) return;\n\n            this.participantId = new ParticipantId(this.config.StateName, this.context.GrainReference, this.config.SupportedRoles);\n\n            var storageFactory = this.context.ActivationServices.GetRequiredService<INamedTransactionalStateStorageFactory>();\n            ITransactionalStateStorage<TState> storage = storageFactory.Create<TState>(this.config.StorageName, this.config.StateName);\n\n            // setup transaction processing pipe\n            void deactivate() => grainRuntime.DeactivateOnIdle(context);\n            var options = this.context.ActivationServices.GetRequiredService<IOptions<TransactionalStateOptions>>();\n            var clock = this.context.ActivationServices.GetRequiredService<IClock>();\n            var timerManager = this.context.ActivationServices.GetRequiredService<ITimerManager>();\n            this.queue = new TransactionQueue<TState>(options, this.participantId, deactivate, storage, clock, logger, timerManager, this.activationLifetime);\n\n            setupResourceFactory(this.context, this.config.StateName, queue);\n\n            // recover state\n            await this.queue.NotifyOfRestore();\n        }\n\n        private TResult CopyResult<TResult>(TResult result)\n        {\n            ITransactionDataCopier<TResult> resultCopier;\n            if (!this.copiers.TryGetValue(typeof(TResult), out object cp))\n            {\n                resultCopier = this.context.ActivationServices.GetRequiredService<ITransactionDataCopier<TResult>>();\n                this.copiers.Add(typeof(TResult), resultCopier);\n            }\n            else\n            {\n                resultCopier = (ITransactionDataCopier<TResult>)cp;\n            }\n            return resultCopier.DeepCopy(result);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"StartRead {Info}\"\n        )]\n        private partial void LogTraceStartRead(TransactionInfo info);\n\n        private readonly struct DateTimeLogRecord(DateTime ts)\n        {\n            public override string ToString() => ts.ToString(\"o\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Update-lock read v{SequenceNumber} {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogDebugUpdateLockRead(long sequenceNumber, Guid transactionId, DateTimeLogRecord timestamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"EndRead {Info} {Result} {State}\"\n        )]\n        private partial void LogTraceEndRead(TransactionInfo info, object result, TState state);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"StartWrite {Info}\"\n        )]\n        private partial void LogTraceStartWrite(TransactionInfo info);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Update-lock write v{SequenceNumber} {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogDebugUpdateLockWrite(long sequenceNumber, Guid transactionId, DateTimeLogRecord timestamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"EndWrite {Info} {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogTraceEndWrite(TransactionInfo info, Guid transactionId, DateTimeLogRecord timestamp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionalStateFactory.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionalStateFactory : ITransactionalStateFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n        public TransactionalStateFactory(IGrainContextAccessor contextAccessor)\n        {\n            this.contextAccessor = contextAccessor;\n        }\n\n        public ITransactionalState<TState> Create<TState>(TransactionalStateConfiguration config) where TState : class, new()\n        {\n            var currentContext = this.contextAccessor.GrainContext;\n            TransactionalState<TState> transactionalState = ActivatorUtilities.CreateInstance<TransactionalState<TState>>(currentContext.ActivationServices, config, this.contextAccessor);\n            transactionalState.Participate(currentContext.ObservableLifecycle);\n            return transactionalState;\n        }\n\n        public static JsonSerializerSettings GetJsonSerializerSettings(IServiceProvider serviceProvider)\n        {\n            var serializerSettings = OrleansJsonSerializerSettings.GetDefaultSerializerSettings(serviceProvider);\n            serializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;\n            return serializerSettings;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionalStateOptions.cs",
    "content": "using System;\n\nnamespace Orleans.Configuration\n{\n    public class TransactionalStateOptions\n    {\n        // max time a group can occupy the lock\n        public TimeSpan LockTimeout { get; set; } = DefaultLockTimeout;\n        public static TimeSpan DefaultLockTimeout = TimeSpan.FromSeconds(8);\n\n        // max time the TM will wait for prepare phase to complete\n        public TimeSpan PrepareTimeout { get; set; } = DefaultPrepareTimeout;\n        public static TimeSpan DefaultPrepareTimeout => TimeSpan.FromSeconds(20);\n\n        // max time a transaction will wait for the lock to become available\n        public TimeSpan LockAcquireTimeout { get; set; } = DefaultLockAcquireTimeout;\n        public static TimeSpan DefaultLockAcquireTimeout => TimeSpan.FromSeconds(10);\n\n        public TimeSpan RemoteTransactionPingFrequency { get; set; } = DefaultRemoteTransactionPingFrequency;\n        public static TimeSpan DefaultRemoteTransactionPingFrequency = TimeSpan.FromSeconds(60);\n\n        public TimeSpan ConfirmationRetryDelay { get; set; } = DefaultConfirmationRetryDelay;\n        private static TimeSpan DefaultConfirmationRetryDelay => TimeSpan.FromSeconds(30);\n\n        public static int ConfirmationRetryLimit { get; set; } = DefaultConfirmationRetryLimit;\n        public const int DefaultConfirmationRetryLimit = 3;\n\n        public int MaxLockGroupSize { get; set; } = DefaultMaxLockGroupSize;\n        public const int DefaultMaxLockGroupSize = 20;\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/State/TransactionalStateStorageProviderWrapper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Orleans.Core;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.Transactions.Abstractions;\n\n#nullable enable\nnamespace Orleans.Transactions\n{\n    internal sealed class TransactionalStateStorageProviderWrapper<TState> : ITransactionalStateStorage<TState>\n        where TState : class, new()\n    {\n        private readonly IGrainStorage grainStorage;\n        private readonly IGrainContext context;\n        private readonly string stateName;\n\n        private StateStorageBridge<TransactionalStateRecord<TState>>? stateStorage;\n        [MemberNotNull(nameof(stateStorage))]\n        private StateStorageBridge<TransactionalStateRecord<TState>> StateStorage => stateStorage ??= GetStateStorage();\n\n        public TransactionalStateStorageProviderWrapper(IGrainStorage grainStorage, string stateName, IGrainContext context)\n        {\n            this.grainStorage = grainStorage;\n            this.context = context;\n            this.stateName = stateName;\n        }\n\n        public async Task<TransactionalStorageLoadResponse<TState>> Load()\n        {\n            await this.StateStorage.ReadStateAsync();\n            var state = stateStorage.State;\n            return new TransactionalStorageLoadResponse<TState>(stateStorage.Etag, state.CommittedState, state.CommittedSequenceId, state.Metadata, state.PendingStates);\n        }\n\n        public async Task<string> Store(string expectedETag, TransactionalStateMetaData metadata, List<PendingTransactionState<TState>> statesToPrepare, long? commitUpTo, long? abortAfter)\n        {\n            if (this.StateStorage.Etag != expectedETag)\n                throw new ArgumentException(nameof(expectedETag), \"Etag does not match\");\n            var state = stateStorage.State;\n            state.Metadata = metadata;\n\n            var pendinglist = state.PendingStates;\n\n            // abort\n            if (abortAfter.HasValue && pendinglist.Count != 0)\n            {\n                var pos = pendinglist.FindIndex(t => t.SequenceId > abortAfter.Value);\n                if (pos != -1)\n                {\n                    pendinglist.RemoveRange(pos, pendinglist.Count - pos);\n                }\n            }\n\n            // prepare\n            if (statesToPrepare?.Count > 0)\n            {\n                foreach (var p in statesToPrepare)\n                {\n                    var pos = pendinglist.FindIndex(t => t.SequenceId >= p.SequenceId);\n                    if (pos == -1)\n                    {\n                        pendinglist.Add(p); //append\n                    }\n                    else if (pendinglist[pos].SequenceId == p.SequenceId)\n                    {\n                        pendinglist[pos] = p;  //replace\n                    }\n                    else\n                    {\n                        pendinglist.Insert(pos, p); //insert\n                    }\n                }\n            }\n\n            // commit\n            if (commitUpTo.HasValue && commitUpTo.Value > state.CommittedSequenceId)\n            {\n                var pos = pendinglist.FindIndex(t => t.SequenceId == commitUpTo.Value);\n                if (pos != -1)\n                {\n                    var committedState = pendinglist[pos];\n                    state.CommittedSequenceId = committedState.SequenceId;\n                    state.CommittedState = committedState.State;\n                    pendinglist.RemoveRange(0, pos + 1);\n                }\n                else\n                {\n                    throw new InvalidOperationException($\"Transactional state corrupted. Missing prepare record (SequenceId={commitUpTo.Value}) for committed transaction.\");\n                }\n            }\n\n            await stateStorage.WriteStateAsync();\n            return stateStorage.Etag!;\n        }\n\n        private StateStorageBridge<TransactionalStateRecord<TState>> GetStateStorage()\n        {\n            return new(this.stateName, context, grainStorage);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public sealed class TransactionalStateRecord<TState>\n        where TState : class, new()\n    {\n        [Id(0)]\n        public TState CommittedState { get; set; } = new TState();\n\n        [Id(1)]\n        public long CommittedSequenceId { get; set; }\n\n        [Id(2)]\n        public TransactionalStateMetaData Metadata { get; set; } = new TransactionalStateMetaData();\n\n        [Id(3)]\n        public List<PendingTransactionState<TState>> PendingStates { get; set; } = new List<PendingTransactionState<TState>>();\n    }\n}"
  },
  {
    "path": "src/Orleans.Transactions/TOC/TocTransactionQueue.cs",
    "content": "using System;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Timers.Internal;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.State;\n\nnamespace Orleans.Transactions.TOC\n{\n    internal class TocTransactionQueue<TService> : TransactionQueue<TransactionCommitter<TService>.OperationState>\n                where TService : class\n    {\n        private readonly TService service;\n\n        public TocTransactionQueue(\n            TService service,\n            IOptions<TransactionalStateOptions> options,\n            ParticipantId resource,\n            Action deactivate,\n            ITransactionalStateStorage<TransactionCommitter<TService>.OperationState> storage,\n            IClock clock,\n            ILogger logger,\n            ITimerManager timerManager,\n            IActivationLifetime activationLifetime)\n            : base(options, resource, deactivate, storage, clock, logger, timerManager, activationLifetime)\n        {\n            this.service = service;\n        }\n\n        protected override void OnLocalCommit(TransactionRecord<TransactionCommitter<TService>.OperationState> entry)\n        {\n            base.storageBatch.AddStorePreCondition(() => entry.State.Operation.Commit(entry.TransactionId, this.service));\n            base.OnLocalCommit(entry);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/TOC/TransactionCommitter.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Timers.Internal;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.State;\nusing Orleans.Transactions.TOC;\n\nnamespace Orleans.Transactions\n{\n    public partial class TransactionCommitter<TService> : ITransactionCommitter<TService>, ILifecycleParticipant<IGrainLifecycle>\n        where TService : class\n    {\n        private readonly ITransactionCommitterConfiguration config;\n        private readonly IGrainContext context;\n        private readonly ITransactionDataCopier<OperationState> copier;\n        private readonly IGrainRuntime grainRuntime;\n        private readonly ActivationLifetime activationLifetime;\n        private readonly ILogger logger;\n        private ParticipantId participantId;\n        private TransactionQueue<OperationState> queue;\n\n        private bool detectReentrancy;\n\n        public TransactionCommitter(\n            ITransactionCommitterConfiguration config,\n            IGrainContextAccessor contextAccessor,\n            ITransactionDataCopier<OperationState> copier,\n            IGrainRuntime grainRuntime,\n            ILogger<TransactionCommitter<TService>> logger)\n        {\n            this.config = config;\n            this.context = contextAccessor.GrainContext;\n            this.copier = copier;\n            this.grainRuntime = grainRuntime;\n            this.logger = logger;\n            this.activationLifetime = new ActivationLifetime(this.context);\n        }\n\n        /// <inheritdoc/>\n        public Task OnCommit(ITransactionCommitOperation<TService> operation)\n        {\n            if (operation == null) throw new ArgumentNullException(nameof(operation));\n            if (detectReentrancy)\n            {\n                throw new LockRecursionException(\"cannot perform an update operation from within another operation\");\n            }\n\n            var info = TransactionContext.GetRequiredTransactionInfo();\n\n            LogTraceStartWrite(info);\n            if (info.IsReadOnly)\n            {\n                throw new OrleansReadOnlyViolatedException(info.Id);\n            }\n\n            info.Participants.TryGetValue(this.participantId, out var recordedaccesses);\n\n            return this.queue.RWLock.EnterLock<bool>(info.TransactionId, info.Priority, recordedaccesses, false,\n                () =>\n                {\n                    // check if we expired while waiting\n                    if (!this.queue.RWLock.TryGetRecord(info.TransactionId, out TransactionRecord<OperationState> record))\n                    {\n                        throw new OrleansCascadingAbortException(info.TransactionId.ToString());\n                    }\n\n                    // merge the current clock into the transaction time stamp\n                    record.Timestamp = this.queue.Clock.MergeUtcNow(info.TimeStamp);\n\n                    // link to the latest state\n                    if (record.State == null)\n                    {\n                        this.queue.GetMostRecentState(out record.State, out record.SequenceNumber);\n                    }\n\n                    // if this is the first write, make a deep copy of the state\n                    if (!record.HasCopiedState)\n                    {\n                        record.State = this.copier.DeepCopy(record.State);\n                        record.SequenceNumber++;\n                        record.HasCopiedState = true;\n                    }\n\n                    LogDebugUpdateLockWrite(record.SequenceNumber, record.TransactionId, new(record.Timestamp));\n\n                    // record this write in the transaction info data structure\n                    info.RecordWrite(this.participantId, record.Timestamp);\n\n                    // perform the write\n                    try\n                    {\n                        detectReentrancy = true;\n\n                        record.State.Operation = operation;\n                        return true;\n                    }\n                    finally\n                    {\n                        LogTraceEndWrite(info, record.TransactionId, new(record.Timestamp));\n                        detectReentrancy = false;\n                    }\n                }\n            );\n        }\n\n        public void Participate(IGrainLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<TransactionalState<OperationState>>(GrainLifecycleStage.SetupState, OnSetupState);\n        }\n\n        private async Task OnSetupState(CancellationToken ct)\n        {\n            if (ct.IsCancellationRequested) return;\n\n            this.participantId = new ParticipantId(this.config.ServiceName, this.context.GrainReference, ParticipantId.Role.Resource | ParticipantId.Role.PriorityManager);\n\n            var storageFactory = this.context.ActivationServices.GetRequiredService<INamedTransactionalStateStorageFactory>();\n            ITransactionalStateStorage<OperationState> storage = storageFactory.Create<OperationState>(this.config.StorageName, this.config.ServiceName);\n\n            // setup transaction processing pipe\n            void deactivate() => grainRuntime.DeactivateOnIdle(context);\n            var options = this.context.ActivationServices.GetRequiredService<IOptions<TransactionalStateOptions>>();\n            var clock = this.context.ActivationServices.GetRequiredService<IClock>();\n            TService service = this.context.ActivationServices.GetRequiredKeyedService<TService>(this.config.ServiceName);\n            var timerManager = this.context.ActivationServices.GetRequiredService<ITimerManager>();\n            this.queue = new TocTransactionQueue<TService>(service, options, this.participantId, deactivate, storage, clock, logger, timerManager, this.activationLifetime);\n\n            // Add transaction manager factory to the grain context\n            this.context.RegisterResourceFactory<ITransactionManager>(this.config.ServiceName, () => new TransactionManager<OperationState>(this.queue));\n\n            // recover state\n            await this.queue.NotifyOfRestore();\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public sealed class OperationState\n        {\n            [Id(0)]\n            public ITransactionCommitOperation<TService> Operation { get; set; }\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"StartWrite {Info}\"\n        )]\n        private partial void LogTraceStartWrite(TransactionInfo info);\n\n        private readonly struct DateTimeLogRecord(DateTime ts)\n        {\n            public override string ToString() => ts.ToString(\"o\");\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Update-lock write v{SequenceNumber} {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogDebugUpdateLockWrite(long sequenceNumber, Guid transactionId, DateTimeLogRecord timestamp);\n\n        [LoggerMessage(\n            Level = LogLevel.Trace,\n            Message = \"EndWrite {Info} {TransactionId} {Timestamp}\"\n        )]\n        private partial void LogTraceEndWrite(TransactionInfo info, Guid transactionId, DateTimeLogRecord timestamp);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/TOC/TransactionCommitterFactory.cs",
    "content": "\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions\n{\n    public class TransactionCommitterFactory : ITransactionCommitterFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n\n        public TransactionCommitterFactory(IGrainContextAccessor contextAccessor)\n        {\n            this.contextAccessor = contextAccessor;\n        }\n\n        public ITransactionCommitter<TService> Create<TService>(ITransactionCommitterConfiguration config) where TService : class\n        {\n            var currentContext = contextAccessor.GrainContext;\n            TransactionCommitter<TService> transactionalState = ActivatorUtilities.CreateInstance<TransactionCommitter<TService>>(currentContext.ActivationServices, config, this.contextAccessor);\n            transactionalState.Participate(currentContext.ObservableLifecycle);\n            return transactionalState;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/TransactionAttribute.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Runtime.ExceptionServices;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGeneration;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Transactions;\n\nnamespace Orleans\n{\n    /// <summary>\n    /// The TransactionAttribute attribute is used to mark methods that start and join transactions.\n    /// </summary>\n    [InvokableCustomInitializer(\"SetTransactionOptions\")]\n    [InvokableBaseType(typeof(GrainReference), typeof(ValueTask), typeof(TransactionRequest))]\n    [InvokableBaseType(typeof(GrainReference), typeof(ValueTask<>), typeof(TransactionRequest<>))]\n    [InvokableBaseType(typeof(GrainReference), typeof(Task), typeof(TransactionTaskRequest))]\n    [InvokableBaseType(typeof(GrainReference), typeof(Task<>), typeof(TransactionTaskRequest<>))]\n    [AttributeUsage(AttributeTargets.Method)]\n    public sealed class TransactionAttribute : Attribute\n    {\n        public TransactionAttribute(TransactionOption requirement)\n        {\n            Requirement = requirement;\n        }\n\n        public TransactionAttribute(TransactionOptionAlias alias)\n        {\n            Requirement = (TransactionOption)(int)alias;\n        }\n\n        public TransactionOption Requirement { get; }\n\n        [Obsolete(\"Use [ReadOnly] attribute instead.\")]\n        public bool ReadOnly { get; set; }\n    }\n\n    public enum TransactionOption\n    {\n        Suppress,     // Logic is not transactional but can be called from within a transaction.  If called within the context of a transaction, the context will not be passed to the call.\n        CreateOrJoin, // Logic is transactional.  If called within the context of a transaction, it will use that context, else it will create a new context.\n        Create,       // Logic is transactional and will always create a new transaction context, even if called within an existing transaction context.\n        Join,         // Logic is transactional but can only be called within the context of an existing transaction.\n        Supported,    // Logic is not transactional but supports transactions.  If called within the context of a transaction, the context will be passed to the call.\n        NotAllowed    // Logic is not transactional and cannot be called from within a transaction.  If called within the context of a transaction, it will throw a not supported exception.\n    }\n\n    public enum TransactionOptionAlias\n    {\n        Suppress     = TransactionOption.Supported,\n        Required     = TransactionOption.CreateOrJoin,\n        RequiresNew  = TransactionOption.Create,\n        Mandatory    = TransactionOption.Join,\n        Never        = TransactionOption.NotAllowed,\n    }\n\n    [GenerateSerializer]\n    public abstract class TransactionRequestBase : RequestBase, IOutgoingGrainCallFilter, IOnDeserialized\n    {\n        [NonSerialized]\n        private Serializer<OrleansTransactionAbortedException> _serializer;\n\n        [NonSerialized]\n        private ITransactionAgent _transactionAgent;\n\n        private ITransactionAgent TransactionAgent => _transactionAgent ?? throw new OrleansTransactionsDisabledException();\n\n        [Id(0)]\n        public TransactionOption TransactionOption { get; set; }\n\n        [Id(1)]\n        public TransactionInfo TransactionInfo { get; set; }\n\n        [GeneratedActivatorConstructor]\n        protected TransactionRequestBase(Serializer<OrleansTransactionAbortedException> exceptionSerializer, IServiceProvider serviceProvider)\n        {\n            _serializer = exceptionSerializer;\n\n            // May be null, eg on an external client. We will throw if it's null at the time of invocation.\n            _transactionAgent = serviceProvider.GetService<ITransactionAgent>();\n        }\n\n        public bool IsAmbientTransactionSuppressed => TransactionOption switch\n        {\n            TransactionOption.Create => true,\n            TransactionOption.Suppress => true,\n            _ => false\n        };\n\n        public bool IsTransactionRequired => TransactionOption switch\n        {\n            TransactionOption.Create => true,\n            TransactionOption.CreateOrJoin => true,\n            TransactionOption.Join => true,\n            _ => false\n        };\n\n        protected void SetTransactionOptions(TransactionOptionAlias txOption) => SetTransactionOptions((TransactionOption)txOption);\n\n        protected void SetTransactionOptions(TransactionOption txOption)\n        {\n            this.TransactionOption = txOption;\n        }\n\n        async Task IOutgoingGrainCallFilter.Invoke(IOutgoingGrainCallContext context)\n        {\n            var transactionInfo = SetTransactionInfo();\n            try\n            {\n                await context.Invoke();\n            }\n            finally\n            {\n                if (context.Response is TransactionResponse txResponse)\n                {\n                    var returnedTransactionInfo = txResponse.TransactionInfo;\n\n                    if (transactionInfo is { } && returnedTransactionInfo is { })\n                    {\n                        transactionInfo.Join(returnedTransactionInfo);\n                    }\n\n                    if (txResponse.GetException() is { } exception)\n                    {\n                        ExceptionDispatchInfo.Throw(exception);\n                    }\n                }\n            }\n        }\n\n        private TransactionInfo SetTransactionInfo()\n        {\n            // Clear transaction info if transaction operation requires new transaction.\n            var transactionInfo = TransactionContext.GetTransactionInfo();\n\n            // Enforce join transaction calls\n            if (TransactionOption == TransactionOption.Join && transactionInfo == null)\n            {\n                throw new NotSupportedException(\"Call cannot be made outside of a transaction.\");\n            }\n\n            // Enforce not allowed transaction calls\n            if (TransactionOption == TransactionOption.NotAllowed && transactionInfo != null)\n            {\n                throw new NotSupportedException(\"Call cannot be made within a transaction.\");\n            }\n\n            // Clear transaction context if creating a transaction or transaction is suppressed\n            if (TransactionOption is TransactionOption.Create or TransactionOption.Suppress)\n            {\n                transactionInfo = null;\n            }\n\n            if (transactionInfo == null)\n            {\n                // if we're leaving a transaction context, make sure it's been cleared from the request context.\n                TransactionContext.Clear();\n            }\n            else\n            {\n                this.TransactionInfo = transactionInfo?.Fork();\n            }\n\n            return transactionInfo;\n        }\n\n        public override async ValueTask<Response> Invoke()\n        {\n            Response response;\n            var transactionInfo = this.TransactionInfo;\n            bool startedNewTransaction = false;\n            try\n            {\n                if (IsTransactionRequired && transactionInfo == null)\n                {\n                    // TODO: this should be a configurable parameter\n                    var transactionTimeout = Debugger.IsAttached ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(10);\n\n                    // Start a new transaction\n                    var isReadOnly = this.Options.HasFlag(InvokeMethodOptions.ReadOnly);\n                    transactionInfo = await TransactionAgent.StartTransaction(isReadOnly, transactionTimeout);\n                    startedNewTransaction = true;\n                }\n\n                TransactionContext.SetTransactionInfo(transactionInfo);\n                response = await BaseInvoke();\n            }\n            catch (Exception exception)\n            {\n                response = Response.FromException(exception);\n            }\n            finally\n            {\n                TransactionContext.Clear();\n            }\n\n            if (transactionInfo != null)\n            {\n                transactionInfo.ReconcilePending();\n\n                if (response.Exception is { } invokeException)\n                {\n                    // Record reason for abort, if not already set.\n                    transactionInfo.RecordException(invokeException, _serializer);\n                }\n\n                OrleansTransactionException transactionException = transactionInfo.MustAbort(_serializer);\n\n                // This request started the transaction, so we try to commit before returning,\n                // or if it must abort, tell participants that it aborted\n                if (startedNewTransaction)\n                {\n                    if (transactionException is not null || transactionInfo.TryToCommit is false)\n                    {\n                        await TransactionAgent.Abort(transactionInfo);\n                    }\n                    else\n                    {\n                        var (status, exception) = await TransactionAgent.Resolve(transactionInfo);\n                        if (status != TransactionalStatus.Ok)\n                        {\n                            transactionException = status.ConvertToUserException(transactionInfo.Id, exception);\n                        }\n                    }\n                }\n\n                if (transactionException != null)\n                {\n                    response = Response.FromException(transactionException);\n                }\n\n                response = TransactionResponse.Create(response, transactionInfo);\n            }\n\n            return response;\n        }\n\n        protected abstract ValueTask<Response> BaseInvoke();\n\n        public override void Dispose()\n        {\n           TransactionInfo = null;\n        }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            _serializer = context.ServiceProvider.GetRequiredService<Serializer<OrleansTransactionAbortedException>>();\n            _transactionAgent = context.ServiceProvider.GetRequiredService<ITransactionAgent>();\n        }\n    }\n\n    [GenerateSerializer]\n    public sealed class TransactionResponse : Response\n    {\n        [Id(0)]\n        private Response _response;\n\n        [Id(1)]\n        public TransactionInfo TransactionInfo { get; set; }\n\n        public static TransactionResponse Create(Response response, TransactionInfo transactionInfo)\n        {\n            return new TransactionResponse\n            {\n                _response = response,\n                TransactionInfo = transactionInfo\n            };\n        }\n\n        public Response InnerResponse => _response;\n\n        public override object Result\n        {\n            get\n            {\n                if (_response.Exception is { } exception)\n                {\n                    ExceptionDispatchInfo.Capture(exception).Throw();\n                }\n\n                return _response.Result;\n            }\n\n            set => _response.Result = value;\n        }\n\n        public override Exception Exception\n        {\n            get\n            {\n                // Suppress any exception here, allowing ResponseCompletionSource to complete with a Response instead of an exception.\n                // This gives TransactionRequestBase a chance to inspect this instance and retrieve the TransactionInfo property first.\n                // After, it will use GetException to get and throw the exeption.\n                return null;\n            }\n\n            set => _response.Exception = value;\n        }\n\n        public Exception GetException() => _response.Exception;\n\n        public override void Dispose()\n        {\n            TransactionInfo = null;\n            _response.Dispose();\n        }\n\n        public override T GetResult<T>() => _response.GetResult<T>();\n    }\n\n    [SerializerTransparent]\n    public abstract class TransactionRequest : TransactionRequestBase\n    {\n        protected TransactionRequest(Serializer<OrleansTransactionAbortedException> exceptionSerializer, IServiceProvider serviceProvider) : base(exceptionSerializer, serviceProvider)\n        {\n        }\n\n        protected sealed override ValueTask<Response> BaseInvoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.Completed);\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.Completed;\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract ValueTask InvokeInner();\n    }\n\n    [SerializerTransparent]\n    public abstract class TransactionRequest<TResult> : TransactionRequestBase\n    {\n        protected TransactionRequest(Serializer<OrleansTransactionAbortedException> exceptionSerializer, IServiceProvider serviceProvider) : base(exceptionSerializer, serviceProvider)\n        {\n        }\n\n        protected sealed override ValueTask<Response> BaseInvoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.Result));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract ValueTask<TResult> InvokeInner();\n    }\n\n    [SerializerTransparent]\n    public abstract class TransactionTaskRequest<TResult> : TransactionRequestBase\n    {\n        protected TransactionTaskRequest(Serializer<OrleansTransactionAbortedException> exceptionSerializer, IServiceProvider serviceProvider) : base(exceptionSerializer, serviceProvider)\n        {\n        }\n\n        protected sealed override ValueTask<Response> BaseInvoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                var status = resultTask.Status;\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.GetAwaiter().GetResult()));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract Task<TResult> InvokeInner();\n    }\n\n    [SerializerTransparent]\n    public abstract class TransactionTaskRequest : TransactionRequestBase\n    {\n        protected TransactionTaskRequest(Serializer<OrleansTransactionAbortedException> exceptionSerializer, IServiceProvider serviceProvider) : base(exceptionSerializer, serviceProvider)\n        {\n        }\n\n        protected sealed override ValueTask<Response> BaseInvoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                var status = resultTask.Status;\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.Completed);\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.Completed;\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract Task InvokeInner();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/TransactionContext.cs",
    "content": "using System.Threading;\n\nnamespace Orleans.Transactions\n{\n    public static class TransactionContext\n    {\n        private static readonly AsyncLocal<TransactionInfo> CurrentContext = new();\n\n        public static TransactionInfo GetTransactionInfo() => CurrentContext.Value;\n\n        public static string CurrentTransactionId => GetRequiredTransactionInfo().Id;\n\n        public static TransactionInfo GetRequiredTransactionInfo() => GetTransactionInfo() ?? throw new OrleansTransactionException($\"A transaction context is required for access. Did you forget a [Transaction] attribute?\");\n\n        internal static void SetTransactionInfo(TransactionInfo info)\n        {\n            if (!ReferenceEquals(CurrentContext.Value, info))\n            {\n                CurrentContext.Value = info;\n            }\n        }\n\n        internal static void Clear() => CurrentContext.Value = null;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/TransactionalStatus.cs",
    "content": "\nusing System;\n\nnamespace Orleans.Transactions\n{\n\n    /// <summary>\n    /// Used to propagate information about the status of a transaction. Used for transaction orchestration, for diagnostics, \n    /// and for generating informative user exceptions\n    /// </summary>\n    public enum TransactionalStatus\n    {\n        Ok,\n\n        PrepareTimeout,    // TM could not finish prepare in time\n        CascadingAbort,    // a transaction this transaction depends on aborted\n        BrokenLock,        // a lock was lost due to timeout, wait-die, or failures\n        LockValidationFailed,  // during prepare, recorded accesses did not match\n        ParticipantResponseTimeout, // TA timed out waiting for response from participants of read-only transaction\n        TMResponseTimeout,  // TA timed out waiting for response from TM\n\n        StorageConflict,   // storage was modified by duplicate grain activation\n\n        PresumedAbort,     // TM never heard of this transaction\n\n        UnknownException,  // an unknown exception was caught\n        AssertionFailed,   // an internal assertion was violated\n        CommitFailure,     // Unable to commit transaction\n    }\n\n    public static class TransactionalStatusExtensions\n    {\n        public static bool DefinitelyAborted(this TransactionalStatus status)\n        {\n            switch (status)\n            {\n                case TransactionalStatus.PrepareTimeout:\n                case TransactionalStatus.CascadingAbort:\n                case TransactionalStatus.BrokenLock:\n                case TransactionalStatus.LockValidationFailed:\n                case TransactionalStatus.ParticipantResponseTimeout:\n                case TransactionalStatus.CommitFailure:\n                    return true;\n\n                default:\n                    return false;\n            }\n        }\n\n        public static OrleansTransactionException ConvertToUserException(this TransactionalStatus status, string transactionId, Exception exception)\n        {\n            switch (status)\n            {\n                case TransactionalStatus.PrepareTimeout:\n                    return new OrleansTransactionPrepareTimeoutException(transactionId, exception);\n\n                case TransactionalStatus.CascadingAbort:\n                    return new OrleansCascadingAbortException(transactionId, exception);\n\n                case TransactionalStatus.BrokenLock:\n                    return new OrleansBrokenTransactionLockException(transactionId, \"before prepare\", exception);\n\n                case TransactionalStatus.LockValidationFailed:\n                    return new OrleansBrokenTransactionLockException(transactionId, \"when validating accesses during prepare\", exception);\n\n                case TransactionalStatus.ParticipantResponseTimeout:\n                    return new OrleansTransactionTransientFailureException(transactionId, $\"transaction agent timed out waiting for read-only transaction participant responses ({status})\", exception);\n\n                case TransactionalStatus.TMResponseTimeout:\n                    return new OrleansTransactionInDoubtException(transactionId, $\"transaction agent timed out waiting for read-only transaction participant responses ({status})\", exception);\n\n                case TransactionalStatus.CommitFailure:\n                    return new OrleansTransactionAbortedException(transactionId, $\"Unable to commit transaction ({status})\", exception);\n\n                default:\n                    return new OrleansTransactionInDoubtException(transactionId, $\"failure during transaction commit, status={status}\", exception);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Utilities/CausalClock.cs",
    "content": "\nusing System;\nusing System.Threading;\n\nnamespace Orleans.Transactions\n{\n    public class CausalClock\n    {\n#if NET9_0_OR_GREATER\n        private readonly Lock lockable = new();\n#else\n        private readonly object lockable = new();\n#endif\n        private readonly IClock clock;\n        private long previous;\n\n        public CausalClock(IClock clock)\n        {\n            this.clock = clock ?? throw new ArgumentNullException(nameof(clock));\n        }\n\n        public DateTime UtcNow()\n        {\n            lock (this.lockable)\n            {\n                var ticks = previous = Math.Max(previous + 1, this.clock.UtcNow().Ticks);\n                return new DateTime(ticks, DateTimeKind.Utc);\n            }\n        }\n\n        public DateTime Merge(DateTime timestamp)\n        {\n            lock (this.lockable)\n            {\n                var ticks = previous = Math.Max(previous, timestamp.Ticks);\n                return new DateTime(ticks, DateTimeKind.Utc);\n            }\n        }\n\n        public DateTime MergeUtcNow(DateTime timestamp)\n        {\n            lock (this.lockable)\n            {\n                var ticks = previous = Math.Max(Math.Max(previous + 1, timestamp.Ticks + 1), this.clock.UtcNow().Ticks);\n                return new DateTime(ticks, DateTimeKind.Utc);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Utilities/Clock.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions\n{\n    public class Clock : IClock\n    {\n        public DateTime UtcNow()\n        {\n            return DateTime.UtcNow;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Utilities/CommitQueue.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// A queue data structure that stores transaction records in a circular buffer, sorted by timestamps.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    internal struct CommitQueue<T>\n    {\n        private const int DefaultCapacity = 8;\n        private TransactionRecord<T>[] _buffer;\n        private int _pos;\n\n        public int Count { get; private set; }\n\n        // Indexer to provide read/write access to the file.\n        public readonly TransactionRecord<T> this[int index]\n        {\n            get\n            {\n                if (index < 0 || index > (Count - 1))\n                    throw new ArgumentOutOfRangeException(nameof(index));\n\n                return _buffer[(_pos + index) % _buffer.Length];\n            }\n        }\n\n        public readonly IEnumerable<TransactionRecord<T>> Elements\n        {\n            get\n            {\n                if (_buffer != null)\n                {\n                    for (int i = 0; i < Count; i++)\n                        yield return _buffer[(_pos + i) % _buffer.Length];\n                }\n            }\n        }\n\n        public readonly TransactionRecord<T> First => _buffer[_pos];\n\n        public readonly TransactionRecord<T> Last => _buffer[(_pos + Count - 1) % _buffer.Length];\n\n        public void Add(TransactionRecord<T> entry)\n        {\n            // ensure we have room\n            if (_buffer == null)\n            {\n                _buffer = new TransactionRecord<T>[DefaultCapacity];\n            }\n            else if (Count == _buffer.Length)\n            {\n                var newBuffer = new TransactionRecord<T>[_buffer.Length * 2];\n                Array.Copy(_buffer, _pos, newBuffer, 0, _buffer.Length - _pos);\n                Array.Copy(_buffer, 0, newBuffer, _buffer.Length - _pos, _pos);\n                _buffer = newBuffer;\n                _pos = 0;\n            }\n\n            if (Count > 0 && _buffer[(_pos + Count - 1) % _buffer.Length].Timestamp > entry.Timestamp)\n                throw new ArgumentException($\"elements must be added in timestamp order, but {entry.Timestamp:o} is before {_buffer[(_pos + Count - 1) % _buffer.Length].Timestamp:o}\", nameof(entry));\n\n            // add the element\n            _buffer[(_pos + Count) % _buffer.Length] = entry;\n            Count++;\n        }\n\n        public void Clear()\n        {\n            for (int i = 0; i < Count; i++)\n                _buffer[(_pos + i) % _buffer.Length] = null;\n            Count = 0;\n            _pos = 0;\n        }\n\n        public void RemoveFromFront(int howMany)\n        {\n            if (howMany <= 0)\n            {\n                throw new ArgumentException(\"Value must be greater than zero\", nameof(howMany));\n            }\n\n            if (_buffer == null || howMany > Count)\n            {\n                throw new ArgumentException(\"cannot remove more elements than are in the queue\", nameof(howMany));\n            }\n\n            // clear entries so they can ge GCd\n            for (int i = 0; i < howMany; i++)\n                _buffer[(_pos + i) % _buffer.Length] = null;\n\n            _pos = (_pos + howMany) % _buffer.Length;\n\n            Count -= howMany;\n        }\n\n        public void RemoveFromBack(int howMany)\n        {\n            if (howMany > 0 && (_buffer == null || howMany > Count))\n                throw new ArgumentException(\"cannot remove more elements than are in the queue\", nameof(howMany));\n\n            // clear entries so they can ge GCd\n            for (int i = 0; i < howMany; i++)\n                _buffer[(_pos + Count - i - 1) % _buffer.Length] = null;\n\n            Count -= howMany;\n        }\n\n        public readonly int Find(Guid TransactionId, DateTime key)\n        {\n            // do a binary search\n            int left = 0;\n            int right = Count;\n            while (left < right)\n            {\n                int mid = (left + right) / 2;\n                var record = _buffer[(_pos + mid) % _buffer.Length];\n                if (record.Timestamp < key)\n                {\n                    left = mid + 1;\n                    continue;\n                }\n                else if (record.Timestamp > key)\n                {\n                    right = mid;\n                    continue;\n                }\n                else if (record.TransactionId == TransactionId)\n                {\n                    return mid;\n                }\n                else\n                {\n                    // search to the left\n                    for (int j = mid - 1; j >= left; j--)\n                    {\n                        record = _buffer[(_pos + j) % _buffer.Length];\n                        if (record.TransactionId == TransactionId)\n                            return j;\n                        if (record.Timestamp != key)\n                            break;\n                    }\n                    // search to the right\n                    for (int j = mid + 1; j < right; j++)\n                    {\n                        record = _buffer[(_pos + j) % _buffer.Length];\n                        if (record.TransactionId == TransactionId)\n                            return j;\n                        if (record.Timestamp != key)\n                            break;\n                    }\n                    return NotFound;\n                }\n            }\n\n            return NotFound;\n        }\n\n        private const int NotFound = -1;\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Utilities/IClock.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions\n{\n    /// <summary>\n    /// System clock abstraction\n    /// </summary>\n    public interface IClock\n    {\n        /// <summary>\n        /// Current time in utc\n        /// </summary>\n        /// <returns></returns>\n        DateTime UtcNow();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions/Utilities/PeriodicAction.cs",
    "content": "using System;\n\nnamespace Orleans.Internal.Trasactions\n{\n    internal class PeriodicAction\n    {\n        private readonly Action action;\n        private readonly TimeSpan period;\n        private DateTime nextUtc;\n\n        public PeriodicAction(TimeSpan period, Action action, DateTime? start = null)\n        {\n            this.period = period;\n            this.nextUtc = start ?? DateTime.UtcNow + period;\n            this.action = action;\n        }\n\n        public bool TryAction(DateTime nowUtc)\n        {\n            if (nowUtc < this.nextUtc) return false;\n            this.nextUtc = nowUtc + this.period;\n            this.action();\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Consistency/ConsistencyTestGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Transactions.Abstractions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    [Reentrant]\n    public class ConsistencyTestGrain : Grain, IConsistencyTestGrain\n    {\n        private Random random;\n        private readonly ILogger logger;\n\n        [Serializable]\n        [GenerateSerializer]\n        public class State\n        {\n            [Id(0)]\n            public string WriterTx = ConsistencyTestHarness.InitialTx; // last writer\n            [Id(1)]\n            public int SeqNo;   // 0, 1, 2,...\n        }\n\n        protected ITransactionalState<State> data;\n\n        public ConsistencyTestGrain(\n            [TransactionalState(\"data\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<State> data,\n            ILoggerFactory loggerFactory\n            )\n        {\n            this.data = data;\n            this.logger = loggerFactory.CreateLogger(nameof(ConsistencyTestGrain) + \".graincall\");\n        }\n\n        private int MyNumber => (int)(this.GetPrimaryKeyLong() % ConsistencyTestOptions.MaxGrains);\n\n        private const double RecursionProbability = .1 - .9 * (1.0 / (10 * 40 - 1));\n\n        public async Task<Observation[]> Run(ConsistencyTestOptions options, int depth, string stack, int maxgrain, DateTime stopAfter)\n        {\n            if (random == null)\n                random = new Random(options.RandomSeed* options.NumGrains + MyNumber);\n\n            if (depth < options.MaxDepth && random.NextDouble() < RecursionProbability)\n            {\n                switch (random.Next(2))\n                {\n                    case 0:\n                        return await Recurse(options, depth, stack, random, 10, ! options.AvoidDeadlocks, maxgrain, stopAfter);\n                    case 1:\n                        return await Recurse(options, depth, stack, random, 10, false, maxgrain, stopAfter);\n                    case 2:\n                        return await Recurse(options, depth, stack, random, 3, false, maxgrain, stopAfter);\n                }\n            }\n\n            //if (random.Next(20 + 6 * depth) == 0)\n            //{\n            //    logger.LogTrace($\"g{MyNumber} {data.CurrentTransactionId} {partition}.{iteration} L{depth} UserAbort\");\n            //    throw new UserAbort();\n            //}\n\n            var txhash = stack[..stack.IndexOf(')')].GetHashCode();\n\n            var whethertoreadorwrite =\n                  (options.ReadWrite == ReadWriteDetermination.PerTransaction) ? new Random(options.RandomSeed + txhash)\n                : (options.ReadWrite == ReadWriteDetermination.PerGrain) ? new Random(options.RandomSeed + txhash * 10000 + MyNumber)\n                : random;\n\n            try\n            {\n                switch (whethertoreadorwrite.Next(4))\n                {\n                    case 0:\n                        logger.LogTrace(\"g{MyNumber} {CurrentTransactionId} {Stack} Write\", MyNumber, TransactionContext.CurrentTransactionId, stack);\n                        return await Write();\n                    default:\n                        logger.LogTrace(\n                            \"g{MyNumber} {CurrentTransactionId} {stack} Read\",\n                            MyNumber,\n                            TransactionContext.CurrentTransactionId,\n                            stack);\n                        return await Read();\n                }\n            } catch(Exception e)\n            {\n                logger.LogTrace(\"g{MyNumber} {CurrentTransactionId} {Stack} --> {ExceptionType}\", MyNumber, TransactionContext.CurrentTransactionId, stack, e.GetType().Name);\n                throw;\n            }\n        }\n\n        private Task<Observation[]> Read()\n        {\n            var txid = TransactionContext.CurrentTransactionId;\n            return data.PerformRead((state) =>\n            {\n                return new Observation[] {\n                    new Observation()\n                    {\n                        ExecutingTx = txid,\n                        WriterTx = state.WriterTx,\n                        Grain = MyNumber,\n                        SeqNo = state.SeqNo\n                    }\n                };\n            });\n        }\n\n        private Task<Observation[]> Write()\n        { \n            var txid = TransactionContext.CurrentTransactionId;\n            return data.PerformUpdate((state) =>\n            {\n                var observe = new Observation[2];\n                observe[0] = new Observation()\n                {\n                    ExecutingTx = txid,\n                    WriterTx = state.WriterTx,\n                    Grain = MyNumber,\n                    SeqNo = state.SeqNo\n                };\n                state.WriterTx = txid;\n                state.SeqNo++;\n                observe[1] = new Observation()\n                {\n                    ExecutingTx = txid,\n                    WriterTx = state.WriterTx,\n                    Grain = MyNumber,\n                    SeqNo = state.SeqNo\n                };\n                return observe;\n            });\n        }\n\n        private async Task<Observation[]> Recurse(ConsistencyTestOptions options, int depth, string stack, Random random, int count, bool parallel, int maxgrain, DateTime stopAfter)\n        {\n            logger.LogTrace(\"g{MyNumber} {CurrentTransactionId} {Stack} Recurse {Count} {ParallelOrSequential}\", MyNumber, TransactionContext.CurrentTransactionId, stack, count, (parallel ? \"par\" : \"seq\"));\n            try\n            {\n                int min = options.AvoidDeadlocks ? MyNumber : 0;\n                int max = options.AvoidDeadlocks ? maxgrain : options.NumGrains;\n                var tasks = new List<Task<Observation[]>>();\n                int[] targets = new int[count];\n                for (int i = 0; i < count; i++)\n                    targets[i] = random.Next(min, max);\n                if (options.AvoidDeadlocks)\n                    Array.Sort(targets);\n                for (int i = 0; i < count; i++)\n                {\n                    var randomTarget = GrainFactory.GetGrain<IConsistencyTestGrain>(options.GrainOffset + targets[i]);\n                    var maxgrainfornested = (i < count - 1) ? targets[i + 1] : max;\n                    var task = randomTarget.Run(options, depth + 1, $\"{stack}.{(parallel ? 'P' : 'S')}{i}\", maxgrainfornested, stopAfter);\n                    tasks.Add(task);\n                    if (!parallel)\n                        await task;\n                    if (DateTime.UtcNow > stopAfter)\n                        break;\n                }\n                await Task.WhenAll(tasks);\n                var result = new HashSet<Observation>();\n                for (int i = 0; i < count; i++)\n                {\n                    foreach (var x in tasks[i].Result)\n                        result.Add(x);\n                }\n                return result.ToArray();\n            }\n            catch (Exception e)\n            {\n                logger.LogTrace(\n                    \"g{MyNumber} {CurrentTransactionId} {Stack} --> {ExceptionType}\",\n                    MyNumber,\n                    TransactionContext.CurrentTransactionId,\n                    stack,\n                    e.GetType().Name);\n                throw;\n            }\n        }\n    } \n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Consistency/ConsistencyTestHarness.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.TestingHost;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    public class ConsistencyTestHarness\n    {\n        private readonly ConsistencyTestOptions options;\n        private Action<string> output;\n\n        private readonly Dictionary<int,       // Grain\n                          SortedDictionary<int, // SeqNo\n                          Dictionary<string,    // WriterTx\n                          HashSet<string>>>>    // ReaderTx\n            tuples;\n\n        private readonly HashSet<string> succeeded;\n        private readonly HashSet<string> aborted;\n        private readonly Dictionary<string, string> indoubt;\n        private bool timeoutsOccurred;\n        private readonly bool tolerateUnknownExceptions;\n        private readonly IGrainFactory grainFactory;\n\n        private readonly Dictionary<string, HashSet<string>> orderEdges = new Dictionary<string, HashSet<string>>();\n        private readonly Dictionary<string, bool> marks = new Dictionary<string, bool>();\n\n\n        public ConsistencyTestHarness(\n            IGrainFactory grainFactory,\n            int numGrains,\n            int seed,\n            bool avoidDeadlocks,\n            bool avoidTimeouts,\n            ReadWriteDetermination readWrite,\n            bool tolerateUnknownExceptions)\n        {\n            this.grainFactory = grainFactory;\n\n            numGrains.Should().BeLessThan(ConsistencyTestOptions.MaxGrains);\n            this.options = new ConsistencyTestOptions()\n            {\n                AvoidDeadlocks = avoidDeadlocks,\n                ReadWrite = readWrite,\n                MaxDepth = 5,\n                NumGrains = numGrains,\n                RandomSeed = seed,\n                AvoidTimeouts = avoidTimeouts,\n                GrainOffset = (DateTime.UtcNow.Ticks & 0xFFFFFFFF) * ConsistencyTestOptions.MaxGrains,\n            };\n\n            this.tuples = new Dictionary<int, SortedDictionary<int, Dictionary<string, HashSet<string>>>>();\n            this.succeeded = new HashSet<string>();\n            this.aborted = new HashSet<string>();\n            this.indoubt = new Dictionary<string, string>();\n\n            // determine what to check for in the end\n            this.tolerateUnknownExceptions = tolerateUnknownExceptions;\n        }\n\n        public const string InitialTx = \"initial\";\n\n        public int NumAborted => aborted.Count;\n\n        public async Task RunRandomTransactionSequence(int partition, int count, IGrainFactory grainFactory, Action<string> output)\n        {\n            this.output = output;\n            var localRandom = new Random(options.RandomSeed + partition);\n\n            for (int i = 0; i < count; i++)\n            {\n                var target = localRandom.Next(options.NumGrains);\n                output($\"({partition},{i}) g{target}\");\n\n                try\n                {\n                    var targetgrain = grainFactory.GetGrain<IConsistencyTestGrain>(options.GrainOffset + target);\n                    var stopAfter = options.AvoidTimeouts ? DateTime.UtcNow + TimeSpan.FromSeconds(22) : DateTime.MaxValue;\n                    var result = await targetgrain.Run(options, 0, $\"({partition},{i})\", options.NumGrains, stopAfter);\n\n                    if (result.Length > 0)\n                    {\n                        var id = result[0].ExecutingTx;\n\n                        lock (succeeded)\n                            succeeded.Add(id);                           \n\n                        output($\"{partition}.{i} g{target} -> {result.Length} tuples\");\n\n                        foreach (var tuple in result)\n                        {\n                            tuple.ExecutingTx.Should().BeEquivalentTo(id); // all effects of this transaction must have same id\n                            lock (tuples)\n                            {\n                                if (!tuples.TryGetValue(tuple.Grain, out var versions))\n                                {\n                                    tuples.Add(tuple.Grain, versions = new SortedDictionary<int, Dictionary<string, HashSet<string>>>());\n                                }\n                                if (!versions.TryGetValue(tuple.SeqNo, out var writers))\n                                {\n                                    versions.Add(tuple.SeqNo, writers = new Dictionary<string, HashSet<string>>());\n                                }\n                                if (!writers.TryGetValue(tuple.WriterTx, out var readers))\n                                {\n                                    writers.Add(tuple.WriterTx, readers = new HashSet<string>());\n                                }\n                                readers.Add(tuple.ExecutingTx);\n                            }\n                        }\n                    }\n\n                }\n                catch (OrleansTransactionAbortedException e)\n                {\n                    output($\"{partition}.{i} g{target} -> aborted {e.GetType().Name} {e.InnerException} {e.TransactionId}\");\n                    lock (aborted)\n                        aborted.Add(e.TransactionId);\n                }\n                catch (OrleansTransactionInDoubtException f)\n                {\n                    output($\"{partition}.{i} g{target} -> in doubt {f.TransactionId}\");\n                    lock (indoubt)\n                        indoubt.Add(f.TransactionId, f.Message);\n                }\n                catch (System.TimeoutException)\n                {\n                    output($\"{partition}.{i} g{target} -> timeout\");\n                    timeoutsOccurred = true;\n                }\n                catch (OrleansException o)\n                {\n                    if (o.InnerException is RandomlyInjectedStorageException)\n                        output($\"{partition}.{i} g{target} -> injected fault\");\n                    else\n                        throw;\n                }\n            }\n        }\n\n        public void CheckConsistency(bool tolerateGenericTimeouts = false, bool tolerateUnknownExceptions = false)\n        {\n            foreach (var grainKvp in tuples)\n            {\n                var pos = 0;\n                void fail(string msg)\n                {\n                    foreach (var kvp1 in grainKvp.Value)\n                        foreach (var kvp2 in kvp1.Value)\n                            foreach (var r in kvp2.Value)\n                                output($\"g{grainKvp.Key} v{kvp1.Key} w:{kvp2.Key} a:{r}\");\n                    true.Should().BeFalse(msg);\n                }\n\n                HashSet<string> readersOfPreviousVersion = new HashSet<string>();\n                \n                foreach (var seqnoKvp in grainKvp.Value)\n                {\n                    var seqno = seqnoKvp.Key;\n\n                    if (pos++ != seqno && indoubt.Count == 0 && !timeoutsOccurred)\n                        fail($\"g{grainKvp.Key} is missing version v{pos - 1}, found v{seqno} instead\");\n\n                    var writers = seqnoKvp.Value;\n                    if (writers.Count != 1)\n                        fail($\"g{grainKvp.Key} v{seqno} has multiple writers {string.Join(\",\", writers.Keys)}\");\n\n                    var writer = writers.First().Key;\n                    var readers = writers.First().Value;\n \n                    if (seqno == 0)\n                    {\n                        if (writer != InitialTx)\n                            fail($\"g{grainKvp.Key} v{seqno} not written by {InitialTx}\");\n                    }\n                    else\n                    {\n                        if (aborted.Contains(writer))\n                            fail($\"g{grainKvp.Key} v{seqno} written by aborted transaction {writer}\");\n                        if (!timeoutsOccurred && !(succeeded.Contains(writer) || indoubt.ContainsKey(writer)))\n                            fail($\"g{grainKvp.Key} v{seqno} written by unknown transaction {writer}\");\n                        if (indoubt.Count == 0 && !timeoutsOccurred && !readers.Contains(writer))\n                            fail($\"g{grainKvp.Key} v{seqno} writer {writer} missing\");\n                    }\n\n                    // add edges from previous readers to this write\n                    foreach (var r in readersOfPreviousVersion)\n                        if (r != writer)\n                        {\n                            if (!orderEdges.TryGetValue(r, out var readedges))\n                                orderEdges[r] = readedges = new HashSet<string>();\n                            readedges.Add(writer);\n                        }\n\n                    if (!orderEdges.TryGetValue(writer, out var writeedges))\n                        orderEdges[writer] = writeedges = new HashSet<string>();\n\n                    foreach (var r in readers)\n                        if (r != writer)\n                        {\n                            if (!succeeded.Contains(r))\n                                fail($\"g{grainKvp.Key} v{seqno} read by aborted transaction {r}\");\n                            writeedges.Add(r);\n                        }\n\n                    readersOfPreviousVersion = readers;\n                }\n            }\n\n            // due a DFS to find cycles in the ordered-before graph (= violation of serializability)\n            DFS();             \n\n            // report unknown exceptions\n            if (!tolerateUnknownExceptions)\n            foreach (var kvp in indoubt)\n                if (kvp.Value.Contains(\"failure during transaction commit\"))\n                    true.Should().BeFalse($\"exception during commit {kvp.Key} {kvp.Value}\");\n\n            // report timeout exceptions          \n            if (!tolerateGenericTimeouts && timeoutsOccurred)\n                true.Should().BeFalse($\"generic timeout exception caught\");\n        }\n\n\n        private void DFS()\n        {\n            foreach (var kvp in orderEdges)\n                if (!marks.ContainsKey(kvp.Key))\n                {\n                    var cycleFound = Visit(kvp.Key, kvp.Value);\n                    cycleFound.Should().BeFalse($\"found serializability violation\");\n                }\n        }\n\n        private bool Visit(string node, HashSet<string> edges)\n        {\n            if (marks.TryGetValue(node, out var mark))\n            {\n                if (mark)\n                {\n                    return false;\n                }\n                else\n                {\n                    output($\"!!! CYCLE FOUND:\");\n                    output($\"{node}\");\n                    return true;\n                }\n            }\n            else\n            {\n                marks[node] = false;\n                foreach (var n in edges)\n                    if (orderEdges.TryGetValue(n, out var edges2))\n                    {\n                        if (Visit(n, edges2))\n                        {\n                            output($\"{node}\");\n                            return true;\n                        }\n                    }\n                marks[node] = true;\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Consistency/ConsistencyTestOptions.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class ConsistencyTestOptions\n    {\n        [Id(0)]\n        public int RandomSeed { get; set; } = 0;\n        [Id(1)]\n        public int NumGrains { get; set; } = 50;\n        [Id(2)]\n        public int MaxDepth { get; set; } = 5;\n        [Id(3)]\n        public bool AvoidDeadlocks { get; set; } = true;\n        [Id(4)]\n        public bool AvoidTimeouts { get; set; } = true;\n        [Id(5)]\n        public ReadWriteDetermination ReadWrite { get; set; } = ReadWriteDetermination.PerGrain;\n        [Id(6)]\n        public long GrainOffset { get; set; }\n\n        public const int MaxGrains = 100000;\n    }\n\n    public enum ReadWriteDetermination\n    {\n        PerTransaction, PerGrain, PerAccess\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Consistency/IConsistencyTestGrain.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    public interface IConsistencyTestGrain : IGrainWithIntegerKey\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<Observation[]> Run(ConsistencyTestOptions options, int depth, string stack, int max, DateTime stopAfter);\n    }\n\n\n    [Serializable]\n    [GenerateSerializer]\n    public class UserAbort : Exception\n    {\n        public UserAbort() : base(\"User aborted transaction\") { }\n\n        [Obsolete]\n        protected UserAbort(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Consistency/Observation.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    [Serializable]\n    [GenerateSerializer]\n    public struct Observation\n    {\n        [Id(0)]\n        public int Grain { get; set; }\n        [Id(1)]\n        public int SeqNo { get; set; }\n        [Id(2)]\n        public string WriterTx { get; set; }\n        [Id(3)]\n        public string ExecutingTx { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/FaultInjectionAzureTableTransactionStateStorage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.AzureStorage;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class FaultInjectionAzureTableTransactionStateStorage<TState> : ITransactionalStateStorage<TState>\n        where TState : class, new()\n    {\n        private readonly AzureTableTransactionalStateStorage<TState> stateStorage;\n        private readonly ITransactionFaultInjector faultInjector;\n        public FaultInjectionAzureTableTransactionStateStorage(ITransactionFaultInjector faultInjector,\n            AzureTableTransactionalStateStorage<TState> azureStateStorage)\n        {\n            this.faultInjector = faultInjector;\n            this.stateStorage = azureStateStorage;\n        }\n\n        public Task<TransactionalStorageLoadResponse<TState>> Load()\n        {\n            return this.stateStorage.Load();\n        }\n\n        public async Task<string> Store(\n\n            string expectedETag,\n            TransactionalStateMetaData metadata,\n\n            // a list of transactions to prepare.\n            List<PendingTransactionState<TState>> statesToPrepare,\n\n            // if non-null, commit all pending transaction up to and including this sequence number.\n            long? commitUpTo,\n\n            // if non-null, abort all pending transactions with sequence numbers strictly larger than this one.\n            long? abortAfter\n        )\n        {\n            faultInjector.BeforeStore();\n            var result = await this.stateStorage.Store(expectedETag, metadata, statesToPrepare, commitUpTo, abortAfter);\n            faultInjector.AfterStore();\n            return result;\n        }\n    }\n\n    public class FaultInjectionAzureTableTransactionStateStorageFactory : ITransactionalStateStorageFactory,\n        ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly AzureTableTransactionalStateStorageFactory factory;\n\n        public static ITransactionalStateStorageFactory Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<AzureTableTransactionalStateOptions>>();\n            var azureFactory = ActivatorUtilities.CreateInstance<AzureTableTransactionalStateStorageFactory>(services, name, optionsMonitor.Get(name));\n            return new FaultInjectionAzureTableTransactionStateStorageFactory(azureFactory);\n        }\n\n        public FaultInjectionAzureTableTransactionStateStorageFactory(\n            AzureTableTransactionalStateStorageFactory factory)\n        {\n            this.factory = factory;\n        }\n\n        public ITransactionalStateStorage<TState> Create<TState>(string stateName, IGrainContext context) where TState : class, new()\n        {\n            var azureStateStorage = this.factory.Create<TState>(stateName, context);\n            return ActivatorUtilities.CreateInstance<FaultInjectionAzureTableTransactionStateStorage<TState>>(\n                context.ActivationServices, azureStateStorage);\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            this.factory.Participate(lifecycle);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/FaultInjectionTransactionCoordinatorGrain.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface IFaultInjectionTransactionCoordinatorGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainSet(List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainAddAndFaultInjection(List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd, \n            FaultInjectionControl faultInjection = null);\n    }\n    public class FaultInjectionTransactionCoordinatorGrain : Grain, IFaultInjectionTransactionCoordinatorGrain\n    {\n        public Task MultiGrainSet(List<IFaultInjectionTransactionTestGrain> grains, int newValue)\n        {\n            return Task.WhenAll(grains.Select(g => g.Set(newValue)));\n        }\n\n        public Task MultiGrainAddAndFaultInjection(List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd,\n            FaultInjectionControl faultInjection = null)\n        {\n            return Task.WhenAll(grains.Select(g => g.Add(numberToAdd, faultInjection)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/FaultInjectionTransactionReource.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.State;\n\nnamespace Orleans.Transactions.TestKit\n{\n    internal class FaultInjectionTransactionManager<TState> : ITransactionManager\n        where TState : class, new()\n    {\n        private readonly TransactionManager<TState> tm;\n        private readonly IGrainRuntime grainRuntime;\n        private readonly IGrainContext context;\n        private readonly FaultInjectionControl faultInjectionControl;\n        private readonly ILogger logger;\n        private readonly IControlledTransactionFaultInjector faultInjector;\n        public FaultInjectionTransactionManager(IControlledTransactionFaultInjector faultInjector, FaultInjectionControl faultInjectionControl, TransactionManager<TState> tm, IGrainContext activationContext, ILogger logger, IGrainRuntime grainRuntime)\n        {\n            this.grainRuntime = grainRuntime;\n            this.tm = tm;\n            this.faultInjectionControl = faultInjectionControl;\n            this.logger = logger;\n            this.context = activationContext;\n            this.faultInjector = faultInjector;\n        }\n\n        public async Task<TransactionalStatus> PrepareAndCommit(Guid transactionId, AccessCounter accessCount, DateTime timeStamp, List<ParticipantId> writeParticipants, int totalParticipants)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} started PrepareAndCommit transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.BeforePrepareAndCommit)\n            {\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionBeforeStore)\n                    this.faultInjector.InjectBeforeStore = true;\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionAfterStore)\n                    this.faultInjector.InjectAfterStore = true;\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} injected fault before transaction {TransactionId} PrepareAndCommit, with fault type {FaultInjectionType}\",\n                    faultInjectionControl.FaultInjectionType,\n                    context.GrainInstance,\n                    transactionId);\n            }\n            var result = await this.tm.PrepareAndCommit(transactionId, accessCount, timeStamp, writeParticipants, totalParticipants);\n            if (this.faultInjectionControl?.FaultInjectionPhase == TransactionFaultInjectPhase.AfterPrepareAndCommit && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} PrepareAndCommit\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n            return result;\n        }\n\n        public async Task Prepared(Guid transactionId, DateTime timeStamp, ParticipantId participant, TransactionalStatus status)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} started Prepared transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n            await this.tm.Prepared(transactionId, timeStamp, participant, status);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterPrepared\n                && this.faultInjectionControl?.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} Prepared\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n\n        public async Task Ping(Guid transactionId, DateTime timeStamp, ParticipantId participant)\n        {\n            this.logger.LogInformation(\"Grain {GrainInstance} started Ping transaction {TransactionId}\", context.GrainInstance, transactionId);\n            await this.tm.Ping(transactionId, timeStamp, participant);\n            if (this.faultInjectionControl?.FaultInjectionPhase == TransactionFaultInjectPhase.AfterPing\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} Ping\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n\n    }\n\n    internal class FaultInjectionTransactionalResource<TState> : ITransactionalResource\n        where TState : class, new()\n    {\n\n        private readonly IGrainRuntime grainRuntime;\n        private readonly IGrainContext context;\n        private readonly FaultInjectionControl faultInjectionControl;\n        private readonly TransactionalResource<TState> tResource;\n        private readonly IControlledTransactionFaultInjector faultInjector;\n        private readonly ILogger logger;\n        public FaultInjectionTransactionalResource(IControlledTransactionFaultInjector faultInjector, FaultInjectionControl faultInjectionControl, \n            TransactionalResource<TState> tResource, IGrainContext activationContext, ILogger logger, IGrainRuntime grainRuntime)\n        {\n            this.grainRuntime = grainRuntime;\n            this.tResource = tResource;\n            this.faultInjectionControl = faultInjectionControl;\n            this.logger = logger;\n            this.faultInjector = faultInjector;\n            this.context = activationContext;\n        }\n\n        public async Task<TransactionalStatus> CommitReadOnly(Guid transactionId, AccessCounter accessCount, DateTime timeStamp)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} started CommitReadOnly transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n            var result = await this.tResource.CommitReadOnly(transactionId, accessCount, timeStamp);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterCommitReadOnly\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} CommitReadOnly\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n\n            this.faultInjectionControl.Reset();\n            return result;\n        }\n\n        public async Task Abort(Guid transactionId)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} aborting transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n            await this.tResource.Abort(transactionId);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterAbort\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} abort\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n\n        public async Task Cancel(Guid transactionId, DateTime timeStamp, TransactionalStatus status)\n        {\n            this.logger.LogInformation(\"Grain {GrainInstance} canceling transaction {TransactionId}\", context.GrainInstance, transactionId);\n            await this.tResource.Cancel(transactionId, timeStamp, status);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterCancel\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} cancel\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n\n        public async Task Confirm(Guid transactionId, DateTime timeStamp)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} started Confirm transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n            if (this.faultInjectionControl?.FaultInjectionPhase == TransactionFaultInjectPhase.BeforeConfirm)\n            {\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionBeforeStore)\n                    this.faultInjector.InjectBeforeStore = true;\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionAfterStore)\n                    this.faultInjector.InjectAfterStore = true;\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} injected fault before transaction {TransactionId} Confirm, with fault type {FaultInjectionType}\",\n                    faultInjectionControl.FaultInjectionType,\n                    context.GrainInstance,\n                    transactionId);\n            }\n            await this.tResource.Confirm(transactionId, timeStamp);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterConfirm\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} deactivating after transaction {TransactionId} Confirm\",\n                    context.GrainInstance,\n                    transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n\n        public async Task Prepare(Guid transactionId, AccessCounter accessCount, DateTime timeStamp, ParticipantId transactionManager)\n        {\n            this.logger.LogInformation(\n                \"Grain {GrainInstance} started Prepare transaction {TransactionId}\",\n                context.GrainInstance,\n                transactionId);\n\n            if (this.faultInjectionControl?.FaultInjectionPhase == TransactionFaultInjectPhase.BeforePrepare)\n            {\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionBeforeStore)\n                    this.faultInjector.InjectBeforeStore = true;\n                if (this.faultInjectionControl.FaultInjectionType == FaultInjectionType.ExceptionAfterStore)\n                    this.faultInjector.InjectAfterStore = true;\n                this.logger.LogInformation(\n                    \"Grain {GrainInstance} injected fault before transaction {TransactionId} Prepare, with fault type {FaultInjectionType}\",\n                    this.context.GrainInstance,\n                    transactionId,\n                    faultInjectionControl.FaultInjectionType);\n            }\n\n            await this.tResource.Prepare(transactionId, accessCount, timeStamp, transactionManager);\n            if (this.faultInjectionControl.FaultInjectionPhase == TransactionFaultInjectPhase.AfterPrepare\n                && this.faultInjectionControl.FaultInjectionType == FaultInjectionType.Deactivation)\n            {\n                this.grainRuntime.DeactivateOnIdle(context);\n                this.logger.LogInformation(\"Grain {GrainInstance} deactivating after transaction {TransactionId} Prepare\", this.context.GrainInstance, transactionId);\n            }\n            this.faultInjectionControl.Reset();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/FaultInjectionTransactionState.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.State;\n\nnamespace Orleans.Transactions.TestKit\n{\n    [GenerateSerializer]\n    public class FaultInjectionControl\n    {\n        [Id(0)]\n        public TransactionFaultInjectPhase FaultInjectionPhase = TransactionFaultInjectPhase.None;\n\n        [Id(1)]\n        public FaultInjectionType FaultInjectionType = FaultInjectionType.None;\n\n        public void Reset()\n        {\n            this.FaultInjectionType = FaultInjectionType.None;\n            this.FaultInjectionPhase = TransactionFaultInjectPhase.None;\n        }\n    }\n\n    [GenerateSerializer]\n    public enum TransactionFaultInjectPhase\n    {\n        None,\n        //deactivation injection phase\n        AfterCommitReadOnly,\n        AfterPrepare,\n        AfterPrepareAndCommit,\n        AfterAbort,\n        AfterPrepared,\n        AfterCancel,\n        AfterConfirm,\n        AfterPing,\n\n        //storage exception injection phase\n        BeforeConfirm,\n        BeforePrepare,\n        BeforePrepareAndCommit\n    }\n\n    public enum FaultInjectionType\n    {\n        None, \n        Deactivation,\n        ExceptionBeforeStore,\n        ExceptionAfterStore\n    }\n\n    public interface IFaultInjectionTransactionalState<TState> : ITransactionalState<TState> where TState : class, new()\n    {\n        FaultInjectionControl FaultInjectionControl { get; set; }\n    }\n\n    internal class FaultInjectionTransactionalState<TState> : IFaultInjectionTransactionalState<TState>, ILifecycleParticipant<IGrainLifecycle>\n        where TState : class, new()\n    {\n        private readonly IGrainRuntime grainRuntime;\n        private readonly TransactionalState<TState> txState;\n        private readonly ILogger logger;\n        public FaultInjectionControl FaultInjectionControl { get; set; }\n        private readonly IControlledTransactionFaultInjector faultInjector;\n        public string CurrentTransactionId => this.txState.CurrentTransactionId;\n        public FaultInjectionTransactionalState(TransactionalState<TState> txState, IControlledTransactionFaultInjector faultInjector, IGrainRuntime grainRuntime, ILogger<FaultInjectionTransactionalState<TState>> logger)\n        {\n            this.grainRuntime = grainRuntime;\n            this.txState = txState;\n            this.logger = logger;\n            this.FaultInjectionControl = new FaultInjectionControl();\n            this.faultInjector = faultInjector;\n        }\n\n        public void Participate(IGrainLifecycle lifecycle)\n        {\n            lifecycle.Subscribe<FaultInjectionTransactionalState<TState>>(GrainLifecycleStage.SetupState,\n                (ct) => this.txState.OnSetupState(this.SetupResourceFactory, ct));\n        }\n\n        internal void SetupResourceFactory(IGrainContext context, string stateName, TransactionQueue<TState> queue)\n        {\n            // Add resources factory to the grain context\n            context.RegisterResourceFactory<ITransactionalResource>(stateName, () => new FaultInjectionTransactionalResource<TState>(this.faultInjector, FaultInjectionControl, new TransactionalResource<TState>(queue), context, logger,  grainRuntime));\n\n            // Add tm factory to the grain context\n            context.RegisterResourceFactory<ITransactionManager>(stateName, () => new FaultInjectionTransactionManager<TState>(this.faultInjector, FaultInjectionControl, new TransactionManager<TState>(queue), context, logger, grainRuntime));\n        }\n\n        public Task<TResult> PerformRead<TResult>(Func<TState, TResult> readFunction)\n        {\n            return this.txState.PerformRead(readFunction);\n        }\n\n        public Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateFunction)\n        {\n            return this.txState.PerformUpdate(updateFunction);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/FaultInjectionTransactionStateAttribute.cs",
    "content": "using System;\nusing System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface IFaultInjectionTransactionalStateConfiguration : ITransactionalStateConfiguration\n    {\n    }\n\n    [AttributeUsage(AttributeTargets.Parameter)]\n    public class FaultInjectionTransactionalStateAttribute : Attribute, IFacetMetadata, IFaultInjectionTransactionalStateConfiguration\n    {\n        public string StateName { get; }\n        public string StorageName { get; }\n\n        public FaultInjectionTransactionalStateAttribute(string stateName, string storageName = null)\n        {\n            this.StateName = stateName;\n            this.StorageName = storageName;\n        }\n    }\n\n    public interface IFaultInjectionTransactionalStateFactory\n    {\n        IFaultInjectionTransactionalState<TState> Create<TState>(IFaultInjectionTransactionalStateConfiguration config) where TState : class, new();\n    }\n\n    public class FaultInjectionTransactionalStateFactory : IFaultInjectionTransactionalStateFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n        public FaultInjectionTransactionalStateFactory(IGrainContextAccessor contextAccessor)\n        {\n            this.contextAccessor = contextAccessor;\n        }\n\n        public IFaultInjectionTransactionalState<TState> Create<TState>(IFaultInjectionTransactionalStateConfiguration config) where TState : class, new()\n        {\n            var currentContext = this.contextAccessor.GrainContext;\n            TransactionalState<TState> transactionalState = ActivatorUtilities.CreateInstance<TransactionalState<TState>>(currentContext.ActivationServices, new TransactionalStateConfiguration(config), this.contextAccessor);\n            FaultInjectionTransactionalState<TState> deactivationTransactionalState = ActivatorUtilities.CreateInstance<FaultInjectionTransactionalState<TState>>(currentContext.ActivationServices, transactionalState);\n            deactivationTransactionalState.Participate(currentContext.ObservableLifecycle);\n            return deactivationTransactionalState;\n        }\n    }\n\n    public class FaultInjectionTransactionalStateAttributeMapper : IAttributeToFactoryMapper<FaultInjectionTransactionalStateAttribute>\n    {\n        private static readonly MethodInfo create =\n            typeof(IFaultInjectionTransactionalStateFactory).GetMethod(\"Create\");\n        public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, FaultInjectionTransactionalStateAttribute attribute)\n        {\n            IFaultInjectionTransactionalStateConfiguration config = attribute;\n            // use generic type args to define collection type.\n            MethodInfo genericCreate = create.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());\n            object[] args = new object[] { config };\n            return context => Create(context, genericCreate, args);\n        }\n\n        private static object Create(IGrainContext context, MethodInfo genericCreate, object[] args)\n        {\n            IFaultInjectionTransactionalStateFactory factory = context.ActivationServices.GetRequiredService<IFaultInjectionTransactionalStateFactory>();\n            return genericCreate.Invoke(factory, args);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/HostingExtensions.cs",
    "content": "using System;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Providers;\nusing Orleans.Transactions.TestKit;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public static class SiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configure cluster to use the distributed TM algorithm\n        /// </summary>\n        public static ISiloBuilder UseControlledFaultInjectionTransactionState(this ISiloBuilder builder)\n        {\n            return builder.ConfigureServices(services => services.UseControlledFaultInjectionTransactionState());\n        }\n\n        public static ISiloBuilder AddFaultInjectionAzureTableTransactionalStateStorage(this ISiloBuilder builder, Action<AzureTableTransactionalStateOptions> configureOptions)\n        {\n            return builder.AddFaultInjectionAzureTableTransactionalStateStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        public static ISiloBuilder AddFaultInjectionAzureTableTransactionalStateStorage(this ISiloBuilder builder, string name, Action<AzureTableTransactionalStateOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddFaultInjectionAzureTableTransactionalStateStorage(name, ob => ob.Configure(configureOptions)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/IControlledFaultInjector.cs",
    "content": "﻿namespace Orleans.Transactions.TestKit\n{\n    public interface IControlledTransactionFaultInjector : ITransactionFaultInjector\n    {\n        bool InjectBeforeStore { get; set; }\n        bool InjectAfterStore { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/SimpleAzureStorageExceptionInjector.cs",
    "content": "using System;\nusing System.ComponentModel;\nusing System.Runtime.Serialization;\nusing Azure;\nusing Microsoft.Extensions.Logging;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class SimpleAzureStorageExceptionInjector : IControlledTransactionFaultInjector\n    {\n        public bool InjectBeforeStore { get; set; }\n        public bool InjectAfterStore { get; set; }\n        private int injectionBeforeStoreCounter = 0;\n        private int injectionAfterStoreCounter = 0;\n        private readonly ILogger logger;\n        public SimpleAzureStorageExceptionInjector(ILogger<SimpleAzureStorageExceptionInjector> logger)\n        {\n            this.logger = logger;\n        }\n\n        public void AfterStore()\n        {\n            if (InjectAfterStore)\n            {\n                InjectAfterStore = false;\n                this.injectionAfterStoreCounter++;\n                var message = $\"Storage exception thrown after store, thrown total {injectionAfterStoreCounter}\";\n                this.logger.LogInformation(message);\n                throw new SimpleAzureStorageException(message);\n            }\n        }\n\n        public void BeforeStore()\n        {\n            if (InjectBeforeStore)\n            {\n                InjectBeforeStore = false;\n                this.injectionBeforeStoreCounter++;\n                var message = $\"Storage exception thrown before store. Thrown total {injectionBeforeStoreCounter}\";\n                this.logger.LogInformation(message);\n                throw new SimpleAzureStorageException(message);\n            }\n        }\n    }\n\n    [GenerateSerializer]\n    public class SimpleAzureStorageException : RequestFailedException\n    {\n        public SimpleAzureStorageException(string message) : base(message)\n        {\n        }\n\n        public SimpleAzureStorageException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        public SimpleAzureStorageException(int status, string message) : base(status, message)\n        {\n        }\n\n        public SimpleAzureStorageException(int status, string message, Exception innerException) : base(status, message, innerException)\n        {\n        }\n\n        public SimpleAzureStorageException(int status, string message, string errorCode, Exception innerException) : base(status, message, errorCode, innerException)\n        {\n        }\n\n        [Obsolete(\"TThe serialization constructor pattern was made obsolete in modern versions of .NET. Use the other constructors instead.\")]\n        [EditorBrowsable(EditorBrowsableState.Never)]\n        protected SimpleAzureStorageException(SerializationInfo info, StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/SingleStateDeactivatingTransactionalGrain.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit\n{\n\n    public interface IFaultInjectionTransactionTestGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task Set(int newValue);\n\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task Add(int numberToAdd, FaultInjectionControl faultInjectionControl = null);\n\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<int> Get();\n\n        Task Deactivate();\n    }\n\n    public class SingleStateFaultInjectionTransactionalGrain : Grain, IFaultInjectionTransactionTestGrain\n    {\n        private readonly IFaultInjectionTransactionalState<GrainData> data;\n        private readonly ILoggerFactory loggerFactory;\n        private ILogger logger;\n\n        public SingleStateFaultInjectionTransactionalGrain(\n            [FaultInjectionTransactionalState(\"data\", TransactionTestConstants.TransactionStore)]\n            IFaultInjectionTransactionalState<GrainData> data,\n            ILoggerFactory loggerFactory)\n        {\n            this.data = data;\n            this.loggerFactory = loggerFactory;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger = this.loggerFactory.CreateLogger(this.GetGrainId().ToString());\n            this.logger.LogInformation(\"GrainId {GrainId}\", this.GetPrimaryKey());\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task Set(int newValue)\n        {\n            return this.data.PerformUpdate(d =>\n            {\n                this.logger.LogInformation(\"Setting value {NewValue}.\", newValue);\n                d.Value = newValue;\n            });\n        }\n\n        public Task Add(int numberToAdd, FaultInjectionControl faultInjectionControl = null)\n        {\n            //reset in case control from last tx isn't cleared for some reason\n            this.data.FaultInjectionControl.Reset();\n            //dont replace it with this.data.FaultInjectionControl = faultInjectionControl, \n            //this.data.FaultInjectionControl must remain the same reference\n            if (faultInjectionControl != null)\n            {\n                this.data.FaultInjectionControl.FaultInjectionPhase = faultInjectionControl.FaultInjectionPhase;\n                this.data.FaultInjectionControl.FaultInjectionType = faultInjectionControl.FaultInjectionType;\n            }\n           \n            return this.data.PerformUpdate(d =>\n            {\n                this.logger.LogInformation(\"Adding {NumberToAdd} to value {Value}.\", numberToAdd, d.Value);\n                d.Value += numberToAdd;\n            });\n        }\n\n        public Task<int> Get()\n        {\n            return this.data.PerformRead<int>(d => d.Value);\n        }\n\n        public Task Deactivate()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ControlledInjection/TransactionFaultInjectionServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.TestKit;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class TransactionFaultInjectionServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configure cluster to use the distributed TM algorithm\n        /// </summary>\n        public static IServiceCollection UseControlledFaultInjectionTransactionState(this IServiceCollection services)\n        {\n            services.AddSingleton<IAttributeToFactoryMapper<FaultInjectionTransactionalStateAttribute>, FaultInjectionTransactionalStateAttributeMapper>();\n            services.TryAddTransient<IFaultInjectionTransactionalStateFactory, FaultInjectionTransactionalStateFactory>();\n            services.AddTransient(typeof(IFaultInjectionTransactionalState<>), typeof(FaultInjectionTransactionalState<>));\n            return services;\n        }\n\n        internal static IServiceCollection AddFaultInjectionAzureTableTransactionalStateStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<AzureTableTransactionalStateOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<AzureTableTransactionalStateOptions>(name));\n\n            services.TryAddSingleton<ITransactionalStateStorageFactory>(sp => sp.GetKeyedService<ITransactionalStateStorageFactory>(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME));\n            services.AddKeyedSingleton<ITransactionalStateStorageFactory>(name, (sp, key) => FaultInjectionAzureTableTransactionStateStorageFactory.Create(sp, key as string));\n            services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>>(s => (ILifecycleParticipant<ISiloLifecycle>)s.GetRequiredKeyedService<ITransactionalStateStorageFactory>(name));\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/ITransactionFaultInjector.cs",
    "content": "﻿namespace Orleans.Transactions.TestKit\n{\n    public interface ITransactionFaultInjector\n    {\n        void BeforeStore();\n        void AfterStore();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/FaultInjection/RandomInjection/RandomErrorInjector.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\nusing Orleans.Storage;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class RandomErrorInjector : ITransactionFaultInjector\n    {\n        private readonly double conflictProbability;\n        private readonly double beforeProbability;\n        private readonly double afterProbability;\n\n        public RandomErrorInjector(double injectionProbability)\n        {\n            conflictProbability = injectionProbability / 5;\n            beforeProbability = 2 * injectionProbability / 5;\n            afterProbability = 2 * injectionProbability / 5;\n        }\n\n        public void BeforeStore()\n        {\n            if (Random.Shared.NextDouble() < conflictProbability)\n            {\n                throw new RandomlyInjectedInconsistentStateException();\n            }\n            if (Random.Shared.NextDouble() < beforeProbability)\n            {\n                throw new RandomlyInjectedStorageException();\n            }\n        }\n\n        public void AfterStore()\n        {\n            if (Random.Shared.NextDouble() < afterProbability)\n            {\n                throw new RandomlyInjectedStorageException();\n            }\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class RandomlyInjectedStorageException : Exception\n        {\n            public RandomlyInjectedStorageException() : base(\"injected fault\") { }\n\n            [Obsolete]\n            protected RandomlyInjectedStorageException(SerializationInfo info, StreamingContext context)\n                : base(info, context)\n            {\n            }\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class RandomlyInjectedInconsistentStateException : InconsistentStateException\n        {\n            public RandomlyInjectedInconsistentStateException() : base(\"injected fault\") { }\n\n            [Obsolete]\n            protected RandomlyInjectedInconsistentStateException(SerializationInfo info, StreamingContext context)\n                : base(info, context)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/ITransactionAttributionGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface INoAttributionGrain : IGrainWithGuidKey\n    {\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface ISuppressAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Suppress)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface ICreateOrJoinAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface ICreateAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Create)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface IJoinAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOptionAlias.Mandatory)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface ISupportedAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Supported)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public interface INotAllowedAttributionGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.NotAllowed)]\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    #region wrappers\n    public interface ITransactionAttributionGrain\n    {\n        Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public static class TransactionAttributionGrainExtensions\n    {\n        public static ITransactionAttributionGrain GetTransactionAttributionGrain(this IGrainFactory grainFactory, Guid id, TransactionOption? option = null)\n        {\n            if(!option.HasValue)\n            {\n                return new NoAttributionGrain(grainFactory.GetGrain<INoAttributionGrain>(id));\n            }\n            switch(option.Value)\n            {\n                case TransactionOption.Suppress:\n                    return new SuppressAttributionGrain(grainFactory.GetGrain<ISuppressAttributionGrain>(id));\n                case TransactionOption.CreateOrJoin:\n                    return new CreateOrJoinAttributionGrain(grainFactory.GetGrain<ICreateOrJoinAttributionGrain>(id));\n                case TransactionOption.Create:\n                    return new CreateAttributionGrain(grainFactory.GetGrain<ICreateAttributionGrain>(id));\n                case TransactionOption.Join:\n                    return new JoinAttributionGrain(grainFactory.GetGrain<IJoinAttributionGrain>(id));\n                case TransactionOption.Supported:\n                    return new SupportedAttributionGrain(grainFactory.GetGrain<ISupportedAttributionGrain>(id));\n                case TransactionOption.NotAllowed:\n                    return new NotAllowedAttributionGrain(grainFactory.GetGrain<INotAllowedAttributionGrain>(id));\n                default:\n                    throw new NotSupportedException($\"Transaction option {option.Value} is not supported.\");\n            }\n        }\n\n        [GenerateSerializer]\n        public class NoAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public INoAttributionGrain grain;\n\n            public NoAttributionGrain(INoAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class SuppressAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ISuppressAttributionGrain grain;\n\n            public SuppressAttributionGrain(ISuppressAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class CreateOrJoinAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ICreateOrJoinAttributionGrain grain;\n\n            public CreateOrJoinAttributionGrain(ICreateOrJoinAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class CreateAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ICreateAttributionGrain grain;\n\n            public CreateAttributionGrain(ICreateAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class JoinAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public IJoinAttributionGrain grain;\n\n            public JoinAttributionGrain(IJoinAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class SupportedAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ISupportedAttributionGrain grain;\n\n            public SupportedAttributionGrain(ISupportedAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n\n        [GenerateSerializer]\n        public class NotAllowedAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public INotAllowedAttributionGrain grain;\n\n            public NotAllowedAttributionGrain(INotAllowedAttributionGrain grain)\n            {\n                this.grain = grain;\n            }\n\n            public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n            {\n                return this.grain.GetNestedTransactionIds(tier, tiers);\n            }\n        }\n    }\n    #endregion wrappers\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/ITransactionCommitterTestGrain.cs",
    "content": "﻿\nusing Orleans.Transactions.Abstractions;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface ITransactionCommitterTestGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Join)]\n        Task Commit(ITransactionCommitOperation<IRemoteCommitService> operation);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/ITransactionCoordinatorGrain.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.TestKit.Correctnesss;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface ITransactionCoordinatorGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainSet(List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainAdd(List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainDouble(List<ITransactionTestGrain> grains);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainDoubleByRWRW(List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainDoubleByWRWR(List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task OrphanCallTransaction();\n\n        [Transaction(TransactionOption.Create)]\n        Task AddAndThrow(ITransactionTestGrain grain, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainAddAndThrow(List<ITransactionTestGrain> grain, List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainSetBit(List<ITransactionalBitArrayGrain> grains, int bitIndex);\n\n        [Transaction(TransactionOption.Create)]\n        Task MultiGrainAdd(ITransactionCommitterTestGrain committer, ITransactionCommitOperation<IRemoteCommitService> operation, List<ITransactionTestGrain> grains, int numberToAdd);\n\n        [Transaction(TransactionOption.Create)]\n        [ReadOnly]\n        Task UpdateViolated(ITransactionTestGrain grains, int numberToAdd);\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/ITransactionTestGrain.cs",
    "content": "using System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface ITransactionTestGrain : IGrainWithGuidKey\n    {\n\n        /// <summary>\n        /// apply set operation to every transaction state\n        /// </summary>\n        /// <param name=\"newValue\"></param>\n        /// <returns></returns>\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task Set(int newValue);\n\n        /// <summary>\n        /// apply add operation to every transaction state\n        /// </summary>\n        /// <param name=\"numberToAdd\"></param>\n        /// <returns></returns>\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<int[]> Add(int numberToAdd);\n\n        /// <summary>\n        /// apply get operation to every transaction state\n        /// </summary>\n        /// <returns></returns>\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<int[]> Get();\n\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task AddAndThrow(int numberToAdd);\n\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task SetAndThrow(int numberToSet);\n\n        Task Deactivate();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/ITransactionalBitArrayGrain.cs",
    "content": "﻿\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit.Correctnesss\n{\n    public interface ITransactionalBitArrayGrain : IGrainWithGuidKey\n    {\n        /// <summary>\n        /// Ping \n        /// </summary>\n        /// <returns></returns>\n        Task Ping();\n        /// <summary>\n        /// apply set operation to every transaction state\n        /// </summary>\n        /// <param name=\"newValue\"></param>\n        /// <returns></returns>\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task SetBit(int newValue);\n\n        /// <summary>\n        /// Performs a read transaction on each state, returning the results in order.\n        /// </summary>\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task<List<BitArrayState>> Get();\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/MultiStateTransactionalBitArrayGrain.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Newtonsoft.Json;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.Correctnesss\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class BitArrayState\n    {\n        protected bool Equals(BitArrayState other)\n        {\n            if (ReferenceEquals(null, this.value)) return false;\n            if (ReferenceEquals(null, other.value)) return false;\n            if (this.value.Length != other.value.Length) return false;\n            for (var i = 0; i < this.value.Length; i++)\n            {\n                if (this.value[i] != other.value[i])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            if (ReferenceEquals(this, obj)) return true;\n            if (obj.GetType() != this.GetType()) return false;\n            return Equals((BitArrayState) obj);\n        }\n\n        public override int GetHashCode() => HashCode.Combine(value);\n\n        private static readonly int BitsInInt = sizeof(int) * 8;\n\n        [JsonProperty(\"v\")]\n        [Id(0)]\n        private int[] value = { 0 };\n\n        [JsonIgnore]\n        public int[] Value => value;\n\n        [JsonIgnore]\n        public int Length => this.value.Length;\n\n        public BitArrayState()\n        {\n        }\n\n        public BitArrayState(BitArrayState other)\n        {\n            this.value = new int[other.value.Length];\n            for (var i = 0; i < other.value.Length; i++)\n            {\n                this.value[i] = other.value[i];\n            }\n        }\n\n        public void Set(int index, bool value)\n        {\n            int idx = index / BitsInInt;\n            if (idx >= this.value.Length)\n            {\n                Array.Resize(ref this.value, idx+1);\n            }\n            int shift = 1 << (index % BitsInInt);\n            if (value)\n            {\n                this.value[idx] |= shift;\n            } else\n                this.value[idx] &= ~shift;\n        }\n\n        public IEnumerator<int> GetEnumerator()\n        {\n            foreach (var v in this.value) yield return v;\n        }\n\n        public override string ToString()\n        {\n            // Write the values from least significant bit to most significant bit\n            var builder = new StringBuilder();\n            foreach (var v in this.value)\n            {\n                builder.Append(Reverse(Convert.ToString(v, 2)).PadRight(BitsInInt, '0'));\n\n                string Reverse(string s)\n                {\n                    char[] charArray = s.ToCharArray();\n                    Array.Reverse(charArray);\n                    return new string(charArray);\n                }\n            }\n            return builder.ToString();\n        }\n\n        public int this[int index]\n        {\n            get => this.value[index];\n            set => this.value[index] = value;\n        }\n\n        public static bool operator ==(BitArrayState left, BitArrayState right)\n        {\n            if (ReferenceEquals(left, right)) return true;\n            if (ReferenceEquals(left, null)) return false;\n            if (ReferenceEquals(right, null)) return false;\n            return left.Equals(right);\n        }\n\n        public static bool operator !=(BitArrayState left, BitArrayState right)\n        {\n            return !(left == right);\n        }\n\n        public static BitArrayState operator ^(BitArrayState left, BitArrayState right)\n        {\n            return Apply(left, right, (l, r) => l ^ r);\n        }\n\n        public static BitArrayState operator |(BitArrayState left, BitArrayState right)\n        {\n            return Apply(left, right, (l, r) => l | r);\n        }\n\n        public static BitArrayState operator &(BitArrayState left, BitArrayState right)\n        {\n            return Apply(left, right, (l, r) => l & r);\n        }\n\n        public static BitArrayState Apply(BitArrayState left, BitArrayState right, Func<int, int, int> op)\n        {\n            var result = new BitArrayState(left.value.Length > right.value.Length ? left : right);\n            var overlappingLength = Math.Min(left.value.Length, right.value.Length);\n            var i = 0;\n            for (; i < overlappingLength; i++)\n            {\n                result.value[i] = op(left.value[i], right.value[i]);\n            }\n\n            // Continue with the non-overlapping portion.\n            for (; i < result.value.Length; i++)\n            {\n                var leftVal = left.value.Length > i ? left.value[i] : 0;\n                var rightVal = right.value.Length > i ? right.value[i] : 0;\n                result.value[i] = op(leftVal, rightVal);\n            }\n\n            return result;\n        }\n    }\n\n    [GrainType(\"txn-correctness-MaxStateTransactionalGrain\")]\n    public class MaxStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public MaxStateTransactionalGrain(ITransactionalStateFactory stateFactory,\n            ILoggerFactory loggerFactory)\n            : base(Enumerable.Range(0, TransactionTestConstants.MaxCoordinatedTransactions)\n                .Select(i => stateFactory.Create<BitArrayState>(new TransactionalStateConfiguration(new TransactionalStateAttribute($\"data{i}\", TransactionTestConstants.TransactionStore))))\n                .ToArray(),\n                  loggerFactory)\n        {\n        }\n    }\n\n    [GrainType(\"txn-correctness-DoubleStateTransactionalGrain\")]\n    public class DoubleStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public DoubleStateTransactionalGrain(\n            [TransactionalState(\"data1\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<BitArrayState> data1,\n            [TransactionalState(\"data2\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<BitArrayState> data2,\n            ILoggerFactory loggerFactory)\n            : base(new ITransactionalState<BitArrayState>[2] { data1, data2 }, loggerFactory)\n        {\n        }\n    }\n\n    [GrainType(\"txn-correctness-SingleStateTransactionalGrain\")]\n    public class SingleStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public SingleStateTransactionalGrain(\n            [TransactionalState(\"data\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<BitArrayState> data,\n            ILoggerFactory loggerFactory)\n            : base(new ITransactionalState<BitArrayState>[1] { data }, loggerFactory)\n        {\n        }\n    }\n\n    [GrainType(\"txn-correctness-MultiStateTransactionalBitArrayGrain\")]\n    public class MultiStateTransactionalBitArrayGrain : Grain, ITransactionalBitArrayGrain\n    {\n        protected ITransactionalState<BitArrayState>[] dataArray;\n        private readonly ILoggerFactory loggerFactory;\n        protected ILogger logger;\n\n        public MultiStateTransactionalBitArrayGrain(\n            ITransactionalState<BitArrayState>[] dataArray,\n            ILoggerFactory loggerFactory)\n        {\n            this.dataArray = dataArray;\n            this.loggerFactory = loggerFactory;\n        }\n        \n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger = this.loggerFactory.CreateLogger(this.GetGrainId().ToString());\n            this.logger.LogTrace(\"GrainId: {GrainId}.\", this.GetPrimaryKey());\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task Ping()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task SetBit(int index)\n        {\n            return Task.WhenAll(this.dataArray\n                .Select(data => data.PerformUpdate(state =>\n                {\n                    this.logger.LogTrace(\"Setting bit {Index} in state {State}. Transaction {CurrentTransactionId}\", index, state, TransactionContext.CurrentTransactionId);\n                    state.Set(index, true);\n                    this.logger.LogTrace(\"Set bit {Index} in state {State}.\", index, state);\n                })));\n        }\n\n        public async Task<List<BitArrayState>> Get()\n        {\n            return (await Task.WhenAll(this.dataArray\n                .Select(state => state.PerformRead(s =>\n                {\n                    this.logger.LogTrace(\"Get state {State}.\", s);\n                    return s;\n                })))).ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/MultiStateTransactionalGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Transactions.Abstractions;\nusing System;\nusing System.Linq;\nusing System.Runtime.Serialization;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class GrainData\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    public class MaxStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public MaxStateTransactionalGrain(ITransactionalStateFactory stateFactory,\n            ILoggerFactory loggerFactory)\n            : base(Enumerable.Range(0, TransactionTestConstants.MaxCoordinatedTransactions)\n                .Select(i => stateFactory.Create<GrainData>(new TransactionalStateConfiguration(new TransactionalStateAttribute($\"data{i}\", TransactionTestConstants.TransactionStore))))\n                .ToArray(),\n                  loggerFactory)\n        {\n        }\n    }\n\n    public class DoubleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public DoubleStateTransactionalGrain(\n            [TransactionalState(\"data1\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<GrainData> data1,\n            [TransactionalState(\"data2\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<GrainData> data2,\n            ILoggerFactory loggerFactory)\n            : base(new ITransactionalState<GrainData>[2] { data1, data2 }, loggerFactory)\n        {\n        }\n    }\n\n    public class SingleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public SingleStateTransactionalGrain(\n            [TransactionalState(\"data\", TransactionTestConstants.TransactionStore)]\n            ITransactionalState<GrainData> data,\n            ILoggerFactory loggerFactory)\n            : base(new ITransactionalState<GrainData>[1] { data }, loggerFactory)\n        {\n        }\n    }\n\n    public class NoStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public NoStateTransactionalGrain(\n            ILoggerFactory loggerFactory)\n            : base(Array.Empty<ITransactionalState<GrainData>>(), loggerFactory)\n        {\n        }\n    }\n\n    public class MultiStateTransactionalGrainBaseClass : Grain, ITransactionTestGrain\n    {\n        protected ITransactionalState<GrainData>[] dataArray;\n        private readonly ILoggerFactory loggerFactory;\n        protected ILogger logger;\n\n        public MultiStateTransactionalGrainBaseClass(\n            ITransactionalState<GrainData>[] dataArray,\n            ILoggerFactory loggerFactory)\n        {\n            this.dataArray = dataArray;\n            this.loggerFactory = loggerFactory;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger = this.loggerFactory.CreateLogger(this.GetGrainId().ToString());\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public async Task Set(int newValue)\n        {\n            foreach(var data in this.dataArray)\n            {\n                await data.PerformUpdate(state =>\n                {\n                    this.logger.LogInformation(\"Setting from {Value} to {NewValue}.\", state.Value, newValue);\n                    state.Value = newValue;\n                    this.logger.LogInformation(\"Set to {Value}.\", state.Value);\n                });\n            }\n        }\n\n        public async Task<int[]> Add(int numberToAdd)\n        {\n            var result = new int[dataArray.Length];\n            for(int i = 0; i < dataArray.Length; i++)\n            {\n                result[i] = await dataArray[i].PerformUpdate(state =>\n                {\n                    this.logger.LogInformation(\"Adding {NumberToAdd} to value {Value}.\", numberToAdd, state.Value);\n                    state.Value += numberToAdd;\n                    this.logger.LogInformation(\"Value after Adding {NumberToAdd} is {Value}.\", numberToAdd, state.Value);\n                    return state.Value;\n                });\n            }\n            return result;\n        }\n\n        public async Task<int[]> Get()\n        {\n            var result = new int[dataArray.Length];\n            for (int i = 0; i < dataArray.Length; i++)\n            {\n                result[i] = await dataArray[i].PerformRead(state =>\n                {\n                    this.logger.LogInformation(\"Get {Value}.\", state.Value);\n                    return state.Value;\n                });\n            }\n            return result;\n        }\n\n        public async Task AddAndThrow(int numberToAdd)\n        {\n            await Add(numberToAdd);\n            throw new AddAndThrowException($\"{GetType().Name} test exception\");\n        }\n\n        public async Task SetAndThrow(int numberToSet)\n        {\n            await Set(numberToSet);\n            throw new AddAndThrowException($\"{GetType().Name} test exception\");\n        }\n\n        public Task Deactivate()\n        {\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class AddAndThrowException : Exception\n    {\n        public AddAndThrowException() : base(\"Unexpected error.\") { }\n\n        public AddAndThrowException(string message) : base(message) { }\n\n        public AddAndThrowException(string message, Exception innerException) : base(message, innerException) { }\n\n        [Obsolete]\n        protected AddAndThrowException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/RemoteCommitService.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public interface IRemoteCommitService\n    {\n        Task<bool> Pass(Guid transactionId, string data);\n        Task<bool> Fail(Guid transactionId, string data);\n        Task<bool> Throw(Guid transactionId, string data);\n    }\n\n    // TODO : Replace with more complete service implementation which:\n    // - can be called to verify that commit service receive Callme with proper args.\n    // - can produce errors for fault senarios.\n    public class RemoteCommitService : IRemoteCommitService\n    {\n        private readonly ILogger logger;\n\n        public RemoteCommitService(ILogger<RemoteCommitService> logger)\n        {\n            this.logger = logger;\n        }\n\n        public async Task<bool> Pass(Guid transactionId, string data)\n        {\n            this.logger.LogInformation(\"Transaction {TransactionId} Passed with data: {Data}\", transactionId, data);\n            await Task.Delay(30);\n            return true;\n        }\n\n        public async Task<bool> Fail(Guid transactionId, string data)\n        {\n            this.logger.LogInformation(\"Transaction {TransactionId} Failed with data: {Data}\", transactionId, data);\n            await Task.Delay(30);\n            return false;\n        }\n\n        public async Task<bool> Throw(Guid transactionId, string data)\n        {\n            this.logger.LogInformation(\"Transaction {TransactionId} Threw with data: {Data}\", transactionId, data);\n            await Task.Delay(30);\n            throw new ApplicationException(\"Transaction {transactionId} Threw with data: {data}\");\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class PassOperation : ITransactionCommitOperation<IRemoteCommitService>\n    {\n        [Id(0)]\n        public string Data { get; set; }\n\n        public PassOperation(string data)\n        {\n            this.Data = data;\n        }\n\n        public async Task<bool> Commit(Guid transactionId, IRemoteCommitService service)\n        {\n            return await service.Pass(transactionId, this.Data);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class FailOperation : ITransactionCommitOperation<IRemoteCommitService>\n    {\n        [Id(0)]\n        public string Data { get; set; }\n\n        public FailOperation(string data)\n        {\n            this.Data = data;\n        }\n\n        public async Task<bool> Commit(Guid transactionId, IRemoteCommitService service)\n        {\n            return await service.Fail(transactionId, this.Data);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class ThrowOperation : ITransactionCommitOperation<IRemoteCommitService>\n    {\n        [Id(0)]\n        public string Data { get; set; }\n\n        public ThrowOperation(string data)\n        {\n            this.Data = data;\n        }\n\n        public async Task<bool> Commit(Guid transactionId, IRemoteCommitService service)\n        {\n            return await service.Throw(transactionId, this.Data);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/TransactionAttributionGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class NoAttributionGrain : Grain, INoAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class SuppressAttributionGrain : Grain, ISuppressAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class CreateOrJoinAttributionGrain : Grain, ICreateOrJoinAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class CreateAttributionGrain : Grain, ICreateAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class JoinAttributionGrain : Grain, IJoinAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class SupportedAttributionGrain : Grain, ISupportedAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    public class NotAllowedAttributionGrain : Grain, INotAllowedAttributionGrain\n    {\n        public Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            return AttributionGrain.GetNestedTransactionIds(tier, tiers);\n        }\n    }\n\n    internal static class AttributionGrain\n    {\n        public static async Task<List<string>[]> GetNestedTransactionIds(int tier, List<ITransactionAttributionGrain>[] tiers)\n        {\n            TransactionInfo ti = TransactionContext.GetTransactionInfo();\n            List<string>[] results = new List<string>[tier + 1 + tiers.Length];\n            results[tier] = new List<string>(new[] { ti?.Id });\n\n            if (tiers.Length == 0)\n            {\n                return results;\n            }\n\n            List<ITransactionAttributionGrain> nextTier = tiers.FirstOrDefault();\n            List<ITransactionAttributionGrain>[] nextTiers = tiers.Skip(1).ToArray();\n            List<string>[][] tiersResults = await Task.WhenAll(nextTier.Select(g => g.GetNestedTransactionIds(tier+1, nextTiers)));\n            foreach (List<string>[] result in tiersResults)\n            {\n                if (result.Length != results.Length) throw new ApplicationException(\"Invalid result length\");\n                for (int i = tier + 1; i < results.Length; i++)\n                {\n                    if (results[i] != null)\n                    {\n                        results[i].AddRange(result[i]);\n                    }\n                    else\n                        results[i] = result[i];\n                }\n            }\n\n            return results;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/TransactionCommitterTestGrain.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class TransactionCommitterTestGrain : Grain, ITransactionCommitterTestGrain\n    {\n        protected ITransactionCommitter<IRemoteCommitService> committer;\n        private readonly ILoggerFactory loggerFactory;\n        protected ILogger logger;\n\n        public TransactionCommitterTestGrain(\n            [TransactionCommitter(TransactionTestConstants.RemoteCommitService, TransactionTestConstants.TransactionStore)] ITransactionCommitter<IRemoteCommitService> committer,\n            ILoggerFactory loggerFactory)\n        {\n            this.committer = committer;\n            this.loggerFactory = loggerFactory;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger = this.loggerFactory.CreateLogger(this.GetGrainId().ToString());\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task Commit(ITransactionCommitOperation<IRemoteCommitService> operation)\n        {\n            return this.committer.OnCommit(operation);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Grains/TransactionCoordinatorGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.Transactions;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.TestKit.Correctnesss;\n\nnamespace Orleans.Transactions.TestKit\n{\n    [StatelessWorker]\n    public class TransactionCoordinatorGrain : Grain, ITransactionCoordinatorGrain\n    {\n        public Task MultiGrainSet(List<ITransactionTestGrain> grains, int newValue)\n        {\n            return Task.WhenAll(grains.Select(g => g.Set(newValue)));\n        }\n\n        public Task MultiGrainAdd(List<ITransactionTestGrain> grains, int numberToAdd)\n        {\n            return Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n        }\n\n        public Task MultiGrainDouble(List<ITransactionTestGrain> grains)\n        {\n            return Task.WhenAll(grains.Select(Double));\n        }\n\n        public Task OrphanCallTransaction()\n        {\n            _ = TransactionContext.GetRequiredTransactionInfo().Fork();\n            return Task.CompletedTask;\n        }\n\n        public async Task AddAndThrow(ITransactionTestGrain grain, int numberToAdd)\n        {\n            await grain.Add(numberToAdd);\n            throw new Exception(\"This should abort the transaction\");\n        }\n\n        public async Task MultiGrainAddAndThrow(List<ITransactionTestGrain> throwGrains, List<ITransactionTestGrain> grains, int numberToAdd)\n        {\n            await Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n            await Task.WhenAll(throwGrains.Select(tg => tg.AddAndThrow(numberToAdd)));\n        }\n\n        public Task MultiGrainSetBit(List<ITransactionalBitArrayGrain> grains, int bitIndex)\n        {\n            return Task.WhenAll(grains.Select(g => g.SetBit(bitIndex)));\n        }\n\n        public Task MultiGrainAdd(ITransactionCommitterTestGrain committer, ITransactionCommitOperation<IRemoteCommitService> operation, List<ITransactionTestGrain> grains, int numberToAdd)\n        {\n            List<Task> tasks = new List<Task>();\n            tasks.AddRange(grains.Select(g => g.Add(numberToAdd)));\n            tasks.Add(committer.Commit(operation));\n            return Task.WhenAll(tasks);\n        }\n\n        public Task UpdateViolated(ITransactionTestGrain grain, int numberToAdd)\n        {\n            return grain.Add(numberToAdd);\n        }\n\n        private async Task Double(ITransactionTestGrain grain)\n        {\n            int[] values = await grain.Get();\n            await grain.Add(values[0]);\n        }\n\n        public async Task MultiGrainDoubleByRWRW(List<ITransactionTestGrain> grains, int numberToAdd)\n        {\n            await Task.WhenAll(grains.Select(g => g.Get()));\n            await Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n            await Task.WhenAll(grains.Select(g => g.Get()));\n            await Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n        }\n\n        public async Task MultiGrainDoubleByWRWR(List<ITransactionTestGrain> grains, int numberToAdd)\n        {\n            await Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n            await Task.WhenAll(grains.Select(g => g.Get()));\n            await Task.WhenAll(grains.Select(g => g.Add(numberToAdd)));\n            await Task.WhenAll(grains.Select(g => g.Get()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/ITestState.cs",
    "content": "namespace Orleans.Transactions.TestKit\n{\n    public interface ITestState\n    {\n        int state { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/Orleans.Transactions.TestKit.Base.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Transactions.TestKit.Base</PackageId>\n    <Title>Microsoft Orleans Transactions test kit base</Title>\n    <Description>Testkit base library for transactions</Description>\n    <PackageTags>$(PackageTags) TransactionTestkKit</PackageTags>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Transactions.TestKit.Base</AssemblyName>\n    <RootNamespace>Orleans.Transactions.TestKit.Base</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AwesomeAssertions\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Transactions.AzureStorage\\Orleans.Transactions.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Transactions\\Orleans.Transactions.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/ConsistencyTransactionTestRunner.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\nusing Orleans.Transactions.TestKit.Consistency;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class ConsistencyTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected ConsistencyTransactionTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n\n\n        // settings that are configuration dependent can be overridden by runner subclasses\n        // this allows tests to adapt their logic, or be skipped, for specific contexts\n        protected abstract bool StorageAdaptorHasLimitedCommitSpace { get; }\n        protected abstract bool StorageErrorInjectionActive { get; }\n\n        public virtual async Task RandomizedConsistency(int numGrains, int scale, bool avoidDeadlocks, bool avoidTimeouts, ReadWriteDetermination readwrite)\n        {\n            var random = new Random(scale + numGrains * 1000 + (avoidDeadlocks ? 666 : 333) + ((int)readwrite) * 123976);\n\n            var harness = new ConsistencyTestHarness(grainFactory, numGrains, random.Next(), avoidDeadlocks, avoidTimeouts, readwrite, StorageErrorInjectionActive);\n\n            // first, run the random work load to generate history events\n            testOutput($\"start at {DateTime.UtcNow}\");\n            int numThreads = scale;\n            int numTxsPerThread = scale * scale;\n\n            // start the threads that run transactions\n            var tasks = new Task[numThreads];\n            for (int i = 0; i < numThreads; i++)\n            {\n                tasks[i] = harness.RunRandomTransactionSequence(i, numTxsPerThread, grainFactory, this.testOutput);\n            }\n\n            // wait for the test to finish\n            await Task.WhenAll(tasks);\n            testOutput($\"end at {DateTime.UtcNow}\");\n\n            // golden path: all transactions are expected to pass when avoiding deadlocks and lock upgrades\n            if (!StorageErrorInjectionActive\n                && avoidDeadlocks\n                && (readwrite == ReadWriteDetermination.PerGrain || readwrite == ReadWriteDetermination.PerTransaction))\n            {\n                harness.NumAborted.Should().Be(0);\n            }\n\n            // then, analyze the history results\n            var tolerateGenericTimeouts = StorageErrorInjectionActive || (scale >= 3 && !avoidTimeouts);\n            var tolerateUnknownExceptions = StorageAdaptorHasLimitedCommitSpace || StorageErrorInjectionActive;\n            harness.CheckConsistency(tolerateGenericTimeouts, tolerateUnknownExceptions);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/ControlledFaultInjectionTransactionTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class ControlledFaultInjectionTransactionTestRunner : TransactionTestRunnerBase\n    {\n        public ControlledFaultInjectionTransactionTestRunner(IGrainFactory grainFactory, Action<string> output)\n         : base(grainFactory, output)\n        { }\n        \n        public virtual async Task SingleGrainReadTransaction()\n        {\n            const int expected = 5;\n\n            IFaultInjectionTransactionTestGrain grain = grainFactory.GetGrain<IFaultInjectionTransactionTestGrain>(Guid.NewGuid());\n            await grain.Set(expected);\n            int actual = await grain.Get();\n            actual.Should().Be(expected);\n            await grain.Deactivate();\n            actual = await grain.Get();\n            actual.Should().Be(expected);\n        }\n        \n        public virtual async Task SingleGrainWriteTransaction()\n        {\n            const int delta = 5;\n            IFaultInjectionTransactionTestGrain grain = this.grainFactory.GetGrain<IFaultInjectionTransactionTestGrain>(Guid.NewGuid());\n            int original = await grain.Get();\n            await grain.Add(delta);\n            await grain.Deactivate();\n            int expected = original + delta;\n            int actual = await grain.Get();\n            actual.Should().Be(expected);\n        }\n\n        public virtual async Task MultiGrainWriteTransaction_FaultInjection(TransactionFaultInjectPhase injectionPhase, FaultInjectionType injectionType)\n        {\n            const int setval = 5;\n            const int addval = 7;\n            int expected = setval + addval;\n            const int grainCount = TransactionTestConstants.MaxCoordinatedTransactions;\n            var faultInjectionControl = new FaultInjectionControl() { FaultInjectionPhase = injectionPhase, FaultInjectionType = injectionType };\n            List<IFaultInjectionTransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => this.grainFactory.GetGrain<IFaultInjectionTransactionTestGrain>(Guid.NewGuid()))\n                    .ToList();\n\n            IFaultInjectionTransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<IFaultInjectionTransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(grains, setval);\n            // add delay between transactions so confirmation errors don't bleed into neighboring transactions\n            if (injectionPhase == TransactionFaultInjectPhase.BeforeConfirm || injectionPhase == TransactionFaultInjectPhase.AfterConfirm)\n                await Task.Delay(TimeSpan.FromSeconds(30));\n            try\n            {\n                await coordinator.MultiGrainAddAndFaultInjection(grains, addval, faultInjectionControl);\n                // add delay between transactions so confirmation errors don't bleed into neighboring transactions\n                if (injectionPhase == TransactionFaultInjectPhase.BeforeConfirm || injectionPhase == TransactionFaultInjectPhase.AfterConfirm)\n                    await Task.Delay(TimeSpan.FromSeconds(30));\n            }\n            catch (OrleansTransactionAbortedException)\n            {\n                // add delay between transactions so errors don't bleed into neighboring transactions\n                await coordinator.MultiGrainAddAndFaultInjection(grains, addval);\n            }\n            catch (OrleansTransactionException e)\n            {\n                this.testOutput($\"Call failed with exception: {e}, retrying without fault\");\n                bool cascadingAbort = false;\n                bool firstAttempt = true;\n\n                do\n                {\n                    cascadingAbort = false;\n                    try\n                    {\n                        expected = await grains[0].Get() + addval;\n                        await coordinator.MultiGrainAddAndFaultInjection(grains, addval);\n                    }\n                    catch (OrleansCascadingAbortException)\n                    {\n                        this.testOutput($\"Retry failed with OrleansCascadingAbortException: {e}, retrying without fault\");\n                        // should only encounter this when faulting after storage write\n                        injectionType.Should().Be(FaultInjectionType.ExceptionAfterStore);\n                        // only allow one retry\n                        firstAttempt.Should().BeTrue();\n                        // add delay prevent castcading abort.\n                        cascadingAbort = true;\n                        firstAttempt = false;\n                    }\n                } while (cascadingAbort);\n            }\n\n            //if transactional state loaded correctly after reactivation, then following should pass\n            foreach (var grain in grains)\n            {\n                int actual = await grain.Get();\n                actual.Should().Be(expected);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/DisabledTransactionsTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class DisabledTransactionsTestRunner : TransactionTestRunnerBase\n    {\n        protected DisabledTransactionsTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n\n        public virtual void TransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName)\n        {\n            const int delta = 5;\n            ITransactionTestGrain grain = RandomTestGrain(transactionTestGrainClassName);\n            Func<Task> task = ()=>grain.Set(delta);\n            var response = task.Should().ThrowAsync<OrleansTransactionsDisabledException>();\n        }\n\n        public virtual void MultiTransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName)\n        {\n            const int delta = 5;\n            const int grainCount = TransactionTestConstants.MaxCoordinatedTransactions;\n\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(transactionTestGrainClassName))\n                    .ToList();\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            Func<Task> task = () => coordinator.MultiGrainSet(grains, delta);\n            var response = task.Should().ThrowAsync<OrleansTransactionsDisabledException>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/GoldenPathTransactionTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class GoldenPathTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected GoldenPathTransactionTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n\n        public virtual async Task SingleGrainReadTransaction(string grainStates)\n        {\n            const int expected = 0;\n\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            var actualResults = await grain.Get();\n            //each transaction state should all be 0 since no operation was applied yet\n            foreach (var actual in actualResults)\n            {\n                actual.Should().Be(expected);\n            }\n        }\n\n        public virtual async Task SingleGrainWriteTransaction(string grainStates)\n        {\n            const int delta = 5;\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            var original = await grain.Get();\n            await grain.Add(delta);\n            var expected = original.Select(value => value + delta).ToArray();\n            var actual = await grain.Get();\n            actual.Should().BeEquivalentTo(expected);\n        }\n\n        public virtual async Task MultiGrainWriteTransaction(string grainStates, int grainCount)\n        {\n            const int expected = 5;\n\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainAdd(grains, expected);\n\n            foreach (var grain in grains)\n            {\n                var actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            }\n        }\n\n        public virtual async Task MultiGrainReadWriteTransaction(string grainStates, int grainCount)\n        {\n            const int delta = 5;\n\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(grains, delta);\n            await coordinator.MultiGrainDouble(grains);\n\n            int expected = delta + delta;\n            foreach (var grain in grains)\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    if (expected != actual) this.testOutput($\"{grain} - failed\");\n                    actual.Should().Be(expected);\n                }\n            }\n        }\n\n        public virtual async Task RepeatGrainReadWriteTransaction(string grainStates, int grainCount)\n        {\n            const int repeat = 10;\n            const int delta = 5;\n\n            List<Guid> grainIds = Enumerable.Range(0, grainCount)\n                    .Select(i => Guid.NewGuid())\n                    .ToList();\n\n            List<ITransactionTestGrain> grains = grainIds\n                    .Select(id => TestGrain(grainStates, id))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(grains, delta);\n            for (int i = 0; i < repeat; i++)\n            {\n                await coordinator.MultiGrainDouble(grains);\n\n                int expected = delta * (int)Math.Pow(2,i+1);\n                foreach (var grain in grains)\n                {\n                    int[] actualValues = await grain.Get();\n                    foreach (var actual in actualValues)\n                    {\n                        if (expected != actual) this.testOutput($\"{grain} - failed\");\n                        actual.Should().Be(expected);\n                    }\n                }\n            }\n        }\n\n        public virtual async Task MultiWriteToSingleGrainTransaction(string grainStates)\n        {\n            const int delta = 5;\n            const int concurrentWrites = 3;\n\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            List<ITransactionTestGrain> grains = Enumerable.Repeat(grain, concurrentWrites).ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainAdd(grains, delta);\n\n            int expected = delta * concurrentWrites;\n            int[] actualValues = await grains[0].Get();\n            foreach (var actual in actualValues)\n            {\n                actual.Should().Be(expected);\n            }\n        }\n\n        public virtual async Task RWRWTest(string grainStates, int grainCount)\n        {\n            const int delta = 5;\n\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainDoubleByRWRW(grains, delta);\n\n            int expected = delta + delta;\n            foreach (var grain in grains)\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    if (expected != actual) this.testOutput($\"{grain} - failed\");\n                    actual.Should().Be(expected);\n                }\n            }\n        }\n\n        public virtual async Task WRWRTest(string grainStates, int grainCount)\n        {\n            const int delta = 5;\n\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainDoubleByWRWR(grains, delta);\n\n            int expected = delta + delta;\n            foreach (var grain in grains)\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    if (expected != actual) this.testOutput($\"{grain} - failed\");\n                    actual.Should().Be(expected);\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/GrainFaultTransactionTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class GrainFaultTransactionTestRunner : TransactionTestRunnerBase\n    {\n        public GrainFaultTransactionTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output)\n        { }\n\n        public virtual async Task AbortTransactionOnExceptions(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(new List<ITransactionTestGrain> { grain }, expected);\n            Func<Task> task = () => coordinator.AddAndThrow(grain, expected);\n            await task.Should().ThrowAsync<OrleansTransactionAbortedException>();\n\n            await TestAfterDustSettles(async () =>\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            });\n        }\n\n        public virtual async Task AbortTransactionOnReadOnlyViolatedException(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(new List<ITransactionTestGrain> { grain }, expected);\n            Func<Task> task = () => coordinator.UpdateViolated(grain, expected);\n            await task.Should().ThrowAsync<OrleansReadOnlyViolatedException>();\n\n            await TestAfterDustSettles(async () =>\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            });\n        }\n\n        public virtual async Task MultiGrainAbortTransactionOnExceptions(string grainStates)\n        {\n            const int grainCount = TransactionTestConstants.MaxCoordinatedTransactions - 1;\n            const int expected = 5;\n\n            ITransactionTestGrain throwGrain = RandomTestGrain(grainStates);\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await throwGrain.Set(expected);\n            await coordinator.MultiGrainSet(grains, expected);\n            Func<Task> task = () => coordinator.MultiGrainAddAndThrow(new List<ITransactionTestGrain>()\n            {\n                throwGrain\n            }, grains, expected);\n            await task.Should().ThrowAsync<OrleansTransactionAbortedException>();\n            grains.Add(throwGrain);\n\n            await TestAfterDustSettles(async () =>\n            {\n                foreach (var grain in grains)\n                {\n                    int[] actualValues = await grain.Get();\n                    foreach (var actual in actualValues)\n                    {\n                        actual.Should().Be(expected);\n                    }\n                }\n            });\n        }\n\n        public virtual async Task AbortTransactionExceptionInnerExceptionOnlyContainsOneRootCauseException(string grainStates)\n        {\n            const int throwGrainCount = 3;\n            const int grainCount = TransactionTestConstants.MaxCoordinatedTransactions - throwGrainCount;\n            const int expected = 5;\n\n            List<ITransactionTestGrain> throwGrains = Enumerable.Range(0, throwGrainCount)\n                .Select(i => RandomTestGrain(grainStates))\n                .ToList();\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainSet(throwGrains, expected);\n            await coordinator.MultiGrainSet(grains, expected);\n\n            async Task InnerExceptionCheck()\n            {\n                try\n                {\n                    await coordinator.MultiGrainAddAndThrow(throwGrains, grains, expected);\n                }\n                catch (Exception e)\n                {\n                    e.InnerException.Should().BeOfType<AddAndThrowException>();\n                    throw;\n                }\n            }\n\n            Func<Task> task = () => InnerExceptionCheck();\n            await task.Should().ThrowAsync<OrleansTransactionAbortedException>();\n\n            grains.AddRange(throwGrains);\n\n            await TestAfterDustSettles(async () =>\n            {\n                foreach (var grain in grains)\n                {\n                    int[] actualValues = await grain.Get();\n                    foreach (var actual in actualValues)\n                    {\n                        actual.Should().Be(expected);\n                    }\n                }\n            });\n        }\n\n        public virtual async Task AbortTransactionOnOrphanCalls(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain = RandomTestGrain(grainStates);\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await grain.Set(expected);\n            Func<Task> task = () => coordinator.OrphanCallTransaction();\n            await task.Should().ThrowAsync<OrleansOrphanCallException>();\n\n            //await Task.Delay(20000); // give time for GC\n\n            await TestAfterDustSettles(async () =>\n            {\n                int[] actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            });\n        }\n\n        private static async Task TestAfterDustSettles(Func<Task> what)\n        {\n            int tries = 2;\n            while (tries-- > 0)\n            {\n                try\n                {\n                    await what();\n                }\n                catch (OrleansCascadingAbortException)\n                {\n                    // due to optimistic reading we may read state of aborted transactions\n                    // which causes cascading abort\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/ScopedTransactionsTestRunner.cs",
    "content": "using System;\nusing System.Threading.Tasks;\n\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class ScopedTransactionsTestRunner : TransactionTestRunnerBase\n    {\n        private readonly ITransactionClient _transactionClient;\n\n        protected ScopedTransactionsTestRunner(IGrainFactory grainFactory, ITransactionClient transactionClient, Action<string> output)\n            : base(grainFactory, output)\n        {\n            _transactionClient = transactionClient;\n        }\n\n        public virtual async Task CreateTransactionScopeAndSetValue(string grainStates)\n        {\n            // Arrange\n            var grain = RandomTestGrain(grainStates);\n\n            // Act\n            Func<Task> act = () => grain.Set(57);\n\n            await _transactionClient.RunTransaction(TransactionOption.Create, async () =>\n                // Assert\n                await act.Should().NotThrowAsync(because: \"No failure expected\"));\n        }\n\n        public virtual async Task CreateTransactionScopeAndSetValueWithFailure(string grainStates)\n        {\n            // Arrange\n            var grain = RandomTestGrain(grainStates);\n\n            // Act\n            Func<Task> act = () => _transactionClient.RunTransaction(TransactionOption.Create, () => grain.SetAndThrow(57));\n\n            // Assert\n            await act.Should().ThrowAsync<OrleansTransactionAbortedException>(because: \"Failure expected\");\n        }\n\n        public virtual async Task CreateTransactionScopeAndSetValueAndAssert(string grainStates)\n        {\n            var result = Array.Empty<int>();\n\n            // Arrange\n            var grain = RandomTestGrain(grainStates);\n\n            // Act\n            await _transactionClient.RunTransaction(TransactionOption.Create, async () =>\n            {\n                await grain.Set(57);\n                result = await grain.Get();\n            });\n\n            // Assert\n            result.Should().OnlyContain(number => number == 57);\n        }\n\n        public virtual async Task CreateNestedTransactionScopeAndSetValueAndInnerFailAndAssert(string grainStates)\n        {\n            var result = Array.Empty<int>();\n\n            // Arrange\n            var grain = RandomTestGrain(grainStates);\n\n            // Act\n            await _transactionClient.RunTransaction(TransactionOption.Create, async () =>\n            {\n                try\n                {\n                    await _transactionClient.RunTransaction(TransactionOption.Create, async () => await grain.SetAndThrow(67));\n                }\n                catch\n                { }\n\n                await grain.Set(57);\n            });\n\n            result = await grain.Get();\n\n            // Assert\n            result.Should().OnlyContain(number => number == 57);\n        }\n    }\n}"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/SkewedClock.cs",
    "content": "using System;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class SkewedClock : IClock\n    {\n        private readonly TimeSpan minSkew;\n        private readonly int skewRangeTicks;\n\n        public SkewedClock(TimeSpan minSkew, TimeSpan maxSkew)\n        {\n            this.minSkew = minSkew;\n            this.skewRangeTicks = (int)(maxSkew.Ticks - minSkew.Ticks);\n        }\n\n        public DateTime UtcNow()\n        {\n            TimeSpan skew = TimeSpan.FromTicks(minSkew.Ticks + Random.Shared.Next(skewRangeTicks));\n            // skew forward in time or backward in time\n            return ((Random.Shared.Next() & 1) != 0)\n                ? DateTime.UtcNow + skew\n                : DateTime.UtcNow - skew;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/SkewedClockConfigurator.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.TestingHost;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class SkewedClockConfigurator : ISiloConfigurator\n    {\n        private static readonly TimeSpan MinSkew = TimeSpan.FromSeconds(3);\n        private static readonly TimeSpan MaxSkew = TimeSpan.FromSeconds(5);\n\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .ConfigureServices(services => services.AddSingleton<IClock>(sp => new SkewedClock(MinSkew, MaxSkew)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/TOCGoldenPathTestRunner.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class TocGoldenPathTestRunner : TransactionTestRunnerBase\n    {\n        protected TocGoldenPathTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n        public virtual async Task MultiGrainWriteTransaction(string grainStates, int grainCount)\n        {\n            const int expected = 5;\n\n            ITransactionCommitterTestGrain committer = this.grainFactory.GetGrain<ITransactionCommitterTestGrain>(Guid.NewGuid());\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainAdd(committer, new PassOperation(\"pass\"), grains, expected);\n\n            foreach (var grain in grains)\n            {\n                var actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            }\n\n            // TODO : Add verification that commit service receive call with proper args.\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/TocFaultTransactionTestRunner.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class TocFaultTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected TocFaultTransactionTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n\n        public virtual async Task MultiGrainWriteTransactionWithCommitFailure(string grainStates, int grainCount)\n        {\n            const int expected = 5;\n\n            ITransactionCommitterTestGrain committer = this.grainFactory.GetGrain<ITransactionCommitterTestGrain>(Guid.NewGuid());\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainAdd(committer, new PassOperation(\"pass\"), grains, expected);\n\n            Func<Task> task = () => coordinator.MultiGrainAdd(committer, new FailOperation(\"fail\"), grains, expected);\n            await task.Should().ThrowAsync<OrleansTransactionAbortedException>();\n\n            foreach (var grain in grains)\n            {\n                var actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            }\n\n            // TODO : Add verification that commit service receive call with proper args.\n        }\n\n        public virtual async Task MultiGrainWriteTransactionWithCommitException(string grainStates, int grainCount)\n        {\n            const int expected = 5;\n\n            ITransactionCommitterTestGrain committer = this.grainFactory.GetGrain<ITransactionCommitterTestGrain>(Guid.NewGuid());\n            List<ITransactionTestGrain> grains =\n                Enumerable.Range(0, grainCount)\n                    .Select(i => RandomTestGrain(grainStates))\n                    .ToList();\n\n            ITransactionCoordinatorGrain coordinator = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n\n            await coordinator.MultiGrainAdd(committer, new PassOperation(\"pass\"), grains, expected);\n\n            Func<Task> task = () => coordinator.MultiGrainAdd(committer, new ThrowOperation(\"throw\"), grains, expected);\n            await task.Should().ThrowAsync<OrleansTransactionInDoubtException>();\n\n            foreach (var grain in grains)\n            {\n                var actualValues = await grain.Get();\n                foreach (var actual in actualValues)\n                {\n                    actual.Should().Be(expected);\n                }\n            }\n\n            // TODO : Add verification that commit service receive call with proper args.\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/TransactionConcurrencyTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class TransactionConcurrencyTestRunner : TransactionTestRunnerBase\n    {\n        protected TransactionConcurrencyTestRunner(IGrainFactory grainFactory, Action<string> output)\n        : base(grainFactory, output) { }\n\n        /// <summary>\n        /// Two transaction share a single grain\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        public virtual async Task SingleSharedGrainTest(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain1 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain2 = RandomTestGrain(grainStates);\n            ITransactionTestGrain sharedGrain = RandomTestGrain(grainStates);\n            List<ITransactionTestGrain> transaction1Members = new List<ITransactionTestGrain>(new[] { grain1, sharedGrain });\n            List<ITransactionTestGrain> transaction2Members = new List<ITransactionTestGrain>(new[] { grain2, sharedGrain });\n            \n            ITransactionCoordinatorGrain coordinator1 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator2 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            await Task.WhenAll(\n                coordinator1.MultiGrainAdd(transaction1Members, expected),\n                coordinator2.MultiGrainAdd(transaction2Members, expected));\n\n            int[] actual = await grain1.Get();\n            expected.Should().Be(actual.FirstOrDefault());\n            actual = await grain2.Get();\n            expected.Should().Be(actual.FirstOrDefault());\n            actual = await sharedGrain.Get();\n            actual.FirstOrDefault().Should().Be(expected * 2);\n        }\n\n        /// <summary>\n        /// Chain of transactions, each dependent on the results of the previous\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        public virtual async Task TransactionChainTest(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain1 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain2 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain3 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain4 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain5 = RandomTestGrain(grainStates);\n            List<ITransactionTestGrain> transaction1Members = new List<ITransactionTestGrain>(new[] { grain1, grain2 });\n            List<ITransactionTestGrain> transaction2Members = new List<ITransactionTestGrain>(new[] { grain2, grain3 });\n            List<ITransactionTestGrain> transaction3Members = new List<ITransactionTestGrain>(new[] { grain3, grain4 });\n            List<ITransactionTestGrain> transaction4Members = new List<ITransactionTestGrain>(new[] { grain4, grain5 });\n\n            ITransactionCoordinatorGrain coordinator1 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator2 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator3 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator4 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            await Task.WhenAll(\n                coordinator1.MultiGrainAdd(transaction1Members, expected),\n                coordinator2.MultiGrainAdd(transaction2Members, expected),\n                coordinator3.MultiGrainAdd(transaction3Members, expected),\n                coordinator4.MultiGrainAdd(transaction4Members, expected));\n\n            int[] actual = await grain1.Get();\n            actual.FirstOrDefault().Should().Be(expected);\n            actual = await grain2.Get();\n            actual.FirstOrDefault().Should().Be(expected*2);\n            actual = await grain3.Get();\n            actual.FirstOrDefault().Should().Be(expected*2);\n            actual = await grain4.Get();\n            actual.FirstOrDefault().Should().Be(expected*2);\n            actual = await grain5.Get();\n            actual.FirstOrDefault().Should().Be(expected);\n        }\n\n        /// <summary>\n        /// Single transaction containing two grains is dependent on two other transaction, one from each grain\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        public virtual async Task TransactionTreeTest(string grainStates)\n        {\n            const int expected = 5;\n\n            ITransactionTestGrain grain1 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain2 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain3 = RandomTestGrain(grainStates);\n            ITransactionTestGrain grain4 = RandomTestGrain(grainStates);\n            List<ITransactionTestGrain> transaction1Members = new List<ITransactionTestGrain>(new[] { grain1, grain2 });\n            List<ITransactionTestGrain> transaction2Members = new List<ITransactionTestGrain>(new[] { grain3, grain4 });\n            List<ITransactionTestGrain> transaction3Members = new List<ITransactionTestGrain>(new[] { grain2, grain3 });\n\n            ITransactionCoordinatorGrain coordinator1 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator2 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            ITransactionCoordinatorGrain coordinator3 = this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid());\n            await Task.WhenAll(\n                coordinator1.MultiGrainAdd(transaction1Members, expected),\n                coordinator2.MultiGrainAdd(transaction2Members, expected),\n                coordinator3.MultiGrainAdd(transaction3Members, expected));\n\n            int[] actual = await grain1.Get();\n            actual.FirstOrDefault().Should().Be(expected);\n            actual = await grain2.Get();\n            actual.FirstOrDefault().Should().Be(expected*2);\n            actual = await grain3.Get();\n            actual.FirstOrDefault().Should().Be(expected*2);\n            actual = await grain4.Get();\n            actual.FirstOrDefault().Should().Be(expected);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/TransactionRecoveryTestsRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing Orleans.Transactions.TestKit.Correctnesss;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class TransactionRecoveryTestsRunner : TransactionTestRunnerBase\n    {\n        private static readonly TimeSpan RecoveryTimeout = TimeSpan.FromSeconds(60);\n        // reduce to or remove once we fix timeouts abort\n        private static readonly TimeSpan RetryDelay = TimeSpan.FromSeconds(1);\n\n        private readonly TestCluster testCluster;\n        private readonly ILogger logger;\n\n        protected void Log(string message)\n        {\n            this.testOutput($\"[{DateTime.Now}] {message}\");\n            this.logger.LogInformation(message);\n        }\n\n        private class ExpectedGrainActivity\n        {\n            public ExpectedGrainActivity(Guid grainId, ITransactionalBitArrayGrain grain)\n            {\n                this.GrainId = grainId;\n                this.Grain = grain;\n            }\n            public Guid GrainId { get; }\n            public ITransactionalBitArrayGrain Grain { get; }\n            public BitArrayState Expected { get; } = new BitArrayState();\n            public BitArrayState Unambiguous { get; } = new BitArrayState();\n            public List<BitArrayState> Actual { get; set; }\n            public async Task GetActual()\n            {\n                try\n                {\n                    this.Actual = await this.Grain.Get();\n                } catch(Exception)\n                {\n                    // allow a single retry\n                    await Task.Delay(TimeSpan.FromSeconds(30));\n                    this.Actual = await this.Grain.Get();\n                }\n            }\n        }\n\n        public TransactionRecoveryTestsRunner(TestCluster testCluster, Action<string> testOutput)\n            : base(testCluster.GrainFactory, testOutput)\n        {\n            this.testCluster = testCluster;\n            this.logger = this.testCluster.ServiceProvider.GetService<ILogger<TransactionRecoveryTestsRunner>>();\n        }\n\n        public virtual Task TransactionWillRecoverAfterRandomSiloGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return TransactionWillRecoverAfterRandomSiloFailure(transactionTestGrainClassName, concurrent, true);\n        }\n\n        public virtual Task TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return TransactionWillRecoverAfterRandomSiloFailure(transactionTestGrainClassName, concurrent, false);\n        }\n\n        protected virtual async Task TransactionWillRecoverAfterRandomSiloFailure(string transactionTestGrainClassName, int concurrent, bool gracefulShutdown)\n        {\n            var endOnCommand = new[] { false };\n            var index = new[] { 0 };\n            int getIndex() => index[0]++;\n            List<ExpectedGrainActivity> txGrains = Enumerable.Range(0, concurrent * 2)\n                .Select(i => Guid.NewGuid())\n                .Select(grainId => new ExpectedGrainActivity(grainId, TestGrain<ITransactionalBitArrayGrain>(transactionTestGrainClassName, grainId)))\n                .ToList();\n            //ping all grains to activate them\n            await WakeupGrains(txGrains.Select(g=>g.Grain).ToList());\n            List<ExpectedGrainActivity>[] transactionGroups = txGrains\n                .Select((txGrain, i) => new { index = i, value = txGrain })\n                .GroupBy(v => v.index / 2)\n                .Select(g => g.Select(i => i.value).ToList())\n                .ToArray();\n            var txSucceedBeforeInterruption = await AllTxSucceed(transactionGroups, getIndex());\n            txSucceedBeforeInterruption.Should().BeTrue();\n            await ValidateResults(txGrains, transactionGroups);\n\n            // have transactions in flight when silo goes down\n            Task<bool> succeeding = RunWhileSucceeding(transactionGroups, getIndex, endOnCommand);\n            await Task.Delay(TimeSpan.FromSeconds(2));\n\n            var siloToTerminate = this.testCluster.Silos[Random.Shared.Next(this.testCluster.Silos.Count)];\n            this.Log($\"Warmup transaction succeeded. {(gracefulShutdown ? \"Stopping\" : \"Killing\")} silo {siloToTerminate.SiloAddress} ({siloToTerminate.Name}) and continuing\");\n\n            if (gracefulShutdown)\n                await this.testCluster.StopSiloAsync(siloToTerminate);\n            else\n                await this.testCluster.KillSiloAsync(siloToTerminate);\n\n            this.Log(\"Waiting for transactions to stop completing successfully\");\n            var complete = await Task.WhenAny(succeeding, Task.Delay(TimeSpan.FromSeconds(30)));\n            endOnCommand[0] = true;\n            bool endedOnCommand = await succeeding;\n            if (endedOnCommand) this.Log($\"No transactions failed due to silo death.  Test may not be valid\");\n\n            this.Log($\"Waiting for system to recover. Performed {index[0]} transactions on each group.\");\n            var transactionGroupsRef = new[] { transactionGroups };\n            await TestingUtils.WaitUntilAsync(lastTry => CheckTxResult(transactionGroupsRef, getIndex, lastTry), RecoveryTimeout, RetryDelay);\n            this.Log($\"Recovery completed. Performed {index[0]} transactions on each group. Validating results.\");\n            await ValidateResults(txGrains, transactionGroups);\n        }\n\n        private static Task WakeupGrains(List<ITransactionalBitArrayGrain> grains)\n        {\n            var tasks =  new List<Task>();\n            foreach (var grain in grains)\n            {\n                tasks.Add(grain.Ping());\n            }\n            return Task.WhenAll(tasks);\n        }\n\n        private async Task<bool> RunWhileSucceeding(List<ExpectedGrainActivity>[] transactionGroups, Func<int> getIndex, bool[] end)\n        {\n            // Loop until failure, or getTime changes\n            while (await AllTxSucceed(transactionGroups, getIndex()) && !end[0])\n            {\n            }\n            return end[0];\n        }\n\n        private async Task<bool> CheckTxResult(List<ExpectedGrainActivity>[][] transactionGroupsRef, Func<int> getIndex, bool assertIsTrue)\n        {\n            // only retry failed transactions\n            transactionGroupsRef[0] = await RunAllTxReportFailed(transactionGroupsRef[0], getIndex());\n            bool succeed = transactionGroupsRef[0] == null;\n            this.Log($\"All transactions succeed after interruption : {succeed}\");\n            if (assertIsTrue)\n            {\n                //consider it recovered if all tx succeed\n                this.Log($\"Final check : {succeed}\");\n                succeed.Should().BeTrue();\n                return succeed;\n            }\n            else\n            {\n                return succeed;\n            }\n        }\n\n        // Runs all transactions and returns failed;\n        private async Task<List<ExpectedGrainActivity>[]> RunAllTxReportFailed(List<ExpectedGrainActivity>[] transactionGroups, int index)\n        {\n            List<Task> tasks = transactionGroups\n                .Select(p => SetBit(p, index))\n                .ToList();\n            try\n            {\n                await Task.WhenAll(tasks);\n                return null;\n            }\n            catch (Exception)\n            {\n                // Collect the indices of the transaction groups which failed their transactions for diagnostics.\n                List<ExpectedGrainActivity>[] failedGroups = tasks.Select((task, i) => new { task, i }).Where(t => t.task.IsFaulted).Select(t => transactionGroups[t.i]).ToArray();\n                this.Log($\"Some transactions failed. Index: {index}. {failedGroups.Length} out of {tasks.Count} failed. Failed groups: {string.Join(\", \", failedGroups.Select(transactionGroup => string.Join(\":\", transactionGroup.Select(a => a.GrainId))))}\");\n                return failedGroups;\n            }\n        }\n\n        private async Task<bool> AllTxSucceed(List<ExpectedGrainActivity>[] transactionGroups, int index)\n        {\n            // null return indicates none failed\n            return (await RunAllTxReportFailed(transactionGroups, index) == null);\n        }\n\n        private async Task SetBit(List<ExpectedGrainActivity> grains, int index)\n        {\n            try\n            {\n                await this.grainFactory.GetGrain<ITransactionCoordinatorGrain>(Guid.NewGuid()).MultiGrainSetBit(grains.Select(v => v.Grain).ToList(), index);\n                grains.ForEach(g =>\n                {\n                    g.Expected.Set(index, true);\n                    g.Unambiguous.Set(index, true);\n                });\n            }\n            catch (OrleansTransactionAbortedException e)\n            {\n                this.Log($\"Some transactions failed. Index: {index}: Exception: {e.GetType().Name}\");\n                grains.ForEach(g =>\n                {\n                    g.Expected.Set(index, false);\n                    g.Unambiguous.Set(index, true);\n                });\n                throw;\n            }\n            catch (Exception e)\n            {\n                this.Log($\"Ambiguous transaction failure. Index: {index}: Exception: {e.GetType().Name}\");\n                grains.ForEach(g =>\n                {\n                    g.Expected.Set(index, false);\n                    g.Unambiguous.Set(index, false);\n                });\n                throw;\n            }\n        }\n\n        private async Task ValidateResults(List<ExpectedGrainActivity> txGrains, List<ExpectedGrainActivity>[] transactionGroups)\n        {\n            await Task.WhenAll(txGrains.Select(a => a.GetActual()));\n            this.Log($\"Got all {txGrains.Count} actual values\");\n\n            bool pass = true;\n            foreach (List<ExpectedGrainActivity> transactionGroup in transactionGroups)\n            {\n                if (transactionGroup.Count == 0) continue;\n                BitArrayState first = transactionGroup[0].Actual.FirstOrDefault();\n                foreach (ExpectedGrainActivity activity in transactionGroup.Skip(1))\n                {\n                    BitArrayState actual = activity.Actual.FirstOrDefault();\n                    BitArrayState difference = first ^ actual;\n                    if (difference.Value.Any(v => v != 0))\n                    {\n                        this.Log($\"Activity on grain {activity.GrainId} did not match activity on {transactionGroup[0].GrainId}:\\n\"\n                                 + $\"{first} ^\\n\"\n                                 + $\"{actual} = \\n\"\n                                 + $\"{difference}\\n\"\n                                 + $\"Activation: {activity.GrainId}\");\n                        pass = false;\n                    }\n\n                }\n            }\n\n            int i = 0;\n            foreach (ExpectedGrainActivity activity in txGrains)\n            {\n                BitArrayState expected = activity.Expected;\n                BitArrayState unambiguous = activity.Unambiguous;\n                BitArrayState unambuguousExpected = expected & unambiguous;\n                List<BitArrayState> actual = activity.Actual;\n                BitArrayState first = actual.FirstOrDefault();\n                if (first == null)\n                {\n                    this.Log($\"No activity for {i} ({activity.GrainId})\");\n                    pass = false;\n                    continue;\n                }\n\n                int j = 0;\n                foreach (BitArrayState result in actual)\n                {\n                    // skip comparing first to first.\n                    if (ReferenceEquals(first, result)) continue;\n                    // Check if each state is identical to the first state.\n                    var difference = result ^ first;\n                    if (difference.Value.Any(v => v != 0))\n                    {\n                        this.Log($\"Activity on grain {i}, state {j} did not match 'first':\\n\"\n                                 + $\"  {first}\\n\"\n                                 + $\"^ {result}\\n\"\n                                 + $\"= {difference}\\n\"\n                                 + $\"Activation: {activity.GrainId}\");\n                        pass = false;\n                    }\n\n                    j++;\n                }\n\n                // Check if the unambiguous portions of the first match.\n                var unambiguousFirst = first & unambiguous;\n                var unambiguousDifference = unambuguousExpected ^ unambiguousFirst;\n\n                if (unambiguousDifference.Value.Any(v => v != 0))\n                {\n                    this.Log(\n                        $\"First state on grain {i} did not match 'expected':\\n\"\n                        + $\"  {unambuguousExpected}\\n\"\n                        + $\"^ {unambiguousFirst}\\n\"\n                        + $\"= {unambiguousDifference}\\n\"\n                        + $\"Activation: {activity.GrainId}\");\n                    pass = false;\n                }\n\n                i++;\n            }\n            this.Log($\"Report complete : {pass}\");\n            pass.Should().BeTrue();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TestRunners/TransactionalStateStorageTestRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\nusing AwesomeAssertions.Equivalency;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public abstract class TransactionalStateStorageTestRunner<TState> : TransactionTestRunnerBase\n        where TState : class, new()\n    {\n        protected Func<Task<ITransactionalStateStorage<TState>>> stateStorageFactory;\n        protected Func<int, TState> stateFactory;\n        protected Func<EquivalencyOptions<TState>, EquivalencyOptions<TState>> assertConfig;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"stateStorageFactory\">factory to create ITransactionalStateStorage, the test runner are assuming the state \n        /// in storage is empty when ITransactionalStateStorage was created </param>\n        /// <param name=\"stateFactory\">factory to create TState for test</param>\n        /// <param name=\"grainFactory\">grain Factory needed for test runner</param>\n        /// <param name=\"testOutput\">test output to helpful messages</param>\n        /// <param name=\"assertConfig\">A reference to the AwesomeAssertions.Equivalency.EquivalencyOptions`1\n        ///     configuration object that can be used to influence the way the object graphs\n        ///     are compared</param>\n        protected TransactionalStateStorageTestRunner(Func<Task<ITransactionalStateStorage<TState>>> stateStorageFactory, Func<int, TState> stateFactory, \n            IGrainFactory grainFactory, Action<string> testOutput,\n            Func<EquivalencyOptions<TState>, EquivalencyOptions<TState>> assertConfig = null)\n            :base(grainFactory, testOutput)\n        {\n            this.stateStorageFactory = stateStorageFactory;\n            this.stateFactory = stateFactory;\n            this.assertConfig = assertConfig;\n        }\n\n        public virtual async Task FirstTime_Load_ShouldReturnEmptyLoadResponse()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var response = await stateStorage.Load();\n            var defaultStateValue = new TState();\n\n            //Assertion\n            response.Should().NotBeNull();\n            response.ETag.Should().BeNull();\n            response.CommittedSequenceId.Should().Be(0);\n            AssertTState(response.CommittedState, defaultStateValue);\n            response.PendingStates.Should().BeEmpty();\n        }\n\n        private static readonly List<PendingTransactionState<TState>> emptyPendingStates = new List<PendingTransactionState<TState>>();\n  \n        public virtual async Task StoreWithoutChanges()\n        {\n            var stateStorage = await this.stateStorageFactory();\n\n            // load first time\n            var loadresponse = await stateStorage.Load();\n\n            // store without any changes\n            var etag1 = await stateStorage.Store(loadresponse.ETag, loadresponse.Metadata, emptyPendingStates, null, null);\n\n            // load again\n            loadresponse = await stateStorage.Load();\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Should().BeEmpty();\n            loadresponse.ETag.Should().Be(etag1);\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Should().BeEmpty();\n\n            // update metadata, then write back\n            var now = DateTime.UtcNow;\n            var cr = MakeCommitRecords(2, 2);\n            var metadata = new TransactionalStateMetaData() { TimeStamp = now, CommitRecords = cr };\n            var etag2 = await stateStorage.Store(etag1, metadata, emptyPendingStates, null, null);\n\n            // load again, check content\n            loadresponse = await stateStorage.Load();\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.Metadata.TimeStamp.Should().Be(now);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(cr.Count);\n            loadresponse.ETag.Should().Be(etag2);\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Should().BeEmpty();\n        }\n\n        public virtual async Task WrongEtags()\n        {\n            var stateStorage = await this.stateStorageFactory();\n\n            // load first time\n            var loadresponse = await stateStorage.Load();\n\n            // store with wrong e-tag, must fail\n            try\n            {\n                var etag1 = await stateStorage.Store(\"wrong-etag\", loadresponse.Metadata, emptyPendingStates, null, null);\n                throw new Exception(\"storage did not catch e-tag mismatch\");\n            }\n            catch (Exception) { }\n\n            // load again\n            loadresponse = await stateStorage.Load();\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Should().BeEmpty();\n            loadresponse.ETag.Should().BeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Should().BeEmpty();\n\n            // update timestamp in metadata, then write back with correct e-tag\n            var now = DateTime.UtcNow;\n            var cr = MakeCommitRecords(2,2);\n            var metadata = new TransactionalStateMetaData() { TimeStamp = now, CommitRecords = cr };\n            var etag2 = await stateStorage.Store(null, metadata, emptyPendingStates, null, null);\n\n            // update timestamp in metadata, then write back with wrong e-tag, must fail\n            try\n            {\n                var now2 = DateTime.UtcNow;\n                var metadata2 = new TransactionalStateMetaData() { TimeStamp = now2, CommitRecords = MakeCommitRecords(3,3) };\n                await stateStorage.Store(null, metadata, emptyPendingStates, null, null);\n                throw new Exception(\"storage did not catch e-tag mismatch\");\n            }\n            catch (Exception) { }\n\n            // load again, check content\n            loadresponse = await stateStorage.Load();\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.Metadata.TimeStamp.Should().Be(now);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(cr.Count);\n            loadresponse.ETag.Should().Be(etag2);\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Should().BeEmpty();\n        }\n\n        private void AssertTState(TState actual, TState expected)\n        {\n            if(assertConfig == null)\n                actual.Should().BeEquivalentTo(expected);\n            else\n                actual.Should().BeEquivalentTo(expected, assertConfig);\n        }\n\n        private static PendingTransactionState<TState> MakePendingState(long seqno, TState val, bool tm)\n        {\n            var result = new PendingTransactionState<TState>()\n            {\n                SequenceId = seqno,\n                TimeStamp = DateTime.UtcNow,\n                TransactionId = Guid.NewGuid().ToString(),\n                TransactionManager = tm ? default : MakeParticipantId(),\n                State = new TState()\n            };\n            result.State = val;\n            return result;\n        }\n\n        private static ParticipantId MakeParticipantId()\n        {\n            return new ParticipantId(\n                                    \"tm\",\n                                    null,\n                                    // (GrainReference) grainFactory.GetGrain<ITransactionTestGrain>(Guid.NewGuid(), TransactionTestConstants.SingleStateTransactionalGrain),\n                                    ParticipantId.Role.Resource | ParticipantId.Role.Manager);\n        }\n\n        private static Dictionary<Guid, CommitRecord> MakeCommitRecords(int count, int size)\n        {\n            var result = new Dictionary<Guid, CommitRecord>();\n            for (int j = 0; j < size; j++)\n            {\n                var r = new CommitRecord()\n                {\n                    Timestamp = DateTime.UtcNow,\n                    WriteParticipants = new List<ParticipantId>(),\n                };\n                for (int i = 0; i < size; i++)\n                {\n                    r.WriteParticipants.Add(MakeParticipantId());\n                }\n                result.Add(Guid.NewGuid(), r);\n            }\n            return result;\n        }\n\n        private async Task PrepareOne()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedState = this.stateFactory(123);\n            var pendingstate = MakePendingState(1, expectedState, false);\n            _ = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate }, null, null);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(1);\n            loadresponse.PendingStates[0].SequenceId.Should().Be(1);\n            loadresponse.PendingStates[0].TimeStamp.Should().Be(pendingstate.TimeStamp);\n            loadresponse.PendingStates[0].TransactionManager.Should().Be(pendingstate.TransactionManager);\n            loadresponse.PendingStates[0].TransactionId.Should().Be(pendingstate.TransactionId);\n            AssertTState(loadresponse.PendingStates[0].State, expectedState);\n        }\n\n        public virtual async Task ConfirmOne(bool useTwoSteps)\n        { \n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedState = this.stateFactory(123);\n            var pendingstate = MakePendingState(1, expectedState, false);\n\n            if (useTwoSteps)\n            {\n                etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate }, null, null);\n                _ = await stateStorage.Store(etag, metadata, emptyPendingStates, 1, null);\n            }\n            else\n            {\n                _ = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate }, 1, null);\n            }\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(1);\n            loadresponse.PendingStates.Count.Should().Be(0);\n            AssertTState(loadresponse.CommittedState, expectedState);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n        }\n\n        public virtual async Task CancelOne()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n            \n            var pendingstate = MakePendingState(1, this.stateFactory(123), false);\n\n            etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate }, null, null);\n            _ = await stateStorage.Store(etag, metadata, emptyPendingStates, null, 0);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(0);\n            AssertTState(loadresponse.CommittedState,initialstate);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n        }\n\n        public virtual async Task ReplaceOne()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedState1 = this.stateFactory(123);\n            var expectedState2 = this.stateFactory(456);\n            var pendingstate1 = MakePendingState(1, expectedState1, false);\n            var pendingstate2 = MakePendingState(1, expectedState2, false);\n\n            etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate1 }, null, null);\n            _ = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate2 }, null, null);\n      \n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(1);\n            loadresponse.PendingStates[0].SequenceId.Should().Be(1);\n            loadresponse.PendingStates[0].TimeStamp.Should().Be(pendingstate2.TimeStamp);\n            loadresponse.PendingStates[0].TransactionManager.Should().Be(pendingstate2.TransactionManager);\n            loadresponse.PendingStates[0].TransactionId.Should().Be(pendingstate2.TransactionId);\n            AssertTState(loadresponse.PendingStates[0].State,expectedState2);\n        }\n\n\n        public virtual async Task ConfirmOneAndCancelOne(bool useTwoSteps = false, bool reverseOrder = false)\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedState = this.stateFactory(123);\n            var pendingstate1 = MakePendingState(1, expectedState, false);\n            var pendingstate2 = MakePendingState(2, this.stateFactory(456), false);\n\n            etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate1, pendingstate2 }, null, null);\n\n            if (useTwoSteps)\n            {\n                if (reverseOrder)\n                {\n                    etag = await stateStorage.Store(etag, metadata, emptyPendingStates, null, 1);\n                    _ = await stateStorage.Store(etag, metadata, emptyPendingStates, 1, null);\n                }\n                else\n                {\n                    etag = await stateStorage.Store(etag, metadata, emptyPendingStates, 1, null);\n                    _ = await stateStorage.Store(etag, metadata, emptyPendingStates, null, 1);\n                }\n            }\n            else\n            {\n                _ = await stateStorage.Store(etag, metadata, emptyPendingStates, 1, 1);\n            }\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(1);\n            loadresponse.PendingStates.Count.Should().Be(0);\n            AssertTState(loadresponse.CommittedState,expectedState);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n        }\n\n        public virtual async Task PrepareMany(int count)\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var pendingstates = new List<PendingTransactionState<TState>>();\n            var expectedStates = new List<TState>();\n            for (int i = 0; i < count; i++)\n            {\n                expectedStates.Add(this.stateFactory(i * 1000));\n            }\n\n            for (int i = 0; i < count; i++)\n            {\n                pendingstates.Add(MakePendingState(i + 1, expectedStates[i], false));\n            }\n            _ = await stateStorage.Store(etag, metadata, pendingstates, null, null);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(count);\n\n            for (int i = 0; i < count; i++)\n            {\n                loadresponse.PendingStates[i].SequenceId.Should().Be(i+1);\n                loadresponse.PendingStates[i].TimeStamp.Should().Be(pendingstates[i].TimeStamp);\n                loadresponse.PendingStates[i].TransactionManager.Should().Be(pendingstates[i].TransactionManager);\n                loadresponse.PendingStates[i].TransactionId.Should().Be(pendingstates[i].TransactionId);\n                AssertTState(loadresponse.PendingStates[i].State,expectedStates[i]);\n            }\n        }\n\n        public virtual async Task ConfirmMany(int count, bool useTwoSteps)\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedStates = new List<TState>();\n            for (int i = 0; i < count; i++)\n            {\n                expectedStates.Add(this.stateFactory(i * 1000));\n            }\n            var pendingstates = new List<PendingTransactionState<TState>>();\n            for (int i = 0; i < count; i++)\n            {\n                pendingstates.Add(MakePendingState(i + 1, expectedStates[i], false));\n            }\n\n            if (useTwoSteps)\n            {\n                etag = await stateStorage.Store(etag, metadata, pendingstates, null, null);\n                _ = await stateStorage.Store(etag, metadata, emptyPendingStates, count, null);\n            }\n            else\n            {\n                _ = await stateStorage.Store(etag, metadata, pendingstates, count, null);\n            }\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(count);\n            loadresponse.PendingStates.Count.Should().Be(0);\n            AssertTState(loadresponse.CommittedState,expectedStates[count - 1]);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n        }\n\n        public virtual async Task CancelMany(int count)\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedStates = new List<TState>();\n            for (int i = 0; i < count; i++)\n            {\n                expectedStates.Add(this.stateFactory(i * 1000));\n            }\n\n            var pendingstates = new List<PendingTransactionState<TState>>();\n            for (int i = 0; i < count; i++)\n            {\n                pendingstates.Add(MakePendingState(i + 1, expectedStates[i], false));\n            }\n\n            etag = await stateStorage.Store(etag, metadata, pendingstates, null, null);\n            _ = await stateStorage.Store(etag, metadata, emptyPendingStates, null, 0);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(0);\n            AssertTState(loadresponse.CommittedState,initialstate);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n        }\n\n        public virtual async Task ReplaceMany(int count)\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var expectedStates1 = new List<TState>();\n            for (int i = 0; i < count; i++)\n            {\n                expectedStates1.Add(this.stateFactory(i * 1000 + 1));\n            }\n\n            var expectedStates2 = new List<TState>();\n            for (int i = 0; i < count; i++)\n            {\n                expectedStates2.Add(this.stateFactory(i * 1000));\n            }\n\n            var pendingstates1 = new List<PendingTransactionState<TState>>();\n            for (int i = 0; i < count; i++)\n            {\n                pendingstates1.Add(MakePendingState(i + 1, expectedStates1[i], false));\n            }\n            var pendingstates2 = new List<PendingTransactionState<TState>>();\n            for (int i = 0; i < count; i++)\n            {\n                pendingstates2.Add(MakePendingState(i + 1, expectedStates2[i], false));\n            }\n\n            etag = await stateStorage.Store(etag, metadata, pendingstates1, null, null);\n            _ = await stateStorage.Store(etag, metadata, pendingstates2, null, null);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(count);\n\n            for (int i = 0; i < count; i++)\n            {\n                loadresponse.PendingStates[i].SequenceId.Should().Be(i + 1);\n                loadresponse.PendingStates[i].TimeStamp.Should().Be(pendingstates2[i].TimeStamp);\n                loadresponse.PendingStates[i].TransactionManager.Should().Be(pendingstates2[i].TransactionManager);\n                loadresponse.PendingStates[i].TransactionId.Should().Be(pendingstates2[i].TransactionId);\n                AssertTState(loadresponse.PendingStates[i].State, expectedStates2[i]);\n            }\n        }\n\n\n        public virtual async Task GrowingBatch()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n            \n            var pendingstate1 = MakePendingState(1, this.stateFactory(11), false);\n            var pendingstate2 = MakePendingState(2, this.stateFactory(22), false);\n            var pendingstate3a = MakePendingState(3, this.stateFactory(333), false);\n            var pendingstate4a = MakePendingState(4, this.stateFactory(444), false);\n            var pendingstate3b = MakePendingState(3, this.stateFactory(33), false);\n            var pendingstate4b = MakePendingState(4, this.stateFactory(44), false);\n            var pendingstate5 = MakePendingState(5, this.stateFactory(55), false);\n\n            var expectedState6 = this.stateFactory(66);\n            var pendingstate6 = MakePendingState(6, expectedState6, false);\n            var expectedState7 = this.stateFactory(77);\n            var pendingstate7 = MakePendingState(7, expectedState7, false);\n            var expectedState8 = this.stateFactory(88);\n            var pendingstate8 = MakePendingState(8, expectedState8, false);\n           \n\n            // prepare 1,2,3a,4a\n            etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate1, pendingstate2, pendingstate3a, pendingstate4a}, null, null);\n\n            // replace 3b,4b, prepare 5, 6, 7, 8 confirm 1, 2, 3b, 4b, 5, 6\n            _ = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate3b, pendingstate4b, pendingstate5, pendingstate6, pendingstate7, pendingstate8 }, 6, null);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(6);\n            AssertTState(loadresponse.CommittedState, expectedState6);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(2);\n            loadresponse.PendingStates[0].SequenceId.Should().Be(7);\n            loadresponse.PendingStates[0].TimeStamp.Should().Be(pendingstate7.TimeStamp);\n            loadresponse.PendingStates[0].TransactionManager.Should().Be(pendingstate7.TransactionManager);\n            loadresponse.PendingStates[0].TransactionId.Should().Be(pendingstate7.TransactionId);\n            AssertTState(loadresponse.PendingStates[0].State, expectedState7);\n            loadresponse.PendingStates[1].SequenceId.Should().Be(8);\n            loadresponse.PendingStates[1].TimeStamp.Should().Be(pendingstate8.TimeStamp);\n            loadresponse.PendingStates[1].TransactionManager.Should().Be(pendingstate8.TransactionManager);\n            loadresponse.PendingStates[1].TransactionId.Should().Be(pendingstate8.TransactionId);\n            AssertTState(loadresponse.PendingStates[1].State, expectedState8);\n        }\n\n        public virtual async Task ShrinkingBatch()\n        {\n            var stateStorage = await this.stateStorageFactory();\n            var loadresponse = await stateStorage.Load();\n            var etag = loadresponse.ETag;\n            var metadata = loadresponse.Metadata;\n            var initialstate = loadresponse.CommittedState;\n\n            var pendingstate1 = MakePendingState(1, this.stateFactory(11), false);\n            var pendingstate2 = MakePendingState(2, this.stateFactory(22), false);\n            var pendingstate3a = MakePendingState(3, this.stateFactory(333), false);\n            var pendingstate4a = MakePendingState(4, this.stateFactory(444), false);\n            var pendingstate5 = MakePendingState(5, this.stateFactory(55), false);\n            var pendingstate6 = MakePendingState(6, this.stateFactory(66), false);\n            var pendingstate7 = MakePendingState(7, this.stateFactory(77), false);\n            var pendingstate8 = MakePendingState(8, this.stateFactory(88), false);\n            var expectedState3b = this.stateFactory(33);\n            var pendingstate3b = MakePendingState(3, expectedState3b, false);\n            var expectedState4b = this.stateFactory(44);\n            var pendingstate4b = MakePendingState(4, expectedState4b, false);\n\n\n            // prepare 1,2,3a,4a, 5, 6, 7, 8\n            etag = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate1, pendingstate2, pendingstate3a, pendingstate4a, pendingstate5, pendingstate6, pendingstate7, pendingstate8 }, null, null);\n\n            // replace 3b,4b, confirm 1, 2, 3b, cancel 5, 6, 7, 8\n            _ = await stateStorage.Store(etag, metadata, new List<PendingTransactionState<TState>>() { pendingstate3b, pendingstate4b }, 3, 4);\n\n            loadresponse = await stateStorage.Load();\n            _ = loadresponse.ETag;\n            _ = loadresponse.Metadata;\n\n            loadresponse.Should().NotBeNull();\n            loadresponse.Metadata.Should().NotBeNull();\n            loadresponse.CommittedSequenceId.Should().Be(3);\n            AssertTState(loadresponse.CommittedState, expectedState3b);\n            loadresponse.Metadata.TimeStamp.Should().Be(default);\n            loadresponse.Metadata.CommitRecords.Count.Should().Be(0);\n            loadresponse.PendingStates.Count.Should().Be(1);\n            loadresponse.PendingStates[0].SequenceId.Should().Be(4);\n            loadresponse.PendingStates[0].TimeStamp.Should().Be(pendingstate4b.TimeStamp);\n            loadresponse.PendingStates[0].TransactionManager.Should().Be(pendingstate4b.TransactionManager);\n            loadresponse.PendingStates[0].TransactionId.Should().Be(pendingstate4b.TransactionId);\n            AssertTState(loadresponse.PendingStates[0].State, expectedState4b);\n        }\n        \n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TransactionTestConstants.cs",
    "content": "﻿\nnamespace Orleans.Transactions.TestKit\n{\n    public static class TransactionTestConstants\n    {\n        /// <summary>\n        /// Max number of grains to include in a transaction for test purposes.  Not a hard limit of the transaction system.\n        /// </summary>\n        public const int MaxCoordinatedTransactions = 8;\n\n        // storage providers\n        public const string TransactionStore = \"TransactionStore\";\n\n        // committer service\n        public const string RemoteCommitService = \"RemoteCommitService\";\n        \n        // grain implementations\n        public const string NoStateTransactionalGrain = \"NoStateTransactionalGrain\";\n        public const string SingleStateTransactionalGrain = \"SingleStateTransactionalGrain\";\n        public const string DoubleStateTransactionalGrain = \"DoubleStateTransactionalGrain\";\n        public const string MaxStateTransactionalGrain = \"MaxStateTransactionalGrain\";\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.Base/TransactionTestRunnerBase.cs",
    "content": "﻿using System;\n\nnamespace Orleans.Transactions.TestKit\n{\n    public class TransactionTestRunnerBase\n    {\n        protected readonly IGrainFactory grainFactory;\n        protected readonly Action<string> testOutput;\n\n        protected TransactionTestRunnerBase(IGrainFactory grainFactory, Action<string> testOutput)\n        {\n            this.grainFactory = grainFactory;\n            this.testOutput = testOutput;\n        }\n\n        protected ITransactionTestGrain RandomTestGrain(string transactionTestGrainClassNames)\n        {\n            return RandomTestGrain<ITransactionTestGrain>(transactionTestGrainClassNames);\n        }\n\n        protected TGrainInterface RandomTestGrain<TGrainInterface>(string transactionTestGrainClassNames)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            return TestGrain<TGrainInterface>(transactionTestGrainClassNames, Guid.NewGuid());\n        }\n\n        protected virtual ITransactionTestGrain TestGrain(string transactionTestGrainClassName, Guid id)\n        {\n            return TestGrain<ITransactionTestGrain>(transactionTestGrainClassName, id);\n        }\n\n        protected virtual TGrainInterface TestGrain<TGrainInterface>(string transactionTestGrainClassName, Guid id)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            return grainFactory.GetGrain<TGrainInterface>(id, $\"{typeof(TGrainInterface).Namespace}.{transactionTestGrainClassName}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/ConsistencyTransactionTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Transactions.TestKit.Consistency;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class ConsistencyTransactionTestRunnerxUnit : ConsistencyTransactionTestRunner\n    {\n        public ConsistencyTransactionTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n            :base(grainFactory, output.WriteLine)\n        {\n        }\n\n        protected override bool StorageAdaptorHasLimitedCommitSpace => true;\n        protected override bool StorageErrorInjectionActive => true;\n\n        [SkippableTheory]\n        // high congestion\n        [InlineData(2, 2, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 3, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 4, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 5, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 2, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 3, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 4, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 5, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 2, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 3, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 4, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 5, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 2, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 3, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 4, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 5, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 2, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 3, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 4, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 5, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(2, 2, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 3, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 4, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 5, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(2, 2, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 3, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 4, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 5, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 2, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 3, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 4, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(2, 5, false, false, ReadWriteDetermination.PerAccess)]\n        // medium congestion\n        [InlineData(30, 2, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 3, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 4, true, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 2, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 3, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 4, true, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 2, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 3, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 4, true, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 2, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 3, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 4, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 2, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 3, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 4, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 5, true, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(30, 2, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 3, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 4, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 5, true, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(30, 2, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 3, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 4, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 5, true, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 2, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 3, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 4, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(30, 5, false, false, ReadWriteDetermination.PerAccess)]\n        // low congestion\n        [InlineData(1000, 2, false, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 3, false, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 4, false, true, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 2, false, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 3, false, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 4, false, true, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 2, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 3, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 4, false, true, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 2, false, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 3, false, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 4, false, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 5, false, false, ReadWriteDetermination.PerGrain)]\n        [InlineData(1000, 2, false, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 3, false, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 4, false, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 5, false, false, ReadWriteDetermination.PerTransaction)]\n        [InlineData(1000, 2, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 3, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 4, false, false, ReadWriteDetermination.PerAccess)]\n        [InlineData(1000, 5, false, false, ReadWriteDetermination.PerAccess)]\n        public override Task RandomizedConsistency(int numGrains, int scale, bool avoidDeadlocks,\n            bool avoidTimeouts, ReadWriteDetermination readwrite)\n        {\n            return base.RandomizedConsistency(numGrains, scale, avoidDeadlocks, avoidTimeouts, readwrite);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/ControlledFaultInjectionTransactionTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public class ControlledFaultInjectionTransactionTestRunnerxUnit : ControlledFaultInjectionTransactionTestRunner\n    {\n        public ControlledFaultInjectionTransactionTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n         : base(grainFactory, output.WriteLine)\n        { }\n\n        [SkippableFact]\n        public override Task SingleGrainReadTransaction()\n        {\n            return base.SingleGrainReadTransaction();\n        }\n\n        [SkippableFact]\n        public override Task SingleGrainWriteTransaction()\n        {\n            return base.SingleGrainWriteTransaction();\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9551\")]\n        [InlineData(TransactionFaultInjectPhase.AfterPrepare, FaultInjectionType.Deactivation)]\n        [InlineData(TransactionFaultInjectPhase.AfterConfirm, FaultInjectionType.Deactivation)]\n        [InlineData(TransactionFaultInjectPhase.AfterPrepared, FaultInjectionType.Deactivation)]\n        [InlineData(TransactionFaultInjectPhase.AfterPrepareAndCommit, FaultInjectionType.Deactivation)]\n        [InlineData(TransactionFaultInjectPhase.BeforePrepare, FaultInjectionType.ExceptionAfterStore)]\n        [InlineData(TransactionFaultInjectPhase.BeforePrepare, FaultInjectionType.ExceptionBeforeStore)]\n        [InlineData(TransactionFaultInjectPhase.BeforeConfirm, FaultInjectionType.ExceptionAfterStore)]\n        [InlineData(TransactionFaultInjectPhase.BeforeConfirm, FaultInjectionType.ExceptionBeforeStore)]\n        [InlineData(TransactionFaultInjectPhase.BeforePrepareAndCommit, FaultInjectionType.ExceptionAfterStore)]\n        [InlineData(TransactionFaultInjectPhase.BeforePrepareAndCommit, FaultInjectionType.ExceptionBeforeStore)]\n        public override Task MultiGrainWriteTransaction_FaultInjection(TransactionFaultInjectPhase injectionPhase, FaultInjectionType injectionType)\n        {\n            return base.MultiGrainWriteTransaction_FaultInjection(injectionPhase, injectionType);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/DisabledTransactionsTestRunner.cs",
    "content": "﻿using Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public class DisabledTransactionsTestRunnerxUnit : DisabledTransactionsTestRunner\n    {\n        protected DisabledTransactionsTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine) { }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.NoStateTransactionalGrain)]\n        public override void TransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName)\n        {\n             base.TransactionGrainsThrowWhenTransactions(transactionTestGrainClassName);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.NoStateTransactionalGrain)]\n        public override void MultiTransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName)\n        {\n            base.MultiTransactionGrainsThrowWhenTransactions(transactionTestGrainClassName);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/GoldenPathTransactionTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class GoldenPathTransactionTestRunnerxUnit : GoldenPathTransactionTestRunner\n    {\n        protected GoldenPathTransactionTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine) { }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task SingleGrainReadTransaction(string grainStates)\n        {\n            return base.SingleGrainReadTransaction(grainStates);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task SingleGrainWriteTransaction(string grainStates)\n        {\n            return base.SingleGrainWriteTransaction(grainStates);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task MultiGrainWriteTransaction(string grainStates, int grainCount)\n        {\n            return base.MultiGrainWriteTransaction(grainStates, grainCount);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task MultiGrainReadWriteTransaction(string grainStates, int grainCount)\n        {\n            return base.MultiGrainReadWriteTransaction(grainStates, grainCount);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task RepeatGrainReadWriteTransaction(string grainStates, int grainCount)\n        {\n            return base.RepeatGrainReadWriteTransaction(grainStates, grainCount);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task MultiWriteToSingleGrainTransaction(string grainStates)\n        {\n            return base.MultiWriteToSingleGrainTransaction(grainStates);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task RWRWTest(string grainStates, int grainCount)\n        {\n            return base.RWRWTest(grainStates, grainCount);\n        }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task WRWRTest(string grainStates, int grainCount)\n        {\n            return base.WRWRTest(grainStates, grainCount);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/GrainFaultTransactionTestRunner.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public class GrainFaultTransactionTestRunnerxUnit : GrainFaultTransactionTestRunner\n    {\n        public GrainFaultTransactionTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine)\n        { }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task AbortTransactionOnExceptions(string grainStates)\n        {\n            return base.AbortTransactionOnExceptions(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task AbortTransactionOnReadOnlyViolatedException(string grainStates)\n        {\n            return base.AbortTransactionOnReadOnlyViolatedException(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task MultiGrainAbortTransactionOnExceptions(string grainStates)\n        {\n            return base.MultiGrainAbortTransactionOnExceptions(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task AbortTransactionExceptionInnerExceptionOnlyContainsOneRootCauseException(string grainStates)\n        {\n            return base.AbortTransactionExceptionInnerExceptionOnlyContainsOneRootCauseException(grainStates);\n        }\n\n        [SkippableTheory()]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task AbortTransactionOnOrphanCalls(string grainStates)\n        {\n            return base.AbortTransactionOnOrphanCalls(grainStates);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/Orleans.Transactions.TestKit.xUnit.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <PackageId>Microsoft.Orleans.Transactions.TestKit.xUnit</PackageId>\n    <Title>Microsoft Orleans Transactions test kit for xUnit</Title>\n    <Description>xUnit testkit library for transactions</Description>\n    <PackageTags>$(PackageTags) TransactionTestKit</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>Orleans.Transactions.TestKit.xUnit</AssemblyName>\n    <RootNamespace>Orleans.Transactions.TestKit.xUnit</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit.extensibility.core\" />\n    <PackageReference Include=\"xunit.extensibility.execution\" />\n    <PackageReference Include=\"xunit.assert\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Orleans.Transactions.TestKit.Base\\Orleans.Transactions.TestKit.Base.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/ScopedTransactionsTestRunnerxUnit.cs",
    "content": "using System.Threading.Tasks;\n\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class ScopedTransactionsTestRunnerxUnit : ScopedTransactionsTestRunner\n    {\n        protected ScopedTransactionsTestRunnerxUnit(IGrainFactory grainFactory, ITransactionClient transactionFrame, ITestOutputHelper output)\n        : base(grainFactory, transactionFrame, output.WriteLine) { }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task CreateTransactionScopeAndSetValue(string grainStates)\n        {\n            return base.CreateTransactionScopeAndSetValue(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task CreateTransactionScopeAndSetValueWithFailure(string grainStates)\n        {\n            return base.CreateTransactionScopeAndSetValueWithFailure(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task CreateTransactionScopeAndSetValueAndAssert(string grainStates)\n        {\n            return base.CreateTransactionScopeAndSetValueAndAssert(grainStates);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task CreateNestedTransactionScopeAndSetValueAndInnerFailAndAssert(string grainStates)\n        {\n            return base.CreateNestedTransactionScopeAndSetValueAndInnerFailAndAssert(grainStates);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/TOCGoldenPathTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class TocGoldenPathTestRunnerxUnit : TocGoldenPathTestRunner\n    {\n        protected TocGoldenPathTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine) { }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9556\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        public override Task MultiGrainWriteTransaction(string grainStates, int grainCount)\n        {\n            return base.MultiGrainWriteTransaction(grainStates, grainCount);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/TocFaultTransactionTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class TocFaultTransactionTestRunnerxUnit : TocFaultTransactionTestRunner\n    {\n        protected TocFaultTransactionTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine) { }\n\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9556\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task MultiGrainWriteTransactionWithCommitFailure(string grainStates, int grainCount)\n        {\n            return base.MultiGrainWriteTransactionWithCommitFailure(grainStates, grainCount);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, TransactionTestConstants.MaxCoordinatedTransactions / 2)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain, 1)]\n        public override Task MultiGrainWriteTransactionWithCommitException(string grainStates, int grainCount)\n        {\n            return base.MultiGrainWriteTransactionWithCommitException(grainStates, grainCount);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/TransactionConcurrencyTestRunner.cs",
    "content": "using System.Threading.Tasks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class TransactionConcurrencyTestRunnerxUnit : TransactionConcurrencyTestRunner\n    {\n        protected TransactionConcurrencyTestRunnerxUnit(IGrainFactory grainFactory, ITestOutputHelper output)\n        : base(grainFactory, output.WriteLine) { }\n\n        /// <summary>\n        /// Two transaction share a single grain\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task SingleSharedGrainTest(string grainStates)\n        {\n            return base.SingleSharedGrainTest(grainStates);\n        }\n\n        /// <summary>\n        /// Chain of transactions, each dependent on the results of the previous\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task TransactionChainTest(string grainStates)\n        {\n            return base.TransactionChainTest(grainStates);\n        }\n\n        /// <summary>\n        /// Single transaction containing two grains is dependent on two other transaction, one from each grain\n        /// </summary>\n        /// <param name=\"grainStates\"></param>\n        /// <returns></returns>\n        [SkippableTheory(Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain)]\n        [InlineData(TransactionTestConstants.MaxStateTransactionalGrain)]\n        public override Task TransactionTreeTest(string grainStates)\n        {\n            return base.TransactionTreeTest(grainStates);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/TransactionRecoveryTestsRunner.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Orleans.TestingHost;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public class TransactionRecoveryTestsRunnerxUnit : TransactionRecoveryTestsRunner\n    {\n        public TransactionRecoveryTestsRunnerxUnit(TestCluster cluster, ITestOutputHelper testOutput)\n            :base(cluster, testOutput.WriteLine)\n        {\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, 30)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, 20)]\n        public override Task TransactionWillRecoverAfterRandomSiloGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return base.TransactionWillRecoverAfterRandomSiloGracefulShutdown(transactionTestGrainClassName, concurrent);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, 30)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, 20)]\n        public override Task TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return base.TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(transactionTestGrainClassName, concurrent);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Orleans.Transactions.TestKit.xUnit/TransactionalStateStorageTestRunner.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing AwesomeAssertions.Equivalency;\nusing Orleans.Transactions.Abstractions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract class TransactionalStateStorageTestRunnerxUnit<TState> : TransactionalStateStorageTestRunner<TState>\n        where TState: class, new()\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"stateStorageFactory\">factory to create ITransactionalStateStorage, the test runner are assuming the state \n        /// in storage is empty when ITransactionalStateStorage was created </param>\n        /// <param name=\"stateFactory\">factory to create TState for test</param>\n        /// <param name=\"grainFactory\">grain Factory needed for test runner</param>\n        /// <param name=\"testOutput\">test output to helpful messages</param>\n        /// <param name=\"assertConfig\">A reference to the AwesomeAssertions.Equivalency.EquivalencyOptions`1\n        ///     configuration object that can be used to influence the way the object graphs\n        ///     are compared</param>\n        public TransactionalStateStorageTestRunnerxUnit(Func<Task<ITransactionalStateStorage<TState>>> stateStorageFactory,\n            Func<int, TState> stateFactory, IGrainFactory grainFactory, ITestOutputHelper testOutput,\n            Func<EquivalencyOptions<TState>, EquivalencyOptions<TState>> assertConfig = null)\n            : base(stateStorageFactory, stateFactory, grainFactory, testOutput.WriteLine, assertConfig)\n        {\n        }\n\n        [Fact]\n        public override Task FirstTime_Load_ShouldReturnEmptyLoadResponse()\n        {\n            return base.FirstTime_Load_ShouldReturnEmptyLoadResponse();\n        }\n\n        [Theory]\n        [InlineData(true)]\n        [InlineData(false)]\n        public override Task ConfirmOne(bool useTwoSteps)\n        {\n            return base.ConfirmOne(useTwoSteps);\n        }\n\n        [Fact]\n        public override Task CancelOne()\n        {\n            return base.CancelOne();\n        }\n\n        [Fact]\n        public override Task ReplaceOne()\n        {\n            return base.ReplaceOne();\n        }\n\n        [Theory]\n        [InlineData(false, false)]\n        [InlineData(true, true)]\n        [InlineData(true, false)]\n        public override Task ConfirmOneAndCancelOne(bool useTwoSteps, bool reverseOrder)\n        {\n            return base.ConfirmOneAndCancelOne(useTwoSteps, reverseOrder);\n        }\n\n        [Fact]\n        public override Task GrowingBatch()\n        {\n            return base.GrowingBatch();\n        }\n\n        [Fact]\n        public override Task ShrinkingBatch()\n        {\n            return base.ShrinkingBatch();\n        }\n\n        [Theory]\n        [InlineData(99)]\n        [InlineData(100)]\n        [InlineData(200)]\n        public override Task PrepareMany(int count)\n        {\n            return base.PrepareMany(count);\n        }\n\n        [Theory]\n        [InlineData(99, true)]\n        [InlineData(99, false)]\n        [InlineData(100, true)]\n        [InlineData(100, false)]\n        [InlineData(200, true)]\n        [InlineData(200, false)]\n        public override Task ConfirmMany(int count, bool useTwoSteps)\n        {\n            return base.ConfirmMany(count, useTwoSteps);\n        }\n\n        [Theory]\n        [InlineData(99)]\n        [InlineData(100)]\n        [InlineData(200)]\n        public override Task CancelMany(int count)\n        {\n            return base.CancelMany(count);\n        }\n\n        [Theory]\n        [InlineData(99)]\n        [InlineData(100)]\n        [InlineData(200)]\n        public override Task ReplaceMany(int count)\n        {\n            return base.ReplaceMany(count);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Hosting/HostingExtensions.ICientBuilder.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Messaging;\nusing Orleans.Clustering.Redis;\nusing StackExchange.Redis;\n\nnamespace Microsoft.Extensions.Hosting\n{\n    /// <summary>\n    /// Hosting extensions for Redis clustering.\n    /// </summary>\n    public static class RedisClusteringIClientBuilderExtensions\n    {\n        /// <summary>\n        /// Configures Redis as the clustering provider.\n        /// </summary>\n        public static IClientBuilder UseRedisClustering(this IClientBuilder builder, Action<RedisClusteringOptions> configuration)\n        {\n            return builder.ConfigureServices(services =>\n            {\n                if (configuration != null)\n                {\n                    services.Configure(configuration);\n                }\n\n                services\n                    .AddRedisClustering()\n                    .AddSingleton<IGatewayListProvider, RedisGatewayListProvider>();\n            });\n        }\n\n        /// <summary>\n        /// Configures Redis as the clustering provider.\n        /// </summary>\n        public static IClientBuilder UseRedisClustering(this IClientBuilder builder, string redisConnectionString)\n        {\n            return builder.ConfigureServices(services => services\n                .Configure<RedisClusteringOptions>(opt =>\n                {\n                    opt.ConfigurationOptions = ConfigurationOptions.Parse(redisConnectionString);\n                })\n                .AddRedisClustering()\n                .AddSingleton<IGatewayListProvider, RedisGatewayListProvider>());\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Hosting/HostingExtensions.ISiloBuilder.cs",
    "content": "using System;\nusing Orleans;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Hosting;\nusing Orleans.Clustering.Redis;\nusing StackExchange.Redis;\n\nnamespace Microsoft.Extensions.Hosting\n{\n    /// <summary>\n    /// Hosting extensions for the Redis clustering provider.\n    /// </summary>\n    public static class RedisClusteringISiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configures Redis as the clustering provider.\n        /// </summary>\n        public static ISiloBuilder UseRedisClustering(this ISiloBuilder builder, Action<RedisClusteringOptions> configuration)\n        {\n            return builder.ConfigureServices(services =>\n            {\n                if (configuration != null)\n                {\n                    services.Configure(configuration);\n                }\n\n                services.AddRedisClustering();\n            });\n        }\n\n        /// <summary>\n        /// Configures Redis as the clustering provider.\n        /// </summary>\n        public static ISiloBuilder UseRedisClustering(this ISiloBuilder builder, string redisConnectionString)\n        {\n            return builder.ConfigureServices(services => services\n                .Configure<RedisClusteringOptions>(options =>\n                {\n                    options.ConfigurationOptions = ConfigurationOptions.Parse(redisConnectionString);\n                })\n                .AddRedisClustering());\n        }\n\n        internal static IServiceCollection AddRedisClustering(this IServiceCollection services)\n        {\n            services.AddSingleton<RedisMembershipTable>();\n            services.AddSingleton<IConfigurationValidator, RedisClusteringOptionsValidator>();\n            services.AddSingleton<IMembershipTable>(sp => sp.GetRequiredService<RedisMembershipTable>());\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Hosting/RedisClusteringProviderBuilder.cs",
    "content": "using Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing StackExchange.Redis;\nusing Orleans.Clustering.Redis.Hosting;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\n[assembly: RegisterProvider(\"Redis\", \"Clustering\", \"Silo\", typeof(RedisClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"AzureRedisCache\", \"Clustering\", \"Silo\", typeof(RedisClusteringProviderBuilder))]\n\n[assembly: RegisterProvider(\"Redis\", \"Clustering\", \"Client\", typeof(RedisClusteringProviderBuilder))]\n[assembly: RegisterProvider(\"AzureRedisCache\", \"Clustering\", \"Client\", typeof(RedisClusteringProviderBuilder))]\n\nnamespace Orleans.Clustering.Redis.Hosting;\n\ninternal sealed class RedisClusteringProviderBuilder : IProviderBuilder<ISiloBuilder>, IProviderBuilder<IClientBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseRedisClustering(_ => { });\n        builder.Services.AddOptions<RedisClusteringOptions>()\n            .Configure<IServiceProvider>((options, services) =>\n            {\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a connection multiplexer instance by name.\n                    var multiplexer = services.GetRequiredKeyedService<IConnectionMultiplexer>(serviceKey);\n                    options.CreateMultiplexer = _ => Task.FromResult(multiplexer);\n                    options.ConfigurationOptions = new ConfigurationOptions();\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                    }\n                }\n            });\n    }\n\n    public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseRedisClustering(_ => { });\n        builder.Services.AddOptions<RedisClusteringOptions>()\n            .Configure<IServiceProvider>((options, services) =>\n            {\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a connection multiplexer instance by name.\n                    var multiplexer = services.GetRequiredKeyedService<IConnectionMultiplexer>(serviceKey);\n                    options.CreateMultiplexer = _ => Task.FromResult(multiplexer);\n                    options.ConfigurationOptions = new ConfigurationOptions();\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                    }\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Orleans.Clustering.Redis.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Clustering.Redis</PackageId>\n    <Title>Microsoft Orleans Clustering Redis Provider</Title>\n    <Description>Microsoft Orleans Clustering implementation that uses Redis</Description>\n    <PackageTags>$(PackageTags) Redis Clustering</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Options.ConfigurationExtensions\" />\n\t  <PackageReference Include=\"StackExchange.Redis\" />\n\t  <PackageReference Include=\"Newtonsoft.Json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Providers/RedisClusteringOptions.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\nusing System;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Orleans.Configuration;\n\nnamespace Orleans.Clustering.Redis\n{\n    /// <summary>\n    /// Options for Redis clustering.\n    /// </summary>\n    public class RedisClusteringOptions\n    {\n        /// <summary>\n        /// Gets or sets the Redis client configuration.\n        /// </summary>\n        [RedactRedisConfigurationOptions]\n        public ConfigurationOptions ConfigurationOptions { get; set; }\n\n        /// <summary>\n        /// The delegate used to create a Redis connection multiplexer.\n        /// </summary>\n        public Func<RedisClusteringOptions, Task<IConnectionMultiplexer>> CreateMultiplexer { get; set; } = DefaultCreateMultiplexer;\n\n        /// <summary>\n        /// The delegate used to create redis key for RedisMembershipTable.\n        /// </summary>\n        public Func<ClusterOptions, RedisKey> CreateRedisKey { get; set; } = DefaultCreateRedisKey;\n\n        /// <summary>\n        /// Entry expiry, null by default. A value should be set ONLY for ephemeral environments (like in tests).\n        /// Setting a value different from null will cause entries to be deleted after some period of time.\n        /// </summary>\n        public TimeSpan? EntryExpiry { get; set; } = null;\n\n        /// <summary>\n        /// The default multiplexer creation delegate.\n        /// </summary>\n        public static async Task<IConnectionMultiplexer> DefaultCreateMultiplexer(RedisClusteringOptions options)\n        {\n            return await ConnectionMultiplexer.ConnectAsync(options.ConfigurationOptions);\n        }\n\n        /// <summary>\n        /// The default multiplexer creation redis key for RedisMembershipTable.\n        /// </summary>\n        /// <returns></returns>\n        public static RedisKey DefaultCreateRedisKey(ClusterOptions clusterOptions)\n        {\n            return Encoding.UTF8.GetBytes($\"{clusterOptions.ServiceId}/members/{clusterOptions.ClusterId}\");\n        }\n    }\n\n    internal class RedactRedisConfigurationOptions : RedactAttribute\n    {\n        public override string Redact(object value) => value is ConfigurationOptions cfg ? cfg.ToString(includePassword: false) : base.Redact(value);\n    }\n\n    /// <summary>\n    /// Configuration validator for <see cref=\"RedisClusteringOptions\"/>.\n    /// </summary>\n    public class RedisClusteringOptionsValidator : IConfigurationValidator\n    {\n        private readonly RedisClusteringOptions _options;\n\n        public RedisClusteringOptionsValidator(IOptions<RedisClusteringOptions> options)\n        {\n            _options = options.Value;\n        }\n\n        /// <inheritdoc/>\n        public void ValidateConfiguration()\n        {\n            if (_options.ConfigurationOptions == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid configuration for {nameof(RedisMembershipTable)}. {nameof(RedisClusteringOptions)}.{nameof(_options.ConfigurationOptions)} is required.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Providers/RedisGatewayListProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.Configuration;\nusing System.Linq;\nusing Microsoft.Extensions.Options;\n\nnamespace Orleans.Clustering.Redis;\n\ninternal sealed class RedisGatewayListProvider(RedisMembershipTable table, IOptions<GatewayOptions> options) : IGatewayListProvider\n{\n    private readonly RedisMembershipTable _table = table;\n    private readonly GatewayOptions _gatewayOptions = options.Value;\n\n    public TimeSpan MaxStaleness => _gatewayOptions.GatewayListRefreshPeriod;\n\n    public bool IsUpdatable => true;\n\n    public async Task<IList<Uri>> GetGateways()\n    {\n        if (!_table.IsInitialized)\n        {\n            await _table.InitializeMembershipTable(true);\n        }\n\n        var all = await _table.ReadAll();\n        var result = all.Members\n           .Where(x => x.Item1.Status == SiloStatus.Active && x.Item1.ProxyPort != 0)\n           .Select(x =>\n            {\n                var entry = x.Item1;\n                return SiloAddress.New(entry.SiloAddress.Endpoint.Address, entry.ProxyPort, entry.SiloAddress.Generation).ToGatewayUri();\n            }).ToList();\n        return result;\n    }\n\n    public async Task InitializeGatewayListProvider()\n    {\n        await _table.InitializeMembershipTable(true);\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/README.md",
    "content": "# Microsoft Orleans Clustering for Redis\n\n## Introduction\nMicrosoft Orleans Clustering for Redis provides cluster membership functionality for Microsoft Orleans using Redis. This allows Orleans silos to coordinate and form a cluster using Redis as the backing store.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Clustering.Redis\n```\n\n## Example - Configuring Redis Membership\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            // Configure Redis as the membership provider\n            .UseRedisClustering(options =>\n            {\n                options.ConnectionString = \"localhost:6379\";\n                options.Database = 0;\n            });\n    });\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"Redis\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Example - Client Configuration\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Threading.Tasks;\n\nvar clientBuilder = Host.CreateApplicationBuilder(args)\n    .UseOrleansClient(builder =>\n    {\n        builder\n            // Configure Redis as the gateway provider\n            .UseRedisGatewayListProvider(options =>\n            {\n                options.ConnectionString = \"localhost:6379\";\n                options.Database = 0;\n            });\n    });\n\nvar host = clientBuilder.Build();\nawait host.StartAsync();\nvar client = host.Services.GetRequiredService<IClusterClient>();\n\n// Get a reference to a grain and call it\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"Redis Client\");\n\n// Print the result\nConsole.WriteLine($\"Grain response: {response}\");\n\n// Keep the host running until the application is shut down\nawait host.WaitForShutdownAsync();\n```\n\n## Configuration via Microsoft.Extensions.Configuration\n\nYou can configure Orleans Redis clustering using `Microsoft.Extensions.Configuration` (such as `appsettings.json`) instead of configuring it in code. When using this approach, Orleans will automatically read the configuration from the `Orleans` section.\n\n> **Note**: You can use either `\"ProviderType\": \"Redis\"` or `\"ProviderType\": \"AzureRedisCache\"` - both are supported and functionally equivalent.\n\n### Example - appsettings.json (Silo)\n```json\n{\n  \"ConnectionStrings\": {\n    \"redis\": \"localhost:6379\"\n  },\n  \"Orleans\": {\n    \"ClusterId\": \"my-cluster\",\n    \"ServiceId\": \"MyOrleansService\",\n    \"Clustering\": {\n      \"ProviderType\": \"Redis\",\n      \"ServiceKey\": \"redis\"\n    }\n  }\n}\n```\n\n### Example - appsettings.json (Client)\n```json\n{\n  \"ConnectionStrings\": {\n    \"redis\": \"localhost:6379\"\n  },\n  \"Orleans\": {\n    \"ClusterId\": \"my-cluster\",\n    \"ServiceId\": \"MyOrleansService\", \n    \"Clustering\": {\n      \"ProviderType\": \"Redis\",\n      \"ServiceKey\": \"redis\"\n    }\n  }\n}\n```\n\n### .NET Aspire Integration\n\nFor applications using .NET Aspire, consider using the [.NET Aspire Redis integration](https://learn.microsoft.com/en-us/dotnet/aspire/caching/stackexchange-redis-integration) which provides simplified Redis configuration, automatic service discovery, health checks, and telemetry. The Aspire integration automatically configures connection strings that Orleans can consume via the configuration system.\n\n#### Example - Program.cs with Aspire Redis Integration\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\n// Add service defaults (Aspire configurations)\nbuilder.AddServiceDefaults();\n\n// Add Redis via Aspire client integration\nbuilder.AddKeyedRedisClient(\"redis\");\n\n// Add Orleans\nbuilder.UseOrleans();\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IHelloGrain>(\"user123\");\nvar response = await grain.SayHello(\"Aspire Redis\");\n\nConsole.WriteLine($\"Grain response: {response}\");\nawait host.WaitForShutdownAsync();\n```\n\nThis example assumes your AppHost project has configured Redis like this:\n```csharp\n// In your AppHost/Program.cs\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"redis\");\n\nvar orleans = builder.AddOrleans(\"orleans\")\n    .WithClustering(redis);\n\nbuilder.AddProject<Projects.MyOrleansApp>(\"orleans-app\")\n    .WithReference(orleans);\n\nbuilder.Build().Run();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Configuration Guide](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/)\n- [Orleans Clustering](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/cluster-management)\n- [Redis Documentation](https://redis.io/documentation)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Storage/JsonSettings.cs",
    "content": "﻿using System;\nusing Newtonsoft.Json;\nusing System.Net;\nusing Orleans.Runtime;\nusing Newtonsoft.Json.Linq;\nusing System.Globalization;\n\nnamespace Orleans.Clustering.Redis\n{\n    internal static class JsonSettings\n    {\n        public static JsonSerializerSettings JsonSerializerSettings => new JsonSerializerSettings\n        {\n            Formatting = Formatting.None,\n            TypeNameHandling = TypeNameHandling.None,\n            DefaultValueHandling = DefaultValueHandling.Include,\n            DateTimeZoneHandling = DateTimeZoneHandling.Utc,\n            DateParseHandling = DateParseHandling.DateTimeOffset,\n            Culture = CultureInfo.InvariantCulture,\n            MissingMemberHandling = MissingMemberHandling.Ignore,\n            PreserveReferencesHandling = PreserveReferencesHandling.None,\n            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,\n            MaxDepth = 10,\n            Converters = { new IPAddressConverter(), new IPEndPointConverter(), new SiloAddressConverter() }\n        };\n\n        private class IPAddressConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return objectType == typeof(IPAddress);\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                IPAddress ip = (IPAddress)value;\n                writer.WriteValue(ip.ToString());\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n            {\n                JToken token = JToken.Load(reader);\n                return IPAddress.Parse(token.Value<string>());\n            }\n        }\n\n        private class IPEndPointConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return objectType == typeof(IPEndPoint);\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                IPEndPoint ep = (IPEndPoint)value;\n                writer.WriteStartObject();\n                writer.WritePropertyName(\"Address\");\n                serializer.Serialize(writer, ep.Address);\n                writer.WritePropertyName(\"Port\");\n                writer.WriteValue(ep.Port);\n                writer.WriteEndObject();\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n            {\n                JObject jo = JObject.Load(reader);\n                IPAddress address = jo[\"Address\"].ToObject<IPAddress>(serializer);\n                int port = jo[\"Port\"].Value<int>();\n                return new IPEndPoint(address, port);\n            }\n        }\n\n        private class SiloAddressConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return objectType == typeof(SiloAddress);\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                SiloAddress addr = (SiloAddress)value;\n                writer.WriteStartObject();\n                writer.WritePropertyName(\"SiloAddress\");\n                writer.WriteValue(addr.ToParsableString());\n                writer.WriteEndObject();\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n            {\n                JObject jo = JObject.Load(reader);\n                SiloAddress addr = SiloAddress.FromParsableString(jo[\"SiloAddress\"].ToObject<string>());\n                return addr;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Storage/RedisClusteringException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Clustering.Redis\n{\n    /// <summary>\n    /// Represents an exception which occurred in the Redis clustering.\n    /// </summary>\n    [Serializable]\n    public class RedisClusteringException : Exception\n    {\n        /// <inheritdoc/>\n        public RedisClusteringException() : base() { }\n\n        /// <inheritdoc/>\n        public RedisClusteringException(string message) : base(message) { }\n\n        /// <inheritdoc/>\n        public RedisClusteringException(string message, Exception innerException) : base(message, innerException) { }\n\n        /// <inheritdoc/>\n        [Obsolete]\n        protected RedisClusteringException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Clustering.Redis/Storage/RedisMembershipTable.cs",
    "content": "#nullable enable\nusing System;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\nusing Orleans.Configuration;\nusing Newtonsoft.Json;\nusing System.Linq;\nusing Microsoft.Extensions.Options;\nusing System.Globalization;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Orleans.Clustering.Redis\n{\n    internal class RedisMembershipTable : IMembershipTable, IDisposable\n    {\n        private const string TableVersionKey = \"Version\";\n        private static readonly TableVersion DefaultTableVersion = new TableVersion(0, \"0\");\n        private readonly RedisClusteringOptions _redisOptions;\n        private readonly ClusterOptions _clusterOptions;\n        private readonly JsonSerializerSettings _jsonSerializerSettings;\n        private readonly RedisKey _clusterKey;\n        private IConnectionMultiplexer _muxer = null!;\n        private IDatabase _db = null!;\n\n        public RedisMembershipTable(IOptions<RedisClusteringOptions> redisOptions, IOptions<ClusterOptions> clusterOptions)\n        {\n            _redisOptions = redisOptions.Value;\n            _clusterOptions = clusterOptions.Value;\n            _clusterKey = _redisOptions.CreateRedisKey(_clusterOptions);\n            _jsonSerializerSettings = JsonSettings.JsonSerializerSettings;\n        }\n\n        public bool IsInitialized { get; private set; }\n\n        public async Task DeleteMembershipTableEntries(string clusterId)\n        {\n            await _db.KeyDeleteAsync(_clusterKey);\n        }\n\n        public async Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            _muxer = await _redisOptions.CreateMultiplexer(_redisOptions);\n            _db = _muxer.GetDatabase();\n\n            if (tryInitTableVersion)\n            {\n                await _db.HashSetAsync(_clusterKey, TableVersionKey, SerializeVersion(DefaultTableVersion), When.NotExists);\n\n                if (_redisOptions.EntryExpiry is { } expiry)\n                {\n                    await _db.KeyExpireAsync(_clusterKey, expiry);\n                }\n            }\n\n            this.IsInitialized = true;\n        }\n\n        public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            return await UpsertRowInternal(entry, tableVersion, updateTableVersion: true, allowInsertOnly: true) == UpsertResult.Success;\n        }\n\n        private async Task<UpsertResult> UpsertRowInternal(MembershipEntry entry, TableVersion tableVersion, bool updateTableVersion, bool allowInsertOnly)\n        {\n            var tx = _db.CreateTransaction();\n            var rowKey = entry.SiloAddress.ToString();\n\n            if (updateTableVersion)\n            {\n                tx.HashSetAsync(_clusterKey, TableVersionKey, SerializeVersion(tableVersion)).Ignore();\n            }\n\n            var versionCondition = tx.AddCondition(Condition.HashEqual(_clusterKey, TableVersionKey, SerializeVersion(Predeccessor(tableVersion))));\n\n            ConditionResult? insertCondition;\n            if (allowInsertOnly)\n            {\n                insertCondition = tx.AddCondition(Condition.HashNotExists(_clusterKey, rowKey));\n            }\n            else\n            {\n                insertCondition = null;\n            }\n\n            tx.HashSetAsync(_clusterKey, rowKey, Serialize(entry)).Ignore();\n\n            var success = await tx.ExecuteAsync();\n\n            if (success)\n            {\n                return UpsertResult.Success;\n            }\n\n            if (!versionCondition.WasSatisfied)\n            {\n                return UpsertResult.Conflict;\n            }\n\n            if (insertCondition is not null && !insertCondition.WasSatisfied)\n            {\n                return UpsertResult.Conflict;\n            }\n\n            return UpsertResult.Failure;\n        }\n\n        public async Task<MembershipTableData> ReadAll()\n        {\n            var all = await _db.HashGetAllAsync(_clusterKey);\n            var tableVersionRow = all.SingleOrDefault(h => TableVersionKey.Equals(h.Name, StringComparison.Ordinal));\n            TableVersion tableVersion = GetTableVersionFromRow(tableVersionRow.Value);\n\n            var data = all.Where(x => !TableVersionKey.Equals(x.Name, StringComparison.Ordinal) && x.Value.HasValue)\n                .Select(x => Tuple.Create(Deserialize(x.Value!), tableVersion.VersionEtag))\n                .ToList();\n            return new MembershipTableData(data, tableVersion);\n        }\n\n        private static TableVersion GetTableVersionFromRow(RedisValue tableVersionRow)\n        {\n            if (TryGetValueString(tableVersionRow, out var value))\n            {\n                return DeserializeVersion(value);\n            }\n\n            return DefaultTableVersion;\n        }\n\n        private static bool TryGetValueString(RedisValue key, [NotNullWhen(true)] out string? value)\n        {\n            if (key.HasValue)\n            {\n                value = key.ToString();\n                return true;\n            }\n\n            value = null;\n            return false;\n        }\n\n        public async Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            var tx = _db.CreateTransaction();\n            var tableVersionRowTask = tx.HashGetAsync(_clusterKey, TableVersionKey);\n            var entryRowTask = tx.HashGetAsync(_clusterKey, key.ToString());\n            if (!await tx.ExecuteAsync())\n            {\n                throw new RedisClusteringException($\"Unexpected transaction failure while reading key {key}\");\n            }\n\n            TableVersion tableVersion = GetTableVersionFromRow(await tableVersionRowTask);\n            var entryRow = await entryRowTask;\n            if (TryGetValueString(entryRow, out var entryValueString))\n            {\n                var entry = Deserialize(entryValueString);\n                return new MembershipTableData(Tuple.Create(entry, tableVersion.VersionEtag), tableVersion);\n            }\n            else\n            {\n                return new MembershipTableData(tableVersion);\n            }\n        }\n\n        public async Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            var key = entry.SiloAddress.ToString();\n            var tx = _db.CreateTransaction();\n            var tableVersionRowTask = tx.HashGetAsync(_clusterKey, TableVersionKey);\n            var entryRowTask = tx.HashGetAsync(_clusterKey, key);\n            if (!await tx.ExecuteAsync())\n            {\n                throw new RedisClusteringException($\"Unexpected transaction failure while reading key {key}\");\n            }\n\n            var entryRow = await entryRowTask;\n            if (!TryGetValueString(entryRow, out var entryRowValue))\n            {\n                throw new RedisClusteringException($\"Could not find a value for the key {key}\");\n            }\n\n            TableVersion tableVersion = GetTableVersionFromRow(await tableVersionRowTask).Next();\n            var existingEntry = Deserialize(entryRowValue);\n\n            // Update only the IAmAliveTime property.\n            existingEntry.IAmAliveTime = entry.IAmAliveTime;\n\n            var result = await UpsertRowInternal(existingEntry, tableVersion, updateTableVersion: false, allowInsertOnly: false);\n            if (result == UpsertResult.Conflict)\n            {\n                throw new RedisClusteringException($\"Failed to update IAmAlive value for key {key} due to conflict\");\n            }\n            else if (result != UpsertResult.Success)\n            {\n                throw new RedisClusteringException($\"Failed to update IAmAlive value for key {key} for an unknown reason\");\n            }\n        }\n\n        public async Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            return await UpsertRowInternal(entry, tableVersion, updateTableVersion: true, allowInsertOnly: false) == UpsertResult.Success;\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            var entries = await this.ReadAll();\n            foreach (var (entry, _) in entries.Members)\n            {\n                if (entry.Status != SiloStatus.Active\n                    && new DateTime(Math.Max(entry.IAmAliveTime.Ticks, entry.StartTime.Ticks), DateTimeKind.Utc) < beforeDate)\n                {\n                    await _db.HashDeleteAsync(_clusterKey, entry.SiloAddress.ToString());\n                }\n            }\n        }\n\n        public void Dispose()\n        {\n            _muxer?.Dispose();\n        }\n\n        private enum UpsertResult\n        {\n            Success = 1,\n            Failure = 2,\n            Conflict = 3,\n        }\n\n        private static string SerializeVersion(TableVersion tableVersion) => tableVersion.Version.ToString(CultureInfo.InvariantCulture);\n\n        private static TableVersion DeserializeVersion(string versionString)\n        {\n            if (string.IsNullOrWhiteSpace(versionString))\n            {\n                return DefaultTableVersion;\n            }\n\n            var version = int.Parse(versionString);\n            return new TableVersion(version, versionString);\n        }\n\n        private static TableVersion Predeccessor(TableVersion tableVersion) => new TableVersion(tableVersion.Version - 1, (tableVersion.Version - 1).ToString(CultureInfo.InvariantCulture));\n\n\n        private string Serialize(MembershipEntry value)\n        {\n            return JsonConvert.SerializeObject(value, _jsonSerializerSettings);\n        }\n\n        private MembershipEntry Deserialize(string json)\n        {\n            return JsonConvert.DeserializeObject<MembershipEntry>(json, _jsonSerializerSettings)!;\n        }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/Hosting/RedisGrainDirectoryExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.GrainDirectory.Redis;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Extensions for configuring Redis as a grain directory provider.\n    /// </summary>\n    public static class RedisGrainDirectoryExtensions\n    {\n        /// <summary>\n        /// Adds a default grain directory which persists entries in Redis.\n        /// </summary>\n        public static ISiloBuilder UseRedisGrainDirectoryAsDefault(\n            this ISiloBuilder builder,\n            Action<RedisGrainDirectoryOptions> configureOptions)\n        {\n            return builder.UseRedisGrainDirectoryAsDefault(ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Adds a default grain directory which persists entries in Redis.\n        /// </summary>\n        public static ISiloBuilder UseRedisGrainDirectoryAsDefault(\n            this ISiloBuilder builder,\n            Action<OptionsBuilder<RedisGrainDirectoryOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddRedisGrainDirectory(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, configureOptions));\n        }\n\n        /// <summary>\n        /// Adds a named grain directory which persists entries in Redis.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainDirectory(\n            this ISiloBuilder builder,\n            string name,\n            Action<RedisGrainDirectoryOptions> configureOptions)\n        {\n            return builder.AddRedisGrainDirectory(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Adds a named grain directory which persists entries in Redis.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainDirectory(\n            this ISiloBuilder builder,\n            string name,\n            Action<OptionsBuilder<RedisGrainDirectoryOptions>> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddRedisGrainDirectory(name, configureOptions));\n        }\n\n        private static IServiceCollection AddRedisGrainDirectory(\n            this IServiceCollection services,\n            string name,\n            Action<OptionsBuilder<RedisGrainDirectoryOptions>> configureOptions)\n        {\n            configureOptions.Invoke(services.AddOptions<RedisGrainDirectoryOptions>(name));\n            services\n                .AddTransient<IConfigurationValidator>(sp => new RedisGrainDirectoryOptionsValidator(sp.GetRequiredService<IOptionsMonitor<RedisGrainDirectoryOptions>>().Get(name), name))\n                .ConfigureNamedOptionForLogging<RedisGrainDirectoryOptions>(name)\n                .AddGrainDirectory(name, (sp, key) => ActivatorUtilities.CreateInstance<RedisGrainDirectory>(sp, sp.GetOptionsByName<RedisGrainDirectoryOptions>(key)));\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/Hosting/RedisGrainDirectoryProviderBuilder.cs",
    "content": "using Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing StackExchange.Redis;\nusing System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Threading.Tasks;\n\n[assembly: RegisterProvider(\"Redis\", \"GrainDirectory\", \"Silo\", typeof(RedisGrainDirectoryProviderBuilder))]\n[assembly: RegisterProvider(\"AzureRedisCache\", \"GrainDirectory\", \"Silo\", typeof(RedisGrainDirectoryProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class RedisGrainDirectoryProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddRedisGrainDirectory(name, (OptionsBuilder<RedisGrainDirectoryOptions> optionsBuilder) =>\n        {\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a connection multiplexer instance by name.\n                    var multiplexer = services.GetRequiredKeyedService<IConnectionMultiplexer>(serviceKey);\n                    options.CreateMultiplexer = _ => Task.FromResult(multiplexer);\n                    options.ConfigurationOptions = new ConfigurationOptions();\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                    }\n                }\n            });\n        });\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/Options/RedisGrainDirectoryOptions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.GrainDirectory.Redis;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Configuration options for the <see cref=\"RedisGrainDirectory\"/>\n    /// </summary>\n    public class RedisGrainDirectoryOptions \n    {\n        /// <summary>\n        /// Gets or sets the Redis client configuration.\n        /// </summary>\n        [RedactRedisConfigurationOptions]\n        public ConfigurationOptions ConfigurationOptions { get; set; }\n\n        /// <summary>\n        /// The delegate used to create a Redis connection multiplexer.\n        /// </summary>\n        public Func<RedisGrainDirectoryOptions, Task<IConnectionMultiplexer>> CreateMultiplexer { get; set; } = DefaultCreateMultiplexer;\n\n        /// <summary>\n        /// Entry expiry, null by default. A value should be set ONLY for ephemeral environments (like in tests).\n        /// Setting a value different from null will cause duplicate activations in the cluster.\n        /// </summary>\n        public TimeSpan? EntryExpiry { get; set; } = null;\n\n        /// <summary>\n        /// The default multiplexer creation delegate.\n        /// </summary>\n        public static async Task<IConnectionMultiplexer> DefaultCreateMultiplexer(RedisGrainDirectoryOptions options) => await ConnectionMultiplexer.ConnectAsync(options.ConfigurationOptions);\n    }\n\n    internal class RedactRedisConfigurationOptions : RedactAttribute\n    {\n        public override string Redact(object value) => value is ConfigurationOptions cfg ? cfg.ToString(includePassword: false) : base.Redact(value);\n    }\n\n    /// <summary>\n    /// Configuration validator for <see cref=\"RedisGrainDirectoryOptions\"/>.\n    /// </summary>\n    public class RedisGrainDirectoryOptionsValidator : IConfigurationValidator\n    {\n        private readonly RedisGrainDirectoryOptions _options;\n        private readonly string _name;\n\n        public RedisGrainDirectoryOptionsValidator(RedisGrainDirectoryOptions options, string name)\n        {\n            _options = options;\n            _name = name;\n        }\n\n        /// <inheritdoc/>\n        public void ValidateConfiguration()\n        {\n            if (_options.ConfigurationOptions == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid configuration for {nameof(RedisGrainDirectory)} with name {_name}. {nameof(RedisGrainDirectoryOptions)}.{nameof(_options.ConfigurationOptions)} is required.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/Orleans.GrainDirectory.Redis.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.GrainDirectory.Redis</PackageId>\n    <Title>Microsoft Orleans Grain Directory Redis Provider</Title>\n    <Description>Microsoft Orleans Grain Directory implementation that uses Redis</Description>\n    <PackageTags>$(PackageTags) Redis Grain Directory</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StackExchange.Redis\" />\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/README.md",
    "content": "# Microsoft Orleans Grain Directory for Redis\n\n## Introduction\nMicrosoft Orleans Grain Directory for Redis provides a grain directory implementation using Redis. The grain directory is used to locate active grain instances across the cluster, and this package allows Orleans to store that information in Redis.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.GrainDirectory.Redis\n```\n\n## Example - Configuring Redis Grain Directory\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Redis as the grain directory\n            .UseRedisGrainDirectoryAsDefault(options =>\n            {\n                options.ConnectionString = \"localhost:6379\";\n                options.Database = 0;\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Configuration via Microsoft.Extensions.Configuration\n\nYou can configure Orleans Redis grain directory using `Microsoft.Extensions.Configuration` (such as `appsettings.json`) instead of configuring it in code. When using this approach, Orleans will automatically read the configuration from the `Orleans` section.\n\n> **Note**: You can use either `\"ProviderType\": \"Redis\"` or `\"ProviderType\": \"AzureRedisCache\"` - both are supported and functionally equivalent.\n\n### Example - appsettings.json\n```json\n{\n  \"ConnectionStrings\": {\n    \"redis\": \"localhost:6379\"\n  },\n  \"Orleans\": {\n    \"ClusterId\": \"my-cluster\",\n    \"ServiceId\": \"MyOrleansService\",\n    \"GrainDirectory\": {\n      \"Default\": {\n        \"ProviderType\": \"Redis\",\n        \"ServiceKey\": \"redis\"\n      }\n    }\n  }\n}\n```\n\n### .NET Aspire Integration\n\nFor applications using .NET Aspire, consider using the [.NET Aspire Redis integration](https://learn.microsoft.com/en-us/dotnet/aspire/caching/stackexchange-redis-integration) which provides simplified Redis configuration, automatic service discovery, health checks, and telemetry. The Aspire integration automatically configures connection strings that Orleans can consume via the configuration system.\n\n#### Example - Program.cs with Aspire Redis Integration\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\n// Add service defaults (Aspire configurations)\nbuilder.AddServiceDefaults();\n\n// Add Redis via Aspire client integration\nbuilder.AddKeyedRedisClient(\"redis\");\n\n// Add Orleans\nbuilder.UseOrleans();\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IMyGrain>(\"user123\");\nvar response = await grain.SayHello(\"Aspire Redis Grain Directory\");\n\nConsole.WriteLine($\"Grain response: {response}\");\nawait host.WaitForShutdownAsync();\n```\n\nThis example assumes your AppHost project has configured Redis like this:\n```csharp\n// In your AppHost/Program.cs\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"redis\");\n\nvar orleans = builder.AddOrleans(\"orleans\")\n    .WithGrainDirectory(\"Default\", redis);\n\nbuilder.AddProject<Projects.MyOrleansApp>(\"orleans-app\")\n    .WithReference(orleans);\n\nbuilder.Build().Run();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Configuration Guide](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/)\n- [Implementation Details](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/index)\n- [Redis Documentation](https://redis.io/documentation)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Redis/Orleans.GrainDirectory.Redis/RedisGrainDirectory.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Net;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\n\nnamespace Orleans.GrainDirectory.Redis\n{\n    public partial class RedisGrainDirectory : IGrainDirectory, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly RedisGrainDirectoryOptions _directoryOptions;\n        private readonly ClusterOptions _clusterOptions;\n        private readonly ILogger<RedisGrainDirectory> _logger;\n        private readonly RedisKey _keyPrefix;\n        private readonly string _ttl;\n\n        // Both are initialized in the Initialize method.\n        private IConnectionMultiplexer _redis = null!;\n        private IDatabase _database = null!;\n\n        private bool _disposed;\n\n        public RedisGrainDirectory(\n            RedisGrainDirectoryOptions directoryOptions,\n            IOptions<ClusterOptions> clusterOptions,\n            ILogger<RedisGrainDirectory> logger)\n        {\n            _directoryOptions = directoryOptions;\n            _logger = logger;\n            _clusterOptions = clusterOptions.Value;\n            _keyPrefix = Encoding.UTF8.GetBytes($\"{_clusterOptions.ClusterId}/directory/\");\n            _ttl = directoryOptions.EntryExpiry is { } ts ? ts.TotalSeconds.ToString(CultureInfo.InvariantCulture) : \"-1\";\n        }\n\n        public async Task<GrainAddress?> Lookup(GrainId grainId)\n        {\n            try\n            {\n                var result = _disposed ? null : (string?)await _database.StringGetAsync(GetKey(grainId));\n\n                LogDebugLookup(grainId, string.IsNullOrWhiteSpace(result) ? \"null\" : result);\n\n                if (string.IsNullOrWhiteSpace(result))\n                    return default;\n\n                return JsonSerializer.Deserialize<GrainAddress>(result);\n            }\n            catch (Exception ex)\n            {\n                LogErrorLookupFailed(ex, grainId);\n\n                if (IsRedisException(ex))\n                    throw new OrleansException($\"Lookup failed for {grainId} : {ex}\");\n                else\n                    throw;\n            }\n        }\n\n        public Task<GrainAddress?> Register(GrainAddress address) => Register(address, null);\n\n        public async Task<GrainAddress?> Register(GrainAddress address, GrainAddress? previousAddress)\n        {\n            const string RegisterScript =\n                \"\"\"\n                local cur = redis.call('GET', KEYS[1])\n                local success = true\n                if cur ~= false then\n                    local typedCur = cjson.decode(cur)\n                    if typedCur.ActivationId ~= ARGV[2] then\n                       success = false\n                    end\n                end\n\n                if (success) then\n                    redis.call('SET', KEYS[1], ARGV[1])\n                    if ARGV[3] ~= '-1' then\n                        redis.call('EXPIRE', KEYS[1], ARGV[3])\n                    end\n                    return nil\n                end\n\n                return cur\n                \"\"\";\n\n            var value = JsonSerializer.Serialize(address);\n            try\n            {\n                ObjectDisposedException.ThrowIf(_disposed, _database);\n\n                var previousActivationId = previousAddress is { } ? previousAddress.ActivationId.ToString() : \"\";\n                var key = GetKey(address.GrainId);\n                var entryString = (string?)await _database.ScriptEvaluateAsync(\n                    RegisterScript,\n                    keys: new RedisKey[] { key },\n                    values: new RedisValue[] { value, previousActivationId, _ttl })!;\n\n                if (entryString is null)\n                {\n                    LogDebugRegistered(address.GrainId, value);\n\n                    return address;\n                }\n\n                LogDebugRegisterFailed(address.GrainId, value, entryString);\n\n                return JsonSerializer.Deserialize<GrainAddress>(entryString);\n            }\n            catch (Exception ex)\n            {\n                LogErrorRegisterFailed(ex, address.GrainId, value);\n\n                if (IsRedisException(ex))\n                {\n                    throw new OrleansException($\"Register failed for {address.GrainId} ({value}) : {ex}\");\n                }\n                else\n                {\n                    throw;\n                }\n            }\n        }\n\n        public async Task Unregister(GrainAddress address)\n        {\n            const string DeleteScript =\n                \"\"\"\n                local cur = redis.call('GET', KEYS[1])\n                if cur ~= false then\n                    local typedCur = cjson.decode(cur)\n                    if typedCur.ActivationId == ARGV[1] then\n                        return redis.call('DEL', KEYS[1])\n                    end\n                end\n                return 0\n                \"\"\";\n\n            try\n            {\n                ObjectDisposedException.ThrowIf(_disposed, _database);\n\n                var value = JsonSerializer.Serialize(address);\n                var result = (int)await _database.ScriptEvaluateAsync(\n                    DeleteScript,\n                    keys: new RedisKey[] { GetKey(address.GrainId) },\n                    values: new RedisValue[] { address.ActivationId.ToString() });\n\n                LogDebugUnregister(address.GrainId, new(address), (result != 0) ? \"OK\" : \"Conflict\");\n            }\n            catch (Exception ex)\n            {\n                LogErrorUnregisterFailed(ex, address.GrainId, new(address));\n\n                if (IsRedisException(ex))\n                    throw new OrleansException($\"Unregister failed for {address.GrainId} ({JsonSerializer.Serialize(address)}) : {ex}\");\n                else\n                    throw;\n            }\n        }\n\n        public Task UnregisterSilos(List<SiloAddress> siloAddresses)\n        {\n            return Task.CompletedTask;\n        }\n\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(nameof(RedisGrainDirectory), ServiceLifecycleStage.RuntimeInitialize, Initialize, Uninitialize);\n        }\n\n        public async Task Initialize(CancellationToken ct = default)\n        {\n            _redis = await _directoryOptions.CreateMultiplexer(_directoryOptions);\n\n            // Configure logging\n            _redis.ConnectionRestored += LogConnectionRestored;\n            _redis.ConnectionFailed += LogConnectionFailed;\n            _redis.ErrorMessage += LogErrorMessage;\n            _redis.InternalError += LogInternalError;\n\n            _database = _redis.GetDatabase();\n        }\n\n        private async Task Uninitialize(CancellationToken arg)\n        {\n            if (_redis != null && _redis.IsConnected)\n            {\n                _disposed = true;\n\n                await _redis.CloseAsync();\n                _redis.Dispose();\n                _redis = null!;\n                _database = null!;\n            }\n        }\n\n        private RedisKey GetKey(GrainId grainId) => _keyPrefix.Append(grainId.ToString());\n\n        #region Logging\n        private void LogConnectionRestored(object? sender, ConnectionFailedEventArgs e)\n            => LogInfoConnectionRestored(e.Exception, e.EndPoint, e.FailureType);\n\n        private void LogConnectionFailed(object? sender, ConnectionFailedEventArgs e)\n            => LogErrorConnectionFailed(e.Exception, e.EndPoint, e.FailureType);\n\n        private void LogErrorMessage(object? sender, RedisErrorEventArgs e)\n            => LogErrorRedisMessage(e.Message);\n\n        private void LogInternalError(object? sender, InternalErrorEventArgs e)\n            => LogErrorInternalError(e.Exception);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Lookup {GrainId}: {Result}\"\n        )]\n        private partial void LogDebugLookup(GrainId grainId, string result);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Lookup failed for {GrainId}\"\n        )]\n        private partial void LogErrorLookupFailed(Exception exception, GrainId grainId);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Registered {GrainId} ({Address})\"\n        )]\n        private partial void LogDebugRegistered(GrainId grainId, string address);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Failed to register {GrainId} ({Address}) in directory: Conflicted with existing value, {Result}\"\n        )]\n        private partial void LogDebugRegisterFailed(GrainId grainId, string address, string result);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to register {GrainId} ({Address}) in directory\"\n        )]\n        private partial void LogErrorRegisterFailed(Exception exception, GrainId grainId, string address);\n\n        private readonly struct GrainAddressLogRecord(GrainAddress address)\n        {\n            public override string ToString() => JsonSerializer.Serialize(address);\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Unregister {GrainId} ({Address}): {Result}\"\n        )]\n        private partial void LogDebugUnregister(GrainId grainId, GrainAddressLogRecord address, string result);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Unregister failed for {GrainId} ({Address})\"\n        )]\n        private partial void LogErrorUnregisterFailed(Exception exception, GrainId grainId, GrainAddressLogRecord address);\n\n        [LoggerMessage(\n            Level = LogLevel.Information,\n            Message = \"Connection to {EndPoint} restored: {FailureType}\"\n        )]\n        private partial void LogInfoConnectionRestored(Exception? exception, EndPoint? endPoint, ConnectionFailureType failureType);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Connection to {EndPoint} failed: {FailureType}\"\n        )]\n        private partial void LogErrorConnectionFailed(Exception? exception, EndPoint? endPoint, ConnectionFailureType failureType);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"{Message}\"\n        )]\n        private partial void LogErrorRedisMessage(string message);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Internal error\"\n        )]\n        private partial void LogErrorInternalError(Exception? exception);\n        #endregion\n\n        // These exceptions are not serializable by the client\n        private static bool IsRedisException(Exception ex) => ex is RedisException || ex is RedisTimeoutException || ex is RedisCommandException;\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Hosting/RedisGrainStorageProviderBuilder.cs",
    "content": "using Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing StackExchange.Redis;\nusing Microsoft.Extensions.Options;\nusing Orleans.Persistence;\nusing System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Storage;\n\n[assembly: RegisterProvider(\"Redis\", \"GrainStorage\", \"Silo\", typeof(RedisGrainStorageProviderBuilder))]\n[assembly: RegisterProvider(\"AzureRedisCache\", \"GrainStorage\", \"Silo\", typeof(RedisGrainStorageProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class RedisGrainStorageProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.AddRedisGrainStorage(name, (OptionsBuilder<RedisStorageOptions> optionsBuilder) =>\n        {\n            optionsBuilder.Configure<IServiceProvider>((options, services) =>\n            {\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a connection multiplexer instance by name.\n                    var multiplexer = services.GetRequiredKeyedService<IConnectionMultiplexer>(serviceKey);\n                    options.CreateMultiplexer = _ => Task.FromResult(multiplexer);\n                    options.ConfigurationOptions = new ConfigurationOptions();\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                    }\n                }\n\n                var serializerKey = configurationSection[\"SerializerKey\"];\n                if (!string.IsNullOrEmpty(serializerKey))\n                {\n                    options.GrainStorageSerializer = services.GetRequiredKeyedService<IGrainStorageSerializer>(serializerKey);\n                }\n            });\n        });\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Hosting/RedisGrainStorageServiceCollectionExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Persistence;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"IServiceCollection\"/> extensions.\n    /// </summary>\n    public static class RedisGrainStorageServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Configures Redis as the default grain storage provider.\n        /// </summary>\n        public static IServiceCollection AddRedisGrainStorageAsDefault(this IServiceCollection services, Action<RedisStorageOptions> configureOptions)\n        {\n            return services.AddRedisGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configures Redis as a grain storage provider.\n        /// </summary>\n        public static IServiceCollection AddRedisGrainStorage(this IServiceCollection services, string name, Action<RedisStorageOptions> configureOptions)\n        {\n            return services.AddRedisGrainStorage(name, ob => ob.Configure(configureOptions));\n        }\n\n        /// <summary>\n        /// Configures Redis as the default grain storage provider.\n        /// </summary>\n        public static IServiceCollection AddRedisGrainStorageAsDefault(this IServiceCollection services, Action<OptionsBuilder<RedisStorageOptions>> configureOptions = null)\n        {\n            return services.AddRedisGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configures Redis as a grain storage provider.\n        /// </summary>\n        public static IServiceCollection AddRedisGrainStorage(this IServiceCollection services, string name,\n            Action<OptionsBuilder<RedisStorageOptions>> configureOptions = null)\n        {\n            configureOptions?.Invoke(services.AddOptions<RedisStorageOptions>(name));\n            services.AddTransient<IConfigurationValidator>(sp => new RedisStorageOptionsValidator(sp.GetRequiredService<IOptionsMonitor<RedisStorageOptions>>().Get(name), name));\n            services.AddTransient<IPostConfigureOptions<RedisStorageOptions>, DefaultStorageProviderSerializerOptionsConfigurator<RedisStorageOptions>>();\n            services.ConfigureNamedOptionForLogging<RedisStorageOptions>(name);\n            return services.AddGrainStorage(name, RedisGrainStorageFactory.Create);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Hosting/RedisSiloBuilderExtensions.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing Orleans.Persistence;\nusing Orleans.Providers;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// <see cref=\"ISiloBuilder\"/> extensions.\n    /// </summary>\n    public static class RedisSiloBuilderExtensions\n    {\n        /// <summary>\n        /// Configures Redis as the default grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder, Action<RedisStorageOptions> configureOptions)\n        {\n            return builder.AddRedisGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptions);\n        }\n\n        /// <summary>\n        /// Configures Redis as a grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name, Action<RedisStorageOptions> configureOptions)\n        {\n            return builder.ConfigureServices(services => services.AddRedisGrainStorage(name, configureOptions));\n        }\n\n        /// <summary>\n        /// Configures Redis as the default grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder)\n            => builder.AddRedisGrainStorageAsDefault(configureOptionsBuilder: null);\n\n        /// <summary>\n        /// Configures Redis as the default grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder, Action<OptionsBuilder<RedisStorageOptions>> configureOptionsBuilder)\n        {\n            return builder.AddRedisGrainStorage(ProviderConstants.DEFAULT_STORAGE_PROVIDER_NAME, configureOptionsBuilder);\n        }\n\n        /// <summary>\n        /// Configures Redis as a grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name)\n            => builder.AddRedisGrainStorage(name, configureOptionsBuilder: null);\n\n        /// <summary>\n        /// Configures Redis as a grain storage provider.\n        /// </summary>\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name, Action<OptionsBuilder<RedisStorageOptions>> configureOptionsBuilder)\n        {\n            return builder.ConfigureServices(services => services.AddRedisGrainStorage(name, configureOptionsBuilder));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Orleans.Persistence.Redis.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Persistence.Redis</PackageId>\n    <Title>Microsoft Orleans Persistence Redis Provider</Title>\n    <Description>Microsoft Orleans Persistence implementation that uses Redis</Description>\n    <PackageTags>$(PackageTags) Redis Persistence</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n\t<ItemGroup>\n\t\t<PackageReference Include=\"StackExchange.Redis\" />\n\t</ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Providers/RedisStorageOptions.cs",
    "content": "#nullable enable\nusing System;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing StackExchange.Redis;\n\nnamespace Orleans.Persistence\n{\n    /// <summary>\n    /// Redis grain storage options.\n    /// </summary>\n    public class RedisStorageOptions : IStorageProviderSerializerOptions\n    {\n        /// <summary>\n        /// Whether or not to delete state during a clear operation.\n        /// </summary>\n        public bool DeleteStateOnClear { get; set; }\n\n        /// <summary>\n        /// Stage of silo lifecycle where storage should be initialized.  Storage must be initialized prior to use.\n        /// </summary>\n        public int InitStage { get; set; } = ServiceLifecycleStage.ApplicationServices;\n\n        /// <inheritdoc/>\n        public IGrainStorageSerializer? GrainStorageSerializer { get; set; }\n\n        /// <summary>\n        /// Gets or sets the Redis client configuration.\n        /// </summary>\n        [RedactRedisConfigurationOptions]\n        public ConfigurationOptions? ConfigurationOptions { get; set; }\n\n        /// <summary>\n        /// The delegate used to create a Redis connection multiplexer.\n        /// </summary>\n        public Func<RedisStorageOptions, Task<IConnectionMultiplexer>> CreateMultiplexer { get; set; } = DefaultCreateMultiplexer;\n\n        /// <summary>\n        /// Entry expiry, null by default. A value should be set only for ephemeral environments, such as testing environments.\n        /// Setting a value different from <see langword=\"null\"/> will cause duplicate activations in the cluster.\n        /// </summary>\n        public TimeSpan? EntryExpiry { get; set; } = null;\n\n        /// <summary>\n        /// Gets the Redis key for the provided grain type and grain identifier. If not set, the default implementation will be used, which is equivalent to <c>{ServiceId}/state/{grainId}/{grainType}</c>.\n        /// </summary>\n        public Func<string, GrainId, RedisKey>? GetStorageKey { get; set; }\n\n        /// <summary>\n        /// The default multiplexer creation delegate.\n        /// </summary>\n        public static async Task<IConnectionMultiplexer> DefaultCreateMultiplexer(RedisStorageOptions options) => await ConnectionMultiplexer.ConnectAsync(options.ConfigurationOptions!);\n    }\n\n    /// <summary>\n    /// Extension methods for configuring <see cref=\"RedisStorageOptions\"/>.\n    /// </summary>\n    public static class RedisStorageOptionsExtensions\n    {\n        /// <summary>\n        /// Configures the provided options to use a Redis key format that ignores the grain type, equivalent to <c>{ServiceId}/state/{grainId}</c>.\n        /// </summary>\n        /// <remarks>\n        /// This method is provided as a compatibility utility for users who are migrating from prerelease versions of the Redis storage provider.\n        /// </remarks>\n        /// <param name=\"optionsBuilder\">The options builder.</param>\n        public static void UseGetRedisKeyIgnoringGrainType(this OptionsBuilder<RedisStorageOptions> optionsBuilder)\n        {\n            optionsBuilder.Configure((RedisStorageOptions options, IOptions<ClusterOptions> clusterOptions) =>\n            {\n                RedisKey keyPrefix = Encoding.UTF8.GetBytes($\"{clusterOptions.Value.ServiceId}/state/\");\n                options.GetStorageKey = (_, grainId) => keyPrefix.Append(grainId.ToString());\n            });\n        }\n    }\n\n    internal class RedactRedisConfigurationOptions : RedactAttribute\n    {\n        public override string Redact(object value) => value is ConfigurationOptions cfg ? cfg.ToString(includePassword: false) : base.Redact(value);\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Providers/RedisStorageOptionsValidator.cs",
    "content": "using Orleans.Runtime;\n\nnamespace Orleans.Persistence\n{\n    internal class RedisStorageOptionsValidator : IConfigurationValidator\n    {\n        private readonly RedisStorageOptions _options;\n        private readonly string _name;\n\n        public RedisStorageOptionsValidator(RedisStorageOptions options, string name)\n        {\n            _options = options;\n            _name = name;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (_options.ConfigurationOptions == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid configuration for {nameof(RedisGrainStorage)} with name {_name}. {nameof(RedisStorageOptions)}.{nameof(_options.ConfigurationOptions)} is required.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/README.md",
    "content": "# Microsoft Orleans Persistence for Redis\n\n## Introduction\nMicrosoft Orleans Persistence for Redis provides grain persistence for Microsoft Orleans using Redis. This allows your grains to persist their state in Redis and reload it when they are reactivated, leveraging Redis's in-memory data store for fast access.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Persistence.Redis\n```\n\n## Example - Configuring Redis Persistence\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Redis as grain storage\n            .AddRedisGrainStorage(\n                name: \"redisStore\",\n                configureOptions: options =>\n                {\n                    options.ConnectionString = \"localhost:6379\";\n                    options.Database = 0;\n                    options.UseJson = true; // Serializes grain state as JSON\n                    options.KeyPrefix = \"grain-\"; // Optional prefix for Redis keys\n                });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Grain Storage in a Grain\n```csharp\n// Define grain state class\n\npublic class MyGrainState\n{\n    public string Data { get; set; }\n    public int Version { get; set; }\n}\n\n// Grain implementation that uses Redis storage\npublic class MyGrain : Grain, IMyGrain, IGrainWithStringKey\n{\n    private readonly IPersistentState<MyGrainState> _state;\n\n    public MyGrain([PersistentState(\"state\", \"redisStore\")] IPersistentState<MyGrainState> state)\n    {\n        _state = state;\n    }\n\n    public async Task SetData(string data)\n    {\n        _state.State.Data = data;\n        _state.State.Version++;\n        await _state.WriteStateAsync();\n    }\n\n    public Task<string> GetData()\n    {\n        return Task.FromResult(_state.State.Data);\n    }\n}\n```\n\n## Configuration via Microsoft.Extensions.Configuration\n\nYou can configure Orleans Redis persistence using `Microsoft.Extensions.Configuration` (such as `appsettings.json`) instead of configuring it in code. When using this approach, Orleans will automatically read the configuration from the `Orleans` section.\n\n> **Note**: You can use either `\"ProviderType\": \"Redis\"` or `\"ProviderType\": \"AzureRedisCache\"` - both are supported and functionally equivalent.\n\n### Example - appsettings.json\n```json\n{\n  \"ConnectionStrings\": {\n    \"redis\": \"localhost:6379\"\n  },\n  \"Orleans\": {\n    \"ClusterId\": \"my-cluster\",\n    \"ServiceId\": \"MyOrleansService\",\n    \"GrainStorage\": {\n      \"redisStore\": {\n        \"ProviderType\": \"Redis\",\n        \"ServiceKey\": \"redis\"\n      }\n    }\n  }\n}\n```\n\n### .NET Aspire Integration\n\nFor applications using .NET Aspire, consider using the [.NET Aspire Redis integration](https://learn.microsoft.com/en-us/dotnet/aspire/caching/stackexchange-redis-integration) which provides simplified Redis configuration, automatic service discovery, health checks, and telemetry. The Aspire integration automatically configures connection strings that Orleans can consume via the configuration system.\n\n#### Example - Program.cs with Aspire Redis Integration\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\n// Add service defaults (Aspire configurations)\nbuilder.AddServiceDefaults();\n\n// Add Redis via Aspire client integration\nbuilder.AddKeyedRedisClient(\"redis\");\n\n// Add Orleans\nbuilder.UseOrleans();\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IMyGrain>(\"user123\");\nawait grain.SetData(\"Hello from Aspire Redis!\");\nvar data = await grain.GetData();\n\nConsole.WriteLine($\"Grain data: {data}\");\nawait host.WaitForShutdownAsync();\n```\n\nThis example assumes your AppHost project has configured Redis like this:\n```csharp\n// In your AppHost/Program.cs\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"redis\");\n\nvar orleans = builder.AddOrleans(\"orleans\")\n    .WithGrainStorage(\"redisStore\", redis);\n\nbuilder.AddProject<Projects.MyOrleansApp>(\"orleans-app\")\n    .WithReference(orleans);\n\nbuilder.Build().Run();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Grain Persistence](https://learn.microsoft.com/en-us/dotnet/orleans/grains/grain-persistence)\n- [Redis Documentation](https://redis.io/documentation)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Storage/RedisGrainStorage.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Persistence.Redis;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage;\nusing StackExchange.Redis;\nusing static System.FormattableString;\n\nnamespace Orleans.Persistence\n{\n    /// <summary>\n    /// Redis-based grain storage provider\n    /// </summary>\n    public partial class RedisGrainStorage : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>\n    {\n        private readonly string _serviceId;\n        private readonly RedisValue _ttl;\n        private readonly RedisKey _keyPrefix;\n        private readonly string _name;\n        private readonly ILogger _logger;\n        private readonly RedisStorageOptions _options;\n        private readonly IActivatorProvider _activatorProvider;\n        private readonly IGrainStorageSerializer _grainStorageSerializer;\n        private readonly Func<string, GrainId, RedisKey> _getKeyFunc;\n        private IConnectionMultiplexer _connection;\n        private IDatabase _db;\n\n        /// <summary>\n        /// Creates a new instance of the <see cref=\"RedisGrainStorage\"/> type.\n        /// </summary>\n        public RedisGrainStorage(\n            string name,\n            RedisStorageOptions options,\n            IGrainStorageSerializer grainStorageSerializer,\n            IOptions<ClusterOptions> clusterOptions,\n            IActivatorProvider activatorProvider,\n            ILogger<RedisGrainStorage> logger)\n        {\n            _name = name;\n            _logger = logger;\n            _options = options;\n            _activatorProvider = activatorProvider;\n            _grainStorageSerializer = options.GrainStorageSerializer ?? grainStorageSerializer;\n            _serviceId = clusterOptions.Value.ServiceId;\n            _ttl = options.EntryExpiry is { } ts ? ts.TotalSeconds.ToString(CultureInfo.InvariantCulture) : \"-1\";\n            _keyPrefix = Encoding.UTF8.GetBytes($\"{_serviceId}/state/\");\n            _getKeyFunc = _options.GetStorageKey ?? DefaultGetStorageKey;\n        }\n\n        /// <inheritdoc />\n        public void Participate(ISiloLifecycle lifecycle)\n        {\n            var name = OptionFormattingUtilities.Name<RedisGrainStorage>(_name);\n            lifecycle.Subscribe(name, _options.InitStage, Init, Close);\n        }\n\n        private async Task Init(CancellationToken cancellationToken)\n        {\n            var startTime = Stopwatch.GetTimestamp();\n\n            try\n            {\n                LogDebugInitializing(_name, _serviceId, _options.DeleteStateOnClear);\n\n                _connection = await _options.CreateMultiplexer(_options).ConfigureAwait(false);\n                _db = _connection.GetDatabase();\n\n                var elapsed = Stopwatch.GetElapsedTime(startTime);\n                LogDebugInitialized(_name, _serviceId, elapsed.TotalMilliseconds);\n            }\n            catch (Exception ex)\n            {\n                var elapsed = Stopwatch.GetElapsedTime(startTime);\n                LogErrorInitFailed(ex, _name, _serviceId, elapsed.TotalMilliseconds);\n                throw new RedisStorageException(Invariant($\"{ex.GetType()}: {ex.Message}\"));\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            var key = _getKeyFunc(grainType, grainId);\n\n            try\n            {\n                var hashEntries = await _db.HashGetAllAsync(key).ConfigureAwait(false);\n                if (hashEntries.Length == 2)\n                {\n                    string eTag = hashEntries.Single(static e => e.Name == \"etag\").Value;\n                    grainState.ETag = eTag;\n\n                    ReadOnlyMemory<byte> data = hashEntries.Single(static e => e.Name == \"data\").Value;\n                    if (data.Length > 0)\n                    {\n                        grainState.State = _grainStorageSerializer.Deserialize<T>(data);\n                        grainState.RecordExists = true;\n                    }\n                    else\n                    {\n                        grainState.State = CreateInstance<T>();\n                        grainState.RecordExists = false;\n                    }\n                }\n                else\n                {\n                    grainState.ETag = null;\n                    grainState.State = CreateInstance<T>();\n                    grainState.RecordExists = false;\n                }\n            }\n            catch (Exception exception)\n            {\n                LogErrorReadStateFailed(exception, grainType, grainId, key);\n                throw new RedisStorageException(Invariant($\"Failed to read grain state for {grainType} with ID {grainId} and storage key {key}. {exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            const string WriteScript =\n                \"\"\"\n                local etag = redis.call('HGET', KEYS[1], 'etag')\n                if ((not etag or etag == '') and (not ARGV[1] or ARGV[1] == '')) or etag == ARGV[1] then\n                  redis.call('HMSET', KEYS[1], 'etag', ARGV[2], 'data', ARGV[3])\n                  if ARGV[4] ~= '-1' then\n                    redis.call('EXPIRE', KEYS[1], ARGV[4])\n                  end\n                  return 0\n                else\n                  return -1\n                end\n                \"\"\";\n\n            var key = _getKeyFunc(grainType, grainId);\n            RedisValue etag = grainState.ETag ?? \"\";\n            RedisValue newEtag = Guid.NewGuid().ToString(\"N\");\n\n            try\n            {\n                RedisValue payload = _grainStorageSerializer.Serialize<T>(grainState.State).ToMemory();\n                var keys = new RedisKey[] { key };\n                var args = new RedisValue[] { etag, newEtag, payload, _ttl };\n                var response = await _db.ScriptEvaluateAsync(WriteScript, keys, args).ConfigureAwait(false);\n\n                if (response is not null && (int)response == -1)\n                {\n                    throw new InconsistentStateException($\"Version conflict ({nameof(WriteStateAsync)}): ServiceId={_serviceId} ProviderName={_name} GrainType={grainType} GrainId={grainId} ETag={grainState.ETag}.\");\n                }\n\n                grainState.ETag = newEtag;\n                grainState.RecordExists = true;\n            }\n            catch (Exception exception) when (exception is not InconsistentStateException)\n            {\n                LogErrorWriteStateFailed(exception, grainType, grainId, key);\n                throw new RedisStorageException(\n                    Invariant($\"Failed to write grain state for {grainType} grain with ID {grainId} and storage key {key}. {exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        /// <summary>\n        /// Default implementation of <see cref=\"RedisStorageOptions.GetStorageKey\"/> which returns a key equivalent to <c>{ServiceId}/state/{grainId}/{grainType}</c>\n        /// </summary>\n        private RedisKey DefaultGetStorageKey(string grainType, GrainId grainId)\n        {\n            var grainIdTypeBytes = IdSpan.UnsafeGetArray(grainId.Type.Value);\n            var grainIdKeyBytes = IdSpan.UnsafeGetArray(grainId.Key);\n            var grainTypeLength = Encoding.UTF8.GetByteCount(grainType);\n            var suffix = new byte[grainIdTypeBytes.Length + 1 + grainIdKeyBytes.Length + 1 + grainTypeLength];\n            var index = 0;\n\n            grainIdTypeBytes.CopyTo(suffix, 0);\n            index += grainIdTypeBytes.Length;\n\n            suffix[index++] = (byte)'/';\n\n            grainIdKeyBytes.CopyTo(suffix, index);\n            index += grainIdKeyBytes.Length;\n\n            suffix[index++] = (byte)'/';\n\n            var bytesWritten = Encoding.UTF8.GetBytes(grainType, suffix.AsSpan(index));\n\n            Debug.Assert(bytesWritten == grainTypeLength);\n            Debug.Assert(index + bytesWritten == suffix.Length);\n            return _keyPrefix.Append(suffix);\n        }\n\n        /// <inheritdoc />\n        public async Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            try\n            {\n                RedisValue etag = grainState.ETag ?? \"\";\n                RedisResult response;\n                string newETag;\n                var key = _getKeyFunc(grainType, grainId);\n                if (_options.DeleteStateOnClear)\n                {\n                    const string DeleteScript =\n                        \"\"\"\n                        local etag = redis.call('HGET', KEYS[1], 'etag')\n                        if ((not etag or etag == '') and (not ARGV[1] or ARGV[1] == '')) or etag == ARGV[1] then\n                          redis.call('DEL', KEYS[1])\n                          return 0\n                        else\n                          return -1\n                        end\n                        \"\"\";\n                    response = await _db.ScriptEvaluateAsync(DeleteScript, keys: new[] { key }, values: new[] { etag }).ConfigureAwait(false);\n                    newETag = null;\n                }\n                else\n                {\n                    const string ClearScript =\n                        \"\"\"\n                        local etag = redis.call('HGET', KEYS[1], 'etag')\n                        if ((not etag or etag == '') and (not ARGV[1] or ARGV[1] == '')) or etag == ARGV[1] then\n                          redis.call('HMSET', KEYS[1], 'etag', ARGV[2], 'data', '')\n                          return 0\n                        else\n                          return -1\n                        end\n                        \"\"\";\n                    newETag = Guid.NewGuid().ToString(\"N\");\n                    response = await _db.ScriptEvaluateAsync(ClearScript, keys: new[] { key }, values: new RedisValue[] { etag, newETag }).ConfigureAwait(false);\n                }\n\n                if (response is not null && (int)response == -1)\n                {\n                    throw new InconsistentStateException($\"Version conflict ({nameof(ClearStateAsync)}): ServiceId={_serviceId} ProviderName={_name} GrainType={grainType} GrainId={grainId} ETag={grainState.ETag}.\");\n                }\n\n                grainState.ETag = newETag;\n                grainState.State = CreateInstance<T>();\n                grainState.RecordExists = false;\n            }\n            catch (Exception exception) when (exception is not InconsistentStateException)\n            {\n                throw new RedisStorageException(Invariant($\"Failed to clear grain state for grain {grainType} with ID {grainId}. {exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        private async Task Close(CancellationToken cancellationToken)\n        {\n            if (_connection is null) return;\n\n            await _connection.CloseAsync().ConfigureAwait(false);\n            _connection.Dispose();\n        }\n\n        private T CreateInstance<T>() => _activatorProvider.GetActivator<T>().Create();\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"RedisGrainStorage {Name} is initializing: ServiceId={ServiceId} DeleteOnClear={DeleteOnClear}\"\n        )]\n        private partial void LogDebugInitializing(string name, string serviceId, bool deleteOnClear);\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"Init: Name={Name} ServiceId={ServiceId}, initialized in {ElapsedMilliseconds} ms\"\n        )]\n        private partial void LogDebugInitialized(string name, string serviceId, double elapsedMilliseconds);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Init: Name={Name} ServiceId={ServiceId}, errored in {ElapsedMilliseconds} ms.\"\n        )]\n        private partial void LogErrorInitFailed(Exception exception, string name, string serviceId, double elapsedMilliseconds);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to read grain state for {GrainType} grain with ID {GrainId} and storage key {Key}.\"\n        )]\n        private partial void LogErrorReadStateFailed(Exception exception, string grainType, GrainId grainId, RedisKey key);\n\n        [LoggerMessage(\n            Level = LogLevel.Error,\n            Message = \"Failed to write grain state for {GrainType} grain with ID {GrainId} and storage key {Key}.\"\n        )]\n        private partial void LogErrorWriteStateFailed(Exception exception, string grainType, GrainId grainId, RedisKey key);\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Storage/RedisGrainStorageFactory.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Storage;\nusing System;\n\nnamespace Orleans.Persistence\n{\n    /// <summary>\n    /// Factory used to create instances of Redis grain storage.\n    /// </summary>\n    public static class RedisGrainStorageFactory\n    {\n        /// <summary>\n        /// Creates a grain storage instance.\n        /// </summary>\n        public static RedisGrainStorage Create(IServiceProvider services, string name)\n        {\n            var optionsMonitor = services.GetRequiredService<IOptionsMonitor<RedisStorageOptions>>();\n            var redisGrainStorage = ActivatorUtilities.CreateInstance<RedisGrainStorage>(services, name, optionsMonitor.Get(name));\n            return redisGrainStorage;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Persistence.Redis/Storage/RedisStorageException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Persistence.Redis\n{\n    /// <summary>\n    /// Exception for throwing from Redis grain storage.\n    /// </summary>\n    [GenerateSerializer]\n    public class RedisStorageException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisStorageException\"/>.\n        /// </summary>\n        public RedisStorageException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisStorageException\"/>.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        public RedisStorageException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisStorageException\"/>.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        /// <param name=\"inner\">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>\n        public RedisStorageException(string message, Exception inner) : base(message, inner)\n        {\n        }\n\n        /// <inheritdoc />\n        [Obsolete]\n        protected RedisStorageException(\n            SerializationInfo info,\n            StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Hosting/RedisRemindersProviderBuilder.cs",
    "content": "using Orleans.Providers;\nusing Microsoft.Extensions.Configuration;\nusing Orleans;\nusing Orleans.Hosting;\nusing StackExchange.Redis;\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing System.Threading.Tasks;\n\n[assembly: RegisterProvider(\"Redis\", \"Reminders\", \"Silo\", typeof(RedisRemindersProviderBuilder))]\n[assembly: RegisterProvider(\"AzureRedisCache\", \"Reminders\", \"Silo\", typeof(RedisRemindersProviderBuilder))]\n\nnamespace Orleans.Hosting;\n\ninternal sealed class RedisRemindersProviderBuilder : IProviderBuilder<ISiloBuilder>\n{\n    public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection)\n    {\n        builder.UseRedisReminderService(_ => { });\n        builder.Services.AddOptions<RedisReminderTableOptions>()\n            .Configure<IServiceProvider>((options, services) =>\n            {\n                var serviceKey = configurationSection[\"ServiceKey\"];\n                if (!string.IsNullOrEmpty(serviceKey))\n                {\n                    // Get a connection multiplexer instance by name.\n                    var multiplexer = services.GetRequiredKeyedService<IConnectionMultiplexer>(serviceKey);\n                    options.CreateMultiplexer = _ => Task.FromResult(multiplexer);\n                    options.ConfigurationOptions = new ConfigurationOptions();\n                }\n                else\n                {\n                    // Construct a connection multiplexer from a connection string.\n                    var connectionName = configurationSection[\"ConnectionName\"];\n                    var connectionString = configurationSection[\"ConnectionString\"];\n                    if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))\n                    {\n                        var rootConfiguration = services.GetRequiredService<IConfiguration>();\n                        connectionString = rootConfiguration.GetConnectionString(connectionName);\n                    }\n\n                    if (!string.IsNullOrEmpty(connectionString))\n                    {\n                        options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                    }\n                }\n            });\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Hosting/SiloBuilderReminderExtensions.cs",
    "content": "using System;\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Reminders.Redis;\n\nnamespace Orleans.Hosting\n{\n    /// <summary>\n    /// Silo host builder extensions.\n    /// </summary>\n    public static class SiloBuilderReminderExtensions\n    {\n        /// <summary>\n        /// Adds reminder storage backed by Redis.\n        /// </summary>\n        /// <param name=\"builder\">\n        /// The builder.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"ISiloBuilder\"/>, for chaining.\n        /// </returns>\n        public static ISiloBuilder UseRedisReminderService(this ISiloBuilder builder, Action<RedisReminderTableOptions> configure)\n        {\n            builder.ConfigureServices(services => services.UseRedisReminderService(configure));\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds reminder storage backed by Redis.\n        /// </summary>\n        /// <param name=\"services\">\n        /// The service collection.\n        /// </param>\n        /// <param name=\"configure\">\n        /// The delegate used to configure the reminder store.\n        /// </param>\n        /// <returns>\n        /// The provided <see cref=\"IServiceCollection\"/>, for chaining.\n        /// </returns>\n        public static IServiceCollection UseRedisReminderService(this IServiceCollection services, Action<RedisReminderTableOptions> configure)\n        {\n            services.AddReminders();\n            services.AddSingleton<IReminderTable, RedisReminderTable>();\n            services.Configure<RedisReminderTableOptions>(configure);\n            services.AddSingleton<IConfigurationValidator, RedisReminderTableOptionsValidator>();\n            services.ConfigureFormatter<RedisReminderTableOptions>();\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Orleans.Reminders.Redis.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Reminders.Redis</PackageId>\n    <Title>Microsoft Orleans Reminders Redis Provider</Title>\n    <Description>Microsoft Orleans Reminders implementation that uses Redis</Description>\n    <PackageTags>$(PackageTags) Redis Reminders</PackageTags>\n    <TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StackExchange.Redis\" />\n    <PackageReference Include=\"Newtonsoft.Json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Providers/RedisReminderTableOptions.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\nusing Orleans.Reminders.Redis;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\n\nnamespace Orleans.Configuration\n{\n    /// <summary>\n    /// Redis reminder options.\n    /// </summary>\n    public class RedisReminderTableOptions\n    {\n        /// <summary>\n        /// Gets or sets the Redis client options.\n        /// </summary>\n        [RedactRedisConfigurationOptions]\n        public ConfigurationOptions ConfigurationOptions { get; set; }\n\n        /// <summary>\n        /// The delegate used to create a Redis connection multiplexer.\n        /// </summary>\n        public Func<RedisReminderTableOptions, Task<IConnectionMultiplexer>> CreateMultiplexer { get; set; } = DefaultCreateMultiplexer;\n\n        /// <summary>\n        /// Entry expiry, null by default. A value should be set ONLY for ephemeral environments (like in tests).\n        /// Setting a value different from null will cause reminder entries to be deleted after some period of time.\n        /// </summary>\n        public TimeSpan? EntryExpiry { get; set; } = null;\n\n        /// <summary>\n        /// The default multiplexer creation delegate.\n        /// </summary>\n        public static async Task<IConnectionMultiplexer> DefaultCreateMultiplexer(RedisReminderTableOptions options) => await ConnectionMultiplexer.ConnectAsync(options.ConfigurationOptions);\n    }\n\n    internal class RedactRedisConfigurationOptions : RedactAttribute\n    {\n        public override string Redact(object value) => value is ConfigurationOptions cfg ? cfg.ToString(includePassword: false) : base.Redact(value);\n    }\n\n    /// <summary>\n    /// Configuration validator for <see cref=\"RedisReminderTableOptions\"/>.\n    /// </summary>\n    public class RedisReminderTableOptionsValidator : IConfigurationValidator\n    {\n        private readonly RedisReminderTableOptions _options;\n\n        public RedisReminderTableOptionsValidator(IOptions<RedisReminderTableOptions> options)\n        {\n            _options = options.Value;\n        }\n\n        public void ValidateConfiguration()\n        {\n            if (_options.ConfigurationOptions == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid configuration for {nameof(RedisReminderTable)}. {nameof(RedisReminderTableOptions)}.{nameof(_options.ConfigurationOptions)} is required.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/README.md",
    "content": "# Microsoft Orleans Reminders for Redis\n\n## Introduction\nMicrosoft Orleans Reminders for Redis provides persistence for Orleans reminders using Redis. This allows your Orleans applications to schedule persistent reminders that will be triggered even after silo restarts or grain deactivation.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Reminders.Redis\n```\n\n## Example - Configuring Redis Reminders\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Redis as reminder storage\n            .UseRedisReminderService(options =>\n            {\n                options.ConnectionString = \"localhost:6379\";\n                options.Database = 0;\n                options.KeyPrefix = \"reminder-\"; // Optional prefix for Redis keys\n            });\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Example - Using Reminders in a Grain\n```csharp\npublic class ReminderGrain : Grain, IReminderGrain, IRemindable\n{\n    private string _reminderName = \"MyReminder\";\n\n    public async Task StartReminder(string reminderName)\n    {\n        _reminderName = reminderName;\n        \n        // Register a persistent reminder\n        await RegisterOrUpdateReminder(\n            reminderName,\n            TimeSpan.FromMinutes(2),  // Time to delay before the first tick (must be > 1 minute)\n            TimeSpan.FromMinutes(5)); // Period of the reminder (must be > 1 minute)\n    }\n\n    public async Task StopReminder()\n    {\n        // Find and unregister the reminder\n        var reminder = await GetReminder(_reminderName);\n        if (reminder != null)\n        {\n            await UnregisterReminder(reminder);\n        }\n    }\n\n    public Task ReceiveReminder(string reminderName, TickStatus status)\n    {\n        // This method is called when the reminder ticks\n        Console.WriteLine($\"Reminder {reminderName} triggered at {DateTime.UtcNow}. Status: {status}\");\n        return Task.CompletedTask;\n    }\n}\n```\n\n## Configuration via Microsoft.Extensions.Configuration\n\nYou can configure Orleans Redis reminders using `Microsoft.Extensions.Configuration` (such as `appsettings.json`) instead of configuring it in code. When using this approach, Orleans will automatically read the configuration from the `Orleans` section.\n\n> **Note**: You can use either `\"ProviderType\": \"Redis\"` or `\"ProviderType\": \"AzureRedisCache\"` - both are supported and functionally equivalent.\n\n### Example - appsettings.json\n```json\n{\n  \"ConnectionStrings\": {\n    \"redis\": \"localhost:6379\"\n  },\n  \"Orleans\": {\n    \"ClusterId\": \"my-cluster\",\n    \"ServiceId\": \"MyOrleansService\",\n    \"Reminders\": {\n      \"ProviderType\": \"Redis\",\n      \"ServiceKey\": \"redis\",\n      \"Database\": 0,\n      \"KeyPrefix\": \"reminder-\"\n    }\n  }\n}\n```\n\n### .NET Aspire Integration\n\nFor applications using .NET Aspire, consider using the [.NET Aspire Redis integration](https://learn.microsoft.com/en-us/dotnet/aspire/caching/stackexchange-redis-integration) which provides simplified Redis configuration, automatic service discovery, health checks, and telemetry. The Aspire integration automatically configures connection strings that Orleans can consume via the configuration system.\n\n#### Example - Program.cs with Aspire Redis Integration\n```csharp\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar builder = Host.CreateApplicationBuilder(args);\n\n// Add service defaults (Aspire configurations)\nbuilder.AddServiceDefaults();\n\n// Add Redis via Aspire client integration\nbuilder.AddKeyedRedisClient(\"redis\");\n\n// Add Orleans\nbuilder.UseOrleans();\n\nvar host = builder.Build();\nawait host.StartAsync();\n\n// Get a reference to a grain and call it\nvar client = host.Services.GetRequiredService<IClusterClient>();\nvar grain = client.GetGrain<IReminderGrain>(\"user123\");\nawait grain.StartReminder(\"AspireReminder\");\n\nConsole.WriteLine(\"Reminder started with Aspire Redis!\");\nawait host.WaitForShutdownAsync();\n```\n\nThis example assumes your AppHost project has configured Redis like this:\n```csharp\n// In your AppHost/Program.cs\nvar builder = DistributedApplication.CreateBuilder(args);\n\nvar redis = builder.AddRedis(\"redis\");\n\nvar orleans = builder.AddOrleans(\"orleans\")\n    .WithReminders(redis);\n\nbuilder.AddProject<Projects.MyOrleansApp>(\"orleans-app\")\n    .WithReference(orleans);\n\nbuilder.Build().Run();\n```\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Reminders and Timers](https://learn.microsoft.com/en-us/dotnet/orleans/grains/timers-and-reminders)\n- [Reminder Services](https://learn.microsoft.com/en-us/dotnet/orleans/implementation/reminder-services)\n- [Redis Documentation](https://redis.io/documentation)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Storage/RedisReminderTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nusing Newtonsoft.Json;\n\nusing Orleans.Configuration;\nusing Orleans.Runtime;\n\nusing StackExchange.Redis;\nusing static System.FormattableString;\n\nnamespace Orleans.Reminders.Redis\n{\n    internal partial class RedisReminderTable : IReminderTable\n    {\n        private readonly RedisKey _hashSetKey;\n        private readonly RedisReminderTableOptions _redisOptions;\n        private readonly ClusterOptions _clusterOptions;\n        private readonly ILogger _logger;\n        private IConnectionMultiplexer _muxer;\n        private IDatabase _db;\n\n        private readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings()\n        {\n            DateFormatHandling = DateFormatHandling.IsoDateFormat,\n            DefaultValueHandling = DefaultValueHandling.Ignore,\n            MissingMemberHandling = MissingMemberHandling.Ignore,\n            NullValueHandling = NullValueHandling.Ignore,\n        };\n\n        public RedisReminderTable(\n            ILogger<RedisReminderTable> logger,\n            IOptions<ClusterOptions> clusterOptions,\n            IOptions<RedisReminderTableOptions> redisOptions)\n        {\n            _redisOptions = redisOptions.Value;\n            _clusterOptions = clusterOptions.Value;\n            _logger = logger;\n\n            _hashSetKey = Encoding.UTF8.GetBytes($\"{_clusterOptions.ServiceId}/reminders\");\n        }\n\n        public async Task Init()\n        {\n            try\n            {\n                _muxer = await _redisOptions.CreateMultiplexer(_redisOptions);\n                _db = _muxer.GetDatabase();\n\n                if (_redisOptions.EntryExpiry is { } expiry)\n                {\n                    await _db.KeyExpireAsync(_hashSetKey, expiry);\n                }\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName)\n        {\n            try\n            {\n                var (from, to) = GetFilter(grainId, reminderName);\n                RedisValue[] values = await _db.SortedSetRangeByValueAsync(_hashSetKey, from, to);\n                if (values.Length == 0)\n                {\n                    return null;\n                }\n                else\n                {\n                    return ConvertToEntry(values.SingleOrDefault());\n                }\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task<ReminderTableData> ReadRows(GrainId grainId)\n        {\n            try\n            {\n                var (from, to) = GetFilter(grainId);\n                RedisValue[] values = await _db.SortedSetRangeByValueAsync(_hashSetKey, from, to);\n                IEnumerable<ReminderEntry> records = values.Select(static v => ConvertToEntry(v));\n                return new ReminderTableData(records);\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task<ReminderTableData> ReadRows(uint begin, uint end)\n        {\n            try\n            {\n                var (_, from) = GetFilter(begin);\n                var (_, to) = GetFilter(end);\n                IEnumerable<RedisValue> values;\n                if (begin < end)\n                {\n                    // -----begin******end-----\n                    values = await _db.SortedSetRangeByValueAsync(_hashSetKey, from, to);\n                }\n                else\n                {\n                    // *****end------begin*****\n                    RedisValue[] values1 = await _db.SortedSetRangeByValueAsync(_hashSetKey, from, \"\\\"FFFFFFFF\\\",#\");\n                    RedisValue[] values2 = await _db.SortedSetRangeByValueAsync(_hashSetKey, \"\\\"00000000\\\",\\\"\", to);\n                    values = values1.Concat(values2);\n                }\n\n                IEnumerable<ReminderEntry> records = values.Select(static v => ConvertToEntry(v));\n                return new ReminderTableData(records);\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag)\n        {\n            try\n            {\n                var (from, to) = GetFilter(grainId, reminderName, eTag);\n                long removed = await _db.SortedSetRemoveRangeByValueAsync(_hashSetKey, from, to);\n                return removed > 0;\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task TestOnlyClearTable()\n        {\n            try\n            {\n                await _db.KeyDeleteAsync(_hashSetKey);\n            }\n            catch (Exception exception)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        public async Task<string> UpsertRow(ReminderEntry entry)\n        {\n            const string UpsertScript =\n                \"\"\"\n                local key = KEYS[1]\n                local from = '[' .. ARGV[1] -- start of the conditional (with etag) key range\n                local to = '[' .. ARGV[2] -- end of the conditional (with etag) key range\n                local value = ARGV[3]\n\n                -- Remove all entries for this reminder\n                local remRes = redis.call('ZREMRANGEBYLEX', key, from, to);\n\n                -- Add the new reminder entry\n                local addRes = redis.call('ZADD', key, 0, value);\n                return { key, from, to, value, remRes, addRes }\n                \"\"\";\n\n            try\n            {\n                LogDebugUpsertRow(new(entry), entry.ETag);\n\n                var (newETag, value) = ConvertFromEntry(entry);\n                var (from, to) = GetFilter(entry.GrainId, entry.ReminderName);\n                var res = await _db.ScriptEvaluateAsync(UpsertScript, keys: new[] { _hashSetKey }, values: new[] { from, to, value });\n                return newETag;\n            }\n            catch (Exception exception) when (exception is not ReminderException)\n            {\n                throw new RedisRemindersException(Invariant($\"{exception.GetType()}: {exception.Message}\"));\n            }\n        }\n\n        private static ReminderEntry ConvertToEntry(string reminderValue)\n        {\n            string[] segments = JsonConvert.DeserializeObject<string[]>($\"[{reminderValue}]\");\n\n            return new ReminderEntry\n            {\n                GrainId = GrainId.Parse(segments[1]),\n                ReminderName = segments[2],\n                ETag = segments[3],\n                StartAt = DateTime.Parse(segments[4], null, DateTimeStyles.RoundtripKind),\n                Period = TimeSpan.Parse(segments[5]),\n            };\n        }\n\n        private (RedisValue from, RedisValue to) GetFilter(uint grainHash)\n        {\n            return GetFilter(grainHash.ToString(\"X8\"));\n        }\n\n        private (RedisValue from, RedisValue to) GetFilter(GrainId grainId)\n        {\n            return GetFilter(grainId.GetUniformHashCode().ToString(\"X8\"), grainId.ToString());\n        }\n\n        private (RedisValue from, RedisValue to) GetFilter(GrainId grainId, string reminderName)\n        {\n            return GetFilter(grainId.GetUniformHashCode().ToString(\"X8\"), grainId.ToString(), reminderName);\n        }\n\n        private (RedisValue from, RedisValue to) GetFilter(GrainId grainId, string reminderName, string eTag)\n        {\n            return GetFilter(grainId.GetUniformHashCode().ToString(\"X8\"), grainId.ToString(), reminderName, eTag);\n        }\n\n        private (RedisValue from, RedisValue to) GetFilter(params string[] segments)\n        {\n            string prefix = JsonConvert.SerializeObject(segments, _jsonSettings);\n            return ($\"{prefix[1..^1]},\\\"\", $\"{prefix[1..^1]},#\");\n        }\n\n        private (RedisValue eTag, RedisValue value) ConvertFromEntry(ReminderEntry entry)\n        {\n            string grainHash = entry.GrainId.GetUniformHashCode().ToString(\"X8\");\n            string eTag = Guid.NewGuid().ToString();\n            string[] segments = new string[]\n            {\n                grainHash,\n                entry.GrainId.ToString(),\n                entry.ReminderName,\n                eTag,\n                entry.StartAt.ToString(\"O\"),\n                entry.Period.ToString()\n            };\n\n            return (eTag, JsonConvert.SerializeObject(segments, _jsonSettings)[1..^1]);\n        }\n\n        private readonly struct ReminderEntryLogValue(ReminderEntry entry)\n        {\n            public override string ToString() => entry.ToString();\n        }\n\n        [LoggerMessage(\n            Level = LogLevel.Debug,\n            Message = \"UpsertRow entry = {Entry}, ETag = {ETag}\"\n        )]\n        private partial void LogDebugUpsertRow(ReminderEntryLogValue entry, string eTag);\n    }\n}\n"
  },
  {
    "path": "src/Redis/Orleans.Reminders.Redis/Storage/RedisRemindersException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Reminders.Redis\n{\n    /// <summary>\n    /// Exception thrown from <see cref=\"RedisReminderTable\"/>.\n    /// </summary>\n    [GenerateSerializer]\n    public class RedisRemindersException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisRemindersException\"/>.\n        /// </summary>\n        public RedisRemindersException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisRemindersException\"/>.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        public RedisRemindersException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"RedisRemindersException\"/>.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        /// <param name=\"inner\">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>\n        public RedisRemindersException(string message, Exception inner) : base(message, inner)\n        {\n        }\n\n        /// <inheritdoc />\n        [Obsolete]\n        protected RedisRemindersException(\n            SerializationInfo info,\n            StreamingContext context) : base(info, context)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/ByteStringCodec.cs",
    "content": "using System;\nusing Google.Protobuf;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Serializer for <see cref=\"ByteString\"/>.\n/// </summary>\n[RegisterSerializer]\npublic sealed class ByteStringCodec : IFieldCodec<ByteString>\n{\n    /// <inheritdoc/>\n    ByteString IFieldCodec<ByteString>.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<ByteString, TInput>(ref reader, field);\n        }\n\n        field.EnsureWireType(WireType.LengthPrefixed);\n        var length = reader.ReadVarUInt32();\n        var result = UnsafeByteOperations.UnsafeWrap(reader.ReadBytes(length));\n        ReferenceCodec.RecordObject(reader.Session, result);\n        return result;\n    }\n\n    /// <inheritdoc/>\n    void IFieldCodec<ByteString>.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, ByteString value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, typeof(ByteString), WireType.LengthPrefixed);\n        writer.WriteVarUInt32((uint)value.Length);\n        writer.Write(value.Span);\n    }\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/ByteStringCopier.cs",
    "content": "using Google.Protobuf;\nusing Orleans.Serialization.Cloning;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Copier for <see cref=\"ByteString\"/>.\n/// </summary>\n[RegisterCopier]\npublic sealed class ByteStringCopier : IDeepCopier<ByteString>\n{\n    /// <inheritdoc/>\n    public ByteString DeepCopy(ByteString input, CopyContext context)\n    {\n        if (context.TryGetCopy<ByteString>(input, out var result))\n        {\n            return result;\n        }\n\n        result = ByteString.CopyFrom(input.Span);\n        context.RecordCopy(input, result);\n        return result;\n    }\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/MapFieldCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing Google.Protobuf.Collections;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Serializer for <see cref=\"MapField{TKey,TValue}\"/>.\n/// </summary>\n/// <typeparam name=\"TKey\">The key type.</typeparam>\n/// <typeparam name=\"TValue\">The value type.</typeparam>\n[RegisterSerializer]\npublic sealed class MapFieldCodec<TKey, TValue> : IFieldCodec<MapField<TKey, TValue>>\n{\n    private readonly Type _keyFieldType = typeof(TKey);\n    private readonly Type _valueFieldType = typeof(TValue);\n\n    private readonly IFieldCodec<TKey> _keyCodec;\n    private readonly IFieldCodec<TValue> _valueCodec;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"MapFieldCodec{TKey, TValue}\"/> class.\n    /// </summary>\n    /// <param name=\"keyCodec\">The key codec.</param>\n    /// <param name=\"valueCodec\">The value codec.</param>\n    public MapFieldCodec(\n        IFieldCodec<TKey> keyCodec,\n        IFieldCodec<TValue> valueCodec)\n    {\n        _keyCodec = OrleansGeneratedCodeHelper.UnwrapService(this, keyCodec);\n        _valueCodec = OrleansGeneratedCodeHelper.UnwrapService(this, valueCodec);\n    }\n\n    /// <inheritdoc/>\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, MapField<TKey, TValue> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n        if (value.Count > 0)\n        {\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value)\n            {\n                _keyCodec.WriteField(ref writer, innerFieldIdDelta, _keyFieldType, element.Key);\n                _valueCodec.WriteField(ref writer, 0, _valueFieldType, element.Value);\n                innerFieldIdDelta = 0;\n            }\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    public MapField<TKey, TValue> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<MapField<TKey, TValue>, TInput>(ref reader, field);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        TKey key = default;\n        var valueExpected = false;\n        MapField<TKey, TValue> result = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                    if (length > 10240 && length > reader.Length)\n                    {\n                        ThrowInvalidSizeException(length);\n                    }\n\n                    result = CreateInstance(reader.Session, placeholderReferenceId);\n                    break;\n                case 1:\n                    if (result is null)\n                        ThrowLengthFieldMissing();\n\n                    if (!valueExpected)\n                    {\n                        key = _keyCodec.ReadValue(ref reader, header);\n                        valueExpected = true;\n                    }\n                    else\n                    {\n                        result.Add(key, _valueCodec.ReadValue(ref reader, header));\n                        valueExpected = false;\n                    }\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        result ??= CreateInstance(reader.Session, placeholderReferenceId);\n        return result;\n    }\n\n    private static MapField<TKey, TValue> CreateInstance(SerializerSession session, uint placeholderReferenceId)\n    {\n        var result = new MapField<TKey, TValue>();\n        ReferenceCodec.RecordObject(session, result, placeholderReferenceId);\n        return result;\n    }\n\n    private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n        $\"Declared length of {typeof(MapField<TKey, TValue>)}, {length}, is greater than total length of input.\");\n\n    private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized MapField is missing its length field.\");\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/MapFieldCopier.cs",
    "content": "using Google.Protobuf.Collections;\nusing Orleans.Serialization.Cloning;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Copier for <see cref=\"MapField{TKey, TValue}\"/>.\n/// </summary>\n/// <typeparam name=\"TKey\">The type of the t key.</typeparam>\n/// <typeparam name=\"TValue\">The type of the t value.</typeparam>\n[RegisterCopier]\npublic sealed class MapFieldCopier<TKey, TValue> : IDeepCopier<MapField<TKey, TValue>>, IBaseCopier<MapField<TKey, TValue>>\n{\n    private readonly IDeepCopier<TKey> _keyCopier;\n    private readonly IDeepCopier<TValue> _valueCopier;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"MapFieldCopier{TKey, TValue}\"/> class.\n    /// </summary>\n    /// <param name=\"keyCopier\">The key copier.</param>\n    /// <param name=\"valueCopier\">The value copier.</param>\n    public MapFieldCopier(IDeepCopier<TKey> keyCopier, IDeepCopier<TValue> valueCopier)\n    {\n        _keyCopier = keyCopier;\n        _valueCopier = valueCopier;\n    }\n\n    /// <inheritdoc/>\n    public MapField<TKey, TValue> DeepCopy(MapField<TKey, TValue> input, CopyContext context)\n    {\n        if (context.TryGetCopy<MapField<TKey, TValue>>(input, out var result))\n        {\n            return result;\n        }\n\n        if (input.GetType() != typeof(MapField<TKey, TValue>))\n        {\n            return context.DeepCopy(input);\n        }\n\n        result = new MapField<TKey, TValue>();\n        context.RecordCopy(input, result);\n        foreach (var pair in input)\n        {\n            result[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    public void DeepCopy(MapField<TKey, TValue> input, MapField<TKey, TValue> output, CopyContext context)\n    {\n        foreach (var pair in input)\n        {\n            output[_keyCopier.DeepCopy(pair.Key, context)] = _valueCopier.DeepCopy(pair.Value, context);\n        }\n    }\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/Orleans.Serialization.Protobuf.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageId>Microsoft.Orleans.Serialization.Protobuf</PackageId>\n    <TargetFrameworks>$(DefaultTargetFrameworks);netstandard2.1</TargetFrameworks>\n    <PackageDescription>Google.Protobuf integration for Orleans.Serialization</PackageDescription>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <IsOrleansFrameworkPart>false</IsOrleansFrameworkPart>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Google.Protobuf\" Version=\"$(GoogleProtobufVersion)\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/ProtobufCodec.cs",
    "content": "using Google.Protobuf;\nusing Orleans.Metadata;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.WireProtocol;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Orleans.Serialization;\n\n[Alias(WellKnownAlias)]\npublic sealed class ProtobufCodec : IGeneralizedCodec, IGeneralizedCopier, ITypeFilter\n{\n    public const string WellKnownAlias = \"protobuf\";\n\n    private static readonly Type SelfType = typeof(ProtobufCodec);\n    private static readonly Type MessageType = typeof(IMessage);\n    private static readonly Type MessageGenericType = typeof(IMessage<>);\n    private static readonly ConcurrentDictionary<RuntimeTypeHandle, MessageParser> MessageParsers = new();\n\n    private readonly ICodecSelector[] _serializableTypeSelectors;\n    private readonly ICopierSelector[] _copyableTypeSelectors;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"ProtobufCodec\"/> class.\n    /// </summary>\n    /// <param name=\"serializableTypeSelectors\">Filters used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"copyableTypeSelectors\">Filters used to indicate which types should be copied by this codec.</param>\n    public ProtobufCodec(\n        IEnumerable<ICodecSelector> serializableTypeSelectors,\n        IEnumerable<ICopierSelector> copyableTypeSelectors)\n    {\n        _serializableTypeSelectors = serializableTypeSelectors.Where(t => string.Equals(t.CodecName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n        _copyableTypeSelectors = copyableTypeSelectors.Where(t => string.Equals(t.CopierName, WellKnownAlias, StringComparison.Ordinal)).ToArray();\n    }\n\n    /// <inheritdoc/>\n    public object DeepCopy(object input, CopyContext context)\n    {\n        if (!context.TryGetCopy(input, out object result))\n        {\n            if (input is not IMessage protobufMessage)\n            {\n                throw new InvalidOperationException(\"Input is not a protobuf message\");\n            }\n\n            var messageSize = protobufMessage.CalculateSize();\n            using var buffer = new PooledBuffer();\n            var spanBuffer = buffer.GetSpan(messageSize)[..messageSize];\n            protobufMessage.WriteTo(spanBuffer);\n\n            result = protobufMessage.Descriptor.Parser.ParseFrom(spanBuffer);\n\n            context.RecordCopy(input, result);\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCodec.IsSupportedType(Type type)\n    {\n        if (type == SelfType)\n        {\n            return true;\n        }\n\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _serializableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return IsProtobufMessage(type);\n            }\n        }\n\n        return false;\n    }\n\n    /// <inheritdoc/>\n    bool IGeneralizedCopier.IsSupportedType(Type type)\n    {\n        if (CommonCodecTypeFilter.IsAbstractOrFrameworkType(type))\n        {\n            return false;\n        }\n\n        foreach (var selector in _copyableTypeSelectors)\n        {\n            if (selector.IsSupportedType(type))\n            {\n                return IsProtobufMessage(type);\n            }\n        }\n\n        return false;\n    }\n\n    /// <inheritdoc/>\n    bool? ITypeFilter.IsTypeAllowed(Type type)\n    {\n        if (!MessageType.IsAssignableFrom(type))\n        {\n            return null;\n        }\n\n        if (type == MessageType)\n        {\n            // While IMessage is the basis of all supported types, it isn't directly supported\n            return null;\n        }\n\n        return ((IGeneralizedCodec)this).IsSupportedType(type) || ((IGeneralizedCopier)this).IsSupportedType(type);\n    }\n\n    private static bool IsProtobufMessage(Type type)\n    {\n        if (type == MessageType)\n        {\n            // Not a concrete implementation, so not directly serializable\n            return false;\n        }\n\n        if (type == MessageGenericType)\n        {\n            // Not a concrete implementation, but the generic type does give the concrete type\n            type = type.GenericTypeArguments[0];\n        }\n\n        if (!MessageParsers.ContainsKey(type.TypeHandle))\n        {\n            if (Activator.CreateInstance(type) is not IMessage protobufMessageInstance)\n            {\n                return false;\n            }\n\n            MessageParsers.TryAdd(type.TypeHandle, protobufMessageInstance.Descriptor.Parser);\n        }\n\n        return true;\n    }\n\n    /// <inheritdoc/>\n    object IFieldCodec.ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.IsReference)\n        {\n            return ReferenceCodec.ReadReference(ref reader, field.FieldType);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        object result = null;\n        Type type = null;\n        uint fieldId = 0;\n\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    type = reader.Session.TypeCodec.ReadLengthPrefixed(ref reader);\n                    break;\n                case 1:\n                    if (type is null)\n                    {\n                        ThrowTypeFieldMissing();\n                    }\n\n                    if (!MessageParsers.TryGetValue(type.TypeHandle, out var messageParser))\n                    {\n                        throw new ArgumentException($\"No parser found for the expected type {type.Name}\", nameof(TInput));\n                    }\n\n                    ReferenceCodec.MarkValueField(reader.Session);\n                    var length = (int)reader.ReadVarUInt32();\n\n                    using (var buffer = new PooledBuffer())\n                    {\n                        var spanBuffer = buffer.GetSpan(length)[..length];\n                        reader.ReadBytes(spanBuffer);\n                        result = messageParser.ParseFrom(spanBuffer);\n                    }\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        return result;\n    }\n\n    private static void ThrowTypeFieldMissing() => throw new RequiredFieldMissingException(\"Serialized value is missing its type field.\");\n\n    /// <inheritdoc/>\n    void IFieldCodec.WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, object value)\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        if (value is not IMessage protobufMessage)\n        {\n            throw new ArgumentException(\"The provided value for serialization in not an instance of IMessage\");\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, SelfType, WireType.TagDelimited);\n\n        // Write the type name\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(0, WireType.LengthPrefixed);\n        writer.Session.TypeCodec.WriteLengthPrefixed(ref writer, value.GetType());\n\n        var messageSize = protobufMessage.CalculateSize();\n\n        using var buffer = new PooledBuffer();\n        var spanBuffer = buffer.GetSpan(messageSize)[..messageSize];\n\n        // Write the serialized payload\n        protobufMessage.WriteTo(spanBuffer);\n\n        ReferenceCodec.MarkValueField(writer.Session);\n        writer.WriteFieldHeaderExpected(1, WireType.LengthPrefixed);\n        writer.WriteVarUInt32((uint)spanBuffer.Length);\n        writer.Write(spanBuffer);\n\n        writer.WriteEndObject();\n    }\n}\n"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/README.md",
    "content": "# Microsoft Orleans Serialization for Protobuf\n\n## Introduction\nMicrosoft Orleans Serialization for Protobuf provides Protocol Buffers (Protobuf) serialization support for Microsoft Orleans using **Google.Protobuf**. This package integrates Google's official `Google.Protobuf` library with Orleans, allowing you to use Protocol Buffers messages in your grain interfaces and implementations.\n\n## Getting Started\nTo use this package, install it via NuGet:\n\n```shell\ndotnet add package Microsoft.Orleans.Serialization.Protobuf\n```\n\n## Example - Configuring Protobuf Serialization\n```csharp\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\n\nvar builder = Host.CreateApplicationBuilder(args)\n    .UseOrleans(siloBuilder =>\n    {\n        siloBuilder\n            .UseLocalhostClustering()\n            // Configure Protobuf as a serializer\n            .AddSerializer(serializerBuilder => serializerBuilder.AddProtobufSerializer());\n    });\n\n// Run the host\nawait builder.RunAsync();\n```\n\n## Using Protobuf Types with Orleans\nThis package supports types generated from `.proto` files using Google.Protobuf. For detailed information on creating Protobuf messages and configuring your project, see [Create Protobuf messages for .NET apps](https://learn.microsoft.com/en-us/aspnet/core/grpc/protobuf).\n\nOnce you have defined your Protobuf messages and configured code generation, you can use them directly in your grain interfaces:\n\n```csharp\nusing Orleans;\nusing MyApp.Models;\n\npublic interface IMyGrain : IGrainWithStringKey\n{\n    Task<MyProtobufClass> GetData();\n    Task SetData(MyProtobufClass data);\n}\n\npublic class MyGrain : Grain, IMyGrain\n{\n    private MyProtobufClass _data;\n\n    public Task<MyProtobufClass> GetData() => Task.FromResult(_data);\n    public Task SetData(MyProtobufClass data)\n    {\n        _data = data;\n        return Task.CompletedTask;\n    }\n}\n```\n\n**Note:** Google.Protobuf collection types (`RepeatedField<T>`, `MapField<TKey, TValue>`, and `ByteString`) are automatically supported.\n\n## Documentation\nFor more comprehensive documentation, please refer to:\n- [Create Protobuf messages for .NET apps](https://learn.microsoft.com/en-us/aspnet/core/grpc/protobuf) - Official guide for working with Protobuf in .NET\n- [Microsoft Orleans Documentation](https://learn.microsoft.com/dotnet/orleans/)\n- [Orleans Serialization](https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization)\n\n## Feedback & Contributing\n- If you have any issues or would like to provide feedback, please [open an issue on GitHub](https://github.com/dotnet/orleans/issues)\n- Join our community on [Discord](https://aka.ms/orleans-discord)\n- Follow the [@msftorleans](https://twitter.com/msftorleans) Twitter account for Orleans announcements\n- Contributions are welcome! Please review our [contribution guidelines](https://github.com/dotnet/orleans/blob/main/CONTRIBUTING.md)\n- This project is licensed under the [MIT license](https://github.com/dotnet/orleans/blob/main/LICENSE)"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/RepeatedFieldCodec.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.CompilerServices;\nusing Google.Protobuf.Collections;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Serializer for <see cref=\"RepeatedField{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterSerializer]\npublic sealed class RepeatedFieldCodec<T> : IFieldCodec<RepeatedField<T>>\n{\n    private readonly Type CodecElementType = typeof(T);\n\n    private readonly IFieldCodec<T> _fieldCodec;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"RepeatedFieldCodec{T}\"/> class.\n    /// </summary>\n    /// <param name=\"fieldCodec\">The field codec.</param>\n    public RepeatedFieldCodec(IFieldCodec<T> fieldCodec)\n    {\n        _fieldCodec = OrleansGeneratedCodeHelper.UnwrapService(this, fieldCodec);\n    }\n\n    /// <inheritdoc/>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, RepeatedField<T> value) where TBufferWriter : IBufferWriter<byte>\n    {\n        if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, value))\n        {\n            return;\n        }\n\n        writer.WriteFieldHeader(fieldIdDelta, expectedType, value.GetType(), WireType.TagDelimited);\n\n        if (value.Count > 0)\n        {\n            UInt32Codec.WriteField(ref writer, 0, (uint)value.Count);\n            uint innerFieldIdDelta = 1;\n            foreach (var element in value)\n            {\n                _fieldCodec.WriteField(ref writer, innerFieldIdDelta, CodecElementType, element);\n                innerFieldIdDelta = 0;\n            }\n        }\n\n        writer.WriteEndObject();\n    }\n\n    /// <inheritdoc/>\n    public RepeatedField<T> ReadValue<TInput>(ref Reader<TInput> reader, Field field)\n    {\n        if (field.WireType == WireType.Reference)\n        {\n            return ReferenceCodec.ReadReference<RepeatedField<T>, TInput>(ref reader, field);\n        }\n\n        field.EnsureWireTypeTagDelimited();\n\n        var placeholderReferenceId = ReferenceCodec.CreateRecordPlaceholder(reader.Session);\n        RepeatedField<T> result = null;\n        uint fieldId = 0;\n        while (true)\n        {\n            var header = reader.ReadFieldHeader();\n            if (header.IsEndBaseOrEndObject)\n            {\n                break;\n            }\n\n            fieldId += header.FieldIdDelta;\n            switch (fieldId)\n            {\n                case 0:\n                    var length = (int)UInt32Codec.ReadValue(ref reader, header);\n                    if (length > 10240 && length > reader.Length)\n                    {\n                        ThrowInvalidSizeException(length);\n                    }\n\n                    result = new RepeatedField<T>{ Capacity = length };\n                    ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n                    break;\n                case 1:\n                    if (result is null)\n                    {\n                        ThrowLengthFieldMissing();\n                    }\n\n                    result.Add(_fieldCodec.ReadValue(ref reader, header));\n                    break;\n                default:\n                    reader.ConsumeUnknownField(header);\n                    break;\n            }\n        }\n\n        if (result is null)\n        {\n            result = new();\n            ReferenceCodec.RecordObject(reader.Session, result, placeholderReferenceId);\n        }\n\n        return result;\n    }\n\n    private static void ThrowInvalidSizeException(int length) => throw new IndexOutOfRangeException(\n        $\"Declared length of {typeof(RepeatedField<T>)}, {length}, is greater than total length of input.\");\n\n    private static void ThrowLengthFieldMissing() => throw new RequiredFieldMissingException(\"Serialized RepeatedField is missing its length field.\");\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/RepeatedFieldCopier.cs",
    "content": "using Google.Protobuf.Collections;\nusing Orleans.Serialization.Cloning;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Copier for <see cref=\"RepeatedField{T}\"/>.\n/// </summary>\n/// <typeparam name=\"T\">The element type.</typeparam>\n[RegisterCopier]\npublic sealed class RepeatedFieldCopier<T> : IDeepCopier<RepeatedField<T>>, IBaseCopier<RepeatedField<T>>\n{\n    private readonly IDeepCopier<T> _copier;\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"RepeatedFieldCopier{T}\"/> class.\n    /// </summary>\n    /// <param name=\"valueCopier\">The value copier.</param>\n    public RepeatedFieldCopier(IDeepCopier<T> valueCopier)\n    {\n        _copier = valueCopier;\n    }\n\n    /// <inheritdoc/>\n    public RepeatedField<T> DeepCopy(RepeatedField<T> input, CopyContext context)\n    {\n        if (context.TryGetCopy<RepeatedField<T>>(input, out var result))\n        {\n            return result;\n        }\n\n        if (input.GetType() != typeof(RepeatedField<T>))\n        {\n            return context.DeepCopy(input);\n        }\n\n        result = new RepeatedField<T> { Capacity = input.Count };\n        context.RecordCopy(input, result);\n        foreach (var item in input)\n        {\n            result.Add(_copier.DeepCopy(item, context));\n        }\n\n        return result;\n    }\n\n    /// <inheritdoc/>\n    public void DeepCopy(RepeatedField<T> input, RepeatedField<T> output, CopyContext context)\n    {\n        foreach (var item in input)\n        {\n            output.Add(_copier.DeepCopy(item, context));\n        }\n    }\n}"
  },
  {
    "path": "src/Serializers/Orleans.Serialization.Protobuf/SerializationHostingExtensions.cs",
    "content": "using Google.Protobuf;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Utilities.Internal;\nusing System;\n\nnamespace Orleans.Serialization;\n\n/// <summary>\n/// Extension method for <see cref=\"ISerializerBuilder\"/>.\n/// </summary>\npublic static class SerializationHostingExtensions\n{\n    private static readonly ServiceDescriptor ServiceDescriptor = new (typeof(ProtobufCodec), typeof(ProtobufCodec));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing Protobuf IMessage types using <see cref=\"MessageParser\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    public static ISerializerBuilder AddProtobufSerializer(\n        this ISerializerBuilder serializerBuilder)\n        => serializerBuilder.AddProtobufSerializer(\n            isSerializable: type => typeof(IMessage).IsAssignableFrom(type),\n            isCopyable: type => typeof(IMessage).IsAssignableFrom(type));\n\n    /// <summary>\n    /// Adds support for serializing and deserializing Protobuf IMessage types using <see cref=\"MessageParser\"/>.\n    /// </summary>\n    /// <param name=\"serializerBuilder\">The serializer builder.</param>\n    /// <param name=\"isSerializable\">A delegate used to indicate which types should be serialized by this codec.</param>\n    /// <param name=\"isCopyable\">A delegate used to indicate which types should be copied by this codec.</param>\n    public static ISerializerBuilder AddProtobufSerializer(\n        this ISerializerBuilder serializerBuilder,\n        Func<Type, bool> isSerializable,\n        Func<Type, bool> isCopyable)\n    {\n        var services = serializerBuilder.Services;\n\n        if (isSerializable != null)\n        {\n            services.AddSingleton<ICodecSelector>(new DelegateCodecSelector\n            {\n                CodecName = ProtobufCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isSerializable\n            });\n        }\n\n        if (isCopyable != null)\n        {\n            services.AddSingleton<ICopierSelector>(new DelegateCopierSelector\n            {\n                CopierName = ProtobufCodec.WellKnownAlias,\n                IsSupportedTypeDelegate = isCopyable\n            });\n        }\n\n        if (!services.Contains(ServiceDescriptor))\n        {\n            services.AddSingleton<ProtobufCodec>();\n            services.AddFromExisting<IGeneralizedCodec, ProtobufCodec>();\n            services.AddFromExisting<IGeneralizedCopier, ProtobufCodec>();\n            services.AddFromExisting<ITypeFilter, ProtobufCodec>();\n\n            serializerBuilder.Configure(options => options.WellKnownTypeAliases[ProtobufCodec.WellKnownAlias] = typeof(ProtobufCodec));\n        }\n\n        return serializerBuilder;\n    }\n}"
  },
  {
    "path": "src/api/AWS/Orleans.Clustering.DynamoDB/Orleans.Clustering.DynamoDB.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Clustering.DynamoDB\n{\n    public partial class DynamoDBClientOptions\n    {\n        [Redact]\n        public string AccessKey { get { throw null; } set { } }\n\n        public string ProfileName { get { throw null; } set { } }\n\n        [Redact]\n        public string SecretKey { get { throw null; } set { } }\n\n        public string Service { get { throw null; } set { } }\n\n        public string Token { get { throw null; } set { } }\n    }\n\n    public partial class DynamoDBGatewayListProviderHelper\n    {\n    }\n\n    public partial class DynamoDBMembershipHelper\n    {\n        public static void ParseDataConnectionString(string dataConnectionString, Configuration.DynamoDBClusteringOptions options) { }\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class DynamoDBClusteringOptions : Clustering.DynamoDB.DynamoDBClientOptions\n    {\n        public bool CreateIfNotExists { get { throw null; } set { } }\n\n        public int ReadCapacityUnits { get { throw null; } set { } }\n\n        public string TableName { get { throw null; } set { } }\n\n        public bool UpdateIfExists { get { throw null; } set { } }\n\n        public bool UseProvisionedThroughput { get { throw null; } set { } }\n\n        public int WriteCapacityUnits { get { throw null; } set { } }\n    }\n\n    public partial class DynamoDBClusteringSiloOptions\n    {\n        [RedactConnectionString]\n        public string ConnectionString { get { throw null; } set { } }\n    }\n\n    public partial class DynamoDBGatewayOptions : Clustering.DynamoDB.DynamoDBClientOptions\n    {\n        public bool CreateIfNotExists { get { throw null; } set { } }\n\n        public int ReadCapacityUnits { get { throw null; } set { } }\n\n        public string TableName { get { throw null; } set { } }\n\n        public bool UpdateIfExists { get { throw null; } set { } }\n\n        public bool UseProvisionedThroughput { get { throw null; } set { } }\n\n        public int WriteCapacityUnits { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AwsUtilsHostingExtensions\n    {\n        public static IClientBuilder UseDynamoDBClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBGatewayOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseDynamoDBClustering(this IClientBuilder builder, System.Action<Configuration.DynamoDBGatewayOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseDynamoDBClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBClusteringOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseDynamoDBClustering(this ISiloBuilder builder, System.Action<Configuration.DynamoDBClusteringOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AWS/Orleans.Persistence.DynamoDB/Orleans.Persistence.DynamoDB.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class DynamoDBGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        public DynamoDBGrainStorageOptionsValidator(DynamoDBStorageOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class DynamoDBStorageOptions : Persistence.DynamoDB.DynamoDBClientOptions, Storage.IStorageProviderSerializerOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public bool CreateIfNotExists { get { throw null; } set { } }\n\n        public bool DeleteStateOnClear { get { throw null; } set { } }\n\n        public Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public int ReadCapacityUnits { get { throw null; } set { } }\n\n        public string ServiceId { get { throw null; } set { } }\n\n        public string TableName { get { throw null; } set { } }\n\n        public System.TimeSpan? TimeToLive { get { throw null; } set { } }\n\n        public bool UpdateIfExists { get { throw null; } set { } }\n\n        public bool UseProvisionedThroughput { get { throw null; } set { } }\n\n        public int WriteCapacityUnits { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class DynamoDBGrainStorageServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDynamoDBGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDynamoDBGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Configuration.DynamoDBStorageOptions> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDynamoDBGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddDynamoDBGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Configuration.DynamoDBStorageOptions> configureOptions) { throw null; }\n    }\n\n    public static partial class DynamoDBGrainStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddDynamoDBGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddDynamoDBGrainStorage(this ISiloBuilder builder, string name, System.Action<Configuration.DynamoDBStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddDynamoDBGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DynamoDBStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddDynamoDBGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.DynamoDBStorageOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Persistence.DynamoDB\n{\n    public partial class DynamoDBClientOptions\n    {\n        [Redact]\n        public string AccessKey { get { throw null; } set { } }\n\n        public string ProfileName { get { throw null; } set { } }\n\n        [Redact]\n        public string SecretKey { get { throw null; } set { } }\n\n        public string Service { get { throw null; } set { } }\n\n        public string Token { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Storage\n{\n    public partial class DynamoDBGrainStorage : IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public DynamoDBGrainStorage(string name, Configuration.DynamoDBStorageOptions options, Serialization.Serializers.IActivatorProvider activatorProvider, Microsoft.Extensions.Logging.ILogger<DynamoDBGrainStorage> logger) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task Close(System.Threading.CancellationToken ct) { throw null; }\n\n        public System.Threading.Tasks.Task Init(System.Threading.CancellationToken ct) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class DynamoDBGrainStorageFactory\n    {\n        public static DynamoDBGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AWS/Orleans.Reminders.DynamoDB/Orleans.Reminders.DynamoDB.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class DynamoDBReminderStorageOptions : Reminders.DynamoDB.DynamoDBClientOptions\n    {\n        public bool CreateIfNotExists { get { throw null; } set { } }\n\n        public int ReadCapacityUnits { get { throw null; } set { } }\n\n        public string TableName { get { throw null; } set { } }\n\n        public bool UpdateIfExists { get { throw null; } set { } }\n\n        public bool UseProvisionedThroughput { get { throw null; } set { } }\n\n        public int WriteCapacityUnits { get { throw null; } set { } }\n    }\n\n    public static partial class DynamoDBReminderStorageOptionsExtensions\n    {\n        public static void ParseConnectionString(this DynamoDBReminderStorageOptions options, string connectionString) { }\n    }\n\n    public partial class DynamoDBReminderTableOptions\n    {\n        [RedactConnectionString]\n        public string ConnectionString { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class DynamoDBServiceCollectionReminderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseDynamoDBReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Configuration.DynamoDBReminderStorageOptions> configure) { throw null; }\n    }\n\n    public static partial class DynamoDBSiloBuilderReminderExtensions\n    {\n        public static ISiloBuilder UseDynamoDBReminderService(this ISiloBuilder builder, System.Action<Configuration.DynamoDBReminderStorageOptions> configure) { throw null; }\n    }\n}\n\nnamespace Orleans.Reminders.DynamoDB\n{\n    public partial class DynamoDBClientOptions\n    {\n        [Redact]\n        public string AccessKey { get { throw null; } set { } }\n\n        public string ProfileName { get { throw null; } set { } }\n\n        [Redact]\n        public string SecretKey { get { throw null; } set { } }\n\n        public string Service { get { throw null; } set { } }\n\n        public string Token { get { throw null; } set { } }\n    }\n}"
  },
  {
    "path": "src/api/AWS/Orleans.Streaming.SQS/Orleans.Streaming.SQS.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class SqsOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ClientBuilderExtensions\n    {\n        public static IClientBuilder AddSqsStreams(this IClientBuilder builder, string name, System.Action<Configuration.SqsOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder AddSqsStreams(this IClientBuilder builder, string name, System.Action<ClusterClientSqsStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class ClusterClientSqsStreamConfigurator : ClusterClientPersistentStreamConfigurator\n    {\n        public ClusterClientSqsStreamConfigurator(string name, IClientBuilder builder) : base(default!, default!, default!) { }\n\n        public ClusterClientSqsStreamConfigurator ConfigurePartitioning(int numOfparitions = 8) { throw null; }\n\n        public ClusterClientSqsStreamConfigurator ConfigureSqs(System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.SqsOptions>> configureOptions) { throw null; }\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder AddSqsStreams(this ISiloBuilder builder, string name, System.Action<Configuration.SqsOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddSqsStreams(this ISiloBuilder builder, string name, System.Action<SiloSqsStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class SiloSqsStreamConfigurator : SiloPersistentStreamConfigurator\n    {\n        public SiloSqsStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureServicesDelegate) : base(default!, default!, default!) { }\n\n        public SiloSqsStreamConfigurator ConfigureCache(int cacheSize = 4096) { throw null; }\n\n        public SiloSqsStreamConfigurator ConfigurePartitioning(int numOfparitions = 8) { throw null; }\n\n        public SiloSqsStreamConfigurator ConfigureSqs(System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.SqsOptions>> configureOptions) { throw null; }\n    }\n}\n\nnamespace OrleansAWSUtils.Streams\n{\n    public partial class SQSAdapterFactory : Orleans.Streams.IQueueAdapterFactory\n    {\n        public SQSAdapterFactory(string name, Orleans.Configuration.SqsOptions sqsOptions, Orleans.Configuration.HashRingStreamQueueMapperOptions queueMapperOptions, Orleans.Configuration.SimpleQueueCacheOptions cacheOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions, Orleans.Serialization.Serializer serializer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        protected System.Func<Orleans.Streams.QueueId, System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler>> StreamFailureHandlerFactory { set { } }\n\n        public static SQSAdapterFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public virtual System.Threading.Tasks.Task<Orleans.Streams.IQueueAdapter> CreateAdapter() { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler> GetDeliveryFailureHandler(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public virtual Orleans.Streams.IQueueAdapterCache GetQueueAdapterCache() { throw null; }\n\n        public Orleans.Streams.IStreamQueueMapper GetStreamQueueMapper() { throw null; }\n\n        public virtual void Init() { }\n    }\n\n    public partial class SQSStreamProviderUtils\n    {\n        public static System.Threading.Tasks.Task DeleteAllUsedQueues(string providerName, string clusterId, string storageConnectionString, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AdoNet/Orleans.Clustering.AdoNet/Orleans.Clustering.AdoNet.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AdoNetClusteringClientOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n\n        public string Invariant { get { throw null; } set { } }\n    }\n\n    public partial class AdoNetClusteringClientOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetClusteringClientOptionsValidator(Microsoft.Extensions.Options.IOptions<AdoNetClusteringClientOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class AdoNetClusteringSiloOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n\n        public string Invariant { get { throw null; } set { } }\n    }\n\n    public partial class AdoNetClusteringSiloOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetClusteringSiloOptionsValidator(Microsoft.Extensions.Options.IOptions<AdoNetClusteringSiloOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AdoNetHostingExtensions\n    {\n        public static IClientBuilder UseAdoNetClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetClusteringClientOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseAdoNetClustering(this IClientBuilder builder, System.Action<Configuration.AdoNetClusteringClientOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetClusteringSiloOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetClustering(this ISiloBuilder builder, System.Action<Configuration.AdoNetClusteringSiloOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Membership\n{\n    public partial class AdoNetGatewayListProvider : Orleans.Messaging.IGatewayListProvider\n    {\n        public AdoNetGatewayListProvider(Microsoft.Extensions.Logging.ILogger<AdoNetGatewayListProvider> logger, System.IServiceProvider serviceProvider, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.AdoNetClusteringClientOptions> options, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.GatewayOptions> gatewayOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions) { }\n\n        public bool IsUpdatable { get { throw null; } }\n\n        public System.TimeSpan MaxStaleness { get { throw null; } }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IList<System.Uri>> GetGateways() { throw null; }\n\n        public System.Threading.Tasks.Task InitializeGatewayListProvider() { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.MembershipService\n{\n    public partial class AdoNetClusteringTable : IMembershipTable\n    {\n        public AdoNetClusteringTable(System.IServiceProvider serviceProvider, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.AdoNetClusteringSiloOptions> clusteringOptions, Microsoft.Extensions.Logging.ILogger<AdoNetClusteringTable> logger) { }\n\n        public System.Threading.Tasks.Task CleanupDefunctSiloEntries(System.DateTimeOffset beforeDate) { throw null; }\n\n        public System.Threading.Tasks.Task DeleteMembershipTableEntries(string clusterId) { throw null; }\n\n        public System.Threading.Tasks.Task InitializeMembershipTable(bool tryInitTableVersion) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion) { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadAll() { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadRow(SiloAddress key) { throw null; }\n\n        public System.Threading.Tasks.Task UpdateIAmAlive(MembershipEntry entry) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AdoNet/Orleans.GrainDirectory.AdoNet/Orleans.GrainDirectory.AdoNet.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AdoNetGrainDirectoryOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetGrainDirectoryOptionsValidator(GrainDirectory.AdoNet.AdoNetGrainDirectoryOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.GrainDirectory.AdoNet\n{\n    public partial class AdoNetGrainDirectoryOptions\n    {\n        [Redact]\n        [System.ComponentModel.DataAnnotations.Required]\n        public string ConnectionString { get { throw null; } set { } }\n\n        [System.ComponentModel.DataAnnotations.Required]\n        public string Invariant { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AdoNetGrainDirectorySiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAdoNetGrainDirectory(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<GrainDirectory.AdoNet.AdoNetGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAdoNetGrainDirectory(this ISiloBuilder builder, string name, System.Action<GrainDirectory.AdoNet.AdoNetGrainDirectoryOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<GrainDirectory.AdoNet.AdoNetGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<GrainDirectory.AdoNet.AdoNetGrainDirectoryOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AdoNet/Orleans.Persistence.AdoNet/Orleans.Persistence.AdoNet.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AdoNetGrainStorageOptions : Storage.IStorageProviderSerializerOptions\n    {\n        public const string DEFAULT_ADONET_INVARIANT = \"System.Data.SqlClient\";\n        public const int DEFAULT_INIT_STAGE = 10000;\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n\n        public Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } }\n\n        public Storage.IStorageHasherPicker HashPicker { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public string Invariant { get { throw null; } set { } }\n\n        public void UseOrleans3CompatibleHasher() { }\n    }\n\n    public partial class AdoNetGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetGrainStorageOptionsValidator(AdoNetGrainStorageOptions configurationOptions, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class DefaultAdoNetGrainStorageOptionsHashPickerConfigurator : Microsoft.Extensions.Options.IPostConfigureOptions<AdoNetGrainStorageOptions>\n    {\n        public void PostConfigure(string name, AdoNetGrainStorageOptions options) { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AdoNetGrainStorageServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAdoNetGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Configuration.AdoNetGrainStorageOptions> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAdoNetGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetGrainStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAdoNetGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Configuration.AdoNetGrainStorageOptions> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAdoNetGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetGrainStorageOptions>> configureOptions = null) { throw null; }\n    }\n\n    public static partial class AdoNetGrainStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAdoNetGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetGrainStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAdoNetGrainStorage(this ISiloBuilder builder, string name, System.Action<Configuration.AdoNetGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAdoNetGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetGrainStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAdoNetGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.AdoNetGrainStorageOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Storage\n{\n    [System.Diagnostics.DebuggerDisplay(\"Name = {Name}, ConnectionString = {Storage.ConnectionString}\")]\n    public partial class AdoNetGrainStorage : IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public const string BinaryFormatSerializerTag = \"BinaryFormatSerializer\";\n        public const string DefaultInitializationQuery = \"SELECT QueryKey, QueryText FROM OrleansQuery WHERE QueryKey = 'WriteToStorageKey' OR QueryKey = 'ReadFromStorageKey' OR QueryKey = 'ClearStorageKey'\";\n        public const string JsonFormatSerializerTag = \"JsonFormatSerializer\";\n        public const string XmlFormatSerializerTag = \"XmlFormatSerializer\";\n        public AdoNetGrainStorage(Serialization.Serializers.IActivatorProvider activatorProvider, Microsoft.Extensions.Logging.ILogger<AdoNetGrainStorage> logger, Microsoft.Extensions.Options.IOptions<Configuration.AdoNetGrainStorageOptions> options, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, string name) { }\n\n        public RelationalStorageProviderQueries CurrentOperationalQueries { get { throw null; } set { } }\n\n        public IStorageHasherPicker HashPicker { get { throw null; } set { } }\n\n        public IGrainStorageSerializer Serializer { get { throw null; } set { } }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainReference, IGrainState<T> grainState) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainReference, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainReference, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class AdoNetGrainStorageFactory\n    {\n        public static AdoNetGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    public partial interface IHasher\n    {\n        string Description { get; }\n\n        int Hash(byte[] data);\n    }\n\n    public partial interface IStorageHasherPicker\n    {\n        System.Collections.Generic.ICollection<IHasher> HashProviders { get; }\n\n        IHasher PickHasher<T>(string serviceId, string storageProviderInstanceName, string grainType, Runtime.GrainId grainId, IGrainState<T> grainState, string tag = null);\n    }\n\n    public partial class Orleans3CompatibleStorageHashPicker : IStorageHasherPicker\n    {\n        public System.Collections.Generic.ICollection<IHasher> HashProviders { get { throw null; } }\n\n        public IHasher PickHasher<T>(string serviceId, string storageProviderInstanceName, string grainType, Runtime.GrainId grainId, IGrainState<T> grainState, string tag = null) { throw null; }\n    }\n\n    public sealed partial class OrleansDefaultHasher : IHasher\n    {\n        public string Description { get { throw null; } }\n\n        public int Hash(byte[] data) { throw null; }\n    }\n\n    public partial class RelationalStorageProviderQueries\n    {\n        public RelationalStorageProviderQueries(string writeToStorage, string readFromStorage, string clearState) { }\n\n        public string ClearState { get { throw null; } set { } }\n\n        public string ReadFromStorage { get { throw null; } set { } }\n\n        public string WriteToStorage { get { throw null; } }\n    }\n\n    public partial class StorageHasherPicker : IStorageHasherPicker\n    {\n        public StorageHasherPicker(System.Collections.Generic.IEnumerable<IHasher> hashProviders) { }\n\n        public System.Collections.Generic.ICollection<IHasher> HashProviders { get { throw null; } }\n\n        public IHasher PickHasher<T>(string serviceId, string storageProviderInstanceName, string grainType, Runtime.GrainId grainId, IGrainState<T> grainState, string tag = null) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AdoNet/Orleans.Reminders.AdoNet/Orleans.Reminders.AdoNet.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AdoNetReminderTableOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n\n        public string Invariant { get { throw null; } set { } }\n    }\n\n    public partial class AdoNetReminderTableOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetReminderTableOptionsValidator(Microsoft.Extensions.Options.IOptions<AdoNetReminderTableOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class SiloBuilderReminderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseAdoNetReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetReminderTableOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetReminderService(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetReminderTableOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAdoNetReminderService(this ISiloBuilder builder, System.Action<Configuration.AdoNetReminderTableOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/AdoNet/Orleans.Streaming.AdoNet/Orleans.Streaming.AdoNet.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AdoNetStreamOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n\n        public System.TimeSpan DeadLetterEvictionTimeout { get { throw null; } set { } }\n\n        public int EvictionBatchSize { get { throw null; } set { } }\n\n        public System.TimeSpan EvictionInterval { get { throw null; } set { } }\n\n        public System.TimeSpan ExpiryTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan InitializationTimeout { get { throw null; } set { } }\n\n        public string Invariant { get { throw null; } set { } }\n\n        public int MaxAttempts { get { throw null; } set { } }\n\n        public System.TimeSpan VisibilityTimeout { get { throw null; } set { } }\n    }\n\n    public partial class AdoNetStreamOptionsValidator : IConfigurationValidator\n    {\n        public AdoNetStreamOptionsValidator(AdoNetStreamOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public partial class ClusterClientAdoNetStreamConfigurator : ClusterClientPersistentStreamConfigurator\n    {\n        public ClusterClientAdoNetStreamConfigurator(string name, IClientBuilder clientBuilder) : base(default!, default!, default!) { }\n\n        public ClusterClientAdoNetStreamConfigurator ConfigureAdoNet(System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetStreamOptions>> configureOptions) { throw null; }\n\n        public ClusterClientAdoNetStreamConfigurator ConfigureCache(int cacheSize = 4096) { throw null; }\n\n        public ClusterClientAdoNetStreamConfigurator ConfigurePartitioning(int partitions = 8) { throw null; }\n    }\n\n    public static partial class ClusterClientAdoNetStreamExtensions\n    {\n        public static IClientBuilder AddAdoNetStreams(this IClientBuilder builder, string name, System.Action<Configuration.AdoNetStreamOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder AddAdoNetStreams(this IClientBuilder builder, string name, System.Action<ClusterClientAdoNetStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class SiloAdoNetStreamConfigurator : SiloPersistentStreamConfigurator\n    {\n        public SiloAdoNetStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureDelegate) : base(default!, default!, default!) { }\n\n        public SiloAdoNetStreamConfigurator ConfigureAdoNet(System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AdoNetStreamOptions>> configureOptions) { throw null; }\n\n        public SiloAdoNetStreamConfigurator ConfigureCache(int cacheSize = 4096) { throw null; }\n\n        public SiloAdoNetStreamConfigurator ConfigurePartitioning(int partitions = 8) { throw null; }\n    }\n\n    public static partial class SiloBuilderAdoNetStreamExtensions\n    {\n        public static ISiloBuilder AddAdoNetStreams(this ISiloBuilder builder, string name, System.Action<Configuration.AdoNetStreamOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAdoNetStreams(this ISiloBuilder builder, string name, System.Action<SiloAdoNetStreamConfigurator> configure) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Clustering.AzureStorage/Orleans.Clustering.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Clustering.AzureStorage\n{\n    public partial class AzureStorageClusteringOptions : AzureStorageOperationOptions\n    {\n        public const string DEFAULT_TABLE_NAME = \"OrleansSiloInstances\";\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureStorageClusteringOptionsValidator : AzureStorageOperationOptionsValidator<AzureStorageClusteringOptions>\n    {\n        public AzureStorageClusteringOptionsValidator(AzureStorageClusteringOptions options, string name) : base(default!, default!) { }\n    }\n\n    public partial class AzureStorageGatewayOptions : AzureStorageOperationOptions\n    {\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureStorageGatewayOptionsValidator : AzureStorageOperationOptionsValidator<AzureStorageGatewayOptions>\n    {\n        public AzureStorageGatewayOptionsValidator(AzureStorageGatewayOptions options, string name) : base(default!, default!) { }\n    }\n\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AzureTableClusteringExtensions\n    {\n        public static IClientBuilder UseAzureStorageClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.AzureStorage.AzureStorageGatewayOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseAzureStorageClustering(this IClientBuilder builder, System.Action<Clustering.AzureStorage.AzureStorageGatewayOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAzureStorageClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.AzureStorage.AzureStorageClusteringOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAzureStorageClustering(this ISiloBuilder builder, System.Action<Clustering.AzureStorage.AzureStorageClusteringOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Clustering.Cosmos/Orleans.Clustering.Cosmos.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Clustering.Cosmos\n{\n    public partial class CosmosClusteringOptions : CosmosOptions\n    {\n    }\n\n    public partial class CosmosClusteringOptionsValidator : CosmosOptionsValidator<CosmosClusteringOptions>\n    {\n        public CosmosClusteringOptionsValidator(CosmosClusteringOptions options, string name) : base(default!, default!) { }\n    }\n\n    public abstract partial class CosmosOptions\n    {\n        public bool CleanResourcesOnInitialization { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.CosmosClientOptions ClientOptions { get { throw null; } set { } }\n\n        public string ContainerName { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.ThroughputProperties? ContainerThroughputProperties { get { throw null; } set { } }\n\n        public string DatabaseName { get { throw null; } set { } }\n\n        public int? DatabaseThroughput { get { throw null; } set { } }\n\n        public bool IsResourceCreationEnabled { get { throw null; } set { } }\n\n        public ICosmosOperationExecutor OperationExecutor { get { throw null; } set { } }\n\n        public void ConfigureCosmosClient(System.Func<System.IServiceProvider, System.Threading.Tasks.ValueTask<Microsoft.Azure.Cosmos.CosmosClient>> createClient) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.AzureKeyCredential authKeyOrResourceTokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.Core.TokenCredential tokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, string authKeyOrResourceToken) { }\n\n        public void ConfigureCosmosClient(string connectionString) { }\n    }\n\n    public partial class CosmosOptionsValidator<TOptions> : IConfigurationValidator where TOptions : CosmosOptions\n    {\n        public CosmosOptionsValidator(TOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial interface ICosmosOperationExecutor\n    {\n        System.Threading.Tasks.Task<TResult> ExecuteOperation<TArg, TResult>(System.Func<TArg, System.Threading.Tasks.Task<TResult>> func, TArg arg);\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class HostingExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosClustering(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.Cosmos.CosmosClusteringOptions>> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosClustering(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Clustering.Cosmos.CosmosClusteringOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseCosmosClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.Cosmos.CosmosClusteringOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseCosmosClustering(this ISiloBuilder builder, System.Action<Clustering.Cosmos.CosmosClusteringOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseCosmosClustering(this ISiloBuilder builder) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosGatewayListProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.Cosmos.CosmosClusteringOptions>> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosGatewayListProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Clustering.Cosmos.CosmosClusteringOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseCosmosGatewayListProvider(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Clustering.Cosmos.CosmosClusteringOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseCosmosGatewayListProvider(this IClientBuilder builder, System.Action<Clustering.Cosmos.CosmosClusteringOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseCosmosGatewayListProvider(this IClientBuilder builder) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.GrainDirectory.AzureStorage/Orleans.GrainDirectory.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AzureTableGrainDirectoryOptions : GrainDirectory.AzureStorage.AzureStorageOperationOptions\n    {\n        public const string DEFAULT_TABLE_NAME = \"GrainDirectory\";\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableGrainDirectoryOptionsValidator : GrainDirectory.AzureStorage.AzureStorageOperationOptionsValidator<AzureTableGrainDirectoryOptions>\n    {\n        public AzureTableGrainDirectoryOptionsValidator(AzureTableGrainDirectoryOptions options, string name) : base(default!, default!) { }\n    }\n}\n\nnamespace Orleans.GrainDirectory.AzureStorage\n{\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableGrainDirectory : IGrainDirectory, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public AzureTableGrainDirectory(Configuration.AzureTableGrainDirectoryOptions directoryOptions, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task InitializeIfNeeded(System.Threading.CancellationToken ct = default) { throw null; }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Lookup(Runtime.GrainId grainId) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address, Runtime.GrainAddress? previousAddress) { throw null; }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address) { throw null; }\n\n        public System.Threading.Tasks.Task Unregister(Runtime.GrainAddress address) { throw null; }\n\n        public System.Threading.Tasks.Task UnregisterMany(System.Collections.Generic.List<Runtime.GrainAddress> addresses) { throw null; }\n\n        public System.Threading.Tasks.Task UnregisterSilos(System.Collections.Generic.List<Runtime.SiloAddress> siloAddresses) { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AzureTableGrainDirectoryServiceCollectionExtensions\n    {\n    }\n\n    public static partial class AzureTableGrainDirectorySiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAzureTableGrainDirectory(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAzureTableGrainDirectory(this ISiloBuilder builder, string name, System.Action<Configuration.AzureTableGrainDirectoryOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAzureTableGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAzureTableGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<Configuration.AzureTableGrainDirectoryOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Journaling.AzureStorage/Orleans.Journaling.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Journaling\n{\n    public sealed partial class AzureAppendBlobStateMachineStorageOptions\n    {\n        public const string DEFAULT_CONTAINER_NAME = \"state\";\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public Azure.Storage.Blobs.BlobServiceClient? BlobServiceClient { get { throw null; } set { } }\n\n        public System.Func<System.IServiceProvider, AzureAppendBlobStateMachineStorageOptions, IBlobContainerFactory> BuildContainerFactory { get { throw null; } set { } }\n\n        public Azure.Storage.Blobs.BlobClientOptions? ClientOptions { get { throw null; } set { } }\n\n        public string ContainerName { get { throw null; } set { } }\n\n        public System.Func<Runtime.GrainId, string> GetBlobName { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public void ConfigureBlobServiceClient(System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<Azure.Storage.Blobs.BlobServiceClient>> createClientCallback) { }\n\n        public void ConfigureBlobServiceClient(string connectionString) { }\n\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { }\n\n        public void ConfigureBlobServiceClient(System.Uri serviceUri) { }\n    }\n\n    public static partial class AzureBlobStorageHostingExtensions\n    {\n        public static Hosting.ISiloBuilder AddAzureAppendBlobStateMachineStorage(this Hosting.ISiloBuilder builder, System.Action<AzureAppendBlobStateMachineStorageOptions>? configure) { throw null; }\n\n        public static Hosting.ISiloBuilder AddAzureAppendBlobStateMachineStorage(this Hosting.ISiloBuilder builder) { throw null; }\n    }\n\n    public partial interface IBlobContainerFactory\n    {\n        Azure.Storage.Blobs.BlobContainerClient GetBlobContainerClient(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task InitializeAsync(Azure.Storage.Blobs.BlobServiceClient client, System.Threading.CancellationToken cancellationToken);\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Persistence.AzureStorage/Orleans.Persistence.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AzureBlobStorageOptions : Storage.IStorageProviderSerializerOptions\n    {\n        public const string DEFAULT_CONTAINER_NAME = \"grainstate\";\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public Azure.Storage.Blobs.BlobServiceClient BlobServiceClient { get { throw null; } set { } }\n\n        public System.Func<System.IServiceProvider, AzureBlobStorageOptions, Storage.IBlobContainerFactory> BuildContainerFactory { get { throw null; } set { } }\n\n        public Azure.Storage.Blobs.BlobClientOptions ClientOptions { get { throw null; } set { } }\n\n        public string ContainerName { get { throw null; } set { } }\n\n        public bool DeleteStateOnClear { get { throw null; } set { } }\n\n        public Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Storage.Blobs.BlobServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureBlobStorageOptionsValidator : IConfigurationValidator\n    {\n        public AzureBlobStorageOptionsValidator(AzureBlobStorageOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class AzureTableGrainStorageOptionsValidator : Persistence.AzureStorage.AzureStorageOperationOptionsValidator<AzureTableStorageOptions>\n    {\n        public AzureTableGrainStorageOptionsValidator(AzureTableStorageOptions options, string name) : base(default!, default!) { }\n    }\n\n    public partial class AzureTableStorageOptions : Persistence.AzureStorage.AzureStorageOperationOptions, Storage.IStorageProviderSerializerOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public const string DEFAULT_TABLE_NAME = \"OrleansGrainState\";\n        public bool DeleteStateOnClear { get { throw null; } set { } }\n\n        public Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public override string TableName { get { throw null; } set { } }\n\n        public bool UseStringFormat { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AzureBlobGrainStorageServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAzureBlobGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAzureBlobGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Configuration.AzureBlobStorageOptions> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAzureBlobGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddAzureBlobGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Configuration.AzureBlobStorageOptions> configureOptions) { throw null; }\n    }\n\n    public static partial class AzureBlobSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAzureBlobGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureBlobGrainStorage(this ISiloBuilder builder, string name, System.Action<Configuration.AzureBlobStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAzureBlobGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureBlobGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.AzureBlobStorageOptions> configureOptions) { throw null; }\n    }\n\n    public static partial class AzureTableSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAzureTableGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureTableGrainStorage(this ISiloBuilder builder, string name, System.Action<Configuration.AzureTableStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAzureTableGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureTableGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.AzureTableStorageOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Persistence.AzureStorage\n{\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Storage\n{\n    public partial class AzureBlobGrainStorage : IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public AzureBlobGrainStorage(string name, Configuration.AzureBlobStorageOptions options, IBlobContainerFactory blobContainerFactory, Serialization.Serializers.IActivatorProvider activatorProvider, Microsoft.Extensions.Logging.ILogger<AzureBlobGrainStorage> logger) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class AzureBlobGrainStorageFactory\n    {\n        public static AzureBlobGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    public partial class AzureTableGrainStorage : IGrainStorage, IRestExceptionDecoder, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public AzureTableGrainStorage(string name, Configuration.AzureTableStorageOptions options, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Logging.ILogger<AzureTableGrainStorage> logger, Serialization.Serializers.IActivatorProvider activatorProvider) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public bool DecodeException(System.Exception e, out System.Net.HttpStatusCode httpStatusCode, out string restStatus, bool getRESTErrors = false) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class AzureTableGrainStorageFactory\n    {\n        public static AzureTableGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    public partial interface IBlobContainerFactory\n    {\n        Azure.Storage.Blobs.BlobContainerClient GetBlobContainerClient(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task InitializeAsync(Azure.Storage.Blobs.BlobServiceClient client);\n    }\n\n    [GenerateSerializer]\n    public partial class TableStorageUpdateConditionNotSatisfiedException : InconsistentStateException\n    {\n        public TableStorageUpdateConditionNotSatisfiedException() { }\n\n        [System.Obsolete]\n        protected TableStorageUpdateConditionNotSatisfiedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public TableStorageUpdateConditionNotSatisfiedException(string msg, System.Exception exc) { }\n\n        public TableStorageUpdateConditionNotSatisfiedException(string grainType, string grainId, string tableName, string storedEtag, string currentEtag, System.Exception storageException) { }\n\n        public TableStorageUpdateConditionNotSatisfiedException(string errorMsg, string grainType, string grainId, string tableName, string storedEtag, string currentEtag, System.Exception storageException) { }\n\n        public TableStorageUpdateConditionNotSatisfiedException(string msg) { }\n\n        [Id(0)]\n        public string GrainId { get { throw null; } }\n\n        [Id(1)]\n        public string GrainType { get { throw null; } }\n\n        [Id(2)]\n        public string TableName { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Storage\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TableStorageUpdateConditionNotSatisfiedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_TableStorageUpdateConditionNotSatisfiedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException instance) { }\n\n        public global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TableStorageUpdateConditionNotSatisfiedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException, global::Orleans.Storage.InconsistentStateException>\n    {\n        public Copier_TableStorageUpdateConditionNotSatisfiedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException input, global::Orleans.Storage.TableStorageUpdateConditionNotSatisfiedException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Persistence.Cosmos/Orleans.Persistence.Cosmos.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class HostingExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddCosmosGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddCosmosGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage(this ISiloBuilder builder, string name, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions, System.Type customPartitionKeyProviderType) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage(this ISiloBuilder builder, string name, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage(this ISiloBuilder builder, string name, System.Type customPartitionKeyProviderType, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage<TPartitionKeyProvider>(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null)\n            where TPartitionKeyProvider : class, Persistence.Cosmos.IPartitionKeyProvider { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorage<TPartitionKeyProvider>(this ISiloBuilder builder, string name, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions)\n            where TPartitionKeyProvider : class, Persistence.Cosmos.IPartitionKeyProvider { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddCosmosGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddCosmosGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions, System.Type customPartitionKeyProviderType) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault(this ISiloBuilder builder, System.Type customPartitionKeyProviderType, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault<TPartitionKeyProvider>(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.Cosmos.CosmosGrainStorageOptions>>? configureOptions = null)\n            where TPartitionKeyProvider : class, Persistence.Cosmos.IPartitionKeyProvider { throw null; }\n\n        public static ISiloBuilder AddCosmosGrainStorageAsDefault<TPartitionKeyProvider>(this ISiloBuilder builder, System.Action<Persistence.Cosmos.CosmosGrainStorageOptions> configureOptions)\n            where TPartitionKeyProvider : class, Persistence.Cosmos.IPartitionKeyProvider { throw null; }\n    }\n}\n\nnamespace Orleans.Persistence.Cosmos\n{\n    [GenerateSerializer]\n    public partial class CosmosConditionNotSatisfiedException : Storage.InconsistentStateException\n    {\n        public CosmosConditionNotSatisfiedException() { }\n\n        [System.Obsolete]\n        protected CosmosConditionNotSatisfiedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public CosmosConditionNotSatisfiedException(string grainType, Runtime.GrainId grainId, string collection, string storedEtag, string currentEtag) { }\n\n        public CosmosConditionNotSatisfiedException(string msg, System.Exception exc) { }\n\n        public CosmosConditionNotSatisfiedException(string errorMsg, string grainType, Runtime.GrainId grainId, string collection, string storedEtag, string currentEtag) { }\n\n        public CosmosConditionNotSatisfiedException(string msg) { }\n\n        [Id(2)]\n        public string Collection { get { throw null; } }\n\n        [Id(0)]\n        public string GrainId { get { throw null; } }\n\n        [Id(1)]\n        public string GrainType { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    public sealed partial class CosmosGrainStorage : Storage.IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public CosmosGrainStorage(string name, CosmosGrainStorageOptions options, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.IServiceProvider serviceProvider, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, IPartitionKeyProvider partitionKeyProvider, Serialization.Serializers.IActivatorProvider activatorProvider) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public partial class CosmosGrainStorageOptions : CosmosOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public bool DeleteStateOnClear { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public string PartitionKeyPath { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<string> StateFieldsToIndex { get { throw null; } set { } }\n    }\n\n    public abstract partial class CosmosOptions\n    {\n        public bool CleanResourcesOnInitialization { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.CosmosClientOptions ClientOptions { get { throw null; } set { } }\n\n        public string ContainerName { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.ThroughputProperties? ContainerThroughputProperties { get { throw null; } set { } }\n\n        public string DatabaseName { get { throw null; } set { } }\n\n        public int? DatabaseThroughput { get { throw null; } set { } }\n\n        public bool IsResourceCreationEnabled { get { throw null; } set { } }\n\n        public ICosmosOperationExecutor OperationExecutor { get { throw null; } set { } }\n\n        public void ConfigureCosmosClient(System.Func<System.IServiceProvider, System.Threading.Tasks.ValueTask<Microsoft.Azure.Cosmos.CosmosClient>> createClient) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.AzureKeyCredential authKeyOrResourceTokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.Core.TokenCredential tokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, string authKeyOrResourceToken) { }\n\n        public void ConfigureCosmosClient(string connectionString) { }\n    }\n\n    public partial class CosmosOptionsValidator<TOptions> : IConfigurationValidator where TOptions : CosmosOptions\n    {\n        public CosmosOptionsValidator(TOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public static partial class CosmosStorageFactory\n    {\n        public static CosmosGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    public partial interface ICosmosOperationExecutor\n    {\n        System.Threading.Tasks.Task<TResult> ExecuteOperation<TArg, TResult>(System.Func<TArg, System.Threading.Tasks.Task<TResult>> func, TArg arg);\n    }\n\n    public partial interface IPartitionKeyProvider\n    {\n        System.Threading.Tasks.ValueTask<string> GetPartitionKey(string grainType, Runtime.GrainId grainId);\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Persistence.Cosmos\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CosmosConditionNotSatisfiedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_CosmosConditionNotSatisfiedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException instance) { }\n\n        public global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_CosmosConditionNotSatisfiedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException, global::Orleans.Storage.InconsistentStateException>\n    {\n        public Copier_CosmosConditionNotSatisfiedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException input, global::Orleans.Persistence.Cosmos.CosmosConditionNotSatisfiedException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Reminders.AzureStorage/Orleans.Reminders.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class AzureStorageReminderServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseAzureTableReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Reminders.AzureStorage.AzureTableReminderStorageOptions>> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseAzureTableReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Reminders.AzureStorage.AzureTableReminderStorageOptions> configure) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseAzureTableReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string connectionString) { throw null; }\n    }\n\n    public static partial class AzureStorageReminderSiloBuilderExtensions\n    {\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Reminders.AzureStorage.AzureTableReminderStorageOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, System.Action<Reminders.AzureStorage.AzureTableReminderStorageOptions> configure) { throw null; }\n\n        public static ISiloBuilder UseAzureTableReminderService(this ISiloBuilder builder, string connectionString) { throw null; }\n    }\n}\n\nnamespace Orleans.Reminders.AzureStorage\n{\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableReminderStorageOptions : AzureStorageOperationOptions\n    {\n        public const string DEFAULT_TABLE_NAME = \"OrleansReminders\";\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableReminderStorageOptionsValidator : AzureStorageOperationOptionsValidator<AzureTableReminderStorageOptions>\n    {\n        public AzureTableReminderStorageOptionsValidator(AzureTableReminderStorageOptions options, string name) : base(default!, default!) { }\n    }\n}\n\nnamespace Orleans.Runtime.ReminderService\n{\n    public sealed partial class AzureBasedReminderTable : IReminderTable\n    {\n        public AzureBasedReminderTable(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Options.IOptions<Reminders.AzureStorage.AzureTableReminderStorageOptions> storageOptions) { }\n\n        public System.Threading.Tasks.Task<ReminderEntry> ReadRow(GrainId grainId, string reminderName) { throw null; }\n\n        public System.Threading.Tasks.Task<ReminderTableData> ReadRows(GrainId grainId) { throw null; }\n\n        public System.Threading.Tasks.Task<ReminderTableData> ReadRows(uint begin, uint end) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> RemoveRow(GrainId grainId, string reminderName, string eTag) { throw null; }\n\n        public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task TestOnlyClearTable() { throw null; }\n\n        public System.Threading.Tasks.Task<string> UpsertRow(ReminderEntry entry) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Reminders.Cosmos/Orleans.Reminders.Cosmos.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class HostingExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Reminders.Cosmos.CosmosReminderTableOptions>> configure) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseCosmosReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Reminders.Cosmos.CosmosReminderTableOptions> configure) { throw null; }\n\n        public static ISiloBuilder UseCosmosReminderService(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Reminders.Cosmos.CosmosReminderTableOptions>> configure) { throw null; }\n\n        public static ISiloBuilder UseCosmosReminderService(this ISiloBuilder builder, System.Action<Reminders.Cosmos.CosmosReminderTableOptions> configure) { throw null; }\n    }\n}\n\nnamespace Orleans.Reminders.Cosmos\n{\n    public abstract partial class CosmosOptions\n    {\n        public bool CleanResourcesOnInitialization { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.CosmosClientOptions ClientOptions { get { throw null; } set { } }\n\n        public string ContainerName { get { throw null; } set { } }\n\n        public Microsoft.Azure.Cosmos.ThroughputProperties? ContainerThroughputProperties { get { throw null; } set { } }\n\n        public string DatabaseName { get { throw null; } set { } }\n\n        public int? DatabaseThroughput { get { throw null; } set { } }\n\n        public bool IsResourceCreationEnabled { get { throw null; } set { } }\n\n        public ICosmosOperationExecutor OperationExecutor { get { throw null; } set { } }\n\n        public void ConfigureCosmosClient(System.Func<System.IServiceProvider, System.Threading.Tasks.ValueTask<Microsoft.Azure.Cosmos.CosmosClient>> createClient) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.AzureKeyCredential authKeyOrResourceTokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, Azure.Core.TokenCredential tokenCredential) { }\n\n        public void ConfigureCosmosClient(string accountEndpoint, string authKeyOrResourceToken) { }\n\n        public void ConfigureCosmosClient(string connectionString) { }\n    }\n\n    public partial class CosmosOptionsValidator<TOptions> : IConfigurationValidator where TOptions : CosmosOptions\n    {\n        public CosmosOptionsValidator(TOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class CosmosReminderTableOptions : CosmosOptions\n    {\n    }\n\n    public partial interface ICosmosOperationExecutor\n    {\n        System.Threading.Tasks.Task<TResult> ExecuteOperation<TArg, TResult>(System.Func<TArg, System.Threading.Tasks.Task<TResult>> func, TArg arg);\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Streaming.AzureStorage/Orleans.Streaming.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.AzureUtils\n{\n    public partial class AzureQueueDataManager\n    {\n        public AzureQueueDataManager(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, string queueName, Configuration.AzureQueueOptions options) { }\n\n        public AzureQueueDataManager(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, string queueName, string storageConnectionString, System.TimeSpan? visibilityTimeout = null) { }\n\n        public string QueueName { get { throw null; } }\n\n        public System.Threading.Tasks.Task AddQueueMessage(string message) { throw null; }\n\n        public System.Threading.Tasks.Task ClearQueue() { throw null; }\n\n        public System.Threading.Tasks.Task DeleteQueue() { throw null; }\n\n        public System.Threading.Tasks.Task DeleteQueueMessage(Azure.Storage.Queues.Models.QueueMessage message) { throw null; }\n\n        public System.Threading.Tasks.Task<int> GetApproximateMessageCount() { throw null; }\n\n        public System.Threading.Tasks.Task<Azure.Storage.Queues.Models.QueueMessage> GetQueueMessage() { throw null; }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Azure.Storage.Queues.Models.QueueMessage>> GetQueueMessages(int? count = null) { throw null; }\n\n        public System.Threading.Tasks.Task InitQueueAsync() { throw null; }\n\n        public System.Threading.Tasks.Task<Azure.Storage.Queues.Models.PeekedMessage> PeekQueueMessage() { throw null; }\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class AzureBlobLeaseProviderOptions\n    {\n        public const string DefaultBlobContainerName = \"Leases\";\n        public string BlobContainerName { get { throw null; } set { } }\n\n        public Azure.Storage.Blobs.BlobServiceClient BlobServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public Azure.Storage.Blobs.BlobClientOptions ClientOptions { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Storage.Blobs.BlobServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the BlobServiceClient property directly.\")]\n        public void ConfigureBlobServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureBlobLeaseProviderOptionsValidator : IConfigurationValidator\n    {\n        public AzureBlobLeaseProviderOptionsValidator(Microsoft.Extensions.Options.IOptions<AzureBlobLeaseProviderOptions> options) { }\n\n        public static IConfigurationValidator Create(System.IServiceProvider services, string name) { throw null; }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class AzureQueueOptions\n    {\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public Azure.Storage.Queues.QueueClientOptions ClientOptions { get { throw null; } set { } }\n\n        public System.TimeSpan? MessageVisibilityTimeout { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<string> QueueNames { get { throw null; } set { } }\n\n        public Azure.Storage.Queues.QueueServiceClient QueueServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Storage.Queues.QueueServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the QueueServiceClient property directly.\")]\n        public void ConfigureQueueServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureQueueOptionsValidator : IConfigurationValidator\n    {\n        internal AzureQueueOptionsValidator() { }\n\n        public static IConfigurationValidator Create(System.IServiceProvider services, string name) { throw null; }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AzureQueueStreamConfiguratorExtensions\n    {\n        public static void ConfigureAzureQueue(this IAzureQueueStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureQueueOptions>> configureOptions) { }\n\n        public static void ConfigureQueueDataAdapter(this IAzureQueueStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streams.IQueueDataAdapter<string, Streams.IBatchContainer>> factory) { }\n\n        public static void ConfigureQueueDataAdapter<TQueueDataAdapter>(this IAzureQueueStreamConfigurator configurator)\n            where TQueueDataAdapter : Streams.IQueueDataAdapter<string, Streams.IBatchContainer> { }\n    }\n\n    public sealed partial class AzureQueueStreamProviderBuilder : Providers.IProviderBuilder<ISiloBuilder>, Providers.IProviderBuilder<IClientBuilder>\n    {\n        public void Configure(IClientBuilder builder, string name, Microsoft.Extensions.Configuration.IConfigurationSection configurationSection) { }\n\n        public void Configure(ISiloBuilder builder, string name, Microsoft.Extensions.Configuration.IConfigurationSection configurationSection) { }\n    }\n\n    public static partial class ClientBuilderExtensions\n    {\n        public static IClientBuilder AddAzureQueueStreams(this IClientBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureQueueOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder AddAzureQueueStreams(this IClientBuilder builder, string name, System.Action<ClusterClientAzureQueueStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class ClusterClientAzureQueueStreamConfigurator : ClusterClientPersistentStreamConfigurator, IClusterClientAzureQueueStreamConfigurator, IAzureQueueStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n        public ClusterClientAzureQueueStreamConfigurator(string name, IClientBuilder builder) : base(default!, default!, default!) { }\n    }\n\n    public partial interface IAzureQueueStreamConfigurator : INamedServiceConfigurator\n    {\n    }\n\n    public partial interface IClusterClientAzureQueueStreamConfigurator : IAzureQueueStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public partial interface ISiloAzureQueueStreamConfigurator : IAzureQueueStreamConfigurator, INamedServiceConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public partial class SiloAzureQueueStreamConfigurator : SiloPersistentStreamConfigurator, ISiloAzureQueueStreamConfigurator, IAzureQueueStreamConfigurator, INamedServiceConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n        public SiloAzureQueueStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureServicesDelegate) : base(default!, default!, default!) { }\n    }\n\n    public static partial class SiloAzureQueueStreamConfiguratorExtensions\n    {\n        public static void ConfigureCacheSize(this ISiloAzureQueueStreamConfigurator configurator, int cacheSize = 4096) { }\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAzureQueueStreams(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureQueueOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAzureQueueStreams(this ISiloBuilder builder, string name, System.Action<SiloAzureQueueStreamConfigurator> configure) { throw null; }\n\n        public static ISiloBuilder UseAzureBlobLeaseProvider(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobLeaseProviderOptions>> configureOptions) { throw null; }\n\n        public static void UseAzureBlobLeaseProvider(this ISiloPersistentStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureBlobLeaseProviderOptions>> configureOptions) { }\n    }\n}\n\nnamespace Orleans.LeaseProviders\n{\n    public partial class AzureBlobLeaseProvider : ILeaseProvider\n    {\n        public AzureBlobLeaseProvider(Microsoft.Extensions.Options.IOptions<Configuration.AzureBlobLeaseProviderOptions> options) { }\n\n        public System.Threading.Tasks.Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests) { throw null; }\n\n        public static ILeaseProvider Create(System.IServiceProvider services, string name) { throw null; }\n\n        public System.Threading.Tasks.Task Release(string category, AcquiredLease[] acquiredLeases) { throw null; }\n\n        public System.Threading.Tasks.Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] acquiredLeases) { throw null; }\n    }\n}\n\nnamespace Orleans.Providers.Streams.AzureQueue\n{\n    public partial class AzureQueueAdapterFactory : Orleans.Streams.IQueueAdapterFactory\n    {\n        public AzureQueueAdapterFactory(string name, Configuration.AzureQueueOptions options, Configuration.SimpleQueueCacheOptions cacheOptions, Orleans.Streams.IQueueDataAdapter<string, Orleans.Streams.IBatchContainer> dataAdapter, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        protected System.Func<Orleans.Streams.QueueId, System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler>> StreamFailureHandlerFactory { set { } }\n\n        public static AzureQueueAdapterFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public virtual System.Threading.Tasks.Task<Orleans.Streams.IQueueAdapter> CreateAdapter() { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler> GetDeliveryFailureHandler(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public virtual Orleans.Streams.IQueueAdapterCache GetQueueAdapterCache() { throw null; }\n\n        public Orleans.Streams.IStreamQueueMapper GetStreamQueueMapper() { throw null; }\n\n        public virtual void Init() { }\n    }\n\n    [SerializationCallbacks(typeof(Runtime.OnDeserializedCallbacks))]\n    public partial class AzureQueueDataAdapterV1 : Orleans.Streams.IQueueDataAdapter<string, Orleans.Streams.IBatchContainer>, Orleans.Streams.IQueueDataAdapter<string>, Serialization.IOnDeserialized\n    {\n        public AzureQueueDataAdapterV1(Serialization.Serializer serializer) { }\n\n        public Orleans.Streams.IBatchContainer FromQueueMessage(string cloudMsg, long sequenceId) { throw null; }\n\n        void Serialization.IOnDeserialized.OnDeserialized(Serialization.DeserializationContext context) { }\n\n        public string ToQueueMessage<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Orleans.Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    [SerializationCallbacks(typeof(Runtime.OnDeserializedCallbacks))]\n    public partial class AzureQueueDataAdapterV2 : Orleans.Streams.IQueueDataAdapter<string, Orleans.Streams.IBatchContainer>, Orleans.Streams.IQueueDataAdapter<string>, Serialization.IOnDeserialized\n    {\n        public AzureQueueDataAdapterV2(Serialization.Serializer serializer) { }\n\n        public Orleans.Streams.IBatchContainer FromQueueMessage(string cloudMsg, long sequenceId) { throw null; }\n\n        void Serialization.IOnDeserialized.OnDeserialized(Serialization.DeserializationContext context) { }\n\n        public string ToQueueMessage<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Orleans.Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    public partial class AzureQueueStreamProviderUtils\n    {\n        public static System.Threading.Tasks.Task ClearAllUsedAzureQueues(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Collections.Generic.List<string> azureQueueNames, Configuration.AzureQueueOptions queueOptions) { throw null; }\n\n        public static System.Threading.Tasks.Task ClearAllUsedAzureQueues(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Collections.Generic.List<string> azureQueueNames, string storageConnectionString) { throw null; }\n\n        public static System.Threading.Tasks.Task DeleteAllUsedAzureQueues(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Collections.Generic.List<string> azureQueueNames, Configuration.AzureQueueOptions queueOptions) { throw null; }\n\n        public static System.Threading.Tasks.Task DeleteAllUsedAzureQueues(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Collections.Generic.List<string> azureQueueNames, string storageConnectionString) { throw null; }\n\n        public static System.Collections.Generic.List<string> GenerateDefaultAzureQueueNames(string serviceId, string providerName) { throw null; }\n    }\n}\n\nnamespace Orleans.Providers.Streams.PersistentStreams\n{\n    public partial class AzureTableStorageStreamFailureHandler<TEntity> : Orleans.Streams.IStreamFailureHandler where TEntity : StreamDeliveryFailureEntity, new()\n    {\n        public AzureTableStorageStreamFailureHandler(Serialization.Serializer<Orleans.Streams.StreamSequenceToken> serializer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, bool faultOnFailure, string clusterId, Streaming.AzureStorage.AzureStorageOperationOptions azureStorageOptions, System.Func<TEntity> createEntity = null) { }\n\n        public bool ShouldFaultSubsriptionOnError { get { throw null; } }\n\n        public System.Threading.Tasks.Task InitAsync() { throw null; }\n\n        public System.Threading.Tasks.Task OnDeliveryFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken sequenceToken) { throw null; }\n\n        public System.Threading.Tasks.Task OnSubscriptionFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken sequenceToken) { throw null; }\n    }\n\n    public partial class StreamDeliveryFailureEntity : Azure.Data.Tables.ITableEntity\n    {\n        public Azure.ETag ETag { get { throw null; } set { } }\n\n        public string PartitionKey { get { throw null; } set { } }\n\n        public string RowKey { get { throw null; } set { } }\n\n        public byte[] SequenceToken { get { throw null; } set { } }\n\n        public string StreamGuid { get { throw null; } set { } }\n\n        public string StreamNamespace { get { throw null; } set { } }\n\n        public string StreamProviderName { get { throw null; } set { } }\n\n        public System.Guid SubscriptionId { get { throw null; } set { } }\n\n        public System.DateTimeOffset? Timestamp { get { throw null; } set { } }\n\n        public virtual Orleans.Streams.StreamSequenceToken GetSequenceToken(Serialization.Serializer<Orleans.Streams.StreamSequenceToken> serializer) { throw null; }\n\n        public static string MakeDefaultPartitionKey(string streamProviderName, string deploymentId) { throw null; }\n\n        protected static long ReverseOrderTimestampTicks() { throw null; }\n\n        public virtual void SetPartitionKey(string deploymentId) { }\n\n        public virtual void SetRowkey() { }\n\n        public virtual void SetSequenceToken(Serialization.Serializer<Orleans.Streams.StreamSequenceToken> serializer, Orleans.Streams.StreamSequenceToken token) { }\n    }\n}\n\nnamespace Orleans.Streaming.AzureStorage\n{\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Streaming.EventHubs/Orleans.Streaming.EventHubs.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AzureTableStreamCheckpointerOptions : Streaming.EventHubs.AzureStorageOperationOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_CHECKPOINT_PERSIST_INTERVAL;\n        public const string DEFAULT_TABLE_NAME = \"Checkpoint\";\n        public System.TimeSpan PersistInterval { get { throw null; } set { } }\n\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableStreamCheckpointerOptionsValidator : Streaming.EventHubs.AzureStorageOperationOptionsValidator<AzureTableStreamCheckpointerOptions>\n    {\n        public AzureTableStreamCheckpointerOptionsValidator(AzureTableStreamCheckpointerOptions options, string name) : base(default!, default!) { }\n    }\n\n    public partial class EventDataGeneratorStreamOptions\n    {\n        public const int DefaultEventHubPartitionCount = 4;\n        public int EventHubPartitionCount;\n    }\n\n    public partial class EventHubOptions\n    {\n        public Azure.Messaging.EventHubs.EventHubConnectionOptions ConnectionOptions { get { throw null; } set { } }\n\n        public void ConfigureEventHubConnection(Azure.Messaging.EventHubs.EventHubConnection connection, string consumerGroup) { }\n\n        public void ConfigureEventHubConnection(CreateConnectionDelegate createConnection, string eventHubName, string consumerGroup) { }\n\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, Azure.AzureNamedKeyCredential credential) { }\n\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, Azure.AzureSasCredential credential) { }\n\n        public void ConfigureEventHubConnection(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, Azure.Core.TokenCredential credential) { }\n\n        public void ConfigureEventHubConnection(string connectionString, string eventHubName, string consumerGroup) { }\n\n        public delegate Azure.Messaging.EventHubs.EventHubConnection CreateConnectionDelegate(Azure.Messaging.EventHubs.EventHubConnectionOptions connectionOptions);\n    }\n\n    public partial class EventHubOptionsValidator : IConfigurationValidator\n    {\n        public EventHubOptionsValidator(EventHubOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class EventHubReceiverOptions\n    {\n        public int? PrefetchCount { get { throw null; } set { } }\n\n        public bool StartFromNow { get { throw null; } set { } }\n    }\n\n    public partial class EventHubStreamCachePressureOptions\n    {\n        public double? AveragingCachePressureMonitorFlowControlThreshold { get { throw null; } set { } }\n\n        public double? SlowConsumingMonitorFlowControlThreshold { get { throw null; } set { } }\n\n        public System.TimeSpan? SlowConsumingMonitorPressureWindowSize { get { throw null; } set { } }\n    }\n\n    public partial class StreamCheckpointerConfigurationValidator : IConfigurationValidator\n    {\n        public StreamCheckpointerConfigurationValidator(System.IServiceProvider services, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ClientBuilderExtensions\n    {\n        public static IClientBuilder AddEventHubStreams(this IClientBuilder builder, string name, System.Action<Configuration.EventHubOptions> configureEventHub) { throw null; }\n\n        public static IClientBuilder AddEventHubStreams(this IClientBuilder builder, string name, System.Action<IClusterClientEventHubStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class ClusterClientEventHubStreamConfigurator : ClusterClientPersistentStreamConfigurator, IClusterClientEventHubStreamConfigurator, IEventHubStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n        public ClusterClientEventHubStreamConfigurator(string name, IClientBuilder builder) : base(default!, default!, default!) { }\n    }\n\n    public static partial class EventHubStreamConfiguratorExtensions\n    {\n        public static void ConfigureEventHub(this IEventHubStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.EventHubOptions>> configureOptions) { }\n\n        public static void UseDataAdapter(this IEventHubStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streaming.EventHubs.IEventHubDataAdapter> factory) { }\n    }\n\n    public partial interface IClusterClientEventHubStreamConfigurator : IEventHubStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public partial interface IEventHubStreamConfigurator : INamedServiceConfigurator\n    {\n    }\n\n    public partial interface ISiloEventHubStreamConfigurator : IEventHubStreamConfigurator, INamedServiceConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder AddEventHubStreams(this ISiloBuilder builder, string name, System.Action<Configuration.EventHubOptions> configureEventHub, System.Action<Configuration.AzureTableStreamCheckpointerOptions> configureDefaultCheckpointer) { throw null; }\n\n        public static ISiloBuilder AddEventHubStreams(this ISiloBuilder builder, string name, System.Action<ISiloEventHubStreamConfigurator> configure) { throw null; }\n    }\n\n    public partial class SiloEventHubStreamConfigurator : SiloRecoverableStreamConfigurator, ISiloEventHubStreamConfigurator, IEventHubStreamConfigurator, INamedServiceConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n        public SiloEventHubStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureServicesDelegate) : base(default!, default!, default!) { }\n    }\n\n    public static partial class SiloEventHubStreamConfiguratorExtensions\n    {\n        public static void ConfigureCachePressuring(this ISiloEventHubStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.EventHubStreamCachePressureOptions>> configureOptions) { }\n\n        public static void ConfigureCheckpointer<TOptions>(this ISiloEventHubStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streams.IStreamQueueCheckpointerFactory> checkpointerFactoryBuilder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new() { }\n\n        public static void ConfigurePartitionReceiver(this ISiloEventHubStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.EventHubReceiverOptions>> configureOptions) { }\n\n        public static void UseAzureTableCheckpointer(this ISiloEventHubStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableStreamCheckpointerOptions>> configureOptions) { }\n    }\n}\n\nnamespace Orleans.Hosting.Developer\n{\n    public static partial class EventDataGeneratorConfiguratorExtensions\n    {\n        public static void ConfigureCachePressuring(this IEventDataGeneratorStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.EventHubStreamCachePressureOptions>> configureOptions) { }\n\n        public static void UseDataAdapter(this IEventDataGeneratorStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streaming.EventHubs.IEventHubDataAdapter> factory) { }\n    }\n\n    public partial class EventDataGeneratorStreamConfigurator : SiloRecoverableStreamConfigurator, IEventDataGeneratorStreamConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n        public EventDataGeneratorStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureServicesDelegate) : base(default!, default!, default!) { }\n    }\n\n    public partial interface IEventDataGeneratorStreamConfigurator : ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder AddEventDataGeneratorStreams(this ISiloBuilder builder, string name, System.Action<IEventDataGeneratorStreamConfigurator> configure) { throw null; }\n    }\n}\n\nnamespace Orleans.Streaming.EventHubs\n{\n    public partial class AggregatedCachePressureMonitor : System.Collections.Generic.List<ICachePressureMonitor>, ICachePressureMonitor\n    {\n        public AggregatedCachePressureMonitor(Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public Providers.Streams.Common.ICacheMonitor CacheMonitor { set { } }\n\n        public void AddCachePressureMonitor(ICachePressureMonitor monitor) { }\n\n        public bool IsUnderPressure(System.DateTime utcNow) { throw null; }\n\n        public void RecordCachePressureContribution(double cachePressureContribution) { }\n    }\n\n    public partial class AveragingCachePressureMonitor : ICachePressureMonitor\n    {\n        public AveragingCachePressureMonitor(Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public AveragingCachePressureMonitor(double flowControlThreshold, Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public Providers.Streams.Common.ICacheMonitor CacheMonitor { set { } }\n\n        public bool IsUnderPressure(System.DateTime utcNow) { throw null; }\n\n        public void RecordCachePressureContribution(double cachePressureContribution) { }\n    }\n\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n\n    public partial class DefaultEventHubReceiverMonitor : Providers.Streams.Common.DefaultQueueAdapterReceiverMonitor\n    {\n        public DefaultEventHubReceiverMonitor(EventHubReceiverMonitorDimensions dimensions) : base(default(System.Collections.Generic.KeyValuePair<string, object>[])!) { }\n    }\n\n    public static partial class EventDataExtensions\n    {\n        public static System.Collections.Generic.IDictionary<string, object> DeserializeProperties(this System.ArraySegment<byte> bytes, Serialization.Serializer serializer) { throw null; }\n\n        public static string GetStreamNamespaceProperty(this Azure.Messaging.EventHubs.EventData eventData) { throw null; }\n\n        public static byte[] SerializeProperties(this Azure.Messaging.EventHubs.EventData eventData, Serialization.Serializer serializer) { throw null; }\n\n        public static void SetStreamNamespaceProperty(this Azure.Messaging.EventHubs.EventData eventData, string streamNamespace) { }\n    }\n\n    public partial class EventHubAdapterFactory : Streams.IQueueAdapterFactory, Streams.IQueueAdapter, Streams.IQueueAdapterCache\n    {\n        protected readonly IEventHubDataAdapter dataAdapter;\n        protected System.Func<EventHubPartitionSettings, string, Microsoft.Extensions.Logging.ILogger, IEventHubReceiver> EventHubReceiverFactory;\n        protected Microsoft.Extensions.Logging.ILogger logger;\n        protected readonly System.IServiceProvider serviceProvider;\n        public EventHubAdapterFactory(string name, Configuration.EventHubOptions ehOptions, Configuration.EventHubReceiverOptions receiverOptions, Configuration.EventHubStreamCachePressureOptions cacheOptions, Configuration.StreamCacheEvictionOptions cacheEvictionOptions, Configuration.StreamStatisticOptions statisticOptions, IEventHubDataAdapter dataAdapter, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Statistics.IEnvironmentStatisticsProvider environmentStatisticsProvider) { }\n\n        protected System.Func<string, Streams.IStreamQueueCheckpointer<string>, Microsoft.Extensions.Logging.ILoggerFactory, IEventHubQueueCache> CacheFactory { get { throw null; } set { } }\n\n        public Streams.StreamProviderDirection Direction { get { throw null; } protected set { } }\n\n        public bool IsRewindable { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        protected System.Func<string[], Streams.HashRingBasedPartitionedStreamQueueMapper> QueueMapperFactory { get { throw null; } set { } }\n\n        protected System.Func<EventHubReceiverMonitorDimensions, Microsoft.Extensions.Logging.ILoggerFactory, Providers.Streams.Common.IQueueAdapterReceiverMonitor> ReceiverMonitorFactory { get { throw null; } set { } }\n\n        protected System.Func<string, System.Threading.Tasks.Task<Streams.IStreamFailureHandler>> StreamFailureHandlerFactory { get { throw null; } set { } }\n\n        public static EventHubAdapterFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public System.Threading.Tasks.Task<Streams.IQueueAdapter> CreateAdapter() { throw null; }\n\n        protected virtual IEventHubQueueCacheFactory CreateCacheFactory(Configuration.EventHubStreamCachePressureOptions eventHubCacheOptions) { throw null; }\n\n        public Streams.IQueueCache CreateQueueCache(Streams.QueueId queueId) { throw null; }\n\n        public Streams.IQueueAdapterReceiver CreateReceiver(Streams.QueueId queueId) { throw null; }\n\n        public System.Threading.Tasks.Task<Streams.IStreamFailureHandler> GetDeliveryFailureHandler(Streams.QueueId queueId) { throw null; }\n\n        protected virtual System.Threading.Tasks.Task<string[]> GetPartitionIdsAsync() { throw null; }\n\n        public Streams.IQueueAdapterCache GetQueueAdapterCache() { throw null; }\n\n        public Streams.IStreamQueueMapper GetStreamQueueMapper() { throw null; }\n\n        public virtual void Init() { }\n\n        protected virtual void InitEventHubClient() { }\n\n        public virtual System.Threading.Tasks.Task QueueMessageBatchAsync<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class EventHubBatchContainer : Streams.IBatchContainer\n    {\n        public EventHubBatchContainer(EventHubMessage eventHubMessage, Serialization.Serializer serializer) { }\n\n        public Streams.StreamSequenceToken SequenceToken { get { throw null; } }\n\n        public Runtime.StreamId StreamId { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<System.Tuple<T, Streams.StreamSequenceToken>> GetEvents<T>() { throw null; }\n\n        public bool ImportRequestContext() { throw null; }\n\n        public static Azure.Messaging.EventHubs.EventData ToEventData<T>(Serialization.Serializer bodySerializer, Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n\n        public static void UpdateEventData<T>(Azure.Messaging.EventHubs.EventData eventData, Serialization.Serializer bodySerializer, Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, System.Collections.Generic.Dictionary<string, object> requestContext) { }\n    }\n\n    public partial class EventHubBlockPoolMonitorDimensions : EventHubMonitorAggregationDimensions\n    {\n        public EventHubBlockPoolMonitorDimensions() { }\n\n        public EventHubBlockPoolMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string blockPoolId) { }\n\n        public string BlockPoolId { get { throw null; } set { } }\n    }\n\n    public partial class EventHubCacheMonitorDimensions : EventHubReceiverMonitorDimensions\n    {\n        public EventHubCacheMonitorDimensions() { }\n\n        public EventHubCacheMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string ehPartition, string blockPoolId) { }\n\n        public string BlockPoolId { get { throw null; } set { } }\n    }\n\n    public partial class EventHubCheckpointer : Streams.IStreamQueueCheckpointer<string>\n    {\n        internal EventHubCheckpointer() { }\n\n        public bool CheckpointExists { get { throw null; } }\n\n        public static System.Threading.Tasks.Task<Streams.IStreamQueueCheckpointer<string>> Create(Configuration.AzureTableStreamCheckpointerOptions options, string streamProviderName, string partition, string serviceId, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { throw null; }\n\n        public System.Threading.Tasks.Task<string> Load() { throw null; }\n\n        public void Update(string offset, System.DateTime utcNow) { }\n    }\n\n    public partial class EventHubCheckpointerFactory : Streams.IStreamQueueCheckpointerFactory\n    {\n        public EventHubCheckpointerFactory(string providerName, Configuration.AzureTableStreamCheckpointerOptions options, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task<Streams.IStreamQueueCheckpointer<string>> Create(string partition) { throw null; }\n\n        public static Streams.IStreamQueueCheckpointerFactory CreateFactory(System.IServiceProvider services, string providerName) { throw null; }\n    }\n\n    public partial class EventHubDataAdapter : IEventHubDataAdapter, Streams.IQueueDataAdapter<Azure.Messaging.EventHubs.EventData>, Providers.Streams.Common.ICacheDataAdapter\n    {\n        public EventHubDataAdapter(Serialization.Serializer serializer) { }\n\n        protected virtual System.ArraySegment<byte> EncodeMessageIntoSegment(Azure.Messaging.EventHubs.EventData queueMessage, System.Func<int, System.ArraySegment<byte>> getSegment) { throw null; }\n\n        public virtual Providers.Streams.Common.CachedMessage FromQueueMessage(Streams.StreamPosition streamPosition, Azure.Messaging.EventHubs.EventData queueMessage, System.DateTime dequeueTime, System.Func<int, System.ArraySegment<byte>> getSegment) { throw null; }\n\n        public virtual Streams.IBatchContainer GetBatchContainer(ref Providers.Streams.Common.CachedMessage cachedMessage) { throw null; }\n\n        protected virtual Streams.IBatchContainer GetBatchContainer(EventHubMessage eventHubMessage) { throw null; }\n\n        public virtual string GetOffset(Providers.Streams.Common.CachedMessage lastItemPurged) { throw null; }\n\n        public virtual string GetPartitionKey(Runtime.StreamId streamId) { throw null; }\n\n        public virtual Streams.StreamSequenceToken GetSequenceToken(ref Providers.Streams.Common.CachedMessage cachedMessage) { throw null; }\n\n        public virtual Runtime.StreamId GetStreamIdentity(Azure.Messaging.EventHubs.EventData queueMessage) { throw null; }\n\n        public virtual Streams.StreamPosition GetStreamPosition(string partition, Azure.Messaging.EventHubs.EventData queueMessage) { throw null; }\n\n        public virtual Azure.Messaging.EventHubs.EventData ToQueueMessage<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class EventHubMessage\n    {\n        public EventHubMessage(Providers.Streams.Common.CachedMessage cachedMessage, Serialization.Serializer serializer) { }\n\n        public EventHubMessage(Runtime.StreamId streamId, string partitionKey, string offset, long sequenceNumber, System.DateTime enqueueTimeUtc, System.DateTime dequeueTimeUtc, System.Collections.Generic.IDictionary<string, object> properties, byte[] payload) { }\n\n        [Id(5)]\n        public System.DateTime DequeueTimeUtc { get { throw null; } }\n\n        [Id(4)]\n        public System.DateTime EnqueueTimeUtc { get { throw null; } }\n\n        [Id(2)]\n        public string Offset { get { throw null; } }\n\n        [Id(1)]\n        public string PartitionKey { get { throw null; } }\n\n        [Id(7)]\n        public byte[] Payload { get { throw null; } }\n\n        [Id(6)]\n        public System.Collections.Generic.IDictionary<string, object> Properties { get { throw null; } }\n\n        [Id(3)]\n        public long SequenceNumber { get { throw null; } }\n\n        [Id(0)]\n        public Runtime.StreamId StreamId { get { throw null; } }\n    }\n\n    public partial class EventHubMonitorAggregationDimensions\n    {\n        public EventHubMonitorAggregationDimensions() { }\n\n        public EventHubMonitorAggregationDimensions(EventHubMonitorAggregationDimensions dimensions) { }\n\n        public EventHubMonitorAggregationDimensions(string ehHubPath) { }\n\n        public string EventHubPath { get { throw null; } set { } }\n    }\n\n    public partial class EventHubPartitionSettings\n    {\n        public Configuration.EventHubOptions Hub { get { throw null; } set { } }\n\n        public string Partition { get { throw null; } set { } }\n\n        public Configuration.EventHubReceiverOptions ReceiverOptions { get { throw null; } set { } }\n    }\n\n    public partial class EventHubQueueCache : IEventHubQueueCache, Streams.IQueueFlowController, System.IDisposable\n    {\n        protected readonly Providers.Streams.Common.PooledQueueCache cache;\n        public EventHubQueueCache(string partition, int defaultMaxAddCount, Providers.Streams.Common.IObjectPool<Providers.Streams.Common.FixedSizeBuffer> bufferPool, IEventHubDataAdapter dataAdapter, Providers.Streams.Common.IEvictionStrategy evictionStrategy, Streams.IStreamQueueCheckpointer<string> checkpointer, Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor cacheMonitor, System.TimeSpan? cacheMonitorWriteInterval, System.TimeSpan? metadataMinTimeInCache) { }\n\n        public string Partition { get { throw null; } }\n\n        public System.Collections.Generic.List<Streams.StreamPosition> Add(System.Collections.Generic.List<Azure.Messaging.EventHubs.EventData> messages, System.DateTime dequeueTimeUtc) { throw null; }\n\n        public void AddCachePressureMonitor(ICachePressureMonitor monitor) { }\n\n        public void Dispose() { }\n\n        public object GetCursor(Runtime.StreamId streamId, Streams.StreamSequenceToken sequenceToken) { throw null; }\n\n        public int GetMaxAddCount() { throw null; }\n\n        public void SignalPurge() { }\n\n        public bool TryGetNextMessage(object cursorObj, out Streams.IBatchContainer message) { throw null; }\n    }\n\n    public partial class EventHubQueueCacheFactory : IEventHubQueueCacheFactory\n    {\n        public EventHubQueueCacheFactory(Configuration.EventHubStreamCachePressureOptions cacheOptions, Configuration.StreamCacheEvictionOptions evictionOptions, Configuration.StreamStatisticOptions statisticOptions, IEventHubDataAdapter dataAdater, EventHubMonitorAggregationDimensions sharedDimensions, System.Func<EventHubCacheMonitorDimensions, Microsoft.Extensions.Logging.ILoggerFactory, Providers.Streams.Common.ICacheMonitor> cacheMonitorFactory = null, System.Func<EventHubBlockPoolMonitorDimensions, Microsoft.Extensions.Logging.ILoggerFactory, Providers.Streams.Common.IBlockPoolMonitor> blockPoolMonitorFactory = null) { }\n\n        public System.Func<EventHubBlockPoolMonitorDimensions, Microsoft.Extensions.Logging.ILoggerFactory, Providers.Streams.Common.IBlockPoolMonitor> BlockPoolMonitorFactory { get { throw null; } set { } }\n\n        public System.Func<EventHubCacheMonitorDimensions, Microsoft.Extensions.Logging.ILoggerFactory, Providers.Streams.Common.ICacheMonitor> CacheMonitorFactory { get { throw null; } set { } }\n\n        protected virtual void AddCachePressureMonitors(IEventHubQueueCache cache, Configuration.EventHubStreamCachePressureOptions providerOptions, Microsoft.Extensions.Logging.ILogger cacheLogger) { }\n\n        protected virtual Providers.Streams.Common.IObjectPool<Providers.Streams.Common.FixedSizeBuffer> CreateBufferPool(Configuration.StreamStatisticOptions statisticOptions, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, EventHubMonitorAggregationDimensions sharedDimensions, out string blockPoolId) { throw null; }\n\n        protected virtual IEventHubQueueCache CreateCache(string partition, IEventHubDataAdapter dataAdatper, Configuration.StreamStatisticOptions statisticOptions, Configuration.StreamCacheEvictionOptions streamCacheEvictionOptions, Streams.IStreamQueueCheckpointer<string> checkpointer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Providers.Streams.Common.IObjectPool<Providers.Streams.Common.FixedSizeBuffer> bufferPool, string blockPoolId, Providers.Streams.Common.TimePurgePredicate timePurge, EventHubMonitorAggregationDimensions sharedDimensions) { throw null; }\n\n        public IEventHubQueueCache CreateCache(string partition, Streams.IStreamQueueCheckpointer<string> checkpointer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { throw null; }\n    }\n\n    public partial class EventHubReceiverMonitorDimensions : EventHubMonitorAggregationDimensions\n    {\n        public EventHubReceiverMonitorDimensions() { }\n\n        public EventHubReceiverMonitorDimensions(EventHubMonitorAggregationDimensions dimensions, string ehPartition) { }\n\n        public string EventHubPartition { get { throw null; } set { } }\n    }\n\n    [GenerateSerializer]\n    public partial class EventHubSequenceToken : Providers.Streams.Common.EventSequenceToken, IEventHubPartitionLocation\n    {\n        public EventHubSequenceToken() { }\n\n        public EventHubSequenceToken(string eventHubOffset, long sequenceNumber, int eventIndex) { }\n\n        [Id(0)]\n        [Newtonsoft.Json.JsonProperty]\n        public string EventHubOffset { get { throw null; } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class EventHubSequenceTokenV2 : EventHubSequenceToken\n    {\n        public EventHubSequenceTokenV2() { }\n\n        public EventHubSequenceTokenV2(string eventHubOffset, long sequenceNumber, int eventIndex) { }\n    }\n\n    public partial interface ICachePressureMonitor\n    {\n        Providers.Streams.Common.ICacheMonitor CacheMonitor { set; }\n\n        bool IsUnderPressure(System.DateTime utcNow);\n        void RecordCachePressureContribution(double cachePressureContribution);\n    }\n\n    public partial interface IEventHubDataAdapter : Streams.IQueueDataAdapter<Azure.Messaging.EventHubs.EventData>, Providers.Streams.Common.ICacheDataAdapter\n    {\n        Providers.Streams.Common.CachedMessage FromQueueMessage(Streams.StreamPosition position, Azure.Messaging.EventHubs.EventData queueMessage, System.DateTime dequeueTime, System.Func<int, System.ArraySegment<byte>> getSegment);\n        string GetOffset(Providers.Streams.Common.CachedMessage cachedMessage);\n        string GetPartitionKey(Runtime.StreamId streamId);\n        Runtime.StreamId GetStreamIdentity(Azure.Messaging.EventHubs.EventData queueMessage);\n        Streams.StreamPosition GetStreamPosition(string partition, Azure.Messaging.EventHubs.EventData queueMessage);\n    }\n\n    public partial interface IEventHubPartitionLocation\n    {\n        string EventHubOffset { get; }\n\n        long SequenceNumber { get; }\n    }\n\n    public partial interface IEventHubQueueCache : Streams.IQueueFlowController, System.IDisposable\n    {\n        System.Collections.Generic.List<Streams.StreamPosition> Add(System.Collections.Generic.List<Azure.Messaging.EventHubs.EventData> message, System.DateTime dequeueTimeUtc);\n        void AddCachePressureMonitor(ICachePressureMonitor monitor);\n        object GetCursor(Runtime.StreamId streamId, Streams.StreamSequenceToken sequenceToken);\n        void SignalPurge();\n        bool TryGetNextMessage(object cursorObj, out Streams.IBatchContainer message);\n    }\n\n    public partial interface IEventHubQueueCacheFactory\n    {\n        IEventHubQueueCache CreateCache(string partition, Streams.IStreamQueueCheckpointer<string> checkpointer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory);\n    }\n\n    public partial interface IEventHubReceiver\n    {\n        System.Threading.Tasks.Task CloseAsync();\n        System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Azure.Messaging.EventHubs.EventData>> ReceiveAsync(int maxCount, System.TimeSpan waitTime);\n    }\n\n    public partial class SlowConsumingPressureMonitor : ICachePressureMonitor\n    {\n        public const double DefaultFlowControlThreshold = 0.5D;\n        public static System.TimeSpan DefaultPressureWindowSize;\n        public SlowConsumingPressureMonitor(Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public SlowConsumingPressureMonitor(double flowControlThreshold, Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public SlowConsumingPressureMonitor(double flowControlThreshold, System.TimeSpan pressureWindowSzie, Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public SlowConsumingPressureMonitor(System.TimeSpan pressureWindowSize, Microsoft.Extensions.Logging.ILogger logger, Providers.Streams.Common.ICacheMonitor monitor = null) { }\n\n        public Providers.Streams.Common.ICacheMonitor CacheMonitor { set { } }\n\n        public double FlowControlThreshold { get { throw null; } set { } }\n\n        public System.TimeSpan PressureWindowSize { get { throw null; } set { } }\n\n        public bool IsUnderPressure(System.DateTime utcNow) { throw null; }\n\n        public void RecordCachePressureContribution(double cachePressureContribution) { }\n    }\n}\n\nnamespace Orleans.Streaming.EventHubs.StatisticMonitors\n{\n    public partial class DefaultEventHubBlockPoolMonitor : Providers.Streams.Common.DefaultBlockPoolMonitor\n    {\n        public DefaultEventHubBlockPoolMonitor(EventHubBlockPoolMonitorDimensions dimensions) : base(default(System.Collections.Generic.KeyValuePair<string, object>[])!) { }\n    }\n\n    public partial class DefaultEventHubCacheMonitor : Providers.Streams.Common.DefaultCacheMonitor\n    {\n        public DefaultEventHubCacheMonitor(EventHubCacheMonitorDimensions dimensions) : base(default(System.Collections.Generic.KeyValuePair<string, object>[])!) { }\n    }\n}\n\nnamespace Orleans.Streaming.EventHubs.Testing\n{\n    public partial class EventDataGeneratorAdapterFactory : EventHubAdapterFactory, Providers.IControllable\n    {\n        public EventDataGeneratorAdapterFactory(string name, Configuration.EventDataGeneratorStreamOptions options, Configuration.EventHubOptions ehOptions, Configuration.EventHubReceiverOptions receiverOptions, Configuration.EventHubStreamCachePressureOptions cacheOptions, Configuration.StreamCacheEvictionOptions evictionOptions, Configuration.StreamStatisticOptions statisticOptions, IEventHubDataAdapter dataAdapter, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Statistics.IEnvironmentStatisticsProvider environmentStatisticsProvider) : base(default!, default!, default!, default!, default!, default!, default!, default!, default!, default!) { }\n\n        public new static EventDataGeneratorAdapterFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public virtual System.Threading.Tasks.Task<object> ExecuteCommand(int command, object arg) { throw null; }\n\n        public static string[] GenerateEventHubPartitions(int partitionCount) { throw null; }\n\n        protected override System.Threading.Tasks.Task<string[]> GetPartitionIdsAsync() { throw null; }\n\n        public override void Init() { }\n\n        protected override void InitEventHubClient() { }\n\n        public enum Commands\n        {\n            Randomly_Place_Stream_To_Queue = 20004,\n            Stop_Producing_On_Stream = 20005\n        }\n\n        [GenerateSerializer]\n        public partial class StreamRandomPlacementArg\n        {\n            public StreamRandomPlacementArg(Runtime.StreamId streamId, int randomNumber) { }\n\n            [Id(1)]\n            public int RandomNumber { get { throw null; } set { } }\n\n            [Id(0)]\n            public Runtime.StreamId StreamId { get { throw null; } set { } }\n        }\n    }\n\n    public partial class EventHubPartitionDataGenerator : IDataGenerator<Azure.Messaging.EventHubs.EventData>, IStreamDataGeneratingController\n    {\n        public EventHubPartitionDataGenerator(Configuration.EventDataGeneratorStreamOptions options, System.Func<Runtime.StreamId, IStreamDataGenerator<Azure.Messaging.EventHubs.EventData>> generatorFactory, Microsoft.Extensions.Logging.ILogger logger) { }\n\n        public void AddDataGeneratorForStream(Runtime.StreamId streamId) { }\n\n        public void StopProducingOnStream(Runtime.StreamId streamId) { }\n\n        public bool TryReadEvents(int maxCount, out System.Collections.Generic.IEnumerable<Azure.Messaging.EventHubs.EventData> events) { throw null; }\n    }\n\n    public partial class EventHubPartitionGeneratorReceiver : IEventHubReceiver\n    {\n        public EventHubPartitionGeneratorReceiver(IDataGenerator<Azure.Messaging.EventHubs.EventData> generator) { }\n\n        public System.Threading.Tasks.Task CloseAsync() { throw null; }\n\n        public void ConfigureDataGeneratorForStream(Runtime.StreamId streamId) { }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Azure.Messaging.EventHubs.EventData>> ReceiveAsync(int maxCount, System.TimeSpan waitTime) { throw null; }\n\n        public void StopProducingOnStream(Runtime.StreamId streamId) { }\n    }\n\n    public partial interface IDataGenerator<T>\n    {\n        bool TryReadEvents(int maxCount, out System.Collections.Generic.IEnumerable<T> events);\n    }\n\n    public partial interface IIntCounter\n    {\n        int Value { get; }\n\n        void Increment();\n    }\n\n    public partial interface IStreamDataGeneratingController\n    {\n        void AddDataGeneratorForStream(Runtime.StreamId streamId);\n        void StopProducingOnStream(Runtime.StreamId streamId);\n    }\n\n    public partial interface IStreamDataGenerator<T> : IDataGenerator<T>\n    {\n        IIntCounter SequenceNumberCounter { set; }\n\n        bool ShouldProduce { set; }\n\n        Runtime.StreamId StreamId { get; }\n    }\n\n    public partial class NoOpCheckpointer : Streams.IStreamQueueCheckpointer<string>\n    {\n        public static NoOpCheckpointer Instance;\n        public bool CheckpointExists { get { throw null; } }\n\n        public System.Threading.Tasks.Task<string> Load() { throw null; }\n\n        public void Update(string offset, System.DateTime utcNow) { }\n    }\n\n    public partial class NoOpCheckpointerFactory : Streams.IStreamQueueCheckpointerFactory\n    {\n        public static NoOpCheckpointerFactory Instance;\n        public System.Threading.Tasks.Task<Streams.IStreamQueueCheckpointer<string>> Create(string partition) { throw null; }\n    }\n\n    public partial class SimpleStreamEventDataGenerator : IStreamDataGenerator<Azure.Messaging.EventHubs.EventData>, IDataGenerator<Azure.Messaging.EventHubs.EventData>\n    {\n        public SimpleStreamEventDataGenerator(Runtime.StreamId streamId, Microsoft.Extensions.Logging.ILogger<SimpleStreamEventDataGenerator> logger, Serialization.DeepCopier deepCopier, Serialization.Serializer serializer) { }\n\n        public IIntCounter SequenceNumberCounter { set { } }\n\n        public bool ShouldProduce { set { } }\n\n        public Runtime.StreamId StreamId { get { throw null; } set { } }\n\n        public static System.Func<Runtime.StreamId, IStreamDataGenerator<Azure.Messaging.EventHubs.EventData>> CreateFactory(System.IServiceProvider services) { throw null; }\n\n        public bool TryReadEvents(int maxCount, out System.Collections.Generic.IEnumerable<Azure.Messaging.EventHubs.EventData> events) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Streaming.EventHubs\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventHubBatchContainer : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streaming.EventHubs.EventHubBatchContainer>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streaming.EventHubs.EventHubBatchContainer>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventHubBatchContainer(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.EventHubBatchContainer> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streaming.EventHubs.EventHubBatchContainer instance) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubBatchContainer ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streaming.EventHubs.EventHubBatchContainer instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streaming.EventHubs.EventHubBatchContainer value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventHubMessage : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streaming.EventHubs.EventHubMessage>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streaming.EventHubs.EventHubMessage>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventHubMessage(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.EventHubMessage> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streaming.EventHubs.EventHubMessage instance) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubMessage ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streaming.EventHubs.EventHubMessage instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streaming.EventHubs.EventHubMessage value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventHubSequenceToken : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streaming.EventHubs.EventHubSequenceToken>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streaming.EventHubs.EventHubSequenceToken>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventHubSequenceToken(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streaming.EventHubs.EventHubSequenceToken instance) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubSequenceToken ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streaming.EventHubs.EventHubSequenceToken instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streaming.EventHubs.EventHubSequenceToken value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventHubSequenceTokenV2 : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventHubSequenceTokenV2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 instance) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventHubBatchContainer : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streaming.EventHubs.EventHubBatchContainer>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streaming.EventHubs.EventHubBatchContainer>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventHubBatchContainer(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.EventHubBatchContainer> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubBatchContainer DeepCopy(global::Orleans.Streaming.EventHubs.EventHubBatchContainer original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streaming.EventHubs.EventHubBatchContainer input, global::Orleans.Streaming.EventHubs.EventHubBatchContainer output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventHubMessage : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streaming.EventHubs.EventHubMessage>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streaming.EventHubs.EventHubMessage>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventHubMessage(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.EventHubMessage> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubMessage DeepCopy(global::Orleans.Streaming.EventHubs.EventHubMessage original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streaming.EventHubs.EventHubMessage input, global::Orleans.Streaming.EventHubs.EventHubMessage output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventHubSequenceToken : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streaming.EventHubs.EventHubSequenceToken>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streaming.EventHubs.EventHubSequenceToken>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventHubSequenceToken(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubSequenceToken DeepCopy(global::Orleans.Streaming.EventHubs.EventHubSequenceToken original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streaming.EventHubs.EventHubSequenceToken input, global::Orleans.Streaming.EventHubs.EventHubSequenceToken output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventHubSequenceTokenV2 : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventHubSequenceTokenV2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 DeepCopy(global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 input, global::Orleans.Streaming.EventHubs.EventHubSequenceTokenV2 output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamRandomPlacementArg : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_StreamRandomPlacementArg(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg instance) { }\n\n        public global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_StreamRandomPlacementArg : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_StreamRandomPlacementArg(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg> _activator) { }\n\n        public global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg DeepCopy(global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg input, global::Orleans.Streaming.EventHubs.Testing.EventDataGeneratorAdapterFactory.StreamRandomPlacementArg output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}"
  },
  {
    "path": "src/api/Azure/Orleans.Transactions.AzureStorage/Orleans.Transactions.AzureStorage.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class AzureTableTransactionalStateOptions : Transactions.AzureStorage.AzureStorageOperationOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public int InitStage { get { throw null; } set { } }\n\n        public override string TableName { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableTransactionalStateOptionsValidator : Transactions.AzureStorage.AzureStorageOperationOptionsValidator<AzureTableTransactionalStateOptions>\n    {\n        public AzureTableTransactionalStateOptionsValidator(AzureTableTransactionalStateOptions options, string name) : base(default!, default!) { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class AzureTableTransactionServicecollectionExtensions\n    {\n    }\n\n    public static partial class AzureTableTransactionSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddAzureTableTransactionalStateStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableTransactionalStateOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureTableTransactionalStateStorage(this ISiloBuilder builder, string name, System.Action<Configuration.AzureTableTransactionalStateOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddAzureTableTransactionalStateStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.AzureTableTransactionalStateOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddAzureTableTransactionalStateStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.AzureTableTransactionalStateOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Transactions.AzureStorage\n{\n    public partial class AzureStorageOperationOptions\n    {\n        public Azure.Data.Tables.TableClientOptions ClientOptions { get { throw null; } set { } }\n\n        public AzureStoragePolicyOptions StoragePolicyOptions { get { throw null; } }\n\n        public virtual string TableName { get { throw null; } set { } }\n\n        public Azure.Data.Tables.TableServiceClient TableServiceClient { get { throw null; } set { } }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Func<System.Threading.Tasks.Task<Azure.Data.Tables.TableServiceClient>> createClientCallback) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(string connectionString) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.AzureSasCredential azureSasCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Core.TokenCredential tokenCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri, Azure.Data.Tables.TableSharedKeyCredential sharedKeyCredential) { }\n\n        [System.Obsolete(\"Set the TableServiceClient property directly.\")]\n        public void ConfigureTableServiceClient(System.Uri serviceUri) { }\n    }\n\n    public partial class AzureStorageOperationOptionsValidator<TOptions> : IConfigurationValidator where TOptions : AzureStorageOperationOptions\n    {\n        public AzureStorageOperationOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n\n    public partial class AzureStoragePolicyOptions\n    {\n        public System.TimeSpan CreationTimeout { get { throw null; } set { } }\n\n        public int MaxBulkUpdateRows { get { throw null; } set { } }\n\n        public int MaxCreationRetries { get { throw null; } set { } }\n\n        public int MaxOperationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan OperationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenCreationRetries { get { throw null; } set { } }\n\n        public System.TimeSpan PauseBetweenOperationRetries { get { throw null; } set { } }\n    }\n\n    public partial class AzureTableTransactionalStateStorageFactory : Abstractions.ITransactionalStateStorageFactory, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public AzureTableTransactionalStateStorageFactory(string name, Configuration.AzureTableTransactionalStateOptions options, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, System.IServiceProvider services, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public static Abstractions.ITransactionalStateStorageFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public Abstractions.ITransactionalStateStorage<TState> Create<TState>(string stateName, Runtime.IGrainContext context)\n            where TState : class, new() { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n    }\n\n    public partial class AzureTableTransactionalStateStorage<TState> : Abstractions.ITransactionalStateStorage<TState> where TState : class, new()\n    {\n        public AzureTableTransactionalStateStorage(Azure.Data.Tables.TableClient table, string partition, Newtonsoft.Json.JsonSerializerSettings JsonSettings, Microsoft.Extensions.Logging.ILogger<AzureTableTransactionalStateStorage<TState>> logger) { }\n\n        public System.Threading.Tasks.Task<Abstractions.TransactionalStorageLoadResponse<TState>> Load() { throw null; }\n\n        public System.Threading.Tasks.Task<string> Store(string expectedETag, Abstractions.TransactionalStateMetaData metadata, System.Collections.Generic.List<Abstractions.PendingTransactionState<TState>> statesToPrepare, long? commitUpTo, long? abortAfter) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Cassandra/Orleans.Clustering.Cassandra/Orleans.Clustering.Cassandra.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Clustering.Cassandra.Hosting\n{\n    public partial class CassandraClusteringOptions\n    {\n        public System.TimeSpan InitializeRetryMaxDelay { get { throw null; } set { } }\n\n        public bool UseCassandraTtl { get { throw null; } set { } }\n\n        public void ConfigureClient(System.Func<System.IServiceProvider, System.Threading.Tasks.Task<global::Cassandra.ISession>> configurationDelegate) { }\n\n        public void ConfigureClient(string connectionString, string keyspace = \"orleans\") { }\n    }\n\n    public static partial class CassandraMembershipHostingExtensions\n    {\n        public static Orleans.Hosting.IClientBuilder UseCassandraClustering(this Orleans.Hosting.IClientBuilder builder, System.Action<CassandraClusteringOptions> configureOptions) { throw null; }\n\n        public static Orleans.Hosting.IClientBuilder UseCassandraClustering(this Orleans.Hosting.IClientBuilder builder, System.Func<System.IServiceProvider, System.Threading.Tasks.Task<global::Cassandra.ISession>> sessionProvider) { throw null; }\n\n        public static Orleans.Hosting.IClientBuilder UseCassandraClustering(this Orleans.Hosting.IClientBuilder builder, string connectionString, string keyspace = \"orleans\") { throw null; }\n\n        public static Orleans.Hosting.IClientBuilder UseCassandraClustering(this Orleans.Hosting.IClientBuilder builder) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseCassandraClustering(this Orleans.Hosting.ISiloBuilder builder, System.Action<CassandraClusteringOptions> configureOptions) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseCassandraClustering(this Orleans.Hosting.ISiloBuilder builder, System.Func<System.IServiceProvider, System.Threading.Tasks.Task<global::Cassandra.ISession>> sessionProvider) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseCassandraClustering(this Orleans.Hosting.ISiloBuilder builder, string connectionString, string keyspace = \"orleans\") { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseCassandraClustering(this Orleans.Hosting.ISiloBuilder builder) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.BroadcastChannel/Orleans.BroadcastChannel.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public partial class ImplicitChannelSubscriptionAttribute : System.Attribute, Metadata.IGrainBindingsProviderAttribute\n    {\n        public ImplicitChannelSubscriptionAttribute() { }\n\n        public ImplicitChannelSubscriptionAttribute(BroadcastChannel.IChannelNamespacePredicate predicate, string channelIdMapper = null) { }\n\n        public ImplicitChannelSubscriptionAttribute(string streamNamespace, string channelIdMapper = null) { }\n\n        public ImplicitChannelSubscriptionAttribute(System.Type predicateType, string channelIdMapper = null) { }\n\n        public string ChannelIdMapper { get { throw null; } }\n\n        public BroadcastChannel.IChannelNamespacePredicate Predicate { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<System.Collections.Generic.Dictionary<string, string>> GetBindings(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public sealed partial class RegexImplicitChannelSubscriptionAttribute : ImplicitChannelSubscriptionAttribute\n    {\n        public RegexImplicitChannelSubscriptionAttribute(string pattern) { }\n    }\n}\n\nnamespace Orleans.BroadcastChannel\n{\n    public partial class BroadcastChannelOptions\n    {\n        public bool FireAndForgetDelivery { get { throw null; } set { } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct ChannelId : System.IEquatable<ChannelId>, System.IComparable<ChannelId>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public System.ReadOnlyMemory<byte> FullKey { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> Key { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> Namespace { get { throw null; } }\n\n        public readonly int CompareTo(ChannelId other) { throw null; }\n\n        public static ChannelId Create(System.ReadOnlySpan<byte> ns, System.ReadOnlySpan<byte> key) { throw null; }\n\n        public static ChannelId Create(string ns, System.Guid key) { throw null; }\n\n        public static ChannelId Create(string ns, string key) { throw null; }\n\n        public readonly bool Equals(ChannelId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly string GetKeyAsString() { throw null; }\n\n        public readonly string? GetNamespace() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public static bool operator ==(ChannelId s1, ChannelId s2) { throw null; }\n\n        public static bool operator !=(ChannelId s1, ChannelId s2) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public partial class ConstructorChannelNamespacePredicateProvider : IChannelNamespacePredicateProvider\n    {\n        public const string Prefix = \"ctor\";\n        public static string FormatPattern(System.Type predicateType, string constructorArgument) { throw null; }\n\n        public bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate) { throw null; }\n    }\n\n    public sealed partial class DefaultChannelIdMapper : IChannelIdMapper\n    {\n        public const string Name = \"default\";\n        public Runtime.IdSpan GetGrainKeyId(Metadata.GrainBindings grainBindings, ChannelId streamId) { throw null; }\n    }\n\n    public partial class DefaultChannelNamespacePredicateProvider : IChannelNamespacePredicateProvider\n    {\n        public bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate) { throw null; }\n    }\n\n    public partial interface IBroadcastChannelProvider\n    {\n        IBroadcastChannelWriter<T> GetChannelWriter<T>(ChannelId streamId);\n    }\n\n    public partial interface IBroadcastChannelSubscription\n    {\n        ChannelId ChannelId { get; }\n\n        string ProviderName { get; }\n\n        System.Threading.Tasks.Task Attach<T>(System.Func<T, System.Threading.Tasks.Task> onPublished, System.Func<System.Exception, System.Threading.Tasks.Task> onError = null);\n    }\n\n    public partial interface IBroadcastChannelWriter<T>\n    {\n        System.Threading.Tasks.Task Publish(T item);\n    }\n\n    public partial interface IChannelIdMapper\n    {\n        Runtime.IdSpan GetGrainKeyId(Metadata.GrainBindings grainBindings, ChannelId streamId);\n    }\n\n    public partial interface IChannelNamespacePredicate\n    {\n        string PredicatePattern { get; }\n\n        bool IsMatch(string streamNamespace);\n    }\n\n    public partial interface IChannelNamespacePredicateProvider\n    {\n        bool TryGetPredicate(string predicatePattern, out IChannelNamespacePredicate predicate);\n    }\n\n    public partial interface IOnBroadcastChannelSubscribed\n    {\n        System.Threading.Tasks.Task OnSubscribed(IBroadcastChannelSubscription streamSubscription);\n    }\n\n    public partial class RegexChannelNamespacePredicate : IChannelNamespacePredicate\n    {\n        public RegexChannelNamespacePredicate(string regex) { }\n\n        public string PredicatePattern { get { throw null; } }\n\n        public bool IsMatch(string streamNameSpace) { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ChannelHostingExtensions\n    {\n        public static IClientBuilder AddBroadcastChannel(this IClientBuilder @this, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<BroadcastChannel.BroadcastChannelOptions>> configureOptions = null) { throw null; }\n\n        public static IClientBuilder AddBroadcastChannel(this IClientBuilder @this, string name, System.Action<BroadcastChannel.BroadcastChannelOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddBroadcastChannel(this ISiloBuilder @this, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<BroadcastChannel.BroadcastChannelOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddBroadcastChannel(this ISiloBuilder @this, string name, System.Action<BroadcastChannel.BroadcastChannelOptions> configureOptions) { throw null; }\n\n        public static BroadcastChannel.IBroadcastChannelProvider GetBroadcastChannelProvider(this IClusterClient @this, string name) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.BroadcastChannel\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ChannelId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.BroadcastChannel.ChannelId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.BroadcastChannel.ChannelId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.BroadcastChannel.ChannelId instance) { }\n\n        public global::Orleans.BroadcastChannel.ChannelId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.BroadcastChannel.ChannelId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.BroadcastChannel.ChannelId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Client/Orleans.Client.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/api/Orleans.Clustering.Consul/Orleans.Clustering.Consul.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class ConsulClusteringOptions\n    {\n        public System.Func<Consul.IConsulClient> CreateClient { get { throw null; } }\n\n        public string KvRootFolder { get { throw null; } set { } }\n\n        public void ConfigureConsulClient(System.Func<Consul.IConsulClient> createClientCallback) { }\n\n        public void ConfigureConsulClient(System.Uri address, string aclClientToken = null) { }\n    }\n\n    public partial class ConsulClusteringOptionsValidator<TOptions> : IConfigurationValidator where TOptions : ConsulClusteringOptions\n    {\n        public ConsulClusteringOptionsValidator(TOptions options, string name = null) { }\n\n        public string Name { get { throw null; } }\n\n        public TOptions Options { get { throw null; } }\n\n        public virtual void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ConsulUtilsHostingExtensions\n    {\n        public static IClientBuilder UseConsulClientClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.ConsulClusteringOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseConsulClientClustering(this IClientBuilder builder, System.Action<Configuration.ConsulClusteringOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseConsulSiloClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.ConsulClusteringOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseConsulSiloClustering(this ISiloBuilder builder, System.Action<Configuration.ConsulClusteringOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Host\n{\n    [Newtonsoft.Json.JsonObject]\n    public partial class ConsulSiloRegistration\n    {\n        internal ConsulSiloRegistration() { }\n\n        [Newtonsoft.Json.JsonProperty]\n        public string Hostname { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public int ProxyPort { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public string SiloName { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public System.DateTime StartTime { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public SiloStatus Status { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public System.Collections.Generic.List<SuspectingSilo> SuspectingSilos { get { throw null; } set { } }\n    }\n\n    [Newtonsoft.Json.JsonObject]\n    public partial class SuspectingSilo\n    {\n        [Newtonsoft.Json.JsonProperty]\n        public string Id { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonProperty]\n        public System.DateTime Time { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Runtime.Membership\n{\n    public partial class ConsulBasedMembershipTable : IMembershipTable\n    {\n        public ConsulBasedMembershipTable(Microsoft.Extensions.Logging.ILogger<ConsulBasedMembershipTable> logger, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ConsulClusteringOptions> membershipTableOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions) { }\n\n        public System.Threading.Tasks.Task CleanupDefunctSiloEntries(System.DateTimeOffset beforeDate) { throw null; }\n\n        public System.Threading.Tasks.Task DeleteMembershipTableEntries(string clusterId) { throw null; }\n\n        public System.Threading.Tasks.Task InitializeMembershipTable(bool tryInitTableVersion) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion) { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadAll() { throw null; }\n\n        public static System.Threading.Tasks.Task<MembershipTableData> ReadAll(Consul.IConsulClient consulClient, string clusterId, string kvRootFolder, Microsoft.Extensions.Logging.ILogger logger, string versionKey) { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadRow(SiloAddress siloAddress) { throw null; }\n\n        public System.Threading.Tasks.Task UpdateIAmAlive(MembershipEntry entry) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) { throw null; }\n    }\n\n    public partial class ConsulGatewayListProvider : Orleans.Messaging.IGatewayListProvider\n    {\n        public ConsulGatewayListProvider(Microsoft.Extensions.Logging.ILogger<ConsulGatewayListProvider> logger, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ConsulClusteringOptions> options, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.GatewayOptions> gatewayOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions) { }\n\n        public bool IsUpdatable { get { throw null; } }\n\n        public System.TimeSpan MaxStaleness { get { throw null; } }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IList<System.Uri>> GetGateways() { throw null; }\n\n        public System.Threading.Tasks.Task InitializeGatewayListProvider() { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Clustering.ZooKeeper/Orleans.Clustering.ZooKeeper.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class ZooKeeperClusteringSiloOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n    }\n\n    public partial class ZooKeeperGatewayListProviderOptions\n    {\n        [Redact]\n        public string ConnectionString { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ZooKeeperHostingExtensions\n    {\n        public static IClientBuilder UseZooKeeperClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.ZooKeeperGatewayListProviderOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseZooKeeperClustering(this IClientBuilder builder, System.Action<Configuration.ZooKeeperGatewayListProviderOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseZooKeeperClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.ZooKeeperClusteringSiloOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseZooKeeperClustering(this ISiloBuilder builder, System.Action<Configuration.ZooKeeperClusteringSiloOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Membership\n{\n    public partial class ZooKeeperBasedMembershipTable : IMembershipTable\n    {\n        public ZooKeeperBasedMembershipTable(Microsoft.Extensions.Logging.ILogger<ZooKeeperBasedMembershipTable> logger, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ZooKeeperClusteringSiloOptions> membershipTableOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions) { }\n\n        public System.Threading.Tasks.Task CleanupDefunctSiloEntries(System.DateTimeOffset beforeDate) { throw null; }\n\n        public System.Threading.Tasks.Task DeleteMembershipTableEntries(string clusterId) { throw null; }\n\n        public System.Threading.Tasks.Task InitializeMembershipTable(bool tryInitPath) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion) { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadAll() { throw null; }\n\n        public System.Threading.Tasks.Task<MembershipTableData> ReadRow(SiloAddress siloAddress) { throw null; }\n\n        public System.Threading.Tasks.Task UpdateIAmAlive(MembershipEntry entry) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) { throw null; }\n    }\n\n    public partial class ZooKeeperGatewayListProvider : Orleans.Messaging.IGatewayListProvider\n    {\n        public ZooKeeperGatewayListProvider(Microsoft.Extensions.Logging.ILogger<ZooKeeperGatewayListProvider> logger, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ZooKeeperGatewayListProviderOptions> options, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.GatewayOptions> gatewayOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.ClusterOptions> clusterOptions) { }\n\n        public bool IsUpdatable { get { throw null; } }\n\n        public System.TimeSpan MaxStaleness { get { throw null; } }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IList<System.Uri>> GetGateways() { throw null; }\n\n        public System.Threading.Tasks.Task InitializeGatewayListProvider() { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Connections.Security/Orleans.Connections.Security.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    public static partial class TlsConnectionBuilderExtensions\n    {\n        public static void UseClientTls(this Microsoft.AspNetCore.Connections.IConnectionBuilder builder, Connections.Security.TlsOptions options) { }\n\n        public static void UseServerTls(this Microsoft.AspNetCore.Connections.IConnectionBuilder builder, Connections.Security.TlsOptions options) { }\n    }\n}\n\nnamespace Orleans.Connections.Security\n{\n    public static partial class CertificateLoader\n    {\n        public static System.Security.Cryptography.X509Certificates.X509Certificate2 LoadFromStoreCert(string subject, string storeName, System.Security.Cryptography.X509Certificates.StoreLocation storeLocation, bool allowInvalid, bool server) { throw null; }\n    }\n\n    public delegate System.Security.Cryptography.X509Certificates.X509Certificate ClientCertificateSelectionCallback(object sender, string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection localCertificates, System.Security.Cryptography.X509Certificates.X509Certificate remoteCertificate, string[] acceptableIssuers);\n    public partial interface ITlsApplicationProtocolFeature\n    {\n        System.ReadOnlyMemory<byte> ApplicationProtocol { get; }\n    }\n\n    public partial interface ITlsConnectionFeature\n    {\n        System.Security.Cryptography.X509Certificates.X509Certificate2 RemoteCertificate { get; set; }\n\n        System.Threading.Tasks.Task<System.Security.Cryptography.X509Certificates.X509Certificate2> GetRemoteCertificateAsync(System.Threading.CancellationToken cancellationToken);\n    }\n\n    public partial interface ITlsHandshakeFeature\n    {\n        System.Security.Authentication.CipherAlgorithmType CipherAlgorithm { get; }\n\n        int CipherStrength { get; }\n\n        System.Security.Authentication.HashAlgorithmType HashAlgorithm { get; }\n\n        int HashStrength { get; }\n\n        System.Security.Authentication.ExchangeAlgorithmType KeyExchangeAlgorithm { get; }\n\n        int KeyExchangeStrength { get; }\n\n        System.Security.Authentication.SslProtocols Protocol { get; }\n    }\n\n    public enum RemoteCertificateMode\n    {\n        NoCertificate = 0,\n        AllowCertificate = 1,\n        RequireCertificate = 2\n    }\n\n    public delegate bool RemoteCertificateValidator(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors policyErrors);\n    public delegate System.Security.Cryptography.X509Certificates.X509Certificate ServerCertificateSelectionCallback(object sender, string hostName);\n    public partial class TlsClientAuthenticationOptions\n    {\n        public System.Security.Cryptography.X509Certificates.X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }\n\n        public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } set { } }\n\n        public System.Security.Authentication.SslProtocols EnabledSslProtocols { get { throw null; } set { } }\n\n        public ClientCertificateSelectionCallback LocalCertificateSelectionCallback { get { throw null; } set { } }\n\n        public object SslClientAuthenticationOptions { get { throw null; } }\n\n        public string TargetHost { get { throw null; } set { } }\n    }\n\n    public partial class TlsOptions\n    {\n        public bool CheckCertificateRevocation { get { throw null; } set { } }\n\n        public RemoteCertificateMode ClientCertificateMode { get { throw null; } set { } }\n\n        public System.TimeSpan HandshakeTimeout { get { throw null; } set { } }\n\n        public System.Security.Cryptography.X509Certificates.X509Certificate2 LocalCertificate { get { throw null; } set { } }\n\n        public System.Func<object, string, System.Security.Cryptography.X509Certificates.X509CertificateCollection, System.Security.Cryptography.X509Certificates.X509Certificate, string[], System.Security.Cryptography.X509Certificates.X509Certificate2> LocalClientCertificateSelector { get { throw null; } set { } }\n\n        public System.Func<Microsoft.AspNetCore.Connections.ConnectionContext, string, System.Security.Cryptography.X509Certificates.X509Certificate2> LocalServerCertificateSelector { get { throw null; } set { } }\n\n        public System.Action<Microsoft.AspNetCore.Connections.ConnectionContext, TlsClientAuthenticationOptions> OnAuthenticateAsClient { get { throw null; } set { } }\n\n        public System.Action<Microsoft.AspNetCore.Connections.ConnectionContext, TlsServerAuthenticationOptions> OnAuthenticateAsServer { get { throw null; } set { } }\n\n        public RemoteCertificateMode RemoteCertificateMode { get { throw null; } set { } }\n\n        public RemoteCertificateValidator RemoteCertificateValidation { get { throw null; } set { } }\n\n        public System.Security.Authentication.SslProtocols SslProtocols { get { throw null; } set { } }\n\n        public void AllowAnyRemoteCertificate() { }\n    }\n\n    public partial class TlsServerAuthenticationOptions\n    {\n        public System.Security.Cryptography.X509Certificates.X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }\n\n        public bool ClientCertificateRequired { get { throw null; } set { } }\n\n        public System.Security.Authentication.SslProtocols EnabledSslProtocols { get { throw null; } set { } }\n\n        public System.Security.Cryptography.X509Certificates.X509Certificate ServerCertificate { get { throw null; } set { } }\n\n        public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get { throw null; } set { } }\n\n        public object SslServerAuthenticationOptions { get { throw null; } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class OrleansConnectionSecurityHostingExtensions\n    {\n        public static IClientBuilder UseTls(this IClientBuilder builder, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseTls(this IClientBuilder builder, System.Security.Cryptography.X509Certificates.StoreName storeName, string subject, bool allowInvalid, System.Security.Cryptography.X509Certificates.StoreLocation location, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseTls(this IClientBuilder builder, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseTls(this IClientBuilder builder, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }\n\n        public static ISiloBuilder UseTls(this ISiloBuilder builder, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseTls(this ISiloBuilder builder, System.Security.Cryptography.X509Certificates.StoreName storeName, string subject, bool allowInvalid, System.Security.Cryptography.X509Certificates.StoreLocation location, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseTls(this ISiloBuilder builder, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Action<Connections.Security.TlsOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseTls(this ISiloBuilder builder, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Core/Orleans.Core.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Microsoft.Extensions.Hosting\n{\n    public static partial class OrleansClientGenericHostExtensions\n    {\n        public static DependencyInjection.IServiceCollection AddOrleansClient(this DependencyInjection.IServiceCollection services, Configuration.IConfiguration configuration, System.Action<Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static DependencyInjection.IServiceCollection AddOrleansClient(this DependencyInjection.IServiceCollection services, System.Action<Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static HostApplicationBuilder UseOrleansClient(this HostApplicationBuilder hostAppBuilder, System.Action<Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static HostApplicationBuilder UseOrleansClient(this HostApplicationBuilder hostAppBuilder) { throw null; }\n\n        public static IHostApplicationBuilder UseOrleansClient(this IHostApplicationBuilder hostAppBuilder, System.Action<Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static IHostApplicationBuilder UseOrleansClient(this IHostApplicationBuilder hostAppBuilder) { throw null; }\n\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder, System.Action<HostBuilderContext, Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder, System.Action<Orleans.Hosting.IClientBuilder> configureDelegate) { throw null; }\n\n        public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder) { throw null; }\n    }\n}\n\nnamespace Orleans\n{\n    public partial class AsyncSerialExecutor\n    {\n        public System.Threading.Tasks.Task AddNext(System.Func<System.Threading.Tasks.Task> func) { throw null; }\n    }\n\n    public partial class AsyncSerialExecutor<TResult>\n    {\n        public System.Threading.Tasks.Task<TResult> AddNext(System.Func<System.Threading.Tasks.Task<TResult>> func) { throw null; }\n    }\n\n    public abstract partial class BatchWorker\n    {\n        protected System.Threading.CancellationToken CancellationToken { get { throw null; } set { } }\n\n        public bool IsIdle() { throw null; }\n\n        public void Notify() { }\n\n        public void Notify(System.DateTime utcTime) { }\n\n        public System.Threading.Tasks.Task NotifyAndWaitForWorkToBeServiced() { throw null; }\n\n        public System.Threading.Tasks.Task WaitForCurrentWorkToBeServiced() { throw null; }\n\n        protected abstract System.Threading.Tasks.Task Work();\n    }\n\n    public partial class BatchWorkerFromDelegate : BatchWorker\n    {\n        public BatchWorkerFromDelegate(System.Func<System.Threading.Tasks.Task> work, System.Threading.CancellationToken cancellationToken = default) { }\n\n        protected override System.Threading.Tasks.Task Work() { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public partial class CollectionAgeLimitAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public static readonly System.TimeSpan MinAgeLimit;\n        public CollectionAgeLimitAttribute() { }\n\n        public CollectionAgeLimitAttribute(string inactivityPeriod) { }\n\n        public System.TimeSpan AgeLimit { get { throw null; } }\n\n        public bool AlwaysActive { get { throw null; } set { } }\n\n        public double Days { get { throw null; } set { } }\n\n        public double Hours { get { throw null; } set { } }\n\n        public double Minutes { get { throw null; } set { } }\n\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public delegate void ConnectionToClusterLostHandler(object sender, System.EventArgs e);\n    public delegate TInstance Factory<out TInstance>();\n    public delegate TInstance Factory<in TParam1, out TInstance>(TParam1 param1);\n    public delegate TInstance Factory<in TParam1, in TParam2, out TInstance>(TParam1 param1, TParam2 param2);\n    public delegate TInstance Factory<in TParam1, in TParam2, in TParam3, out TInstance>(TParam1 param1, TParam2 param2, TParam3 param3);\n    public partial class GatewayCountChangedEventArgs : System.EventArgs\n    {\n        public GatewayCountChangedEventArgs(int currentNumberOfConnectedGateways, int previousNumberOfConnectedGateways) { }\n\n        public bool ConnectionRecovered { get { throw null; } }\n\n        public int NumberOfConnectedGateways { get { throw null; } }\n\n        public int PreviousNumberOfConnectedGateways { get { throw null; } }\n    }\n\n    public delegate void GatewayCountChangedHandler(object sender, GatewayCountChangedEventArgs e);\n    public partial class GrainInterfaceTypeToGrainTypeResolver\n    {\n        public GrainInterfaceTypeToGrainTypeResolver(Runtime.IClusterManifestProvider clusterManifestProvider) { }\n\n        public Runtime.GrainType GetGrainType(Runtime.GrainInterfaceType interfaceType, string prefix) { throw null; }\n\n        public Runtime.GrainType GetGrainType(Runtime.GrainInterfaceType interfaceType) { throw null; }\n\n        public bool TryGetGrainType(Runtime.GrainInterfaceType interfaceType, out Runtime.GrainType result) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GrainState<T> : IGrainState<T>\n    {\n        public GrainState() { }\n\n        public GrainState(T state, string eTag) { }\n\n        public GrainState(T state) { }\n\n        [Id(1)]\n        public string ETag { get { throw null; } set { } }\n\n        [Id(2)]\n        public bool RecordExists { get { throw null; } set { } }\n\n        [Id(0)]\n        public T State { get { throw null; } set { } }\n    }\n\n    public partial interface IClientConnectionRetryFilter\n    {\n        System.Threading.Tasks.Task<bool> ShouldRetryConnectionAttempt(System.Exception exception, System.Threading.CancellationToken cancellationToken);\n    }\n\n    public partial interface IClusterClient : IGrainFactory\n    {\n        System.IServiceProvider ServiceProvider { get; }\n    }\n\n    public partial interface IClusterClientLifecycle : ILifecycleObservable\n    {\n    }\n\n    public partial interface IClusterConnectionStatusObserver\n    {\n        void NotifyClusterConnectionLost();\n        void NotifyGatewayCountChanged(int currentNumberOfGateways, int previousNumberOfGateways, bool connectionRecovered);\n    }\n\n    public partial interface IGrainState<T>\n    {\n        string ETag { get; set; }\n\n        bool RecordExists { get; set; }\n\n        T State { get; set; }\n    }\n\n    public partial interface IMembershipTable\n    {\n        System.Threading.Tasks.Task CleanupDefunctSiloEntries(System.DateTimeOffset beforeDate);\n        System.Threading.Tasks.Task DeleteMembershipTableEntries(string clusterId);\n        System.Threading.Tasks.Task InitializeMembershipTable(bool tryInitTableVersion);\n        System.Threading.Tasks.Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion);\n        System.Threading.Tasks.Task<MembershipTableData> ReadAll();\n        System.Threading.Tasks.Task<MembershipTableData> ReadRow(Runtime.SiloAddress key);\n        System.Threading.Tasks.Task UpdateIAmAlive(MembershipEntry entry);\n        System.Threading.Tasks.Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion);\n    }\n\n    [Concurrency.Unordered]\n    public partial interface IMembershipTableSystemTarget : IMembershipTable, ISystemTarget, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IOptionFormatter\n    {\n        string Name { get; }\n\n        System.Collections.Generic.IEnumerable<string> Format();\n    }\n\n    public partial interface IOptionFormatterResolver<T>\n    {\n        IOptionFormatter<T> Resolve(string name);\n    }\n\n    public partial interface IOptionFormatter<T> : IOptionFormatter\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public partial class KeepAliveAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public abstract partial class LifecycleSubject : ILifecycleSubject, ILifecycleObservable, ILifecycleObserver\n    {\n        protected readonly Microsoft.Extensions.Logging.ILogger Logger;\n        protected LifecycleSubject(Microsoft.Extensions.Logging.ILogger logger) { }\n\n        protected virtual System.Threading.Tasks.Task CallObserverStopAsync(ILifecycleObserver observer, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        protected virtual string GetStageName(int stage) { throw null; }\n\n        protected static System.Collections.Immutable.ImmutableDictionary<int, string> GetStageNames(System.Type type) { throw null; }\n\n        public virtual System.Threading.Tasks.Task OnStart(System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n        protected virtual void OnStartStageCompleted(int stage) { }\n\n        public virtual System.Threading.Tasks.Task OnStop(System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n        protected virtual void OnStopStageCompleted(int stage) { }\n\n        protected virtual void PerfMeasureOnStart(int stage, System.TimeSpan elapsed) { }\n\n        protected virtual void PerfMeasureOnStop(int stage, System.TimeSpan elapsed) { }\n\n        public virtual System.IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class MembershipEntry\n    {\n        [Id(8)]\n        public int FaultZone { get { throw null; } set { } }\n\n        [Id(4)]\n        public string HostName { get { throw null; } set { } }\n\n        [Id(10)]\n        public System.DateTime IAmAliveTime { get { throw null; } set { } }\n\n        [Id(3)]\n        public int ProxyPort { get { throw null; } set { } }\n\n        [Id(6)]\n        public string RoleName { get { throw null; } set { } }\n\n        [Id(0)]\n        public Runtime.SiloAddress SiloAddress { get { throw null; } set { } }\n\n        [Id(5)]\n        public string SiloName { get { throw null; } set { } }\n\n        [Id(9)]\n        public System.DateTime StartTime { get { throw null; } set { } }\n\n        [Id(1)]\n        public Runtime.SiloStatus Status { get { throw null; } set { } }\n\n        [Id(2)]\n        public System.Collections.Generic.List<System.Tuple<Runtime.SiloAddress, System.DateTime>> SuspectTimes { get { throw null; } set { } }\n\n        [Id(7)]\n        public int UpdateZone { get { throw null; } set { } }\n\n        public void AddOrUpdateSuspector(Runtime.SiloAddress localSilo, System.DateTime voteTime, int maxVotes) { }\n\n        public void AddSuspector(Runtime.SiloAddress suspectingSilo, System.DateTime suspectingTime) { }\n\n        public string ToFullString() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class MembershipTableData\n    {\n        public MembershipTableData(TableVersion version) { }\n\n        public MembershipTableData(System.Collections.Generic.List<System.Tuple<MembershipEntry, string>> list, TableVersion version) { }\n\n        public MembershipTableData(System.Tuple<MembershipEntry, string> tuple, TableVersion version) { }\n\n        [Id(0)]\n        public System.Collections.Generic.IReadOnlyList<System.Tuple<MembershipEntry, string>> Members { get { throw null; } }\n\n        [Id(1)]\n        public TableVersion Version { get { throw null; } }\n\n        public override string ToString() { throw null; }\n\n        public System.Tuple<MembershipEntry, string> TryGet(Runtime.SiloAddress silo) { throw null; }\n\n        public MembershipTableData WithoutDuplicateDeads() { throw null; }\n    }\n\n    public static partial class NamedOptionExtensions\n    {\n        public static TOption GetOptionsByName<TOption>(this System.IServiceProvider services, string name)\n            where TOption : class, new() { throw null; }\n    }\n\n    public static partial class OptionFormattingUtilities\n    {\n        public static string Format(object key, object value, string formatting = null) { throw null; }\n\n        public static string Name<TOptions>(string name = null, string formatting = null) { throw null; }\n    }\n\n    public abstract partial class OptionsLogger\n    {\n        protected OptionsLogger(Microsoft.Extensions.Logging.ILogger logger, System.IServiceProvider services) { }\n\n        public void LogOption(IOptionFormatter formatter) { }\n\n        public void LogOptions() { }\n\n        public void LogOptions(System.Collections.Generic.IEnumerable<IOptionFormatter> formatters) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]\n    public partial class RedactAttribute : System.Attribute\n    {\n        public virtual string Redact(object value) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]\n    public partial class RedactConnectionStringAttribute : RedactAttribute\n    {\n        public override string Redact(object value) { throw null; }\n    }\n\n    public partial class SerializerConfigurationValidator : IConfigurationValidator\n    {\n        public SerializerConfigurationValidator(Serialization.Serializers.ICodecProvider codecProvider, Microsoft.Extensions.Options.IOptions<Serialization.Configuration.TypeManifestOptions> options, System.IServiceProvider serviceProvider) { }\n\n        void IConfigurationValidator.ValidateConfiguration() { }\n    }\n\n    public static partial class ServiceLifecycleStage\n    {\n        public const int Active = 20000;\n        public const int AfterRuntimeGrainServices = 8100;\n        public const int ApplicationServices = 10000;\n        public const int BecomeActive = 19999;\n        public const int First = int.MinValue;\n        public const int Last = int.MaxValue;\n        public const int RuntimeGrainServices = 8000;\n        public const int RuntimeInitialize = 2000;\n        public const int RuntimeServices = 4000;\n        public const int RuntimeStorageServices = 6000;\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class TableVersion : System.ISpanFormattable, System.IFormattable, System.IEquatable<TableVersion>\n    {\n        public TableVersion(int version, string eTag) { }\n\n        [Id(0)]\n        public int Version { get { throw null; } }\n\n        [Id(1)]\n        public string VersionEtag { get { throw null; } }\n\n        public bool Equals(TableVersion other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public TableVersion Next() { throw null; }\n\n        public static bool operator ==(TableVersion left, TableVersion right) { throw null; }\n\n        public static bool operator !=(TableVersion left, TableVersion right) { throw null; }\n\n        string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider provider) { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class ClientConnectionOptions\n    {\n        public void ConfigureConnection(System.Action<Microsoft.AspNetCore.Connections.IConnectionBuilder> configure) { }\n    }\n\n    public partial class ClientMessagingOptions : MessagingOptions\n    {\n        public const int DEFAULT_CLIENT_SENDER_BUCKETS = 8192;\n        public const System.Net.Sockets.AddressFamily DEFAULT_PREFERRED_FAMILY = 2;\n        public int ClientSenderBuckets { get { throw null; } set { } }\n\n        public System.Net.IPAddress LocalAddress { get { throw null; } set { } }\n\n        public string NetworkInterfaceName { get { throw null; } set { } }\n\n        public System.Net.Sockets.AddressFamily PreferredFamily { get { throw null; } set { } }\n    }\n\n    public partial class ClusterMembershipOptions\n    {\n        public System.TimeSpan DeathVoteExpirationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan? DefunctSiloCleanupPeriod { get { throw null; } set { } }\n\n        public System.TimeSpan DefunctSiloExpiration { get { throw null; } set { } }\n\n        public bool EnableIndirectProbes { get { throw null; } set { } }\n\n        public bool EvictWhenMaxJoinAttemptTimeExceeded { get { throw null; } set { } }\n\n        public bool ExtendProbeTimeoutDuringDegradation { get { throw null; } set { } }\n\n        public System.TimeSpan IAmAliveTablePublishTimeout { get { throw null; } set { } }\n\n        public bool LivenessEnabled { get { throw null; } set { } }\n\n        public System.TimeSpan LocalHealthDegradationMonitoringPeriod { get { throw null; } set { } }\n\n        public System.TimeSpan MaxJoinAttemptTime { get { throw null; } set { } }\n\n        public int NumMissedProbesLimit { get { throw null; } set { } }\n\n        public int NumMissedTableIAmAliveLimit { get { throw null; } set { } }\n\n        public int NumProbedSilos { get { throw null; } set { } }\n\n        public int NumVotesForDeathDeclaration { get { throw null; } set { } }\n\n        public System.TimeSpan ProbeTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan TableRefreshTimeout { get { throw null; } set { } }\n\n        public bool UseLivenessGossip { get { throw null; } set { } }\n    }\n\n    public partial class ClusterOptions\n    {\n        public const string DefaultClusterId = \"default\";\n        public const string DefaultServiceId = \"default\";\n        public string ClusterId { get { throw null; } set { } }\n\n        public string ServiceId { get { throw null; } set { } }\n    }\n\n    public partial class ClusterOptionsValidator : IConfigurationValidator\n    {\n        public ClusterOptionsValidator(Microsoft.Extensions.Options.IOptions<ClusterOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class ConnectionOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_OPENCONNECTION_TIMEOUT;\n        public System.TimeSpan ConnectionRetryDelay { get { throw null; } set { } }\n\n        public int ConnectionsPerEndpoint { get { throw null; } set { } }\n\n        public System.TimeSpan OpenConnectionTimeout { get { throw null; } set { } }\n\n        public Runtime.Messaging.NetworkProtocolVersion ProtocolVersion { get { throw null; } set { } }\n    }\n\n    public partial class GatewayOptions\n    {\n        public const int DEFAULT_PREFERED_GATEWAY_INDEX = -1;\n        public System.TimeSpan GatewayListRefreshPeriod { get { throw null; } set { } }\n\n        public int PreferredGatewayIndex { get { throw null; } set { } }\n    }\n\n    public partial class GrainTypeOptions\n    {\n        public System.Collections.Generic.HashSet<System.Type> Classes { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> Interfaces { get { throw null; } }\n    }\n\n    public sealed partial class GrainTypeOptionsValidator : IConfigurationValidator\n    {\n        public GrainTypeOptionsValidator(Microsoft.Extensions.Options.IOptions<GrainTypeOptions> options, System.IServiceProvider serviceProvider) { }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class GrainVersioningOptions\n    {\n        public string DefaultCompatibilityStrategy { get { throw null; } set { } }\n\n        public string DefaultVersionSelectorStrategy { get { throw null; } set { } }\n    }\n\n    public partial class LoadSheddingOptions\n    {\n        public int CpuThreshold { get { throw null; } set { } }\n\n        public bool LoadSheddingEnabled { get { throw null; } set { } }\n\n        [System.Obsolete(\"Use CpuThreshold instead.\", true)]\n        public int LoadSheddingLimit { get { throw null; } set { } }\n\n        public int MemoryThreshold { get { throw null; } set { } }\n    }\n\n    public abstract partial class MessagingOptions\n    {\n        public bool CancelRequestOnTimeout { get { throw null; } set { } }\n\n        public bool DropExpiredMessages { get { throw null; } set { } }\n\n        public int MaxMessageBodySize { get { throw null; } set { } }\n\n        public int MaxMessageHeaderSize { get { throw null; } set { } }\n\n        public System.TimeSpan ResponseTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan ResponseTimeoutWithDebugger { get { throw null; } set { } }\n\n        public bool WaitForCancellationAcknowledgement { get { throw null; } set { } }\n    }\n\n    public static partial class OptionConfigureExtensionMethods\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureFormatter<TOptions>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TOptions : class, new() { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureFormatter<TOptions, TOptionFormatter>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TOptions : class where TOptionFormatter : class, IOptionFormatter<TOptions> { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureFormatterResolver<TOptions, TOptionFormatterResolver>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TOptions : class where TOptionFormatterResolver : class, IOptionFormatterResolver<TOptions> { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureNamedOptionForLogging<TOptions>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name)\n            where TOptions : class { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection TryConfigureFormatter<TOptions, TOptionFormatter>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TOptions : class where TOptionFormatter : class, IOptionFormatter<TOptions> { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection TryConfigureFormatterResolver<TOptions, TOptionFormatterResolver>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TOptions : class where TOptionFormatterResolver : class, IOptionFormatterResolver<TOptions> { throw null; }\n    }\n\n    public partial class StaticGatewayListProviderOptions\n    {\n        public System.Collections.Generic.List<System.Uri> Gateways { get { throw null; } set { } }\n    }\n\n    public partial class TypeManagementOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_REFRESH_CLUSTER_INTERFACEMAP_TIME;\n        public System.TimeSpan TypeMapRefreshInterval { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Configuration.Internal\n{\n    public static partial class ServiceCollectionExtensions\n    {\n        public static void AddFromExisting(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Type service, System.Type implementation) { }\n\n        public static void AddFromExisting<TService, TImplementation>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TImplementation : TService { }\n\n        public static void TryAddFromExisting<TService, TImplementation>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TImplementation : TService { }\n    }\n}\n\nnamespace Orleans.Configuration.Overrides\n{\n    public static partial class OptionsOverrides\n    {\n        public static Microsoft.Extensions.Options.IOptions<ClusterOptions> GetProviderClusterOptions(this System.IServiceProvider services, string providerName) { throw null; }\n    }\n}\n\nnamespace Orleans.GrainDirectory\n{\n    public partial interface IGrainLocator\n    {\n        void InvalidateCache(Runtime.GrainAddress address);\n        void InvalidateCache(Runtime.GrainId grainId);\n        System.Threading.Tasks.ValueTask<Runtime.GrainAddress?> Lookup(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address, Runtime.GrainAddress? previousRegistration);\n        bool TryLookupInCache(Runtime.GrainId grainId, out Runtime.GrainAddress? address);\n        System.Threading.Tasks.Task Unregister(Runtime.GrainAddress address, UnregistrationCause cause);\n        void UpdateCache(Runtime.GrainId grainId, Runtime.SiloAddress siloAddress);\n    }\n\n    public enum UnregistrationCause : byte\n    {\n        Force = 0,\n        NonexistentActivation = 1\n    }\n}\n\nnamespace Orleans.GrainReferences\n{\n    public sealed partial class GrainReferenceActivator\n    {\n        public GrainReferenceActivator(System.IServiceProvider serviceProvider, System.Collections.Generic.IEnumerable<IGrainReferenceActivatorProvider> providers) { }\n\n        public Runtime.GrainReference CreateReference(Runtime.GrainId grainId, Runtime.GrainInterfaceType interfaceType) { throw null; }\n    }\n\n    public partial interface IGrainReferenceActivator\n    {\n        Runtime.GrainReference CreateReference(Runtime.GrainId grainId);\n    }\n\n    public partial interface IGrainReferenceActivatorProvider\n    {\n        bool TryGet(Runtime.GrainType grainType, Runtime.GrainInterfaceType interfaceType, out IGrainReferenceActivator activator);\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public partial class ClientBuilder : IClientBuilder\n    {\n        public ClientBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollection services, Microsoft.Extensions.Configuration.IConfiguration configuration) { }\n\n        public Microsoft.Extensions.Configuration.IConfiguration Configuration { get { throw null; } }\n\n        public Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get { throw null; } }\n    }\n\n    public static partial class ClientBuilderExtensions\n    {\n        public static IClientBuilder AddActivityPropagation(this IClientBuilder builder) { throw null; }\n\n        public static IClientBuilder AddClusterConnectionLostHandler(this IClientBuilder builder, ConnectionToClusterLostHandler handler) { throw null; }\n\n        public static IClientBuilder AddClusterConnectionLostHandler(this IClientBuilder builder, System.Func<System.IServiceProvider, ConnectionToClusterLostHandler> handlerFactory) { throw null; }\n\n        public static IClientBuilder AddClusterConnectionStatusObserver<TObserver>(this IClientBuilder builder, TObserver observer)\n            where TObserver : IClusterConnectionStatusObserver { throw null; }\n\n        public static IClientBuilder AddClusterConnectionStatusObserver<TObserver>(this IClientBuilder builder)\n            where TObserver : class, IClusterConnectionStatusObserver { throw null; }\n\n        public static IClientBuilder AddGatewayCountChangedHandler(this IClientBuilder builder, GatewayCountChangedHandler handler) { throw null; }\n\n        public static IClientBuilder AddGatewayCountChangedHandler(this IClientBuilder builder, System.Func<System.IServiceProvider, GatewayCountChangedHandler> handlerFactory) { throw null; }\n\n        public static IClientBuilder Configure<TOptions>(this IClientBuilder builder, Microsoft.Extensions.Configuration.IConfiguration configuration)\n            where TOptions : class { throw null; }\n\n        public static IClientBuilder Configure<TOptions>(this IClientBuilder builder, System.Action<TOptions> configureOptions)\n            where TOptions : class { throw null; }\n\n        public static IClientBuilder ConfigureServices(this IClientBuilder builder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> configureDelegate) { throw null; }\n\n        public static IClientBuilder UseConnectionRetryFilter(this IClientBuilder builder, IClientConnectionRetryFilter connectionRetryFilter) { throw null; }\n\n        public static IClientBuilder UseConnectionRetryFilter(this IClientBuilder builder, System.Func<System.Exception, System.Threading.CancellationToken, System.Threading.Tasks.Task<bool>> connectionRetryFilter) { throw null; }\n\n        public static IClientBuilder UseConnectionRetryFilter<TConnectionRetryFilter>(this IClientBuilder builder)\n            where TConnectionRetryFilter : class, IClientConnectionRetryFilter { throw null; }\n\n        public static IClientBuilder UseLocalhostClustering(this IClientBuilder builder, int gatewayPort = 30000, string serviceId = \"dev\", string clusterId = \"dev\") { throw null; }\n\n        public static IClientBuilder UseLocalhostClustering(this IClientBuilder builder, int[] gatewayPorts, string serviceId = \"dev\", string clusterId = \"dev\") { throw null; }\n\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StaticGatewayListProviderOptions>> configureOptions) { throw null; }\n\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, System.Action<Configuration.StaticGatewayListProviderOptions> configureOptions) { throw null; }\n\n        public static IClientBuilder UseStaticClustering(this IClientBuilder builder, params System.Net.IPEndPoint[] endpoints) { throw null; }\n    }\n\n    public static partial class ClientBuilderGrainCallFilterExtensions\n    {\n        public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IIncomingGrainCallFilter filter) { throw null; }\n\n        public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IncomingGrainCallFilterDelegate filter) { throw null; }\n\n        public static IClientBuilder AddIncomingGrainCallFilter<TImplementation>(this IClientBuilder builder)\n            where TImplementation : class, IIncomingGrainCallFilter { throw null; }\n\n        public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, IOutgoingGrainCallFilter filter) { throw null; }\n\n        public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, OutgoingGrainCallFilterDelegate filter) { throw null; }\n\n        public static IClientBuilder AddOutgoingGrainCallFilter<TImplementation>(this IClientBuilder builder)\n            where TImplementation : class, IOutgoingGrainCallFilter { throw null; }\n    }\n\n    public static partial class GrainCallFilterServiceCollectionExtensions\n    {\n        [System.Obsolete(\"Use ISiloBuilder.AddIncomingGrainCallFilter\", true)]\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainCallFilter(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, GrainCallFilterDelegate filter) { throw null; }\n\n        [System.Obsolete(\"Use ISiloBuilder.AddIncomingGrainCallFilter\", true)]\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainCallFilter(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, IIncomingGrainCallFilter filter) { throw null; }\n\n        [System.Obsolete(\"Use ISiloBuilder.AddIncomingGrainCallFilter\", true)]\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainCallFilter<TImplementation>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TImplementation : class, IIncomingGrainCallFilter { throw null; }\n    }\n\n    public partial interface IClientBuilder\n    {\n        Microsoft.Extensions.Configuration.IConfiguration Configuration { get; }\n\n        Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }\n    }\n\n    public partial interface INamedServiceConfigurator\n    {\n        System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> ConfigureDelegate { get; }\n\n        string Name { get; }\n    }\n\n    public partial class NamedServiceConfigurator : INamedServiceConfigurator\n    {\n        public NamedServiceConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureDelegate) { }\n\n        public System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> ConfigureDelegate { get { throw null; } }\n\n        public string Name { get { throw null; } }\n    }\n\n    public static partial class NamedServiceConfiguratorExtensions\n    {\n        public static void Configure<TOptions>(this INamedServiceConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new() { }\n\n        public static void ConfigureComponent<TComponent>(this INamedServiceConfigurator configurator, System.Func<System.IServiceProvider, string, TComponent> factory)\n            where TComponent : class { }\n\n        public static void ConfigureComponent<TOptions, TComponent>(this INamedServiceConfigurator configurator, System.Func<System.IServiceProvider, string, TComponent> factory, System.Action<Microsoft.Extensions.Options.OptionsBuilder<TOptions>> configureOptions = null)\n            where TOptions : class, new()\n            where TComponent : class { }\n\n        public static void ConfigureLifecycle<T>(this INamedServiceConfigurator configurator)\n            where T : ILifecycleSubject { }\n    }\n}\n\nnamespace Orleans.Internal\n{\n    public static partial class AsyncExecutorWithRetries\n    {\n        public static readonly int INFINITE_RETRIES;\n        public static System.Threading.Tasks.Task ExecuteWithRetries(System.Func<int, System.Threading.Tasks.Task> action, int maxNumErrorTries, System.Func<System.Exception, int, bool> retryExceptionFilter, System.TimeSpan maxExecutionTime, IBackoffProvider onErrorBackOff) { throw null; }\n\n        public static System.Threading.Tasks.Task<T> ExecuteWithRetries<T>(System.Func<int, System.Threading.Tasks.Task<T>> function, int maxNumErrorTries, System.Func<System.Exception, int, bool> retryExceptionFilter, System.TimeSpan maxExecutionTime, IBackoffProvider onErrorBackOff, System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n        public static System.Threading.Tasks.Task<T> ExecuteWithRetries<T>(System.Func<int, System.Threading.Tasks.Task<T>> function, int maxNumSuccessTries, int maxNumErrorTries, System.Func<T, int, bool> retryValueFilter, System.Func<System.Exception, int, bool> retryExceptionFilter, System.TimeSpan maxExecutionTime = default, IBackoffProvider onSuccessBackOff = null, IBackoffProvider onErrorBackOff = null, System.Threading.CancellationToken cancellationToken = default) { throw null; }\n    }\n\n    public partial class FixedBackoff : IBackoffProvider\n    {\n        public FixedBackoff(System.TimeSpan delay) { }\n\n        public System.TimeSpan Next(int attempt) { throw null; }\n    }\n\n    public partial interface IBackoffProvider\n    {\n        System.TimeSpan Next(int attempt);\n    }\n}\n\nnamespace Orleans.LeaseProviders\n{\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class AcquiredLease\n    {\n        public AcquiredLease(string resourceKey, System.TimeSpan duration, string token, System.DateTime startTimeUtc) { }\n\n        public AcquiredLease(string resourceKey) { }\n\n        [Id(1)]\n        public System.TimeSpan Duration { get { throw null; } }\n\n        [Id(0)]\n        public string ResourceKey { get { throw null; } }\n\n        [Id(3)]\n        public System.DateTime StartTimeUtc { get { throw null; } }\n\n        [Id(2)]\n        public string Token { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class AcquireLeaseResult\n    {\n        public AcquireLeaseResult(AcquiredLease acquiredLease, ResponseCode statusCode, System.Exception failureException) { }\n\n        [Id(0)]\n        public AcquiredLease AcquiredLease { get { throw null; } }\n\n        [Id(2)]\n        public System.Exception FailureException { get { throw null; } }\n\n        [Id(1)]\n        public ResponseCode StatusCode { get { throw null; } }\n    }\n\n    public partial interface ILeaseProvider\n    {\n        System.Threading.Tasks.Task<AcquireLeaseResult[]> Acquire(string category, LeaseRequest[] leaseRequests);\n        System.Threading.Tasks.Task Release(string category, AcquiredLease[] aquiredLeases);\n        System.Threading.Tasks.Task<AcquireLeaseResult[]> Renew(string category, AcquiredLease[] aquiredLeases);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class LeaseRequest\n    {\n        public LeaseRequest(string resourceKey, System.TimeSpan duration) { }\n\n        [Id(1)]\n        public System.TimeSpan Duration { get { throw null; } }\n\n        [Id(0)]\n        public string ResourceKey { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    public enum ResponseCode\n    {\n        OK = 0,\n        LeaseNotAvailable = 1,\n        InvalidToken = 2,\n        TransientFailure = 3\n    }\n}\n\nnamespace Orleans.Messaging\n{\n    public partial interface IGatewayListProvider\n    {\n        [System.Obsolete(\"This attribute is no longer used and all providers are considered updatable\")]\n        bool IsUpdatable { get; }\n\n        System.TimeSpan MaxStaleness { get; }\n\n        System.Threading.Tasks.Task<System.Collections.Generic.IList<System.Uri>> GetGateways();\n        System.Threading.Tasks.Task InitializeGatewayListProvider();\n    }\n\n    public partial class StaticGatewayListProvider : IGatewayListProvider\n    {\n        public StaticGatewayListProvider(Microsoft.Extensions.Options.IOptions<Configuration.StaticGatewayListProviderOptions> options, Microsoft.Extensions.Options.IOptions<Configuration.GatewayOptions> gatewayOptions) { }\n\n        public bool IsUpdatable { get { throw null; } }\n\n        public System.TimeSpan MaxStaleness { get { throw null; } }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.IList<System.Uri>> GetGateways() { throw null; }\n\n        public System.Threading.Tasks.Task InitializeGatewayListProvider() { throw null; }\n    }\n}\n\nnamespace Orleans.Metadata\n{\n    public partial class GrainBindings\n    {\n        public GrainBindings(Runtime.GrainType grainType, System.Collections.Immutable.ImmutableArray<System.Collections.Immutable.ImmutableDictionary<string, string>> bindings) { }\n\n        public System.Collections.Immutable.ImmutableArray<System.Collections.Immutable.ImmutableDictionary<string, string>> Bindings { get { throw null; } }\n\n        public Runtime.GrainType GrainType { get { throw null; } }\n    }\n\n    public partial class GrainBindingsResolver\n    {\n        public GrainBindingsResolver(Runtime.IClusterManifestProvider clusterManifestProvider) { }\n\n        public (MajorMinorVersion Version, System.Collections.Immutable.ImmutableDictionary<Runtime.GrainType, GrainBindings> Bindings) GetAllBindings() { throw null; }\n\n        public GrainBindings GetBindings(Runtime.GrainType grainType) { throw null; }\n    }\n\n    public partial class GrainInterfaceTypeResolver\n    {\n        public GrainInterfaceTypeResolver(System.Collections.Generic.IEnumerable<Runtime.IGrainInterfaceTypeProvider> providers, Serialization.TypeSystem.TypeConverter typeConverter) { }\n\n        public Runtime.GrainInterfaceType GetGrainInterfaceType(System.Type type) { throw null; }\n\n        public Runtime.GrainInterfaceType GetGrainInterfaceTypeByConvention(System.Type type) { throw null; }\n    }\n\n    public partial class GrainPropertiesResolver\n    {\n        public GrainPropertiesResolver(Runtime.IClusterManifestProvider clusterManifestProvider) { }\n\n        public GrainProperties GetGrainProperties(Runtime.GrainType grainType) { throw null; }\n\n        public bool TryGetGrainProperties(Runtime.GrainType grainType, out GrainProperties properties) { throw null; }\n    }\n\n    public partial class GrainTypeResolver\n    {\n        public GrainTypeResolver(System.Collections.Generic.IEnumerable<IGrainTypeProvider> resolvers, Serialization.TypeSystem.TypeConverter argumentFormatter) { }\n\n        public Runtime.GrainType GetGrainType(System.Type type) { throw null; }\n    }\n}\n\nnamespace Orleans.Networking.Shared\n{\n    [GenerateSerializer]\n    public sealed partial class SocketConnectionException : Runtime.OrleansException\n    {\n        [System.Obsolete]\n        public SocketConnectionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public SocketConnectionException(string message, System.Exception innerException) { }\n\n        public SocketConnectionException(string message) { }\n    }\n\n    public partial class SocketConnectionOptions\n    {\n        public int IOQueueCount { get { throw null; } set { } }\n\n        public bool KeepAlive { get { throw null; } set { } }\n\n        public int KeepAliveIntervalSeconds { get { throw null; } set { } }\n\n        public int KeepAliveRetryCount { get { throw null; } set { } }\n\n        public int KeepAliveTimeSeconds { get { throw null; } set { } }\n\n        public bool NoDelay { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Placement\n{\n    public partial interface IPlacementFilterDirector\n    {\n        System.Collections.Generic.IEnumerable<Runtime.SiloAddress> Filter(PlacementFilterStrategy filterStrategy, Runtime.Placement.PlacementTarget target, System.Collections.Generic.IEnumerable<Runtime.SiloAddress> silos);\n    }\n\n    public static partial class PlacementFilterExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddPlacementFilter<TFilter, TDirector>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, Microsoft.Extensions.DependencyInjection.ServiceLifetime strategyLifetime)\n            where TFilter : PlacementFilterStrategy, new()\n            where TDirector : class, IPlacementFilterDirector { throw null; }\n    }\n}\n\nnamespace Orleans.Placement.Rebalancing\n{\n    public partial interface IActivationRebalancer\n    {\n        System.Threading.Tasks.ValueTask<RebalancingReport> GetRebalancingReport(bool force = false);\n        System.Threading.Tasks.Task ResumeRebalancing();\n        void SubscribeToReports(IActivationRebalancerReportListener listener);\n        System.Threading.Tasks.Task SuspendRebalancing(System.TimeSpan? duration = null);\n        void UnsubscribeFromReports(IActivationRebalancerReportListener listener);\n    }\n\n    public partial interface IActivationRebalancerReportListener\n    {\n        void OnReport(RebalancingReport report);\n    }\n\n    public partial interface IFailedSessionBackoffProvider : Internal.IBackoffProvider\n    {\n    }\n\n    [GenerateSerializer]\n    public enum RebalancerStatus : byte\n    {\n        Executing = 0,\n        Suspended = 1\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [Alias(\"RebalancingReport\")]\n    public readonly partial struct RebalancingReport\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        [Id(3)]\n        public required double ClusterImbalance { get { throw null; } init { } }\n\n        [Id(0)]\n        public required Runtime.SiloAddress Host { get { throw null; } init { } }\n\n        [Id(4)]\n        public required System.Collections.Immutable.ImmutableArray<RebalancingStatistics> Statistics { get { throw null; } init { } }\n\n        [Id(1)]\n        public required RebalancerStatus Status { get { throw null; } init { } }\n\n        [Id(2)]\n        public System.TimeSpan? SuspensionDuration { get { throw null; } init { } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [Alias(\"RebalancingStatistics\")]\n    public readonly partial struct RebalancingStatistics\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        [Id(3)]\n        public required ulong AcquiredActivations { get { throw null; } init { } }\n\n        [Id(2)]\n        public required ulong DispersedActivations { get { throw null; } init { } }\n\n        [Id(1)]\n        public required Runtime.SiloAddress SiloAddress { get { throw null; } init { } }\n\n        [Id(0)]\n        public required System.DateTime TimeStamp { get { throw null; } init { } }\n    }\n}\n\nnamespace Orleans.Placement.Repartitioning\n{\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct CandidateConnectedVertex\n    {\n        private readonly int _dummyPrimitive;\n        public CandidateConnectedVertex(Runtime.GrainId id, long transferScore) { }\n\n        [Id(0)]\n        public Runtime.GrainId Id { get { throw null; } }\n\n        [Id(1)]\n        public long TransferScore { get { throw null; } }\n\n        public readonly bool Equals(CandidateConnectedVertex other) { throw null; }\n\n        public override readonly bool Equals(object obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(CandidateConnectedVertex left, CandidateConnectedVertex right) { throw null; }\n\n        public static bool operator !=(CandidateConnectedVertex left, CandidateConnectedVertex right) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct EdgeVertex : System.IEquatable<EdgeVertex>\n    {\n        [Id(0)]\n        public readonly Runtime.GrainId Id;\n        [Id(2)]\n        public readonly bool IsMigratable;\n        [Id(1)]\n        public readonly Runtime.SiloAddress Silo;\n        public EdgeVertex(Runtime.GrainId id, Runtime.SiloAddress silo, bool isMigratable) { }\n\n        public readonly bool Equals(EdgeVertex other) { throw null; }\n\n        public override readonly bool Equals(object obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(EdgeVertex left, EdgeVertex right) { throw null; }\n\n        public static bool operator !=(EdgeVertex left, EdgeVertex right) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public partial interface IImbalanceToleranceRule\n    {\n        bool IsSatisfiedBy(uint imbalance);\n    }\n}\n\nnamespace Orleans.Providers\n{\n    public partial interface IControllable\n    {\n        System.Threading.Tasks.Task<object> ExecuteCommand(int command, object arg);\n    }\n\n    public partial interface IProviderRuntime\n    {\n        IGrainFactory GrainFactory { get; }\n\n        System.IServiceProvider ServiceProvider { get; }\n\n        (TExtension Extension, TExtensionInterface ExtensionReference) BindExtension<TExtension, TExtensionInterface>(System.Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface where TExtensionInterface : class, Runtime.IGrainExtension;\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ProviderInitializationException : Runtime.OrleansException\n    {\n        public ProviderInitializationException() { }\n\n        public ProviderInitializationException(string message, System.Exception innerException) { }\n\n        public ProviderInitializationException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ProviderStateException : Runtime.OrleansException\n    {\n        public ProviderStateException() { }\n\n        public ProviderStateException(string message, System.Exception innerException) { }\n\n        public ProviderStateException(string message) { }\n    }\n}\n\nnamespace Orleans.Runtime\n{\n    public static partial class ClientInstruments\n    {\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public partial class ClusterManifestUpdate\n    {\n        public ClusterManifestUpdate(Metadata.MajorMinorVersion manifestVersion, System.Collections.Immutable.ImmutableDictionary<SiloAddress, Metadata.GrainManifest> siloManifests, bool includesAllActiveServers) { }\n\n        [Id(2)]\n        public bool IncludesAllActiveServers { get { throw null; } }\n\n        [Id(1)]\n        public System.Collections.Immutable.ImmutableDictionary<SiloAddress, Metadata.GrainManifest> SiloManifests { get { throw null; } }\n\n        [Id(0)]\n        public Metadata.MajorMinorVersion Version { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class DetailedGrainStatistic\n    {\n        [Id(2)]\n        public GrainId GrainId { get { throw null; } init { } }\n\n        [Id(0)]\n        public string GrainType { get { throw null; } init { } }\n\n        [Id(1)]\n        public SiloAddress SiloAddress { get { throw null; } init { } }\n    }\n\n    [Immutable]\n    public readonly partial struct GenericGrainInterfaceType\n    {\n        private readonly int _dummyPrimitive;\n        public int Arity { get { throw null; } }\n\n        public bool IsConstructed { get { throw null; } }\n\n        public GrainInterfaceType Value { get { throw null; } }\n\n        public readonly GenericGrainInterfaceType Construct(Orleans.Serialization.TypeSystem.TypeConverter formatter, params System.Type[] typeArguments) { throw null; }\n\n        public readonly System.Type[] GetArguments(Orleans.Serialization.TypeSystem.TypeConverter formatter) { throw null; }\n\n        public readonly GenericGrainInterfaceType GetGenericGrainType() { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        public static bool TryParse(GrainInterfaceType grainType, out GenericGrainInterfaceType result) { throw null; }\n    }\n\n    [Immutable]\n    public readonly partial struct GenericGrainType : System.IEquatable<GenericGrainType>\n    {\n        private readonly int _dummyPrimitive;\n        public int Arity { get { throw null; } }\n\n        public GrainType GrainType { get { throw null; } }\n\n        public bool IsConstructed { get { throw null; } }\n\n        public readonly GenericGrainType Construct(Orleans.Serialization.TypeSystem.TypeConverter formatter, params System.Type[] typeArguments) { throw null; }\n\n        public readonly bool Equals(GenericGrainType other) { throw null; }\n\n        public override readonly bool Equals(object obj) { throw null; }\n\n        public readonly System.Type[] GetArguments(Orleans.Serialization.TypeSystem.TypeConverter converter) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly GenericGrainType GetUnconstructedGrainType() { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        public static bool TryParse(GrainType grainType, out GenericGrainType result) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Alias(\"Orleans.Runtime.GrainCallFrequency\")]\n    [Immutable]\n    public partial struct GrainCallFrequency\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        [Id(4)]\n        public ulong CallCount { get { throw null; } set { } }\n\n        [Id(0)]\n        public GrainId SourceGrain { get { throw null; } set { } }\n\n        [Id(2)]\n        public SiloAddress SourceHost { get { throw null; } set { } }\n\n        [Id(1)]\n        public GrainId TargetGrain { get { throw null; } set { } }\n\n        [Id(3)]\n        public SiloAddress TargetHost { get { throw null; } set { } }\n    }\n\n    public partial interface IClusterManifestProvider\n    {\n        Metadata.ClusterManifest Current { get; }\n\n        Metadata.GrainManifest LocalGrainManifest { get; }\n\n        System.Collections.Generic.IAsyncEnumerable<Metadata.ClusterManifest> Updates { get; }\n    }\n\n    public partial interface IHealthCheckable\n    {\n        bool CheckHealth(System.DateTime lastCheckTime, out string reason);\n    }\n\n    public partial interface ILocalSiloDetails\n    {\n        string ClusterId { get; }\n\n        string DnsHostName { get; }\n\n        SiloAddress GatewayAddress { get; }\n\n        string Name { get; }\n\n        SiloAddress SiloAddress { get; }\n    }\n\n    public partial interface IManagementGrain : IGrainWithIntegerKey, IGrain, IAddressable, IVersionManager\n    {\n        System.Threading.Tasks.Task ForceActivationCollection(SiloAddress[] hostsIds, System.TimeSpan ageLimit);\n        System.Threading.Tasks.Task ForceActivationCollection(System.TimeSpan ageLimit);\n        System.Threading.Tasks.Task ForceGarbageCollection(SiloAddress[] hostsIds);\n        System.Threading.Tasks.Task ForceRuntimeStatisticsCollection(SiloAddress[] siloAddresses);\n        System.Threading.Tasks.ValueTask<SiloAddress> GetActivationAddress(IAddressable reference);\n        System.Threading.Tasks.ValueTask<System.Collections.Generic.List<GrainId>> GetActiveGrains(GrainType type);\n        System.Threading.Tasks.Task<DetailedGrainStatistic[]> GetDetailedGrainStatistics(string[] types = null, SiloAddress[] hostsIds = null);\n        System.Threading.Tasks.Task<MembershipEntry[]> GetDetailedHosts(bool onlyActive = false);\n        System.Threading.Tasks.Task<int> GetGrainActivationCount(GrainReference grainReference);\n        System.Threading.Tasks.Task<System.Collections.Generic.List<GrainCallFrequency>> GetGrainCallFrequencies(SiloAddress[] hostsIds = null);\n        System.Threading.Tasks.Task<System.Collections.Generic.Dictionary<SiloAddress, SiloStatus>> GetHosts(bool onlyActive = false);\n        System.Threading.Tasks.Task<SiloRuntimeStatistics[]> GetRuntimeStatistics(SiloAddress[] hostsIds);\n        System.Threading.Tasks.Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics();\n        System.Threading.Tasks.Task<SimpleGrainStatistic[]> GetSimpleGrainStatistics(SiloAddress[] hostsIds);\n        System.Threading.Tasks.Task<int> GetTotalActivationCount();\n        System.Threading.Tasks.ValueTask ResetGrainCallFrequencies(SiloAddress[] hostsIds = null);\n        System.Threading.Tasks.Task<object[]> SendControlCommandToProvider<T>(string providerName, int command, object arg = null)\n            where T : Providers.IControllable;\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct IndirectProbeResponse\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        [Id(3)]\n        public string FailureMessage { get { throw null; } init { } }\n\n        [Id(0)]\n        public int IntermediaryHealthScore { get { throw null; } init { } }\n\n        [Id(2)]\n        public System.TimeSpan ProbeResponseTime { get { throw null; } init { } }\n\n        [Id(1)]\n        public bool Succeeded { get { throw null; } init { } }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public static partial class Instruments\n    {\n        public static readonly System.Diagnostics.Metrics.Meter Meter;\n    }\n\n    public partial interface IRingRange\n    {\n        bool InRange(GrainId grainId);\n        bool InRange(uint value);\n    }\n\n    public partial interface ISingleRange : IRingRange\n    {\n        uint Begin { get; }\n\n        uint End { get; }\n    }\n\n    public static partial class LifecycleParticipantExtensions\n    {\n        public static ILifecycleParticipant<TLifecycle> ParticipateIn<TLifecycle>(this ILifecycleParticipant<ILifecycleObservable> participant)\n            where TLifecycle : ILifecycleObservable { throw null; }\n    }\n\n    public partial class OnDeserializedCallbacks : Orleans.Serialization.DeserializationContext\n    {\n        public OnDeserializedCallbacks(System.IServiceProvider serviceProvider) { }\n\n        public override object RuntimeClient { get { throw null; } }\n\n        public override System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        public void OnDeserialized(Orleans.Serialization.IOnDeserialized value) { }\n    }\n\n    public static partial class RangeFactory\n    {\n        public const long RING_SIZE = 4294967296L;\n        public static IRingRange CreateFullRange() { throw null; }\n\n        public static IRingRange CreateRange(System.Collections.Generic.List<IRingRange> inRanges) { throw null; }\n\n        public static IRingRange CreateRange(uint begin, uint end) { throw null; }\n\n        public static System.Collections.Generic.IEnumerable<ISingleRange> GetSubRanges(IRingRange range) { throw null; }\n    }\n\n    public static partial class RequestContextExtensions\n    {\n        public static System.Collections.Generic.Dictionary<string, object>? Export(Orleans.Serialization.DeepCopier copier) { throw null; }\n\n        public static void Import(System.Collections.Generic.Dictionary<string, object>? contextData) { }\n    }\n\n    public static partial class SiloRuntimeMetricsListener\n    {\n        public static long ConnectedClientCount { get { throw null; } }\n\n        public static long MessageReceivedTotal { get { throw null; } }\n\n        public static long MessageSentTotal { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class SiloRuntimeStatistics\n    {\n        internal SiloRuntimeStatistics() { }\n\n        [Id(0)]\n        public int ActivationCount { get { throw null; } }\n\n        [Id(3)]\n        [System.Obsolete(\"The will be removed, use EnvironmentStatistics.FilteredAvailableMemoryBytes instead.\", false)]\n        public float? AvailableMemory { get { throw null; } }\n\n        [Id(7)]\n        public long ClientCount { get { throw null; } }\n\n        [Id(2)]\n        [System.Obsolete(\"The will be removed, use EnvironmentStatistics.FilteredCpuUsagePercentage instead.\", false)]\n        public float? CpuUsage { get { throw null; } }\n\n        [Id(10)]\n        public System.DateTime DateTime { get { throw null; } }\n\n        [Id(11)]\n        public Statistics.EnvironmentStatistics EnvironmentStatistics { get { throw null; } }\n\n        [Id(6)]\n        public bool IsOverloaded { get { throw null; } }\n\n        [Id(4)]\n        [System.Obsolete(\"The will be removed, use EnvironmentStatistics.FilteredMemoryUsageBytes instead.\", false)]\n        public long? MemoryUsage { get { throw null; } }\n\n        [Id(8)]\n        public long ReceivedMessages { get { throw null; } }\n\n        [Id(1)]\n        public int RecentlyUsedActivationCount { get { throw null; } }\n\n        [Id(9)]\n        public long SentMessages { get { throw null; } }\n\n        [Id(5)]\n        [System.Obsolete(\"The will be removed, use EnvironmentStatistics.MaximumAvailableMemoryBytes instead.\", false)]\n        public long? TotalPhysicalMemory { get { throw null; } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public enum SiloStatus\n    {\n        None = 0,\n        Created = 1,\n        Joining = 2,\n        Active = 3,\n        ShuttingDown = 4,\n        Stopping = 5,\n        Dead = 6\n    }\n\n    public static partial class SiloStatusExtensions\n    {\n        public static bool IsTerminating(this SiloStatus siloStatus) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class SimpleGrainStatistic\n    {\n        [Id(2)]\n        public int ActivationCount { get { throw null; } init { } }\n\n        [Id(0)]\n        public string GrainType { get { throw null; } init { } }\n\n        [Id(1)]\n        public SiloAddress SiloAddress { get { throw null; } init { } }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Configuration\n{\n    public static partial class ConfigUtilities\n    {\n        public static string RedactConnectionStringInfo(string connectionString) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Internal\n{\n    public ref partial struct ExecutionContextSuppressor\n    {\n        private int _dummyPrimitive;\n        public readonly void Dispose() { }\n    }\n}\n\nnamespace Orleans.Runtime.Messaging\n{\n    public partial class ConnectionFailedException : OrleansException\n    {\n        public ConnectionFailedException() { }\n\n        [System.Obsolete]\n        protected ConnectionFailedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public ConnectionFailedException(string message, System.Exception innerException) { }\n\n        public ConnectionFailedException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class InvalidMessageFrameException : OrleansException\n    {\n        public InvalidMessageFrameException() { }\n\n        [System.Obsolete]\n        protected InvalidMessageFrameException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public InvalidMessageFrameException(string message, System.Exception innerException) { }\n\n        public InvalidMessageFrameException(string message) { }\n    }\n\n    public enum NetworkProtocolVersion : byte\n    {\n        Version1 = 1\n    }\n}\n\nnamespace Orleans.Runtime.Placement\n{\n    public partial interface IPlacementContext\n    {\n        SiloAddress LocalSilo { get; }\n\n        SiloStatus LocalSiloStatus { get; }\n\n        SiloAddress[] GetCompatibleSilos(PlacementTarget target);\n        System.Collections.Generic.IReadOnlyDictionary<ushort, SiloAddress[]> GetCompatibleSilosWithVersions(PlacementTarget target);\n    }\n\n    public partial interface IPlacementDirector\n    {\n        string PlacementHintKey { get; set; }\n\n        SiloAddress GetPlacementHint(System.Collections.Generic.Dictionary<string, object> requestContextData, SiloAddress[] compatibleSilos);\n        System.Threading.Tasks.Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context);\n    }\n\n    public readonly partial struct PlacementTarget\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public PlacementTarget(GrainId grainIdentity, System.Collections.Generic.Dictionary<string, object> requestContextData, GrainInterfaceType interfaceType, ushort interfaceVersion) { }\n\n        public GrainId GrainIdentity { get { throw null; } }\n\n        public GrainInterfaceType InterfaceType { get { throw null; } }\n\n        public ushort InterfaceVersion { get { throw null; } }\n\n        public System.Collections.Generic.Dictionary<string, object> RequestContextData { get { throw null; } }\n    }\n}\n\nnamespace Orleans.Serialization\n{\n    public partial class ActivationIdConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class ConfigureOrleansJsonSerializerOptions : Microsoft.Extensions.Options.IPostConfigureOptions<OrleansJsonSerializerOptions>\n    {\n        public ConfigureOrleansJsonSerializerOptions(System.IServiceProvider serviceProvider) { }\n\n        public void PostConfigure(string name, OrleansJsonSerializerOptions options) { }\n    }\n\n    public partial class GrainIdConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class GrainReferenceJsonConverter : Newtonsoft.Json.JsonConverter\n    {\n        public GrainReferenceJsonConverter(GrainReferences.GrainReferenceActivator referenceActivator) { }\n\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class IPAddressConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class IPEndPointConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class MembershipVersionJsonConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class OrleansJsonSerializationBinder : Newtonsoft.Json.Serialization.DefaultSerializationBinder\n    {\n        public OrleansJsonSerializationBinder(TypeSystem.TypeResolver typeResolver) { }\n\n        public override System.Type BindToType(string assemblyName, string typeName) { throw null; }\n    }\n\n    public partial class OrleansJsonSerializer\n    {\n        public const string IndentJsonProperty = \"IndentJSON\";\n        public const string TypeNameHandlingProperty = \"TypeNameHandling\";\n        public const string UseFullAssemblyNamesProperty = \"UseFullAssemblyNames\";\n        public OrleansJsonSerializer(Microsoft.Extensions.Options.IOptions<OrleansJsonSerializerOptions> options) { }\n\n        public object Deserialize(System.Type expectedType, string input) { throw null; }\n\n        public string Serialize(object item, System.Type expectedType) { throw null; }\n    }\n\n    public partial class OrleansJsonSerializerOptions\n    {\n        public Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { throw null; } set { } }\n    }\n\n    public static partial class OrleansJsonSerializerSettings\n    {\n        public static Newtonsoft.Json.JsonSerializerSettings GetDefaultSerializerSettings(System.IServiceProvider services) { throw null; }\n\n        public static Newtonsoft.Json.JsonSerializerSettings UpdateSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings, bool useFullAssemblyNames, bool indentJson, Newtonsoft.Json.TypeNameHandling? typeNameHandling) { throw null; }\n    }\n\n    public partial class SiloAddressJsonConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n\n    public partial class UniqueKeyConverter : Newtonsoft.Json.JsonConverter\n    {\n        public override bool CanConvert(System.Type objectType) { throw null; }\n\n        public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }\n\n        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }\n    }\n}\n\nnamespace Orleans.Storage\n{\n    [GenerateSerializer]\n    public sealed partial class BadProviderConfigException : Runtime.OrleansException\n    {\n        public BadProviderConfigException() { }\n\n        public BadProviderConfigException(string msg, System.Exception exc) { }\n\n        public BadProviderConfigException(string msg) { }\n    }\n\n    public partial class DefaultStorageProviderSerializerOptionsConfigurator<TOptions> : Microsoft.Extensions.Options.IPostConfigureOptions<TOptions> where TOptions : class, IStorageProviderSerializerOptions\n    {\n        public DefaultStorageProviderSerializerOptionsConfigurator(System.IServiceProvider serviceProvider) { }\n\n        public void PostConfigure(string name, TOptions options) { }\n    }\n\n    public static partial class GrainStorageHelpers\n    {\n        public static IGrainStorage GetGrainStorage(System.Type grainType, System.IServiceProvider services) { throw null; }\n    }\n\n    public partial class GrainStorageSerializer : IGrainStorageSerializer\n    {\n        public GrainStorageSerializer(IGrainStorageSerializer serializer, IGrainStorageSerializer fallbackDeserializer) { }\n\n        public T Deserialize<T>(System.BinaryData input) { throw null; }\n\n        public System.BinaryData Serialize<T>(T input) { throw null; }\n    }\n\n    public static partial class GrainStorageSerializerExtensions\n    {\n        public static T Deserialize<T>(this IGrainStorageSerializer serializer, System.ReadOnlyMemory<byte> input) { throw null; }\n    }\n\n    public partial interface IGrainStorage\n    {\n        System.Threading.Tasks.Task ClearStateAsync<T>(string stateName, Runtime.GrainId grainId, IGrainState<T> grainState);\n        System.Threading.Tasks.Task ReadStateAsync<T>(string stateName, Runtime.GrainId grainId, IGrainState<T> grainState);\n        System.Threading.Tasks.Task WriteStateAsync<T>(string stateName, Runtime.GrainId grainId, IGrainState<T> grainState);\n    }\n\n    public partial interface IGrainStorageSerializer\n    {\n        T Deserialize<T>(System.BinaryData input);\n        System.BinaryData Serialize<T>(T input);\n    }\n\n    public partial interface IMemoryStorageGrain : IGrainWithIntegerKey, IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task DeleteStateAsync<T>(string grainStoreKey, string eTag);\n        System.Threading.Tasks.Task<IGrainState<T>> ReadStateAsync<T>(string grainStoreKey);\n        System.Threading.Tasks.Task<string> WriteStateAsync<T>(string grainStoreKey, IGrainState<T> grainState);\n    }\n\n    [GenerateSerializer]\n    public partial class InconsistentStateException : Runtime.OrleansException\n    {\n        public InconsistentStateException() { }\n\n        [System.Obsolete]\n        protected InconsistentStateException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public InconsistentStateException(string message, System.Exception innerException) { }\n\n        public InconsistentStateException(string storedEtag, string currentEtag, System.Exception storageException) { }\n\n        public InconsistentStateException(string errorMsg, string storedEtag, string currentEtag, System.Exception storageException) { }\n\n        public InconsistentStateException(string errorMsg, string storedEtag, string currentEtag) { }\n\n        public InconsistentStateException(string message) { }\n\n        [Id(2)]\n        public string CurrentEtag { get { throw null; } }\n\n        [Id(1)]\n        public string StoredEtag { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial interface IRestExceptionDecoder\n    {\n        bool DecodeException(System.Exception exception, out System.Net.HttpStatusCode httpStatusCode, out string restStatus, bool getExtendedErrors = false);\n    }\n\n    public partial interface IStorageProviderSerializerOptions\n    {\n        IGrainStorageSerializer GrainStorageSerializer { get; set; }\n    }\n\n    public partial class JsonGrainStorageSerializer : IGrainStorageSerializer\n    {\n        public JsonGrainStorageSerializer(Serialization.OrleansJsonSerializer orleansJsonSerializer) { }\n\n        public T Deserialize<T>(System.BinaryData input) { throw null; }\n\n        public System.BinaryData Serialize<T>(T value) { throw null; }\n    }\n\n    public partial class OrleansGrainStorageSerializer : IGrainStorageSerializer\n    {\n        public OrleansGrainStorageSerializer(Serialization.Serializer serializer) { }\n\n        public T Deserialize<T>(System.BinaryData input) { throw null; }\n\n        public System.BinaryData Serialize<T>(T value) { throw null; }\n    }\n}\n\nnamespace Orleans.Timers.Internal\n{\n    public partial interface ITimerManager\n    {\n        System.Threading.Tasks.Task<bool> Delay(System.TimeSpan timeSpan, System.Threading.CancellationToken cancellationToken = default);\n    }\n}\n\nnamespace Orleans.Utilities\n{\n    public partial class ObserverManager<TObserver> : ObserverManager<Runtime.IAddressable, TObserver>\n    {\n        public ObserverManager(System.TimeSpan expiration, Microsoft.Extensions.Logging.ILogger log) : base(default, default!) { }\n    }\n\n    public partial class ObserverManager<TIdentity, TObserver> : System.Collections.Generic.IEnumerable<TObserver>, System.Collections.IEnumerable\n    {\n        public ObserverManager(System.TimeSpan expiration, Microsoft.Extensions.Logging.ILogger log) { }\n\n        public int Count { get { throw null; } }\n\n        public System.TimeSpan ExpirationDuration { get { throw null; } set { } }\n\n        public System.Func<System.DateTime> GetDateTime { get { throw null; } set { } }\n\n        public System.Collections.Generic.IReadOnlyDictionary<TIdentity, TObserver> Observers { get { throw null; } }\n\n        public void Clear() { }\n\n        public void ClearExpired() { }\n\n        public System.Collections.Generic.IEnumerator<TObserver> GetEnumerator() { throw null; }\n\n        public void Notify(System.Action<TObserver> notification, System.Func<TObserver, bool>? predicate = null) { }\n\n        public System.Threading.Tasks.Task Notify(System.Func<TObserver, System.Threading.Tasks.Task> notification, System.Func<TObserver, bool>? predicate = null) { throw null; }\n\n        public void Subscribe(TIdentity id, TObserver observer) { }\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }\n\n        public void Unsubscribe(TIdentity id) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainState<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.GrainState<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.GrainState<T> instance) { }\n\n        public global::Orleans.GrainState<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.GrainState<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.GrainState<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_00BCE16F : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_00BCE16F>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_00BCE16F instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_00BCE16F ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_00BCE16F instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_00BCE16F value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_7A519C2E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_7A519C2E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_7A519C2E instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_7A519C2E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_7A519C2E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_7A519C2E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_B1A52D2B : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_B1A52D2B>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMembershipTable_GrainReference_B1A52D2B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_B1A52D2B instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_B1A52D2B ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_B1A52D2B instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_B1A52D2B value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_BF899C85 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_BF899C85>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_BF899C85 instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_BF899C85 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_BF899C85 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_BF899C85 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_D851FB33 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_D851FB33>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMembershipTable_GrainReference_D851FB33(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_D851FB33 instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_D851FB33 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_D851FB33 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_D851FB33 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_E06D3DBC : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_E06D3DBC>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMembershipTable_GrainReference_E06D3DBC(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_E06D3DBC instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_E06D3DBC ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_E06D3DBC instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_E06D3DBC value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_FB89E5E9 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_FB89E5E9>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_FB89E5E9 instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_FB89E5E9 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_FB89E5E9 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_FB89E5E9 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMembershipTable_GrainReference_FEF3AC5A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMembershipTable_GrainReference_FEF3AC5A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMembershipTable_GrainReference_FEF3AC5A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMembershipTable_GrainReference_FEF3AC5A instance) { }\n\n        public Invokable_IMembershipTable_GrainReference_FEF3AC5A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMembershipTable_GrainReference_FEF3AC5A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMembershipTable_GrainReference_FEF3AC5A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IVersionManager_GrainReference_4AAEAFCE : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IVersionManager_GrainReference_4AAEAFCE>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IVersionManager_GrainReference_4AAEAFCE(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IVersionManager_GrainReference_4AAEAFCE instance) { }\n\n        public Invokable_IVersionManager_GrainReference_4AAEAFCE ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IVersionManager_GrainReference_4AAEAFCE instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IVersionManager_GrainReference_4AAEAFCE value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IVersionManager_GrainReference_8F5C15A9 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IVersionManager_GrainReference_8F5C15A9>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IVersionManager_GrainReference_8F5C15A9(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IVersionManager_GrainReference_8F5C15A9 instance) { }\n\n        public Invokable_IVersionManager_GrainReference_8F5C15A9 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IVersionManager_GrainReference_8F5C15A9 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IVersionManager_GrainReference_8F5C15A9 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IVersionManager_GrainReference_90AB9D5E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IVersionManager_GrainReference_90AB9D5E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IVersionManager_GrainReference_90AB9D5E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IVersionManager_GrainReference_90AB9D5E instance) { }\n\n        public Invokable_IVersionManager_GrainReference_90AB9D5E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IVersionManager_GrainReference_90AB9D5E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IVersionManager_GrainReference_90AB9D5E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IVersionManager_GrainReference_C01C4EE8 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IVersionManager_GrainReference_C01C4EE8>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IVersionManager_GrainReference_C01C4EE8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IVersionManager_GrainReference_C01C4EE8 instance) { }\n\n        public Invokable_IVersionManager_GrainReference_C01C4EE8 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IVersionManager_GrainReference_C01C4EE8 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IVersionManager_GrainReference_C01C4EE8 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MembershipEntry : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.MembershipEntry>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_MembershipEntry(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.MembershipEntry instance) { }\n\n        public global::Orleans.MembershipEntry ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.MembershipEntry instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.MembershipEntry value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MembershipTableData : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.MembershipTableData>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_MembershipTableData(global::Orleans.Serialization.Activators.IActivator<global::Orleans.MembershipTableData> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.MembershipTableData instance) { }\n\n        public global::Orleans.MembershipTableData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.MembershipTableData instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.MembershipTableData value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TableVersion : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.TableVersion>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_TableVersion(global::Orleans.Serialization.Activators.IActivator<global::Orleans.TableVersion> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.TableVersion instance) { }\n\n        public global::Orleans.TableVersion ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.TableVersion instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.TableVersion value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainState<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.GrainState<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_GrainState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.GrainState<T> DeepCopy(global::Orleans.GrainState<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_00BCE16F : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_00BCE16F>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMembershipTable_GrainReference_00BCE16F DeepCopy(Invokable_IMembershipTable_GrainReference_00BCE16F original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_7A519C2E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_7A519C2E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMembershipTable_GrainReference_7A519C2E DeepCopy(Invokable_IMembershipTable_GrainReference_7A519C2E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_B1A52D2B : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_B1A52D2B>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IMembershipTable_GrainReference_B1A52D2B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IMembershipTable_GrainReference_B1A52D2B DeepCopy(Invokable_IMembershipTable_GrainReference_B1A52D2B original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_BF899C85 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_BF899C85>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMembershipTable_GrainReference_BF899C85 DeepCopy(Invokable_IMembershipTable_GrainReference_BF899C85 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_D851FB33 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_D851FB33>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMembershipTable_GrainReference_D851FB33 DeepCopy(Invokable_IMembershipTable_GrainReference_D851FB33 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_E06D3DBC : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_E06D3DBC>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IMembershipTable_GrainReference_E06D3DBC(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IMembershipTable_GrainReference_E06D3DBC DeepCopy(Invokable_IMembershipTable_GrainReference_E06D3DBC original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_FB89E5E9 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_FB89E5E9>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMembershipTable_GrainReference_FB89E5E9 DeepCopy(Invokable_IMembershipTable_GrainReference_FB89E5E9 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMembershipTable_GrainReference_FEF3AC5A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMembershipTable_GrainReference_FEF3AC5A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IMembershipTable_GrainReference_FEF3AC5A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IMembershipTable_GrainReference_FEF3AC5A DeepCopy(Invokable_IMembershipTable_GrainReference_FEF3AC5A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IVersionManager_GrainReference_4AAEAFCE : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IVersionManager_GrainReference_4AAEAFCE>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IVersionManager_GrainReference_4AAEAFCE(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IVersionManager_GrainReference_4AAEAFCE DeepCopy(Invokable_IVersionManager_GrainReference_4AAEAFCE original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IVersionManager_GrainReference_8F5C15A9 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IVersionManager_GrainReference_8F5C15A9>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IVersionManager_GrainReference_8F5C15A9(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IVersionManager_GrainReference_8F5C15A9 DeepCopy(Invokable_IVersionManager_GrainReference_8F5C15A9 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IVersionManager_GrainReference_90AB9D5E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IVersionManager_GrainReference_90AB9D5E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IVersionManager_GrainReference_90AB9D5E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IVersionManager_GrainReference_90AB9D5E DeepCopy(Invokable_IVersionManager_GrainReference_90AB9D5E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IVersionManager_GrainReference_C01C4EE8 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IVersionManager_GrainReference_C01C4EE8>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IVersionManager_GrainReference_C01C4EE8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IVersionManager_GrainReference_C01C4EE8 DeepCopy(Invokable_IVersionManager_GrainReference_C01C4EE8 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_MembershipEntry : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.MembershipEntry>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_MembershipEntry(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.MembershipEntry DeepCopy(global::Orleans.MembershipEntry original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_MembershipTableData : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.MembershipTableData>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_MembershipTableData(global::Orleans.Serialization.Activators.IActivator<global::Orleans.MembershipTableData> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.MembershipTableData DeepCopy(global::Orleans.MembershipTableData original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"00BCE16F\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_00BCE16F : global::Orleans.Runtime.TaskRequest<global::Orleans.MembershipTableData>\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.MembershipTableData> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"7A519C2E\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_7A519C2E : global::Orleans.Runtime.TaskRequest\n    {\n        public System.DateTimeOffset arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"B1A52D2B\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_B1A52D2B : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.MembershipEntry arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"BF899C85\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_BF899C85 : global::Orleans.Runtime.TaskRequest\n    {\n        public string arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"D851FB33\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_D851FB33 : global::Orleans.Runtime.TaskRequest<global::Orleans.MembershipTableData>\n    {\n        public global::Orleans.Runtime.SiloAddress arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.MembershipTableData> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"E06D3DBC\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_E06D3DBC : global::Orleans.Runtime.TaskRequest<bool>\n    {\n        public global::Orleans.MembershipEntry arg0;\n        public string arg1;\n        public global::Orleans.TableVersion arg2;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<bool> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"FB89E5E9\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_FB89E5E9 : global::Orleans.Runtime.TaskRequest\n    {\n        public bool arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IMembershipTable), \"FEF3AC5A\" })]\n    public sealed partial class Invokable_IMembershipTable_GrainReference_FEF3AC5A : global::Orleans.Runtime.TaskRequest<bool>\n    {\n        public global::Orleans.MembershipEntry arg0;\n        public global::Orleans.TableVersion arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<bool> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IVersionManager), \"4AAEAFCE\" })]\n    public sealed partial class Invokable_IVersionManager_GrainReference_4AAEAFCE : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Versions.Selector.VersionSelectorStrategy arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IVersionManager), \"8F5C15A9\" })]\n    public sealed partial class Invokable_IVersionManager_GrainReference_8F5C15A9 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Versions.Compatibility.CompatibilityStrategy arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IVersionManager), \"90AB9D5E\" })]\n    public sealed partial class Invokable_IVersionManager_GrainReference_90AB9D5E : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainInterfaceType arg0;\n        public global::Orleans.Versions.Selector.VersionSelectorStrategy arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IVersionManager), \"C01C4EE8\" })]\n    public sealed partial class Invokable_IVersionManager_GrainReference_C01C4EE8 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainInterfaceType arg0;\n        public global::Orleans.Versions.Compatibility.CompatibilityStrategy arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.LeaseProviders\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AcquiredLease : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.LeaseProviders.AcquiredLease>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_AcquiredLease(global::Orleans.Serialization.Activators.IActivator<global::Orleans.LeaseProviders.AcquiredLease> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.LeaseProviders.AcquiredLease instance) { }\n\n        public global::Orleans.LeaseProviders.AcquiredLease ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.LeaseProviders.AcquiredLease instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.LeaseProviders.AcquiredLease value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AcquireLeaseResult : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.LeaseProviders.AcquireLeaseResult>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_AcquireLeaseResult(global::Orleans.Serialization.Activators.IActivator<global::Orleans.LeaseProviders.AcquireLeaseResult> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.LeaseProviders.AcquireLeaseResult instance) { }\n\n        public global::Orleans.LeaseProviders.AcquireLeaseResult ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.LeaseProviders.AcquireLeaseResult instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.LeaseProviders.AcquireLeaseResult value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LeaseRequest : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.LeaseProviders.LeaseRequest>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_LeaseRequest(global::Orleans.Serialization.Activators.IActivator<global::Orleans.LeaseProviders.LeaseRequest> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.LeaseProviders.LeaseRequest instance) { }\n\n        public global::Orleans.LeaseProviders.LeaseRequest ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.LeaseProviders.LeaseRequest instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.LeaseProviders.LeaseRequest value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ResponseCode : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.LeaseProviders.ResponseCode>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.LeaseProviders.ResponseCode ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.LeaseProviders.ResponseCode value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Networking.Shared\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SocketConnectionException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Networking.Shared.SocketConnectionException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_SocketConnectionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Networking.Shared.SocketConnectionException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Networking.Shared.SocketConnectionException instance) { }\n\n        public global::Orleans.Networking.Shared.SocketConnectionException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Networking.Shared.SocketConnectionException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Networking.Shared.SocketConnectionException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SocketConnectionException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Networking.Shared.SocketConnectionException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_SocketConnectionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Placement.Rebalancing\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IActivationRebalancer_GrainReference_25E91D88 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IActivationRebalancer_GrainReference_25E91D88>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IActivationRebalancer_GrainReference_25E91D88(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IActivationRebalancer_GrainReference_25E91D88 instance) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_25E91D88 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IActivationRebalancer_GrainReference_25E91D88 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IActivationRebalancer_GrainReference_25E91D88 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IActivationRebalancer_GrainReference_2FF852F5 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IActivationRebalancer_GrainReference_2FF852F5>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IActivationRebalancer_GrainReference_2FF852F5 instance) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_2FF852F5 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IActivationRebalancer_GrainReference_2FF852F5 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IActivationRebalancer_GrainReference_2FF852F5 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IActivationRebalancer_GrainReference_D7EB6469 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IActivationRebalancer_GrainReference_D7EB6469>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IActivationRebalancer_GrainReference_D7EB6469 instance) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_D7EB6469 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IActivationRebalancer_GrainReference_D7EB6469 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IActivationRebalancer_GrainReference_D7EB6469 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IActivationRebalancer_GrainReference_D9CA3E16 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IActivationRebalancer_GrainReference_D9CA3E16>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IActivationRebalancer_GrainReference_D9CA3E16(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IActivationRebalancer_GrainReference_D9CA3E16 instance) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_D9CA3E16 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IActivationRebalancer_GrainReference_D9CA3E16 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IActivationRebalancer_GrainReference_D9CA3E16 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IActivationRebalancer_GrainReference_DCF3A7BB : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IActivationRebalancer_GrainReference_DCF3A7BB>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IActivationRebalancer_GrainReference_DCF3A7BB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IActivationRebalancer_GrainReference_DCF3A7BB instance) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_DCF3A7BB ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IActivationRebalancer_GrainReference_DCF3A7BB instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IActivationRebalancer_GrainReference_DCF3A7BB value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RebalancerStatus : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Placement.Rebalancing.RebalancerStatus>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Placement.Rebalancing.RebalancerStatus ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Placement.Rebalancing.RebalancerStatus value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RebalancingReport : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Placement.Rebalancing.RebalancingReport>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Placement.Rebalancing.RebalancingReport>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_RebalancingReport(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Placement.Rebalancing.RebalancingReport> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Placement.Rebalancing.RebalancingReport instance) { }\n\n        public global::Orleans.Placement.Rebalancing.RebalancingReport ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Placement.Rebalancing.RebalancingReport instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Placement.Rebalancing.RebalancingReport value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RebalancingStatistics : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Placement.Rebalancing.RebalancingStatistics>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Placement.Rebalancing.RebalancingStatistics>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_RebalancingStatistics(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Placement.Rebalancing.RebalancingStatistics> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Placement.Rebalancing.RebalancingStatistics instance) { }\n\n        public global::Orleans.Placement.Rebalancing.RebalancingStatistics ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Placement.Rebalancing.RebalancingStatistics instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Placement.Rebalancing.RebalancingStatistics value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IActivationRebalancer_GrainReference_25E91D88 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IActivationRebalancer_GrainReference_25E91D88>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IActivationRebalancer_GrainReference_25E91D88(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_25E91D88 DeepCopy(Invokable_IActivationRebalancer_GrainReference_25E91D88 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IActivationRebalancer_GrainReference_2FF852F5 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IActivationRebalancer_GrainReference_2FF852F5>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IActivationRebalancer_GrainReference_2FF852F5 DeepCopy(Invokable_IActivationRebalancer_GrainReference_2FF852F5 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IActivationRebalancer_GrainReference_D7EB6469 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IActivationRebalancer_GrainReference_D7EB6469>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IActivationRebalancer_GrainReference_D7EB6469 DeepCopy(Invokable_IActivationRebalancer_GrainReference_D7EB6469 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IActivationRebalancer_GrainReference_D9CA3E16 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IActivationRebalancer_GrainReference_D9CA3E16>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IActivationRebalancer_GrainReference_D9CA3E16(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IActivationRebalancer_GrainReference_D9CA3E16 DeepCopy(Invokable_IActivationRebalancer_GrainReference_D9CA3E16 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IActivationRebalancer_GrainReference_DCF3A7BB : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IActivationRebalancer_GrainReference_DCF3A7BB>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IActivationRebalancer_GrainReference_DCF3A7BB DeepCopy(Invokable_IActivationRebalancer_GrainReference_DCF3A7BB original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Placement.Rebalancing.IActivationRebalancer), \"25E91D88\" })]\n    public sealed partial class Invokable_IActivationRebalancer_GrainReference_25E91D88 : global::Orleans.Runtime.VoidRequest\n    {\n        public global::Orleans.Placement.Rebalancing.IActivationRebalancerReportListener arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override void InvokeInner() { }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Placement.Rebalancing.IActivationRebalancer), \"2FF852F5\" })]\n    public sealed partial class Invokable_IActivationRebalancer_GrainReference_2FF852F5 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Placement.Rebalancing.IActivationRebalancer), \"D7EB6469\" })]\n    public sealed partial class Invokable_IActivationRebalancer_GrainReference_D7EB6469 : global::Orleans.Runtime.Request<global::Orleans.Placement.Rebalancing.RebalancingReport>\n    {\n        public bool arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask<global::Orleans.Placement.Rebalancing.RebalancingReport> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Placement.Rebalancing.IActivationRebalancer), \"D9CA3E16\" })]\n    public sealed partial class Invokable_IActivationRebalancer_GrainReference_D9CA3E16 : global::Orleans.Runtime.VoidRequest\n    {\n        public global::Orleans.Placement.Rebalancing.IActivationRebalancerReportListener arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override void InvokeInner() { }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Placement.Rebalancing.IActivationRebalancer), \"DCF3A7BB\" })]\n    public sealed partial class Invokable_IActivationRebalancer_GrainReference_DCF3A7BB : global::Orleans.Runtime.TaskRequest\n    {\n        public System.TimeSpan? arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Placement.Repartitioning\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CandidateConnectedVertex : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Placement.Repartitioning.CandidateConnectedVertex>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Placement.Repartitioning.CandidateConnectedVertex>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_CandidateConnectedVertex(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Placement.Repartitioning.CandidateConnectedVertex instance) { }\n\n        public global::Orleans.Placement.Repartitioning.CandidateConnectedVertex ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Placement.Repartitioning.CandidateConnectedVertex instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Placement.Repartitioning.CandidateConnectedVertex value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EdgeVertex : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Placement.Repartitioning.EdgeVertex>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Placement.Repartitioning.EdgeVertex>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_EdgeVertex(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Placement.Repartitioning.EdgeVertex instance) { }\n\n        public global::Orleans.Placement.Repartitioning.EdgeVertex ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Placement.Repartitioning.EdgeVertex instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Placement.Repartitioning.EdgeVertex value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Providers\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ProviderInitializationException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.ProviderInitializationException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ProviderInitializationException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.ProviderInitializationException instance) { }\n\n        public global::Orleans.Providers.ProviderInitializationException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.ProviderInitializationException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.ProviderInitializationException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ProviderStateException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.ProviderStateException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ProviderStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.ProviderStateException instance) { }\n\n        public global::Orleans.Providers.ProviderStateException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.ProviderStateException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.ProviderStateException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ProviderInitializationException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Providers.ProviderInitializationException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ProviderInitializationException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ProviderStateException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Providers.ProviderStateException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ProviderStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClusterManifestUpdate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ClusterManifestUpdate>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.ClusterManifestUpdate>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_ClusterManifestUpdate(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ClusterManifestUpdate> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ClusterManifestUpdate instance) { }\n\n        public global::Orleans.Runtime.ClusterManifestUpdate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ClusterManifestUpdate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ClusterManifestUpdate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DetailedGrainStatistic : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.DetailedGrainStatistic>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_DetailedGrainStatistic(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.DetailedGrainStatistic instance) { }\n\n        public global::Orleans.Runtime.DetailedGrainStatistic ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.DetailedGrainStatistic instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.DetailedGrainStatistic value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainCallFrequency : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainCallFrequency>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.GrainCallFrequency>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_GrainCallFrequency(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.GrainCallFrequency instance) { }\n\n        public global::Orleans.Runtime.GrainCallFrequency ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.GrainCallFrequency instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainCallFrequency value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_IndirectProbeResponse : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.IndirectProbeResponse>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.IndirectProbeResponse>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.IndirectProbeResponse instance) { }\n\n        public global::Orleans.Runtime.IndirectProbeResponse ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.IndirectProbeResponse instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.IndirectProbeResponse value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_0A1C0D82 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_0A1C0D82>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_0A1C0D82(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_0A1C0D82 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_0A1C0D82 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_0A1C0D82 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_0A1C0D82 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_0F06E027 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_0F06E027>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_0F06E027(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_0F06E027 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_0F06E027 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_0F06E027 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_0F06E027 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_2D761B36 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_2D761B36>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_2D761B36(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_2D761B36 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_2D761B36 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_2D761B36 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_2D761B36 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_317D82B6 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_317D82B6>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_317D82B6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_317D82B6 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_317D82B6 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_317D82B6 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_317D82B6 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_329F9A1B : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_329F9A1B>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_329F9A1B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_329F9A1B instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_329F9A1B ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_329F9A1B instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_329F9A1B value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_3CFF788C : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_3CFF788C>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_3CFF788C(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_3CFF788C instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_3CFF788C ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_3CFF788C instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_3CFF788C value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_3DB7923B : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_3DB7923B>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_3DB7923B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_3DB7923B instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_3DB7923B ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_3DB7923B instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_3DB7923B value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_4C0864C2 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_4C0864C2>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_4C0864C2 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_4C0864C2 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_4C0864C2 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_4C0864C2 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_54E6D1D1 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_54E6D1D1>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_54E6D1D1 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_54E6D1D1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_54E6D1D1 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_54E6D1D1 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_54FE0FEC : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_54FE0FEC>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_54FE0FEC(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_54FE0FEC instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_54FE0FEC ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_54FE0FEC instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_54FE0FEC value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_5922EB76 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_5922EB76>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_5922EB76(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_5922EB76 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_5922EB76 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_5922EB76 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_5922EB76 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_ACCE9D6A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_ACCE9D6A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_ACCE9D6A instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_ACCE9D6A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_ACCE9D6A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_ACCE9D6A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_AEDE93F6 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_AEDE93F6>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_AEDE93F6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_AEDE93F6 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_AEDE93F6 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_AEDE93F6 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_AEDE93F6 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_B761B345 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_B761B345>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IManagementGrain_GrainReference_B761B345(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_B761B345 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_B761B345 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_B761B345 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_B761B345 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_CC6CCBC3 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_CC6CCBC3>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_CC6CCBC3 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_CC6CCBC3 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_CC6CCBC3 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_CC6CCBC3 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_D7365B43 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_D7365B43>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_D7365B43 instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_D7365B43 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_D7365B43 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_D7365B43 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IManagementGrain_GrainReference_F67965CC_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IManagementGrain_GrainReference_F67965CC_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec where T : global::Orleans.Providers.IControllable\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IManagementGrain_GrainReference_F67965CC_1<T> instance) { }\n\n        public Invokable_IManagementGrain_GrainReference_F67965CC_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IManagementGrain_GrainReference_F67965CC_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IManagementGrain_GrainReference_F67965CC_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SiloRuntimeStatistics : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SiloRuntimeStatistics>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_SiloRuntimeStatistics(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.SiloRuntimeStatistics> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.SiloRuntimeStatistics instance) { }\n\n        public global::Orleans.Runtime.SiloRuntimeStatistics ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.SiloRuntimeStatistics instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SiloRuntimeStatistics value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SiloStatus : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SiloStatus>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Runtime.SiloStatus ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SiloStatus value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SimpleGrainStatistic : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SimpleGrainStatistic>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_SimpleGrainStatistic(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.SimpleGrainStatistic instance) { }\n\n        public global::Orleans.Runtime.SimpleGrainStatistic ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.SimpleGrainStatistic instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SimpleGrainStatistic value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ClusterManifestUpdate : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Runtime.ClusterManifestUpdate>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Runtime.ClusterManifestUpdate>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public void DeepCopy(global::Orleans.Runtime.ClusterManifestUpdate input, global::Orleans.Runtime.ClusterManifestUpdate output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Runtime.ClusterManifestUpdate DeepCopy(global::Orleans.Runtime.ClusterManifestUpdate original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_0A1C0D82 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_0A1C0D82>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_0A1C0D82(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_0A1C0D82 DeepCopy(Invokable_IManagementGrain_GrainReference_0A1C0D82 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_0F06E027 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_0F06E027>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_0F06E027(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_0F06E027 DeepCopy(Invokable_IManagementGrain_GrainReference_0F06E027 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_2D761B36 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_2D761B36>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_2D761B36(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_2D761B36 DeepCopy(Invokable_IManagementGrain_GrainReference_2D761B36 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_317D82B6 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_317D82B6>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_317D82B6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_317D82B6 DeepCopy(Invokable_IManagementGrain_GrainReference_317D82B6 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_329F9A1B : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_329F9A1B>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_329F9A1B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_329F9A1B DeepCopy(Invokable_IManagementGrain_GrainReference_329F9A1B original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_3CFF788C : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_3CFF788C>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_3CFF788C(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_3CFF788C DeepCopy(Invokable_IManagementGrain_GrainReference_3CFF788C original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_3DB7923B : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_3DB7923B>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_3DB7923B DeepCopy(Invokable_IManagementGrain_GrainReference_3DB7923B original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_4C0864C2 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_4C0864C2>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_4C0864C2 DeepCopy(Invokable_IManagementGrain_GrainReference_4C0864C2 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_54E6D1D1 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_54E6D1D1>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_54E6D1D1 DeepCopy(Invokable_IManagementGrain_GrainReference_54E6D1D1 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_54FE0FEC : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_54FE0FEC>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_54FE0FEC(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_54FE0FEC DeepCopy(Invokable_IManagementGrain_GrainReference_54FE0FEC original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_5922EB76 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_5922EB76>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_5922EB76(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_5922EB76 DeepCopy(Invokable_IManagementGrain_GrainReference_5922EB76 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_ACCE9D6A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_ACCE9D6A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_ACCE9D6A DeepCopy(Invokable_IManagementGrain_GrainReference_ACCE9D6A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_AEDE93F6 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_AEDE93F6>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_AEDE93F6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_AEDE93F6 DeepCopy(Invokable_IManagementGrain_GrainReference_AEDE93F6 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_B761B345 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_B761B345>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IManagementGrain_GrainReference_B761B345(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IManagementGrain_GrainReference_B761B345 DeepCopy(Invokable_IManagementGrain_GrainReference_B761B345 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_CC6CCBC3 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_CC6CCBC3>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_CC6CCBC3 DeepCopy(Invokable_IManagementGrain_GrainReference_CC6CCBC3 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_D7365B43 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_D7365B43>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IManagementGrain_GrainReference_D7365B43 DeepCopy(Invokable_IManagementGrain_GrainReference_D7365B43 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IManagementGrain_GrainReference_F67965CC_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IManagementGrain_GrainReference_F67965CC_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier where T : global::Orleans.Providers.IControllable\n    {\n        public Invokable_IManagementGrain_GrainReference_F67965CC_1<T> DeepCopy(Invokable_IManagementGrain_GrainReference_F67965CC_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"0A1C0D82\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_0A1C0D82 : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.DetailedGrainStatistic[]>\n    {\n        public string[] arg0;\n        public global::Orleans.Runtime.SiloAddress[] arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.DetailedGrainStatistic[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"0F06E027\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_0F06E027 : global::Orleans.Runtime.TaskRequest<System.Collections.Generic.List<global::Orleans.Runtime.GrainCallFrequency>>\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<global::Orleans.Runtime.GrainCallFrequency>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"2D761B36\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_2D761B36 : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.SiloRuntimeStatistics[]>\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.SiloRuntimeStatistics[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"317D82B6\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_317D82B6 : global::Orleans.Runtime.Request<global::Orleans.Runtime.SiloAddress>\n    {\n        public global::Orleans.Runtime.IAddressable arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask<global::Orleans.Runtime.SiloAddress> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"329F9A1B\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_329F9A1B : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public System.TimeSpan arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"3CFF788C\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_3CFF788C : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.SimpleGrainStatistic[]>\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.SimpleGrainStatistic[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"3DB7923B\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_3DB7923B : global::Orleans.Runtime.Request<System.Collections.Generic.List<global::Orleans.Runtime.GrainId>>\n    {\n        public global::Orleans.Runtime.GrainType arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask<System.Collections.Generic.List<global::Orleans.Runtime.GrainId>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"4C0864C2\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_4C0864C2 : global::Orleans.Runtime.TaskRequest<System.Collections.Generic.Dictionary<global::Orleans.Runtime.SiloAddress, global::Orleans.Runtime.SiloStatus>>\n    {\n        public bool arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.Dictionary<global::Orleans.Runtime.SiloAddress, global::Orleans.Runtime.SiloStatus>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"54E6D1D1\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_54E6D1D1 : global::Orleans.Runtime.TaskRequest\n    {\n        public System.TimeSpan arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"54FE0FEC\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_54FE0FEC : global::Orleans.Runtime.Request\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"5922EB76\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_5922EB76 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"ACCE9D6A\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_ACCE9D6A : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.SimpleGrainStatistic[]>\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.SimpleGrainStatistic[]> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"AEDE93F6\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_AEDE93F6 : global::Orleans.Runtime.TaskRequest<int>\n    {\n        public global::Orleans.Runtime.GrainReference arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<int> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"B761B345\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_B761B345 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.SiloAddress[] arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"CC6CCBC3\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_CC6CCBC3 : global::Orleans.Runtime.TaskRequest<global::Orleans.MembershipEntry[]>\n    {\n        public bool arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.MembershipEntry[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"D7365B43\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_D7365B43 : global::Orleans.Runtime.TaskRequest<int>\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<int> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Runtime.IManagementGrain), \"F67965CC\" })]\n    public sealed partial class Invokable_IManagementGrain_GrainReference_F67965CC_1<T> : global::Orleans.Runtime.TaskRequest<object[]> where T : global::Orleans.Providers.IControllable\n    {\n        public string arg0;\n        public int arg1;\n        public object arg2;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<object[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime.Messaging\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_InvalidMessageFrameException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.Messaging.InvalidMessageFrameException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_InvalidMessageFrameException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.Messaging.InvalidMessageFrameException instance) { }\n\n        public global::Orleans.Runtime.Messaging.InvalidMessageFrameException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.Messaging.InvalidMessageFrameException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.Messaging.InvalidMessageFrameException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_InvalidMessageFrameException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.Messaging.InvalidMessageFrameException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_InvalidMessageFrameException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Storage\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_BadProviderConfigException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Storage.BadProviderConfigException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_BadProviderConfigException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Storage.BadProviderConfigException instance) { }\n\n        public global::Orleans.Storage.BadProviderConfigException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Storage.BadProviderConfigException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Storage.BadProviderConfigException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_InconsistentStateException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Storage.InconsistentStateException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Storage.InconsistentStateException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_InconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Storage.InconsistentStateException instance) { }\n\n        public global::Orleans.Storage.InconsistentStateException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Storage.InconsistentStateException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Storage.InconsistentStateException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> instance) { }\n\n        public Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> instance) { }\n\n        public Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> instance) { }\n\n        public Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_BadProviderConfigException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Storage.BadProviderConfigException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_BadProviderConfigException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_InconsistentStateException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Storage.InconsistentStateException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_InconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Storage.InconsistentStateException input, global::Orleans.Storage.InconsistentStateException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> DeepCopy(Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> DeepCopy(Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> DeepCopy(Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Storage.IMemoryStorageGrain), \"45659318\" })]\n    public sealed partial class Invokable_IMemoryStorageGrain_GrainReference_45659318_1<T> : global::Orleans.Runtime.TaskRequest<global::Orleans.IGrainState<T>>\n    {\n        public string arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.IGrainState<T>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Storage.IMemoryStorageGrain), \"7CC6CA25\" })]\n    public sealed partial class Invokable_IMemoryStorageGrain_GrainReference_7CC6CA25_1<T> : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        public global::Orleans.IGrainState<T> arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<string> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Storage.IMemoryStorageGrain), \"B7CADD03\" })]\n    public sealed partial class Invokable_IMemoryStorageGrain_GrainReference_B7CADD03_1<T> : global::Orleans.Runtime.TaskRequest\n    {\n        public string arg0;\n        public string arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n"
  },
  {
    "path": "src/api/Orleans.Core.Abstractions/Orleans.Core.Abstractions.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    public readonly partial struct DeactivationReason\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public DeactivationReason(DeactivationReasonCode code, System.Exception? exception, string text) { }\n\n        public DeactivationReason(DeactivationReasonCode code, string text) { }\n\n        public string Description { get { throw null; } }\n\n        public System.Exception? Exception { get { throw null; } }\n\n        public DeactivationReasonCode ReasonCode { get { throw null; } }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public enum DeactivationReasonCode : byte\n    {\n        None = 0,\n        ShuttingDown = 1,\n        ActivationFailed = 2,\n        DirectoryFailure = 3,\n        ActivationIdle = 4,\n        ActivationUnresponsive = 5,\n        DuplicateActivation = 6,\n        IncompatibleRequest = 7,\n        ApplicationError = 8,\n        ApplicationRequested = 9,\n        Migrating = 10,\n        RuntimeRequested = 11,\n        HighMemoryPressure = 12\n    }\n\n    public enum ErrorCode\n    {\n        Runtime = 100000,\n        Runtime_Error_100001 = 100001,\n        Logger_ProcessCrashing = 100002,\n        Runtime_Error_100002 = 100002,\n        Runtime_Error_100003 = 100003,\n        Runtime_Error_100004 = 100004,\n        Runtime_Error_100005 = 100005,\n        Runtime_Error_100006 = 100006,\n        Runtime_Error_100007 = 100007,\n        Runtime_Error_100008 = 100008,\n        Runtime_Error_100009 = 100009,\n        Runtime_Error_100010 = 100010,\n        Runtime_Error_100011 = 100011,\n        Runtime_Error_100012 = 100012,\n        Runtime_Error_100013 = 100013,\n        Runtime_Error_100014 = 100014,\n        Runtime_Error_100015 = 100015,\n        Runtime_Error_100016 = 100016,\n        Runtime_Error_100017 = 100017,\n        Runtime_Error_100018 = 100018,\n        Runtime_Error_100019 = 100019,\n        Runtime_Error_100020 = 100020,\n        ProxyClient_ReceiveError = 100021,\n        Runtime_Error_100021 = 100021,\n        Runtime_Error_100022 = 100022,\n        Runtime_Error_100023 = 100023,\n        Runtime_Error_100024 = 100024,\n        Runtime_Error_100025 = 100025,\n        Runtime_Error_100026 = 100026,\n        Runtime_Error_100027 = 100027,\n        Runtime_Error_100028 = 100028,\n        Runtime_Error_100029 = 100029,\n        Runtime_Error_100030 = 100030,\n        Runtime_Error_100031 = 100031,\n        Runtime_Error_100032 = 100032,\n        Runtime_Error_100033 = 100033,\n        Ser_IncompatibleIntermediateType = 100033,\n        Runtime_Error_100034 = 100034,\n        Ser_CannotConstructBaseObj = 100034,\n        Runtime_Error_100035 = 100035,\n        Ser_IncompatibleType = 100035,\n        Runtime_Error_100036 = 100036,\n        Runtime_Error_100037 = 100037,\n        TimerCallbackError = 100037,\n        Runtime_Error_100039 = 100039,\n        Runtime_Error_100040 = 100040,\n        Runtime_Error_100041 = 100041,\n        Runtime_Error_100042 = 100042,\n        Runtime_Error_100043 = 100043,\n        Runtime_Error_100044 = 100044,\n        Runtime_Error_100045 = 100045,\n        Runtime_Error_100046 = 100046,\n        Loader_NotGrainAssembly = 100047,\n        Runtime_Error_100047 = 100047,\n        Loader_TypeLoadError = 100048,\n        Runtime_Error_100048 = 100048,\n        Loader_ProxyLoadError = 100049,\n        Runtime_Error_100049 = 100049,\n        Runtime_Error_100050 = 100050,\n        Runtime_Error_100051 = 100051,\n        Runtime_Error_100052 = 100052,\n        Runtime_Error_100053 = 100053,\n        Runtime_Error_100054 = 100054,\n        Runtime_Error_100055 = 100055,\n        Runtime_Error_100056 = 100056,\n        Runtime_Error_100057 = 100057,\n        Runtime_Error_100058 = 100058,\n        Runtime_Error_100059 = 100059,\n        Runtime_Error_100060 = 100060,\n        Runtime_Error_100061 = 100061,\n        Runtime_Error_100062 = 100062,\n        Runtime_Error_100063 = 100063,\n        Runtime_Error_100064 = 100064,\n        Runtime_Error_100065 = 100065,\n        Runtime_Error_100066 = 100066,\n        Runtime_Error_100067 = 100067,\n        Runtime_Error_100068 = 100068,\n        Runtime_Error_100069 = 100069,\n        Runtime_Error_100070 = 100070,\n        Dispatcher_SelectTarget_Failed = 100071,\n        Runtime_Error_100071 = 100071,\n        Dispatcher_InvalidEnum_Direction = 100072,\n        Runtime_Error_100072 = 100072,\n        Dispatcher_NoCallbackForRejectionResp = 100073,\n        Runtime_Error_100073 = 100073,\n        Runtime_Error_100074 = 100074,\n        Dispatcher_InvalidEnum_RejectionType = 100075,\n        Runtime_Error_100075 = 100075,\n        Dispatcher_NoCallbackForResp = 100076,\n        Runtime_Error_100076 = 100076,\n        Dispatcher_InvalidMsg_Direction = 100077,\n        Runtime_Error_100077 = 100077,\n        Runtime_Error_100078 = 100078,\n        Runtime_Error_100079 = 100079,\n        Runtime_Error_100080 = 100080,\n        Runtime_Error_100081 = 100081,\n        Runtime_Error_100082 = 100082,\n        Runtime_Error_100083 = 100083,\n        Runtime_Error_100084 = 100084,\n        Runtime_Error_100085 = 100085,\n        Runtime_Error_100086 = 100086,\n        Runtime_Error_100087 = 100087,\n        Runtime_Error_100088 = 100088,\n        Runtime_Error_100089 = 100089,\n        Runtime_Error_100090 = 100090,\n        Runtime_Error_100091 = 100091,\n        Runtime_Error_100092 = 100092,\n        Runtime_Error_100093 = 100093,\n        Runtime_Error_100094 = 100094,\n        Runtime_Error_100095 = 100095,\n        Runtime_Error_100096 = 100096,\n        Runtime_Error_100097 = 100097,\n        Runtime_Error_100098 = 100098,\n        Runtime_Error_100099 = 100099,\n        Runtime_Error_100100 = 100100,\n        Runtime_Error_100101 = 100101,\n        Runtime_Error_100102 = 100102,\n        Runtime_Error_100103 = 100103,\n        Runtime_Error_100104 = 100104,\n        Runtime_Error_100105 = 100105,\n        Runtime_Error_100106 = 100106,\n        Runtime_Error_100107 = 100107,\n        Runtime_Error_100108 = 100108,\n        Runtime_Error_100109 = 100109,\n        Runtime_Error_100110 = 100110,\n        Runtime_Error_100111 = 100111,\n        Runtime_Error_100112 = 100112,\n        Runtime_Error_100113 = 100113,\n        Runtime_Error_100114 = 100114,\n        Runtime_Error_100115 = 100115,\n        Runtime_Error_100116 = 100116,\n        Runtime_Error_100117 = 100117,\n        Runtime_Error_100118 = 100118,\n        Runtime_Error_100119 = 100119,\n        Runtime_Error_100120 = 100120,\n        Runtime_Error_100121 = 100121,\n        Runtime_Error_100122 = 100122,\n        Runtime_Error_100123 = 100123,\n        Runtime_Error_100124 = 100124,\n        Runtime_Error_100125 = 100125,\n        Runtime_Error_100126 = 100126,\n        Runtime_Error_100127 = 100127,\n        Runtime_Error_100128 = 100128,\n        Runtime_Error_100129 = 100129,\n        Runtime_Error_100130 = 100130,\n        Runtime_Error_100131 = 100131,\n        Runtime_Error_100132 = 100132,\n        Runtime_Error_100133 = 100133,\n        Runtime_Error_100134 = 100134,\n        Runtime_Error_100135 = 100135,\n        Runtime_Error_100136 = 100136,\n        Runtime_Error_100137 = 100137,\n        Runtime_Error_100138 = 100138,\n        Runtime_Error_100139 = 100139,\n        Runtime_Error_100140 = 100140,\n        Runtime_Error_100141 = 100141,\n        Runtime_Error_100142 = 100142,\n        Runtime_Error_100143 = 100143,\n        Runtime_Error_100144 = 100144,\n        Runtime_Error_100145 = 100145,\n        Runtime_Error_100146 = 100146,\n        Dispatcher_Intermediate_GetOrCreateActivation = 100147,\n        Runtime_Error_100147 = 100147,\n        Dispatcher_NoTargetActivation = 100148,\n        Runtime_Error_100148 = 100148,\n        Runtime_Error_100149 = 100149,\n        Runtime_Error_100150 = 100150,\n        SiloHeartbeatTimerStalled = 100150,\n        Runtime_Error_100151 = 100151,\n        Dispatcher_QueueingRequestBadTargetState = 100152,\n        Runtime_Error_100152 = 100152,\n        Runtime_Error_100153 = 100153,\n        Runtime_Error_100154 = 100154,\n        Runtime_Error_100155 = 100155,\n        Runtime_Error_100156 = 100156,\n        Runtime_Error_100157 = 100157,\n        Runtime_Error_100158 = 100158,\n        ProxyClient_SerializationError = 100159,\n        Runtime_Error_100159 = 100159,\n        Runtime_Error_100160 = 100160,\n        ProxyClient_SocketSendError = 100161,\n        Runtime_Error_100161 = 100161,\n        Runtime_Error_100162 = 100162,\n        ProxyClient_ByteCountMismatch = 100163,\n        Runtime_Error_100163 = 100163,\n        Runtime_Error_100164 = 100164,\n        Runtime_Error_100165 = 100165,\n        Runtime_Error_100166 = 100166,\n        Runtime_Error_100167 = 100167,\n        Runtime_Error_100168 = 100168,\n        Runtime_Error_100169 = 100169,\n        Runtime_Error_100170 = 100170,\n        Runtime_Error_100171 = 100171,\n        Runtime_Error_100172 = 100172,\n        Runtime_Error_100173 = 100173,\n        Runtime_Error_100174 = 100174,\n        Runtime_Error_100175 = 100175,\n        Runtime_Error_100176 = 100176,\n        Runtime_Error_100177 = 100177,\n        ProxyClient_CannotConnect = 100178,\n        Runtime_Error_100178 = 100178,\n        Runtime_Error_100179 = 100179,\n        Runtime_Error_100180 = 100180,\n        Runtime_Error_100181 = 100181,\n        Runtime_Error_100182 = 100182,\n        Runtime_Error_100183 = 100183,\n        Runtime_Error_100184 = 100184,\n        Runtime_Error_100185 = 100185,\n        Runtime_Error_100186 = 100186,\n        Runtime_Error_100187 = 100187,\n        Runtime_Error_100188 = 100188,\n        Runtime_Error_100189 = 100189,\n        Runtime_Error_100190 = 100190,\n        Runtime_Error_100191 = 100191,\n        Runtime_Error_100192 = 100192,\n        Runtime_Error_100193 = 100193,\n        Runtime_Error_100194 = 100194,\n        Runtime_Error_100195 = 100195,\n        Runtime_Error_100196 = 100196,\n        Runtime_Error_100197 = 100197,\n        Runtime_Error_100198 = 100198,\n        Runtime_Error_100199 = 100199,\n        Runtime_Error_100200 = 100200,\n        Runtime_Error_100201 = 100201,\n        Runtime_Error_100202 = 100202,\n        Runtime_Error_100203 = 100203,\n        Runtime_Error_100204 = 100204,\n        Runtime_Error_100205 = 100205,\n        Runtime_Error_100206 = 100206,\n        Runtime_Error_100207 = 100207,\n        Runtime_Error_100208 = 100208,\n        Runtime_Error_100209 = 100209,\n        Runtime_Error_100210 = 100210,\n        Runtime_Error_100211 = 100211,\n        Runtime_Error_100212 = 100212,\n        Runtime_Error_100213 = 100213,\n        Runtime_Error_100214 = 100214,\n        Runtime_Error_100215 = 100215,\n        Runtime_Error_100216 = 100216,\n        Runtime_Error_100217 = 100217,\n        Runtime_Error_100218 = 100218,\n        Runtime_Error_100219 = 100219,\n        Runtime_Error_100220 = 100220,\n        Runtime_Error_100221 = 100221,\n        Runtime_Error_100222 = 100222,\n        Runtime_Error_100223 = 100223,\n        Runtime_Error_100224 = 100224,\n        MembershipCantWriteLivenessDisabled = 100225,\n        Runtime_Error_100225 = 100225,\n        Runtime_Error_100226 = 100226,\n        Runtime_Error_100227 = 100227,\n        Runtime_Error_100228 = 100228,\n        Runtime_Error_100229 = 100229,\n        Runtime_Error_100230 = 100230,\n        Runtime_Error_100231 = 100231,\n        Runtime_Error_100232 = 100232,\n        Runtime_Error_100233 = 100233,\n        Runtime_Error_100234 = 100234,\n        Runtime_Error_100235 = 100235,\n        Runtime_Error_100236 = 100236,\n        Runtime_Error_100237 = 100237,\n        Runtime_Error_100238 = 100238,\n        Runtime_Error_100239 = 100239,\n        Runtime_Error_100240 = 100240,\n        Runtime_Error_100241 = 100241,\n        Runtime_Error_100242 = 100242,\n        Runtime_Error_100243 = 100243,\n        Runtime_Error_100244 = 100244,\n        Runtime_Error_100245 = 100245,\n        Runtime_Error_100246 = 100246,\n        Runtime_Error_100247 = 100247,\n        Runtime_Error_100248 = 100248,\n        Runtime_Error_100249 = 100249,\n        Runtime_Error_100250 = 100250,\n        Runtime_Error_100251 = 100251,\n        Runtime_Error_100252 = 100252,\n        Runtime_Error_100253 = 100253,\n        Runtime_Error_100254 = 100254,\n        Runtime_Error_100255 = 100255,\n        Runtime_Error_100256 = 100256,\n        Runtime_Error_100257 = 100257,\n        Runtime_Error_100258 = 100258,\n        Runtime_Error_100259 = 100259,\n        Runtime_Error_100260 = 100260,\n        Runtime_Error_100261 = 100261,\n        Runtime_Error_100262 = 100262,\n        Runtime_Error_100263 = 100263,\n        Runtime_Error_100264 = 100264,\n        Runtime_Error_100265 = 100265,\n        Runtime_Error_100266 = 100266,\n        Runtime_Error_100267 = 100267,\n        Runtime_Error_100268 = 100268,\n        Runtime_Error_100269 = 100269,\n        Runtime_Error_100270 = 100270,\n        Runtime_Error_100271 = 100271,\n        Runtime_Error_100272 = 100272,\n        Runtime_Error_100273 = 100273,\n        Runtime_Error_100274 = 100274,\n        Runtime_Error_100275 = 100275,\n        Runtime_Error_100276 = 100276,\n        Runtime_Error_100277 = 100277,\n        Runtime_Error_100278 = 100278,\n        Runtime_Error_100279 = 100279,\n        Runtime_Error_100280 = 100280,\n        Runtime_Error_100281 = 100281,\n        Runtime_Error_100282 = 100282,\n        Runtime_Error_100283 = 100283,\n        Runtime_Error_100284 = 100284,\n        Runtime_Error_100285 = 100285,\n        Runtime_Error_100286 = 100286,\n        Runtime_Error_100287 = 100287,\n        Runtime_Error_100288 = 100288,\n        Runtime_Error_100289 = 100289,\n        Runtime_Error_100290 = 100290,\n        Runtime_Error_100291 = 100291,\n        Runtime_Error_100292 = 100292,\n        Runtime_Error_100293 = 100293,\n        Runtime_Error_100294 = 100294,\n        Runtime_Error_100295 = 100295,\n        Runtime_Error_100296 = 100296,\n        Runtime_Error_100297 = 100297,\n        Runtime_Error_100298 = 100298,\n        Dispatcher_InjectingRejection = 100299,\n        Runtime_Error_100299 = 100299,\n        Dispatcher_InjectingMessageLoss = 100300,\n        Runtime_Error_100300 = 100300,\n        Runtime_Error_100301 = 100301,\n        Runtime_Error_100302 = 100302,\n        Dispatcher_UnknownTypeCode = 100303,\n        Runtime_Error_100303 = 100303,\n        Runtime_Error_100304 = 100304,\n        Runtime_Error_100305 = 100305,\n        Runtime_Error_100306 = 100306,\n        Runtime_Error_100307 = 100307,\n        Runtime_Error_100308 = 100308,\n        Runtime_Error_100309 = 100309,\n        Runtime_Error_100310 = 100310,\n        Runtime_Error_100311 = 100311,\n        Runtime_Error_100312 = 100312,\n        ClientInitializing = 100313,\n        ClientStarting = 100314,\n        ClientError = 100315,\n        Runtime_Error_100316 = 100316,\n        Runtime_Error_100317 = 100317,\n        Runtime_Error_100318 = 100318,\n        Runtime_Error_100319 = 100319,\n        Runtime_Error_100320 = 100320,\n        Runtime_Error_100321 = 100321,\n        GrainInvokeException = 100322,\n        Runtime_Error_100323 = 100323,\n        Runtime_Error_100324 = 100324,\n        Runtime_Error_100325 = 100325,\n        Runtime_Error_100326 = 100326,\n        Runtime_Error_100327 = 100327,\n        Runtime_Error_100328 = 100328,\n        Runtime_Error_100329 = 100329,\n        Runtime_Error_100330 = 100330,\n        Runtime_Error_100331 = 100331,\n        SiloBase = 100400,\n        SiloStarting = 100401,\n        SiloStarted = 100402,\n        SiloInitializing = 100403,\n        SiloGcSetting = 100404,\n        SiloGcWarning = 100405,\n        SiloSetDeploymentId = 100406,\n        SiloSetSiloEndpoint = 100407,\n        SiloSetProxyEndpoint = 100408,\n        SiloSetSeedNode = 100409,\n        SiloAddSeedNode = 100410,\n        SiloSetPrimaryNode = 100411,\n        SiloSetWorkingDir = 100412,\n        SiloStopped = 100413,\n        SiloStopping = 100414,\n        SiloInitConfig = 100415,\n        SiloDebugDump = 100416,\n        SiloShuttingDown = 100417,\n        SiloShutDown = 100418,\n        SiloFailedToStopMembership = 100419,\n        SiloIgnoreErrorDuringStop = 100420,\n        SiloCannotResetHeartbeatTimer = 100421,\n        SiloInitializingFinished = 100422,\n        SiloSetSiloType = 100423,\n        SiloStartupEventName = 100424,\n        SiloStartupEventCreated = 100425,\n        SiloStartupEventOpened = 100426,\n        SiloStopInProgress = 100427,\n        WaitingForSiloStop = 100428,\n        CannotCheckRoleEnvironment = 100429,\n        SiloConfiguredThreadPool = 100430,\n        SiloFailedToConfigureThreadPool = 100431,\n        SetSiloLivenessType = 100434,\n        SiloEndpointConfigError = 100435,\n        SiloConfiguredServicePointManager = 100436,\n        SiloCallingProviderInit = 100437,\n        SetReminderServiceType = 100438,\n        SiloStartError = 100439,\n        SiloConfigDeprecated = 100440,\n        SiloShutdownEventName = 100441,\n        SiloShutdownEventCreated = 100442,\n        SiloShutdownEventOpened = 100443,\n        SiloShutdownEventReceived = 100444,\n        SiloLoadedDI = 100445,\n        SiloFailedToLoadDI = 100446,\n        SiloFileNotFoundLoadingDI = 100447,\n        SiloStartupEventFailure = 100448,\n        SiloShutdownEventFailure = 100449,\n        LifecycleStartFailure = 100450,\n        LifecycleStopFailure = 100451,\n        SiloStartPerfMeasure = 100452,\n        LifecycleStagesReport = 100453,\n        CatalogBase = 100500,\n        CatalogNonExistingActivation1 = 100501,\n        Catalog_UnregisterManyAsync = 100502,\n        Catalog_DestroyActivations = 100503,\n        Catalog_UnknownActivation = 100504,\n        Catalog_ActivationException = 100505,\n        Catalog_GetApproximateSiloStatuses = 100506,\n        Catalog_BeforeCollection = 100507,\n        Catalog_AfterCollection = 100508,\n        Catalog_ShutdownActivations_1 = 100509,\n        CatalogNonExistingActivation2 = 100510,\n        Catalog_BeforeCallingActivate = 100511,\n        Catalog_AfterCallingActivate = 100512,\n        Catalog_ErrorCallingActivate = 100513,\n        Catalog_BeforeCallingDeactivate = 100514,\n        Catalog_AfterCallingDeactivate = 100515,\n        Catalog_ErrorCallingDeactivate = 100516,\n        Catalog_MissingTypeOnCreate = 100517,\n        Catalog_ResendDuplicateFailed = 100518,\n        Catalog_NullGetTypeAndStrategies = 100519,\n        Catalog_DuplicateActivation = 100520,\n        Catalog_RegistrationFailure = 100521,\n        Catalog_Warn_ActivationTooManyRequests = 100522,\n        Catalog_Reject_ActivationTooManyRequests = 100523,\n        Catalog_SiloStatusChangeNotification = 100524,\n        Catalog_SiloStatusChangeNotification_Exception = 100525,\n        Catalog_AttemptToCollectActivationEarly = 100526,\n        Catalog_DeactivateActivation_Exception = 100527,\n        Catalog_ActivationDirectory_Statistics = 100528,\n        Catalog_UnregisterMessageTarget1 = 100529,\n        Catalog_UnregisterMessageTarget2 = 100530,\n        Catalog_UnregisterMessageTarget3 = 100531,\n        Catalog_UnregisterMessageTarget4 = 100532,\n        Catalog_Failed_SetupActivationState = 100533,\n        Catalog_Failed_InvokeActivate = 100534,\n        Catalog_RerouteAllQueuedMessages = 100535,\n        Catalog_WaitForAllTimersToFinish_Exception = 100536,\n        Catalog_ActivationCollector_BadState_1 = 100537,\n        Catalog_ActivationCollector_BadState_2 = 100538,\n        Catalog_DestroyActivations_Done = 100539,\n        Catalog_ShutdownActivations_2 = 100540,\n        Catalog_ShutdownActivations_3 = 100541,\n        Catalog_DeactivateStreamResources_Exception = 100542,\n        Catalog_FinishDeactivateActivation_Exception = 100543,\n        Catalog_FinishGrainDeactivateAndCleanupStreams_Exception = 100544,\n        Catalog_DeactivateAllActivations = 100545,\n        Catalog_ActivationCollector_BadState_3 = 100546,\n        Catalog_UnregisterAsync = 100547,\n        MembershipBase = 100600,\n        MembershipNodeMigrated = 100601,\n        MembershipNodeRestarted = 100602,\n        MembershipStarting = 100603,\n        MembershipBecomeActive = 100604,\n        MembershipFinishBecomeActive = 100605,\n        MembershipShutDown = 100606,\n        MembershipStop = 100607,\n        MembershipReadTable = 100608,\n        MembershipKillMyself = 100609,\n        MembershipVotingForKill = 100610,\n        MembershipMarkingAsDead = 100611,\n        MembershipWatchList = 100612,\n        MembershipMissedPing = 100613,\n        MembershipSendingPreJoinPing = 100614,\n        MembershipFailedToWrite = 100615,\n        MembershipFailedToWriteConditional = 100616,\n        MembershipFoundMyselfDead1 = 100617,\n        MembershipFoundMyselfDead2 = 100618,\n        MembershipDetectedOlder = 100619,\n        MembershipDetectedNewer = 100620,\n        MembershipDelayedTableUpdateTimer = 100621,\n        MembershipDelayedProbeOtherSilosTimer = 100622,\n        MembershipFailedToReadSilo = 100623,\n        MembershipDelayedIAmAliveUpdateTimer = 100624,\n        MembershipMissedIAmAliveTableUpdate = 100625,\n        MembershipLocalSubscriberException = 100626,\n        MembershipKillMyselfLocally = 100627,\n        MembershipFoundMyselfDead3 = 100628,\n        MembershipMarkDeadWriteFailed = 100629,\n        MembershipTableGrainInit1 = 100630,\n        MembershipTableGrainInit2 = 100631,\n        MembershipTableGrainInit3 = 100632,\n        MembershipTableGrainInit4 = 100633,\n        MembershipReadAll_1 = 100634,\n        MembershipFactory1 = 100635,\n        MembershipFactory2 = 100636,\n        MembershipGrainBasedTable1 = 100637,\n        MembershipGrainBasedTable2 = 100638,\n        MembershipGrainBasedTable3 = 100639,\n        MembershipFileBasedTable1 = 100640,\n        MembershipFileBasedTable2 = 100641,\n        MembershipFileBasedTable3 = 100642,\n        MembershipFileBasedTable4 = 100643,\n        MembershipPingedSiloNotInWatchList = 100644,\n        MembershipReadAll_2 = 100645,\n        MembershipFailedToStart = 100646,\n        MembershipFailedToBecomeActive = 100647,\n        MembershipFailedToStop = 100648,\n        MembershipFailedToShutdown = 100649,\n        MembershipFailedToKillMyself = 100650,\n        MembershipFailedToSuspect = 100651,\n        MembershipReadAll_Cleanup = 100652,\n        MembershipShutDownFailure = 100653,\n        MembershipKillMyselfFailure = 100654,\n        MembershipGossipProcessingFailure = 100655,\n        MembershipGossipSendFailure = 100656,\n        MembershipTimerProcessingFailure = 100657,\n        MembershipSendPingFailure = 100658,\n        MembershipUpdateIAmAliveFailure = 100659,\n        MembershipStartingIAmAliveTimer = 100660,\n        MembershipJoiningPreconditionFailure = 100661,\n        MembershipCleanDeadEntriesFailure = 100662,\n        MembershipJoining = 100663,\n        MembershipFailedToJoin = 100664,\n        NSMembershipStarting = 100670,\n        NSMembershipBecomeActive = 100671,\n        NSMembershipFailedToBecomeActive = 100672,\n        NSMembershipShutDown = 100673,\n        NSMembershipStop = 100674,\n        NSMembershipKillMyself = 100675,\n        NSMembershipKillMyselfLocally = 100676,\n        NSMembershipNotificationProcessingFailure = 100677,\n        NSMembershipReadAll_1 = 100678,\n        NSMembershipReadAll_2 = 100679,\n        NSMembershipFoundMyselfDead2 = 100680,\n        NSMembershipDetectedOlder = 100681,\n        NSMembershipDetectedNewer = 100682,\n        NSMembershipTimerProcessingFailure = 100683,\n        NSMembershipShutDownFailure = 100684,\n        NSMembershipKillMyselfFailure = 100685,\n        NSMembershipNSDetails = 100686,\n        SSMT_ReadRowError = 100687,\n        SSMT_ReadAllError = 100688,\n        SSMT_InsertRowError = 100689,\n        SSMT_UpdateRowError = 100690,\n        SSMT_MergeRowError = 100691,\n        SSMT_EtagMismatch_Insert = 100692,\n        SSMT_EtagMismatch_Update = 100693,\n        PerfCounterBase = 100700,\n        PerfCounterNotFound = 100701,\n        PerfCounterStarting = 100702,\n        PerfCounterStopping = 100703,\n        PerfCounterDumpAll = 100704,\n        PerfCounterWriteErrors = 100705,\n        PerfCounterWriteSuccess = 100706,\n        PerfCounterWriteTooManyErrors = 100707,\n        PerfCounterNotRegistered = 100708,\n        PerfCounterUnableToConnect = 100709,\n        PerfCounterUnableToWrite = 100710,\n        PerfCounterWriting = 100711,\n        PerfCounterSkipping = 100712,\n        PerfMetricsStoppingTimer = 100713,\n        PerfMetricsStartingTimer = 100714,\n        PerfStatistics = 100715,\n        PerfCounterRegistering = 100716,\n        PerfCounterTimerError = 100717,\n        TimerChangeError = 100717,\n        PerfCounterCategoryCheckError = 100718,\n        PerfCounterConnectError = 100719,\n        PerfCounterFailedToInitialize = 100720,\n        ProxyClientBase = 100900,\n        ProxyClientUnhandledExceptionWhileSending = 100901,\n        ProxyClientUnhandledExceptionWhileReceiving = 100902,\n        ProxyClient_CannotSend = 100903,\n        ProxyClient_CannotSend_NoGateway = 100904,\n        ProxyClient_DroppingMsg = 100905,\n        ProxyClient_RejectingMsg = 100906,\n        ProxyClient_MsgSent = 100907,\n        ProxyClient_Connected = 100908,\n        ProxyClient_PauseBeforeRetry = 100909,\n        ProxyClient_MsgCtrNotRunning = 100910,\n        ProxyClient_DeadGateway = 100911,\n        ProxyClient_MarkGatewayDead = 100912,\n        ProxyClient_MarkGatewayDisconnected = 100913,\n        ProxyClient_GatewayConnStarted = 100914,\n        ProxyClient_CreatedGatewayUnordered = 100915,\n        ProxyClient_CreatedGatewayToGrain = 100916,\n        ProxyClient_NewBucketIndex = 100917,\n        ProxyClient_QueueRequest = 100918,\n        ProxyClient_ThreadAbort = 100919,\n        ProxyClient_OperationCancelled = 100920,\n        ProxyClient_GetGateways = 100921,\n        ProxyClient_NetworkError = 100922,\n        ProxyClient_SendException = 100923,\n        ProxyClient_OGC_TargetNotFound = 100924,\n        ProxyClient_OGC_SendResponseFailed = 100925,\n        ProxyClient_OGC_SendExceptionResponseFailed = 100926,\n        ProxyClient_OGC_UnhandledExceptionInOneWayInvoke = 100927,\n        ProxyClient_ClientInvokeCallback_Error = 100928,\n        ProxyClient_StartDone = 100929,\n        ProxyClient_OGC_TargetNotFound_2 = 100930,\n        ProxyClient_AppDomain_Unload = 100931,\n        ProxyClient_GatewayUnknownStatus = 100932,\n        ProxyClient_FailedToUnregisterCallback = 100933,\n        MessagingBase = 101000,\n        Messaging_IMA_DroppingConnection = 101001,\n        Messaging_Dispatcher_DiscardRejection = 101002,\n        MessagingBeginReceiveException = 101003,\n        MessagingBeginAcceptSocketException = 101004,\n        MessagingAcceptingSocketClosed = 101005,\n        MessagingEndAcceptSocketException = 101006,\n        MessagingUnexpectedSendError = 101007,\n        MessagingSendingRejection = 101008,\n        MessagingMessageFromUnknownActivation = 101009,\n        Messaging_IMA_OpenedListeningSocket = 101010,\n        Messaging_IMA_AcceptCallbackNullState = 101011,\n        Messaging_IMA_AcceptCallbackUnexpectedState = 101012,\n        Messaging_IMA_NewBeginReceiveException = 101013,\n        Messaging_Socket_ReceiveError = 101014,\n        Messaging_IMA_ClosingSocket = 101015,\n        Messaging_OutgoingMS_DroppingMessage = 101016,\n        MessagingProcessReceiveBufferException = 101017,\n        Messaging_LargeMsg_Outgoing = 101018,\n        Messaging_LargeMsg_Incoming = 101019,\n        Messaging_SiloNetworkError = 101020,\n        Messaging_UnableToGetSendingSocket = 101021,\n        Messaging_ExceptionSending = 101022,\n        Messaging_CountMismatchSending = 101023,\n        Messaging_ExceptionReceiving = 101024,\n        Messaging_ExceptionBeginReceiving = 101025,\n        Messaging_IMA_ExceptionAccepting = 101026,\n        Messaging_IMA_BadBufferReceived = 101027,\n        Messaging_IMA_ActivationOverloaded = 101028,\n        Messaging_SerializationError = 101029,\n        Messaging_UnableToDeserializeBody = 101030,\n        Messaging_Dispatcher_TryForward = 101031,\n        Messaging_Dispatcher_TryForwardFailed = 101032,\n        Messaging_Dispatcher_ForwardingRequests = 101033,\n        Messaging_SimulatedMessageLoss = 101034,\n        Messaging_Dispatcher_ReturnToOriginCluster = 101035,\n        MessagingAcceptAsyncSocketException = 101036,\n        Messaging_ExceptionReceiveAsync = 101037,\n        Messaging_DroppingExpiredMessage = 101038,\n        Messaging_DroppingBlockedMessage = 101039,\n        Messaging_Inbound_Enqueue = 101040,\n        Messaging_Inbound_Dequeue = 101041,\n        Messaging_Dispatcher_Rejected = 101042,\n        DirectoryBase = 101100,\n        DirectoryBothPrimaryAndBackupForGrain = 101101,\n        DirectoryPartitionPredecessorExpected = 101102,\n        DirectoryUnexpectedDelta = 101104,\n        Directory_SiloStatusChangeNotification_Exception = 101105,\n        SchedulerBase = 101200,\n        SchedulerWorkerPoolThreadQueueWaitTime = 101201,\n        SchedulerWorkItemGroupQueueWaitTime = 101202,\n        SchedulerStatistics = 101203,\n        SchedulerFinishShutdown = 101204,\n        SchedulerNullActivation = 101205,\n        SchedulerExceptionFromExecute = 101206,\n        SchedulerNullContext = 101207,\n        SchedulerTaskExecuteIncomplete1 = 101208,\n        WaitCalledInsideGrain = 101209,\n        SchedulerStatus = 101210,\n        WaitCalledInServerCode = 101211,\n        ExecutorTurnTooLong = 101212,\n        SchedulerTooManyPendingItems = 101213,\n        SchedulerTurnTooLong2 = 101214,\n        SchedulerTurnTooLong3 = 101215,\n        SchedulerWorkGroupShuttingDown = 101216,\n        SchedulerEnqueueWorkWhenShutdown = 101217,\n        SchedulerNotExecuteWhenShutdown = 101218,\n        SchedulerAppTurnsStopped_1 = 101219,\n        SchedulerWorkGroupStopping = 101220,\n        SchedulerSkipWorkStopping = 101221,\n        SchedulerSkipWorkCancelled = 101222,\n        SchedulerTaskRunningOnWrongScheduler1 = 101223,\n        SchedulerQueueWorkItemWrongCall = 101224,\n        SchedulerQueueTaskWrongCall = 101225,\n        SchedulerTaskExecuteIncomplete2 = 101226,\n        SchedulerTaskExecuteIncomplete3 = 101227,\n        SchedulerTaskExecuteIncomplete4 = 101228,\n        SchedulerTaskWaitIncomplete = 101229,\n        ExecutorWorkerThreadExc = 101230,\n        SchedulerQueueWorkItemWrongContext = 101231,\n        SchedulerAppTurnsStopped_2 = 101232,\n        ExecutorProcessingError = 101233,\n        GatewayBase = 101300,\n        GatewayClientOpenedSocket = 101301,\n        GatewayClientClosedSocket = 101302,\n        GatewayDroppingClient = 101303,\n        GatewayTryingToSendToUnrecognizedClient = 101304,\n        GatewayByteCountMismatch = 101305,\n        GatewayExceptionSendingToClient = 101306,\n        GatewayAcceptor_SocketClosed = 101307,\n        GatewayAcceptor_ExceptionReceiving = 101308,\n        GatewayManager_FoundKnownGateways = 101309,\n        MessageAcceptor_Connection = 101310,\n        MessageAcceptor_NotAProxiedConnection = 101311,\n        MessageAcceptor_UnexpectedProxiedConnection = 101312,\n        GatewayManager_NoGateways = 101313,\n        GatewayNetworkError = 101314,\n        GatewayFailedToParse = 101315,\n        ClientRegistrarFailedToRegister = 101316,\n        ClientRegistrarFailedToRegister_2 = 101317,\n        ClientRegistrarFailedToUnregister = 101318,\n        ClientRegistrarTimerFailed = 101319,\n        GatewayAcceptor_WrongClusterId = 101320,\n        GatewayManager_AllGatewaysDead = 101321,\n        GatewayAcceptor_InvalidSize = 101322,\n        TimerBase = 101400,\n        TimerDisposeError = 101401,\n        TimerStopError = 101402,\n        TimerQueueTickError = 101403,\n        TimerChanging = 101404,\n        TimerBeforeCallback = 101405,\n        TimerAfterCallback = 101406,\n        TimerNextTick = 101407,\n        TimerDisposing = 101408,\n        TimerStopped = 101409,\n        Timer_TimerInsideGrainIsNotTicking = 101410,\n        Timer_TimerInsideGrainIsDelayed = 101411,\n        Timer_SafeTimerIsNotTicking = 101412,\n        Timer_GrainTimerCallbackError = 101413,\n        Timer_InvalidContext = 101414,\n        DispatcherBase = 101500,\n        Dispatcher_SelectTarget_FailPending = 101501,\n        Dispatcher_RegisterCallback_Replaced = 101502,\n        Dispatcher_Send_BufferResponse = 101503,\n        Dispatcher_Send_AddressedMessage = 101504,\n        Dispatcher_Receive_InvalidActivation = 101505,\n        Dispatcher_WriteGrainFailed = 101506,\n        Dispatcher_ActivationEndedTurn_Waiting = 101507,\n        Dispatcher_Retarget = 101508,\n        Dispatcher_TryAcceptMessage = 101509,\n        Dispatcher_UpdateReceiveOrder = 101510,\n        Dispatcher_ReceiveOrderCorrelation = 101511,\n        Dispatcher_AddSendOrder = 101512,\n        Dispatcher_AddSendOrderNoPrior = 101513,\n        Dispatcher_AddSendOrder_PriorIds = 101514,\n        Dispatcher_AddSendOrder_First = 101515,\n        Dispatcher_EnqueueMessage = 101516,\n        Dispatcher_AddressMsg = 101517,\n        Dispatcher_AddressMsg_GrainOrder = 101518,\n        Dispatcher_AddressMsg_NullingLastSentTo = 101519,\n        Dispatcher_AddressMsg_SMPlacement = 101520,\n        Dispatcher_AddressMsg_UnregisteredClient = 101521,\n        Dispatcher_AddressMsg_SelectTarget = 101522,\n        Dispatcher_HandleMsg = 101523,\n        Dispatcher_OnActivationCompletedRequest_Waiting = 101524,\n        IGC_DisposeError = 101525,\n        IGC_SendRequest_NullContext = 101526,\n        IGC_SniffIncomingMessage_Exc = 101527,\n        Dispatcher_DetectedDeadlock = 101528,\n        Dispatcher_ActivationOverloaded = 101530,\n        IGC_SendResponseFailed = 101531,\n        IGC_SendExceptionResponseFailed = 101532,\n        IGC_UnhandledExceptionInInvoke = 101533,\n        Dispatcher_ExtendedMessageProcessing = 101534,\n        Dispatcher_FailedToUnregisterNonExistingAct = 101535,\n        Dispatcher_NoGrainInstance = 101536,\n        Dispatcher_RuntimeStatisticsUnavailable = 101537,\n        Dispatcher_InvalidActivation = 101538,\n        InvokeWorkItem_UnhandledExceptionInInvoke = 101539,\n        Dispatcher_ErrorCreatingActivation = 101540,\n        Dispatcher_StuckActivation = 101541,\n        Dispatcher_FailedToUnregisterCallback = 101542,\n        SerializationBase = 101600,\n        Ser_AssemblyLoadError = 101601,\n        Ser_BadRegisterSerializer = 101602,\n        Ser_AssemblyLoadErrorDetails = 101603,\n        Ser_AssemblyLoadSuccess = 101604,\n        Ser_LargeObjectAllocated = 101605,\n        LoaderBase = 101700,\n        Loader_AssemblyLookupFailed = 101701,\n        Loader_AssemblyLookupResolved = 101702,\n        Loader_LoadingFromDir = 101703,\n        Loader_LoadingFromFile = 101704,\n        Loader_DirNotFound = 101705,\n        Loader_LoadingSerInfo = 101706,\n        Loader_LoadingGrainType = 101707,\n        Loader_SkippingFile = 101708,\n        Loader_SkippingDynamicAssembly = 101709,\n        Loader_AssemblyInspectError = 101710,\n        Loader_GrainTypeFullList = 101711,\n        Loader_IgnoreAbstractGrainClass = 101712,\n        Loader_AssemblyInspectionError = 101713,\n        Loader_FoundBinary = 101714,\n        Loader_IgnoreNonPublicGrainClass = 101715,\n        Loader_UnexpectedException = 101716,\n        Loader_SkippingBadAssembly = 101717,\n        Loader_TypeLoadError_2 = 101718,\n        Loader_TypeLoadError_3 = 101719,\n        Loader_TypeLoadError_4 = 101720,\n        Loader_LoadAndCreateInstance_Failure = 101721,\n        Loader_TryLoadAndCreateInstance_Failure = 101722,\n        Loader_TypeLoadError_5 = 101723,\n        Loader_AssemblyLoadError = 101724,\n        PlacementBase = 101800,\n        Placement_RuntimeStatisticsUpdateFailure_1 = 101801,\n        Placement_RuntimeStatisticsUpdateFailure_2 = 101802,\n        Placement_RuntimeStatisticsUpdateFailure_3 = 101803,\n        Placement_ActivationCountBasedDirector_NoSilos = 101804,\n        StorageProviderBase = 102200,\n        StorageProvider_ReadFailed = 102202,\n        StorageProvider_WriteFailed = 102203,\n        StorageProvider_DeleteFailed = 102204,\n        StorageProvider_ForceReRead = 102205,\n        SerializationManagerBase = 102400,\n        SerMgr_TypeRegistrationFailure = 102401,\n        SerMgr_MissingRegisterMethod = 102402,\n        SerMgr_ErrorBindingMethods = 102403,\n        SerMgr_ErrorLoadingAssemblyTypes = 102404,\n        SerMgr_TooLongSerialize = 102405,\n        SerMgr_TooLongDeserialize = 102406,\n        SerMgr_TooLongDeepCopy = 102407,\n        SerMgr_IgnoreAssembly = 102408,\n        SerMgr_TypeRegistrationFailureIgnore = 102409,\n        SerMgr_ArtifactReport = 102410,\n        SerMgr_UnavailableSerializer = 102411,\n        SerMgr_SerializationMethodsMissing = 102412,\n        WatchdogBase = 102600,\n        Watchdog_ParticipantThrownException = 102601,\n        Watchdog_InternalError = 102602,\n        Watchdog_HealthCheckFailure = 102603,\n        LoggerBase = 102700,\n        Logger_LogMessageTruncated = 102701,\n        WFServiceBase = 102800,\n        WFService_Error_1 = 102801,\n        WFService_Error_2 = 102802,\n        WFService_Error_3 = 102803,\n        WFService_Error_4 = 102804,\n        WFService_Error_5 = 102805,\n        WFService_Error_6 = 102806,\n        WFService_Error_7 = 102807,\n        WFService_Error_8 = 102808,\n        WFService_Error_9 = 102809,\n        ReminderServiceBase = 102900,\n        RS_Register_TableError = 102905,\n        RS_Register_AlreadyRegistered = 102907,\n        RS_Register_InvalidPeriod = 102908,\n        RS_Register_NotRemindable = 102909,\n        RS_NotResponsible = 102910,\n        RS_Unregister_NotFoundLocally = 102911,\n        RS_Unregister_TableError = 102912,\n        RS_Table_Insert = 102913,\n        RS_Table_Remove = 102914,\n        RS_Tick_Delivery_Error = 102915,\n        RS_Not_Started = 102916,\n        RS_UnregisterGrain_TableError = 102917,\n        RS_GrainBasedTable1 = 102918,\n        RS_Factory1 = 102919,\n        RS_FailedToReadTableAndStartTimer = 102920,\n        RS_TableGrainInit1 = 102921,\n        RS_TableGrainInit2 = 102922,\n        RS_TableGrainInit3 = 102923,\n        RS_GrainBasedTable2 = 102924,\n        RS_ServiceStarting = 102925,\n        RS_ServiceStarted = 102926,\n        RS_ServiceStopping = 102927,\n        RS_RegisterOrUpdate = 102928,\n        RS_Unregister = 102929,\n        RS_Stop = 102930,\n        RS_RemoveFromTable = 102931,\n        RS_GetReminder = 102932,\n        RS_GetReminders = 102933,\n        RS_RangeChanged = 102934,\n        RS_LocalStop = 102935,\n        RS_Started = 102936,\n        RS_ServiceInitialLoadFailing = 102937,\n        RS_ServiceInitialLoadFailed = 102938,\n        RS_FastReminderInterval = 102939,\n        ConsistentRingProviderBase = 103000,\n        CRP_Local_Subscriber_Exception = 103001,\n        CRP_ForGrains_Local_Subscriber_Exception_1 = 103002,\n        CRP_Added_Silo = 103003,\n        CRP_Removed_Silo = 103004,\n        CRP_Notify = 103005,\n        CRP_ForGrains_Local_Subscriber_Exception_2 = 103006,\n        ProviderManagerBase = 103100,\n        Provider_InstanceConstructionError1 = 103101,\n        Provider_Loaded = 103102,\n        Provider_AssemblyLoadError = 103103,\n        Provider_CatalogNoStorageProvider_1 = 103104,\n        Provider_CatalogNoStorageProvider_2 = 103105,\n        Provider_CatalogStorageProviderAllocated = 103106,\n        Provider_NoDefaultProvider = 103107,\n        Provider_ConfiguredProviderNotLoaded = 103108,\n        Provider_ErrorFromInit = 103109,\n        Provider_IgnoringExplicitSet = 103110,\n        Provider_NotLoaded = 103111,\n        Provider_Manager_Already_Loaded = 103112,\n        Provider_CatalogNoStorageProvider_3 = 103113,\n        Provider_ProviderLoadedOk = 103114,\n        Provider_ProviderNotFound = 103115,\n        Provider_ProviderNotControllable = 103116,\n        Provider_CatalogNoLogConsistencyProvider = 103117,\n        Provider_CatalogLogConsistencyProviderAllocated = 103118,\n        Provider_ErrorFromClose = 103119,\n        PersistentStreamPullingAgentBase = 103300,\n        PersistentStreamPullingAgent_01 = 103301,\n        PersistentStreamPullingAgent_02 = 103302,\n        PersistentStreamPullingAgent_03 = 103303,\n        PersistentStreamPullingAgent_04 = 103304,\n        PersistentStreamPullingAgent_05 = 103305,\n        PersistentStreamPullingAgent_06 = 103306,\n        PersistentStreamPullingAgent_07 = 103307,\n        PersistentStreamPullingAgent_08 = 103308,\n        PersistentStreamPullingAgent_09 = 103309,\n        PersistentStreamPullingAgent_10 = 103310,\n        PersistentStreamPullingAgent_11 = 103311,\n        PersistentStreamPullingAgent_12 = 103312,\n        PersistentStreamPullingAgent_13 = 103313,\n        PersistentStreamPullingAgent_14 = 103314,\n        PersistentStreamPullingAgent_15 = 103315,\n        PersistentStreamPullingAgent_16 = 103316,\n        PersistentStreamPullingAgent_17 = 103317,\n        PersistentStreamPullingAgent_18 = 103318,\n        PersistentStreamPullingAgent_19 = 103319,\n        PersistentStreamPullingAgent_20 = 103320,\n        PersistentStreamPullingAgent_21 = 103321,\n        PersistentStreamPullingAgent_22 = 103322,\n        PersistentStreamPullingAgent_23 = 103323,\n        PersistentStreamPullingAgent_24 = 103324,\n        PersistentStreamPullingAgent_25 = 103325,\n        PersistentStreamPullingAgent_26 = 103326,\n        PersistentStreamPullingAgent_27 = 103327,\n        PersistentStreamPullingAgent_28 = 103328,\n        StreamProviderManagerBase = 103400,\n        StreamProvider_FailedToDispose = 103401,\n        StreamProvider_ProducerFailedToUnregister = 103402,\n        StreamProvider_NoStreamForItem = 103403,\n        StreamProvider_AddObserverException = 103404,\n        Stream_ExtensionNotInstalled = 103405,\n        Stream_ProducerIsDead = 103406,\n        StreamProvider_NoStreamForBatch = 103407,\n        StreamProvider_ConsumerFailedToUnregister = 103408,\n        Stream_ConsumerIsDead = 103409,\n        Stream_RegisterProducerFailed = 103410,\n        Stream_UnregisterProducerFailed = 103411,\n        Stream_RegisterConsumerFailed = 103412,\n        Stream_UnregisterConsumerFailed = 103413,\n        Stream_SetSubscriptionToFaultedFailed = 103414,\n        PersistentStreamPullingManagerBase = 103500,\n        PersistentStreamPullingManager_01 = 103501,\n        PersistentStreamPullingManager_02 = 103502,\n        PersistentStreamPullingManager_03 = 103503,\n        PersistentStreamPullingManager_04 = 103504,\n        PersistentStreamPullingManager_05 = 103505,\n        PersistentStreamPullingManager_06 = 103506,\n        PersistentStreamPullingManager_07 = 103507,\n        PersistentStreamPullingManager_08 = 103508,\n        PersistentStreamPullingManager_09 = 103509,\n        PersistentStreamPullingManager_10 = 103510,\n        PersistentStreamPullingManager_11 = 103511,\n        PersistentStreamPullingManager_12 = 103512,\n        PersistentStreamPullingManager_13 = 103513,\n        PersistentStreamPullingManager_14 = 103514,\n        PersistentStreamPullingManager_15 = 103515,\n        PersistentStreamPullingManager_16 = 103516,\n        PersistentStreamPullingManager_Starting = 103517,\n        PersistentStreamPullingManager_Stopping = 103518,\n        PersistentStreamPullingManager_Started = 103519,\n        PersistentStreamPullingManager_Stopped = 103520,\n        PersistentStreamPullingManager_AlreadyStarted = 103521,\n        PersistentStreamPullingManager_AlreadyStopped = 103522,\n        PersistentStreamPullingManager_PeriodicPrint = 103523,\n        AzureServiceRuntimeWrapper = 103700,\n        AzureServiceRuntime_NotLoaded = 103701,\n        AzureServiceRuntime_FailedToLoad = 103702,\n        CodeGenBase = 103800,\n        CodeGenCompilationFailed = 103801,\n        CodeGenCompilationSucceeded = 103802,\n        CodeGenSourceGenerated = 103803,\n        CodeGenSerializerGenerator = 103804,\n        CodeGenIgnoringTypes = 103805,\n        CodeGenDllMissing = 103806,\n        CodeGenSystemTypeRequiresSerializer = 103807,\n        MultiClusterNetworkBase = 103900,\n        MultiClusterNetwork_Starting = 103901,\n        MultiClusterNetwork_Started = 103902,\n        MultiClusterNetwork_FailedToStart = 103903,\n        MultiClusterNetwork_LocalSubscriberException = 103904,\n        MultiClusterNetwork_GossipCommunicationFailure = 103905,\n        MultiClusterNetwork_NoChannelsConfigured = 103906,\n        CancellationTokenManagerBase = 104000,\n        CancellationTokenCancelFailed = 104001,\n        CancellationExtensionCreationFailed = 104002,\n        GlobalSingleInstanceBase = 104100,\n        GlobalSingleInstance_ProtocolError = 104101,\n        GlobalSingleInstance_WarningInvalidOrigin = 104102,\n        GlobalSingleInstance_MaintainerException = 104103,\n        GlobalSingleInstance_MultipleOwners = 104104,\n        TypeManagerBase = 104200,\n        TypeManager_GetSiloGrainInterfaceMapError = 104201,\n        TypeManager_GetClusterGrainTypeResolverError = 104202,\n        LogConsistencyBase = 104300,\n        LogConsistency_UserCodeException = 104301,\n        LogConsistency_CaughtException = 104302,\n        LogConsistency_ProtocolError = 104303,\n        LogConsistency_ProtocolFatalError = 104304,\n        ServiceFabricBase = 104400,\n        TransactionsBase = 104500,\n        Transactions_SendingTMRequest = 104501,\n        Transactions_ReceivedTMResponse = 104502,\n        Transactions_TMError = 104503,\n        OSBase = 104600,\n        OS_InvalidOS = 104601\n    }\n\n    public abstract partial class Grain : IGrainBase, Runtime.IAddressable\n    {\n        protected Grain() { }\n\n        protected Grain(Runtime.IGrainContext grainContext, Runtime.IGrainRuntime? grainRuntime = null) { }\n\n        public Runtime.IGrainContext GrainContext { get { throw null; } }\n\n        protected IGrainFactory GrainFactory { get { throw null; } }\n\n        public Runtime.GrainReference GrainReference { get { throw null; } }\n\n        public string IdentityString { get { throw null; } }\n\n        public string RuntimeIdentity { get { throw null; } }\n\n        protected internal System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        protected void DeactivateOnIdle() { }\n\n        protected void DelayDeactivation(System.TimeSpan timeSpan) { }\n\n        protected void MigrateOnIdle() { }\n\n        public virtual System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public virtual System.Threading.Tasks.Task OnDeactivateAsync(DeactivationReason reason, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        [System.Obsolete(\"Use 'this.RegisterGrainTimer(callback, state, new() { DueTime = dueTime, Period = period, Interleave = true })' instead.\")]\n        protected System.IDisposable RegisterTimer(System.Func<object?, System.Threading.Tasks.Task> callback, object? state, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n    }\n\n    public static partial class GrainBaseExtensions\n    {\n        public static void DeactivateOnIdle(this IGrainBase grain) { }\n\n        public static void MigrateOnIdle(this IGrainBase grain) { }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer(this IGrainBase grain, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, Runtime.GrainTimerCreationOptions options) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer(this IGrainBase grain, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer(this IGrainBase grain, System.Func<System.Threading.Tasks.Task> callback, Runtime.GrainTimerCreationOptions options) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer(this IGrainBase grain, System.Func<System.Threading.Tasks.Task> callback, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, System.Func<TState, System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, TState state, Runtime.GrainTimerCreationOptions options) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, System.Func<TState, System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, TState state, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, System.Func<TState, System.Threading.Tasks.Task> callback, TState state, Runtime.GrainTimerCreationOptions options) { throw null; }\n\n        public static Runtime.IGrainTimer RegisterGrainTimer<TState>(this IGrainBase grain, System.Func<TState, System.Threading.Tasks.Task> callback, TState state, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n    }\n\n    public delegate System.Threading.Tasks.Task GrainCallFilterDelegate(IGrainCallContext context);\n    [Immutable]\n    public sealed partial class GrainCancellationToken : System.IDisposable\n    {\n        internal GrainCancellationToken() { }\n\n        public System.Threading.CancellationToken CancellationToken { get { throw null; } }\n\n        public void Dispose() { }\n    }\n\n    public sealed partial class GrainCancellationTokenSource : System.IDisposable\n    {\n        public bool IsCancellationRequested { get { throw null; } }\n\n        public GrainCancellationToken Token { get { throw null; } }\n\n        public System.Threading.Tasks.Task Cancel() { throw null; }\n\n        public void Dispose() { }\n    }\n\n    public static partial class GrainContextComponentExtensions\n    {\n        public static TComponent GetGrainExtension<TComponent>(this Runtime.IGrainContext context)\n            where TComponent : class, Runtime.IGrainExtension { throw null; }\n    }\n\n    public static partial class GrainExtensions\n    {\n        public static object AsReference(this Runtime.IAddressable grain, System.Type interfaceType) { throw null; }\n\n        public static TGrainInterface AsReference<TGrainInterface>(this Runtime.IAddressable grain) { throw null; }\n\n        public static object Cast(this Runtime.IAddressable grain, System.Type interfaceType) { throw null; }\n\n        public static TGrainInterface Cast<TGrainInterface>(this Runtime.IAddressable grain) { throw null; }\n\n        public static Runtime.GrainId GetGrainId(this Runtime.IAddressable grain) { throw null; }\n\n        public static System.Guid GetPrimaryKey(this Runtime.IAddressable grain, out string? keyExt) { throw null; }\n\n        public static System.Guid GetPrimaryKey(this Runtime.IAddressable grain) { throw null; }\n\n        public static long GetPrimaryKeyLong(this Runtime.IAddressable grain, out string? keyExt) { throw null; }\n\n        public static long GetPrimaryKeyLong(this Runtime.IAddressable grain) { throw null; }\n\n        public static string GetPrimaryKeyString(this Runtime.IAddressable grain) { throw null; }\n\n        public static bool IsPrimaryKeyBasedOnLong(this Runtime.IAddressable grain) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class GrainTypeAttribute : System.Attribute, Metadata.IGrainTypeProviderAttribute\n    {\n        public GrainTypeAttribute(string grainType) { }\n\n        public Runtime.GrainType GetGrainType(System.IServiceProvider services, System.Type type) { throw null; }\n    }\n\n    public partial class Grain<TGrainState> : Grain\n    {\n        protected Grain() { }\n\n        protected Grain(Core.IStorage<TGrainState> storage) { }\n\n        protected TGrainState State { get { throw null; } set { } }\n\n        protected virtual System.Threading.Tasks.Task ClearStateAsync() { throw null; }\n\n        protected virtual System.Threading.Tasks.Task ReadStateAsync() { throw null; }\n\n        protected virtual System.Threading.Tasks.Task WriteStateAsync() { throw null; }\n    }\n\n    public partial interface IConfigurationValidator\n    {\n        void ValidateConfiguration();\n    }\n\n    public partial interface IGrain : Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainBase\n    {\n        Runtime.IGrainContext GrainContext { get; }\n\n        System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken token);\n        System.Threading.Tasks.Task OnDeactivateAsync(DeactivationReason reason, System.Threading.CancellationToken token);\n    }\n\n    public partial interface IGrainCallContext\n    {\n        object Grain { get; }\n\n        System.Reflection.MethodInfo InterfaceMethod { get; }\n\n        string InterfaceName { get; }\n\n        Runtime.GrainInterfaceType InterfaceType { get; }\n\n        string MethodName { get; }\n\n        Serialization.Invocation.IInvokable Request { get; }\n\n        Serialization.Invocation.Response? Response { get; set; }\n\n        object? Result { get; set; }\n\n        Runtime.GrainId? SourceId { get; }\n\n        Runtime.GrainId TargetId { get; }\n\n        System.Threading.Tasks.Task Invoke();\n    }\n\n    public partial interface IGrainFactory\n    {\n        TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj)\n            where TGrainObserverInterface : IGrainObserver;\n        void DeleteObjectReference<TGrainObserverInterface>(IGrainObserver obj)\n            where TGrainObserverInterface : IGrainObserver;\n        Runtime.IAddressable GetGrain(Runtime.GrainId grainId, Runtime.GrainInterfaceType interfaceType);\n        Runtime.IAddressable GetGrain(Runtime.GrainId grainId);\n        IGrain GetGrain(System.Type grainInterfaceType, System.Guid grainPrimaryKey, string keyExtension);\n        IGrain GetGrain(System.Type grainInterfaceType, System.Guid grainPrimaryKey);\n        IGrain GetGrain(System.Type grainInterfaceType, long grainPrimaryKey, string keyExtension);\n        IGrain GetGrain(System.Type grainInterfaceType, long grainPrimaryKey);\n        IGrain GetGrain(System.Type grainInterfaceType, string grainPrimaryKey);\n        TGrainInterface GetGrain<TGrainInterface>(Runtime.GrainId grainId)\n            where TGrainInterface : Runtime.IAddressable;\n        TGrainInterface GetGrain<TGrainInterface>(System.Guid primaryKey, string keyExtension, string? grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey;\n        TGrainInterface GetGrain<TGrainInterface>(System.Guid primaryKey, string? grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidKey;\n        TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string? grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey;\n        TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string? grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerKey;\n        TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string? grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey;\n    }\n\n    public partial interface IGrainObserver : Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainWithGuidCompoundKey : IGrain, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainWithGuidKey : IGrain, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainWithIntegerCompoundKey : IGrain, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainWithIntegerKey : IGrain, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainWithStringKey : IGrain, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IIncomingGrainCallContext : IGrainCallContext\n    {\n        System.Reflection.MethodInfo ImplementationMethod { get; }\n\n        Runtime.IGrainContext TargetContext { get; }\n    }\n\n    public partial interface IIncomingGrainCallFilter\n    {\n        System.Threading.Tasks.Task Invoke(IIncomingGrainCallContext context);\n    }\n\n    public partial interface ILifecycleObservable\n    {\n        System.IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer);\n    }\n\n    public partial interface ILifecycleObserver\n    {\n        System.Threading.Tasks.Task OnStart(System.Threading.CancellationToken cancellationToken = default);\n        System.Threading.Tasks.Task OnStop(System.Threading.CancellationToken cancellationToken = default);\n    }\n\n    public partial interface ILifecycleParticipant<TLifecycleObservable>\n        where TLifecycleObservable : ILifecycleObservable\n    {\n        void Participate(TLifecycleObservable lifecycle);\n    }\n\n    public partial interface ILifecycleSubject : ILifecycleObservable, ILifecycleObserver\n    {\n    }\n\n    public delegate System.Threading.Tasks.Task IncomingGrainCallFilterDelegate(IIncomingGrainCallContext context);\n    public partial interface IOutgoingGrainCallContext : IGrainCallContext\n    {\n        Runtime.IGrainContext? SourceContext { get; }\n    }\n\n    public partial interface IOutgoingGrainCallFilter\n    {\n        System.Threading.Tasks.Task Invoke(IOutgoingGrainCallContext context);\n    }\n\n    public partial interface ISystemTarget : Runtime.IAddressable\n    {\n    }\n\n    public partial interface IVersionManager\n    {\n        System.Threading.Tasks.Task SetCompatibilityStrategy(Runtime.GrainInterfaceType interfaceType, Versions.Compatibility.CompatibilityStrategy strategy);\n        System.Threading.Tasks.Task SetCompatibilityStrategy(Versions.Compatibility.CompatibilityStrategy strategy);\n        System.Threading.Tasks.Task SetSelectorStrategy(Runtime.GrainInterfaceType interfaceType, Versions.Selector.VersionSelectorStrategy strategy);\n        System.Threading.Tasks.Task SetSelectorStrategy(Versions.Selector.VersionSelectorStrategy strategy);\n    }\n\n    public static partial class LifecycleExtensions\n    {\n        public static System.IDisposable Subscribe(this ILifecycleObservable observable, int stage, ILifecycleObserver observer) { throw null; }\n\n        public static System.IDisposable Subscribe(this ILifecycleObservable observable, string observerName, int stage, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> onStart, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task>? onStop) { throw null; }\n\n        public static System.IDisposable Subscribe(this ILifecycleObservable observable, string observerName, int stage, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> onStart) { throw null; }\n\n        public static System.IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, ILifecycleObserver observer) { throw null; }\n\n        public static System.IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> onStart, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> onStop) { throw null; }\n\n        public static System.IDisposable Subscribe<TObserver>(this ILifecycleObservable observable, int stage, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> onStart) { throw null; }\n    }\n\n    public delegate System.Threading.Tasks.Task OutgoingGrainCallFilterDelegate(IOutgoingGrainCallContext context);\n    public static partial class PublicOrleansTaskExtensions\n    {\n        public static void Ignore(this System.Threading.Tasks.Task task) { }\n    }\n\n    public static partial class StableHash\n    {\n        public static uint ComputeHash(System.ReadOnlySpan<byte> data) { throw null; }\n\n        public static uint ComputeHash(string data) { throw null; }\n    }\n}\n\nnamespace Orleans.CodeGeneration\n{\n    [System.Flags]\n    [GenerateSerializer]\n    public enum InvokeMethodOptions\n    {\n        None = 0,\n        OneWay = 1,\n        ReadOnly = 2,\n        AlwaysInterleave = 4,\n        Unordered = 8\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Interface)]\n    public sealed partial class VersionAttribute : System.Attribute, Metadata.IGrainInterfacePropertiesProviderAttribute\n    {\n        public VersionAttribute(ushort version) { }\n\n        public ushort Version { get { throw null; } }\n\n        void Metadata.IGrainInterfacePropertiesProviderAttribute.Populate(System.IServiceProvider services, System.Type type, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n}\n\nnamespace Orleans.Concurrency\n{\n    [InvokableCustomInitializer(\"AddInvokeMethodOptions\", CodeGeneration.InvokeMethodOptions.AlwaysInterleave)]\n    [System.AttributeUsage(System.AttributeTargets.Method)]\n    public sealed partial class AlwaysInterleaveAttribute : System.Attribute\n    {\n    }\n\n    public static partial class ImmutableExtensions\n    {\n        public static Immutable<T> AsImmutable<T>(this T value) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct Immutable<T>\n    {\n        [Id(0)]\n        public readonly T Value;\n        public Immutable(T value) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class MayInterleaveAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public MayInterleaveAttribute(string callbackMethodName) { }\n\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [InvokableCustomInitializer(\"AddInvokeMethodOptions\", CodeGeneration.InvokeMethodOptions.OneWay)]\n    [System.AttributeUsage(System.AttributeTargets.Method)]\n    public sealed partial class OneWayAttribute : System.Attribute\n    {\n    }\n\n    [InvokableCustomInitializer(\"AddInvokeMethodOptions\", CodeGeneration.InvokeMethodOptions.ReadOnly)]\n    [System.AttributeUsage(System.AttributeTargets.Method)]\n    public sealed partial class ReadOnlyAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class ReentrantAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class StatelessWorkerAttribute : Placement.PlacementAttribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public StatelessWorkerAttribute() : base(default!) { }\n\n        public StatelessWorkerAttribute(int maxLocalWorkers, bool removeIdleWorkers) : base(default!) { }\n\n        public StatelessWorkerAttribute(int maxLocalWorkers) : base(default!) { }\n\n        public override void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Interface)]\n    public sealed partial class UnorderedAttribute : System.Attribute\n    {\n    }\n}\n\nnamespace Orleans.Core\n{\n    public partial interface IStorage\n    {\n        string? Etag { get; }\n\n        bool RecordExists { get; }\n\n        System.Threading.Tasks.Task ClearStateAsync();\n        System.Threading.Tasks.Task ClearStateAsync(System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.Task ReadStateAsync();\n        System.Threading.Tasks.Task ReadStateAsync(System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.Task WriteStateAsync();\n        System.Threading.Tasks.Task WriteStateAsync(System.Threading.CancellationToken cancellationToken);\n    }\n\n    public partial interface IStorage<TState> : IStorage\n    {\n        TState State { get; set; }\n    }\n}\n\nnamespace Orleans.Core.Internal\n{\n    public partial interface ICallChainReentrantGrainContext\n    {\n        void OnEnterReentrantSection(System.Guid reentrancyId);\n        void OnExitReentrantSection(System.Guid reentrancyId);\n    }\n\n    public partial interface IGrainManagementExtension : Runtime.IGrainExtension, Runtime.IAddressable\n    {\n        System.Threading.Tasks.ValueTask DeactivateOnIdle();\n        System.Threading.Tasks.ValueTask MigrateOnIdle();\n    }\n}\n\nnamespace Orleans.GrainDirectory\n{\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class GrainDirectoryAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public const string DEFAULT_GRAIN_DIRECTORY = \"default\";\n        public GrainDirectoryAttribute() { }\n\n        public GrainDirectoryAttribute(string grainDirectoryName) { }\n\n        public string GrainDirectoryName { get { throw null; } set { } }\n\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public partial interface IGrainDirectory\n    {\n        System.Threading.Tasks.Task<Runtime.GrainAddress?> Lookup(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address, Runtime.GrainAddress? previousAddress);\n        System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address);\n        System.Threading.Tasks.Task Unregister(Runtime.GrainAddress address);\n        System.Threading.Tasks.Task UnregisterSilos(System.Collections.Generic.List<Runtime.SiloAddress> siloAddresses);\n    }\n}\n\nnamespace Orleans.Metadata\n{\n    public sealed partial class AttributeGrainBindingsProvider : IGrainPropertiesProvider\n    {\n        public AttributeGrainBindingsProvider(System.IServiceProvider serviceProvider) { }\n\n        public void Populate(System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public sealed partial class AttributeGrainPropertiesProvider : IGrainPropertiesProvider\n    {\n        public AttributeGrainPropertiesProvider(System.IServiceProvider serviceProvider) { }\n\n        public void Populate(System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public partial class AttributeGrainTypeProvider : IGrainTypeProvider\n    {\n        public AttributeGrainTypeProvider(System.IServiceProvider serviceProvider) { }\n\n        public bool TryGetGrainType(System.Type grainClass, out Runtime.GrainType grainType) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class ClusterManifest\n    {\n        public ClusterManifest(MajorMinorVersion version, System.Collections.Immutable.ImmutableDictionary<Runtime.SiloAddress, GrainManifest> silos) { }\n\n        [Id(2)]\n        public System.Collections.Immutable.ImmutableArray<GrainManifest> AllGrainManifests { get { throw null; } }\n\n        [Id(1)]\n        public System.Collections.Immutable.ImmutableDictionary<Runtime.SiloAddress, GrainManifest> Silos { get { throw null; } }\n\n        [Id(0)]\n        public MajorMinorVersion Version { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Interface, AllowMultiple = false)]\n    public sealed partial class DefaultGrainTypeAttribute : System.Attribute, IGrainInterfacePropertiesProviderAttribute\n    {\n        public DefaultGrainTypeAttribute(string grainType) { }\n\n        void IGrainInterfacePropertiesProviderAttribute.Populate(System.IServiceProvider services, System.Type type, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class GrainInterfaceProperties\n    {\n        public GrainInterfaceProperties(System.Collections.Immutable.ImmutableDictionary<string, string> values) { }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableDictionary<string, string> Properties { get { throw null; } }\n\n        public string ToDetailedString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class GrainManifest\n    {\n        public GrainManifest(System.Collections.Immutable.ImmutableDictionary<Runtime.GrainType, GrainProperties> grains, System.Collections.Immutable.ImmutableDictionary<Runtime.GrainInterfaceType, GrainInterfaceProperties> interfaces) { }\n\n        [Id(1)]\n        public System.Collections.Immutable.ImmutableDictionary<Runtime.GrainType, GrainProperties> Grains { get { throw null; } }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableDictionary<Runtime.GrainInterfaceType, GrainInterfaceProperties> Interfaces { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class GrainProperties\n    {\n        public GrainProperties(System.Collections.Immutable.ImmutableDictionary<string, string> values) { }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableDictionary<string, string> Properties { get { throw null; } }\n\n        public string ToDetailedString() { throw null; }\n    }\n\n    public partial interface IGrainBindingsProviderAttribute\n    {\n        System.Collections.Generic.IEnumerable<System.Collections.Generic.Dictionary<string, string>> GetBindings(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType);\n    }\n\n    public partial interface IGrainInterfacePropertiesProvider\n    {\n        void Populate(System.Type interfaceType, Runtime.GrainInterfaceType grainInterfaceType, System.Collections.Generic.Dictionary<string, string> properties);\n    }\n\n    public partial interface IGrainInterfacePropertiesProviderAttribute\n    {\n        void Populate(System.IServiceProvider services, System.Type interfaceType, System.Collections.Generic.Dictionary<string, string> properties);\n    }\n\n    public partial interface IGrainPropertiesProvider\n    {\n        void Populate(System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties);\n    }\n\n    public partial interface IGrainPropertiesProviderAttribute\n    {\n        void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties);\n    }\n\n    public partial interface IGrainTypeProvider\n    {\n        bool TryGetGrainType(System.Type type, out Runtime.GrainType grainType);\n    }\n\n    public partial interface IGrainTypeProviderAttribute\n    {\n        Runtime.GrainType GetGrainType(System.IServiceProvider services, System.Type type);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct MajorMinorVersion : System.IComparable<MajorMinorVersion>, System.IEquatable<MajorMinorVersion>\n    {\n        private readonly int _dummyPrimitive;\n        public MajorMinorVersion(long majorVersion, long minorVersion) { }\n\n        [Id(0)]\n        public long Major { get { throw null; } }\n\n        [Id(1)]\n        public long Minor { get { throw null; } }\n\n        public static MajorMinorVersion MinValue { get { throw null; } }\n\n        public static MajorMinorVersion Zero { get { throw null; } }\n\n        public readonly int CompareTo(MajorMinorVersion other) { throw null; }\n\n        public readonly bool Equals(MajorMinorVersion other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static bool operator >(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static bool operator >=(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static bool operator !=(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static bool operator <(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static bool operator <=(MajorMinorVersion left, MajorMinorVersion right) { throw null; }\n\n        public static MajorMinorVersion Parse(string value) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public static partial class WellKnownGrainInterfaceProperties\n    {\n        public const string DefaultGrainType = \"primary-grain-type\";\n        public const string TypeName = \"type-name\";\n        public const string Version = \"version\";\n    }\n\n    public static partial class WellKnownGrainTypeProperties\n    {\n        public const string BindingPrefix = \"binding\";\n        public const string BindingTypeKey = \"type\";\n        public const string BroadcastChannelBindingPatternKey = \"channel-pattern\";\n        public const string BroadcastChannelBindingTypeValue = \"broadcast-channel\";\n        public const string ChannelIdMapperKey = \"channelid-mapper\";\n        public const string FullTypeName = \"full-type-name\";\n        public const string GrainDirectory = \"directory-policy\";\n        public const string IdleDeactivationPeriod = \"idle-duration\";\n        public const string Immovable = \"immovable\";\n        public const string ImplementedInterfacePrefix = \"interface.\";\n        public const string IndefiniteIdleDeactivationPeriodValue = \"indefinite\";\n        public const string LegacyGrainKeyType = \"legacy-grain-key-type\";\n        public const string MayInterleavePredicate = \"may-interleave-predicate\";\n        public const string PlacementFilter = \"placement-filter\";\n        public const string PlacementStrategy = \"placement-strategy\";\n        public const string Reentrant = \"reentrant\";\n        public const string StreamBindingIncludeNamespaceKey = \"include-namespace\";\n        public const string StreamBindingPatternKey = \"pattern\";\n        public const string StreamBindingTypeValue = \"stream\";\n        public const string StreamIdMapperKey = \"streamid-mapper\";\n        public const string TypeName = \"type-name\";\n        public const string Unordered = \"unordered\";\n    }\n}\n\nnamespace Orleans.Placement\n{\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class ActivationCountBasedPlacementAttribute : PlacementAttribute\n    {\n        public ActivationCountBasedPlacementAttribute() : base(default!) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class HashBasedPlacementAttribute : PlacementAttribute\n    {\n        public HashBasedPlacementAttribute() : base(default!) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class ImmovableAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        public ImmovableAttribute(ImmovableKind kind = ImmovableKind.Any) { }\n\n        public ImmovableKind Kind { get { throw null; } }\n\n        public void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [System.Flags]\n    public enum ImmovableKind : byte\n    {\n        Repartitioner = 1,\n        Rebalancer = 2,\n        Any = 3\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public abstract partial class PlacementAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        protected PlacementAttribute(Runtime.PlacementStrategy placement) { }\n\n        public Runtime.PlacementStrategy PlacementStrategy { get { throw null; } }\n\n        public virtual void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public abstract partial class PlacementFilterAttribute : System.Attribute, Metadata.IGrainPropertiesProviderAttribute\n    {\n        protected PlacementFilterAttribute(PlacementFilterStrategy placement) { }\n\n        public PlacementFilterStrategy PlacementFilterStrategy { get { throw null; } }\n\n        public virtual void Populate(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    public abstract partial class PlacementFilterStrategy\n    {\n        protected PlacementFilterStrategy(int order) { }\n\n        public int Order { get { throw null; } }\n\n        public virtual void AdditionalInitialize(Metadata.GrainProperties properties) { }\n\n        protected virtual System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> GetAdditionalGrainProperties(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.IReadOnlyDictionary<string, string> existingProperties) { throw null; }\n\n        protected string? GetPlacementFilterGrainProperty(string key, Metadata.GrainProperties properties) { throw null; }\n\n        public void Initialize(Metadata.GrainProperties properties) { }\n\n        public void PopulateGrainProperties(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class PreferLocalPlacementAttribute : PlacementAttribute\n    {\n        public PreferLocalPlacementAttribute() : base(default!) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class RandomPlacementAttribute : PlacementAttribute\n    {\n        public RandomPlacementAttribute() : base(default!) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class ResourceOptimizedPlacementAttribute : PlacementAttribute\n    {\n        public ResourceOptimizedPlacementAttribute() : base(default!) { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    public sealed partial class SiloRoleBasedPlacementAttribute : PlacementAttribute\n    {\n        public SiloRoleBasedPlacementAttribute() : base(default!) { }\n    }\n}\n\nnamespace Orleans.Providers\n{\n    public partial interface IProviderBuilder<TBuilder>\n    {\n        void Configure(TBuilder builder, string? name, Microsoft.Extensions.Configuration.IConfigurationSection configurationSection);\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class LogConsistencyProviderAttribute : System.Attribute\n    {\n        public string ProviderName { get { throw null; } set { } }\n    }\n\n    public static partial class ProviderConstants\n    {\n        public const string DEFAULT_LOG_CONSISTENCY_PROVIDER_NAME = \"Default\";\n        public const string DEFAULT_PUBSUB_PROVIDER_NAME = \"PubSubStore\";\n        public const string DEFAULT_STORAGE_PROVIDER_NAME = \"Default\";\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class StorageProviderAttribute : System.Attribute\n    {\n        public string ProviderName { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Runtime\n{\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class ActivationCountBasedPlacement : PlacementStrategy\n    {\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [System.Text.Json.Serialization.JsonConverter(typeof(ActivationIdConverter))]\n    public readonly partial struct ActivationId : System.IEquatable<ActivationId>, System.ISpanFormattable, System.IFormattable\n    {\n        private readonly int _dummyPrimitive;\n        public ActivationId(System.Guid key) { }\n\n        public bool IsDefault { get { throw null; } }\n\n        public readonly bool Equals(ActivationId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public static ActivationId FromParsableString(string activationId) { throw null; }\n\n        public static ActivationId GetDeterministic(GrainId grain) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static ActivationId NewId() { throw null; }\n\n        public static bool operator ==(ActivationId left, ActivationId right) { throw null; }\n\n        public static bool operator !=(ActivationId left, ActivationId right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public readonly string ToParsableString() { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public sealed partial class ActivationIdConverter : System.Text.Json.Serialization.JsonConverter<ActivationId>\n    {\n        public override ActivationId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { throw null; }\n\n        public override void Write(System.Text.Json.Utf8JsonWriter writer, ActivationId value, System.Text.Json.JsonSerializerOptions options) { }\n    }\n\n    public static partial class AsyncEnumerableExtensions\n    {\n        public static System.Collections.Generic.IAsyncEnumerable<T> WithBatchSize<T>(this System.Collections.Generic.IAsyncEnumerable<T> self, int maxBatchSize) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [SuppressReferenceTracking]\n    [Invocation.ReturnValueProxy(\"InitializeRequest\")]\n    public abstract partial class AsyncEnumerableRequest<T> : RequestBase, System.Collections.Generic.IAsyncEnumerable<T>, IAsyncEnumerableRequest<T>, IRequest, Orleans.Serialization.Invocation.IInvokable, System.IDisposable\n    {\n        [Id(0)]\n        public int MaxBatchSize { get { throw null; } set { } }\n\n        public System.Collections.Generic.IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n        public System.Collections.Generic.IAsyncEnumerable<T> InitializeRequest(GrainReference targetGrainReference) { throw null; }\n\n        public override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        public System.Collections.Generic.IAsyncEnumerable<T> InvokeImplementation() { throw null; }\n\n        protected abstract System.Collections.Generic.IAsyncEnumerable<T> InvokeInner();\n    }\n\n    public partial class AttributeGrainInterfaceTypeProvider : IGrainInterfaceTypeProvider\n    {\n        public AttributeGrainInterfaceTypeProvider(System.IServiceProvider serviceProvider) { }\n\n        public bool TryGetGrainInterfaceType(System.Type type, out GrainInterfaceType grainInterfaceType) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ClientNotAvailableException : OrleansException\n    {\n        internal ClientNotAvailableException() { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class EnumerationAbortedException : System.Exception\n    {\n        public EnumerationAbortedException() { }\n\n        [System.Obsolete]\n        protected EnumerationAbortedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public EnumerationAbortedException(string message, System.Exception innerException) { }\n\n        public EnumerationAbortedException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public enum EnumerationResult\n    {\n        Heartbeat = 1,\n        Element = 2,\n        Batch = 4,\n        Completed = 8,\n        CompletedWithElement = 10,\n        CompletedWithBatch = 12,\n        MissingEnumeratorError = 16,\n        Error = 32,\n        Canceled = 64\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GatewayTooBusyException : OrleansException\n    {\n        public GatewayTooBusyException() { }\n\n        public GatewayTooBusyException(string message, System.Exception innerException) { }\n\n        public GatewayTooBusyException(string message) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class GrainAddress : System.IEquatable<GrainAddress>, System.ISpanFormattable, System.IFormattable\n    {\n        public ActivationId ActivationId { get { throw null; } init { } }\n\n        public GrainId GrainId { get { throw null; } init { } }\n\n        [System.Text.Json.Serialization.JsonIgnore]\n        public bool IsComplete { get { throw null; } }\n\n        [Id(3)]\n        public MembershipVersion MembershipVersion { get { throw null; } init { } }\n\n        [Id(2)]\n        public SiloAddress? SiloAddress { get { throw null; } init { } }\n\n        public bool Equals(GrainAddress? other) { throw null; }\n\n        public override bool Equals(object? obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public bool Matches(GrainAddress? other) { throw null; }\n\n        string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public string ToFullString() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class GrainAddressCacheUpdate : System.ISpanFormattable, System.IFormattable\n    {\n        public GrainAddressCacheUpdate(GrainAddress invalidAddress, GrainAddress? validAddress) { }\n\n        public GrainId GrainId { get { throw null; } }\n\n        public ActivationId InvalidActivationId { get { throw null; } }\n\n        public GrainAddress InvalidGrainAddress { get { throw null; } }\n\n        public SiloAddress? InvalidSiloAddress { get { throw null; } }\n\n        public GrainAddress? ValidGrainAddress { get { throw null; } }\n\n        string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public string ToFullString() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public static partial class GrainContextExtensions\n    {\n        [System.Obsolete(\"This method is error-prone: waiting deactivation to complete from within the grain being deactivated will usually result in a deadlock.\")]\n        public static System.Threading.Tasks.Task DeactivateAsync(this IGrainContext grainContext, DeactivationReason deactivationReason, System.Threading.CancellationToken cancellationToken = default) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GrainExtensionNotInstalledException : OrleansException\n    {\n        public GrainExtensionNotInstalledException() { }\n\n        public GrainExtensionNotInstalledException(string message, System.Exception innerException) { }\n\n        public GrainExtensionNotInstalledException(string message) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [System.Text.Json.Serialization.JsonConverter(typeof(GrainIdJsonConverter))]\n    public readonly partial struct GrainId : System.IEquatable<GrainId>, System.IComparable<GrainId>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable, System.ISpanParsable<GrainId>, System.IParsable<GrainId>\n    {\n        public GrainId(GrainType type, IdSpan key) { }\n\n        public bool IsDefault { get { throw null; } }\n\n        public IdSpan Key { get { throw null; } }\n\n        public GrainType Type { get { throw null; } }\n\n        public readonly int CompareTo(GrainId other) { throw null; }\n\n        public static GrainId Create(GrainType type, IdSpan key) { throw null; }\n\n        public static GrainId Create(GrainType type, string key) { throw null; }\n\n        public static GrainId Create(string type, string key) { throw null; }\n\n        public readonly bool Equals(GrainId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public readonly uint GetUniformHashCode() { throw null; }\n\n        public static bool operator ==(GrainId left, GrainId right) { throw null; }\n\n        public static bool operator !=(GrainId left, GrainId right) { throw null; }\n\n        static GrainId System.ISpanParsable<GrainId>.Parse(System.ReadOnlySpan<char> value, System.IFormatProvider? provider) { throw null; }\n\n        static GrainId System.IParsable<GrainId>.Parse(string value, System.IFormatProvider? provider) { throw null; }\n\n        public static GrainId Parse(string value) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        static bool System.ISpanParsable<GrainId>.TryParse(System.ReadOnlySpan<char> value, System.IFormatProvider? provider, out GrainId result) { throw null; }\n\n        public static bool TryParse(string? value, out GrainId result) { throw null; }\n\n        static bool System.IParsable<GrainId>.TryParse(string? value, System.IFormatProvider? provider, out GrainId result) { throw null; }\n    }\n\n    public sealed partial class GrainIdJsonConverter : System.Text.Json.Serialization.JsonConverter<GrainId>\n    {\n        public override GrainId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { throw null; }\n\n        public override GrainId ReadAsPropertyName(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { throw null; }\n\n        public override void Write(System.Text.Json.Utf8JsonWriter writer, GrainId value, System.Text.Json.JsonSerializerOptions options) { }\n\n        public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, GrainId value, System.Text.Json.JsonSerializerOptions options) { }\n    }\n\n    public static partial class GrainIdKeyExtensions\n    {\n        public static IdSpan CreateGuidKey(System.Guid key, System.ReadOnlySpan<byte> keyExtension) { throw null; }\n\n        public static IdSpan CreateGuidKey(System.Guid key, string? keyExtension) { throw null; }\n\n        public static IdSpan CreateGuidKey(System.Guid key) { throw null; }\n\n        public static IdSpan CreateIntegerKey(long key, System.ReadOnlySpan<byte> keyExtension) { throw null; }\n\n        public static IdSpan CreateIntegerKey(long key, string? keyExtension) { throw null; }\n\n        public static IdSpan CreateIntegerKey(long key) { throw null; }\n\n        public static System.Guid GetGuidKey(this GrainId grainId, out string? keyExt) { throw null; }\n\n        public static System.Guid GetGuidKey(this GrainId grainId) { throw null; }\n\n        public static long GetIntegerKey(this GrainId grainId, out string? keyExt) { throw null; }\n\n        public static long GetIntegerKey(this GrainId grainId) { throw null; }\n\n        public static bool TryGetGuidKey(this GrainId grainId, out System.Guid key, out string? keyExt) { throw null; }\n\n        public static bool TryGetIntegerKey(this GrainId grainId, out long key, out string? keyExt) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct GrainInterfaceType : System.IEquatable<GrainInterfaceType>, System.ISpanFormattable, System.IFormattable\n    {\n        public GrainInterfaceType(IdSpan value) { }\n\n        public GrainInterfaceType(string value) { }\n\n        public bool IsDefault { get { throw null; } }\n\n        public IdSpan Value { get { throw null; } }\n\n        public static GrainInterfaceType Create(string value) { throw null; }\n\n        public readonly bool Equals(GrainInterfaceType other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(GrainInterfaceType left, GrainInterfaceType right) { throw null; }\n\n        public static bool operator !=(GrainInterfaceType left, GrainInterfaceType right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Interface, AllowMultiple = false)]\n    public sealed partial class GrainInterfaceTypeAttribute : System.Attribute, IGrainInterfaceTypeProviderAttribute\n    {\n        public GrainInterfaceTypeAttribute(string value) { }\n\n        public GrainInterfaceType GetGrainInterfaceType(System.IServiceProvider services, System.Type type) { throw null; }\n    }\n\n    public static partial class GrainLifecycleStage\n    {\n        public const int Activate = 2000;\n        public const int First = int.MinValue;\n        public const int Last = int.MaxValue;\n        public const int SetupState = 1000;\n    }\n\n    [Alias(\"GrainRef\")]\n    [DefaultInvokableBaseType(typeof(System.Threading.Tasks.ValueTask<>), typeof(Request<>))]\n    [DefaultInvokableBaseType(typeof(System.Threading.Tasks.ValueTask), typeof(Request))]\n    [DefaultInvokableBaseType(typeof(System.Threading.Tasks.Task<>), typeof(TaskRequest<>))]\n    [DefaultInvokableBaseType(typeof(System.Threading.Tasks.Task), typeof(TaskRequest))]\n    [DefaultInvokableBaseType(typeof(void), typeof(VoidRequest))]\n    [DefaultInvokableBaseType(typeof(System.Collections.Generic.IAsyncEnumerable<>), typeof(AsyncEnumerableRequest<>))]\n    public partial class GrainReference : IAddressable, System.IEquatable<GrainReference>, System.ISpanFormattable, System.IFormattable\n    {\n        protected GrainReference(GrainReferenceShared shared, IdSpan key) { }\n\n        protected Orleans.Serialization.Serializers.CodecProvider CodecProvider { get { throw null; } }\n\n        protected Orleans.Serialization.Cloning.CopyContextPool CopyContextPool { get { throw null; } }\n\n        public GrainId GrainId { get { throw null; } }\n\n        public virtual string InterfaceName { get { throw null; } }\n\n        public GrainInterfaceType InterfaceType { get { throw null; } }\n\n        public ushort InterfaceVersion { get { throw null; } }\n\n        public virtual TGrainInterface Cast<TGrainInterface>()\n            where TGrainInterface : IAddressable { throw null; }\n\n        public bool Equals(GrainReference? other) { throw null; }\n\n        public override bool Equals(object? obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        protected TInvokable GetInvokable<TInvokable>() { throw null; }\n\n        public uint GetUniformHashCode() { throw null; }\n\n        protected void Invoke(IRequest methodDescription) { }\n\n        protected System.Threading.Tasks.ValueTask InvokeAsync(IRequest methodDescription) { throw null; }\n\n        protected System.Threading.Tasks.ValueTask<T> InvokeAsync<T>(IRequest methodDescription) { throw null; }\n\n        public static bool operator ==(GrainReference? reference1, GrainReference? reference2) { throw null; }\n\n        public static bool operator !=(GrainReference? reference1, GrainReference? reference2) { throw null; }\n\n        string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public sealed override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GrainReferenceNotBoundException : OrleansException\n    {\n        internal GrainReferenceNotBoundException() { }\n    }\n\n    public partial class GrainReferenceShared\n    {\n        public GrainReferenceShared(GrainType grainType, GrainInterfaceType grainInterfaceType, ushort interfaceVersion, IGrainReferenceRuntime runtime, CodeGeneration.InvokeMethodOptions invokeMethodOptions, Orleans.Serialization.Serializers.CodecProvider codecProvider, Orleans.Serialization.Cloning.CopyContextPool copyContextPool, System.IServiceProvider serviceProvider) { }\n\n        public Orleans.Serialization.Serializers.CodecProvider CodecProvider { get { throw null; } }\n\n        public Orleans.Serialization.Cloning.CopyContextPool CopyContextPool { get { throw null; } }\n\n        public GrainType GrainType { get { throw null; } }\n\n        public GrainInterfaceType InterfaceType { get { throw null; } }\n\n        public ushort InterfaceVersion { get { throw null; } }\n\n        public CodeGeneration.InvokeMethodOptions InvokeMethodOptions { get { throw null; } }\n\n        public IGrainReferenceRuntime Runtime { get { throw null; } }\n\n        public System.IServiceProvider ServiceProvider { get { throw null; } }\n    }\n\n    public readonly partial struct GrainTimerCreationOptions\n    {\n        private readonly int _dummyPrimitive;\n        public GrainTimerCreationOptions() { }\n\n        [System.Diagnostics.CodeAnalysis.SetsRequiredMembers]\n        public GrainTimerCreationOptions(System.TimeSpan dueTime, System.TimeSpan period) { }\n\n        public required System.TimeSpan DueTime { get { throw null; } init { } }\n\n        public bool Interleave { get { throw null; } init { } }\n\n        public bool KeepAlive { get { throw null; } init { } }\n\n        public required System.TimeSpan Period { get { throw null; } init { } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct GrainType : System.IEquatable<GrainType>, System.IComparable<GrainType>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable\n    {\n        public GrainType(IdSpan id) { }\n\n        public GrainType(byte[] value) { }\n\n        public bool IsDefault { get { throw null; } }\n\n        public IdSpan Value { get { throw null; } }\n\n        public readonly System.ReadOnlySpan<byte> AsSpan() { throw null; }\n\n        public readonly int CompareTo(GrainType other) { throw null; }\n\n        public static GrainType Create(string value) { throw null; }\n\n        public readonly bool Equals(GrainType obj) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public readonly uint GetUniformHashCode() { throw null; }\n\n        public static bool operator ==(GrainType left, GrainType right) { throw null; }\n\n        public static explicit operator IdSpan(GrainType kind) { throw null; }\n\n        public static explicit operator GrainType(IdSpan id) { throw null; }\n\n        public static bool operator !=(GrainType left, GrainType right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string? ToString() { throw null; }\n\n        public static byte[]? UnsafeGetArray(GrainType id) { throw null; }\n    }\n\n    public static partial class GrainTypePrefix\n    {\n        public static readonly GrainType ClientGrainType;\n        public const string ClientPrefix = \"sys.client\";\n        public static readonly System.ReadOnlyMemory<byte> ClientPrefixBytes;\n        public const string GrainServicePrefix = \"sys.svc.user.\";\n        public static readonly System.ReadOnlyMemory<byte> GrainServicePrefixBytes;\n        public const string LegacyGrainPrefix = \"sys.grain.v1.\";\n        public static readonly System.ReadOnlyMemory<byte> LegacyGrainPrefixBytes;\n        public const string SystemPrefix = \"sys.\";\n        public const string SystemTargetPrefix = \"sys.svc.\";\n        public static readonly System.ReadOnlyMemory<byte> SystemTargetPrefixBytes;\n        public static bool IsClient(this in GrainId id) { throw null; }\n\n        public static bool IsClient(this in GrainType type) { throw null; }\n\n        public static bool IsGrainService(this in GrainType type) { throw null; }\n\n        public static bool IsLegacyGrain(this in GrainType type) { throw null; }\n\n        public static bool IsSystemTarget(this in GrainId id) { throw null; }\n\n        public static bool IsSystemTarget(this in GrainType type) { throw null; }\n    }\n\n    [Immutable]\n    [GenerateSerializer]\n    public sealed partial class GuidId : System.IEquatable<GuidId>, System.IComparable<GuidId>, System.Runtime.Serialization.ISerializable\n    {\n        internal GuidId() { }\n\n        [Id(0)]\n        public readonly System.Guid Guid;\n        public int CompareTo(GuidId? other) { throw null; }\n\n        public bool Equals(GuidId? other) { throw null; }\n\n        public override bool Equals(object? obj) { throw null; }\n\n        public static GuidId GetGuidId(System.Guid guid) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public static GuidId GetNewGuidId() { throw null; }\n\n        public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public static bool operator ==(GuidId? left, GuidId? right) { throw null; }\n\n        public static bool operator !=(GuidId? left, GuidId? right) { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class HashBasedPlacement : PlacementStrategy\n    {\n    }\n\n    [GenerateMethodSerializers(typeof(GrainReference), false)]\n    public partial interface IAddressable\n    {\n    }\n\n    public partial interface IAsyncEnumerableGrainExtension : IGrainExtension, IAddressable\n    {\n        [Concurrency.AlwaysInterleave]\n        System.Threading.Tasks.ValueTask DisposeAsync(System.Guid requestId);\n        [Concurrency.AlwaysInterleave]\n        System.Threading.Tasks.ValueTask<(EnumerationResult Status, object Value)> MoveNext<T>(System.Guid requestId);\n        [Concurrency.AlwaysInterleave]\n        System.Threading.Tasks.ValueTask<(EnumerationResult Status, object Value)> StartEnumeration<T>(System.Guid requestId, IAsyncEnumerableRequest<T> request);\n    }\n\n    public partial interface IAsyncEnumerableRequest<T> : IRequest, Orleans.Serialization.Invocation.IInvokable, System.IDisposable\n    {\n        int MaxBatchSize { get; set; }\n\n        System.Collections.Generic.IAsyncEnumerable<T> InvokeImplementation();\n    }\n\n    public partial interface IDehydrationContext\n    {\n        System.Collections.Generic.IEnumerable<string> Keys { get; }\n\n        void AddBytes(string key, System.ReadOnlySpan<byte> value);\n        void AddBytes<T>(string key, System.Action<T, System.Buffers.IBufferWriter<byte>> valueWriter, T value);\n        bool TryAddValue<T>(string key, T? value);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct IdSpan : System.IEquatable<IdSpan>, System.IComparable<IdSpan>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public IdSpan(byte[] value) { }\n\n        public bool IsDefault { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> Value { get { throw null; } }\n\n        public readonly System.ReadOnlySpan<byte> AsSpan() { throw null; }\n\n        public readonly int CompareTo(IdSpan other) { throw null; }\n\n        public static IdSpan Create(string id) { throw null; }\n\n        public readonly bool Equals(IdSpan obj) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public readonly uint GetUniformHashCode() { throw null; }\n\n        public static bool operator ==(IdSpan left, IdSpan right) { throw null; }\n\n        public static bool operator !=(IdSpan left, IdSpan right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        public readonly bool TryFormat(System.Span<char> destination, out int charsWritten) { throw null; }\n\n        public static IdSpan UnsafeCreate(byte[]? value, int hashCode) { throw null; }\n\n        public static byte[]? UnsafeGetArray(IdSpan id) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class IdSpanCodec : Orleans.Serialization.Codecs.IFieldCodec<IdSpan>, Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public static IdSpan ReadRaw<TInput>(ref Orleans.Serialization.Buffers.Reader<TInput> reader) { throw null; }\n\n        public IdSpan ReadValue<TInput>(ref Orleans.Serialization.Buffers.Reader<TInput> reader, Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, IdSpan value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteRaw<TBufferWriter>(ref Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, IdSpan value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial interface IGrainContext : Orleans.Serialization.Invocation.ITargetHolder, System.IEquatable<IGrainContext>\n    {\n        ActivationId ActivationId { get; }\n\n        System.IServiceProvider ActivationServices { get; }\n\n        GrainAddress Address { get; }\n\n        System.Threading.Tasks.Task Deactivated { get; }\n\n        GrainId GrainId { get; }\n\n        object? GrainInstance { get; }\n\n        GrainReference GrainReference { get; }\n\n        IGrainLifecycle ObservableLifecycle { get; }\n\n        IWorkItemScheduler Scheduler { get; }\n\n        void Activate(System.Collections.Generic.Dictionary<string, object>? requestContext, System.Threading.CancellationToken cancellationToken = default);\n        void Deactivate(DeactivationReason deactivationReason, System.Threading.CancellationToken cancellationToken = default);\n        void Migrate(System.Collections.Generic.Dictionary<string, object>? requestContext, System.Threading.CancellationToken cancellationToken = default);\n        void ReceiveMessage(object message);\n        void Rehydrate(IRehydrationContext context);\n        void SetComponent<TComponent>(TComponent? value)\n            where TComponent : class;\n    }\n\n    public partial interface IGrainContextAccessor\n    {\n        IGrainContext GrainContext { get; }\n    }\n\n    [GenerateMethodSerializers(typeof(GrainReference), true)]\n    public partial interface IGrainExtension : IAddressable\n    {\n    }\n\n    public partial interface IGrainExtensionBinder\n    {\n        TExtensionInterface GetExtension<TExtensionInterface>()\n            where TExtensionInterface : class, IGrainExtension;\n        (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(System.Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface where TExtensionInterface : class, IGrainExtension;\n    }\n\n    public partial interface IGrainInterfaceTypeProvider\n    {\n        bool TryGetGrainInterfaceType(System.Type type, out GrainInterfaceType grainInterfaceType);\n    }\n\n    public partial interface IGrainInterfaceTypeProviderAttribute\n    {\n        GrainInterfaceType GetGrainInterfaceType(System.IServiceProvider services, System.Type type);\n    }\n\n    public partial interface IGrainLifecycle : ILifecycleObservable\n    {\n        void AddMigrationParticipant(IGrainMigrationParticipant participant);\n        void RemoveMigrationParticipant(IGrainMigrationParticipant participant);\n    }\n\n    public partial interface IGrainMigrationParticipant\n    {\n        void OnDehydrate(IDehydrationContext dehydrationContext);\n        void OnRehydrate(IRehydrationContext rehydrationContext);\n    }\n\n    public partial interface IGrainReferenceRuntime\n    {\n        object Cast(IAddressable grain, System.Type interfaceType);\n        void InvokeMethod(GrainReference reference, Orleans.Serialization.Invocation.IInvokable request, CodeGeneration.InvokeMethodOptions options);\n        System.Threading.Tasks.ValueTask InvokeMethodAsync(GrainReference reference, Orleans.Serialization.Invocation.IInvokable request, CodeGeneration.InvokeMethodOptions options);\n        System.Threading.Tasks.ValueTask<T> InvokeMethodAsync<T>(GrainReference reference, Orleans.Serialization.Invocation.IInvokable request, CodeGeneration.InvokeMethodOptions options);\n    }\n\n    public partial interface IGrainRuntime\n    {\n        IGrainFactory GrainFactory { get; }\n\n        System.IServiceProvider ServiceProvider { get; }\n\n        SiloAddress SiloAddress { get; }\n\n        string SiloIdentity { get; }\n\n        System.TimeProvider TimeProvider { get; }\n\n        Timers.ITimerRegistry TimerRegistry { get; }\n\n        void DeactivateOnIdle(IGrainContext grainContext);\n        void DelayDeactivation(IGrainContext grainContext, System.TimeSpan timeSpan);\n        Core.IStorage<TGrainState> GetStorage<TGrainState>(IGrainContext grainContext);\n    }\n\n    public partial interface IGrainTimer : System.IDisposable\n    {\n        void Change(System.TimeSpan dueTime, System.TimeSpan period);\n    }\n\n    public partial interface IRehydrationContext\n    {\n        System.Collections.Generic.IEnumerable<string> Keys { get; }\n\n        bool TryGetBytes(string key, out System.Buffers.ReadOnlySequence<byte> value);\n        bool TryGetValue<T>(string key, out T? value);\n    }\n\n    public partial interface IRequest : Orleans.Serialization.Invocation.IInvokable, System.IDisposable\n    {\n        CodeGeneration.InvokeMethodOptions Options { get; }\n\n        void AddInvokeMethodOptions(CodeGeneration.InvokeMethodOptions options);\n        string ToMethodCallString(IRequest request);\n        string ToString(IRequest request);\n    }\n\n    public partial interface IWorkItemScheduler\n    {\n        void QueueAction(System.Action action);\n        void QueueAction(System.Action<object> action, object state);\n        void QueueTask(System.Threading.Tasks.Task task);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class LegacyGrainId : System.IEquatable<LegacyGrainId>, System.IComparable<LegacyGrainId>\n    {\n        internal LegacyGrainId() { }\n\n        public UniqueKey.Category Category { get { throw null; } }\n\n        public string IdentityString { get { throw null; } }\n\n        public bool IsClient { get { throw null; } }\n\n        public bool IsGrain { get { throw null; } }\n\n        public bool IsLongKey { get { throw null; } }\n\n        public bool IsSystemTarget { get { throw null; } }\n\n        public System.Guid PrimaryKey { get { throw null; } }\n\n        public long PrimaryKeyLong { get { throw null; } }\n\n        public string PrimaryKeyString { get { throw null; } }\n\n        public int TypeCode { get { throw null; } }\n\n        public int CompareTo(LegacyGrainId? other) { throw null; }\n\n        public static GrainType CreateGrainTypeForGrain(int typeCode) { throw null; }\n\n        public static GrainType CreateGrainTypeForSystemTarget(int typeCode) { throw null; }\n\n        public bool Equals(LegacyGrainId? other) { throw null; }\n\n        public override bool Equals(object? obj) { throw null; }\n\n        public static LegacyGrainId FromGrainId(GrainId id) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public uint GetHashCode_Modulo(uint umod) { throw null; }\n\n        public System.Guid GetPrimaryKey(out string? keyExt) { throw null; }\n\n        public long GetPrimaryKeyLong(out string? keyExt) { throw null; }\n\n        public uint GetUniformHashCode() { throw null; }\n\n        public static bool IsLegacyGrainType(System.Type type) { throw null; }\n\n        public static bool IsLegacyKeyExtGrainType(System.Type type) { throw null; }\n\n        public static LegacyGrainId NewClientId() { throw null; }\n\n        public static LegacyGrainId NewId() { throw null; }\n\n        public static implicit operator GrainId(LegacyGrainId legacy) { throw null; }\n\n        public GrainId ToGrainId() { throw null; }\n\n        public override string ToString() { throw null; }\n\n        public static bool TryConvertFromGrainId(GrainId id, out LegacyGrainId? legacyId) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class LimitExceededException : OrleansException\n    {\n        public LimitExceededException() { }\n\n        public LimitExceededException(string message, System.Exception innerException) { }\n\n        public LimitExceededException(string limitName, int current, int threshold, object extraInfo) { }\n\n        public LimitExceededException(string message) { }\n    }\n\n    public static partial class LogFormatter\n    {\n        public const int MAX_LOG_MESSAGE_SIZE = 20000;\n        public static System.DateTime ParseDate(string dateStr) { throw null; }\n\n        public static string PrintDate(System.DateTime date) { throw null; }\n\n        public static string PrintException(System.Exception exception) { throw null; }\n\n        public static string PrintTime(System.DateTime date) { throw null; }\n\n        public static void SetExceptionDecoder(System.Type exceptionType, System.Func<System.Exception, string> decoder) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [System.Text.Json.Serialization.JsonConverter(typeof(MembershipVersionConverter))]\n    public readonly partial struct MembershipVersion : System.IComparable<MembershipVersion>, System.IEquatable<MembershipVersion>\n    {\n        private readonly int _dummyPrimitive;\n        public MembershipVersion(long version) { }\n\n        public static MembershipVersion MinValue { get { throw null; } }\n\n        [Id(0)]\n        public long Value { get { throw null; } init { } }\n\n        public readonly int CompareTo(MembershipVersion other) { throw null; }\n\n        public readonly bool Equals(MembershipVersion other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public static bool operator >(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public static bool operator >=(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public static bool operator !=(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public static bool operator <(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public static bool operator <=(MembershipVersion left, MembershipVersion right) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public sealed partial class MembershipVersionConverter : System.Text.Json.Serialization.JsonConverter<MembershipVersion>\n    {\n        public override MembershipVersion Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { throw null; }\n\n        public override void Write(System.Text.Json.Utf8JsonWriter writer, MembershipVersion value, System.Text.Json.JsonSerializerOptions options) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansConfigurationException : System.Exception\n    {\n        public OrleansConfigurationException(string message, System.Exception innerException) { }\n\n        public OrleansConfigurationException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public partial class OrleansException : System.Exception\n    {\n        public OrleansException() { }\n\n        [System.Obsolete]\n        protected OrleansException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public OrleansException(string message, System.Exception innerException) { }\n\n        public OrleansException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansLifecycleCanceledException : OrleansException\n    {\n        internal OrleansLifecycleCanceledException() { }\n    }\n\n    [GenerateSerializer]\n    public partial class OrleansMessageRejectionException : OrleansException\n    {\n        [System.Obsolete]\n        protected OrleansMessageRejectionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class PlacementStrategy\n    {\n        public virtual bool IsUsingGrainDirectory { get { throw null; } }\n\n        public virtual void Initialize(Metadata.GrainProperties properties) { }\n\n        public virtual void PopulateGrainProperties(System.IServiceProvider services, System.Type grainClass, GrainType grainType, System.Collections.Generic.Dictionary<string, string> properties) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class PreferLocalPlacement : PlacementStrategy\n    {\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class RandomPlacement : PlacementStrategy\n    {\n    }\n\n    [SerializerTransparent]\n    public abstract partial class Request : RequestBase\n    {\n        public sealed override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.ValueTask InvokeInner();\n    }\n\n    [SuppressReferenceTracking]\n    [SerializerTransparent]\n    public abstract partial class RequestBase : IRequest, Orleans.Serialization.Invocation.IInvokable, System.IDisposable\n    {\n        public CodeGeneration.InvokeMethodOptions Options { get { throw null; } protected set { } }\n\n        public void AddInvokeMethodOptions(CodeGeneration.InvokeMethodOptions options) { }\n\n        public abstract void Dispose();\n        public abstract string GetActivityName();\n        public virtual object GetArgument(int index) { throw null; }\n\n        public virtual int GetArgumentCount() { throw null; }\n\n        public virtual System.Threading.CancellationToken GetCancellationToken() { throw null; }\n\n        public virtual System.TimeSpan? GetDefaultResponseTimeout() { throw null; }\n\n        public abstract string GetInterfaceName();\n        public abstract System.Type GetInterfaceType();\n        public abstract System.Reflection.MethodInfo GetMethod();\n        public abstract string GetMethodName();\n        public abstract object GetTarget();\n        public abstract System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke();\n        public virtual void SetArgument(int index, object value) { }\n\n        public abstract void SetTarget(Orleans.Serialization.Invocation.ITargetHolder holder);\n        public override string ToString() { throw null; }\n\n        public virtual bool TryCancel() { throw null; }\n    }\n\n    public static partial class RequestContext\n    {\n        public static System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object>> Entries { get { throw null; } }\n\n        public static System.Collections.Generic.IEnumerable<string> Keys { get { throw null; } }\n\n        public static System.Guid ReentrancyId { get { throw null; } set { } }\n\n        public static ReentrancySection AllowCallChainReentrancy() { throw null; }\n\n        public static void Clear() { }\n\n        public static object? Get(string key) { throw null; }\n\n        public static bool Remove(string key) { throw null; }\n\n        public static void Set(string key, object value) { }\n\n        public static ReentrancySection SuppressCallChainReentrancy() { throw null; }\n\n        public readonly partial struct ReentrancySection : System.IDisposable\n        {\n            private readonly int _dummyPrimitive;\n            public ReentrancySection(System.Guid originalReentrancyId, System.Guid newReentrancyId) { }\n\n            public readonly void Dispose() { }\n        }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class Request<TResult> : RequestBase\n    {\n        public sealed override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.ValueTask<TResult> InvokeInner();\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class ResourceOptimizedPlacement : PlacementStrategy\n    {\n    }\n\n    [Immutable]\n    [System.Text.Json.Serialization.JsonConverter(typeof(SiloAddressConverter))]\n    [System.Diagnostics.DebuggerDisplay(\"SiloAddress {ToString()}\")]\n    [SuppressReferenceTracking]\n    public sealed partial class SiloAddress : System.IEquatable<SiloAddress>, System.IComparable<SiloAddress>, System.ISpanFormattable, System.IFormattable\n    {\n        internal SiloAddress() { }\n\n        [Id(0)]\n        public System.Net.IPEndPoint Endpoint { get { throw null; } }\n\n        [Id(1)]\n        public int Generation { get { throw null; } }\n\n        public bool IsClient { get { throw null; } }\n\n        public static SiloAddress Zero { get { throw null; } }\n\n        public static int AllocateNewGeneration() { throw null; }\n\n        public int CompareTo(SiloAddress? other) { throw null; }\n\n        public bool Equals(SiloAddress? other) { throw null; }\n\n        public override bool Equals(object? obj) { throw null; }\n\n        public static SiloAddress FromParsableString(string addr) { throw null; }\n\n        public static SiloAddress FromUtf8String(System.ReadOnlySpan<byte> addr) { throw null; }\n\n        public int GetConsistentHashCode() { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public uint[] GetUniformHashCodes(int numHashes) { throw null; }\n\n        public bool IsPredecessorOf(SiloAddress other) { throw null; }\n\n        public bool IsSuccessorOf(SiloAddress other) { throw null; }\n\n        public static SiloAddress New(System.Net.IPAddress address, int port, int generation) { throw null; }\n\n        public static SiloAddress New(System.Net.IPEndPoint ep, int gen) { throw null; }\n\n        string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public string ToParsableString() { throw null; }\n\n        public override string ToString() { throw null; }\n\n        public string ToStringWithHashCode() { throw null; }\n    }\n\n    public sealed partial class SiloAddressConverter : System.Text.Json.Serialization.JsonConverter<SiloAddress>\n    {\n        public override SiloAddress? Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { throw null; }\n\n        public override void Write(System.Text.Json.Utf8JsonWriter writer, SiloAddress value, System.Text.Json.JsonSerializerOptions options) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public partial class SiloRoleBasedPlacement : PlacementStrategy\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class SiloUnavailableException : OrleansMessageRejectionException\n    {\n        public SiloUnavailableException() : base(default!, default) { }\n\n        public SiloUnavailableException(string message, System.Exception innerException) : base(default!, default) { }\n\n        public SiloUnavailableException(string msg) : base(default!, default) { }\n    }\n\n    [Immutable]\n    public readonly partial struct SystemTargetGrainId : System.IEquatable<SystemTargetGrainId>, System.IComparable<SystemTargetGrainId>, System.ISpanFormattable, System.IFormattable\n    {\n        public GrainId GrainId { get { throw null; } }\n\n        public readonly int CompareTo(SystemTargetGrainId other) { throw null; }\n\n        public static SystemTargetGrainId Create(GrainType kind, SiloAddress address, string? extraIdentifier) { throw null; }\n\n        public static SystemTargetGrainId Create(GrainType kind, SiloAddress address) { throw null; }\n\n        public static GrainId CreateGrainServiceGrainId(int typeCode, string grainSystemId, SiloAddress address) { throw null; }\n\n        public static GrainType CreateGrainType(string name) { throw null; }\n\n        public readonly bool Equals(SystemTargetGrainId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly SiloAddress GetSiloAddress() { throw null; }\n\n        public static bool IsSystemTargetGrainId(in GrainId id) { throw null; }\n\n        public static bool operator ==(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        public static bool operator >(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        public static bool operator >=(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        public static bool operator !=(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        public static bool operator <(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        public static bool operator <=(SystemTargetGrainId left, SystemTargetGrainId right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        public static bool TryParse(GrainId grainId, out SystemTargetGrainId systemTargetId) { throw null; }\n\n        public readonly SystemTargetGrainId WithSiloAddress(SiloAddress siloAddress) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class SystemTargetPlacementStrategy : PlacementStrategy\n    {\n        public static SystemTargetPlacementStrategy Instance { get { throw null; } }\n\n        public override bool IsUsingGrainDirectory { get { throw null; } }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TaskRequest : RequestBase\n    {\n        public sealed override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.Task InvokeInner();\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TaskRequest<TResult> : RequestBase\n    {\n        public sealed override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.Task<TResult> InvokeInner();\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class UniqueKey : System.IComparable<UniqueKey>, System.IEquatable<UniqueKey>\n    {\n        public int BaseTypeCode { get { throw null; } }\n\n        public bool HasKeyExt { get { throw null; } }\n\n        public Category IdCategory { get { throw null; } }\n\n        public bool IsLongKey { get { throw null; } }\n\n        public bool IsSystemTargetKey { get { throw null; } }\n\n        [Id(3)]\n        public string? KeyExt { get { throw null; } }\n\n        [Id(0)]\n        public ulong N0 { get { throw null; } }\n\n        [Id(1)]\n        public ulong N1 { get { throw null; } }\n\n        [Id(2)]\n        public ulong TypeCodeData { get { throw null; } }\n\n        public int CompareTo(UniqueKey? other) { throw null; }\n\n        public bool Equals(UniqueKey? other) { throw null; }\n\n        public override bool Equals(object? o) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public static UniqueKey NewGrainServiceKey(short key, long typeData) { throw null; }\n\n        public static UniqueKey NewGrainServiceKey(string key, long typeData) { throw null; }\n\n        public static UniqueKey NewKey() { throw null; }\n\n        public static UniqueKey NewSystemTargetKey(System.Guid guid, long typeData) { throw null; }\n\n        public static UniqueKey NewSystemTargetKey(short systemId) { throw null; }\n\n        public System.Guid PrimaryKeyToGuid() { throw null; }\n\n        public System.Guid PrimaryKeyToGuid(out string? extendedKey) { throw null; }\n\n        public long PrimaryKeyToLong() { throw null; }\n\n        public long PrimaryKeyToLong(out string? extendedKey) { throw null; }\n\n        public override string ToString() { throw null; }\n\n        public enum Category : byte\n        {\n            None = 0,\n            SystemTarget = 1,\n            SystemGrain = 2,\n            Grain = 3,\n            Client = 4,\n            KeyExtGrain = 6,\n            KeyExtSystemTarget = 8\n        }\n    }\n\n    public static partial class Utils\n    {\n        public static float AverageTicksToMilliSeconds(float ticks) { throw null; }\n\n        public static System.Collections.Generic.IEnumerable<System.Collections.Generic.List<T>> BatchIEnumerable<T>(this System.Collections.Generic.IEnumerable<T> sequence, int batchSize) { throw null; }\n\n        public static string DictionaryToString<T1, T2>(System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<T1, T2>> dict, System.Func<T2, string?>? toString = null, string? separator = null) { throw null; }\n\n        public static string EnumerableToString<T>(System.Collections.Generic.IEnumerable<T>? collection, System.Func<T, string>? toString = null, string separator = \", \", bool putInBrackets = true) { throw null; }\n\n        public static string GetStackTrace(int skipFrames = 0) { throw null; }\n\n        public static void SafeExecute(System.Action action, Microsoft.Extensions.Logging.ILogger? logger = null, string? caller = null) { }\n\n        public static void SafeExecute(System.Action action) { }\n\n        public static System.Threading.Tasks.Task SafeExecuteAsync(System.Threading.Tasks.Task task) { throw null; }\n\n        public static long TicksToMilliSeconds(long ticks) { throw null; }\n\n        public static string TimeSpanToString(System.TimeSpan timeSpan) { throw null; }\n\n        public static SiloAddress? ToGatewayAddress(this System.Uri uri) { throw null; }\n\n        public static System.Uri ToGatewayUri(this SiloAddress address) { throw null; }\n\n        public static System.Uri ToGatewayUri(this System.Net.IPEndPoint ep) { throw null; }\n\n        public static System.Net.IPEndPoint? ToIPEndPoint(this System.Uri uri) { throw null; }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class VoidRequest : RequestBase\n    {\n        public sealed override System.Threading.Tasks.ValueTask<Orleans.Serialization.Invocation.Response> Invoke() { throw null; }\n\n        protected abstract void InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public partial class WrappedException : OrleansException\n    {\n        [System.Obsolete]\n        protected WrappedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public WrappedException(string message) { }\n\n        [Id(0)]\n        public string? OriginalExceptionType { get { throw null; } set { } }\n\n        [System.Diagnostics.CodeAnalysis.DoesNotReturn]\n        public static void CreateAndRethrow(System.Exception exception) { }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Serialization\n{\n    [RegisterSerializer]\n    public sealed partial class SiloAddressCodec : Orleans.Serialization.Codecs.IFieldCodec<SiloAddress>, Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public SiloAddress ReadValue<TReaderInput>(ref Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, SiloAddress? value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace Orleans.Serialization\n{\n    public abstract partial class DeserializationContext\n    {\n        public abstract object RuntimeClient { get; }\n        public abstract System.IServiceProvider ServiceProvider { get; }\n    }\n\n    public partial interface IOnDeserialized\n    {\n        void OnDeserialized(DeserializationContext context);\n    }\n}\n\nnamespace Orleans.Services\n{\n    public partial interface IGrainService : ISystemTarget, Runtime.IAddressable\n    {\n    }\n\n    public partial interface IGrainServiceClient<TGrainService>\n        where TGrainService : IGrainService\n    {\n    }\n}\n\nnamespace Orleans.Statistics\n{\n    [Immutable]\n    [GenerateSerializer]\n    [Alias(\"Orleans.Statistics.EnvironmentStatistics\")]\n    [System.Diagnostics.DebuggerDisplay(\"{ToString(),nq}\")]\n    public readonly partial struct EnvironmentStatistics\n    {\n        [Id(2)]\n        public readonly long FilteredAvailableMemoryBytes;\n        [Id(0)]\n        public readonly float FilteredCpuUsagePercentage;\n        [Id(1)]\n        public readonly long FilteredMemoryUsageBytes;\n        [Id(3)]\n        public readonly long MaximumAvailableMemoryBytes;\n        [Id(6)]\n        public readonly long RawAvailableMemoryBytes;\n        [Id(4)]\n        public readonly float RawCpuUsagePercentage;\n        [Id(5)]\n        public readonly long RawMemoryUsageBytes;\n        public float AvailableMemoryPercentage { get { throw null; } }\n\n        public float MemoryUsagePercentage { get { throw null; } }\n\n        public float NormalizedAvailableMemory { get { throw null; } }\n\n        public float NormalizedFilteredAvailableMemory { get { throw null; } }\n\n        public float NormalizedFilteredMemoryUsage { get { throw null; } }\n\n        public float NormalizedMemoryUsage { get { throw null; } }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    [System.Obsolete(\"This functionality will be removed, use IEnvironmentStatisticsProvider.GetEnvironmentStatistics instead.\")]\n    public partial interface IAppEnvironmentStatistics\n    {\n        long? MemoryUsage { get; }\n    }\n\n    public partial interface IEnvironmentStatisticsProvider\n    {\n        EnvironmentStatistics GetEnvironmentStatistics();\n    }\n\n    [System.Obsolete(\"This functionality will be removed, use IEnvironmentStatisticsProvider.GetEnvironmentStatistics instead.\")]\n    public partial interface IHostEnvironmentStatistics\n    {\n        long? AvailableMemory { get; }\n\n        float? CpuUsage { get; }\n\n        long? TotalPhysicalMemory { get; }\n    }\n}\n\nnamespace Orleans.Timers\n{\n    public partial interface ITimerRegistry\n    {\n        Runtime.IGrainTimer RegisterGrainTimer<TState>(Runtime.IGrainContext grainContext, System.Func<TState, System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, TState state, Runtime.GrainTimerCreationOptions options);\n        [System.Obsolete(\"Use 'RegisterGrainTimer(grainContext, callback, state, new() { DueTime = dueTime, Period = period, Interleave = true })' instead.\")]\n        System.IDisposable RegisterTimer(Runtime.IGrainContext grainContext, System.Func<object?, System.Threading.Tasks.Task> callback, object? state, System.TimeSpan dueTime, System.TimeSpan period);\n    }\n}\n\nnamespace Orleans.Versions\n{\n    public partial interface IVersionStore : IVersionManager\n    {\n        bool IsEnabled { get; }\n\n        System.Threading.Tasks.Task<System.Collections.Generic.Dictionary<Runtime.GrainInterfaceType, Compatibility.CompatibilityStrategy>> GetCompatibilityStrategies();\n        System.Threading.Tasks.Task<Compatibility.CompatibilityStrategy> GetCompatibilityStrategy();\n        System.Threading.Tasks.Task<System.Collections.Generic.Dictionary<Runtime.GrainInterfaceType, Selector.VersionSelectorStrategy>> GetSelectorStrategies();\n        System.Threading.Tasks.Task<Selector.VersionSelectorStrategy> GetSelectorStrategy();\n    }\n}\n\nnamespace Orleans.Versions.Compatibility\n{\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class AllVersionsCompatible : CompatibilityStrategy\n    {\n        public static AllVersionsCompatible Singleton { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class BackwardCompatible : CompatibilityStrategy\n    {\n        public static BackwardCompatible Singleton { get { throw null; } }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class CompatibilityStrategy\n    {\n    }\n\n    public partial interface ICompatibilityDirector\n    {\n        bool IsCompatible(ushort requestedVersion, ushort currentVersion);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class StrictVersionCompatible : CompatibilityStrategy\n    {\n        public static StrictVersionCompatible Singleton { get { throw null; } }\n    }\n}\n\nnamespace Orleans.Versions.Selector\n{\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class AllCompatibleVersions : VersionSelectorStrategy\n    {\n        public static AllCompatibleVersions Singleton { get { throw null; } }\n    }\n\n    public partial interface IVersionSelector\n    {\n        ushort[] GetSuitableVersion(ushort requestedVersion, ushort[] availableVersions, Compatibility.ICompatibilityDirector compatibilityDirector);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class LatestVersion : VersionSelectorStrategy\n    {\n        public static LatestVersion Singleton { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    [SuppressReferenceTracking]\n    public sealed partial class MinimumVersion : VersionSelectorStrategy\n    {\n        public static MinimumVersion Singleton { get { throw null; } }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class VersionSelectorStrategy\n    {\n    }\n}\n\nnamespace OrleansCodeGen.Orleans\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DeactivationReasonCode : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.DeactivationReasonCode>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.DeactivationReasonCode ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.DeactivationReasonCode value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.CodeGeneration\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_InvokeMethodOptions : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.CodeGeneration.InvokeMethodOptions>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.CodeGeneration.InvokeMethodOptions ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.CodeGeneration.InvokeMethodOptions value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Concurrency\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Immutable<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Concurrency.Immutable<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Concurrency.Immutable<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_Immutable(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Concurrency.Immutable<T> instance) { }\n\n        public global::Orleans.Concurrency.Immutable<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Concurrency.Immutable<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Concurrency.Immutable<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Immutable<T> : global::Orleans.Serialization.Cloning.ShallowCopier<global::Orleans.Concurrency.Immutable<T>>\n    {\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Core.Internal\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 instance) { }\n\n        public Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 instance) { }\n\n        public Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 DeepCopy(Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 DeepCopy(Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Core.Internal.IGrainManagementExtension), typeof(global::Orleans.Core.Internal.IGrainManagementExtension), \"1B9614D1\" })]\n    public sealed partial class Invokable_IGrainManagementExtension_GrainReference_Ext_1B9614D1 : global::Orleans.Runtime.Request\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Core.Internal.IGrainManagementExtension), typeof(global::Orleans.Core.Internal.IGrainManagementExtension), \"4CC93B45\" })]\n    public sealed partial class Invokable_IGrainManagementExtension_GrainReference_Ext_4CC93B45 : global::Orleans.Runtime.Request\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Metadata\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClusterManifest : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Metadata.ClusterManifest>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ClusterManifest(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Metadata.ClusterManifest> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Metadata.ClusterManifest instance) { }\n\n        public global::Orleans.Metadata.ClusterManifest ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Metadata.ClusterManifest instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Metadata.ClusterManifest value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainInterfaceProperties : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Metadata.GrainInterfaceProperties>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainInterfaceProperties(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Metadata.GrainInterfaceProperties> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Metadata.GrainInterfaceProperties instance) { }\n\n        public global::Orleans.Metadata.GrainInterfaceProperties ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Metadata.GrainInterfaceProperties instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Metadata.GrainInterfaceProperties value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainManifest : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Metadata.GrainManifest>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainManifest(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Metadata.GrainManifest> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Metadata.GrainManifest instance) { }\n\n        public global::Orleans.Metadata.GrainManifest ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Metadata.GrainManifest instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Metadata.GrainManifest value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainProperties : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Metadata.GrainProperties>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainProperties(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Metadata.GrainProperties> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Metadata.GrainProperties instance) { }\n\n        public global::Orleans.Metadata.GrainProperties ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Metadata.GrainProperties instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Metadata.GrainProperties value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MajorMinorVersion : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Metadata.MajorMinorVersion>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Metadata.MajorMinorVersion>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Metadata.MajorMinorVersion instance) { }\n\n        public global::Orleans.Metadata.MajorMinorVersion ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Metadata.MajorMinorVersion instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Metadata.MajorMinorVersion value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ActivationCountBasedPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ActivationCountBasedPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ActivationCountBasedPlacement instance) { }\n\n        public global::Orleans.Runtime.ActivationCountBasedPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ActivationCountBasedPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ActivationCountBasedPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ActivationId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ActivationId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.ActivationId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.ActivationId instance) { }\n\n        public global::Orleans.Runtime.ActivationId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.ActivationId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ActivationId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AsyncEnumerableRequest<T> : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.Runtime.AsyncEnumerableRequest<T>>\n    {\n        public override void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.AsyncEnumerableRequest<T> instance) { }\n\n        public override void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.AsyncEnumerableRequest<T> instance) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClientNotAvailableException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ClientNotAvailableException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ClientNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ClientNotAvailableException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ClientNotAvailableException instance) { }\n\n        public global::Orleans.Runtime.ClientNotAvailableException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ClientNotAvailableException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ClientNotAvailableException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EnumerationAbortedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.EnumerationAbortedException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_EnumerationAbortedException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.EnumerationAbortedException instance) { }\n\n        public global::Orleans.Runtime.EnumerationAbortedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.EnumerationAbortedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.EnumerationAbortedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EnumerationResult : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.EnumerationResult>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Runtime.EnumerationResult ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.EnumerationResult value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GatewayTooBusyException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GatewayTooBusyException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GatewayTooBusyException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GatewayTooBusyException instance) { }\n\n        public global::Orleans.Runtime.GatewayTooBusyException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GatewayTooBusyException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GatewayTooBusyException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainAddress : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainAddress>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainAddress(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GrainAddress instance) { }\n\n        public global::Orleans.Runtime.GrainAddress ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GrainAddress instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainAddress value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainAddressCacheUpdate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainAddressCacheUpdate>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainAddressCacheUpdate(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.GrainAddressCacheUpdate> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GrainAddressCacheUpdate instance) { }\n\n        public global::Orleans.Runtime.GrainAddressCacheUpdate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GrainAddressCacheUpdate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainAddressCacheUpdate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainExtensionNotInstalledException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainExtensionNotInstalledException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainExtensionNotInstalledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GrainExtensionNotInstalledException instance) { }\n\n        public global::Orleans.Runtime.GrainExtensionNotInstalledException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GrainExtensionNotInstalledException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainExtensionNotInstalledException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.GrainId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_GrainId(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.GrainId instance) { }\n\n        public global::Orleans.Runtime.GrainId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.GrainId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainInterfaceType : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainInterfaceType>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.GrainInterfaceType>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_GrainInterfaceType(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.GrainInterfaceType instance) { }\n\n        public global::Orleans.Runtime.GrainInterfaceType ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.GrainInterfaceType instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainInterfaceType value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainReferenceNotBoundException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainReferenceNotBoundException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GrainReferenceNotBoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.GrainReferenceNotBoundException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GrainReferenceNotBoundException instance) { }\n\n        public global::Orleans.Runtime.GrainReferenceNotBoundException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GrainReferenceNotBoundException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainReferenceNotBoundException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainType : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GrainType>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.GrainType>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_GrainType(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.GrainType instance) { }\n\n        public global::Orleans.Runtime.GrainType ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.GrainType instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GrainType value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GuidId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.GuidId>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GuidId(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.GuidId> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.GuidId instance) { }\n\n        public global::Orleans.Runtime.GuidId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.GuidId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.GuidId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_HashBasedPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.HashBasedPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.HashBasedPlacement instance) { }\n\n        public global::Orleans.Runtime.HashBasedPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.HashBasedPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.HashBasedPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_IdSpan : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.IdSpan>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.IdSpan>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.IdSpan instance) { }\n\n        public global::Orleans.Runtime.IdSpan ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.IdSpan instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.IdSpan value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> instance) { }\n\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 instance) { }\n\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T>>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> instance) { }\n\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LegacyGrainId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.LegacyGrainId>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_LegacyGrainId(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.LegacyGrainId> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.LegacyGrainId instance) { }\n\n        public global::Orleans.Runtime.LegacyGrainId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.LegacyGrainId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.LegacyGrainId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LimitExceededException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.LimitExceededException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_LimitExceededException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.LimitExceededException instance) { }\n\n        public global::Orleans.Runtime.LimitExceededException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.LimitExceededException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.LimitExceededException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MembershipVersion : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.MembershipVersion>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.MembershipVersion>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.MembershipVersion instance) { }\n\n        public global::Orleans.Runtime.MembershipVersion ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.MembershipVersion instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.MembershipVersion value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansConfigurationException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.OrleansConfigurationException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansConfigurationException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.OrleansConfigurationException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.OrleansConfigurationException instance) { }\n\n        public global::Orleans.Runtime.OrleansConfigurationException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.OrleansConfigurationException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.OrleansConfigurationException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.OrleansException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.OrleansException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_OrleansException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.OrleansException instance) { }\n\n        public global::Orleans.Runtime.OrleansException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.OrleansException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.OrleansException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansLifecycleCanceledException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.OrleansLifecycleCanceledException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansLifecycleCanceledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.OrleansLifecycleCanceledException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.OrleansLifecycleCanceledException instance) { }\n\n        public global::Orleans.Runtime.OrleansLifecycleCanceledException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.OrleansLifecycleCanceledException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.OrleansLifecycleCanceledException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansMessageRejectionException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.OrleansMessageRejectionException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.OrleansMessageRejectionException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_OrleansMessageRejectionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.OrleansMessageRejectionException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.OrleansMessageRejectionException instance) { }\n\n        public global::Orleans.Runtime.OrleansMessageRejectionException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.OrleansMessageRejectionException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.OrleansMessageRejectionException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_PreferLocalPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.PreferLocalPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.PreferLocalPlacement instance) { }\n\n        public global::Orleans.Runtime.PreferLocalPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.PreferLocalPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.PreferLocalPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RandomPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.RandomPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.RandomPlacement instance) { }\n\n        public global::Orleans.Runtime.RandomPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.RandomPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.RandomPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ResourceOptimizedPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ResourceOptimizedPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ResourceOptimizedPlacement instance) { }\n\n        public global::Orleans.Runtime.ResourceOptimizedPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ResourceOptimizedPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ResourceOptimizedPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SiloRoleBasedPlacement : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SiloRoleBasedPlacement>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.SiloRoleBasedPlacement>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.SiloRoleBasedPlacement instance) { }\n\n        public global::Orleans.Runtime.SiloRoleBasedPlacement ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.SiloRoleBasedPlacement instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SiloRoleBasedPlacement value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SiloUnavailableException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SiloUnavailableException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_SiloUnavailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.SiloUnavailableException instance) { }\n\n        public global::Orleans.Runtime.SiloUnavailableException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.SiloUnavailableException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SiloUnavailableException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SystemTargetPlacementStrategy : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.SystemTargetPlacementStrategy>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.SystemTargetPlacementStrategy instance) { }\n\n        public global::Orleans.Runtime.SystemTargetPlacementStrategy ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.SystemTargetPlacementStrategy instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.SystemTargetPlacementStrategy value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UniqueKey : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.UniqueKey>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.UniqueKey instance) { }\n\n        public global::Orleans.Runtime.UniqueKey ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.UniqueKey instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.UniqueKey value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_WrappedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.WrappedException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.WrappedException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_WrappedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.WrappedException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.WrappedException instance) { }\n\n        public global::Orleans.Runtime.WrappedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.WrappedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.WrappedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_AsyncEnumerableRequest<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Runtime.AsyncEnumerableRequest<T>>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Runtime.AsyncEnumerableRequest<T>>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public void DeepCopy(global::Orleans.Runtime.AsyncEnumerableRequest<T> input, global::Orleans.Runtime.AsyncEnumerableRequest<T> output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Runtime.AsyncEnumerableRequest<T> DeepCopy(global::Orleans.Runtime.AsyncEnumerableRequest<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ClientNotAvailableException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.ClientNotAvailableException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ClientNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EnumerationAbortedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.EnumerationAbortedException, System.Exception>\n    {\n        public Copier_EnumerationAbortedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GatewayTooBusyException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.GatewayTooBusyException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_GatewayTooBusyException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainExtensionNotInstalledException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.GrainExtensionNotInstalledException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_GrainExtensionNotInstalledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainReferenceNotBoundException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.GrainReferenceNotBoundException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_GrainReferenceNotBoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> DeepCopy(Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 DeepCopy(Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> DeepCopy(Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_LimitExceededException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.LimitExceededException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_LimitExceededException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansConfigurationException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.OrleansConfigurationException, System.Exception>\n    {\n        public Copier_OrleansConfigurationException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.OrleansException, System.Exception>\n    {\n        public Copier_OrleansException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansLifecycleCanceledException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.OrleansLifecycleCanceledException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_OrleansLifecycleCanceledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansMessageRejectionException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.OrleansMessageRejectionException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_OrleansMessageRejectionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SiloRoleBasedPlacement : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Runtime.SiloRoleBasedPlacement>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Runtime.SiloRoleBasedPlacement>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public void DeepCopy(global::Orleans.Runtime.SiloRoleBasedPlacement input, global::Orleans.Runtime.SiloRoleBasedPlacement output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Runtime.SiloRoleBasedPlacement DeepCopy(global::Orleans.Runtime.SiloRoleBasedPlacement original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SiloUnavailableException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.SiloUnavailableException, global::Orleans.Runtime.OrleansMessageRejectionException>\n    {\n        public Copier_SiloUnavailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_WrappedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.WrappedException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_WrappedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Runtime.WrappedException input, global::Orleans.Runtime.WrappedException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), \"370CD5AB\" })]\n    public sealed partial class Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_370CD5AB_1<T> : global::Orleans.Runtime.Request<(global::Orleans.Runtime.EnumerationResult, object)>\n    {\n        public System.Guid arg0;\n        public global::Orleans.Runtime.IAsyncEnumerableRequest<T> arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask<(global::Orleans.Runtime.EnumerationResult, object)> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), \"3C6D7209\" })]\n    public sealed partial class Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_3C6D7209 : global::Orleans.Runtime.Request\n    {\n        public System.Guid arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), typeof(global::Orleans.Runtime.IAsyncEnumerableGrainExtension), \"A7FA7E30\" })]\n    public sealed partial class Invokable_IAsyncEnumerableGrainExtension_GrainReference_Ext_A7FA7E30_1<T> : global::Orleans.Runtime.Request<(global::Orleans.Runtime.EnumerationResult, object)>\n    {\n        public System.Guid arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.ValueTask<(global::Orleans.Runtime.EnumerationResult, object)> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Statistics\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EnvironmentStatistics : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Statistics.EnvironmentStatistics>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Statistics.EnvironmentStatistics>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Statistics.EnvironmentStatistics instance) { }\n\n        public global::Orleans.Statistics.EnvironmentStatistics ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Statistics.EnvironmentStatistics instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Statistics.EnvironmentStatistics value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Versions.Compatibility\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AllVersionsCompatible : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Compatibility.AllVersionsCompatible>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Compatibility.AllVersionsCompatible instance) { }\n\n        public global::Orleans.Versions.Compatibility.AllVersionsCompatible ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Compatibility.AllVersionsCompatible instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Compatibility.AllVersionsCompatible value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_BackwardCompatible : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Compatibility.BackwardCompatible>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Compatibility.BackwardCompatible instance) { }\n\n        public global::Orleans.Versions.Compatibility.BackwardCompatible ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Compatibility.BackwardCompatible instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Compatibility.BackwardCompatible value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StrictVersionCompatible : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Compatibility.StrictVersionCompatible>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Compatibility.StrictVersionCompatible instance) { }\n\n        public global::Orleans.Versions.Compatibility.StrictVersionCompatible ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Compatibility.StrictVersionCompatible instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Compatibility.StrictVersionCompatible value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Versions.Selector\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AllCompatibleVersions : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Selector.AllCompatibleVersions>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Selector.AllCompatibleVersions instance) { }\n\n        public global::Orleans.Versions.Selector.AllCompatibleVersions ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Selector.AllCompatibleVersions instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Selector.AllCompatibleVersions value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LatestVersion : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Selector.LatestVersion>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Selector.LatestVersion instance) { }\n\n        public global::Orleans.Versions.Selector.LatestVersion ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Selector.LatestVersion instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Selector.LatestVersion value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MinimumVersion : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Versions.Selector.MinimumVersion>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Versions.Selector.MinimumVersion instance) { }\n\n        public global::Orleans.Versions.Selector.MinimumVersion ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Versions.Selector.MinimumVersion instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Versions.Selector.MinimumVersion value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.EventSourcing/Orleans.EventSourcing.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class CustomStorageLogConsistencyOptions\n    {\n        public string PrimaryCluster { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.EventSourcing\n{\n    [GenerateSerializer]\n    public abstract partial class ConnectionIssue\n    {\n        [Id(2)]\n        public int NumberOfConsecutiveFailures { get { throw null; } set { } }\n\n        [Id(3)]\n        public System.TimeSpan RetryDelay { get { throw null; } set { } }\n\n        [Id(1)]\n        public System.DateTime TimeOfFirstFailure { get { throw null; } set { } }\n\n        [Id(0)]\n        public System.DateTime TimeStamp { get { throw null; } set { } }\n\n        public abstract System.TimeSpan ComputeRetryDelay(System.TimeSpan? previous);\n    }\n\n    public partial interface IConnectionIssueListener\n    {\n        void OnConnectionIssue(ConnectionIssue connectionIssue);\n        void OnConnectionIssueResolved(ConnectionIssue connectionIssue);\n    }\n\n    public partial interface ILogConsistencyDiagnostics\n    {\n        void DisableStatsCollection();\n        void EnableStatsCollection();\n        LogConsistencyStatistics GetStats();\n    }\n\n    public partial interface ILogConsistencyProtocolMessage\n    {\n    }\n\n    public partial interface ILogConsistencyProtocolParticipant : IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task DeactivateProtocolParticipant();\n        System.Threading.Tasks.Task PostActivateProtocolParticipant();\n        System.Threading.Tasks.Task PreActivateProtocolParticipant();\n    }\n\n    public partial interface ILogConsistencyProtocolServices\n    {\n        Runtime.GrainId GrainId { get; }\n\n        string MyClusterId { get; }\n\n        void CaughtException(string where, System.Exception e);\n        void CaughtUserCodeException(string callback, string where, System.Exception e);\n        T DeepCopy<T>(T value);\n        void Log(Microsoft.Extensions.Logging.LogLevel level, string format, params object[] args);\n        void ProtocolError(string msg, bool throwexception);\n    }\n\n    public partial interface ILogViewAdaptorFactory\n    {\n        bool UsesStorageProvider { get; }\n\n        ILogViewAdaptor<TLogView, TLogEntry> MakeLogViewAdaptor<TLogView, TLogEntry>(ILogViewAdaptorHost<TLogView, TLogEntry> hostGrain, TLogView initialState, string grainTypeName, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where TLogView : class, new()\n            where TLogEntry : class;\n    }\n\n    public partial interface ILogViewAdaptorHost<TLogView, TLogEntry> : IConnectionIssueListener\n    {\n        void OnViewChanged(bool tentative, bool confirmed);\n        void UpdateView(TLogView view, TLogEntry entry);\n    }\n\n    public partial interface ILogViewAdaptor<TLogView, TLogEntry> : ILogViewRead<TLogView, TLogEntry>, ILogViewUpdate<TLogEntry>, ILogConsistencyDiagnostics where TLogView : new()\n    {\n        System.Threading.Tasks.Task PostOnActivate();\n        System.Threading.Tasks.Task PostOnDeactivate();\n        System.Threading.Tasks.Task PreOnActivate();\n    }\n\n    public partial interface ILogViewRead<TView, TLogEntry>\n    {\n        int ConfirmedVersion { get; }\n\n        TView ConfirmedView { get; }\n\n        TView TentativeView { get; }\n\n        System.Collections.Generic.IEnumerable<TLogEntry> UnconfirmedSuffix { get; }\n\n        System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<TLogEntry>> RetrieveLogSegment(int fromVersion, int toVersion);\n    }\n\n    public partial interface ILogViewUpdate<TLogEntry>\n    {\n        System.Threading.Tasks.Task ClearLogAsync(System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.Task ConfirmSubmittedEntries();\n        void Submit(TLogEntry entry);\n        void SubmitRange(System.Collections.Generic.IEnumerable<TLogEntry> entries);\n        System.Threading.Tasks.Task Synchronize();\n        System.Threading.Tasks.Task<bool> TryAppend(TLogEntry entry);\n        System.Threading.Tasks.Task<bool> TryAppendRange(System.Collections.Generic.IEnumerable<TLogEntry> entries);\n    }\n\n    public abstract partial class JournaledGrain<TGrainState> : JournaledGrain<TGrainState, object> where TGrainState : class, new()\n    {\n    }\n\n    public abstract partial class JournaledGrain<TGrainState, TEventBase> : LogConsistentGrain<TGrainState>, ILogConsistencyProtocolParticipant, IGrain, Runtime.IAddressable, ILogViewAdaptorHost<TGrainState, TEventBase>, IConnectionIssueListener where TGrainState : class, new()\n        where TEventBase : class\n    {\n        protected override ILogViewAdaptorFactory DefaultAdaptorFactory { get { throw null; } }\n\n        protected TGrainState State { get { throw null; } }\n\n        protected TGrainState TentativeState { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<TEventBase> UnconfirmedEvents { get { throw null; } }\n\n        protected int Version { get { throw null; } }\n\n        protected System.Threading.Tasks.Task ConfirmEvents() { throw null; }\n\n        protected void DisableStatsCollection() { }\n\n        protected void EnableStatsCollection() { }\n\n        protected LogConsistencyStatistics GetStats() { throw null; }\n\n        protected override void InstallAdaptor(ILogViewAdaptorFactory factory, object initialState, string graintypename, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services) { }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        protected virtual void OnConnectionIssue(ConnectionIssue issue) { }\n\n        protected virtual void OnConnectionIssueResolved(ConnectionIssue issue) { }\n\n        protected virtual void OnStateChanged() { }\n\n        protected virtual void OnTentativeStateChanged() { }\n\n        void IConnectionIssueListener.OnConnectionIssue(ConnectionIssue connectionIssue) { }\n\n        void IConnectionIssueListener.OnConnectionIssueResolved(ConnectionIssue connectionIssue) { }\n\n        System.Threading.Tasks.Task ILogConsistencyProtocolParticipant.DeactivateProtocolParticipant() { throw null; }\n\n        System.Threading.Tasks.Task ILogConsistencyProtocolParticipant.PostActivateProtocolParticipant() { throw null; }\n\n        System.Threading.Tasks.Task ILogConsistencyProtocolParticipant.PreActivateProtocolParticipant() { throw null; }\n\n        void ILogViewAdaptorHost<TGrainState, TEventBase>.OnViewChanged(bool tentative, bool confirmed) { }\n\n        void ILogViewAdaptorHost<TGrainState, TEventBase>.UpdateView(TGrainState view, TEventBase entry) { }\n\n        protected virtual System.Threading.Tasks.Task<bool> RaiseConditionalEvent<TEvent>(TEvent @event)\n            where TEvent : TEventBase { throw null; }\n\n        protected virtual System.Threading.Tasks.Task<bool> RaiseConditionalEvents<TEvent>(System.Collections.Generic.IEnumerable<TEvent> events)\n            where TEvent : TEventBase { throw null; }\n\n        protected virtual void RaiseEvent<TEvent>(TEvent @event)\n            where TEvent : TEventBase { }\n\n        protected virtual void RaiseEvents<TEvent>(System.Collections.Generic.IEnumerable<TEvent> events)\n            where TEvent : TEventBase { }\n\n        protected System.Threading.Tasks.Task RefreshNow() { throw null; }\n\n        protected System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<TEventBase>> RetrieveConfirmedEvents(int fromVersion, int toVersion) { throw null; }\n\n        protected virtual void TransitionState(TGrainState state, TEventBase @event) { }\n    }\n\n    public partial class LogConsistencyStatistics\n    {\n        public System.Collections.Generic.Dictionary<string, long> EventCounters;\n        public System.Collections.Generic.List<int> StabilizationLatenciesInMsecs;\n    }\n\n    public abstract partial class LogConsistentGrain<TView> : Grain, ILifecycleParticipant<Runtime.IGrainLifecycle>\n    {\n        protected abstract ILogViewAdaptorFactory DefaultAdaptorFactory { get; }\n\n        protected abstract void InstallAdaptor(ILogViewAdaptorFactory factory, object state, string grainTypeName, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services);\n        public virtual void Participate(Runtime.IGrainLifecycle lifecycle) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ProtocolTransportException : Runtime.OrleansException\n    {\n        public ProtocolTransportException() { }\n\n        [System.Obsolete]\n        protected ProtocolTransportException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public ProtocolTransportException(string msg, System.Exception exc) { }\n\n        public ProtocolTransportException(string msg) { }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.EventSourcing.Common\n{\n    [GenerateSerializer]\n    public sealed partial class BatchedNotificationMessage : INotificationMessage, ILogConsistencyProtocolMessage\n    {\n        [Id(0)]\n        public System.Collections.Generic.List<INotificationMessage> Notifications { get { throw null; } set { } }\n\n        public int Version { get { throw null; } }\n    }\n\n    public partial interface INotificationMessage : ILogConsistencyProtocolMessage\n    {\n        int Version { get; }\n    }\n\n    public abstract partial class PrimaryBasedLogViewAdaptor<TLogView, TLogEntry, TSubmissionEntry> : ILogViewAdaptor<TLogView, TLogEntry>, ILogViewRead<TLogView, TLogEntry>, ILogViewUpdate<TLogEntry>, ILogConsistencyDiagnostics where TLogView : class, new()\n        where TLogEntry : class where TSubmissionEntry : SubmissionEntry<TLogEntry>\n    {\n        protected RecordedConnectionIssue LastPrimaryIssue;\n        protected LogConsistencyStatistics stats;\n        protected PrimaryBasedLogViewAdaptor(ILogViewAdaptorHost<TLogView, TLogEntry> host, TLogView initialstate, ILogConsistencyProtocolServices services) { }\n\n        public int ConfirmedVersion { get { throw null; } }\n\n        public TLogView ConfirmedView { get { throw null; } }\n\n        protected ILogViewAdaptorHost<TLogView, TLogEntry> Host { get { throw null; } }\n\n        protected ILogConsistencyProtocolServices Services { get { throw null; } }\n\n        protected virtual bool SupportSubmissions { get { throw null; } }\n\n        public TLogView TentativeView { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<TLogEntry> UnconfirmedSuffix { get { throw null; } }\n\n        public System.Threading.Tasks.Task ConfirmSubmittedEntries() { throw null; }\n\n        protected TLogView CopyTentativeState() { throw null; }\n\n        public void DisableStatsCollection() { }\n\n        public virtual void EnableStatsCollection() { }\n\n        protected System.Threading.Tasks.Task EnsureClusterJoinedAsync() { throw null; }\n\n        protected abstract int GetConfirmedVersion();\n        protected TSubmissionEntry[] GetCurrentBatchOfUpdates() { throw null; }\n\n        protected int GetNumberPendingUpdates() { throw null; }\n\n        public LogConsistencyStatistics GetStats() { throw null; }\n\n        protected abstract void InitializeConfirmedView(TLogView initialstate);\n        protected bool IsMyClusterJoined() { throw null; }\n\n        protected abstract TLogView LastConfirmedView();\n        protected abstract TSubmissionEntry MakeSubmissionEntry(TLogEntry entry);\n        protected virtual INotificationMessage Merge(INotificationMessage earliermessage, INotificationMessage latermessage) { throw null; }\n\n        protected void NotifyPromises(int count, bool success) { }\n\n        protected virtual System.Threading.Tasks.Task<ILogConsistencyProtocolMessage> OnMessageReceived(ILogConsistencyProtocolMessage payload) { throw null; }\n\n        protected virtual void OnNotificationReceived(INotificationMessage payload) { }\n\n        public System.Threading.Tasks.Task<ILogConsistencyProtocolMessage> OnProtocolMessageReceived(ILogConsistencyProtocolMessage payLoad) { throw null; }\n\n        public virtual System.Threading.Tasks.Task PostOnActivate() { throw null; }\n\n        public virtual System.Threading.Tasks.Task PostOnDeactivate() { throw null; }\n\n        public virtual System.Threading.Tasks.Task PreOnActivate() { throw null; }\n\n        protected virtual void ProcessNotifications() { }\n\n        protected abstract System.Threading.Tasks.Task ReadAsync();\n        protected void RemoveStaleConditionalUpdates() { }\n\n        public virtual System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<TLogEntry>> RetrieveLogSegment(int fromVersion, int length) { throw null; }\n\n        public void Submit(TLogEntry logEntry) { }\n\n        public void SubmitRange(System.Collections.Generic.IEnumerable<TLogEntry> logEntries) { }\n\n        public System.Threading.Tasks.Task Synchronize() { throw null; }\n\n        public System.Threading.Tasks.Task<bool> TryAppend(TLogEntry logEntry) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> TryAppendRange(System.Collections.Generic.IEnumerable<TLogEntry> logEntries) { throw null; }\n\n        protected abstract System.Threading.Tasks.Task<int> WriteAsync();\n    }\n\n    [GenerateSerializer]\n    public abstract partial class PrimaryOperationFailed : ConnectionIssue\n    {\n        [Id(0)]\n        public System.Exception Exception { get { throw null; } set { } }\n\n        public override System.TimeSpan ComputeRetryDelay(System.TimeSpan? previous) { throw null; }\n    }\n\n    public partial struct RecordedConnectionIssue\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public ConnectionIssue Issue { get { throw null; } }\n\n        public readonly System.Threading.Tasks.Task DelayBeforeRetry() { throw null; }\n\n        public void Record(ConnectionIssue newIssue, IConnectionIssueListener listener, ILogConsistencyProtocolServices services) { }\n\n        public void Resolve(IConnectionIssueListener listener, ILogConsistencyProtocolServices services) { }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    public static partial class StringEncodedWriteVector\n    {\n        public static bool FlipBit(ref string writeVector, string Replica) { throw null; }\n\n        public static bool GetBit(string writeVector, string Replica) { throw null; }\n    }\n\n    public partial class SubmissionEntry<TLogEntry>\n    {\n        public int ConditionalPosition;\n        public TLogEntry Entry;\n        public System.Threading.Tasks.TaskCompletionSource<bool> ResultPromise;\n        public System.DateTime SubmissionTime;\n    }\n\n    [GenerateSerializer]\n    public sealed partial class VersionNotificationMessage : INotificationMessage, ILogConsistencyProtocolMessage\n    {\n        [Id(0)]\n        public int Version { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.EventSourcing.CustomStorage\n{\n    public partial interface ICustomStorageInterface<TState, TDelta>\n    {\n        System.Threading.Tasks.Task<bool> ApplyUpdatesToStorage(System.Collections.Generic.IReadOnlyList<TDelta> updates, int expectedVersion);\n        System.Threading.Tasks.Task<System.Collections.Generic.KeyValuePair<int, TState>> ReadStateFromStorage();\n    }\n\n    public partial class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        public LogConsistencyProvider(Configuration.CustomStorageLogConsistencyOptions options) { }\n\n        public string PrimaryCluster { get { throw null; } }\n\n        public bool UsesStorageProvider { get { throw null; } }\n\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where TView : class, new()\n            where TEntry : class { throw null; }\n    }\n\n    public static partial class LogConsistencyProviderFactory\n    {\n        public static ILogViewAdaptorFactory Create(System.IServiceProvider services, string name) { throw null; }\n    }\n}\n\nnamespace Orleans.EventSourcing.LogStorage\n{\n    public partial class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        public bool UsesStorageProvider { get { throw null; } }\n\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where TView : class, new()\n            where TEntry : class { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class LogStateWithMetaDataAndETag<TEntry> : IGrainState<LogStateWithMetaData<TEntry>> where TEntry : class\n    {\n        [Id(1)]\n        public string ETag { get { throw null; } set { } }\n\n        [Id(2)]\n        public bool RecordExists { get { throw null; } set { } }\n\n        public LogStateWithMetaData<TEntry> State { get { throw null; } set { } }\n\n        [Id(0)]\n        public LogStateWithMetaData<TEntry> StateAndMetaData { get { throw null; } set { } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class LogStateWithMetaData<TEntry>\n        where TEntry : class\n    {\n        public int GlobalVersion { get { throw null; } }\n\n        [Id(0)]\n        public System.Collections.Generic.List<TEntry> Log { get { throw null; } set { } }\n\n        [Id(1)]\n        public string WriteVector { get { throw null; } set { } }\n\n        public bool FlipBit(string replica) { throw null; }\n\n        public bool GetBit(string replica) { throw null; }\n    }\n}\n\nnamespace Orleans.EventSourcing.StateStorage\n{\n    [GenerateSerializer]\n    public sealed partial class GrainStateWithMetaDataAndETag<TView> : IGrainState<GrainStateWithMetaData<TView>> where TView : class, new()\n    {\n        public GrainStateWithMetaDataAndETag() { }\n\n        public GrainStateWithMetaDataAndETag(TView initialview) { }\n\n        [Id(1)]\n        public string ETag { get { throw null; } set { } }\n\n        [Id(2)]\n        public bool RecordExists { get { throw null; } set { } }\n\n        public GrainStateWithMetaData<TView> State { get { throw null; } set { } }\n\n        [Id(0)]\n        public GrainStateWithMetaData<TView> StateAndMetaData { get { throw null; } set { } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GrainStateWithMetaData<TView>\n        where TView : class, new()\n    {\n        public GrainStateWithMetaData() { }\n\n        public GrainStateWithMetaData(TView initialstate) { }\n\n        [Id(1)]\n        public int GlobalVersion { get { throw null; } set { } }\n\n        [Id(0)]\n        public TView State { get { throw null; } set { } }\n\n        [Id(2)]\n        public string WriteVector { get { throw null; } set { } }\n\n        public bool FlipBit(string Replica) { throw null; }\n\n        public bool GetBit(string Replica) { throw null; }\n    }\n\n    public partial class LogConsistencyProvider : ILogViewAdaptorFactory\n    {\n        public bool UsesStorageProvider { get { throw null; } }\n\n        public ILogViewAdaptor<TView, TEntry> MakeLogViewAdaptor<TView, TEntry>(ILogViewAdaptorHost<TView, TEntry> hostGrain, TView initialState, string grainTypeName, Storage.IGrainStorage grainStorage, ILogConsistencyProtocolServices services)\n            where TView : class, new()\n            where TEntry : class { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class CustomStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddCustomStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"LogStorage\", string primaryCluster = null) { throw null; }\n\n        public static ISiloBuilder AddCustomStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder, string primaryCluster = null) { throw null; }\n    }\n\n    public static partial class LogStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddLogStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"LogStorage\") { throw null; }\n\n        public static ISiloBuilder AddLogStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder) { throw null; }\n    }\n\n    public static partial class StateStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddStateStorageBasedLogConsistencyProvider(this ISiloBuilder builder, string name = \"StateStorage\") { throw null; }\n\n        public static ISiloBuilder AddStateStorageBasedLogConsistencyProviderAsDefault(this ISiloBuilder builder) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.EventSourcing\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ConnectionIssue : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.EventSourcing.ConnectionIssue>\n    {\n        public override void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.ConnectionIssue instance) { }\n\n        public override void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.ConnectionIssue instance) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 instance) { }\n\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 instance) { }\n\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 instance) { }\n\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ProtocolTransportException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.ProtocolTransportException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ProtocolTransportException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.ProtocolTransportException instance) { }\n\n        public global::Orleans.EventSourcing.ProtocolTransportException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.ProtocolTransportException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.ProtocolTransportException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ConnectionIssue : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.ConnectionIssue>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.EventSourcing.ConnectionIssue>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public void DeepCopy(global::Orleans.EventSourcing.ConnectionIssue input, global::Orleans.EventSourcing.ConnectionIssue output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.EventSourcing.ConnectionIssue DeepCopy(global::Orleans.EventSourcing.ConnectionIssue original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 DeepCopy(Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 DeepCopy(Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 DeepCopy(Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ProtocolTransportException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.EventSourcing.ProtocolTransportException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ProtocolTransportException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.EventSourcing.ILogConsistencyProtocolParticipant), \"0DB087C8\" })]\n    public sealed partial class Invokable_ILogConsistencyProtocolParticipant_GrainReference_0DB087C8 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.EventSourcing.ILogConsistencyProtocolParticipant), \"22FD7D72\" })]\n    public sealed partial class Invokable_ILogConsistencyProtocolParticipant_GrainReference_22FD7D72 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.EventSourcing.ILogConsistencyProtocolParticipant), \"A36FC884\" })]\n    public sealed partial class Invokable_ILogConsistencyProtocolParticipant_GrainReference_A36FC884 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.EventSourcing.Common\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_BatchedNotificationMessage : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.Common.BatchedNotificationMessage>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_BatchedNotificationMessage(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.Common.BatchedNotificationMessage instance) { }\n\n        public global::Orleans.EventSourcing.Common.BatchedNotificationMessage ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.Common.BatchedNotificationMessage instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.Common.BatchedNotificationMessage value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_PrimaryOperationFailed : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.EventSourcing.Common.PrimaryOperationFailed>\n    {\n        public Codec_PrimaryOperationFailed(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public override void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.Common.PrimaryOperationFailed instance) { }\n\n        public override void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.Common.PrimaryOperationFailed instance) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_VersionNotificationMessage : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.Common.VersionNotificationMessage>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.Common.VersionNotificationMessage instance) { }\n\n        public global::Orleans.EventSourcing.Common.VersionNotificationMessage ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.Common.VersionNotificationMessage instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.Common.VersionNotificationMessage value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_BatchedNotificationMessage : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.Common.BatchedNotificationMessage>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_BatchedNotificationMessage(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.EventSourcing.Common.BatchedNotificationMessage DeepCopy(global::Orleans.EventSourcing.Common.BatchedNotificationMessage original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_PrimaryOperationFailed : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.Common.PrimaryOperationFailed>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.EventSourcing.Common.PrimaryOperationFailed>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_PrimaryOperationFailed(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void DeepCopy(global::Orleans.EventSourcing.Common.PrimaryOperationFailed input, global::Orleans.EventSourcing.Common.PrimaryOperationFailed output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.EventSourcing.Common.PrimaryOperationFailed DeepCopy(global::Orleans.EventSourcing.Common.PrimaryOperationFailed original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_VersionNotificationMessage : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.Common.VersionNotificationMessage>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public global::Orleans.EventSourcing.Common.VersionNotificationMessage DeepCopy(global::Orleans.EventSourcing.Common.VersionNotificationMessage original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.EventSourcing.LogStorage\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LogStateWithMetaDataAndETag<TEntry> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry>>, global::Orleans.Serialization.Codecs.IFieldCodec where TEntry : class\n    {\n        public Codec_LogStateWithMetaDataAndETag(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> instance) { }\n\n        public global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_LogStateWithMetaData<TEntry> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry>>, global::Orleans.Serialization.Codecs.IFieldCodec where TEntry : class\n    {\n        public Codec_LogStateWithMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> instance) { }\n\n        public global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_LogStateWithMetaDataAndETag<TEntry> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry>>, global::Orleans.Serialization.Cloning.IDeepCopier where TEntry : class\n    {\n        public Copier_LogStateWithMetaDataAndETag(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> DeepCopy(global::Orleans.EventSourcing.LogStorage.LogStateWithMetaDataAndETag<TEntry> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_LogStateWithMetaData<TEntry> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry>>, global::Orleans.Serialization.Cloning.IDeepCopier where TEntry : class\n    {\n        public Copier_LogStateWithMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> DeepCopy(global::Orleans.EventSourcing.LogStorage.LogStateWithMetaData<TEntry> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.EventSourcing.StateStorage\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainStateWithMetaDataAndETag<TView> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView>>, global::Orleans.Serialization.Codecs.IFieldCodec where TView : class, new()\n    {\n        public Codec_GrainStateWithMetaDataAndETag(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> instance) { }\n\n        public global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainStateWithMetaData<TView> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView>>, global::Orleans.Serialization.Codecs.IFieldCodec where TView : class, new()\n    {\n        public Codec_GrainStateWithMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> instance) { }\n\n        public global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainStateWithMetaDataAndETag<TView> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView>>, global::Orleans.Serialization.Cloning.IDeepCopier where TView : class, new()\n    {\n        public Copier_GrainStateWithMetaDataAndETag(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> DeepCopy(global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaDataAndETag<TView> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainStateWithMetaData<TView> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView>>, global::Orleans.Serialization.Cloning.IDeepCopier where TView : class, new()\n    {\n        public Copier_GrainStateWithMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> DeepCopy(global::Orleans.EventSourcing.StateStorage.GrainStateWithMetaData<TView> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n"
  },
  {
    "path": "src/api/Orleans.Hosting.Kubernetes/Orleans.Hosting.Kubernetes.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class KubernetesHostingExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseKubernetesHosting(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Kubernetes.KubernetesHostingOptions>> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseKubernetesHosting(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }\n\n        public static ISiloBuilder UseKubernetesHosting(this ISiloBuilder siloBuilder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Kubernetes.KubernetesHostingOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseKubernetesHosting(this ISiloBuilder siloBuilder) { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting.Kubernetes\n{\n    public sealed partial class KubernetesClusterAgent : ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public KubernetesClusterAgent(Runtime.IClusterMembershipService clusterMembershipService, Microsoft.Extensions.Logging.ILogger<KubernetesClusterAgent> logger, Microsoft.Extensions.Options.IOptionsMonitor<KubernetesHostingOptions> options, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Runtime.ILocalSiloDetails localSiloDetails) { }\n\n        public System.Threading.Tasks.Task OnStop(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n    }\n\n    public sealed partial class KubernetesHostingOptions\n    {\n        public const string ClusterIdEnvironmentVariable = \"ORLEANS_CLUSTER_ID\";\n        public const string ClusterIdLabel = \"orleans/clusterId\";\n        public const string PodIPEnvironmentVariable = \"POD_IP\";\n        public const string PodNameEnvironmentVariable = \"POD_NAME\";\n        public const string PodNamespaceEnvironmentVariable = \"POD_NAMESPACE\";\n        public const string ServiceIdEnvironmentVariable = \"ORLEANS_SERVICE_ID\";\n        public const string ServiceIdLabel = \"orleans/serviceId\";\n        public bool DeleteDefunctSiloPods { get { throw null; } set { } }\n\n        public System.Func<k8s.KubernetesClientConfiguration> GetClientConfiguration { get { throw null; } set { } }\n\n        public int MaxAgents { get { throw null; } set { } }\n\n        public int MaxKubernetesApiRetryAttempts { get { throw null; } set { } }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Journaling/Orleans.Journaling.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Journaling\n{\n    public abstract partial class DurableGrain : Grain, IGrainBase\n    {\n        protected IStateMachineManager StateMachineManager { get { throw null; } }\n\n        protected TStateMachine GetOrCreateStateMachine<TStateMachine>(string name)\n            where TStateMachine : class, IDurableStateMachine { throw null; }\n\n        protected TStateMachine GetOrCreateStateMachine<TState, TStateMachine>(string name, System.Func<TState, TStateMachine> createStateMachine, TState state)\n            where TStateMachine : class, IDurableStateMachine { throw null; }\n\n        protected System.Threading.Tasks.ValueTask WriteStateAsync(System.Threading.CancellationToken cancellationToken = default) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct DurableTaskCompletionSourceState<T>\n    {\n        private readonly T? _Value_k__BackingField;\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        [Id(2)]\n        public System.Exception? Exception { get { throw null; } init { } }\n\n        [Id(0)]\n        public DurableTaskCompletionSourceStatus Status { get { throw null; } init { } }\n\n        [Id(1)]\n        public T? Value { get { throw null; } init { } }\n    }\n\n    [GenerateSerializer]\n    public enum DurableTaskCompletionSourceStatus : byte\n    {\n        Pending = 0,\n        Completed = 1,\n        Faulted = 2,\n        Canceled = 3\n    }\n\n    public static partial class HostingExtensions\n    {\n        public static Hosting.ISiloBuilder AddStateMachineStorage(this Hosting.ISiloBuilder builder) { throw null; }\n    }\n\n    public partial interface IDurableDictionary<K, V> : System.Collections.Generic.IDictionary<K, V>, System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>>, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<K, V>>, System.Collections.IEnumerable\n    {\n    }\n\n    public partial interface IDurableList<T> : System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable\n    {\n        void AddRange(System.Collections.Generic.IEnumerable<T> collection);\n        System.Collections.ObjectModel.ReadOnlyCollection<T> AsReadOnly();\n    }\n\n    public partial interface IDurableNothing\n    {\n    }\n\n    public partial interface IDurableQueue<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection<T>\n    {\n        void Clear();\n        bool Contains(T item);\n        void CopyTo(T[] array, int arrayIndex);\n        T Dequeue();\n        void Enqueue(T item);\n        T Peek();\n        bool TryDequeue(out T item);\n        bool TryPeek(out T item);\n    }\n\n    public partial interface IDurableSet<T> : System.Collections.Generic.ISet<T>, System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlySet<T>\n    {\n        int Count { get; }\n\n        bool Add(T item);\n        bool Contains(T item);\n        bool IsProperSubsetOf(System.Collections.Generic.IEnumerable<T> other);\n        bool IsProperSupersetOf(System.Collections.Generic.IEnumerable<T> other);\n        bool IsSubsetOf(System.Collections.Generic.IEnumerable<T> other);\n        bool IsSupersetOf(System.Collections.Generic.IEnumerable<T> other);\n        bool Overlaps(System.Collections.Generic.IEnumerable<T> other);\n        bool SetEquals(System.Collections.Generic.IEnumerable<T> other);\n    }\n\n    public partial interface IDurableStateMachine\n    {\n        void AppendEntries(StateMachineStorageWriter writer);\n        void AppendSnapshot(StateMachineStorageWriter writer);\n        void Apply(System.Buffers.ReadOnlySequence<byte> entry);\n        IDurableStateMachine DeepCopy();\n        void OnRecoveryCompleted();\n        void OnWriteCompleted();\n        void Reset(IStateMachineLogWriter storage);\n    }\n\n    public partial interface IDurableTaskCompletionSource<T>\n    {\n        DurableTaskCompletionSourceState<T> State { get; }\n\n        System.Threading.Tasks.Task<T> Task { get; }\n\n        bool TrySetCanceled();\n        bool TrySetException(System.Exception exception);\n        bool TrySetResult(T value);\n    }\n\n    public partial interface IDurableValue<T>\n    {\n        T? Value { get; set; }\n    }\n\n    public partial interface IStateMachineLogWriter\n    {\n        void AppendEntries<TState>(System.Action<TState, StateMachineStorageWriter> action, TState state);\n        void AppendEntry<TState>(System.Action<TState, System.Buffers.IBufferWriter<byte>> action, TState state);\n    }\n\n    public partial interface IStateMachineManager\n    {\n        System.Threading.Tasks.ValueTask DeleteStateAsync(System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.ValueTask InitializeAsync(System.Threading.CancellationToken cancellationToken);\n        void RegisterStateMachine(string name, IDurableStateMachine stateMachine);\n        bool TryGetStateMachine(string name, out IDurableStateMachine? stateMachine);\n        System.Threading.Tasks.ValueTask WriteStateAsync(System.Threading.CancellationToken cancellationToken);\n    }\n\n    public partial interface IStateMachineStorage\n    {\n        bool IsCompactionRequested { get; }\n\n        System.Threading.Tasks.ValueTask AppendAsync(LogExtentBuilder value, System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.ValueTask DeleteAsync(System.Threading.CancellationToken cancellationToken);\n        System.Collections.Generic.IAsyncEnumerable<LogExtent> ReadAsync(System.Threading.CancellationToken cancellationToken);\n        System.Threading.Tasks.ValueTask ReplaceAsync(LogExtentBuilder value, System.Threading.CancellationToken cancellationToken);\n    }\n\n    public partial interface IStateMachineStorageProvider\n    {\n        IStateMachineStorage Create(Runtime.IGrainContext grainContext);\n    }\n\n    public sealed partial class LogExtent : System.IDisposable\n    {\n        public LogExtent() { }\n\n        public LogExtent(Serialization.Buffers.ArcBuffer buffer) { }\n\n        public bool IsEmpty { get { throw null; } }\n\n        public void Dispose() { }\n\n        public readonly partial struct Entry : System.IEquatable<Entry>\n        {\n            private readonly int _dummyPrimitive;\n            public Entry(StateMachineId StreamId, System.Buffers.ReadOnlySequence<byte> Payload) { }\n\n            public System.Buffers.ReadOnlySequence<byte> Payload { get { throw null; } init { } }\n\n            public StateMachineId StreamId { get { throw null; } init { } }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public readonly void Deconstruct(out StateMachineId StreamId, out System.Buffers.ReadOnlySequence<byte> Payload) { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public readonly bool Equals(Entry other) { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public override readonly bool Equals(object obj) { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public override readonly int GetHashCode() { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public static bool operator ==(Entry left, Entry right) { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public static bool operator !=(Entry left, Entry right) { throw null; }\n\n            [System.Runtime.CompilerServices.CompilerGenerated]\n            public override readonly string ToString() { throw null; }\n        }\n    }\n\n    public sealed partial class LogExtentBuilder : System.IDisposable, System.Buffers.IBufferWriter<byte>\n    {\n        public LogExtentBuilder() { }\n\n        public LogExtentBuilder(Serialization.Buffers.ArcBufferWriter buffer) { }\n\n        public bool IsEmpty { get { throw null; } }\n\n        public long Length { get { throw null; } }\n\n        public void CopyTo(System.IO.Stream destination, int bufferSize) { }\n\n        public System.Threading.Tasks.ValueTask CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public StateMachineStorageWriter CreateLogWriter(StateMachineId id) { throw null; }\n\n        public void Dispose() { }\n\n        public void Reset() { }\n\n        void System.Buffers.IBufferWriter<byte>.Advance(int count) { }\n\n        System.Memory<byte> System.Buffers.IBufferWriter<byte>.GetMemory(int sizeHint) { throw null; }\n\n        System.Span<byte> System.Buffers.IBufferWriter<byte>.GetSpan(int sizeHint) { throw null; }\n\n        public byte[] ToArray() { throw null; }\n\n        public sealed partial class ReadOnlyStream : System.IO.Stream\n        {\n            public override bool CanRead { get { throw null; } }\n\n            public override bool CanSeek { get { throw null; } }\n\n            public override bool CanWrite { get { throw null; } }\n\n            public override long Length { get { throw null; } }\n\n            public override long Position { get { throw null; } set { } }\n\n            public override void CopyTo(System.IO.Stream destination, int bufferSize) { }\n\n            public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n            public override void Flush() { }\n\n            public override int Read(byte[] buffer, int offset, int count) { throw null; }\n\n            public override int Read(System.Span<byte> buffer) { throw null; }\n\n            public override System.Threading.Tasks.Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n            public override System.Threading.Tasks.ValueTask<int> ReadAsync(System.Memory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n            public void Reset() { }\n\n            public override long Seek(long offset, System.IO.SeekOrigin origin) { throw null; }\n\n            public void SetBuilder(LogExtentBuilder builder) { }\n\n            public override void SetLength(long value) { }\n\n            public override void Write(byte[] buffer, int offset, int count) { }\n\n            public override void Write(System.ReadOnlySpan<byte> buffer) { }\n\n            public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory<byte> buffer, System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n            public override void WriteByte(byte value) { }\n        }\n    }\n\n    public readonly partial struct StateMachineId : System.IEquatable<StateMachineId>\n    {\n        private readonly int _dummyPrimitive;\n        public StateMachineId(ulong Value) { }\n\n        public ulong Value { get { throw null; } init { } }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public readonly void Deconstruct(out ulong Value) { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public readonly bool Equals(StateMachineId other) { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public override readonly bool Equals(object obj) { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public override readonly int GetHashCode() { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public static bool operator ==(StateMachineId left, StateMachineId right) { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public static bool operator !=(StateMachineId left, StateMachineId right) { throw null; }\n\n        [System.Runtime.CompilerServices.CompilerGenerated]\n        public override readonly string ToString() { throw null; }\n    }\n\n    public readonly partial struct StateMachineStorageWriter\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public readonly void AppendEntry(System.ArraySegment<byte> value) { }\n\n        public readonly void AppendEntry(System.Buffers.ReadOnlySequence<byte> value) { }\n\n        public readonly void AppendEntry(byte[] value) { }\n\n        public readonly void AppendEntry(System.Memory<byte> value) { }\n\n        public readonly void AppendEntry(System.ReadOnlyMemory<byte> value) { }\n\n        public readonly void AppendEntry(System.ReadOnlySpan<byte> value) { }\n\n        public readonly void AppendEntry(System.Span<byte> value) { }\n\n        public readonly void AppendEntry<T>(System.Action<T, System.Buffers.IBufferWriter<byte>> valueWriter, T value) { }\n    }\n\n    public sealed partial class VolatileStateMachineStorage : IStateMachineStorage\n    {\n        public bool IsCompactionRequested { get { throw null; } }\n\n        public System.Threading.Tasks.ValueTask AppendAsync(LogExtentBuilder segment, System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.ValueTask DeleteAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Collections.Generic.IAsyncEnumerable<LogExtent> ReadAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.ValueTask ReplaceAsync(LogExtentBuilder snapshot, System.Threading.CancellationToken cancellationToken) { throw null; }\n    }\n\n    public sealed partial class VolatileStateMachineStorageProvider : IStateMachineStorageProvider\n    {\n        public IStateMachineStorage Create(Runtime.IGrainContext grainContext) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Journaling\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DurableTaskCompletionSourceState<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Journaling.DurableTaskCompletionSourceState<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Journaling.DurableTaskCompletionSourceState<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_DurableTaskCompletionSourceState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Journaling.DurableTaskCompletionSourceState<T> instance) { }\n\n        public global::Orleans.Journaling.DurableTaskCompletionSourceState<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Journaling.DurableTaskCompletionSourceState<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Journaling.DurableTaskCompletionSourceState<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DurableTaskCompletionSourceStatus : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Journaling.DurableTaskCompletionSourceStatus>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Journaling.DurableTaskCompletionSourceStatus ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Journaling.DurableTaskCompletionSourceStatus value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_DurableTaskCompletionSourceState<T> : global::Orleans.Serialization.Cloning.ShallowCopier<global::Orleans.Journaling.DurableTaskCompletionSourceState<T>>\n    {\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Persistence.Memory/Orleans.Persistence.Memory.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class MemoryGrainStorageOptions : Storage.IStorageProviderSerializerOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public const int NumStorageGrainsDefaultValue = 10;\n        public Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public int NumStorageGrains { get { throw null; } set { } }\n    }\n\n    public partial class MemoryGrainStorageOptionsValidator : IConfigurationValidator\n    {\n        public MemoryGrainStorageOptionsValidator(MemoryGrainStorageOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class MemoryGrainStorageSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddMemoryGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.MemoryGrainStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddMemoryGrainStorage(this ISiloBuilder builder, string name, System.Action<Configuration.MemoryGrainStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddMemoryGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.MemoryGrainStorageOptions>> configureOptions = null) { throw null; }\n\n        public static ISiloBuilder AddMemoryGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Configuration.MemoryGrainStorageOptions> configureOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.Storage\n{\n    [System.Diagnostics.DebuggerDisplay(\"MemoryStore:{name}\")]\n    public partial class MemoryGrainStorage : IGrainStorage, System.IDisposable\n    {\n        public MemoryGrainStorage(string name, Configuration.MemoryGrainStorageOptions options, Microsoft.Extensions.Logging.ILogger<MemoryGrainStorage> logger, IGrainFactory grainFactory, IGrainStorageSerializer defaultGrainStorageSerializer, Serialization.Serializers.IActivatorProvider activatorProvider) { }\n\n        public virtual System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public void Dispose() { }\n\n        public virtual System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public virtual System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class MemoryGrainStorageFactory\n    {\n        public static MemoryGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    [System.Diagnostics.DebuggerDisplay(\"MemoryStore:{Name},WithLatency:{latency}\")]\n    public partial class MemoryGrainStorageWithLatency : IGrainStorage\n    {\n        public MemoryGrainStorageWithLatency(string name, MemoryStorageWithLatencyOptions options, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, IGrainFactory grainFactory, Serialization.Serializers.IActivatorProvider activatorProvider, IGrainStorageSerializer defaultGrainStorageSerializer) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public partial class MemoryStorageWithLatencyOptions : Configuration.MemoryGrainStorageOptions\n    {\n        public static readonly System.TimeSpan DefaultLatency;\n        public System.TimeSpan Latency { get { throw null; } set { } }\n\n        public bool MockCallsOnly { get { throw null; } set { } }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Reminders/Orleans.Reminders.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    public static partial class GrainReminderExtensions\n    {\n        public static System.Threading.Tasks.Task<Runtime.IGrainReminder?> GetReminder(this Grain grain, string reminderName) { throw null; }\n\n        public static System.Threading.Tasks.Task<Runtime.IGrainReminder?> GetReminder(this IGrainBase grain, string reminderName) { throw null; }\n\n        public static System.Threading.Tasks.Task<System.Collections.Generic.List<Runtime.IGrainReminder>> GetReminders(this Grain grain) { throw null; }\n\n        public static System.Threading.Tasks.Task<System.Collections.Generic.List<Runtime.IGrainReminder>> GetReminders(this IGrainBase grain) { throw null; }\n\n        public static System.Threading.Tasks.Task<Runtime.IGrainReminder> RegisterOrUpdateReminder(this Grain grain, string reminderName, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public static System.Threading.Tasks.Task<Runtime.IGrainReminder> RegisterOrUpdateReminder(this IGrainBase grain, string reminderName, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public static System.Threading.Tasks.Task UnregisterReminder(this Grain grain, Runtime.IGrainReminder reminder) { throw null; }\n\n        public static System.Threading.Tasks.Task UnregisterReminder(this IGrainBase grain, Runtime.IGrainReminder reminder) { throw null; }\n    }\n\n    public partial interface IRemindable : IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task ReceiveReminder(string reminderName, Runtime.TickStatus status);\n    }\n\n    public partial interface IReminderService : Services.IGrainService, ISystemTarget, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task<Runtime.IGrainReminder> GetReminder(Runtime.GrainId grainId, string reminderName);\n        System.Threading.Tasks.Task<System.Collections.Generic.List<Runtime.IGrainReminder>> GetReminders(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task<Runtime.IGrainReminder> RegisterOrUpdateReminder(Runtime.GrainId grainId, string reminderName, System.TimeSpan dueTime, System.TimeSpan period);\n        System.Threading.Tasks.Task Start();\n        System.Threading.Tasks.Task Stop();\n        System.Threading.Tasks.Task UnregisterReminder(Runtime.IGrainReminder reminder);\n    }\n\n    public partial interface IReminderTable\n    {\n        [System.Obsolete(\"Implement and use StartAsync instead\")]\n        System.Threading.Tasks.Task Init();\n        System.Threading.Tasks.Task<ReminderEntry> ReadRow(Runtime.GrainId grainId, string reminderName);\n        System.Threading.Tasks.Task<ReminderTableData> ReadRows(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task<ReminderTableData> ReadRows(uint begin, uint end);\n        System.Threading.Tasks.Task<bool> RemoveRow(Runtime.GrainId grainId, string reminderName, string eTag);\n        System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken = default);\n        System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken = default);\n        System.Threading.Tasks.Task TestOnlyClearTable();\n        System.Threading.Tasks.Task<string> UpsertRow(ReminderEntry entry);\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ReminderEntry\n    {\n        [Id(4)]\n        public string ETag { get { throw null; } set { } }\n\n        [Id(0)]\n        public Runtime.GrainId GrainId { get { throw null; } set { } }\n\n        [Id(3)]\n        public System.TimeSpan Period { get { throw null; } set { } }\n\n        [Id(1)]\n        public string ReminderName { get { throw null; } set { } }\n\n        [Id(2)]\n        public System.DateTime StartAt { get { throw null; } set { } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ReminderTableData\n    {\n        public ReminderTableData() { }\n\n        public ReminderTableData(ReminderEntry entry) { }\n\n        public ReminderTableData(System.Collections.Generic.IEnumerable<ReminderEntry> list) { }\n\n        [Id(0)]\n        public System.Collections.Generic.IList<ReminderEntry> Reminders { get { throw null; } }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public sealed partial class ReminderOptions\n    {\n        public System.TimeSpan InitializationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan MinimumReminderPeriod { get { throw null; } set { } }\n\n        public System.TimeSpan RefreshReminderListPeriod { get { throw null; } set { } }\n    }\n\n    public static partial class SiloBuilderReminderExtensions\n    {\n        public static void AddReminders(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { }\n\n        public static ISiloBuilder AddReminders(this ISiloBuilder builder) { throw null; }\n    }\n\n    public static partial class SiloBuilderReminderMemoryExtensions\n    {\n        public static ISiloBuilder UseInMemoryReminderService(this ISiloBuilder builder) { throw null; }\n    }\n}\n\nnamespace Orleans.Reminders\n{\n    public enum RSErrorCode\n    {\n        ReminderServiceBase = 102900,\n        RS_Register_TableError = 102905,\n        RS_Register_AlreadyRegistered = 102907,\n        RS_Register_InvalidPeriod = 102908,\n        RS_Register_NotRemindable = 102909,\n        RS_NotResponsible = 102910,\n        RS_Unregister_NotFoundLocally = 102911,\n        RS_Unregister_TableError = 102912,\n        RS_Table_Insert = 102913,\n        RS_Table_Remove = 102914,\n        RS_Tick_Delivery_Error = 102915,\n        RS_Not_Started = 102916,\n        RS_UnregisterGrain_TableError = 102917,\n        RS_GrainBasedTable1 = 102918,\n        RS_Factory1 = 102919,\n        RS_FailedToReadTableAndStartTimer = 102920,\n        RS_TableGrainInit1 = 102921,\n        RS_TableGrainInit2 = 102922,\n        RS_TableGrainInit3 = 102923,\n        RS_GrainBasedTable2 = 102924,\n        RS_ServiceStarting = 102925,\n        RS_ServiceStarted = 102926,\n        RS_ServiceStopping = 102927,\n        RS_RegisterOrUpdate = 102928,\n        RS_Unregister = 102929,\n        RS_Stop = 102930,\n        RS_RemoveFromTable = 102931,\n        RS_GetReminder = 102932,\n        RS_GetReminders = 102933,\n        RS_RangeChanged = 102934,\n        RS_LocalStop = 102935,\n        RS_Started = 102936,\n        RS_ServiceInitialLoadFailing = 102937,\n        RS_ServiceInitialLoadFailed = 102938,\n        RS_FastReminderInterval = 102939\n    }\n}\n\nnamespace Orleans.Runtime\n{\n    public partial interface IGrainReminder\n    {\n        string ReminderName { get; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ReminderException : OrleansException\n    {\n        [System.Obsolete]\n        public ReminderException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public ReminderException(string message) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct TickStatus\n    {\n        private readonly int _dummyPrimitive;\n        public TickStatus(System.DateTime firstTickTime, System.TimeSpan period, System.DateTime timeStamp) { }\n\n        [Id(2)]\n        public System.DateTime CurrentTickTime { get { throw null; } }\n\n        [Id(0)]\n        public System.DateTime FirstTickTime { get { throw null; } }\n\n        [Id(1)]\n        public System.TimeSpan Period { get { throw null; } }\n\n        public override readonly string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Timers\n{\n    public partial interface IReminderRegistry : Services.IGrainServiceClient<IReminderService>\n    {\n        System.Threading.Tasks.Task<Runtime.IGrainReminder> GetReminder(Runtime.GrainId callingGrainId, string reminderName);\n        System.Threading.Tasks.Task<System.Collections.Generic.List<Runtime.IGrainReminder>> GetReminders(Runtime.GrainId callingGrainId);\n        System.Threading.Tasks.Task<Runtime.IGrainReminder> RegisterOrUpdateReminder(Runtime.GrainId callingGrainId, string reminderName, System.TimeSpan dueTime, System.TimeSpan period);\n        System.Threading.Tasks.Task UnregisterReminder(Runtime.GrainId callingGrainId, Runtime.IGrainReminder reminder);\n    }\n}\n\nnamespace OrleansCodeGen.Orleans\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IRemindable_GrainReference_6461BF2F : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IRemindable_GrainReference_6461BF2F>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IRemindable_GrainReference_6461BF2F(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IRemindable_GrainReference_6461BF2F instance) { }\n\n        public Invokable_IRemindable_GrainReference_6461BF2F ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IRemindable_GrainReference_6461BF2F instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IRemindable_GrainReference_6461BF2F value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_1281C86D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_1281C86D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IReminderService_GrainReference_1281C86D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_1281C86D instance) { }\n\n        public Invokable_IReminderService_GrainReference_1281C86D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_1281C86D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_1281C86D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_419EB51E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_419EB51E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IReminderService_GrainReference_419EB51E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_419EB51E instance) { }\n\n        public Invokable_IReminderService_GrainReference_419EB51E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_419EB51E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_419EB51E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_5CF78F8A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_5CF78F8A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_5CF78F8A instance) { }\n\n        public Invokable_IReminderService_GrainReference_5CF78F8A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_5CF78F8A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_5CF78F8A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_A7AF84A8 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_A7AF84A8>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IReminderService_GrainReference_A7AF84A8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_A7AF84A8 instance) { }\n\n        public Invokable_IReminderService_GrainReference_A7AF84A8 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_A7AF84A8 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_A7AF84A8 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_AC622EEB : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_AC622EEB>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IReminderService_GrainReference_AC622EEB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_AC622EEB instance) { }\n\n        public Invokable_IReminderService_GrainReference_AC622EEB ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_AC622EEB instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_AC622EEB value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IReminderService_GrainReference_DCFCA00D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IReminderService_GrainReference_DCFCA00D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IReminderService_GrainReference_DCFCA00D instance) { }\n\n        public Invokable_IReminderService_GrainReference_DCFCA00D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IReminderService_GrainReference_DCFCA00D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IReminderService_GrainReference_DCFCA00D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReminderEntry : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.ReminderEntry>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ReminderEntry(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.ReminderEntry instance) { }\n\n        public global::Orleans.ReminderEntry ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.ReminderEntry instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.ReminderEntry value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReminderTableData : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.ReminderTableData>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ReminderTableData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.ReminderTableData instance) { }\n\n        public global::Orleans.ReminderTableData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.ReminderTableData instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.ReminderTableData value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IRemindable_GrainReference_6461BF2F : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IRemindable_GrainReference_6461BF2F>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IRemindable_GrainReference_6461BF2F DeepCopy(Invokable_IRemindable_GrainReference_6461BF2F original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_1281C86D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_1281C86D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IReminderService_GrainReference_1281C86D DeepCopy(Invokable_IReminderService_GrainReference_1281C86D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_419EB51E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_419EB51E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IReminderService_GrainReference_419EB51E DeepCopy(Invokable_IReminderService_GrainReference_419EB51E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_5CF78F8A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_5CF78F8A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IReminderService_GrainReference_5CF78F8A DeepCopy(Invokable_IReminderService_GrainReference_5CF78F8A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_A7AF84A8 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_A7AF84A8>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IReminderService_GrainReference_A7AF84A8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IReminderService_GrainReference_A7AF84A8 DeepCopy(Invokable_IReminderService_GrainReference_A7AF84A8 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_AC622EEB : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_AC622EEB>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IReminderService_GrainReference_AC622EEB DeepCopy(Invokable_IReminderService_GrainReference_AC622EEB original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IReminderService_GrainReference_DCFCA00D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IReminderService_GrainReference_DCFCA00D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IReminderService_GrainReference_DCFCA00D DeepCopy(Invokable_IReminderService_GrainReference_DCFCA00D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReminderEntry : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.ReminderEntry>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public global::Orleans.ReminderEntry DeepCopy(global::Orleans.ReminderEntry original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReminderTableData : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.ReminderTableData>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ReminderTableData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.ReminderTableData DeepCopy(global::Orleans.ReminderTableData original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IRemindable), \"6461BF2F\" })]\n    public sealed partial class Invokable_IRemindable_GrainReference_6461BF2F : global::Orleans.Runtime.TaskRequest\n    {\n        public string arg0;\n        public global::Orleans.Runtime.TickStatus arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"1281C86D\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_1281C86D : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.IGrainReminder>\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public string arg1;\n        public System.TimeSpan arg2;\n        public System.TimeSpan arg3;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.IGrainReminder> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"419EB51E\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_419EB51E : global::Orleans.Runtime.TaskRequest<System.Collections.Generic.List<global::Orleans.Runtime.IGrainReminder>>\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<global::Orleans.Runtime.IGrainReminder>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"5CF78F8A\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_5CF78F8A : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"A7AF84A8\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_A7AF84A8 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.IGrainReminder arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"AC622EEB\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_AC622EEB : global::Orleans.Runtime.TaskRequest<global::Orleans.Runtime.IGrainReminder>\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public string arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Runtime.IGrainReminder> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.IReminderService), \"DCFCA00D\" })]\n    public sealed partial class Invokable_IReminderService_GrainReference_DCFCA00D : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReminderException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ReminderException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ReminderException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ReminderException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ReminderException instance) { }\n\n        public global::Orleans.Runtime.ReminderException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ReminderException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ReminderException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TickStatus : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.TickStatus>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.TickStatus>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.TickStatus instance) { }\n\n        public global::Orleans.Runtime.TickStatus ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.TickStatus instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.TickStatus value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReminderException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.ReminderException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ReminderException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Reminders.Abstractions/Orleans.Reminders.Abstractions.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/api/Orleans.Runtime/Orleans.Runtime.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Microsoft.Extensions.Hosting\n{\n    public static partial class OrleansSiloGenericHostExtensions\n    {\n        public static DependencyInjection.IServiceCollection AddOrleans(this DependencyInjection.IServiceCollection services, System.Action<Orleans.Hosting.ISiloBuilder> configureDelegate) { throw null; }\n\n        public static HostApplicationBuilder UseOrleans(this HostApplicationBuilder hostAppBuilder, System.Action<Orleans.Hosting.ISiloBuilder> configureDelegate) { throw null; }\n\n        public static HostApplicationBuilder UseOrleans(this HostApplicationBuilder hostAppBuilder) { throw null; }\n\n        public static IHostApplicationBuilder UseOrleans(this IHostApplicationBuilder hostAppBuilder, System.Action<Orleans.Hosting.ISiloBuilder> configureDelegate) { throw null; }\n\n        public static IHostApplicationBuilder UseOrleans(this IHostApplicationBuilder hostAppBuilder) { throw null; }\n\n        public static IHostBuilder UseOrleans(this IHostBuilder hostBuilder, System.Action<HostBuilderContext, Orleans.Hosting.ISiloBuilder> configureDelegate) { throw null; }\n\n        public static IHostBuilder UseOrleans(this IHostBuilder hostBuilder, System.Action<Orleans.Hosting.ISiloBuilder> configureDelegate) { throw null; }\n    }\n}\n\nnamespace Orleans\n{\n    public partial interface IFacetMetadata\n    {\n    }\n\n    public partial class PersistentStateAttributeMapper : Runtime.IAttributeToFactoryMapper<Runtime.PersistentStateAttribute>\n    {\n        public Factory<Runtime.IGrainContext, object> GetFactory(System.Reflection.ParameterInfo parameter, Runtime.PersistentStateAttribute attribute) { throw null; }\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class ActivationCountBasedPlacementOptions\n    {\n        public const int DEFAULT_ACTIVATION_COUNT_PLACEMENT_CHOOSE_OUT_OF = 2;\n        public int ChooseOutOf { get { throw null; } set { } }\n    }\n\n    public sealed partial class ActivationRebalancerOptions\n    {\n        public const int DEFAULT_ACTIVATION_MIGRATION_COUNT_LIMIT = int.MaxValue;\n        public const double DEFAULT_ALLOWED_ENTROPY_DEVIATION = 0.0001D;\n        public const double DEFAULT_CYCLE_NUMBER_WEIGHT = 0.1D;\n        public const double DEFAULT_ENTROPY_QUANTUM = 0.0001D;\n        public const int DEFAULT_MAX_STAGNANT_CYCLES = 3;\n        public static readonly System.TimeSpan DEFAULT_REBALANCER_DUE_TIME;\n        public const bool DEFAULT_SCALE_ALLOWED_ENTROPY_DEVIATION = true;\n        public const int DEFAULT_SCALED_ENTROPY_DEVIATION_ACTIVATION_THRESHOLD = 10000;\n        public static readonly System.TimeSpan DEFAULT_SESSION_CYCLE_PERIOD;\n        public const double DEFAULT_SILO_NUMBER_WEIGHT = 0.1D;\n        public const double MAX_SCALED_ENTROPY_DEVIATION = 0.1D;\n        public int ActivationMigrationCountLimit { get { throw null; } set { } }\n\n        public double AllowedEntropyDeviation { get { throw null; } set { } }\n\n        public double CycleNumberWeight { get { throw null; } set { } }\n\n        public double EntropyQuantum { get { throw null; } set { } }\n\n        public int MaxStagnantCycles { get { throw null; } set { } }\n\n        public System.TimeSpan RebalancerDueTime { get { throw null; } set { } }\n\n        public bool ScaleAllowedEntropyDeviation { get { throw null; } set { } }\n\n        public int ScaledEntropyDeviationActivationThreshold { get { throw null; } set { } }\n\n        public System.TimeSpan SessionCyclePeriod { get { throw null; } set { } }\n\n        public double SiloNumberWeight { get { throw null; } set { } }\n    }\n\n    public sealed partial class ActivationRepartitionerOptions\n    {\n        public const bool DEFAULT_ANCHORING_FILTER_ENABLED = true;\n        public const int DEFAULT_MAX_EDGE_COUNT = 10000;\n        public const int DEFAULT_MAX_UNPROCESSED_EDGES = 100000;\n        public static readonly System.TimeSpan DEFAULT_MAXIMUM_ROUND_PERIOD;\n        public static readonly System.TimeSpan DEFAULT_MINUMUM_ROUND_PERIOD;\n        public const double DEFAULT_PROBABILISTIC_FILTERING_MAX_ALLOWED_ERROR = 0.01D;\n        public static readonly System.TimeSpan DEFAULT_RECOVERY_PERIOD;\n        public bool AnchoringFilterEnabled { get { throw null; } set { } }\n\n        public int MaxEdgeCount { get { throw null; } set { } }\n\n        public System.TimeSpan MaxRoundPeriod { get { throw null; } set { } }\n\n        public int MaxUnprocessedEdges { get { throw null; } set { } }\n\n        public System.TimeSpan MinRoundPeriod { get { throw null; } set { } }\n\n        public double ProbabilisticFilteringMaxAllowedErrorRate { get { throw null; } set { } }\n\n        public System.TimeSpan RecoveryPeriod { get { throw null; } set { } }\n    }\n\n    public partial class ConsistentRingOptions\n    {\n        public const int DEFAULT_NUM_VIRTUAL_RING_BUCKETS = 30;\n        public const bool DEFAULT_USE_VIRTUAL_RING_BUCKETS = true;\n        public int NumVirtualBucketsConsistentRing { get { throw null; } set { } }\n\n        public bool UseVirtualBucketsConsistentRing { get { throw null; } set { } }\n    }\n\n    public partial class DeploymentLoadPublisherOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_DEPLOYMENT_LOAD_PUBLISHER_REFRESH_TIME;\n        public System.TimeSpan DeploymentLoadPublisherRefreshTime { get { throw null; } set { } }\n    }\n\n    public partial class DevelopmentClusterMembershipOptions\n    {\n        public System.Net.IPEndPoint PrimarySiloEndpoint { get { throw null; } set { } }\n    }\n\n    public partial class EndpointOptions\n    {\n        public const int DEFAULT_GATEWAY_PORT = 30000;\n        public const int DEFAULT_SILO_PORT = 11111;\n        public System.Net.IPAddress AdvertisedIPAddress { get { throw null; } set { } }\n\n        public System.Net.IPEndPoint GatewayListeningEndpoint { get { throw null; } set { } }\n\n        public int GatewayPort { get { throw null; } set { } }\n\n        public System.Net.IPEndPoint SiloListeningEndpoint { get { throw null; } set { } }\n\n        public int SiloPort { get { throw null; } set { } }\n    }\n\n    public partial class GrainCollectionOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_ACTIVATION_TIMEOUT;\n        public static readonly System.TimeSpan DEFAULT_COLLECTION_QUANTUM;\n        public static readonly System.TimeSpan DEFAULT_DEACTIVATION_TIMEOUT;\n        public System.TimeSpan ActivationTimeout { get { throw null; } set { } }\n\n        public System.Collections.Generic.Dictionary<string, System.TimeSpan> ClassSpecificCollectionAge { get { throw null; } set { } }\n\n        public System.TimeSpan CollectionAge { get { throw null; } set { } }\n\n        public System.TimeSpan CollectionQuantum { get { throw null; } set { } }\n\n        public System.TimeSpan DeactivationTimeout { get { throw null; } set { } }\n\n        public bool EnableActivationSheddingOnMemoryPressure { get { throw null; } set { } }\n\n        public double MemoryUsageLimitPercentage { get { throw null; } set { } }\n\n        public System.TimeSpan MemoryUsagePollingPeriod { get { throw null; } set { } }\n\n        public double MemoryUsageTargetPercentage { get { throw null; } set { } }\n    }\n\n    public partial class GrainDirectoryOptions\n    {\n        public const int DEFAULT_CACHE_SIZE = 1000000;\n        public const CachingStrategyType DEFAULT_CACHING_STRATEGY = 1;\n        [System.Obsolete(\"DEFAULT_INITIAL_CACHE_TTL is deprecated and will be removed in a future version.\")]\n        public static readonly System.TimeSpan DEFAULT_INITIAL_CACHE_TTL;\n        [System.Obsolete(\"DEFAULT_MAXIMUM_CACHE_TTL is deprecated and will be removed in a future version.\")]\n        public static readonly System.TimeSpan DEFAULT_MAXIMUM_CACHE_TTL;\n        [System.Obsolete(\"DEFAULT_TTL_EXTENSION_FACTOR is deprecated and will be removed in a future version.\")]\n        public const double DEFAULT_TTL_EXTENSION_FACTOR = 2D;\n        public static readonly System.TimeSpan DEFAULT_UNREGISTER_RACE_DELAY;\n        public int CacheSize { get { throw null; } set { } }\n\n        [System.Obsolete(\"CacheTTLExtensionFactor is deprecated and will be removed in a future version.\")]\n        public double CacheTTLExtensionFactor { get { throw null; } set { } }\n\n        public CachingStrategyType CachingStrategy { get { throw null; } set { } }\n\n        [System.Obsolete(\"InitialCacheTTL is deprecated and will be removed in a future version.\")]\n        public System.TimeSpan InitialCacheTTL { get { throw null; } set { } }\n\n        public System.TimeSpan LazyDeregistrationDelay { get { throw null; } set { } }\n\n        [System.Obsolete(\"MaximumCacheTTL is deprecated and will be removed in a future version.\")]\n        public System.TimeSpan MaximumCacheTTL { get { throw null; } set { } }\n\n        public enum CachingStrategyType\n        {\n            None = 0,\n            LRU = 1,\n            Adaptive = 2,\n            Custom = 3\n        }\n    }\n\n    public sealed partial class ResourceOptimizedPlacementOptions\n    {\n        public const int DEFAULT_ACTIVATION_COUNT_WEIGHT = 15;\n        public const int DEFAULT_AVAILABLE_MEMORY_WEIGHT = 20;\n        public const int DEFAULT_CPU_USAGE_WEIGHT = 40;\n        public const int DEFAULT_LOCAL_SILO_PREFERENCE_MARGIN = 5;\n        public const int DEFAULT_MAX_AVAILABLE_MEMORY_WEIGHT = 5;\n        public const int DEFAULT_MEMORY_USAGE_WEIGHT = 20;\n        public int ActivationCountWeight { get { throw null; } set { } }\n\n        public int AvailableMemoryWeight { get { throw null; } set { } }\n\n        public int CpuUsageWeight { get { throw null; } set { } }\n\n        public int LocalSiloPreferenceMargin { get { throw null; } set { } }\n\n        public int MaxAvailableMemoryWeight { get { throw null; } set { } }\n\n        public int MemoryUsageWeight { get { throw null; } set { } }\n    }\n\n    public partial class SchedulingOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_ACTIVATION_SCHEDULING_QUANTUM;\n        public static readonly System.TimeSpan DEFAULT_DELAY_WARNING_THRESHOLD;\n        public const int DEFAULT_MAX_PENDING_ITEMS_SOFT_LIMIT = 0;\n        public static readonly System.TimeSpan DEFAULT_TURN_WARNING_THRESHOLD;\n        public System.TimeSpan ActivationSchedulingQuantum { get { throw null; } set { } }\n\n        public System.TimeSpan DelayWarningThreshold { get { throw null; } set { } }\n\n        public int MaxPendingWorkItemsSoftLimit { get { throw null; } set { } }\n\n        public System.TimeSpan StoppedActivationWarningInterval { get { throw null; } set { } }\n\n        public System.TimeSpan TurnWarningLengthThreshold { get { throw null; } set { } }\n    }\n\n    public partial class SiloConnectionOptions : SiloConnectionOptions.ISiloConnectionBuilderOptions\n    {\n        public void ConfigureGatewayInboundConnection(System.Action<Microsoft.AspNetCore.Connections.IConnectionBuilder> configure) { }\n\n        public void ConfigureSiloInboundConnection(System.Action<Microsoft.AspNetCore.Connections.IConnectionBuilder> configure) { }\n\n        public void ConfigureSiloOutboundConnection(System.Action<Microsoft.AspNetCore.Connections.IConnectionBuilder> configure) { }\n\n        void ISiloConnectionBuilderOptions.ConfigureGatewayInboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder) { }\n\n        void ISiloConnectionBuilderOptions.ConfigureSiloInboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder) { }\n\n        void ISiloConnectionBuilderOptions.ConfigureSiloOutboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder) { }\n\n        public partial interface ISiloConnectionBuilderOptions\n        {\n            void ConfigureGatewayInboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder);\n            void ConfigureSiloInboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder);\n            void ConfigureSiloOutboundBuilder(Microsoft.AspNetCore.Connections.IConnectionBuilder builder);\n        }\n    }\n\n    public partial class SiloMessagingOptions : MessagingOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_CLIENT_GW_NOTIFICATION_TIMEOUT;\n        public static readonly System.TimeSpan DEFAULT_CLIENT_REGISTRATION_REFRESH;\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_HARD_LIMIT = 0;\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_SOFT_LIMIT = 0;\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_HARD_LIMIT = 0;\n        public const int DEFAULT_MAX_ENQUEUED_REQUESTS_STATELESS_WORKER_SOFT_LIMIT = 0;\n        public static readonly System.TimeSpan DEFAULT_MAX_REQUEST_PROCESSING_TIME;\n        [System.Obsolete(\"Unused, will be removed in a future version.\")]\n        public static readonly System.TimeSpan DEFAULT_SHUTDOWN_REROUTE_TIMEOUT;\n        public static readonly System.TimeSpan DEFAULT_WAIT_FOR_MESSAGE_TO_BE_QUEUED_FOR_OUTBOUND_TIME;\n        public bool AssumeHomogenousSilosForTesting { get { throw null; } set { } }\n\n        public System.TimeSpan ClientDropTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan ClientGatewayShutdownNotificationTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan ClientRegistrationRefresh { get { throw null; } set { } }\n\n        public int GatewaySenderQueues { get { throw null; } set { } }\n\n        public System.TimeSpan GrainWorkloadAnalysisPeriod { get { throw null; } set { } }\n\n        public int MaxEnqueuedRequestsHardLimit { get { throw null; } set { } }\n\n        public int MaxEnqueuedRequestsHardLimit_StatelessWorker { get { throw null; } set { } }\n\n        public int MaxEnqueuedRequestsSoftLimit { get { throw null; } set { } }\n\n        public int MaxEnqueuedRequestsSoftLimit_StatelessWorker { get { throw null; } set { } }\n\n        public int MaxForwardCount { get { throw null; } set { } }\n\n        public System.TimeSpan MaxRequestProcessingTime { get { throw null; } set { } }\n\n        public System.TimeSpan RequestProcessingWarningTime { get { throw null; } set { } }\n\n        public System.TimeSpan RequestQueueDelayWarningTime { get { throw null; } set { } }\n\n        [System.Obsolete(\"Unused, will be removed in a future version.\")]\n        public System.TimeSpan ShutdownRerouteTimeout { get { throw null; } set { } }\n\n        public int SiloSenderQueues { get { throw null; } set { } }\n\n        public System.TimeSpan SystemResponseTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan WaitForMessageToBeQueuedForOutboundTime { get { throw null; } set { } }\n    }\n\n    public partial class SiloOptions\n    {\n        public string SiloName { get { throw null; } set { } }\n    }\n\n    public partial class StatelessWorkerOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_IDLE_WORKERS_INSPECTION_PERIOD;\n        public const int DEFAULT_MIN_IDLE_CYCLES_BEFORE_REMOVAL = 3;\n        public const bool DEFAULT_REMOVE_IDLE_WORKERS = true;\n        public System.TimeSpan IdleWorkersInspectionPeriod { get { throw null; } set { } }\n\n        public int MinIdleCyclesBeforeRemoval { get { throw null; } set { } }\n\n        public bool RemoveIdleWorkers { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Core\n{\n    public partial class StateStorageBridge<TState> : IStorage<TState>, IStorage, Runtime.IGrainMigrationParticipant\n    {\n        [System.Obsolete(\"Use StateStorageBridge(string, IGrainContext, IGrainStorage) instead.\")]\n        public StateStorageBridge(string name, Runtime.IGrainContext grainContext, Storage.IGrainStorage store, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Serialization.Serializers.IActivatorProvider activatorProvider) { }\n\n        public StateStorageBridge(string name, Runtime.IGrainContext grainContext, Storage.IGrainStorage store) { }\n\n        public string? Etag { get { throw null; } set { } }\n\n        public bool RecordExists { get { throw null; } }\n\n        public TState State { get { throw null; } set { } }\n\n        public System.Threading.Tasks.Task ClearStateAsync() { throw null; }\n\n        public void OnDehydrate(Runtime.IDehydrationContext dehydrationContext) { }\n\n        public void OnRehydrate(Runtime.IRehydrationContext rehydrationContext) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync() { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync() { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ActivationRebalancerExtensions\n    {\n        [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP002\")]\n        public static ISiloBuilder AddActivationRebalancer(this ISiloBuilder builder) { throw null; }\n\n        [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP002\")]\n        public static ISiloBuilder AddActivationRebalancer<TProvider>(this ISiloBuilder builder)\n            where TProvider : class, Placement.Rebalancing.IFailedSessionBackoffProvider { throw null; }\n    }\n\n    public static partial class ActivationRepartitioningExtensions\n    {\n        [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP001\")]\n        public static ISiloBuilder AddActivationRepartitioner(this ISiloBuilder builder) { throw null; }\n\n        [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP001\")]\n        public static ISiloBuilder AddActivationRepartitioner<TRule>(this ISiloBuilder builder)\n            where TRule : class, Placement.Repartitioning.IImbalanceToleranceRule { throw null; }\n    }\n\n    public static partial class CoreHostingExtensions\n    {\n        public static ISiloBuilder AddActivityPropagation(this ISiloBuilder builder) { throw null; }\n\n        [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP003\")]\n        public static ISiloBuilder AddDistributedGrainDirectory(this ISiloBuilder siloBuilder, string? name = null) { throw null; }\n\n        public static ISiloBuilder UseDevelopmentClustering(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.DevelopmentClusterMembershipOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseDevelopmentClustering(this ISiloBuilder builder, System.Action<Configuration.DevelopmentClusterMembershipOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseDevelopmentClustering(this ISiloBuilder builder, System.Net.IPEndPoint primarySiloEndpoint) { throw null; }\n\n        public static ISiloBuilder UseLocalhostClustering(this ISiloBuilder builder, int siloPort = 11111, int gatewayPort = 30000, System.Net.IPEndPoint? primarySiloEndpoint = null, string serviceId = \"dev\", string clusterId = \"dev\") { throw null; }\n    }\n\n    public static partial class EndpointOptionsExtensions\n    {\n        public static ISiloBuilder ConfigureEndpoints(this ISiloBuilder builder, int siloPort, int gatewayPort, System.Net.Sockets.AddressFamily addressFamily = System.Net.Sockets.AddressFamily.InterNetwork, bool listenOnAnyHostAddress = false) { throw null; }\n\n        public static ISiloBuilder ConfigureEndpoints(this ISiloBuilder builder, System.Net.IPAddress advertisedIP, int siloPort, int gatewayPort, bool listenOnAnyHostAddress = false) { throw null; }\n\n        public static ISiloBuilder ConfigureEndpoints(this ISiloBuilder builder, string hostname, int siloPort, int gatewayPort, System.Net.Sockets.AddressFamily addressFamily = System.Net.Sockets.AddressFamily.InterNetwork, bool listenOnAnyHostAddress = false) { throw null; }\n    }\n\n    public static partial class GrainCallFilterSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddIncomingGrainCallFilter(this ISiloBuilder builder, IIncomingGrainCallFilter filter) { throw null; }\n\n        public static ISiloBuilder AddIncomingGrainCallFilter(this ISiloBuilder builder, IncomingGrainCallFilterDelegate filter) { throw null; }\n\n        public static ISiloBuilder AddIncomingGrainCallFilter<TImplementation>(this ISiloBuilder builder)\n            where TImplementation : class, IIncomingGrainCallFilter { throw null; }\n\n        public static ISiloBuilder AddOutgoingGrainCallFilter(this ISiloBuilder builder, IOutgoingGrainCallFilter filter) { throw null; }\n\n        public static ISiloBuilder AddOutgoingGrainCallFilter(this ISiloBuilder builder, OutgoingGrainCallFilterDelegate filter) { throw null; }\n\n        public static ISiloBuilder AddOutgoingGrainCallFilter<TImplementation>(this ISiloBuilder builder)\n            where TImplementation : class, IOutgoingGrainCallFilter { throw null; }\n    }\n\n    public static partial class GrainServicesSiloBuilderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Type grainServiceType) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainService<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }\n\n        public static ISiloBuilder AddGrainService<T>(this ISiloBuilder builder)\n            where T : Runtime.GrainService { throw null; }\n    }\n\n    public static partial class HostingGrainExtensions\n    {\n        public static ISiloBuilder AddGrainExtension<TExtensionInterface, TExtension>(this ISiloBuilder builder)\n            where TExtensionInterface : class, Runtime.IGrainExtension where TExtension : class, TExtensionInterface { throw null; }\n    }\n\n    public partial interface ISiloBuilder\n    {\n        Microsoft.Extensions.Configuration.IConfiguration Configuration { get; }\n\n        Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }\n    }\n\n    public static partial class PlacementStrategyExtensions\n    {\n        public static void AddPlacementDirector<TStrategy>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Func<System.IServiceProvider, Runtime.Placement.IPlacementDirector> createDirector, Microsoft.Extensions.DependencyInjection.ServiceLifetime strategyLifetime)\n            where TStrategy : Runtime.PlacementStrategy, new() { }\n\n        public static void AddPlacementDirector<TStrategy>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Func<System.IServiceProvider, Runtime.Placement.IPlacementDirector> createDirector)\n            where TStrategy : Runtime.PlacementStrategy, new() { }\n\n        public static ISiloBuilder AddPlacementDirector<TStrategy>(this ISiloBuilder builder, System.Func<System.IServiceProvider, Runtime.Placement.IPlacementDirector> createDirector)\n            where TStrategy : Runtime.PlacementStrategy, new() { throw null; }\n\n        public static void AddPlacementDirector<TStrategy, TDirector>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, Microsoft.Extensions.DependencyInjection.ServiceLifetime strategyLifetime)\n            where TStrategy : Runtime.PlacementStrategy, new()\n            where TDirector : class, Runtime.Placement.IPlacementDirector { }\n\n        public static void AddPlacementDirector<TStrategy, TDirector>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TStrategy : Runtime.PlacementStrategy, new()\n            where TDirector : class, Runtime.Placement.IPlacementDirector { }\n\n        public static ISiloBuilder AddPlacementDirector<TStrategy, TDirector>(this ISiloBuilder builder)\n            where TStrategy : Runtime.PlacementStrategy, new()\n            where TDirector : class, Runtime.Placement.IPlacementDirector { throw null; }\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder Configure<TOptions>(this ISiloBuilder builder, Microsoft.Extensions.Configuration.IConfiguration configuration)\n            where TOptions : class { throw null; }\n\n        public static ISiloBuilder Configure<TOptions>(this ISiloBuilder builder, System.Action<TOptions> configureOptions)\n            where TOptions : class { throw null; }\n\n        public static ISiloBuilder ConfigureLogging(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }\n\n        public static ISiloBuilder ConfigureServices(this ISiloBuilder builder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> configureDelegate) { throw null; }\n    }\n\n    public static partial class SiloBuilderStartupExtensions\n    {\n        public static ISiloBuilder AddStartupTask(this ISiloBuilder builder, Runtime.IStartupTask startupTask, int stage = 20000) { throw null; }\n\n        public static ISiloBuilder AddStartupTask(this ISiloBuilder builder, System.Func<System.IServiceProvider, System.Threading.CancellationToken, System.Threading.Tasks.Task> startupTask, int stage = 20000) { throw null; }\n\n        public static ISiloBuilder AddStartupTask<TStartup>(this ISiloBuilder builder, int stage = 20000)\n            where TStartup : class, Runtime.IStartupTask { throw null; }\n    }\n}\n\nnamespace Orleans.Metadata\n{\n    public partial class GrainClassMap\n    {\n        public GrainClassMap(Serialization.TypeSystem.TypeConverter typeConverter, System.Collections.Immutable.ImmutableDictionary<Runtime.GrainType, System.Type> classes) { }\n\n        public bool TryGetGrainClass(Runtime.GrainType grainType, out System.Type grainClass) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime\n{\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class ClusterMember : System.IEquatable<ClusterMember>\n    {\n        public ClusterMember(SiloAddress siloAddress, SiloStatus status, string name) { }\n\n        [Id(2)]\n        public string Name { get { throw null; } }\n\n        [Id(0)]\n        public SiloAddress SiloAddress { get { throw null; } }\n\n        [Id(1)]\n        public SiloStatus Status { get { throw null; } }\n\n        public bool Equals(ClusterMember other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class ClusterMembershipSnapshot\n    {\n        public ClusterMembershipSnapshot(System.Collections.Immutable.ImmutableDictionary<SiloAddress, ClusterMember> members, MembershipVersion version) { }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableDictionary<SiloAddress, ClusterMember> Members { get { throw null; } }\n\n        [Id(1)]\n        public MembershipVersion Version { get { throw null; } }\n\n        public ClusterMembershipUpdate AsUpdate() { throw null; }\n\n        public ClusterMembershipUpdate CreateUpdate(ClusterMembershipSnapshot previous) { throw null; }\n\n        public SiloStatus GetSiloStatus(SiloAddress silo) { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class ClusterMembershipUpdate\n    {\n        public ClusterMembershipUpdate(ClusterMembershipSnapshot snapshot, System.Collections.Immutable.ImmutableArray<ClusterMember> changes) { }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableArray<ClusterMember> Changes { get { throw null; } }\n\n        public bool HasChanges { get { throw null; } }\n\n        [Id(1)]\n        public ClusterMembershipSnapshot Snapshot { get { throw null; } }\n    }\n\n    public partial class DefaultGrainActivator : IGrainActivator\n    {\n        public DefaultGrainActivator(System.IServiceProvider serviceProvider, System.Type grainClass) { }\n\n        public object CreateInstance(IGrainContext context) { throw null; }\n\n        public System.Threading.Tasks.ValueTask DisposeInstance(IGrainContext context, object instance) { throw null; }\n    }\n\n    public partial class GrainConstructorArgumentFactory\n    {\n        public GrainConstructorArgumentFactory(System.IServiceProvider serviceProvider, System.Type grainType) { }\n\n        public System.Type[] ArgumentTypes { get { throw null; } }\n\n        public object[] CreateArguments(IGrainContext grainContext) { throw null; }\n    }\n\n    public sealed partial class GrainContextActivator\n    {\n        public GrainContextActivator(System.Collections.Generic.IEnumerable<IGrainContextActivatorProvider> providers, System.Collections.Generic.IEnumerable<IConfigureGrainContextProvider> configureContextActions, Orleans.Metadata.GrainPropertiesResolver grainPropertiesResolver) { }\n\n        public IGrainContext CreateInstance(GrainAddress address) { throw null; }\n    }\n\n    public abstract partial class GrainService : SystemTarget, Orleans.Services.IGrainService, ISystemTarget, IAddressable\n    {\n        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n        [System.Obsolete(\"Do not call the empty constructor.\")]\n        protected GrainService() { }\n\n        protected GrainService(GrainId grainId, Silo silo, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        protected int RangeSerialNumber { get { throw null; } }\n\n        protected IRingRange RingRange { get { throw null; } }\n\n        protected GrainServiceStatus Status { get { throw null; } set { } }\n\n        protected System.Threading.CancellationTokenSource StoppedCancellationTokenSource { get { throw null; } }\n\n        public virtual System.Threading.Tasks.Task Init(System.IServiceProvider serviceProvider) { throw null; }\n\n        public virtual System.Threading.Tasks.Task OnRangeChange(IRingRange oldRange, IRingRange newRange, bool increased) { throw null; }\n\n        public virtual System.Threading.Tasks.Task Start() { throw null; }\n\n        protected virtual System.Threading.Tasks.Task StartInBackground() { throw null; }\n\n        public virtual System.Threading.Tasks.Task Stop() { throw null; }\n\n        protected enum GrainServiceStatus\n        {\n            Booting = 0,\n            Started = 1,\n            Stopped = 2\n        }\n    }\n\n    public sealed partial class GrainTypeSharedContext\n    {\n        public GrainTypeSharedContext(GrainType grainType, IClusterManifestProvider clusterManifestProvider, Orleans.Metadata.GrainClassMap grainClassMap, Placement.PlacementStrategyResolver placementStrategyResolver, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.SiloMessagingOptions> messagingOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.GrainCollectionOptions> collectionOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.SchedulingOptions> schedulingOptions, Microsoft.Extensions.Options.IOptions<Orleans.Configuration.StatelessWorkerOptions> statelessWorkerOptions, IGrainRuntime grainRuntime, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, GrainReferences.GrainReferenceActivator grainReferenceActivator, System.IServiceProvider serviceProvider, Orleans.Serialization.Session.SerializerSessionPool serializerSessionPool) { }\n\n        public System.TimeSpan CollectionAgeLimit { get { throw null; } }\n\n        public Orleans.GrainDirectory.IGrainDirectory? GrainDirectory { get { throw null; } }\n\n        public GrainReferences.GrainReferenceActivator GrainReferenceActivator { get { throw null; } }\n\n        public string? GrainTypeName { get { throw null; } }\n\n        public Microsoft.Extensions.Logging.ILogger Logger { get { throw null; } }\n\n        public System.TimeSpan MaxRequestProcessingTime { get { throw null; } }\n\n        public System.TimeSpan MaxWarningRequestProcessingTime { get { throw null; } }\n\n        public Orleans.Configuration.SiloMessagingOptions MessagingOptions { get { throw null; } }\n\n        public PlacementStrategy PlacementStrategy { get { throw null; } }\n\n        public IGrainRuntime Runtime { get { throw null; } }\n\n        public Orleans.Configuration.SchedulingOptions SchedulingOptions { get { throw null; } }\n\n        public Orleans.Serialization.Session.SerializerSessionPool SerializerSessionPool { get { throw null; } }\n\n        public Orleans.Configuration.StatelessWorkerOptions StatelessWorkerOptions { get { throw null; } }\n\n        public TComponent? GetComponent<TComponent>() { throw null; }\n\n        public void OnCreateActivation(IGrainContext grainContext) { }\n\n        public void OnDestroyActivation(IGrainContext grainContext) { }\n\n        public void SetComponent<TComponent>(TComponent? instance) { }\n    }\n\n    public partial class GrainTypeSharedContextResolver\n    {\n        public GrainTypeSharedContextResolver(System.Collections.Generic.IEnumerable<IConfigureGrainTypeComponents> configurators, Orleans.Metadata.GrainPropertiesResolver grainPropertiesResolver, System.IServiceProvider serviceProvider) { }\n\n        public GrainTypeSharedContext GetComponents(GrainType grainType) { throw null; }\n    }\n\n    public partial interface IActivationWorkingSet\n    {\n        int Count { get; }\n\n        void OnActivated(IActivationWorkingSetMember member);\n        void OnActive(IActivationWorkingSetMember member);\n        void OnDeactivated(IActivationWorkingSetMember member);\n        void OnDeactivating(IActivationWorkingSetMember member);\n    }\n\n    public partial interface IActivationWorkingSetMember\n    {\n        bool IsCandidateForRemoval(bool wouldRemove);\n    }\n\n    public partial interface IActivationWorkingSetObserver\n    {\n        void OnActive(IActivationWorkingSetMember member);\n        void OnAdded(IActivationWorkingSetMember member);\n        void OnDeactivated(IActivationWorkingSetMember member);\n        void OnDeactivating(IActivationWorkingSetMember member);\n        void OnEvicted(IActivationWorkingSetMember member);\n        void OnIdle(IActivationWorkingSetMember member);\n    }\n\n    public partial interface IAttributeToFactoryMapper<in TMetadata>\n        where TMetadata : IFacetMetadata\n    {\n        Factory<IGrainContext, object> GetFactory(System.Reflection.ParameterInfo parameter, TMetadata metadata);\n    }\n\n    public partial interface IClusterMembershipService\n    {\n        ClusterMembershipSnapshot CurrentSnapshot { get; }\n\n        System.Collections.Generic.IAsyncEnumerable<ClusterMembershipSnapshot> MembershipUpdates { get; }\n\n        System.Threading.Tasks.ValueTask Refresh(MembershipVersion minimumVersion = default);\n        System.Threading.Tasks.Task<bool> TryKill(SiloAddress siloAddress);\n    }\n\n    public partial interface IConfigureGrainContext\n    {\n        void Configure(IGrainContext context);\n    }\n\n    public partial interface IConfigureGrainContextProvider\n    {\n        bool TryGetConfigurator(GrainType grainType, Orleans.Metadata.GrainProperties properties, out IConfigureGrainContext configurator);\n    }\n\n    public partial interface IConfigureGrainTypeComponents\n    {\n        void Configure(GrainType grainType, Orleans.Metadata.GrainProperties properties, GrainTypeSharedContext shared);\n    }\n\n    public partial interface IFatalErrorHandler\n    {\n        bool IsUnexpected(System.Exception exception);\n        void OnFatalException(object sender = null, string context = null, System.Exception exception = null);\n    }\n\n    public partial interface IGrainActivator\n    {\n        object CreateInstance(IGrainContext context);\n        System.Threading.Tasks.ValueTask DisposeInstance(IGrainContext context, object instance);\n    }\n\n    public partial interface IGrainContextActivator\n    {\n        IGrainContext CreateContext(GrainAddress address);\n    }\n\n    public partial interface IGrainContextActivatorProvider\n    {\n        bool TryGet(GrainType grainType, out IGrainContextActivator activator);\n    }\n\n    public partial interface IGrainServiceFactory\n    {\n        T CastToGrainServiceReference<T>(GrainReference grainReference)\n            where T : Orleans.Services.IGrainService;\n    }\n\n    public partial interface IHealthCheckParticipant : IHealthCheckable\n    {\n    }\n\n    public partial interface IPersistentStateConfiguration\n    {\n        string StateName { get; }\n\n        string StorageName { get; }\n    }\n\n    public partial interface IPersistentStateFactory\n    {\n        IPersistentState<TState> Create<TState>(IGrainContext context, IPersistentStateConfiguration config);\n    }\n\n    public partial interface IPersistentState<TState> : Core.IStorage<TState>, Core.IStorage\n    {\n    }\n\n    public partial interface ISiloLifecycle : ILifecycleObservable\n    {\n        int HighestCompletedStage { get; }\n\n        int LowestStoppedStage { get; }\n    }\n\n    public partial interface ISiloLifecycleSubject : ISiloLifecycle, ILifecycleObservable, ILifecycleObserver\n    {\n    }\n\n    public partial interface ISiloStatusListener\n    {\n        void SiloStatusChangeNotification(SiloAddress updatedSilo, SiloStatus status);\n    }\n\n    public partial interface ISiloStatusOracle\n    {\n        SiloStatus CurrentStatus { get; }\n\n        SiloAddress SiloAddress { get; }\n\n        string SiloName { get; }\n\n        System.Collections.Immutable.ImmutableArray<SiloAddress> GetActiveSilos();\n        SiloStatus GetApproximateSiloStatus(SiloAddress siloAddress);\n        System.Collections.Generic.Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false);\n        bool IsDeadSilo(SiloAddress silo);\n        bool IsFunctionalDirectory(SiloAddress siloAddress);\n        bool SubscribeToSiloStatusEvents(ISiloStatusListener observer);\n        bool TryGetSiloName(SiloAddress siloAddress, out string siloName);\n        bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener observer);\n    }\n\n    public partial interface IStartupTask\n    {\n        System.Threading.Tasks.Task Execute(System.Threading.CancellationToken cancellationToken);\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Parameter)]\n    public partial class PersistentStateAttribute : System.Attribute, IFacetMetadata, IPersistentStateConfiguration\n    {\n        public PersistentStateAttribute(string stateName, string storageName = null) { }\n\n        public string StateName { get { throw null; } }\n\n        public string StorageName { get { throw null; } }\n    }\n\n    public partial class PersistentStateFactory : IPersistentStateFactory\n    {\n        public IPersistentState<TState> Create<TState>(IGrainContext context, IPersistentStateConfiguration cfg) { throw null; }\n\n        protected virtual string GetFullStateName(IGrainContext context, IPersistentStateConfiguration cfg) { throw null; }\n    }\n\n    public sealed partial class Silo : System.IAsyncDisposable, System.IDisposable\n    {\n        public const string PrimarySiloName = \"Primary\";\n        [System.Obsolete(\"This constructor is obsolete and may be removed in a future release. Use SiloHostBuilder to create an instance of ISiloHost instead.\")]\n        public Silo(ILocalSiloDetails siloDetails, System.IServiceProvider services) { }\n\n        public SiloAddress SiloAddress { get { throw null; } }\n\n        public System.Threading.Tasks.Task SiloTerminated { get { throw null; } }\n\n        public void Dispose() { }\n\n        public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public void Stop() { }\n\n        public System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class SiloLifecycleSubject : LifecycleSubject, ISiloLifecycleSubject, ISiloLifecycle, ILifecycleObservable, ILifecycleObserver\n    {\n        public SiloLifecycleSubject(Microsoft.Extensions.Logging.ILogger<SiloLifecycleSubject> logger) : base(default!) { }\n\n        public int HighestCompletedStage { get { throw null; } }\n\n        public int LowestStoppedStage { get { throw null; } }\n\n        protected override string GetStageName(int stage) { throw null; }\n\n        public override System.Threading.Tasks.Task OnStart(System.Threading.CancellationToken cancellationToken = default) { throw null; }\n\n        protected override void OnStartStageCompleted(int stage) { }\n\n        protected override void OnStopStageCompleted(int stage) { }\n\n        protected override void PerfMeasureOnStart(int stage, System.TimeSpan elapsed) { }\n\n        protected override void PerfMeasureOnStop(int stage, System.TimeSpan elapsed) { }\n\n        public override System.IDisposable Subscribe(string observerName, int stage, ILifecycleObserver observer) { throw null; }\n    }\n\n    public abstract partial class SystemTarget : ISystemTarget, IAddressable, IGrainContext, Orleans.Serialization.Invocation.ITargetHolder, System.IEquatable<IGrainContext>, IGrainExtensionBinder, System.ISpanFormattable, System.IFormattable, System.IDisposable\n    {\n        public System.IServiceProvider ActivationServices { get { throw null; } }\n\n        public System.Threading.Tasks.Task Deactivated { get { throw null; } }\n\n        public GrainId GrainId { get { throw null; } }\n\n        public GrainReference GrainReference { get { throw null; } }\n\n        ActivationId IGrainContext.ActivationId { get { throw null; } }\n\n        GrainAddress IGrainContext.Address { get { throw null; } }\n\n        object IGrainContext.GrainInstance { get { throw null; } }\n\n        IGrainLifecycle IGrainContext.ObservableLifecycle { get { throw null; } }\n\n        public IWorkItemScheduler Scheduler { get { throw null; } }\n\n        public SiloAddress Silo { get { throw null; } }\n\n        public void Activate(System.Collections.Generic.Dictionary<string, object> requestContext, System.Threading.CancellationToken cancellationToken) { }\n\n        public void Deactivate(DeactivationReason deactivationReason, System.Threading.CancellationToken cancellationToken) { }\n\n        public void Dispose() { }\n\n        public TComponent GetComponent<TComponent>() { throw null; }\n\n        public TExtensionInterface GetExtension<TExtensionInterface>()\n            where TExtensionInterface : class, IGrainExtension { throw null; }\n\n        public (TExtension, TExtensionInterface) GetOrSetExtension<TExtension, TExtensionInterface>(System.Func<TExtension> newExtensionFunc)\n            where TExtension : class, TExtensionInterface where TExtensionInterface : class, IGrainExtension { throw null; }\n\n        public TTarget GetTarget<TTarget>()\n            where TTarget : class { throw null; }\n\n        public void Migrate(System.Collections.Generic.Dictionary<string, object> requestContext, System.Threading.CancellationToken cancellationToken) { }\n\n        TComponent Orleans.Serialization.Invocation.ITargetHolder.GetComponent<TComponent>() { throw null; }\n\n        public void ReceiveMessage(object message) { }\n\n        public IGrainTimer RegisterGrainTimer(System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public IGrainTimer RegisterGrainTimer<TState>(System.Func<TState, System.Threading.CancellationToken, System.Threading.Tasks.Task> callback, TState state, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public IGrainTimer RegisterTimer(System.Func<object, System.Threading.Tasks.Task> callback, object state, System.TimeSpan dueTime, System.TimeSpan period) { throw null; }\n\n        public void Rehydrate(IRehydrationContext context) { }\n\n        public void SetComponent<TComponent>(TComponent instance)\n            where TComponent : class { }\n\n        bool System.IEquatable<IGrainContext>.Equals(IGrainContext other) { throw null; }\n\n        string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider) { throw null; }\n\n        bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider provider) { throw null; }\n\n        public sealed override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Development\n{\n    public static partial class DevelopmentSiloBuilderExtensions\n    {\n        public static Orleans.Hosting.ISiloBuilder UseInMemoryLeaseProvider(this Orleans.Hosting.ISiloBuilder builder) { throw null; }\n    }\n\n    public partial class InMemoryLeaseProvider : LeaseProviders.ILeaseProvider\n    {\n        public InMemoryLeaseProvider(IGrainFactory grainFactory) { }\n\n        public System.Threading.Tasks.Task<LeaseProviders.AcquireLeaseResult[]> Acquire(string category, LeaseProviders.LeaseRequest[] leaseRequests) { throw null; }\n\n        public System.Threading.Tasks.Task Release(string category, LeaseProviders.AcquiredLease[] acquiredLeases) { throw null; }\n\n        public System.Threading.Tasks.Task<LeaseProviders.AcquireLeaseResult[]> Renew(string category, LeaseProviders.AcquiredLease[] acquiredLeases) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.GrainDirectory\n{\n    public static partial class GrainDirectoryCacheFactory\n    {\n        public static IGrainDirectoryCache CreateGrainDirectoryCache(System.IServiceProvider services, Orleans.Configuration.GrainDirectoryOptions options) { throw null; }\n    }\n\n    public partial interface IGrainDirectoryCache\n    {\n        System.Collections.Generic.IEnumerable<(GrainAddress ActivationAddress, int Version)> KeyValues { get; }\n\n        void AddOrUpdate(GrainAddress value, int version);\n        void Clear();\n        bool LookUp(GrainId key, out GrainAddress result, out int version);\n        bool Remove(GrainAddress key);\n        bool Remove(GrainId key);\n    }\n\n    public partial interface IGrainDirectoryResolver\n    {\n        bool TryResolveGrainDirectory(GrainType grainType, Orleans.Metadata.GrainProperties properties, out Orleans.GrainDirectory.IGrainDirectory grainDirectory);\n    }\n}\n\nnamespace Orleans.Runtime.Hosting\n{\n    public static partial class DirectorySiloBuilderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainDirectory<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection collection, string name, System.Func<System.IServiceProvider, string, T> implementationFactory)\n            where T : class, Orleans.GrainDirectory.IGrainDirectory { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder AddGrainDirectory<T>(this Orleans.Hosting.ISiloBuilder builder, string name, System.Func<System.IServiceProvider, string, T> implementationFactory)\n            where T : class, Orleans.GrainDirectory.IGrainDirectory { throw null; }\n    }\n\n    public static partial class StorageProviderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddGrainStorage<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection collection, string name, System.Func<System.IServiceProvider, string, T> implementationFactory)\n            where T : Storage.IGrainStorage { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.MembershipService\n{\n    [GenerateSerializer]\n    public sealed partial class OrleansClusterConnectivityCheckFailedException : OrleansException\n    {\n        public OrleansClusterConnectivityCheckFailedException() { }\n\n        public OrleansClusterConnectivityCheckFailedException(string message, System.Exception innerException) { }\n\n        public OrleansClusterConnectivityCheckFailedException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansMissingMembershipEntryException : OrleansException\n    {\n        public OrleansMissingMembershipEntryException() { }\n\n        public OrleansMissingMembershipEntryException(string message, System.Exception innerException) { }\n\n        public OrleansMissingMembershipEntryException(string message) { }\n    }\n}\n\nnamespace Orleans.Runtime.MembershipService.SiloMetadata\n{\n    public partial interface ISiloMetadataCache\n    {\n        SiloMetadata GetSiloMetadata(SiloAddress siloAddress);\n    }\n\n    [GenerateSerializer]\n    [Alias(\"Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata\")]\n    public partial record SiloMetadata()\n    {\n        public static SiloMetadata Empty { get { throw null; } }\n\n        [Id(0)]\n        public System.Collections.Immutable.ImmutableDictionary<string, string> Metadata { get { throw null; } }\n    }\n\n    public static partial class SiloMetadataHostingExtensions\n    {\n        public static Orleans.Hosting.ISiloBuilder UseSiloMetadata(this Orleans.Hosting.ISiloBuilder builder, Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseSiloMetadata(this Orleans.Hosting.ISiloBuilder builder, Microsoft.Extensions.Configuration.IConfigurationSection configurationSection) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseSiloMetadata(this Orleans.Hosting.ISiloBuilder builder, System.Collections.Generic.Dictionary<string, string> metadata) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseSiloMetadata(this Orleans.Hosting.ISiloBuilder builder) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Placement\n{\n    public partial interface IPlacementStrategyResolver\n    {\n        bool TryResolvePlacementStrategy(GrainType grainType, Orleans.Metadata.GrainProperties properties, out PlacementStrategy result);\n    }\n\n    public sealed partial class PlacementDirectorResolver\n    {\n        public PlacementDirectorResolver(System.IServiceProvider services) { }\n\n        public IPlacementDirector GetPlacementDirector(PlacementStrategy placementStrategy) { throw null; }\n    }\n\n    public sealed partial class PlacementStrategyResolver\n    {\n        public PlacementStrategyResolver(System.IServiceProvider services, System.Collections.Generic.IEnumerable<IPlacementStrategyResolver> resolvers, Orleans.Metadata.GrainPropertiesResolver grainPropertiesResolver) { }\n\n        public PlacementStrategy GetPlacementStrategy(GrainType grainType) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Placement.Filtering\n{\n    public sealed partial class PlacementFilterDirectorResolver\n    {\n        public PlacementFilterDirectorResolver(System.IServiceProvider services) { }\n\n        public Orleans.Placement.IPlacementFilterDirector GetFilterDirector(Orleans.Placement.PlacementFilterStrategy placementFilterStrategy) { throw null; }\n    }\n\n    public sealed partial class PlacementFilterStrategyResolver\n    {\n        public PlacementFilterStrategyResolver(System.IServiceProvider services, Orleans.Metadata.GrainPropertiesResolver grainPropertiesResolver) { }\n\n        public Orleans.Placement.PlacementFilterStrategy[] GetPlacementFilterStrategies(GrainType grainType) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP004\")]\n    public partial class PreferredMatchSiloMetadataPlacementFilterAttribute : Orleans.Placement.PlacementFilterAttribute\n    {\n        public PreferredMatchSiloMetadataPlacementFilterAttribute(string[] orderedMetadataKeys, int minCandidates = 2, int order = 0) : base(default!) { }\n    }\n\n    public partial class PreferredMatchSiloMetadataPlacementFilterStrategy : Orleans.Placement.PlacementFilterStrategy\n    {\n        public PreferredMatchSiloMetadataPlacementFilterStrategy() : base(default) { }\n\n        public PreferredMatchSiloMetadataPlacementFilterStrategy(string[] orderedMetadataKeys, int minCandidates, int order) : base(default) { }\n\n        public int MinCandidates { get { throw null; } set { } }\n\n        public string[] OrderedMetadataKeys { get { throw null; } set { } }\n\n        public override void AdditionalInitialize(Orleans.Metadata.GrainProperties properties) { }\n\n        protected override System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> GetAdditionalGrainProperties(System.IServiceProvider services, System.Type grainClass, GrainType grainType, System.Collections.Generic.IReadOnlyDictionary<string, string> existingProperties) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false)]\n    [System.Diagnostics.CodeAnalysis.Experimental(\"ORLEANSEXP004\")]\n    public partial class RequiredMatchSiloMetadataPlacementFilterAttribute : Orleans.Placement.PlacementFilterAttribute\n    {\n        public RequiredMatchSiloMetadataPlacementFilterAttribute(string[] metadataKeys, int order = 0) : base(default!) { }\n    }\n\n    public partial class RequiredMatchSiloMetadataPlacementFilterStrategy : Orleans.Placement.PlacementFilterStrategy\n    {\n        public RequiredMatchSiloMetadataPlacementFilterStrategy() : base(default) { }\n\n        public RequiredMatchSiloMetadataPlacementFilterStrategy(string[] metadataKeys, int order) : base(default) { }\n\n        public string[] MetadataKeys { get { throw null; } }\n\n        public override void AdditionalInitialize(Orleans.Metadata.GrainProperties properties) { }\n\n        protected override System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> GetAdditionalGrainProperties(System.IServiceProvider services, System.Type grainClass, GrainType grainType, System.Collections.Generic.IReadOnlyDictionary<string, string> existingProperties) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Services\n{\n    public abstract partial class GrainServiceClient<TGrainService> : Orleans.Services.IGrainServiceClient<TGrainService> where TGrainService : Orleans.Services.IGrainService\n    {\n        protected GrainServiceClient(System.IServiceProvider serviceProvider) { }\n\n        protected GrainReference CurrentGrainReference { get { throw null; } }\n\n        protected TGrainService GetGrainService(GrainId callingGrainId) { throw null; }\n\n        protected TGrainService GetGrainService(SiloAddress destination) { throw null; }\n\n        protected TGrainService GetGrainService(uint key) { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Utilities\n{\n    public static partial class OrleansDebuggerHelper\n    {\n        public static object GetGrainInstance(object grainReference) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.LeaseProviders\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILeaseProvider_GrainReference_5C7B2877 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILeaseProvider_GrainReference_5C7B2877>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ILeaseProvider_GrainReference_5C7B2877(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILeaseProvider_GrainReference_5C7B2877 instance) { }\n\n        public Invokable_ILeaseProvider_GrainReference_5C7B2877 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILeaseProvider_GrainReference_5C7B2877 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILeaseProvider_GrainReference_5C7B2877 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILeaseProvider_GrainReference_ACF8E0DD : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILeaseProvider_GrainReference_ACF8E0DD>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ILeaseProvider_GrainReference_ACF8E0DD(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILeaseProvider_GrainReference_ACF8E0DD instance) { }\n\n        public Invokable_ILeaseProvider_GrainReference_ACF8E0DD ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILeaseProvider_GrainReference_ACF8E0DD instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILeaseProvider_GrainReference_ACF8E0DD value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ILeaseProvider_GrainReference_F2BF11D0 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ILeaseProvider_GrainReference_F2BF11D0>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ILeaseProvider_GrainReference_F2BF11D0(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ILeaseProvider_GrainReference_F2BF11D0 instance) { }\n\n        public Invokable_ILeaseProvider_GrainReference_F2BF11D0 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ILeaseProvider_GrainReference_F2BF11D0 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ILeaseProvider_GrainReference_F2BF11D0 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILeaseProvider_GrainReference_5C7B2877 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILeaseProvider_GrainReference_5C7B2877>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ILeaseProvider_GrainReference_5C7B2877(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_ILeaseProvider_GrainReference_5C7B2877 DeepCopy(Invokable_ILeaseProvider_GrainReference_5C7B2877 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILeaseProvider_GrainReference_ACF8E0DD : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILeaseProvider_GrainReference_ACF8E0DD>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ILeaseProvider_GrainReference_ACF8E0DD(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_ILeaseProvider_GrainReference_ACF8E0DD DeepCopy(Invokable_ILeaseProvider_GrainReference_ACF8E0DD original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ILeaseProvider_GrainReference_F2BF11D0 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ILeaseProvider_GrainReference_F2BF11D0>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ILeaseProvider_GrainReference_F2BF11D0(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_ILeaseProvider_GrainReference_F2BF11D0 DeepCopy(Invokable_ILeaseProvider_GrainReference_F2BF11D0 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.LeaseProviders.ILeaseProvider), \"5C7B2877\" })]\n    public sealed partial class Invokable_ILeaseProvider_GrainReference_5C7B2877 : global::Orleans.Runtime.TaskRequest<global::Orleans.LeaseProviders.AcquireLeaseResult[]>\n    {\n        public string arg0;\n        public global::Orleans.LeaseProviders.LeaseRequest[] arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.LeaseProviders.AcquireLeaseResult[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.LeaseProviders.ILeaseProvider), \"ACF8E0DD\" })]\n    public sealed partial class Invokable_ILeaseProvider_GrainReference_ACF8E0DD : global::Orleans.Runtime.TaskRequest<global::Orleans.LeaseProviders.AcquireLeaseResult[]>\n    {\n        public string arg0;\n        public global::Orleans.LeaseProviders.AcquiredLease[] arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.LeaseProviders.AcquireLeaseResult[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.LeaseProviders.ILeaseProvider), \"F2BF11D0\" })]\n    public sealed partial class Invokable_ILeaseProvider_GrainReference_F2BF11D0 : global::Orleans.Runtime.TaskRequest\n    {\n        public string arg0;\n        public global::Orleans.LeaseProviders.AcquiredLease[] arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClusterMember : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ClusterMember>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ClusterMember(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ClusterMember> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ClusterMember instance) { }\n\n        public global::Orleans.Runtime.ClusterMember ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ClusterMember instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ClusterMember value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClusterMembershipSnapshot : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ClusterMembershipSnapshot>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ClusterMembershipSnapshot(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ClusterMembershipSnapshot> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ClusterMembershipSnapshot instance) { }\n\n        public global::Orleans.Runtime.ClusterMembershipSnapshot ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ClusterMembershipSnapshot instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ClusterMembershipSnapshot value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ClusterMembershipUpdate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.ClusterMembershipUpdate>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ClusterMembershipUpdate(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Runtime.ClusterMembershipUpdate> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.ClusterMembershipUpdate instance) { }\n\n        public global::Orleans.Runtime.ClusterMembershipUpdate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.ClusterMembershipUpdate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.ClusterMembershipUpdate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime.MembershipService\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansClusterConnectivityCheckFailedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansClusterConnectivityCheckFailedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException instance) { }\n\n        public global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansMissingMembershipEntryException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansMissingMembershipEntryException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException instance) { }\n\n        public global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansClusterConnectivityCheckFailedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.MembershipService.OrleansClusterConnectivityCheckFailedException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_OrleansClusterConnectivityCheckFailedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansMissingMembershipEntryException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Runtime.MembershipService.OrleansMissingMembershipEntryException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_OrleansMissingMembershipEntryException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime.MembershipService.SiloMetadata\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SiloMetadata : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_SiloMetadata(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata instance) { }\n\n        public global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SiloMetadata : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public void DeepCopy(global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata input, global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata DeepCopy(global::Orleans.Runtime.MembershipService.SiloMetadata.SiloMetadata original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Sdk/Orleans.Sdk.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/api/Orleans.Serialization/Orleans.Serialization.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [GenerateSerializer]\n    public sealed partial class CodecNotFoundException : SerializerException\n    {\n        public CodecNotFoundException(string message) { }\n    }\n\n    public sealed partial class DeepCopier\n    {\n        public DeepCopier(Serializers.CodecProvider codecProvider, Cloning.CopyContextPool contextPool) { }\n\n        public T Copy<T>(T value) { throw null; }\n\n        public DeepCopier<T> GetCopier<T>() { throw null; }\n    }\n\n    public sealed partial class DeepCopier<T>\n    {\n        public DeepCopier(Cloning.IDeepCopier<T> copier, Cloning.CopyContextPool contextPool) { }\n\n        public T Copy(T value) { throw null; }\n    }\n\n    [Alias(\"ISerializable\")]\n    public partial class DotNetSerializableCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec\n    {\n        public static readonly System.Type CodecType;\n        public DotNetSerializableCodec(TypeSystem.TypeConverter typeResolver) { }\n\n        [System.Security.SecurityCritical]\n        public bool IsSupportedType(System.Type type) { throw null; }\n\n        [System.Security.SecurityCritical]\n        public object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        [System.Security.SecurityCritical]\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    [RegisterCopier]\n    [Alias(\"Exception\")]\n    public sealed partial class ExceptionCodec : Codecs.IFieldCodec<System.Exception>, Codecs.IFieldCodec, Serializers.IBaseCodec<System.Exception>, Serializers.IBaseCodec, Serializers.IGeneralizedCodec, Serializers.IGeneralizedBaseCodec, Serializers.IBaseCodec<object>, Cloning.IBaseCopier<System.Exception>, Cloning.IBaseCopier\n    {\n        public ExceptionCodec(TypeSystem.TypeConverter typeConverter, Codecs.IFieldCodec<System.Collections.Generic.Dictionary<object, object>> dictionaryCodec, Cloning.IDeepCopier<System.Collections.Generic.Dictionary<object, object>> dictionaryCopier, Cloning.IDeepCopier<System.Exception> exceptionCopier, Microsoft.Extensions.Options.IOptions<ExceptionSerializationOptions> exceptionSerializationOptions) { }\n\n        public void DeepCopy(System.Exception input, System.Exception output, Cloning.CopyContext context) { }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, System.Exception value) { }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, object value) { }\n\n        public System.Exception DeserializeException<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public System.Collections.Generic.Dictionary<object, object> GetDataProperty(System.Exception exception) { throw null; }\n\n        public System.Runtime.Serialization.SerializationInfo GetObjectData(System.Exception value) { throw null; }\n\n        public bool IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public System.Exception ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Exception value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void SerializeException<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Exception value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void SetBaseProperties(System.Exception value, string message, string stackTrace, System.Exception innerException, int hResult, System.Collections.Generic.Dictionary<object, object> data) { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Exception value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial class ExceptionSerializationOptions\n    {\n        public System.Func<System.Type, bool> SupportedExceptionTypeFilter { get { throw null; } set { } }\n\n        public System.Collections.Generic.HashSet<string> SupportedNamespacePrefixes { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ExtendedWireTypeInvalidException : SerializerException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class FieldIdNotPresentException : SerializerException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class FieldTypeInvalidException : SerializerException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class FieldTypeMissingException : SerializerException\n    {\n        public FieldTypeMissingException(System.Type type) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class IllegalTypeException : SerializerException\n    {\n        public IllegalTypeException(string typeName) { }\n\n        [Id(0)]\n        public string TypeName { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    public partial interface ISerializerBuilder\n    {\n        Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }\n    }\n\n    public partial interface ITypeConverter\n    {\n        bool TryFormat(System.Type type, out string formatted);\n        bool TryParse(string formatted, out System.Type type);\n    }\n\n    public partial interface ITypeFilter\n    {\n        bool? IsTypeAllowed(System.Type type);\n    }\n\n    public partial interface ITypeNameFilter\n    {\n        bool? IsTypeNameAllowed(string typeName, string assemblyName);\n    }\n\n    public sealed partial class ObjectSerializer\n    {\n        public ObjectSerializer(Session.SerializerSessionPool sessionPool) { }\n\n        public bool CanSerialize(System.Type type) { throw null; }\n\n        public object Deserialize(System.ArraySegment<byte> source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(System.ArraySegment<byte> source, System.Type type) { throw null; }\n\n        public object Deserialize(System.Buffers.ReadOnlySequence<byte> source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(System.Buffers.ReadOnlySequence<byte> source, System.Type type) { throw null; }\n\n        public object Deserialize(byte[] source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(byte[] source, System.Type type) { throw null; }\n\n        public object Deserialize(System.IO.Stream source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(System.IO.Stream source, System.Type type) { throw null; }\n\n        public object Deserialize(System.ReadOnlyMemory<byte> source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(System.ReadOnlyMemory<byte> source, System.Type type) { throw null; }\n\n        public object Deserialize(System.ReadOnlySpan<byte> source, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public object Deserialize(System.ReadOnlySpan<byte> source, System.Type type) { throw null; }\n\n        public object Deserialize<TInput>(ref Buffers.Reader<TInput> source, System.Type type) { throw null; }\n\n        public int Serialize(object value, System.ArraySegment<byte> destination, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public int Serialize(object value, System.ArraySegment<byte> destination, System.Type type) { throw null; }\n\n        public int Serialize(object value, byte[] destination, Session.SerializerSession session, System.Type type) { throw null; }\n\n        public int Serialize(object value, byte[] destination, System.Type type) { throw null; }\n\n        public void Serialize(object value, System.IO.Stream destination, Session.SerializerSession session, System.Type type, int sizeHint = 0) { }\n\n        public void Serialize(object value, System.IO.Stream destination, System.Type type, int sizeHint = 0) { }\n\n        public void Serialize(object value, ref System.Memory<byte> destination, Session.SerializerSession session, System.Type type) { }\n\n        public void Serialize(object value, ref System.Memory<byte> destination, System.Type type) { }\n\n        public void Serialize(object value, ref System.Span<byte> destination, Session.SerializerSession session, System.Type type) { }\n\n        public void Serialize(object value, ref System.Span<byte> destination, System.Type type) { }\n\n        public void Serialize<TBufferWriter>(object value, TBufferWriter destination, Session.SerializerSession session, System.Type type)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(object value, TBufferWriter destination, System.Type type)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(object value, ref Buffers.Writer<TBufferWriter> destination, System.Type type)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ReferenceFieldNotSupportedException : SerializerException\n    {\n        public ReferenceFieldNotSupportedException(System.Type targetType) { }\n\n        [Id(0)]\n        public System.Type TargetReferenceType { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ReferenceNotFoundException : SerializerException\n    {\n        public ReferenceNotFoundException(System.Type targetType, uint targetId) { }\n\n        [Id(0)]\n        public uint TargetReference { get { throw null; } }\n\n        [Id(1)]\n        public System.Type TargetReferenceType { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class RequiredFieldMissingException : SerializerException\n    {\n        public RequiredFieldMissingException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class SchemaTypeInvalidException : SerializerException\n    {\n    }\n\n    public partial class SerializationConstructorNotFoundException : System.Exception\n    {\n        [System.Security.SecurityCritical]\n        [System.Obsolete]\n        protected SerializationConstructorNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        [System.Security.SecurityCritical]\n        public SerializationConstructorNotFoundException(System.Type type) { }\n    }\n\n    public sealed partial class Serializer\n    {\n        public Serializer(Session.SerializerSessionPool sessionPool) { }\n\n        public Session.SerializerSessionPool SessionPool { get { throw null; } }\n\n        public bool CanSerialize(System.Type type) { throw null; }\n\n        public bool CanSerialize<T>() { throw null; }\n\n        public T Deserialize<T>(Buffers.PooledBuffer.BufferSlice source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(Buffers.PooledBuffer.BufferSlice source) { throw null; }\n\n        public T Deserialize<T>(System.ArraySegment<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(System.ArraySegment<byte> source) { throw null; }\n\n        public T Deserialize<T>(System.Buffers.ReadOnlySequence<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(System.Buffers.ReadOnlySequence<byte> source) { throw null; }\n\n        public T Deserialize<T>(byte[] source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(byte[] source) { throw null; }\n\n        public T Deserialize<T>(System.IO.Stream source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(System.IO.Stream source) { throw null; }\n\n        public T Deserialize<T>(System.ReadOnlyMemory<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(System.ReadOnlyMemory<byte> source) { throw null; }\n\n        public T Deserialize<T>(System.ReadOnlySpan<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize<T>(System.ReadOnlySpan<byte> source) { throw null; }\n\n        public T Deserialize<T, TInput>(ref Buffers.Reader<TInput> source) { throw null; }\n\n        public Serializer<T> GetSerializer<T>() { throw null; }\n\n        public int Serialize<T>(T value, System.ArraySegment<byte> destination, Session.SerializerSession session) { throw null; }\n\n        public int Serialize<T>(T value, System.ArraySegment<byte> destination) { throw null; }\n\n        public int Serialize<T>(T value, byte[] destination, Session.SerializerSession session) { throw null; }\n\n        public int Serialize<T>(T value, byte[] destination) { throw null; }\n\n        public void Serialize<T>(T value, System.IO.Stream destination, Session.SerializerSession session, int sizeHint = 0) { }\n\n        public void Serialize<T>(T value, System.IO.Stream destination, int sizeHint = 0) { }\n\n        public void Serialize<T>(T value, ref System.Memory<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize<T>(T value, ref System.Memory<byte> destination) { }\n\n        public void Serialize<T>(T value, ref System.Span<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize<T>(T value, ref System.Span<byte> destination) { }\n\n        public void Serialize<T, TBufferWriter>(T value, TBufferWriter destination, Session.SerializerSession session)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<T, TBufferWriter>(T value, TBufferWriter destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<T, TBufferWriter>(T value, ref Buffers.Writer<TBufferWriter> destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public byte[] SerializeToArray<T>(T value) { throw null; }\n    }\n\n    public static partial class SerializerBuilderExtensions\n    {\n        public static ISerializerBuilder AddAssembly(this ISerializerBuilder builder, System.Reflection.Assembly assembly) { throw null; }\n\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, Microsoft.Extensions.Options.IConfigureOptions<Configuration.TypeManifestOptions> configure) { throw null; }\n\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, System.Action<Configuration.TypeManifestOptions> configure) { throw null; }\n\n        public static ISerializerBuilder Configure(this ISerializerBuilder builder, System.Func<System.IServiceProvider, Microsoft.Extensions.Options.IConfigureOptions<Configuration.TypeManifestOptions>> factory) { throw null; }\n    }\n\n    public static partial class SerializerConfigurationAnalyzer\n    {\n        public static System.Collections.Generic.Dictionary<System.Type, SerializerConfigurationComplaint> AnalyzeSerializerAvailability(Serializers.ICodecProvider codecProvider, Configuration.TypeManifestOptions options) { throw null; }\n\n        public partial class SerializerConfigurationComplaint\n        {\n            public bool HasCopier { get { throw null; } set { } }\n\n            public bool HasSerializer { get { throw null; } set { } }\n\n            public System.Collections.Generic.Dictionary<System.Type, System.Collections.Generic.HashSet<System.Reflection.MethodInfo>> Methods { get { throw null; } }\n        }\n    }\n\n    [GenerateSerializer]\n    public partial class SerializerException : System.Exception\n    {\n        public SerializerException() { }\n\n        [System.Obsolete]\n        protected SerializerException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public SerializerException(string message, System.Exception innerException) { }\n\n        public SerializerException(string message) { }\n    }\n\n    public sealed partial class Serializer<T>\n    {\n        public Serializer(Codecs.IFieldCodec<T> codec, Session.SerializerSessionPool sessionPool) { }\n\n        public Serializer(Session.SerializerSessionPool sessionPool) { }\n\n        public T Deserialize(Buffers.PooledBuffer.BufferSlice source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(Buffers.PooledBuffer.BufferSlice source) { throw null; }\n\n        public T Deserialize(System.ArraySegment<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(System.ArraySegment<byte> source) { throw null; }\n\n        public T Deserialize(System.Buffers.ReadOnlySequence<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(System.Buffers.ReadOnlySequence<byte> source) { throw null; }\n\n        public T Deserialize(byte[] source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(byte[] source) { throw null; }\n\n        public T Deserialize(System.IO.Stream source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(System.IO.Stream source) { throw null; }\n\n        public T Deserialize(System.ReadOnlyMemory<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(System.ReadOnlyMemory<byte> source) { throw null; }\n\n        public T Deserialize(System.ReadOnlySpan<byte> source, Session.SerializerSession session) { throw null; }\n\n        public T Deserialize(System.ReadOnlySpan<byte> source) { throw null; }\n\n        public T Deserialize<TInput>(ref Buffers.Reader<TInput> source) { throw null; }\n\n        public int Serialize(T value, byte[] destination, Session.SerializerSession session) { throw null; }\n\n        public int Serialize(T value, byte[] destination) { throw null; }\n\n        public void Serialize(T value, System.IO.Stream destination, Session.SerializerSession session, int sizeHint = 0) { }\n\n        public void Serialize(T value, System.IO.Stream destination, int sizeHint = 0) { }\n\n        public void Serialize(T value, ref System.Memory<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize(T value, ref System.Memory<byte> destination) { }\n\n        public void Serialize(T value, ref System.Span<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize(T value, ref System.Span<byte> destination) { }\n\n        public void Serialize<TBufferWriter>(T value, TBufferWriter destination, Session.SerializerSession session)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(T value, TBufferWriter destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(T value, ref Buffers.Writer<TBufferWriter> destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public byte[] SerializeToArray(T value) { throw null; }\n    }\n\n    public static partial class ServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddSerializer(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<ISerializerBuilder> configure = null) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class TypeMissingException : SerializerException\n    {\n    }\n\n    [System.Diagnostics.DebuggerDisplay(\"{GetDebuggerDisplay(),nq}\")]\n    public sealed partial class UnavailableExceptionFallbackException : System.Exception\n    {\n        public UnavailableExceptionFallbackException() { }\n\n        [System.Obsolete]\n        public UnavailableExceptionFallbackException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public UnavailableExceptionFallbackException(string message, System.Exception innerException) { }\n\n        public string ExceptionType { get { throw null; } }\n\n        public System.Collections.Generic.Dictionary<string, object> Properties { get { throw null; } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class UnexpectedLengthPrefixValueException : SerializerException\n    {\n        public UnexpectedLengthPrefixValueException(string typeName, uint expectedLength, uint actualLength) { }\n\n        public UnexpectedLengthPrefixValueException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class UnknownReferencedTypeException : SerializerException\n    {\n        public UnknownReferencedTypeException(uint reference) { }\n\n        [Id(0)]\n        public uint Reference { get { throw null; } set { } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class UnknownWellKnownTypeException : SerializerException\n    {\n        public UnknownWellKnownTypeException(uint id) { }\n\n        [Id(0)]\n        public uint Id { get { throw null; } set { } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class UnsupportedWireTypeException : SerializerException\n    {\n        public UnsupportedWireTypeException() { }\n\n        public UnsupportedWireTypeException(string message) { }\n    }\n\n    public sealed partial class ValueSerializer<T>\n        where T : struct\n    {\n        public ValueSerializer(Serializers.IValueSerializerProvider codecProvider, Session.SerializerSessionPool sessionPool) { }\n\n        public void Deserialize(System.ArraySegment<byte> source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(System.ArraySegment<byte> source, scoped ref T result) { }\n\n        public void Deserialize(System.Buffers.ReadOnlySequence<byte> source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(System.Buffers.ReadOnlySequence<byte> source, scoped ref T result) { }\n\n        public void Deserialize(byte[] source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(byte[] source, scoped ref T result) { }\n\n        public void Deserialize(System.IO.Stream source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(System.IO.Stream source, scoped ref T result) { }\n\n        public void Deserialize(System.ReadOnlyMemory<byte> source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(System.ReadOnlyMemory<byte> source, scoped ref T result) { }\n\n        public void Deserialize(System.ReadOnlySpan<byte> source, scoped ref T result, Session.SerializerSession session) { }\n\n        public void Deserialize(System.ReadOnlySpan<byte> source, scoped ref T result) { }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> source, scoped ref T result) { }\n\n        public void Serialize(scoped ref T value, System.ArraySegment<byte> destination) { }\n\n        public int Serialize(scoped ref T value, byte[] destination, Session.SerializerSession session) { throw null; }\n\n        public int Serialize(scoped ref T value, byte[] destination) { throw null; }\n\n        public void Serialize(scoped ref T value, System.IO.Stream destination, Session.SerializerSession session, int sizeHint = 0) { }\n\n        public void Serialize(scoped ref T value, System.IO.Stream destination, int sizeHint = 0) { }\n\n        public void Serialize(scoped ref T value, ref System.Memory<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize(scoped ref T value, ref System.Memory<byte> destination) { }\n\n        public void Serialize(scoped ref T value, ref System.Span<byte> destination, Session.SerializerSession session) { }\n\n        public void Serialize(scoped ref T value, ref System.Span<byte> destination) { }\n\n        public void Serialize<TBufferWriter>(scoped ref T value, TBufferWriter destination, Session.SerializerSession session)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(scoped ref T value, TBufferWriter destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Serialize<TBufferWriter>(scoped ref T value, ref Buffers.Writer<TBufferWriter> destination)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public byte[] SerializeToArray(scoped ref T value) { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.Activators\n{\n    public partial interface IActivator<T>\n    {\n        T Create();\n    }\n}\n\nnamespace Orleans.Serialization.Buffers\n{\n    public partial struct ArcBuffer : System.IDisposable\n    {\n        private int _dummyPrimitive;\n        public readonly ArcBufferPage First;\n        public readonly int Length;\n        public readonly int Offset;\n        public ArcBuffer(ArcBufferPage first, int token, int offset, int length) { }\n\n        public ArraySegmentEnumerator ArraySegments { get { throw null; } }\n\n        public MemoryEnumerator MemorySegments { get { throw null; } }\n\n        public SpanEnumerator SpanSegments { get { throw null; } }\n\n        public readonly System.Buffers.ReadOnlySequence<byte> AsReadOnlySequence() { throw null; }\n\n        public readonly void CopyTo(ArcBufferWriter output) { }\n\n        public readonly int CopyTo(System.Span<byte> output) { throw null; }\n\n        public readonly void CopyTo<TBufferWriter>(ref TBufferWriter output)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Dispose() { }\n\n        public readonly SpanEnumerator GetEnumerator() { throw null; }\n\n        public readonly void Pin() { }\n\n        public readonly ArcBuffer Slice(int offset, int length) { throw null; }\n\n        public readonly ArcBuffer Slice(int offset) { throw null; }\n\n        public readonly byte[] ToArray() { throw null; }\n\n        public void Unpin() { }\n\n        public readonly ArcBuffer UnsafeSlice(int offset, int length) { throw null; }\n\n        public partial struct ArraySegmentEnumerator : System.Collections.Generic.IEnumerable<System.ArraySegment<byte>>, System.Collections.IEnumerable, System.Collections.Generic.IEnumerator<System.ArraySegment<byte>>, System.Collections.IEnumerator, System.IDisposable\n        {\n            public ArraySegmentEnumerator(ArcBuffer slice) { }\n\n            public System.ArraySegment<byte> Current { get { throw null; } }\n\n            public bool IsCompleted { get { throw null; } }\n\n            object? System.Collections.IEnumerator.Current { get { throw null; } }\n\n            public readonly ArraySegmentEnumerator GetEnumerator() { throw null; }\n\n            public bool MoveNext() { throw null; }\n\n            readonly System.Collections.Generic.IEnumerator<System.ArraySegment<byte>> System.Collections.Generic.IEnumerable<System.ArraySegment<byte>>.GetEnumerator() { throw null; }\n\n            readonly System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }\n\n            void System.Collections.IEnumerator.Reset() { }\n\n            readonly void System.IDisposable.Dispose() { }\n        }\n\n        public partial struct MemoryEnumerator : System.Collections.Generic.IEnumerable<System.ReadOnlyMemory<byte>>, System.Collections.IEnumerable, System.Collections.Generic.IEnumerator<System.ReadOnlyMemory<byte>>, System.Collections.IEnumerator, System.IDisposable\n        {\n            public MemoryEnumerator(ArcBuffer slice) { }\n\n            public System.ReadOnlyMemory<byte> Current { get { throw null; } }\n\n            object? System.Collections.IEnumerator.Current { get { throw null; } }\n\n            public readonly MemoryEnumerator GetEnumerator() { throw null; }\n\n            public bool MoveNext() { throw null; }\n\n            readonly System.Collections.Generic.IEnumerator<System.ReadOnlyMemory<byte>> System.Collections.Generic.IEnumerable<System.ReadOnlyMemory<byte>>.GetEnumerator() { throw null; }\n\n            readonly System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }\n\n            void System.Collections.IEnumerator.Reset() { }\n\n            readonly void System.IDisposable.Dispose() { }\n        }\n\n        public readonly partial struct PageSegment\n        {\n            public readonly int Length;\n            public readonly int Offset;\n            public readonly ArcBufferPage Page;\n            public PageSegment(ArcBufferPage page, int offset, int length) { }\n\n            public System.ArraySegment<byte> ArraySegment { get { throw null; } }\n\n            public System.ReadOnlyMemory<byte> Memory { get { throw null; } }\n\n            public System.ReadOnlySpan<byte> Span { get { throw null; } }\n        }\n\n        public ref partial struct SpanEnumerator\n        {\n            private object _dummy;\n            private int _dummyPrimitive;\n            public SpanEnumerator(ArcBuffer slice) { }\n\n            public System.ReadOnlySpan<byte> Current { get { throw null; } }\n\n            public readonly SpanEnumerator GetEnumerator() { throw null; }\n\n            public bool MoveNext() { throw null; }\n        }\n    }\n\n    public sealed partial class ArcBufferPage\n    {\n        internal ArcBufferPage() { }\n\n        public byte[] Array { get { throw null; } }\n\n        public bool IsMinimumSize { get { throw null; } }\n\n        public bool IsValid { get { throw null; } }\n\n        public int Length { get { throw null; } }\n\n        public ArcBufferPage? Next { get { throw null; } protected set { } }\n\n        public System.ArraySegment<byte> ReadableArraySegment { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> ReadableMemory { get { throw null; } }\n\n        public System.ReadOnlySpan<byte> ReadableSpan { get { throw null; } }\n\n        public int Version { get { throw null; } }\n\n        public System.ArraySegment<byte> WritableArraySegment { get { throw null; } }\n\n        public System.Memory<byte> WritableMemory { get { throw null; } }\n\n        public System.Span<byte> WritableSpan { get { throw null; } }\n\n        public int WriteCapacity { get { throw null; } }\n\n        public void Advance(int bytes) { }\n\n        public System.ArraySegment<byte> AsArraySegment(int offset, int length) { throw null; }\n\n        public System.Memory<byte> AsMemory(int offset, int length) { throw null; }\n\n        public System.Memory<byte> AsMemory(int offset) { throw null; }\n\n        public System.Span<byte> AsSpan(int offset, int length) { throw null; }\n\n        public System.Span<byte> AsSpan(int offset) { throw null; }\n\n        public void CheckValidity(int token) { }\n\n        public void Pin(int token) { }\n\n        public void ResizeLargeSegment(int length) { }\n\n        public void SetNext(ArcBufferPage next, int token) { }\n\n        public void Unpin(int token) { }\n    }\n\n    public readonly partial struct ArcBufferReader\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public ArcBufferReader(ArcBufferWriter writer) { }\n\n        public int Length { get { throw null; } }\n\n        public readonly void Consume(System.Span<byte> output) { }\n\n        public readonly ArcBuffer ConsumeSlice(int count) { throw null; }\n\n        public readonly System.ReadOnlySpan<byte> Peek(scoped in System.Span<byte> destination) { throw null; }\n\n        public readonly ArcBuffer PeekSlice(int count) { throw null; }\n\n        public readonly void Skip(int count) { }\n    }\n\n    [Immutable]\n    public sealed partial class ArcBufferWriter : System.Buffers.IBufferWriter<byte>, System.IDisposable\n    {\n        public const int MinimumPageSize = 16384;\n        public int Length { get { throw null; } }\n\n        public void AdvanceReader(int count) { }\n\n        public void AdvanceWriter(int count) { }\n\n        public ArcBuffer ConsumeSlice(int count) { throw null; }\n\n        public void Dispose() { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n\n        public int Peek(System.Span<byte> output) { throw null; }\n\n        public System.ReadOnlySpan<byte> Peek(scoped in System.Span<byte> destination) { throw null; }\n\n        public ArcBuffer PeekSlice(int count) { throw null; }\n\n        public void ReplenishBuffers(System.Collections.Generic.List<System.ArraySegment<byte>> buffers) { }\n\n        public void Reset() { }\n\n        void System.Buffers.IBufferWriter<byte>.Advance(int count) { }\n\n        public void Write(System.Buffers.ReadOnlySequence<byte> input) { }\n\n        public void Write(System.ReadOnlySpan<byte> value) { }\n    }\n\n    public static partial class BufferWriterExtensions\n    {\n        public static Writer<TBufferWriter> CreateWriter<TBufferWriter>(this TBufferWriter buffer, Session.SerializerSession session)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { throw null; }\n    }\n\n    [Immutable]\n    public partial struct PooledBuffer : System.Buffers.IBufferWriter<byte>, System.IDisposable\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public int Length { get { throw null; } }\n\n        public MemoryEnumerator MemorySegments { get { throw null; } }\n\n        public void Advance(int bytes) { }\n\n        public System.Buffers.ReadOnlySequence<byte> AsReadOnlySequence() { throw null; }\n\n        public readonly void CopyTo(System.Span<byte> output) { }\n\n        public readonly void CopyTo<TBufferWriter>(ref TBufferWriter writer)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public readonly void CopyTo<TBufferWriter>(ref Writer<TBufferWriter> writer)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void Dispose() { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n\n        public void Reset() { }\n\n        public readonly BufferSlice Slice() { throw null; }\n\n        public readonly BufferSlice Slice(int offset, int length) { throw null; }\n\n        public readonly BufferSlice Slice(int offset) { throw null; }\n\n        public readonly byte[] ToArray() { throw null; }\n\n        public void Write(System.Buffers.ReadOnlySequence<byte> input) { }\n\n        public void Write(System.ReadOnlySpan<byte> value) { }\n\n        public readonly partial struct BufferSlice\n        {\n            private readonly object _dummy;\n            private readonly int _dummyPrimitive;\n            public BufferSlice(in PooledBuffer buffer, int offset, int length) { }\n\n            public PooledBuffer Buffer { get { throw null; } }\n\n            public int Length { get { throw null; } }\n\n            public MemoryEnumerator MemorySegments { get { throw null; } }\n\n            public int Offset { get { throw null; } }\n\n            public readonly void CopyTo(ref PooledBuffer output) { }\n\n            public readonly int CopyTo(System.Span<byte> output) { throw null; }\n\n            public readonly void CopyTo<TBufferWriter>(ref TBufferWriter output)\n                where TBufferWriter : struct, System.Buffers.IBufferWriter<byte> { }\n\n            public readonly SpanEnumerator GetEnumerator() { throw null; }\n\n            public readonly BufferSlice Slice(int offset, int length) { throw null; }\n\n            public readonly BufferSlice Slice(int offset) { throw null; }\n\n            public readonly byte[] ToArray() { throw null; }\n\n            public partial struct MemoryEnumerator\n            {\n                private object _dummy;\n                private int _dummyPrimitive;\n                public MemoryEnumerator(BufferSlice slice) { }\n\n                public System.ReadOnlyMemory<byte> Current { get { throw null; } }\n\n                public readonly MemoryEnumerator GetEnumerator() { throw null; }\n\n                public bool MoveNext() { throw null; }\n            }\n\n            public ref partial struct SpanEnumerator\n            {\n                private object _dummy;\n                private int _dummyPrimitive;\n                public SpanEnumerator(BufferSlice slice) { }\n\n                public System.ReadOnlySpan<byte> Current { get { throw null; } }\n\n                public readonly SpanEnumerator GetEnumerator() { throw null; }\n\n                public bool MoveNext() { throw null; }\n            }\n        }\n\n        public partial struct MemoryEnumerator\n        {\n            private object _dummy;\n            private int _dummyPrimitive;\n            public System.ReadOnlyMemory<byte> CurrentMemory;\n            public MemoryEnumerator(PooledBuffer buffer) { }\n\n            public System.ReadOnlyMemory<byte> Current { get { throw null; } }\n\n            public readonly MemoryEnumerator GetEnumerator() { throw null; }\n\n            public bool MoveNext() { throw null; }\n        }\n\n        public ref partial struct SpanEnumerator\n        {\n            private object _dummy;\n            private int _dummyPrimitive;\n            public SpanEnumerator(ref PooledBuffer buffer) { }\n\n            public System.ReadOnlySpan<byte> Current { get { throw null; } }\n\n            public readonly SpanEnumerator GetEnumerator() { throw null; }\n\n            public bool MoveNext() { throw null; }\n        }\n    }\n\n    public static partial class PooledBufferExtensions\n    {\n        public static PooledBuffer.SpanEnumerator GetEnumerator(this ref PooledBuffer buffer) { throw null; }\n    }\n\n    public static partial class Reader\n    {\n        public static Reader<Adaptors.BufferSliceReaderInput> Create(PooledBuffer input, Session.SerializerSession session) { throw null; }\n\n        public static Reader<Adaptors.BufferSliceReaderInput> Create(PooledBuffer.BufferSlice input, Session.SerializerSession session) { throw null; }\n\n        public static Reader<ReadOnlySequenceInput> Create(System.Buffers.ReadOnlySequence<byte> sequence, Session.SerializerSession session) { throw null; }\n\n        public static Reader<SpanReaderInput> Create(byte[] buffer, Session.SerializerSession session) { throw null; }\n\n        public static Reader<ReaderInput> Create(System.IO.Stream stream, Session.SerializerSession session) { throw null; }\n\n        public static Reader<SpanReaderInput> Create(System.ReadOnlyMemory<byte> buffer, Session.SerializerSession session) { throw null; }\n\n        public static Reader<SpanReaderInput> Create(System.ReadOnlySpan<byte> buffer, Session.SerializerSession session) { throw null; }\n    }\n\n    public abstract partial class ReaderInput\n    {\n        public abstract long Length { get; }\n        public abstract long Position { get; }\n\n        public abstract byte ReadByte();\n        public abstract void ReadBytes(byte[] destination, int offset, int length);\n        public abstract void ReadBytes(System.Span<byte> destination);\n        public abstract uint ReadUInt32();\n        public abstract ulong ReadUInt64();\n        public abstract void Seek(long position);\n        public abstract void Skip(long count);\n        public abstract bool TryReadBytes(int length, out System.ReadOnlySpan<byte> bytes);\n    }\n\n    public ref partial struct Reader<TInput>\n    {\n        private TInput _input;\n        private object _dummy;\n        private int _dummyPrimitive;\n        public long Length { get { throw null; } }\n\n        public long Position { get { throw null; } }\n\n        public Session.SerializerSession Session { get { throw null; } }\n\n        public void ForkFrom(long position, out Reader<TInput> forked) { throw null; }\n\n        public byte ReadByte() { throw null; }\n\n        public void ReadBytes(scoped System.Span<byte> destination) { }\n\n        public byte[] ReadBytes(uint count) { throw null; }\n\n        public void ReadBytes<TBufferWriter>(scoped ref TBufferWriter writer, int count)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public int ReadInt32() { throw null; }\n\n        public long ReadInt64() { throw null; }\n\n        public uint ReadUInt32() { throw null; }\n\n        public ulong ReadUInt64() { throw null; }\n\n        public uint ReadVarUInt32() { throw null; }\n\n        public ulong ReadVarUInt64() { throw null; }\n\n        public void ResumeFrom(long position) { }\n\n        public void Skip(long count) { }\n\n        public bool TryReadBytes(int length, out System.ReadOnlySpan<byte> bytes) { throw null; }\n    }\n\n    public partial struct ReadOnlySequenceInput\n    {\n        private int _dummyPrimitive;\n    }\n\n    public readonly partial struct SpanReaderInput\n    {\n    }\n\n    public static partial class VarIntReaderExtensions\n    {\n        public static short ReadInt16<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static int ReadInt32<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static long ReadInt64<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static sbyte ReadInt8<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static ushort ReadUInt16<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static uint ReadUInt32<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static ulong ReadUInt64<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static byte ReadUInt8<TInput>(this ref Reader<TInput> reader, WireProtocol.WireType wireType) { throw null; }\n\n        public static short ReadVarInt16<TInput>(this ref Reader<TInput> reader) { throw null; }\n\n        public static int ReadVarInt32<TInput>(this ref Reader<TInput> reader) { throw null; }\n\n        public static long ReadVarInt64<TInput>(this ref Reader<TInput> reader) { throw null; }\n\n        public static sbyte ReadVarInt8<TInput>(this ref Reader<TInput> reader) { throw null; }\n\n        public static ushort ReadVarUInt16<TInput>(this ref Reader<TInput> reader) { throw null; }\n\n        public static byte ReadVarUInt8<TInput>(this ref Reader<TInput> reader) { throw null; }\n    }\n\n    public static partial class Writer\n    {\n        public static Writer<Adaptors.SpanBufferWriter> Create(byte[] output, Session.SerializerSession session) { throw null; }\n\n        public static Writer<Adaptors.MemoryStreamBufferWriter> Create(System.IO.MemoryStream destination, Session.SerializerSession session) { throw null; }\n\n        public static Writer<Adaptors.ArrayStreamBufferWriter> Create(System.IO.Stream destination, Session.SerializerSession session, int sizeHint = 0) { throw null; }\n\n        public static Writer<Adaptors.MemoryBufferWriter> Create(System.Memory<byte> output, Session.SerializerSession session) { throw null; }\n\n        public static Writer<Adaptors.SpanBufferWriter> Create(System.Span<byte> output, Session.SerializerSession session) { throw null; }\n\n        public static Writer<TBufferWriter> Create<TBufferWriter>(TBufferWriter destination, Session.SerializerSession session)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { throw null; }\n\n        public static Writer<PooledBuffer> CreatePooled(Session.SerializerSession session) { throw null; }\n\n        public static Writer<Adaptors.PoolingStreamBufferWriter> CreatePooled(System.IO.Stream destination, Session.SerializerSession session, int sizeHint = 0) { throw null; }\n    }\n\n    public ref partial struct Writer<TBufferWriter>\n        where TBufferWriter : System.Buffers.IBufferWriter<byte>\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public TBufferWriter Output;\n        public int Position { get { throw null; } }\n\n        public Session.SerializerSession Session { get { throw null; } }\n\n        public System.Span<byte> WritableSpan { get { throw null; } }\n\n        public void AdvanceSpan(int length) { }\n\n        public void Allocate(int sizeHint) { }\n\n        public void Commit() { }\n\n        public void Dispose() { }\n\n        public void EnsureContiguous(int length) { }\n\n        public void Write(scoped System.ReadOnlySpan<byte> value) { }\n\n        public void WriteByte(byte value) { }\n\n        public void WriteEndBase() { }\n\n        public void WriteEndObject() { }\n\n        public void WriteFieldHeader(uint fieldId, System.Type expectedType, System.Type actualType, WireProtocol.WireType wireType) { }\n\n        public void WriteFieldHeaderExpected(uint fieldId, WireProtocol.WireType wireType) { }\n\n        public void WriteInt32(int value) { }\n\n        public void WriteInt64(long value) { }\n\n        public void WriteStartObject(uint fieldId, System.Type expectedType, System.Type actualType) { }\n\n        public void WriteUInt32(uint value) { }\n\n        public void WriteUInt64(ulong value) { }\n\n        public void WriteVarInt16(short value) { }\n\n        public void WriteVarInt32(int value) { }\n\n        public void WriteVarInt64(long value) { }\n\n        public void WriteVarInt8(sbyte value) { }\n\n        public void WriteVarUInt16(ushort value) { }\n\n        public void WriteVarUInt32(uint value) { }\n\n        public void WriteVarUInt64(ulong value) { }\n\n        public void WriteVarUInt8(byte value) { }\n    }\n}\n\nnamespace Orleans.Serialization.Buffers.Adaptors\n{\n    public partial struct ArrayStreamBufferWriter : System.Buffers.IBufferWriter<byte>\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public const int DefaultInitialBufferSize = 256;\n        public ArrayStreamBufferWriter(System.IO.Stream stream, int sizeHint = 0) { }\n\n        public void Advance(int count) { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n\n    public partial struct BufferSliceReaderInput\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public BufferSliceReaderInput(in PooledBuffer.BufferSlice slice) { }\n    }\n\n    public partial class BufferWriterBox<TBufferWriter> : System.Buffers.IBufferWriter<byte> where TBufferWriter : struct, System.Buffers.IBufferWriter<byte>\n    {\n        public BufferWriterBox(TBufferWriter bufferWriter) { }\n\n        public ref TBufferWriter Value { get { throw null; } }\n\n        public void Advance(int count) { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n\n    public partial struct MemoryBufferWriter : System.Buffers.IBufferWriter<byte>\n    {\n        private int _dummyPrimitive;\n        public int BytesWritten { get { throw null; } }\n\n        public void Advance(int count) { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n\n    public readonly partial struct MemoryStreamBufferWriter : System.Buffers.IBufferWriter<byte>\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public MemoryStreamBufferWriter(System.IO.MemoryStream stream) { }\n\n        public readonly void Advance(int count) { }\n\n        public readonly System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public readonly System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n\n    public sealed partial class PooledBufferStream : System.IO.Stream\n    {\n        public PooledBufferStream() { }\n\n        public PooledBufferStream(int minAllocationSize = 0) { }\n\n        public override bool CanRead { get { throw null; } }\n\n        public override bool CanSeek { get { throw null; } }\n\n        public override bool CanWrite { get { throw null; } }\n\n        public override long Length { get { throw null; } }\n\n        public override long Position { get { throw null; } set { } }\n\n        public void CopyTo<TBufferWriter>(ref Writer<TBufferWriter> writer)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public override void Flush() { }\n\n        public override int Read(byte[] buffer, int offset, int count) { throw null; }\n\n        public static PooledBufferStream Rent() { throw null; }\n\n        public System.Buffers.ReadOnlySequence<byte> RentReadOnlySequence() { throw null; }\n\n        public void Reset() { }\n\n        public static void Return(PooledBufferStream stream) { }\n\n        public void ReturnReadOnlySequence(in System.Buffers.ReadOnlySequence<byte> sequence) { }\n\n        public override long Seek(long offset, System.IO.SeekOrigin origin) { throw null; }\n\n        public override void SetLength(long value) { }\n\n        public byte[] ToArray() { throw null; }\n\n        public override void Write(byte[] buffer, int offset, int count) { }\n    }\n\n    public partial struct PoolingStreamBufferWriter : System.Buffers.IBufferWriter<byte>, System.IDisposable\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public void Advance(int count) { }\n\n        public readonly void Dispose() { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n\n    public partial struct SpanBufferWriter : System.Buffers.IBufferWriter<byte>\n    {\n        private int _dummyPrimitive;\n        public int BytesWritten { get { throw null; } }\n\n        public void Advance(int count) { }\n\n        public readonly System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public readonly System.Span<byte> GetSpan(int sizeHint = 0) { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.Cloning\n{\n    public sealed partial class CopyContext : System.IDisposable\n    {\n        public CopyContext(Serializers.CodecProvider codecProvider, System.Action<CopyContext> onDisposed) { }\n\n        public T? DeepCopy<T>(T? value) { throw null; }\n\n        public void Dispose() { }\n\n        public void RecordCopy(object original, object copy) { }\n\n        public void Reset() { }\n\n        public bool TryGetCopy<T>(object? original, out T? result)\n            where T : class { throw null; }\n    }\n\n    public sealed partial class CopyContextPool\n    {\n        public CopyContextPool(Serializers.CodecProvider codecProvider) { }\n\n        public CopyContext GetContext() { throw null; }\n    }\n\n    public partial interface IBaseCopier\n    {\n    }\n\n    public partial interface IBaseCopier<T> : IBaseCopier where T : class\n    {\n        void DeepCopy(T input, T output, CopyContext context);\n    }\n\n    public partial interface IDeepCopier\n    {\n        object? DeepCopy(object? input, CopyContext context);\n    }\n\n    public partial interface IDeepCopierProvider\n    {\n        IBaseCopier<T> GetBaseCopier<T>()\n            where T : class;\n        IDeepCopier GetDeepCopier(System.Type type);\n        IDeepCopier<T> GetDeepCopier<T>();\n        IDeepCopier? TryGetDeepCopier(System.Type type);\n        IDeepCopier<T>? TryGetDeepCopier<T>();\n    }\n\n    public partial interface IDeepCopier<T> : IDeepCopier\n    {\n        T DeepCopy(T input, CopyContext context);\n        object? IDeepCopier.DeepCopy(object? input, CopyContext context);\n    }\n\n    public partial interface IDerivedTypeCopier : IDeepCopier\n    {\n    }\n\n    public partial interface IGeneralizedCopier : IDeepCopier\n    {\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface IOptionalDeepCopier : IDeepCopier\n    {\n        bool IsShallowCopyable();\n    }\n\n    public partial interface ISpecializableCopier\n    {\n        IDeepCopier GetSpecializedCopier(System.Type type);\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial class ShallowCopier<T> : IOptionalDeepCopier, IDeepCopier, IDeepCopier<T>\n    {\n        public T DeepCopy(T input, CopyContext _) { throw null; }\n\n        public object? DeepCopy(object? input, CopyContext _) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.Codecs\n{\n    [RegisterSerializer]\n    public sealed partial class ArrayCodec<T> : IFieldCodec<T[]>, IFieldCodec\n    {\n        public ArrayCodec(IFieldCodec<T> fieldCodec) { }\n\n        public T[] ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, T[] value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ArrayCopier<T> : Cloning.IDeepCopier<T[]>, Cloning.IDeepCopier\n    {\n        public ArrayCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public T[] DeepCopy(T[] input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ArrayListCodec : GeneralizedReferenceTypeSurrogateCodec<System.Collections.ArrayList, ArrayListSurrogate>\n    {\n        public ArrayListCodec(Serializers.IValueSerializer<ArrayListSurrogate> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.ArrayList ConvertFromSurrogate(ref ArrayListSurrogate surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.ArrayList value, ref ArrayListSurrogate surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ArrayListCopier : Cloning.IDeepCopier<System.Collections.ArrayList>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.ArrayList>, Cloning.IBaseCopier\n    {\n        public System.Collections.ArrayList DeepCopy(System.Collections.ArrayList input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.ArrayList input, System.Collections.ArrayList output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct ArrayListSurrogate\n    {\n        [Id(0)]\n        public object[] Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ArraySegmentCodec<T> : IFieldCodec<System.ArraySegment<T>>, IFieldCodec\n    {\n        public ArraySegmentCodec(IFieldCodec<T> fieldCodec) { }\n\n        public System.ArraySegment<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ArraySegment<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ArraySegmentCopier<T> : Cloning.IDeepCopier<System.ArraySegment<T>>, Cloning.IDeepCopier\n    {\n        public ArraySegmentCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public System.ArraySegment<T> DeepCopy(System.ArraySegment<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ArraySegmentOfByteCopier : Cloning.IDeepCopier<System.ArraySegment<byte>>, Cloning.IDeepCopier\n    {\n        public static System.ArraySegment<byte> DeepCopy(System.ArraySegment<byte> input, Cloning.CopyContext copyContext) { throw null; }\n\n        System.ArraySegment<byte> Cloning.IDeepCopier<System.ArraySegment<byte>>.DeepCopy(System.ArraySegment<byte> input, Cloning.CopyContext _) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class BitArrayCodec : IFieldCodec<System.Collections.BitArray>, IFieldCodec\n    {\n        System.Collections.BitArray IFieldCodec<System.Collections.BitArray>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Collections.BitArray>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.BitArray value) { }\n\n        public static System.Collections.BitArray ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class BitArrayCopier : Cloning.IDeepCopier<System.Collections.BitArray>, Cloning.IDeepCopier\n    {\n        public static System.Collections.BitArray DeepCopy(System.Collections.BitArray input, Cloning.CopyContext context) { throw null; }\n\n        System.Collections.BitArray Cloning.IDeepCopier<System.Collections.BitArray>.DeepCopy(System.Collections.BitArray input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class BitVector32Codec : IFieldCodec<System.Collections.Specialized.BitVector32>, IFieldCodec\n    {\n        public System.Collections.Specialized.BitVector32 ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Specialized.BitVector32 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class BoolCodec : IFieldCodec<bool>, IFieldCodec\n    {\n        bool IFieldCodec<bool>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<bool>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, bool value) { }\n\n        public static bool ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, bool value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ByteArrayCodec : IFieldCodec<byte[]>, IFieldCodec\n    {\n        byte[] IFieldCodec<byte[]>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<byte[]>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, byte[] value) { }\n\n        public static byte[] ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, byte[] value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ByteArrayCopier : Cloning.IDeepCopier<byte[]>, Cloning.IDeepCopier\n    {\n        public static byte[] DeepCopy(byte[] input, Cloning.CopyContext context) { throw null; }\n\n        byte[] Cloning.IDeepCopier<byte[]>.DeepCopy(byte[] input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ByteCodec : IFieldCodec<byte>, IFieldCodec\n    {\n        byte IFieldCodec<byte>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<byte>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, byte value) { }\n\n        public static byte ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, byte value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, byte value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class CharCodec : IFieldCodec<char>, IFieldCodec\n    {\n        char IFieldCodec<char>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<char>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, char value) { }\n\n        public static char ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, char value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class CollectionCodec<T> : IFieldCodec<System.Collections.ObjectModel.Collection<T>>, IFieldCodec, Serializers.IBaseCodec<System.Collections.ObjectModel.Collection<T>>, Serializers.IBaseCodec\n    {\n        public CollectionCodec(IFieldCodec<T> fieldCodec) { }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, System.Collections.ObjectModel.Collection<T> value) { }\n\n        public System.Collections.ObjectModel.Collection<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Collections.ObjectModel.Collection<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.ObjectModel.Collection<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class CollectionCopier<T> : Cloning.IDeepCopier<System.Collections.ObjectModel.Collection<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.ObjectModel.Collection<T>>, Cloning.IBaseCopier\n    {\n        public CollectionCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.ObjectModel.Collection<T> DeepCopy(System.Collections.ObjectModel.Collection<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.ObjectModel.Collection<T> input, System.Collections.ObjectModel.Collection<T> output, Cloning.CopyContext context) { }\n    }\n\n    public partial class CommonCodecTypeFilter\n    {\n        public static bool IsAbstractOrFrameworkType(System.Type type) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class CompareInfoCodec : IFieldCodec<System.Globalization.CompareInfo>, IFieldCodec\n    {\n        public System.Globalization.CompareInfo ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Globalization.CompareInfo value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ConcurrentDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>, ConcurrentDictionarySurrogate<TKey, TValue>>\n    {\n        public ConcurrentDictionaryCodec(Serializers.IValueSerializer<ConcurrentDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> ConvertFromSurrogate(ref ConcurrentDictionarySurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> value, ref ConcurrentDictionarySurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ConcurrentDictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>>, Cloning.IBaseCopier\n    {\n        public ConcurrentDictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> DeepCopy(System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> input, System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct ConcurrentDictionarySurrogate<TKey, TValue>\n    {\n        [Id(0)]\n        public System.Collections.Generic.Dictionary<TKey, TValue> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ConcurrentQueueCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Concurrent.ConcurrentQueue<T>, ConcurrentQueueSurrogate<T>>\n    {\n        public ConcurrentQueueCodec(Serializers.IValueSerializer<ConcurrentQueueSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Concurrent.ConcurrentQueue<T> ConvertFromSurrogate(ref ConcurrentQueueSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Concurrent.ConcurrentQueue<T> value, ref ConcurrentQueueSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ConcurrentQueueCopier<T> : Cloning.IDeepCopier<System.Collections.Concurrent.ConcurrentQueue<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Concurrent.ConcurrentQueue<T>>, Cloning.IBaseCopier\n    {\n        public ConcurrentQueueCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.Concurrent.ConcurrentQueue<T> DeepCopy(System.Collections.Concurrent.ConcurrentQueue<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Concurrent.ConcurrentQueue<T> input, System.Collections.Concurrent.ConcurrentQueue<T> output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct ConcurrentQueueSurrogate<T>\n    {\n        [Id(0)]\n        public System.Collections.Generic.Queue<T> Values;\n    }\n\n    public static partial class ConsumeFieldExtension\n    {\n        public static void ConsumeUnknownField<TInput>(this ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { }\n\n        public static void ConsumeUnknownField<TInput>(this ref Buffers.Reader<TInput> reader, scoped ref WireProtocol.Field field) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class CultureInfoCodec : GeneralizedReferenceTypeSurrogateCodec<System.Globalization.CultureInfo, CultureInfoSurrogate>\n    {\n        public CultureInfoCodec(Serializers.IValueSerializer<CultureInfoSurrogate> surrogateSerializer) : base(default!) { }\n\n        public override System.Globalization.CultureInfo ConvertFromSurrogate(ref CultureInfoSurrogate surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Globalization.CultureInfo value, ref CultureInfoSurrogate surrogate) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct CultureInfoSurrogate\n    {\n        [Id(0)]\n        public string Name;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DateOnlyCodec : IFieldCodec<System.DateOnly>, IFieldCodec\n    {\n        System.DateOnly IFieldCodec<System.DateOnly>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.DateOnly>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.DateOnly value) { }\n\n        public static System.DateOnly ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.DateOnly value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DateTimeCodec : IFieldCodec<System.DateTime>, IFieldCodec\n    {\n        System.DateTime IFieldCodec<System.DateTime>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.DateTime>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.DateTime value) { }\n\n        public static System.DateTime ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.DateTime value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DateTimeOffsetCodec : IFieldCodec<System.DateTimeOffset>, IFieldCodec\n    {\n        System.DateTimeOffset IFieldCodec<System.DateTimeOffset>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.DateTimeOffset>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.DateTimeOffset value) { }\n\n        public static System.DateTimeOffset ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.DateTimeOffset value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DecimalCodec : IFieldCodec<decimal>, IFieldCodec\n    {\n        decimal IFieldCodec<decimal>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<decimal>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, decimal value) { }\n\n        public static decimal ReadDecimalRaw<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static decimal ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, decimal value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DictionaryBaseCodec<TKey, TValue> : Serializers.IBaseCodec<System.Collections.Generic.Dictionary<TKey, TValue>>, Serializers.IBaseCodec\n    {\n        public DictionaryBaseCodec(IFieldCodec<TKey> keyCodec, IFieldCodec<TValue> valueCodec, IFieldCodec<System.Collections.Generic.IEqualityComparer<TKey>> comparerCodec) { }\n\n        void Serializers.IBaseCodec<System.Collections.Generic.Dictionary<TKey, TValue>>.Deserialize<TInput>(ref Buffers.Reader<TInput> reader, System.Collections.Generic.Dictionary<TKey, TValue> value) { }\n\n        void Serializers.IBaseCodec<System.Collections.Generic.Dictionary<TKey, TValue>>.Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Collections.Generic.Dictionary<TKey, TValue> value) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DictionaryCodec<TKey, TValue> : IFieldCodec<System.Collections.Generic.Dictionary<TKey, TValue>>, IFieldCodec\n    {\n        public DictionaryCodec(IFieldCodec<TKey> keyCodec, IFieldCodec<TValue> valueCodec, IFieldCodec<System.Collections.Generic.IEqualityComparer<TKey>> comparerCodec) { }\n\n        public System.Collections.Generic.Dictionary<TKey, TValue> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.Dictionary<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class DictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Generic.Dictionary<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.Dictionary<TKey, TValue>>, Cloning.IBaseCopier\n    {\n        public DictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Generic.Dictionary<TKey, TValue> DeepCopy(System.Collections.Generic.Dictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.Dictionary<TKey, TValue> input, System.Collections.Generic.Dictionary<TKey, TValue> output, Cloning.CopyContext context) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class DoubleCodec : IFieldCodec<double>, IFieldCodec\n    {\n        double IFieldCodec<double>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<double>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, double value) { }\n\n        public static double ReadDoubleRaw<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static double ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, double value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public abstract partial class Enum32BaseCodec<T> : IFieldCodec<T>, IFieldCodec where T : unmanaged, System.Enum\n    {\n        public T ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, T value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public static partial class FieldHeaderCodec\n    {\n        public static void ReadFieldHeader<TInput>(this ref Buffers.Reader<TInput> reader, scoped ref WireProtocol.Field field) { }\n\n        public static WireProtocol.Field ReadFieldHeader<TInput>(this ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static (WireProtocol.Field Field, string Type) ReadFieldHeaderForAnalysis<TInput>(this ref Buffers.Reader<TInput> reader) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class FloatCodec : IFieldCodec<float>, IFieldCodec\n    {\n        float IFieldCodec<float>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<float>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, float value) { }\n\n        public static float ReadFloatRaw<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static float ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, float value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public abstract partial class GeneralizedReferenceTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField>, IFieldCodec, IDerivedTypeCodec where TField : class where TSurrogate : struct\n    {\n        protected GeneralizedReferenceTypeSurrogateCodec(Serializers.IValueSerializer<TSurrogate> surrogateSerializer) { }\n\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate);\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public abstract partial class GeneralizedValueTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField>, IFieldCodec where TField : struct where TSurrogate : struct\n    {\n        protected GeneralizedValueTypeSurrogateCodec(Serializers.IValueSerializer<TSurrogate> surrogateSerializer) { }\n\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate);\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class GuidCodec : IFieldCodec<System.Guid>, IFieldCodec\n    {\n        System.Guid IFieldCodec<System.Guid>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Guid>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Guid value) { }\n\n        public static System.Guid ReadRaw<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static System.Guid ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Guid value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteRaw<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Guid value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class HalfCodec : IFieldCodec<System.Half>, IFieldCodec\n    {\n        System.Half IFieldCodec<System.Half>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Half>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Half value) { }\n\n        public static System.Half ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Half value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class HashSetCodec<T> : IFieldCodec<System.Collections.Generic.HashSet<T>>, IFieldCodec, Serializers.IBaseCodec<System.Collections.Generic.HashSet<T>>, Serializers.IBaseCodec\n    {\n        public HashSetCodec(IFieldCodec<T> fieldCodec, IFieldCodec<System.Collections.Generic.IEqualityComparer<T>> comparerCodec) { }\n\n        void Serializers.IBaseCodec<System.Collections.Generic.HashSet<T>>.Deserialize<TInput>(ref Buffers.Reader<TInput> reader, System.Collections.Generic.HashSet<T> value) { }\n\n        public System.Collections.Generic.HashSet<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Collections.Generic.HashSet<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.HashSet<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class HashSetCopier<T> : Cloning.IDeepCopier<System.Collections.Generic.HashSet<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.HashSet<T>>, Cloning.IBaseCopier\n    {\n        public HashSetCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.Generic.HashSet<T> DeepCopy(System.Collections.Generic.HashSet<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.HashSet<T> input, System.Collections.Generic.HashSet<T> output, Cloning.CopyContext context) { }\n    }\n\n    public partial interface IDerivedTypeCodec : IFieldCodec\n    {\n    }\n\n    public partial interface IFieldCodec\n    {\n        object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field);\n        void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte>;\n    }\n\n    public partial interface IFieldCodec<T> : IFieldCodec\n    {\n        object IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field);\n        void IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value);\n        T ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field);\n        void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, T value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte>;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableArrayCodec<T> : GeneralizedValueTypeSurrogateCodec<System.Collections.Immutable.ImmutableArray<T>, ImmutableArraySurrogate<T>>\n    {\n        public ImmutableArrayCodec(Serializers.IValueSerializer<ImmutableArraySurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableArray<T> ConvertFromSurrogate(ref ImmutableArraySurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableArray<T> value, ref ImmutableArraySurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableArrayCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableArray<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableArrayCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableArray<T> DeepCopy(System.Collections.Immutable.ImmutableArray<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableArraySurrogate<T>\n    {\n        [Id(0)]\n        public T[] Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableDictionary<TKey, TValue>, ImmutableDictionarySurrogate<TKey, TValue>>\n    {\n        public ImmutableDictionaryCodec(Serializers.IValueSerializer<ImmutableDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableDictionary<TKey, TValue> ConvertFromSurrogate(ref ImmutableDictionarySurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableDictionary<TKey, TValue> value, ref ImmutableDictionarySurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableDictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableDictionary<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableDictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Immutable.ImmutableDictionary<TKey, TValue> DeepCopy(System.Collections.Immutable.ImmutableDictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableDictionarySurrogate<TKey, TValue>\n    {\n        [Id(0)]\n        public System.Collections.Generic.Dictionary<TKey, TValue> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableHashSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableHashSet<T>, ImmutableHashSetSurrogate<T>>\n    {\n        public ImmutableHashSetCodec(Serializers.IValueSerializer<ImmutableHashSetSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableHashSet<T> ConvertFromSurrogate(ref ImmutableHashSetSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableHashSet<T> value, ref ImmutableHashSetSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableHashSetCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableHashSet<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableHashSetCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableHashSet<T> DeepCopy(System.Collections.Immutable.ImmutableHashSet<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableHashSetSurrogate<T>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IEqualityComparer<T> KeyComparer;\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableListCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableList<T>, ImmutableListSurrogate<T>>\n    {\n        public ImmutableListCodec(Serializers.IValueSerializer<ImmutableListSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableList<T> ConvertFromSurrogate(ref ImmutableListSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableList<T> value, ref ImmutableListSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableListCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableList<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableListCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableList<T> DeepCopy(System.Collections.Immutable.ImmutableList<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableListSurrogate<T>\n    {\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableQueueCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableQueue<T>, ImmutableQueueSurrogate<T>>\n    {\n        public ImmutableQueueCodec(Serializers.IValueSerializer<ImmutableQueueSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableQueue<T> ConvertFromSurrogate(ref ImmutableQueueSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableQueue<T> value, ref ImmutableQueueSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableQueueCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableQueue<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableQueueCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableQueue<T> DeepCopy(System.Collections.Immutable.ImmutableQueue<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableQueueSurrogate<T>\n    {\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableSortedDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue>, ImmutableSortedDictionarySurrogate<TKey, TValue>>\n    {\n        public ImmutableSortedDictionaryCodec(Serializers.IValueSerializer<ImmutableSortedDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue> ConvertFromSurrogate(ref ImmutableSortedDictionarySurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue> value, ref ImmutableSortedDictionarySurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableSortedDictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableSortedDictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue> DeepCopy(System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableSortedDictionarySurrogate<TKey, TValue>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IComparer<TKey> KeyComparer;\n        [Id(2)]\n        public System.Collections.Generic.IEqualityComparer<TValue> ValueComparer;\n        [Id(0)]\n        public System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<TKey, TValue>> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableSortedSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableSortedSet<T>, ImmutableSortedSetSurrogate<T>>\n    {\n        public ImmutableSortedSetCodec(Serializers.IValueSerializer<ImmutableSortedSetSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableSortedSet<T> ConvertFromSurrogate(ref ImmutableSortedSetSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableSortedSet<T> value, ref ImmutableSortedSetSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableSortedSetCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableSortedSet<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableSortedSetCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableSortedSet<T> DeepCopy(System.Collections.Immutable.ImmutableSortedSet<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableSortedSetSurrogate<T>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IComparer<T> KeyComparer;\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ImmutableStackCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Immutable.ImmutableStack<T>, ImmutableStackSurrogate<T>>\n    {\n        public ImmutableStackCodec(Serializers.IValueSerializer<ImmutableStackSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Immutable.ImmutableStack<T> ConvertFromSurrogate(ref ImmutableStackSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Immutable.ImmutableStack<T> value, ref ImmutableStackSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ImmutableStackCopier<T> : Cloning.IDeepCopier<System.Collections.Immutable.ImmutableStack<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ImmutableStackCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Collections.Immutable.ImmutableStack<T> DeepCopy(System.Collections.Immutable.ImmutableStack<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ImmutableStackSurrogate<T>\n    {\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class Int128Codec : IFieldCodec<System.Int128>, IFieldCodec\n    {\n        System.Int128 IFieldCodec<System.Int128>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Int128>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Int128 value) { }\n\n        public static System.Int128 ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Int128 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class Int16Codec : IFieldCodec<short>, IFieldCodec\n    {\n        short IFieldCodec<short>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<short>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, short value) { }\n\n        public static short ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, short value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, short value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class Int32Codec : IFieldCodec<int>, IFieldCodec\n    {\n        int IFieldCodec<int>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<int>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, int value) { }\n\n        public static int ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, int value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, int value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class Int64Codec : IFieldCodec<long>, IFieldCodec\n    {\n        long IFieldCodec<long>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<long>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, long value) { }\n\n        public static long ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, long value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, long value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class IPAddressCodec : IFieldCodec<System.Net.IPAddress>, IFieldCodec, IDerivedTypeCodec\n    {\n        System.Net.IPAddress IFieldCodec<System.Net.IPAddress>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Net.IPAddress>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Net.IPAddress value) { }\n\n        public static System.Net.IPAddress ReadRaw<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public static System.Net.IPAddress ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Net.IPAddress value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteRaw<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Net.IPAddress value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class IPEndPointCodec : IFieldCodec<System.Net.IPEndPoint>, IFieldCodec, IDerivedTypeCodec\n    {\n        System.Net.IPEndPoint IFieldCodec<System.Net.IPEndPoint>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Net.IPEndPoint>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Net.IPEndPoint value) { }\n\n        public static System.Net.IPEndPoint ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Net.IPEndPoint value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial interface ISerializationCallbacks<T>\n    {\n        void OnCopied(T original, T result);\n        void OnCopying(T original, T result);\n        void OnDeserialized(T value);\n        void OnDeserializing(T value);\n        void OnSerialized(T value);\n        void OnSerializing(T value);\n    }\n\n    [RegisterSerializer]\n    public sealed partial class KeyValuePairCodec<TKey, TValue> : IFieldCodec<System.Collections.Generic.KeyValuePair<TKey, TValue>>, IFieldCodec\n    {\n        public KeyValuePairCodec(IFieldCodec<TKey> keyCodec, IFieldCodec<TValue> valueCodec) { }\n\n        public System.Collections.Generic.KeyValuePair<TKey, TValue> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.KeyValuePair<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class KeyValuePairCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Generic.KeyValuePair<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public KeyValuePairCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Generic.KeyValuePair<TKey, TValue> DeepCopy(System.Collections.Generic.KeyValuePair<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ListCodec<T> : IFieldCodec<System.Collections.Generic.List<T>>, IFieldCodec, Serializers.IBaseCodec<System.Collections.Generic.List<T>>, Serializers.IBaseCodec\n    {\n        public ListCodec(IFieldCodec<T> fieldCodec) { }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, System.Collections.Generic.List<T> value) { }\n\n        public System.Collections.Generic.List<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Collections.Generic.List<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.List<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ListCopier<T> : Cloning.IDeepCopier<System.Collections.Generic.List<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.List<T>>, Cloning.IBaseCopier\n    {\n        public ListCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.Generic.List<T> DeepCopy(System.Collections.Generic.List<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.List<T> input, System.Collections.Generic.List<T> output, Cloning.CopyContext context) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class MemoryCodec<T> : IFieldCodec<System.Memory<T>>, IFieldCodec\n    {\n        public MemoryCodec(IFieldCodec<T> fieldCodec) { }\n\n        public System.Memory<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Memory<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class MemoryCopier<T> : Cloning.IDeepCopier<System.Memory<T>>, Cloning.IDeepCopier\n    {\n        public MemoryCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public System.Memory<T> DeepCopy(System.Memory<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class MemoryOfByteCodec : IFieldCodec<System.Memory<byte>>, IFieldCodec\n    {\n        System.Memory<byte> IFieldCodec<System.Memory<byte>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Memory<byte>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Memory<byte> value) { }\n\n        public static System.Memory<byte> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Memory<byte> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class MemoryOfByteCopier : Cloning.IDeepCopier<System.Memory<byte>>, Cloning.IDeepCopier\n    {\n        public static System.Memory<byte> DeepCopy(System.Memory<byte> input, Cloning.CopyContext copyContext) { throw null; }\n\n        System.Memory<byte> Cloning.IDeepCopier<System.Memory<byte>>.DeepCopy(System.Memory<byte> input, Cloning.CopyContext _) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class NameValueCollectionCodec : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Specialized.NameValueCollection, NameValueCollectionSurrogate>\n    {\n        public NameValueCollectionCodec(Serializers.IValueSerializer<NameValueCollectionSurrogate> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Specialized.NameValueCollection ConvertFromSurrogate(ref NameValueCollectionSurrogate surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Specialized.NameValueCollection value, ref NameValueCollectionSurrogate surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class NameValueCollectionCopier : Cloning.IDeepCopier<System.Collections.Specialized.NameValueCollection>, Cloning.IDeepCopier\n    {\n        public System.Collections.Specialized.NameValueCollection DeepCopy(System.Collections.Specialized.NameValueCollection input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct NameValueCollectionSurrogate\n    {\n        [Id(0)]\n        public System.Collections.Generic.Dictionary<string, string> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class NullableCodec<T> : IFieldCodec<T?>, IFieldCodec where T : struct\n    {\n        public NullableCodec(IFieldCodec<T> fieldCodec) { }\n\n        public T? ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, T? value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class NullableCopier<T> : Cloning.IDeepCopier<T?>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier where T : struct\n    {\n        public NullableCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public T? DeepCopy(T? input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ObjectCodec : IFieldCodec<object>, IFieldCodec\n    {\n        object IFieldCodec<object>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<object>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        void IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        public static object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ObjectCopier : Cloning.IDeepCopier<object>, Cloning.IDeepCopier\n    {\n        public static object DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        object Cloning.IDeepCopier<object>.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class PooledBufferCodec : IFieldCodec<Buffers.PooledBuffer>, IFieldCodec\n    {\n        public Buffers.PooledBuffer ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Buffers.PooledBuffer value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class PooledBufferCopier : Cloning.IDeepCopier<Buffers.PooledBuffer>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public Buffers.PooledBuffer DeepCopy(Buffers.PooledBuffer input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class QueueCodec<T> : IFieldCodec<System.Collections.Generic.Queue<T>>, IFieldCodec\n    {\n        public QueueCodec(IFieldCodec<T> fieldCodec) { }\n\n        public System.Collections.Generic.Queue<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.Queue<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class QueueCopier<T> : Cloning.IDeepCopier<System.Collections.Generic.Queue<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.Queue<T>>, Cloning.IBaseCopier\n    {\n        public QueueCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.Generic.Queue<T> DeepCopy(System.Collections.Generic.Queue<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.Queue<T> input, System.Collections.Generic.Queue<T> output, Cloning.CopyContext context) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ReadOnlyCollectionCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.ObjectModel.ReadOnlyCollection<T>, ReadOnlyCollectionSurrogate<T>>\n    {\n        public ReadOnlyCollectionCodec(Serializers.IValueSerializer<ReadOnlyCollectionSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.ObjectModel.ReadOnlyCollection<T> ConvertFromSurrogate(ref ReadOnlyCollectionSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.ObjectModel.ReadOnlyCollection<T> value, ref ReadOnlyCollectionSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ReadOnlyCollectionCopier<T> : Cloning.IDeepCopier<System.Collections.ObjectModel.ReadOnlyCollection<T>>, Cloning.IDeepCopier\n    {\n        public ReadOnlyCollectionCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public System.Collections.ObjectModel.ReadOnlyCollection<T> DeepCopy(System.Collections.ObjectModel.ReadOnlyCollection<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ReadOnlyCollectionSurrogate<T>\n    {\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ReadOnlyDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue>, ReadOnlyDictionarySurrogate<TKey, TValue>>\n    {\n        public ReadOnlyDictionaryCodec(Serializers.IValueSerializer<ReadOnlyDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue> ConvertFromSurrogate(ref ReadOnlyDictionarySurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue> value, ref ReadOnlyDictionarySurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ReadOnlyDictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue>>, Cloning.IDeepCopier\n    {\n        public ReadOnlyDictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue> DeepCopy(System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct ReadOnlyDictionarySurrogate<TKey, TValue>\n    {\n        [Id(0)]\n        public System.Collections.Generic.Dictionary<TKey, TValue> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ReadOnlyMemoryCodec<T> : IFieldCodec<System.ReadOnlyMemory<T>>, IFieldCodec\n    {\n        public ReadOnlyMemoryCodec(IFieldCodec<T> fieldCodec) { }\n\n        public System.ReadOnlyMemory<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ReadOnlyMemory<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ReadOnlyMemoryCopier<T> : Cloning.IDeepCopier<System.ReadOnlyMemory<T>>, Cloning.IDeepCopier\n    {\n        public ReadOnlyMemoryCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public System.ReadOnlyMemory<T> DeepCopy(System.ReadOnlyMemory<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ReadOnlyMemoryOfByteCodec : IFieldCodec<System.ReadOnlyMemory<byte>>, IFieldCodec\n    {\n        System.ReadOnlyMemory<byte> IFieldCodec<System.ReadOnlyMemory<byte>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.ReadOnlyMemory<byte>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ReadOnlyMemory<byte> value) { }\n\n        public static byte[] ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.ReadOnlyMemory<byte> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ReadOnlyMemoryOfByteCopier : Cloning.IDeepCopier<System.ReadOnlyMemory<byte>>, Cloning.IDeepCopier\n    {\n        public static System.ReadOnlyMemory<byte> DeepCopy(System.ReadOnlyMemory<byte> input, Cloning.CopyContext copyContext) { throw null; }\n\n        System.ReadOnlyMemory<byte> Cloning.IDeepCopier<System.ReadOnlyMemory<byte>>.DeepCopy(System.ReadOnlyMemory<byte> input, Cloning.CopyContext _) { throw null; }\n    }\n\n    public static partial class ReferenceCodec\n    {\n        public static uint CreateRecordPlaceholder(Session.SerializerSession session) { throw null; }\n\n        public static void MarkValueField(Session.SerializerSession session) { }\n\n        public static object ReadReference<TInput>(ref Buffers.Reader<TInput> reader, System.Type fieldType) { throw null; }\n\n        public static T ReadReference<T, TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void RecordObject(Session.SerializerSession session, object value, uint referenceId) { }\n\n        public static void RecordObject(Session.SerializerSession session, object value) { }\n\n        public static bool TryWriteReferenceField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldId, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { throw null; }\n\n        public static bool TryWriteReferenceField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldId, System.Type expectedType, System.Type actualType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { throw null; }\n\n        public static void WriteNullReference<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldId)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public abstract partial class ReferenceTypeSurrogateCodec<TField, TSurrogate> : IFieldCodec<TField>, IFieldCodec where TSurrogate : struct\n    {\n        protected ReferenceTypeSurrogateCodec(Serializers.IValueSerializer<TSurrogate> surrogateSerializer) { }\n\n        public abstract TField ConvertFromSurrogate(ref TSurrogate surrogate);\n        public abstract void ConvertToSurrogate(TField value, ref TSurrogate surrogate);\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class SByteCodec : IFieldCodec<sbyte>, IFieldCodec\n    {\n        sbyte IFieldCodec<sbyte>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<sbyte>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, sbyte value) { }\n\n        public static sbyte ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, sbyte value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, sbyte value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial class SkipFieldCodec : IFieldCodec\n    {\n        public object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public static partial class SkipFieldExtension\n    {\n        public static void SkipField<TInput>(this ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class SortedDictionaryCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Generic.SortedDictionary<TKey, TValue>, SortedDictionarySurrogate<TKey, TValue>>\n    {\n        public SortedDictionaryCodec(Serializers.IValueSerializer<SortedDictionarySurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Generic.SortedDictionary<TKey, TValue> ConvertFromSurrogate(ref SortedDictionarySurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Generic.SortedDictionary<TKey, TValue> value, ref SortedDictionarySurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class SortedDictionaryCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Generic.SortedDictionary<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.SortedDictionary<TKey, TValue>>, Cloning.IBaseCopier\n    {\n        public SortedDictionaryCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Generic.SortedDictionary<TKey, TValue> DeepCopy(System.Collections.Generic.SortedDictionary<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.SortedDictionary<TKey, TValue> input, System.Collections.Generic.SortedDictionary<TKey, TValue> output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct SortedDictionarySurrogate<TKey, TValue>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IComparer<TKey> Comparer;\n        [Id(0)]\n        public System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<TKey, TValue>> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class SortedListCodec<TKey, TValue> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Generic.SortedList<TKey, TValue>, SortedListSurrogate<TKey, TValue>>\n    {\n        public SortedListCodec(Serializers.IValueSerializer<SortedListSurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Generic.SortedList<TKey, TValue> ConvertFromSurrogate(ref SortedListSurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Generic.SortedList<TKey, TValue> value, ref SortedListSurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class SortedListCopier<TKey, TValue> : Cloning.IDeepCopier<System.Collections.Generic.SortedList<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.SortedList<TKey, TValue>>, Cloning.IBaseCopier\n    {\n        public SortedListCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public System.Collections.Generic.SortedList<TKey, TValue> DeepCopy(System.Collections.Generic.SortedList<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.SortedList<TKey, TValue> input, System.Collections.Generic.SortedList<TKey, TValue> output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct SortedListSurrogate<TKey, TValue>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IComparer<TKey> Comparer;\n        [Id(0)]\n        public System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<TKey, TValue>> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class SortedSetCodec<T> : GeneralizedReferenceTypeSurrogateCodec<System.Collections.Generic.SortedSet<T>, SortedSetSurrogate<T>>\n    {\n        public SortedSetCodec(Serializers.IValueSerializer<SortedSetSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override System.Collections.Generic.SortedSet<T> ConvertFromSurrogate(ref SortedSetSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Collections.Generic.SortedSet<T> value, ref SortedSetSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class SortedSetCopier<T> : Cloning.IDeepCopier<System.Collections.Generic.SortedSet<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.SortedSet<T>>, Cloning.IBaseCopier\n    {\n        public SortedSetCopier(Cloning.IDeepCopier<T> elementCopier) { }\n\n        public System.Collections.Generic.SortedSet<T> DeepCopy(System.Collections.Generic.SortedSet<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.SortedSet<T> input, System.Collections.Generic.SortedSet<T> output, Cloning.CopyContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct SortedSetSurrogate<T>\n    {\n        [Id(1)]\n        public System.Collections.Generic.IComparer<T> Comparer;\n        [Id(0)]\n        public System.Collections.Generic.List<T> Values;\n    }\n\n    [RegisterSerializer]\n    public sealed partial class StackCodec<T> : IFieldCodec<System.Collections.Generic.Stack<T>>, IFieldCodec\n    {\n        public StackCodec(IFieldCodec<T> fieldCodec) { }\n\n        public System.Collections.Generic.Stack<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Collections.Generic.Stack<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class StackCopier<T> : Cloning.IDeepCopier<System.Collections.Generic.Stack<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<System.Collections.Generic.Stack<T>>, Cloning.IBaseCopier\n    {\n        public StackCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public System.Collections.Generic.Stack<T> DeepCopy(System.Collections.Generic.Stack<T> input, Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(System.Collections.Generic.Stack<T> input, System.Collections.Generic.Stack<T> output, Cloning.CopyContext context) { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class StringCodec : IFieldCodec<string>, IFieldCodec\n    {\n        string IFieldCodec<string>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<string>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, string value) { }\n\n        public static string ReadRaw<TInput>(ref Buffers.Reader<TInput> reader, uint numBytes) { throw null; }\n\n        public static string ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, string value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteRaw<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, string value, int numBytes)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TimeOnlyCodec : IFieldCodec<System.TimeOnly>, IFieldCodec\n    {\n        System.TimeOnly IFieldCodec<System.TimeOnly>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.TimeOnly>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.TimeOnly value) { }\n\n        public static System.TimeOnly ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.TimeOnly value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TimeSpanCodec : IFieldCodec<System.TimeSpan>, IFieldCodec\n    {\n        System.TimeSpan IFieldCodec<System.TimeSpan>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.TimeSpan>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.TimeSpan value) { }\n\n        public static System.TimeSpan ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.TimeSpan value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T> : IFieldCodec<System.Tuple<T>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T> valueCodec) { }\n\n        public System.Tuple<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2> : IFieldCodec<System.Tuple<T1, T2>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec) { }\n\n        public System.Tuple<T1, T2> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3> : IFieldCodec<System.Tuple<T1, T2, T3>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec) { }\n\n        public System.Tuple<T1, T2, T3> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3, T4> : IFieldCodec<System.Tuple<T1, T2, T3, T4>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec) { }\n\n        public System.Tuple<T1, T2, T3, T4> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3, T4> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3, T4, T5> : IFieldCodec<System.Tuple<T1, T2, T3, T4, T5>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3, T4, T5> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3, T4, T5, T6> : IFieldCodec<System.Tuple<T1, T2, T3, T4, T5, T6>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3, T4, T5, T6> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3, T4, T5, T6, T7> : IFieldCodec<System.Tuple<T1, T2, T3, T4, T5, T6, T7>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec, IFieldCodec<T7> item7Codec) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6, T7> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3, T4, T5, T6, T7> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TupleCodec<T1, T2, T3, T4, T5, T6, T7, T8> : IFieldCodec<System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8>>, IFieldCodec\n    {\n        public TupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec, IFieldCodec<T7> item7Codec, IFieldCodec<T8> item8Codec) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T> : Cloning.IDeepCopier<System.Tuple<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.Tuple<T> DeepCopy(System.Tuple<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2> : Cloning.IDeepCopier<System.Tuple<T1, T2>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2) { }\n\n        public System.Tuple<T1, T2> DeepCopy(System.Tuple<T1, T2> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3) { }\n\n        public System.Tuple<T1, T2, T3> DeepCopy(System.Tuple<T1, T2, T3> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3, T4> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3, T4>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4) { }\n\n        public System.Tuple<T1, T2, T3, T4> DeepCopy(System.Tuple<T1, T2, T3, T4> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3, T4, T5> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3, T4, T5>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5> DeepCopy(System.Tuple<T1, T2, T3, T4, T5> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3, T4, T5, T6> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3, T4, T5, T6>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6> DeepCopy(System.Tuple<T1, T2, T3, T4, T5, T6> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3, T4, T5, T6, T7> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3, T4, T5, T6, T7>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6, Cloning.IDeepCopier<T7> copier7) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6, T7> DeepCopy(System.Tuple<T1, T2, T3, T4, T5, T6, T7> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class TupleCopier<T1, T2, T3, T4, T5, T6, T7, T8> : Cloning.IDeepCopier<System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public TupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6, Cloning.IDeepCopier<T7> copier7, Cloning.IDeepCopier<T8> copier8) { }\n\n        public System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8> DeepCopy(System.Tuple<T1, T2, T3, T4, T5, T6, T7, T8> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class TypeSerializerCodec : IFieldCodec<System.Type>, IFieldCodec, IDerivedTypeCodec\n    {\n        System.Type IFieldCodec<System.Type>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Type>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Type value) { }\n\n        public static System.Type ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class UInt128Codec : IFieldCodec<System.UInt128>, IFieldCodec\n    {\n        System.UInt128 IFieldCodec<System.UInt128>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.UInt128>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.UInt128 value) { }\n\n        public static System.UInt128 ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.UInt128 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class UInt16Codec : IFieldCodec<ushort>, IFieldCodec\n    {\n        ushort IFieldCodec<ushort>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<ushort>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, ushort value) { }\n\n        public static ushort ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, ushort value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, ushort value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class UInt32Codec : IFieldCodec<uint>, IFieldCodec\n    {\n        uint IFieldCodec<uint>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<uint>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, uint value) { }\n\n        public static uint ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, uint value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, uint value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class UInt64Codec : IFieldCodec<ulong>, IFieldCodec\n    {\n        ulong IFieldCodec<ulong>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<ulong>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, ulong value) { }\n\n        public static ulong ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, ulong value, System.Type actualType)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, ulong value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public sealed partial class UnknownFieldMarker\n    {\n        public UnknownFieldMarker(WireProtocol.Field field, long position) { }\n\n        public WireProtocol.Field Field { get { throw null; } }\n\n        public long Position { get { throw null; } }\n\n        public override string ToString() { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class UriCodec : IFieldCodec<System.Uri>, IFieldCodec, IDerivedTypeCodec\n    {\n        System.Uri IFieldCodec<System.Uri>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void IFieldCodec<System.Uri>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.Uri value) { }\n\n        public static System.Uri ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public static void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Uri value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec : IFieldCodec<System.ValueTuple>, IFieldCodec\n    {\n        public System.ValueTuple ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ValueTuple value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T> : IFieldCodec<System.ValueTuple<T>>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T> valueCodec) { }\n\n        public System.ValueTuple<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ValueTuple<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2> : IFieldCodec<(T1, T2)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec) { }\n\n        public (T1, T2) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3> : IFieldCodec<(T1, T2, T3)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec) { }\n\n        public (T1, T2, T3) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2, T3) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3, T4> : IFieldCodec<(T1, T2, T3, T4)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec) { }\n\n        public (T1, T2, T3, T4) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2, T3, T4) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3, T4, T5> : IFieldCodec<(T1, T2, T3, T4, T5)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec) { }\n\n        public (T1, T2, T3, T4, T5) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2, T3, T4, T5) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3, T4, T5, T6> : IFieldCodec<(T1, T2, T3, T4, T5, T6)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec) { }\n\n        public (T1, T2, T3, T4, T5, T6) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2, T3, T4, T5, T6) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3, T4, T5, T6, T7> : IFieldCodec<(T1, T2, T3, T4, T5, T6, T7)>, IFieldCodec\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec, IFieldCodec<T7> item7Codec) { }\n\n        public (T1, T2, T3, T4, T5, T6, T7) ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, (T1, T2, T3, T4, T5, T6, T7) value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class ValueTupleCodec<T1, T2, T3, T4, T5, T6, T7, T8> : IFieldCodec<System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8>>, IFieldCodec where T8 : struct\n    {\n        public ValueTupleCodec(IFieldCodec<T1> item1Codec, IFieldCodec<T2> item2Codec, IFieldCodec<T3> item3Codec, IFieldCodec<T4> item4Codec, IFieldCodec<T5> item5Codec, IFieldCodec<T6> item6Codec, IFieldCodec<T7> item7Codec, IFieldCodec<T8> item8Codec) { }\n\n        public System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier : Cloning.IDeepCopier<System.ValueTuple>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public System.ValueTuple DeepCopy(System.ValueTuple input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T> : Cloning.IDeepCopier<System.ValueTuple<T>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public System.ValueTuple<T> DeepCopy(System.ValueTuple<T> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2> : Cloning.IDeepCopier<(T1, T2)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2) { }\n\n        public (T1, T2) DeepCopy((T1, T2) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3> : Cloning.IDeepCopier<(T1, T2, T3)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3) { }\n\n        public (T1, T2, T3) DeepCopy((T1, T2, T3) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3, T4> : Cloning.IDeepCopier<(T1, T2, T3, T4)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4) { }\n\n        public (T1, T2, T3, T4) DeepCopy((T1, T2, T3, T4) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3, T4, T5> : Cloning.IDeepCopier<(T1, T2, T3, T4, T5)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5) { }\n\n        public (T1, T2, T3, T4, T5) DeepCopy((T1, T2, T3, T4, T5) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3, T4, T5, T6> : Cloning.IDeepCopier<(T1, T2, T3, T4, T5, T6)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6) { }\n\n        public (T1, T2, T3, T4, T5, T6) DeepCopy((T1, T2, T3, T4, T5, T6) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3, T4, T5, T6, T7> : Cloning.IDeepCopier<(T1, T2, T3, T4, T5, T6, T7)>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6, Cloning.IDeepCopier<T7> copier7) { }\n\n        public (T1, T2, T3, T4, T5, T6, T7) DeepCopy((T1, T2, T3, T4, T5, T6, T7) input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ValueTupleCopier<T1, T2, T3, T4, T5, T6, T7, T8> : Cloning.IDeepCopier<System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8>>, Cloning.IDeepCopier, Cloning.IOptionalDeepCopier where T8 : struct\n    {\n        public ValueTupleCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6, Cloning.IDeepCopier<T7> copier7, Cloning.IDeepCopier<T8> copier8) { }\n\n        public System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> DeepCopy(System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, T8> input, Cloning.CopyContext context) { throw null; }\n\n        public bool IsShallowCopyable() { throw null; }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class VersionCodec : GeneralizedReferenceTypeSurrogateCodec<System.Version, VersionSurrogate>\n    {\n        public VersionCodec(Serializers.IValueSerializer<VersionSurrogate> surrogateSerializer) : base(default!) { }\n\n        public override System.Version ConvertFromSurrogate(ref VersionSurrogate surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(System.Version value, ref VersionSurrogate surrogate) { }\n    }\n\n    [GenerateSerializer]\n    public partial struct VersionSurrogate\n    {\n        [Id(2)]\n        public int Build;\n        [Id(0)]\n        public int Major;\n        [Id(1)]\n        public int Minor;\n        [Id(3)]\n        public int Revision;\n    }\n\n    [Alias(\"StringComparer\")]\n    public sealed partial class WellKnownStringComparerCodec : Serializers.IGeneralizedCodec, IFieldCodec\n    {\n        public bool IsSupportedType(System.Type type) { throw null; }\n\n        public object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace Orleans.Serialization.Configuration\n{\n    public partial interface ITypeManifestProvider : Microsoft.Extensions.Options.IConfigureOptions<TypeManifestOptions>\n    {\n    }\n\n    public sealed partial class TypeManifestOptions\n    {\n        public System.Collections.Generic.HashSet<System.Type> Activators { get { throw null; } }\n\n        public bool AllowAllTypes { get { throw null; } set { } }\n\n        public System.Collections.Generic.HashSet<string> AllowedTypes { get { throw null; } }\n\n        public TypeSystem.CompoundTypeAliasTree CompoundTypeAliases { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> Converters { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> Copiers { get { throw null; } }\n\n        public bool? EnableConfigurationAnalysis { get { throw null; } set { } }\n\n        public System.Collections.Generic.HashSet<System.Type> FieldCodecs { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> InterfaceImplementations { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> InterfaceProxies { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> Interfaces { get { throw null; } }\n\n        public System.Collections.Generic.HashSet<System.Type> Serializers { get { throw null; } }\n\n        public System.Collections.Generic.Dictionary<string, System.Type> WellKnownTypeAliases { get { throw null; } }\n\n        public System.Collections.Generic.Dictionary<uint, System.Type> WellKnownTypeIds { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed partial class TypeManifestProviderAttribute : System.Attribute\n    {\n        public TypeManifestProviderAttribute(System.Type providerType) { }\n\n        public System.Type ProviderType { get { throw null; } }\n    }\n\n    public abstract partial class TypeManifestProviderBase : ITypeManifestProvider, Microsoft.Extensions.Options.IConfigureOptions<TypeManifestOptions>\n    {\n        public virtual object Key { get { throw null; } }\n\n        protected abstract void ConfigureInner(TypeManifestOptions options);\n        void Microsoft.Extensions.Options.IConfigureOptions<TypeManifestOptions>.Configure(TypeManifestOptions options) { }\n    }\n}\n\nnamespace Orleans.Serialization.GeneratedCodeHelpers\n{\n    public static partial class OrleansGeneratedCodeHelper\n    {\n        public static void ConsumeEndBaseOrEndObject<TInput>(this ref Buffers.Reader<TInput> reader, scoped ref WireProtocol.Field field) { }\n\n        public static void ConsumeEndBaseOrEndObject<TInput>(this ref Buffers.Reader<TInput> reader) { }\n\n        public static TField DeserializeUnexpectedType<TInput, TField>(this ref Buffers.Reader<TInput> reader, scoped ref WireProtocol.Field field)\n            where TField : class { throw null; }\n\n        public static System.Reflection.MethodInfo GetMethodInfoOrDefault(System.Type interfaceType, string methodName, System.Type[] methodTypeParameters, System.Type[] parameterTypes) { throw null; }\n\n        public static Cloning.IDeepCopier<T> GetOptionalCopier<T>(Cloning.IDeepCopier<T> copier) { throw null; }\n\n        public static TService GetService<TService>(object caller, Serializers.ICodecProvider codecProvider) { throw null; }\n\n        public static object InvokableThrowArgumentOutOfRange(int index, int maxArgs) { throw null; }\n\n        public static void SerializeUnexpectedType<TBufferWriter>(this ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public static TService UnwrapService<TService>(object caller, TService service) { throw null; }\n\n        public abstract partial class ExceptionCopier<T, B> : Cloning.IDeepCopier<T>, Cloning.IDeepCopier, Cloning.IBaseCopier<T>, Cloning.IBaseCopier where T : B where B : System.Exception\n        {\n            protected ExceptionCopier(Serializers.ICodecProvider codecProvider) { }\n\n            public virtual void DeepCopy(T input, T output, Cloning.CopyContext context) { }\n\n            public T DeepCopy(T original, Cloning.CopyContext context) { throw null; }\n        }\n    }\n}\n\nnamespace Orleans.Serialization.Internal\n{\n    public static partial class ReferencedAssemblyProvider\n    {\n        public static void AddAssembly(System.Collections.Generic.HashSet<System.Reflection.Assembly> parts, System.Reflection.Assembly assembly) { }\n\n        public static void AddFromAssemblyLoadContext(System.Collections.Generic.HashSet<System.Reflection.Assembly> parts, System.Reflection.Assembly assembly = null) { }\n\n        public static void AddFromAssemblyLoadContext(System.Collections.Generic.HashSet<System.Reflection.Assembly> parts, System.Runtime.Loader.AssemblyLoadContext context) { }\n\n        public static void AddFromDependencyContext(System.Collections.Generic.HashSet<System.Reflection.Assembly> parts, System.Reflection.Assembly assembly = null) { }\n\n        public static System.Collections.Generic.IEnumerable<System.Reflection.Assembly> GetRelevantAssemblies() { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.Invocation\n{\n    [GenerateSerializer]\n    [Immutable]\n    [UseActivator]\n    [SuppressReferenceTracking]\n    public sealed partial class CompletedResponse : Response\n    {\n        public override System.Exception? Exception { get { throw null; } set { } }\n\n        public static CompletedResponse Instance { get { throw null; } }\n\n        public override object? Result { get { throw null; } set { } }\n\n        public override void Dispose() { }\n\n        public override T GetResult<T>() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class ExceptionResponse : Response\n    {\n        [Id(0)]\n        public override System.Exception? Exception { get { throw null; } set { } }\n\n        public override object? Result { get { throw null; } set { } }\n\n        public override void Dispose() { }\n\n        public override T GetResult<T>() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial interface IInvokable : System.IDisposable\n    {\n        string GetActivityName();\n        object? GetArgument(int index);\n        int GetArgumentCount();\n        System.Threading.CancellationToken GetCancellationToken();\n        System.TimeSpan? GetDefaultResponseTimeout();\n        string GetInterfaceName();\n        System.Type GetInterfaceType();\n        System.Reflection.MethodInfo GetMethod();\n        string GetMethodName();\n        object? GetTarget();\n        System.Threading.Tasks.ValueTask<Response> Invoke();\n        void SetArgument(int index, object value);\n        void SetTarget(ITargetHolder holder);\n        bool TryCancel();\n    }\n\n    public static partial class InvokablePool\n    {\n        public static T Get<T>()\n            where T : class, IInvokable, new() { throw null; }\n\n        public static void Return<T>(T obj)\n            where T : class, IInvokable, new() { }\n    }\n\n    public partial interface IResponseCompletionSource\n    {\n        void Complete();\n        void Complete(Response value);\n    }\n\n    public partial interface ITargetHolder\n    {\n        TComponent? GetComponent<TComponent>()\n            where TComponent : class;\n        TTarget? GetTarget<TTarget>()\n            where TTarget : class;\n    }\n\n    [SerializerTransparent]\n    public abstract partial class Response : System.IDisposable\n    {\n        public static Response Completed { get { throw null; } }\n\n        public abstract System.Exception? Exception { get; set; }\n        public abstract object? Result { get; set; }\n\n        public abstract void Dispose();\n        public static Response FromException(System.Exception exception) { throw null; }\n\n        public static Response FromResult<TResult>(TResult value) { throw null; }\n\n        public abstract T GetResult<T>();\n        public virtual System.Type? GetSimpleResultType() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public abstract partial class ResponseCodec\n    {\n        public abstract object ReadRaw<TInput>(ref Buffers.Reader<TInput> reader, scoped ref WireProtocol.Field field);\n        public abstract void WriteRaw<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte>;\n    }\n\n    public sealed partial class ResponseCompletionSource : IResponseCompletionSource, System.Threading.Tasks.Sources.IValueTaskSource<Response>, System.Threading.Tasks.Sources.IValueTaskSource\n    {\n        public System.Threading.Tasks.ValueTask<Response> AsValueTask() { throw null; }\n\n        public System.Threading.Tasks.ValueTask AsVoidValueTask() { throw null; }\n\n        public void Complete() { }\n\n        public void Complete(Response value) { }\n\n        public Response GetResult(short token) { throw null; }\n\n        public System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token) { throw null; }\n\n        public void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags) { }\n\n        public void Reset() { }\n\n        public void SetException(System.Exception exception) { }\n\n        public void SetResult(Response result) { }\n\n        void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token) { }\n    }\n\n    public static partial class ResponseCompletionSourcePool\n    {\n        public static ResponseCompletionSource Get() { throw null; }\n\n        public static ResponseCompletionSource<T> Get<T>() { throw null; }\n\n        public static void Return(ResponseCompletionSource obj) { }\n\n        public static void Return<T>(ResponseCompletionSource<T> obj) { }\n    }\n\n    public sealed partial class ResponseCompletionSource<TResult> : IResponseCompletionSource, System.Threading.Tasks.Sources.IValueTaskSource<TResult>, System.Threading.Tasks.Sources.IValueTaskSource\n    {\n        public System.Threading.Tasks.ValueTask<TResult> AsValueTask() { throw null; }\n\n        public System.Threading.Tasks.ValueTask AsVoidValueTask() { throw null; }\n\n        public void Complete() { }\n\n        public void Complete(Response value) { }\n\n        public void Complete(Response<TResult> value) { }\n\n        public TResult GetResult(short token) { throw null; }\n\n        public System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token) { throw null; }\n\n        public void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags) { }\n\n        public void Reset() { }\n\n        public void SetException(System.Exception exception) { }\n\n        public void SetResult(TResult result) { }\n\n        void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token) { }\n    }\n\n    public static partial class ResponseExtensions\n    {\n        public static void ThrowIfExceptionResponse(this Response response) { }\n    }\n\n    public static partial class ResponsePool\n    {\n        public static Response<T> Get<T>() { throw null; }\n\n        public static void Return<T>(Response<T> obj) { }\n    }\n\n    [UseActivator]\n    [SuppressReferenceTracking]\n    public sealed partial class Response<TResult> : Response\n    {\n        public override System.Exception? Exception { get { throw null; } set { } }\n\n        public override object? Result { get { throw null; } set { } }\n\n        public TResult? TypedResult { get { throw null; } set { } }\n\n        public override void Dispose() { }\n\n        public override T GetResult<T>() { throw null; }\n\n        public override System.Type GetSimpleResultType() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.Serializers\n{\n    public partial class AbstractTypeSerializer : Codecs.IFieldCodec\n    {\n        protected internal AbstractTypeSerializer(System.Type fieldType) { }\n\n        public object ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial class AbstractTypeSerializer<TField> : AbstractTypeSerializer, Codecs.IFieldCodec<TField>, Codecs.IFieldCodec, IBaseCodec<TField>, IBaseCodec where TField : class\n    {\n        protected AbstractTypeSerializer() : base(default!) { }\n\n        public virtual void Deserialize<TReaderInput>(ref Buffers.Reader<TReaderInput> reader, TField instance) { }\n\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public virtual void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, TField instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public sealed partial class CodecProvider : ICodecProvider, IFieldCodecProvider, IBaseCodecProvider, IValueSerializerProvider, IActivatorProvider, Cloning.IDeepCopierProvider\n    {\n        public CodecProvider(System.IServiceProvider serviceProvider, Microsoft.Extensions.Options.IOptions<Configuration.TypeManifestOptions> codecConfiguration) { }\n\n        public System.IServiceProvider Services { get { throw null; } }\n\n        public Activators.IActivator<T> GetActivator<T>() { throw null; }\n\n        public IBaseCodec<TField> GetBaseCodec<TField>()\n            where TField : class { throw null; }\n\n        public Cloning.IBaseCopier<TField> GetBaseCopier<TField>()\n            where TField : class { throw null; }\n\n        public Codecs.IFieldCodec GetCodec(System.Type fieldType) { throw null; }\n\n        public Codecs.IFieldCodec<TField> GetCodec<TField>() { throw null; }\n\n        public Cloning.IDeepCopier GetDeepCopier(System.Type fieldType) { throw null; }\n\n        public Cloning.IDeepCopier<T> GetDeepCopier<T>() { throw null; }\n\n        public IValueSerializer<TField> GetValueSerializer<TField>()\n            where TField : struct { throw null; }\n\n        public Codecs.IFieldCodec TryGetCodec(System.Type fieldType) { throw null; }\n\n        public Codecs.IFieldCodec<TField> TryGetCodec<TField>() { throw null; }\n\n        public Cloning.IDeepCopier TryGetDeepCopier(System.Type fieldType) { throw null; }\n\n        public Cloning.IDeepCopier<T> TryGetDeepCopier<T>() { throw null; }\n    }\n\n    public sealed partial class ConcreteTypeSerializer<TField, TBaseCodec> : Codecs.IFieldCodec<TField>, Codecs.IFieldCodec where TField : class where TBaseCodec : IBaseCodec<TField>\n    {\n        public ConcreteTypeSerializer(Activators.IActivator<TField> activator, TBaseCodec serializer) { }\n\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public TField ReadValueSealed<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public sealed partial class DelegateCodecSelector : ICodecSelector\n    {\n        public string CodecName { get { throw null; } init { } }\n\n        public System.Func<System.Type, bool> IsSupportedTypeDelegate { get { throw null; } init { } }\n\n        public bool IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public sealed partial class DelegateCopierSelector : ICopierSelector\n    {\n        public string CopierName { get { throw null; } init { } }\n\n        public System.Func<System.Type, bool> IsSupportedTypeDelegate { get { throw null; } init { } }\n\n        public bool IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public partial interface IActivatorProvider\n    {\n        Activators.IActivator<T> GetActivator<T>();\n    }\n\n    public partial interface IBaseCodec\n    {\n    }\n\n    public partial interface IBaseCodecProvider\n    {\n        IBaseCodec<TField> GetBaseCodec<TField>()\n            where TField : class;\n    }\n\n    public partial interface IBaseCodec<in T> : IBaseCodec where T : class\n    {\n        void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, T value);\n        void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, T value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte>;\n    }\n\n    public partial interface ICodecProvider : IFieldCodecProvider, IBaseCodecProvider, IValueSerializerProvider, IActivatorProvider, Cloning.IDeepCopierProvider\n    {\n        System.IServiceProvider Services { get; }\n    }\n\n    public partial interface ICodecSelector\n    {\n        string CodecName { get; }\n\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface ICopierSelector\n    {\n        string CopierName { get; }\n\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface IFieldCodecProvider\n    {\n        Codecs.IFieldCodec GetCodec(System.Type fieldType);\n        Codecs.IFieldCodec<TField> GetCodec<TField>();\n        Codecs.IFieldCodec TryGetCodec(System.Type fieldType);\n        Codecs.IFieldCodec<TField> TryGetCodec<TField>();\n    }\n\n    public partial interface IGeneralizedBaseCodec : IBaseCodec<object>, IBaseCodec\n    {\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface IGeneralizedCodec : Codecs.IFieldCodec\n    {\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface ISpecializableBaseCodec\n    {\n        IBaseCodec GetSpecializedCodec(System.Type type);\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface ISpecializableCodec\n    {\n        Codecs.IFieldCodec GetSpecializedCodec(System.Type type);\n        bool IsSupportedType(System.Type type);\n    }\n\n    public partial interface IValueSerializer\n    {\n    }\n\n    public partial interface IValueSerializerProvider\n    {\n        IValueSerializer<TField> GetValueSerializer<TField>()\n            where TField : struct;\n    }\n\n    public partial interface IValueSerializer<T> : IValueSerializer where T : struct\n    {\n        void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, scoped ref T value);\n        void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, scoped ref T value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte>;\n    }\n\n    public sealed partial class SurrogateCodec<TField, TSurrogate, TConverter> : Codecs.IFieldCodec<TField>, Codecs.IFieldCodec, Cloning.IDeepCopier<TField>, Cloning.IDeepCopier, IBaseCodec<TField>, IBaseCodec, Cloning.IBaseCopier<TField>, Cloning.IBaseCopier where TField : class where TSurrogate : struct where TConverter : IConverter<TField, TSurrogate>\n    {\n        public SurrogateCodec(IValueSerializer<TSurrogate> surrogateSerializer, Cloning.IDeepCopier<TSurrogate> surrogateCopier, TConverter converter) { }\n\n        public void DeepCopy(TField input, TField output, Cloning.CopyContext context) { }\n\n        public TField DeepCopy(TField input, Cloning.CopyContext context) { throw null; }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, TField value) { }\n\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public sealed partial class ValueSerializer<TField, TValueSerializer> : Codecs.IFieldCodec<TField>, Codecs.IFieldCodec where TField : struct where TValueSerializer : IValueSerializer<TField>\n    {\n        public ValueSerializer(TValueSerializer serializer) { }\n\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public sealed partial class ValueTypeSurrogateCodec<TField, TSurrogate, TConverter> : Codecs.IFieldCodec<TField>, Codecs.IFieldCodec, Cloning.IDeepCopier<TField>, Cloning.IDeepCopier, IValueSerializer<TField>, IValueSerializer where TField : struct where TSurrogate : struct where TConverter : IConverter<TField, TSurrogate>\n    {\n        public ValueTypeSurrogateCodec(IValueSerializer<TSurrogate> surrogateSerializer, Cloning.IDeepCopier<TSurrogate> surrogateCopier, TConverter converter) { }\n\n        public TField DeepCopy(TField input, Cloning.CopyContext context) { throw null; }\n\n        public void Deserialize<TInput>(ref Buffers.Reader<TInput> reader, scoped ref TField value) { }\n\n        public TField ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, scoped ref TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, TField value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace Orleans.Serialization.Session\n{\n    public sealed partial class ReferencedObjectCollection\n    {\n        public uint CurrentReferenceId { get { throw null; } set { } }\n\n        public System.Collections.Generic.Dictionary<object, uint> CopyIdTable() { throw null; }\n\n        public System.Collections.Generic.Dictionary<uint, object> CopyReferenceTable() { throw null; }\n\n        public bool GetOrAddReference(object value, out uint reference) { throw null; }\n\n        public int GetReferenceIndex(object value) { throw null; }\n\n        public void MarkValueField() { }\n\n        public void RecordReferenceField(object value, uint referenceId) { }\n\n        public void RecordReferenceField(object value) { }\n\n        public void Reset() { }\n\n        public object TryGetReferencedObject(uint reference) { throw null; }\n    }\n\n    public sealed partial class ReferencedTypeCollection\n    {\n        public uint GetOrAddTypeReference(System.Type type) { throw null; }\n\n        public System.Type GetReferencedType(uint reference) { throw null; }\n\n        public void RecordReferencedType(System.Type type) { }\n\n        public void Reset() { }\n\n        public bool TryGetReferencedType(uint reference, out System.Type type) { throw null; }\n\n        public bool TryGetTypeReference(System.Type type, out uint reference) { throw null; }\n    }\n\n    public sealed partial class SerializerSession : System.IDisposable\n    {\n        public SerializerSession(TypeSystem.TypeCodec typeCodec, WellKnownTypeCollection wellKnownTypes, Serializers.CodecProvider codecProvider) { }\n\n        public Serializers.CodecProvider CodecProvider { get { throw null; } }\n\n        public ReferencedObjectCollection ReferencedObjects { get { throw null; } }\n\n        public ReferencedTypeCollection ReferencedTypes { get { throw null; } }\n\n        public TypeSystem.TypeCodec TypeCodec { get { throw null; } }\n\n        public WellKnownTypeCollection WellKnownTypes { get { throw null; } }\n\n        public void Dispose() { }\n\n        public void PartialReset() { }\n\n        public void Reset() { }\n    }\n\n    public sealed partial class SerializerSessionPool\n    {\n        public SerializerSessionPool(TypeSystem.TypeCodec typeCodec, WellKnownTypeCollection wellKnownTypes, Serializers.CodecProvider codecProvider) { }\n\n        public Serializers.CodecProvider CodecProvider { get { throw null; } }\n\n        public SerializerSession GetSession() { throw null; }\n    }\n\n    public sealed partial class WellKnownTypeCollection\n    {\n        public WellKnownTypeCollection(Microsoft.Extensions.Options.IOptions<Configuration.TypeManifestOptions> config) { }\n\n        public System.Type GetWellKnownType(uint typeId) { throw null; }\n\n        public bool TryGetWellKnownType(uint typeId, out System.Type type) { throw null; }\n\n        public bool TryGetWellKnownTypeId(System.Type type, out uint typeId) { throw null; }\n    }\n}\n\nnamespace Orleans.Serialization.TypeSystem\n{\n    public partial class ArrayTypeSpec : TypeSpec\n    {\n        public ArrayTypeSpec(TypeSpec elementType, int dimensions) { }\n\n        public int Dimensions { get { throw null; } }\n\n        public TypeSpec ElementType { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class AssemblyQualifiedTypeSpec : TypeSpec\n    {\n        public AssemblyQualifiedTypeSpec(TypeSpec type, string? assembly) { }\n\n        public string? Assembly { get { throw null; } }\n\n        public TypeSpec Type { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public sealed partial class CachedTypeResolver : TypeResolver\n    {\n        public static string GetName(System.Reflection.Assembly assembly) { throw null; }\n\n        public override System.Type ResolveType(string name) { throw null; }\n\n        public override bool TryResolveType(string name, out System.Type type) { throw null; }\n    }\n\n    public partial class CompoundTypeAliasTree\n    {\n        internal CompoundTypeAliasTree() { }\n\n        public object? Key { get { throw null; } }\n\n        public System.Type? Value { get { throw null; } }\n\n        public CompoundTypeAliasTree Add(string key, System.Type value) { throw null; }\n\n        public CompoundTypeAliasTree Add(string key) { throw null; }\n\n        public CompoundTypeAliasTree Add(System.Type key, System.Type value) { throw null; }\n\n        public CompoundTypeAliasTree Add(System.Type key) { throw null; }\n\n        public static CompoundTypeAliasTree Create() { throw null; }\n    }\n\n    public partial class ConstructedGenericTypeSpec : TypeSpec\n    {\n        public ConstructedGenericTypeSpec(TypeSpec unconstructedType, int arity, TypeSpec[] arguments) { }\n\n        public TypeSpec[] Arguments { get { throw null; } }\n\n        public TypeSpec UnconstructedType { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public sealed partial class DefaultTypeFilter : ITypeNameFilter\n    {\n        public bool? IsTypeNameAllowed(string typeName, string assemblyName) { throw null; }\n    }\n\n    public partial class LiteralTypeSpec : TypeSpec\n    {\n        public LiteralTypeSpec(string value) { }\n\n        public string Value { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class NamedTypeSpec : TypeSpec\n    {\n        public NamedTypeSpec(NamedTypeSpec containingType, string name, int arity) { }\n\n        public int Arity { get { throw null; } }\n\n        public NamedTypeSpec? ContainingType { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public string GetNamespaceQualifiedName() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class PointerTypeSpec : TypeSpec\n    {\n        public PointerTypeSpec(TypeSpec elementType) { }\n\n        public TypeSpec ElementType { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public readonly partial struct QualifiedType\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public QualifiedType(string? assembly, string type) { }\n\n        public string? Assembly { get { throw null; } }\n\n        public static QualifiedTypeEqualityComparer EqualityComparer { get { throw null; } }\n\n        public string Type { get { throw null; } }\n\n        public readonly void Deconstruct(out string? assembly, out string type) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public static bool operator ==(QualifiedType left, QualifiedType right) { throw null; }\n\n        public static implicit operator QualifiedType((string Assembly, string Type) args) { throw null; }\n\n        public static bool operator !=(QualifiedType left, QualifiedType right) { throw null; }\n\n        public sealed partial class QualifiedTypeEqualityComparer : System.Collections.Generic.IEqualityComparer<QualifiedType>\n        {\n            public bool Equals(QualifiedType x, QualifiedType y) { throw null; }\n\n            public int GetHashCode(QualifiedType obj) { throw null; }\n        }\n    }\n\n    public partial class ReferenceTypeSpec : TypeSpec\n    {\n        public ReferenceTypeSpec(TypeSpec elementType) { }\n\n        public TypeSpec ElementType { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public static partial class RuntimeTypeNameFormatter\n    {\n        public static string Format(System.Type type) { throw null; }\n    }\n\n    public static partial class RuntimeTypeNameParser\n    {\n        public static TypeSpec Parse(System.ReadOnlySpan<char> input) { throw null; }\n\n        public static TypeSpec Parse(string input) { throw null; }\n    }\n\n    public partial class TupleTypeSpec : TypeSpec\n    {\n        public TupleTypeSpec(TypeSpec[] elements, int arity) { }\n\n        public int Arity { get { throw null; } }\n\n        public TypeSpec[] Elements { get { throw null; } }\n\n        public override string Format() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public sealed partial class TypeCodec\n    {\n        public TypeCodec(TypeConverter typeConverter) { }\n\n        public System.Type ReadLengthPrefixed<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public System.Type TryRead<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n\n        public bool TryReadForAnalysis<TInput>(ref Buffers.Reader<TInput> reader, out System.Type type, out string typeString) { throw null; }\n\n        public void WriteEncodedType<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Type type)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteLengthPrefixed<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, System.Type type)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    public partial class TypeConverter\n    {\n        public TypeConverter(System.Collections.Generic.IEnumerable<ITypeConverter> formatters, System.Collections.Generic.IEnumerable<ITypeNameFilter> typeNameFilters, System.Collections.Generic.IEnumerable<ITypeFilter> typeFilters, Microsoft.Extensions.Options.IOptions<Configuration.TypeManifestOptions> options, TypeResolver typeResolver) { }\n\n        public string Format(System.Type type, bool allowAllTypes = false) { throw null; }\n\n        public string Format(System.Type type, System.Func<TypeSpec, TypeSpec> rewriter, bool allowAllTypes = false) { throw null; }\n\n        public System.Type Parse(string formatted) { throw null; }\n\n        public bool TryParse(string formatted, out System.Type result) { throw null; }\n    }\n\n    public abstract partial class TypeResolver\n    {\n        public abstract System.Type ResolveType(string name);\n        public abstract bool TryResolveType(string name, out System.Type type);\n    }\n\n    public abstract partial class TypeSpec\n    {\n        public abstract string Format();\n    }\n}\n\nnamespace Orleans.Serialization.Utilities\n{\n    public static partial class BitStreamFormatter\n    {\n        public static string Format(Buffers.PooledBuffer.BufferSlice slice, Session.SerializerSession session) { throw null; }\n\n        public static string Format(System.Buffers.ReadOnlySequence<byte> input, Session.SerializerSession session) { throw null; }\n\n        public static string Format(byte[] array, Session.SerializerSession session) { throw null; }\n\n        public static string Format(System.IO.Stream input, Session.SerializerSession session) { throw null; }\n\n        public static string Format(System.ReadOnlyMemory<byte> input, Session.SerializerSession session) { throw null; }\n\n        public static string Format(System.ReadOnlySpan<byte> input, Session.SerializerSession session) { throw null; }\n\n        public static void Format<TInput>(ref Buffers.Reader<TInput> reader, System.Text.StringBuilder result) { }\n\n        public static string Format<TInput>(ref Buffers.Reader<TInput> reader) { throw null; }\n    }\n\n    public static partial class FieldAccessor\n    {\n        public static System.Delegate GetGetter(System.Type declaringType, string fieldName) { throw null; }\n\n        public static System.Delegate GetReferenceSetter(System.Type declaringType, string fieldName) { throw null; }\n\n        public static System.Delegate GetValueGetter(System.Type declaringType, string fieldName) { throw null; }\n\n        public static System.Delegate GetValueSetter(System.Type declaringType, string fieldName) { throw null; }\n    }\n\n    public delegate TField ValueTypeGetter<TDeclaring, out TField>(ref TDeclaring instance)\n        where TDeclaring : struct;\n    public delegate void ValueTypeSetter<TDeclaring, in TField>(ref TDeclaring instance, TField value)\n        where TDeclaring : struct;\n}\n\nnamespace Orleans.Serialization.Utilities.Internal\n{\n    public static partial class InternalServiceCollectionExtensions\n    {\n        public static void AddFromExisting(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Type service, System.Type implementation) { }\n\n        public static void AddFromExisting<TService, TImplementation>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)\n            where TImplementation : TService { }\n    }\n}\n\nnamespace Orleans.Serialization.WireProtocol\n{\n    public enum ExtendedWireType : uint\n    {\n        EndTagDelimited = 0U,\n        EndBaseFields = 8U\n    }\n\n    public partial struct Field\n    {\n        public uint FieldIdDeltaRaw;\n        public System.Type FieldTypeRaw;\n        public Tag Tag;\n        public Field(Tag tag, uint extendedFieldIdDelta, System.Type type) { }\n\n        public Field(Tag tag) { }\n\n        public ExtendedWireType ExtendedWireType { get { throw null; } set { } }\n\n        public uint FieldIdDelta { get { throw null; } set { } }\n\n        public System.Type FieldType { get { throw null; } set { } }\n\n        public bool HasExtendedFieldId { get { throw null; } }\n\n        public bool HasExtendedSchemaType { get { throw null; } }\n\n        public bool HasFieldId { get { throw null; } }\n\n        public bool IsEndBaseFields { get { throw null; } }\n\n        public bool IsEndBaseOrEndObject { get { throw null; } }\n\n        public bool IsEndObject { get { throw null; } }\n\n        public bool IsReference { get { throw null; } }\n\n        public bool IsSchemaTypeValid { get { throw null; } }\n\n        public SchemaType SchemaType { get { throw null; } set { } }\n\n        public WireType WireType { get { throw null; } set { } }\n\n        public void EnsureWireType(WireType expectedType) { }\n\n        public void EnsureWireTypeTagDelimited() { }\n\n        public override string ToString() { throw null; }\n    }\n\n    public enum SchemaType : uint\n    {\n        Expected = 0U,\n        WellKnown = 8U,\n        Encoded = 16U,\n        Referenced = 24U\n    }\n\n    public partial struct Tag\n    {\n        private int _dummyPrimitive;\n        public const byte ExtendedWireTypeMask = 24;\n        public const byte FieldIdCompleteMask = 7;\n        public const byte FieldIdMask = 7;\n        public const int MaxEmbeddedFieldIdDelta = 6;\n        public const byte SchemaTypeMask = 24;\n        public const byte WireTypeMask = 224;\n        public Tag(byte tag) { }\n\n        public ExtendedWireType ExtendedWireType { get { throw null; } set { } }\n\n        public uint FieldIdDelta { get { throw null; } set { } }\n\n        public bool HasExtendedFieldId { get { throw null; } }\n\n        public bool HasExtendedWireType { get { throw null; } }\n\n        public bool IsFieldIdValid { get { throw null; } }\n\n        public bool IsSchemaTypeValid { get { throw null; } }\n\n        public SchemaType SchemaType { get { throw null; } set { } }\n\n        public WireType WireType { get { throw null; } set { } }\n\n        public static implicit operator byte(Tag tag) { throw null; }\n\n        public static implicit operator Tag(byte tag) { throw null; }\n\n        public void SetFieldIdInvalid() { }\n    }\n\n    public enum WireType : uint\n    {\n        VarInt = 0U,\n        TagDelimited = 32U,\n        LengthPrefixed = 64U,\n        Fixed32 = 96U,\n        Fixed64 = 128U,\n        Reference = 192U,\n        Extended = 224U\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Serialization\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CodecNotFoundException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.CodecNotFoundException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_CodecNotFoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.CodecNotFoundException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.CodecNotFoundException instance) { }\n\n        public global::Orleans.Serialization.CodecNotFoundException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.CodecNotFoundException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.CodecNotFoundException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ExtendedWireTypeInvalidException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.ExtendedWireTypeInvalidException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ExtendedWireTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.ExtendedWireTypeInvalidException instance) { }\n\n        public global::Orleans.Serialization.ExtendedWireTypeInvalidException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.ExtendedWireTypeInvalidException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.ExtendedWireTypeInvalidException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FieldIdNotPresentException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FieldIdNotPresentException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_FieldIdNotPresentException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.FieldIdNotPresentException instance) { }\n\n        public global::Orleans.Serialization.FieldIdNotPresentException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.FieldIdNotPresentException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FieldIdNotPresentException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FieldTypeInvalidException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FieldTypeInvalidException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_FieldTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.FieldTypeInvalidException instance) { }\n\n        public global::Orleans.Serialization.FieldTypeInvalidException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.FieldTypeInvalidException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FieldTypeInvalidException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FieldTypeMissingException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FieldTypeMissingException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_FieldTypeMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.FieldTypeMissingException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.FieldTypeMissingException instance) { }\n\n        public global::Orleans.Serialization.FieldTypeMissingException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.FieldTypeMissingException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FieldTypeMissingException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_IllegalTypeException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.IllegalTypeException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_IllegalTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.IllegalTypeException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.IllegalTypeException instance) { }\n\n        public global::Orleans.Serialization.IllegalTypeException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.IllegalTypeException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.IllegalTypeException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReferenceFieldNotSupportedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.ReferenceFieldNotSupportedException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ReferenceFieldNotSupportedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.ReferenceFieldNotSupportedException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.ReferenceFieldNotSupportedException instance) { }\n\n        public global::Orleans.Serialization.ReferenceFieldNotSupportedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.ReferenceFieldNotSupportedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.ReferenceFieldNotSupportedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReferenceNotFoundException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.ReferenceNotFoundException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ReferenceNotFoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.ReferenceNotFoundException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.ReferenceNotFoundException instance) { }\n\n        public global::Orleans.Serialization.ReferenceNotFoundException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.ReferenceNotFoundException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.ReferenceNotFoundException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RequiredFieldMissingException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.RequiredFieldMissingException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_RequiredFieldMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.RequiredFieldMissingException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.RequiredFieldMissingException instance) { }\n\n        public global::Orleans.Serialization.RequiredFieldMissingException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.RequiredFieldMissingException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.RequiredFieldMissingException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SchemaTypeInvalidException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.SchemaTypeInvalidException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_SchemaTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.SchemaTypeInvalidException instance) { }\n\n        public global::Orleans.Serialization.SchemaTypeInvalidException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.SchemaTypeInvalidException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.SchemaTypeInvalidException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SerializerException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.SerializerException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Serialization.SerializerException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_SerializerException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.SerializerException instance) { }\n\n        public global::Orleans.Serialization.SerializerException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.SerializerException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.SerializerException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TypeMissingException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.TypeMissingException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_TypeMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.TypeMissingException instance) { }\n\n        public global::Orleans.Serialization.TypeMissingException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.TypeMissingException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.TypeMissingException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UnexpectedLengthPrefixValueException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.UnexpectedLengthPrefixValueException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_UnexpectedLengthPrefixValueException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.UnexpectedLengthPrefixValueException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.UnexpectedLengthPrefixValueException instance) { }\n\n        public global::Orleans.Serialization.UnexpectedLengthPrefixValueException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.UnexpectedLengthPrefixValueException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.UnexpectedLengthPrefixValueException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UnknownReferencedTypeException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.UnknownReferencedTypeException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_UnknownReferencedTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.UnknownReferencedTypeException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.UnknownReferencedTypeException instance) { }\n\n        public global::Orleans.Serialization.UnknownReferencedTypeException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.UnknownReferencedTypeException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.UnknownReferencedTypeException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UnknownWellKnownTypeException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.UnknownWellKnownTypeException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_UnknownWellKnownTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.UnknownWellKnownTypeException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.UnknownWellKnownTypeException instance) { }\n\n        public global::Orleans.Serialization.UnknownWellKnownTypeException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.UnknownWellKnownTypeException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.UnknownWellKnownTypeException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UnsupportedWireTypeException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.UnsupportedWireTypeException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_UnsupportedWireTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.UnsupportedWireTypeException instance) { }\n\n        public global::Orleans.Serialization.UnsupportedWireTypeException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.UnsupportedWireTypeException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.UnsupportedWireTypeException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_CodecNotFoundException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.CodecNotFoundException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_CodecNotFoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ExtendedWireTypeInvalidException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.ExtendedWireTypeInvalidException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_ExtendedWireTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FieldIdNotPresentException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.FieldIdNotPresentException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_FieldIdNotPresentException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FieldTypeInvalidException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.FieldTypeInvalidException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_FieldTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FieldTypeMissingException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.FieldTypeMissingException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_FieldTypeMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_IllegalTypeException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.IllegalTypeException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_IllegalTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Serialization.IllegalTypeException input, global::Orleans.Serialization.IllegalTypeException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReferenceFieldNotSupportedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.ReferenceFieldNotSupportedException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_ReferenceFieldNotSupportedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Serialization.ReferenceFieldNotSupportedException input, global::Orleans.Serialization.ReferenceFieldNotSupportedException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReferenceNotFoundException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.ReferenceNotFoundException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_ReferenceNotFoundException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Serialization.ReferenceNotFoundException input, global::Orleans.Serialization.ReferenceNotFoundException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RequiredFieldMissingException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.RequiredFieldMissingException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_RequiredFieldMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SchemaTypeInvalidException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.SchemaTypeInvalidException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_SchemaTypeInvalidException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SerializerException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.SerializerException, System.Exception>\n    {\n        public Copier_SerializerException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TypeMissingException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.TypeMissingException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_TypeMissingException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_UnexpectedLengthPrefixValueException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.UnexpectedLengthPrefixValueException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_UnexpectedLengthPrefixValueException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_UnknownReferencedTypeException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.UnknownReferencedTypeException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_UnknownReferencedTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Serialization.UnknownReferencedTypeException input, global::Orleans.Serialization.UnknownReferencedTypeException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_UnknownWellKnownTypeException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.UnknownWellKnownTypeException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_UnknownWellKnownTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Serialization.UnknownWellKnownTypeException input, global::Orleans.Serialization.UnknownWellKnownTypeException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_UnsupportedWireTypeException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Serialization.UnsupportedWireTypeException, global::Orleans.Serialization.SerializerException>\n    {\n        public Copier_UnsupportedWireTypeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Serialization.Codecs\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ArrayListSurrogate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ArrayListSurrogate>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ArrayListSurrogate>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ArrayListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ArrayListSurrogate instance) { }\n\n        public global::Orleans.Serialization.Codecs.ArrayListSurrogate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ArrayListSurrogate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ArrayListSurrogate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ConcurrentDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ConcurrentDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ConcurrentQueueSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ConcurrentQueueSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CultureInfoSurrogate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.CultureInfoSurrogate>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.CultureInfoSurrogate>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.CultureInfoSurrogate instance) { }\n\n        public global::Orleans.Serialization.Codecs.CultureInfoSurrogate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.CultureInfoSurrogate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.CultureInfoSurrogate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableArraySurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableArraySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableHashSetSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableHashSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableListSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableQueueSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableQueueSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableSortedDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableSortedDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableSortedSetSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableSortedSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ImmutableStackSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ImmutableStackSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_NameValueCollectionSurrogate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_NameValueCollectionSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate instance) { }\n\n        public global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReadOnlyCollectionSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ReadOnlyCollectionSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ReadOnlyDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ReadOnlyDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SortedDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_SortedDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SortedListSurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_SortedListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SortedSetSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.SortedSetSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.SortedSetSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_SortedSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_VersionSurrogate : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Codecs.VersionSurrogate>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.Codecs.VersionSurrogate>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.Codecs.VersionSurrogate instance) { }\n\n        public global::Orleans.Serialization.Codecs.VersionSurrogate ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.Codecs.VersionSurrogate instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Codecs.VersionSurrogate value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ArrayListSurrogate : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ArrayListSurrogate>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ArrayListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ArrayListSurrogate DeepCopy(global::Orleans.Serialization.Codecs.ArrayListSurrogate result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ConcurrentDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ConcurrentDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.ConcurrentDictionarySurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ConcurrentQueueSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ConcurrentQueueSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ConcurrentQueueSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableArraySurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableArraySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableArraySurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableDictionarySurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableHashSetSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableHashSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableHashSetSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableListSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableListSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableQueueSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableQueueSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableQueueSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableSortedDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableSortedDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableSortedDictionarySurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableSortedSetSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableSortedSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableSortedSetSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ImmutableStackSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ImmutableStackSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ImmutableStackSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_NameValueCollectionSurrogate : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_NameValueCollectionSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate DeepCopy(global::Orleans.Serialization.Codecs.NameValueCollectionSurrogate result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReadOnlyCollectionSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ReadOnlyCollectionSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.ReadOnlyCollectionSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ReadOnlyDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_ReadOnlyDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.ReadOnlyDictionarySurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SortedDictionarySurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_SortedDictionarySurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.SortedDictionarySurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SortedListSurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_SortedListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.Codecs.SortedListSurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SortedSetSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.Codecs.SortedSetSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_SortedSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> DeepCopy(global::Orleans.Serialization.Codecs.SortedSetSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Serialization.Invocation\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CompletedResponse : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Invocation.CompletedResponse>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_CompletedResponse(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Serialization.Invocation.CompletedResponse> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.Invocation.CompletedResponse instance) { }\n\n        public global::Orleans.Serialization.Invocation.CompletedResponse ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.Invocation.CompletedResponse instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Invocation.CompletedResponse value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ExceptionResponse : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.Invocation.ExceptionResponse>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ExceptionResponse(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.Invocation.ExceptionResponse instance) { }\n\n        public global::Orleans.Serialization.Invocation.ExceptionResponse ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Serialization.Invocation.ExceptionResponse instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.Invocation.ExceptionResponse value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Enum | System.AttributeTargets.Method | System.AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed partial class AliasAttribute : System.Attribute\n    {\n        public AliasAttribute(string alias) { }\n\n        public string Alias { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed partial class ApplicationPartAttribute : System.Attribute\n    {\n        public ApplicationPartAttribute(string assemblyName) { }\n\n        public string AssemblyName { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Enum | System.AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed partial class CompoundTypeAliasAttribute : System.Attribute\n    {\n        public CompoundTypeAliasAttribute(params object[] components) { }\n\n        public object[] Components { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public sealed partial class DefaultInvokableBaseTypeAttribute : System.Attribute\n    {\n        public DefaultInvokableBaseTypeAttribute(System.Type returnType, System.Type invokableBaseType) { }\n\n        public System.Type InvokableBaseType { get { throw null; } }\n\n        public string ProxyInvokeMethodName { get { throw null; } init { } }\n\n        public System.Type ReturnType { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public sealed partial class DefaultInvokeMethodNameAttribute : System.Attribute\n    {\n        public DefaultInvokeMethodNameAttribute(System.Type returnType, string methodName) { }\n\n        public string MethodName { get { throw null; } }\n\n        public System.Type ReturnType { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed partial class GenerateCodeForDeclaringAssemblyAttribute : System.Attribute\n    {\n        public GenerateCodeForDeclaringAssemblyAttribute(System.Type type) { }\n\n        public System.Type Type { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Constructor)]\n    public sealed partial class GeneratedActivatorConstructorAttribute : System.Attribute\n    {\n    }\n\n    public enum GenerateFieldIds\n    {\n        None = 0,\n        PublicProperties = 1\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed partial class GenerateMethodSerializersAttribute : System.Attribute\n    {\n        public GenerateMethodSerializersAttribute(System.Type proxyBase, bool isExtension = false) { }\n\n        public bool IsExtension { get { throw null; } }\n\n        public System.Type ProxyBase { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Enum)]\n    public sealed partial class GenerateSerializerAttribute : System.Attribute\n    {\n        public GenerateFieldIds GenerateFieldIds { get { throw null; } init { } }\n\n        public bool IncludePrimaryConstructorParameters { get { throw null; } init { } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class GetCompletionSourceMethodNameAttribute : System.Attribute\n    {\n        public GetCompletionSourceMethodNameAttribute(string methodName) { }\n\n        public string MethodName { get { throw null; } }\n    }\n\n    public partial interface IConverter<TValue, TSurrogate>\n        where TSurrogate : struct\n    {\n        TValue ConvertFromSurrogate(in TSurrogate surrogate);\n        TSurrogate ConvertToSurrogate(in TValue value);\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Enum | System.AttributeTargets.Method | System.AttributeTargets.Property | System.AttributeTargets.Field)]\n    public sealed partial class IdAttribute : System.Attribute\n    {\n        public IdAttribute(uint id) { }\n\n        public uint Id { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Property | System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.ReturnValue, Inherited = false)]\n    public sealed partial class ImmutableAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = true)]\n    public sealed partial class InvokableBaseTypeAttribute : System.Attribute\n    {\n        public InvokableBaseTypeAttribute(System.Type proxyBaseClass, System.Type returnType, System.Type invokableBaseType) { }\n\n        public System.Type InvokableBaseType { get { throw null; } }\n\n        public System.Type ProxyBaseClass { get { throw null; } }\n\n        public string ProxyInvokeMethodName { get { throw null; } init { } }\n\n        public System.Type ReturnType { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public sealed partial class InvokableCustomInitializerAttribute : System.Attribute\n    {\n        public InvokableCustomInitializerAttribute(string methodName, object methodArgumentValue) { }\n\n        public InvokableCustomInitializerAttribute(string methodName) { }\n\n        public int AttributeArgumentIndex { get { throw null; } init { } }\n\n        public int AttributeArgumentName { get { throw null; } init { } }\n\n        public object MethodArgumentValue { get { throw null; } }\n\n        public string MethodName { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class InvokeMethodNameAttribute : System.Attribute\n    {\n        public InvokeMethodNameAttribute(string invokeMethodName) { }\n\n        public string InvokeMethodName { get { throw null; } }\n    }\n\n    public partial interface IPopulator<TValue, TSurrogate>\n        where TValue : class where TSurrogate : struct\n    {\n        void Populate(in TSurrogate surrogate, TValue value);\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class OmitDefaultMemberValuesAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Constructor)]\n    public sealed partial class OrleansConstructorAttribute : Microsoft.Extensions.DependencyInjection.ActivatorUtilitiesConstructorAttribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class RegisterActivatorAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class RegisterConverterAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class RegisterCopierAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)]\n    public sealed partial class RegisterProviderAttribute : System.Attribute\n    {\n        public RegisterProviderAttribute(string name, string kind, string target, System.Type type) { }\n\n        public string Kind { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        public string Target { get { throw null; } }\n\n        public System.Type Type { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class RegisterSerializerAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Method)]\n    public sealed partial class ResponseTimeoutAttribute : System.Attribute\n    {\n        public ResponseTimeoutAttribute(string timeout) { }\n\n        public System.TimeSpan? Timeout { get { throw null; } init { } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class SerializationCallbacksAttribute : System.Attribute\n    {\n        public SerializationCallbacksAttribute(System.Type hookType) { }\n\n        public System.Type HookType { get { throw null; } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, Inherited = false)]\n    public sealed partial class SerializerTransparentAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class SuppressReferenceTrackingAttribute : System.Attribute\n    {\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]\n    public sealed partial class UseActivatorAttribute : System.Attribute\n    {\n    }\n}\n\nnamespace Orleans.Invocation\n{\n    [System.AttributeUsage(System.AttributeTargets.Class)]\n    public sealed partial class ReturnValueProxyAttribute : System.Attribute\n    {\n        public ReturnValueProxyAttribute(string initializerMethodName) { }\n\n        public string InitializerMethodName { get { throw null; } }\n    }\n}\n\nnamespace Orleans.Metadata\n{\n    [System.AttributeUsage(System.AttributeTargets.Assembly)]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    public sealed partial class FrameworkPartAttribute : System.Attribute\n    {\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.FSharp/Orleans.Serialization.FSharp.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [RegisterSerializer]\n    public partial class FSharpChoiceCodec<T1, T2> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpChoiceCodec(Codecs.IFieldCodec<T1> item1Codec, Codecs.IFieldCodec<T2> item2Codec) { }\n\n        Microsoft.FSharp.Core.FSharpChoice<T1, T2> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpChoice<T1, T2> value) { }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpChoiceCodec<T1, T2, T3> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpChoiceCodec(Codecs.IFieldCodec<T1> item1Codec, Codecs.IFieldCodec<T2> item2Codec, Codecs.IFieldCodec<T3> item3Codec) { }\n\n        Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3> value) { }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpChoiceCodec<T1, T2, T3, T4> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpChoiceCodec(Codecs.IFieldCodec<T1> item1Codec, Codecs.IFieldCodec<T2> item2Codec, Codecs.IFieldCodec<T3> item3Codec, Codecs.IFieldCodec<T4> item4Codec) { }\n\n        Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4> value) { }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpChoiceCodec<T1, T2, T3, T4, T5> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpChoiceCodec(Codecs.IFieldCodec<T1> item1Codec, Codecs.IFieldCodec<T2> item2Codec, Codecs.IFieldCodec<T3> item3Codec, Codecs.IFieldCodec<T4> item4Codec, Codecs.IFieldCodec<T5> item5Codec) { }\n\n        Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5> value) { }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpChoiceCodec<T1, T2, T3, T4, T5, T6> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpChoiceCodec(Codecs.IFieldCodec<T1> item1Codec, Codecs.IFieldCodec<T2> item2Codec, Codecs.IFieldCodec<T3> item3Codec, Codecs.IFieldCodec<T4> item4Codec, Codecs.IFieldCodec<T5> item5Codec, Codecs.IFieldCodec<T6> item6Codec) { }\n\n        Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6> value) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpChoiceCopier<T1, T2> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpChoice<T1, T2>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpChoiceCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2) { }\n\n        public Microsoft.FSharp.Core.FSharpChoice<T1, T2> DeepCopy(Microsoft.FSharp.Core.FSharpChoice<T1, T2> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpChoiceCopier<T1, T2, T3> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpChoiceCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3) { }\n\n        public Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3> DeepCopy(Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpChoiceCopier<T1, T2, T3, T4> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpChoiceCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4) { }\n\n        public Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4> DeepCopy(Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpChoiceCopier<T1, T2, T3, T4, T5> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpChoiceCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5) { }\n\n        public Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5> DeepCopy(Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpChoiceCopier<T1, T2, T3, T4, T5, T6> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpChoiceCopier(Cloning.IDeepCopier<T1> copier1, Cloning.IDeepCopier<T2> copier2, Cloning.IDeepCopier<T3> copier3, Cloning.IDeepCopier<T4> copier4, Cloning.IDeepCopier<T5> copier5, Cloning.IDeepCopier<T6> copier6) { }\n\n        public Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6> DeepCopy(Microsoft.FSharp.Core.FSharpChoice<T1, T2, T3, T4, T5, T6> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpListCodec<T> : Codecs.GeneralizedReferenceTypeSurrogateCodec<Microsoft.FSharp.Collections.FSharpList<T>, FSharpListSurrogate<T>>\n    {\n        public FSharpListCodec(Serializers.IValueSerializer<FSharpListSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override Microsoft.FSharp.Collections.FSharpList<T> ConvertFromSurrogate(ref FSharpListSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(Microsoft.FSharp.Collections.FSharpList<T> value, ref FSharpListSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpListCopier<T> : Cloning.IDeepCopier<Microsoft.FSharp.Collections.FSharpList<T>>, Cloning.IDeepCopier\n    {\n        public FSharpListCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public Microsoft.FSharp.Collections.FSharpList<T> DeepCopy(Microsoft.FSharp.Collections.FSharpList<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct FSharpListSurrogate<T>\n    {\n        private System.Collections.Generic.List<T> _Value_k__BackingField;\n        private object _dummy;\n        private int _dummyPrimitive;\n        [Id(0)]\n        public System.Collections.Generic.List<T> Value { get { throw null; } set { } }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpMapCodec<TKey, TValue> : Codecs.GeneralizedReferenceTypeSurrogateCodec<Microsoft.FSharp.Collections.FSharpMap<TKey, TValue>, FSharpMapSurrogate<TKey, TValue>>\n    {\n        public FSharpMapCodec(Serializers.IValueSerializer<FSharpMapSurrogate<TKey, TValue>> surrogateSerializer) : base(default!) { }\n\n        public override Microsoft.FSharp.Collections.FSharpMap<TKey, TValue> ConvertFromSurrogate(ref FSharpMapSurrogate<TKey, TValue> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(Microsoft.FSharp.Collections.FSharpMap<TKey, TValue> value, ref FSharpMapSurrogate<TKey, TValue> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpMapCopier<TKey, TValue> : Cloning.IDeepCopier<Microsoft.FSharp.Collections.FSharpMap<TKey, TValue>>, Cloning.IDeepCopier\n    {\n        public FSharpMapCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public Microsoft.FSharp.Collections.FSharpMap<TKey, TValue> DeepCopy(Microsoft.FSharp.Collections.FSharpMap<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct FSharpMapSurrogate<TKey, TValue>\n    {\n        private System.Collections.Generic.List<System.Tuple<TKey, TValue>> _Value_k__BackingField;\n        private object _dummy;\n        private int _dummyPrimitive;\n        [Id(0)]\n        public System.Collections.Generic.List<System.Tuple<TKey, TValue>> Value { get { throw null; } set { } }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class FSharpOptionCodec<T> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpOption<T>>, Codecs.IFieldCodec\n    {\n        public FSharpOptionCodec(Codecs.IFieldCodec<T> fieldCodec) { }\n\n        public Microsoft.FSharp.Core.FSharpOption<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpOption<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class FSharpOptionCopier<T> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpOption<T>>, Cloning.IDeepCopier\n    {\n        public FSharpOptionCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public Microsoft.FSharp.Core.FSharpOption<T> DeepCopy(Microsoft.FSharp.Core.FSharpOption<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpRefCodec<T> : Codecs.GeneralizedReferenceTypeSurrogateCodec<Microsoft.FSharp.Core.FSharpRef<T>, FSharpRefSurrogate<T>>\n    {\n        public FSharpRefCodec(Serializers.IValueSerializer<FSharpRefSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override Microsoft.FSharp.Core.FSharpRef<T> ConvertFromSurrogate(ref FSharpRefSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(Microsoft.FSharp.Core.FSharpRef<T> value, ref FSharpRefSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpRefCopier<T> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpRef<T>>, Cloning.IDeepCopier\n    {\n        public FSharpRefCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public Microsoft.FSharp.Core.FSharpRef<T> DeepCopy(Microsoft.FSharp.Core.FSharpRef<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct FSharpRefSurrogate<T>\n    {\n        private T _Value_k__BackingField;\n        [Id(0)]\n        public T Value { get { throw null; } set { } }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpResultCodec<T, TError> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpResult<T, TError>>, Codecs.IFieldCodec, Codecs.IDerivedTypeCodec\n    {\n        public FSharpResultCodec(Codecs.IFieldCodec<T> item1Codec, Codecs.IFieldCodec<TError> item2Codec) { }\n\n        Microsoft.FSharp.Core.FSharpResult<T, TError> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpResult<T, TError>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpResult<T, TError>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpResult<T, TError> value) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpResultCopier<T, TError> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpResult<T, TError>>, Cloning.IDeepCopier, Cloning.IDerivedTypeCopier\n    {\n        public FSharpResultCopier(Cloning.IDeepCopier<T> copier1, Cloning.IDeepCopier<TError> copier2) { }\n\n        public Microsoft.FSharp.Core.FSharpResult<T, TError> DeepCopy(Microsoft.FSharp.Core.FSharpResult<T, TError> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpSetCodec<T> : Codecs.GeneralizedReferenceTypeSurrogateCodec<Microsoft.FSharp.Collections.FSharpSet<T>, FSharpSetSurrogate<T>>\n    {\n        public FSharpSetCodec(Serializers.IValueSerializer<FSharpSetSurrogate<T>> surrogateSerializer) : base(default!) { }\n\n        public override Microsoft.FSharp.Collections.FSharpSet<T> ConvertFromSurrogate(ref FSharpSetSurrogate<T> surrogate) { throw null; }\n\n        public override void ConvertToSurrogate(Microsoft.FSharp.Collections.FSharpSet<T> value, ref FSharpSetSurrogate<T> surrogate) { }\n    }\n\n    [RegisterCopier]\n    public partial class FSharpSetCopier<T> : Cloning.IDeepCopier<Microsoft.FSharp.Collections.FSharpSet<T>>, Cloning.IDeepCopier\n    {\n        public FSharpSetCopier(Cloning.IDeepCopier<T> copier) { }\n\n        public Microsoft.FSharp.Collections.FSharpSet<T> DeepCopy(Microsoft.FSharp.Collections.FSharpSet<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial struct FSharpSetSurrogate<T>\n    {\n        private System.Collections.Generic.List<T> _Value_k__BackingField;\n        private object _dummy;\n        private int _dummyPrimitive;\n        [Id(0)]\n        public System.Collections.Generic.List<T> Value { get { throw null; } set { } }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class FSharpUnitCodec : Codecs.IFieldCodec<Microsoft.FSharp.Core.Unit>, Codecs.IFieldCodec\n    {\n        public Microsoft.FSharp.Core.Unit ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.Unit value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class FSharpUnitCopier : Cloning.ShallowCopier<Microsoft.FSharp.Core.Unit>\n    {\n    }\n\n    [RegisterSerializer]\n    public partial class FSharpValueOptionCodec<T> : Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpValueOption<T>>, Codecs.IFieldCodec\n    {\n        public FSharpValueOptionCodec(Codecs.IFieldCodec<T> item1Codec) { }\n\n        Microsoft.FSharp.Core.FSharpValueOption<T> Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpValueOption<T>>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Microsoft.FSharp.Core.FSharpValueOption<T>>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Microsoft.FSharp.Core.FSharpValueOption<T> value) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class FSharpValueOptionCopier<T> : Cloning.IDeepCopier<Microsoft.FSharp.Core.FSharpValueOption<T>>, Cloning.IDeepCopier\n    {\n        public FSharpValueOptionCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public Microsoft.FSharp.Core.FSharpValueOption<T> DeepCopy(Microsoft.FSharp.Core.FSharpValueOption<T> input, Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Serialization\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FSharpListSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FSharpListSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.FSharpListSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_FSharpListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.FSharpListSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.FSharpListSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.FSharpListSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FSharpListSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FSharpMapSurrogate<TKey, TValue> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_FSharpMapSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> instance) { }\n\n        public global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FSharpRefSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FSharpRefSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.FSharpRefSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_FSharpRefSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.FSharpRefSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.FSharpRefSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.FSharpRefSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FSharpRefSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FSharpSetSurrogate<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Serialization.FSharpSetSurrogate<T>>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Serialization.FSharpSetSurrogate<T>>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_FSharpSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Serialization.FSharpSetSurrogate<T> instance) { }\n\n        public global::Orleans.Serialization.FSharpSetSurrogate<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Serialization.FSharpSetSurrogate<T> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Serialization.FSharpSetSurrogate<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FSharpListSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.FSharpListSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_FSharpListSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.FSharpListSurrogate<T> DeepCopy(global::Orleans.Serialization.FSharpListSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FSharpMapSurrogate<TKey, TValue> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_FSharpMapSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> DeepCopy(global::Orleans.Serialization.FSharpMapSurrogate<TKey, TValue> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FSharpRefSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.FSharpRefSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_FSharpRefSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.FSharpRefSurrogate<T> DeepCopy(global::Orleans.Serialization.FSharpRefSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FSharpSetSurrogate<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Serialization.FSharpSetSurrogate<T>>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_FSharpSetSurrogate(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Serialization.FSharpSetSurrogate<T> DeepCopy(global::Orleans.Serialization.FSharpSetSurrogate<T> result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.MemoryPack/Orleans.Serialization.MemoryPack.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [Alias(\"memorypack\")]\n    public partial class MemoryPackCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter\n    {\n        public const string WellKnownAlias = \"memorypack\";\n        public MemoryPackCodec(System.Collections.Generic.IEnumerable<Serializers.ICodecSelector> serializableTypeSelectors, System.Collections.Generic.IEnumerable<Serializers.ICopierSelector> copyableTypeSelectors, Microsoft.Extensions.Options.IOptions<MemoryPackCodecOptions> options) { }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }\n\n        bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public partial class MemoryPackCodecOptions\n    {\n        public System.Func<System.Type, bool?> IsCopyableType { get { throw null; } set { } }\n\n        public System.Func<System.Type, bool?> IsSerializableType { get { throw null; } set { } }\n\n        public MemoryPack.MemoryPackSerializerOptions SerializerOptions { get { throw null; } set { } }\n    }\n\n    public static partial class SerializationHostingExtensions\n    {\n        public static ISerializerBuilder AddMemoryPackSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable = null, System.Func<System.Type, bool> isCopyable = null, MemoryPack.MemoryPackSerializerOptions memoryPackSerializerOptions = null) { throw null; }\n\n        public static ISerializerBuilder AddMemoryPackSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable, System.Func<System.Type, bool> isCopyable, System.Action<Microsoft.Extensions.Options.OptionsBuilder<MemoryPackCodecOptions>> configureOptions = null) { throw null; }\n    }\n}\n"
  },
  {
    "path": "src/api/Orleans.Serialization.MessagePack/Orleans.Serialization.MessagePack.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [Alias(\"msgpack\")]\n    public partial class MessagePackCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter\n    {\n        public const string WellKnownAlias = \"msgpack\";\n        public MessagePackCodec(System.Collections.Generic.IEnumerable<Serializers.ICodecSelector> serializableTypeSelectors, System.Collections.Generic.IEnumerable<Serializers.ICopierSelector> copyableTypeSelectors, Microsoft.Extensions.Options.IOptions<MessagePackCodecOptions> options) { }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }\n\n        bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public partial class MessagePackCodecOptions\n    {\n        public bool AllowDataContractAttributes { get { throw null; } set { } }\n\n        public System.Func<System.Type, bool?> IsCopyableType { get { throw null; } set { } }\n\n        public System.Func<System.Type, bool?> IsSerializableType { get { throw null; } set { } }\n\n        public MessagePack.MessagePackSerializerOptions SerializerOptions { get { throw null; } set { } }\n    }\n\n    public static partial class SerializationHostingExtensions\n    {\n        public static ISerializerBuilder AddMessagePackSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable = null, System.Func<System.Type, bool> isCopyable = null, MessagePack.MessagePackSerializerOptions messagePackSerializerOptions = null) { throw null; }\n\n        public static ISerializerBuilder AddMessagePackSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable, System.Func<System.Type, bool> isCopyable, System.Action<Microsoft.Extensions.Options.OptionsBuilder<MessagePackCodecOptions>> configureOptions = null) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.NewtonsoftJson/Orleans.Serialization.NewtonsoftJson.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [Alias(\"json.net\")]\n    public partial class NewtonsoftJsonCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter\n    {\n        public const string WellKnownAlias = \"json.net\";\n        public NewtonsoftJsonCodec(System.Collections.Generic.IEnumerable<Serializers.ICodecSelector> serializableTypeSelectors, System.Collections.Generic.IEnumerable<Serializers.ICopierSelector> copyableTypeSelectors, Microsoft.Extensions.Options.IOptions<NewtonsoftJsonCodecOptions> options) { }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }\n\n        bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public partial class NewtonsoftJsonCodecOptions\n    {\n        public System.Func<System.Type, bool?> IsCopyableType { get { throw null; } set { } }\n\n        public System.Func<System.Type, bool?> IsSerializableType { get { throw null; } set { } }\n\n        public Newtonsoft.Json.JsonSerializerSettings SerializerSettings { get { throw null; } set { } }\n    }\n\n    public static partial class SerializationHostingExtensions\n    {\n        public static ISerializerBuilder AddNewtonsoftJsonSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSupported, Newtonsoft.Json.JsonSerializerSettings jsonSerializerSettings = null) { throw null; }\n\n        public static ISerializerBuilder AddNewtonsoftJsonSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSupported, System.Action<Microsoft.Extensions.Options.OptionsBuilder<NewtonsoftJsonCodecOptions>> configureOptions) { throw null; }\n\n        public static ISerializerBuilder AddNewtonsoftJsonSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable, System.Func<System.Type, bool> isCopyable, System.Action<Microsoft.Extensions.Options.OptionsBuilder<NewtonsoftJsonCodecOptions>> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.SystemTextJson/Orleans.Serialization.SystemTextJson.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [Alias(\"json\")]\n    public partial class JsonCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter\n    {\n        public const string WellKnownAlias = \"json\";\n        public JsonCodec(System.Collections.Generic.IEnumerable<Serializers.ICodecSelector> serializableTypeSelectors, System.Collections.Generic.IEnumerable<Serializers.ICopierSelector> copyableTypeSelectors, Microsoft.Extensions.Options.IOptions<JsonCodecOptions> options) { }\n\n        object Cloning.IDeepCopier.DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }\n\n        bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }\n    }\n\n    public partial class JsonCodecOptions\n    {\n        public System.Func<System.Type, bool?> IsCopyableType { get { throw null; } set { } }\n\n        public System.Func<System.Type, bool?> IsSerializableType { get { throw null; } set { } }\n\n        public System.Text.Json.JsonReaderOptions ReaderOptions { get { throw null; } set { } }\n\n        public System.Text.Json.JsonSerializerOptions SerializerOptions { get { throw null; } set { } }\n\n        public System.Text.Json.JsonWriterOptions WriterOptions { get { throw null; } set { } }\n    }\n\n    public static partial class SerializationHostingExtensions\n    {\n        public static ISerializerBuilder AddJsonSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable, System.Func<System.Type, bool> isCopyable, System.Action<Microsoft.Extensions.Options.OptionsBuilder<JsonCodecOptions>> configureOptions = null) { throw null; }\n\n        public static ISerializerBuilder AddJsonSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSupported, System.Text.Json.JsonSerializerOptions jsonSerializerOptions = null) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Serialization.TestKit/Orleans.Serialization.TestKit.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization.TestKit\n{\n    [Xunit.Trait(\"Category\", \"BVT\")]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public abstract partial class CopierTester<TValue, TCopier>\n        where TCopier : class, Cloning.IDeepCopier<TValue>\n    {\n        protected CopierTester(Xunit.Abstractions.ITestOutputHelper output) { }\n\n        protected virtual bool IsImmutable { get { throw null; } }\n\n        protected virtual bool IsPooled { get { throw null; } }\n\n        protected System.Random Random { get { throw null; } }\n\n        protected System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        protected abstract TValue[] TestValues { get; }\n\n        protected virtual System.Action<System.Action<TValue>> ValueProvider { get { throw null; } }\n\n        [Xunit.Fact]\n        public void CanCopyCollectionViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanCopyCollectionViaUntypedSerializer() { }\n\n        [Xunit.Fact]\n        public void CanCopyTupleViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanCopyUntypedTupleViaSerializer() { }\n\n        protected virtual void Configure(ISerializerBuilder builder) { }\n\n        [Xunit.Fact]\n        public void CopiedValuesAreEqual() { }\n\n        protected virtual TCopier CreateCopier() { throw null; }\n\n        protected abstract TValue CreateValue();\n        protected virtual bool Equals(TValue left, TValue right) { throw null; }\n\n        [Xunit.Fact]\n        public void ReferencesAreAddedToCopyContext() { }\n    }\n\n    [Xunit.Trait(\"Category\", \"BVT\")]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public abstract partial class FieldCodecTester<TValue, TCodec> : System.IDisposable where TCodec : class, Codecs.IFieldCodec<TValue>\n    {\n        protected FieldCodecTester(Xunit.Abstractions.ITestOutputHelper output) { }\n\n        protected virtual int[] MaxSegmentSizes { get { throw null; } }\n\n        protected System.Random Random { get { throw null; } }\n\n        protected System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        protected Session.SerializerSessionPool SessionPool { get { throw null; } }\n\n        protected abstract TValue[] TestValues { get; }\n\n        protected virtual System.Action<System.Action<TValue>> ValueProvider { get { throw null; } }\n\n        [Xunit.Fact]\n        public void CanRoundTripCollectionViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripDefaultValueViaCodec() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripTupleViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaObjectSerializer() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_Array() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_Memory() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_MemoryStream() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_ReadByteByByte() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_Span() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripViaSerializer_StreamPooled() { }\n\n        [Xunit.Fact]\n        public void CanRoundTripWeaklyTypedCollectionViaSerializer() { }\n\n        [Xunit.Fact]\n        public void CanSkipDefaultValue() { }\n\n        [Xunit.Fact]\n        public void CanSkipValue() { }\n\n        protected virtual void Configure(ISerializerBuilder builder) { }\n\n        [Xunit.Fact]\n        public void CorrectlyAdvancesReferenceCounter() { }\n\n        [Xunit.Fact]\n        public void CorrectlyAdvancesReferenceCounterStream() { }\n\n        [Xunit.Fact]\n        public void CorrectlyHandlesBuffers() { }\n\n        protected virtual TCodec CreateCodec() { throw null; }\n\n        protected abstract TValue CreateValue();\n        protected virtual bool Equals(TValue left, TValue right) { throw null; }\n\n        protected virtual TValue GetWriteCopy(TValue input) { throw null; }\n\n        [Xunit.Fact]\n        public void ProducesValidBitStream() { }\n\n        [Xunit.Fact]\n        public void RoundTrippedValuesEqual() { }\n\n        protected T RoundTripThroughCodec<T>(T original) { throw null; }\n\n        protected object RoundTripThroughUntypedSerializer(object original, out string formattedBitStream) { throw null; }\n\n        void System.IDisposable.Dispose() { }\n\n        [Xunit.Fact]\n        public void WritersProduceSameResults() { }\n    }\n\n    public partial interface IOutputBuffer\n    {\n        System.Buffers.ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize);\n    }\n\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public static partial class ReadOnlySequenceHelper\n    {\n        public static System.Collections.Generic.IEnumerable<byte[]> Batch(this System.Collections.Generic.IEnumerable<byte> sequence, int batchSize) { throw null; }\n\n        public static System.Buffers.ReadOnlySequence<byte> CreateReadOnlySequence(params byte[][] buffers) { throw null; }\n\n        public static System.Buffers.ReadOnlySequence<byte> ToReadOnlySequence(this System.Collections.Generic.IEnumerable<byte[]> buffers) { throw null; }\n\n        public static System.Buffers.ReadOnlySequence<byte> ToReadOnlySequence(this System.Collections.Generic.IEnumerable<System.Memory<byte>> buffers) { throw null; }\n    }\n\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public partial struct TestBufferWriterStruct : System.Buffers.IBufferWriter<byte>, IOutputBuffer\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        public TestBufferWriterStruct(byte[] buffer) { }\n\n        public void Advance(int bytes) { }\n\n        public readonly System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public readonly System.Buffers.ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize) { throw null; }\n\n        public readonly System.Span<byte> GetSpan(int sizeHint) { throw null; }\n    }\n\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public partial class TestMultiSegmentBufferWriter : System.Buffers.IBufferWriter<byte>, IOutputBuffer\n    {\n        public TestMultiSegmentBufferWriter(int maxAllocationSize) { }\n\n        public void Advance(int bytes) { }\n\n        public System.Memory<byte> GetMemory(int sizeHint = 0) { throw null; }\n\n        public System.Buffers.ReadOnlySequence<byte> GetReadOnlySequence(int maxSegmentSize) { throw null; }\n\n        public System.Span<byte> GetSpan(int sizeHint) { throw null; }\n\n        public System.Buffers.ReadOnlySequence<byte> PeekAllBuffers() { throw null; }\n    }\n\n    public abstract partial class ValueTypeFieldCodecTester<TField, TCodec> : FieldCodecTester<TField, TCodec> where TField : struct where TCodec : class, Codecs.IFieldCodec<TField>\n    {\n        protected ValueTypeFieldCodecTester(Xunit.Abstractions.ITestOutputHelper output) : base(default!) { }\n\n        [Xunit.Fact]\n        public void DirectAccessValueSerializerRoundTrip() { }\n\n        [Xunit.Fact]\n        public void ValueSerializerRoundTrip() { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Server/Orleans.Server.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/api/Orleans.Streaming/Orleans.Streaming.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    public static partial class ClientStreamingExtensions\n    {\n        public static Streams.IStreamProvider GetStreamProvider(this IClusterClient client, string name) { throw null; }\n    }\n\n    public static partial class GrainStreamingExtensions\n    {\n        public static Streams.IStreamProvider GetStreamProvider(this Grain grain, string name) { throw null; }\n\n        public static Streams.IStreamProvider GetStreamProvider(this IGrainBase grain, string name) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public partial class ImplicitStreamSubscriptionAttribute : System.Attribute, Metadata.IGrainBindingsProviderAttribute\n    {\n        public ImplicitStreamSubscriptionAttribute() { }\n\n        public ImplicitStreamSubscriptionAttribute(Streams.IStreamNamespacePredicate predicate, string streamIdMapper = null) { }\n\n        public ImplicitStreamSubscriptionAttribute(string streamNamespace, string streamIdMapper = null) { }\n\n        public ImplicitStreamSubscriptionAttribute(System.Type predicateType, string streamIdMapper = null) { }\n\n        public Streams.IStreamNamespacePredicate Predicate { get { throw null; } }\n\n        public string StreamIdMapper { get { throw null; } init { } }\n\n        public System.Collections.Generic.IEnumerable<System.Collections.Generic.Dictionary<string, string>> GetBindings(System.IServiceProvider services, System.Type grainClass, Runtime.GrainType grainType) { throw null; }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]\n    public sealed partial class RegexImplicitStreamSubscriptionAttribute : ImplicitStreamSubscriptionAttribute\n    {\n        public RegexImplicitStreamSubscriptionAttribute(string pattern) { }\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class DeploymentBasedQueueBalancerOptions\n    {\n        public static readonly System.TimeSpan DEFAULT_SILO_MATURITY_PERIOD;\n        public bool IsFixed { get { throw null; } set { } }\n\n        public System.TimeSpan SiloMaturityPeriod { get { throw null; } set { } }\n    }\n\n    public partial class HashRingStreamQueueMapperOptions\n    {\n        public const int DEFAULT_NUM_QUEUES = 8;\n        public int TotalQueueCount { get { throw null; } set { } }\n    }\n\n    public partial class LeaseBasedQueueBalancerOptions\n    {\n        public const string DefaultLeaseCategory = \"QueueBalancer\";\n        public static readonly System.TimeSpan DefaultLeaseLength;\n        public static readonly System.TimeSpan DefaultLeaseRenewPeriod;\n        public static readonly System.TimeSpan DefaultMinLeaseAcquisitionPeriod;\n        [System.Obsolete(\"Use DefaultMinLeaseAcquisitionPeriod instead.\", true)]\n        public static readonly System.TimeSpan DefaultMinLeaseAquisitionPeriod;\n        public System.TimeSpan LeaseAcquisitionPeriod { get { throw null; } set { } }\n\n        [System.Obsolete(\"Use LeaseAcquisitionPeriod instead.\", true)]\n        public System.TimeSpan LeaseAquisitionPeriod { get { throw null; } set { } }\n\n        public string LeaseCategory { get { throw null; } set { } }\n\n        public System.TimeSpan LeaseLength { get { throw null; } set { } }\n\n        public System.TimeSpan LeaseRenewPeriod { get { throw null; } set { } }\n    }\n\n    public partial class SimpleQueueCacheOptions\n    {\n        public const int DEFAULT_CACHE_SIZE = 4096;\n        public int CacheSize { get { throw null; } set { } }\n    }\n\n    public partial class SimpleQueueCacheOptionsValidator : IConfigurationValidator\n    {\n        internal SimpleQueueCacheOptionsValidator() { }\n\n        public static IConfigurationValidator Create(System.IServiceProvider services, string name) { throw null; }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public partial class StreamCacheEvictionOptions\n    {\n        public static readonly System.TimeSpan DefaultDataMaxAgeInCache;\n        public static readonly System.TimeSpan DefaultDataMinTimeInCache;\n        public static readonly System.TimeSpan DefaultMetadataMinTimeInCache;\n        public System.TimeSpan DataMaxAgeInCache { get { throw null; } set { } }\n\n        public System.TimeSpan DataMinTimeInCache { get { throw null; } set { } }\n\n        public System.TimeSpan? MetadataMinTimeInCache { get { throw null; } set { } }\n    }\n\n    public partial class StreamLifecycleOptions\n    {\n        public const int DEFAULT_INIT_STAGE = 10000;\n        public const int DEFAULT_START_STAGE = 20000;\n        public const RunState DEFAULT_STARTUP_STATE = 2;\n        public int InitStage { get { throw null; } set { } }\n\n        public int StartStage { get { throw null; } set { } }\n\n        public RunState StartupState { get { throw null; } set { } }\n\n        public enum RunState\n        {\n            None = 0,\n            Initialized = 1,\n            AgentsStarted = 2,\n            AgentsStopped = 3\n        }\n    }\n\n    public partial class StreamPubSubOptions\n    {\n        public const Streams.StreamPubSubType DEFAULT_STREAM_PUBSUB_TYPE = 0;\n        public Streams.StreamPubSubType PubSubType { get { throw null; } set { } }\n    }\n\n    public partial class StreamPullingAgentOptions\n    {\n        public static readonly int DEFAULT_BATCH_CONTAINER_BATCH_SIZE;\n        public static readonly System.TimeSpan DEFAULT_GET_QUEUE_MESSAGES_TIMER_PERIOD;\n        public static readonly System.TimeSpan DEFAULT_INIT_QUEUE_TIMEOUT;\n        public static readonly System.TimeSpan DEFAULT_MAX_EVENT_DELIVERY_TIME;\n        public static readonly System.TimeSpan DEFAULT_STREAM_INACTIVITY_PERIOD;\n        public int BatchContainerBatchSize { get { throw null; } set { } }\n\n        public System.TimeSpan GetQueueMsgsTimerPeriod { get { throw null; } set { } }\n\n        public System.TimeSpan InitQueueTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan MaxEventDeliveryTime { get { throw null; } set { } }\n\n        public System.TimeSpan StreamInactivityPeriod { get { throw null; } set { } }\n    }\n\n    public partial class StreamStatisticOptions\n    {\n        public static readonly System.TimeSpan DefaultStatisticMonitorWriteInterval;\n        public System.TimeSpan StatisticMonitorWriteInterval { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ClientBuilderStreamingExtensions\n    {\n        public static IClientBuilder AddMemoryStreams(this IClientBuilder builder, string name, System.Action<IClusterClientMemoryStreamConfigurator> configure = null) { throw null; }\n\n        public static IClientBuilder AddMemoryStreams<TSerializer>(this IClientBuilder builder, string name, System.Action<IClusterClientMemoryStreamConfigurator> configure = null)\n            where TSerializer : class, Providers.IMemoryMessageBodySerializer { throw null; }\n\n        public static IClientBuilder AddPersistentStreams(this IClientBuilder builder, string name, System.Func<System.IServiceProvider, string, Streams.IQueueAdapterFactory> adapterFactory, System.Action<IClusterClientPersistentStreamConfigurator> configureStream) { throw null; }\n\n        public static IClientBuilder AddStreaming(this IClientBuilder builder) { throw null; }\n    }\n\n    public partial class ClusterClientMemoryStreamConfigurator<TSerializer> : ClusterClientPersistentStreamConfigurator, IClusterClientMemoryStreamConfigurator, IMemoryStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator where TSerializer : class, Providers.IMemoryMessageBodySerializer\n    {\n        public ClusterClientMemoryStreamConfigurator(string name, IClientBuilder builder) : base(default!, default!, default!) { }\n    }\n\n    public partial class ClusterClientPersistentStreamConfigurator : NamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n        public ClusterClientPersistentStreamConfigurator(string name, IClientBuilder clientBuilder, System.Func<System.IServiceProvider, string, Streams.IQueueAdapterFactory> adapterFactory) : base(default!, default!) { }\n    }\n\n    public static partial class ClusterClientPersistentStreamConfiguratorExtensions\n    {\n        public static void ConfigureLifecycle(this IClusterClientPersistentStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StreamLifecycleOptions>> configureOptions) { }\n    }\n\n    public partial interface IClusterClientMemoryStreamConfigurator : IMemoryStreamConfigurator, INamedServiceConfigurator, IClusterClientPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public partial interface IClusterClientPersistentStreamConfigurator : IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n    }\n\n    public partial interface IMemoryStreamConfigurator : INamedServiceConfigurator\n    {\n    }\n\n    public partial interface IPersistentStreamConfigurator : INamedServiceConfigurator\n    {\n    }\n\n    public partial interface ISiloMemoryStreamConfigurator : IMemoryStreamConfigurator, INamedServiceConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator\n    {\n    }\n\n    public partial interface ISiloPersistentStreamConfigurator : IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n    }\n\n    public partial interface ISiloRecoverableStreamConfigurator : ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n    }\n\n    public static partial class MemoryStreamConfiguratorExtensions\n    {\n        public static void ConfigurePartitioning(this IMemoryStreamConfigurator configurator, int numOfQueues = 8) { }\n    }\n\n    public static partial class PersistentStreamConfiguratorExtensions\n    {\n        public static void ConfigureStreamPubSub(this IPersistentStreamConfigurator configurator, Streams.StreamPubSubType pubsubType = Streams.StreamPubSubType.ExplicitGrainBasedAndImplicit) { }\n    }\n\n    public partial class PersistentStreamStorageConfigurationValidator : IConfigurationValidator\n    {\n        internal PersistentStreamStorageConfigurationValidator() { }\n\n        public static IConfigurationValidator Create(System.IServiceProvider services, string name) { throw null; }\n\n        public void ValidateConfiguration() { }\n    }\n\n    public static partial class SiloBuilderMemoryStreamExtensions\n    {\n        public static ISiloBuilder AddMemoryStreams(this ISiloBuilder builder, string name, System.Action<ISiloMemoryStreamConfigurator> configure = null) { throw null; }\n\n        public static ISiloBuilder AddMemoryStreams<TSerializer>(this ISiloBuilder builder, string name, System.Action<ISiloMemoryStreamConfigurator> configure = null)\n            where TSerializer : class, Providers.IMemoryMessageBodySerializer { throw null; }\n    }\n\n    public static partial class SiloBuilderStreamingExtensions\n    {\n        public static ISiloBuilder AddPersistentStreams(this ISiloBuilder builder, string name, System.Func<System.IServiceProvider, string, Streams.IQueueAdapterFactory> adapterFactory, System.Action<ISiloPersistentStreamConfigurator> configureStream) { throw null; }\n\n        public static IClientBuilder AddStreamFilter<T>(this IClientBuilder builder, string name)\n            where T : class, Streams.Filtering.IStreamFilter { throw null; }\n\n        public static ISiloBuilder AddStreamFilter<T>(this ISiloBuilder builder, string name)\n            where T : class, Streams.Filtering.IStreamFilter { throw null; }\n\n        public static ISiloBuilder AddStreaming(this ISiloBuilder builder) { throw null; }\n    }\n\n    public partial class SiloMemoryStreamConfigurator<TSerializer> : SiloRecoverableStreamConfigurator, ISiloMemoryStreamConfigurator, IMemoryStreamConfigurator, INamedServiceConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator where TSerializer : class, Providers.IMemoryMessageBodySerializer\n    {\n        public SiloMemoryStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureServicesDelegate) : base(default!, default!, default!) { }\n    }\n\n    public partial class SiloPersistentStreamConfigurator : NamedServiceConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n        public SiloPersistentStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureDelegate, System.Func<System.IServiceProvider, string, Streams.IQueueAdapterFactory> adapterFactory) : base(default!, default!) { }\n    }\n\n    public static partial class SiloPersistentStreamConfiguratorExtension\n    {\n        public static void UseConsistentRingQueueBalancer(this ISiloPersistentStreamConfigurator configurator) { }\n\n        public static void UseDynamicClusterConfigDeploymentBalancer(this ISiloPersistentStreamConfigurator configurator, System.TimeSpan? siloMaturityPeriod = null) { }\n\n        public static void UseLeaseBasedQueueBalancer(this ISiloPersistentStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.LeaseBasedQueueBalancerOptions>> configureOptions = null) { }\n\n        public static void UseStaticClusterConfigDeploymentBalancer(this ISiloPersistentStreamConfigurator configurator, System.TimeSpan? siloMaturityPeriod = null) { }\n    }\n\n    public static partial class SiloPersistentStreamConfiguratorExtensions\n    {\n        public static void ConfigureBackoffProvider(this ISiloPersistentStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Runtime.Providers.IMessageDeliveryBackoffProvider> factory) { }\n\n        public static void ConfigureBackoffProvider(this ISiloPersistentStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Runtime.Providers.IQueueReaderBackoffProvider> factory) { }\n\n        public static void ConfigureLifecycle(this ISiloPersistentStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StreamLifecycleOptions>> configureOptions) { }\n\n        public static void ConfigurePartitionBalancing(this ISiloPersistentStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streams.IStreamQueueBalancer> factory) { }\n\n        public static void ConfigurePartitionBalancing<TOptions>(this ISiloPersistentStreamConfigurator configurator, System.Func<System.IServiceProvider, string, Streams.IStreamQueueBalancer> factory, System.Action<Microsoft.Extensions.Options.OptionsBuilder<TOptions>> configureOptions)\n            where TOptions : class, new() { }\n\n        public static void ConfigurePullingAgent(this ISiloPersistentStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StreamPullingAgentOptions>> configureOptions = null) { }\n    }\n\n    public partial class SiloRecoverableStreamConfigurator : SiloPersistentStreamConfigurator, ISiloRecoverableStreamConfigurator, ISiloPersistentStreamConfigurator, IPersistentStreamConfigurator, INamedServiceConfigurator\n    {\n        public SiloRecoverableStreamConfigurator(string name, System.Action<System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection>> configureDelegate, System.Func<System.IServiceProvider, string, Streams.IQueueAdapterFactory> adapterFactory) : base(default!, default!, default!) { }\n    }\n\n    public static partial class SiloRecoverableStreamConfiguratorExtensions\n    {\n        public static void ConfigureCacheEviction(this ISiloRecoverableStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StreamCacheEvictionOptions>> configureOptions) { }\n\n        public static void ConfigureStatistics(this ISiloRecoverableStreamConfigurator configurator, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.StreamStatisticOptions>> configureOptions) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class SimpleGeneratorOptions : Providers.Streams.Generator.IStreamGeneratorConfig\n    {\n        public const int DEFAULT_EVENTS_IN_STREAM = 100;\n        [Id(1)]\n        public int EventsInStream { get { throw null; } set { } }\n\n        public System.Type StreamGeneratorType { get { throw null; } }\n\n        [Id(0)]\n        public string StreamNamespace { get { throw null; } set { } }\n    }\n\n    public partial class StaticClusterDeploymentOptions : Streams.IDeploymentConfiguration\n    {\n        public System.Collections.Generic.IList<string> SiloNames { get { throw null; } set { } }\n\n        System.Collections.Generic.IList<string> Streams.IDeploymentConfiguration.GetAllSiloNames() { throw null; }\n    }\n\n    public static partial class StreamingServiceCollectionExtensions\n    {\n        public static void AddClientStreaming(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { }\n\n        public static void AddSiloStreaming(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddStreamFilter<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name)\n            where T : class, Streams.Filtering.IStreamFilter { throw null; }\n    }\n}\n\nnamespace Orleans.Providers\n{\n    [GenerateSerializer]\n    [Immutable]\n    [SerializationCallbacks(typeof(Runtime.OnDeserializedCallbacks))]\n    public sealed partial class DefaultMemoryMessageBodySerializer : IMemoryMessageBodySerializer, Serialization.IOnDeserialized\n    {\n        public DefaultMemoryMessageBodySerializer(Serialization.Serializer<MemoryMessageBody> serializer) { }\n\n        public MemoryMessageBody Deserialize(System.ArraySegment<byte> bodyBytes) { throw null; }\n\n        void Serialization.IOnDeserialized.OnDeserialized(Serialization.DeserializationContext context) { }\n\n        public System.ArraySegment<byte> Serialize(MemoryMessageBody body) { throw null; }\n    }\n\n    public partial interface IMemoryMessageBodySerializer\n    {\n        MemoryMessageBody Deserialize(System.ArraySegment<byte> bodyBytes);\n        System.ArraySegment<byte> Serialize(MemoryMessageBody body);\n    }\n\n    public partial interface IMemoryStreamQueueGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task<System.Collections.Generic.List<MemoryMessageData>> Dequeue(int maxCount);\n        System.Threading.Tasks.Task Enqueue(MemoryMessageData data);\n    }\n\n    public partial class MemoryAdapterFactory<TSerializer> : Orleans.Streams.IQueueAdapterFactory, Orleans.Streams.IQueueAdapter, Orleans.Streams.IQueueAdapterCache where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        protected System.Func<Streams.Common.BlockPoolMonitorDimensions, Streams.Common.IBlockPoolMonitor> BlockPoolMonitorFactory;\n        protected System.Func<Streams.Common.CacheMonitorDimensions, Streams.Common.ICacheMonitor> CacheMonitorFactory;\n        protected System.Func<Streams.Common.ReceiverMonitorDimensions, Streams.Common.IQueueAdapterReceiverMonitor> ReceiverMonitorFactory;\n        public MemoryAdapterFactory(string providerName, Configuration.StreamCacheEvictionOptions cacheOptions, Configuration.StreamStatisticOptions statisticOptions, Configuration.HashRingStreamQueueMapperOptions queueMapperOptions, System.IServiceProvider serviceProvider, IGrainFactory grainFactory, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public Orleans.Streams.StreamProviderDirection Direction { get { throw null; } }\n\n        public bool IsRewindable { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        protected System.Func<string, System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler>> StreamFailureHandlerFactory { get { throw null; } set { } }\n\n        public static MemoryAdapterFactory<TSerializer> Create(System.IServiceProvider services, string name) { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IQueueAdapter> CreateAdapter() { throw null; }\n\n        public Orleans.Streams.IQueueCache CreateQueueCache(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public Orleans.Streams.IQueueAdapterReceiver CreateReceiver(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler> GetDeliveryFailureHandler(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public Orleans.Streams.IQueueAdapterCache GetQueueAdapterCache() { throw null; }\n\n        public Orleans.Streams.IStreamQueueMapper GetStreamQueueMapper() { throw null; }\n\n        public void Init() { }\n\n        public System.Threading.Tasks.Task QueueMessageBatchAsync<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Orleans.Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class MemoryMessageBody\n    {\n        public MemoryMessageBody(System.Collections.Generic.IEnumerable<object> events, System.Collections.Generic.Dictionary<string, object> requestContext) { }\n\n        [Id(0)]\n        public System.Collections.Generic.List<object> Events { get { throw null; } }\n\n        [Id(1)]\n        public System.Collections.Generic.Dictionary<string, object> RequestContext { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    public partial struct MemoryMessageData\n    {\n        [Id(2)]\n        public System.DateTime DequeueTimeUtc;\n        [Id(3)]\n        public System.DateTime EnqueueTimeUtc;\n        [Id(4)]\n        public System.ArraySegment<byte> Payload;\n        [Id(1)]\n        public long SequenceNumber;\n        [Id(0)]\n        public Runtime.StreamId StreamId;\n    }\n\n    public partial class MemoryPooledCache<TSerializer> : Orleans.Streams.IQueueCache, Orleans.Streams.IQueueFlowController, Streams.Common.ICacheDataAdapter where TSerializer : class, IMemoryMessageBodySerializer\n    {\n        public MemoryPooledCache(Streams.Common.IObjectPool<Streams.Common.FixedSizeBuffer> bufferPool, Streams.Common.TimePurgePredicate purgePredicate, Microsoft.Extensions.Logging.ILogger logger, TSerializer serializer, Streams.Common.ICacheMonitor cacheMonitor, System.TimeSpan? monitorWriteInterval, System.TimeSpan? purgeMetadataInterval) { }\n\n        public void AddToCache(System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> messages) { }\n\n        public Orleans.Streams.IBatchContainer GetBatchContainer(ref Streams.Common.CachedMessage cachedMessage) { throw null; }\n\n        public Orleans.Streams.IQueueCacheCursor GetCacheCursor(Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken token) { throw null; }\n\n        public int GetMaxAddCount() { throw null; }\n\n        public Orleans.Streams.StreamSequenceToken GetSequenceToken(ref Streams.Common.CachedMessage cachedMessage) { throw null; }\n\n        public bool IsUnderPressure() { throw null; }\n\n        public bool TryPurgeFromCache(out System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> purgedItems) { throw null; }\n    }\n\n    public partial class MemoryStreamQueueGrain : Grain, IMemoryStreamQueueGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable, Runtime.IGrainMigrationParticipant\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<MemoryMessageData>> Dequeue(int maxCount) { throw null; }\n\n        public System.Threading.Tasks.Task Enqueue(MemoryMessageData data) { throw null; }\n\n        void Runtime.IGrainMigrationParticipant.OnDehydrate(Runtime.IDehydrationContext dehydrationContext) { }\n\n        void Runtime.IGrainMigrationParticipant.OnRehydrate(Runtime.IRehydrationContext rehydrationContext) { }\n    }\n}\n\nnamespace Orleans.Providers.Streams.Common\n{\n    public partial class BlockPoolMonitorDimensions\n    {\n        public BlockPoolMonitorDimensions(string blockPoolId) { }\n\n        public string BlockPoolId { get { throw null; } set { } }\n    }\n\n    public partial struct CachedMessage\n    {\n        public System.DateTime DequeueTimeUtc;\n        public System.DateTime EnqueueTimeUtc;\n        public int EventIndex;\n        public System.ArraySegment<byte> Segment;\n        public long SequenceNumber;\n        public Runtime.StreamId StreamId;\n    }\n\n    public partial class CachedMessageBlock : PooledResource<CachedMessageBlock>\n    {\n        public CachedMessageBlock(int blockSize = 16384) { }\n\n        public bool HasCapacity { get { throw null; } }\n\n        public bool IsEmpty { get { throw null; } }\n\n        public CachedMessage this[int index] { get { throw null; } }\n\n        public int ItemCount { get { throw null; } }\n\n        public CachedMessage NewestMessage { get { throw null; } }\n\n        public int NewestMessageIndex { get { throw null; } }\n\n        public System.Collections.Generic.LinkedListNode<CachedMessageBlock> Node { get { throw null; } }\n\n        public CachedMessage OldestMessage { get { throw null; } }\n\n        public int OldestMessageIndex { get { throw null; } }\n\n        public void Add(CachedMessage message) { }\n\n        public int GetIndexOfFirstMessageLessThanOrEqualTo(Orleans.Streams.StreamSequenceToken token) { throw null; }\n\n        public Orleans.Streams.StreamSequenceToken GetNewestSequenceToken(ICacheDataAdapter dataAdapter) { throw null; }\n\n        public Orleans.Streams.StreamSequenceToken GetOldestSequenceToken(ICacheDataAdapter dataAdapter) { throw null; }\n\n        public Orleans.Streams.StreamSequenceToken GetSequenceToken(int index, ICacheDataAdapter dataAdapter) { throw null; }\n\n        public override void OnResetState() { }\n\n        public bool Remove() { throw null; }\n\n        public bool TryFindFirstMessage(Runtime.StreamId streamId, ICacheDataAdapter dataAdapter, out int index) { throw null; }\n\n        public bool TryFindNextMessage(int start, Runtime.StreamId streamId, ICacheDataAdapter dataAdapter, out int index) { throw null; }\n    }\n\n    public static partial class CachedMessageExtensions\n    {\n        public static int Compare(this ref CachedMessage cachedMessage, Orleans.Streams.StreamSequenceToken token) { throw null; }\n\n        public static bool CompareStreamId(this ref CachedMessage cachedMessage, Runtime.StreamId streamId) { throw null; }\n    }\n\n    public partial class CacheMonitorDimensions : ReceiverMonitorDimensions\n    {\n        public CacheMonitorDimensions(string queueId, string blockPoolId) { }\n\n        public string BlockPoolId { get { throw null; } set { } }\n    }\n\n    public partial class ChronologicalEvictionStrategy : IEvictionStrategy\n    {\n        protected readonly System.Collections.Generic.Queue<FixedSizeBuffer> inUseBuffers;\n        public ChronologicalEvictionStrategy(Microsoft.Extensions.Logging.ILogger logger, TimePurgePredicate timePurage, ICacheMonitor cacheMonitor, System.TimeSpan? monitorWriteInterval) { }\n\n        public System.Action<CachedMessage?, CachedMessage?> OnPurged { get { throw null; } set { } }\n\n        public IPurgeObservable PurgeObservable { set { } }\n\n        public void OnBlockAllocated(FixedSizeBuffer newBlock) { }\n\n        public void PerformPurge(System.DateTime nowUtc) { }\n\n        protected virtual bool ShouldPurge(ref CachedMessage cachedMessage, ref CachedMessage newestCachedMessage, System.DateTime nowUtc) { throw null; }\n    }\n\n    public partial class DefaultBlockPoolMonitor : IBlockPoolMonitor\n    {\n        protected System.Collections.Generic.KeyValuePair<string, object>[] _dimensions;\n        public DefaultBlockPoolMonitor(BlockPoolMonitorDimensions dimensions) { }\n\n        protected DefaultBlockPoolMonitor(System.Collections.Generic.KeyValuePair<string, object>[] dimensions) { }\n\n        public void Report(long totalMemoryInByte, long availableMemoryInByte, long claimedMemoryInByte) { }\n\n        public void TrackMemoryAllocated(long allocatedMemoryInByte) { }\n\n        public void TrackMemoryReleased(long releasedMemoryInByte) { }\n    }\n\n    public partial class DefaultCacheMonitor : ICacheMonitor\n    {\n        public DefaultCacheMonitor(CacheMonitorDimensions dimensions) { }\n\n        protected DefaultCacheMonitor(System.Collections.Generic.KeyValuePair<string, object>[] dimensions) { }\n\n        public void ReportCacheSize(long totalCacheSizeInByte) { }\n\n        public void ReportMessageStatistics(System.DateTime? oldestMessageEnqueueTimeUtc, System.DateTime? oldestMessageDequeueTimeUtc, System.DateTime? newestMessageEnqueueTimeUtc, long totalMessageCount) { }\n\n        public void TrackCachePressureMonitorStatusChange(string pressureMonitorType, bool underPressure, double? cachePressureContributionCount, double? currentPressure, double? flowControlThreshold) { }\n\n        public void TrackMemoryAllocated(int memoryInByte) { }\n\n        public void TrackMemoryReleased(int memoryInByte) { }\n\n        public void TrackMessagesAdded(long messageAdded) { }\n\n        public void TrackMessagesPurged(long messagePurged) { }\n    }\n\n    public partial class DefaultQueueAdapterReceiverMonitor : IQueueAdapterReceiverMonitor\n    {\n        public DefaultQueueAdapterReceiverMonitor(ReceiverMonitorDimensions dimensions) { }\n\n        protected DefaultQueueAdapterReceiverMonitor(System.Collections.Generic.KeyValuePair<string, object>[] dimensions) { }\n\n        public void TrackInitialization(bool success, System.TimeSpan callTime, System.Exception exception) { }\n\n        public void TrackMessagesReceived(long count, System.DateTime? oldestMessageEnqueueTimeUtc, System.DateTime? newestMessageEnqueueTimeUtc) { }\n\n        public void TrackRead(bool success, System.TimeSpan callTime, System.Exception exception) { }\n\n        public void TrackShutdown(bool success, System.TimeSpan callTime, System.Exception exception) { }\n    }\n\n    [GenerateSerializer]\n    public partial class EventSequenceToken : Orleans.Streams.StreamSequenceToken\n    {\n        [Newtonsoft.Json.JsonConstructor]\n        public EventSequenceToken() { }\n\n        public EventSequenceToken(long sequenceNumber, int eventIndex) { }\n\n        public EventSequenceToken(long sequenceNumber) { }\n\n        [Id(1)]\n        [Newtonsoft.Json.JsonProperty]\n        public override int EventIndex { get { throw null; } protected set { } }\n\n        [Id(0)]\n        [Newtonsoft.Json.JsonProperty]\n        public override long SequenceNumber { get { throw null; } protected set { } }\n\n        public override int CompareTo(Orleans.Streams.StreamSequenceToken other) { throw null; }\n\n        public EventSequenceToken CreateSequenceTokenForEvent(int eventInd) { throw null; }\n\n        public override bool Equals(Orleans.Streams.StreamSequenceToken other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class EventSequenceTokenV2 : Orleans.Streams.StreamSequenceToken\n    {\n        public EventSequenceTokenV2() { }\n\n        public EventSequenceTokenV2(long seqNumber, int eventInd) { }\n\n        public EventSequenceTokenV2(long seqNumber) { }\n\n        [Id(1)]\n        [Newtonsoft.Json.JsonProperty]\n        public override int EventIndex { get { throw null; } protected set { } }\n\n        [Id(0)]\n        [Newtonsoft.Json.JsonProperty]\n        public override long SequenceNumber { get { throw null; } protected set { } }\n\n        public override int CompareTo(Orleans.Streams.StreamSequenceToken other) { throw null; }\n\n        public EventSequenceTokenV2 CreateSequenceTokenForEvent(int eventInd) { throw null; }\n\n        public override bool Equals(Orleans.Streams.StreamSequenceToken other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class FixedSizeBuffer : PooledResource<FixedSizeBuffer>\n    {\n        public readonly int SizeInByte;\n        public FixedSizeBuffer(int blockSizeInByte) { }\n\n        public object Id { get { throw null; } }\n\n        public override void OnResetState() { }\n\n        public bool TryGetSegment(int size, out System.ArraySegment<byte> value) { throw null; }\n    }\n\n    public partial interface IBlockPoolMonitor\n    {\n        void Report(long totalSizeInByte, long availableMemoryInByte, long claimedMemoryInByte);\n        void TrackMemoryAllocated(long allocatedMemoryInBytes);\n        void TrackMemoryReleased(long releasedMemoryInBytes);\n    }\n\n    public partial interface ICacheDataAdapter\n    {\n        Orleans.Streams.IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage);\n        Orleans.Streams.StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage);\n    }\n\n    public partial interface ICacheMonitor\n    {\n        void ReportCacheSize(long totalCacheSizeInBytes);\n        void ReportMessageStatistics(System.DateTime? oldestMessageEnqueueTimeUtc, System.DateTime? oldestMessageDequeueTimeUtc, System.DateTime? newestMessageEnqueueTimeUtc, long totalMessageCount);\n        void TrackCachePressureMonitorStatusChange(string pressureMonitorType, bool underPressure, double? cachePressureContributionCount, double? currentPressure, double? flowControlThreshold);\n        void TrackMemoryAllocated(int memoryInBytes);\n        void TrackMemoryReleased(int memoryInBytes);\n        void TrackMessagesAdded(long messagesAdded);\n        void TrackMessagesPurged(long messagesPurged);\n    }\n\n    public partial interface IEvictionStrategy\n    {\n        System.Action<CachedMessage?, CachedMessage?> OnPurged { get; set; }\n\n        IPurgeObservable PurgeObservable { set; }\n\n        void OnBlockAllocated(FixedSizeBuffer newBlock);\n        void PerformPurge(System.DateTime utcNow);\n    }\n\n    public partial interface IObjectPoolMonitor\n    {\n        void Report(long totalObjects, long availableObjects, long claimedObjects);\n        void TrackObjectAllocated();\n        void TrackObjectReleased();\n    }\n\n    public partial interface IObjectPool<T>\n        where T : System.IDisposable\n    {\n        T Allocate();\n        void Free(T resource);\n    }\n\n    public partial interface IPurgeObservable\n    {\n        bool IsEmpty { get; }\n\n        int ItemCount { get; }\n\n        CachedMessage? Newest { get; }\n\n        CachedMessage? Oldest { get; }\n\n        void RemoveOldestMessage();\n    }\n\n    public partial interface IQueueAdapterReceiverMonitor\n    {\n        void TrackInitialization(bool success, System.TimeSpan callTime, System.Exception exception);\n        void TrackMessagesReceived(long count, System.DateTime? oldestMessageEnqueueTimeUtc, System.DateTime? newestMessageEnqueueTimeUtc);\n        void TrackRead(bool success, System.TimeSpan callTime, System.Exception exception);\n        void TrackShutdown(bool success, System.TimeSpan callTime, System.Exception exception);\n    }\n\n    public partial class ObjectPoolMonitorBridge : IObjectPoolMonitor\n    {\n        public ObjectPoolMonitorBridge(IBlockPoolMonitor blockPoolMonitor, int blockSizeInBytes) { }\n\n        public void Report(long totalObjects, long availableObjects, long claimedObjects) { }\n\n        public void TrackObjectAllocated() { }\n\n        public void TrackObjectReleased() { }\n    }\n\n    public partial class ObjectPool<T> : IObjectPool<T> where T : PooledResource<T>\n    {\n        public ObjectPool(System.Func<T> factoryFunc, IObjectPoolMonitor monitor = null, System.TimeSpan? monitorWriteInterval = null) { }\n\n        public virtual T Allocate() { throw null; }\n\n        public virtual void Free(T resource) { }\n    }\n\n    public partial class PersistentStreamProvider : Orleans.Streams.IStreamProvider, IControllable, Orleans.Streams.Core.IStreamSubscriptionManagerRetriever, ILifecycleParticipant<ILifecycleObservable>\n    {\n        public PersistentStreamProvider(string name, Configuration.StreamPubSubOptions pubsubOptions, Configuration.StreamLifecycleOptions lifeCycleOptions, IProviderRuntime runtime, Serialization.DeepCopier deepCopier, Microsoft.Extensions.Logging.ILogger<PersistentStreamProvider> logger) { }\n\n        public bool IsRewindable { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        public static Orleans.Streams.IStreamProvider Create(System.IServiceProvider services, string name) { throw null; }\n\n        public System.Threading.Tasks.Task<object> ExecuteCommand(int command, object arg) { throw null; }\n\n        public Orleans.Streams.IAsyncStream<T> GetStream<T>(Runtime.StreamId streamId) { throw null; }\n\n        public Orleans.Streams.Core.IStreamSubscriptionManager GetStreamSubscriptionManager() { throw null; }\n\n        public void Participate(ILifecycleObservable lifecycle) { }\n\n        public static ILifecycleParticipant<TLifecycle> ParticipateIn<TLifecycle>(System.IServiceProvider serviceProvider, string name)\n            where TLifecycle : ILifecycleObservable { throw null; }\n    }\n\n    public enum PersistentStreamProviderCommand\n    {\n        None = 0,\n        StartAgents = 1,\n        StopAgents = 2,\n        GetAgentsState = 3,\n        GetNumberRunningAgents = 4,\n        AdapterCommandStartRange = 10000,\n        AdapterCommandEndRange = 19999,\n        AdapterFactoryCommandStartRange = 20000,\n        AdapterFactoryCommandEndRange = 29999\n    }\n\n    public partial class PooledQueueCache : IPurgeObservable\n    {\n        public PooledQueueCache(ICacheDataAdapter cacheDataAdapter, Microsoft.Extensions.Logging.ILogger logger, ICacheMonitor cacheMonitor, System.TimeSpan? cacheMonitorWriteInterval, System.TimeSpan? purgeMetadataInterval = null) { }\n\n        public bool IsEmpty { get { throw null; } }\n\n        public int ItemCount { get { throw null; } }\n\n        public CachedMessage? Newest { get { throw null; } }\n\n        public CachedMessage? Oldest { get { throw null; } }\n\n        public void Add(System.Collections.Generic.List<CachedMessage> messages, System.DateTime dequeueTime) { }\n\n        public object GetCursor(Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken sequenceToken) { throw null; }\n\n        public void RemoveOldestMessage() { }\n\n        public bool TryGetNextMessage(object cursorObj, out Orleans.Streams.IBatchContainer message) { throw null; }\n    }\n\n    public abstract partial class PooledResource<T> : System.IDisposable where T : PooledResource<T>, System.IDisposable\n    {\n        public IObjectPool<T> Pool { set { } }\n\n        public void Dispose() { }\n\n        public virtual void OnResetState() { }\n\n        public virtual void SignalPurge() { }\n    }\n\n    public partial class ReceiverMonitorDimensions\n    {\n        public ReceiverMonitorDimensions() { }\n\n        public ReceiverMonitorDimensions(string queueId) { }\n\n        public string QueueId { get { throw null; } set { } }\n    }\n\n    public static partial class SegmentBuilder\n    {\n        public static void Append(System.ArraySegment<byte> segment, ref int writerOffset, System.ReadOnlySpan<byte> bytes) { }\n\n        public static void Append(System.ArraySegment<byte> segment, ref int writerOffset, string str) { }\n\n        public static int CalculateAppendSize(System.ReadOnlySpan<byte> memory) { throw null; }\n\n        public static int CalculateAppendSize(string str) { throw null; }\n\n        public static System.ArraySegment<byte> ReadNextBytes(System.ArraySegment<byte> segment, ref int readerOffset) { throw null; }\n\n        public static string ReadNextString(System.ArraySegment<byte> segment, ref int readerOffset) { throw null; }\n    }\n\n    public partial class SimpleQueueAdapterCache : Orleans.Streams.IQueueAdapterCache\n    {\n        public const string CacheSizePropertyName = \"CacheSize\";\n        public SimpleQueueAdapterCache(Configuration.SimpleQueueCacheOptions options, string providerName, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public Orleans.Streams.IQueueCache CreateQueueCache(Orleans.Streams.QueueId queueId) { throw null; }\n    }\n\n    public partial class SimpleQueueCache : Orleans.Streams.IQueueCache, Orleans.Streams.IQueueFlowController\n    {\n        public SimpleQueueCache(int cacheSize, Microsoft.Extensions.Logging.ILogger logger) { }\n\n        public int Size { get { throw null; } }\n\n        public virtual void AddToCache(System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> msgs) { }\n\n        public virtual Orleans.Streams.IQueueCacheCursor GetCacheCursor(Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken token) { throw null; }\n\n        public int GetMaxAddCount() { throw null; }\n\n        public virtual bool IsUnderPressure() { throw null; }\n\n        public virtual bool TryPurgeFromCache(out System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> purgedItems) { throw null; }\n    }\n\n    public partial class SimpleQueueCacheCursor : Orleans.Streams.IQueueCacheCursor, System.IDisposable\n    {\n        public SimpleQueueCacheCursor(SimpleQueueCache cache, Runtime.StreamId streamId, Microsoft.Extensions.Logging.ILogger logger) { }\n\n        public void Dispose() { }\n\n        protected virtual void Dispose(bool disposing) { }\n\n        public virtual Orleans.Streams.IBatchContainer GetCurrent(out System.Exception exception) { throw null; }\n\n        public virtual bool MoveNext() { throw null; }\n\n        public void RecordDeliveryFailure() { }\n\n        public virtual void Refresh(Orleans.Streams.StreamSequenceToken sequenceToken) { }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class TimePurgePredicate\n    {\n        public TimePurgePredicate(System.TimeSpan minTimeInCache, System.TimeSpan maxRelativeMessageAge) { }\n\n        public virtual bool ShouldPurgeFromTime(System.TimeSpan timeInCache, System.TimeSpan relativeAge) { throw null; }\n    }\n}\n\nnamespace Orleans.Providers.Streams.Generator\n{\n    [GenerateSerializer]\n    public sealed partial class GeneratedBatchContainer : Orleans.Streams.IBatchContainer\n    {\n        public GeneratedBatchContainer(Runtime.StreamId streamId, object payload, Common.EventSequenceTokenV2 token) { }\n\n        [Id(2)]\n        public System.DateTime EnqueueTimeUtc { get { throw null; } }\n\n        [Id(3)]\n        public object Payload { get { throw null; } }\n\n        [Id(1)]\n        public Common.EventSequenceTokenV2 RealToken { get { throw null; } }\n\n        public Orleans.Streams.StreamSequenceToken SequenceToken { get { throw null; } }\n\n        [Id(0)]\n        public Runtime.StreamId StreamId { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<System.Tuple<T, Orleans.Streams.StreamSequenceToken>> GetEvents<T>() { throw null; }\n\n        public bool ImportRequestContext() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class GeneratedEvent\n    {\n        [Id(0)]\n        public GeneratedEventType EventType { get { throw null; } set { } }\n\n        [Id(1)]\n        public int[] Payload { get { throw null; } set { } }\n\n        public enum GeneratedEventType\n        {\n            Fill = 0,\n            Report = 1\n        }\n    }\n\n    public partial class GeneratorAdapterFactory : Orleans.Streams.IQueueAdapterFactory, Orleans.Streams.IQueueAdapter, Orleans.Streams.IQueueAdapterCache, IControllable\n    {\n        protected System.Func<Common.BlockPoolMonitorDimensions, Common.IBlockPoolMonitor> BlockPoolMonitorFactory;\n        protected System.Func<Common.CacheMonitorDimensions, Common.ICacheMonitor> CacheMonitorFactory;\n        protected System.Func<Common.ReceiverMonitorDimensions, Common.IQueueAdapterReceiverMonitor> ReceiverMonitorFactory;\n        public GeneratorAdapterFactory(string providerName, Configuration.HashRingStreamQueueMapperOptions queueMapperOptions, Configuration.StreamStatisticOptions statisticOptions, System.IServiceProvider serviceProvider, Serialization.Serializer serializer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public Orleans.Streams.StreamProviderDirection Direction { get { throw null; } }\n\n        public bool IsRewindable { get { throw null; } }\n\n        public string Name { get { throw null; } }\n\n        public static GeneratorAdapterFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IQueueAdapter> CreateAdapter() { throw null; }\n\n        public Orleans.Streams.IQueueCache CreateQueueCache(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public Orleans.Streams.IQueueAdapterReceiver CreateReceiver(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public System.Threading.Tasks.Task<object> ExecuteCommand(int command, object arg) { throw null; }\n\n        public System.Threading.Tasks.Task<Orleans.Streams.IStreamFailureHandler> GetDeliveryFailureHandler(Orleans.Streams.QueueId queueId) { throw null; }\n\n        public Orleans.Streams.IQueueAdapterCache GetQueueAdapterCache() { throw null; }\n\n        public Orleans.Streams.IStreamQueueMapper GetStreamQueueMapper() { throw null; }\n\n        public void Init() { }\n\n        public System.Threading.Tasks.Task QueueMessageBatchAsync<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, Orleans.Streams.StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    public partial class GeneratorPooledCache : Orleans.Streams.IQueueCache, Orleans.Streams.IQueueFlowController, Common.ICacheDataAdapter\n    {\n        public GeneratorPooledCache(Common.IObjectPool<Common.FixedSizeBuffer> bufferPool, Microsoft.Extensions.Logging.ILogger logger, Serialization.Serializer serializer, Common.ICacheMonitor cacheMonitor, System.TimeSpan? monitorWriteInterval) { }\n\n        public void AddToCache(System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> messages) { }\n\n        public Orleans.Streams.IBatchContainer GetBatchContainer(ref Common.CachedMessage cachedMessage) { throw null; }\n\n        public Orleans.Streams.IQueueCacheCursor GetCacheCursor(Runtime.StreamId streamId, Orleans.Streams.StreamSequenceToken token) { throw null; }\n\n        public int GetMaxAddCount() { throw null; }\n\n        public Orleans.Streams.StreamSequenceToken GetSequenceToken(ref Common.CachedMessage cachedMessage) { throw null; }\n\n        public bool IsUnderPressure() { throw null; }\n\n        public bool TryPurgeFromCache(out System.Collections.Generic.IList<Orleans.Streams.IBatchContainer> purgedItems) { throw null; }\n    }\n\n    public partial interface IStreamGenerator\n    {\n        void Configure(System.IServiceProvider serviceProvider, IStreamGeneratorConfig generatorConfig);\n        bool TryReadEvents(System.DateTime utcNow, int maxCount, out System.Collections.Generic.List<Orleans.Streams.IBatchContainer> events);\n    }\n\n    public partial interface IStreamGeneratorConfig\n    {\n        System.Type StreamGeneratorType { get; }\n    }\n\n    public enum StreamGeneratorCommand\n    {\n        Configure = 20000\n    }\n}\n\nnamespace Orleans.Runtime\n{\n    [Immutable]\n    [GenerateSerializer]\n    public readonly partial struct QualifiedStreamId : System.IEquatable<QualifiedStreamId>, System.IComparable<QualifiedStreamId>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable\n    {\n        [Id(1)]\n        public readonly string ProviderName;\n        [Id(0)]\n        public readonly StreamId StreamId;\n        public QualifiedStreamId(string providerName, StreamId streamId) { }\n\n        public readonly int CompareTo(QualifiedStreamId other) { throw null; }\n\n        public readonly bool Equals(QualifiedStreamId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public static bool operator ==(QualifiedStreamId s1, QualifiedStreamId s2) { throw null; }\n\n        public static implicit operator StreamId(QualifiedStreamId internalStreamId) { throw null; }\n\n        public static bool operator !=(QualifiedStreamId s1, QualifiedStreamId s2) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n\n    [Immutable]\n    [GenerateSerializer]\n    public readonly partial struct StreamId : System.IEquatable<StreamId>, System.IComparable<StreamId>, System.Runtime.Serialization.ISerializable, System.ISpanFormattable, System.IFormattable\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public System.ReadOnlyMemory<byte> FullKey { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> Key { get { throw null; } }\n\n        public System.ReadOnlyMemory<byte> Namespace { get { throw null; } }\n\n        public readonly int CompareTo(StreamId other) { throw null; }\n\n        public static StreamId Create(Streams.IStreamIdentity streamIdentity) { throw null; }\n\n        public static StreamId Create(System.ReadOnlySpan<byte> ns, System.ReadOnlySpan<byte> key) { throw null; }\n\n        public static StreamId Create(string ns, System.Guid key) { throw null; }\n\n        public static StreamId Create(string ns, long key) { throw null; }\n\n        public static StreamId Create(string ns, string key) { throw null; }\n\n        public readonly bool Equals(StreamId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly string GetKeyAsString() { throw null; }\n\n        public readonly string? GetNamespace() { throw null; }\n\n        public readonly void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public static bool operator ==(StreamId s1, StreamId s2) { throw null; }\n\n        public static bool operator !=(StreamId s1, StreamId s2) { throw null; }\n\n        public static StreamId Parse(System.ReadOnlySpan<byte> value) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n    }\n}\n\nnamespace Orleans.Runtime.Providers\n{\n    public partial interface IMessageDeliveryBackoffProvider : Orleans.Internal.IBackoffProvider\n    {\n    }\n\n    public partial interface IQueueReaderBackoffProvider : Orleans.Internal.IBackoffProvider\n    {\n    }\n}\n\nnamespace Orleans.Streams\n{\n    public partial class AggregatedQueueFlowController : System.Collections.Generic.List<IQueueFlowController>, IQueueFlowController\n    {\n        public AggregatedQueueFlowController(int defaultMaxAddCount) { }\n\n        public int GetMaxAddCount() { throw null; }\n    }\n\n    public static partial class AsyncBatchObservableExtensions\n    {\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncBatchObservable<T> obs, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync) { throw null; }\n    }\n\n    public static partial class AsyncObservableExtensions\n    {\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, StreamSequenceToken token) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, StreamSequenceToken token) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync<T>(this IAsyncObservable<T> obs, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class BatchContainerBatch : IBatchContainerBatch, IBatchContainer\n    {\n        public BatchContainerBatch(System.Collections.Generic.List<IBatchContainer> batchContainers) { }\n\n        [Id(2)]\n        public System.Collections.Generic.List<IBatchContainer> BatchContainers { get { throw null; } }\n\n        [Id(1)]\n        public StreamSequenceToken SequenceToken { get { throw null; } }\n\n        [Id(0)]\n        public Runtime.StreamId StreamId { get { throw null; } }\n\n        public System.Collections.Generic.IEnumerable<System.Tuple<T, StreamSequenceToken>> GetEvents<T>() { throw null; }\n\n        public bool ImportRequestContext() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class CacheFullException : Runtime.OrleansException\n    {\n        public CacheFullException() { }\n\n        public CacheFullException(string message, System.Exception inner) { }\n\n        public CacheFullException(string message) { }\n    }\n\n    public partial class ConstructorStreamNamespacePredicateProvider : IStreamNamespacePredicateProvider\n    {\n        public const string Prefix = \"ctor\";\n        public static string FormatPattern(System.Type predicateType, string constructorArgument) { throw null; }\n\n        public bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class DataNotAvailableException : Runtime.OrleansException\n    {\n        public DataNotAvailableException() { }\n\n        [System.Obsolete]\n        protected DataNotAvailableException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public DataNotAvailableException(string message, System.Exception inner) { }\n\n        public DataNotAvailableException(string message) { }\n    }\n\n    public sealed partial class DefaultStreamIdMapper : IStreamIdMapper\n    {\n        public const string Name = \"default\";\n        public Runtime.IdSpan GetGrainKeyId(Metadata.GrainBindings grainBindings, Runtime.StreamId streamId) { throw null; }\n    }\n\n    public partial class DefaultStreamNamespacePredicateProvider : IStreamNamespacePredicateProvider\n    {\n        public bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate) { throw null; }\n    }\n\n    public partial class DeploymentBasedQueueBalancer : QueueBalancerBase, IStreamQueueBalancer\n    {\n        public DeploymentBasedQueueBalancer(Runtime.ISiloStatusOracle siloStatusOracle, IDeploymentConfiguration deploymentConfig, Configuration.DeploymentBasedQueueBalancerOptions options, System.IServiceProvider services, Microsoft.Extensions.Logging.ILogger<DeploymentBasedQueueBalancer> logger) : base(default!, default!) { }\n\n        public static IStreamQueueBalancer Create(System.IServiceProvider services, string name, IDeploymentConfiguration deploymentConfiguration) { throw null; }\n\n        public override System.Collections.Generic.IEnumerable<QueueId> GetMyQueues() { throw null; }\n\n        public override System.Threading.Tasks.Task Initialize(IStreamQueueMapper queueMapper) { throw null; }\n\n        protected override void OnClusterMembershipChange(System.Collections.Generic.HashSet<Runtime.SiloAddress> activeSilos) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class FaultedSubscriptionException : Runtime.OrleansException\n    {\n        public FaultedSubscriptionException() { }\n\n        public FaultedSubscriptionException(string message, System.Exception innerException) { }\n\n        public FaultedSubscriptionException(string message) { }\n    }\n\n    public sealed partial class HashRingBasedPartitionedStreamQueueMapper : HashRingBasedStreamQueueMapper\n    {\n        public HashRingBasedPartitionedStreamQueueMapper(System.Collections.Generic.IReadOnlyList<string> partitionIds, string queueNamePrefix) : base(default!, default!) { }\n\n        public string QueueToPartition(QueueId queue) { throw null; }\n    }\n\n    public partial class HashRingBasedStreamQueueMapper : IConsistentRingStreamQueueMapper, IStreamQueueMapper\n    {\n        public HashRingBasedStreamQueueMapper(Configuration.HashRingStreamQueueMapperOptions options, string queueNamePrefix) { }\n\n        public System.Collections.Generic.IEnumerable<QueueId> GetAllQueues() { throw null; }\n\n        public QueueId GetQueueForStream(Runtime.StreamId streamId) { throw null; }\n\n        public System.Collections.Generic.IEnumerable<QueueId> GetQueuesForRange(Runtime.IRingRange range) { throw null; }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial interface IAsyncBatchObservable<T>\n    {\n        System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> observer, StreamSequenceToken? token);\n        System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncBatchObserver<T> observer);\n    }\n\n    public partial interface IAsyncBatchObserver<T>\n    {\n        System.Threading.Tasks.Task OnCompletedAsync();\n        System.Threading.Tasks.Task OnErrorAsync(System.Exception ex);\n        System.Threading.Tasks.Task OnNextAsync(System.Collections.Generic.IList<SequentialItem<T>> items);\n    }\n\n    public partial interface IAsyncBatchProducer<T> : IAsyncObserver<T>\n    {\n        System.Threading.Tasks.Task OnNextBatchAsync(System.Collections.Generic.IEnumerable<T> batch, StreamSequenceToken token = null);\n    }\n\n    public partial interface IAsyncObservable<T>\n    {\n        System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer, StreamSequenceToken? token, string? filterData = null);\n        System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> SubscribeAsync(IAsyncObserver<T> observer);\n    }\n\n    public partial interface IAsyncObserver<in T>\n    {\n        System.Threading.Tasks.Task OnCompletedAsync();\n        System.Threading.Tasks.Task OnErrorAsync(System.Exception ex);\n        System.Threading.Tasks.Task OnNextAsync(T item, StreamSequenceToken? token = null);\n    }\n\n    public partial interface IAsyncStream\n    {\n        bool IsRewindable { get; }\n\n        string ProviderName { get; }\n\n        Runtime.StreamId StreamId { get; }\n    }\n\n    public partial interface IAsyncStream<T> : IAsyncStream, System.IEquatable<IAsyncStream<T>>, System.IComparable<IAsyncStream<T>>, IAsyncObservable<T>, IAsyncBatchObservable<T>, IAsyncBatchProducer<T>, IAsyncObserver<T>\n    {\n        System.Threading.Tasks.Task<System.Collections.Generic.IList<StreamSubscriptionHandle<T>>> GetAllSubscriptionHandles();\n    }\n\n    public partial interface IBatchContainer\n    {\n        StreamSequenceToken SequenceToken { get; }\n\n        Runtime.StreamId StreamId { get; }\n\n        System.Collections.Generic.IEnumerable<System.Tuple<T, StreamSequenceToken>> GetEvents<T>();\n        bool ImportRequestContext();\n    }\n\n    public partial interface IBatchContainerBatch : IBatchContainer\n    {\n        System.Collections.Generic.List<IBatchContainer> BatchContainers { get; }\n    }\n\n    public partial interface IConsistentRingStreamQueueMapper : IStreamQueueMapper\n    {\n        System.Collections.Generic.IEnumerable<QueueId> GetQueuesForRange(Runtime.IRingRange range);\n    }\n\n    public partial interface IDeploymentConfiguration\n    {\n        System.Collections.Generic.IList<string> GetAllSiloNames();\n    }\n\n    public static partial class ImplicitConsumerGrainExtensions\n    {\n        public static StreamIdentity GetImplicitStreamIdentity(this IGrainWithGuidCompoundKey grain) { throw null; }\n    }\n\n    public partial interface IQueueAdapter\n    {\n        StreamProviderDirection Direction { get; }\n\n        bool IsRewindable { get; }\n\n        string Name { get; }\n\n        IQueueAdapterReceiver CreateReceiver(QueueId queueId);\n        System.Threading.Tasks.Task QueueMessageBatchAsync<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext);\n    }\n\n    public partial interface IQueueAdapterCache\n    {\n        IQueueCache CreateQueueCache(QueueId queueId);\n    }\n\n    public partial interface IQueueAdapterFactory\n    {\n        System.Threading.Tasks.Task<IQueueAdapter> CreateAdapter();\n        System.Threading.Tasks.Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId);\n        IQueueAdapterCache GetQueueAdapterCache();\n        IStreamQueueMapper GetStreamQueueMapper();\n    }\n\n    public partial interface IQueueAdapterReceiver\n    {\n        System.Threading.Tasks.Task<System.Collections.Generic.IList<IBatchContainer>> GetQueueMessagesAsync(int maxCount);\n        System.Threading.Tasks.Task Initialize(System.TimeSpan timeout);\n        System.Threading.Tasks.Task MessagesDeliveredAsync(System.Collections.Generic.IList<IBatchContainer> messages);\n        System.Threading.Tasks.Task Shutdown(System.TimeSpan timeout);\n    }\n\n    public partial interface IQueueCache : IQueueFlowController\n    {\n        void AddToCache(System.Collections.Generic.IList<IBatchContainer> messages);\n        IQueueCacheCursor GetCacheCursor(Runtime.StreamId streamId, StreamSequenceToken token);\n        bool IsUnderPressure();\n        bool TryPurgeFromCache(out System.Collections.Generic.IList<IBatchContainer> purgedItems);\n    }\n\n    public partial interface IQueueCacheCursor : System.IDisposable\n    {\n        IBatchContainer GetCurrent(out System.Exception exception);\n        bool MoveNext();\n        void RecordDeliveryFailure();\n        void Refresh(StreamSequenceToken token);\n    }\n\n    public partial interface IQueueDataAdapter<TQueueMessage>\n    {\n        TQueueMessage ToQueueMessage<T>(Runtime.StreamId streamId, System.Collections.Generic.IEnumerable<T> events, StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext);\n    }\n\n    public partial interface IQueueDataAdapter<TQueueMessage, TMessageBatch> : IQueueDataAdapter<TQueueMessage>\n    {\n        TMessageBatch FromQueueMessage(TQueueMessage queueMessage, long sequenceId);\n    }\n\n    public partial interface IQueueFlowController\n    {\n        int GetMaxAddCount();\n    }\n\n    public partial interface IStreamFailureHandler\n    {\n        bool ShouldFaultSubsriptionOnError { get; }\n\n        System.Threading.Tasks.Task OnDeliveryFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamIdentity, StreamSequenceToken sequenceToken);\n        System.Threading.Tasks.Task OnSubscriptionFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamIdentity, StreamSequenceToken sequenceToken);\n    }\n\n    public partial interface IStreamIdentity\n    {\n        System.Guid Guid { get; }\n\n        string Namespace { get; }\n    }\n\n    public partial interface IStreamIdMapper\n    {\n        Runtime.IdSpan GetGrainKeyId(Metadata.GrainBindings grainBindings, Runtime.StreamId streamId);\n    }\n\n    public partial interface IStreamNamespacePredicate\n    {\n        string PredicatePattern { get; }\n\n        bool IsMatch(string streamNamespace);\n    }\n\n    public partial interface IStreamNamespacePredicateProvider\n    {\n        bool TryGetPredicate(string predicatePattern, out IStreamNamespacePredicate predicate);\n    }\n\n    public partial interface IStreamProvider\n    {\n        bool IsRewindable { get; }\n\n        string Name { get; }\n\n        IAsyncStream<T> GetStream<T>(Runtime.StreamId streamId);\n    }\n\n    public partial interface IStreamPubSub\n    {\n        System.Threading.Tasks.Task<int> ConsumerCount(Runtime.QualifiedStreamId streamId);\n        Runtime.GuidId CreateSubscriptionId(Runtime.QualifiedStreamId streamId, Runtime.GrainId streamConsumer);\n        System.Threading.Tasks.Task<bool> FaultSubscription(Runtime.QualifiedStreamId streamId, Runtime.GuidId subscriptionId);\n        System.Threading.Tasks.Task<System.Collections.Generic.List<Core.StreamSubscription>> GetAllSubscriptions(Runtime.QualifiedStreamId streamId, Runtime.GrainId streamConsumer = default);\n        System.Threading.Tasks.Task<int> ProducerCount(Runtime.QualifiedStreamId streamId);\n        System.Threading.Tasks.Task RegisterConsumer(Runtime.GuidId subscriptionId, Runtime.QualifiedStreamId streamId, Runtime.GrainId streamConsumer, string filterData);\n        System.Threading.Tasks.Task<System.Collections.Generic.ISet<PubSubSubscriptionState>> RegisterProducer(Runtime.QualifiedStreamId streamId, Runtime.GrainId streamProducer);\n        System.Threading.Tasks.Task UnregisterConsumer(Runtime.GuidId subscriptionId, Runtime.QualifiedStreamId streamId);\n        System.Threading.Tasks.Task UnregisterProducer(Runtime.QualifiedStreamId streamId, Runtime.GrainId streamProducer);\n    }\n\n    public partial interface IStreamQueueBalanceListener\n    {\n        System.Threading.Tasks.Task QueueDistributionChangeNotification();\n    }\n\n    public partial interface IStreamQueueBalancer\n    {\n        System.Collections.Generic.IEnumerable<QueueId> GetMyQueues();\n        System.Threading.Tasks.Task Initialize(IStreamQueueMapper queueMapper);\n        System.Threading.Tasks.Task Shutdown();\n        bool SubscribeToQueueDistributionChangeEvents(IStreamQueueBalanceListener observer);\n        bool UnSubscribeFromQueueDistributionChangeEvents(IStreamQueueBalanceListener observer);\n    }\n\n    public partial interface IStreamQueueCheckpointerFactory\n    {\n        System.Threading.Tasks.Task<IStreamQueueCheckpointer<string>> Create(string partition);\n    }\n\n    public partial interface IStreamQueueCheckpointer<TCheckpoint>\n    {\n        bool CheckpointExists { get; }\n\n        System.Threading.Tasks.Task<TCheckpoint> Load();\n        void Update(TCheckpoint offset, System.DateTime utcNow);\n    }\n\n    public partial interface IStreamQueueMapper\n    {\n        System.Collections.Generic.IEnumerable<QueueId> GetAllQueues();\n        QueueId GetQueueForStream(Runtime.StreamId streamId);\n    }\n\n    public partial class LeaseBasedQueueBalancer : QueueBalancerBase, IStreamQueueBalancer\n    {\n        public LeaseBasedQueueBalancer(string name, Configuration.LeaseBasedQueueBalancerOptions options, LeaseProviders.ILeaseProvider leaseProvider, System.IServiceProvider services, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.TimeProvider timeProvider) : base(default!, default!) { }\n\n        public static IStreamQueueBalancer Create(System.IServiceProvider services, string name) { throw null; }\n\n        public override System.Collections.Generic.IEnumerable<QueueId> GetMyQueues() { throw null; }\n\n        public override System.Threading.Tasks.Task Initialize(IStreamQueueMapper queueMapper) { throw null; }\n\n        protected override void OnClusterMembershipChange(System.Collections.Generic.HashSet<Runtime.SiloAddress> activeSilos) { }\n\n        public override System.Threading.Tasks.Task Shutdown() { throw null; }\n    }\n\n    public partial class LoadShedQueueFlowController : IQueueFlowController\n    {\n        internal LoadShedQueueFlowController() { }\n\n        public static IQueueFlowController CreateAsPercentageOfCPU(int loadSheddingLimit, Configuration.LoadSheddingOptions options, Statistics.IEnvironmentStatisticsProvider environmentStatisticsProvider) { throw null; }\n\n        public static IQueueFlowController CreateAsPercentOfLoadSheddingLimit(Configuration.LoadSheddingOptions options, Statistics.IEnvironmentStatisticsProvider environmentStatisticsProvider, int percentOfSiloSheddingLimit = 95) { throw null; }\n\n        public int GetMaxAddCount() { throw null; }\n    }\n\n    public partial class NoOpStreamDeliveryFailureHandler : IStreamFailureHandler\n    {\n        public NoOpStreamDeliveryFailureHandler() { }\n\n        public NoOpStreamDeliveryFailureHandler(bool faultOnError) { }\n\n        public bool ShouldFaultSubsriptionOnError { get { throw null; } }\n\n        public System.Threading.Tasks.Task OnDeliveryFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamId, StreamSequenceToken sequenceToken) { throw null; }\n\n        public System.Threading.Tasks.Task OnSubscriptionFailure(Runtime.GuidId subscriptionId, string streamProviderName, Runtime.StreamId streamId, StreamSequenceToken sequenceToken) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class ProviderStartException : Runtime.OrleansException\n    {\n        public ProviderStartException() { }\n\n        public ProviderStartException(string message, System.Exception innerException) { }\n\n        public ProviderStartException(string message) { }\n    }\n\n    [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)]\n    [GenerateSerializer]\n    public sealed partial class PubSubSubscriptionState : System.IEquatable<PubSubSubscriptionState>\n    {\n        [Newtonsoft.Json.JsonProperty]\n        [Id(2)]\n        public Runtime.GrainId Consumer;\n        [Newtonsoft.Json.JsonProperty]\n        [Id(3)]\n        public string FilterData;\n        [Newtonsoft.Json.JsonProperty]\n        [Id(4)]\n        public SubscriptionStates state;\n        [Newtonsoft.Json.JsonProperty]\n        [Id(1)]\n        public Runtime.QualifiedStreamId Stream;\n        [Newtonsoft.Json.JsonProperty]\n        [Id(0)]\n        public Runtime.GuidId SubscriptionId;\n        public PubSubSubscriptionState(Runtime.GuidId subscriptionId, Runtime.QualifiedStreamId streamId, Runtime.GrainId streamConsumer) { }\n\n        [Newtonsoft.Json.JsonIgnore]\n        public bool IsFaulted { get { throw null; } }\n\n        public void AddFilter(string filterData) { }\n\n        public bool Equals(Runtime.GuidId subscriptionId) { throw null; }\n\n        public bool Equals(PubSubSubscriptionState other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public void Fault() { }\n\n        public override int GetHashCode() { throw null; }\n\n        public static bool operator ==(PubSubSubscriptionState left, PubSubSubscriptionState right) { throw null; }\n\n        public static bool operator !=(PubSubSubscriptionState left, PubSubSubscriptionState right) { throw null; }\n\n        public override string ToString() { throw null; }\n\n        public enum SubscriptionStates\n        {\n            Active = 0,\n            Faulted = 1\n        }\n    }\n\n    public static partial class QueueAdapterConstants\n    {\n        public const int UNLIMITED_GET_QUEUE_MSG = -1;\n    }\n\n    public static partial class QueueAdapterExtensions\n    {\n        public static System.Threading.Tasks.Task QueueMessageAsync<T>(this IQueueAdapter adapter, Runtime.StreamId streamId, T evt, StreamSequenceToken token, System.Collections.Generic.Dictionary<string, object> requestContext) { throw null; }\n    }\n\n    public abstract partial class QueueBalancerBase : IStreamQueueBalancer\n    {\n        protected QueueBalancerBase(System.IServiceProvider sp, Microsoft.Extensions.Logging.ILogger logger) { }\n\n        protected System.Threading.CancellationToken Cancellation { get { throw null; } }\n\n        protected Microsoft.Extensions.Logging.ILogger Logger { get { throw null; } }\n\n        protected Runtime.SiloAddress SiloAddress { get { throw null; } }\n\n        public abstract System.Collections.Generic.IEnumerable<QueueId> GetMyQueues();\n        public virtual System.Threading.Tasks.Task Initialize(IStreamQueueMapper queueMapper) { throw null; }\n\n        protected System.Threading.Tasks.Task NotifyListeners() { throw null; }\n\n        protected abstract void OnClusterMembershipChange(System.Collections.Generic.HashSet<Runtime.SiloAddress> activeSilos);\n        public virtual System.Threading.Tasks.Task Shutdown() { throw null; }\n\n        public bool SubscribeToQueueDistributionChangeEvents(IStreamQueueBalanceListener observer) { throw null; }\n\n        public bool UnSubscribeFromQueueDistributionChangeEvents(IStreamQueueBalanceListener observer) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class QueueCacheMissException : DataNotAvailableException\n    {\n        public QueueCacheMissException() { }\n\n        public QueueCacheMissException(StreamSequenceToken requested, StreamSequenceToken low, StreamSequenceToken high) { }\n\n        public QueueCacheMissException(string message, System.Exception innerException) { }\n\n        public QueueCacheMissException(string requested, string low, string high) { }\n\n        public QueueCacheMissException(string message) { }\n\n        [Id(2)]\n        public string High { get { throw null; } }\n\n        [Id(1)]\n        public string Low { get { throw null; } }\n\n        [Id(0)]\n        public string Requested { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [Immutable]\n    [GenerateSerializer]\n    public readonly partial struct QueueId : System.IEquatable<QueueId>, System.IComparable<QueueId>, System.ISpanFormattable, System.IFormattable\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public bool IsDefault { get { throw null; } }\n\n        public readonly int CompareTo(QueueId other) { throw null; }\n\n        public readonly bool Equals(QueueId other) { throw null; }\n\n        public override readonly bool Equals(object? obj) { throw null; }\n\n        public override readonly int GetHashCode() { throw null; }\n\n        public readonly uint GetNumericId() { throw null; }\n\n        public static QueueId GetQueueId(string queueName, uint queueId, uint hash) { throw null; }\n\n        public readonly string GetStringNamePrefix() { throw null; }\n\n        public readonly uint GetUniformHashCode() { throw null; }\n\n        public static bool operator ==(QueueId left, QueueId right) { throw null; }\n\n        public static bool operator !=(QueueId left, QueueId right) { throw null; }\n\n        readonly string System.IFormattable.ToString(string? format, System.IFormatProvider? formatProvider) { throw null; }\n\n        readonly bool System.ISpanFormattable.TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format, System.IFormatProvider? provider) { throw null; }\n\n        public override readonly string ToString() { throw null; }\n\n        public readonly string ToStringWithHashCode() { throw null; }\n    }\n\n    public partial class RegexStreamNamespacePredicate : IStreamNamespacePredicate\n    {\n        public RegexStreamNamespacePredicate(string regex) { }\n\n        public string PredicatePattern { get { throw null; } }\n\n        public bool IsMatch(string streamNameSpace) { throw null; }\n    }\n\n    public partial class SequentialItem<T>\n    {\n        public SequentialItem(T item, StreamSequenceToken token) { }\n\n        public T Item { get { throw null; } }\n\n        public StreamSequenceToken Token { get { throw null; } }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class StreamEventDeliveryFailureException : Runtime.OrleansException\n    {\n        public StreamEventDeliveryFailureException() { }\n\n        [System.Obsolete]\n        public StreamEventDeliveryFailureException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public StreamEventDeliveryFailureException(string message, System.Exception innerException) { }\n\n        public StreamEventDeliveryFailureException(string message) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class StreamIdentity : IStreamIdentity\n    {\n        public StreamIdentity(System.Guid streamGuid, string streamNamespace) { }\n\n        [Id(0)]\n        public System.Guid Guid { get { throw null; } }\n\n        [Id(1)]\n        public string Namespace { get { throw null; } }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public override int GetHashCode() { throw null; }\n    }\n\n    public partial class StreamPosition\n    {\n        public StreamPosition(Runtime.StreamId streamId, StreamSequenceToken sequenceToken) { }\n\n        public StreamSequenceToken SequenceToken { get { throw null; } }\n\n        public Runtime.StreamId StreamId { get { throw null; } }\n    }\n\n    public enum StreamProviderDirection\n    {\n        None = 0,\n        ReadOnly = 1,\n        WriteOnly = 2,\n        ReadWrite = 3\n    }\n\n    public static partial class StreamProviderExtensions\n    {\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, System.Guid id) { throw null; }\n\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, long id) { throw null; }\n\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, System.Guid id) { throw null; }\n\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, long id) { throw null; }\n\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string ns, string id) { throw null; }\n\n        public static IAsyncStream<T> GetStream<T>(this IStreamProvider streamProvider, string id) { throw null; }\n    }\n\n    public enum StreamPubSubType\n    {\n        ExplicitGrainBasedAndImplicit = 0,\n        ExplicitGrainBasedOnly = 1,\n        ImplicitOnly = 2\n    }\n\n    [GenerateSerializer]\n    public abstract partial class StreamSequenceToken : System.IEquatable<StreamSequenceToken>, System.IComparable<StreamSequenceToken>\n    {\n        public abstract int EventIndex { get; protected set; }\n        public abstract long SequenceNumber { get; protected set; }\n\n        public abstract int CompareTo(StreamSequenceToken other);\n        public abstract bool Equals(StreamSequenceToken other);\n    }\n\n    public static partial class StreamSequenceTokenUtilities\n    {\n        public static bool Newer(this StreamSequenceToken me, StreamSequenceToken other) { throw null; }\n\n        public static bool Older(this StreamSequenceToken me, StreamSequenceToken other) { throw null; }\n    }\n\n    public static partial class StreamSubscriptionHandleExtensions\n    {\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<T, StreamSequenceToken, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Exception, System.Threading.Tasks.Task> onErrorAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token = null) { throw null; }\n\n        public static System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync<T>(this StreamSubscriptionHandle<T> handle, System.Func<System.Collections.Generic.IList<SequentialItem<T>>, System.Threading.Tasks.Task> onNextAsync, System.Func<System.Threading.Tasks.Task> onCompletedAsync, StreamSequenceToken token = null) { throw null; }\n    }\n\n    public partial class StreamSubscriptionHandlerFactory : Core.IStreamSubscriptionHandleFactory\n    {\n        public StreamSubscriptionHandlerFactory(IStreamProvider streamProvider, Runtime.StreamId streamId, string providerName, Runtime.GuidId subscriptionId) { }\n\n        public string ProviderName { get { throw null; } }\n\n        public Runtime.StreamId StreamId { get { throw null; } }\n\n        public Runtime.GuidId SubscriptionId { get { throw null; } }\n\n        public StreamSubscriptionHandle<T> Create<T>() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public abstract partial class StreamSubscriptionHandle<T> : System.IEquatable<StreamSubscriptionHandle<T>>\n    {\n        public abstract System.Guid HandleId { get; }\n        public abstract string ProviderName { get; }\n        public abstract Runtime.StreamId StreamId { get; }\n\n        public abstract bool Equals(StreamSubscriptionHandle<T> other);\n        public abstract System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncBatchObserver<T> observer, StreamSequenceToken token = null);\n        public abstract System.Threading.Tasks.Task<StreamSubscriptionHandle<T>> ResumeAsync(IAsyncObserver<T> observer, StreamSequenceToken token = null);\n        public abstract System.Threading.Tasks.Task UnsubscribeAsync();\n    }\n}\n\nnamespace Orleans.Streams.Core\n{\n    public partial interface IStreamSubscriptionHandleFactory\n    {\n        string ProviderName { get; }\n\n        Runtime.StreamId StreamId { get; }\n\n        Runtime.GuidId SubscriptionId { get; }\n\n        StreamSubscriptionHandle<T> Create<T>();\n    }\n\n    public partial interface IStreamSubscriptionManager\n    {\n        System.Threading.Tasks.Task<StreamSubscription> AddSubscription(string streamProviderName, Runtime.StreamId streamId, Runtime.GrainReference grainRef);\n        System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<StreamSubscription>> GetSubscriptions(string streamProviderName, Runtime.StreamId streamId);\n        System.Threading.Tasks.Task RemoveSubscription(string streamProviderName, Runtime.StreamId streamId, System.Guid subscriptionId);\n    }\n\n    public partial interface IStreamSubscriptionManagerAdmin\n    {\n        IStreamSubscriptionManager GetStreamSubscriptionManager(string managerType);\n    }\n\n    public partial interface IStreamSubscriptionManagerRetriever\n    {\n        IStreamSubscriptionManager GetStreamSubscriptionManager();\n    }\n\n    public partial interface IStreamSubscriptionObserver\n    {\n        System.Threading.Tasks.Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class StreamSubscription\n    {\n        public StreamSubscription(System.Guid subscriptionId, string streamProviderName, Runtime.StreamId streamId, Runtime.GrainId grainId) { }\n\n        [Id(3)]\n        public Runtime.GrainId GrainId { get { throw null; } }\n\n        [Id(2)]\n        public Runtime.StreamId StreamId { get { throw null; } }\n\n        [Id(1)]\n        public string StreamProviderName { get { throw null; } }\n\n        [Id(0)]\n        public System.Guid SubscriptionId { get { throw null; } }\n    }\n\n    public static partial class StreamSubscriptionManagerType\n    {\n        public const string ExplicitSubscribeOnly = \"ExplicitSubscribeOnly\";\n    }\n}\n\nnamespace Orleans.Streams.Filtering\n{\n    public partial interface IStreamFilter\n    {\n        bool ShouldDeliver(Runtime.StreamId streamId, object item, string filterData);\n    }\n}\n\nnamespace Orleans.Streams.PubSub\n{\n    public static partial class StreamSubscriptionManagerExtensions\n    {\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, Runtime.GrainId grainId)\n            where TGrainInterface : IGrainWithGuidKey { throw null; }\n\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, System.Guid primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidCompoundKey { throw null; }\n\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, System.Guid primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithGuidKey { throw null; }\n\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, long primaryKey, string keyExtension, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerCompoundKey { throw null; }\n\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, long primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithIntegerKey { throw null; }\n\n        public static System.Threading.Tasks.Task<Core.StreamSubscription> AddSubscription<TGrainInterface>(this Core.IStreamSubscriptionManager manager, IGrainFactory grainFactory, Runtime.StreamId streamId, string streamProviderName, string primaryKey, string grainClassNamePrefix = null)\n            where TGrainInterface : IGrainWithStringKey { throw null; }\n\n        public static bool TryGetStreamSubscriptionManager(this IStreamProvider streamProvider, out Core.IStreamSubscriptionManager manager) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Hosting\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SimpleGeneratorOptions : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Hosting.SimpleGeneratorOptions>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Hosting.SimpleGeneratorOptions instance) { }\n\n        public global::Orleans.Hosting.SimpleGeneratorOptions ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Hosting.SimpleGeneratorOptions instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Hosting.SimpleGeneratorOptions value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SimpleGeneratorOptions : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Hosting.SimpleGeneratorOptions>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public global::Orleans.Hosting.SimpleGeneratorOptions DeepCopy(global::Orleans.Hosting.SimpleGeneratorOptions original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Providers\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DefaultMemoryMessageBodySerializer : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.DefaultMemoryMessageBodySerializer>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_DefaultMemoryMessageBodySerializer(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Providers.DefaultMemoryMessageBodySerializer> _activator, global::Orleans.Runtime.OnDeserializedCallbacks _hook0) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.DefaultMemoryMessageBodySerializer instance) { }\n\n        public global::Orleans.Providers.DefaultMemoryMessageBodySerializer ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.DefaultMemoryMessageBodySerializer instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.DefaultMemoryMessageBodySerializer value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 instance) { }\n\n        public Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A instance) { }\n\n        public Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MemoryMessageBody : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.MemoryMessageBody>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_MemoryMessageBody(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Providers.MemoryMessageBody> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.MemoryMessageBody instance) { }\n\n        public global::Orleans.Providers.MemoryMessageBody ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.MemoryMessageBody instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.MemoryMessageBody value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_MemoryMessageData : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.MemoryMessageData>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Providers.MemoryMessageData>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_MemoryMessageData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Providers.MemoryMessageData instance) { }\n\n        public global::Orleans.Providers.MemoryMessageData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Providers.MemoryMessageData instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.MemoryMessageData value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 DeepCopy(Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A DeepCopy(Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_MemoryMessageBody : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.MemoryMessageBody>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_MemoryMessageBody(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Providers.MemoryMessageBody> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Providers.MemoryMessageBody DeepCopy(global::Orleans.Providers.MemoryMessageBody original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_MemoryMessageData : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.MemoryMessageData>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_MemoryMessageData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Providers.MemoryMessageData DeepCopy(global::Orleans.Providers.MemoryMessageData result, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Providers.IMemoryStreamQueueGrain), \"74D60341\" })]\n    public sealed partial class Invokable_IMemoryStreamQueueGrain_GrainReference_74D60341 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Providers.MemoryMessageData arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Providers.IMemoryStreamQueueGrain), \"7A8F8C1A\" })]\n    public sealed partial class Invokable_IMemoryStreamQueueGrain_GrainReference_7A8F8C1A : global::Orleans.Runtime.TaskRequest<System.Collections.Generic.List<global::Orleans.Providers.MemoryMessageData>>\n    {\n        public int arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<global::Orleans.Providers.MemoryMessageData>> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Providers.Streams.Common\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventSequenceToken : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.Streams.Common.EventSequenceToken>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Providers.Streams.Common.EventSequenceToken>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventSequenceToken(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.Streams.Common.EventSequenceToken instance) { }\n\n        public global::Orleans.Providers.Streams.Common.EventSequenceToken ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.Streams.Common.EventSequenceToken instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.Streams.Common.EventSequenceToken value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_EventSequenceTokenV2 : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.Streams.Common.EventSequenceTokenV2>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Providers.Streams.Common.EventSequenceTokenV2>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_EventSequenceTokenV2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 instance) { }\n\n        public global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventSequenceToken : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.Streams.Common.EventSequenceToken>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Providers.Streams.Common.EventSequenceToken>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventSequenceToken(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void DeepCopy(global::Orleans.Providers.Streams.Common.EventSequenceToken input, global::Orleans.Providers.Streams.Common.EventSequenceToken output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Providers.Streams.Common.EventSequenceToken DeepCopy(global::Orleans.Providers.Streams.Common.EventSequenceToken original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_EventSequenceTokenV2 : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.Streams.Common.EventSequenceTokenV2>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Providers.Streams.Common.EventSequenceTokenV2>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_EventSequenceTokenV2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void DeepCopy(global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 input, global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n\n        public global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 DeepCopy(global::Orleans.Providers.Streams.Common.EventSequenceTokenV2 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Providers.Streams.Generator\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GeneratedBatchContainer : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GeneratedBatchContainer(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer instance) { }\n\n        public global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GeneratedEvent : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Providers.Streams.Generator.GeneratedEvent>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_GeneratedEvent(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Providers.Streams.Generator.GeneratedEvent instance) { }\n\n        public global::Orleans.Providers.Streams.Generator.GeneratedEvent ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Providers.Streams.Generator.GeneratedEvent instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Providers.Streams.Generator.GeneratedEvent value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GeneratedBatchContainer : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_GeneratedBatchContainer(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer DeepCopy(global::Orleans.Providers.Streams.Generator.GeneratedBatchContainer original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GeneratedEvent : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Providers.Streams.Generator.GeneratedEvent>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_GeneratedEvent(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Providers.Streams.Generator.GeneratedEvent DeepCopy(global::Orleans.Providers.Streams.Generator.GeneratedEvent original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Runtime\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_QualifiedStreamId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.QualifiedStreamId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.QualifiedStreamId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_QualifiedStreamId(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.QualifiedStreamId instance) { }\n\n        public global::Orleans.Runtime.QualifiedStreamId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.QualifiedStreamId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.QualifiedStreamId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Runtime.StreamId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Runtime.StreamId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Runtime.StreamId instance) { }\n\n        public global::Orleans.Runtime.StreamId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Runtime.StreamId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Runtime.StreamId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Streams\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_BatchContainerBatch : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.BatchContainerBatch>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_BatchContainerBatch(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.BatchContainerBatch> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.BatchContainerBatch instance) { }\n\n        public global::Orleans.Streams.BatchContainerBatch ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.BatchContainerBatch instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.BatchContainerBatch value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CacheFullException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.CacheFullException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_CacheFullException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.CacheFullException instance) { }\n\n        public global::Orleans.Streams.CacheFullException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.CacheFullException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.CacheFullException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_DataNotAvailableException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.DataNotAvailableException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Streams.DataNotAvailableException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_DataNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.DataNotAvailableException instance) { }\n\n        public global::Orleans.Streams.DataNotAvailableException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.DataNotAvailableException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.DataNotAvailableException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FaultedSubscriptionException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.FaultedSubscriptionException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_FaultedSubscriptionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.FaultedSubscriptionException instance) { }\n\n        public global::Orleans.Streams.FaultedSubscriptionException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.FaultedSubscriptionException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.FaultedSubscriptionException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ProviderStartException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.ProviderStartException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_ProviderStartException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.ProviderStartException instance) { }\n\n        public global::Orleans.Streams.ProviderStartException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.ProviderStartException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.ProviderStartException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_PubSubSubscriptionState : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.PubSubSubscriptionState>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_PubSubSubscriptionState(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.PubSubSubscriptionState> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.PubSubSubscriptionState instance) { }\n\n        public global::Orleans.Streams.PubSubSubscriptionState ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.PubSubSubscriptionState instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.PubSubSubscriptionState value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_QueueCacheMissException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.QueueCacheMissException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_QueueCacheMissException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.QueueCacheMissException instance) { }\n\n        public global::Orleans.Streams.QueueCacheMissException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.QueueCacheMissException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.QueueCacheMissException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_QueueId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.QueueId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Streams.QueueId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Streams.QueueId instance) { }\n\n        public global::Orleans.Streams.QueueId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Streams.QueueId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.QueueId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamEventDeliveryFailureException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.StreamEventDeliveryFailureException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_StreamEventDeliveryFailureException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.StreamEventDeliveryFailureException instance) { }\n\n        public global::Orleans.Streams.StreamEventDeliveryFailureException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.StreamEventDeliveryFailureException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.StreamEventDeliveryFailureException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamIdentity : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.StreamIdentity>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_StreamIdentity(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.StreamIdentity> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.StreamIdentity instance) { }\n\n        public global::Orleans.Streams.StreamIdentity ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.StreamIdentity instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.StreamIdentity value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamSequenceToken : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.Streams.StreamSequenceToken>\n    {\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamSubscriptionHandle<T> : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.Streams.StreamSubscriptionHandle<T>>\n    {\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_BatchContainerBatch : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streams.BatchContainerBatch>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_BatchContainerBatch(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.BatchContainerBatch> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Streams.BatchContainerBatch DeepCopy(global::Orleans.Streams.BatchContainerBatch original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_CacheFullException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.CacheFullException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_CacheFullException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_DataNotAvailableException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.DataNotAvailableException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_DataNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FaultedSubscriptionException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.FaultedSubscriptionException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_FaultedSubscriptionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ProviderStartException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.ProviderStartException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_ProviderStartException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_PubSubSubscriptionState : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streams.PubSubSubscriptionState>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_PubSubSubscriptionState(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.PubSubSubscriptionState> _activator) { }\n\n        public global::Orleans.Streams.PubSubSubscriptionState DeepCopy(global::Orleans.Streams.PubSubSubscriptionState original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_QueueCacheMissException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.QueueCacheMissException, global::Orleans.Streams.DataNotAvailableException>\n    {\n        public Copier_QueueCacheMissException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Streams.QueueCacheMissException input, global::Orleans.Streams.QueueCacheMissException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_StreamEventDeliveryFailureException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Streams.StreamEventDeliveryFailureException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_StreamEventDeliveryFailureException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_StreamSequenceToken : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streams.StreamSequenceToken>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streams.StreamSequenceToken>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Streams.StreamSequenceToken DeepCopy(global::Orleans.Streams.StreamSequenceToken original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streams.StreamSequenceToken input, global::Orleans.Streams.StreamSequenceToken output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_StreamSubscriptionHandle<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Streams.StreamSubscriptionHandle<T>>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Streams.StreamSubscriptionHandle<T>>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Streams.StreamSubscriptionHandle<T> DeepCopy(global::Orleans.Streams.StreamSubscriptionHandle<T> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Streams.StreamSubscriptionHandle<T> input, global::Orleans.Streams.StreamSubscriptionHandle<T> output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Streams.Core\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_StreamSubscription : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Streams.Core.StreamSubscription>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_StreamSubscription(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Streams.Core.StreamSubscription> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Streams.Core.StreamSubscription instance) { }\n\n        public global::Orleans.Streams.Core.StreamSubscription ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Streams.Core.StreamSubscription instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Streams.Core.StreamSubscription value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Streaming.Abstractions/Orleans.Streaming.Abstractions.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/api/Orleans.TestingHost/Orleans.TestingHost.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class FaultInjectionStorageServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddFaultInjectionMemoryStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.MemoryGrainStorageOptions>> configureOptions = null, System.Action<Microsoft.Extensions.Options.OptionsBuilder<TestingHost.FaultInjectionGrainStorageOptions>> configureFaultInjectionOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddFaultInjectionMemoryStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Configuration.MemoryGrainStorageOptions> configureOptions, System.Action<TestingHost.FaultInjectionGrainStorageOptions> configureFaultInjectionOptions) { throw null; }\n    }\n}\n\nnamespace Orleans.TestingHost\n{\n    public enum ConnectionTransportType\n    {\n        TcpSocket = 0,\n        InMemory = 1,\n        UnixSocket = 2\n    }\n\n    public partial class FaultInjectionGrainStorage : Storage.IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public FaultInjectionGrainStorage(Storage.IGrainStorage realStorageProvider, string name, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, IGrainFactory grainFactory, FaultInjectionGrainStorageOptions faultInjectionOptions) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class FaultInjectionGrainStorageFactory\n    {\n        public static Storage.IGrainStorage Create(System.IServiceProvider services, string name, System.Func<System.IServiceProvider, string, Storage.IGrainStorage> injectedGrainStorageFactory) { throw null; }\n    }\n\n    public partial class FaultInjectionGrainStorageOptions\n    {\n        public static System.TimeSpan DEFAULT_LATENCY;\n        public System.TimeSpan Latency { get { throw null; } set { } }\n    }\n\n    public partial interface IClientBuilderConfigurator\n    {\n        void Configure(Microsoft.Extensions.Configuration.IConfiguration configuration, Hosting.IClientBuilder clientBuilder);\n    }\n\n    public partial interface IHostConfigurator\n    {\n        void Configure(Microsoft.Extensions.Hosting.IHostBuilder hostBuilder);\n    }\n\n    public partial class InProcessSiloHandle : SiloHandle\n    {\n        public override bool IsActive { get { throw null; } }\n\n        public System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        public Microsoft.Extensions.Hosting.IHost SiloHost { get { throw null; } init { } }\n\n        public static System.Threading.Tasks.Task<InProcessSiloHandle> CreateAsync(string siloName, Microsoft.Extensions.Configuration.IConfiguration configuration, System.Action<Microsoft.Extensions.Hosting.IHostBuilder> postConfigureHostBuilder = null) { throw null; }\n\n        protected override void Dispose(bool disposing) { }\n\n        public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }\n\n        public override System.Threading.Tasks.Task StopSiloAsync(bool stopGracefully) { throw null; }\n\n        public override System.Threading.Tasks.Task StopSiloAsync(System.Threading.CancellationToken ct) { throw null; }\n    }\n\n    public sealed partial class InProcessTestCluster : System.IDisposable, System.IAsyncDisposable\n    {\n        public InProcessTestCluster(InProcessTestClusterOptions options, ITestClusterPortAllocator portAllocator) { }\n\n        public IClusterClient Client { get { throw null; } }\n\n        public InProcessTestClusterOptions Options { get { throw null; } }\n\n        public ITestClusterPortAllocator PortAllocator { get { throw null; } }\n\n        public System.Collections.ObjectModel.ReadOnlyCollection<InProcessSiloHandle> Silos { get { throw null; } }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> CreateSiloAsync(InProcessTestSiloSpecificOptions siloOptions) { throw null; }\n\n        public System.Threading.Tasks.Task DeployAsync() { throw null; }\n\n        public void Dispose() { }\n\n        public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }\n\n        public System.Collections.Generic.IEnumerable<InProcessSiloHandle> GetActiveSilos() { throw null; }\n\n        public static System.TimeSpan GetLivenessStabilizationTime(Configuration.ClusterMembershipOptions clusterMembershipOptions, bool didKill = false) { throw null; }\n\n        public string GetLog() { throw null; }\n\n        public InProcessSiloHandle GetSiloForAddress(Runtime.SiloAddress siloAddress) { throw null; }\n\n        public System.IServiceProvider GetSiloServiceProvider(Runtime.SiloAddress silo = null) { throw null; }\n\n        public System.Threading.Tasks.Task InitializeClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task KillClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task KillSiloAsync(InProcessSiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> RestartSiloAsync(InProcessSiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> RestartStoppedSecondarySiloAsync(string siloName) { throw null; }\n\n        public InProcessSiloHandle StartAdditionalSilo() { throw null; }\n\n        [System.Obsolete(\"Use overload which does not have a 'startAdditionalSiloOnNewPort' parameter.\")]\n        public InProcessSiloHandle StartAdditionalSilo(bool startAdditionalSiloOnNewPort) { throw null; }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> StartAdditionalSiloAsync() { throw null; }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> StartAdditionalSiloAsync(bool startAdditionalSiloOnNewPort) { throw null; }\n\n        [System.Obsolete(\"Use the overload which does not have a 'startSiloOnNewPort' parameter.\")]\n        public static System.Threading.Tasks.Task<InProcessSiloHandle> StartSiloAsync(InProcessTestCluster cluster, int instanceNumber, InProcessTestClusterOptions clusterOptions, System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> configurationOverrides, bool startSiloOnNewPort) { throw null; }\n\n        public static System.Threading.Tasks.Task<InProcessSiloHandle> StartSiloAsync(InProcessTestCluster cluster, int instanceNumber, InProcessTestClusterOptions clusterOptions) { throw null; }\n\n        [System.Obsolete(\"Use the overload which does not have a 'startSiloOnNewPort' parameter.\")]\n        public System.Threading.Tasks.Task<InProcessSiloHandle> StartSiloAsync(int instanceNumber, InProcessTestClusterOptions clusterOptions, System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> configurationOverrides, bool startSiloOnNewPort) { throw null; }\n\n        public System.Threading.Tasks.Task<InProcessSiloHandle> StartSiloAsync(int instanceNumber, InProcessTestClusterOptions clusterOptions) { throw null; }\n\n        [System.Obsolete(\"Use overload which does not have a 'startAdditionalSiloOnNewPort' parameter.\")]\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<InProcessSiloHandle>> StartSilosAsync(int silosToStart, bool startAdditionalSiloOnNewPort) { throw null; }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<InProcessSiloHandle>> StartSilosAsync(int silosToStart) { throw null; }\n\n        public void StopAllSilos() { }\n\n        public System.Threading.Tasks.Task StopAllSilosAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopClusterClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopSiloAsync(InProcessSiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task StopSilosAsync() { throw null; }\n\n        public System.Threading.Tasks.Task WaitForLivenessToStabilizeAsync(bool didKill = false) { throw null; }\n    }\n\n    public sealed partial class InProcessTestClusterBuilder\n    {\n        public InProcessTestClusterBuilder() { }\n\n        public InProcessTestClusterBuilder(short initialSilosCount) { }\n\n        public InProcessTestClusterOptions Options { get { throw null; } }\n\n        public ITestClusterPortAllocator PortAllocator { get { throw null; } }\n\n        public InProcessTestCluster Build() { throw null; }\n\n        public InProcessTestClusterBuilder ConfigureClient(System.Action<Hosting.IClientBuilder> configureClientDelegate) { throw null; }\n\n        public InProcessTestClusterBuilder ConfigureClientHost(System.Action<Microsoft.Extensions.Hosting.IHostApplicationBuilder> configureHostDelegate) { throw null; }\n\n        public InProcessTestClusterBuilder ConfigureHost(System.Action<Microsoft.Extensions.Hosting.IHostApplicationBuilder> configureDelegate) { throw null; }\n\n        public InProcessTestClusterBuilder ConfigureSilo(System.Action<InProcessTestSiloSpecificOptions, Hosting.ISiloBuilder> configureSiloDelegate) { throw null; }\n\n        public InProcessTestClusterBuilder ConfigureSiloHost(System.Action<InProcessTestSiloSpecificOptions, Microsoft.Extensions.Hosting.IHostApplicationBuilder> configureSiloHostDelegate) { throw null; }\n\n        public static string CreateClusterId() { throw null; }\n    }\n\n    public sealed partial class InProcessTestClusterOptions\n    {\n        public bool AssumeHomogenousSilosForTesting { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<System.Action<Microsoft.Extensions.Hosting.IHostApplicationBuilder>> ClientHostConfigurationDelegates { get { throw null; } }\n\n        public string ClusterId { get { throw null; } set { } }\n\n        public bool ConfigureFileLogging { get { throw null; } set { } }\n\n        public bool GatewayPerSilo { get { throw null; } set { } }\n\n        public bool InitializeClientOnDeploy { get { throw null; } set { } }\n\n        public short InitialSilosCount { get { throw null; } set { } }\n\n        public string ServiceId { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<System.Action<InProcessTestSiloSpecificOptions, Microsoft.Extensions.Hosting.IHostApplicationBuilder>> SiloHostConfigurationDelegates { get { throw null; } }\n\n        public bool UseRealEnvironmentStatistics { get { throw null; } set { } }\n    }\n\n    public sealed partial class InProcessTestSiloSpecificOptions\n    {\n        public int GatewayPort { get { throw null; } set { } }\n\n        public string SiloName { get { throw null; } set { } }\n\n        public int SiloPort { get { throw null; } set { } }\n\n        public static InProcessTestSiloSpecificOptions Create(InProcessTestCluster testCluster, InProcessTestClusterOptions testClusterOptions, int instanceNumber, bool assignNewPort = false) { throw null; }\n    }\n\n    public partial interface ISiloConfigurator\n    {\n        void Configure(Hosting.ISiloBuilder siloBuilder);\n    }\n\n    public partial interface IStorageFaultGrain : IGrainWithStringKey, IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task AddFaultOnClear(Runtime.GrainId grainId, System.Exception exception);\n        System.Threading.Tasks.Task AddFaultOnRead(Runtime.GrainId grainId, System.Exception exception);\n        System.Threading.Tasks.Task AddFaultOnWrite(Runtime.GrainId grainId, System.Exception exception);\n        System.Threading.Tasks.Task OnClear(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task OnRead(Runtime.GrainId grainId);\n        System.Threading.Tasks.Task OnWrite(Runtime.GrainId grainId);\n    }\n\n    public partial interface ITestClusterPortAllocator : System.IDisposable\n    {\n        (int, int) AllocateConsecutivePortPairs(int numPorts);\n    }\n\n    [GenerateSerializer]\n    public sealed partial class RandomlyInjectedInconsistentStateException : Storage.InconsistentStateException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class RandomlyInjectedStorageException : System.Exception\n    {\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static Hosting.ISiloBuilder AddFaultInjectionMemoryStorage(this Hosting.ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.MemoryGrainStorageOptions>> configureOptions = null, System.Action<Microsoft.Extensions.Options.OptionsBuilder<FaultInjectionGrainStorageOptions>> configureFaultInjectionOptions = null) { throw null; }\n\n        public static Hosting.ISiloBuilder AddFaultInjectionMemoryStorage(this Hosting.ISiloBuilder builder, string name, System.Action<Configuration.MemoryGrainStorageOptions> configureOptions, System.Action<FaultInjectionGrainStorageOptions> configureFaultInjectionOptions) { throw null; }\n    }\n\n    public abstract partial class SiloHandle : System.IDisposable, System.IAsyncDisposable\n    {\n        public TestClusterOptions ClusterOptions { get { throw null; } set { } }\n\n        public Runtime.SiloAddress GatewayAddress { get { throw null; } set { } }\n\n        public short InstanceNumber { get { throw null; } set { } }\n\n        public abstract bool IsActive { get; }\n\n        public string Name { get { throw null; } set { } }\n\n        public Runtime.SiloAddress SiloAddress { get { throw null; } set { } }\n\n        public void Dispose() { }\n\n        protected virtual void Dispose(bool disposing) { }\n\n        public abstract System.Threading.Tasks.ValueTask DisposeAsync();\n        ~SiloHandle() {\n        }\n\n        public abstract System.Threading.Tasks.Task StopSiloAsync(bool stopGracefully);\n        public abstract System.Threading.Tasks.Task StopSiloAsync(System.Threading.CancellationToken ct);\n        public override string ToString() { throw null; }\n    }\n\n    public partial class StandaloneSiloHandle : SiloHandle\n    {\n        public const string ExecutablePathConfigKey = \"ExecutablePath\";\n        public StandaloneSiloHandle(string siloName, Microsoft.Extensions.Configuration.IConfiguration configuration, string executablePath) { }\n\n        public override bool IsActive { get { throw null; } }\n\n        public static System.Threading.Tasks.Task<SiloHandle> Create(string siloName, Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }\n\n        public static System.Func<string, Microsoft.Extensions.Configuration.IConfiguration, System.Threading.Tasks.Task<SiloHandle>> CreateDelegate(string executablePath) { throw null; }\n\n        public static System.Func<string, Microsoft.Extensions.Configuration.IConfiguration, System.Threading.Tasks.Task<SiloHandle>> CreateForAssembly(System.Reflection.Assembly assembly) { throw null; }\n\n        protected override void Dispose(bool disposing) { }\n\n        public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }\n\n        public override System.Threading.Tasks.Task StopSiloAsync(bool stopGracefully) { throw null; }\n\n        public override System.Threading.Tasks.Task StopSiloAsync(System.Threading.CancellationToken ct) { throw null; }\n    }\n\n    public static partial class StandaloneSiloHost\n    {\n        public const string GatewayAddressLog = \"#### GATEWAY \";\n        public const string ShutdownCommand = \"#### SHUTDOWN\";\n        public const string SiloAddressLog = \"#### SILO \";\n        public const string StartedLog = \"#### STARTED\";\n        public static System.Threading.Tasks.Task Main(string[] args) { throw null; }\n    }\n\n    public partial class StorageFaultGrain : Grain, IStorageFaultGrain, IGrainWithStringKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task AddFaultOnClear(Runtime.GrainId grainId, System.Exception exception) { throw null; }\n\n        public System.Threading.Tasks.Task AddFaultOnRead(Runtime.GrainId grainId, System.Exception exception) { throw null; }\n\n        public System.Threading.Tasks.Task AddFaultOnWrite(Runtime.GrainId grainId, System.Exception exception) { throw null; }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task OnClear(Runtime.GrainId grainId) { throw null; }\n\n        public System.Threading.Tasks.Task OnRead(Runtime.GrainId grainId) { throw null; }\n\n        public System.Threading.Tasks.Task OnWrite(Runtime.GrainId grainId) { throw null; }\n    }\n\n    public partial class TestCluster : System.IDisposable, System.IAsyncDisposable\n    {\n        public TestCluster(TestClusterOptions options, System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> configurationSources, ITestClusterPortAllocator portAllocator) { }\n\n        public IClusterClient Client { get { throw null; } }\n\n        public System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> ConfigurationSources { get { throw null; } }\n\n        public System.Func<string, Microsoft.Extensions.Configuration.IConfiguration, System.Threading.Tasks.Task<SiloHandle>> CreateSiloAsync { set { } }\n\n        public IGrainFactory GrainFactory { get { throw null; } }\n\n        public TestClusterOptions Options { get { throw null; } }\n\n        public ITestClusterPortAllocator PortAllocator { get { throw null; } }\n\n        public SiloHandle Primary { get { throw null; } }\n\n        public System.Collections.Generic.IReadOnlyList<SiloHandle> SecondarySilos { get { throw null; } }\n\n        public System.IServiceProvider ServiceProvider { get { throw null; } }\n\n        public System.Collections.ObjectModel.ReadOnlyCollection<SiloHandle> Silos { get { throw null; } }\n\n        public System.Threading.Tasks.Task<SiloHandle> DefaultCreateSiloAsync(string siloName, Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }\n\n        public void Deploy() { }\n\n        public System.Threading.Tasks.Task DeployAsync() { throw null; }\n\n        public void Dispose() { }\n\n        public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }\n\n        public System.Collections.Generic.IEnumerable<SiloHandle> GetActiveSilos() { throw null; }\n\n        public static System.TimeSpan GetLivenessStabilizationTime(Configuration.ClusterMembershipOptions clusterMembershipOptions, bool didKill = false) { throw null; }\n\n        public string GetLog() { throw null; }\n\n        public SiloHandle GetSiloForAddress(Runtime.SiloAddress siloAddress) { throw null; }\n\n        public System.IServiceProvider GetSiloServiceProvider(Runtime.SiloAddress silo = null) { throw null; }\n\n        public System.Threading.Tasks.Task InitializeClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task KillClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task KillSiloAsync(SiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task<SiloHandle> RestartSiloAsync(SiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task<SiloHandle> RestartStoppedSecondarySiloAsync(string siloName) { throw null; }\n\n        public SiloHandle StartAdditionalSilo(bool startAdditionalSiloOnNewPort = false) { throw null; }\n\n        public System.Threading.Tasks.Task<SiloHandle> StartAdditionalSiloAsync(bool startAdditionalSiloOnNewPort = false) { throw null; }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<SiloHandle>> StartAdditionalSilosAsync(int silosToStart, bool startAdditionalSiloOnNewPort = false) { throw null; }\n\n        public static System.Threading.Tasks.Task<SiloHandle> StartSiloAsync(TestCluster cluster, int instanceNumber, TestClusterOptions clusterOptions, System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> configurationOverrides = null, bool startSiloOnNewPort = false) { throw null; }\n\n        public System.Threading.Tasks.Task<SiloHandle> StartSiloAsync(int instanceNumber, TestClusterOptions clusterOptions, System.Collections.Generic.IReadOnlyList<Microsoft.Extensions.Configuration.IConfigurationSource> configurationOverrides = null, bool startSiloOnNewPort = false) { throw null; }\n\n        public void StopAllSilos() { }\n\n        public System.Threading.Tasks.Task StopAllSilosAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopClusterClientAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopPrimarySiloAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopSecondarySilosAsync() { throw null; }\n\n        public System.Threading.Tasks.Task StopSiloAsync(SiloHandle instance) { throw null; }\n\n        public System.Threading.Tasks.Task WaitForLivenessToStabilizeAsync(bool didKill = false) { throw null; }\n    }\n\n    public partial class TestClusterBuilder\n    {\n        public TestClusterBuilder() { }\n\n        public TestClusterBuilder(short initialSilosCount) { }\n\n        public System.Func<string, Microsoft.Extensions.Configuration.IConfiguration, System.Threading.Tasks.Task<SiloHandle>> CreateSiloAsync { set { } }\n\n        public TestClusterOptions Options { get { throw null; } }\n\n        public ITestClusterPortAllocator PortAllocator { get { throw null; } set { } }\n\n        public System.Collections.Generic.Dictionary<string, string> Properties { get { throw null; } }\n\n        public TestClusterBuilder AddClientBuilderConfigurator<T>()\n            where T : new() { throw null; }\n\n        public TestClusterBuilder AddSiloBuilderConfigurator<T>()\n            where T : new() { throw null; }\n\n        public TestCluster Build() { throw null; }\n\n        public TestClusterBuilder ConfigureBuilder(System.Action configureDelegate) { throw null; }\n\n        public TestClusterBuilder ConfigureHostConfiguration(System.Action<Microsoft.Extensions.Configuration.IConfigurationBuilder> configureDelegate) { throw null; }\n\n        public static string CreateClusterId() { throw null; }\n    }\n\n    public static partial class TestClusterExtensions\n    {\n        public static Microsoft.Extensions.Configuration.IConfiguration GetConfiguration(this Microsoft.Extensions.Hosting.IHostBuilder builder) { throw null; }\n\n        public static string GetConfigurationValue(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, string key) { throw null; }\n\n        public static TestClusterOptions GetTestClusterOptions(this Microsoft.Extensions.Configuration.IConfiguration config) { throw null; }\n\n        public static TestClusterOptions GetTestClusterOptions(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder) { throw null; }\n    }\n\n    public partial class TestClusterHostFactory\n    {\n        public static Microsoft.Extensions.Hosting.IHost CreateClusterClient(string hostName, Microsoft.Extensions.Configuration.IConfiguration configuration, System.Action<Microsoft.Extensions.Hosting.IHostBuilder> postConfigureHostBuilder = null) { throw null; }\n\n        public static Microsoft.Extensions.Hosting.IHost CreateSiloHost(string hostName, Microsoft.Extensions.Configuration.IConfiguration configuration, System.Action<Microsoft.Extensions.Hosting.IHostBuilder> postConfigureHostBuilder = null) { throw null; }\n\n        public static Microsoft.Extensions.Configuration.IConfiguration DeserializeConfiguration(string serializedSources) { throw null; }\n\n        public static string SerializeConfiguration(Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }\n    }\n\n    public partial class TestClusterOptions\n    {\n        public string ApplicationBaseDirectory { get { throw null; } set { } }\n\n        public bool AssumeHomogenousSilosForTesting { get { throw null; } set { } }\n\n        public int BaseGatewayPort { get { throw null; } set { } }\n\n        public int BaseSiloPort { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<string> ClientBuilderConfiguratorTypes { get { throw null; } }\n\n        public string ClusterId { get { throw null; } set { } }\n\n        public bool ConfigureFileLogging { get { throw null; } set { } }\n\n        public ConnectionTransportType ConnectionTransport { get { throw null; } set { } }\n\n        public bool GatewayPerSilo { get { throw null; } set { } }\n\n        public bool InitializeClientOnDeploy { get { throw null; } set { } }\n\n        public short InitialSilosCount { get { throw null; } set { } }\n\n        public string ServiceId { get { throw null; } set { } }\n\n        public System.Collections.Generic.List<string> SiloBuilderConfiguratorTypes { get { throw null; } }\n\n        public bool UseRealEnvironmentStatistics { get { throw null; } set { } }\n\n        public bool UseTestClusterMembership { get { throw null; } set { } }\n\n        public System.Collections.Generic.Dictionary<string, string> ToDictionary() { throw null; }\n    }\n\n    public partial class TestClusterPortAllocator : ITestClusterPortAllocator, System.IDisposable\n    {\n        public (int, int) AllocateConsecutivePortPairs(int numPorts = 5) { throw null; }\n\n        public void Dispose() { }\n\n        protected virtual void Dispose(bool disposing) { }\n\n        ~TestClusterPortAllocator() {\n        }\n    }\n\n    public partial class TestSiloSpecificOptions\n    {\n        public int GatewayPort { get { throw null; } set { } }\n\n        public System.Net.IPEndPoint PrimarySiloEndPoint { get { throw null; } set { } }\n\n        public string SiloName { get { throw null; } set { } }\n\n        public int SiloPort { get { throw null; } set { } }\n\n        public static TestSiloSpecificOptions Create(TestCluster testCluster, TestClusterOptions testClusterOptions, int instanceNumber, bool assignNewPort = false) { throw null; }\n\n        public System.Collections.Generic.Dictionary<string, string> ToDictionary() { throw null; }\n    }\n}\n\nnamespace Orleans.TestingHost.Logging\n{\n    public partial class FileLogger : Microsoft.Extensions.Logging.ILogger\n    {\n        public FileLogger(FileLoggingOutput output, string category) { }\n\n        public System.IDisposable BeginScope<TState>(TState state) { throw null; }\n\n        public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) { throw null; }\n\n        public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, System.Exception exception, System.Func<TState, System.Exception, string> formatter) { }\n    }\n\n    public partial class FileLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, System.IDisposable\n    {\n        public FileLoggerProvider(string filePath) { }\n\n        public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) { throw null; }\n\n        public void Dispose() { }\n    }\n\n    public static partial class FileLoggerProviderExtensions\n    {\n        public static Microsoft.Extensions.Logging.ILoggingBuilder AddFile(this Microsoft.Extensions.Logging.ILoggingBuilder builder, string filePathName) { throw null; }\n    }\n\n    public partial class FileLoggingOutput : System.IDisposable\n    {\n        public FileLoggingOutput(string fileName) { }\n\n        public void Dispose() { }\n\n        public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, System.Exception exception, System.Func<TState, System.Exception, string> formatter, string category) { }\n    }\n}\n\nnamespace Orleans.TestingHost.UnixSocketTransport\n{\n    public static partial class UnixSocketConnectionExtensions\n    {\n        public static Hosting.IClientBuilder UseUnixSocketConnection(this Hosting.IClientBuilder clientBuilder) { throw null; }\n\n        public static Hosting.ISiloBuilder UseUnixSocketConnection(this Hosting.ISiloBuilder siloBuilder) { throw null; }\n    }\n\n    public partial class UnixSocketConnectionOptions\n    {\n        public System.Func<System.Net.EndPoint, string> ConvertEndpointToPath { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.TestingHost.Utils\n{\n    public partial class AsyncResultHandle\n    {\n        public bool Continue { get { throw null; } set { } }\n\n        public bool Done { get { throw null; } set { } }\n\n        public System.Exception Exception { get { throw null; } set { } }\n\n        public object Result { get { throw null; } set { } }\n\n        public virtual void Reset() { }\n\n        public System.Threading.Tasks.Task<bool> WaitFor(System.TimeSpan timeout, System.Func<bool> checkFlag) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> WaitForContinue(System.TimeSpan timeout) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> WaitForFinished(System.TimeSpan timeout) { throw null; }\n    }\n\n    public static partial class StorageEmulator\n    {\n        public static bool Exists { get { throw null; } }\n\n        public static string Help() { throw null; }\n\n        public static bool IsStarted() { throw null; }\n\n        public static bool Start() { throw null; }\n\n        public static bool Stop() { throw null; }\n\n        public static bool TryStart() { throw null; }\n    }\n\n    public static partial class TestingUtils\n    {\n        public static void ConfigureDefaultLoggingBuilder(Microsoft.Extensions.Logging.ILoggingBuilder builder, string filePath) { }\n\n        public static void ConfigureThreadPoolSettingsForStorageTests(int numDotNetPoolThreads = 200) { }\n\n        public static Microsoft.Extensions.Logging.ILoggerFactory CreateDefaultLoggerFactory(string filePath, Microsoft.Extensions.Logging.LoggerFilterOptions filters) { throw null; }\n\n        public static Microsoft.Extensions.Logging.ILoggerFactory CreateDefaultLoggerFactory(string filePath) { throw null; }\n\n        public static string CreateTraceFileName(string nodeName, string clusterId) { throw null; }\n\n        public static System.TimeSpan Multiply(System.TimeSpan time, double value) { throw null; }\n\n        public static System.Threading.Tasks.Task WaitUntilAsync(System.Func<bool, System.Threading.Tasks.Task<bool>> predicate, System.TimeSpan timeout, System.TimeSpan? delayOnFail = null) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.TestingHost\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_1150D526 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_1150D526>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_1150D526(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_1150D526 instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_1150D526 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_1150D526 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_1150D526 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_1A607A31 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_1A607A31>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_1A607A31(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_1A607A31 instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_1A607A31 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_1A607A31 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_1A607A31 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_5D91E1AF : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_5D91E1AF>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_5D91E1AF(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_5D91E1AF instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_5D91E1AF ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_5D91E1AF instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_5D91E1AF value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_B9852E6E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_B9852E6E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_B9852E6E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_B9852E6E instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_B9852E6E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_B9852E6E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_B9852E6E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_C94BA77C : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_C94BA77C>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_C94BA77C(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_C94BA77C instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_C94BA77C ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_C94BA77C instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_C94BA77C value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IStorageFaultGrain_GrainReference_E8594820 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IStorageFaultGrain_GrainReference_E8594820>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IStorageFaultGrain_GrainReference_E8594820(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IStorageFaultGrain_GrainReference_E8594820 instance) { }\n\n        public Invokable_IStorageFaultGrain_GrainReference_E8594820 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IStorageFaultGrain_GrainReference_E8594820 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IStorageFaultGrain_GrainReference_E8594820 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RandomlyInjectedInconsistentStateException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_RandomlyInjectedInconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException instance) { }\n\n        public global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RandomlyInjectedStorageException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.TestingHost.RandomlyInjectedStorageException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_RandomlyInjectedStorageException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.TestingHost.RandomlyInjectedStorageException instance) { }\n\n        public global::Orleans.TestingHost.RandomlyInjectedStorageException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.TestingHost.RandomlyInjectedStorageException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.TestingHost.RandomlyInjectedStorageException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_1150D526 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_1150D526>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_1150D526 DeepCopy(Invokable_IStorageFaultGrain_GrainReference_1150D526 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_1A607A31 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_1A607A31>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_1A607A31 DeepCopy(Invokable_IStorageFaultGrain_GrainReference_1A607A31 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_5D91E1AF : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_5D91E1AF>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_5D91E1AF DeepCopy(Invokable_IStorageFaultGrain_GrainReference_5D91E1AF original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_B9852E6E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_B9852E6E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_B9852E6E DeepCopy(Invokable_IStorageFaultGrain_GrainReference_B9852E6E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_C94BA77C : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_C94BA77C>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_C94BA77C DeepCopy(Invokable_IStorageFaultGrain_GrainReference_C94BA77C original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IStorageFaultGrain_GrainReference_E8594820 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IStorageFaultGrain_GrainReference_E8594820>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IStorageFaultGrain_GrainReference_E8594820 DeepCopy(Invokable_IStorageFaultGrain_GrainReference_E8594820 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RandomlyInjectedInconsistentStateException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.TestingHost.RandomlyInjectedInconsistentStateException, global::Orleans.Storage.InconsistentStateException>\n    {\n        public Copier_RandomlyInjectedInconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RandomlyInjectedStorageException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.TestingHost.RandomlyInjectedStorageException, System.Exception>\n    {\n        public Copier_RandomlyInjectedStorageException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"1150D526\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_1150D526 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public System.Exception arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"1A607A31\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_1A607A31 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public System.Exception arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"5D91E1AF\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_5D91E1AF : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"B9852E6E\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_B9852E6E : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public System.Exception arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"C94BA77C\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_C94BA77C : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.TestingHost.IStorageFaultGrain), \"E8594820\" })]\n    public sealed partial class Invokable_IStorageFaultGrain_GrainReference_E8594820 : global::Orleans.Runtime.TaskRequest\n    {\n        public global::Orleans.Runtime.GrainId arg0;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Transactions/Orleans.Transactions.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans\n{\n    public partial interface ITransactionClient\n    {\n        System.Threading.Tasks.Task RunTransaction(TransactionOption transactionOption, System.Func<System.Threading.Tasks.Task<bool>> transactionDelegate);\n        System.Threading.Tasks.Task RunTransaction(TransactionOption transactionOption, System.Func<System.Threading.Tasks.Task> transactionDelegate);\n    }\n\n    [InvokableCustomInitializer(\"SetTransactionOptions\")]\n    [InvokableBaseType(typeof(Runtime.GrainReference), typeof(System.Threading.Tasks.ValueTask), typeof(TransactionRequest))]\n    [InvokableBaseType(typeof(Runtime.GrainReference), typeof(System.Threading.Tasks.ValueTask<>), typeof(TransactionRequest<>))]\n    [InvokableBaseType(typeof(Runtime.GrainReference), typeof(System.Threading.Tasks.Task), typeof(TransactionTaskRequest))]\n    [InvokableBaseType(typeof(Runtime.GrainReference), typeof(System.Threading.Tasks.Task<>), typeof(TransactionTaskRequest<>))]\n    [System.AttributeUsage(System.AttributeTargets.Method)]\n    public sealed partial class TransactionAttribute : System.Attribute\n    {\n        public TransactionAttribute(TransactionOption requirement) { }\n\n        public TransactionAttribute(TransactionOptionAlias alias) { }\n\n        [System.Obsolete(\"Use [ReadOnly] attribute instead.\")]\n        public bool ReadOnly { get { throw null; } set { } }\n\n        public TransactionOption Requirement { get { throw null; } }\n    }\n\n    public enum TransactionOption\n    {\n        Suppress = 0,\n        CreateOrJoin = 1,\n        Create = 2,\n        Join = 3,\n        Supported = 4,\n        NotAllowed = 5\n    }\n\n    public enum TransactionOptionAlias\n    {\n        Required = 1,\n        RequiresNew = 2,\n        Mandatory = 3,\n        Suppress = 4,\n        Never = 5\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TransactionRequest : TransactionRequestBase\n    {\n        protected TransactionRequest(Serialization.Serializer<Transactions.OrleansTransactionAbortedException> exceptionSerializer, System.IServiceProvider serviceProvider) : base(default!, default!) { }\n\n        protected sealed override System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> BaseInvoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.ValueTask InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public abstract partial class TransactionRequestBase : Runtime.RequestBase, IOutgoingGrainCallFilter, Serialization.IOnDeserialized\n    {\n        [GeneratedActivatorConstructor]\n        protected TransactionRequestBase(Serialization.Serializer<Transactions.OrleansTransactionAbortedException> exceptionSerializer, System.IServiceProvider serviceProvider) { }\n\n        public bool IsAmbientTransactionSuppressed { get { throw null; } }\n\n        public bool IsTransactionRequired { get { throw null; } }\n\n        [Id(1)]\n        public Transactions.TransactionInfo TransactionInfo { get { throw null; } set { } }\n\n        [Id(0)]\n        public TransactionOption TransactionOption { get { throw null; } set { } }\n\n        protected abstract System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> BaseInvoke();\n        public override void Dispose() { }\n\n        public override System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> Invoke() { throw null; }\n\n        System.Threading.Tasks.Task IOutgoingGrainCallFilter.Invoke(IOutgoingGrainCallContext context) { throw null; }\n\n        void Serialization.IOnDeserialized.OnDeserialized(Serialization.DeserializationContext context) { }\n\n        protected void SetTransactionOptions(TransactionOption txOption) { }\n\n        protected void SetTransactionOptions(TransactionOptionAlias txOption) { }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TransactionRequest<TResult> : TransactionRequestBase\n    {\n        protected TransactionRequest(Serialization.Serializer<Transactions.OrleansTransactionAbortedException> exceptionSerializer, System.IServiceProvider serviceProvider) : base(default!, default!) { }\n\n        protected sealed override System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> BaseInvoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.ValueTask<TResult> InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public sealed partial class TransactionResponse : Serialization.Invocation.Response\n    {\n        public override System.Exception Exception { get { throw null; } set { } }\n\n        public Serialization.Invocation.Response InnerResponse { get { throw null; } }\n\n        public override object Result { get { throw null; } set { } }\n\n        [Id(1)]\n        public Transactions.TransactionInfo TransactionInfo { get { throw null; } set { } }\n\n        public static TransactionResponse Create(Serialization.Invocation.Response response, Transactions.TransactionInfo transactionInfo) { throw null; }\n\n        public override void Dispose() { }\n\n        public System.Exception GetException() { throw null; }\n\n        public override T GetResult<T>() { throw null; }\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TransactionTaskRequest : TransactionRequestBase\n    {\n        protected TransactionTaskRequest(Serialization.Serializer<Transactions.OrleansTransactionAbortedException> exceptionSerializer, System.IServiceProvider serviceProvider) : base(default!, default!) { }\n\n        protected sealed override System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> BaseInvoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.Task InvokeInner();\n    }\n\n    [SerializerTransparent]\n    public abstract partial class TransactionTaskRequest<TResult> : TransactionRequestBase\n    {\n        protected TransactionTaskRequest(Serialization.Serializer<Transactions.OrleansTransactionAbortedException> exceptionSerializer, System.IServiceProvider serviceProvider) : base(default!, default!) { }\n\n        protected sealed override System.Threading.Tasks.ValueTask<Serialization.Invocation.Response> BaseInvoke() { throw null; }\n\n        protected abstract System.Threading.Tasks.Task<TResult> InvokeInner();\n    }\n}\n\nnamespace Orleans.Configuration\n{\n    public partial class TransactionalStateOptions\n    {\n        public const int DefaultConfirmationRetryLimit = 3;\n        public static System.TimeSpan DefaultLockTimeout;\n        public const int DefaultMaxLockGroupSize = 20;\n        public static System.TimeSpan DefaultRemoteTransactionPingFrequency;\n        public System.TimeSpan ConfirmationRetryDelay { get { throw null; } set { } }\n\n        public static int ConfirmationRetryLimit { get { throw null; } set { } }\n\n        public static System.TimeSpan DefaultLockAcquireTimeout { get { throw null; } }\n\n        public static System.TimeSpan DefaultPrepareTimeout { get { throw null; } }\n\n        public System.TimeSpan LockAcquireTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan LockTimeout { get { throw null; } set { } }\n\n        public int MaxLockGroupSize { get { throw null; } set { } }\n\n        public System.TimeSpan PrepareTimeout { get { throw null; } set { } }\n\n        public System.TimeSpan RemoteTransactionPingFrequency { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class ClientBuilderExtensions\n    {\n        public static IClientBuilder UseTransactions(this IClientBuilder builder) { throw null; }\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static ISiloBuilder UseTransactions(this ISiloBuilder builder) { throw null; }\n    }\n\n    public static partial class TransactionsServiceCollectionExtensions\n    {\n    }\n}\n\nnamespace Orleans.Transactions\n{\n    public partial class CausalClock\n    {\n        public CausalClock(IClock clock) { }\n\n        public System.DateTime Merge(System.DateTime timestamp) { throw null; }\n\n        public System.DateTime MergeUtcNow(System.DateTime timestamp) { throw null; }\n\n        public System.DateTime UtcNow() { throw null; }\n    }\n\n    public partial class Clock : IClock\n    {\n        public System.DateTime UtcNow() { throw null; }\n    }\n\n    public partial class DefaultTransactionDataCopier<TData> : Abstractions.ITransactionDataCopier<TData>\n    {\n        public DefaultTransactionDataCopier(Serialization.DeepCopier<TData> deepCopier) { }\n\n        public TData DeepCopy(TData original) { throw null; }\n    }\n\n    public partial interface IClock\n    {\n        System.DateTime UtcNow();\n    }\n\n    public partial interface ITransactionAgent\n    {\n        System.Threading.Tasks.Task Abort(TransactionInfo transactionInfo);\n        System.Threading.Tasks.Task<(TransactionalStatus Status, System.Exception exception)> Resolve(TransactionInfo transactionInfo);\n        System.Threading.Tasks.Task<TransactionInfo> StartTransaction(bool readOnly, System.TimeSpan timeout);\n    }\n\n    public partial interface ITransactionalStateStorageEvents<TState>\n        where TState : class, new()\n    {\n        void Cancel(long sequenceNumber);\n        void Collect(System.Guid transactionId);\n        void Commit(System.Guid transactionId, System.DateTime timestamp, System.Collections.Generic.List<ParticipantId> writeResources);\n        void Confirm(long sequenceNumber);\n        void Prepare(long sequenceNumber, System.Guid transactionId, System.DateTime timestamp, ParticipantId transactionManager, TState state);\n        void Read(System.DateTime timestamp);\n    }\n\n    public partial interface ITransactionOverloadDetector\n    {\n        bool IsOverloaded();\n    }\n\n    public partial class NamedTransactionalStateStorageFactory : Abstractions.INamedTransactionalStateStorageFactory\n    {\n        [System.Obsolete(\"Use the NamedTransactionalStateStorageFactory(IGrainContextAccessor contextAccessor) constructor.\")]\n        public NamedTransactionalStateStorageFactory(Runtime.IGrainContextAccessor contextAccessor, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public NamedTransactionalStateStorageFactory(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public Abstractions.ITransactionalStateStorage<TState> Create<TState>(string storageName, string stateName)\n            where TState : class, new() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansBrokenTransactionLockException : OrleansTransactionTransientFailureException\n    {\n        public OrleansBrokenTransactionLockException(string transactionId, string situation, System.Exception innerException) : base(default!, default(string)!) { }\n\n        public OrleansBrokenTransactionLockException(string transactionId, string situation) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansCascadingAbortException : OrleansTransactionTransientFailureException\n    {\n        public OrleansCascadingAbortException(string transactionId, System.Exception innerException) : base(default!, default(string)!) { }\n\n        public OrleansCascadingAbortException(string transactionId, string dependentId) : base(default!, default(string)!) { }\n\n        public OrleansCascadingAbortException(string transactionId) : base(default!, default(string)!) { }\n\n        [Id(0)]\n        public string DependentTransactionId { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansOrphanCallException : OrleansTransactionAbortedException\n    {\n        public OrleansOrphanCallException(string transactionId, int pendingCalls) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansReadOnlyViolatedException : OrleansTransactionAbortedException\n    {\n        public OrleansReadOnlyViolatedException(string transactionId) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansStartTransactionFailedException : OrleansTransactionException\n    {\n        public OrleansStartTransactionFailedException(System.Exception innerException) { }\n    }\n\n    [GenerateSerializer]\n    public partial class OrleansTransactionAbortedException : OrleansTransactionException\n    {\n        [System.Obsolete]\n        protected OrleansTransactionAbortedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public OrleansTransactionAbortedException(string transactionId, System.Exception innerException) { }\n\n        public OrleansTransactionAbortedException(string transactionId, string msg, System.Exception innerException) { }\n\n        public OrleansTransactionAbortedException(string transactionId, string msg) { }\n\n        [Id(0)]\n        public string TransactionId { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public partial class OrleansTransactionException : Runtime.OrleansException\n    {\n        public OrleansTransactionException() { }\n\n        [System.Obsolete]\n        protected OrleansTransactionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public OrleansTransactionException(string message, System.Exception innerException) { }\n\n        public OrleansTransactionException(string message) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionInDoubtException : OrleansTransactionException\n    {\n        public OrleansTransactionInDoubtException(string transactionId, System.Exception exc) { }\n\n        public OrleansTransactionInDoubtException(string transactionId, string msg, System.Exception innerException) { }\n\n        public OrleansTransactionInDoubtException(string transactionId) { }\n\n        [Id(0)]\n        public string TransactionId { get { throw null; } }\n\n        [System.Obsolete]\n        public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionLockUpgradeException : OrleansTransactionTransientFailureException\n    {\n        public OrleansTransactionLockUpgradeException(string transactionId) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionOverloadException : OrleansTransactionException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionPrepareTimeoutException : OrleansTransactionTransientFailureException\n    {\n        public OrleansTransactionPrepareTimeoutException(string transactionId, System.Exception innerException) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionsDisabledException : OrleansTransactionException\n    {\n    }\n\n    [GenerateSerializer]\n    public sealed partial class OrleansTransactionServiceNotAvailableException : OrleansTransactionException\n    {\n    }\n\n    [GenerateSerializer]\n    public partial class OrleansTransactionTransientFailureException : OrleansTransactionAbortedException\n    {\n        [System.Obsolete]\n        protected OrleansTransactionTransientFailureException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(default!, default(string)!) { }\n\n        public OrleansTransactionTransientFailureException(string transactionId, string msg, System.Exception innerException) : base(default!, default(string)!) { }\n\n        public OrleansTransactionTransientFailureException(string transactionId, string msg) : base(default!, default(string)!) { }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public readonly partial struct ParticipantId\n    {\n        private readonly object _dummy;\n        private readonly int _dummyPrimitive;\n        public static readonly System.Collections.Generic.IEqualityComparer<ParticipantId> Comparer;\n        public ParticipantId(string name, Runtime.GrainReference reference, Role supportedRoles) { }\n\n        [Id(0)]\n        public string Name { get { throw null; } }\n\n        [Id(1)]\n        public Runtime.GrainReference Reference { get { throw null; } }\n\n        [Id(2)]\n        public Role SupportedRoles { get { throw null; } }\n\n        public override readonly string ToString() { throw null; }\n\n        [GenerateSerializer]\n        [Immutable]\n        public sealed partial class IdComparer : System.Collections.Generic.IEqualityComparer<ParticipantId>\n        {\n            public bool Equals(ParticipantId x, ParticipantId y) { throw null; }\n\n            public int GetHashCode(ParticipantId obj) { throw null; }\n        }\n\n        [GenerateSerializer]\n        [System.Flags]\n        public enum Role\n        {\n            Resource = 1,\n            Manager = 2,\n            PriorityManager = 4\n        }\n    }\n\n    public static partial class ParticipantRoleExtensions\n    {\n        public static bool IsManager(this ParticipantId participant) { throw null; }\n\n        public static bool IsPriorityManager(this ParticipantId participant) { throw null; }\n\n        public static bool IsResource(this ParticipantId participant) { throw null; }\n\n        public static System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<ParticipantId, Abstractions.AccessCounter>> SelectManagers(this System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<ParticipantId, Abstractions.AccessCounter>> participants) { throw null; }\n\n        public static System.Collections.Generic.IEnumerable<ParticipantId> SelectPriorityManagers(this System.Collections.Generic.IEnumerable<ParticipantId> participants) { throw null; }\n\n        public static System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<ParticipantId, Abstractions.AccessCounter>> SelectResources(this System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<ParticipantId, Abstractions.AccessCounter>> participants) { throw null; }\n\n        public static bool SupportsRoles(this ParticipantId participant, ParticipantId.Role role) { throw null; }\n    }\n\n    public partial class TransactionAgentStatistics : Abstractions.ITransactionAgentStatistics\n    {\n        public long TransactionsFailed { get { throw null; } }\n\n        public long TransactionsStarted { get { throw null; } }\n\n        public long TransactionsSucceeded { get { throw null; } }\n\n        public long TransactionsThrottled { get { throw null; } }\n\n        public static Abstractions.ITransactionAgentStatistics Copy(Abstractions.ITransactionAgentStatistics initialStatistics) { throw null; }\n\n        public void TrackTransactionFailed() { }\n\n        public void TrackTransactionStarted() { }\n\n        public void TrackTransactionSucceeded() { }\n\n        public void TrackTransactionThrottled() { }\n    }\n\n    public partial class TransactionalResourceExtension : Abstractions.ITransactionalResourceExtension, Runtime.IGrainExtension, Runtime.IAddressable\n    {\n        public TransactionalResourceExtension(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public System.Threading.Tasks.Task Abort(string resourceId, System.Guid transactionId) { throw null; }\n\n        public System.Threading.Tasks.Task Cancel(string resourceId, System.Guid transactionId, System.DateTime timeStamp, TransactionalStatus status) { throw null; }\n\n        public System.Threading.Tasks.Task<TransactionalStatus> CommitReadOnly(string resourceId, System.Guid transactionId, Abstractions.AccessCounter accessCount, System.DateTime timeStamp) { throw null; }\n\n        public System.Threading.Tasks.Task Confirm(string resourceId, System.Guid transactionId, System.DateTime timeStamp) { throw null; }\n\n        public System.Threading.Tasks.Task Prepare(string resourceId, System.Guid transactionId, Abstractions.AccessCounter accessCount, System.DateTime timeStamp, ParticipantId transactionManager) { throw null; }\n    }\n\n    public partial class TransactionalStateAttributeMapper : TransactionalStateAttributeMapper<Abstractions.TransactionalStateAttribute>\n    {\n        protected override Abstractions.TransactionalStateConfiguration AttributeToConfig(Abstractions.TransactionalStateAttribute attribute) { throw null; }\n    }\n\n    public abstract partial class TransactionalStateAttributeMapper<TAttribute> : Runtime.IAttributeToFactoryMapper<TAttribute> where TAttribute : IFacetMetadata, Abstractions.ITransactionalStateConfiguration\n    {\n        protected abstract Abstractions.TransactionalStateConfiguration AttributeToConfig(TAttribute attribute);\n        public Factory<Runtime.IGrainContext, object> GetFactory(System.Reflection.ParameterInfo parameter, TAttribute attribute) { throw null; }\n    }\n\n    public partial class TransactionalStateFactory : Abstractions.ITransactionalStateFactory\n    {\n        public TransactionalStateFactory(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public Abstractions.ITransactionalState<TState> Create<TState>(Abstractions.TransactionalStateConfiguration config)\n            where TState : class, new() { throw null; }\n\n        public static Newtonsoft.Json.JsonSerializerSettings GetJsonSerializerSettings(System.IServiceProvider serviceProvider) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class TransactionalStateRecord<TState>\n        where TState : class, new()\n    {\n        [Id(1)]\n        public long CommittedSequenceId { get { throw null; } set { } }\n\n        [Id(0)]\n        public TState CommittedState { get { throw null; } set { } }\n\n        [Id(2)]\n        public Abstractions.TransactionalStateMetaData Metadata { get { throw null; } set { } }\n\n        [Id(3)]\n        public System.Collections.Generic.List<Abstractions.PendingTransactionState<TState>> PendingStates { get { throw null; } set { } }\n    }\n\n    public partial class TransactionalState<TState> : Abstractions.ITransactionalState<TState>, ILifecycleParticipant<Runtime.IGrainLifecycle> where TState : class, new()\n    {\n        public TransactionalState(Abstractions.TransactionalStateConfiguration transactionalStateConfiguration, Runtime.IGrainContextAccessor contextAccessor, Abstractions.ITransactionDataCopier<TState> copier, Runtime.IGrainRuntime grainRuntime, Microsoft.Extensions.Logging.ILogger<TransactionalState<TState>> logger) { }\n\n        public string CurrentTransactionId { get { throw null; } }\n\n        public void Participate(Runtime.IGrainLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task<TResult> PerformRead<TResult>(System.Func<TState, TResult> operation) { throw null; }\n\n        public System.Threading.Tasks.Task<TResult> PerformUpdate<TResult>(System.Func<TState, TResult> updateAction) { throw null; }\n    }\n\n    public enum TransactionalStatus\n    {\n        Ok = 0,\n        PrepareTimeout = 1,\n        CascadingAbort = 2,\n        BrokenLock = 3,\n        LockValidationFailed = 4,\n        ParticipantResponseTimeout = 5,\n        TMResponseTimeout = 6,\n        StorageConflict = 7,\n        PresumedAbort = 8,\n        UnknownException = 9,\n        AssertionFailed = 10,\n        CommitFailure = 11\n    }\n\n    public static partial class TransactionalStatusExtensions\n    {\n        public static OrleansTransactionException ConvertToUserException(this TransactionalStatus status, string transactionId, System.Exception exception) { throw null; }\n\n        public static bool DefinitelyAborted(this TransactionalStatus status) { throw null; }\n    }\n\n    public partial class TransactionCommitterFactory : Abstractions.ITransactionCommitterFactory\n    {\n        public TransactionCommitterFactory(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public Abstractions.ITransactionCommitter<TService> Create<TService>(Abstractions.ITransactionCommitterConfiguration config)\n            where TService : class { throw null; }\n    }\n\n    public partial class TransactionCommitter<TService> : Abstractions.ITransactionCommitter<TService>, ILifecycleParticipant<Runtime.IGrainLifecycle> where TService : class\n    {\n        public TransactionCommitter(Abstractions.ITransactionCommitterConfiguration config, Runtime.IGrainContextAccessor contextAccessor, Abstractions.ITransactionDataCopier<OperationState> copier, Runtime.IGrainRuntime grainRuntime, Microsoft.Extensions.Logging.ILogger<TransactionCommitter<TService>> logger) { }\n\n        public System.Threading.Tasks.Task OnCommit(Abstractions.ITransactionCommitOperation<TService> operation) { throw null; }\n\n        public void Participate(Runtime.IGrainLifecycle lifecycle) { }\n\n        [GenerateSerializer]\n        public sealed partial class OperationState\n        {\n            [Id(0)]\n            public Abstractions.ITransactionCommitOperation<TService> Operation { get { throw null; } set { } }\n        }\n    }\n\n    public static partial class TransactionContext\n    {\n        public static string CurrentTransactionId { get { throw null; } }\n\n        public static TransactionInfo GetRequiredTransactionInfo() { throw null; }\n\n        public static TransactionInfo GetTransactionInfo() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class TransactionInfo\n    {\n        public int PendingCalls;\n        public TransactionInfo() { }\n\n        public TransactionInfo(TransactionInfo other) { }\n\n        public TransactionInfo(System.Guid id, System.DateTime timeStamp, System.DateTime priority, bool readOnly = false) { }\n\n        public string Id { get { throw null; } }\n\n        [Id(3)]\n        public bool IsReadOnly { get { throw null; } }\n\n        [Id(4)]\n        public byte[] OriginalException { get { throw null; } set { } }\n\n        [Id(5)]\n        public System.Collections.Generic.Dictionary<ParticipantId, Abstractions.AccessCounter> Participants { get { throw null; } }\n\n        [Id(2)]\n        public System.DateTime Priority { get { throw null; } set { } }\n\n        [Id(1)]\n        public System.DateTime TimeStamp { get { throw null; } set { } }\n\n        [Id(0)]\n        public System.Guid TransactionId { get { throw null; } }\n\n        [Id(6)]\n        public bool TryToCommit { get { throw null; } }\n\n        public TransactionInfo Fork() { throw null; }\n\n        public void Join(TransactionInfo x) { }\n\n        public OrleansTransactionAbortedException MustAbort(Serialization.Serializer<OrleansTransactionAbortedException> serializer) { throw null; }\n\n        public void ReconcilePending() { }\n\n        public void RecordException(System.Exception e, Serialization.Serializer<OrleansTransactionAbortedException> sm) { }\n\n        public void RecordRead(ParticipantId id, System.DateTime minTime) { }\n\n        public void RecordWrite(ParticipantId id, System.DateTime minTime) { }\n\n        public override string ToString() { throw null; }\n    }\n\n    public partial class TransactionManagerExtension : Abstractions.ITransactionManagerExtension, Runtime.IGrainExtension, Runtime.IAddressable\n    {\n        public TransactionManagerExtension(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public System.Threading.Tasks.Task Ping(string resourceId, System.Guid transactionId, System.DateTime timeStamp, ParticipantId resource) { throw null; }\n\n        public System.Threading.Tasks.Task<TransactionalStatus> PrepareAndCommit(string resourceId, System.Guid transactionId, Abstractions.AccessCounter accessCount, System.DateTime timeStamp, System.Collections.Generic.List<ParticipantId> writeResources, int totalResources) { throw null; }\n\n        public System.Threading.Tasks.Task Prepared(string resourceId, System.Guid transactionId, System.DateTime timestamp, ParticipantId resource, TransactionalStatus status) { throw null; }\n    }\n\n    public partial class TransactionOverloadDetector : ITransactionOverloadDetector\n    {\n        public TransactionOverloadDetector(Abstractions.ITransactionAgentStatistics statistics, Microsoft.Extensions.Options.IOptions<TransactionRateLoadSheddingOptions> options) { }\n\n        public bool IsOverloaded() { throw null; }\n    }\n\n    public partial class TransactionRateLoadSheddingOptions\n    {\n        public const double DEFAULT_LIMIT = 700D;\n        public bool Enabled { get { throw null; } set { } }\n\n        public double Limit { get { throw null; } set { } }\n    }\n}\n\nnamespace Orleans.Transactions.Abstractions\n{\n    [GenerateSerializer]\n    public partial struct AccessCounter\n    {\n        [Id(0)]\n        public int Reads;\n        [Id(1)]\n        public int Writes;\n        public static AccessCounter operator +(AccessCounter c1, AccessCounter c2) { throw null; }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class CommitRecord\n    {\n        [Id(0)]\n        public System.DateTime Timestamp { get { throw null; } set { } }\n\n        [Id(1)]\n        public System.Collections.Generic.List<ParticipantId> WriteParticipants { get { throw null; } set { } }\n    }\n\n    public partial interface INamedTransactionalStateStorageFactory\n    {\n        ITransactionalStateStorage<TState> Create<TState>(string storageName, string stateName)\n            where TState : class, new();\n    }\n\n    public partial interface ITransactionAgentStatistics\n    {\n        long TransactionsFailed { get; }\n\n        long TransactionsStarted { get; }\n\n        long TransactionsSucceeded { get; }\n\n        long TransactionsThrottled { get; }\n\n        void TrackTransactionFailed();\n        void TrackTransactionStarted();\n        void TrackTransactionSucceeded();\n        void TrackTransactionThrottled();\n    }\n\n    public partial interface ITransactionalResource\n    {\n        System.Threading.Tasks.Task Abort(System.Guid transactionId);\n        System.Threading.Tasks.Task Cancel(System.Guid transactionId, System.DateTime timeStamp, TransactionalStatus status);\n        System.Threading.Tasks.Task<TransactionalStatus> CommitReadOnly(System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp);\n        System.Threading.Tasks.Task Confirm(System.Guid transactionId, System.DateTime timeStamp);\n        System.Threading.Tasks.Task Prepare(System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp, ParticipantId transactionManager);\n    }\n\n    public partial interface ITransactionalResourceExtension : Runtime.IGrainExtension, Runtime.IAddressable\n    {\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task Abort(string resourceId, System.Guid transactionId);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task Cancel(string resourceId, System.Guid transactionId, System.DateTime timeStamp, TransactionalStatus status);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task<TransactionalStatus> CommitReadOnly(string resourceId, System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task Confirm(string resourceId, System.Guid transactionId, System.DateTime timeStamp);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [Concurrency.OneWay]\n        System.Threading.Tasks.Task Prepare(string resourceId, System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp, ParticipantId transactionManager);\n    }\n\n    public partial interface ITransactionalStateConfiguration\n    {\n        string StateName { get; }\n\n        string StorageName { get; }\n    }\n\n    public partial interface ITransactionalStateFactory\n    {\n        ITransactionalState<TState> Create<TState>(TransactionalStateConfiguration config)\n            where TState : class, new();\n    }\n\n    public partial interface ITransactionalStateStorageFactory\n    {\n        ITransactionalStateStorage<TState> Create<TState>(string stateName, Runtime.IGrainContext context)\n            where TState : class, new();\n    }\n\n    public partial interface ITransactionalStateStorage<TState>\n        where TState : class, new()\n    {\n        System.Threading.Tasks.Task<TransactionalStorageLoadResponse<TState>> Load();\n        System.Threading.Tasks.Task<string> Store(string expectedETag, TransactionalStateMetaData metadata, System.Collections.Generic.List<PendingTransactionState<TState>> statesToPrepare, long? commitUpTo, long? abortAfter);\n    }\n\n    public partial interface ITransactionalState<TState>\n        where TState : class, new()\n    {\n        System.Threading.Tasks.Task<TResult> PerformRead<TResult>(System.Func<TState, TResult> readFunction);\n        System.Threading.Tasks.Task<TResult> PerformUpdate<TResult>(System.Func<TState, TResult> updateFunction);\n    }\n\n    public partial interface ITransactionCommitOperation<TService>\n        where TService : class\n    {\n        System.Threading.Tasks.Task<bool> Commit(System.Guid transactionId, TService service);\n    }\n\n    public partial interface ITransactionCommitterConfiguration\n    {\n        string ServiceName { get; }\n\n        string StorageName { get; }\n    }\n\n    public partial interface ITransactionCommitterFactory\n    {\n        ITransactionCommitter<TService> Create<TService>(ITransactionCommitterConfiguration config)\n            where TService : class;\n    }\n\n    public partial interface ITransactionCommitter<TService>\n        where TService : class\n    {\n        System.Threading.Tasks.Task OnCommit(ITransactionCommitOperation<TService> operation);\n    }\n\n    public partial interface ITransactionDataCopier<TData>\n    {\n        TData DeepCopy(TData original);\n    }\n\n    public partial interface ITransactionManager\n    {\n        System.Threading.Tasks.Task Ping(System.Guid transactionId, System.DateTime timeStamp, ParticipantId resource);\n        System.Threading.Tasks.Task<TransactionalStatus> PrepareAndCommit(System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp, System.Collections.Generic.List<ParticipantId> writerResources, int totalParticipants);\n        System.Threading.Tasks.Task Prepared(System.Guid transactionId, System.DateTime timeStamp, ParticipantId resource, TransactionalStatus status);\n    }\n\n    public partial interface ITransactionManagerExtension : Runtime.IGrainExtension, Runtime.IAddressable\n    {\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [Concurrency.OneWay]\n        System.Threading.Tasks.Task Ping(string resourceId, System.Guid transactionId, System.DateTime timeStamp, ParticipantId resource);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task<TransactionalStatus> PrepareAndCommit(string resourceId, System.Guid transactionId, AccessCounter accessCount, System.DateTime timeStamp, System.Collections.Generic.List<ParticipantId> writeResources, int totalParticipants);\n        [Concurrency.AlwaysInterleave]\n        [Transaction(TransactionOption.Suppress)]\n        [Concurrency.OneWay]\n        System.Threading.Tasks.Task Prepared(string resourceId, System.Guid transactionId, System.DateTime timestamp, ParticipantId resource, TransactionalStatus status);\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class PendingTransactionState<TState>\n        where TState : class, new()\n    {\n        [Id(0)]\n        public long SequenceId { get { throw null; } set { } }\n\n        [Id(4)]\n        public TState State { get { throw null; } set { } }\n\n        [Id(2)]\n        public System.DateTime TimeStamp { get { throw null; } set { } }\n\n        [Id(1)]\n        public string TransactionId { get { throw null; } set { } }\n\n        [Id(3)]\n        public ParticipantId TransactionManager { get { throw null; } set { } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Parameter)]\n    public partial class TransactionalStateAttribute : System.Attribute, IFacetMetadata, ITransactionalStateConfiguration\n    {\n        public TransactionalStateAttribute(string stateName, string storageName = null) { }\n\n        public string StateName { get { throw null; } }\n\n        public string StorageName { get { throw null; } }\n    }\n\n    public partial class TransactionalStateConfiguration : ITransactionalStateConfiguration\n    {\n        public TransactionalStateConfiguration(ITransactionalStateConfiguration config, ParticipantId.Role supportedRoles = ParticipantId.Role.Resource | ParticipantId.Role.Manager) { }\n\n        public string StateName { get { throw null; } }\n\n        public string StorageName { get { throw null; } }\n\n        public ParticipantId.Role SupportedRoles { get { throw null; } }\n    }\n\n    public static partial class TransactionalStateExtensions\n    {\n        public static System.Threading.Tasks.Task PerformUpdate<TState>(this ITransactionalState<TState> transactionalState, System.Action<TState> updateAction)\n            where TState : class, new() { throw null; }\n    }\n\n    [GenerateSerializer]\n    public sealed partial class TransactionalStateMetaData\n    {\n        [Id(1)]\n        public System.Collections.Generic.Dictionary<System.Guid, CommitRecord> CommitRecords { get { throw null; } set { } }\n\n        [Id(0)]\n        public System.DateTime TimeStamp { get { throw null; } set { } }\n    }\n\n    [GenerateSerializer]\n    [Immutable]\n    public sealed partial class TransactionalStorageLoadResponse<TState>\n        where TState : class, new()\n    {\n        public TransactionalStorageLoadResponse() { }\n\n        public TransactionalStorageLoadResponse(string etag, TState committedState, long committedSequenceId, TransactionalStateMetaData metadata, System.Collections.Generic.IReadOnlyList<PendingTransactionState<TState>> pendingStates) { }\n\n        [Id(2)]\n        public long CommittedSequenceId { get { throw null; } set { } }\n\n        [Id(1)]\n        public TState CommittedState { get { throw null; } set { } }\n\n        [Id(0)]\n        public string ETag { get { throw null; } set { } }\n\n        [Id(3)]\n        public TransactionalStateMetaData Metadata { get { throw null; } set { } }\n\n        [Id(4)]\n        public System.Collections.Generic.IReadOnlyList<PendingTransactionState<TState>> PendingStates { get { throw null; } set { } }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Parameter)]\n    public partial class TransactionCommitterAttribute : System.Attribute, IFacetMetadata, ITransactionCommitterConfiguration\n    {\n        public TransactionCommitterAttribute(string serviceName, string storageName = null) { }\n\n        public string ServiceName { get { throw null; } }\n\n        public string StorageName { get { throw null; } }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionRequestBase : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::Orleans.TransactionRequestBase>\n    {\n        public Codec_TransactionRequestBase(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public override void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.TransactionRequestBase instance) { }\n\n        public override void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.TransactionRequestBase instance) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionResponse : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.TransactionResponse>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_TransactionResponse(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.TransactionResponse instance) { }\n\n        public global::Orleans.TransactionResponse ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.TransactionResponse instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.TransactionResponse value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionRequestBase : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.TransactionRequestBase>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.TransactionRequestBase>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_TransactionRequestBase(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.TransactionRequestBase DeepCopy(global::Orleans.TransactionRequestBase original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.TransactionRequestBase input, global::Orleans.TransactionRequestBase output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionResponse : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.TransactionResponse>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_TransactionResponse(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.TransactionResponse DeepCopy(global::Orleans.TransactionResponse original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansBrokenTransactionLockException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansBrokenTransactionLockException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansBrokenTransactionLockException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansBrokenTransactionLockException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansBrokenTransactionLockException instance) { }\n\n        public global::Orleans.Transactions.OrleansBrokenTransactionLockException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansBrokenTransactionLockException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansBrokenTransactionLockException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansCascadingAbortException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansCascadingAbortException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansCascadingAbortException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansCascadingAbortException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansCascadingAbortException instance) { }\n\n        public global::Orleans.Transactions.OrleansCascadingAbortException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansCascadingAbortException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansCascadingAbortException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansOrphanCallException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansOrphanCallException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansOrphanCallException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansOrphanCallException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansOrphanCallException instance) { }\n\n        public global::Orleans.Transactions.OrleansOrphanCallException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansOrphanCallException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansOrphanCallException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansReadOnlyViolatedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansReadOnlyViolatedException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansReadOnlyViolatedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansReadOnlyViolatedException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansReadOnlyViolatedException instance) { }\n\n        public global::Orleans.Transactions.OrleansReadOnlyViolatedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansReadOnlyViolatedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansReadOnlyViolatedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansStartTransactionFailedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansStartTransactionFailedException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansStartTransactionFailedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansStartTransactionFailedException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansStartTransactionFailedException instance) { }\n\n        public global::Orleans.Transactions.OrleansStartTransactionFailedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansStartTransactionFailedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansStartTransactionFailedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionAbortedException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionAbortedException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.OrleansTransactionAbortedException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_OrleansTransactionAbortedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansTransactionAbortedException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionAbortedException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionAbortedException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionAbortedException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionAbortedException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.OrleansTransactionException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_OrleansTransactionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionInDoubtException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionInDoubtException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionInDoubtException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansTransactionInDoubtException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionInDoubtException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionInDoubtException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionInDoubtException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionInDoubtException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionLockUpgradeException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionLockUpgradeException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionLockUpgradeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansTransactionLockUpgradeException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionLockUpgradeException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionLockUpgradeException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionLockUpgradeException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionLockUpgradeException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionOverloadException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionOverloadException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionOverloadException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionOverloadException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionOverloadException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionOverloadException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionOverloadException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionPrepareTimeoutException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionPrepareTimeoutException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionsDisabledException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionsDisabledException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionsDisabledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionsDisabledException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionsDisabledException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionsDisabledException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionsDisabledException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionServiceNotAvailableException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_OrleansTransactionServiceNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OrleansTransactionTransientFailureException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.OrleansTransactionTransientFailureException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.OrleansTransactionTransientFailureException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_OrleansTransactionTransientFailureException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.OrleansTransactionTransientFailureException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.OrleansTransactionTransientFailureException instance) { }\n\n        public global::Orleans.Transactions.OrleansTransactionTransientFailureException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.OrleansTransactionTransientFailureException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.OrleansTransactionTransientFailureException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ParticipantId : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.ParticipantId>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Transactions.ParticipantId>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public Codec_ParticipantId(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Transactions.ParticipantId instance) { }\n\n        public global::Orleans.Transactions.ParticipantId ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Transactions.ParticipantId instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.ParticipantId value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionalStateRecord<TState> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TransactionalStateRecord<TState>>, global::Orleans.Serialization.Codecs.IFieldCodec where TState : class, new()\n    {\n        public Codec_TransactionalStateRecord(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TransactionalStateRecord<TState> instance) { }\n\n        public global::Orleans.Transactions.TransactionalStateRecord<TState> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TransactionalStateRecord<TState> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TransactionalStateRecord<TState> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionInfo : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TransactionInfo>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_TransactionInfo(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TransactionInfo instance) { }\n\n        public global::Orleans.Transactions.TransactionInfo ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TransactionInfo instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TransactionInfo value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansBrokenTransactionLockException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansBrokenTransactionLockException, global::Orleans.Transactions.OrleansTransactionTransientFailureException>\n    {\n        public Copier_OrleansBrokenTransactionLockException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansCascadingAbortException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansCascadingAbortException, global::Orleans.Transactions.OrleansTransactionTransientFailureException>\n    {\n        public Copier_OrleansCascadingAbortException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Transactions.OrleansCascadingAbortException input, global::Orleans.Transactions.OrleansCascadingAbortException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansOrphanCallException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansOrphanCallException, global::Orleans.Transactions.OrleansTransactionAbortedException>\n    {\n        public Copier_OrleansOrphanCallException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansReadOnlyViolatedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansReadOnlyViolatedException, global::Orleans.Transactions.OrleansTransactionAbortedException>\n    {\n        public Copier_OrleansReadOnlyViolatedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansStartTransactionFailedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansStartTransactionFailedException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansStartTransactionFailedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionAbortedException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionAbortedException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansTransactionAbortedException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Transactions.OrleansTransactionAbortedException input, global::Orleans.Transactions.OrleansTransactionAbortedException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionException, global::Orleans.Runtime.OrleansException>\n    {\n        public Copier_OrleansTransactionException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionInDoubtException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionInDoubtException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansTransactionInDoubtException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n\n        public override void DeepCopy(global::Orleans.Transactions.OrleansTransactionInDoubtException input, global::Orleans.Transactions.OrleansTransactionInDoubtException output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionLockUpgradeException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionLockUpgradeException, global::Orleans.Transactions.OrleansTransactionTransientFailureException>\n    {\n        public Copier_OrleansTransactionLockUpgradeException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionOverloadException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionOverloadException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansTransactionOverloadException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionPrepareTimeoutException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionPrepareTimeoutException, global::Orleans.Transactions.OrleansTransactionTransientFailureException>\n    {\n        public Copier_OrleansTransactionPrepareTimeoutException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionsDisabledException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionsDisabledException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansTransactionsDisabledException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionServiceNotAvailableException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionServiceNotAvailableException, global::Orleans.Transactions.OrleansTransactionException>\n    {\n        public Copier_OrleansTransactionServiceNotAvailableException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OrleansTransactionTransientFailureException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.OrleansTransactionTransientFailureException, global::Orleans.Transactions.OrleansTransactionAbortedException>\n    {\n        public Copier_OrleansTransactionTransientFailureException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionalStateRecord<TState> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TransactionalStateRecord<TState>>, global::Orleans.Serialization.Cloning.IDeepCopier where TState : class, new()\n    {\n        public Copier_TransactionalStateRecord(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TransactionalStateRecord<TState> DeepCopy(global::Orleans.Transactions.TransactionalStateRecord<TState> original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionInfo : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TransactionInfo>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_TransactionInfo(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TransactionInfo DeepCopy(global::Orleans.Transactions.TransactionInfo original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.Abstractions\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AccessCounter : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.Abstractions.AccessCounter>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Transactions.Abstractions.AccessCounter>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Transactions.Abstractions.AccessCounter instance) { }\n\n        public global::Orleans.Transactions.Abstractions.AccessCounter ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Transactions.Abstractions.AccessCounter instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.Abstractions.AccessCounter value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CommitRecord : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.Abstractions.CommitRecord>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_CommitRecord(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.Abstractions.CommitRecord instance) { }\n\n        public global::Orleans.Transactions.Abstractions.CommitRecord ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.Abstractions.CommitRecord instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.Abstractions.CommitRecord value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE instance) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 instance) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 instance) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 instance) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 instance) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 instance) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB instance) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 instance) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_PendingTransactionState<TState> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.Abstractions.PendingTransactionState<TState>>, global::Orleans.Serialization.Codecs.IFieldCodec where TState : class, new()\n    {\n        public Codec_PendingTransactionState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.Abstractions.PendingTransactionState<TState> instance) { }\n\n        public global::Orleans.Transactions.Abstractions.PendingTransactionState<TState> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.Abstractions.PendingTransactionState<TState> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.Abstractions.PendingTransactionState<TState> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionalStateMetaData : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.Abstractions.TransactionalStateMetaData>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_TransactionalStateMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.Abstractions.TransactionalStateMetaData instance) { }\n\n        public global::Orleans.Transactions.Abstractions.TransactionalStateMetaData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.Abstractions.TransactionalStateMetaData instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.Abstractions.TransactionalStateMetaData value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionalStorageLoadResponse<TState> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState>>, global::Orleans.Serialization.Codecs.IFieldCodec where TState : class, new()\n    {\n        public Codec_TransactionalStorageLoadResponse(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState> instance) { }\n\n        public global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState> instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE> _activator) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE DeepCopy(Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608> _activator) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 DeepCopy(Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0> _activator) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 DeepCopy(Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9> _activator) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 DeepCopy(Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23> _activator) { }\n\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 DeepCopy(Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17> _activator) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 DeepCopy(Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB> _activator) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB DeepCopy(Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6> _activator) { }\n\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 DeepCopy(Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_PendingTransactionState<TState> : global::Orleans.Serialization.Cloning.ShallowCopier<global::Orleans.Transactions.Abstractions.PendingTransactionState<TState>> where TState : class, new()\n    {\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionalStateMetaData : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.Abstractions.TransactionalStateMetaData>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_TransactionalStateMetaData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.Abstractions.TransactionalStateMetaData DeepCopy(global::Orleans.Transactions.Abstractions.TransactionalStateMetaData original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_TransactionalStorageLoadResponse<TState> : global::Orleans.Serialization.Cloning.ShallowCopier<global::Orleans.Transactions.Abstractions.TransactionalStorageLoadResponse<TState>> where TState : class, new()\n    {\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), \"1BB071FE\" })]\n    public sealed partial class Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE : global::Orleans.TransactionTaskRequest<global::Orleans.Transactions.TransactionalStatus>\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public global::Orleans.Transactions.Abstractions.AccessCounter arg2;\n        public System.DateTime arg3;\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_1BB071FE(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Transactions.TransactionalStatus> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), \"2ADCC608\" })]\n    public sealed partial class Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608 : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public global::Orleans.Transactions.Abstractions.AccessCounter arg2;\n        public System.DateTime arg3;\n        public global::Orleans.Transactions.ParticipantId arg4;\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_2ADCC608(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), \"5DDDE6F0\" })]\n    public sealed partial class Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0 : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public System.DateTime arg2;\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_5DDDE6F0(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), \"80028AB9\" })]\n    public sealed partial class Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9 : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public System.DateTime arg2;\n        public global::Orleans.Transactions.TransactionalStatus arg3;\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_80028AB9(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionalResourceExtension), \"BD051D23\" })]\n    public sealed partial class Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23 : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public Invokable_ITransactionalResourceExtension_GrainReference_Ext_BD051D23(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), \"12BEFA17\" })]\n    public sealed partial class Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17 : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public System.DateTime arg2;\n        public global::Orleans.Transactions.ParticipantId arg3;\n        public global::Orleans.Transactions.TransactionalStatus arg4;\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_12BEFA17(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), \"AC4A9AEB\" })]\n    public sealed partial class Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB : global::Orleans.TransactionTaskRequest\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public System.DateTime arg2;\n        public global::Orleans.Transactions.ParticipantId arg3;\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_AC4A9AEB(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), \"Ext\", typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), typeof(global::Orleans.Transactions.Abstractions.ITransactionManagerExtension), \"B024EFA6\" })]\n    public sealed partial class Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6 : global::Orleans.TransactionTaskRequest<global::Orleans.Transactions.TransactionalStatus>\n    {\n        public string arg0;\n        public System.Guid arg1;\n        public global::Orleans.Transactions.Abstractions.AccessCounter arg2;\n        public System.DateTime arg3;\n        public System.Collections.Generic.List<global::Orleans.Transactions.ParticipantId> arg4;\n        public int arg5;\n        public Invokable_ITransactionManagerExtension_GrainReference_Ext_B024EFA6(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Transactions.TransactionalStatus> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.ParticipantId\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_IdComparer : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.ParticipantId.IdComparer>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.ParticipantId.IdComparer instance) { }\n\n        public global::Orleans.Transactions.ParticipantId.IdComparer ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.ParticipantId.IdComparer instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.ParticipantId.IdComparer value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Role : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.ParticipantId.Role>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Transactions.ParticipantId.Role ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.ParticipantId.Role value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TransactionCommitter\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_OperationState<TService> : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TransactionCommitter<TService>.OperationState>, global::Orleans.Serialization.Codecs.IFieldCodec where TService : class\n    {\n        public Codec_OperationState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TransactionCommitter<TService>.OperationState instance) { }\n\n        public global::Orleans.Transactions.TransactionCommitter<TService>.OperationState ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TransactionCommitter<TService>.OperationState instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TransactionCommitter<TService>.OperationState value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_OperationState<TService> : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TransactionCommitter<TService>.OperationState>, global::Orleans.Serialization.Cloning.IDeepCopier where TService : class\n    {\n        public Copier_OperationState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TransactionCommitter<TService>.OperationState DeepCopy(global::Orleans.Transactions.TransactionCommitter<TService>.OperationState original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Transactions.TestKit.Base/Orleans.Transactions.TestKit.Base.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class TransactionFaultInjectionServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseControlledFaultInjectionTransactionState(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; }\n    }\n}\n\nnamespace Orleans.Transactions.TestKit\n{\n    [GenerateSerializer]\n    public partial class AddAndThrowException : System.Exception\n    {\n        public AddAndThrowException() { }\n\n        [System.Obsolete]\n        protected AddAndThrowException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public AddAndThrowException(string message, System.Exception innerException) { }\n\n        public AddAndThrowException(string message) { }\n    }\n\n    public abstract partial class ConsistencyTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected ConsistencyTransactionTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        protected abstract bool StorageAdaptorHasLimitedCommitSpace { get; }\n        protected abstract bool StorageErrorInjectionActive { get; }\n\n        public virtual System.Threading.Tasks.Task RandomizedConsistency(int numGrains, int scale, bool avoidDeadlocks, bool avoidTimeouts, Consistency.ReadWriteDetermination readwrite) { throw null; }\n    }\n\n    public partial class ControlledFaultInjectionTransactionTestRunner : TransactionTestRunnerBase\n    {\n        public ControlledFaultInjectionTransactionTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task MultiGrainWriteTransaction_FaultInjection(TransactionFaultInjectPhase injectionPhase, FaultInjectionType injectionType) { throw null; }\n\n        public virtual System.Threading.Tasks.Task SingleGrainReadTransaction() { throw null; }\n\n        public virtual System.Threading.Tasks.Task SingleGrainWriteTransaction() { throw null; }\n    }\n\n    public partial class CreateAttributionGrain : Grain, ICreateAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    public partial class CreateOrJoinAttributionGrain : Grain, ICreateOrJoinAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    public abstract partial class DisabledTransactionsTestRunner : TransactionTestRunnerBase\n    {\n        protected DisabledTransactionsTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual void MultiTransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName) { }\n\n        public virtual void TransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName) { }\n    }\n\n    public partial class DoubleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public DoubleStateTransactionalGrain(Abstractions.ITransactionalState<GrainData> data1, Abstractions.ITransactionalState<GrainData> data2, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    [GenerateSerializer]\n    public partial class FailOperation : Abstractions.ITransactionCommitOperation<IRemoteCommitService>\n    {\n        public FailOperation(string data) { }\n\n        [Id(0)]\n        public string Data { get { throw null; } set { } }\n\n        public System.Threading.Tasks.Task<bool> Commit(System.Guid transactionId, IRemoteCommitService service) { throw null; }\n    }\n\n    public partial class FaultInjectionAzureTableTransactionStateStorageFactory : Abstractions.ITransactionalStateStorageFactory, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public FaultInjectionAzureTableTransactionStateStorageFactory(AzureStorage.AzureTableTransactionalStateStorageFactory factory) { }\n\n        public static Abstractions.ITransactionalStateStorageFactory Create(System.IServiceProvider services, string name) { throw null; }\n\n        public Abstractions.ITransactionalStateStorage<TState> Create<TState>(string stateName, Runtime.IGrainContext context)\n            where TState : class, new() { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n    }\n\n    public partial class FaultInjectionAzureTableTransactionStateStorage<TState> : Abstractions.ITransactionalStateStorage<TState> where TState : class, new()\n    {\n        public FaultInjectionAzureTableTransactionStateStorage(ITransactionFaultInjector faultInjector, AzureStorage.AzureTableTransactionalStateStorage<TState> azureStateStorage) { }\n\n        public System.Threading.Tasks.Task<Abstractions.TransactionalStorageLoadResponse<TState>> Load() { throw null; }\n\n        public System.Threading.Tasks.Task<string> Store(string expectedETag, Abstractions.TransactionalStateMetaData metadata, System.Collections.Generic.List<Abstractions.PendingTransactionState<TState>> statesToPrepare, long? commitUpTo, long? abortAfter) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class FaultInjectionControl\n    {\n        [Id(0)]\n        public TransactionFaultInjectPhase FaultInjectionPhase;\n        [Id(1)]\n        public FaultInjectionType FaultInjectionType;\n        public void Reset() { }\n    }\n\n    [System.AttributeUsage(System.AttributeTargets.Parameter)]\n    public partial class FaultInjectionTransactionalStateAttribute : System.Attribute, IFacetMetadata, IFaultInjectionTransactionalStateConfiguration, Abstractions.ITransactionalStateConfiguration\n    {\n        public FaultInjectionTransactionalStateAttribute(string stateName, string storageName = null) { }\n\n        public string StateName { get { throw null; } }\n\n        public string StorageName { get { throw null; } }\n    }\n\n    public partial class FaultInjectionTransactionalStateAttributeMapper : Runtime.IAttributeToFactoryMapper<FaultInjectionTransactionalStateAttribute>\n    {\n        public Factory<Runtime.IGrainContext, object> GetFactory(System.Reflection.ParameterInfo parameter, FaultInjectionTransactionalStateAttribute attribute) { throw null; }\n    }\n\n    public partial class FaultInjectionTransactionalStateFactory : IFaultInjectionTransactionalStateFactory\n    {\n        public FaultInjectionTransactionalStateFactory(Runtime.IGrainContextAccessor contextAccessor) { }\n\n        public IFaultInjectionTransactionalState<TState> Create<TState>(IFaultInjectionTransactionalStateConfiguration config)\n            where TState : class, new() { throw null; }\n    }\n\n    public partial class FaultInjectionTransactionCoordinatorGrain : Grain, IFaultInjectionTransactionCoordinatorGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task MultiGrainAddAndFaultInjection(System.Collections.Generic.List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd, FaultInjectionControl faultInjection = null) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainSet(System.Collections.Generic.List<IFaultInjectionTransactionTestGrain> grains, int newValue) { throw null; }\n    }\n\n    public enum FaultInjectionType\n    {\n        None = 0,\n        Deactivation = 1,\n        ExceptionBeforeStore = 2,\n        ExceptionAfterStore = 3\n    }\n\n    public abstract partial class GoldenPathTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected GoldenPathTransactionTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task MultiGrainReadWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        public virtual System.Threading.Tasks.Task MultiGrainWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        public virtual System.Threading.Tasks.Task MultiWriteToSingleGrainTransaction(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task RepeatGrainReadWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        public virtual System.Threading.Tasks.Task RWRWTest(string grainStates, int grainCount) { throw null; }\n\n        public virtual System.Threading.Tasks.Task SingleGrainReadTransaction(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task SingleGrainWriteTransaction(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task WRWRTest(string grainStates, int grainCount) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class GrainData\n    {\n        [Id(0)]\n        public int Value { get { throw null; } set { } }\n    }\n\n    public abstract partial class GrainFaultTransactionTestRunner : TransactionTestRunnerBase\n    {\n        public GrainFaultTransactionTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task AbortTransactionExceptionInnerExceptionOnlyContainsOneRootCauseException(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task AbortTransactionOnExceptions(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task AbortTransactionOnOrphanCalls(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task AbortTransactionOnReadOnlyViolatedException(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task MultiGrainAbortTransactionOnExceptions(string grainStates) { throw null; }\n    }\n\n    public partial interface IControlledTransactionFaultInjector : ITransactionFaultInjector\n    {\n        bool InjectAfterStore { get; set; }\n\n        bool InjectBeforeStore { get; set; }\n    }\n\n    public partial interface ICreateAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface ICreateOrJoinAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface IFaultInjectionTransactionalStateConfiguration : Abstractions.ITransactionalStateConfiguration\n    {\n    }\n\n    public partial interface IFaultInjectionTransactionalStateFactory\n    {\n        IFaultInjectionTransactionalState<TState> Create<TState>(IFaultInjectionTransactionalStateConfiguration config)\n            where TState : class, new();\n    }\n\n    public partial interface IFaultInjectionTransactionalState<TState> : Abstractions.ITransactionalState<TState> where TState : class, new()\n    {\n        FaultInjectionControl FaultInjectionControl { get; set; }\n    }\n\n    public partial interface IFaultInjectionTransactionCoordinatorGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainAddAndFaultInjection(System.Collections.Generic.List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd, FaultInjectionControl faultInjection = null);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainSet(System.Collections.Generic.List<IFaultInjectionTransactionTestGrain> grains, int numberToAdd);\n    }\n\n    public partial interface IFaultInjectionTransactionTestGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task Add(int numberToAdd, FaultInjectionControl faultInjectionControl = null);\n        System.Threading.Tasks.Task Deactivate();\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<int> Get();\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task Set(int newValue);\n    }\n\n    public partial interface IJoinAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOptionAlias.Mandatory)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface INoAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface INotAllowedAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.NotAllowed)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface IRemoteCommitService\n    {\n        System.Threading.Tasks.Task<bool> Fail(System.Guid transactionId, string data);\n        System.Threading.Tasks.Task<bool> Pass(System.Guid transactionId, string data);\n        System.Threading.Tasks.Task<bool> Throw(System.Guid transactionId, string data);\n    }\n\n    public partial interface ISupportedAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Supported)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface ISuppressAttributionGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Suppress)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface ITestState\n    {\n        int state { get; set; }\n    }\n\n    public partial interface ITransactionAttributionGrain\n    {\n        System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers);\n    }\n\n    public partial interface ITransactionCommitterTestGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Join)]\n        System.Threading.Tasks.Task Commit(Abstractions.ITransactionCommitOperation<IRemoteCommitService> operation);\n    }\n\n    public partial interface ITransactionCoordinatorGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task AddAndThrow(ITransactionTestGrain grain, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainAdd(ITransactionCommitterTestGrain committer, Abstractions.ITransactionCommitOperation<IRemoteCommitService> operation, System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainAdd(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainAddAndThrow(System.Collections.Generic.List<ITransactionTestGrain> grain, System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainDouble(System.Collections.Generic.List<ITransactionTestGrain> grains);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainDoubleByRWRW(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainDoubleByWRWR(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainSet(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task MultiGrainSetBit(System.Collections.Generic.List<Correctnesss.ITransactionalBitArrayGrain> grains, int bitIndex);\n        [Transaction(TransactionOption.Create)]\n        System.Threading.Tasks.Task OrphanCallTransaction();\n        [Transaction(TransactionOption.Create)]\n        [Concurrency.ReadOnly]\n        System.Threading.Tasks.Task UpdateViolated(ITransactionTestGrain grains, int numberToAdd);\n    }\n\n    public partial interface ITransactionFaultInjector\n    {\n        void AfterStore();\n        void BeforeStore();\n    }\n\n    public partial interface ITransactionTestGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<int[]> Add(int numberToAdd);\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task AddAndThrow(int numberToAdd);\n        System.Threading.Tasks.Task Deactivate();\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<int[]> Get();\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task Set(int newValue);\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task SetAndThrow(int numberToSet);\n    }\n\n    public partial class JoinAttributionGrain : Grain, IJoinAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    public partial class MaxStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public MaxStateTransactionalGrain(Abstractions.ITransactionalStateFactory stateFactory, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    public partial class MultiStateTransactionalGrainBaseClass : Grain, ITransactionTestGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        protected Abstractions.ITransactionalState<GrainData>[] dataArray;\n        protected Microsoft.Extensions.Logging.ILogger logger;\n        public MultiStateTransactionalGrainBaseClass(Abstractions.ITransactionalState<GrainData>[] dataArray, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task<int[]> Add(int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task AddAndThrow(int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task Deactivate() { throw null; }\n\n        public System.Threading.Tasks.Task<int[]> Get() { throw null; }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task Set(int newValue) { throw null; }\n\n        public System.Threading.Tasks.Task SetAndThrow(int numberToSet) { throw null; }\n    }\n\n    public partial class NoAttributionGrain : Grain, INoAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    public partial class NoStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public NoStateTransactionalGrain(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    public partial class NotAllowedAttributionGrain : Grain, INotAllowedAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class PassOperation : Abstractions.ITransactionCommitOperation<IRemoteCommitService>\n    {\n        public PassOperation(string data) { }\n\n        [Id(0)]\n        public string Data { get { throw null; } set { } }\n\n        public System.Threading.Tasks.Task<bool> Commit(System.Guid transactionId, IRemoteCommitService service) { throw null; }\n    }\n\n    public partial class RandomErrorInjector : ITransactionFaultInjector\n    {\n        public RandomErrorInjector(double injectionProbability) { }\n\n        public void AfterStore() { }\n\n        public void BeforeStore() { }\n\n        [GenerateSerializer]\n        public partial class RandomlyInjectedInconsistentStateException : Storage.InconsistentStateException\n        {\n            public RandomlyInjectedInconsistentStateException() { }\n\n            [System.Obsolete]\n            protected RandomlyInjectedInconsistentStateException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n        }\n\n        [GenerateSerializer]\n        public partial class RandomlyInjectedStorageException : System.Exception\n        {\n            public RandomlyInjectedStorageException() { }\n\n            [System.Obsolete]\n            protected RandomlyInjectedStorageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n        }\n    }\n\n    public partial class RemoteCommitService : IRemoteCommitService\n    {\n        public RemoteCommitService(Microsoft.Extensions.Logging.ILogger<RemoteCommitService> logger) { }\n\n        public System.Threading.Tasks.Task<bool> Fail(System.Guid transactionId, string data) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> Pass(System.Guid transactionId, string data) { throw null; }\n\n        public System.Threading.Tasks.Task<bool> Throw(System.Guid transactionId, string data) { throw null; }\n    }\n\n    public abstract partial class ScopedTransactionsTestRunner : TransactionTestRunnerBase\n    {\n        protected ScopedTransactionsTestRunner(IGrainFactory grainFactory, ITransactionClient transactionClient, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task CreateNestedTransactionScopeAndSetValueAndInnerFailAndAssert(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task CreateTransactionScopeAndSetValue(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task CreateTransactionScopeAndSetValueAndAssert(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task CreateTransactionScopeAndSetValueWithFailure(string grainStates) { throw null; }\n    }\n\n    public static partial class SiloBuilderExtensions\n    {\n        public static Hosting.ISiloBuilder AddFaultInjectionAzureTableTransactionalStateStorage(this Hosting.ISiloBuilder builder, System.Action<Configuration.AzureTableTransactionalStateOptions> configureOptions) { throw null; }\n\n        public static Hosting.ISiloBuilder AddFaultInjectionAzureTableTransactionalStateStorage(this Hosting.ISiloBuilder builder, string name, System.Action<Configuration.AzureTableTransactionalStateOptions> configureOptions) { throw null; }\n\n        public static Hosting.ISiloBuilder UseControlledFaultInjectionTransactionState(this Hosting.ISiloBuilder builder) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class SimpleAzureStorageException : Azure.RequestFailedException\n    {\n        public SimpleAzureStorageException(int status, string message, System.Exception innerException) : base(default(string)!) { }\n\n        public SimpleAzureStorageException(int status, string message, string errorCode, System.Exception innerException) : base(default(string)!) { }\n\n        public SimpleAzureStorageException(int status, string message) : base(default(string)!) { }\n\n        [System.Obsolete(\"TThe serialization constructor pattern was made obsolete in modern versions of .NET. Use the other constructors instead.\")]\n        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n        protected SimpleAzureStorageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(default(string)!) { }\n\n        public SimpleAzureStorageException(string message, System.Exception innerException) : base(default(string)!) { }\n\n        public SimpleAzureStorageException(string message) : base(default(string)!) { }\n    }\n\n    public partial class SimpleAzureStorageExceptionInjector : IControlledTransactionFaultInjector, ITransactionFaultInjector\n    {\n        public SimpleAzureStorageExceptionInjector(Microsoft.Extensions.Logging.ILogger<SimpleAzureStorageExceptionInjector> logger) { }\n\n        public bool InjectAfterStore { get { throw null; } set { } }\n\n        public bool InjectBeforeStore { get { throw null; } set { } }\n\n        public void AfterStore() { }\n\n        public void BeforeStore() { }\n    }\n\n    public partial class SingleStateFaultInjectionTransactionalGrain : Grain, IFaultInjectionTransactionTestGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public SingleStateFaultInjectionTransactionalGrain(IFaultInjectionTransactionalState<GrainData> data, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task Add(int numberToAdd, FaultInjectionControl faultInjectionControl = null) { throw null; }\n\n        public System.Threading.Tasks.Task Deactivate() { throw null; }\n\n        public System.Threading.Tasks.Task<int> Get() { throw null; }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task Set(int newValue) { throw null; }\n    }\n\n    public partial class SingleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass\n    {\n        public SingleStateTransactionalGrain(Abstractions.ITransactionalState<GrainData> data, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    public partial class SkewedClock : IClock\n    {\n        public SkewedClock(System.TimeSpan minSkew, System.TimeSpan maxSkew) { }\n\n        public System.DateTime UtcNow() { throw null; }\n    }\n\n    public partial class SkewedClockConfigurator : TestingHost.ISiloConfigurator\n    {\n        public void Configure(Hosting.ISiloBuilder hostBuilder) { }\n    }\n\n    public partial class SupportedAttributionGrain : Grain, ISupportedAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    public partial class SuppressAttributionGrain : Grain, ISuppressAttributionGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class ThrowOperation : Abstractions.ITransactionCommitOperation<IRemoteCommitService>\n    {\n        public ThrowOperation(string data) { }\n\n        [Id(0)]\n        public string Data { get { throw null; } set { } }\n\n        public System.Threading.Tasks.Task<bool> Commit(System.Guid transactionId, IRemoteCommitService service) { throw null; }\n    }\n\n    public abstract partial class TocFaultTransactionTestRunner : TransactionTestRunnerBase\n    {\n        protected TocFaultTransactionTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task MultiGrainWriteTransactionWithCommitException(string grainStates, int grainCount) { throw null; }\n\n        public virtual System.Threading.Tasks.Task MultiGrainWriteTransactionWithCommitFailure(string grainStates, int grainCount) { throw null; }\n    }\n\n    public abstract partial class TocGoldenPathTestRunner : TransactionTestRunnerBase\n    {\n        protected TocGoldenPathTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task MultiGrainWriteTransaction(string grainStates, int grainCount) { throw null; }\n    }\n\n    public abstract partial class TransactionalStateStorageTestRunner<TState> : TransactionTestRunnerBase where TState : class, new()\n    {\n        protected System.Func<FluentAssertions.Equivalency.EquivalencyOptions<TState>, FluentAssertions.Equivalency.EquivalencyOptions<TState>> assertConfig;\n        protected System.Func<int, TState> stateFactory;\n        protected System.Func<System.Threading.Tasks.Task<Abstractions.ITransactionalStateStorage<TState>>> stateStorageFactory;\n        protected TransactionalStateStorageTestRunner(System.Func<System.Threading.Tasks.Task<Abstractions.ITransactionalStateStorage<TState>>> stateStorageFactory, System.Func<int, TState> stateFactory, IGrainFactory grainFactory, System.Action<string> testOutput, System.Func<FluentAssertions.Equivalency.EquivalencyOptions<TState>, FluentAssertions.Equivalency.EquivalencyOptions<TState>> assertConfig = null) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task CancelMany(int count) { throw null; }\n\n        public virtual System.Threading.Tasks.Task CancelOne() { throw null; }\n\n        public virtual System.Threading.Tasks.Task ConfirmMany(int count, bool useTwoSteps) { throw null; }\n\n        public virtual System.Threading.Tasks.Task ConfirmOne(bool useTwoSteps) { throw null; }\n\n        public virtual System.Threading.Tasks.Task ConfirmOneAndCancelOne(bool useTwoSteps = false, bool reverseOrder = false) { throw null; }\n\n        public virtual System.Threading.Tasks.Task FirstTime_Load_ShouldReturnEmptyLoadResponse() { throw null; }\n\n        public virtual System.Threading.Tasks.Task GrowingBatch() { throw null; }\n\n        public virtual System.Threading.Tasks.Task PrepareMany(int count) { throw null; }\n\n        public virtual System.Threading.Tasks.Task ReplaceMany(int count) { throw null; }\n\n        public virtual System.Threading.Tasks.Task ReplaceOne() { throw null; }\n\n        public virtual System.Threading.Tasks.Task ShrinkingBatch() { throw null; }\n\n        public virtual System.Threading.Tasks.Task StoreWithoutChanges() { throw null; }\n\n        public virtual System.Threading.Tasks.Task WrongEtags() { throw null; }\n    }\n\n    public static partial class TransactionAttributionGrainExtensions\n    {\n        public static ITransactionAttributionGrain GetTransactionAttributionGrain(this IGrainFactory grainFactory, System.Guid id, TransactionOption? option = null) { throw null; }\n\n        [GenerateSerializer]\n        public partial class CreateAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ICreateAttributionGrain grain;\n            public CreateAttributionGrain(ICreateAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class CreateOrJoinAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ICreateOrJoinAttributionGrain grain;\n            public CreateOrJoinAttributionGrain(ICreateOrJoinAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class JoinAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public IJoinAttributionGrain grain;\n            public JoinAttributionGrain(IJoinAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class NoAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public INoAttributionGrain grain;\n            public NoAttributionGrain(INoAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class NotAllowedAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public INotAllowedAttributionGrain grain;\n            public NotAllowedAttributionGrain(INotAllowedAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class SupportedAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ISupportedAttributionGrain grain;\n            public SupportedAttributionGrain(ISupportedAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n\n        [GenerateSerializer]\n        public partial class SuppressAttributionGrain : ITransactionAttributionGrain\n        {\n            [Id(0)]\n            public ISuppressAttributionGrain grain;\n            public SuppressAttributionGrain(ISuppressAttributionGrain grain) { }\n\n            public System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> GetNestedTransactionIds(int tier, System.Collections.Generic.List<ITransactionAttributionGrain>[] tiers) { throw null; }\n        }\n    }\n\n    public partial class TransactionCommitterTestGrain : Grain, ITransactionCommitterTestGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        protected Abstractions.ITransactionCommitter<IRemoteCommitService> committer;\n        protected Microsoft.Extensions.Logging.ILogger logger;\n        public TransactionCommitterTestGrain(Abstractions.ITransactionCommitter<IRemoteCommitService> committer, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task Commit(Abstractions.ITransactionCommitOperation<IRemoteCommitService> operation) { throw null; }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n    }\n\n    public abstract partial class TransactionConcurrencyTestRunner : TransactionTestRunnerBase\n    {\n        protected TransactionConcurrencyTestRunner(IGrainFactory grainFactory, System.Action<string> output) : base(default!, default!) { }\n\n        public virtual System.Threading.Tasks.Task SingleSharedGrainTest(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task TransactionChainTest(string grainStates) { throw null; }\n\n        public virtual System.Threading.Tasks.Task TransactionTreeTest(string grainStates) { throw null; }\n    }\n\n    [Concurrency.StatelessWorker]\n    public partial class TransactionCoordinatorGrain : Grain, ITransactionCoordinatorGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        public System.Threading.Tasks.Task AddAndThrow(ITransactionTestGrain grain, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainAdd(ITransactionCommitterTestGrain committer, Abstractions.ITransactionCommitOperation<IRemoteCommitService> operation, System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainAdd(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainAddAndThrow(System.Collections.Generic.List<ITransactionTestGrain> throwGrains, System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainDouble(System.Collections.Generic.List<ITransactionTestGrain> grains) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainDoubleByRWRW(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainDoubleByWRWR(System.Collections.Generic.List<ITransactionTestGrain> grains, int numberToAdd) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainSet(System.Collections.Generic.List<ITransactionTestGrain> grains, int newValue) { throw null; }\n\n        public System.Threading.Tasks.Task MultiGrainSetBit(System.Collections.Generic.List<Correctnesss.ITransactionalBitArrayGrain> grains, int bitIndex) { throw null; }\n\n        public System.Threading.Tasks.Task OrphanCallTransaction() { throw null; }\n\n        public System.Threading.Tasks.Task UpdateViolated(ITransactionTestGrain grain, int numberToAdd) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public enum TransactionFaultInjectPhase\n    {\n        None = 0,\n        AfterCommitReadOnly = 1,\n        AfterPrepare = 2,\n        AfterPrepareAndCommit = 3,\n        AfterAbort = 4,\n        AfterPrepared = 5,\n        AfterCancel = 6,\n        AfterConfirm = 7,\n        AfterPing = 8,\n        BeforeConfirm = 9,\n        BeforePrepare = 10,\n        BeforePrepareAndCommit = 11\n    }\n\n    public partial class TransactionRecoveryTestsRunner : TransactionTestRunnerBase\n    {\n        public TransactionRecoveryTestsRunner(TestingHost.TestCluster testCluster, System.Action<string> testOutput) : base(default!, default!) { }\n\n        protected void Log(string message) { }\n\n        protected virtual System.Threading.Tasks.Task TransactionWillRecoverAfterRandomSiloFailure(string transactionTestGrainClassName, int concurrent, bool gracefulShutdown) { throw null; }\n\n        public virtual System.Threading.Tasks.Task TransactionWillRecoverAfterRandomSiloGracefulShutdown(string transactionTestGrainClassName, int concurrent) { throw null; }\n\n        public virtual System.Threading.Tasks.Task TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(string transactionTestGrainClassName, int concurrent) { throw null; }\n    }\n\n    public static partial class TransactionTestConstants\n    {\n        public const string DoubleStateTransactionalGrain = \"DoubleStateTransactionalGrain\";\n        public const int MaxCoordinatedTransactions = 8;\n        public const string MaxStateTransactionalGrain = \"MaxStateTransactionalGrain\";\n        public const string NoStateTransactionalGrain = \"NoStateTransactionalGrain\";\n        public const string RemoteCommitService = \"RemoteCommitService\";\n        public const string SingleStateTransactionalGrain = \"SingleStateTransactionalGrain\";\n        public const string TransactionStore = \"TransactionStore\";\n    }\n\n    public partial class TransactionTestRunnerBase\n    {\n        protected readonly IGrainFactory grainFactory;\n        protected readonly System.Action<string> testOutput;\n        protected TransactionTestRunnerBase(IGrainFactory grainFactory, System.Action<string> testOutput) { }\n\n        protected ITransactionTestGrain RandomTestGrain(string transactionTestGrainClassNames) { throw null; }\n\n        protected TGrainInterface RandomTestGrain<TGrainInterface>(string transactionTestGrainClassNames)\n            where TGrainInterface : IGrainWithGuidKey { throw null; }\n\n        protected virtual ITransactionTestGrain TestGrain(string transactionTestGrainClassName, System.Guid id) { throw null; }\n\n        protected virtual TGrainInterface TestGrain<TGrainInterface>(string transactionTestGrainClassName, System.Guid id)\n            where TGrainInterface : IGrainWithGuidKey { throw null; }\n    }\n}\n\nnamespace Orleans.Transactions.TestKit.Consistency\n{\n    [Concurrency.Reentrant]\n    public partial class ConsistencyTestGrain : Grain, IConsistencyTestGrain, IGrainWithIntegerKey, IGrain, Runtime.IAddressable\n    {\n        protected Abstractions.ITransactionalState<State> data;\n        public ConsistencyTestGrain(Abstractions.ITransactionalState<State> data, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task<Observation[]> Run(ConsistencyTestOptions options, int depth, string stack, int maxgrain, System.DateTime stopAfter) { throw null; }\n\n        [GenerateSerializer]\n        public partial class State\n        {\n            [Id(1)]\n            public int SeqNo;\n            [Id(0)]\n            public string WriterTx;\n        }\n    }\n\n    public partial class ConsistencyTestHarness\n    {\n        public const string InitialTx = \"initial\";\n        public ConsistencyTestHarness(IGrainFactory grainFactory, int numGrains, int seed, bool avoidDeadlocks, bool avoidTimeouts, ReadWriteDetermination readWrite, bool tolerateUnknownExceptions) { }\n\n        public int NumAborted { get { throw null; } }\n\n        public void CheckConsistency(bool tolerateGenericTimeouts = false, bool tolerateUnknownExceptions = false) { }\n\n        public System.Threading.Tasks.Task RunRandomTransactionSequence(int partition, int count, IGrainFactory grainFactory, System.Action<string> output) { throw null; }\n    }\n\n    [GenerateSerializer]\n    public partial class ConsistencyTestOptions\n    {\n        public const int MaxGrains = 100000;\n        [Id(3)]\n        public bool AvoidDeadlocks { get { throw null; } set { } }\n\n        [Id(4)]\n        public bool AvoidTimeouts { get { throw null; } set { } }\n\n        [Id(6)]\n        public long GrainOffset { get { throw null; } set { } }\n\n        [Id(2)]\n        public int MaxDepth { get { throw null; } set { } }\n\n        [Id(1)]\n        public int NumGrains { get { throw null; } set { } }\n\n        [Id(0)]\n        public int RandomSeed { get { throw null; } set { } }\n\n        [Id(5)]\n        public ReadWriteDetermination ReadWrite { get { throw null; } set { } }\n    }\n\n    public partial interface IConsistencyTestGrain : IGrainWithIntegerKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<Observation[]> Run(ConsistencyTestOptions options, int depth, string stack, int max, System.DateTime stopAfter);\n    }\n\n    [GenerateSerializer]\n    public partial struct Observation\n    {\n        private object _dummy;\n        private int _dummyPrimitive;\n        [Id(3)]\n        public string ExecutingTx { get { throw null; } set { } }\n\n        [Id(0)]\n        public int Grain { get { throw null; } set { } }\n\n        [Id(1)]\n        public int SeqNo { get { throw null; } set { } }\n\n        [Id(2)]\n        public string WriterTx { get { throw null; } set { } }\n    }\n\n    public enum ReadWriteDetermination\n    {\n        PerTransaction = 0,\n        PerGrain = 1,\n        PerAccess = 2\n    }\n\n    [GenerateSerializer]\n    public partial class UserAbort : System.Exception\n    {\n        public UserAbort() { }\n\n        [System.Obsolete]\n        protected UserAbort(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n    }\n}\n\nnamespace Orleans.Transactions.TestKit.Correctnesss\n{\n    [GenerateSerializer]\n    public partial class BitArrayState\n    {\n        public BitArrayState() { }\n\n        public BitArrayState(BitArrayState other) { }\n\n        public int this[int index] { get { throw null; } set { } }\n\n        [Newtonsoft.Json.JsonIgnore]\n        public int Length { get { throw null; } }\n\n        [Newtonsoft.Json.JsonIgnore]\n        public int[] Value { get { throw null; } }\n\n        public static BitArrayState Apply(BitArrayState left, BitArrayState right, System.Func<int, int, int> op) { throw null; }\n\n        protected bool Equals(BitArrayState other) { throw null; }\n\n        public override bool Equals(object obj) { throw null; }\n\n        public System.Collections.Generic.IEnumerator<int> GetEnumerator() { throw null; }\n\n        public override int GetHashCode() { throw null; }\n\n        public static BitArrayState operator &(BitArrayState left, BitArrayState right) { throw null; }\n\n        public static BitArrayState operator |(BitArrayState left, BitArrayState right) { throw null; }\n\n        public static bool operator ==(BitArrayState left, BitArrayState right) { throw null; }\n\n        public static BitArrayState operator ^(BitArrayState left, BitArrayState right) { throw null; }\n\n        public static bool operator !=(BitArrayState left, BitArrayState right) { throw null; }\n\n        public void Set(int index, bool value) { }\n\n        public override string ToString() { throw null; }\n    }\n\n    [GrainType(\"txn-correctness-DoubleStateTransactionalGrain\")]\n    public partial class DoubleStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public DoubleStateTransactionalGrain(Abstractions.ITransactionalState<BitArrayState> data1, Abstractions.ITransactionalState<BitArrayState> data2, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    public partial interface ITransactionalBitArrayGrain : IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task<System.Collections.Generic.List<BitArrayState>> Get();\n        System.Threading.Tasks.Task Ping();\n        [Transaction(TransactionOption.CreateOrJoin)]\n        System.Threading.Tasks.Task SetBit(int newValue);\n    }\n\n    [GrainType(\"txn-correctness-MaxStateTransactionalGrain\")]\n    public partial class MaxStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public MaxStateTransactionalGrain(Abstractions.ITransactionalStateFactory stateFactory, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n\n    [GrainType(\"txn-correctness-MultiStateTransactionalBitArrayGrain\")]\n    public partial class MultiStateTransactionalBitArrayGrain : Grain, ITransactionalBitArrayGrain, IGrainWithGuidKey, IGrain, Runtime.IAddressable\n    {\n        protected Abstractions.ITransactionalState<BitArrayState>[] dataArray;\n        protected Microsoft.Extensions.Logging.ILogger logger;\n        public MultiStateTransactionalBitArrayGrain(Abstractions.ITransactionalState<BitArrayState>[] dataArray, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }\n\n        public System.Threading.Tasks.Task<System.Collections.Generic.List<BitArrayState>> Get() { throw null; }\n\n        public override System.Threading.Tasks.Task OnActivateAsync(System.Threading.CancellationToken cancellationToken) { throw null; }\n\n        public System.Threading.Tasks.Task Ping() { throw null; }\n\n        public System.Threading.Tasks.Task SetBit(int index) { throw null; }\n    }\n\n    [GrainType(\"txn-correctness-SingleStateTransactionalGrain\")]\n    public partial class SingleStateTransactionalGrain : MultiStateTransactionalBitArrayGrain\n    {\n        public SingleStateTransactionalGrain(Abstractions.ITransactionalState<BitArrayState> data, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base(default!, default!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_AddAndThrowException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.AddAndThrowException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.AddAndThrowException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_AddAndThrowException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.AddAndThrowException instance) { }\n\n        public global::Orleans.Transactions.TestKit.AddAndThrowException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.AddAndThrowException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.AddAndThrowException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FailOperation : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.FailOperation>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.FailOperation>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_FailOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.FailOperation> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.FailOperation instance) { }\n\n        public global::Orleans.Transactions.TestKit.FailOperation ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.FailOperation instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.FailOperation value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_FaultInjectionControl : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.FaultInjectionControl>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.FaultInjectionControl>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_FaultInjectionControl(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.FaultInjectionControl instance) { }\n\n        public global::Orleans.Transactions.TestKit.FaultInjectionControl ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.FaultInjectionControl instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.FaultInjectionControl value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_GrainData : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.GrainData>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.GrainData>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.GrainData instance) { }\n\n        public global::Orleans.Transactions.TestKit.GrainData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.GrainData instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.GrainData value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D instance) { }\n\n        public Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 instance) { }\n\n        public Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 instance) { }\n\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 instance) { }\n\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A instance) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C instance) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E instance) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D instance) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IJoinAttributionGrain_GrainReference_B1619F67 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IJoinAttributionGrain_GrainReference_B1619F67>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IJoinAttributionGrain_GrainReference_B1619F67(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IJoinAttributionGrain_GrainReference_B1619F67> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IJoinAttributionGrain_GrainReference_B1619F67 instance) { }\n\n        public Invokable_IJoinAttributionGrain_GrainReference_B1619F67 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IJoinAttributionGrain_GrainReference_B1619F67 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IJoinAttributionGrain_GrainReference_B1619F67 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_INoAttributionGrain_GrainReference_BC7E3A79 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_INoAttributionGrain_GrainReference_BC7E3A79>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_INoAttributionGrain_GrainReference_BC7E3A79(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_INoAttributionGrain_GrainReference_BC7E3A79 instance) { }\n\n        public Invokable_INoAttributionGrain_GrainReference_BC7E3A79 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_INoAttributionGrain_GrainReference_BC7E3A79 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_INoAttributionGrain_GrainReference_BC7E3A79 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_INotAllowedAttributionGrain_GrainReference_891D027E : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_INotAllowedAttributionGrain_GrainReference_891D027E>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_INotAllowedAttributionGrain_GrainReference_891D027E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_INotAllowedAttributionGrain_GrainReference_891D027E> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_INotAllowedAttributionGrain_GrainReference_891D027E instance) { }\n\n        public Invokable_INotAllowedAttributionGrain_GrainReference_891D027E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_INotAllowedAttributionGrain_GrainReference_891D027E instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_INotAllowedAttributionGrain_GrainReference_891D027E value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A instance) { }\n\n        public Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ISuppressAttributionGrain_GrainReference_5A02311D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ISuppressAttributionGrain_GrainReference_5A02311D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ISuppressAttributionGrain_GrainReference_5A02311D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ISuppressAttributionGrain_GrainReference_5A02311D> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ISuppressAttributionGrain_GrainReference_5A02311D instance) { }\n\n        public Invokable_ISuppressAttributionGrain_GrainReference_5A02311D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ISuppressAttributionGrain_GrainReference_5A02311D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ISuppressAttributionGrain_GrainReference_5A02311D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 instance) { }\n\n        public Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F instance) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_25B066B5 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_25B066B5>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionTestGrain_GrainReference_25B066B5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_25B066B5> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_25B066B5 instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_25B066B5 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_25B066B5 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_25B066B5 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_35C87F81 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_35C87F81>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionTestGrain_GrainReference_35C87F81(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_35C87F81> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_35C87F81 instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_35C87F81 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_35C87F81 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_35C87F81 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_35D6FD32 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_35D6FD32>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_35D6FD32 instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_35D6FD32 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_35D6FD32 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_35D6FD32 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_8DAA79AA : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_8DAA79AA>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionTestGrain_GrainReference_8DAA79AA(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_8DAA79AA> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_8DAA79AA instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_8DAA79AA ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_8DAA79AA instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_8DAA79AA value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_CE9EC80B : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_CE9EC80B>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionTestGrain_GrainReference_CE9EC80B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_CE9EC80B> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_CE9EC80B instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_CE9EC80B ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_CE9EC80B instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_CE9EC80B value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionTestGrain_GrainReference_DC07DAEA : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionTestGrain_GrainReference_DC07DAEA>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionTestGrain_GrainReference_DC07DAEA(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_DC07DAEA> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionTestGrain_GrainReference_DC07DAEA instance) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_DC07DAEA ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionTestGrain_GrainReference_DC07DAEA instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionTestGrain_GrainReference_DC07DAEA value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_PassOperation : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.PassOperation>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.PassOperation>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_PassOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.PassOperation> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.PassOperation instance) { }\n\n        public global::Orleans.Transactions.TestKit.PassOperation ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.PassOperation instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.PassOperation value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SimpleAzureStorageException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.SimpleAzureStorageException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.SimpleAzureStorageException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_SimpleAzureStorageException(global::Orleans.Serialization.Serializers.IBaseCodec<Azure.RequestFailedException> _baseTypeSerializer, global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.SimpleAzureStorageException> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.SimpleAzureStorageException instance) { }\n\n        public global::Orleans.Transactions.TestKit.SimpleAzureStorageException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.SimpleAzureStorageException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.SimpleAzureStorageException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ThrowOperation : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.ThrowOperation>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.ThrowOperation>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_ThrowOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.ThrowOperation> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.ThrowOperation instance) { }\n\n        public global::Orleans.Transactions.TestKit.ThrowOperation ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.ThrowOperation instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.ThrowOperation value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_TransactionFaultInjectPhase : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionFaultInjectPhase>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public global::Orleans.Transactions.TestKit.TransactionFaultInjectPhase ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionFaultInjectPhase value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_AddAndThrowException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.TestKit.AddAndThrowException, System.Exception>\n    {\n        public Copier_AddAndThrowException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FailOperation : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.FailOperation>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.FailOperation>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_FailOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.FailOperation> _activator) { }\n\n        public global::Orleans.Transactions.TestKit.FailOperation DeepCopy(global::Orleans.Transactions.TestKit.FailOperation original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.FailOperation input, global::Orleans.Transactions.TestKit.FailOperation output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_FaultInjectionControl : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.FaultInjectionControl>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.FaultInjectionControl>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Transactions.TestKit.FaultInjectionControl DeepCopy(global::Orleans.Transactions.TestKit.FaultInjectionControl original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.FaultInjectionControl input, global::Orleans.Transactions.TestKit.FaultInjectionControl output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_GrainData : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.GrainData>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.GrainData>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Transactions.TestKit.GrainData DeepCopy(global::Orleans.Transactions.TestKit.GrainData original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.GrainData input, global::Orleans.Transactions.TestKit.GrainData output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D> _activator) { }\n\n        public Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D DeepCopy(Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8> _activator) { }\n\n        public Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 DeepCopy(Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60> _activator) { }\n\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 DeepCopy(Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5> _activator) { }\n\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 DeepCopy(Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A> _activator) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A DeepCopy(Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C> _activator) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C DeepCopy(Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E DeepCopy(Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D> _activator) { }\n\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D DeepCopy(Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IJoinAttributionGrain_GrainReference_B1619F67 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IJoinAttributionGrain_GrainReference_B1619F67>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IJoinAttributionGrain_GrainReference_B1619F67(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IJoinAttributionGrain_GrainReference_B1619F67> _activator) { }\n\n        public Invokable_IJoinAttributionGrain_GrainReference_B1619F67 DeepCopy(Invokable_IJoinAttributionGrain_GrainReference_B1619F67 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_INoAttributionGrain_GrainReference_BC7E3A79 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_INoAttributionGrain_GrainReference_BC7E3A79>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_INoAttributionGrain_GrainReference_BC7E3A79(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public Invokable_INoAttributionGrain_GrainReference_BC7E3A79 DeepCopy(Invokable_INoAttributionGrain_GrainReference_BC7E3A79 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_INotAllowedAttributionGrain_GrainReference_891D027E : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_INotAllowedAttributionGrain_GrainReference_891D027E>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_INotAllowedAttributionGrain_GrainReference_891D027E(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_INotAllowedAttributionGrain_GrainReference_891D027E> _activator) { }\n\n        public Invokable_INotAllowedAttributionGrain_GrainReference_891D027E DeepCopy(Invokable_INotAllowedAttributionGrain_GrainReference_891D027E original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A> _activator) { }\n\n        public Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A DeepCopy(Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ISuppressAttributionGrain_GrainReference_5A02311D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ISuppressAttributionGrain_GrainReference_5A02311D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ISuppressAttributionGrain_GrainReference_5A02311D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ISuppressAttributionGrain_GrainReference_5A02311D> _activator) { }\n\n        public Invokable_ISuppressAttributionGrain_GrainReference_5A02311D DeepCopy(Invokable_ISuppressAttributionGrain_GrainReference_5A02311D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4> _activator) { }\n\n        public Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 DeepCopy(Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F> _activator) { }\n\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F DeepCopy(Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_25B066B5 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_25B066B5>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionTestGrain_GrainReference_25B066B5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_25B066B5> _activator) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_25B066B5 DeepCopy(Invokable_ITransactionTestGrain_GrainReference_25B066B5 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_35C87F81 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_35C87F81>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionTestGrain_GrainReference_35C87F81(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_35C87F81> _activator) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_35C87F81 DeepCopy(Invokable_ITransactionTestGrain_GrainReference_35C87F81 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_35D6FD32 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_35D6FD32>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_ITransactionTestGrain_GrainReference_35D6FD32 DeepCopy(Invokable_ITransactionTestGrain_GrainReference_35D6FD32 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_8DAA79AA : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_8DAA79AA>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionTestGrain_GrainReference_8DAA79AA(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_8DAA79AA> _activator) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_8DAA79AA DeepCopy(Invokable_ITransactionTestGrain_GrainReference_8DAA79AA original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_CE9EC80B : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_CE9EC80B>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionTestGrain_GrainReference_CE9EC80B(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_CE9EC80B> _activator) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_CE9EC80B DeepCopy(Invokable_ITransactionTestGrain_GrainReference_CE9EC80B original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionTestGrain_GrainReference_DC07DAEA : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionTestGrain_GrainReference_DC07DAEA>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionTestGrain_GrainReference_DC07DAEA(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionTestGrain_GrainReference_DC07DAEA> _activator) { }\n\n        public Invokable_ITransactionTestGrain_GrainReference_DC07DAEA DeepCopy(Invokable_ITransactionTestGrain_GrainReference_DC07DAEA original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_PassOperation : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.PassOperation>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.PassOperation>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_PassOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.PassOperation> _activator) { }\n\n        public global::Orleans.Transactions.TestKit.PassOperation DeepCopy(global::Orleans.Transactions.TestKit.PassOperation original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.PassOperation input, global::Orleans.Transactions.TestKit.PassOperation output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SimpleAzureStorageException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.TestKit.SimpleAzureStorageException, Azure.RequestFailedException>\n    {\n        public Copier_SimpleAzureStorageException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ThrowOperation : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.ThrowOperation>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.ThrowOperation>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_ThrowOperation(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.ThrowOperation> _activator) { }\n\n        public global::Orleans.Transactions.TestKit.ThrowOperation DeepCopy(global::Orleans.Transactions.TestKit.ThrowOperation original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.ThrowOperation input, global::Orleans.Transactions.TestKit.ThrowOperation output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ICreateAttributionGrain), \"3EFBDD5D\" })]\n    public sealed partial class Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_ICreateAttributionGrain_GrainReference_3EFBDD5D(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ICreateOrJoinAttributionGrain), \"C9B8ECB8\" })]\n    public sealed partial class Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8 : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_ICreateOrJoinAttributionGrain_GrainReference_C9B8ECB8(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionCoordinatorGrain), \"70FF7C60\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain> arg0;\n        public int arg1;\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_70FF7C60(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionCoordinatorGrain), \"E67D54A5\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain> arg0;\n        public int arg1;\n        public global::Orleans.Transactions.TestKit.FaultInjectionControl arg2;\n        public Invokable_IFaultInjectionTransactionCoordinatorGrain_GrainReference_E67D54A5(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain), \"8389970A\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_8389970A(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain), \"A4CAE05C\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public global::Orleans.Transactions.TestKit.FaultInjectionControl arg1;\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A4CAE05C(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain), \"A6C1652E\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionTestGrain_GrainReference_A6C1652E : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IFaultInjectionTransactionTestGrain), \"C752DF7D\" })]\n    public sealed partial class Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D : global::Orleans.TransactionTaskRequest<int>\n    {\n        public Invokable_IFaultInjectionTransactionTestGrain_GrainReference_C752DF7D(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<int> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.IJoinAttributionGrain), \"B1619F67\" })]\n    public sealed partial class Invokable_IJoinAttributionGrain_GrainReference_B1619F67 : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_IJoinAttributionGrain_GrainReference_B1619F67(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.INoAttributionGrain), \"BC7E3A79\" })]\n    public sealed partial class Invokable_INoAttributionGrain_GrainReference_BC7E3A79 : global::Orleans.Runtime.TaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.INotAllowedAttributionGrain), \"891D027E\" })]\n    public sealed partial class Invokable_INotAllowedAttributionGrain_GrainReference_891D027E : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_INotAllowedAttributionGrain_GrainReference_891D027E(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ISupportedAttributionGrain), \"BC7DBC0A\" })]\n    public sealed partial class Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_ISupportedAttributionGrain_GrainReference_BC7DBC0A(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ISuppressAttributionGrain), \"5A02311D\" })]\n    public sealed partial class Invokable_ISuppressAttributionGrain_GrainReference_5A02311D : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<string>[]>\n    {\n        public int arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionAttributionGrain>[] arg1;\n        public Invokable_ISuppressAttributionGrain_GrainReference_5A02311D(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<string>[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCommitterTestGrain), \"C44BE2A4\" })]\n    public sealed partial class Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4 : global::Orleans.TransactionTaskRequest\n    {\n        public global::Orleans.Transactions.Abstractions.ITransactionCommitOperation<global::Orleans.Transactions.TestKit.IRemoteCommitService> arg0;\n        public Invokable_ITransactionCommitterTestGrain_GrainReference_C44BE2A4(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"2760260D\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg1;\n        public int arg2;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_2760260D(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"3A6B9237\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_3A6B9237(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"485592B2\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2 : global::Orleans.TransactionTaskRequest\n    {\n        public global::Orleans.Transactions.TestKit.ITransactionTestGrain arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_485592B2(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"5FC2E7A1\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FC2E7A1(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"5FF4F216\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.Correctnesss.ITransactionalBitArrayGrain> arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_5FF4F216(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"78D54907\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_78D54907(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"8EE5E563\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563 : global::Orleans.TransactionTaskRequest\n    {\n        public global::Orleans.Transactions.TestKit.ITransactionCommitterTestGrain arg0;\n        public global::Orleans.Transactions.Abstractions.ITransactionCommitOperation<global::Orleans.Transactions.TestKit.IRemoteCommitService> arg1;\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg2;\n        public int arg3;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_8EE5E563(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"9EFEA7F3\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3 : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_9EFEA7F3(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"B013DBF6\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6 : global::Orleans.TransactionTaskRequest\n    {\n        public global::Orleans.Transactions.TestKit.ITransactionTestGrain arg0;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B013DBF6(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"B4376B4D\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D : global::Orleans.TransactionTaskRequest\n    {\n        public System.Collections.Generic.List<global::Orleans.Transactions.TestKit.ITransactionTestGrain> arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_B4376B4D(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionCoordinatorGrain), \"D3EF444F\" })]\n    public sealed partial class Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F : global::Orleans.TransactionTaskRequest\n    {\n        public global::Orleans.Transactions.TestKit.ITransactionTestGrain arg0;\n        public int arg1;\n        public Invokable_ITransactionCoordinatorGrain_GrainReference_D3EF444F(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"25B066B5\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_25B066B5 : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public Invokable_ITransactionTestGrain_GrainReference_25B066B5(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"35C87F81\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_35C87F81 : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public Invokable_ITransactionTestGrain_GrainReference_35C87F81(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"35D6FD32\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_35D6FD32 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"8DAA79AA\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_8DAA79AA : global::Orleans.TransactionTaskRequest<int[]>\n    {\n        public Invokable_ITransactionTestGrain_GrainReference_8DAA79AA(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<int[]> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"CE9EC80B\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_CE9EC80B : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public Invokable_ITransactionTestGrain_GrainReference_CE9EC80B(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.ITransactionTestGrain), \"DC07DAEA\" })]\n    public sealed partial class Invokable_ITransactionTestGrain_GrainReference_DC07DAEA : global::Orleans.TransactionTaskRequest<int[]>\n    {\n        public int arg0;\n        public Invokable_ITransactionTestGrain_GrainReference_DC07DAEA(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<int[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit.Consistency\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_ConsistencyTestOptions : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_ConsistencyTestOptions(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions instance) { }\n\n        public global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_IConsistencyTestGrain_GrainReference_2EB318CB : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_IConsistencyTestGrain_GrainReference_2EB318CB>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_IConsistencyTestGrain_GrainReference_2EB318CB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IConsistencyTestGrain_GrainReference_2EB318CB> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_IConsistencyTestGrain_GrainReference_2EB318CB instance) { }\n\n        public Invokable_IConsistencyTestGrain_GrainReference_2EB318CB ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_IConsistencyTestGrain_GrainReference_2EB318CB instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_IConsistencyTestGrain_GrainReference_2EB318CB value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Observation : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.Consistency.Observation>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IValueSerializer<global::Orleans.Transactions.TestKit.Consistency.Observation>, global::Orleans.Serialization.Serializers.IValueSerializer\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::Orleans.Transactions.TestKit.Consistency.Observation instance) { }\n\n        public global::Orleans.Transactions.TestKit.Consistency.Observation ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::Orleans.Transactions.TestKit.Consistency.Observation instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.Consistency.Observation value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_UserAbort : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.Consistency.UserAbort>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.Consistency.UserAbort>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_UserAbort(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.Consistency.UserAbort instance) { }\n\n        public global::Orleans.Transactions.TestKit.Consistency.UserAbort ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.Consistency.UserAbort instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.Consistency.UserAbort value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_ConsistencyTestOptions : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions DeepCopy(global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions input, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_IConsistencyTestGrain_GrainReference_2EB318CB : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_IConsistencyTestGrain_GrainReference_2EB318CB>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_IConsistencyTestGrain_GrainReference_2EB318CB(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_IConsistencyTestGrain_GrainReference_2EB318CB> _activator) { }\n\n        public Invokable_IConsistencyTestGrain_GrainReference_2EB318CB DeepCopy(Invokable_IConsistencyTestGrain_GrainReference_2EB318CB original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_UserAbort : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.TestKit.Consistency.UserAbort, System.Exception>\n    {\n        public Copier_UserAbort(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.Consistency.IConsistencyTestGrain), \"2EB318CB\" })]\n    public sealed partial class Invokable_IConsistencyTestGrain_GrainReference_2EB318CB : global::Orleans.TransactionTaskRequest<global::Orleans.Transactions.TestKit.Consistency.Observation[]>\n    {\n        public global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestOptions arg0;\n        public int arg1;\n        public string arg2;\n        public int arg3;\n        public System.DateTime arg4;\n        public Invokable_IConsistencyTestGrain_GrainReference_2EB318CB(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<global::Orleans.Transactions.TestKit.Consistency.Observation[]> InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_State : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State instance) { }\n\n        public global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_State : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State DeepCopy(global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State input, global::Orleans.Transactions.TestKit.Consistency.ConsistencyTestGrain.State output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit.Correctnesss\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_BitArrayState : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_BitArrayState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState instance) { }\n\n        public global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 instance) { }\n\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 instance) { }\n\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 : global::Orleans.Serialization.Codecs.IFieldCodec<Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1>, global::Orleans.Serialization.Codecs.IFieldCodec\n    {\n        public Codec_Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1> _activator) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 instance) { }\n\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_BitArrayState : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_BitArrayState(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState DeepCopy(global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState input, global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5> _activator) { }\n\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 DeepCopy(Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 DeepCopy(Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 : global::Orleans.Serialization.Cloning.IDeepCopier<Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1>, global::Orleans.Serialization.Cloning.IDeepCopier\n    {\n        public Copier_Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1> _activator) { }\n\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 DeepCopy(Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.Correctnesss.ITransactionalBitArrayGrain), \"0183C2F5\" })]\n    public sealed partial class Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5 : global::Orleans.TransactionTaskRequest\n    {\n        public int arg0;\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_0183C2F5(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override object GetArgument(int index) { throw null; }\n\n        public override int GetArgumentCount() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetArgument(int index, object value) { }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.Correctnesss.ITransactionalBitArrayGrain), \"9A5740F1\" })]\n    public sealed partial class Invokable_ITransactionalBitArrayGrain_GrainReference_9A5740F1 : global::Orleans.Runtime.TaskRequest\n    {\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    [global::Orleans.CompoundTypeAlias(new[] { \"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::Orleans.Transactions.TestKit.Correctnesss.ITransactionalBitArrayGrain), \"B821F3B1\" })]\n    public sealed partial class Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1 : global::Orleans.TransactionTaskRequest<System.Collections.Generic.List<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>>\n    {\n        public Invokable_ITransactionalBitArrayGrain_GrainReference_B821F3B1(global::Orleans.Serialization.Serializer<global::Orleans.Transactions.OrleansTransactionAbortedException> base0, System.IServiceProvider base1) : base(default(Serialization.Serializer<Transactions.OrleansTransactionAbortedException>)!, default!) { }\n\n        public override void Dispose() { }\n\n        public override string GetActivityName() { throw null; }\n\n        public override string GetInterfaceName() { throw null; }\n\n        public override System.Type GetInterfaceType() { throw null; }\n\n        public override System.Reflection.MethodInfo GetMethod() { throw null; }\n\n        public override string GetMethodName() { throw null; }\n\n        public override object GetTarget() { throw null; }\n\n        protected override System.Threading.Tasks.Task<System.Collections.Generic.List<global::Orleans.Transactions.TestKit.Correctnesss.BitArrayState>> InvokeInner() { throw null; }\n\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit.RandomErrorInjector\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RandomlyInjectedInconsistentStateException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_RandomlyInjectedInconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException instance) { }\n\n        public global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RandomlyInjectedStorageException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_RandomlyInjectedStorageException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException instance) { }\n\n        public global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RandomlyInjectedInconsistentStateException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedInconsistentStateException, global::Orleans.Storage.InconsistentStateException>\n    {\n        public Copier_RandomlyInjectedInconsistentStateException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RandomlyInjectedStorageException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Transactions.TestKit.RandomErrorInjector.RandomlyInjectedStorageException, System.Exception>\n    {\n        public Copier_RandomlyInjectedStorageException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CreateAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_CreateAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_CreateOrJoinAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_CreateOrJoinAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_JoinAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_JoinAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_NoAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_NoAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_NotAllowedAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_NotAllowedAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SupportedAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_SupportedAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_SuppressAttributionGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_SuppressAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain instance) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_CreateAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_CreateAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_CreateOrJoinAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_CreateOrJoinAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.CreateOrJoinAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_JoinAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_JoinAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.JoinAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_NoAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_NoAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NoAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_NotAllowedAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_NotAllowedAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.NotAllowedAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SupportedAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_SupportedAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SupportedAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_SuppressAttributionGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain>, global::Orleans.Serialization.Cloning.IDeepCopier, global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain>, global::Orleans.Serialization.Cloning.IBaseCopier\n    {\n        public Copier_SuppressAttributionGrain(global::Orleans.Serialization.Activators.IActivator<global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) { }\n\n        public global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain original, global::Orleans.Serialization.Cloning.CopyContext context) { throw null; }\n\n        public void DeepCopy(global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain input, global::Orleans.Transactions.TestKit.TransactionAttributionGrainExtensions.SuppressAttributionGrain output, global::Orleans.Serialization.Cloning.CopyContext context) { }\n    }\n}"
  },
  {
    "path": "src/api/Orleans.Transactions.TestKit.xUnit/Orleans.Transactions.TestKit.xUnit.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Transactions.TestKit.xUnit\n{\n    public abstract partial class ConsistencyTransactionTestRunnerxUnit : ConsistencyTransactionTestRunner\n    {\n        public ConsistencyTransactionTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        protected override bool StorageAdaptorHasLimitedCommitSpace { get { throw null; } }\n\n        protected override bool StorageErrorInjectionActive { get { throw null; } }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { 2, 2, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 3, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 4, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 5, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 2, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 3, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 4, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 5, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 2, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 3, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 4, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 5, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 2, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 3, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 4, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 5, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 2, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 3, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 4, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 5, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 2, 2, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 3, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 4, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 5, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 2, 2, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 3, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 4, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 5, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 2, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 3, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 4, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 2, 5, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 2, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 3, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 4, true, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 2, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 3, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 4, true, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 2, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 3, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 4, true, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 2, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 3, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 4, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 2, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 3, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 4, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 5, true, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 30, 2, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 3, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 4, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 5, true, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 30, 2, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 3, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 4, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 5, true, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 2, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 3, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 4, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 30, 5, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 2, false, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 3, false, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 4, false, true, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 2, false, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 3, false, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 4, false, true, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 2, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 3, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 4, false, true, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 2, false, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 3, false, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 4, false, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 5, false, false, Consistency.ReadWriteDetermination.PerGrain })]\n        [Xunit.InlineData(new[] { 1000, 2, false, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 3, false, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 4, false, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 5, false, false, Consistency.ReadWriteDetermination.PerTransaction })]\n        [Xunit.InlineData(new[] { 1000, 2, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 3, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 4, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        [Xunit.InlineData(new[] { 1000, 5, false, false, Consistency.ReadWriteDetermination.PerAccess })]\n        public override System.Threading.Tasks.Task RandomizedConsistency(int numGrains, int scale, bool avoidDeadlocks, bool avoidTimeouts, Consistency.ReadWriteDetermination readwrite) { throw null; }\n    }\n\n    public partial class ControlledFaultInjectionTransactionTestRunnerxUnit : ControlledFaultInjectionTransactionTestRunner\n    {\n        public ControlledFaultInjectionTransactionTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9551\")]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.AfterPrepare, FaultInjectionType.Deactivation })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.AfterConfirm, FaultInjectionType.Deactivation })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.AfterPrepared, FaultInjectionType.Deactivation })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.AfterPrepareAndCommit, FaultInjectionType.Deactivation })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforePrepare, FaultInjectionType.ExceptionAfterStore })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforePrepare, FaultInjectionType.ExceptionBeforeStore })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforeConfirm, FaultInjectionType.ExceptionAfterStore })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforeConfirm, FaultInjectionType.ExceptionBeforeStore })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforePrepareAndCommit, FaultInjectionType.ExceptionAfterStore })]\n        [Xunit.InlineData(new[] { TransactionFaultInjectPhase.BeforePrepareAndCommit, FaultInjectionType.ExceptionBeforeStore })]\n        public override System.Threading.Tasks.Task MultiGrainWriteTransaction_FaultInjection(TransactionFaultInjectPhase injectionPhase, FaultInjectionType injectionType) { throw null; }\n\n        [SkippableFact(new[] { })]\n        public override System.Threading.Tasks.Task SingleGrainReadTransaction() { throw null; }\n\n        [SkippableFact(new[] { })]\n        public override System.Threading.Tasks.Task SingleGrainWriteTransaction() { throw null; }\n    }\n\n    public partial class DisabledTransactionsTestRunnerxUnit : DisabledTransactionsTestRunner\n    {\n        protected DisabledTransactionsTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"NoStateTransactionalGrain\" })]\n        public override void MultiTransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"NoStateTransactionalGrain\" })]\n        public override void TransactionGrainsThrowWhenTransactions(string transactionTestGrainClassName) { }\n    }\n\n    public abstract partial class GoldenPathTransactionTestRunnerxUnit : GoldenPathTransactionTestRunner\n    {\n        protected GoldenPathTransactionTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task MultiGrainReadWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task MultiGrainWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task MultiWriteToSingleGrainTransaction(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task RepeatGrainReadWriteTransaction(string grainStates, int grainCount) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task RWRWTest(string grainStates, int grainCount) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task SingleGrainReadTransaction(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task SingleGrainWriteTransaction(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9553\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task WRWRTest(string grainStates, int grainCount) { throw null; }\n    }\n\n    public partial class GrainFaultTransactionTestRunnerxUnit : GrainFaultTransactionTestRunner\n    {\n        public GrainFaultTransactionTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task AbortTransactionExceptionInnerExceptionOnlyContainsOneRootCauseException(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task AbortTransactionOnExceptions(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task AbortTransactionOnOrphanCalls(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task AbortTransactionOnReadOnlyViolatedException(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task MultiGrainAbortTransactionOnExceptions(string grainStates) { throw null; }\n    }\n\n    public abstract partial class ScopedTransactionsTestRunnerxUnit : ScopedTransactionsTestRunner\n    {\n        protected ScopedTransactionsTestRunnerxUnit(IGrainFactory grainFactory, ITransactionClient transactionFrame, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!, default!) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task CreateNestedTransactionScopeAndSetValueAndInnerFailAndAssert(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task CreateTransactionScopeAndSetValue(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task CreateTransactionScopeAndSetValueAndAssert(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task CreateTransactionScopeAndSetValueWithFailure(string grainStates) { throw null; }\n    }\n\n    public abstract partial class TocFaultTransactionTestRunnerxUnit : TocFaultTransactionTestRunner\n    {\n        protected TocFaultTransactionTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task MultiGrainWriteTransactionWithCommitException(string grainStates, int grainCount) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9556\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\", 1 })]\n        public override System.Threading.Tasks.Task MultiGrainWriteTransactionWithCommitFailure(string grainStates, int grainCount) { throw null; }\n    }\n\n    public abstract partial class TocGoldenPathTestRunnerxUnit : TocGoldenPathTestRunner\n    {\n        protected TocGoldenPathTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9556\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 8 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 4 })]\n        public override System.Threading.Tasks.Task MultiGrainWriteTransaction(string grainStates, int grainCount) { throw null; }\n    }\n\n    public abstract partial class TransactionalStateStorageTestRunnerxUnit<TState> : TransactionalStateStorageTestRunner<TState> where TState : class, new()\n    {\n        public TransactionalStateStorageTestRunnerxUnit(System.Func<System.Threading.Tasks.Task<Abstractions.ITransactionalStateStorage<TState>>> stateStorageFactory, System.Func<int, TState> stateFactory, IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper testOutput, System.Func<FluentAssertions.Equivalency.EquivalencyOptions<TState>, FluentAssertions.Equivalency.EquivalencyOptions<TState>> assertConfig = null) : base(default!, default!, default!, default!, default!) { }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { 99 })]\n        [Xunit.InlineData(new[] { 100 })]\n        [Xunit.InlineData(new[] { 200 })]\n        public override System.Threading.Tasks.Task CancelMany(int count) { throw null; }\n\n        [Xunit.Fact]\n        public override System.Threading.Tasks.Task CancelOne() { throw null; }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { 99, true })]\n        [Xunit.InlineData(new[] { 99, false })]\n        [Xunit.InlineData(new[] { 100, true })]\n        [Xunit.InlineData(new[] { 100, false })]\n        [Xunit.InlineData(new[] { 200, true })]\n        [Xunit.InlineData(new[] { 200, false })]\n        public override System.Threading.Tasks.Task ConfirmMany(int count, bool useTwoSteps) { throw null; }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { true })]\n        [Xunit.InlineData(new[] { false })]\n        public override System.Threading.Tasks.Task ConfirmOne(bool useTwoSteps) { throw null; }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { false, false })]\n        [Xunit.InlineData(new[] { true, true })]\n        [Xunit.InlineData(new[] { true, false })]\n        public override System.Threading.Tasks.Task ConfirmOneAndCancelOne(bool useTwoSteps, bool reverseOrder) { throw null; }\n\n        [Xunit.Fact]\n        public override System.Threading.Tasks.Task FirstTime_Load_ShouldReturnEmptyLoadResponse() { throw null; }\n\n        [Xunit.Fact]\n        public override System.Threading.Tasks.Task GrowingBatch() { throw null; }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { 99 })]\n        [Xunit.InlineData(new[] { 100 })]\n        [Xunit.InlineData(new[] { 200 })]\n        public override System.Threading.Tasks.Task PrepareMany(int count) { throw null; }\n\n        [Xunit.Theory]\n        [Xunit.InlineData(new[] { 99 })]\n        [Xunit.InlineData(new[] { 100 })]\n        [Xunit.InlineData(new[] { 200 })]\n        public override System.Threading.Tasks.Task ReplaceMany(int count) { throw null; }\n\n        [Xunit.Fact]\n        public override System.Threading.Tasks.Task ReplaceOne() { throw null; }\n\n        [Xunit.Fact]\n        public override System.Threading.Tasks.Task ShrinkingBatch() { throw null; }\n    }\n\n    public abstract partial class TransactionConcurrencyTestRunnerxUnit : TransactionConcurrencyTestRunner\n    {\n        protected TransactionConcurrencyTestRunnerxUnit(IGrainFactory grainFactory, Xunit.Abstractions.ITestOutputHelper output) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task SingleSharedGrainTest(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task TransactionChainTest(string grainStates) { throw null; }\n\n        [SkippableTheory(new[] { }, Skip = \"https://github.com/dotnet/orleans/issues/9554\")]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\" })]\n        [Xunit.InlineData(new[] { \"MaxStateTransactionalGrain\" })]\n        public override System.Threading.Tasks.Task TransactionTreeTest(string grainStates) { throw null; }\n    }\n\n    public partial class TransactionRecoveryTestsRunnerxUnit : TransactionRecoveryTestsRunner\n    {\n        public TransactionRecoveryTestsRunnerxUnit(TestingHost.TestCluster cluster, Xunit.Abstractions.ITestOutputHelper testOutput) : base(default!, default!) { }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 30 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 20 })]\n        public override System.Threading.Tasks.Task TransactionWillRecoverAfterRandomSiloGracefulShutdown(string transactionTestGrainClassName, int concurrent) { throw null; }\n\n        [SkippableTheory(new[] { })]\n        [Xunit.InlineData(new[] { \"SingleStateTransactionalGrain\", 30 })]\n        [Xunit.InlineData(new[] { \"DoubleStateTransactionalGrain\", 20 })]\n        public override System.Threading.Tasks.Task TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(string transactionTestGrainClassName, int concurrent) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/README.md",
    "content": "# Generate API surface\n\nThis directory contains generated files describing the public API surface area for all packable projects in this repository.\n\nThe API surface are is generated by a scheduled workflow, [generate-api-diffs.yml](../../.github/workflows/generate-api-diffs.yml).\n"
  },
  {
    "path": "src/api/Redis/Orleans.Clustering.Redis/Orleans.Clustering.Redis.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Microsoft.Extensions.Hosting\n{\n    public static partial class RedisClusteringIClientBuilderExtensions\n    {\n        public static Orleans.Hosting.IClientBuilder UseRedisClustering(this Orleans.Hosting.IClientBuilder builder, System.Action<Orleans.Clustering.Redis.RedisClusteringOptions> configuration) { throw null; }\n\n        public static Orleans.Hosting.IClientBuilder UseRedisClustering(this Orleans.Hosting.IClientBuilder builder, string redisConnectionString) { throw null; }\n    }\n\n    public static partial class RedisClusteringISiloBuilderExtensions\n    {\n        public static Orleans.Hosting.ISiloBuilder UseRedisClustering(this Orleans.Hosting.ISiloBuilder builder, System.Action<Orleans.Clustering.Redis.RedisClusteringOptions> configuration) { throw null; }\n\n        public static Orleans.Hosting.ISiloBuilder UseRedisClustering(this Orleans.Hosting.ISiloBuilder builder, string redisConnectionString) { throw null; }\n    }\n}\n\nnamespace Orleans.Clustering.Redis\n{\n    public partial class RedisClusteringException : System.Exception\n    {\n        public RedisClusteringException() { }\n\n        [System.Obsolete]\n        protected RedisClusteringException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public RedisClusteringException(string message, System.Exception innerException) { }\n\n        public RedisClusteringException(string message) { }\n    }\n\n    public partial class RedisClusteringOptions\n    {\n        public StackExchange.Redis.ConfigurationOptions ConfigurationOptions { get { throw null; } set { } }\n\n        public System.Func<RedisClusteringOptions, System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer>> CreateMultiplexer { get { throw null; } set { } }\n\n        public System.Func<Configuration.ClusterOptions, StackExchange.Redis.RedisKey> CreateRedisKey { get { throw null; } set { } }\n\n        public System.TimeSpan? EntryExpiry { get { throw null; } set { } }\n\n        public static System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer> DefaultCreateMultiplexer(RedisClusteringOptions options) { throw null; }\n\n        public static StackExchange.Redis.RedisKey DefaultCreateRedisKey(Configuration.ClusterOptions clusterOptions) { throw null; }\n    }\n\n    public partial class RedisClusteringOptionsValidator : IConfigurationValidator\n    {\n        public RedisClusteringOptionsValidator(Microsoft.Extensions.Options.IOptions<RedisClusteringOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n}"
  },
  {
    "path": "src/api/Redis/Orleans.GrainDirectory.Redis/Orleans.GrainDirectory.Redis.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class RedisGrainDirectoryOptions\n    {\n        public StackExchange.Redis.ConfigurationOptions ConfigurationOptions { get { throw null; } set { } }\n\n        public System.Func<RedisGrainDirectoryOptions, System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer>> CreateMultiplexer { get { throw null; } set { } }\n\n        public System.TimeSpan? EntryExpiry { get { throw null; } set { } }\n\n        public static System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer> DefaultCreateMultiplexer(RedisGrainDirectoryOptions options) { throw null; }\n    }\n\n    public partial class RedisGrainDirectoryOptionsValidator : IConfigurationValidator\n    {\n        public RedisGrainDirectoryOptionsValidator(RedisGrainDirectoryOptions options, string name) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.GrainDirectory.Redis\n{\n    public partial class RedisGrainDirectory : IGrainDirectory, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public RedisGrainDirectory(Configuration.RedisGrainDirectoryOptions directoryOptions, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Microsoft.Extensions.Logging.ILogger<RedisGrainDirectory> logger) { }\n\n        public System.Threading.Tasks.Task Initialize(System.Threading.CancellationToken ct = default) { throw null; }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Lookup(Runtime.GrainId grainId) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address, Runtime.GrainAddress? previousAddress) { throw null; }\n\n        public System.Threading.Tasks.Task<Runtime.GrainAddress?> Register(Runtime.GrainAddress address) { throw null; }\n\n        public System.Threading.Tasks.Task Unregister(Runtime.GrainAddress address) { throw null; }\n\n        public System.Threading.Tasks.Task UnregisterSilos(System.Collections.Generic.List<Runtime.SiloAddress> siloAddresses) { throw null; }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class RedisGrainDirectoryExtensions\n    {\n        public static ISiloBuilder AddRedisGrainDirectory(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.RedisGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainDirectory(this ISiloBuilder builder, string name, System.Action<Configuration.RedisGrainDirectoryOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseRedisGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Configuration.RedisGrainDirectoryOptions>> configureOptions) { throw null; }\n\n        public static ISiloBuilder UseRedisGrainDirectoryAsDefault(this ISiloBuilder builder, System.Action<Configuration.RedisGrainDirectoryOptions> configureOptions) { throw null; }\n    }\n}"
  },
  {
    "path": "src/api/Redis/Orleans.Persistence.Redis/Orleans.Persistence.Redis.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Hosting\n{\n    public static partial class RedisGrainStorageServiceCollectionExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRedisGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.RedisStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRedisGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action<Persistence.RedisStorageOptions> configureOptions) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRedisGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.RedisStorageOptions>> configureOptions = null) { throw null; }\n\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddRedisGrainStorageAsDefault(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Persistence.RedisStorageOptions> configureOptions) { throw null; }\n    }\n\n    public static partial class RedisSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.RedisStorageOptions>> configureOptionsBuilder) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name, System.Action<Persistence.RedisStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainStorage(this ISiloBuilder builder, string name) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Microsoft.Extensions.Options.OptionsBuilder<Persistence.RedisStorageOptions>> configureOptionsBuilder) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder, System.Action<Persistence.RedisStorageOptions> configureOptions) { throw null; }\n\n        public static ISiloBuilder AddRedisGrainStorageAsDefault(this ISiloBuilder builder) { throw null; }\n    }\n}\n\nnamespace Orleans.Persistence\n{\n    public partial class RedisGrainStorage : Storage.IGrainStorage, ILifecycleParticipant<Runtime.ISiloLifecycle>\n    {\n        public RedisGrainStorage(string name, RedisStorageOptions options, Storage.IGrainStorageSerializer grainStorageSerializer, Microsoft.Extensions.Options.IOptions<Configuration.ClusterOptions> clusterOptions, Serialization.Serializers.IActivatorProvider activatorProvider, Microsoft.Extensions.Logging.ILogger<RedisGrainStorage> logger) { }\n\n        public System.Threading.Tasks.Task ClearStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public void Participate(Runtime.ISiloLifecycle lifecycle) { }\n\n        public System.Threading.Tasks.Task ReadStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n\n        public System.Threading.Tasks.Task WriteStateAsync<T>(string grainType, Runtime.GrainId grainId, IGrainState<T> grainState) { throw null; }\n    }\n\n    public static partial class RedisGrainStorageFactory\n    {\n        public static RedisGrainStorage Create(System.IServiceProvider services, string name) { throw null; }\n    }\n\n    public partial class RedisStorageOptions : Storage.IStorageProviderSerializerOptions\n    {\n        public StackExchange.Redis.ConfigurationOptions? ConfigurationOptions { get { throw null; } set { } }\n\n        public System.Func<RedisStorageOptions, System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer>> CreateMultiplexer { get { throw null; } set { } }\n\n        public bool DeleteStateOnClear { get { throw null; } set { } }\n\n        public System.TimeSpan? EntryExpiry { get { throw null; } set { } }\n\n        public System.Func<string, Runtime.GrainId, StackExchange.Redis.RedisKey>? GetStorageKey { get { throw null; } set { } }\n\n        public Storage.IGrainStorageSerializer? GrainStorageSerializer { get { throw null; } set { } }\n\n        public int InitStage { get { throw null; } set { } }\n\n        public static System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer> DefaultCreateMultiplexer(RedisStorageOptions options) { throw null; }\n    }\n\n    public static partial class RedisStorageOptionsExtensions\n    {\n        public static void UseGetRedisKeyIgnoringGrainType(this Microsoft.Extensions.Options.OptionsBuilder<RedisStorageOptions> optionsBuilder) { }\n    }\n}\n\nnamespace Orleans.Persistence.Redis\n{\n    [GenerateSerializer]\n    public partial class RedisStorageException : System.Exception\n    {\n        public RedisStorageException() { }\n\n        [System.Obsolete]\n        protected RedisStorageException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public RedisStorageException(string message, System.Exception inner) { }\n\n        public RedisStorageException(string message) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Persistence.Redis\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RedisStorageException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Persistence.Redis.RedisStorageException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Persistence.Redis.RedisStorageException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_RedisStorageException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Persistence.Redis.RedisStorageException instance) { }\n\n        public global::Orleans.Persistence.Redis.RedisStorageException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Persistence.Redis.RedisStorageException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Persistence.Redis.RedisStorageException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RedisStorageException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Persistence.Redis.RedisStorageException, System.Exception>\n    {\n        public Copier_RedisStorageException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}"
  },
  {
    "path": "src/api/Redis/Orleans.Reminders.Redis/Orleans.Reminders.Redis.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Configuration\n{\n    public partial class RedisReminderTableOptions\n    {\n        public StackExchange.Redis.ConfigurationOptions ConfigurationOptions { get { throw null; } set { } }\n\n        public System.Func<RedisReminderTableOptions, System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer>> CreateMultiplexer { get { throw null; } set { } }\n\n        public System.TimeSpan? EntryExpiry { get { throw null; } set { } }\n\n        public static System.Threading.Tasks.Task<StackExchange.Redis.IConnectionMultiplexer> DefaultCreateMultiplexer(RedisReminderTableOptions options) { throw null; }\n    }\n\n    public partial class RedisReminderTableOptionsValidator : IConfigurationValidator\n    {\n        public RedisReminderTableOptionsValidator(Microsoft.Extensions.Options.IOptions<RedisReminderTableOptions> options) { }\n\n        public void ValidateConfiguration() { }\n    }\n}\n\nnamespace Orleans.Hosting\n{\n    public static partial class SiloBuilderReminderExtensions\n    {\n        public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseRedisReminderService(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action<Configuration.RedisReminderTableOptions> configure) { throw null; }\n\n        public static ISiloBuilder UseRedisReminderService(this ISiloBuilder builder, System.Action<Configuration.RedisReminderTableOptions> configure) { throw null; }\n    }\n}\n\nnamespace Orleans.Reminders.Redis\n{\n    [GenerateSerializer]\n    public partial class RedisRemindersException : System.Exception\n    {\n        public RedisRemindersException() { }\n\n        [System.Obsolete]\n        protected RedisRemindersException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }\n\n        public RedisRemindersException(string message, System.Exception inner) { }\n\n        public RedisRemindersException(string message) { }\n    }\n}\n\nnamespace OrleansCodeGen.Orleans.Reminders.Redis\n{\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Codec_RedisRemindersException : global::Orleans.Serialization.Codecs.IFieldCodec<global::Orleans.Reminders.Redis.RedisRemindersException>, global::Orleans.Serialization.Codecs.IFieldCodec, global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Reminders.Redis.RedisRemindersException>, global::Orleans.Serialization.Serializers.IBaseCodec\n    {\n        public Codec_RedisRemindersException(global::Orleans.Serialization.Serializers.IBaseCodec<System.Exception> _baseTypeSerializer) { }\n\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Reminders.Redis.RedisRemindersException instance) { }\n\n        public global::Orleans.Reminders.Redis.RedisRemindersException ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field) { throw null; }\n\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::Orleans.Reminders.Redis.RedisRemindersException instance)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, global::Orleans.Reminders.Redis.RedisRemindersException value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [System.CodeDom.Compiler.GeneratedCode(\"OrleansCodeGen\", \"9.0.0.0\")]\n    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\n    [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]\n    public sealed partial class Copier_RedisRemindersException : global::Orleans.Serialization.GeneratedCodeHelpers.OrleansGeneratedCodeHelper.ExceptionCopier<global::Orleans.Reminders.Redis.RedisRemindersException, System.Exception>\n    {\n        public Copier_RedisRemindersException(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider) : base(default(Serialization.Serializers.ICodecProvider)!) { }\n    }\n}"
  },
  {
    "path": "src/api/Serializers/Orleans.Serialization.Protobuf/Orleans.Serialization.Protobuf.cs",
    "content": "//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\nnamespace Orleans.Serialization\n{\n    [RegisterSerializer]\n    public sealed partial class ByteStringCodec : Codecs.IFieldCodec<Google.Protobuf.ByteString>, Codecs.IFieldCodec\n    {\n        Google.Protobuf.ByteString Codecs.IFieldCodec<Google.Protobuf.ByteString>.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec<Google.Protobuf.ByteString>.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Google.Protobuf.ByteString value) { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class ByteStringCopier : Cloning.IDeepCopier<Google.Protobuf.ByteString>, Cloning.IDeepCopier\n    {\n        public Google.Protobuf.ByteString DeepCopy(Google.Protobuf.ByteString input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class MapFieldCodec<TKey, TValue> : Codecs.IFieldCodec<Google.Protobuf.Collections.MapField<TKey, TValue>>, Codecs.IFieldCodec\n    {\n        public MapFieldCodec(Codecs.IFieldCodec<TKey> keyCodec, Codecs.IFieldCodec<TValue> valueCodec) { }\n\n        public Google.Protobuf.Collections.MapField<TKey, TValue> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Google.Protobuf.Collections.MapField<TKey, TValue> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class MapFieldCopier<TKey, TValue> : Cloning.IDeepCopier<Google.Protobuf.Collections.MapField<TKey, TValue>>, Cloning.IDeepCopier, Cloning.IBaseCopier<Google.Protobuf.Collections.MapField<TKey, TValue>>, Cloning.IBaseCopier\n    {\n        public MapFieldCopier(Cloning.IDeepCopier<TKey> keyCopier, Cloning.IDeepCopier<TValue> valueCopier) { }\n\n        public void DeepCopy(Google.Protobuf.Collections.MapField<TKey, TValue> input, Google.Protobuf.Collections.MapField<TKey, TValue> output, Cloning.CopyContext context) { }\n\n        public Google.Protobuf.Collections.MapField<TKey, TValue> DeepCopy(Google.Protobuf.Collections.MapField<TKey, TValue> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    [Alias(\"protobuf\")]\n    public sealed partial class ProtobufCodec : Serializers.IGeneralizedCodec, Codecs.IFieldCodec, Cloning.IGeneralizedCopier, Cloning.IDeepCopier, ITypeFilter\n    {\n        public const string WellKnownAlias = \"protobuf\";\n        public ProtobufCodec(System.Collections.Generic.IEnumerable<Serializers.ICodecSelector> serializableTypeSelectors, System.Collections.Generic.IEnumerable<Serializers.ICopierSelector> copyableTypeSelectors) { }\n\n        public object DeepCopy(object input, Cloning.CopyContext context) { throw null; }\n\n        bool Cloning.IGeneralizedCopier.IsSupportedType(System.Type type) { throw null; }\n\n        object Codecs.IFieldCodec.ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        void Codecs.IFieldCodec.WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, object value) { }\n\n        bool? ITypeFilter.IsTypeAllowed(System.Type type) { throw null; }\n\n        bool Serializers.IGeneralizedCodec.IsSupportedType(System.Type type) { throw null; }\n    }\n\n    [RegisterSerializer]\n    public sealed partial class RepeatedFieldCodec<T> : Codecs.IFieldCodec<Google.Protobuf.Collections.RepeatedField<T>>, Codecs.IFieldCodec\n    {\n        public RepeatedFieldCodec(Codecs.IFieldCodec<T> fieldCodec) { }\n\n        public Google.Protobuf.Collections.RepeatedField<T> ReadValue<TInput>(ref Buffers.Reader<TInput> reader, WireProtocol.Field field) { throw null; }\n\n        public void WriteField<TBufferWriter>(ref Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, System.Type expectedType, Google.Protobuf.Collections.RepeatedField<T> value)\n            where TBufferWriter : System.Buffers.IBufferWriter<byte> { }\n    }\n\n    [RegisterCopier]\n    public sealed partial class RepeatedFieldCopier<T> : Cloning.IDeepCopier<Google.Protobuf.Collections.RepeatedField<T>>, Cloning.IDeepCopier, Cloning.IBaseCopier<Google.Protobuf.Collections.RepeatedField<T>>, Cloning.IBaseCopier\n    {\n        public RepeatedFieldCopier(Cloning.IDeepCopier<T> valueCopier) { }\n\n        public void DeepCopy(Google.Protobuf.Collections.RepeatedField<T> input, Google.Protobuf.Collections.RepeatedField<T> output, Cloning.CopyContext context) { }\n\n        public Google.Protobuf.Collections.RepeatedField<T> DeepCopy(Google.Protobuf.Collections.RepeatedField<T> input, Cloning.CopyContext context) { throw null; }\n    }\n\n    public static partial class SerializationHostingExtensions\n    {\n        public static ISerializerBuilder AddProtobufSerializer(this ISerializerBuilder serializerBuilder, System.Func<System.Type, bool> isSerializable, System.Func<System.Type, bool> isCopyable) { throw null; }\n\n        public static ISerializerBuilder AddProtobufSerializer(this ISerializerBuilder serializerBuilder) { throw null; }\n    }\n}"
  },
  {
    "path": "test/Benchmarks/App.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <gcServer enabled=\"true\"/>\n    <gcConcurrent enabled=\"true\"/>\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "test/Benchmarks/Benchmarks.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>Benchmarks</RootNamespace>\n    <AssemblyName>Benchmarks</AssemblyName>\n    <TargetFrameworks>net10.0;net8.0</TargetFrameworks>\n    <OutputType>Exe</OutputType>\n    <DebugSymbols>true</DebugSymbols>\n    <ServerGarbageCollection>true</ServerGarbageCollection>\n    <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <GenerateProgramFile>false</GenerateProgramFile>\n    <!-- Do not warn on errors caused by Protocol Buffers codegen, eg: \"error CS8981: The type name 'pb' only contains lower-cased ascii characters. Such names may become reserved for the language.\" -->\n    <NoWarn>$(NoWarn);8981</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"BenchmarkDotNet\" />\n    <PackageReference Include=\"BenchmarkDotNet.Diagnostics.Windows\" />\n    <PackageReference Include=\"Microsoft.NETFramework.ReferenceAssemblies\" PrivateAssets=\"All\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis\" />\n    <!-- Temporarily kept to resolve a conflict between Microsoft.Azure.DocumentDB.Core's dependencies -->\n    <PackageReference Include=\"System.CodeDom\" />\n    <PackageReference Include=\"Microsoft.Data.SqlClient\" />\n    <PackageReference Include=\"MessagePack\" />\n    <PackageReference Include=\"ZeroFormatter\" />\n    <PackageReference Include=\"Utf8Json\" />\n    <PackageReference Include=\"SpanJson\" />\n    <PackageReference Include=\"Hyperion\" />\n    <PackageReference Include=\"Google.Protobuf\" />\n    <PackageReference Include=\"Grpc.Tools\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Persistence.AzureStorage\\Orleans.Persistence.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Transactions.AzureStorage\\Orleans.Transactions.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AdoNet\\Orleans.Persistence.AdoNet\\Orleans.Persistence.AdoNet.csproj\" />\n    <ProjectReference Include=\"..\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"..\\Grains\\BenchmarkGrains\\BenchmarkGrains.csproj\" />\n    <ProjectReference Include=\"..\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Dashboard\\Orleans.Dashboard\\Orleans.Dashboard.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"Serialization\\Models\\ProtoIntClass.proto\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Update=\"coverlet.collector\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Benchmarks/Dashboard/DashboardGrainBenchmark.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BenchmarkDotNet.Attributes;\nusing Orleans.Dashboard.Metrics.History;\nusing System.Collections;\n\nnamespace Benchmarks.Dashboard\n{\n    [ShortRunJob]\n    [MemoryDiagnoser]\n    internal class DashboardGrainBenchmark\n    {\n        [Params(10)]\n        public int SiloCount { get; set; }\n\n        [Params(50)]\n        public int GrainTypeCount { get; set; }\n\n        [Params(10)]\n        public int GrainMethodCount { get; set; }\n\n        [Params(100)]\n        public int HistorySize { get; set; }\n\n        [ParamsSource(nameof(Histories))]\n        public ITraceHistory History { get; set; }\n\n        public IEnumerable<ITraceHistory> Histories\n        {\n            get\n            {\n                yield return new TraceHistory(HistorySize);\n            }\n        }\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            var startTime = DateTime.UtcNow;\n\n            Setup(startTime, History);\n\n            testTraces = Helper.CreateTraces(startTime.AddSeconds(HistorySize), SiloCount, GrainTypeCount, GrainMethodCount).ToList();\n        }\n\n        private List<TestTraces> testTraces;\n\n        [Benchmark]\n        public void Test_Add_TraceHistory()\n        {\n            foreach (var trace in testTraces)\n            {\n                History.Add(trace.Time, trace.Silo, trace.Traces);\n            }\n        }\n        \n        [Benchmark]\n        public ICollection Test_QueryAll_TraceHistory()\n        {\n            return History.QueryAll();\n        }\n\n        [Benchmark]\n        public ICollection Test_QuerySilo_TraceHistory()\n        {\n            return History.QuerySilo(\"SILO_0\");\n        }\n\n        [Benchmark]\n        public ICollection Test_QueryGrain_TraceHistory()\n        {\n            return History.QueryGrain(\"GRAIN_0\");\n        }\n\n        [Benchmark]\n        public ICollection Test_GroupByGrainAndSilo_TraceHistory()\n        {\n            return History.GroupByGrainAndSilo().ToList();\n        }\n        \n        [Benchmark]\n        public ICollection Test_AggregateByGrainMethod_TraceHistory()\n        {\n            return History.AggregateByGrainMethod().ToList();\n        }\n\n        private void Setup(DateTime startTime, ITraceHistory history)\n        {\n            for (var timeIndex = 0; timeIndex < HistorySize; timeIndex++)\n            {\n                var time = startTime.AddSeconds(timeIndex);\n\n                foreach (var trace in Helper.CreateTraces(time, SiloCount, GrainTypeCount, GrainMethodCount))\n                {\n                    history.Add(trace.Time, trace.Silo, trace.Traces);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Dashboard/Helper.cs",
    "content": "using Orleans.Dashboard.Model;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Benchmarks.Dashboard\n{\n    internal class Helper\n    {\n        public static IEnumerable<TestTraces> CreateTraces(DateTime time, int siloCount, int grainCount, int methodCount)\n        {\n            for (var siloIndex = 0; siloIndex < siloCount; siloIndex++)\n            {\n                var trace = new List<SiloGrainTraceEntry>();\n\n                for (var grainIndex = 0; grainIndex < grainCount; grainIndex++)\n                {\n                    for (var grainMethodIndex = 0; grainMethodIndex < methodCount; grainMethodIndex++)\n                    {\n                        trace.Add(new SiloGrainTraceEntry\n                        {\n                            ElapsedTime = 10,\n                            Count = 100,\n                            Method = $\"METHOD_{grainMethodIndex}\",\n                            Grain = $\"GRAIN_{grainIndex}\",\n                            ExceptionCount = 0\n                        });\n                    }\n                }\n\n                yield return new TestTraces(time, $\"SILO_{siloIndex}\", trace.ToArray());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Dashboard/ManualTests.cs",
    "content": "using Orleans.Dashboard.Metrics.History;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n\nnamespace Benchmarks.Dashboard\n{\n    internal class ManualTests\n    {\n        private const int HistorySize = 100;\n        private readonly ITraceHistory history1 = new TraceHistory(HistorySize);\n        private readonly List<TestTraces> testTraces;\n\n        public ManualTests()\n        {\n            var startTime = DateTime.UtcNow;\n\n            Setup(startTime, history1);\n\n            testTraces = Helper.CreateTraces(startTime.AddSeconds(HistorySize), 10, 50, 10).ToList();\n        }\n\n        private static void Setup(DateTime startTime, ITraceHistory history)\n        {\n            for (var timeIndex = 0; timeIndex < HistorySize; timeIndex++)\n            {\n                var time = startTime.AddSeconds(timeIndex);\n\n                foreach (var trace in Helper.CreateTraces(time, 10, 50, 10))\n                {\n                    history.Add(trace.Time, trace.Silo, trace.Traces);\n                }\n            }\n        }\n\n        public void Run()\n        {\n            Test(\"Add\", history =>\n            {\n                foreach (var trace in testTraces)\n                {\n                    history.Add(trace.Time, trace.Silo, trace.Traces);\n                }\n            });\n\n            Test(\"Query All\", history =>\n            {\n                history.QueryAll();\n            });\n\n            Test(\"Query By Silo\", history =>\n            {\n                history.QuerySilo(\"SILO_0\");\n            });\n\n            Test(\"Query By Grain\", history =>\n            {\n                history.QueryGrain(\"GRAIN_0\");\n            });\n\n            Test(\"Query By Grain and Silo\", history =>\n            {\n                history.GroupByGrainAndSilo();\n            });\n\n            Test(\"Query Aggregated\", history =>\n            {\n                history.AggregateByGrainMethod();\n            });\n        }\n\n        private void Test(string name, Action<ITraceHistory> action)\n        {\n            const int NumIterations = 1;\n\n            var watch = Stopwatch.StartNew();\n\n            for (var i = 0; i < NumIterations; i++)\n            {\n                action(history1);\n            }\n\n            watch.Start();\n\n            Console.WriteLine(\"{0} V1: {1}\", name, watch.Elapsed / NumIterations);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Dashboard/TestTraces.cs",
    "content": "using Orleans.Dashboard.Model;\nusing System;\n\nnamespace Benchmarks.Dashboard\n{\n    internal sealed record TestTraces(DateTime Time, string Silo, SiloGrainTraceEntry[] Traces)\n    {\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/GrainStorage/GrainStorageBenchmark.cs",
    "content": "using System.Diagnostics;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing BenchmarkGrainInterfaces.GrainStorage;\n\nnamespace Benchmarks.GrainStorage;\n\n/// <summary>\n/// Benchmarks grain storage providers by measuring read/write operations against different storage backends.\n/// </summary>\npublic class GrainStorageBenchmark : IDisposable\n{\n    private TestCluster host;\n    private readonly int concurrent;\n    private readonly int payloadSize;\n    private readonly TimeSpan duration;\n\n    public GrainStorageBenchmark(int concurrent, int payloadSize, TimeSpan duration)\n    {\n        this.concurrent = concurrent;\n        this.payloadSize = payloadSize;\n        this.duration = duration;\n    }\n\n    public void MemorySetup()\n    {\n        var builder = new TestClusterBuilder();\n        builder.AddSiloBuilderConfigurator<SiloMemoryStorageConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void AzureTableSetup()\n    {\n        var builder = new TestClusterBuilder();\n        builder.AddSiloBuilderConfigurator<SiloAzureTableStorageConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void AzureBlobSetup()\n    {\n        var builder = new TestClusterBuilder();\n        builder.AddSiloBuilderConfigurator<SiloAzureBlobStorageConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void AdoNetSetup()\n    {\n        var builder = new TestClusterBuilder();\n        builder.AddSiloBuilderConfigurator<SiloAdoNetStorageConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public class SiloMemoryStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddMemoryGrainStorageAsDefault();\n        }\n    }\n\n    public class SiloAzureTableStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddAzureTableGrainStorageAsDefault(options =>\n            {\n                options.TableServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            });\n        }\n    }\n\n    public class SiloAzureBlobStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddAzureBlobGrainStorageAsDefault(options =>\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            });\n        }\n    }\n\n    public class SiloAdoNetStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddAdoNetGrainStorageAsDefault(options =>\n            {\n                options.ConnectionString = TestDefaultConfiguration.DataConnectionString;\n            });\n        }\n    }\n\n    public async Task RunAsync()\n    {\n        Stopwatch sw = Stopwatch.StartNew();\n        bool running = true;\n        bool isRunning() => running;\n        var runTask = Task.WhenAll(Enumerable.Range(0, concurrent).Select(i => RunAsync(i, isRunning)).ToList());\n        Task[] waitTasks = { runTask, Task.Delay(duration) };\n        await Task.WhenAny(waitTasks);\n        running = false;\n        var runResults = await runTask;\n        sw.Stop(); \n        var reports = runResults.SelectMany(r => r).ToList();\n\n        var stored = reports.Count(r => r.Success);\n        var failed = reports.Count(r => !r.Success);\n        var calltimes = reports.Select(r => r.Elapsed.TotalMilliseconds);\n        var calltime = calltimes.Sum();\n        var maxCalltime = calltimes.Max();\n        var averageCalltime = calltimes.Average();\n        Console.WriteLine($\"Performed {stored} persist (read & write) operations with {failed} failures in {sw.ElapsedMilliseconds}ms.\");\n        Console.WriteLine($\"Average time in ms per call was {averageCalltime}, with longest call taking {maxCalltime}ms.\");\n        Console.WriteLine($\"Total time waiting for the persistent store was {calltime}ms.\");\n    }\n\n    public async Task<List<Report>> RunAsync(int instance, Func<bool> running)\n    {\n        var persistentGrain = this.host.Client.GetGrain<IPersistentGrain>(Guid.NewGuid());\n        // activate grain\n        await persistentGrain.Init(payloadSize);\n        var iteration = instance % payloadSize;\n        var reports = new List<Report>(5000);\n        while (running())\n        {\n            var report = await persistentGrain.TrySet(iteration);\n            reports.Add(report);\n            iteration = (iteration + 1) % payloadSize;\n        }\n\n        return reports;\n    }\n\n    public void Teardown()\n    {\n        host.StopAllSilos();\n    }\n\n    public void Dispose()\n    {\n        host?.Dispose();\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/MapReduce/MapReduceBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing BenchmarkGrainInterfaces.MapReduce;\nusing BenchmarkGrains.MapReduce;\nusing Orleans.TestingHost;\n\nnamespace Benchmarks.MapReduce;\n\n/// <summary>\n/// Benchmarks Orleans' capability to perform map-reduce operations with complex processing pipelines.\n/// </summary>\npublic class MapReduceBenchmark : IDisposable\n{\n    private static TestCluster _host;\n    private readonly int _intermediateStagesCount = 15;\n    private readonly int _pipelineParallelization = 4;\n    private readonly int _repeats = 50000;\n    private int _currentRepeat = 0;\n\n    [GlobalSetup]\n    public void BenchmarkSetup()\n    {\n        var builder = new TestClusterBuilder(1);\n        _host = builder.Build();\n        _host.Deploy();\n    }\n\n    [Benchmark]\n    public async Task Bench()\n    {\n        var pipelines = Enumerable\n            .Range(0, this._pipelineParallelization)\n            .AsParallel()\n            .WithDegreeOfParallelism(4)\n            .Select(async i =>\n            {\n                await BenchCore();\n            });\n\n        await Task.WhenAll(pipelines);\n    }\n\n    [GlobalCleanup]\n    public void Teardown()\n    {\n        _host.StopAllSilos();\n    }\n\n    private async Task BenchCore()\n    {\n        List<Task> initializationTasks = new List<Task>();\n        var mapper = _host.GrainFactory.GetGrain<ITransformGrain<string, List<string>>>(Guid.NewGuid());\n        initializationTasks.Add(mapper.Initialize(new MapProcessor()));\n        var reducer =\n            _host.GrainFactory.GetGrain<ITransformGrain<List<string>, Dictionary<string, int>>>(Guid.NewGuid());\n        initializationTasks.Add(reducer.Initialize(new ReduceProcessor()));\n\n        // used for imitation of complex processing pipelines\n        var intermediateGrains = Enumerable\n            .Range(0, this._intermediateStagesCount)\n            .Select(i =>\n            {\n                var intermediateProcessor =\n                    _host.GrainFactory.GetGrain<ITransformGrain<Dictionary<string, int>, Dictionary<string, int>>>\n                        (Guid.NewGuid());\n                initializationTasks.Add(intermediateProcessor.Initialize(new EmptyProcessor()));\n                return intermediateProcessor;\n            });\n\n        initializationTasks.Add(mapper.LinkTo(reducer));\n        var collector = _host.GrainFactory.GetGrain<IBufferGrain<Dictionary<string, int>>>(Guid.NewGuid());\n        using (var e = intermediateGrains.GetEnumerator())\n        {\n            ITransformGrain<Dictionary<string, int>, Dictionary<string, int>> previous = null;\n            if (e.MoveNext())\n            {\n                initializationTasks.Add(reducer.LinkTo(e.Current));\n                previous = e.Current;\n            }\n\n            while (e.MoveNext())\n            {\n                initializationTasks.Add(previous.LinkTo(e.Current));\n                previous = e.Current;\n            }\n\n            initializationTasks.Add(previous.LinkTo(collector));\n        }\n\n        await Task.WhenAll(initializationTasks);\n\n        List<Dictionary<string, int>> resultList = new List<Dictionary<string, int>>();\n\n        while (Interlocked.Increment(ref this._currentRepeat) < this._repeats)\n        {\n            await mapper.SendAsync(this._text);\n            while (!resultList.Any() || resultList.First().Count < 84) // rough way of checking of pipeline completition.\n            {\n                resultList = await collector.ReceiveAll();\n            }\n        }\n    }\n\n    public void Dispose()\n    {\n        _host?.Dispose();\n    }\n\n    private readonly string _text = @\"Historically, the world of data and the world of objects\" +\n      @\" have not been well integrated. Programmers work in C# or Visual Basic\" +\n      @\" and also in SQL or XQuery. On the one side are concepts such as classes,\" +\n      @\" objects, fields, inheritance, and .NET Framework APIs. On the other side\" +\n      @\" are tables, columns, rows, nodes, and separate languages for dealing with\" +\n      @\" them. Data types often require translation between the two worlds; there are\" +\n      @\" different standard functions. Because the object world has no notion of query, a\" +\n      @\" query can only be represented as a string without compile-time type checking or\" +\n      @\" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to\" +\n      @\" objects in memory is often tedious and error-prone. Historically, the world of data and the world of objects\" +\n      @\" have not been well integrated. Programmers work in C# or Visual Basic\" +\n      @\" and also in SQL or XQuery. On the one side are concepts such as classes,\" +\n      @\" objects, fields, inheritance, and .NET Framework APIs. On the other side\" +\n      @\" are tables, columns, rows, nodes, and separate languages for dealing with\" +\n      @\" them. Data types often require translation between the two worlds; there are\" +\n      @\" different standard functions. Because the object world has no notion of query, a\" +\n      @\" query can only be represented as a string without compile-time type checking or\" +\n      @\" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to\" +\n      @\" objects in memory is often tedious and error-prone.\";\n}"
  },
  {
    "path": "test/Benchmarks/MapReduce/MapReduceBenchmarkConfig.cs",
    "content": "using BenchmarkDotNet.Configs;\nusing BenchmarkDotNet.Jobs;\n\nnamespace Benchmarks.MapReduce;\n\npublic class MapReduceBenchmarkConfig : ManualConfig\n{\n    public MapReduceBenchmarkConfig()\n    {\n        AddJob(new Job\n        {\n            Run = {\n                LaunchCount = 1,\n                IterationCount = 2,\n                WarmupCount = 0\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Ping/ConcurrentLoadGenerator.cs",
    "content": "using System.Threading.Channels;\nusing System.Diagnostics;\n\nnamespace Benchmarks.Ping;\n\npublic sealed class ConcurrentLoadGenerator<TState>\n{\n    private static readonly double StopwatchTickPerSecond = Stopwatch.Frequency;\n    private struct WorkBlock\n    {\n        public long StartTimestamp { get; set; }\n        public long EndTimestamp { get; set; }\n        public int Successes { get; set; }\n        public int Failures { get; set; }\n        public readonly int Completed => this.Successes + this.Failures;\n        public readonly double ElapsedSeconds => (this.EndTimestamp - this.StartTimestamp) / StopwatchTickPerSecond;\n        public readonly double RequestsPerSecond => this.Completed / this.ElapsedSeconds;\n    }\n\n    private Channel<WorkBlock> _completedBlocks;\n    private readonly Func<TState, ValueTask> _issueRequest;\n    private readonly Func<int, TState> _getStateForWorker;\n    private readonly bool _logIntermediateResults;\n    private readonly Task[] _tasks;\n    private readonly TState[] _states;\n    private readonly int _numWorkers;\n    private readonly int _blocksPerWorker;\n    private readonly int _requestsPerBlock;\n\n    public ConcurrentLoadGenerator(\n        int maxConcurrency,\n        int blocksPerWorker,\n        int requestsPerBlock,\n        Func<TState, ValueTask> issueRequest,\n        Func<int, TState> getStateForWorker,\n        bool logIntermediateResults = false)\n    {\n        this._numWorkers = maxConcurrency;\n        this._blocksPerWorker = blocksPerWorker;\n        this._requestsPerBlock = requestsPerBlock;\n        this._issueRequest = issueRequest;\n        this._getStateForWorker = getStateForWorker;\n        this._logIntermediateResults = logIntermediateResults;\n        this._tasks = new Task[maxConcurrency];\n        this._states = new TState[maxConcurrency];\n    }\n\n    public async Task Warmup()\n    {\n        this.ResetBetweenRuns();\n        var completedBlockReader = this._completedBlocks.Reader;\n\n        for (var ree = 0; ree < this._numWorkers; ree++)\n        {\n            this._states[ree] = _getStateForWorker(ree);\n            this._tasks[ree] = this.RunWorker(this._states[ree], this._requestsPerBlock, 3);\n        }\n\n        // Wait for warmup to complete.\n        await Task.WhenAll(this._tasks);\n\n        // Ignore warmup blocks.\n        while (completedBlockReader.TryRead(out _)) ;\n        GC.Collect();\n    }\n\n    private void ResetBetweenRuns()\n    {\n        this._completedBlocks = Channel.CreateUnbounded<WorkBlock>(\n            new UnboundedChannelOptions\n            {\n                SingleReader = true,\n                SingleWriter = false,\n                AllowSynchronousContinuations = false\n            });\n    }\n\n    public async Task Run()\n    {\n        this.ResetBetweenRuns();\n        var completedBlockReader = this._completedBlocks.Reader;\n\n        // Start the run.\n        for (var i = 0; i < this._numWorkers; i++)\n        {\n            this._tasks[i] = this.RunWorker(this._states[i], this._requestsPerBlock, this._blocksPerWorker);\n        }\n\n        _ = Task.Run(async () => { try { await Task.WhenAll(this._tasks); } catch { } finally { this._completedBlocks.Writer.Complete(); } });\n        var blocks = new List<WorkBlock>(this._numWorkers * this._blocksPerWorker);\n        var blocksPerReport = this._numWorkers * this._blocksPerWorker / 5;\n        var nextReportBlockCount = blocksPerReport;\n        while (true)\n        {\n            var more = await completedBlockReader.WaitToReadAsync();\n            if (!more) break;\n            while (completedBlockReader.TryRead(out var block))\n            {\n                blocks.Add(block);\n            }\n\n            if (this._logIntermediateResults && blocks.Count >= nextReportBlockCount)\n            {\n                nextReportBlockCount += blocksPerReport;\n                Console.WriteLine(\"    \" + PrintReport(0));\n            }\n        }\n\n        if (this._logIntermediateResults) Console.WriteLine(\"  Total: \" + PrintReport(0));\n        else Console.WriteLine(PrintReport(0));\n\n        string PrintReport(int statingBlockIndex)\n        {\n            if (blocks.Count == 0) return \"No blocks completed\";\n            var successes = 0;\n            var failures = 0;\n            long completed = 0;\n            var reportBlocks = 0;\n            long minStartTime = long.MaxValue;\n            long maxEndTime = long.MinValue;\n            for (var i = statingBlockIndex; i < blocks.Count; i++)\n            {\n                var b = blocks[i];\n                ++reportBlocks;\n                successes += b.Successes;\n                failures += b.Failures;\n                completed += b.Completed;\n                if (b.StartTimestamp < minStartTime) minStartTime = b.StartTimestamp;\n                if (b.EndTimestamp > maxEndTime) maxEndTime = b.EndTimestamp;\n            }\n\n            var totalSeconds = (maxEndTime - minStartTime) / StopwatchTickPerSecond;\n            var ratePerSecond = (long)(completed / totalSeconds);\n            var failureString = failures == 0 ? string.Empty : $\" with {failures} failures\";\n            return $\"{ratePerSecond,6}/s {successes,7} reqs in {totalSeconds,6:0.000}s{failureString}\";\n        }\n    }\n\n    private async Task RunWorker(TState state, int requestsPerBlock, int numBlocks)\n    {\n        var completedBlockWriter = this._completedBlocks.Writer;\n        while (numBlocks > 0)\n        {\n            var workBlock = new WorkBlock();\n            workBlock.StartTimestamp = Stopwatch.GetTimestamp();\n            while (workBlock.Completed < requestsPerBlock)\n            {\n                try\n                {\n                    await this._issueRequest(state).ConfigureAwait(false);\n                    ++workBlock.Successes;\n                }\n                catch\n                {\n                    ++workBlock.Failures;\n                }\n            }\n\n            workBlock.EndTimestamp = Stopwatch.GetTimestamp();\n            await completedBlockWriter.WriteAsync(workBlock).ConfigureAwait(false);\n            --numBlocks;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Ping/FanoutBenchmark.cs",
    "content": "using System.Net;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkGrainInterfaces.Ping;\nusing BenchmarkGrains.Ping;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Console;\nusing Orleans.Configuration;\n\nnamespace Benchmarks.Ping;\n\n/// <summary>\n/// Benchmarks grain communication with fanout patterns across multiple silos.\n/// </summary>\n[MemoryDiagnoser]\npublic class FanoutBenchmark : IDisposable\n{\n    private readonly ConsoleCancelEventHandler _onCancelEvent;\n    private readonly List<IHost> hosts = new();\n    private readonly ITreeGrain grain;\n    private readonly IClusterClient client;\n    private readonly IHost clientHost;\n\n    public FanoutBenchmark() : this(2, true) { }\n\n    public FanoutBenchmark(int numSilos, bool startClient, bool grainsOnSecondariesOnly = false)\n    {\n        for (var i = 0; i < numSilos; ++i)\n        {\n            var primary = i == 0 ? null : new IPEndPoint(IPAddress.Loopback, 11111);\n            var hostBuilder = new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n            {\n#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                siloBuilder.AddActivationRepartitioner();\n#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                siloBuilder.ConfigureLogging(l =>\n                {\n                    l.AddSimpleConsole(o =>\n                    {\n                        o.UseUtcTimestamp = true;\n                        o.TimestampFormat = \"HH:mm:ss \";\n                        o.ColorBehavior = LoggerColorBehavior.Enabled;\n                    });\n                    l.AddFilter(\"Orleans.Runtime.Placement.Repartitioning\", LogLevel.Debug);\n                });\n                siloBuilder.Configure<ActivationRepartitionerOptions>(o =>\n                {\n                });\n                siloBuilder.UseLocalhostClustering(\n                    siloPort: 11111 + i,\n                    gatewayPort: 30000 + i,\n                    primarySiloEndpoint: primary);\n\n                if (i == 0 && grainsOnSecondariesOnly)\n                {\n                    siloBuilder.Configure<GrainTypeOptions>(options => options.Classes.Remove(typeof(PingGrain)));\n                }\n            });\n\n            var host = hostBuilder.Build();\n\n            host.StartAsync().GetAwaiter().GetResult();\n            this.hosts.Add(host);\n        }\n\n        if (grainsOnSecondariesOnly) Thread.Sleep(4000);\n\n        if (startClient)\n        {\n            var hostBuilder = new HostBuilder().UseOrleansClient((ctx, clientBuilder) =>\n            {\n                if (numSilos == 1)\n                {\n                    clientBuilder.UseLocalhostClustering();\n                }\n                else\n                {\n                    var gateways = Enumerable.Range(30000, numSilos).Select(i => new IPEndPoint(IPAddress.Loopback, i)).ToArray();\n                    clientBuilder.UseStaticClustering(gateways);\n                }\n            });\n\n            this.clientHost = hostBuilder.Build();\n            this.clientHost.StartAsync().GetAwaiter().GetResult();\n\n            this.client = this.clientHost.Services.GetRequiredService<IClusterClient>();\n            var grainFactory = this.client;\n\n            this.grain = grainFactory.GetGrain<ITreeGrain>(0, keyExtension: \"0\");\n            this.grain.Ping().AsTask().GetAwaiter().GetResult();\n        }\n\n        _onCancelEvent = CancelPressed;\n        Console.CancelKeyPress += _onCancelEvent;\n        AppDomain.CurrentDomain.FirstChanceException += (object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e) => Console.WriteLine(\"FIRST CHANCE EXCEPTION: \" + LogFormatter.PrintException(e.Exception));\n        AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => Console.WriteLine(\"UNHANDLED EXCEPTION: \" + LogFormatter.PrintException((Exception)e.ExceptionObject));\n    }\n\n    private void CancelPressed(object sender, ConsoleCancelEventArgs e)\n    {\n        Environment.Exit(0);\n    }\n\n    [Benchmark]\n    public ValueTask Ping() => grain.Ping();\n\n    public async Task PingForever()\n    {\n        while (true)\n        {\n            await grain.Ping();\n        }\n    }\n\n    public async Task Shutdown()\n    {\n        if (clientHost is { } client)\n        {\n            await client.StopAsync();\n            if (client is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync();\n            }\n            else\n            {\n                client.Dispose();\n            }\n        }\n\n        this.hosts.Reverse();\n        foreach (var host in this.hosts)\n        {\n            await host.StopAsync();\n            if (host is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync();\n            }\n            else\n            {\n                host.Dispose();\n            }\n        }\n    }\n\n    [GlobalCleanup]\n    public void Dispose()\n    {\n        (this.client as IDisposable)?.Dispose();\n        this.hosts.ForEach(h => h.Dispose());\n\n        Console.CancelKeyPress -= _onCancelEvent;\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Ping/PingBenchmark.cs",
    "content": "using System.Net;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkGrainInterfaces.Ping;\nusing BenchmarkGrains.Ping;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\n\nnamespace Benchmarks.Ping;\n\n/// <summary>\n/// Benchmarks grain-to-grain communication latency and throughput using simple ping operations.\n/// </summary>\n[MemoryDiagnoser]\npublic class PingBenchmark : IDisposable\n{\n    private readonly ConsoleCancelEventHandler _onCancelEvent;\n    private readonly List<IHost> hosts = new List<IHost>();\n    private readonly IPingGrain grain;\n    private readonly IClusterClient client;\n    private readonly IHost clientHost;\n\n    public PingBenchmark() : this(1, true) { }\n\n    public PingBenchmark(int numSilos, bool startClient, bool grainsOnSecondariesOnly = false)\n    {\n        for (var i = 0; i < numSilos; ++i)\n        {\n            var primary = i == 0 ? null : new IPEndPoint(IPAddress.Loopback, 11111);\n            var hostBuilder = new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder.UseLocalhostClustering(\n                    siloPort: 11111 + i,\n                    gatewayPort: 30000 + i,\n                    primarySiloEndpoint: primary);\n\n                if (i == 0 && grainsOnSecondariesOnly)\n                {\n                    siloBuilder.Configure<GrainTypeOptions>(options => options.Classes.Remove(typeof(PingGrain)));\n                }\n            });\n\n            var host = hostBuilder.Build();\n\n            host.StartAsync().GetAwaiter().GetResult();\n            this.hosts.Add(host);\n        }\n\n        if (grainsOnSecondariesOnly) Thread.Sleep(4000);\n\n        if (startClient)\n        {\n            var hostBuilder = new HostBuilder().UseOrleansClient((ctx, clientBuilder) =>\n            {\n                if (numSilos == 1)\n                {\n                    clientBuilder.UseLocalhostClustering();\n                }\n                else\n                {\n                    var gateways = Enumerable.Range(30000, numSilos).Select(i => new IPEndPoint(IPAddress.Loopback, i)).ToArray();\n                    clientBuilder.UseStaticClustering(gateways);\n                }\n            });\n\n            this.clientHost = hostBuilder.Build();\n            this.clientHost.StartAsync().GetAwaiter().GetResult();\n\n            this.client = this.clientHost.Services.GetRequiredService<IClusterClient>();\n            var grainFactory = this.client;\n\n            this.grain = grainFactory.GetGrain<IPingGrain>(Guid.NewGuid().GetHashCode());\n            this.grain.Run().AsTask().GetAwaiter().GetResult();\n        }\n\n        _onCancelEvent = CancelPressed;\n        Console.CancelKeyPress += _onCancelEvent;\n    }\n\n    private void CancelPressed(object sender, ConsoleCancelEventArgs e)\n    {\n        Environment.Exit(0);\n    }\n\n    [Benchmark]\n    public ValueTask Ping() => grain.Run();\n\n    public async Task PingForever()\n    {\n        while (true)\n        {\n            await grain.Run();\n        }\n    }\n\n    public Task PingConcurrentForever() => this.Run(\n        runs: int.MaxValue,\n        grainFactory: this.client,\n        blocksPerWorker: 10);\n\n    public Task PingConcurrent() => this.Run(\n        runs: 3,\n        grainFactory: this.client,\n        blocksPerWorker: 10);\n\n    public Task PingConcurrentHostedClient(int blocksPerWorker = 30) => this.Run(\n        runs: 3,\n        grainFactory: (IGrainFactory)this.hosts[0].Services.GetService(typeof(IGrainFactory)),\n        blocksPerWorker: blocksPerWorker);\n\n    private async Task Run(int runs, IGrainFactory grainFactory, int blocksPerWorker)\n    {\n        var loadGenerator = new ConcurrentLoadGenerator<IPingGrain>(\n            maxConcurrency: 250,\n            blocksPerWorker: blocksPerWorker,\n            requestsPerBlock: 500,\n            issueRequest: g => g.Run(),\n            getStateForWorker: workerId => grainFactory.GetGrain<IPingGrain>(workerId));\n        await loadGenerator.Warmup();\n        while (runs-- > 0) await loadGenerator.Run();\n    }\n\n    public async Task PingPongForever()\n    {\n        var other = this.client.GetGrain<IPingGrain>(Guid.NewGuid().GetHashCode());\n        while (true)\n        {\n            await grain.PingPongInterleave(other, 100);\n        }\n    }\n\n    public async Task Shutdown()\n    {\n        if (clientHost is { } client)\n        {\n            await client.StopAsync();\n            if (client is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync();\n            }\n            else\n            {\n                client.Dispose();\n            }\n        }\n\n        this.hosts.Reverse();\n        foreach (var host in this.hosts)\n        {\n            await host.StopAsync();\n            if (host is IAsyncDisposable asyncDisposable)\n            {\n                await asyncDisposable.DisposeAsync();\n            }\n            else\n            {\n                host.Dispose();\n            }\n        }\n    }\n\n    [GlobalCleanup]\n    public void Dispose()\n    {\n        (this.client as IDisposable)?.Dispose();\n        this.hosts.ForEach(h => h.Dispose());\n\n        Console.CancelKeyPress -= _onCancelEvent;\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Ping/StatelessWorkerBenchmark.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Concurrency;\n\nnamespace Benchmarks.Ping;\n\n/// <summary>\n/// Benchmarks stateless worker grain performance and adaptive worker pool management.\n/// </summary>\npublic class StatelessWorkerBenchmark : IDisposable\n{\n    private readonly IHost _host;\n    private readonly IGrainFactory _grainFactory;\n\n    public StatelessWorkerBenchmark()\n    {\n        _host = new HostBuilder()\n            .UseOrleans((_, siloBuilder) => siloBuilder\n            .UseLocalhostClustering())\n            .Build();\n\n        _host.StartAsync().GetAwaiter().GetResult();\n        _grainFactory = _host.Services.GetRequiredService<IGrainFactory>();\n    }\n\n    public void Dispose()\n    {\n        _host.StopAsync().GetAwaiter().GetResult();\n        _host.Dispose();\n    }\n\n    public async Task RunAsync()\n    {\n        await Run<IMonotonicGrain, SWMonotonicGrain>(_grainFactory.GetGrain<IMonotonicGrain>(0));\n        await Run<IAdaptiveGrain, SWAdaptiveGrain>(_grainFactory.GetGrain<IAdaptiveGrain>(0));\n    }\n\n    private async static Task Run<T, H>(T grain)\n        where T : IProcessorGrain\n        where H : BaseGrain<H>\n    {\n        Console.WriteLine($\"Executing benchmark for {typeof(H).Name}\");\n\n        using var cts = new CancellationTokenSource();\n\n        var statsCollector = Task.Run(async () =>\n        {\n            while (!cts.Token.IsCancellationRequested)\n            {\n                await Task.Delay(1, cts.Token);\n                BaseGrain<H>.UpdateStats();\n            }\n        }, cts.Token);\n\n        var tasks = new List<Task>();\n\n        const int ConcurrencyLevel = 100;\n        const double Lambda = 10.0d;\n\n        for (var i = 0; i < ConcurrencyLevel; i++)\n        {\n            // For a Poisson process with rate λ (tasks / sec in our case), the time between arrivals is\n            // exponentially distributed with density: f(t) = λe^(-λt), t >= 0; and the interarrival\n            // time can be generated as: Δt = -ln(U) / λ, where U is uniformly distributed on (0, 1)\n\n            var u = Random.Shared.NextDouble();\n            var delaySec = -Math.Log(u > 0 ? u : double.Epsilon) / Lambda;\n            var delayMs = (int)(1000 * delaySec);\n\n            await Task.Delay(delayMs);\n            tasks.Add(grain.Process());\n        }\n\n        await Task.WhenAll(tasks);\n\n        const int CooldownCycles = 10;\n\n        for (var i = 1; i <= CooldownCycles; i++)\n        {\n            var cooldownCycle = $\"({i}/{CooldownCycles})\";\n\n            Console.WriteLine($\"\\nWaiting for cooldown {cooldownCycle}\\n\");\n\n            var cooldownMs = (int)(0.1 * Math.Ceiling(BenchmarkConstants.ProcessDelayMs *\n               ((double)ConcurrencyLevel / BenchmarkConstants.MaxWorkersLimit)));\n\n            await Task.Delay(cooldownMs);\n\n            Console.WriteLine($\"Stats {cooldownCycle}:\");\n            Console.WriteLine($\" Active Workers:  {BaseGrain<H>.GetActiveWorkers()}\");\n            Console.WriteLine($\" Average Workers: {BaseGrain<H>.GetAverageActiveWorkers()}\");\n            Console.WriteLine($\" Maximum Workers: {BaseGrain<H>.GetMaxActiveWorkers()}\");\n            Console.Write(\"\\n---------------------------------------------------------------------\\n\");\n        }\n\n        cts.Cancel();\n\n        try\n        {\n            await statsCollector;\n        }\n        catch (OperationCanceledException)\n        {\n\n        }\n\n        BaseGrain<H>.Stop();\n    }\n\n    public static class BenchmarkConstants\n    {\n        public const int MaxWorkersLimit = 10;\n        public const int ProcessDelayMs = 1000;\n    }\n\n    public interface IProcessorGrain : IGrainWithIntegerKey\n    {\n        Task Process();\n    }\n\n    public interface IAdaptiveGrain : IProcessorGrain { }\n    public interface IMonotonicGrain : IProcessorGrain { }\n\n    [StatelessWorker(BenchmarkConstants.MaxWorkersLimit, removeIdleWorkers: false)]\n    public class SWMonotonicGrain : BaseGrain<SWMonotonicGrain>, IMonotonicGrain { }\n\n    [StatelessWorker(BenchmarkConstants.MaxWorkersLimit, removeIdleWorkers: true)]\n    public class SWAdaptiveGrain : BaseGrain<SWAdaptiveGrain>, IAdaptiveGrain { }\n\n    public abstract class BaseGrain<T> : Grain, IProcessorGrain where T : BaseGrain<T>\n    {\n        private static int _activeWorkers = 0;\n        private static int _maxActiveWorkers = 0;\n        private static long _totalWorkerTicks = 0;\n        private static long _lastUpdateTicks = 0;\n\n        private static int _watchStarted = 0;\n        private static int _watchStopped = 0;\n\n        private static readonly Stopwatch Watch = new();\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (Interlocked.CompareExchange(ref _watchStarted, 1, 0) == 0)\n            {\n                Watch.Start();\n            }\n\n            Interlocked.Increment(ref _activeWorkers);\n            UpdateStats();\n\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            Interlocked.Decrement(ref _activeWorkers);\n            UpdateStats();\n\n            if (Volatile.Read(ref _activeWorkers) == 0 &&\n                Interlocked.CompareExchange(ref _watchStopped, 1, 0) == 0)\n            {\n                Watch.Stop();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task Process() => Task.Delay(BenchmarkConstants.ProcessDelayMs);\n\n        public static void UpdateStats()\n        {\n            var currentWorkers = Volatile.Read(ref _activeWorkers);\n\n            int oldMax;\n            do\n            {\n                oldMax = Volatile.Read(ref _maxActiveWorkers);\n                if (currentWorkers <= oldMax)\n                {\n                    break;\n                }\n            } while (Interlocked.CompareExchange(ref _maxActiveWorkers, currentWorkers, oldMax) != oldMax);\n\n            var elapsedTicks = Watch.Elapsed.Ticks;\n            var previousUpdate = Interlocked.Exchange(ref _lastUpdateTicks, elapsedTicks);\n            var elapsedSinceLastUpdate = elapsedTicks - previousUpdate;\n\n            Interlocked.Add(ref _totalWorkerTicks, currentWorkers * elapsedSinceLastUpdate);\n        }\n\n        public static void Stop()\n        {\n            UpdateStats();\n            Watch.Stop();\n        }\n\n        public static int GetActiveWorkers() => Volatile.Read(ref _activeWorkers);\n        public static int GetMaxActiveWorkers() => Volatile.Read(ref _maxActiveWorkers);\n\n        public static double GetAverageActiveWorkers()\n        {\n            var totalTicks = Volatile.Read(ref _totalWorkerTicks);\n            var elapsedTicks = Watch.Elapsed.Ticks;\n            var result = elapsedTicks == 0 ? 0 : (double)totalTicks / elapsedTicks;\n\n            return Math.Round(result, MidpointRounding.ToEven);\n        }\n    }\n}"
  },
  {
    "path": "test/Benchmarks/Program.cs",
    "content": "using System.Diagnostics;\nusing BenchmarkDotNet.Running;\nusing Benchmarks.MapReduce;\nusing Benchmarks.Ping;\nusing Benchmarks.Transactions;\nusing Benchmarks.GrainStorage;\n\nnamespace Benchmarks;\n\ninternal class Program\n{\n    private static readonly Dictionary<string, Action<string[]>> _benchmarks = new Dictionary<string, Action<string[]>>\n    {\n        [\"MapReduce\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running MapReduce benchmark\",\n            () =>\n            {\n                var mapReduceBenchmark = new MapReduceBenchmark();\n                mapReduceBenchmark.BenchmarkSetup();\n                return mapReduceBenchmark;\n            },\n            benchmark => benchmark.Bench().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"Transactions.Memory\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running Transactions benchmark\",\n            () =>\n            {\n                var benchmark = new TransactionBenchmark(2, 20000, 5000);\n                benchmark.MemorySetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"Transactions.Memory.Throttled\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running Transactions benchmark\",\n            () =>\n            {\n                var benchmark = new TransactionBenchmark(2, 200000, 15000);\n                benchmark.MemoryThrottledSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"Transactions.Azure\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running Transactions benchmark\",\n            () =>\n            {\n                var benchmark = new TransactionBenchmark(2, 20000, 5000);\n                benchmark.AzureSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"Transactions.Azure.Throttled\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running Transactions benchmark\",\n            () =>\n            {\n                var benchmark = new TransactionBenchmark(2, 200000, 15000);\n                benchmark.AzureThrottledSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"Transactions.Azure.Overloaded\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running Transactions benchmark\",\n            () =>\n            {\n                var benchmark = new TransactionBenchmark(2, 200000, 15000);\n                benchmark.AzureSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"SequentialPing\"] = _ =>\n        {\n            BenchmarkRunner.Run<PingBenchmark>();\n        },\n        [\"ConcurrentPing\"] = _ =>\n        {\n            {\n                Console.WriteLine(\"## Client to Silo ##\");\n                var test = new PingBenchmark(numSilos: 1, startClient: true);\n                test.PingConcurrent().GetAwaiter().GetResult();\n                test.Shutdown().GetAwaiter().GetResult();\n            }\n            GC.Collect();\n            {\n                Console.WriteLine(\"## Client to 2 Silos ##\");\n                var test = new PingBenchmark(numSilos: 2, startClient: true);\n                test.PingConcurrent().GetAwaiter().GetResult();\n                test.Shutdown().GetAwaiter().GetResult();\n            }\n            GC.Collect();\n            {\n                Console.WriteLine(\"## Hosted Client ##\");\n                var test = new PingBenchmark(numSilos: 1, startClient: false);\n                test.PingConcurrentHostedClient().GetAwaiter().GetResult();\n                test.Shutdown().GetAwaiter().GetResult();\n            }\n            GC.Collect();\n            {\n                // All calls are cross-silo because the calling silo doesn't have any grain classes.\n                Console.WriteLine(\"## Silo to Silo ##\");\n                var test = new PingBenchmark(numSilos: 2, startClient: false, grainsOnSecondariesOnly: true);\n                test.PingConcurrentHostedClient(blocksPerWorker: 10).GetAwaiter().GetResult();\n                test.Shutdown().GetAwaiter().GetResult();\n            }\n            GC.Collect();\n            {\n                Console.WriteLine(\"## Hosted Client ##\");\n                var test = new PingBenchmark(numSilos: 1, startClient: false);\n                test.PingConcurrentHostedClient().GetAwaiter().GetResult();\n                test.Shutdown().GetAwaiter().GetResult();\n            }\n        },\n        [\"ConcurrentPing_OneSilo\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 1, startClient: true).PingConcurrent().GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_TwoSilos\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 2, startClient: true).PingConcurrent().GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_TwoSilos_Forever\"] = _ =>\n        {\n            Console.WriteLine(\"## Client to 2 Silos ##\");\n            var test = new PingBenchmark(numSilos: 2, startClient: true);\n            test.PingConcurrentForever().GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_HostedClient\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 1, startClient: false).PingConcurrentHostedClient().GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_HostedClient_Forever\"] = _ =>\n        {\n            var benchmark = new PingBenchmark(numSilos: 1, startClient: false);\n            Console.WriteLine(\"Press any key to begin.\");\n            Console.ReadKey();\n            Console.WriteLine(\"Press any key to end.\");\n            Console.WriteLine(\"## Hosted Client ##\");\n            while (!Console.KeyAvailable)\n            {\n                benchmark.PingConcurrentHostedClient().GetAwaiter().GetResult();\n            }\n\n            Console.WriteLine(\"Interrupted by user\");\n        },\n        [\"ConcurrentPing_SiloToSilo\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 2, startClient: false, grainsOnSecondariesOnly: true).PingConcurrentHostedClient(blocksPerWorker: 10).GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_SiloToSilo_Forever\"] = _ =>\n        {\n            //Console.WriteLine(\"Press any key to begin.\");\n            //Console.ReadKey();\n            Console.WriteLine(\"Press any key to end.\");\n            Console.WriteLine(\"## Silo to Silo ##\");\n            while (!Console.KeyAvailable)\n            {\n                Console.WriteLine(\"Initializing\");\n                var test = new PingBenchmark(numSilos: 2, startClient: false, grainsOnSecondariesOnly: true);\n                Console.WriteLine(\"Starting\");\n                test.PingConcurrentHostedClient(blocksPerWorker: 100).GetAwaiter().GetResult();\n                Console.WriteLine(\"Stopping\");\n                test.Shutdown().GetAwaiter().GetResult();\n                Console.WriteLine(\"Stopped\");\n            }\n\n            Console.WriteLine(\"Interrupted by user\");\n        },\n        [\"ConcurrentPing_SiloToSilo_Long\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 2, startClient: false, grainsOnSecondariesOnly: true).PingConcurrentHostedClient(blocksPerWorker: 1000).GetAwaiter().GetResult();\n        },\n        [\"ConcurrentPing_OneSilo_Forever\"] = _ =>\n        {\n            new PingBenchmark(numSilos: 1, startClient: true).PingConcurrentForever().GetAwaiter().GetResult();\n        },\n        [\"PingOnce\"] = _ =>\n        {\n            new PingBenchmark().Ping().GetAwaiter().GetResult();\n        },\n        [\"PingForever\"] = _ =>\n        {\n            new PingBenchmark().PingForever().GetAwaiter().GetResult();\n        },\n        [\"PingPongForever\"] = _ =>\n        {\n            new PingBenchmark().PingPongForever().GetAwaiter().GetResult();\n        },\n        [\"PingForever_Min_Threads\"] = _ =>\n        {\n            ThreadPool.SetMaxThreads(1, 1);\n            new PingBenchmark().PingForever().GetAwaiter().GetResult();\n        },\n        [\"FanoutForever\"] = _ =>\n        {\n            new FanoutBenchmark().PingForever().GetAwaiter().GetResult();\n        },\n        [\"StatelessWorker\"] = _ =>\n        {\n            RunBenchmark(\"\", () => new StatelessWorkerBenchmark(),\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Dispose());\n        },\n        [\"GrainStorage.Memory\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running grain storage benchmark against memory\",\n            () =>\n            {\n                var benchmark = new GrainStorageBenchmark(10, 10000, TimeSpan.FromSeconds( 30 ));\n                benchmark.MemorySetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"GrainStorage.AzureTable\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running grain storage benchmark against Azure Table\",\n            () =>\n            {\n                var benchmark = new GrainStorageBenchmark(100, 10000, TimeSpan.FromSeconds( 30 ));\n                benchmark.AzureTableSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"GrainStorage.AzureBlob\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running grain storage benchmark against Azure Blob\",\n            () =>\n            {\n                var benchmark = new GrainStorageBenchmark(10, 10000, TimeSpan.FromSeconds( 30 ));\n                benchmark.AzureBlobSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n        [\"GrainStorage.AdoNet\"] = _ =>\n        {\n            RunBenchmark(\n            \"Running grain storage benchmark against AdoNet\",\n            () =>\n            {\n                var benchmark = new GrainStorageBenchmark(100, 10000, TimeSpan.FromSeconds( 30 ));\n                benchmark.AdoNetSetup();\n                return benchmark;\n            },\n            benchmark => benchmark.RunAsync().GetAwaiter().GetResult(),\n            benchmark => benchmark.Teardown());\n        },\n            [\"Dashboard\"] = _ =>\n            {\n                BenchmarkRunner.Run<Benchmarks.Dashboard.DashboardGrainBenchmark>();\n            },\n            [\"Dashboard.Manual\"] = _ =>\n            {\n                new Benchmarks.Dashboard.ManualTests().Run();\n            },\n        [\"suite\"] = args =>\n        {\n            _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);\n        }\n    };\n\n    // requires benchmark name or 'All' word as first parameter\n    public static void Main(string[] args)\n    {\n        var slicedArgs = args.Skip(1).ToArray();\n        if (args.Length > 0 && args[0].Equals(\"all\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            Console.WriteLine(\"Running full benchmarks suite\");\n            _benchmarks.Select(pair => pair.Value).ToList().ForEach(action => action(slicedArgs));\n            return;\n        }\n\n        if (args.Length == 0 || !_benchmarks.ContainsKey(args[0]))\n        {\n            Console.WriteLine(\"Please, select benchmark, list of available:\");\n            _benchmarks\n                .Select(pair => pair.Key)\n                .ToList()\n                .ForEach(Console.WriteLine);\n            Console.WriteLine(\"All\");\n            return;\n        }\n\n        _benchmarks[args[0]](slicedArgs);\n    }\n\n    private static void RunBenchmark<T>(string name, Func<T> init, Action<T> benchmarkAction, Action<T> tearDown)\n    {\n        Console.WriteLine(name);\n        var bench = init();\n        var stopWatch = Stopwatch.StartNew();\n        benchmarkAction(bench);\n        Console.WriteLine($\"Elapsed milliseconds: {stopWatch.ElapsedMilliseconds}\");\n        Console.WriteLine(\"Press any key to continue ...\");\n        tearDown(bench);\n        Console.ReadLine();\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Benchmarks\": {\n      \"commandName\": \"Project\",\n      \"commandLineArgs\": \"FanoutForever\"\n    }\n  }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/ArrayDeserializeBenchmark.cs",
    "content": "using System.Buffers;\nusing System.Text;\nusing System.Text.Json;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Configs;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\nusing MessagePack;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n#pragma warning disable IDE1006 // Naming Styles\n/// <summary>\n/// Compares Orleans deserialization performance against other popular serializers for array types.\n/// </summary>\n[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\npublic class ArrayDeserializeBenchmark\n{\n    private static readonly MyVector3[] _value;\n    private static readonly Serializer<MyVector3[]> _orleansSerializer;\n    private static readonly byte[] _stjPayload;\n    private static readonly byte[] _protobufPayload;\n    private static readonly byte[] _orleansPayload;\n    private static readonly byte[] _messagePackPayload;\n\n    static ArrayDeserializeBenchmark()\n    {\n        _value = Enumerable.Repeat(new MyVector3 { X = 10.3f, Y = 40.5f, Z = 13411.3f }, 1000).ToArray();\n        var serviceProvider = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        _orleansSerializer = serviceProvider.GetRequiredService<Serializer<MyVector3[]>>();\n\n\n        _orleansPayload = _orleansSerializer.SerializeToArray(_value);\n        _messagePackPayload = MessagePackSerializer.Serialize(_value);\n\n        var stream = new MemoryStream();\n        ProtoBuf.Serializer.Serialize(stream, _value);\n        stream.Position = 0;\n        _protobufPayload = stream.ToArray();\n        _stjPayload = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(_value));\n    }\n\n    [Benchmark(Baseline = true)]\n    public MyVector3[] MessagePackDeserialize() => MessagePackSerializer.Deserialize<MyVector3[]>(_messagePackPayload);\n\n    [Benchmark]\n    public MyVector3[] ProtobufNetDeserialize() => ProtoBuf.Serializer.Deserialize<MyVector3[]>(_protobufPayload.AsSpan());\n\n    [Benchmark]\n    public MyVector3[] SystemTextJsonDeserialize() => JsonSerializer.Deserialize<MyVector3[]>(_stjPayload);\n\n    [Benchmark]\n    public MyVector3[] OrleansDeserialize() => _orleansSerializer.Deserialize(_orleansPayload);\n}\n#pragma warning restore IDE1006 // Naming Styles\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/ArraySerializeBenchmark.cs",
    "content": "using System.Buffers;\nusing System.IO.Pipelines;\nusing System.Text;\nusing System.Text.Json;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Configs;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\nusing MessagePack;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Xunit;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Compares Orleans serialization performance against other popular serializers for array types.\n/// </summary>\n[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\npublic class ArraySerializeBenchmark\n{\n    private static readonly MyVector3[] _value;\n    private static readonly Serializer<MyVector3[]> _orleansSerializer;\n    private static readonly SerializerSession _session;\n    private static readonly ArrayBufferWriter<byte> _arrayBufferWriter;\n    private static readonly Utf8JsonWriter _jsonWriter;\n    private static readonly MemoryStream _stream;\n    private static readonly Pipe _pipe;\n\n    static ArraySerializeBenchmark()\n    {\n        _value = Enumerable.Repeat(new MyVector3 { X = 10.3f, Y = 40.5f, Z = 13411.3f }, 1000).ToArray();\n        var serviceProvider = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        _orleansSerializer = serviceProvider.GetRequiredService<Serializer<MyVector3[]>>();\n        _session = serviceProvider.GetRequiredService<SerializerSessionPool>().GetSession();\n\n        // create buffers\n        _stream = new MemoryStream();\n\n        var serialize1 = _orleansSerializer.SerializeToArray(_value);\n        var serialize2 = MessagePackSerializer.Serialize(_value);\n        ProtoBuf.Serializer.Serialize(_stream, _value);\n        var serialize3 = _stream.ToArray();\n        _stream.Position = 0;\n        var serialize4 = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(_value));\n\n        _arrayBufferWriter = new ArrayBufferWriter<byte>(new[] { serialize1, serialize2, serialize3, serialize4 }.Max(x => x.Length));\n        _jsonWriter = new Utf8JsonWriter(_arrayBufferWriter);\n\n        _pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 0));\n    }\n\n    // return byte[]\n\n    [Benchmark(Baseline = true), BenchmarkCategory(\" byte[]\")]\n    public byte[] MessagePackSerialize()\n    {\n        return MessagePackSerializer.Serialize(_value);\n    }\n\n    [Benchmark, BenchmarkCategory(\" byte[]\")]\n    public byte[] ProtobufNetSerialize()\n    {\n        ProtoBuf.Serializer.Serialize(_stream, _value);\n        var array = _stream.ToArray();\n        _stream.Position = 0;\n        return array;\n    }\n\n    [Benchmark, BenchmarkCategory(\" byte[]\")]\n    public byte[] SystemTextJsonSerialize()\n    {\n        JsonSerializer.Serialize(_stream, _value);\n        var array = _stream.ToArray();\n        _stream.Position = 0;\n        return array;\n    }\n\n    [Benchmark, BenchmarkCategory(\" byte[]\")]\n    public byte[] OrleansSerialize()\n    {\n        return _orleansSerializer.SerializeToArray(_value);\n    }\n\n    // use BufferWriter\n\n    [Fact]\n    [Benchmark(Baseline = true), BenchmarkCategory(\"BufferWriter\")]\n    public void MessagePackBufferWriter()\n    {\n        MessagePackSerializer.Serialize(_arrayBufferWriter, _value);\n        _arrayBufferWriter.Clear();\n    }\n\n    [Fact]\n    [Benchmark, BenchmarkCategory(\"BufferWriter\")]\n    public void ProtobufNetBufferWriter()\n    {\n        ProtoBuf.Serializer.Serialize(_arrayBufferWriter, _value);\n        _arrayBufferWriter.Clear();\n    }\n\n    [Fact]\n    [Benchmark, BenchmarkCategory(\"BufferWriter\")]\n    public void SystemTextJsonBufferWriter()\n    {\n        JsonSerializer.Serialize(_jsonWriter, _value);\n        _jsonWriter.Flush();\n        _arrayBufferWriter.Clear();\n        _jsonWriter.Reset(_arrayBufferWriter);\n    }\n\n    [Fact]\n    [Benchmark, BenchmarkCategory(\"BufferWriter\")]\n    public void OrleansBufferWriter()\n    {\n        var writer = Writer.CreatePooled(_session);\n        try\n        {\n            _orleansSerializer.Serialize(_value, ref writer);\n        }\n        finally\n        {\n            writer.Dispose();\n            _session.Reset();\n        }\n    }\n\n    [Fact]\n    [Benchmark, BenchmarkCategory(\"BufferWriter\")]\n    public void OrleansBufferWriter2()\n    {\n        // wrap ArrayBufferWriter<byte>\n        var writer = _arrayBufferWriter.CreateWriter(_session);\n        try\n        {\n            _orleansSerializer.Serialize(_value, ref writer);\n        }\n        finally\n        {\n            writer.Dispose();\n            _session.Reset();\n        }\n\n        _arrayBufferWriter.Clear(); // clear ArrayBufferWriter<byte>\n    }\n\n    [Fact]\n    [Benchmark]\n    public void OrleansPipeWriter()\n    {\n        var writer = _pipe.Writer.CreateWriter(_session);\n        _orleansSerializer.Serialize(_value, ref writer);\n        _session.Reset();\n\n        _pipe.Writer.Complete();\n        _pipe.Reader.Complete();\n        _pipe.Reset();\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/ClassDeserializeBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Benchmarks.Models;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing Xunit;\nusing SerializerSession = Orleans.Serialization.Session.SerializerSession;\nusing Utf8JsonNS = Utf8Json;\nusing Hyperion;\nusing System.Buffers;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Compares Orleans deserialization performance against other popular serializers for class types.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\n//[DisassemblyDiagnoser(recursiveDepth: 2, printSource: true)]\n//[EtwProfiler]\npublic class ClassDeserializeBenchmark\n{\n    private static readonly MemoryStream ProtoInput;\n\n    private static readonly ReadOnlySequence<byte> GoogleProtoInput;\n\n    private static readonly byte[] MsgPackInput = MessagePack.MessagePackSerializer.Serialize(IntClass.Create());\n\n    private static readonly string NewtonsoftJsonInput = JsonConvert.SerializeObject(IntClass.Create());\n\n    private static readonly byte[] SpanJsonInput = SpanJson.JsonSerializer.Generic.Utf8.Serialize(IntClass.Create());\n\n    private static readonly Hyperion.Serializer HyperionSerializer = new(SerializerOptions.Default.WithKnownTypes(new[] { typeof(IntClass) }));\n    private static readonly MemoryStream HyperionInput;\n\n    private static readonly Serializer<IntClass> Serializer;\n    private static readonly byte[] Input;\n    private static readonly SerializerSession Session;\n\n    private static readonly DeserializerSession HyperionSession;\n\n    private static readonly Utf8JsonNS.IJsonFormatterResolver Utf8JsonResolver = Utf8JsonNS.Resolvers.StandardResolver.Default;\n    private static readonly byte[] Utf8JsonInput;\n\n    private static readonly byte[] SystemTextJsonInput;\n\n    static ClassDeserializeBenchmark()\n    {\n        ProtoInput = new MemoryStream();\n        ProtoBuf.Serializer.Serialize(ProtoInput, IntClass.Create());\n\n        ProtoInput = new MemoryStream();\n        GoogleProtoInput = new ReadOnlySequence<byte>(Google.Protobuf.MessageExtensions.ToByteArray(ProtoIntClass.Create()));\n\n        HyperionInput = new MemoryStream();\n        HyperionSession = HyperionSerializer.GetDeserializerSession();\n        HyperionSerializer.Serialize(IntClass.Create(), HyperionInput);\n\n        // \n        var services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        Serializer = services.GetRequiredService<Serializer<IntClass>>();\n        var bytes = new byte[1000];\n        Session = services.GetRequiredService<SerializerSessionPool>().GetSession();\n        var writer = new SingleSegmentBuffer(bytes).CreateWriter(Session);\n        Serializer.Serialize(IntClass.Create(), ref writer);\n        Input = bytes;\n\n        Utf8JsonInput = Utf8JsonNS.JsonSerializer.Serialize(IntClass.Create(), Utf8JsonResolver);\n\n        var stream = new MemoryStream();\n        using (var jsonWriter = new System.Text.Json.Utf8JsonWriter(stream))\n        {\n            System.Text.Json.JsonSerializer.Serialize(jsonWriter, IntClass.Create());\n        }\n\n        SystemTextJsonInput = stream.ToArray();\n    }\n\n    private static int SumResult(IntClass result) => result.MyProperty1 +\n               result.MyProperty2 +\n               result.MyProperty3 +\n               result.MyProperty4 +\n               result.MyProperty5 +\n               result.MyProperty6 +\n               result.MyProperty7 +\n               result.MyProperty8 +\n               result.MyProperty9;\n\n    private static int SumResult(ProtoIntClass result) => result.MyProperty1 +\n               result.MyProperty2 +\n               result.MyProperty3 +\n               result.MyProperty4 +\n               result.MyProperty5 +\n               result.MyProperty6 +\n               result.MyProperty7 +\n               result.MyProperty8 +\n               result.MyProperty9;\n\n    [Benchmark(Baseline = true)]\n    public int Orleans()\n    {\n        Session.Reset();\n        var instance = Serializer.Deserialize(Input, Session);\n        return SumResult(instance);\n    }\n\n    [Benchmark]\n    public int Utf8Json() => SumResult(Utf8JsonNS.JsonSerializer.Deserialize<IntClass>(Utf8JsonInput, Utf8JsonResolver));\n\n    [Benchmark]\n    public int SystemTextJson() => SumResult(System.Text.Json.JsonSerializer.Deserialize<IntClass>(SystemTextJsonInput));\n\n    [Benchmark]\n    public int MessagePackCSharp() => SumResult(MessagePack.MessagePackSerializer.Deserialize<IntClass>(MsgPackInput));\n\n    [Benchmark]\n    public int ProtobufNet()\n    {\n        ProtoInput.Position = 0;\n        return SumResult(ProtoBuf.Serializer.Deserialize<IntClass>(ProtoInput));\n    }\n\n    [Benchmark]\n    public int GoogleProtobuf()\n    {\n        return SumResult(ProtoIntClass.Parser.ParseFrom(GoogleProtoInput));\n    }\n\n    [Benchmark]\n    public int Hyperion()\n    {\n        HyperionInput.Position = 0;\n\n        return SumResult(HyperionSerializer.Deserialize<IntClass>(HyperionInput, HyperionSession));\n    }\n\n    [Benchmark]\n    public int NewtonsoftJson() => SumResult(JsonConvert.DeserializeObject<IntClass>(NewtonsoftJsonInput));\n\n    [Benchmark(Description = \"SpanJson\")]\n    public int SpanJsonUtf8() => SumResult(SpanJson.JsonSerializer.Generic.Utf8.Deserialize<IntClass>(SpanJsonInput));\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/ClassSerializeBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Benchmarks.Models;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing System.Text;\nusing System.Text.Json;\nusing Xunit;\nusing SerializerSession = Orleans.Serialization.Session.SerializerSession;\nusing Utf8JsonNS = Utf8Json;\nusing Hyperion;\nusing ZeroFormatter;\nusing Google.Protobuf;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Compares Orleans serialization performance against other popular serializers for class types.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\n[PayloadSizeColumn]\npublic class ClassSerializeBenchmark\n{\n    private static readonly IntClass Input = IntClass.Create();\n    private static readonly VirtualIntsClass ZeroFormatterInput = VirtualIntsClass.Create();\n    private static readonly IBufferMessage ProtoInput = ProtoIntClass.Create();\n\n    private static readonly Hyperion.Serializer HyperionSerializer = new(SerializerOptions.Default.WithKnownTypes(new[] { typeof(IntClass) }));\n    private static readonly Hyperion.SerializerSession HyperionSession;\n    private static readonly MemoryStream HyperionBuffer = new();\n\n    private static readonly Serializer<IntClass> Serializer;\n    private static readonly byte[] Data;\n    private static readonly SerializerSession Session;\n\n    private static readonly MemoryStream ProtoBuffer = new();\n\n    private static readonly ClassSingleSegmentBuffer ProtoSegmentBuffer;\n\n    private static readonly MemoryStream Utf8JsonOutput = new();\n    private static readonly Utf8JsonNS.IJsonFormatterResolver Utf8JsonResolver = Utf8JsonNS.Resolvers.StandardResolver.Default;\n\n    private static readonly MemoryStream SystemTextJsonOutput = new();\n    private static readonly Utf8JsonWriter SystemTextJsonWriter;\n\n    static ClassSerializeBenchmark()\n    {\n        var services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        Serializer = services.GetRequiredService<Serializer<IntClass>>();\n        Session = services.GetRequiredService<SerializerSessionPool>().GetSession();\n        Data = new byte[1000];\n\n        HyperionSession = HyperionSerializer.GetSerializerSession();\n\n        SystemTextJsonWriter = new Utf8JsonWriter(SystemTextJsonOutput);\n\n        ProtoSegmentBuffer = new ClassSingleSegmentBuffer(Data);\n    }\n\n    [Benchmark(Baseline = true)]\n    public long Orleans()\n    {\n        Session.Reset();\n        return Serializer.Serialize(Input, Data, Session);\n    }\n\n    [Benchmark]\n    public long Utf8Json()\n    {\n        Utf8JsonOutput.Position = 0;\n        Utf8JsonNS.JsonSerializer.Serialize(Utf8JsonOutput, Input, Utf8JsonResolver);\n        return Utf8JsonOutput.Length;\n    }\n\n    [Benchmark]\n    public long SystemTextJson()\n    {\n        SystemTextJsonOutput.Position = 0;\n        System.Text.Json.JsonSerializer.Serialize(SystemTextJsonWriter, Input);\n        SystemTextJsonWriter.Reset();\n        return SystemTextJsonOutput.Length;\n    }\n\n    [Benchmark]\n    public int MessagePackCSharp()\n    {\n        var bytes = MessagePack.MessagePackSerializer.Serialize(Input);\n        return bytes.Length;\n    }\n\n    [Benchmark]\n    public long ProtobufNet()\n    {\n        ProtoBuffer.Position = 0;\n        ProtoBuf.Serializer.Serialize(ProtoBuffer, Input);\n        return ProtoBuffer.Length;\n    }\n\n    [Benchmark]\n    public long GoogleProtobuf()\n    {\n        ProtoSegmentBuffer.Reset();\n        ProtoInput.WriteTo(ProtoSegmentBuffer);\n        return ProtoSegmentBuffer.Length;\n    }\n\n    [Benchmark]\n    public long Hyperion()\n    {\n        HyperionBuffer.Position = 0;\n        HyperionSerializer.Serialize(Input, HyperionBuffer, HyperionSession);\n        return HyperionBuffer.Length;\n    }\n\n    //[Benchmark]\n    public int ZeroFormatter()\n    {\n        var bytes = ZeroFormatterSerializer.Serialize(ZeroFormatterInput);\n        return bytes.Length;\n    }\n\n    [Benchmark]\n    public int NewtonsoftJson()\n    {\n        var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Input));\n        return bytes.Length;\n    }\n\n    [Benchmark(Description = \"SpanJson\")]\n    public int SpanJsonUtf8()\n    {\n        var bytes = SpanJson.JsonSerializer.Generic.Utf8.Serialize(Input);\n        return bytes.Length;\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/CopierBenchmark.cs",
    "content": "using System.Buffers;\nusing BenchmarkDotNet.Attributes;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Session;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Benchmarks Orleans deep copy performance for various object types including arrays and value types.\n/// </summary>\n[Config(typeof(BenchmarkConfig))]\npublic class CopierBenchmark\n{\n    private static readonly MyVector3[] _vectorArray;\n    private static readonly DeepCopier<MyVector3[]> _arrayCopier;\n    private static readonly DeepCopier<IntStruct> _structCopier;\n    private static readonly IntStruct _intStruct;\n    private static readonly DeepCopier<IntClass> _classCopier;\n    private static readonly ImmutableVector3[] _arrayOfImmutableVectors;\n    private static readonly IntClass _intClass;\n    private static readonly DeepCopier<ImmutableVector3[]> _arrayOfImmutableVectorsCopier;\n    private static readonly SerializerSession _session;\n\n    static CopierBenchmark()\n    {\n        _vectorArray = Enumerable.Repeat(new MyVector3 { X = 10.3f, Y = 40.5f, Z = 13411.3f }, 1000).ToArray();\n        _arrayOfImmutableVectors = Enumerable.Repeat(new ImmutableVector3 { X = 10.3f, Y = 40.5f, Z = 13411.3f }, 1000).ToArray();\n        var serviceProvider = new ServiceCollection()\n            .AddSerializer(builder => builder.AddAssembly(typeof(ArraySerializeBenchmark).Assembly))\n            .BuildServiceProvider();\n        _arrayCopier = serviceProvider.GetRequiredService<DeepCopier<MyVector3[]>>();\n        _structCopier = serviceProvider.GetRequiredService<DeepCopier<IntStruct>>();\n        _intStruct = IntStruct.Create();\n        _classCopier = serviceProvider.GetRequiredService<DeepCopier<IntClass>>();\n        _intClass = IntClass.Create();\n        _arrayOfImmutableVectorsCopier = serviceProvider.GetRequiredService<DeepCopier<ImmutableVector3[]>>();\n        _session = serviceProvider.GetRequiredService<SerializerSessionPool>().GetSession();\n    }\n\n    [Benchmark]\n    public void VectorArray() => _arrayCopier.Copy(_vectorArray);\n\n    [Benchmark]\n    public void ImmutableVectorArray() => _arrayOfImmutableVectorsCopier.Copy(_arrayOfImmutableVectors);\n\n    [Benchmark]\n    public void Struct() => _structCopier.Copy(_intStruct);\n\n    [Benchmark]\n    public void Class() => _classCopier.Copy(_intClass);\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/StructDeserializeBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing Xunit;\nusing SerializerSession = Orleans.Serialization.Session.SerializerSession;\nusing Utf8JsonNS = Utf8Json;\nusing Hyperion;\nusing ZeroFormatter;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Compares Orleans deserialization performance against other popular serializers for struct types.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\n//[DisassemblyDiagnoser(recursiveDepth: 4)]\n//[EtwProfiler]\npublic class StructDeserializeBenchmark\n{\n    private static readonly MemoryStream ProtoInput;\n    private static readonly string NewtonsoftJsonInput = JsonConvert.SerializeObject(IntStruct.Create());\n\n    private static readonly byte[] SpanJsonInput = SpanJson.JsonSerializer.Generic.Utf8.Serialize(IntStruct.Create());\n\n    private static readonly byte[] MsgPackInput = MessagePack.MessagePackSerializer.Serialize(IntStruct.Create());\n    private static readonly byte[] ZeroFormatterInput = ZeroFormatterSerializer.Serialize(IntStruct.Create());\n\n    private static readonly Hyperion.Serializer HyperionSerializer = new(SerializerOptions.Default.WithKnownTypes(new[] { typeof(IntStruct) }));\n    private static readonly MemoryStream HyperionInput;\n    private static readonly DeserializerSession HyperionSession;\n\n    private static readonly ValueSerializer<IntStruct> Serializer;\n    private static readonly byte[] Input;\n    private static readonly SerializerSession Session;\n\n    private static readonly Utf8JsonNS.IJsonFormatterResolver Utf8JsonResolver = Utf8JsonNS.Resolvers.StandardResolver.Default;\n    private static readonly byte[] Utf8JsonInput;\n    private static readonly byte[] SystemTextJsonInput;\n\n    static StructDeserializeBenchmark()\n    {\n        ProtoInput = new MemoryStream();\n        ProtoBuf.Serializer.Serialize(ProtoInput, IntStruct.Create());\n\n        HyperionInput = new MemoryStream();\n        HyperionSerializer.Serialize(IntStruct.Create(), HyperionInput);\n\n        // \n        var services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        Serializer = services.GetRequiredService<ValueSerializer<IntStruct>>();\n        Session = services.GetRequiredService<SerializerSessionPool>().GetSession();\n        var bytes = new byte[1000];\n        var writer = new SingleSegmentBuffer(bytes).CreateWriter(Session);\n        IntStruct intStruct = IntStruct.Create();\n        Serializer.Serialize(ref intStruct, ref writer);\n        Input = bytes;\n\n        HyperionSession = HyperionSerializer.GetDeserializerSession();\n\n        Utf8JsonInput = Utf8JsonNS.JsonSerializer.Serialize(IntStruct.Create(), Utf8JsonResolver);\n\n        var stream = new MemoryStream();\n        using (var jsonWriter = new System.Text.Json.Utf8JsonWriter(stream))\n        {\n            System.Text.Json.JsonSerializer.Serialize(jsonWriter, IntStruct.Create());\n        }\n\n        SystemTextJsonInput = stream.ToArray();\n    }\n\n    private static int SumResult(in IntStruct result) => result.MyProperty1 +\n               result.MyProperty2 +\n               result.MyProperty3 +\n               result.MyProperty4 +\n               result.MyProperty5 +\n               result.MyProperty6 +\n               result.MyProperty7 +\n               result.MyProperty8 +\n               result.MyProperty9;\n\n    [Benchmark(Baseline = true)]\n    public int Orleans()\n    {\n        Session.Reset();\n        IntStruct result = default;\n        Serializer.Deserialize(Input, ref result, Session);\n        return SumResult(in result);\n    }\n\n    [Benchmark]\n    public int Utf8Json() => SumResult(Utf8JsonNS.JsonSerializer.Deserialize<IntStruct>(Utf8JsonInput, Utf8JsonResolver));\n\n    [Benchmark]\n    public int SystemTextJson() => SumResult(System.Text.Json.JsonSerializer.Deserialize<IntStruct>(SystemTextJsonInput));\n\n    [Benchmark]\n    public int MessagePackCSharp() => SumResult(MessagePack.MessagePackSerializer.Deserialize<IntStruct>(MsgPackInput));\n\n    [Benchmark]\n    public int ProtobufNet()\n    {\n        ProtoInput.Position = 0;\n        return SumResult(ProtoBuf.Serializer.Deserialize<IntStruct>(ProtoInput));\n    }\n\n    [Benchmark]\n    public int Hyperion()\n    {\n        HyperionInput.Position = 0;\n        return SumResult(HyperionSerializer.Deserialize<IntStruct>(HyperionInput, HyperionSession));\n    }\n\n    //[Benchmark]\n    public int ZeroFormatter() => SumResult(ZeroFormatterSerializer.Deserialize<IntStruct>(ZeroFormatterInput));\n\n    [Benchmark]\n    public int NewtonsoftJson() => SumResult(JsonConvert.DeserializeObject<IntStruct>(NewtonsoftJsonInput));\n\n    [Benchmark(Description = \"SpanJson\")]\n    public int SpanJsonUtf8() => SumResult(SpanJson.JsonSerializer.Generic.Utf8.Deserialize<IntStruct>(SpanJsonInput));\n} \n"
  },
  {
    "path": "test/Benchmarks/Serialization/Comparison/StructSerializeBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing System.Text;\nusing System.Text.Json;\nusing Xunit;\nusing SerializerSession = Orleans.Serialization.Session.SerializerSession;\nusing Utf8JsonNS = Utf8Json;\nusing Hyperion;\nusing ZeroFormatter;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization.Comparison;\n\n/// <summary>\n/// Compares Orleans serialization performance against other popular serializers for struct types.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\n[BenchmarkCategory(\"Serialization\")]\n[PayloadSizeColumn]\npublic class StructSerializeBenchmark\n{\n    private static readonly IntStruct Input = IntStruct.Create();\n\n    private static readonly Hyperion.Serializer HyperionSerializer = new(SerializerOptions.Default.WithKnownTypes(new[] { typeof(IntStruct) }));\n    private static readonly Hyperion.SerializerSession HyperionSession;\n\n    private static readonly Serializer<IntStruct> Serializer;\n    private static readonly byte[] Data;\n    private static readonly SerializerSession Session;\n    private static readonly MemoryStream ProtoBuffer = new();\n    private static readonly MemoryStream HyperionBuffer = new();\n\n    private static readonly MemoryStream Utf8JsonOutput = new();\n    private static readonly Utf8JsonNS.IJsonFormatterResolver Utf8JsonResolver = Utf8JsonNS.Resolvers.StandardResolver.Default;\n\n    private static readonly MemoryStream SystemTextJsonOutput = new();\n    private static readonly Utf8JsonWriter SystemTextJsonWriter;\n\n    static StructSerializeBenchmark()\n    {\n        // \n        var services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        Serializer = services.GetRequiredService<Serializer<IntStruct>>();\n        Data = new byte[1000];\n        Session = services.GetRequiredService<SerializerSessionPool>().GetSession();\n\n        HyperionSession = HyperionSerializer.GetSerializerSession();\n\n        SystemTextJsonWriter = new Utf8JsonWriter(SystemTextJsonOutput);\n    }\n\n    [Benchmark(Baseline = true)]\n    public long Orleans()\n    {\n        Session.Reset();\n        return Serializer.Serialize(Input, Data, Session);\n    }\n\n    [Benchmark]\n    public long Utf8Json()\n    {\n        Utf8JsonOutput.Position = 0;\n        Utf8JsonNS.JsonSerializer.Serialize(Utf8JsonOutput, Input, Utf8JsonResolver);\n        return Utf8JsonOutput.Length;\n    }\n\n    [Benchmark]\n    public long SystemTextJson()\n    {\n        SystemTextJsonOutput.Position = 0;\n        System.Text.Json.JsonSerializer.Serialize(SystemTextJsonWriter, Input);\n\n        SystemTextJsonWriter.Reset();\n        return SystemTextJsonOutput.Length;\n    }\n\n    [Benchmark]\n    public int MessagePackCSharp()\n    {\n        var bytes = MessagePack.MessagePackSerializer.Serialize(Input);\n        return bytes.Length;\n    }\n\n    [Benchmark]\n    public long ProtobufNet()\n    {\n        ProtoBuffer.Position = 0;\n        ProtoBuf.Serializer.Serialize(ProtoBuffer, Input);\n        return ProtoBuffer.Length;\n    }\n\n    [Benchmark]\n    public long Hyperion()\n    {\n        HyperionBuffer.Position = 0;\n        HyperionSerializer.Serialize(Input, HyperionBuffer, HyperionSession);\n        return HyperionBuffer.Length;\n    }\n\n    //[Benchmark]\n    public int ZeroFormatter()\n    {\n        var bytes = ZeroFormatterSerializer.Serialize(Input);\n        return bytes.Length;\n    }\n\n    [Benchmark]\n    public int NewtonsoftJson()\n    {\n        var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Input));\n        return bytes.Length;\n    }\n\n    [Benchmark(Description = \"SpanJson\")]\n    public int SpanJsonUtf8()\n    {\n        var bytes = SpanJson.JsonSerializer.Generic.Utf8.Serialize(Input);\n        return bytes.Length;\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/ComplexTypeBenchmarks.cs",
    "content": "using System.Buffers;\nusing System.IO.Pipelines;\nusing BenchmarkDotNet.Attributes;\nusing Benchmarks.Serialization.Models;\nusing Benchmarks.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Networking.Shared;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Session;\nusing Xunit;\n\nnamespace Benchmarks.Serialization;\n\n/// <summary>\n/// Benchmarks Orleans serialization performance for complex object graphs with circular references.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\n[MemoryDiagnoser]\npublic class ComplexTypeBenchmarks\n{\n    private static SingleSegmentBuffer Buffer = new(new byte[1000]);\n    private readonly Serializer<SimpleStruct> _structSerializer;\n    private readonly DeepCopier<SimpleStruct> _structCopier;\n    private readonly Serializer<ComplexClass> _serializer;\n    private readonly DeepCopier<ComplexClass> _copier;\n    private readonly SerializerSessionPool _sessionPool;\n    private readonly ComplexClass _value;\n    private readonly SerializerSession _session;\n    private readonly ReadOnlySequence<byte> _serializedPayload;\n    private readonly long _readBytesLength;\n    private readonly Pipe _pipe;\n    private readonly MessageSerializer _messageSerializer;\n    private readonly SimpleStruct _structValue;\n    private readonly Message _message;\n    private readonly Message _structMessage;\n\n    public ComplexTypeBenchmarks()\n    {\n        var services = new ServiceCollection();\n        _ = services\n            .AddSerializer();\n        var serviceProvider = services.BuildServiceProvider();\n        _serializer = serviceProvider.GetRequiredService<Serializer<ComplexClass>>();\n        _copier = serviceProvider.GetRequiredService<DeepCopier<ComplexClass>>();\n        _structSerializer = serviceProvider.GetRequiredService<Serializer<SimpleStruct>>();\n        _structCopier = serviceProvider.GetRequiredService<DeepCopier<SimpleStruct>>();\n        _sessionPool = serviceProvider.GetRequiredService<SerializerSessionPool>();\n        _value = new ComplexClass\n        {\n            BaseInt = 192,\n            Int = 501,\n            String = \"bananas\",\n            //Array = Enumerable.Range(0, 60).ToArray(),\n            //MultiDimensionalArray = new[,] {{0, 2, 4}, {1, 5, 6}}\n        };\n        _value.AlsoSelf = _value.BaseSelf = _value.Self = _value;\n        _message = new() { BodyObject = new Response<ComplexClass> { TypedResult = _value } };\n\n        _structValue = new SimpleStruct\n        {\n            Int = 42,\n            Bool = true,\n            Guid = Guid.NewGuid()\n        };\n        _structMessage = new() { BodyObject = new Response<SimpleStruct> { TypedResult = _structValue } };\n\n        _session = _sessionPool.GetSession();\n        var writer = Buffer.CreateWriter(_session);\n\n        _serializer.Serialize(_value, ref writer);\n        var bytes = new byte[writer.Output.GetMemory().Length];\n        writer.Output.GetReadOnlySpan().CopyTo(bytes);\n        _serializedPayload = new ReadOnlySequence<byte>(bytes);\n        Buffer.Reset();\n        _readBytesLength = _serializedPayload.Length;\n\n        _pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 0));\n        var memoryPool = new SharedMemoryPool();\n        _messageSerializer = new(_sessionPool, memoryPool, new SiloMessagingOptions());\n    }\n\n    [Fact]\n    public void SerializeComplex()\n    {\n        var writer = Buffer.CreateWriter(_session);\n        _session.Reset();\n        _serializer.Serialize(_value, ref writer);\n\n        _session.Reset();\n        var reader = Reader.Create(writer.Output.GetReadOnlySpan(), _session);\n        _ = _serializer.Deserialize(ref reader);\n        Buffer.Reset();\n    }\n\n    [Fact]\n    public void CopyComplex()\n    {\n        _copier.Copy(_value); \n    }\n\n    [Fact]\n    public void CopyComplexStruct()\n    {\n        _structCopier.Copy(_structValue); \n    }\n\n    [Benchmark]\n    public SimpleStruct OrleansStructRoundTrip()\n    {\n        var writer = Buffer.CreateWriter(_session);\n        _session.Reset();\n        _structSerializer.Serialize(_structValue, ref writer);\n\n        _session.Reset();\n        var reader = Reader.Create(writer.Output.GetReadOnlySpan(), _session);\n        var result = _structSerializer.Deserialize(ref reader);\n        Buffer.Reset();\n        return result;\n    }\n\n/*\n    [Fact]\n    [Benchmark]\n    public void OrleansMessageSerializerStructRoundTrip()\n    {\n        var buffer = new PooledBuffer();\n        var (headerLength, bodyLength) = _messageSerializer.Write(ref buffer, _structMessage);\n\n        var readBuffer = buffer.Slice();\n        _messageSerializer.Read(in readBuffer, headerLength, bodyLength, out var result);\n\n        ((Response<SimpleStruct>)result.BodyObject).Dispose();\n    }\n    */\n\n    //[Benchmark]\n    public object OrleansClassRoundTrip()\n    {\n        var writer = Buffer.CreateWriter(_session);\n        _session.Reset();\n        _serializer.Serialize(_value, ref writer);\n\n        _session.Reset();\n        var reader = Reader.Create(writer.Output.GetReadOnlySpan(), _session);\n        var result = _serializer.Deserialize(ref reader);\n        Buffer.Reset();\n        return result;\n    }\n\n    /*\n    [Fact]\n    //[Benchmark]\n    public void OrleansMessageSerializerClassRoundTrip()\n    {\n        var buffer = new PooledBuffer();\n        var (headerLength, bodyLength) = _messageSerializer.Write(ref buffer, _message);\n\n        var readBuffer = buffer.Slice();\n        _messageSerializer.Read(in readBuffer, headerLength, bodyLength, out var result);\n\n        ((Response<ComplexClass>)result.BodyObject).Dispose();\n\n        _pipe.Writer.Complete();\n        _pipe.Reader.Complete();\n        _pipe.Reset();\n    }\n    */\n\n    //[Benchmark]\n    public object OrleansSerialize()\n    {\n        var writer = Buffer.CreateWriter(_session);\n        _session.Reset();\n        _serializer.Serialize(_value, ref writer);\n        Buffer.Reset();\n        return _session;\n    }\n\n    //[Benchmark]\n    public object OrleansDeserialize()\n    {\n        _session.Reset();\n        var reader = Reader.Create(_serializedPayload, _session);\n        return _serializer.Deserialize(ref reader);\n    }\n\n    //[Benchmark]\n    public int OrleansReadEachByte()\n    {\n        var sum = 0;\n        var reader = Reader.Create(_serializedPayload, _session);\n        for (var i = 0; i < _readBytesLength; i++)\n        {\n            sum ^= reader.ReadByte();\n        }\n\n        return sum;\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/FieldHeaderBenchmarks.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.WireProtocol;\nusing Microsoft.Extensions.DependencyInjection;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization;\n\n/// <summary>\n/// Benchmarks Orleans wire protocol field header encoding and writing performance.\n/// </summary>\n[Config(typeof(BenchmarkConfig))]\npublic class FieldHeaderBenchmarks\n{\n    private static readonly SerializerSession Session;\n    private static readonly byte[] OrleansBuffer = new byte[1000];\n\n    static FieldHeaderBenchmarks()\n    {\n        var services = new ServiceCollection().AddSerializer();\n        var serviceProvider = services.BuildServiceProvider();\n        var sessionPool = serviceProvider.GetRequiredService<SerializerSessionPool>();\n        Session = sessionPool.GetSession();\n    }\n\n    [Benchmark(Baseline = true)]\n    public void WritePlainExpectedEmbeddedId()\n    {\n        var writer = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n\n        // Use an expected type and a field id with a value small enough to be embedded.\n        writer.WriteFieldHeader(4, typeof(uint), typeof(uint), WireType.VarInt);\n    }\n\n    [Benchmark]\n    public void WritePlainExpectedExtendedId()\n    {\n        var writer = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n\n        // Use a field id delta which is too large to be embedded.\n        writer.WriteFieldHeader(Tag.MaxEmbeddedFieldIdDelta + 20, typeof(uint), typeof(uint), WireType.VarInt);\n    }\n\n    [Benchmark]\n    public void WriteFastEmbedded()\n    {\n        var writer = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n\n        // Use an expected type and a field id with a value small enough to be embedded.\n        writer.WriteFieldHeaderExpected(4, WireType.VarInt);\n    }\n\n    [Benchmark]\n    public void WriteFastExtended()\n    {\n        var writer = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n\n        // Use a field id delta which is too large to be embedded.\n        writer.WriteFieldHeaderExpected(Tag.MaxEmbeddedFieldIdDelta + 20, WireType.VarInt);\n    }\n\n    [Benchmark]\n    public void CreateWriter() => _ = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n\n    [Benchmark]\n    public void WriteByte()\n    {\n        var writer = new SingleSegmentBuffer(OrleansBuffer).CreateWriter(Session);\n        writer.WriteByte((byte)4);\n    }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/MegaGraphBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Buffers;\nusing System.Globalization;\nusing System.IO.Pipelines;\nusing Xunit;\nusing SerializerSession = Orleans.Serialization.Session.SerializerSession;\nusing Benchmarks.Serialization.Utilities;\n\nnamespace Benchmarks.Serialization;\n\n/// <summary>\n/// Benchmarks Orleans serialization performance for very large object graphs with hundreds of thousands of items.\n/// </summary>\n[Trait(\"Category\", \"Benchmark\")]\n[Config(typeof(BenchmarkConfig))]\npublic class MegaGraphBenchmark\n{\n    private static readonly Serializer<Dictionary<string, int>> Serializer;\n    private static readonly byte[] Input;\n    private static readonly SerializerSession Session;\n    private static readonly Dictionary<string, int> Value;\n\n    static MegaGraphBenchmark()\n    {\n        const int Size = 250_000;\n        Value = new Dictionary<string, int>(Size);\n        for (var i = 0; i < Size; i++)\n        {\n            Value[i.ToString(CultureInfo.InvariantCulture)] = i;\n        }\n        \n        var services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        Serializer = services.GetRequiredService<Serializer<Dictionary<string, int>>>();\n        Session = services.GetRequiredService<SerializerSessionPool>().GetSession();\n        var pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline));\n        var writer = pipe.Writer.CreateWriter(Session);\n        Serializer.Serialize(Value, ref writer);\n        pipe.Writer.FlushAsync();\n        pipe.Reader.TryRead(out var result);\n        Input = result.Buffer.ToArray();\n    }\n\n    [Benchmark]\n    public object Deserialize()\n    {\n        Session.Reset();\n        var instance = Serializer.Deserialize(Input, Session);\n        return instance;\n    }\n\n    [Benchmark]\n    public int Serialize()\n    {\n        Session.Reset();\n        var writer = Writer.CreatePooled(Session);\n        Serializer.Serialize(Value, ref writer);\n        writer.Dispose();\n        return writer.Position;\n    }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/ComplexClass.cs",
    "content": "namespace Benchmarks.Serialization.Models;\n\n[Serializable]\n[GenerateSerializer]\npublic class ComplexClass : SimpleClass\n{\n    [Id(0)]\n    public int Int { get; set; }\n\n    [Id(1)]\n    public string String { get; set; }\n\n    [Id(2)]\n    public ComplexClass Self { get; set; }\n\n    [Id(3)]\n    public object AlsoSelf { get; set; }\n\n    [Id(4)]\n    public SimpleClass BaseSelf { get; set; }\n\n    [Id(5)]\n    public int[] Array { get; set; }\n\n    [Id(6)]\n    public int[,] MultiDimensionalArray { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/IntClass.cs",
    "content": "using MessagePack;\nusing ProtoBuf;\n\nnamespace Benchmarks.Serialization.Models;\n\n[Serializable]\n[GenerateSerializer]\n[ProtoContract]\n[MessagePackObject]\npublic sealed class IntClass\n{\n    public static IntClass Create()\n    {\n        var result = new IntClass();\n        result.Initialize();\n        return result;\n    }\n\n    public void Initialize() => MyProperty1 = MyProperty2 =\n        MyProperty3 = MyProperty4 = MyProperty5 = MyProperty6 = MyProperty7 = MyProperty8 = MyProperty9 = 10;\n\n    [Id(0)]\n    [ProtoMember(1)]\n    [Key(0)]\n    public int MyProperty1 { get; set; }\n\n    [Id(1)]\n    [ProtoMember(2)]\n    [Key(1)]\n    public int MyProperty2 { get; set; }\n\n    [Id(2)]\n    [ProtoMember(3)]\n    [Key(2)]\n    public int MyProperty3 { get; set; }\n\n    [Id(3)]\n    [ProtoMember(4)]\n    [Key(3)]\n    public int MyProperty4 { get; set; }\n\n    [Id(4)]\n    [ProtoMember(5)]\n    [Key(4)]\n    public int MyProperty5 { get; set; }\n\n    [Id(5)]\n    [ProtoMember(6)]\n    [Key(5)]\n    public int MyProperty6 { get; set; }\n\n    [Id(6)]\n    [ProtoMember(7)]\n    [Key(6)]\n    public int MyProperty7 { get; set; }\n\n    [Id(7)]\n    [ProtoMember(8)]\n    [Key(7)]\n    public int MyProperty8 { get; set; }\n\n    [Id(8)]\n    [ProtoMember(9)]\n    [Key(8)]\n    public int MyProperty9 { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/IntStruct.cs",
    "content": "using MessagePack;\nusing ProtoBuf;\nusing ZeroFormatter;\n\nnamespace Benchmarks.Serialization.Models;\n\n[Serializable]\n[GenerateSerializer]\n[ProtoContract]\n[ZeroFormattable]\n[MessagePackObject]\npublic struct IntStruct\n{\n    public static IntStruct Create()\n    {\n        var result = new IntStruct();\n        result.Initialize();\n        return result;\n    }\n\n    public void Initialize() => MyProperty1 = MyProperty2 =\n        MyProperty3 = MyProperty4 = MyProperty5 = MyProperty6 = MyProperty7 = MyProperty8 = MyProperty9 = 10;\n\n    public IntStruct(int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9)\n    {\n        MyProperty1 = p1;\n        MyProperty2 = p2;\n        MyProperty3 = p3;\n        MyProperty4 = p4;\n        MyProperty5 = p5;\n        MyProperty6 = p6;\n        MyProperty7 = p7;\n        MyProperty8 = p8;\n        MyProperty9 = p9;\n    }\n\n    [Id(0)]\n    [Index(0)]\n    [Key(0)]\n    [ProtoMember(1)]\n    public int MyProperty1 { get; set; }\n\n    [Id(1)]\n    [Index(1)]\n    [Key(1)]\n    [ProtoMember(2)]\n    public int MyProperty2 { get; set; }\n\n    [Id(2)]\n    [Index(2)]\n    [Key(2)]\n    [ProtoMember(3)]\n    public int MyProperty3 { get; set; }\n\n    [Id(3)]\n    [Index(3)]\n    [Key(3)]\n    [ProtoMember(4)]\n    public int MyProperty4 { get; set; }\n\n    [Id(4)]\n    [Key(4)]\n    [Index(4)]\n    [ProtoMember(5)]\n    public int MyProperty5 { get; set; }\n\n    [Id(5)]\n    [Key(5)]\n    [Index(5)]\n    [ProtoMember(6)]\n    public int MyProperty6 { get; set; }\n\n    [Id(6)]\n    [Index(6)]\n    [Key(6)]\n    [ProtoMember(7)]\n    public int MyProperty7 { get; set; }\n\n    [Id(7)]\n    [ProtoMember(8)]\n    [Index(7)]\n    [Key(7)]\n    public int MyProperty8 { get; set; }\n\n    [Id(8)]\n    [ProtoMember(9)]\n    [Index(8)]\n    [Key(8)]\n    public int MyProperty9 { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/ProtoIntClass.cs",
    "content": "namespace Benchmarks.Models;\n\npublic partial class ProtoIntClass\n{\n    public static ProtoIntClass Create()\n    {\n        var result = new ProtoIntClass();\n        result.Initialize();\n        return result;\n    }\n\n    public void Initialize() => MyProperty1 = MyProperty2 =\n        MyProperty3 = MyProperty4 = MyProperty5 = MyProperty6 = MyProperty7 = MyProperty8 = MyProperty9 = 10;\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/ProtoIntClass.proto",
    "content": "syntax = \"proto3\";\n\npackage Benchmarks.Models;\n\nmessage ProtoIntClass {\n  int32 my_property_1 = 1;\n  int32 my_property_2 = 2;\n  int32 my_property_3 = 3;\n  int32 my_property_4 = 4;\n  int32 my_property_5 = 5;\n  int32 my_property_6 = 6;\n  int32 my_property_7 = 7;\n  int32 my_property_8 = 8;\n  int32 my_property_9 = 9;\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/SimpleClass.cs",
    "content": "namespace Benchmarks.Serialization.Models;\n\n[Serializable]\n[GenerateSerializer]\npublic class SimpleClass\n{\n    [Id(0)]\n    public int BaseInt { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/SimpleStruct.cs",
    "content": "namespace Benchmarks.Serialization.Models;\n\n[Serializable]\n[GenerateSerializer]\npublic struct SimpleStruct\n{\n    [Id(0)]\n    public int Int { get; set; }\n\n    [Id(1)]\n    public bool Bool { get; set; }\n\n    [Id(3)]\n    public object AlwaysNull { get; set; }\n\n    [Id(4)]\n    public Guid Guid { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/Vector3.cs",
    "content": "using MessagePack;\nusing ProtoBuf;\n\nnamespace Benchmarks.Serialization.Models;\n\n[MessagePackObject]\n[ProtoContract]\n[GenerateSerializer]\npublic struct MyVector3\n{\n    [Key(0)]\n    [ProtoMember(1)]\n    [Id(0)]\n    public float X;\n\n    [Key(1)]\n    [ProtoMember(2)]\n    [Id(1)]\n    public float Y;\n\n    [Key(2)]\n    [ProtoMember(3)]\n    [Id(2)]\n    public float Z;\n}\n\n[Immutable]\n[GenerateSerializer]\npublic struct ImmutableVector3\n{\n    [Id(0)]\n    public float X;\n\n    [Id(1)]\n    public float Y;\n\n    [Id(2)]\n    public float Z;\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Models/VirtualIntsClass.cs",
    "content": "using ZeroFormatter;\n\nnamespace Benchmarks.Serialization.Models;\n\n[ZeroFormattable]\npublic class VirtualIntsClass\n{\n    public static VirtualIntsClass Create()\n    {\n        var result = new VirtualIntsClass();\n        result.Initialize();\n        return result;\n    }\n\n    public void Initialize() => MyProperty1 = MyProperty2 =\n        MyProperty3 = MyProperty4 = MyProperty5 = MyProperty6 = MyProperty7 = MyProperty8 = MyProperty9 = 10;\n\n    [Index(0)]\n    public virtual int MyProperty1 { get; set; }\n\n    [Index(1)]\n    public virtual int MyProperty2 { get; set; }\n\n    [Index(2)]\n    public virtual int MyProperty3 { get; set; }\n\n    [Index(3)]\n    public virtual int MyProperty4 { get; set; }\n\n    [Index(4)]\n    public virtual int MyProperty5 { get; set; }\n\n    [Index(5)]\n    public virtual int MyProperty6 { get; set; }\n\n    [Index(6)]\n    public virtual int MyProperty7 { get; set; }\n\n    [Index(7)]\n    public virtual int MyProperty8 { get; set; }\n\n    [Index(8)]\n    public virtual int MyProperty9 { get; set; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Utilities/BenchmarkConfig.cs",
    "content": "using BenchmarkDotNet.Configs;\nusing BenchmarkDotNet.Diagnosers;\nusing BenchmarkDotNet.Environments;\nusing BenchmarkDotNet.Exporters;\nusing BenchmarkDotNet.Jobs;\n\nnamespace Benchmarks.Serialization.Utilities;\n\ninternal class BenchmarkConfig : ManualConfig\n{\n    public BenchmarkConfig()\n    {\n        ArtifactsPath = \".\\\\BenchmarkDotNet.Aritfacts.\" + DateTime.Now.ToString(\"u\").Replace(' ', '_').Replace(':', '-');\n        AddExporter(MarkdownExporter.GitHub);\n        AddDiagnoser(MemoryDiagnoser.Default);\n        Options |= ConfigOptions.KeepBenchmarkFiles;\n        AddJob(Job.Default.WithRuntime(CoreRuntime.Core80));\n        AddJob(Job.Default.WithRuntime(CoreRuntime.Core90));\n#if NET10_0_OR_GREATER\n        AddJob(Job.Default.WithRuntime(CoreRuntime.Core10_0));\n#endif\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Utilities/ClassSingleSegmentBuffer.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics.Contracts;\nusing System.Text;\n\nnamespace Benchmarks.Serialization.Utilities;\n\npublic class ClassSingleSegmentBuffer : IBufferWriter<byte>\n{\n    private readonly byte[] _buffer;\n    private int _written;\n\n    public ClassSingleSegmentBuffer(byte[] buffer)\n    {\n        _buffer = buffer;\n        _written = 0;\n    }\n\n    public void Advance(int bytes) => _written += bytes;\n\n    [Pure]\n    public Memory<byte> GetMemory(int sizeHint = 0) => _buffer.AsMemory(_written);\n\n    [Pure]\n    public Span<byte> GetSpan(int sizeHint) => _buffer.AsSpan(_written);\n\n    public byte[] ToArray() => _buffer.AsSpan(0, _written).ToArray();\n\n    public void Reset() => _written = 0;\n\n    [Pure]\n    public int Length => _written;\n\n    [Pure]\n    public ReadOnlySequence<byte> GetReadOnlySequence() => new(_buffer, 0, _written);\n\n    public override string ToString() => Encoding.UTF8.GetString(_buffer.AsSpan(0, _written).ToArray());\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Utilities/MethodResultColumn.cs",
    "content": "using BenchmarkDotNet.Columns;\nusing BenchmarkDotNet.Reports;\nusing BenchmarkDotNet.Running;\nusing System.Reflection;\n\nnamespace Benchmarks.Serialization.Utilities;\n\npublic class MethodResultColumn : IColumn\n{\n    private readonly Func<object, string> _formatter;\n\n    public MethodResultColumn(string columnName, Func<object, string> formatter, string legend = null)\n    {\n        ColumnName = columnName;\n        _formatter = formatter;\n        Legend = legend;\n    }\n\n    public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => GetValue(summary, benchmarkCase, null);\n\n    public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => _formatter(CallMethod(benchmarkCase));\n\n    private static object CallMethod(BenchmarkCase benchmarkCase)\n    {\n        try\n        {\n            var descriptor = benchmarkCase.Descriptor;\n            var instance = Activator.CreateInstance(descriptor.Type);\n            TryInvoke(instance, descriptor.GlobalSetupMethod);\n            TryInvoke(instance, descriptor.IterationSetupMethod);\n            var result = descriptor.WorkloadMethod.Invoke(instance, Array.Empty<object>());\n            TryInvoke(instance, descriptor.IterationCleanupMethod);\n            TryInvoke(instance, descriptor.GlobalCleanupMethod);\n\n            return result;\n\n            static void TryInvoke(object target, MethodInfo method)\n            {\n                try\n                {\n                    _ = (method?.Invoke(target, Array.Empty<object>()));\n                }\n                catch\n                {\n                }\n            }\n        }\n        catch\n        {\n            return null;\n        }\n    }\n\n    public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false;\n\n    public bool IsAvailable(Summary summary) => summary.Reports.Any(r => CallMethod(r.BenchmarkCase) != null);\n\n    public string Id => nameof(MethodResultColumn) + \"_\" + ColumnName;\n    public string ColumnName { get; }\n    public bool AlwaysShow => true;\n    public ColumnCategory Category => ColumnCategory.Metric;\n    public int PriorityInCategory => 0;\n    public bool IsNumeric => true;\n    public UnitType UnitType => UnitType.Size;\n    public string Legend { get; }\n}"
  },
  {
    "path": "test/Benchmarks/Serialization/Utilities/PayloadSizeColumnAttribute.cs",
    "content": "using BenchmarkDotNet.Configs;\n\nnamespace Benchmarks.Serialization.Utilities;\n\n[AttributeUsage(AttributeTargets.Class)]\npublic class PayloadSizeColumnAttribute : Attribute, IConfigSource\n{\n    public PayloadSizeColumnAttribute(string columnName = \"Payload\")\n    {\n        var config = ManualConfig.CreateEmpty();\n        config.AddColumn(\n            new MethodResultColumn(columnName,\n                val =>\n                {\n                    uint result;\n                    switch (val)\n                    {\n                        case int i:\n                            result = (uint)i;\n                            break;\n                        case uint i:\n                            result = i;\n                            break;\n                        case long i:\n                            result = (uint)i;\n                            break;\n                        case ulong i:\n                            result = (uint)i;\n                            break;\n                        default: return \"Invalid\";\n                    }\n\n                    return result + \" B\";\n                }));\n        Config = config;\n    }\n\n    public IConfig Config { get; }\n}\n"
  },
  {
    "path": "test/Benchmarks/Serialization/Utilities/SingleSegmentBuffer.cs",
    "content": "using System.Buffers;\nusing System.Diagnostics.Contracts;\nusing System.Text;\n\nnamespace Benchmarks.Serialization.Utilities;\n\npublic struct SingleSegmentBuffer : IBufferWriter<byte>\n{\n    private readonly byte[] _buffer;\n    private int _written;\n\n    public SingleSegmentBuffer(byte[] buffer)\n    {\n        _buffer = buffer;\n        _written = 0;\n    }\n\n    public void Advance(int bytes) => _written += bytes;\n\n    [Pure]\n    public readonly Memory<byte> GetMemory(int sizeHint = 0) => _buffer.AsMemory(_written);\n\n    [Pure]\n    public readonly Span<byte> GetSpan(int sizeHint) => _buffer.AsSpan(_written);\n\n    public readonly byte[] ToArray() => _buffer.AsSpan(0, _written).ToArray();\n\n    public void Reset() => _written = 0;\n\n    [Pure]\n    public readonly int Length => _written;\n\n    [Pure]\n    public readonly ReadOnlySpan<byte> GetReadOnlySpan() => new(_buffer, 0, _written);\n\n    public override readonly string ToString() => Encoding.UTF8.GetString(_buffer.AsSpan(0, _written).ToArray());\n}"
  },
  {
    "path": "test/Benchmarks/TopK/BloomFilterBenchmark.cs",
    "content": "using System.Collections;\nusing System.Diagnostics;\nusing System.IO.Hashing;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Columns;\nusing BenchmarkDotNet.Configs;\nusing Benchmarks.Serialization.Utilities;\nusing Orleans.Runtime.Placement.Repartitioning;\n\nnamespace Benchmarks.TopK;\n\n[MemoryDiagnoser]\n[FalsePositiveRateColumn]\n[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory), CategoriesColumn]\npublic class BloomFilterBenchmark\n{\n    private BloomFilter _bloomFilter;\n    private BloomFilter _bloomFilterWithSamples;\n    private OriginalBloomFilter _originalBloomFilter;\n    private OriginalBloomFilter _originalBloomFilterWithSamples;\n    private BlockedBloomFilter _blockedBloomFilter;\n    private BlockedBloomFilter _blockedBloomFilterWithSamples;\n    private GrainId[] _population;\n    private HashSet<GrainId> _set;\n    private ZipfRejectionSampler _sampler;\n    private GrainId[] _samples;\n\n    [Params(1_000_000, Priority = 4)]\n    public int Pop { get; set; }\n\n    [Params(/*0.2, 0.4, 0.6, 0.8, */1.02 /*, 1.2, 1.4, 1.6*/, Priority = 3)]\n    public double Skew { get; set; }\n\n    [Params(1_000_000, Priority = 1)]\n    public int Cap { get; set; }\n\n    [Params(0.01, 0.001, Priority = 2)]\n    public double FP { get; set; }\n\n    [Params(10_000, Priority = 5)]\n    public int Samples { get; set; }\n\n    [GlobalSetup]\n    public void GlobalSetup()\n    {\n        _population = new GrainId[Pop];\n        _sampler = new(new Random(42), Pop, Skew);\n        for (var i = 0; i < Pop; i++)\n        {\n            _population[i] = GrainId.Create($\"grain_{i}\", i.ToString());\n        }\n\n        _bloomFilter = new(Cap, FP);\n        _bloomFilterWithSamples = new(Cap, FP);\n        _originalBloomFilter = new();\n        _originalBloomFilterWithSamples = new();\n        _blockedBloomFilter = new(Cap, FP);\n        _blockedBloomFilterWithSamples = new(Cap, FP);\n\n        _samples = new GrainId[Samples];\n        _set = new(Samples);\n        for (var i = 0; i < Samples; i++)\n        {\n            //var sample = _sampler.Sample();\n            var value = _population[i];\n            _samples[i] = value;\n            _set.Add(value);\n            _bloomFilterWithSamples.Add(value);\n            _originalBloomFilterWithSamples.Add(value);\n        }\n    }\n\n    [Benchmark]\n    [BenchmarkCategory(\"Add\")]\n    public void BloomFilter_Add()\n    {\n        foreach (var sample in _samples)\n        {\n            _bloomFilter.Add(sample);\n        }\n    }\n\n    [Benchmark]\n    [BenchmarkCategory(\"Contains\")]\n    public void BloomFilter_Contains()\n    {\n        foreach (var sample in _samples)\n        {\n            _bloomFilterWithSamples.Contains(sample);\n        }\n    }\n\n    [Benchmark]\n    [BenchmarkCategory(\"FP rate\")]\n    public int BloomFilter_FPR()\n    {\n        var correct = 0;\n        var incorrect = 0;\n        foreach (var sample in _population)\n        {\n            if (!_bloomFilterWithSamples.Contains(sample) == _set.Contains(sample))\n            {\n                correct++;\n            }\n            else\n            {\n                incorrect++;\n            }\n        }\n\n        return incorrect;\n    }\n\n\n    [Benchmark(Baseline = true)]\n    [BenchmarkCategory(\"Add\")]\n    public void OriginalBloomFilter_Add()\n    {\n        foreach (var sample in _samples)\n        {\n            _originalBloomFilter.Add(sample);\n        }\n    }\n\n    [Benchmark(Baseline = true)]\n    [BenchmarkCategory(\"Contains\")]\n    public void OriginalBloomFilter_Contains()\n    {\n        foreach (var sample in _samples)\n        {\n            _originalBloomFilterWithSamples.Contains(sample);\n        }\n    }\n\n    /*\n    [Benchmark(Baseline = true)]\n    [BenchmarkCategory(\"FP rate\")]\n    public int OriginalBloomFilter_FPR()\n    {\n        var correct = 0;\n        var incorrect = 0;\n        foreach (var sample in _population)\n        {\n            if (!_originalBloomFilterWithSamples.Contains(sample) == _set.Contains(sample))\n            {\n                correct++;\n            }\n            else\n            {\n                incorrect++;\n            }\n        }\n\n        return incorrect;\n    }\n    */\n\n    [Benchmark]\n    [BenchmarkCategory(\"Add\")]\n    public void BlockedBloomFilter_Add()\n    {\n        foreach (var sample in _samples)\n        {\n            _blockedBloomFilter.Add(sample);\n        }\n    }\n\n    [Benchmark]\n    [BenchmarkCategory(\"Contains\")]\n    public void BlockedBloomFilter_Contains()\n    {\n        foreach (var sample in _samples)\n        {\n            _blockedBloomFilterWithSamples.Contains(sample);\n        }\n    }\n\n    // This is expected to yield a slighly higher FP rate, due to tuning\n    [Benchmark]\n    [BenchmarkCategory(\"FP rate\")]\n    public int BlockedBloomFilter_FPR()\n    {\n        var correct = 0;\n        var incorrect = 0;\n        foreach (var sample in _population)\n        {\n            if (!_blockedBloomFilterWithSamples.Contains(sample) == _set.Contains(sample))\n            {\n                correct++;\n            }\n            else\n            {\n                incorrect++;\n            }\n        }\n\n        return incorrect;\n    }\n}\n\n[AttributeUsage(AttributeTargets.Class)]\npublic class FalsePositiveRateColumnAttribute : Attribute, IConfigSource\n{\n    public FalsePositiveRateColumnAttribute(string columnName = \"FP %\")\n    {\n        var config = ManualConfig.CreateEmpty();\n        config.AddColumn(\n            new MethodResultColumn(columnName,\n                val =>\n                {\n                    return $\"{val}\";\n                }));\n        Config = config;\n    }\n\n    public IConfig Config { get; }\n}\npublic class OriginalBloomFilter\n{\n    private const int bitArraySize = 1_198_132; // formula 8 * n / ln(2) -> for 1000 elements, 0.01%\n    private readonly int[] hashFuncSeeds = Enumerable.Range(0, 6).Select(p => (int)unchecked(p * 0xFBA4C795 + 1)).ToArray();\n    private readonly BitArray filterBits = new(bitArraySize);\n\n    public void Add(GrainId id)\n    {\n        foreach (int s in hashFuncSeeds)\n        {\n            uint i = XxHash32.HashToUInt32(id.Key.AsSpan(), s);\n            filterBits.Set((int)(i % (uint)filterBits.Length), true);\n        }\n    }\n\n    public bool Contains(GrainId id)\n    {\n        foreach (int s in hashFuncSeeds)\n        {\n            uint i = XxHash32.HashToUInt32(id.Key.AsSpan(), s);\n            if (!filterBits.Get((int)(i % (uint)filterBits.Length)))\n            {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n\ninternal sealed class BloomFilter\n{\n    private const double Ln2Squared = 0.4804530139182014246671025263266649717305529515945455;\n    private const double Ln2 = 0.6931471805599453094172321214581765680755001343602552;\n    private readonly ulong[] _hashFuncSeeds;\n    private readonly int[] _filter;\n    private readonly int _indexMask;\n\n    public BloomFilter(int capacity, double falsePositiveRate)\n    {\n        // Calculate the ideal bloom filter size and hash code count for the given (estimated) capacity and desired false positive rate.\n        // See https://en.wikipedia.org/wiki/Bloom_filter.\n        var minBitCount = (int)(-1 / Ln2Squared * capacity * Math.Log(falsePositiveRate)) / 8;\n        var arraySize = (int)CeilingPowerOfTwo((uint)(minBitCount - 1 + (1 << 5)) >> 5);\n        _indexMask = arraySize - 1;\n        _filter = new int[arraySize];\n\n        // Divide the hash count by 2 since we are using 64-bit hash codes split into two 32-bit hash codes.\n        var hashFuncCount = (int)Math.Min(minBitCount * 8 / capacity * Ln2 / 2, 8);\n        Debug.Assert(hashFuncCount > 0);\n        _hashFuncSeeds = Enumerable.Range(0, hashFuncCount).Select(p => unchecked((ulong)p * 0xFBA4C795FBA4C795 + 1)).ToArray();\n        Debug.Assert(_hashFuncSeeds.Length == hashFuncCount);\n    }\n\n    public void Add(GrainId id)\n    {\n        var hash = XxHash3.HashToUInt64(id.Key.AsSpan(), id.GetUniformHashCode());\n        foreach (var seed in _hashFuncSeeds)\n        {\n            hash = Mix64(hash ^ seed);\n            Set((int)hash);\n            Set((int)(hash >> 32));\n        }\n    }\n\n    public bool Contains(GrainId id)\n    {\n        var hash = XxHash3.HashToUInt64(id.Key.AsSpan(), id.GetUniformHashCode());\n        foreach (var seed in _hashFuncSeeds)\n        {\n            hash = Mix64(hash ^ seed);\n            var clear = IsClear((int)hash);\n            clear |= IsClear((int)(hash >> 32));\n            if (clear)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool IsClear(int index) => (_filter[(index >> 5) & _indexMask] & (1 << index)) == 0;\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public void Set(int index) => _filter[(index >> 5) & _indexMask] |= 1 << index;\n\n    /// <summary>\n    /// Computes Stafford variant 13 of 64-bit mix function.\n    /// </summary>\n    /// <param name=\"z\">The input parameter.</param>\n    /// <returns>A bit mix of the input parameter.</returns>\n    /// <remarks>\n    /// See http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html\n    /// </remarks>\n    public static ulong Mix64(ulong z)\n    {\n        z = (z ^ z >> 30) * 0xbf58476d1ce4e5b9L;\n        z = (z ^ z >> 27) * 0x94d049bb133111ebL;\n        return z ^ z >> 31;\n    }\n\n    public void Reset() => Array.Clear(_filter);\n\n    private static uint CeilingPowerOfTwo(uint x) => 1u << -BitOperations.LeadingZeroCount(x - 1);\n}\n\n"
  },
  {
    "path": "test/Benchmarks/TopK/TopKBenchmark.cs",
    "content": "using System.Diagnostics;\nusing System.Net;\nusing System.Runtime.CompilerServices;\nusing BenchmarkDotNet.Attributes;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Runtime.Placement.Repartitioning;\n\nnamespace Benchmarks.TopK;\n\n[MemoryDiagnoser]\npublic class TopKBenchmark\n{\n    private ZipfRejectionSampler _sampler;\n    private ulong[] ULongSamples;\n    private Edge[] EdgeSamples;\n    private EdgeClass[] EdgeClassSamples;\n    private UlongFrequentItemCollection _fss;\n    private EdgeClassFrequentItemCollection _fssClass;\n    private EdgeFrequentItemCollection _fssEdge;\n    private FrequencySink _sink;\n\n    [Params(100_000, Priority = 3)]\n    public int Pop { get; set; }\n\n    [Params(0.2, 0.4, 0.6, 0.8, 1.02, 1.2, 1.4, 1.6, Priority = 2)]\n    public double Skew { get; set; }\n\n    [Params(10_000, Priority = 1)]\n    public int Cap { get; set; }\n\n    [Params(1_000_000, Priority = 4)]\n    public int Samples { get; set; }\n\n    [GlobalSetup]\n    public void GlobalSetup()\n    {\n        _sampler = new(new Random(42), Pop, Skew);\n\n        var silos = new SiloAddress[100];\n        for (var i = 0; i < silos.Length; i++)\n        {\n            silos[i] = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, i), i);\n        }\n\n        var grains = new GrainId[Pop];\n        for (var i = 0; i < Pop; i++)\n        {\n            grains[i] = GrainId.Create(\"grain\", i.ToString());\n        }\n\n        var grainEdges = new Edge[Pop];\n        for (var i = 0; i < Pop; i++)\n        {\n            grainEdges[i] = new Edge(new(grains[i % grains.Length], silos[i % silos.Length], true), new(grains[(i + 1) % grains.Length], silos[(i + 1) % silos.Length], true));\n        }\n\n        var grainEdgeClasses = new EdgeClass[Pop];\n        for (var i = 0; i < Pop; i++)\n        {\n            grainEdgeClasses[i] = new(grainEdges[i]);\n        }\n\n        ULongSamples = new ulong[Samples];\n        EdgeSamples = new Edge[Samples];\n        EdgeClassSamples = new EdgeClass[Samples];\n        for (var i = 0; i < Samples; i++)\n        {\n            var sample = _sampler.Sample();\n            ULongSamples[i] = (ulong)sample;\n            EdgeSamples[i] = grainEdges[sample % grainEdges.Length];\n            EdgeClassSamples[i] = grainEdgeClasses[sample % grainEdgeClasses.Length];\n        }\n\n        _fss = new UlongFrequentItemCollection(Cap);\n        _fssClass = new EdgeClassFrequentItemCollection(Cap);\n        _fssEdge = new EdgeFrequentItemCollection(Cap);\n        _sink = new FrequencySink(Cap);\n    }\n\n    internal sealed record class EdgeClass(Edge Edge);\n\n    [IterationSetup]\n    public void IterationSetup()\n    {\n        /*\n        _fss.Clear();\n        _fssEdge.Clear();\n        _fssClass.Clear();\n        */\n        //_sink = new FrequencySink(Cap);\n    }\n\n    /*\n    [Benchmark]\n    [BenchmarkCategory(\"Add\")]\n    public void FssULongAdd()\n    {\n        foreach (var sample in ULongSamples)\n        {\n            _fss.Add(sample);\n        }\n    }\n    */\n\n    /*\n    [Benchmark]\n    [BenchmarkCategory(\"Add\")]\n    public void FssClassAdd()\n    {\n        foreach (var sample in EdgeClassSamples)\n        {\n            _fssClass.Add(sample);\n        }\n    }\n    */\n\n    [Benchmark]\n    [BenchmarkCategory(\"FSS\")]\n    public void FssAdd()\n    {\n        foreach (var sample in EdgeSamples)\n        {\n            _fssEdge.Add(sample);\n        }\n    }\n\n    [Benchmark]\n    [BenchmarkCategory(\"SS\")]\n    public void SinkAdd()\n    {\n        foreach (var sample in EdgeSamples)\n        {\n            _sink.Add(sample);\n        }\n    }\n\n    private sealed class EdgeFrequentItemCollection(int capacity) : FrequentItemCollection<ulong, Edge>(capacity)\n    {\n        protected override ulong GetKey(in Edge element) => (ulong)element.Source.Id.GetUniformHashCode() << 32 | element.Target.Id.GetUniformHashCode();\n        public void Clear() => ClearCore();\n    }\n\n    private sealed class EdgeClassFrequentItemCollection(int capacity) : FrequentItemCollection<ulong, EdgeClass>(capacity)\n    {\n        static ulong GetKey(in Edge element) => (ulong)element.Source.Id.GetUniformHashCode() << 32 | element.Target.Id.GetUniformHashCode();\n        protected override ulong GetKey(in EdgeClass element) => GetKey(element.Edge);\n        public void Clear() => ClearCore();\n    }\n\n    private sealed class UlongFrequentItemCollection(int capacity) : FrequentItemCollection<ulong, ulong>(capacity)\n    {\n        protected override ulong GetKey(in ulong element) => element;\n        public void Remove(in ulong element) => Remove(GetKey(element));\n        public void Clear() => ClearCore();\n    }\n\n    internal class EdgeCounter(ulong value, Edge edge)\n    {\n        public ulong Value { get; set; } = value;\n        public Edge Edge { get; } = edge;\n\n    }\n\n    /// <summary>\n    /// Implementation of the Space-Saving algorithm: https://www.cse.ust.hk/~raywong/comp5331/References/EfficientComputationOfFrequentAndTop-kElementsInDataStreams.pdf\n    /// </summary>\n    internal sealed class FrequencySink(int capacity)\n    {\n        public ulong GetKey(in Edge element) => (ulong)element.Source.Id.GetUniformHashCode() << 32 | element.Target.Id.GetUniformHashCode();\n        private readonly Dictionary<ulong, EdgeCounter> _counters = new(capacity);\n        private readonly UpdateableMinHeap _heap = new(capacity);\n\n        public int Capacity { get; } = capacity;\n        public Dictionary<ulong, EdgeCounter>.ValueCollection Counters => _counters.Values;\n\n        public void Add(Edge edge)\n        {\n            var combinedHash = GetKey(edge);\n            if (_counters.TryGetValue(combinedHash, out var counter))\n            {\n                counter.Value++;\n                _heap.Update(combinedHash, counter.Value);\n\n                return;\n            }\n\n            if (_counters.Count == Capacity)\n            {\n                var minHash = _heap.Dequeue();\n                _counters.Remove(minHash);\n            }\n\n            _counters.Add(combinedHash, new EdgeCounter(1, edge));\n            _heap.Enqueue(combinedHash, _counters[combinedHash].Value);\n        }\n\n        public void Remove(uint sourceHash, uint targetHash)\n        {\n            var combinedHash = CombineHashes(sourceHash, targetHash);\n            var reversedHash = CombineHashes(targetHash, sourceHash);\n\n            if (_counters.Remove(combinedHash))\n            {\n                _ = _heap.Remove(combinedHash);\n            }\n\n            if (_counters.Remove(reversedHash))\n            {\n                _ = _heap.Remove(reversedHash);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static ulong CombineHashes(uint sourceHash, uint targetHash)\n            => (ulong)sourceHash << 32 | targetHash;\n\n        // Inspired by: https://github.com/DesignEngrLab/TVGL/blob/master/TessellationAndVoxelizationGeometryLibrary/Miscellaneous%20Functions/UpdatablePriorityQueue.cs\n        private class UpdateableMinHeap(int capacity)\n        {\n            private const int Arity = 4;\n            private const int Log2Arity = 2;\n\n            private readonly Dictionary<ulong, int> _hashIndexes = new(capacity);\n            private readonly (ulong Hash, ulong Value)[] _nodes = new (ulong, ulong)[capacity];\n\n            private int _size;\n\n            public void Enqueue(ulong hash, ulong value)\n            {\n                var currentSize = _size;\n                _size = currentSize + 1;\n\n                MoveNodeUp((hash, value), currentSize);\n            }\n\n            public ulong Dequeue()\n            {\n                var hash = _nodes[0].Hash;\n                _hashIndexes.Remove(hash);\n\n                var lastNodeIndex = --_size;\n                if (lastNodeIndex > 0)\n                {\n                    var lastNode = _nodes[lastNodeIndex];\n                    MoveNodeDown(lastNode, 0);\n                }\n\n                return hash;\n            }\n\n            public bool Remove(ulong hash)\n            {\n                if (!_hashIndexes.TryGetValue(hash, out var index))\n                {\n                    return false;\n                }\n\n                var nodes = _nodes;\n                var newSize = --_size;\n\n                if (index < newSize)\n                {\n                    var lastNode = nodes[newSize];\n                    MoveNodeDown(lastNode, index);\n                }\n\n                _hashIndexes.Remove(hash);\n                nodes[newSize] = default;\n\n                return true;\n            }\n\n            public void Update(ulong hash, ulong newValue)\n            {\n                Remove(hash);\n                Enqueue(hash, newValue);\n            }\n\n            private void MoveNodeUp((ulong Hash, ulong Value) node, int nodeIndex)\n            {\n                Debug.Assert(0 <= nodeIndex && nodeIndex < _size);\n\n                var nodes = _nodes;\n\n                while (nodeIndex > 0)\n                {\n                    var parentIndex = GetParentIndex(nodeIndex);\n                    var parent = nodes[parentIndex];\n\n                    if (Comparer<ulong>.Default.Compare(node.Value, parent.Value) < 0)\n                    {\n                        nodes[nodeIndex] = parent;\n                        _hashIndexes[parent.Hash] = nodeIndex;\n                        nodeIndex = parentIndex;\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n\n                _hashIndexes[node.Hash] = nodeIndex;\n                nodes[nodeIndex] = node;\n\n                [MethodImpl(MethodImplOptions.AggressiveInlining)]\n                static int GetParentIndex(int index) => (index - 1) >> Log2Arity;\n            }\n\n            private void MoveNodeDown((ulong Hash, ulong Value) node, int nodeIndex)\n            {\n                Debug.Assert(0 <= nodeIndex && nodeIndex < _size);\n\n                var nodes = _nodes;\n                var size = _size;\n\n                int i;\n                while ((i = GetFirstChildIndex(nodeIndex)) < size)\n                {\n                    var minChild = nodes[i];\n                    var minChildIndex = i;\n\n                    var childIndexUpperBound = Math.Min(i + Arity, size);\n                    while (++i < childIndexUpperBound)\n                    {\n                        var nextChild = nodes[i];\n                        if (nextChild.Value < minChild.Value)\n                        {\n                            minChild = nextChild;\n                            minChildIndex = i;\n                        }\n                    }\n\n                    if (node.Value <= minChild.Value)\n                    {\n                        break;\n                    }\n\n                    nodes[nodeIndex] = minChild;\n                    _hashIndexes[minChild.Hash] = nodeIndex;\n                    nodeIndex = minChildIndex;\n                }\n\n                _hashIndexes[node.Hash] = nodeIndex;\n                nodes[nodeIndex] = node;\n\n                [MethodImpl(MethodImplOptions.AggressiveInlining)]\n                static int GetFirstChildIndex(int index) => (index << Log2Arity) + 1;\n            }\n        }\n    }\n}\n\n    // https://jasoncrease.medium.com/rejection-sampling-the-zipf-distribution-6b359792cffa\n    internal sealed class ZipfRejectionSampler\n    {\n        private readonly Random _rand;\n        private readonly double _skew;\n        private readonly double _t;\n\n        public ZipfRejectionSampler(Random random, long cardinality, double skew)\n        {\n            _rand = random;\n            _skew = skew;\n            _t = (Math.Pow(cardinality, 1 - skew) - skew) / (1 - skew);\n        }\n\n        public long Sample()\n        {\n            while (true)\n            {\n                double invB = bInvCdf(_rand.NextDouble());\n                long sampleX = (long)(invB + 1);\n                double yRand = _rand.NextDouble();\n                double ratioTop = Math.Pow(sampleX, -_skew);\n                double ratioBottom = sampleX <= 1 ? 1 / _t : Math.Pow(invB, -_skew) / _t;\n                double rat = (ratioTop) / (ratioBottom * _t);\n\n                if (yRand < rat)\n                    return sampleX;\n            }\n        }\n        private double bInvCdf(double p)\n        {\n            if (p * _t <= 1)\n                return p * _t;\n            else\n                return Math.Pow((p * _t) * (1 - _skew) + _skew, 1 / (1 - _skew));\n        }\n    }\n"
  },
  {
    "path": "test/Benchmarks/Transactions/TransactionBenchmark.cs",
    "content": "using Orleans.TestingHost;\nusing BenchmarkGrainInterfaces.Transaction;\nusing TestExtensions;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Transactions;\n\nnamespace Benchmarks.Transactions;\n\npublic class TransactionBenchmark : IDisposable\n{\n    private TestCluster host;\n    private readonly int runs;\n    private readonly int transactionsPerRun;\n    private readonly int concurrent;\n\n    public TransactionBenchmark(int runs, int transactionsPerRun, int concurrent)\n    {\n        this.runs = runs;\n        this.transactionsPerRun = transactionsPerRun;\n        this.concurrent = concurrent;\n    }\n\n    public void MemorySetup()\n    {\n        var builder = new TestClusterBuilder(4);\n        builder.AddSiloBuilderConfigurator<SiloMemoryStorageConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void MemoryThrottledSetup()\n    {\n        var builder = new TestClusterBuilder(4);\n        builder.AddSiloBuilderConfigurator<SiloMemoryStorageConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionThrottlingConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void AzureSetup()\n    {\n        var builder = new TestClusterBuilder(4);\n        builder.AddSiloBuilderConfigurator<SiloAzureStorageConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public void AzureThrottledSetup()\n    {\n        var builder = new TestClusterBuilder(4);\n        builder.AddSiloBuilderConfigurator<SiloAzureStorageConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionConfigurator>();\n        builder.AddSiloBuilderConfigurator<SiloTransactionThrottlingConfigurator>();\n        this.host = builder.Build();\n        this.host.Deploy();\n    }\n\n    public class SiloMemoryStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddMemoryGrainStorageAsDefault();\n        }\n    }\n\n    public class SiloAzureStorageConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.AddAzureTableTransactionalStateStorageAsDefault(options =>\n            {\n                options.TableServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            });\n        }\n    }\n\n    public class SiloTransactionThrottlingConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.Configure<TransactionRateLoadSheddingOptions>(options =>\n            {\n                options.Enabled = true;\n                options.Limit = 50;\n            });\n        }\n    }\n\n    public async Task RunAsync()\n    {\n        Console.WriteLine($\"Cold Run.\");\n        await FullRunAsync();\n        for(int i=0; i<runs; i++)\n        {\n            Console.WriteLine($\"Warm Run {i+1}.\");\n            await FullRunAsync();\n        }\n    }\n\n    private async Task FullRunAsync()\n    {\n        int runners = Math.Max(1,(int)Math.Sqrt(concurrent));\n        int transactionsPerRunner = Math.Max(1, this.transactionsPerRun / runners);\n        Report[] reports = await Task.WhenAll(Enumerable.Range(0, runners).Select(i => RunAsync(i, transactionsPerRunner, runners)));\n        Report finalReport = new Report();\n        foreach (Report report in reports)\n        {\n            finalReport.Succeeded += report.Succeeded;\n            finalReport.Failed += report.Failed;\n            finalReport.Throttled += report.Throttled;\n            finalReport.Elapsed = TimeSpan.FromMilliseconds(Math.Max(finalReport.Elapsed.TotalMilliseconds, report.Elapsed.TotalMilliseconds));\n        }\n        Console.WriteLine($\"{finalReport.Succeeded} transactions in {finalReport.Elapsed.TotalMilliseconds}ms.\");\n        Console.WriteLine($\"{(int)(finalReport.Succeeded * 1000 / finalReport.Elapsed.TotalMilliseconds)} transactions per second.\");\n        Console.WriteLine($\"{finalReport.Failed} transactions failed.\");\n        Console.WriteLine($\"{finalReport.Throttled} transactions were throttled.\");\n    }\n\n    public async Task<Report> RunAsync(int run, int transactiosPerRun, int concurrentPerRun)\n    {\n        ILoadGrain load = this.host.Client.GetGrain<ILoadGrain>(Guid.NewGuid());\n        await load.Generate(run, transactiosPerRun, concurrentPerRun);\n        Report report = null;\n        while (report == null)\n        {\n            await Task.Delay(TimeSpan.FromSeconds(10));\n            report = await load.TryGetReport();\n        }\n        return report;\n    }\n\n    public void Teardown()\n    {\n        host.StopAllSilos();\n    }\n\n    public void Dispose()\n    {\n        host?.Dispose();\n    }\n\n    public sealed class SiloTransactionConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.UseTransactions();\n        }\n    }\n}"
  },
  {
    "path": "test/Benchmarks/run_test.cmd",
    "content": "pushd %~dp0\ngit log -n 1\ngit --no-pager diff\ndotnet run -c Release -- ConcurrentPing\npopd"
  },
  {
    "path": "test/Benchmarks.AdoNet/Benchmarks.AdoNet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"BenchmarkDotNet\" />\n    <PackageReference Include=\"BenchmarkDotNet.Diagnostics.Windows\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\AdoNet\\Orleans.Streaming.AdoNet\\Orleans.Streaming.AdoNet.csproj\" />\n    <ProjectReference Include=\"..\\Extensions\\Orleans.AdoNet.Tests\\Orleans.AdoNet.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Benchmarks.AdoNet/Program.cs",
    "content": "BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);"
  },
  {
    "path": "test/Benchmarks.AdoNet/Properties/Usings.cs",
    "content": "global using BenchmarkDotNet.Running;"
  },
  {
    "path": "test/Benchmarks.AdoNet/Streaming/MessageDequeueingBenchmark.cs",
    "content": "using Microsoft.Data.SqlClient;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Engines;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Benchmarks.AdoNet.Streaming;\n\npublic class SqlServerMessageDequeuingBenchmark() : MessageDequeuingBenchmark(AdoNetInvariants.InvariantNameSqlServer, \"OrleansStreamTest\")\n{\n    public override void GlobalSetup()\n    {\n        base.GlobalSetup();\n\n        SqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// This benchmark measures the performance of message queueing.\n/// </summary>\n[WarmupCount(1), IterationCount(3), InvocationCount(1), MarkdownExporter]\npublic abstract class MessageDequeuingBenchmark(string invariant, string database)\n{\n    private const int OperationsPerInvoke = 1000;\n\n    private readonly Consumer _consumer = new();\n    private IRelationalStorage _storage = default!;\n    private RelationalOrleansQueries _queries = default!;\n    private byte[] _payload = [];\n    private string[] _queueIds = default!;\n    private AdoNetStreamMessageAck[] _acks = [];\n\n    /// <summary>\n    /// This highlights degradation from queue concurrency.\n    /// </summary>\n    [Params(1, 4, 8)]\n    public int QueueCount { get; set; }\n\n    /// <summary>\n    /// This highlights degradation from payload size.\n    /// </summary>\n    [Params(10000)]\n    public int PayloadSize { get; set; }\n\n    /// <summary>\n    /// This highlights variation according to batch size.\n    /// </summary>\n    [Params(1, 16, 32)]\n    public int BatchSize { get; set; }\n\n    /// <summary>\n    /// This highlights variation from how full the table is.\n    /// </summary>\n    [Params(0, 0.5, 1)]\n    public double FullnessRatio { get; set; }\n\n    [GlobalSetup]\n    public virtual void GlobalSetup()\n    {\n        Async().GetAwaiter().GetResult();\n\n        async Task Async()\n        {\n            // create an appropriate size payload\n            _payload = new byte[PayloadSize];\n            Array.Fill<byte>(_payload, 0xFF);\n\n            // define the set queues\n            _queueIds = Enumerable.Range(0, QueueCount).Select(i => $\"QueueId-{i}\").ToArray();\n\n            // setup the test database\n            var testing = await RelationalStorageForTesting.SetupInstance(invariant, database);\n            if (IsNullOrEmpty(testing.CurrentConnectionString))\n            {\n                throw new InvalidOperationException($\"Database '{database}' not initialized\");\n            }\n            _storage = RelationalStorage.CreateInstance(invariant, testing.CurrentConnectionString);\n            _queries = await RelationalOrleansQueries.CreateInstance(invariant, testing.CurrentConnectionString);\n        }\n    }\n\n    [IterationSetup]\n    public void IterationSetup()\n    {\n        Async().GetAwaiter().GetResult();\n\n        async Task Async()\n        {\n            await _storage.ExecuteAsync(\"TRUNCATE TABLE OrleansStreamMessage\");\n\n            // generate test data to dequeue\n            var count = (int)Math.Ceiling(OperationsPerInvoke * QueueCount * BatchSize * FullnessRatio);\n            _acks = new AdoNetStreamMessageAck[count];\n            await Parallel.ForAsync(0, count, async (i, ct) =>\n            {\n                // generate messages in round robin queue order to help simulate multiple agents\n                var queueId = _queueIds[i % _queueIds.Length];\n                var ack = await _queries.QueueStreamMessageAsync(\"ServiceId-0\", \"ProviderId-0\", queueId, _payload, 1000);\n\n                _acks[i] = ack;\n            });\n        }\n    }\n\n    [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]\n    public async Task GetStreamMessages()\n    {\n        var count = OperationsPerInvoke * QueueCount;\n\n        await Parallel.ForAsync(0, count, new ParallelOptions { MaxDegreeOfParallelism = QueueCount }, async (i, ct) =>\n        {\n            // get a queue id in round robin order to help simulate multiple agents\n            var queueId = _queueIds[i % _queueIds.Length];\n\n            // get messages for the queue of the ack\n            // the queue may or may not have data to dequeue depending on the fullness and batch size parameters\n            // we dequeue regardless in order to measure overhead\n            var messages = await _queries.GetStreamMessagesAsync(\"ServiceId-0\", \"ProviderId-0\", queueId, BatchSize, 1, 1000, 1000, 1000, 1000);\n\n            _consumer.Consume(messages);\n        });\n    }\n}\n"
  },
  {
    "path": "test/Benchmarks.AdoNet/Streaming/MessageQueueingBenchmark.cs",
    "content": "using Microsoft.Data.SqlClient;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Engines;\nusing Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Benchmarks.AdoNet.Streaming;\n\npublic class SqlServerMessageQueueingBenchmark() : MessageQueueingBenchmark(AdoNetInvariants.InvariantNameSqlServer, \"OrleansStreamTest\")\n{\n    public override void GlobalSetup()\n    {\n        base.GlobalSetup();\n\n        SqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// This benchmark measures the performance of message queueing.\n/// </summary>\n[WarmupCount(1), IterationCount(3), InvocationCount(1), MarkdownExporter]\npublic abstract class MessageQueueingBenchmark(string invariant, string database)\n{\n    private const int OperationsPerInvoke = 1000;\n\n    private readonly Consumer _consumer = new();\n    private IRelationalStorage _storage = default!;\n    private RelationalOrleansQueries _queries = default!;\n    private byte[] _payload = [];\n    private string[] _queueIds = default!;\n\n    /// <summary>\n    /// This highlights degradation from database locking.\n    /// </summary>\n    [Params(1, 4, 8)]\n    public int QueueCount { get; set; }\n\n    /// <summary>\n    /// This highlights degradation from payload size.\n    /// </summary>\n    [Params(1000, 10000, 100000)]\n    public int PayloadSize { get; set; }\n\n    /// <summary>\n    /// This highlights degradation from concurrency.\n    /// </summary>\n    [Params(1, 4, 8)]\n    public int Concurrency { get; set; }\n\n    [GlobalSetup]\n    public virtual void GlobalSetup()\n    {\n        _payload = new byte[PayloadSize];\n        Array.Fill<byte>(_payload, 0xFF);\n\n        _queueIds = Enumerable.Range(0, QueueCount).Select(i => $\"QueueId-{i}\").ToArray();\n\n        var testing = RelationalStorageForTesting.SetupInstance(invariant, database).GetAwaiter().GetResult();\n\n        if (IsNullOrEmpty(testing.CurrentConnectionString))\n        {\n            throw new InvalidOperationException($\"Database '{database}' not initialized\");\n        }\n\n        _storage = RelationalStorage.CreateInstance(invariant, testing.CurrentConnectionString);\n\n        _queries = RelationalOrleansQueries.CreateInstance(invariant, testing.CurrentConnectionString).GetAwaiter().GetResult();\n    }\n\n    [IterationSetup]\n    public void IterationSetup() => _storage.ExecuteAsync(\"TRUNCATE TABLE OrleansStreamMessage\").GetAwaiter().GetResult();\n\n    [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]\n    public Task QueueStreamMessage()\n    {\n        var count = OperationsPerInvoke * Concurrency;\n\n        return Parallel.ForAsync(0, count, new ParallelOptions { MaxDegreeOfParallelism = Concurrency }, async (i, ct) =>\n        {\n            var queueId = _queueIds[Random.Shared.Next(_queueIds.Length)];\n            var ack = await _queries.QueueStreamMessageAsync(\"ServiceId-0\", \"ProviderId-0\", queueId, _payload, 1000);\n\n            _consumer.Consume(ack);\n        });\n    }\n}\n"
  },
  {
    "path": "test/Directory.Build.props",
    "content": "<Project>\n  <PropertyGroup>\n    <_ParentDirectoryBuildPropsPath Condition=\"'$(_DirectoryBuildPropsFile)' != ''\">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildPropsFile)'))</_ParentDirectoryBuildPropsPath>\n  </PropertyGroup>\n\n  <Import Project=\"$(_ParentDirectoryBuildPropsPath)\" Condition=\"Exists('$(_ParentDirectoryBuildPropsPath)')\"/>\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <GenerateDocumentationFile>false</GenerateDocumentationFile>\n    <NoWarn>$(NoWarn);FS2003;1591</NoWarn>\n    <ServerGarbageCollection>true</ServerGarbageCollection>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <TestTargetFrameworks Condition=\"'$(TestTargetFrameworks)' == ''\">net8.0;net10.0</TestTargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"$(MsBuildThisFileDirectory)xunit.runner.json\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Directory.Build.targets",
    "content": "<Project>\n\n  <PropertyGroup>\n    <_ParentDirectoryBuildTargetsPath Condition=\"'$(_DirectoryBuildTargetsFile)' != ''\">$([System.IO.Path]::Combine('..', '$(_DirectoryBuildTargetsFile)'))</_ParentDirectoryBuildTargetsPath>\n  </PropertyGroup>\n  \n  <Import Project=\"$(_ParentDirectoryBuildTargetsPath)\" Condition=\"Exists('$(_ParentDirectoryBuildTargetsPath)')\"/>\n  \n  </Project>\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/Commands/ChaosAgentCommand.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Invocation;\nusing DistributedTests.Common.MessageChannel;\nusing Microsoft.Extensions.Logging;\n\nnamespace DistributedTests.Client.Commands\n{\n    public class ChaosAgentCommand : Command\n    {\n        private readonly ILogger _logger;\n\n        private class Parameters\n        {\n            public string ServiceId { get; set; }\n            public string ClusterId { get; set; }\n            public Uri AzureTableUri { get; set; }\n            public Uri AzureQueueUri { get; set; }\n            public int Wait { get; set; }\n            public int ServersPerRound { get; set; }\n            public int Rounds { get; set; }\n            public int RoundDelay { get; set; }\n            public bool Graceful { get; set; }\n            public bool Restart { get; set; }\n        }\n\n        public ChaosAgentCommand(ILogger logger)\n            : base(\"chaosagent\", \"Shutdown/restart servers gracefully or not\")\n        {\n            AddOption(OptionHelper.CreateOption<string>(\"--serviceId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<string>(\"--clusterId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureTableUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureQueueUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<int>(\"--wait\", defaultValue: 30));\n            AddOption(OptionHelper.CreateOption<int>(\"--serversPerRound\", defaultValue: 1));\n            AddOption(OptionHelper.CreateOption<int>(\"--rounds\", defaultValue: 5));\n            AddOption(OptionHelper.CreateOption<int>(\"--roundDelay\", defaultValue: 60));\n            AddOption(OptionHelper.CreateOption<bool>(\"--graceful\", defaultValue: false));\n            AddOption(OptionHelper.CreateOption<bool>(\"--restart\", defaultValue: false));\n\n            Handler = CommandHandler.Create<Parameters>(RunAsync);\n            _logger = logger;\n        }\n\n        private async Task RunAsync(Parameters parameters)\n        {\n            var channel = await Channels.CreateSendChannel(parameters.ClusterId, parameters.AzureQueueUri);\n\n            _logger.LogInformation(\"Waiting {WaitSeconds} seconds before starting...\", parameters.Wait);\n            await Task.Delay(TimeSpan.FromSeconds(parameters.Wait));\n\n            for (var i=0; i<parameters.Rounds; i++)\n            {\n                _logger.LogInformation(\n                    \"Round #{Round}: sending {ServersPerRound} orders [Restart: {Restart}, Graceful: {Graceful}]\",\n                    i + 1,\n                    parameters.ServersPerRound,\n                    parameters.Restart,\n                    parameters.Graceful);\n                var responses = await channel.SendMessages(\n                    GetMessages(),\n                    new CancellationTokenSource(TimeSpan.FromSeconds(parameters.RoundDelay)).Token);\n                _logger.LogInformation(\n                    \"Round #{Round}: silos {Silos} acked\",\n                    i + 1,\n                    string.Join(\",\", responses.Select(r => r.ServerName)));\n                _logger.LogInformation(\"Round #{Round}: waiting {RoundDelay}\", i + 1, parameters.RoundDelay);\n                await Task.Delay(TimeSpan.FromSeconds(parameters.RoundDelay));\n            }\n\n            List<ServerMessage> GetMessages()\n            {\n                var msgs = new List<ServerMessage>();\n                for (var i = 0; i < parameters.ServersPerRound; i++)\n                {\n                    msgs.Add(new ServerMessage(parameters.Graceful, parameters.Restart));\n                }\n                return msgs;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/Commands/CounterCaptureCommand.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Invocation;\nusing DistributedTests.Common;\nusing DistributedTests.GrainInterfaces;\nusing Microsoft.Crank.EventSources;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\n\nnamespace DistributedTests.Client.Commands\n{\n    public class CounterCaptureCommand : Command\n    {\n        private readonly ILogger _logger;\n\n        private class Parameters\n        {\n            public string ServiceId { get; set; }\n            public string ClusterId { get; set; }\n            public Uri AzureTableUri { get; set; }\n            public Uri AzureQueueUri { get; set; }\n            public string CounterKey { get; set; }\n            public List<string> Counters { get; set; }\n        }\n\n        public CounterCaptureCommand(ILogger logger)\n            : base(\"counter\", \"capture the counters in parameter\")\n        {\n            AddOption(OptionHelper.CreateOption<string>(\"--serviceId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<string>(\"--clusterId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureTableUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureQueueUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption(\"--counterKey\", defaultValue: StreamingConstants.DefaultCounterGrain));\n            AddArgument(new Argument<List<string>>(\"Counters\") { Arity = ArgumentArity.OneOrMore });\n\n            Handler = CommandHandler.Create<Parameters>(RunAsync);\n            _logger = logger;\n        }\n\n        private async Task RunAsync(Parameters parameters)\n        {\n            _logger.LogInformation(\"Connecting to cluster...\");\n            var hostBuilder = new HostBuilder()\n                .UseOrleansClient((ctx, builder) => {\n                    builder\n                        .Configure<ClusterOptions>(options => { options.ClusterId = parameters.ClusterId; options.ServiceId = parameters.ServiceId; })\n                        .UseAzureStorageClustering(options => options.TableServiceClient = parameters.AzureTableUri.CreateTableServiceClient());\n                });\n            using var host = hostBuilder.Build();\n            await host.StartAsync();\n\n            var client = host.Services.GetService<IClusterClient>();\n\n            var counterGrain = client.GetGrain<ICounterGrain>(parameters.CounterKey);\n\n            var duration = await counterGrain.GetRunDuration();\n            BenchmarksEventSource.Register(\"duration\", Operations.First, Operations.Last, \"duration\", \"duration\", \"n0\");\n            BenchmarksEventSource.Measure(\"duration\", duration.TotalSeconds);\n\n            var initialWait = await counterGrain.WaitTimeForReport();\n\n            _logger.LogInformation(\"Counters should be ready in {InitialWait}\", initialWait);\n            await Task.Delay(initialWait);\n\n            _logger.LogInformation(\"Counters ready\");\n            foreach (var counter in parameters.Counters)\n            {\n                var value = await counterGrain.GetTotalCounterValue(counter);\n                _logger.LogInformation(\"{Counter}: {Value}\", counter, value);\n                BenchmarksEventSource.Register(counter, Operations.First, Operations.Sum, counter, counter, \"n0\");\n                BenchmarksEventSource.Measure(counter, value);\n                if (string.Equals(counter, \"requests\", StringComparison.InvariantCultureIgnoreCase))\n                {\n                    var rps = (float) value / duration.TotalSeconds;\n                    BenchmarksEventSource.Register(\"rps\", Operations.First, Operations.Last, \"rps\", \"Requests per second\", \"n0\");\n                    BenchmarksEventSource.Measure(\"rps\", rps);\n                }\n            }\n\n            await host.StopAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/Commands/ScenarioCommand.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Invocation;\nusing DistributedTests.Client.LoadGeneratorScenario;\nusing Microsoft.Extensions.Logging;\n\nnamespace DistributedTests.Client.Commands\n{\n    public class ScenarioCommand<T> : Command\n    {\n        private readonly LoadGeneratorScenarioRunner<T> _runner;\n\n        public ScenarioCommand(ILoadGeneratorScenario<T> scenario, ILoggerFactory loggerFactory)\n            : base(scenario.Name)\n        {\n            _runner = new LoadGeneratorScenarioRunner<T>(scenario, loggerFactory);\n\n            // ClientParameters\n            AddOption(OptionHelper.CreateOption<string>(\"--serviceId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<string>(\"--clusterId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<int>(\"--connectionsPerEndpoint\", defaultValue: 1, validator: OptionHelper.OnlyStrictlyPositive));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureQueueUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureTableUri\", isRequired: true));\n\n            // LoadGeneratorParameters\n            AddOption(OptionHelper.CreateOption<int>(\"--numWorkers\", defaultValue: 250, validator: OptionHelper.OnlyStrictlyPositive));\n            AddOption(OptionHelper.CreateOption<int>(\"--blocksPerWorker\", defaultValue: 10));\n            AddOption(OptionHelper.CreateOption<int>(\"--requestsPerBlock\", defaultValue: 500, validator: OptionHelper.OnlyStrictlyPositive));\n            AddOption(OptionHelper.CreateOption<int>(\"--duration\", defaultValue: 0, validator: OptionHelper.OnlyPositiveOrZero));\n\n            Handler = CommandHandler.Create<ClientParameters, LoadGeneratorParameters>(_runner.Run);\n        }\n    }\n\n    public static class Scenario\n    {\n        public static Command CreateCommand<T>(ILoadGeneratorScenario<T> scenario, ILoggerFactory loggerFactory) => new ScenarioCommand<T>(scenario, loggerFactory);\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/DistributedTests.Client.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <OutputPath Condition=\" '$(DistributedTestsOutputPath)'!='' \">$(DistributedTestsOutputPath)/DistributedTests.Client</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\"..\\secrets.json\" Link=\"secrets.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Azure\\Orleans.Clustering.AzureStorage\\Orleans.Clustering.AzureStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Client\\Orleans.Client.csproj\" />\n    <ProjectReference Include=\"..\\DistributedTests.Common\\DistributedTests.Common.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Crank.EventSources\" />\n    <PackageReference Include=\"System.CommandLine\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/LoadGeneratorScenario/ConcurrentLoadGenerator.cs",
    "content": "using System.Threading.Channels;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Crank.EventSources;\n\nnamespace DistributedTests.Client\n{\n    public struct LoadGeneratorReport\n    {\n        public long Completed { get; set; }\n\n        public long Successes { get; set; }\n\n        public long Failures { get; set; }\n\n        public double TotalDuration { get; set; }\n\n        public int BlocksCompleted { get; set; }\n\n        public readonly long RatePerSecond => (long)(Completed / TotalDuration);\n\n        public override readonly string ToString()\n        {\n            if (BlocksCompleted == 0) return \"No blocks completed\";\n            var failureString = Failures == 0 ? string.Empty : $\" with {Failures} failures\";\n            return $\"{RatePerSecond,6}/s {Successes,7} reqs in {TotalDuration,6:0.000}s{failureString}\";\n        }\n    }\n\n    public sealed class ConcurrentLoadGenerator<TState>\n    {\n        private static readonly double StopwatchTickPerSecond = Stopwatch.Frequency;\n        private struct WorkBlock\n        {\n            public long StartTimestamp { get; set; }\n            public long EndTimestamp { get; set; }\n            public int Successes { get; set; }\n            public int Failures { get; set; }\n            public readonly int Completed => this.Successes + this.Failures;\n            public readonly double ElapsedSeconds => (this.EndTimestamp - this.StartTimestamp) / StopwatchTickPerSecond;\n            public readonly double RequestsPerSecond => this.Completed / this.ElapsedSeconds;\n        }\n\n        private Channel<WorkBlock> _completedBlocks;\n        private readonly Func<TState, ValueTask> _issueRequest;\n        private readonly Func<int, TState> _getStateForWorker;\n        private readonly ILogger _logger;\n        private readonly bool _logIntermediateResults;\n        private readonly Task[] _tasks;\n        private readonly TState[] _states;\n        private readonly int _numWorkers;\n        private readonly int _blocksPerWorker;\n        private readonly int _requestsPerBlock;\n\n        public ConcurrentLoadGenerator(\n            int numWorkers,\n            int blocksPerWorker,\n            int requestsPerBlock,\n            Func<TState, ValueTask> issueRequest,\n            Func<int, TState> getStateForWorker,\n            ILogger logger,\n            bool logIntermediateResults = false)\n        {\n            this._numWorkers = numWorkers;\n            this._blocksPerWorker = blocksPerWorker;\n            this._requestsPerBlock = requestsPerBlock;\n            this._issueRequest = issueRequest;\n            this._getStateForWorker = getStateForWorker;\n            this._logger = logger;\n            this._logIntermediateResults = logIntermediateResults;\n            this._tasks = new Task[numWorkers];\n            this._states = new TState[numWorkers];\n        }\n\n        public async Task Warmup()\n        {\n            this.ResetBetweenRuns();\n            var completedBlockReader = this._completedBlocks.Reader;\n\n            for (var ree = 0; ree < this._numWorkers; ree++)\n            {\n                this._states[ree] = _getStateForWorker(ree);\n                this._tasks[ree] = this.RunWorker(this._states[ree], this._requestsPerBlock, 3, default);\n            }\n\n            // Wait for warmup to complete.\n            await Task.WhenAll(this._tasks);\n\n            // Ignore warmup blocks.\n            while (completedBlockReader.TryRead(out _)) ;\n            GC.Collect();\n            GC.Collect();\n            GC.Collect();\n        }\n\n        private void ResetBetweenRuns()\n        {\n            this._completedBlocks = Channel.CreateUnbounded<WorkBlock>(\n                new UnboundedChannelOptions\n                {\n                    SingleReader = true,\n                    SingleWriter = false,\n                    AllowSynchronousContinuations = false\n                });\n        }\n\n        public async Task<LoadGeneratorReport> Run(CancellationToken ct)\n        {\n            this.ResetBetweenRuns();\n            var completedBlockReader = this._completedBlocks.Reader;\n\n            // Start the run.\n            for (var i = 0; i < this._numWorkers; i++)\n            {\n                this._tasks[i] = this.RunWorker(this._states[i], this._requestsPerBlock, this._blocksPerWorker, ct);\n            }\n\n            var completion = Task.WhenAll(this._tasks);\n            _ = Task.Run(async () => { try { await completion; } catch { } finally { this._completedBlocks.Writer.Complete(); } });\n            // Do not allocated a list with a too high capacity\n            var blocks = new List<WorkBlock>(this._numWorkers * Math.Min(100, this._blocksPerWorker));\n            var blocksPerReport = this._numWorkers * Math.Min(100, this._blocksPerWorker) / 5;\n            var nextReportBlockCount = blocksPerReport;\n            while (!completion.IsCompleted)\n            {\n                var more = await completedBlockReader.WaitToReadAsync();\n                if (!more) break;\n                while (completedBlockReader.TryRead(out var block))\n                {\n                    // Register the measurement values\n                    BenchmarksEventSource.Measure(\"requests\", block.Completed);\n                    BenchmarksEventSource.Measure(\"failures\", block.Failures);\n                    BenchmarksEventSource.Measure(\"rps\", block.RequestsPerSecond);\n\n                    blocks.Add(block);\n                }\n\n                if (this._logIntermediateResults && blocks.Count >= nextReportBlockCount)\n                {\n                    nextReportBlockCount += blocksPerReport;\n                    _logger.LogInformation(\"    \" + BuildReport(0));\n                }\n            }\n\n            var finalReport = BuildReport(0);\n\n            if (this._logIntermediateResults) _logger.LogInformation(\"  Total: \" + finalReport);\n            else _logger.LogInformation(finalReport.ToString());\n\n            return finalReport;\n\n            LoadGeneratorReport BuildReport(int statingBlockIndex)\n            {\n                if (blocks.Count == 0) return default;\n                var successes = 0;\n                var failures = 0;\n                long completed = 0;\n                var reportBlocks = 0;\n                long minStartTime = long.MaxValue;\n                long maxEndTime = long.MinValue;\n                for (var i = statingBlockIndex; i < blocks.Count; i++)\n                {\n                    var b = blocks[i];\n                    ++reportBlocks;\n                    successes += b.Successes;\n                    failures += b.Failures;\n                    completed += b.Completed;\n                    if (b.StartTimestamp < minStartTime) minStartTime = b.StartTimestamp;\n                    if (b.EndTimestamp > maxEndTime) maxEndTime = b.EndTimestamp;\n                }\n\n                var totalSeconds = (maxEndTime - minStartTime) / StopwatchTickPerSecond;\n                var ratePerSecond = (long)(completed / totalSeconds);\n                return new LoadGeneratorReport\n                {\n                    Completed = completed,\n                    Successes = successes,\n                    Failures = failures,\n                    BlocksCompleted = reportBlocks,\n                    TotalDuration = totalSeconds,\n                };\n            }\n        }\n\n        private async Task RunWorker(TState state, int requestsPerBlock, int numBlocks, CancellationToken ct)\n        {\n            var completedBlockWriter = this._completedBlocks.Writer;\n            while (numBlocks > 0 && !ct.IsCancellationRequested)\n            {\n                var workBlock = new WorkBlock();\n                workBlock.StartTimestamp = Stopwatch.GetTimestamp();\n                while (workBlock.Completed < requestsPerBlock)\n                {\n                    try\n                    {\n                        await this._issueRequest(state).ConfigureAwait(false);\n                        ++workBlock.Successes;\n                    }\n                    catch\n                    {\n                        ++workBlock.Failures;\n                    }\n                }\n\n                workBlock.EndTimestamp = Stopwatch.GetTimestamp();\n                await completedBlockWriter.WriteAsync(workBlock);\n                --numBlocks;\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/LoadGeneratorScenario/LoadGeneratorScenarioRunner.cs",
    "content": "using Azure.Identity;\nusing DistributedTests.Common;\nusing Microsoft.Crank.EventSources;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\n\nnamespace DistributedTests.Client.LoadGeneratorScenario\n{\n    public class ClientParameters\n    {\n        public string ServiceId { get; set; }\n        public string ClusterId { get; set; }\n        public int ConnectionsPerEndpoint { get; set; }\n        public Uri AzureTableUri { get; set; }\n        public Uri AzureQueueUri { get; set; }\n    }\n\n    public class LoadGeneratorParameters\n    {\n        public int NumWorkers { get; set; }\n        public int BlocksPerWorker { get; set; }\n        public int RequestsPerBlock { get; set; } \n        public int Duration { get; set; }\n    }\n\n    public class LoadGeneratorScenarioRunner<T>\n    {\n        private readonly ILoadGeneratorScenario<T> _scenario;\n        private readonly ILogger _logger;\n\n        public LoadGeneratorScenarioRunner(ILoadGeneratorScenario<T> scenario, ILoggerFactory loggerFactory)\n        {\n            _scenario = scenario;\n            _logger = loggerFactory.CreateLogger(scenario.Name);\n        }\n\n        public async Task Run(ClientParameters clientParams, LoadGeneratorParameters loadParams)\n        {\n            Console.WriteLine($\"AzureTableUri: {clientParams.AzureTableUri}\");\n\n            // Register the measurements. n0 -> format as natural number\n            BenchmarksEventSource.Register(\"requests\", Operations.Sum, Operations.Sum, \"Requests\", \"Number of requests completed\", \"n0\");\n            BenchmarksEventSource.Register(\"failures\", Operations.Sum, Operations.Sum, \"Failures\", \"Number of failures\", \"n0\");\n            BenchmarksEventSource.Register(\"rps\", Operations.Sum, Operations.Median, \"Median RPS\", \"Rate per second\", \"n0\");\n\n            var hostBuilder = new HostBuilder().UseOrleansClient((ctx, builder) =>\n                builder.Configure<ClusterOptions>(options => { options.ClusterId = clientParams.ClusterId; options.ServiceId = clientParams.ServiceId; })\n                       .Configure<ConnectionOptions>(options => clientParams.ConnectionsPerEndpoint = 2)\n                       .UseAzureStorageClustering(options => options.TableServiceClient = clientParams.AzureTableUri.CreateTableServiceClient()));\n            using var host = hostBuilder.Build();\n\n            _logger.LogInformation(\"Connecting to cluster...\");\n            await host.StartAsync();\n            var client = host.Services.GetService<IClusterClient>();\n\n            var generator = new ConcurrentLoadGenerator<T>(\n                numWorkers: loadParams.NumWorkers,\n                blocksPerWorker: loadParams.BlocksPerWorker != 0 ? loadParams.BlocksPerWorker : int.MaxValue,\n                requestsPerBlock: loadParams.RequestsPerBlock,\n                issueRequest: _scenario.IssueRequest,\n                getStateForWorker: workerId => _scenario.GetStateForWorker(client, workerId),\n                logger: _logger,\n                logIntermediateResults: true);\n\n            _logger.LogInformation(\"Warming-up...\");\n            await generator.Warmup();\n\n            var cts = loadParams.Duration != 0\n                ? new CancellationTokenSource(TimeSpan.FromSeconds(loadParams.Duration))\n                : new CancellationTokenSource();\n\n            _logger.LogInformation(\"Running\");\n            var report = await generator.Run(cts.Token);\n\n            BenchmarksEventSource.Register(\"overall-rps\", Operations.Last, Operations.Last, \"Overall RPS\", \"RPS\", \"n0\");\n            BenchmarksEventSource.Measure(\"overall-rps\", report.RatePerSecond);\n\n            await host.StopAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/LoadGeneratorScenario/LoadGeneratorScenarios.cs",
    "content": "using DistributedTests.GrainInterfaces;\n\nnamespace DistributedTests.Client.LoadGeneratorScenario\n{\n    public interface ILoadGeneratorScenario<TState>\n    {\n        string Name { get; }\n\n        TState GetStateForWorker(IClusterClient client, int workerId);\n\n        ValueTask IssueRequest(TState state);\n    }\n\n    public class PingScenario : ILoadGeneratorScenario<IPingGrain>\n    {\n        public string Name => \"ping\";\n\n        public IPingGrain GetStateForWorker(IClusterClient client, int workerId) => client.GetGrain<IPingGrain>(Guid.NewGuid());\n\n        public ValueTask IssueRequest(IPingGrain state) => state.Ping();\n    }\n\n    public class FanOutScenario : ILoadGeneratorScenario<ITreeGrain>\n    {\n        public string Name => \"fan-out\";\n\n        public ITreeGrain GetStateForWorker(IClusterClient client, int workerId) => client.GetGrain<ITreeGrain>(primaryKey: 0, keyExtension: workerId.ToString());\n\n        public ValueTask IssueRequest(ITreeGrain root) => root.Ping();\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Client/Program.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Parsing;\nusing DistributedTests.Client.Commands;\nusing DistributedTests.Client.LoadGeneratorScenario;\nusing Microsoft.Extensions.Logging;\n\nvar loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Information)\n                                                           .AddSimpleConsole(options => options.SingleLine = true));\n\nvar root = new RootCommand();\n\nroot.Add(Scenario.CreateCommand(new PingScenario(), loggerFactory));\nroot.Add(Scenario.CreateCommand(new FanOutScenario(), loggerFactory));\nroot.Add(new CounterCaptureCommand(loggerFactory.CreateLogger<CounterCaptureCommand>()));\nroot.Add(new ChaosAgentCommand(loggerFactory.CreateLogger<ChaosAgentCommand>()));\n\nawait root.InvokeAsync(args);\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/DistributedTests.Common.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Console\" />\n    <PackageReference Include=\"Azure.Storage.Queues\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Json\" />\n    <PackageReference Include=\"System.CommandLine\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/GrainInterfaces/IPingGrain.cs",
    "content": "namespace DistributedTests.GrainInterfaces;\n\npublic interface IPingGrain : IGrainWithGuidKey\n{\n    ValueTask Ping();\n}\n\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/GrainInterfaces/IStreamingGrains.cs",
    "content": "namespace DistributedTests.GrainInterfaces\n{\n    public static class StreamingConstants\n    {\n        public const string StreamingProvider = \"TestStreamingProvider\";\n        public const string StreamingNamespace = \"TestStreamingNamespace\";\n\n        public const string DefaultCounterGrain = \"default\";\n    }\n\n    public class ReportingOptions\n    {\n        public DateTime ReportAt { get; set; }\n\n        public int Duration { get; set; }\n    }\n\n    public interface IGrainWithCounter : IGrainWithGuidKey\n    {\n        Task<int> GetCounterValue(string counterName);\n    }\n\n    public interface IImplicitSubscriberGrain : IGrainWithCounter\n    {\n    }\n\n    public interface ICounterGrain : IGrainWithStringKey\n    {\n        Task Track(IGrainWithCounter grain);\n\n        Task<TimeSpan> GetRunDuration();\n\n        Task<TimeSpan> WaitTimeForReport();\n\n        Task<int> GetTotalCounterValue(string counterName);\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/GrainInterfaces/ITreeGrain.cs",
    "content": "﻿namespace DistributedTests.GrainInterfaces;\n\npublic interface ITreeGrain : IGrainWithIntegerCompoundKey\n{\n    public ValueTask Ping();\n}\n\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/MessageChannel/Channels.cs",
    "content": "using System.Diagnostics;\nusing System.Text.Json;\nusing Azure.Identity;\nusing Azure.Storage.Queues;\n\nnamespace DistributedTests.Common.MessageChannel\n{\n    public interface ISendChannel\n    {\n        Task<List<AckMessage>> SendMessages(List<ServerMessage> messages, CancellationToken cancellationToken);\n    }\n\n    public interface IReceiveChannel\n    {\n        Task<ServerMessage> WaitForMessage(CancellationToken cancellationToken);\n\n        Task SendAck(ServerMessage message);\n    }\n\n    public class SendChannel : ISendChannel\n    {\n        private readonly QueueClient _writeQueue;\n        private readonly QueueClient _readQueue;\n\n        internal SendChannel(QueueClient writeQueue, QueueClient readQueue)\n        {\n            _writeQueue = writeQueue;\n            _readQueue = readQueue;\n        }\n\n        public async Task<List<AckMessage>> SendMessages(List<ServerMessage> messages, CancellationToken cancellationToken)\n        {\n            foreach (var msg in messages)\n            {\n                await _writeQueue.SendMessageAsync(JsonSerializer.Serialize(msg), cancellationToken);\n            }\n            var acks = new List<AckMessage>();\n            for (var i = 0; i < messages.Count; i++)\n            {\n                var msg = await _readQueue.WaitForMessage<AckMessage>(cancellationToken);\n                acks.Add(msg);\n            }\n            return acks;\n        }\n    }\n\n    public class ReceiveChannel : IReceiveChannel\n    {\n        private readonly QueueClient _writeQueue;\n        private readonly QueueClient _readQueue;\n        private readonly string _serverName;\n\n        internal ReceiveChannel(QueueClient writeQueue, QueueClient readQueue, string serverName)\n        {\n            _writeQueue = writeQueue;\n            _readQueue = readQueue;\n            _serverName = serverName;\n        }\n\n        public async Task<ServerMessage> WaitForMessage(CancellationToken cancellationToken) => await _readQueue.WaitForMessage<ServerMessage>(cancellationToken);\n\n        public async Task SendAck(ServerMessage message)\n        {\n            var ack = AckMessage.CreateAckMessage(message, _serverName);\n            await _writeQueue.SendMessageAsync(JsonSerializer.Serialize(ack));\n        }\n    }\n\n    public static class Channels\n    {\n        private static readonly string CLIENT_TO_SERVER_QUEUE = \"servers-{0}\";\n        private static readonly string SILO_TO_CLIENT_QUEUE = \"client-{0}\";\n\n        public static Task<ISendChannel> CreateSendChannel(string clusterId, Uri azureQueueUri)\n            => CreateSendChannel(clusterId, azureQueueUri.CreateQueueServiceClient());\n\n        public static async Task<ISendChannel> CreateSendChannel(string clusterId, QueueServiceClient queueServiceClient)\n        {\n            var writeQueue = queueServiceClient.GetQueueClient(string.Format(CLIENT_TO_SERVER_QUEUE, clusterId));\n            var readQueue = queueServiceClient.GetQueueClient(string.Format(SILO_TO_CLIENT_QUEUE, clusterId));\n\n            await writeQueue.CreateIfNotExistsAsync();\n            await readQueue.CreateIfNotExistsAsync();\n\n            return new SendChannel(writeQueue, readQueue);\n        }\n\n        public static Task<IReceiveChannel> CreateReceiveChannel(string serverName, string clusterId, Uri azureQueueUri)\n            => CreateReceiveChannel(serverName, clusterId, azureQueueUri.CreateQueueServiceClient());\n\n        public static async Task<IReceiveChannel> CreateReceiveChannel(string serverName, string clusterId, QueueServiceClient queueServiceClient)\n        {\n            var writeQueue = queueServiceClient.GetQueueClient(string.Format(SILO_TO_CLIENT_QUEUE, clusterId));\n            var readQueue = queueServiceClient.GetQueueClient(string.Format(CLIENT_TO_SERVER_QUEUE, clusterId));\n\n            await writeQueue.CreateIfNotExistsAsync();\n            await readQueue.CreateIfNotExistsAsync();\n\n            return new ReceiveChannel(writeQueue, readQueue, serverName);\n        }\n\n        internal static async Task<T> WaitForMessage<T>(this QueueClient queueClient, CancellationToken ct)\n        {\n            while (!ct.IsCancellationRequested)\n            {\n                var result = await queueClient.ReceiveMessagesAsync(maxMessages: 1, cancellationToken: ct);\n                var msg = result.Value?.FirstOrDefault();\n\n                if (msg != null)\n                {\n                    await queueClient.DeleteMessageAsync(msg.MessageId, msg.PopReceipt);\n                    return JsonSerializer.Deserialize<T>(msg.MessageText);\n                }\n\n                await Task.Delay(1000, ct);\n            }\n            ct.ThrowIfCancellationRequested();\n            throw new Exception(\"No message\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/MessageChannel/Messages.cs",
    "content": "namespace DistributedTests.Common.MessageChannel\n{\n    public class ServerMessage\n    {\n        public Guid MessageId { get; }\n\n        public bool IsGraceful { get; }\n\n        public bool Restart { get; }\n\n        public ServerMessage(bool isGraceful, bool restart)\n        {\n            MessageId = Guid.NewGuid();\n            IsGraceful = isGraceful;\n            Restart = restart;\n        }\n    }\n\n    public class AckMessage\n    {\n        public Guid MessageId { get; }\n\n        public string ServerName { get; set; }\n\n        public AckMessage(Guid messageId, string serverName)\n        {\n            MessageId = messageId;\n            ServerName = serverName;\n        }\n\n        public static AckMessage CreateAckMessage(ServerMessage msg, string serverName) => new(msg.MessageId, serverName);\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/OptionHelper.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Parsing;\n\nnamespace DistributedTests\n{\n    public static class OptionHelper\n    {\n        public static Option<T> CreateOption<T>(string alias, string description = null, bool isRequired = false, T defaultValue = default, Func<T, bool> validator = null)\n        {\n            var options = new Option<T>(alias, description) { IsRequired = isRequired };\n            if (!isRequired)\n            {\n                options.SetDefaultValue(defaultValue);\n            }\n            if (validator != null)\n            {\n                options.AddValidator(result => Validator(result, validator));\n            }\n            return options;\n        }\n\n        public static string Validator<T>(OptionResult result, Func<T, bool> validator)\n        {\n            var value = result.GetValueOrDefault<T>();\n            if (!validator(value))\n            {\n                return $\"Option {result.Token?.Value} cannot be set to {value}\";\n            }\n            return string.Empty;\n        }\n\n        public static bool OnlyStrictlyPositive(int value) => value > 0;\n        public static bool OnlyPositiveOrZero(int value) => value >= 0;\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Common/TokenCredentialHelper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Azure.Core;\nusing Azure.Data.Tables;\nusing Azure.Identity;\nusing Azure.Storage.Queues;\n\nnamespace DistributedTests.Common;\n\npublic static class TokenCredentialHelper\n{\n    private static string EmulatorConnectionString = \"UseDevelopmentStorage=true\";\n\n    public static TableServiceClient CreateTableServiceClient(this Uri azureTableUri)\n    {\n        if (azureTableUri.IsLoopback)\n        {\n            // Assume it's the emulator/azurite\n            return new TableServiceClient(EmulatorConnectionString);\n        }\n        return new TableServiceClient(azureTableUri, GetTokenCredential());\n    }\n\n    public static QueueServiceClient CreateQueueServiceClient(this Uri azureQueueUri)\n    {\n        if (azureQueueUri.IsLoopback)\n        {\n            // Assume it's the emulator/azurite\n            return new QueueServiceClient(EmulatorConnectionString);\n        }\n        return new QueueServiceClient(azureQueueUri, GetTokenCredential());\n    }\n\n    public static TokenCredential GetTokenCredential()\n    {\n        var tenantId = Environment.GetEnvironmentVariable(\"TENANT_ID\");\n        var clientId = Environment.GetEnvironmentVariable(\"CLIENT_ID\");\n        if (tenantId != null && clientId != null)\n        {\n            // Uses Federated Id Creds, from here:\n            // https://review.learn.microsoft.com/en-us/identity/microsoft-identity-platform/federated-identity-credentials?branch=main&tabs=dotnet#azure-sdk-for-net\n            return new ClientAssertionCredential(\n              tenantId, // Tenant ID for destination resource\n              clientId,  // Client ID of the app we're federating to\n              () => GetManagedIdentityToken(null, \"api://AzureADTokenExchange\")) // null here for default MSI\n            ;\n        }\n        else\n        {\n            return new DefaultAzureCredential();\n        }\n    }\n\n    /// <summary>\n    /// Gets a token for the user-assigned Managed Identity.\n    /// </summary>\n    /// <param name=\"msiClientId\">Client ID for the Managed Identity.</param>\n    /// <param name=\"audience\">Target audience. For public clouds should be api://AzureADTokenExchange.</param>\n    /// <returns>If successful, returns an access token.</returns>\n    public static string GetManagedIdentityToken(string msiClientId, string audience)\n    {\n        var miCredential = new ManagedIdentityCredential(msiClientId);\n        return miCredential.GetToken(new TokenRequestContext(new[] { $\"{audience}/.default\" })).Token;\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Grains/CounterReportingGrain.cs",
    "content": "using DistributedTests.GrainInterfaces;\nusing Microsoft.Extensions.Options;\n\nnamespace DistributedTests.Grains\n{\n    public class CounterGrain : Grain, ICounterGrain\n    {\n        private readonly ReportingOptions _options;\n        private readonly List<IGrainWithCounter> _trackedGrains = new();\n\n        public CounterGrain(IOptions<ReportingOptions> options)\n        {\n            _options = options.Value;\n        }\n\n        public Task<TimeSpan> GetRunDuration() => Task.FromResult(TimeSpan.FromSeconds(_options.Duration));\n\n        public async Task<int> GetTotalCounterValue(string counterName)\n        {\n            var counter = 0;\n            foreach (var grain in _trackedGrains)\n            {\n                counter += await grain.GetCounterValue(counterName);\n            }\n            return counter;\n        }\n\n        public Task Track(IGrainWithCounter grain)\n        {\n            _trackedGrains.Add(grain);\n            return Task.CompletedTask;\n        }\n\n        public Task<TimeSpan> WaitTimeForReport()\n        {\n            var ts = _options.ReportAt - DateTime.UtcNow;\n            return ts < TimeSpan.Zero\n                ? Task.FromResult(TimeSpan.Zero)\n                : Task.FromResult(ts);\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Grains/DistributedTests.Grains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\DistributedTests\\DistributedTests.Common\\DistributedTests.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Grains/ImplicitSubscriberGrain.cs",
    "content": "using DistributedTests.GrainInterfaces;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\n\nnamespace DistributedTests.Grains\n{\n    [ImplicitStreamSubscription(StreamingConstants.StreamingNamespace)]\n    public class ImplicitSubscriberGrain : Grain, IImplicitSubscriberGrain, IStreamSubscriptionObserver, IAsyncObserver<object>\n    {\n        private readonly ILogger _logger;\n        private int _requestCounter;\n        private int _errorCounter;\n\n        public ImplicitSubscriberGrain(ILogger<ImplicitSubscriberGrain> logger)\n        {\n            _logger = logger;\n        }\n\n        public Task<int> GetCounterValue(string counterName)\n        {\n            return counterName switch\n            {\n                \"requests\" => Task.FromResult(_requestCounter),\n                \"errors\" => Task.FromResult(_errorCounter),\n                _ => throw new ArgumentOutOfRangeException(nameof(counterName)),\n            };\n        }\n\n        public Task OnCompletedAsync() => Task.CompletedTask;\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            _logger.LogError(ex, \"OnErrorAsync\");\n            _errorCounter++;\n            return Task.CompletedTask;\n        }\n\n        public Task OnNextAsync(object item, StreamSequenceToken token = null)\n        {\n            if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace(\"OnNextAsync {Item}\", item);\n\n            _requestCounter++;\n\n            return Task.CompletedTask;\n        }\n\n        public async Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace(\"OnSubscribed {StreamId}\", handleFactory.StreamId);\n\n            await GrainFactory\n                .GetGrain<ICounterGrain>(StreamingConstants.DefaultCounterGrain)\n                .Track(this.AsReference<IGrainWithCounter>());\n\n            await handleFactory\n                .Create<object>()\n                .ResumeAsync(this);\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Grains/PingGrain.cs",
    "content": "using DistributedTests.GrainInterfaces;\n\nnamespace DistributedTests.Grains;\n\npublic class PingGrain : Grain, IPingGrain\n{\n    public ValueTask Ping() => default;\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Grains/TreeGrain.cs",
    "content": "using DistributedTests.GrainInterfaces;\n\nnamespace DistributedTests.Grains;\n\npublic class TreeGrain : Grain, ITreeGrain\n{\n    // 16^4 grains (~65K)\n    public const int FanOutFactor = 16;\n    public const int MaxLevel = 4;\n    private readonly List<ITreeGrain> _children;\n\n    public TreeGrain()\n    {\n        var id = this.GetPrimaryKeyLong(out var forestName);\n\n        var level = id == 0 ? 0 : (int)Math.Log(id, FanOutFactor);\n        var numChildren = level < MaxLevel ? FanOutFactor : 0;\n        _children = new List<ITreeGrain>(numChildren);\n        var childBase = (id + 1) * FanOutFactor;\n        for (var i = 1; i <= numChildren; i++)\n        {\n            var child = GrainFactory.GetGrain<ITreeGrain>(childBase + i, keyExtension: forestName);\n            _children.Add(child);\n        }\n    }\n\n    public async ValueTask Ping()\n    {\n        var tasks = new List<ValueTask>(_children.Count);\n        foreach (var child in _children)\n        {\n            tasks.Add(child.Ping());\n        }\n\n        // Wait for the tasks to complete.\n        foreach (var task in tasks)\n        {\n            await task;\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/Configurator/EventGeneratorStreamingSilo.cs",
    "content": "using System.CommandLine;\nusing DistributedTests.GrainInterfaces;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace DistributedTests.Server.Configurator\n{\n    public class EventGeneratorStreamingSilo : ISiloConfigurator<EventGeneratorStreamingSilo.Parameter>\n    {\n        public class Parameter\n        {\n            public StreamPubSubType Type { get; set; }\n\n            public int StreamsPerQueue { get; set; }\n\n            public int QueueCount { get; set; }\n\n            public int BatchSize { get; set; }\n\n            public int Wait { get; set; }\n\n            public int Duration { get; set; }\n        }\n\n        public string Name => nameof(EventGeneratorStreamingSilo);\n\n        public List<Option> Options => new()\n        {\n            OptionHelper.CreateOption<StreamPubSubType>(\"--type\", defaultValue: StreamPubSubType.ExplicitGrainBasedAndImplicit),\n            OptionHelper.CreateOption<int>(\"--streamsPerQueue\", defaultValue: 1000),\n            OptionHelper.CreateOption<int>(\"--queueCount\", defaultValue: 8),\n            OptionHelper.CreateOption<int>(\"--batchSize\", defaultValue: 5),\n            OptionHelper.CreateOption<int>(\"--wait\", \"initial wait, in seconds, before starting generating events\", defaultValue: 30),\n            OptionHelper.CreateOption<int>(\"--duration\", \"duration, in seconds, of the run\", defaultValue: 120),\n        };\n\n        public void Configure(ISiloBuilder siloBuilder, Parameter parameters)\n        {\n            var generatorOptions = new TimeBoundEventGeneratorConfig\n            {\n                NumberOfStreams = parameters.StreamsPerQueue,\n                StreamNamespace = StreamingConstants.StreamingNamespace,\n                StartTime = DateTime.UtcNow.AddSeconds(parameters.Wait),\n                EndTime = DateTime.UtcNow.AddSeconds(parameters.Duration),\n            };\n\n            siloBuilder\n                .AddMemoryGrainStorage(\"PubSubStore\")\n                .ConfigureServices(svc =>\n                {\n                    svc.AddOptions<ReportingOptions>().Configure(options =>\n                    {\n                        options.ReportAt = generatorOptions.EndTime.AddSeconds(parameters.Wait);\n                        options.Duration = parameters.Duration;\n                    });\n                })\n                .ConfigureServices(services => services.AddKeyedSingleton<IStreamGeneratorConfig>(StreamingConstants.StreamingProvider, (s, n) => generatorOptions))\n                .AddPersistentStreams(\n                    StreamingConstants.StreamingProvider,\n                    GeneratorAdapterFactory.Create,\n                    b =>\n                    {\n                        b.ConfigurePullingAgent(ob => ob.Configure(options => { options.BatchContainerBatchSize = parameters.BatchSize; }));\n                        b.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = parameters.QueueCount));\n                        b.UseConsistentRingQueueBalancer();\n                        b.ConfigureStreamPubSub(parameters.Type);\n                    });\n        }\n    }\n\n    public class TimeBoundEventGeneratorConfig : IStreamGeneratorConfig\n    {\n        public Type StreamGeneratorType => typeof(TimeBoundEventGenerator);\n\n        public string StreamNamespace { get; set; }\n\n        public int NumberOfStreams { get; set; }\n\n        public Type PayloadType { get; set; } = typeof(object);\n\n        public DateTime StartTime { get; set; }\n\n        public DateTime EndTime { get; set; }\n    }\n\n    public class TimeBoundEventGenerator : IStreamGenerator\n    {\n        private DateTime _startTime;\n        private DateTime _endTime;\n        private readonly List<StreamId> _streamIds = new List<StreamId>();\n        private int _sequenceId = 0;\n        private object _payload;\n\n        public void Configure(IServiceProvider serviceProvider, IStreamGeneratorConfig generatorConfig)\n        {\n            var config = (generatorConfig as TimeBoundEventGeneratorConfig) ?? throw new ArgumentException(\"Invalid configuration type\", nameof(generatorConfig));\n            _startTime = config.StartTime;\n            _endTime = config.EndTime;\n            for (var i = 0; i < config.NumberOfStreams; i++)\n            {\n                _streamIds.Add(StreamId.Create(config.StreamNamespace, Guid.NewGuid()));\n            }\n            _payload = Activator.CreateInstance(config.PayloadType);\n        }\n\n        public bool TryReadEvents(DateTime utcNow, int maxCount, out List<IBatchContainer> events)\n        {\n            if (utcNow < _startTime || utcNow > _endTime)\n            {\n                events = null;\n                return false;\n            }\n\n            events = new List<IBatchContainer>(maxCount);\n            for (int i = 0; i < maxCount; i++)\n            {\n                var streamId = _streamIds[_sequenceId % _streamIds.Count];\n                var container = new GeneratedBatchContainer(streamId, _payload, new EventSequenceTokenV2(_sequenceId));\n                events.Add(container);\n                _sequenceId++;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/Configurator/ISiloConfigurator.cs",
    "content": "using System.CommandLine;\n\nnamespace DistributedTests.Server.Configurator\n{\n    public interface ISiloConfigurator<T>\n    {\n        string Name { get; }\n\n        List<Option> Options { get; }\n\n        void Configure(ISiloBuilder siloBuilder, T parameters);\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/Configurator/SimpleSilo.cs",
    "content": "using System.CommandLine;\n\nnamespace DistributedTests.Server.Configurator\n{\n    public class SimpleSilo : ISiloConfigurator<object>\n    {\n        public string Name => nameof(SimpleSilo);\n\n        public List<Option> Options => new();\n\n        public void Configure(ISiloBuilder siloBuilder, object parameters)\n        {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/DistributedTests.Server.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <OutputPath Condition=\" '$(DistributedTestsOutputPath)'!='' \">$(DistributedTestsOutputPath)/DistributedTests.Server</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\"..\\secrets.json\" Link=\"secrets.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Clustering.AzureStorage\\Orleans.Clustering.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Persistence.Memory\\Orleans.Persistence.Memory.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Server\\Orleans.Server.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\DistributedTests\\DistributedTests.Common\\DistributedTests.Common.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\DistributedTests\\DistributedTests.Grains\\DistributedTests.Grains.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Console\" />\n    <PackageReference Include=\"System.CommandLine\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/Program.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Parsing;\nusing DistributedTests.Server;\nusing DistributedTests.Server.Configurator;\n\nvar root = new RootCommand();\n\nroot.Add(Server.CreateCommand(new SimpleSilo()));\nroot.Add(Server.CreateCommand(new EventGeneratorStreamingSilo()));\n\nawait root.InvokeAsync(args);"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/ServerCommand.cs",
    "content": "using System.CommandLine;\nusing System.CommandLine.Invocation;\nusing DistributedTests.Server.Configurator;\nusing Microsoft.Extensions.Hosting;\n\nnamespace DistributedTests.Server\n{\n    public class ServerCommand<T> : Command\n    {\n        private readonly ServerRunner<T> _siloRunner;\n\n        public ServerCommand(ISiloConfigurator<T> siloConfigurator)\n            : base(siloConfigurator.Name)\n        {\n            _siloRunner = new ServerRunner<T>(siloConfigurator);\n\n            AddOption(OptionHelper.CreateOption<string>(\"--serviceId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<string>(\"--clusterId\", isRequired: true));\n            AddOption(OptionHelper.CreateOption(\"--siloPort\", defaultValue: 11111));\n            AddOption(OptionHelper.CreateOption(\"--gatewayPort\", defaultValue: 30000));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureQueueUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption<Uri>(\"--azureTableUri\", isRequired: true));\n            AddOption(OptionHelper.CreateOption(\"--activationRepartitioning\", defaultValue: false));\n\n            foreach (var opt in siloConfigurator.Options)\n            {\n                AddOption(opt);\n            }\n\n            Handler = CommandHandler.Create<CommonParameters, T>(_siloRunner.Run);\n        }\n    }\n\n    public static class Server\n    {\n        public static Command CreateCommand<T>(ISiloConfigurator<T> configurator) => new ServerCommand<T>(configurator);\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/DistributedTests.Server/ServerRunner.cs",
    "content": "using DistributedTests.Server.Configurator;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing DistributedTests.Common.MessageChannel;\nusing Microsoft.Extensions.Logging;\nusing Azure.Identity;\nusing DistributedTests.Common;\n\nnamespace DistributedTests.Server\n{\n    public class CommonParameters\n    {\n        public string ServiceId { get; set; }\n        public string ClusterId { get; set; }\n        public int SiloPort { get; set; }\n        public int GatewayPort { get; set; }\n        public Uri AzureTableUri { get; set; }\n        public Uri AzureQueueUri { get; set; }\n        public bool ActivationRepartitioning { get; set; }\n    }\n\n    public class ServerRunner<T>\n    {\n        private readonly ISiloConfigurator<T> _siloConfigurator;\n        private readonly string _siloName;\n\n        public ServerRunner(ISiloConfigurator<T> siloConfigurator)\n        {\n            _siloConfigurator = siloConfigurator;\n            _siloName = $\"{Environment.MachineName}-{Guid.NewGuid().ToString(\"N\")[..5]}\";\n        }\n\n        public async Task Run(CommonParameters commonParameters, T configuratorParameters)\n        {\n            var channel = await Channels.CreateReceiveChannel(_siloName, commonParameters.ClusterId, commonParameters.AzureQueueUri);\n\n            ServerMessage msg = null;\n\n            while (true)\n            {\n                var host = Host\n                    .CreateDefaultBuilder()\n                    .ConfigureLogging(logging =>\n                    {\n                        logging.AddFilter(\"Orleans.Runtime.Placement.Repartitioning\", LogLevel.Debug);\n                    })\n                    .UseOrleans((ctx, siloBuilder) => ConfigureOrleans(siloBuilder, commonParameters, configuratorParameters))\n                    .Build();\n\n                var hostTask = host.RunAsync();\n\n                if (msg != null)\n                {\n                    // we did restart the silo\n                    await channel.SendAck(msg);\n                    msg = null;\n                }\n\n                msg = await channel.WaitForMessage(CancellationToken.None);\n\n                await host.StopAsync(new CancellationToken(!msg.IsGraceful));\n\n                if (!msg.Restart)\n                {\n                    await channel.SendAck(msg);\n                    break;\n                }\n            }\n        }\n\n        private void ConfigureOrleans(ISiloBuilder siloBuilder, CommonParameters commonParameters, T configuratorParameters)\n        {\n            siloBuilder\n                .Configure<SiloOptions>(options => options.SiloName = _siloName)\n                .Configure<ClusterOptions>(options => { options.ClusterId = commonParameters.ClusterId; options.ServiceId = commonParameters.ServiceId; })\n                .ConfigureEndpoints(siloPort: commonParameters.SiloPort, gatewayPort: commonParameters.GatewayPort)\n                .UseAzureStorageClustering(options => options.TableServiceClient = commonParameters.AzureTableUri.CreateTableServiceClient());\n\n            if (commonParameters.ActivationRepartitioning)\n            {\n#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                siloBuilder.AddActivationRepartitioner();\n#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n            }\n\n            _siloConfigurator.Configure(siloBuilder, configuratorParameters);\n        }\n    }\n}\n"
  },
  {
    "path": "test/DistributedTests/README.md",
    "content": "# Distributed Tests\n\n## Running locally\n\n### Install crank and crank-agent\n\n```sh\ndotnet tool install -g Microsoft.Crank.Controller --version 0.2.0-*\n```\n\n```sh\ndotnet tool install -g Microsoft.Crank.Agent --version \"0.2.0-*\"\n```\n\n### Run crank agent\n\nDo this in a separate terminal.\n\n```sh\ncrank-agent --url http://*:5010\n```\n\n### Build Orleans\n\n```sh\ndotnet build -c Release\n```\n\n### Run crank scenario\n\nRun this from the root of the repository (next to Orleans.slnx):\n\n```sh\ncrank --config .\\distributed-tests.yml --scenario ping --profile local\n```\n\nNote: scenarios can be found in `distributed-tests.yml`.\n"
  },
  {
    "path": "test/DistributedTests/secrets.json",
    "content": "{\n  \"ClusteringConnectionString\":\"UseDevelopmentStorage=true\"\n}"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace AWSUtils.Tests\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides AWS-specific test environment setup and resources.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/LivenessTests.cs",
    "content": "using AWSUtils.Tests.StorageTests;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace AWSUtils.Tests.Liveness\n{\n    /// <summary>\n    /// Liveness tests for AWS DynamoDB membership provider.\n    /// \n    /// These tests verify that Orleans cluster membership management works correctly\n    /// when using DynamoDB as the membership table provider. DynamoDB provides:\n    /// - Distributed membership tracking across silos\n    /// - Failure detection and recovery\n    /// - Consistent cluster topology views\n    /// \n    /// The tests simulate various failure scenarios to ensure the cluster\n    /// maintains consistency and recovers properly.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    public class LivenessTests_DynamoDB : LivenessTestsBase\n    {\n        public LivenessTests_DynamoDB(ITestOutputHelper output) : base(output)\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to DynamoDB simulator\");\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        /// <summary>\n        /// Configures silos to use DynamoDB for cluster membership.\n        /// Sets up the DynamoDB service endpoint for testing (typically a local simulator).\n        /// </summary>\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseDynamoDBClustering(options => { options.Service = AWSTestConstants.DynamoDbService; });\n            }\n        }\n\n        /// <summary>\n        /// Configures clients to use DynamoDB for discovering cluster gateways.\n        /// Ensures clients can locate and connect to silos using the same\n        /// DynamoDB-based membership information.\n        /// </summary>\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.UseDynamoDBClustering(ob => ob.Configure(gatewayOptions => \n                {\n                    gatewayOptions.Service = AWSTestConstants.DynamoDbService;\n                }));\n            }\n        }\n\n        /// <summary>\n        /// Basic liveness test verifying cluster membership operations.\n        /// Tests that silos can join the cluster, be discovered by other silos,\n        /// and maintain accurate membership information in DynamoDB.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_AWS_DynamoDB_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        /// <summary>\n        /// Tests cluster recovery when the primary silo is restarted.\n        /// Verifies that the cluster can handle the loss and recovery of\n        /// the primary silo without losing membership consistency.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_AWS_DynamoDB_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        /// <summary>\n        /// Tests cluster recovery when a gateway silo is restarted.\n        /// Verifies that client connections can recover and find alternative\n        /// gateways when their connected gateway fails.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_AWS_DynamoDB_3_Restart_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        /// <summary>\n        /// Tests cluster recovery when a non-primary silo is restarted.\n        /// Verifies that grain activations are properly migrated and\n        /// the cluster maintains operation during silo failures.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_AWS_DynamoDB_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        /// <summary>\n        /// Tests cluster recovery when a silo with active timers is killed.\n        /// Verifies that timer registrations are properly recovered when\n        /// grains are reactivated on other silos after failure.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_AWS_DynamoDB_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/MembershipTests/DynamoDBMembershipTableTest.cs",
    "content": "using AWSUtils.Tests.StorageTests;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.DynamoDB;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing TestExtensions;\nusing UnitTests;\nusing UnitTests.MembershipTests;\nusing Xunit;\n\nnamespace AWSUtils.Tests.MembershipTests\n{\n    /// <summary>\n    /// Tests for operation of Orleans Membership Table using AWS DynamoDB - Requires access to external DynamoDB storage\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    public class DynamoDBMembershipTableTest : MembershipTableTestsBase, IClassFixture<DynamoDBStorageTestsFixture>\n    {\n        public DynamoDBMembershipTableTest(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(\"DynamoDBDataManager\", LogLevel.Trace);\n            filters.AddFilter(\"OrleansSiloInstanceManager\", LogLevel.Trace);\n            filters.AddFilter(\"Storage\", LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to AWS DynamoDB simulator\");\n            var options = new DynamoDBClusteringOptions();\n            DynamoDBMembershipHelper.ParseDataConnectionString(this.connectionString, options);\n            return new DynamoDBMembershipTable(this.loggerFactory, Options.Create(options), this._clusterOptions);\n        }\n\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new DynamoDBGatewayOptions();\n            DynamoDBGatewayListProviderHelper.ParseDataConnectionString(this.connectionString, options);\n            return new DynamoDBGatewayListProvider(this.loggerFactory.CreateLogger<DynamoDBGatewayListProvider>(), Options.Create(options), this._clusterOptions, this._gatewayOptions);\n        }\n\n        protected override Task<string> GetConnectionString()\n        {\n            return Task.FromResult(AWSTestConstants.IsDynamoDbAvailable ? $\"Service={AWSTestConstants.DynamoDbService}\" : null);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_DynamoDB_CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_DynamoDB_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_DynamoDB_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/MembershipTests/SiloInstanceRecordTests.cs",
    "content": "﻿using System.Net;\nusing Amazon.DynamoDBv2.Model;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing Xunit;\n\nnamespace AWSUtils.Tests.MembershipTests\n{\n    /// <summary>\n    /// Tests DynamoDB silo instance record key generation and retrieval for membership table entries.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    public class SiloInstanceRecordTests\n    {\n        [Fact]\n        public void GetKeysTest()\n        {\n            SiloAddress address = SiloAddress.New(new IPEndPoint(IPAddress.Parse(\"127.0.0.1\"), 12345), 67890); \n            var instanceRecord = new SiloInstanceRecord\n            {\n                DeploymentId = \"deploymentID\",\n                SiloIdentity = SiloInstanceRecord.ConstructSiloIdentity(address)\n            };\n\n            Dictionary<string, AttributeValue> keys = instanceRecord.GetKeys();\n\n            Assert.Equal(2, keys.Count);\n            Assert.Equal(instanceRecord.DeploymentId, keys[SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME].S);\n            Assert.Equal(instanceRecord.SiloIdentity, keys[SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME].S);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Orleans.AWS.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <DefineConstants>$(DefineConstants);AWSUTILS_TESTS</DefineConstants>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"$(SourceRoot)src\\AWS\\Shared\\AWSUtils.cs\" Link=\"AWSUtils.cs\" />\n    <Compile Include=\"$(SourceRoot)src\\AWS\\Shared\\Storage\\DynamoDBStorage.cs\" Link=\"Storage\\DynamoDBStorage.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\AWS\\Orleans.Clustering.DynamoDB\\Orleans.Clustering.DynamoDB.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AWS\\Orleans.Persistence.DynamoDB\\Orleans.Persistence.DynamoDB.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AWS\\Orleans.Reminders.DynamoDB\\Orleans.Reminders.DynamoDB.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AWS\\Orleans.Streaming.SQS\\Orleans.Streaming.SQS.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Streaming.Tests\\Orleans.Streaming.Tests.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Reminder/DynamoDBRemindersTableTests.cs",
    "content": "using AWSUtils.Tests.StorageTests;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Reminders.DynamoDB;\nusing TestExtensions;\nusing UnitTests;\nusing UnitTests.RemindersTest;\nusing Xunit;\n\nnamespace AWSUtils.Tests.RemindersTest\n{\n    /// <summary>\n    /// Tests DynamoDB implementation of the Orleans reminders table for storing and retrieving grain reminders.\n    /// </summary>\n    [TestCategory(\"Reminders\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class DynamoDBRemindersTableTests : ReminderTableTestsBase, IClassFixture<DynamoDBStorageTestsFixture>\n    {\n        public DynamoDBRemindersTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, new LoggerFilterOptions())\n        {\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to AWS DynamoDB simulator\");\n\n            var options = new DynamoDBReminderStorageOptions();\n            options.ParseConnectionString(this.connectionStringFixture.ConnectionString);\n\n            return new DynamoDBReminderTable(\n                this.loggerFactory,\n                this.clusterOptions,\n                Options.Create(options));\n        }\n\n        protected override Task<string> GetConnectionString()\n        {\n            return Task.FromResult(AWSTestConstants.IsDynamoDbAvailable ? $\"Service={AWSTestConstants.DynamoDbService}\" : null);\n        }\n\n        [SkippableFact]\n        public void RemindersTable_AWS_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_AWS_RemindersRange()\n        {\n            await RemindersRange(50);\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_AWS_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_AWS_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/AWSTestConstants.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing Amazon.Runtime;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.AWSUtils.Tests;\nusing Orleans.Internal;\nusing TestExtensions;\n\nnamespace AWSUtils.Tests.StorageTests\n{\n    public class AWSTestConstants\n    {\n        private static readonly Lazy<bool> _isDynamoDbAvailable = new Lazy<bool>(() =>\n        {\n            if (string.IsNullOrEmpty(DynamoDbService))\n            {\n                return false;\n            }\n\n            try\n            {\n                DynamoDBStorage storage;\n                try\n                {\n                    storage = new DynamoDBStorage(NullLoggerFactory.Instance.CreateLogger(\"DynamoDBStorage\"), DynamoDbService);\n                }\n                catch (AmazonServiceException)\n                {\n                    return false;\n                }\n                storage.InitializeTable(\n                    \"TestTable\",\n                    new List<KeySchemaElement> {\n                        new KeySchemaElement { AttributeName = \"PartitionKey\", KeyType = KeyType.HASH }\n                    },\n                    new List<AttributeDefinition> {\n                        new AttributeDefinition { AttributeName = \"PartitionKey\", AttributeType = ScalarAttributeType.S }\n                    })\n                .WaitAsync(TimeSpan.FromSeconds(2)).Wait();\n                return true;\n            }\n            catch (Exception exc)\n            {\n                if (exc.InnerException is TimeoutException)\n                    return false;\n\n                throw;\n            }\n        });\n\n        public static string DynamoDbAccessKey { get; set; } = TestDefaultConfiguration.DynamoDbAccessKey;\n        public static string DynamoDbSecretKey { get; set; } = TestDefaultConfiguration.DynamoDbSecretKey;\n        public static string DynamoDbService { get; set; } = TestDefaultConfiguration.DynamoDbService;\n        public static string SqsConnectionString { get; set; } = TestDefaultConfiguration.SqsConnectionString;\n\n        public static bool IsDynamoDbAvailable => _isDynamoDbAvailable.Value;\n        public static bool IsSqsAvailable => !string.IsNullOrWhiteSpace(SqsConnectionString);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/DynamoDBStorageProviderTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing TestExtensions;\nusing UnitTests.Persistence;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Orleans.Storage.DynamoDBGrainStorage;\n\nnamespace AWSUtils.Tests.StorageTests\n{\n    /// <summary>\n    /// Tests DynamoDB storage provider functionality including read/write operations and format conversions.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class DynamoDBStorageProviderTests\n    {\n        private readonly IProviderRuntime providerRuntime;\n        private readonly ITestOutputHelper output;\n        private readonly Dictionary<string, string> providerCfgProps = new Dictionary<string, string>();\n        private readonly TestEnvironmentFixture fixture;\n\n        public DynamoDBStorageProviderTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            providerCfgProps[\"DataConnectionString\"] = $\"Service={AWSTestConstants.DynamoDbService}\";\n            this.providerRuntime = new ClientProviderRuntime(\n                fixture.InternalGrainFactory,\n                fixture.Services,\n                fixture.Services.GetRequiredService<ClientGrainContext>());\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\")]\n        [InlineData(null, false)]\n        [InlineData(null, true)]\n        [InlineData(400_000, false)]\n        [InlineData(400_000, true)]\n        public async Task PersistenceProvider_DynamoDB_WriteRead(int? stringLength, bool useJson)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4})\",\n                nameof(PersistenceProvider_DynamoDB_WriteRead),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJson), useJson);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var store = await InitDynamoDBGrainStorage(useJson);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\")]\n        [InlineData(null, false, false)]\n        [InlineData(null, true, false)]\n        [InlineData(400_000, false, false)]\n        [InlineData(400_000, true, false)]\n        public async Task PersistenceProvider_DynamoDB_WriteClearRead(int? stringLength, bool useJson, bool useFallback)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4}, {5} = {6})\",\n                nameof(PersistenceProvider_DynamoDB_WriteClearRead),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJson), useJson,\n                nameof(useFallback), useFallback);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var store = await InitDynamoDBGrainStorage(useJson, useFallback);\n\n            await Test_PersistenceProvider_WriteClearRead(testName, store, grainState);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\")]\n        [InlineData(null, true, false)]\n        [InlineData(null, false, true)]\n        [InlineData(400_000, true, false)]\n        [InlineData(400_000, false, true)]\n        public async Task PersistenceProvider_DynamoDB_ChangeReadFormat(int? stringLength, bool useJsonForWrite, bool useJsonForRead)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4}, {5} = {6})\",\n                nameof(PersistenceProvider_DynamoDB_ChangeReadFormat),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJsonForWrite), useJsonForWrite,\n                nameof(useJsonForRead), useJsonForRead);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n            var grainId = GrainId.Create(\"test\", Guid.NewGuid().ToString(\"N\"));\n\n            var store = await InitDynamoDBGrainStorage(useJsonForWrite);\n\n            grainState = await Test_PersistenceProvider_WriteRead(testName, store,\n                grainState, grainId);\n\n            store = await InitDynamoDBGrainStorage(useJsonForRead);\n\n            await Test_PersistenceProvider_Read(testName, store, grainState, grainId);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\")]\n        [InlineData(null, true, false)]\n        [InlineData(null, false, true)]\n        [InlineData(100_000, true, false)]\n        [InlineData(100_000, false, true)]\n        public async Task PersistenceProvider_DynamoDB_ChangeWriteFormat(int? stringLength, bool useJsonForFirstWrite, bool useJsonForSecondWrite)\n        {\n            var testName = string.Format(\"{0}({1}={2},{3}={4},{5}={6})\",\n                nameof(PersistenceProvider_DynamoDB_ChangeWriteFormat),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                \"json1stW\", useJsonForFirstWrite,\n                \"json2ndW\", useJsonForSecondWrite);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var grainId = GrainId.Create(\"test\", Guid.NewGuid().ToString(\"N\"));\n\n            var store = await InitDynamoDBGrainStorage(useJsonForFirstWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n\n            grainState = TestStoreGrainState.NewRandomState(stringLength);\n            grainState.ETag = \"*\";\n\n            store = await InitDynamoDBGrainStorage(useJsonForSecondWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\")]\n        [InlineData(null, false)]\n        [InlineData(null, true)]\n        [InlineData(400_000, false)]\n        [InlineData(400_000, true)]\n        public async Task DynamoDBStorage_ConvertToFromStorageFormat(int? stringLength, bool useJson)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4})\",\n               nameof(DynamoDBStorage_ConvertToFromStorageFormat),\n               nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n               nameof(useJson), useJson);\n\n            var state = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(state);\n\n            var storage = await InitDynamoDBGrainStorage(useJson);\n            var initialState = state.State;\n\n            var entity = new GrainStateRecord();\n\n            storage.ConvertToStorageFormat(initialState, entity);\n\n            var convertedState = storage.ConvertFromStorageFormat<TestStoreGrainState>(entity);\n            Assert.NotNull(convertedState);\n            Assert.Equal(initialState.A, convertedState.A);\n            Assert.Equal(initialState.B, convertedState.B);\n            Assert.Equal(initialState.C, convertedState.C);\n        }\n\n        private async Task<DynamoDBGrainStorage> InitDynamoDBGrainStorage(DynamoDBStorageOptions options)\n        {\n            DynamoDBGrainStorage store = ActivatorUtilities.CreateInstance<DynamoDBGrainStorage>(this.providerRuntime.ServiceProvider, \"StorageProviderTests\", options);\n            ISiloLifecycleSubject lifecycle = ActivatorUtilities.CreateInstance<SiloLifecycleSubject>(this.providerRuntime.ServiceProvider, NullLogger<SiloLifecycleSubject>.Instance);\n            store.Participate(lifecycle);\n            await lifecycle.OnStart();\n            return store;\n        }\n\n        private Task<DynamoDBGrainStorage> InitDynamoDBGrainStorage(bool useJson = false, bool useFallback = true)\n        {\n            var options = new DynamoDBStorageOptions\n            {\n                Service = AWSTestConstants.DynamoDbService,\n            };\n\n            var jsonOptions = this.providerRuntime.ServiceProvider.GetService<IOptions<OrleansJsonSerializerOptions>>();\n            var binarySerializer = new OrleansGrainStorageSerializer(this.providerRuntime.ServiceProvider.GetRequiredService<Serializer>());\n            var jsonSerializer = new JsonGrainStorageSerializer(new OrleansJsonSerializer(jsonOptions));\n\n            if (useFallback)\n                options.GrainStorageSerializer = useJson\n                    ? new GrainStorageSerializer(jsonSerializer, binarySerializer)\n                    : new GrainStorageSerializer(binarySerializer, jsonSerializer);\n            else\n                options.GrainStorageSerializer = useJson ? jsonSerializer : binarySerializer;\n\n            return InitDynamoDBGrainStorage(options);\n        }\n\n        private async Task Test_PersistenceProvider_Read(string grainTypeName, IGrainStorage store,\n            GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? GrainId.Create(\"test\", Guid.NewGuid().ToString(\"N\")) : grainId;\n\n            if (grainState == null)\n            {\n                grainState = new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n            }\n            var storedGrainState = new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Read time = {1}\", store.GetType().FullName, readTime);\n\n            var storedState = storedGrainState.State;\n            Assert.Equal(grainState.State.A, storedState.A);\n            Assert.Equal(grainState.State.B, storedState.B);\n            Assert.Equal(grainState.State.C, storedState.C);\n        }\n\n        private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteRead(string grainTypeName,\n            IGrainStorage store, GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? GrainId.Create(\"test\", Guid.NewGuid().ToString(\"N\")) : grainId;\n\n            if (grainState == null)\n            {\n                grainState = TestStoreGrainState.NewRandomState();\n            }\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.WriteStateAsync(grainTypeName, reference, grainState);\n\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n\n            var storedGrainState = new GrainState<TestStoreGrainState>\n            {\n                State = new TestStoreGrainState()\n            };\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.Equal(grainState.State.A, storedGrainState.State.A);\n            Assert.Equal(grainState.State.B, storedGrainState.State.B);\n            Assert.Equal(grainState.State.C, storedGrainState.State.C);\n\n            return storedGrainState;\n        }\n\n        private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteClearRead(string grainTypeName,\n            IGrainStorage store, GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? GrainId.Create(\"test\", Guid.NewGuid().ToString(\"N\")) : grainId;\n\n            if (grainState == null)\n            {\n                grainState = TestStoreGrainState.NewRandomState();\n            }\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.WriteStateAsync(grainTypeName, reference, grainState);\n\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n\n            await store.ClearStateAsync(grainTypeName, reference, grainState);\n\n            var storedGrainState = new GrainState<TestStoreGrainState>\n            {\n                State = new TestStoreGrainState()\n            };\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.NotNull(storedGrainState.State);\n            Assert.Equal(default, storedGrainState.State.A);\n            Assert.Equal(default, storedGrainState.State.B);\n            Assert.Equal(default, storedGrainState.State.C);\n\n            return storedGrainState;\n        }\n\n        private static void EnsureEnvironmentSupportsState(GrainState<TestStoreGrainState> grainState)\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to DynamoDB simulator\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/DynamoDBStorageStressTests.cs",
    "content": "using Amazon.DynamoDBv2.Model;\nusing Orleans.TestingHost.Utils;\nusing System.Diagnostics;\nusing System.Globalization;\nusing AWSUtils.Tests.StorageTests.AWSUtils;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace AWSUtils.Tests.StorageTests\n{\n    /// <summary>\n    /// Stress tests for DynamoDB storage to verify performance under high-volume read/write operations.\n    /// </summary>\n    [TestCategory(\"Storage\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\"), TestCategory(\"Stress\")]\n    public class DynamoDBStorageStressTests : IClassFixture<DynamoDBStorageTestsFixture>\n    {\n        private readonly ITestOutputHelper output;\n        private readonly string PartitionKey;\n        private readonly UnitTestDynamoDBStorage manager;\n\n        public DynamoDBStorageStressTests(DynamoDBStorageTestsFixture fixture, ITestOutputHelper output)\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to AWS DynamoDB simulator\");\n\n            this.output = output;\n\n            manager = fixture.DataManager;\n            PartitionKey = \"PK-DynamoDBDataManagerStressTests-\" + Guid.NewGuid();\n        }\n\n        [SkippableFact]\n        public void DynamoDBDataManagerStressTests_WriteAlot_SinglePartition()\n        {\n            const string testName = \"DynamoDBDataManagerStressTests_WriteAlot_SinglePartition\";\n            const int iterations = 2000;\n            const int batchSize = 1000;\n            const int numPartitions = 1;\n\n            // Write some data\n            WriteAlot_Async(testName, numPartitions, iterations, batchSize);\n        }\n\n        [SkippableFact]\n        public void DynamoDBDataManagerStressTests_WriteAlot_MultiPartition()\n        {\n            const string testName = \"DynamoDBDataManagerStressTests_WriteAlot_MultiPartition\";\n            const int iterations = 2000;\n            const int batchSize = 1000;\n            const int numPartitions = 100;\n\n            // Write some data\n            WriteAlot_Async(testName, numPartitions, iterations, batchSize);\n        }\n\n        [SkippableFact]\n        public void DynamoDBDataManagerStressTests_ReadAll_SinglePartition()\n        {\n            const string testName = \"DynamoDBDataManagerStressTests_ReadAll\";\n            const int iterations = 1000;\n\n            // Write some data\n            WriteAlot_Async(testName, 1, iterations, iterations);\n\n            Stopwatch sw = Stopwatch.StartNew();\n\n            var keys = new Dictionary<string, AttributeValue> { { \":PK\", new AttributeValue(PartitionKey) } };\n            var data = manager.QueryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, keys, $\"PartitionKey = :PK\", item => new UnitTestDynamoDBTableData(item)).Result;\n\n            sw.Stop();\n            int count = data.results.Count;\n            output.WriteLine(\"DynamoDBDataManagerStressTests_ReadAll completed. ReadAll {0} entries in {1} at {2} RPS\", count, sw.Elapsed, count / sw.Elapsed.TotalSeconds);\n\n            //Assert.True(count >= iterations, $\"ReadAllshould return some data: Found={count}\");\n        }\n\n        private void WriteAlot_Async(string testName, int numPartitions, int iterations, int batchSize)\n        {\n            output.WriteLine(\"Iterations={0}, Batch={1}, Partitions={2}\", iterations, batchSize, numPartitions);\n            List<Task> promises = new List<Task>();\n            Stopwatch sw = Stopwatch.StartNew();\n            for (int i = 0; i < iterations; i++)\n            {\n                string partitionKey = PartitionKey;\n                if (numPartitions > 1) partitionKey += (i % numPartitions);\n                string rowKey = i.ToString(CultureInfo.InvariantCulture);\n\n                UnitTestDynamoDBTableData dataObject = new UnitTestDynamoDBTableData();\n                dataObject.PartitionKey = partitionKey;\n                dataObject.RowKey = rowKey;\n                dataObject.StringData = rowKey;\n                var promise = manager.UpsertEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, DynamoDBStorageTests.GetKeys(dataObject), DynamoDBStorageTests.GetValues(dataObject));\n                promises.Add(promise);\n                if ((i % batchSize) == 0 && i > 0)\n                {\n                    Task.WhenAll(promises);\n                    promises.Clear();\n                    output.WriteLine(\"{0} has written {1} rows in {2} at {3} RPS\",\n                        testName, i, sw.Elapsed, i / sw.Elapsed.TotalSeconds);\n                }\n            }\n            Task.WhenAll(promises);\n            sw.Stop();\n            output.WriteLine(\"{0} completed. Wrote {1} entries to {2} partition(s) in {3} at {4} RPS\",\n                testName, iterations, numPartitions, sw.Elapsed, iterations / sw.Elapsed.TotalSeconds);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/DynamoDBStorageTestFixture.cs",
    "content": "﻿namespace AWSUtils.Tests.StorageTests\n{\n    public class DynamoDBStorageTestsFixture\n    {\n        internal UnitTestDynamoDBStorage DataManager { get; set; }\n\n        public DynamoDBStorageTestsFixture()\n        {\n            if (AWSTestConstants.IsDynamoDbAvailable)\n            {\n                DataManager = new UnitTestDynamoDBStorage();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/DynamoDBStorageTests.cs",
    "content": "﻿using Amazon.DynamoDBv2.Model;\nusing Xunit;\n\nnamespace AWSUtils.Tests.StorageTests.AWSUtils\n{\n    /// <summary>\n    /// Tests for DynamoDB storage operations.\n    /// Verifies CRUD operations, conditional updates, and etag-based concurrency control.\n    /// </summary>\n    [TestCategory(\"Storage\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    public class DynamoDBStorageTests : IClassFixture<DynamoDBStorageTestsFixture>\n    {\n        private readonly string PartitionKey;\n        private readonly UnitTestDynamoDBStorage manager;\n\n        public DynamoDBStorageTests(DynamoDBStorageTestsFixture fixture)\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n                throw new SkipException(\"Unable to connect to AWS DynamoDB simulator\");\n\n            manager = fixture.DataManager;\n            PartitionKey = \"PK-DynamoDBDataManagerTests-\" + Guid.NewGuid();\n        }\n\n        private UnitTestDynamoDBTableData GenerateNewData()\n        {\n            return new UnitTestDynamoDBTableData(\"JustData\", PartitionKey, \"RK-\" + Guid.NewGuid());\n        }\n\n        /// <summary>\n        /// Tests creating a new item with conditional check to prevent duplicates.\n        /// Verifies that the conditional expression prevents overwriting existing items.\n        /// </summary>\n        [SkippableFact,  TestCategory(\"Functional\")]\n        public async Task DynamoDBDataManager_CreateItemAsync()\n        {\n            var expression = \"attribute_not_exists(PartitionKey) AND attribute_not_exists(RowKey)\";\n            var toPersist = GenerateNewData();\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true), expression);\n            var originalEtag = toPersist.ETag;\n            var persisted = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), response => new UnitTestDynamoDBTableData(response) );\n            Assert.Equal(toPersist.StringData, persisted.StringData);\n            Assert.True(persisted.ETag == 0);\n            Assert.Equal(originalEtag, persisted.ETag);\n\n            await Assert.ThrowsAsync<ConditionalCheckFailedException>(async () =>\n            {\n                var toPersist2 = toPersist.Clone();\n                await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true), expression);\n            });\n        }\n\n        /// <summary>\n        /// Tests upserting items (insert or update).\n        /// Verifies that items can be created and then updated in subsequent operations.\n        /// </summary>\n        [SkippableFact,  TestCategory(\"Functional\")]\n        public async Task DynamoDBDataManager_UpsertItemAsync()\n        {\n            var expression = \"attribute_not_exists(PartitionKey) AND attribute_not_exists(RowKey)\";\n            var toPersist = GenerateNewData();\n            toPersist.StringData = \"Create\";\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true), expression);\n\n            toPersist.StringData = \"Replaced\";            \n            await manager.UpsertEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), GetValues(toPersist));\n            var persisted = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), response => new UnitTestDynamoDBTableData(response));\n            Assert.Equal(\"Replaced\", persisted.StringData);\n            Assert.True(persisted.ETag == 0); //Yes, ETag didn't changed cause we didn't \n\n            persisted.StringData = \"Updated\";\n            var persistedEtag = persisted.ETag;\n            expression = $\"ETag = :OldETag\";\n            persisted.ETag++; //Increase ETag\n            var expValues = new Dictionary<string, AttributeValue> { { \":OldETag\", new AttributeValue { N = persistedEtag.ToString() } } };\n            await manager.UpsertEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(persisted), GetValues(persisted), expression, expValues);\n            persisted = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), response => new UnitTestDynamoDBTableData(response));\n            Assert.Equal(\"Updated\", persisted.StringData);\n            Assert.NotEqual(persistedEtag, persisted.ETag); //Now ETag changed cause we did it\n\n            await Assert.ThrowsAsync<ConditionalCheckFailedException>(async () =>\n            {\n                await manager.UpsertEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), GetValues(toPersist), expression, expValues);\n            });\n        }\n\n        [SkippableFact,  TestCategory(\"Functional\")]\n        public async Task DynamoDBDataManager_DeleteItemAsync()\n        {\n            var toPersist = GenerateNewData();\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true));\n            await manager.DeleteEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist));\n            var persisted = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), response => new UnitTestDynamoDBTableData(response));\n            Assert.Null(persisted);\n        }\n\n        [SkippableFact,  TestCategory(\"Functional\")]\n        public async Task DynamoDBDataManager_ReadSingleTableEntryAsync()\n        {\n            var toPersist = GenerateNewData();\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true));\n            var persisted = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(toPersist), response => new UnitTestDynamoDBTableData(response));\n            Assert.NotNull(persisted);\n\n            var data = GenerateNewData();\n            var notFound = await manager.ReadSingleEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetKeys(data), response => new UnitTestDynamoDBTableData(response));\n            Assert.Null(notFound);\n        }\n\n        [SkippableFact,  TestCategory(\"Functional\")]\n        public async Task DynamoDBDataManager_ReadAllTableEntryByPartitionAsync()\n        {\n            var toPersist = GenerateNewData();\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist, true));\n            var toPersist2 = toPersist.Clone();\n            toPersist2.RowKey += \"otherKey\";\n            await manager.PutEntryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, GetValues(toPersist2, true));\n            var keys = new Dictionary<string, AttributeValue> { { \":PK\", new AttributeValue(toPersist.PartitionKey) } };\n            var found = await manager.QueryAsync(UnitTestDynamoDBStorage.INSTANCE_TABLE_NAME, keys, $\"PartitionKey = :PK\", item => new UnitTestDynamoDBTableData(item));\n            Assert.NotNull(found.results);\n            Assert.True(found.results.Count == 2);\n        }\n        \n        internal static Dictionary<string, AttributeValue> GetKeys(UnitTestDynamoDBTableData data)\n        {\n            var keys = new Dictionary<string, AttributeValue>();\n            keys.Add(\"PartitionKey\", new AttributeValue(data.PartitionKey));\n            keys.Add(\"RowKey\", new AttributeValue(data.RowKey));\n            return keys;\n        }\n\n        internal static Dictionary<string, AttributeValue> GetValues(UnitTestDynamoDBTableData data, bool includeKeys = false)\n        {\n            var values = new Dictionary<string, AttributeValue>();\n            if (!string.IsNullOrWhiteSpace(data.StringData))\n            {\n                values.Add(\"StringData\", new AttributeValue(data.StringData)); \n            }\n            if (data.BinaryData != null && data.BinaryData.Length > 0)\n            {\n                values.Add(\"BinaryData\", new AttributeValue { B = new MemoryStream(data.BinaryData) }); \n            }\n\n            if (includeKeys)\n            {\n                values.Add(\"PartitionKey\", new AttributeValue(data.PartitionKey));\n                values.Add(\"RowKey\", new AttributeValue(data.RowKey));\n            }\n\n            values.Add(\"ETag\", new AttributeValue { N = data.ETag.ToString() });\n            return values;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/PersistenceGrainTests_AWSDynamoDBStore.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing TesterInternal;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Orleans.Storage.DynamoDBGrainStorage;\nusing TestExtensions.Runners;\n\nnamespace AWSUtils.Tests.StorageTests\n{\n    /// <summary>\n    /// Tests DynamoDB storage provider for grain persistence including serialization of grain references.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"AWS\"), TestCategory(\"DynamoDb\")]\n    public class PersistenceGrainTests_AWSDynamoDBStore : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_AWSDynamoDBStore.Fixture>\n    {\n        public class Fixture : TestExtensions.BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                if (AWSTestConstants.IsDynamoDbAvailable)\n                {\n                    builder.Options.InitialSilosCount = 4;\n                    builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n                }\n            }\n\n            public class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddMemoryGrainStorage(\"MemoryStore\");\n                    hostBuilder.AddMemoryGrainStorage(\"test1\");\n                    hostBuilder.AddDynamoDBGrainStorage(\"GrainStorageForTest\", options => options.Service = AWSTestConstants.DynamoDbService);\n                }\n            }\n        }\n\n        public PersistenceGrainTests_AWSDynamoDBStore(ITestOutputHelper output, Fixture fixture) : base(output, fixture, grainNamespace: \"UnitTests.Grains\")\n        {\n            if (!AWSTestConstants.IsDynamoDbAvailable)\n            {\n                output.WriteLine(\"Unable to connect to AWS DynamoDB simulator\");\n                throw new SkipException(\"Unable to connect to AWS DynamoDB simulator\");\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AWSDynamoDBStore_ConvertToFromStorageFormat_GrainReference()\n        {\n            // NOTE: This test requires Silo to be running & Client init so that grain references can be resolved before serialization.\n            Guid id = Guid.NewGuid();\n            IUser grain = this.HostedCluster.GrainFactory.GetGrain<IUser>(id);\n\n            var initialState = new GrainStateContainingGrainReferences { Grain = grain };\n            var entity = new GrainStateRecord();\n            var storage = await InitDynamoDBTableStorageProvider(\n                this.HostedCluster.ServiceProvider.GetRequiredService<IProviderRuntime>(), \"TestTable\");\n            storage.ConvertToStorageFormat(initialState, entity);\n            var convertedState = storage.ConvertFromStorageFormat<GrainStateContainingGrainReferences>(entity);\n            Assert.NotNull(convertedState); // Converted state\n            Assert.Equal(initialState.Grain, convertedState.Grain);  // \"Grain\"\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AWSDynamoDBStore_ConvertToFromStorageFormat_GrainReference_List()\n        {\n            // NOTE: This test requires Silo to be running & Client init so that grain references can be resolved before serialization.\n            Guid[] ids = { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };\n            IUser[] grains = new IUser[3];\n            grains[0] = this.HostedCluster.GrainFactory.GetGrain<IUser>(ids[0]);\n            grains[1] = this.HostedCluster.GrainFactory.GetGrain<IUser>(ids[1]);\n            grains[2] = this.HostedCluster.GrainFactory.GetGrain<IUser>(ids[2]);\n\n            var initialState = new GrainStateContainingGrainReferences();\n            foreach (var g in grains)\n            {\n                initialState.GrainList.Add(g);\n                initialState.GrainDict.Add(g.GetPrimaryKey().ToString(), g);\n            }\n            var entity = new GrainStateRecord();\n            var storage =\n                await InitDynamoDBTableStorageProvider(\n                    this.HostedCluster.ServiceProvider.GetRequiredService<IProviderRuntime>(), \"TestTable\");\n            storage.ConvertToStorageFormat(initialState, entity);\n            var convertedState = storage.ConvertFromStorageFormat<GrainStateContainingGrainReferences>(entity);\n            Assert.NotNull(convertedState);\n            Assert.Equal(initialState.GrainList.Count, convertedState.GrainList.Count);  // \"GrainList size\"\n            Assert.Equal(initialState.GrainDict.Count, convertedState.GrainDict.Count);  // \"GrainDict size\"\n            for (int i = 0; i < grains.Length; i++)\n            {\n                string iStr = ids[i].ToString();\n                Assert.Equal(initialState.GrainList[i], convertedState.GrainList[i]);  // \"GrainList #{0}\", i\n                Assert.Equal(initialState.GrainDict[iStr], convertedState.GrainDict[iStr]);  // \"GrainDict #{0}\", i\n            }\n            Assert.Equal(initialState.Grain, convertedState.Grain);  // \"Grain\"\n        }\n\n        private static async Task<DynamoDBGrainStorage> InitDynamoDBTableStorageProvider(IProviderRuntime runtime, string storageName)\n        {\n            var options = new DynamoDBStorageOptions();\n            options.Service = AWSTestConstants.DynamoDbService;\n            options.GrainStorageSerializer = ActivatorUtilities.CreateInstance<OrleansGrainStorageSerializer>(runtime.ServiceProvider);\n\n            DynamoDBGrainStorage store = ActivatorUtilities.CreateInstance<DynamoDBGrainStorage>(runtime.ServiceProvider, \"PersistenceGrainTests\", options);\n            ISiloLifecycleSubject lifecycle = ActivatorUtilities.CreateInstance<SiloLifecycleSubject>(runtime.ServiceProvider, NullLogger<SiloLifecycleSubject>.Instance);\n            store.Participate(lifecycle);\n            await lifecycle.OnStart();\n            return store;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/StorageTests/UnitTestDynamoDBStorage.cs",
    "content": "using Amazon.DynamoDBv2;\nusing Amazon.DynamoDBv2.Model;\nusing System.Text;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.AWSUtils.Tests;\n\nnamespace AWSUtils.Tests.StorageTests\n{\n    /// <summary>\n    /// Test data model for DynamoDB storage unit tests.\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    internal class UnitTestDynamoDBTableData\n    {\n        private const string DATA_FIELD = \"Data\";\n        private const string STRING_DATA_FIELD = \"StringData\";\n\n        [Orleans.Id(0)]\n        public string PartitionKey { get; set; }\n        [Orleans.Id(1)]\n        public string RowKey { get; set; }\n        [Orleans.Id(2)]\n        public int ETag { get; set; }\n        [Orleans.Id(3)]\n        public byte[] BinaryData { get; set; }\n\n        [Orleans.Id(4)]\n        public string StringData { get; set; }\n\n        public UnitTestDynamoDBTableData()\n        {\n\n        }\n\n        public UnitTestDynamoDBTableData(Dictionary<string, AttributeValue> fields)\n        {\n            if (fields.ContainsKey(\"PartitionKey\"))\n            {\n                PartitionKey = fields[\"PartitionKey\"].S;\n            }\n\n            if (fields.ContainsKey(\"RowKey\"))\n            {\n                RowKey = fields[\"RowKey\"].S;\n            }\n\n            if (fields.ContainsKey(\"StringData\"))\n            {\n                StringData = fields[\"StringData\"].S;\n            }\n\n            if (fields.ContainsKey(\"ETag\"))\n            {\n                ETag = int.Parse(fields[\"ETag\"].N);\n            }\n\n            if (fields.ContainsKey(\"BinaryData\"))\n            {\n                BinaryData = fields[\"BinaryData\"].B?.ToArray();\n            }\n        }\n\n        public UnitTestDynamoDBTableData(string data, string partitionKey, string rowKey)\n        {\n            StringData = data;\n            PartitionKey = partitionKey;\n            RowKey = rowKey;\n        }\n\n        public UnitTestDynamoDBTableData Clone()\n        {\n            return new UnitTestDynamoDBTableData\n            {\n                StringData = this.StringData,\n                PartitionKey = this.PartitionKey,\n                RowKey = this.RowKey\n            };\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder();\n            sb.Append(\"UnitTestDDBData[\");\n            sb.Append(\" PartitionKey=\").Append(PartitionKey);\n            sb.Append(\" RowKey=\").Append(RowKey);\n            sb.Append(\" ETag=\").Append(ETag);\n            sb.Append(\" ]\");\n            return sb.ToString();\n        }\n    }\n\n    /// <summary>\n    /// Test implementation of DynamoDB storage for unit testing DynamoDB operations.\n    /// </summary>\n    internal class UnitTestDynamoDBStorage : DynamoDBStorage\n    {\n        public const string INSTANCE_TABLE_NAME = \"UnitTestDDBTableData\";\n\n        public UnitTestDynamoDBStorage()\n            : base(NullLoggerFactory.Instance.CreateLogger(\"DynamoDBStorage\"), AWSTestConstants.DynamoDbService)\n        {\n            if (AWSTestConstants.IsDynamoDbAvailable)\n            {\n                InitializeTable(INSTANCE_TABLE_NAME,\n                               new List<KeySchemaElement>\n                               {\n                    new KeySchemaElement { AttributeName = \"PartitionKey\", KeyType = KeyType.HASH },\n                    new KeySchemaElement { AttributeName = \"RowKey\", KeyType = KeyType.RANGE }\n                               },\n                               new List<AttributeDefinition>\n                               {\n                    new AttributeDefinition { AttributeName = \"PartitionKey\", AttributeType = ScalarAttributeType.S },\n                    new AttributeDefinition { AttributeName = \"RowKey\", AttributeType = ScalarAttributeType.S }\n                               }).Wait();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Streaming/SQSAdapterTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Globalization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Streams;\nusing OrleansAWSUtils.Streams;\nusing AWSUtils.Tests.StorageTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing OrleansAWSUtils.Storage;\nusing Orleans.Configuration;\n\nnamespace AWSUtils.Tests.Streaming\n{\n    /// <summary>\n    /// Tests SQS queue adapter functionality for sending and receiving messages through Orleans streaming.\n    /// </summary>\n    [TestCategory(\"AWS\"), TestCategory(\"SQS\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class SQSAdapterTests : IAsyncLifetime\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n        private const int NumBatches = 20;\n        private const int NumMessagesPerBatch = 20;\n        private readonly string clusterId;\n        public static readonly string SQS_STREAM_PROVIDER_NAME = \"SQSAdapterTests\";\n\n        public SQSAdapterTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            if (!AWSTestConstants.IsSqsAvailable)\n            {\n                throw new SkipException(\"Empty connection string\");\n            }\n\n            this.output = output;\n            this.fixture = fixture;\n            this.clusterId = MakeClusterId();\n        }\n\n        public Task InitializeAsync() => Task.CompletedTask;\n\n        public async Task DisposeAsync()\n        {\n            if (!string.IsNullOrWhiteSpace(AWSTestConstants.SqsConnectionString))\n            {\n                await SQSStreamProviderUtils.DeleteAllUsedQueues(\n                    SQS_STREAM_PROVIDER_NAME,\n                    this.clusterId,\n                    AWSTestConstants.SqsConnectionString,\n                    NullLoggerFactory.Instance);\n            }\n        }\n\n        [SkippableFact]\n        public async Task SendAndReceiveFromSQS()\n        {\n            var options = new SqsOptions\n            {\n                ConnectionString = AWSTestConstants.SqsConnectionString,\n            };\n\n            // Create a service collection to build a serializer\n            var serviceProvider = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            var serializer = serviceProvider.GetRequiredService<Serializer>();\n\n            var adapterFactory = new SQSAdapterFactory(SQS_STREAM_PROVIDER_NAME, options, new HashRingStreamQueueMapperOptions(), new SimpleQueueCacheOptions(), Options.Create(new ClusterOptions()), serializer, NullLoggerFactory.Instance);\n            adapterFactory.Init();\n            await SendAndReceiveFromQueueAdapter(adapterFactory);\n        }\n\n        private async Task SendAndReceiveFromQueueAdapter(IQueueAdapterFactory adapterFactory)\n        {\n            IQueueAdapter adapter = await adapterFactory.CreateAdapter();\n            IQueueAdapterCache cache = adapterFactory.GetQueueAdapterCache();\n\n            // Create receiver per queue\n            IStreamQueueMapper mapper = adapterFactory.GetStreamQueueMapper();\n            Dictionary<QueueId, IQueueAdapterReceiver> receivers = mapper.GetAllQueues().ToDictionary(queueId => queueId, adapter.CreateReceiver);\n            Dictionary<QueueId, IQueueCache> caches = mapper.GetAllQueues().ToDictionary(queueId => queueId, cache.CreateQueueCache);\n\n            await Task.WhenAll(receivers.Values.Select(receiver => receiver.Initialize(TimeSpan.FromSeconds(5))));\n\n            // test using 2 streams\n            Guid streamId1 = Guid.NewGuid();\n            Guid streamId2 = Guid.NewGuid();\n\n            int receivedBatches = 0;\n            var streamsPerQueue = new ConcurrentDictionary<QueueId, HashSet<StreamId>>();\n\n            // reader threads (at most 2 active queues because only two streams)\n            var work = new List<Task>();\n            foreach (KeyValuePair<QueueId, IQueueAdapterReceiver> receiverKvp in receivers)\n            {\n                QueueId queueId = receiverKvp.Key;\n                var receiver = receiverKvp.Value;\n                var qCache = caches[queueId];\n                Task task = Task.Factory.StartNew(() =>\n                {\n                    while (receivedBatches < NumBatches)\n                    {\n                        var messages = receiver.GetQueueMessagesAsync(SQSStorage.MAX_NUMBER_OF_MESSAGE_TO_PEEK).Result.ToArray();\n                        if (!messages.Any())\n                        {\n                            continue;\n                        }\n                        foreach (var message in messages.Cast<SQSBatchContainer>())\n                        {\n                            streamsPerQueue.AddOrUpdate(queueId,\n                                id => new HashSet<StreamId> { message.StreamId },\n                                (id, set) =>\n                                {\n                                    set.Add(message.StreamId);\n                                    return set;\n                                });\n                            output.WriteLine(\"Queue {0} received message on stream {1}\", queueId,\n                                message.StreamId);\n                            Assert.Equal(NumMessagesPerBatch / 2, message.GetEvents<int>().Count());  // \"Half the events were ints\"\n                            Assert.Equal(NumMessagesPerBatch / 2, message.GetEvents<string>().Count());  // \"Half the events were strings\"\n                        }\n                        Interlocked.Add(ref receivedBatches, messages.Length);\n                        qCache.AddToCache(messages);\n                    }\n                });\n                work.Add(task);\n            }\n\n            // send events\n            List<object> events = CreateEvents(NumMessagesPerBatch);\n            work.Add(Task.Factory.StartNew(() => Enumerable.Range(0, NumBatches)\n                .Select(i => i % 2 == 0 ? streamId1 : streamId2)\n                .ToList()\n                .ForEach(streamId =>\n                    adapter.QueueMessageBatchAsync(StreamId.Create(streamId.ToString(), streamId),\n                        events.Take(NumMessagesPerBatch).ToArray(), null, RequestContextExtensions.Export(this.fixture.DeepCopier)).Wait())));\n            await Task.WhenAll(work);\n\n            // Make sure we got back everything we sent\n            Assert.Equal(NumBatches, receivedBatches);\n\n            // check to see if all the events are in the cache and we can enumerate through them\n            StreamSequenceToken firstInCache = new EventSequenceTokenV2(0);\n            foreach (KeyValuePair<QueueId, HashSet<StreamId>> kvp in streamsPerQueue)\n            {\n                var receiver = receivers[kvp.Key];\n                var qCache = caches[kvp.Key];\n\n                foreach (StreamId streamGuid in kvp.Value)\n                {\n                    // read all messages in cache for stream\n                    IQueueCacheCursor cursor = qCache.GetCacheCursor(streamGuid, firstInCache);\n                    int messageCount = 0;\n                    StreamSequenceToken tenthInCache = null;\n                    StreamSequenceToken lastToken = firstInCache;\n                    while (cursor.MoveNext())\n                    {\n                        Exception ex;\n                        messageCount++;\n                        IBatchContainer batch = cursor.GetCurrent(out ex);\n                        output.WriteLine(\"Token: {0}\", batch.SequenceToken);\n                        Assert.True(batch.SequenceToken.CompareTo(lastToken) >= 0, $\"order check for event {messageCount}\");\n                        lastToken = batch.SequenceToken;\n                        if (messageCount == 10)\n                        {\n                            tenthInCache = batch.SequenceToken;\n                        }\n                    }\n                    output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount, streamGuid);\n                    Assert.Equal(NumBatches / 2, messageCount);\n                    Assert.NotNull(tenthInCache);\n\n                    // read all messages from the 10th\n                    cursor = qCache.GetCacheCursor(streamGuid, tenthInCache);\n                    messageCount = 0;\n                    while (cursor.MoveNext())\n                    {\n                        messageCount++;\n                    }\n                    output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount, streamGuid);\n                    const int expected = NumBatches / 2 - 10 + 1; // all except the first 10, including the 10th (10 + 1)\n                    Assert.Equal(expected, messageCount);\n                }\n            }\n        }\n\n        private static List<object> CreateEvents(int count)\n        {\n            return Enumerable.Range(0, count).Select(i =>\n            {\n                if (i % 2 == 0)\n                {\n                    return Random.Shared.Next(int.MaxValue) as object;\n                }\n                return Random.Shared.Next(int.MaxValue).ToString(CultureInfo.InvariantCulture);\n            }).ToList();\n        }\n\n        internal static string MakeClusterId()\n        {\n            const string DeploymentIdFormat = \"cluster-{0}\";\n            string now = DateTime.UtcNow.ToString(\"yyyy-MM-dd-hh-mm-ss-ffff\");\n            return string.Format(DeploymentIdFormat, now);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Streaming/SQSClientStreamTests.cs",
    "content": "using AWSUtils.Tests.StorageTests;\nusing Orleans.TestingHost;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing OrleansAWSUtils.Streams;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\n\nnamespace AWSUtils.Tests.Streaming\n{\n    /// <summary>\n    /// Tests SQS streaming functionality from Orleans client perspective including producer dropout scenarios.\n    /// </summary>\n    public class SQSClientStreamTests : TestClusterPerTest\n    {\n        private const string SQSStreamProviderName = \"SQSProvider\";\n        private const string StreamNamespace = \"SQSSubscriptionMultiplicityTestsNamespace\";\n        private readonly string StorageConnectionString = AWSTestConstants.SqsConnectionString;\n\n        private readonly ITestOutputHelper output;\n        private ClientStreamTestRunner runner;\n\n        public SQSClientStreamTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new ClientStreamTestRunner(this.HostedCluster);\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            if (!AWSTestConstants.IsSqsAvailable)\n            {\n                throw new SkipException(\"Empty connection string\");\n            }\n\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddSqsStreams(SQSStreamProviderName, options => \n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    })\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddSqsStreams(SQSStreamProviderName, (Action<SqsOptions>)(options =>\n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    }));\n            }\n        }\n\n        public override async Task DisposeAsync()\n        {\n            var clusterId = HostedCluster.Options.ClusterId;\n            await base.DisposeAsync();\n            if (!string.IsNullOrWhiteSpace(StorageConnectionString))\n            {\n                await SQSStreamProviderUtils.DeleteAllUsedQueues(SQSStreamProviderName, clusterId, StorageConnectionString, NullLoggerFactory.Instance);\n            }\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSStreamProducerOnDroppedClientTest()\n        {\n            logger.LogInformation(\"************************ AQStreamProducerOnDroppedClientTest *********************************\");\n            await runner.StreamProducerOnDroppedClientTest(SQSStreamProviderName, StreamNamespace);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Streaming/SQSStreamTests.cs",
    "content": "using AWSUtils.Tests.StorageTests;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing TestExtensions;\nusing UnitTests.Streaming;\nusing OrleansAWSUtils.Streams;\n\nnamespace AWSUtils.Tests.Streaming\n{\n    /// <summary>\n    /// Tests SQS streaming provider with various producer/consumer configurations between grains and clients.\n    /// </summary>\n    [TestCategory(\"AWS\"), TestCategory(\"SQS\")]\n    public class SQSStreamTests : TestClusterPerTest\n    {\n        public static readonly string SQS_STREAM_PROVIDER_NAME = \"SQSProvider\";\n\n        private SingleStreamTestRunner runner;\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            if (!AWSTestConstants.IsSqsAvailable)\n            {\n                throw new SkipException(\"Empty connection string\");\n            }\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddSqsStreams(\"SQSProvider\", options =>\n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    })\n                    .AddSqsStreams(\"SQSProvider2\", options =>\n                     {\n                         options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                     })\n                    .AddDynamoDBGrainStorage(\"DynamoDBStore\", options =>\n                    {\n                        options.Service = AWSTestConstants.DynamoDbService;\n                        options.SecretKey = AWSTestConstants.DynamoDbSecretKey;\n                        options.AccessKey = AWSTestConstants.DynamoDbAccessKey;\n                        options.DeleteStateOnClear = true;\n                    })\n                    .AddDynamoDBGrainStorage(\"PubSubStore\", options =>\n                    {\n                        options.Service = AWSTestConstants.DynamoDbService;\n                        options.SecretKey = AWSTestConstants.DynamoDbSecretKey;\n                        options.AccessKey = AWSTestConstants.DynamoDbAccessKey;\n                    })\n                    .AddMemoryGrainStorage(\"MemoryStore\", op=>op.NumStorageGrains = 1);\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddSqsStreams(\"SQSProvider\", (System.Action<Orleans.Configuration.SqsOptions>)(options =>\n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    }));\n            }\n        }\n        \n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new SingleStreamTestRunner(this.InternalClient, SQS_STREAM_PROVIDER_NAME);\n        }\n\n        public override async Task DisposeAsync()\n        {\n            var clusterId = HostedCluster.Options.ClusterId;\n            await base.DisposeAsync();\n            if (!string.IsNullOrWhiteSpace(AWSTestConstants.SqsConnectionString))\n            {\n                SQSStreamProviderUtils.DeleteAllUsedQueues(SQS_STREAM_PROVIDER_NAME, clusterId, AWSTestConstants.SqsConnectionString, NullLoggerFactory.Instance).Wait();\n            }\n        }\n\n        ////------------------------ One to One ----------------------//\n\n        [SkippableFact]\n        public async Task SQS_01_OneProducerGrainOneConsumerGrain()\n        {\n            await runner.StreamTest_01_OneProducerGrainOneConsumerGrain();\n        }\n\n        [SkippableFact]\n        public async Task SQS_02_OneProducerGrainOneConsumerClient()\n        {\n            await runner.StreamTest_02_OneProducerGrainOneConsumerClient();\n        }\n\n        [SkippableFact]\n        public async Task SQS_03_OneProducerClientOneConsumerGrain()\n        {\n            await runner.StreamTest_03_OneProducerClientOneConsumerGrain();\n        }\n\n        [SkippableFact]\n        public async Task SQS_04_OneProducerClientOneConsumerClient()\n        {\n            await runner.StreamTest_04_OneProducerClientOneConsumerClient();\n        }\n\n        //------------------------ MANY to Many different grains ----------------------//\n\n        [SkippableFact]\n        public async Task SQS_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n        {\n            await runner.StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact]\n        public async Task SQS_06_ManyDifferent_ManyProducerGrainManyConsumerClients()\n        {\n            await runner.StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients();\n        }\n\n        [SkippableFact]\n        public async Task SQS_07_ManyDifferent_ManyProducerClientsManyConsumerGrains()\n        {\n            await runner.StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains();\n        }\n\n        [SkippableFact]\n        public async Task SQS_08_ManyDifferent_ManyProducerClientsManyConsumerClients()\n        {\n            await runner.StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients();\n        }\n\n        //------------------------ MANY to Many Same grains ----------------------//\n        [SkippableFact]\n        public async Task SQS_09_ManySame_ManyProducerGrainsManyConsumerGrains()\n        {\n            await runner.StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact]\n        public async Task SQS_10_ManySame_ManyConsumerGrainsManyProducerGrains()\n        {\n            await runner.StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains();\n        }\n\n        [SkippableFact]\n        public async Task SQS_11_ManySame_ManyProducerGrainsManyConsumerClients()\n        {\n            await runner.StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients();\n        }\n\n        [SkippableFact]\n        public async Task SQS_12_ManySame_ManyProducerClientsManyConsumerGrains()\n        {\n            await runner.StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains();\n        }\n\n        //------------------------ MANY to Many producer consumer same grain ----------------------//\n\n        [SkippableFact]\n        public async Task SQS_13_SameGrain_ConsumerFirstProducerLater()\n        {\n            await runner.StreamTest_13_SameGrain_ConsumerFirstProducerLater(false);\n        }\n\n        [SkippableFact]\n        public async Task SQS_14_SameGrain_ProducerFirstConsumerLater()\n        {\n            await runner.StreamTest_14_SameGrain_ProducerFirstConsumerLater(false);\n        }\n\n        //----------------------------------------------//\n\n        [SkippableFact]\n        public async Task SQS_15_ConsumeAtProducersRequest()\n        {\n            await runner.StreamTest_15_ConsumeAtProducersRequest();\n        }\n\n        [SkippableFact]\n        public async Task SQS_16_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n        {\n            var multiRunner = new MultipleStreamsTestRunner(this.InternalClient, SQS_STREAM_PROVIDER_NAME, 16, false);\n            await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact]\n        public async Task SQS_17_MultipleStreams_1J_ManyProducerGrainsManyConsumerGrains()\n        {\n            var multiRunner = new MultipleStreamsTestRunner(this.InternalClient, SQS_STREAM_PROVIDER_NAME, 17, false);\n            await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(\n                () => HostedCluster.StartAdditionalSilo());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AWS.Tests/Streaming/SQSSubscriptionMultiplicityTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Configuration;\nusing AWSUtils.Tests.StorageTests;\nusing Microsoft.Extensions.Logging;\nusing Xunit;\nusing Orleans.TestingHost;\nusing OrleansAWSUtils.Streams;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\n\nnamespace AWSUtils.Tests.Streaming\n{\n    /// <summary>\n    /// Tests multiple subscription scenarios for SQS streams including parallel, linear, and resubscription patterns.\n    /// </summary>\n    public class SQSSubscriptionMultiplicityTests : TestClusterPerTest\n    {\n        private const string SQSStreamProviderName = \"SQSProvider\";\n        private const string StreamNamespace = \"SQSSubscriptionMultiplicityTestsNamespace\";\n        private readonly string StreamConnectionString = AWSTestConstants.SqsConnectionString;\n        private SubscriptionMultiplicityTestRunner runner;\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            if (!AWSTestConstants.IsSqsAvailable)\n            {\n                throw new SkipException(\"Empty connection string\");\n            }\n\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddSqsStreams(SQSStreamProviderName, (Action<Orleans.Configuration.SqsOptions>)(options =>\n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    }));\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddSqsStreams(SQSStreamProviderName, (Action<Orleans.Configuration.SqsOptions>)(options =>\n                    {\n                        options.ConnectionString = AWSTestConstants.SqsConnectionString;\n                    }));\n            }\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new SubscriptionMultiplicityTestRunner(SQSStreamProviderName, this.HostedCluster);\n        }\n\n        public override async Task DisposeAsync()\n        {\n            var clusterId = HostedCluster.Options.ClusterId;\n            await base.DisposeAsync();\n            if (!string.IsNullOrWhiteSpace(StreamConnectionString))\n            {\n                await SQSStreamProviderUtils.DeleteAllUsedQueues(SQSStreamProviderName, clusterId, StreamConnectionString, NullLoggerFactory.Instance);\n            }\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSMultipleParallelSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ SQSMultipleParallelSubscriptionTest *********************************\");\n            await runner.MultipleParallelSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSMultipleLinearSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ SQSMultipleLinearSubscriptionTest *********************************\");\n            await runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSMultipleSubscriptionTest_AddRemove()\n        {\n            logger.LogInformation(\"************************ SQSMultipleSubscriptionTest_AddRemove *********************************\");\n            await runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSResubscriptionTest()\n        {\n            logger.LogInformation(\"************************ SQSResubscriptionTest *********************************\");\n            await runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSResubscriptionAfterDeactivationTest()\n        {\n            logger.LogInformation(\"************************ ResubscriptionAfterDeactivationTest *********************************\");\n            await runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSActiveSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ SQSActiveSubscriptionTest *********************************\");\n            await runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSTwoIntermitentStreamTest()\n        {\n            logger.LogInformation(\"************************ SQSTwoIntermitentStreamTest *********************************\");\n            await runner.TwoIntermitentStreamTest(Guid.NewGuid());\n        }\n\n        [SkippableFact, TestCategory(\"AWS\")]\n        public async Task SQSSubscribeFromClientTest()\n        {\n            logger.LogInformation(\"************************ SQSSubscribeFromClientTest *********************************\");\n            await runner.SubscribeFromClientTest(Guid.NewGuid(), StreamNamespace);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace Tester.SQLUtils\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides ADO.NET and SQL database specific test environment setup.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Fakes/FakeHostApplicationLifetime.cs",
    "content": "using Microsoft.Extensions.Hosting;\n\nnamespace Tester.AdoNet.Fakes;\n\n/// <summary>\n/// A fake implementation of <see cref=\"IHostApplicationLifetime\"/> for unit test use.\n/// </summary>\ninternal sealed class FakeHostApplicationLifetime : IHostApplicationLifetime\n{\n    private readonly CancellationTokenSource _applicationStarted = new();\n    private readonly CancellationTokenSource _applicationStopping = new();\n    private readonly CancellationTokenSource _applicationStopped = new();\n\n    public CancellationToken ApplicationStarted => _applicationStarted.Token;\n\n    public CancellationToken ApplicationStopping => _applicationStopping.Token;\n\n    public CancellationToken ApplicationStopped => _applicationStopped.Token;\n\n    public void StartApplication() => _applicationStarted.Cancel();\n\n    public void StopApplication()\n    {\n        _applicationStopping.Cancel();\n        _applicationStopped.Cancel();\n    }\n\n    public void Dispose()\n    {\n        _applicationStarted.Dispose();\n        _applicationStopping.Dispose();\n        _applicationStopped.Dispose();\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/GrainDirectory/AdoNetGrainDirectoryClusterTests.cs",
    "content": "using MySql.Data.MySqlClient;\nusing Npgsql;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing Tester.Directories;\nusing UnitTests.General;\nusing UnitTests.Grains.Directories;\nusing static System.String;\n\nnamespace Tester.AdoNet.GrainDirectory;\n\n/// <summary>\n/// Cluster tests for ADO.NET Grain Directory against SQL Server.\n/// </summary>\n[TestCategory(\"SqlServer\")]\npublic class SqlServerAdoNetGrainDirectoryClusterTests() : AdoNetGrainDirectoryClusterTests(AdoNetInvariants.InvariantNameSqlServer)\n{\n}\n\n/// <summary>\n/// Cluster tests for ADO.NET Grain Directory against PostgreSQL.\n/// </summary>\n[TestCategory(\"PostgreSql\")]\npublic class PostgreSqlAdoNetGrainDirectoryClusterTests : AdoNetGrainDirectoryClusterTests\n{\n    public PostgreSqlAdoNetGrainDirectoryClusterTests() : base(AdoNetInvariants.InvariantNamePostgreSql)\n    {\n        NpgsqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Cluster tests for ADO.NET Grain Directory against MySQL.\n/// </summary>\n[TestCategory(\"MySql\")]\npublic class MySqlAdoNetGrainDirectoryClusterTests : AdoNetGrainDirectoryClusterTests\n{\n    public MySqlAdoNetGrainDirectoryClusterTests() : base(AdoNetInvariants.InvariantNameMySql)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Cluster tests base class for ADO.NET Grain Directory.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"AdoNet\"), TestCategory(\"GrainDirectory\")]\npublic abstract class AdoNetGrainDirectoryClusterTests : MultipleGrainDirectoriesTests\n{\n    private const string TestDatabaseName = \"OrleansGrainDirectoryTest\";\n\n    private static RelationalStorageForTesting _testing;\n    private static string _invariant;\n\n    public AdoNetGrainDirectoryClusterTests(string invariant)\n    {\n        _invariant = invariant;\n    }\n\n    public override async Task InitializeAsync()\n    {\n        // set up the adonet environment before the base initializes\n        _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        // base initialization must only happen after the above\n        await base.InitializeAsync();\n    }\n\n    public class SiloConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n            siloBuilder.AddAdoNetGrainDirectory(CustomDirectoryGrain.DIRECTORY, options =>\n            {\n                options.Invariant = _invariant;\n                options.ConnectionString = _testing.CurrentConnectionString;\n            });\n        }\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        base.ConfigureTestCluster(builder);\n\n        builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/GrainDirectory/AdoNetGrainDirectoryTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing MySql.Data.MySqlClient;\nusing Npgsql;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory.AdoNet;\nusing Orleans.Tests.SqlUtils;\nusing Tester.AdoNet.Fakes;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.GrainDirectory;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetGrainDirectory\"/> against SQL Server.\n/// </summary>\n[TestCategory(\"SqlServer\")]\npublic class SqlServerAdoNetGrainDirectoryTests() : AdoNetGrainDirectoryTests(AdoNetInvariants.InvariantNameSqlServer, 90)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetGrainDirectory\"/> against PostgreSQL.\n/// </summary>\n[TestCategory(\"PostgreSql\")]\npublic class PostgreSqlAdoNetGrainDirectoryTests : AdoNetGrainDirectoryTests\n{\n    public PostgreSqlAdoNetGrainDirectoryTests() : base(AdoNetInvariants.InvariantNamePostgreSql, 90)\n    {\n        NpgsqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetGrainDirectory\"/> against MySQL.\n/// </summary>\n[TestCategory(\"MySql\")]\npublic class MySqlAdoNetGrainDirectoryTests : AdoNetGrainDirectoryTests\n{\n    public MySqlAdoNetGrainDirectoryTests() : base(AdoNetInvariants.InvariantNameMySql, 90)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetGrainDirectory\"/>.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"Functional\"), TestCategory(\"AdoNet\"), TestCategory(\"GrainDirectory\")]\npublic abstract class AdoNetGrainDirectoryTests(string invariant, int concurrency = 100) : IAsyncLifetime\n{\n    private RelationalStorageForTesting _testing;\n    private IRelationalStorage _storage;\n\n    private const string TestDatabaseName = \"OrleansGrainDirectoryTest\";\n\n    public async Task InitializeAsync()\n    {\n        _testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = _testing.Storage;\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n\n    /// <summary>\n    /// Tests that a grain activation is registered.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetGrainDirectory_RegistersActivation()\n    {\n        // arrange\n        var options = new AdoNetGrainDirectoryOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _testing.CurrentConnectionString\n        };\n        var logger = NullLogger<AdoNetGrainDirectory>.Instance;\n        var clusterOptions = Options.Create(new ClusterOptions\n        {\n            ClusterId = \"MyClusterId\"\n        });\n        var lifetime = new FakeHostApplicationLifetime();\n        var directory = new AdoNetGrainDirectory(\"MyProviderId\", options, logger, clusterOptions, lifetime);\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        // act\n        var address = new GrainAddress\n        {\n            GrainId = GrainId.Create(\"MyGrainType\", \"MyGrainKey\"),\n            SiloAddress = SiloAddress.New(IPEndPoint.Parse(\"127.0.0.1:11111\"), 123456),\n            ActivationId = ActivationId.NewId()\n        };\n        var result = await directory.Register(address);\n\n        // assert\n        Assert.NotNull(result);\n        Assert.Equal(address.GrainId, result.GrainId);\n        Assert.Equal(address.SiloAddress, result.SiloAddress);\n        Assert.Equal(address.ActivationId, result.ActivationId);\n\n        var saved = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        var entry = Assert.Single(saved);\n        Assert.Equal(\"MyClusterId\", entry.ClusterId);\n        Assert.Equal(\"MyProviderId\", entry.ProviderId);\n        Assert.Equal(address.GrainId.ToString(), entry.GrainId);\n        Assert.Equal(address.SiloAddress.ToParsableString(), entry.SiloAddress);\n        Assert.Equal(address.ActivationId.ToParsableString(), entry.ActivationId);\n    }\n\n    /// <summary>\n    /// Tests that a grain activation is unregistered.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetGrainDirectory_UnregistersActivation()\n    {\n        // arrange\n        var options = new AdoNetGrainDirectoryOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _testing.CurrentConnectionString\n        };\n        var logger = NullLogger<AdoNetGrainDirectory>.Instance;\n        var clusterOptions = Options.Create(new ClusterOptions\n        {\n            ClusterId = \"MyClusterId\"\n        });\n        var lifetime = new FakeHostApplicationLifetime();\n        var directory = new AdoNetGrainDirectory(\"MyProviderId\", options, logger, clusterOptions, lifetime);\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        var address = new GrainAddress\n        {\n            GrainId = GrainId.Create(\"MyGrainType\", \"MyGrainKey\"),\n            SiloAddress = SiloAddress.New(IPEndPoint.Parse(\"127.0.0.1:11111\"), 123456),\n            ActivationId = ActivationId.NewId()\n        };\n        await directory.Register(address);\n\n        // act\n        await directory.Unregister(address);\n\n        // assert\n        var saved = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        Assert.Empty(saved);\n    }\n\n    /// <summary>\n    /// Tests that a grain activation can be looked up.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetGrainDirectory_LooksUpActivation()\n    {\n        // arrange\n        var options = new AdoNetGrainDirectoryOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _testing.CurrentConnectionString\n        };\n        var logger = NullLogger<AdoNetGrainDirectory>.Instance;\n        var clusterOptions = Options.Create(new ClusterOptions\n        {\n            ClusterId = \"MyClusterId\"\n        });\n        var lifetime = new FakeHostApplicationLifetime();\n        var directory = new AdoNetGrainDirectory(\"MyProviderId\", options, logger, clusterOptions, lifetime);\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        var grainId = GrainId.Create(\"MyGrainType\", \"MyGrainKey\");\n        var siloAddress = SiloAddress.New(IPEndPoint.Parse(\"127.0.0.1:11111\"), 123456);\n        var activationId = ActivationId.NewId();\n        var address = new GrainAddress\n        {\n            GrainId = grainId,\n            SiloAddress = siloAddress,\n            ActivationId = activationId\n        };\n        await directory.Register(address);\n\n        // act\n        var result = await directory.Lookup(grainId);\n\n        // assert\n        Assert.NotNull(result);\n        Assert.Equal(grainId, result.GrainId);\n        Assert.Equal(siloAddress, result.SiloAddress);\n        Assert.Equal(activationId, result.ActivationId);\n    }\n\n    /// <summary>\n    /// Tests that grain activations can be unregistered for a set of silos.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetGrainDirectory_UnregistersActivationsForSilos()\n    {\n        // arrange\n        var options = new AdoNetGrainDirectoryOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _testing.CurrentConnectionString\n        };\n        var logger = NullLogger<AdoNetGrainDirectory>.Instance;\n        var clusterOptions = Options.Create(new ClusterOptions\n        {\n            ClusterId = \"MyClusterId\"\n        });\n        var lifetime = new FakeHostApplicationLifetime();\n        var directory = new AdoNetGrainDirectory(\"MyProviderId\", options, logger, clusterOptions, lifetime);\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        var grainIds = Enumerable.Range(0, 5).Select(i => GrainId.Create(\"MyGrainType\", $\"MyGrainKey{i}\")).ToArray();\n        var siloAddresses = Enumerable.Range(0, 5).Select(i => SiloAddress.New(IPEndPoint.Parse($\"127.0.0.{i}:11111\"), 123456)).ToArray();\n        var activationIds = Enumerable.Range(0, 5).Select(_ => ActivationId.NewId()).ToArray();\n        var addresses = Enumerable.Range(0, 5).Select(i => new GrainAddress\n        {\n            GrainId = grainIds[i],\n            SiloAddress = siloAddresses[i],\n            ActivationId = activationIds[i]\n        }).ToArray();\n\n        for (var i = 0; i < 5; i++)\n        {\n            await directory.Register(addresses[i]);\n        }\n\n        // act\n        await directory.UnregisterSilos([siloAddresses[0], siloAddresses[2], siloAddresses[4]]);\n\n        // assert\n        var results = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory ORDER BY GrainId\");\n        var resultAddresses = results.Select(entry => entry.ToGrainAddress()).ToArray();\n        Assert.Equal([addresses[1], addresses[3]], resultAddresses);\n    }\n\n    /// <summary>\n    /// Tests that a grain activation can be looked up.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetGrainDirectory_ChaosTest()\n    {\n        // arrange\n        var options = new AdoNetGrainDirectoryOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _testing.CurrentConnectionString\n        };\n        var logger = NullLogger<AdoNetGrainDirectory>.Instance;\n        var clusterOptions = Options.Create(new ClusterOptions\n        {\n            ClusterId = \"MyClusterId\"\n        });\n        var lifetime = new FakeHostApplicationLifetime();\n        var directory = new AdoNetGrainDirectory(\"MyProviderId\", options, logger, clusterOptions, lifetime);\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        // act\n        await Parallel.ForAsync(0, 10000, new ParallelOptions { MaxDegreeOfParallelism = concurrency }, async (i, ct) =>\n        {\n            var grainId = GrainId.Create(\"MyGrainType\", $\"MyGrainKey{Random.Shared.Next(10)}\");\n            var siloAddress = SiloAddress.New(IPEndPoint.Parse($\"127.0.0.{Random.Shared.Next(10)}:11111\"), 123456);\n            var activationId = ActivationId.NewId();\n            var address = new GrainAddress\n            {\n                GrainId = grainId,\n                SiloAddress = siloAddress,\n                ActivationId = activationId\n            };\n            var lookups = Random.Shared.Next(10);\n\n            // simulate the lifecycle including unstable overlapping operations\n            var registered = await directory.Register(address);\n            for (var j = 0; j < lookups; j++)\n            {\n                var result = await directory.Lookup(grainId);\n            }\n\n            // it is possible that the registration failed due to some other concurrent operation\n            if (registered is not null)\n            {\n                await directory.Unregister(registered);\n            }\n        });\n\n        // assert\n        var remaining = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        Assert.Empty(remaining);\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/GrainDirectory/RelationalOrleansQueriesTests.cs",
    "content": "using MySql.Data.MySqlClient;\nusing Npgsql;\nusing Orleans.GrainDirectory.AdoNet;\nusing Orleans.GrainDirectory.AdoNet.Storage;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.GrainDirectory;\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against Sql Server.\n/// </summary>\n[TestCategory(\"SqlServer\")]\npublic class SqlServerRelationalOrleansQueriesTests() : RelationalOrleansQueriesTests(AdoNetInvariants.InvariantNameSqlServer, 90)\n{\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against PostgreSQL.\n/// </summary>\n[TestCategory(\"PostgreSql\")]\npublic class PostgreSqlRelationalOrleansQueriesTests : RelationalOrleansQueriesTests\n{\n    public PostgreSqlRelationalOrleansQueriesTests() : base(AdoNetInvariants.InvariantNamePostgreSql, 90)\n    {\n        NpgsqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against MySQL.\n/// </summary>\n[TestCategory(\"MySql\")]\npublic class MySqlRelationalOrleansQueriesTests : RelationalOrleansQueriesTests\n{\n    public MySqlRelationalOrleansQueriesTests() : base(AdoNetInvariants.InvariantNameMySql, 90)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/>.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"AdoNet\"), TestCategory(\"GrainDirectory\")]\npublic abstract class RelationalOrleansQueriesTests(string invariant, int concurrency = 100) : IAsyncLifetime\n{\n    private const string TestDatabaseName = \"OrleansGrainDirectoryTest\";\n\n    private IRelationalStorage _storage;\n    private RelationalOrleansQueries _queries;\n\n    public async Task InitializeAsync()\n    {\n        var testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n        Skip.If(IsNullOrEmpty(testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = RelationalStorage.CreateInstance(invariant, testing.CurrentConnectionString);\n\n        _queries = await RelationalOrleansQueries.CreateInstance(invariant, testing.CurrentConnectionString);\n    }\n\n    private static string RandomClusterId(int max = 10) => $\"ClusterId{Random.Shared.Next(max)}\";\n\n    private static string RandomProviderId(int max = 10) => $\"ProviderId{Random.Shared.Next(max)}\";\n\n    private static string RandomGrainId(int max = 10) => $\"GrainId{Random.Shared.Next(max)}\";\n\n    private static string RandomSiloAddress(int max = 10) => $\"SiloAddress{Random.Shared.Next(max)}\";\n\n    private static string RandomActivationId(int max = 10) => $\"ActivationId{Random.Shared.Next(max)}\";\n\n    public Task DisposeAsync() => Task.CompletedTask;\n\n    /// <summary>\n    /// Tests that a grain activation is registered.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_RegistersActivation()\n    {\n        // arrange\n        var clusterId = RandomClusterId();\n        var providerId = RandomProviderId();\n        var grainId = RandomGrainId();\n        var siloAddress = RandomSiloAddress();\n        var activationId = RandomActivationId();\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        // act\n        var entry = await _queries.RegisterGrainActivationAsync(clusterId, providerId, grainId, siloAddress, activationId);\n\n        // assert\n        Assert.NotNull(entry);\n        Assert.Equal(clusterId, entry.ClusterId);\n        Assert.Equal(providerId, entry.ProviderId);\n        Assert.Equal(grainId, entry.GrainId);\n        Assert.Equal(siloAddress, entry.SiloAddress);\n        Assert.Equal(activationId, entry.ActivationId);\n\n        var results = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        var result = Assert.Single(results);\n        Assert.Equal(clusterId, result.ClusterId);\n        Assert.Equal(providerId, result.ProviderId);\n        Assert.Equal(grainId, result.GrainId);\n        Assert.Equal(siloAddress, result.SiloAddress);\n        Assert.Equal(activationId, result.ActivationId);\n    }\n\n    /// <summary>\n    /// Tests that a grain activation is unregistered.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_UnregistersActivation()\n    {\n        // arrange\n        var clusterId = RandomClusterId();\n        var providerId = RandomProviderId();\n        var grainId = RandomGrainId();\n        var siloAddress = RandomSiloAddress();\n        var activationId = RandomActivationId();\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        // act\n        var entry = await _queries.RegisterGrainActivationAsync(clusterId, providerId, grainId, siloAddress, activationId);\n        var count = await _queries.UnregisterGrainActivationAsync(clusterId, providerId, grainId, activationId);\n\n        // assert\n        Assert.NotNull(entry);\n        Assert.Equal(1, count);\n\n        var results = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        Assert.Empty(results);\n    }\n\n    /// <summary>\n    /// Tests that a grain activation can be looked up.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_LooksUpActivation()\n    {\n        // arrange\n        var clusterId = RandomClusterId();\n        var providerId = RandomProviderId();\n        var grainId = RandomGrainId();\n        var siloAddress = RandomSiloAddress();\n        var activationId = RandomActivationId();\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        // act\n        var entry = await _queries.RegisterGrainActivationAsync(clusterId, providerId, grainId, siloAddress, activationId);\n        var result = await _queries.LookupGrainActivationAsync(clusterId, providerId, grainId);\n\n        // assert\n        Assert.NotNull(entry);\n        Assert.NotNull(result);\n        Assert.Equal(clusterId, result.ClusterId);\n        Assert.Equal(providerId, result.ProviderId);\n        Assert.Equal(grainId, result.GrainId);\n        Assert.Equal(siloAddress, result.SiloAddress);\n        Assert.Equal(activationId, result.ActivationId);\n    }\n\n    /// <summary>\n    /// Tests that grain activations for a set of silos are unregistered.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_UnregistersActivationsForSilos()\n    {\n        // arrange\n        var clusterId = RandomClusterId();\n        var providerId = RandomProviderId();\n        var grainId = RandomGrainId();\n        var activationId = RandomActivationId();\n\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansGrainDirectory\");\n\n        await _queries.RegisterGrainActivationAsync(clusterId, providerId, \"G1\", \"A\", \"A1\");\n        await _queries.RegisterGrainActivationAsync(clusterId, providerId, \"G2\", \"B\", \"A2\");\n        await _queries.RegisterGrainActivationAsync(clusterId, providerId, \"G3\", \"C\", \"A3\");\n        await _queries.RegisterGrainActivationAsync(clusterId, providerId, \"G4\", \"D\", \"A4\");\n        await _queries.RegisterGrainActivationAsync(clusterId, providerId, \"G5\", \"E\", \"A5\");\n\n        // act\n        var count = await _queries.UnregisterGrainActivationsAsync(clusterId, providerId, \"A|C|E\");\n\n        // assert\n        Assert.Equal(3, count);\n\n        var remaining = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        Assert.Collection(remaining.OrderBy(x => x.GrainId),\n            entry => Assert.Equal(\"G2\", entry.GrainId),\n            entry => Assert.Equal(\"G4\", entry.GrainId));\n    }\n\n    /// <summary>\n    /// Chaos test for concurrent grain directory queries.\n    /// </summary>\n    /// <remarks>\n    /// This test looks for susceptibility to database deadlocks and other concurrency issues.\n    /// During development, this test consistently triggered deadlocking until the queries were made to prevent it.\n    /// If this test shows flakiness then it is likely the queries need to be looked at.\n    /// </remarks>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_ChaosTest()\n    {\n        var clusterId = RandomClusterId();\n        var providerId = RandomProviderId();\n\n        // act\n        await Parallel.ForAsync(0, 10000, new ParallelOptions { MaxDegreeOfParallelism = concurrency }, async (x, ct) =>\n        {\n            var grainId = RandomGrainId();\n            var siloAddress = RandomSiloAddress();\n            var activationId = RandomActivationId();\n            var randomLookups = Random.Shared.Next(10);\n\n            // simulate the lifecycle including unstable overlapping operations\n            await _queries.RegisterGrainActivationAsync(clusterId, providerId, grainId, siloAddress, activationId);\n            for (var i = 0; i < randomLookups; i++)\n            {\n                await _queries.LookupGrainActivationAsync(clusterId, providerId, grainId);\n            }\n            await _queries.UnregisterGrainActivationAsync(clusterId, providerId, grainId, activationId);\n        });\n\n        // assert\n        var remaining = await _storage.ReadAsync<AdoNetGrainDirectoryEntry>(\"SELECT * FROM OrleansGrainDirectory\");\n        Assert.Empty(remaining);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/LivenessTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing Orleans.TestingHost;\nusing UnitTests.General;\nusing Xunit.Abstractions;\nusing Microsoft.Extensions.Hosting;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for Orleans silo membership liveness functionality using SQL Server as the membership provider.\n    /// </summary>\n    [TestCategory(\"SqlServer\"), TestCategory(\"Functional\"), TestCategory(\"Membership\"), TestCategory(\"AdoNet\")]\n    public class LivenessTests_SqlServer : LivenessTestsBase\n    {\n        public const string TestDatabaseName = \"OrleansTest_SqlServer_Liveness\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNameSqlServer;\n        public LivenessTests_SqlServer(ITestOutputHelper output) : base(output)\n        {\n            EnsurePreconditionsMet();\n        }\n\n        protected override void CheckPreconditionsOrThrow() => RelationalStorageForTesting.CheckPreconditionsOrThrow(AdoNetInvariantName);\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).GetAwaiter().GetResult();\n            builder.Properties[\"RelationalStorageConnectionString\"] = relationalStorage.CurrentConnectionString;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var cfg = hostBuilder.GetConfiguration();\n                var connectionString = cfg[\"RelationalStorageConnectionString\"];\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseAdoNetClustering(options =>\n                    {\n                        options.ConnectionString = connectionString;\n                        options.Invariant = AdoNetInvariantName;\n                    });\n                });\n            }\n        }\n\n        [SkippableFact]\n        public async Task Liveness_SqlServer_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact]\n        public async Task Liveness_SqlServer_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_SqlServer_3_Restartl_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_SqlServer_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_SqlServer_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n\n    /// <summary>\n    /// Tests for Orleans silo membership liveness functionality using PostgreSQL as the membership provider.\n    /// </summary>\n    [TestCategory(\"PostgreSql\"), TestCategory(\"Functional\"), TestCategory(\"Membership\"), TestCategory(\"AdoNet\")]\n    public class LivenessTests_PostgreSql : LivenessTestsBase\n    {\n        public const string TestDatabaseName = \"OrleansTest_Postgres_Liveness\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNamePostgreSql;\n        public LivenessTests_PostgreSql(ITestOutputHelper output) : base(output)\n        {\n            EnsurePreconditionsMet();\n        }\n\n        protected override void CheckPreconditionsOrThrow() => RelationalStorageForTesting.CheckPreconditionsOrThrow(AdoNetInvariantName);\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).Result;\n            builder.Properties[\"RelationalStorageConnectionString\"] = relationalStorage.CurrentConnectionString;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var cfg = hostBuilder.GetConfiguration();\n                var connectionString = cfg[\"RelationalStorageConnectionString\"];\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseAdoNetClustering(options =>\n                    {\n                        options.ConnectionString = connectionString;\n                        options.Invariant = AdoNetInvariantName;\n                    });\n                });\n            }\n        }\n\n        [SkippableFact]\n        public async Task Liveness_PostgreSql_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact]\n        public async Task Liveness_PostgreSql_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_PostgreSql_3_Restartl_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_PostgreSql_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_PostgreSql_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n\n    /// <summary>\n    /// Tests for Orleans silo membership liveness functionality using MySQL as the membership provider.\n    /// </summary>\n    [TestCategory(\"MySql\"), TestCategory(\"Functional\"), TestCategory(\"Membership\"), TestCategory(\"AdoNet\")]\n    public class LivenessTests_MySql : LivenessTestsBase\n    {\n        public const string TestDatabaseName = \"OrleansTest_MySql_Liveness\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNamePostgreSql;\n        public LivenessTests_MySql(ITestOutputHelper output) : base(output)\n        {\n            EnsurePreconditionsMet();\n        }\n\n        protected override void CheckPreconditionsOrThrow() => RelationalStorageForTesting.CheckPreconditionsOrThrow(AdoNetInvariantName);\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).Result;\n            builder.Properties[\"RelationalStorageConnectionString\"] = relationalStorage.CurrentConnectionString;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var cfg = hostBuilder.GetConfiguration();\n                var connectionString = cfg[\"RelationalStorageConnectionString\"];\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseAdoNetClustering(options =>\n                    {\n                        options.ConnectionString = connectionString;\n                        options.Invariant = AdoNetInvariantName;\n                    });\n                });\n            }\n        }\n\n        [SkippableFact]\n        public async Task Liveness_MySql_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact]\n        public async Task Liveness_MySql_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_MySql_3_Restartl_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_MySql_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_MySql_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/MySqlMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for operation of Orleans Membership Table using MySQL\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"MySql\"), TestCategory(\"Functional\")]\n    public class MySqlMembershipTableTests : MembershipTableTestsBase\n    {\n        public MySqlMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        protected override string GetAdoInvariant() => AdoNetInvariants.InvariantNameMySql;\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(typeof(MySqlMembershipTableTests).Name, LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            var options = new AdoNetClusteringSiloOptions()\n            {\n                Invariant = GetAdoInvariant(),\n                ConnectionString = this.connectionString,\n            };\n            return new AdoNetClusteringTable(this.Services, this._clusterOptions, Options.Create(options), loggerFactory.CreateLogger<AdoNetClusteringTable>());\n        }\n\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new AdoNetClusteringClientOptions()\n            {\n                ConnectionString = this.connectionString,\n                Invariant = GetAdoInvariant()\n            };\n            return new AdoNetGatewayListProvider(loggerFactory.CreateLogger<AdoNetGatewayListProvider>(), this.Services, Options.Create(options), this._gatewayOptions, this._clusterOptions);\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void MembershipTable_MySql_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_MySql_CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Orleans.AdoNet.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <DefineConstants>$(DefineConstants);TESTER_SQLUTILS</DefineConstants>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Benchmarks.AdoNet\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Data.SqlClient\" />\n    <!--<PackageReference Include=\"MySqlConnector\" Version=\"1.2.1\" />-->\n    <PackageReference Include=\"Microsoft.Data.Sqlite\" />\n    <PackageReference Include=\"Npgsql\" />\n    <PackageReference Include=\"MySql.Data\" />\n    <PackageReference Include=\"System.Drawing.Common\" /> <!-- For some reason it's a dependency of MySql.Data. We want to force it to a specific version -->\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Include=\"$(SourceRoot)src\\AdoNet\\Shared\\Storage\\*.cs\" LinkBase=\"Storage\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\AdoNet\\Orleans.Clustering.AdoNet\\Orleans.Clustering.AdoNet.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AdoNet\\Orleans.Persistence.AdoNet\\Orleans.Persistence.AdoNet.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AdoNet\\Orleans.Reminders.AdoNet\\Orleans.Reminders.AdoNet.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Streaming.Tests\\Orleans.Streaming.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\AdoNet\\Orleans.Streaming.AdoNet\\Orleans.Streaming.AdoNet.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\AdoNet\\Orleans.GrainDirectory.AdoNet\\Orleans.GrainDirectory.AdoNet.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"$(SourceRoot)src\\AdoNet\\**\\*.sql\" Link=\"%(Filename)%(Extension)\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/PackageReferences.cs",
    "content": "using System.Data.Common;\n\nnamespace Tester.AdoNet\n{\n    internal static class PackageReferences\n    {\n        public static readonly DbProviderFactory[] Factories =\n        {\n            Microsoft.Data.SqlClient.SqlClientFactory.Instance,\n            MySql.Data.MySqlClient.MySqlClientFactory.Instance,\n            //Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance, // no tests currently\n            Npgsql.NpgsqlFactory.Instance,\n            Microsoft.Data.Sqlite.SqliteFactory.Instance,\n            //MySqlConnector.MySqlConnectorFactory.Instance, // no tests currently\n        };\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_MySql.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using MySQL as the storage provider.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"MySql\")]\n    public class PersistenceGrainTests_MySql : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_MySql.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_MySql_Storage\";\n        public const string AdoInvariant = AdoNetInvariants.InvariantNameMySql;\n        public const string ConnectionStringKey = \"AdoNetConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.MySqlConnectionString))\n                {\n                    throw new SkipException(\"MySQL connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_MySql(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_MySql_DeleteStateOnClear.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using MySQL\n    /// with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"MySql\")]\n    public class PersistenceGrainTests_MySql_DeleteStateOnClear : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_MySql_DeleteStateOnClear.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_MySql_Storage\";\n        public static string AdoInvariant = AdoNetInvariants.InvariantNameMySql;\n        public static string ConnectionStringKey = \"AdoNetConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.MySqlConnectionString))\n                {\n                    throw new SkipException(\"MySQL connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                                options.DeleteStateOnClear = true;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_MySql_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DeleteStateOnClear = true;\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_Postgres.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using PostgreSQL as the storage provider.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"PostgreSql\")]\n    public class PersistenceGrainTests_Postgres : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_Postgres.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_Postgres_Storage\";\n        public static string AdoInvariant = AdoNetInvariants.InvariantNamePostgreSql;\n        public static string ConnectionStringKey = \"AdoNetConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.PostgresConnectionString))\n                {\n                    throw new SkipException(\"Postgres connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_Postgres(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_Postgres_DeleteStateOnClear.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using PostgreSQL\n    /// with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"PostgreSql\")]\n    public class PersistenceGrainTests_Postgres_DeleteStateOnClear : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_Postgres_DeleteStateOnClear.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_Postgres_Storage\";\n        public static string AdoInvariant = AdoNetInvariants.InvariantNamePostgreSql;\n        public static string ConnectionStringKey = \"AdoNetConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.PostgresConnectionString))\n                {\n                    throw new SkipException(\"Postgres connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                                options.DeleteStateOnClear = true;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_Postgres_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DeleteStateOnClear = true;\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_SqlServer.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using SQL Server as the storage provider.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"SqlServer\")]\n    public class PersistenceGrainTests_SqlServer : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_SqlServer.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_SqlServer_Storage\";\n        public static string AdoInvariant = AdoNetInvariants.InvariantNameSqlServer;\n        public static string ConnectionStringKey = \"AdoNetConnectionString\";\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.MsSqlConnectionString))\n                {\n                    throw new SkipException(\"SQL Server connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_SqlServer(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/PersistenceGrainTests_SqlServer_DeleteStateOnClear.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.General;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    /// <summary>\n    /// Tests for Orleans grain state persistence functionality using SQL Server\n    /// with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"SqlServer\")]\n    public class PersistenceGrainTests_SqlServer_DeleteStateOnClear : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_SqlServer_DeleteStateOnClear.Fixture>\n    {\n        public const string TestDatabaseName = \"OrleansTest_SqlServer_Storage\";\n        public static string AdoInvariant = AdoNetInvariants.InvariantNameSqlServer;\n        public static string ConnectionStringKey = \"AdoNetConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                if (string.IsNullOrEmpty(TestDefaultConfiguration.MsSqlConnectionString))\n                {\n                    throw new SkipException(\"SQL Server connection string is not specified.\");\n                }\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                var relationalStorage = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName).Result;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, relationalStorage.CurrentConnectionString}\n                    }));\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddAdoNetGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConnectionString = connectionString;\n                                options.Invariant = AdoInvariant;\n                                options.DeleteStateOnClear = true;\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n        }\n\n        public PersistenceGrainTests_SqlServer_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            DeleteStateOnClear = true;\n            DistinguishesGenericGrainTypeParameters = false;\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/SqlitePersistenceGrainStorageFixture.cs",
    "content": "using Microsoft.Data.Sqlite;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\n\nnamespace Tester.AdoNet.Persistence\n{\n    public sealed class SqlitePersistenceGrainStorageFixture : TestEnvironmentFixture\n    {\n        public const string AdoInvariant = AdoNetInvariants.InvariantNameSqlLite;\n\n        public SqlitePersistenceGrainStorageFixture()\n        {\n            this.DatabaseFilePath = Path.Combine(Path.GetTempPath(), $\"orleans-sqlite-persistence-{Guid.NewGuid():N}.db\");\n            this.ConnectionString = new SqliteConnectionStringBuilder\n            {\n                DataSource = this.DatabaseFilePath,\n                Mode = SqliteOpenMode.ReadWriteCreate\n            }.ToString();\n\n            this.DatabaseStorage = RelationalStorage.CreateInstance(AdoInvariant, this.ConnectionString);\n            this.InitializeSchemaAsync().GetAwaiter().GetResult();\n            this.Storage = this.CreateGrainStorageAsync().GetAwaiter().GetResult();\n        }\n\n        public string DatabaseFilePath { get; }\n\n        public string ConnectionString { get; }\n\n        public IRelationalStorage DatabaseStorage { get; }\n\n        public AdoNetGrainStorage Storage { get; }\n\n        public async Task InitializeSchemaAsync()\n        {\n            await this.DatabaseStorage.ExecuteAsync(await LoadScriptAsync(\"Sqlite-Main.sql\"), command => { }).ConfigureAwait(false);\n            await this.DatabaseStorage.ExecuteAsync(await LoadScriptAsync(\"Sqlite-Persistence.sql\"), command => { }).ConfigureAwait(false);\n        }\n\n        public async Task<AdoNetGrainStorage> CreateGrainStorageAsync(string storageName = \"SqliteGrainStorageForTest\")\n        {\n            var providerRuntime = new ClientProviderRuntime(\n                this.InternalGrainFactory,\n                this.Services,\n                this.Services.GetRequiredService<ClientGrainContext>());\n\n            var options = new AdoNetGrainStorageOptions\n            {\n                ConnectionString = this.ConnectionString,\n                Invariant = AdoInvariant,\n                GrainStorageSerializer = new JsonGrainStorageSerializer(providerRuntime.ServiceProvider.GetService<OrleansJsonSerializer>())\n            };\n\n            var storageProvider = new AdoNetGrainStorage(\n                providerRuntime.ServiceProvider.GetRequiredService<IActivatorProvider>(),\n                providerRuntime.ServiceProvider.GetRequiredService<ILogger<AdoNetGrainStorage>>(),\n                Options.Create(options),\n                Options.Create(new ClusterOptions { ServiceId = Guid.NewGuid().ToString() }),\n                storageName);\n\n            ISiloLifecycleSubject siloLifeCycle = new SiloLifecycleSubject(NullLoggerFactory.Instance.CreateLogger<SiloLifecycleSubject>());\n            storageProvider.Participate(siloLifeCycle);\n            await siloLifeCycle.OnStart(CancellationToken.None).ConfigureAwait(false);\n            return storageProvider;\n        }\n\n        private static async Task<string> LoadScriptAsync(string fileName)\n        {\n            var scriptPath = Path.Combine(AppContext.BaseDirectory, fileName);\n            if (!File.Exists(scriptPath))\n            {\n                scriptPath = Path.Combine(Environment.CurrentDirectory, fileName);\n            }\n\n            if (!File.Exists(scriptPath))\n            {\n                throw new FileNotFoundException($\"Unable to locate SQL script '{fileName}'.\", fileName);\n            }\n\n            return await File.ReadAllTextAsync(scriptPath).ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Persistence/SqlitePersistenceGrainStorageTests.cs",
    "content": "using System.Globalization;\nusing Microsoft.Data.Sqlite;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing TestExtensions;\nusing UnitTests.StorageTests.Relational;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace Tester.AdoNet.Persistence\n{\n    [TestCategory(\"AdoNet\"), TestCategory(\"Persistence\"), TestCategory(\"Sqlite\"), TestCategory(\"Functional\")]\n    public class SqlitePersistenceGrainStorageTests : IClassFixture<SqlitePersistenceGrainStorageFixture>\n    {\n        private readonly SqlitePersistenceGrainStorageFixture fixture;\n        private readonly CommonStorageTests commonStorageTests;\n\n        public SqlitePersistenceGrainStorageTests(SqlitePersistenceGrainStorageFixture fixture)\n        {\n            this.fixture = fixture;\n            this.commonStorageTests = new CommonStorageTests(fixture.Storage);\n        }\n\n        [Fact]\n        public async Task WriteRead()\n        {\n            var (grainType, grainId, grainState) = StorageDataSetPlain<long>.GetTestData(0);\n            await this.commonStorageTests.Store_WriteRead(grainType, grainId, grainState);\n        }\n\n        [Fact]\n        public async Task WriteClearRead()\n        {\n            var (grainType, grainId, grainState) = StorageDataSetPlain<long>.GetTestData(1);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, grainId, grainState);\n        }\n\n        [Fact]\n        public async Task WriteDuplicateFailsWithInconsistentStateException()\n        {\n            var exception = await this.commonStorageTests.PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        [Fact]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            var exception = await this.commonStorageTests.PersistenceStorage_WriteInconsistentFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        [Fact]\n        public async Task ClearInconsistentFailsWithInconsistentStateException()\n        {\n            var storage = await this.fixture.CreateGrainStorageAsync($\"SqliteClearInconsistent-{Guid.NewGuid():N}\");\n            const string grainType = \"sqlite-clear-inconsistent-grain\";\n            var grainId = GrainId.Create(GrainType.Create(grainType), GrainIdKeyExtensions.CreateIntegerKey(Random.Shared.NextInt64()));\n\n            var grainState = new GrainState<TestState1> { State = new TestState1 { A = \"initial\", B = 1, C = 1 } };\n            await storage.WriteStateAsync(grainType, grainId, grainState);\n\n            grainState.State = new TestState1 { A = \"latest\", B = 2, C = 2 };\n            await storage.WriteStateAsync(grainType, grainId, grainState);\n            var staleVersion = (int.Parse(Assert.IsType<string>(grainState.ETag), CultureInfo.InvariantCulture) - 1).ToString(CultureInfo.InvariantCulture);\n\n            var staleState = new GrainState<TestState1> { State = new TestState1(), ETag = staleVersion, RecordExists = true };\n            var exception = await Record.ExceptionAsync(() => storage.ClearStateAsync(grainType, grainId, staleState));\n            var inconsistent = Assert.IsType<InconsistentStateException>(exception);\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(inconsistent.Message);\n\n            var readState = new GrainState<TestState1> { State = new TestState1() };\n            await storage.ReadStateAsync(grainType, grainId, readState);\n            Assert.True(readState.RecordExists);\n            Assert.Equal(grainState.State, readState.State);\n        }\n\n        [Fact]\n        public async Task HashCollisionWriteReadWriteRead()\n        {\n            var storage = await this.fixture.CreateGrainStorageAsync($\"SqliteHashCollision-{Guid.NewGuid():N}\");\n            storage.HashPicker = new StorageHasherPicker(new[] { new ConstantHasher() });\n            var storageTests = new CommonStorageTests(storage);\n            await storageTests.PersistenceStorage_WriteReadWriteReadStatesInParallel(nameof(HashCollisionWriteReadWriteRead), 2);\n        }\n\n        [Fact]\n        public async Task ExtensionStringIdentityMatching()\n        {\n            var storage = await this.fixture.CreateGrainStorageAsync($\"SqliteExtension-{Guid.NewGuid():N}\");\n            storage.HashPicker = new StorageHasherPicker(new[] { new ConstantHasher() });\n\n            const string grainType = \"sqlite-extension-string-sensitive-grain\";\n            const long grainKey = 71337;\n            var grainIdA = GrainId.Create(GrainType.Create(grainType), GrainIdKeyExtensions.CreateIntegerKey(grainKey, \"A\"));\n            var grainIdB = GrainId.Create(GrainType.Create(grainType), GrainIdKeyExtensions.CreateIntegerKey(grainKey, \"B\"));\n            var grainStateA = new GrainState<TestState1> { State = new TestState1 { A = \"alpha\", B = 10, C = 20 } };\n            var grainStateB = new GrainState<TestState1> { State = new TestState1 { A = \"beta\", B = 30, C = 40 } };\n\n            await storage.WriteStateAsync(grainType, grainIdA, grainStateA);\n            await storage.WriteStateAsync(grainType, grainIdB, grainStateB);\n\n            var readA = new GrainState<TestState1> { State = new TestState1() };\n            var readB = new GrainState<TestState1> { State = new TestState1() };\n            await storage.ReadStateAsync(grainType, grainIdA, readA);\n            await storage.ReadStateAsync(grainType, grainIdB, readB);\n\n            Assert.Equal(grainStateA.State, readA.State);\n            Assert.Equal(grainStateB.State, readB.State);\n            Assert.NotEqual(readA.State, readB.State);\n        }\n\n        [Fact]\n        public async Task ConcurrentFirstWriteRaceUsesOptimisticConcurrency()\n        {\n            var storage = await this.fixture.CreateGrainStorageAsync($\"SqliteConcurrentFirstWrite-{Guid.NewGuid():N}\");\n            const string grainType = \"sqlite-concurrent-first-write-grain\";\n            var inconsistentStateExceptionCount = 0;\n\n            for (var i = 0; i < 20; i++)\n            {\n                var grainId = GrainId.Create(GrainType.Create(grainType), GrainIdKeyExtensions.CreateIntegerKey(Random.Shared.NextInt64()));\n                var startGate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n                var firstWrite = Task.Run(async () =>\n                {\n                    await startGate.Task;\n                    var state = new GrainState<TestState1> { State = new TestState1 { A = \"first\", B = i, C = i } };\n                    return await Record.ExceptionAsync(() => storage.WriteStateAsync(grainType, grainId, state));\n                });\n\n                var secondWrite = Task.Run(async () =>\n                {\n                    await startGate.Task;\n                    var state = new GrainState<TestState1> { State = new TestState1 { A = \"second\", B = i + 1000, C = i + 1000 } };\n                    return await Record.ExceptionAsync(() => storage.WriteStateAsync(grainType, grainId, state));\n                });\n\n                startGate.SetResult();\n                var exceptions = await Task.WhenAll(firstWrite, secondWrite);\n\n                foreach (var exception in exceptions.Where(exception => exception is not null))\n                {\n                    Assert.IsNotType<SqliteException>(exception);\n                    Assert.IsType<InconsistentStateException>(exception);\n                    inconsistentStateExceptionCount++;\n                }\n            }\n\n            Assert.True(inconsistentStateExceptionCount > 0);\n        }\n\n        [Fact]\n        public async Task VersionProgressionAfterWriteClearWrite()\n        {\n            const string grainType = \"sqlite-version-progression-grain\";\n            var grainId = GrainId.Create(GrainType.Create(grainType), GrainIdKeyExtensions.CreateIntegerKey(Random.Shared.NextInt64()));\n            var grainState = new GrainState<TestState1> { State = new TestState1 { A = \"v1\", B = 1, C = 1 } };\n\n            await this.fixture.Storage.WriteStateAsync(grainType, grainId, grainState);\n            var versionAfterFirstWrite = int.Parse(Assert.IsType<string>(grainState.ETag), CultureInfo.InvariantCulture);\n\n            grainState.State = new TestState1 { A = \"v2\", B = 2, C = 2 };\n            await this.fixture.Storage.WriteStateAsync(grainType, grainId, grainState);\n            var versionAfterSecondWrite = int.Parse(Assert.IsType<string>(grainState.ETag), CultureInfo.InvariantCulture);\n            Assert.Equal(versionAfterFirstWrite + 1, versionAfterSecondWrite);\n\n            await this.fixture.Storage.ClearStateAsync(grainType, grainId, grainState);\n            var versionAfterClear = int.Parse(Assert.IsType<string>(grainState.ETag), CultureInfo.InvariantCulture);\n            Assert.Equal(versionAfterSecondWrite + 1, versionAfterClear);\n\n            grainState.State = new TestState1 { A = \"v3\", B = 3, C = 3 };\n            await this.fixture.Storage.WriteStateAsync(grainType, grainId, grainState);\n            var versionAfterWritePostClear = int.Parse(Assert.IsType<string>(grainState.ETag), CultureInfo.InvariantCulture);\n            Assert.Equal(versionAfterClear + 1, versionAfterWritePostClear);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/PostgreSqlMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Tests.SqlUtils;\nusing Orleans.Configuration;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for Orleans membership table operations using PostgreSQL as the storage backend.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"PostgreSql\"), TestCategory(\"Functional\")]\n    public class PostgreSqlMembershipTableTests : MembershipTableTestsBase\n    {\n        public PostgreSqlMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(typeof(PostgreSqlMembershipTableTests).Name, LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            var options = new AdoNetClusteringSiloOptions()\n            {\n                Invariant = GetAdoInvariant(),\n                ConnectionString = this.connectionString,\n            };\n            return new AdoNetClusteringTable(this.Services, this._clusterOptions, Options.Create(options), this.loggerFactory.CreateLogger<AdoNetClusteringTable>());\n        }\n\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new AdoNetClusteringClientOptions()\n            {\n                ConnectionString = this.connectionString,\n                Invariant = GetAdoInvariant()\n            };\n            return new AdoNetGatewayListProvider(this.loggerFactory.CreateLogger<AdoNetGatewayListProvider>(), this.Services, Options.Create(options), this._gatewayOptions, this._clusterOptions);\n        }\n\n        protected override string GetAdoInvariant()\n        {\n            return AdoNetInvariants.InvariantNamePostgreSql;\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void MembershipTable_PostgreSql_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_PostgreSql_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTablePostgreSql_CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Properties/GlobalSuppressions.cs",
    "content": "// This file is used by Code Analysis to maintain SuppressMessage\n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given\n// a specific target and scoped to a namespace, type, member, etc.\n\n[assembly: SuppressMessage(\"Blocker Code Smell\", \"S2699:Tests should include assertions\", Justification = \"Test Runner\")]"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Properties/Usings.cs",
    "content": "global using System.Diagnostics.CodeAnalysis;\nglobal using Xunit;\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/RelationalUtilities/MySqlStorageForTesting.cs",
    "content": "using MySql.Data.MySqlClient;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\n\nnamespace UnitTests.General\n{\n    internal class MySqlStorageForTesting : RelationalStorageForTesting\n    {\n        protected override string ProviderMoniker => \"MySQL\";\n        public MySqlStorageForTesting(string connectionString) : base(AdoNetInvariants.InvariantNameMySql, connectionString ?? TestDefaultConfiguration.MySqlConnectionString)\n        {\n        }\n\n        public override string CancellationTestQuery { get { return \"DO SLEEP(10); SELECT 1;\"; } }\n\n        public override string CreateStreamTestTable { get { return \"CREATE TABLE StreamingTest(Id INT NOT NULL, StreamData LONGBLOB NOT NULL);\"; } }\n\n        public IEnumerable<string> SplitScript(string setupScript)\n        {\n            return setupScript.Replace(\"END$$\", \"END;\")\n                .Split(new[] { \"DELIMITER $$\", \"DELIMITER ;\" }, StringSplitOptions.RemoveEmptyEntries);\n        }\n\n        protected override string CreateDatabaseTemplate\n        {\n            get { return @\"CREATE DATABASE `{0}`\"; }\n        }\n\n        protected override string DropDatabaseTemplate\n        {\n            get { return @\"DROP DATABASE `{0}`\"; }\n        }\n         \n        protected override string ExistsDatabaseTemplate\n        {\n            get { return \"SELECT COUNT(1) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '{0}'\"; }\n        }\n\n        protected override IEnumerable<string> ConvertToExecutableBatches(string setupScript, string databaseName)\n        {\n            var batches = setupScript.Replace(\"END$$\", \"END;\").Split(new[] { \"DELIMITER $$\", \"DELIMITER ;\" }, StringSplitOptions.RemoveEmptyEntries).ToList();\n            batches.Add(CreateStreamTestTable);\n\n            return batches;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/RelationalUtilities/PostgreSqlStorageForTesting.cs",
    "content": "using Npgsql;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\n\nnamespace Tester.RelationalUtilities\n{\n    internal class PostgreSqlStorageForTesting : RelationalStorageForTesting\n    {\n        protected override string ProviderMoniker => \"PostgreSQL\";\n\n        public PostgreSqlStorageForTesting(string connectionString)\n            : base(AdoNetInvariants.InvariantNamePostgreSql, connectionString ?? TestDefaultConfiguration.PostgresConnectionString)\n        {\n        }\n\n        public override string CancellationTestQuery { get { return \"SELECT pg_sleep(10); SELECT 1; \"; } }\n\n        public override string CreateStreamTestTable { get { return \"CREATE TABLE StreamingTest(Id integer NOT NULL, StreamData bytea NOT NULL);\"; } }\n\n\n        protected override string CreateDatabaseTemplate\n        {\n            get\n            {\n                return @\"CREATE DATABASE \"\"{0}\"\" WITH ENCODING='UTF8' CONNECTION LIMIT=-1;\";\n            }\n        }\n\n        protected override string DropDatabaseTemplate => @\"DROP DATABASE \"\"{0}\"\" WITH (FORCE);\";\n\n        protected override string ExistsDatabaseTemplate\n        {\n            get\n            {\n                return \"SELECT COUNT(1)::int::boolean FROM pg_database WHERE datname = '{0}';\";\n            }\n        }\n\n\n        protected override IEnumerable<string> ConvertToExecutableBatches(string setupScript, string dataBaseName)\n        {\n\n            var batches = new List<string>\n            {\n                setupScript,\n                CreateStreamTestTable\n            }; \n            \n\n            return batches;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/RelationalUtilities/RelationalStorageForTesting.cs",
    "content": "using System.Data.Common;\nusing Orleans.Tests.SqlUtils;\nusing Tester.RelationalUtilities;\nusing TestExtensions;\n\nnamespace UnitTests.General\n{\n    public abstract class RelationalStorageForTesting\n    {\n        private static readonly Dictionary<string, Func<string, RelationalStorageForTesting>> instanceFactory =\n            new Dictionary<string, Func<string, RelationalStorageForTesting>>\n            {\n                {AdoNetInvariants.InvariantNameSqlServer, cs => new SqlServerStorageForTesting(cs)},\n                {AdoNetInvariants.InvariantNameMySql, cs => new MySqlStorageForTesting(cs)},\n                {AdoNetInvariants.InvariantNamePostgreSql, cs => new PostgreSqlStorageForTesting(cs)}\n            };\n\n        private static readonly Dictionary<string, string> ConnectionStringsByInvariant =\n            new()\n            {\n                {AdoNetInvariants.InvariantNameSqlServer, TestDefaultConfiguration.MsSqlConnectionString},\n                {AdoNetInvariants.InvariantNameMySql, TestDefaultConfiguration.MySqlConnectionString},\n                {AdoNetInvariants.InvariantNamePostgreSql, TestDefaultConfiguration.PostgresConnectionString}\n            };\n\n        public IRelationalStorage Storage { get; private set; }\n\n        public string CurrentConnectionString\n        {\n            get { return Storage?.ConnectionString; }\n        }\n\n        /// <summary>\n        /// The name of the provider type (MySQL, SQLServer, Oracle, PostgreSQL, etc).\n        /// </summary>\n        protected abstract string ProviderMoniker { get; }\n\n        /// <summary>\n        /// A delayed query that is then cancelled in a test to see if cancellation works.\n        /// </summary>\n        public abstract string CancellationTestQuery { get; }\n\n        public abstract string CreateStreamTestTable { get; }\n\n        public virtual string DeleteStreamTestTable\n        { get { return \"DELETE StreamingTest;\"; } }\n\n        public virtual string StreamTestSelect\n        { get { return \"SELECT Id, StreamData FROM StreamingTest WHERE Id = @streamId;\"; } }\n\n        public virtual string StreamTestInsert\n        { get { return \"INSERT INTO StreamingTest(Id, StreamData) VALUES(@id, @streamData);\"; } }\n\n        /// <summary>\n        /// The script that creates Orleans schema in the database, usually CreateOrleansTables_xxxx.sql\n        /// </summary>\n        protected string[] SetupSqlScriptFileNames => new[] {\n                                $\"{this.ProviderMoniker}-Main.sql\",\n                                $\"{this.ProviderMoniker}-Clustering.sql\",\n                                $\"{this.ProviderMoniker}-Persistence.sql\",\n                                $\"{this.ProviderMoniker}-Reminders.sql\",\n                                $\"{this.ProviderMoniker}-Streaming.sql\",\n                                $\"{this.ProviderMoniker}-GrainDirectory.sql\"\n                                }.Concat(Directory.GetFiles(Environment.CurrentDirectory, $\"{this.ProviderMoniker}-Clustering-*.sql\")\n                                .Concat(Directory.GetFiles(Environment.CurrentDirectory, $\"{this.ProviderMoniker}-Persistence-*.sql\"))\n                                .Concat(Directory.GetFiles(Environment.CurrentDirectory, $\"{this.ProviderMoniker}-Reminders-*.sql\"))\n                                .Concat(Directory.GetFiles(Environment.CurrentDirectory, $\"{this.ProviderMoniker}-Streaming-*.sql\"))\n                                .Concat(Directory.GetFiles(Environment.CurrentDirectory, $\"{this.ProviderMoniker}-GrainDirectory-*.sql\"))\n                                .Select(f => Path.GetFileName(f))\n                                .OrderBy(f => f)).ToArray();\n\n        /// <summary>\n        /// A query template to create a database with a given name.\n        /// </summary>\n        protected abstract string CreateDatabaseTemplate { get; }\n\n        /// <summary>\n        /// A query template to drop a database with a given name.\n        /// </summary>\n        protected abstract string DropDatabaseTemplate { get; }\n\n        /// <summary>\n        /// A query template if a database with a given name exists.\n        /// </summary>\n        protected abstract string ExistsDatabaseTemplate { get; }\n\n        /// <summary>\n        /// Converts the given script into batches to execute sequentially\n        /// </summary>\n        /// <param name=\"setupScript\">the script. usually CreateOrleansTables_xxxx.sql</param>\n        /// <param name=\"databaseName\">the name of the database</param>\n        protected abstract IEnumerable<string> ConvertToExecutableBatches(string setupScript, string databaseName);\n\n        public static void CheckPreconditionsOrThrow(string invariantName, string connectionString = null)\n        {\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                Skip.IfNot(ConnectionStringsByInvariant.TryGetValue(invariantName, out connectionString), $\"Unknown ADO.NET invariant, '{invariantName}'\");\n            }\n\n            Skip.If(string.IsNullOrEmpty(connectionString), \"Connection string not provided.\");\n        }\n\n        public static async Task<RelationalStorageForTesting> SetupInstance(string invariantName, string testDatabaseName, string connectionString = null)\n        {\n            CheckPreconditionsOrThrow(invariantName, connectionString);\n            if (string.IsNullOrWhiteSpace(invariantName))\n            {\n                throw new ArgumentException(\"The name of invariant must contain characters\", nameof(invariantName));\n            }\n\n            if (string.IsNullOrWhiteSpace(testDatabaseName))\n            {\n                throw new ArgumentException(\"database string must contain characters\", nameof(testDatabaseName));\n            }\n\n            Console.WriteLine(\"Initializing relational databases...\");\n\n            RelationalStorageForTesting testStorage;\n            testStorage = CreateTestInstance(invariantName, connectionString);\n\n            if (string.IsNullOrEmpty(testStorage.CurrentConnectionString))\n            {\n                Console.WriteLine(\"No storage configured\");\n                return testStorage;\n            }\n\n            Console.WriteLine(\"Dropping and recreating database '{0}' with ConnectionString '{1}'\", testDatabaseName, testStorage.CurrentConnectionString);\n\n            if (await testStorage.ExistsDatabaseAsync(testDatabaseName))\n            {\n                await testStorage.DropDatabaseAsync(testDatabaseName);\n            }\n\n            await testStorage.CreateDatabaseAsync(testDatabaseName);\n\n            //The old storage instance has the previous connection string, time have a new handle with a new connection string...\n            testStorage = testStorage.CopyInstance(testDatabaseName);\n\n            Console.WriteLine(\"Creating database tables...\");\n\n            var setupScript = string.Empty;\n\n            // Concatenate scripts\n            foreach (var fileName in testStorage.SetupSqlScriptFileNames)\n            {\n                setupScript += File.ReadAllText(fileName);\n\n                // Just in case add a CRLF between files, but they should end in a new line.\n                setupScript += \"\\r\\n\";\n            }\n\n            await testStorage.ExecuteSetupScript(setupScript, testDatabaseName);\n\n            Console.WriteLine(\"Initializing relational databases done.\");\n\n            return testStorage;\n        }\n\n        private static RelationalStorageForTesting CreateTestInstance(string invariantName, string connectionString)\n        {\n            return instanceFactory[invariantName](connectionString);\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"invariantName\"></param>\n        /// <param name=\"connectionString\"></param>\n        protected RelationalStorageForTesting(string invariantName, string connectionString)\n        {\n            if (!string.IsNullOrEmpty(connectionString))\n            {\n                Storage = RelationalStorage.CreateInstance(invariantName, connectionString);\n            }\n            else\n            {\n                throw new SkipException(\"ConnectionString not provided.\");\n            }\n        }\n\n        /// <summary>\n        /// Executes the given script in a test context.\n        /// </summary>\n        /// <param name=\"setupScript\">the script. usually CreateOrleansTables_xxxx.sql</param>\n        /// <param name=\"dataBaseName\">the target database to be populated</param>\n        /// <returns></returns>\n        private async Task ExecuteSetupScript(string setupScript, string dataBaseName)\n        {\n            var splitScripts = ConvertToExecutableBatches(setupScript, dataBaseName);\n            foreach (var script in splitScripts)\n            {\n                _ = await Storage.ExecuteAsync(script);\n            }\n        }\n\n        /// <summary>\n        /// Checks the existence of a database using the given <see paramref=\"storage\"/> storage object.\n        /// </summary>\n        /// <param name=\"databaseName\">The name of the database existence of which to check.</param>\n        /// <returns><em>TRUE</em> if the given database exists. <em>FALSE</em> otherwise.</returns>\n        private async Task<bool> ExistsDatabaseAsync(string databaseName)\n        {\n            var ret = await Storage.ReadAsync(string.Format(ExistsDatabaseTemplate, databaseName), command =>\n            { }, (selector, resultSetCount, cancellationToken) => { return Task.FromResult(selector.GetBoolean(0)); }).ConfigureAwait(continueOnCapturedContext: false);\n\n            return ret.First();\n        }\n\n        /// <summary>\n        /// Creates a database with a given name.\n        /// </summary>\n        /// <param name=\"databaseName\">The name of the database to create.</param>\n        /// <returns>The call will be successful if the DDL query is successful. Otherwise an exception will be thrown.</returns>\n        private async Task CreateDatabaseAsync(string databaseName)\n        {\n            await Storage.ExecuteAsync(string.Format(CreateDatabaseTemplate, databaseName), command => { }).ConfigureAwait(continueOnCapturedContext: false);\n        }\n\n        /// <summary>\n        /// Drops a database with a given name.\n        /// </summary>\n        /// <param name=\"databaseName\">The name of the database to drop.</param>\n        /// <returns>The call will be successful if the DDL query is successful. Otherwise an exception will be thrown.</returns>\n        private async Task DropDatabaseAsync(string databaseName)\n        {\n            await Storage.ExecuteAsync(string.Format(DropDatabaseTemplate, databaseName), command => { });\n        }\n\n        /// <summary>\n        /// Creates a new instance of the storage based on the old connection string by changing the database name.\n        /// </summary>\n        /// <param name=\"newDatabaseName\">Connection string instance name of the database.</param>\n        /// <returns>A new <see cref=\"RelationalStorageForTesting\"/> instance with having the same connection string but with a new databaseName.</returns>\n        private RelationalStorageForTesting CopyInstance(string newDatabaseName)\n        {\n            var csb = new DbConnectionStringBuilder();\n            csb.ConnectionString = Storage.ConnectionString;\n            csb[\"Database\"] = newDatabaseName;\n            return CreateTestInstance(Storage.InvariantName, csb.ConnectionString);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/RelationalUtilities/SqlServerStorageForTesting.cs",
    "content": "using Microsoft.Data.SqlClient;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\n\nnamespace UnitTests.General\n{\n    public class SqlServerStorageForTesting : RelationalStorageForTesting\n    {\n        protected override string ProviderMoniker => \"SQLServer\";\n\n        public SqlServerStorageForTesting(string connectionString)\n            : base(AdoNetInvariants.InvariantNameSqlServer, connectionString ?? TestDefaultConfiguration.MsSqlConnectionString)\n        {\n        }\n\n        public override string CancellationTestQuery { get { return \"WAITFOR DELAY '00:00:010'; SELECT 1; \"; } }\n\n        public override string CreateStreamTestTable { get { return \"CREATE TABLE StreamingTest(Id INT NOT NULL, StreamData VARBINARY(MAX) NOT NULL);\"; } }\n\n        protected override string CreateDatabaseTemplate\n        {\n            get\n            {\n                return @\"USE [Master];\n                DECLARE @fileName AS NVARCHAR(255) = CONVERT(NVARCHAR(255), SERVERPROPERTY('instancedefaultdatapath')) + N'{0}';\n                EXEC('CREATE DATABASE [{0}] ON PRIMARY\n                (\n                    NAME = [{0}],\n                    FILENAME =''' + @fileName + ''',\n                    SIZE = 20MB,\n                    MAXSIZE = 10000MB,\n                    FILEGROWTH = 5MB\n                )')\";\n            }\n        }\n\n        protected override string DropDatabaseTemplate\n        {\n            get\n            {\n                return @\"USE [Master]; ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{0}];\";\n            }\n        }\n\n        protected override string ExistsDatabaseTemplate\n        {\n            get\n            {\n                return \"SELECT CAST(COUNT(1) AS BIT) FROM sys.databases WHERE name = '{0}'\";\n            }\n        }\n\n\n        protected override IEnumerable<string> ConvertToExecutableBatches(string setupScript, string dataBaseName)\n        {\n            var batches = setupScript.Split(new[] {\"GO\"}, StringSplitOptions.RemoveEmptyEntries).ToList();\n\n            //This removes the use of recovery log in case of database crashes, which\n            //improves performance to some degree, depending on usage. For non-performance testing only.\n            batches.Add(string.Format(\"ALTER DATABASE [{0}] SET RECOVERY SIMPLE;\", dataBaseName));\n            batches.Add(CreateStreamTestTable);\n\n            return batches;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Reminders/MySqlRemindersTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ReminderService;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.RemindersTest\n{\n    /// <summary>\n    /// Tests for Orleans reminders table operations using MySQL as the storage backend.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Reminders\"), TestCategory(\"AdoNet\"), TestCategory(\"MySql\")]\n    public class MySqlRemindersTableTests : ReminderTableTestsBase\n    {\n        public MySqlRemindersTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n            \n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(nameof(MySqlRemindersTableTests), LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            var options = new AdoNetReminderTableOptions\n            {\n                Invariant = this.GetAdoInvariant(),\n                ConnectionString = this.connectionStringFixture.ConnectionString\n            };\n            return new AdoNetReminderTable(\n                this.clusterOptions,\n                Options.Create(options));\n        }\n\n        protected override string GetAdoInvariant()\n        {\n            return AdoNetInvariants.InvariantNameMySql;\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void RemindersTable_MySql_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_MySql_RemindersRange()\n        {\n            await RemindersRange(iterations: 50);\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_MySql_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_MySql_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Reminders/PostgreSqlRemindersTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ReminderService;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\n\nnamespace UnitTests.RemindersTest\n{\n    /// <summary>\n    /// Tests for Orleans reminders table operations using PostgreSQL as the storage backend.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Reminders\"), TestCategory(\"AdoNet\"), TestCategory(\"PostgreSql\")]\n    public class PostgreSqlRemindersTableTests : ReminderTableTestsBase\n    {\n        public PostgreSqlRemindersTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(nameof(PostgreSqlRemindersTableTests), LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            var options = new AdoNetReminderTableOptions\n            {\n                Invariant = this.GetAdoInvariant(),\n                ConnectionString = this.connectionStringFixture.ConnectionString\n            };\n            return new AdoNetReminderTable(\n                this.clusterOptions,\n                Options.Create(options));\n        }\n\n        protected override string GetAdoInvariant()\n        {\n            return AdoNetInvariants.InvariantNamePostgreSql;\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void RemindersTable_PostgreSql_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_PostgreSql_RemindersRange()\n        {\n            await RemindersRange(iterations: 50);\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_PostgreSql_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_PostgreSql_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Reminders/ReminderTests_AdoNet_SqlServer.cs",
    "content": "//#define USE_SQL_SERVER\n\nusing Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.General;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.TimerTests;\nusing Orleans.Tests.SqlUtils;\nusing Orleans.Internal;\nusing Xunit;\nusing Microsoft.Extensions.Hosting;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable UnusedVariable\n\nnamespace Tester.AdoNet.Reminders\n{\n    /// <summary>\n    /// Integration tests for Orleans reminders functionality using SQL Server as the reminder service backend.\n    /// </summary>\n    [TestCategory(\"Reminders\"), TestCategory(\"AdoNet\"), TestCategory(\"SqlServer\")]\n    public class ReminderTests_AdoNet_SqlServer : ReminderTests_Base, IClassFixture<ReminderTests_AdoNet_SqlServer.Fixture>\n    {\n        private const string TestDatabaseName = \"OrleansTest_SqlServer_Reminders\";\n        private static readonly string AdoInvariant = AdoNetInvariants.InvariantNameSqlServer;\n        private const string ConnectionStringKey = \"ReminderConnectionString\";\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                RelationalStorageForTesting.CheckPreconditionsOrThrow(AdoInvariant);\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                string connectionString = RelationalStorageForTesting.SetupInstance(AdoInvariant, TestDatabaseName)\n                    .Result.CurrentConnectionString;\n                builder.ConfigureHostConfiguration(config => config.AddInMemoryCollection(new Dictionary<string, string>\n                {\n                    [ConnectionStringKey] = connectionString\n                }));\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseAdoNetReminderService(options =>\n                    {\n                        options.ConnectionString = hostBuilder.GetConfigurationValue(ConnectionStringKey);\n                        options.Invariant = AdoInvariant;\n                    });\n                });\n            }\n        }\n\n        public ReminderTests_AdoNet_SqlServer(Fixture fixture) : base(fixture)\n        {\n            // ReminderTable.Clear() cannot be called from a non-Orleans thread,\n            // so we must proxy the call through a grain.\n            var controlProxy = fixture.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            controlProxy.EraseReminderTable().WaitAsync(TestConstants.InitTimeout).Wait();\n        }\n        \n        // Basic tests\n\n        [SkippableFact]\n        public async Task Rem_Sql_Basic_StopByRef()\n        {\n            await Test_Reminders_Basic_StopByRef();\n        }\n\n        [SkippableFact]\n        public async Task Rem_Sql_Basic_ListOps()\n        {\n            await Test_Reminders_Basic_ListOps();\n        }\n\n        // Single join tests ... multi grain, multi reminders\n\n        [SkippableFact]\n        public async Task Rem_Sql_1J_MultiGrainMultiReminders()\n        {\n            await Test_Reminders_1J_MultiGrainMultiReminders();\n        }\n\n        [SkippableFact]\n        public async Task Rem_Sql_ReminderNotFound()\n        {\n            await Test_Reminders_ReminderNotFound();\n        }\n    }\n}\n// ReSharper restore InconsistentNaming\n// ReSharper restore UnusedVariable\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Reminders/SqlServerRemindersTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ReminderService;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.RemindersTest\n{\n    /// <summary>\n    /// Tests for operation of Orleans Reminders Table using SQL Server\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Reminders\"), TestCategory(\"AdoNet\"), TestCategory(\"SqlServer\")]\n    public class SqlServerRemindersTableTests : ReminderTableTestsBase\n    {\n        public SqlServerRemindersTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(nameof(SqlServerRemindersTableTests), LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            var options = new AdoNetReminderTableOptions\n            {\n                Invariant = this.GetAdoInvariant(),\n                ConnectionString = this.connectionStringFixture.ConnectionString\n            };\n            return new AdoNetReminderTable(\n                this.clusterOptions,\n                Options.Create(options));\n        }\n\n        protected override string GetAdoInvariant()\n        {\n            return AdoNetInvariants.InvariantNameSqlServer;\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void RemindersTable_SqlServer_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_SqlServer_RemindersRange()\n        {\n            await RemindersRange(iterations: 30);\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_SqlServer_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_SqlServer_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/SqlServerMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Runtime.MembershipService;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for operation of Orleans Membership Table using SQL Server\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"SQLServer\"), TestCategory(\"Functional\")]\n    public class SqlServerMembershipTableTests : MembershipTableTestsBase\n    {\n        public SqlServerMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(typeof(SqlServerMembershipTableTests).Name, LogLevel.Trace);\n            return filters;\n        }\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            var options = new AdoNetClusteringSiloOptions()\n            {\n                Invariant = GetAdoInvariant(),\n                ConnectionString = this.connectionString,\n            };\n            return new AdoNetClusteringTable(this.Services, this._clusterOptions, Options.Create(options),  this.loggerFactory.CreateLogger<AdoNetClusteringTable>());\n        }\n\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new AdoNetClusteringClientOptions()\n            {\n                ConnectionString = this.connectionString,\n                Invariant = GetAdoInvariant()\n            };\n            return new AdoNetGatewayListProvider(this.loggerFactory.CreateLogger<AdoNetGatewayListProvider>(), this.Services, Options.Create(options), _gatewayOptions, this._clusterOptions);\n        }\n\n        protected override string GetAdoInvariant()\n        {\n            return AdoNetInvariants.InvariantNameSqlServer;\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            var instance = await RelationalStorageForTesting.SetupInstance(GetAdoInvariant(), testDatabaseName);\n            return instance.CurrentConnectionString;\n        }\n\n        [SkippableFact]\n        public void MembershipTable_SqlServer_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_SqlServer_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTableSqlServerSql_CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/MySqlRelationalStoreTests.cs",
    "content": "using System.Runtime.ExceptionServices;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.AdoNet\n{\n    /// <summary>\n    /// Tests for MySQL relational storage functionality.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"MySql\")]\n    public class MySqlRelationalStoreTests : RelationalStoreTestsBase, IClassFixture<MySqlRelationalStoreTests.Fixture>\n    {\n        private const string TestDatabaseName = \"OrleansStreamTest\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNameMySql;\n\n        private readonly RelationalStorageForTesting _storage;\n\n        public class Fixture\n        {\n            private readonly ExceptionDispatchInfo preconditionsException;\n\n            public void EnsurePreconditionsMet()\n            {\n                this.preconditionsException?.Throw();\n            }\n\n            public Fixture()\n            {\n                try\n                {\n                    Storage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).GetAwaiter().GetResult();\n                }\n                catch (Exception ex)\n                {\n                    this.preconditionsException = ExceptionDispatchInfo.Capture(ex);\n                    return;\n                }\n            }\n\n            public RelationalStorageForTesting Storage { get; private set; }\n        }\n\n        public MySqlRelationalStoreTests(Fixture fixture) : base(AdoNetInvariantName)\n        {\n            fixture.EnsurePreconditionsMet();\n            _storage = fixture.Storage;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Streaming_MySql_Test()\n        {\n            using(var tokenSource = new CancellationTokenSource(StreamCancellationTimeoutLimit))\n            {             \n                var isMatch = await Task.WhenAll(InsertAndReadStreamsAndCheckMatch(_storage, StreamSizeToBeInsertedInBytes, NumberOfParallelStreams, tokenSource.Token));\n                Assert.True(isMatch.All(i => i), \"All inserted streams should be equal to read streams.\");\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task CancellationToken_MySql_Test()\n        {\n            await CancellationTokenTest(_storage, CancellationTestTimeoutLimit);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/PostgreSqlRelationalStoreTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.AdoNet\n{\n    /// <summary>\n    /// Tests for PostgreSQL relational storage functionality.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"PostgreSql\")]\n    public class PostgreSqlRelationalStoreTests : RelationalStoreTestsBase, IClassFixture<PostgreSqlRelationalStoreTests.Fixture>\n    {\n        private const string TestDatabaseName = \"OrleansStreamTest\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNamePostgreSql;\n\n        private readonly RelationalStorageForTesting _storage;\n\n        public class Fixture\n        {\n            public Fixture()\n            {\n                try\n                {\n                    Storage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).GetAwaiter().GetResult();\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine($\"Failed to initialize {AdoNetInvariantName} for testing: {ex}\");\n                }\n            }\n\n            public RelationalStorageForTesting Storage { get; private set; }\n        }\n\n        public PostgreSqlRelationalStoreTests(Fixture fixture) : base(AdoNetInvariantName)\n        {\n            _storage = fixture.Storage;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Streaming_PostgreSql_Test()\n        {\n            using(var tokenSource = new CancellationTokenSource(StreamCancellationTimeoutLimit))\n            {             \n                var isMatch = await Task.WhenAll(InsertAndReadStreamsAndCheckMatch(_storage, StreamSizeToBeInsertedInBytes, NumberOfParallelStreams, tokenSource.Token));\n                Assert.True(isMatch.All(i => i), \"All inserted streams should be equal to read streams.\");\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task CancellationToken_PostgreSql_Test()\n        {\n            await CancellationTokenTest(_storage, CancellationTestTimeoutLimit);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/AdotNetProviderFunctionalityTests.cs",
    "content": "using Orleans.Storage;\nusing System.Globalization;\nusing System.Text;\nusing Xunit;\n\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Tests for various helper classes.\n    /// </summary>\n    public class AdotNetProviderFunctionalityTests\n    {\n        [TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        [Fact]\n        public void AdoNetStorageProviderGrainTypeHashing()\n        {\n            //This way of using the hasher is like ADO.NET Storage provider would use it. This tests\n            //the hasher is thread safe.\n            var adonetDefaultHasher = new StorageHasherPicker(new[] { new OrleansDefaultHasher() });\n            const int TestGrainHash = -201809205;\n            var grainType = \"Grains.PersonGrain\";\n            Parallel.For(0, 1000000, i =>\n            {\n                //These parameters can be null in this test.\n                int grainTypeHash = adonetDefaultHasher.PickHasher<object>(null, null, null, default, null, null).Hash(Encoding.UTF8.GetBytes(grainType));\n                Assert.Equal(TestGrainHash, grainTypeHash);\n            });\n        }\n\n        [TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        [Fact]\n        public void LongGrainIdToN1KeyAreSame()\n        {\n            const long LongGrainId = 1001;\n            var longGrainIdAsN1 = new AdoGrainKey(LongGrainId, null);\n\n            Assert.Equal(LongGrainId, longGrainIdAsN1.N1Key);\n        }\n\n        [TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        [Fact]\n        public void LongGrainIdToStringAreSame()\n        {\n            const long LongGrainId = 1001;\n            var longGrainIdAsString = new AdoGrainKey(LongGrainId, null).ToString();\n\n            Assert.Equal(longGrainIdAsString, LongGrainId.ToString(CultureInfo.InvariantCulture));\n        }\n\n        [TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        [Fact]\n        public void LongGrainIdWithExtensionAreSame()\n        {\n            const long LongGrainId = 1001;\n            const string ExtensionKey = \"ExtensionKey\";\n            var longGrainIdWitExtensionAsString = new AdoGrainKey(LongGrainId, ExtensionKey).ToString();\n\n            //AdoGrainKey helper class splits the grain key and extension key using character '#'.\n            //The key and its extension are the two distinct elements.\n            var grainKeys = longGrainIdWitExtensionAsString.Split(new[] { \"#\" }, StringSplitOptions.RemoveEmptyEntries);\n            Assert.Equal(2, grainKeys.Length);\n\n            Assert.Equal(grainKeys[0], LongGrainId.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(ExtensionKey, grainKeys[1]);\n        }\n\n        [TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        [Fact]\n        public void GuidGrainIdWithExtensionAreSame()\n        {\n            Guid guidId = Guid.Parse(\"751D8030-9C84-4A91-816E-E95F64CE7588\");\n            var guidIdAsString = new AdoGrainKey(guidId, null).ToString();\n\n            Assert.Equal(guidIdAsString, guidId.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/CommonFixture.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Tests.SqlUtils;\nusing Orleans.Storage;\nusing TestExtensions;\nusing UnitTests.General;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// A common fixture to all the classes. XUnit.NET keeps this alive during the test run upon first\n    /// instantiation, so this is used to coordinate environment invariant enforcing and to cache\n    /// heavier setup.\n    /// </summary>\n    public class CommonFixture : TestEnvironmentFixture\n    {\n        /// <summary>\n        /// Caches storage provider for multiple uses using a unique, back-end specific key.\n        /// The value will be <em>null</em> if environment invariants have failed to hold upon\n        /// storage provider creation.\n        /// </summary>\n        private Dictionary<string, IGrainStorage> StorageProviders { get; set; } = new Dictionary<string, IGrainStorage>();\n\n        /// <summary>\n        /// This is used to lock the storage providers dictionary.\n        /// </summary>\n        private static AsyncLock StorageLock { get; } = new AsyncLock();\n\n        /// <summary>\n        /// Caches DefaultProviderRuntime for multiple uses.\n        /// </summary>\n        private IProviderRuntime DefaultProviderRuntime { get; }\n\n        /// <summary>\n        /// The environment contract and its invariants.\n        /// </summary>\n        private TestEnvironmentInvariant Invariants { get; } = new TestEnvironmentInvariant();\n\n        /// <summary>\n        /// The underlying relational storage connection if used.\n        /// </summary>\n        public RelationalStorageForTesting Storage { get; set; }\n\n        /// <summary>\n        /// Constructor.\n        /// </summary>\n        public CommonFixture()\n        {\n            _ = this.Services.GetRequiredService<IOptions<ClusterOptions>>();\n            DefaultProviderRuntime = new ClientProviderRuntime(\n                this.InternalGrainFactory,\n                this.Services,\n                this.Services.GetRequiredService<ClientGrainContext>());\n        }\n\n        /// <summary>\n        /// Returns a correct implementation of the persistence provider according to environment variables.\n        /// </summary>\n        /// <remarks>If the environment invariants have failed to hold upon creation of the storage provider,\n        /// a <em>null</em> value will be provided.</remarks>\n        public async Task<IGrainStorage> GetStorageProvider(string storageInvariant)\n        {\n            return await GetStorageProvider(storageInvariant, deleteStateOnClear: false);\n        }\n\n        /// <summary>\n        /// Returns a correct implementation of the persistence provider according to environment variables.\n        /// </summary>\n        /// <param name=\"storageInvariant\">The ADO.NET invariant name for the storage provider.</param>\n        /// <param name=\"deleteStateOnClear\">If <see langword=\"true\"/>, the provider will delete the row from the database when clearing state.</param>\n        /// <remarks>If the environment invariants have failed to hold upon creation of the storage provider,\n        /// a <em>null</em> value will be provided.</remarks>\n        public async Task<IGrainStorage> GetStorageProvider(string storageInvariant, bool deleteStateOnClear)\n        {\n            //Make sure the environment invariants hold before trying to give a functioning SUT instantiation.\n            //This is done instead of the constructor to have more granularity on how the environment should be initialized.\n            using (await StorageLock.LockAsync())\n            {\n                var cacheKey = deleteStateOnClear ? $\"{storageInvariant}_DeleteOnClear\" : storageInvariant;\n                if (AdoNetInvariants.Invariants.Contains(storageInvariant))\n                {\n                    if (!StorageProviders.ContainsKey(cacheKey))\n                    {\n                        var connectionString = Invariants.ActiveSettings.ConnectionStrings.FirstOrDefault(i => i.StorageInvariant == storageInvariant);\n\n                        if (string.IsNullOrWhiteSpace(connectionString.ConnectionString))\n                        {\n                            StorageProviders.Add(cacheKey, null);\n                        }\n                        else\n                        {\n                            Storage = Invariants.EnsureStorageForTesting(connectionString);\n\n                            var options = new AdoNetGrainStorageOptions()\n                            {\n                                ConnectionString = Storage.Storage.ConnectionString,\n                                Invariant = storageInvariant,\n                                GrainStorageSerializer = new JsonGrainStorageSerializer(this.DefaultProviderRuntime.ServiceProvider.GetService<OrleansJsonSerializer>()),\n                                DeleteStateOnClear = deleteStateOnClear,\n                            };\n                            var clusterOptions = new ClusterOptions()\n                            {\n                                ServiceId = Guid.NewGuid().ToString()\n                            };\n                            var storageProvider = new AdoNetGrainStorage(\n                                DefaultProviderRuntime.ServiceProvider.GetRequiredService<IActivatorProvider>(),\n                                DefaultProviderRuntime.ServiceProvider.GetRequiredService<ILogger<AdoNetGrainStorage>>(),\n                                Options.Create(options),\n                                Options.Create(clusterOptions),\n                                storageInvariant + \"_StorageProvider\");\n                            ISiloLifecycleSubject siloLifeCycle = new SiloLifecycleSubject(NullLoggerFactory.Instance.CreateLogger<SiloLifecycleSubject>());\n                            storageProvider.Participate(siloLifeCycle);\n                            await siloLifeCycle.OnStart(CancellationToken.None);\n\n                            StorageProviders[cacheKey] = storageProvider;\n                        }\n                    }\n                }\n            }\n\n            var key = deleteStateOnClear ? $\"{storageInvariant}_DeleteOnClear\" : storageInvariant;\n            return StorageProviders[key];\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/ConstantHasher.cs",
    "content": "﻿using Orleans.Storage;\n\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Returns a constant hash value to all input. This is used to induce hash collisions\n    /// one scenarios that involve more than one case.\n    /// </summary>\n    public class ConstantHasher: IHasher\n    {\n        /// <summary>\n        /// The hash value to which every input will be hashed to.\n        /// </summary>\n        public const int ConstantHash = 1;\n\n        /// <summary>\n        /// <see cref=\"IHasher.Description\"/>.\n        /// </summary>\n        public string Description { get; } = $\"Returns {ConstantHash} to all input, thus inducing hash collisions.\";\n\n        /// <summary>\n        /// <see cref=\"IHasher.Hash(byte[])\"/>.\n        /// </summary>\n        public int Hash(byte[] data) { return ConstantHash; }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/MySqlStorageDeleteOnClearTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Persistence tests for MySQL with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"MySql\"), TestCategory(\"Persistence\")]\n    public class MySqlStorageDeleteOnClearTests : RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNameMySql;\n\n        public MySqlStorageDeleteOnClearTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture, deleteStateOnClear: true)\n        {\n            Skip.If(PersistenceStorageTests == null, \"Persistence storage not available for MySql.\");\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/MySqlStorageTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Persistence tests for MySQL.\n    /// </summary>\n    /// <remarks>\n    /// To duplicate these tests to any back-end, not just for relational, copy and paste this\n    /// class, optionally remove <see cref=\"RelationalStorageTests\"/> inheritance and implement a\n    /// provider and environment setup as done in <see cref=\"CommonFixture\"/> and how it delegates it.\n    /// </remarks>\n    [TestCategory(\"MySql\"), TestCategory(\"Persistence\")]\n    public class MySqlStorageTests : RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        /// <summary>\n        /// The storage invariant, storage ID, or ADO.NET invariant for this test set.\n        /// </summary>\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNameMySql;\n\n        public MySqlStorageTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture)\n        {\n            //XUnit.NET will automatically call this constructor before every test method run.\n            Skip.If(PersistenceStorageTests == null, $\"Persistence storage not available for MySql.\");\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            await Relational_WriteDuplicateFailsWithInconsistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task StorageDataSetGeneric_HashCollisionTests()\n        {\n            await Relational_HashCollisionTests();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            await Relational_WriteInconsistentFailsWithIncosistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteRead100StatesInParallel()\n        {\n            await Relational_WriteReadWriteRead100StatesInParallel();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadCyrillic()\n        {\n            await PersistenceStorageTests.PersistenceStorage_Relational_WriteReadIdCyrillic();\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Json_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.Relational_Json_WriteRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Binary_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.Relational_Binary_WriteRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/PostgreSqlStorageDeleteOnClearTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Persistence tests for PostgreSQL with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"PostgreSql\"), TestCategory(\"Persistence\")]\n    public class PostgreSqlStorageDeleteOnClearTests : RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNamePostgreSql;\n\n        public PostgreSqlStorageDeleteOnClearTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture, deleteStateOnClear: true)\n        {\n            Skip.If(PersistenceStorageTests == null, \"Persistence storage not available for PostgreSql.\");\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/PostgreSqlStorageTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Persistence tests for PostgreSQL.\n    /// </summary>\n    /// <remarks>To duplicate these tests to any back-end, not just for relational, copy and paste this class,\n    /// optionally remove <see cref=\"RelationalStorageTests\"/> inheritance and implement a provider and environment\n    /// setup as done in <see cref=\"CommonFixture\"/> and how it delegates it.</remarks>\n    [TestCategory(\"PostgreSql\"), TestCategory(\"Persistence\")]\n    public class PostgreSqlStorageTests : RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        /// <summary>\n        /// The storage invariant, storage ID, or ADO.NET invariant for this test set.\n        /// </summary>\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNamePostgreSql;\n        \n        public PostgreSqlStorageTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture)\n        {\n            //XUnit.NET will automatically call this constructor before every test method run.\n            Skip.If(PersistenceStorageTests == null, $\"Persistence storage not available for PostgreSql.\");\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadCyrillic()\n        {\n            await PersistenceStorageTests.PersistenceStorage_Relational_WriteReadIdCyrillic();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadWriteRead100StatesInParallel()\n        {\n            await Relational_WriteReadWriteRead100StatesInParallel();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task StorageDataSetGeneric_HashCollisionTests()\n        {\n            await Relational_HashCollisionTests();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteDuplicateFailsWithInconsistentStateException()\n        {\n            await Relational_WriteDuplicateFailsWithInconsistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            await Relational_WriteInconsistentFailsWithIncosistentStateException();\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Json_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.Relational_Json_WriteRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Binary_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.Relational_Binary_WriteRead(grainType, getGrain, grainState);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/RelationalStorageTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing UnitTests.StorageTests.Relational.TestDataSets;\n\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// The relational back-ends share quite a lot of functionality. This shared functionality\n    /// is collected here, but concrete implementations can provide and implement storage specific\n    /// actions.\n    /// </summary>\n    public abstract class RelationalStorageTests\n    {\n        private IStorageHasherPicker ConstantHasher { get; } = new StorageHasherPicker(new[] { new ConstantHasher() });\n\n        /// <summary>\n        /// The tests and assertions common across all back-ends are here.\n        /// </summary>\n        internal CommonStorageTests PersistenceStorageTests { get; }\n\n        /// <summary>\n        /// The tests and assertions common across all back-ends are here.\n        /// </summary>\n        protected CommonFixture Fixture { get; }\n\n        /// <summary>\n        /// The fixture holds cached data such as the underlying connection to the storage.\n        /// </summary>\n        public string GrainCountQuery { get; } = \"SELECT COUNT(*) AS Count FROM Storage WHERE GrainTypeString = N'{0}';\";\n\n\n        public RelationalStorageTests(string adoNetInvariant, CommonFixture fixture, bool deleteStateOnClear = false)\n        {\n            Fixture = fixture;\n            var persistenceStorage = fixture.GetStorageProvider(adoNetInvariant, deleteStateOnClear).GetAwaiter().GetResult();\n            if(persistenceStorage != null)\n            {\n                PersistenceStorageTests = new CommonStorageTests(persistenceStorage);\n            }\n        }\n\n        internal Task Relational_WriteReadWriteRead100StatesInParallel()\n        {\n            return PersistenceStorageTests.PersistenceStorage_WriteReadWriteReadStatesInParallel(nameof(Relational_WriteReadWriteRead100StatesInParallel));\n        }\n\n        internal Task Relational_HashCollisionTests()\n        {\n            ((AdoNetGrainStorage)PersistenceStorageTests.Storage).HashPicker = ConstantHasher;\n            return PersistenceStorageTests.PersistenceStorage_WriteReadWriteReadStatesInParallel(nameof(Relational_HashCollisionTests), 2);\n        }\n\n        internal async Task Relational_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            var exception = await PersistenceStorageTests.PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        internal async Task Relational_WriteInconsistentFailsWithIncosistentStateException()\n        {\n            var exception = await PersistenceStorageTests.PersistenceStorage_WriteInconsistentFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        internal Task Relational_Json_WriteRead(string grainType, GrainId grainId, GrainState<TestStateGeneric1<string>> grainState)\n        {\n            ((AdoNetGrainStorage)PersistenceStorageTests.Storage).Serializer = GetJsonGrainStorageSerializer();\n            return PersistenceStorageTests.Store_WriteRead(grainType, grainId, grainState);\n        }\n\n        internal Task Relational_Binary_WriteRead(string grainType, GrainId grainId, GrainState<TestStateGeneric1<string>> grainState)\n        {\n            ((AdoNetGrainStorage)PersistenceStorageTests.Storage).Serializer = GetOrleansGrainStorageSerializer();\n            return PersistenceStorageTests.Store_WriteRead(grainType, grainId, grainState);\n        }\n\n        private JsonGrainStorageSerializer GetJsonGrainStorageSerializer()\n        {\n            var serializer = this.Fixture.Services.GetRequiredService<OrleansJsonSerializer>();\n            return new JsonGrainStorageSerializer(serializer);\n        }\n\n        private OrleansGrainStorageSerializer GetOrleansGrainStorageSerializer()\n        {\n            var serializer = this.Fixture.Services.GetRequiredService<Serializer>();\n            return new OrleansGrainStorageSerializer(serializer);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/SqlServerStorageDeleteOnClearTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Persistence tests for SQL Server with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"AdoNet\"), TestCategory(\"SqlServer\"), TestCategory(\"Persistence\")]\n    public class SqlServerStorageDeleteOnClearTests : RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNameSqlServer;\n\n        public SqlServerStorageDeleteOnClearTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture, deleteStateOnClear: true)\n        {\n            Skip.If(PersistenceStorageTests == null, \"Persistence storage not available for SqlServer.\");\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/SqlServerStorageTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    public struct WriteReadTestResult { public long Count { get; set; } }\n\n    /// <summary>\n    /// Persistence tests for SQL Server.\n    /// </summary>\n    /// <remarks>To duplicate these tests to any back-end, not just for relational, copy and paste this class,\n    /// optionally remove <see cref=\"RelationalStorageTests\"/> inheritance and implement a provider and environment\n    /// setup as done in <see cref=\"CommonFixture\"/> and how it delegates it.</remarks>\n    [TestCategory(\"AdoNet\"), TestCategory(\"SqlServer\"), TestCategory(\"Persistence\")]\n    public class SqlServerStorageTests: RelationalStorageTests, IClassFixture<CommonFixture>\n    {\n        /// <summary>\n        /// The storage invariant, storage ID, or ADO.NET invariant for this test set.\n        /// </summary>\n        private const string AdoNetInvariant = AdoNetInvariants.InvariantNameSqlServer;\n\n        public SqlServerStorageTests(CommonFixture commonFixture) : base(AdoNetInvariant, commonFixture)\n        {\n            //XUnit.NET will automatically call this constructor before every test method run.\n            Skip.If(PersistenceStorageTests == null, $\"Persistence storage not available for SqlServer.\");\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadCyrillic()\n        {\n            await PersistenceStorageTests.PersistenceStorage_Relational_WriteReadIdCyrillic();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadWriteRead100StatesInParallel()\n        {\n            await Relational_WriteReadWriteRead100StatesInParallel();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task StorageDataSetGeneric_HashCollisionTests()\n        {\n            await Relational_HashCollisionTests();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteDuplicateFailsWithInconsistentStateException()\n        {\n            await Relational_WriteDuplicateFailsWithInconsistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            await Relational_WriteInconsistentFailsWithIncosistentStateException();\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.PersistenceStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Json_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            var grainReference = getGrain;\n            await this.Relational_Json_WriteRead(grainType, grainReference, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_Binary_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.Relational_Binary_WriteRead(grainType, getGrain, grainState);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/Relational/TestEnvironmentInvariant.cs",
    "content": "using Newtonsoft.Json.Linq;\nusing Orleans.Tests.SqlUtils;\nusing Orleans.TestingHost.Utils;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Reflection;\nusing UnitTests.General;\nusing TestExtensions;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    [Serializable]\n    [DebuggerDisplay(\"StorageInvariant = {StorageInvariant}, ConnectionString = {ConnectionString}\")]\n    [Orleans.GenerateSerializer]\n    public struct StorageConnection\n    {\n        [Orleans.Id(0)]\n        public string StorageInvariant { get; set; }\n\n        [Orleans.Id(1)]\n        public string ConnectionString { get; set; }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class TestEnvironmentSettings\n    {\n        [Orleans.Id(0)]\n        public ICollection<StorageConnection> ConnectionStrings { get; set; }\n\n        [Orleans.Id(1)]\n        public string EnvironmentId { get; set; }\n    }\n\n    /// <summary>\n    /// This enforces the necessary environment invariants hold before starting to run tests.\n    /// This servers as a class or object invariant for the test environment.\n    /// </summary>\n    public class TestEnvironmentInvariant\n    {\n        /// <summary>\n        /// An environment variable to set a test settings file location.\n        /// </summary>\n        public const string EnvVariableForCustomSettingLocation = \"customTestSettingsFileLocation\";\n\n        /// <summary>\n        /// A default custom settings file location if <see cref=\"EnvVariableForCustomSettingLocation\"/> is not set.\n        /// </summary>\n        public const string FallBackCustomTestSettingsFileLocation = @\"..\\..\\..\\CustomTestSettings.json\";\n\n        /// <summary>\n        /// The default test settings before merging with external ones.\n        /// </summary>\n        public TestEnvironmentSettings DefaultSettings { get; } = new TestEnvironmentSettings\n        {\n            ConnectionStrings = new Collection<StorageConnection>(new List<StorageConnection>(new[]\n            {\n                new StorageConnection\n                {\n                    StorageInvariant = AdoNetInvariants.InvariantNameSqlServer,\n                    ConnectionString = TestDefaultConfiguration.MsSqlConnectionString\n                },\n                new StorageConnection\n                {\n                    StorageInvariant = AdoNetInvariants.InvariantNameMySql,\n                    ConnectionString = TestDefaultConfiguration.MySqlConnectionString\n                },\n                new StorageConnection\n                {\n                    StorageInvariant = AdoNetInvariants.InvariantNamePostgreSql,\n                    ConnectionString = TestDefaultConfiguration.PostgresConnectionString\n                }\n            })),\n            EnvironmentId = \"Default\"\n        };\n\n        /// <summary>\n        /// The active settings after merging the default ones with the active ones.\n        /// </summary>\n        public TestEnvironmentSettings ActiveSettings { get; set; }\n\n        /// <summary>\n        /// The default constructor.\n        /// </summary>\n        public TestEnvironmentInvariant()\n        {\n            ActiveSettings = TryLoadAndMergeWithCustomSettings(DefaultSettings);\n        }\n\n        /// <summary>\n        /// Ensures the storage with the given connection is functional and if not, tries to make it functional.\n        /// </summary>\n        /// <param name=\"connection\">The connection with which to ensure the storage is functional.</param>\n        /// <param name=\"storageName\">Storage name. This is optional.</param>\n        /// <returns></returns>\n        public RelationalStorageForTesting EnsureStorageForTesting(StorageConnection connection, string storageName = null)\n        {\n\n            if (AdoNetInvariants.Invariants.Contains(connection.StorageInvariant))\n            {\n                const string RelationalStorageTestDb = \"OrleansStorageTests\";\n                return RelationalStorageForTesting.SetupInstance(connection.StorageInvariant, storageName ?? RelationalStorageTestDb, connection.ConnectionString).GetAwaiter().GetResult();\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Tries to ensure the storage emulator is running before the tests start.\n        /// </summary>\n        /// <remarks>This could perhaps have more functionality.</remarks>\n        public bool EnsureEmulatorStorageForTesting()\n        {\n            return StorageEmulator.TryStart();\n        }\n\n        /// <summary>\n        /// Tries to load custom settings and if one is find, tries to merge them to the given default settings.\n        /// </summary>\n        /// <param name=\"defaultSettings\">The default settings with which to merge the ones.</param>\n        /// <returns>The result settings after merge.</returns>\n        private static TestEnvironmentSettings TryLoadAndMergeWithCustomSettings(TestEnvironmentSettings defaultSettings)\n        {\n            string customTestSettingsFileLocation = Environment.GetEnvironmentVariable(EnvVariableForCustomSettingLocation, EnvironmentVariableTarget.User) ?? FallBackCustomTestSettingsFileLocation;\n\n            var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);\n            var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);\n            var dirPath = Path.GetDirectoryName(codeBasePath);\n            var customFileLoc = Path.Combine(dirPath, customTestSettingsFileLocation);\n\n            var finalSettings = JObject.FromObject(defaultSettings);\n            if (File.Exists(customFileLoc))\n            {\n                //TODO: Print that parsing custom values...\n                var mergeSettings = new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union };\n                var customSettingsJson = JObject.Parse(File.ReadAllText(customFileLoc));\n                customSettingsJson.Merge(finalSettings, mergeSettings);\n                finalSettings = customSettingsJson;\n            }\n\n            return finalSettings.ToObject<TestEnvironmentSettings>();\n        }\n\n        /// <summary>\n        /// Checks if a given storage is reachable.\n        /// </summary>\n        /// <param name=\"connection\">The connection to check.</param>\n        /// <returns></returns>\n        private static async Task<bool> CanConnectToStorage(StorageConnection connection)\n        {\n            //How detect if a database can be connected is surprisingly tricky. Some information at\n            //http://stackoverflow.com/questions/3668506/efficient-sql-test-query-or-validation-query-that-will-work-across-all-or-most.\n            var storage = RelationalStorage.CreateInstance(connection.StorageInvariant, connection.ConnectionString);\n            var query = connection.ConnectionString != AdoNetInvariants.InvariantNameOracleDatabase ? \"SELECT 1;\" : \"SELECT 1 FROM DUAL;\";\n            try\n            {\n                await storage.ExecuteAsync(query);\n            }\n            catch\n            {\n                return false;\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/RelationalStoreTests.cs",
    "content": "using System.Data;\nusing System.Data.Common;\nusing Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.AdoNet\n{\n    /// <summary>\n    /// Test data model for streaming tests.\n    /// </summary>\n    public class StreamingTest\n    {\n        public int Id { get; set; }\n\n        public byte[] StreamData { get; set; }\n    }\n\n    /// <summary>\n    /// Base class for relational storage tests.\n    /// </summary>\n    public abstract class RelationalStoreTestsBase\n    {\n        //This timeout limit should be clearly less than that defined in RelationalStorageForTesting.CancellationTestQuery. \n        protected readonly TimeSpan CancellationTestTimeoutLimit = TimeSpan.FromSeconds(5);\n        protected readonly TimeSpan StreamCancellationTimeoutLimit = TimeSpan.FromSeconds(15);\n        protected const int MiB = 1048576;\n        protected const int StreamSizeToBeInsertedInBytes = MiB * 2;\n        protected const int NumberOfParallelStreams = 5;\n\n        protected RelationalStoreTestsBase(string adoNetInvariantName)\n        {\n            RelationalStorageForTesting.CheckPreconditionsOrThrow(adoNetInvariantName);\n        }\n\n        protected static Task<bool>[] InsertAndReadStreamsAndCheckMatch(RelationalStorageForTesting sut, int streamSize, int countOfStreams, CancellationToken cancellationToken)\n        {\n            Skip.If(string.IsNullOrEmpty(sut.CurrentConnectionString), \"Database was not initialized correctly\");\n\n            //Stream in and steam out three binary streams in parallel.\n            var streamChecks = new Task<bool>[countOfStreams];\n            for(int i = 0; i < countOfStreams; ++i)\n            {\n                int streamId = i;\n                streamChecks[i] = Task.Run(async () =>\n                {\n                    var rb = new byte[streamSize];\n                    Random.Shared.NextBytes(rb);\n                    await InsertIntoDatabaseUsingStream(sut, streamId, rb, cancellationToken);\n                    var dataStreamFromTheDb = await ReadFromDatabaseUsingAsyncStream(sut, streamId, cancellationToken);\n                    return dataStreamFromTheDb.StreamData.SequenceEqual(rb);\n                });\n            }\n\n            return streamChecks;\n        }\n\n        protected static async Task InsertIntoDatabaseUsingStream(RelationalStorageForTesting sut, int streamId, byte[] dataToInsert, CancellationToken cancellationToken)\n        {\n            Skip.If(string.IsNullOrEmpty(sut.CurrentConnectionString), \"Database was not initialized correctly\");\n            //The dataToInsert could be inserted here directly, but it wouldn't be streamed.\n            using (var ms = new MemoryStream(dataToInsert))\n            {\n                await sut.Storage.ExecuteAsync(sut.StreamTestInsert, command =>\n                {\n                    var p1 = command.CreateParameter();\n                    p1.ParameterName = \"Id\";\n                    p1.Value = streamId;\n                    command.Parameters.Add(p1);\n\n                    //MySQL does not support streams in and for the time being there\n                    //is not a custom stream defined. For ideas, see http://dev.mysql.com/doc/refman/5.7/en/blob.html\n                    //for string operations for blobs and http://rusanu.com/2010/12/28/download-and-upload-images-from-sql-server-with-asp-net-mvc/\n                    //on how one could go defining one.\n                    var p2 = command.CreateParameter();\n                    p2.ParameterName = \"StreamData\";\n                    p2.Value = dataToInsert;\n                    p2.DbType = DbType.Binary;\n                    p2.Size = dataToInsert.Length;\n                    command.Parameters.Add(p2);\n\n                }, CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false);\n            }\n        }\n\n        protected static async Task<StreamingTest> ReadFromDatabaseUsingAsyncStream(RelationalStorageForTesting sut, int streamId, CancellationToken cancellationToken)\n        {\n            Skip.If(string.IsNullOrEmpty(sut.CurrentConnectionString), \"Database was not initialized correctly\");\n            return (await sut.Storage.ReadAsync(sut.StreamTestSelect, command =>\n            {\n                var p = command.CreateParameter();\n                p.ParameterName = \"streamId\";\n                p.Value = streamId;\n                command.Parameters.Add(p);\n            }, async (selector, resultSetCount, canellationToken) =>\n            {\n                var streamSelector = (DbDataReader)selector;\n                var id = await streamSelector.GetValueAsync<int>(\"Id\");\n                using (var ms = new MemoryStream())\n                {\n                    using (var downloadStream = streamSelector.GetStream(1, sut.Storage))\n                    {\n                        await downloadStream.CopyToAsync(ms);\n\n                        return new StreamingTest { Id = id, StreamData = ms.ToArray() };\n                    }\n                }\n            }, CommandBehavior.SequentialAccess, cancellationToken).ConfigureAwait(false)).Single();\n        }\n\n        protected static Task CancellationTokenTest(RelationalStorageForTesting sut, TimeSpan timeoutLimit)\n        {\n            Skip.If(string.IsNullOrEmpty(sut.CurrentConnectionString), \"Database was not initialized correctly\");\n            using (var tokenSource = new CancellationTokenSource(timeoutLimit))\n            {\n                try\n                {\n                    //Here one second is added to the task timeout limit in order to account for the delays.\n                    //The delays are mainly in the underlying ADO.NET libraries and database.\n                    var task = sut.Storage.ReadAsync<int>(sut.CancellationTestQuery, tokenSource.Token);\n                    if(!task.Wait(timeoutLimit.Add(TimeSpan.FromSeconds(2))))\n                    {\n                        Assert.Fail(string.Format(\"Timeout limit {0} ms exceeded.\", timeoutLimit.TotalMilliseconds));\n                    }\n                }\n                catch(Exception ex)\n                {\n                    //There can be a DbException due to the operation being forcefully cancelled...\n                    //... Unless this is a test for a provider which does not support for cancellation.\n                    //The exception is wrapped into an AggregrateException due to the test arrangement of hard synchronous\n                    //wait to force for actual cancellation check and remove \"natural timeout\" causes.\n                    var innerException = ex?.InnerException;\n                    if(sut.Storage.SupportsCommandCancellation())\n                    {\n                        //If the operation is cancelled already before database calls, a OperationCancelledException\n                        //will be thrown in any case.\n                        Assert.True(innerException is DbException || innerException is OperationCanceledException, $\"Unexpected exception: {ex}\");\n                    }\n                    else\n                    {\n                        Assert.True(innerException is OperationCanceledException, $\"Unexpected exception: {ex}\");\n                    }\n                }\n            }\n\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/StorageTests/SqlServerRelationalStoreTests.cs",
    "content": "using Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.AdoNet\n{\n    /// <summary>\n    /// Tests for SQL Server relational storage functionality.\n    /// </summary>\n    [TestCategory(\"Persistence\"), TestCategory(\"SqlServer\")]\n    public class SqlServerRelationalStoreTests : RelationalStoreTestsBase, IClassFixture<SqlServerRelationalStoreTests.Fixture>\n    {\n        private const string TestDatabaseName = \"OrleansStreamTest\";\n        private const string AdoNetInvariantName = AdoNetInvariants.InvariantNameSqlServer;\n        private readonly RelationalStorageForTesting _storage;\n\n        public class Fixture\n        {\n            public Fixture()\n            {\n                try\n                {\n                    Storage = RelationalStorageForTesting.SetupInstance(AdoNetInvariantName, TestDatabaseName).GetAwaiter().GetResult();\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine($\"Failed to initialize {AdoNetInvariantName} for testing: {ex}\");\n                }\n            }\n\n            public RelationalStorageForTesting Storage { get; private set; }\n        }\n\n        public SqlServerRelationalStoreTests(Fixture fixture) : base(AdoNetInvariantName)\n        {\n            _storage = fixture.Storage;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Streaming_SqlServer_Test()\n        {\n            using(var tokenSource = new CancellationTokenSource(StreamCancellationTimeoutLimit))\n            {                \n                var isMatch = await Task.WhenAll(InsertAndReadStreamsAndCheckMatch(_storage, StreamSizeToBeInsertedInBytes, NumberOfParallelStreams, tokenSource.Token));\n                Assert.True(isMatch.All(i => i), \"All inserted streams should be equal to read streams.\");\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task CancellationToken_SqlServer_Test()\n        {\n            await CancellationTokenTest(_storage, CancellationTestTimeoutLimit);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetBatchContainerTests.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streaming.AdoNet;\nusing TestExtensions;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetBatchContainer\"/>.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic class AdoNetBatchContainerTests(TestEnvironmentFixture fixture)\n{\n    [Fact]\n    public void AdoNetBatchContainer_Constructs()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n\n        // act\n        var container = new AdoNetBatchContainer(streamId, events, requestContext);\n\n        // assert\n        Assert.Equal(streamId, container.StreamId);\n        Assert.Equal(events, container.Events);\n        Assert.Equal(requestContext, container.RequestContext);\n        Assert.Null(container.SequenceToken);\n        Assert.Equal(0, container.Dequeued);\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_FromMessage_CreatesContainer()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1), new OtherModel(2), new TestModel(3), new OtherModel(4) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n        var temp = new AdoNetBatchContainer(streamId, events, requestContext);\n        var serializer = fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var payload = serializer.SerializeToArray(temp);\n        var message = new AdoNetStreamMessage(\"MyServiceId\", \"MyProviderId\", \"MyQueueId\", 123, 234, DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow, payload);\n\n        // act\n        var container = AdoNetBatchContainer.FromMessage(serializer, message);\n\n        // assert\n        Assert.Equal(streamId, container.StreamId);\n        Assert.Equal(events, container.Events);\n        Assert.Equal(requestContext, container.RequestContext);\n        Assert.Equal(new EventSequenceTokenV2(123), container.SequenceToken);\n        Assert.Equal(234, container.Dequeued);\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_ToMessagePayload_CreatesPayload()\n    {\n        // arrange\n        var serializer = fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1), new OtherModel(2), new TestModel(3), new OtherModel(4) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n\n        // act\n        var payload = AdoNetBatchContainer.ToMessagePayload(serializer, streamId, events, requestContext);\n\n        // assert\n        var container = serializer.Deserialize(payload);\n        Assert.Equal(streamId, container.StreamId);\n        Assert.Equal(events, container.Events);\n        Assert.Equal(requestContext, container.RequestContext);\n        Assert.Null(container.SequenceToken);\n        Assert.Equal(0, container.Dequeued);\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_GetEvents_ThrowsOnHalfBaked()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1), new OtherModel(2), new TestModel(3), new OtherModel(4) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n\n        // act\n        var container = new AdoNetBatchContainer(streamId, events, requestContext);\n\n        // assert\n        Assert.Throws<InvalidOperationException>(container.GetEvents<TestModel>);\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_GetEvents_FiltersEvents()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1), new OtherModel(2), new TestModel(3), new OtherModel(4) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n        var temp = new AdoNetBatchContainer(streamId, events, requestContext);\n        var serializer = fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var payload = serializer.SerializeToArray(temp);\n        var message = new AdoNetStreamMessage(\"MyServiceId\", \"MyProviderId\", \"MyQueueId\", 123, 234, DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow, DateTime.UtcNow, payload);\n\n        // act\n        var container = AdoNetBatchContainer.FromMessage(serializer, message);\n\n        // assert\n        Assert.Equal([new TestModel(1), new TestModel(3)], container.GetEvents<TestModel>().Select(x => x.Item1));\n        Assert.Equal([new EventSequenceTokenV2(123, 0), new EventSequenceTokenV2(123, 1)], container.GetEvents<TestModel>().Select(x => x.Item2));\n        Assert.Equal([new OtherModel(2), new OtherModel(4)], container.GetEvents<OtherModel>().Select(x => x.Item1));\n        Assert.Equal([new EventSequenceTokenV2(123, 0), new EventSequenceTokenV2(123, 1)], container.GetEvents<OtherModel>().Select(x => x.Item2));\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_ImportsRequestContext()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n\n        // act\n        var container = new AdoNetBatchContainer(streamId, events, requestContext);\n\n        // assert\n        Assert.Equal(streamId, container.StreamId);\n        Assert.Equal(events, container.Events);\n        Assert.Equal(requestContext, container.RequestContext);\n        Assert.Null(container.SequenceToken);\n        Assert.Equal(0, container.Dequeued);\n    }\n\n    [Fact]\n    public void AdoNetBatchContainer_ToString_Renders()\n    {\n        // arrange\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1) };\n        var requestContext = new Dictionary<string, object> { { \"MyKey\", \"Value\" } };\n        var container = new AdoNetBatchContainer(streamId, events, requestContext);\n\n        // act\n        var result = container.ToString();\n\n        // assert\n        Assert.Equal($\"[{nameof(AdoNetBatchContainer)}:Stream={streamId},#Items={events.Count}]\", result);\n    }\n\n    [GenerateSerializer]\n    [Alias(\"Tester.AdoNet.Streaming.AdoNetBatchContainerTests.TestModel\")]\n    public record TestModel(\n        [property: Id(0)] int Value);\n\n    [GenerateSerializer]\n    [Alias(\"Tester.AdoNet.Streaming.AdoNetBatchContainerTests.OtherModel\")]\n    public record OtherModel(\n        [property: Id(0)] int Value);\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetClientStreamTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Streaming.AdoNet.Storage;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing UnitTests.General;\nusing Xunit.Abstractions;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for SQL Server ADO.NET client stream functionality.\n/// </summary>\npublic class SqlServerAdoNetClientStreamTests(ITestOutputHelper output) : AdoNetClientStreamTests(AdoNetInvariants.InvariantNameSqlServer, output)\n{\n}\n\n/// <summary>\n/// Tests for MySQL ADO.NET client stream functionality.\n/// </summary>\npublic class MySqlAdoNetClientStreamTests : AdoNetClientStreamTests\n{\n    public MySqlAdoNetClientStreamTests(ITestOutputHelper output) : base(AdoNetInvariants.InvariantNameMySql, output)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for PostgreSQL ADO.NET client stream functionality.\n/// </summary>\npublic class PostgreSqlAdoNetClientStreamTests(ITestOutputHelper output) : AdoNetClientStreamTests(AdoNetInvariants.InvariantNamePostgreSql, output)\n{\n}\n\n/// <summary>\n/// Base class for ADO.NET client stream tests.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetClientStreamTests : TestClusterPerTest\n{\n    protected AdoNetClientStreamTests(string invariant, ITestOutputHelper output)\n    {\n        _invariant = invariant;\n        RelationalStorageForTesting.CheckPreconditionsOrThrow(_invariant);\n        _output = output;\n    }\n\n    private static string _invariant;\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private const string AdoNetStreamProviderName = \"AdoNet\";\n    private const string StreamNamespace = \"AdoNetSubscriptionMultiplicityTestsNamespace\";\n\n    private readonly ITestOutputHelper _output;\n    private static RelationalStorageForTesting _testing;\n    private ClientStreamTestRunner _runner;\n\n    public override async Task InitializeAsync()\n    {\n        // set up the adonet environment before the base initializes\n        _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        // base initialization must only happen after the above\n        await base.InitializeAsync();\n\n        _runner = new ClientStreamTestRunner(HostedCluster);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<TestClientBuilderConfigurator>();\n    }\n\n    private class TestClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder\n                .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                {\n                    options.Invariant = _invariant;\n                    options.ConnectionString = _testing.CurrentConnectionString;\n                })\n                .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n        }\n    }\n\n    private class TestSiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n            siloBuilder\n                .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                {\n                    options.Invariant = _invariant;\n                    options.ConnectionString = _testing.CurrentConnectionString;\n                })\n                .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5))\n                .AddMemoryGrainStorage(\"PubSubStore\");\n        }\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetStreamProducerOnDroppedClientTest() => _runner.StreamProducerOnDroppedClientTest(AdoNetStreamProviderName, StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public virtual Task AdoNetStreamConsumerOnDroppedClientTest()\n    {\n        return _runner.StreamConsumerOnDroppedClientTest(\n            AdoNetStreamProviderName,\n            StreamNamespace,\n            _output,\n            async () => (await _testing.Storage.ReadAsync(\n                \"SELECT COUNT(*) FROM OrleansStreamDeadLetter\",\n                _ => { },\n                (record, i, ct) => Task.FromResult(record.GetInt32(0))))\n                .Single());\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetQueueAdapterFactoryTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Streams;\nusing Orleans.Tests.SqlUtils;\nusing Tester.AdoNet.Fakes;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterFactory\"/> against SQL Server.\n/// </summary>\npublic class SqlServerAdoNetQueueAdapterFactoryTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterFactoryTests(AdoNetInvariants.InvariantNameSqlServer, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterFactory\"/> against MySQL.\n/// </summary>\npublic class MySqlAdoNetQueueAdapterFactoryTests : AdoNetQueueAdapterFactoryTests\n{\n    public MySqlAdoNetQueueAdapterFactoryTests(TestEnvironmentFixture fixture) : base(AdoNetInvariants.InvariantNameMySql, fixture)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterFactory\"/> against PostgreSQL.\n/// </summary>\npublic class PostgreSqlAdoNetQueueAdapterFactoryTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterFactoryTests(AdoNetInvariants.InvariantNamePostgreSql, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterFactory\"/>.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetQueueAdapterFactoryTests(string invariant, TestEnvironmentFixture fixture) : IAsyncLifetime\n{\n    private readonly TestEnvironmentFixture _fixture = fixture;\n    private RelationalStorageForTesting _testing;\n    private IRelationalStorage _storage;\n\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n\n    public async Task InitializeAsync()\n    {\n        _testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = _testing.Storage;\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterFactory\"/> creates an <see cref=\"AdoNetQueueAdapter\"/> instance.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapterFactory_CreatesAdapter()\n    {\n        // arrange\n        var name = \"MyProviderName\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var hashOptions = new HashRingStreamQueueMapperOptions();\n        var loggerFactory = NullLoggerFactory.Instance;\n        var lifetime = new FakeHostApplicationLifetime();\n        var serviceProvider = _fixture.Services;\n        var factory = new AdoNetQueueAdapterFactory(name, streamOptions, clusterOptions, cacheOptions, hashOptions, loggerFactory, lifetime, serviceProvider);\n\n        // act\n        var adapter = await factory.CreateAdapter();\n\n        // assert\n        Assert.NotNull(adapter);\n        Assert.IsType<AdoNetQueueAdapter>(adapter);\n        Assert.Equal(name, adapter.Name);\n        Assert.False(adapter.IsRewindable);\n        Assert.Equal(StreamProviderDirection.ReadWrite, adapter.Direction);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterFactory\"/> gets a <see cref=\"AdoNetStreamFailureHandler\"/> instance.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapterFactory_GetsDeliveryFailureHandler()\n    {\n        // arrange\n        var name = \"MyProviderName\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var hashOptions = new HashRingStreamQueueMapperOptions();\n        var loggerFactory = NullLoggerFactory.Instance;\n        var lifetime = new FakeHostApplicationLifetime();\n        var serviceProvider = _fixture.Services;\n        var factory = new AdoNetQueueAdapterFactory(name, streamOptions, clusterOptions, cacheOptions, hashOptions, loggerFactory, lifetime, serviceProvider);\n        var queueId = QueueId.GetQueueId(\"MyQueueName\", 1, 2);\n\n        // act\n        var handler = await factory.GetDeliveryFailureHandler(queueId);\n\n        // assert\n        Assert.NotNull(handler);\n        Assert.IsType<AdoNetStreamFailureHandler>(handler);\n        Assert.False(handler.ShouldFaultSubsriptionOnError);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterFactory\"/> gets a <see cref=\"SimpleQueueCache\"/> instance.\n    /// </summary>\n    [SkippableFact]\n    public void AdoNetQueueAdapterFactory_GetsQueueAdapterCache()\n    {\n        // arrange\n        var name = \"MyProviderName\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var hashOptions = new HashRingStreamQueueMapperOptions();\n        var loggerFactory = NullLoggerFactory.Instance;\n        var lifetime = new FakeHostApplicationLifetime();\n        var serviceProvider = _fixture.Services;\n        var factory = new AdoNetQueueAdapterFactory(name, streamOptions, clusterOptions, cacheOptions, hashOptions, loggerFactory, lifetime, serviceProvider);\n\n        // act\n        var cache = factory.GetQueueAdapterCache();\n\n        // assert\n        Assert.NotNull(cache);\n        Assert.IsType<SimpleQueueAdapterCache>(cache);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterFactory\"/> gets a <see cref=\"HashRingBasedStreamQueueMapper\"/> instance.\n    /// </summary>\n    [SkippableFact]\n    public void AdoNetQueueAdapterFactory_GetsStreamQueueMapper()\n    {\n        // arrange\n        var name = \"MyProviderName\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var hashOptions = new HashRingStreamQueueMapperOptions();\n        var loggerFactory = NullLoggerFactory.Instance;\n        var lifetime = new FakeHostApplicationLifetime();\n        var serviceProvider = _fixture.Services;\n        var factory = new AdoNetQueueAdapterFactory(name, streamOptions, clusterOptions, cacheOptions, hashOptions, loggerFactory, lifetime, serviceProvider);\n\n        // act\n        var mapper = factory.GetStreamQueueMapper();\n\n        // assert\n        Assert.NotNull(mapper);\n        Assert.IsType<HashRingBasedStreamQueueMapper>(mapper);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterFactory\"/> constructs via its static factory method.\n    /// </summary>\n    [SkippableFact]\n    public void AdoNetQueueAdapterFactory_ConstructsViaStaticFactory()\n    {\n        // arrange\n        var name = \"MyProviderName\";\n\n        // act\n        var factory = AdoNetQueueAdapterFactory.Create(_fixture.Services, name);\n\n        // assert\n        Assert.NotNull(factory);\n        Assert.IsType<AdoNetQueueAdapterFactory>(factory);\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetQueueAdapterReceiverTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\nusing RelationalOrleansQueries = Orleans.Streaming.AdoNet.Storage.RelationalOrleansQueries;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterReceiverTests\"/> against SQL Server.\n/// </summary>\npublic class SqlServerAdoNetQueueAdapterReceiverTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterReceiverTests(AdoNetInvariants.InvariantNameSqlServer, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterReceiverTests\"/> against MySQL.\n/// </summary>\npublic class MySqlAdoNetQueueAdapterReceiverTests : AdoNetQueueAdapterReceiverTests\n{\n    public MySqlAdoNetQueueAdapterReceiverTests(TestEnvironmentFixture fixture) : base(AdoNetInvariants.InvariantNameMySql, fixture)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterReceiverTests\"/> against PostgreSQL.\n/// </summary>\npublic class PostgreSqlAdoNetQueueAdapterReceiverTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterReceiverTests(AdoNetInvariants.InvariantNamePostgreSql, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapterReceiverTests\"/>.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetQueueAdapterReceiverTests(string invariant, TestEnvironmentFixture fixture) : IAsyncLifetime\n{\n    private readonly TestEnvironmentFixture _fixture = fixture;\n    private RelationalStorageForTesting _testing;\n    private IRelationalStorage _storage;\n    private RelationalOrleansQueries _queries;\n\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n\n    public async Task InitializeAsync()\n    {\n        _testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = _testing.Storage;\n        _queries = await RelationalOrleansQueries.CreateInstance(invariant, _storage.ConnectionString);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapterReceiver\"/> can get and confirm messages.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapterReceiver_GetsMessages_ConfirmsMessages()\n    {\n        // arrange - receiver\n        var serviceId = \"MyServiceId\";\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = serviceId\n        };\n        var providerId = \"MyProviderId\";\n        var queueId = \"MyQueueId\";\n        var maxCount = 10;\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString,\n\n            // disable eviction for this test\n            EvictionBatchSize = 0\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var serializer = _fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var logger = NullLogger<AdoNetQueueAdapterReceiver>.Instance;\n        var receiver = new AdoNetQueueAdapterReceiver(providerId, queueId, streamOptions, clusterOptions, cacheOptions, _queries, serializer, logger);\n        await receiver.Initialize(TimeSpan.FromSeconds(10));\n\n        // arrange - data\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var events = new List<object> { new TestModel(1), new TestModel(2), new TestModel(3) };\n        var context = new Dictionary<string, object> { { \"MyKey\", \"MyValue\" } };\n        var container = new AdoNetBatchContainer(streamId, events, context);\n        var payload = serializer.SerializeToArray(container);\n\n        // arrange - enqueue (via storage) some invalid messages followed by a valid message\n        var ackExpired = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, 0);\n        var ackOtherQueueId = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId + \"X\", payload, 100);\n        var ackOtherProviderId = await _queries.QueueStreamMessageAsync(serviceId, providerId + \"X\", queueId, payload, 100);\n        var ackOtherServiceId = await _queries.QueueStreamMessageAsync(serviceId + \"X\", providerId, queueId, payload, 100);\n        var ackValid = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, 100);\n\n        // act - dequeue messages via receiver\n        var dequeued = await receiver.GetQueueMessagesAsync(maxCount);\n        var storedDequeued = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\")).ToDictionary(x => x.MessageId);\n\n        // act - confirm messages via receiver\n        await receiver.MessagesDeliveredAsync(dequeued);\n        var storedConfirmed = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\")).ToDictionary(x => x.MessageId);\n\n        // assert - dequeued messages are as expected\n        Assert.NotNull(dequeued);\n        var single = Assert.IsType<AdoNetBatchContainer>(Assert.Single(dequeued));\n        Assert.Equal(streamId, single.StreamId);\n        Assert.Equal(events, single.Events);\n        Assert.Equal(context.Select(x => (x.Key, x.Value)), single.RequestContext.Select(x => (x.Key, x.Value)));\n        Assert.Equal(ackValid.MessageId, single.SequenceToken.SequenceNumber);\n        Assert.Equal(1, single.Dequeued);\n\n        // assert - storage is as expected after dequeuing\n        Assert.Equal(5, storedDequeued.Count);\n        Assert.Equal(0, storedDequeued[ackExpired.MessageId].Dequeued);\n        Assert.Equal(0, storedDequeued[ackOtherQueueId.MessageId].Dequeued);\n        Assert.Equal(0, storedDequeued[ackOtherProviderId.MessageId].Dequeued);\n        Assert.Equal(0, storedDequeued[ackOtherServiceId.MessageId].Dequeued);\n        Assert.Equal(1, storedDequeued[ackValid.MessageId].Dequeued);\n\n        // assert - stored confirmed messages\n        Assert.Equal(4, storedConfirmed.Count);\n        Assert.True(storedConfirmed.ContainsKey(ackExpired.MessageId));\n        Assert.True(storedConfirmed.ContainsKey(ackOtherQueueId.MessageId));\n        Assert.True(storedConfirmed.ContainsKey(ackOtherProviderId.MessageId));\n        Assert.True(storedConfirmed.ContainsKey(ackOtherServiceId.MessageId));\n        Assert.False(storedConfirmed.ContainsKey(ackValid.MessageId));\n    }\n\n    /// <summary>\n    /// Tests that <see cref=\"AdoNetQueueAdapterReceiver.Shutdown(TimeSpan)\"/> waits for the outstanding task.\n    /// </summary>\n    /// <returns></returns>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapterReceiver_Shutdown_WaitsForOutstandingTask()\n    {\n        // arrange - receiver\n        var serviceId = \"MyServiceId\";\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = serviceId\n        };\n        var providerId = \"MyProviderId\";\n        var queueId = \"MyQueueId\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var serializer = _fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var logger = NullLogger<AdoNetQueueAdapterReceiver>.Instance;\n        var receiver = new AdoNetQueueAdapterReceiver(providerId, queueId, streamOptions, clusterOptions, cacheOptions, _queries, serializer, logger);\n        await receiver.Initialize(TimeSpan.FromSeconds(10));\n\n        // arrange - enqueue a message\n        var payload = serializer.SerializeToArray(new AdoNetBatchContainer(StreamId.Create(\"MyNamespace\", \"MyKey\"), [new TestModel(1)], null));\n        await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, 100);\n\n        // act - start getting messages from the receiver\n        var getTask = receiver.GetQueueMessagesAsync(10);\n\n        // act - shutdown the receiver\n        await receiver.Shutdown(TimeSpan.FromSeconds(10));\n\n        // assert - the outstanding task completes before the shutdown task\n        Assert.True(getTask.IsCompleted);\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n\n    [GenerateSerializer]\n    [Alias(\"Tester.AdoNet.Streaming.AdoNetQueueAdapterReceiverTests.TestModel\")]\n    public record TestModel(\n        [property: Id(0)] int Value);\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetQueueAdapterTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Streams;\nusing Orleans.Tests.SqlUtils;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\nusing RelationalOrleansQueries = Orleans.Streaming.AdoNet.Storage.RelationalOrleansQueries;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapter\"/> against SQL Server.\n/// </summary>\npublic class SqlServerAdoNetQueueAdapterTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterTests(AdoNetInvariants.InvariantNameSqlServer, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapter\"/> against MySQL.\n/// </summary>\npublic class MySqlAdoNetQueueAdapterTests : AdoNetQueueAdapterTests\n{\n    public MySqlAdoNetQueueAdapterTests(TestEnvironmentFixture fixture) : base(AdoNetInvariants.InvariantNameMySql, fixture)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapter\"/> against PostgreSQL.\n/// </summary>\npublic class PostgreSqlAdoNetQueueAdapterTests(TestEnvironmentFixture fixture) : AdoNetQueueAdapterTests(AdoNetInvariants.InvariantNamePostgreSql, fixture)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetQueueAdapter\"/>.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetQueueAdapterTests(string invariant, TestEnvironmentFixture fixture) : IAsyncLifetime\n{\n    private readonly TestEnvironmentFixture _fixture = fixture;\n    private RelationalStorageForTesting _testing;\n    private IRelationalStorage _storage;\n    private RelationalOrleansQueries _queries;\n\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n\n    public async Task InitializeAsync()\n    {\n        _testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = _testing.Storage;\n        _queries = await RelationalOrleansQueries.CreateInstance(invariant, _testing.CurrentConnectionString);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapter\"/> constructs with the expected state.\n    /// </summary>\n    [SkippableFact]\n    public void AdoNetQueueAdapter_Constructs()\n    {\n        // arrange\n        var name = \"MyProviderId\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var mapper = new AdoNetStreamQueueMapper(new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions { TotalQueueCount = 8 }, \"MyQueue\"));\n        var serializer = _fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var logger = NullLogger<AdoNetQueueAdapter>.Instance;\n        var serviceProvider = _fixture.Services;\n\n        // act\n        var adapter = new AdoNetQueueAdapter(name, streamOptions, clusterOptions, cacheOptions, mapper, _queries, serializer, logger, serviceProvider);\n\n        // assert\n        Assert.Equal(name, adapter.Name);\n        Assert.False(adapter.IsRewindable);\n        Assert.Equal(StreamProviderDirection.ReadWrite, adapter.Direction);\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapter\"/> can enqueue messages.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapter_EnqueuesMessages()\n    {\n        // arrange\n        var serviceId = \"MyServiceId\";\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = serviceId\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var providerId = \"MyProviderId\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString,\n            ExpiryTimeout = TimeSpan.FromSeconds(100)\n        };\n        var serializer = _fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var logger = NullLogger<AdoNetQueueAdapter>.Instance;\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var hashOptions = new HashRingStreamQueueMapperOptions { TotalQueueCount = 8 };\n        var hashMapper = new HashRingBasedStreamQueueMapper(hashOptions, \"MyQueue\");\n        var adoNetMapper = new AdoNetStreamQueueMapper(hashMapper);\n        var adoNetQueueId = adoNetMapper.GetAdoNetQueueId(streamId);\n        var adapter = new AdoNetQueueAdapter(providerId, streamOptions, clusterOptions, cacheOptions, adoNetMapper, _queries, serializer, logger, _fixture.Services);\n        var context = new Dictionary<string, object> { { \"MyKey\", \"MyValue\" } };\n\n        // act - enqueue (via adapter) some messages\n        var beforeEnqueued = DateTime.UtcNow;\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(1) }, null, context);\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(2) }, null, context);\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(3) }, null, context);\n        var afterEnqueued = DateTime.UtcNow;\n\n        // assert - stored messages are as expected\n        var stored = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\")).ToList();\n        for (var i = 0; i < stored.Count; i++)\n        {\n            var item = stored[i];\n\n            Assert.Equal(serviceId, item.ServiceId);\n            Assert.Equal(providerId, item.ProviderId);\n            Assert.Equal(adoNetQueueId, item.QueueId);\n            Assert.NotEqual(0, item.MessageId);\n            Assert.Equal(0, item.Dequeued);\n            Assert.True(item.VisibleOn >= beforeEnqueued);\n            Assert.True(item.VisibleOn <= afterEnqueued);\n            Assert.True(item.ExpiresOn >= beforeEnqueued.Add(streamOptions.ExpiryTimeout));\n            Assert.True(item.ExpiresOn <= afterEnqueued.Add(streamOptions.ExpiryTimeout));\n            Assert.Equal(item.VisibleOn, item.CreatedOn);\n            Assert.Equal(item.VisibleOn, item.ModifiedOn);\n\n            var serializedContainer = serializer.Deserialize(item.Payload);\n            Assert.Equal(streamId, serializedContainer.StreamId);\n            Assert.Null(serializedContainer.SequenceToken);\n            Assert.Equal(new[] { new TestModel(i + 1) }, serializedContainer.Events);\n            Assert.Single(serializedContainer.RequestContext);\n            Assert.Equal(\"MyValue\", serializedContainer.RequestContext[\"MyKey\"]);\n            Assert.Equal(0, serializedContainer.Dequeued);\n        }\n    }\n\n    /// <summary>\n    /// Tests that the <see cref=\"AdoNetQueueAdapter\"/> can enqueue messages that are visible to its receivers.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetQueueAdapter_WiresUpReceiver()\n    {\n        // arrange\n        var serviceId = \"MyServiceId\";\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = serviceId\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var providerId = \"MyProviderId\";\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var serializer = _fixture.Serializer.GetSerializer<AdoNetBatchContainer>();\n        var logger = NullLogger<AdoNetQueueAdapter>.Instance;\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var hashOptions = new HashRingStreamQueueMapperOptions { TotalQueueCount = 8 };\n        var hashMapper = new HashRingBasedStreamQueueMapper(hashOptions, \"MyQueue\");\n        var queueId = hashMapper.GetQueueForStream(streamId);\n        var adoMapper = new AdoNetStreamQueueMapper(hashMapper);\n        var adoNetQueueId = adoMapper.GetAdoNetQueueId(streamId);\n        var adapter = new AdoNetQueueAdapter(providerId, streamOptions, clusterOptions, cacheOptions, adoMapper, _queries, serializer, logger, _fixture.Services);\n\n        // act - enqueue (via adapter) some messages\n        var beforeEnqueued = DateTime.UtcNow;\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(1) }, null, new Dictionary<string, object> { { \"MyKey\", 1 } });\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(2) }, null, new Dictionary<string, object> { { \"MyKey\", 2 } });\n        await adapter.QueueMessageBatchAsync(streamId, new[] { new TestModel(3) }, null, new Dictionary<string, object> { { \"MyKey\", 3 } });\n        var afterEnqueued = DateTime.UtcNow;\n\n        // act - grab receiver and dequeue messages\n        var receiver = adapter.CreateReceiver(queueId);\n        await receiver.Initialize(TimeSpan.FromSeconds(10));\n        var beforeDequeued = DateTime.UtcNow;\n        var messages = await receiver.GetQueueMessagesAsync(10);\n        var afterDequeued = DateTime.UtcNow;\n\n        // assert - dequeued messages are as expected\n        Assert.Equal(3, messages.Count);\n        for (var i = 0; i < messages.Count; i++)\n        {\n            var message = messages[i];\n\n            Assert.Equal(streamId, message.StreamId);\n            Assert.Equal([new TestModel(i + 1)], message.GetEvents<TestModel>().Select(x => x.Item1));\n            Assert.True(message.ImportRequestContext());\n            Assert.Equal(i + 1, RequestContext.Get(\"MyKey\"));\n        }\n\n        // assert - stored messages are as expected\n        var stored = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\")).ToList();\n        for (var i = 0; i < stored.Count; i++)\n        {\n            var item = stored[i];\n\n            Assert.Equal(serviceId, item.ServiceId);\n            Assert.Equal(providerId, item.ProviderId);\n            Assert.Equal(adoNetQueueId, item.QueueId);\n            Assert.NotEqual(0, item.MessageId);\n            Assert.Equal(1, item.Dequeued);\n            Assert.True(item.VisibleOn >= beforeDequeued.Add(streamOptions.VisibilityTimeout));\n            Assert.True(item.VisibleOn <= afterDequeued.Add(streamOptions.VisibilityTimeout));\n            Assert.True(item.ExpiresOn >= beforeEnqueued.Add(streamOptions.ExpiryTimeout));\n            Assert.True(item.ExpiresOn <= afterEnqueued.Add(streamOptions.ExpiryTimeout));\n            Assert.True(item.CreatedOn >= beforeEnqueued);\n            Assert.True(item.CreatedOn <= afterEnqueued);\n            Assert.True(item.ModifiedOn >= beforeDequeued);\n            Assert.True(item.ModifiedOn <= afterDequeued);\n\n            var serializedContainer = serializer.Deserialize(item.Payload);\n            Assert.Equal(streamId, serializedContainer.StreamId);\n            Assert.Null(serializedContainer.SequenceToken);\n            Assert.Equal(new[] { new TestModel(i + 1) }, serializedContainer.Events);\n            Assert.Single(serializedContainer.RequestContext);\n            Assert.Equal(i + 1, serializedContainer.RequestContext[\"MyKey\"]);\n            Assert.Equal(0, serializedContainer.Dequeued);\n        }\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n\n    [GenerateSerializer]\n    [Alias(\"Tester.AdoNet.Streaming.AdoNetQueueAdapterTests.TestModel\")]\n    public record TestModel(\n        [property: Id(0)] int Value);\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetStreamFailureHandlerTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Streams;\nusing Orleans.Tests.SqlUtils;\nusing UnitTests.General;\nusing static System.String;\nusing RelationalOrleansQueries = Orleans.Streaming.AdoNet.Storage.RelationalOrleansQueries;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetStreamFailureHandler\"/> against SQL Server.\n/// </summary>\npublic class SqlServerAdoNetStreamFailureHandlerTests() : AdoNetStreamFailureHandlerTests(AdoNetInvariants.InvariantNameSqlServer)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetStreamFailureHandler\"/> against MySQL.\n/// </summary>\npublic class MySqlAdoNetStreamFailureHandlerTests : AdoNetStreamFailureHandlerTests\n{\n    public MySqlAdoNetStreamFailureHandlerTests() : base(AdoNetInvariants.InvariantNameMySql)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetStreamFailureHandler\"/> against PostgreSQL.\n/// </summary>\npublic class PostgreSqlAdoNetStreamFailureHandlerTests() : AdoNetStreamFailureHandlerTests(AdoNetInvariants.InvariantNamePostgreSql)\n{\n}\n\n/// <summary>\n/// Tests for <see cref=\"AdoNetStreamFailureHandler\"/>.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetStreamFailureHandlerTests(string invariant) : IAsyncLifetime\n{\n    private RelationalStorageForTesting _testing;\n    private IRelationalStorage _storage;\n    private RelationalOrleansQueries _queries;\n\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n\n    public async Task InitializeAsync()\n    {\n        _testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = _testing.Storage;\n        _queries = await RelationalOrleansQueries.CreateInstance(invariant, _testing.CurrentConnectionString);\n    }\n\n    /// <summary>\n    /// Tests that a <see cref=\"AdoNetStreamFailureHandler\"/> can be constructed.\n    /// </summary>\n    [SkippableFact]\n    public void AdoNetStreamFailureHandler_Constructs()\n    {\n        // arrange\n        var faultOnFailure = false;\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var mapper = new AdoNetStreamQueueMapper(new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions(), \"MyQueuePrefix\"));\n        var logger = NullLogger<AdoNetStreamFailureHandler>.Instance;\n\n        // act\n        var handler = new AdoNetStreamFailureHandler(faultOnFailure, streamOptions, clusterOptions, mapper, _queries, logger);\n\n        // assert\n        Assert.Equal(faultOnFailure, handler.ShouldFaultSubsriptionOnError);\n    }\n\n    /// <summary>\n    /// Tests that a <see cref=\"AdoNetStreamFailureHandler\"/> can move a poisoned message to dead letters.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetStreamFailureHandler_OnDeliveryFailure_MovesPoisonedMessageToDeadLetters()\n    {\n        // arrange - handler\n        var providerId = \"MyProviderId\";\n        var faultOnFailure = false;\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString,\n            MaxAttempts = 1\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var agentOptions = new StreamPullingAgentOptions\n        {\n            MaxEventDeliveryTime = TimeSpan.FromSeconds(0)\n        };\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var mapper = new AdoNetStreamQueueMapper(new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions(), \"MyQueuePrefix\"));\n        var logger = NullLogger<AdoNetStreamFailureHandler>.Instance;\n        var handler = new AdoNetStreamFailureHandler(faultOnFailure, streamOptions, clusterOptions, mapper, _queries, logger);\n\n        // arrange - queue an expired message\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var queueId = mapper.GetAdoNetQueueId(streamId);\n        var payload = new byte[] { 0xFF };\n\n        var beforeQueued = DateTime.UtcNow;\n        var ack = await _queries.QueueStreamMessageAsync(clusterOptions.ServiceId, providerId, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());\n        var afterQueued = DateTime.UtcNow;\n\n        // arrange - dequeue the message and make immediately available\n        var beforeDequeued = DateTime.UtcNow;\n        await _queries.GetStreamMessagesAsync(\n            ack.ServiceId,\n            ack.ProviderId,\n            ack.QueueId,\n            cacheOptions.CacheSize,\n            streamOptions.MaxAttempts,\n            agentOptions.MaxEventDeliveryTime.TotalSecondsCeiling(),\n            streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling(),\n            streamOptions.EvictionInterval.TotalSecondsCeiling(),\n            streamOptions.EvictionBatchSize);\n        var afterDequeued = DateTime.UtcNow;\n\n        // act - clean up with max attempts of one so the message above is flagged\n        var beforeFailure = DateTime.UtcNow;\n        await handler.OnDeliveryFailure(GuidId.GetNewGuidId(), providerId, streamId, new EventSequenceTokenV2(ack.MessageId));\n        var afterFailure = DateTime.UtcNow;\n\n        // assert\n        var dead = Assert.Single(await _storage.ReadAsync<AdoNetStreamDeadLetter>(\"SELECT * FROM OrleansStreamDeadLetter\"));\n        Assert.Equal(clusterOptions.ServiceId, dead.ServiceId);\n        Assert.Equal(providerId, dead.ProviderId);\n        Assert.Equal(queueId, dead.QueueId);\n        Assert.Equal(ack.MessageId, dead.MessageId);\n        Assert.Equal(1, dead.Dequeued);\n        Assert.True(dead.ExpiresOn >= beforeQueued.Add(streamOptions.ExpiryTimeout.SecondsCeiling()));\n        Assert.True(dead.ExpiresOn <= afterQueued.Add(streamOptions.ExpiryTimeout.SecondsCeiling()));\n        Assert.True(dead.CreatedOn >= beforeQueued);\n        Assert.True(dead.CreatedOn <= afterQueued);\n        Assert.True(dead.ModifiedOn >= beforeDequeued);\n        Assert.True(dead.ModifiedOn <= afterDequeued);\n        Assert.True(dead.DeadOn >= beforeFailure);\n        Assert.True(dead.DeadOn <= afterFailure);\n        Assert.True(dead.RemoveOn >= beforeFailure.Add(streamOptions.DeadLetterEvictionTimeout.SecondsCeiling()));\n        Assert.True(dead.RemoveOn <= afterFailure.Add(streamOptions.DeadLetterEvictionTimeout.SecondsCeiling()));\n        Assert.Equal(payload, dead.Payload);\n    }\n\n    /// <summary>\n    /// Tests that a <see cref=\"AdoNetStreamFailureHandler\"/> can move a poisoned message to dead letters.\n    /// </summary>\n    [SkippableFact]\n    public async Task AdoNetStreamFailureHandler_OnDeliveryFailure_DoesNotMoveHealthyMessageToDeadLetters()\n    {\n        // arrange - handler\n        var providerId = \"MyProviderId\";\n        var faultOnFailure = false;\n        var streamOptions = new AdoNetStreamOptions\n        {\n            Invariant = invariant,\n            ConnectionString = _storage.ConnectionString\n        };\n        var cacheOptions = new SimpleQueueCacheOptions();\n        var agentOptions = new StreamPullingAgentOptions();\n        var clusterOptions = new ClusterOptions\n        {\n            ServiceId = \"MyServiceId\"\n        };\n        var mapper = new AdoNetStreamQueueMapper(new HashRingBasedStreamQueueMapper(new HashRingStreamQueueMapperOptions(), \"MyQueuePrefix\"));\n        var logger = NullLogger<AdoNetStreamFailureHandler>.Instance;\n        var handler = new AdoNetStreamFailureHandler(faultOnFailure, streamOptions, clusterOptions, mapper, _queries, logger);\n\n        // arrange - queue an expired message\n        var streamId = StreamId.Create(\"MyNamespace\", \"MyKey\");\n        var queueId = mapper.GetAdoNetQueueId(streamId);\n        var payload = new byte[] { 0xFF };\n        var ack = await _queries.QueueStreamMessageAsync(clusterOptions.ServiceId, providerId, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());\n\n        // arrange - dequeue the message and make immediately available\n        await _queries.GetStreamMessagesAsync(\n            ack.ServiceId,\n            ack.ProviderId,\n            ack.QueueId,\n            cacheOptions.CacheSize,\n            streamOptions.MaxAttempts,\n            agentOptions.MaxEventDeliveryTime.TotalSecondsCeiling(),\n            streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling(),\n            streamOptions.EvictionInterval.TotalSecondsCeiling(),\n            streamOptions.EvictionBatchSize);\n\n        // act - clean up with max attempts of one so the message above is flagged\n        await handler.OnDeliveryFailure(GuidId.GetNewGuidId(), providerId, streamId, new EventSequenceTokenV2(ack.MessageId));\n\n        // assert\n        Assert.Empty(await _storage.ReadAsync<AdoNetStreamDeadLetter>(\"SELECT * FROM OrleansStreamDeadLetter\"));\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetStreamFilteringTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing MySql.Data.MySqlClient;\nusing Orleans.Streaming.AdoNet.Storage;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests.Filtering;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for SQL Server ADO.NET stream filtering functionality.\n/// </summary>\npublic class SqlServerAdoNetStreamFilteringTests() : AdoNetStreamFilteringTests(new Fixture(AdoNetInvariants.InvariantNameSqlServer))\n{\n}\n\n/// <summary>\n/// Tests for MySQL ADO.NET stream filtering functionality.\n/// </summary>\npublic class MySqlAdoNetStreamFilteringTests : AdoNetStreamFilteringTests\n{\n    public MySqlAdoNetStreamFilteringTests() : base(new Fixture(AdoNetInvariants.InvariantNameMySql))\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for PostgreSQL ADO.NET stream filtering functionality.\n/// </summary>\npublic class PostgreSqlAdoNetStreamFilteringTests() : AdoNetStreamFilteringTests(new Fixture(AdoNetInvariants.InvariantNamePostgreSql))\n{\n}\n\n/// <summary>\n/// Base class for ADO.NET stream filtering tests.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetStreamFilteringTests : StreamFilteringTestsBase, IAsyncLifetime\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private const string AdoNetStreamProviderName = \"AdoNet\";\n\n    private static RelationalStorageForTesting _testing;\n\n    protected AdoNetStreamFilteringTests(Fixture fixture) : base(fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n\n    public Task InitializeAsync() => fixture.InitializeAsync();\n\n    public Task DisposeAsync() => fixture.DisposeAsync();\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        private static string _invariant;\n\n        public Fixture(string invariant)\n        {\n            _invariant = invariant;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            // set up the adonet environment before the base initializes\n            _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n            Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n            await base.InitializeAsync();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddClientBuilderConfigurator<TestClientConfigurator>();\n            builder.AddSiloBuilderConfigurator<TestSiloConfigurator>();\n        }\n\n        public class TestSiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder\n                    .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                    {\n                        options.Invariant = _invariant;\n                        options.ConnectionString = _testing.CurrentConnectionString;\n                    })\n                    .AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddStreamFilter<CustomStreamFilter>(AdoNetStreamProviderName);\n            }\n        }\n\n        public class TestClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                    {\n                        options.Invariant = _invariant;\n                        options.ConnectionString = _testing.CurrentConnectionString;\n                    })\n                    .AddStreamFilter<CustomStreamFilter>(AdoNetStreamProviderName);\n            }\n        }\n    }\n\n    protected override string ProviderName => AdoNetStreamProviderName;\n\n    protected override TimeSpan WaitTime => TimeSpan.FromSeconds(2);\n\n    [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Filters\")]\n    public override Task IgnoreBadFilter() => base.IgnoreBadFilter();\n\n    [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Filters\")]\n    public override Task OnlyEvenItems() => base.OnlyEvenItems();\n\n    [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Filters\")]\n    public override Task MultipleSubscriptionsDifferentFilterData() => base.MultipleSubscriptionsDifferentFilterData();\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetStreamingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing MySql.Data.MySqlClient;\nusing Orleans.Streaming.AdoNet.Storage;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.General;\nusing UnitTests.Streaming;\nusing UnitTests.StreamingTests;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Cluster streaming tests for ADO.NET Streaming against SQL Server.\n/// </summary>\npublic class SqlServerAdoNetStreamingTests() : AdoNetStreamingTests(AdoNetInvariants.InvariantNameSqlServer)\n{\n}\n\n/// <summary>\n/// Cluster streaming tests for ADO.NET Streaming against MySQL.\n/// </summary>\npublic class MySqlAdoNetStreamingTests : AdoNetStreamingTests\n{\n    public MySqlAdoNetStreamingTests() : base(AdoNetInvariants.InvariantNameMySql)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Cluster streaming tests for ADO.NET Streaming against PostgreSQL.\n/// </summary>\npublic class PostgreSqlAdoNetStreamingTests() : AdoNetStreamingTests(AdoNetInvariants.InvariantNamePostgreSql)\n{\n}\n\n/// <summary>\n/// Cluster streaming tests for ADO.NET Streaming.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetStreamingTests : TestClusterPerTest\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private const string AdoNetStreamProviderName = \"AdoNet\";\n\n    private static string _invariant;\n\n    protected AdoNetStreamingTests(string invariant)\n    {\n        _invariant = invariant;\n        RelationalStorageForTesting.CheckPreconditionsOrThrow(_invariant);\n    }\n\n    private static RelationalStorageForTesting _testing;\n    private SingleStreamTestRunner _runner;\n\n    public override async Task InitializeAsync()\n    {\n        // set up the adonet environment before the base initializes\n        _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        // base initialization must only happen after the above\n        await base.InitializeAsync();\n\n        // the runner must only be created after base initialization\n        _runner = new SingleStreamTestRunner(InternalClient, AdoNetStreamProviderName);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<TestClientBuilderConfigurator>();\n    }\n\n    private class TestSiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n            siloBuilder\n                .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                {\n                    options.Invariant = _invariant;\n                    options.ConnectionString = _testing.CurrentConnectionString;\n                })\n                .AddMemoryGrainStorage(\"MemoryStore\")\n                .AddMemoryGrainStorage(\"PubSubStore\");\n        }\n    }\n\n    private class TestClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder.AddAdoNetStreams(AdoNetStreamProviderName, options =>\n            {\n                options.Invariant = _invariant;\n                options.ConnectionString = _testing.CurrentConnectionString;\n            });\n        }\n    }\n\n    //------------------------ One to One -----------------------------------------------------//\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_01_OneProducerGrainOneConsumerGrain() => _runner.StreamTest_01_OneProducerGrainOneConsumerGrain();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_02_OneProducerGrainOneConsumerClient() => _runner.StreamTest_02_OneProducerGrainOneConsumerClient();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_03_OneProducerClientOneConsumerGrain() => _runner.StreamTest_03_OneProducerClientOneConsumerGrain();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_04_OneProducerClientOneConsumerClient() => _runner.StreamTest_04_OneProducerClientOneConsumerClient();\n\n    //------------------------ MANY to Many different grains ----------------------------------//\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains() => _runner.StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_06_ManyDifferent_ManyProducerGrainManyConsumerClients() => _runner.StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_07_ManyDifferent_ManyProducerClientsManyConsumerGrains() => _runner.StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_08_ManyDifferent_ManyProducerClientsManyConsumerClients() => _runner.StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients();\n\n    //------------------------ MANY to Many Same grains ---------------------------------------//\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_09_ManySame_ManyProducerGrainsManyConsumerGrains() => _runner.StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_10_ManySame_ManyConsumerGrainsManyProducerGrains() => _runner.StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_11_ManySame_ManyProducerGrainsManyConsumerClients() => _runner.StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_12_ManySame_ManyProducerClientsManyConsumerGrains() => _runner.StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains();\n\n    //------------------------ MANY to Many producer consumer same grain ----------------------//\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_13_SameGrain_ConsumerFirstProducerLater() => _runner.StreamTest_13_SameGrain_ConsumerFirstProducerLater(false);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_14_SameGrain_ProducerFirstConsumerLater() => _runner.StreamTest_14_SameGrain_ProducerFirstConsumerLater(false);\n\n    //-----------------------------------------------------------------------------------------//\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNet_15_ConsumeAtProducersRequest() => _runner.StreamTest_15_ConsumeAtProducersRequest();\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task AdoNet_16_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n    {\n        var multiRunner = new MultipleStreamsTestRunner(InternalClient, AdoNetStreamProviderName, 16, false);\n\n        await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task AdoNet_17_MultipleStreams_1J_ManyProducerGrainsManyConsumerGrains()\n    {\n        var multiRunner = new MultipleStreamsTestRunner(InternalClient, AdoNetStreamProviderName, 17, false);\n\n        await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(() => HostedCluster.StartAdditionalSilo());\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetStreamsBatchingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Options;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Streaming.AdoNet.Storage;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.General;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StreamingTests;\nusing Xunit.Abstractions;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for SQL Server ADO.NET stream batching functionality.\n/// </summary>\npublic class SqlServerAdoNetStreamsBatchingTests(ITestOutputHelper output) : AdoNetStreamsBatchingTests(new Fixture(AdoNetInvariants.InvariantNameSqlServer), output)\n{\n}\n\n/// <summary>\n/// Tests for MySQL ADO.NET stream batching functionality.\n/// </summary>\npublic class MySqlAdoNetStreamsBatchingTests : AdoNetStreamsBatchingTests\n{\n    public MySqlAdoNetStreamsBatchingTests(ITestOutputHelper output) : base(new Fixture(AdoNetInvariants.InvariantNameMySql), output)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for PostgreSQL ADO.NET stream batching functionality.\n/// </summary>\npublic class PostgreSqlAdoNetStreamsBatchingTests(ITestOutputHelper output) : AdoNetStreamsBatchingTests(new Fixture(AdoNetInvariants.InvariantNamePostgreSql), output)\n{\n}\n\n/// <summary>\n/// Base class for ADO.NET stream batching tests.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetStreamsBatchingTests : StreamBatchingTestRunner, IAsyncLifetime\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private static RelationalStorageForTesting _testing;\n\n    protected AdoNetStreamsBatchingTests(Fixture fixture, ITestOutputHelper output) : base(fixture, output)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n\n    public Task InitializeAsync() => fixture.InitializeAsync();\n\n    public Task DisposeAsync() => fixture.DisposeAsync();\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        private static string _invariant;\n\n        public Fixture(string invariant)\n        {\n            _invariant = invariant;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            // set up the adonet environment before the base initializes\n            _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n            Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n            await base.InitializeAsync();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<TestClientBuilderConfigurator>();\n        }\n\n        private class TestSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder\n                    .AddAdoNetStreams(StreamBatchingTestConst.ProviderName, sb =>\n                    {\n                        sb.ConfigureAdoNet(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.Invariant = _invariant;\n                            options.ConnectionString = _testing.CurrentConnectionString;\n                        }));\n                        sb.ConfigurePullingAgent(ob => ob.Configure(options => options.BatchContainerBatchSize = 10));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n            }\n        }\n\n        private class TestClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddAdoNetStreams(StreamBatchingTestConst.ProviderName, sb =>\n                    {\n                        sb.ConfigureAdoNet(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.Invariant = _invariant;\n                            options.ConnectionString = _testing.CurrentConnectionString;\n                        }));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetSubscriptionMultiplicityTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing MySql.Data.MySqlClient;\nusing Orleans.Streaming.AdoNet.Storage;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.General;\nusing UnitTests.StreamingTests;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for SQL Server ADO.NET subscription multiplicity.\n/// </summary>\npublic class SqlServerAdoNetSubscriptionMultiplicityTests() : AdoNetSubscriptionMultiplicityTests(AdoNetInvariants.InvariantNameSqlServer)\n{\n}\n\n/// <summary>\n/// Tests for MySQL ADO.NET subscription multiplicity.\n/// </summary>\npublic class MySqlAdoNetSubscriptionMultiplicityTests : AdoNetSubscriptionMultiplicityTests\n{\n    public MySqlAdoNetSubscriptionMultiplicityTests() : base(AdoNetInvariants.InvariantNameMySql)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for PostgreSQL ADO.NET subscription multiplicity.\n/// </summary>\npublic class PostgreSqlAdoNetSubscriptionMultiplicityTests() : AdoNetSubscriptionMultiplicityTests(AdoNetInvariants.InvariantNamePostgreSql)\n{\n}\n\n/// <summary>\n/// Base class for ADO.NET subscription multiplicity tests.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class AdoNetSubscriptionMultiplicityTests : TestClusterPerTest\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private const string AdoNetStreamProviderName = \"AdoNet\";\n    private const string StreamNamespace = \"AdoNetSubscriptionMultiplicityTestsNamespace\";\n\n    private static string _invariant;\n\n    private static RelationalStorageForTesting _testing;\n    private SubscriptionMultiplicityTestRunner _runner;\n\n    protected AdoNetSubscriptionMultiplicityTests(string invariant)\n    {\n        _invariant = invariant;\n        RelationalStorageForTesting.CheckPreconditionsOrThrow(_invariant);\n    }\n\n    public override async Task InitializeAsync()\n    {\n        // set up the adonet environment before the base initializes\n        _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n        Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        // base initialization must only happen after the above\n        await base.InitializeAsync();\n\n        // the runner must only be created after base initialization\n        _runner = new SubscriptionMultiplicityTestRunner(AdoNetStreamProviderName, HostedCluster);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<TestClientBuilderConfigurator>();\n    }\n\n    private class TestClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder\n                .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                {\n                    options.Invariant = _invariant;\n                    options.ConnectionString = _testing.CurrentConnectionString;\n                });\n        }\n    }\n\n    private class TestSiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n            siloBuilder\n                .AddAdoNetStreams(AdoNetStreamProviderName, options =>\n                {\n                    options.Invariant = _invariant;\n                    options.ConnectionString = _testing.CurrentConnectionString;\n                })\n                .AddMemoryGrainStorage(\"PubSubStore\");\n        }\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetMultipleParallelSubscriptionTest() => _runner.MultipleParallelSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetMultipleLinearSubscriptionTest() => _runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetMultipleSubscriptionTest_AddRemove() => _runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetResubscriptionTest() => _runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetResubscriptionAfterDeactivationTest() => _runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetActiveSubscriptionTest() => _runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetTwoIntermittentStreamTest() => _runner.TwoIntermitentStreamTest(Guid.NewGuid());\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public Task AdoNetSubscribeFromClientTest() => _runner.SubscribeFromClientTest(Guid.NewGuid(), StreamNamespace);\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/AdoNetSubscriptionObserverWithImplicitSubscribingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Options;\nusing MySql.Data.MySqlClient;\nusing Orleans.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.Tests.SqlUtils;\nusing Tester.StreamingTests.ProgrammaticSubscribeTests;\nusing TestExtensions;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests for SQL Server ADO.NET subscription observer with implicit subscribing.\n/// </summary>\npublic class SqlServerAdoNetSubscriptionObserverWithImplicitSubscribingTests() : AdoNetSubscriptionObserverWithImplicitSubscribingTests(new Fixture(AdoNetInvariants.InvariantNameSqlServer))\n{\n}\n\n/// <summary>\n/// Tests for MySQL ADO.NET subscription observer with implicit subscribing.\n/// </summary>\npublic class MySqlAdoNetSubscriptionObserverWithImplicitSubscribingTests : AdoNetSubscriptionObserverWithImplicitSubscribingTests\n{\n    public MySqlAdoNetSubscriptionObserverWithImplicitSubscribingTests() : base(new Fixture(AdoNetInvariants.InvariantNameMySql))\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests for PostgreSQL ADO.NET subscription observer with implicit subscribing.\n/// </summary>\npublic class PostgreSqlAdoNetSubscriptionObserverWithImplicitSubscribingTests() : AdoNetSubscriptionObserverWithImplicitSubscribingTests(new Fixture(AdoNetInvariants.InvariantNamePostgreSql))\n{\n}\n\n/// <summary>\n/// Base class for ADO.NET subscription observer with implicit subscribing tests.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\npublic abstract class AdoNetSubscriptionObserverWithImplicitSubscribingTests(AdoNetSubscriptionObserverWithImplicitSubscribingTests.Fixture fixture) : SubscriptionObserverWithImplicitSubscribingTestRunner(fixture), IAsyncLifetime\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n    private static RelationalStorageForTesting _testing;\n    private readonly Fixture _fixture = fixture;\n\n    public async Task InitializeAsync()\n    {\n        await _fixture.InitializeAsync();\n\n        _fixture.EnsurePreconditionsMet();\n    }\n\n    public Task DisposeAsync() => _fixture.DisposeAsync();\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        private static string _invariant;\n\n        public Fixture(string invariant)\n        {\n            _invariant = invariant;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            // set up the adonet environment before the base initializes\n            _testing = await RelationalStorageForTesting.SetupInstance(_invariant, TestDatabaseName);\n\n            Skip.If(IsNullOrEmpty(_testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n            await base.InitializeAsync();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n            builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n        }\n\n        private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder\n                    .AddAdoNetStreams(StreamProviderName, sb =>\n                    {\n                        sb.ConfigureAdoNet(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.Invariant = _invariant;\n                            options.ConnectionString = _testing.CurrentConnectionString;\n                        }));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    })\n                    .AddAdoNetStreams(StreamProviderName2, sb =>\n                    {\n                        sb.ConfigureAdoNet(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.Invariant = _invariant;\n                            options.ConnectionString = _testing.CurrentConnectionString;\n                        }));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    })\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.AdoNet.Tests/Streaming/RelationalOrleansQueriesTests.cs",
    "content": "using System.Collections.Concurrent;\nusing MySql.Data.MySqlClient;\nusing Npgsql;\nusing Orleans.Configuration;\nusing Orleans.Streaming.AdoNet;\nusing Orleans.Streaming.AdoNet.Storage;\nusing UnitTests.General;\nusing static System.String;\n\nnamespace Tester.AdoNet.Streaming;\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against Sql Server.\n/// </summary>\npublic class SqlServerRelationalOrleansQueriesTests() : RelationalOrleansQueriesTests(AdoNetInvariants.InvariantNameSqlServer, 90)\n{\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against MySQL.\n/// </summary>\npublic class MySqlRelationalOrleansQueriesTests : RelationalOrleansQueriesTests\n{\n    public MySqlRelationalOrleansQueriesTests() : base(AdoNetInvariants.InvariantNameMySql, 100)\n    {\n        MySqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/> against PostgreSQL.\n/// </summary>\npublic class PostgreSqlRelationalOrleansQueriesTests : RelationalOrleansQueriesTests\n{\n    public PostgreSqlRelationalOrleansQueriesTests() : base(AdoNetInvariants.InvariantNamePostgreSql, 99)\n    {\n        NpgsqlConnection.ClearAllPools();\n    }\n}\n\n/// <summary>\n/// Tests the relational storage layer via <see cref=\"RelationalOrleansQueries\"/>.\n/// </summary>\n[TestCategory(\"AdoNet\"), TestCategory(\"Streaming\")]\npublic abstract class RelationalOrleansQueriesTests(string invariant, int concurrency = 100) : IAsyncLifetime\n{\n    private const string TestDatabaseName = \"OrleansStreamTest\";\n\n    private IRelationalStorage _storage;\n    private RelationalOrleansQueries _queries;\n\n    public async Task InitializeAsync()\n    {\n        var testing = await RelationalStorageForTesting.SetupInstance(invariant, TestDatabaseName);\n        Skip.If(IsNullOrEmpty(testing.CurrentConnectionString), $\"Database '{TestDatabaseName}' not initialized\");\n\n        _storage = RelationalStorage.CreateInstance(invariant, testing.CurrentConnectionString);\n\n        _queries = await RelationalOrleansQueries.CreateInstance(invariant, testing.CurrentConnectionString);\n    }\n\n    private static string RandomServiceId(int max = 10) => $\"ServiceId{Random.Shared.Next(max)}\";\n\n    private static string RandomProviderId(int max = 10) => $\"ProviderId{Random.Shared.Next(max)}\";\n\n    private static string RandomQueueId(int max = 10) => $\"QueueId{Random.Shared.Next(max)}\";\n\n    private static int RandomExpiryTimeout(int max = 100) => Random.Shared.Next(max);\n\n    private static byte[] RandomPayload(int size = 1_000_000)\n    {\n        var payload = new byte[size];\n        Random.Shared.NextBytes(payload);\n        return payload;\n    }\n\n    public Task DisposeAsync() => Task.CompletedTask;\n\n    /// <summary>\n    /// Tests that a single message is queued.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_QueuesMessage()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var expiryTimeout = RandomExpiryTimeout();\n        var payload = RandomPayload();\n\n        // act\n        var before = DateTime.UtcNow.AddSeconds(-1);\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n        var after = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - ack\n        Assert.NotNull(ack);\n        Assert.Equal(serviceId, ack.ServiceId);\n        Assert.Equal(providerId, ack.ProviderId);\n        Assert.Equal(queueId, ack.QueueId);\n        Assert.Equal(1, ack.MessageId);\n\n        // assert - storage\n        var messages = await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\");\n        var message = Assert.Single(messages);\n        Assert.Equal(serviceId, message.ServiceId);\n        Assert.Equal(providerId, message.ProviderId);\n        Assert.Equal(queueId, message.QueueId);\n        Assert.Equal(ack.MessageId, message.MessageId);\n        Assert.Equal(0, message.Dequeued);\n        Assert.True(message.VisibleOn >= before);\n        Assert.True(message.VisibleOn <= after);\n        Assert.True(message.ExpiresOn >= before.AddSeconds(expiryTimeout));\n        Assert.True(message.ExpiresOn <= after.AddSeconds(expiryTimeout));\n        Assert.Equal(message.VisibleOn, message.CreatedOn);\n        Assert.Equal(message.VisibleOn, message.ModifiedOn);\n        Assert.Equal(payload, message.Payload);\n    }\n\n    /// <summary>\n    /// Tests that many messages are queued in parallel on the same queue.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_QueuesManyMessagesInParallel()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var expiryTimeout = RandomExpiryTimeout();\n        var payload = RandomPayload(1000);\n        var count = 10000;\n\n        // this keeps requests under the default connection pool limit to avoid flaky tests due to connection timeouts\n        using var semaphore = new SemaphoreSlim(concurrency);\n\n        // act\n        var before = DateTime.UtcNow.AddSeconds(-1);\n        var acks = await Task.WhenAll(Enumerable\n            .Range(0, count)\n            .Select(i => Task.Run(async () =>\n            {\n                await semaphore.WaitAsync();\n                try\n                {\n                    return await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n                }\n                finally\n                {\n                    semaphore.Release();\n                }\n            }))\n            .ToList());\n        var after = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - messages were inserted in sequence.\n        var ordered = acks\n            .OrderBy(x => x.ServiceId)\n            .ThenBy(x => x.ProviderId)\n            .ThenBy(x => x.QueueId)\n            .ThenBy(x => x.MessageId)\n            .ToList();\n        var messageId = ordered[0].MessageId;\n        for (var i = 0; i < count; i++)\n        {\n            Assert.Equal(serviceId, ordered[i].ServiceId);\n            Assert.Equal(providerId, ordered[i].ProviderId);\n            Assert.Equal(queueId, ordered[i].QueueId);\n            Assert.Equal(messageId++, ordered[i].MessageId);\n        }\n\n        // assert - messages were stored as expected\n        var stored = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"))\n            .OrderBy(x => x.ServiceId)\n            .ThenBy(x => x.ProviderId)\n            .ThenBy(x => x.QueueId)\n            .ThenBy(x => x.MessageId)\n            .ToList();\n        for (var i = 0; i < count; i++)\n        {\n            Assert.Equal(ordered[i].ServiceId, stored[i].ServiceId);\n            Assert.Equal(ordered[i].ProviderId, stored[i].ProviderId);\n            Assert.Equal(ordered[i].QueueId, stored[i].QueueId);\n            Assert.Equal(ordered[i].MessageId, stored[i].MessageId);\n            Assert.Equal(0, stored[i].Dequeued);\n            Assert.True(stored[i].VisibleOn >= before);\n            Assert.True(stored[i].VisibleOn <= after);\n            Assert.True(stored[i].ExpiresOn >= before.AddSeconds(expiryTimeout));\n            Assert.True(stored[i].ExpiresOn <= after.AddSeconds(expiryTimeout));\n            Assert.Equal(stored[i].VisibleOn, stored[i].CreatedOn);\n            Assert.Equal(stored[i].VisibleOn, stored[i].ModifiedOn);\n            Assert.Equal(payload, stored[i].Payload);\n        }\n    }\n\n    /// <summary>\n    /// Tests that many messages are queued in parallel on many queues.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_QueuesManyMessagesInParallelOnManyQueues()\n    {\n        // arrange - create up to 27 random partition keys with around 1000 random messages per partition in random order\n        var expiryTimeout = RandomExpiryTimeout();\n        var count = 3 * 3 * 3 * 1000;\n        var partitions = Enumerable\n            .Range(0, count)\n            .Select(i =>\n            (\n                ServiceId: RandomServiceId(3),\n                ProviderId: RandomProviderId(3),\n                QueueId: RandomQueueId(3),\n                Payload: RandomPayload(1000)\n            ))\n            .ToList();\n\n        // this keeps requests under the default connection pool limit to avoid flaky tests due to connection timeouts\n        using var semaphore = new SemaphoreSlim(concurrency);\n\n        // act - queue the random messages in parallel\n        var before = DateTime.UtcNow.AddSeconds(-1);\n        var results = await Task.WhenAll(partitions\n            .Select(p => Task.Run(async () =>\n            {\n                await semaphore.WaitAsync();\n                try\n                {\n                    var ack = await _queries.QueueStreamMessageAsync(p.ServiceId, p.ProviderId, p.QueueId, p.Payload, expiryTimeout);\n                    return (Partition: p, Ack: ack);\n                }\n                finally\n                {\n                    semaphore.Release();\n                }\n            }))\n            .ToList());\n        var after = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - all messages were acknowledged\n        var messageIds = new SortedSet<long>();\n        foreach (var (partition, ack) in results)\n        {\n            Assert.Equal(ack.ServiceId, partition.ServiceId);\n            Assert.Equal(ack.ProviderId, partition.ProviderId);\n            Assert.Equal(ack.QueueId, partition.QueueId);\n            Assert.True(messageIds.Add(ack.MessageId), $\"Duplicate {ack.MessageId}\");\n        }\n\n        // assert - generated message ids are consistent\n        Assert.Equal(count, messageIds.Count);\n        Assert.Equal(1, messageIds.Min);\n        Assert.Equal(messageIds.Count, messageIds.Max);\n\n        // assert - messages were stored as expected\n        var stored = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"))\n            .ToDictionary(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId));\n\n        foreach (var (partition, ack) in results)\n        {\n            Assert.True(stored.TryGetValue((ack.ServiceId, ack.ProviderId, ack.QueueId, ack.MessageId), out var message), $\"Message not found in storage\");\n\n            Assert.Equal(0, message.Dequeued);\n            Assert.True(message.VisibleOn >= before);\n            Assert.True(message.VisibleOn <= after);\n            Assert.True(message.ExpiresOn >= before.AddSeconds(expiryTimeout));\n            Assert.True(message.ExpiresOn <= after.AddSeconds(expiryTimeout));\n            Assert.Equal(message.VisibleOn, message.CreatedOn);\n            Assert.Equal(message.VisibleOn, message.ModifiedOn);\n            Assert.Equal(partition.Payload, message.Payload);\n\n            stored.Remove((ack.ServiceId, ack.ProviderId, ack.QueueId, ack.MessageId));\n        }\n    }\n\n    /// <summary>\n    /// Tests that a single message is dequeued correctly.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DequeuesSingleMessage()\n    {\n        // arrange\n        await _storage.ExecuteAsync(\"DELETE FROM OrleansStreamMessage\");\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 1;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n\n        // arrange - enqueue a message\n        var beforeQueueing = DateTime.UtcNow.AddSeconds(-1);\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n        var afterQueueing = DateTime.UtcNow.AddSeconds(1);\n\n        // act - dequeue a message\n        var beforeDequeuing = DateTime.UtcNow.AddSeconds(-1);\n        var message = Assert.Single(await _queries.GetStreamMessagesAsync(\n            serviceId,\n            providerId,\n            queueId,\n            maxCount,\n            maxAttempts,\n            visibilityTimeout,\n            removalTimeout,\n            evictionInterval,\n            evictionBatchSize));\n        var afterDequeuing = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - the message is the same\n        Assert.Equal(ack.ServiceId, message.ServiceId);\n        Assert.Equal(ack.ProviderId, message.ProviderId);\n        Assert.Equal(ack.QueueId, message.QueueId);\n        Assert.Equal(ack.MessageId, message.MessageId);\n        Assert.Equal(1, message.Dequeued);\n        Assert.True(message.VisibleOn >= beforeDequeuing.AddSeconds(visibilityTimeout));\n        Assert.True(message.VisibleOn <= afterDequeuing.AddSeconds(visibilityTimeout));\n        Assert.True(message.ExpiresOn >= beforeQueueing.AddSeconds(expiryTimeout));\n        Assert.True(message.ExpiresOn <= afterQueueing.AddSeconds(expiryTimeout));\n        Assert.True(message.CreatedOn >= beforeQueueing);\n        Assert.True(message.CreatedOn <= afterQueueing);\n        Assert.True(message.ModifiedOn >= beforeDequeuing);\n        Assert.True(message.ModifiedOn <= afterDequeuing);\n        Assert.Equal(payload, message.Payload);\n\n        // assert - the stored message changed\n        var stored = Assert.Single(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n        Assert.Equal(message.ServiceId, stored.ServiceId);\n        Assert.Equal(message.ProviderId, stored.ProviderId);\n        Assert.Equal(message.QueueId, stored.QueueId);\n        Assert.Equal(message.MessageId, stored.MessageId);\n        Assert.Equal(message.Dequeued, stored.Dequeued);\n        Assert.Equal(message.VisibleOn, stored.VisibleOn);\n        Assert.Equal(message.ExpiresOn, stored.ExpiresOn);\n        Assert.Equal(message.CreatedOn, stored.CreatedOn);\n        Assert.Equal(message.ModifiedOn, stored.ModifiedOn);\n        Assert.Equal(message.Payload, stored.Payload);\n    }\n\n    /// <summary>\n    /// Tests that messages are dequeued in a batch.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DequeuesMessageBatches()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 3;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n        var total = 5;\n\n        // arrange - enqueue five messages\n        var beforeQueueing = DateTime.UtcNow.AddSeconds(-1);\n        var acks = await Task.WhenAll(Enumerable\n            .Range(0, total)\n            .Select(i => _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout))\n            .ToList());\n        var afterQueueing = DateTime.UtcNow.AddSeconds(1);\n\n        // act - dequeue three batches of three messages\n        var beforeDequeuing = DateTime.UtcNow.AddSeconds(-1);\n        var first = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n        var second = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n        var third = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n        var afterDequeuing = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - batch counts\n        Assert.Equal(maxCount, first.Count);\n        Assert.Equal(total - maxCount, second.Count);\n        Assert.Empty(third);\n\n        // assert - dequeued messages are consistent with acks\n        var ackLookup = acks.ToDictionary(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId));\n        var messages = first.Concat(second).Concat(third).ToList();\n        foreach (var message in messages)\n        {\n            Assert.True(ackLookup.TryGetValue((message.ServiceId, message.ProviderId, message.QueueId, message.MessageId), out var ack), \"Ack not found\");\n            Assert.Equal(ack.ServiceId, message.ServiceId);\n            Assert.Equal(ack.ProviderId, message.ProviderId);\n            Assert.Equal(ack.QueueId, message.QueueId);\n            Assert.Equal(ack.MessageId, message.MessageId);\n            Assert.Equal(1, message.Dequeued);\n            Assert.True(message.VisibleOn >= beforeDequeuing.AddSeconds(visibilityTimeout));\n            Assert.True(message.VisibleOn <= afterDequeuing.AddSeconds(visibilityTimeout));\n            Assert.True(message.ExpiresOn >= beforeQueueing.AddSeconds(expiryTimeout));\n            Assert.True(message.ExpiresOn <= afterQueueing.AddSeconds(expiryTimeout));\n            Assert.True(message.CreatedOn >= beforeQueueing);\n            Assert.True(message.CreatedOn <= afterQueueing);\n            Assert.True(message.ModifiedOn >= beforeDequeuing);\n            Assert.True(message.ModifiedOn <= afterDequeuing);\n            Assert.Equal(payload, message.Payload);\n\n            ackLookup.Remove((message.ServiceId, message.ProviderId, message.QueueId, message.MessageId));\n        }\n\n        // assert - stored messages are consistent with dequeued messages\n        var messageLookup = messages.ToDictionary(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId));\n        var stored = await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\");\n        foreach (var item in stored)\n        {\n            Assert.True(messageLookup.TryGetValue((item.ServiceId, item.ProviderId, item.QueueId, item.MessageId), out var message), \"Message not found\");\n\n            Assert.Equal(message.ServiceId, item.ServiceId);\n            Assert.Equal(message.ProviderId, item.ProviderId);\n            Assert.Equal(message.QueueId, item.QueueId);\n            Assert.Equal(message.MessageId, item.MessageId);\n            Assert.Equal(message.Dequeued, item.Dequeued);\n            Assert.Equal(message.VisibleOn, item.VisibleOn);\n            Assert.Equal(message.ExpiresOn, item.ExpiresOn);\n            Assert.Equal(message.CreatedOn, item.CreatedOn);\n            Assert.Equal(message.ModifiedOn, item.ModifiedOn);\n            Assert.Equal(message.Payload, item.Payload);\n        }\n    }\n\n    /// <summary>\n    /// Tests that a single message is re-dequeued after visibility timeout until max attempts.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DequeuesSingleMessageAgainAfterVisibilityTimeout()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 1;\n        var maxAttempts = 3;\n        var visibilityTimeout = 0;\n        var removalTimeout = 100;\n        var evictionInterval = 100;\n        var evictionBatchSize = 0;\n\n        // arrange - enqueue a message\n        var beforeQueueing = DateTime.UtcNow.AddSeconds(-1);\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n        var afterQueueing = DateTime.UtcNow.AddSeconds(1);\n\n        // act - dequeue messages until max attempts plus one\n        var beforeDequeuing = DateTime.UtcNow.AddSeconds(-1);\n        var results = new List<IList<AdoNetStreamMessage>>();\n        for (var i = 0; i < maxAttempts + 1; i++)\n        {\n            results.Add(await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize));\n        }\n        var afterDequeuing = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - batches are as expected\n        for (var i = 0; i < maxAttempts; i++)\n        {\n            var message = Assert.Single(results[i]);\n\n            Assert.Equal(ack.ServiceId, message.ServiceId);\n            Assert.Equal(ack.ProviderId, message.ProviderId);\n            Assert.Equal(ack.QueueId, message.QueueId);\n            Assert.Equal(ack.MessageId, message.MessageId);\n            Assert.Equal(i + 1, message.Dequeued);\n            Assert.True(message.VisibleOn >= beforeDequeuing.AddSeconds(visibilityTimeout));\n            Assert.True(message.VisibleOn <= afterDequeuing.AddSeconds(visibilityTimeout));\n            Assert.True(message.ExpiresOn >= beforeQueueing.AddSeconds(expiryTimeout));\n            Assert.True(message.ExpiresOn <= afterQueueing.AddSeconds(expiryTimeout));\n            Assert.True(message.CreatedOn >= beforeQueueing);\n            Assert.True(message.CreatedOn <= afterQueueing);\n            Assert.True(message.ModifiedOn >= beforeDequeuing);\n            Assert.True(message.ModifiedOn <= afterDequeuing);\n            Assert.Equal(payload, message.Payload);\n        }\n\n        // assert - final batch is empty\n        Assert.Empty(results[maxAttempts]);\n\n        // assert - final stored message is consistent with final dequeued message\n        var stored = Assert.Single(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n        var final = Assert.Single(results[maxAttempts - 1]);\n        Assert.Equal(final.ServiceId, stored.ServiceId);\n        Assert.Equal(final.ProviderId, stored.ProviderId);\n        Assert.Equal(final.QueueId, stored.QueueId);\n        Assert.Equal(final.MessageId, stored.MessageId);\n        Assert.Equal(final.Dequeued, stored.Dequeued);\n        Assert.Equal(final.VisibleOn, stored.VisibleOn);\n        Assert.Equal(final.ExpiresOn, stored.ExpiresOn);\n        Assert.Equal(final.CreatedOn, stored.CreatedOn);\n        Assert.Equal(final.ModifiedOn, stored.ModifiedOn);\n        Assert.Equal(final.Payload, stored.Payload);\n    }\n\n    /// <summary>\n    /// Tests that a single message is not dequeued again before the visibility timeout.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DoesNotDequeueSingleMessageBeforeVisibilityTimeout()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 3;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n\n        // arrange - enqueue a message\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n\n        // act - dequeue messages\n        var first = Assert.Single(await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize));\n        var second = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n\n        // assert - first dequeued message is consistent with ack\n        Assert.Equal(ack.ServiceId, first.ServiceId);\n        Assert.Equal(ack.ProviderId, first.ProviderId);\n        Assert.Equal(ack.QueueId, first.QueueId);\n        Assert.Equal(ack.MessageId, first.MessageId);\n\n        // assert - stored message is consistent with first message\n        var stored = Assert.Single(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n        Assert.Equal(first.ServiceId, stored.ServiceId);\n        Assert.Equal(first.ProviderId, stored.ProviderId);\n        Assert.Equal(first.QueueId, stored.QueueId);\n        Assert.Equal(first.MessageId, stored.MessageId);\n        Assert.Equal(first.Dequeued, stored.Dequeued);\n        Assert.Equal(first.VisibleOn, stored.VisibleOn);\n        Assert.Equal(first.ExpiresOn, stored.ExpiresOn);\n        Assert.Equal(first.CreatedOn, stored.CreatedOn);\n        Assert.Equal(first.ModifiedOn, stored.ModifiedOn);\n        Assert.Equal(first.Payload, stored.Payload);\n\n        // assert - message not dequeued again\n        Assert.Empty(second);\n    }\n\n    /// <summary>\n    /// Tests that a single message is not dequeued again after expiry\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DoesNotDequeueSingleMessageAfterExpiry()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 0;\n        var maxCount = 3;\n        var maxAttempts = 3;\n        var visibilityTimeout = 0;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 0;\n\n        // arrange - enqueue a message\n        var before = DateTime.UtcNow.AddSeconds(-1);\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout);\n        var after = DateTime.UtcNow.AddSeconds(1);\n\n        // act - dequeue messages\n        var messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n\n        // assert - no messages dequeued\n        Assert.Empty(messages);\n\n        // assert - stored message are as expected\n        var stored = Assert.Single(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n        Assert.Equal(ack.ServiceId, stored.ServiceId);\n        Assert.Equal(ack.ProviderId, stored.ProviderId);\n        Assert.Equal(ack.QueueId, stored.QueueId);\n        Assert.Equal(ack.MessageId, stored.MessageId);\n        Assert.Equal(0, stored.Dequeued);\n        Assert.True(stored.VisibleOn >= before);\n        Assert.True(stored.VisibleOn <= after);\n        Assert.True(stored.ExpiresOn >= before);\n        Assert.True(stored.ExpiresOn <= after);\n        Assert.True(stored.CreatedOn >= before);\n        Assert.True(stored.CreatedOn <= after);\n        Assert.True(stored.ModifiedOn >= before);\n        Assert.True(stored.ModifiedOn <= after);\n        Assert.Equal(payload, stored.Payload);\n    }\n\n    /// <summary>\n    /// Tests that messages can be confirmed.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_ConfirmsMessages()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 10;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n\n        // arrange - enqueue many messages\n        var acks = await Task.WhenAll(Enumerable\n            .Range(0, maxCount)\n            .Select(i => _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout))\n            .ToList());\n\n        // arrange - dequeue all messages\n        var messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n\n        // act - confirm all messages\n        var items = messages.Select(x => new AdoNetStreamConfirmation(x.MessageId, x.Dequeued)).ToList();\n        var results = await _queries.ConfirmStreamMessagesAsync(serviceId, providerId, queueId, items);\n\n        // assert - confirmations are as expected\n        Assert.Equal(maxCount, acks.Length);\n        Assert.Equal(maxCount, messages.Count);\n        Assert.Equal(maxCount, results.Count);\n\n        var lookup = acks.Select(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId)).ToHashSet();\n        foreach (var result in results)\n        {\n            Assert.True(lookup.Remove((result.ServiceId, result.ProviderId, result.QueueId, result.MessageId)), \"Unexpected Confirmation\");\n        }\n\n        // assert - no data remains in storage\n        var stored = await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\");\n        Assert.Empty(stored);\n    }\n\n    /// <summary>\n    /// Tests that messages are not confirmed if the receipt is incorrect.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DoesNotConfirmMessagesWithWrongReceipt()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload();\n        var expiryTimeout = 100;\n        var maxCount = 10;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n\n        // arrange - enqueue many messages\n        var acks = await Task.WhenAll(Enumerable\n            .Range(0, maxCount)\n            .Select(i => _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout))\n            .ToList());\n\n        // arrange - dequeue all messages\n        var messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n\n        // act - confirm all messages in a faulty way\n        var faulty = messages.Select(x => new AdoNetStreamConfirmation(x.MessageId, x.Dequeued - 1)).ToList();\n        var results = await _queries.ConfirmStreamMessagesAsync(serviceId, providerId, queueId, faulty);\n\n        // assert - confirmations are as expected\n        Assert.Equal(maxCount, acks.Length);\n        Assert.Equal(maxCount, messages.Count);\n        Assert.Empty(results);\n\n        // assert - data remains in storage\n        var stored = await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\");\n        Assert.Equal(maxCount, stored.Count());\n    }\n\n    /// <summary>\n    /// Chaos tests that some messages can be confirmed while others are not.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_ConfirmsSomeMessagesAndNotOthers()\n    {\n        // arrange\n        var serviceId = RandomServiceId();\n        var providerId = RandomProviderId();\n        var queueId = RandomQueueId();\n        var payload = RandomPayload(1000);\n        var expiryTimeout = 100;\n        var maxCount = 100;\n        var maxAttempts = 3;\n        var visibilityTimeout = 10;\n        var removalTimeout = 100;\n        var evictionInterval = 10;\n        var evictionBatchSize = 1000;\n        var partial = 30;\n\n        // arrange - enqueue many messages\n        var acks = await Task.WhenAll(Enumerable\n            .Range(0, maxCount)\n            .Select(i => _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, expiryTimeout))\n            .ToList());\n\n        // arrange - dequeue all the messages\n        var messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n\n        // act - confirm some of the messages at random\n        var completed = Randomize(messages).Take(partial).Select(x => new AdoNetStreamConfirmation(x.MessageId, x.Dequeued)).ToList();\n        var confirmed = await _queries.ConfirmStreamMessagesAsync(serviceId, providerId, queueId, completed);\n\n        // assert - counts are as expected\n        Assert.Equal(maxCount, acks.Length);\n        Assert.Equal(maxCount, messages.Count);\n        Assert.Equal(partial, confirmed.Count);\n\n        // assert - confirmed messages are as expected\n        var lookup = acks.ToDictionary(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId));\n        var stored = (await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"))\n            .ToDictionary(x => (x.ServiceId, x.ProviderId, x.QueueId, x.MessageId));\n        foreach (var item in confirmed)\n        {\n            Assert.True(lookup.Remove((item.ServiceId, item.ProviderId, item.QueueId, item.MessageId)), \"Unexpected Confirmation\");\n            Assert.False(stored.TryGetValue((item.ServiceId, item.ProviderId, item.QueueId, item.MessageId), out _), \"Message still in storage\");\n        }\n\n        // assert - unconfirmed messages remain in storage\n        Assert.Equal(maxCount - partial, stored.Count);\n        Assert.Equal(lookup.Keys.Order(), stored.Keys.Order());\n    }\n\n    /// <summary>\n    /// Chaos tests that queuing, dequeuing, confirmation and eviction work in parallel in a complex random scenario.\n    /// This looks for concurrent brittleness, especially proneness to database deadlocks, rather than a specific condition.\n    /// If this test faults due to deadlocks then there is likely some issue with the implementation that needs investigation.\n    /// </summary>\n    /// <remarks>\n    /// At early dev time, this test consistently induced deadlocks until the underlying queries were perfected.\n    /// This is an expensive test to run but can protect against query regression.\n    /// For MySQL in particular, this test also detected deadlocks with the driver connection pool itself, which required a package upgrade.\n    /// See: https://bugs.mysql.com/bug.php?id=114272\n    /// </remarks>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_ChaosTest()\n    {\n        // arrange - generate test data\n        var total = 10000;\n        var serviceIds = Enumerable.Range(0, 3).Select(x => $\"ServiceId{x}\").ToList();\n        var providerIds = Enumerable.Range(0, 3).Select(x => $\"ProviderId{x}\").ToList();\n        var queueIds = Enumerable.Range(0, 3).Select(x => $\"QueueId{x}\").ToList();\n        var payload = RandomPayload(1000);\n        var maxCount = 10;\n        var maxAttempts = 3;\n        var visibilityTimeout = 1;\n        var removalTimeout = 1;\n        var evictionInterval = 1;\n        var evictionBatchSize = 1000;\n\n        // this keeps requests under the default connection pool limit to avoid flaky tests due to connection timeouts\n        using var semaphore = new SemaphoreSlim(concurrency);\n\n        // act - chaos enqueue, dequeue, confirm\n        // the tasks below are not expected to result in a planned outcome but are expected to result in a consistent one\n        var acks = new ConcurrentBag<AdoNetStreamMessageAck>();\n        var dequeued1 = new ConcurrentBag<AdoNetStreamMessage>();\n        var dequeued2 = new ConcurrentBag<AdoNetStreamMessage>();\n        var confirmed = new ConcurrentBag<AdoNetStreamConfirmationAck>();\n        await Task.WhenAll(Enumerable\n            .Range(0, total)\n            .Select(async i =>\n            {\n                // spin up a random enqueuing task\n                var enqueue = Task.Run(async () =>\n                {\n                    var serviceId = serviceIds[Random.Shared.Next(serviceIds.Count)];\n                    var providerId = providerIds[Random.Shared.Next(providerIds.Count)];\n                    var queueId = queueIds[Random.Shared.Next(queueIds.Count)];\n\n                    AdoNetStreamMessageAck ack;\n                    await semaphore.WaitAsync();\n                    try\n                    {\n                        ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, visibilityTimeout);\n                    }\n                    finally\n                    {\n                        semaphore.Release();\n                    }\n\n                    acks.Add(ack);\n                });\n\n                // spin up a random dequeuing task that does not confirm\n                var dequeue = Task.Run(async () =>\n                {\n                    var serviceId = serviceIds[Random.Shared.Next(serviceIds.Count)];\n                    var providerId = providerIds[Random.Shared.Next(providerIds.Count)];\n                    var queueId = queueIds[Random.Shared.Next(queueIds.Count)];\n\n                    IEnumerable<AdoNetStreamMessage> messages;\n                    await semaphore.WaitAsync();\n                    try\n                    {\n                        messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n                    }\n                    finally\n                    {\n                        semaphore.Release();\n                    }\n\n                    foreach (var item in messages)\n                    {\n                        dequeued1.Add(item);\n                    }\n                });\n\n                // spin a random dequeuing task that also confirms\n                var confirm = Task.Run(async () =>\n                {\n                    var serviceId = serviceIds[Random.Shared.Next(serviceIds.Count)];\n                    var providerId = providerIds[Random.Shared.Next(providerIds.Count)];\n                    var queueId = queueIds[Random.Shared.Next(queueIds.Count)];\n\n                    IEnumerable<AdoNetStreamMessage> messages;\n                    await semaphore.WaitAsync();\n                    try\n                    {\n                        messages = await _queries.GetStreamMessagesAsync(serviceId, providerId, queueId, maxCount, maxAttempts, visibilityTimeout, removalTimeout, evictionInterval, evictionBatchSize);\n                    }\n                    finally\n                    {\n                        semaphore.Release();\n                    }\n\n                    foreach (var item in messages)\n                    {\n                        dequeued2.Add(item);\n                    }\n\n                    IEnumerable<AdoNetStreamConfirmationAck> confirmation;\n                    await semaphore.WaitAsync();\n                    try\n                    {\n                        confirmation = await _queries.ConfirmStreamMessagesAsync(serviceId, providerId, queueId, messages.Select(x => new AdoNetStreamConfirmation(x.MessageId, x.Dequeued)).ToList());\n                    }\n                    finally\n                    {\n                        semaphore.Release();\n                    }\n\n                    foreach (var item in confirmation)\n                    {\n                        confirmed.Add(item);\n                    }\n                });\n\n                // wait for all to complete\n                await Task.WhenAll(enqueue, dequeue, confirm);\n            })\n            .ToList());\n\n        // assert - all messages were enqueued\n        Assert.Equal(total, acks.Count);\n\n        // assert - some messages were dequeued (rng dependant, remove assert if flaky)\n        Assert.NotEmpty(dequeued1);\n        Assert.NotEmpty(dequeued2);\n\n        // assert - some messages were confirmed (rng dependant, remove assert if flaky)\n        Assert.NotEmpty(confirmed);\n\n        // assert - some messages were left behind (rng dependant, remove assert if flaky)\n        var stored = await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\");\n        Assert.NotEmpty(stored);\n\n        // assert - confirmed messages were not left behind\n        Assert.Empty(confirmed.IntersectBy(stored.Select(x => x.MessageId), x => x.MessageId));\n\n        // assert - confirmed messages all match acks\n        Assert.Empty(confirmed.ExceptBy(acks.Select(x => x.MessageId), x => x.MessageId));\n    }\n\n    /// <summary>\n    /// Tests that a poisoned message can be moved to dead letters.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_MovesPoisonedMessageToDeadLetters()\n    {\n        // arrange\n        var serviceId = \"ServiceId\";\n        var providerId = \"ProviderId\";\n        var streamOptions = new AdoNetStreamOptions();\n        var cacheOptions = new SimpleQueueCacheOptions();\n\n        // arrange - queue an expired message\n        var queueId = \"QueueId\";\n        var payload = new byte[] { 0xFF };\n\n        var beforeQueued = DateTime.UtcNow.AddSeconds(-1);\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());\n        var afterQueued = DateTime.UtcNow.AddSeconds(1);\n\n        // arrange - dequeue the message and make immediately available\n        var beforeDequeued = DateTime.UtcNow.AddSeconds(-1);\n        await _queries.GetStreamMessagesAsync(ack.ServiceId, ack.ProviderId, ack.QueueId, cacheOptions.CacheSize, streamOptions.MaxAttempts, 0, streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling(), streamOptions.EvictionInterval.TotalSecondsCeiling(), streamOptions.EvictionBatchSize);\n        var afterDequeued = DateTime.UtcNow.AddSeconds(1);\n\n        // act - clean up with max attempts of one so the message above is flagged\n        var beforeFailure = DateTime.UtcNow.AddSeconds(-1);\n        await _queries.FailStreamMessageAsync(ack.ServiceId, ack.ProviderId, ack.QueueId, ack.MessageId, 1, streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling());\n        var afterFailure = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - message no longer in the message table\n        Assert.Empty(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n\n        // assert - message was moved\n        var dead = Assert.Single(await _storage.ReadAsync<AdoNetStreamDeadLetter>(\"SELECT * FROM OrleansStreamDeadLetter\"));\n        Assert.Equal(serviceId, dead.ServiceId);\n        Assert.Equal(providerId, dead.ProviderId);\n        Assert.Equal(queueId, dead.QueueId);\n        Assert.Equal(ack.MessageId, dead.MessageId);\n        Assert.Equal(1, dead.Dequeued);\n        Assert.True(dead.ExpiresOn >= beforeQueued);\n        Assert.True(dead.ExpiresOn <= afterQueued.Add(streamOptions.ExpiryTimeout.SecondsCeiling()));\n        Assert.True(dead.CreatedOn >= beforeQueued);\n        Assert.True(dead.CreatedOn <= afterQueued);\n        Assert.True(dead.ModifiedOn >= beforeDequeued);\n        Assert.True(dead.ModifiedOn <= afterDequeued);\n        Assert.True(dead.DeadOn >= beforeFailure);\n        Assert.True(dead.DeadOn <= afterFailure);\n        Assert.True(dead.RemoveOn >= beforeFailure);\n        Assert.True(dead.RemoveOn <= afterFailure.Add(streamOptions.DeadLetterEvictionTimeout.SecondsCeiling()));\n        Assert.Equal(payload, dead.Payload);\n    }\n\n    /// <summary>\n    /// Tests that a healthy message is not moved to dead letters.\n    /// </summary>\n    [SkippableFact]\n    public async Task RelationalOrleansQueries_DoesNotMoveHealthyMessageToDeadLetters()\n    {\n        // arrange\n        var serviceId = \"ServiceId\";\n        var providerId = \"ProviderId\";\n        var queueId = \"QueueId\";\n        var streamOptions = new AdoNetStreamOptions();\n        var cacheOptions = new SimpleQueueCacheOptions();\n\n        // arrange - queue a normal message\n        var payload = new byte[] { 0xFF };\n        var ack = await _queries.QueueStreamMessageAsync(serviceId, providerId, queueId, payload, streamOptions.ExpiryTimeout.TotalSecondsCeiling());\n\n        // arrange - dequeue the message\n        await _queries.GetStreamMessagesAsync(ack.ServiceId, ack.ProviderId, ack.QueueId, cacheOptions.CacheSize, streamOptions.MaxAttempts, streamOptions.VisibilityTimeout.TotalSecondsCeiling(), streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling(), streamOptions.EvictionInterval.TotalSecondsCeiling(), streamOptions.EvictionBatchSize);\n\n        // act - fail the message\n        var beforeFailed = DateTime.UtcNow.AddSeconds(-1);\n        await _queries.FailStreamMessageAsync(ack.ServiceId, ack.ProviderId, ack.QueueId, ack.MessageId, streamOptions.MaxAttempts, streamOptions.DeadLetterEvictionTimeout.TotalSecondsCeiling());\n        var afterFailed = DateTime.UtcNow.AddSeconds(1);\n\n        // assert - the message is still in the table and was made visible again\n        var saved = Assert.Single(await _storage.ReadAsync<AdoNetStreamMessage>(\"SELECT * FROM OrleansStreamMessage\"));\n        Assert.Equal(ack.ServiceId, saved.ServiceId);\n        Assert.Equal(ack.ProviderId, saved.ProviderId);\n        Assert.Equal(ack.QueueId, saved.QueueId);\n        Assert.Equal(ack.MessageId, saved.MessageId);\n        Assert.Equal(1, saved.Dequeued);\n        Assert.True(saved.VisibleOn >= beforeFailed, $\"{saved.VisibleOn} must be greater than or equal to {beforeFailed}\");\n        Assert.True(saved.VisibleOn <= afterFailed, $\"{saved.VisibleOn} must be lesser than or equal to {afterFailed}\");\n\n        // assert - no message arrived at dead letters\n        Assert.Empty(await _storage.ReadAsync<AdoNetStreamDeadLetter>(\"SELECT * FROM OrleansStreamDeadLetter\"));\n    }\n\n    private static List<T> Randomize<T>(IEnumerable<T> source)\n    {\n        var list = new List<T>(source.TryGetNonEnumeratedCount(out var count) ? count : 0);\n\n        foreach (var item in source)\n        {\n            var index = Random.Shared.Next(list.Count + 1);\n            if (index == list.Count)\n            {\n                list.Add(item);\n            }\n            else\n            {\n                list.Add(list[index]);\n                list[index] = item;\n            }\n        }\n\n        return list;\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureGrainDirectoryTests.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory.AzureStorage;\nusing Orleans.TestingHost.Utils;\nusing Tester.Directories;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for Azure Table-based grain directory functionality, including registration, lookup, and unregistration operations.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Directory\")]\n    public class AzureTableGrainDirectoryTests(ITestOutputHelper testOutput) : GrainDirectoryTests<AzureTableGrainDirectory>(testOutput)\n    {\n        protected override AzureTableGrainDirectory CreateGrainDirectory()\n        {\n            TestUtils.CheckForAzureStorage();\n            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n\n            var clusterOptions = new ClusterOptions\n            {\n                ClusterId = Guid.NewGuid().ToString(\"N\"),\n                ServiceId = Guid.NewGuid().ToString(\"N\"),\n            };\n\n            var directoryOptions = new AzureTableGrainDirectoryOptions();\n            directoryOptions.ConfigureTestDefaults();\n\n            var loggerFactory = TestingUtils.CreateDefaultLoggerFactory(\"AzureGrainDirectoryTests.log\");\n\n            var directory = new AzureTableGrainDirectory(directoryOptions, Options.Create(clusterOptions), loggerFactory);\n            directory.InitializeIfNeeded().GetAwaiter().GetResult();\n\n            return directory;\n        }\n\n        /// <summary>\n        /// Tests batch unregistration of multiple grain addresses, including handling of concurrent modifications.\n        /// </summary>\n        [SkippableFact]\n        public async Task UnregisterMany()\n        {\n            const int N = 25;\n            const int R = 4;\n\n            // Create and insert N entries\n            var addresses = new List<GrainAddress>();\n            for (var i = 0; i < N; i++)\n            {\n                var addr = new GrainAddress\n                {\n                    ActivationId = ActivationId.NewId(),\n                    GrainId = GrainId.Parse(\"user/someraondomuser_\" + Guid.NewGuid().ToString(\"N\")),\n                    SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n                    MembershipVersion = new MembershipVersion(51)\n                };\n                addresses.Add(addr);\n                await GrainDirectory.Register(addr, previousAddress: null);\n            }\n\n            // Modify the Rth entry locally, to simulate another activation tentative by another silo\n            var ra = addresses[R];\n            var oldActivation = ra.ActivationId;\n            addresses[R] = new()\n            {\n                GrainId = ra.GrainId,\n                SiloAddress = ra.SiloAddress,\n                MembershipVersion = ra.MembershipVersion,\n                ActivationId = ActivationId.NewId()\n            };\n\n            // Batch unregister\n            await GrainDirectory.UnregisterMany(addresses);\n\n            // Now we should only find the old Rth entry\n            for (int i = 0; i < N; i++)\n            {\n                if (i == R)\n                {\n                    var addr = await GrainDirectory.Lookup(addresses[i].GrainId);\n                    Assert.NotNull(addr);\n                    Assert.Equal(oldActivation, addr.ActivationId);\n                }\n                else\n                {\n                    Assert.Null(await GrainDirectory.Lookup(addresses[i].GrainId));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Tests conversion between GrainAddress and Azure Table entity representations.\n        /// </summary>\n        [Fact]\n        public void ConversionTest()\n        {\n            var addr = new GrainAddress\n            {\n                ActivationId = ActivationId.NewId(),\n                GrainId = GrainId.Parse(\"user/someraondomuser_\" + Guid.NewGuid().ToString(\"N\")),\n                SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n                MembershipVersion = new MembershipVersion(806)\n            };\n            var entity = AzureTableGrainDirectory.GrainDirectoryEntity.FromGrainAddress(\"MyClusterId\", addr);\n            Assert.Equal(addr, entity.ToGrainAddress());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureLivenessTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for silo liveness and membership functionality using Azure Table Storage as the membership table.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"AzureStorage\")]\n    public class LivenessTests_AzureTable : LivenessTestsBase\n    {\n        public LivenessTests_AzureTable(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<Configurator>();\n            builder.AddClientBuilderConfigurator<Configurator>();\n        }\n\n        public class Configurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseAzureStorageClustering(options => options.ConfigureTestDefaults());\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.UseAzureStorageClustering(options => options.ConfigureTestDefaults());\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Azure_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Azure_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Azure_3_Restart_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Azure_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Azure_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.AzureUtils;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.Messaging;\nusing Orleans.Runtime.MembershipService;\nusing TestExtensions;\nusing UnitTests;\nusing UnitTests.MembershipTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for operation of Orleans Membership Table using AzureStore - Requires access to external Azure storage\n    /// \n    /// Azure Table Storage provides a scalable, highly available membership table implementation for Orleans.\n    /// Key features include:\n    /// - Automatic partitioning and load balancing\n    /// - Strong consistency guarantees within partitions\n    /// - Built-in redundancy and disaster recovery\n    /// - Integration with Azure monitoring and diagnostics\n    /// \n    /// These tests verify all membership operations work correctly with Azure Table Storage,\n    /// including concurrent updates, failure detection, and gateway discovery.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"AzureStorage\")]\n    public class AzureMembershipTableTests : MembershipTableTestsBase\n    {\n        public AzureMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n            TestUtils.CheckForAzureStorage();\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(typeof(Orleans.Clustering.AzureStorage.AzureTableDataManager<>).FullName, LogLevel.Trace);\n            filters.AddFilter(typeof(OrleansSiloInstanceManager).FullName, LogLevel.Trace);\n            filters.AddFilter(\"Orleans.Storage\", LogLevel.Trace);\n            return filters;\n        }\n\n        /// <summary>\n        /// Creates an Azure Table Storage-based membership table for testing.\n        /// Configures the table with test defaults including connection strings\n        /// and table names suitable for unit testing.\n        /// </summary>\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            TestUtils.CheckForAzureStorage();\n            var options = new AzureStorageClusteringOptions();\n            options.ConfigureTestDefaults();\n            return new AzureBasedMembershipTable(loggerFactory, Options.Create(options), this._clusterOptions);\n        }\n\n        /// <summary>\n        /// Creates an Azure-based gateway list provider for client connections.\n        /// This provider queries Azure Table Storage to discover available\n        /// gateway silos that clients can connect to.\n        /// </summary>\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new AzureStorageGatewayOptions();\n            options.ConfigureTestDefaults();\n            return new AzureGatewayListProvider(loggerFactory, Options.Create(options), this._clusterOptions, this._gatewayOptions);\n        }\n\n        protected override Task<string> GetConnectionString()\n        {\n            TestUtils.CheckForAzureStorage();\n            return Task.FromResult(\"not used\");\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public void MembershipTable_Azure_Init()\n        {\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        /// <summary>\n        /// Tests inserting a new silo entry into Azure Table Storage.\n        /// Verifies that the entry is correctly stored with all required\n        /// properties and can handle Azure's entity size limitations.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        /// <summary>\n        /// Tests concurrent updates to membership entries.\n        /// Verifies that Azure Table Storage's optimistic concurrency control\n        /// correctly handles simultaneous updates from multiple silos.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        /// <summary>\n        /// Tests the heartbeat mechanism using Azure Table Storage.\n        /// Verifies that silos can efficiently update their liveness\n        /// timestamps without conflicts or excessive storage operations.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Azure_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureQueueDataManagerTests.cs",
    "content": "using Azure.Storage.Queues.Models;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for Azure Queue Storage data manager operations including queue message handling and visibility timeouts.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\"), TestCategory(\"AzureQueue\")]\n    public class AzureQueueDataManagerTests : IAsyncLifetime\n    {\n        private readonly ILogger logger;\n        private readonly ILoggerFactory loggerFactory;\n        public static string DeploymentId = \"aqdatamanagertests\".ToLower();\n        private string queueName;\n\n        public AzureQueueDataManagerTests()\n        {\n            TestUtils.CheckForAzureStorage();\n\n            var loggerFactory = TestingUtils.CreateDefaultLoggerFactory(TestingUtils.CreateTraceFileName(\"Client\", DateTime.Now.ToString(\"yyyyMMdd_hhmmss\")));\n            logger = loggerFactory.CreateLogger<AzureQueueDataManagerTests>();\n            this.loggerFactory = loggerFactory;\n        }\n\n        public Task InitializeAsync() => Task.CompletedTask;\n\n        public async Task DisposeAsync()\n        {\n            AzureQueueDataManager manager = await GetTableManager(queueName);\n            await manager.DeleteQueue();\n        }\n\n        private async Task<AzureQueueDataManager> GetTableManager(string qName, TimeSpan? visibilityTimeout = null)\n        {\n            AzureQueueDataManager manager = new AzureQueueDataManager(this.loggerFactory, $\"{qName}-{DeploymentId}\", new AzureQueueOptions { MessageVisibilityTimeout = visibilityTimeout }.ConfigureTestDefaults());\n            await manager.InitQueueAsync();\n            return manager;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_Standalone_1()\n        {\n            queueName = \"Test-1-\".ToLower() + Guid.NewGuid();\n            AzureQueueDataManager manager = await GetTableManager(queueName);\n            Assert.Equal(0, await manager.GetApproximateMessageCount());\n\n            var inMessage = \"Hello, World\";\n            await manager.AddQueueMessage(inMessage);\n            //Nullable<int> count = manager.ApproximateMessageCount;\n            Assert.Equal(1, await manager.GetApproximateMessageCount());\n\n            var outMessage1 = await manager.PeekQueueMessage();\n            logger.LogInformation(\"PeekQueueMessage 1: {Message}\", PrintQueueMessage(outMessage1));\n            Assert.Equal(inMessage, outMessage1.MessageText);\n\n            var outMessage2 = await manager.PeekQueueMessage();\n            logger.LogInformation(\"PeekQueueMessage 2: {Message}\", PrintQueueMessage(outMessage2));\n            Assert.Equal(inMessage, outMessage2.MessageText);\n\n            QueueMessage outMessage3 = await manager.GetQueueMessage();\n            logger.LogInformation(\"GetQueueMessage 3: {Message}\", PrintQueueMessage(outMessage3));\n            Assert.Equal(inMessage, outMessage3.MessageText);\n            Assert.Equal(1, await manager.GetApproximateMessageCount());\n\n            QueueMessage outMessage4 = await manager.GetQueueMessage();\n            Assert.Null(outMessage4);\n\n            Assert.Equal(1, await manager.GetApproximateMessageCount());\n\n            await manager.DeleteQueueMessage(outMessage3);\n            Assert.Equal(0, await manager.GetApproximateMessageCount());\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_Standalone_2()\n        {\n            queueName = \"Test-2-\".ToLower() + Guid.NewGuid();\n            AzureQueueDataManager manager = await GetTableManager(queueName);\n\n            IEnumerable<QueueMessage> msgs = await manager.GetQueueMessages();\n            Assert.True(msgs == null || !msgs.Any());\n\n            int numMsgs = 10;\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < numMsgs; i++)\n            {\n                promises.Add(manager.AddQueueMessage(i.ToString()));\n            }\n            Task.WaitAll(promises.ToArray());\n            Assert.Equal(numMsgs, await manager.GetApproximateMessageCount());\n\n            msgs = new List<QueueMessage>(await manager.GetQueueMessages(numMsgs));\n            Assert.Equal(numMsgs, msgs.Count());\n            Assert.Equal(numMsgs, await manager.GetApproximateMessageCount());\n\n            promises = new List<Task>();\n            foreach (var msg in msgs)\n            {\n                promises.Add(manager.DeleteQueueMessage(msg));\n            }\n            Task.WaitAll(promises.ToArray());\n            Assert.Equal(0, await manager.GetApproximateMessageCount());\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_Standalone_3_Init_MultipleThreads()\n        {\n            queueName = \"Test-4-\".ToLower() + Guid.NewGuid();\n\n            const int NumThreads = 100;\n            Task<bool>[] promises = new Task<bool>[NumThreads];\n\n            for (int i = 0; i < NumThreads; i++)\n            {\n                promises[i] = Task.Run(async () =>\n                {\n                    AzureQueueDataManager manager = await GetTableManager(queueName);\n                    return true;\n                });\n            }\n            await Task.WhenAll(promises);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9552\"), TestCategory(\"Functional\")]\n        public async Task AQ_Standalone_4()\n        {\n            TimeSpan visibilityTimeout = TimeSpan.FromSeconds(2);\n\n            queueName = \"Test-5-\".ToLower() + Guid.NewGuid();\n            AzureQueueDataManager manager = await GetTableManager(queueName, visibilityTimeout);\n            Assert.Equal(0, await manager.GetApproximateMessageCount());\n\n            var inMessage = \"Hello, World\";\n            await manager.AddQueueMessage(inMessage);\n            Assert.Equal(1, await manager.GetApproximateMessageCount());\n\n            QueueMessage outMessage = await manager.GetQueueMessage();\n            logger.LogInformation(\"GetQueueMessage: {Message}\", PrintQueueMessage(outMessage));\n            Assert.Equal(inMessage, outMessage.MessageText);\n\n            await Task.Delay(visibilityTimeout);\n\n            Assert.Equal(1, await manager.GetApproximateMessageCount());\n\n            QueueMessage outMessage2 = await manager.GetQueueMessage();\n            Assert.Equal(inMessage, outMessage2.MessageText);\n\n            await manager.DeleteQueueMessage(outMessage2);\n            Assert.Equal(0, await manager.GetApproximateMessageCount());\n        }\n\n        private static string PrintQueueMessage(QueueMessage message)\n        {\n            return string.Format(\"QueueMessage: Id = {0}, NextVisibleTime = {1}, DequeueCount = {2}, PopReceipt = {3}, Content = {4}\",\n                    message.MessageId,\n                    message.NextVisibleOn.HasValue ? LogFormatter.PrintDate(message.NextVisibleOn.Value.DateTime) : \"\",\n                    message.DequeueCount,\n                    message.PopReceipt,\n                    message.MessageText);\n        }\n\n        private static string PrintQueueMessage(PeekedMessage message)\n        {\n            return string.Format(\"QueueMessage: Id = {0}, DequeueCount = {1}, Content = {2}\",\n                    message.MessageId,\n                    message.DequeueCount,\n                    message.MessageText);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureRemindersTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime.ReminderService;\nusing Tester;\nusing TestExtensions;\nusing Xunit;\nusing Orleans.Reminders.AzureStorage;\nusing Tester.AzureUtils;\n\nnamespace UnitTests.RemindersTest\n{\n    /// <summary>\n    /// Tests for operation of Orleans Reminders Table using Azure\n    /// </summary>\n    [TestCategory(\"Reminders\"), TestCategory(\"AzureStorage\")]\n    public class AzureRemindersTableTests : ReminderTableTestsBase\n    {\n        public AzureRemindersTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        {\n            TestUtils.CheckForAzureStorage();\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(\"AzureTableDataManager\", LogLevel.Trace);\n            filters.AddFilter(\"OrleansSiloInstanceManager\", LogLevel.Trace);\n            filters.AddFilter(\"Storage\", LogLevel.Trace);\n            return filters;\n        }\n\n        public override Task DisposeAsync()\n        {\n            // Reset init timeout after tests\n            return base.DisposeAsync();\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            TestUtils.CheckForAzureStorage();\n            var options = Options.Create(new AzureTableReminderStorageOptions());\n            options.Value.ConfigureTestDefaults();\n            return new AzureBasedReminderTable(loggerFactory, this.clusterOptions, options);\n        }\n\n        protected override Task<string> GetConnectionString()\n        {\n            TestUtils.CheckForAzureStorage();\n            return Task.FromResult(\"not used\");\n        }\n\n        [SkippableFact]\n        public void RemindersTable_Azure_Init()\n        {\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task RemindersTable_Azure_RemindersRange()\n        {\n            await RemindersRange(50);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task RemindersTable_Azure_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task RemindersTable_Azure_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureStorageBasicTests.cs",
    "content": "﻿namespace Tester.AzureUtils\n{\n    /// <summary>\n    /// DO NOT use this class as a <code>IClassFixture</code> due to https://github.com/AArnott/Xunit.SkippableFact/issues/32\n    /// </summary>\n    public abstract class AzureStorageBasicTests\n    {\n        public AzureStorageBasicTests()\n        {\n            TestUtils.CheckForAzureStorage();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureStorageOperationOptionsExtensions.cs",
    "content": "using Azure.Core.Diagnostics;\nusing Azure.Data.Tables;\nusing Azure.Identity;\nusing Azure.Storage.Blobs;\nusing TestExtensions;\n\nnamespace Tester.AzureUtils\n{\n    public static class AzureStorageOperationOptionsExtensions\n    {\n        public static DefaultAzureCredential Credential = new DefaultAzureCredential();\n\n        public static Orleans.Clustering.AzureStorage.AzureStorageOperationOptions ConfigureTestDefaults(this Orleans.Clustering.AzureStorage.AzureStorageOperationOptions options)\n        {\n            options.TableServiceClient = GetTableServiceClient();\n\n            return options;\n        }\n\n        public static TableServiceClient GetTableServiceClient()\n        {\n            return TestDefaultConfiguration.UseAadAuthentication\n                ? new(TestDefaultConfiguration.TableEndpoint, TestDefaultConfiguration.TokenCredential)\n                : new(TestDefaultConfiguration.DataConnectionString);\n        }\n\n        public static Orleans.GrainDirectory.AzureStorage.AzureStorageOperationOptions ConfigureTestDefaults(this Orleans.GrainDirectory.AzureStorage.AzureStorageOperationOptions options)\n        {\n            options.TableServiceClient = GetTableServiceClient();\n\n            return options;\n        }\n\n        public static Orleans.Persistence.AzureStorage.AzureStorageOperationOptions ConfigureTestDefaults(this Orleans.Persistence.AzureStorage.AzureStorageOperationOptions options)\n        {\n            options.TableServiceClient = GetTableServiceClient();\n\n            return options;\n        }\n\n        public static Orleans.Reminders.AzureStorage.AzureStorageOperationOptions ConfigureTestDefaults(this Orleans.Reminders.AzureStorage.AzureStorageOperationOptions options)\n        {\n            options.TableServiceClient = GetTableServiceClient();\n\n            return options;\n        }\n\n        public static Orleans.Configuration.AzureBlobStorageOptions ConfigureTestDefaults(this Orleans.Configuration.AzureBlobStorageOptions options)\n        {\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataBlobUri, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            }\n\n            return options;\n        }\n\n        public static AzureStorageJobShardOptions ConfigureTestDefaults(this AzureStorageJobShardOptions options)\n        {\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataBlobUri, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            }\n\n            return options;\n        }\n\n        public static Orleans.Configuration.AzureQueueOptions ConfigureTestDefaults(this Orleans.Configuration.AzureQueueOptions options)\n        {\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.QueueServiceClient = new(TestDefaultConfiguration.DataQueueUri, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.QueueServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            }\n\n            return options;\n        }\n\n        public static Orleans.Configuration.AzureBlobLeaseProviderOptions ConfigureTestDefaults(this Orleans.Configuration.AzureBlobLeaseProviderOptions options)\n        {\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataBlobUri, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.BlobServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            }\n\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureTableDataManagerStressTests.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing Orleans.TestingHost.Utils;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Internal;\nusing AzureStoragePolicyOptions = Orleans.Clustering.AzureStorage.AzureStoragePolicyOptions;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Stress tests for Azure Table Storage data manager testing high-volume read/write operations and performance.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\"), TestCategory(\"Stress\")]\n    public class AzureTableDataManagerStressTests : AzureStorageBasicTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly string PartitionKey;\n        private readonly UnitTestAzureTableDataManager manager;\n\n        public AzureTableDataManagerStressTests(ITestOutputHelper output)\n        {\n            this.output = output;\n\n            // Pre-create table, if required\n            manager = new UnitTestAzureTableDataManager();\n\n            PartitionKey = \"AzureTableDataManagerStressTests-\" + Guid.NewGuid();\n        }\n\n        [SkippableFact]\n        public async Task AzureTableDataManagerStressTests_WriteAlot_SinglePartition()\n        {\n            const string testName = \"AzureTableDataManagerStressTests_WriteAlot_SinglePartition\";\n            const int iterations = 2000;\n            const int batchSize = 1000;\n            const int numPartitions = 1;\n\n            // Write some data\n            await WriteAlot_Async(testName, numPartitions, iterations, batchSize);\n        }\n\n        [SkippableFact]\n        public async Task AzureTableDataManagerStressTests_WriteAlot_MultiPartition()\n        {\n            const string testName = \"AzureTableDataManagerStressTests_WriteAlot_MultiPartition\";\n            const int iterations = 2000;\n            const int batchSize = 1000;\n            const int numPartitions = 100;\n\n            // Write some data\n            await WriteAlot_Async(testName, numPartitions, iterations, batchSize);\n        }\n\n        [SkippableFact]\n        public async Task AzureTableDataManagerStressTests_ReadAll_SinglePartition()\n        {\n            const string testName = \"AzureTableDataManagerStressTests_ReadAll\";\n            const int iterations = 1000;\n\n            // Write some data\n            await WriteAlot_Async(testName, 1, iterations, iterations);\n\n            Stopwatch sw = Stopwatch.StartNew();\n\n            var data = (await manager.ReadAllTableEntriesForPartitionAsync(PartitionKey)\n                .WaitAsync(new AzureStoragePolicyOptions().CreationTimeout)).Select(tuple => tuple.Entity);\n\n            sw.Stop();\n            int count = data.Count();\n            output.WriteLine(\"AzureTable_ReadAll completed. ReadAll {0} entries in {1} at {2} RPS\", count, sw.Elapsed, count / sw.Elapsed.TotalSeconds);\n\n            Assert.True(count >= iterations, $\"ReadAllshould return some data: Found={count}\");\n        }\n\n        [SkippableFact]\n        public async Task AzureTableDataManagerStressTests_ReadAllTableEntities()\n        {\n            const string testName = \"AzureTableDataManagerStressTests_ReadAllTableEntities\";\n            const int iterations = 2000;\n\n            // Write some data\n            await WriteAlot_Async(testName, 3, iterations, iterations);\n\n            Stopwatch sw = Stopwatch.StartNew();\n\n            var data = (await manager.ReadAllTableEntriesAsync().WaitAsync(new AzureStoragePolicyOptions().CreationTimeout))\n                .Select(tuple => tuple.Entity);\n\n            sw.Stop();\n            int count = data.Count();\n            output.WriteLine(\"AzureTable_ReadAllTableEntities completed. ReadAll {0} entries in {1} at {2} RPS\", count, sw.Elapsed, count / sw.Elapsed.TotalSeconds);\n\n            Assert.True(count >= iterations, $\"ReadAllshould return some data: Found={count}\");\n\n            sw = Stopwatch.StartNew();\n            await manager.ClearTableAsync().WaitAsync(new AzureStoragePolicyOptions().CreationTimeout);\n            sw.Stop();\n            output.WriteLine(\"AzureTable_ReadAllTableEntities clear. Cleared table of {0} entries in {1} at {2} RPS\", count, sw.Elapsed, count / sw.Elapsed.TotalSeconds);\n        }\n\n        private async Task WriteAlot_Async(string testName, int numPartitions, int iterations, int batchSize)\n        {\n            output.WriteLine(\"Iterations={0}, Batch={1}, Partitions={2}\", iterations, batchSize, numPartitions);\n            List<Task> promises = new List<Task>();\n            Stopwatch sw = Stopwatch.StartNew();\n            for (int i = 0; i < iterations; i++)\n            {\n                string partitionKey = PartitionKey;\n                if (numPartitions > 1) partitionKey += (i % numPartitions);\n                string rowKey = i.ToString(CultureInfo.InvariantCulture);\n\n                UnitTestAzureTableData dataObject = new UnitTestAzureTableData();\n                dataObject.PartitionKey = partitionKey;\n                dataObject.RowKey = rowKey;\n                dataObject.StringData = rowKey;\n                var promise = manager.UpsertTableEntryAsync(dataObject);\n                promises.Add(promise);\n                if ((i % batchSize) == 0 && i > 0)\n                {\n                    await Task.WhenAll(promises).WaitAsync(new AzureStoragePolicyOptions().CreationTimeout);\n                    promises.Clear();\n                    output.WriteLine(\"{0} has written {1} rows in {2} at {3} RPS\",\n                        testName, i, sw.Elapsed, i / sw.Elapsed.TotalSeconds);\n                }\n            }\n            await Task.WhenAll(promises).WaitAsync(new AzureStoragePolicyOptions().CreationTimeout);\n            sw.Stop();\n            output.WriteLine(\"{0} completed. Wrote {1} entries to {2} partition(s) in {3} at {4} RPS\",\n                testName, iterations, numPartitions, sw.Elapsed, iterations / sw.Elapsed.TotalSeconds);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureTableDataManagerTests.cs",
    "content": "using System.Net;\nusing Azure;\nusing Azure.Data.Tables.Models;\nusing Orleans.Clustering.AzureStorage;\nusing Orleans.TestingHost.Utils;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for Azure Table Storage data manager CRUD operations and conditional updates.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\")]\n    public class AzureTableDataManagerTests : AzureStorageBasicTests\n    {\n        private readonly string PartitionKey;\n        private readonly UnitTestAzureTableDataManager manager;\n\n        private UnitTestAzureTableData GenerateNewData()\n        {\n            return new UnitTestAzureTableData(\"JustData\", PartitionKey, \"RK-\" + Guid.NewGuid());\n        }\n\n        public AzureTableDataManagerTests()\n        {\n            // Pre-create table, if required\n            manager = new UnitTestAzureTableDataManager();\n            PartitionKey = \"PK-AzureTableDataManagerTests-\" + Guid.NewGuid();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_CreateTableEntryAsync()\n        {\n            var data = GenerateNewData();\n            await manager.CreateTableEntryAsync(data);\n            try\n            {\n                var data2 = data.Clone();\n                data2.StringData = \"NewData\";\n                await manager.CreateTableEntryAsync(data2);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // \"Creating an already existing entry.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);\n                Assert.Equal(\"EntityAlreadyExists\", restStatus);\n            }\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Equal(data.StringData, tuple.Entity.StringData);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_UpsertTableEntryAsync()\n        {\n            var data = GenerateNewData();\n            await manager.UpsertTableEntryAsync(data);\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Equal(data.StringData, tuple.Entity.StringData);\n\n            var data2 = data.Clone();\n            data2.StringData = \"NewData\";\n            await manager.UpsertTableEntryAsync(data2);\n            tuple = await manager.ReadSingleTableEntryAsync(data2.PartitionKey, data2.RowKey);\n            Assert.Equal(data2.StringData, tuple.Entity.StringData);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_UpdateTableEntryAsync()\n        {\n            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n            var data = GenerateNewData();\n            try\n            {\n                await manager.UpdateTableEntryAsync(data, AzureTableUtils.ANY_ETAG);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Update before insert.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);\n            }\n\n            await manager.UpsertTableEntryAsync(data);\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Equal(data.StringData, tuple.Entity.StringData);\n\n            var data2 = data.Clone();\n            data2.StringData = \"NewData\";\n            string eTag1 = await manager.UpdateTableEntryAsync(data2, AzureTableUtils.ANY_ETAG);\n            tuple = await manager.ReadSingleTableEntryAsync(data2.PartitionKey, data2.RowKey);\n            Assert.Equal(data2.StringData, tuple.Entity.StringData);\n\n            var data3 = data.Clone();\n            data3.StringData = \"EvenNewerData\";\n            _ = await manager.UpdateTableEntryAsync(data3, eTag1);\n            tuple = await manager.ReadSingleTableEntryAsync(data3.PartitionKey, data3.RowKey);\n            Assert.Equal(data3.StringData, tuple.Entity.StringData);\n\n            try\n            {\n                string eTag3 = await manager.UpdateTableEntryAsync(data3.Clone(), eTag1);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // \"Wrong eTag\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);\n                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_DeleteTableAsync()\n        {\n            var data = GenerateNewData();\n            try\n            {\n                await manager.DeleteTableEntryAsync(data, AzureTableUtils.ANY_ETAG);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Delete before create.\"\n                HttpStatusCode httpStatusCode;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out _, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n            }\n\n            string eTag1 = await manager.UpsertTableEntryAsync(data);\n            await manager.DeleteTableEntryAsync(data, eTag1);\n\n            try\n            {\n                await manager.DeleteTableEntryAsync(data, eTag1);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Deleting an already deleted item.\"\n                HttpStatusCode httpStatusCode;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out _, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n            }\n\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Null(tuple.Entity);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_MergeTableAsync()\n        {\n            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n            var data = GenerateNewData();\n            try\n            {\n                await manager.MergeTableEntryAsync(data, AzureTableUtils.ANY_ETAG);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Merge before create.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);\n            }\n\n            string eTag1 = await manager.UpsertTableEntryAsync(data);\n            var data2 = data.Clone();\n            data2.StringData = \"NewData\";\n            await manager.MergeTableEntryAsync(data2, eTag1);\n\n            try\n            {\n                await manager.MergeTableEntryAsync(data, eTag1);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // \"Wrong eTag.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);\n                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());\n            }\n\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Equal(\"NewData\", tuple.Entity.StringData);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_ReadSingleTableEntryAsync()\n        {\n            var data = GenerateNewData();\n            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);\n            Assert.Null(tuple.Entity);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_InsertTwoTableEntriesConditionallyAsync()\n        {\n            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n\n            var data1 = GenerateNewData();\n            var data2 = GenerateNewData();\n            try\n            {\n                await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, AzureTableUtils.ANY_ETAG);\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Upadte item 2 before created it.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);\n            }\n\n            string etag = await manager.CreateTableEntryAsync(data2.Clone());\n            var tuple = await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, etag);\n            try\n            {\n                await manager.InsertTwoTableEntriesConditionallyAsync(data1.Clone(), data2.Clone(), tuple.Item2);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // \"Inserting an already existing item 1.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);\n                Assert.Equal(\"EntityAlreadyExists\", restStatus);\n            }\n\n            try\n            {\n                await manager.InsertTwoTableEntriesConditionallyAsync(data1.Clone(), data2.Clone(), AzureTableUtils.ANY_ETAG);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // \"Inserting an already existing item 1 AND wring eTag\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);\n                Assert.Equal(\"EntityAlreadyExists\", restStatus);\n            };\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AzureTableDataManager_UpdateTwoTableEntriesConditionallyAsync()\n        {\n            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n\n            var data1 = GenerateNewData();\n            var data2 = GenerateNewData();\n            try\n            {\n                await manager.UpdateTwoTableEntriesConditionallyAsync(data1, AzureTableUtils.ANY_ETAG, data2, AzureTableUtils.ANY_ETAG);\n                Assert.Fail(\"Update should have failed since the data has not been created yet\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // \"Update before insert.\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);\n                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);\n            }\n\n            string etag = await manager.CreateTableEntryAsync(data2.Clone());\n            var tuple1 = await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, etag);\n            _ = await manager.UpdateTwoTableEntriesConditionallyAsync(data1, tuple1.Item1, data2, tuple1.Item2);\n\n            try\n            {\n                await manager.UpdateTwoTableEntriesConditionallyAsync(data1, tuple1.Item1, data2, tuple1.Item2);\n                Assert.Fail(\"Should have thrown RequestFailedException.\");\n            }\n            catch (RequestFailedException exc)\n            {\n                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // \"Wrong eTag\"\n                HttpStatusCode httpStatusCode;\n                string restStatus;\n                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);\n                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);\n                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/AzureTableErrorCodeTests.cs",
    "content": "using System.Net;\nusing Orleans.Persistence.AzureStorage;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for Azure Storage error code handling and validation of table/container names.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\")]\n    public class AzureTableErrorCodeTests\n    {\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureTableErrorCode_IsRetriableHttpError()\n        {\n            Assert.True(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 503, null));\n            Assert.True(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 504, null));\n            Assert.True(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 408, null));\n\n            Assert.True(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 500, \"OperationTimedOut\"));\n            Assert.False(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 500, null));\n            Assert.False(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 500, \"SomeOtherStatusValue\"));\n\n            // Current behaviour is to ignore successes as not retriable:\n            Assert.False(AzureTableUtils.IsRetriableHttpError((HttpStatusCode) 200, null));\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureTableErrorCode_IsContentionError()\n        {\n            Assert.True(AzureTableUtils.IsContentionError(HttpStatusCode.PreconditionFailed));\n            Assert.True(AzureTableUtils.IsContentionError(HttpStatusCode.Conflict));\n            Assert.True(AzureTableUtils.IsContentionError(HttpStatusCode.NotFound));\n            Assert.True(AzureTableUtils.IsContentionError(HttpStatusCode.NotImplemented));\n\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 503));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 504));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 408));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 500));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 500));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 500));\n            Assert.False(AzureTableUtils.IsContentionError((HttpStatusCode) 200));\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureTableErrorCode_BadTableName()\n        {\n            \n            string tableName = \"abc-123\";\n            Assert.Throws<ArgumentException>(() =>\n            AzureTableUtils.ValidateTableName(tableName));\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureStorageUtils_ContainerName()\n        {\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"this is a test\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"MyContainer\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"my_container123\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"_container\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"__\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateContainerName(\"_.\"));\n            AzureBlobUtils.ValidateContainerName(\"123\");\n            AzureBlobUtils.ValidateContainerName(\"container\");\n            AzureBlobUtils.ValidateContainerName(\"my-container123\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureStorageUtils_BlobName()\n        {\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateBlobName(\"\"));\n            Assert.Throws<ArgumentException>(() => AzureBlobUtils.ValidateBlobName(\" \"));\n            AzureBlobUtils.ValidateBlobName(\".\");\n            AzureBlobUtils.ValidateBlobName(\"/\");\n            AzureBlobUtils.ValidateContainerName(\"123\");\n            AzureBlobUtils.ValidateContainerName(\"orleans-blob\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void AzureStorageUtils_TablePropertyShouldBeSanitized()\n        {\n            var tableProperty = \"/A\\\\C#?\";\n            Assert.Equal(\"_A_C__\", AzureTableUtils.SanitizeTableProperty(tableProperty));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/CollectionFixtures.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides Azure Storage and related services specific test environment setup.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/DurableJobs/AzureStorageBlobDurableJobsTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing Tester;\nusing Tester.DurableJobs;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.AzureUtils.DurableJobs;\n\npublic class AzureStorageBlobDurableJobsTests : TestClusterPerTest\n{\n    private DurableJobTestsRunner _runner;\n\n    protected override void CheckPreconditionsOrThrow() => TestUtils.CheckForAzureStorage();\n\n    public override async Task InitializeAsync()\n    {\n        await base.InitializeAsync();\n        _runner = new DurableJobTestsRunner(this.GrainFactory);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n    }\n\n    public class SiloHostConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .UseAzureBlobDurableJobs(options => options.ConfigureTestDefaults())\n                .AddMemoryGrainStorageAsDefault();\n        }\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task DurableJobGrain()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DurableJobGrain(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task JobExecutionOrder()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobExecutionOrder(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task PastDueTime()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.PastDueTime(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task JobWithMetadata()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobWithMetadata(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task MultipleGrains()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.MultipleGrains(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task DuplicateJobNames()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DuplicateJobNames(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task CancelNonExistentJob()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.CancelNonExistentJob(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task CancelAlreadyExecutedJob()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.CancelAlreadyExecutedJob(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task ConcurrentScheduling()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ConcurrentScheduling(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task JobPropertiesVerification()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobPropertiesVerification(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task DequeueCount()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DequeueCount(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task ScheduleJobOnAnotherGrain()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ScheduleJobOnAnotherGrain(cts.Token);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"DurableJobs\")]\n    public async Task JobRetry()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobRetry(cts.Token);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/DurableJobs/AzureStorageJobShardBatchingTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\nusing Orleans.DurableJobs.AzureStorage;\nusing Tester.AzureUtils;\nusing Xunit;\n\nnamespace Tester.AzureUtils.DurableJobs;\n\n/// <summary>\n/// Azure Storage-specific tests for job shard batching functionality.\n/// These tests verify Azure-specific batching behaviors that don't apply to all providers.\n/// </summary>\n[TestCategory(\"DurableJobs\")]\npublic class AzureStorageJobShardBatchingTests : AzureStorageBasicTests, IAsyncDisposable\n{\n    private readonly IDictionary<string, string> _metadata = new Dictionary<string, string>\n    {\n        { \"CreatedBy\", \"UnitTest\" },\n        { \"Purpose\", \"Testing\" }\n    };\n\n    internal InMemoryClusterMembershipService MembershipService { get; }\n\n    internal IOptions<AzureStorageJobShardOptions> StorageOptions { get; }\n    internal IOptions<DurableJobsOptions> DurableJobsOptions { get; }\n\n    public AzureStorageJobShardBatchingTests()\n    {\n        MembershipService = new InMemoryClusterMembershipService();\n        StorageOptions = Options.Create(new AzureStorageJobShardOptions());\n        DurableJobsOptions = Options.Create(new DurableJobsOptions());\n        StorageOptions.Value.ConfigureTestDefaults();\n        StorageOptions.Value.ContainerName = \"test-batch-container-\" + Guid.NewGuid().ToString(\"N\");\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        // Cleanup storage container\n        var client = StorageOptions.Value.BlobServiceClient;\n        var container = client.GetBlobContainerClient(StorageOptions.Value.ContainerName);\n        await container.DeleteIfExistsAsync();\n    }\n\n    public class TestLocalSiloDetails : ILocalSiloDetails\n    {\n        public TestLocalSiloDetails(SiloAddress siloAddress)\n        {\n            SiloAddress = siloAddress;\n        }\n\n        public string Name => SiloAddress.ToString();\n\n        public string ClusterId => \"TestCluster\";\n\n        public string DnsHostName => SiloAddress.ToString();\n\n        public SiloAddress SiloAddress { get; }\n\n        public SiloAddress GatewayAddress => SiloAddress;\n    }\n\n    internal AzureStorageJobShardManager CreateManager(SiloAddress siloAddress)\n    {\n        var localSiloDetails = new TestLocalSiloDetails(siloAddress);\n        return new AzureStorageJobShardManager(localSiloDetails, StorageOptions, DurableJobsOptions, MembershipService, NullLoggerFactory.Instance);\n    }\n\n    internal void SetSiloStatus(SiloAddress siloAddress, SiloStatus status)\n    {\n        MembershipService.SetSiloStatus(siloAddress, status);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShard_MultipleOperationsBatched()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        var cancellationToken = cts.Token;\n        // Configure batching options to batch multiple operations\n        StorageOptions.Value.MinBatchSize = 5;\n        StorageOptions.Value.MaxBatchSize = 50;\n        StorageOptions.Value.BatchFlushInterval = TimeSpan.FromMilliseconds(100);\n\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard = await manager.CreateShardAsync(date, date.AddHours(1), _metadata, cancellationToken);\n\n        // Schedule 10 jobs rapidly to trigger batching\n        var tasks = new List<Task>();\n        for (int i = 0; i < 10; i++)\n        {\n            tasks.Add(shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", $\"target{i}\"), JobName = $\"job{i}\", DueTime = date.AddMilliseconds(i * 10d), Metadata = null }, cancellationToken));\n        }\n\n        await Task.WhenAll(tasks);\n\n        // Wait for batches to flush\n        await Task.Delay(TimeSpan.FromMilliseconds(300), cancellationToken);\n\n        // Verify batching occurred - should have fewer committed blocks than individual operations\n        var azureShard = (AzureStorageJobShard)shard;\n        Assert.True(azureShard.CommitedBlockCount < 10, $\"Expected batching to reduce block count, but got {azureShard.CommitedBlockCount}\");\n\n        // Verify all jobs were persisted by marking silo as dead and reassigning\n        SetSiloStatus(localAddress, SiloStatus.Dead);\n        var newSiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 1);\n        SetSiloStatus(newSiloAddress, SiloStatus.Active);\n\n        var newManager = CreateManager(newSiloAddress);\n        var shards = await newManager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n\n        var consumedJobs = new List<string>();\n        await foreach (var jobCtx in shards[0].ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n            await shards[0].RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(10, consumedJobs.Count);\n        await newManager.UnregisterShardAsync(shards[0], cancellationToken);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShard_PartialBatchFlushesOnTimeout()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        var cancellationToken = cts.Token;\n        // Configure batching to require 10 operations but with a short timeout\n        StorageOptions.Value.MinBatchSize = 10;\n        StorageOptions.Value.MaxBatchSize = 100;\n        StorageOptions.Value.BatchFlushInterval = TimeSpan.FromMilliseconds(200);\n\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard = await manager.CreateShardAsync(date, date.AddHours(1), _metadata, cancellationToken);\n\n        // Schedule only 3 jobs (less than MinBatchSize of 10)\n        var tasks = new Task[3];\n        tasks[0] = shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = date.AddSeconds(1), Metadata = null }, cancellationToken);\n        tasks[1] = shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = date.AddSeconds(2), Metadata = null }, cancellationToken);\n        tasks[2] = shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target3\"), JobName = \"job3\", DueTime = date.AddSeconds(3), Metadata = null }, cancellationToken);\n\n        await Task.WhenAll(tasks);\n\n        // Verify that the partial batch was flushed - should have 1 committed block\n        var azureShard = (AzureStorageJobShard)shard;\n        Assert.Equal(1, azureShard.CommitedBlockCount);\n\n        // Verify jobs were persisted despite not reaching MinBatchSize\n        SetSiloStatus(localAddress, SiloStatus.Dead);\n        var newSiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 1);\n        SetSiloStatus(newSiloAddress, SiloStatus.Active);\n\n        var newManager = CreateManager(newSiloAddress);\n        var shards = await newManager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n\n        var consumedJobs = new List<string>();\n        await foreach (var jobCtx in shards[0].ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n            await shards[0].RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(3, consumedJobs.Count);\n        await newManager.UnregisterShardAsync(shards[0], cancellationToken);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShard_MaxBatchSizeEnforced()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        var cancellationToken = cts.Token;\n        // Configure batching with a small max batch size\n        StorageOptions.Value.MinBatchSize = 1;\n        StorageOptions.Value.MaxBatchSize = 20;\n        StorageOptions.Value.BatchFlushInterval = TimeSpan.FromMilliseconds(50);\n\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard = await manager.CreateShardAsync(date, date.AddHours(1), _metadata, cancellationToken);\n\n        // Schedule 50 jobs rapidly (exceeds MaxBatchSize of 20)\n        var tasks = new List<Task>();\n        for (int i = 0; i < 50; i++)\n        {\n            tasks.Add(shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", $\"target{i}\"), JobName = $\"job{i}\", DueTime = date.AddMilliseconds(i), Metadata = null }, cancellationToken));\n        }\n\n        await Task.WhenAll(tasks);\n\n        // Wait for all batches to flush\n        await Task.Delay(TimeSpan.FromMilliseconds(500), cancellationToken);\n\n        // Verify multiple batches were created due to MaxBatchSize limit\n        // With 50 jobs and MaxBatchSize=20, expect at least 3 blocks (50/20 = 2.5, rounded up)\n        var azureShard = (AzureStorageJobShard)shard;\n        Assert.True(azureShard.CommitedBlockCount >= 3, $\"Expected at least 3 blocks for 50 jobs with MaxBatchSize=20, but got {azureShard.CommitedBlockCount}\");\n\n        // Verify all jobs were persisted (should be split into multiple batches)\n        SetSiloStatus(localAddress, SiloStatus.Dead);\n        var newSiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 1);\n        SetSiloStatus(newSiloAddress, SiloStatus.Active);\n\n        var newManager = CreateManager(newSiloAddress);\n        var shards = await newManager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n\n        var consumedJobs = new List<string>();\n        await foreach (var jobCtx in shards[0].ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n            await shards[0].RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(50, consumedJobs.Count);\n        await newManager.UnregisterShardAsync(shards[0], cancellationToken);\n    }\n\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShard_MetadataOperationsBreakBatches()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        var cancellationToken = cts.Token;\n        // Configure batching to require large batch\n        StorageOptions.Value.MinBatchSize = 10;\n        StorageOptions.Value.MaxBatchSize = 100;\n        StorageOptions.Value.BatchFlushInterval = TimeSpan.FromSeconds(5);\n\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard = await manager.CreateShardAsync(date, date.AddHours(1), _metadata, cancellationToken);\n\n        // Schedule 5 jobs (less than MinBatchSize)\n        var tasks = new List<Task>();\n        for (int i = 0; i < 5; i++)\n        {\n            tasks.Add(shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", $\"target{i}\"), JobName = $\"job{i}\", DueTime = date.AddMilliseconds(i), Metadata = null }, cancellationToken));\n        }\n\n        // Give operations time to queue\n        await Task.Delay(50, cancellationToken);\n\n        // Verify no blocks committed yet (batch still pending)\n        var azureShard = (AzureStorageJobShard)shard;\n        var blockCountBefore = azureShard.CommitedBlockCount;\n\n        // Update metadata (should flush pending batch and process immediately)\n        var newMetadata = new Dictionary<string, string>(shard.Metadata) { [\"Updated\"] = \"true\" };\n        await azureShard.UpdateBlobMetadata(newMetadata, cancellationToken);\n\n        Assert.All(tasks, t => Assert.True(t.IsCompletedSuccessfully, \"Expected all job scheduling tasks to complete successfully\"));\n        Assert.True(azureShard.CommitedBlockCount > blockCountBefore, \"Expected metadata update to flush pending batch\");\n\n        // Verify metadata was updated\n        var props = await azureShard.BlobClient.GetPropertiesAsync(cancellationToken: cancellationToken);\n        Assert.True(props.Value.Metadata.ContainsKey(\"Updated\"));\n        Assert.Equal(\"true\", props.Value.Metadata[\"Updated\"]);\n\n        // Verify jobs were persisted (even though batch was incomplete)\n        SetSiloStatus(localAddress, SiloStatus.Dead);\n        var newSiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 1);\n        SetSiloStatus(newSiloAddress, SiloStatus.Active);\n\n        // Reconfigure batching to make test faster\n        StorageOptions.Value.MinBatchSize = 1;\n        StorageOptions.Value.MaxBatchSize = 1;\n        StorageOptions.Value.BatchFlushInterval = TimeSpan.FromMilliseconds(100);\n\n        var newManager = CreateManager(newSiloAddress);\n        var shards = await newManager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n\n        var consumedJobs = new List<string>();\n        await foreach (var jobCtx in shards[0].ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n            await shards[0].RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(5, consumedJobs.Count);\n        await newManager.UnregisterShardAsync(shards[0], cancellationToken);\n    }\n\n    public class InMemoryClusterMembershipService : IClusterMembershipService\n    {\n        private readonly Dictionary<SiloAddress, ClusterMember> _silos = new();\n        private int _version = 0;\n\n        public ClusterMembershipSnapshot CurrentSnapshot =>\n            new ClusterMembershipSnapshot(_silos.ToImmutableDictionary(), new MembershipVersion(_version));\n\n        public IAsyncEnumerable<ClusterMembershipSnapshot> MembershipUpdates => throw new NotImplementedException();\n\n        public void SetSiloStatus(SiloAddress address, SiloStatus status)\n        {\n            _silos[address] = new ClusterMember(address, status, address.ToParsableString());\n            _version++;\n        }\n\n        public ValueTask Refresh(MembershipVersion minimumVersion = default, CancellationToken cancellationToken = default) =>\n            ValueTask.CompletedTask;\n\n        public Task<bool> TryKill(SiloAddress siloAddress) => throw new NotImplementedException();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/DurableJobs/AzureStorageJobShardManagerTestFixture.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\nusing Orleans.DurableJobs.AzureStorage;\nusing Tester.AzureUtils;\nusing Tester.DurableJobs;\n\nnamespace Orleans.Tests.DurableJobs.AzureStorage;\n\n/// <summary>\n/// Azure Storage implementation of <see cref=\"IJobShardManagerTestFixture\"/>.\n/// Provides the infrastructure needed to run shared job shard manager tests against Azure Storage.\n/// </summary>\ninternal sealed class AzureStorageJobShardManagerTestFixture : IJobShardManagerTestFixture\n{\n    private readonly IOptions<AzureStorageJobShardOptions> _storageOptions;\n    private readonly IOptions<DurableJobsOptions> _durableJobsOptions;\n\n    public AzureStorageJobShardManagerTestFixture()\n    {\n        _storageOptions = Options.Create(new AzureStorageJobShardOptions());\n        _durableJobsOptions = Options.Create(new DurableJobsOptions());\n        _storageOptions.Value.ConfigureTestDefaults();\n        _storageOptions.Value.ContainerName = \"test-container-\" + Guid.NewGuid().ToString(\"N\");\n    }\n\n    public JobShardManager CreateManager(ILocalSiloDetails localSiloDetails, IClusterMembershipService membershipService)\n    {\n        return new AzureStorageJobShardManager(\n            localSiloDetails,\n            _storageOptions,\n            _durableJobsOptions,\n            membershipService,\n            NullLoggerFactory.Instance);\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        // Cleanup storage container\n        var client = _storageOptions.Value.BlobServiceClient;\n        var container = client.GetBlobContainerClient(_storageOptions.Value.ContainerName);\n        await container.DeleteIfExistsAsync();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/DurableJobs/AzureStorageJobShardManagerTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Internal;\nusing Orleans.DurableJobs;\nusing Orleans.DurableJobs.AzureStorage;\nusing Orleans.Tests.DurableJobs.AzureStorage;\nusing Tester.DurableJobs;\nusing Xunit;\nusing Xunit.Sdk;\n\nnamespace Tester.AzureUtils.DurableJobs;\n\n/// <summary>\n/// Azure Storage-specific tests for job shard manager functionality.\n/// Common tests are delegated to <see cref=\"JobShardManagerTestsRunner\"/> for reusability across providers.\n/// Provider-specific tests (e.g., batching) remain here.\n/// </summary>\n[TestCategory(\"DurableJobs\")]\npublic class AzureStorageJobShardManagerTests : AzureStorageBasicTests, IAsyncDisposable\n{\n    private readonly AzureStorageJobShardManagerTestFixture _fixture;\n    private readonly JobShardManagerTestsRunner _runner;\n\n    internal IOptions<AzureStorageJobShardOptions> StorageOptions { get; }\n\n    public AzureStorageJobShardManagerTests()\n    {\n        StorageOptions = Options.Create(new AzureStorageJobShardOptions());\n        StorageOptions.Value.ConfigureTestDefaults();\n        StorageOptions.Value.ContainerName = \"test-container-\" + Guid.NewGuid().ToString(\"N\");\n\n        // Create fixture and runner for common tests\n        _fixture = new AzureStorageJobShardManagerTestFixture();\n        _runner = new JobShardManagerTestsRunner(_fixture);\n    }\n\n    public async ValueTask DisposeAsync() \n    {\n        // Cleanup storage container\n        var client = StorageOptions.Value.BlobServiceClient;\n        var container = client.GetBlobContainerClient(StorageOptions.Value.ContainerName);\n        await container.DeleteIfExistsAsync();\n        \n        // Cleanup fixture\n        await _fixture.DisposeAsync();\n    }\n\n    #region Common Tests (Delegated to Runner)\n\n    /// <summary>\n    /// Tests basic shard creation and assignment workflow.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_Creation_Assignation()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardCreationAndAssignment(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests reading and consuming jobs from a frozen shard after ownership transfer.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_ReadFrozenShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ReadFrozenShard(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests consuming jobs from a live shard.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_LiveShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.LiveShard(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests job metadata persistence across ownership transfers.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_JobMetadata()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobMetadata(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests concurrent shard assignment to verify ownership conflict resolution.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_ConcurrentShardAssignment_OwnershipConflicts()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ConcurrentShardAssignment_OwnershipConflicts(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests shard metadata preservation across ownership transfers.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_ShardMetadataMerge()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardMetadataMerge(cts.Token);\n    }\n\n    #endregion\n\n    /// <summary>\n    /// Tests stopping shard processing and verifying jobs remain for reassignment.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_StopProcessingShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.StopProcessingShard(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests retrying a job with a new due time.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_RetryJobLater()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.RetryJobLater(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests job cancellation before and during processing.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_JobCancellation()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobCancellation(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests that multiple shard registrations with the same time range produce unique IDs.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_ShardRegistrationRetry_IdCollisions()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardRegistrationRetry_IdCollisions(cts.Token);\n    }\n\n    /// <summary>\n    /// Tests that unregistering a shard with remaining jobs preserves the shard for reassignment.\n    /// This test is delegated to the runner for reuse across providers.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Azure\"), TestCategory(\"Functional\")]\n    public async Task AzureStorageJobShardManager_UnregisterShard_WithJobsRemaining()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.UnregisterShard_WithJobsRemaining(cts.Token);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/DurableJobs/NetstringJsonSerializerTests.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing AwesomeAssertions;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs.AzureStorage;\nusing Xunit;\n\nnamespace Tester.AzureUtils.DurableJobs;\n\n[TestCategory(\"DurableJobs\"), TestCategory(\"BVT\")]\npublic class NetstringJsonSerializerTests\n{\n    private static byte[] EncodeToBytes(JobOperation operation)\n    {\n        var stream = new MemoryStream();\n        NetstringJsonSerializer<JobOperation>.Encode(operation, stream, JobOperationJsonContext.Default.JobOperation);\n        return stream.ToArray();\n    }\n    [Fact]\n    public void Encode_RemoveOperation_ProducesCorrectFormat()\n    {\n        var operation = JobOperation.CreateRemoveOperation(\"job123\");\n        var result = EncodeToBytes(operation);\n        var resultString = Encoding.UTF8.GetString(result);\n        \n        resultString.Should().EndWith(\"\\n\");\n        resultString.Should().Match(\"*:*\\n\");\n        resultString.Should().Contain(\"\\\"type\\\":1\");\n        resultString.Should().Contain(\"\\\"id\\\":\\\"job123\\\"\");\n    }\n\n    [Fact]\n    public void Encode_AddOperation_ProducesCorrectFormat()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var operation = JobOperation.CreateAddOperation(\"job456\", \"TestJob\", dueTime, grainId, null);\n        var result = EncodeToBytes(operation);\n        var resultString = Encoding.UTF8.GetString(result);\n        \n        resultString.Should().EndWith(\"\\n\");\n        resultString.Should().Match(\"*:*\\n\");\n        resultString.Should().Contain(\"\\\"id\\\":\\\"job456\\\"\");\n        resultString.Should().Contain(\"\\\"name\\\":\\\"TestJob\\\"\");\n    }\n\n    [Fact]\n    public void Encode_RetryOperation_ProducesCorrectFormat()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var operation = JobOperation.CreateRetryOperation(\"job789\", dueTime);\n        var result = EncodeToBytes(operation);\n        var resultString = Encoding.UTF8.GetString(result);\n        \n        resultString.Should().EndWith(\"\\n\");\n        resultString.Should().Match(\"*:*\\n\");\n        resultString.Should().Contain(\"\\\"type\\\":2\");\n        resultString.Should().Contain(\"\\\"id\\\":\\\"job789\\\"\");\n    }\n\n    [Fact]\n    public void Encode_AddOperationWithMetadata_ProducesCorrectFormat()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var metadata = new Dictionary<string, string> { [\"key1\"] = \"value1\", [\"key2\"] = \"value2\" };\n        var operation = JobOperation.CreateAddOperation(\"job999\", \"MetaJob\", dueTime, grainId, metadata);\n        var result = EncodeToBytes(operation);\n        var resultString = Encoding.UTF8.GetString(result);\n        \n        resultString.Should().EndWith(\"\\n\");\n        resultString.Should().Contain(\"\\\"metadata\\\"\");\n        resultString.Should().Contain(\"\\\"key1\\\":\\\"value1\\\"\");\n        resultString.Should().Contain(\"\\\"key2\\\":\\\"value2\\\"\");\n    }\n\n    [Fact]\n    public void Encode_VerifiesNetstringFormat()\n    {\n        var operation = JobOperation.CreateRemoveOperation(\"test\");\n        var result = EncodeToBytes(operation);\n        var resultString = Encoding.UTF8.GetString(result);\n        \n        var parts = resultString.Split(':', 2);\n        parts.Should().HaveCount(2);\n        \n        var lengthStr = parts[0];\n        lengthStr.Should().HaveLength(6, \"length prefix should be 6 hex digits\");\n        int.TryParse(lengthStr, System.Globalization.NumberStyles.HexNumber, null, out var length).Should().BeTrue(\"length should be valid hex\");\n        length.Should().BeGreaterThan(0);\n        \n        var dataAndNewline = parts[1];\n        dataAndNewline.Should().EndWith(\"\\n\");\n        \n        var jsonData = dataAndNewline[..^1];\n        var jsonBytes = Encoding.UTF8.GetBytes(jsonData);\n        jsonBytes.Length.Should().Be(length, \"JSON data length should match the hex length prefix\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_RemoveOperation_DecodesCorrectly()\n    {\n        var operation = JobOperation.CreateRemoveOperation(\"job123\");\n        var encoded = EncodeToBytes(operation);\n        var stream = new MemoryStream(encoded);\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(1);\n        results[0].Type.Should().Be(JobOperation.OperationType.Remove);\n        results[0].Id.Should().Be(\"job123\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_AddOperation_DecodesCorrectly()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var operation = JobOperation.CreateAddOperation(\"job456\", \"TestJob\", dueTime, grainId, null);\n        var encoded = EncodeToBytes(operation);\n        var stream = new MemoryStream(encoded);\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(1);\n        results[0].Type.Should().Be(JobOperation.OperationType.Add);\n        results[0].Id.Should().Be(\"job456\");\n        results[0].Name.Should().Be(\"TestJob\");\n        results[0].DueTime.Should().Be(dueTime);\n        results[0].TargetGrainId.Should().Be(grainId);\n    }\n\n    [Fact]\n    public async Task DecodeAsync_MultipleOperations_DecodesCorrectly()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var op1 = JobOperation.CreateAddOperation(\"job1\", \"Job1\", dueTime, grainId, null);\n        var op2 = JobOperation.CreateRemoveOperation(\"job2\");\n        var op3 = JobOperation.CreateRetryOperation(\"job3\", dueTime.AddHours(1));\n        \n        var stream = new MemoryStream();\n        await stream.WriteAsync(EncodeToBytes(op1));\n        await stream.WriteAsync(EncodeToBytes(op2));\n        await stream.WriteAsync(EncodeToBytes(op3));\n        stream.Position = 0;\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(3);\n        results[0].Type.Should().Be(JobOperation.OperationType.Add);\n        results[0].Id.Should().Be(\"job1\");\n        results[1].Type.Should().Be(JobOperation.OperationType.Remove);\n        results[1].Id.Should().Be(\"job2\");\n        results[2].Type.Should().Be(JobOperation.OperationType.Retry);\n        results[2].Id.Should().Be(\"job3\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_AddOperationWithMetadata_DecodesCorrectly()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var metadata = new Dictionary<string, string> { [\"key1\"] = \"value1\", [\"key2\"] = \"value2\" };\n        var operation = JobOperation.CreateAddOperation(\"job999\", \"MetaJob\", dueTime, grainId, metadata);\n        var encoded = EncodeToBytes(operation);\n        var stream = new MemoryStream(encoded);\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(1);\n        results[0].Metadata.Should().NotBeNull();\n        results[0].Metadata.Should().ContainKey(\"key1\").WhoseValue.Should().Be(\"value1\");\n        results[0].Metadata.Should().ContainKey(\"key2\").WhoseValue.Should().Be(\"value2\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_EmptyStream_ReturnsEmpty()\n    {\n        var stream = new MemoryStream();\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().BeEmpty();\n    }\n\n    [Fact]\n    public async Task DecodeAsync_InvalidLength_ThrowsInvalidDataException()\n    {\n        var encoded = \"GGGGGG:{\\\"type\\\":1,\\\"id\\\":\\\"test\\\"}\\n\"; // Invalid hex\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw before yielding any items\n            }\n        };\n        \n        await act.Should().ThrowAsync<InvalidDataException>()\n            .WithMessage(\"Invalid netstring length: GGGGGG\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_ExcessiveLength_ThrowsInvalidDataException()\n    {\n        var encoded = \"FFFFFF:{\\\"type\\\":1}\\n\"; // 16777215 bytes, exceeds MaxLength\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw before yielding any items\n            }\n        };\n        \n        await act.Should().ThrowAsync<InvalidDataException>()\n            .WithMessage(\"Netstring length out of valid range: *\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_MissingTrailingNewline_ThrowsInvalidDataException()\n    {\n        var json = \"{\\\"type\\\":1,\\\"id\\\":\\\"test\\\"}\";\n        var jsonBytes = Encoding.UTF8.GetBytes(json);\n        var encoded = $\"{jsonBytes.Length:X6}:{json}x\"; // Use 6-digit hex format\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw after reading the data\n            }\n        };\n        \n        await act.Should().ThrowAsync<InvalidDataException>()\n            .WithMessage(\"Expected newline at end of netstring, got byte value *\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_IncompleteData_ThrowsEndOfStreamException()\n    {\n        var encoded = \"000064:{\\\"type\\\":1}\"; // Claims 100 bytes but only provides 11\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw before yielding any items\n            }\n        };\n        \n        await act.Should().ThrowAsync<InvalidDataException>();\n    }\n\n    [Fact]\n    public async Task DecodeAsync_WrongTrailingCharacter_ThrowsInvalidDataException()\n    {\n        var json = \"{\\\"type\\\":1,\\\"id\\\":\\\"test\\\"}\";\n        var jsonBytes = Encoding.UTF8.GetBytes(json);\n        var encoded = $\"{jsonBytes.Length:X6}:{json}X\"; // Use 6-digit hex format\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw after reading the data\n            }\n        };\n        \n        await act.Should().ThrowAsync<InvalidDataException>()\n            .WithMessage(\"Expected newline at end of netstring, got byte value *\");\n    }\n\n    [Fact]\n    public async Task DecodeAsync_InvalidJson_ThrowsJsonException()\n    {\n        var invalidJson = \"{invalid json}\";\n        var jsonBytes = Encoding.UTF8.GetBytes(invalidJson);\n        var encoded = $\"{jsonBytes.Length:X6}:{invalidJson}\\n\"; // Use 6-digit hex format\n        var stream = new MemoryStream(Encoding.UTF8.GetBytes(encoded));\n        \n        var act = async () =>\n        {\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                // Should throw when deserializing\n            }\n        };\n        \n        await act.Should().ThrowAsync<JsonException>();\n    }\n\n    [Fact]\n    public async Task EncodeAndDecode_RoundTrip_PreservesData()\n    {\n        var dueTime1 = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var dueTime2 = new DateTimeOffset(2025, 11, 1, 14, 30, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        var metadata = new Dictionary<string, string> { [\"env\"] = \"prod\", [\"region\"] = \"us-east\" };\n        \n        var testOperations = new[]\n        {\n            JobOperation.CreateRemoveOperation(\"remove-job\"),\n            JobOperation.CreateAddOperation(\"add-job\", \"MyJob\", dueTime1, grainId, null),\n            JobOperation.CreateRetryOperation(\"retry-job\", dueTime2),\n            JobOperation.CreateAddOperation(\"meta-job\", \"MetaJob\", dueTime1, grainId, metadata)\n        };\n\n        foreach (var operation in testOperations)\n        {\n            var encoded = EncodeToBytes(operation);\n            var stream = new MemoryStream(encoded);\n            \n            var results = new List<JobOperation>();\n            await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n            {\n                results.Add(item);\n            }\n            \n            results.Should().HaveCount(1);\n            results[0].Type.Should().Be(operation.Type);\n            results[0].Id.Should().Be(operation.Id);\n            results[0].Name.Should().Be(operation.Name);\n            results[0].DueTime.Should().Be(operation.DueTime);\n            results[0].TargetGrainId.Should().Be(operation.TargetGrainId);\n            \n            if (operation.Metadata is not null)\n            {\n                results[0].Metadata.Should().NotBeNull();\n                results[0].Metadata.Should().BeEquivalentTo(operation.Metadata);\n            }\n        }\n    }\n\n    [Fact]\n    public async Task EncodeAndDecode_MultipleOperations_RoundTrip()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        \n        var testOperations = new[]\n        {\n            JobOperation.CreateAddOperation(\"job1\", \"First\", dueTime, grainId, null),\n            JobOperation.CreateRemoveOperation(\"job2\"),\n            JobOperation.CreateRetryOperation(\"job3\", dueTime.AddHours(1)),\n            JobOperation.CreateAddOperation(\"job4\", \"Fourth\", dueTime.AddDays(1), grainId, null)\n        };\n\n        var memoryStream = new MemoryStream();\n        foreach (var operation in testOperations)\n        {\n            var encoded = EncodeToBytes(operation);\n            await memoryStream.WriteAsync(encoded);\n        }\n        \n        memoryStream.Position = 0;\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(memoryStream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(4);\n        for (var i = 0; i < testOperations.Length; i++)\n        {\n            results[i].Type.Should().Be(testOperations[i].Type);\n            results[i].Id.Should().Be(testOperations[i].Id);\n        }\n    }\n\n    [Fact]\n    public async Task DecodeAsync_StreamPosition_IsPreserved()\n    {\n        var operation = JobOperation.CreateRemoveOperation(\"test\");\n        var encoded = EncodeToBytes(operation);\n        var stream = new MemoryStream(encoded);\n        \n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            // Stream should be at the end after reading\n        }\n        \n        stream.Position.Should().Be(stream.Length);\n    }\n\n    [Fact]\n    public async Task EncodeAndDecode_LargeMetadata_HandlesCorrectly()\n    {\n        var dueTime = new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero);\n        var grainId = GrainId.Create(\"test\", \"grain1\");\n        \n        var largeMetadata = new Dictionary<string, string>();\n        for (var i = 0; i < 100; i++)\n        {\n            largeMetadata[$\"key{i}\"] = new string('x', 1000);\n        }\n        \n        var operation = JobOperation.CreateAddOperation(\"large-job\", \"LargeMetaJob\", dueTime, grainId, largeMetadata);\n        var encoded = EncodeToBytes(operation);\n        var stream = new MemoryStream(encoded);\n        \n        var results = new List<JobOperation>();\n        await foreach (var item in NetstringJsonSerializer<JobOperation>.DecodeAsync(stream, JobOperationJsonContext.Default.JobOperation, CancellationToken.None))\n        {\n            results.Add(item);\n        }\n        \n        results.Should().HaveCount(1);\n        results[0].Metadata.Should().NotBeNull();\n        results[0].Metadata.Should().HaveCount(100);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/GenericGrainsInAzureStorageTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester.AzureUtils.General\n{\n    /// <summary>\n    /// Tests for generic grain types using Azure Table Storage as the persistence provider.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Generics\")]\n    public class GenericGrainsInAzureTableStorageTests : OrleansTestingBase, IClassFixture<GenericGrainsInAzureTableStorageTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            }\n\n            protected override void CheckPreconditionsOrThrow()\n            {\n                base.CheckPreconditionsOrThrow();\n                StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n            }\n\n            private class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddAzureTableGrainStorage(\"AzureStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                        {\n                            options.ConfigureTestDefaults();\n                        }));\n                }\n            }\n        }\n\n        public GenericGrainsInAzureTableStorageTests(Fixture fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n            this.fixture = fixture;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Generic_OnAzureTableStorage_LongNamedGrain_EchoValue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ISimpleGenericGrainUsingAzureStorageAndLongGrainName<int>>(Guid.NewGuid());\n            await grain.EchoAsync(42);\n\n            await grain.ClearState();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Generic_OnAzureTableStorage_ShortNamedGrain_EchoValue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ITinyNameGrain<int>>(Guid.NewGuid());\n            await grain.EchoAsync(42);\n\n            await grain.ClearState();\n        }\n    }\n\n    /// <summary>\n    /// Tests for generic grain types using Azure Blob Storage as the persistence provider.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Generics\")]\n    public class GenericGrainsInAzureBlobStorageTests : OrleansTestingBase, IClassFixture<GenericGrainsInAzureBlobStorageTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            }\n\n            private class StorageSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddAzureBlobGrainStorage(\"AzureStore\", (AzureBlobStorageOptions options) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    });\n                }\n            }\n\n            protected override void CheckPreconditionsOrThrow()\n            {\n                base.CheckPreconditionsOrThrow();\n                StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n            }\n        }\n\n        public GenericGrainsInAzureBlobStorageTests(Fixture fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n            this.fixture = fixture;\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Generic_OnAzureBlobStorage_LongNamedGrain_EchoValue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ISimpleGenericGrainUsingAzureStorageAndLongGrainName<int>>(Guid.NewGuid());\n            await grain.EchoAsync(42);\n\n            await grain.ClearState();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Generic_OnAzureBlobStorage_ShortNamedGrain_EchoValue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ITinyNameGrain<int>>(Guid.NewGuid());\n            await grain.EchoAsync(42);\n\n            await grain.ClearState();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/GrainDirectory/AzureMultipleGrainDirectoriesTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing Tester.AzureUtils;\nusing UnitTests.Grains.Directories;\n\nnamespace Tester.Directories\n{\n    /// <summary>\n    /// Tests for custom grain directory functionality using Azure Table Storage as the directory backend.\n    /// </summary>\n    [TestCategory(\"AzureStorage\")]\n    public class AzureMultipleGrainDirectoriesTests : MultipleGrainDirectoriesTests\n    {\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder.AddAzureTableGrainDirectory(\n                    CustomDirectoryGrain.DIRECTORY,\n                    options => options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient());\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow() => TestUtils.CheckForAzureStorage();\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            EnsurePreconditionsMet();\n\n            base.ConfigureTestCluster(builder);\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Lease/AzureBlobLeaseProviderTests.cs",
    "content": "using Xunit.Abstractions;\nusing Orleans.LeaseProviders;\nusing TestExtensions.Runners;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.Options;\n\nnamespace Tester.AzureUtils.Lease\n{\n    [TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"Lease\")]\n    public class AzureBlobLeaseProviderTests : GoldenPathLeaseProviderTestRunner\n    {\n        public AzureBlobLeaseProviderTests(ITestOutputHelper output)\n            :base(CreateLeaseProvider(), output)\n        {\n        }\n\n        private static ILeaseProvider CreateLeaseProvider()\n        {\n            TestUtils.CheckForAzureStorage();\n            return new AzureBlobLeaseProvider(Options.Create(new AzureBlobLeaseProviderOptions()\n            {\n                BlobContainerName = \"test-blob-container-name\"\n            }.ConfigureTestDefaults()));\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Lease/LeaseBasedQueueBalancerTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Lease\n{\n    /// <summary>\n    /// Tests for lease-based queue balancer functionality in Azure Storage, including auto-scaling and node failure scenarios.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"Lease\")]\n    public class LeaseBasedQueueBalancerTests : TestClusterPerTest\n    {\n        private const string StreamProviderName = \"MemoryStreamProvider\";\n        private static readonly int totalQueueCount = 6;\n        private static readonly short siloCount = 4;\n\n        //since lease length is 1 min, so set time out to be two minutes to fulfill some test scenario\n        public static readonly TimeSpan TimeOut = TimeSpan.FromMinutes(2);\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n            builder.Options.InitialSilosCount = siloCount;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .UseAzureBlobLeaseProvider(ob => ob.Configure<IOptions<ClusterOptions>>((options, cluster) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.BlobContainerName = \"cluster-\" + cluster.Value.ClusterId + \"-leases\";\n                    }))\n                    .UseAzureStorageClustering(options => options.ConfigureTestDefaults())\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b=>\n                    {\n                        b.ConfigurePartitioning(totalQueueCount);\n                        b.UseLeaseBasedQueueBalancer(ob => ob.Configure(options =>\n                        {\n                            options.LeaseLength = TimeSpan.FromSeconds(15);\n                            options.LeaseRenewPeriod = TimeSpan.FromSeconds(10);\n                            options.LeaseAcquisitionPeriod = TimeSpan.FromSeconds(10);\n                        }));\n                    })\n                    .ConfigureLogging(builder => builder.AddFilter($\"LeaseBasedQueueBalancer-{StreamProviderName}\", LogLevel.Trace))\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n        }\n\n        [SkippableFact]\n        public async Task LeaseBalancedQueueBalancer_SupportAutoScaleScenario()\n        {\n            var mgmtGrain = this.GrainFactory.GetGrain<IManagementGrain>(0);\n            //6 queue and 4 silo, then each agent manager should own queues/agents in range of [1, 2]\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(1, 2, mgmtGrain, lastTry), TimeOut);\n            //stop one silo, 6 queues, 3 silo, then each agent manager should own 2 queues \n            await this.HostedCluster.StopSiloAsync(this.HostedCluster.SecondarySilos[0]);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(2, 2, mgmtGrain, lastTry), TimeOut);\n            //stop another silo, 6 queues, 2 silo, then each agent manager should own 3 queues\n            await this.HostedCluster.StopSiloAsync(this.HostedCluster.SecondarySilos[0]);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(3, 3, mgmtGrain, lastTry), TimeOut);\n            //start one silo, 6 queues, 3 silo, then each agent manager should own 2 queues\n            this.HostedCluster.StartAdditionalSilo(true);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(2, 2, mgmtGrain, lastTry), TimeOut);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9559\")]\n        public async Task LeaseBalancedQueueBalancer_SupportUnexpectedNodeFailureScenerio()\n        {\n            var mgmtGrain = this.GrainFactory.GetGrain<IManagementGrain>(0);\n            //6 queue and 4 silo, then each agent manager should own queues/agents in range of [1, 2]\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(1, 2, mgmtGrain, lastTry), TimeOut);\n            //stop one silo, 6 queues, 3 silo, then each agent manager should own 2 queues \n            await this.HostedCluster.KillSiloAsync(this.HostedCluster.SecondarySilos[0]);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(2, 2, mgmtGrain, lastTry), TimeOut);\n            //stop another silo, 6 queues, 2 silo, then each agent manager should own 3 queues\n            await this.HostedCluster.KillSiloAsync(this.HostedCluster.SecondarySilos[0]);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(3, 3, mgmtGrain, lastTry), TimeOut);\n            //start one silo, 6 queues, 3 silo, then each agent manager should own 2 queues\n            this.HostedCluster.StartAdditionalSilo(true);\n            await TestingUtils.WaitUntilAsync(lastTry => AgentManagerOwnCorrectAmountOfAgents(2, 2, mgmtGrain, lastTry), TimeOut);\n        }\n\n        private static async Task<bool> AgentManagerOwnCorrectAmountOfAgents(int expectedAgentCountMin, int expectedAgentCountMax, IManagementGrain mgmtGrain, bool assertIsTrue)\n        {\n            await Task.Delay(TimeSpan.FromSeconds(10));\n            bool pass;\n            try\n            {\n                object[] agentStarted = await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName, (int)PersistentStreamProviderCommand.GetNumberRunningAgents, null);\n                int[] counts = agentStarted.Select(startedAgentInEachSilo => Convert.ToInt32(startedAgentInEachSilo)).ToArray();\n                int sum = counts.Sum();\n                pass = totalQueueCount == sum &&\n                    counts.All(startedAgentInEachSilo => startedAgentInEachSilo <= expectedAgentCountMax && startedAgentInEachSilo >= expectedAgentCountMin);\n                if(!pass && assertIsTrue)\n                    throw new OrleansException($\"AgentManager doesn't own correct amount of agents: {string.Join(\",\", counts.Select(startedAgentInEachSilo => startedAgentInEachSilo.ToString()))}\");\n            }\n            catch\n            {\n                pass = false;\n                if (assertIsTrue)\n                    throw;\n            }\n            return pass;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Orleans.Azure.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <DefineConstants>TRACE;TESTER_AZUREUTILS;ORLEANS_PERSISTENCE</DefineConstants>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <GenerateProgramFile>false</GenerateProgramFile>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n    <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Aspire.Azure.Storage.Queues\" />\n    <PackageReference Include=\"Azure.Data.Tables\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Streaming.Tests\\Orleans.Streaming.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.DurableJobs.Tests\\Orleans.DurableJobs.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)\\src\\Azure\\Orleans.Reminders.AzureStorage\\Orleans.Reminders.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)\\src\\Azure\\Orleans.DurableJobs.AzureStorage\\Orleans.DurableJobs.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)\\src\\Azure\\Orleans.GrainDirectory.AzureStorage\\Orleans.GrainDirectory.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)\\src\\Azure\\Orleans.Streaming.AzureStorage\\Orleans.Streaming.AzureStorage.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Include=\"$(SourceRoot)src\\Azure\\Shared\\Utilities\\ErrorCode.cs\" Link=\"Utilities\\ErrorCode.cs\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceGrainTests_AzureBlobStore.cs",
    "content": "//#define REREAD_STATE_AFTER_WRITE_FAILED\n\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\nusing Orleans.Configuration;\n\nnamespace Tester.AzureUtils.Persistence;\n\n/// <summary>\n/// PersistenceGrainTests using AzureStore - Requires access to external Azure blob storage\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceGrainTests_AzureBlobStore : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceGrainTests_AzureBlobStore.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddAzureBlobGrainStorage(\"AzureStore\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddAzureBlobGrainStorage(\"AzureStore1\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddAzureBlobGrainStorage(\"AzureStore2\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddAzureBlobGrainStorage(\"AzureStore3\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddAzureBlobGrainStorage(\"GrainStorageForTest\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddMemoryGrainStorage(\"test1\")\n                .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n    }\n\n    public PersistenceGrainTests_AzureBlobStore(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n\n    [SkippableTheory, TestCategory(\"Functional\")]\n    [InlineData(\"AzureStore\")]\n    [InlineData(\"AzureStore1\")]\n    [InlineData(\"AzureStore2\")]\n    [InlineData(\"AzureStore3\")]\n    public Task Persistence_Silo_StorageProvider_AzureBlobStore(string providerName)\n    {\n        return base.Persistence_Silo_StorageProvider(providerName);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceGrainTests_AzureBlobStore_Json.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.TestingHost;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Persistence;\n\n/// <summary>\n/// PersistenceGrainTests using AzureStore - Requires access to external Azure blob storage\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceGrainTests_AzureBlobStore_Json : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceGrainTests_AzureBlobStore_Json.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureBlobGrainStorage(\"GrainStorageForTest\", (AzureBlobStorageOptions options) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    })\n                    .AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddMemoryGrainStorage(\"test1\");\n            }\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n    }\n\n    public PersistenceGrainTests_AzureBlobStore_Json(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceGrainTests_AzureStore.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing TestExtensions.Runners;\n\nnamespace Tester.AzureUtils.Persistence\n{\n    /// <summary>\n    /// Base_PersistenceGrainTests - a base class for testing persistence providers\n    /// </summary>\n    public abstract class Base_PersistenceGrainTests_AzureStore : GrainPersistenceTestsRunner\n    {\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseAzureStorageClustering(options =>\n                {\n                    options.ConfigureTestDefaults();\n                });\n            }\n        }\n\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.UseAzureStorageClustering(gatewayOptions => { gatewayOptions.ConfigureTestDefaults(); });\n            }\n        }\n\n        protected Base_PersistenceGrainTests_AzureStore(ITestOutputHelper output, BaseTestClusterFixture fixture, string grainNamespace = \"UnitTests.Grains\")\n            : base(output, fixture, grainNamespace)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceGrainTests_AzureTableGrainStorage.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\n\nnamespace Tester.AzureUtils.Persistence;\n\n/// <summary>\n/// PersistenceGrainTests using AzureGrainStorage - Requires access to external Azure table storage\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceGrainTests_AzureTableGrainStorage : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceGrainTests_AzureTableGrainStorage.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureTableGrainStorage(\"GrainStorageForTest\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore1\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore2\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore3\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n    }\n\n    public PersistenceGrainTests_AzureTableGrainStorage(ITestOutputHelper output, Fixture fixture) : \n        base(output, fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceGrainTests_AzureTableGrainStorage_DeleteStateOnClear : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceGrainTests_AzureTableGrainStorage_DeleteStateOnClear.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureTableGrainStorage(\"GrainStorageForTest\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.DeleteStateOnClear = true;\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore1\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore2\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddAzureTableGrainStorage(\"AzureStore3\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n    }\n\n    public PersistenceGrainTests_AzureTableGrainStorage_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture) : \n        base(output, fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceProviderTests.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing Azure.Data.Tables;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Newtonsoft.Json;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Storage;\nusing Samples.StorageProviders;\nusing TestExtensions;\nusing UnitTests.Persistence;\nusing UnitTests.StorageTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Persistence\n{\n    /// <summary>\n    /// Tests for Azure Table Storage persistence provider, including serialization formats and storage conversions.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    [TestCategory(\"Persistence\")]\n    public class PersistenceProviderTests_Local\n    {\n        private readonly IProviderRuntime providerRuntime;\n        private readonly Dictionary<string, string> providerCfgProps = new Dictionary<string, string>();\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n\n        public PersistenceProviderTests_Local(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            this.providerRuntime = new ClientProviderRuntime(\n                fixture.InternalGrainFactory,\n                fixture.Services,\n                fixture.Services.GetRequiredService<ClientGrainContext>());\n            this.providerCfgProps.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task PersistenceProvider_Mock_WriteRead()\n        {\n            const string testName = nameof(PersistenceProvider_Mock_WriteRead);\n\n            var store = ActivatorUtilities.CreateInstance<MockStorageProvider>(fixture.Services, testName);\n\n            await Test_PersistenceProvider_WriteRead(testName, store);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task PersistenceProvider_FileStore_WriteRead()\n        {\n            const string testName = nameof(PersistenceProvider_FileStore_WriteRead);\n\n            var store = new OrleansFileStorage(\"Data\");\n            await Test_PersistenceProvider_WriteRead(testName, store);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        public async Task PersistenceProvider_Azure_Read()\n        {\n            TestUtils.CheckForAzureStorage();\n            const string testName = nameof(PersistenceProvider_Azure_Read);\n\n            AzureTableGrainStorage store = await InitAzureTableGrainStorage();\n            await Test_PersistenceProvider_Read(testName, store);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, false)]\n        [InlineData(null, true)]\n        [InlineData(15 * 64 * 1024 - 256, false)]\n        [InlineData(15 * 32 * 1024 - 256, true)]\n        public async Task PersistenceProvider_Azure_WriteRead(int? stringLength, bool useJson)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4})\",\n                nameof(PersistenceProvider_Azure_WriteRead),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJson), useJson);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var store = await InitAzureTableGrainStorage(useJson);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, false, false)]\n        [InlineData(null, true, false)]\n        [InlineData(15 * 64 * 1024 - 256, false, false)]\n        [InlineData(15 * 32 * 1024 - 256, true, false)]\n        public async Task PersistenceProvider_Azure_WriteClearRead(int? stringLength, bool useJson, bool useFallback)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4}, {5} = {6})\",\n                nameof(PersistenceProvider_Azure_WriteClearRead),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJson), useJson,\n                nameof(useFallback), useFallback);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var store = await InitAzureTableGrainStorage(useJson, useFallback);\n\n            await Test_PersistenceProvider_WriteClearRead(testName, store, grainState);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, true, false)]\n        [InlineData(null, false, true)]\n        [InlineData(15 * 32 * 1024 - 256, true, false)]\n        [InlineData(15 * 32 * 1024 - 256, false, true)]\n        public async Task PersistenceProvider_Azure_ChangeReadFormat(int? stringLength, bool useJsonForWrite, bool useJsonForRead)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4}, {5} = {6})\",\n                nameof(PersistenceProvider_Azure_ChangeReadFormat),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                nameof(useJsonForWrite), useJsonForWrite,\n                nameof(useJsonForRead), useJsonForRead);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n            var grainId = LegacyGrainId.NewId();\n\n            var store = await InitAzureTableGrainStorage(useJsonForWrite);\n\n            grainState = await Test_PersistenceProvider_WriteRead(testName, store,\n                grainState, grainId);\n\n            store = await InitAzureTableGrainStorage(useJsonForRead);\n\n            await Test_PersistenceProvider_Read(testName, store, grainState, grainId);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, true, false)]\n        [InlineData(null, false, true)]\n        [InlineData(15 * 32 * 1024 - 256, true, false)]\n        [InlineData(15 * 32 * 1024 - 256, false, true)]\n        public async Task PersistenceProvider_Azure_ChangeWriteFormat(int? stringLength, bool useJsonForFirstWrite, bool useJsonForSecondWrite)\n        {\n            var testName = string.Format(\"{0}({1}={2},{3}={4},{5}={6})\",\n                nameof(PersistenceProvider_Azure_ChangeWriteFormat),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                \"json1stW\", useJsonForFirstWrite,\n                \"json2ndW\", useJsonForSecondWrite);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var grainId = LegacyGrainId.NewId();\n\n            var store = await InitAzureTableGrainStorage(useJsonForFirstWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n\n            grainState = TestStoreGrainState.NewRandomState(stringLength);\n            grainState.ETag = \"*\";\n\n            store = await InitAzureTableGrainStorage(useJsonForSecondWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, true, false)]\n        [InlineData(null, false, true)]\n        [InlineData(15 * 32 * 1024 - 256, true, false)]\n        [InlineData(15 * 32 * 1024 - 256, false, true)]\n        public async Task PersistenceProvider_Azure_ChangeStorageDataFormat_WhenJsonSerializerIsUsed(int? stringLength, bool useStringFormatForFirstWrite, bool useStringFormatForSecondWrite)\n        {\n            // always use JsonSerializer over OrleansSerializer since specifying 'useStringFormat = true'\n            // writes to 'StringData', the OrleansSerializer can not read from the 'StringData' column as its not a format which it expects.\n            const bool useJson = true;\n\n            var testName = string.Format(\"{0}({1}={2},{3}={4},{5}={6})\",\n                nameof(PersistenceProvider_Azure_ChangeStorageDataFormat_WhenJsonSerializerIsUsed),\n                nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n                \"strFormat1stW\", useStringFormatForFirstWrite,\n                \"strFormat2ndW\", useStringFormatForSecondWrite);\n\n            var grainState = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(grainState);\n\n            var grainId = LegacyGrainId.NewId();\n\n            var store = await InitAzureTableGrainStorage(useJson: useJson, useStringFormat: useStringFormatForFirstWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n\n            grainState = TestStoreGrainState.NewRandomState(stringLength);\n            grainState.ETag = \"*\";\n\n            store = await InitAzureTableGrainStorage(useJson: useJson, useStringFormat: useStringFormatForSecondWrite);\n\n            await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n        }\n\n        [SkippableTheory, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        [InlineData(null, false)]\n        [InlineData(null, true)]\n        [InlineData(15 * 64 * 1024 - 256, false)]\n        [InlineData(15 * 32 * 1024 - 256, true)]\n        public async Task AzureTableStorage_ConvertToFromStorageFormat(int? stringLength, bool useJson)\n        {\n            var testName = string.Format(\"{0}({1} = {2}, {3} = {4})\",\n               nameof(AzureTableStorage_ConvertToFromStorageFormat),\n               nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString(),\n               nameof(useJson), useJson);\n\n            var state = TestStoreGrainState.NewRandomState(stringLength);\n            EnsureEnvironmentSupportsState(state);\n\n            var storage = await InitAzureTableGrainStorage(useJson);\n            var initialState = state.State;\n\n            var entity = new TableEntity();\n\n            storage.ConvertToStorageFormat(initialState, entity);\n\n            var convertedState = storage.ConvertFromStorageFormat<TestStoreGrainState>(entity);\n            Assert.NotNull(convertedState);\n            Assert.Equal(initialState.A, convertedState.A);\n            Assert.Equal(initialState.B, convertedState.B);\n            Assert.Equal(initialState.C, convertedState.C);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        public async Task AzureTableStorage_ConvertJsonToFromStorageFormatWithCustomJsonProperties()\n        {\n            TestUtils.CheckForAzureStorage();\n            var state = TestStoreGrainStateWithCustomJsonProperties.NewRandomState(null);\n\n            var storage = await InitAzureTableGrainStorage(useJson: true, typeNameHandling: TypeNameHandling.None);\n            var initialState = state.State;\n\n            var entity = new TableEntity();\n\n            storage.ConvertToStorageFormat(initialState, entity);\n\n            var convertedState = storage.ConvertFromStorageFormat<TestStoreGrainStateWithCustomJsonProperties>(entity);\n            Assert.NotNull(convertedState);\n            Assert.Equal(initialState.String, convertedState.String);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public async Task PersistenceProvider_Memory_FixedLatency_WriteRead()\n        {\n            const string testName = nameof(PersistenceProvider_Memory_FixedLatency_WriteRead);\n            var expectedLatency = TimeSpan.FromMilliseconds(200);\n            var store = new MemoryGrainStorageWithLatency(\n                testName,\n                new MemoryStorageWithLatencyOptions()\n                {\n                    Latency = expectedLatency,\n                    MockCallsOnly = true\n                },\n                NullLoggerFactory.Instance,\n                providerRuntime.ServiceProvider.GetRequiredService<IGrainFactory>(),\n                providerRuntime.ServiceProvider.GetRequiredService<IActivatorProvider>(),\n                providerRuntime.ServiceProvider.GetService<IGrainStorageSerializer>());\n\n            var reference = (GrainId)LegacyGrainId.NewId();\n            var state = TestStoreGrainState.NewRandomState();\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            await store.WriteStateAsync(testName, reference, state);\n            TimeSpan writeTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Write time = {1}\", store.GetType().FullName, writeTime);\n            Assert.True(writeTime >= expectedLatency, $\"Write: Expected minimum latency = {expectedLatency} Actual = {writeTime}\");\n\n            sw.Restart();\n            var storedState = new GrainState<TestStoreGrainState>();\n            await store.ReadStateAsync(testName, reference, storedState);\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Read time = {1}\", store.GetType().FullName, readTime);\n            Assert.True(readTime >= expectedLatency, $\"Read: Expected minimum latency = {expectedLatency} Actual = {readTime}\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void LoadClassByName()\n        {\n            string className = typeof(MockStorageProvider).FullName;\n            Type classType = new CachedTypeResolver().ResolveType(className);\n            Assert.NotNull(classType); // Type\n            Assert.True(typeof(IGrainStorage).IsAssignableFrom(classType), $\"Is an IStorageProvider : {classType.FullName}\");\n        }\n\n        private async Task<AzureTableGrainStorage> InitAzureTableGrainStorage(bool useJson = false, bool useFallback = true, bool useStringFormat = false, TypeNameHandling? typeNameHandling = null)\n        {\n            if (useStringFormat && !useJson)\n            {\n                throw new InvalidOperationException($\"Using {nameof(OrleansGrainStorageSerializer)} in conjuction with string data format makes no sense, there for stopping attempt.\");\n            }\n\n            var options = new AzureTableStorageOptions();\n            var jsonOptions = this.providerRuntime.ServiceProvider.GetService<IOptions<OrleansJsonSerializerOptions>>();\n            if (typeNameHandling != null)\n            {\n                jsonOptions.Value.JsonSerializerSettings.TypeNameHandling = typeNameHandling.Value;\n            }\n\n            options.ConfigureTestDefaults();\n            options.UseStringFormat = useStringFormat;\n\n            // TODO change test to include more serializer?\n            var binarySerializer = new OrleansGrainStorageSerializer(this.providerRuntime.ServiceProvider.GetRequiredService<Serializer>());\n            var jsonSerializer = new JsonGrainStorageSerializer(new OrleansJsonSerializer(jsonOptions));\n            if (useFallback)\n                options.GrainStorageSerializer = useJson\n                    ? new GrainStorageSerializer(jsonSerializer, binarySerializer)\n                    : new GrainStorageSerializer(binarySerializer, jsonSerializer);\n            else\n                options.GrainStorageSerializer = useJson ? jsonSerializer : binarySerializer;\n\n            AzureTableGrainStorage store = ActivatorUtilities.CreateInstance<AzureTableGrainStorage>(this.providerRuntime.ServiceProvider, options, \"TestStorage\");\n            ISiloLifecycleSubject lifecycle = ActivatorUtilities.CreateInstance<SiloLifecycleSubject>(this.providerRuntime.ServiceProvider);\n            store.Participate(lifecycle);\n            await lifecycle.OnStart();\n            return store;\n        }\n\n        private async Task Test_PersistenceProvider_Read(string grainTypeName, IGrainStorage store,\n            GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? (GrainId)LegacyGrainId.NewId() : grainId;\n\n            if (grainState == null)\n            {\n                grainState = new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n            }\n            var storedGrainState = new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Read time = {1}\", store.GetType().FullName, readTime);\n\n            var storedState = storedGrainState.State;\n            Assert.Equal(grainState.State.A, storedState.A);\n            Assert.Equal(grainState.State.B, storedState.B);\n            Assert.Equal(grainState.State.C, storedState.C);\n        }\n\n        private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteRead(string grainTypeName,\n            IGrainStorage store, GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? (GrainId)LegacyGrainId.NewId() : grainId;\n\n            if (grainState == null)\n            {\n                grainState = TestStoreGrainState.NewRandomState();\n            }\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.WriteStateAsync(grainTypeName, reference, grainState);\n\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n\n            var storedGrainState = new GrainState<TestStoreGrainState>\n            {\n                State = new TestStoreGrainState()\n            };\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.Equal(grainState.State.A, storedGrainState.State.A);\n            Assert.Equal(grainState.State.B, storedGrainState.State.B);\n            Assert.Equal(grainState.State.C, storedGrainState.State.C);\n\n            return storedGrainState;\n        }\n\n        private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteClearRead(string grainTypeName,\n            IGrainStorage store, GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n        {\n            var reference = grainId.IsDefault ? (GrainId)LegacyGrainId.NewId() : grainId;\n\n            if (grainState == null)\n            {\n                grainState = TestStoreGrainState.NewRandomState();\n            }\n\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n\n            await store.WriteStateAsync(grainTypeName, reference, grainState);\n\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n\n            await store.ClearStateAsync(grainTypeName, reference, grainState);\n\n            var storedGrainState = new GrainState<TestStoreGrainState>\n            {\n                State = new TestStoreGrainState()\n            };\n            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);\n            TimeSpan readTime = sw.Elapsed;\n            this.output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.NotNull(storedGrainState.State);\n            Assert.Equal(default, storedGrainState.State.A);\n            Assert.Equal(default, storedGrainState.State.B);\n            Assert.Equal(default, storedGrainState.State.C);\n\n            return storedGrainState;\n        }\n\n        private static void EnsureEnvironmentSupportsState(GrainState<TestStoreGrainState> grainState)\n        {\n            if (grainState.State.A.Length > 400 * 1024)\n            {\n                StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();\n            }\n\n            TestUtils.CheckForAzureStorage();\n        }\n\n        public class TestStoreGrainStateWithCustomJsonProperties\n        {\n            [JsonProperty(\"s\")]\n            public string String { get; set; }\n\n            internal static GrainState<TestStoreGrainStateWithCustomJsonProperties> NewRandomState(int? aPropertyLength = null)\n            {\n                return new GrainState<TestStoreGrainStateWithCustomJsonProperties>\n                {\n                    State = new TestStoreGrainStateWithCustomJsonProperties\n                    {\n                        String = aPropertyLength == null\n                            ? Random.Shared.Next().ToString(CultureInfo.InvariantCulture)\n                            : GenerateRandomDigitString(aPropertyLength.Value)\n                    }\n                };\n            }\n\n            private static string GenerateRandomDigitString(int stringLength)\n            {\n                var characters = new char[stringLength];\n                for (var i = 0; i < stringLength; ++i)\n                {\n                    characters[i] = (char)Random.Shared.Next('0', '9' + 1);\n                }\n                return new string(characters);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceStateTests_AzureBlobStore.cs",
    "content": "//#define REREAD_STATE_AFTER_WRITE_FAILED\n\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\nusing Orleans.Configuration;\nusing Orleans.Storage;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Azure.Storage.Blobs;\n\nnamespace Tester.AzureUtils.Persistence;\n\n/// <summary>\n/// PersistenceStateTests using AzureStore - Requires access to external Azure blob storage\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceStateTests_AzureBlobStore : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceStateTests_AzureBlobStore.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddAzureBlobGrainStorage(\"GrainStorageForTest\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.DeleteStateOnClear = false;\n                });\n            }\n        }\n    }\n\n    public PersistenceStateTests_AzureBlobStore(ITestOutputHelper output, Fixture fixture) : base(output, fixture, \"UnitTests.PersistentState.Grains\")\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceStateTests_AzureBlobStore_CustomContainerFactory : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceStateTests_AzureBlobStore_CustomContainerFactory.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddAzureBlobGrainStorage(\"GrainStorageForTest\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.DeleteStateOnClear = true;\n                    options.BuildContainerFactory = (_, _) => new TestBlobContainerFactory();\n                });\n            }\n        }\n\n        private class TestBlobContainerFactory : IBlobContainerFactory\n        {\n            private BlobServiceClient _blobServiceClient;\n            private const string NamePrefix = \"test-container\";\n\n            public BlobContainerClient GetBlobContainerClient(GrainId grainId)\n            {\n                if (_blobServiceClient == null)\n                {\n                    throw new InvalidOperationException(\"BlobServiceClient is not initialized.\");\n                }\n                var grainKey = grainId.Key.ToString();\n                var containerName = BuildAzureBlobContainerName(NamePrefix, grainKey);\n                return _blobServiceClient.GetBlobContainerClient(containerName);\n            }\n\n            public Task InitializeAsync(BlobServiceClient client)\n            {\n                _blobServiceClient = client;\n                return Task.CompletedTask;\n            }\n\n            private static string BuildAzureBlobContainerName(string prefix, string grainKey)\n            {\n                var normalizedGrainKey = KeepLettersAndDigits(grainKey);\n                if (string.IsNullOrWhiteSpace(normalizedGrainKey))\n                {\n                    normalizedGrainKey = \"non-alphanumeric-grain-key\";\n                }\n                return new StringBuilder().Append(prefix)\n                    .Append('-')\n                    .Append(normalizedGrainKey)\n                    .ToString()\n                    .ToLowerInvariant();\n            }\n            private static string KeepLettersAndDigits(string token)\n                => Regex.Replace(token.ToLowerInvariant(),\n                    @\"[^a-z0-9]\",\n                    string.Empty,\n                    RegexOptions.Compiled,\n                    TimeSpan.FromSeconds(10));\n        }\n    }\n\n    public PersistenceStateTests_AzureBlobStore_CustomContainerFactory(ITestOutputHelper output, Fixture fixture) : base(output, fixture, \"UnitTests.PersistentState.Grains\")\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceStateTests_AzureBlobStore_DeleteStateOnClear : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceStateTests_AzureBlobStore_DeleteStateOnClear.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddAzureBlobGrainStorage(\"GrainStorageForTest\", (AzureBlobStorageOptions options) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.DeleteStateOnClear = true;\n                });\n            }\n        }\n    }\n\n    public PersistenceStateTests_AzureBlobStore_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture) : base(output, fixture, \"UnitTests.PersistentState.Grains\")\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Persistence/PersistenceStateTests_AzureTableGrainStorage.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\n\nnamespace Tester.AzureUtils.Persistence;\n\n/// <summary>\n/// PersistenceStateTests using AzureGrainStorage - Requires access to external Azure table storage\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"AzureStorage\")]\npublic class PersistenceStateTests_AzureTableGrainStorage : Base_PersistenceGrainTests_AzureStore, IClassFixture<PersistenceStateTests_AzureTableGrainStorage.Fixture>\n{\n    public class Fixture : BaseAzureTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseTestClusterMembership = false;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureTableGrainStorage(\"GrainStorageForTest\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.DeleteStateOnClear = true;\n                    }));\n            }\n        }\n    }\n\n    public PersistenceStateTests_AzureTableGrainStorage(ITestOutputHelper output, Fixture fixture) :\n        base(output, fixture, \"UnitTests.PersistentState.Grains\")\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Program.cs",
    "content": "using Orleans.TestingHost;\n\nnamespace Tester.AzureUtils.TestSilo\n{\n    public static class Program \n    {\n        public static async Task Main(string[] args) => await StandaloneSiloHost.Main(args);\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Reminder/ReminderTests_AzureTable.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Microsoft.Extensions.Logging;\nusing UnitTests.TimerTests;\nusing Orleans.Internal;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable UnusedVariable\n\nnamespace Tester.AzureUtils.TimerTests\n{\n    /// <summary>\n    /// Tests for Azure Table Storage-based reminder service, including basic operations, failover, and multi-grain scenarios.\n    /// </summary>\n    [TestCategory(\"Reminders\"), TestCategory(\"AzureStorage\")]\n    public class ReminderTests_AzureTable : ReminderTests_Base, IClassFixture<ReminderTests_AzureTable.Fixture>\n    {\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n        }\n\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseAzureTableReminderService(options =>\n                {\n                    options.ConfigureTestDefaults();\n                });\n            }\n        }\n\n        public ReminderTests_AzureTable(Fixture fixture) : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n\n        // Basic tests\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Basic_StopByRef()\n        {\n            await Test_Reminders_Basic_StopByRef();\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9337\"), TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Basic_ListOps()\n        {\n            await Test_Reminders_Basic_ListOps();\n        }\n\n        // Single join tests ... multi grain, multi reminders\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_1J_MultiGrainMultiReminders()\n        {\n            await Test_Reminders_1J_MultiGrainMultiReminders();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_ReminderNotFound()\n        {\n            await Test_Reminders_ReminderNotFound();\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9344\"), TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Basic()\n        {\n            // start up a test grain and get the period that it's programmed to use.\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            TimeSpan period = await grain.GetReminderPeriod(DR);\n            // start up the 'DR' reminder and wait for two ticks to pass.\n            await grain.StartReminder(DR);\n            Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n            // retrieve the value of the counter-- it should match the sequence number which is the number of periods\n            // we've waited.\n            long last = await grain.GetCounter(DR);\n            Assert.Equal(2, last);\n            // stop the timer and wait for a whole period.\n            await grain.StopReminder(DR);\n            Thread.Sleep(period.Multiply(1) + LEEWAY); // giving some leeway\n            // the counter should not have changed.\n            long curr = await grain.GetCounter(DR);\n            Assert.Equal(last, curr);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9557\"), TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Basic_Restart()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            TimeSpan period = await grain.GetReminderPeriod(DR);\n            await grain.StartReminder(DR);\n            Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n            long last = await grain.GetCounter(DR);\n            Assert.Equal(2, last);\n\n            await grain.StopReminder(DR);\n            TimeSpan sleepFor = period.Multiply(1) + LEEWAY;\n            Thread.Sleep(sleepFor); // giving some leeway\n            long curr = await grain.GetCounter(DR);\n            Assert.Equal(last, curr);\n            AssertIsInRange(curr, last, last + 1, grain, DR, sleepFor);\n\n            // start the same reminder again\n            await grain.StartReminder(DR);\n            sleepFor = period.Multiply(2) + LEEWAY;\n            Thread.Sleep(sleepFor); // giving some leeway\n            curr = await grain.GetCounter(DR);\n            AssertIsInRange(curr, 2, 3, grain, DR, sleepFor);\n            await grain.StopReminder(DR); // cleanup\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_MultipleReminders()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            await PerGrainMultiReminderTest(grain);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_2J_MultiGrainMultiReminders()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g3 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g4 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g5 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task<bool>[] tasks =\n            {\n                Task.Run(() => PerGrainMultiReminderTestChurn(g1)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g2)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g3)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g4)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g5)),\n            };\n\n            await Task.Delay(period.Multiply(5));\n\n            // start two extra silos ... although it will take it a while before they stabilize\n            log.LogInformation(\"Starting 2 extra silos\");\n\n            await this.HostedCluster.StartAdditionalSilosAsync(2, true);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            //Block until all tasks complete.\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_MultiGrainMultiReminders()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g3 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g4 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g5 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            Task<bool>[] tasks =\n            {\n                Task.Run(() => PerGrainMultiReminderTest(g1)),\n                Task.Run(() => PerGrainMultiReminderTest(g2)),\n                Task.Run(() => PerGrainMultiReminderTest(g3)),\n                Task.Run(() => PerGrainMultiReminderTest(g4)),\n                Task.Run(() => PerGrainMultiReminderTest(g5)),\n            };\n\n            //Block until all tasks complete.\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_1F_Basic()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task<bool> test = Task.Run(async () => { await PerGrainFailureTest(g1); return true; });\n\n            Thread.Sleep(period.Multiply(failAfter));\n            // stop the secondary silo\n            log.LogInformation(\"Stopping secondary silo\");\n            await this.HostedCluster.StopSiloAsync(this.HostedCluster.SecondarySilos.First());\n\n            await test; // Block until test completes.\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_2F_MultiGrain()\n        {\n            List<SiloHandle> silos = await this.HostedCluster.StartAdditionalSilosAsync(2,true);\n\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g3 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g4 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g5 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task[] tasks =\n            {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerGrainFailureTest(g3)),\n                Task.Run(() => PerGrainFailureTest(g4)),\n                Task.Run(() => PerGrainFailureTest(g5)),\n            };\n\n            Thread.Sleep(period.Multiply(failAfter));\n\n            // stop a couple of silos\n            log.LogInformation(\"Stopping 2 silos\");\n            int i = Random.Shared.Next(silos.Count);\n            await this.HostedCluster.StopSiloAsync(silos[i]);\n            silos.RemoveAt(i);\n            await this.HostedCluster.StopSiloAsync(silos[Random.Shared.Next(silos.Count)]);\n\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_1F1J_MultiGrain()\n        {\n            List<SiloHandle> silos = await this.HostedCluster.StartAdditionalSilosAsync(1);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g3 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g4 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g5 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task[] tasks =\n            {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerGrainFailureTest(g3)),\n                Task.Run(() => PerGrainFailureTest(g4)),\n                Task.Run(() => PerGrainFailureTest(g5)),\n            };\n\n            Thread.Sleep(period.Multiply(failAfter));\n\n            var siloToKill = silos[Random.Shared.Next(silos.Count)];\n            // stop a silo and join a new one in parallel\n            log.LogInformation(\"Stopping a silo and joining a silo\");\n            Task t1 = Task.Factory.StartNew(async () => await this.HostedCluster.StopSiloAsync(siloToKill));\n            Task t2 = this.HostedCluster.StartAdditionalSilosAsync(1, true).ContinueWith(t =>\n            {\n                t.GetAwaiter().GetResult();\n            });\n            await Task.WhenAll(new[] { t1, t2 }).WaitAsync(ENDWAIT);\n\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n            log.LogInformation(\"\\n\\n\\nReminderTest_1F1J_MultiGrain passed OK.\\n\\n\\n\");\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_RegisterSameReminderTwice()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            Task<IGrainReminder> promise1 = grain.StartReminder(DR);\n            Task<IGrainReminder> promise2 = grain.StartReminder(DR);\n            Task<IGrainReminder>[] tasks = { promise1, promise2 };\n            await Task.WhenAll(tasks).WaitAsync(TimeSpan.FromSeconds(15));\n            //Assert.NotEqual(promise1.Result, promise2.Result);\n            // TODO: write tests where period of a reminder is changed\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/9557\"), TestCategory(\"Functional\")]\n        public async Task Rem_Azure_GT_Basic()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestCopyGrain g2 = this.GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n            TimeSpan period = await g1.GetReminderPeriod(DR); // using same period\n\n            await g1.StartReminder(DR);\n            Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n            await g2.StartReminder(DR);\n            Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n            long last1 = await g1.GetCounter(DR);\n            Assert.Equal(4, last1);\n            long last2 = await g2.GetCounter(DR);\n            Assert.Equal(2, last2); // CopyGrain fault\n\n            await g1.StopReminder(DR);\n            Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n            await g2.StopReminder(DR);\n            long curr1 = await g1.GetCounter(DR);\n            Assert.Equal(last1, curr1);\n            long curr2 = await g2.GetCounter(DR);\n            Assert.Equal(4, curr2); // CopyGrain fault\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4319\"), TestCategory(\"Functional\")]\n        public async Task Rem_Azure_GT_1F1J_MultiGrain()\n        {\n            List<SiloHandle> silos = await this.HostedCluster.StartAdditionalSilosAsync(1);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestCopyGrain g3 = this.GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n            IReminderTestCopyGrain g4 = this.GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task[] tasks =\n            {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerCopyGrainFailureTest(g3)),\n                Task.Run(() => PerCopyGrainFailureTest(g4)),\n            };\n\n            Thread.Sleep(period.Multiply(failAfter));\n\n            var siloToKill = silos[Random.Shared.Next(silos.Count)];\n            // stop a silo and join a new one in parallel\n            log.LogInformation(\"Stopping a silo and joining a silo\");\n            Task t1 = Task.Run(async () => await this.HostedCluster.StopSiloAsync(siloToKill));\n            Task t2 = Task.Run(async () => await this.HostedCluster.StartAdditionalSilosAsync(1));\n            await Task.WhenAll(new[] { t1, t2 }).WaitAsync(ENDWAIT);\n\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Wrong_LowerThanAllowedPeriod()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            await Assert.ThrowsAsync<ArgumentException>(() =>\n                grain.StartReminder(DR, TimeSpan.FromMilliseconds(3000), true));\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Rem_Azure_Wrong_Grain()\n        {\n            IReminderGrainWrong grain = this.GrainFactory.GetGrain<IReminderGrainWrong>(0);\n\n            await Assert.ThrowsAsync<InvalidOperationException>(() =>\n                grain.StartReminder(DR));\n        }\n    }\n\n}\n// ReSharper restore InconsistentNaming\n// ReSharper restore UnusedVariable\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Reminder/ReminderTests_Azure_Standalone.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Runtime.ReminderService;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.TestingHost.Utils;\nusing Orleans.Internal;\nusing Orleans.Reminders.AzureStorage;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable UnusedVariable\n\nnamespace Tester.AzureUtils.TimerTests\n{\n    /// <summary>\n    /// Standalone tests for Azure Table Storage reminder functionality, including insert rate performance and data persistence.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    [TestCategory(\"AzureStorage\")]\n    public class ReminderTests_Azure_Standalone : AzureStorageBasicTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n        private readonly string serviceId;\n        private readonly ILogger log;\n        private readonly ILoggerFactory loggerFactory;\n\n        public ReminderTests_Azure_Standalone(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            this.loggerFactory = TestingUtils.CreateDefaultLoggerFactory($\"{GetType().Name}.log\");\n            this.log = this.loggerFactory.CreateLogger<ReminderTests_Azure_Standalone>();\n\n            this.serviceId = Guid.NewGuid().ToString();\n        }\n\n        [SkippableFact, TestCategory(\"Reminders\"), TestCategory(\"Performance\")]\n        public async Task Reminders_AzureTable_InsertRate()\n        {\n            var clusterOptions = Options.Create(new ClusterOptions { ClusterId = \"TMSLocalTesting\", ServiceId = this.serviceId });\n            var storageOptions = Options.Create(new AzureTableReminderStorageOptions());\n            storageOptions.Value.ConfigureTestDefaults();\n\n            IReminderTable table = new AzureBasedReminderTable(this.loggerFactory, clusterOptions, storageOptions);\n            await table.StartAsync();\n\n            await TestTableInsertRate(table, 10);\n            await TestTableInsertRate(table, 500);\n        }\n\n        [SkippableFact, TestCategory(\"Reminders\")]\n        public async Task Reminders_AzureTable_InsertNewRowAndReadBack()\n        {\n            string clusterId = NewClusterId();\n            var clusterOptions = Options.Create(new ClusterOptions { ClusterId = clusterId, ServiceId = this.serviceId });\n            var storageOptions = Options.Create(new AzureTableReminderStorageOptions());\n            storageOptions.Value.ConfigureTestDefaults();\n            IReminderTable table = new AzureBasedReminderTable(this.loggerFactory, clusterOptions, storageOptions);\n            await table.StartAsync();\n\n            ReminderEntry[] rows = (await GetAllRows(table)).ToArray();\n            Assert.Empty(rows); // \"The reminder table (sid={0}, did={1}) was not empty.\", ServiceId, clusterId);\n\n            ReminderEntry expected = NewReminderEntry();\n            await table.UpsertRow(expected);\n            rows = (await GetAllRows(table)).ToArray();\n\n            Assert.Single(rows); // \"The reminder table (sid={0}, did={1}) did not contain the correct number of rows (1).\", ServiceId, clusterId);\n            ReminderEntry actual = rows[0];\n            Assert.Equal(expected.GrainId, actual.GrainId); // \"The newly inserted reminder table (sid={0}, did={1}) row did not contain the expected grain reference.\", ServiceId, clusterId);\n            Assert.Equal(expected.ReminderName, actual.ReminderName); // \"The newly inserted reminder table (sid={0}, did={1}) row did not have the expected reminder name.\", ServiceId, clusterId);\n            Assert.Equal(expected.Period, actual.Period); // \"The newly inserted reminder table (sid={0}, did={1}) row did not have the expected period.\", ServiceId, clusterId);\n            // the following assertion fails but i don't know why yet-- the timestamps appear identical in the error message. it's not really a priority to hunt down the reason, however, because i have high confidence it is working well enough for the moment.\n            /*Assert.Equal(expected.StartAt,  actual.StartAt); // \"The newly inserted reminder table (sid={0}, did={1}) row did not contain the correct start time.\", ServiceId, clusterId);*/\n            Assert.False(string.IsNullOrWhiteSpace(actual.ETag), $\"The newly inserted reminder table (sid={this.serviceId}, did={clusterId}) row contains an invalid etag.\");\n        }\n\n        private async Task TestTableInsertRate(IReminderTable reminderTable, double numOfInserts)\n        {\n            DateTime startedAt = DateTime.UtcNow;\n\n            try\n            {\n                List<Task<bool>> promises = new List<Task<bool>>();\n                for (int i = 0; i < numOfInserts; i++)\n                {\n                    //\"177BF46E-D06D-44C0-943B-C12F26DF5373\"\n                    string s = string.Format(\"177BF46E-D06D-44C0-943B-C12F26D{0:d5}\", i);\n\n                    var e = new ReminderEntry\n                    {\n                        //GrainId = LegacyGrainId.GetGrainId(new Guid(s)),\n                        GrainId = fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId()).GetGrainId(),\n                        ReminderName = \"MY_REMINDER_\" + i,\n                        Period = TimeSpan.FromSeconds(5),\n                        StartAt = DateTime.UtcNow\n                    };\n\n                    int capture = i;\n                    Task<bool> promise = Task.Run(async () =>\n                    {\n                        await reminderTable.UpsertRow(e);\n                        this.output.WriteLine(\"Done \" + capture);\n                        return true;\n                    });\n                    promises.Add(promise);\n                    this.log.LogInformation(\"Started {Capture}\", capture);\n                }\n                this.log.LogInformation(\"Started all, now waiting...\");\n                await Task.WhenAll(promises).WaitAsync(TimeSpan.FromSeconds(500));\n            }\n            catch (Exception exc)\n            {\n                this.log.LogInformation(exc, \"Exception caught\");\n            }\n            TimeSpan dur = DateTime.UtcNow - startedAt;\n            this.log.LogInformation(\n                \"Inserted {InsertCount} rows in {Duration}, i.e., {Rate} upserts/sec\",\n                numOfInserts,\n                dur,\n                (numOfInserts / dur.TotalSeconds).ToString(\"f2\"));\n        }\n\n        private ReminderEntry NewReminderEntry()\n        {\n            Guid guid = Guid.NewGuid();\n            return new ReminderEntry\n            {\n                GrainId = fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId()).GetGrainId(),\n                ReminderName = string.Format(\"TestReminder.{0}\", guid),\n                Period = TimeSpan.FromSeconds(5),\n                StartAt = DateTime.UtcNow\n            };\n        }\n\n        private static string NewClusterId()\n        {\n            return string.Format(\"ReminderTest.{0}\", Guid.NewGuid());\n        }\n\n        private static async Task<IEnumerable<ReminderEntry>> GetAllRows(IReminderTable table)\n        {\n            ReminderTableData data = await table.ReadRows(0, 0xffffffff);\n            return data.Reminders;\n        }\n    }\n}\n// ReSharper restore InconsistentNaming\n// ReSharper restore UnusedVariable\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/SiloInstanceTableManagerTests.cs",
    "content": "using System.Globalization;\nusing System.Net;\nusing Microsoft.Extensions.Logging;\nusing Orleans.AzureUtils;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Internal;\nusing Orleans.Clustering.AzureStorage;\n\nnamespace Tester.AzureUtils\n{\n    /// <summary>\n    /// Tests for operation of Orleans SiloInstanceManager using AzureStore - Requires access to external Azure storage\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\")]\n    public class SiloInstanceTableManagerTests : IClassFixture<SiloInstanceTableManagerTests.Fixture>, IDisposable\n    {\n        public class Fixture : IDisposable\n        {\n            public ILoggerFactory LoggerFactory { get; set; } =\n                TestingUtils.CreateDefaultLoggerFactory(\"SiloInstanceTableManagerTests.log\");\n\n            public void Dispose()\n            {\n                this.LoggerFactory.Dispose();\n            }\n        }\n\n        private readonly string clusterId;\n        private int generation;\n        private SiloAddress siloAddress;\n        private SiloInstanceTableEntry myEntry;\n        private OrleansSiloInstanceManager manager;\n        private readonly ITestOutputHelper output;\n\n        public SiloInstanceTableManagerTests(ITestOutputHelper output, Fixture fixture)\n        {\n            TestUtils.CheckForAzureStorage();\n            this.output = output;\n            this.clusterId = \"test-\" + Guid.NewGuid();\n            generation = SiloAddress.AllocateNewGeneration();\n            siloAddress = SiloAddressUtils.NewLocalSiloAddress(generation);\n\n            output.WriteLine(\"ClusterId={0} Generation={1}\", this.clusterId, generation);\n\n            output.WriteLine(\"Initializing SiloInstanceManager\");\n            manager = OrleansSiloInstanceManager.GetManager(\n                this.clusterId,\n                fixture.LoggerFactory,\n                new AzureStorageClusteringOptions { TableName = new AzureStorageClusteringOptions().TableName }.ConfigureTestDefaults())\n                .WaitAsync(SiloInstanceTableTestConstants.Timeout).Result;\n        }\n\n        // Use TestCleanup to run code after each test has run\n        public void Dispose()\n        {\n            if (manager != null && SiloInstanceTableTestConstants.DeleteEntriesAfterTest)\n            {\n                TimeSpan timeout = SiloInstanceTableTestConstants.Timeout;\n\n                output.WriteLine(\"TestCleanup Timeout={0}\", timeout);\n\n                manager.DeleteTableEntries(this.clusterId).WaitAsync(timeout).Wait();\n\n                output.WriteLine(\"TestCleanup -  Finished\");\n                manager = null;\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public void SiloInstanceTable_Op_RegisterSiloInstance()\n        {\n            RegisterSiloInstance();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Op_ActivateSiloInstance()\n        {\n            RegisterSiloInstance();\n\n            await manager.ActivateSiloInstance(myEntry);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Op_UnregisterSiloInstance()\n        {\n            RegisterSiloInstance();\n\n            await manager.UnregisterSiloInstance(myEntry);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Op_CleanDeadSiloInstance()\n        {\n            // Register a silo entry\n            await manager.TryCreateTableVersionEntryAsync();\n            this.generation = 0;\n            RegisterSiloInstance();\n            // and mark it as dead\n            await manager.UnregisterSiloInstance(myEntry);\n\n            // Create new active entries\n            for (int i = 1; i < 5; i++)\n            {\n                this.generation = i;\n                this.siloAddress = SiloAddressUtils.NewLocalSiloAddress(generation);\n                var instance = RegisterSiloInstance();\n                await manager.ActivateSiloInstance(instance);\n            }\n\n            await Task.Delay(TimeSpan.FromSeconds(3));\n\n            await manager.CleanupDefunctSiloEntries(DateTime.Now - TimeSpan.FromSeconds(1));\n\n            var entries = await manager.FindAllSiloEntries();\n            Assert.Equal(5, entries.Count);\n            Assert.All(entries, e => Assert.NotEqual(SiloInstanceTableTestConstants.INSTANCE_STATUS_DEAD, e.Item1.Status));\n        }\n\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Op_CreateSiloEntryConditionally()\n        {\n            bool didInsert = await manager.TryCreateTableVersionEntryAsync()\n                .WaitAsync(new AzureStoragePolicyOptions().OperationTimeout);\n\n            Assert.True(didInsert, \"Did insert\");\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Register_CheckData()\n        {\n            const string testName = \"SiloInstanceTable_Register_CheckData\";\n            output.WriteLine(\"Start {0}\", testName);\n\n            RegisterSiloInstance();\n\n            var data = await FindSiloEntry(siloAddress);\n            SiloInstanceTableEntry siloEntry = data.Entity;\n            string eTag = data.ETag;\n\n            Assert.NotNull(eTag); // ETag should not be null\n            Assert.NotNull(siloEntry); // SiloInstanceTableEntry should not be null\n\n            Assert.Equal(SiloInstanceTableTestConstants.INSTANCE_STATUS_CREATED, siloEntry.Status);\n\n            CheckSiloInstanceTableEntry(myEntry, siloEntry);\n            output.WriteLine(\"End {0}\", testName);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Activate_CheckData()\n        {\n            RegisterSiloInstance();\n\n            await manager.ActivateSiloInstance(myEntry);\n\n            var data = await FindSiloEntry(siloAddress);\n            Assert.NotNull(data.Entity); // Data returned should not be null\n\n            SiloInstanceTableEntry siloEntry = data.Entity;\n            string eTag = data.ETag;\n\n            Assert.NotNull(eTag); // ETag should not be null\n            Assert.NotNull(siloEntry); // SiloInstanceTableEntry should not be null\n\n            Assert.Equal(SiloInstanceTableTestConstants.INSTANCE_STATUS_ACTIVE, siloEntry.Status);\n\n            CheckSiloInstanceTableEntry(myEntry, siloEntry);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_Unregister_CheckData()\n        {\n            RegisterSiloInstance();\n\n            await manager.UnregisterSiloInstance(myEntry);\n\n            var data = await FindSiloEntry(siloAddress);\n            SiloInstanceTableEntry siloEntry = data.Entity;\n            string eTag = data.ETag;\n\n            Assert.NotNull(eTag); // ETag should not be null\n            Assert.NotNull(siloEntry); // SiloInstanceTableEntry should not be null\n\n            Assert.Equal(SiloInstanceTableTestConstants.INSTANCE_STATUS_DEAD, siloEntry.Status);\n\n            CheckSiloInstanceTableEntry(myEntry, siloEntry);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SiloInstanceTable_FindAllGatewayProxyEndpoints()\n        {\n            RegisterSiloInstance();\n\n            var gateways = await manager.FindAllGatewayProxyEndpoints();\n            Assert.Empty(gateways);  // \"Number of gateways before Silo.Activate\"\n\n            await manager.ActivateSiloInstance(myEntry);\n\n            gateways = await manager.FindAllGatewayProxyEndpoints();\n            Assert.Single(gateways);  // \"Number of gateways after Silo.Activate\"\n\n            Uri myGateway = gateways.First();\n            Assert.Equal(myEntry.Address,  myGateway.Host.ToString());  // \"Gateway address\"\n            Assert.Equal(myEntry.ProxyPort,  myGateway.Port.ToString(CultureInfo.InvariantCulture));  // \"Gateway port\"\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public void SiloAddress_ToFrom_RowKey()\n        {\n            string ipAddress = \"1.2.3.4\";\n            int port = 5555;\n            int generation = 6666;\n\n            IPAddress address = IPAddress.Parse(ipAddress);\n            IPEndPoint endpoint = new IPEndPoint(address, port);\n            SiloAddress siloAddress = SiloAddress.New(endpoint, generation);\n\n            string MembershipRowKey = SiloInstanceTableEntry.ConstructRowKey(siloAddress);\n\n            output.WriteLine(\"SiloAddress = {0} Row Key string = {1}\", siloAddress, MembershipRowKey);\n\n            SiloAddress fromRowKey = SiloInstanceTableEntry.UnpackRowKey(MembershipRowKey);\n\n            output.WriteLine(\"SiloAddress result = {0} From Row Key string = {1}\", fromRowKey, MembershipRowKey);\n\n            Assert.Equal(siloAddress,  fromRowKey);\n            Assert.Equal(SiloInstanceTableEntry.ConstructRowKey(siloAddress), SiloInstanceTableEntry.ConstructRowKey(fromRowKey));\n        }\n\n        private SiloInstanceTableEntry RegisterSiloInstance()\n        {\n            string partitionKey = this.clusterId;\n            string rowKey = SiloInstanceTableEntry.ConstructRowKey(siloAddress);\n\n            IPEndPoint myEndpoint = siloAddress.Endpoint;\n\n            myEntry = new SiloInstanceTableEntry\n            {\n                PartitionKey = partitionKey,\n                RowKey = rowKey,\n\n                DeploymentId = this.clusterId,\n                Address = myEndpoint.Address.ToString(),\n                Port = myEndpoint.Port.ToString(CultureInfo.InvariantCulture),\n                Generation = generation.ToString(CultureInfo.InvariantCulture),\n\n                HostName = myEndpoint.Address.ToString(),\n                ProxyPort = \"30000\",\n\n                RoleName = \"MyRole\",\n                SiloName = \"MyInstance\",\n                UpdateZone = \"0\",\n                FaultZone = \"0\",\n                StartTime = LogFormatter.PrintDate(DateTime.UtcNow),\n            };\n\n            output.WriteLine(\"MyEntry={0}\", myEntry);\n\n            manager.RegisterSiloInstance(myEntry);\n            return myEntry;\n        }\n\n        private async Task<(SiloInstanceTableEntry Entity, string ETag)> FindSiloEntry(SiloAddress siloAddr)\n        {\n            string partitionKey = this.clusterId;\n            string rowKey = SiloInstanceTableEntry.ConstructRowKey(siloAddr);\n\n            output.WriteLine(\"FindSiloEntry for SiloAddress={0} PartitionKey={1} RowKey={2}\", siloAddr, partitionKey, rowKey);\n\n            var data = await manager.ReadSingleTableEntryAsync(partitionKey, rowKey);\n\n            output.WriteLine(\"FindSiloEntry returning Data={0}\", data);\n            return data;\n        }\n\n        private static void CheckSiloInstanceTableEntry(SiloInstanceTableEntry referenceEntry, SiloInstanceTableEntry entry)\n        {\n            Assert.Equal(referenceEntry.DeploymentId, entry.DeploymentId);\n            Assert.Equal(referenceEntry.Address, entry.Address);\n            Assert.Equal(referenceEntry.Port, entry.Port);\n            Assert.Equal(referenceEntry.Generation,  entry.Generation);\n            Assert.Equal(referenceEntry.HostName, entry.HostName);\n            //Assert.Equal(referenceEntry.Status, entry.Status);\n            Assert.Equal(referenceEntry.ProxyPort, entry.ProxyPort);\n            Assert.Equal(referenceEntry.RoleName, entry.RoleName);\n            Assert.Equal(referenceEntry.SiloName, entry.SiloName);\n            Assert.Equal(referenceEntry.UpdateZone, entry.UpdateZone);\n            Assert.Equal(referenceEntry.FaultZone, entry.FaultZone);\n            Assert.Equal(referenceEntry.StartTime, entry.StartTime);\n            Assert.Equal(referenceEntry.IAmAliveTime, entry.IAmAliveTime);\n            Assert.Equal(referenceEntry.MembershipVersion, entry.MembershipVersion);\n\n            Assert.Equal(referenceEntry.SuspectingTimes, entry.SuspectingTimes);\n            Assert.Equal(referenceEntry.SuspectingSilos, entry.SuspectingSilos);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/StorageEmulatorUtilities.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace Tester.AzureUtils\n{\n    public static class StorageEmulatorUtilities\n    {\n        public static void EnsureEmulatorIsNotUsed()\n        {\n            if (TestDefaultConfiguration.DataConnectionString is { Length: > 0 } connectionString\n                && (connectionString.Contains(\"UseDevelopmentStorage\", StringComparison.OrdinalIgnoreCase)\n                || connectionString.Contains(\"devstoreaccount\", StringComparison.OrdinalIgnoreCase)))\n            {\n                throw new SkipException(\"This test does not support the storage emulator.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQClientStreamTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    /// <summary>\n    /// Tests for Azure Queue streaming client functionality, including producer and consumer behavior with dropped clients.\n    /// </summary>\n    public class AQClientStreamTests : TestClusterPerTest\n    {\n        private const string AQStreamProviderName = \"AzureQueueProvider\";\n        private const string StreamNamespace = \"AQSubscriptionMultiplicityTestsNamespace\";\n\n        private readonly ITestOutputHelper output;\n        private ClientStreamTestRunner runner;\n\n        public AQClientStreamTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new ClientStreamTestRunner(this.HostedCluster);\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddAzureQueueStreams(AQStreamProviderName, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                        (options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                        }))\n                    .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n            }\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureQueueStreams(AQStreamProviderName, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                        (options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                        }))\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n        }\n\n        public override async Task DisposeAsync()\n        {\n            await base.DisposeAsync();\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                var serviceId = this.HostedCluster.Client.ServiceProvider.GetRequiredService<IOptions<ClusterOptions>>().Value.ServiceId;\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance, AzureQueueStreamProviderUtils.GenerateDefaultAzureQueueNames(serviceId, AQStreamProviderName),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n                await TestAzureTableStorageStreamFailureHandler.DeleteAll();\n            }\n            catch (SkipException)\n            {\n                // Ignore\n            }\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5639\"), TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"Storage\"), TestCategory(\"Streaming\")]\n        public async Task AQStreamProducerOnDroppedClientTest()\n        {\n            logger.LogInformation(\"************************ AQStreamProducerOnDroppedClientTest *********************************\");\n            await runner.StreamProducerOnDroppedClientTest(AQStreamProviderName, StreamNamespace);\n        }\n\n        [SkippableFact(Skip = \"AzureQueue has unpredictable event delivery counts - re-enable when we figure out how to handle this.\"), TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"Storage\"), TestCategory(\"Streaming\")]\n        public async Task AQStreamConsumerOnDroppedClientTest()\n        {\n            logger.LogInformation(\"************************ AQStreamConsumerOnDroppedClientTest *********************************\");\n            await runner.StreamConsumerOnDroppedClientTest(AQStreamProviderName, StreamNamespace, output,\n                    () => TestAzureTableStorageStreamFailureHandler.GetDeliveryFailureCount(AQStreamProviderName));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQProgrammaticSubscribeTest.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    /// <summary>\n    /// Tests for programmatic subscription functionality with Azure Queue streaming providers.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"AQStreaming\")]\n    public class AQProgrammaticSubscribeTest : ProgrammaticSubscribeTestsRunner, IClassFixture<AQProgrammaticSubscribeTest.Fixture>\n    {\n        private const int queueCount = 8;\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n                builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n            }\n\n            private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddAzureQueueStreams(StreamProviderName2, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                            (options, dep) =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.QueueNames = AzureQueueUtilities.GenerateQueueNames($\"{dep.Value.ClusterId}2\", queueCount);\n                        }))\n                        .AddAzureQueueStreams(StreamProviderName, ob => ob.Configure<IOptions<ClusterOptions>>(\n                            (options, dep) =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                        }));\n                    hostBuilder\n                        .AddMemoryGrainStorageAsDefault()\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n            }\n\n            public override async Task DisposeAsync()\n            {\n                await base.DisposeAsync();\n\n                // Only perform cleanup if this suite was not skipped.\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount), new AzureQueueOptions().ConfigureTestDefaults());\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}2\", queueCount), new AzureQueueOptions().ConfigureTestDefaults());\n                }\n                catch (SkipException)\n                {\n                    // ignore\n                }\n            }\n        }\n\n        public AQProgrammaticSubscribeTest(ITestOutputHelper output, Fixture fixture)\n            : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQStreamFilteringTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests.Filtering;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    /// <summary>\n    /// Tests for stream filtering functionality with Azure Queue streaming providers.\n    /// </summary>\n    public class AQStreamFilteringTests : StreamFilteringTestsBase, IClassFixture<AQStreamFilteringTests.Fixture>, IAsyncLifetime\n    {\n        private const int queueCount = 1;\n\n        public AQStreamFilteringTests(Fixture fixture) : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                TestUtils.CheckForAzureStorage();\n                builder.AddClientBuilderConfigurator<ClientConfigurator>();\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n\n            public class SiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddAzureQueueStreams(StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME, ob => ob.Configure<IOptions<ClusterOptions>>(\n                            (options, dep) =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                            }))\n                        .AddMemoryGrainStorage(\"MemoryStore\")\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddStreamFilter<CustomStreamFilter>(StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME);\n                }\n            }\n\n            public class ClientConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder\n                        .AddAzureQueueStreams(StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME, ob => ob.Configure<IOptions<ClusterOptions>>(\n                            (options, dep) =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                            }))\n                        .AddStreamFilter<CustomStreamFilter>(StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME);\n                }\n            }\n\n            protected override void CheckPreconditionsOrThrow()\n            {\n                TestUtils.CheckForEventHub();\n            }\n        }\n\n        protected override string ProviderName => StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n\n        protected override TimeSpan WaitTime => TimeSpan.FromSeconds(2);\n\n        [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"Filters\")]\n        public async override Task IgnoreBadFilter() => await base.IgnoreBadFilter();\n\n        [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"Filters\")]\n        public async override Task OnlyEvenItems() => await base.OnlyEvenItems();\n\n        [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"Filters\")]\n        public async override Task MultipleSubscriptionsDifferentFilterData() => await base.MultipleSubscriptionsDifferentFilterData();\n\n        public Task InitializeAsync() => Task.CompletedTask;\n\n        public async Task DisposeAsync()\n        {\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.ClearAllUsedAzureQueues(\n                  NullLoggerFactory.Instance,\n                  AzureQueueUtilities.GenerateQueueNames(this.fixture.HostedCluster.Options.ClusterId, queueCount),\n                  new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException)\n            {\n                // Ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQStreamingTests.cs",
    "content": "using System.Runtime.CompilerServices;\nusing System.Runtime.ExceptionServices;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.Streaming;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"Streaming\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n    public class AQStreamingTests(AQStreamingTests.Fixture fixture) : IClassFixture<AQStreamingTests.Fixture>\n    {\n        public const string AzureQueueStreamProviderName = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        public const string SmsStreamProviderName = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n        private const int queueCount = 8;\n\n        public sealed class Fixture : IAsyncLifetime\n        {\n            private readonly ExceptionDispatchInfo _preconditionsException;\n\n            public Fixture()\n            {\n                var builder = new InProcessTestClusterBuilder();\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                }\n                catch (Exception ex)\n                {\n                    _preconditionsException = ExceptionDispatchInfo.Capture(ex);\n                    return;\n                }\n\n                builder.ConfigureHost(cb =>\n                {\n                    Dictionary<string, string> queueConfig = [];\n                    void ConfigureStreaming(string option, string value)\n                    {\n                        var prefix = $\"Orleans:Streaming:{AzureQueueStreamProviderName}:\";\n                        queueConfig[$\"{prefix}{option}\"] = value;\n                    }\n\n                    ConfigureStreaming(\"ProviderType\", \"AzureQueueStorage\");\n                    if (TestDefaultConfiguration.UseAadAuthentication)\n                    {\n                        cb.AddKeyedAzureQueueServiceClient(AzureQueueStreamProviderName, settings =>\n                        {\n                            settings.ServiceUri = TestDefaultConfiguration.DataQueueUri;\n                            settings.Credential = TestDefaultConfiguration.TokenCredential;\n                        });\n                        ConfigureStreaming(\"ServiceKey\", AzureQueueStreamProviderName);\n                    }\n                    else\n                    {\n                        ConfigureStreaming(\"ConnectionString\", TestDefaultConfiguration.DataConnectionString);\n                    }\n\n                    var names = AzureQueueUtilities.GenerateQueueNames(builder.Options.ClusterId, queueCount);\n                    for (var i = 0; i < names.Count; i++)\n                    {\n                        ConfigureStreaming($\"QueueNames:{i}\", names[i]);\n                    }\n\n                    cb.Configuration.AddInMemoryCollection(queueConfig);\n                });\n                builder.ConfigureSilo((options, siloBuilder) =>\n                {\n                    siloBuilder\n                        .AddAzureTableGrainStorage(\"AzureStore\", builder => builder.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.DeleteStateOnClear = true;\n                        }))\n                        .AddAzureTableGrainStorage(\"PubSubStore\", builder => builder.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.DeleteStateOnClear = true;\n                            }))\n                        .AddMemoryGrainStorage(\"MemoryStore\");\n                });\n                builder.ConfigureClient(clientBuilder =>\n                {\n                    clientBuilder\n                        .AddAzureQueueStreams(AzureQueueStreamProviderName, b=>\n                        b.ConfigureAzureQueue(ob=>ob.Configure<IOptions<ClusterOptions>>(\n                            (options, dep) =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                            })));\n                });\n                Cluster = builder.Build();\n            }\n\n            public InProcessTestCluster Cluster { get; }\n            public SingleStreamTestRunner Runner { get; private set; }\n\n            public async Task DisposeAsync()\n            {\n                if (Cluster is null)\n                {\n                    return;\n                }\n\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                    await AzureQueueStreamProviderUtils.ClearAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames(Cluster.Options.ClusterId, queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                }\n                catch (SkipException)\n                {\n                    // ignore\n                }\n\n                await Cluster.DisposeAsync();\n            }\n\n            public async Task InitializeAsync()\n            {\n                _preconditionsException?.Throw();\n                await Cluster.DeployAsync();\n                Runner = new SingleStreamTestRunner(Cluster.InternalClient, SingleStreamTestRunner.AQ_STREAM_PROVIDER_NAME);\n            }\n        }\n\n        ////------------------------ One to One ----------------------//\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_01_OneProducerGrainOneConsumerGrain()\n        {\n            await fixture.Runner.StreamTest_01_OneProducerGrainOneConsumerGrain();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_02_OneProducerGrainOneConsumerClient()\n        {\n            await fixture.Runner.StreamTest_02_OneProducerGrainOneConsumerClient();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_03_OneProducerClientOneConsumerGrain()\n        {\n            await fixture.Runner.StreamTest_03_OneProducerClientOneConsumerGrain();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_04_OneProducerClientOneConsumerClient()\n        {\n            await fixture.Runner.StreamTest_04_OneProducerClientOneConsumerClient();\n        }\n\n        //------------------------ MANY to Many different grains ----------------------//\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n        {\n            await fixture.Runner.StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_06_ManyDifferent_ManyProducerGrainManyConsumerClients()\n        {\n            await fixture.Runner.StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients();\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5648\"), TestCategory(\"Functional\")]\n        public async Task AQ_07_ManyDifferent_ManyProducerClientsManyConsumerGrains()\n        {\n            await fixture.Runner.StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_08_ManyDifferent_ManyProducerClientsManyConsumerClients()\n        {\n            await fixture.Runner.StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients();\n        }\n\n        //------------------------ MANY to Many Same grains ----------------------//\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_09_ManySame_ManyProducerGrainsManyConsumerGrains()\n        {\n            await fixture.Runner.StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_10_ManySame_ManyConsumerGrainsManyProducerGrains()\n        {\n            await fixture.Runner.StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_11_ManySame_ManyProducerGrainsManyConsumerClients()\n        {\n            await fixture.Runner.StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_12_ManySame_ManyProducerClientsManyConsumerGrains()\n        {\n            await fixture.Runner.StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains();\n        }\n\n        //------------------------ MANY to Many producer consumer same grain ----------------------//\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_13_SameGrain_ConsumerFirstProducerLater()\n        {\n            await fixture.Runner.StreamTest_13_SameGrain_ConsumerFirstProducerLater(false);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_14_SameGrain_ProducerFirstConsumerLater()\n        {\n            await fixture.Runner.StreamTest_14_SameGrain_ProducerFirstConsumerLater(false);\n        }\n\n        //----------------------------------------------//\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_15_ConsumeAtProducersRequest()\n        {\n            await fixture.Runner.StreamTest_15_ConsumeAtProducersRequest();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_16_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n        {\n            var multiRunner = new MultipleStreamsTestRunner(fixture.Cluster.InternalClient, SingleStreamTestRunner.AQ_STREAM_PROVIDER_NAME, 16, false);\n            await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQ_17_MultipleStreams_1J_ManyProducerGrainsManyConsumerGrains()\n        {\n            var multiRunner = new MultipleStreamsTestRunner(fixture.Cluster.InternalClient, SingleStreamTestRunner.AQ_STREAM_PROVIDER_NAME, 17, false);\n            await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(\n                fixture.Cluster.StartAdditionalSilo);\n        }\n\n        //[SkippableFact, TestCategory(\"BVT\")]\n        /*public async Task AQ_18_MultipleStreams_1J_1F_ManyProducerGrainsManyConsumerGrains()\n        {\n            var multiRunner = new MultipleStreamsTestRunner(this.InternalClient, SingleStreamTestRunner.AQ_STREAM_PROVIDER_NAME, 18, false);\n            await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(\n                this.HostedCluster.StartAdditionalSilo,\n                this.HostedCluster.StopSilo);\n        }*/\n\n        [SkippableFact]\n        public async Task AQ_19_ConsumerImplicitlySubscribedToProducerClient()\n        {\n            // todo: currently, the Azure queue queue adaptor doesn't support namespaces, so this test will fail.\n            await fixture.Runner.StreamTest_19_ConsumerImplicitlySubscribedToProducerClient();\n        }\n\n        [SkippableFact]\n        public async Task AQ_20_ConsumerImplicitlySubscribedToProducerGrain()\n        {\n            // todo: currently, the Azure queue queue adaptor doesn't support namespaces, so this test will fail.\n            await fixture.Runner.StreamTest_20_ConsumerImplicitlySubscribedToProducerGrain();\n        }\n\n        [SkippableFact(Skip = \"Ignored\"), TestCategory(\"Failures\")]\n        public async Task AQ_21_GenericConsumerImplicitlySubscribedToProducerGrain()\n        {\n            // todo: currently, the Azure queue queue adaptor doesn't support namespaces, so this test will fail.\n            await fixture.Runner.StreamTest_21_GenericConsumerImplicitlySubscribedToProducerGrain();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQStreamsBatchingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"AQStreaming\"), TestCategory(\"AzureStorage\")]\n    public class AQStreamsBatchingTests : StreamBatchingTestRunner, IClassFixture<AQStreamsBatchingTests.Fixture>\n    {\n        private const int queueCount = 8;\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n            }\n\n            private class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddAzureQueueStreams(StreamBatchingTestConst.ProviderName, b =>\n                        {\n                            b.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>(\n                                (options, dep) =>\n                                {\n                                    options.ConfigureTestDefaults();\n                                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                                }));\n                            b.ConfigurePullingAgent(ob => ob.Configure(options =>\n                            {\n                                options.BatchContainerBatchSize = 10;\n                            }));\n                            b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        });\n                }\n            }\n\n            private class ClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder\n                        .AddAzureQueueStreams(StreamBatchingTestConst.ProviderName, b =>\n                        {\n                            b.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>(\n                                (options, dep) =>\n                                {\n                                    options.ConfigureTestDefaults();\n                                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                                }));\n                            b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        });\n                }\n            }\n\n            public override async Task DisposeAsync()\n            {\n                await base.DisposeAsync();\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}2\", queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                }\n                catch (SkipException) { }\n            }\n        }\n\n        public AQStreamsBatchingTests(Fixture fixture, ITestOutputHelper output)\n            : base(fixture, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQSubscriptionMultiplicityTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Storage\"), TestCategory(\"Streaming\")]\n    public class AQSubscriptionMultiplicityTests : TestClusterPerTest\n    {\n        private const string AQStreamProviderName = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        private const string StreamNamespace = \"AQSubscriptionMultiplicityTestsNamespace\";\n        private SubscriptionMultiplicityTestRunner runner;\n        private const int queueCount = 8;\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddAzureQueueStreams(AQStreamProviderName, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                        (options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                        }));\n            }\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                     .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddAzureQueueStreams(AQStreamProviderName, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                        (options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                        }));\n            }\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new SubscriptionMultiplicityTestRunner(AQStreamProviderName, this.HostedCluster);\n        }\n\n        public override async Task DisposeAsync()\n        {\n            await base.DisposeAsync();\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(\n                    NullLoggerFactory.Instance,\n                    AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException) { }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQMultipleParallelSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ AQMultipleParallelSubscriptionTest *********************************\");\n            await runner.MultipleParallelSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQMultipleLinearSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ AQMultipleLinearSubscriptionTest *********************************\");\n            await runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQMultipleSubscriptionTest_AddRemove()\n        {\n            logger.LogInformation(\"************************ AQMultipleSubscriptionTest_AddRemove *********************************\");\n            await runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQResubscriptionTest()\n        {\n            logger.LogInformation(\"************************ AQResubscriptionTest *********************************\");\n            await runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQResubscriptionAfterDeactivationTest()\n        {\n            logger.LogInformation(\"************************ ResubscriptionAfterDeactivationTest *********************************\");\n            await runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQActiveSubscriptionTest()\n        {\n            logger.LogInformation(\"************************ AQActiveSubscriptionTest *********************************\");\n            await runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQTwoIntermitentStreamTest()\n        {\n            logger.LogInformation(\"************************ AQTwoIntermitentStreamTest *********************************\");\n            await runner.TwoIntermitentStreamTest(Guid.NewGuid());\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task AQSubscribeFromClientTest()\n        {\n            logger.LogInformation(\"************************ AQSubscribeFromClientTest *********************************\");\n            await runner.SubscribeFromClientTest(Guid.NewGuid(), StreamNamespace);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AQSubscriptionObserverWithImplicitSubscribingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests.ProgrammaticSubscribeTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"Functional\")]\n    public class AQSubscriptionObserverWithImplicitSubscribingTests : SubscriptionObserverWithImplicitSubscribingTestRunner, IClassFixture<AQSubscriptionObserverWithImplicitSubscribingTests.Fixture>\n    {\n        private const int queueCount = 8;\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n                builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n            }\n\n            public override async Task DisposeAsync()\n            {\n                await base.DisposeAsync();\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}{StreamProviderName}\", queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}{StreamProviderName2}\", queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                }\n                catch (SkipException)\n                {\n                    // ignore\n                }\n            }\n        }\n\n        private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureQueueStreams(StreamProviderName, sb=>\n                    {\n                        sb.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames($\"{dep.Value.ClusterId}{StreamProviderName}\", queueCount);\n                        }));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    })\n                    .AddAzureQueueStreams(StreamProviderName2, sb =>\n                    {\n                        sb.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames($\"{dep.Value.ClusterId}{StreamProviderName2}\", queueCount);\n                        }));\n                        sb.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    })\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n        }\n\n        public AQSubscriptionObserverWithImplicitSubscribingTests(ITestOutputHelper output, Fixture fixture)\n            : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AzureQueueAdapterTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Globalization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Serialization;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Streaming\")]\n    public class AzureQueueAdapterTests : AzureStorageBasicTests, IAsyncLifetime\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n        private const int NumBatches = 20;\n        private const int NumMessagesPerBatch = 20;\n        public static readonly string AZURE_QUEUE_STREAM_PROVIDER_NAME = \"AQAdapterTests\";\n        private readonly ILoggerFactory loggerFactory;\n        private static readonly List<string> azureQueueNames = AzureQueueUtilities.GenerateQueueNames($\"AzureQueueAdapterTests-{Guid.NewGuid()}\", 8);\n\n        public AzureQueueAdapterTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            this.loggerFactory = this.fixture.Services.GetService<ILoggerFactory>();\n        }\n\n        public Task InitializeAsync() => Task.CompletedTask;\n\n        public async Task DisposeAsync()\n        {\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(this.loggerFactory, azureQueueNames, new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException) { }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"Halo\")]\n        public async Task SendAndReceiveFromAzureQueue()\n        {\n            var options = new AzureQueueOptions\n            {\n                MessageVisibilityTimeout = TimeSpan.FromSeconds(30),\n                QueueNames = azureQueueNames\n            };\n            options.ConfigureTestDefaults();\n            var serializer = this.fixture.Services.GetService<Serializer>();\n            var queueCacheOptions = new SimpleQueueCacheOptions();\n            var queueDataAdapter = new AzureQueueDataAdapterV2(serializer);\n            var adapterFactory = new AzureQueueAdapterFactory(\n                AZURE_QUEUE_STREAM_PROVIDER_NAME,\n                options,\n                queueCacheOptions,\n                queueDataAdapter,\n                loggerFactory);\n            adapterFactory.Init();\n            await SendAndReceiveFromQueueAdapter(adapterFactory);\n        }\n\n        private async Task SendAndReceiveFromQueueAdapter(IQueueAdapterFactory adapterFactory)\n        {\n            IQueueAdapter adapter = await adapterFactory.CreateAdapter();\n            IQueueAdapterCache cache = adapterFactory.GetQueueAdapterCache();\n\n            // Create receiver per queue\n            IStreamQueueMapper mapper = adapterFactory.GetStreamQueueMapper();\n            Dictionary<QueueId, IQueueAdapterReceiver> receivers = mapper.GetAllQueues().ToDictionary(queueId => queueId, adapter.CreateReceiver);\n            Dictionary<QueueId, IQueueCache> caches = mapper.GetAllQueues().ToDictionary(queueId => queueId, cache.CreateQueueCache);\n\n            await Task.WhenAll(receivers.Values.Select(receiver => receiver.Initialize(TimeSpan.FromSeconds(5))));\n\n            // test using 2 streams\n            Guid streamId1 = Guid.NewGuid();\n            Guid streamId2 = Guid.NewGuid();\n\n            int receivedBatches = 0;\n            var streamsPerQueue = new ConcurrentDictionary<QueueId, HashSet<StreamId>>();\n\n            // reader threads (at most 2 active queues because only two streams)\n            var work = new List<Task>();\n            foreach( KeyValuePair<QueueId, IQueueAdapterReceiver> receiverKvp in receivers)\n            {\n                QueueId queueId = receiverKvp.Key;\n                var receiver = receiverKvp.Value;\n                var qCache = caches[queueId];\n                Task task = Task.Factory.StartNew(() =>\n                {\n                    while (receivedBatches < NumBatches)\n                    {\n                        var messages = receiver.GetQueueMessagesAsync(QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG).Result.ToArray();\n                        if (!messages.Any())\n                        {\n                            continue;\n                        }\n                        foreach (IBatchContainer message in messages)\n                        {\n                            streamsPerQueue.AddOrUpdate(queueId,\n                                id => new HashSet<StreamId> { message.StreamId },\n                                (id, set) =>\n                                {\n                                    set.Add(message.StreamId);\n                                    return set;\n                                });\n                            this.output.WriteLine(\"Queue {0} received message on stream {1}\", queueId,\n                                message.StreamId);\n                            Assert.Equal(NumMessagesPerBatch / 2, message.GetEvents<int>().Count());  // \"Half the events were ints\"\n                            Assert.Equal(NumMessagesPerBatch / 2, message.GetEvents<string>().Count());  // \"Half the events were strings\"\n                        }\n                        Interlocked.Add(ref receivedBatches, messages.Length);\n                        qCache.AddToCache(messages);\n                    }\n                });\n                work.Add(task);\n            }\n\n            // send events\n            List<object> events = CreateEvents(NumMessagesPerBatch);\n            work.Add(Task.Factory.StartNew(() => Enumerable.Range(0, NumBatches)\n                .Select(i => i % 2 == 0 ? streamId1 : streamId2)\n                .ToList()\n                .ForEach(streamId =>\n                    adapter.QueueMessageBatchAsync(StreamId.Create(streamId.ToString(), streamId),\n                        events.Take(NumMessagesPerBatch).ToArray(), null, RequestContextExtensions.Export(this.fixture.DeepCopier)).Wait())));\n            await Task.WhenAll(work);\n\n            // Make sure we got back everything we sent\n            Assert.Equal(NumBatches, receivedBatches);\n\n            // check to see if all the events are in the cache and we can enumerate through them\n            StreamSequenceToken firstInCache = new EventSequenceTokenV2(0);\n            foreach (KeyValuePair<QueueId, HashSet<StreamId>> kvp in streamsPerQueue)\n            {\n                var receiver = receivers[kvp.Key];\n                var qCache = caches[kvp.Key];\n\n                foreach (StreamId streamGuid in kvp.Value)\n                {\n                    // read all messages in cache for stream\n                    IQueueCacheCursor cursor = qCache.GetCacheCursor(streamGuid, firstInCache);\n                    int messageCount = 0;\n                    StreamSequenceToken tenthInCache = null;\n                    StreamSequenceToken lastToken = firstInCache;\n                    while (cursor.MoveNext())\n                    {\n                        Exception ex;\n                        messageCount++;\n                        IBatchContainer batch = cursor.GetCurrent(out ex);\n                        this.output.WriteLine(\"Token: {0}\", batch.SequenceToken);\n                        Assert.True(batch.SequenceToken.CompareTo(lastToken) >= 0, $\"order check for event {messageCount}\");\n                        lastToken = batch.SequenceToken;\n                        if (messageCount == 10)\n                        {\n                            tenthInCache = batch.SequenceToken;\n                        }\n                    }\n                    this.output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount, streamGuid);\n                    Assert.Equal(NumBatches / 2, messageCount);\n                    Assert.NotNull(tenthInCache);\n\n                    // read all messages from the 10th\n                    cursor = qCache.GetCacheCursor(streamGuid, tenthInCache);\n                    messageCount = 0;\n                    while (cursor.MoveNext())\n                    {\n                        messageCount++;\n                    }\n                    this.output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount, streamGuid);\n                    const int expected = NumBatches / 2 - 10 + 1; // all except the first 10, including the 10th (10 + 1)\n                    Assert.Equal(expected, messageCount);\n                }\n            }\n        }\n\n        private List<object> CreateEvents(int count)\n        {\n            return Enumerable.Range(0, count).Select(i =>\n            {\n                if (i % 2 == 0)\n                {\n                    return Random.Shared.Next(int.MaxValue) as object;\n                }\n                return Random.Shared.Next(int.MaxValue).ToString(CultureInfo.InvariantCulture);\n            }).ToList();\n        }\n\n        internal static string MakeClusterId()\n        {\n            const string DeploymentIdFormat = \"cluster-{0}\";\n            string now = DateTime.UtcNow.ToString(\"yyyy-MM-dd-hh-mm-ss-ffff\");\n            return string.Format(DeploymentIdFormat, now);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/AzureQueueStreamProviderBuilderTests.cs",
    "content": "﻿using System.Text;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Xunit;\n\nnamespace Tester.AzureUtils;\n\n/// <summary>\n/// Tests for Azure Queue Stream Provider configuration builder, validating various configuration scenarios.\n/// </summary>\npublic class AzureQueueStreamProviderBuilderTests\n{\n\t/// <summary>\n\t/// Verifies that missing connection string results in null QueueServiceClient.\n\t/// </summary>\n\t[Fact]\n\tpublic void Missing_ConnectionString()\n\t{\n\t\tstring json = \"\"\"\n\t\t{\n\t\t\t\"Orleans\": {\n\t\t\t\t\"Streaming\": {\n\t\t\t\t\t\"AzureQueueProvider\": {\n\t\t\t\t\t\t\"ProviderType\": \"AzureQueueStorage\",\n\t\t\t\t\t\t\"QueueNames\": [\n\t\t\t\t\t\t\t\"q1\"\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\"\"\";\n\n\t\tvar queueOptions = ConfigureSilo(json).Services.BuildServiceProvider().GetOptionsByName<AzureQueueOptions>(null);\n\n\t\tAssert.Null(queueOptions.QueueServiceClient);\n\t}\n\n\t/// <summary>\n\t/// Verifies that minimal required configuration creates valid QueueServiceClient with default settings.\n\t/// </summary>\n\t[Fact]\n\tpublic void Minimal_Configuration()\n\t{\n\t\tstring json = \"\"\"\n\t\t{\n\t\t\t\"Orleans\": {\n\t\t\t\t\"Streaming\": {\n\t\t\t\t\t\"AzureQueueProvider\": {\n\t\t\t\t\t\t\"ProviderType\": \"AzureQueueStorage\",\n\t\t\t\t\t\t\"ConnectionString\": \"UseDevelopmentStorage=true\",\n\t\t\t\t\t\t\"QueueNames\": [\n\t\t\t\t\t\t\t\"q1\"\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\"\"\";\n\n\t\tvar queueOptions = ConfigureSilo(json).Services.BuildServiceProvider().GetOptionsByName<AzureQueueOptions>(null);\n\n\t\tAssert.NotNull(queueOptions.QueueServiceClient);\n\t\tAssert.Equal(\"devstoreaccount1\", queueOptions.QueueServiceClient.AccountName);\n\t\tAssert.Equal([\"q1\"], queueOptions.QueueNames);\n\t\tAssert.Null(queueOptions.MessageVisibilityTimeout);\n\t}\n\n\t/// <summary>\n\t/// Verifies that all configuration options are properly parsed and applied.\n\t/// </summary>\n\t[Fact]\n\tpublic void Full_Configuration()\n\t{\n\t\tstring json = \"\"\"\n\t\t{\n\t\t\t\"Orleans\": {\n\t\t\t\t\"Streaming\": {\n\t\t\t\t\t\"AzureQueueProvider\": {\n\t\t\t\t\t\t\"ProviderType\": \"AzureQueueStorage\",\n\t\t\t\t\t\t\"ConnectionString\": \"UseDevelopmentStorage=true\",\n\t\t\t\t\t\t\"MessageVisibilityTimeout\": \"00:00:37\",\n\t\t\t\t\t\t\"QueueNames\": [\n\t\t\t\t\t\t\t\"q1\",\n\t\t\t\t\t\t\t\"q2\"\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\"\"\";\n\n\t\tvar queueOptions = ConfigureSilo(json).Services.BuildServiceProvider().GetOptionsByName<AzureQueueOptions>(null);\n\n\t\tAssert.NotNull(queueOptions.QueueServiceClient);\n\t\tAssert.Equal(\"devstoreaccount1\", queueOptions.QueueServiceClient.AccountName);\n\t\tAssert.Equal([\"q1\", \"q2\"], queueOptions.QueueNames);\n\t\tAssert.Equal(TimeSpan.FromSeconds(37), queueOptions.MessageVisibilityTimeout);\n\t}\n\n\tstatic TestSiloBuilder ConfigureSilo(string json)\n\t{\n\t\tvar siloBuilder = new TestSiloBuilder(json);\n\t\tvar aqsBuilder = new AzureQueueStreamProviderBuilder();\n\t\taqsBuilder.Configure(siloBuilder, null, siloBuilder.Configuration.GetSection(\"Orleans:Streaming:AzureQueueProvider\"));\n\t\treturn siloBuilder;\n\t}\n\n\tclass TestSiloBuilder(string json) : ISiloBuilder\n\t{\n\t\tpublic IServiceCollection Services { get; } = new ServiceCollection();\n\n\t\tpublic IConfiguration Configuration { get; } = GetConfig(json);\n\t}\n\n\tstatic IConfigurationRoot GetConfig(string json) => new ConfigurationBuilder().AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(json))).Build();\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/DelayedQueueRebalancingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"Streaming\")]\n    public class DelayedQueueRebalancingTests : TestClusterPerTest\n    {\n        private const string adapterName = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n#pragma warning disable 618\n        private readonly string adapterType = typeof(PersistentStreamProvider).FullName;\n#pragma warning restore 618\n        private static readonly TimeSpan SILO_IMMATURE_PERIOD = TimeSpan.FromSeconds(40); // matches the config\n        private static readonly TimeSpan LEEWAY = TimeSpan.FromSeconds(10);\n        private const int queueCount = 8;\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n\n            // Define a cluster of 4, but 2 will be stopped.\n            builder.CreateSiloAsync = StandaloneSiloHandle.CreateForAssembly(this.GetType().Assembly);\n            builder.Options.InitialSilosCount = 2;\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n        }\n\n        private class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<StaticGatewayListProviderOptions>(options => options.Gateways = options.Gateways.Take(1).ToList());\n            }\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureQueueStreams(adapterName, b =>\n                    {\n                        b.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                        }));\n                        b.UseDynamicClusterConfigDeploymentBalancer(SILO_IMMATURE_PERIOD);\n                    })\n                    .Configure<StaticClusterDeploymentOptions>(op =>\n                    {\n                        op.SiloNames = new List<string>() {\"Primary\", \"Secondary_1\", \"Secondary_2\", \"Secondary_3\"};\n                    });\n                hostBuilder.AddMemoryGrainStorage(\"PubSubStore\");\n            }\n        }\n\n        public override async Task DisposeAsync()\n        {\n            await base.DisposeAsync();\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                    AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException) { }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task DelayedQueueRebalancingTests_1()\n        {\n            await ValidateAgentsState(2, 2, \"1\");\n\n            await Task.Delay(SILO_IMMATURE_PERIOD + LEEWAY);\n\n            await ValidateAgentsState(2, 4, \"2\");\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task DelayedQueueRebalancingTests_2()\n        {\n            await ValidateAgentsState(2, 2, \"1\");\n\n            await this.HostedCluster.StartAdditionalSilosAsync(2, true);\n            await ValidateAgentsState(4, 2, \"2\");\n\n            await Task.Delay(SILO_IMMATURE_PERIOD + LEEWAY);\n\n            await ValidateAgentsState(4, 2, \"3\");\n        }\n\n        private async Task ValidateAgentsState(int numExpectedSilos, int numExpectedAgentsPerSilo, string callContext)\n        {\n            var mgmt = this.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            object[] results = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.GetNumberRunningAgents, null);\n            Assert.Equal(numExpectedSilos, results.Length);\n\n            // Convert.ToInt32 is used because of different behavior of the fallback serializers: binary formatter and Json.Net.\n            // The binary one deserializes object[] into array of ints when the latter one - into longs. http://stackoverflow.com/a/17918824\n            var numAgents = results.Select(Convert.ToInt32).ToArray();\n            logger.LogInformation(\"Got back RunningAgentCounts: {RunningAgentCounts}\", Utils.EnumerableToString(numAgents));\n            int i = 0;\n            foreach (var agents in numAgents)\n            {\n                logger.LogCritical($\"Silo {i++} get agents {agents}\");\n                Assert.Equal(numExpectedAgentsPerSilo, agents);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/HaloStreamSubscribeTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing Tester;\nusing Tester.AzureUtils;\nusing Tester.AzureUtils.Streaming;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace UnitTests.HaloTests.Streaming\n{\n    [TestCategory(\"Streaming\"), TestCategory(\"Halo\")]\n    public class HaloStreamSubscribeTests : OrleansTestingBase, IClassFixture<HaloStreamSubscribeTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private const int queueCount = 8;\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            public const string AzureQueueStreamProviderName = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n            public const string SmsStreamProviderName = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            }\n\n            private class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"MemoryStore\", options => options.NumStorageGrains = 1)\n                        .AddAzureTableGrainStorage(\"AzureStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.DeleteStateOnClear = true;\n                        }))\n                        .AddAzureTableGrainStorage(\"PubSubStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                        {\n                            options.DeleteStateOnClear = true;\n                            options.ConfigureTestDefaults();\n                        }))\n                        .AddAzureQueueStreams(AzureQueueStreamProviderName, b=>b\n                        .ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>(\n                                (options, dep) =>\n                                {\n                                    options.ConfigureTestDefaults();\n                                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                            })));\n                    hostBuilder\n                        .AddAzureQueueStreams(\"AzureQueueProvider2\", b=>b\n                        .ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>(\n                                (options, dep) =>\n                                {\n                                    options.ConfigureTestDefaults();\n                                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames($\"{dep.Value.ClusterId}2\", queueCount);\n                            })));\n                }\n            }\n\n            public override async Task DisposeAsync()\n            {\n                await base.DisposeAsync();\n                try\n                {\n                    TestUtils.CheckForAzureStorage();\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                    await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                        AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}2\", queueCount),\n                        new AzureQueueOptions().ConfigureTestDefaults());\n                }\n                catch (SkipException) { }\n            }\n        }\n\n        protected TestCluster HostedCluster { get; }\n\n        private const string SmsStreamProviderName = Fixture.SmsStreamProviderName;\n        private const string AzureQueueStreamProviderName = Fixture.AzureQueueStreamProviderName;\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10);\n\n        private Guid _streamId;\n        private string _streamProvider;\n        private readonly ILoggerFactory loggerFactory;\n        public HaloStreamSubscribeTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            HostedCluster = fixture.HostedCluster;\n            fixture.EnsurePreconditionsMet();\n            this.loggerFactory = fixture.HostedCluster.ServiceProvider.GetService<ILoggerFactory>();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Halo_AzureQueue_ResubscribeTest_ConsumerProducer()\n        {\n            this.fixture.Logger.LogInformation(\"\\n\\n************************ Halo_AzureQueue_ResubscribeTest_ConsumerProducer ********************************* \\n\\n\");\n            _streamId = Guid.NewGuid();\n            _streamProvider = AzureQueueStreamProviderName;\n            Guid consumerGuid = Guid.NewGuid();\n            Guid producerGuid = Guid.NewGuid();\n            await ConsumerProducerTest(consumerGuid, producerGuid);\n            await ConsumerProducerTest(consumerGuid, producerGuid);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Halo_AzureQueue_ResubscribeTest_ProducerConsumer()\n        {\n            this.fixture.Logger.LogInformation(\"\\n\\n************************ Halo_AzureQueue_ResubscribeTest_ProducerConsumer ********************************* \\n\\n\");\n            _streamId = Guid.NewGuid();\n            _streamProvider = AzureQueueStreamProviderName;\n            Guid producerGuid = Guid.NewGuid();\n            Guid consumerGuid = Guid.NewGuid();\n            await ProducerConsumerTest(producerGuid, consumerGuid);\n            await ProducerConsumerTest(producerGuid, consumerGuid);\n        }\n\n        private async Task ConsumerProducerTest(Guid consumerGuid, Guid producerGuid)\n        {\n            // consumer joins first, producer later\n            IConsumerEventCountingGrain consumer = this.fixture.GrainFactory.GetGrain<IConsumerEventCountingGrain>(consumerGuid);\n            await consumer.BecomeConsumer(_streamId, _streamProvider);\n\n            IProducerEventCountingGrain producer = this.fixture.GrainFactory.GetGrain<IProducerEventCountingGrain>(producerGuid);\n            await producer.BecomeProducer(_streamId, _streamProvider);\n\n            await producer.SendEvent();\n\n            await Task.Delay(1000);\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer), Timeout);\n\n            await consumer.StopConsuming();\n        }\n\n        private async Task ProducerConsumerTest(Guid producerGuid, Guid consumerGuid)\n        {\n            // producer joins first, consumer later\n            IProducerEventCountingGrain producer = this.fixture.GrainFactory.GetGrain<IProducerEventCountingGrain>(producerGuid);\n            await producer.BecomeProducer(_streamId, _streamProvider);\n\n            IConsumerEventCountingGrain consumer = this.fixture.GrainFactory.GetGrain<IConsumerEventCountingGrain>(consumerGuid);\n            await consumer.BecomeConsumer(_streamId, _streamProvider);\n\n            await producer.SendEvent();\n\n            await Task.Delay(1000);\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer), Timeout);\n\n            await consumer.StopConsuming();\n        }\n\n        private async Task<bool> CheckCounters(IProducerEventCountingGrain producer, IConsumerEventCountingGrain consumer)\n        {\n            var numProduced = await producer.GetNumberProduced();\n            var numConsumed = await consumer.GetNumberConsumed();\n            this.fixture.Logger.LogInformation(\"CheckCounters: numProduced = {ProducedCount}, numConsumed = {ConsumedCount}\", numProduced, numConsumed);\n            return numProduced == numConsumed;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/PullingAgentManagementTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Tester;\nusing Tester.AzureUtils;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    public class PullingAgentManagementTests : OrleansTestingBase, IClassFixture<PullingAgentManagementTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                    .AddAzureQueueStreams(StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME, b=>\n                        b.ConfigureAzureQueue(ob => ob.Configure<IOptions<ClusterOptions>>((options, dep) =>\n                           {\n                               options.ConfigureTestDefaults();\n                               options.QueueNames = Enumerable.Range(0, 8).Select(num => $\"{dep.Value.ClusterId}-{num}\").ToList();\n                           })));\n\n                    hostBuilder.AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n            protected override void CheckPreconditionsOrThrow()\n            {\n                base.CheckPreconditionsOrThrow();\n                TestUtils.CheckForAzureStorage();\n            }\n        }\n\n        private const string adapterName = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n#pragma warning disable 618\n        private readonly string adapterType = typeof(PersistentStreamProvider).FullName;\n#pragma warning restore 618\n\n        public PullingAgentManagementTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            this.fixture.EnsurePreconditionsMet();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task PullingAgents_ControlCmd_1()\n        {\n            var mgmt = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);;\n\n            await ValidateAgentsState(StreamLifecycleOptions.RunState.AgentsStarted);\n\n            await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.StartAgents);\n            await ValidateAgentsState(StreamLifecycleOptions.RunState.AgentsStarted);\n\n            await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.StopAgents);\n            await ValidateAgentsState(StreamLifecycleOptions.RunState.AgentsStopped);\n\n\n            await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.StartAgents);\n            await ValidateAgentsState(StreamLifecycleOptions.RunState.AgentsStarted);\n\n        }\n\n        private async Task ValidateAgentsState(StreamLifecycleOptions.RunState expectedState)\n        {\n            var mgmt = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            var states = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.GetAgentsState);\n            Assert.Equal(2, states.Length);\n            foreach (var state in states)\n            {\n                StreamLifecycleOptions.RunState providerState;\n                Enum.TryParse(state.ToString(), out providerState);\n                Assert.Equal(expectedState, providerState);\n            }\n\n            var numAgents = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(adapterName, (int)PersistentStreamProviderCommand.GetNumberRunningAgents);\n            Assert.Equal(2, numAgents.Length);\n            int totalNumAgents = numAgents.Select(Convert.ToInt32).Sum();\n            if (expectedState == StreamLifecycleOptions.RunState.AgentsStarted)\n            {\n                Assert.Equal(HashRingStreamQueueMapperOptions.DEFAULT_NUM_QUEUES, totalNumAgents);\n            }\n            else\n            {\n                Assert.Equal(0, totalNumAgents);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/SampleAzureQueueStreamingTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    [TestCategory(\"Streaming\")]\n    public class SampleAzureQueueStreamingTests : TestClusterPerTest\n    {\n        private const string StreamProvider = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        private const int queueCount = 8;\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureQueueStreams(StreamProvider, ob=>ob.Configure<IOptions<ClusterOptions>>(\n                        (options, dep) =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, queueCount);\n                        }))\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n        }\n\n        public override async Task DisposeAsync()\n        {\n            await base.DisposeAsync();\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                    AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, queueCount),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException) { }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SampleStreamingTests_4()\n        {\n            logger.LogInformation(\"************************ SampleStreamingTests_4 *********************************\");\n            var runner = new SampleStreamingTests(StreamProvider, this.logger, this.HostedCluster);\n            await runner.StreamingTests_Consumer_Producer(Guid.NewGuid());\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SampleStreamingTests_5()\n        {\n            logger.LogInformation(\"************************ SampleStreamingTests_5 *********************************\");\n            var runner = new SampleStreamingTests(StreamProvider, this.logger, this.HostedCluster);\n            await runner.StreamingTests_Producer_Consumer(Guid.NewGuid());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/StreamReliabilityTests.cs",
    "content": "//#define USE_GENERICS\n//#define DELETE_AFTER_TEST\n\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.AzureQueue;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Tester;\nusing Tester.AzureUtils.Streaming;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Tester.AzureUtils;\nusing Orleans.Serialization.TypeSystem;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers;\n\n// ReSharper disable ConvertToConstant.Local\n// ReSharper disable CheckNamespace\n\nnamespace UnitTests.Streaming.Reliability\n{\n    [TestCategory(\"Streaming\"), TestCategory(\"Reliability\")]\n    public class StreamReliabilityTests : TestClusterPerTest\n    {\n        private readonly ITestOutputHelper _output;\n        public const string SMS_STREAM_PROVIDER_NAME = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n        public const string AZURE_QUEUE_STREAM_PROVIDER_NAME = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        private const int QueueCount = 8;\n        private Guid _streamId;\n        private string _streamProviderName;\n        private int _numExpectedSilos;\n#if DELETE_AFTER_TEST\n        private HashSet<IStreamReliabilityTestGrain> _usedGrains;\n#endif\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForAzureStorage();\n\n            this._numExpectedSilos = 2;\n            builder.CreateSiloAsync = StandaloneSiloHandle.CreateForAssembly(this.GetType().Assembly);\n            builder.Options.InitialSilosCount = (short) this._numExpectedSilos;\n            builder.Options.UseTestClusterMembership = false;\n\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.UseAzureStorageClustering(gatewayOptions =>\n                {\n                    gatewayOptions.ConfigureTestDefaults();\n                })\n                .AddAzureQueueStreams(AZURE_QUEUE_STREAM_PROVIDER_NAME, ob => ob.Configure<IOptions<ClusterOptions>>(\n                    (options, dep) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, QueueCount);\n                    }))\n                .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(SMS_STREAM_PROVIDER_NAME)\n                .Configure<GatewayOptions>(options => options.GatewayListRefreshPeriod = TimeSpan.FromSeconds(5));\n            }\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseAzureStorageClustering(options =>\n                {\n                    options.ConfigureTestDefaults();\n                })\n                .AddAzureTableGrainStorage(\"AzureStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.DeleteStateOnClear = true;\n                    }))\n                .AddMemoryGrainStorage(\"MemoryStore\", options => options.NumStorageGrains = 1)\n                .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(SMS_STREAM_PROVIDER_NAME)\n                .AddAzureTableGrainStorage(\"PubSubStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                {\n                    options.DeleteStateOnClear = true;\n                    options.ConfigureTestDefaults();\n                }))\n                .AddAzureQueueStreams(AZURE_QUEUE_STREAM_PROVIDER_NAME, ob => ob.Configure<IOptions<ClusterOptions>>(\n                (options, dep) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames(dep.Value.ClusterId, QueueCount);\n                }))\n                .AddAzureQueueStreams(\"AzureQueueProvider2\", ob => ob.Configure<IOptions<ClusterOptions>>(\n                (options, dep) =>\n                {\n                    options.ConfigureTestDefaults();\n                    options.QueueNames = AzureQueueUtilities.GenerateQueueNames($\"{dep.Value.ClusterId}2\", QueueCount);\n                }));\n            }\n        }\n\n        public StreamReliabilityTests(ITestOutputHelper output)\n        {\n            this._output = output;\n#if DELETE_AFTER_TEST\n            _usedGrains = new HashSet<IStreamReliabilityTestGrain>();\n#endif\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            CheckSilosRunning(\"Initially\", _numExpectedSilos);\n        }\n\n        public override async Task DisposeAsync()\n        {\n#if DELETE_AFTER_TEST\n            List<Task> promises = new List<Task>();\n            foreach (var g in _usedGrains)\n            {\n                promises.Add(g.ClearGrain());\n            }\n\n            await Task.WhenAll(promises);\n#endif\n            await base.DisposeAsync();\n\n            try\n            {\n                TestUtils.CheckForAzureStorage();\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                    AzureQueueUtilities.GenerateQueueNames(this.HostedCluster.Options.ClusterId, QueueCount),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n                await AzureQueueStreamProviderUtils.DeleteAllUsedAzureQueues(NullLoggerFactory.Instance,\n                    AzureQueueUtilities.GenerateQueueNames($\"{this.HostedCluster.Options.ClusterId}2\", QueueCount),\n                    new AzureQueueOptions().ConfigureTestDefaults());\n            }\n            catch (SkipException) { }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public void Baseline_StreamRel()\n        {\n            // This test case is just a sanity-check that the silo test config is OK.\n            const string testName = \"Baseline_StreamRel\";\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Baseline_StreamRel_RestartSilos()\n        {\n            // This test case is just a sanity-check that the silo test config is OK.\n            const string testName = \"Baseline_StreamRel_RestartSilos\";\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            CheckSilosRunning(\"Before Restart\", _numExpectedSilos);\n            var silos = this.HostedCluster.Silos;\n            await RestartAllSilos();\n\n            CheckSilosRunning(\"After Restart\", _numExpectedSilos);\n\n            Assert.NotEqual(silos, this.HostedCluster.Silos); // Should be different silos after restart\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_Baseline_StreamRel()\n        {\n            // This test case is just a sanity-check that the SMS test config is OK.\n            const string testName = \"SMS_Baseline_StreamRel\";\n            _streamId = Guid.NewGuid();\n            _streamProviderName = SMS_STREAM_PROVIDER_NAME;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            // Grain Producer -> Grain Consumer\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\")]\n        public async Task AQ_Baseline_StreamRel()\n        {\n            // This test case is just a sanity-check that the AzureQueue test config is OK.\n            const string testName = \"AQ_Baseline_StreamRel\";\n            _streamId = Guid.NewGuid();\n            _streamProviderName = AZURE_QUEUE_STREAM_PROVIDER_NAME;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        [SkippableFact(Skip =\"Ignore\"), TestCategory(\"Failures\"), TestCategory(\"Streaming\"), TestCategory(\"Reliability\")]\n        public async Task SMS_AddMany_Consumers()\n        {\n            const string testName = \"SMS_AddMany_Consumers\";\n            await Test_AddMany_Consumers(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact(Skip = \"Ignore\"), TestCategory(\"Failures\"), TestCategory(\"Streaming\"), TestCategory(\"Reliability\"), TestCategory(\"AzureStorage\")]\n        public async Task AQ_AddMany_Consumers()\n        {\n            const string testName = \"AQ_AddMany_Consumers\";\n            await Test_AddMany_Consumers(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_PubSub_MultiConsumerSameGrain()\n        {\n            const string testName = \"SMS_PubSub_MultiConsumerSameGrain\";\n            await Test_PubSub_MultiConsumerSameGrain(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        // AQ_PubSub_MultiConsumerSameGrain not required - does not use PubSub\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_PubSub_MultiProducerSameGrain()\n        {\n            const string testName = \"SMS_PubSub_MultiProducerSameGrain\";\n            await Test_PubSub_MultiProducerSameGrain(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        // AQ_PubSub_MultiProducerSameGrain not required - does not use PubSub\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_PubSub_Unsubscribe()\n        {\n            const string testName = \"SMS_PubSub_Unsubscribe\";\n            await Test_PubSub_Unsubscribe(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        // AQ_PubSub_Unsubscribe not required - does not use PubSub\n\n        //TODO: This test fails because the resubscribe to streams after restart creates a new subscription, losing the events on the previous subscription.  Should be fixed when 'renew' subscription feature is added. - jbragg\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"Failures\")]\n        public async Task SMS_StreamRel_AllSilosRestart_PubSubCounts()\n        {\n            const string testName = \"SMS_StreamRel_AllSilosRestart_PubSubCounts\";\n            await Test_AllSilosRestart_PubSubCounts(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        // AQ_StreamRel_AllSilosRestart_PubSubCounts not required - does not use PubSub\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_StreamRel_AllSilosRestart()\n        {\n            const string testName = \"SMS_StreamRel_AllSilosRestart\";\n\n            await Test_AllSilosRestart(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_AllSilosRestart()\n        {\n            const string testName = \"AQ_StreamRel_AllSilosRestart\";\n\n            await Test_AllSilosRestart(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_SiloJoins()\n        {\n            const string testName = \"AQ_StreamRel_SiloJoins\";\n\n            await Test_SiloJoins(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_StreamRel_SiloDies_Consumer()\n        {\n            const string testName = \"SMS_StreamRel_SiloDies_Consumer\";\n            await Test_SiloDies_Consumer(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_SiloDies_Consumer()\n        {\n            const string testName = \"AQ_StreamRel_SiloDies_Consumer\";\n            await Test_SiloDies_Consumer(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_StreamRel_SiloDies_Producer()\n        {\n            const string testName = \"SMS_StreamRel_SiloDies_Producer\";\n            await Test_SiloDies_Producer(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_SiloDies_Producer()\n        {\n            const string testName = \"AQ_StreamRel_SiloDies_Producer\";\n            await Test_SiloDies_Producer(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_StreamRel_SiloRestarts_Consumer()\n        {\n            const string testName = \"SMS_StreamRel_SiloRestarts_Consumer\";\n            await Test_SiloRestarts_Consumer(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_SiloRestarts_Consumer()\n        {\n            const string testName = \"AQ_StreamRel_SiloRestarts_Consumer\";\n            await Test_SiloRestarts_Consumer(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_StreamRel_SiloRestarts_Producer()\n        {\n            const string testName = \"SMS_StreamRel_SiloRestarts_Producer\";\n            await Test_SiloRestarts_Producer(testName, SMS_STREAM_PROVIDER_NAME);\n        }\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"AzureStorage\"), TestCategory(\"AzureQueue\")]\n        public async Task AQ_StreamRel_SiloRestarts_Producer()\n        {\n            const string testName = \"AQ_StreamRel_SiloRestarts_Producer\";\n            await Test_SiloRestarts_Producer(testName, AZURE_QUEUE_STREAM_PROVIDER_NAME);\n        }\n\n        // -------------------\n        // Test helper methods\n\n#if USE_GENERICS\n        private async Task<IStreamReliabilityTestGrain<int>> Do_BaselineTest(long consumerGrainId, long producerGrainId)\n#else\n        private async Task<IStreamReliabilityTestGrain> Do_BaselineTest(long consumerGrainId, long producerGrainId)\n#endif\n        {\n            logger.LogInformation(\"Initializing: ConsumerGrain={ConsumerGrainId} ProducerGrain={ProducerGrainId}\", consumerGrainId, producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n            var producerGrain = GetGrain(producerGrainId);\n#if DELETE_AFTER_TEST\n            _usedGrains.Add(producerGrain);\n            _usedGrains.Add(producerGrain);\n#endif\n\n            await producerGrain.Ping();\n\n            string when = \"Before subscribe\";\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, false, false);\n\n            logger.LogInformation(\"AddConsumer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            logger.LogInformation(\"BecomeProducer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n\n            when = \"After subscribe\";\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            when = \"Ping\";\n            await producerGrain.Ping();\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            when = \"SendItem\";\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            return producerGrain;\n        }\n\n#if USE_GENERICS\n        private async Task<IStreamReliabilityTestGrain<int>[]> Do_AddConsumerGrains(long baseId, int numGrains)\n#else\n        private async Task<IStreamReliabilityTestGrain[]> Do_AddConsumerGrains(long baseId, int numGrains)\n#endif\n        {\n            logger.LogInformation(\"Initializing: BaseId={BaseId} NumGrains={NumGrains}\", baseId, numGrains);\n\n#if USE_GENERICS\n            var grains = new IStreamReliabilityTestGrain<int>[numGrains];\n#else\n            var grains = new IStreamReliabilityTestGrain[numGrains];\n#endif\n            List<Task> promises = new List<Task>(numGrains);\n            for (int i = 0; i < numGrains; i++)\n            {\n                grains[i] = GetGrain(i + baseId);\n\n                promises.Add(grains[i].Ping());\n#if DELETE_AFTER_TEST\n                _usedGrains.Add(grains[i]);\n#endif\n            }\n            await Task.WhenAll(promises);\n\n            logger.LogInformation(\"AddConsumer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await Task.WhenAll(grains.Select(g => g.AddConsumer(_streamId, _streamProviderName)));\n\n            return grains;\n        }\n\n        private static int _baseConsumerId = 0;\n\n        private async Task Test_AddMany_Consumers(string testName, string streamProviderName)\n        {\n            const int numLoops = 100;\n            const int numGrains = 10;\n\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = GetGrain(producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n#if DELETE_AFTER_TEST\n            _usedGrains.Add(producerGrain);\n            _usedGrains.Add(consumerGrain);\n#endif\n\n            // Note: This does first SendItem\n            await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            int baseId = 10000 * ++_baseConsumerId;\n\n            var grains1 = await Do_AddConsumerGrains(baseId, numGrains);\n            for (int i = 0; i < numLoops; i++)\n            {\n                await producerGrain.SendItem(2);\n            }\n            string when1 = \"AddConsumers-Send-2\";\n            // Messages received by original consumer grain\n            await CheckReceivedCounts(when1, consumerGrain, numLoops + 1, 0);\n            // Messages received by new consumer grains\n            // ReSharper disable once AccessToModifiedClosure\n            await Task.WhenAll(grains1.Select(async g =>\n            {\n                await CheckReceivedCounts(when1, g, numLoops, 0);\n#if DELETE_AFTER_TEST\n                _usedGrains.Add(g);\n#endif\n            }));\n\n            string when2 = \"AddConsumers-Send-3\";\n            baseId = 10000 * ++_baseConsumerId;\n            var grains2 = await Do_AddConsumerGrains(baseId, numGrains);\n            for (int i = 0; i < numLoops; i++)\n            {\n                await producerGrain.SendItem(3);\n            }\n            ////Thread.Sleep(TimeSpan.FromSeconds(2));\n            // Messages received by original consumer grain\n            await CheckReceivedCounts(when2, consumerGrain, numLoops*2 + 1, 0);\n            // Messages received by new consumer grains\n            await Task.WhenAll(grains2.Select(g => CheckReceivedCounts(when2, g, numLoops, 0)));\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_PubSub_MultiConsumerSameGrain(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            // Grain Producer -> Grain 2 x Consumer\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            string when;\n            logger.LogInformation(\"Initializing: ConsumerGrain={ConsumerGrainId} ProducerGrain={ProducerGrainId}\", consumerGrainId, producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n            var producerGrain = GetGrain(producerGrainId);\n\n            logger.LogInformation(\"BecomeProducer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n\n            when = \"After BecomeProducer\";\n            // Note: Only semantics guarenteed for producer is that they will have been registered by time that first msg is sent.\n            await producerGrain.SendItem(0);\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 0, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            logger.LogInformation(\"AddConsumer x 2 : StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After first AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After second AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 2, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_PubSub_MultiProducerSameGrain(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            // Grain Producer -> Grain 2 x Consumer\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            string when;\n            logger.LogInformation(\"Initializing: ConsumerGrain={ConsumerGrainId} ProducerGrain={ProducerGrainId}\", consumerGrainId, producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n            var producerGrain = GetGrain(producerGrainId);\n\n            logger.LogInformation(\"BecomeProducer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n            when = \"After first BecomeProducer\";\n            // Note: Only semantics guarenteed for producer is that they will have been registered by time that first msg is sent.\n            await producerGrain.SendItem(0);\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 0, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n            when = \"After second BecomeProducer\";\n            await producerGrain.SendItem(0);\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 0, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            logger.LogInformation(\"AddConsumer x 2 : StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After first AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After second AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 2, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_PubSub_Unsubscribe(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            // Grain Producer -> Grain 2 x Consumer\n            // Note: PubSub should only count distinct grains, even if a grain has multiple consumer handles\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            string when;\n            logger.LogInformation(\"Initializing: ConsumerGrain={ConsumerGrainId} ProducerGrain={ProducerGrainId}\", consumerGrainId, producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n            var producerGrain = GetGrain(producerGrainId);\n\n            logger.LogInformation(\"BecomeProducer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n            await producerGrain.BecomeProducer(_streamId, _streamProviderName);\n            when = \"After BecomeProducer\";\n            // Note: Only semantics guarenteed are that producer will have been registered by time that first msg is sent.\n            await producerGrain.SendItem(0);\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 0, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            logger.LogInformation(\"AddConsumer x 2 : StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            var c1 = await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After first AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n            await CheckConsumerCounts(when, consumerGrain, 1);\n            var c2 = await consumerGrain.AddConsumer(_streamId, _streamProviderName);\n            when = \"After second AddConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 2, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n            await CheckConsumerCounts(when, consumerGrain, 2);\n\n            logger.LogInformation(\"RemoveConsumer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.RemoveConsumer(_streamId, _streamProviderName, c1);\n            when = \"After first RemoveConsumer\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n            await CheckConsumerCounts(when, consumerGrain, 1);\n#if REMOVE_PRODUCER\n            logger.LogInformation(\"RemoveProducer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await producerGrain.RemoveProducer(_streamId, _streamProviderName);\n            when = \"After RemoveProducer\";\n            await CheckPubSubCounts(when, 0, 1);\n            await CheckConsumerCounts(when, consumerGrain, 1);\n#endif\n            logger.LogInformation(\"RemoveConsumer: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.RemoveConsumer(_streamId, _streamProviderName, c2);\n            when = \"After second RemoveConsumer\";\n#if REMOVE_PRODUCER\n            await CheckPubSubCounts(when, 0, 0);\n#else\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 0, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n#endif\n            await CheckConsumerCounts(when, consumerGrain, 0);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task SMS_AllSilosRestart_UnsubscribeConsumer()\n        {\n            const string testName = \"SMS_AllSilosRestart_UnsubscribeConsumer\";\n            _streamId = Guid.NewGuid();\n            _streamProviderName = SMS_STREAM_PROVIDER_NAME;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            var consumerGrain = this.GrainFactory.GetGrain<IStreamUnsubscribeTestGrain>(consumerGrainId);\n\n            logger.LogInformation(\"Subscribe: StreamId={StreamId} Provider={Provider}\", _streamId, _streamProviderName);\n            await consumerGrain.Subscribe(_streamId, _streamProviderName);\n\n            // Restart silos\n            await RestartAllSilos();\n\n            string when = \"After restart all silos\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            // Since we restart all silos, the client might not haave had enough\n            // time to reconnect to the new gateways. Let's retry the call if it\n            // is the case\n            for (int i = 0; i < 3; i++)\n            {\n                try\n                {\n                    await consumerGrain.UnSubscribeFromAllStreams();\n                    break;\n                }\n                catch (OrleansMessageRejectionException ex)\n                {\n                    if (!ex.Message.Contains(\"No gateways available\"))\n                        throw;\n                }\n                await Task.Delay(100);\n            }\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_AllSilosRestart(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            // Restart silos\n            await RestartAllSilos();\n\n            string when = \"After restart all silos\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            when = \"SendItem\";\n            var producerGrain = GetGrain(producerGrainId);\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_AllSilosRestart_PubSubCounts(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n#if USE_GENERICS\n            IStreamReliabilityTestGrain<int> producerGrain =\n#else\n            IStreamReliabilityTestGrain producerGrain =\n#endif\n await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            string when = \"Before restart all silos\";\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            // Restart silos\n            //RestartDefaultSilosButKeepCurrentClient(testName);\n            await RestartAllSilos();\n\n            when = \"After restart all silos\";\n            CheckSilosRunning(when, _numExpectedSilos);\n            // Note: It is not guaranteed that the list of producers will not get modified / cleaned up during silo shutdown, so can't assume count will be 1 here.\n            // Expected == -1 means don't care.\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, -1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            await producerGrain.SendItem(1);\n            when = \"After SendItem\";\n\n            await StreamTestUtils.CheckPubSubCounts(this.InternalClient, _output, when, 1, 1, _streamId, _streamProviderName, StreamTestsConstants.StreamReliabilityNamespace);\n\n            var consumerGrain = GetGrain(consumerGrainId);\n            await CheckReceivedCounts(when, consumerGrain, 1, 0);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_SiloDies_Consumer(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n            string when;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            when = \"Before kill one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            bool sameSilo = await CheckGrainCounts();\n\n            // Find which silo the consumer grain is located on\n            var consumerGrain = GetGrain(consumerGrainId);\n            SiloAddress siloAddress = await consumerGrain.GetLocation();\n\n            _output.WriteLine(\"Consumer grain is located on silo {0} ; Producer on same silo = {1}\", siloAddress, sameSilo);\n\n            // Kill the silo containing the consumer grain\n            SiloHandle siloToKill = this.HostedCluster.Silos.First(s => s.SiloAddress.Equals(siloAddress));\n            await StopSilo(siloToKill, true, false);\n            // Note: Don't restart failed silo for this test case\n            // Note: Don't reinitialize client\n\n            when = \"After kill one silo\";\n            CheckSilosRunning(when, _numExpectedSilos - 1);\n\n            when = \"SendItem\";\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_SiloDies_Producer(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n            string when;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            when = \"Before kill one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            bool sameSilo = await CheckGrainCounts();\n\n            // Find which silo the producer grain is located on\n            SiloAddress siloAddress = await producerGrain.GetLocation();\n            _output.WriteLine(\"Producer grain is located on silo {0} ; Consumer on same silo = {1}\", siloAddress, sameSilo);\n\n            // Kill the silo containing the producer grain\n            SiloHandle siloToKill = this.HostedCluster.Silos.First(s => s.SiloAddress.Equals(siloAddress));\n            await StopSilo(siloToKill, true, false);\n            // Note: Don't restart failed silo for this test case\n            // Note: Don't reinitialize client\n\n            when = \"After kill one silo\";\n            CheckSilosRunning(when, _numExpectedSilos - 1);\n\n            when = \"SendItem\";\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_SiloRestarts_Consumer(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n            string when;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            when = \"Before restart one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            bool sameSilo = await CheckGrainCounts();\n\n            // Find which silo the consumer grain is located on\n            var consumerGrain = GetGrain(consumerGrainId);\n            SiloAddress siloAddress = await consumerGrain.GetLocation();\n\n            _output.WriteLine(\"Consumer grain is located on silo {0} ; Producer on same silo = {1}\", siloAddress, sameSilo);\n\n            // Restart the silo containing the consumer grain\n            SiloHandle siloToKill = this.HostedCluster.Silos.First(s => s.SiloAddress.Equals(siloAddress));\n            await StopSilo(siloToKill, true, true);\n            // Note: Don't reinitialize client\n\n            when = \"After restart one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            when = \"SendItem\";\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_SiloRestarts_Producer(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n            string when;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = await Do_BaselineTest(consumerGrainId, producerGrainId);\n\n            when = \"Before restart one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            bool sameSilo = await CheckGrainCounts();\n\n            // Find which silo the producer grain is located on\n            SiloAddress siloAddress = await producerGrain.GetLocation();\n\n            _output.WriteLine(\"Producer grain is located on silo {0} ; Consumer on same silo = {1}\", siloAddress, sameSilo);\n\n            // Restart the silo containing the consumer grain\n            SiloHandle siloToKill = this.HostedCluster.Silos.First(s => s.SiloAddress.Equals(siloAddress));\n            await StopSilo(siloToKill, true, true);\n            // Note: Don't reinitialize client\n\n            when = \"After restart one silo\";\n            CheckSilosRunning(when, _numExpectedSilos);\n\n            when = \"SendItem\";\n            await producerGrain.SendItem(1);\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        private async Task Test_SiloJoins(string testName, string streamProviderName)\n        {\n            _streamId = Guid.NewGuid();\n            _streamProviderName = streamProviderName;\n\n            const int numLoops = 3;\n\n            StreamTestUtils.LogStartTest(testName, _streamId, _streamProviderName, logger, HostedCluster);\n\n            long consumerGrainId = Random.Shared.Next();\n            long producerGrainId = Random.Shared.Next();\n\n            var producerGrain = GetGrain(producerGrainId);\n            SiloAddress producerLocation = await producerGrain.GetLocation();\n\n            var consumerGrain = GetGrain(consumerGrainId);\n            SiloAddress consumerLocation = await consumerGrain.GetLocation();\n\n            _output.WriteLine(\"Grain silo locations: Producer={0} Consumer={1}\", producerLocation, consumerLocation);\n\n            // Note: This does first SendItem\n            await Do_BaselineTest(consumerGrainId, producerGrainId);\n            int expectedReceived = 1;\n\n            string when = \"SendItem-2\";\n            for (int i = 0; i < numLoops; i++)\n            {\n                await producerGrain.SendItem(2);\n            }\n            expectedReceived += numLoops;\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n            await CheckReceivedCounts(when, consumerGrain, expectedReceived, 0);\n\n            // Add new silo\n            //SiloHandle newSilo = StartAdditionalOrleans();\n            //WaitForLivenessToStabilize();\n            SiloHandle newSilo = await this.HostedCluster.StartAdditionalSiloAsync();\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n\n            when = \"After starting additional silo \" + newSilo;\n            _output.WriteLine(when);\n            CheckSilosRunning(when, _numExpectedSilos + 1);\n\n            //when = \"SendItem-3\";\n            //output.WriteLine(when);\n            //for (int i = 0; i < numLoops; i++)\n            //{\n            //    await producerGrain.SendItem(3);\n            //}\n            //expectedReceived += numLoops;\n            //await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId, true, true);\n            //await CheckReceivedCounts(when, consumerGrain, expectedReceived, 0);\n\n            // Find a Consumer Grain on the new silo\n            IStreamReliabilityTestGrain newConsumer = CreateGrainOnSilo(newSilo.SiloAddress);\n            await newConsumer.AddConsumer(_streamId, _streamProviderName);\n            _output.WriteLine(\"Grain silo locations: Producer={0} OldConsumer={1} NewConsumer={2}\", producerLocation, consumerLocation, newSilo.SiloAddress);\n\n            ////Thread.Sleep(TimeSpan.FromSeconds(2));\n\n            when = \"SendItem-4\";\n            _output.WriteLine(when);\n            for (int i = 0; i < numLoops; i++)\n            {\n                await producerGrain.SendItem(4);\n            }\n            expectedReceived += numLoops;\n            // Old consumer received the newly published messages\n            await CheckReceivedCounts(when+\"-Old\", consumerGrain, expectedReceived, 0);\n            // New consumer received the newly published messages\n            await CheckReceivedCounts(when+\"-New\", newConsumer, numLoops, 0);\n\n            StreamTestUtils.LogEndTest(testName, logger);\n        }\n\n        // ---------- Utility Functions ----------\n\n        private async Task RestartAllSilos()\n        {\n            _output.WriteLine(\"\\n\\n\\n\\n-----------------------------------------------------\\n\" +\n                            \"Restarting all silos - Old Primary={0} Secondary={1}\" +\n                            \"\\n-----------------------------------------------------\\n\\n\\n\",\n                            this.HostedCluster.Primary?.SiloAddress, this.HostedCluster.SecondarySilos.FirstOrDefault()?.SiloAddress);\n\n            foreach (var silo in this.HostedCluster.GetActiveSilos().ToList())\n            {\n                await this.HostedCluster.RestartSiloAsync(silo);\n            }\n\n            // Note: Needed to reinitialize client in this test case to connect to new silos\n            // this.HostedCluster.InitializeClient();\n\n            _output.WriteLine(\"\\n\\n\\n\\n-----------------------------------------------------\\n\" +\n                            \"Restarted new silos - New Primary={0} Secondary={1}\" +\n                            \"\\n-----------------------------------------------------\\n\\n\\n\",\n                            this.HostedCluster.Primary?.SiloAddress, this.HostedCluster.SecondarySilos.FirstOrDefault()?.SiloAddress);\n        }\n\n        private async Task StopSilo(SiloHandle silo, bool kill, bool restart)\n        {\n            SiloAddress oldSilo = silo.SiloAddress;\n            bool isPrimary = oldSilo.Equals(this.HostedCluster.Primary?.SiloAddress);\n            string siloType = isPrimary ? \"Primary\" : \"Secondary\";\n            var action = (restart, kill) switch\n            {\n                (true, true) => \"Kill and restart\",\n                (true, false) => \"Stop and restart\",\n                (false, true) => \"Kill\",\n                (false, false) => \"Stop\",\n            };\n\n            logger.LogWarning(\"{Action} {SiloType} silo {OldSilo}\", action, siloType, oldSilo);\n\n            if (restart)\n            {\n                //RestartRuntime(silo, kill);\n                SiloHandle newSilo = await this.HostedCluster.RestartSiloAsync(silo);\n\n                logger.LogInformation(\"Restarted new {SiloType} silo {SiloAddress}\", siloType, newSilo.SiloAddress);\n\n                Assert.NotEqual(oldSilo, newSilo.SiloAddress); //\"Should be different silo address after Restart\"\n            }\n            else if (kill)\n            {\n               await this.HostedCluster.KillSiloAsync(silo);\n               Assert.False(silo.IsActive);\n            }\n            else\n            {\n               await this.HostedCluster.StopSiloAsync(silo);\n               Assert.False(silo.IsActive);\n            }\n\n            // WaitForLivenessToStabilize(!kill);\n            this.HostedCluster.WaitForLivenessToStabilizeAsync(kill).Wait();\n        }\n\n#if USE_GENERICS\n        protected IStreamReliabilityTestGrain<int> GetGrain(long grainId)\n#else\n        protected IStreamReliabilityTestGrain GetGrain(long grainId)\n#endif\n        {\n#if USE_GENERICS\n            return StreamReliabilityTestGrainFactory<int>.GetGrain(grainId);\n#else\n            return this.GrainFactory.GetGrain<IStreamReliabilityTestGrain>(grainId);\n#endif\n        }\n\n#if USE_GENERICS\n        private IStreamReliabilityTestGrain<int> CreateGrainOnSilo(SiloHandle silo)\n#else\n        private IStreamReliabilityTestGrain CreateGrainOnSilo(SiloAddress silo)\n#endif\n        {\n            // Find a Grain to use which is located on the specified silo\n            IStreamReliabilityTestGrain newGrain;\n            long kp = Random.Shared.Next();\n            while (true)\n            {\n                newGrain = GetGrain(++kp);\n                SiloAddress loc = newGrain.GetLocation().Result;\n                if (loc.Equals(silo))\n                    break;\n            }\n            _output.WriteLine(\"Using Grain {0} located on silo {1}\", kp, silo);\n            return newGrain;\n        }\n\n        protected async Task CheckConsumerProducerStatus(string when, long producerGrainId, long consumerGrainId, bool expectIsProducer, bool expectIsConsumer)\n        {\n            await CheckConsumerProducerStatus(when, producerGrainId, consumerGrainId,\n                expectIsProducer ? 1 : 0,\n                expectIsConsumer ? 1 : 0);\n        }\n        protected async Task CheckConsumerProducerStatus(string when, long producerGrainId, long consumerGrainId, int expectedNumProducers, int expectedNumConsumers)\n        {\n            var producerGrain = GetGrain(producerGrainId);\n            var consumerGrain = GetGrain(consumerGrainId);\n\n            bool isProducer = await producerGrain.IsProducer();\n            _output.WriteLine(\"Grain {0} IsProducer={1}\", producerGrainId, isProducer);\n            Assert.Equal(expectedNumProducers > 0, isProducer);\n\n            bool isConsumer = await consumerGrain.IsConsumer();\n            _output.WriteLine(\"Grain {0} IsConsumer={1}\", consumerGrainId, isConsumer);\n            Assert.Equal(expectedNumConsumers > 0, isConsumer);\n\n            int consumerHandleCount = await consumerGrain.GetConsumerHandlesCount();\n            int consumerObserverCount = await consumerGrain.GetConsumerHandlesCount();\n            _output.WriteLine(\"Grain {0} HandleCount={1} ObserverCount={2}\", consumerGrainId, consumerHandleCount, consumerObserverCount);\n            Assert.Equal(expectedNumConsumers, consumerHandleCount);\n            Assert.Equal(expectedNumConsumers, consumerObserverCount);\n        }\n        private void CheckSilosRunning(string when, int expectedNumSilos)\n        {\n            Assert.Equal(expectedNumSilos, this.HostedCluster.GetActiveSilos().Count());\n        }\n        protected async Task<bool> CheckGrainCounts()\n        {\n#if USE_GENERICS\n            string grainType = RuntimeTypeNameFormatter.Format(typeof(StreamReliabilityTestGrain<int>));\n#else\n            string grainType = RuntimeTypeNameFormatter.Format(typeof(StreamReliabilityTestGrain));\n#endif\n            IManagementGrain mgmtGrain = this.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            SimpleGrainStatistic[] grainStats = await mgmtGrain.GetSimpleGrainStatistics();\n            _output.WriteLine(\"Found grains \" + Utils.EnumerableToString(grainStats));\n\n            var grainLocs = grainStats.Where(gs => gs.GrainType == grainType).ToArray();\n\n            Assert.True(grainLocs.Length > 0, \"Found too few grains\");\n            Assert.True(grainLocs.Length <= 2, \"Found too many grains \" + grainLocs.Length);\n\n            bool sameSilo = grainLocs.Length == 1;\n            if (sameSilo)\n            {\n                StreamTestUtils.Assert_AreEqual(_output, 2, grainLocs[0].ActivationCount, \"Num grains on same Silo \" + grainLocs[0].SiloAddress);\n            }\n            else\n            {\n                StreamTestUtils.Assert_AreEqual(_output, 1, grainLocs[0].ActivationCount, \"Num grains on Silo \" + grainLocs[0].SiloAddress);\n                StreamTestUtils.Assert_AreEqual(_output, 1, grainLocs[1].ActivationCount, \"Num grains on Silo \" + grainLocs[1].SiloAddress);\n            }\n            return sameSilo;\n        }\n\n#if USE_GENERICS\n        protected async Task CheckReceivedCounts<T>(string when, IStreamReliabilityTestGrain<T> consumerGrain, int expectedReceivedCount, int expectedErrorsCount)\n#else\n        protected async Task CheckReceivedCounts(string when, IStreamReliabilityTestGrain consumerGrain, int expectedReceivedCount, int expectedErrorsCount)\n#endif\n        {\n            long pk = consumerGrain.GetPrimaryKeyLong();\n\n            int receivedCount = 0;\n            for (int i = 0; i < 20; i++)\n            {\n                receivedCount = await consumerGrain.GetReceivedCount();\n                _output.WriteLine(\"After {0}s ReceivedCount={1} for grain {2}\", i, receivedCount, pk);\n\n                if (receivedCount == expectedReceivedCount)\n                    break;\n\n                Thread.Sleep(TimeSpan.FromSeconds(1));\n            }\n            StreamTestUtils.Assert_AreEqual(_output, expectedReceivedCount, receivedCount,\n                \"ReceivedCount for stream {0} for grain {1} {2}\", _streamId, pk, when);\n\n            int errorsCount = await consumerGrain.GetErrorsCount();\n            StreamTestUtils.Assert_AreEqual(_output, expectedErrorsCount, errorsCount, \"ErrorsCount for stream {0} for grain {1} {2}\", _streamId, pk, when);\n        }\n#if USE_GENERICS\n        protected async Task CheckConsumerCounts<T>(string when, IStreamReliabilityTestGrain<T> consumerGrain, int expectedConsumerCount)\n#else\n        protected async Task CheckConsumerCounts(string when, IStreamReliabilityTestGrain consumerGrain, int expectedConsumerCount)\n#endif\n        {\n            int consumerCount = await consumerGrain.GetConsumerCount();\n            StreamTestUtils.Assert_AreEqual(_output, expectedConsumerCount, consumerCount, \"ConsumerCount for stream {0} {1}\", _streamId, when);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Streaming/TestAzureTableStorageStreamFailureHandler.cs",
    "content": "using Azure.Data.Tables;\nusing Azure.Identity;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Persistence.AzureStorage;\nusing Orleans.Providers.Streams.PersistentStreams;\nusing TestExtensions;\n\nnamespace Tester.AzureUtils.Streaming\n{\n    public static class TestAzureTableStorageStreamFailureHandler\n    {\n        private const string TableName = \"TestStreamFailures\";\n        private const string DeploymentId = \"TestDeployment\";\n\n        public static async Task<int> GetDeliveryFailureCount(string streamProviderName)\n        {\n            var dataManager = GetDataManager();\n            await dataManager.InitTableAsync();\n            var deliveryErrors =\n                await dataManager.ReadAllTableEntriesForPartitionAsync(\n                        StreamDeliveryFailureEntity.MakeDefaultPartitionKey(streamProviderName, DeploymentId));\n            return deliveryErrors.Count;\n        }\n\n        public static async Task DeleteAll()\n        {\n            var dataManager = GetDataManager();\n            await dataManager.InitTableAsync();\n            await dataManager.DeleteTableAsync();\n        }\n\n        private static AzureTableDataManager<TableEntity> GetDataManager()\n        {\n            var options = new AzureStorageOperationOptions { TableName = TableName };\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.TableServiceClient = new(TestDefaultConfiguration.TableEndpoint, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.TableServiceClient = new(TestDefaultConfiguration.DataConnectionString);\n            }\n            return new AzureTableDataManager<TableEntity>(options, NullLogger.Instance);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/UnitTestAzureTableDataManager.cs",
    "content": "using System.Text;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Clustering.AzureStorage;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Azure.Data.Tables;\nusing Azure;\n\nnamespace Tester.AzureUtils\n{\n    public class UnitTestAzureTableData : ITableEntity\n    {\n        public byte[] Data { get; set; }\n        public string StringData { get; set; }\n        public string PartitionKey { get; set; }\n        public string RowKey { get; set; }\n        public DateTimeOffset? Timestamp { get; set; }\n        public ETag ETag { get; set; }\n\n        public UnitTestAzureTableData()\n        {\n\n        }\n\n        public UnitTestAzureTableData(string data, string partitionKey, string rowKey)\n        {\n            StringData = data;\n            PartitionKey = partitionKey;\n            RowKey = rowKey;\n        }\n\n        public UnitTestAzureTableData Clone()\n        {\n            return new UnitTestAzureTableData\n            {\n                StringData = this.StringData,\n                PartitionKey = this.PartitionKey,\n                RowKey = this.RowKey\n            };\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder();\n            sb.Append(\"UnitTestAzureData[\");\n            sb.Append(\" PartitionKey=\").Append(PartitionKey);\n            sb.Append(\" RowKey=\").Append(RowKey);\n            sb.Append(\" ]\");\n            return sb.ToString();\n        }\n    }\n\n    internal class UnitTestAzureTableDataManager : AzureTableDataManager<UnitTestAzureTableData>\n    {\n        protected const string INSTANCE_TABLE_NAME = \"UnitTestAzureData\";\n\n        public UnitTestAzureTableDataManager()\n            : base(new AzureStorageOperationOptions { TableName = INSTANCE_TABLE_NAME }.ConfigureTestDefaults(),\n                  NullLoggerFactory.Instance.CreateLogger<UnitTestAzureTableDataManager>())\n        {\n            InitTableAsync().WaitAsync(new AzureStoragePolicyOptions().CreationTimeout).Wait();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Azure.Tests/Utilities/AzureQueueUtilities.cs",
    "content": "namespace Tester.AzureUtils.Streaming\n{\n    public static class AzureQueueUtilities\n    {\n        public static List<string> GenerateQueueNames(string queueNamePrefix, int queueCount)\n        {\n            return Enumerable.Range(0, queueCount).Select(num => $\"{queueNamePrefix}-{num}\").ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Cassandra.Tests/Clustering/CassandraClusteringTableTests.cs",
    "content": "using System.Net;\nusing Cassandra;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Clustering.Cassandra;\nusing Orleans.Clustering.Cassandra.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Tester.Cassandra.Utility;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Cassandra.Clustering;\n\n/// <summary>\n/// Tests for Orleans membership table operations using Apache Cassandra as the backing store.\n/// </summary>\n[TestCategory(\"Cassandra\"), TestCategory(\"Clustering\")]\n[Collection(\"Cassandra\")]\npublic sealed class CassandraClusteringTableTests : IClassFixture<CassandraContainer>\n{\n    private readonly CassandraContainer _cassandraContainer;\n    private readonly ITestOutputHelper _testOutputHelper;\n    private static readonly string HostName = Dns.GetHostName();\n    private static int _generation;\n\n    public CassandraClusteringTableTests(CassandraContainer cassandraContainer, ITestOutputHelper testOutputHelper)\n    {\n        _cassandraContainer = cassandraContainer;\n        _cassandraContainer.Name = nameof(Cassandra);\n        _testOutputHelper = testOutputHelper;\n    }\n\n    [Fact]\n    public async Task MembershipTable_GetGateways()\n    {\n        var (membershipTable, gatewayListProvider) = await CreateNewMembershipTableAsync();\n\n        var membershipEntries = Enumerable.Range(0, 10).Select(_ => CreateMembershipEntryForTest()).ToArray();\n\n        membershipEntries[3].Status = SiloStatus.Active;\n        membershipEntries[3].ProxyPort = 0;\n        membershipEntries[5].Status = SiloStatus.Active;\n        membershipEntries[9].Status = SiloStatus.Active;\n\n        var data = await membershipTable.ReadAll();\n        Assert.NotNull(data);\n        Assert.Empty(data.Members);\n\n        var version = data.Version;\n        foreach (var membershipEntry in membershipEntries)\n        {\n            Assert.True(await membershipTable.InsertRow(membershipEntry, version.Next()));\n            version = (await membershipTable.ReadRow(membershipEntry.SiloAddress)).Version;\n        }\n\n        var gateways = await gatewayListProvider.GetGateways();\n\n        var entries = new List<string>(gateways.Select(g => g.ToString()));\n\n        // only members with a non-zero Gateway port\n        Assert.DoesNotContain(membershipEntries[3].SiloAddress.ToGatewayUri().ToString(), entries);\n\n        // only Active members\n        Assert.Contains(membershipEntries[5].SiloAddress.ToGatewayUri().ToString(), entries);\n        Assert.Contains(membershipEntries[9].SiloAddress.ToGatewayUri().ToString(), entries);\n        Assert.Equal(2, entries.Count);\n    }\n\n    [Fact]\n    public async Task MembershipTable_ReadAll_EmptyTable()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var data = await membershipTable.ReadAll();\n        Assert.NotNull(data);\n\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Empty(data.Members);\n        Assert.NotNull(data.Version.VersionEtag);\n        Assert.Equal(0, data.Version.Version);\n    }\n\n    [Fact]\n    public async Task MembershipTable_InsertRow()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var membershipEntry = CreateMembershipEntryForTest();\n\n        var data = await membershipTable.ReadAll();\n        Assert.NotNull(data);\n        Assert.Empty(data.Members);\n\n        var nextTableVersion = data.Version.Next();\n\n        var ok = await membershipTable.InsertRow(membershipEntry, nextTableVersion);\n        Assert.True(ok, \"InsertRow failed\");\n\n        data = await membershipTable.ReadAll();\n\n        Assert.Equal(1, data.Version.Version);\n\n        Assert.Single(data.Members);\n    }\n\n    [Fact]\n    public async Task MembershipTable_ReadRow_Insert_Read()\n    {\n        var (membershipTable, gatewayProvider) = await CreateNewMembershipTableAsync(\"Phalanx\", \"blu\");\n\n        MembershipTableData data = await membershipTable.ReadAll();\n\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Empty(data.Members);\n\n        TableVersion newTableVersion = data.Version.Next();\n\n        MembershipEntry newEntry = CreateMembershipEntryForTest();\n        bool ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n        Assert.True(ok, \"InsertRow failed\");\n\n        ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n        Assert.False(ok, \"InsertRow should have failed - same entry, old table version\");\n\n        ok = await membershipTable.InsertRow(CreateMembershipEntryForTest(), newTableVersion);\n        Assert.False(ok, \"InsertRow should have failed - new entry, old table version\");\n\n        data = await membershipTable.ReadAll();\n\n        Assert.Equal(1, data.Version.Version);\n\n        TableVersion nextTableVersion = data.Version.Next();\n\n        ok = await membershipTable.InsertRow(newEntry, nextTableVersion);\n        Assert.False(ok, \"InsertRow should have failed - duplicate entry\");\n\n        data = await membershipTable.ReadAll();\n        Assert.Single(data.Members);\n\n        data = await membershipTable.ReadRow(newEntry.SiloAddress);\n        Assert.Equal(newTableVersion.Version, data.Version.Version);\n\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Single(data.Members);\n        Assert.NotNull(data.Version.VersionEtag);\n\n        Assert.NotEqual(newTableVersion.VersionEtag, data.Version.VersionEtag);\n        Assert.Equal(newTableVersion.Version, data.Version.Version);\n\n        var membershipEntry = data.Members[0].Item1;\n        string eTag = data.Members[0].Item2;\n        _testOutputHelper.WriteLine(\"Membership.ReadRow returned MembershipEntry ETag={0} Entry={1}\", eTag, membershipEntry);\n\n        Assert.NotNull(eTag);\n        Assert.NotNull(membershipEntry);\n    }\n\n    [Fact]\n    public async Task MembershipTable_ReadAll_Insert_ReadAll()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var data = await membershipTable.ReadAll();\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Empty(data.Members);\n\n        var newTableVersion = data.Version.Next();\n\n        var newEntry = CreateMembershipEntryForTest();\n        var ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n        Assert.True(ok, \"InsertRow failed\");\n\n        data = await membershipTable.ReadAll();\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Single(data.Members);\n        Assert.NotNull(data.Version.VersionEtag);\n\n        Assert.NotEqual(newTableVersion.VersionEtag, data.Version.VersionEtag);\n        Assert.Equal(newTableVersion.Version, data.Version.Version);\n\n        var membershipEntry = data.Members[0].Item1;\n        var eTag = data.Members[0].Item2;\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned MembershipEntry ETag={0} Entry={1}\", eTag, membershipEntry);\n\n        Assert.NotNull(eTag);\n        Assert.NotNull(membershipEntry);\n    }\n\n    [Fact]\n    public async Task MembershipTable_UpdateRow()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var tableData = await membershipTable.ReadAll();\n        Assert.NotNull(tableData.Version);\n\n        Assert.Equal(0, tableData.Version.Version);\n        Assert.Empty(tableData.Members);\n\n        for (var i = 1; i < 10; i++)\n        {\n            var siloEntry = CreateMembershipEntryForTest();\n\n            siloEntry.SuspectTimes =\n            [\n                new Tuple<SiloAddress, DateTime>(CreateSiloAddressForTest(), GetUtcNowWithSecondsResolution().AddSeconds(1)),\n                new Tuple<SiloAddress, DateTime>(CreateSiloAddressForTest(), GetUtcNowWithSecondsResolution().AddSeconds(2))\n            ];\n\n            var tableVersion = tableData.Version.Next();\n\n            _testOutputHelper.WriteLine(\"Calling InsertRow with Entry = {0} TableVersion = {1}\", siloEntry, tableVersion);\n            var ok = await membershipTable.InsertRow(siloEntry, tableVersion);\n            Assert.True(ok, \"InsertRow failed\");\n\n            tableData = await membershipTable.ReadAll();\n\n            var etagBefore = tableData.TryGet(siloEntry.SiloAddress)?.Item2;\n\n            Assert.NotNull(etagBefore);\n\n            _testOutputHelper.WriteLine(\n                \"Calling UpdateRow with Entry = {0} correct eTag = {1} old version={2}\",\n                siloEntry,\n                etagBefore,\n                tableVersion?.ToString() ?? \"null\");\n            ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n            Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n            tableData = await membershipTable.ReadAll();\n\n            tableVersion = tableData.Version.Next();\n\n            _testOutputHelper.WriteLine(\n                \"Calling UpdateRow with Entry = {0} correct eTag = {1} correct version={2}\",\n                siloEntry,\n                etagBefore,\n                tableVersion?.ToString() ?? \"null\");\n\n            ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n\n            Assert.True(ok, $\"UpdateRow failed - Table Data = {tableData}\");\n\n            _testOutputHelper.WriteLine(\n                \"Calling UpdateRow with Entry = {0} old eTag = {1} old version={2}\",\n                siloEntry,\n                etagBefore,\n                tableVersion?.ToString() ?? \"null\");\n            ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n            Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n\n            tableData = await membershipTable.ReadAll();\n\n            var tuple = tableData.TryGet(siloEntry.SiloAddress);\n\n            Assert.Equal(tuple.Item1.ToFullString(), siloEntry.ToFullString());\n\n            var etagAfter = tuple.Item2;\n\n            _testOutputHelper.WriteLine(\n                \"Calling UpdateRow with Entry = {0} correct eTag = {1} old version={2}\",\n                siloEntry,\n                etagAfter,\n                tableVersion?.ToString() ?? \"null\");\n\n            ok = await membershipTable.UpdateRow(siloEntry, etagAfter, tableVersion);\n\n            Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n\n            tableData = await membershipTable.ReadAll();\n\n            etagBefore = etagAfter;\n\n            etagAfter = tableData.TryGet(siloEntry.SiloAddress)?.Item2;\n\n            Assert.Equal(etagBefore, etagAfter);\n            Assert.NotNull(tableData.Version);\n            Assert.Equal(tableVersion!.Version, tableData.Version.Version);\n\n            Assert.Equal(i, tableData.Members.Count);\n        }\n    }\n\n    [Fact]\n    public async Task MembershipTable_ManyMembershipTables()\n    {\n        var tasks = new List<Task>();\n        for (var i = 0; i < 50; i++)\n        {\n            tasks.Add(Task.Run(async () =>\n            {\n                await Task.Yield();\n                var (membershipTable, _) = await CreateNewMembershipTableAsync();\n            }));\n        }\n        await Task.WhenAll(tasks);\n    }\n\n    [Fact]\n    public async Task MembershipTable_UpdateRowInParallel()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var tableData = await membershipTable.ReadAll();\n\n        var data = CreateMembershipEntryForTest();\n\n        var newTableVer = tableData.Version.Next();\n\n        var insertions = Task.WhenAll(Enumerable.Range(1, 20).Select(async _ => { try { return await membershipTable.InsertRow(data, newTableVer); } catch { return false; } }));\n\n        Assert.True((await insertions).Single(x => x), \"InsertRow failed\");\n\n        await Task.WhenAll(Enumerable.Range(1, 19).Select(async _ =>\n        {\n            var done = false;\n            do\n            {\n                var updatedTableData = await membershipTable.ReadAll();\n                var updatedRow = updatedTableData.TryGet(data.SiloAddress);\n\n                await Task.Delay(10);\n                if (updatedRow is null) continue;\n\n                var tableVersion = updatedTableData.Version.Next();\n                try\n                {\n                    done = await membershipTable.UpdateRow(updatedRow.Item1, updatedRow.Item2, tableVersion);\n                }\n                catch\n                {\n                    done = false;\n                }\n            } while (!done);\n        })).WithTimeout(TimeSpan.FromSeconds(30));\n\n\n        tableData = await membershipTable.ReadAll();\n        Assert.NotNull(tableData.Version);\n\n        Assert.Equal(20, tableData.Version.Version);\n\n        Assert.Single(tableData.Members);\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public async Task MembershipTable_UpdateIAmAlive(bool cassandraTtl)\n    {\n        // Drop the membership table before starting because the TTL behavior depends on the table creation\n        ISession ttlSession = await CreateSession();\n        await ttlSession.ExecuteAsync(new SimpleStatement(\"DROP TABLE IF EXISTS membership;\"));\n\n        var (membershipTable, _) = await CreateNewMembershipTableAsync(cassandraTtl:cassandraTtl);\n\n        var tableData = await membershipTable.ReadAll();\n\n        var newTableVersion = tableData.Version.Next();\n        var newEntry = CreateMembershipEntryForTest();\n        var ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n        Assert.True(ok);\n        MembershipEntry originalMembershipEntry = (await membershipTable.ReadAll())\n            .Members.First(e => e.Item1.SiloAddress.Equals(newEntry.SiloAddress))\n            .Item1;\n        Assert.Null(originalMembershipEntry.SuspectTimes);\n\n        // Validate initial TTL values\n        var initialTtlValues = new Dictionary<string, int>();\n        await ValidateTtlValues(initial:true);\n\n        var amAliveTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));\n\n        // This mimics the arguments MembershipOracle.OnIAmAliveUpdateInTableTimer passes in\n        var entry = new MembershipEntry\n        {\n            SiloAddress = newEntry.SiloAddress,\n            IAmAliveTime = amAliveTime\n        };\n\n        await membershipTable.UpdateIAmAlive(entry);\n\n        tableData = await membershipTable.ReadAll();\n        MembershipEntry updatedMember = tableData.Members\n            .First(e => e.Item1.SiloAddress.Equals(newEntry.SiloAddress))\n            .Item1;\n\n        // compare that the value is close to what we passed in, but not exactly, as the underlying store can set its own precision settings\n        // (ie: in SQL Server this is defined as datetime2(3), so we don't expect precision to account for less than 0.001s values)\n        Assert.True(\n            (amAliveTime - updatedMember.IAmAliveTime).Duration() < TimeSpan.FromSeconds(2),\n            $\"Expected time around {amAliveTime} but got {updatedMember.IAmAliveTime} that is off by {(amAliveTime - updatedMember.IAmAliveTime).Duration()}\");\n        Assert.Equal(newTableVersion.Version, tableData.Version.Version);\n\n        // Validate the rest of the data is still the same after the update\n        Assert.Equal(originalMembershipEntry.SiloAddress, updatedMember.SiloAddress);\n        Assert.Equal(originalMembershipEntry.SiloName, updatedMember.SiloName);\n        Assert.Equal(originalMembershipEntry.HostName, updatedMember.HostName);\n        Assert.Equal(originalMembershipEntry.Status, updatedMember.Status);\n        Assert.Equal(originalMembershipEntry.ProxyPort, updatedMember.ProxyPort);\n        Assert.Null(updatedMember.SuspectTimes);\n        Assert.Equal(originalMembershipEntry.StartTime, updatedMember.StartTime);\n\n        // Validate the TTL values are greater than the initial values read after the delay\n        await ValidateTtlValues(initial:false);\n\n        // Validate data automatically expires when using Cassandra TTL, and is still present if not\n        // The Cassandra TTL is set to 20 seconds for this testing\n        using var cts = new CancellationTokenSource(delay:TimeSpan.FromSeconds(30));\n        if (cassandraTtl)\n        {\n            await ValidateDataIsDeleted(cts.Token);\n        }\n        else\n        {\n            await ValidateDataIsNotDeleted(cts.Token);\n        }\n\n        return;\n\n        async Task ValidateTtlValues(bool initial)\n        {\n            if (cassandraTtl && initial)\n            {\n                // When actually using the TTL, wait 5 seconds so the TTL values will be less than 20\n                await Task.Delay(TimeSpan.FromSeconds(5), CancellationToken.None);\n            }\n\n            // Cassandra columns that are part of the primary key are not available with the TTL command\n            // See https://issues.apache.org/jira/browse/CASSANDRA-9312\n            Row ttlResult = (await ttlSession.ExecuteAsync(new SimpleStatement(\n                    \"\"\"\n                    SELECT\n                        TTL (version) as version_tll,\n                        TTL (silo_name) as siloname_ttl,\n                        TTL (host_name) as hostname_ttl,\n                        TTL (status) as status_ttl,\n                        TTL (proxy_port) as proxyport_ttl,\n                        TTL (suspect_times) as suspecttimes_ttl,\n                        TTL (start_time) as starttime_ttl,\n                        TTL (i_am_alive_time) as iamalivetime_ttl\n                    FROM membership\n                    \"\"\")))\n                .First();\n\n            object versionTtl = ttlResult[\"version_tll\"];\n            object siloNameTtl = ttlResult[\"siloname_ttl\"];\n            object hostNameTtl = ttlResult[\"hostname_ttl\"];\n            object statusTtl = ttlResult[\"status_ttl\"];\n            object proxyPortTtl = ttlResult[\"proxyport_ttl\"];\n            object suspectTimesTtl = ttlResult[\"suspecttimes_ttl\"];\n            object startTimeTtl = ttlResult[\"starttime_ttl\"];\n            object iAmAliveTtl = ttlResult[\"iamalivetime_ttl\"];\n\n            if (cassandraTtl)\n            {\n                // TTLs should be non-null, and if not the initial TTL check, should be greater\n                Assert.True(int.TryParse(versionTtl.ToString(), out int versionInt));\n                Assert.True(int.TryParse(siloNameTtl.ToString(), out int siloNameInt));\n                Assert.True(int.TryParse(hostNameTtl.ToString(), out int hostNameInt));\n                Assert.True(int.TryParse(statusTtl.ToString(), out int statusInt));\n                Assert.True(int.TryParse(proxyPortTtl.ToString(), out int proxyPortInt));\n                Assert.True(int.TryParse(startTimeTtl.ToString(), out int startTimeInt));\n                Assert.True(int.TryParse(iAmAliveTtl.ToString(), out int iAmAliveInt));\n                if (initial)\n                {\n                    Assert.True(versionInt > 0);\n                    Assert.True(siloNameInt > 0);\n                    Assert.True(hostNameInt > 0);\n                    Assert.True(statusInt > 0);\n                    Assert.True(proxyPortInt > 0);\n                    Assert.True(startTimeInt > 0);\n                    Assert.True(iAmAliveInt > 0);\n\n                    initialTtlValues[\"version_tll\"] = versionInt;\n                    initialTtlValues[\"siloname_ttl\"] = siloNameInt;\n                    initialTtlValues[\"hostname_ttl\"] = hostNameInt;\n                    initialTtlValues[\"status_ttl\"] = statusInt;\n                    initialTtlValues[\"proxyport_ttl\"] = proxyPortInt;\n                    initialTtlValues[\"starttime_ttl\"] = startTimeInt;\n                    initialTtlValues[\"iamalivetime_ttl\"] = iAmAliveInt;\n                }\n                else\n                {\n                    Assert.True(versionInt > initialTtlValues[\"version_tll\"]);\n                    Assert.True(siloNameInt > initialTtlValues[\"siloname_ttl\"]);\n                    Assert.True(hostNameInt > initialTtlValues[\"hostname_ttl\"]);\n                    Assert.True(statusInt > initialTtlValues[\"status_ttl\"]);\n                    Assert.True(proxyPortInt > initialTtlValues[\"proxyport_ttl\"]);\n                    Assert.True(startTimeInt > initialTtlValues[\"starttime_ttl\"]);\n                    Assert.True(iAmAliveInt > initialTtlValues[\"iamalivetime_ttl\"]);\n                }\n\n                // suspect times will always be null because we're not actually filing it out in the test\n                Assert.Null(suspectTimesTtl);\n            }\n            else\n            {\n                // TTLs should always be null when Cassandra TTL is disabled (default_time_to_live is 0)\n                Assert.Null(versionTtl);\n                Assert.Null(siloNameTtl);\n                Assert.Null(hostNameTtl);\n                Assert.Null(statusTtl);\n                Assert.Null(proxyPortTtl);\n                Assert.Null(suspectTimesTtl);\n                Assert.Null(startTimeTtl);\n                Assert.Null(iAmAliveTtl);\n            }\n        }\n\n        async Task ValidateDataIsDeleted(CancellationToken ct)\n        {\n            while (true)\n            {\n                if (ct.IsCancellationRequested)\n                {\n                    throw new TimeoutException(\"Did not validate Cassandra data deletion within timeout\");\n                }\n\n                tableData = await membershipTable.ReadAll();\n                if (tableData.Members.Count == 0)\n                {\n                    // Success!\n                    return;\n                }\n\n                await Task.Delay(TimeSpan.FromSeconds(1), CancellationToken.None);\n            }\n        }\n\n        async Task ValidateDataIsNotDeleted(CancellationToken ct)\n        {\n            while (!ct.IsCancellationRequested)\n            {\n                tableData = await membershipTable.ReadAll();\n                if (tableData.Members.Count == 0)\n                {\n                    throw new Exception(\"Cassandra data was unexpectedly deleted when not using a TTL\");\n                }\n\n                await Task.Delay(TimeSpan.FromSeconds(1), CancellationToken.None);\n            }\n        }\n    }\n\n    [Fact]\n    public async Task MembershipTable_CleanupDefunctSiloEntries()\n    {\n        var (membershipTable, _) = await CreateNewMembershipTableAsync();\n\n        var data = await membershipTable.ReadAll();\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Empty(data.Members);\n\n        var newTableVersion = data.Version.Next();\n\n        var oldEntryDead = CreateMembershipEntryForTest();\n        oldEntryDead.IAmAliveTime = oldEntryDead.IAmAliveTime.AddDays(-10);\n        oldEntryDead.StartTime = oldEntryDead.StartTime.AddDays(-10);\n        oldEntryDead.Status = SiloStatus.Dead;\n        var ok = await membershipTable.InsertRow(oldEntryDead, newTableVersion);\n        var table = await membershipTable.ReadAll();\n\n        Assert.True(ok, \"InsertRow Dead failed\");\n\n        newTableVersion = table.Version.Next();\n        var oldEntryJoining = CreateMembershipEntryForTest();\n        oldEntryJoining.IAmAliveTime = oldEntryJoining.IAmAliveTime.AddDays(-10);\n        oldEntryJoining.StartTime = oldEntryJoining.StartTime.AddDays(-10);\n        oldEntryJoining.Status = SiloStatus.Joining;\n        ok = await membershipTable.InsertRow(oldEntryJoining, newTableVersion);\n        table = await membershipTable.ReadAll();\n\n        Assert.True(ok, \"InsertRow Joining failed\");\n\n        newTableVersion = table.Version.Next();\n        var newEntry = CreateMembershipEntryForTest();\n        ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n        Assert.True(ok, \"InsertRow failed\");\n\n        data = await membershipTable.ReadAll();\n        newTableVersion = data.Version.Next();\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Equal(3, data.Members.Count);\n\n        // Every status other than Active should get cleared out if old\n        foreach (var siloStatus in Enum.GetValues<SiloStatus>())\n        {\n            var oldEntry = CreateMembershipEntryForTest();\n            oldEntry.IAmAliveTime = oldEntry.IAmAliveTime.AddDays(-10);\n            oldEntry.StartTime = oldEntry.StartTime.AddDays(-10);\n            oldEntry.Status = siloStatus;\n            ok = await membershipTable.InsertRow(oldEntry, newTableVersion);\n            table = await membershipTable.ReadAll();\n\n            Assert.True(ok, \"InsertRow failed\");\n\n            newTableVersion = table.Version.Next();\n        }\n\n        await membershipTable.CleanupDefunctSiloEntries(oldEntryDead.IAmAliveTime.AddDays(3));\n\n        data = await membershipTable.ReadAll();\n        _testOutputHelper.WriteLine(\"Membership.ReadAll returned TableVersion={0} Data={1}\", data.Version, data);\n\n        Assert.Equal(2, data.Members.Count);\n    }\n\n    // Utility methods\n    private static MembershipEntry CreateMembershipEntryForTest()\n    {\n        var siloAddress = CreateSiloAddressForTest();\n\n        var membershipEntry = new MembershipEntry\n        {\n            SiloAddress = siloAddress,\n            HostName = HostName,\n            SiloName = \"TestSiloName\",\n            Status = SiloStatus.Joining,\n            ProxyPort = siloAddress.Endpoint.Port,\n            StartTime = GetUtcNowWithSecondsResolution(),\n            IAmAliveTime = GetUtcNowWithSecondsResolution()\n        };\n\n        return membershipEntry;\n    }\n\n    private static DateTime GetUtcNowWithSecondsResolution()\n    {\n        var now = DateTime.UtcNow;\n        return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, DateTimeKind.Utc);\n    }\n\n    private static SiloAddress CreateSiloAddressForTest()\n    {\n        var siloAddress = SiloAddressUtils.NewLocalSiloAddress(Interlocked.Increment(ref _generation));\n        siloAddress.Endpoint.Port = 12345;\n        return siloAddress;\n    }\n\n    private async Task<(IMembershipTable, IGatewayListProvider)> CreateNewMembershipTableAsync(\n        string serviceId,\n        string clusterId,\n        bool cassandraTtl = false)\n    {\n        var services = new ServiceCollection()\n            .AddSingleton<CassandraClusteringTable>()\n            .AddSingleton<CassandraGatewayListProvider>()\n            .Configure<ClusterOptions>(o => { o.ServiceId = serviceId; o.ClusterId = clusterId; })\n            .Configure<CassandraClusteringOptions>(o =>\n            {\n                o.ConfigureClient(async _ => await CreateSession());\n                o.UseCassandraTtl = cassandraTtl;\n            })\n            .Configure<ClusterMembershipOptions>(o =>\n            {\n                if (cassandraTtl)\n                {\n                    // Shorten the Cassandra TTL period so we can more easily check that rows are automatically deleted\n                    o.DefunctSiloExpiration = TimeSpan.FromSeconds(20);\n                }\n            })\n            .Configure<GatewayOptions>(o => o.GatewayListRefreshPeriod = TimeSpan.FromSeconds(15))\n            .BuildServiceProvider();\n        IMembershipTable membershipTable = services.GetRequiredService<CassandraClusteringTable>();\n        await membershipTable.InitializeMembershipTable(true);\n\n        IGatewayListProvider gatewayProvider = services.GetRequiredService < CassandraGatewayListProvider>();\n        await gatewayProvider.InitializeGatewayListProvider();\n\n        return (membershipTable, gatewayProvider);\n    }\n\n    private async Task<ISession> CreateSession()\n    {\n        var container = await _cassandraContainer.RunImage();\n\n        return container.session;\n    }\n\n    private Task<(IMembershipTable, IGatewayListProvider)> CreateNewMembershipTableAsync(bool cassandraTtl = false)\n    {\n        var serviceId = $\"Service_{Guid.NewGuid()}\";\n        var clusterId = $\"Cluster_{Guid.NewGuid()}\";\n\n        return CreateNewMembershipTableAsync(serviceId, clusterId, cassandraTtl);\n    }\n\n    [Fact]\n    public async Task A_Test()\n    {\n        var serviceId = $\"Service_{Guid.NewGuid()}\";\n        var clusterId = $\"Cluster_{Guid.NewGuid()}\";\n        var clusterOptions = new ClusterOptions { ServiceId = serviceId, ClusterId = clusterId + \"_1\" };\n        var clusterIdentifier = clusterOptions.ServiceId + \"-\" + clusterOptions.ClusterId;\n        var (membershipTable, gatewayProvider) = await CreateNewMembershipTableAsync(serviceId, clusterId + \"_1\");\n\n        var (otherMembershipTable, _) = await CreateNewMembershipTableAsync(serviceId, clusterId + \"_2\");\n\n        var tableData = await membershipTable.ReadAll();\n\n        await membershipTable.InsertRow(\n            new MembershipEntry\n            {\n                HostName = \"host1\",\n                IAmAliveTime = DateTime.UtcNow,\n                ProxyPort = 2345,\n                SiloAddress = SiloAddress.New(IPAddress.Loopback, 2345, 1),\n                SiloName = \"silo1\",\n                Status = SiloStatus.Created,\n                StartTime = DateTime.UtcNow\n            }, tableData.Version.Next());\n\n        tableData = await membershipTable.ReadAll();\n\n        await membershipTable.InsertRow(\n            new MembershipEntry\n            {\n                HostName = \"host1\",\n                IAmAliveTime = DateTime.UtcNow,\n                ProxyPort = 2345,\n                SiloAddress = SiloAddress.New(IPAddress.Loopback, 2345, 1),\n                SiloName = \"silo1\",\n                Status = SiloStatus.Joining,\n                StartTime = DateTime.UtcNow\n            }, tableData.Version.Next());\n\n        tableData = await otherMembershipTable.ReadAll();\n        await otherMembershipTable.InsertRow(\n            new MembershipEntry\n            {\n                HostName = \"host1\",\n                IAmAliveTime = DateTime.UtcNow,\n                ProxyPort = 2345,\n                SiloAddress = SiloAddress.New(IPAddress.Loopback, 2345, 1),\n                SiloName = \"silo1\",\n                Status = SiloStatus.Joining,\n                StartTime = DateTime.UtcNow\n            }, tableData.Version.Next());\n\n        tableData = await membershipTable.ReadAll();\n\n        var membershipEntry = new MembershipEntry\n        {\n            HostName = \"host1\",\n            IAmAliveTime = DateTime.UtcNow,\n            ProxyPort = 2345,\n            SiloAddress = SiloAddress.New(IPAddress.Loopback, 2346, 1),\n            SiloName = \"silo1\",\n            Status = SiloStatus.Active,\n            StartTime = DateTime.UtcNow\n        };\n        await membershipTable.InsertRow(membershipEntry, tableData.Version.Next());\n\n        var readAll = await membershipTable.ReadAll();\n\n        _testOutputHelper.WriteLine(readAll.Version.Version.ToString());\n        foreach (var row in readAll.Members)\n        {\n            var entry = row.Item1;\n            _testOutputHelper.WriteLine(clusterIdentifier);\n            _testOutputHelper.WriteLine(\"  \" + entry.HostName);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloName);\n            _testOutputHelper.WriteLine(\"  \" + entry.StartTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.IAmAliveTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloAddress);\n            _testOutputHelper.WriteLine(\"  \" + entry.ProxyPort);\n            _testOutputHelper.WriteLine(\"  \" + entry.Status);\n        }\n\n        membershipEntry.IAmAliveTime = DateTime.UtcNow + TimeSpan.FromSeconds(10);\n        await membershipTable.UpdateIAmAlive(membershipEntry);\n\n        readAll = await membershipTable.ReadAll();\n\n        _testOutputHelper.WriteLine(readAll.Version.Version.ToString());\n        foreach (var row in readAll.Members)\n        {\n            var entry = row.Item1;\n            _testOutputHelper.WriteLine(clusterIdentifier);\n            _testOutputHelper.WriteLine(\"  \" + entry.HostName);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloName);\n            _testOutputHelper.WriteLine(\"  \" + entry.StartTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.IAmAliveTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloAddress);\n            _testOutputHelper.WriteLine(\"  \" + entry.ProxyPort);\n            _testOutputHelper.WriteLine(\"  \" + entry.Status);\n        }\n\n        await gatewayProvider.InitializeGatewayListProvider();\n\n        _ = await gatewayProvider.GetGateways();\n        var gateways = await gatewayProvider.GetGateways();\n\n        foreach (var gateway in gateways)\n        {\n            _testOutputHelper.WriteLine(gateway.ToString());\n        }\n\n        var queriedEntry = await membershipTable.ReadRow(membershipEntry.SiloAddress);\n        foreach (var queriedEntryMember in queriedEntry.Members)\n        {\n            _testOutputHelper.WriteLine(queriedEntryMember.Item1.SiloAddress.ToParsableString());\n        }\n\n        await membershipTable.DeleteMembershipTableEntries(clusterOptions.ClusterId);\n\n        readAll = await membershipTable.ReadAll();\n\n        _testOutputHelper.WriteLine(readAll.Version.Version.ToString());\n        foreach (var row in readAll.Members)\n        {\n            var entry = row.Item1;\n            _testOutputHelper.WriteLine(clusterIdentifier);\n            _testOutputHelper.WriteLine(\"  \" + entry.HostName);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloName);\n            _testOutputHelper.WriteLine(\"  \" + entry.StartTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.IAmAliveTime);\n            _testOutputHelper.WriteLine(\"  \" + entry.SiloAddress);\n            _testOutputHelper.WriteLine(\"  \" + entry.ProxyPort);\n            _testOutputHelper.WriteLine(\"  \" + entry.Status);\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Cassandra.Tests/Clustering/CassandraContainer.cs",
    "content": "using System.Net;\nusing Cassandra;\nusing DotNet.Testcontainers.Builders;\nusing DotNet.Testcontainers.Containers;\n\nnamespace Tester.Cassandra.Clustering;\n\npublic class CassandraContainer\n{\n    public Task<(IContainer container, ushort exposedPort, Cluster cluster, ISession session)> RunImage() => _innerRunImage.Value;\n\n    private readonly Lazy<Task<(IContainer container, ushort exposedPort, Cluster cluster, ISession session)>> _innerRunImage =\n        new(async () =>\n        {\n            var containerPort = 9042;\n\n            var container = new ContainerBuilder(\"cassandra:\" + Environment.GetEnvironmentVariable(\"CASSANDRAVERSION\"))\n                    .WithPortBinding(containerPort, true)\n                    .WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(containerPort))\n                    .Build();\n\n            await container.StartAsync();\n\n            var exposedPort = container.GetMappedPublicPort(containerPort);\n\n            var cluster = Cluster.Builder()\n                .WithDefaultKeyspace(\"orleans\")\n                .AddContactPoints(new IPEndPoint(IPAddress.Loopback, exposedPort))\n                .Build();\n\n            // Connect to the nodes using a keyspace\n            var session =\n                cluster.ConnectAndCreateDefaultKeyspaceIfNotExists(ReplicationStrategies\n                    .CreateSimpleStrategyReplicationProperty(1));\n\n            return (container, exposedPort, cluster, session);\n        });\n\n    public string Name { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Cassandra.Tests/Clustering/SiloAddressUtils.cs",
    "content": "using System.Net;\nusing Orleans.Runtime;\n\nnamespace Tester.Cassandra.Clustering;\n\npublic static class SiloAddressUtils\n{\n    private static readonly IPEndPoint s_localEndpoint = new(IPAddress.Loopback, 0);\n\n    public static SiloAddress NewLocalSiloAddress(int gen)\n    {\n        return SiloAddress.New(s_localEndpoint, gen);\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Cassandra.Tests/Orleans.Clustering.Cassandra.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Testcontainers\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Cassandra\\Orleans.Clustering.Cassandra\\Orleans.Clustering.Cassandra.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Cassandra.Tests/Utility/TestExtensions.cs",
    "content": "namespace Tester.Cassandra.Utility\n{\n    public static class TestExtensions\n    {\n        public static async Task WithTimeout(this Task taskToComplete, TimeSpan timeout)\n        {\n            if (taskToComplete.IsCompleted)\n            {\n                await taskToComplete;\n                return;\n            }\n\n            using var timeoutCancellationTokenSource = new CancellationTokenSource();\n            var completedTask = await Task.WhenAny(taskToComplete, Task.Delay(timeout, timeoutCancellationTokenSource.Token));\n\n            if (taskToComplete == completedTask)\n            {\n                timeoutCancellationTokenSource.Cancel();\n                await taskToComplete;\n                return;\n            }\n\n            taskToComplete.Ignore();\n            throw new TimeoutException(string.Format(\"WithTimeout has timed out after {0}.\", timeout));\n        }\n\n        public static async Task<T> WithTimeout<T>(this Task<T> taskToComplete, TimeSpan timeout)\n        {\n            if (taskToComplete.IsCompleted)\n            {\n                return await taskToComplete;\n            }\n\n            using var timeoutCancellationTokenSource = new CancellationTokenSource();\n            var completedTask = await Task.WhenAny(taskToComplete, Task.Delay(timeout, timeoutCancellationTokenSource.Token));\n\n            if (taskToComplete == completedTask)\n            {\n                timeoutCancellationTokenSource.Cancel();\n                return await taskToComplete;\n            }\n\n            taskToComplete.Ignore();\n            throw new TimeoutException(string.Format(\"WithTimeout has timed out after {0}.\", timeout));\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace Consul.Tests\n{\n    // Assembly collections must be defined once in each assembly\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides Consul-specific test environment setup and resources.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/ConsulClusteringOptionsTests.cs",
    "content": "using Orleans.Configuration;\nusing Xunit;\n\nnamespace Consul.Tests\n{\n    public class ConsulClusteringOptionsTests\n    {\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Consul\")]\n        public void DefaultCreationBehaviorIsRetained()\n        {            \n            var options = new ConsulClusteringOptions();\n\n            // ensure we set a default value.\n            var actual = options.CreateClient;\n\n            Assert.NotNull(actual);\n        }       \n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Consul\")]\n        public void ThrowsArgumentNullExceptionIfCallbackIsNull()\n        {            \n            var  options = new ConsulClusteringOptions();\n            Func<IConsulClient> callback = null;\n\n            // ensure we check the callback.\n            void shouldThrow() => options.ConfigureConsulClient(callback);\n\n            Assert.Throws<ArgumentNullException>(shouldThrow);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Consul\")]\n        public void WeCanInjectAConsulClient()\n        {\n            var fakeConsul = new FakeConsul();\n            var options = new ConsulClusteringOptions();\n            IConsulClient callback() => fakeConsul;\n\n            //we can inject the consul\n            options.ConfigureConsulClient(callback);\n\n            var actual = options.CreateClient();\n            Assert.Equal(fakeConsul, actual);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Consul\")]\n        public void WeCanUseConfigureToSetupTheDefaultClient()\n        {\n            var address = new Uri(\"http://localhost:8501\");\n            var token = \"SomeToken\";\n\n            var options = new ConsulClusteringOptions();            \n\n            //we can configure the default consult client\n            options.ConfigureConsulClient(address, token);\n\n            var client = (ConsulClient) options.CreateClient();\n\n            Assert.Equal(address, client.Config.Address);\n            Assert.Equal(token, client.Config.Token);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Consul\")]\n        public void WeCanUseConfigureToSetupTheDefaultClientWithoutAAclToken()\n        {\n            var address = new Uri(\"http://localhost:8501\");           \n            var options = new ConsulClusteringOptions();\n\n            //we can configure the default consult client\n            options.ConfigureConsulClient(address);\n\n            var client = (ConsulClient)options.CreateClient();\n\n            Assert.Equal(address, client.Config.Address);\n            Assert.Null(client.Config.Token);\n        }\n\n        /// <summary>\n        /// Fake Client with no function.\n        /// </summary>\n        private class FakeConsul : IConsulClient\n        {\n            [Obsolete]\n            public IACLEndpoint ACL => throw new NotImplementedException();\n\n            public IPolicyEndpoint Policy => throw new NotImplementedException();\n\n            public IRoleEndpoint Role => throw new NotImplementedException();\n\n            public ITokenEndpoint Token => throw new NotImplementedException();\n\n            public IAgentEndpoint Agent => throw new NotImplementedException();\n\n            public ICatalogEndpoint Catalog => throw new NotImplementedException();\n\n            public Consul.Interfaces.IConfigurationEndpoint Configuration => throw new NotImplementedException();\n\n            public IEventEndpoint Event => throw new NotImplementedException();\n\n            public IHealthEndpoint Health => throw new NotImplementedException();\n\n            public IKVEndpoint KV => throw new NotImplementedException();\n\n            public IRawEndpoint Raw => throw new NotImplementedException();\n\n            public ISessionEndpoint Session => throw new NotImplementedException();\n\n            public IStatusEndpoint Status => throw new NotImplementedException();\n\n            public IOperatorEndpoint Operator => throw new NotImplementedException();\n\n            public IPreparedQueryEndpoint PreparedQuery => throw new NotImplementedException();\n\n            public ICoordinateEndpoint Coordinate => throw new NotImplementedException();\n\n            public ISnapshotEndpoint Snapshot => throw new NotImplementedException();\n\n            public Consul.Interfaces.IDiscoveryChainEndpoint DiscoveryChain => throw new NotImplementedException();\n\n            public Task<IDistributedLock> AcquireLock(LockOptions opts, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task<IDistributedLock> AcquireLock(string key, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task<IDistributedSemaphore> AcquireSemaphore(SemaphoreOptions opts, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task<IDistributedSemaphore> AcquireSemaphore(string prefix, int limit, CancellationToken ct = default) => throw new NotImplementedException();\n            public IDistributedLock CreateLock(LockOptions opts) => throw new NotImplementedException();\n            public IDistributedLock CreateLock(string key) => throw new NotImplementedException();\n            public void Dispose() => throw new NotImplementedException();\n            public Task ExecuteInSemaphore(SemaphoreOptions opts, Action a, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task ExecuteInSemaphore(string prefix, int limit, Action a, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task ExecuteLocked(LockOptions opts, Action action, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task ExecuteLocked(LockOptions opts, CancellationToken ct, Action action) => throw new NotImplementedException();\n            public Task ExecuteLocked(string key, Action action, CancellationToken ct = default) => throw new NotImplementedException();\n            public Task ExecuteLocked(string key, CancellationToken ct, Action action) => throw new NotImplementedException();\n            public IDistributedSemaphore Semaphore(SemaphoreOptions opts) => throw new NotImplementedException();\n            public IDistributedSemaphore Semaphore(string prefix, int limit) => throw new NotImplementedException();\n        }       \n    }\n}\n\n\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/ConsulMembershipTableTest.cs",
    "content": "using Orleans.Messaging;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.Membership;\nusing TestExtensions;\nusing UnitTests;\nusing UnitTests.MembershipTests;\nusing Xunit;\n\nnamespace Consul.Tests\n{\n    /// <summary>\n    /// Tests for operation of Orleans Membership Table using Consul - Requires access to external Consul cluster\n    /// \n    /// Consul provides a distributed key-value store that Orleans uses for:\n    /// - Cluster membership management\n    /// - Service discovery\n    /// - Health checking and failure detection\n    /// \n    /// These tests verify that the Consul-based membership provider correctly implements\n    /// all required membership table operations including:\n    /// - Reading and writing silo entries\n    /// - Updating liveness information (I Am Alive)\n    /// - Gateway discovery for clients\n    /// - Cleanup of defunct silo entries\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"Consul\")]\n    public class ConsulMembershipTableTest : MembershipTableTestsBase\n    {\n        public ConsulMembershipTableTest(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n        { \n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(\"ConsulBasedMembershipTable\", Microsoft.Extensions.Logging.LogLevel.Trace);\n            filters.AddFilter(\"Storage\", Microsoft.Extensions.Logging.LogLevel.Trace);\n            return filters;\n        }\n\n        /// <summary>\n        /// Creates a Consul-based membership table for testing.\n        /// Configures the Consul client with the test server address\n        /// and creates the membership table implementation.\n        /// </summary>\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            ConsulTestUtils.EnsureConsul();\n            var options = new ConsulClusteringOptions();\n            var address = new Uri(this.connectionString);\n\n            options.ConfigureConsulClient(address);\n            \n            return new ConsulBasedMembershipTable(loggerFactory.CreateLogger<ConsulBasedMembershipTable>(), Options.Create(options), this._clusterOptions);\n        }\n\n        /// <summary>\n        /// Creates a Consul-based gateway list provider for testing.\n        /// This provider allows clients to discover available gateways\n        /// by querying the Consul service registry.\n        /// </summary>\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            ConsulTestUtils.EnsureConsul();\n            var options = new ConsulClusteringOptions();\n            var address = new Uri(this.connectionString);\n\n            options.ConfigureConsulClient(address);\n            \n            return new ConsulGatewayListProvider(loggerFactory.CreateLogger<ConsulGatewayListProvider>(), Options.Create(options), this._gatewayOptions, this._clusterOptions);\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            return await ConsulTestUtils.EnsureConsulAsync() ? ConsulTestUtils.ConsulConnectionString : null;\n        }\n\n        /// <summary>\n        /// Tests gateway discovery through Consul.\n        /// Verifies that clients can retrieve the list of available\n        /// gateway silos from the Consul service registry.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        /// <summary>\n        /// Tests reading from an empty membership table.\n        /// Verifies that the provider correctly handles the case\n        /// when no silos have registered yet.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_InsertRow()\n        {\n            await MembershipTable_InsertRow(false);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read(false);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll(false);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_UpdateRow()\n        {\n            await MembershipTable_UpdateRow(false);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel(false);\n        }\n\n        /// <summary>\n        /// Tests the \"I Am Alive\" heartbeat mechanism.\n        /// Verifies that silos can update their liveness timestamp\n        /// in Consul to indicate they are still running.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive(false);\n        }\n\n        /// <summary>\n        /// Tests cleanup of dead silo entries.\n        /// Verifies that the membership table can remove entries\n        /// for silos that have been declared dead to prevent\n        /// the table from growing indefinitely.\n        /// </summary>\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task MembershipTable_Consul_CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries(false);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/ConsulTestUtils.cs",
    "content": "using Docker.DotNet;\nusing DotNet.Testcontainers.Configurations;\nusing Testcontainers.Consul;\nusing Xunit;\n\nnamespace Consul.Tests\n{\n    /// <summary>\n    /// Utility class for Consul test setup and connection verification.\n    /// </summary>\n    public static class ConsulTestUtils\n    {\n        private const string DockerUnavailableSkipReason = \"Docker is unavailable, so Consul tests are skipped.\";\n\n        private const string WindowsDockerModeSkipReason = \"Docker is running in Windows container mode (OSType=windows), so Consul tests are skipped.\";\n\n        private static readonly Lazy<string> DockerDaemonOsTypeLazy = new(GetDockerDaemonOsType);\n\n        private static readonly Lazy<string> EnsureConsulSkipReasonLazy = new(() => EnsureConsulAndGetSkipReasonAsync().GetAwaiter().GetResult());\n\n        private static readonly ConsulContainer _container = new ConsulBuilder(\"public.ecr.aws/hashicorp/consul:1.19\")\n            .WithCreateParameterModifier(parameters =>\n            {\n                if (parameters.HostConfig is not null && !IsWindowsDockerDaemon())\n                {\n                    parameters.HostConfig.CapAdd = [\"IPC_LOCK\"];\n                }\n            })\n            .Build();\n\n        public static string ConsulConnectionString\n        {\n            get\n            {\n                EnsureConsul();\n                return _container.GetBaseAddress();\n            }\n        }\n\n        public static void EnsureConsul()\n        {\n            var skipReason = EnsureConsulSkipReasonLazy.Value;\n            if (skipReason is not null)\n                throw new SkipException(skipReason);\n        }\n\n        public static Task<bool> EnsureConsulAsync()\n        {\n            return Task.FromResult(EnsureConsulSkipReasonLazy.Value is null);\n        }\n\n        private static async Task<string> EnsureConsulAndGetSkipReasonAsync()\n        {\n            var skipReason = GetDockerSkipReason();\n            if (skipReason is not null)\n            {\n                return skipReason;\n            }\n\n            try\n            {\n                await _container.StartAsync();\n                return null;\n            }\n            catch (HttpRequestException)\n            {\n                return DockerUnavailableSkipReason;\n            }\n            catch (OperationCanceledException)\n            {\n                return DockerUnavailableSkipReason;\n            }\n        }\n\n        private static string GetDockerSkipReason()\n        {\n            var dockerDaemonOsType = DockerDaemonOsTypeLazy.Value;\n            if (string.IsNullOrWhiteSpace(dockerDaemonOsType))\n            {\n                return DockerUnavailableSkipReason;\n            }\n\n            if (string.Equals(dockerDaemonOsType, \"windows\", StringComparison.OrdinalIgnoreCase))\n            {\n                return WindowsDockerModeSkipReason;\n            }\n\n            return null;\n        }\n\n        private static bool IsWindowsDockerDaemon()\n        {\n            return string.Equals(DockerDaemonOsTypeLazy.Value, \"windows\", StringComparison.OrdinalIgnoreCase);\n        }\n\n        private static string GetDockerDaemonOsType()\n        {\n            try\n            {\n                using var dockerClient = TestcontainersSettings.OS.DockerEndpointAuthConfig\n                    .GetDockerClientConfiguration(Guid.NewGuid())\n                    .CreateClient();\n                var dockerInfo = dockerClient.System.GetSystemInfoAsync().GetAwaiter().GetResult();\n                return dockerInfo.OSType;\n            }\n            catch (HttpRequestException)\n            {\n                return null;\n            }\n            catch (OperationCanceledException)\n            {\n                return null;\n            }\n            catch (DockerApiException)\n            {\n                return null;\n            }\n            catch (InvalidOperationException)\n            {\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/LivenessTests.cs",
    "content": "using Orleans.TestingHost;\nusing Microsoft.Extensions.Configuration;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Consul.Tests\n{\n    /// <summary>\n    /// Tests Orleans cluster liveness functionality using Consul as the membership provider.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"Consul\")]\n    public class LivenessTests_Consul : LivenessTestsBase\n    {\n        public LivenessTests_Consul(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            ConsulTestUtils.EnsureConsul();\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseConsulSiloClustering(options =>\n                {\n                    var address = new Uri(ConsulTestUtils.ConsulConnectionString);\n                    options.ConfigureConsulClient(address);\n                });\n            }\n        }\n\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .UseConsulClientClustering(gatewayOptions =>\n                    {\n                        var address = new Uri(ConsulTestUtils.ConsulConnectionString);\n                        gatewayOptions.ConfigureConsulClient(address);\n                    });\n            }\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Consul_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Consul_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Consul_3_Restart_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Consul_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\")]\n        public async Task Liveness_Consul_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/Orleans.Clustering.Consul.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Testcontainers.Consul\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Clustering.Consul\\Orleans.Clustering.Consul.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.Consul.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace Tester.ZooKeeperUtils\n{\n    // Assembly collections must be defined once in each assembly\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides ZooKeeper-specific test environment setup and resources.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/LivenessTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.ZooKeeperUtils\n{\n    [TestCategory(\"Membership\"), TestCategory(\"ZooKeeper\")]\n    public class LivenessTests_ZK : LivenessTestsBase\n    {\n        public LivenessTests_ZK(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            ZookeeperTestUtils.EnsureZooKeeper();\n\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseZooKeeperClustering(options => { options.ConnectionString = TestDefaultConfiguration.ZooKeeperConnectionString; });\n            }\n        }\n\n        [SkippableFact]\n        public async Task Liveness_ZooKeeper_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [SkippableFact]\n        public async Task Liveness_ZooKeeper_2_Restart_Primary()\n        {\n            await Do_Liveness_OracleTest_2(0);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_ZooKeeper_3_Restart_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_ZooKeeper_4_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [SkippableFact]\n        public async Task Liveness_ZooKeeper_5_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/Orleans.Clustering.ZooKeeper.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Clustering.ZooKeeper\\Orleans.Clustering.ZooKeeper.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZookeeperMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Messaging;\nusing Orleans.Runtime.Membership;\nusing Orleans.Configuration;\nusing TestExtensions;\nusing Xunit;\nusing Tester.ZooKeeperUtils;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for operation of Orleans SiloInstanceManager using ZookeeperStore - Requires access to external Zookeeper storage\n    /// \n    /// Apache ZooKeeper provides a hierarchical namespace for distributed coordination.\n    /// Orleans uses ZooKeeper for:\n    /// - Distributed membership management using znodes (ZooKeeper nodes)\n    /// - Leader election and distributed consensus\n    /// - Ephemeral nodes for automatic cleanup on silo failure\n    /// - Watch notifications for membership changes\n    /// \n    /// These tests verify the ZooKeeper-based membership provider handles all\n    /// membership operations correctly, including node failures and network partitions.\n    /// </summary>\n    [TestCategory(\"Membership\"), TestCategory(\"ZooKeeper\")]\n    public class ZookeeperMembershipTableTests : MembershipTableTestsBase\n    {\n        public ZookeeperMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment)\n            : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(typeof(ZookeeperMembershipTableTests).Name, LogLevel.Trace);\n            return filters;\n        }\n\n        /// <summary>\n        /// Creates a ZooKeeper-based membership table for testing.\n        /// Configures the ZooKeeper connection and creates the membership\n        /// table that uses ZooKeeper's hierarchical namespace for storage.\n        /// </summary>\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            var options = new ZooKeeperClusteringSiloOptions();\n            options.ConnectionString = this.connectionString;\n           \n            return new ZooKeeperBasedMembershipTable(this.Services.GetService<ILogger<ZooKeeperBasedMembershipTable>>(), Options.Create(options), this._clusterOptions);\n        }\n\n        /// <summary>\n        /// Creates a ZooKeeper-based gateway list provider.\n        /// This provider uses ZooKeeper watches to maintain an up-to-date\n        /// list of available gateways for client connections.\n        /// </summary>\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            var options = new ZooKeeperGatewayListProviderOptions();\n            options.ConnectionString = this.connectionString;\n\n            return ActivatorUtilities.CreateInstance<ZooKeeperGatewayListProvider>(this.Services, Options.Create(options), this._clusterOptions);\n        }\n\n        protected override async Task<string> GetConnectionString()\n        {\n            bool isReachable = await ZookeeperTestUtils.EnsureZooKeeperAsync();\n            return isReachable ? TestDefaultConfiguration.ZooKeeperConnectionString : null;\n        }\n\n        [SkippableFact]\n        public void MembershipTable_ZooKeeper_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        /// <summary>\n        /// Tests inserting a silo entry as a ZooKeeper znode.\n        /// Verifies that the membership data is correctly serialized\n        /// and stored in ZooKeeper's hierarchical structure.\n        /// </summary>\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        /// <summary>\n        /// Tests concurrent updates using ZooKeeper's versioning.\n        /// Verifies that ZooKeeper's optimistic concurrency control\n        /// correctly handles simultaneous updates from multiple silos.\n        /// </summary>\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel();\n        }\n\n        /// <summary>\n        /// Tests heartbeat updates using ZooKeeper.\n        /// Verifies that ephemeral nodes and session timeouts\n        /// work correctly for detecting failed silos.\n        /// </summary>\n        [SkippableFact]\n        public async Task MembershipTable_ZooKeeper_UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZookeeperTestUtils.cs",
    "content": "using org.apache.zookeeper;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.ZooKeeperUtils\n{\n    public static class ZookeeperTestUtils\n    {\n        private static readonly Lazy<bool> EnsureZooKeeperLazy = new Lazy<bool>(() => EnsureZooKeeperAsync().Result);\n\n        public static void EnsureZooKeeper()\n        {\n            if (!EnsureZooKeeperLazy.Value)\n                throw new SkipException(\"ZooKeeper isn't running\");\n        }\n\n        public static async Task<bool> EnsureZooKeeperAsync()\n        {\n            var connectionString = TestDefaultConfiguration.ZooKeeperConnectionString;\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                return false;\n            }\n\n            return await ZooKeeper.Using(connectionString, 2000, new ZooKeeperWatcher(), async zk =>\n            {\n                try\n                {\n                    await zk.existsAsync(\"/test\", false);\n                    return true;\n                }\n                catch (KeeperException.ConnectionLossException)\n                {\n                    return false;\n                }\n            });\n        }\n\n        private class ZooKeeperWatcher : Watcher\n        {\n            public override Task process(WatchedEvent @event) => Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/CollectionFixtures.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace Consul.Cosmos\n{\n    // Assembly collections must be defined once in each assembly\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides Azure Cosmos DB specific test environment setup and resources.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/CosmosMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing TestExtensions;\nusing UnitTests.MembershipTests;\nusing Orleans.Messaging;\nusing Orleans.Clustering.Cosmos;\nusing UnitTests;\n\nnamespace Tester.Cosmos.Clustering;\n\n/// <summary>\n/// Tests for operation of Orleans Membership Table using Azure Cosmos DB - Requires access to external Azure Cosmos DB account\n/// \n/// Azure Cosmos DB provides a globally distributed, multi-model database service that Orleans can use for cluster membership\n/// management.\n/// \n/// These tests verify the Cosmos DB membership provider correctly implements\n/// all membership operations with Cosmos DB's unique features like:\n/// - Document-based storage with SQL querying\n/// - Optimistic concurrency using ETags\n/// - Partition key strategies for cluster isolation\n/// </summary>\n[TestCategory(\"Membership\"), TestCategory(\"Cosmos\")]\npublic class CosmosMembershipTableTests : MembershipTableTestsBase\n{\n    public CosmosMembershipTableTests(ConnectionStringFixture fixture, TestEnvironmentFixture environment) : base(fixture, environment, CreateFilters())\n    {\n    }\n\n    private static LoggerFilterOptions CreateFilters()\n    {\n        var filters = new LoggerFilterOptions();\n        filters.AddFilter(typeof(CosmosMembershipTable).FullName, LogLevel.Trace);\n        filters.AddFilter(\"Orleans.Storage\", LogLevel.Trace);\n        return filters;\n    }\n\n    /// <summary>\n    /// Creates a Cosmos DB-based membership table for testing.\n    /// Configures the Cosmos DB client with test-specific settings\n    /// including database/container names and consistency levels.\n    /// </summary>\n    protected override IMembershipTable CreateMembershipTable(ILogger logger)\n    {\n        CosmosTestUtils.CheckCosmosStorage();\n        var options = new CosmosClusteringOptions();\n        options.ConfigureTestDefaults();\n        return new CosmosMembershipTable(loggerFactory, Services, Options.Create(options), _clusterOptions);\n    }\n\n    /// <summary>\n    /// Creates a Cosmos DB-based gateway list provider.\n    /// Uses Cosmos DB's querying capabilities to efficiently\n    /// retrieve available gateway silos for client connections.\n    /// </summary>\n    protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n    {\n        var options = new CosmosClusteringOptions();\n        options.ConfigureTestDefaults();\n        return new CosmosGatewayListProvider(loggerFactory, Services, Options.Create(options), _clusterOptions, _gatewayOptions);\n    }\n\n    protected override Task<string> GetConnectionString()\n    {\n        return Task.FromResult(TestDefaultConfiguration.CosmosDBAccountKey);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public void MembershipTable_Cosmos_Init()\n    {\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_GetGateways()\n    {\n        await MembershipTable_GetGateways();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_ReadAll_EmptyTable()\n    {\n        await MembershipTable_ReadAll_EmptyTable();\n    }\n\n    /// <summary>\n    /// Tests inserting a silo entry as a Cosmos DB document.\n    /// Verifies document creation with proper partition key assignment\n    /// and automatic indexing for efficient queries.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_InsertRow()\n    {\n        await MembershipTable_InsertRow();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_ReadRow_Insert_Read()\n    {\n        await MembershipTable_ReadRow_Insert_Read();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_ReadAll_Insert_ReadAll()\n    {\n        await MembershipTable_ReadAll_Insert_ReadAll();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_UpdateRow()\n    {\n        await MembershipTable_UpdateRow();\n    }\n\n    /// <summary>\n    /// Tests concurrent updates using Cosmos DB's ETag-based concurrency.\n    /// Verifies that optimistic concurrency control prevents\n    /// conflicting updates and ensures data consistency.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_UpdateRowInParallel()\n    {\n        await MembershipTable_UpdateRowInParallel();\n    }\n\n    /// <summary>\n    /// Tests heartbeat updates in Cosmos DB.\n    /// Verifies efficient partial document updates for liveness\n    /// information without rewriting entire membership entries.\n    /// </summary>\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task MembershipTable_Cosmos_UpdateIAmAlive()\n    {\n        await MembershipTable_UpdateIAmAlive();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/CosmosOptionsExtensions.cs",
    "content": "using Azure.Identity;\nusing Microsoft.Azure.Cosmos;\nusing Orleans.Clustering.Cosmos;\nusing Orleans.Persistence.Cosmos;\nusing Orleans.Reminders.Cosmos;\nusing TestExtensions;\n\nnamespace Tester.Cosmos;\n\npublic static class CosmosOptionsExtensions\n{\n    public static void ConfigureTestDefaults(this CosmosClusteringOptions options)\n    {\n        if (TestDefaultConfiguration.UseAadAuthentication)\n        {\n            options.ConfigureCosmosClient(TestDefaultConfiguration.CosmosDBAccountEndpoint, TestDefaultConfiguration.TokenCredential);\n        }\n        else\n        {\n            options.ConfigureCosmosClient(GetCosmosClientUsingAccountKey());\n        }\n\n        options.IsResourceCreationEnabled = true;\n    }\n\n    public static void ConfigureTestDefaults(this CosmosGrainStorageOptions options)\n    {\n        if (TestDefaultConfiguration.UseAadAuthentication)\n        {\n            options.ConfigureCosmosClient(TestDefaultConfiguration.CosmosDBAccountEndpoint, TestDefaultConfiguration.TokenCredential);\n        }\n        else\n        {\n            options.ConfigureCosmosClient(GetCosmosClientUsingAccountKey());\n        }\n\n        options.IsResourceCreationEnabled = true;\n    }\n\n    public static void ConfigureTestDefaults(this CosmosReminderTableOptions options)\n    {\n        if (TestDefaultConfiguration.UseAadAuthentication)\n        {\n            options.ConfigureCosmosClient(TestDefaultConfiguration.CosmosDBAccountEndpoint, TestDefaultConfiguration.TokenCredential);\n        }\n        else\n        {\n            options.ConfigureCosmosClient(GetCosmosClientUsingAccountKey());\n        }\n\n        options.IsResourceCreationEnabled = true;\n    }\n\n    private static Func<IServiceProvider, ValueTask<CosmosClient>> GetCosmosClientUsingAccountKey()\n    {\n        return _ =>\n        {\n            var cosmosClientOptions = new CosmosClientOptions()\n            {\n                HttpClientFactory = () =>\n                {\n                    HttpMessageHandler httpMessageHandler = new HttpClientHandler()\n                    {\n                        ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator\n                    };\n\n                    return new HttpClient(httpMessageHandler);\n                },\n\n                ConnectionMode = ConnectionMode.Gateway\n            };\n\n            return new(new CosmosClient(TestDefaultConfiguration.CosmosDBAccountEndpoint, TestDefaultConfiguration.CosmosDBAccountKey, cosmosClientOptions));\n        };\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/CosmosTestUtils.cs",
    "content": "using TestExtensions;\n\nnamespace Tester.Cosmos;\n\npublic class CosmosTestUtils\n{\n    public static void CheckCosmosStorage()\n    {\n        if (string.IsNullOrWhiteSpace(TestDefaultConfiguration.CosmosDBAccountEndpoint)\n            || string.IsNullOrWhiteSpace(TestDefaultConfiguration.CosmosDBAccountKey))\n        {\n            throw new SkipException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/Orleans.Cosmos.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Azure\\Orleans.Reminders.Cosmos\\Orleans.Reminders.Cosmos.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Azure\\Orleans.Clustering.Cosmos\\Orleans.Clustering.Cosmos.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Azure\\Orleans.Persistence.Cosmos\\Orleans.Persistence.Cosmos.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/PersistenceGrainTests_CosmosGrainStorage.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Xunit.Abstractions;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.Options;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing TestExtensions.Runners;\n\nnamespace Tester.Cosmos.Persistence;\n\n/// <summary>\n/// PersistenceGrainTests using Cosmos DB - Requires access to Cosmos DB\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"Cosmos\")]\npublic class PersistenceGrainTests_CosmosGrainStorage : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_CosmosGrainStorage.Fixture>\n{\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddCosmosGrainStorage(\"GrainStorageForTest\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                    }))\n                    .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            CosmosTestUtils.CheckCosmosStorage();\n        }\n    }\n\n    public PersistenceGrainTests_CosmosGrainStorage(ITestOutputHelper output, Fixture fixture, string grainNamespace = \"UnitTests.Grains\")\n        : base(output, fixture, grainNamespace)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n\n[TestCategory(\"Persistence\"), TestCategory(\"Cosmos\")]\npublic class PersistenceGrainTests_CosmosGrainStorage_DeleteStateOnClear : GrainPersistenceTestsRunner, IClassFixture<PersistenceGrainTests_CosmosGrainStorage_DeleteStateOnClear.Fixture>\n{\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddCosmosGrainStorage(\"GrainStorageForTest\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                    {\n                        options.ConfigureTestDefaults();\n                        options.DeleteStateOnClear = true;\n                    }))\n                    .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            CosmosTestUtils.CheckCosmosStorage();\n        }\n    }\n\n    public PersistenceGrainTests_CosmosGrainStorage_DeleteStateOnClear(ITestOutputHelper output, Fixture fixture, string grainNamespace = \"UnitTests.Grains\")\n        : base(output, fixture, grainNamespace)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/PersistenceProviderTests_Cosmos.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing System.Text.Json.Serialization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit.Abstractions;\nusing TestExtensions;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.Providers;\nusing Orleans.Configuration;\nusing Orleans.Persistence.Cosmos;\nusing UnitTests.Persistence;\nusing Microsoft.Extensions.Options;\n\nnamespace Tester.Cosmos.Persistence;\n\n/// <summary>\n/// Tests for Orleans grain state persistence operations using Azure Cosmos DB as the storage provider.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"Persistence\"), TestCategory(\"Cosmos\")]\npublic class PersistenceProviderTests_Cosmos\n{\n    private readonly IProviderRuntime providerRuntime;\n    private readonly Dictionary<string, string> providerCfgProps = new Dictionary<string, string>();\n    private readonly ITestOutputHelper output;\n    private readonly TestEnvironmentFixture fixture;\n    private readonly string _clusterId;\n    private readonly string _serviceId;\n\n    public PersistenceProviderTests_Cosmos(ITestOutputHelper output, TestEnvironmentFixture fixture)\n    {\n        CosmosTestUtils.CheckCosmosStorage();\n\n        this.output = output;\n        this.fixture = fixture;\n        providerRuntime = new ClientProviderRuntime(\n            fixture.InternalGrainFactory,\n            fixture.Services,\n            fixture.Services.GetRequiredService<ClientGrainContext>());\n        providerCfgProps.Clear();\n        _clusterId = Guid.NewGuid().ToString(\"N\");\n        _serviceId = Guid.NewGuid().ToString(\"N\");\n    }\n\n    private async Task<CosmosGrainStorage> InitializeStorage()\n    {\n        var options = new CosmosGrainStorageOptions();\n\n        options.ConfigureTestDefaults();\n\n        var pkProvider = new DefaultPartitionKeyProvider();\n        var clusterOptions = Options.Create(new ClusterOptions { ClusterId = _clusterId, ServiceId = _serviceId });\n\n        var store = ActivatorUtilities.CreateInstance<CosmosGrainStorage>(providerRuntime.ServiceProvider, options, clusterOptions, \"TestStorage\", pkProvider);\n        var lifecycle = ActivatorUtilities.CreateInstance<SiloLifecycleSubject>(providerRuntime.ServiceProvider);\n        store.Participate(lifecycle);\n        await lifecycle.OnStart();\n        return store;\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task PersistenceProvider_Azure_Read()\n    {\n        const string testName = nameof(PersistenceProvider_Azure_Read);\n\n        var store = await InitializeStorage();\n        await Test_PersistenceProvider_Read(testName, store, null, grainId: GrainId.Create(\"testgrain\", Guid.NewGuid().ToString()));\n    }\n\n    [SkippableTheory, TestCategory(\"Functional\")]\n    [InlineData(null)]\n    [InlineData(15 * 64 * 1024 - 256)]\n    [InlineData(15 * 32 * 1024 - 256)]\n    public async Task PersistenceProvider_Azure_WriteRead(int? stringLength)\n    {\n        var testName = string.Format(\"{0}({1} = {2})\",\n            nameof(PersistenceProvider_Azure_WriteRead),\n            nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString());\n\n        var grainState = TestStoreGrainState.NewRandomState(stringLength);\n\n        var store = await InitializeStorage();\n\n        await Test_PersistenceProvider_WriteRead(testName, store, grainState, GrainId.Create(\"testgrain\", Guid.NewGuid().ToString()));\n    }\n\n    [SkippableTheory, TestCategory(\"Functional\")]\n    [InlineData(null)]\n    [InlineData(15 * 64 * 1024 - 256)]\n    [InlineData(15 * 32 * 1024 - 256)]\n    public async Task PersistenceProvider_Azure_WriteClearRead(int? stringLength)\n    {\n        var testName = string.Format(\"{0}({1} = {2})\",\n            nameof(PersistenceProvider_Azure_WriteClearRead),\n            nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString());\n\n        var grainState = TestStoreGrainState.NewRandomState(stringLength);\n\n        var store = await InitializeStorage();\n\n        await Test_PersistenceProvider_WriteClearRead(testName, store, grainState);\n    }\n\n    [SkippableTheory, TestCategory(\"Functional\")]\n    [InlineData(null)]\n    [InlineData(15 * 32 * 1024 - 256)]\n    public async Task PersistenceProvider_Azure_ChangeReadFormat(int? stringLength)\n    {\n        var testName = string.Format(\"{0}({1} = {2})\",\n            nameof(PersistenceProvider_Azure_ChangeReadFormat),\n            nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString());\n\n        var grainState = TestStoreGrainState.NewRandomState(stringLength);\n        var grainId = GrainId.Create(\"testgrain\", Guid.NewGuid().ToString());\n\n        var store = await InitializeStorage();\n\n        grainState = await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n\n        store = await InitializeStorage();\n\n        await Test_PersistenceProvider_Read(testName, store, grainState, grainId);\n    }\n\n    [SkippableTheory, TestCategory(\"Functional\")]\n    [InlineData(null)]\n    [InlineData(15 * 32 * 1024 - 256)]\n    public async Task PersistenceProvider_Azure_ChangeWriteFormat(int? stringLength)\n    {\n        var testName = string.Format(\"{0}({1}={2})\",\n            nameof(PersistenceProvider_Azure_ChangeWriteFormat),\n            nameof(stringLength), stringLength == null ? \"default\" : stringLength.ToString());\n\n        var grainState = TestStoreGrainState.NewRandomState(stringLength);\n\n        var grainId = GrainId.Create(\"testgrain\", Guid.NewGuid().ToString());\n\n        var store = await InitializeStorage();\n\n        await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n\n        grainState = TestStoreGrainState.NewRandomState(stringLength);\n        grainState.ETag = \"*\";\n\n        store = await InitializeStorage();\n\n        await Test_PersistenceProvider_WriteRead(testName, store, grainState, grainId);\n    }\n\n    private async Task Test_PersistenceProvider_Read(string grainTypeName, IGrainStorage store, GrainState<TestStoreGrainState> grainState, GrainId grainId)\n    {\n        grainState ??= new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n\n        var storedGrainState = new GrainState<TestStoreGrainState>(new TestStoreGrainState());\n\n        Stopwatch sw = new Stopwatch();\n        sw.Start();\n\n        await store.ReadStateAsync(grainTypeName, grainId, storedGrainState);\n\n        TimeSpan readTime = sw.Elapsed;\n        output.WriteLine(\"{0} - Read time = {1}\", store.GetType().FullName, readTime);\n\n        var storedState = storedGrainState.State;\n        Assert.Equal(grainState.State.A, storedState.A);\n        Assert.Equal(grainState.State.B, storedState.B);\n        Assert.Equal(grainState.State.C, storedState.C);\n    }\n\n    private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteRead(string grainTypeName,\n        IGrainStorage store, GrainState<TestStoreGrainState> grainState, GrainId grainId)\n    {\n        grainState ??= TestStoreGrainState.NewRandomState();\n\n        Stopwatch sw = new Stopwatch();\n        sw.Start();\n\n        await store.WriteStateAsync(grainTypeName, grainId, grainState);\n\n        TimeSpan writeTime = sw.Elapsed;\n        sw.Restart();\n\n        var storedGrainState = new GrainState<TestStoreGrainState>\n        {\n            State = new TestStoreGrainState()\n        };\n        await store.ReadStateAsync(grainTypeName, grainId, storedGrainState);\n        TimeSpan readTime = sw.Elapsed;\n        output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n        Assert.Equal(grainState.State.A, storedGrainState.State.A);\n        Assert.Equal(grainState.State.B, storedGrainState.State.B);\n        Assert.Equal(grainState.State.C, storedGrainState.State.C);\n\n        return storedGrainState;\n    }\n\n    private async Task<GrainState<TestStoreGrainState>> Test_PersistenceProvider_WriteClearRead(string grainTypeName,\n        IGrainStorage store, GrainState<TestStoreGrainState> grainState = null, GrainId grainId = default)\n    {\n        grainId = fixture.InternalGrainFactory.GetGrain(grainId.IsDefault ? LegacyGrainId.NewId().ToGrainId() : grainId).GetGrainId();\n\n        if (grainState == null)\n        {\n            grainState = TestStoreGrainState.NewRandomState();\n        }\n\n        Stopwatch sw = new Stopwatch();\n        sw.Start();\n\n        await store.WriteStateAsync(grainTypeName, grainId, grainState);\n\n        TimeSpan writeTime = sw.Elapsed;\n        sw.Restart();\n\n        await store.ClearStateAsync(grainTypeName, grainId, grainState);\n\n        var storedGrainState = new GrainState<TestStoreGrainState>\n        {\n            State = new TestStoreGrainState()\n        };\n        await store.ReadStateAsync(grainTypeName, grainId, storedGrainState);\n        TimeSpan readTime = sw.Elapsed;\n        output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n        Assert.NotNull(storedGrainState.State);\n        Assert.Equal(default, storedGrainState.State.A);\n        Assert.Equal(default, storedGrainState.State.B);\n        Assert.Equal(default, storedGrainState.State.C);\n\n        return storedGrainState;\n    }\n\n    public class TestStoreGrainStateWithCustomJsonProperties\n    {\n        [JsonPropertyName(\"s\")]\n        public string String { get; set; }\n\n        internal static GrainState<TestStoreGrainStateWithCustomJsonProperties> NewRandomState(int? aPropertyLength = null)\n        {\n            return new GrainState<TestStoreGrainStateWithCustomJsonProperties>\n            {\n                State = new TestStoreGrainStateWithCustomJsonProperties\n                {\n                    String = aPropertyLength == null\n                        ? Random.Shared.Next().ToString(CultureInfo.InvariantCulture)\n                        : GenerateRandomDigitString(aPropertyLength.Value)\n                }\n            };\n        }\n\n        private static string GenerateRandomDigitString(int stringLength)\n        {\n            var characters = new char[stringLength];\n            for (var i = 0; i < stringLength; ++i)\n            {\n                characters[i] = (char)Random.Shared.Next('0', '9' + 1);\n            }\n            return new string(characters);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/ReminderTests_Cosmos.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Internal;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.TimerTests;\nusing UnitTests.GrainInterfaces;\n\nnamespace Tester.Cosmos.Reminders;\n\n/// <summary>\n/// Tests for Orleans reminders functionality using Azure Cosmos DB as the reminder service backing store.\n/// </summary>\n[TestCategory(\"Reminders\"), TestCategory(\"Cosmos\")]\npublic class ReminderTests_Cosmos : ReminderTests_Base, IClassFixture<ReminderTests_Cosmos.Fixture>\n{\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow() => CosmosTestUtils.CheckCosmosStorage();\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n    }\n\n    public class SiloConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder.UseCosmosReminderService(options =>\n            {\n                options.ConfigureTestDefaults();\n            });\n        }\n    }\n\n    public ReminderTests_Cosmos(Fixture fixture) : base(fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n    }\n\n    // Basic tests\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Basic_StopByRef()\n    {\n        await Test_Reminders_Basic_StopByRef();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Basic_ListOps()\n    {\n        await Test_Reminders_Basic_ListOps();\n    }\n\n    // Single join tests ... multi grain, multi reminders\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_1J_MultiGrainMultiReminders()\n    {\n        await Test_Reminders_1J_MultiGrainMultiReminders();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_ReminderNotFound()\n    {\n        await Test_Reminders_ReminderNotFound();\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Basic()\n    {\n        // start up a test grain and get the period that it's programmed to use.\n        IReminderTestGrain2 grain = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        TimeSpan period = await grain.GetReminderPeriod(DR);\n        // start up the 'DR' reminder and wait for two ticks to pass.\n        await grain.StartReminder(DR);\n        Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n                                                   // retrieve the value of the counter-- it should match the sequence number which is the number of periods\n                                                   // we've waited.\n        long last = await grain.GetCounter(DR);\n        Assert.Equal(2, last);\n        // stop the timer and wait for a whole period.\n        await grain.StopReminder(DR);\n        Thread.Sleep(period.Multiply(1) + LEEWAY); // giving some leeway\n                                                   // the counter should not have changed.\n        long curr = await grain.GetCounter(DR);\n        Assert.Equal(last, curr);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Basic_Restart()\n    {\n        IReminderTestGrain2 grain = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        TimeSpan period = await grain.GetReminderPeriod(DR);\n        await grain.StartReminder(DR);\n        Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n        long last = await grain.GetCounter(DR);\n        Assert.Equal(2, last);\n\n        await grain.StopReminder(DR);\n        TimeSpan sleepFor = period.Multiply(1) + LEEWAY;\n        Thread.Sleep(sleepFor); // giving some leeway\n        long curr = await grain.GetCounter(DR);\n        Assert.Equal(last, curr);\n        AssertIsInRange(curr, last, last + 1, grain, DR, sleepFor);\n\n        // start the same reminder again\n        await grain.StartReminder(DR);\n        sleepFor = period.Multiply(2) + LEEWAY;\n        Thread.Sleep(sleepFor); // giving some leeway\n        curr = await grain.GetCounter(DR);\n        AssertIsInRange(curr, 2, 3, grain, DR, sleepFor);\n        await grain.StopReminder(DR); // cleanup\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_MultipleReminders()\n    {\n        IReminderTestGrain2 grain = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        await PerGrainMultiReminderTest(grain);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_2J_MultiGrainMultiReminders()\n    {\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g2 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g3 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g4 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g5 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n        TimeSpan period = await g1.GetReminderPeriod(DR);\n\n        Task<bool>[] tasks =\n        {\n                Task.Run(() => PerGrainMultiReminderTestChurn(g1)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g2)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g3)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g4)),\n                Task.Run(() => PerGrainMultiReminderTestChurn(g5)),\n            };\n\n        await Task.Delay(period.Multiply(5));\n\n        // start two extra silos ... although it will take it a while before they stabilize\n        log.LogInformation(\"Starting 2 extra silos\");\n\n        await HostedCluster.StartAdditionalSilosAsync(2, true);\n        await HostedCluster.WaitForLivenessToStabilizeAsync();\n\n        //Block until all tasks complete.\n        await Task.WhenAll(tasks).WaitAsync(ENDWAIT);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_MultiGrainMultiReminders()\n    {\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g2 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g3 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g4 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g5 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n        Task<bool>[] tasks =\n        {\n                Task.Run(() => PerGrainMultiReminderTest(g1)),\n                Task.Run(() => PerGrainMultiReminderTest(g2)),\n                Task.Run(() => PerGrainMultiReminderTest(g3)),\n                Task.Run(() => PerGrainMultiReminderTest(g4)),\n                Task.Run(() => PerGrainMultiReminderTest(g5)),\n            };\n\n        //Block until all tasks complete.\n        await Task.WhenAll(tasks).WaitAsync(ENDWAIT);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_1F_Basic()\n    {\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n        TimeSpan period = await g1.GetReminderPeriod(DR);\n\n        Task<bool> test = Task.Run(async () => { await PerGrainFailureTest(g1); return true; });\n\n        Thread.Sleep(period.Multiply(failAfter));\n        // stop the secondary silo\n        log.LogInformation(\"Stopping secondary silo\");\n        await HostedCluster.StopSiloAsync(HostedCluster.SecondarySilos.First());\n\n        await test; // Block until test completes.\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_2F_MultiGrain()\n    {\n        List<SiloHandle> silos = await HostedCluster.StartAdditionalSilosAsync(2, true);\n\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g2 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g3 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g4 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g5 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n        TimeSpan period = await g1.GetReminderPeriod(DR);\n\n        Task[] tasks =\n        {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerGrainFailureTest(g3)),\n                Task.Run(() => PerGrainFailureTest(g4)),\n                Task.Run(() => PerGrainFailureTest(g5)),\n            };\n\n        Thread.Sleep(period.Multiply(failAfter));\n\n        // stop a couple of silos\n        log.LogInformation(\"Stopping 2 silos\");\n        int i = Random.Shared.Next(silos.Count);\n        await HostedCluster.StopSiloAsync(silos[i]);\n        silos.RemoveAt(i);\n        await HostedCluster.StopSiloAsync(silos[Random.Shared.Next(silos.Count)]);\n\n        await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_1F1J_MultiGrain()\n    {\n        List<SiloHandle> silos = await HostedCluster.StartAdditionalSilosAsync(1);\n        await HostedCluster.WaitForLivenessToStabilizeAsync();\n\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g2 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g3 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g4 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g5 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n        TimeSpan period = await g1.GetReminderPeriod(DR);\n\n        Task[] tasks =\n        {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerGrainFailureTest(g3)),\n                Task.Run(() => PerGrainFailureTest(g4)),\n                Task.Run(() => PerGrainFailureTest(g5)),\n            };\n\n        Thread.Sleep(period.Multiply(failAfter));\n\n        var siloToKill = silos[Random.Shared.Next(silos.Count)];\n        // stop a silo and join a new one in parallel\n        log.LogInformation(\"Stopping a silo and joining a silo\");\n        Task t1 = Task.Factory.StartNew(async () => await HostedCluster.StopSiloAsync(siloToKill));\n        Task t2 = HostedCluster.StartAdditionalSilosAsync(1, true).ContinueWith(t =>\n        {\n            t.GetAwaiter().GetResult();\n        });\n        await Task.WhenAll(new[] { t1, t2 }).WaitAsync(ENDWAIT);\n\n        await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n        log.LogInformation(\"\\n\\n\\nReminderTest_1F1J_MultiGrain passed OK.\\n\\n\\n\");\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_RegisterSameReminderTwice()\n    {\n        IReminderTestGrain2 grain = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        Task<IGrainReminder> promise1 = grain.StartReminder(DR);\n        Task<IGrainReminder> promise2 = grain.StartReminder(DR);\n        Task<IGrainReminder>[] tasks = { promise1, promise2 };\n        await Task.WhenAll(tasks).WaitAsync(TimeSpan.FromSeconds(15));\n        //Assert.NotEqual(promise1.Result, promise2.Result);\n        // TODO: write tests where period of a reminder is changed\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_GT_Basic()\n    {\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestCopyGrain g2 = GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n        TimeSpan period = await g1.GetReminderPeriod(DR); // using same period\n\n        await g1.StartReminder(DR);\n        Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n        await g2.StartReminder(DR);\n        Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n        long last1 = await g1.GetCounter(DR);\n        Assert.Equal(4, last1);\n        long last2 = await g2.GetCounter(DR);\n        Assert.Equal(2, last2); // CopyGrain fault\n\n        await g1.StopReminder(DR);\n        Thread.Sleep(period.Multiply(2) + LEEWAY); // giving some leeway\n        await g2.StopReminder(DR);\n        long curr1 = await g1.GetCounter(DR);\n        Assert.Equal(last1, curr1);\n        long curr2 = await g2.GetCounter(DR);\n        Assert.Equal(4, curr2); // CopyGrain fault\n    }\n\n    [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4319\"), TestCategory(\"Functional\")]\n    public async Task Rem_Azure_GT_1F1J_MultiGrain()\n    {\n        List<SiloHandle> silos = await HostedCluster.StartAdditionalSilosAsync(1);\n        await HostedCluster.WaitForLivenessToStabilizeAsync();\n\n        IReminderTestGrain2 g1 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestGrain2 g2 = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        IReminderTestCopyGrain g3 = GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n        IReminderTestCopyGrain g4 = GrainFactory.GetGrain<IReminderTestCopyGrain>(Guid.NewGuid());\n\n        TimeSpan period = await g1.GetReminderPeriod(DR);\n\n        Task[] tasks =\n        {\n                Task.Run(() => PerGrainFailureTest(g1)),\n                Task.Run(() => PerGrainFailureTest(g2)),\n                Task.Run(() => PerCopyGrainFailureTest(g3)),\n                Task.Run(() => PerCopyGrainFailureTest(g4)),\n            };\n\n        Thread.Sleep(period.Multiply(failAfter));\n\n        var siloToKill = silos[Random.Shared.Next(silos.Count)];\n        // stop a silo and join a new one in parallel\n        log.LogInformation(\"Stopping a silo and joining a silo\");\n        Task t1 = Task.Run(async () => await HostedCluster.StopSiloAsync(siloToKill));\n        Task t2 = Task.Run(async () => await HostedCluster.StartAdditionalSilosAsync(1));\n        await Task.WhenAll(new[] { t1, t2 }).WaitAsync(ENDWAIT);\n\n        await Task.WhenAll(tasks).WaitAsync(ENDWAIT); // Block until all tasks complete.\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Wrong_LowerThanAllowedPeriod()\n    {\n        IReminderTestGrain2 grain = GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n        await Assert.ThrowsAsync<ArgumentException>(() =>\n            grain.StartReminder(DR, TimeSpan.FromMilliseconds(3000), true));\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Rem_Azure_Wrong_Grain()\n    {\n        IReminderGrainWrong grain = GrainFactory.GetGrain<IReminderGrainWrong>(0);\n\n        await Assert.ThrowsAsync<InvalidOperationException>(() =>\n            grain.StartReminder(DR));\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/ReminderTests_Cosmos_Standalone.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing Xunit.Abstractions;\nusing Orleans.Internal;\nusing Orleans.Configuration;\nusing Orleans.TestingHost.Utils;\nusing Orleans.Reminders.Cosmos;\n\nnamespace Tester.Cosmos.Reminders;\n\n/// <summary>\n/// Standalone tests for Cosmos DB reminder table operations including performance benchmarks and table-level operations.\n/// </summary>\n[Collection(TestEnvironmentFixture.DefaultCollection)]\n[TestCategory(\"Cosmos\")]\npublic class ReminderTests_Cosmos_Standalone\n{\n    private readonly ITestOutputHelper _output;\n    private readonly TestEnvironmentFixture _fixture;\n    private readonly string _serviceId;\n    private readonly ILogger _log;\n    private readonly ILoggerFactory _loggerFactory;\n\n    public ReminderTests_Cosmos_Standalone(ITestOutputHelper output, TestEnvironmentFixture fixture)\n    {\n        CosmosTestUtils.CheckCosmosStorage();\n\n        _output = output;\n        _fixture = fixture;\n        _loggerFactory = TestingUtils.CreateDefaultLoggerFactory($\"{GetType().Name}.log\");\n        _log = _loggerFactory.CreateLogger<ReminderTests_Cosmos_Standalone>();\n\n        _serviceId = Guid.NewGuid().ToString();\n    }\n\n    [SkippableFact, TestCategory(\"Reminders\"), TestCategory(\"Performance\")]\n    public async Task Reminders_AzureTable_InsertRate()\n    {\n        var clusterOptions = Options.Create(new ClusterOptions { ClusterId = \"TMSLocalTesting\", ServiceId = _serviceId });\n        var storageOptions = Options.Create(new CosmosReminderTableOptions());\n        storageOptions.Value.ConfigureTestDefaults();\n\n        IReminderTable table = new CosmosReminderTable(_loggerFactory, _fixture.Services, storageOptions, clusterOptions);\n        using var cancellation = new CancellationTokenSource(new ReminderOptions().InitializationTimeout);\n        await table.StartAsync(cancellation.Token);\n\n        await TestTableInsertRate(table, 10);\n        await TestTableInsertRate(table, 500);\n    }\n\n    [SkippableFact, TestCategory(\"Reminders\")]\n    public async Task Reminders_AzureTable_InsertNewRowAndReadBack()\n    {\n        string clusterId = NewClusterId();\n        var clusterOptions = Options.Create(new ClusterOptions { ClusterId = clusterId, ServiceId = _serviceId });\n        var storageOptions = Options.Create(new CosmosReminderTableOptions());\n        storageOptions.Value.ConfigureTestDefaults();\n        IReminderTable table = new CosmosReminderTable(_loggerFactory, _fixture.Services, storageOptions, clusterOptions);\n        using var cancellation = new CancellationTokenSource(new ReminderOptions().InitializationTimeout);\n        await table.StartAsync(cancellation.Token);\n\n        ReminderEntry[] rows = (await GetAllRows(table)).ToArray();\n        Assert.Empty(rows); // \"The reminder table (sid={0}, did={1}) was not empty.\", ServiceId, clusterId);\n\n        ReminderEntry expected = NewReminderEntry();\n        await table.UpsertRow(expected);\n        rows = (await GetAllRows(table)).ToArray();\n\n        Assert.Single(rows); // \"The reminder table (sid={0}, did={1}) did not contain the correct number of rows (1).\", ServiceId, clusterId);\n        ReminderEntry actual = rows[0];\n        Assert.Equal(expected.GrainId, actual.GrainId); // \"The newly inserted reminder table (sid={0}, did={1}) row did not contain the expected grain reference.\", ServiceId, clusterId);\n        Assert.Equal(expected.ReminderName, actual.ReminderName); // \"The newly inserted reminder table (sid={0}, did={1}) row did not have the expected reminder name.\", ServiceId, clusterId);\n        Assert.Equal(expected.Period, actual.Period); // \"The newly inserted reminder table (sid={0}, did={1}) row did not have the expected period.\", ServiceId, clusterId);\n                                                      // the following assertion fails but i don't know why yet-- the timestamps appear identical in the error message. it's not really a priority to hunt down the reason, however, because i have high confidence it is working well enough for the moment.\n        /*Assert.Equal(expected.StartAt,  actual.StartAt); // \"The newly inserted reminder table (sid={0}, did={1}) row did not contain the correct start time.\", ServiceId, clusterId);*/\n        Assert.False(string.IsNullOrWhiteSpace(actual.ETag), $\"The newly inserted reminder table (sid={_serviceId}, did={clusterId}) row contains an invalid etag.\");\n    }\n\n    private async Task TestTableInsertRate(IReminderTable reminderTable, double numOfInserts)\n    {\n        DateTime startedAt = DateTime.UtcNow;\n\n        try\n        {\n            List<Task<bool>> promises = new List<Task<bool>>();\n            for (int i = 0; i < numOfInserts; i++)\n            {\n                //\"177BF46E-D06D-44C0-943B-C12F26DF5373\"\n                string s = string.Format(\"177BF46E-D06D-44C0-943B-C12F26D{0:d5}\", i);\n\n                var e = new ReminderEntry\n                {\n                    //GrainId = LegacyGrainId.GetGrainId(new Guid(s)),\n                    GrainId = _fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId()).GetGrainId(),\n                    ReminderName = \"MY_REMINDER_\" + i,\n                    Period = TimeSpan.FromSeconds(5),\n                    StartAt = DateTime.UtcNow\n                };\n\n                int capture = i;\n                Task<bool> promise = Task.Run(async () =>\n                {\n                    await reminderTable.UpsertRow(e);\n                    _output.WriteLine(\"Done \" + capture);\n                    return true;\n                });\n                promises.Add(promise);\n                _log.LogInformation(\"Started {Capture}\", capture);\n            }\n            _log.LogInformation(\"Started all, now waiting...\");\n            await Task.WhenAll(promises).WaitAsync(TimeSpan.FromSeconds(500));\n        }\n        catch (Exception exc)\n        {\n            _log.LogInformation(exc, \"Exception caught\");\n        }\n        TimeSpan dur = DateTime.UtcNow - startedAt;\n        _log.LogInformation(\n            \"Inserted {InsertCount} rows in {Duration}, i.e., {Rate} upserts/sec\",\n            numOfInserts,\n            dur,\n            (numOfInserts / dur.TotalSeconds).ToString(\"f2\"));\n    }\n\n    private ReminderEntry NewReminderEntry()\n    {\n        Guid guid = Guid.NewGuid();\n        return new ReminderEntry\n        {\n            GrainId = _fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId()).GetGrainId(),\n            ReminderName = string.Format(\"TestReminder.{0}\", guid),\n            Period = TimeSpan.FromSeconds(5),\n            StartAt = DateTime.UtcNow\n        };\n    }\n\n    private static string NewClusterId()\n    {\n        return string.Format(\"ReminderTest.{0}\", Guid.NewGuid());\n    }\n\n    private static async Task<IEnumerable<ReminderEntry>> GetAllRows(IReminderTable table)\n    {\n        ReminderTableData data = await table.ReadRows(0, 0xffffffff);\n        return data.Reminders;\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Cosmos.Tests/Usings.cs",
    "content": "global using Xunit;"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Clustering/RedisMembershipTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Clustering.Redis;\nusing Orleans.Messaging;\nusing Xunit;\nusing UnitTests.MembershipTests;\nusing TestExtensions;\nusing UnitTests;\nusing StackExchange.Redis;\n\nnamespace Tester.Redis.Clustering\n{\n    /// <summary>\n    /// Tests for Orleans membership table operations using Redis as the backing store.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Clustering\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisMembershipTableTests : MembershipTableTestsBase\n    {\n        public RedisMembershipTableTests(ConnectionStringFixture fixture, CommonFixture environment) : base(fixture, environment, CreateFilters())\n        {\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            var filters = new LoggerFilterOptions();\n            return filters;\n        }\n\n        internal RedisMembershipTable membershipTable;\n\n        protected override IMembershipTable CreateMembershipTable(ILogger logger)\n        {\n            TestUtils.CheckForRedis();\n\n            membershipTable = new RedisMembershipTable(\n                Options.Create(new RedisClusteringOptions()\n                {\n                    ConfigurationOptions = ConfigurationOptions.Parse(GetConnectionString().Result),\n                    EntryExpiry = TimeSpan.FromHours(1)\n                }),\n                this._clusterOptions);\n\n            return membershipTable;\n        }\n\n        protected override IGatewayListProvider CreateGatewayListProvider(ILogger logger)\n        {\n            return new RedisGatewayListProvider(\n                //(RedisMembershipTable)this.membershipTable,\n                (RedisMembershipTable)CreateMembershipTable(logger),\n                this._gatewayOptions);\n        }\n\n        protected override Task<string> GetConnectionString() => Task.FromResult(TestDefaultConfiguration.RedisConnectionString);\n\n        [SkippableFact]\n        public async Task GetGateways()\n        {\n            await MembershipTable_GetGateways();\n        }\n\n        [SkippableFact]\n        public async Task ReadAll_EmptyTable()\n        {\n            await MembershipTable_ReadAll_EmptyTable();\n        }\n\n        [SkippableFact]\n        public async Task InsertRow()\n        {\n            await MembershipTable_InsertRow();\n        }\n\n        [SkippableFact]\n        public async Task ReadRow_Insert_Read()\n        {\n            await MembershipTable_ReadRow_Insert_Read();\n        }\n\n        [SkippableFact]\n        public async Task ReadAll_Insert_ReadAll()\n        {\n            await MembershipTable_ReadAll_Insert_ReadAll();\n        }\n\n        [SkippableFact]\n        public async Task UpdateRow()\n        {\n            await MembershipTable_UpdateRow();\n        }\n\n        [SkippableFact]\n        public async Task UpdateRowInParallel()\n        {\n            await MembershipTable_UpdateRowInParallel(false);\n        }\n\n        [SkippableFact]\n        public async Task UpdateIAmAlive()\n        {\n            await MembershipTable_UpdateIAmAlive();\n        }\n\n        [SkippableFact]\n        public async Task CleanupDefunctSiloEntries()\n        {\n            await MembershipTable_CleanupDefunctSiloEntries(false);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/CollectionFixtures.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace Tester.Redis\n{\n    // Assembly collections must be defined once in each assembly\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides Redis-specific test environment setup using a common fixture.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<CommonFixture> { }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/GrainDirectory/RedisGrainDirectoryTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory.Redis;\nusing StackExchange.Redis;\nusing Tester.Directories;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Redis.GrainDirectory\n{\n    /// <summary>\n    /// Tests for Orleans grain directory functionality using Redis as the directory storage backend.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Directory\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisGrainDirectoryTests : GrainDirectoryTests<RedisGrainDirectory>\n    {\n        public RedisGrainDirectoryTests(ITestOutputHelper testOutput) : base(testOutput)\n        {\n        }\n\n        protected override RedisGrainDirectory CreateGrainDirectory()\n        {\n            TestUtils.CheckForRedis();\n            var configuration = TestDefaultConfiguration.RedisConnectionString;\n            var directoryOptions = new RedisGrainDirectoryOptions\n            {\n                ConfigurationOptions = ConfigurationOptions.Parse(configuration),\n                EntryExpiry = TimeSpan.FromMinutes(1),\n            };\n\n            var clusterOptions = Options.Create(new ClusterOptions { ServiceId = \"SomeServiceId\", ClusterId = Guid.NewGuid().ToString(\"N\") });\n            var directory = new RedisGrainDirectory(\n                directoryOptions,\n                clusterOptions,\n                this.loggerFactory.CreateLogger<RedisGrainDirectory>());\n            directory.Initialize().GetAwaiter().GetResult();\n            return directory;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/GrainDirectory/RedisMultipleGrainDirectoriesTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.GrainDirectory.Redis;\nusing Orleans.TestingHost;\nusing StackExchange.Redis;\nusing Tester.Directories;\nusing TestExtensions;\nusing UnitTests.Grains.Directories;\nusing Xunit;\n\nnamespace Tester.Redis.GrainDirectory\n{\n    /// <summary>\n    /// Tests for Orleans clusters using multiple grain directories with Redis as the directory storage backend.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Directory\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisMultipleGrainDirectoriesTests : MultipleGrainDirectoriesTests\n    {\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                TestUtils.CheckForRedis();\n\n                siloBuilder\n                    .AddRedisGrainDirectory(\n                        CustomDirectoryGrain.DIRECTORY,\n                        options =>\n                        {\n                            options.ConfigurationOptions = ConfigurationOptions.Parse(TestDefaultConfiguration.RedisConnectionString);\n                            options.EntryExpiry = TimeSpan.FromMinutes(5);\n                        })\n                    .ConfigureLogging(builder => builder.AddFilter(typeof(RedisGrainDirectory).FullName, LogLevel.Debug));\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow() => TestUtils.CheckForRedis();\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            base.ConfigureTestCluster(builder);\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Orleans.Redis.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Redis\\Orleans.Clustering.Redis\\Orleans.Clustering.Redis.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Redis\\Orleans.Reminders.Redis\\Orleans.Reminders.Redis.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Redis\\Orleans.Persistence.Redis\\Orleans.Persistence.Redis.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Redis\\Orleans.GrainDirectory.Redis\\Orleans.GrainDirectory.Redis.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/GrainState.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace Tester.Redis.Persistence\n{\n    [GenerateSerializer]\n    public class GrainState\n    {\n        [Id(0)]\n        public string StringValue { get; set; }\n        [Id(1)]\n        public int IntValue { get; set; }\n        [Id(2)]\n        public DateTime DateTimeValue { get; set; }\n        [Id(3)]\n        public Guid GuidValue { get; set; }\n        [Id(4)]\n        public IGrainStorageGenericGrain<GrainState> GrainValue { get; set; }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/RedisPersistenceGrainTests.cs",
    "content": "using System.Text.RegularExpressions;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing StackExchange.Redis;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Redis.Persistence\n{\n    /// <summary>\n    /// Tests for grain persistence functionality using Redis as the storage provider, including Redis-specific scenarios.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Persistence\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisPersistenceGrainTests : GrainPersistenceTestsRunner, IClassFixture<RedisPersistenceGrainTests.Fixture>\n    {\n        public static readonly string ServiceId = Guid.NewGuid().ToString(\"N\");\n        public const string ConnectionStringKey = \"ConnectionString\";\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 4;\n                builder.Options.UseTestClusterMembership = true;\n                builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddInMemoryCollection(\n                    new Dictionary<string, string>\n                    {\n                        {ConnectionStringKey, TestDefaultConfiguration.RedisConnectionString}\n                    }));\n                builder.Options.ServiceId = ServiceId;\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<GatewayConnectionTests.ClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    var connectionString = hostBuilder.GetConfiguration()[ConnectionStringKey];\n                    hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder\n                            .AddRedisGrainStorage(\"GrainStorageForTest\", options =>\n                            {\n                                options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                                options.EntryExpiry = TimeSpan.FromHours(1);\n                            })\n                            .AddMemoryGrainStorage(\"MemoryStore\");\n                    });\n                }\n            }\n\n            protected override void CheckPreconditionsOrThrow() => TestUtils.CheckForRedis();\n        }\n\n        private readonly Fixture fixture;\n\n        public RedisPersistenceGrainTests(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n        {\n            try\n            {\n                this.fixture = fixture;\n            }\n            catch(OrleansConfigurationException) { }\n\n            this.fixture.EnsurePreconditionsMet();\n\n            var redisOptions = ConfigurationOptions.Parse(TestDefaultConfiguration.RedisConnectionString);\n            var redis = ConnectionMultiplexer.ConnectAsync(redisOptions).Result;\n            this.database = redis.GetDatabase();\n\n            this.state = new()\n            {\n                DateTimeValue = DateTime.UtcNow,\n                GuidValue = Guid.NewGuid(),\n                IntValue = 12345,\n                StringValue = \"string value\",\n                GrainValue = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(999)\n            };\n        }\n\n        // Redis specific tests\n\n        private readonly GrainState state;\n        private readonly IDatabase database;\n\n        [SkippableFact]\n        public async Task Redis_InitializeWithNoStateTest()\n        {\n            var grain = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(0);\n            var result = await grain.DoRead();\n\n            //Assert.NotNull(result);\n            Assert.Equal(default, result);\n            //Assert.Equal(default(string), result.StringValue);\n            //Assert.Equal(default(int), result.IntValue);\n            //Assert.Equal(default(DateTime), result.DateTimeValue);\n            //Assert.Equal(default(Guid), result.GuidValue);\n            //Assert.Equal(default(ITestGrain), result.GrainValue);\n        }\n\n        [SkippableFact]\n        public async Task Redis_TestStaticIdentifierGrains()\n        {\n            var grain = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(12345);\n            await grain.DoWrite(state);\n\n            var grain2 = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(12345);\n            var result = await grain2.DoRead();\n            Assert.Equal(result.StringValue, state.StringValue);\n            Assert.Equal(result.IntValue, state.IntValue);\n            Assert.Equal(result.DateTimeValue, state.DateTimeValue);\n            Assert.Equal(result.GuidValue, state.GuidValue);\n            Assert.Equal(result.GrainValue, state.GrainValue);\n        }\n\n        [SkippableFact]\n        public async Task Redis_TestRedisScriptCacheClearBeforeGrainWriteState()\n        {\n            var grain = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(1111);\n\n            var info = (string)await database.ExecuteAsync(\"INFO\");\n            var versionString = Regex.Match(info, @\"redis_version:[\\s]*([^\\s]+)\").Groups[1].Value;\n            var version = Version.Parse(versionString);\n            if (version >= Version.Parse(\"6.2.0\"))\n            {\n                await database.ExecuteAsync(\"SCRIPT\", \"FLUSH\", \"SYNC\");\n            }\n            else\n            {\n                await database.ExecuteAsync(\"SCRIPT\", \"FLUSH\");\n            }\n\n            await grain.DoWrite(state);\n\n            var result = await grain.DoRead();\n            Assert.Equal(result.StringValue, state.StringValue);\n            Assert.Equal(result.IntValue, state.IntValue);\n            Assert.Equal(result.DateTimeValue, state.DateTimeValue);\n            Assert.Equal(result.GuidValue, state.GuidValue);\n            Assert.Equal(result.GrainValue, state.GrainValue);\n        }\n\n        [SkippableFact]\n        public async Task Redis_DoubleActivationETagConflictSimulation()\n        {\n            var grain = fixture.GrainFactory.GetGrain<IGrainStorageGenericGrain<GrainState>>(54321);\n            var data = await grain.DoRead();\n\n            var key = $\"{ServiceId}/state/{grain.GetGrainId()}/state\";\n            await database.HashSetAsync(key, new[] { new HashEntry(\"etag\", \"derp\") });\n\n            await Assert.ThrowsAsync<InconsistentStateException>(() => grain.DoWrite(state));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/RedisPersistenceSetupTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Hosting;\nusing Xunit;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing StackExchange.Redis;\nusing TestExtensions;\n\nnamespace Tester.Redis.Persistence\n{\n    /// <summary>\n    /// Tests for Redis grain storage configuration validation and setup scenarios.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Persistence\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisPersistenceSetupTests\n    {\n        [SkippableTheory]\n        [InlineData(null)]\n        [InlineData(\"localhost:1234\")]\n        public void StorageOptionsValidator(string connectionString)\n        {\n            TestUtils.CheckForRedis();\n\n            var siloPort = 11111;\n            int gatewayPort = 30000;\n            var siloAddress = IPAddress.Loopback;\n\n            var host = Host.CreateDefaultBuilder()\n                .UseOrleans((ctx, builder) => {\n                    builder.Configure<ClusterOptions>(options => options.ClusterId = \"TESTCLUSTER\")\n                        .UseDevelopmentClustering(options => options.PrimarySiloEndpoint = new IPEndPoint(siloAddress, siloPort))\n                        .ConfigureEndpoints(siloAddress, siloPort, gatewayPort)\n                        .AddRedisGrainStorage(\"Redis\", optionsBuilder => optionsBuilder.Configure(options =>\n                        {\n                            if (connectionString is not null)\n                            {\n                                options.ConfigurationOptions = ConfigurationOptions.Parse(connectionString);\n                            }\n                        }));\n                }).Build();\n\n            if (string.IsNullOrWhiteSpace(connectionString))\n            {\n                Assert.Throws<OrleansConfigurationException>(() => host.Start());\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/RedisStorageTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.StorageTests.Relational;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Redis.Persistence\n{\n    /// <summary>\n    /// Tests for Redis grain storage provider with various data types and serialization scenarios.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Persistence\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisStorageTests\n    {\n        private readonly CommonFixture fixture;\n        private readonly CommonStorageTests commonStorageTests;\n    \n        public RedisStorageTests(ITestOutputHelper output, CommonFixture commonFixture) \n        {\n            TestUtils.CheckForRedis();\n            this.fixture = commonFixture;\n            this.commonStorageTests = new CommonStorageTests(commonFixture.CreateRedisGrainStorage(false).GetAwaiter().GetResult());      \n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            await Relational_WriteInconsistentFailsWithIncosistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteRead100StatesInParallel()\n        {\n            await Relational_WriteReadWriteRead100StatesInParallel();\n        }\n        internal Task Relational_WriteReadWriteRead100StatesInParallel()\n        {\n            return commonStorageTests.PersistenceStorage_WriteReadWriteReadStatesInParallel(nameof(Relational_WriteReadWriteRead100StatesInParallel));\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadCyrillic()\n        {\n            await commonStorageTests.PersistenceStorage_Relational_WriteReadIdCyrillic();\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await commonStorageTests.Store_WriteRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            await Relational_WriteDuplicateFailsWithInconsistentStateException();\n        }\n\n        internal async Task Relational_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            var exception = await commonStorageTests.PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        internal async Task Relational_WriteInconsistentFailsWithIncosistentStateException()\n        {\n            var exception = await commonStorageTests.PersistenceStorage_WriteInconsistentFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/RedisStorageTests_DeleteStateOnClear.cs",
    "content": "using TestExtensions;\nusing UnitTests.StorageTests.Relational;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Redis.Persistence\n{\n    /// <summary>\n    /// Tests for Redis grain storage provider with the delete-state-on-clear option enabled.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Persistence\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisStorageTests_DeleteStateOnClear\n    {\n        private readonly CommonFixture fixture;\n        private readonly CommonStorageTests commonStorageTests;\n    \n        public RedisStorageTests_DeleteStateOnClear(ITestOutputHelper output, CommonFixture commonFixture) \n        {\n            TestUtils.CheckForRedis();\n            this.fixture = commonFixture;\n            this.commonStorageTests = new CommonStorageTests(commonFixture.CreateRedisGrainStorage(useOrleansSerializer: false, deleteStateOnClear: true).GetAwaiter().GetResult());      \n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Persistence/RedisStorageTests_OrleansSerializer.cs",
    "content": "using TestExtensions;\nusing UnitTests.StorageTests.Relational;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Redis.Persistence\n{\n    /// <summary>\n    /// Tests for Redis grain storage using Orleans serializer.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Persistence\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisStorageTests_OrleansSerializer\n    {\n        private readonly CommonFixture fixture;\n        private readonly CommonStorageTests commonStorageTests;\n\n        public RedisStorageTests_OrleansSerializer(ITestOutputHelper output, CommonFixture commonFixture)\n        {\n            TestUtils.CheckForRedis();\n            this.fixture = commonFixture;\n            var storageProvider = fixture.CreateRedisGrainStorage(true).Result;\n            this.commonStorageTests = new CommonStorageTests(storageProvider);\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteInconsistentFailsWithIncosistentStateException()\n        {\n            await Relational_WriteInconsistentFailsWithIncosistentStateException();\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteRead100StatesInParallel()\n        {\n            await Relational_WriteReadWriteRead100StatesInParallel();\n        }\n        internal Task Relational_WriteReadWriteRead100StatesInParallel()\n        {\n            return commonStorageTests.PersistenceStorage_WriteReadWriteReadStatesInParallel(nameof(Relational_WriteReadWriteRead100StatesInParallel));\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task WriteReadCyrillic()\n        {\n            await commonStorageTests.PersistenceStorage_Relational_WriteReadIdCyrillic();\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSet2CyrillicIdsAndGrainNames<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task DataSet2_Cyrillic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSet2CyrillicIdsAndGrainNames<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<long>))]\n        [TestCategory(\"Functional\")]\n        internal async Task PersistenceStorage_StorageDataSetPlain_IntegerKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<long>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<Guid, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_GuidKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<Guid, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<long, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_IntegerKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<long, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_StringKey_Generic_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetGeneric<string, string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetGeneric_WriteRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetGeneric<string, string>.GetTestData(testNum);\n            await commonStorageTests.Store_WriteRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<Guid>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_GuidKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<Guid>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableTheory, ClassData(typeof(StorageDataSetPlain<string>))]\n        [TestCategory(\"Functional\")]\n        internal async Task StorageDataSetPlain_StringKey_WriteClearRead(int testNum)\n        {\n            var (grainType, getGrain, grainState) = StorageDataSetPlain<string>.GetTestData(testNum);\n            await this.commonStorageTests.Store_WriteClearRead(grainType, getGrain, grainState);\n        }\n\n        [SkippableFact]\n        [TestCategory(\"Functional\")]\n        public async Task PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            await Relational_WriteDuplicateFailsWithInconsistentStateException();\n        }\n\n        internal async Task Relational_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            var exception = await commonStorageTests.PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n\n        internal async Task Relational_WriteInconsistentFailsWithIncosistentStateException()\n        {\n            var exception = await commonStorageTests.PersistenceStorage_WriteInconsistentFailsWithInconsistentStateException();\n            CommonStorageUtilities.AssertRelationalInconsistentExceptionMessage(exception.Message);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Reminders/RedisReminderTableTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Reminders.Redis;\nusing StackExchange.Redis;\nusing TestExtensions;\nusing UnitTests;\nusing UnitTests.RemindersTest;\nusing Xunit;\n\nnamespace Tester.Redis.Reminders\n{\n    /// <summary>\n    /// Tests for Redis reminder table implementation.\n    /// </summary>\n    [TestCategory(\"Redis\"), TestCategory(\"Reminders\"), TestCategory(\"Functional\")]\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RedisRemindersTableTests : ReminderTableTestsBase\n    {\n        public RedisRemindersTableTests(ConnectionStringFixture fixture, CommonFixture clusterFixture) : base (fixture, clusterFixture, CreateFilters())\n        {\n            TestUtils.CheckForRedis();\n        }\n\n        private static LoggerFilterOptions CreateFilters()\n        {\n            LoggerFilterOptions filters = new LoggerFilterOptions();\n            filters.AddFilter(nameof(RedisRemindersTableTests), LogLevel.Trace);\n            return filters;\n        }\n\n        protected override IReminderTable CreateRemindersTable()\n        {\n            TestUtils.CheckForRedis();\n\n            RedisReminderTable reminderTable = new(\n                this.loggerFactory.CreateLogger<RedisReminderTable>(),\n                this.clusterOptions,\n                Options.Create(new RedisReminderTableOptions()\n                {\n                    ConfigurationOptions = ConfigurationOptions.Parse(GetConnectionString().Result),\n                    EntryExpiry = TimeSpan.FromHours(1)\n                })); \n\n            if (reminderTable == null)\n            {\n                throw new InvalidOperationException(\"RedisReminderTable not configured\");\n            }\n\n            return reminderTable;\n        }\n\n        protected override Task<string> GetConnectionString() => Task.FromResult(TestDefaultConfiguration.RedisConnectionString);\n\n        [SkippableFact]\n        public void RemindersTable_Redis_Init()\n        {\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_Redis_RemindersRange()\n        {\n            await RemindersRange(iterations: 50);\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_Redis_RemindersParallelUpsert()\n        {\n            await RemindersParallelUpsert();\n        }\n\n        [SkippableFact]\n        public async Task RemindersTable_Redis_ReminderSimple()\n        {\n            await ReminderSimple();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Utility/CommonFixture.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Persistence;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Storage;\nusing StackExchange.Redis;\nusing Tester;\nusing TestExtensions;\n\npublic class CommonFixture : TestEnvironmentFixture\n{\n    /// <summary>\n    /// Caches DefaultProviderRuntime for multiple uses.\n    /// </summary>\n    private IProviderRuntime DefaultProviderRuntime { get; }\n\n    /// <summary>\n    /// Constructor.\n    /// </summary>\n    public CommonFixture()\n    {\n        _ = this.Services.GetRequiredService<IOptions<ClusterOptions>>();\n        DefaultProviderRuntime = new ClientProviderRuntime(\n            this.InternalGrainFactory,\n            this.Services,\n            this.Services.GetRequiredService<ClientGrainContext>());\n    }\n\n    /// <summary>\n    /// Returns a correct implementation of the persistence provider according to environment variables.\n    /// </summary>\n    /// <remarks>If the environment invariants have failed to hold upon creation of the storage provider,\n    /// a <em>null</em> value will be provided.</remarks>\n    public async Task<IGrainStorage> CreateRedisGrainStorage(bool useOrleansSerializer = false, bool deleteStateOnClear = false)\n    {\n        TestUtils.CheckForRedis();\n        IGrainStorageSerializer grainStorageSerializer = useOrleansSerializer ? new OrleansGrainStorageSerializer(this.DefaultProviderRuntime.ServiceProvider.GetService<Serializer>())\n                                                                              : new JsonGrainStorageSerializer(this.DefaultProviderRuntime.ServiceProvider.GetService<OrleansJsonSerializer>());\n        var options = new RedisStorageOptions()\n        {\n            ConfigurationOptions = ConfigurationOptions.Parse(TestDefaultConfiguration.RedisConnectionString),\n            GrainStorageSerializer = grainStorageSerializer,\n            DeleteStateOnClear = deleteStateOnClear,\n        };\n\n        var clusterOptions = new ClusterOptions()\n        {\n            ServiceId = Guid.NewGuid().ToString()\n        };\n\n        var serviceProvider = DefaultProviderRuntime.ServiceProvider;\n        var storageProvider = new RedisGrainStorage(\n            string.Empty,\n            options,\n            grainStorageSerializer,\n            Options.Create(clusterOptions),\n            serviceProvider.GetRequiredService<IActivatorProvider>(),\n            serviceProvider.GetRequiredService<ILogger<RedisGrainStorage>>());\n        ISiloLifecycleSubject siloLifeCycle = new SiloLifecycleSubject(NullLoggerFactory.Instance.CreateLogger<SiloLifecycleSubject>());\n        storageProvider.Participate(siloLifeCycle);\n        await siloLifeCycle.OnStart(CancellationToken.None);\n        return storageProvider;\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Redis.Tests/Utility/TestExtensions.cs",
    "content": "using Orleans.Runtime;\nusing System.Net;\n\nnamespace Tester.Redis.Utility\n{\n    public static class TestExtensions\n    {\n        public static async Task WithTimeout(this Task taskToComplete, TimeSpan timeout)\n        {\n            if (taskToComplete.IsCompleted)\n            {\n                await taskToComplete;\n                return;\n            }\n\n            using var timeoutCancellationTokenSource = new CancellationTokenSource();\n            var completedTask = await Task.WhenAny(taskToComplete, Task.Delay(timeout, timeoutCancellationTokenSource.Token));\n\n            if (taskToComplete == completedTask)\n            {\n                timeoutCancellationTokenSource.Cancel();\n                await taskToComplete;\n                return;\n            }\n\n            taskToComplete.Ignore();\n            throw new TimeoutException(string.Format(\"WithTimeout has timed out after {0}.\", timeout));\n        }\n    }\n\n    public static class SiloAddressUtils\n    {\n        private static readonly IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Loopback, 0);\n\n        public static SiloAddress NewLocalSiloAddress(int gen)\n        {\n            return SiloAddress.New(localEndpoint, gen);\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/CollectionFixtures.cs",
    "content": "using Orleans.Runtime;\nusing Tester;\nusing TestExtensions;\nusing Xunit;\n\nnamespace ServiceBus.Tests\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n    \n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides Azure Service Bus and Event Hub specific test environment setup.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n\n    /// <summary>\n    /// Base test cluster fixture for Event Hub integration tests.\n    /// Ensures Event Hub connectivity and waits for stream queue initialization.\n    /// </summary>\n    public abstract class BaseEventHubTestClusterFixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForEventHub();\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            var collector = new Microsoft.Extensions.Diagnostics.Metrics.Testing.MetricCollector<long>(Instruments.Meter, \"orleans-streams-queue-read-duration\");\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n            // Wait for 10 queue read\n            await collector.WaitForMeasurementsAsync(10, cts.Token);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/EventHubConfigurationExtensions.cs",
    "content": "using Azure.Identity;\nusing Orleans.Configuration;\nusing Tester.AzureUtils;\nusing TestExtensions;\n\nnamespace ServiceBus.Tests\n{\n    public static class EventHubConfigurationExtensions\n    {\n        public static EventHubOptions ConfigureTestDefaults(this EventHubOptions options, string eventHubName, string consumerGroup)\n        {\n            if (TestDefaultConfiguration.UseAadAuthentication)\n            {\n                options.ConfigureEventHubConnection(TestDefaultConfiguration.EventHubFullyQualifiedNamespace, eventHubName, consumerGroup, TestDefaultConfiguration.TokenCredential);\n            }\n            else\n            {\n                options.ConfigureEventHubConnection(TestDefaultConfiguration.EventHubConnectionString, eventHubName, consumerGroup);\n            }\n\n            return options;\n        }\n\n        public static AzureTableStreamCheckpointerOptions ConfigureTestDefaults(this AzureTableStreamCheckpointerOptions options)\n        {\n            options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/EvictionStrategyTests/EHPurgeLogicTests.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Configuration;\nusing Xunit;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Azure.Messaging.EventHubs;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\nusing Orleans.Statistics;\nusing System.Globalization;\n\nnamespace ServiceBus.Tests.EvictionStrategyTests\n{\n    /// <summary>\n    /// Tests for EventHub cache purge logic and eviction strategy behavior under pressure conditions.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n    public class EHPurgeLogicTests\n    {\n        private readonly CachePressureInjectionMonitor cachePressureInjectionMonitor;\n        private readonly PurgeDecisionInjectionPredicate purgePredicate;\n        private readonly Serializer serializer;\n        private EventHubAdapterReceiver receiver1;\n        private EventHubAdapterReceiver receiver2;\n        private readonly ObjectPool<FixedSizeBuffer> bufferPool;\n        private readonly TimeSpan timeOut = TimeSpan.FromSeconds(30);\n        private readonly EventHubPartitionSettings ehSettings;\n        private IEnvironmentStatisticsProvider environmentStatisticsProvider;\n        private ConcurrentBag<EventHubQueueCacheForTesting> cacheList;\n        private List<EHEvictionStrategyForTesting> evictionStrategyList;\n\n        public EHPurgeLogicTests()\n        {\n            //an mock eh settings\n            this.ehSettings = new EventHubPartitionSettings\n            {\n                Hub = new EventHubOptions(),\n                Partition = \"MockPartition\",\n                ReceiverOptions = new EventHubReceiverOptions()\n            };\n\n            //set up cache pressure monitor and purge predicate\n            this.environmentStatisticsProvider = new EnvironmentStatisticsProvider();\n            this.cachePressureInjectionMonitor = new CachePressureInjectionMonitor();\n            this.purgePredicate = new PurgeDecisionInjectionPredicate(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(30));\n\n            // set up serialization env\n            var serviceProvider = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            this.serializer = serviceProvider.GetRequiredService<Serializer>();\n\n            //set up buffer pool, small buffer size make it easy for cache to allocate multiple buffers\n            var oneKB = 1024;\n            this.bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(oneKB));\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task EventHubQueueCache_WontPurge_WhenUnderPressure()\n        {\n            InitForTesting();\n            var tasks = new List<Task>();\n            //add items into cache, make sure will allocate multiple buffers from the pool\n            int itemAddToCache = 100;\n            foreach(var cache in this.cacheList)\n                tasks.Add(AddDataIntoCache(cache, itemAddToCache));\n            await Task.WhenAll(tasks);\n\n            //set cachePressureMonitor to be underPressure\n            this.cachePressureInjectionMonitor.isUnderPressure = true;\n            //set purgePredicate to be ShouldPurge\n            this.purgePredicate.ShouldPurge = true;\n            this.receiver1.TryPurgeFromCache(out _);\n            this.receiver2.TryPurgeFromCache(out _);\n\n            //Assert\n            int expectedItemCountInCacheList = itemAddToCache + itemAddToCache;\n            Assert.Equal(expectedItemCountInCacheList, GetItemCountInAllCache(this.cacheList));\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task EventHubQueueCache_WontPurge_WhenTimePurgePredicateSaysDontPurge()\n        {\n            InitForTesting();\n            var tasks = new List<Task>();\n            //add items into cache\n            int itemAddToCache = 100;\n            foreach (var cache in this.cacheList)\n                tasks.Add(AddDataIntoCache(cache, itemAddToCache));\n            await Task.WhenAll(tasks);\n\n            //set cachePressureMonitor to be underPressure\n            this.cachePressureInjectionMonitor.isUnderPressure = false;\n            //set purgePredicate to be ShouldPurge\n            this.purgePredicate.ShouldPurge = false;\n\n            //perform purge\n            this.receiver1.TryPurgeFromCache(out _);\n            this.receiver2.TryPurgeFromCache(out _);\n\n            //Assert\n            int expectedItemCountInCacheList = itemAddToCache + itemAddToCache;\n            Assert.Equal(expectedItemCountInCacheList, GetItemCountInAllCache(this.cacheList));\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task EventHubQueueCache_WillPurge_WhenTimePurgePredicateSaysPurge_And_NotUnderPressure()\n        {\n            InitForTesting();\n            var tasks = new List<Task>();\n            //add items into cache\n            int itemAddToCache = 100;\n            foreach (var cache in this.cacheList)\n                tasks.Add(AddDataIntoCache(cache, itemAddToCache));\n            await Task.WhenAll(tasks);\n\n            //set cachePressureMonitor to be underPressure\n            this.cachePressureInjectionMonitor.isUnderPressure = false;\n            //set purgePredicate to be ShouldPurge\n            this.purgePredicate.ShouldPurge = true;\n\n            //perform purge\n            this.receiver1.TryPurgeFromCache(out _);\n            this.receiver2.TryPurgeFromCache(out _);\n\n            //Assert\n            int expectedItemCountInCaches = 0;\n            //items got purged\n            Assert.Equal(expectedItemCountInCaches, GetItemCountInAllCache(this.cacheList));\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task EventHubQueueCache_EvictionStrategy_Behavior()\n        {\n            InitForTesting();\n            var tasks = new List<Task>();\n            //add items into cache\n            int itemAddToCache = 100;\n            foreach (var cache in this.cacheList)\n                tasks.Add(AddDataIntoCache(cache, itemAddToCache));\n            await Task.WhenAll(tasks);\n\n            //set up condition so that purge will be performed\n            this.cachePressureInjectionMonitor.isUnderPressure = false;\n            this.purgePredicate.ShouldPurge = true;\n\n            //Each cache should each have buffers allocated\n            this.evictionStrategyList.ForEach(strategy => Assert.True(strategy.InUseBuffers.Count > 0));\n\n            //perform purge\n\n            //after purge, inUseBuffers should be purged and return to the pool, except for the current buffer\n            var expectedPurgedBuffers = new List<FixedSizeBuffer>();\n            this.evictionStrategyList.ForEach(strategy =>\n            {\n                var purgedBufferList = strategy.InUseBuffers.ToArray<FixedSizeBuffer>();\n                //last one in purgedBufferList should be current buffer, which shouldn't be purged\n                for (int i = 0; i < purgedBufferList.Count() - 1; i++)\n                    expectedPurgedBuffers.Add(purgedBufferList[i]);\n            });\n\n            IList<IBatchContainer> ignore;\n            this.receiver1.TryPurgeFromCache(out ignore);\n            this.receiver2.TryPurgeFromCache(out ignore);\n\n            //Each cache should have all buffers purged, except for current buffer\n            this.evictionStrategyList.ForEach(strategy => Assert.Single(strategy.InUseBuffers));\n            var oldBuffersInCaches = new List<FixedSizeBuffer>();\n            this.evictionStrategyList.ForEach(strategy => {\n                foreach (var inUseBuffer in strategy.InUseBuffers)\n                    oldBuffersInCaches.Add(inUseBuffer);\n                });\n            //add items into cache again\n            itemAddToCache = 100;\n            foreach (var cache in this.cacheList)\n                tasks.Add(AddDataIntoCache(cache, itemAddToCache));\n            await Task.WhenAll(tasks);\n            //block pool should have purged buffers returned by now, and used those to allocate buffer for new item\n            var newBufferAllocated = new List<FixedSizeBuffer>();\n            this.evictionStrategyList.ForEach(strategy => {\n                foreach (var inUseBuffer in strategy.InUseBuffers)\n                    newBufferAllocated.Add(inUseBuffer);\n            });\n            //remove old buffer in cache, to get newly allocated buffers after purge\n            newBufferAllocated.RemoveAll(buffer => oldBuffersInCaches.Contains(buffer));\n            //purged buffer should return to the pool after purge, and used to allocate new buffer\n            expectedPurgedBuffers.ForEach(buffer => Assert.Contains(buffer, newBufferAllocated));\n        }\n\n        private void InitForTesting()\n        {\n            this.cacheList = new ConcurrentBag<EventHubQueueCacheForTesting>();\n            this.evictionStrategyList = new List<EHEvictionStrategyForTesting>();\n            var monitorDimensions = new EventHubReceiverMonitorDimensions\n            {\n                EventHubPartition = this.ehSettings.Partition,\n                EventHubPath = this.ehSettings.Hub.EventHubName,\n            };\n\n            this.receiver1 = new EventHubAdapterReceiver(this.ehSettings, this.CacheFactory, this.CheckPointerFactory, NullLoggerFactory.Instance,\n                new DefaultEventHubReceiverMonitor(monitorDimensions), new LoadSheddingOptions(), environmentStatisticsProvider);\n            this.receiver2 = new EventHubAdapterReceiver(this.ehSettings, this.CacheFactory, this.CheckPointerFactory, NullLoggerFactory.Instance,\n                new DefaultEventHubReceiverMonitor(monitorDimensions), new LoadSheddingOptions(), environmentStatisticsProvider);\n            this.receiver1.Initialize(this.timeOut);\n            this.receiver2.Initialize(this.timeOut);\n        }\n\n        private int GetItemCountInAllCache(ConcurrentBag<EventHubQueueCacheForTesting> caches)\n        {\n            int itemCount = 0;\n            foreach (var cache in caches)\n            {\n                itemCount += cache.ItemCount;\n            }\n            return itemCount;\n        }\n\n        private static async Task AddDataIntoCache(EventHubQueueCacheForTesting cache, int count)\n        {\n            await Task.Delay(10);\n            List<EventData> messages = Enumerable.Range(0, count)\n                .Select(i => MakeEventData(i))\n                .ToList();\n            cache.Add(messages, DateTime.UtcNow);\n        }\n\n        private static EventData MakeEventData(long sequenceNumber)\n        {\n            var now = DateTime.UtcNow;\n            var eventData = EventHubsModelFactory.EventData(\n                eventBody: new BinaryData([12, 23]),\n                offsetString: now.Ticks.ToString(CultureInfo.InvariantCulture),\n                sequenceNumber: sequenceNumber,\n                enqueuedTime: now);\n            return eventData;\n        }\n\n        private Task<IStreamQueueCheckpointer<string>> CheckPointerFactory(string partition)\n        {\n            return Task.FromResult<IStreamQueueCheckpointer<string>>(NoOpCheckpointer.Instance);\n        }\n\n        private IEventHubQueueCache CacheFactory(string partition, IStreamQueueCheckpointer<string> checkpointer, ILoggerFactory loggerFactory)\n        {\n            var cacheLogger = loggerFactory.CreateLogger($\"{typeof(EventHubQueueCacheForTesting)}.{partition}\");\n            var evictionStrategy = new EHEvictionStrategyForTesting(cacheLogger, null, null, this.purgePredicate);\n            this.evictionStrategyList.Add(evictionStrategy);\n            var cache = new EventHubQueueCacheForTesting(\n                this.bufferPool,\n                new MockEventHubCacheAdaptor(this.serializer),\n                evictionStrategy,\n                checkpointer,\n                cacheLogger);\n            cache.AddCachePressureMonitor(this.cachePressureInjectionMonitor);\n            this.cacheList.Add(cache);\n            return cache;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/EvictionStrategyTests/TestMocks.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Azure.Messaging.EventHubs;\n\nnamespace ServiceBus.Tests.EvictionStrategyTests\n{\n    public class EventHubQueueCacheForTesting : EventHubQueueCache\n    {\n        public EventHubQueueCacheForTesting(IObjectPool<FixedSizeBuffer> bufferPool, IEventHubDataAdapter dataAdapter, IEvictionStrategy evictionStrategy, IStreamQueueCheckpointer<string> checkpointer,\n            ILogger logger)\n            :base(\"test\", EventHubAdapterReceiver.MaxMessagesPerRead, bufferPool, dataAdapter, evictionStrategy, checkpointer, logger, null, null, null)\n            { }\n\n        public int ItemCount => this.cache.ItemCount;\n    }\n    public class EHEvictionStrategyForTesting : ChronologicalEvictionStrategy\n    {\n        public EHEvictionStrategyForTesting(ILogger logger, ICacheMonitor cacheMonitor = null, TimeSpan? monitorWriteInterval = null, TimePurgePredicate timePurage = null)\n            :base(logger, timePurage, cacheMonitor, monitorWriteInterval)\n        { }\n\n        public Queue<FixedSizeBuffer> InUseBuffers => this.inUseBuffers;\n    }\n\n    public class MockEventHubCacheAdaptor : EventHubDataAdapter\n    {\n        private long sequenceNumberCounter = 0;\n        private readonly int eventIndex = 1;\n        private readonly string eventHubOffset = \"OffSet\";\n        public MockEventHubCacheAdaptor(Orleans.Serialization.Serializer serializer) : base(serializer)\n        { }\n\n        public override StreamPosition GetStreamPosition(string partition, EventData queueMessage)\n        {\n            var steamIdentity = StreamId.Create(\"EmptySpace\", Guid.NewGuid());\n            var sequenceToken = new EventHubSequenceTokenV2(this.eventHubOffset, this.sequenceNumberCounter++, this.eventIndex);\n            return new StreamPosition(steamIdentity, sequenceToken);\n        }\n    }\n\n    internal class CachePressureInjectionMonitor : ICachePressureMonitor\n    {\n        public bool isUnderPressure { get; set; }\n        public ICacheMonitor CacheMonitor { set; private get; }\n        public CachePressureInjectionMonitor()\n        {\n            this.isUnderPressure = false;\n        }\n\n        public void RecordCachePressureContribution(double cachePressureContribution)\n        {\n\n        }\n\n        public bool IsUnderPressure(DateTime utcNow)\n        {\n            return this.isUnderPressure;\n        }\n    }\n\n    internal class PurgeDecisionInjectionPredicate : TimePurgePredicate\n    {\n        public bool ShouldPurge { get; set; }\n        public PurgeDecisionInjectionPredicate(TimeSpan minTimeInCache, TimeSpan maxRelativeMessageAge)\n            : base(minTimeInCache, maxRelativeMessageAge)\n        {\n            this.ShouldPurge = false;\n        }\n\n        public override bool ShouldPurgeFromTime(TimeSpan timeInCache, TimeSpan relativeAge)\n        {\n            return this.ShouldPurge;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Orleans.Streaming.EventHubs.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Azure.Identity\" />\n    <PackageReference Include=\"System.Diagnostics.PerformanceCounter\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Persistence.AzureStorage\\Orleans.Persistence.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Streaming.EventHubs\\Orleans.Streaming.EventHubs.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Streaming.AzureStorage\\Orleans.Streaming.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Streaming.Tests\\Orleans.Streaming.Tests.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Azure.Tests\\Orleans.Azure.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/PluggableQueueBalancerTests.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.Hosting.Developer;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ServiceBus.Tests\n{\n    /// <summary>\n    /// Tests for pluggable queue balancer functionality with EventHub streaming provider.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n    public class PluggableQueueBalancerTestsWithEHStreamProvider : PluggableQueueBalancerTestBase, IClassFixture<PluggableQueueBalancerTestsWithEHStreamProvider.Fixture>\n    {\n        private const string StreamProviderName = \"EventHubStreamProvider\";\n        private static readonly int TotalQueueCount = 6;\n        private static readonly short SiloCount = 2;\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = SiloCount;\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddEventDataGeneratorStreams(\n                            StreamProviderName,\n                            b=>\n                            {\n                                b.Configure<EventDataGeneratorStreamOptions>(ob => ob.Configure(\n                                options =>\n                                {\n                                    options.EventHubPartitionCount = TotalQueueCount;\n                                }));\n                                b.ConfigurePartitionBalancing((s, n) => ActivatorUtilities.CreateInstance<LeaseBasedQueueBalancerForTest>(s, n));\n                            });\n                }\n            }\n        }\n\n        public PluggableQueueBalancerTestsWithEHStreamProvider(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/4317\"), TestCategory(\"BVT\")]\n        public Task PluggableQueueBalancerTest_ShouldUseInjectedQueueBalancerAndBalanceCorrectly()\n        {\n            return base.ShouldUseInjectedQueueBalancerAndBalanceCorrectly(this.fixture, StreamProviderName, SiloCount, TotalQueueCount);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/SlowConsumingTests/EHSlowConsumingTests.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing ServiceBus.Tests.TestStreamProviders;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace ServiceBus.Tests.SlowConsumingTests\n{\n    /// <summary>\n    /// Tests for EventHub slow consumer detection and back pressure algorithm behavior.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n    public class EHSlowConsumingTests : OrleansTestingBase, IClassFixture<EHSlowConsumingTests.Fixture>\n    {\n        private const string StreamProviderName = \"EventHubStreamProvider\";\n        private const string StreamNamespace = \"EHTestsNamespace\";\n        private static readonly string CheckpointNamespace = Guid.NewGuid().ToString();\n        private static readonly TimeSpan monitorPressureWindowSize = TimeSpan.FromSeconds(3);\n        private static readonly TimeSpan timeout = TimeSpan.FromSeconds(30);\n        private const double flowControlThredhold = 0.6;\n\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddPersistentStreams(\n                        StreamProviderName,\n                        EHStreamProviderWithCreatedCacheListAdapterFactory.Create,\n                        b=>\n                        {\n                            b.Configure<EventHubStreamCachePressureOptions>(ob => ob.Configure(options =>\n                            {\n                                options.SlowConsumingMonitorPressureWindowSize = monitorPressureWindowSize;\n                                options.SlowConsumingMonitorFlowControlThreshold = flowControlThredhold;\n                                options.AveragingCachePressureMonitorFlowControlThreshold = null;\n                            }));\n                            b.ConfigureComponent<IStreamQueueCheckpointerFactory>((s, n) => NoOpCheckpointerFactory.Instance);\n                            b.UseDynamicClusterConfigDeploymentBalancer();\n                        });\n                    hostBuilder.AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n        }\n\n        private readonly Random seed;\n\n        public EHSlowConsumingTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n            seed = new Random();\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task EHSlowConsuming_ShouldFavorSlowConsumer()\n        {\n            var streamGuid = Guid.NewGuid();\n            var streamId = StreamId.Create(StreamNamespace, streamGuid);\n            //set up one slow consumer grain\n            var slowConsumer = this.fixture.GrainFactory.GetGrain<ISlowConsumingGrain>(Guid.NewGuid());\n            await slowConsumer.BecomeConsumer(streamGuid, StreamNamespace, StreamProviderName);\n\n            //set up 30 healthy consumer grain to show how much we favor slow consumer \n            int healthyConsumerCount = 30;\n            var healthyConsumers = await SetUpHealthyConsumerGrain(this.fixture.GrainFactory, streamGuid, StreamNamespace, StreamProviderName, healthyConsumerCount);\n\n            //configure data generator for stream and start producing\n            var mgmtGrain = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n            var randomStreamPlacementArg = new EventDataGeneratorAdapterFactory.StreamRandomPlacementArg(streamId, this.seed.Next(100));\n            await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EventDataGeneratorAdapterFactory.Commands.Randomly_Place_Stream_To_Queue, randomStreamPlacementArg);\n            //since there's an extreme slow consumer, so the back pressure algorithm should be triggered\n            await TestingUtils.WaitUntilAsync(lastTry => AssertCacheBackPressureTriggered(true, lastTry), timeout);\n\n            //make slow consumer stop consuming\n            await slowConsumer.StopConsuming();\n\n            //slowConsumer stopped consuming, back pressure algorithm should be cleared in next check period.\n            await Task.Delay(monitorPressureWindowSize);\n            await TestingUtils.WaitUntilAsync(lastTry => AssertCacheBackPressureTriggered(false, lastTry), timeout);\n\n            //clean up test\n            await StopHealthyConsumerGrainComing(healthyConsumers);\n            await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EventDataGeneratorAdapterFactory.Commands.Stop_Producing_On_Stream, streamId);\n        }\n\n        public static async Task<List<ISampleStreaming_ConsumerGrain>> SetUpHealthyConsumerGrain(IGrainFactory GrainFactory, Guid streamId, string streamNameSpace, string streamProvider, int grainCount)\n        {\n            List<ISampleStreaming_ConsumerGrain> grains = new List<ISampleStreaming_ConsumerGrain>();\n            List<Task> tasks = new List<Task>();\n            while (grainCount > 0)\n            {\n                var consumer = GrainFactory.GetGrain<ISampleStreaming_ConsumerGrain>(Guid.NewGuid());\n                grains.Add(consumer);\n                tasks.Add(consumer.BecomeConsumer(streamId, streamNameSpace, streamProvider));\n                grainCount--;\n            }\n            await Task.WhenAll(tasks);\n            return grains;\n        }\n\n        private static async Task StopHealthyConsumerGrainComing(List<ISampleStreaming_ConsumerGrain> grains)\n        {\n            List<Task> tasks = new List<Task>();\n            foreach (var grain in grains)\n            {\n                tasks.Add(grain.StopConsuming());\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        private async Task<bool> AssertCacheBackPressureTriggered(bool expectedResult, bool assertIsTrue)\n        {\n            if (assertIsTrue)\n            {\n                bool actualResult = await IsBackPressureTriggered();\n                Assert.True(expectedResult == actualResult, $\"Back pressure algorithm should be triggered? expected: {expectedResult}, actual: {actualResult}\");\n                return true;\n            }\n            else\n            {\n                return (await IsBackPressureTriggered()) == expectedResult;\n            }\n        }\n\n        private async Task<bool> IsBackPressureTriggered()\n        {\n            IManagementGrain mgmtGrain = this.fixture.HostedCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n            object[] replies = await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(\n                             StreamProviderName, EHStreamProviderWithCreatedCacheListAdapterFactory.IsCacheBackPressureTriggeredCommand, null);\n            foreach (var re in replies)\n            {\n                if ((bool)re)\n                    return true;\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/StatisticMonitorTests/BlockPoolMonitorForTesting.cs",
    "content": "﻿using Orleans.Providers.Streams.Common;\n\nnamespace ServiceBus.Tests.MonitorTests\n{\n    public class BlockPoolMonitorForTesting : IBlockPoolMonitor\n    {\n        public ObjectPoolMonitorCounters CallCounters { get; } = new ObjectPoolMonitorCounters();\n \n        public void TrackMemoryAllocated(long allocatedMemoryInByte)\n        {\n            Interlocked.Increment(ref this.CallCounters.TrackObjectAllocatedByCacheCallCounter);\n        }\n\n        public void TrackMemoryReleased(long releasedMemoryInByte)\n        {\n            Interlocked.Increment(ref this.CallCounters.TrackObjectReleasedFromCacheCallCounter);\n        }\n\n        public void Report(long totalMemoryInByte, long availableMemoryInByte, long claimedMemoryInByte)\n        {\n            Interlocked.Increment(ref this.CallCounters.ReportCallCounter);\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class ObjectPoolMonitorCounters\n    {\n        [Orleans.Id(0)]\n        public int TrackObjectAllocatedByCacheCallCounter;\n        [Orleans.Id(1)]\n        public int TrackObjectReleasedFromCacheCallCounter;\n        [Orleans.Id(2)]\n        public int ReportCallCounter;\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/StatisticMonitorTests/CacheMonitorForTesting.cs",
    "content": "﻿using Orleans.Providers.Streams.Common;\n\nnamespace ServiceBus.Tests.MonitorTests\n{\n    public class CacheMonitorForTesting : ICacheMonitor\n    {\n        public CacheMonitorCounters CallCounters { get; } = new CacheMonitorCounters();\n        \n        public void TrackCachePressureMonitorStatusChange(string pressureMonitorType, bool underPressure, double? cachePressureContributionCount, double? currentPressure,\n            double? flowControlThreshold)\n        {\n            Interlocked.Increment(ref CallCounters.TrackCachePressureMonitorStatusChangeCallCounter);\n        }\n\n        public void ReportCacheSize(long totalCacheSizeInByte)\n        {\n            Interlocked.Increment(ref CallCounters.ReportCacheSizeCallCounter);\n        }\n\n        public void ReportMessageStatistics(DateTime? oldestMessageEnqueueTimeUtc, DateTime? oldestMessageDequeueTimeUtc, DateTime? newestMessageEnqueueTimeUtc, long totalMessageCount)\n        {\n            Interlocked.Increment(ref CallCounters.ReportMessageStatisticsCallCounter);\n        }\n\n        public void TrackMemoryAllocated(int memoryInByte)\n        {\n            Interlocked.Increment(ref CallCounters.TrackMemoryAllocatedCallCounter);\n        }\n\n        public void TrackMemoryReleased(int memoryInByte)\n        {\n            Interlocked.Increment(ref CallCounters.TrackMemoryReleasedCallCounter);\n        }\n\n        public void TrackMessagesAdded(long mesageAdded)\n        {\n            Interlocked.Increment(ref CallCounters.TrackMessageAddedCounter);\n        }\n\n        public void TrackMessagesPurged(long messagePurged)\n        {\n            Interlocked.Increment(ref CallCounters.TrackMessagePurgedCounter);\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class CacheMonitorCounters\n    {\n        [Orleans.Id(0)]\n        public int TrackCachePressureMonitorStatusChangeCallCounter;\n        [Orleans.Id(1)]\n        public int ReportCacheSizeCallCounter;\n        [Orleans.Id(2)]\n        public int ReportMessageStatisticsCallCounter;\n        [Orleans.Id(3)]\n        public int TrackMemoryAllocatedCallCounter;\n        [Orleans.Id(4)]\n        public int TrackMemoryReleasedCallCounter;\n        [Orleans.Id(5)]\n        public int TrackMessageAddedCounter;\n        [Orleans.Id(6)]\n        public int TrackMessagePurgedCounter;\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/StatisticMonitorTests/EHStatisticMonitorTests.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing ServiceBus.Tests.TestStreamProviders;\nusing TestExtensions;\nusing UnitTests.Grains.ProgrammaticSubscribe;\nusing Xunit;\nusing ServiceBus.Tests.SlowConsumingTests;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ServiceBus.Tests.MonitorTests\n{\n    /// <summary>\n    /// Tests for EventHub statistics monitoring including receiver, cache, and object pool monitor counters.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n    public class EHStatisticMonitorTests : OrleansTestingBase, IClassFixture<EHStatisticMonitorTests.Fixture>\n    {\n        private const string StreamProviderName = \"EventHubStreamProvider\";\n        private const string StreamNamespace = \"EHTestsNamespace\";\n        private static readonly TimeSpan timeout = TimeSpan.FromSeconds(5);\n        private static readonly TimeSpan monitorWriteInterval = TimeSpan.FromSeconds(2);\n        private static readonly int ehPartitionCountPerSilo = 4;\n\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddPersistentStreams(\n                            StreamProviderName,\n                            EHStreamProviderForMonitorTestsAdapterFactory.Create,\n                            b=>\n                            {\n                                b.ConfigureComponent<IStreamQueueCheckpointerFactory>((s, n) => NoOpCheckpointerFactory.Instance);\n                                b.Configure<StreamStatisticOptions>(ob => ob.Configure(options => options.StatisticMonitorWriteInterval = monitorWriteInterval));\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                            });\n                    hostBuilder\n                        .ConfigureServices(services =>\n                        {\n                            services.AddKeyedTransient(StreamProviderName, (s, n) => SimpleStreamEventDataGenerator.CreateFactory(s));\n                        })\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n        }\n\n        private readonly Random seed;\n\n        public EHStatisticMonitorTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n            seed = new Random();\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/4594\"), TestCategory(\"Functional\")]\n        public async Task EHStatistics_MonitorCalledAccordingly()\n        {\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), StreamNamespace, StreamProviderName);\n            //set up 30 healthy consumer grain to show how much we favor slow consumer \n            int healthyConsumerCount = 30;\n            _ = await EHSlowConsumingTests.SetUpHealthyConsumerGrain(this.fixture.GrainFactory, streamId.Guid, StreamNamespace, StreamProviderName, healthyConsumerCount);\n\n            //configure data generator for stream and start producing\n            var mgmtGrain = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n            var randomStreamPlacementArg = new EHStreamProviderForMonitorTestsAdapterFactory.StreamRandomPlacementArg(streamId, this.seed.Next(100));\n            await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EHStreamProviderForMonitorTestsAdapterFactory.Commands.Randomly_Place_Stream_To_Queue, randomStreamPlacementArg);\n\n            // let the test to run for a while to build up some streaming traffic\n            await Task.Delay(timeout);\n            //wait sometime after cache pressure changing, for the system to notice it and trigger cache monitor to track it\n            await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EHStreamProviderForMonitorTestsAdapterFactory.QueryCommands.ChangeCachePressure, null);\n            await Task.Delay(timeout);\n\n            //assert EventHubReceiverMonitor call counters\n            var receiverMonitorCounters = await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EHStreamProviderForMonitorTestsAdapterFactory.QueryCommands.GetReceiverMonitorCallCounters, null);\n            foreach (var callCounter in receiverMonitorCounters)\n            {\n                AssertReceiverMonitorCallCounters(callCounter as EventHubReceiverMonitorCounters);\n            }\n\n            var cacheMonitorCounters = await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n                (int)EHStreamProviderForMonitorTestsAdapterFactory.QueryCommands.GetCacheMonitorCallCounters, null);\n            foreach (var callCounter in cacheMonitorCounters)\n            {\n                AssertCacheMonitorCallCounters(callCounter as CacheMonitorCounters);\n            }\n\n            var objectPoolMonitorCounters = await mgmtGrain.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName,\n             (int)EHStreamProviderForMonitorTestsAdapterFactory.QueryCommands.GetObjectPoolMonitorCallCounters, null);\n            foreach (var callCounter in objectPoolMonitorCounters)\n            {\n                AssertObjectPoolMonitorCallCounters(callCounter as ObjectPoolMonitorCounters);\n            }\n        }\n\n        private static void AssertCacheMonitorCallCounters(CacheMonitorCounters totalCacheMonitorCallCounters)\n        {\n            var c = totalCacheMonitorCallCounters;\n            Assert.True(c.TrackCachePressureMonitorStatusChangeCallCounter > 0,\n                $\"Expected {nameof(c.TrackCachePressureMonitorStatusChangeCallCounter)} > 0, got {c.TrackCachePressureMonitorStatusChangeCallCounter}\");\n            Assert.True(c.TrackMemoryAllocatedCallCounter > 0, $\"Expected {nameof(c.TrackMemoryAllocatedCallCounter)} > 0, got {c.TrackMemoryAllocatedCallCounter}\");\n            Assert.True(0 == c.TrackMemoryReleasedCallCounter, $\"Expected {nameof(c.TrackMemoryReleasedCallCounter)} == 0, got {c.TrackMemoryReleasedCallCounter}\");\n            Assert.True(c.TrackMessageAddedCounter > 0, $\"Expected {nameof(c.TrackMessageAddedCounter)} > 0, got {c.TrackMessageAddedCounter}\");\n            Assert.True(0 == c.TrackMessagePurgedCounter, $\"Expected {nameof(c.TrackMessagePurgedCounter)} == 0, got {c.TrackMessagePurgedCounter}\");\n        }\n\n        private static void AssertReceiverMonitorCallCounters(EventHubReceiverMonitorCounters totalReceiverMonitorCallCounters)\n        {\n            var c = totalReceiverMonitorCallCounters;\n            Assert.True(ehPartitionCountPerSilo == c.TrackInitializationCallCounter, $\"Expected {nameof(c.TrackInitializationCallCounter)} == {ehPartitionCountPerSilo}, got {c.TrackInitializationCallCounter}\");\n            Assert.True(c.TrackMessagesReceivedCallCounter > 0, $\"Expected {nameof(c.TrackMessagesReceivedCallCounter)} > 0, got {c.TrackMessagesReceivedCallCounter}\");\n            Assert.True(c.TrackReadCallCounter > 0, $\"Expected {nameof(c.TrackReadCallCounter)} > 0, got {c.TrackReadCallCounter}\");\n            Assert.True(0 == c.TrackShutdownCallCounter, $\"Expected {nameof(c.TrackShutdownCallCounter)} == 0, got {c.TrackShutdownCallCounter}\");\n        }\n\n        private static void AssertObjectPoolMonitorCallCounters(ObjectPoolMonitorCounters totalObjectPoolMonitorCallCounters)\n        {\n            var c = totalObjectPoolMonitorCallCounters;\n            Assert.True(c.TrackObjectAllocatedByCacheCallCounter > 0, $\"Expected {nameof(c.TrackObjectAllocatedByCacheCallCounter)} > 0, got {c.TrackObjectAllocatedByCacheCallCounter}\");\n            Assert.True(0 == c.TrackObjectReleasedFromCacheCallCounter, $\"Expected {nameof(c.TrackObjectReleasedFromCacheCallCounter)} == 0, got {c.TrackObjectReleasedFromCacheCallCounter}\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/StatisticMonitorTests/EventHubReceiverMonitorForTesting.cs",
    "content": "using Orleans.Providers.Streams.Common;\n\nnamespace ServiceBus.Tests.MonitorTests\n{\n    public class EventHubReceiverMonitorForTesting : IQueueAdapterReceiverMonitor\n    {\n        public EventHubReceiverMonitorCounters CallCounters { get; } = new EventHubReceiverMonitorCounters();\n\n        public void TrackInitialization(bool success, TimeSpan callTime, Exception exception)\n        {\n            if(success) Interlocked.Increment(ref this.CallCounters.TrackInitializationCallCounter);\n        }\n\n        public void TrackRead(bool success, TimeSpan callTime, Exception exception)\n        {\n            if (success) Interlocked.Increment(ref this.CallCounters.TrackReadCallCounter);\n        }\n\n        public void TrackMessagesReceived(long count, DateTime? oldestEnqueueTime, DateTime? newestEnqueueTime)\n        {\n            Interlocked.Increment(ref this.CallCounters.TrackMessagesReceivedCallCounter);\n        }\n\n        public void TrackShutdown(bool success, TimeSpan callTime, Exception exception)\n        {\n            Interlocked.Increment(ref this.CallCounters.TrackShutdownCallCounter);\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class EventHubReceiverMonitorCounters \n    {\n        [Orleans.Id(0)]\n        public int TrackInitializationCallCounter;\n        [Orleans.Id(1)]\n        public int TrackReadCallCounter;\n        [Orleans.Id(2)]\n        public int TrackMessagesReceivedCallCounter;\n        [Orleans.Id(3)]\n        public int TrackShutdownCallCounter;\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHBatchedSubscriptionMultiplicityTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub subscription multiplicity scenarios with batched message processing.\n    /// </summary>\n    public class EHBatchedSubscriptionMultiplicityTests : OrleansTestingBase, IClassFixture<EHBatchedSubscriptionMultiplicityTests.Fixture>\n    {\n        private const string StreamProviderName = \"EHStreamPerPartition\";\n        private const string StreamNamespace = \"EHPullingAgentBatchingTests\";\n        private const string EHPath = \"ehorleanstest\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        private readonly SubscriptionMultiplicityTestRunner runner;\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddEventHubStreams(StreamProviderName,\n                            b =>\n                            {\n                                b.ConfigureEventHub(ob => ob.Configure(options =>\n                                {\n                                    options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                                }));\n                                b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                                 {\n                                     options.ConfigureTestDefaults();\n                                     options.PersistInterval = TimeSpan.FromSeconds(10);\n                                 }));\n                                b.ConfigurePullingAgent(ob => ob.Configure(options =>\n                                 {\n                                    // sets up batching in the pulling agent\n                                    options.BatchContainerBatchSize = 10;\n                                 }));\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                            });\n                }\n            }\n        }\n\n        public EHBatchedSubscriptionMultiplicityTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            this.runner = new SubscriptionMultiplicityTestRunner(StreamProviderName, fixture.HostedCluster);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedMultipleParallelSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedMultipleParallelSubscriptionTest *********************************\");\n            await runner.MultipleParallelSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedMultipleLinearSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedMultipleLinearSubscriptionTest *********************************\");\n            await runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedMultipleSubscriptionTest_AddRemove()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedMultipleSubscriptionTest_AddRemove *********************************\");\n            await runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedResubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedResubscriptionTest *********************************\");\n            await runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedResubscriptionAfterDeactivationTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedResubscriptionAfterDeactivationTest *********************************\");\n            await runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedActiveSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedActiveSubscriptionTest *********************************\");\n            await runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHBatchedTwoIntermitentStreamTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHBatchedTwoIntermitentStreamTest *********************************\");\n            await runner.TwoIntermitentStreamTest(Guid.NewGuid());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHClientStreamTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing ServiceBus.Tests.TestStreamProviders.EventHub;\nusing Tester;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub streaming functionality with client producer/consumer scenarios and dropped client handling.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHClientStreamTests : TestClusterPerTest\n    {\n        private const string StreamProviderName = \"EventHubStreamProvider\";\n        private const string StreamNamespace = \"StreamNamespace\";\n        private const string EHPath = \"ehorleanstest\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        private readonly ITestOutputHelper output;\n        private ClientStreamTestRunner runner;\n        public EHClientStreamTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            runner = new ClientStreamTestRunner(this.HostedCluster);\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForEventHub();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddPersistentStreams(StreamProviderName, TestEventHubStreamAdapterFactory.Create, b=>\n                    {\n                        b.Configure<SiloMessagingOptions>(ob => ob.Configure(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5)));\n                        b.Configure<EventHubOptions>(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.ConfigureComponent<AzureTableStreamCheckpointerOptions, IStreamQueueCheckpointerFactory>(\n                            EventHubCheckpointerFactory.CreateFactory,\n                            ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(10);\n                            }));\n                    })\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .ConfigureServices(services => services.TryAddSingleton<IEventHubDataAdapter, EventHubDataAdapter>());\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddPersistentStreams(StreamProviderName, TestEventHubStreamAdapterFactory.Create, b=>b\n                        .Configure<EventHubOptions>(ob=>ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        })))\n                    .ConfigureServices(services => services.TryAddSingleton<IEventHubDataAdapter, EventHubDataAdapter>());\n            }\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5657\")]\n        public async Task EHStreamProducerOnDroppedClientTest()\n        {\n            logger.LogInformation(\"************************ EHStreamProducerOnDroppedClientTest *********************************\");\n            await runner.StreamProducerOnDroppedClientTest(StreamProviderName, StreamNamespace);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5634\")]\n        public async Task EHStreamConsumerOnDroppedClientTest()\n        {\n            logger.LogInformation(\"************************ EHStreamConsumerOnDroppedClientTest *********************************\");\n            await runner.StreamConsumerOnDroppedClientTest(StreamProviderName, StreamNamespace, output,\n                    () => TestAzureTableStorageStreamFailureHandler.GetDeliveryFailureCount(StreamProviderName), true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHImplicitSubscriptionStreamRecoveryTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing TestGrains;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub stream recovery with implicit subscriptions handling transient and non-transient errors.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHImplicitSubscriptionStreamRecoveryTests : OrleansTestingBase, IClassFixture<EHImplicitSubscriptionStreamRecoveryTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n        private const string EHPath = \"ehorleanstest2\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        private readonly ImplicitSubscritionRecoverableStreamTestRunner runner;\n\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                // poor fault injection requires grain instances stay on same host, so only single host for this test\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddEventHubStreams(StreamProviderName, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(1);\n                            }));\n                            b.UseDynamicClusterConfigDeploymentBalancer();\n                            b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        });\n                    hostBuilder\n                        .AddMemoryGrainStorageAsDefault();\n                }\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddEventHubStreams(StreamProviderName, b=>\n                    {\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                         {\n                             options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                         }));\n                    });\n                }\n            }\n        }\n\n        public EHImplicitSubscriptionStreamRecoveryTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n            this.runner = new ImplicitSubscritionRecoverableStreamTestRunner(this.fixture.GrainFactory, StreamProviderName);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5633\")]\n        public async Task Recoverable100EventStreamsWithTransientErrorsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHRecoverable100EventStreamsWithTransientErrorsTest *********************************\");\n            await runner.Recoverable100EventStreamsWithTransientErrors(GenerateEvents, ImplicitSubscription_TransientError_RecoverableStream_CollectorGrain.StreamNamespace, 4, 100);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5638\")]\n        public async Task Recoverable100EventStreamsWith1NonTransientErrorTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHRecoverable100EventStreamsWith1NonTransientErrorTest *********************************\");\n            await runner.Recoverable100EventStreamsWith1NonTransientError(GenerateEvents, ImplicitSubscription_NonTransientError_RecoverableStream_CollectorGrain.StreamNamespace, 4, 100);\n        }\n\n        private async Task GenerateEvents(string streamNamespace, int streamCount, int eventsInStream)\n        {\n            IStreamProvider streamProvider = this.fixture.HostedCluster.ServiceProvider.GetKeyedService<IStreamProvider>(StreamProviderName);\n            IAsyncStream<GeneratedEvent>[] producers =\n                Enumerable.Range(0, streamCount)\n                    .Select(i => streamProvider.GetStream<GeneratedEvent>(streamNamespace, Guid.NewGuid()))\n                    .ToArray();\n\n            for (int i = 0; i < eventsInStream - 1; i++)\n            {\n                // send event on each stream\n                for (int j = 0; j < streamCount; j++)\n                {\n                    await producers[j].OnNextAsync(new GeneratedEvent { EventType = GeneratedEvent.GeneratedEventType.Fill });\n                }\n            }\n            // send end events\n            for (int j = 0; j < streamCount; j++)\n            {\n                await producers[j].OnNextAsync(new GeneratedEvent { EventType = GeneratedEvent.GeneratedEventType.Report });\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHProgrammaticSubscribeTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace ServiceBus.Tests.Streaming\n{\n    /// <summary>\n    /// Tests for EventHub programmatic subscription functionality with multiple stream providers.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHProgrammaticSubscribeTest : ProgrammaticSubscribeTestsRunner, IClassFixture<EHProgrammaticSubscribeTest.Fixture>\n    {\n        private const string EHPath = \"ehorleanstest4\";\n        private const string EHPath2 = \"ehorleanstest3\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n                builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n            }\n\n            private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddEventHubStreams(StreamProviderName, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(10);\n                            }));\n                        });\n\n                    hostBuilder\n                        .AddEventHubStreams(StreamProviderName2, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath2, EHConsumerGroup);\n\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(10);\n                            }));\n                        });\n\n                    hostBuilder\n                          .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n            }\n        }\n\n        public EHProgrammaticSubscribeTest(ITestOutputHelper output, Fixture fixture)\n            : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHStreamBatchingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace ServiceBus.Tests.Streaming\n{\n    /// <summary>\n    /// Tests for EventHub stream batching functionality with implicit subscriptions.\n    /// </summary>\n    [TestCategory(\"EventHub\")]\n    public class EHStreamBatchingTests : StreamBatchingTestRunner, IClassFixture<EHStreamBatchingTests.Fixture>\n    {\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            private const string EHPath = \"ehorleanstest7\";\n            private const string EHConsumerGroup = \"orleansnightly\";\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddEventHubStreams(StreamBatchingTestConst.ProviderName, b =>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(1);\n                            }));\n                            b.UseDynamicClusterConfigDeploymentBalancer();\n                            b.ConfigurePullingAgent(ob => ob.Configure(options =>\n                            {\n                                options.BatchContainerBatchSize = 10;\n                            }));\n                            b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        });\n                    hostBuilder\n                        .AddMemoryGrainStorageAsDefault();\n                }\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddEventHubStreams(StreamBatchingTestConst.ProviderName, b =>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n                }\n            }\n        }\n\n        public EHStreamBatchingTests(Fixture fixture, ITestOutputHelper output)\n            : base(fixture, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHStreamCacheMissTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit.Abstractions;\nusing Orleans.Streaming.EventHubs;\nusing Tester;\nusing Microsoft.Extensions.DependencyInjection;\nusing Tester.StreamingTests;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub streaming cache miss scenarios with custom stream filters and cache eviction.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\"), TestCategory(\"StreamingCacheMiss\")]\n    public class EHStreamCacheMissTests : StreamingCacheMissTests\n    {\n        private const string EHPath = \"ehorleanstest\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        public EHStreamCacheMissTests(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForEventHub();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        #region Configuration stuff\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddEventHubStreams(StreamProviderName, b =>\n                    {\n                        b.ConfigureCacheEviction(ob => ob.Configure(options =>\n                        {\n                            options.DataMaxAgeInCache = TimeSpan.FromSeconds(5);\n                            options.DataMinTimeInCache = TimeSpan.FromSeconds(0);\n                            options.MetadataMinTimeInCache = TimeSpan.FromMinutes(1);\n                        }));\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.PersistInterval = TimeSpan.FromSeconds(10);\n                        }));\n                        b.UseDataAdapter((sp, n) => ActivatorUtilities.CreateInstance<EventHubDataAdapter>(sp));\n                    })\n                    .AddStreamFilter<CustomStreamFilter>(StreamProviderName);\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddEventHubStreams(StreamProviderName, b =>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.UseDataAdapter((sp, n) => ActivatorUtilities.CreateInstance<EventHubDataAdapter>(sp));\n                    });\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHStreamPerPartitionTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing ServiceBus.Tests.TestStreamProviders.EventHub;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub stream-per-partition data adapter functionality.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHStreamPerPartitionTests : OrleansTestingBase, IClassFixture<EHStreamPerPartitionTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private const string StreamProviderName = \"EHStreamPerPartition\";\n        private const string EHPath = \"ehorleanstest5\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddEventHubStreams(StreamProviderName, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(1);\n                            }));\n                            b.UseDynamicClusterConfigDeploymentBalancer();\n                            b.UseDataAdapter((s,n) => ActivatorUtilities.CreateInstance<StreamPerPartitionDataAdapter>(s));\n                        });\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder\n                        .AddEventHubStreams(StreamProviderName, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                            }));\n                            b.UseDataAdapter((s, n) => ActivatorUtilities.CreateInstance<StreamPerPartitionDataAdapter>(s));\n                        });\n                }\n            }\n        }\n\n        public EHStreamPerPartitionTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n        }\n\n        [SkippableFact(Skip = \"Not sure what this test is testing, also the hacky test approach would make this test fail if there's any messages in the hub\" +\n                              \"left from previous tests\")]\n        public async Task EH100StreamsTo4PartitionStreamsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EH100StreamsTo4PartitionStreamsTest *********************************\");\n\n            int streamCount = 100;\n            int eventsInStream = 10;\n            int partitionCount = 4;\n\n            List<ISampleStreaming_ConsumerGrain> consumers = new List<ISampleStreaming_ConsumerGrain>(partitionCount);\n            for (int i = 0; i < partitionCount; i++)\n            {\n                consumers.Add(this.fixture.GrainFactory.GetGrain<ISampleStreaming_ConsumerGrain>(Guid.NewGuid()));\n            }\n\n            // subscribe to each partition\n            List<Task> becomeConsumersTasks = consumers\n                .Select( (consumer, i) => consumer.BecomeConsumer(StreamPerPartitionDataAdapter.GetPartitionGuid(i.ToString()), null, StreamProviderName))\n                .ToList();\n            await Task.WhenAll(becomeConsumersTasks);\n\n            await GenerateEvents(streamCount, eventsInStream);\n            await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(consumers, streamCount * eventsInStream, assertIsTrue), TimeSpan.FromSeconds(30));\n        }\n\n        private async Task GenerateEvents(int streamCount, int eventsInStream)\n        {\n            IStreamProvider streamProvider = this.fixture.Client.GetStreamProvider(StreamProviderName);\n            IAsyncStream<int>[] producers =\n                Enumerable.Range(0, streamCount)\n                    .Select(i => streamProvider.GetStream<int>(Guid.NewGuid()))\n                    .ToArray();\n\n            for (int i = 0; i < eventsInStream; i++)\n            {\n                // send event on each stream\n                for (int j = 0; j < streamCount; j++)\n                {\n                    await producers[j].OnNextAsync(i);\n                }\n            }\n        }\n\n        private static async Task<bool> CheckCounters(List<ISampleStreaming_ConsumerGrain> consumers, int totalEventCount, bool assertIsTrue)\n        {\n            List<Task<int>> becomeConsumersTasks = consumers\n                .Select((consumer, i) => consumer.GetNumberConsumed())\n                .ToList();\n            int[] counts = await Task.WhenAll(becomeConsumersTasks);\n\n            if (assertIsTrue)\n            {\n                // one stream per queue\n                Assert.Equal(totalEventCount, counts.Sum());\n            }\n            else if (totalEventCount != counts.Sum())\n            {\n                return false;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHStreamProviderCheckpointTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing TestGrainInterfaces;\nusing TestGrains;\nusing UnitTests.Grains;\nusing Xunit;\nusing Orleans.Configuration;\nusing Tester;\nusing Tester.AzureUtils;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub stream provider checkpoint and recovery functionality after agent restarts or silo failures.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHStreamProviderCheckpointTests : TestClusterPerTest\n    {\n        private static readonly string StreamProviderTypeName = typeof(PersistentStreamProvider).FullName;\n        private const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n        private const string EHPath = \"ehorleanstest6\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForEventHub();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddAzureBlobGrainStorage(\n                        ImplicitSubscription_RecoverableStream_CollectorGrain.StorageProviderName,\n                        (AzureBlobStorageOptions options) =>\n                        {\n                            options.ConfigureTestDefaults();\n                        })\n                    .AddEventHubStreams(StreamProviderName, b=>\n                    {\n                        b.UseDynamicClusterConfigDeploymentBalancer();\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                        b.ConfigureEventHub(ob => ob.Configure(\n                            options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n\n                            }));\n\n                        b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.PersistInterval = TimeSpan.FromSeconds(1);\n                        }));\n                    });\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddEventHubStreams(StreamProviderName, b=>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n            }\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5356\")]\n        public async Task ReloadFromCheckpointTest()\n        {\n            logger.LogInformation(\"************************ EHReloadFromCheckpointTest *********************************\");\n            await this.ReloadFromCheckpointTestRunner(ImplicitSubscription_RecoverableStream_CollectorGrain.StreamNamespace, 1, 256);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5356\")]\n        public async Task RestartSiloAfterCheckpointTest()\n        {\n            logger.LogInformation(\"************************ EHRestartSiloAfterCheckpointTest *********************************\");\n            await this.RestartSiloAfterCheckpointTestRunner(ImplicitSubscription_RecoverableStream_CollectorGrain.StreamNamespace, 8, 32);\n        }\n\n        private async Task ReloadFromCheckpointTestRunner(string streamNamespace, int streamCount, int eventsInStream)\n        {\n            List<Guid> streamGuids = Enumerable.Range(0, streamCount).Select(_ => Guid.NewGuid()).ToList();\n            try\n            {\n                await GenerateEvents(streamNamespace, streamGuids, eventsInStream, 4096);\n                await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(streamNamespace, streamCount, eventsInStream, assertIsTrue), TimeSpan.FromSeconds(60));\n\n                await RestartAgents();\n\n                await GenerateEvents(streamNamespace, streamGuids, eventsInStream, 4096);\n                await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(streamNamespace, streamCount, eventsInStream * 2, assertIsTrue), TimeSpan.FromSeconds(90));\n            }\n            finally\n            {\n                var reporter = this.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n                reporter.Reset().Ignore();\n            }\n        }\n\n        private async Task RestartSiloAfterCheckpointTestRunner(string streamNamespace, int streamCount, int eventsInStream)\n        {\n            List<Guid> streamGuids = Enumerable.Range(0, streamCount).Select(_ => Guid.NewGuid()).ToList();\n            try\n            {\n                await GenerateEvents(streamNamespace, streamGuids, eventsInStream, 0);\n                await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(streamNamespace, streamCount, eventsInStream, assertIsTrue), TimeSpan.FromSeconds(60));\n\n                await HostedCluster.RestartSiloAsync(HostedCluster.SecondarySilos[0]);\n                await HostedCluster.WaitForLivenessToStabilizeAsync();\n\n                await GenerateEvents(streamNamespace, streamGuids, eventsInStream, 0);\n                await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(streamNamespace, streamCount, eventsInStream * 2, assertIsTrue), TimeSpan.FromSeconds(90));\n            }\n            finally\n            {\n                var reporter = this.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n                reporter.Reset().Ignore();\n            }\n        }\n\n        private async Task<bool> CheckCounters(string streamNamespace, int streamCount, int eventsInStream, bool assertIsTrue)\n        {\n            var reporter = this.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n\n            var report = await reporter.GetReport(StreamProviderName, streamNamespace);\n            if (assertIsTrue)\n            {\n                // one stream per queue\n                Assert.Equal(streamCount, report.Count);\n                foreach (int eventsPerStream in report.Values)\n                {\n                    Assert.Equal(eventsInStream, eventsPerStream);\n                }\n            }\n            else if (streamCount != report.Count ||\n                     report.Values.Any(count => count != eventsInStream))\n            {\n                return false;\n            }\n            return true;\n        }\n\n        private async Task RestartAgents()\n        {\n            var mgmt = this.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName, (int)PersistentStreamProviderCommand.StopAgents, null);\n            await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(StreamProviderName, (int)PersistentStreamProviderCommand.StartAgents, null);\n        }\n\n        private async Task GenerateEvents(string streamNamespace, List<Guid> streamGuids, int eventsInStream, int payloadSize)\n        {\n            IStreamProvider streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n            IAsyncStream<GeneratedEvent>[] producers = streamGuids\n                    .Select(streamGuid => streamProvider.GetStream<GeneratedEvent>(streamNamespace, streamGuid))\n                    .ToArray();\n\n            for (int i = 0; i < eventsInStream - 1; i++)\n            {\n                // send event on each stream\n                for (int j = 0; j < streamGuids.Count; j++)\n                {\n                    await producers[j].OnNextAsync(new GeneratedEvent { EventType = GeneratedEvent.GeneratedEventType.Fill, Payload = new int[payloadSize] });\n                }\n            }\n            // send end events\n            for (int j = 0; j < streamGuids.Count; j++)\n            {\n                await producers[j].OnNextAsync(new GeneratedEvent { EventType = GeneratedEvent.GeneratedEventType.Report, Payload = new int[payloadSize] });\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHStreamingResumeTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.TestingHost;\nusing Tester;\nusing Tester.StreamingTests;\nusing TestExtensions;\n\nnamespace ServiceBus.Tests.Streaming\n{\n    /// <summary>\n    /// Tests for EventHub streaming resume functionality with configurable cache eviction and stream inactivity settings.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"StreamingResume\")]\n    public class EHStreamingResumeTests : StreamingResumeTests\n    {\n        private const string EHPath = \"ehorleanstest\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddEventHubStreams(StreamProviderName, b =>\n                    {\n                        b.ConfigurePullingAgent(ob => ob.Configure(options =>\n                        {\n                            options.StreamInactivityPeriod = StreamInactivityPeriod;\n                        }));\n                        b.ConfigureCacheEviction(ob => ob.Configure(options =>\n                        {\n                            options.MetadataMinTimeInCache = MetadataMinTimeInCache;\n                            options.DataMaxAgeInCache = DataMaxAgeInCache;\n                            options.DataMinTimeInCache = DataMinTimeInCache;\n                        }));\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.PersistInterval = TimeSpan.FromSeconds(10);\n                        }));\n                        b.UseDataAdapter((sp, n) => ActivatorUtilities.CreateInstance<EventHubDataAdapter>(sp));\n                    });\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddEventHubStreams(StreamProviderName, b =>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                    });\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow() => TestUtils.CheckForEventHub();\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            TestUtils.CheckForEventHub();\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHSubscriptionMultiplicityTests.cs",
    "content": "using System.Diagnostics.Metrics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub subscription multiplicity scenarios including parallel, linear, and resubscription behaviors.\n    /// </summary>\n    [TestCategory(\"Functional\")]\n    public class EHSubscriptionMultiplicityTests : OrleansTestingBase, IClassFixture<EHSubscriptionMultiplicityTests.Fixture>\n    {\n        private const string StreamProviderName = \"EventHubStreamProvider\";\n        private const string StreamNamespace = \"EHSubscriptionMultiplicityTestsNamespace\";\n        private const string EHPath = \"ehorleanstest7\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        private readonly SubscriptionMultiplicityTestRunner runner;\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddEventHubStreams(StreamProviderName, b=>\n                        {\n                            b.ConfigureEventHub(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n\n                            }));\n                            b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                            {\n                                options.ConfigureTestDefaults();\n                                options.PersistInterval = TimeSpan.FromSeconds(1);\n                            }));\n                            b.UseDynamicClusterConfigDeploymentBalancer();\n                        });\n                }\n            }\n        }\n\n        public EHSubscriptionMultiplicityTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n            runner = new SubscriptionMultiplicityTestRunner(StreamProviderName, fixture.HostedCluster);            \n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHMultipleParallelSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHMultipleParallelSubscriptionTest *********************************\");\n            await runner.MultipleParallelSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHMultipleLinearSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHMultipleLinearSubscriptionTest *********************************\");\n            await runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHMultipleSubscriptionTest_AddRemove()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHMultipleSubscriptionTest_AddRemove *********************************\");\n            await runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHResubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHResubscriptionTest *********************************\");\n            await runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHResubscriptionAfterDeactivationTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHResubscriptionAfterDeactivationTest *********************************\");\n            await runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHActiveSubscriptionTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHActiveSubscriptionTest *********************************\");\n            await runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n        }\n\n        [SkippableFact, TestCategory(\"EventHub\"), TestCategory(\"Streaming\")]\n        public async Task EHTwoIntermitentStreamTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ EHTwoIntermitentStreamTest *********************************\");\n            await runner.TwoIntermitentStreamTest(Guid.NewGuid());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/EHSubscriptionObserverWithImplicitSubscribingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests.ProgrammaticSubscribeTests;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    /// <summary>\n    /// Tests for EventHub subscription observer behavior with implicit subscriptions across multiple stream providers.\n    /// </summary>\n    [TestCategory(\"EventHub\"), TestCategory(\"Streaming\"), TestCategory(\"Functional\")]\n    public class EHSubscriptionObserverWithImplicitSubscribingTests : SubscriptionObserverWithImplicitSubscribingTestRunner, IClassFixture<EHSubscriptionObserverWithImplicitSubscribingTests.Fixture>\n    {\n        private const string EHPath = \"ehorleanstest8\";\n        private const string EHPath2 = \"ehorleanstest9\";\n        private const string EHConsumerGroup = \"orleansnightly\";\n\n        public class Fixture : BaseEventHubTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n                builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n            }\n        }\n\n        private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddEventHubStreams(StreamProviderName, b =>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath, EHConsumerGroup);\n                        }));\n                        b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.PersistInterval = TimeSpan.FromSeconds(10);\n                        }));\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n\n                hostBuilder\n                    .AddEventHubStreams(StreamProviderName2, b =>\n                    {\n                        b.ConfigureEventHub(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults(EHPath2, EHConsumerGroup);\n\n                        }));\n                        b.UseAzureTableCheckpointer(ob => ob.Configure(options =>\n                        {\n                            options.ConfigureTestDefaults();\n                            options.PersistInterval = TimeSpan.FromSeconds(10);\n                        }));\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n\n                hostBuilder\n                    .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n        }\n\n        public EHSubscriptionObserverWithImplicitSubscribingTests(ITestOutputHelper output, Fixture fixture)\n            : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/Streaming/TimePurgePredicateTests.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Xunit;\n\nnamespace ServiceBus.Tests.StreamingTests\n{\n    public class TimePurgePredicateTests\n    {\n        private static readonly TimeSpan MinTimeInCache = TimeSpan.FromMinutes(5);\n        private static readonly TimeSpan MaxRelitiveAgeInCache = TimeSpan.FromMinutes(30);\n        private static readonly TimePurgePredicate TimePurge = new TimePurgePredicate(MinTimeInCache, MaxRelitiveAgeInCache);\n        private static readonly DateTime CacheMaxEnqueTime = new DateTime(2000, 3, 12, 10, 13, 32, DateTimeKind.Utc);\n        private static readonly DateTime NowUtc = DateTime.UtcNow;\n\n        /// <summary>\n        /// Message has not been in cache long enough to purge, and message age is not old enough to purge\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void TimePurgePredicate_NoPurgeThreshold_Tests()\n        {\n            DateTime messageEnqueTime = CacheMaxEnqueTime - MaxRelitiveAgeInCache;\n            DateTime timeRead = NowUtc - MinTimeInCache;\n            TimeSpan timeInCache = NowUtc - timeRead;\n            TimeSpan relativeAge = CacheMaxEnqueTime - messageEnqueTime;\n            Assert.False(TimePurge.ShouldPurgeFromTime(timeInCache, relativeAge));\n        }\n\n        /// <summary>\n        /// Message has been in cache long enough to purge, and message age is old enough to purge\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void TimePurgePredicate_PurgeDataThreshold_Tests()\n        {\n            DateTime messageEnqueTime = CacheMaxEnqueTime - MaxRelitiveAgeInCache - TimeSpan.FromTicks(1);\n            DateTime timeRead = NowUtc - MinTimeInCache - TimeSpan.FromTicks(1);\n            TimeSpan timeInCache = NowUtc - timeRead;\n            TimeSpan relativeAge = CacheMaxEnqueTime - messageEnqueTime;\n            Assert.True(TimePurge.ShouldPurgeFromTime(timeInCache, relativeAge));\n        }\n\n        /// <summary>\n        /// Message has been in cache long enough to purge, but message age is not old enough to purge\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void TimePurgePredicate_NoPurgeAgeThreshold_Tests()\n        {\n            DateTime messageEnqueTime = CacheMaxEnqueTime - MaxRelitiveAgeInCache;\n            DateTime timeRead = NowUtc - MinTimeInCache - TimeSpan.FromTicks(1);\n            TimeSpan timeInCache = NowUtc - timeRead;\n            TimeSpan relativeAge = CacheMaxEnqueTime - messageEnqueTime;\n            Assert.False(TimePurge.ShouldPurgeFromTime(timeInCache, relativeAge));\n        }\n\n        /// <summary>\n        /// Message has not been in cache long enough to purge, but message age is old enough to purge\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void TimePurgePredicate_NoPurgeTimeInCacheThreshold_Tests()\n        {\n            DateTime messageEnqueTime = CacheMaxEnqueTime - MaxRelitiveAgeInCache - TimeSpan.FromTicks(1);\n            DateTime timeRead = NowUtc - MinTimeInCache;\n            TimeSpan timeInCache = NowUtc - timeRead;\n            TimeSpan relativeAge = CacheMaxEnqueTime - messageEnqueTime;\n            Assert.False(TimePurge.ShouldPurgeFromTime(timeInCache, relativeAge));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/TestStreamProviders/EHStreamProviderForMonitorTests.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Orleans.Configuration;\nusing ServiceBus.Tests.MonitorTests;\nusing Orleans.Statistics;\n\nnamespace ServiceBus.Tests.TestStreamProviders\n{\n    public class EHStreamProviderForMonitorTestsAdapterFactory : EventDataGeneratorAdapterFactory\n    {\n        private CachePressureInjectionMonitor cachePressureInjectionMonitor;\n        private readonly EventHubStreamCachePressureOptions cacheOptions;\n        private readonly StreamCacheEvictionOptions evictionOptions;\n        private readonly StreamStatisticOptions staticticOptions;\n        private readonly EventHubOptions ehOptions;\n        private readonly CacheMonitorForTesting cacheMonitorForTesting = new CacheMonitorForTesting();\n        private readonly EventHubReceiverMonitorForTesting eventHubReceiverMonitorForTesting = new EventHubReceiverMonitorForTesting();\n        private readonly BlockPoolMonitorForTesting blockPoolMonitorForTesting = new BlockPoolMonitorForTesting();\n\n\n        public EHStreamProviderForMonitorTestsAdapterFactory(\n            string name,\n            EventDataGeneratorStreamOptions options,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions,\n            StreamCacheEvictionOptions streamCacheEvictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdapter,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n            : base(name, options, ehOptions, receiverOptions, cacheOptions, streamCacheEvictionOptions, statisticOptions, dataAdapter, serviceProvider, loggerFactory, environmentStatisticsProvider)\n        {\n            this.cacheOptions = cacheOptions;\n            this.staticticOptions = statisticOptions;\n            this.ehOptions = ehOptions;\n            this.evictionOptions = streamCacheEvictionOptions;\n        }\n\n        public new static EHStreamProviderForMonitorTestsAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var generatorOptions = services.GetOptionsByName<EventDataGeneratorStreamOptions>(name);\n            var ehOptions = services.GetOptionsByName<EventHubOptions>(name);\n            var receiverOptions = services.GetOptionsByName<EventHubReceiverOptions>(name);\n            var cacheOptions = services.GetOptionsByName<EventHubStreamCachePressureOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            var evictionOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            IEventHubDataAdapter dataAdapter = services.GetKeyedService<IEventHubDataAdapter>(name)\n                ?? services.GetService<IEventHubDataAdapter>()\n                ?? ActivatorUtilities.CreateInstance<EventHubDataAdapter>(services);\n            var factory = ActivatorUtilities.CreateInstance<EHStreamProviderForMonitorTestsAdapterFactory>(services, name, generatorOptions, ehOptions, receiverOptions, cacheOptions, \n                evictionOptions, statisticOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n\n        public override void Init()\n        {\n            this.ReceiverMonitorFactory = (dimensions, logger) => eventHubReceiverMonitorForTesting;\n            this.cachePressureInjectionMonitor = new CachePressureInjectionMonitor();\n            base.Init();\n        }\n\n        private void ChangeCachePressure()\n        {\n            this.cachePressureInjectionMonitor.UnderPressure = !this.cachePressureInjectionMonitor.UnderPressure;\n        }\n\n        protected override IEventHubQueueCacheFactory CreateCacheFactory(EventHubStreamCachePressureOptions cacheOptions)\n        {\n            var loggerFactory = this.serviceProvider.GetRequiredService<ILoggerFactory>();\n            var eventHubPath = this.ehOptions.EventHubName;\n            var sharedDimensions = new EventHubMonitorAggregationDimensions(eventHubPath);\n            ICacheMonitor cacheMonitorFactory(EventHubCacheMonitorDimensions dimensions, ILoggerFactory logger) => this.cacheMonitorForTesting;\n            IBlockPoolMonitor blockPoolMonitorFactory(EventHubBlockPoolMonitorDimensions dimensions, ILoggerFactory logger) => this.blockPoolMonitorForTesting;\n            return new CacheFactoryForMonitorTesting(\n                this.cachePressureInjectionMonitor,\n                this.cacheOptions,\n                this.evictionOptions,\n                this.staticticOptions,\n                base.dataAdapter,\n                sharedDimensions,\n                loggerFactory,\n                cacheMonitorFactory,\n                blockPoolMonitorFactory);\n        }\n\n        private class CacheFactoryForMonitorTesting : EventHubQueueCacheFactory\n        {\n            private readonly CachePressureInjectionMonitor cachePressureInjectionMonitor;\n            public CacheFactoryForMonitorTesting(\n                CachePressureInjectionMonitor cachePressureInjectionMonitor,\n                EventHubStreamCachePressureOptions cacheOptions,\n                StreamCacheEvictionOptions streamCacheEviction,\n                StreamStatisticOptions statisticOptions,\n                IEventHubDataAdapter dataAdater,\n                EventHubMonitorAggregationDimensions sharedDimensions,\n                ILoggerFactory loggerFactory,\n                Func<EventHubCacheMonitorDimensions, ILoggerFactory, ICacheMonitor> cacheMonitorFactory = null,\n                Func<EventHubBlockPoolMonitorDimensions, ILoggerFactory, IBlockPoolMonitor> blockPoolMonitorFactory = null)\n                : base(cacheOptions, streamCacheEviction, statisticOptions, dataAdater, sharedDimensions, cacheMonitorFactory, blockPoolMonitorFactory)\n            {\n                this.cachePressureInjectionMonitor = cachePressureInjectionMonitor;\n            }\n\n            protected override void AddCachePressureMonitors(IEventHubQueueCache cache, EventHubStreamCachePressureOptions providerOptions,\n                    ILogger cacheLogger)\n            {\n                cache.AddCachePressureMonitor(this.cachePressureInjectionMonitor);\n            }\n        }\n        public enum QueryCommands\n        {\n            GetCacheMonitorCallCounters = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 10,\n            GetReceiverMonitorCallCounters = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 11,\n            GetObjectPoolMonitorCallCounters = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 12,\n            ChangeCachePressure = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 13\n        }\n\n        public override Task<object> ExecuteCommand(int command, object arg)\n        {\n            object re = null;\n            switch (command)\n            {\n                case (int)QueryCommands.GetCacheMonitorCallCounters:\n                    re = this.cacheMonitorForTesting.CallCounters;\n                    break;\n                case (int)QueryCommands.GetReceiverMonitorCallCounters:\n                    re = this.eventHubReceiverMonitorForTesting.CallCounters;\n                    break;\n                case (int)QueryCommands.GetObjectPoolMonitorCallCounters:\n                    re = this.blockPoolMonitorForTesting.CallCounters;\n                    break;\n                case (int)QueryCommands.ChangeCachePressure:\n                    ChangeCachePressure();\n                    break;\n                default: return base.ExecuteCommand(command, arg);\n\n            }\n            return Task.FromResult(re);\n        }\n    }\n\n    public class CachePressureInjectionMonitor : ICachePressureMonitor\n    {\n        public bool UnderPressure { get; set; }\n        private bool wasUnderPressur;\n        public ICacheMonitor CacheMonitor { set; private get; }\n        public CachePressureInjectionMonitor()\n        {\n            this.UnderPressure = false;\n            this.wasUnderPressur = this.UnderPressure;\n        }\n\n        public void RecordCachePressureContribution(double cachePressureContribution)\n        {\n\n        }\n\n        public bool IsUnderPressure(DateTime utcNow)\n        {\n            if (this.wasUnderPressur != this.UnderPressure)\n            {\n                this.CacheMonitor?.TrackCachePressureMonitorStatusChange(this.GetType().Name, this.UnderPressure, null, null, null);\n                this.wasUnderPressur = this.UnderPressure;\n            }\n            return this.UnderPressure;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/TestStreamProviders/EHStreamProviderWithCreatedCacheList.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing Orleans.Streaming.EventHubs.Testing;\nusing Orleans.Configuration;\nusing Orleans.Statistics;\n\nnamespace ServiceBus.Tests.TestStreamProviders\n{\n    public class EHStreamProviderWithCreatedCacheListAdapterFactory : EventDataGeneratorAdapterFactory\n    {\n        private readonly ConcurrentBag<QueueCacheForTesting> createdCaches = new ConcurrentBag<QueueCacheForTesting>();\n        private readonly EventHubStreamCachePressureOptions cacheOptions;\n        private readonly StreamStatisticOptions staticticOptions;\n        private readonly EventHubOptions ehOptions;\n        private readonly StreamCacheEvictionOptions evictionOptions;\n        public EHStreamProviderWithCreatedCacheListAdapterFactory(\n            string name,\n            EventDataGeneratorStreamOptions options,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions,\n            StreamCacheEvictionOptions evictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdatper,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n            : base(name, options, ehOptions, receiverOptions, cacheOptions, evictionOptions, statisticOptions, dataAdatper, serviceProvider, loggerFactory, environmentStatisticsProvider)\n\n        {\n            this.createdCaches = new ConcurrentBag<QueueCacheForTesting>();\n            this.cacheOptions = cacheOptions;\n            this.staticticOptions = statisticOptions;\n            this.ehOptions = ehOptions;\n            this.evictionOptions = evictionOptions;\n        }\n\n        protected override IEventHubQueueCacheFactory CreateCacheFactory(EventHubStreamCachePressureOptions options)\n        {\n            var eventHubPath = this.ehOptions.EventHubName;\n            var sharedDimensions = new EventHubMonitorAggregationDimensions(eventHubPath);\n            return new CacheFactoryForTesting(this.Name, this.cacheOptions, this.evictionOptions,this.staticticOptions, base.dataAdapter, this.createdCaches, sharedDimensions, this.serviceProvider.GetRequiredService<ILoggerFactory>());\n        }\n\n        private class CacheFactoryForTesting : EventHubQueueCacheFactory\n        {\n            private readonly ConcurrentBag<QueueCacheForTesting> caches; \n            private readonly string name;\n\n            public CacheFactoryForTesting(string name, EventHubStreamCachePressureOptions cacheOptions, StreamCacheEvictionOptions evictionOptions, StreamStatisticOptions statisticOptions,\n                IEventHubDataAdapter dataAdapter, ConcurrentBag<QueueCacheForTesting> caches, EventHubMonitorAggregationDimensions sharedDimensions,\n                ILoggerFactory loggerFactory,\n                Func<EventHubCacheMonitorDimensions, ILoggerFactory, ICacheMonitor> cacheMonitorFactory = null,\n                Func<EventHubBlockPoolMonitorDimensions, ILoggerFactory, IBlockPoolMonitor> blockPoolMonitorFactory = null)\n                : base(cacheOptions, evictionOptions, statisticOptions, dataAdapter, sharedDimensions, cacheMonitorFactory, blockPoolMonitorFactory)\n            {\n                this.name = name;\n                this.caches = caches;\n            }\n            private const int DefaultMaxAddCount = 10;\n            protected override IEventHubQueueCache CreateCache(\n                string partition,\n                IEventHubDataAdapter dataAdatper,\n                StreamStatisticOptions options,\n                StreamCacheEvictionOptions evictionOptions,\n                IStreamQueueCheckpointer<string> checkpointer,\n                ILoggerFactory loggerFactory,\n                IObjectPool<FixedSizeBuffer> bufferPool,\n                string blockPoolId,\n                TimePurgePredicate timePurge,\n                EventHubMonitorAggregationDimensions sharedDimensions)\n            {\n                var cacheMonitorDimensions = new EventHubCacheMonitorDimensions(sharedDimensions, partition, blockPoolId);\n                var cacheMonitor = this.CacheMonitorFactory(cacheMonitorDimensions, loggerFactory);\n                var cacheLogger = loggerFactory.CreateLogger($\"{typeof(EventHubQueueCache).FullName}.{this.name}.{partition}\");\n                var evictionStrategy = new ChronologicalEvictionStrategy(cacheLogger, timePurge, cacheMonitor, options.StatisticMonitorWriteInterval);\n                //set defaultMaxAddCount to 10 so TryCalculateCachePressureContribution will start to calculate real contribution shortly\n                var cache = new QueueCacheForTesting(DefaultMaxAddCount, bufferPool, dataAdatper, evictionStrategy, checkpointer,\n                    cacheLogger, cacheMonitor, options.StatisticMonitorWriteInterval);\n                this.caches.Add(cache);\n                return cache;\n            }\n        }\n\n        private class QueueCacheForTesting : EventHubQueueCache, IQueueFlowController\n        {\n            public bool IsUnderPressure { get; private set; }\n\n            public QueueCacheForTesting(int defaultMaxAddCount, IObjectPool<FixedSizeBuffer> bufferPool, IEventHubDataAdapter dataAdapter, IEvictionStrategy evictionStrategy, IStreamQueueCheckpointer<string> checkpointer, ILogger logger,\n                ICacheMonitor cacheMonitor, TimeSpan? cacheMonitorWriteInterval)\n                : base(\"test\", defaultMaxAddCount, bufferPool, dataAdapter, evictionStrategy, checkpointer, logger, cacheMonitor, cacheMonitorWriteInterval, null)\n            {\n            }\n\n            int IQueueFlowController.GetMaxAddCount()\n            {\n                int maxAddCount = base.GetMaxAddCount();\n                this.IsUnderPressure = maxAddCount <= 0;\n                return maxAddCount;\n            }\n        }\n\n        public const int IsCacheBackPressureTriggeredCommand = (int)PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 3;\n\n        /// <summary>\n        /// Only command expecting: determine whether back pressure algorithm on any of the created caches\n        /// is triggered.\n        /// </summary>\n        /// <param name=\"command\"></param>\n        /// <param name=\"arg\"></param>\n        /// <returns></returns>\n        public override Task<object> ExecuteCommand(int command, object arg)\n        {\n            switch (command)\n            {\n                case IsCacheBackPressureTriggeredCommand:\n                    return Task.FromResult<object>(this.createdCaches.Any(cache => cache.IsUnderPressure));\n                default: return base.ExecuteCommand(command, arg);\n            }\n        }\n\n        public new static EHStreamProviderWithCreatedCacheListAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var generatorOptions = services.GetOptionsByName<EventDataGeneratorStreamOptions>(name);\n            var ehOptions = services.GetOptionsByName<EventHubOptions>(name);\n            var receiverOptions = services.GetOptionsByName<EventHubReceiverOptions>(name);\n            var cacheOptions = services.GetOptionsByName<EventHubStreamCachePressureOptions>(name);\n            var evictionOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            IEventHubDataAdapter dataAdapter = services.GetKeyedService<IEventHubDataAdapter>(name)\n                ?? services.GetService<IEventHubDataAdapter>()\n                ?? ActivatorUtilities.CreateInstance<EventHubDataAdapter>(services);\n            var factory = ActivatorUtilities.CreateInstance<EHStreamProviderWithCreatedCacheListAdapterFactory>(services, name, generatorOptions, ehOptions, receiverOptions, \n                cacheOptions, evictionOptions, statisticOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/TestStreamProviders/StreamPerPartitionEventHubStreamProvider.cs",
    "content": "using System.Text;\nusing Orleans.Runtime;\nusing Azure.Messaging.EventHubs;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\n\nnamespace ServiceBus.Tests.TestStreamProviders.EventHub\n{\n    public class StreamPerPartitionDataAdapter : EventHubDataAdapter\n    {\n        public StreamPerPartitionDataAdapter(Orleans.Serialization.Serializer serializer) : base(serializer) {}\n\n        public override StreamPosition GetStreamPosition(string partition, EventData queueMessage)\n        {\n            var streamId = StreamId.Create(new StreamIdentity(GetPartitionGuid(partition), null));\n            StreamSequenceToken token =\n            new EventHubSequenceTokenV2(queueMessage.OffsetString, queueMessage.SequenceNumber, 0);\n\n            return new StreamPosition(streamId, token);\n        }\n\n        public static Guid GetPartitionGuid(string partition)\n        {\n            byte[] bytes = Encoding.UTF8.GetBytes(partition);\n            Array.Resize(ref bytes, 10);\n            return new Guid(partition.GetHashCode(), bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/TestStreamProviders/TestAzureTableStorageStreamFailureHandler.cs",
    "content": "using Azure.Data.Tables;\nusing Azure.Identity;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Providers.Streams.PersistentStreams;\nusing Orleans.Serialization;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing TestExtensions;\nusing Tester.AzureUtils;\n\nnamespace ServiceBus.Tests.TestStreamProviders.EventHub\n{\n    public class TestAzureTableStorageStreamFailureHandler : AzureTableStorageStreamFailureHandler<StreamDeliveryFailureEntity>\n    {\n        private const string TableName = \"TestStreamFailures\";\n        private const string DeploymentId = \"TestDeployment\";\n        private TestAzureTableStorageStreamFailureHandler(Serializer<StreamSequenceToken> serializer)\n            : base(serializer, NullLoggerFactory.Instance, false, DeploymentId, GetStreamingAzureStorageOperationOptions())\n        {\n        }\n\n        public static async Task<IStreamFailureHandler> Create(Serializer<StreamSequenceToken> serializer)\n        {\n            var failureHandler = new TestAzureTableStorageStreamFailureHandler(serializer);\n            await failureHandler.InitAsync();\n            return failureHandler;\n        }\n\n        public static async Task<int> GetDeliveryFailureCount(string streamProviderName)\n        {\n            var dataManager = GetDataManager();\n            await dataManager.InitTableAsync();\n            var deliveryErrors =\n                await dataManager.ReadAllTableEntriesForPartitionAsync(\n                        StreamDeliveryFailureEntity.MakeDefaultPartitionKey(streamProviderName, DeploymentId));\n            return deliveryErrors.Count;\n        }\n\n        private static AzureTableDataManager<TableEntity> GetDataManager()\n        {\n            var options = GetAzureStorageOperationOptions();\n            return new AzureTableDataManager<TableEntity>(options, NullLogger.Instance);\n        }\n\n        private static AzureStorageOperationOptions GetAzureStorageOperationOptions()\n        {\n            var options = new AzureStorageOperationOptions { TableName = TableName };\n            options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n\n            return options;\n        }\n\n        private static Orleans.Streaming.AzureStorage.AzureStorageOperationOptions GetStreamingAzureStorageOperationOptions()\n        {\n            var options = new Orleans.Streaming.AzureStorage.AzureStorageOperationOptions { TableName = TableName };\n            options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n\n            return options;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.EventHubs.Tests/TestStreamProviders/TestEventHubStreamProvider.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Serialization;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing Orleans.Statistics;\n\nnamespace ServiceBus.Tests.TestStreamProviders.EventHub\n{\n    public class TestEventHubStreamAdapterFactory : EventHubAdapterFactory\n    {\n        public TestEventHubStreamAdapterFactory(\n            string name,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions,\n            StreamCacheEvictionOptions evictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdapter,\n            IServiceProvider serviceProvider,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider,\n            ILoggerFactory loggerFactory)\n            : base(name, ehOptions, receiverOptions, cacheOptions, evictionOptions, statisticOptions, dataAdapter, serviceProvider, loggerFactory, environmentStatisticsProvider)\n        {\n            StreamFailureHandlerFactory = qid => TestAzureTableStorageStreamFailureHandler.Create(this.serviceProvider.GetRequiredService<Serializer<StreamSequenceToken>>());\n        }\n\n        public static new TestEventHubStreamAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var ehOptions = services.GetOptionsByName<EventHubOptions>(name);\n            var receiverOptions = services.GetOptionsByName<EventHubReceiverOptions>(name);\n            var cacheOptions = services.GetOptionsByName<EventHubStreamCachePressureOptions>(name);\n            var evictionOptions = services.GetOptionsByName<StreamCacheEvictionOptions>(name);\n            var statisticOptions = services.GetOptionsByName<StreamStatisticOptions>(name);\n            IEventHubDataAdapter dataAdapter = services.GetKeyedService<IEventHubDataAdapter>(name)\n                ?? services.GetService<IEventHubDataAdapter>()\n                ?? ActivatorUtilities.CreateInstance<EventHubDataAdapter>(services);\n            var factory = ActivatorUtilities.CreateInstance<TestEventHubStreamAdapterFactory>(services, name, ehOptions, receiverOptions, cacheOptions, evictionOptions, statisticOptions, dataAdapter);\n            factory.Init();\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/NatsAdapterTests.cs",
    "content": "using System.Globalization;\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing TestExtensions;\nusing Orleans.Streams;\nusing Orleans.Configuration;\nusing Orleans.Streaming.NATS;\nusing Orleans.Providers.Streams.Common;\nusing Xunit;\nusing NATS.Client.Core;\nusing Xunit.Abstractions;\nusing NATS.Client.JetStream;\n\nnamespace NATS.Tests;\n\n[TestCategory(\"NATS\")]\n[Collection(TestEnvironmentFixture.DefaultCollection)]\npublic class NatsAdapterTests : IAsyncLifetime, IClassFixture<TestEnvironmentFixture>\n{\n    private const int NumBatches = 20;\n    private const int NumMessagesPerBatch = 20;\n    public static readonly string NATS_STREAM_PROVIDER_NAME = \"NATSAdapterTests\";\n    private readonly ITestOutputHelper output;\n    private readonly TestEnvironmentFixture fixture;\n    private readonly string testStreamName;\n    private readonly NatsConnection natsConnection;\n    private readonly NatsJSContext natsContext;\n\n    public NatsAdapterTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Nats Server is not available\");\n        }\n\n        this.output = output;\n        this.fixture = fixture;\n\n        this.natsConnection = new NatsConnection();\n        this.natsContext = new NatsJSContext(this.natsConnection);\n\n        this.testStreamName = $\"test-stream-{Guid.NewGuid()}\";\n    }\n\n    public async Task InitializeAsync()\n    {\n        await natsConnection.ConnectAsync();\n\n        try\n        {\n            var stream = await natsContext.GetStreamAsync(this.testStreamName);\n\n            await stream.DeleteAsync();\n        }\n        catch (NatsJSApiException)\n        {\n            // Ignore, stream not found\n        }\n    }\n\n    public async Task DisposeAsync()\n    {\n        if (NatsTestConstants.IsNatsAvailable)\n        {\n            var stream = await natsContext.GetStreamAsync(this.testStreamName);\n\n            await stream.DeleteAsync();\n\n            await natsConnection.DisposeAsync();\n        }\n    }\n\n    [SkippableFact]\n    public async Task SendAndReceiveFromNats()\n    {\n        var options = new NatsOptions { StreamName = testStreamName };\n        var adapterFactory = new NatsAdapterFactory(\n            NATS_STREAM_PROVIDER_NAME,\n            options,\n            new HashRingStreamQueueMapperOptions(),\n            new SimpleQueueCacheOptions(),\n            Options.Create(new ClusterOptions()),\n            fixture.Serializer,\n            NullLoggerFactory.Instance);\n        adapterFactory.Init();\n        await SendAndReceiveFromQueueAdapter(adapterFactory);\n    }\n\n    private async Task SendAndReceiveFromQueueAdapter(IQueueAdapterFactory adapterFactory)\n    {\n        IQueueAdapter adapter = await adapterFactory.CreateAdapter();\n        IQueueAdapterCache cache = adapterFactory.GetQueueAdapterCache();\n\n        // Create receiver per queue\n        IStreamQueueMapper mapper = adapterFactory.GetStreamQueueMapper();\n        Dictionary<QueueId, IQueueAdapterReceiver> receivers =\n            mapper.GetAllQueues().ToDictionary(queueId => queueId, adapter.CreateReceiver);\n        Dictionary<QueueId, IQueueCache> caches =\n            mapper.GetAllQueues().ToDictionary(queueId => queueId, cache.CreateQueueCache);\n\n        await Task.WhenAll(receivers.Values.Select(receiver => receiver.Initialize(TimeSpan.FromSeconds(5))));\n\n        // test using 2 streams\n        Guid streamId1 = Guid.NewGuid();\n        Guid streamId2 = Guid.NewGuid();\n\n        int receivedBatches = 0;\n        var streamsPerQueue = new ConcurrentDictionary<QueueId, HashSet<StreamId>>();\n\n        // reader threads (at most 2 active queues because only two streams)\n        var work = new List<Task>();\n        foreach (KeyValuePair<QueueId, IQueueAdapterReceiver> receiverKvp in receivers)\n        {\n            QueueId queueId = receiverKvp.Key;\n            var receiver = receiverKvp.Value;\n            var qCache = caches[queueId];\n            Task task = Task.Factory.StartNew(() =>\n            {\n                while (receivedBatches < NumBatches)\n                {\n                    var messages = receiver.GetQueueMessagesAsync(50).Result.ToArray();\n                    if (!messages.Any())\n                    {\n                        continue;\n                    }\n\n                    foreach (var message in messages.Cast<NatsBatchContainer>())\n                    {\n                        streamsPerQueue.AddOrUpdate(queueId,\n                            id => new HashSet<StreamId> { message.StreamId },\n                            (id, set) =>\n                            {\n                                set.Add(message.StreamId);\n                                return set;\n                            });\n                        output.WriteLine(\"Queue {0} received message on stream {1}\", queueId,\n                            message.StreamId);\n                        Assert.Equal(NumMessagesPerBatch / 2,\n                            message.GetEvents<int>().Count()); // \"Half the events were ints\"\n                        Assert.Equal(NumMessagesPerBatch / 2,\n                            message.GetEvents<string>().Count()); // \"Half the events were strings\"\n                    }\n\n                    Interlocked.Add(ref receivedBatches, messages.Length);\n                    qCache.AddToCache(messages);\n                }\n            });\n            work.Add(task);\n        }\n\n        // send events\n        List<object> events = CreateEvents(NumMessagesPerBatch);\n        work.Add(Task.Factory.StartNew(() => Enumerable.Range(0, NumBatches)\n            .Select(i => i % 2 == 0 ? streamId1 : streamId2)\n            .ToList()\n            .ForEach(streamId =>\n                adapter.QueueMessageBatchAsync(StreamId.Create(streamId.ToString(), streamId),\n                    events.Take(NumMessagesPerBatch).ToArray(), null,\n                    RequestContextExtensions.Export(this.fixture.DeepCopier)).Wait())));\n        await Task.WhenAll(work);\n\n        // Make sure we got back everything we sent\n        Assert.Equal(NumBatches, receivedBatches);\n\n        // check to see if all the events are in the cache and we can enumerate through them\n        StreamSequenceToken firstInCache = new EventSequenceTokenV2(0);\n        foreach (KeyValuePair<QueueId, HashSet<StreamId>> kvp in streamsPerQueue)\n        {\n            var receiver = receivers[kvp.Key];\n            var qCache = caches[kvp.Key];\n\n            foreach (StreamId streamGuid in kvp.Value)\n            {\n                // read all messages in cache for stream\n                IQueueCacheCursor cursor = qCache.GetCacheCursor(streamGuid, firstInCache);\n                int messageCount = 0;\n                StreamSequenceToken tenthInCache = null;\n                StreamSequenceToken lastToken = firstInCache;\n                while (cursor.MoveNext())\n                {\n                    Exception ex;\n                    messageCount++;\n                    IBatchContainer batch = cursor.GetCurrent(out ex);\n                    output.WriteLine(\"Token: {0}\", batch.SequenceToken);\n                    Assert.True(batch.SequenceToken.CompareTo(lastToken) >= 0, $\"order check for event {messageCount}\");\n                    lastToken = batch.SequenceToken;\n                    if (messageCount == 10)\n                    {\n                        tenthInCache = batch.SequenceToken;\n                    }\n                }\n\n                output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount,\n                    streamGuid);\n                Assert.Equal(NumBatches / 2, messageCount);\n                Assert.NotNull(tenthInCache);\n\n                // read all messages from the 10th\n                cursor = qCache.GetCacheCursor(streamGuid, tenthInCache);\n                messageCount = 0;\n                while (cursor.MoveNext())\n                {\n                    messageCount++;\n                }\n\n                output.WriteLine(\"On Queue {0} we received a total of {1} message on stream {2}\", kvp.Key, messageCount,\n                    streamGuid);\n                const int expected = NumBatches / 2 - 10 + 1; // all except the first 10, including the 10th (10 + 1)\n                Assert.Equal(expected, messageCount);\n            }\n        }\n    }\n\n    private static List<object> CreateEvents(int count)\n    {\n        return Enumerable.Range(0, count).Select(i =>\n        {\n            if (i % 2 == 0)\n            {\n                return Random.Shared.Next(int.MaxValue) as object;\n            }\n\n            return Random.Shared.Next(int.MaxValue).ToString(CultureInfo.InvariantCulture);\n        }).ToList();\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/NatsClientStreamTests.cs",
    "content": "using Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing NATS.Client.Core;\nusing NATS.Client.JetStream;\nusing Orleans.Configuration;\nusing Orleans.Streaming.NATS.Hosting;\n\nnamespace NATS.Tests;\n\npublic class NatsClientStreamTests : TestClusterPerTest\n{\n    private const string NatsStreamProviderName = \"NatsProvider-Client-Test\";\n    private const string StreamNamespace = \"NatsSubscriptionMultiplicityTestsNamespace\";\n    private const string TestStreamName = \"test-client-stream\";\n    private ClientStreamTestRunner runner;\n    private readonly NatsConnection natsConnection;\n    private readonly NatsJSContext natsContext;\n\n    public NatsClientStreamTests()\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Nats Server is not available\");\n        }\n\n        this.natsConnection = new NatsConnection();\n        this.natsContext = new NatsJSContext(this.natsConnection);\n    }\n\n    public override async Task InitializeAsync()\n    {\n        await natsConnection.ConnectAsync();\n\n        try\n        {\n            var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n            await stream.DeleteAsync();\n        }\n        catch (NatsJSApiException)\n        {\n            // Ignore, stream not found\n        }\n\n        await base.InitializeAsync();\n        runner = new ClientStreamTestRunner(this.HostedCluster);\n    }\n\n    public override async Task DisposeAsync()\n    {\n        var clusterId = HostedCluster.Options.ClusterId;\n        await base.DisposeAsync();\n\n        if (NatsTestConstants.IsNatsAvailable)\n        {\n            var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n            await stream.DeleteAsync();\n\n            await natsConnection.DisposeAsync();\n        }\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Empty connection string\");\n        }\n\n        builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n    }\n\n    private class MySiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                })\n                .AddMemoryGrainStorage(\"PubSubStore\")\n                .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n        }\n    }\n\n    private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                });\n            ;\n        }\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task StreamProducerOnDroppedClientTest()\n    {\n        logger.LogInformation(\n            \"************************ NatStreamProducerOnDroppedClientTest *********************************\");\n        await runner.StreamProducerOnDroppedClientTest(NatsStreamProviderName, StreamNamespace);\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/NatsStreamTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing NATS.Client.Core;\nusing NATS.Client.JetStream;\nusing Orleans.Streaming.NATS.Hosting;\nusing Orleans.TestingHost;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing TestExtensions;\nusing UnitTests.Streaming;\n\nnamespace NATS.Tests;\n\n[TestCategory(\"NATS\")]\npublic class NatsStreamTests : TestClusterPerTest\n{\n    private const string NatsStreamProviderName = \"NatsProvider-Test\";\n    private const string TestStreamName = \"test-stream\";\n\n    private readonly NatsConnection natsConnection;\n    private readonly NatsJSContext natsContext;\n    private SingleStreamTestRunner runner;\n\n    public NatsStreamTests()\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Nats Server is not available\");\n        }\n\n        this.natsConnection = new NatsConnection();\n        this.natsContext = new NatsJSContext(this.natsConnection);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Empty connection string\");\n        }\n\n        builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n    }\n\n    private class MySiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                })\n                .AddNatsStreams($\"{NatsStreamProviderName}2\", options =>\n                {\n                    options.StreamName = $\"{TestStreamName}2\";\n                })\n                .AddMemoryGrainStorage(\"PubSubStore\", opt => opt.NumStorageGrains = 1)\n                .AddMemoryGrainStorage(\"MemoryStore\", op => op.NumStorageGrains = 1);\n            ;\n        }\n    }\n\n    private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                });\n        }\n    }\n\n    public override async Task InitializeAsync()\n    {\n        await natsConnection.ConnectAsync();\n\n        try\n        {\n            var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n            await stream.DeleteAsync();\n        }\n        catch (NatsJSApiException)\n        {\n            // Ignore, stream not found\n        }\n\n        try\n        {\n            var stream = await natsContext.GetStreamAsync($\"{TestStreamName}2\");\n\n            await stream.DeleteAsync();\n        }\n        catch (NatsJSApiException)\n        {\n            // Ignore, stream not found\n        }\n\n        await base.InitializeAsync();\n        runner = new SingleStreamTestRunner(this.InternalClient, NatsStreamProviderName);\n    }\n\n    public override async Task DisposeAsync()\n    {\n        await base.DisposeAsync();\n\n        if (NatsTestConstants.IsNatsAvailable)\n        {\n            try\n            {\n                var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n                await stream.DeleteAsync();\n            }\n            catch (NatsJSApiException) { }\n\n            try\n            {\n                var stream = await natsContext.GetStreamAsync($\"{TestStreamName}2\");\n\n                await stream.DeleteAsync();\n            }\n            catch (NatsJSApiException) { }\n\n            await natsConnection.DisposeAsync();\n        }\n    }\n\n    ////------------------------ One to One ----------------------//\n\n    [SkippableFact]\n    public async Task Nats_01_OneProducerGrainOneConsumerGrain()\n    {\n        await runner.StreamTest_01_OneProducerGrainOneConsumerGrain();\n    }\n\n    [SkippableFact]\n    public async Task Nats_02_OneProducerGrainOneConsumerClient()\n    {\n        await runner.StreamTest_02_OneProducerGrainOneConsumerClient();\n    }\n\n    [SkippableFact]\n    public async Task Nats_03_OneProducerClientOneConsumerGrain()\n    {\n        await runner.StreamTest_03_OneProducerClientOneConsumerGrain();\n    }\n\n    [SkippableFact]\n    public async Task Nats_04_OneProducerClientOneConsumerClient()\n    {\n        await runner.StreamTest_04_OneProducerClientOneConsumerClient();\n    }\n\n    //------------------------ MANY to Many different grains ----------------------//\n\n    [SkippableFact]\n    public async Task Nats_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n    {\n        await runner.StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n    }\n\n    [SkippableFact]\n    public async Task Nats_06_ManyDifferent_ManyProducerGrainManyConsumerClients()\n    {\n        await runner.StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients();\n    }\n\n    [SkippableFact]\n    public async Task Nats_07_ManyDifferent_ManyProducerClientsManyConsumerGrains()\n    {\n        await runner.StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains();\n    }\n\n    [SkippableFact]\n    public async Task Nats_08_ManyDifferent_ManyProducerClientsManyConsumerClients()\n    {\n        await runner.StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients();\n    }\n\n    //------------------------ MANY to Many Same grains ----------------------//\n    [SkippableFact]\n    public async Task Nats_09_ManySame_ManyProducerGrainsManyConsumerGrains()\n    {\n        await runner.StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains();\n    }\n\n    [SkippableFact]\n    public async Task Nats_10_ManySame_ManyConsumerGrainsManyProducerGrains()\n    {\n        await runner.StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains();\n    }\n\n    [SkippableFact]\n    public async Task Nats_11_ManySame_ManyProducerGrainsManyConsumerClients()\n    {\n        await runner.StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients();\n    }\n\n    [SkippableFact]\n    public async Task Nats_12_ManySame_ManyProducerClientsManyConsumerGrains()\n    {\n        await runner.StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains();\n    }\n\n    //------------------------ MANY to Many producer consumer same grain ----------------------//\n\n    [SkippableFact]\n    public async Task Nats_13_SameGrain_ConsumerFirstProducerLater()\n    {\n        await runner.StreamTest_13_SameGrain_ConsumerFirstProducerLater(false);\n    }\n\n    [SkippableFact]\n    public async Task Nats_14_SameGrain_ProducerFirstConsumerLater()\n    {\n        await runner.StreamTest_14_SameGrain_ProducerFirstConsumerLater(false);\n    }\n\n    //----------------------------------------------//\n\n    [SkippableFact]\n    public async Task Nats_15_ConsumeAtProducersRequest()\n    {\n        await runner.StreamTest_15_ConsumeAtProducersRequest();\n    }\n\n    [SkippableFact]\n    public async Task Nats_16_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n    {\n        var multiRunner = new MultipleStreamsTestRunner(this.InternalClient, NatsStreamProviderName, 16, false);\n        await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains();\n    }\n\n    [SkippableFact]\n    public async Task Nats_17_MultipleStreams_1J_ManyProducerGrainsManyConsumerGrains()\n    {\n        var multiRunner = new MultipleStreamsTestRunner(this.InternalClient, NatsStreamProviderName, 17, false);\n        await multiRunner.StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(\n            () => this.HostedCluster.StartAdditionalSilo());\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/NatsSubscriptionMultiplicityTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing NATS.Client.Core;\nusing NATS.Client.JetStream;\nusing Orleans.Streaming.NATS.Hosting;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.StreamingTests;\nusing Xunit;\n\nnamespace NATS.Tests;\n\npublic class NatsSubscriptionMultiplicityTests : TestClusterPerTest\n{\n    private const string NatsStreamProviderName = \"NatsProvider-Subscription-Test\";\n    private const string StreamNamespace = \"NatsSubscriptionMultiplicityTestsNamespace\";\n    private const string TestStreamName = \"test-subscription-stream\";\n    private SubscriptionMultiplicityTestRunner runner;\n    private readonly NatsConnection natsConnection;\n    private readonly NatsJSContext natsContext;\n\n    public NatsSubscriptionMultiplicityTests()\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Nats Server is not available\");\n        }\n\n        this.natsConnection = new NatsConnection();\n        this.natsContext = new NatsJSContext(this.natsConnection);\n    }\n\n    protected override void ConfigureTestCluster(TestClusterBuilder builder)\n    {\n        if (!NatsTestConstants.IsNatsAvailable)\n        {\n            throw new SkipException(\"Empty connection string\");\n        }\n\n        builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n        builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n    }\n\n    private class MySiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                })\n                .AddMemoryGrainStorage(\"PubSubStore\", opt => opt.NumStorageGrains = 1);\n        }\n    }\n\n    private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n    {\n        public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n        {\n            clientBuilder\n                .AddNatsStreams(NatsStreamProviderName, options =>\n                {\n                    options.StreamName = TestStreamName;\n                });\n        }\n    }\n\n    public override async Task InitializeAsync()\n    {\n        await natsConnection.ConnectAsync();\n\n        try\n        {\n            var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n            await stream.DeleteAsync();\n        }\n        catch (NatsJSApiException)\n        {\n            // Ignore, stream not found\n        }\n\n        await base.InitializeAsync();\n        runner = new SubscriptionMultiplicityTestRunner(NatsStreamProviderName, this.HostedCluster);\n    }\n\n    public override async Task DisposeAsync()\n    {\n        await base.DisposeAsync();\n\n        if (NatsTestConstants.IsNatsAvailable)\n        {\n            try\n            {\n                var stream = await natsContext.GetStreamAsync(TestStreamName);\n\n                await stream.DeleteAsync();\n            }\n            catch (NatsJSApiException) { }\n\n            await natsConnection.DisposeAsync();\n        }\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsMultipleLinearSubscriptionTest()\n    {\n        logger.LogInformation(\n            \"************************ NatsMultipleLinearSubscriptionTest *********************************\");\n        await runner.MultipleLinearSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsMultipleSubscriptionTest_AddRemove()\n    {\n        logger.LogInformation(\n            \"************************ NatsMultipleSubscriptionTest_AddRemove *********************************\");\n        await runner.MultipleSubscriptionTest_AddRemove(Guid.NewGuid(), StreamNamespace);\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsResubscriptionTest()\n    {\n        logger.LogInformation(\"************************ NatsResubscriptionTest *********************************\");\n        await runner.ResubscriptionTest(Guid.NewGuid(), StreamNamespace);\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsResubscriptionAfterDeactivationTest()\n    {\n        logger.LogInformation(\n            \"************************ ResubscriptionAfterDeactivationTest *********************************\");\n        await runner.ResubscriptionAfterDeactivationTest(Guid.NewGuid(), StreamNamespace);\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsActiveSubscriptionTest()\n    {\n        logger.LogInformation(\"************************ NatsActiveSubscriptionTest *********************************\");\n        await runner.ActiveSubscriptionTest(Guid.NewGuid(), StreamNamespace);\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsTwoIntermitentStreamTest()\n    {\n        logger.LogInformation(\"************************ NatsTwoIntermitentStreamTest *********************************\");\n        await runner.TwoIntermitentStreamTest(Guid.NewGuid());\n    }\n\n    [SkippableFact, TestCategory(\"NATS\")]\n    public async Task NatsSubscribeFromClientTest()\n    {\n        logger.LogInformation(\"************************ NatsSubscribeFromClientTest *********************************\");\n        await runner.SubscribeFromClientTest(Guid.NewGuid(), StreamNamespace);\n    }\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/NatsTestConstants.cs",
    "content": "using NATS.Client.Core;\n\nnamespace NATS.Tests;\n\npublic static class NatsTestConstants\n{\n    private static readonly Lazy<bool> _isNatsAvailable = new(() =>\n    {\n        try\n        {\n            var nats = new NatsConnection();\n            nats.ConnectAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(2)).Wait();\n            return nats.ConnectionState == NatsConnectionState.Open;\n        }\n        catch\n        {\n            return false;\n        }\n    });\n\n    public static bool IsNatsAvailable => _isNatsAvailable.Value;\n}"
  },
  {
    "path": "test/Extensions/Orleans.Streaming.NATS.Tests/Orleans.Streaming.NATS.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming.NATS\\Orleans.Streaming.NATS.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Streaming.Tests\\Orleans.Streaming.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/BenchmarkGrainInterfaces.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Transactions\\Orleans.Transactions.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/GrainStorage/IPersistentGrain.cs",
    "content": "namespace BenchmarkGrainInterfaces.GrainStorage\n{\n    [GenerateSerializer]\n    public class Report\n    {\n        [Id(1)]\n        public bool Success { get; set; }\n\n        [Id(2)]\n        public TimeSpan Elapsed { get; set; }\n    }\n\n    public interface IPersistentGrain : IGrainWithGuidKey\n    {\n        Task Init(int payloadSize);\n        Task<Report> TrySet(int index);\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/MapReduce/DataflowGrainsInterfaces.cs",
    "content": "﻿namespace BenchmarkGrainInterfaces.MapReduce\n{\n    public interface IDataflowGrain : IGrain\n    {\n        Task Complete();\n\n        Task Fault();\n\n        Task Completion();\n    }\n\n    public interface ITargetGrain<in TInput> : IDataflowGrain, IGrainWithGuidKey\n    {\n        Task<GrainDataflowMessageStatus> OfferMessage(TInput messageValue, bool consumeToAccept);\n\n        Task SendAsync(TInput t);\n\n        Task SendAsync(TInput t, GrainCancellationToken gct);\n    }\n\n    public interface ISourceGrain<TOutput> : IDataflowGrain, IGrainWithGuidKey\n    {\n        Task LinkTo(ITargetGrain<TOutput> t);\n\n        Task<TOutput> ConsumeMessage();\n    }\n\n    public interface IProcessor<in TProcessor>\n    {\n        Task Initialize(TProcessor processor);\n    }\n\n    public interface ITargetProcessor<in TInput>\n    {\n        void Process(TInput t);\n    }\n\n    public interface ITransformProcessor<in TInput, out TOutput>\n    {\n        TOutput Process(TInput input);\n    }\n\n    public interface IPropagatorGrain<in TInput, TOutput> : ITargetGrain<TInput>, ISourceGrain<TOutput>\n    {\n        Task<List<TOutput>> ReceiveAll();\n    }\n    \n    public interface ITransformGrain<TInput, TOutput> : IPropagatorGrain<TInput, TOutput>, IProcessor<ITransformProcessor<TInput, TOutput>>\n    {\n    }\n\n    public interface IBufferGrain<T> : IPropagatorGrain<T, T>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/MapReduce/GrainDataflowMessageStatus.cs",
    "content": "﻿namespace BenchmarkGrainInterfaces.MapReduce\n{\n    public enum GrainDataflowMessageStatus\n    {\n        Accepted,\n        Declined,\n        DecliningPermanently\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Ping/ILoadGrain.cs",
    "content": "namespace BenchmarkGrainInterfaces.Ping\n{\n    [GenerateSerializer]\n    public class Report\n    {\n        [Id(1)]\n        public long Succeeded { get; set; }\n        [Id(2)]\n        public long Failed { get; set; }\n        [Id(3)]\n        public TimeSpan Elapsed { get; set; }\n    }\n\n    public interface ILoadGrain : IGrainWithGuidKey\n    {\n        Task Generate(int run, int conncurrent);\n        Task<Report> TryGetReport();\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Ping/IPingGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace BenchmarkGrainInterfaces.Ping\n{\n    public interface IPingGrain : IGrainWithIntegerKey\n    {\n        ValueTask Run();\n\n        [AlwaysInterleave]\n        ValueTask PingPongInterleave(IPingGrain other, int count);\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Ping/ITreeGrain.cs",
    "content": "namespace BenchmarkGrainInterfaces.Ping;\n\npublic interface ITreeGrain : IGrainWithIntegerCompoundKey\n{\n    public ValueTask Ping();\n}\n\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Ping/MyType.cs",
    "content": "namespace BenchmarkGrainInterfaces.Ping;\n\n[GenerateSerializer]\npublic class UserProfile\n{\n    [Id(0)]\n    public string DisplayName { get; set; }\n\n    [Id(1)]\n    public string PreferredLanguage { get; set; }\n\n    [Id(2)]\n    public DateTimeOffset AccountCreated { get; set; }\n}\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Transaction/ILoadGrain.cs",
    "content": "namespace BenchmarkGrainInterfaces.Transaction\n{\n    [GenerateSerializer]\n    public class Report\n    {\n        [Id(1)]\n        public int Succeeded { get; set; }\n\n        [Id(2)]\n        public int Failed { get; set; }\n\n        [Id(3)]\n        public int Throttled { get; set; }\n\n        [Id(4)]\n        public TimeSpan Elapsed { get; set; }\n    }\n\n    public interface ILoadGrain : IGrainWithGuidKey\n    {\n        Task Generate(int run, int transactions, int conncurrent);\n        Task<Report> TryGetReport();\n    }\n}"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Transaction/ITransactionGrain.cs",
    "content": "﻿namespace BenchmarkGrainInterfaces.Transaction\n{\n    public interface ITransactionGrain : IGrainWithIntegerKey\n    {\n        [Transaction(TransactionOption.CreateOrJoin)]\n        Task Run();\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrainInterfaces/Transaction/ITransactionRootGrain.cs",
    "content": "﻿namespace BenchmarkGrainInterfaces.Transaction\n{\n    public interface ITransactionRootGrain : IGrainWithGuidKey\n    {\n        [Transaction(TransactionOption.Create)]\n        Task Run(List<int> grains);\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/BenchmarkGrains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Transactions\\Orleans.Transactions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\BenchmarkGrainInterfaces\\BenchmarkGrainInterfaces.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/GrainStorage/PersistentGrain.cs",
    "content": "using System.Diagnostics;\nusing BenchmarkGrainInterfaces.GrainStorage;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\n\nnamespace BenchmarkGrains.GrainStorage\n{\n    [Serializable]\n    public class PersistentGrainState\n    {\n        public byte[] Payload { get; set; }\n    }\n\n    public class PersistentGrain : Grain, IPersistentGrain\n    {\n        private readonly ILogger<PersistentGrain> logger;\n        private readonly IPersistentState<PersistentGrainState> persistentState;\n\n        public PersistentGrain(\n            ILogger<PersistentGrain> logger,\n            [PersistentState(\"state\")]\n            IPersistentState<PersistentGrainState> persistentState)\n        {\n            this.logger = logger;\n            this.persistentState = persistentState;\n        }\n\n        public async Task Init(int payloadSize)\n        {\n            this.persistentState.State.Payload = Enumerable.Range(0, payloadSize).Select(i => (byte)i).ToArray();\n            await this.persistentState.WriteStateAsync();\n        }\n\n        public async Task<Report> TrySet(int index)\n        {\n            Stopwatch sw = Stopwatch.StartNew();\n            bool success;\n            try\n            {\n                await this.persistentState.ReadStateAsync();\n                this.persistentState.State.Payload[index] = (byte)(this.persistentState.State.Payload[index] + 1);\n                await this.persistentState.WriteStateAsync();\n                sw.Stop();\n                logger.LogInformation(\"Grain {GrainId} took {WriteTimeMs}ms to set state.\", this.GetPrimaryKey(), sw.ElapsedMilliseconds);\n                success = true;\n            } catch(Exception ex)\n            {\n                sw.Stop();\n                this.logger.LogError(ex, \"Grain {GrainId} failed to set state in {WriteTimeMs}ms to set state.\",  this.GetPrimaryKey(), sw.ElapsedMilliseconds );\n                success = false;\n            }\n\n            return new Report\n            {\n                Success = success,\n                Elapsed = sw.Elapsed,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/MapReduce/BufferGrain.cs",
    "content": "﻿using BenchmarkGrainInterfaces.MapReduce;\n\nnamespace BenchmarkGrains.MapReduce\n{\n    public class BufferGrain<T> : DataflowGrain, IBufferGrain<T>\n    {\n        private readonly List<T> _items = new List<T>();\n        public Task<GrainDataflowMessageStatus> OfferMessage(T messageValue, bool consumeToAccept)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task SendAsync(T t)\n        {\n            this._items.Add(t);\n            return Task.CompletedTask;\n        }\n\n        public Task SendAsync(T t, GrainCancellationToken gct)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task LinkTo(ITargetGrain<T> t)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<T> ConsumeMessage()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<List<T>> ReceiveAll()\n        {\n            var items = this._items.ToList();\n            this._items.Clear();\n            return Task.FromResult(items);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/BenchmarkGrains/MapReduce/DataflowGrain.cs",
    "content": "﻿using BenchmarkGrainInterfaces.MapReduce;\n\nnamespace BenchmarkGrains.MapReduce\n{\n    public abstract class DataflowGrain : Grain, IDataflowGrain\n    {\n        public Task Complete()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task Fault()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task Completion()\n        {\n            throw new NotImplementedException();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/BenchmarkGrains/MapReduce/Processors.cs",
    "content": "﻿using BenchmarkGrainInterfaces.MapReduce;\n\nnamespace BenchmarkGrains.MapReduce\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class MapProcessor : ITransformProcessor<string, List<string>>\n    {\n        private static readonly char[] _delimiters = { '.', '?', '!', ' ', ';', ':', ',' };\n\n        public List<string> Process(string input)\n        {\n            return input\n                 .Split(_delimiters, StringSplitOptions.RemoveEmptyEntries)\n                 .ToList();\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class ReduceProcessor : ITransformProcessor<List<string>, Dictionary<string, int>>\n    {\n        public Dictionary<string, int> Process(List<string> input)\n        {\n            return input.GroupBy(v => v.ToLowerInvariant()).Select(v => new\n            {\n                key = v.Key,\n                count = v.Count()\n            }).ToDictionary(arg => arg.key, arg => arg.count);\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class EmptyProcessor : ITransformProcessor<Dictionary<string, int>, Dictionary<string, int>>\n    {\n        public Dictionary<string, int> Process(Dictionary<string, int> input)\n        {\n            return input;\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/BenchmarkGrains/MapReduce/TargetGrain.cs",
    "content": "﻿using BenchmarkGrainInterfaces.MapReduce;\n\nnamespace BenchmarkGrains.MapReduce\n{\n    public class TargetGrain<TInput> : DataflowGrain, ITargetGrain<TInput>\n    {\n        private ITargetProcessor<TInput> _processor;\n\n        public Task Init(ITargetProcessor<TInput> processor)\n        {\n            this._processor = processor;\n            return Task.CompletedTask;\n        }\n\n        public Task<GrainDataflowMessageStatus> OfferMessage(TInput messageValue, bool consumeToAccept)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task SendAsync(TInput t)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task SendAsync(TInput t, GrainCancellationToken gct)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/MapReduce/TransformGrain.cs",
    "content": "using System.Collections.Concurrent;\nusing BenchmarkGrainInterfaces.MapReduce;\n\nnamespace BenchmarkGrains.MapReduce\n{\n    public class TransformGrain<TInput, TOutput> : DataflowGrain, ITransformGrain<TInput, TOutput>\n    {\n        private ITransformProcessor<TInput, TOutput> _processor;\n        private bool _processingStarted ;\n        private bool _proccessingStopped;\n\n        private const bool ProcessOnThreadPool = true;\n\n        // it should be list\n        private ITargetGrain<TOutput> _target;\n\n        // BlockingCollection has shown worse perf results for this workload types\n        private readonly ConcurrentQueue<TInput> _input = new ConcurrentQueue<TInput>();\n\n        private readonly ConcurrentQueue<TOutput> _output = new ConcurrentQueue<TOutput>();\n\n        public Task Initialize(ITransformProcessor<TInput, TOutput> processor)\n        {\n            if (processor == null) throw new ArgumentNullException(nameof(processor));\n            this._processor = processor;\n            return Task.CompletedTask;\n        }\n\n        public Task<TOutput> ConsumeMessage()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task LinkTo(ITargetGrain<TOutput> t)\n        {\n            this._target = t;\n            return Task.CompletedTask;\n        }\n\n        public Task<GrainDataflowMessageStatus> OfferMessage(TInput messageValue, bool consumeToAccept)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task SendAsync(TInput t)\n        {\n            this._input.Enqueue(t);\n            NotifyOfPendingWork();\n            return Task.CompletedTask;\n        }\n\n        public Task SendAsync(TInput t, GrainCancellationToken gct)\n        {\n            throw new NotImplementedException();\n        }\n\n        private void NotifyOfPendingWork()\n        {\n            if (this._processingStarted) return;\n\n            var orleansTs = TaskScheduler.Current;\n            if (ProcessOnThreadPool)\n            {\n                Task.Run(async () =>\n                {\n                    while (!this._proccessingStopped)\n                    {\n                        TInput itemToProcess;\n                        if (!this._input.TryDequeue(out itemToProcess))\n                        {\n                            await Task.Delay(7);\n                            continue;\n                        }\n\n                        var processed = this._processor.Process(itemToProcess);\n                        await Task.Factory.StartNew(\n                            async () => await this._target.SendAsync(processed), CancellationToken.None, TaskCreationOptions.None, orleansTs);\n                    }\n                });\n            }\n\n            this._processingStarted = true;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            this._proccessingStopped = true;\n            this._processingStarted = false;\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task<List<TOutput>> ReceiveAll()\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Ping/LoadGrain.cs",
    "content": "using System.Diagnostics;\nusing BenchmarkGrainInterfaces.Ping;\n\nnamespace BenchmarkGrains.Ping\n{\n    public class LoadGrain : Grain, ILoadGrain\n    {\n        private Task<Report> runTask;\n        private bool end = false;\n\n        public Task Generate(int run, int conncurrent)\n        {\n            this.runTask = RunGeneration(run, conncurrent);\n            return Task.CompletedTask;\n        }\n\n        public async Task<Report> TryGetReport()\n        {\n            this.end = true;\n            return await this.runTask;\n        }\n\n        private async Task<Report> RunGeneration(int run, int conncurrent)\n        {\n            List<Pending> pendingWork = Enumerable.Range(run * conncurrent, conncurrent).Select(i => new Pending() { Grain = GrainFactory.GetGrain<IPingGrain>(i) }).ToList();\n            Report report = new Report();\n            Stopwatch sw = Stopwatch.StartNew();\n            while (!this.end)\n            {\n                foreach(Pending pending in pendingWork.Where(t => t.PendingCall == default))\n                {\n                    pending.PendingCall = pending.Grain.Run();\n                }\n                await ResolvePending(pendingWork, report);\n            }\n            await ResolvePending(pendingWork, report, true);\n            sw.Stop();\n            report.Elapsed = sw.Elapsed;\n            return report;\n        }\n\n        private static async Task ResolvePending(List<Pending> pendingWork, Report report, bool all = false)\n        {\n            try\n            {\n                if(all)\n                {\n                    await Task.WhenAll(pendingWork.Where(t => !t.PendingCall.IsCompletedSuccessfully).Select(p => p.PendingCall.AsTask()));\n                }\n                else\n                {\n                    await Task.WhenAny(pendingWork.Where(t => !t.PendingCall.IsCompletedSuccessfully).Select(p => p.PendingCall.AsTask()));\n                }\n            } catch (Exception) {}\n            foreach (Pending pending in pendingWork.Where(p => p.PendingCall != default))\n            {\n                if (pending.PendingCall.IsFaulted || pending.PendingCall.IsCanceled)\n                {\n                    report.Failed++;\n                    pending.PendingCall = default;\n                }\n                else if (pending.PendingCall.IsCompleted)\n                {\n                    report.Succeeded++;\n                    pending.PendingCall = default;\n                }\n            }\n        }\n\n        private class Pending\n        {\n            public IPingGrain Grain { get; set; }\n            public ValueTask PendingCall { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Ping/PingGrain.cs",
    "content": "using BenchmarkGrainInterfaces.Ping;\nusing Orleans.Runtime;\n\nnamespace BenchmarkGrains.Ping\n{\n    public class PingGrain : IGrainBase, IPingGrain\n    {\n        private IPingGrain _self;\n\n        public PingGrain(IGrainContext context)\n        {\n            GrainContext = context;\n        }\n\n        public IGrainContext GrainContext { get; set; }\n\n        public Task OnActivateAsync(CancellationToken cancellationToken)\n\n        {\n            _self = this.AsReference<IPingGrain>();\n            return Task.CompletedTask;\n        }\n\n        public ValueTask Run() => default;\n\n        public ValueTask PingPongInterleave(IPingGrain other, int count)\n        {\n            if (count == 0) return default;\n            return other.PingPongInterleave(_self, count - 1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Ping/TreeGrain.cs",
    "content": "using BenchmarkGrainInterfaces.Ping;\n\nnamespace BenchmarkGrains.Ping;\n\npublic class TreeGrain : Grain, ITreeGrain\n{\n    // 16^4 grains (~65K)\n    public const int FanOutFactor = 16;\n    public const int MaxLevel = 4;\n    private readonly List<ITreeGrain> _children;\n\n    public TreeGrain()\n    {\n        var id = this.GetPrimaryKeyLong(out var forestName);\n\n        var level = id == 0 ? 0 : (int)Math.Log(id, FanOutFactor);\n        var numChildren = level < MaxLevel ? FanOutFactor : 0;\n        _children = new List<ITreeGrain>(numChildren);\n        var childBase = (id + 1) * FanOutFactor;\n        for (var i = 1; i <= numChildren; i++)\n        {\n            var child = GrainFactory.GetGrain<ITreeGrain>(childBase + i, keyExtension: forestName);\n            _children.Add(child);\n        }\n    }\n\n    public async ValueTask Ping()\n    {\n        var tasks = new List<ValueTask>(_children.Count);\n        foreach (var child in _children)\n        {\n            tasks.Add(child.Ping());\n        }\n\n        // Wait for the tasks to complete.\n        foreach (var task in tasks)\n        {\n            await task;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Transaction/LoadGrain.cs",
    "content": "using System.Diagnostics;\nusing BenchmarkGrainInterfaces.Transaction;\nusing Orleans.Transactions;\n\nnamespace BenchmarkGrains.Transaction\n{\n    [GrainType(\"txload\")]\n    public class LoadGrain : Grain, ILoadGrain\n    {\n        private Task<Report> runTask;\n\n        public Task Generate(int run, int transactions, int conncurrent)\n        {\n            this.runTask = RunGeneration(run, transactions, conncurrent);\n            this.runTask.Ignore();\n            return Task.CompletedTask;\n        }\n\n        public async Task<Report> TryGetReport()\n        {\n            if (!this.runTask.IsCompleted) return default;\n            return await this.runTask;\n        }\n\n        private async Task<Report> RunGeneration(int run, int transactions, int conncurrent)\n        {\n            List<Task> pending = new List<Task>();\n            Report report = new Report();\n            Stopwatch sw = Stopwatch.StartNew();\n            int generated = run * transactions * 2;\n            int max = generated + transactions;\n            while (generated < max)\n            {\n                while (generated < max && pending.Count < conncurrent)\n                {\n                    pending.Add(StartTransaction(generated++));\n                }\n                pending = await ResolvePending(pending, report);\n            }\n            await ResolvePending(pending, report, true);\n            sw.Stop();\n            report.Elapsed = sw.Elapsed;\n            return report;\n        }\n\n        private static async Task<List<Task>> ResolvePending(List<Task> pending, Report report, bool all = false)\n        {\n            try\n            {\n                if(all)\n                {\n                    await Task.WhenAll(pending);\n                }\n                else\n                {\n                    await Task.WhenAny(pending);\n                }\n            } catch (Exception) {}\n            List<Task> remaining = new List<Task>();\n            foreach (Task t in pending)\n            {\n                if (t.IsFaulted || t.IsCanceled)\n                {\n                    if(t.Exception.Flatten().GetBaseException() is OrleansStartTransactionFailedException)\n                    {\n                        report.Throttled++;\n\n                    } else\n                    {\n                        report.Failed++;\n                    }\n                }\n                else if (t.IsCompleted)\n                {\n                    report.Succeeded++;\n                }\n                else\n                {\n                    remaining.Add(t);\n                }\n            }\n            return remaining;\n        }\n\n        private async Task StartTransaction(int index)\n        {\n            try\n            {\n                await GrainFactory.GetGrain<ITransactionRootGrain>(Guid.Empty).Run(new List<int>() { index * 2, index * 2 + 1 });\n            } catch(OrleansStartTransactionFailedException)\n            {\n                // Depay before retry\n                await Task.Delay(TimeSpan.FromSeconds(1));\n                throw;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Transaction/TransactionGrain.cs",
    "content": "using Orleans.Transactions.Abstractions;\nusing BenchmarkGrainInterfaces.Transaction;\n\nnamespace BenchmarkGrains.Transaction\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class Info\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    public class TransactionGrain : Grain, ITransactionGrain\n    {\n        private readonly ITransactionalState<Info> info;\n\n        public TransactionGrain(\n            [TransactionalState(\"Info\")] ITransactionalState<Info> info)\n        {\n            this.info = info ?? throw new ArgumentNullException(nameof(info));\n        }\n\n        public Task Run()\n        {\n            return this.info.PerformUpdate(s => s.Value += 1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/BenchmarkGrains/Transaction/TransactionRootGrain.cs",
    "content": "﻿using Orleans.Concurrency;\nusing BenchmarkGrainInterfaces.Transaction;\n\nnamespace BenchmarkGrains.Transaction\n{\n    [Reentrant]\n    [StatelessWorker]\n    public class TransactionRootGrain : Grain, ITransactionRootGrain\n    {\n        public Task Run(List<int> grains)\n        {\n            return Task.WhenAll(grains.Select(id => GrainFactory.GetGrain<ITransactionGrain>(id).Run()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestFSharp/Grains.fs",
    "content": "namespace UnitTests.FSharpGrains\n\nopen System.Threading.Tasks\nopen UnitTests.GrainInterfaces\nopen Orleans\nopen Orleans.Metadata\n\n[<GrainType(\"fsharp.generic`1\")>]\ntype Generic1ArgumentGrain<'T>() = \n    inherit Grain()\n\n    interface INonGenericBase with \n        member x.Ping() = Task.CompletedTask\n\n    interface IGeneric1Argument<'T> with \n        member x.Ping(t:'T) = Task.FromResult(t);\n"
  },
  {
    "path": "test/Grains/TestFSharp/TestFSharp.fsproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <LangVersion>latest</LangVersion>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"Types.fs\" />\n    <Compile Include=\"Grains.fs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FSharp.Core\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Grains/TestFSharp/Types.fs",
    "content": "namespace UnitTests.FSharpTypes\n\nopen System.Runtime.CompilerServices\nopen Orleans\n\n[<Immutable; GenerateSerializer>]\ntype EnumStyleDU =\n    | Case1\n    | Case2\n    | Case3\n\n[<Immutable; GenerateSerializer>]\ntype MixCaseDU =\n    | Case1\n    | Case2 of string\n\n[<Immutable; GenerateSerializer>]\ntype RecursiveDU =\n    | Case1\n    | Case2 of RecursiveDU\n\n[<Immutable; GenerateSerializer>]\ntype GenericDU<'T> =\n    | Case1 of 'T\n    | Case2\n\n[<Immutable; GenerateSerializer>]\ntype PrivateConstructorDU =\n    private Constructor of string\n        static member SomeValue =\n            Constructor \"some value\"\n\n[<Immutable; GenerateSerializer>]\ntype PrivateConstructorDoubleCaseDU =\n    private\n        | ConstructorOne of string\n        | ConstructorTwo of value: int\n    static member One =\n        ConstructorOne \"some one\"\n    static member Two =\n        ConstructorTwo 2\n\n[<Immutable; GenerateSerializer>]\ntype SingleCaseDU =\n    | Case1 of int\n    static member ofInt i = Case1 i\n\n[<Immutable; GenerateSerializer>]\ntype DoubleCaseDU =\n    | Case1 of string\n    | Case2 of int\n\n[<Immutable; GenerateSerializer>]\ntype TripleCaseDU =\n    | Case1 of string\n    | Case2 of int\n    | Case3 of char\n\n[<Immutable; GenerateSerializer>]\ntype QuadrupleCaseDU =\n    | Case1 of string\n    | Case2 of int\n    | Case3 of char\n    | Case4 of byte\n\n[<Immutable; GenerateSerializer>]\ntype NamedFieldsSingleCaseDU =\n    | Case1 of something: string\n\n[<Immutable; GenerateSerializer>]\ntype NamedFieldsDoubleCaseDU =\n    | Case1 of something: string * int\n    | Case2 of other: string\n\n[<Immutable; GenerateSerializer>]\ntype NamedFieldsTripleCaseDU =\n    | Case1 of something: string\n    | Case2 of other: string * byte\n    | Case3 of string * second: string * third: int\n\n[<Immutable; GenerateSerializer>]\ntype QuintupleCaseDU =\n    | Case1\n    | Case2 of number: int * string\n    | Case3\n    | Case4 of theByte: byte * theLong: int64\n    | Case5 of string\n\n[<Immutable; GenerateSerializer>]\ntype DUMutually =\n    | Case1 of int\n    | Case2 of DURecursive\nand [<Immutable; GenerateSerializer>] DURecursive =\n    | Case1 of DUMutually\n    | Case2 of DURecursive * DUMutually\n\n[<Struct; GenerateSerializer>]\ntype SingleCaseStructDU = Case of string\n\n[<Struct; GenerateSerializer>]\ntype MulticaseStructDU =\n    | Case1 of value1: string\n    | Case2 of value2: string\n    | Case3 of valueInt: int\n    | Case4\n    | Case5 of int64\n\n[<Immutable; GenerateSerializer>]\ntype Record = {  [<Id(1u)>] A: SingleCaseDU } with\n    static member ofInt x = { A = SingleCaseDU.ofInt x }\n\n[<Immutable; GenerateSerializer>]\ntype RecordOfIntOption = {  [<Id(1u)>] A: int option } with\n    static member Empty = { A = None }\n    static member ofInt x = { A = Some x}\n\n[<Immutable; GenerateSerializer>]\ntype RecordOfIntOptionWithNoAttributes = {  [<Id(1u)>] A: int option } with\n    static member Empty = { A = None }\n    static member ofInt x = { A = Some x}\n\n[<Immutable; GenerateSerializer>]\ntype GenericRecord<'T> = { [<Id(1u)>] Value: 'T } with\n    static member ofT x = { Value = x }\n\n[<Immutable; GenerateSerializer>]\ntype DiscriminatedUnion =\n    | ArrayFieldCase of int array\n    | ListFieldCase of int list\n    | MapFieldCase of Map<int,string>\n    | SetFieldCase of Set<int>\n\n    static member array l = ArrayFieldCase l\n    static member emptyArray() = ArrayFieldCase [||]\n    static member nonEmptyArray() = ArrayFieldCase [|1; 2; 3|]\n\n    static member list l = ListFieldCase l\n    static member emptyList() = ListFieldCase []\n    static member nonEmptyList() = ListFieldCase [1; 2; 3]\n\n    static member set s = SetFieldCase s\n    static member emptySet() = SetFieldCase Set.empty\n    static member nonEmptySet() = Set.ofList [1; 2; 3] |> SetFieldCase\n\n    static member map m = MapFieldCase m\n    static member emptyMap() = MapFieldCase Map.empty\n    static member nonEmptyMap() = Map.ofList [0, \"zero\"; 1, \"one\"] |> MapFieldCase\n\n[<InternalsVisibleTo(\"TestFSharpGrainInterfaces\")>]\ndo ()\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/FSharpInterfaces/IFSharpBaseInterface.fs",
    "content": "namespace UnitTests.FSharpInterfaces\n\nopen System.Threading.Tasks\n\ntype public IFSharpBaseInterface =\n    abstract Echo: int -> Task<int>\n    abstract MultipleParameterEcho: string -> int -> Task<string*int>\n\n\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/FSharpInterfaces/IFSharpParameters.fs",
    "content": "﻿namespace UnitTests.FSharpInterfaces\n\nopen System.Threading.Tasks\n\ntype public DiscriminatedUnion<'T> =\n    | Nothing\n    | Something of 'T\n\ntype public IFSharpParameters<'T> =\n    abstract OptionRoundtrip: 'T option -> Task<'T option>\n\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/FSharpInterfaces/TestFSharpInterfaces.fsproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <LangVersion>latest</LangVersion>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"IFSharpBaseInterface.fs\" />\n    <Compile Include=\"IFSharpParameters.fs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FSharp.Core\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/IFSharpParametersGrain.cs",
    "content": "using UnitTests.FSharpGrains;\nusing UnitTests.FSharpInterfaces;\n\n[assembly: GenerateCodeForDeclaringAssembly(typeof(Generic1ArgumentGrain<>))]\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IFSharpParametersGrain<T,U> : IGrainWithGuidKey, IFSharpParameters<T>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/IGeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain.cs",
    "content": "﻿using UnitTests.FSharpInterfaces;\n\nnamespace UnitTests.GrainInterfaces\n{\n    // uncomment the following interface definition to reproduce #1349\n\n    public interface IGeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain : IGrainWithGuidKey, IFSharpBaseInterface\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestFSharpGrainInterfaces/TestFSharpGrainInterfaces.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.GrainInterfaces</RootNamespace>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestFSharp\\TestFSharp.fsproj\" />\n    <ProjectReference Include=\"FSharpInterfaces\\TestFSharpInterfaces.fsproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Serialization.FSharp\\Orleans.Serialization.FSharp.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FSharp.Core\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" />\n    <PackageReference Include=\"Newtonsoft.Json\" />\n    <PackageReference Include=\"protobuf-net\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/AdoNet/ICustomerGrain.cs",
    "content": "﻿namespace Orleans.SqlUtils.StorageProvider.GrainInterfaces\n{\n    public interface ICustomerGrain : IGrainWithIntegerKey\n    {\n        Task<string> IntroduceSelf();\n         \n        Task Set(int customerId, string firstName, string lastName);\n\n        Task AddDevice(IDeviceGrain device);\n\n        Task SetRandomState();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/AdoNet/IDeviceGrain.cs",
    "content": "﻿namespace Orleans.SqlUtils.StorageProvider.GrainInterfaces\n{\n    public interface IDeviceGrain : IGrainWithGuidKey\n    {\n        Task<string> GetSerialNumber();\n\n        Task SetOwner(ICustomerGrain customer);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ClassNotReferencingOrleansTypeDto.cs",
    "content": "﻿namespace UnitTests.Dtos\n{\n    [Serializable]\n    public class ClassNotReferencingOrleansTypeDto\n    {\n        public string MyProperty { get; set; }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ClassReferencingOrleansTypeDto.cs",
    "content": "namespace UnitTests.DtosRefOrleans\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class ClassReferencingOrleansTypeDto\n    {\n        static ClassReferencingOrleansTypeDto()\n        {\n            _ = typeof(IGrain).ToString();\n        }\n\n        [Id(0)]\n        public string MyProperty { get; set; }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/CodegenTestInterfaces.cs",
    "content": "using System.Collections;\n\nnamespace UnitTests.GrainInterfaces\n{\n    using Orleans.Concurrency;\n\n    namespace One\n    {\n        [GenerateSerializer]\n        public class Command\n        {\n        }\n    }\n\n    namespace Two\n    {\n        [GenerateSerializer]\n        public class Command\n        {\n        }\n    }\n\n    /// <summary>\n    /// Repro for https://github.com/dotnet/orleans/issues/3713.\n    /// Having multiple methods with the same name and same parameter type\n    /// name would cause a code generation failure because only one of the\n    /// methods would be implemented in the generated GrainReference.\n    /// </summary>\n    internal interface ISameNameParameterTypeGrain : IGrainWithIntegerKey\n    {\n        Task ExecuteCommand(One.Command command);\n        Task ExecuteCommand(Two.Command command);\n    }\n\n    internal interface IInternalPingGrain : IGrainWithIntegerKey\n    {\n        Task Ping();\n    }\n\n    public interface ISomeGrain : IGrainWithIntegerKey\n    {\n        Task Do(Outsider o);\n    }\n\n    public interface ISerializationGenerationGrain : IGrainWithIntegerKey\n    {\n        Task<object> RoundTripObject(object input);\n        Task<SomeStruct> RoundTripStruct(SomeStruct input);\n        Task<SomeAbstractClass> RoundTripClass(SomeAbstractClass input);\n        Task<ISomeInterface> RoundTripInterface(ISomeInterface input);\n        Task<SomeAbstractClass.SomeEnum> RoundTripEnum(SomeAbstractClass.SomeEnum input);\n\n        Task SetState(SomeAbstractClass input);\n        Task<SomeAbstractClass> GetState();\n    }\n}\n\n[GenerateSerializer]\npublic class Outsider { }\n\nnamespace UnitTests.GrainInterfaces\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class CaseInsensitiveStringEquality : EqualityComparer<string>\n    {\n        public override bool Equals(string x, string y)\n        {\n            return x.Equals(y, StringComparison.OrdinalIgnoreCase);\n        }\n\n        public override int GetHashCode(string obj)\n        {\n            return obj.ToLowerInvariant().GetHashCode();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Mod5IntegerComparer : EqualityComparer<int>\n    {\n        public override bool Equals(int x, int y)\n        {\n            return ((x - y) % 5) == 0;\n        }\n\n        public override int GetHashCode(int obj)\n        {\n            return obj % 5;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class CaseInsensitiveStringComparer : Comparer<string>\n    {\n        public override int Compare(string x, string y)\n        {\n            var x1 = x.ToLowerInvariant();\n            var y1 = y.ToLowerInvariant();\n            return Comparer<string>.Default.Compare(x1, y1);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class RootType\n    {\n        public RootType()\n        {\n            MyDictionary = new Dictionary<string, object>();\n            MyDictionary.Add(\"obj1\", new InnerType());\n            MyDictionary.Add(\"obj2\", new InnerType());\n            MyDictionary.Add(\"obj3\", new InnerType());\n            MyDictionary.Add(\"obj4\", new InnerType());\n        }\n\n        [Id(0)]\n        public Dictionary<string, object> MyDictionary { get; set; }\n\n        public override bool Equals(object obj)\n        {\n            var actual = obj as RootType;\n            if (actual == null)\n            {\n                return false;\n            }\n            if (MyDictionary == null) return actual.MyDictionary == null;\n            if (actual.MyDictionary == null) return false;\n\n            var set1 = new HashSet<KeyValuePair<string, object>>(MyDictionary);\n            var set2 = new HashSet<KeyValuePair<string, object>>(actual.MyDictionary);\n            bool ret = set1.SetEquals(set2);\n            return ret;\n        }\n\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public struct SomeStruct\n    {\n        [Id(0)]\n        public Guid Id { get; set; }\n        [Id(1)]\n        public int PublicValue { get; set; }\n        [Id(2)]\n        public int ValueWithPrivateSetter { get; private set; }\n        [Id(3)]\n        public int ValueWithPrivateGetter { private get; set; }\n        [Id(4)]\n        private int PrivateValue { get; set; }\n\n        [Id(5)]\n        public readonly int ReadonlyField;\n\n        [Id(6)]\n        public IEchoGrain SomeGrainReference { get; set; }\n\n        public SomeStruct(int readonlyField)\n            : this()\n        {\n            this.ReadonlyField = readonlyField;\n        }\n\n        public readonly int GetValueWithPrivateGetter()\n        {\n            return this.ValueWithPrivateGetter;\n        }\n\n        public readonly int GetPrivateValue()\n        {\n            return this.PrivateValue;\n        }\n\n        public void SetPrivateValue(int value)\n        {\n            this.PrivateValue = value;\n        }\n\n        public void SetValueWithPrivateSetter(int value)\n        {\n            this.ValueWithPrivateSetter = value;\n        }\n    }\n\n    public interface ISomeInterface { int Int { get; set; } }\n\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class SomeAbstractClass : ISomeInterface\n    {\n        [NonSerialized]\n        private int _nonSerializedIntField;\n\n        public abstract int Int { get; set; }\n\n        [Id(1)]\n        public List<ISomeInterface> Interfaces { get; set; }\n\n        [Id(2)]\n        public SomeAbstractClass[] Classes { get; set; }\n\n        [Obsolete(\"This field should not be serialized\", true)]\n        [Id(3)]\n        public int ObsoleteIntWithError { get; set; }\n\n        [Obsolete(\"This field should be serialized\")]\n        [Id(4)]\n        public int ObsoleteInt { get; set; }\n\n        [Id(5)]\n        public IEchoGrain SomeGrainReference { get; set; }\n        \n#pragma warning disable 618\n        public int GetObsoleteInt() => this.ObsoleteInt;\n        public void SetObsoleteInt(int value)\n        {\n            this.ObsoleteInt = value;\n        }\n#pragma warning restore 618\n\n        [Id(6)]\n        public SomeEnum Enum { get; set; }\n\n        public int NonSerializedInt\n        {\n            get\n            {\n                return this._nonSerializedIntField;\n            }\n\n            set\n            {\n                this._nonSerializedIntField = value;\n            }\n        }\n\n        [Serializable]\n        public enum SomeEnum\n        {\n            None,\n\n            Something,\n\n            SomethingElse\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class AnotherConcreteClass : SomeAbstractClass\n    {\n        [Id(0)]\n        public override int Int { get; set; }\n\n        [Id(1)]\n        public string AnotherString { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class InnerType\n    {\n        public InnerType()\n        {\n            Id = Guid.NewGuid();\n            Something = Id.ToString();\n        }\n\n        [Id(0)]\n        public Guid Id { get; set; }\n        [Id(1)]\n        public string Something { get; set; }\n\n        public override bool Equals(object obj)\n        {\n            var actual = obj as InnerType;\n            if (actual == null)\n            {\n                return false;\n            }\n            return Id.Equals(actual.Id) && Equals(Something, actual.Something);\n        }\n\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class ClassWithStructConstraint<T>\n        where T : struct\n    {\n        [Id(0)]\n        public T Value { get; set; }\n    }\n\n    // This class should not have a serializer generated for it, since the serializer would not be able to access\n    // the nested private class.\n    [Serializable]\n    public class ClassWithNestedPrivateClassInListField\n    {\n        private readonly List<NestedPrivateClass> _coolBeans = new List<NestedPrivateClass>\n        {\n            new NestedPrivateClass()\n        };\n\n        public IEnumerable CoolBeans => this._coolBeans;\n\n        private class NestedPrivateClass\n        {\n        }\n    }\n\n    /// <summary>\n    /// Regression test for https://github.com/dotnet/orleans/issues/5243.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public readonly struct ReadOnlyStructWithReadOnlyArray\n    {\n#pragma warning disable IDE0032 // Use auto property\n        [Id(0)]\n        private readonly byte[] _value;\n#pragma warning restore IDE0032 // Use auto property\n\n        public ReadOnlyStructWithReadOnlyArray(byte[] value) => this._value = value;\n\n        public byte[] Value => this._value;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/CustomPlacement.cs",
    "content": "using Orleans.Metadata;\nusing Orleans.Placement;\nusing Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface ICustomPlacementTestGrain : IGrainWithGuidKey\n    {\n        Task<string> GetRuntimeInstanceId();\n    }\n\n    public interface IHashBasedPlacementGrain : IGrainWithGuidKey\n    {\n        Task<SiloAddress> GetSiloAddress();\n    }\n\n\n    public enum CustomPlacementScenario\n    {\n        FixedSilo,\n        ExcludeOne,\n        RequestContextBased,\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class TestCustomPlacementStrategy : PlacementStrategy\n    {\n        private const string ScenarioKey = \"test-placement-scenario\";\n\n        [Id(0)]\n        public CustomPlacementScenario Scenario { get; private set; }\n\n        public static TestCustomPlacementStrategy FixedSilo { get; } = new TestCustomPlacementStrategy(CustomPlacementScenario.FixedSilo);\n        public static TestCustomPlacementStrategy ExcludeOne { get; } = new TestCustomPlacementStrategy(CustomPlacementScenario.ExcludeOne);\n        public static TestCustomPlacementStrategy RequestContextBased { get; } = new TestCustomPlacementStrategy(CustomPlacementScenario.RequestContextBased);\n\n        internal TestCustomPlacementStrategy(CustomPlacementScenario scenario)\n        {\n            Scenario = scenario;\n        }\n\n        public TestCustomPlacementStrategy() { }\n\n        public override void Initialize(GrainProperties properties)\n        {\n            base.Initialize(properties);\n            CustomPlacementScenario result;\n            if (properties.Properties.TryGetValue(ScenarioKey, out var value) && Enum.TryParse(value, out result))\n            {\n                this.Scenario = result;\n            }\n        }\n\n        public override void PopulateGrainProperties(IServiceProvider services, Type grainClass, GrainType grainType, Dictionary<string, string> properties)\n        {\n            base.PopulateGrainProperties(services, grainClass, grainType, properties);\n            properties[ScenarioKey] = this.Scenario.ToString();\n        }\n    }\n\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public sealed class TestPlacementStrategyAttribute : PlacementAttribute\n    {\n        public CustomPlacementScenario Scenario { get; private set; }\n\n        public TestPlacementStrategyAttribute(CustomPlacementScenario scenario) :\n            base(GetCustomPlacementStrategy(scenario))\n        {\n            Scenario = scenario;\n        }\n\n        private static TestCustomPlacementStrategy GetCustomPlacementStrategy(CustomPlacementScenario scenario)\n        {\n            switch (scenario)\n            {\n                case CustomPlacementScenario.FixedSilo:\n                    return TestCustomPlacementStrategy.FixedSilo;\n                case CustomPlacementScenario.ExcludeOne:\n                    return TestCustomPlacementStrategy.ExcludeOne;\n                case CustomPlacementScenario.RequestContextBased:\n                    return TestCustomPlacementStrategy.RequestContextBased;\n                default:\n                    throw new Exception(\"Unknown CustomPlacementScenario\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/Directories/ICommonDirectoryGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces.Directories\n{\n    public interface ICommonDirectoryGrain : IGrainWithGuidKey\n    {\n        Task<int> Ping();\n\n        Task Reset();\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task<int> ProxyPing(ICommonDirectoryGrain grain);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/Directories/ICustomDirectoryGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces.Directories\n{\n    public interface ICustomDirectoryGrain : ICommonDirectoryGrain\n    { }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/Directories/IDefaultDirectoryGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces.Directories\n{\n    public interface IDefaultDirectoryGrain : ICommonDirectoryGrain\n    { }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/IAccountGrain.cs",
    "content": "﻿namespace TestGrainInterfaces\n{\n    /// <summary>\n    /// A grain that models a bank account\n    /// </summary>\n    public interface IAccountGrain : IGrainWithStringKey\n    {\n        Task<uint> Balance();\n\n        Task Deposit(uint amount, Guid guid, string desc);\n\n        Task<bool> Withdraw(uint amount, Guid guid, string desc);\n\n        Task<IReadOnlyList<Transaction>> GetTransactionLog();\n    }\n\n    // the classes below represent events/transactions on the account\n    // all fields are user-defined (none have a special meaning),\n    // so these can be any type of object you like, as long as they are serializable\n    // (so they can be sent over the wire and persisted in a log).\n\n    [Serializable]\n    [GenerateSerializer]\n    public abstract class Transaction\n    {\n        /// <summary> A unique identifier for this transaction  </summary>\n        [Id(0)]\n        public Guid Guid { get; set; }\n\n        /// <summary> A description for this transaction  </summary>\n        [Id(1)]\n        public string Description { get; set; }\n\n        /// <summary> time on which the request entered the system  </summary>\n        [Id(2)]\n        public DateTime IssueTime { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class DepositTransaction : Transaction\n    {\n        [Id(0)]\n        public uint DepositAmount { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class WithdrawalTransaction : Transaction\n    {\n        [Id(0)]\n        public uint WithdrawalAmount { get; set; }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/IChatGrain.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing System.Xml.Linq;\n\nnamespace TestGrainInterfaces\n{\n    /// <summary>\n    /// The grain interface for the chat grain.\n    /// </summary>\n    public interface IChatGrain : IGrainWithStringKey\n    {\n        /// <summary> Return the current content of the chat room. </summary>\n        Task<XDocument> GetChat();\n\n        /// <summary> Add a new post. </summary>\n        Task Post(Guid guid, string user, string text);\n\n        /// <summary> Delete a specific post. </summary>\n        Task Delete(Guid guid);\n\n        /// <summary> Edit a specific post. </summary>\n        Task Edit(Guid guid, string text);\n    }\n\n    /// <summary>\n    /// Since XDocument does not seem to serialize automatically, we provide the necessary methods\n    /// </summary>\n    [RegisterSerializer]\n    [RegisterCopier]\n    public class XDocumentSerialization : GeneralizedReferenceTypeSurrogateCodec<XDocument, XDocumentSurrogate>, IDeepCopier<XDocument>\n    {\n        public XDocumentSerialization(IValueSerializer<XDocumentSurrogate> surrogateSerializer) : base(surrogateSerializer)\n        {\n        }\n\n        public override XDocument ConvertFromSurrogate(ref XDocumentSurrogate surrogate) => XDocument.Load(new StringReader(surrogate.Value));\n        public override void ConvertToSurrogate(XDocument value, ref XDocumentSurrogate surrogate) => surrogate.Value = value.ToString();\n        public XDocument DeepCopy(XDocument input, CopyContext context) => new(input);\n    }\n\n    [GenerateSerializer]\n    public struct XDocumentSurrogate\n    {\n        [Id(0)]\n        public string Value { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/ICountersGrain.cs",
    "content": "﻿namespace TestGrainInterfaces\n{\n\n    /// <summary>\n    /// A grain that maintains a number of counters, indexed by a string key\n    /// </summary>\n    public interface ICountersGrain : Orleans.IGrainWithIntegerKey\n    {\n        /// <summary> Updates the counter for the given key by the given amount </summary>\n        Task Add(string key, int amount, bool wait_for_confirmation);\n\n        /// <summary> Resets all counters to zero </summary>\n        Task Reset(bool wait_for_confirmation);\n\n        /// <summary> Retrieves the tentative value of the counter for the given key </summary>\n        Task<int> GetTentativeCount(string key);\n\n        /// <summary> Retrieves the tentative value of all counters </summary>\n        Task<IReadOnlyDictionary<string, int>> GetTentativeState();\n\n        /// <summary> Retrieves the confirmed value of all counters </summary>\n        Task<IReadOnlyDictionary<string, int>> GetConfirmedState();\n\n        /// <summary> Confirm all events </summary>\n        Task ConfirmAllPreviouslyRaisedEvents();\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/IPersonGrain.cs",
    "content": "namespace TestGrainInterfaces\n{\n    public enum GenderType\n    {\n        Male,\n        Female\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PersonAttributes\n    {\n        [Orleans.Id(0)]\n        public string FirstName { get; set; }\n        [Orleans.Id(1)]\n        public string LastName { get; set; }\n        [Orleans.Id(2)]\n        public GenderType Gender { get; set; }\n    }\n\n    /// <summary>\n    /// Orleans grain communication interface IPerson\n    /// </summary>\n    public interface IPersonGrain : Orleans.IGrainWithGuidKey\n    {\n        Task RegisterBirth(PersonAttributes person);\n        Task Marry(IPersonGrain spouse);\n\n        Task<PersonAttributes> GetTentativePersonalAttributes();\n\n        // Tests\n\n        Task RunTentativeConfirmedStateTest();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/ISeatReservationGrain.cs",
    "content": "﻿namespace TestGrainInterfaces\n{\n    // The grain supports an operation to reserve a seat\n    public interface ISeatReservationGrain : IGrainWithIntegerKey\n    {\n        // returns a boolean if reservation was successful\n        Task<bool> Reserve(int seatnumber, string userid);\n    }\n\n\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/EventSourcing/XDocumentSurrogate.cs",
    "content": "namespace TestGrainInterfaces\n{\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/GetGrainInterfaces.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IBase : IGrainWithIntegerKey\n    {\n        Task<bool> Foo();\n    }\n\n    public interface IDerivedFromBase : IBase\n    {\n        Task<bool> Bar();\n    }\n\n    public interface IBase1 : IGrainWithIntegerKey\n    {\n        Task<bool> Foo();\n    }\n\n    public interface IBase2 : IGrainWithIntegerKey\n    {\n        Task<bool> Bar();\n    }\n\n    public interface IBase3 : IGrainWithIntegerKey\n    {\n        Task<bool> Foo();\n    }\n\n    public interface IBase4 : IGrainWithIntegerKey\n    {\n        Task<bool> Foo();\n    }\n\n    public interface IStringGrain : IGrainWithStringKey\n    {\n        Task<bool> Foo();\n    }\n\n    public interface IGuidGrain : IGrainWithGuidKey\n    {\n        Task<bool> Foo();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/GrainInterfaceHierarchyIGrains.cs",
    "content": "﻿namespace TestGrainInterfaces\n{\n    public interface IDoSomething\n    {\n        Task<string> DoIt();\n\n        Task SetA(int a);\n\n        Task IncrementA();\n\n        Task<int> GetA();\n    }\n\n    public interface IDoSomethingWithMoreGrain : IDoSomething, IGrainWithIntegerKey\n    {\n        Task<string> DoThat();\n\n        Task SetB(int a);\n\n        Task IncrementB();\n\n        Task<int> GetB();\n    }\n\n    public interface IDoSomethingEmptyGrain : IDoSomething, IGrainWithIntegerKey\n    {\n    }\n\n    public interface IDoSomethingEmptyWithMoreGrain : IDoSomethingEmptyGrain\n    {\n        Task<string> DoMore();\n    }\n\n    public interface IDoSomethingWithMoreEmptyGrain : IDoSomethingEmptyWithMoreGrain\n    {\n    }\n\n    public interface IDoSomethingCombinedGrain : IDoSomethingWithMoreGrain, IDoSomethingWithMoreEmptyGrain\n    {\n        Task SetC(int a);\n\n        Task IncrementC();\n\n        Task<int> GetC();\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IActivateDeactivateTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    // Note: Self-managed can only implement one grain interface, so have to use copy-paste rather than subclassing \n\n    public interface ISimpleActivateDeactivateTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n        Task DoDeactivate();\n    }\n\n    public interface ITailCallActivateDeactivateTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n        Task DoDeactivate();\n    }\n\n    public interface ILongRunningActivateDeactivateTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n        Task DoDeactivate();\n    }\n\n    public interface IBadActivateDeactivateTestGrain : IGrainWithIntegerKey\n    {\n        Task ThrowSomething();\n        Task<long> GetKey();\n    }\n\n    public interface IBadConstructorTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n    }\n\n    public interface ITaskActionActivateDeactivateTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n        Task DoDeactivate();\n    }\n\n    public interface ICreateGrainReferenceTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n\n        Task ForwardCall(IBadActivateDeactivateTestGrain otherGrain);\n    }\n\n    public interface IDeactivatingWhileActivatingTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> DoSomething();\n    }\n    \n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IActivateDeactivateWatcherGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IActivateDeactivateWatcherGrain : IGrainWithIntegerKey\n    {\n        Task<string[]> GetActivateCalls();\n        Task<string[]> GetDeactivateCalls();\n\n        Task Clear();\n\n        Task RecordActivateCall(string activation);\n        Task RecordDeactivateCall(string activation);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IActivationCancellationTestGrain.cs",
    "content": "#nullable enable\n\nnamespace UnitTests.GrainInterfaces;\n\n/// <summary>\n/// Interface for testing activation cancellation scenarios.\n/// These grains are used to verify the proper handling of cancellation during grain activation.\n/// </summary>\npublic interface IActivationCancellationTestGrain : IGrainWithGuidKey\n{\n    /// <summary>\n    /// A simple method to test that the grain is activated and working.\n    /// </summary>\n    Task<string> GetActivationId();\n\n    /// <summary>\n    /// Checks if the activation was successful.\n    /// </summary>\n    Task<bool> IsActivated();\n}\n\n/// <summary>\n/// Grain that throws OperationCanceledException during OnActivateAsync when the cancellation token is triggered.\n/// This simulates code that properly observes the cancellation token.\n/// </summary>\npublic interface IActivationCancellation_ThrowsOperationCancelledGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that throws ObjectDisposedException during OnActivateAsync when trying to access disposed services.\n/// This simulates code that doesn't observe the cancellation token but tries to access services that have been disposed.\n/// </summary>\npublic interface IActivationCancellation_ThrowsObjectDisposedGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that throws a generic exception during OnActivateAsync (not related to cancellation).\n/// This is used to verify that non-cancellation exceptions are still handled properly.\n/// </summary>\npublic interface IActivationCancellation_ThrowsGenericExceptionGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that activates successfully without any issues.\n/// This is a baseline to verify normal activation continues to work.\n/// </summary>\npublic interface IActivationCancellation_SuccessfulActivationGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that throws TaskCanceledException during OnActivateAsync.\n/// TaskCanceledException inherits from OperationCanceledException and should be handled the same way.\n/// </summary>\npublic interface IActivationCancellation_ThrowsTaskCancelledGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that throws ObjectDisposedException unconditionally (not due to cancellation).\n/// This tests that ObjectDisposedException thrown for other reasons is NOT treated as cancellation.\n/// </summary>\npublic interface IActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain : IActivationCancellationTestGrain;\n\n/// <summary>\n/// Grain that throws OperationCanceledException unconditionally (not due to cancellation).\n/// This tests that OperationCanceledException thrown for other reasons is NOT treated as cancellation.\n/// </summary>\npublic interface IActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain : IActivationCancellationTestGrain;\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IActivityGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IActivityGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n    }\n\n    /// <summary>\n    /// Grain interface for testing IAsyncEnumerable activity tracing.\n    /// </summary>\n    public interface IAsyncEnumerableActivityGrain : IGrainWithIntegerKey\n    {\n        /// <summary>\n        /// Gets multiple ActivityData items as an async enumerable.\n        /// Each item captures the current Activity context at the time of yield.\n        /// </summary>\n        /// <param name=\"count\">Number of items to yield.</param>\n        /// <param name=\"cancellationToken\">Cancellation token.</param>\n        /// <returns>An async enumerable of ActivityData items.</returns>\n        IAsyncEnumerable<ActivityData> GetActivityDataStream(int count, CancellationToken cancellationToken = default);\n    }\n\n    [GenerateSerializer]\n    public class ActivityData\n    {\n        [Id(0)]\n        public string Id { get; set; }\n\n        [Id(1)]\n        public string TraceState { get; set; }\n\n        [Id(2)]\n        public List<KeyValuePair<string, string>> Baggage { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ICSharpBaseInterface.cs",
    "content": "﻿namespace UnitTests.Interfaces\n{\n    public interface ICSharpBaseInterface\n    {\n        Task<int> Echo(int x);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ICancellationTestSystemTarget.cs",
    "content": "#nullable enable\nnamespace UnitTests.GrainInterfaces;\n\n/// <summary>\n/// System target interface for testing CancellationToken propagation and handling.\n/// Note: All SystemTarget calls are interleaving by default - they execute immediately without queueing.\n/// </summary>\npublic interface ICancellationTestSystemTarget : ISystemTarget\n{\n    /// <summary>\n    /// Gets the runtime instance identifier for the silo hosting this system target.\n    /// </summary>\n    Task<string> GetRuntimeInstanceId();\n\n    /// <summary>\n    /// Performs a long wait that can be cancelled via the provided cancellation token.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <param name=\"delay\">The delay to wait.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task LongWait(CancellationToken cancellationToken, TimeSpan delay, Guid callId);\n\n    /// <summary>\n    /// Calls another system target's LongWait method, passing through the cancellation token.\n    /// </summary>\n    /// <param name=\"target\">The target system target to call.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <param name=\"delay\">The delay to wait.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task CallOtherLongRunningTask(ICancellationTestSystemTarget target, CancellationToken cancellationToken, TimeSpan delay, Guid callId);\n\n    /// <summary>\n    /// Calls another system target's LongWait method with a locally created cancellation token\n    /// that is cancelled after a specified delay.\n    /// </summary>\n    /// <param name=\"target\">The target system target to call.</param>\n    /// <param name=\"delay\">The delay for the long wait.</param>\n    /// <param name=\"delayBeforeCancel\">The delay before cancelling.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task CallOtherLongRunningTaskWithLocalCancellation(ICancellationTestSystemTarget target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId);\n\n    /// <summary>\n    /// Tests that cancellation token callbacks execute in the correct execution context.\n    /// Returns true if the callback ran on the correct TaskScheduler.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task<bool> CancellationTokenCallbackResolve(CancellationToken cancellationToken, Guid callId);\n\n    /// <summary>\n    /// Calls another system target's CancellationTokenCallbackResolve method with a locally created\n    /// cancellation token that is cancelled after a delay.\n    /// </summary>\n    /// <param name=\"target\">The target system target to call.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task<bool> CallOtherCancellationTokenCallbackResolve(ICancellationTestSystemTarget target, Guid callId);\n\n    /// <summary>\n    /// Tests that exceptions thrown in cancellation callbacks do not propagate.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <param name=\"callId\">A unique identifier for this call, used to track cancellations.</param>\n    Task CancellationTokenCallbackThrow(CancellationToken cancellationToken, Guid callId);\n\n    /// <summary>\n    /// Checks if a specific call was cancelled.\n    /// </summary>\n    /// <param name=\"callId\">The call identifier to check.</param>\n    /// <returns>True if the call was cancelled, false otherwise.</returns>\n    Task<bool> WasCallCancelled(Guid callId);\n\n    /// <summary>\n    /// Waits for a specific call to be cancelled.\n    /// </summary>\n    /// <param name=\"callId\">The call identifier to wait for.</param>\n    /// <param name=\"timeout\">The maximum time to wait.</param>\n    /// <returns>A tuple containing whether the call was cancelled and any error that occurred.</returns>\n    Task<(bool WasCancelled, Exception? Error)> WaitForCancellation(Guid callId, TimeSpan timeout);\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ICatalogTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface ICatalogTestGrain : IGrainWithIntegerKey\n    {\n        Task Initialize();\n        Task BlastCallNewGrains(int nGrains, long startingKey, int nCallsToEach);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IChainedGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IChainedGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetId();\n        Task<int> GetX();\n        Task<IChainedGrain> GetNext();\n        //[ReadOnly]\n        Task<int> GetCalculatedValue();\n        Task SetNext(IChainedGrain next);\n        Task SetNextNested(ChainGrainHolder next);\n        //[ReadOnly]\n        Task Validate(bool nextIsSet);\n        Task PassThis(IChainedGrain next);\n        Task PassNull(IChainedGrain next);\n        Task PassThisNested(ChainGrainHolder next);\n        Task PassNullNested(ChainGrainHolder next);\n    }\n    \n    [GenerateSerializer]\n    public class ChainGrainHolder\n    {\n        [Id(0)]\n        public IChainedGrain Next { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ICircularStateTestGrain.cs",
    "content": "﻿namespace TestGrainInterfaces\n{\n    public interface ICircularStateTestGrain : IGrainWithGuidCompoundKey\n    {\n        Task<CircularTest1> GetState();\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class CircularStateTestState\n    {\n        [Id(0)]\n        public CircularTest1 CircularTest1 { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class CircularTest1\n    {\n        [Id(0)]\n        public CircularTest2 CircularTest2 { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class CircularTest2\n    {\n        public CircularTest2()\n        {\n            CircularTest1List = new List<CircularTest1>();\n        }\n\n        [Id(0)]\n        public List<CircularTest1> CircularTest1List { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IClientAddressableTestConsumer.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IClientAddressableTestConsumer : IGrainWithIntegerKey\n    {\n        Task<int> PollProducer();\n        Task Setup();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IClusterTestGrains.cs",
    "content": "namespace TestGrainInterfaces\n{\n    public interface IClusterTestGrain : IGrainWithIntegerKey\n    {\n        Task<int> SayHelloAsync();\n        Task Deactivate();\n        Task<string> GetRuntimeId();\n        Task Subscribe(IClusterTestListener listener);\n        Task EnableStreamNotifications();\n    }\n\n    public interface IClusterTestListener : IGrainObserver\n    {\n        void GotHello(int number);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ICollectionTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface ICollectionTestGrain : IGrainWithIntegerKey\n    {\n        Task<TimeSpan> GetAge();\n\n        Task<int> IncrCounter();\n\n        Task DeactivateSelf();\n\n        Task SetOther(ICollectionTestGrain other);\n\n        Task<TimeSpan> GetOtherAge();\n\n        Task<ICollectionTestGrain> GetGrainReference();\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task StartTimer(TimeSpan timerPeriod, TimeSpan delayPeriod);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IConcurrentGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IConcurrentGrain : IGrainWithIntegerKey\n    {\n        Task Initialize(int index);\n\n        //[ReadOnly]\n        Task<int> A();\n        //[ReadOnly]\n        Task<int> B(int time);\n\n        Task<List<int>> ModifyReturnList_Test();\n\n        Task Initialize_2(int index);\n        Task<int> TailCall_Caller(IConcurrentReentrantGrain another, bool doCW);\n        Task<int> TailCall_Resolver(IConcurrentReentrantGrain another);\n    }\n\n    public interface IConcurrentReentrantGrain : IGrainWithIntegerKey\n    {\n        Task Initialize_2(int index);\n        Task<int> TailCall_Called();\n        Task<int> TailCall_Resolve();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IConsumerEventCountingGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// Stream consumer grain that just counts the events it consumes\n    /// </summary>\n    public interface IConsumerEventCountingGrain : IGrainWithGuidKey\n    {\n        Task BecomeConsumer(Guid streamId, string providerToUse);\n\n        Task StopConsuming();\n\n        Task<int> GetNumberConsumed();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IDeadlockGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IDeadlockNonReentrantGrain : IGrainWithIntegerKey\n    {\n        Task CallNext_1(List<(long GrainId, bool Blocking)> callChain, int currCallIndex);\n        Task CallNext_2(List<(long GrainId, bool Blocking)> callChain, int currCallIndex);\n    }\n\n    public interface IDeadlockReentrantGrain : IGrainWithIntegerKey\n    {\n        Task CallNext_1(List<(long GrainId, bool Blocking)> callChain, int currCallIndex);\n        Task CallNext_2(List<(long GrainId, bool Blocking)> callChain, int currCallIndex);\n    }\n\n    public interface ICallChainObserver : IGrainObserver\n    {\n        Task OnEnter(string grain, int callIndex);\n        Task OnExit(string grain, int callIndex);\n    }\n\n    public interface ICallChainReentrancyGrain : IGrainWithStringKey\n    {\n        Task CallChain(ICallChainObserver observer, List<(string TargetGrain, ReentrancyCallType CallType)> callChain, int callIndex, CancellationToken cancellationToken = default);\n\n        [AlwaysInterleave]\n        Task UnblockWaiters(CancellationToken cancellationToken = default);\n    }\n\n    [GenerateSerializer]\n    public enum ReentrancyCallType\n    {\n        Regular,\n        AllowCallChainReentrancy,\n        SuppressCallChainReentrancy,\n    }\n}\n\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IDurableJobGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.DurableJobs;\n\nnamespace UnitTests.GrainInterfaces;\n\npublic interface IDurableJobGrain : IGrainWithStringKey\n{\n    Task<DurableJob> ScheduleJobAsync(string jobName, DateTimeOffset scheduledTime, IReadOnlyDictionary<string, string> metadata = null);\n\n    Task<bool> TryCancelJobAsync(DurableJob job);\n\n    Task<bool> HasJobRan(string jobId);\n\n    [AlwaysInterleave]\n    Task WaitForJobToRun(string jobId);\n\n    Task<DateTimeOffset> GetJobExecutionTime(string jobId);\n\n    Task<IJobRunContext> GetJobRun(string jobId);\n\n    Task<bool> WasCancellationTokenCancelled(string jobId);\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IEchoTaskGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    ///  A simple echo grain\n    /// </summary>\n    public interface IEchoGrain : IGrainWithGuidKey\n    {\n        Task<string> GetLastEcho();\n\n        Task<string> Echo(string data);\n        Task<string> EchoError(string data);\n        Task<Nullable<DateTime>> EchoNullable(Nullable<DateTime> value);\n    }\n\n    [GenerateMethodSerializers(typeof(GrainReference))]\n    public interface IEchoTaskGrain : IGrainWithGuidKey\n    {\n        Task<int> GetMyIdAsync();\n\n        Task<string> GetLastEchoAsync();\n\n        Task<string> EchoAsync(string data);\n        Task<string> EchoErrorAsync(string data);\n\n        [ResponseTimeout(\"00:00:05\")]\n        Task<int> BlockingCallTimeoutAsync(TimeSpan delay);\n\n        Task<int> BlockingCallTimeoutNoResponseTimeoutOverrideAsync(TimeSpan delay);\n\n        Task PingAsync();\n\n        Task PingLocalSiloAsync();\n        Task PingRemoteSiloAsync(SiloAddress siloAddress);\n        Task PingOtherSiloAsync();\n        Task PingClusterMemberAsync();\n    }\n\n    public interface IBlockingEchoTaskGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetMyId();\n\n        Task<string> GetLastEcho();\n\n        Task<string> Echo(string data);\n        Task<string> CallMethodTask_Await(string data);\n        Task<string> CallMethodAV_Await(string data);\n        Task<string> CallMethodTask_Block(string data);\n        Task<string> CallMethodAV_Block(string data);\n    }\n\n    public interface IReentrantBlockingEchoTaskGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetMyId();\n\n        Task<string> GetLastEcho();\n\n        Task<string> Echo(string data);\n        Task<string> CallMethodTask_Await(string data);\n        Task<string> CallMethodAV_Await(string data);\n        Task<string> CallMethodTask_Block(string data);\n        Task<string> CallMethodAV_Block(string data);\n    }\n\n    public interface IDebuggerHelperTestGrain : IGrain\n    {\n        Task OrleansDebuggerHelper_GetGrainInstance_Test();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IErrorGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IErrorGrain : ISimpleGrain\n    {\n        Task LogMessage(string msg);\n        Task SetAError(int a);\n        Task SetBError(int a);\n        Task<int> GetAxBError();\n        Task<int> GetAxBError(int a, int b);\n        Task LongMethod(int waitTime);\n        Task LongMethodWithError(int waitTime);\n        Task DelayMethod(int milliseconds);\n        Task Dispose();\n        Task<int> UnobservedErrorImmediate();\n        Task<int> UnobservedErrorDelayed();\n        Task<int> UnobservedErrorContinuation2();\n        Task<int> UnobservedErrorContinuation3();\n        Task<int> UnobservedIgnoredError();\n        Task AddChildren(List<IErrorGrain> children);\n        Task<bool> ExecuteDelayed(TimeSpan delay);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IExceptionGrain.cs",
    "content": "using System.Buffers;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\n\nnamespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// The ExceptionGrain interface.\n    /// </summary>\n    public interface IExceptionGrain : IGrainWithIntegerKey\n    {\n        Task Canceled();\n\n        Task ThrowsInvalidOperationException();\n\n        Task ThrowsNullReferenceException();\n\n        Task ThrowsAggregateExceptionWrappingInvalidOperationException();\n\n        Task ThrowsNestedAggregateExceptionsWrappingInvalidOperationException();\n\n        Task GrainCallToThrowsInvalidOperationException(long otherGrainId);\n\n        Task GrainCallToThrowsAggregateExceptionWrappingInvalidOperationException(long otherGrainId);\n\n        Task ThrowsSynchronousInvalidOperationException();\n\n        Task<object> ThrowsSynchronousExceptionObjectTask();\n\n        Task ThrowsMultipleExceptionsAggregatedInFaultedTask();\n\n        Task ThrowsSynchronousAggregateExceptionWithMultipleInnerExceptions();\n    }\n\n    public interface IMessageSerializationGrain : IGrainWithIntegerKey\n    {\n        Task SendUnserializable(UnserializableType input);\n        Task SendUndeserializable(UndeserializableType input);\n        Task<UnserializableType> GetUnserializable();\n        Task<UndeserializableType> GetUndeserializable();\n\n        Task SendUnserializableToOtherSilo();\n        Task SendUndeserializableToOtherSilo();\n        Task GetUnserializableFromOtherSilo();\n        Task GetUndeserializableFromOtherSilo();\n\n        Task SendUnserializableToClient(IMessageSerializationClientObject obj);\n        Task SendUndeserializableToClient(IMessageSerializationClientObject obj);\n        Task GetUnserializableFromClient(IMessageSerializationClientObject obj);\n        Task GetUndeserializableFromClient(IMessageSerializationClientObject obj);\n\n        Task<string> GetSiloIdentity();\n    }\n\n    public interface IMessageSerializationClientObject : IAddressable\n    {\n        Task SendUnserializable(UnserializableType input);\n        Task SendUndeserializable(UndeserializableType input);\n        Task<UnserializableType> GetUnserializable();\n        Task<UndeserializableType> GetUndeserializable();\n    }\n\n    public struct UndeserializableType\n    {\n        public const string FailureMessage = \"Can't do it, sorry.\";\n\n        public UndeserializableType(int num)\n        {\n            this.Number = num;\n        }\n\n        public int Number { get; }\n    }\n\n    public class UnserializableType\n    {\n    }\n\n    [RegisterSerializer]\n    [RegisterCopier]\n    public sealed class UndeserializableTypeCodec : IFieldCodec<UndeserializableType>, IDeepCopier<UndeserializableType>\n    {\n        public UndeserializableType DeepCopy(UndeserializableType input, CopyContext context) => input;\n\n        public UndeserializableType ReadValue<TInput>(ref Reader<TInput> reader, Field field) => throw new NotSupportedException(UndeserializableType.FailureMessage);\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, UndeserializableType value) where TBufferWriter : IBufferWriter<byte>\n        {\n            Int32Codec.WriteField(ref writer, fieldIdDelta, value.Number);\n        }\n    }\n\n    [RegisterSerializer]\n    [RegisterCopier]\n    public sealed class UnserializableTypeCodec : IFieldCodec<UnserializableType>, IDeepCopier<UnserializableType>\n    {\n        public UnserializableType DeepCopy(UnserializableType input, CopyContext context) => input;\n\n        public UnserializableType ReadValue<TInput>(ref Reader<TInput> reader, Field field) => default;\n        public void WriteField<TBufferWriter>(ref Writer<TBufferWriter> writer, uint fieldIdDelta, Type expectedType, UnserializableType value) where TBufferWriter : IBufferWriter<byte>\n        {\n            throw new NotSupportedException(UndeserializableType.FailureMessage);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IExtensionTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IExtensionTestGrain : IGrainWithIntegerKey\n    {\n        Task InstallExtension(string name);\n    }\n\n    public interface IGenericExtensionTestGrain<in T> : IGrainWithIntegerKey\n    {\n        Task InstallExtension(T name);\n    }\n\n    public interface IGenericGrainWithNonGenericExtension<in T> : IGrainWithIntegerKey\n    {\n        Task DoSomething();\n    }\n\n    public interface INoOpTestGrain : IGrainWithIntegerKey\n    {\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IExternalTypeGrain.cs",
    "content": "using System.Collections.Specialized;\n\nnamespace UnitTests.GrainInterfaces\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class EnumClass\n    {\n        [Id(0)]\n        public IEnumerable<DateTimeKind> EnumsList { get; set; }\n    }\n\n    public interface IExternalTypeGrain : IGrainWithIntegerKey\n    {\n        Task GetAbstractModel(IEnumerable<NameObjectCollectionBase> list);\n\n        Task<EnumClass> GetEnumModel();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IFaultableConsumerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IFaultableConsumerGrain : IGrainWithGuidKey\n    {\n        Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task SetFailPeriod(TimeSpan failPeriod);\n\n        Task StopConsuming();\n\n        Task<int> GetNumberConsumed();\n\n        Task<int> GetNumberFailed();\n\n        Task<int> GetErrorCount();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IFilteredImplicitSubscriptionGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IFilteredImplicitSubscriptionGrain : IGrainWithGuidKey\n    {\n        Task<int> GetCounter(string streamNamespace);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IFilteredImplicitSubscriptionWithExtensionGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IFilteredImplicitSubscriptionWithExtensionGrain : IGrainWithGuidCompoundKey\n    {\n        Task<int> GetCounter();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratedEventCollectorGrain.cs",
    "content": "namespace TestGrainInterfaces\n{\n    public interface IGeneratedEventCollectorGrain : IGrainWithGuidKey\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratedEventReporterGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace TestGrainInterfaces\n{\n    public interface IGeneratedEventReporterGrain : IGrainWithGuidKey\n    {\n        Task ReportResult(Guid streamGuid, string streamProvider, string streamNamespace, int count);\n\n        Task<IDictionary<Guid,int>> GetReport(string streamProvider, string streamNamespace);\n\n        Task Reset();\n\n        Task<bool> IsLocatedOnSilo(SiloAddress siloAddress);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratorTestDerivedDerivedGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class ReplaceArguments\n    {\n        [Orleans.Id(0)]\n        public string OldString { get; private set; }\n        [Orleans.Id(1)]\n        public string NewString { get; private set; }\n\n        public ReplaceArguments(string oldStr, string newStr)\n        {\n            OldString = oldStr;\n            NewString = newStr;\n        }\n    }\n\n    public interface IGeneratorTestDerivedDerivedGrain : IGeneratorTestDerivedGrain2\n    {\n        Task<string> StringNConcat(string[] strArray);\n        Task<string> StringReplace(ReplaceArguments strs);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain.cs",
    "content": "﻿using UnitTests.Interfaces;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IGeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain : IGrainWithGuidKey, ICSharpBaseInterface\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratorTestDerivedGrain1.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IGeneratorTestDerivedGrain1 : IGeneratorTestGrain\n    {\n        Task<byte[]> ByteAppend(byte[] data);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratorTestDerivedGrain2.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IGeneratorTestDerivedGrain2 : IGeneratorTestGrain\n    {\n        Task<string> StringConcat(string str1, string str2, string str3);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGeneratorTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public enum ReturnCode\n    {\n        OK = 0,\n        Fail = 1\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public struct MemberVariables\n    {\n        [Id(0)]\n        public byte[] byteArray;\n        [Id(1)]\n        public string stringVar;\n        [Id(2)]\n        public ReturnCode code;\n\n        public MemberVariables(byte[] bytes, string str, ReturnCode codeInput)\n        {\n            byteArray = bytes;\n            stringVar = str;\n            code = codeInput;\n        }\n    }\n\n    public interface IGeneratorTestGrain : IGrainWithIntegerKey\n    {\n        Task<byte[]> ByteSet(byte[] data);\n        Task StringSet(string str);\n        Task<bool> StringIsNullOrEmpty();\n        Task<MemberVariables> GetMemberVariables();\n        Task SetMemberVariables(MemberVariables x);\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGenericInterfaces.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IGenericGrainWithGenericState<TFirstTypeParam, TStateType, TLastTypeParam> : IGrainWithGuidKey\n    {\n        Task<Type> GetStateType();\n    }\n\n    public class GenericGrainWithGenericState<TFirstTypeParam, TStateType, TLastTypeParam> : Grain<TStateType>,\n        IGenericGrainWithGenericState<TFirstTypeParam, TStateType, TLastTypeParam> where TStateType : new()\n    {\n        public Task<Type> GetStateType() => Task.FromResult(this.State.GetType());\n    }\n\n    public interface IGenericGrain<T, U> : IGrainWithIntegerKey\n    {\n        Task SetT(T a);\n        Task<U> MapT2U();\n    }\n\n    public interface ISimpleGenericGrain1<T> : IGrainWithIntegerKey\n    {\n        Task<T> GetA();\n        Task<string> GetAxB();\n        Task<string> GetAxB(T a, T b);\n        Task SetA(T a);\n        Task SetB(T b);\n    }\n\n    /// <summary>\n    /// Long named grain type, which can cause issues in AzureTableStorage\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface ISimpleGenericGrainUsingAzureStorageAndLongGrainName<T> : IGrainWithGuidKey\n    {\n        Task<T> EchoAsync(T entity);\n\n        Task ClearState();\n    }\n\n    /// <summary>\n    /// Short named grain type, which shouldn't cause issues in AzureTableStorage\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public interface ITinyNameGrain<T> : IGrainWithGuidKey\n    {\n        Task<T> EchoAsync(T entity);\n\n        Task ClearState();\n    }\n\n    public interface ISimpleGenericGrainU<U> : IGrainWithIntegerKey\n    {\n        Task<U> GetA();\n        Task<string> GetAxB();\n        Task<string> GetAxB(U a, U b);\n        Task SetA(U a);\n        Task SetB(U b);\n    }\n\n    public interface ISimpleGenericGrain2<T, in U> : IGrainWithIntegerKey\n    {\n        Task<T> GetA();\n        Task<string> GetAxB();\n        Task<string> GetAxB(T a, U b);\n        Task SetA(T a);\n        Task SetB(U b);\n    }\n\n    public interface IGenericGrainWithNoProperties<in T> : IGrainWithIntegerKey\n    {\n        Task<string> GetAxB(T a, T b);\n    }\n    public interface IGrainWithNoProperties : IGrainWithIntegerKey\n    {\n        Task<string> GetAxB(int a, int b);\n    }\n\n    public interface IGrainWithListFields : IGrainWithIntegerKey\n    {\n        Task AddItem(string item);\n        Task<IList<string>> GetItems();\n    }\n    public interface IGenericGrainWithListFields<T> : IGrainWithIntegerKey\n    {\n        Task AddItem(T item);\n        Task<IList<T>> GetItems();\n    }\n\n    public interface IGenericReader1<T> : IGrainWithIntegerKey\n    {\n        Task<T> GetValue();\n    }\n    public interface IGenericWriter1<in T> : IGrainWithIntegerKey\n    {\n        Task SetValue(T value);\n    }\n    public interface IGenericReaderWriterGrain1<T> : IGenericWriter1<T>, IGenericReader1<T>\n    {\n    }\n\n    public interface IGenericReader2<TOne, TTwo> : IGrainWithIntegerKey\n    {\n        Task<TOne> GetValue1();\n        Task<TTwo> GetValue2();\n    }\n    public interface IGenericWriter2<in TOne, in TTwo> : IGrainWithIntegerKey\n    {\n        Task SetValue1(TOne value);\n        Task SetValue2(TTwo value);\n    }\n    public interface IGenericReaderWriterGrain2<TOne, TTwo> : IGenericWriter2<TOne, TTwo>, IGenericReader2<TOne, TTwo>\n    {\n    }\n\n    public interface IGenericReader3<TOne, TTwo, TThree> : IGenericReader2<TOne, TTwo>\n    {\n        Task<TThree> GetValue3();\n    }\n    public interface IGenericWriter3<in TOne, in TTwo, in TThree> : IGenericWriter2<TOne, TTwo>\n    {\n        Task SetValue3(TThree value);\n    }\n    public interface IGenericReaderWriterGrain3<TOne, TTwo, TThree> : IGenericWriter3<TOne, TTwo, TThree>, IGenericReader3<TOne, TTwo, TThree>\n    {\n    }\n\n    public interface IBasicGenericGrain<T, U> : IGrainWithIntegerKey\n    {\n        Task<T> GetA();\n        Task<string> GetAxB();\n        Task<string> GetAxB(T a, U b);\n        Task SetA(T a);\n        Task SetB(U b);\n    }\n\n    public interface IHubGrain<TKey, T1, T2> : IGrainWithIntegerKey\n    {\n        Task Bar(TKey key, T1 message1, T2 message2);\n\n    }\n\n    public interface IEchoHubGrain<TKey, TMessage> : IHubGrain<TKey, TMessage, TMessage>\n    {\n        Task Foo(TKey key, TMessage message, int x);\n        Task<int> GetX();\n    }\n\n    public interface IEchoGenericChainGrain<T> : IGrainWithIntegerKey\n    {\n        Task<T> Echo(T item);\n        Task<T> Echo2(T item);\n        Task<T> Echo3(T item);\n        Task<T> Echo4(T item);\n        Task<T> Echo5(T item);\n        Task<T> Echo6(T item);\n    }\n\n    public interface INonGenericBase : IGrainWithGuidKey\n    {\n        Task Ping();\n    }\n\n    public interface IGeneric1Argument<T> : IGrainWithGuidKey\n    {\n        Task<T> Ping(T t);\n    }\n\n    public interface IGeneric2Arguments<T, U> : IGrainWithIntegerKey\n    {\n        Task<Tuple<T, U>> Ping(T t, U u);\n    }\n\n    public interface IDbGrain<T> : IGrainWithIntegerKey\n    {\n        Task SetValue(T value);\n        Task<T> GetValue();\n    }\n\n    public interface IGenericPingSelf<T> : IGrainWithGuidKey\n    {\n        Task<T> Ping(T t);\n        Task<T> PingSelf(T t);\n        Task<T> PingOther(IGenericPingSelf<T> target, T t);\n        Task<T> PingSelfThroughOther(IGenericPingSelf<T> target, T t);\n        Task<T> GetLastValue();\n        Task ScheduleDelayedPing(IGenericPingSelf<T> target, T t, TimeSpan delay);\n        Task ScheduleDelayedPingToSelfAndDeactivate(IGenericPingSelf<T> target, T t, TimeSpan delay);\n    }\n\n    public interface ILongRunningTaskGrain<T> : IGrainWithGuidKey\n    {\n        Task<string> GetRuntimeInstanceId();\n        Task<string> GetRuntimeInstanceIdWithDelay(TimeSpan delay);\n        Task<T> LongRunningTask(T t, TimeSpan delay);\n        Task<T> CallOtherLongRunningTask(ILongRunningTaskGrain<T> target, T t, TimeSpan delay);\n        Task<T> FanOutOtherLongRunningTask(ILongRunningTaskGrain<T> target, T t, TimeSpan delay, int degreeOfParallelism);\n\n        Task LongWaitGrainCancellation(GrainCancellationToken tc, TimeSpan delay, Guid callId);\n        [AlwaysInterleave]\n        Task LongWaitGrainCancellationInterleaving(GrainCancellationToken tc, TimeSpan delay, Guid callId);\n        Task LongWait(CancellationToken tc, TimeSpan delay, Guid callId);\n        [AlwaysInterleave]\n        Task LongWaitInterleaving(CancellationToken tc, TimeSpan delay, Guid callId);\n        Task CallOtherLongRunningTask(ILongRunningTaskGrain<T> target, CancellationToken tc, TimeSpan delay, Guid callId);\n        Task CallOtherLongRunningTaskGrainCancellation(ILongRunningTaskGrain<T> target, GrainCancellationToken tc, TimeSpan delay, Guid callId);\n        Task CallOtherLongRunningTaskWithLocalGrainCancellationToken(ILongRunningTaskGrain<T> target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId);\n        Task CallOtherLongRunningTaskWithLocalCancellation(ILongRunningTaskGrain<T> target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId);\n        Task<bool> GrainCancellationTokenCallbackResolve(GrainCancellationToken tc, Guid callId);\n        Task<bool> CancellationTokenCallbackResolve(CancellationToken tc, Guid callId);\n        Task<bool> CallOtherGrainCancellationTokenCallbackResolve(ILongRunningTaskGrain<T> target, Guid callId);\n        Task<bool> CallOtherCancellationTokenCallbackResolve(ILongRunningTaskGrain<T> target, Guid callId);\n        Task GrainCancellationTokenCallbackThrow(GrainCancellationToken tc, Guid callId);\n        Task CancellationTokenCallbackThrow(CancellationToken tc, Guid callId);\n        Task<T> GetLastValue();\n\n        IAsyncEnumerable<(Guid CallId, Exception Error)> WatchCancellations(CancellationToken cancellationToken = default);\n    }\n\n    [Alias(\"IGenericGrainWithConstraints`3\")]\n    public interface IGenericGrainWithConstraints<A, B, C> : IGrainWithStringKey\n        where A : ICollection<B>, new() where B : struct where C : class\n    {\n        [Alias(\"GetCount\")]\n        Task<int> GetCount();\n\n        Task Add(B item);\n\n        Task<C> RoundTrip(C value);\n    }\n\n    public interface INonGenericCastableGrain : IGrainWithGuidKey\n    {\n        Task DoSomething();\n    }\n\n\n    public interface IGenericCastableGrain<T> : IGrainWithGuidKey\n    { }\n\n    public interface IGenericRegisterGrain<T> : IGrainWithIntegerKey\n    {\n        Task Set(T value);\n        Task<T> Get();\n    }\n\n    public interface IGenericArrayRegisterGrain<T> : IGenericRegisterGrain<T[]>\n    {\n    }\n\n    public interface IGrainSayingHello : IGrainWithGuidKey\n    {\n        Task<string> Hello();\n    }\n\n    public interface ISomeGenericGrain<T> : IGrainSayingHello\n    { }\n\n    public interface INonGenericCastGrain : IGrainSayingHello\n    { }\n\n\n\n    public interface IIndependentlyConcretizedGrain : ISomeGenericGrain<string>\n    { }\n\n    public interface IIndependentlyConcretizedGenericGrain<T> : ISomeGenericGrain<T>\n    { }\n\n\n    namespace Generic.EdgeCases\n    {\n        public interface IBasicGrain : IGrainWithGuidKey\n        {\n            Task<string> Hello();\n            Task<string[]> ConcreteGenArgTypeNames();\n        }\n\n\n        public interface IGrainWithTwoGenArgs<T1, T2> : IBasicGrain\n        { }\n\n        public interface IGrainWithThreeGenArgs<T1, T2, T3> : IBasicGrain\n        { }\n\n        public interface IGrainReceivingRepeatedGenArgs<T1, T2> : IBasicGrain\n        { }\n\n        public interface IPartiallySpecifyingInterface<T> : IGrainWithTwoGenArgs<T, int>\n        { }\n\n        public interface IReceivingRepeatedGenArgsAmongstOthers<T1, T2, T3> : IBasicGrain\n        { }\n\n        public interface IReceivingRepeatedGenArgsFromOtherInterface<T1, T2, T3> : IBasicGrain\n        { }\n\n        public interface ISpecifyingGenArgsRepeatedlyToParentInterface<T> : IReceivingRepeatedGenArgsFromOtherInterface<T, T, T>\n        { }\n\n        public interface IReceivingRearrangedGenArgs<T1, T2> : IBasicGrain\n        { }\n\n        public interface IReceivingRearrangedGenArgsViaCast<T1, T2> : IBasicGrain\n        { }\n\n        public interface ISpecifyingRearrangedGenArgsToParentInterface<T1, T2> : IReceivingRearrangedGenArgsViaCast<T2, T1>\n        { }\n\n        public interface IArbitraryInterface<T1, T2> : IBasicGrain\n        { }\n\n        public interface IInterfaceUnrelatedToConcreteGenArgs<T> : IBasicGrain\n        { }\n\n        public interface IInterfaceTakingFurtherSpecializedGenArg<T> : IBasicGrain\n        { }\n\n\n        public interface IAnotherReceivingFurtherSpecializedGenArg<T> : IBasicGrain\n        { }\n\n        public interface IYetOneMoreReceivingFurtherSpecializedGenArg<T> : IBasicGrain\n        { }\n    }\n\n    public interface IG2<T1, T2> : IGrainWithGuidKey\n    { }\n\n    public class HalfOpenGrain1<T> : IG2<T, int>\n    { }\n    public class HalfOpenGrain2<T> : IG2<int, T>\n    { }\n\n    public class OpenGeneric<T2, T1> : IG2<T2, T1>\n    { }\n\n    public class ClosedGeneric : IG2<Dummy1, Dummy2>\n    { }\n\n    public class ClosedGenericWithManyInterfaces : IG2<Dummy1, Dummy2>, IG2<Dummy2, Dummy1>\n    { }\n\n    [GenerateSerializer]\n    public class Dummy1 { }\n\n    [GenerateSerializer]\n    public class Dummy2 { }\n\n    public interface IG<T> : IGrain\n    {\n    }\n\n    public class G1<T1, T2, T3, T4> : Grain, Root<T1>.IA<T2, T3, T4>\n    {\n    }\n\n    public class Root<TRoot>\n    {\n        public interface IA<T1, T2, T3> : IGrainWithIntegerKey\n        {\n\n        }\n\n        public class G<T1, T2, T3> : Grain, IG<IA<T1, T2, T3>>\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IGrainServiceTestGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IGrainServiceTestGrain : IGrainWithIntegerKey\n    {\n\n        Task<string> GetHelloWorldUsingCustomService();\n        Task<bool> CallHasStarted();\n        Task<bool> CallHasStartedInBackground();\n        Task<bool> CallHasInit();\n        Task<string> GetServiceConfigProperty();\n        Task<string> EchoViaExtension(string what);\n    }\n\n    public interface IEchoExtension : IGrainExtension\n    {\n        Task<string> Echo(string what);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IImplicitSubscriptionCounterGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IImplicitSubscriptionCounterGrain : IGrainWithGuidKey\n    {\n        Task<int> GetEventCounter();\n\n        Task<int> GetErrorCounter();\n\n        Task Deactivate();\n\n        Task DeactivateOnEvent(bool deactivate);\n    }\n\n    public interface IFastImplicitSubscriptionCounterGrain : IImplicitSubscriptionCounterGrain\n    { }\n\n    public interface ISlowImplicitSubscriptionCounterGrain : IImplicitSubscriptionCounterGrain\n    { }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IImplicitSubscriptionKeyTypeGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IImplicitSubscriptionKeyTypeGrain\n    {\n        Task<int> GetValue();\n    }\n\n    public interface IImplicitSubscriptionLongKeyGrain : IImplicitSubscriptionKeyTypeGrain, IGrainWithIntegerKey\n    { }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IInitialStateGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IInitialStateGrain : IGrainWithIntegerKey\n    {\n        Task<List<string>> GetNames();\n        Task AddName(string name);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IKeyExtensionTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IKeyExtensionTestGrain : IGrainWithGuidCompoundKey\n    {\n        Task<IKeyExtensionTestGrain> GetGrainReference();\n        Task<string> GetActivationId();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ILivenessTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface ILivenessTestGrain : IGrainWithIntegerKey\n    {\n        // separate label that can be set\n        Task<string> GetLabel();\n\n        Task SetLabel(string label);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task<string> GetUniqueId();\n\n        Task<ILivenessTestGrain> GetGrainReference();\n\n        Task StartTimer();\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ILogTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// A grain used for testing log-consistency providers.\n    /// The content of this class is pretty arbitrary and messy;\n    /// (don't use this as an introduction on how to use JournaledGrain)\n    /// it started from SimpleGrain, but a lot of stuff got added over time \n    /// </summary>\n    public interface ILogTestGrain: IGrainWithIntegerKey\n    {\n        // read A\n\n        Task<int> GetAGlobal();\n\n        Task<int> GetALocal();\n\n        // read both\n\n        Task<AB> GetBothGlobal();\n\n        Task<AB> GetBothLocal();\n\n        // reservations\n\n        Task<int[]> GetReservationsGlobal();\n\n        // version\n\n        Task<int> GetConfirmedVersion();\n\n        // set or increment A\n\n        Task SetAGlobal(int a);\n\n        Task<Tuple<int, bool>> SetAConditional(int a);\n\n        Task SetALocal(int a);\n\n        Task IncrementALocal();\n\n        Task IncrementAGlobal();\n\n        // set B\n\n        Task SetBGlobal(int b);\n\n        Task SetBLocal(int b);\n\n        // reservations\n\n        Task AddReservationLocal(int x);\n\n        Task RemoveReservationLocal(int x);\n\n\n        Task<KeyValuePair<int, object>> Read();\n        Task<bool> Update(IReadOnlyList<object> updates, int expectedversion);\n\n        Task<IReadOnlyList<object>> GetEventLog();\n\n\n        // other operations\n\n        Task SynchronizeGlobalState();\n        Task Clear();\n        Task Deactivate();\n    }\n\n    /// <summary>\n    /// Used by unit tests. \n    /// The fields don't really have any meaning. \n    /// The point of the struct is just that a grain method can return both A and B at the same time.\n    /// </summary>\n    [GenerateSerializer]\n    public struct AB\n    {\n        [Id(0)]\n        public int A;\n\n        [Id(1)]\n        public int B;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ILongRunningObserver.cs",
    "content": "#nullable enable\nusing Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces;\n\n/// <summary>\n/// Observer interface that supports long-running operations with cancellation.\n/// </summary>\npublic interface ILongRunningObserver : IGrainObserver\n{\n    /// <summary>\n    /// Performs a long wait that can be cancelled via the provided cancellation token.\n    /// </summary>\n    Task LongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Tests that cancellation token callbacks execute in the correct execution context.\n    /// </summary>\n    Task<bool> CancellationTokenCallbackResolve(Guid callId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Performs a long wait that can be cancelled via the provided cancellation token.\n    /// This method is marked as AlwaysInterleave to allow it to execute concurrently with other requests.\n    /// </summary>\n    [AlwaysInterleave]\n    Task InterleavingLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken);\n}\n\n/// <summary>\n/// Grain interface that can notify observers with cancellation support.\n/// </summary>\npublic interface IObserverWithCancellationGrain : IGrainWithGuidKey\n{\n    /// <summary>\n    /// Subscribes an observer for notifications.\n    /// </summary>\n    Task Subscribe(ILongRunningObserver observer);\n\n    /// <summary>\n    /// Unsubscribes an observer from notifications.\n    /// </summary>\n    Task Unsubscribe(ILongRunningObserver observer);\n\n    /// <summary>\n    /// Notifies the observer to perform a long wait with cancellation support.\n    /// </summary>\n    Task NotifyLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Notifies the observer to test cancellation token callback execution context.\n    /// </summary>\n    Task<bool> NotifyCancellationTokenCallbackResolve(Guid callId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Notifies the observer to perform an interleaving long wait with cancellation support.\n    /// </summary>\n    [AlwaysInterleave]\n    Task NotifyInterleavingLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken);\n\n    /// <summary>\n    /// Gets the list of cancellations that have been processed by the observer.\n    /// </summary>\n    Task<List<(Guid CallId, Exception? Error)>> GetProcessedCancellations();\n\n    /// <summary>\n    /// Clears the list of processed cancellations.\n    /// </summary>\n    Task ClearProcessedCancellations();\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IMethodInterceptionGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    using System;\n    using Orleans;\n    using Orleans.Runtime;\n\n    [GrainInterfaceType(\"method-interception-custom-name\")]\n    public interface IMethodInterceptionGrain : IGrainWithIntegerKey, IMethodFromAnotherInterface\n    {\n        [Id(14142)]\n        Task<string> One();\n\n        [Id(4142)]\n        Task<string> Echo(string someArg);\n        Task<string> NotIntercepted();\n        Task<string> Throw();\n        Task<string> IncorrectResultType();\n        Task FilterThrows();\n\n        Task SystemWideCallFilterMarker();\n    }\n\n    [GrainInterfaceType(\"obs-method-interception-custom-name\")]\n    public interface IMethodInterceptionGrainObserver : IGrainObserver, IMethodFromAnotherInterface\n    {\n        [Id(14142)]\n        Task<string> One();\n\n        [Id(4142)]\n        Task<string> Echo(string someArg);\n        Task<string> NotIntercepted();\n        Task<string> Throw();\n        Task<string> IncorrectResultType();\n        Task FilterThrows();\n\n        Task SystemWideCallFilterMarker();\n    }\n\n    [GrainInterfaceType(\"custom-outgoing-interception-grain\")]\n    public interface IOutgoingMethodInterceptionGrain : IGrainWithIntegerKey\n    {\n        Task<Dictionary<string, object>> EchoViaOtherGrain(IMethodInterceptionGrain otherGrain, string message);\n        Task<string> ThrowIfGreaterThanZero(int value);\n    }\n\n    [Alias(\"UnitTests.GrainInterfaces.IGenericMethodInterceptionGrain`1\")]\n    public interface IGenericMethodInterceptionGrain<in T> : IGrainWithIntegerKey, IMethodFromAnotherInterface\n    {\n        [Alias(\"GetInputAsString\")]\n        Task<string> GetInputAsString(T input);\n    }\n\n    [Alias(\"UnitTests.GrainInterfaces.IGenericMethodInterceptionGrainObserver`1\")]\n    public interface IGenericMethodInterceptionGrainObserver<in T> : IGrainObserver, IMethodFromAnotherInterface\n    {\n        [Alias(\"GetInputAsString\")]\n        Task<string> GetInputAsString(T input);\n    }\n\n    public interface IMethodFromAnotherInterface\n    {\n        Task<string> SayHello();\n    }\n\n    [Alias(\"UnitTests.GrainInterfaces.ITrickyMethodInterceptionGrain\")]\n    public interface ITrickyMethodInterceptionGrain : IGenericMethodInterceptionGrain<string>, IGenericMethodInterceptionGrain<bool>\n    {\n        [Alias(\"GetBestNumber\")]\n        Task<int> GetBestNumber();\n    }\n\n    [Alias(\"UnitTests.GrainInterfaces.ITrickyMethodInterceptionGrainObserver\")]\n    public interface ITrickyMethodInterceptionGrainObserver : IGenericMethodInterceptionGrainObserver<string>, IGenericMethodInterceptionGrainObserver<bool>\n    {\n        [Alias(\"GetBestNumber\")]\n        Task<int> GetBestNumber();\n    }\n\n    [Alias(\"UnitTests.GrainInterfaces.ITrickierMethodInterceptionGrain\")]\n    public interface ITrickierMethodInterceptionGrain : IGenericMethodInterceptionGrain<List<int>>, IGenericMethodInterceptionGrain<List<bool>>\n    {\n    }\n\n    public static class GrainCallFilterTestConstants\n    {\n        public const string Key = \"GrainInfo\";\n    }\n\n    public interface IGrainCallFilterTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> ThrowIfGreaterThanZero(int value);\n        Task<string> GetRequestContext();\n\n        Task<int> SumSet(HashSet<int> numbers);\n\n        Task SystemWideCallFilterMarker();\n        Task GrainSpecificCallFilterMarker();\n    }\n\n    public interface IGrainCallFilterTestGrainObserver : IGrainObserver\n    {\n        Task<string> ThrowIfGreaterThanZero(int value);\n        Task<string> GetRequestContext();\n\n        Task<int> SumSet(HashSet<int> numbers);\n\n        Task SystemWideCallFilterMarker();\n        Task GrainSpecificCallFilterMarker();\n    }\n\n    public interface IHungryGrain<T> : IGrainWithIntegerKey\n    {\n        [TestMethodTag(\"hungry-eat\")]\n        Task Eat(T food);\n\n        [TestMethodTag(\"hungry-eatwith\")]\n        Task EatWith<U>(T food, U condiment);\n    }\n\n    public interface IOmnivoreGrain : IGrainWithIntegerKey\n    {\n        [TestMethodTag(\"omnivore-eat\")]\n        Task Eat<T>(T food);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Apple { }\n\n    public interface ICaterpillarGrain : IHungryGrain<Apple>, IOmnivoreGrain\n    {\n        [TestMethodTag(\"caterpillar-eat\")]\n        new Task Eat<T>(T food);\n    }\n\n    [AttributeUsage(AttributeTargets.Method)]\n    public class TestMethodTagAttribute : Attribute\n    {\n        public TestMethodTagAttribute(string tag) => this.Tag = tag;\n        public string Tag { get; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IMultifacetReader.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n\n{\n    public interface IMultifacetReader : IGrainWithIntegerKey\n    {\n        Task<int> GetValue();\n        //event ValueUpdateEventHandler ValueUpdateEvent;\n        //event ValueUpdateEventHandler CommonEvent;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IMultifacetWriter.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n\n{\n    public interface IMultifacetWriter : IGrainWithIntegerKey\n    {\n        Task SetValue(int x);\n        //event ValueUpdateEventHandler ValueReadEvent;\n        //event ValueUpdateEventHandler CommonEvent;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IMultipleImplicitSubscriptionGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IMultipleImplicitSubscriptionGrain : IGrainWithGuidKey\n    {\n        Task<Tuple<int, int>> GetCounters();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IMultipleSubscriptionConsumerGrain.cs",
    "content": "using Orleans.Streams;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IMultipleSubscriptionConsumerGrain : IGrainWithGuidKey\n    {\n        Task<StreamSubscriptionHandle<int>> BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task<StreamSubscriptionHandle<int>> Resume(StreamSubscriptionHandle<int> handle);\n\n        Task StopConsuming(StreamSubscriptionHandle<int> handle);\n\n        Task<IList<StreamSubscriptionHandle<int>>> GetAllSubscriptions(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task<Dictionary<StreamSubscriptionHandle<int>, Tuple<int,int>>> GetNumberConsumed();\n\n        Task ClearNumberConsumed();\n\n        Task Deactivate();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/INullStateGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    [GenerateSerializer]\n    public class NullableState\n    {\n        [Id(0)]\n        public string Name { get; set; }\n    }\n\n    public interface INullStateGrain : IGrainWithIntegerKey\n    {\n        Task SetStateAndDeactivate(NullableState state);\n        Task<NullableState> GetState();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IObservableGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// A grain which returns IAsyncEnumerable\n    /// </summary>\n    public interface IObservableGrain : IGrainWithGuidKey\n    {\n        ValueTask Complete();\n        ValueTask Fail();\n        ValueTask Deactivate();\n        ValueTask OnNext(string data);\n        IAsyncEnumerable<string> GetValues(CancellationToken cancellationToken = default);\n        IAsyncEnumerable<int> GetValuesWithError(int errorIndex, bool waitAfterYield, string errorMessage, CancellationToken cancellationToken = default);\n        IAsyncEnumerable<int> SleepyEnumerable(Guid id, TimeSpan delay, CancellationToken cancellationToken = default);\n\n        [AlwaysInterleave]\n        ValueTask<HashSet<Guid>> GetCanceledCalls();\n\n        [AlwaysInterleave]\n        ValueTask WaitForCall(Guid id);\n\n        [AlwaysInterleave]\n        ValueTask<List<(string InterfaceName, string MethodName)>> GetIncomingCalls();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IObserverGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IObserverGrain : IGrainWithIntegerKey\n    {\n        Task SetTarget(ISimpleObserverableGrain target);\n        Task Subscribe(ISimpleGrainObserver observer);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IPersistenceTestGrains.cs",
    "content": "// ReSharper disable InconsistentNaming\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IServiceIdGrain : IGrainWithGuidKey\n    {\n        Task<string> GetServiceId();\n    }\n\n    public interface IPersistenceTestGrain : IGrainWithGuidKey\n    {\n        Task<bool> CheckStateInit();\n        Task<string> CheckProviderType();\n        Task DoSomething();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task<int> GetValue();\n        Task DoDelete();\n    }\n\n    public interface IPersistenceTestGenericGrain<T> : IPersistenceTestGrain // IGrainWithGuidKey\n    { }\n    //    Task<bool> CheckStateInit();\n    //    Task<string> CheckProviderType();\n    //    Task DoSomething();\n    //    Task DoWrite(int val);\n    //    Task<int> DoRead();\n    //    Task<int> GetValue();\n    //    Task DoDelete();\n    //}\n\n    public interface IMemoryStorageTestGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task DoDelete();\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class PersistenceTestGrainState\n    {\n        public PersistenceTestGrainState()\n        {\n            SortedDict = new SortedDictionary<int, int>();\n        }\n\n        [Id(0)]\n        public int Field1 { get; set; }\n        [Id(1)]\n        public string Field2 { get; set; }\n        [Id(2)]\n        public SortedDictionary<int, int> SortedDict { get; set; }\n    }\n\n    public interface IGrainStorageTestGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task DoDelete();\n        ValueTask<GrainState<PersistenceTestGrainState>> GetStateAsync();\n    }\n\n    public interface IGrainStorageGenericGrain<T> : IGrainWithIntegerKey\n    {\n        Task<T> GetValue();\n        Task DoWrite(T val);\n        Task<T> DoRead();\n        Task DoDelete();\n    }\n\n    public interface IGrainStorageTestGrain_GuidExtendedKey : IGrainWithGuidCompoundKey\n    {\n        Task<string> GetExtendedKeyValue();\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task DoDelete();\n    }\n\n    public interface IGrainStorageTestGrain_LongKey : IGrainWithIntegerKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task DoDelete();\n    }\n\n    public interface IGrainStorageTestGrain_LongExtendedKey : IGrainWithIntegerCompoundKey\n    {\n        Task<string> GetExtendedKeyValue();\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task DoDelete();\n    }\n\n    public interface IPersistenceErrorGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task DoWriteError(int val, bool errorBeforeWrite);\n        Task<int> DoRead();\n        Task<int> DoReadError(bool errorBeforeRead);\n    }\n\n    public interface IPersistenceProviderErrorGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val);\n        Task<int> DoRead();\n        Task<string> GetActivationId();\n    }\n\n    public interface IPersistenceProviderErrorProxyGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue(IPersistenceProviderErrorGrain other);\n        Task DoWrite(int val, IPersistenceProviderErrorGrain other);\n        Task<int> DoRead(IPersistenceProviderErrorGrain other);\n        Task<string> GetActivationId();\n    }\n\n    public interface IPersistenceUserHandledErrorGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task DoWrite(int val, bool recover);\n        Task<int> DoRead(bool recover);\n    }\n\n    public interface IBadProviderTestGrain : IGrainWithGuidKey\n    {\n        Task DoSomething();\n    }\n\n    public interface IPersistenceNoStateTestGrain : IGrainWithGuidKey\n    {\n        Task DoSomething();\n    }\n\n    public interface IUser : IGrainWithGuidKey\n    {\n        Task<string> GetName();\n        Task<string> GetStatus();\n\n        Task UpdateStatus(string status);\n        Task SetName(string name);\n        Task AddFriend(IUser friend);\n        Task<List<IUser>> GetFriends();\n        Task<string> GetFriendsStatuses();\n    }\n\n    public interface IReentrentGrainWithState : IGrainWithGuidKey\n    {\n        Task Setup(IReentrentGrainWithState other);\n        Task Test1();\n        Task Test2();\n        Task SetOne(int val);\n        Task SetTwo(int val);\n        Task Task_Delay(bool doStart);\n    }\n\n    public interface INonReentrantStressGrainWithoutState : IGrainWithGuidKey\n    {\n        Task Test1();\n        Task Task_Delay(bool doStart);\n    }\n\n    public interface IInternalGrainWithState : IGrainWithIntegerKey\n    {\n        Task SetOne(int val);\n    }\n\n    public interface IStateInheritanceTestGrain : IGrainWithGuidKey\n    {\n        Task<int> GetValue();\n        Task SetValue(int val);\n    }\n\n    public interface IMyPredicate\n    {\n        bool FilterFunc(int i);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class MyPredicate : IMyPredicate\n    {\n        [Id(0)]\n        private readonly int filterValue;\n\n        public MyPredicate(int filter)\n        {\n            this.filterValue = filter;\n        }\n\n        public bool FilterFunc(int i)\n        {\n            return i == filterValue;\n\n        }\n    }\n\n    public interface ISurrogateStateForTypeWithoutPublicConstructorGrain<T> : IGrainWithGuidKey\n        where T : class\n    {\n        Task SetState(T state);\n        Task<T> GetState();\n    }\n\n    public interface IRecordTypeWithoutPublicParameterlessConstructorGrain<T> : IGrainWithGuidKey\n        where T : class\n    {\n        Task SetState(T state);\n        Task<T> GetState();\n    }\n}\n// ReSharper restore InconsistentNaming\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IPlacementTestGrain.cs",
    "content": "using System.Net;\nusing Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IPlacementTestGrain : IGrainWithGuidKey\n    {\n        Task<IPEndPoint> GetEndpoint();\n        Task<string> GetRuntimeInstanceId();\n        Task<string> GetActivationId();\n        Task StartLocalGrains(List<Guid> keys);\n        Task<Guid> StartPreferLocalGrain(Guid key);\n        Task<List<IPEndPoint>> SampleLocalGrainEndpoint(Guid key, int sampleSize);\n        Task Nop();\n        Task EnableOverloadDetection(bool enabled);\n        Task LatchOverloaded();\n        Task UnlatchOverloaded();\n        Task LatchCpuUsage(float value);\n        Task UnlatchCpuUsage();\n        Task<SiloAddress> GetLocation();\n    }\n\n    public interface IActivationCountBasedPlacementTestGrain : IPlacementTestGrain\n    { }\n\n    public interface IRandomPlacementTestGrain : IPlacementTestGrain\n    { }\n\n    public interface IPreferLocalPlacementTestGrain : IPlacementTestGrain\n    { }\n\n    public interface IStatelessWorkerPlacementTestGrain : IPlacementTestGrain\n    {\n        ValueTask<int> GetWorkerLimit();\n    }\n    \n    public interface IOtherStatelessWorkerPlacementTestGrain : IStatelessWorkerPlacementTestGrain\n    {\n    }\n\n    internal interface IDefaultPlacementTestGrain\n    {\n        bool IsDefaultPlacementRandom();\n    }\n\n    //----------------------------------------------------------//\n    // Interfaces for LocalContent grain case, when grain is activated on every silo by bootstrap provider.\n\n    public interface ILocalContentGrain : IGrainWithGuidKey\n    {\n        Task Init();                            // a dummy call to just activate this grain.\n        Task<object> GetContent();\n    }\n\n    public interface ITestContentGrain : IGrainWithIntegerKey\n    {\n        Task<string> GetRuntimeInstanceId();    // just for test\n        Task<object> FetchContentFromLocalGrain();\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IPolymorphicTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IPolymorphicTestGrain : IF\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IProducerEventCountingGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// Stream producer grain that sends a single event at a time (when told, see SendEvent) and tracks the number of events sent\n    /// </summary>\n    public interface IProducerEventCountingGrain : IGrainWithGuidKey\n    {\n        Task BecomeProducer(Guid streamId, string providerToUse);\n\n        /// <summary>\n        /// Sends a single event and, upon successful completion, updates the number of events produced.\n        /// </summary>\n        /// <returns></returns>\n        Task SendEvent();\n\n        Task<int> GetNumberProduced();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IPromiseForwardGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IPromiseForwardGrain : ISimpleGrain, ISimpleGrainAsync\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IProxyGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IProxyGrain : IGrainWithIntegerKey\n    {\n        Task CreateProxy(long key);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task<string> GetProxyRuntimeInstanceId();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IReentrancyCorrelationIdGrains.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IFirstGrain : IGrainWithGuidKey\n    {\n        Task Start(Guid guid1, Guid guid2);\n    }\n\n    public interface ISecondGrain : IGrainWithGuidKey\n    {\n        Task SecondGrainMethod(Guid guid);\n    }\n\n    public interface IThirdGrain : IGrainWithStringKey\n    {\n        Task ThirdGrainMethod(Guid userId);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IReentrancyGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IReentrantGrain : IGrainWithIntegerKey\n    {\n        Task<string> One();\n\n        Task<string> Two();\n\n        Task SetSelf(IReentrantGrain self);\n    }\n\n    public interface INonReentrantGrain : IGrainWithIntegerKey\n    {\n        Task<string> One();\n\n        Task<string> Two();\n\n        Task SetSelf(INonReentrantGrain self);\n    }\n\n    public interface IMayInterleaveStaticPredicateGrain : IGrainWithIntegerKey\n    {\n        Task<string> One(string arg); // this interleaves only when arg == \"reentrant\"\n\n        Task<string> Two();\n        Task<string> TwoReentrant();\n\n        Task Exceptional();\n\n        Task SubscribeToStream();\n        Task PushToStream(string item);\n\n        Task SetSelf(IMayInterleaveStaticPredicateGrain self);\n    }\n\n    public interface IMayInterleaveInstancedPredicateGrain : IGrainWithIntegerKey\n    {\n        Task<string> One(string arg); // this interleaves only when arg == \"reentrant\"\n\n        Task<string> Two();\n        Task<string> TwoReentrant();\n\n        Task Exceptional();\n\n        Task SubscribeToStream();\n        Task PushToStream(string item);\n\n        Task SetSelf(IMayInterleaveInstancedPredicateGrain self);\n    }\n\n    public interface IReentrantSelfManagedGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetCounter();\n\n        Task Ping(int seconds);\n\n        Task SetDestination(long id);\n    }\n\n    public interface INonReentrantSelfManagedGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetCounter();\n\n        Task Ping(int seconds);\n\n        Task SetDestination(long id);\n    }\n\n    public interface IReentrantTaskGrain : IGrainWithIntegerKey\n    {\n        Task SetDestination(long id);\n        Task Ping(TimeSpan wait);\n        Task<int> GetCounter();\n    }\n\n    public interface INonReentrantTaskGrain : IGrainWithIntegerKey\n    {\n        Task SetDestination(long id);\n        Task Ping(TimeSpan wait);\n        Task<int> GetCounter();\n    }\n\n    public interface ICallOrderingGrain : IGrainWithStringKey\n    {\n        Task Reset();\n        Task MethodA();\n        Task MethodB();\n        Task Unblock();\n        Task<List<string>> GetLog();\n    }\n\n    public interface IFanOutGrain : IGrainWithIntegerKey\n    {\n        Task FanOutReentrant(int offset, int num);\n        Task FanOutNonReentrant(int offset, int num);\n        Task FanOutReentrant_Chain(int offset, int num);\n        Task FanOutNonReentrant_Chain(int offset, int num);\n    }\n\n    public interface IFanOutACGrain : IGrainWithIntegerKey\n    {\n        Task FanOutACReentrant(int offset, int num);\n        Task FanOutACNonReentrant(int offset, int num);\n        Task FanOutACReentrant_Chain(int offset, int num);\n        Task FanOutACNonReentrant_Chain(int offset, int num);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IReentrantStressTestGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IReentrantStressTestGrain : IGrainWithIntegerKey\n    {\n        Task<byte[]> Echo(byte[] data);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task Ping(byte[] data);\n\n        Task PingWithDelay(byte[] data, TimeSpan delay);\n\n        Task PingMutableArray(byte[] data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingImmutableArray(Immutable<byte[]> data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingMutableDictionary(Dictionary<int, string> data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingImmutableDictionary(Immutable<Dictionary<int, string>> data, long nextGrain, bool nextGrainIsRemote);\n\n        Task InterleavingConsistencyTest(int numItems);\n    }\n\n    public interface IReentrantLocalStressTestGrain : IGrainWithIntegerKey\n    {\n        Task<byte[]> Echo(byte[] data);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task Ping(byte[] data);\n\n        Task PingWithDelay(byte[] data, TimeSpan delay);\n\n        Task PingMutableArray(byte[] data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingImmutableArray(Immutable<byte[]> data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingMutableDictionary(Dictionary<int, string> data, long nextGrain, bool nextGrainIsRemote);\n\n        Task PingImmutableDictionary(Immutable<Dictionary<int, string>> data, long nextGrain, bool nextGrainIsRemote);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IReminderTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IReminderTestGrain : IGrainWithIntegerKey\n    {\n        Task<bool> IsReminderExists(string reminderName);\n        Task AddReminder(string reminderName);\n        Task RemoveReminder(string reminderName);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IReminderTestGrain2.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    [GenerateSerializer]\n    public record class ReminderState([property: Id(0)] IGrainReminder Reminder)\n    {\n        [Id(1)] public DateTime? Registered { get; init; } = null;\n        [Id(2)] public DateTime? Unregistered { get; init; } = null;\n        [Id(3)] public List<DateTime> Fired { get; init; } = new();\n        [Id(4)] public List<(DateTime, string)> Log { get; init; } = new();\n    }\n\n    public interface IReminderTestGrain2 : IGrainWithGuidKey\n    {\n        Task<IGrainReminder> StartReminder(string reminderName, TimeSpan? period = null, bool validate = false);\n\n        Task StopReminder(string reminderName);\n        Task StopReminder(IGrainReminder reminder);\n\n        Task<TimeSpan> GetReminderPeriod(string reminderName);\n        Task<(TimeSpan DueTime, TimeSpan Period)> GetReminderDueTimeAndPeriod(string reminderName);\n        Task<long> GetCounter(string name);\n        Task<IGrainReminder> GetReminderObject(string reminderName);\n        Task<List<IGrainReminder>> GetRemindersList();\n\n        Task EraseReminderTable();\n\n        Task<Dictionary<string, ReminderState>> GetReminderStates();\n    }\n\n    // to test reminders for different grain types\n    public interface IReminderTestCopyGrain : IGrainWithGuidKey\n    {\n        Task<IGrainReminder> StartReminder(string reminderName, TimeSpan? period = null, bool validate = false);\n        Task StopReminder(string reminderName);\n\n        Task<TimeSpan> GetReminderPeriod(string reminderName);\n        Task<long> GetCounter(string name);\n    }\n\n    public interface IReminderGrainWrong : IGrainWithIntegerKey\n    // since the grain doesnt implement IRemindable, we should get an error at run time\n    // we need a way to let the user know at compile time if IRemindable isn't implemented and tries to register a reminder\n    {\n        Task<bool> StartReminder(string reminderName);\n    }\n}\n\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IRequestContextTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IRequestContextTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> TraceIdEcho();\n\n        Task<string> TraceIdDoubleEcho();\n\n        Task<string> TraceIdDelayedEcho1();\n\n        Task<string> TraceIdDelayedEcho2();\n\n        Task<Guid> E2EActivityId();\n    }\n\n    public interface IRequestContextTaskGrain : IGrainWithIntegerKey\n    {\n        Task<string> TraceIdEcho();\n\n        Task<string> TraceIdDoubleEcho();\n\n        Task<string> TraceIdDelayedEcho1();\n\n        Task<string> TraceIdDelayedEcho2();\n\n        Task<string> TraceIdDelayedEchoAwait();\n\n        Task<string> TraceIdDelayedEchoTaskRun();\n\n        Task<Guid> E2EActivityId();\n\n        Task<Tuple<string, string>> TestRequestContext();\n    }\n\n    public interface IRequestContextProxyGrain : IGrainWithIntegerKey\n    {\n        Task<Guid> E2EActivityId();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IRetryTestGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Concurrency;\nusing Orleans.DurableJobs;\n\nnamespace UnitTests.GrainInterfaces;\n\npublic interface IRetryTestGrain : IGrainWithStringKey\n{\n    Task<DurableJob> ScheduleJobAsync(string jobName, DateTimeOffset scheduledTime, IReadOnlyDictionary<string, string> metadata = null);\n\n    Task<bool> HasJobSucceeded(string jobId);\n\n    [AlwaysInterleave]\n    Task WaitForJobToSucceed(string jobId);\n\n    Task<int> GetJobExecutionAttemptCount(string jobId);\n\n    Task<List<int>> GetJobDequeueCountHistory(string jobId);\n\n    Task<IJobRunContext> GetFinalJobRun(string jobId);\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISampleStreamingGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISampleStreaming_ProducerGrain : IGrainWithGuidKey\n    {\n        Task BecomeProducer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task StartPeriodicProducing();\n\n        Task StopPeriodicProducing();\n\n        Task<int> GetNumberProduced();\n\n        Task ClearNumberProduced();\n        Task Produce();\n    }\n\n    public interface ISampleStreaming_ConsumerGrain : IGrainWithGuidKey\n    {\n        Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task StopConsuming();\n\n        Task<int> GetNumberConsumed();\n    }\n\n    public interface ISampleStreaming_InlineConsumerGrain : ISampleStreaming_ConsumerGrain\n    {\n    }\n\n    public interface IGrainWithGenericMethodsValue : IGrainWithGuidKey\n    {\n        ValueTask<int> ValueTaskMethod(bool useCache);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISchedulerGrain.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Orleans.DurableJobs;\n\nnamespace UnitTests.GrainInterfaces;\n\npublic interface ISchedulerGrain : IGrainWithStringKey\n{\n    Task<DurableJob> ScheduleJobOnAnotherGrainAsync(string targetGrainKey, string jobName, DateTimeOffset scheduledTime);\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISiloRoleBasedPlacementGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISiloRoleBasedPlacementGrain : IGrainWithStringKey\n    {\n        Task<bool> Ping();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimpleDIGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISimpleDIGrain : IGrainWithIntegerKey\n    {\n        Task<long> GetLongValue();\n        Task<string> GetStringValue();\n        Task DoDeactivate();\n    }\n\n    public interface IDIGrainWithInjectedServices : ISimpleDIGrain\n    {\n        Task<int> GetGrainFactoryId();\n        Task<string> GetInjectedSingletonServiceValue();\n        Task<string> GetInjectedScopedServiceValue();\n        Task AssertCanResolveSameServiceInstances();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimpleGenericGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISimpleGenericGrain<T> : IGrainWithIntegerKey\n    {\n        Task Set(T t);\n\n        Task Transform();\n\n        Task<T> Get();\n\n        Task CompareGrainReferences(ISimpleGenericGrain<T> clientRef);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimpleGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISimpleGrain : IGrainWithIntegerKey\n    {\n        Task SetA(int a);\n        Task SetB(int b);\n        Task IncrementA();\n        Task<int> GetAxB();\n        Task<int> GetAxB(int a, int b);\n        Task<int> GetA();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimpleGrainWithAsyncMethods.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface ISimpleGrainAsync : IGrainWithIntegerKey\n    { \n        Task SetA_Async(int a);\n        Task SetB_Async(int b);\n        Task<int> GetAxB_Async();\n        Task<int> GetAxB_Async(int a, int b);\n        Task<int> GetA_Async();\n        Task IncrementA_Async();\n    }\n\n    public interface ISimpleGrainWithAsyncMethods : ISimpleGrainAsync\n    {\n        Task<int> GetX();\n        Task SetX(int x);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimpleObserverableGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISimpleObserverableGrain : ISimpleGrain\n    {\n        Task Subscribe(ISimpleGrainObserver observer);\n        Task Unsubscribe(ISimpleGrainObserver observer);\n        Task<string> GetRuntimeInstanceId();\n    }\n\n    public interface ISimpleGrainObserver : IGrainObserver\n    {\n        void StateChanged(int a, int b);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ISimplePersistentGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ISimplePersistentGrain : ISimpleGrain\n    {\n        Task SetA(int a, bool deactivate);\n        Task<Guid> GetVersion();\n        Task<object> GetRequestContext();\n        Task SetRequestContext(int data);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerExceptionGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IStatelessWorkerExceptionGrain : IGrainWithIntegerKey\n    {\n        Task Ping();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IStatelessWorkerGrain : IGrainWithIntegerKey\n    {\n        Task LongCall();\n        Task<Tuple<Guid, string, List<Tuple<DateTime, DateTime>>>> GetCallStats();\n\n        Task DummyCall();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerScalingGrain.cs",
    "content": "using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces;\n\npublic interface IStatelessWorkerScalingGrain : IGrainWithIntegerKey\n{\n    Task Wait();\n\n    [AlwaysInterleave]\n    Task Release();\n\n    [AlwaysInterleave]\n    Task<int> GetActivationCount();\n\n    [AlwaysInterleave]\n    Task<int> GetWaitingCount();\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerStreamConsumerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IStatelessWorkerStreamConsumerGrain : IGrainWithIntegerKey\n    {\n        Task BecomeConsumer(Guid streamId, string providerToUse);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerStreamProducerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IStatelessWorkerStreamProducerGrain : IGrainWithIntegerKey\n    {\n        Task Produce(Guid streamId, string providerToUse, string message);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatelessWorkerWithMayInterleaveGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces;\n\npublic interface IStatelessWorkerWithMayInterleaveGrain : IGrainWithIntegerKey\n{\n    Task GoSlow(ICallbackGrainObserver callback);\n    Task GoFast(ICallbackGrainObserver callback);\n}\n\npublic interface ICallbackGrainObserver : IGrainObserver\n{\n    Task WaitAsync();\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStatsCollectorGrain.cs",
    "content": "﻿namespace UnitTests.Stats\n{\n    public interface IStatsCollectorGrain : IGrainWithIntegerKey\n    {\n        Task ReportStatsCalled();\n        \n        Task<long> GetReportStatsCallCount();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamBatchingTestConsumerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public static class StreamBatchingTestConst\n    {\n        public const string ProviderName = \"StreamBatchingTest\";\n        public const string BatchingNameSpace = \"batching\";\n        public const string NonBatchingNameSpace = \"nonbatching\";\n    }\n\n    [GenerateSerializer]\n    public class ConsumptionReport\n    {\n        [Id(0)]\n        public int Consumed { get; set; }\n\n        [Id(1)]\n        public int MaxBatchSize { get; set; }\n    }\n\n    public interface IStreamBatchingTestConsumerGrain : IGrainWithGuidKey\n    {\n        Task<ConsumptionReport> GetConsumptionReport();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamInterceptionGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IStreamInterceptionGrain : IGrainWithGuidKey\n    {\n        Task<int> GetLastStreamValue();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamLifecycleTestGrains.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IStreamLifecycleConsumerGrain : IGrainWithGuidKey\n    {\n        Task<int> GetReceivedCount();\n        Task<int> GetErrorsCount();\n\n        Task Ping();\n        Task BecomeConsumer(StreamId streamId, string providerName);\n        Task TestBecomeConsumerSlim(StreamId streamId, string providerName);\n        Task RemoveConsumer(StreamId streamId, string providerName, StreamSubscriptionHandle<int> consumerHandle);\n        Task ClearGrain();\n    }\n\n    public interface IFilteredStreamConsumerGrain : IStreamLifecycleConsumerGrain\n    {\n        Task BecomeConsumer(StreamId streamId, string providerName, bool sendEvensOnly);\n        Task SubscribeWithBadFunc(StreamId streamId, string providerName);\n    }\n\n    public interface IStreamLifecycleProducerGrain : IGrainWithGuidKey\n    {\n        Task<int> GetSendCount();\n        Task<int> GetErrorsCount();\n\n        Task Ping();\n\n        Task BecomeProducer(StreamId streamId, string providerName);\n        Task ClearGrain();\n\n        Task DoDeactivateNoClose();\n\n        Task SendItem(int item);\n    }\n\n    public static class StreamLifecycleConsumerGrainExtensions\n    {\n        public static Task BecomeConsumer(this IStreamLifecycleConsumerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.BecomeConsumer(streamId, providerName);\n        }\n\n        public static Task TestBecomeConsumerSlim(this IStreamLifecycleConsumerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.TestBecomeConsumerSlim(streamId, providerName);\n        }\n\n        public static  Task RemoveConsumer(this IStreamLifecycleConsumerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName, StreamSubscriptionHandle<int> consumerHandle)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.RemoveConsumer(streamId, providerName, consumerHandle);\n        }\n\n        public static Task BecomeConsumer(this IFilteredStreamConsumerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName, bool sendEvensOnly)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.BecomeConsumer(streamId, providerName, sendEvensOnly);\n        }\n\n        public static Task SubscribeWithBadFunc(this IFilteredStreamConsumerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.SubscribeWithBadFunc(streamId, providerName);\n        }\n\n        public static Task BecomeProducer(this IStreamLifecycleProducerGrain grain, Guid streamIdGuid, string streamNamespace, string providerName)\n        {\n            var streamId = StreamId.Create(streamNamespace, streamIdGuid);\n            return grain.BecomeProducer(streamId, providerName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamLifecycleTestInternalGrains.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n\n    public interface IStreamLifecycleProducerInternalGrain : IStreamLifecycleProducerGrain\n    {\n        Task DoBadDeactivateNoClose();\n        Task TestInternalRemoveProducer(Guid streamId, string providerName);\n    }\n\n    public interface IStreamLifecycleConsumerInternalGrain : IStreamLifecycleConsumerGrain\n    {\n        Task TestBecomeConsumerSlim(Guid streamId, string providerName);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamReliabilityTestGrains.cs",
    "content": "﻿//#define USE_GENERICS\n\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace UnitTests.GrainInterfaces\n{\n#if USE_GENERICS\n    public interface IStreamReliabilityTestGrain<in T> : IGrainWithIntegerKey\n#else\n    public interface IStreamReliabilityTestGrain : IGrainWithIntegerKey\n#endif\n    {\n        Task<int> GetReceivedCount();\n        Task<int> GetErrorsCount();\n        Task<int> GetConsumerCount();\n\n        Task Ping();\n#if USE_GENERICS\n        Task<StreamSubscriptionHandle<T>> AddConsumer(Guid streamId, string providerName);\n        Task RemoveConsumer(Guid streamId, string providerName, StreamSubscriptionHandle<T> consumerHandle);\n#else\n        Task<StreamSubscriptionHandle<int>> AddConsumer(Guid streamId, string providerName);\n        Task RemoveConsumer(Guid streamId, string providerName, StreamSubscriptionHandle<int> consumerHandle);\n#endif\n        \n        Task BecomeProducer(Guid streamId, string providerName);\n        Task RemoveProducer(Guid streamId, string providerName);\n        Task ClearGrain();\n        Task RemoveAllConsumers();\n\n        Task<bool> IsConsumer();\n        Task<bool> IsProducer();\n        Task<int> GetConsumerHandlesCount();\n        Task<int> GetConsumerObserversCount();\n\n#if USE_GENERICS\n        Task SendItem(T item);\n#else\n        Task SendItem(int item);\n#endif\n\n        Task<SiloAddress> GetLocation();\n    }\n\n        \n    public interface IStreamUnsubscribeTestGrain : IGrainWithIntegerKey\n    {\n        Task Subscribe(Guid streamId, string providerName);\n        Task UnSubscribeFromAllStreams();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamingGrain.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IStreaming_ConsumerGrain : IGrainWithGuidKey\n    {\n        Task BecomeConsumer(Guid streamId, string providerToUse, string streamNamespace);\n        Task StopBeingConsumer();\n        Task<int> GetItemsConsumed();\n        Task<int> GetConsumerCount();\n        Task DeactivateConsumerOnIdle();\n    }\n\n    public interface IPersistentStreaming_ProducerGrain : IStreaming_ProducerGrain\n    {\n    }\n\n    public interface IPersistentStreaming_ConsumerGrain : IStreaming_ConsumerGrain\n    {\n    }\n\n    public interface IStreaming_ProducerConsumerGrain : IGrainWithIntegerKey, IStreaming_ProducerGrain, IStreaming_ConsumerGrain\n    {\n    }\n\n    public interface IStreaming_Reentrant_ProducerConsumerGrain : IGrainWithIntegerKey, IStreaming_ProducerGrain, IStreaming_ConsumerGrain\n    {\n    }\n\n    public interface IStreaming_ImplicitlySubscribedConsumerGrain : IGrainWithIntegerKey, IStreaming_ConsumerGrain\n    {\n    }\n\n    public interface IStreaming_ImplicitlySubscribedGenericConsumerGrain<T> : IGrainWithIntegerKey, IStreaming_ConsumerGrain\n    {\n    }\n\n\n    //------- STATE interfaces ----//\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Streaming_ProducerGrain_State\n    {\n        [Id(0)]\n        public List<IProducerObserver> Producers { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Streaming_ConsumerGrain_State\n    {\n        [Id(0)]\n        public List<IConsumerObserver> Consumers { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Streaming_ProducerConsumerGrain_State\n    {\n        [Id(0)]\n        public List<IProducerObserver> Producers { get; set; }\n        [Id(1)]\n        public List<IConsumerObserver> Consumers { get; set; }\n    }\n\n    //------- POCO interfaces for objects that implement the actual test logic ----///\n\n    public interface IProducerObserver\n    {\n        void BecomeProducer(Guid streamId, IStreamProvider streamProvider, string streamNamespace);\n        void RenewProducer(ILogger logger, IStreamProvider streamProvider);\n        Task StopBeingProducer();\n        Task ProduceSequentialSeries(int count);\n        Task ProduceParallelSeries(int count);\n        Task ProducePeriodicSeries(Func<Func<object, Task>, IDisposable> createTimerFunc, int count);\n        Task<int> ExpectedItemsProduced { get; }\n        Task<int> ItemsProduced { get; }\n        Task AddNewConsumerGrain(Guid consumerGrainId);\n        Task<int> ProducerCount { get; }\n        Task VerifyFinished();\n        string ProviderName { get; }\n    }\n\n    public interface IConsumerObserver\n    {\n        Task BecomeConsumer(Guid streamId, IStreamProvider streamProvider, string streamNamespace);\n        Task RenewConsumer(ILogger logger, IStreamProvider streamProvider);\n        Task StopBeingConsumer(IStreamProvider streamProvider);\n        Task<int> ItemsConsumed { get; }\n        Task<int> ConsumerCount { get; }\n        string ProviderName { get; }\n    }    \n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamingHistoryGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IStreamingHistoryGrain : IGrainWithStringKey\n    {\n        Task BecomeConsumer(StreamId streamId, string provider, string filterData = null);\n\n        Task StopBeingConsumer();\n\n        Task<List<int>> GetReceivedItems();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreamingImmutabilityTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IStreamingImmutabilityTestGrain : IGrainWithGuidKey\n    {\n        Task SubscribeToStream(Guid guid, string providerName);\n        Task UnsubscribeFromStream();\n        Task SendTestObject(string providerName);\n        Task SetTestObjectStringProperty(string value);\n        Task<string> GetTestObjectStringProperty();\n        Task<string> GetSiloIdentifier();\n\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStreaming_ProducerGrain.cs",
    "content": "﻿using Orleans.Concurrency;\n\nnamespace UnitTests.GrainInterfaces\n{\n    //------- GRAIN interfaces ----//\n    public interface IStreaming_ProducerGrain : IGrainWithGuidKey\n    {\n        Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace);\n        Task StopBeingProducer();\n        Task ProduceSequentialSeries(int count);\n        Task ProduceParallelSeries(int count);\n        Task ProducePeriodicSeries(int count);\n        Task<int> GetExpectedItemsProduced();\n        Task<int> GetItemsProduced();\n        Task AddNewConsumerGrain(Guid consumerGrainId);\n        Task<int> GetProducerCount();\n        Task DeactivateProducerOnIdle();\n\n        [AlwaysInterleave]\n        Task VerifyFinished();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IStuckGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface IStuckGrain : IGrainWithGuidKey\n    {\n        Task RunForever();\n\n        Task NonBlockingCall();\n\n        Task<int> GetNonBlockingCallCounter();\n\n        Task<bool> DidActivationTryToStart(GrainId id);\n\n        Task BlockingDeactivation();\n    }\n\n    public interface IStuckCleanGrain : IGrainWithGuidKey\n    {\n        Task Release(Guid key);\n\n        Task<bool> IsActivated(Guid key);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ITestExtension.cs",
    "content": "﻿using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface ITestExtension : IGrainExtension\n    {\n        Task<string> CheckExtension_1();\n\n        Task<string> CheckExtension_2();\n    }\n\n    public interface IGenericTestExtension<T> : IGrainExtension\n    {\n        Task<T> CheckExtension_1();\n\n        Task<string> CheckExtension_2();\n    }\n\n    public interface ISimpleExtension : IGrainExtension\n    {\n        Task<string> CheckExtension_1();\n    }\n\n    public interface IAutoExtension : IGrainExtension\n    {\n        Task<string> CheckExtension();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ITestGrain.cs",
    "content": "using Orleans.Concurrency;\nusing Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public interface ITestGrain : IGrainWithIntegerKey\n    {\n        // duplicate to verify identity\n        Task<long> GetKey();\n\n        // separate label that can be set\n        Task<string> GetLabel();\n\n        Task SetLabel(string label);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task<string> GetActivationId();\n\n        Task<ITestGrain> GetGrainReference();\n\n        Task<Tuple<string, string>> TestRequestContext();\n\n        Task<IGrain[]> GetMultipleGrainInterfaces_Array();\n\n        Task<List<IGrain>> GetMultipleGrainInterfaces_List();\n\n        Task StartTimer();\n\n        [ResponseTimeout(\"00:00:01\")]\n        Task DoLongAction(TimeSpan timespan, string str);\n    }\n\n    public interface ITestGrainLongOnActivateAsync : IGrainWithIntegerKey\n    {\n        Task<long> GetKey();\n    }\n\n    public interface IGuidTestGrain : IGrainWithGuidKey\n    {\n        // duplicate to verify identity\n        Task<Guid> GetKey();\n\n        // separate label that can be set\n        Task<string> GetLabel();\n\n        Task SetLabel(string label);\n\n        Task<string> GetRuntimeInstanceId();\n\n        Task<string> GetActivationId();\n\n        Task<SiloAddress> GetSiloAddress();\n    }\n\n    public interface IOneWayGrain : IGrainWithGuidKey\n    {\n        [OneWay]\n        Task Notify(ISimpleGrainObserver observer);\n\n        [OneWay]\n        ValueTask NotifyValueTask(ISimpleGrainObserver observer);\n\n        [OneWay]\n        Task ThrowsOneWay();\n\n        [OneWay]\n        ValueTask ThrowsOneWayValueTask();\n\n        Task<bool> NotifyOtherGrain(IOneWayGrain otherGrain, ISimpleGrainObserver observer);\n\n        Task<bool> NotifyOtherGrainValueTask(IOneWayGrain otherGrain, ISimpleGrainObserver observer);\n\n        Task<IOneWayGrain> GetOtherGrain();\n\n        Task NotifyOtherGrain();\n\n        Task<int> GetCount();\n\n        Task Deactivate();\n\n        Task<SiloAddress> GetSiloAddress();\n\n        Task<SiloAddress> GetPrimaryForGrain();\n\n        Task<string> GetActivationId();\n\n        Task<string> GetActivationAddress(IGrain grain);\n\n        Task SignalSelfViaOther();\n\n        [OneWay]\n        Task SendSignalTo(IOneWayGrain grain);\n\n        [AlwaysInterleave]\n        Task<(int NumSignals, string SignallerId)> WaitForSignal();\n\n        [AlwaysInterleave]\n        Task Signal(string id);\n    }\n\n    public interface ICanBeOneWayGrain : IGrainWithGuidKey\n    {\n        Task Notify(ISimpleGrainObserver observer);\n\n        ValueTask NotifyValueTask(ISimpleGrainObserver observer);\n\n        Task Throws();\n\n        ValueTask ThrowsValueTask();\n\n        Task<int> GetCount();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ITimerGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface ITimerGrain : IGrainWithIntegerKey\n    {\n        Task StopDefaultTimer();\n        Task<TimeSpan> GetTimerPeriod();\n        Task<int> GetCounter();\n        Task SetCounter(int value);\n        Task StartTimer(string timerName);\n        Task StopTimer(string timerName);\n        Task LongWait(TimeSpan time);\n        Task Deactivate();\n    }\n\n    public interface IPocoTimerGrain : ITimerGrain\n    {\n    }\n\n    public interface ITimerCallGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetTickCount();\n        Task<Exception> GetException();\n\n        Task StartTimer(string name, TimeSpan dueTime);\n        Task StartTimer(string name, TimeSpan dueTime, string operationType);\n        Task RestartTimer(string name, TimeSpan dueTime);\n        Task RestartTimer(string name, TimeSpan dueTime, TimeSpan period);\n        Task StopTimer(string name);\n        Task RunSelfDisposingTimer();\n    }\n\n    public interface IPocoTimerCallGrain : ITimerCallGrain\n    {\n    }\n\n    public interface ITimerRequestGrain : IGrainWithIntegerKey\n    {\n        Task StartAndWaitTimerTick(TimeSpan dueTime);\n\n        Task StartStuckTimer(TimeSpan dueTime);\n\n        Task<string> GetRuntimeInstanceId();\n        Task<int> TestAllTimerOverloads();\n        Task<int> PollCompletedTimers();\n        Task TestCompletedTimerResults();\n    }\n\n    public interface IPocoTimerRequestGrain : ITimerRequestGrain\n    {\n    }\n\n    public interface INonReentrantTimerCallGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetTickCount();\n        Task<Exception> GetException();\n\n        Task StartTimer(string name, TimeSpan delay, bool keepAlive = true);\n        Task StopTimer(string name);\n        Task ExternalTick(string name);\n    }\n\n    public interface IPocoNonReentrantTimerCallGrain : INonReentrantTimerCallGrain\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IValueTypeTestGrain.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing Orleans.Concurrency;\nusing ProtoBuf;\n\nnamespace UnitTests.GrainInterfaces\n{\n    [Serializable]\n    [GenerateSerializer]\n    public struct ValueTypeTestData\n    {\n        [Id(0)]\n        [Newtonsoft.Json.JsonProperty]\n        public int Value { get; set; }\n\n        public ValueTypeTestData(int i)\n        {\n            Value = i;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public enum TestEnum : byte\n    {\n        First,\n        Second,\n        Third\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public enum CampaignEnemyTestType : sbyte\n    {\n        None = -1,\n        Brute = 0,\n        Enemy1,\n        Enemy2,\n        Enemy3\n    }\n\n    [GenerateSerializer]\n    public class ClassWithEnumTestData\n    {\n        [Id(0)]\n        public TestEnum EnumValue { get; set; }\n\n        [Id(1)]\n        public CampaignEnemyTestType Enemy { get; set; }\n    }\n\n    [ProtoContract]\n    [Serializable]\n    [GenerateSerializer]\n    public class LargeTestData\n    {\n        [ProtoMember(1)]\n        [Id(0)]\n        public string TestString { get; set; }\n        [ProtoMember(2)]\n        [Id(1)]\n        private readonly bool[] boolArray;\n        [ProtoMember(3)]\n        [Id(2)]\n        protected Dictionary<string, int> stringIntDict;\n        [ProtoMember(4)]\n        [Id(3)]\n        public TestEnum EnumValue { get; set; }\n        [ProtoMember(5)]\n        [Id(4)]\n        private readonly ClassWithEnumTestData[] classArray;\n        [ProtoMember(6)]\n        [Id(5)]\n        public string Description { get; set; }\n\n        public LargeTestData()\n        {\n            boolArray = new bool[20];\n            stringIntDict = new Dictionary<string, int>();\n            classArray = new ClassWithEnumTestData[50];\n            for (var i = 0; i < 50; i++)\n            {\n                classArray[i] = new ClassWithEnumTestData();\n            }\n        }\n\n        public void SetBit(int n, bool value = true)\n        {\n            boolArray[n] = value;\n        }\n        public bool GetBit(int n)\n        {\n            return boolArray[n];\n        }\n        public void SetEnemy(int n, CampaignEnemyTestType enemy)\n        {\n            classArray[n].Enemy = enemy;\n        }\n        public CampaignEnemyTestType GetEnemy(int n)\n        {\n            return classArray[n].Enemy;\n        }\n        public void SetNumber(string name, int value)\n        {\n            stringIntDict[name] = value;\n        }\n        public int GetNumber(string name)\n        {\n            return stringIntDict[name];\n        }\n\n        // This class is not actually used anywhere. It is here to test that the serializer generator properly handles\n        // nested generic classes. If it doesn't, then the generated serializer for this class will fail to compile.\n        [Serializable]\n        [GenerateSerializer]\n        public class NestedGeneric<T>\n        {\n            [Id(0)]\n            private T myT;\n            [Id(1)]\n            private string s;\n\n            public NestedGeneric(T t)\n            {\n                myT = t;\n                s = myT.ToString();\n            }\n\n            public override string ToString()\n            {\n                return s;\n            }\n\n            public void SetT(T t)\n            {\n                myT = t;\n                s = myT.ToString();\n            }\n        }\n    }\n\n    public interface IValueTypeTestGrain : IGrainWithGuidKey\n    {\n        Task<ValueTypeTestData> GetStateData();\n\n        Task SetStateData(ValueTypeTestData d);\n    }\n\n    public interface IRoundtripSerializationGrain : IGrainWithIntegerKey\n    {\n        Task<CampaignEnemyTestType> GetEnemyType();\n\n        Task<object> GetClosedGenericValue();\n\n        Task<RetVal> GetRetValForParamVal(ParamVal param);\n    }\n\n    [GenerateSerializer]\n    public record ParamVal([field: Id(0)] int Value);\n\n    [GenerateSerializer]\n    public record RetVal([field: Id(0)] int Value);\n\n    [Serializable]\n    [Immutable]\n    [GenerateSerializer]\n    public class ImmutableType\n    {\n        [Id(0)]\n        private readonly int a;\n        [Id(1)]\n        private readonly int b;\n\n        public int A { get { return a; } }\n        public int B { get { return b; } }\n\n        public ImmutableType(int aval, int bval)\n        {\n            a = aval;\n            b = bval;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class EmbeddedImmutable\n    {\n        [Id(0)]\n        public string A { get; set; }\n\n        [Id(1)]\n        private readonly Immutable<List<int>> list;\n        public Immutable<List<int>> B { get { return list; } }\n\n        public EmbeddedImmutable(string a, params int[] listOfInts)\n        {\n            A = a;\n            var l = new List<int>();\n            l.AddRange(listOfInts);\n            list = new Immutable<List<int>>(l);\n        }\n    }\n\n    [GenerateSerializer]\n    public sealed class ClassWithEmbeddedImmutable\n    {\n        [Id(1), Immutable] public IEnumerable<byte> Immutable;\n        [Id(2)] public object Mutable;\n    }\n\n    [GenerateSerializer]\n    public struct StructWithEmbeddedImmutable\n    {\n        [Id(1), Immutable] public byte[] Immutable;\n        [Id(2)] public byte[] Mutable;\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public struct DefaultActivatorValueTypeWithRequiredField\n    {\n        [Id(0)] public required int Value;\n\n        [SetsRequiredMembers]\n        public DefaultActivatorValueTypeWithRequiredField(int value)\n        {\n            Value = value;\n        }\n    }\n\n    public struct WithGrainIdType\n    {\n        public GrainId GrainId { get; set; }\n\n        public WithGrainIdType(GrainId grainId)\n        {\n            GrainId = grainId;\n        }\n    }\n\n    public struct WithGrainIdMapType\n    {\n        public IDictionary<GrainId, int> Map { get; set; }\n\n        public WithGrainIdMapType(IDictionary<GrainId, int> map)\n        {\n            Map = map;\n        }\n    }\n\n    public struct WithGrainIdSetType\n    {\n        public ISet<GrainId> Set { get; set; }\n\n        public WithGrainIdSetType(ISet<GrainId> set)\n        {\n            Set = set;\n        }\n    }\n\n    [UseActivator]\n    [Serializable]\n    [GenerateSerializer]\n    public struct DefaultActivatorValueTypeWithUseActivator\n    {\n        [Id(0)] public int Value;\n\n        [SetsRequiredMembers]\n        public DefaultActivatorValueTypeWithUseActivator()\n        {\n            Value = 4;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/IsExternalInit.cs",
    "content": "namespace System.Runtime.CompilerServices\n{\n    // required for record serialization support for downlevel\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/ProgramaticStreamSubscribe/IPassive_ConsumerGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// Consumer grain which passively reacts to subscriptions which was made on behalf of\n    /// it using Programmatic Subscribing \n    /// </summary>\n    public interface IPassive_ConsumerGrain: IGrainWithGuidKey\n    {\n        Task StopConsuming();\n        Task<int> GetCountOfOnAddFuncCalled();\n        Task<int> GetNumberConsumed();\n    }\n\n    //the consumer grain marker interface which would unsubscribe on any subscription added by StreamSubscriptionManager\n    public interface IJerk_ConsumerGrain : IGrainWithGuidKey\n    {\n    }\n\n    public interface IImplicitSubscribeGrain: IPassive_ConsumerGrain\n    {\n    }\n\n    public interface ITypedProducerGrain: IGrainWithGuidKey\n    {\n        Task BecomeProducer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task StartPeriodicProducing(TimeSpan? firePeriod = null);\n\n        Task StopPeriodicProducing();\n\n        Task<int> GetNumberProduced();\n\n        Task ClearNumberProduced();\n        Task Produce();\n    }\n\n    public interface ITypedProducerGrainProducingInt : ITypedProducerGrain\n    { }\n\n    public interface ITypedProducerGrainProducingApple : ITypedProducerGrain\n    { }\n\n    public interface IFruit\n    {\n        int GetNumber();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/RecursiveType.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IReferenceRecursiveTypeGrain : IGrainWithGuidKey\n    {\n        Task<RecursiveType> Echo(RecursiveType arg);\n    }\n\n    /// <summary>\n    /// These classes form a repro for https://github.com/dotnet/orleans/issues/5473, which resulted in a\n    /// StackOverflowException during code generation.\n    /// </summary>\n    [Serializable]\n    [GenerateSerializer]\n    public class RecursiveType : SelfTyped<RecursiveType>\n    {\n    }\n\n    [GenerateSerializer]\n    public abstract class SelfTyped<T> where T : SelfTyped<T>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/RedStreamNamespacePredicate.cs",
    "content": "using Orleans.Streams;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public class RedStreamNamespacePredicate : IStreamNamespacePredicate\n    {\n        public string PredicatePattern => ConstructorStreamNamespacePredicateProvider.FormatPattern(typeof(RedStreamNamespacePredicate), constructorArgument: null);\n\n        public bool IsMatch(string streamNamespace)\n        {\n            return streamNamespace.StartsWith(\"red\");\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/SerializerExclusions.cs",
    "content": "namespace Orleans.UnitTest.GrainInterfaces\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class MyTypeWithAnInternalTypeField\n    {\n        [Id(0)]\n        private readonly MyInternalDependency _dependency;\n\n        public MyTypeWithAnInternalTypeField()\n        {\n            _dependency = new MyInternalDependency();\n        }\n\n        [GenerateSerializer]\n        internal class MyInternalDependency\n        {\n        }\n    }\n\n    // Verify that we do generate a custom serializer for MyTypeWithAnInternalTypeField because it is visible within the assembly.\n    public interface IInternalReturnType : IGrainWithIntegerKey\n    {\n        Task<MyTypeWithAnInternalTypeField> Foo();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/SerializerTestTypes.cs",
    "content": "using Orleans.Serialization;\n\nnamespace UnitTests.GrainInterfaces\n{\n    /// <summary>\n    /// A type with an <see cref=\"IOnDeserialized\"/> hook, to test that it is correctly called by the internal serializers.\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    [Orleans.SerializationCallbacks(typeof(Orleans.Runtime.OnDeserializedCallbacks))]\n    public class TypeWithOnDeserializedHook : IOnDeserialized\n    {\n        [NonSerialized]\n        public DeserializationContext Context;\n\n        [Orleans.Id(0)]\n        public int Int { get; set; }\n\n        void IOnDeserialized.OnDeserialized(DeserializationContext context)\n        {\n            this.Context = context;\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class BaseClassWithAutoProp\n    {\n        [Orleans.Id(0)]\n        public int AutoProp { get; set; }\n    }\n\n    /// <summary>\n    /// Code generation test to ensure that an overridden autoprop with a type which differs from\n    /// the base autoprop is not used during serializer generation\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class SubClassOverridingAutoProp : BaseClassWithAutoProp\n    {\n        public new string AutoProp { get => base.AutoProp.ToString(); set => base.AutoProp = int.Parse(value); }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/SlowConsumingGrains/ISlowConsumingGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface ISlowConsumingGrain : IGrainWithGuidKey\n    {\n        Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse);\n\n        Task StopConsuming();\n\n        Task<int> GetNumberConsumed();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/TestGrainInterfaces.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.GrainInterfaces</RootNamespace>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Streaming\\Orleans.Streaming.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.DurableJobs\\Orleans.DurableJobs.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"protobuf-net\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/TestTypeA.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class TestTypeA\n    {\n        [Orleans.Id(0)]\n        public ICollection<TestTypeA> Collection { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/UnitTestGrainInterfaces.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IA : IGrainWithIntegerKey\n    {\n        Task<string> CommonMethod();\n        Task<string> A1Method();\n        Task<string> A2Method();\n        Task<string> A3Method();\n    }\n\n    public interface IB : IGrainWithIntegerKey\n    {\n        Task<string> CommonMethod();\n        Task<string> B1Method();\n        Task<string> B2Method();\n        Task<string> B3Method();\n    }\n\n    public interface IC : IA, IB\n    {\n        new Task<string> CommonMethod();\n        Task<string> C1Method();\n        Task<string> C2Method();\n        Task<string> C3Method();\n    }\n\n    public interface ID : IC\n    {\n        Task<string> D1Method();\n        Task<string> D2Method();\n        Task<string> D3Method();\n    }\n\n    public interface IE : IGrainWithIntegerKey\n    {\n        Task<string> E1Method();\n        Task<string> E2Method();\n        Task<string> E3Method();\n    }\n\n    public interface IF : ID, IE\n    {\n        Task<string> F1Method();\n        Task<string> F2Method();\n        Task<string> F3Method();\n    }\n\n    public interface IG : IGrainWithIntegerKey\n    {\n        Task<string> AmbiguousMethod();\n    }\n    public interface IH : IGrainWithIntegerKey\n    {\n        Task<string> H1Method();\n        Task<string> H2Method();\n        Task<string> H3Method();\n    }\n\n    public interface IServiceType : IF\n    {\n        Task<string> ServiceTypeMethod1();\n        Task<string> ServiceTypeMethod2();\n        Task<string> ServiceTypeMethod3();\n    }\n\n    public interface IDerivedServiceType : IServiceType, IH\n    {\n        Task<string> DerivedServiceTypeMethod1();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrainInterfaces/VersionAwarePlacementDirector.cs",
    "content": "using Orleans.Placement;\nusing Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    [AttributeUsage(AttributeTargets.Class)]\n    public sealed class VersionAwareStrategyAttribute : PlacementAttribute\n    {\n        public VersionAwareStrategyAttribute()\n            : base(VersionAwarePlacementStrategy.Singleton)\n        {\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class VersionAwarePlacementStrategy : PlacementStrategy\n    {\n        internal static VersionAwarePlacementStrategy Singleton { get; } = new VersionAwarePlacementStrategy();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ActivateDeactivateWatcherGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class ActivateDeactivateWatcherGrain : IActivateDeactivateWatcherGrain\n    {\n        private readonly ILogger logger;\n\n        private readonly List<string> activationCalls = new List<string>();\n        private readonly List<string> deactivationCalls = new List<string>();\n\n        public ActivateDeactivateWatcherGrain(ILogger<ActivateDeactivateWatcherGrain> logger)\n        {\n            this.logger = logger;\n        }\n\n        public Task<string[]> GetActivateCalls() { return Task.FromResult(activationCalls.ToArray()); }\n        public Task<string[]> GetDeactivateCalls() { return Task.FromResult(deactivationCalls.ToArray()); }\n\n        public Task Clear()\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Clear\");\n            activationCalls.Clear();\n            deactivationCalls.Clear();\n            return Task.CompletedTask;\n        }\n        public Task RecordActivateCall(string activation)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"RecordActivateCall: \" + activation);\n            activationCalls.Add(activation);\n            return Task.CompletedTask;\n        }\n\n        public Task RecordDeactivateCall(string activation)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"RecordDeactivateCall: \" + activation);\n            deactivationCalls.Add(activation);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ActivationCancellationTestGrains.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\n/// <summary>\n/// Base class for activation cancellation test grains.\n/// </summary>\npublic abstract class ActivationCancellationTestGrainBase : Grain\n{\n    protected readonly ILogger Logger;\n    protected readonly string ActivationId = Guid.NewGuid().ToString();\n    protected bool IsActivatedSuccessfully;\n    private readonly IGrainRuntime _grainRuntime;\n\n    protected ActivationCancellationTestGrainBase(ILogger logger, IGrainRuntime grainRuntime)\n    {\n        Logger = logger;\n        _grainRuntime = grainRuntime;\n    }\n\n    /// <summary>\n    /// Gets the TimeProvider from the grain runtime.\n    /// </summary>\n    protected TimeProvider TimeProvider => _grainRuntime.TimeProvider;\n\n    public Task<string> GetActivationId() => Task.FromResult(ActivationId);\n\n    public Task<bool> IsActivated() => Task.FromResult(IsActivatedSuccessfully);\n}\n\n/// <summary>\n/// Grain that throws OperationCanceledException during OnActivateAsync when the cancellation token is triggered.\n/// This simulates code that properly observes the cancellation token by passing it to async methods.\n/// </summary>\npublic class ActivationCancellation_ThrowsOperationCancelledGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsOperationCancelledGrain\n{\n    public ActivationCancellation_ThrowsOperationCancelledGrain(ILogger<ActivationCancellation_ThrowsOperationCancelledGrain> logger, IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        // Check if we should simulate a delay that would cause cancellation\n        if (RequestContext.Get(\"delay_activation_ms\") is int delayMs && delayMs > 0)\n        {\n            Logger.LogDebug(\"Delaying activation by {DelayMs}ms\", delayMs);\n            await Task.Delay(TimeSpan.FromMilliseconds(delayMs), cancellationToken);\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        await base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that throws ObjectDisposedException during OnActivateAsync.\n/// This simulates code that doesn't observe the cancellation token but tries to access services\n/// that have been disposed after cancellation.\n/// </summary>\npublic class ActivationCancellation_ThrowsObjectDisposedGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsObjectDisposedGrain\n{\n    public ActivationCancellation_ThrowsObjectDisposedGrain(\n        ILogger<ActivationCancellation_ThrowsObjectDisposedGrain> logger,\n        IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        if (RequestContext.Get(\"delay_activation_ms\") is int delayMs && delayMs > 0)\n        {\n            Logger.LogDebug(\"Setting up cancellation callback to throw ObjectDisposedException after {DelayMs}ms max\", delayMs);\n            \n            var tcs = new TaskCompletionSource<bool>();\n            \n            // Register callback to throw ObjectDisposedException when cancellation is requested\n            await using var registration = cancellationToken.Register(() =>\n            {\n                Logger.LogDebug(\"Cancellation was requested, throwing ObjectDisposedException\");\n                tcs.TrySetException(new ObjectDisposedException(\"IServiceProvider\", \"The service provider has been disposed because the activation was cancelled.\"));\n            });\n\n            Thread.Sleep(TimeSpan.FromMilliseconds(delayMs));\n\n            await tcs.Task;\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        await base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that throws a generic exception during OnActivateAsync (not related to cancellation).\n/// </summary>\npublic class ActivationCancellation_ThrowsGenericExceptionGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsGenericExceptionGrain\n{\n    public ActivationCancellation_ThrowsGenericExceptionGrain(ILogger<ActivationCancellation_ThrowsGenericExceptionGrain> logger, IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        // Check if we should throw an exception\n        if (RequestContext.Get(\"throw_exception\") is bool shouldThrow && shouldThrow)\n        {\n            Logger.LogDebug(\"Throwing generic exception as requested\");\n            throw new InvalidOperationException(\"This is a test exception thrown during activation.\");\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        return base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that activates successfully without any issues.\n/// </summary>\npublic class ActivationCancellation_SuccessfulActivationGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_SuccessfulActivationGrain\n{\n    public ActivationCancellation_SuccessfulActivationGrain(ILogger<ActivationCancellation_SuccessfulActivationGrain> logger, IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        return base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that throws TaskCanceledException during OnActivateAsync.\n/// TaskCanceledException inherits from OperationCanceledException and should be handled the same way.\n/// </summary>\npublic class ActivationCancellation_ThrowsTaskCancelledGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsTaskCancelledGrain\n{\n    public ActivationCancellation_ThrowsTaskCancelledGrain(ILogger<ActivationCancellation_ThrowsTaskCancelledGrain> logger, IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override async Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        if (RequestContext.Get(\"delay_activation_ms\") is int delayMs && delayMs > 0)\n        {\n            Logger.LogDebug(\"Setting up cancellation callback to throw TaskCanceledException after {DelayMs}ms max\", delayMs);\n            \n            var tcs = new TaskCompletionSource<bool>();\n            \n            // Register callback to throw TaskCanceledException when cancellation is requested\n            /*await using var registration = cancellationToken.Register(() =>\n            {\n                Logger.LogDebug(\"Cancellation was requested, throwing TaskCanceledException\");\n                tcs.TrySetException(new TaskCanceledException(\"Activation was cancelled\", null, cancellationToken));\n            });*/\n\n            // Start the delay task (without cancellation token)\n            var delayTask = Task.Delay(TimeSpan.FromMilliseconds(delayMs), TimeProvider, CancellationToken.None);\n            \n            // Wait for either the delay to complete or the cancellation to trigger the exception\n            var completedTask = await Task.WhenAny(delayTask, tcs.Task);\n            \n            // If the TCS task completed, it has an exception - await it to propagate\n            if (completedTask == tcs.Task)\n            {\n                await tcs.Task;\n            }\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        await base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that throws ObjectDisposedException unconditionally (not due to cancellation).\n/// This tests that ObjectDisposedException thrown for other reasons is NOT treated as cancellation.\n/// </summary>\npublic class ActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain\n{\n    public ActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain(\n        ILogger<ActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain> logger,\n        IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        // Check if we should throw an exception (without cancellation being requested)\n        if (RequestContext.Get(\"throw_object_disposed\") is bool shouldThrow && shouldThrow)\n        {\n            Logger.LogDebug(\"Throwing ObjectDisposedException unconditionally (cancellation NOT requested)\");\n            // This simulates a bug where ObjectDisposedException is thrown for reasons\n            // unrelated to cancellation - should NOT be treated as ActivationCancelledException\n            throw new ObjectDisposedException(\"SomeObject\", \"This object was disposed for reasons unrelated to cancellation.\");\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        return base.OnActivateAsync(cancellationToken);\n    }\n}\n\n/// <summary>\n/// Grain that throws OperationCanceledException unconditionally (not due to cancellation token being cancelled).\n/// This tests that OperationCanceledException thrown for other reasons is NOT treated as ActivationCancelledException.\n/// </summary>\npublic class ActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain\n    : ActivationCancellationTestGrainBase, IActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain\n{\n    public ActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain(\n        ILogger<ActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain> logger,\n        IGrainRuntime grainRuntime)\n        : base(logger, grainRuntime)\n    {\n    }\n\n    public override Task OnActivateAsync(CancellationToken cancellationToken)\n    {\n        Logger.LogDebug(\"OnActivateAsync starting for {GrainType}\", GetType().Name);\n\n        // Check if we should throw an exception (without cancellation being requested)\n        if (RequestContext.Get(\"throw_operation_cancelled\") is bool shouldThrow && shouldThrow)\n        {\n            Logger.LogDebug(\"Throwing OperationCanceledException unconditionally (cancellation NOT requested on the passed token)\");\n            // This simulates a scenario where OperationCanceledException is thrown for reasons\n            // unrelated to the activation's cancellation token being cancelled\n            // The code should check cancellationToken.IsCancellationRequested before converting to ActivationCancelledException\n            throw new OperationCanceledException(\"Operation was cancelled for reasons unrelated to activation cancellation.\");\n        }\n\n        IsActivatedSuccessfully = true;\n        Logger.LogDebug(\"OnActivateAsync completed successfully for {GrainType}\", GetType().Name);\n        return base.OnActivateAsync(cancellationToken);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ActivityGrain.cs",
    "content": "using System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ActivityGrain : IActivityGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity == null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            var result = new ActivityData()\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            };\n\n            return Task.FromResult(result);\n        }\n    }\n\n    /// <summary>\n    /// Grain implementation for testing IAsyncEnumerable activity tracing.\n    /// </summary>\n    public class AsyncEnumerableActivityGrain : Grain, IAsyncEnumerableActivityGrain\n    {\n        public async IAsyncEnumerable<ActivityData> GetActivityDataStream(int count, [EnumeratorCancellation] CancellationToken cancellationToken = default)\n        {\n            for (int i = 0; i < count; i++)\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n\n                var activity = Activity.Current;\n                var data = activity is null\n                    ? new ActivityData()\n                    : new ActivityData\n                    {\n                        Id = activity.Id,\n                        TraceState = activity.TraceStateString,\n                        Baggage = activity.Baggage.ToList(),\n                    };\n\n                yield return data;\n\n                // Small delay to allow for proper activity propagation\n                await Task.Yield();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/AdoNet/CustomerGrain.cs",
    "content": "using Orleans.Providers;\nusing Orleans.SqlUtils.StorageProvider.GrainInterfaces;\n\nnamespace Orleans.SqlUtils.StorageProvider.GrainClasses\n{\n    [StorageProvider(ProviderName = \"SqlStore\")]\n    public class CustomerGrain : Grain<CustomerState>, ICustomerGrain\n    {\n        private readonly Random _random = new Random();\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<string> IntroduceSelf()\n        {\n            return Task.FromResult(string.Format(\"Hello, my name is {0} {1}\", State.FirstName, State.LastName));\n        }\n\n        public async Task Set(int customerId, string firstName, string lastName)\n        {\n            State.CustomerId = customerId;\n            State.FirstName = firstName;\n            State.LastName = lastName;\n\n            await WriteStateAsync();\n        }\n\n        public async Task AddDevice(IDeviceGrain device)\n        {\n            if (device == null)\n                throw new ArgumentNullException(nameof(device));\n\n            if (null == State.Devices)\n                State.Devices = new List<IDeviceGrain>();\n\n            if (!State.Devices.Contains(device))\n            {\n                State.Devices.Add(device);\n                await device.SetOwner(this);\n            }\n\n            await WriteStateAsync();\n        }\n\n        public async Task SetRandomState()\n        {\n            int customerId = (int)this.GetPrimaryKeyLong();\n            \n            var dt = DateTime.UtcNow;\n            var now = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, DateTimeKind.Utc);\n\n            State.CustomerId = customerId;\n            State.FirstName = \"FirstName_\" + customerId;\n            State.LastName = \"LastName_\" + customerId;\n            State.NickName = \"NickName_\" + customerId;\n            State.BirthDate = new DateTime(_random.Next(40) + 1970, _random.Next(12) + 1,  _random.Next(28) + 1, 0, 0, 0, DateTimeKind.Utc);\n            State.Gender = _random.Next(2);\n            State.Country = \"Country_\" + _random.Next();\n            State.AvatarUrl = \"AvatarUrl_\" + _random.Next();\n            State.KudoPoints = _random.Next();\n            State.Status = _random.Next();\n            State.LastLogin = now;\n            State.Devices = new List<IDeviceGrain>();\n\n            await WriteStateAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/AdoNet/DeviceGrain.cs",
    "content": "using Orleans.Providers;\nusing Orleans.SqlUtils.StorageProvider.GrainInterfaces;\n\nnamespace Orleans.SqlUtils.StorageProvider.GrainClasses\n{\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class DeviceGrain : Grain<DeviceState>, IDeviceGrain\n    {\n        public Task<string> GetSerialNumber()\n        {\n            return Task.FromResult(State.SerialNumber);\n        }\n\n        public async Task SetOwner(ICustomerGrain customer)\n        {\n            if (customer == null)\n                throw new ArgumentNullException(nameof(customer));\n\n            State.Owner = customer;\n\n            await WriteStateAsync();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/AdoNet/ICustomerState.cs",
    "content": "using Orleans.SqlUtils.StorageProvider.GrainInterfaces;\n\nnamespace Orleans.SqlUtils.StorageProvider.GrainClasses\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class CustomerState\n    {\n        [Id(0)]\n        public int CustomerId { get; set; }\n        [Id(1)]\n        public string FirstName { get; set; }\n        [Id(2)]\n        public string LastName { get; set; }\n        [Id(3)]\n        public string NickName { get; set; }\n        [Id(4)]\n        public DateTime BirthDate { get; set; }\n        [Id(5)]\n        public int Gender { get; set; }\n        [Id(6)]\n        public string Country { get; set; }\n        [Id(7)]\n        public string AvatarUrl { get; set; }\n        [Id(8)]\n        public int KudoPoints { get; set; }\n        [Id(9)]\n        public int Status { get; set; }\n        [Id(10)]\n        public DateTime LastLogin { get; set; }\n        [Id(11)]\n        public List<IDeviceGrain> Devices { get; set; }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/AdoNet/IDeviceState.cs",
    "content": "using Orleans.SqlUtils.StorageProvider.GrainInterfaces;\n\nnamespace Orleans.SqlUtils.StorageProvider.GrainClasses\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class DeviceState\n    {\n        [Id(0)]\n        public ICustomerGrain Owner { get; set; }\n        [Id(1)]\n        public string SerialNumber { get; set; }\n        [Id(2)]\n        public long EventId { get; set; }\n        [Id(3)]\n        public int VehicleId { get; set; }\n        [Id(4)]\n        public short CustomerId { get; set; }\n        [Id(5)]\n        public short CompanyId { get; set; }\n        [Id(6)]\n        public short SoftwareId { get; set; }\n        [Id(7)]\n        public short StatusId { get; set; }\n        [Id(8)]\n        public short LifeCycleId { get; set; }\n        [Id(9)]\n        public int DateKey { get; set; }\n        [Id(10)]\n        public int TimeKey { get; set; }\n        [Id(11)]\n        public short MillisecondKey { get; set; }\n        [Id(12)]\n        public int FaultId { get; set; }\n        [Id(13)]\n        public short SystemId { get; set; }\n        [Id(14)]\n        public short EventTypeId { get; set; }\n        [Id(15)]\n        public int LocationId { get; set; }\n        [Id(16)]\n        public double Latitude { get; set; }\n        [Id(17)]\n        public double Longitude { get; set; }\n        [Id(18)]\n        public DateTime TriggerTime { get; set; }\n        [Id(19)]\n        public long Altitude { get; set; }\n        [Id(20)]\n        public long Heading { get; set; }\n        [Id(21)]\n        public int PeakBusUtilization { get; set; }\n        [Id(22)]\n        public int TripId { get; set; }\n        [Id(23)]\n        public int CurrentBusUtilization { get; set; }\n        [Id(24)]\n        public int TotalSnapshots { get; set; }\n        [Id(25)]\n        public bool ProtectLampOn { get; set; }\n        [Id(26)]\n        public bool AmberWarningLampOn { get; set; }\n        [Id(27)]\n        public bool RedStopLampOn { get; set; }\n        [Id(28)]\n        public bool MalfunctionIndicatorLampOn { get; set; }\n        [Id(29)]\n        public bool FlashProtectLampOn { get; set; }\n        [Id(30)]\n        public bool FlashAmberWarningLampOn { get; set; }\n        [Id(31)]\n        public bool FlashRedStopLampOn { get; set; }\n        [Id(32)]\n        public bool FlashMalfunctionIndicatorLampOn { get; set; }\n        [Id(33)]\n        public int ConversionMethod { get; set; }\n        [Id(34)]\n        public int OccurrenceCount { get; set; }\n        [Id(35)]\n        public int PreTriggerSamples { get; set; }\n        [Id(36)]\n        public int PostTriggerSamples { get; set; }\n        [Id(37)]\n        public double AllLampsOnTime { get; set; }\n        [Id(38)]\n        public int AmberLampCount { get; set; }\n        [Id(39)]\n        public double AmberLampTime { get; set; }\n        [Id(40)]\n        public int RedLampCount { get; set; }\n        [Id(41)]\n        public double RedLampTime { get; set; }\n        [Id(42)]\n        public int MilLampCount { get; set; }\n        [Id(43)]\n        public double MilLampTime { get; set; }\n        [Id(44)]\n        public double EngineStartAmbient { get; set; }\n        [Id(45)]\n        public double EngineStartCoolant { get; set; }\n        [Id(46)]\n        public double TotalDistance { get; set; }\n        [Id(47)]\n        public double TotalEngineHours { get; set; }\n        [Id(48)]\n        public double TotalIdleFuel { get; set; }\n        [Id(49)]\n        public double TotalIdleHours { get; set; }\n        [Id(50)]\n        public double TotalFuel { get; set; }\n        [Id(51)]\n        public double TotalPtoFuel { get; set; }\n        [Id(52)]\n        public Guid TransactionId { get; set; }\n        [Id(53)]\n        public string MessageId { get; set; }\n        [Id(54)]\n        public short LampId { get; set; }\n        [Id(55)]\n        public short EngineFamilyId { get; set; }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/AsyncSimpleGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    public class AsyncSimpleGrain : SimpleGrain, ISimpleGrainWithAsyncMethods\n    {\n        private TaskCompletionSource<int> resolver;\n\n        public AsyncSimpleGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        public async Task<int> GetAxB_Async()\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            return await GetAxB();\n        }\n\n        public async Task<int> GetAxB_Async(int a, int b)\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            return await GetAxB(a, b);\n        }\n        public async Task SetA_Async(int a)\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            await SetA(a);\n        }\n        public async Task SetB_Async(int b)\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            await SetB(b);\n        }\n\n        public async Task IncrementA_Async()\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            await IncrementA();\n        }\n\n        public async Task<int> GetA_Async()\n        {\n            await Task.Delay(1000); // just to delay resolution of the promise for testing purposes\n            return await GetA();\n        }\n\n        public Task<int> GetX()\n        {\n            resolver = new TaskCompletionSource<int>();\n            return resolver.Task;\n        }\n\n        public Task SetX(int x)\n        {\n            resolver.SetResult(x);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/CatalogTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class CatalogTestGrain : Grain, ICatalogTestGrain\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.Delay(TimeSpan.FromMilliseconds(50));\n        }\n\n        public Task Initialize()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task BlastCallNewGrains(int nGrains, long startingKey, int nCallsToEach)\n        {\n            var promises = new List<Task>(nGrains * nCallsToEach);\n\n            for (int i = 0; i < nGrains; i++)\n            {\n                var grain = GrainFactory.GetGrain<ICatalogTestGrain>(startingKey + i);\n\n                for (int j = 0; j < nCallsToEach; j++)\n                    promises.Add(grain.Initialize());\n            }\n\n            return Task.WhenAll(promises);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ChainedGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class ChainedGrainState\n    {\n        [Id(0)]\n        public int Id { get; set; }\n\n        [Id(1)]\n        public int X { get; set; }\n\n        [Id(2)]\n        public IChainedGrain Next { get; set; }\n    }\n\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class ChainedGrain : Grain<ChainedGrainState>, IChainedGrain\n    {\n        private readonly ILogger logger;\n\n        public ChainedGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        Task<IChainedGrain> IChainedGrain.GetNext() { return Task.FromResult(State.Next); } \n\n        Task<int> IChainedGrain.GetId() { return Task.FromResult(State.Id); }\n\n        Task<int> IChainedGrain.GetX() { return Task.FromResult(State.X); }\n\n        public async Task<int> GetCalculatedValue()\n        {\n            if (State.Next == null)\n            {/*\n                if (Id % 10 != 0)\n                {\n                    Console.ForegroundColor = ConsoleColor.Yellow;\n                    Console.WriteLine(String.Format(\"Id={0}, Next=null, X={1}\", Id, X));\n                    Console.ResetColor();\n                }*/\n                return State.X;\n            }\n            int nextValue = await State.Next.GetCalculatedValue();\n            return State.X + nextValue;\n        }\n\n        public Task SetNext(IChainedGrain next)\n        {\n            State.Next = next;\n            return Task.CompletedTask;\n        }\n\n        public Task SetNextNested(ChainGrainHolder next)\n        {\n            State.Next = next.Next;\n            return Task.CompletedTask;\n        }\n\n        public Task Validate(bool nextIsSet)\n        {\n            if ((nextIsSet && State.Next != null) || (!nextIsSet && State.Next == null))\n            {\n                // logger.Verbose(\"Id={0} validated successfully: Next={1}\", State.Id, State.Next);\n                return Task.CompletedTask;\n            }\n\n            logger.LogWarning(\"ChainGrain Id={Id} is in an invalid state. Next={Next}\", State.Id, State.Next);\n            throw new OrleansException($\"ChainGrain Id={State.Id} is in an invalid state. Next={State.Next}\");\n        }\n\n        public Task PassThis(IChainedGrain next)\n        {\n            return next.SetNext(this);\n        }\n\n        public Task PassNull(IChainedGrain next)\n        {\n            return next.SetNext(null);\n        }\n\n        public Task PassThisNested(ChainGrainHolder next)\n        {\n            return next.Next.SetNextNested(new ChainGrainHolder { Next = this });\n        }\n\n        public Task PassNullNested(ChainGrainHolder next)\n        {\n            return next.Next.SetNextNested(new ChainGrainHolder { Next = null });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/CircularStateTestGrain.cs",
    "content": "using TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    public class CircularStateTestGrain : Grain<CircularStateTestState>, ICircularStateTestGrain\n    {\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var c1 = new CircularTest1();\n            var c2 = new CircularTest2();\n            c2.CircularTest1List.Add(c1);\n            c1.CircularTest2 = c2;\n\n            State.CircularTest1 = c1;\n            await WriteStateAsync();\n        }\n        public Task<CircularTest1> GetState()\n        {\n            return Task.FromResult(State.CircularTest1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ConcreteGrainsWithGenericInterfaces.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class ConcreteGrainWithGenericInterfaceOfIntFloat : Grain, IGenericGrain<int, float>\n    {\n        protected int T { get; set; }\n\n        public Task SetT(int t)\n        {\n            T = t;\n            return Task.CompletedTask;\n        }\n\n        public Task<float> MapT2U()\n        {\n            return Task.FromResult((float)T);\n        }\n    }\n\n    internal class ConcreteGrainWithGenericInterfaceOfFloatString : Grain, IGenericGrain<float, string>\n    {\n        protected float T { get; set; }\n\n        public Task SetT(float t)\n        {\n            T = t;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> MapT2U()\n        {\n            return Task.FromResult(Convert.ToString(T));\n        }\n    }\n\n    internal class ConcreteGrainWith2GenericInterfaces : Grain, IGenericGrain<int, string>, ISimpleGenericGrain<int>\n    {\n        // IGenericGrain<int, string> methods:\n\n        protected int T { get; set; }\n\n        public Task SetT(int t)\n        {\n            T = t;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> MapT2U()\n        {\n            return Task.FromResult(Convert.ToString(T * 10, 10));\n        }\n\n        //ISimpleGenericGrain<int> methods:\n\n        public Task Set(int t)\n        {\n            return SetT(t);\n        }\n\n        public Task Transform()\n        {\n            T = T * 10;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> Get()\n        {\n            return Task.FromResult(T);\n        }\n\n        public Task CompareGrainReferences(ISimpleGenericGrain<int> clientReference)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ConcurrentGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ConcurrentGrain : Grain, IConcurrentGrain\n    {\n        private readonly ILogger logger;\n        private List<IConcurrentGrain> children;\n        private int index;\n        private int callNumber;\n\n        public ConcurrentGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public async Task Initialize(int ind)\n        {\n            this.index = ind;\n            logger.LogInformation(\"Initialize({Index})\", index);\n            if (index == 0)\n            {\n                children = new List<IConcurrentGrain>();\n                for (int i = 0; i < 1; i++)\n                {\n                    IConcurrentGrain grain = GrainFactory.GetGrain<IConcurrentGrain>((new Random()).Next());\n                    await grain.Initialize(i + 1);\n                    children.Add(grain);\n                }\n            }\n        }\n\n        public async Task<int> A()\n        {\n            callNumber++;\n            int call = callNumber;\n            logger.LogInformation(\"A() start callNumber {Call}\", call);\n            int i = 1;\n            foreach (IConcurrentGrain child in children)\n            {\n                logger.LogInformation(\"Calling B({Index}, {Call})\", i, call);\n                int ret = await child.B(call);\n                logger.LogInformation(\"Resolved the call to B({Index}, {Call})\", i, call);\n                i++;\n            }\n            logger.LogInformation(\"A() END callNumber {Call}\", call);\n            return 1;\n        }\n\n        public Task<int> B(int number)\n        {\n            logger.LogInformation(\"B({Index}) call {Number}\", index, number);\n            Thread.Sleep(100);\n            logger.LogInformation(\"B({Index}) call {Number} after sleep\", index, number);\n            return Task.FromResult(1);\n        }\n\n        private readonly List<int> m_list = new List<int>();\n\n        public Task<List<int>> ModifyReturnList_Test()\n        {\n            return Task<List<int>>.Factory.StartNew(() =>\n            {\n                // just do a lot of modifications of the list\n                for (int i = 0; i < 10; i++)\n                {\n                    if (m_list.Count < 1000)\n                        m_list.Add(i);\n                }\n                for (int i = 0; i < 5; i++)\n                {\n                    m_list.RemoveAt(0);\n                }\n                return m_list;\n            });\n        }\n\n        public Task Initialize_2(int ind)\n        {\n            index = ind;\n            logger.LogInformation(\"Initialize({Index})\", index);\n            return Task.CompletedTask;\n        }\n\n        // start a long tail call on the 1st grain by calling into the 2nd grain \n        public async Task<int> TailCall_Caller(IConcurrentReentrantGrain another, bool doCW)\n        {\n            logger.LogInformation(\"TailCall_Caller\");\n            if (doCW)\n            {\n                int i = await another.TailCall_Called();\n                return i;\n            }\n            return await another.TailCall_Called();\n        }\n\n\n        // calls into the 1st grain while the tail call (TailCall_Caller) is not resolved yet.\n        // if tail call optimization is working, this call should go in (the grain should be considered not executing request).\n        public Task<int> TailCall_Resolver(IConcurrentReentrantGrain another)\n        {\n            logger.LogInformation(\"TailCall_Resolver\");\n            return another.TailCall_Resolve();\n        }\n    }\n\n    [Reentrant]\n    public class ConcurrentReentrantGrain : Grain, IConcurrentReentrantGrain\n    {\n        private readonly ILogger logger;\n        private int index;\n        private TaskCompletionSource<int> resolver;\n\n        public ConcurrentReentrantGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public Task Initialize_2(int ind)\n        {\n            index = ind;\n            logger.LogInformation(\"Initialize({Index})\", index);\n            return Task.CompletedTask;\n        }\n\n        public Task<int> TailCall_Called()\n        {\n            logger.LogInformation(\"TailCall_Called\");\n            resolver = new TaskCompletionSource<int>();\n            return resolver.Task;\n        }\n\n        public Task<int> TailCall_Resolve()\n        {\n            logger.LogInformation(\"TailCall_Resolve\");\n            resolver.SetResult(7);\n            return Task.FromResult(8);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ConsumerEventCountingGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ConsumerEventCountingGrain : Grain, IConsumerEventCountingGrain\n    {\n        private int _numConsumedItems;\n        private readonly ILogger _logger;\n        private IAsyncObservable<int> _consumer;\n        private StreamSubscriptionHandle<int> _subscriptionHandle;\n        internal const string StreamNamespace = \"HaloStreamingNamespace\";\n\n        public ConsumerEventCountingGrain(ILoggerFactory loggerFactory)\n        {\n            _logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        private class AsyncObserver<T> : IAsyncObserver<T>\n        {\n            private readonly Func<T, Task> _onNext;\n\n            public AsyncObserver(Func<T, Task> onNext)\n            {\n                _onNext = onNext;\n            }\n\n            public Task OnNextAsync(T item, StreamSequenceToken token = null)\n            {\n                return _onNext(item);\n            }\n\n            public Task OnCompletedAsync()\n            {\n                return Task.CompletedTask;\n            }\n\n            public Task OnErrorAsync(Exception ex)\n            {\n                return Task.CompletedTask;\n            }\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Consumer.OnActivateAsync\");\n            _numConsumedItems = 0;\n            _subscriptionHandle = null;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Consumer.OnDeactivateAsync\");\n            await StopConsuming();\n            _numConsumedItems = 0;\n            await base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string providerToUse)\n        {\n            _logger.LogInformation(\"Consumer.BecomeConsumer\");\n            if (string.IsNullOrEmpty(providerToUse))\n            {\n                throw new ArgumentNullException(nameof(providerToUse));\n            }\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            IAsyncStream<int> stream = streamProvider.GetStream<int>(StreamNamespace, streamId);\n            _consumer = stream;\n            _subscriptionHandle = await _consumer.SubscribeAsync(new AsyncObserver<int>(EventArrived));\n        }\n\n        private Task EventArrived(int evt)\n        {\n            _numConsumedItems++;\n            _logger.LogInformation(\"Consumer.EventArrived. NumConsumed so far: {Count}\", _numConsumedItems);\n            return Task.CompletedTask;\n        }\n\n        public async Task StopConsuming()\n        {\n            _logger.LogInformation(\"Consumer.StopConsuming\");\n            if (_subscriptionHandle != null && _consumer != null)\n            {\n                await _subscriptionHandle.UnsubscribeAsync();\n                _subscriptionHandle = null;\n                _consumer = null;\n            }\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            return Task.FromResult(_numConsumedItems);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/CustomPlacementGrains.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public abstract class CustomPlacementBaseGrain : Grain, ICustomPlacementTestGrain\n    {\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n    }\n\n    [TestPlacementStrategy(CustomPlacementScenario.FixedSilo)]\n    public class CustomPlacement_FixedSiloGrain : CustomPlacementBaseGrain\n    {\n    }\n\n    [TestPlacementStrategy(CustomPlacementScenario.ExcludeOne)]\n    public class CustomPlacement_ExcludeOneGrain : CustomPlacementBaseGrain\n    {\n    }\n\n    [TestPlacementStrategy(CustomPlacementScenario.RequestContextBased)]\n    public class CustomPlacement_RequestContextBased : CustomPlacementBaseGrain\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/DeadlockGrain.cs",
    "content": "#nullable enable\n\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class DeadlockGrain\n    {\n        internal static Task CallNext(IGrainFactory grainFactory, List<(long GrainId, bool Blocking)> callChain, int currCallIndex)\n        {\n            if (currCallIndex >= callChain.Count) return Task.CompletedTask;\n            (long GrainId, bool Blocking) next = callChain[currCallIndex];\n            bool call_1 = (currCallIndex % 2) == 1; // odd (1) call 1, even (zero) - call 2.\n            if (next.Blocking)\n            {\n                IDeadlockNonReentrantGrain nextGrain = grainFactory.GetGrain<IDeadlockNonReentrantGrain>(next.GrainId);\n                if (call_1)\n                    return nextGrain.CallNext_1(callChain, currCallIndex + 1);\n                else\n                    return nextGrain.CallNext_2(callChain, currCallIndex + 1);\n            }\n            else\n            {\n                IDeadlockReentrantGrain nextGrain = grainFactory.GetGrain<IDeadlockReentrantGrain>(next.GrainId);\n                if (call_1)\n                    return nextGrain.CallNext_1(callChain, currCallIndex + 1);\n                else\n                    return nextGrain.CallNext_2(callChain, currCallIndex + 1);\n            }\n        }\n    }\n\n    public class DeadlockNonReentrantGrain : Grain, IDeadlockNonReentrantGrain\n    {\n        private readonly ILogger logger;\n        public DeadlockNonReentrantGrain(ILoggerFactory loggerFactory) => this.logger = loggerFactory.CreateLogger(this.Id);\n        private string Id { get { return string.Format(\"DeadlockNonReentrantGrain {0}\", base.IdentityString); } }\n\n        public async Task CallNext_1(List<(long GrainId, bool Blocking)> callChain, int currCallIndex)\n        {\n            using var _ = RequestContext.AllowCallChainReentrancy();\n            this.logger.LogInformation(\"Inside grain {Id} CallNext_1().\", Id);\n            await DeadlockGrain.CallNext(GrainFactory, callChain, currCallIndex);\n        }\n\n        public async Task CallNext_2(List<(long GrainId, bool Blocking)> callChain, int currCallIndex)\n        {\n            using var _ = RequestContext.AllowCallChainReentrancy();\n            this.logger.LogInformation(\"Inside grain {Id} CallNext_2().\", Id);\n            await DeadlockGrain.CallNext(GrainFactory, callChain, currCallIndex);\n        }\n    }\n\n    [Reentrant]\n    public class DeadlockReentrantGrain : Grain, IDeadlockReentrantGrain\n    {\n        private readonly ILogger logger;\n        public DeadlockReentrantGrain(ILoggerFactory loggerFactory) => this.logger = loggerFactory.CreateLogger(this.Id);\n        private string Id => $\"DeadlockReentrantGrain {base.IdentityString}\";\n\n        public async Task CallNext_1(List<(long GrainId, bool Blocking)> callChain, int currCallIndex)\n        {\n            using var _ = RequestContext.AllowCallChainReentrancy();\n            this.logger.LogInformation(\"Inside grain {Id} CallNext_1()\", Id);\n            await DeadlockGrain.CallNext(GrainFactory, callChain, currCallIndex);\n        }\n\n        public async Task CallNext_2(List<(long GrainId, bool Blocking)> callChain, int currCallIndex)\n        {\n            using var _ = RequestContext.AllowCallChainReentrancy();\n            this.logger.LogInformation(\"Inside grain {Id} CallNext_2()\", Id);\n            await DeadlockGrain.CallNext(GrainFactory, callChain, currCallIndex);\n        }\n    }\n\n    public class CallChainReentrancyGrain : Grain, ICallChainReentrancyGrain\n    {\n        private TaskCompletionSource _unblocker = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        private string Id => this.GetPrimaryKeyString();\n\n        public async Task CallChain(ICallChainObserver observer, List<(string TargetGrain, ReentrancyCallType CallType)> callChain, int callIndex, CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            var unblocker = _unblocker;\n            await observer.OnEnter(Id, callIndex);\n            try\n            {\n                if (callChain.Count == 0)\n                {\n                    return;\n                }\n\n                var op = callChain[0];\n                var target = GrainFactory.GetGrain<ICallChainReentrancyGrain>(op.TargetGrain);\n                var newChain = callChain.Skip(1).ToList();\n                var nextCallIndex = callIndex + 1;\n                switch (op.CallType)\n                {\n                    case ReentrancyCallType.Regular:\n                        await Task.WhenAny(unblocker.Task, target.CallChain(observer, newChain, nextCallIndex, cancellationToken));\n                        break;\n                    case ReentrancyCallType.AllowCallChainReentrancy:\n                        {\n                            using var _ = RequestContext.AllowCallChainReentrancy();\n                            await Task.WhenAny(unblocker.Task, target.CallChain(observer, newChain, nextCallIndex, cancellationToken));\n                            break;\n                        }\n\n                    case ReentrancyCallType.SuppressCallChainReentrancy:\n                        {\n                            using var _ = RequestContext.SuppressCallChainReentrancy();\n                            await Task.WhenAny(unblocker.Task, target.CallChain(observer, newChain, nextCallIndex, cancellationToken));\n                            break;\n                        }\n                }\n            }\n            finally\n            {\n                await observer.OnExit(Id, callIndex);\n            }\n        }\n\n        public Task UnblockWaiters(CancellationToken cancellationToken = default)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            _unblocker?.SetResult();\n            _unblocker = new(TaskCreationOptions.RunContinuationsAsynchronously);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/DerivedServiceType.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class DerivedServiceType : ServiceType, IDerivedServiceType\n    {\n        public Task<string> DerivedServiceTypeMethod1()\n        {\n            return Task.FromResult(\"DerivedServiceTypeMethod1\");\n        }\n\n        public Task<string> H1Method()\n        {\n            return Task.FromResult(\"H1\");\n        }\n\n        public Task<string> H2Method()\n        {\n            return Task.FromResult(\"H2\");\n        }\n\n        public Task<string> H3Method()\n        {\n            return Task.FromResult(\"H3\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/Directories/CustomDirectoryGrain.cs",
    "content": "using Orleans.GrainDirectory;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces.Directories;\n\nnamespace UnitTests.Grains.Directories\n{\n    [GrainDirectory(GrainDirectoryName = DIRECTORY), GrainType(DIRECTORY)]\n    public class CustomDirectoryGrain : ICustomDirectoryGrain\n    {\n        private int counter = 0;\n        private readonly SiloAddress _siloAddress;\n\n        public const string DIRECTORY = \"CustomGrainDirectory\";\n\n        public CustomDirectoryGrain(ILocalSiloDetails siloDetails)\n        {\n            _siloAddress = siloDetails.SiloAddress;\n        }\n\n        public Task<int> Ping() => Task.FromResult(++this.counter);\n\n        public Task Reset()\n        {\n            counter = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(_siloAddress.ToString());\n        }\n\n        public Task<int> ProxyPing(ICommonDirectoryGrain grain)\n        {\n            return grain.Ping();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/Directories/DefaultDirectoryGrain.cs",
    "content": "using UnitTests.GrainInterfaces.Directories;\n\nnamespace UnitTests.Grains.Directories\n{\n    [GrainType(DIRECTORY)]\n    public class DefaultDirectoryGrain : Grain, IDefaultDirectoryGrain\n    {\n        private int counter = 0;\n\n        public const string DIRECTORY = \"Default\";\n\n        public Task<int> Ping() => Task.FromResult(++this.counter);\n\n        public Task Reset()\n        {\n            counter = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public Task<int> ProxyPing(ICommonDirectoryGrain grain)\n        {\n            return grain.Ping();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/DurableJobGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.DurableJobs;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\npublic class DurableJobGrain : Grain, IDurableJobGrain, IDurableJobHandler\n{\n    private Dictionary<string, TaskCompletionSource> jobRunStatus = new();\n    private Dictionary<string, DateTimeOffset> jobExecutionTimes = new();\n    private Dictionary<string, IJobRunContext> jobContexts = new();\n    private Dictionary<string, bool> cancellationTokenStatus = new();\n    private readonly ILocalDurableJobManager _localDurableJobManager;\n    private readonly ILogger<DurableJobGrain> _logger;\n\n    public DurableJobGrain(ILocalDurableJobManager localDurableJobManager, ILogger<DurableJobGrain> logger)\n    {\n        _localDurableJobManager = localDurableJobManager;\n        _logger = logger;\n    }\n\n    public Task<bool> HasJobRan(string jobId)\n    {\n        return Task.FromResult(jobRunStatus.TryGetValue(jobId, out var taskResult) && taskResult.Task.IsCompleted);\n    }\n\n    public Task ExecuteJobAsync(IJobRunContext ctx, CancellationToken cancellationToken)\n    {\n        _logger.LogInformation(\"Job {JobId} received at {ReceivedTime}\", ctx.Job.Id, DateTime.UtcNow);\n        jobExecutionTimes[ctx.Job.Id] = DateTimeOffset.UtcNow;\n        jobContexts[ctx.Job.Id] = ctx;\n        cancellationTokenStatus[ctx.Job.Id] = cancellationToken.IsCancellationRequested;\n        jobRunStatus[ctx.Job.Id].SetResult();\n        return Task.CompletedTask;\n    }\n\n    public async Task<DurableJob> ScheduleJobAsync(string jobName, DateTimeOffset scheduledTime, IReadOnlyDictionary<string, string> metadata = null)\n    {\n        var request = new ScheduleJobRequest\n        {\n            Target = this.GetGrainId(),\n            JobName = jobName,\n            DueTime = scheduledTime,\n            Metadata = metadata\n        };\n        var job = await _localDurableJobManager.ScheduleJobAsync(request, CancellationToken.None);\n        jobRunStatus[job.Id] = new TaskCompletionSource();\n        return job;\n    }\n\n    public async Task WaitForJobToRun(string jobId)\n    {\n        if (!jobRunStatus.TryGetValue(jobId, out var taskResult))\n        {\n            // The job might not have been scheduled on this grain.\n            jobRunStatus[jobId] = new TaskCompletionSource();\n            taskResult = jobRunStatus[jobId];\n        }\n\n        await taskResult.Task;\n    }\n\n    public async Task<bool> TryCancelJobAsync(DurableJob job)\n    {\n        return await _localDurableJobManager.TryCancelDurableJobAsync(job, CancellationToken.None);\n    }\n\n    public Task<DateTimeOffset> GetJobExecutionTime(string jobId)\n    {\n        if (!jobExecutionTimes.TryGetValue(jobId, out var time))\n        {\n            throw new InvalidOperationException($\"Job {jobId} has not executed or was not scheduled on this grain.\");\n        }\n\n        return Task.FromResult(time);\n    }\n\n    public Task<IJobRunContext> GetJobRun(string jobId)\n    {\n        if (!jobContexts.TryGetValue(jobId, out var ctx))\n        {\n            throw new InvalidOperationException($\"Job {jobId} has not executed or was not scheduled on this grain.\");\n        }\n\n        return Task.FromResult(ctx);\n    }\n\n    public Task<bool> WasCancellationTokenCancelled(string jobId)\n    {\n        return Task.FromResult(cancellationTokenStatus.TryGetValue(jobId, out var cancelled) && cancelled);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/AccountGrain.cs",
    "content": "using Orleans.EventSourcing;\nusing Orleans.Providers;\nusing TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// An example of a journaled grain that models a bank account.\n    /// \n    /// Configured to use the default storage provider.\n    /// Configured to use the LogStorage consistency provider.\n    /// \n    /// This provider persists all events, and allows us to retrieve them all.\n    /// </summary>\n\n    [StorageProvider(ProviderName = \"Default\")]\n    [LogConsistencyProvider(ProviderName = \"LogStorage\")]\n\n    public class AccountGrain : JournaledGrain<AccountGrain.GrainState, Transaction>, IAccountGrain\n    {\n        /// <summary>\n        /// The state of this grain is just the current balance.\n        /// </summary>\n        [Serializable]\n        [Orleans.GenerateSerializer]\n        public class GrainState\n        {\n            [Orleans.Id(0)]\n            public uint Balance { get; set; }\n\n            public void Apply(DepositTransaction d)\n            {\n                Balance = Balance + d.DepositAmount;\n            }\n\n            public void Apply(WithdrawalTransaction d)\n            {\n                if (d.WithdrawalAmount > Balance)\n                    throw new InvalidOperationException(\"we make sure this never happens\");\n\n                Balance = Balance - d.WithdrawalAmount;\n            }\n        }\n\n        public Task<uint> Balance()\n        {\n            return Task.FromResult(State.Balance);\n        }\n\n        public Task Deposit(uint amount, Guid guid, string description)\n        {\n            RaiseEvent(new DepositTransaction() {\n                Guid = guid,\n                IssueTime = DateTime.UtcNow,\n                DepositAmount = amount,\n                Description = description\n            });\n\n            // we wait for storage ack\n            return ConfirmEvents();\n        }\n\n        public Task<bool> Withdraw(uint amount, Guid guid, string description)\n        {\n            // if the balance is too low, can't withdraw\n            // reject it immediately\n            if (State.Balance < amount)\n                return Task.FromResult(false);\n\n            // use a conditional event for withdrawal\n            // (conditional events commit only if the version hasn't already changed in the meantime)\n            // this is important so we can guarantee that we never overdraw\n            // even if racing with other clusters, of in transient duplicate grain situations\n            return RaiseConditionalEvent(new WithdrawalTransaction()\n            {\n                Guid = guid,\n                IssueTime = DateTime.UtcNow,\n                WithdrawalAmount = amount,\n                Description = description\n            });\n        }\n\n        public Task<IReadOnlyList<Transaction>> GetTransactionLog()\n        {\n            return RetrieveConfirmedEvents(0, Version);\n        }\n    }\n\n    \n    /// A variant of the same grain that does not persist the log, but only the latest grain state\n    /// (so it does not do true event sourcing). \n    [LogConsistencyProvider(ProviderName = \"StateStorage\")]\n    public class AccountGrain_PersistStateOnly : AccountGrain\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/ChatEvents.cs",
    "content": "﻿using System.Xml.Linq;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// all chat events implement this interface, to define how each event changes the XML document\n    /// </summary>\n    public interface IChatEvent\n    {\n        void Update(XDocument document);\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class CreatedEvent : IChatEvent\n    {\n        [Orleans.Id(0)]\n        public DateTime Timestamp { get; set; }\n        [Orleans.Id(1)]\n        public string Origin { get; set; }\n\n        public void Update(XDocument document)\n        {\n            document.Initialize(Timestamp, Origin);\n        }\n    }\n\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PostedEvent : IChatEvent\n    {\n        [Orleans.Id(0)]\n        public Guid Guid { get; set; }\n        [Orleans.Id(1)]\n        public string User { get; set; }\n        [Orleans.Id(2)]\n        public DateTime Timestamp { get; set; }\n        [Orleans.Id(3)]\n        public string Text { get; set; }\n\n        public void Update(XDocument document)\n        {\n            var container = document.GetPostsContainer();\n            container.Add(ChatFormat.MakePost(Guid, User, Timestamp, Text));\n            document.EnforceLimit();\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class DeletedEvent : IChatEvent\n    {\n        [Orleans.Id(0)]\n        public Guid Guid { get; set; }\n\n        public void Update(XDocument document)\n        {\n            document.FindPost(Guid.ToString())?.Remove();\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class EditedEvent : IChatEvent\n    {\n        [Orleans.Id(0)]\n        public Guid Guid { get; set; }\n        [Orleans.Id(1)]\n        public string Text { get; set; }\n\n        public void Update(XDocument document)\n        {\n            document.FindPost(Guid.ToString())?.ReplaceText(Text);\n        }\n    }\n}\n   "
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/ChatFormat.cs",
    "content": "using System.Xml.Linq;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// Encapsulate choices about how to format the chat XML document (schema).\n    /// Since a grain replays the event log whenever it is loaded,\n    /// it is possible to change this schema, without having to write an XML transformation\n    /// </summary>\n    public static class ChatFormat\n    {\n        public static void Initialize(this XDocument document, DateTime timestamp, string origin)\n        {\n            if (!document.Nodes().Any())\n            {\n                document.Add(new XComment($\"This chat room was created by {origin}\"));\n                document.Add(new XElement(\"root\",\n                    new XElement(\"created\", timestamp.ToString(\"s\", System.Globalization.CultureInfo.InvariantCulture)),\n                    new XElement(\"posts\")));\n            }\n        }\n\n        public static XElement GetPostsContainer(this XDocument document)\n        {\n            return document.Elements().Single(x => x.Name.LocalName == \"root\").Elements().Single(x => x.Name.LocalName == \"posts\");\n        }\n\n        public static XElement MakePost(Guid guid, string user, DateTime timestamp, string text)\n        {\n            return new XElement(\"post\", new XAttribute(\"id\", guid.ToString()),\n                 new XElement(\"user\", user),\n                 new XElement(\"timestamp\", timestamp.ToString(\"s\", System.Globalization.CultureInfo.InvariantCulture)),\n                 new XElement(\"text\", text)\n            );\n        }\n\n        public static XElement FindPost(this XDocument document, string guid)\n        {\n            return document.GetPostsContainer()\n                       .Elements(\"post\")\n                       .FirstOrDefault(x => x.Attribute(\"id\").Value == guid);\n        }\n\n        public static void ReplaceText(this XElement post, string text)\n        {\n            post.Element(\"text\").ReplaceAll(text);\n        }\n\n        public static void EnforceLimit(this XDocument document)\n        {\n            var container = document.GetPostsContainer();\n            if (container.Nodes().Count() > ChatFormat.MaxNumPosts)\n                container.Nodes().First().Remove();\n        }\n\n        public const int MaxNumPosts = 100;\n    }\n\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/ChatGrain.cs",
    "content": "using Orleans.EventSourcing;\nusing Orleans.Providers;\nusing System.Xml.Linq;\nusing TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// An example of a journaled grain implementing a chat.\n    /// The state of the grain is an XML document (System.Xml.Linq.XDocument).\n    ///\n    /// Configured to use the default storage provider.\n    /// Configured to use the LogStorage consistency provider.\n    ///\n    /// This means we persist all events; since events are replayed when a grain is loaded\n    /// we can change the XML schema later\n    ///\n    /// </summary>\n\n    [StorageProvider(ProviderName = \"Default\")]\n    [LogConsistencyProvider(ProviderName = \"LogStorage\")]\n    public class ChatGrain : JournaledGrain<XDocument, IChatEvent>, IChatGrain\n    {\n        // we want to ensure chats are correctly initialized when first used\n        // so we override the default activation, to insert a creation event if needed\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            // first, wait for all events to be loaded from storage so we are caught up with the latest version\n            await base.OnActivateAsync(cancellationToken);\n\n            // if the chat has not been initialized, do that now\n            if (Version == 0)\n            {\n                // we are using a conditional event (in case creation is racing with other clusters)\n                // (conditional events commit only if the version hasn't already changed in the meantime)\n                await RaiseConditionalEvent(new CreatedEvent()\n                {\n                    Timestamp = DateTime.UtcNow,\n                    Origin = typeof(ChatGrain).FullName\n                });\n            }\n        }\n\n        /// <summary>\n        /// in order to apply events correctly to the grain state, we\n        /// must override the transition function\n        /// (because an XDocument object does not have an Apply function)\n        /// </summary>\n        protected override void TransitionState(XDocument state, IChatEvent @event)\n        {\n            @event.Update(state);\n        }\n\n        public Task<XDocument> GetChat()\n        {\n            return Task.FromResult(TentativeState);\n        }\n\n        public Task Post(Guid guid, string user, string text)\n        {\n            RaiseEvent(new PostedEvent() { Guid = guid, User = user, Text = text, Timestamp = DateTime.UtcNow });\n            return Task.CompletedTask;\n        }\n\n        public Task Delete(Guid guid)\n        {\n            RaiseEvent(new DeletedEvent() { Guid = guid });\n            return Task.CompletedTask;\n        }\n\n        public Task Edit(Guid guid, string text)\n        {\n            RaiseEvent(new EditedEvent() { Guid = guid, Text = text});\n            return Task.CompletedTask;\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/CountersGrain.cs",
    "content": "using Orleans.EventSourcing;\nusing TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// An example of a journaled grain that counts statistics.\n    /// \n    /// For configuration options, see derived classes in CountersGrainVariations.cs\n    /// </summary>\n    [GrainType(\"simple-counters-grain\")]\n    public class CountersGrain : JournaledGrain<CountersGrain.GrainState>, ICountersGrain\n    {\n        /// <summary>\n        /// The state of this grain is a dictionary that keeps a count for each key.\n        /// We define this as a nested class, just for scoping convenience.\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public class GrainState\n        {\n            /// <summary>  the current count </summary>\n            [Id(0)]\n            public Dictionary<string, int> Counts { get; set; }\n\n            public GrainState()\n            {\n                Counts = new Dictionary<string, int>();\n            }\n\n            public void Apply(UpdatedEvent e)\n            {\n                if (Counts.ContainsKey(e.Key))\n                    Counts[e.Key] += e.Amount;\n                else\n                    Counts.Add(e.Key, e.Amount);\n            }\n\n            public void Apply(ResetAllEvent e)\n            {\n                Counts.Clear();\n            }\n        }\n\n        /// <summary>\n        /// An event representing a counter update\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public class UpdatedEvent\n        {\n            [Id(0)]\n            public string Key { get; set; }\n            [Id(1)]\n            public int Amount { get; set; }\n        }\n\n        /// <summary>\n        /// An event representing a reset of all counters\n        /// </summary>\n        [Serializable]\n        [GenerateSerializer]\n        public class ResetAllEvent\n        {\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            // on activation, we load lazily (do not wait until the current state is loaded).\n            return Task.CompletedTask;\n        }\n\n        public async Task Add(string key, int amount, bool wait_for_confirmation)\n        {\n            RaiseEvent(new UpdatedEvent() { Key = key, Amount = amount });\n\n            // optionally, wait until the event has been persisted to storage\n            if (wait_for_confirmation)\n                await ConfirmEvents();\n        }\n\n        public async Task Reset(bool wait_for_confirmation)\n        {\n            RaiseEvent(new ResetAllEvent());\n\n            // optionally, wait until the event has been persisted to storage\n            if (wait_for_confirmation)\n                await ConfirmEvents();\n        }\n\n        public Task ConfirmAllPreviouslyRaisedEvents()\n        {\n            return ConfirmEvents();\n        }\n            \n\n        public Task<int> GetTentativeCount(string key)\n        {\n            return Task.FromResult(TentativeState.Counts[key]);\n        }\n\n        public Task<IReadOnlyDictionary<string, int>> GetTentativeState()\n        {\n            return Task.FromResult((IReadOnlyDictionary<string, int>)TentativeState.Counts);\n        }\n\n        public Task<IReadOnlyDictionary<string, int>> GetConfirmedState()\n        {\n            return Task.FromResult((IReadOnlyDictionary<string, int>)State.Counts);\n        }\n\n\n        // some providers allow you to look at the log of events\n        public Task<IReadOnlyList<object>> GetAllEvents()\n        {\n            return RetrieveConfirmedEvents(0, Version);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/CountersGrainVariations.cs",
    "content": "﻿using Orleans.Concurrency;\nusing Orleans.Providers;\n\nnamespace TestGrains\n{\n    // we define four variants of the CountersGrain that have different configurations.\n    //\n    // all variants use the SlowMemoryStore storage provider; it delays all storage accesses by 10ms\n    // to simulate cloud storage latency\n    //\n    // the other configurations pick all four combinations of:\n    // state vs. log storage\n    // reentrant vs. non-reentrant\n\n    /// When using the StateStorage consistency provider, we persist the latest state only ... we are \n    /// not truly \"event sourcing\", as we do not want to persist \n    /// the events, but only state snapshots.\n    /// \n    /// When using the LogStorage consistency provider, we persist the log,\n    /// i.e. the complete sequence of all events\n\n    [LogConsistencyProvider(ProviderName = \"StateStorage\")]\n    [StorageProvider(ProviderName = \"SlowMemoryStore\")]\n    public class CountersGrain_StateStore_NonReentrant : CountersGrain\n    {\n    }\n\n    [LogConsistencyProvider(ProviderName = \"StateStorage\")]\n    [StorageProvider(ProviderName = \"SlowMemoryStore\")]\n    [Reentrant]\n    public class CountersGrain_StateStore_Reentrant : CountersGrain\n    {\n    }\n    \n    [LogConsistencyProvider(ProviderName = \"LogStorage\")]\n    [StorageProvider(ProviderName = \"SlowMemoryStore\")]\n    public class CountersGrain_LogStore_NonReentrant : CountersGrain\n    {\n    }\n\n    [LogConsistencyProvider(ProviderName = \"LogStorage\")]\n    [StorageProvider(ProviderName = \"SlowMemoryStore\")]\n    [Reentrant]\n    public class CountersGrain_LogStore_Reentrant : CountersGrain\n    {\n    }\n\n \n\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/PersonEvents.cs",
    "content": "using TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    // We list all the events supported by the JournaledPersonGrain \n\n    // we chose to have all these events implement the following marker interface\n    // (this is optional, but gives us a bit more typechecking)\n    public interface IPersonEvent { } \n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PersonRegistered : IPersonEvent\n    {\n        [Orleans.Id(0)]\n        public string FirstName { get; set; }\n        [Orleans.Id(1)]\n        public string LastName { get; set; }\n        [Orleans.Id(2)]\n        public GenderType Gender { get; set; }\n\n        public PersonRegistered(string firstName, string lastName, GenderType gender)\n        {\n            FirstName = firstName;\n            LastName = lastName;\n            Gender = gender;\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PersonMarried : IPersonEvent\n    {\n        [Orleans.Id(0)]\n        public Guid SpouseId { get; set; }\n        [Orleans.Id(1)]\n        public string SpouseFirstName { get; set; }\n        [Orleans.Id(2)]\n        public string SpouseLastName { get; set; }\n        \n        public PersonMarried(Guid spouseId, string spouseFirstName, string spouseLastName)\n        {\n            SpouseId = spouseId;\n            SpouseFirstName = spouseFirstName;\n            SpouseLastName = spouseLastName;\n        }\n    }\n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PersonLastNameChanged : IPersonEvent\n    {\n        [Orleans.Id(0)]\n        public string LastName { get; set; }\n\n        public PersonLastNameChanged(string lastName)\n        {\n            LastName = lastName;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/PersonGrain.cs",
    "content": "using Orleans.EventSourcing;\nusing TestGrainInterfaces;\nusing Orleans.Runtime;\n\nnamespace TestGrains\n{\n    public class PersonGrain : JournaledGrain<PersonState,IPersonEvent>, IPersonGrain\n    {\n\n        public Task RegisterBirth(PersonAttributes props)\n        {\n            if (this.State.FirstName == null)\n            {\n                RaiseEvent(new PersonRegistered(props.FirstName, props.LastName, props.Gender));\n\n                return ConfirmEvents();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public async Task Marry(IPersonGrain spouse)\n        {\n            if (State.IsMarried)\n                throw new NotSupportedException(string.Format(\"{0} is already married.\", State.LastName));\n\n            var spouseData = await spouse.GetTentativePersonalAttributes();\n\n            var events = new List<IPersonEvent>();\n\n            events.Add(new PersonMarried(spouse.GetPrimaryKey(), spouseData.FirstName, spouseData.LastName));\n\n            if (State.LastName != spouseData.LastName)\n            {\n                events.Add(new PersonLastNameChanged(spouseData.LastName));\n            }\n\n            // issue all events atomically\n            RaiseEvents(events);\n            await ConfirmEvents();\n        }\n\n        public Task ChangeLastName(string lastName)\n        {\n            RaiseEvent(new PersonLastNameChanged(lastName));\n\n            // we are not confirming this event here!\n            // therefore, the tentative state and the confirmed state can differ for some time\n\n            return Task.CompletedTask;\n        }\n\n        public Task ConfirmChanges()\n        {\n            return ConfirmEvents();\n        }\n\n        public Task<PersonAttributes> GetTentativePersonalAttributes()\n        {\n            return Task.FromResult(new PersonAttributes\n            {\n                FirstName = TentativeState.FirstName,\n                LastName = TentativeState.LastName,\n                Gender = TentativeState.Gender\n            });\n        }\n\n        public Task<PersonAttributes> GetConfirmedPersonalAttributes()\n        {\n            return Task.FromResult(new PersonAttributes\n            {\n                FirstName = State.FirstName,\n                LastName = State.LastName,\n                Gender = State.Gender\n            });\n        }\n\n        public Task<int> GetConfirmedVersion()\n        {\n            return Task.FromResult(Version);\n        }\n\n        public Task<int> GetTentativeVersion()\n        {\n            return Task.FromResult(TentativeVersion);\n        }\n\n        private int TentativeVersion\n        {\n            get\n            {\n                return Version + UnconfirmedEvents.Count();\n            }\n        }\n\n        // below is a unit test; ideally this code would be in the Tester project,\n        // but this test has to run on the grain, not the client, so we had to add it here\n\n        private static void AssertEqual<T>(T a, T b)\n        {\n            if (!Object.Equals(a, b))\n                throw new OrleansException($\"Test failed. Expected = {a}. Actual = {b}.\");\n        }\n\n\n        public async Task RunTentativeConfirmedStateTest()\n        {\n            // initially both the confirmed version and the tentative version are the same: version 0\n            AssertEqual(0, Version);\n            AssertEqual(0, TentativeVersion);\n            AssertEqual(null, State.LastName);\n            AssertEqual(null, TentativeState.LastName);\n\n            // now we change the last name\n            await ChangeLastName(\"Organa\");\n\n            // while the udpate is pending, the confirmed version and the tentative version are different\n            AssertEqual(0, Version);\n            AssertEqual(1, TentativeVersion);\n            AssertEqual(null, State.LastName);\n            AssertEqual(\"Organa\", TentativeState.LastName);\n\n            // let's wait until the update has been confirmed.\n            await ConfirmChanges();\n\n            // now the two versions are the same again\n            AssertEqual(1, Version);\n            AssertEqual(1, TentativeVersion);\n            AssertEqual(\"Organa\", State.LastName);\n            AssertEqual(\"Organa\", TentativeState.LastName);\n\n            // issue another change\n            await ChangeLastName(\"Solo\");\n\n            // again, the confirmed and the tentative versions are different\n            AssertEqual(1, Version);\n            AssertEqual(2, TentativeVersion);\n            AssertEqual(\"Organa\", State.LastName);\n            AssertEqual(\"Solo\", TentativeState.LastName);\n\n            // this time, we wait for (what should be) enough time to commit to MemoryStorage.\n            // we would never use such timing assumptions in real code. But this is a unit test.\n            for (int i = 0; i < 10; i++)\n            {\n                await Task.Delay(20);\n                if (Version == 2) break;\n            }\n\n            // now the two versions should be the same again\n            AssertEqual(2, Version);\n            AssertEqual(2, TentativeVersion);\n            AssertEqual(\"Solo\", State.LastName);\n            AssertEqual(\"Solo\", TentativeState.LastName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/PersonState.cs",
    "content": "using TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class PersonState\n    {\n        [Orleans.Id(0)]\n        public string FirstName { get; set; }\n        [Orleans.Id(1)]\n        public string LastName { get; set; }\n        [Orleans.Id(2)]\n        public GenderType Gender { get; set; }\n        [Orleans.Id(3)]\n        public bool IsMarried { get; set; }\n\n        public void Apply(PersonRegistered @event)\n        {\n            this.FirstName = @event.FirstName;\n            this.LastName = @event.LastName;\n            this.Gender = @event.Gender;\n        }\n\n        public void Apply(PersonMarried @event)\n        {\n            this.IsMarried = true;\n        }\n\n        public void Apply(PersonLastNameChanged @event)\n        {\n            this.LastName = @event.LastName;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/EventSourcing/SeatReservationGrain.cs",
    "content": "using TestGrainInterfaces;\nusing Orleans.Providers;\nusing Orleans.EventSourcing;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// An example of a journaled grain that records seat reservations.\n    /// \n    /// Configured to have one instance per cluster.\n    /// Configured to use the default storage provider.\n    /// Configured to use the StateStorage consistency provider.\n    /// \n    /// This means we persist the latest state only ... we are not truly \"event sourcing\".\n    /// It is not necessary here to persist all events, as the state already stores all the successful reservations.\n    /// \n    /// </summary>\n\n    [StorageProvider(ProviderName = \"Default\")]\n    [LogConsistencyProvider(ProviderName = \"StateStorage\")]\n    public class SeatReservationGrain : JournaledGrain<ReservationState,SeatReservation>, ISeatReservationGrain\n    {\n      \n        public async Task<bool> Reserve(int seatnumber, string userid)\n        {\n            // first, enqueue the request\n            RaiseEvent(new SeatReservation() { Seat = seatnumber, UserId = userid });\n\n            // then, wait for the request to propagate\n            await ConfirmEvents();\n\n            // we can determine if the reservation went through\n            // by re-reading it - if it is not there, it means a different user won\n            var success = (State.Reservations.ContainsKey(seatnumber)\n                                 && State.Reservations[seatnumber].UserId == userid);\n            return success;\n        }\n    }\n\n\n    /// <summary>\n    /// The state of the reservation grain\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class ReservationState\n    {\n        [Orleans.Id(0)]\n        public Dictionary<int, SeatReservation> Reservations { get; set; }\n\n        public ReservationState()\n        {\n            Reservations = new Dictionary<int, SeatReservation>();\n        }\n\n        private void Apply(SeatReservation reservation)\n        {\n            // see if this reservation targets an available seat\n            // otherwise, treat it as a no-op\n            // (this is a \"first writer wins\" conflict resolution)\n            if (!Reservations.ContainsKey(reservation.Seat))\n                Reservations.Add(reservation.Seat, reservation);\n        }\n    }\n\n    /// <summary>\n    /// The class that defines the update operation when a reservation is requested\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class SeatReservation\n    {\n        [Orleans.Id(0)]\n        public int Seat { get; set; }\n        [Orleans.Id(1)]\n        public string UserId { get; set; }\n    }\n\n\n}\n\n"
  },
  {
    "path": "test/Grains/TestGrains/ExceptionGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ExceptionGrain : Grain, IExceptionGrain\n    {\n        /// <summary>\n        /// Returns a canceled <see cref=\"Task\"/>.\n        /// </summary>\n        /// <returns>A canceled <see cref=\"Task\"/>.</returns>\n        public Task Canceled()\n        {\n            var tcs = new TaskCompletionSource<int>();\n            tcs.TrySetCanceled();\n            return tcs.Task;\n        }\n\n        public async Task ThrowsInvalidOperationException()\n        {\n            await Task.Delay(0);\n            throw new InvalidOperationException(\"Test exception\");\n        }\n\n        public Task ThrowsNullReferenceException()\n        {\n            throw new NullReferenceException(\"null null null\");\n        }\n\n        public async Task ThrowsAggregateExceptionWrappingInvalidOperationException()\n        {\n            await Task.Delay(0);\n            ThrowsInvalidOperationException().Wait();\n        }\n\n        public async Task ThrowsNestedAggregateExceptionsWrappingInvalidOperationException()\n        {\n            await Task.Delay(0);\n            ThrowsAggregateExceptionWrappingInvalidOperationException().Wait();\n        }\n\n        public Task GrainCallToThrowsInvalidOperationException(long otherGrainId)\n        {\n            var otherGrain = GrainFactory.GetGrain<IExceptionGrain>(otherGrainId);\n            return otherGrain.ThrowsInvalidOperationException();\n        }\n\n        public Task GrainCallToThrowsAggregateExceptionWrappingInvalidOperationException(long otherGrainId)\n        {\n            var otherGrain = GrainFactory.GetGrain<IExceptionGrain>(otherGrainId);\n            return otherGrain.ThrowsAggregateExceptionWrappingInvalidOperationException();\n        }\n\n        public Task ThrowsSynchronousInvalidOperationException()\n        {\n            throw new InvalidOperationException(\"Test exception\");\n        }\n\n        public Task<object> ThrowsSynchronousExceptionObjectTask()\n        {\n            throw new InvalidOperationException(\"Test exception\");\n        }\n\n        public Task ThrowsMultipleExceptionsAggregatedInFaultedTask()\n        {\n            var tcs = new TaskCompletionSource<object>();\n            tcs.SetException(new[]\n            {\n                new InvalidOperationException(\"Test exception 1\"),\n                new InvalidOperationException(\"Test exception 2\"),\n            });\n\n            return tcs.Task;\n        }\n\n        public Task ThrowsSynchronousAggregateExceptionWithMultipleInnerExceptions()\n        {\n            throw new AggregateException(\n                \"Test AggregateException message\",\n                new InvalidOperationException(\"Test exception 1\"),\n                new InvalidOperationException(\"Test exception 2\"));\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ExternalTypeGrain.cs",
    "content": "using System.Collections.Specialized;\nusing Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ExternalTypeGrain : Grain, IExternalTypeGrain\n    {\n        private readonly ILogger<ExternalTypeGrain> logger;\n\n        public ExternalTypeGrain(ILogger<ExternalTypeGrain> logger)\n        {\n            this.logger = logger;\n        }\n\n        public Task GetAbstractModel(IEnumerable<NameObjectCollectionBase> list)\n        {\n            this.logger.LogDebug(\"GetAbstractModel: Success\");\n            return Task.CompletedTask;\n        }\n\n        public Task<EnumClass> GetEnumModel()\n        {\n            return Task.FromResult( new EnumClass() { EnumsList = new List<DateTimeKind>() { DateTimeKind.Local } });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/FaultableConsumerGrain.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class FaultableConsumerGrain : Grain, IFaultableConsumerGrain\n    {\n        private IAsyncObservable<int> consumer;\n        private int eventsConsumedCount;\n        private int errorsCount;\n        private int eventsFailedCount;\n        private readonly ILogger logger;\n        private StreamSubscriptionHandle<int> consumerHandle;\n        private Stopwatch failPeriodTimer;\n        private TimeSpan failPeriod;\n\n        public FaultableConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger(\"FaultableConsumerGrain \" + base.IdentityString);\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            Reset();\n            return Task.CompletedTask;\n        }\n\n        private void Reset()\n        {\n            eventsConsumedCount = 0;\n            errorsCount = 0;\n            eventsFailedCount = 0;\n            consumerHandle = null;\n            failPeriodTimer = null;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeConsumer\");\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            consumer = streamProvider.GetStream<int>(streamNamespace, streamId);\n            consumerHandle = await consumer.SubscribeAsync(\n                OnNextAsync,\n                OnErrorAsync,\n                () =>\n                {\n                    Reset();\n                    return Task.CompletedTask;\n                });\n        }\n\n        public Task SetFailPeriod(TimeSpan failurePeriod)\n        {\n            failPeriod = failurePeriod;\n            failPeriodTimer = Stopwatch.StartNew();\n            return Task.CompletedTask;\n        }\n\n        public async Task StopConsuming()\n        {\n            logger.LogInformation(\"StopConsuming\");\n            if (consumerHandle != null)\n            {\n                await consumerHandle.UnsubscribeAsync();\n                consumerHandle = null;\n            }\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            return Task.FromResult(eventsConsumedCount);\n        }\n\n        public Task<int> GetNumberFailed()\n        {\n            return Task.FromResult(eventsFailedCount);\n        }\n\n        public Task<int> GetErrorCount()\n        {\n            return Task.FromResult(errorsCount);\n        }\n\n        public Task OnNextAsync(int item, StreamSequenceToken token = null)\n        {\n            logger.LogInformation(\"OnNextAsync(item={Item}, token={Token})\", item, token != null ? token.ToString() : \"null\");\n            if (failPeriodTimer == null)\n            {\n                eventsConsumedCount++;\n            }\n            else if(failPeriodTimer.Elapsed >= failPeriod)\n            {\n                failPeriodTimer = null;\n                eventsConsumedCount++;\n            }\n            else\n            {\n                eventsFailedCount++;\n                throw new AggregateException(\"GO WAY!\");\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            logger.LogInformation(\"OnCompletedAsync()\");\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            logger.LogInformation(ex, \"OnErrorAsync()\");\n            errorsCount++;\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/FilteredImplicitSubscriptionGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [ImplicitStreamSubscription(typeof(RedStreamNamespacePredicate))]\n    public class FilteredImplicitSubscriptionGrain : Grain, IFilteredImplicitSubscriptionGrain\n    {\n        private readonly ILogger logger;\n        private Dictionary<string, int> counters;\n\n        public FilteredImplicitSubscriptionGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{nameof(FilteredImplicitSubscriptionGrain)} {IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            var streamProvider = this.GetStreamProvider(\"SMSProvider\");\n            var streamNamespaces = new[] { \"red1\", \"red2\", \"blue3\", \"blue4\" };\n            counters = new Dictionary<string, int>();\n            foreach (var streamNamespace in streamNamespaces)\n            {\n                counters[streamNamespace] = 0;\n                var stream = streamProvider.GetStream<int>(streamNamespace, this.GetPrimaryKey());\n                await stream.SubscribeAsync(\n                    (e, t) =>\n                    {\n                        logger.LogInformation(\"Received a {StreamNamespace} event {Event}\", streamNamespace, e);\n                        counters[streamNamespace]++;\n                        return Task.CompletedTask;\n                    });\n            }\n        }\n\n        public Task<int> GetCounter(string streamNamespace)\n        {\n            return Task.FromResult(counters[streamNamespace]);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/FilteredImplicitSubscriptionWithExtensionGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [ImplicitStreamSubscription(typeof(RedStreamNamespacePredicate))]\n    public class FilteredImplicitSubscriptionWithExtensionGrain : Grain, IFilteredImplicitSubscriptionWithExtensionGrain\n    {\n        private int counter;\n        private readonly ILogger logger;\n\n        public FilteredImplicitSubscriptionWithExtensionGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{nameof(FilteredImplicitSubscriptionWithExtensionGrain)} {IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            var streamProvider = this.GetStreamProvider(\"SMSProvider\");\n\n            var streamIdentity = this.GetImplicitStreamIdentity();\n            var stream = streamProvider.GetStream<int>(streamIdentity.Namespace, streamIdentity.Guid);\n            await stream.SubscribeAsync(\n                (e, t) =>\n                {\n                    logger.LogInformation(\"Received a {StreamNamespace} event {Event}\", streamIdentity.Namespace, e);\n                    ++counter;\n                    return Task.CompletedTask;\n                });\n        }\n\n        public Task<int> GetCounter()\n        {\n            return Task.FromResult(counter);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/GeneratedEventCollectorGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Streams;\nusing TestGrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace TestGrains\n{\n    [RegexImplicitStreamSubscription(\"THIS.WONT.MATCH.ONLY.FOR.TESTING.SERIALIZATION\")]\n    [ImplicitStreamSubscription(StreamNamespace)]\n    public class GeneratedEventCollectorGrain : Grain, IGeneratedEventCollectorGrain\n    {\n        public const string StreamNamespace = \"Generated\";\n\n        private readonly ILogger logger;\n        private IAsyncStream<GeneratedEvent> stream;\n        private int accumulated;\n\n        public GeneratedEventCollectorGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            var streamProvider = this.GetStreamProvider(GeneratedStreamTestConstants.StreamProviderName);\n            stream = streamProvider.GetStream<GeneratedEvent>(StreamNamespace, this.GetPrimaryKey());\n\n            IList<StreamSubscriptionHandle<GeneratedEvent>> handles = await stream.GetAllSubscriptionHandles();\n            if (handles.Count == 0)\n            {\n                await stream.SubscribeAsync(OnNextAsync);\n            }\n            else\n            {\n                foreach (StreamSubscriptionHandle<GeneratedEvent> handle in handles)\n                {\n                    await handle.ResumeAsync(OnNextAsync);\n                }\n            }\n        }\n\n        public Task OnNextAsync(IList<SequentialItem<GeneratedEvent>> items)\n        {\n            this.accumulated += items.Count;\n            logger.LogInformation(\"Received {Count} generated event. Accumulated {Accumulated} events so far.\", items.Count, this.accumulated);\n            if (items.Last().Item.EventType == GeneratedEvent.GeneratedEventType.Fill)\n            {\n                return Task.CompletedTask;\n            }\n            var reporter = this.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n            return reporter.ReportResult(this.GetPrimaryKey(), GeneratedStreamTestConstants.StreamProviderName, StreamNamespace, this.accumulated);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GeneratedEventReporterGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    internal class GeneratedEventReporterGrain : Grain, IGeneratedEventReporterGrain\n    {\n        private readonly ILogger logger;\n\n        private Dictionary<Tuple<string, string>, Dictionary<Guid, int>> reports;\n\n        public GeneratedEventReporterGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            reports = new Dictionary<Tuple<string, string>, Dictionary<Guid, int>>();\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task ReportResult(Guid streamGuid, string streamProvider, string streamNamespace, int count)\n        {\n            Dictionary<Guid, int> counts;\n            Tuple<string, string> key = Tuple.Create(streamProvider, streamNamespace);\n            if (!reports.TryGetValue(key, out counts))\n            {\n                counts = new Dictionary<Guid, int>();\n                reports[key] = counts;\n            }\n\n            logger.LogInformation(\n                \"ReportResult. StreamProvider: {StreamProvider}, StreamNamespace: {StreamNamespace}, StreamGuid: {StreamGuid}, Count: {Count}\",\n                streamProvider,\n                streamNamespace,\n                streamGuid,\n                count);\n            counts[streamGuid] = count;\n            return Task.CompletedTask;\n        }\n\n        public Task<IDictionary<Guid, int>> GetReport(string streamProvider, string streamNamespace)\n        {\n            Dictionary<Guid, int> counts;\n            Tuple<string, string> key = Tuple.Create(streamProvider, streamNamespace);\n            if (!reports.TryGetValue(key, out counts))\n            {\n                return Task.FromResult<IDictionary<Guid, int>>(new Dictionary<Guid, int>());\n            }\n            return Task.FromResult<IDictionary<Guid, int>>(counts);\n        }\n\n        public Task Reset()\n        {\n            reports = new Dictionary<Tuple<string, string>, Dictionary<Guid, int>>();\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> IsLocatedOnSilo(SiloAddress siloAddress)\n        {\n            return Task.FromResult(RuntimeIdentity == siloAddress.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GeneratedStreamTestConstants.cs",
    "content": "﻿namespace UnitTests.Grains\n{\n    public class GeneratedStreamTestConstants\n    {\n        public static Guid ReporterId = new Guid(\"f83247af-c14d-422c-8141-74d7a79717dc\");\n        public const string StreamProviderName = \"GeneratedStreamProvider\";\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestDerivedDerivedGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GeneratorTestDerivedDerivedGrain : GeneratorTestDerivedGrain2, IGeneratorTestDerivedDerivedGrain\n    {\n        public Task<string> StringNConcat(string[] strArray)\n        {\n            string strAll = string.Empty;\n            foreach(string str in strArray)\n                strAll = string.Concat(strAll, str);\n\n            return Task.FromResult(strAll);\n        }\n\n        public Task<string> StringReplace(ReplaceArguments strs)\n        {\n            myGrainString = myGrainString.Replace(strs.OldString, strs.NewString);\n            return Task.FromResult(myGrainString);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain : Grain, IGeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain\n    {\n        public Task<int> Echo(int x)\n        {\n            return Task.FromResult(x);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    // uncomment the following class to verify correct code generation for #1349\n    // (do so once code generation succeeds)\n    // NOTE: also uncomment the corresponding test in Tester/GeneratorGrainTests.cs\n\n    public class GeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain : Grain, IGeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain\n    {\n        public Task<int> Echo(int x)\n        {\n            return Task.FromResult(x);\n        }\n\n        public Task<Tuple<string, int>> MultipleParameterEcho(string s, int x)\n        {\n            return Task.FromResult(new Tuple<string,int>(s,x));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestDerivedGrain1.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GeneratorTestDerivedGrain1 : GeneratorTestGrain, IGeneratorTestDerivedGrain1\n    {\n        public Task<byte[]> ByteAppend(byte[] data)\n        {\n            byte[] tmp = new byte[myGrainBytes.Length + data.Length];\n            myGrainBytes.CopyTo(tmp, 0);\n            data.CopyTo(tmp, myGrainBytes.Length);\n            myGrainBytes = tmp;\n            //RaiseStateUpdateEvent();\n            return Task.FromResult(myGrainBytes);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestDerivedGrain2.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GeneratorTestDerivedGrain2 : GeneratorTestGrain, IGeneratorTestDerivedGrain2\n    {\n        public Task<string> StringConcat(string str1, string str2, string str3)\n        {\n            return Task.FromResult((string.Concat(str1, str2, str3)));\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/GeneratorTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GeneratorTestGrain : Grain, IGeneratorTestGrain\n    {\n        protected byte[] myGrainBytes;\n        protected string myGrainString = string.Empty;\n        protected ReturnCode myCode;\n\n        public Task<byte[]> ByteSet(byte[] data)\n        {\n            myGrainBytes = (byte[])data.Clone();\n            //RaiseStateUpdateEvent();\n            return Task.FromResult(myGrainBytes);\n        }\n\n        public Task StringSet(string str)\n        {\n            myGrainString = str;\n            //RaiseStateUpdateEvent();\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> StringIsNullOrEmpty()\n        {\n            return Task.FromResult(string.IsNullOrEmpty(myGrainString));\n        }\n\n        public Task<MemberVariables> GetMemberVariables()\n        {\n            MemberVariables memberVar = new MemberVariables(myGrainBytes, myGrainString, myCode);\n            return Task.FromResult(memberVar);\n        }\n\n        public Task SetMemberVariables(MemberVariables x)\n        {\n            myGrainBytes = (byte[])x.byteArray.Clone();\n            myGrainString = x.stringVar;\n            myCode = x.code;\n            //RaiseStateUpdateEvent();\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GenericGrains.cs",
    "content": "using System.Globalization;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Channels;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Providers;\nusing Orleans.Timers;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class SimpleGenericGrainState<T>\n    {\n        [Id(0)]\n        public T A { get; set; }\n        [Id(1)]\n        public T B { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class SimpleGenericGrain1<T> : Grain<SimpleGenericGrainState<T>>, ISimpleGenericGrain1<T>\n    {\n        public Task<T> GetA()\n        {\n            return Task.FromResult(State.A);\n        }\n\n        public Task SetA(T a)\n        {\n            State.A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(T b)\n        {\n            State.B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetAxB()\n        {\n            string retValue = string.Format(\"{0}x{1}\", State.A, State.B);\n            return Task.FromResult(retValue);\n        }\n\n        public Task<string> GetAxB(T a, T b)\n        {\n            string retValue = string.Format(\"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n    }\n\n    [StorageProvider(ProviderName = \"AzureStore\")]\n    public class SimpleGenericGrainUsingAzureStorageAndLongGrainName<T> : Grain<SimpleGenericGrainState<T>>, ISimpleGenericGrainUsingAzureStorageAndLongGrainName<T>\n    {\n        public async Task<T> EchoAsync(T entity)\n        {\n            State.A = entity;\n            await WriteStateAsync();\n            return entity;\n        }\n\n        public async Task ClearState()\n        {\n            await ClearStateAsync();\n        }\n    }\n\n    [StorageProvider(ProviderName = \"AzureStore\")]\n    public class TinyNameGrain<T> : Grain<SimpleGenericGrainState<T>>, ITinyNameGrain<T>\n    {\n        public async Task<T> EchoAsync(T entity)\n        {\n            State.A = entity;\n            await WriteStateAsync();\n            return entity;\n        }\n\n        public async Task ClearState()\n        {\n            await ClearStateAsync();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class SimpleGenericGrainUState<U>\n    {\n        [Id(0)]\n        public U A { get; set; }\n        [Id(1)]\n        public U B { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class SimpleGenericGrainU<U> : Grain<SimpleGenericGrainUState<U>>, ISimpleGenericGrainU<U>\n    {\n        public Task<U> GetA()\n        {\n            return Task.FromResult(State.A);\n        }\n\n        public Task SetA(U a)\n        {\n            State.A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(U b)\n        {\n            State.B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetAxB()\n        {\n            string retValue = string.Format(\"{0}x{1}\", State.A, State.B);\n            return Task.FromResult(retValue);\n        }\n\n        public Task<string> GetAxB(U a, U b)\n        {\n            string retValue = string.Format(\"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class SimpleGenericGrain2State<T, U>\n    {\n        [Id(0)]\n        public T A { get; set; }\n        [Id(1)]\n        public U B { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class SimpleGenericGrain2<T, U> : Grain<SimpleGenericGrain2State<T, U>>, ISimpleGenericGrain2<T, U>\n    {\n        public Task<T> GetA()\n        {\n            return Task.FromResult(State.A);\n        }\n\n        public Task SetA(T a)\n        {\n            State.A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(U b)\n        {\n            State.B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetAxB()\n        {\n            string retValue = string.Format(CultureInfo.InvariantCulture, \"{0}x{1}\", State.A, State.B);\n            return Task.FromResult(retValue);\n        }\n\n        public Task<string> GetAxB(T a, U b)\n        {\n            string retValue = string.Format(CultureInfo.InvariantCulture, \"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n    }\n\n    public class GenericGrainWithNoProperties<T> : Grain, IGenericGrainWithNoProperties<T>\n    {\n        public Task<string> GetAxB(T a, T b)\n        {\n            string retValue = string.Format(\"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n    }\n    public class GrainWithNoProperties : Grain, IGrainWithNoProperties\n    {\n        public Task<string> GetAxB(int a, int b)\n        {\n            string retValue = string.Format(\"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class IGrainWithListFieldsState\n    {\n        [Id(0)]\n        public IList<string> Items { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class GrainWithListFields : Grain<IGrainWithListFieldsState>, IGrainWithListFields\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (State.Items == null)\n                State.Items = new List<string>();\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task AddItem(string item)\n        {\n            State.Items.Add(item);\n            return Task.CompletedTask;\n        }\n\n        public Task<IList<string>> GetItems()\n        {\n            return Task.FromResult((State.Items));\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericGrainWithListFieldsState<T>\n    {\n        [Id(0)]\n        public IList<T> Items { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class GenericGrainWithListFields<T> : Grain<GenericGrainWithListFieldsState<T>>, IGenericGrainWithListFields<T>\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (State.Items == null)\n                State.Items = new List<T>();\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task AddItem(T item)\n        {\n            State.Items.Add(item);\n            return Task.CompletedTask;\n        }\n\n        public Task<IList<T>> GetItems()\n        {\n            return Task.FromResult(State.Items);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericReaderWriterState<T>\n    {\n        [Id(0)]\n        public T Value { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericReader2State<TOne, TTwo>\n    {\n        [Id(0)]\n        public TOne Value1 { get; set; }\n        [Id(1)]\n        public TTwo Value2 { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericReaderWriterGrain2State<TOne, TTwo>\n    {\n        [Id(0)]\n        public TOne Value1 { get; set; }\n        [Id(1)]\n        public TTwo Value2 { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericReader3State<TOne, TTwo, TThree>\n    {\n        [Id(0)]\n        public TOne Value1 { get; set; }\n        [Id(1)]\n        public TTwo Value2 { get; set; }\n        [Id(2)]\n        public TThree Value3 { get; set; }\n    }\n\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class GenericReaderWriterGrain1<T> : Grain<GenericReaderWriterState<T>>, IGenericReaderWriterGrain1<T>\n    {\n        public Task SetValue(T value)\n        {\n            State.Value = value;\n            return Task.CompletedTask;\n        }\n\n        public Task<T> GetValue()\n        {\n            return Task.FromResult(State.Value);\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class GenericReaderWriterGrain2<TOne, TTwo> : Grain<GenericReaderWriterGrain2State<TOne, TTwo>>, IGenericReaderWriterGrain2<TOne, TTwo>\n    {\n        public Task SetValue1(TOne value)\n        {\n            State.Value1 = value;\n            return Task.CompletedTask;\n        }\n        public Task SetValue2(TTwo value)\n        {\n            State.Value2 = value;\n            return Task.CompletedTask;\n        }\n\n        public Task<TOne> GetValue1()\n        {\n            return Task.FromResult(State.Value1);\n        }\n\n        public Task<TTwo> GetValue2()\n        {\n            return Task.FromResult(State.Value2);\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class GenericReaderWriterGrain3<TOne, TTwo, TThree> : Grain<GenericReader3State<TOne, TTwo, TThree>>, IGenericReaderWriterGrain3<TOne, TTwo, TThree>\n    {\n        public Task SetValue1(TOne value)\n        {\n            State.Value1 = value;\n            return Task.CompletedTask;\n        }\n        public Task SetValue2(TTwo value)\n        {\n            State.Value2 = value;\n            return Task.CompletedTask;\n        }\n        public Task SetValue3(TThree value)\n        {\n            State.Value3 = value;\n            return Task.CompletedTask;\n        }\n\n        public Task<TThree> GetValue3()\n        {\n            return Task.FromResult(State.Value3);\n        }\n\n        public Task<TOne> GetValue1()\n        {\n            return Task.FromResult(State.Value1);\n        }\n\n        public Task<TTwo> GetValue2()\n        {\n            return Task.FromResult(State.Value2);\n        }\n    }\n\n    public class BasicGenericGrain<T, U> : Grain, IBasicGenericGrain<T, U>\n    {\n        private T _a;\n        private U _b;\n\n        public Task<T> GetA()\n        {\n            return Task.FromResult(_a);\n        }\n\n        public Task<string> GetAxB()\n        {\n            string retValue = string.Format(CultureInfo.InvariantCulture, \"{0}x{1}\", _a, _b);\n            return Task.FromResult(retValue);\n        }\n\n        public Task<string> GetAxB(T a, U b)\n        {\n            string retValue = string.Format(CultureInfo.InvariantCulture, \"{0}x{1}\", a, b);\n            return Task.FromResult(retValue);\n        }\n\n        public Task SetA(T a)\n        {\n            this._a = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(U b)\n        {\n            this._b = b;\n            return Task.CompletedTask;\n        }\n    }\n\n    public class HubGrain<TKey, T1, T2> : Grain, IHubGrain<TKey, T1, T2>\n    {\n        public virtual Task Bar(TKey key, T1 message1, T2 message2)\n        {\n            throw new System.NotImplementedException();\n        }\n    }\n\n    public class EchoHubGrain<TKey, TMessage> : HubGrain<TKey, TMessage, TMessage>, IEchoHubGrain<TKey, TMessage>\n    {\n        private int _x;\n\n        public Task Foo(TKey key, TMessage message, int x)\n        {\n            _x = x;\n            return Task.CompletedTask;\n        }\n\n        public override Task Bar(TKey key, TMessage message1, TMessage message2)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetX()\n        {\n            return Task.FromResult(_x);\n        }\n    }\n\n    public class EchoGenericChainGrain<T> : Grain, IEchoGenericChainGrain<T>\n    {\n        public async Task<T> Echo(T item)\n        {\n            long pk = this.GetPrimaryKeyLong();\n            var otherGrain = GrainFactory.GetGrain<ISimpleGenericGrain1<T>>(pk);\n            await otherGrain.SetA(item);\n            return await otherGrain.GetA();\n        }\n\n        public async Task<T> Echo2(T item)\n        {\n            long pk = this.GetPrimaryKeyLong() + 1;\n            var otherGrain = GrainFactory.GetGrain<IEchoGenericChainGrain<T>>(pk);\n            return await otherGrain.Echo(item);\n        }\n\n        public async Task<T> Echo3(T item)\n        {\n            long pk = this.GetPrimaryKeyLong() + 1;\n            var otherGrain = GrainFactory.GetGrain<IEchoGenericChainGrain<T>>(pk);\n            return await otherGrain.Echo2(item);\n        }\n\n        public async Task<T> Echo4(T item)\n        {\n            long pk = this.GetPrimaryKeyLong() + 1;\n            var otherGrain = GrainFactory.GetGrain<ISimpleGenericGrain1<T>>(pk);\n            await otherGrain.SetA(item);\n            return await otherGrain.GetA();\n        }\n\n        public async Task<T> Echo5(T item)\n        {\n            long pk = this.GetPrimaryKeyLong() + 1;\n            var otherGrain = GrainFactory.GetGrain<IEchoGenericChainGrain<T>>(pk);\n            return await otherGrain.Echo4(item);\n        }\n\n        public async Task<T> Echo6(T item)\n        {\n            long pk = this.GetPrimaryKeyLong() + 1;\n            var otherGrain = GrainFactory.GetGrain<IEchoGenericChainGrain<T>>(pk);\n            return await otherGrain.Echo5(item);\n        }\n    }\n\n    public class NonGenericBaseGrain : Grain, INonGenericBase\n    {\n        public Task Ping()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    public class Generic1ArgumentGrain<T> : NonGenericBaseGrain, IGeneric1Argument<T>\n    {\n        public Task<T> Ping(T t)\n        {\n            return Task.FromResult(t);\n        }\n    }\n\n    public class Generic1ArgumentDerivedGrain<T> : NonGenericBaseGrain, IGeneric1Argument<T>\n    {\n        public Task<T> Ping(T t)\n        {\n            return Task.FromResult(t);\n        }\n    }\n\n    public class Generic2ArgumentGrain<T, U> : Grain, IGeneric2Arguments<T, U>\n    {\n        public Task<Tuple<T, U>> Ping(T t, U u)\n        {\n            return Task.FromResult(new Tuple<T, U>(t, u));\n        }\n\n        public Task Ping()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    public class Generic2ArgumentsDerivedGrain<T, U> : NonGenericBaseGrain, IGeneric2Arguments<T, U>\n    {\n        public Task<Tuple<T, U>> Ping(T t, U u)\n        {\n            return Task.FromResult(new Tuple<T, U>(t, u));\n        }\n    }\n\n    public class DbGrain<T> : Grain, IDbGrain<T>\n    {\n        private T _value;\n\n        public Task SetValue(T value)\n        {\n            _value = value;\n            return Task.CompletedTask;\n        }\n\n        public Task<T> GetValue()\n        {\n            return Task.FromResult(_value);\n        }\n    }\n\n    [Reentrant]\n    public class PingSelfGrain<T> : IGrainBase, IGenericPingSelf<T>\n    {\n        private readonly ILogger logger;\n        private T _lastValue;\n        private readonly ITimerRegistry _timerRegistry;\n\n        public PingSelfGrain(ILogger<PingSelfGrain<T>> logger, IGrainContext context, ITimerRegistry timerRegistry)\n        {\n            this.logger = logger;\n            this.GrainContext = context;\n            _timerRegistry = timerRegistry;\n        }\n\n        public IGrainContext GrainContext { get; set; }\n\n        public Task<T> Ping(T t)\n        {\n            _lastValue = t;\n            return Task.FromResult(t);\n        }\n\n        public Task<T> PingOther(IGenericPingSelf<T> target, T t)\n        {\n            return target.Ping(t);\n        }\n\n\n        public Task<T> PingSelf(T t)\n        {\n            return PingOther(this, t);\n        }\n\n\n        public Task<T> PingSelfThroughOther(IGenericPingSelf<T> target, T t)\n        {\n            return target.PingOther(this, t);\n        }\n\n        public Task ScheduleDelayedPing(IGenericPingSelf<T> target, T t, TimeSpan delay)\n        {\n            _timerRegistry.RegisterGrainTimer<object>(\n                GrainContext,\n                (_, cancellationToken) =>\n                {\n                    this.logger.LogDebug(\"***Timer fired for pinging {0}***\", target.GetPrimaryKey());\n                    return target.Ping(t);\n                },\n                null,\n                new() { DueTime = delay, Period = Timeout.InfiniteTimeSpan });\n            return Task.CompletedTask;\n        }\n\n        public Task<T> GetLastValue()\n        {\n            return Task.FromResult(_lastValue);\n        }\n\n        public async Task ScheduleDelayedPingToSelfAndDeactivate(IGenericPingSelf<T> target, T t, TimeSpan delay)\n        {\n            await target.ScheduleDelayedPing(this, t, delay);\n            this.DeactivateOnIdle();\n        }\n\n        public Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger.LogDebug(\"***Activating*** {0}\", this.GetPrimaryKey());\n            return Task.CompletedTask;\n        }\n\n        public Task OnDeactivateAsync(DeactivationReason deactivationReason, CancellationToken cancellationToken)\n        {\n            this.logger.LogDebug(\"***Deactivating*** {0}\", this.GetPrimaryKey());\n            return Task.CompletedTask;\n        }\n    }\n\n    public class LongRunningTaskGrain<T> : Grain, ILongRunningTaskGrain<T>\n    {\n        private readonly Channel<(Guid CallId, Exception Error)> _cancelledCalls = Channel.CreateUnbounded<(Guid, Exception)>();\n        private T lastValue;\n\n        public async Task GrainCancellationTokenCallbackThrow(GrainCancellationToken ct, Guid callId)\n        {\n            ct.CancellationToken.Register(() =>\n            {\n                _cancelledCalls.Writer.TryWrite((callId, null));\n                throw new InvalidOperationException(\"From cancellation token callback\");\n            });\n\n            await Task.Delay(TimeSpan.FromSeconds(10), ct.CancellationToken);\n        }\n\n        public async Task CancellationTokenCallbackThrow(CancellationToken ct, Guid callId)\n        {\n            ct.Register(() =>\n            {\n                _cancelledCalls.Writer.TryWrite((callId, null));\n                throw new InvalidOperationException(\"From cancellation token callback\");\n            });\n\n            await Task.Delay(TimeSpan.FromSeconds(10), ct);\n        }\n\n        public Task<T> GetLastValue()\n        {\n            return Task.FromResult(lastValue);\n        }\n\n        public async Task<bool> CallOtherCancellationTokenCallbackResolve(ILongRunningTaskGrain<T> target, Guid callId)\n        {\n            using var cts = new CancellationTokenSource();\n            var grainTask = target.CancellationTokenCallbackResolve(cts.Token, callId);\n            cts.CancelAfter(300);\n            return await grainTask;\n        }\n\n        public async Task<bool> CallOtherGrainCancellationTokenCallbackResolve(ILongRunningTaskGrain<T> target, Guid callId)\n        {\n            using var cts = new GrainCancellationTokenSource();\n            var grainTask = target.GrainCancellationTokenCallbackResolve(cts.Token, callId);\n            await Task.Delay(300);\n            await cts.Cancel();\n            return await grainTask;\n        }\n\n        public Task<bool> GrainCancellationTokenCallbackResolve(GrainCancellationToken tc, Guid callId)\n        {\n            var tcs = new TaskCompletionSource<bool>();\n            var orleansTs = TaskScheduler.Current;\n            tc.CancellationToken.Register(() =>\n            {\n                if (TaskScheduler.Current != orleansTs)\n                {\n                    var exception = new Exception(\"Callback executed on wrong thread\");\n                    _cancelledCalls.Writer.TryWrite((callId, exception));\n                    tcs.SetException(exception);\n                }\n                else\n                {\n                    _cancelledCalls.Writer.TryWrite((callId, null));\n                    tcs.SetResult(true);\n                }\n            });\n\n            return tcs.Task;\n        }\n\n        public Task<bool> CancellationTokenCallbackResolve(CancellationToken tc, Guid callId)\n        {\n            var tcs = new TaskCompletionSource<bool>();\n            var orleansTs = TaskScheduler.Current;\n            tc.Register(() =>\n            {\n                if (TaskScheduler.Current != orleansTs)\n                {\n                    var exception = new Exception(\"Callback executed on wrong thread\");\n                    _cancelledCalls.Writer.TryWrite((callId, exception));\n                    tcs.SetException(exception);\n                }\n                else\n                {\n                    _cancelledCalls.Writer.TryWrite((callId, null));\n                    tcs.SetResult(true);\n                }\n            });\n\n            return tcs.Task;\n        }\n\n        public async Task<T> CallOtherLongRunningTask(ILongRunningTaskGrain<T> target, T t, TimeSpan delay)\n        {\n            return await target.LongRunningTask(t, delay);\n        }\n\n        public async Task<T> FanOutOtherLongRunningTask(ILongRunningTaskGrain<T> target, T t, TimeSpan delay, int degreeOfParallelism)\n        {\n            var promises = Enumerable\n                .Range(0, degreeOfParallelism)\n                .Select(_ => target.LongRunningTask(t, delay))\n                .ToList();\n\n            await Task.WhenAll(promises);\n            return t;\n        }\n\n        public async Task CallOtherLongRunningTaskGrainCancellation(ILongRunningTaskGrain<T> target, GrainCancellationToken tc, TimeSpan delay, Guid callId)\n        {\n            await target.LongWaitGrainCancellation(tc, delay, callId);\n        }\n\n        public async Task CallOtherLongRunningTask(ILongRunningTaskGrain<T> target, CancellationToken tc, TimeSpan delay, Guid callId)\n        {\n            await target.LongWait(tc, delay, callId);\n        }\n\n        public async Task CallOtherLongRunningTaskWithLocalCancellation(ILongRunningTaskGrain<T> target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId)\n        {\n            using var cts = new CancellationTokenSource();\n            var task = target.LongWait(cts.Token, delay, callId);\n            cts.CancelAfter(delayBeforeCancel);\n            await task;\n        }\n\n        public async Task CallOtherLongRunningTaskWithLocalGrainCancellationToken(ILongRunningTaskGrain<T> target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId)\n        {\n            using var cts = new GrainCancellationTokenSource();\n            var task = target.LongWaitGrainCancellation(cts.Token, delay, callId);\n            await Task.Delay(delayBeforeCancel);\n            await cts.Cancel();\n            await task;\n        }\n\n        public Task LongWaitGrainCancellationInterleaving(GrainCancellationToken tc, TimeSpan delay, Guid callId) => LongWaitGrainCancellation(tc, delay, callId);\n\n        public async Task LongWaitGrainCancellation(GrainCancellationToken ct, TimeSpan delay, Guid callId)\n        {\n            try\n            {\n                await Task.Delay(delay, ct.CancellationToken);\n            }\n            catch (OperationCanceledException)\n            {\n                _cancelledCalls.Writer.TryWrite((callId, null));\n                throw;\n            }\n        }\n\n        public Task LongWaitInterleaving(CancellationToken ct, TimeSpan delay, Guid callId) => LongWait(ct, delay, callId);\n        public async Task LongWait(CancellationToken ct, TimeSpan delay, Guid callId)\n        {\n            try\n            {\n                await Task.Delay(delay, ct);\n            }\n            catch (OperationCanceledException)\n            {\n                _cancelledCalls.Writer.TryWrite((callId, null));\n                throw;\n            }\n        }\n\n        public async Task<T> LongRunningTask(T t, TimeSpan delay)\n        {\n            await Task.Delay(delay);\n            this.lastValue = t;\n            return await Task.FromResult(t);\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public async Task<string> GetRuntimeInstanceIdWithDelay(TimeSpan delay)\n        {\n            await Task.Delay(delay);\n            return RuntimeIdentity;\n        }\n\n        public async IAsyncEnumerable<(Guid CallId, Exception Error)> WatchCancellations([EnumeratorCancellation] CancellationToken cancellationToken = default)\n        {\n            await foreach (var item in _cancelledCalls.Reader.ReadAllAsync(cancellationToken))\n            {\n                yield return item;\n            }\n        }\n    }\n\n    public class GenericGrainWithContraints<A, B, C>: Grain, IGenericGrainWithConstraints<A, B, C>\n        where A : ICollection<B>, new()\n        where B : struct\n        where C : class\n    {\n        private A collection;\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            collection = new A();\n            return Task.CompletedTask;\n        }\n\n        [Alias(\"GenericGrainWithConstraints.GetCount\")]\n        public Task<int> GetCount() { return Task.FromResult(collection.Count); }\n\n        public Task Add(B item)\n        {\n            collection.Add(item);\n            return Task.CompletedTask;\n        }\n\n        public Task<C> RoundTrip(C value)\n        {\n            return Task.FromResult(value);\n        }\n    }\n\n    public class NonGenericCastableGrain : Grain, INonGenericCastableGrain, ISomeGenericGrain<string>, IIndependentlyConcretizedGenericGrain<string>, IIndependentlyConcretizedGrain\n    {\n        public Task DoSomething() {\n            return Task.CompletedTask;\n        }\n\n        public Task<string> Hello() {\n            return Task.FromResult(\"Hello!\");\n        }\n    }\n\n    public class GenericCastableGrain<T> : Grain, IGenericCastableGrain<T>, INonGenericCastGrain\n    {\n        public Task<string> Hello() {\n            return Task.FromResult(\"Hello!\");\n        }\n    }\n\n    public class GenericArrayRegisterGrain<T> : Grain, IGenericArrayRegisterGrain<T>\n    {\n        private T[] _value;\n        public Task<T[]> Get() => Task.FromResult(_value);\n        public Task Set(T[] value)\n        {\n            _value = value;\n            return Task.CompletedTask;\n        }\n    }\n\n    public class IndependentlyConcretizedGenericGrain : Grain, IIndependentlyConcretizedGenericGrain<string>, IIndependentlyConcretizedGrain\n    {\n        public Task<string> Hello() => Task.FromResult(\"I have been independently concretized!\");\n    }\n\n    public interface IReducer<TState, TAction>\n    {\n        Task<TState> Handle(TState prevState, TAction act);\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Reducer1Action { }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Reducer2Action { }\n\n    public class Reducer1 : IReducer<string, Reducer1Action>\n    {\n        public Task<string> Handle(string prevState, Reducer1Action act) => Task.FromResult(prevState + act);\n    }\n\n    public class Reducer2 : IReducer<int, Reducer2Action>\n    {\n        public Task<int> Handle(int prevState, Reducer2Action act) => Task.FromResult(prevState + act.ToString().Length);\n    }\n\n    public interface IUnmanagedArgGrain<T> : IGrainWithGuidKey where T : unmanaged\n    {\n        ValueTask<T> Echo(T value);\n        ValueTask<U> EchoNonNullable<U>(U value) where U : notnull;\n        ValueTask<U> EchoReference<U>(U value) where U : class;\n        ValueTask<U> EchoValue<U>(U value) where U : struct;\n    }\n\n    public class UnmanagedArgGrain<T> : IUnmanagedArgGrain<T> where T : unmanaged\n    {\n        public ValueTask<T> Echo(T value) => new(value);\n        public ValueTask<U> EchoNonNullable<U>(U value)  where U : notnull => new(value);\n        public ValueTask<U> EchoReference<U>(U value) where U : class => new(value);\n        public ValueTask<U> EchoValue<U>(U value) where U : struct => new(value);\n    }\n\n    public interface IReducerGameGrain<TState, TAction> : IGrainWithStringKey\n    {\n        Task<TState> Go(TState prevState, TAction act);\n    }\n\n    public class ReducerGameGrain<TState, TAction> : Grain, IReducerGameGrain<TState, TAction>\n    {\n        private readonly IReducer<TState, TAction> reducer;\n\n        public ReducerGameGrain(IReducer<TState, TAction> reducer)\n        {\n            this.reducer = reducer;\n        }\n\n        public Task<TState> Go(TState prevState, TAction act) => this.reducer.Handle(prevState, act);\n    }\n\n    namespace Generic.EdgeCases\n    {\n        using System.Linq;\n        using UnitTests.GrainInterfaces.Generic.EdgeCases;\n\n        public abstract class BasicGrain : Grain\n        {\n            public Task<string> Hello()\n            {\n                return Task.FromResult(\"Hello!\");\n            }\n\n            public Task<string[]> ConcreteGenArgTypeNames()\n            {\n                var grainType = GetImmediateSubclass(this.GetType());\n                return Task.FromResult(grainType.GetGenericArguments().Select(t => t.FullName).ToArray());\n            }\n\n            private Type GetImmediateSubclass(Type subject)\n            {\n                if(subject.BaseType == typeof(BasicGrain))\n                {\n                    return subject;\n                }\n\n                return GetImmediateSubclass(subject.BaseType);\n            }\n        }\n\n        public class PartiallySpecifyingGrain<T> : BasicGrain, IGrainWithTwoGenArgs<string, T>\n        { }\n\n        public class GrainWithPartiallySpecifyingInterface<T> : BasicGrain, IPartiallySpecifyingInterface<T>\n        { }\n\n        public class GrainSpecifyingSameGenArgTwice<T> : BasicGrain, IGrainReceivingRepeatedGenArgs<T, T>\n        { }\n\n        public class SpecifyingRepeatedGenArgsAmongstOthers<T1, T2> : BasicGrain, IReceivingRepeatedGenArgsAmongstOthers<T2, T1, T2>\n        { }\n\n        public class GrainForTestingCastingBetweenInterfacesWithReusedGenArgs : BasicGrain, ISpecifyingGenArgsRepeatedlyToParentInterface<bool>\n        { }\n\n        public class SpecifyingSameGenArgsButRearranged<T1, T2> : BasicGrain, IReceivingRearrangedGenArgs<T2, T1>\n        { }\n\n        public class GrainForTestingCastingWithRearrangedGenArgs<T1, T2> : BasicGrain, ISpecifyingRearrangedGenArgsToParentInterface<T1, T2>\n        { }\n\n        public class GrainWithGenArgsUnrelatedToFullySpecifiedGenericInterface<T1, T2> : BasicGrain, IArbitraryInterface<T1, T2>, IInterfaceUnrelatedToConcreteGenArgs<float>\n        { }\n\n        public class GrainSupplyingFurtherSpecializedGenArg<T> : BasicGrain, IInterfaceTakingFurtherSpecializedGenArg<List<T>>\n        { }\n\n        public class GrainSupplyingGenArgSpecializedIntoArray<T> : BasicGrain, IInterfaceTakingFurtherSpecializedGenArg<T[]>\n        { }\n\n        public class GrainForCastingBetweenInterfacesOfFurtherSpecializedGenArgs<T>\n            : BasicGrain, IAnotherReceivingFurtherSpecializedGenArg<List<T>>, IYetOneMoreReceivingFurtherSpecializedGenArg<T[]>\n        { }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GetGrainGrains.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class BaseGrain : Grain, IBase\n    {\n        public const string GrainPrefix = \"UnitTests.Grains.Base\";\n\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(true);\n        }\n    }\n\n    public class DerivedFromBaseGrain : Grain, IDerivedFromBase\n    {\n        public Task<bool> Bar()\n        {\n            return Task.FromResult(true);\n        }\n\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(false);\n        }\n    }\n\n    public class BaseGrain1 : Grain, IBase1\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(false);\n        }\n    }\n\n    public class BaseGrain1And2 : Grain, IBase3, IBase2\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(false);\n        }\n\n        public Task<bool> Bar()\n        {\n            return Task.FromResult(true);\n        }\n    }\n\n    public class Base4 : Grain, IBase4\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(false);\n        }\n    }\n\n    public class Base4_ : Grain, IBase4\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(true);\n        }\n    }\n\n    public class StringGrain : Grain, IStringGrain\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(true);\n        }\n    }\n\n    public class GuidGrain : Grain, IGuidGrain\n    {\n        public Task<bool> Foo()\n        {\n            return Task.FromResult(true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GrainInterfaceHierarchyGrains.cs",
    "content": "﻿using TestGrainInterfaces;\n\nnamespace TestGrains\n{\n    public class DoSomethingEmptyGrain : Grain, IDoSomethingEmptyGrain\n    {\n        private int A;\n\n        public Task<string> DoIt()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n    }\n\n    public class DoSomethingEmptyWithMoreGrain : Grain, IDoSomethingEmptyWithMoreGrain\n    {\n        private int A;\n\n        public Task<string> DoIt()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task<string> DoMore()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n    }\n\n    public class DoSomethingWithMoreGrain : Grain, IDoSomethingWithMoreGrain\n    {\n        private int A;\n        private int B;\n\n        public Task<string> DoIt()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task<string> DoThat()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n        \n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n\n        public Task SetB(int b)\n        {\n            B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementB()\n        {\n            B++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetB()\n        {\n            return Task.FromResult(B);\n        }\n\n    }\n\n    public class DoSomethingWithMoreEmptyGrain : Grain, IDoSomethingWithMoreEmptyGrain\n    {\n        private int A;\n\n        public Task<string> DoIt()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n\n        public Task<string> DoMore()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n    }\n\n\n\n    public class DoSomethingCombinedGrain : Grain, IDoSomethingCombinedGrain\n    {\n        private int A;\n        private int B;\n        private int C;\n\n        public Task<string> DoIt()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task<string> DoMore()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task<string> DoThat()\n        {\n            return Task.FromResult(GetType().Name);\n        }\n\n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n\n        public Task SetB(int b)\n        {\n            B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementB()\n        {\n            B++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetB()\n        {\n            return Task.FromResult(B);\n        }\n\n        public Task SetC(int c)\n        {\n            C = c;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementC()\n        {\n            C++;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetC()\n        {\n            return Task.FromResult(C);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GrainService/GrainServiceTestGrain.cs",
    "content": "using Tester;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class GrainServiceTestGrain : Grain, IGrainServiceTestGrain\n    {\n        private readonly ITestGrainServiceClient testGrainServiceClient;\n\n        public GrainServiceTestGrain(ITestGrainServiceClient testGrainServiceClient)\n        {\n            this.testGrainServiceClient = testGrainServiceClient;\n        }\n\n        public Task<string> GetHelloWorldUsingCustomService()\n        {\n            return this.testGrainServiceClient.GetHelloWorldUsingCustomService();\n        }\n\n        public Task<bool> CallHasStarted()\n        {\n            return this.testGrainServiceClient.HasStarted();\n        }\n\n        public Task<bool> CallHasStartedInBackground()\n        {\n            return this.testGrainServiceClient.HasStartedInBackground();\n        }\n\n        public Task<bool> CallHasInit()\n        {\n            return this.testGrainServiceClient.HasInit();\n        }\n\n        public Task<string> GetServiceConfigProperty()\n        {\n            return this.testGrainServiceClient.GetServiceConfigProperty();\n        }\n\n        public Task<string> EchoViaExtension(string what)\n        {\n            return this.testGrainServiceClient.EchoViaExtension(what);\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/GrainService/ITestGrainService.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Services;\n\nnamespace Tester\n{\n    public interface ITestGrainService : IGrainService\n    {\n        Task<string> GetHelloWorldUsingCustomService(GrainReference reference);\n        Task<bool> HasStarted();\n        Task<bool> HasStartedInBackground();\n        Task<bool> HasInit();\n        Task<string> GetServiceConfigProperty();\n    }\n\n    public interface ITestGrainServiceClient : IGrainServiceClient<ITestGrainService>\n    {\n        Task<string> GetHelloWorldUsingCustomService();\n        Task<bool> HasStarted();\n        Task<bool> HasStartedInBackground();\n        Task<bool> HasInit();\n        Task<string> GetServiceConfigProperty();\n        Task<string> EchoViaExtension(string what);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitStreamTestConstants.cs",
    "content": "namespace UnitTests.Grains\n{\n    public sealed class ImplicitStreamTestConstants\n    {\n        public const string StreamProviderName = \"ImplicitStreamProvider\";\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitSubscriptionCounterGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [ImplicitStreamSubscription(nameof(IImplicitSubscriptionCounterGrain))]\n    public class ImplicitSubscriptionCounterGrain : Grain<ImplicitSubscriptionCounterGrain.MyState>, IImplicitSubscriptionCounterGrain, IStreamSubscriptionObserver\n    {\n        private readonly ILogger logger;\n        private bool deactivateOnEvent;\n\n        [GenerateSerializer]\n        public class MyState\n        {\n            [Id(0)]\n            public int EventCounter { get; set; }\n            [Id(1)]\n            public int ErrorCounter { get; set; }\n            [Id(2)]\n            public StreamSequenceToken Token { get; set; }\n        }\n\n        public ImplicitSubscriptionCounterGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{nameof(ImplicitSubscriptionCounterGrain)} {this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation(\"OnActivateAsync\");\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation($\"OnDeactivateAsync: {reason}\");\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task<int> GetErrorCounter() => Task.FromResult(this.State.ErrorCounter);\n\n        public Task<int> GetEventCounter() => Task.FromResult(this.State.EventCounter);\n\n        public Task Deactivate()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public async Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            this.logger.LogInformation($\"OnSubscribed: {handleFactory.ProviderName}/{handleFactory.StreamId}\");\n\n            await handleFactory.Create<byte[]>().ResumeAsync(OnNext, OnError, OnCompleted, this.State.Token);\n\n            async Task OnNext(byte[] value, StreamSequenceToken token)\n            {\n                this.logger.LogInformation(\"Received: [{Value} {Token}]\", value, token);\n                this.State.EventCounter++;\n                this.State.Token = token;\n                await this.WriteStateAsync();\n                if (this.deactivateOnEvent)\n                {\n                    this.DeactivateOnIdle();\n                }\n            }\n\n            async Task OnError(Exception ex)\n            {\n                this.logger.LogError(\"Error: {Exception}\", ex);\n                this.State.ErrorCounter++;\n                await this.WriteStateAsync();\n            }\n\n            Task OnCompleted() => Task.CompletedTask;\n        }\n\n        public Task DeactivateOnEvent(bool deactivate)\n        {\n            this.deactivateOnEvent = deactivate;\n            return Task.CompletedTask;\n        }\n    }\n\n    [ImplicitStreamSubscription(\"FastSlowImplicitSubscriptionCounterGrain\")]\n    public class FastImplicitSubscriptionCounterGrain : ImplicitSubscriptionCounterGrain, IFastImplicitSubscriptionCounterGrain\n    {\n        public FastImplicitSubscriptionCounterGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n    }\n\n    [ImplicitStreamSubscription(\"FastSlowImplicitSubscriptionCounterGrain\")]\n    public class SlowImplicitSubscriptionCounterGrain : ImplicitSubscriptionCounterGrain, ISlowImplicitSubscriptionCounterGrain\n    {\n        public SlowImplicitSubscriptionCounterGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await Task.Delay(10_000);\n            await base.OnActivateAsync(cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitSubscriptionWithKeyTypeGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [ImplicitStreamSubscription(nameof(IImplicitSubscriptionLongKeyGrain))]\n    public class ImplicitSubscriptionWithLongKeyGrain : Grain, IImplicitSubscriptionLongKeyGrain\n    {\n        private readonly ILogger logger;\n        private int value;\n\n        public ImplicitSubscriptionWithLongKeyGrain(ILoggerFactory loggerFactory)\n        {\n            logger = loggerFactory.CreateLogger($\"{nameof(ImplicitSubscriptionWithLongKeyGrain)} {IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            value = 0;\n            IStreamProvider streamProvider = this.GetStreamProvider(ImplicitStreamTestConstants.StreamProviderName);\n            IAsyncStream<int> stream = streamProvider.GetStream<int>(nameof(IImplicitSubscriptionLongKeyGrain), this.GetPrimaryKeyLong());\n\n            await stream.SubscribeAsync(\n                (data, token) =>\n                {\n                    logger.LogInformation(\"Received event {Event}\", data);\n                    value = data;\n                    return Task.CompletedTask;\n                });\n        }\n\n        public Task<int> GetValue() => Task.FromResult(value);\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitSubscription_NonTransientError_RecoverableStream_CollectorGrain.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Placement;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing TestGrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace TestGrains\n{\n    [ImplicitStreamSubscription(StreamNamespace)]\n    [PreferLocalPlacement]\n    public class ImplicitSubscription_NonTransientError_RecoverableStream_CollectorGrain : Grain<StreamCheckpoint<int>>, IGeneratedEventCollectorGrain\n    {\n        public const string StreamNamespace = \"NonTransientError_RecoverableStream\";\n     \n        // grain instance state\n        private readonly ILogger logger;\n        private IAsyncStream<GeneratedEvent> stream;\n\n        private class FaultsState\n        {\n            public bool FaultCleared { get; set; }\n        }\n        private static readonly ConcurrentDictionary<Guid, FaultsState> FaultInjectionTracker = new ConcurrentDictionary<Guid, FaultsState>();\n        private FaultsState myFaults;\n        private FaultsState Faults { get { return myFaults ?? (myFaults = FaultInjectionTracker.GetOrAdd(this.GetPrimaryKey(), key => new FaultsState())); } }\n\n        public ImplicitSubscription_NonTransientError_RecoverableStream_CollectorGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger(\"RecoverableStreamCollectorGrain \" + base.IdentityString);\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            await ReadStateAsync();\n\n            Guid streamGuid = this.GetPrimaryKey();\n            if (State.StreamGuid != streamGuid)\n            {\n                State.StreamGuid = streamGuid;\n                State.StreamNamespace = StreamNamespace;\n                await WriteStateAsync();\n            }\n\n            var streamProvider = this.GetStreamProvider(GeneratedStreamTestConstants.StreamProviderName);\n            stream = streamProvider.GetStream<GeneratedEvent>(State.StreamNamespace, State.StreamGuid);\n\n            await stream.SubscribeAsync(OnNextAsync, OnErrorAsync, State.RecoveryToken);\n        }\n\n        private async Task OnNextAsync(GeneratedEvent evt, StreamSequenceToken sequenceToken)\n        {\n            // Ignore duplicates\n            if (State.IsDuplicate(sequenceToken))\n            {\n                logger.LogInformation(\"Received duplicate event. StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n                return;\n            }\n\n            logger.LogInformation(\"Received event. StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n\n            // We will only update the start token if this is the first event we're processed\n            // In that case, we'll want to save the start token in case something goes wrong.\n            if (State.TryUpdateStartToken(sequenceToken))\n            {\n                await WriteStateAsync();\n            }\n\n            // fault on 33rd event until fault is cleared\n            if (State.Accumulator == 32 && !Faults.FaultCleared)\n            {\n                InjectFault();\n            }\n\n            State.Accumulator++;\n            State.LastProcessedToken = sequenceToken;\n            if (evt.EventType != GeneratedEvent.GeneratedEventType.Report)\n            {\n                // every 10 events, checkpoint our grain state\n                if (State.Accumulator%10 != 0) return;\n                logger.LogInformation(\n                    \"Checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}\",\n                    State.StreamGuid,\n                    State.StreamNamespace,\n                    sequenceToken,\n                    State.Accumulator);\n                await WriteStateAsync();\n                return;\n            }\n\n            logger.LogInformation(\n                \"Final checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\",\n                State.StreamGuid,\n                State.StreamNamespace,\n                sequenceToken,\n                State.Accumulator);\n            await WriteStateAsync();\n            var reporter = GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n            await reporter.ReportResult(this.GetPrimaryKey(), GeneratedStreamTestConstants.StreamProviderName, StreamNamespace, State.Accumulator);\n        }\n\n        private Task OnErrorAsync(Exception ex)\n        {\n            logger.LogInformation(\n                ex,\n                \"Received an error on stream. StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}\",\n                State.StreamGuid,\n                State.StreamNamespace);\n            Faults.FaultCleared = true;\n            return Task.CompletedTask;\n        }\n\n        private void InjectFault()\n        {\n            logger.LogInformation(\n                \"InjectingFault: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\",\n                State.StreamGuid,\n                State.StreamNamespace,\n                State.RecoveryToken,\n                State.Accumulator);\n            throw new ApplicationException(\"Injecting Fault\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitSubscription_RecoverableStream_CollectorGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Providers;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Streams;\nusing TestGrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace TestGrains\n{\n    [ImplicitStreamSubscription(StreamNamespace)]\n    [StorageProvider(ProviderName = StorageProviderName)]\n    public class ImplicitSubscription_RecoverableStream_CollectorGrain : Grain<StreamCheckpoint<int>>, IGeneratedEventCollectorGrain\n    {\n        public const string StreamNamespace = \"RecoverableStream\";\n        public const string StorageProviderName = \"AzureStorage\";\n        \n        // grain instance state\n        private readonly ILogger logger;\n        private IAsyncStream<GeneratedEvent> stream;\n\n        public ImplicitSubscription_RecoverableStream_CollectorGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            await ReadStateAsync();\n\n            Guid streamGuid = this.GetPrimaryKey();\n            if (State.StreamGuid != streamGuid)\n            {\n                State.StreamGuid = streamGuid;\n                State.StreamNamespace = StreamNamespace;\n                await WriteStateAsync();\n            }\n\n            var streamProvider = this.GetStreamProvider(GeneratedStreamTestConstants.StreamProviderName);\n            stream = streamProvider.GetStream<GeneratedEvent>(State.StreamNamespace, State.StreamGuid);\n\n            await stream.SubscribeAsync(OnNextAsync, OnErrorAsync, State.RecoveryToken);\n        }\n\n        private async Task OnNextAsync(GeneratedEvent evt, StreamSequenceToken sequenceToken)\n        {\n\n            // ignore duplicates\n            if (State.IsDuplicate(sequenceToken))\n            {\n                logger.LogInformation(\"Received duplicate event. StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n                return;\n            }\n\n            logger.LogInformation(\"Received event. StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n\n            // We will only update the start token if this is the first event we're processed\n            // In that case, we'll want to save the start token in case something goes wrong.\n            if (State.TryUpdateStartToken(sequenceToken))\n            {\n                await WriteStateAsync();\n            }\n\n            State.Accumulator++;\n            State.LastProcessedToken = sequenceToken;\n            if (evt.EventType != GeneratedEvent.GeneratedEventType.Report)\n            {\n                // every 10 events, checkpoint our grain state\n                if (State.Accumulator % 10 != 0) return;\n                logger.LogInformation(\"Checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\", State.StreamGuid, State.StreamNamespace, sequenceToken, State.Accumulator);\n                await WriteStateAsync();\n                return;\n            }\n            logger.LogInformation(\"Final checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\", State.StreamGuid, State.StreamNamespace, sequenceToken, State.Accumulator);\n            await WriteStateAsync();\n            var reporter = GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n            await reporter.ReportResult(this.GetPrimaryKey(), GeneratedStreamTestConstants.StreamProviderName, StreamNamespace, State.Accumulator);\n        }\n\n        private Task OnErrorAsync(Exception ex)\n        {\n            logger.LogInformation(ex, \"Received an error on stream. StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}\", State.StreamGuid, State.StreamNamespace);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ImplicitSubscription_TransientError_RecoverableStream_CollectorGrain.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Placement;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing TestGrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace TestGrains\n{\n    [ImplicitStreamSubscription(StreamNamespace)]\n    [PreferLocalPlacement]\n    public class ImplicitSubscription_TransientError_RecoverableStream_CollectorGrain : Grain<StreamCheckpoint<int>>, IGeneratedEventCollectorGrain\n    {\n        public const string StreamNamespace = \"TransientError_RecoverableStream\";\n\n        // Fault injection\n        // Simulate simple transient failures.\n        // Each failure occures once.\n        // We place failures at key points to test recoverabilty.\n        // - On first grain activation.\n        // - after activation, but before storing start token.\n        // - after start token has been stored, but befor it's message has been processed.\n        // - mid stream processing (33rd message in this test, but realy depends on stream)\n        // - last message in stream.\n        private class FireOnNthTry\n        {\n            private readonly int attemptToFireOn;\n            private int tries;\n\n            public FireOnNthTry(int attemptToFireOn)\n            {\n                this.attemptToFireOn = attemptToFireOn;\n            }\n\n            public bool TryFire(Action fireAction)\n            {\n                tries++;\n                if (tries != attemptToFireOn) return false;\n                fireAction();\n                return true;\n            }\n        }\n\n        private class FaultsState\n        {\n            public readonly FireOnNthTry onActivateFault;\n            public readonly FireOnNthTry onFirstMessageFault;\n            public readonly FireOnNthTry onFirstMessageProcessedFault;\n            public readonly FireOnNthTry on33rdMessageFault;\n            public readonly FireOnNthTry onLastMessageFault;\n\n            public FaultsState()\n            {\n                onActivateFault = new FireOnNthTry(1);\n                onFirstMessageFault = new FireOnNthTry(1);\n                onFirstMessageProcessedFault = new FireOnNthTry(1);\n                on33rdMessageFault = new FireOnNthTry(33);\n                onLastMessageFault = new FireOnNthTry(1);\n            }\n        }\n\n        private static readonly ConcurrentDictionary<Guid, FaultsState> FaultInjectionTracker = new ConcurrentDictionary<Guid, FaultsState>();\n\n        private FaultsState myFaults;\n        private FaultsState Faults { get { return myFaults ?? (myFaults = FaultInjectionTracker.GetOrAdd(this.GetPrimaryKey(), key => new FaultsState())); } }\n     \n        // grain instance state\n        private readonly ILogger logger;\n        private IAsyncStream<GeneratedEvent> stream;\n\n        public ImplicitSubscription_TransientError_RecoverableStream_CollectorGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            Faults.onActivateFault.TryFire(() => InjectFault(activating: true));\n            await ReadStateAsync();\n\n            Guid streamGuid = this.GetPrimaryKey();\n            if (State.StreamGuid != streamGuid)\n            {\n                State.StreamGuid = streamGuid;\n                State.StreamNamespace = StreamNamespace;\n                await WriteStateAsync();\n            }\n\n            var streamProvider = this.GetStreamProvider(GeneratedStreamTestConstants.StreamProviderName);\n            stream = streamProvider.GetStream<GeneratedEvent>(State.StreamNamespace, State.StreamGuid);\n            foreach (StreamSubscriptionHandle<GeneratedEvent> handle in await stream.GetAllSubscriptionHandles())\n            {\n                await handle.ResumeAsync(OnNextAsync, OnErrorAsync, State.RecoveryToken);\n            }\n        }\n\n        private async Task OnNextAsync(GeneratedEvent evt, StreamSequenceToken sequenceToken)\n        {\n\n            // ignore duplicates\n            if (State.IsDuplicate(sequenceToken))\n            {\n                logger.LogInformation(\"Received duplicate event.  StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n                return;\n            }\n\n            logger.LogInformation(\"Received event.  StreamGuid: {StreamGuid}, SequenceToken: {SequenceToken}\", State.StreamGuid, sequenceToken);\n\n            // Increment accumulator before trying to inject fault\n            State.Accumulator++;\n\n            // We will only update the start token if this is the first event we're processed\n            // In that case, we'll want to save the start token in case something goes wrong.\n            if (State.TryUpdateStartToken(sequenceToken))\n            {\n                Faults.onFirstMessageFault.TryFire(InjectFault);\n                await WriteStateAsync();\n            }\n\n            State.LastProcessedToken = sequenceToken;\n            if (evt.EventType != GeneratedEvent.GeneratedEventType.Report)\n            {\n                Faults.onFirstMessageProcessedFault.TryFire(InjectFault);\n                Faults.on33rdMessageFault.TryFire(InjectFault);\n                // every 10 events, checkpoint our grain state\n                if (State.Accumulator%10 != 0) return;\n                logger.LogInformation(\n                    \"Checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\",\n                    State.StreamGuid,\n                    State.StreamNamespace,\n                    sequenceToken,\n                    State.Accumulator);\n                await WriteStateAsync();\n                return;\n            }\n            Faults.onLastMessageFault.TryFire(InjectFault);\n            logger.LogInformation(\n                \"Final checkpointing: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\",\n                State.StreamGuid,\n                State.StreamNamespace,\n                sequenceToken,\n                State.Accumulator);\n            await WriteStateAsync();\n            var reporter = GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n            await reporter.ReportResult(this.GetPrimaryKey(), GeneratedStreamTestConstants.StreamProviderName, StreamNamespace, State.Accumulator);\n        }\n\n        private Task OnErrorAsync(Exception ex)\n        {\n            logger.LogInformation(ex, \"Received an error on stream. StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}\", State.StreamGuid, State.StreamNamespace);\n            return Task.CompletedTask;\n        }\n\n        private void InjectFault() => InjectFault(activating: false);\n\n        private void InjectFault(bool activating)\n        {\n            logger.LogInformation(\n                \"InjectingFault: StreamGuid: {StreamGuid}, StreamNamespace: {StreamNamespace}, SequenceToken: {SequenceToken}, Accumulator: {Accumulator}.\",\n                State.StreamGuid,\n                State.StreamNamespace,\n                State.RecoveryToken,\n                State.Accumulator);\n\n            if (!activating)\n            {\n                DeactivateOnIdle(); // kill grain and reaload from checkpoint\n            }\n\n            throw new ApplicationException(\"Injecting Fault\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/InitialStateGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class Initialized_State\n    {\n        [Id(0)]\n        public List<string> Names { get; set; }\n        public Initialized_State()\n        {\n            Names = new List<string>();\n        }\n    }\n\n    public class InitialStateGrain : Grain<Initialized_State>, IInitialStateGrain\n    {\n        public Task<List<string>> GetNames()\n        {\n            return Task.FromResult(State.Names);\n        }\n\n        public Task AddName(string name)\n        {\n            State.Names.Add(name);\n            return WriteStateAsync();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/KeyExtensionTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class KeyExtensionTestGrain : Grain, IKeyExtensionTestGrain\n    {\n        private readonly Guid uniqueId = Guid.NewGuid();\n\n        public Task<IKeyExtensionTestGrain> GetGrainReference()\n        {\n            return Task.FromResult(this.AsReference<IKeyExtensionTestGrain>());\n        }\n\n        public Task<string> GetActivationId()\n        {\n            return Task.FromResult(uniqueId.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/LivenessTestGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class LivenessTestGrain : Grain, ILivenessTestGrain\n    {\n        private string label;\n        private readonly ILogger logger;\n        private Guid uniqueId;\n\n        public LivenessTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (this.GetPrimaryKeyLong() == -2)\n                throw new ArgumentException(\"Primary key cannot be -2 for this test case\");\n\n            uniqueId = Guid.NewGuid();\n            label = this.GetPrimaryKeyLong().ToString();\n            logger.LogInformation(\"OnActivateAsync\");\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"!!! OnDeactivateAsync\");\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task<string> GetLabel()\n        {\n            return Task.FromResult(label);\n        }\n\n        public Task SetLabel(string label)\n        {\n            this.label = label;\n            logger.LogInformation(\"SetLabel {Label} received\", label);\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer()\n        {\n            logger.LogInformation(\"StartTimer.\");\n            this.RegisterGrainTimer(TimerTick, TimeSpan.Zero, TimeSpan.FromSeconds(10));\n            \n            return Task.CompletedTask;\n        }\n\n        private Task TimerTick()\n        {\n            logger.LogInformation(\"TimerTick.\");\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public Task<string> GetUniqueId()\n        {\n            return Task.FromResult(uniqueId.ToString());\n        }\n\n        public Task<ILivenessTestGrain> GetGrainReference()\n        {\n            return Task.FromResult(this.AsReference<ILivenessTestGrain>());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/LogTestGrain.cs",
    "content": "using Orleans.EventSourcing;\nusing UnitTests.GrainInterfaces;\n\nnamespace TestGrains\n{\n    /// <summary>\n    /// A class used by many different unit tests for the various log consistency providers.\n    /// The content of this class is pretty arbitrary and messy;\n    /// (don't use this as an introduction on how to use JournaledGrain)\n    /// it started from SimpleGrain, but a lot of stuff got added over time \n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class MyGrainState\n    {\n        [Orleans.Id(0)]\n        public int A;\n        [Orleans.Id(1)]\n        public int B;\n        [Orleans.Id(2)]\n        public Dictionary<string, int> Reservations;\n\n        public MyGrainState()\n        {\n            Reservations = new Dictionary<string, int>();\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"A={0} B={1} R={{{2}}}\", A, B, string.Join(\", \", Reservations.Select(kvp => string.Format(\"{0}:{1}\", kvp.Key, kvp.Value))));\n        }\n\n        // all the update operations are listed here\n        public void Apply(UpdateA x) { A = x.Val; }\n        public void Apply(UpdateB x) { B = x.Val; }\n        public void Apply(IncrementA x) { A++; }\n\n        public void Apply(AddReservation x) { Reservations[x.Val.ToString()] = x.Val; }\n        public void Apply(RemoveReservation x) { Reservations.Remove(x.Val.ToString()); }\n    }\n \n\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class UpdateA {[Orleans.Id(0)] public int Val; }\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class UpdateB  {[Orleans.Id(0)] public int Val; }\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class IncrementA  {[Orleans.Id(0)] public int Val; }\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class AddReservation {[Orleans.Id(0)] public int Val; }\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class RemoveReservation {[Orleans.Id(0)] public int Val; }\n\n\n\n    /// <summary>\n    /// A grain used for testing log-consistency providers.\n    /// has two fields A, B that can be updated or incremented;\n    /// and a dictionary of reservations that can be added and removed\n    /// We subclass this to create variations for all storage providers\n    /// </summary>\n    public abstract class LogTestGrain : JournaledGrain<MyGrainState,object>, UnitTests.GrainInterfaces.ILogTestGrain\n    {\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask; // do not wait for initial load\n        }\n\n        public async Task SetAGlobal(int x)\n        {\n            RaiseEvent(new UpdateA() { Val = x });\n            await ConfirmEvents();\n        }\n\n        public async Task<Tuple<int, bool>> SetAConditional(int x)\n        {\n            int version = this.Version;\n            bool success = await RaiseConditionalEvent(new UpdateA() { Val = x });\n            return new Tuple<int, bool>(version, success);\n        }\n\n        public Task SetALocal(int x)\n        {\n            RaiseEvent(new UpdateA() { Val = x });\n            return Task.CompletedTask;\n        }\n        public async Task SetBGlobal(int x)\n        {\n            RaiseEvent(new UpdateB() { Val = x });\n            await ConfirmEvents();\n        }\n\n        public Task SetBLocal(int x)\n        {\n            RaiseEvent(new UpdateB() { Val = x });\n            return Task.CompletedTask;\n        }\n\n        public async Task IncrementAGlobal()\n        {\n            RaiseEvent(new IncrementA());\n            await ConfirmEvents();\n        }\n\n        public Task IncrementALocal()\n        {\n            RaiseEvent(new IncrementA());\n            return Task.CompletedTask;\n\n        }\n\n        public async Task<int> GetAGlobal()\n        {\n            await RefreshNow();\n            return State.A;\n        }\n\n        public Task<int> GetALocal()\n        {\n            return Task.FromResult(TentativeState.A);\n        }\n\n        public async Task<AB> GetBothGlobal()\n        {\n            await RefreshNow();\n            return new AB() { A = State.A, B = State.B };\n        }\n\n        public Task<AB> GetBothLocal()\n        {\n            return Task.FromResult(new AB() { A = TentativeState.A, B = TentativeState.B });\n        }\n\n        public Task AddReservationLocal(int val)\n        {\n            RaiseEvent(new AddReservation() { Val = val });\n            return Task.CompletedTask;\n\n        }\n        public Task RemoveReservationLocal(int val)\n        {\n            RaiseEvent(new RemoveReservation() { Val = val });\n            return Task.CompletedTask;\n\n        }\n        public async Task<int[]> GetReservationsGlobal()\n        {\n            await RefreshNow();\n            return State.Reservations.Values.ToArray();\n        }\n\n        public Task SynchronizeGlobalState()\n        {\n            return RefreshNow();\n        }\n\n        public Task<int> GetConfirmedVersion()\n        {\n            return Task.FromResult(this.Version);\n        }\n\n        public async Task<KeyValuePair<int, object>> Read()\n        {\n            await RefreshNow();\n            return new KeyValuePair<int, object>(Version, State);\n        }\n        public async Task<bool> Update(IReadOnlyList<object> updates, int expectedversion)\n        {\n            if (expectedversion > Version)\n                await RefreshNow();\n            if (expectedversion != Version)\n                return false;\n            return await RaiseConditionalEvents(updates);\n        }\n\n        public Task Deactivate()\n        {\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task Clear()\n        {\n            return ClearLogAsync();\n        }\n\n        public Task<IReadOnlyList<object>> GetEventLog() {\n            return this.RetrieveConfirmedEvents(0, Version);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/LogTestGrainVariations.cs",
    "content": "using Orleans.Providers;\nusing Orleans.Serialization;\nusing UnitTests.GrainInterfaces;\n\nnamespace TestGrains\n{\n    // variations of the log consistent grain are used to test a variety of provider and configurations\n\n    // use azure storage and a explicitly configured consistency provider\n    [StorageProvider(ProviderName = \"AzureStore\")]\n    [LogConsistencyProvider(ProviderName = \"StateStorage\")]\n    public class LogTestGrainSharedStateStorage : LogTestGrain\n    {\n    }\n\n    // use azure storage and a explicitly configured consistency provider\n    [StorageProvider(ProviderName = \"AzureStore\")]\n    [LogConsistencyProvider(ProviderName = \"LogStorage\")]\n    public class LogTestGrainSharedLogStorage : LogTestGrain\n    {\n    }\n\n    // use the default storage provider as the shared storage\n    public class LogTestGrainDefaultStorage : LogTestGrain\n    {\n    }\n\n    // use MemoryStore (which uses GSI grain)\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class LogTestGrainMemoryStorage : LogTestGrain\n    {\n    }\n\n    // use the explictly specified \"CustomStorage\" log-consistency provider with symmetric access from all clusters\n    [LogConsistencyProvider(ProviderName = \"CustomStorage\")]\n    public class LogTestGrainCustomStorage : LogTestGrain,\n        Orleans.EventSourcing.CustomStorage.ICustomStorageInterface<MyGrainState, object>\n    {\n\n        // we use another impl of this grain as the primary.\n        private ILogTestGrain storagegrain;\n\n        private ILogTestGrain GetStorageGrain()\n        {\n            if (storagegrain == null)\n            {\n                storagegrain = GrainFactory.GetGrain<ILogTestGrain>(this.GetPrimaryKeyLong(), \"TestGrains.LogTestGrainSharedStateStorage\");\n            }\n            return storagegrain;\n        }\n \n\n        public Task<bool> ApplyUpdatesToStorage(IReadOnlyList<object> updates, int expectedversion)\n        {\n            return GetStorageGrain().Update(updates, expectedversion);\n        }\n\n        public async Task<KeyValuePair<int, MyGrainState>> ReadStateFromStorage()\n        {\n            var kvp = await GetStorageGrain().Read();\n            return new KeyValuePair<int, MyGrainState>(kvp.Key, (MyGrainState)kvp.Value);\n        }\n\n        public Task ClearStoredState()\n        {\n            return GetStorageGrain().Clear();\n        }\n    }\n\n    // use the explictly specified \"CustomStorage\" log-consistency provider with access from primary cluster only\n    [LogConsistencyProvider(ProviderName = \"CustomStoragePrimaryCluster\")]\n    public class LogTestGrainCustomStoragePrimaryCluster : LogTestGrain,\n        Orleans.EventSourcing.CustomStorage.ICustomStorageInterface<MyGrainState, object>\n    {\n        private readonly DeepCopier<MyGrainState> copier;\n\n        // we use fake in-memory state as the storage\n        private MyGrainState state;\n        private int version;\n\n        public LogTestGrainCustomStoragePrimaryCluster(DeepCopier<MyGrainState> copier)\n        {\n            this.copier = copier;\n        }\n\n        // simulate an async call during activation. This caused deadlock in earlier version,\n        // so I add it here to catch regressions.\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await Task.Run(async () =>\n            {\n                await Task.Delay(10);\n            });\n        }\n\n\n        public Task<bool> ApplyUpdatesToStorage(IReadOnlyList<object> updates, int expectedversion)\n        {\n            if (state == null)\n            {\n                state = new MyGrainState();\n                version = 0;\n            }\n\n            if (expectedversion != version)\n                return Task.FromResult(false);\n\n            foreach (var u in updates)\n            {\n                this.TransitionState(state, u);\n                version++;\n            }\n\n            return Task.FromResult(true);\n        }\n\n        public Task<KeyValuePair<int, MyGrainState>> ReadStateFromStorage()\n        {\n            if (state == null)\n            {\n                state = new MyGrainState();\n                version = 0;\n            }\n            return Task.FromResult(new KeyValuePair<int, MyGrainState>(version, this.copier.Copy(state)));\n        }\n\n        public Task ClearStoredState()\n        {\n            state = null;\n            version = 0;\n            return Task.CompletedTask;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MessageSerializationGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime.Placement;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class MessageSerializationGrain : Grain, IMessageSerializationGrain\n    {\n        private IMessageSerializationGrain grainOnOtherSilo;\n\n        public Task SendUnserializable(UnserializableType input) => Task.CompletedTask;\n        public Task SendUndeserializable(UndeserializableType input) => Task.CompletedTask;\n        public Task<UnserializableType> GetUnserializable() => Task.FromResult(new UnserializableType());\n        public Task<UndeserializableType> GetUndeserializable() => Task.FromResult(new UndeserializableType());\n\n        public async Task SendUndeserializableToOtherSilo()\n        {\n            var otherGrain = await GetGrainOnOtherSilo();\n\n            // Message that grain in a way which should fail.\n            await otherGrain.SendUndeserializable(new UndeserializableType(35));\n        }\n\n        public async Task GetUnserializableFromOtherSilo()\n        {\n            var otherGrain = await GetGrainOnOtherSilo();\n\n            // Message that grain in a way which should fail.\n            await otherGrain.GetUnserializable();\n        }\n\n        public async Task SendUnserializableToOtherSilo()\n        {\n            var otherGrain = await GetGrainOnOtherSilo();\n\n            // Message that grain in a way which should fail.\n            await otherGrain.SendUnserializable(new UnserializableType());\n        }\n\n        public async Task GetUndeserializableFromOtherSilo()\n        {\n            var otherGrain = await GetGrainOnOtherSilo();\n\n            // Message that grain in a way which should fail.\n            await otherGrain.GetUndeserializable();\n        }\n\n        public Task SendUndeserializableToClient(IMessageSerializationClientObject obj) => obj.SendUndeserializable(new UndeserializableType(35));\n        public Task SendUnserializableToClient(IMessageSerializationClientObject obj) => obj.SendUnserializable(new UnserializableType());\n\n        public Task GetUnserializableFromClient(IMessageSerializationClientObject obj) => obj.GetUnserializable();\n        public Task GetUndeserializableFromClient(IMessageSerializationClientObject obj) => obj.GetUndeserializable();\n\n        private async Task<IMessageSerializationGrain> GetGrainOnOtherSilo()\n        {\n            if (this.grainOnOtherSilo != null) return this.grainOnOtherSilo;\n\n            // Find a grain on another silo.\n            IMessageSerializationGrain otherGrain;\n            var id = this.GetPrimaryKeyLong();\n            var currentSiloIdentity = await this.GetSiloIdentity();\n            var silos = ServiceProvider.GetRequiredService<IClusterMembershipService>().CurrentSnapshot.Members.Where(kv => kv.Value.Status == SiloStatus.Active).Select(kv => kv.Key).ToHashSet();\n            silos.Remove(ServiceProvider.GetRequiredService<ILocalSiloDetails>().SiloAddress);\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, silos.First());\n                otherGrain = this.GrainFactory.GetGrain<IMessageSerializationGrain>(++id);\n                var otherIdentity = await otherGrain.GetSiloIdentity();\n                if (!string.Equals(otherIdentity, currentSiloIdentity))\n                {\n                    break;\n                }\n            }\n\n            return this.grainOnOtherSilo = otherGrain;\n        }\n\n        public Task<string> GetSiloIdentity()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MethodInterceptionGrain.cs",
    "content": "using System.Globalization;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class OutgoingMethodInterceptionGrain : IOutgoingMethodInterceptionGrain\n    {\n        public async Task<Dictionary<string, object>> EchoViaOtherGrain(IMethodInterceptionGrain otherGrain, string message)\n        {\n            return new Dictionary<string, object>\n            {\n                [\"result\"] = await otherGrain.Echo(message)\n            };\n        }\n\n        public Task<string> ThrowIfGreaterThanZero(int value)\n        {\n            if (value > 0)\n            {\n                throw new ArgumentOutOfRangeException($\"{value} is greater than zero!\");\n            }\n\n            return Task.FromResult(\"Thanks for nothing\");\n        }\n    }\n\n    public class MethodInterceptionGrain : IMethodInterceptionGrain, IIncomingGrainCallFilter\n    {\n        public Task<string> One() => throw new InvalidOperationException(\"Not allowed to actually invoke this method!\");\n\n        [MessWithResult]\n        public Task<string> Echo(string someArg) => Task.FromResult(someArg);\n\n        public Task<string> NotIntercepted() => Task.FromResult(\"not intercepted\");\n\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> Throw() => throw new MyDomainSpecificException(\"Oi!\");\n\n        public Task FilterThrows() => Task.CompletedTask;\n\n        public Task SystemWideCallFilterMarker() => Task.CompletedTask;\n\n        public Task<string> IncorrectResultType() => Task.FromResult(\"hop scotch\");\n\n        async Task IIncomingGrainCallFilter.Invoke(IIncomingGrainCallContext context)\n        {\n            var methodInfo = context.ImplementationMethod;\n            if (methodInfo.Name == nameof(One) && methodInfo.GetParameters().Length == 0)\n            {\n                // Short-circuit the request and return to the caller without actually invoking the grain method.\n                context.Result = \"intercepted one with no args\";\n                return;\n            }\n\n            if (methodInfo.Name == nameof(IncorrectResultType))\n            {\n                // This method has a string return type, but we are setting the result to a Guid.\n                // This should result in an invalid cast exception.\n                context.Result = Guid.NewGuid();\n                return;\n            }\n\n            if (methodInfo.Name == nameof(FilterThrows))\n            {\n                throw new MyDomainSpecificException(\"Filter THROW!\");\n            }\n\n            // Invoke the request.\n            try\n            {\n                await context.Invoke();\n            }\n            catch (MyDomainSpecificException e)\n            {\n                context.Result = \"EXCEPTION! \" + e.Message;\n                return;\n            }\n\n            // To prove that the MethodInfo is from the implementation and not the interface,\n            // we check for this attribute which is only present on the implementation. This could be\n            // done in a simpler fashion, but this demonstrates a potential usage scenario.\n            var shouldMessWithResult = methodInfo.GetCustomAttribute<MessWithResultAttribute>();\n            var resultString = context.Result as string;\n            if (shouldMessWithResult != null && resultString != null)\n            {\n                context.Result = string.Concat(resultString.Reverse());\n            }\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class MyDomainSpecificException : Exception\n        {\n            public MyDomainSpecificException()\n            {\n            }\n\n            public MyDomainSpecificException(string message) : base(message)\n            {\n            }\n\n            [Obsolete]\n            protected MyDomainSpecificException(SerializationInfo info, StreamingContext context) : base(info, context)\n            {\n            }\n        }\n\n        [AttributeUsage(AttributeTargets.Method)]\n        public class MessWithResultAttribute : Attribute\n        {\n        }\n    }\n\n    public class MethodInterceptionGrainObserver : IMethodInterceptionGrainObserver, IIncomingGrainCallFilter\n    {\n        public Task<string> One() => throw new InvalidOperationException(\"Not allowed to actually invoke this method!\");\n\n        [MessWithResult]\n        public Task<string> Echo(string someArg) => Task.FromResult(someArg);\n\n        public Task<string> NotIntercepted() => Task.FromResult(\"not intercepted\");\n\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> Throw() => throw new MyDomainSpecificException(\"Oi!\");\n\n        public Task FilterThrows() => Task.CompletedTask;\n\n        public Task SystemWideCallFilterMarker() => Task.CompletedTask;\n\n        public Task<string> IncorrectResultType() => Task.FromResult(\"hop scotch\");\n\n        async Task IIncomingGrainCallFilter.Invoke(IIncomingGrainCallContext context)\n        {\n            var methodInfo = context.ImplementationMethod;\n            if (methodInfo.Name == nameof(One) && methodInfo.GetParameters().Length == 0)\n            {\n                // Short-circuit the request and return to the caller without actually invoking the grain method.\n                context.Result = \"intercepted one with no args\";\n                return;\n            }\n\n            if (methodInfo.Name == nameof(IncorrectResultType))\n            {\n                // This method has a string return type, but we are setting the result to a Guid.\n                // This should result in an invalid cast exception.\n                context.Result = Guid.NewGuid();\n                return;\n            }\n\n            if (methodInfo.Name == nameof(FilterThrows))\n            {\n                throw new MyDomainSpecificException(\"Filter THROW!\");\n            }\n\n            // Invoke the request.\n            try\n            {\n                await context.Invoke();\n            }\n            catch (MyDomainSpecificException e)\n            {\n                context.Result = \"EXCEPTION! \" + e.Message;\n                return;\n            }\n\n            // To prove that the MethodInfo is from the implementation and not the interface,\n            // we check for this attribute which is only present on the implementation. This could be\n            // done in a simpler fashion, but this demonstrates a potential usage scenario.\n            var shouldMessWithResult = methodInfo.GetCustomAttribute<MessWithResultAttribute>();\n            var resultString = context.Result as string;\n            if (shouldMessWithResult != null && resultString != null)\n            {\n                context.Result = string.Concat(resultString.Reverse());\n            }\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class MyDomainSpecificException : Exception\n        {\n            public MyDomainSpecificException()\n            {\n            }\n\n            public MyDomainSpecificException(string message) : base(message)\n            {\n            }\n\n            [Obsolete]\n            protected MyDomainSpecificException(SerializationInfo info, StreamingContext context) : base(info, context)\n            {\n            }\n        }\n\n        [AttributeUsage(AttributeTargets.Method)]\n        public class MessWithResultAttribute : Attribute\n        {\n        }\n    }\n\n    public class GenericMethodInterceptionGrain<T> : IGenericMethodInterceptionGrain<T>, IIncomingGrainCallFilter\n    {\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> GetInputAsString(T input) => Task.FromResult(input.ToString());\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            if (context.ImplementationMethod.Name == nameof(GetInputAsString))\n            {\n                context.Result = $\"Hah! You wanted {context.Request.GetArgument(0)}, but you got me!\";\n                return;\n            }\n\n            await context.Invoke();\n        }\n    }\n\n    public class TrickyInterceptionGrain : ITrickyMethodInterceptionGrain, IIncomingGrainCallFilter\n    {\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> GetInputAsString(string input) => Task.FromResult(input);\n\n        public Task<string> GetInputAsString(bool input) => Task.FromResult(input.ToString(CultureInfo.InvariantCulture));\n\n        public Task<int> GetBestNumber() => Task.FromResult(38);\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            if (context.ImplementationMethod.Name == nameof(GetInputAsString))\n            {\n                context.Result = $\"Hah! You wanted {context.Request.GetArgument(0)}, but you got me!\";\n                return;\n            }\n\n            await context.Invoke();\n        }\n    }\n\n    public class GenericMethodInterceptionGrainObserver<T> : IGenericMethodInterceptionGrainObserver<T>, IIncomingGrainCallFilter\n    {\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> GetInputAsString(T input) => Task.FromResult(input.ToString());\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            if (context.ImplementationMethod.Name == nameof(GetInputAsString))\n            {\n                context.Result = $\"Hah! You wanted {context.Request.GetArgument(0)}, but you got me!\";\n                return;\n            }\n\n            await context.Invoke();\n        }\n    }\n\n    public class TrickyInterceptionGrainObserver : ITrickyMethodInterceptionGrainObserver, IIncomingGrainCallFilter\n    {\n        public Task<string> SayHello() => Task.FromResult(\"Hello\");\n\n        public Task<string> GetInputAsString(string input) => Task.FromResult(input);\n\n        public Task<string> GetInputAsString(bool input) => Task.FromResult(input.ToString(CultureInfo.InvariantCulture));\n\n        public Task<int> GetBestNumber() => Task.FromResult(38);\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            if (context.ImplementationMethod.Name == nameof(GetInputAsString))\n            {\n                context.Result = $\"Hah! You wanted {context.Request.GetArgument(0)}, but you got me!\";\n                return;\n            }\n\n            await context.Invoke();\n        }\n    }\n\n    public class GrainCallFilterTestGrain : IGrainCallFilterTestGrain, IIncomingGrainCallFilter\n    {\n        private const string Key = GrainCallFilterTestConstants.Key;\n\n        public Task<string> ThrowIfGreaterThanZero(int value)\n        {\n            if (value > 0)\n            {\n                throw new ArgumentOutOfRangeException($\"{value} is greater than zero!\");\n            }\n\n            return Task.FromResult(\"Thanks for nothing\");\n        }\n\n        public Task<string> GetRequestContext() => Task.FromResult((string)RequestContext.Get(Key) + \"4\");\n\n        public async Task Invoke(IIncomingGrainCallContext ctx)\n        {\n            var attemptsRemaining = 2;\n\n            while (attemptsRemaining > 0)\n            {\n                try\n                {\n                    var interfaceMethod = ctx.InterfaceMethod ?? throw new ArgumentException(\"InterfaceMethod is null!\");\n                    var implementationMethod = ctx.ImplementationMethod ?? throw new ArgumentException(\"ImplementationMethod is null!\");\n                    if (!string.Equals(implementationMethod.Name, interfaceMethod.Name))\n                    {\n                        throw new ArgumentException(\"InterfaceMethod.Name != ImplementationMethod.Name\");\n                    }\n\n                    if (string.Equals(implementationMethod.Name, nameof(GrainSpecificCallFilterMarker)))\n                    {\n                        // explicitly do not continue calling Invoke\n                        return;\n                    }\n\n                    if (RequestContext.Get(Key) is string value) RequestContext.Set(Key, value + '3');\n                    await ctx.Invoke();\n                    return;\n                }\n                catch (ArgumentOutOfRangeException) when (attemptsRemaining > 1)\n                {\n                    if (string.Equals(ctx.ImplementationMethod?.Name, nameof(ThrowIfGreaterThanZero)) && ctx.Request.GetArgument(0) is int value)\n                    {\n                        ctx.Request.SetArgument(0, value - 1);\n                    }\n\n                    --attemptsRemaining;\n                }\n            }\n        }\n\n        public Task<int> SumSet(HashSet<int> numbers) => Task.FromResult(numbers.Sum());\n\n        public Task SystemWideCallFilterMarker() => Task.CompletedTask;\n\n        public Task GrainSpecificCallFilterMarker() => Task.CompletedTask;\n    }\n\n    public class GrainCallFilterTestGrainObserver : IGrainCallFilterTestGrainObserver, IIncomingGrainCallFilter\n    {\n        private const string Key = GrainCallFilterTestConstants.Key;\n\n        public Task<string> ThrowIfGreaterThanZero(int value)\n        {\n            if (value > 0)\n            {\n                throw new ArgumentOutOfRangeException($\"{value} is greater than zero!\");\n            }\n\n            return Task.FromResult(\"Thanks for nothing\");\n        }\n\n        public Task<string> GetRequestContext() => Task.FromResult((string)RequestContext.Get(Key) + \"4\");\n\n        public async Task Invoke(IIncomingGrainCallContext ctx)\n        {\n            var attemptsRemaining = 2;\n\n            while (attemptsRemaining > 0)\n            {\n                try\n                {\n                    var interfaceMethod = ctx.InterfaceMethod ?? throw new ArgumentException(\"InterfaceMethod is null!\");\n                    var implementationMethod = ctx.ImplementationMethod ?? throw new ArgumentException(\"ImplementationMethod is null!\");\n                    if (!string.Equals(implementationMethod.Name, interfaceMethod.Name))\n                    {\n                        throw new ArgumentException(\"InterfaceMethod.Name != ImplementationMethod.Name\");\n                    }\n\n                    if (string.Equals(implementationMethod.Name, nameof(GrainSpecificCallFilterMarker)))\n                    {\n                        // explicitly do not continue calling Invoke\n                        return;\n                    }\n\n                    if (RequestContext.Get(Key) is string value) RequestContext.Set(Key, value + '3');\n                    await ctx.Invoke();\n                    return;\n                }\n                catch (ArgumentOutOfRangeException) when (attemptsRemaining > 1)\n                {\n                    if (string.Equals(ctx.ImplementationMethod?.Name, nameof(ThrowIfGreaterThanZero)) && ctx.Request.GetArgument(0) is int value)\n                    {\n                        ctx.Request.SetArgument(0, value - 1);\n                    }\n\n                    --attemptsRemaining;\n                }\n            }\n        }\n\n        public Task<int> SumSet(HashSet<int> numbers) => Task.FromResult(numbers.Sum());\n\n        public Task SystemWideCallFilterMarker() => Task.CompletedTask;\n\n        public Task GrainSpecificCallFilterMarker() => Task.CompletedTask;\n    }\n\n    public class CaterpillarGrain : ICaterpillarGrain, IIncomingGrainCallFilter\n    {\n        Task IIncomingGrainCallFilter.Invoke(IIncomingGrainCallContext ctx)\n        {\n            if (ctx.InterfaceMethod is null) throw new Exception(\"InterfaceMethod is null\");\n            if (!ctx.InterfaceMethod.DeclaringType.IsInterface) throw new Exception(\"InterfaceMethod is not an interface method\");\n\n            if (ctx.ImplementationMethod is null) throw new Exception(\"ImplementationMethod is null\");\n            if (ctx.ImplementationMethod.DeclaringType.IsInterface) throw new Exception(\"ImplementationMethod is an interface method\");\n\n            if (RequestContext.Get(\"tag\") is string tag)\n            {\n                var ifaceTag = ctx.InterfaceMethod.GetCustomAttribute<TestMethodTagAttribute>()?.Tag;\n                var implTag = ctx.ImplementationMethod.GetCustomAttribute<TestMethodTagAttribute>()?.Tag;\n                if (!string.Equals(tag, ifaceTag, StringComparison.Ordinal)\n                    || !string.Equals(tag, implTag, StringComparison.Ordinal))\n                {\n                    throw new Exception($\"Expected method tags to be equal to request context tag: RequestContext: {tag} Interface: {ifaceTag} Implementation: {implTag}\");\n                }\n            }\n\n            return ctx.Invoke();\n        }\n\n        [TestMethodTag(\"hungry-eat\")]\n        public Task Eat(Apple food) => Task.CompletedTask;\n\n        [TestMethodTag(\"omnivore-eat\")]\n        Task IOmnivoreGrain.Eat<T>(T food) => Task.CompletedTask;\n\n        [TestMethodTag(\"caterpillar-eat\")]\n        public Task Eat<T>(T food) => Task.CompletedTask;\n\n        [TestMethodTag(\"hungry-eatwith\")]\n        public Task EatWith<U>(Apple food, U condiment) => Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MultipleConstructorsSimpleGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class MultipleConstructorsSimpleGrain : SimpleGrain, ISimpleGrain\n    {\n        public const string MultipleConstructorsSimpleGrainPrefix = \"UnitTests.Grains.MultipleConstructorsS\";\n        public const int ValueUsedByParameterlessConstructor = 42;\n\n        public MultipleConstructorsSimpleGrain(ILoggerFactory loggerFactory)\n            : this(loggerFactory, ValueUsedByParameterlessConstructor)\n        {\n            // orleans will use this constructor when DI is not configured\n        }\n\n        public MultipleConstructorsSimpleGrain(ILoggerFactory loggerFactory, int initialValueofA) : base(loggerFactory)\n        {\n            base.A = initialValueofA;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MultipleGenericParameterInterfaceImpl.cs",
    "content": "﻿namespace UnitTests.Grains\n{\n    public class CodeGenTestPoco\n    {\n        public int SomeProperty { get; set; }\n    }\n\n    // This class forms a code generation test case.\n    // If the code generator does generate any code for the async state machine in the Product\n    // method, it must generate valid C# syntax. See: https://github.com/dotnet/orleans/pull/3639\n    public class FeaturePopulatorCodeGenTestClass : CodeGenTestPoco, FeaturePopulatorCodeGenTestClass.IFactory<int, double>\n    {\n        public interface IFactory<TInput, TOutput>\n        {\n            Task<TOutput> Product(TInput input);\n        }\n\n        async Task<double> IFactory<int, double>.Product(int input)\n        {\n            await Task.Delay(100);\n            return input;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MultipleImplicitSubscriptionGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n\n    [ImplicitStreamSubscription(\"red\")]\n    [ImplicitStreamSubscription(\"blue\")]\n    public class MultipleImplicitSubscriptionGrain : Grain, IMultipleImplicitSubscriptionGrain\n    {\n        private readonly ILogger logger;\n        private IAsyncStream<int> redStream, blueStream;\n        private int redCounter, blueCounter;\n\n        public MultipleImplicitSubscriptionGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger(\"MultipleImplicitSubscriptionGrain \" + base.IdentityString);\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n\n            var streamProvider = this.GetStreamProvider(\"SMSProvider\");\n            redStream = streamProvider.GetStream<int>(\"red\", this.GetPrimaryKey());\n            blueStream = streamProvider.GetStream<int>(\"blue\", this.GetPrimaryKey());\n\n            await redStream.SubscribeAsync(\n                (e, t) =>\n                {\n                    logger.LogInformation(\"Received a red event {Event}\", e);\n                    redCounter++;\n                    return Task.CompletedTask;\n                });\n\n            await blueStream.SubscribeAsync(\n                (e, t) =>\n                {\n                    logger.LogInformation(\"Received a blue event {Event}\", e);\n                    blueCounter++;\n                    return Task.CompletedTask;\n                });\n        }\n\n        public Task<Tuple<int, int>> GetCounters()\n        {\n            return Task.FromResult(new Tuple<int, int>(redCounter, blueCounter));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/MultipleSubscriptionConsumerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class MultipleSubscriptionConsumerGrain : Grain, IMultipleSubscriptionConsumerGrain\n    {\n        private readonly Dictionary<StreamSubscriptionHandle<int>, Tuple<Counter,Counter>> consumedMessageCounts;\n        private readonly ILogger logger;\n        private int consumerCount = 0;\n\n        public MultipleSubscriptionConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n            consumedMessageCounts = new Dictionary<StreamSubscriptionHandle<int>, Tuple<Counter, Counter>>();\n        }\n\n        private class Counter\n        {\n            public int Value { get; private set; }\n\n            public void Increment()\n            {\n                Value++;\n            }\n\n            public void Clear()\n            {\n                Value = 0;\n            }\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task<StreamSubscriptionHandle<int>> BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeConsumer\");\n\n            // new counter for this subscription\n            var count = new Counter();\n            var error = new Counter();\n\n            // get stream\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            var stream = streamProvider.GetStream<int>(streamNamespace, streamId);\n\n            int countCapture = consumerCount;\n            consumerCount++;\n            // subscribe\n            StreamSubscriptionHandle<int> handle = await stream.SubscribeAsync(\n                (items) => OnNext(items, countCapture, count),\n                e => OnError(e, countCapture, error));\n\n            // track counter\n            consumedMessageCounts.Add(handle, Tuple.Create(count,error));\n\n            // return handle\n            return handle;\n        }\n\n        public async Task<StreamSubscriptionHandle<int>> Resume(StreamSubscriptionHandle<int> handle)\n        {\n            logger.LogInformation(\"Resume\");\n            if(handle == null)\n                throw new ArgumentNullException(nameof(handle));\n\n            // new counter for this subscription\n            Tuple<Counter,Counter> counters;\n            if (!consumedMessageCounts.TryGetValue(handle, out counters))\n            {\n                counters = Tuple.Create(new Counter(), new Counter());\n            }\n\n            int countCapture = consumerCount;\n            consumerCount++;\n            // subscribe\n            StreamSubscriptionHandle<int> newhandle = await handle.ResumeAsync(\n                (items) => OnNext(items, countCapture, counters.Item1),\n                e => OnError(e, countCapture, counters.Item2));\n\n            // track counter\n            consumedMessageCounts[newhandle] = counters;\n\n            // return handle\n            return newhandle;\n\n        }\n\n        public async Task StopConsuming(StreamSubscriptionHandle<int> handle)\n        {\n            logger.LogInformation(\"StopConsuming\");\n            // unsubscribe\n            await handle.UnsubscribeAsync();\n\n            // stop tracking event count for stream\n            consumedMessageCounts.Remove(handle);\n        }\n\n        public Task<IList<StreamSubscriptionHandle<int>>> GetAllSubscriptions(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"GetAllSubscriptionHandles\");\n\n            // get stream\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            var stream = streamProvider.GetStream<int>(streamNamespace, streamId);\n\n            // get all active subscription handles for this stream.\n            return stream.GetAllSubscriptionHandles();\n        }\n\n        public Task<Dictionary<StreamSubscriptionHandle<int>, Tuple<int,int>>> GetNumberConsumed()\n        {\n            logger.LogInformation(\n                \"ConsumedMessageCounts = {Counts}\",\n                Utils.EnumerableToString(\n                    consumedMessageCounts,\n                    kvp => $\"Consumer: {kvp.Key.HandleId} -> count: {kvp.Value}\"));\n\n            return Task.FromResult(consumedMessageCounts.ToDictionary(kvp => kvp.Key, kvp => Tuple.Create(kvp.Value.Item1.Value, kvp.Value.Item2.Value)));\n        }\n\n        public Task ClearNumberConsumed()\n        {\n            logger.LogInformation(\"ClearNumberConsumed\");\n            foreach (var counters in consumedMessageCounts.Values)\n            {\n                counters.Item1.Clear();\n                counters.Item2.Clear();\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task Deactivate()\n        {\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        private Task OnNext(IList<SequentialItem<int>> items, int countCapture, Counter count)\n        {\n            foreach(SequentialItem<int> item in items)\n            {\n                logger.LogInformation(\"Got next event {Item} on handle {Handle}\", item.Item, countCapture);\n                var contextValue = RequestContext.Get(SampleStreaming_ProducerGrain.RequestContextKey) as string;\n                if (!string.Equals(contextValue, SampleStreaming_ProducerGrain.RequestContextValue))\n                {\n                    throw new Exception($\"Got the wrong RequestContext value {contextValue}.\");\n                }\n                count.Increment();\n            }\n            return Task.CompletedTask;\n        }\n\n        private Task OnError(Exception e, int countCapture, Counter error)\n        {\n            logger.LogInformation(e, \"Got exception on handle {Handle}\", countCapture);\n            error.Increment();\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/NoOpTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class NoOpTestGrain : Grain, INoOpTestGrain\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/NullStateGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class NullStateGrain : Grain<NullableState>, INullStateGrain\n    {\n        public async Task SetStateAndDeactivate(NullableState state)\n        {\n            this.State = state;\n            await WriteStateAsync();\n            DeactivateOnIdle();\n        }\n\n        public Task<NullableState> GetState()\n        {\n            return Task.FromResult(this.State);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ObserverGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ObserverGrain : Grain, IObserverGrain, ISimpleGrainObserver\n    {\n        protected  ISimpleGrainObserver Observer { get; set; } // supports only a single observer\n\n        protected ISimpleObserverableGrain Target { get; set; }\n\n        public Task SetTarget(ISimpleObserverableGrain target)\n        {\n            Target = target;\n            return target.Subscribe(this);\n        }\n\n        public Task Subscribe(ISimpleGrainObserver observer)\n        {\n            this.Observer = observer;\n            return Task.CompletedTask;\n        }\n\n        public void StateChanged(int a, int b)\n        {\n            Observer.StateChanged(a, b);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ObserverWithCancellationGrain.cs",
    "content": "#nullable enable\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\n/// <summary>\n/// Grain that manages observers with cancellation support for testing purposes.\n/// </summary>\npublic class ObserverWithCancellationGrain : Grain, IObserverWithCancellationGrain\n{\n    private readonly List<(Guid CallId, Exception? Error)> _processedCancellations = [];\n    private ILongRunningObserver? _observer;\n\n    /// <inheritdoc />\n    public Task Subscribe(ILongRunningObserver observer)\n    {\n        _observer = observer;\n        return Task.CompletedTask;\n    }\n\n    /// <inheritdoc />\n    public Task Unsubscribe(ILongRunningObserver observer)\n    {\n        if (ReferenceEquals(_observer, observer))\n        {\n            _observer = null;\n        }\n\n        return Task.CompletedTask;\n    }\n\n    /// <inheritdoc />\n    public async Task NotifyLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken)\n    {\n        if (_observer is null)\n        {\n            throw new InvalidOperationException(\"No observer subscribed.\");\n        }\n\n        try\n        {\n            await _observer.LongWait(delay, callId, cancellationToken);\n        }\n        catch (OperationCanceledException)\n        {\n            _processedCancellations.Add((callId, null));\n            throw;\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task<bool> NotifyCancellationTokenCallbackResolve(Guid callId, CancellationToken cancellationToken)\n    {\n        if (_observer is null)\n        {\n            throw new InvalidOperationException(\"No observer subscribed.\");\n        }\n\n        try\n        {\n            return await _observer.CancellationTokenCallbackResolve(callId, cancellationToken);\n        }\n        finally\n        {\n            _processedCancellations.Add((callId, null));\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task NotifyInterleavingLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken)\n    {\n        if (_observer is null)\n        {\n            throw new InvalidOperationException(\"No observer subscribed.\");\n        }\n\n        try\n        {\n            await _observer.InterleavingLongWait(delay, callId, cancellationToken);\n        }\n        catch (OperationCanceledException)\n        {\n            _processedCancellations.Add((callId, null));\n            throw;\n        }\n    }\n\n    /// <inheritdoc />\n    public Task<List<(Guid CallId, Exception? Error)>> GetProcessedCancellations()\n    {\n        return Task.FromResult(_processedCancellations.ToList());\n    }\n\n    /// <inheritdoc />\n    public Task ClearProcessedCancellations()\n    {\n        _processedCancellations.Clear();\n        return Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/PolymorphicTestGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class PolymorphicTestGrain : Grain, IPolymorphicTestGrain\n    {\n        public Task<string> F1Method() => Task.FromResult(\"F1\");\n        public Task<string> F2Method() => Task.FromResult(\"F2\");\n        public Task<string> F3Method() => Task.FromResult(\"F3\");\n        public Task<string> E1Method() => Task.FromResult(\"E1\");\n        public Task<string> E2Method() => Task.FromResult(\"E2\");\n        public Task<string> E3Method() => Task.FromResult(\"E3\");\n        public Task<string> D1Method() => Task.FromResult(\"D1\");\n        public Task<string> D2Method() => Task.FromResult(\"D2\");\n        public Task<string> D3Method() => Task.FromResult(\"D3\");\n        public Task<string> C1Method() => Task.FromResult(\"C1\");\n        public Task<string> C2Method() => Task.FromResult(\"C2\");\n        public Task<string> C3Method() => Task.FromResult(\"C3\");\n        public Task<string> B1Method() => Task.FromResult(\"B1\");\n        public Task<string> B2Method() => Task.FromResult(\"B2\");\n        public Task<string> B3Method() => Task.FromResult(\"B3\");\n        public Task<string> A1Method() => Task.FromResult(\"A1\");\n        public Task<string> A2Method() => Task.FromResult(\"A2\");\n        public Task<string> A3Method() => Task.FromResult(\"A3\");\n        Task<string> IC.CommonMethod() => Task.FromResult(\"IC\");\n        Task<string> IA.CommonMethod() => Task.FromResult(\"IA\");\n        Task<string> IB.CommonMethod() => Task.FromResult(\"IB\");\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ProducerEventCountingGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class ProducerEventCountingGrain : BaseGrain, IProducerEventCountingGrain\n    {\n        private IAsyncObserver<int> _producer;\n        private int _numProducedItems;\n        private readonly ILogger _logger;\n\n        public ProducerEventCountingGrain(ILoggerFactory loggerFactory)\n        {\n            _logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Producer.OnActivateAsync\");\n            _numProducedItems = 0;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Producer.OnDeactivateAsync\");\n            _numProducedItems = 0;\n            await base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task BecomeProducer(Guid streamId, string providerToUse)\n        {\n            _logger.LogInformation(\"Producer.BecomeProducer\");\n            if (string.IsNullOrEmpty(providerToUse))\n            {\n                throw new ArgumentNullException(nameof(providerToUse));\n            }\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            IAsyncStream<int> stream = streamProvider.GetStream<int>(ConsumerEventCountingGrain.StreamNamespace, streamId);\n            _producer = stream;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetNumberProduced()\n        {\n            return Task.FromResult(_numProducedItems);\n        }\n\n        public async Task SendEvent()\n        {\n            _logger.LogInformation(\"Producer.SendEvent called\");\n            if (_producer == null)\n            {\n                throw new ApplicationException(\"Not yet a producer on a stream.  Must call BecomeProducer first.\");\n            }\n\n            await _producer.OnNextAsync(_numProducedItems + 1);\n\n            // update after send in case of error\n            _numProducedItems++;\n            _logger.LogInformation(\"Producer.SendEvent - TotalSent: {Count}\", _numProducedItems);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/ProgrammaticSubscribe/Passive_ConsumerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class Passive_ConsumerGrain : Grain, IPassive_ConsumerGrain, IStreamSubscriptionObserver\n    {\n        internal ILogger logger;\n        private List<ICounterObserver> consumerObservers;\n        private List<StreamSubscriptionHandle<IFruit>> consumerHandles;\n        private int onAddCalledCount;\n\n        public Passive_ConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            onAddCalledCount = 0;\n            consumerObservers = new List<ICounterObserver>();\n            consumerHandles = new List<StreamSubscriptionHandle<IFruit>>();\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetCountOfOnAddFuncCalled()\n        {\n            return Task.FromResult(this.onAddCalledCount);\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            int sum = 0;\n            foreach (var observer in consumerObservers)\n            {\n                sum += observer.NumConsumed;\n            }\n\n            logger.LogInformation(\"GetNumberConsumed {Sum}\", sum);\n            return Task.FromResult(sum);\n        }\n\n        public async Task StopConsuming()\n        {\n            logger.LogInformation(\"StopConsuming\");\n            foreach (var handle in consumerHandles)\n            {\n                await handle.UnsubscribeAsync();\n            }\n            consumerHandles.Clear();\n            consumerObservers.Clear();\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            logger.LogInformation(\"OnAdd\");\n            this.onAddCalledCount++;\n            var observer = new CounterObserver<IFruit>(this.logger);\n            var newhandle = handleFactory.Create<IFruit>();\n            this.consumerHandles.Add(await newhandle.ResumeAsync(observer));\n            this.consumerObservers.Add(observer);\n        }\n    }\n\n    public class Jerk_ConsumerGrain : Grain, IJerk_ConsumerGrain, IStreamSubscriptionObserver\n    {\n        internal ILogger logger;\n\n        public Jerk_ConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        //Jerk_ConsumerGrai would unsubscrube on any subscription added to it\n        public async Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            var handle = handleFactory.Create<int>();\n            await handle.UnsubscribeAsync();\n        }\n    }\n\n    public interface ICounterObserver\n    {\n        int NumConsumed { get; }\n    }\n\n    public class CounterObserver<T> : IAsyncObserver<T>, ICounterObserver\n    {\n        public int NumConsumed { get; private set; }\n        private readonly ILogger logger;\n        internal CounterObserver(ILogger logger)\n        {\n            this.NumConsumed = 0;\n            this.logger = logger;\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken token = null)\n        {\n            this.NumConsumed++;\n            this.logger.LogInformation(\"Consumer {HashCode} OnNextAsync() received item {Item}, with NumConsumed {NumConsumed}\", this.GetHashCode(), item, NumConsumed);\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            this.logger.LogInformation(\"Consumer {HashCode} OnCompletedAsync()\", this.GetHashCode());\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            this.logger.LogInformation(ex, \"Consumer {HashCode} OnErrorAsync()\", this.GetHashCode());\n            return Task.CompletedTask;\n        }\n    }\n\n    [ImplicitStreamSubscription(StreamNameSpace)]\n    [ImplicitStreamSubscription(StreamNameSpace2)]\n    public class ImplicitSubscribeGrain : Passive_ConsumerGrain, IImplicitSubscribeGrain\n    {\n        public const string StreamNameSpace = \"ImplicitSubscriptionSpace11\";\n        public const string StreamNameSpace2 = \"ImplicitSubscriptionSpace22\";\n\n        public ImplicitSubscribeGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ProgrammaticSubscribe/SubscribeGrain.cs",
    "content": "using Orleans.Streams;\nusing Orleans.Runtime;\nusing Orleans.Streams.PubSub;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace UnitTests.Grains.ProgrammaticSubscribe\n{\n    public interface ISubscribeGrain : IGrainWithGuidKey\n    {\n        Task<bool> CanGetSubscriptionManager(string providerName);\n    }\n\n    public class SubscribeGrain : Grain, ISubscribeGrain\n    {\n        public Task<bool> CanGetSubscriptionManager(string providerName)\n        {\n            return Task.FromResult(this.ServiceProvider.GetKeyedService<IStreamProvider>(providerName).TryGetStreamSubscriptionManager(out _));\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class FullStreamIdentity : IStreamIdentity\n    {\n        public FullStreamIdentity(Guid streamGuid, string streamNamespace, string providerName)\n        {\n            Guid = streamGuid;\n            Namespace = streamNamespace;\n            this.ProviderName = providerName;\n        }\n\n        [Id(0)]\n        public string ProviderName;\n\n        /// <summary>\n        /// Stream primary key guid.\n        /// </summary>\n        [Id(1)]\n        public Guid Guid { get; }\n\n        /// <summary>\n        /// Stream namespace.\n        /// </summary>\n        [Id(2)]\n        public string Namespace { get; }\n\n        public static implicit operator StreamId(FullStreamIdentity identity) => StreamId.Create(identity);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ProgrammaticSubscribe/TypedProducerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing System.Runtime.CompilerServices;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains.ProgrammaticSubscribe\n{\n    public class TypedProducerGrain<T> : Grain, ITypedProducerGrain\n    {\n        private IAsyncStream<T> producer;\n        protected int numProducedItems;\n        private IDisposable producerTimer;\n        internal ILogger logger;\n        private static readonly TimeSpan defaultFirePeriod = TimeSpan.FromMilliseconds(10);\n        private readonly List<Exception> producerExceptions = new();\n\n        public TypedProducerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            numProducedItems = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task BecomeProducer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeProducer\");\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            producer = streamProvider.GetStream<T>(streamNamespace, streamId);\n            return Task.CompletedTask;\n        }\n\n        public Task StartPeriodicProducing(TimeSpan? firePeriod = null)\n        {\n            logger.LogInformation(\"StartPeriodicProducing\");\n            var period = (firePeriod == null)? defaultFirePeriod : firePeriod;\n            producerTimer = this.RegisterGrainTimer(TimerCallback, TimeSpan.Zero, period.Value);\n            return Task.CompletedTask;\n        }\n\n        public Task StopPeriodicProducing()\n        {\n            logger.LogInformation(\"StopPeriodicProducing\");\n            producerTimer.Dispose();\n            producerTimer = null;\n            if (producerExceptions is { Count: > 0 } exceptions)\n            {\n                throw new AggregateException(\"Exceptions occurred while producing messages to stream\", exceptions.ToArray());\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetNumberProduced()\n        {\n            logger.LogInformation(\"GetNumberProduced {Count}\", numProducedItems);\n            return Task.FromResult(numProducedItems);\n        }\n\n        public Task ClearNumberProduced()\n        {\n            numProducedItems = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task Produce()\n        {\n            return Fire();\n        }\n\n        private Task TimerCallback()\n        {\n            return producerTimer != null ? Fire() : Task.CompletedTask;\n        }\n\n        protected virtual async Task ProducerOnNextAsync(IAsyncStream<T> theProducer)\n        {\n            try\n            {\n                await theProducer.OnNextAsync(Activator.CreateInstance<T>());\n            }\n            catch (Exception exception)\n            {\n                logger.LogError(exception, \"Exception producing to stream {StreamId}\", theProducer.StreamId);\n                producerExceptions.Add(exception);\n            }\n        }\n\n        private async Task Fire([CallerMemberName] string caller = null)\n        {\n            numProducedItems++;\n            await ProducerOnNextAsync(this.producer);\n            logger.LogInformation(\"{Caller} (item={Item})\", caller, numProducedItems);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n    }\n    public class TypedProducerGrainProducingInt : TypedProducerGrain<int>, ITypedProducerGrainProducingInt\n    {\n        public TypedProducerGrainProducingInt(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        protected override Task ProducerOnNextAsync(IAsyncStream<int> theProducer)\n        {\n            return theProducer.OnNextAsync(this.numProducedItems);\n        }\n    }\n\n    public class TypedProducerGrainProducingApple : TypedProducerGrain<Apple>, ITypedProducerGrainProducingApple\n    {\n        public TypedProducerGrainProducingApple(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        protected override Task ProducerOnNextAsync(IAsyncStream<Apple> theProducer)\n        {\n            return theProducer.OnNextAsync(new Apple(this.numProducedItems));\n        }\n    }\n\n    [GenerateSerializer]\n    public class Apple : IFruit\n    {\n        [Id(0)]\n        private readonly int number;\n\n        public Apple(int number)\n        {\n            this.number = number;\n        }\n\n        public int GetNumber()\n        {\n            return number;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/PromiseForwardGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class SimpleGrainState\n    {\n        [Id(0)]\n        public int A { get; set; }\n        [Id(1)]\n        public int EventDelay { get; set; }\n    }\n\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class PromiseForwardGrain : Grain<SimpleGrainState>, IPromiseForwardGrain\n    {\n        protected  ISimpleGrain MySimpleGrain { get; set; }\n        protected int b = 0;\n        public Task<int> GetAxB_Async()\n        {\n            return GetSimpleGrain().GetAxB();\n        }\n        public Task<int> GetAxB_Async(int a, int b)\n        {\n            return GetSimpleGrain().GetAxB(a, b);\n        }\n        public Task SetA_Async(int a)\n        {\n            return GetSimpleGrain().SetA(a);\n        }\n        public Task SetB_Async(int b)\n        {\n            return GetSimpleGrain().SetB(b);\n        }\n        public Task IncrementA_Async()\n        {\n            return GetSimpleGrain().IncrementA();\n        }\n        public Task<int> GetA_Async()\n        {\n            return GetSimpleGrain().GetA();\n        }\n\n        public async Task SetA(int a)\n        {\n            await GetSimpleGrain().SetA(a);\n        }\n        public async Task SetB(int a)\n        {\n            await GetSimpleGrain().SetB(a);\n        }\n        public Task<int> GetAxB()\n        {\n            return GetSimpleGrain().GetAxB();\n        }\n        public Task<int> GetAxB(int a, int b)\n        {\n            return GetSimpleGrain().GetAxB(a, b);\n        }\n        public async Task IncrementA()\n        {\n            await GetSimpleGrain().IncrementA();\n        }\n        public Task<int> GetA()\n        {\n            return GetSimpleGrain().GetA();\n        }\n        \n        private ISimpleGrain GetSimpleGrain()\n        {\n            if( MySimpleGrain == null )\n                MySimpleGrain = GrainFactory.GetGrain<ISimpleGrain>((new Random()).Next(), SimpleGrain.SimpleGrainNamePrefix);\n\n            return MySimpleGrain;\n        }\n\n        public Task<int> A\n        {\n            get { return Task.FromResult(State.A); }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ProxyGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace TestInternalGrains\n{\n    public class ProxyGrain : Grain, IProxyGrain\n    {\n        private ITestGrain proxy;\n\n        public Task CreateProxy(long key)\n        {\n            proxy = GrainFactory.GetGrain<ITestGrain>(key);\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public Task<string> GetProxyRuntimeInstanceId()\n        {\n            return proxy.GetRuntimeInstanceId();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ReentrancyCorrelationIdGrains.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class FirstGrain : Grain, IFirstGrain\n    {\n        public async Task Start(Guid guid1, Guid guid2)\n        {\n            var acceptedByUserTask = GrainFactory.GetGrain<ISecondGrain>(guid2).SecondGrainMethod(this.GetPrimaryKey());\n            var callOwnerUserTask = GrainFactory.GetGrain<ISecondGrain>(guid1).SecondGrainMethod(this.GetPrimaryKey());\n            await Task.WhenAll(acceptedByUserTask, callOwnerUserTask);\n        }\n    }\n\n    public class SecondGrain : Grain, ISecondGrain\n    {\n        public async Task SecondGrainMethod(Guid guid)\n        {\n            var keys = new[] { \"AAA\", \"BBB\" };\n\n            var tasks = new List<Task>();\n            foreach (var key in keys)\n            {\n                tasks.Add(GrainFactory.GetGrain<IThirdGrain>(key).ThirdGrainMethod(guid));\n            }\n\n            await Task.WhenAll(tasks);\n        }\n    }\n\n    [GenerateSerializer]\n    public class ThirdGrainState\n    {\n    }\n\n    public class ThirdGrain : Grain<ThirdGrainState>, IThirdGrain\n    {\n        private int inFlightCounter = 0;\n\n        public async Task ThirdGrainMethod(Guid userId)\n        {\n            this.inFlightCounter++;\n\n            if (this.inFlightCounter > 1)\n                throw new Exception(\"More than 1 in flight call too this method!\");\n\n            await this.WriteStateAsync();\n            this.inFlightCounter--;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ReentrantGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Streams;\n\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Reentrant]\n    public class ReentrantGrain : Grain, IReentrantGrain\n    {\n        private IReentrantGrain Self { get; set; }\n\n        public Task<string> One()\n        {\n            return Task.FromResult(\"one\");\n        }\n\n        public async Task<string> Two()\n        {\n            return await Self.One() + \" two\";\n        }\n\n        public Task SetSelf(IReentrantGrain self)\n        {\n            Self = self;\n            return Task.CompletedTask;\n        }\n    }\n\n    public class NonRentrantGrain : Grain, INonReentrantGrain\n    {\n        private INonReentrantGrain Self { get; set; }\n\n        private readonly ILogger logger;\n\n        public NonRentrantGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<string> One()\n        {\n            logger.LogInformation(\"Entering One\");\n            string result = \"one\";\n            logger.LogInformation(\"Exiting One\");\n            return Task.FromResult(result);\n        }\n\n        public async Task<string> Two()\n        {\n            logger.LogInformation(\"Entering Two\");\n            string result = await Self.One();\n            result = result + \" two\";\n            logger.LogInformation(\"Exiting Two\");\n            return result;\n        }\n\n        public Task SetSelf(INonReentrantGrain self)\n        {\n            logger.LogInformation(\"SetSelf {Self}\", self);\n            Self = self;\n            return Task.CompletedTask;\n        }\n    }\n\n    [MayInterleave(nameof(MayInterleave))]\n    public class MayInterleaveStaticPredicateGrain : Grain, IMayInterleaveStaticPredicateGrain\n    {\n        private readonly ILogger logger;\n\n        public MayInterleaveStaticPredicateGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public static bool MayInterleave(IInvokable req)\n        {\n            // not interested\n            if (req.GetArgumentCount() == 0)\n                return false;\n\n            string arg = null;\n\n            // assume single argument message\n            if (req.GetArgumentCount() == 1)\n                arg = (string)UnwrapImmutable(req.GetArgument(0));\n\n            // assume stream message\n            if (req.GetArgumentCount() == 2)\n                arg = (string)UnwrapImmutable(req.GetArgument(1));\n\n            if (arg == \"err\")\n                throw new ApplicationException(\"boom\");\n\n            return arg == \"reentrant\";\n        }\n\n        private static object UnwrapImmutable(object item) => item is Immutable<object> ? ((Immutable<object>)item).Value : item;\n\n        private IMayInterleaveStaticPredicateGrain Self { get; set; }\n\n        // this interleaves only when arg == \"reentrant\"\n        // and test predicate will throw when arg = \"err\"\n        public Task<string> One(string arg)\n        {\n            return Task.FromResult(\"one\");\n        }\n\n        public async Task<string> Two()\n        {\n            return await Self.One(\"\") + \" two\";\n        }\n\n        public async Task<string> TwoReentrant()\n        {\n            return await Self.One(\"reentrant\") + \" two\";\n        }\n\n        public Task Exceptional()\n        {\n            return Self.One(\"err\");\n        }\n\n        public async Task SubscribeToStream()\n        {\n            var stream = GetStream();\n\n            await stream.SubscribeAsync((item, _) =>\n            {\n                logger.LogInformation(\"Received stream item: {Item}\", item);\n                return Task.CompletedTask;\n            });\n        }\n\n        public Task PushToStream(string item)\n        {\n            return GetStream().OnNextAsync(item);\n        }\n\n        private IAsyncStream<string> GetStream() =>\n            this.GetStreamProvider(\"sms\").GetStream<string>(\"test-stream-interleave\", Guid.Empty);\n\n        public Task SetSelf(IMayInterleaveStaticPredicateGrain self)\n        {\n            Self = self;\n            return Task.CompletedTask;\n        }\n    }\n\n    [MayInterleave(nameof(MayInterleave))]\n    public class MayInterleaveInstancedPredicateGrain : Grain, IMayInterleaveInstancedPredicateGrain\n    {\n        private readonly ILogger logger;\n\n        public MayInterleaveInstancedPredicateGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public bool MayInterleave(IInvokable req)\n        {\n            // not interested\n            if (req.GetArgumentCount() == 0)\n                return false;\n\n            string arg = null;\n\n            // assume single argument message\n            if (req.GetArgumentCount() == 1)\n                arg = (string)UnwrapImmutable(req.GetArgument(0));\n\n            // assume stream message\n            if (req.GetArgumentCount() == 2)\n                arg = (string)UnwrapImmutable(req.GetArgument(1));\n\n            if (arg == \"err\")\n                throw new ApplicationException(\"boom\");\n\n            return arg == \"reentrant\";\n        }\n\n        private static object UnwrapImmutable(object item) => item is Immutable<object> ? ((Immutable<object>)item).Value : item;\n\n        private IMayInterleaveInstancedPredicateGrain Self { get; set; }\n\n        // this interleaves only when arg == \"reentrant\"\n        // and test predicate will throw when arg = \"err\"\n        public Task<string> One(string arg)\n        {\n            return Task.FromResult(\"one\");\n        }\n\n        public async Task<string> Two()\n        {\n            return await Self.One(\"\") + \" two\";\n        }\n\n        public async Task<string> TwoReentrant()\n        {\n            return await Self.One(\"reentrant\") + \" two\";\n        }\n\n        public Task Exceptional()\n        {\n            return Self.One(\"err\");\n        }\n\n        public async Task SubscribeToStream()\n        {\n            var stream = GetStream();\n\n            await stream.SubscribeAsync((item, _) =>\n            {\n                logger.LogInformation(\"Received stream item: {Item}\", item);\n                return Task.CompletedTask;\n            });\n        }\n\n        public Task PushToStream(string item)\n        {\n            return GetStream().OnNextAsync(item);\n        }\n\n        private IAsyncStream<string> GetStream() =>\n            this.GetStreamProvider(\"sms\").GetStream<string>(\"test-stream-interleave\", Guid.Empty);\n\n        public Task SetSelf(IMayInterleaveInstancedPredicateGrain self)\n        {\n            Self = self;\n            return Task.CompletedTask;\n        }\n    }\n\n    [Reentrant]\n    public class ReentrantSelfManagedGrain1 : Grain, IReentrantSelfManagedGrain\n    {\n        private long destination;\n        private readonly ILogger logger;\n\n        public ReentrantSelfManagedGrain1(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetCounter()\n        {\n            return Task.FromResult(1);\n        }\n\n        public Task SetDestination(long id)\n        {\n            destination = id;\n            return Task.CompletedTask;\n        }\n\n        public Task Ping(int seconds)\n        {\n            logger.LogInformation(\"Start Ping({Seconds})\", seconds);\n            var start = DateTime.UtcNow;\n            var end = start + TimeSpan.FromSeconds(seconds);\n            int foo = 0;\n            while (DateTime.UtcNow < end)\n            {\n                foo++;\n                if (foo > 100000)\n                    foo = 0;\n            }\n\n            logger.LogInformation(\"Before GetCounter - OtherId={OtherId}\", destination);\n            IReentrantSelfManagedGrain otherGrain = GrainFactory.GetGrain<IReentrantSelfManagedGrain>(destination);\n            var ctr = otherGrain.GetCounter();\n            logger.LogInformation(\"After GetCounter() - returning promise\");\n            return ctr;\n        }\n    }\n\n    public class NonReentrantSelfManagedGrain1 : Grain, INonReentrantSelfManagedGrain\n    {\n        private long destination;\n        private readonly ILogger logger;\n\n        public NonReentrantSelfManagedGrain1(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetCounter()\n        {\n            return Task.FromResult(1);\n        }\n\n        public Task SetDestination(long id)\n        {\n            destination = id;\n            return Task.CompletedTask;\n        }\n\n        public Task Ping(int seconds)\n        {\n            logger.LogInformation(\"Start Ping({Seconds})\", seconds);\n            var start = DateTime.UtcNow;\n            var end = start + TimeSpan.FromSeconds(seconds);\n            int foo = 0;\n            while (DateTime.UtcNow < end)\n            {\n                foo++;\n                if (foo > 100000)\n                    foo = 0;\n            }\n\n            logger.LogInformation(\"Before GetCounter - OtherId={OtherId}\", destination);\n            INonReentrantSelfManagedGrain otherGrain = GrainFactory.GetGrain<INonReentrantSelfManagedGrain>(destination);\n            var ctr = otherGrain.GetCounter();\n            logger.LogInformation(\"After GetCounter() - returning promise\");\n            return ctr;\n        }\n    }\n\n    [Reentrant]\n    public class FanOutGrain : Grain, IFanOutGrain\n    {\n        private readonly ILogger logger;\n        private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);\n\n        public FanOutGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task FanOutReentrant(int offset, int num)\n        {\n            IReentrantTaskGrain[] fanOutGrains = await InitTaskGrains_Reentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                //Task promise = fanOutGrains[i].Ping(OneSecond);\n                Task promise = fanOutGrains[i].GetCounter();\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains with offset={Offset}\", num, offset);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutNonReentrant(int offset, int num)\n        {\n            INonReentrantTaskGrain[] fanOutGrains = await InitTaskGrains_NonReentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                //Task promise = fanOutGrains[i].Ping(OneSecond);\n                Task promise = fanOutGrains[i].GetCounter();\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutReentrant_Chain(int offset, int num)\n        {\n            IReentrantTaskGrain[] fanOutGrains = await InitTaskGrains_Reentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out chain calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].Ping(OneSecond);\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains with offset={offset}\", num, offset);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutNonReentrant_Chain(int offset, int num)\n        {\n            INonReentrantTaskGrain[] fanOutGrains = await InitTaskGrains_NonReentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out chain calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].Ping(OneSecond);\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        private async Task<IReentrantTaskGrain[]> InitTaskGrains_Reentrant(int offset, int num)\n        {\n            IReentrantTaskGrain[] fanOutGrains = new IReentrantTaskGrain[num];\n\n            logger.LogInformation(\"Creating {Count} fan-out reentrant worker grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                int idx = offset + i;\n                IReentrantTaskGrain grain = GrainFactory.GetGrain<IReentrantTaskGrain>(idx);\n                fanOutGrains[i] = grain;\n                int next = offset + ((i + 1) % num);\n                Task promise = grain.SetDestination(next);\n                promises.Add(promise);\n            }\n            await Task.WhenAll(promises);\n            return fanOutGrains;\n        }\n        private async Task<INonReentrantTaskGrain[]> InitTaskGrains_NonReentrant(int offset, int num)\n        {\n            INonReentrantTaskGrain[] fanOutGrains = new INonReentrantTaskGrain[num];\n\n            logger.LogInformation(\"Creating {Count} fan-out non-reentrant worker grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                int idx = offset + i;\n                INonReentrantTaskGrain grain = GrainFactory.GetGrain<INonReentrantTaskGrain>(idx);\n                fanOutGrains[i] = grain;\n                int next = offset + ((i + 1) % num);\n                Task promise = grain.SetDestination(next);\n                promises.Add(promise);\n            }\n            await Task.WhenAll(promises);\n            return fanOutGrains;\n        }\n    }\n\n    [Reentrant]\n    public class FanOutACGrain : Grain, IFanOutACGrain\n    {\n        private readonly ILogger logger;\n        private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);\n\n        public FanOutACGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task FanOutACReentrant(int offset, int num)\n        {\n            IReentrantSelfManagedGrain[] fanOutGrains = await InitACGrains_Reentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].GetCounter();\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutACNonReentrant(int offset, int num)\n        {\n            INonReentrantSelfManagedGrain[] fanOutGrains = await InitACGrains_NonReentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].GetCounter();\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutACReentrant_Chain(int offset, int num)\n        {\n            IReentrantSelfManagedGrain[] fanOutGrains = await InitACGrains_Reentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].Ping(OneSecond.Seconds);\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        public async Task FanOutACNonReentrant_Chain(int offset, int num)\n        {\n            INonReentrantSelfManagedGrain[] fanOutGrains = await InitACGrains_NonReentrant(offset, num);\n\n            logger.LogInformation(\"Starting fan-out calls to {Count} grains\", num);\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < num; i++)\n            {\n                Task promise = fanOutGrains[i].Ping(OneSecond.Seconds);\n                promises.Add(promise);\n            }\n            logger.LogInformation(\"Waiting for responses from {Count} grains\", num);\n            await Task.WhenAll(promises);\n            logger.LogInformation(\"Received {Count} responses\", num);\n        }\n\n        private async Task<IReentrantSelfManagedGrain[]> InitACGrains_Reentrant(int offset, int num)\n        {\n            var fanOutGrains = new IReentrantSelfManagedGrain[num];\n            List<Task> promises = new List<Task>();\n            logger.LogInformation(\"Creating {Count} fan-out reentrant worker grains with offset={Offset}\", num, offset);\n            for (int i = 0; i < num; i++)\n            {\n                int idx = offset + i;\n                var grain = GrainFactory.GetGrain<IReentrantSelfManagedGrain>(idx);\n                fanOutGrains[i] = grain;\n                int next = offset + ((i + 1) % num);\n                Task promise = grain.SetDestination(next);\n                promises.Add(promise);\n            }\n            await Task.WhenAll(promises);\n            return fanOutGrains;\n        }\n\n        private async Task<INonReentrantSelfManagedGrain[]> InitACGrains_NonReentrant(int offset, int num)\n        {\n            var fanOutGrains = new INonReentrantSelfManagedGrain[num];\n            List<Task> promises = new List<Task>();\n            logger.LogInformation(\"Creating {Count} fan-out non-reentrant worker grains with offset={offset}\", num, offset);\n            for (int i = 0; i < num; i++)\n            {\n                int idx = offset + i;\n                var grain = GrainFactory.GetGrain<INonReentrantSelfManagedGrain>(idx);\n                fanOutGrains[i] = grain;\n                int next = offset + ((i + 1) % num);\n                Task promise = grain.SetDestination(next);\n                promises.Add(promise);\n            }\n            await Task.WhenAll(promises);\n            return fanOutGrains;\n        }\n    }\n\n    [Reentrant]\n    public class ReentrantTaskGrain : Grain, IReentrantTaskGrain\n    {\n        private readonly ILogger logger;\n        private long otherId;\n        private int count;\n\n        public ReentrantTaskGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task SetDestination(long id)\n        {\n            otherId = id;\n            return Task.CompletedTask;\n        }\n\n        public async Task Ping(TimeSpan wait)\n        {\n            logger.LogInformation(\"Ping Delay={Delay}\", wait);\n            await Task.Delay(wait);\n            logger.LogInformation(\"Before GetCounter - OtherId={OtherId}\", otherId);\n            var otherGrain = GrainFactory.GetGrain<IReentrantTaskGrain>(otherId);\n            var ctr = await otherGrain.GetCounter();\n            logger.LogInformation(\"After GetCounter() - got value={Counter}\", ctr);\n        }\n\n        public Task<int> GetCounter()\n        {\n            return Task.FromResult(++count);\n        }\n    }\n\n    public class NonReentrantTaskGrain : Grain, INonReentrantTaskGrain\n    {\n        private readonly ILogger logger;\n        private long otherId;\n        private int count;\n\n        public NonReentrantTaskGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task SetDestination(long id)\n        {\n            otherId = id;\n            return Task.CompletedTask;\n        }\n\n        public async Task Ping(TimeSpan wait)\n        {\n            logger.LogInformation(\"Ping Delay={Delay}\", wait);\n            await Task.Delay(wait);\n            logger.LogInformation(\"Before GetCounter - OtherId={OtherId}\", otherId);\n            var otherGrain = GrainFactory.GetGrain<INonReentrantTaskGrain>(otherId);\n            var ctr = await otherGrain.GetCounter();\n            logger.LogInformation(\"After GetCounter() - got value={Counter}\", ctr);\n        }\n\n        public Task<int> GetCounter()\n        {\n            return Task.FromResult(++count);\n        }\n    }\n\n    [MayInterleave(nameof(WillInterleave))]\n    public class CallOrderingGrain : Grain, ICallOrderingGrain\n    {\n        private readonly List<string> _log = new();\n        private TaskCompletionSource _blocker = new(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        public static bool WillInterleave(IInvokable req)\n        {\n            return req.GetMethodName() == nameof(MethodA)  // MethodA allows interleaving\n                || req.GetMethodName() == nameof(Unblock); // Unblock allows interleaving\n        }\n\n        public async Task MethodA()\n        {\n            _log.Add(\"enter:A\");\n            await _blocker.Task;\n            _log.Add(\"exit:A\");\n        }\n\n        public async Task MethodB()\n        {\n            _log.Add(\"enter:B\");\n            await _blocker.Task;\n            _log.Add(\"exit:B\");\n        }\n\n        public Task Unblock()\n        {\n            _blocker.TrySetResult();\n            return Task.CompletedTask;\n        }\n\n        public Task Reset()\n        {\n            _log.Clear();\n            _blocker = new(TaskCreationOptions.RunContinuationsAsynchronously);\n            return Task.CompletedTask;\n        }\n\n        public Task<List<string>> GetLog() => Task.FromResult(_log.ToList());\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ReminderTestGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class ReminderTestGrain : Grain, IReminderTestGrain, IRemindable\n    {\n        public async Task<bool> IsReminderExists(string reminderName)\n        {\n            var reminder = await this.GetReminder(reminderName);\n            return reminder != null;\n        }\n\n        public Task AddReminder(string reminderName) => this.RegisterOrUpdateReminder(reminderName, TimeSpan.FromDays(1), TimeSpan.FromDays(1));\n\n        public async Task RemoveReminder(string reminderName)\n        {\n            var r = await this.GetReminder(reminderName) ?? throw new Exception(\"Reminder not found\");\n            await this.UnregisterReminder(r);\n        }\n\n        public Task ReceiveReminder(string reminderName, Orleans.Runtime.TickStatus status) => throw new NotSupportedException();\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/RequestContextTestGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class RequestContextTestGrain : Grain, IRequestContextTestGrain\n    {\n        public Task<string> TraceIdEcho()\n        {\n            return Task.FromResult(RequestContext.Get(\"TraceId\") as string);\n        }\n\n        public Task<string> TraceIdDoubleEcho()\n        {\n            var grain = GrainFactory.GetGrain<IRequestContextTestGrain>((new Random()).Next());\n            return grain.TraceIdEcho();\n        }\n\n        public Task<string> TraceIdDelayedEcho1()\n        {\n            return Task.Factory.StartNew(() => RequestContext.Get(\"TraceId\") as string);\n        }\n\n        public async Task<string> TraceIdDelayedEcho2()\n        {\n            await Task.CompletedTask;\n            return RequestContext.Get(\"TraceId\") as string;\n        }\n\n        public Task<Guid> E2EActivityId()\n        {\n            return Task.FromResult(RequestContext.ReentrancyId);\n        }\n    }\n\n    public class RequestContextTaskGrain : Grain, IRequestContextTaskGrain\n    {\n        private readonly ILogger logger;\n\n        public RequestContextTaskGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public Task<string> TraceIdEcho()\n        {\n            string traceId = RequestContext.Get(\"TraceId\") as string;\n            logger.LogInformation(\"{Method}: TraceId={TraceId}\", \"TraceIdEcho\", traceId);\n            return Task.FromResult(traceId);\n        }\n\n        public Task<string> TraceIdDoubleEcho()\n        {\n            var grain = GrainFactory.GetGrain<IRequestContextTaskGrain>((new Random()).Next());\n            return grain.TraceIdEcho();\n        }\n\n        public Task<string> TraceIdDelayedEcho1()\n        {\n            string method = \"TraceIdDelayedEcho1\";\n            logger.LogInformation(\"{Method}: Entered\", method);\n            string traceIdOutside = RequestContext.Get(\"TraceId\") as string;\n            logger.LogInformation(\"{Method}: Outside TraceId={TraceId}\", method, traceIdOutside);\n\n            return Task.Factory.StartNew(() =>\n            {\n                string traceIdInside = RequestContext.Get(\"TraceId\") as string;\n                logger.LogInformation(\"{Method}: Inside TraceId={TraceId}\", method, traceIdInside);\n                return traceIdInside;\n            });\n        }\n\n        public Task<string> TraceIdDelayedEcho2()\n        {\n            string method = \"TraceIdDelayedEcho2\";\n            logger.LogInformation(\"{Method}: Entered\", method);\n            string traceIdOutside = RequestContext.Get(\"TraceId\") as string;\n            logger.LogInformation(\"{Method}: Outside TraceId={TraceId}\", method, traceIdOutside);\n\n            return Task.CompletedTask.ContinueWith(task =>\n            {\n                string traceIdInside = RequestContext.Get(\"TraceId\") as string;\n                logger.LogInformation(\"{Method}: Inside TraceId={TraceId}\", method, traceIdInside);\n                return traceIdInside;\n            });\n        }\n\n        public async Task<string> TraceIdDelayedEchoAwait()\n        {\n            string method = \"TraceIdDelayedEchoAwait\";\n            logger.LogInformation(\"{Method}: Entered\", method);\n            string traceIdOutside = RequestContext.Get(\"TraceId\") as string;\n            logger.LogInformation(\"{Method}: Outside TraceId={TraceId}\", method, traceIdOutside);\n\n            string traceId = await Task.CompletedTask.ContinueWith(task =>\n            {\n                string traceIdInside = RequestContext.Get(\"TraceId\") as string;\n                logger.LogInformation(\"{Method}: Inside TraceId={TraceId}\", method, traceIdInside);\n                return traceIdInside;\n            });\n            logger.LogInformation(\"{Method}: After await TraceId={TraceId}\", \"TraceIdDelayedEchoAwait\", traceId);\n            return traceId;\n        }\n\n        public Task<string> TraceIdDelayedEchoTaskRun()\n        {\n            string method = \"TraceIdDelayedEchoTaskRun\";\n            logger.LogInformation(\"{Method}: Entered\", method);\n            string traceIdOutside = RequestContext.Get(\"TraceId\") as string;\n            logger.LogInformation(\"{Method}: Outside TraceId={TraceId}\", method, traceIdOutside);\n\n            return Task.Run(() =>\n            {\n                string traceIdInside = RequestContext.Get(\"TraceId\") as string;\n                logger.LogInformation(\"{Method}: Inside TraceId={TraceId}\", method, traceIdInside);\n                return traceIdInside;\n            });\n        }\n\n        public Task<Guid> E2EActivityId()\n        {\n            return Task.FromResult(RequestContext.ReentrancyId);\n        }\n\n        public async Task<Tuple<string, string>> TestRequestContext()\n        {\n            string bar1 = null;\n            RequestContext.Set(\"jarjar\", \"binks\");\n\n            Task task = Task.Factory.StartNew(() =>\n            {\n                bar1 = (string)RequestContext.Get(\"jarjar\");\n                logger.LogInformation(\"jarjar inside Task.Factory.StartNew = {Bar}.\", bar1);\n            });\n\n            string bar2 = null;\n            Task ac = Task.Factory.StartNew(() =>\n            {\n                bar2 = (string)RequestContext.Get(\"jarjar\");\n                logger.LogInformation(\"jarjar inside Task.StartNew  = {Bar}.\", bar2);\n            });\n\n            await Task.WhenAll(task, ac);\n            return new Tuple<string, string>(bar1, bar2);\n        }\n    }\n\n    public class RequestContextProxyGrain : Grain, IRequestContextProxyGrain\n    {\n        public Task<Guid> E2EActivityId()\n        {\n            var grain = GrainFactory.GetGrain<IRequestContextTestGrain>((new Random()).Next());\n            return grain.E2EActivityId();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/RetryTestGrain.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.DurableJobs;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\npublic class RetryTestGrain : Grain, IRetryTestGrain, IDurableJobHandler\n{\n    private readonly Dictionary<string, TaskCompletionSource> _jobSuccessStatus = new();\n    private readonly Dictionary<string, int> _jobExecutionAttempts = new();\n    private readonly Dictionary<string, List<int>> _jobDequeueCountHistory = new();\n    private readonly Dictionary<string, IJobRunContext> _finalJobContexts = new();\n    private readonly ILocalDurableJobManager _localDurableJobManager;\n    private readonly ILogger<RetryTestGrain> _logger;\n\n    public RetryTestGrain(ILocalDurableJobManager localDurableJobManager, ILogger<RetryTestGrain> logger)\n    {\n        _localDurableJobManager = localDurableJobManager;\n        _logger = logger;\n    }\n\n    public Task<bool> HasJobSucceeded(string jobId)\n    {\n        return Task.FromResult(_jobSuccessStatus.TryGetValue(jobId, out var tcs) && tcs.Task.IsCompleted);\n    }\n\n    public Task ExecuteJobAsync(IJobRunContext ctx, CancellationToken cancellationToken)\n    {\n        var jobId = ctx.Job.Id;\n        \n        // Initialize tracking if this is the first attempt\n        if (!_jobExecutionAttempts.ContainsKey(jobId))\n        {\n            _jobExecutionAttempts[jobId] = 0;\n            _jobDequeueCountHistory[jobId] = new List<int>();\n        }\n\n        // Track this attempt\n        _jobExecutionAttempts[jobId]++;\n        _jobDequeueCountHistory[jobId].Add(ctx.DequeueCount);\n\n        _logger.LogInformation(\n            \"Job {JobId} execution attempt {Attempt}, DequeueCount: {DequeueCount}\",\n            jobId,\n            _jobExecutionAttempts[jobId],\n            ctx.DequeueCount);\n\n        // Check if we should fail based on metadata\n        if (ctx.Job.Metadata is not null && ctx.Job.Metadata.TryGetValue(\"FailUntilAttempt\", out var failUntilAttemptStr))\n        {\n            if (int.TryParse(failUntilAttemptStr, out var failUntilAttempt))\n            {\n                if (ctx.DequeueCount < failUntilAttempt)\n                {\n                    _logger.LogWarning(\n                        \"Job {JobId} intentionally failing on attempt {Attempt} (DequeueCount: {DequeueCount}, FailUntilAttempt: {FailUntilAttempt})\",\n                        jobId,\n                        _jobExecutionAttempts[jobId],\n                        ctx.DequeueCount,\n                        failUntilAttempt);\n                    \n                    throw new InvalidOperationException($\"Simulated failure for job {jobId} on attempt {_jobExecutionAttempts[jobId]}\");\n                }\n            }\n        }\n\n        // Job succeeded\n        _logger.LogInformation(\"Job {JobId} succeeded on attempt {Attempt}\", jobId, _jobExecutionAttempts[jobId]);\n        _finalJobContexts[jobId] = ctx;\n        _jobSuccessStatus[jobId].SetResult();\n        \n        return Task.CompletedTask;\n    }\n\n    public async Task<DurableJob> ScheduleJobAsync(string jobName, DateTimeOffset scheduledTime, IReadOnlyDictionary<string, string> metadata = null)\n    {\n        var request = new ScheduleJobRequest\n        {\n            Target = this.GetGrainId(),\n            JobName = jobName,\n            DueTime = scheduledTime,\n            Metadata = metadata\n        };\n        var job = await _localDurableJobManager.ScheduleJobAsync(request, CancellationToken.None);\n        \n        _jobSuccessStatus[job.Id] = new TaskCompletionSource();\n        \n        return job;\n    }\n\n    public async Task WaitForJobToSucceed(string jobId)\n    {\n        if (!_jobSuccessStatus.TryGetValue(jobId, out var tcs))\n        {\n            // The job might not have been scheduled on this grain\n            _jobSuccessStatus[jobId] = new TaskCompletionSource();\n            tcs = _jobSuccessStatus[jobId];\n        }\n\n        await tcs.Task;\n    }\n\n    public Task<int> GetJobExecutionAttemptCount(string jobId)\n    {\n        if (!_jobExecutionAttempts.TryGetValue(jobId, out var count))\n        {\n            throw new InvalidOperationException($\"Job {jobId} has not been attempted or was not scheduled on this grain.\");\n        }\n\n        return Task.FromResult(count);\n    }\n\n    public Task<List<int>> GetJobDequeueCountHistory(string jobId)\n    {\n        if (!_jobDequeueCountHistory.TryGetValue(jobId, out var history))\n        {\n            throw new InvalidOperationException($\"Job {jobId} has not been attempted or was not scheduled on this grain.\");\n        }\n\n        return Task.FromResult(history);\n    }\n\n    public Task<IJobRunContext> GetFinalJobRun(string jobId)\n    {\n        if (!_finalJobContexts.TryGetValue(jobId, out var ctx))\n        {\n            throw new InvalidOperationException($\"Job {jobId} has not succeeded or was not scheduled on this grain.\");\n        }\n\n        return Task.FromResult(ctx);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/RoundtripSerializationGrain.cs",
    "content": "using System.Collections.Immutable;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class RoundtripSerializationGrain : Grain, IRoundtripSerializationGrain\n    {\n        public Task<CampaignEnemyTestType> GetEnemyType()\n        {\n            return Task.FromResult(CampaignEnemyTestType.Enemy2);\n        }\n\n        public Task<object> GetClosedGenericValue()\n        {\n            // use a closed generic that is unlikely to be pre-registered\n            var result = new List<ImmutableList<HashSet<Tuple<int, string>>>>();\n            return Task.FromResult((object)result);\n        }\n\n        // test record support\n        public Task<RetVal> GetRetValForParamVal(ParamVal param) => Task.FromResult(new RetVal(param.Value));\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SampleStreamingGrain.cs",
    "content": "using System.Runtime.CompilerServices;\nusing Microsoft.Extensions.Logging;\nusing Orleans;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class SampleConsumerObserver<T> : IAsyncObserver<T>\n    {\n        private readonly SampleStreaming_ConsumerGrain hostingGrain;\n\n        internal SampleConsumerObserver(SampleStreaming_ConsumerGrain hostingGrain)\n        {\n            this.hostingGrain = hostingGrain;\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken token = null)\n        {\n            hostingGrain.logger.LogInformation(\"OnNextAsync(item={Item}, token={Token})\", item, token != null ? token.ToString() : \"null\");\n            hostingGrain.numConsumedItems++;\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            hostingGrain.logger.LogInformation(\"OnCompletedAsync()\");\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            hostingGrain.logger.LogInformation(ex, \"OnErrorAsync()\");\n            return Task.CompletedTask;\n        }\n    }\n\n    public class SampleStreaming_ProducerGrain : Grain, ISampleStreaming_ProducerGrain\n    {\n        private IAsyncStream<int> producer;\n        private int numProducedItems;\n        private IDisposable producerTimer;\n        internal ILogger logger;\n        internal readonly static string RequestContextKey = \"RequestContextField\";\n        internal readonly static string RequestContextValue = \"JustAString\";\n\n        public SampleStreaming_ProducerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            numProducedItems = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task BecomeProducer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeProducer\");\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            producer = streamProvider.GetStream<int>(streamNamespace, streamId);\n            return Task.CompletedTask;\n        }\n\n        public Task StartPeriodicProducing()\n        {\n            logger.LogInformation(\"StartPeriodicProducing\");\n            producerTimer = this.RegisterGrainTimer(TimerCallback, TimeSpan.Zero, TimeSpan.FromMilliseconds(10));\n            return Task.CompletedTask;\n        }\n\n        public Task StopPeriodicProducing()\n        {\n            logger.LogInformation(\"StopPeriodicProducing\");\n            producerTimer.Dispose();\n            producerTimer = null;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetNumberProduced()\n        {\n            logger.LogInformation(\"GetNumberProduced {Count}\", numProducedItems);\n            return Task.FromResult(numProducedItems);\n        }\n\n        public Task ClearNumberProduced()\n        {\n            numProducedItems = 0;\n            return Task.CompletedTask;\n        }\n\n        public Task Produce()\n        {\n            return Fire();\n        }\n\n        private Task TimerCallback()\n        {\n            return producerTimer != null? Fire(): Task.CompletedTask;\n        }\n\n        private async Task Fire([CallerMemberName] string caller = null)\n        {\n            RequestContext.Set(RequestContextKey, RequestContextValue);\n            await producer.OnNextAsync(numProducedItems);\n            numProducedItems++;\n            logger.LogInformation(\"{Caller} (item count={Count})\", caller, numProducedItems);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n    }\n\n    public class SampleStreaming_ConsumerGrain : Grain, ISampleStreaming_ConsumerGrain\n    {\n        private IAsyncObservable<int> consumer;\n        internal int numConsumedItems;\n        internal ILogger logger;\n        private IAsyncObserver<int> consumerObserver;\n        private StreamSubscriptionHandle<int> consumerHandle;\n\n        public SampleStreaming_ConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            numConsumedItems = 0;\n            consumerHandle = null;\n            return Task.CompletedTask;\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeConsumer\");\n            consumerObserver = new SampleConsumerObserver<int>(this);\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            consumer = streamProvider.GetStream<int>(streamNamespace, streamId);\n            consumerHandle = await consumer.SubscribeAsync(consumerObserver);\n        }\n\n        public async Task StopConsuming()\n        {\n            logger.LogInformation(\"StopConsuming\");\n            if (consumerHandle != null)\n            {\n                await consumerHandle.UnsubscribeAsync();\n                consumerHandle = null;\n            }\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            return Task.FromResult(numConsumedItems);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n    }\n\n    public class SampleStreaming_InlineConsumerGrain : Grain, ISampleStreaming_InlineConsumerGrain\n    {\n        private IAsyncObservable<int> consumer;\n        internal int numConsumedItems;\n        internal ILogger logger;\n        private StreamSubscriptionHandle<int> consumerHandle;\n\n        public SampleStreaming_InlineConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation( \"OnActivateAsync\" );\n            numConsumedItems = 0;\n            consumerHandle = null;\n            return Task.CompletedTask;\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation( \"BecomeConsumer\" );\n            IStreamProvider streamProvider = this.GetStreamProvider( providerToUse );\n            consumer = streamProvider.GetStream<int>(streamNamespace, streamId);\n            consumerHandle = await consumer.SubscribeAsync( OnNextAsync, OnErrorAsync, OnCompletedAsync );\n        }\n\n        public async Task StopConsuming()\n        {\n            logger.LogInformation( \"StopConsuming\" );\n            if ( consumerHandle != null )\n            {\n                await consumerHandle.UnsubscribeAsync();\n                //consumerHandle.Dispose();\n                consumerHandle = null;\n            }\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            return Task.FromResult( numConsumedItems );\n        }\n\n        public Task OnNextAsync( int item, StreamSequenceToken token = null )\n        {\n            logger.LogInformation( \"OnNextAsync({Item}{Token})\", item, token != null ? token.ToString() : \"null\" );\n            numConsumedItems++;\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            logger.LogInformation( \"OnCompletedAsync()\" );\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync( Exception ex )\n        {\n            logger.LogInformation(ex,  \"OnErrorAsync()\");\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SchedulerGrain.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Orleans.DurableJobs;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\npublic class SchedulerGrain : Grain, ISchedulerGrain\n{\n    private readonly ILocalDurableJobManager _localDurableJobManager;\n    private readonly IGrainFactory _grainFactory;\n    private readonly ILogger<SchedulerGrain> _logger;\n\n    public SchedulerGrain(\n        ILocalDurableJobManager localDurableJobManager,\n        IGrainFactory grainFactory,\n        ILogger<SchedulerGrain> logger)\n    {\n        _localDurableJobManager = localDurableJobManager;\n        _grainFactory = grainFactory;\n        _logger = logger;\n    }\n\n    public async Task<DurableJob> ScheduleJobOnAnotherGrainAsync(string targetGrainKey, string jobName, DateTimeOffset scheduledTime)\n    {\n        var targetGrain = _grainFactory.GetGrain<IDurableJobGrain>(targetGrainKey);\n        var targetGrainId = targetGrain.GetGrainId();\n\n        _logger.LogInformation(\n            \"Scheduling job {JobName} on grain {TargetGrainKey} from grain {SourceGrain}\",\n            jobName,\n            targetGrainKey,\n            this.GetPrimaryKeyString());\n\n        var request = new ScheduleJobRequest\n        {\n            Target = targetGrainId,\n            JobName = jobName,\n            DueTime = scheduledTime,\n            Metadata = null\n        };\n        var job = await _localDurableJobManager.ScheduleJobAsync(request, CancellationToken.None);\n\n        return job;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SerializationGenerationGrain.cs",
    "content": "﻿namespace TestGrains\n{\n    using System.Collections.Generic;\n    using System.Linq;\n    using Orleans;\n    using UnitTests.GrainInterfaces;\n    public class SerializationGenerationGrain : Grain<SerializationGenerationGrain.MyState>, ISerializationGenerationGrain\n    {\n        public Task<object> RoundTripObject(object input)\n        {\n            return Task.FromResult(input);\n        }\n\n        public Task<SomeStruct> RoundTripStruct(SomeStruct input)\n        {\n            return Task.FromResult(input);\n        }\n\n        public Task<SomeAbstractClass> RoundTripClass(SomeAbstractClass input)\n        {\n            return Task.FromResult(input);\n        }\n\n        public Task<ISomeInterface> RoundTripInterface(ISomeInterface input)\n        {\n            return Task.FromResult(input);\n        }\n\n        public Task<SomeAbstractClass.SomeEnum> RoundTripEnum(SomeAbstractClass.SomeEnum input)\n        {\n            return Task.FromResult(input);\n        }\n\n        public async Task SetState(SomeAbstractClass input)\n        {\n            this.State.Classes = new List<SomeAbstractClass> { input };\n            this.DeactivateOnIdle();\n            await this.WriteStateAsync();\n        }\n\n        public Task<SomeAbstractClass> GetState()\n        {\n            return Task.FromResult(this.State.Classes.FirstOrDefault());\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class MyState\n        {\n            [Id(0)]\n            public IList<SomeAbstractClass> Classes { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ServiceType.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ServiceType : Grain, IServiceType\n    {\n        public Task<string> A1Method()\n        {\n            return Task.FromResult(\"A1\");\n        }\n        public Task<string> A2Method()\n        {\n            return Task.FromResult(\"A2\");\n        }\n        public Task<string> A3Method()\n        {\n            return Task.FromResult(\"A3\");\n        }\n\n        public Task<string> B1Method()\n        {\n            return Task.FromResult(\"B1\");\n        }\n        public Task<string> B2Method()\n        {\n            return Task.FromResult(\"B2\");\n        }\n        public Task<string> B3Method()\n        {\n            return Task.FromResult(\"B3\");\n        }\n\n        public Task<string> C1Method()\n        {\n            return Task.FromResult(\"C1\");\n        }\n        public Task<string> C2Method()\n        {\n            return Task.FromResult(\"C2\");\n        }\n        public Task<string> C3Method()\n        {\n            return Task.FromResult(\"C3\");\n        }\n\n        public Task<string> D1Method()\n        {\n            return Task.FromResult(\"D1\");\n        }\n        public Task<string> D2Method()\n        {\n            return Task.FromResult(\"D2\");\n        }\n        public Task<string> D3Method()\n        {\n            return Task.FromResult(\"D3\");\n        }\n\n        public Task<string> E1Method()\n        {\n            return Task.FromResult(\"E1\");\n        }\n        public Task<string> E2Method()\n        {\n            return Task.FromResult(\"E2\");\n        }\n        public Task<string> E3Method()\n        {\n            return Task.FromResult(\"E3\");\n        }\n\n        public Task<string> F1Method()\n        {\n            return Task.FromResult(\"F1\");\n        }\n        public Task<string> F2Method()\n        {\n            return Task.FromResult(\"F2\");\n        }\n        public Task<string> F3Method()\n        {\n            return Task.FromResult(\"F3\");\n        }\n\n        public Task<string> ServiceTypeMethod1()\n        {\n            return Task.FromResult(\"ServiceTypeMethod1\");\n        }\n\n        public Task<string> ServiceTypeMethod2()\n        {\n            return Task.FromResult(\"ServiceTypeMethod2\");\n        }\n\n        public Task<string> ServiceTypeMethod3()\n        {\n            return Task.FromResult(\"ServiceTypeMethod3\");\n        }\n\n        Task<string> IC.CommonMethod() => Task.FromResult(\"IC\");\n        Task<string> IA.CommonMethod() => Task.FromResult(\"IA\");\n        Task<string> IB.CommonMethod() => Task.FromResult(\"IB\");\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SiloRoleBasedPlacementGrain.cs",
    "content": "using Orleans.Placement;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    [SiloRoleBasedPlacement]\n    public class SiloRoleBasedPlacementGrain : Grain, ISiloRoleBasedPlacementGrain\n    {\n        public Task<bool> Ping()\n        {\n            return Task.FromResult(true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimpleDIGrain.cs",
    "content": "using System.Runtime.Serialization;\nusing UnitTests.GrainInterfaces;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing System.Runtime.CompilerServices;\n\nnamespace UnitTests.Grains\n{\n    public class DIGrainWithInjectedServices : Grain, IDIGrainWithInjectedServices\n    {\n        private readonly IInjectedService injectedService;\n        private readonly IInjectedScopedService injectedScopedService;\n        private readonly IGrainFactory injectedGrainFactory;\n        private readonly int grainFactoryId;\n        private readonly IGrainContextAccessor grainContextAccessor;\n        private IGrainContext originalGrainContext;\n\n        public DIGrainWithInjectedServices(IInjectedService injectedService, IInjectedScopedService injectedScopedService,  IGrainFactory injectedGrainFactory, IGrainContextAccessor grainContextAccessor)\n        {\n            this.injectedService = injectedService;\n            this.injectedGrainFactory = injectedGrainFactory;\n            this.injectedScopedService = injectedScopedService;\n\n            this.grainFactoryId = RuntimeHelpers.GetHashCode(this.injectedGrainFactory);\n            this.grainContextAccessor = grainContextAccessor;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.originalGrainContext = this.grainContextAccessor.GrainContext;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<long> GetLongValue()\n        {\n            return injectedService.GetTicks();\n        }\n\n        public Task<string> GetStringValue()\n        {\n            return Task.FromResult(this.grainContextAccessor.GrainContext.GrainId.ToString());\n        }\n\n        public Task<string> GetInjectedSingletonServiceValue()\n        {\n            return Task.FromResult(this.injectedService.GetInstanceValue());\n        }\n\n        public Task<string> GetInjectedScopedServiceValue()\n        {\n            return Task.FromResult(this.injectedScopedService.GetInstanceValue());\n        }\n\n        public Task<int> GetGrainFactoryId()\n        {\n            return Task.FromResult(this.grainFactoryId);\n        }\n\n        public Task DoDeactivate()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task AssertCanResolveSameServiceInstances()\n        {\n            if (!ReferenceEquals(this.ServiceProvider.GetRequiredService<IInjectedService>(), this.injectedService)) throw new Exception(\"singleton not equal\");\n            if (!ReferenceEquals(this.ServiceProvider.GetRequiredService<IInjectedScopedService>(), this.injectedScopedService)) throw new Exception(\"scoped not equal\");\n            if (!ReferenceEquals(this.ServiceProvider.GetRequiredService<IGrainContextAccessor>().GrainContext, this.originalGrainContext)) throw new Exception(\"scoped grain activation context not equal\");\n\n            return Task.CompletedTask;\n        }\n    }\n\n    [GrainType(\"explicitly-registered\")]\n    public class ExplicitlyRegisteredSimpleDIGrain : Grain, ISimpleDIGrain\n    {\n        private readonly IInjectedService injectedService;\n        private readonly string someValueThatIsNotRegistered;\n        private readonly int numberOfReleasedInstancesBeforeThisActivation;\n\n        public ExplicitlyRegisteredSimpleDIGrain(IInjectedService injectedService, string someValueThatIsNotRegistered, int numberOfReleasedInstancesBeforeThisActivation)\n        {\n            this.injectedService = injectedService;\n            this.someValueThatIsNotRegistered = someValueThatIsNotRegistered;\n            this.numberOfReleasedInstancesBeforeThisActivation = numberOfReleasedInstancesBeforeThisActivation;\n        }\n\n        public Task<long> GetLongValue()\n        {\n            return Task.FromResult((long)numberOfReleasedInstancesBeforeThisActivation);\n        }\n\n        public Task<string> GetStringValue()\n        {\n            return Task.FromResult(this.someValueThatIsNotRegistered);\n        }\n        public Task DoDeactivate()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    public interface IInjectedService\n    {\n        Task<long> GetTicks();\n        string GetInstanceValue();\n    }\n\n    public class InjectedService : IInjectedService, IDisposable\n    {\n        private readonly string instanceValue = Guid.NewGuid().ToString();\n        private readonly ILogger logger;\n\n        public Task<long> GetTicks()\n        {\n            return Task.FromResult(DateTime.UtcNow.Ticks);\n        }\n        public string GetInstanceValue() => this.instanceValue;\n\n        public InjectedService(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger<InjectedService>();\n        }\n\n        public void Dispose()\n        {\n            logger.LogInformation(\"Disposed instance {Value}\", this.instanceValue);\n        }\n    }\n\n    public interface IInjectedScopedService\n    {\n        string GetInstanceValue();\n    }\n\n    public class InjectedScopedService : IInjectedScopedService, IDisposable\n    {\n        private readonly string instanceValue = Guid.NewGuid().ToString();\n        private readonly ILogger logger;\n\n        public InjectedScopedService(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger<InjectedScopedService>();\n        }\n\n        public void Dispose()\n        {\n            logger.LogInformation(\"Disposed instance {Value}\", this.instanceValue);\n        }\n\n        public string GetInstanceValue() =>  this.instanceValue;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimpleGenericGrain.cs",
    "content": "using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class SimpleGenericGrain<TType> : Grain, ISimpleGenericGrain<TType>\n    {\n        protected TType Value { get; set; }\n\n        public virtual Task Set(TType t)\n        {\n            Value = t;\n            return Task.CompletedTask;\n        }\n\n        public virtual Task Transform()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<TType> Get()\n        {\n            return Task.FromResult(Value);\n        }\n\n        public Task CompareGrainReferences(ISimpleGenericGrain<TType> clientReference)\n        {\n            // Compare reference to this grain created by the client \n            var thisReference = GrainFactory.GetGrain<ISimpleGenericGrain<TType>>(this.GetPrimaryKeyLong());\n            if (!thisReference.Equals(clientReference))\n                throw new Exception(string.Format(\"Case_3: 2 grain references are different, while should have been the same: gr1={0}, gr2={1}\", thisReference, clientReference));\n\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimpleGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    public class SimpleGrain : Grain, ISimpleGrain \n    {\n        public const string SimpleGrainNamePrefix = \"UnitTests.Grains.SimpleG\";\n\n        protected ILogger logger;\n\n        public SimpleGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        protected int A { get; set; }\n        protected int B { get; set; }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"Activate.\");\n            return Task.CompletedTask;\n        }\n\n        public Task SetA(int a)\n        {\n            logger.LogInformation(\"SetA={A}\", a);\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(int b)\n        {\n            this.B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A = A + 1;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetAxB()\n        {\n            return Task.FromResult(A * B);\n        }\n\n        public Task<int> GetAxB(int a, int b)\n        {\n            return Task.FromResult(a * b);\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync.\");\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimpleObserverableGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Utilities;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class SimpleObserverableGrain : Grain, ISimpleObserverableGrain\n    {\n        private readonly ILogger logger;\n        internal int A { get; set; }\n        internal int B { get; set; }\n        internal int EventDelay { get; set; }\n        internal ObserverManager<ISimpleGrainObserver> Observers { get; set; }\n\n        public SimpleObserverableGrain(ILoggerFactory loggerFactory)\n        {\n            EventDelay = 1000;\n            logger = loggerFactory.CreateLogger( $\"{nameof(SimpleObserverableGrain)}-{base.IdentityString}-{base.RuntimeIdentity}\");\n            this.Observers = new ObserverManager<ISimpleGrainObserver>(TimeSpan.FromMinutes(5), logger);\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"Activate.\");\n            return Task.CompletedTask;\n        }\n\n        public async Task SetA(int a)\n        {\n            logger.LogInformation(\"SetA={A}\", a);\n            A = a;\n\n            //If this were run with Task.Run there were no need for the added Unwrap call.\n            //However, Task.Run runs in ThreadPool and not in Orleans TaskScheduler, unlike Task.Factory.StartNew.\n            //See more at https://learn.microsoft.com/dotnet/orleans/grains/external-tasks-and-grains.\n            //The extra task comes from the internal asynchronous lambda due to Task.Delay. For deeper\n            //insight, see at http://blogs.msdn.com/b/pfxteam/archive/2012/02/08/10265476.aspx.\n            await Task.Factory.StartNew(async () =>\n            {\n                await Task.Delay(EventDelay);\n                RaiseStateUpdateEvent();\n            }).Unwrap();\n        }\n\n        public async Task SetB(int b)\n        {\n            this.B = b;\n\n            //If this were run with Task.Run there were no need for the added Unwrap call.\n            //However, Task.Run runs in ThreadPool and not in Orleans TaskScheduler, unlike Task.Factory.StartNew.\n            //See more at https://learn.microsoft.com/dotnet/orleans/grains/external-tasks-and-grains.\n            //The extra task comes from the internal asynchronous lambda due to Task.Delay. For deeper\n            //insight, see at http://blogs.msdn.com/b/pfxteam/archive/2012/02/08/10265476.aspx.\n            await Task.Factory.StartNew(async () =>\n            {\n                await Task.Delay(EventDelay);\n                RaiseStateUpdateEvent();\n            }).Unwrap();\n        }\n\n        public async Task IncrementA()\n        {\n            await SetA(A + 1);\n        }\n\n        public Task<int> GetAxB()\n        {\n            return Task.FromResult(A * B);\n        }\n\n        public Task<int> GetAxB(int a, int b)\n        {\n            return Task.FromResult(a * b);\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n\n        public Task Subscribe(ISimpleGrainObserver observer)\n        {\n            Observers.Subscribe(observer, observer);\n            return Task.CompletedTask;\n        }\n\n        public Task Unsubscribe(ISimpleGrainObserver observer)\n        {\n            Observers.Unsubscribe(observer);\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        protected void RaiseStateUpdateEvent()\n        {\n            Observers.Notify((ISimpleGrainObserver observer) =>\n            {\n                observer.StateChanged(A, B);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimplePersistentGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class SimplePersistentGrain_State\n    {\n        [Id(0)]\n        public int A { get; set; }\n        [Id(1)]\n        public int B { get; set; }\n    }\n\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    public class SimplePersistentGrain : Grain<SimplePersistentGrain_State>, ISimplePersistentGrain\n    {\n        private readonly ILogger logger;\n        private Guid version;\n        \n        public SimplePersistentGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"Activate.\");\n            version = Guid.NewGuid();\n            return base.OnActivateAsync(cancellationToken);\n        }\n        public Task SetA(int a)\n        {\n            State.A = a;\n            return WriteStateAsync();\n        }\n\n        public Task SetA(int a, bool deactivate)\n        {\n            if(deactivate)\n                DeactivateOnIdle();\n            return SetA(a);\n        }\n\n        public Task SetB(int b)\n        {\n            State.B = b;\n            return WriteStateAsync();\n        }\n\n        public Task IncrementA()\n        {\n            State.A++;\n            return WriteStateAsync();\n        }\n\n        public Task<int> GetAxB()\n        {\n            return Task.FromResult(State.A*State.B);\n        }\n\n        public Task<int> GetAxB(int a, int b)\n        {\n            return Task.FromResult(a * b);\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(State.A);\n        }\n\n        public Task<Guid> GetVersion()\n        {\n            return Task.FromResult(version);\n        }\n\n        public Task<object> GetRequestContext()\n        {\n            var info = RequestContext.Get(\"GrainInfo\");\n            return Task.FromResult(info);\n        }\n\n        public Task SetRequestContext(int data)\n        {\n            RequestContext.Set(\"GrainInfo\", data);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SimpleStreams/SimpleSubscriberGrain.cs",
    "content": "using Orleans.BroadcastChannel;\n\nnamespace UnitTests.Grains.BroadcastChannel\n{\n    public interface ISubscriberGrain : IGrainWithStringKey\n    {\n        Task<List<Exception>> GetErrors(ChannelId streamId);\n\n        Task<List<int>> GetValues(ChannelId streamId);\n\n        Task<int> GetOnPublishedCounter();\n\n        Task ThrowsOnReceive(bool throwsOnReceive);\n    }\n\n    public interface ISimpleSubscriberGrain : ISubscriberGrain { }\n\n    public interface IRegexNamespaceSubscriberGrain : ISubscriberGrain { }\n\n    public abstract class SubscriberGrainBase : Grain, ISubscriberGrain, IOnBroadcastChannelSubscribed\n    {\n        private readonly Dictionary<ChannelId, List<int>> _values = new();\n        private readonly Dictionary<ChannelId, List<Exception>> _errors = new();\n        private int _onPublishedCounter = 0;\n        private bool _throwsOnReceive = false;\n\n        public Task<List<Exception>> GetErrors(ChannelId streamId) => _errors.TryGetValue(streamId, out var errors) ? Task.FromResult(errors) : Task.FromResult(new List<Exception>());\n        public Task<List<int>> GetValues(ChannelId streamId) => _values.TryGetValue(streamId, out var values) ? Task.FromResult(values) : Task.FromResult(new List<int>());\n        public Task<int> GetOnPublishedCounter() => Task.FromResult(_onPublishedCounter);\n\n        public Task OnSubscribed(IBroadcastChannelSubscription streamSubscription)\n        {\n            streamSubscription.Attach<int>(item => OnPublished(streamSubscription.ChannelId, item), ex => OnError(streamSubscription.ChannelId, ex));\n            return Task.CompletedTask;\n\n            Task OnPublished(ChannelId id, int item)\n            {\n                _onPublishedCounter++;\n                if (_throwsOnReceive)\n                {\n                    throw new Exception(\"Some error message here\");\n                }\n                if (!_values.TryGetValue(id, out var values))\n                {\n                    _values[id] = values = new List<int>();\n                }\n                values.Add(item);\n                return Task.CompletedTask;\n            }\n\n            Task OnError(ChannelId id, Exception ex)\n            {\n                if (!_errors.TryGetValue(id, out var errors))\n                {\n                    _errors[id] = errors = new List<Exception>();\n                }\n                errors.Add(ex);\n                return Task.CompletedTask;\n            }\n        }\n\n        public Task ThrowsOnReceive(bool throwsOnReceive)\n        {\n            _throwsOnReceive = throwsOnReceive;\n            return Task.CompletedTask;\n        }\n    }\n\n    [ImplicitChannelSubscription]\n    public class SimpleSubscriberGrain : SubscriberGrainBase, ISimpleSubscriberGrain { }\n\n    [RegexImplicitChannelSubscription(\"multiple-namespaces-(.)+\")]\n    public class RegexNamespaceSubscriberGrain : SubscriberGrainBase, IRegexNamespaceSubscriberGrain { }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SlowConsumingGrains/SlowConsumingGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    /// <summary>\n    /// SlowConsumingGrain keep asking to rewind to the first item it received to mimic slow consuming behavior\n    /// </summary>\n    public class SlowConsumingGrain : Grain, ISlowConsumingGrain\n    {\n        private readonly ILogger logger;\n        public SlowObserver<int> ConsumerObserver { get; private set; }\n        public StreamSubscriptionHandle<int> ConsumerHandle { get; set; }\n\n        public SlowConsumingGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            ConsumerHandle = null;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetNumberConsumed()\n        {\n            return Task.FromResult(this.ConsumerObserver.NumConsumed);\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string streamNamespace, string providerToUse)\n        {\n            logger.LogInformation(\"BecomeConsumer\");\n            ConsumerObserver = new SlowObserver<int>(this, logger);\n            IStreamProvider streamProvider = this.GetStreamProvider(providerToUse);\n            var consumer = streamProvider.GetStream<int>(streamNamespace, streamId);\n            ConsumerHandle = await consumer.SubscribeAsync(ConsumerObserver);\n        }\n\n        public async Task StopConsuming()\n        {\n            logger.LogInformation(\"StopConsuming\");\n            if (ConsumerHandle != null)\n            {\n                await ConsumerHandle.UnsubscribeAsync();\n                ConsumerHandle = null;\n            }\n        }\n    }\n\n    /// <summary>\n    /// SlowObserver keep rewind to the first item it received, to mimic slow consuming behavior\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    public class SlowObserver<T> : IAsyncObserver<T>\n    {\n        public int NumConsumed { get; private set; }\n        private readonly ILogger logger;\n        private readonly SlowConsumingGrain slowConsumingGrain;\n        private StreamSequenceToken firstToken;\n\n        internal SlowObserver(SlowConsumingGrain grain, ILogger logger)\n        {\n            NumConsumed = 0;\n            this.slowConsumingGrain = grain;\n            this.logger = logger;\n        }\n\n        public async Task OnNextAsync(T item, StreamSequenceToken token = null)\n        {\n            NumConsumed++;\n\n            if (firstToken == null)\n            {\n                firstToken = token;\n            }\n            else\n            {\n                // slow consumer keep asking for the first item it received to mimic slow consuming behavior\n                this.slowConsumingGrain.ConsumerHandle = await this.slowConsumingGrain.ConsumerHandle.ResumeAsync(this.slowConsumingGrain.ConsumerObserver, firstToken);\n            }\n\n            this.logger.LogInformation(\"Consumer {HashCode} OnNextAsync() received item {Item}, with NumConsumed {NumConsumed}\", this.GetHashCode(), item, NumConsumed);\n        }\n\n        public Task OnCompletedAsync()\n        {\n            this.logger.LogInformation(\"Consumer {HashCode} OnCompletedAsync()\", this.GetHashCode());\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            this.logger.LogInformation(ex, \"Consumer {HashCode} OnErrorAsync()\", this.GetHashCode());\n            return Task.CompletedTask;\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/SpecializedSimpleGenericGrain.cs",
    "content": "namespace UnitTests.Grains\n{\n    public class SpecializedSimpleGenericGrain : SimpleGenericGrain<double>\n    {\n        public override Task Transform()\n        {\n            Value = Value * 2.0;\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerExceptionGrain.cs",
    "content": "using Orleans.Concurrency;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    [StatelessWorker(MaxLocalWorkers)]\n    public class StatelessWorkerExceptionGrain : Grain, IStatelessWorkerExceptionGrain\n    {\n        public const int MaxLocalWorkers = 1;\n\n        public StatelessWorkerExceptionGrain()\n        {\n            throw new Exception(\"oops\");\n        }\n\n        public Task Ping()\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    [StatelessWorker(MaxLocalWorkers, removeIdleWorkers: false)]\n    public class StatelessWorkerGrain : Grain, IStatelessWorkerGrain\n    {\n        public const int MaxLocalWorkers = 1;\n\n        private Guid activationGuid;\n        private readonly List<Tuple<DateTime, DateTime>> calls = new List<Tuple<DateTime, DateTime>>();\n        private readonly ILogger logger;\n        private static readonly HashSet<Guid> allActivationIds = new HashSet<Guid>();\n\n        public StatelessWorkerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            activationGuid = Guid.NewGuid();\n            logger.LogInformation(\"Activate.\");\n            return Task.CompletedTask;\n        }\n\n        public Task LongCall()\n        {\n            int count = 0;\n            lock (allActivationIds)\n            {\n                if (!allActivationIds.Contains(activationGuid))\n                {\n                    allActivationIds.Add(activationGuid);\n                }\n                count = allActivationIds.Count;\n            }\n            DateTime start = DateTime.UtcNow;\n            TaskCompletionSource<bool> resolver = new TaskCompletionSource<bool>();\n            this.RegisterGrainTimer(TimerCallback, resolver, new() { DueTime = TimeSpan.FromSeconds(2), Period = Timeout.InfiniteTimeSpan, Interleave = true });\n            return resolver.Task.ContinueWith(\n                (_) =>\n                {\n                    DateTime stop = DateTime.UtcNow;\n                    calls.Add(new Tuple<DateTime, DateTime>(start, stop));\n                    logger.LogInformation(\"{DurationMilliseconds}\", (stop - start).TotalMilliseconds);\n                    logger.LogInformation(\n                        \"Start {StartDate}, stop {StopDate}, duration {Duration}. #act {Count}\",\n                        LogFormatter.PrintDate(start),\n                        LogFormatter.PrintDate(stop),\n                        stop - start,\n                        count);\n                });\n        }\n\n        private static Task TimerCallback(TaskCompletionSource<bool> state, CancellationToken cancellationToken)\n        {\n            state.SetResult(true);\n            return Task.CompletedTask;\n        }\n\n        public Task<Tuple<Guid, string, List<Tuple<DateTime, DateTime>>>> GetCallStats()\n        {\n            Thread.Sleep(200);\n            string silo = RuntimeIdentity;\n            List<Guid> ids;\n            lock (allActivationIds)\n            {\n                ids = allActivationIds.ToList();\n            }\n\n            logger.LogInformation(\n                \"# AllActivationIds {Count} for silo {Silo}: {Ids}\",\n                ids.Count,\n                silo,\n                Utils.EnumerableToString(ids));\n            return Task.FromResult(Tuple.Create(activationGuid, silo, calls));\n        }\n\n        public Task DummyCall() => Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerScalingGrain.cs",
    "content": "using System.Collections.Concurrent;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\npublic class StatelessWorkerScalingGrainSharedState\n{\n    public SemaphoreSlim Semaphore { get; } = new(0);\n    public ConcurrentDictionary<GrainId, int> ActivationCounts { get; } = new();\n    public ConcurrentDictionary<GrainId, int> WaitingActivations { get; } = new();\n}\n\n[StatelessWorker(maxLocalWorkers: 4)]\npublic class StatelessWorkerScalingGrain : Grain, IStatelessWorkerScalingGrain\n{\n    private readonly StatelessWorkerScalingGrainSharedState _shared;\n\n    public StatelessWorkerScalingGrain(StatelessWorkerScalingGrainSharedState shared)\n    {\n        _shared = shared;\n        _shared.ActivationCounts.AddOrUpdate(this.GetGrainId(), 1, (k, v) => v + 1);\n        _shared.WaitingActivations.TryAdd(this.GetGrainId(), 0);\n    }\n\n    public async Task Wait()\n    {\n        _shared.WaitingActivations.AddOrUpdate(this.GetGrainId(), 1, (k, v) => v + 1);\n        await _shared.Semaphore.WaitAsync();\n        _shared.WaitingActivations.AddOrUpdate(this.GetGrainId(), 0, (k, v) => v - 1);\n    }\n\n    public Task Release()\n    {\n        _shared.Semaphore.Release();\n        return Task.CompletedTask;\n    }\n\n    public Task<int> GetActivationCount() => Task.FromResult(_shared.ActivationCounts[this.GetGrainId()]);\n    public Task<int> GetWaitingCount() => Task.FromResult(_shared.WaitingActivations[this.GetGrainId()]);\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerStreamConsumerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [StatelessWorker(MaxLocalWorkers)]\n    public class StatelessWorkerStreamConsumerGrain : Grain, IStatelessWorkerStreamConsumerGrain\n    {\n        internal const int MaxLocalWorkers = 1;\n        internal const string StreamNamespace = \"StatelessWorkerStreamingNamespace\";\n\n        private readonly ILogger logger;\n\n        public StatelessWorkerStreamConsumerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public Task OnCompletedAsync() => Task.CompletedTask;\n\n        public Task OnErrorAsync(Exception ex) => Task.CompletedTask;\n\n        public Task OnNextAsync(string item, StreamSequenceToken token = null) => Task.CompletedTask;\n\n        public async Task BecomeConsumer(Guid streamId, string providerToUse)\n        {\n            var stream = this.GetStreamProvider(providerToUse).GetStream<string>(StreamNamespace, streamId);\n            _ = await stream.SubscribeAsync(OnNextAsync, OnErrorAsync, OnCompletedAsync);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerStreamProducerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [StatelessWorker(MaxLocalWorkers)]\n    public class StatelessWorkerStreamProducerGrain : Grain, IStatelessWorkerStreamProducerGrain\n    {\n        internal const int MaxLocalWorkers = 1;\n        internal const string StreamNamespace = \"StatelessWorkerStreamingNamespace\";\n\n        private readonly ILogger logger;\n\n        public StatelessWorkerStreamProducerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public async Task Produce(Guid streamId, string providerToUse, string message)\n        {\n            var stream = this.GetStreamProvider(providerToUse).GetStream<string>(StreamNamespace, streamId);\n            await stream.OnNextAsync(message);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatelessWorkerWithMayInterleaveGrain.cs",
    "content": "using Orleans.Concurrency;\nusing Orleans.Serialization.Invocation;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains;\n\n[StatelessWorker(1)] // '1' to force interleaving, otherwise it just creates a new worker\n[MayInterleave(nameof(MayInterleaveMethod))]\npublic class StatelessWorkerWithMayInterleaveGrain : Grain, IStatelessWorkerWithMayInterleaveGrain\n{\n    public static bool MayInterleaveMethod(IInvokable req) => req.GetMethodName() == nameof(GoFast);\n\n    public async Task GoSlow(ICallbackGrainObserver callback)\n    {\n        await callback.WaitAsync();\n    }\n\n    public async Task GoFast(ICallbackGrainObserver callback) \n    {\n        await callback.WaitAsync();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StatsCollectorGrain.cs",
    "content": "﻿using Orleans.Placement;\n\nnamespace UnitTests.Stats\n{\n    [PreferLocalPlacement]\n    public class StatsCollectorGrain : Grain, IStatsCollectorGrain\n    {\n        private long numStatsCalls;\n\n        public Task ReportStatsCalled()\n        {\n            numStatsCalls++;\n            return Task.CompletedTask;\n        }\n        \n        public Task<long> GetReportStatsCallCount()\n        {\n            return Task.FromResult(numStatsCalls);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/StreamBatchingTestConsumerGrain.cs",
    "content": "using Orleans.Streams;\nusing Orleans.Streams.Core;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains.Batching\n{\n    [ImplicitStreamSubscription(StreamBatchingTestConst.BatchingNameSpace)]\n    [ImplicitStreamSubscription(StreamBatchingTestConst.NonBatchingNameSpace)]\n    public class BatchingStreamBatchingTestConsumerGrain : Grain, IStreamBatchingTestConsumerGrain, IStreamSubscriptionObserver\n    {\n        private readonly ConsumptionReport report = new ConsumptionReport();\n        \n        public Task<ConsumptionReport> GetConsumptionReport() => Task.FromResult(this.report);\n\n        public Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            StreamSubscriptionHandle<string> handle = handleFactory.Create<string>();\n            return (handle.StreamId.GetNamespace() == StreamBatchingTestConst.BatchingNameSpace)\n                ? handle.ResumeAsync(OnNextBatch)\n                : handle.ResumeAsync(OnNext);\n        }\n\n        private async Task OnNextBatch(IList<SequentialItem<string>> items)\n        {\n            this.report.Consumed += items.Count;\n            this.report.MaxBatchSize = Math.Max(this.report.MaxBatchSize, items.Count);\n            await Task.Delay(500);\n        }\n\n        private Task OnNext(string item, StreamSequenceToken token)\n        {\n            this.report.Consumed++;\n            this.report.MaxBatchSize = 1;\n            return Task.CompletedTask;\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Grains/TestGrains/StreamCheckpoint.cs",
    "content": "﻿using Orleans.Streams;\n\nnamespace TestGrains\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class StreamCheckpoint<TState>\n    {\n        [Orleans.Id(0)]\n        public Guid StreamGuid { get; set; }\n        [Orleans.Id(1)]\n        public string StreamNamespace { get; set; }\n        [Orleans.Id(2)]\n        public StreamSequenceToken StartToken { get; set; }\n        [Orleans.Id(3)]\n        public StreamSequenceToken LastProcessedToken { get; set; }\n        [Orleans.Id(4)]\n        public TState Accumulator { get; set; }\n\n        public StreamSequenceToken RecoveryToken { get { return LastProcessedToken ?? StartToken; } }\n\n        public bool IsDuplicate(StreamSequenceToken sequenceToken)\n        {\n            // This is the first event, so it can't be a duplicate\n            if (StartToken == null)\n                return false;\n\n            // if we have processed events, compare with the sequence token of last event we processed.\n            if (LastProcessedToken != null)\n            {\n                // if Last processed is not older than this sequence token, then this token is a duplicate\n                return !LastProcessedToken.Older(sequenceToken);\n            }\n\n            // If all we have is the start token, then we've not processed the first event, so we should process any event at or after the start token.\n            return StartToken.Newer(sequenceToken);\n        }\n\n        public bool TryUpdateStartToken(StreamSequenceToken sequenceToken)\n        {\n            if (StartToken == null)\n            {\n                StartToken = sequenceToken;\n                return true;\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/StreamInterceptionGrain.cs",
    "content": "using Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [ImplicitStreamSubscription(\"InterceptedStream\")]\n    public class StreamInterceptionGrain : Grain, IStreamInterceptionGrain, IIncomingGrainCallFilter\n    {\n        private int lastStreamValue;\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var streams = this.GetStreamProvider(\"SMSProvider\");\n            var stream = streams.GetStream<int>(\"InterceptedStream\", this.GetPrimaryKey());\n            await stream.SubscribeAsync(\n                (value, token) =>\n                {\n                    this.lastStreamValue = value;\n                    return Task.CompletedTask;\n                });\n            await base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<int> GetLastStreamValue() => Task.FromResult(this.lastStreamValue);\n\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            var initialLastStreamValue = this.lastStreamValue;\n            await context.Invoke();\n\n            // If the last stream value changed after the invoke, then the stream must have produced a value, double\n            // it for testing purposes.\n            if (this.lastStreamValue != initialLastStreamValue)\n            {\n                this.lastStreamValue *= 2;\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/StreamingHistoryGrain.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class StreamingHistoryGrain : Grain, IStreamingHistoryGrain, IAsyncObserver<int>\n    {\n        private readonly List<int> receivedItems = new List<int>();\n        private readonly List<StreamSubscriptionHandle<int>> subscriptionHandles = new List<StreamSubscriptionHandle<int>>();\n\n        public async Task BecomeConsumer(StreamId streamId, string provider, string filterData = null)\n        {\n            var stream = this.GetStreamProvider(provider).GetStream<int>(streamId);\n            this.subscriptionHandles.Add(await stream.SubscribeAsync(this, null, filterData));\n        }\n\n        public Task<List<int>> GetReceivedItems() => Task.FromResult(this.receivedItems);\n\n        public async Task StopBeingConsumer()\n        {\n            foreach (var sub in this.subscriptionHandles)\n            {\n                await sub.UnsubscribeAsync();\n            }\n        }\n\n        public Task OnCompletedAsync() => Task.CompletedTask;\n\n        public Task OnErrorAsync(Exception ex) => Task.CompletedTask;\n\n        public Task OnNextAsync(int item, StreamSequenceToken token = null)\n        {\n            this.receivedItems.Add(item);\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestGrains/StuckGrain.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\n\n\nnamespace UnitTests.Grains\n{\n    public class StuckGrain : Grain, IStuckGrain\n    {\n        private static readonly ConcurrentDictionary<GrainId, bool> ActivationCalls = new();\n        private static readonly Dictionary<Guid, TaskCompletionSource<bool>> tcss = new Dictionary<Guid, TaskCompletionSource<bool>>();\n        private static readonly Dictionary<Guid, int> counters = new Dictionary<Guid, int>();\n        private static readonly HashSet<Guid> grains = new HashSet<Guid>();\n        private readonly ILogger<StuckGrain> _log;\n        private bool isDeactivatingBlocking = false;\n\n        private static readonly ConcurrentDictionary<GrainId, ManualResetEventSlim> blockingMREMap =\n            new ConcurrentDictionary<GrainId, ManualResetEventSlim>();\n\n        public StuckGrain(ILogger<StuckGrain> log)\n        {\n            _log = log;\n        }\n\n        public static bool Release(Guid key)\n        {\n            lock (tcss)\n            {\n                if (!tcss.ContainsKey(key))\n                    return false;\n\n                tcss[key].TrySetResult(true);\n                tcss.Remove(key);\n                return true;\n            }\n        }\n\n        public static Task WaitForDeactivationStart(GrainId key)\n        {\n            if (!blockingMREMap.TryGetValue(key, out var mre) || mre == null)\n                throw new InvalidOperationException();\n\n\n            return Task.Run(() =>\n            {\n                if (!mre.Wait(TimeSpan.FromSeconds(10)))\n                {\n                    throw new TimeoutException(\"Timed out waiting for grain deactivation to start.\");\n                }\n            });\n        }\n\n        public static void SetDeactivationStarted(GrainId key)\n        {\n            if (!blockingMREMap.TryGetValue(key, out var mre) || mre == null)\n                return;\n\n            mre.Set();\n        }\n\n        public static void BlockCallingTestUntilDeactivation(GrainId key)\n        {\n            if (!blockingMREMap.TryGetValue(key, out var mre) || mre == null)\n                mre = new ManualResetEventSlim(false);\n            else if (mre != null)\n                mre.Reset();\n\n            blockingMREMap[key] = mre;\n        }\n\n        public static bool IsActivated(Guid key)\n        {\n            return grains.Contains(key);\n        }\n\n        public Task RunForever()\n        {\n            var key = this.GetPrimaryKey();\n\n            lock (tcss)\n            {\n                if(tcss.ContainsKey(key))\n                    throw new InvalidOperationException(\"Duplicate call for the same grain ID.\");\n\n                var tcs = new TaskCompletionSource<bool>();\n                tcss[key] = tcs;\n                return tcs.Task;\n            }\n        }\n\n        public Task NonBlockingCall()\n        {\n            counters[this.GetPrimaryKey()] = counters[this.GetPrimaryKey()] + 1;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetNonBlockingCallCounter()\n        {\n            return Task.FromResult(counters[this.GetPrimaryKey()]);\n        }\n\n        public Task<bool> DidActivationTryToStart(GrainId id)\n        {\n            return Task.FromResult(ActivationCalls.TryGetValue(id, out _));\n        }\n\n        public Task BlockingDeactivation()\n        {\n            isDeactivatingBlocking = true;\n            BlockCallingTestUntilDeactivation(this.GetGrainId());\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ActivationCalls[this.GetGrainId()] = true;\n\n            _log.LogInformation(\"Activating\");\n            var key = this.GetPrimaryKey();\n            lock (grains)\n            {\n                grains.Add(key);\n            }\n\n            lock (counters)\n            {\n                counters[key] = 0;\n            }\n\n            if (RequestContext.Get(\"block_activation_seconds\") is int blockActivationSeconds && blockActivationSeconds > 1)\n            {\n                try\n                {\n                    await Task.Delay(TimeSpan.FromSeconds(blockActivationSeconds), cancellationToken);\n                }\n                catch (Exception exception)\n                {\n                    _log.LogInformation(exception, \"Error while waiting\");\n                }\n            }\n\n            await base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _log.LogInformation(reason.Exception, \"Deactivating ReasonCode: {ReasonCode} Description: {ReasonText}\", reason.ReasonCode, reason.Description);\n\n            SetDeactivationStarted(this.GetGrainId());\n            if (isDeactivatingBlocking) return RunForever();\n\n            var key = this.GetPrimaryKey();\n            lock (grains)\n            {\n                grains.Remove(key);\n            }\n            lock (tcss)\n            {\n                tcss.Remove(key);\n            }\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n\n    public class StuckCleanupGrain : Grain, IStuckCleanGrain\n    {\n        public Task Release(Guid key)\n        {\n            StuckGrain.Release(key);\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> IsActivated(Guid key)\n        {\n            return Task.FromResult(StuckGrain.IsActivated(key));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/TestGrains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.Grains</RootNamespace>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <NoWarn>$(NoWarn);1591;1591;618</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.EventSourcing\\Orleans.EventSourcing.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestFSharpGrainInterfaces\\TestFSharpGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.BroadcastChannel\\Orleans.BroadcastChannel.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.DurableJobs\\Orleans.DurableJobs.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Grains/TestGrains/TestPlacementStrategyFixedSiloDirector.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Runtime.Placement;\n\nnamespace UnitTests.GrainInterfaces\n{\n    public class TestPlacementStrategyFixedSiloDirector : IPlacementDirector\n    {\n        public const string TARGET_SILO_INDEX = \"TARGET_SILO_INDEX\";\n\n        public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            var silos = context.GetCompatibleSilos(target).OrderBy(s => s).ToArray();\n            var oddTick = DateTime.UtcNow.Ticks % 2 == 1;\n\n            switch (((TestCustomPlacementStrategy)strategy).Scenario)\n            {\n                case CustomPlacementScenario.FixedSilo:\n                    return Task.FromResult(silos[silos.Length - 2]); // second from last silos.\n\n                case CustomPlacementScenario.ExcludeOne:\n                    return Task.FromResult(oddTick ? silos[0] : silos[silos.Length - 1]); // randomly return first or last silos\n\n                case CustomPlacementScenario.RequestContextBased:\n                    var index = (int)target.RequestContextData[TARGET_SILO_INDEX];\n                    return Task.FromResult(silos[index]);\n\n                default:\n                    throw new InvalidOperationException(); // should never get here, only to make compiler happy\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/ValueTypeTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class ValueTypeTestGrain : Grain<ValueTypeTestData>, IValueTypeTestGrain\n    {\n        public ValueTypeTestGrain()\n        {\n        }\n\n        public async Task<ValueTypeTestData> GetStateData()\n        {\n            await ReadStateAsync();\n            return State;\n        }\n\n        public Task SetStateData(ValueTypeTestData d)\n        {\n            State = d;\n            return WriteStateAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestGrains/VersionAwarePlacementDirector.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Runtime.Placement;\n\nnamespace UnitTests.Grains\n{\n    public class VersionAwarePlacementDirector : IPlacementDirector\n    {\n        private readonly Random random = new Random();\n\n        public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)\n        {\n            SiloAddress[] silos;\n            if (target.InterfaceVersion == 0)\n            {\n                silos = context.GetCompatibleSilos(target);\n            }\n            else\n            {\n                var silosByVersion = context.GetCompatibleSilosWithVersions(target);\n                var maxSiloCount = 0;\n                ushort version = 0;\n                foreach (var kvp in silosByVersion)\n                {\n                    if (kvp.Value.Length > maxSiloCount)\n                    {\n                        version = kvp.Key;\n                        maxSiloCount = kvp.Value.Length;\n                    }\n                }\n                silos = silosByVersion[version];\n            }\n\n            return Task.FromResult(silos[random.Next(silos.Length)]);\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/ActivationGCTestGrainInterfaces.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IIdleActivationGcTestGrain1 : IGrainWithGuidKey\n    {\n        Task Nop();\n    }\n\n    public interface IIdleActivationGcTestGrain2 : IGrainWithGuidKey\n    {\n        Task Nop();\n    }\n\n    public interface IBusyActivationGcTestGrain1 : IGrainWithGuidKey\n    {\n        Task Nop();\n        Task Delay(TimeSpan dt);\n        Task<string> IdentifyActivation();\n    }\n\n    public interface IBusyActivationGcTestGrain2 : IGrainWithGuidKey\n    {\n        Task Nop();\n    }\n\n    public interface ICollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain : IGrainWithGuidKey\n    {\n        Task Nop();\n    }\n\n    public interface ICollectionSpecificAgeLimitForZeroSecondsActivationGcTestGrain : IGrainWithGuidKey\n    {\n        Task Nop();\n    }\n\n    public interface IStatelessWorkerActivationCollectorTestGrain1 : IGrainWithGuidKey\n    {\n        Task Nop();\n        Task Delay(TimeSpan dt);\n        Task<string> IdentifyActivation();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IClientAddressableTestClientObject.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IClientAddressableTestClientObject : IGrainObserver\n    {\n        Task<string> OnHappyPath(string message);\n        Task OnSadPath(string message);\n        Task<int> OnSerialStress(int n);\n        Task<int> OnParallelStress(int n);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IClientAddressableTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IClientAddressableTestGrain : IGrainWithIntegerKey\n    {\n        Task SetTarget(IClientAddressableTestClientObject target);\n        Task<string> HappyPath(string message);\n        Task SadPath(string message);\n        Task MicroSerialStressTest(int iterationCount);\n        Task MicroParallelStressTest(int iterationCount);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IClientAddressableTestProducer.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    public interface IClientAddressableTestProducer : IGrainObserver\n    {\n        Task<int> Poll();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IClientAddressableTestRendezvousGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IClientAddressableTestRendezvousGrain : IGrainWithIntegerKey\n    {\n        Task<IClientAddressableTestProducer> GetProducer();\n        Task SetProducer(IClientAddressableTestProducer producer);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IMultifacetFactoryTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IMultifacetFactoryTestGrain : IGrainWithIntegerKey\n    {\n        Task<IMultifacetReader> GetReader(IMultifacetTestGrain grain);\n        Task<IMultifacetReader> GetReader();\n        Task<IMultifacetWriter> GetWriter(IMultifacetTestGrain grain);\n        Task<IMultifacetWriter> GetWriter();\n        Task SetReader(IMultifacetReader reader);\n        Task SetWriter(IMultifacetWriter writer);\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IMultifacetTestGrain.cs",
    "content": "﻿namespace UnitTests.GrainInterfaces\n{\n    public interface IMultifacetTestGrain : IMultifacetReader, IMultifacetWriter\n    {\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IPlacementTestGrain.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    using System.Threading.Tasks;\n\n    using Orleans;\n    using Orleans.Runtime;\n\n    internal interface IDefaultPlacementGrain : IGrainWithIntegerKey\n    {\n        Task<PlacementStrategy> GetDefaultPlacement();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/ISerializerPresenceTest.cs",
    "content": "namespace UnitTests.GrainInterfaces\n{\n    internal interface ISerializerPresenceTest : IGrainWithGuidKey\n    {\n        Task<bool> SerializerExistsForType(System.Type param);\n\n        Task TakeSerializedData(object data);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/IStressTestGrain.cs",
    "content": "using Orleans.Runtime;\n\nnamespace UnitTests.GrainInterfaces\n{\n    internal interface IStressTestGrain : IGrainWithIntegerKey\n    {\n        Task<string> GetLabel();\n\n        Task SetLabel(string label);\n\n        Task PingOthers(long[] others);\n\n        Task<List<Tuple<GrainId, int, List<Tuple<SiloAddress, ActivationId>>>>> LookUpMany(SiloAddress destination, List<Tuple<GrainId, int>> grainAndETagList, int retries = 0);\n\n        Task Send(byte[] data);\n\n        Task<byte[]> Echo(byte[] data);\n\n        Task Ping(byte[] data);\n\n        Task PingWithDelay(byte[] data, TimeSpan delay);\n\n        Task<IStressTestGrain> GetGrainReference();\n\n        Task DeactivateSelf();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrainInterfaces/TestInternalGrainInterfaces.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.GrainInterfaces</RootNamespace>\n    <AssemblyName>TestInternalGrainInterfaces</AssemblyName>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FSharp.Core\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.DefaultCluster.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Placement.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Tests\" />\n    <InternalsVisibleTo Include=\"TestInternalGrains\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ActivateDeactivateTestGrain.cs",
    "content": "using System.Runtime.CompilerServices;\nusing Microsoft.Extensions.Logging;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Grains\n{\n    internal class SimpleActivateDeactivateTestGrain : Grain, ISimpleActivateDeactivateTestGrain\n    {\n        private readonly ILogger logger;\n\n        private IActivateDeactivateWatcherGrain watcher;\n\n        private bool doingActivate;\n        private bool doingDeactivate;\n\n        public SimpleActivateDeactivateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            watcher = GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingActivate = true;\n            await watcher.RecordActivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n            Assert.True(doingActivate, \"Activate method still running\");\n            doingActivate = false;\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingDeactivate = true;\n            await watcher.RecordDeactivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n            Assert.True(doingDeactivate, \"Deactivate method still running\");\n            doingDeactivate = false;\n        }\n\n        public Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            return Task.FromResult(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n        }\n\n        public Task DoDeactivate()\n        {\n            logger.LogInformation(\"DoDeactivate\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class TailCallActivateDeactivateTestGrain : Grain, ITailCallActivateDeactivateTestGrain\n    {\n        private readonly ILogger logger;\n\n        private IActivateDeactivateWatcherGrain watcher;\n\n        private bool doingActivate;\n        private bool doingDeactivate;\n\n        public TailCallActivateDeactivateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            watcher = GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingActivate = true;\n            return watcher.RecordActivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"))\n                .ContinueWith((Task t) =>\n                {\n                    Assert.False(t.IsFaulted, \"RecordActivateCall failed\");\n                    Assert.True(doingActivate, \"Doing Activate\");\n                    doingActivate = false;\n                });\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingDeactivate = true;\n            return watcher.RecordDeactivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"))\n                .ContinueWith((Task t) =>\n                {\n                    Assert.False(t.IsFaulted, \"RecordDeactivateCall failed\");\n                    Assert.True(doingDeactivate, \"Doing Deactivate\");\n                    doingDeactivate = false;\n                });\n        }\n\n        public Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            return Task.FromResult(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n        }\n\n        public Task DoDeactivate()\n        {\n            logger.LogInformation(\"DoDeactivate\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class LongRunningActivateDeactivateTestGrain : Grain, ILongRunningActivateDeactivateTestGrain\n    {\n        private readonly ILogger logger;\n\n        private IActivateDeactivateWatcherGrain watcher;\n\n        private bool doingActivate;\n        private bool doingDeactivate;\n\n        public LongRunningActivateDeactivateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            watcher = GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n\n            Assert.False(doingActivate, \"Not doing Activate yet\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingActivate = true;\n\n            logger.LogInformation(\"OnActivateAsync\");\n\n            // Spawn Task to run on default .NET thread pool\n            var task = Task.Factory.StartNew(() =>\n            {\n                logger.LogInformation(\"Started-OnActivateAsync-SubTask\");\n                Assert.True(TaskScheduler.Current == TaskScheduler.Default,\n                    \"Running under default .NET Task scheduler\");\n                Assert.True(doingActivate, \"Still doing Activate in Sub-Task\");\n                logger.LogInformation(\"Finished-OnActivateAsync-SubTask\");\n            }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);\n            await task;\n\n            logger.LogInformation(\"Started-OnActivateAsync\");\n\n            await watcher.RecordActivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n            Assert.True(doingActivate, \"Doing Activate\");\n\n            logger.LogInformation(\"OnActivateAsync-Sleep\");\n            Thread.Sleep(TimeSpan.FromSeconds(1));\n            Assert.True(doingActivate, \"Still doing Activate after Sleep\");\n\n            logger.LogInformation(\"Finished-OnActivateAsync\");\n            doingActivate = false;\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n\n            Assert.False(doingActivate, \"Not doing Activate yet\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate yet\");\n            doingDeactivate = true;\n\n            logger.LogInformation(\"Started-OnDeactivateAsync\");\n\n            await watcher.RecordDeactivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n            Assert.True(doingDeactivate, \"Doing Deactivate\");\n\n            logger.LogInformation(\"OnDeactivateAsync-Sleep\");\n            Thread.Sleep(TimeSpan.FromSeconds(1));\n            logger.LogInformation(\"Finished-OnDeactivateAsync\");\n            doingDeactivate = false;\n        }\n\n        public Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            return Task.FromResult(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n        }\n\n        public Task DoDeactivate()\n        {\n            logger.LogInformation(\"DoDeactivate\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class TaskActionActivateDeactivateTestGrain : Grain, ITaskActionActivateDeactivateTestGrain\n    {\n        private readonly ILogger logger;\n\n        private IActivateDeactivateWatcherGrain watcher;\n\n        private bool doingActivate;\n        private bool doingDeactivate;\n\n        public TaskActionActivateDeactivateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            Assert.NotNull(TaskScheduler.Current);\n            Assert.NotEqual(TaskScheduler.Current, TaskScheduler.Default);\n            var startMe =\n                new Task(\n                    () =>\n                    {\n                        Assert.NotNull(TaskScheduler.Current);\n                        Assert.NotEqual(TaskScheduler.Current, TaskScheduler.Default);\n                        logger.LogInformation(\"OnActivateAsync\");\n\n                        watcher = GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n\n                        Assert.False(doingActivate, \"Not doing Activate\");\n                        Assert.False(doingDeactivate, \"Not doing Deactivate\");\n                        doingActivate = true;\n                    });\n            // we want to use Task.ContinueWith with an async lambda, an explicitly typed variable is required to avoid\n            // writing code that doesn't do what i think it is doing.\n            async Task asyncCont()\n            {\n                Assert.NotNull(TaskScheduler.Current);\n                Assert.NotEqual(TaskScheduler.Current, TaskScheduler.Default);\n                logger.LogInformation(\"Started-OnActivateAsync\");\n\n                Assert.True(doingActivate, \"Doing Activate 1\");\n                Assert.False(doingDeactivate, \"Not doing Deactivate\");\n\n                try\n                {\n                    logger.LogInformation(\"Calling RecordActivateCall\");\n                    await watcher.RecordActivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n                    logger.LogInformation(\"Returned from calling RecordActivateCall\");\n                }\n                catch (Exception exc)\n                {\n                    logger.LogError(exc, \"RecordActivateCall failed\");\n                    Assert.True(false, \"RecordActivateCall failed with error \" + exc);\n                }\n\n                Assert.True(doingActivate, \"Doing Activate 2\");\n                Assert.False(doingDeactivate, \"Not doing Deactivate\");\n\n                await Task.Delay(TimeSpan.FromSeconds(1));\n\n                doingActivate = false;\n\n                logger.LogInformation(\"Finished-OnActivateAsync\");\n            }\n            var awaitMe = startMe.ContinueWith(_ => asyncCont()).Unwrap();\n            startMe.Start();\n            await awaitMe;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            Task.Factory.StartNew(() => logger.LogInformation(\"OnDeactivateAsync\"));\n\n            Assert.False(doingActivate, \"Not doing Activate\");\n            Assert.False(doingDeactivate, \"Not doing Deactivate\");\n            doingDeactivate = true;\n\n            logger.LogInformation(\"Started-OnDeactivateAsync\");\n            return watcher.RecordDeactivateCall(RuntimeHelpers.GetHashCode(this).ToString(\"X\"))\n                .ContinueWith((Task t) =>\n                {\n                    Assert.False(t.IsFaulted, \"RecordDeactivateCall failed\");\n                    Assert.True(doingDeactivate, \"Doing Deactivate\");\n                    Thread.Sleep(TimeSpan.FromSeconds(1));\n                    doingDeactivate = false;\n                })\n                .ContinueWith((Task t) => logger.LogInformation(\"Finished-OnDeactivateAsync\"),\n                    TaskContinuationOptions.ExecuteSynchronously);\n        }\n\n        public Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            return Task.FromResult(RuntimeHelpers.GetHashCode(this).ToString(\"X\"));\n        }\n\n        public Task DoDeactivate()\n        {\n            logger.LogInformation(\"DoDeactivate\");\n            Assert.False(doingActivate, \"Activate method should have finished\");\n            Assert.False(doingDeactivate, \"Deactivate method should not be running yet\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    public class BadActivateDeactivateTestGrain : Grain, IBadActivateDeactivateTestGrain\n    {\n        private readonly ILogger logger;\n\n        public BadActivateDeactivateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            throw new ApplicationException(\"Thrown from Application-OnActivateAsync\");\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            throw new ApplicationException(\"Thrown from Application-OnDeactivateAsync\");\n        }\n\n        public Task ThrowSomething()\n        {\n            logger.LogInformation(\"ThrowSomething\");\n            throw new InvalidOperationException(\"Exception should have been thrown from Activate\");\n        }\n\n        public Task<long> GetKey()\n        {\n            logger.LogInformation(\"GetKey\");\n            //return this.GetPrimaryKeyLong();\n            throw new InvalidOperationException(\"Exception should have been thrown from Activate\");\n        }\n    }\n\n    internal class BadConstructorTestGrain : Grain, IBadConstructorTestGrain\n    {\n        public BadConstructorTestGrain()\n        {\n            throw new ApplicationException(\"Thrown from Constructor\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            throw new NotImplementedException(\"OnActivateAsync should not have been called\");\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            throw new NotImplementedException(\"OnDeactivateAsync(...) should not have been called\");\n        }\n\n        public Task<string> DoSomething()\n        {\n            throw new NotImplementedException(\"DoSomething should not have been called\");\n        }\n    }\n\n    internal class DeactivatingWhileActivatingTestGrain : Grain, IDeactivatingWhileActivatingTestGrain\n    {\n        private readonly ILogger logger;\n\n        public DeactivatingWhileActivatingTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            throw new NotImplementedException(\"DoSomething should not have been called\");\n        }\n    }\n\n    internal class CreateGrainReferenceTestGrain : Grain, ICreateGrainReferenceTestGrain\n    {\n        private readonly ILogger logger;\n\n        //private IEchoGrain orleansManagedGrain;\n        private ITestGrain grain;\n\n        public CreateGrainReferenceTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            grain = GrainFactory.GetGrain<ITestGrain>(1);\n            logger.LogInformation(\"OnActivateAsync\");\n            grain = GrainFactory.GetGrain<ITestGrain>(1);\n            return Task.CompletedTask;\n        }\n\n        public async Task<string> DoSomething()\n        {\n            logger.LogInformation(\"DoSomething\");\n            var guid = Guid.NewGuid();\n            await grain.SetLabel(guid.ToString());\n            var label = await grain.GetLabel();\n\n            if (string.IsNullOrEmpty(label))\n            {\n                throw new ArgumentException(\"Bad data: Null label returned\");\n            }\n            return RuntimeHelpers.GetHashCode(this).ToString(\"X\");\n        }\n\n        public async Task ForwardCall(IBadActivateDeactivateTestGrain otherGrain)\n        {\n            logger.LogInformation(\"ForwardCall to {OtherGrain}\", otherGrain);\n            await otherGrain.ThrowSomething();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ActivationGCTestGrains.cs",
    "content": "using Orleans.Concurrency;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class IdleActivationGcTestGrain1: Grain, IIdleActivationGcTestGrain1\n    {\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    public class IdleActivationGcTestGrain2: Grain, IIdleActivationGcTestGrain2\n    {\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class BusyActivationGcTestGrain1: Grain, IBusyActivationGcTestGrain1\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n        private readonly ActivationCollector activationCollector;\n        private readonly IGrainContext _grainContext;\n\n        public BusyActivationGcTestGrain1(ActivationCollector activationCollector, IGrainContext grainContext)\n        {\n            this.activationCollector = activationCollector;\n            _grainContext = grainContext;\n        }\n\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task Delay(TimeSpan dt)\n        {\n            return Task.Delay(dt);\n        }\n\n        public Task<string> IdentifyActivation()\n        {\n            return Task.FromResult(_id);\n        }\n    }\n\n    public class BusyActivationGcTestGrain2: Grain, IBusyActivationGcTestGrain2\n    {\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    public class CollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain : Grain, ICollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain\n    {\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    // Use this Test Class in Non.Silo test [SiloBuilder_GrainCollectionOptionsForZeroSecondsAgeLimitTest]\n    public class CollectionSpecificAgeLimitForZeroSecondsActivationGcTestGrain : Grain, ICollectionSpecificAgeLimitForZeroSecondsActivationGcTestGrain\n    {\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    [StatelessWorker]\n    public class StatelessWorkerActivationCollectorTestGrain1 : Grain, IStatelessWorkerActivationCollectorTestGrain1\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task Delay(TimeSpan dt)\n        {\n            return Task.Delay(dt);\n        }\n\n        public Task<string> IdentifyActivation()\n        {\n            return Task.FromResult(_id);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ClientAddressableTestConsumerGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ClientAddressableTestConsumerGrain : Grain, IClientAddressableTestConsumer\n    {\n        private IClientAddressableTestProducer producer;\n        \n        public async Task<int> PollProducer()\n        {\n            return await producer.Poll();\n        }\n\n        public async Task Setup()\n        {\n            var rendezvous = GrainFactory.GetGrain<IClientAddressableTestRendezvousGrain>(0);\n            producer = await rendezvous.GetProducer();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ClientAddressableTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Grains\n{\n    public class ClientAddressableTestGrain : Grain, IClientAddressableTestGrain\n    {\n        private IClientAddressableTestClientObject target;\n\n        public Task SetTarget(IClientAddressableTestClientObject target)\n        {\n            this.target = target;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> HappyPath(string message)\n        {\n            return target.OnHappyPath(message);\n        }\n\n        public Task SadPath(string message)\n        {\n            return target.OnSadPath(message);\n        }\n\n        public async Task MicroSerialStressTest(int iterationCount)\n        {\n            for (var i = 0; i < iterationCount; ++i)\n            {\n                var n = await target.OnSerialStress(i);\n                Assert.Equal(10000 + i, n);\n            }\n        }\n\n        public Task MicroParallelStressTest(int iterationCount)\n        {\n            var tasks = new Task[iterationCount];\n            for (var i = 0; i < iterationCount; ++i)\n            {\n                var n = i;\n                tasks[n] = \n                    target.OnParallelStress(n)\n                    .ContinueWith(\n                        completed =>\n                            {\n                                Assert.True(completed.IsCompleted);\n                                Assert.Equal(10000 + n, completed.Result);\n                            });\n                \n            }\n            return Task.WhenAll(tasks);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ClientAddressableTestRendezvousGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n\n    public class ClientAddressableTestRendezvousGrain : Grain, IClientAddressableTestRendezvousGrain\n    {\n        private IClientAddressableTestProducer producer;\n\n        public Task<IClientAddressableTestProducer> GetProducer()\n        {\n            return Task.FromResult(producer);\n        }\n\n        public Task SetProducer(IClientAddressableTestProducer producer)\n        {\n            this.producer = producer;\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/CollectionTestGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [CollectionAgeLimit(\"00:05:00\")]\n    public class CollectionTestGrain : Grain, ICollectionTestGrain\n    {\n        protected readonly IGrainContext _grainContext;\n        private DateTime activated;\n\n        private ICollectionTestGrain other;\n        private ILogger logger;\n        private int counter;\n        private static int staticCounter;\n\n        public CollectionTestGrain(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        protected virtual ILogger Logger()\n        {\n            return logger;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>()\n                .CreateLogger(string.Format(\"CollectionTestGrain {0} {1} on {2}.\", GrainId, _grainContext.ActivationId, RuntimeIdentity));\n            logger.LogInformation(\"OnActivateAsync.\");\n            activated = DateTime.UtcNow;\n            counter = 0;\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            Logger().LogInformation(\"OnDeactivateAsync.\");\n            return Task.CompletedTask;\n        }\n\n        public virtual Task<int> IncrCounter()\n        {\n            staticCounter++;\n            counter++;\n            int tmpCounter = counter;\n            Logger().LogInformation(\"IncrCounter {Counter}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n            return Task.FromResult(counter);\n        }\n\n        public Task<TimeSpan> GetAge()\n        {\n            Logger().LogInformation(\"GetAge.\");\n            return Task.FromResult(DateTime.UtcNow.Subtract(activated));\n        }\n\n        public virtual Task DeactivateSelf()\n        {\n            Logger().LogInformation(\"DeactivateSelf.\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task SetOther(ICollectionTestGrain other)\n        {\n            Logger().LogInformation(\"SetOther.\");\n            this.other = other;\n            return Task.CompletedTask;\n        }\n\n        public Task<TimeSpan> GetOtherAge()\n        {\n            Logger().LogInformation(\"GetOtherAge.\");\n            return other.GetAge();\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            Logger().LogInformation(\"GetRuntimeInstanceId.\");\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public Task<ICollectionTestGrain> GetGrainReference()\n        {\n            Logger().LogInformation(\"GetGrainReference.\");\n            return Task.FromResult(this.AsReference<ICollectionTestGrain>());\n        }\n\n        public Task StartTimer(TimeSpan timerPeriod, TimeSpan delayPeriod)\n        {\n            this.RegisterGrainTimer(TimerCallback, delayPeriod, TimeSpan.Zero, timerPeriod);\n            return Task.CompletedTask;\n        }\n\n        private async Task TimerCallback(TimeSpan delayPeriod, CancellationToken cancellationToken)\n        {\n            staticCounter++;\n            counter++;\n            int tmpCounter = counter;\n            Logger().LogInformation(\"Start TimerCallback {Counter}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n            await Task.Delay(delayPeriod);\n            Logger().LogInformation(\"After first delay TimerCallback {Counter}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n            await Task.Delay(delayPeriod);\n            Logger().LogInformation(\"After second delay TimerCallback {Counter}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n        }\n    }\n\n    [Reentrant]\n    public class ReentrantCollectionTestGrain : CollectionTestGrain, ICollectionTestGrain\n    {\n        private ILogger logger;\n        private int counter;\n        private static int staticCounter;\n\n        public ReentrantCollectionTestGrain(IGrainContext grainContext) : base(grainContext)\n        {\n        }\n\n        protected override ILogger Logger()\n        {\n            return logger;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>()\n                .CreateLogger($\"CollectionTestGrain {GrainId} {_grainContext.ActivationId} on {RuntimeIdentity}.\");\n            logger.LogInformation(\"OnActivateAsync.\");\n            counter = 0;\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            Logger().LogInformation(\"OnDeactivateAsync.\");\n            return Task.CompletedTask;\n        }\n\n        public override async Task<int> IncrCounter()\n        {\n            staticCounter++;\n            int tmpCounter = counter++;\n            Logger().LogInformation(\"Reentrant:IncrCounter BEFORE Delay {Count}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            Logger().LogInformation(\"Reentrant:IncrCounter AFTER Delay {Count}, staticCounter {StaticCounter}.\", tmpCounter, staticCounter);\n            return counter;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/EchoTaskGrain.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Utilities;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class EchoTaskGrainState\n    {\n        [Id(0)]\n        public int MyId { get; set; }\n        [Id(1)]\n        public string LastEcho { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    [CollectionAgeLimit(Days = 1)] // Added to test the attribute itself.\n    public class EchoGrain : Grain<EchoTaskGrainState>, IEchoGrain\n    {\n        private readonly ILogger logger;\n\n        public EchoGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"{GrainType} created\", GetType().FullName);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<string> GetLastEcho()\n        {\n            return Task.FromResult(State.LastEcho);\n        }\n\n        public Task<string> Echo(string data)\n        {\n            logger.LogInformation(\"IEchoGrain.Echo={Data}\", data);\n            State.LastEcho = data;\n            return Task.FromResult(data);\n        }\n\n        public Task<string> EchoError(string data)\n        {\n            logger.LogInformation(\"IEchoGrain.EchoError={Data}\", data);\n            State.LastEcho = data;\n            throw new Exception(data);\n        }\n\n        public Task<DateTime?> EchoNullable(DateTime? value) => Task.FromResult(value);\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    [CollectionAgeLimit(\"01:00:00\")] // Added to test the attribute itself.\n    internal class EchoTaskGrain : Grain<EchoTaskGrainState>, IEchoTaskGrain, IDebuggerHelperTestGrain\n    {\n        private readonly IInternalGrainFactory internalGrainFactory;\n        private readonly IGrainContext _grainContext;\n        private readonly ILogger logger;\n\n        public EchoTaskGrain(IInternalGrainFactory internalGrainFactory, ILogger<EchoTaskGrain> logger, IGrainContext grainContext)\n        {\n            this.internalGrainFactory = internalGrainFactory;\n            this.logger = logger;\n            _grainContext = grainContext;\n        }\n\n        public Task<int> GetMyIdAsync() { return Task.FromResult(State.MyId); }\n        public Task<string> GetLastEchoAsync() { return Task.FromResult(State.LastEcho); }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"{GrainType} created\", GetType().FullName);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<string> EchoAsync(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.Echo={Data}\", data);\n            State.LastEcho = data;\n            return Task.FromResult(data);\n        }\n\n        public Task<string> EchoErrorAsync(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.EchoError={Data}\", data);\n            State.LastEcho = data;\n            throw new Exception(data);\n        }\n\n        private Task<string> EchoErrorAV(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.EchoErrorAV={Data}\", data);\n            State.LastEcho = data;\n            throw new Exception(data);\n        }\n\n        public async Task<string> AwaitMethodErrorAsync(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.CallMethodErrorAsync={Data}\", data);\n            return await EchoErrorAsync(data);\n        }\n\n        public async Task<string> AwaitAVMethodErrorAsync(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.CallMethodErrorAsync={Data}\", data);\n            return await EchoErrorAV(data);\n        }\n\n        public async Task<string> AwaitAVGrainCallErrorAsync(string data)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.AwaitAVGrainErrorAsync={Data}\", data);\n            IEchoGrain avGrain = GrainFactory.GetGrain<IEchoGrain>(this.GetPrimaryKey());\n            return await avGrain.EchoError(data);\n        }\n\n        public Task<int> BlockingCallTimeoutAsync(TimeSpan delay)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.BlockingCallTimeout Delay={Delay}\", delay);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            Thread.Sleep(delay);\n            logger.LogInformation(\"IEchoGrainAsync.BlockingCallTimeout Awoke from sleep after {ElapsedDuration}\", sw.Elapsed);\n            throw new InvalidOperationException(\"Timeout should have been returned to caller before \" + delay);\n        }\n\n        public Task<int> BlockingCallTimeoutNoResponseTimeoutOverrideAsync(TimeSpan delay)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.BlockingCallTimeoutNoResponseTimeoutOverrideAsync Delay={Delay}\", delay);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            Thread.Sleep(delay);\n            logger.LogInformation(\"IEchoGrainAsync.BlockingCallTimeoutNoResponseTimeoutOverrideAsync Awoke from sleep after {ElapsedDuration}\", sw.Elapsed);\n            throw new InvalidOperationException(\"Timeout should have been returned to caller before \" + delay);\n        }\n\n        public Task PingAsync()\n        {\n            logger.LogInformation(\"IEchoGrainAsync.Ping\");\n            return Task.CompletedTask;\n        }\n\n        public Task PingLocalSiloAsync()\n        {\n            logger.LogInformation(\"IEchoGrainAsync.PingLocal\");\n            SiloAddress mySilo = _grainContext.Address.SiloAddress;\n            return GetSiloControlReference(mySilo).Ping(\"PingLocal\");\n        }\n\n        public Task PingRemoteSiloAsync(SiloAddress siloAddress)\n        {\n            logger.LogInformation(\"IEchoGrainAsync.PingRemote\");\n            return GetSiloControlReference(siloAddress).Ping(\"PingRemote\");\n        }\n\n        public async Task PingOtherSiloAsync()\n        {\n            logger.LogInformation(\"IEchoGrainAsync.PingOtherSilo\");\n            SiloAddress mySilo = _grainContext.Address.SiloAddress;\n\n            IManagementGrain mgmtGrain = GrainFactory.GetGrain<IManagementGrain>(0);\n            var silos = await mgmtGrain.GetHosts();\n\n            SiloAddress siloAddress = silos.Where(pair => !pair.Key.Equals(mySilo)).Select(pair => pair.Key).First();\n            logger.LogInformation(\"Sending Ping to remote silo {SiloAddress}\", siloAddress);\n\n            await GetSiloControlReference(siloAddress).Ping(\"PingOtherSilo-\" + siloAddress);\n            logger.LogInformation(\"Ping reply received for {SiloAddress}\", siloAddress);\n        }\n\n        public async Task PingClusterMemberAsync()\n        {\n            logger.LogInformation(\"IEchoGrainAsync.PingClusterMemberAsync\");\n            SiloAddress mySilo = _grainContext.Address.SiloAddress;\n\n            IManagementGrain mgmtGrain = GrainFactory.GetGrain<IManagementGrain>(0);\n            var silos = await mgmtGrain.GetHosts();\n\n            SiloAddress siloAddress = silos.Where(pair => !pair.Key.Equals(mySilo)).Select(pair => pair.Key).First();\n            logger.LogInformation(\"Sending Ping to remote silo {SiloAddress}\", siloAddress);\n\n            var oracle = this.internalGrainFactory.GetSystemTarget<IMembershipService>(Constants.MembershipServiceType, siloAddress);\n\n            await oracle.Ping(1);\n            logger.LogInformation(\"Ping reply received for {SiloAddress}\", siloAddress);\n        }\n\n        private ISiloControl GetSiloControlReference(SiloAddress silo)\n        {\n            return this.internalGrainFactory.GetSystemTarget<ISiloControl>(Constants.SiloControlType, silo);\n        }\n\n        public Task OrleansDebuggerHelper_GetGrainInstance_Test()\n        {\n            var result = OrleansDebuggerHelper.GetGrainInstance(null);\n            Assert.Null(result);\n\n            result = OrleansDebuggerHelper.GetGrainInstance(this);\n            Assert.Same(this, result);\n\n            result = OrleansDebuggerHelper.GetGrainInstance(this.AsReference<IDebuggerHelperTestGrain>());\n            Assert.Same(this, result);\n\n            result = OrleansDebuggerHelper.GetGrainInstance(this.GrainFactory.GetGrain<IEchoGrain>(Guid.NewGuid()));\n            Assert.Null(result);\n\n            return Task.CompletedTask;\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class BlockingEchoTaskGrain : Grain<EchoTaskGrainState>, IBlockingEchoTaskGrain\n    {\n        private readonly ILogger logger;\n\n        public BlockingEchoTaskGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"{GrainType} created\", GetType().FullName);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<int> GetMyId()\n        {\n            return Task.FromResult(State.MyId);\n        }\n\n        public Task<string> GetLastEcho()\n        {\n            return Task.FromResult(State.LastEcho);\n        }\n\n        public Task<string> Echo(string data)\n        {\n            string name = GetType().Name + \".Echo\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            State.LastEcho = data;\n            var result = Task.FromResult(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n        public async Task<string> CallMethodTask_Await(string data)\n        {\n            string name = GetType().Name + \".CallMethodTask_Await\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoTaskGrain avGrain = GrainFactory.GetGrain<IEchoTaskGrain>(this.GetPrimaryKey());\n            var result = await avGrain.EchoAsync(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n        public async Task<string> CallMethodAV_Await(string data)\n        {\n            string name = GetType().Name + \".CallMethodAV_Await\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoGrain avGrain = GrainFactory.GetGrain<IEchoGrain>(this.GetPrimaryKey());\n            var result = await avGrain.Echo(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n        #pragma warning disable 1998\n        public async Task<string> CallMethodTask_Block(string data)\n        {\n            string name = GetType().Name + \".CallMethodTask_Block\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoTaskGrain avGrain = GrainFactory.GetGrain<IEchoTaskGrain>(this.GetPrimaryKey());\n\n            // Note: We deliberately use .Result here in this test case to block current executing thread\n            var result = avGrain.EchoAsync(data).Result;\n\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n        #pragma warning restore 1998\n\n        #pragma warning disable 1998\n        public async Task<string> CallMethodAV_Block(string data)\n        {\n            string name = GetType().Name + \".CallMethodAV_Block\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoGrain avGrain = GrainFactory.GetGrain<IEchoGrain>(this.GetPrimaryKey());\n\n            // Note: We deliberately use .Result here in this test case to block current executing thread\n            var result = avGrain.Echo(data).Result;\n\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n        #pragma warning restore 1998\n    }\n\n    [Reentrant]\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class ReentrantBlockingEchoTaskGrain : Grain<EchoTaskGrainState>, IReentrantBlockingEchoTaskGrain\n    {\n        private readonly ILogger logger;\n\n        public ReentrantBlockingEchoTaskGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"{GrainType} created\", GetType().FullName);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<int> GetMyId()\n        {\n            return Task.FromResult(State.MyId);\n        }\n\n        public Task<string> GetLastEcho()\n        {\n            return Task.FromResult(State.LastEcho);\n        }\n\n        public Task<string> Echo(string data)\n        {\n            string name = GetType().Name + \".Echo\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            State.LastEcho = data;\n            var result = Task.FromResult(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n        public async Task<string> CallMethodTask_Await(string data)\n        {\n            string name = GetType().Name + \".CallMethodTask_Await\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoTaskGrain avGrain = GrainFactory.GetGrain<IEchoTaskGrain>(this.GetPrimaryKey());\n            var result = await avGrain.EchoAsync(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n        public async Task<string> CallMethodAV_Await(string data)\n        {\n            string name = GetType().Name + \".CallMethodAV_Await\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoGrain avGrain = GrainFactory.GetGrain<IEchoGrain>(this.GetPrimaryKey());\n            var result = await avGrain.Echo(data);\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n\n#pragma warning disable 1998\n        public async Task<string> CallMethodTask_Block(string data)\n        {\n            string name = GetType().Name + \".CallMethodTask_Block\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoTaskGrain avGrain = GrainFactory.GetGrain<IEchoTaskGrain>(this.GetPrimaryKey());\n\n            // Note: We deliberately use .Result here in this test case to block current executing thread\n            var result = avGrain.EchoAsync(data).Result;\n\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n#pragma warning restore 1998\n\n#pragma warning disable 1998\n        public async Task<string> CallMethodAV_Block(string data)\n        {\n            string name = GetType().Name + \".CallMethodAV_Block\";\n\n            logger.LogInformation(\"{Name} Data={Data}\", name, data);\n            IEchoGrain avGrain = GrainFactory.GetGrain<IEchoGrain>(this.GetPrimaryKey());\n\n            // Note: We deliberately use .Result here in this test case to block current executing thread\n            var result = avGrain.Echo(data).Result;\n\n            logger.LogInformation(\"{Name} Result={Result}\", name, result);\n            return result;\n        }\n#pragma warning restore 1998\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ErrorGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    public class ErrorGrain : SimpleGrain, IErrorGrain\n    {\n        private int counter;\n\n        public ErrorGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"Activate.\");\n            return Task.CompletedTask;\n        }\n\n        public Task LogMessage(string msg)\n        {\n            logger.LogInformation(\"{Message}\", msg);\n           return Task.CompletedTask;\n        }\n\n        public Task SetAError(int a)\n        {\n            logger.LogInformation(\"SetAError={A}\", a);\n            A = a;\n            throw new Exception(\"SetAError-Exception\");\n        }\n\n        public Task SetBError(int a)\n        {\n            throw new Exception(\"SetBError-Exception\");\n        }\n\n        public Task<int> GetAxBError()\n        {\n            throw new Exception(\"GetAxBError-Exception\");\n        }\n\n        public Task<int> GetAxBError(int a, int b)\n        {\n            throw new Exception(\"GetAxBError(a,b)-Exception\");\n        }\n\n        public async Task LongMethod(int waitTime)\n        {\n            await Task.Delay(waitTime);\n        }\n\n        public async Task LongMethodWithError(int waitTime)\n        {\n            await Task.Delay(waitTime);\n            throw new Exception(\"LongMethodWithError\");\n        }\n\n        public async Task DelayMethod(int milliseconds)\n        {\n            logger.LogInformation(\"DelayMethod {Counter}.\", counter);\n            counter++;\n            await Task.Delay(TimeSpan.FromMilliseconds(milliseconds));\n        }\n\n        public Task Dispose()\n        {\n            logger.LogInformation(\"Dispose()\");\n            return Task.CompletedTask;\n        }\n\n        public Task<int> UnobservedErrorImmediate()\n        {\n            logger.LogInformation(\"UnobservedErrorImmediate()\");\n\n            bool doThrow = true;\n            // the grain method returns OK, but leaves some unobserved promise\n            Task<long> promise = Task<long>.Factory.StartNew(() =>\n            {\n                if (!doThrow)\n                    return 0;\n                logger.LogInformation(\"About to throw 1.\");\n                throw new ArgumentException(\"ErrorGrain left Immediate Unobserved Error 1.\");\n            });\n            promise = null;\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            return Task.FromResult(11);\n        }\n\n        public Task<int> UnobservedErrorDelayed()\n        {\n            logger.LogInformation(\"UnobservedErrorDelayed()\");\n            bool doThrow = true;\n            // the grain method rturns OK, but leaves some unobserved promise\n            Task<long> promise = Task.Factory.StartNew(async () =>\n            {\n                if (!doThrow)\n                {\n                    return 0L;\n                }\n\n                await Task.Delay(100);\n                logger.LogInformation(\"About to throw 1.5.\");\n                throw new ArgumentException(\"ErrorGrain left Delayed Unobserved Error 1.5.\");\n            }).Unwrap();\n            promise = null;\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            return Task.FromResult(11);\n        }\n\n        public Task<int> UnobservedErrorContinuation2()\n        {\n            logger.LogInformation(\"UnobservedErrorContinuation2()\");\n            // the grain method returns OK, but leaves some unobserved promise\n            Task<long> promise = Task.FromResult((long)25);\n            Task cont = promise.ContinueWith(_ =>\n                {\n                    logger.LogInformation(\"About to throw 2.\");\n                    throw new ArgumentException(\"ErrorGrain left ContinueWith Unobserved Error 2.\");\n                });\n            promise = null;\n            cont = null;\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            return Task.FromResult(11);\n        }\n\n        public Task<int> UnobservedErrorContinuation3()\n        {\n            logger.LogInformation(\"UnobservedErrorContinuation3() from Task {TaskId}\", Task.CurrentId);\n            // the grain method returns OK, but leaves some unobserved promise\n            Task<long> promise = Task<long>.Factory.StartNew(() =>\n            {\n                logger.LogInformation(\"First promise from Task {TaskId}\", Task.CurrentId);\n                return 26;\n            });\n            Task cont = promise.ContinueWith(_ =>\n            {\n                logger.LogInformation(\"About to throw 3 from Task {TaskId}\", Task.CurrentId);\n                throw new ArgumentException(\"ErrorGrain left ContinueWith Unobserved Error 3.\");\n            });\n            //logger.Info(\"cont.number=\" + cont.task.number + \" cont.m_Task.number=\" + cont.task.m_Task.Id);\n            promise = null;\n            cont = null;\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            return Task.FromResult(11);\n        }\n\n        public Task<int> UnobservedIgnoredError()\n        {\n            logger.LogInformation(\"UnobservedIgnoredError()\");\n            bool doThrow = true;\n            // the grain method rturns OK, but leaves some unobserved promise\n            Task<long> promise = Task<long>.Factory.StartNew(() =>\n            {\n                if (!doThrow)\n                    return 0;\n                throw new ArgumentException(\"ErrorGrain left Unobserved Error, but asked to ignore it later.\");\n            });\n            promise.Ignore();\n            return Task.FromResult(11);\n        }\n\n        public Task AddChildren(List<IErrorGrain> children)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task<bool> ExecuteDelayed(TimeSpan delay)\n        {\n            object ctxBefore = RuntimeContext.Current;\n\n            await Task.Delay(delay);\n            object ctxInside = RuntimeContext.Current;\n            return ReferenceEquals(ctxBefore, ctxInside);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ExtensionTestGrain.cs",
    "content": "using Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class ExtensionTestGrain : Grain, IExtensionTestGrain\n    {\n        private readonly IGrainContext _grainContext;\n        public string ExtensionProperty { get; private set; }\n        private TestExtension extender;\n\n        public ExtensionTestGrain(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ExtensionProperty = \"\";\n            extender = null;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task InstallExtension(string name)\n        {\n            if (extender == null)\n            {\n                extender = new TestExtension(this, GrainFactory);\n                _grainContext.SetComponent<ITestExtension>(extender);\n            }\n\n            ExtensionProperty = name;\n            return Task.CompletedTask;\n        }\n    }\n\n    public class GenericExtensionTestGrain<T> : Grain, IGenericExtensionTestGrain<T>\n    {\n        private readonly IGrainContext _grainContext;\n        public T ExtensionProperty { get; private set; }\n        private GenericTestExtension<T> extender;\n\n        public GenericExtensionTestGrain(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ExtensionProperty = default;\n            extender = null;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task InstallExtension(T name)\n        {\n            if (extender == null)\n            {\n                extender = new GenericTestExtension<T>(this, this.GrainFactory);\n                _grainContext.SetComponent<IGenericTestExtension<T>>(extender);\n            }\n\n            ExtensionProperty = name;\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class GenericGrainWithNonGenericExtension<T> : Grain, IGenericGrainWithNonGenericExtension<T>\n    {\n        private readonly IGrainContext _grainContext;\n        private SimpleExtension extender;\n\n        public GenericGrainWithNonGenericExtension(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        public Task DoSomething()\n        {\n            return Task.CompletedTask;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (extender == null)\n            {\n                extender = new SimpleExtension(\"A\");\n                _grainContext.SetComponent<ISimpleExtension>(extender);\n            }\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/HashBasedPlacementGrain.cs",
    "content": "﻿using Orleans.Placement;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [HashBasedPlacement]\n    public class HashBasedBasedPlacementGrain : Grain, IHashBasedPlacementGrain\n    {\n\n        public Task<SiloAddress> GetSiloAddress()\n        {\n            return Task.FromResult(this.Runtime.SiloAddress);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/InterlockedFlag.cs",
    "content": "namespace UnitTests.TestHelper\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public sealed class InterlockedFlag\n    {\n        [Orleans.Id(0)]\n        private int _value;\n\n        public InterlockedFlag()\n        {\n            _value = 0;\n        }\n\n        public bool IsSet { get { return _value != 0; } }\n\n        public bool TrySet()\n        {\n            // attempt to set _value; if we're the first to attempt to do it, return true;\n            return 0 == Interlocked.CompareExchange(ref _value, 1, 0);\n        }\n\n        public void ThrowNotInitializedIfSet()\n        {\n            if (IsSet)\n                throw new InvalidOperationException(\"Attempt to access object that isn't initialized (or has been marked as dead).\");\n        }\n\n        public void ThrowDisposedIfSet(Type type)\n        {\n            if (type == null)\n                throw new ArgumentNullException(nameof(type));\n            if (IsSet)\n                throw new ObjectDisposedException(type.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/MultifacetFactoryTestGrain.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class MultifacetFactoryTestGrainState\n    {\n        [Id(0)]\n        public IMultifacetReader Reader { get; set; }\n        [Id(1)]\n        public IMultifacetWriter Writer { get; set; }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class MultifacetFactoryTestGrain : Grain<MultifacetFactoryTestGrainState>, IMultifacetFactoryTestGrain\n    {\n        public Task<IMultifacetReader> GetReader(IMultifacetTestGrain grain)\n        {\n            return Task.FromResult<IMultifacetReader>(grain);\n        }\n\n        public Task<IMultifacetReader> GetReader()\n        {\n            return Task.FromResult(State.Reader);\n        }\n\n        public Task<IMultifacetWriter> GetWriter(IMultifacetTestGrain grain)\n        {\n            return Task.FromResult<IMultifacetWriter>(grain);\n        }\n\n        public Task<IMultifacetWriter> GetWriter()\n        {\n            return Task.FromResult(State.Writer);\n        }\n\n        public Task SetReader(IMultifacetReader reader)\n        {\n            State.Reader = reader;\n            return Task.CompletedTask;\n        }\n\n        public Task SetWriter(IMultifacetWriter writer)\n        {\n            State.Writer = writer;\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/MultifacetTestGrain.cs",
    "content": "﻿using Orleans.Providers;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class MultifacetTestGrainState\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class MultifacetTestGrain : Grain<MultifacetTestGrainState>, IMultifacetTestGrain\n    {\n        \n        public string GetRuntimeInstanceId()\n        {\n            return RuntimeIdentity;\n        }\n\n        public Task SetValue(int x)\n        {\n            State.Value = x;\n            return Task.CompletedTask;\n        }\n\n        Task<int> IMultifacetReader.GetValue()\n        {\n            return Task.FromResult(State.Value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/ObservableGrain.cs",
    "content": "using System.Runtime.CompilerServices;\nusing System.Threading.Channels;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class ObservableGrain : Grain, IObservableGrain, IIncomingGrainCallFilter\n    {\n        private readonly List<(string InterfaceName, string MethodName)> _localCalls = new();\n        private readonly Channel<string> _updates = Channel.CreateUnbounded<string>();\n        private readonly Dictionary<Guid, TaskCompletionSource> _receivedCalls = [];\n        private readonly HashSet<Guid> _canceledCalls = [];\n\n        public IAsyncEnumerable<string> GetValues(CancellationToken cancellationToken) => _updates.Reader.ReadAllAsync(cancellationToken);\n        public ValueTask<HashSet<Guid>> GetCanceledCalls() => new(_canceledCalls);\n        public ValueTask WaitForCall(Guid id)\n        {\n            var tcs = GetReceivedCallTcs(id);\n\n            return new(tcs.Task);\n        }\n\n        private TaskCompletionSource GetReceivedCallTcs(Guid id)\n        {\n            if (!_receivedCalls.TryGetValue(id, out var tcs))\n            {\n                tcs = _receivedCalls[id] = new();\n            }\n\n            return tcs;\n        }\n\n        public async IAsyncEnumerable<int> GetValuesWithError(int errorIndex, bool waitAfterYield, string errorMessage, [EnumeratorCancellation] CancellationToken cancellationToken)\n        {\n            await Task.Yield();\n            for (var i = 0; i < int.MaxValue; i++)\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n                if (i == errorIndex)\n                {\n                    if (errorMessage == \"cancel\")\n                    {\n                        throw new OperationCanceledException(errorMessage);\n                    }\n\n                    throw new InvalidOperationException(errorMessage);\n                }\n\n                yield return i;\n                await Task.Yield();\n            }\n        }\n\n        public ValueTask Complete()\n        {\n            _updates.Writer.Complete();\n            return default;\n        }\n\n        public ValueTask Fail()\n        {\n            _updates.Writer.Complete(new Exception(\"I've failed you!\"));\n            return default;\n        }\n\n        public ValueTask Deactivate()\n        {\n            DeactivateOnIdle();\n            return default;\n        }\n\n        public ValueTask OnNext(string data) => _updates.Writer.WriteAsync(data);\n\n        public ValueTask<List<(string InterfaceName, string MethodName)>> GetIncomingCalls() => new(_localCalls);\n\n        public Task Invoke(IIncomingGrainCallContext context)\n        {\n            _localCalls.Add((context.InterfaceName, context.MethodName));\n            return context.Invoke();\n        }\n\n        public async IAsyncEnumerable<int> SleepyEnumerable(Guid id, TimeSpan delay, [EnumeratorCancellation] CancellationToken cancellationToken = default)\n        {\n            try\n            {\n                GetReceivedCallTcs(id).TrySetResult();\n                await Task.Delay(delay, cancellationToken);\n                yield return 1;\n            }\n            finally\n            {\n                if (cancellationToken.IsCancellationRequested)\n                {\n                    _canceledCalls.Add(id);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/PersistenceTestGrains.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing System.Text;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Configuration;\nusing Orleans.Core;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Grains\n{\n    internal static class TestRuntimeEnvironmentUtility\n    {\n        public static string CaptureRuntimeEnvironment()\n        {\n            var callStack = Utils.GetStackTrace(1); // Don't include this method in stack trace\n            return\n                $\"\"\"\n                TaskScheduler={TaskScheduler.Current}\n                RuntimeContext={RuntimeContext.Current}\n                WorkerPoolThread={Thread.CurrentThread.Name}\n                Thread.CurrentThread.ManagedThreadId={Environment.CurrentManagedThreadId}\n                StackTrace={callStack}\n                \"\"\";\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class PersistenceGenericGrainState<T>\n    {\n        [Id(0)]\n        public T Field1 { get; set; }\n        [Id(1)]\n        public string Field2 { get; set; }\n        [Id(2)]\n        public SortedDictionary<T, T> SortedDict { get; set; }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"test1\")]\n    public class PersistenceTestGrain : Grain<PersistenceTestGrainState>, IPersistenceTestGrain\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> CheckStateInit()\n        {\n            Assert.NotNull(State);\n            Assert.Equal(0, State.Field1);\n            Assert.Null(State.Field2);\n            //Assert.NotNull(State.Field3, \"Null Field3\");\n            //Assert.AreEqual(0, State.Field3.Count, \"Field3 = {0}\", String.Join(\"'\", State.Field3));\n            Assert.NotNull(State.SortedDict);\n            return Task.FromResult(true);\n        }\n\n        public Task<string> CheckProviderType()\n        {\n            IGrainStorage grainStorage = GrainStorageHelpers.GetGrainStorage(GetType(), this.ServiceProvider);\n            Assert.NotNull(grainStorage);\n            return Task.FromResult(grainStorage.GetType().FullName);\n        }\n\n        public Task DoSomething()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            State.SortedDict[val] = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync();\n            return State.Field1;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public async Task DoDelete()\n        {\n            await ClearStateAsync();\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"test1\")]\n    public class PersistenceTestGenericGrain<T> : PersistenceTestGrain, IPersistenceTestGenericGrain<T>\n    {\n        //...\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"ErrorInjector\")]\n    public class PersistenceProviderErrorGrain : Grain<PersistenceTestGrainState>, IPersistenceProviderErrorGrain\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync();\n            return State.Field1;\n        }\n\n        public Task<string> GetActivationId() => Task.FromResult(_id);\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"ErrorInjector\")]\n    public class PersistenceUserHandledErrorGrain : Grain<PersistenceTestGrainState>, IPersistenceUserHandledErrorGrain\n    {\n        private readonly ILogger logger;\n        private readonly DeepCopier<PersistenceTestGrainState> copier;\n\n        public PersistenceUserHandledErrorGrain(ILoggerFactory loggerFactory, DeepCopier<PersistenceTestGrainState> copier)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n            this.copier = copier;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public async Task DoWrite(int val, bool recover)\n        {\n            var original = this.copier.Copy(State);\n            try\n            {\n                State.Field1 = val;\n                await WriteStateAsync();\n            }\n            catch (Exception exc)\n            {\n                if (!recover) throw;\n\n                this.logger.LogWarning(exc, \"Grain is handling error in DoWrite - Resetting value to {Original}\", original);\n                State = (PersistenceTestGrainState)original;\n            }\n        }\n\n        public async Task<int> DoRead(bool recover)\n        {\n            var original = this.copier.Copy(State);\n            try\n            {\n                await ReadStateAsync();\n            }\n            catch (Exception exc)\n            {\n                if (!recover) throw;\n\n                this.logger.LogWarning(exc, \"Grain is handling error in DoRead - Resetting value to {Original}\", original);\n                State = (PersistenceTestGrainState)original;\n            }\n            return State.Field1;\n        }\n    }\n\n    public class PersistenceProviderErrorProxyGrain : Grain, IPersistenceProviderErrorProxyGrain\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n\n        public Task<int> GetValue(IPersistenceProviderErrorGrain other) => other.GetValue();\n\n        public Task DoWrite(int val, IPersistenceProviderErrorGrain other) => other.DoWrite(val);\n\n        public Task<int> DoRead(IPersistenceProviderErrorGrain other) => other.DoRead();\n\n        public Task<string> GetActivationId() => Task.FromResult(_id);\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"test1\")]\n    public class PersistenceErrorGrain : Grain<PersistenceTestGrainState>, IPersistenceErrorGrain\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task DoWriteError(int val, bool errorBeforeUpdate)\n        {\n            if (errorBeforeUpdate) throw new ApplicationException(\"Before Update\");\n            State.Field1 = val;\n            await WriteStateAsync();\n            throw new ApplicationException(\"After Update\");\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync(); // Re-read state from store\n            return State.Field1;\n        }\n\n        public async Task<int> DoReadError(bool errorBeforeRead)\n        {\n            if (errorBeforeRead) throw new ApplicationException(\"Before Read\");\n            await ReadStateAsync(); // Attempt to re-read state from store\n            throw new ApplicationException(\"After Read\");\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MissingProvider\")]\n    public class BadProviderTestGrain : Grain<PersistenceTestGrainState>, IBadProviderTestGrain\n    {\n        private readonly ILogger logger;\n\n        public BadProviderTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger.LogWarning(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task DoSomething()\n        {\n            this.logger.LogWarning(\"DoSomething\");\n            throw new ApplicationException(\n                \"BadProviderTestGrain.DoSomething should never get called when provider is missing\");\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"test1\")]\n    public class PersistenceNoStateTestGrain : Grain, IPersistenceNoStateTestGrain\n    {\n        private readonly ILogger logger;\n\n        public PersistenceNoStateTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task DoSomething()\n        {\n            this.logger.LogInformation(\"DoSomething\");\n            return Task.CompletedTask;\n        }\n    }\n\n    public class ServiceIdGrain : Grain, IServiceIdGrain\n    {\n        private readonly IOptions<ClusterOptions> clusterOptions;\n\n        public ServiceIdGrain(IOptions<ClusterOptions> clusterOptions)\n        {\n            this.clusterOptions = clusterOptions;\n        }\n\n        public Task<string> GetServiceId()\n        {\n            return Task.FromResult(clusterOptions.Value.ServiceId);\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"GrainStorageForTest\")]\n    public class GrainStorageTestGrain : Grain<PersistenceTestGrainState>,\n        IGrainStorageTestGrain, IGrainStorageTestGrain_LongKey\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync(); // Re-read state from store\n            return State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return ClearStateAsync();\n        }\n\n        public ValueTask<GrainState<PersistenceTestGrainState>> GetStateAsync()\n        {\n            var field = GetType().BaseType.GetField(\"_storage\", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);\n            var storage = (IStorage<PersistenceTestGrainState>)field.GetValue(this);\n            return new(new GrainState<PersistenceTestGrainState>\n            {\n                RecordExists = storage.RecordExists,\n                State = storage.State,\n                ETag = storage.Etag\n            });\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"GrainStorageForTest\")]\n    public class GrainStorageGenericGrain<T> : Grain<PersistenceGenericGrainState<T>>,\n        IGrainStorageGenericGrain<T>\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<T> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task DoWrite(T val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<T> DoRead()\n        {\n            await ReadStateAsync(); // Re-read state from store\n            return State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return ClearStateAsync();\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"GrainStorageForTest\")]\n    public class GrainStorageTestGrainExtendedKey : Grain<PersistenceTestGrainState>,\n        IGrainStorageTestGrain_GuidExtendedKey, IGrainStorageTestGrain_LongExtendedKey\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task<string> GetExtendedKeyValue()\n        {\n            string extKey;\n            _ = this.GetPrimaryKey(out extKey);\n            return Task.FromResult(extKey);\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync(); // Re-read state from store\n            return State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return ClearStateAsync();\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    //[Orleans.Providers.StorageProvider(ProviderName = \"AzureStorageEmulator\")]\n    public class MemoryStorageTestGrain : Grain<MemoryStorageTestGrain.NestedPersistenceTestGrainState>,\n        IMemoryStorageTestGrain\n    {\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(State.Field1);\n        }\n\n        public Task DoWrite(int val)\n        {\n            State.Field1 = val;\n            return WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await ReadStateAsync(); // Re-read state from store\n            return State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return ClearStateAsync();\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class NestedPersistenceTestGrainState\n        {\n            [Id(0)]\n            public int Field1 { get; set; }\n            [Id(1)]\n            public string Field2 { get; set; }\n            [Id(2)]\n            public SortedDictionary<int, int> SortedDict { get; set; }\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class UserState\n    {\n        public UserState()\n        {\n            Friends = new List<IUser>();\n        }\n\n        [Id(0)]\n        public string Name { get; set; }\n        [Id(1)]\n        public string Status { get; set; }\n        [Id(2)]\n        public List<IUser> Friends { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class DerivedUserState : UserState\n    {\n        [Id(0)]\n        public int Field1 { get; set; }\n        [Id(1)]\n        public int Field2 { get; set; }\n    }\n\n    /// <summary>\n    /// Orleans grain implementation class.\n    /// </summary>\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    //[Orleans.Providers.StorageProvider(ProviderName = \"AzureStore\")]\n    //[Orleans.Providers.StorageProvider(ProviderName = \"AzureStorageEmulator\")]\n    public class UserGrain : Grain<DerivedUserState>, IUser\n    {\n        public Task SetName(string name)\n        {\n            State.Name = name;\n            return WriteStateAsync();\n        }\n\n        public Task<string> GetStatus()\n        {\n            return Task.FromResult($\"{State.Name} : {State.Status}\");\n        }\n\n        public Task<string> GetName()\n        {\n            return Task.FromResult(State.Name);\n        }\n\n        public Task UpdateStatus(string status)\n        {\n            State.Status = status;\n            return WriteStateAsync();\n        }\n\n        public Task AddFriend(IUser friend)\n        {\n            if (!State.Friends.Contains(friend))\n                State.Friends.Add(friend);\n            else\n                throw new Exception(\"Already a friend.\");\n\n            return Task.CompletedTask;\n        }\n\n        public Task<List<IUser>> GetFriends()\n        {\n            return Task.FromResult(State.Friends);\n        }\n\n        public async Task<string> GetFriendsStatuses()\n        {\n            var sb = new StringBuilder();\n            var promises = new List<Task<string>>();\n\n            foreach (var friend in State.Friends)\n                promises.Add(friend.GetStatus());\n\n            var friends = await Task.WhenAll(promises);\n\n            foreach (var f in friends)\n            {\n                sb.AppendLine(f);\n            }\n\n            return sb.ToString();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class StateForIReentrentGrain\n    {\n        public StateForIReentrentGrain()\n        {\n            DictOne = new Dictionary<string, int>();\n            DictTwo = new Dictionary<string, int>();\n        }\n\n        [Id(0)]\n        public int One { get; set; }\n        [Id(1)]\n        public int Two { get; set; }\n        [Id(2)]\n        public Dictionary<string, int> DictOne { get; set; }\n        [Id(3)]\n        public Dictionary<string, int> DictTwo { get; set; }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    [Reentrant]\n    public class ReentrentGrainWithState : Grain<StateForIReentrentGrain>, IReentrentGrainWithState\n    {\n        private const int Multiple = 100;\n\n        private IReentrentGrainWithState _other;\n        private IGrainContext _context;\n        private TaskScheduler _scheduler;\n        private readonly ILogger logger;\n        private bool executing;\n        private Task outstandingWriteStateOperation;\n\n        public ReentrentGrainWithState(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _context = RuntimeContext.Current;\n            _scheduler = TaskScheduler.Current;\n            executing = false;\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        // When reentrant grain is doing WriteStateAsync, etag violations are posssible due to concurent writes.\n        // The solution is to serialize all writes, and make sure only a single write is outstanind at any moment in time.\n        // No deadlocks are posssible with that approach, since all WriteStateAsync go to the store, which does not issue call into grains,\n        // thus cycle of calls is not posssible.\n        // Implementaton: need to use While and not if, due to the same \"early check becomes later invalid\" standard problem, like in conditional variables.\n        private async Task PerformSerializedStateUpdate()\n        {\n            while (outstandingWriteStateOperation != null)\n            {\n                await outstandingWriteStateOperation;\n            }\n\n            try\n            {\n                outstandingWriteStateOperation = WriteStateAsync();\n                await outstandingWriteStateOperation;\n            }\n            finally\n            {\n                outstandingWriteStateOperation = null;\n            }\n        }\n\n        public Task Setup(IReentrentGrainWithState other)\n        {\n            logger.LogInformation(\"Setup\");\n            _other = other;\n            return Task.CompletedTask;\n        }\n\n        public async Task SetOne(int val)\n        {\n            logger.LogInformation(\"SetOne Start\");\n            CheckRuntimeEnvironment();\n            var iStr = val.ToString(CultureInfo.InvariantCulture);\n            State.One = val;\n            State.DictOne[iStr] = val;\n            State.DictTwo[iStr] = val;\n            CheckRuntimeEnvironment();\n            await PerformSerializedStateUpdate();\n            CheckRuntimeEnvironment();\n        }\n\n        public async Task SetTwo(int val)\n        {\n            logger.LogInformation(\"SetTwo Start\");\n            CheckRuntimeEnvironment();\n            var iStr = val.ToString(CultureInfo.InvariantCulture);\n            State.Two = val;\n            State.DictTwo[iStr] = val;\n            State.DictOne[iStr] = val;\n            CheckRuntimeEnvironment();\n            await PerformSerializedStateUpdate();\n            CheckRuntimeEnvironment();\n        }\n\n        public async Task Test1()\n        {\n            logger.LogInformation(\" ==================================== Test1 Started\");\n            CheckRuntimeEnvironment();\n            for (var i = 1*Multiple; i < 2*Multiple; i++)\n            {\n                var t1 = SetOne(i);\n                await t1;\n                CheckRuntimeEnvironment();\n\n                var t2 = PerformSerializedStateUpdate();\n                await t2;\n                CheckRuntimeEnvironment();\n\n                var t3 = _other.SetTwo(i);\n                await t3;\n                CheckRuntimeEnvironment();\n\n                var t4 = PerformSerializedStateUpdate();\n                await t4;\n                CheckRuntimeEnvironment();\n            }\n            CheckRuntimeEnvironment();\n            logger.LogInformation(\" ==================================== Test1 Done\");\n        }\n\n        public async Task Test2()\n        {\n            logger.LogInformation(\"==================================== Test2 Started\");\n            CheckRuntimeEnvironment();\n            for (var i = 2*Multiple; i < 3*Multiple; i++)\n            {\n                var t1 = _other.SetOne(i);\n                await t1;\n                CheckRuntimeEnvironment();\n\n                var t2 = PerformSerializedStateUpdate();\n                await t2;\n                CheckRuntimeEnvironment();\n\n                var t3 = SetTwo(i);\n                await t3;\n                CheckRuntimeEnvironment();\n\n                var t4 = PerformSerializedStateUpdate();\n                await t4;\n                CheckRuntimeEnvironment();\n            }\n            CheckRuntimeEnvironment();\n            logger.LogInformation(\" ==================================== Test2 Done\");\n        }\n\n        public async Task Task_Delay(bool doStart)\n        {\n            var wrapper = new Task<Task>(async () =>\n            {\n                logger.LogInformation(\"Before Task.Delay #1 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n                await DoDelay(1);\n                logger.LogInformation(\"After Task.Delay #1 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n                await DoDelay(2);\n                logger.LogInformation(\"After Task.Delay #2 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n            });\n\n            if (doStart)\n            {\n                wrapper.Start(); // THIS IS THE KEY STEP!\n            }\n\n            await wrapper.Unwrap();\n        }\n\n        private async Task DoDelay(int i)\n        {\n            logger.LogInformation(\"Before Task.Delay #{Num} TaskScheduler.Current={TaskScheduler}\", i, TaskScheduler.Current);\n            await Task.Delay(1);\n            logger.LogInformation(\"After Task.Delay #{Num} TaskScheduler.Current={TaskScheduler}\", i, TaskScheduler.Current);\n        }\n\n        private void CheckRuntimeEnvironment()\n        {\n            if (executing)\n            {\n                var errorMsg = \"Found out that this grain is already in the middle of execution.\"\n                               + \" Single threaded-ness violation!\\n\" +\n                               TestRuntimeEnvironmentUtility.CaptureRuntimeEnvironment();\n                this.logger.LogError(1, \"{Message}\", \"\\n\\n\\n\\n\" + errorMsg + \"\\n\\n\\n\\n\");\n                throw new Exception(errorMsg);\n                //Environment.Exit(1);\n            }\n\n            if (RuntimeContext.Current == null)\n            {\n                var errorMsg = \"Found RuntimeContext.Current == null.\\n\" + TestRuntimeEnvironmentUtility.CaptureRuntimeEnvironment();\n                this.logger.LogError(1, \"{Message}\", \"\\n\\n\\n\\n\" + errorMsg + \"\\n\\n\\n\\n\");\n                throw new Exception(errorMsg);\n                //Environment.Exit(1);\n            }\n\n            var context = RuntimeContext.Current;\n            var scheduler = TaskScheduler.Current;\n\n            executing = true;\n            Assert.Equal(_scheduler, scheduler);\n            Assert.Equal(_context, context);\n            Assert.NotNull(context);\n            executing = false;\n        }\n    }\n\n    internal class NonReentrantStressGrainWithoutState : Grain, INonReentrantStressGrainWithoutState\n    {\n        private const int Multiple = 100;\n        private ILogger logger;\n        private bool executing;\n        private const int LEVEL = 2; // level 2 is enough to repro the problem.\n\n        private static int _counter = 1;\n        private int _id;\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _id = _counter++;\n            var loggerFactory = this.ServiceProvider?.GetService<ILoggerFactory>();\n            //if grain created outside a cluster\n            if (loggerFactory == null)\n                loggerFactory = NullLoggerFactory.Instance;\n            logger = loggerFactory.CreateLogger($\"NonReentrantStressGrainWithoutState-{_id}\");\n\n            executing = false;\n            logger.LogTrace(\"--> OnActivateAsync\");\n            logger.LogTrace(\"<-- OnActivateAsync\");\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        private async Task SetOne(int iter, int level)\n        {\n            if (logger.IsEnabled(LogLevel.Trace))\n            {\n                logger.LogTrace(\"---> SetOne {Iteration}-{Level}_0\", iter, level);\n            }\n\n            CheckRuntimeEnvironment();\n            if (level > 0)\n            {\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"SetOne {Iteration}-{Level}_1. Before await Task.CompletedTask.\", iter, level);\n                }\n\n                await Task.CompletedTask;\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"SetOne {Iteration}-{Level}_2. After await Task.CompletedTask.\", iter, level);\n                }\n\n                CheckRuntimeEnvironment();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"SetOne {Iteration}-{Level}_4. Before yield.\", iter, level);\n                }\n\n                await Task.Yield();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"SetOne {Iteration}-{Level}_5. After yield.\", iter, level);\n                }\n\n                CheckRuntimeEnvironment();\n                var nextLevel = level - 1;\n                await SetOne(iter, nextLevel);\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\n                        \"SetOne {Iteration}-{Level}_7 => {NextLevel}. After await SetOne call.\",\n                        iter,\n                        level,\n                        nextLevel);\n                }\n\n                CheckRuntimeEnvironment();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"SetOne {Iteration}-{Level}_9. Finished SetOne.\", iter, level);\n                }\n            }\n\n            CheckRuntimeEnvironment();\n            logger.LogTrace(\"<--- SetOne {Iteration}-{Level}_11\", iter, level);\n        }\n\n        public async Task Test1()\n        {\n            CheckRuntimeEnvironment();\n            if (logger.IsEnabled(LogLevel.Trace))\n            {\n                logger.LogTrace(\"Test1.Start\");\n            }\n\n            var tasks = new List<Task>();\n            for (var i = 0; i < Multiple; i++)\n            {\n                CheckRuntimeEnvironment();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"Test1_ ------> {CallNum}\", i);\n                }\n\n                var task = SetOne(i, LEVEL);\n                CheckRuntimeEnvironment();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"After SetOne call {CallNum}\", i);\n                }\n\n                tasks.Add(task);\n                CheckRuntimeEnvironment();\n                if (logger.IsEnabled(LogLevel.Trace))\n                {\n                    logger.LogTrace(\"Test1_ <------ {CallNum}\", i);\n                }\n            }\n\n            CheckRuntimeEnvironment();\n            if (logger.IsEnabled(LogLevel.Trace))\n            {\n                logger.LogTrace(\"Test1_About to WhenAll\");\n            }\n\n            await Task.WhenAll(tasks);\n            if (logger.IsEnabled(LogLevel.Trace))\n            {\n                logger.LogTrace(\"Test1.Finish\");\n            }\n\n           CheckRuntimeEnvironment();\n//#if DEBUG\n//            // HACK for testing\n//            Logger.SetTraceLevelOverrides(overridesOff.ToList());\n//#endif\n        }\n\n        public async Task Task_Delay(bool doStart)\n        {\n            var wrapper = new Task<Task>(async () =>\n            {\n                logger.LogTrace(\"Before Task.Delay #1 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n                await DoDelay(1);\n                logger.LogTrace(\"After Task.Delay #1 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n                await DoDelay(2);\n                logger.LogTrace(\"After Task.Delay #2 TaskScheduler.Current={TaskScheduler}\", TaskScheduler.Current);\n            });\n\n            if (doStart)\n            {\n                wrapper.Start(); // THIS IS THE KEY STEP!\n            }\n\n            await wrapper.Unwrap();\n        }\n\n        private async Task DoDelay(int i)\n        {\n            logger.LogTrace(\"Before Task.Delay #{Num} TaskScheduler.Current={TaskScheduler}\", i, TaskScheduler.Current);\n            await Task.Delay(1);\n            logger.LogTrace(\"After Task.Delay #{Num} TaskScheduler.Current={TaskScheduler}\", i, TaskScheduler.Current);\n        }\n\n        private void CheckRuntimeEnvironment()\n        {\n            if (executing)\n            {\n                var callStack = new StackTrace();\n                var errorMsg = string.Format(\n                    \"Found out that grain {0} is already in the middle of execution.\"\n                    + \"\\n Single threaded-ness violation!\"\n                    + \"\\n {1} \\n Call Stack={2}\",\n                    this._id,\n                    TestRuntimeEnvironmentUtility.CaptureRuntimeEnvironment(),\n                    callStack);\n                this.logger.LogError(1, \"{Message}\", \"\\n\\n\\n\\n\" + errorMsg + \"\\n\\n\\n\\n\");\n                throw new InvalidOperationException(errorMsg);\n            }\n\n            executing = true;\n            var stopwatch = ValueStopwatch.StartNew();\n            SpinWait.SpinUntil(() => stopwatch.Elapsed > TimeSpan.FromMicroseconds(1));\n            executing = false;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class InternalGrainStateData\n    {\n        [Id(0)]\n        public int One { get; set; }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    internal class InternalGrainWithState : Grain<InternalGrainStateData>, IInternalGrainWithState\n    {\n        private readonly ILogger logger;\n\n        public InternalGrainWithState(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public Task SetOne(int val)\n        {\n            logger.LogInformation(\"SetOne\");\n            State.One = val;\n            return Task.CompletedTask;\n        }\n    }\n\n    public interface IBaseStateData // Note: I am deliberately not using IGrainState here.\n    {\n        int Field1 { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class StateInheritanceTestGrainData : IBaseStateData\n    {\n        [Id(0)]\n        private int Field2 { get; set; }\n\n        [Id(1)]\n        public int Field1 { get; set; }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class StateInheritanceTestGrain : Grain<StateInheritanceTestGrainData>, IStateInheritanceTestGrain\n    {\n        private readonly ILogger logger;\n\n        public StateInheritanceTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<int> GetValue()\n        {\n            var val = State.Field1;\n            logger.LogInformation(\"GetValue {Value}\", val);\n            return Task.FromResult(val);\n        }\n\n        public Task SetValue(int val)\n        {\n            State.Field1 = val;\n            logger.LogInformation(\"SetValue {Value}\", val);\n            return WriteStateAsync();\n        }\n    }\n\n    public sealed class SurrogateStateForTypeWithoutPublicConstructorGrain : IGrainBase, ISurrogateStateForTypeWithoutPublicConstructorGrain<ExternalTypeWithoutPublicConstructor>\n    {\n        private readonly IPersistentState<ExternalTypeWithoutPublicConstructor> _persistence;\n\n        public IGrainContext GrainContext { get; }\n\n        public SurrogateStateForTypeWithoutPublicConstructorGrain(\n            IGrainContext grainContext,\n            [PersistentState(\"test_state\", \"OrleansSerializerMemoryStore\")] IPersistentState<ExternalTypeWithoutPublicConstructor> persistence)\n        {\n            GrainContext = grainContext;\n            _persistence = persistence;\n        }\n\n        public async Task SetState(ExternalTypeWithoutPublicConstructor state)\n        {\n            _persistence.State = state;\n            await _persistence.WriteStateAsync();\n        }\n\n        public async Task<ExternalTypeWithoutPublicConstructor> GetState()\n        {\n            await _persistence.ReadStateAsync();\n            return _persistence.State;\n        }\n    }\n\n    public sealed class ExternalTypeWithoutPublicConstructor\n    {\n        public int Field1 { get; set; }\n        public int Field2 { get; set; }\n\n        public static ExternalTypeWithoutPublicConstructor Create(int field1, int field2)\n            => new(field1, field2);\n\n        private ExternalTypeWithoutPublicConstructor(int field1, int field2)\n        {\n            Field1 = field1;\n            Field2 = field2;\n        }\n    }\n\n    [GenerateSerializer]\n    public struct ExternalTypeWithoutPublicConstructorSurrogate\n    {\n        [Id(0)] public int Field1;\n        [Id(1)] public required int Field2;\n    }\n\n    [RegisterConverter]\n    public sealed class ExternalTypeWithoutPublicConstructorSurrogateConverter : IConverter<ExternalTypeWithoutPublicConstructor, ExternalTypeWithoutPublicConstructorSurrogate>\n    {\n        public ExternalTypeWithoutPublicConstructor ConvertFromSurrogate(in ExternalTypeWithoutPublicConstructorSurrogate surrogate)\n            => ExternalTypeWithoutPublicConstructor.Create(surrogate.Field1, surrogate.Field2);\n\n        public ExternalTypeWithoutPublicConstructorSurrogate ConvertToSurrogate(in ExternalTypeWithoutPublicConstructor value)\n            => new()\n            {\n                Field1 = value.Field1,\n                Field2 = value.Field2,\n            };\n    }\n    \n\n    public sealed class RecordTypeWithoutPublicParameterlessConstructorGrain : IGrainBase, IRecordTypeWithoutPublicParameterlessConstructorGrain<RecordTypeWithoutPublicParameterlessConstructor>\n    {\n        private readonly IPersistentState<RecordTypeWithoutPublicParameterlessConstructor> _persistence;\n\n        public IGrainContext GrainContext { get; }\n\n        public RecordTypeWithoutPublicParameterlessConstructorGrain(\n            IGrainContext grainContext,\n            [PersistentState(\"test_state\", \"OrleansSerializerMemoryStore\")] IPersistentState<RecordTypeWithoutPublicParameterlessConstructor> persistence)\n        {\n            GrainContext = grainContext;\n            _persistence = persistence;\n        }\n\n        public async Task SetState(RecordTypeWithoutPublicParameterlessConstructor state)\n        {\n            _persistence.State = state;\n            await _persistence.WriteStateAsync();\n        }\n\n        public async Task<RecordTypeWithoutPublicParameterlessConstructor> GetState()\n        {\n            await _persistence.ReadStateAsync();\n            return _persistence.State;\n        }\n    }\n\n    [GenerateSerializer]\n    public record class RecordTypeWithoutPublicParameterlessConstructor\n    (\n        [property: Id(0)] int Field\n    );\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/PersistentStateTestGrains.cs",
    "content": "using Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace UnitTests.PersistentState.Grains\n{\n    [GrainType(\"new-test-storage-grain\")]\n    public class GrainStorageTestGrain : Grain,\n        IGrainStorageTestGrain, IGrainStorageTestGrain_LongKey\n    {\n        private readonly IPersistentState<PersistenceTestGrainState> persistentState;\n\n        public GrainStorageTestGrain(\n            [PersistentState(\"state\", \"GrainStorageForTest\")]\n            IPersistentState<PersistenceTestGrainState> persistentState)\n        {\n            this.persistentState = persistentState;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(this.persistentState.State.Field1);\n        }\n\n        public Task DoWrite(int val)\n        {\n            this.persistentState.State.Field1 = val;\n            return this.persistentState.WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await this.persistentState.ReadStateAsync(); // Re-read state from store\n            return this.persistentState.State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return this.persistentState.ClearStateAsync();\n        }\n\n        public ValueTask<GrainState<PersistenceTestGrainState>> GetStateAsync()\n        {\n            return new(new GrainState<PersistenceTestGrainState>\n            {\n                RecordExists = persistentState.RecordExists,\n                State = persistentState.State,\n                ETag = persistentState.Etag\n            });\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"GrainStorageForTest\")]\n    [GrainType(\"new-test-storage-grain-with-extended-key\")]\n    public class GrainStorageTestGrainExtendedKey : Grain,\n        IGrainStorageTestGrain_GuidExtendedKey, IGrainStorageTestGrain_LongExtendedKey\n    {\n        private readonly IPersistentState<PersistenceTestGrainState> persistentState;\n\n        public GrainStorageTestGrainExtendedKey(\n            [PersistentState(\"state\", \"GrainStorageForTest\")]\n            IPersistentState<PersistenceTestGrainState> persistentState)\n        {\n            this.persistentState = persistentState;\n        }\n\n        public Task<int> GetValue()\n        {\n            return Task.FromResult(this.persistentState.State.Field1);\n        }\n\n        public Task<string> GetExtendedKeyValue()\n        {\n            string extKey;\n            _ = this.GetPrimaryKey(out extKey);\n            return Task.FromResult(extKey);\n        }\n\n        public Task DoWrite(int val)\n        {\n            this.persistentState.State.Field1 = val;\n            return this.persistentState.WriteStateAsync();\n        }\n\n        public async Task<int> DoRead()\n        {\n            await this.persistentState.ReadStateAsync(); // Re-read state from store\n            return this.persistentState.State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return this.persistentState.ClearStateAsync();\n        }\n    }\n\n    [GrainType(\"new-test-storage-generic-grain`1\")]\n    public class GrainStorageGenericGrain<T> : Grain,\n        IGrainStorageGenericGrain<T>\n    {\n        private readonly IPersistentState<PersistenceGenericGrainState<T>> persistentState;\n\n        public GrainStorageGenericGrain(\n            [PersistentState(\"state\", \"GrainStorageForTest\")]\n            IPersistentState<PersistenceGenericGrainState<T>> persistentState)\n        {\n            this.persistentState = persistentState;\n        }\n\n        public Task<T> GetValue()\n        {\n            return Task.FromResult(this.persistentState.State.Field1);\n        }\n\n        public Task DoWrite(T val)\n        {\n            this.persistentState.State.Field1 = val;\n            return this.persistentState.WriteStateAsync();\n        }\n\n        public async Task<T> DoRead()\n        {\n            await this.persistentState.ReadStateAsync(); // Re-read state from store\n            return this.persistentState.State.Field1;\n        }\n\n        public Task DoDelete()\n        {\n            return this.persistentState.ClearStateAsync();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/PlacementTestGrain.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Concurrency;\nusing Orleans.Configuration;\nusing Orleans.Placement;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.TestHooks;\nusing Orleans.Statistics;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Grains\n{\n    internal abstract class PlacementTestGrainBase : Grain\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n\n        private readonly OverloadDetector overloadDetector;\n\n        private readonly TestHooksEnvironmentStatisticsProvider environmentStatistics;\n        private readonly IGrainContext _grainContext;\n        private readonly LoadSheddingOptions loadSheddingOptions;\n\n        public PlacementTestGrainBase(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n            this.overloadDetector = overloadDetector;\n            this.environmentStatistics = hostEnvironmentStatistics;\n            this.loadSheddingOptions = loadSheddingOptions.Value;\n        }\n\n        public Task<IPEndPoint> GetEndpoint()\n        {\n            return Task.FromResult(_grainContext.Address.SiloAddress.Endpoint);\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public Task<string> GetActivationId()\n        {\n            return Task.FromResult(_id);\n        }\n\n        public Task Nop()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task StartLocalGrains(List<Guid> keys)\n        {\n            // we call Nop() on the grain references to ensure that they're instantiated before the promise is delivered.\n            var grains = keys.Select(i => GrainFactory.GetGrain<IStatelessWorkerPlacementTestGrain>(i));\n            var promises = grains.Select(g => g.Nop());\n            return Task.WhenAll(promises);\n        }\n\n        public async Task<Guid> StartPreferLocalGrain(Guid key)\n        {\n            // we call Nop() on the grain references to ensure that they're instantiated before the promise is delivered.\n            await GrainFactory.GetGrain<IPreferLocalPlacementTestGrain>(key).Nop();\n            return key;\n        }\n\n        private static IEnumerable<Task<IPEndPoint>> SampleLocalGrainEndpoint(IStatelessWorkerPlacementTestGrain grain, int sampleSize)\n        {\n            for (var i = 0; i < sampleSize; ++i)\n                yield return grain.GetEndpoint();\n        }\n\n        public async Task<List<IPEndPoint>> SampleLocalGrainEndpoint(Guid key, int sampleSize)\n        {\n            var grain = GrainFactory.GetGrain<IStatelessWorkerPlacementTestGrain>(key);\n            var p = await Task.WhenAll(SampleLocalGrainEndpoint(grain, sampleSize));\n            return p.ToList();\n        }\n\n        private static async Task PropagateStatisticsToCluster(IGrainFactory grainFactory)\n        {\n            // force the latched statistics to propagate throughout the cluster.\n            var managementGrain = grainFactory.GetGrain<IManagementGrain>(0);\n            var hosts = await managementGrain.GetHosts(true);\n            var keys = hosts.Select(kvp => kvp.Key).ToArray();\n            await managementGrain.ForceRuntimeStatisticsCollection(keys);\n        }\n\n        public Task EnableOverloadDetection(bool enabled)\n        {\n            this.overloadDetector.Enabled = enabled;\n            return Task.CompletedTask;\n        }\n\n        public Task LatchOverloaded()\n        {\n            var stats = environmentStatistics.GetEnvironmentStatistics();\n            environmentStatistics.LatchHardwareStatistics(new EnvironmentStatistics(\n                cpuUsagePercentage: loadSheddingOptions.CpuThreshold + 1,\n                rawCpuUsagePercentage: loadSheddingOptions.CpuThreshold + 1,\n                memoryUsageBytes: stats.FilteredMemoryUsageBytes,\n                rawMemoryUsageBytes: stats.RawMemoryUsageBytes,\n                availableMemoryBytes: stats.FilteredAvailableMemoryBytes,\n                rawAvailableMemoryBytes: stats.RawAvailableMemoryBytes,\n                maximumAvailableMemoryBytes: stats.MaximumAvailableMemoryBytes));\n            return PropagateStatisticsToCluster(GrainFactory);\n        }\n\n        public Task UnlatchOverloaded()\n        {\n            var stats = environmentStatistics.GetEnvironmentStatistics();\n            environmentStatistics.LatchHardwareStatistics(new(\n                cpuUsagePercentage: 0,\n                rawCpuUsagePercentage: 0,\n                memoryUsageBytes: stats.FilteredMemoryUsageBytes,\n                rawMemoryUsageBytes: stats.RawMemoryUsageBytes,\n                availableMemoryBytes: stats.FilteredAvailableMemoryBytes,\n                rawAvailableMemoryBytes: stats.RawAvailableMemoryBytes,\n                maximumAvailableMemoryBytes: stats.MaximumAvailableMemoryBytes));\n            return PropagateStatisticsToCluster(GrainFactory);\n        }\n\n        public Task LatchCpuUsage(float value)\n        {\n            var stats = environmentStatistics.GetEnvironmentStatistics();\n            environmentStatistics.LatchHardwareStatistics(new(\n                cpuUsagePercentage: value,\n                rawCpuUsagePercentage: value,\n                memoryUsageBytes: stats.FilteredMemoryUsageBytes,\n                rawMemoryUsageBytes: stats.RawMemoryUsageBytes,\n                availableMemoryBytes: stats.FilteredAvailableMemoryBytes,\n                rawAvailableMemoryBytes: stats.RawAvailableMemoryBytes,\n                maximumAvailableMemoryBytes: stats.MaximumAvailableMemoryBytes));\n            return PropagateStatisticsToCluster(GrainFactory);\n        }\n\n        public Task UnlatchCpuUsage()\n        {\n            var stats = environmentStatistics.GetEnvironmentStatistics();\n            environmentStatistics.LatchHardwareStatistics(new(\n                cpuUsagePercentage: 0,\n                rawCpuUsagePercentage: 0,\n                memoryUsageBytes: stats.FilteredMemoryUsageBytes,\n                rawMemoryUsageBytes: stats.RawMemoryUsageBytes,\n                availableMemoryBytes: stats.FilteredAvailableMemoryBytes,\n                rawAvailableMemoryBytes: stats.RawAvailableMemoryBytes,\n                maximumAvailableMemoryBytes: stats.MaximumAvailableMemoryBytes));\n            return PropagateStatisticsToCluster(GrainFactory);\n        }\n\n        public Task<SiloAddress> GetLocation()\n        {\n            return Task.FromResult(_grainContext.Address.SiloAddress);\n        }\n    }\n\n    [RandomPlacement]\n    internal class RandomPlacementTestGrain : PlacementTestGrainBase, IRandomPlacementTestGrain\n    {\n        public RandomPlacementTestGrain(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n            : base(overloadDetector, hostEnvironmentStatistics, loadSheddingOptions, grainContext)\n        {\n        }\n    }\n\n    [PreferLocalPlacement]\n    internal class PreferLocalPlacementTestGrain : PlacementTestGrainBase, IPreferLocalPlacementTestGrain\n    {\n        public PreferLocalPlacementTestGrain(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n            : base(overloadDetector, hostEnvironmentStatistics, loadSheddingOptions, grainContext)\n        {\n        }\n    }\n\n    [StatelessWorker(1)]\n    internal class StatelessWorkerPlacementTestGrain : PlacementTestGrainBase, IStatelessWorkerPlacementTestGrain\n    {\n        public StatelessWorkerPlacementTestGrain(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n            : base(overloadDetector, hostEnvironmentStatistics, loadSheddingOptions, grainContext)\n        {\n        }\n\n        public ValueTask<int> GetWorkerLimit()\n        {\n            var placementStrategy = GrainContext.GetComponent<PlacementStrategy>();\n            if (placementStrategy is not StatelessWorkerPlacement statelessWorkerPlacement)\n            {\n                throw new InvalidOperationException($\"Unexpected placement strategy: {placementStrategy}\");\n            }\n\n            return new(statelessWorkerPlacement.MaxLocal);\n        }\n    }\n\n    [StatelessWorker(2)]\n    internal class OtherStatelessWorkerPlacementTestGrain : PlacementTestGrainBase, IOtherStatelessWorkerPlacementTestGrain\n    {\n        public OtherStatelessWorkerPlacementTestGrain(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n            : base(overloadDetector, hostEnvironmentStatistics, loadSheddingOptions, grainContext)\n        {\n        }\n\n        public ValueTask<int> GetWorkerLimit()\n        {\n            var placementStrategy = GrainContext.GetComponent<PlacementStrategy>();\n            if (placementStrategy is not StatelessWorkerPlacement statelessWorkerPlacement)\n            {\n                throw new InvalidOperationException($\"Unexpected placement strategy: {placementStrategy}\");\n            }\n\n            return new(statelessWorkerPlacement.MaxLocal);\n        }\n    }\n\n    [ActivationCountBasedPlacement]\n    internal class ActivationCountBasedPlacementTestGrain : PlacementTestGrainBase, IActivationCountBasedPlacementTestGrain\n    {\n        public ActivationCountBasedPlacementTestGrain(\n            OverloadDetector overloadDetector,\n            TestHooksEnvironmentStatisticsProvider hostEnvironmentStatistics,\n            IOptions<LoadSheddingOptions> loadSheddingOptions,\n            IGrainContext grainContext)\n            : base(overloadDetector, hostEnvironmentStatistics, loadSheddingOptions, grainContext)\n        {\n        }\n    }\n\n    internal class DefaultPlacementGrain : Grain, IDefaultPlacementGrain\n    {\n        public Task<PlacementStrategy> GetDefaultPlacement()\n        {\n            var defaultStrategy = this.ServiceProvider.GetRequiredService<PlacementStrategy>();\n            return Task.FromResult(defaultStrategy);\n        }\n    }\n\n    //----------------------------------------------------------//\n    // Grains for LocalContent grain case, when grain is activated on every silo by bootstrap provider.\n\n    [PreferLocalPlacement]\n    public class LocalContentGrain : Grain, ILocalContentGrain\n    {\n        private readonly ILogger logger;\n        private object cachedContent;\n        internal static ILocalContentGrain InstanceIdForThisSilo;\n\n        public LocalContentGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            DelayDeactivation(TimeSpan.MaxValue);   // make sure this activation is not collected.\n            cachedContent = RuntimeIdentity;        // store your silo identity as a local cached content in this grain.\n            InstanceIdForThisSilo = this.AsReference<ILocalContentGrain>();\n            return Task.FromResult(0);\n        }\n\n        public Task Init()\n        {\n            logger.LogInformation(\"Init LocalContentGrain on silo {RuntimeIdentity}\", RuntimeIdentity);\n            return Task.FromResult(0);\n        }\n\n        public Task<object> GetContent()\n        {\n            return Task.FromResult(cachedContent);\n        }\n    }\n\n    public class TestContentGrain : Grain, ITestContentGrain\n    {\n        private readonly ILogger logger;\n\n        public TestContentGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"OnActivateAsync\");\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            logger.LogInformation(\"GetRuntimeInstanceId\");\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public async Task<object> FetchContentFromLocalGrain()\n        {\n            logger.LogInformation(\"FetchContentFromLocalGrain\");\n            var localContentGrain = LocalContentGrain.InstanceIdForThisSilo;\n            if (localContentGrain == null)\n            {\n                throw new Exception(\"LocalContentGrain was not correctly initialized during silo startup!\");\n            }\n            object content = await localContentGrain.GetContent();\n            logger.LogInformation(\"Received content = {Content}\", content);\n            return content;\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/Properties/IsExternalInit.cs",
    "content": "namespace System.Runtime.CompilerServices;\n\n// required for record serialization support for downlevel\ninternal static class IsExternalInit { }"
  },
  {
    "path": "test/Grains/TestInternalGrains/ReminderTestGrain2.cs",
    "content": "using System.Globalization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Services;\nusing Orleans.Timers;\nusing UnitTests.GrainInterfaces;\n\n\n#pragma warning disable 612,618\nnamespace UnitTests.Grains\n{\n    // NOTE: if you make any changes here, copy them to ReminderTestCopyGrain\n    public class ReminderTestGrain2 : Grain, IReminderTestGrain2, IRemindable\n    {\n        private readonly IReminderTable reminderTable;\n\n        private readonly IReminderRegistry unvalidatedReminderRegistry;\n        private Dictionary<string, ReminderState> allReminders;\n        private Dictionary<string, long> sequence;\n        private TimeSpan period;\n\n        private static readonly long aCCURACY = 50 * TimeSpan.TicksPerMillisecond; // when we use ticks to compute sequence numbers, we might get wrong results as timeouts don't happen with precision of ticks  ... we keep this as a leeway\n\n        private readonly IOptions<ReminderOptions> reminderOptions;\n\n        private readonly ILogger logger;\n        private string _id; // used to distinguish during debugging between multiple activations of the same grain\n\n        private string filePrefix;\n\n        public ReminderTestGrain2(IServiceProvider services, IReminderTable reminderTable, ILoggerFactory loggerFactory)\n        {\n            this.reminderTable = reminderTable;\n            this.unvalidatedReminderRegistry = new UnvalidatedReminderRegistry(services);\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n            this.reminderOptions = services.GetService<IOptions<ReminderOptions>>();\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this._id = Guid.NewGuid().ToString();\n            this.allReminders = new Dictionary<string, ReminderState>();\n            this.sequence = new Dictionary<string, long>();\n            this.period = GetDefaultPeriod(this.logger);\n            this.logger.LogInformation(\"OnActivateAsync.\");\n            this.filePrefix = \"g\" + this.GrainId.ToString().Replace('/', '_') + \"_\";\n            return GetMissingReminders();\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task<Dictionary<string, ReminderState>> GetReminderStates() => Task.FromResult(allReminders);\n\n        public async Task<IGrainReminder> StartReminder(string reminderName, TimeSpan? p = null, bool validate = false)\n        {\n            TimeSpan usePeriod = p ?? this.period;\n            this.logger.LogInformation(\"Starting reminder {ReminderName}.\", reminderName);\n            TimeSpan dueTime;\n            if (reminderOptions.Value.MinimumReminderPeriod < TimeSpan.FromSeconds(2))\n                dueTime = TimeSpan.FromSeconds(2) - reminderOptions.Value.MinimumReminderPeriod;\n            else dueTime = usePeriod - TimeSpan.FromSeconds(2);\n\n            IGrainReminder r;\n            if (validate)\n                r = await this.RegisterOrUpdateReminder(reminderName, dueTime, usePeriod);\n            else\n                r = await this.unvalidatedReminderRegistry.RegisterOrUpdateReminder(GrainId, reminderName, dueTime, usePeriod);\n\n            this.allReminders[reminderName] = new(r);\n            this.sequence[reminderName] = 0;\n\n            string fileName = GetFileName(reminderName);\n            File.Delete(fileName); // if successfully started, then remove any old data\n            this.logger.LogInformation(\"Started reminder {Reminder}\", r);\n            return r;\n        }\n\n        public Task ReceiveReminder(string reminderName, TickStatus status)\n        {\n            // it can happen that due to failure, when a new activation is created,\n            // it doesn't know which reminders were registered against the grain\n            // hence, this activation may receive a reminder that it didn't register itself, but\n            // the previous activation (incarnation of the grain) registered... so, play it safe\n            if (!this.sequence.ContainsKey(reminderName))\n            {\n                this.sequence.Add(reminderName, 0); // we'll get upto date to the latest sequence number while processing this tick\n            }\n\n            allReminders[reminderName].Fired.Add(status.CurrentTickTime);\n\n            // calculating tick sequence number\n\n            // we do all arithmetics on DateTime by converting into long because we dont have divide operation on DateTime\n            // using dateTime.Ticks is not accurate as between two invocations of ReceiveReminder(), there maybe < period.Ticks\n            // if # of ticks between two consecutive ReceiveReminder() is larger than period.Ticks, everything is fine... the problem is when its less\n            // thus, we reduce our accuracy by ACCURACY ... here, we are preparing all used variables for the given accuracy\n            long now = status.CurrentTickTime.Ticks / aCCURACY; //DateTime.UtcNow.Ticks / ACCURACY;\n            long first = status.FirstTickTime.Ticks / aCCURACY;\n            long per = status.Period.Ticks / aCCURACY;\n            long sequenceNumber = 1 + ((now - first) / per);\n\n            // end of calculating tick sequence number\n\n            // do switch-ing here\n            if (sequenceNumber < this.sequence[reminderName])\n            {\n                this.logger.LogInformation(\"ReceiveReminder: {Reminder} Incorrect tick {ExpectedSequenceNumber} vs. {SequenceNumber} with status {Status}.\", reminderName, this.sequence[reminderName], sequenceNumber, status);\n                return Task.CompletedTask;\n            }\n            this.sequence[reminderName] = sequenceNumber;\n            this.logger.LogInformation(\"ReceiveReminder: {ReminderNAme} Sequence # {SequenceNumber} with status {Status}.\", reminderName, this.sequence[reminderName], status);\n\n            string fileName = GetFileName(reminderName);\n            string counterValue = this.sequence[reminderName].ToString(CultureInfo.InvariantCulture);\n            File.WriteAllText(fileName, counterValue);\n\n            return Task.CompletedTask;\n        }\n\n        public async Task StopReminder(string reminderName)\n        {\n            this.logger.LogInformation(\"Stopping reminder {ReminderName}.\", reminderName);\n            // we dont reset counter as we want the test methods to be able to read it even after stopping the reminder\n            //return UnregisterReminder(allReminders[reminderName]);\n            ReminderState state;\n            if (this.allReminders.TryGetValue(reminderName, out state))\n            {\n                await this.UnregisterReminder(state.Reminder);\n                state.Log.Add((DateTime.UtcNow, $\"Unregistering {reminderName}\"));\n                allReminders[reminderName] = state with { Unregistered = DateTime.UtcNow };\n            }\n            else\n            {\n                // during failures, there may be reminders registered by an earlier activation that we dont have cached locally\n                // therefore, we need to update our local cache\n                await GetMissingReminders();\n                if (this.allReminders.TryGetValue(reminderName, out state))\n                {\n                    await this.UnregisterReminder(state.Reminder);\n                    state.Log.Add((DateTime.UtcNow, $\"Unregistering {reminderName}\"));\n                    allReminders[reminderName] = state with { Unregistered = DateTime.UtcNow };\n                }\n                else\n                {\n                    //var reminders = await this.GetRemindersList();\n                    throw new OrleansException(string.Format(\n                        \"Could not find reminder {0} in grain {1}\", reminderName, this.IdentityString));\n                }\n            }\n        }\n\n        private async Task GetMissingReminders()\n        {\n            List<IGrainReminder> reminders = await this.GetReminders();\n            this.logger.LogInformation(\"Got missing reminders {Reminders}\", Utils.EnumerableToString(reminders));\n            foreach (IGrainReminder l in reminders)\n            {\n                if (!this.allReminders.ContainsKey(l.ReminderName))\n                {\n                    this.allReminders.Add(l.ReminderName, new ReminderState(Reminder: l) { Registered = DateTime.UtcNow, Log = { (DateTime.UtcNow, $\"Adding missing: {l.ReminderName}\") } });\n                }\n            }\n        }\n\n        public async Task StopReminder(IGrainReminder reminder)\n        {\n            this.logger.LogInformation(\"Stopping reminder (using ref) {Reminder}.\", reminder);\n            // we dont reset counter as we want the test methods to be able to read it even after stopping the reminder\n            await this.UnregisterReminder(reminder);\n            var state = allReminders[reminder.ReminderName];\n            state.Log.Add((DateTime.UtcNow, $\"Stopping {reminder.ReminderName}\"));\n            allReminders[reminder.ReminderName] = state with { Unregistered = DateTime.UtcNow };\n        }\n\n        public Task<TimeSpan> GetReminderPeriod(string reminderName)\n        {\n            return Task.FromResult(this.period);\n        }\n\n        public Task<(TimeSpan DueTime, TimeSpan Period)> GetReminderDueTimeAndPeriod(string reminderName)\n        {\n            return Task.FromResult((this.period - TimeSpan.FromSeconds(2), this.period));\n        }\n\n        public Task<long> GetCounter(string name)\n        {\n            string fileName = GetFileName(name);\n            string data = File.ReadAllText(fileName);\n            long counterValue = long.Parse(data);\n            return Task.FromResult(counterValue);\n        }\n\n        public Task<IGrainReminder> GetReminderObject(string reminderName)\n        {\n            return this.GetReminder(reminderName);\n        }\n\n        public async Task<List<IGrainReminder>> GetRemindersList()\n        {\n            return await this.GetReminders();\n        }\n\n        private string GetFileName(string reminderName)\n        {\n            return string.Format(\"{0}{1}\", this.filePrefix, reminderName);\n        }\n\n        public static TimeSpan GetDefaultPeriod(ILogger log)\n        {\n            int period = 12; // Seconds\n            var reminderPeriod = TimeSpan.FromSeconds(period);\n            log.LogInformation(\"Using reminder period of {Period} in ReminderTestGrain\", reminderPeriod);\n            return reminderPeriod;\n        }\n\n        public async Task EraseReminderTable()\n        {\n            await this.reminderTable.TestOnlyClearTable();\n        }\n    }\n\n    // NOTE: do not make changes here ... this is a copy of ReminderTestGrain\n    // changes to make when copying:\n    //      1. rename logger to ReminderCopyGrain\n    //      2. filePrefix should start with \"gc\", instead of \"g\"\n    public class ReminderTestCopyGrain : Grain, IReminderTestCopyGrain, IRemindable\n    {\n        private readonly IReminderRegistry unvalidatedReminderRegistry;\n        private Dictionary<string, IGrainReminder> allReminders;\n        private Dictionary<string, long> sequence;\n        private TimeSpan period;\n\n        private static readonly long aCCURACY = 50 * TimeSpan.TicksPerMillisecond; // when we use ticks to compute sequence numbers, we might get wrong results as timeouts don't happen with precision of ticks  ... we keep this as a leeway\n\n        private readonly ILogger logger;\n        private long myId; // used to distinguish during debugging between multiple activations of the same grain\n\n        private string filePrefix;\n\n        public ReminderTestCopyGrain(IServiceProvider services, ILoggerFactory loggerFactory)\n        {\n            this.unvalidatedReminderRegistry = new UnvalidatedReminderRegistry(services);\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.myId = new Random().Next();\n            this.allReminders = new Dictionary<string, IGrainReminder>();\n            this.sequence = new Dictionary<string, long>();\n            this.period = ReminderTestGrain2.GetDefaultPeriod(this.logger);\n            this.logger.LogInformation(\"OnActivateAsync.\");\n            this.filePrefix = \"gc\" + this.GrainId.Key + \"_\";\n            await GetMissingReminders();\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation(\"OnDeactivateAsync.\");\n            return Task.CompletedTask;\n        }\n\n        public async Task<IGrainReminder> StartReminder(string reminderName, TimeSpan? p = null, bool validate = false)\n        {\n            TimeSpan usePeriod = p ?? this.period;\n            this.logger.LogInformation(\"Starting reminder {ReminderName} for {GrainId}\", reminderName, this.GrainId);\n            IGrainReminder r;\n            if (validate)\n                r = await this.RegisterOrUpdateReminder(reminderName, usePeriod - TimeSpan.FromSeconds(2), usePeriod);\n            else\n                r = await this.unvalidatedReminderRegistry.RegisterOrUpdateReminder(\n                    this.GrainId,\n                    reminderName,\n                    usePeriod - TimeSpan.FromSeconds(2),\n                    usePeriod);\n            if (this.allReminders.ContainsKey(reminderName))\n            {\n                this.allReminders[reminderName] = r;\n                this.sequence[reminderName] = 0;\n            }\n            else\n            {\n                this.allReminders.Add(reminderName, r);\n                this.sequence.Add(reminderName, 0);\n            }\n\n            File.Delete(GetFileName(reminderName)); // if successfully started, then remove any old data\n            this.logger.LogInformation(\"Started reminder {Reminder}.\", r);\n            return r;\n        }\n\n        public Task ReceiveReminder(string reminderName, TickStatus status)\n        {\n            // it can happen that due to failure, when a new activation is created,\n            // it doesn't know which reminders were registered against the grain\n            // hence, this activation may receive a reminder that it didn't register itself, but\n            // the previous activation (incarnation of the grain) registered... so, play it safe\n            if (!this.sequence.ContainsKey(reminderName))\n            {\n                // allReminders.Add(reminderName, r); // not using allReminders at the moment\n                //counters.Add(reminderName, 0);\n                this.sequence.Add(reminderName, 0); // we'll get upto date to the latest sequence number while processing this tick\n            }\n\n            // calculating tick sequence number\n\n            // we do all arithmetics on DateTime by converting into long because we dont have divide operation on DateTime\n            // using dateTime.Ticks is not accurate as between two invocations of ReceiveReminder(), there maybe < period.Ticks\n            // if # of ticks between two consecutive ReceiveReminder() is larger than period.Ticks, everything is fine... the problem is when its less\n            // thus, we reduce our accuracy by ACCURACY ... here, we are preparing all used variables for the given accuracy\n            long now = status.CurrentTickTime.Ticks / aCCURACY; //DateTime.UtcNow.Ticks / ACCURACY;\n            long first = status.FirstTickTime.Ticks / aCCURACY;\n            long per = status.Period.Ticks / aCCURACY;\n            long sequenceNumber = 1 + ((now - first) / per);\n\n            // end of calculating tick sequence number\n\n            // do switch-ing here\n            if (sequenceNumber < this.sequence[reminderName])\n            {\n                this.logger.LogInformation(\"{ReminderName} Incorrect tick {ExpectedSequenceNumber} vs. {SequenceNumber} with status {Status}.\", reminderName, this.sequence[reminderName], sequenceNumber, status);\n                return Task.CompletedTask;\n            }\n\n            this.sequence[reminderName] = sequenceNumber;\n            this.logger.LogInformation(\"{ReminderName} Sequence # {SequenceNumber} with status {Status}.\", reminderName, this.sequence[reminderName], status);\n\n            File.WriteAllText(GetFileName(reminderName), this.sequence[reminderName].ToString());\n\n            return Task.CompletedTask;\n        }\n\n        public async Task StopReminder(string reminderName)\n        {\n            this.logger.LogInformation(\"Stopping reminder {Reminder}.\", reminderName);\n            // we dont reset counter as we want the test methods to be able to read it even after stopping the reminder\n            //return UnregisterReminder(allReminders[reminderName]);\n            IGrainReminder reminder;\n            if (this.allReminders.TryGetValue(reminderName, out reminder))\n            {\n                await this.UnregisterReminder(reminder);\n            }\n            else\n            {\n                // during failures, there may be reminders registered by an earlier activation that we dont have cached locally\n                // therefore, we need to update our local cache\n                await GetMissingReminders();\n                await this.UnregisterReminder(this.allReminders[reminderName]);\n            }\n        }\n\n        private async Task GetMissingReminders()\n        {\n            List<IGrainReminder> reminders = await this.GetReminders();\n            foreach (IGrainReminder l in reminders)\n            {\n                if (!this.allReminders.ContainsKey(l.ReminderName))\n                {\n                    this.allReminders.Add(l.ReminderName, l);\n                }\n            }\n        }\n\n        public async Task StopReminder(IGrainReminder reminder)\n        {\n            this.logger.LogInformation(\"Stopping reminder (using ref) {Reminder}.\", reminder);\n            // we dont reset counter as we want the test methods to be able to read it even after stopping the reminder\n            await this.UnregisterReminder(reminder);\n        }\n\n        public Task<TimeSpan> GetReminderPeriod(string reminderName)\n        {\n            return Task.FromResult(this.period);\n        }\n\n        public Task<long> GetCounter(string name)\n        {\n            return Task.FromResult(long.Parse(File.ReadAllText(GetFileName(name))));\n        }\n\n        public async Task<IGrainReminder> GetReminderObject(string reminderName)\n        {\n            return await this.GetReminder(reminderName);\n        }\n        public async Task<List<IGrainReminder>> GetRemindersList()\n        {\n            return await this.GetReminders();\n        }\n\n        private string GetFileName(string reminderName)\n        {\n            return string.Format(\"{0}{1}\", this.filePrefix, reminderName);\n        }\n    }\n\n    public class WrongReminderGrain : Grain, IReminderGrainWrong\n    {\n        private readonly ILogger logger;\n\n        public WrongReminderGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.logger.LogInformation(\"OnActivateAsync.\");\n            return Task.CompletedTask;\n        }\n\n        public async Task<bool> StartReminder(string reminderName)\n        {\n            this.logger.LogInformation(\"Starting reminder {Reminder}.\", reminderName);\n            IGrainReminder r = await this.RegisterOrUpdateReminder(reminderName, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3));\n            this.logger.LogInformation(\"Started reminder {Reminder}. It shouldn't have succeeded!\", r);\n            return true;\n        }\n    }\n\n\n    internal sealed class UnvalidatedReminderRegistry : GrainServiceClient<IReminderService>, IReminderRegistry\n    {\n        public UnvalidatedReminderRegistry(IServiceProvider serviceProvider) : base(serviceProvider) { }\n\n        public Task<IGrainReminder> RegisterOrUpdateReminder(GrainId callingGrainId, string reminderName, TimeSpan dueTime, TimeSpan period)\n        {\n            return GetGrainService(callingGrainId).RegisterOrUpdateReminder(callingGrainId, reminderName, dueTime, period);\n        }\n\n        public Task UnregisterReminder(GrainId callingGrainId, IGrainReminder reminder)\n            => GetGrainService(callingGrainId).UnregisterReminder(reminder);\n\n        public Task<IGrainReminder> GetReminder(GrainId callingGrainId, string reminderName)\n        {\n            return GetGrainService(callingGrainId).GetReminder(callingGrainId, reminderName);\n        }\n\n        public Task<List<IGrainReminder>> GetReminders(GrainId callingGrainId)\n        {\n            return GetGrainService(callingGrainId).GetReminders(callingGrainId);\n        }\n    }\n}\n#pragma warning restore 612, 618"
  },
  {
    "path": "test/Grains/TestInternalGrains/SerializationTestTypes.cs",
    "content": "namespace UnitTests.Grains\n{\n    [GenerateSerializer]\n    public enum IntEnum\n    {\n        Value1,\n        Value2,\n        Value3\n    }\n\n    [GenerateSerializer]\n    public enum UShortEnum : ushort\n    {\n        Value1,\n        Value2,\n        Value3\n    }\n\n    [GenerateSerializer]\n    public enum CampaignEnemyType : sbyte\n    {\n        None = -1,\n        Brute = 0,\n        Enemy1,\n        Enemy2,\n        Enemy3,\n        Enemy4,\n    }\n\n    public class UnserializableException : Exception\n    {\n        public UnserializableException(string message) : base(message)\n        { }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class Unrecognized\n    {\n        [Id(0)]\n        public int A { get; set; }\n        [Id(1)]\n        public int B { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class ClassWithCustomSerializer\n    {\n        [Id(0)]\n        public int IntProperty { get; set; }\n        [Id(1)]\n        public string StringProperty { get; set; }\n\n        public static int SerializeCounter { get; set; }\n        public static int DeserializeCounter { get; set; }\n\n        static ClassWithCustomSerializer()\n        {\n            SerializeCounter = 0;\n            DeserializeCounter = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/SerializerPresenceTestGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class SerializerPresenceTestGrain : Grain, ISerializerPresenceTest\n    {\n        public Task<bool> SerializerExistsForType(Type t)\n        {\n            return Task.FromResult(this.ServiceProvider.GetRequiredService<Serializer>().CanSerialize(t));\n        }\n\n        public Task TakeSerializedData(object data)\n        {\n            // nothing to do\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamLifecycleTestGrains.cs",
    "content": "#define COUNT_ACTIVATE_DEACTIVATE\n\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class StreamLifecycleTestGrainState\n    {\n        // For producer and consumer\n        // -- only need to store this because of how we run our unit tests against multiple providers\n        [Id(0)]\n        public string StreamProviderName { get; set; }\n\n        // For producer only.\n        [Id(1)]\n        public IAsyncStream<int> Stream { get; set; }\n        [Id(2)]\n        public bool IsProducer { get; set; }\n        [Id(3)]\n        public int NumMessagesSent { get; set; }\n        [Id(4)]\n        public int NumErrors { get; set; }\n\n        // For consumer only.\n        [Id(5)]\n        public HashSet<StreamSubscriptionHandle<int>> ConsumerSubscriptionHandles { get; set; }\n\n        public StreamLifecycleTestGrainState()\n        {\n            ConsumerSubscriptionHandles = new HashSet<StreamSubscriptionHandle<int>>();\n        }\n    }\n\n    public class GenericArg\n    {\n        public string A { get; private set; }\n        public int B { get; private set; }\n\n        public GenericArg(string a, int b)\n        {\n            A = a;\n            B = b;\n        }\n\n        public override bool Equals(object obj)\n        {\n            var item = obj as GenericArg;\n            if (item == null)\n            {\n                return false;\n            }\n\n            return A.Equals(item.A) && B.Equals(item.B);\n        }\n\n        public override int GetHashCode() => HashCode.Combine(A, B);\n    }\n\n    public class AsyncObserverArg : GenericArg\n    {\n        public AsyncObserverArg(string a, int b) : base(a, b) { }\n    }\n\n    public class AsyncObservableArg : GenericArg\n    {\n        public AsyncObservableArg(string a, int b) : base(a, b) { }\n    }\n\n    public class AsyncStreamArg : GenericArg\n    {\n        public AsyncStreamArg(string a, int b) : base(a, b) { }\n    }\n\n    public class StreamSubscriptionHandleArg : GenericArg\n    {\n        public StreamSubscriptionHandleArg(string a, int b) : base(a, b) { }\n    }\n\n    public class StreamLifecycleTestGrainBase : Grain<StreamLifecycleTestGrainState>\n    {\n        protected ILogger logger;\n        protected string _lastProviderName;\n        protected IStreamProvider _streamProvider;\n\n#if COUNT_ACTIVATE_DEACTIVATE\n        private IActivateDeactivateWatcherGrain watcher;\n#endif\n\n        public StreamLifecycleTestGrainBase(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        protected Task RecordActivate()\n        {\n#if COUNT_ACTIVATE_DEACTIVATE\n            watcher = GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n            return watcher.RecordActivateCall(IdentityString);\n#else\n            return Task.CompletedTask;\n#endif\n        }\n\n        protected Task RecordDeactivate()\n        {\n#if COUNT_ACTIVATE_DEACTIVATE\n            return watcher.RecordDeactivateCall(IdentityString);\n#else\n            return Task.CompletedTask;\n#endif\n        }\n\n        protected void InitStream(StreamId streamId, string providerToUse)\n        {\n            if (providerToUse == null) throw new ArgumentNullException(nameof(providerToUse), \"Can't have null stream provider name\");\n\n            if (State.Stream != null && !State.Stream.StreamId.Equals(streamId))\n            {\n                if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Stream already exists for StreamId={0} StreamProvider={1} - Resetting\", State.Stream, providerToUse);\n\n                // Note: in this test, we are deliberately not doing Unsubscribe consumers, just discard old stream and let auto-cleanup functions do their thing.\n                State.ConsumerSubscriptionHandles.Clear();\n                State.IsProducer = false;\n                State.NumMessagesSent = 0;\n                State.NumErrors = 0;\n                State.Stream = null;\n            }\n\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"InitStream StreamId={0} StreamProvider={1}\", streamId, providerToUse);\n\n            if (providerToUse != _lastProviderName)\n            {\n                _streamProvider = this.GetStreamProvider(providerToUse);\n                _lastProviderName = providerToUse;\n            }\n            IAsyncStream<int> stream = _streamProvider.GetStream<int>(streamId);\n            State.Stream = stream;\n            State.StreamProviderName = providerToUse;\n\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"InitStream returning with Stream={0} with ref type = {1}\", State.Stream, State.Stream.GetType().FullName);\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    internal class StreamLifecycleConsumerGrain : StreamLifecycleTestGrainBase, IStreamLifecycleConsumerGrain\n    {\n        protected readonly InsideRuntimeClient runtimeClient;\n        protected readonly IStreamProviderRuntime streamProviderRuntime;\n\n        public StreamLifecycleConsumerGrain(InsideRuntimeClient runtimeClient, IStreamProviderRuntime streamProviderRuntime, ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n            this.runtimeClient = runtimeClient;\n            this.streamProviderRuntime = streamProviderRuntime;\n        }\n\n        protected IDictionary<StreamSubscriptionHandle<int>, MyStreamObserver<int>> Observers { get; set; }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"OnActivateAsync\");\n\n            await RecordActivate();\n\n            if (Observers == null)\n            {\n                Observers = new Dictionary<StreamSubscriptionHandle<int>, MyStreamObserver<int>>();\n            }\n\n            if (State.Stream != null && State.StreamProviderName != null)\n            {\n                if (State.ConsumerSubscriptionHandles.Count > 0)\n                {\n                    var handles = State.ConsumerSubscriptionHandles.ToArray();\n                    logger.LogInformation(\"ReconnectConsumerHandles SubscriptionHandles={Handles} Grain={Grain}\", Utils.EnumerableToString(handles), this.AsReference<IStreamLifecycleConsumerGrain>());\n                    foreach (var handle in handles)\n                    {\n                        var observer = new MyStreamObserver<int>(this.logger);\n                        StreamSubscriptionHandle<int> subsHandle = await handle.ResumeAsync(observer);\n                        Observers.Add(subsHandle, observer);\n                    }\n                }\n            }\n            else\n            {\n                if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Not connected to stream yet.\");\n            }\n        }\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"OnDeactivateAsync\");\n            await RecordDeactivate();\n        }\n\n        public Task<int> GetReceivedCount()\n        {\n            int numReceived = Observers.Sum(o => o.Value.NumItems);\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"ReceivedCount={0}\", numReceived);\n            return Task.FromResult(numReceived);\n        }\n        public Task<int> GetErrorsCount()\n        {\n            int numErrors = Observers.Sum(o => o.Value.NumErrors);\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"ErrorsCount={0}\", numErrors);\n            return Task.FromResult(numErrors);\n        }\n\n        public Task Ping()\n        {\n            logger.LogInformation(\"Ping\");\n            return Task.CompletedTask;\n        }\n\n        public virtual async Task BecomeConsumer(StreamId streamId, string providerToUse)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"BecomeConsumer StreamId={0} StreamProvider={1} Grain={2}\", streamId, providerToUse, this.AsReference<IStreamLifecycleConsumerGrain>());\n            InitStream(streamId, providerToUse);\n            var observer = new MyStreamObserver<int>(logger);\n            var subsHandle = await State.Stream.SubscribeAsync(observer);\n            State.ConsumerSubscriptionHandles.Add(subsHandle);\n            Observers.Add(subsHandle, observer);\n            await WriteStateAsync();\n        }\n\n        public virtual async Task TestBecomeConsumerSlim(StreamId streamId, string providerName)\n        {\n            InitStream(streamId, providerName);\n            var observer = new MyStreamObserver<int>(logger);\n\n            //var subsHandle = await State.Stream.SubscribeAsync(observer);\n\n            var (myExtension, myExtensionReference) = this.streamProviderRuntime.BindExtension<StreamConsumerExtension, IStreamConsumerExtension>(\n                () => new StreamConsumerExtension(streamProviderRuntime));\n            string extKey = providerName + \"_\" + Encoding.UTF8.GetString(State.Stream.StreamId.Namespace.ToArray());\n            var id = new QualifiedStreamId(providerName, streamId);\n            IPubSubRendezvousGrain pubsub = GrainFactory.GetGrain<IPubSubRendezvousGrain>(id.ToString());\n            GuidId subscriptionId = GuidId.GetNewGuidId();\n            await pubsub.RegisterConsumer(subscriptionId, ((StreamImpl<int>)State.Stream).InternalStreamId, myExtensionReference.GetGrainId(), null);\n\n            myExtension.SetObserver(subscriptionId, ((StreamImpl<int>)State.Stream), observer, null, null, null);\n        }\n\n        public async Task RemoveConsumer(StreamId streamId, string providerName, StreamSubscriptionHandle<int> subsHandle)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"RemoveConsumer StreamId={0} StreamProvider={1}\", streamId, providerName);\n            if (State.ConsumerSubscriptionHandles.Count == 0) throw new InvalidOperationException(\"Not a Consumer\");\n            await subsHandle.UnsubscribeAsync();\n            Observers.Remove(subsHandle);\n            State.ConsumerSubscriptionHandles.Remove(subsHandle);\n            await WriteStateAsync();\n        }\n\n        public async Task ClearGrain()\n        {\n            logger.LogInformation(\"ClearGrain\");\n            var subsHandles = State.ConsumerSubscriptionHandles.ToArray();\n            foreach (var handle in subsHandles)\n            {\n                await handle.UnsubscribeAsync();\n            }\n            State.ConsumerSubscriptionHandles.Clear();\n            State.Stream = null;\n            State.IsProducer = false;\n            Observers.Clear();\n            await ClearStateAsync();\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class StreamLifecycleProducerGrain : StreamLifecycleTestGrainBase, IStreamLifecycleProducerGrain\n    {\n        public StreamLifecycleProducerGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"OnActivateAsync\");\n\n            await RecordActivate();\n\n            if (State.Stream != null && State.StreamProviderName != null)\n            {\n                if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Reconnected to stream {0}\", State.Stream);\n            }\n            else\n            {\n                if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Not connected to stream yet.\");\n            }\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"OnDeactivateAsync\");\n            await RecordDeactivate();\n        }\n\n        public Task<int> GetSendCount()\n        {\n            int result = State.NumMessagesSent;\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"GetSendCount={0}\", result);\n            return Task.FromResult(result);\n        }\n\n        public Task<int> GetErrorsCount()\n        {\n            int result = State.NumErrors;\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"GetErrorsCount={0}\", result);\n            return Task.FromResult(result);\n        }\n\n        public Task Ping()\n        {\n            logger.LogInformation(\"Ping\");\n            return Task.CompletedTask;\n        }\n\n        public async Task SendItem(int item)\n        {\n            if (!State.IsProducer || State.Stream == null) throw new InvalidOperationException(\"Not a Producer\");\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"SendItem Item={0}\", item);\n            Exception error = null;\n            try\n            {\n                await State.Stream.OnNextAsync(item);\n\n                if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Successful SendItem \" + item);\n                State.NumMessagesSent++;\n            }\n            catch (Exception exc)\n            {\n                logger.LogError(exc, \"Error from SendItem {Item}\", item);\n                State.NumErrors++;\n                error = exc;\n            }\n            await WriteStateAsync(); // Update counts in persisted state\n\n            if (error != null)\n            {\n                throw new AggregateException(error);\n            }\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Finished SendItem for Item={0}\", item);\n        }\n\n        public async Task BecomeProducer(StreamId streamId, string providerName)\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"BecomeProducer StreamId={0} StreamProvider={1}\", streamId, providerName);\n            InitStream(streamId, providerName);\n            State.IsProducer = true;\n\n            // Send an initial message to ensure we are properly initialized as a Producer.\n            await State.Stream.OnNextAsync(0);\n            State.NumMessagesSent++;\n            await WriteStateAsync();\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Finished BecomeProducer for StreamId={0} StreamProvider={1}\", streamId, providerName);\n        }\n\n        public async Task ClearGrain()\n        {\n            logger.LogInformation(\"ClearGrain\");\n            State.IsProducer = false;\n            State.Stream = null;\n            await ClearStateAsync();\n        }\n\n        public async Task DoDeactivateNoClose()\n        {\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"DoDeactivateNoClose\");\n\n            State.IsProducer = false;\n            State.Stream = null;\n            await WriteStateAsync();\n\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Calling DeactivateOnIdle\");\n            DeactivateOnIdle();\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class MyStreamObserver<T> : IAsyncObserver<T>\n    {\n        [Id(0)]\n        internal int NumItems { get; private set; }\n        [Id(1)]\n        internal int NumErrors { get; private set; }\n\n        [Id(2)]\n        private readonly ILogger logger;\n\n        internal MyStreamObserver(ILogger logger)\n        {\n            this.logger = logger;\n        }\n\n        public Task OnNextAsync(T item, StreamSequenceToken token)\n        {\n            NumItems++;\n\n            if (logger != null && logger.IsEnabled(LogLevel.Debug))\n            {\n                logger.LogDebug(\"Received OnNextAsync - Item={0} - Total Items={1} Errors={2}\", item, NumItems, NumErrors);\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            if (logger != null)\n            {\n                logger.LogInformation(\"Receive OnCompletedAsync - Total Items={ItemCount} Errors={ErrorCount}\", NumItems, NumErrors);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            NumErrors++;\n\n            if (logger != null)\n            {\n                logger.LogWarning(ex, \"Received OnErrorAsync - Total Items={ItemCount} Errors={ErrorCount}\", NumItems, NumErrors);\n            }\n\n            return Task.CompletedTask;\n        }\n    }\n\n    public class ClosedTypeStreamObserver : MyStreamObserver<AsyncObserverArg>\n    {\n        public ClosedTypeStreamObserver(ILogger logger) : base(logger)\n        {\n        }\n    }\n\n    public interface IClosedTypeAsyncObservable : IAsyncObservable<AsyncObservableArg> { }\n\n    public interface IClosedTypeAsyncStream : IAsyncStream<AsyncStreamArg> { }\n\n    internal class ClosedTypeStreamSubscriptionHandle : StreamSubscriptionHandleImpl<StreamSubscriptionHandleArg>\n    {\n        public ClosedTypeStreamSubscriptionHandle() : base(null, null) { /* not a subject to the creation */ }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamLifecycleTestInternalGrains.cs",
    "content": "#define USE_STORAGE\n\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    public class StreamLifecycleProducerInternalGrain : StreamLifecycleProducerGrain, IStreamLifecycleProducerInternalGrain\n    {\n        public StreamLifecycleProducerInternalGrain(ILoggerFactory loggerFactory) : base(loggerFactory)\n        {\n        }\n\n        public async Task TestInternalRemoveProducer(Guid streamId, string providerName)\n        {\n            if (logger.IsEnabled(LogLevel.Debug))\n            {\n                logger.LogDebug(\"RemoveProducer StreamId={0} StreamProvider={1}\", streamId, providerName);\n            }\n\n            if (!State.IsProducer) throw new InvalidOperationException(\"Not a Producer\");\n\n            // Whitebox testing\n            var cleanup = State.Stream as IStreamControl;\n            await cleanup.Cleanup(true, false);\n\n            State.IsProducer = false;\n#if USE_STORAGE\n            await WriteStateAsync();\n#endif\n        }\n\n        public async Task DoBadDeactivateNoClose()\n        {\n            if (logger.IsEnabled(LogLevel.Debug))\n                logger.LogDebug(\"DoBadDeactivateNoClose\");\n\n            if (logger.IsEnabled(LogLevel.Debug))\n                logger.LogDebug(\"Suppressing Cleanup when Deactivate for stream {0}\", State.Stream);\n            StreamResourceTestControl.TestOnlySuppressStreamCleanupOnDeactivate = true;\n\n            State.IsProducer = false;\n            State.Stream = null;\n#if USE_STORAGE\n            await WriteStateAsync();\n#endif\n\n            if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug(\"Calling DeactivateOnIdle\");\n            base.DeactivateOnIdle();\n        }\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"MemoryStore\")]\n    internal class StreamLifecycleConsumerInternalGrain : StreamLifecycleConsumerGrain, IStreamLifecycleConsumerInternalGrain\n    {\n        public StreamLifecycleConsumerInternalGrain(ILoggerFactory loggerFactory, InsideRuntimeClient runtimeClient, IStreamProviderRuntime streamProviderRuntime)\n            : base(runtimeClient, streamProviderRuntime, loggerFactory)\n        {\n        }\n\n        public virtual async Task TestBecomeConsumerSlim(Guid streamIdGuid, string providerName)\n        {\n            // TODO NOT SURE THIS FUNCTION MAKESE ANY SENSE\n            var streamId = StreamId.Create(null, streamIdGuid);\n            InitStream(streamId, providerName);\n            var observer = new MyStreamObserver<int>(logger);\n\n            var (myExtension, myExtensionReference) = this.streamProviderRuntime.BindExtension<StreamConsumerExtension, IStreamConsumerExtension>(\n                () => new StreamConsumerExtension(streamProviderRuntime));\n\n            var id = new QualifiedStreamId(providerName, streamId);\n            IPubSubRendezvousGrain pubsub = GrainFactory.GetGrain<IPubSubRendezvousGrain>(id.ToString());\n            GuidId subscriptionId = GuidId.GetNewGuidId();\n            await pubsub.RegisterConsumer(subscriptionId, ((StreamImpl<int>)State.Stream).InternalStreamId, myExtensionReference.GetGrainId(), null);\n\n            myExtension.SetObserver(subscriptionId, ((StreamImpl<int>)State.Stream), observer, null, null, null);\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamReliabilityTestGrains.cs",
    "content": "//#define USE_GENERICS\n\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StreamingTests;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class StreamReliabilityTestGrainState\n    {\n        // For producer and consumer\n        // -- only need to store because of how we run our unit tests against multiple providers\n        [Id(0)]\n        public string StreamProviderName { get; set; }\n\n        // For producer only.\n#if USE_GENERICS\n        public IAsyncStream<T> Stream { get; set; }\n#else\n        [Id(1)]\n        public IAsyncStream<int> Stream { get; set; }\n#endif\n\n        [Id(2)]\n        public bool IsProducer { get; set; }\n\n        // For consumer only.\n#if USE_GENERICS\n        public HashSet<StreamSubscriptionHandle<T>> ConsumerSubscriptionHandles { get; set; }\n\n        public StreamReliabilityTestGrainState()\n        {\n            ConsumerSubscriptionHandles = new HashSet<StreamSubscriptionHandle<T>>();\n        }\n#else\n        [Id(3)]\n        public HashSet<StreamSubscriptionHandle<int>> ConsumerSubscriptionHandles { get; set; }\n\n        public StreamReliabilityTestGrainState()\n        {\n            ConsumerSubscriptionHandles = new HashSet<StreamSubscriptionHandle<int>>();\n        }\n#endif\n    }\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"AzureStore\")]\n#if USE_GENERICS\n    public class StreamReliabilityTestGrain<T> : Grain<IStreamReliabilityTestGrainState>, IStreamReliabilityTestGrain<T>\n#else\n    public class StreamReliabilityTestGrain : Grain<StreamReliabilityTestGrainState>, IStreamReliabilityTestGrain\n#endif\n    {\n        [NonSerialized]\n        private readonly ILogger _logger;\n\n        private readonly IGrainContext _grainContext;\n\n#if USE_GENERICS\n        private IAsyncStream<T> Stream { get; set; }\n        private IAsyncObserver<T> Producer { get; set; }\n        private Dictionary<StreamSubscriptionHandle<T>, MyStreamObserver<T>> Observers { get; set; }\n#else\n        private IAsyncStream<int> Stream { get { return State.Stream; } }\n        private IAsyncObserver<int> Producer { get; set; }\n        private Dictionary<StreamSubscriptionHandle<int>, MyStreamObserver<int>> Observers { get; set; }\n#endif\n        private const string StreamNamespace = StreamTestsConstants.StreamReliabilityNamespace;\n\n        public StreamReliabilityTestGrain(ILoggerFactory loggerFactory, IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n            this._logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\n                \"OnActivateAsync IsProducer = {IsProducer}, IsConsumer = {IsConsumer}.\",\n                State.IsProducer,\n                State.ConsumerSubscriptionHandles is { Count: > 0 });\n\n            if (Observers == null)\n#if USE_GENERICS\n                Observers = new Dictionary<StreamSubscriptionHandle<T>, MyStreamObserver<T>>();\n#else\n                Observers = new Dictionary<StreamSubscriptionHandle<int>, MyStreamObserver<int>>();\n#endif\n\n            if (State.Stream != null && State.StreamProviderName != null)\n            {\n                //TryInitStream(State.Stream, State.StreamProviderName);\n\n                if (State.ConsumerSubscriptionHandles.Count > 0)\n                {\n                    var handles = State.ConsumerSubscriptionHandles.ToArray();\n                    State.ConsumerSubscriptionHandles.Clear();\n                    await ReconnectConsumerHandles(handles);\n                }\n                if (State.IsProducer)\n                {\n                    //await BecomeProducer(State.StreamId, State.StreamProviderName);\n                    Producer = Stream;\n                    State.IsProducer = true;\n                    await WriteStateAsync();\n                }\n            }\n            else\n            {\n                _logger.LogInformation(\"No stream yet.\");\n            }\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task<int> GetConsumerCount()\n        {\n            int numConsumers = State.ConsumerSubscriptionHandles.Count;\n            _logger.LogInformation(\"ConsumerCount={Count}\", numConsumers);\n            return Task.FromResult(numConsumers);\n        }\n        public Task<int> GetReceivedCount()\n        {\n            int numReceived = Observers.Sum(o => o.Value.NumItems);\n            _logger.LogInformation(\"ReceivedCount={Count}\", numReceived);\n            return Task.FromResult(numReceived);\n        }\n        public Task<int> GetErrorsCount()\n        {\n            int numErrors = Observers.Sum(o => o.Value.NumErrors);\n            _logger.LogInformation(\"ErrorsCount={Count}\", numErrors);\n            return Task.FromResult(numErrors);\n        }\n\n        public Task Ping()\n        {\n            _logger.LogInformation(\"Ping\");\n            return Task.CompletedTask;\n        }\n\n#if USE_GENERICS\n        public async Task<StreamSubscriptionHandle<T>> AddConsumer(Guid streamId, string providerName)\n#else\n        public async Task<StreamSubscriptionHandle<int>> AddConsumer(Guid streamId, string providerName)\n#endif\n        {\n            _logger.LogInformation(\"AddConsumer StreamId={StreamId} StreamProvider={ProviderName} Grain={Grain}\", streamId, providerName, this.AsReference<IStreamReliabilityTestGrain>());\n            TryInitStream(streamId, providerName);\n#if USE_GENERICS\n            var observer = new MyStreamObserver<T>();\n#else\n            var observer = new MyStreamObserver<int>(_logger);\n#endif\n            var subsHandle = await Stream.SubscribeAsync(observer);\n            Observers.Add(subsHandle, observer);\n            State.ConsumerSubscriptionHandles.Add(subsHandle);\n            await WriteStateAsync();\n            return subsHandle;\n        }\n\n#if USE_GENERICS\n        public async Task RemoveConsumer(Guid streamId, string providerName, StreamSubscriptionHandle<T> subsHandle)\n#else\n        public async Task RemoveConsumer(Guid streamId, string providerName, StreamSubscriptionHandle<int> subsHandle)\n#endif\n        {\n            _logger.LogInformation(\"RemoveConsumer StreamId={StreamId} StreamProvider={ProviderName}\", streamId, providerName);\n            if (State.ConsumerSubscriptionHandles.Count == 0) throw new InvalidOperationException(\"Not a Consumer\");\n            await subsHandle.UnsubscribeAsync();\n            Observers.Remove(subsHandle);\n            State.ConsumerSubscriptionHandles.Remove(subsHandle);\n            await WriteStateAsync();\n        }\n\n        public async Task RemoveAllConsumers()\n        {\n            _logger.LogInformation(\"RemoveAllConsumers: State.ConsumerSubscriptionHandles.Count={Count}\", State.ConsumerSubscriptionHandles.Count);\n            if (State.ConsumerSubscriptionHandles.Count == 0) throw new InvalidOperationException(\"Not a Consumer\");\n            var handles = State.ConsumerSubscriptionHandles.ToArray();\n            foreach (var handle in handles)\n            {\n                await handle.UnsubscribeAsync();\n            }\n            //Observers.Remove(subsHandle);\n            State.ConsumerSubscriptionHandles.Clear();\n            await WriteStateAsync();\n        }\n\n        public async Task BecomeProducer(Guid streamId, string providerName)\n        {\n            _logger.LogInformation(\"BecomeProducer StreamId={StreamId} StreamProvider={StreamProvider}\", streamId, providerName);\n            TryInitStream(streamId, providerName);\n            Producer = Stream;\n            State.IsProducer = true;\n            await WriteStateAsync();\n        }\n\n        public async Task RemoveProducer(Guid streamId, string providerName)\n        {\n            _logger.LogInformation(\"RemoveProducer StreamId={StreamId} StreamProvider={ProviderName}\", streamId, providerName);\n            if (!State.IsProducer) throw new InvalidOperationException(\"Not a Producer\");\n            Producer = null;\n            State.IsProducer = false;\n            await WriteStateAsync();\n        }\n\n        public async Task ClearGrain()\n        {\n            _logger.LogInformation(\"ClearGrain.\");\n            State.ConsumerSubscriptionHandles.Clear();\n            State.IsProducer = false;\n            Observers.Clear();\n            State.Stream = null;\n            await ClearStateAsync();\n        }\n\n        public Task<bool> IsConsumer()\n        {\n            bool isConsumer = State.ConsumerSubscriptionHandles.Count > 0;\n            _logger.LogInformation(\"IsConsumer={IsConsumer}\", isConsumer);\n            return Task.FromResult(isConsumer);\n        }\n        public Task<bool> IsProducer()\n        {\n            bool isProducer = State.IsProducer;\n            _logger.LogInformation(\"IsProducer={IsProducer}\", isProducer);\n            return Task.FromResult(isProducer);\n        }\n        public Task<int> GetConsumerHandlesCount()\n        {\n            return Task.FromResult(State.ConsumerSubscriptionHandles.Count);\n        }\n\n        public async Task<int> GetConsumerObserversCount()\n        {\n#if USE_GENERICS\n            var consumer = (StreamConsumer<T>)Stream;\n#else\n            var consumer = (StreamConsumer<int>)Stream;\n#endif\n            return await consumer.DiagGetConsumerObserversCount();\n        }\n\n\n#if USE_GENERICS\n        public async Task SendItem(T item)\n#else\n        public async Task SendItem(int item)\n#endif\n        {\n            _logger.LogInformation(\"SendItem Item={Item}\", item);\n            await Producer.OnNextAsync(item);\n        }\n\n        public Task<SiloAddress> GetLocation()\n        {\n            SiloAddress siloAddress = _grainContext.Address.SiloAddress;\n            _logger.LogInformation(\"GetLocation SiloAddress={SiloAddress}\", siloAddress);\n            return Task.FromResult(siloAddress);\n        }\n\n        private void TryInitStream(Guid streamId, string providerName)\n        {\n            if (providerName == null) throw new ArgumentNullException(nameof(providerName));\n\n            State.StreamProviderName = providerName;\n\n            if (State.Stream == null)\n            {\n                _logger.LogInformation(\"InitStream StreamId={StreamId} StreamProvider={ProviderName}\", streamId, providerName);\n\n                IStreamProvider streamProvider = this.GetStreamProvider(providerName);\n#if USE_GENERICS\n                State.Stream = streamProvider.GetStream<T>(streamId);\n#else\n                State.Stream = streamProvider.GetStream<int>(StreamNamespace, streamId);\n#endif\n            }\n        }\n\n#if USE_GENERICS\n        private async Task ReconnectConsumerHandles(StreamSubscriptionHandle<T>[] subscriptionHandles)\n#else\n        private async Task ReconnectConsumerHandles(StreamSubscriptionHandle<int>[] subscriptionHandles)\n#endif\n        {\n            _logger.LogInformation(\n                \"ReconnectConsumerHandles SubscriptionHandles={SubscriptionHandles} Grain={Grain}\",\n                Utils.EnumerableToString(subscriptionHandles),\n                this.AsReference<IStreamReliabilityTestGrain>());\n\n\n            foreach (var subHandle in subscriptionHandles)\n            {\n#if USE_GENERICS\n                // var stream = GetStreamProvider(State.StreamProviderName).GetStream<T>(subHandle.StreamId);\n                var stream = subHandle.Stream;\n                var observer = new MyStreamObserver<T>();\n#else\n                var observer = new MyStreamObserver<int>(_logger);\n#endif\n                var subsHandle = await subHandle.ResumeAsync(observer);\n                Observers.Add(subsHandle, observer);\n                State.ConsumerSubscriptionHandles.Add(subsHandle);\n            }\n            await WriteStateAsync();\n        }\n    }\n\n    //[Serializable]\n    //public class MyStreamObserver<T> : IAsyncObserver<T>\n    //{\n    //    internal int NumItems { get; private set; }\n    //    internal int NumErrors { get; private set; }\n\n    //    private readonly Logger logger;\n\n    //    internal MyStreamObserver(Logger logger)\n    //    {\n    //        this.logger = logger;\n    //    }\n\n    //    public Task OnNextAsync(T item, StreamSequenceToken token)\n    //    {\n    //        NumItems++;\n    //        if (logger.IsVerbose)\n    //            logger.Verbose(\"Received OnNextAsync - Item={0} - Total Items={1} Errors={2}\", item, NumItems, NumErrors);\n    //        return Task.CompletedTask;\n    //    }\n\n    //    public Task OnCompletedAsync()\n    //    {\n    //        logger.Info(\"Receive OnCompletedAsync - Total Items={0} Errors={1}\", NumItems, NumErrors);\n    //        return Task.CompletedTask;\n    //    }\n\n    //    public Task OnErrorAsync(Exception ex)\n    //    {\n    //        NumErrors++;\n    //        logger.Warn(1, \"Received OnErrorAsync - Exception={0} - Total Items={1} Errors={2}\", ex, NumItems, NumErrors);\n    //        return Task.CompletedTask;\n    //    }\n    //}\n\n\n    [Orleans.Providers.StorageProvider(ProviderName = \"AzureStore\")]\n    public class StreamUnsubscribeTestGrain : Grain<StreamReliabilityTestGrainState>, IStreamUnsubscribeTestGrain\n    {\n        [NonSerialized]\n        private readonly ILogger _logger;\n\n        private const string StreamNamespace = StreamTestsConstants.StreamReliabilityNamespace;\n\n        public StreamUnsubscribeTestGrain(ILoggerFactory loggerFactory)\n        {\n            this._logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(string.Format(\"OnActivateAsync IsProducer = {0}, IsConsumer = {1}.\",\n                State.IsProducer, State.ConsumerSubscriptionHandles != null && State.ConsumerSubscriptionHandles.Count > 0));\n            return Task.CompletedTask;\n        }\n\n        public async Task Subscribe(Guid streamId, string providerName)\n        {\n            _logger.LogInformation(\"Subscribe StreamId={StreamId} StreamProvider={ProviderName} Grain={Grain}\", streamId, providerName, this.AsReference<IStreamUnsubscribeTestGrain>());\n\n            State.StreamProviderName = providerName;\n            if (State.Stream == null)\n            {\n                _logger.LogInformation(\"InitStream StreamId={StreamId} StreamProvider={ProviderName}\", streamId, providerName);\n                IStreamProvider streamProvider = this.GetStreamProvider(providerName);\n                State.Stream = streamProvider.GetStream<int>(StreamNamespace, streamId);\n            }\n\n            var observer = new MyStreamObserver<int>(_logger);\n            var consumer = State.Stream;\n            var subsHandle = await consumer.SubscribeAsync(observer);\n            State.ConsumerSubscriptionHandles.Add(subsHandle);\n            await WriteStateAsync();\n        }\n\n        public async Task UnSubscribeFromAllStreams()\n        {\n            _logger.LogInformation(\"UnSubscribeFromAllStreams: State.ConsumerSubscriptionHandles.Count={Count}\", State.ConsumerSubscriptionHandles.Count);\n            if (State.ConsumerSubscriptionHandles.Count == 0) throw new InvalidOperationException(\"Not a Consumer\");\n            var handles = State.ConsumerSubscriptionHandles.ToArray();\n            foreach (var handle in handles)\n            {\n                await handle.UnsubscribeAsync();\n            }\n            State.ConsumerSubscriptionHandles.Clear();\n            await WriteStateAsync();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamTestsConstants.cs",
    "content": "namespace UnitTests.StreamingTests\n{\n    public class StreamTestsConstants\n    {\n        public const string SMS_STREAM_PROVIDER_NAME = \"SMSProvider\";\n        public const string AZURE_QUEUE_STREAM_PROVIDER_NAME = \"AzureQueueProvider\";\n\n        public const string DefaultStreamNamespace = \"DefaultStreamNamespace\";\n        public const string StreamReliabilityNamespace = \"StreamReliabilityNamespace\";\n        public const string StreamLifecycleTestsNamespace = \"UnitTest.Streaming.LifecycleTests\";\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamingGrain.cs",
    "content": "using System.Buffers.Text;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.Streams.Core;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.TestHelper;\n\nnamespace UnitTests.Grains\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class StreamItem\n    {\n        [Id(0)]\n        public string       Data;\n        [Id(1)]\n        public Guid         StreamId;\n\n        public StreamItem(string data, Guid streamId)\n        {\n            Data = data;\n            StreamId = streamId;\n        }\n\n        public override string ToString()\n        {\n            return string.Format(\"{0}\", Data);\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class ConsumerObserver : IAsyncObserver<StreamItem>, IConsumerObserver\n    {\n        [NonSerialized]\n        private ILogger _logger;\n        [NonSerialized]\n        private StreamSubscriptionHandle<StreamItem> _subscription;\n        [Id(0)]\n        private int _itemsConsumed;\n        [Id(1)]\n        private Guid _streamId;\n        [Id(2)]\n        private string _streamNamespace;\n\n        public Task<int> ItemsConsumed\n        {\n            get { return Task.FromResult(_itemsConsumed); }\n        }\n\n        private ConsumerObserver(ILogger logger)\n        {\n            _logger = logger;\n            _itemsConsumed = 0;\n        }\n\n        public static ConsumerObserver NewObserver(ILogger logger)\n        {\n            if (null == logger)\n                throw new ArgumentNullException(nameof(logger));\n            return new ConsumerObserver(logger);\n        }\n\n        public Task OnNextAsync(StreamItem item, StreamSequenceToken token = null)\n        {\n            if (!item.StreamId.Equals(_streamId))\n            {\n                _logger.LogError(\n                    \"ConsumerObserver.OnNextAsync: received an item from the wrong stream. Got item {Item} from stream = {StreamId}, expecting stream = {ExpectedStreamId}, numConsumed={ItemsConsumed}\",\n                    item,\n                    item.StreamId,\n                    _streamId,\n                    _itemsConsumed);\n                throw new ArgumentException($\"ConsumerObserver.OnNextAsync: received an item from the wrong stream. Got item {item} from stream = {item.StreamId}, expecting stream = {_streamId}, numConsumed={_itemsConsumed}\");\n            }\n            ++_itemsConsumed;\n\n            var logLevel = ProducerObserver.DEBUG_STREAMING_GRAINS ? LogLevel.Information : LogLevel.Debug;\n\n            _logger.Log(\n                logLevel,\n                \"ConsumerObserver.OnNextAsync: StreamId: {StreamId}, Item: {Item}, NumConsumed: {ItemsConsumed}, Token: {Token}\",\n                _streamId,\n                item.Data,\n                _itemsConsumed,\n                token != null ? \", token = \" + token : \"\");\n\n            return Task.CompletedTask;\n        }\n\n        public Task OnCompletedAsync()\n        {\n            _logger.LogInformation(\"ConsumerObserver.OnCompletedAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            _logger.LogInformation(ex, \"ConsumerObserver.OnErrorAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task BecomeConsumer(Guid streamId, IStreamProvider streamProvider, string streamNamespace)\n        {\n            _logger.LogInformation(\"BecomeConsumer\");\n            if (ProviderName != null)\n            {\n                throw new InvalidOperationException(\"Redundant call to BecomeConsumer\");\n            }                \n\n            _streamId = streamId;\n            ProviderName = streamProvider.Name;\n            _streamNamespace = string.IsNullOrWhiteSpace(streamNamespace) ? null : streamNamespace.Trim();\n            IAsyncStream<StreamItem> stream = streamProvider.GetStream<StreamItem>(streamNamespace, streamId);\n\n            _subscription = await stream.SubscribeAsync(this);\n        }\n\n        public async Task RenewConsumer(ILogger logger, IStreamProvider streamProvider)\n        {\n            _logger = logger;\n            _logger.LogInformation(\"RenewConsumer\");\n            IAsyncStream<StreamItem> stream = streamProvider.GetStream<StreamItem>(_streamNamespace, _streamId);\n            _subscription = await stream.SubscribeAsync(this);\n        }\n\n        public async Task StopBeingConsumer(IStreamProvider streamProvider)\n        {\n            _logger.LogInformation(\"StopBeingConsumer\");\n            if (_subscription != null)\n            {\n                await _subscription.UnsubscribeAsync();\n                //_subscription.Dispose();\n                _subscription = null;\n            }\n        }\n\n        public Task<int> ConsumerCount\n        {\n            get { return Task.FromResult(_subscription == null ? 0 : 1); }\n        }\n\n        [Id(3)]\n        public string ProviderName { get; private set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class ProducerObserver : IProducerObserver\n    {\n        [NonSerialized]\n        private ILogger _logger;\n        [NonSerialized]\n        private IAsyncObserver<StreamItem> _observer;\n        [NonSerialized]\n        private Dictionary<IDisposable, TimerState> _timers;\n        [Id(0)]\n        private int _itemsProduced;\n        [Id(1)]\n        private int _expectedItemsProduced;\n        [Id(2)]\n        private Guid _streamId;\n        [Id(3)]\n        private string _streamNamespace;\n        [Id(4)]\n        private string _providerName;\n        [Id(5)]\n        private readonly InterlockedFlag _cleanedUpFlag;\n        [NonSerialized]\n        private bool _observerDisposedYet;\n        [NonSerialized]\n        private readonly IGrainFactory _grainFactory;\n\n        public static bool DEBUG_STREAMING_GRAINS = true;\n\n        private ProducerObserver(ILogger logger, IGrainFactory grainFactory)\n        {\n            _logger = logger;\n            _observer = null;\n            _timers = new Dictionary<IDisposable, TimerState>();\n\n            _itemsProduced = 0;\n            _expectedItemsProduced = 0;\n            _streamId = default;\n            _providerName = null;\n            _cleanedUpFlag = new InterlockedFlag();\n            _observerDisposedYet = false;\n            _grainFactory = grainFactory;\n        }\n\n        public static ProducerObserver NewObserver(ILogger logger, IGrainFactory grainFactory)\n        {\n            if (null == logger)\n                throw new ArgumentNullException(nameof(logger));\n            return new ProducerObserver(logger, grainFactory);\n        }\n\n        public void BecomeProducer(Guid streamId, IStreamProvider streamProvider, string streamNamespace)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            _logger.LogInformation(\"BecomeProducer\");\n            IAsyncStream<StreamItem> stream = streamProvider.GetStream<StreamItem>(streamNamespace, streamId);\n            _observer = stream;\n            _logger.LogInformation(\"ProducerObserver.BecomeProducer: producer requires no disposal; test short-circuited.\");\n            _observerDisposedYet = true; // TODO BPETIT remove that\n            _streamId = streamId;\n            _streamNamespace = string.IsNullOrWhiteSpace(streamNamespace) ? null : streamNamespace.Trim();\n            _providerName = streamProvider.Name;\n        }\n\n        public void RenewProducer(ILogger logger, IStreamProvider streamProvider)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            _logger = logger;\n            _logger.LogInformation(\"RenewProducer\");\n            IAsyncStream<StreamItem> stream = streamProvider.GetStream<StreamItem>(_streamNamespace, _streamId);\n            _observer = stream;\n            _observerDisposedYet = true; // TODO BPETIT remove that\n        }\n\n        private async Task<bool> ProduceItem(string data)\n        {\n            if (_cleanedUpFlag.IsSet)\n                return false;\n\n            StreamItem item = new StreamItem(data, _streamId);\n            await _observer.OnNextAsync(item);\n            _itemsProduced++;\n            var logLevel = DEBUG_STREAMING_GRAINS ? LogLevel.Information : LogLevel.Debug;\n            _logger.Log(logLevel, \"ProducerObserver.ProduceItem: StreamId: {StreamId}, Data: {Data}, NumProduced so far: {ItemsProduced}.\", _streamId, data, _itemsProduced);\n            return true;\n        }\n\n        public async Task ProduceSequentialSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            if (0 >= count)\n                throw new ArgumentOutOfRangeException(nameof(count), \"The count must be greater than zero.\");\n            _expectedItemsProduced += count;\n            _logger.LogInformation(\"ProducerObserver.ProduceSequentialSeries: StreamId={StreamId}, num items to produce={Count}.\", _streamId, count);\n            for (var i = 1; i <= count; ++i)\n                await ProduceItem(string.Format(\"sequential#{0}\", i));\n        }\n\n        public Task ProduceParallelSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            if (0 >= count)\n                throw new ArgumentOutOfRangeException(nameof(count), \"The count must be greater than zero.\");\n            _logger.LogInformation(\"ProducerObserver.ProduceParallelSeries: streamId={StreamId}, num items to produce={Count}.\", _streamId, count);\n            _expectedItemsProduced += count;\n            var tasks = new Task<bool>[count];\n            for (var i = 1; i <= count; ++i)\n            {\n                int capture = i;\n                async Task<bool> func()\n                {\n                    return await ProduceItem($\"parallel#{capture}\");\n                }\n                // Need to call on different threads to force parallel execution.\n                tasks[capture - 1] = Task.Factory.StartNew(func).Unwrap();\n            }\n            return Task.WhenAll(tasks);\n        }\n\n        public Task<int> ItemsProduced\n        {\n            get\n            {\n                _cleanedUpFlag.ThrowNotInitializedIfSet();\n                return Task.FromResult(_itemsProduced);\n            }\n        }\n\n        public Task ProducePeriodicSeries(Func<Func<object, Task>, IDisposable> createTimerFunc, int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            _logger.LogInformation(\"ProducerObserver.ProducePeriodicSeries: streamId={StreamId}, num items to produce={Count}.\", _streamId, count);\n            var timer = TimerState.NewTimer(createTimerFunc, ProduceItem, RemoveTimer, count);\n            // we can't pass the TimerState object in as the argument-- it might be prematurely collected, so we root\n            // it to this object via the _timers dictionary.\n            _timers.Add(timer.Handle, timer);\n            _expectedItemsProduced += count;\n            timer.StartTimer();\n            return Task.CompletedTask;\n        }\n\n        private void RemoveTimer(IDisposable handle)\n        {\n            _logger.LogInformation(\"ProducerObserver.RemoveTimer: streamId={StreamId}.\", _streamId);\n            if (handle == null)\n                throw new ArgumentNullException(nameof(handle));\n            if (!_timers.Remove(handle))\n                throw new InvalidOperationException(\"handle not found\");\n        }\n\n        public Task<Guid> StreamId\n        {\n            get\n            {\n                _cleanedUpFlag.ThrowNotInitializedIfSet();\n                return Task.FromResult(_streamId);\n            }\n        }\n\n        public string ProviderName\n        {\n            get\n            {\n                _cleanedUpFlag.ThrowNotInitializedIfSet();\n                return _providerName;\n            }\n        }\n\n        public Task AddNewConsumerGrain(Guid consumerGrainId)\n        {\n            var grain = _grainFactory.GetGrain<IStreaming_ConsumerGrain>(consumerGrainId, \"UnitTests.Grains.Streaming_ConsumerGrain\");\n            return grain.BecomeConsumer(_streamId, _providerName, _streamNamespace);\n        }\n\n        public Task<int> ExpectedItemsProduced\n        {\n            get\n            {\n                _cleanedUpFlag.ThrowNotInitializedIfSet();\n                return Task.FromResult(_expectedItemsProduced);\n            }\n        }\n\n        public Task<int> ProducerCount\n        {\n            get { return Task.FromResult(_cleanedUpFlag.IsSet ? 0 : 1); }\n        }\n\n        public Task StopBeingProducer()\n        {\n            _logger.LogInformation(\"StopBeingProducer\");\n            if (!_cleanedUpFlag.TrySet())\n                return Task.CompletedTask;\n\n            if (_timers != null)\n            {\n                foreach (var i in _timers)\n                {\n                    try\n                    {\n                        i.Value.Dispose();\n                    }\n                    catch (Exception exc)\n                    {\n                        _logger.LogError(exc, \"StopBeingProducer: Timer Dispose() has thrown\");\n                    }\n                }\n                _timers = null;\n            }\n            _observer = null; // Disposing\n            return Task.CompletedTask;\n        }\n\n        public async Task VerifyFinished()\n        {\n            _logger.LogInformation(\"ProducerObserver.VerifyFinished: waiting for observer disposal; streamId={StreamId}\", _streamId);\n            while (!_observerDisposedYet)\n            {\n                await Task.Delay(1000);\n                GC.Collect();\n                GC.WaitForPendingFinalizers();\n            }\n            _logger.LogInformation(\"ProducerObserver.VerifyFinished: observer disposed; streamId={StreamId}\", _streamId);\n        }\n\n        private class TimerState : IDisposable\n        {\n            private bool _started;\n            public IDisposable Handle { get; private set; }\n            private int _counter;\n            private readonly Func<string, Task<bool>> _produceItemFunc;\n            private readonly Action<IDisposable> _onDisposeFunc;\n            private readonly InterlockedFlag _disposedFlag;\n\n            private TimerState(Func<string, Task<bool>> produceItemFunc, Action<IDisposable> onDisposeFunc, int count)\n            {\n                _produceItemFunc = produceItemFunc;\n                _onDisposeFunc = onDisposeFunc;\n                _counter = count;\n                _disposedFlag = new InterlockedFlag();\n            }\n\n            public static TimerState NewTimer(Func<Func<object, Task>, IDisposable> startTimerFunc, Func<string, Task<bool>> produceItemFunc, Action<IDisposable> onDisposeFunc, int count)\n            {\n                if (null == startTimerFunc)\n                    throw new ArgumentNullException(nameof(startTimerFunc));\n                if (null == produceItemFunc)\n                    throw new ArgumentNullException(nameof(produceItemFunc));\n                if (null == onDisposeFunc)\n                    throw new ArgumentNullException(nameof(onDisposeFunc));\n                if (0 >= count)\n                    throw new ArgumentOutOfRangeException(nameof(count), count, \"argument must be > 0\");\n                var newOb = new TimerState(produceItemFunc, onDisposeFunc, count);\n                newOb.Handle = startTimerFunc(newOb.OnTickAsync);\n                if (null == newOb.Handle)\n                    throw new InvalidOperationException(\"startTimerFunc must not return null\");\n                return newOb;\n            }\n\n            public void StartTimer()\n            {\n                _disposedFlag.ThrowDisposedIfSet(GetType());\n\n                if (_started)\n                    throw new InvalidOperationException(\"timer already started\");\n                _started = true;\n            }\n\n            private async Task OnTickAsync(object unused)\n            {\n                if (_started && !_disposedFlag.IsSet)\n                {\n                    --_counter;\n                    bool shouldContinue = await _produceItemFunc(string.Format(\"periodic#{0}\", _counter));\n                    if (!shouldContinue || 0 == _counter)\n                        Dispose();\n                }\n            }\n\n            public void Dispose()\n            {\n                Dispose(true);\n                GC.SuppressFinalize(this);\n            }\n\n            protected virtual void Dispose(bool disposing)\n            {\n                if (!_disposedFlag.TrySet())\n                    return;\n                _onDisposeFunc(Handle);\n                Handle.Dispose();\n                Handle = null;\n            }\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class Streaming_ProducerGrain : Grain<Streaming_ProducerGrain_State>, IStreaming_ProducerGrain\n    {\n        private InterlockedFlag _cleanedUpFlag;\n        private ILogger _logger;\n        protected List<IProducerObserver> _producers;\n        protected readonly IGrainContext _grainContext;\n\n        public Streaming_ProducerGrain(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var activationId = _grainContext.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.Streaming_ProducerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"OnActivateAsync\");\n             _producers = new List<IProducerObserver>();\n            _cleanedUpFlag = new InterlockedFlag();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public virtual Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            ProducerObserver producer = ProducerObserver.NewObserver(_logger, GrainFactory);\n            producer.BecomeProducer(streamId, this.GetStreamProvider(providerToUse), streamNamespace);\n            _producers.Add(producer);\n            return Task.CompletedTask;\n        }\n\n        public virtual async Task ProduceSequentialSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            foreach (var producer in _producers)\n            {\n                await producer.ProduceSequentialSeries(count);\n            }\n        }\n\n        public virtual async Task ProduceParallelSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            await Task.WhenAll(_producers.Select(p => p.ProduceParallelSeries(count)).ToArray());\n        }\n\n        public virtual async Task ProducePeriodicSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            await Task.WhenAll(_producers.Select(p => p.ProducePeriodicSeries(timerCallback =>\n                {\n                    return this.RegisterGrainTimer(timerCallback, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(10));\n                },count)).ToArray());\n        }\n\n        public virtual async Task<int> GetExpectedItemsProduced()\n        {\n            var tasks = _producers.Select(p => p.ExpectedItemsProduced).ToArray();\n            int[] expectedItemsProduced = await Task.WhenAll(tasks);\n            return expectedItemsProduced.Sum();\n        }\n\n        public virtual async Task<int> GetItemsProduced()\n        {\n            var tasks = _producers.Select(p => p.ItemsProduced).ToArray();\n            int[] itemsProduced = await Task.WhenAll(tasks);\n            return itemsProduced.Sum();\n        }\n\n        public virtual async Task AddNewConsumerGrain(Guid consumerGrainId)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n            await Task.WhenAll(_producers.Select(\n                target =>\n                    target.AddNewConsumerGrain(consumerGrainId)).ToArray());\n        }\n\n        public virtual async Task<int> GetProducerCount()\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n            var tasks = _producers.Select(p => p.ProducerCount).ToArray();\n            int[] producerCount = await Task.WhenAll(tasks);\n            return producerCount.Sum();\n        }\n\n        public virtual async Task StopBeingProducer()\n        {\n            if (!_cleanedUpFlag.TrySet())\n                return;\n\n            var tasks = _producers.Select(p => p.StopBeingProducer()).ToArray();\n            await Task.WhenAll(tasks);\n        }\n\n        public virtual async Task VerifyFinished()\n        {\n            var tasks = _producers.Select(p => p.VerifyFinished()).ToArray();\n            await Task.WhenAll(tasks);\n            _producers.Clear();\n        }\n\n        public virtual Task DeactivateProducerOnIdle()\n        {\n            _logger.LogInformation(\"DeactivateProducerOnIdle\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class PersistentStreaming_ProducerGrain : Streaming_ProducerGrain, IStreaming_ProducerGrain\n    {\n        private ILogger _logger;\n\n        public PersistentStreaming_ProducerGrain(IGrainContext grainContext) : base(grainContext)\n        {\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await base.OnActivateAsync(cancellationToken);\n            var activationId = _grainContext.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.PersistentStreaming_ProducerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"OnActivateAsync\");\n            if (State.Producers == null)\n            {\n                State.Producers = new List<IProducerObserver>();\n                _producers = State.Producers;\n            }\n            else\n            {\n                foreach (var producer in State.Producers)\n                {\n                    producer.RenewProducer(_logger, this.GetStreamProvider(producer.ProviderName));\n                    _producers.Add(producer);\n                }\n            }\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public override async Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            await base.BecomeProducer(streamId, providerToUse, streamNamespace);\n            State.Producers = _producers;\n            await WriteStateAsync();\n        }\n\n        public override async Task ProduceSequentialSeries(int count)\n        {\n            await base.ProduceParallelSeries(count);\n            State.Producers = _producers;\n            await WriteStateAsync();\n        }\n\n        public override async Task ProduceParallelSeries(int count)\n        {\n            await base.ProduceParallelSeries(count);\n            State.Producers = _producers;\n            await WriteStateAsync();\n        }\n\n        public override async Task StopBeingProducer()\n        {\n            await base.StopBeingProducer();\n            State.Producers = _producers;\n            await WriteStateAsync();\n        }\n\n        public override async Task VerifyFinished()\n        {\n            await base.VerifyFinished();\n            await ClearStateAsync();\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class Streaming_ConsumerGrain : Grain<Streaming_ConsumerGrain_State>, IStreaming_ConsumerGrain\n    {\n        private ILogger _logger;\n        protected List<IConsumerObserver> _observers;\n        private string _providerToUse;\n        protected readonly IGrainContext _grainContext;\n\n        public Streaming_ConsumerGrain(IGrainContext grainContext)\n        {\n            _grainContext = grainContext;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var activationId = _grainContext.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.Streaming_ConsumerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"OnActivateAsync\");\n            _observers = new List<IConsumerObserver>();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async virtual Task BecomeConsumer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _providerToUse = providerToUse;\n            ConsumerObserver consumerObserver = ConsumerObserver.NewObserver(_logger);\n            await consumerObserver.BecomeConsumer(streamId, this.GetStreamProvider(providerToUse), streamNamespace);\n            _observers.Add(consumerObserver);\n        }\n\n        public virtual async Task<int> GetItemsConsumed()\n        {\n            var tasks = _observers.Select(p => p.ItemsConsumed).ToArray();\n            int[] itemsConsumed = await Task.WhenAll(tasks);\n            return itemsConsumed.Sum();\n        }\n\n        public virtual async Task<int> GetConsumerCount()\n        {\n            var tasks = _observers.Select(p => p.ConsumerCount).ToArray();\n            int[] consumerCount = await Task.WhenAll(tasks);\n            return consumerCount.Sum();\n        }\n\n        public virtual async Task StopBeingConsumer()\n        {\n            var tasks = _observers.Select(obs => obs.StopBeingConsumer(this.GetStreamProvider(_providerToUse))).ToArray();\n            await Task.WhenAll(tasks);\n            _observers.Clear();\n        }\n\n        public virtual Task DeactivateConsumerOnIdle()\n        {\n            _logger.LogInformation(\"DeactivateConsumerOnIdle\");\n\n            Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(task => { _logger.LogInformation(\"DeactivateConsumerOnIdle ContinueWith fired.\"); }).Ignore(); // .WithTimeout(TimeSpan.FromSeconds(2));\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class PersistentStreaming_ConsumerGrain : Streaming_ConsumerGrain, IPersistentStreaming_ConsumerGrain\n    {\n        private ILogger _logger;\n\n        public PersistentStreaming_ConsumerGrain(IGrainContext grainContext) : base(grainContext)\n        {\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await base.OnActivateAsync(cancellationToken);\n            var activationId = _grainContext.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.PersistentStreaming_ConsumerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"OnActivateAsync\");\n\n            if (State.Consumers == null)\n            {\n                State.Consumers = new List<IConsumerObserver>();\n                _observers = State.Consumers;\n            }\n            else\n            {\n                foreach (var consumer in State.Consumers)\n                {\n                    await consumer.RenewConsumer(_logger, this.GetStreamProvider(consumer.ProviderName));\n                    _observers.Add(consumer);\n                }\n            }\n        }\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            await base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public override async Task BecomeConsumer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            await base.BecomeConsumer(streamId, providerToUse, streamNamespace);\n            State.Consumers = _observers;\n            await WriteStateAsync();\n        }\n\n        public override async Task StopBeingConsumer()\n        {\n            await base.StopBeingConsumer();\n            State.Consumers = _observers;\n            await WriteStateAsync();\n        }\n    }\n\n\n    [Reentrant]\n    public class Streaming_Reentrant_ProducerConsumerGrain : Streaming_ProducerConsumerGrain, IStreaming_Reentrant_ProducerConsumerGrain\n    {\n        private ILogger _logger;\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var activationId = RuntimeContext.Current.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.Streaming_Reentrant_ProducerConsumerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId) ;\n            _logger.LogInformation(\"OnActivateAsync\");\n            await base.OnActivateAsync(cancellationToken);\n        }\n    }\n\n    public class Streaming_ProducerConsumerGrain : Grain, IStreaming_ProducerConsumerGrain\n    {\n        private ILogger _logger;\n        private ProducerObserver _producer;\n        private ConsumerObserver _consumer;\n        private string _providerToUseForConsumer;\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var activationId = RuntimeContext.Current.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.Streaming_ProducerConsumerGrain \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _producer = ProducerObserver.NewObserver(_logger, GrainFactory);\n            _producer.BecomeProducer(streamId, this.GetStreamProvider(providerToUse), streamNamespace);\n            return Task.CompletedTask;\n        }\n\n        public Task ProduceSequentialSeries(int count)\n        {\n            return _producer.ProduceSequentialSeries(count);\n        }\n\n        public Task ProduceParallelSeries(int count)\n        {\n            return _producer.ProduceParallelSeries(count);\n        }\n\n        public Task ProducePeriodicSeries(int count)\n        {\n            return _producer.ProducePeriodicSeries(timerCallback =>\n            {\n                return this.RegisterGrainTimer(timerCallback, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(10));\n            }, count);\n        }\n\n        public Task<int> GetItemsProduced()\n        {\n            return _producer.ItemsProduced;\n        }\n\n        public Task AddNewConsumerGrain(Guid consumerGrainId)\n        {\n            return _producer.AddNewConsumerGrain(consumerGrainId);\n        }\n\n        public async Task BecomeConsumer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _providerToUseForConsumer = providerToUse;\n            _consumer = ConsumerObserver.NewObserver(this._logger);\n            await _consumer.BecomeConsumer(streamId, this.GetStreamProvider(providerToUse), streamNamespace);\n        }\n\n        public async Task<int> GetItemsConsumed()\n        {\n            return await _consumer.ItemsConsumed;\n        }\n\n        public async Task<int> GetExpectedItemsProduced()\n        {\n            return await _producer.ExpectedItemsProduced;\n        }\n\n        public async Task<int> GetConsumerCount()\n        {\n            return await _consumer.ConsumerCount;\n        }\n\n        public async Task<int> GetProducerCount()\n        {\n            return await _producer.ProducerCount;\n        }\n\n        public async Task StopBeingConsumer()\n        {\n            await _consumer.StopBeingConsumer(this.GetStreamProvider(_providerToUseForConsumer));\n            _consumer = null;\n        }\n\n        public async Task StopBeingProducer()\n        {\n            await _producer.StopBeingProducer();\n        }\n\n        public async Task VerifyFinished()\n        {\n            await _producer.VerifyFinished();\n            _producer = null;\n        }\n\n        public Task DeactivateConsumerOnIdle()\n        {\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task DeactivateProducerOnIdle()\n        {\n            _logger.LogInformation(\"DeactivateProducerOnIdle\");\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    public abstract class Streaming_ImplicitlySubscribedConsumerGrainBase : Grain, IStreamSubscriptionObserver\n    {\n        private ILogger _logger;\n        private Dictionary<string, IConsumerObserver> _observers;\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var activationId = RuntimeContext.Current.ActivationId;\n            _logger = this.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Test.Streaming_ImplicitConsumerGrain1 \" + RuntimeIdentity + \"/\" + IdentityString + \"/\" + activationId);\n            _logger.LogInformation(\"{Type}.OnActivateAsync\", GetType().FullName);\n            _observers = new Dictionary<string, IConsumerObserver>();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"OnDeactivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public async Task BecomeConsumer(Guid streamGuid, string providerToUse, string streamNamespace)\n        {\n            if (_observers.ContainsKey(providerToUse))\n            {\n                throw new InvalidOperationException(string.Format(\"consumer already established for provider {0}.\", providerToUse));\n            }\n\n            if (string.IsNullOrWhiteSpace(streamNamespace))\n            {\n                throw new ArgumentException(\"namespace is required (must not be null or whitespace)\", nameof(streamNamespace));\n            }\n\n            ConsumerObserver consumerObserver = ConsumerObserver.NewObserver(_logger);\n            await consumerObserver.BecomeConsumer(streamGuid, this.GetStreamProvider(providerToUse), streamNamespace);\n            _observers[providerToUse] = consumerObserver;\n        }\n\n        public virtual async Task<int> GetItemsConsumed()\n        {\n            int result = 0;\n            foreach (var o in _observers.Values)\n            {\n                result += await o.ItemsConsumed;\n            }\n            return result;\n        }\n\n        public virtual Task<int> GetConsumerCount()\n        {\n            // it's currently impossible to detect how many implicit consumers are being used,\n            // so we must resort to hard-wiring this grain to only use one provider's consumer at a time.\n            // this problem will continue until we require the provider's name to be apart of the implicit subscriber attribute identity.\n            return Task.FromResult(1);\n            /*\n            int result = 0;\n            foreach (var o in _observers.Values)\n            {\n                result += await o.ConsumerCount;\n            }\n            return result;\n            */\n        }\n\n        public async Task StopBeingConsumer()\n        {\n            await Task.WhenAll(_observers.Select(i => i.Value.StopBeingConsumer(this.GetStreamProvider(i.Key))));\n            _observers = null;\n        }\n\n        public Task DeactivateConsumerOnIdle()\n        {\n            _logger.LogInformation(\"DeactivateConsumerOnIdle\");\n\n            Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(task => { _logger.LogInformation(\"DeactivateConsumerOnIdle ContinueWith fired.\"); }).Ignore(); // .WithTimeout(TimeSpan.FromSeconds(2));\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public async Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory)\n        {\n            await BecomeConsumer(Guid.Parse(handleFactory.StreamId.Key.ToString()), handleFactory.ProviderName, handleFactory.StreamId.Namespace.ToString());\n        }\n    }\n\n    [ImplicitStreamSubscription(\"TestNamespace1\")]\n    public class Streaming_ImplicitlySubscribedConsumerGrain : Streaming_ImplicitlySubscribedConsumerGrainBase, IStreaming_ImplicitlySubscribedConsumerGrain\n    {}\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/StreamingImmutabilityTestGrain.cs",
    "content": "using Orleans.Streams;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class StreamingImmutabilityTestGrain : Grain, IStreamingImmutabilityTestGrain\n    {\n        private StreamImmutabilityTestObject _myObject;\n        private StreamSubscriptionHandle<StreamImmutabilityTestObject> _streamSubscriptionHandle;\n\n        public async Task SubscribeToStream(Guid guid, string providerName)\n        {\n            var stream = this.GetStreamProvider(providerName).GetStream<StreamImmutabilityTestObject>(\"Namespace\", guid);\n            _streamSubscriptionHandle = await stream.SubscribeAsync(OnNextAsync);\n        }\n\n        public async Task UnsubscribeFromStream()\n        {\n            if (_streamSubscriptionHandle != null)\n                await _streamSubscriptionHandle.UnsubscribeAsync();\n        }\n\n        public async Task SendTestObject(string providerName)\n        {\n            var stream = this.GetStreamProvider(providerName).GetStream<StreamImmutabilityTestObject>(\"Namespace\", this.GetPrimaryKey());\n            await stream.OnNextAsync(_myObject);\n        }\n\n        public Task SetTestObjectStringProperty(string value)\n        {\n            if(_myObject == null)\n                _myObject = new StreamImmutabilityTestObject();\n\n            _myObject.MyString = value;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetTestObjectStringProperty()\n        {\n            return Task.FromResult(_myObject.MyString);\n        }\n\n        public Task<string> GetSiloIdentifier()\n        {\n            return Task.FromResult(this.Runtime.SiloIdentity);\n        }\n\n        private Task OnNextAsync(StreamImmutabilityTestObject myObject, StreamSequenceToken streamSequenceToken)\n        {\n            _myObject = myObject;\n            return Task.CompletedTask;\n        }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class StreamImmutabilityTestObject\n    {\n        [Id(0)]\n        public string MyString;\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/StressTestGrain.cs",
    "content": "using System.Net;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing UnitTests.GrainInterfaces;\nusing Orleans.Runtime.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\n\nnamespace UnitTests.Grains\n{\n    internal class StressTestGrain : Grain, IStressTestGrain\n    {\n        private string label;\n\n        private readonly ILogger logger;\n\n        public StressTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (this.GetPrimaryKeyLong() == -2)\n                throw new ArgumentException(\"Primary key cannot be -2 for this test case\");\n\n            this.label = this.GetPrimaryKeyLong().ToString();\n            this.logger.LogInformation(\"OnActivateAsync\");\n\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetLabel()\n        {\n            return Task.FromResult(this.label);\n        }\n\n        public Task SetLabel(string label)\n        {\n            this.label = label;\n\n            //logger.Info(\"SetLabel {0} received\", label);\n            return Task.CompletedTask;\n        }\n\n        public Task<IStressTestGrain> GetGrainReference()\n        {\n            return Task.FromResult(this.AsReference<IStressTestGrain>());\n        }\n\n        public Task PingOthers(long[] others)\n        {\n            List<Task> promises = new List<Task>();\n            foreach (long key in others)\n            {\n                IStressTestGrain g1 = this.GrainFactory.GetGrain<IStressTestGrain>(key);\n                Task promise = g1.GetLabel();\n                promises.Add(promise);\n            }\n            return Task.WhenAll(promises);\n        }\n\n        public Task<List<Tuple<GrainId, int, List<Tuple<SiloAddress, ActivationId>>>>> LookUpMany(\n            SiloAddress destination, List<Tuple<GrainId, int>> grainAndETagList, int retries = 0)\n        {\n            var list = new List<Tuple<GrainId, int, List<Tuple<SiloAddress, ActivationId>>>>();\n            foreach (Tuple<GrainId, int> tuple in grainAndETagList)\n            {\n                GrainId id = tuple.Item1;\n                var reply = new List<Tuple<SiloAddress, ActivationId>>();\n                for (int i = 0; i < 10; i++)\n                {\n                    var siloAddress = SiloAddress.New(new IPEndPoint(ConfigUtilities.GetLocalIPAddress(),0), 0);\n                    reply.Add(new Tuple<SiloAddress, ActivationId>(siloAddress, ActivationId.NewId()));\n                }\n                list.Add(new Tuple<GrainId, int, List<Tuple<SiloAddress, ActivationId>>>(id, 3, reply));\n            }\n            return Task.FromResult(list);\n        }\n\n        public Task<byte[]> Echo(byte[] data)\n        {\n            return Task.FromResult(data);\n        }\n\n        public Task Ping(byte[] data)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task PingWithDelay(byte[] data, TimeSpan delay)\n        {\n            await Task.Delay(delay);\n        }\n\n        public Task Send(byte[] data)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task DeactivateSelf()\n        {\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n    }\n\n    [Reentrant]\n    internal class ReentrantStressTestGrain : Grain, IReentrantStressTestGrain\n    {\n        private string label;\n        private readonly ILogger logger;\n\n        public ReentrantStressTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.label = this.GetPrimaryKeyLong().ToString();\n            this.logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public Task<byte[]> Echo(byte[] data)\n        {\n            return Task.FromResult(data);\n        }\n\n        public Task Ping(byte[] data)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task PingWithDelay(byte[] data, TimeSpan delay)\n        {\n            await Task.Delay(delay);\n        }\n\n        public Task PingMutableArray(byte[] data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain).PingMutableArray(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingMutableArray(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingImmutableArray(Immutable<byte[]> data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingImmutableArray(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingImmutableArray(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingMutableDictionary(Dictionary<int, string> data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingMutableDictionary(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingMutableDictionary(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingImmutableDictionary(Immutable<Dictionary<int, string>> data, long nextGrain,\n            bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingImmutableDictionary(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingImmutableDictionary(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public async Task InterleavingConsistencyTest(int numItems)\n        {\n            TimeSpan delay = TimeSpan.FromMilliseconds(1);\n            List<Task> getFileMetadataPromises = new List<Task>(numItems*2);\n            Dictionary<int, string> fileMetadatas = new Dictionary<int, string>(numItems*2);\n\n            for (int i = 0; i < numItems; i++)\n            {\n                int capture = i;\n                Func<Task> func = (\n                    async () =>\n                    {\n                        await Task.Delay(RandomTimeSpan.Next(delay));\n                        int fileMetadata = capture;\n                        if ((fileMetadata%2) == 0)\n                        {\n                            fileMetadatas.Add(fileMetadata, fileMetadata.ToString());\n                        }\n                    });\n                getFileMetadataPromises.Add(func());\n            }\n\n            await Task.WhenAll(getFileMetadataPromises.ToArray());\n\n            List<Task> tagPromises = new List<Task>(fileMetadatas.Count);\n\n            foreach (KeyValuePair<int, string> keyValuePair in fileMetadatas)\n            {\n                int fileId = keyValuePair.Key;\n                Func<Task> func = (async () =>\n                {\n                    await Task.Delay(RandomTimeSpan.Next(delay));\n                    _ = fileMetadatas[fileId];\n                });\n                tagPromises.Add(func());\n            }\n\n            await Task.WhenAll(tagPromises);\n\n            // sort the fileMetadatas according to fileIds.\n            List<string> results = new List<string>(fileMetadatas.Count);\n            for (int i = 0; i < numItems; i++)\n            {\n                string metadata;\n                if (fileMetadatas.TryGetValue(i, out metadata))\n                {\n                    results.Add(metadata);\n                }\n            }\n\n            if (numItems != results.Count)\n            {\n                //throw new OrleansException(String.Format(\"numItems != results.Count, {0} != {1}\", numItems, results.Count));\n            }\n\n        }\n    }\n\n    [Reentrant]\n    [StatelessWorker]\n    public class ReentrantLocalStressTestGrain : Grain, IReentrantLocalStressTestGrain\n    {\n        private string label;\n        private readonly ILogger logger;\n\n        public ReentrantLocalStressTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.label = this.GetPrimaryKeyLong().ToString();\n            this.logger.LogInformation(\"OnActivateAsync\");\n            return Task.CompletedTask;\n        }\n\n        public Task<byte[]> Echo(byte[] data)\n        {\n            return Task.FromResult(data);\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public Task Ping(byte[] data)\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task PingWithDelay(byte[] data, TimeSpan delay)\n        {\n            await Task.Delay(delay);\n        }\n\n        public Task PingMutableArray(byte[] data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain).PingMutableArray(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingMutableArray(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingImmutableArray(Immutable<byte[]> data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingImmutableArray(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingImmutableArray(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingMutableDictionary(Dictionary<int, string> data, long nextGrain, bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingMutableDictionary(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingMutableDictionary(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n\n        public Task PingImmutableDictionary(Immutable<Dictionary<int, string>> data, long nextGrain,\n            bool nextGrainIsRemote)\n        {\n            if (nextGrain > 0)\n            {\n                if (nextGrainIsRemote)\n                {\n                    return this.GrainFactory.GetGrain<IReentrantStressTestGrain>(nextGrain)\n                        .PingImmutableDictionary(data, -1, false);\n                }\n                return this.GrainFactory.GetGrain<IReentrantLocalStressTestGrain>(nextGrain)\n                    .PingImmutableDictionary(data, -1, false);\n            }\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/TestExtension.cs",
    "content": "﻿using UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    internal class TestExtension : ITestExtension\n    {\n        private readonly ExtensionTestGrain grain;\n        private readonly IGrainFactory grainFactory;\n\n        public TestExtension(ExtensionTestGrain g, IGrainFactory grainFactory)\n        {\n            grain = g;\n            this.grainFactory = grainFactory;\n        }\n\n        public Task<string> CheckExtension_1()\n        {\n            return Task.FromResult(grain.ExtensionProperty);\n        }\n\n        // check that one can send messages from within extensions.\n        public Task<string> CheckExtension_2()\n        {\n            ITestGrain g = grainFactory.GetGrain<ITestGrain>(23);\n            return g.GetLabel();\n        }\n    }\n\n    public class SimpleExtension : ISimpleExtension\n    {\n        private readonly string someString;\n\n        public SimpleExtension(string someString)\n        {\n            this.someString = someString;\n        }\n\n        public Task<string> CheckExtension_1()\n        {\n            return Task.FromResult(someString);\n        }\n    }\n    \n    public class AutoExtension : IAutoExtension\n    {\n        public Task<string> CheckExtension()\n        {\n            return Task.FromResult(\"whoot!\");\n        }\n    }\n\n    public class GenericTestExtension<T> : IGenericTestExtension<T>\n    {\n        private readonly GenericExtensionTestGrain<T> grain;\n        private readonly IGrainFactory grainFactory;\n\n        public GenericTestExtension(GenericExtensionTestGrain<T> g, IGrainFactory grainFactory)\n        {\n            grain = g;\n            this.grainFactory = grainFactory;\n        }\n\n        public Task<T> CheckExtension_1()\n        {\n            return Task.FromResult(grain.ExtensionProperty);\n        }\n\n        // check that one can send messages from within extensions.\n        public Task<string> CheckExtension_2()\n        {\n            ITestGrain g = this.grainFactory.GetGrain<ITestGrain>(24);\n            return g.GetLabel();\n        }\n    }\n}"
  },
  {
    "path": "test/Grains/TestInternalGrains/TestGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing UnitTests.GrainInterfaces;\n\nnamespace UnitTests.Grains\n{\n    public class TestGrain : Grain, ITestGrain\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n        private string label;\n        private readonly ILogger logger;\n        private IDisposable timer;\n\n        public TestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            if (this.GetPrimaryKeyLong() == -2)\n                throw new ArgumentException(\"Primary key cannot be -2 for this test case\");\n\n            label = this.GetPrimaryKeyLong().ToString();\n            logger.LogInformation(\"OnActivateAsync\");\n\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"!!! OnDeactivateAsync\");\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n\n        public Task<long> GetKey()\n        {\n            return Task.FromResult(this.GetPrimaryKeyLong());\n        }\n\n        public Task<string> GetLabel()\n        {\n            return Task.FromResult(label);\n        }\n\n        public async Task DoLongAction(TimeSpan timespan, string str)\n        {\n            logger.LogInformation(\"DoLongAction {String} received\", str);\n            await Task.Delay(timespan);\n        }\n\n        public Task SetLabel(string label)\n        {\n            this.label = label;\n            logger.LogInformation(\"SetLabel {Label} received\", label);\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer()\n        {\n            logger.LogInformation(\"StartTimer.\");\n            timer = this.RegisterGrainTimer(TimerTick, dueTime: TimeSpan.Zero, period: TimeSpan.FromSeconds(10));\n\n            return Task.CompletedTask;\n        }\n        private Task Ticker(object obj) => Task.CompletedTask;\n\n        private Task TimerTick(CancellationToken cancellationToken)\n        {\n            logger.LogInformation(\"TimerTick.\");\n            return Task.CompletedTask;\n        }\n\n        public async Task<Tuple<string, string>> TestRequestContext()\n        {\n            string bar1 = null;\n            RequestContext.Set(\"jarjar\", \"binks\");\n\n            var task = Task.Factory.StartNew(() =>\n            {\n                bar1 = (string) RequestContext.Get(\"jarjar\");\n                logger.LogInformation(\"bar = {Bar}.\", bar1);\n            });\n\n            string bar2 = null;\n            var ac = Task.Factory.StartNew(() =>\n            {\n                bar2 = (string) RequestContext.Get(\"jarjar\");\n                logger.LogInformation(\"bar = {Bar}.\", bar2);\n            });\n\n            await Task.WhenAll(task, ac);\n            return new Tuple<string, string>(bar1, bar2);\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public Task<string> GetActivationId()\n        {\n            return Task.FromResult(_id);\n        }\n\n        public Task<ITestGrain> GetGrainReference()\n        {\n            return Task.FromResult(this.AsReference<ITestGrain>());\n        }\n\n        public Task<IGrain[]> GetMultipleGrainInterfaces_Array()\n        {\n            var grains = new IGrain[5];\n            for (var i = 0; i < grains.Length; i++)\n            {\n                grains[i] = GrainFactory.GetGrain<ITestGrain>(i);\n            }\n            return Task.FromResult(grains);\n        }\n\n        public Task<List<IGrain>> GetMultipleGrainInterfaces_List()\n        {\n            var grains = new IGrain[5];\n            for (var i = 0; i < grains.Length; i++)\n            {\n                grains[i] = GrainFactory.GetGrain<ITestGrain>(i);\n            }\n            return Task.FromResult(grains.ToList());\n        }\n    }\n\n    public class TestGrainLongActivateAsync : Grain, ITestGrainLongOnActivateAsync\n    {\n        public TestGrainLongActivateAsync()\n        {\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await Task.Delay(TimeSpan.FromSeconds(3));\n\n            if (this.GetPrimaryKeyLong() == -2)\n                throw new ArgumentException(\"Primary key cannot be -2 for this test case\");\n\n            await base.OnActivateAsync(cancellationToken);\n        }\n\n        public Task<long> GetKey()\n        {\n            return Task.FromResult(this.GetPrimaryKeyLong());\n        }\n    }\n\n    [GrainType(\"guid-test-grain\")]\n    internal class GuidTestGrain : Grain, IGuidTestGrain\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n\n        private string label;\n        private readonly ILogger logger;\n\n        public GuidTestGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            //if (this.GetPrimaryKeyLong() == -2)\n            //    throw new ArgumentException(\"Primary key cannot be -2 for this test case\");\n\n            label = this.GetPrimaryKey().ToString();\n            logger.LogInformation(\"OnActivateAsync\");\n\n            return Task.CompletedTask;\n        }\n\n        public Task<Guid> GetKey()\n        {\n            return Task.FromResult(this.GetPrimaryKey());\n        }\n\n        public Task<string> GetLabel()\n        {\n            return Task.FromResult(label);\n        }\n\n        public Task SetLabel(string label)\n        {\n            this.label = label;\n            return Task.CompletedTask;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(RuntimeIdentity);\n        }\n\n        public Task<string> GetActivationId()\n        {\n            return Task.FromResult(_id);\n        }\n\n        public Task<SiloAddress> GetSiloAddress() => Task.FromResult(ServiceProvider.GetRequiredService<ILocalSiloDetails>().SiloAddress);\n    }\n\n    internal class OneWayGrain : Grain, IOneWayGrain, ISimpleGrainObserver\n    {\n        private readonly string _id = Guid.NewGuid().ToString();\n        private int count;\n        private TaskCompletionSource<string> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n        private IOneWayGrain other;\n        private readonly GrainLocator grainLocator;\n        private int _numSignals;\n\n        public OneWayGrain(GrainLocator grainLocator) => this.grainLocator = grainLocator;\n\n        private ILocalGrainDirectory LocalGrainDirectory => this.ServiceProvider.GetRequiredService<ILocalGrainDirectory>();\n        private ILocalSiloDetails LocalSiloDetails => this.ServiceProvider.GetRequiredService<ILocalSiloDetails>();\n\n        public Task Notify()\n        {\n            this.count++;\n            return Task.CompletedTask;\n        }\n\n        public Task Notify(ISimpleGrainObserver observer)\n        {\n            this.count++;\n            observer.StateChanged(this.count - 1, this.count);\n            return Task.CompletedTask;\n        }\n\n        public ValueTask NotifyValueTask(ISimpleGrainObserver observer)\n        {\n            this.count++;\n            observer.StateChanged(this.count - 1, this.count);\n            return default;\n        }\n\n        public async Task<bool> NotifyOtherGrain(IOneWayGrain otherGrain, ISimpleGrainObserver observer)\n        {\n            var task = otherGrain.Notify(observer);\n            var completedSynchronously = task.Status == TaskStatus.RanToCompletion;\n            await task;\n            return completedSynchronously;\n        }\n\n        public async Task<bool> NotifyOtherGrainValueTask(IOneWayGrain otherGrain, ISimpleGrainObserver observer)\n        {\n            var task = otherGrain.NotifyValueTask(observer);\n            var completedSynchronously = task.IsCompleted;\n            await task;\n            return completedSynchronously;\n        }\n\n        public async Task<IOneWayGrain> GetOtherGrain()\n        {\n            return this.other ?? (this.other = await GetGrainOnOtherSilo());\n\n            async Task<IOneWayGrain> GetGrainOnOtherSilo()\n            {\n                var silos = ServiceProvider.GetRequiredService<IClusterMembershipService>().CurrentSnapshot.Members.Where(kv => kv.Value.Status == SiloStatus.Active).Select(kv => kv.Key).ToHashSet();\n                var thisSilo = await this.GetSiloAddress();\n                silos.Remove(thisSilo);\n                while (true)\n                {\n                    RequestContext.Set(IPlacementDirector.PlacementHintKey, silos.First());\n                    var candidate = this.GrainFactory.GetGrain<IOneWayGrain>(Guid.NewGuid());\n                    var directorySilo = await candidate.GetPrimaryForGrain();\n                    var candidateSilo = await candidate.GetSiloAddress();\n                    if (!directorySilo.Equals(candidateSilo)\n                        && !directorySilo.Equals(thisSilo)\n                        && !candidateSilo.Equals(thisSilo))\n                    {\n                        return candidate;\n                    }\n                }\n            }\n        }\n\n        public Task<string> GetActivationId()\n        {\n            return Task.FromResult(_id);\n        }\n\n        public Task<string> GetActivationAddress(IGrain grain)\n        {\n            var grainId = ((GrainReference)grain).GrainId;\n            if (this.grainLocator.TryLookupInCache(grainId, out var result))\n            {\n                return Task.FromResult(result.ToString());\n            }\n\n            return Task.FromResult<string>(null);\n        }\n\n        public Task NotifyOtherGrain() => this.other.Notify(this.AsReference<ISimpleGrainObserver>());\n\n        public Task<int> GetCount() => Task.FromResult(this.count);\n\n        public Task Deactivate()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task ThrowsOneWay()\n        {\n            throw new Exception(\"GET OUT!\");\n        }\n\n        public ValueTask ThrowsOneWayValueTask()\n        {\n            throw new Exception(\"GET OUT (ValueTask)!\");\n        }\n\n        public Task<SiloAddress> GetSiloAddress()\n        {\n            return Task.FromResult(this.LocalSiloDetails.SiloAddress);\n        }\n\n        public Task<SiloAddress> GetPrimaryForGrain()\n        {\n            var grainId = (GrainId)this.GrainId;\n            var primaryForGrain = this.LocalGrainDirectory.GetPrimaryForGrain(grainId);\n            return Task.FromResult(primaryForGrain);\n        }\n\n        public void StateChanged(int a, int b)\n        {\n            _numSignals++;\n            this.tcs.TrySetResult(null);\n        }\n\n        public async Task SendSignalTo(IOneWayGrain grain)\n        {\n            await grain.Signal(_id);\n        }\n\n        public Task SignalSelfViaOther() => this.other.SendSignalTo(this.AsReference<IOneWayGrain>());\n\n        public async Task<(int NumSignals, string SignallerId)> WaitForSignal()\n        {\n            var signallerId = await this.tcs.Task;\n            this.tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n            return (_numSignals, signallerId);\n        }\n\n        public Task Signal(string id)\n        {\n            _numSignals++;\n            tcs.TrySetResult(id);\n            return Task.CompletedTask;\n        }\n    }\n\n    public class CanBeOneWayGrain : Grain, ICanBeOneWayGrain\n    {\n        private int count;\n\n        public Task Notify()\n        {\n            this.count++;\n            return Task.CompletedTask;\n        }\n\n        public Task Notify(ISimpleGrainObserver observer)\n        {\n            this.count++;\n            observer.StateChanged(this.count - 1, this.count);\n            return Task.CompletedTask;\n        }\n\n        public ValueTask NotifyValueTask(ISimpleGrainObserver observer)\n        {\n            this.count++;\n            observer.StateChanged(this.count - 1, this.count);\n            return default;\n        }\n\n        public Task<int> GetCount() => Task.FromResult(this.count);\n\n        public Task Throws()\n        {\n            throw new Exception(\"GET OUT!\");\n        }\n\n        public ValueTask ThrowsValueTask()\n        {\n            throw new Exception(\"GET OUT!\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/TestInternalGrains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.Grains</RootNamespace>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <NoWarn>$(NoWarn);1591;1591;618</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit.assert\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrains\\TestGrains.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestInternalGrainInterfaces\\TestInternalGrainInterfaces.csproj\" />\n  </ItemGroup>\n\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Grains/TestInternalGrains/TimerGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Scheduler;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\n\nnamespace UnitTestGrains\n{\n    public class TimerGrain : Grain, ITimerGrain\n    {\n        private bool deactivating;\n        private int counter = 0;\n        private Dictionary<string, IDisposable> allTimers;\n        private IDisposable defaultTimer;\n        private static readonly TimeSpan period = TimeSpan.FromMilliseconds(100);\n        private readonly string DefaultTimerName = \"DEFAULT TIMER\";\n        private IGrainContext context;\n\n        private readonly ILogger logger;\n\n        public TimerGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ThrowIfDeactivating();\n            context = RuntimeContext.Current;\n            defaultTimer = this.RegisterGrainTimer(Tick, DefaultTimerName, period, period);\n            allTimers = new Dictionary<string, IDisposable>();\n            return Task.CompletedTask;\n        }\n\n        public Task StopDefaultTimer()\n        {\n            ThrowIfDeactivating();\n            defaultTimer.Dispose();\n            return Task.CompletedTask;\n        }\n        private Task Tick(object data)\n        {\n            counter++;\n            logger.LogInformation(\n                \"{Data} Tick # {Counter} RuntimeContext = {RuntimeContext}\",\n                data,\n                counter,\n                RuntimeContext.Current);\n\n            // make sure we run in the right activation context.\n            if (!Equals(context, RuntimeContext.Current))\n                logger.LogError((int)ErrorCode.Runtime_Error_100146, \"Grain not running in the right activation context\");\n\n            string name = (string)data;\n            IDisposable timer;\n            if (name == DefaultTimerName)\n            {\n                timer = defaultTimer;\n            }\n            else\n            {\n                timer = allTimers[(string)data];\n            }\n            if (timer == null)\n                logger.LogError((int)ErrorCode.Runtime_Error_100146, \"Timer is null\");\n            if (timer != null && counter > 10000)\n            {\n                // do not let orphan timers ticking for long periods\n                timer.Dispose();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task<TimeSpan> GetTimerPeriod()\n        {\n            return Task.FromResult(period);\n        }\n\n        public Task<int> GetCounter()\n        {\n            ThrowIfDeactivating();\n            return Task.FromResult(counter);\n        }\n        public Task SetCounter(int value)\n        {\n            ThrowIfDeactivating();\n            lock (this)\n            {\n                counter = value;\n            }\n            return Task.CompletedTask;\n        }\n        public Task StartTimer(string timerName)\n        {\n            ThrowIfDeactivating();\n            IDisposable timer = this.RegisterGrainTimer(Tick, timerName, TimeSpan.Zero, period);\n            allTimers.Add(timerName, timer);\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string timerName)\n        {\n            ThrowIfDeactivating();\n            IDisposable timer = allTimers[timerName];\n            timer.Dispose();\n            return Task.CompletedTask;\n        }\n\n        public Task LongWait(TimeSpan time)\n        {\n            ThrowIfDeactivating();\n            Thread.Sleep(time);\n            return Task.CompletedTask;\n        }\n\n        public Task Deactivate()\n        {\n            deactivating = true;\n            DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        private void ThrowIfDeactivating()\n        {\n            if (deactivating) throw new InvalidOperationException(\"This activation is deactivating\");\n        }\n    }\n\n    public class TimerCallGrain : Grain, ITimerCallGrain\n    {\n        private int tickCount;\n        private Exception tickException;\n        private IGrainTimer timer;\n        private string timerName;\n        private IGrainContext context;\n        private TaskScheduler activationTaskScheduler;\n\n        private readonly ILogger logger;\n\n        public TimerCallGrain(ILoggerFactory loggerFactory)\n        {\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.IdentityString}\");\n        }\n\n        public Task<int> GetTickCount() { return Task.FromResult(tickCount); }\n        public Task<Exception> GetException() { return Task.FromResult(tickException); }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            context = RuntimeContext.Current;\n            activationTaskScheduler = TaskScheduler.Current;\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay)\n        {\n            logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (timer is not null) throw new InvalidOperationException(\"Expected timer to be null\");\n            this.timer = this.RegisterGrainTimer(TimerTick, name, new(delay, Timeout.InfiniteTimeSpan) { Interleave = true }); // One shot timer\n            this.timerName = name;\n\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay, string operationType)\n        {\n            logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (timer is not null) throw new InvalidOperationException(\"Expected timer to be null\");\n            var state = Tuple.Create<string, object>(operationType, name);\n            this.timer = this.RegisterGrainTimer(TimerTickAdvanced, state, new(delay, Timeout.InfiniteTimeSpan) { Interleave = true }); // One shot timer\n            this.timerName = name;\n\n            return Task.CompletedTask;\n        }\n\n        public Task RestartTimer(string name, TimeSpan delay)\n        {\n            logger.LogInformation(\"RestartTimer Name={Name} Delay={Delay}\", name, delay);\n            this.timerName = name;\n            timer.Change(delay, Timeout.InfiniteTimeSpan);\n\n            return Task.CompletedTask;\n        }\n\n        public Task RestartTimer(string name, TimeSpan delay, TimeSpan period)\n        {\n            logger.LogInformation(\"RestartTimer Name={Name} Delay={Delay} Period={Period}\", name, delay, period);\n            this.timerName = name;\n            timer.Change(delay, period);\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string name)\n        {\n            logger.LogInformation(\"StopTimer Name={Name}\", name);\n            if (name != this.timerName)\n            {\n                throw new ArgumentException($\"Wrong timer name: Expected={this.timerName} Actual={name}\");\n            }\n\n            timer.Dispose();\n            timer = null;\n            timerName = null;\n            return Task.CompletedTask;\n        }\n\n        public async Task RunSelfDisposingTimer()\n        {\n            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n            var timer = new IGrainTimer[1];\n            timer[0] = this.RegisterGrainTimer(async (ct) =>\n            {\n                try\n                {\n                    Assert.False(ct.IsCancellationRequested);\n                    Assert.NotNull(timer[0]);\n                    timer[0].Dispose();\n                    Assert.True(ct.IsCancellationRequested);\n                    await Task.Delay(100);\n                    tcs.TrySetResult();\n                }\n                catch (Exception ex)\n                {\n                    tcs.TrySetException(ex);\n                }\n            },\n            new GrainTimerCreationOptions(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n                Interleave = true\n            });\n\n            await tcs.Task;\n        }\n\n        private async Task TimerTick(object data)\n        {\n            try\n            {\n                await ProcessTimerTick(data);\n            }\n            catch (Exception exc)\n            {\n                this.tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task TimerTickAdvanced(object data)\n        {\n            try\n            {\n                var state = (Tuple<string, object>)data;\n                var operation = state.Item1;\n                var name = state.Item2;\n\n                await ProcessTimerTick(name);\n\n                if (operation == \"update_period\")\n                {\n                    var newPeriod = TimeSpan.FromSeconds(100);\n                    timer.Change(newPeriod, newPeriod);\n                }\n                else if (operation == \"dispose_timer\")\n                {\n                    await StopTimer((string)name);\n                }\n            }\n            catch (Exception exc)\n            {\n                this.tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task ProcessTimerTick(object data)\n        {\n            string step = \"TimerTick\";\n            LogStatus(step);\n            // make sure we run in the right activation context.\n            CheckRuntimeContext(step);\n\n            string name = (string)data;\n            if (name != this.timerName)\n            {\n                throw new ArgumentException(string.Format(\"Wrong timer name: Expected={0} Actual={1}\", this.timerName, name));\n            }\n\n            ISimpleGrain grain = GrainFactory.GetGrain<ISimpleGrain>(0, SimpleGrain.SimpleGrainNamePrefix);\n\n            LogStatus(\"Before grain call #1\");\n            await grain.SetA(tickCount);\n            step = \"After grain call #1\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before Delay\");\n            await Task.Delay(TimeSpan.FromSeconds(1));\n            step = \"After Delay\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before grain call #2\");\n            await grain.SetB(tickCount);\n            step = \"After grain call #2\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before grain call #3\");\n            int res = await grain.GetAxB();\n            step = \"After grain call #3 - Result = \" + res;\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            tickCount++;\n        }\n\n        private void CheckRuntimeContext(string what)\n        {\n            if (RuntimeContext.Current == null\n                || !RuntimeContext.Current.Equals(context))\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected activation context: Expected={1} Actual={2}\",\n                                  what, context, RuntimeContext.Current));\n            }\n            if (TaskScheduler.Current.Equals(activationTaskScheduler) && TaskScheduler.Current is ActivationTaskScheduler)\n            {\n                // Everything is as expected\n            }\n            else\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected TaskScheduler.Current context: Expected={1} Actual={2}\",\n                                  what, activationTaskScheduler, TaskScheduler.Current));\n            }\n        }\n\n        private void LogStatus(string what)\n        {\n            logger.LogInformation(\n                \"{TimerName} Tick # {TickCount} - {Step} - RuntimeContext.Current={RuntimeContext} TaskScheduler.Current={TaskScheduler} CurrentWorkerThread={Thread}\",\n                timerName,\n                tickCount,\n                what,\n                RuntimeContext.Current,\n                TaskScheduler.Current,\n                Thread.CurrentThread.Name);\n        }\n    }\n\n    public class NonReentrantTimerCallGrain : Grain, INonReentrantTimerCallGrain\n    {\n        private readonly Dictionary<string, IGrainTimer> _timers = [];\n        private int _tickCount;\n        private Exception _tickException;\n        private IGrainContext _context;\n        private TaskScheduler _activationTaskScheduler;\n        private Guid _tickId;\n\n        private readonly ILogger _logger;\n\n        public NonReentrantTimerCallGrain(ILoggerFactory loggerFactory)\n        {\n            _logger = loggerFactory.CreateLogger($\"{GetType().Name}-{IdentityString}\");\n        }\n\n        public Task<int> GetTickCount() => Task.FromResult(_tickCount);\n        public Task<Exception> GetException() => Task.FromResult(_tickException);\n\n        public async Task ExternalTick(string name)\n        {\n            await ProcessTimerTick(name, CancellationToken.None);\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _context = RuntimeContext.Current;\n            _activationTaskScheduler = TaskScheduler.Current;\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay, bool keepAlive)\n        {\n            _logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (_timers.TryGetValue(name, out var timer))\n            {\n                // Make the timer fire again after the specified delay.\n                timer.Change(delay, Timeout.InfiniteTimeSpan);\n            }\n            else\n            {\n                _timers[name] = this.RegisterGrainTimer(TimerTick, name, new() { DueTime = delay, Period = Timeout.InfiniteTimeSpan, KeepAlive = keepAlive }); // One shot timer\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string name)\n        {\n            _logger.LogInformation(\"StopTimer Name={Name}\", name);\n\n            if (!_timers.Remove(name, out var timer))\n            {\n                throw new ArgumentException($\"Could not find a timer with name {name}.\");\n            }\n\n            timer.Dispose();\n            return Task.CompletedTask;\n        }\n\n        private async Task TimerTick(object data, CancellationToken cancellationToken)\n        {\n            try\n            {\n                await ProcessTimerTick(data, cancellationToken);\n            }\n            catch (Exception exc)\n            {\n                _tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task ProcessTimerTick(object data, CancellationToken cancellationToken)\n        {\n            var timerName = (string)data;\n            string step = \"TimerTick\";\n            CheckReentrancy(step, Guid.Empty);\n            var expectedTickId = _tickId = Guid.NewGuid();\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            ISimpleGrain grain = GrainFactory.GetGrain<ISimpleGrain>(0, SimpleGrain.SimpleGrainNamePrefix);\n\n            LogStatus(\"Before grain call #1\", timerName);\n            await grain.SetA(_tickCount);\n            step = \"After grain call #1\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before Delay\", timerName);\n            await Task.Delay(TimeSpan.FromSeconds(1));\n            step = \"After Delay\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before grain call #2\", timerName);\n            await grain.SetB(_tickCount);\n            step = \"After grain call #2\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before grain call #3\", timerName);\n            int res = await grain.GetAxB();\n            step = \"After grain call #3 - Result = \" + res;\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            _tickCount++;\n            _tickId = Guid.Empty;\n        }\n\n        private void CheckRuntimeContext(string what)\n        {\n            if (RuntimeContext.Current == null\n                || !RuntimeContext.Current.Equals(_context))\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected activation context: Expected={1} Actual={2}\",\n                                  what, _context, RuntimeContext.Current));\n            }\n            if (TaskScheduler.Current.Equals(_activationTaskScheduler) && TaskScheduler.Current is ActivationTaskScheduler)\n            {\n                // Everything is as expected\n            }\n            else\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected TaskScheduler.Current context: Expected={1} Actual={2}\",\n                                  what, _activationTaskScheduler, TaskScheduler.Current));\n            }\n        }\n\n        private void CheckReentrancy(string what, Guid expected)\n        {\n            if (_tickId != expected)\n            {\n                throw new InvalidOperationException(\n                    $\"{what} in timer callback with unexpected interleaving: Expected={expected} Actual={_tickId}\");\n            }\n        }\n\n        private void LogStatus(string what, string timerName)\n        {\n            _logger.LogInformation(\n                \"{TimerName} Tick # {TickCount} - {Step} - RuntimeContext.Current={RuntimeContext} TaskScheduler.Current={TaskScheduler} CurrentWorkerThread={Thread}\",\n                timerName,\n                _tickCount,\n                what,\n                RuntimeContext.Current,\n                TaskScheduler.Current,\n                Thread.CurrentThread.Name);\n        }\n    }\n\n    public class TimerRequestGrain : Grain, ITimerRequestGrain\n    {\n        private TaskCompletionSource<int> completionSource;\n        private List<TaskCompletionSource<(object, CancellationToken)>> _allTimerCallsTasks;\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(this.RuntimeIdentity);\n        }\n\n        public async Task StartAndWaitTimerTick(TimeSpan dueTime)\n        {\n            this.completionSource = new TaskCompletionSource<int>();\n            using var timer = this.RegisterGrainTimer(TimerTick, new() { DueTime = dueTime, Period = Timeout.InfiniteTimeSpan, Interleave = true });\n            await this.completionSource.Task;\n        }\n\n        public Task StartStuckTimer(TimeSpan dueTime)\n        {\n            this.completionSource = new TaskCompletionSource<int>();\n            var timer = this.RegisterGrainTimer(StuckTimerTick, new() { DueTime = dueTime, Period = TimeSpan.FromSeconds(1), Interleave = true });\n            return Task.CompletedTask;\n        }\n\n        private Task TimerTick()\n        {\n            this.completionSource.TrySetResult(1);\n            return Task.CompletedTask;\n        }\n\n        private async Task StuckTimerTick(CancellationToken cancellationToken)\n        {\n            await completionSource.Task;\n        }\n\n        public Task<int> TestAllTimerOverloads()\n        {\n            var tasks = new List<TaskCompletionSource<(object, CancellationToken)>>();\n            var timers = new List<IGrainTimer>();\n\n            // protected IGrainTimer RegisterGrainTimer(Func<Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(() =>\n            {\n                tasks[0].TrySetResult((\"NONE\", CancellationToken.None));\n                return Task.CompletedTask;\n            }, new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer(Func<Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(() =>\n            {\n                tasks[1].TrySetResult((\"NONE\", CancellationToken.None));\n                return Task.CompletedTask;\n            }, TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, Task> callback, TState state, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(state =>\n            {\n                tasks[2].TrySetResult((state, CancellationToken.None));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(state =>\n            {\n                tasks[3].TrySetResult((state, CancellationToken.None));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // With CancellationToken\n            // protected IGrainTimer RegisterGrainTimer(Func<CancellationToken, Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(ct =>\n            {\n                tasks[4].TrySetResult((\"NONE\", ct));\n                return Task.CompletedTask;\n            }, new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer(Func<CancellationToken, Task> callback, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(ct =>\n            {\n                tasks[5].TrySetResult((\"NONE\", ct));\n                return Task.CompletedTask;\n            }, TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // protected internal IGrainTimer RegisterGrainTimer<TState>(Func<TState, CancellationToken, Task> callback, TState state, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer((state, ct) =>\n            {\n                tasks[6].TrySetResult((state, ct));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, CancellationToken, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer((state, ct) =>\n            {\n                tasks[7].TrySetResult((state, ct));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n            _allTimerCallsTasks = tasks;\n            return Task.FromResult(_allTimerCallsTasks.Count);\n        }\n\n        public Task<int> PollCompletedTimers() => Task.FromResult(_allTimerCallsTasks.Count(c => c.Task.IsCompleted));\n        public async Task TestCompletedTimerResults()\n        {\n            var countWithState = 0;\n            var countWithCancellation = 0;\n\n            foreach (var task in _allTimerCallsTasks.Select(t => t.Task))\n            {\n                var (state, ct) = await task;\n                var stateString  = Assert.IsType<string>(state);\n                var hasState = string.Equals(\"STATE\", stateString, StringComparison.Ordinal);\n                if (hasState)\n                {\n                    countWithState++;\n                }\n\n                Assert.True(hasState || string.Equals(\"NONE\", stateString, StringComparison.Ordinal));\n                if (ct.CanBeCanceled)\n                {\n                    countWithCancellation++;\n                }\n            }\n\n            Assert.Equal(4, countWithState);\n            Assert.Equal(4, countWithCancellation);\n        }\n    }\n\n    public class PocoTimerGrain : IGrainBase, IPocoTimerGrain\n    {\n        private bool deactivating;\n        private int counter = 0;\n        private Dictionary<string, IDisposable> allTimers;\n        private IDisposable defaultTimer;\n        private static readonly TimeSpan period = TimeSpan.FromMilliseconds(100);\n        private readonly string DefaultTimerName = \"DEFAULT TIMER\";\n        private IGrainContext context;\n\n        private readonly ILogger logger;\n\n        public IGrainContext GrainContext { get; }\n\n        public PocoTimerGrain(ILoggerFactory loggerFactory, IGrainContext context)\n        {\n            GrainContext = context;\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{context.GrainId}\");\n        }\n\n        public Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ThrowIfDeactivating();\n            context = RuntimeContext.Current;\n            defaultTimer = this.RegisterGrainTimer(Tick, DefaultTimerName, period, period);\n            allTimers = new Dictionary<string, IDisposable>();\n            return Task.CompletedTask;\n        }\n\n        public Task StopDefaultTimer()\n        {\n            ThrowIfDeactivating();\n            defaultTimer.Dispose();\n            return Task.CompletedTask;\n        }\n\n        private Task Tick(object data)\n        {\n            counter++;\n            logger.LogInformation(\n                \"{Data} Tick # {Counter} RuntimeContext = {RuntimeContext}\",\n                data,\n                counter,\n                RuntimeContext.Current);\n\n            // make sure we run in the right activation context.\n            if (!Equals(context, RuntimeContext.Current))\n                logger.LogError((int)ErrorCode.Runtime_Error_100146, \"Grain not running in the right activation context\");\n\n            string name = (string)data;\n            IDisposable timer;\n            if (name == DefaultTimerName)\n            {\n                timer = defaultTimer;\n            }\n            else\n            {\n                timer = allTimers[(string)data];\n            }\n            if (timer == null)\n                logger.LogError((int)ErrorCode.Runtime_Error_100146, \"Timer is null\");\n            if (timer != null && counter > 10000)\n            {\n                // do not let orphan timers ticking for long periods\n                timer.Dispose();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task<TimeSpan> GetTimerPeriod()\n        {\n            return Task.FromResult(period);\n        }\n\n        public Task<int> GetCounter()\n        {\n            ThrowIfDeactivating();\n            return Task.FromResult(counter);\n        }\n        public Task SetCounter(int value)\n        {\n            ThrowIfDeactivating();\n            lock (this)\n            {\n                counter = value;\n            }\n            return Task.CompletedTask;\n        }\n        public Task StartTimer(string timerName)\n        {\n            ThrowIfDeactivating();\n            IDisposable timer = this.RegisterGrainTimer(Tick, timerName, TimeSpan.Zero, period);\n            allTimers.Add(timerName, timer);\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string timerName)\n        {\n            ThrowIfDeactivating();\n            IDisposable timer = allTimers[timerName];\n            timer.Dispose();\n            return Task.CompletedTask;\n        }\n\n        public Task LongWait(TimeSpan time)\n        {\n            ThrowIfDeactivating();\n            Thread.Sleep(time);\n            return Task.CompletedTask;\n        }\n\n        public Task Deactivate()\n        {\n            deactivating = true;\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        private void ThrowIfDeactivating()\n        {\n            if (deactivating) throw new InvalidOperationException(\"This activation is deactivating\");\n        }\n    }\n\n    public class PocoTimerCallGrain : IGrainBase, IPocoTimerCallGrain\n    {\n        private int tickCount;\n        private Exception tickException;\n        private IGrainTimer timer;\n        private string timerName;\n        private IGrainContext context;\n        private TaskScheduler activationTaskScheduler;\n\n        private readonly ILogger logger;\n        private readonly IGrainFactory _grainFactory;\n\n        public IGrainContext GrainContext { get; }\n\n        public PocoTimerCallGrain(ILoggerFactory loggerFactory, IGrainContext grainContext, IGrainFactory grainFactory)\n        {\n            GrainContext = grainContext;\n            _grainFactory = grainFactory;\n            this.logger = loggerFactory.CreateLogger($\"{this.GetType().Name}-{this.GrainContext.GrainId}\");\n        }\n\n        public Task<int> GetTickCount() { return Task.FromResult(tickCount); }\n        public Task<Exception> GetException() { return Task.FromResult(tickException); }\n\n        public Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            context = RuntimeContext.Current;\n            activationTaskScheduler = TaskScheduler.Current;\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay)\n        {\n            logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (timer is not null) throw new InvalidOperationException(\"Expected timer to be null\");\n            this.timer = this.RegisterGrainTimer(TimerTick, name, new(delay, Timeout.InfiniteTimeSpan)); // One shot timer\n            this.timerName = name;\n\n            return Task.CompletedTask;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay, string operationType)\n        {\n            logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (timer is not null) throw new InvalidOperationException(\"Expected timer to be null\");\n            var state = Tuple.Create<string, object>(operationType, name);\n            this.timer = this.RegisterGrainTimer(TimerTickAdvanced, state, delay, Timeout.InfiniteTimeSpan); // One shot timer\n            this.timerName = name;\n\n            return Task.CompletedTask;\n        }\n\n        public Task RestartTimer(string name, TimeSpan delay)\n        {\n            logger.LogInformation(\"RestartTimer Name={Name} Delay={Delay}\", name, delay);\n            this.timerName = name;\n            timer.Change(delay, Timeout.InfiniteTimeSpan);\n\n            return Task.CompletedTask;\n        }\n\n        public Task RestartTimer(string name, TimeSpan delay, TimeSpan period)\n        {\n            logger.LogInformation(\"RestartTimer Name={Name} Delay={Delay} Period={Period}\", name, delay, period);\n            this.timerName = name;\n            timer.Change(delay, period);\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string name)\n        {\n            logger.LogInformation(\"StopTimer Name={Name}\", name);\n            if (name != this.timerName)\n            {\n                throw new ArgumentException($\"Wrong timer name: Expected={this.timerName} Actual={name}\");\n            }\n\n            timer.Dispose();\n            timer = null;\n            timerName = null;\n            return Task.CompletedTask;\n        }\n\n        public async Task RunSelfDisposingTimer()\n        {\n            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n            var timer = new IGrainTimer[1];\n            timer[0] = this.RegisterGrainTimer(async (ct) =>\n            {\n                try\n                {\n                    Assert.False(ct.IsCancellationRequested);\n                    Assert.NotNull(timer[0]);\n                    timer[0].Dispose();\n                    Assert.True(ct.IsCancellationRequested);\n                    await Task.Delay(100);\n                    tcs.TrySetResult();\n                }\n                catch (Exception ex)\n                {\n                    tcs.TrySetException(ex);\n                }\n            },\n            new GrainTimerCreationOptions(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n                Interleave = true\n            });\n\n            await tcs.Task;\n        }\n\n        private async Task TimerTick(object data)\n        {\n            try\n            {\n                await ProcessTimerTick(data);\n            }\n            catch (Exception exc)\n            {\n                this.tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task TimerTickAdvanced(object data)\n        {\n            try\n            {\n                var state = (Tuple<string, object>)data;\n                var operation = state.Item1;\n                var name = state.Item2;\n\n                await ProcessTimerTick(name);\n\n                if (operation == \"update_period\")\n                {\n                    var newPeriod = TimeSpan.FromSeconds(100);\n                    timer.Change(newPeriod, newPeriod);\n                }\n                else if (operation == \"dispose_timer\")\n                {\n                    await StopTimer((string)name);\n                }\n            }\n            catch (Exception exc)\n            {\n                this.tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task ProcessTimerTick(object data)\n        {\n            string step = \"TimerTick\";\n            LogStatus(step);\n            // make sure we run in the right activation context.\n            CheckRuntimeContext(step);\n\n            string name = (string)data;\n            if (name != this.timerName)\n            {\n                throw new ArgumentException(string.Format(\"Wrong timer name: Expected={0} Actual={1}\", this.timerName, name));\n            }\n\n            ISimpleGrain grain = _grainFactory.GetGrain<ISimpleGrain>(0, SimpleGrain.SimpleGrainNamePrefix);\n\n            LogStatus(\"Before grain call #1\");\n            await grain.SetA(tickCount);\n            step = \"After grain call #1\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before Delay\");\n            await Task.Delay(TimeSpan.FromSeconds(1));\n            step = \"After Delay\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before grain call #2\");\n            await grain.SetB(tickCount);\n            step = \"After grain call #2\";\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            LogStatus(\"Before grain call #3\");\n            int res = await grain.GetAxB();\n            step = \"After grain call #3 - Result = \" + res;\n            LogStatus(step);\n            CheckRuntimeContext(step);\n\n            tickCount++;\n        }\n\n        private void CheckRuntimeContext(string what)\n        {\n            if (RuntimeContext.Current == null\n                || !RuntimeContext.Current.Equals(context))\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected activation context: Expected={1} Actual={2}\",\n                                  what, context, RuntimeContext.Current));\n            }\n            if (TaskScheduler.Current.Equals(activationTaskScheduler) && TaskScheduler.Current is ActivationTaskScheduler)\n            {\n                // Everything is as expected\n            }\n            else\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected TaskScheduler.Current context: Expected={1} Actual={2}\",\n                                  what, activationTaskScheduler, TaskScheduler.Current));\n            }\n        }\n\n        private void LogStatus(string what)\n        {\n            logger.LogInformation(\n                \"{TimerName} Tick # {TickCount} - {Step} - RuntimeContext.Current={RuntimeContext} TaskScheduler.Current={TaskScheduler} CurrentWorkerThread={Thread}\",\n                timerName,\n                tickCount,\n                what,\n                RuntimeContext.Current,\n                TaskScheduler.Current,\n                Thread.CurrentThread.Name);\n        }\n    }\n\n    public class PocoTimerRequestGrain : IGrainBase, IPocoTimerRequestGrain\n    {\n        private TaskCompletionSource<int> completionSource;\n        private List<TaskCompletionSource<(object, CancellationToken)>> _allTimerCallsTasks;\n\n        public IGrainContext GrainContext { get; }\n\n        public PocoTimerRequestGrain(IGrainContext grainContext)\n        {\n            GrainContext = grainContext;\n        }\n\n        public Task<string> GetRuntimeInstanceId()\n        {\n            return Task.FromResult(GrainContext.GrainId.ToString());\n        }\n\n        public async Task StartAndWaitTimerTick(TimeSpan dueTime)\n        {\n            this.completionSource = new TaskCompletionSource<int>();\n            using var timer = this.RegisterGrainTimer(TimerTick, new() { DueTime = dueTime, Period = Timeout.InfiniteTimeSpan, Interleave = true });\n            await this.completionSource.Task;\n        }\n\n        public Task StartStuckTimer(TimeSpan dueTime)\n        {\n            this.completionSource = new TaskCompletionSource<int>();\n            var timer = this.RegisterGrainTimer(StuckTimerTick, new() { DueTime = dueTime, Period = TimeSpan.FromSeconds(1), Interleave = true });\n            return Task.CompletedTask;\n        }\n\n        private Task TimerTick()\n        {\n            this.completionSource.TrySetResult(1);\n            return Task.CompletedTask;\n        }\n\n        private async Task StuckTimerTick(CancellationToken cancellationToken)\n        {\n            await completionSource.Task;\n        }\n\n        public Task<int> TestAllTimerOverloads()\n        {\n            var tasks = new List<TaskCompletionSource<(object, CancellationToken)>>();\n            var timers = new List<IGrainTimer>();\n\n            // protected IGrainTimer RegisterGrainTimer(Func<Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(() =>\n            {\n                tasks[0].TrySetResult((\"NONE\", CancellationToken.None));\n                return Task.CompletedTask;\n            }, new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer(Func<Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(() =>\n            {\n                tasks[1].TrySetResult((\"NONE\", CancellationToken.None));\n                return Task.CompletedTask;\n            }, TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, Task> callback, TState state, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(state =>\n            {\n                tasks[2].TrySetResult((state, CancellationToken.None));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(state =>\n            {\n                tasks[3].TrySetResult((state, CancellationToken.None));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // With CancellationToken\n            // protected IGrainTimer RegisterGrainTimer(Func<CancellationToken, Task> callback, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(ct =>\n            {\n                tasks[4].TrySetResult((\"NONE\", ct));\n                return Task.CompletedTask;\n            }, new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer(Func<CancellationToken, Task> callback, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer(ct =>\n            {\n                tasks[5].TrySetResult((\"NONE\", ct));\n                return Task.CompletedTask;\n            }, TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n\n            // protected internal IGrainTimer RegisterGrainTimer<TState>(Func<TState, CancellationToken, Task> callback, TState state, GrainTimerCreationOptions options)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer((state, ct) =>\n            {\n                tasks[6].TrySetResult((state, ct));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            new GrainTimerCreationOptions(TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)) { Interleave = true }));\n\n            // protected IGrainTimer RegisterGrainTimer<TState>(Func<TState, CancellationToken, Task> callback, TState state, TimeSpan dueTime, TimeSpan period)\n            tasks.Add(new());\n            timers.Add(this.RegisterGrainTimer((state, ct) =>\n            {\n                tasks[7].TrySetResult((state, ct));\n                return Task.CompletedTask;\n            },\n            \"STATE\",\n            TimeSpan.FromMilliseconds(25), TimeSpan.FromSeconds(10)));\n            _allTimerCallsTasks = tasks;\n            return Task.FromResult(_allTimerCallsTasks.Count);\n        }\n\n        public Task<int> PollCompletedTimers() => Task.FromResult(_allTimerCallsTasks.Count(c => c.Task.IsCompleted));\n        public async Task TestCompletedTimerResults()\n        {\n            var countWithState = 0;\n            var countWithCancellation = 0;\n\n            foreach (var task in _allTimerCallsTasks.Select(t => t.Task))\n            {\n                var (state, ct) = await task;\n                var stateString  = Assert.IsType<string>(state);\n                var hasState = string.Equals(\"STATE\", stateString, StringComparison.Ordinal);\n                if (hasState)\n                {\n                    countWithState++;\n                }\n\n                Assert.True(hasState || string.Equals(\"NONE\", stateString, StringComparison.Ordinal));\n                if (ct.CanBeCanceled)\n                {\n                    countWithCancellation++;\n                }\n            }\n\n            Assert.Equal(4, countWithState);\n            Assert.Equal(4, countWithCancellation);\n        }\n    }\n\n    public class PocoNonReentrantTimerCallGrain : IGrainBase, IPocoNonReentrantTimerCallGrain\n    {\n        private readonly Dictionary<string, IGrainTimer> _timers = [];\n        private int _tickCount;\n        private Exception _tickException;\n        private IGrainContext _context;\n        private TaskScheduler _activationTaskScheduler;\n        private Guid _tickId;\n\n        private readonly ILogger _logger;\n        private readonly IGrainFactory _grainFactory;\n\n        public IGrainContext GrainContext { get; }\n\n        public PocoNonReentrantTimerCallGrain(ILoggerFactory loggerFactory, IGrainContext grainContext, IGrainFactory grainFactory)\n        {\n            GrainContext = grainContext;\n            _grainFactory = grainFactory;\n            _logger = loggerFactory.CreateLogger($\"{GetType().Name}-{GrainContext.GrainId}\");\n        }\n\n        public Task<int> GetTickCount() => Task.FromResult(_tickCount);\n        public Task<Exception> GetException() => Task.FromResult(_tickException);\n\n        public async Task ExternalTick(string name)\n        {\n            await ProcessTimerTick(name, CancellationToken.None);\n        }\n\n        public Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _context = RuntimeContext.Current;\n            _activationTaskScheduler = TaskScheduler.Current;\n            return Task.CompletedTask;\n        }\n\n        public async Task RunSelfDisposingTimer()\n        {\n            var tcs = new TaskCompletionSource();\n            var timer = new IGrainTimer[1];\n            timer[0] = this.RegisterGrainTimer(async () =>\n            {\n                try\n                {\n                    Assert.NotNull(timer[0]);\n                    timer[0].Dispose();\n                    tcs.TrySetResult();\n                    await Task.Delay(100);\n                }\n                catch (Exception ex)\n                {\n                    tcs.TrySetException(ex);\n                }\n            },\n            new GrainTimerCreationOptions(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n                Interleave = true\n            });\n\n            await tcs.Task;\n        }\n\n        public Task StartTimer(string name, TimeSpan delay, bool keepAlive)\n        {\n            _logger.LogInformation(\"StartTimer Name={Name} Delay={Delay}\", name, delay);\n            if (_timers.TryGetValue(name, out var timer))\n            {\n                // Make the timer fire again after the specified delay.\n                timer.Change(delay, Timeout.InfiniteTimeSpan);\n            }\n            else\n            {\n                _timers[name] = this.RegisterGrainTimer(TimerTick, name, new() { DueTime = delay, Period = Timeout.InfiniteTimeSpan, KeepAlive = keepAlive }); // One shot timer\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopTimer(string name)\n        {\n            _logger.LogInformation(\"StopTimer Name={Name}\", name);\n\n            if (!_timers.Remove(name, out var timer))\n            {\n                throw new ArgumentException($\"Could not find a timer with name {name}.\");\n            }\n\n            timer.Dispose();\n            return Task.CompletedTask;\n        }\n\n        private async Task TimerTick(object data, CancellationToken cancellationToken)\n        {\n            try\n            {\n                await ProcessTimerTick(data, cancellationToken);\n            }\n            catch (Exception exc)\n            {\n                _tickException = exc;\n                throw;\n            }\n        }\n\n        private async Task ProcessTimerTick(object data, CancellationToken cancellationToken)\n        {\n            var timerName = (string)data;\n            string step = \"TimerTick\";\n            CheckReentrancy(step, Guid.Empty);\n            var expectedTickId = _tickId = Guid.NewGuid();\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            ISimpleGrain grain = _grainFactory.GetGrain<ISimpleGrain>(0, SimpleGrain.SimpleGrainNamePrefix);\n\n            LogStatus(\"Before grain call #1\", timerName);\n            await grain.SetA(_tickCount);\n            step = \"After grain call #1\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before Delay\", timerName);\n            await Task.Delay(TimeSpan.FromSeconds(1));\n            step = \"After Delay\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before grain call #2\", timerName);\n            await grain.SetB(_tickCount);\n            step = \"After grain call #2\";\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            LogStatus(\"Before grain call #3\", timerName);\n            int res = await grain.GetAxB();\n            step = \"After grain call #3 - Result = \" + res;\n            LogStatus(step, timerName);\n            CheckRuntimeContext(step);\n            CheckReentrancy(step, expectedTickId);\n\n            _tickCount++;\n            _tickId = Guid.Empty;\n        }\n\n        private void CheckRuntimeContext(string what)\n        {\n            if (RuntimeContext.Current == null\n                || !RuntimeContext.Current.Equals(_context))\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected activation context: Expected={1} Actual={2}\",\n                                  what, _context, RuntimeContext.Current));\n            }\n            if (TaskScheduler.Current.Equals(_activationTaskScheduler) && TaskScheduler.Current is ActivationTaskScheduler)\n            {\n                // Everything is as expected\n            }\n            else\n            {\n                throw new InvalidOperationException(\n                    string.Format(\"{0} in timer callback with unexpected TaskScheduler.Current context: Expected={1} Actual={2}\",\n                                  what, _activationTaskScheduler, TaskScheduler.Current));\n            }\n        }\n\n        private void CheckReentrancy(string what, Guid expected)\n        {\n            if (_tickId != expected)\n            {\n                throw new InvalidOperationException(\n                    $\"{what} in timer callback with unexpected interleaving: Expected={expected} Actual={_tickId}\");\n            }\n        }\n\n        private void LogStatus(string what, string timerName)\n        {\n            _logger.LogInformation(\n                \"{TimerName} Tick # {TickCount} - {Step} - RuntimeContext.Current={RuntimeContext} TaskScheduler.Current={TaskScheduler} CurrentWorkerThread={Thread}\",\n                timerName,\n                _tickCount,\n                what,\n                RuntimeContext.Current,\n                TaskScheduler.Current,\n                Thread.CurrentThread.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestVersionGrains/IVersionTestGrain.cs",
    "content": "using Orleans.CodeGeneration;\n\nnamespace TestVersionGrainInterfaces\n{\n#if VERSION_1\n    [Version(1)]\n#else\n    [Version(2)]\n#endif\n    public interface IVersionUpgradeTestGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetVersion();\n\n        Task<int> ProxyGetVersion(IVersionUpgradeTestGrain other);\n\n        Task<bool> LongRunningTask(TimeSpan taskTime);\n    }\n\n#if VERSION_1\n    [Version(1)]\n#else\n    [Version(2)]\n#endif\n    public interface IVersionPlacementTestGrain : IGrainWithIntegerKey\n    {\n        Task<int> GetVersion();\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestVersionGrains/Program.cs",
    "content": "using Orleans.TestingHost;\n\nnamespace TestVersionGrains\n{\n    public static class Program \n    {\n        public static async Task Main(string[] args) => await StandaloneSiloHost.Main(args);\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestVersionGrains/TestVersionGrains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n    <PublishRoot>bin\\$(Configuration)\\publish\\</PublishRoot>\n    <PublishDir>$(PublishRoot)$(TargetFramework)</PublishDir>\n    <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\n  </PropertyGroup>\n\n  <!-- Declare that this is version 1 of our code. This is used for #ifdefs in the code -->\n  <PropertyGroup>\n    <DefineConstants>$(DefineConstants);VERSION_1</DefineConstants>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <ProjectReference Update=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Update=\"$(SourceRoot)src\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrains\\TestGrains.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n  </ItemGroup>\n\n  <Target Name=\"PostBuildPublish\" AfterTargets=\"Build\">\n    <CallTarget Targets=\"Publish\" Condition=\"'$(TargetFramework)' != '' and '$(DesignTimeBuild)' == ''\" />\n  </Target>\n</Project>\n"
  },
  {
    "path": "test/Grains/TestVersionGrains/VersionGrainsSiloBuilderConfigurator.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace TestVersionGrains\n{\n    public class VersionGrainsSiloBuilderConfigurator : IHostConfigurator\n    {\n        public void Configure(IHostBuilder hostBuilder)\n        {\n            var cfg = hostBuilder.GetConfiguration();\n            var siloCount = int.Parse(cfg[\"SiloCount\"]);\n            hostBuilder.UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder.Configure<SiloMessagingOptions>(options => options.AssumeHomogenousSilosForTesting = false);\n                siloBuilder.Configure<GrainVersioningOptions>(options =>\n                {\n                    options.DefaultCompatibilityStrategy = cfg[\"CompatibilityStrategy\"];\n                    options.DefaultVersionSelectorStrategy = cfg[\"VersionSelectorStrategy\"];\n                });\n\n                siloBuilder.ConfigureServices(ConfigureServices)\n                    .AddMemoryGrainStorageAsDefault();\n            });\n        }\n\n        private void ConfigureServices(IServiceCollection services)\n        {\n            services.AddPlacementDirector<VersionAwarePlacementStrategy, VersionAwarePlacementDirector>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestVersionGrains/VersionTestGrain.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Placement;\nusing TestVersionGrainInterfaces;\nusing UnitTests.GrainInterfaces;\n\nnamespace TestVersionGrains\n{\n    [RandomPlacement]\n    public class VersionUpgradeTestGrain : Grain, IVersionUpgradeTestGrain\n    {\n        private const int Version =\n#if VERSION_1\n            1;\n#else\n            2;\n#endif\n\n        private readonly ILogger _logger;\n\n        public VersionUpgradeTestGrain(ILogger<VersionUpgradeTestGrain> logger)\n        {\n            logger.LogInformation(\"Creating version '{Version}'.\", Version);\n            _logger = logger;\n        }\n\n        public Task<int> GetVersion()\n        {\n            _logger.LogInformation(\"Version '{Version}' {GrainId} responding to GetVersion().\", Version, this.GetGrainId());\n            return Task.FromResult(Version);\n        }\n\n        public async Task<int> ProxyGetVersion(IVersionUpgradeTestGrain other)\n        {\n            _logger.LogInformation(\"Version '{Version}' {GrainId} calling {OtherGrainId}.\", Version, this.GetGrainId(), other.GetGrainId());\n            var otherVersion = await other.GetVersion();\n            _logger.LogInformation(\"{OtherGrainId} returned '{OtherVersion}'.\", other.GetGrainId(), otherVersion);\n            return otherVersion;\n        }\n\n        public async Task<bool> LongRunningTask(TimeSpan taskTime)\n        {\n            await Task.Delay(taskTime);\n            return true;\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Activating version '{Version}'.\", Version);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Deactivating version '{Version}'.\", Version);\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n    [VersionAwareStrategy]\n    public class VersionPlacementTestGrain : Grain, IVersionPlacementTestGrain\n    {\n        private const int Version =\n#if VERSION_1\n            1;\n#else\n            2;\n#endif\n\n        private readonly ILogger _logger;\n\n        public VersionPlacementTestGrain(ILogger<VersionPlacementTestGrain> logger)\n        {\n            logger.LogInformation(\"Creating version '{Version}'.\", Version);\n            _logger = logger;\n        }\n\n        public Task<int> GetVersion()\n        {\n            _logger.LogInformation(\"Version '{Version}' {GrainId} responding to GetVersion().\", Version, this.GetGrainId());\n            return Task.FromResult(Version);\n        }\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Activating version '{Version}'.\", Version);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _logger.LogInformation(\"Deactivating version '{Version}'.\", Version);\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Grains/TestVersionGrains2/TestVersionGrains2.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>TestVersionGrains</RootNamespace>\n    <AssemblyName>TestVersionGrains</AssemblyName>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n    <PublishRoot>bin\\$(Configuration)\\publish\\</PublishRoot>\n    <PublishDir>$(PublishRoot)$(TargetFramework)</PublishDir>\n    <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>\n    <SourceDir>$(MSBuildThisFileDirectory)../TestVersionGrains/</SourceDir>\n  </PropertyGroup>\n\n  <!-- Declare that this is version 2 of our code. This is used for #ifdefs in the code -->\n  <PropertyGroup>\n    <DefineConstants>$(DefineConstants);VERSION_2</DefineConstants>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <ProjectReference Update=\"$(SourceRoot)src\\Orleans.Core.Abstractions\\Orleans.Core.Abstractions.csproj\" />\n    <ProjectReference Update=\"$(SourceRoot)src\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrains\\TestGrains.csproj\" />\n  </ItemGroup>\n\n  <!-- Link all .cs files from the TestVersionGrains project, since the only difference between the two is that this defines a different version constant -->\n  <ItemGroup>\n    <Compile Include=\"$(SourceDir)/**/*.cs\" Exclude=\"$(SourceDir)obj/**/*.cs;$(SourceDir)bin/**/*.cs\" />\n  </ItemGroup>\n\n  <Target Name=\"PostBuildPublish\" AfterTargets=\"Build\">\n    <CallTarget Targets=\"Publish\" Condition=\"'$(TargetFramework)' != '' and '$(DesignTimeBuild)' == ''\" />\n  </Target>\n</Project>\n"
  },
  {
    "path": "test/Misc/TestSerializerExternalModels/IsExternalInit.cs",
    "content": "namespace System.Runtime.CompilerServices;\n\n// required for record serialization support for downlevel\ninternal static class IsExternalInit {}\n"
  },
  {
    "path": "test/Misc/TestSerializerExternalModels/Models.cs",
    "content": "using Orleans;\n\nnamespace UnitTests.SerializerExternalModels;\n\n[GenerateSerializer]\npublic record struct Person2ExternalStruct(int Age, string Name)\n{\n    [Id(0)]\n    public string FavouriteColor { get; set; }\n\n    [Id(1)]\n    public string StarSign { get; set; }\n}\n\n[GenerateSerializer]\npublic record struct GenericPersonExternalStruct<T>(T CtorParam, string Name)\n{\n    [Id(0)]\n    public T BodyParam { get; set; }\n\n    [Id(1)]\n    public string StarSign { get; set; }\n}\n\n[GenerateSerializer]\npublic readonly record struct ReadonlyGenericPersonExternalStruct<T>(T CtorParam, string Name)\n{\n    [Id(0)]\n    public T BodyParam { get; init; }\n\n    [Id(1)]\n    public string StarSign { get; init; }\n}\n\n#if NET6_0_OR_GREATER\n[GenerateSerializer]\npublic record Person2External(int Age, string Name)\n{\n    [Id(0)]\n    public string FavouriteColor { get; set; }\n\n    [Id(1)]\n    public string StarSign { get; set; }\n}\n\n[GenerateSerializer]\npublic record GenericPersonExternal<T>(T CtorParam, string Name)\n{\n    [Id(0)]\n    public T BodyParam { get; set; }\n\n    [Id(1)]\n    public string StarSign { get; set; }\n}\n#endif\n"
  },
  {
    "path": "test/Misc/TestSerializerExternalModels/TestSerializerExternalModels.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests.SerializerExternalModels</RootNamespace>\n    <AssemblyName>SerializerExternalModels</AssemblyName>\n    <TargetFrameworks>$(TestTargetFrameworks);netcoreapp3.1</TargetFrameworks>\n    <ProduceReferenceAssembly>false</ProduceReferenceAssembly>\n    <SuppressTfmSupportBuildWarnings Condition=\"'$(TargetFramework)' == 'netcoreapp3.1'\">true</SuppressTfmSupportBuildWarnings>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Serialization.Abstractions\\Orleans.Serialization.Abstractions.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/AbstractPropertiesCannotBeSerializedAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the AbstractPropertiesCannotBeSerializedAnalyzer which ensures that abstract properties\n/// cannot be marked with serialization attributes since they have no concrete implementation to serialize.\n/// This analyzer prevents runtime errors by catching invalid serialization configurations at compile time.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class AbstractPropertiesCannotBeSerializedAnalyzerTest : DiagnosticAnalyzerTestBase<AbstractPropertiesCannotBeSerializedAnalyzer>\n{\n    private async Task VerifyGeneratedDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(AbstractPropertiesCannotBeSerializedAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects abstract properties with serialization attributes when using namespace aliases.\n    /// </summary>\n    [Fact]\n    public Task AliasedAttribute()\n        => VerifyGeneratedDiagnostic(\"\"\"\nusing alias = Orleans;\n[alias::GenerateSerializer]\npublic abstract class D { [alias::Id(0)] public abstract int F { get; set; } }\n\"\"\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects abstract properties with serialization attributes when using globally qualified namespaces.\n    /// </summary>\n    [Fact]\n    public Task GloballyQualifiedAttribute()\n        => VerifyGeneratedDiagnostic(\"\"\"\n[global::Orleans.GenerateSerializer]\npublic abstract class D { [global::Orleans.Id(0)] public abstract int F { get; set; } }\n\"\"\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects abstract properties with serialization attributes when using simple attribute names.\n    /// </summary>\n    [Fact]\n    public Task SimpleAttribute()\n        => VerifyGeneratedDiagnostic(\"\"\"\n[GenerateSerializer] public abstract class D { [Id(0)] public abstract int F { get; set; } }\n\"\"\");\n\n    /// <summary>\n    /// Verifies that the analyzer correctly identifies abstract properties with serialization attributes\n    /// even when other unrelated generic attributes are present.\n    /// </summary>\n    [Fact]\n    public Task UnrelatedGenericAttribute()\n        => VerifyGeneratedDiagnostic(\"\"\"\npublic class GenericAttribute<T> : Attribute { }\n[GenerateSerializer]\npublic abstract class D {\n    [GenericAttribute<bool>] [Id(0)] public abstract int F { get; set; }\n}\n\"\"\");\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/AliasClashAttributeAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the AliasClashAttributeAnalyzer which ensures that alias attributes don't have conflicting values.\n/// Orleans uses aliases for type identification in serialization and RPC, so duplicate aliases would cause \n/// runtime conflicts. This analyzer catches these issues at compile time.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class AliasClashAttributeAnalyzerTest : DiagnosticAnalyzerTestBase<AliasClashAttributeAnalyzer>\n{\n    private async Task VerifyHasDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n\n        Assert.NotEmpty(diagnostics);\n        var diagnostic = diagnostics.First();\n\n        Assert.Equal(AliasClashAttributeAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n    }\n\n    private async Task VerifyHasNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two enums have the same alias attribute value.\n    /// </summary>\n    [Fact]\n    public Task Enum_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n            [Alias(\"Enum\")]\n            public enum EA { V }\n\n            [Alias(\"Enum\")]\n            public enum EB { V }\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two records have the same alias attribute value.\n    /// </summary>\n    [Fact]\n    public Task Record_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n            [Alias(\"Record\")]\n            public record RA(string P);\n\n            [Alias(\"Record\")]\n            public record RB(string P);\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two record structs have the same alias attribute value.\n    /// </summary>\n    [Fact]\n    public Task RecordStruct_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n            [Alias(\"RecordStruct\")]\n            public record struct RSA(string P);\n\n            [Alias(\"RecordStruct\")]\n            public record struct RSB(string P);\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two classes have the same alias attribute value.\n    /// </summary>\n    [Fact]\n    public Task Class_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n            [Alias(\"Class\")]\n            public class CA\n            {\n                [Id(0)] public string P { get; set; }\n            }\n\n            [Alias(\"Class\")]\n            public class CB\n            {\n                [Id(0)] public string P { get; set; }\n            }\n            \n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two structs have the same alias attribute value.\n    /// </summary>\n    [Fact]\n    public Task Struct_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n            [Alias(\"Struct\")]\n            public struct SA\n            {\n                public SA() { }\n\n                [Id(0)] public string P { get; set; }\n            }\n\n            [Alias(\"Struct\")]\n            public struct SB\n            {\n                public SB() { }\n\n                [Id(0)] public string P { get; set; }\n            }\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two grain interfaces have the same alias attribute value.\n    /// Tests various grain interface types (IGrain, IGrainWithIntegerKey, etc.).\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task GrainInterface_ShouldTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n            [Alias(\"Interface\")]\n            public interface IA : {{grainInterface}} {}\n\n            [Alias(\"Interface\")]\n            public interface IB : {{grainInterface}} {}\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer does NOT trigger for non-grain interfaces with the same alias,\n    /// as aliases are only meaningful for grain interfaces in Orleans.\n    /// </summary>\n    [Fact]\n    public Task NonGrainInterface_ShouldNotTriggerDiagnostic()\n    {\n        var code = $$\"\"\"\n            [Alias(\"Interface\")]\n            public interface IA {}\n\n            [Alias(\"Interface\")]\n            public interface IB {}\n            \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when two methods in the same grain interface have the same alias.\n    /// Method aliases must be unique within an interface for proper RPC dispatch.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task GrainInterfaceMethod_ShouldTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n            public interface I : {{grainInterface}}\n            {\n                [Alias(\"Void\")] Task Void(int a);\n                [Alias(\"Void\")] Task Void(long a);\n            }\n            \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer allows different aliases for different methods in the same grain interface.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task GrainInterfaceMethod_ShouldNotTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n            public interface I : {{grainInterface}}\n            {\n                [Alias(\"Void\")] Task Void(int a);\n                [Alias(\"Void1\")] Task Void(long a);\n            }\n            \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer allows the same method alias in different grain interfaces,\n    /// as method aliases only need to be unique within each interface.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task DifferentGrainInterfaceMethod_ShouldNotTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n            public interface I1 : {{grainInterface}}\n            {\n                [Alias(\"Void\")] Task Void(string a);\n            }\n                    \n            public interface I2\n            {\n                [Alias(\"Void\")] Task Void(string a);\n            }\n            \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/AlwaysInterleaveDiagnosticAnalyzerTests.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests\n{\n    /// <summary>\n    /// Tests for the AlwaysInterleaveDiagnosticAnalyzer which ensures that the [AlwaysInterleave] attribute\n    /// is only used on grain interface methods, not on grain implementation methods. The attribute must be\n    /// declared on the interface to properly configure interleaving behavior for all implementations.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\n    public class AlwaysInterleaveDiagnosticAnalyzerTest : DiagnosticAnalyzerTestBase<AlwaysInterleaveDiagnosticAnalyzer>\n    {\n        protected override Task<(Diagnostic[], string)> GetDiagnosticsAsync(string source, params string[] extraUsings)\n            => base.GetDiagnosticsAsync(source, extraUsings.Concat(new[] { \"Orleans.Concurrency\" }).ToArray());\n\n        /// <summary>\n        /// Verifies that no diagnostic is reported when the [AlwaysInterleave] attribute is not used at all.\n        /// </summary>\n        [Fact]\n        public async Task AlwaysInterleave_Analyzer_NoWarningsIfAttributeIsNotUsed() => await this.AssertNoDiagnostics(@\"\nclass C\n{\n    Task M() => Task.CompletedTask;\n}\n\");\n\n        /// <summary>\n        /// Verifies that no diagnostic is reported when the [AlwaysInterleave] attribute is correctly used on a grain interface method.\n        /// This is the correct usage pattern for the attribute.\n        /// </summary>\n        [Fact]\n        public async Task AlwaysInterleave_Analyzer_NoWarningsIfAttributeIsUsedOnInterface() => await this.AssertNoDiagnostics(@\"\npublic interface I : IGrain\n{\n    [AlwaysInterleave]\n    Task<string> M();\n}\n\");\n\n        /// <summary>\n        /// Verifies that a diagnostic error is reported when the [AlwaysInterleave] attribute is incorrectly used\n        /// on a grain implementation method instead of the interface method. This is an error because interleaving\n        /// behavior must be specified at the interface level.\n        /// </summary>\n        [Fact]\n        public async Task AlwaysInterleave_Analyzer_WarningIfAttributeisUsedOnGrainClass()\n        {\n            var (diagnostics, source) = await this.GetDiagnosticsAsync(@\"\npublic interface I : IGrain\n{\n    Task<int> Method();\n}\n\npublic class C : I\n{\n    [AlwaysInterleave]\n    public Task<int> Method() => Task.FromResult(0);\n}\n\");\n\n            var diagnostic = diagnostics.Single();\n\n            Assert.Equal(AlwaysInterleaveDiagnosticAnalyzer.DiagnosticId, diagnostic.Id);\n            Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n            Assert.Equal(AlwaysInterleaveDiagnosticAnalyzer.MessageFormat, diagnostic.GetMessage());\n\n            var span = diagnostic.Location.SourceSpan;\n            Assert.Equal(\"AlwaysInterleave\", source[span.Start..span.End]);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/AssemblyInfo.cs",
    "content": "using Xunit;\n\n/// <summary>\n/// Assembly-level configuration for Orleans analyzer tests.\n/// Disables XUnit's concurrency limit to allow maximum parallel test execution,\n/// which is safe for analyzer tests as they don't share state or external resources.\n/// </summary>\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/AtMostOneOrleansConstructorAnalyzerTest.cs",
    "content": "using System.Reflection;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class AtMostOneOrleansConstructorAnalyzerTest : DiagnosticAnalyzerTestBase<AtMostOneOrleansConstructorAnalyzer>\n{\n    [Fact]\n    public async Task TypeWithMultipleAttributedConstructors_ShouldTriggerDiagnostic()\n    {\n        var diagnostics = await GetDiagnosticsAsync(\n            \"\"\"\n            [Orleans.GenerateSerializer]\n            public class C\n            {\n                [Orleans.GenerateSerializer]\n                public C()\n                {\n                }\n\n                [Orleans.GenerateSerializer]\n                public C(int value)\n                {\n                }\n            }\n            \"\"\");\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n        Assert.Equal(AtMostOneOrleansConstructorAnalyzer.RuleId, diagnostics[0].Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostics[0].Severity);\n    }\n\n    [Fact]\n    public async Task TypeWithSingleAttributedConstructor_ShouldNotTriggerDiagnostic()\n    {\n        var diagnostics = await GetDiagnosticsAsync(\n            \"\"\"\n            [Orleans.GenerateSerializer]\n            public class C\n            {\n                [Orleans.GenerateSerializer]\n                public C()\n                {\n                }\n\n                public C(int value)\n                {\n                }\n            }\n            \"\"\");\n\n        Assert.Empty(diagnostics);\n    }\n\n    [Fact]\n    public async Task TypeWithoutGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n    {\n        var diagnostics = await GetDiagnosticsAsync(\n            \"\"\"\n            public class C\n            {\n                [Orleans.GenerateSerializer]\n                public C()\n                {\n                }\n\n                [Orleans.GenerateSerializer]\n                public C(int value)\n                {\n                }\n            }\n            \"\"\");\n\n        Assert.Empty(diagnostics);\n    }\n\n    [Fact]\n    public async Task GeneratedCodeWithMultipleAttributedConstructors_ShouldNotTriggerDiagnostic()\n    {\n        var diagnostics = await GetDiagnosticsAsync(\n            \"\"\"\n            // <auto-generated/>\n            [Orleans.GenerateSerializer]\n            public class C\n            {\n                [Orleans.GenerateSerializer]\n                public C()\n                {\n                }\n\n                [Orleans.GenerateSerializer]\n                public C(int value)\n                {\n                }\n            }\n            \"\"\");\n\n        Assert.Empty(diagnostics);\n    }\n\n    private static async Task<Diagnostic[]> GetDiagnosticsAsync(string source)\n    {\n        const string attributeDefinition = \"\"\"\n            namespace Orleans;\n\n            [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Constructor)]\n            public sealed class GenerateSerializerAttribute : System.Attribute\n            {\n            }\n            \"\"\";\n\n        var compilation = CreateCompilation(\n            \"TestProject\",\n            [CSharpSyntaxTree.ParseText(attributeDefinition), CSharpSyntaxTree.ParseText(source)],\n            GetMetadataReferences());\n\n        var analyzer = new AtMostOneOrleansConstructorAnalyzer();\n        var diagnostics = await compilation\n            .WithOptions(\n                compilation.Options.WithSpecificDiagnosticOptions(\n                    analyzer.SupportedDiagnostics.ToDictionary(d => d.Id, d => ReportDiagnostic.Default)))\n            .WithAnalyzers([analyzer])\n            .GetAnalyzerDiagnosticsAsync();\n\n        return diagnostics.ToArray();\n    }\n\n    private static CSharpCompilation CreateCompilation(string assemblyName, IEnumerable<SyntaxTree> syntaxTrees, IEnumerable<MetadataReference> references)\n        => CSharpCompilation.Create(\n            assemblyName,\n            syntaxTrees,\n            references,\n            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\n\n    private static IReadOnlyCollection<MetadataReference> GetMetadataReferences()\n    {\n        var assemblies = new[]\n        {\n            typeof(object).Assembly,\n            typeof(Attribute).Assembly,\n            typeof(Enumerable).Assembly,\n        };\n\n        var metadataReferences = assemblies\n            .SelectMany(x => x.GetReferencedAssemblies().Select(Assembly.Load))\n            .Concat(assemblies)\n            .Distinct()\n            .Select(x => MetadataReference.CreateFromFile(x.Location))\n            .ToList();\n\n        var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, \"mscorlib.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Core.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Runtime.dll\")));\n\n        return metadataReferences;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/ConfigureAwaitAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CodeActions;\nusing Microsoft.CodeAnalysis.CodeFixes;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Text;\nusing Orleans.Analyzers;\nusing System.Collections.Immutable;\nusing System.Reflection;\nusing System.Text;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that warns against ConfigureAwait(false) or ConfigureAwait without\n/// ContinueOnCapturedContext in grain code. Grains must maintain their synchronization context\n/// to ensure proper execution within the grain's activation context.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class ConfigureAwaitAnalyzerTest : DiagnosticAnalyzerTestBase<ConfigureAwaitAnalyzer>\n{\n    private static readonly string[] Usings = new[] {\n        \"System\",\n        \"System.Threading.Tasks\",\n        \"Orleans\"\n    };\n\n    private async Task VerifyHasDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n\n        Assert.NotEmpty(diagnostics);\n        var diagnostic = diagnostics.First();\n\n        Assert.Equal(ConfigureAwaitAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);\n    }\n\n    private async Task VerifyHasNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n        Assert.Empty(diagnostics);\n    }\n\n    private async Task VerifyCodeFix(string originalCode, string expectedFixedCode, string[] extraUsings = null)\n    {\n        extraUsings ??= Array.Empty<string>();\n\n        // Prepend usings\n        var sb = new StringBuilder();\n        foreach (var @using in Usings.Concat(extraUsings))\n        {\n            sb.AppendLine($\"using {@using};\");\n        }\n        sb.AppendLine(originalCode);\n        var fullOriginalCode = sb.ToString();\n\n        sb.Clear();\n        foreach (var @using in Usings.Concat(extraUsings))\n        {\n            sb.AppendLine($\"using {@using};\");\n        }\n        sb.AppendLine(expectedFixedCode);\n        var fullExpectedCode = sb.ToString();\n\n        // Create project and get diagnostics\n        var project = CreateProject(fullOriginalCode);\n        var document = project.Documents.First();\n        var compilation = await project.GetCompilationAsync();\n\n        var analyzer = new ConfigureAwaitAnalyzer();\n        var compilationWithAnalyzers = compilation\n            .WithOptions(compilation.Options.WithSpecificDiagnosticOptions(\n                analyzer.SupportedDiagnostics.ToDictionary(d => d.Id, d => ReportDiagnostic.Default)))\n            .WithAnalyzers(ImmutableArray.Create<DiagnosticAnalyzer>(analyzer));\n\n        var diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync();\n        Assert.NotEmpty(diagnostics);\n\n        // Apply code fix\n        var codeFixer = new ConfigureAwaitCodeFix();\n        var actions = new List<CodeAction>();\n        var context = new CodeFixContext(\n            document,\n            diagnostics.First(),\n            (action, _) => actions.Add(action),\n            CancellationToken.None);\n\n        await codeFixer.RegisterCodeFixesAsync(context);\n        Assert.NotEmpty(actions);\n\n        var operations = await actions.First().GetOperationsAsync(CancellationToken.None);\n        var changedSolution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;\n        var changedDocument = changedSolution.GetDocument(document.Id);\n        var changedText = await changedDocument.GetTextAsync();\n\n        Assert.Equal(fullExpectedCode, changedText.ToString());\n    }\n\n    private static Project CreateProject(string source)\n    {\n        const string fileName = \"Test.cs\";\n\n        var projectId = ProjectId.CreateNewId(debugName: \"TestProject\");\n        var documentId = DocumentId.CreateNewId(projectId, fileName);\n\n        var assemblies = new[]\n        {\n            typeof(Task).Assembly,\n            typeof(Orleans.IGrain).Assembly,\n            typeof(Orleans.Grain).Assembly,\n            typeof(Attribute).Assembly,\n            typeof(int).Assembly,\n            typeof(object).Assembly,\n        };\n\n        var metadataReferences = assemblies\n            .SelectMany(x => x.GetReferencedAssemblies().Select(Assembly.Load))\n            .Concat(assemblies)\n            .Distinct()\n            .Select(x => MetadataReference.CreateFromFile(x.Location))\n            .Cast<MetadataReference>()\n            .ToList();\n\n        var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"mscorlib.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Core.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Runtime.dll\")));\n\n        var solution = new AdhocWorkspace()\n            .CurrentSolution\n            .AddProject(projectId, \"TestProject\", \"TestProject\", LanguageNames.CSharp)\n            .AddMetadataReferences(projectId, metadataReferences)\n            .AddDocument(documentId, fileName, SourceText.From(source));\n\n        return solution.GetProject(projectId)\n            .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\n    }\n\n    #region ConfigureAwait(false) in Grain\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a generic grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InGenericGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain<MyState>, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n\n                    public class MyState { }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(true) in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitTrue_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(true);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region ConfigureAwait(false) in non-grain class\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a plain class (no inheritance) does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InPlainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class implementing a non-grain interface does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InClassImplementingNonGrainInterface_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public interface IMyService\n                    {\n                        Task DoSomething();\n                    }\n\n                    public class MyService : IMyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class inheriting from a non-grain base class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InClassInheritingNonGrainBase_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class BaseService\n                    {\n                    }\n\n                    public class MyService : BaseService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class with deep non-grain inheritance does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InClassWithDeepNonGrainInheritance_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class GrandparentService\n                    {\n                    }\n\n                    public class ParentService : GrandparentService\n                    {\n                    }\n\n                    public class MyService : ParentService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a struct does not trigger a diagnostic.\n    /// Structs cannot be grains.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InStruct_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public struct MyStruct\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a record does not trigger a diagnostic.\n    /// Records cannot be grains (they don't inherit from Grain or implement IGrainBase).\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InRecord_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public record MyRecord\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a record struct does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InRecordStruct_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public record struct MyRecordStruct\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class implementing IDisposable (not a grain interface) does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InClassImplementingIDisposable_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyService : IDisposable\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n\n                        public void Dispose() { }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a static class does not trigger a diagnostic.\n    /// Static classes cannot be grains.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InStaticClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public static class MyStaticHelper\n                    {\n                        public static async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in an abstract non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InAbstractNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public abstract class MyAbstractService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a generic non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InGenericNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGenericService<T>\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a nested class inside a non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InNestedClassInsideNonGrain_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class OuterService\n                    {\n                        public class InnerService\n                        {\n                            public async Task DoSomething()\n                            {\n                                await Task.Delay(100).ConfigureAwait(false);\n                            }\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions) without ContinueOnCapturedContext \n    /// in a non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_ForceYielding_InNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region No ConfigureAwait\n\n    /// <summary>\n    /// Verifies that awaiting without ConfigureAwait in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task NoConfigureAwait_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region IGrainBase implementation\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class implementing IGrainBase triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InIGrainBaseImplementation_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using Orleans.Runtime;\n\n                    public class MyGrain : IGrainBase, IMyGrain\n                    {\n                        public IGrainContext GrainContext { get; }\n\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    #endregion\n\n    #region ISystemTarget implementation\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class implementing ISystemTarget triggers a diagnostic.\n    /// ISystemTarget is in the Orleans namespace (not Orleans.Runtime), defined in Orleans.Core.Abstractions.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InISystemTargetImplementation_ShouldTriggerDiagnostic()\n    {\n        // Note: ISystemTarget is defined in namespace Orleans (in Orleans.Core.Abstractions assembly),\n        // so no additional using is needed since we already have \"using Orleans;\"\n        var code = \"\"\"\n                    public class MySystemTarget : ISystemTarget\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    #endregion\n\n    #region Nested classes and lambdas\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a lambda within a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InLambdaInsideGrain_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public Task DoSomething()\n                        {\n                            Func<Task> action = async () =>\n                            {\n                                await Task.Delay(100).ConfigureAwait(false);\n                            };\n                            return action();\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a nested class within a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InNestedClassInsideGrain_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public Task DoSomething() => Task.CompletedTask;\n\n                        private class NestedClass\n                        {\n                            public async Task DoWork()\n                            {\n                                await Task.Delay(100).ConfigureAwait(false);\n                            }\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        // The nested class is inside a grain class, so it should still trigger\n        return VerifyHasDiagnostic(code);\n    }\n\n    #endregion\n\n    #region Inherited grain classes\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) in a class that inherits from another grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_InInheritedGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class BaseGrain : Grain\n                    {\n                    }\n\n                    public class MyGrain : BaseGrain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    #endregion\n\n    #region ValueTask\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on ValueTask in a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnValueTask_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await GetValueAsync().ConfigureAwait(false);\n                        }\n\n                        private ValueTask GetValueAsync() => ValueTask.CompletedTask;\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on ValueTask&lt;T&gt; in a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnGenericValueTask_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            var result = await GetValueAsync().ConfigureAwait(false);\n                        }\n\n                        private ValueTask<int> GetValueAsync() => ValueTask.FromResult(42);\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(true) on ValueTask in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitTrue_OnValueTask_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await GetValueAsync().ConfigureAwait(true);\n                        }\n\n                        private ValueTask GetValueAsync() => ValueTask.CompletedTask;\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on ValueTask in a non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnValueTask_InNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await GetValueAsync().ConfigureAwait(false);\n                        }\n\n                        private ValueTask GetValueAsync() => ValueTask.CompletedTask;\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region IAsyncEnumerable\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on IAsyncEnumerable in await foreach in a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnIAsyncEnumerable_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Collections.Generic;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await foreach (var item in GetItemsAsync().ConfigureAwait(false))\n                            {\n                                // Process item\n                            }\n                        }\n\n                        private async IAsyncEnumerable<int> GetItemsAsync()\n                        {\n                            yield return 1;\n                            await Task.Delay(1);\n                            yield return 2;\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(true) on IAsyncEnumerable in await foreach in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitTrue_OnIAsyncEnumerable_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Collections.Generic;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await foreach (var item in GetItemsAsync().ConfigureAwait(true))\n                            {\n                                // Process item\n                            }\n                        }\n\n                        private async IAsyncEnumerable<int> GetItemsAsync()\n                        {\n                            yield return 1;\n                            await Task.Delay(1);\n                            yield return 2;\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on IAsyncEnumerable in a non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnIAsyncEnumerable_InNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Collections.Generic;\n\n                    public class MyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await foreach (var item in GetItemsAsync().ConfigureAwait(false))\n                            {\n                                // Process item\n                            }\n                        }\n\n                        private async IAsyncEnumerable<int> GetItemsAsync()\n                        {\n                            yield return 1;\n                            await Task.Delay(1);\n                            yield return 2;\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that await foreach without ConfigureAwait in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task NoConfigureAwait_OnIAsyncEnumerable_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Collections.Generic;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await foreach (var item in GetItemsAsync())\n                            {\n                                // Process item\n                            }\n                        }\n\n                        private async IAsyncEnumerable<int> GetItemsAsync()\n                        {\n                            yield return 1;\n                            await Task.Delay(1);\n                            yield return 2;\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region Task<T>\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(false) on Task&lt;T&gt; in a grain class triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitFalse_OnGenericTask_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            var result = await Task.FromResult(42).ConfigureAwait(false);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(true) on Task&lt;T&gt; in a grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitTrue_OnGenericTask_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            var result = await Task.FromResult(42).ConfigureAwait(true);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region ConfigureAwait(ConfigureAwaitOptions)\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions.None) in a grain class triggers a diagnostic\n    /// because it doesn't include ContinueOnCapturedContext.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_None_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.None);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions.ForceYielding) in a grain class triggers a diagnostic\n    /// because it doesn't include ContinueOnCapturedContext.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_ForceYielding_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing) in a grain class triggers a diagnostic\n    /// because it doesn't include ContinueOnCapturedContext.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_SuppressThrowing_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext) in a grain class\n    /// does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_ContinueOnCapturedContext_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait with combined flags including ContinueOnCapturedContext\n    /// does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_CombinedWithContinueOnCapturedContext_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait with combined flags NOT including ContinueOnCapturedContext\n    /// triggers a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_CombinedWithoutContinueOnCapturedContext_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.SuppressThrowing);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions) in a non-grain class does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_None_InNonGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyService\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.None);\n                        }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions) on Task&lt;T&gt; works correctly.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_None_OnGenericTask_InGrainClass_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            var result = await Task.FromResult(42).ConfigureAwait(ConfigureAwaitOptions.None);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext) on Task&lt;T&gt; does not trigger a diagnostic.\n    /// </summary>\n    [Fact]\n    public Task ConfigureAwaitOptions_ContinueOnCapturedContext_OnGenericTask_InGrainClass_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            var result = await Task.FromResult(42).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region Code Fix Tests\n\n    /// <summary>\n    /// Verifies that the code fix converts ConfigureAwait(false) to ConfigureAwait(true).\n    /// </summary>\n    [Fact]\n    public Task CodeFix_ConfigureAwaitFalse_ChangesToTrue()\n    {\n        var originalCode = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(false);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        var expectedFixedCode = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(true);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyCodeFix(originalCode, expectedFixedCode);\n    }\n\n    /// <summary>\n    /// Verifies that the code fix converts ConfigureAwait(false) to ConfigureAwait(true) on ValueTask.\n    /// </summary>\n    [Fact]\n    public Task CodeFix_ConfigureAwaitFalse_OnValueTask_ChangesToTrue()\n    {\n        var originalCode = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await GetValueAsync().ConfigureAwait(false);\n                        }\n\n                        private ValueTask GetValueAsync() => ValueTask.CompletedTask;\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        var expectedFixedCode = \"\"\"\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await GetValueAsync().ConfigureAwait(true);\n                        }\n\n                        private ValueTask GetValueAsync() => ValueTask.CompletedTask;\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyCodeFix(originalCode, expectedFixedCode);\n    }\n\n    /// <summary>\n    /// Verifies that the code fix converts ConfigureAwait(ConfigureAwaitOptions.None) to ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext).\n    /// </summary>\n    [Fact]\n    public Task CodeFix_ConfigureAwaitOptionsNone_ChangesToContinueOnCapturedContext()\n    {\n        var originalCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.None);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        var expectedFixedCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyCodeFix(originalCode, expectedFixedCode);\n    }\n\n    /// <summary>\n    /// Verifies that the code fix adds ContinueOnCapturedContext to ConfigureAwait(ConfigureAwaitOptions.ForceYielding).\n    /// </summary>\n    [Fact]\n    public Task CodeFix_ConfigureAwaitOptionsForceYielding_AddsContinueOnCapturedContext()\n    {\n        var originalCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        var expectedFixedCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.ContinueOnCapturedContext);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyCodeFix(originalCode, expectedFixedCode);\n    }\n\n    /// <summary>\n    /// Verifies that the code fix adds ContinueOnCapturedContext to combined ConfigureAwaitOptions.\n    /// </summary>\n    [Fact]\n    public Task CodeFix_ConfigureAwaitOptionsCombined_AddsContinueOnCapturedContext()\n    {\n        var originalCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.SuppressThrowing);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        var expectedFixedCode = \"\"\"\n                    using System.Threading.Tasks;\n\n                    public class MyGrain : Grain, IMyGrain\n                    {\n                        public async Task DoSomething()\n                        {\n                            await Task.Delay(100).ConfigureAwait(ConfigureAwaitOptions.ForceYielding | ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ContinueOnCapturedContext);\n                        }\n                    }\n\n                    public interface IMyGrain : IGrainWithGuidKey\n                    {\n                        Task DoSomething();\n                    }\n                    \"\"\";\n\n        return VerifyCodeFix(originalCode, expectedFixedCode);\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/DiagnosticAnalyzerTestBase.cs",
    "content": "// Derived from Entity Framework Core Analyzer Tests\n// https://github.com/aspnet/EntityFrameworkCore/blob/cbefe76162b16c1122629dbf6c85becbbb5cdc8e/test/EFCore.Analyzers.Tests/TestUtilities/DiagnosticAnalyzerTestBase.cs\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Collections.Immutable;\nusing System.Reflection;\nusing System.Text;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Text;\nusing Roslyn.Utilities;\nusing Xunit;\n\nnamespace Analyzers.Tests\n{\n    /// <summary>\n    /// Base class for testing Roslyn diagnostic analyzers in the Orleans project.\n    /// Provides common infrastructure for compiling test code and running analyzers to verify diagnostics.\n    /// This enables testing of Orleans-specific code analysis rules that help developers avoid common mistakes.\n    /// </summary>\n    /// <typeparam name=\"TDiagnosticAnalyzer\">The type of diagnostic analyzer being tested.</typeparam>\n    public abstract class DiagnosticAnalyzerTestBase<TDiagnosticAnalyzer>\n        where TDiagnosticAnalyzer : DiagnosticAnalyzer, new()\n    {\n        private static readonly string[] Usings = new[] {\n            \"System\",\n            \"System.Threading.Tasks\",\n            \"Orleans\"\n        };\n\n        /// <summary>\n        /// Provides test data for all Orleans grain interface types.\n        /// Used by theory tests to ensure analyzers work correctly with all grain interface variations.\n        /// </summary>\n        public static IEnumerable<object[]> GrainInterfaces =>\n            new List<object[]>\n            {\n                new object[] { \"Orleans.IGrain\" },\n                new object[] { \"Orleans.IGrainWithStringKey\" },\n                new object[] { \"Orleans.IGrainWithGuidKey\" },\n                new object[] { \"Orleans.IGrainWithGuidCompoundKey\" },\n                new object[] { \"Orleans.IGrainWithIntegerKey\" },\n                new object[] { \"Orleans.IGrainWithIntegerCompoundKey\" }\n            };\n\n        /// <summary>\n        /// Creates an instance of the diagnostic analyzer being tested.\n        /// Can be overridden in derived classes to customize analyzer creation.\n        /// </summary>\n        protected virtual DiagnosticAnalyzer CreateDiagnosticAnalyzer() => new TDiagnosticAnalyzer();\n\n        /// <summary>\n        /// Asserts that the provided source code produces no diagnostics when analyzed.\n        /// Used to verify that valid code patterns don't trigger false positives.\n        /// </summary>\n        /// <param name=\"source\">The C# source code to analyze.</param>\n        /// <param name=\"extraUsings\">Additional using statements to include.</param>\n        protected async Task AssertNoDiagnostics(string source, params string[] extraUsings)\n        {\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(source, extraUsings);\n            Assert.Empty(diagnostics);\n        }\n\n        /// <summary>\n        /// Compiles the provided source code and runs the diagnostic analyzer on it.\n        /// Returns any diagnostics produced along with the formatted source code.\n        /// </summary>\n        /// <param name=\"source\">The C# source code to analyze.</param>\n        /// <param name=\"extraUsings\">Additional using statements to include.</param>\n        /// <returns>A tuple containing the diagnostics array and the formatted source code.</returns>\n        protected virtual async Task<(Diagnostic[], string)> GetDiagnosticsAsync(string source, params string[] extraUsings)\n        {\n            var sb = new StringBuilder();\n            foreach (var @using in Usings.Concat(extraUsings))\n            {\n                sb.AppendLine($\"using {@using};\");\n            }\n            sb.AppendLine(source);\n\n            var sourceText = sb.ToString();\n            return (await this.GetDiagnosticsFullSourceAsync(sourceText), sourceText);\n        }\n\n        protected async Task<Diagnostic[]> GetDiagnosticsFullSourceAsync(string source)\n        {\n            var compilation = await CreateProject(source).GetCompilationAsync();\n            var errors = compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error);\n\n            Assert.Empty(errors);\n            var analyzer = this.CreateDiagnosticAnalyzer();\n            var compilationWithAnalyzers\n                = compilation\n                    .WithOptions(\n                        compilation.Options.WithSpecificDiagnosticOptions(\n                            analyzer.SupportedDiagnostics.ToDictionary(d => d.Id, d => ReportDiagnostic.Default)))\n                    .WithAnalyzers(ImmutableArray.Create(analyzer));\n\n            var diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync();\n\n            return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();\n        }\n\n        private static Project CreateProject(string source)\n        {\n            const string fileName = \"Test.cs\";\n\n            var projectId = ProjectId.CreateNewId(debugName: \"TestProject\");\n            var documentId = DocumentId.CreateNewId(projectId, fileName);\n\n            var assemblies = new[]\n            {\n                typeof(Task).Assembly,\n                typeof(Orleans.IGrain).Assembly,\n                typeof(Orleans.Grain).Assembly,\n                typeof(Attribute).Assembly,\n                typeof(int).Assembly,\n                typeof(object).Assembly,\n            }; \n\n            var metadataReferences = assemblies\n                .SelectMany(x => x.GetReferencedAssemblies().Select(Assembly.Load))\n                .Concat(assemblies)\n                .Distinct()\n                .Select(x => MetadataReference.CreateFromFile(x.Location))\n                .Cast<MetadataReference>()\n                .ToList();\n\n            var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);\n            metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"mscorlib.dll\")));\n            metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.dll\")));\n            metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Core.dll\")));\n            metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Runtime.dll\")));\n\n            var solution = new AdhocWorkspace()\n                .CurrentSolution\n                .AddProject(projectId, \"TestProject\", \"TestProject\", LanguageNames.CSharp)\n                .AddMetadataReferences(projectId, metadataReferences)\n                .AddDocument(documentId, fileName, SourceText.From(source));\n\n            return solution.GetProject(projectId)\n                .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/GenerateAliasAttributesAnalyzerTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Reflection;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the GenerateAliasAttributesAnalyzer which suggests adding [Alias] attributes to types and methods\n/// that need them. Orleans uses aliases for stable type identification across versions and deployments.\n/// This analyzer helps developers remember to add aliases to grain interfaces, serializable types, and RPC methods.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class GenerateAliasAttributesAnalyzerTest : DiagnosticAnalyzerTestBase<GenerateAliasAttributesAnalyzer>\n{\n    private async Task VerifyHasDiagnostic(string code, int diagnosticsCount = 1)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Equal(diagnosticsCount, diagnostics.Length);\n\n        var diagnostic = diagnostics.First();\n\n        Assert.Equal(GenerateAliasAttributesAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);\n    }\n\n    private async Task VerifyHasNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n        Assert.Empty(diagnostics);\n    }\n\n    #region Interfaces & Methods\n\n    /// <summary>\n    /// Verifies that the analyzer suggests adding [Alias] attributes to grain interfaces and their methods\n    /// when they don't have them. Each interface and non-static method should have an alias for proper RPC routing.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task GrainInterfaceWithoutAliasAttribute_ShouldTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n                    public interface I : {{grainInterface}}\n                    {\n                        Task<int> M1();\n                        Task<int> M2();\n\n                        static Task<int> M3() => Task.FromResult(0);\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code, 3);  // 3 diagnostics, because 1 for interface, and 2 for the non-static methods\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer does not trigger when grain interfaces and their methods already have [Alias] attributes.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(GrainInterfaces))]\n    public Task GrainInterfaceWithAliasAttribute_ShouldNotTriggerDiagnostic(string grainInterface)\n    {\n        var code = $$\"\"\"\n                    [Alias(\"I\")]\n                    public interface I : {{grainInterface}}\n                    {\n                        [Alias(\"M1\")] Task<int> M1();\n                        [Alias(\"M2\")] Task<int> M2();\n\n                        static Task<int> M3() => Task.FromResult(0);\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer does not suggest aliases for non-grain interfaces,\n    /// as aliases are only needed for grain interfaces in the Orleans RPC system.\n    /// </summary>\n    [Fact]\n    public Task NonGrainInterfaceWithoutAliasAttribute_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public interface I\n                    {\n                        Task<int> M1();\n                        Task<int> M2();\n\n                        static Task<int> M3() => Task.FromResult(0);\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    [Fact]\n    public async Task ReferencedGrainInterfaceWithoutAliasAttribute_ShouldNotCrashAnalyzer()\n    {\n        const string referencedSource = \"\"\"\n            using Orleans;\n            using System.Threading.Tasks;\n\n            public interface IReferencedGrain : IGrainWithGuidKey\n            {\n                Task<int> M1();\n            }\n            \"\"\";\n\n        var diagnostics = await GetDiagnosticsWithReferencedAssemblyAsync(\"public class C {}\", referencedSource);\n\n        Assert.Empty(diagnostics);\n    }\n\n    #endregion\n\n    #region Classes, Structs, Records\n\n    /// <summary>\n    /// Verifies that the analyzer suggests adding [Alias] to classes marked with [GenerateSerializer].\n    /// Serializable types need aliases for version-tolerant serialization.\n    /// </summary>\n    [Fact]\n    public Task ClassWithoutAliasAttribute_AndWithGenerateSerializerAttribute_ShouldTriggerDiagnostic()\n        => VerifyHasDiagnostic(\"[GenerateSerializer] public class C {}\");\n\n    /// <summary>\n    /// Verifies that the analyzer suggests adding [Alias] to structs marked with [GenerateSerializer].\n    /// </summary>\n    [Fact]\n    public Task StructWithoutAliasAttribute_AndWithGenerateSerializerAttribute_ShouldTriggerDiagnostic()\n       => VerifyHasDiagnostic(\"[GenerateSerializer] public struct S {}\");\n\n    /// <summary>\n    /// Verifies that the analyzer suggests adding [Alias] to record classes marked with [GenerateSerializer].\n    /// </summary>\n    [Fact]\n    public Task RecordClassWithoutAliasAttribute_AndWithGenerateSerializerAttribute_ShouldTriggerDiagnostic()\n       => VerifyHasDiagnostic(\"[GenerateSerializer] public record R {}\");\n\n    /// <summary>\n    /// Verifies that the analyzer suggests adding [Alias] to record structs marked with [GenerateSerializer].\n    /// </summary>\n    [Fact]\n    public Task RecordStructWithoutAliasAttribute_AndWithGenerateSerializerAttribute_ShouldTriggerDiagnostic()\n       => VerifyHasDiagnostic(\"[GenerateSerializer] public record struct RS {}\");\n\n    /// <summary>\n    /// Verifies that the analyzer does not trigger when a class with [GenerateSerializer] already has an [Alias].\n    /// </summary>\n    [Fact]\n    public Task ClassWithAliasAttribute_AndWithGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n        => VerifyHasNoDiagnostic(\"[GenerateSerializer, Alias(\\\"C\\\")] public class C {}\");\n\n    [Fact]\n    public Task StructWithAliasAttribute_AndWithGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"[GenerateSerializer, Alias(\\\"S\\\")] public struct S {}\");\n\n    [Fact]\n    public Task RecordClassWithAliasAttribute_AndWithGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"[GenerateSerializer, Alias(\\\"R\\\")] public record R {}\");\n\n    [Fact]\n    public Task RecordStructWithAliasAttribute_AndWithGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"[GenerateSerializer, Alias(\\\"RS\\\")] public record struct RS {}\");\n\n    /// <summary>\n    /// Verifies that the analyzer does not suggest aliases for classes without [GenerateSerializer],\n    /// as only serializable types need aliases.\n    /// </summary>\n    [Fact]\n    public Task ClassWithoutAliasAttribute_AndWithoutGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n        => VerifyHasNoDiagnostic(\"public class C {}\");\n\n    [Fact]\n    public Task StructWithoutAliasAttribute_AndWithoutGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"public struct S {}\");\n\n    [Fact]\n    public Task RecordClassWithoutAliasAttribute_AndWithoutGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"public record R {}\");\n\n    [Fact]\n    public Task RecordStructWithoutAliasAttribute_AndWithoutGenerateSerializerAttribute_ShouldNotTriggerDiagnostic()\n       => VerifyHasNoDiagnostic(\"public record struct RS {}\");\n\n    #endregion\n\n    private static async Task<Diagnostic[]> GetDiagnosticsWithReferencedAssemblyAsync(string source, string referencedSource)\n    {\n        static CSharpCompilation CreateCompilation(string assemblyName, string sourceText, IEnumerable<MetadataReference> references)\n            => CSharpCompilation.Create(\n                assemblyName,\n                [CSharpSyntaxTree.ParseText(sourceText)],\n                references,\n                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\n\n        var references = GetMetadataReferences();\n        var referencedCompilation = CreateCompilation(\"ReferencedAssembly\", referencedSource, references);\n\n        using var stream = new MemoryStream();\n        var emitResult = referencedCompilation.Emit(stream);\n        Assert.True(emitResult.Success, string.Join(Environment.NewLine, emitResult.Diagnostics));\n\n        var compilation = CreateCompilation(\"TestProject\", source, [.. references, MetadataReference.CreateFromImage(stream.ToArray())]);\n        var analyzer = new GenerateAliasAttributesAnalyzer();\n        var compilationWithAnalyzers = compilation\n            .WithOptions(\n                compilation.Options.WithSpecificDiagnosticOptions(\n                    analyzer.SupportedDiagnostics.ToDictionary(d => d.Id, d => ReportDiagnostic.Default)))\n            .WithAnalyzers([analyzer]);\n\n        return (await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync()).ToArray();\n    }\n\n    private static IReadOnlyCollection<MetadataReference> GetMetadataReferences()\n    {\n        var assemblies = new[]\n        {\n            typeof(Task).Assembly,\n            typeof(Orleans.IGrain).Assembly,\n            typeof(Orleans.Grain).Assembly,\n            typeof(Attribute).Assembly,\n            typeof(int).Assembly,\n            typeof(object).Assembly,\n        };\n\n        var metadataReferences = assemblies\n            .SelectMany(x => x.GetReferencedAssemblies().Select(Assembly.Load))\n            .Concat(assemblies)\n            .Distinct()\n            .Select(x => MetadataReference.CreateFromFile(x.Location))\n            .ToList();\n\n        var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, \"mscorlib.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Core.dll\")));\n        metadataReferences.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, \"System.Runtime.dll\")));\n\n        return metadataReferences;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/GenerateGenerateSerializerAttributeAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that suggests using [GenerateSerializer] instead of [Serializable] attribute.\n/// Orleans uses its own serialization system for efficient grain communication, and the [GenerateSerializer]\n/// attribute enables code generation for optimal serialization performance. Using the legacy [Serializable]\n/// attribute can lead to slower serialization and larger message sizes.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class GenerateGenerateSerializerAttributeAnalyzerTest : DiagnosticAnalyzerTestBase<GenerateGenerateSerializerAttributeAnalyzer>\n{\n    private async Task VerifyGeneratedDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(GenerateGenerateSerializerAttributeAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);\n    }\n\n    private async Task VerifyNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a class uses [Serializable] attribute\n    /// and suggests using [GenerateSerializer] instead for better Orleans serialization performance.\n    /// </summary>\n    [Fact]\n    public Task SerializableClass()\n        => VerifyGeneratedDiagnostic(@\"[System.Serializable] public class D { }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a struct uses [Serializable] attribute\n    /// and suggests using [GenerateSerializer] instead for better Orleans serialization performance.\n    /// </summary>\n    [Fact]\n    public Task SerializableStruct()\n        => VerifyGeneratedDiagnostic(@\"[System.Serializable] public struct D { }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a record uses [Serializable] attribute\n    /// and suggests using [GenerateSerializer] instead for better Orleans serialization performance.\n    /// </summary>\n    [Fact]\n    public Task SerializableRecord()\n        => VerifyGeneratedDiagnostic(@\"[System.Serializable] public record D { }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a record struct uses [Serializable] attribute\n    /// and suggests using [GenerateSerializer] instead for better Orleans serialization performance.\n    /// </summary>\n    [Fact]\n    public Task SerializableRecordStruct()\n        => VerifyGeneratedDiagnostic(@\"[System.Serializable] public record struct D { }\");\n\n    [Fact]\n    public Task SerializableClassWithGenerateSerializer_ShouldNotTriggerDiagnostic()\n        => VerifyNoDiagnostic(\n            \"\"\"\n            [System.Serializable, GenerateSerializer]\n            public class D\n            {\n            }\n            \"\"\");\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/GenerateSerializationAttributesAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that ensures types marked with [GenerateSerializer] have proper field attributes.\n/// In Orleans serialization, each serializable field must be marked with an [Id] attribute to ensure\n/// version tolerance and efficient serialization. This analyzer helps developers identify missing\n/// field attributes that could cause serialization issues.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class GenerateSerializationAttributesAnalyzerTest : DiagnosticAnalyzerTestBase<GenerateSerializationAttributesAnalyzer>\n{\n    private async Task VerifyGeneratedDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(GenerateSerializationAttributesAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a class with [GenerateSerializer]\n    /// has fields without [Id] attributes, which are required for proper Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task SerializableClass()\n        => VerifyGeneratedDiagnostic(@\"[GenerateSerializer] public class D { public int f; }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a struct with [GenerateSerializer]\n    /// has fields without [Id] attributes, which are required for proper Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task SerializableStruct()\n        => VerifyGeneratedDiagnostic(@\"[GenerateSerializer] public struct D { public int f; }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a record with [GenerateSerializer]\n    /// has fields without [Id] attributes, which are required for proper Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task SerializableRecord()\n        => VerifyGeneratedDiagnostic(@\"[GenerateSerializer] public record D { public int f; }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a record class with [GenerateSerializer]\n    /// has fields without [Id] attributes, which are required for proper Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task SerializableRecordClass()\n        => VerifyGeneratedDiagnostic(@\"[GenerateSerializer] public record class D { public int f; }\");\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a record struct with [GenerateSerializer]\n    /// has fields without [Id] attributes, which are required for proper Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task SerializableRecordStruct()\n        => VerifyGeneratedDiagnostic(@\"[GenerateSerializer] public record struct D { public int f; }\");\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/GrainInterfaceMethodReturnTypeDiagnosticAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that enforces proper return types for grain interface methods.\n/// Orleans grain methods must return Task, Task&lt;T&gt;, ValueTask, ValueTask&lt;T&gt;, or void\n/// because grain calls are inherently asynchronous across distributed systems.\n/// This analyzer prevents developers from using synchronous return types that would\n/// break the Orleans programming model.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class GrainInterfaceMethodReturnTypeDiagnosticAnalyzerTest : DiagnosticAnalyzerTestBase<GrainInterfaceMethodReturnTypeDiagnosticAnalyzer>\n{\n    private const string DiagnosticId = GrainInterfaceMethodReturnTypeDiagnosticAnalyzer.DiagnosticId;\n    private const string MessageFormat = GrainInterfaceMethodReturnTypeDiagnosticAnalyzer.MessageFormat;\n\n    /// <summary>\n    /// Verifies that the analyzer accepts valid return types for grain interface methods:\n    /// Task, Task&lt;T&gt;, ValueTask, ValueTask&lt;T&gt;, and void are all allowed because they\n    /// support the asynchronous nature of grain calls in Orleans.\n    /// </summary>\n    [Fact]\n    public async Task GrainInterfaceMethodReturnTypeNoError()\n    {\n        var code = \"\"\"\n                    public interface IG : Orleans.IGrain\n                    {\n                        Task TaskMethod(int a);\n                        Task<int> TaskOfIntMethod(int a);\n                        ValueTask ValueTaskMethod(int a);\n                        ValueTask<int> ValueTaskOfIntMethod(int a);\n                        void VoidMethod(int a);\n                    }\n\n                    public interface IA : Orleans.Runtime.IAddressable\n                    {\n                        Task TaskMethod(int a);\n                        Task<int> TaskOfIntMethod(int a);\n                        ValueTask ValueTaskMethod(int a);\n                        ValueTask<int> ValueTaskOfIntMethod(int a);\n                        void VoidMethod(int a);\n                    }\n\n                    public interface IGO : Orleans.IGrainObserver\n                    {\n                        Task TaskMethod(int a);\n                        Task<int> TaskOfIntMethod(int a);\n                        ValueTask ValueTaskMethod(int a);\n                        ValueTask<int> ValueTaskOfIntMethod(int a);\n                        void VoidMethod(int a);\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a grain interface method returns a synchronous type (int).\n    /// This is invalid because grain calls must be asynchronous to work across the distributed cluster.\n    /// </summary>\n    [Fact]\n    public async Task IncompatibleGrainInterfaceMethodReturnType()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrain\n                    {\n                        int MyMethod(int a);\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(DiagnosticId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n        Assert.Equal(MessageFormat, diagnostic.GetMessage());\n    }\n\n    /// <summary>\n    /// Verifies that static interface methods can have any return type since they are not\n    /// subject to the grain call restrictions. Static methods don't participate in the\n    /// distributed grain invocation mechanism.\n    /// </summary>\n    [Fact]\n    public async Task StaticInterfaceMethodsWithRegularReturnsAreAllowed()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrain\n                    {\n                        public static int GetSomeOtherThing(int a) => 0;\n                        public static virtual int GetSomeOtherThingVirtual(int a) => 0;\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/GrainInterfacePropertyDiagnosticAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that prevents properties in grain interfaces.\n/// Orleans grain interfaces cannot have properties because grain calls are RPC-based\n/// and properties would create ambiguity between local state and remote calls.\n/// All grain interaction must be through explicit method calls to maintain clarity\n/// about distributed communication boundaries.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class GrainInterfacePropertyDiagnosticAnalyzerTest : DiagnosticAnalyzerTestBase<GrainInterfacePropertyDiagnosticAnalyzer>\n{\n    private const string DiagnosticId = GrainInterfacePropertyDiagnosticAnalyzer.DiagnosticId;\n    private const string MessageFormat = GrainInterfacePropertyDiagnosticAnalyzer.MessageFormat;\n\n    /// <summary>\n    /// Verifies that grain interfaces with only methods (no properties) pass validation.\n    /// This is the correct pattern for Orleans grain interfaces.\n    /// </summary>\n    [Fact]\n    public async Task GrainInterfacePropertyNoError()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrain\n                    {\n                        Task GetSomeOtherThing(int a);\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects properties in IGrain interfaces.\n    /// Properties are not allowed because they would obscure the distributed nature\n    /// of grain calls and could lead to confusion about local vs. remote state.\n    /// </summary>\n    [Fact]\n    public async Task NoPropertiesAllowedInGrainInterface()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrain\n                    {\n                        int MyProperty { get; set; }\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(DiagnosticId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n        Assert.Equal(MessageFormat, diagnostic.GetMessage());\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects properties in IAddressable interfaces.\n    /// IAddressable is the base interface for grains and has the same restrictions\n    /// regarding properties to maintain consistency in the programming model.\n    /// </summary>\n    [Fact]\n    public async Task NoPropertiesAllowedInIAddressableInterface()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.Runtime.IAddressable\n                    {\n                        int MyProperty { get; set; }\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(DiagnosticId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n        Assert.Equal(MessageFormat, diagnostic.GetMessage());\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects properties in IGrainObserver interfaces.\n    /// Grain observers are used for callbacks and notifications, and like grains,\n    /// they must use explicit methods rather than properties.\n    /// </summary>\n    [Fact]\n    public async Task NoPropertiesAllowedInIGrainObserverInterface()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrainObserver\n                    {\n                        int MyProperty { get; set; }\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Single(diagnostics);\n\n        var diagnostic = diagnostics.First();\n        Assert.Equal(DiagnosticId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n        Assert.Equal(MessageFormat, diagnostic.GetMessage());\n    }\n\n    /// <summary>\n    /// Verifies that static properties are allowed in grain interfaces.\n    /// Static members don't participate in grain invocation and can be used\n    /// for interface-level constants or utility functions.\n    /// </summary>\n    [Fact]\n    public async Task StaticInterfacePropertiesAllowedInGrainInterface()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.IGrain\n                    {\n                        public static int MyProperty => 0;\n                        public static virtual int MyVirtualProperty => 0;\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that static properties are allowed in IAddressable interfaces.\n    /// Static members don't participate in grain invocation and can be used\n    /// for interface-level constants or utility functions.\n    /// </summary>\n    [Fact]\n    public async Task StaticInterfacePropertiesAllowedInAddressableInterface()\n    {\n        var code = \"\"\"\n                    public interface I : Orleans.Runtime.IAddressable\n                    {\n                        public static int MyProperty => 0;\n                        public static virtual int MyVirtualProperty => 0;\n                    }\n                    \"\"\";\n\n        var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n        Assert.Empty(diagnostics);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/IdClashAttributeAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that detects duplicate [Id] attributes in serializable types.\n/// In Orleans serialization, each field must have a unique [Id] attribute value to ensure\n/// proper deserialization and version tolerance. Duplicate IDs would cause serialization\n/// conflicts and data corruption when messages are exchanged between grains.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class IdClashAttributeAnalyzerTest : DiagnosticAnalyzerTestBase<IdClashAttributeAnalyzer>\n{\n    private async Task VerifyHasDiagnostic(string code, int diagnosticsCount)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n\n        Assert.NotEmpty(diagnostics);\n        Assert.Equal(diagnosticsCount, diagnostics.Length);\n\n        var diagnostic = diagnostics.First();\n\n        Assert.Equal(IdClashAttributeAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n    }\n\n    private async Task VerifyHasNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n        Assert.Empty(diagnostics);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer detects when multiple fields in a [GenerateSerializer] type\n    /// have the same [Id] value. This would cause serialization conflicts as the serializer\n    /// wouldn't know which field to map to which ID during deserialization.\n    /// </summary>\n    [Fact]\n    public Task TypesWithGenerateSerializerAndDuplicatedIds_ShouldTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    [GenerateSerializer]\n                    public class C\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(1)] public string P3 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public struct S\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(1)] public string P3 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public record R(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(0)] public string P5 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public record struct RS(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(0)] public string P5 { get; set; }\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code, 8);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer doesn't report issues when all fields in a [GenerateSerializer]\n    /// type have unique [Id] values. This is the correct pattern for Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task TypesWithGenerateSerializerAndNoDuplicatedIds_ShouldNoTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    [GenerateSerializer]\n                    public class C\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(2)] public string P3 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public struct S\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(2)] public string P3 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public record R(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(1)] public string P5 { get; set; }\n                    }\n\n                    [GenerateSerializer]\n                    public record struct RS(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(1)] public string P5 { get; set; }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer ignores types without [GenerateSerializer] attribute,\n    /// even if they have duplicate [Id] attributes. The analyzer only validates types\n    /// that participate in Orleans serialization.\n    /// </summary>\n    [Fact]\n    public Task TypesWithoutGenerateSerializerAndDuplicatedIds_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class C\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(1)] public string P3 { get; set; }\n                    }\n\n                    public struct S\n                    {\n                        [Id(0)] public string P1 { get; set; }\n                        [Id(1)] public string P2 { get; set; }\n                        [Id(1)] public string P3 { get; set; }\n                    }\n\n                    public record R(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(0)] public string P5 { get; set; }\n                    }\n\n                    public record struct RS(string P1, string P2, string P3)\n                    {\n                        [Id(0)] public string P4 { get; set; }\n                        [Id(0)] public string P5 { get; set; }\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/IncorrectAttributeUseAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests;\n\n/// <summary>\n/// Tests for the analyzer that prevents incorrect use of serialization attributes on grain classes.\n/// Grain classes (inheriting from Grain or Grain&lt;T&gt;) should not be marked with [Alias] or\n/// [GenerateSerializer] because grains are not serialized - only their state and method parameters are.\n/// This analyzer helps developers avoid confusion between grain implementations and serializable data types.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\npublic class IncorrectAttributeUseAnalyzerTest : DiagnosticAnalyzerTestBase<IncorrectAttributeUseAnalyzer>\n{\n    private async Task VerifyHasDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n\n        Assert.NotEmpty(diagnostics);\n        var diagnostic = diagnostics.First();\n\n        Assert.Equal(IncorrectAttributeUseAnalyzer.RuleId, diagnostic.Id);\n        Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n    }\n\n    private async Task VerifyHasNoDiagnostic(string code)\n    {\n        var (diagnostics, _) = await GetDiagnosticsAsync(code, Array.Empty<string>());\n        Assert.Empty(diagnostics);\n    }\n\n    #region Grain\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a class inheriting from Grain has\n    /// serialization attributes applied. Grains are not serialized themselves,\n    /// so these attributes are meaningless and indicate a misunderstanding of the Orleans model.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(Attributes))]\n    public Task ClassInheritingFromGrain_HavingAttributeApplied_ShouldTriggerDiagnostic(string attribute)\n    {\n        var code = $$\"\"\"\n                    [{{attribute}}]\n                    public class C : Grain\n                    {\n\n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer allows serialization attributes on regular classes\n    /// that don't inherit from Grain. These classes can be serialized as method parameters\n    /// or grain state.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(Attributes))]\n    public Task ClassNotInheritingFromGrain_HavingAttributeApplied_ShouldNotTriggerDiagnostic(string attribute)\n    {\n        var code = $$\"\"\"\n                    [{{attribute}}]\n                    public class C\n                    {\n\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that grain classes without serialization attributes don't trigger\n    /// the analyzer. This is the correct pattern for grain implementations.\n    /// </summary>\n    [Fact]\n    public Task ClassInheritingFromGrain_NotHavingAttributeApplied_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class C : Grain\n                    {\n\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    #region Grain<TGrainState>\n\n    /// <summary>\n    /// Verifies that the analyzer detects when a class inheriting from Grain&lt;T&gt; has\n    /// serialization attributes applied. Like non-generic grains, stateful grains\n    /// are not serialized themselves - only their state is.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(Attributes))]\n    public Task ClassInheritingFromGenericGrain_HavingAttributeApplied_ShouldTriggerDiagnostic(string attribute)\n    {\n        var code = $$\"\"\"\n                    [{{attribute}}]\n                    public class C : Grain<S>\n                    {\n\n                    }\n\n                    public class S\n                    {\n                    \n                    }\n                    \"\"\";\n\n        return VerifyHasDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that the analyzer allows serialization attributes on regular classes\n    /// that don't inherit from Grain&lt;T&gt;. These classes can be serialized as method parameters\n    /// or grain state.\n    /// </summary>\n    [Theory]\n    [MemberData(nameof(Attributes))]\n    public Task ClassNotInheritingFromGenericGrain_HavingAttributeApplied_ShouldNotTriggerDiagnostic(string attribute)\n    {\n        var code = $$\"\"\"\n                    [{{attribute}}]\n                    public class C\n                    {\n\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    /// <summary>\n    /// Verifies that stateful grain classes without serialization attributes don't trigger\n    /// the analyzer. This is the correct pattern for stateful grain implementations.\n    /// </summary>\n    [Fact]\n    public Task ClassInheritingFromGenericGrain_NotHavingAttributeApplied_ShouldNotTriggerDiagnostic()\n    {\n        var code = \"\"\"\n                    public class C : Grain<S>\n                    {\n\n                    }\n\n                    public class S\n                    {\n\n                    }\n                    \"\"\";\n\n        return VerifyHasNoDiagnostic(code);\n    }\n\n    #endregion\n\n    public static IEnumerable<object[]> Attributes =>\n        new List<object[]>\n        {\n            new object[] { \"Alias(\\\"alias\\\")\" },\n            new object[] { \"GenerateSerializer\" }\n        };\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/NoRefParamsDiagnosticAnalyzerTest.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Orleans.Analyzers;\nusing Xunit;\n\nnamespace Analyzers.Tests\n{\n    /// <summary>\n    /// Tests for the analyzer that prevents ref, out, and in parameters in grain interface methods.\n    /// Orleans grain calls are distributed RPC calls that serialize parameters, so ref/out/in\n    /// parameters cannot work as they would in local method calls. This analyzer helps developers\n    /// avoid this common mistake and ensures grain interfaces follow the Orleans programming model.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Analyzer\")]\n    public class NoRefParamsDiagnosticAnalyzerTest : DiagnosticAnalyzerTestBase<NoRefParamsDiagnosticAnalyzer>\n    {\n        /// <summary>\n        /// Verifies that the analyzer detects ref parameters in grain interface methods.\n        /// Ref parameters cannot work across distributed calls because they require\n        /// shared memory access, which is impossible in a distributed system.\n        /// </summary>\n        [Fact]\n        public async Task NoRefParamsAllowedInGrainInterfaceMethods()\n        {\n            var code = @\"public interface I : IGrain\n                        {\n                            Task GetSomeOtherThing(int a, ref int i);\n                        }\";\n\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n            Assert.NotEmpty(diagnostics);\n            Assert.Single(diagnostics);\n\n            var diagnostic = diagnostics.First();\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.DiagnosticId, diagnostic.Id);\n            Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.MessageFormat, diagnostic.GetMessage());\n        }\n\n        /// <summary>\n        /// Verifies that the analyzer detects out parameters in grain interface methods.\n        /// Out parameters cannot work across distributed calls because they require\n        /// the ability to write back to the caller's memory, which is impossible in RPC.\n        /// </summary>\n        [Fact]\n        public async Task NoOutParamsAllowedInGrainInterfaceMethods()\n        {\n            var code = @\"public interface I : IGrain\n                        {\n                            Task GetSomeOtherThing(out int i);\n                        }\";\n\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n            Assert.NotEmpty(diagnostics);\n            Assert.Single(diagnostics);\n\n            var diagnostic = diagnostics.First();\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.DiagnosticId, diagnostic.Id);\n            Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.MessageFormat, diagnostic.GetMessage());\n        }\n\n        /// <summary>\n        /// Verifies that the analyzer detects multiple ref/out parameter violations\n        /// in grain interface methods, ensuring all problematic parameters are reported.\n        /// </summary>\n        [Fact]\n        public async Task NoRefParamsDiagnosticAnalyzerInClass()\n        {\n            var code = @\"public interface I : IGrain\n                        {\n                            Task GetSomething(ref int i);\n                            Task GetSomeOtherThing(out int i);\n                        }\n\n                        public class Imp : I\n                        {\n                            public Task GetSomething(ref int i) => Task.CompletedTask;\n                            public Task GetSomeOtherThing(out int i)\n                            {\n                                i = 0;\n                                return Task.CompletedTask;\n                            }\n                        }\n                        \";\n\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n            Assert.NotEmpty(diagnostics);\n            Assert.Equal(2, diagnostics.Length);\n\n            var diagnostic = diagnostics.First();\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.DiagnosticId, diagnostic.Id);\n            Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);\n            Assert.Equal(NoRefParamsDiagnosticAnalyzer.MessageFormat, diagnostic.GetMessage());\n        }\n\n        /// <summary>\n        /// Verifies that the analyzer allows regular parameters in grain interface methods\n        /// and doesn't interfere with ref/out/in parameters in non-grain methods,\n        /// which are outside the scope of Orleans restrictions.\n        /// </summary>\n        [Fact]\n        public async Task NoRefParamsDiagnosticAnalyzerNoError()\n        {\n            var code = @\"public interface I : IGrain\n                        {\n                            Task GetSomething(int i);\n                        }\n\n                        public class Imp : I\n                        {\n                            public Task GetSomething(int i) => Task.CompletedTask;\n                            public Task SomeNonInterfaceMethod(ref int value, out int value2, in int value3)\n                            {\n                                value = 0;\n                                value2 = 0;\n                                return Task.CompletedTask;\n                            }\n                        }\n                        \";\n\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n\n            Assert.Empty(diagnostics);\n        }\n\n        /// <summary>\n        /// Verifies that static interface methods can use ref/out parameters.\n        /// Static methods don't participate in grain calls and execute locally,\n        /// so they're not subject to the distributed calling restrictions.\n        /// </summary>\n        [Fact]\n        public async Task OutAndRefParamsAllowedInStaticGrainInterfaceMethods()\n        {\n            var code = @\"public interface I : IGrain\n                        {\n                            public static bool SomeStaticMethod(out int o, ref int v) { o = 0; return false; }\n                            public static virtual bool SomeStaticVirtualMethod(out int o, ref int v) { o = 0; return false; }\n                        }\";\n\n            var (diagnostics, _) = await this.GetDiagnosticsAsync(code, new string[0]);\n            Assert.Empty(diagnostics);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Analyzers.Tests/Orleans.Analyzers.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Analyzers\\Orleans.Analyzers.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/Orleans.CodeGenerator.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>\n    <CollectCoverage>true</CollectCoverage>\n    <CoverletOutputFormat>cobertura</CoverletOutputFormat>\n    <Include>[Orleans.CodeGenerator]*</Include>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <!-- due to Verify.Xunit requiring newer versions of these libraries -->\n    <PackageReference Include=\"coverlet.msbuild\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"System.IO.Hashing\" />\n    <PackageReference Include=\"System.CodeDom\" />\n    <PackageReference Include=\"Verify.Xunit\" />\n    <Compile Remove=\"snapshots\\**\\*\" />\n    <None Include=\"snapshots\\**\\*\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Orleans.CodeGenerator\\Orleans.CodeGenerator.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Runtime\\Orleans.Runtime.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Serialization.FSharp\\Orleans.Serialization.FSharp.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n  </ItemGroup>\n\n\n\n</Project>\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/OrleansSourceGeneratorTests.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Testing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.CodeGenerator.Diagnostics;\nusing Orleans.Serialization;\n\nnamespace Orleans.CodeGenerator.Tests;\n\n/// <summary>\n/// Tests for the Orleans source generator that generates serialization and RPC code.\n///\n/// The Orleans source generator uses Roslyn source generators to:\n/// - Generate serializers for types marked with [GenerateSerializer]\n/// - Generate proxy classes for grain interfaces\n/// - Generate invokable wrappers for grain methods\n/// - Generate metadata for Orleans runtime\n///\n/// Key features tested:\n/// - Serialization code generation for various type patterns\n/// - Support for different C# language features (records, nullable reference types, etc.)\n/// - Grain proxy generation for different grain key types\n/// - Proper handling of generic types\n/// - Diagnostics for incorrect usage\n/// </summary>\npublic class OrleansSourceGeneratorTests\n{\n    /// <summary>\n    /// Tests basic serializer generation for a simple class with a string property.\n    /// This is the most common scenario - a POCO with properties marked with [Id] attributes.\n    /// </summary>\n    [Fact]\n    public Task TestBasicClass() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public string Value { get; set; } = string.Empty;\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for classes with private readonly fields.\n    /// Verifies that the generator can handle:\n    /// - Private fields (not just public properties)\n    /// - Readonly fields that must be set via constructor\n    /// - Property getters that expose private field values\n    /// </summary>\n    [Fact]\n    public Task TestBasicClassWithoutNamespace() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public string Value { get; set; } = string.Empty;\n}\");\n\n    [Fact]\n    public Task TestBasicClassWithDifferentAccessModifiers() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class PublicDemoData\n{\n    [Id(0)]\n    public string Value { get; set; } = string.Empty;\n}\n\n[GenerateSerializer]\ninternal class InternalDemoData\n{\n    [Id(0)]\n    public string Value { get; set; } = string.Empty;\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for classes with private readonly fields.\n    /// Verifies that the generator can handle:\n    /// - Private fields (not just public properties)\n    /// - Readonly fields that must be set via constructor\n    /// - Property getters that expose private field values\n    /// </summary>\n    [Fact]\n    public Task TestBasicClassWithAnnotatedFields() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoDataWithFields\n{\n    [Id(0)]\n    private readonly int _intValue;\n\n    [Id(1)]\n    private readonly string _stringValue;\n\n    public DemoDataWithFields(int intValue, string stringValue)\n    {\n        _intValue = intValue;\n        _stringValue = stringValue;\n    }\n\n    public int IntValue => _intValue;\n\n    public string StringValue => _stringValue;\n}\");\n\n    [Fact]\n    public Task TestBasicClassWithInheritance() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic abstract class BaseData\n{\n    [Id(0)]\n    public string BaseValue { get; set; } = string.Empty;\n\n    protected BaseData(string value)\n    {\n        BaseValue = value;\n    }\n}\n\n[GenerateSerializer]\npublic class DerivedData : BaseData\n{\n    [Id(1)]\n    public string DerivedValue { get; set; } = string.Empty;\n\n    public DerivedData(string baseValue, string derivedValue) : base(baseValue)\n    {\n        DerivedValue = derivedValue;\n    }\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for value types (structs).\n    /// Structs have different semantics than classes (value vs reference types)\n    /// and the generator must handle them appropriately.\n    /// </summary>\n    [Fact]\n    public Task TestBasicStruct() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic struct DemoData\n{\n    [Id(0)]\n    public string Value { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for C# 9+ record types.\n    /// Records are immutable by default and use positional parameters,\n    /// requiring special handling for:\n    /// - Record structs vs record classes\n    /// - Property attributes on positional parameters\n    /// - Init-only properties\n    /// </summary>\n    [Fact]\n    public Task TestRecords() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic record struct DemoDataRecordStruct([property: Id(0)] string Value);\n\n[GenerateSerializer]\npublic record class DemoDataRecordClass([property: Id(0)] string Value);\n\n[GenerateSerializer]\npublic record DemoDataRecord([property: Id(0)] string Value);\");\n\n    /// <summary>\n    /// Tests serializer generation for generic types.\n    /// Generic types require:\n    /// - Generating specialized serializers for each concrete type usage\n    /// - Handling type parameters in serialization logic\n    /// - Supporting nested generic types\n    /// </summary>\n    [Fact]\n    public Task TestGenericClass() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class GenericData<T>\n{\n    [Id(0)]\n    public T Value { get; set; }\n\n    [Id(1)]\n    public string Description { get; set; } = string.Empty;\n}\n\n// Also need a concrete usage to trigger generation for a specific type\n[GenerateSerializer]\npublic class ConcreteUsage\n{\n    [Id(0)]\n    public GenericData<int> IntData { get; set; }\n\n    [Id(1)]\n    public GenericData<string> StringData { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for classes with nullable reference types.\n    /// Verifies support for C# 8+ nullable reference types including:\n    /// - Nullable and non-nullable reference properties\n    /// - Required properties (C# 11+)\n    /// - Init-only setters\n    /// </summary>\n    [Fact]\n    public Task TestClassReferenceProperties() => AssertSuccessfulSourceGeneration(\n@\"#nullable enable\nusing Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public string? NullableStringProp { get; set; }\n\n    [Id(1)]\n    public string StringProp { get; set; } = string.Empty;\n\n    [Id(2)]\n    public required string RequiredStringProp { get; set; }\n\n    [Id(3)]\n    public required string RequiredStringPropInitOnly { get; init; }\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for all primitive .NET types.\n    /// Ensures the generator has built-in support for:\n    /// - Numeric types (int, long, float, double, decimal, etc.)\n    /// - Boolean, char, string\n    /// - Date/time types (DateTime, DateTimeOffset, TimeSpan)\n    /// - GUID and arrays\n    /// </summary>\n    [Fact]\n    public Task TestClassPrimitiveTypes() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public int IntProp { get; set; }\n\n    [Id(1)]\n    public double DoubleProp { get; set; }\n\n    [Id(2)]\n    public float FloatProp { get; set; }\n\n    [Id(3)]\n    public long LongProp { get; set; }\n\n    [Id(4)]\n    public bool BoolProp { get; set; }\n\n    [Id(5)]\n    public byte ByteProp { get; set; }\n\n    [Id(6)]\n    public short ShortProp { get; set; }\n\n    [Id(7)]\n    public char CharProp { get; set; }\n\n    [Id(8)]\n    public uint UIntProp { get; set; }\n\n    [Id(9)]\n    public ulong ULongProp { get; set; }\n\n    [Id(10)]\n    public ushort UShortProp { get; set; }\n\n    [Id(11)]\n    public sbyte SByteProp { get; set; }\n\n    [Id(12)]\n    public decimal DecimalProp { get; set; }\n\n    [Id(13)]\n    public DateTime DateTimeProp { get; set; }\n\n    [Id(14)]\n    public DateTimeOffset DateTimeOffsetProp { get; set; }\n\n    [Id(15)]\n    public TimeSpan TimeSpanProp { get; set; }\n\n    [Id(16)]\n    public Guid GuidProp { get; set; }\n\n    [Id(17)]\n    public int[] IntArrayProp { get; set; }\n}\");\n\n    [Fact]\n    public Task TestClassPrimitiveTypesUsingFullName() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public System.Int32 IntProp { get; set; }\n\n    [Id(1)]\n    public System.Double DoubleProp { get; set; }\n\n    [Id(2)]\n    public System.Single FloatProp { get; set; }\n\n    [Id(3)]\n    public System.Int64 LongProp { get; set; }\n\n    [Id(4)]\n    public System.Boolean BoolProp { get; set; }\n\n    [Id(5)]\n    public System.Byte ByteProp { get; set; }\n\n    [Id(6)]\n    public System.Int16 ShortProp { get; set; }\n\n    [Id(7)]\n    public System.Char CharProp { get; set; }\n\n    [Id(8)]\n    public System.UInt32 UIntProp { get; set; }\n\n    [Id(9)]\n    public System.UInt64 ULongProp { get; set; }\n\n    [Id(10)]\n    public System.UInt16 UShortProp { get; set; }\n\n    [Id(11)]\n    public System.SByte SByteProp { get; set; }\n\n    [Id(12)]\n    public System.Decimal DecimalProp { get; set; }\n\n    [Id(13)]\n    public System.DateTime DateTimeProp { get; set; }\n\n    [Id(14)]\n    public System.DateTimeOffset DateTimeOffsetProp { get; set; }\n\n    [Id(15)]\n    public System.TimeSpan TimeSpanProp { get; set; }\n\n    [Id(16)]\n    public System.Guid GuidProp { get; set; }\n\n    [Id(17)]\n    public System.Int32[] IntArrayProp { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests serializer generation for complex object graphs.\n    /// Verifies handling of:\n    /// - Nested object references\n    /// - Collections of custom types\n    /// - Cyclic references (important for preventing stack overflow)\n    /// </summary>\n    [Fact]\n    public Task TestClassNestedTypes() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System.Collections.Generic;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class DemoData\n{\n    [Id(0)]\n    public NestedClass1 Nested1 { get; set; }\n\n    [Id(1)]\n    public List<NestedClass1> NestedList { get; set; }\n\n    [Id(2)]\n    public CyclicClass Cyclic { get; set; }\n}\n\npublic class NestedClass1\n{\n    [Id(0)]\n    public string Value { get; set; }\n\n    [Id(1)]\n    public NestedClass2 Nested2 { get; set; }\n}\n\npublic class NestedClass2\n{\n    [Id(0)]\n    public string Value { get; set; }\n\n    [Id(1)]\n    public int IntProp { get; set; }\n}\n\npublic class CyclicClass\n{\n    [Id(0)]\n    public CyclicClass Nested { get; set; }\n\n    [Id(1)]\n    public string Value { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests the [Alias] attribute for type name aliases.\n    /// Aliases allow types to be renamed without breaking serialization compatibility,\n    /// essential for versioning and refactoring scenarios.\n    /// </summary>\n    [Fact]\n    public Task TestAlias() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[Alias(\"\"_custom_type_alias_\"\")]\npublic class MyTypeAliasClass\n{\n    [Id(0)]\n    public string Name { get; set; }\n}\n\n[GenerateSerializer]\npublic struct MyTypeAliasStruct\n{\n    [Id(0)]\n    public string Name { get; set; }\n}\n\");\n\n    /// <summary>\n    /// Tests the [CompoundTypeAlias] attribute for complex type aliases.\n    /// Compound aliases can include multiple type components and versions,\n    /// supporting advanced versioning scenarios like type migrations.\n    /// </summary>\n    [Fact]\n    public Task TestCompoundTypeAlias() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[Alias(\"\"_custom_type_alias_\"\")]\npublic class MyTypeAliasClass\n{\n}\n\n[GenerateSerializer]\npublic class MyCompoundTypeAliasBaseClass\n{\n    [Id(0)]\n    public int BaseValue { get; set; }\n}\n\n[GenerateSerializer]\n[CompoundTypeAlias(\"\"xx_test_xx\"\", typeof(MyTypeAliasClass), typeof(int), \"\"1\"\")]\npublic class MyCompoundTypeAliasClass : MyCompoundTypeAliasBaseClass\n{\n    [Id(0)]\n    public string Name { get; set; }\n\n    [Id(1)]\n    public int Value { get; set; }\n}\");\n\n    [Fact]\n    public Task TestClassWithParameterizedConstructor() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\npublic interface IMyService { }\npublic class MyService : IMyService { }\n\n[GenerateSerializer]\npublic class MyServiceConsumer\n{\n    private readonly IMyService _service;\n    private readonly int _value;\n\n    // Constructor requiring parameters, which the generator should use for activation\n    public MyServiceConsumer(IMyService service, int value)\n    {\n        _service = service;\n        _value = value;\n    }\n\n    [Id(0)]\n    public string Name { get; set; }\n}\n\n// Include a type that uses the above class to ensure it's processed\n[GenerateSerializer]\npublic class RootType\n{\n    [Id(0)]\n    public MyServiceConsumer Consumer { get; set; }\n}\");\n\n    [Fact]\n    public Task TestGenericClassWithConstructorParameters() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class GenericWithCtor<T>\n{\n    [Id(0)]\n    private readonly T _value;\n    [Id(1)]\n    private readonly int _id;\n\n    public GenericWithCtor(T value, int id)\n    {\n        _value = value;\n        _id = id;\n    }\n\n    public T Value => _value;\n    public int Id => _id;\n}\n\n[GenerateSerializer]\npublic class UsesGenericWithCtor\n{\n    [Id(0)]\n    public GenericWithCtor<string> StringGen { get; set; }\n}\");\n\n    [Fact]\n    public Task TestClassWithNoPublicConstructors() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class NoPublicCtor\n{\n    private NoPublicCtor() { }\n\n    [Id(0)]\n    public int Value { get; set; }\n}\");\n\n    [Fact]\n    public Task TestClassWithOptionalConstructorParameters() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class OptionalCtorParams\n{\n    [Id(0)]\n    private readonly int _x;\n    [Id(1)]\n    private readonly string _y;\n\n    public OptionalCtorParams(int x = 42, string y = \"\"default\"\")\n    {\n        _x = x;\n        _y = y;\n    }\n\n    public int X => _x;\n    public string Y => _y;\n}\");\n\n    [Fact]\n    public Task TestClassWithInterfaceConstructorParameter() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\npublic interface IMyInterface { }\n\n[GenerateSerializer]\npublic class InterfaceCtorParam\n{\n    [Id(0)]\n    private readonly IMyInterface _iface;\n\n    public InterfaceCtorParam(IMyInterface iface)\n    {\n        _iface = iface;\n    }\n\n    public IMyInterface Iface => _iface;\n}\");\n\n    [Fact]\n    public Task TestClassesWithGeneratedActivatorConstructorAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class ClassWithGeneratedActivatorConstructor\n{\n    [Id(0)]\n    public int Value { get; set; }\n\n    [Id(1)]\n    public string Name { get; set; } = string.Empty;\n\n    [GeneratedActivatorConstructor]\n    public ClassWithGeneratedActivatorConstructor()\n    {\n    }\n\n    public ClassWithGeneratedActivatorConstructor(int value)\n    {\n        Value = value;\n    }\n}\");\n\n    [Fact]\n    public Task TestClassWithGenerateMethodSerializersAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing Orleans.Runtime;\nusing System.Threading.Tasks;\n\n[GenerateMethodSerializers(typeof(GrainReference))]\npublic interface IMyGrain : IGrainWithIntegerKey\n{\n    Task<string> SayHello(string name);\n}\");\n\n    [Fact]\n    public Task TestClassWithGenerateSerializerAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic enum MyCustomEnum\n{\n    None,\n    One,\n    Two,\n    Three\n}\n\n[GenerateSerializer(GenerateFieldIds = GenerateFieldIds.PublicProperties), Immutable]\npublic class ClassWithImplicitFieldIds\n{\n    public string StringValue { get; set; } = string.Empty;\n    public MyCustomEnum EnumValue { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests proxy generation for a basic grain interface.\n    /// Verifies that the generator creates:\n    /// - Proxy class implementing the grain interface\n    /// - Method invokers for RPC calls\n    /// - Proper integration with Orleans runtime\n    /// </summary>\n    [Fact]\n    public Task TestBasicGrain() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\npublic interface IBasicGrain : IGrainWithIntegerKey\n{\n    Task<string> SayHello(string name);\n}\n\n[GenerateSerializer]\npublic class BasicGrain : Grain, IBasicGrain\n{\n    public Task<string> SayHello(string name)\n    {\n        return Task.FromResult($\"\"Hello, {name}!\"\");\n    }\n}\");\n\n    /// <summary>\n    /// Tests proxy generation for grains with different key types.\n    /// Orleans supports multiple grain key types:\n    /// - Integer keys\n    /// - GUID keys\n    /// - String keys\n    /// - Compound keys (primary key + extension)\n    /// Each requires different proxy generation logic.\n    /// </summary>\n    [Fact]\n    public Task TestGrainWithDifferentKeyTypes() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\npublic interface IMyGrainWithGuidKey : IGrainWithGuidKey\n{\n    Task<Guid> GetGuidValue();\n}\n\n[GenerateSerializer]\npublic class GrainWithGuidKey : Grain, IMyGrainWithGuidKey\n{\n    public Task<Guid> GetGuidValue() => Task.FromResult(this.GetPrimaryKey());\n}\n\npublic interface IMyGrainWithStringKey : IGrainWithStringKey\n{\n    Task<string> GetStringKey();\n}\n\n[GenerateSerializer]\npublic class GrainWithStringKey : Grain, IMyGrainWithStringKey\n{\n    public Task<string> GetStringKey() => Task.FromResult(this.GetPrimaryKeyString());\n}\n\npublic interface IMyGrainWithGuidCompoundKey : IGrainWithGuidCompoundKey\n{\n    Task<Tuple<Guid, string>> GetGuidAndStringKey();\n}\n\n[GenerateSerializer]\npublic class GrainWithGuidCompoundKey : Grain, IMyGrainWithGuidCompoundKey\n{\n    public Task<Tuple<Guid, string>> GetGuidAndStringKey()\n    {\n        Guid primaryKey = this.GetPrimaryKey(out var keyExtension);\n        return Task.FromResult(Tuple.Create(primaryKey, keyExtension));\n    }\n}\n\npublic interface IMyGrainWithIntegerCompoundKey : IGrainWithIntegerCompoundKey\n{\n    Task<Tuple<long, string>> GetIntegerAndStringKey();\n}\n\n[GenerateSerializer]\npublic class GrainWithIntegerCompoundKey : Grain, IMyGrainWithIntegerCompoundKey\n{\n    public Task<Tuple<long, string>> GetIntegerAndStringKey()\n    {\n        long primaryKey = this.GetPrimaryKeyLong(out var keyExtension);\n        return Task.FromResult(Tuple.Create(primaryKey, keyExtension));\n    }\n}\");\n\n    /// <summary>\n    /// Tests grain proxy generation with complex method signatures.\n    /// Verifies that the generator correctly handles:\n    /// - Multiple parameters\n    /// - Custom types as parameters and return values\n    /// - Async Task return types\n    /// </summary>\n    [Fact]\n    public Task TestGrainComplexGrain() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\n[GenerateSerializer]\npublic class ComplexData\n{\n    [Id(0)]\n    public int IntValue { get; set; }\n\n    [Id(1)]\n    public string StringValue { get; set; }\n}\n\npublic interface IComplexGrain : IGrainWithIntegerKey\n{\n    Task<ComplexData> ProcessData(int inputInt, string inputString, ComplexData data, CancellationToken ctx);\n}\n\n[GenerateSerializer]\npublic class ComplexGrain : Grain, IComplexGrain\n{\n    public Task<ComplexData> ProcessData(int inputInt, string inputString, ComplexData data, CancellationToken ctx)\n    {\n        var result = new ComplexData\n        {\n            IntValue = inputInt * 2 + data.IntValue,\n            StringValue = $\"\"Processed: {inputString}\"\" + data.StringValue\n        };\n        return Task.FromResult(result);\n    }\n}\");\n\n    [Fact]\n    public Task TestGrainWithMultipleInterfaces() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\npublic interface IGrainA : IGrainWithIntegerKey\n{\n    Task<string> MethodA(string input);\n}\n\npublic interface IGrainB : IGrainWithIntegerKey\n{\n    Task<string> MethodB(string input);\n}\n\npublic class RealGrain : Grain, IGrainA, IGrainB\n{\n    public Task<string> MethodA(string input)\n    {\n        return Task.FromResult($\"\"GrainA: {input}!\"\");\n    }\n\n    public Task<string> MethodB(string input)\n    {\n        return Task.FromResult($\"\"GrainB: {input}!\"\");\n    }\n}\");\n\n    [Fact]\n    public Task TestGrainMethodAnnotatedWithResponseTimeout() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\npublic interface IResponseTimeoutGrain : IGrainWithIntegerKey\n{\n    [ResponseTimeout(\"\"00:00:10\"\")]\n    Task<string> LongRunningMethod(string input);\n}\n\npublic class ResponseTimeoutGrain : Grain, IResponseTimeoutGrain\n{\n    public Task<string> LongRunningMethod(string input)\n    {\n        // Simulate a long-running operation\n        return Task.FromResult($\"\"ResponseTimeoutGrain: {input}!\"\");\n    }\n}\");\n\n    [Fact]\n    public Task TestGrainMethodAnnotatedWithInvokableBaseType() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing Orleans.Runtime;\n\nusing System;\nusing System.Threading.Tasks;\n\nnamespace TestProject;\n\n[InvokableCustomInitializer(nameof(LoggerRequest.SetLoggingOptions))]\n[InvokableBaseType(typeof(GrainReference), typeof(Task), typeof(LoggerRequest))]\n[AttributeUsage(AttributeTargets.Method)]\npublic sealed class LoggingRcpAttribute : Attribute\n{\n    public LoggingRcpAttribute(string options)\n    {\n    }\n}\n\npublic abstract class LoggerRequest : RequestBase\n{\n    public void SetLoggingOptions(string options)\n    {\n    }\n}\n\npublic interface IHelloGrain : IGrainWithIntegerKey\n{\n    [LoggingRcp(\"\"Hello\"\")]\n    Task<string> SayHello(string greeting);\n}\n\n[GenerateSerializer]\npublic class HelloGrain : Grain, IHelloGrain\n{\n    public Task<string> SayHello(string greeting)\n    {\n        return Task.FromResult($\"\"Hello, {greeting}!\"\");\n    }\n}\");\n\n    [Fact]\n    public Task TestWithUseActivatorAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\nusing Orleans.Serialization.Activators;\n\nnamespace TestProject;\n\n[UseActivator]\npublic class DemoClass\n{\n}\n\n[RegisterActivator]\ninternal sealed class DemoClassActivator : IActivator<DemoClass>\n{\n    public DemoClass Create() => new DemoClass();\n}\");\n\n    [Fact]\n    public Task TestWithSerializerTransparentAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[SerializerTransparent]\npublic abstract class DemoTransparentClass\n{\n}\");\n\n    [Fact]\n    public Task TestWithSuppressReferenceTrackingAttribute() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer, SuppressReferenceTracking]\npublic class DemoClass\n{\n    [Id(0)]\n    public string Value { get; set; } = string.Empty;\n}\");\n\n    [Fact]\n    public Task TestWithOmitDefaultMemberValuesAnnotation() => AssertSuccessfulSourceGeneration(\n@\"using Orleans;\n\nnamespace TestProject;\n\n[GenerateSerializer, OmitDefaultMemberValues]\npublic class DemoClass\n{\n    [Id(0)]\n    public string Value { get; set; }\n}\");\n\n    /// <summary>\n    /// Tests that the generator emits a warning when [GenerateSerializer] is used in a reference assembly.\n    /// Reference assemblies contain only metadata, no implementation, so generating serializers\n    /// in them is incorrect. This test ensures developers get proper diagnostics for this mistake.\n    /// </summary>\n    [Fact]\n    public async Task EmitsWarningForGenerateSerializerInReferenceAssembly()\n    {\n        var code = \"\"\"\n            using Orleans;\n\n            namespace TestProject;\n\n            [GenerateSerializer]\n            public class RefAsmType\n            {\n                [Id(0)]\n                public string Value { get; set; } = string.Empty;\n            }\n        \"\"\";\n\n        // The ReferenceAssemblyAttribute marks the assembly as a reference assembly.\n        // This triggers the Orleans code generator's logic to emit a diagnostic if [GenerateSerializer] is used in such an assembly.\n        var compilation = await CreateCompilation(code, \"TestProject\");\n        var referenceAssemblyAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName(\"System.Runtime.CompilerServices.ReferenceAssemblyAttribute\"));\n        var assemblyAttr = SyntaxFactory.AttributeList(\n            SyntaxFactory.SingletonSeparatedList(referenceAssemblyAttribute))\n            .WithTarget(SyntaxFactory.AttributeTargetSpecifier(SyntaxFactory.Token(SyntaxKind.AssemblyKeyword)));\n        var root = (CSharpSyntaxNode)compilation.SyntaxTrees[0].GetRoot();\n        var newRoot = ((CompilationUnitSyntax)root).AddAttributeLists(assemblyAttr);\n        var newTree = compilation.SyntaxTrees[0].WithRootAndOptions(newRoot, compilation.SyntaxTrees[0].Options);\n\n        // leave only syntaxTree with the ReferenceAssemblyAttribute\n        compilation = compilation.RemoveSyntaxTrees(compilation.SyntaxTrees[0]).AddSyntaxTrees(newTree);\n\n        var result = RunSourceGenerator(compilation);\n        Assert.Contains(result.Diagnostics, d => d.Id == DiagnosticRuleId.ReferenceAssemblyWithGenerateSerializer);\n    }\n\n    [Fact]\n    public async Task RemovedCustomAttributeBuildPropertiesAreIgnored()\n    {\n        var code = \"\"\"\n            using System;\n            using Orleans;\n\n            namespace TestProject;\n\n            [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n            public sealed class CustomGenerateSerializerAttribute : Attribute\n            {\n            }\n\n            [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property)]\n            public sealed class CustomImmutableAttribute : Attribute\n            {\n            }\n\n            [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n            public sealed class CustomAliasAttribute : Attribute\n            {\n                public CustomAliasAttribute(string value)\n                {\n                }\n            }\n\n            [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n            public sealed class CustomIdAttribute : Attribute\n            {\n                public CustomIdAttribute(uint id)\n                {\n                }\n            }\n\n            [CustomGenerateSerializer, CustomAlias(\"custom\")]\n            public class DemoData\n            {\n                [CustomId(0), CustomImmutable]\n                public string Value { get; set; } = string.Empty;\n            }\n            \"\"\";\n\n        var compilation = await CreateCompilation(code, \"TestProject\");\n        var baselineResult = RunSourceGenerator(compilation);\n        var configuredResult = RunSourceGenerator(\n            compilation,\n            new Dictionary<string, string>\n            {\n                [\"build_property.orleans_immutableattributes\"] = \"TestProject.CustomImmutableAttribute\",\n                [\"build_property.orleans_idattributes\"] = \"TestProject.CustomIdAttribute\",\n                [\"build_property.orleans_aliasattributes\"] = \"TestProject.CustomAliasAttribute\",\n                [\"build_property.orleans_generateserializerattributes\"] = \"TestProject.CustomGenerateSerializerAttribute\",\n            });\n\n        Assert.Single(baselineResult.GeneratedSources);\n        Assert.Single(configuredResult.GeneratedSources);\n        Assert.Equal(\n            baselineResult.GeneratedSources[0].SourceText.ToString(),\n            configuredResult.GeneratedSources[0].SourceText.ToString());\n        Assert.Equal(\n            baselineResult.Diagnostics.Select(d => d.Id).OrderBy(id => id),\n            configuredResult.Diagnostics.Select(d => d.Id).OrderBy(id => id));\n    }\n\n    private static GeneratorRunResult RunSourceGenerator(\n        CSharpCompilation compilation,\n        IReadOnlyDictionary<string, string>? globalOptions = null)\n    {\n        AnalyzerConfigOptionsProvider? optionsProvider = globalOptions is null\n            ? null\n            : new TestAnalyzerConfigOptionsProvider(globalOptions);\n\n        var generator = new OrleansSerializationSourceGenerator();\n        GeneratorDriver driver = CSharpGeneratorDriver.Create(\n            generators: [generator],\n            optionsProvider: optionsProvider,\n            driverOptions: new GeneratorDriverOptions(default));\n        driver = driver.RunGenerators(compilation);\n        return driver.GetRunResult().Results.Single();\n    }\n\n    /// <summary>\n    /// Helper method that runs the Orleans source generator on the provided code\n    /// and verifies successful generation without errors.\n    /// Uses snapshot testing to verify the generated code matches expectations.\n    /// </summary>\n    private static async Task AssertSuccessfulSourceGeneration(string code)\n    {\n        var projectName = \"TestProject\";\n        var compilation = await CreateCompilation(code, projectName);\n        Assert.Empty(compilation.GetDiagnostics());\n        var result = RunSourceGenerator(compilation);\n        Assert.Empty(result.Diagnostics);\n\n        Assert.Single(result.GeneratedSources);\n        Assert.Equal($\"{projectName}.orleans.g.cs\", result.GeneratedSources[0].HintName);\n        var generatedSource = result.GeneratedSources[0].SourceText.ToString();\n\n        await Verify(generatedSource, extension: \"cs\").UseDirectory(\"snapshots\");\n    }\n\n    private sealed class TestAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider\n    {\n        private static readonly AnalyzerConfigOptions EmptyOptions = new TestAnalyzerConfigOptions(new Dictionary<string, string>());\n        private readonly AnalyzerConfigOptions _globalOptions;\n\n        public TestAnalyzerConfigOptionsProvider(IReadOnlyDictionary<string, string> globalOptions)\n        {\n            _globalOptions = new TestAnalyzerConfigOptions(globalOptions);\n        }\n\n        public override AnalyzerConfigOptions GlobalOptions => _globalOptions;\n\n        public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) => EmptyOptions;\n\n        public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) => EmptyOptions;\n    }\n\n    private sealed class TestAnalyzerConfigOptions : AnalyzerConfigOptions\n    {\n        private readonly IReadOnlyDictionary<string, string> _options;\n\n        public TestAnalyzerConfigOptions(IReadOnlyDictionary<string, string> options)\n        {\n            _options = options;\n        }\n\n        public override bool TryGetValue(string key, out string value) => _options.TryGetValue(key, out value!);\n    }\n\n    /// <summary>\n    /// Creates a Roslyn compilation with the necessary Orleans references.\n    /// This simulates the build environment where the source generator runs,\n    /// including all required Orleans assemblies and .NET framework references.\n    /// </summary>\n    private static async Task<CSharpCompilation> CreateCompilation(string sourceCode, string assemblyName = \"TestProject\")\n    {\n#if NET10_0_OR_GREATER\n        // Manually construct .NET 10.0 reference assemblies\n        var net10References = new ReferenceAssemblies(\n            \"net10.0\",\n            new PackageIdentity(\"Microsoft.NETCore.App.Ref\", \"10.0.0\"),\n            Path.Combine(\"ref\", \"net10.0\"));\n        \n        var references = await net10References.ResolveAsync(LanguageNames.CSharp, default);\n#else\n        var references = await ReferenceAssemblies.Net.Net80.ResolveAsync(LanguageNames.CSharp, default);\n#endif\n\n        // Add the Orleans Orleans.Core.Abstractions assembly\n        references = references.AddRange(\n            // Orleans.Core.Abstractions\n            MetadataReference.CreateFromFile(typeof(GrainId).Assembly.Location),\n            // Orleans.Core\n            MetadataReference.CreateFromFile(typeof(IClusterClientLifecycle).Assembly.Location),\n            // Orleans.Runtime\n            MetadataReference.CreateFromFile(typeof(IGrainActivator).Assembly.Location),\n            // Orleans.Serialization\n            MetadataReference.CreateFromFile(typeof(Serializer).Assembly.Location),\n            // Orleans.Serialization.Abstractions\n            MetadataReference.CreateFromFile(typeof(GenerateFieldIds).Assembly.Location),\n            // Microsoft.Extensions.DependencyInjection.Abstractions\n            MetadataReference.CreateFromFile(typeof(ActivatorUtilitiesConstructorAttribute).Assembly.Location)\n        );\n\n        var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);\n\n        return CSharpCompilation.Create(assemblyName, [syntaxTree], references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\n    }\n}\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_MyTypeAliasStruct : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.MyTypeAliasStruct>, global::Orleans.Serialization.Serializers.IValueSerializer<global::TestProject.MyTypeAliasStruct>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.MyTypeAliasStruct);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::TestProject.MyTypeAliasStruct instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Name);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::TestProject.MyTypeAliasStruct instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Name = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.MyTypeAliasStruct @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, ref @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyTypeAliasStruct ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            var result = default(global::TestProject.MyTypeAliasStruct);\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, ref result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_MyTypeAliasStruct));\n            config.Copiers.Add(typeof(global::Orleans.Serialization.Cloning.ShallowCopier<global::TestProject.MyTypeAliasStruct>));\n            config.WellKnownTypeAliases.Add(\"_custom_type_alias_\", typeof(global::TestProject.MyTypeAliasClass));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData DeepCopy(global::TestProject.DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoData input, global::TestProject.DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData>\n    {\n        public global::TestProject.DemoData Create() => new global::TestProject.DemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithAnnotatedFields.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataWithFields : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataWithFields>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataWithFields>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataWithFields);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator;\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, int> getField0 = (global::System.Func<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, string> getField1 = (global::System.Func<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        public Codec_DemoDataWithFields(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataWithFields instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, getField0(instance));\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, getField1(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataWithFields instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    setField1(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataWithFields @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataWithFields))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithFields ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataWithFields, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataWithFields>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataWithFields : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataWithFields>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataWithFields>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator;\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, int> getField0 = (global::System.Func<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, string> getField1 = (global::System.Func<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithFields DeepCopy(global::TestProject.DemoDataWithFields original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataWithFields existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataWithFields))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoDataWithFields(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataWithFields input, global::TestProject.DemoDataWithFields output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, getField0(input));\n            setField1(output, getField1(input));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataWithFields));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataWithFields));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_PublicDemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.PublicDemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.PublicDemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.PublicDemoData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.PublicDemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.PublicDemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.PublicDemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.PublicDemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.PublicDemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.PublicDemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.PublicDemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.PublicDemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_PublicDemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.PublicDemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.PublicDemoData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.PublicDemoData DeepCopy(global::TestProject.PublicDemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.PublicDemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.PublicDemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.PublicDemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.PublicDemoData input, global::TestProject.PublicDemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_PublicDemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.PublicDemoData>\n    {\n        public global::TestProject.PublicDemoData Create() => new global::TestProject.PublicDemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Codec_InternalDemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.InternalDemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.InternalDemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.InternalDemoData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.InternalDemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.InternalDemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.InternalDemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.InternalDemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.InternalDemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.InternalDemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.InternalDemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.InternalDemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Copier_InternalDemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.InternalDemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.InternalDemoData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.InternalDemoData DeepCopy(global::TestProject.InternalDemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.InternalDemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.InternalDemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.InternalDemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.InternalDemoData input, global::TestProject.InternalDemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_InternalDemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.InternalDemoData>\n    {\n        public global::TestProject.InternalDemoData Create() => new global::TestProject.InternalDemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_PublicDemoData));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_InternalDemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_PublicDemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_InternalDemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_PublicDemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_InternalDemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithFields.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataWithFields : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataWithFields>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataWithFields>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataWithFields);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator;\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, int> getField0 = (global::System.Func<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, string> getField1 = (global::System.Func<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        public Codec_DemoDataWithFields(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataWithFields instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, getField0(instance));\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, getField1(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataWithFields instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    setField1(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataWithFields @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataWithFields))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithFields ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataWithFields, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataWithFields>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataWithFields : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataWithFields>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataWithFields>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator;\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, int> getField0 = (global::System.Func<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithFields, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_intValue\");\n        private static readonly global::System.Func<global::TestProject.DemoDataWithFields, string> getField1 = (global::System.Func<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithFields, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithFields, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithFields), \"_stringValue\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithFields DeepCopy(global::TestProject.DemoDataWithFields original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataWithFields existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataWithFields))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoDataWithFields(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithFields> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataWithFields input, global::TestProject.DemoDataWithFields output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, getField0(input));\n            setField1(output, getField1(input));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataWithFields));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataWithFields));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInheritance.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_BaseData : global::Orleans.Serialization.Serializers.AbstractTypeSerializer<global::TestProject.BaseData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public override void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.BaseData instance)\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.BaseValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public override void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.BaseData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.BaseValue = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_BaseData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.BaseData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.BaseData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.BaseData DeepCopy(global::TestProject.BaseData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            return context.DeepCopy(original);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.BaseData input, global::TestProject.BaseData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.BaseValue = input.BaseValue;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DerivedData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DerivedData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DerivedData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DerivedData);\n        private readonly OrleansCodeGen.TestProject.Codec_BaseData _baseTypeSerializer;\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DerivedData> _activator;\n        public Codec_DerivedData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::TestProject.DerivedData> _activator)\n        {\n            _baseTypeSerializer = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_BaseData>(this, codecProvider);\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DerivedData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.DerivedValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DerivedData instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 1U)\n                {\n                    instance.DerivedValue = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id++;\n                }\n\n                reader.ConsumeUnknownField(ref header);\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DerivedData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DerivedData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DerivedData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DerivedData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DerivedData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DerivedData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DerivedData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DerivedData>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_BaseData _baseTypeCopier;\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DerivedData> _activator;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DerivedData DeepCopy(global::TestProject.DerivedData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DerivedData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DerivedData))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DerivedData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider, global::Orleans.Serialization.Activators.IActivator<global::TestProject.DerivedData> _activator)\n        {\n            _baseTypeCopier = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_BaseData>(this, codecProvider);\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DerivedData input, global::TestProject.DerivedData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n            output.DerivedValue = input.DerivedValue;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_BaseData));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DerivedData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_BaseData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DerivedData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithInitOnlyProperty.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataWithInitOnly : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataWithInitOnly>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataWithInitOnly>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataWithInitOnly);\n        private static readonly global::System.Action<global::TestProject.DemoDataWithInitOnly, string> setField0 = (global::System.Action<global::TestProject.DemoDataWithInitOnly, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithInitOnly), \"<Value>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataWithInitOnly instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataWithInitOnly instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataWithInitOnly @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataWithInitOnly))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithInitOnly ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataWithInitOnly, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoDataWithInitOnly();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataWithInitOnly>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataWithInitOnly : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataWithInitOnly>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataWithInitOnly>\n    {\n        private static readonly global::System.Action<global::TestProject.DemoDataWithInitOnly, string> setField0 = (global::System.Action<global::TestProject.DemoDataWithInitOnly, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithInitOnly), \"<Value>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithInitOnly DeepCopy(global::TestProject.DemoDataWithInitOnly original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataWithInitOnly existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataWithInitOnly))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoDataWithInitOnly();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataWithInitOnly input, global::TestProject.DemoDataWithInitOnly output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, input.Value);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoDataWithInitOnly : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithInitOnly>\n    {\n        public global::TestProject.DemoDataWithInitOnly Create() => new global::TestProject.DemoDataWithInitOnly();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataWithInitOnly));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataWithInitOnly));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoDataWithInitOnly));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::DemoData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::DemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::DemoData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::DemoData DeepCopy(global::DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::DemoData))\n                return context.DeepCopy(original);\n            var result = new global::DemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::DemoData input, global::DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoData : global::Orleans.Serialization.Activators.IActivator<global::DemoData>\n    {\n        public global::DemoData Create() => new global::DemoData();\n    }\n}\n\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.Copier_DemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.Activator_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicGrain.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IBasicGrain), \"6B0E24A1\")]\n    public sealed class Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::TestProject.IBasicGrain _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IBasicGrain), \"SayHello\", null, new[] { typeof(string) });\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"SayHello\";\n        public override string GetInterfaceName() => \"TestProject.IBasicGrain\";\n        public override string GetActivityName() => \"IBasicGrain/SayHello\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IBasicGrain);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IBasicGrain)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.SayHello(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IBasicGrain : global::Orleans.Runtime.GrainReference, global::TestProject.IBasicGrain\n    {\n        public Proxy_IBasicGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IBasicGrain.SayHello(string arg0)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IBasicGrain_GrainReference_6B0E24A1 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 DeepCopy(OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_BasicGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.BasicGrain>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.BasicGrain>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.BasicGrain);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_BasicGrain(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.BasicGrain instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.BasicGrain instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.BasicGrain @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.BasicGrain))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.BasicGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.BasicGrain, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.BasicGrain();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.BasicGrain>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_BasicGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.BasicGrain>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.BasicGrain>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.BasicGrain DeepCopy(global::TestProject.BasicGrain original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.BasicGrain existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.BasicGrain))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.BasicGrain();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_BasicGrain(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.BasicGrain input, global::TestProject.BasicGrain output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_BasicGrain : global::Orleans.Serialization.Activators.IActivator<global::TestProject.BasicGrain>\n    {\n        public global::TestProject.BasicGrain Create() => new global::TestProject.BasicGrain();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IBasicGrain_GrainReference_6B0E24A1));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_BasicGrain));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IBasicGrain_GrainReference_6B0E24A1));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_BasicGrain));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IBasicGrain));\n            config.Interfaces.Add(typeof(global::TestProject.IBasicGrain));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.BasicGrain));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_BasicGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IBasicGrain));\n            n3.Add(\"6B0E24A1\", typeof(OrleansCodeGen.TestProject.Invokable_IBasicGrain_GrainReference_6B0E24A1));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IValueSerializer<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, ref @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            var result = default(global::TestProject.DemoData);\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, ref result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(global::Orleans.Serialization.Cloning.ShallowCopier<global::TestProject.DemoData>));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.CyclicClass);\n        private readonly global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.CyclicClass> _codec0;\n        private readonly global::System.Type _type1 = typeof(global::TestProject.NestedClass1);\n        private readonly global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.NestedClass1> _codec1;\n        private readonly global::System.Type _type2 = typeof(global::System.Collections.Generic.List<global::TestProject.NestedClass1>);\n        private readonly global::Orleans.Serialization.Codecs.ListCodec<global::TestProject.NestedClass1> _codec2;\n        public Codec_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.CyclicClass>>(this, codecProvider);\n            _codec1 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.NestedClass1>>(this, codecProvider);\n            _codec2 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ListCodec<global::TestProject.NestedClass1>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec1.WriteField(ref writer, 0U, _type1, instance.Nested1);\n            _codec2.WriteField(ref writer, 1U, _type2, instance.NestedList);\n            _codec0.WriteField(ref writer, 1U, _type0, instance.Cyclic);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Nested1 = _codec1.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.NestedList = _codec2.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 2U)\n                {\n                    instance.Cyclic = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoData>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.CyclicClass> _copier0;\n        private readonly global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.NestedClass1> _copier1;\n        private readonly global::Orleans.Serialization.Codecs.ListCopier<global::TestProject.NestedClass1> _copier2;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData DeepCopy(global::TestProject.DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.CyclicClass>>(this, codecProvider);\n            _copier1 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.NestedClass1>>(this, codecProvider);\n            _copier2 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ListCopier<global::TestProject.NestedClass1>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoData input, global::TestProject.DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Nested1 = _copier1.DeepCopy(input.Nested1, context);\n            output.NestedList = _copier2.DeepCopy(input.NestedList, context);\n            output.Cyclic = _copier0.DeepCopy(input.Cyclic, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData>\n    {\n        public global::TestProject.DemoData Create() => new global::TestProject.DemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        private readonly global::System.Type _type0 = typeof(int[]);\n        private readonly global::Orleans.Serialization.Codecs.ArrayCodec<int> _codec0;\n        public Codec_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ArrayCodec<int>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.IntProp);\n            global::Orleans.Serialization.Codecs.DoubleCodec.WriteField(ref writer, 1U, instance.DoubleProp);\n            global::Orleans.Serialization.Codecs.FloatCodec.WriteField(ref writer, 1U, instance.FloatProp);\n            global::Orleans.Serialization.Codecs.Int64Codec.WriteField(ref writer, 1U, instance.LongProp);\n            global::Orleans.Serialization.Codecs.BoolCodec.WriteField(ref writer, 1U, instance.BoolProp);\n            global::Orleans.Serialization.Codecs.ByteCodec.WriteField(ref writer, 1U, instance.ByteProp);\n            global::Orleans.Serialization.Codecs.Int16Codec.WriteField(ref writer, 1U, instance.ShortProp);\n            global::Orleans.Serialization.Codecs.CharCodec.WriteField(ref writer, 1U, instance.CharProp);\n            global::Orleans.Serialization.Codecs.UInt32Codec.WriteField(ref writer, 1U, instance.UIntProp);\n            global::Orleans.Serialization.Codecs.UInt64Codec.WriteField(ref writer, 1U, instance.ULongProp);\n            global::Orleans.Serialization.Codecs.UInt16Codec.WriteField(ref writer, 1U, instance.UShortProp);\n            global::Orleans.Serialization.Codecs.SByteCodec.WriteField(ref writer, 1U, instance.SByteProp);\n            global::Orleans.Serialization.Codecs.DecimalCodec.WriteField(ref writer, 1U, instance.DecimalProp);\n            global::Orleans.Serialization.Codecs.DateTimeCodec.WriteField(ref writer, 1U, instance.DateTimeProp);\n            global::Orleans.Serialization.Codecs.DateTimeOffsetCodec.WriteField(ref writer, 1U, instance.DateTimeOffsetProp);\n            global::Orleans.Serialization.Codecs.TimeSpanCodec.WriteField(ref writer, 1U, instance.TimeSpanProp);\n            global::Orleans.Serialization.Codecs.GuidCodec.WriteField(ref writer, 1U, instance.GuidProp);\n            _codec0.WriteField(ref writer, 1U, _type0, instance.IntArrayProp);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.IntProp = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.DoubleProp = global::Orleans.Serialization.Codecs.DoubleCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 2U)\n                {\n                    instance.FloatProp = global::Orleans.Serialization.Codecs.FloatCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 3U)\n                {\n                    instance.LongProp = global::Orleans.Serialization.Codecs.Int64Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 4U)\n                {\n                    instance.BoolProp = global::Orleans.Serialization.Codecs.BoolCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 5U)\n                {\n                    instance.ByteProp = global::Orleans.Serialization.Codecs.ByteCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 6U)\n                {\n                    instance.ShortProp = global::Orleans.Serialization.Codecs.Int16Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 7U)\n                {\n                    instance.CharProp = global::Orleans.Serialization.Codecs.CharCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 8U)\n                {\n                    instance.UIntProp = global::Orleans.Serialization.Codecs.UInt32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 9U)\n                {\n                    instance.ULongProp = global::Orleans.Serialization.Codecs.UInt64Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 10U)\n                {\n                    instance.UShortProp = global::Orleans.Serialization.Codecs.UInt16Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 11U)\n                {\n                    instance.SByteProp = global::Orleans.Serialization.Codecs.SByteCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 12U)\n                {\n                    instance.DecimalProp = global::Orleans.Serialization.Codecs.DecimalCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 13U)\n                {\n                    instance.DateTimeProp = global::Orleans.Serialization.Codecs.DateTimeCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 14U)\n                {\n                    instance.DateTimeOffsetProp = global::Orleans.Serialization.Codecs.DateTimeOffsetCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 15U)\n                {\n                    instance.TimeSpanProp = global::Orleans.Serialization.Codecs.TimeSpanCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 16U)\n                {\n                    instance.GuidProp = global::Orleans.Serialization.Codecs.GuidCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 17U)\n                {\n                    instance.IntArrayProp = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoData>\n    {\n        private readonly global::Orleans.Serialization.Codecs.ArrayCopier<int> _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData DeepCopy(global::TestProject.DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ArrayCopier<int>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoData input, global::TestProject.DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.IntProp = input.IntProp;\n            output.DoubleProp = input.DoubleProp;\n            output.FloatProp = input.FloatProp;\n            output.LongProp = input.LongProp;\n            output.BoolProp = input.BoolProp;\n            output.ByteProp = input.ByteProp;\n            output.ShortProp = input.ShortProp;\n            output.CharProp = input.CharProp;\n            output.UIntProp = input.UIntProp;\n            output.ULongProp = input.ULongProp;\n            output.UShortProp = input.UShortProp;\n            output.SByteProp = input.SByteProp;\n            output.DecimalProp = input.DecimalProp;\n            output.DateTimeProp = input.DateTimeProp;\n            output.DateTimeOffsetProp = input.DateTimeOffsetProp;\n            output.TimeSpanProp = input.TimeSpanProp;\n            output.GuidProp = input.GuidProp;\n            output.IntArrayProp = _copier0.DeepCopy(input.IntArrayProp, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData>\n    {\n        public global::TestProject.DemoData Create() => new global::TestProject.DemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        private readonly global::System.Type _type0 = typeof(int[]);\n        private readonly global::Orleans.Serialization.Codecs.ArrayCodec<int> _codec0;\n        public Codec_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ArrayCodec<int>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.IntProp);\n            global::Orleans.Serialization.Codecs.DoubleCodec.WriteField(ref writer, 1U, instance.DoubleProp);\n            global::Orleans.Serialization.Codecs.FloatCodec.WriteField(ref writer, 1U, instance.FloatProp);\n            global::Orleans.Serialization.Codecs.Int64Codec.WriteField(ref writer, 1U, instance.LongProp);\n            global::Orleans.Serialization.Codecs.BoolCodec.WriteField(ref writer, 1U, instance.BoolProp);\n            global::Orleans.Serialization.Codecs.ByteCodec.WriteField(ref writer, 1U, instance.ByteProp);\n            global::Orleans.Serialization.Codecs.Int16Codec.WriteField(ref writer, 1U, instance.ShortProp);\n            global::Orleans.Serialization.Codecs.CharCodec.WriteField(ref writer, 1U, instance.CharProp);\n            global::Orleans.Serialization.Codecs.UInt32Codec.WriteField(ref writer, 1U, instance.UIntProp);\n            global::Orleans.Serialization.Codecs.UInt64Codec.WriteField(ref writer, 1U, instance.ULongProp);\n            global::Orleans.Serialization.Codecs.UInt16Codec.WriteField(ref writer, 1U, instance.UShortProp);\n            global::Orleans.Serialization.Codecs.SByteCodec.WriteField(ref writer, 1U, instance.SByteProp);\n            global::Orleans.Serialization.Codecs.DecimalCodec.WriteField(ref writer, 1U, instance.DecimalProp);\n            global::Orleans.Serialization.Codecs.DateTimeCodec.WriteField(ref writer, 1U, instance.DateTimeProp);\n            global::Orleans.Serialization.Codecs.DateTimeOffsetCodec.WriteField(ref writer, 1U, instance.DateTimeOffsetProp);\n            global::Orleans.Serialization.Codecs.TimeSpanCodec.WriteField(ref writer, 1U, instance.TimeSpanProp);\n            global::Orleans.Serialization.Codecs.GuidCodec.WriteField(ref writer, 1U, instance.GuidProp);\n            _codec0.WriteField(ref writer, 1U, _type0, instance.IntArrayProp);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.IntProp = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.DoubleProp = global::Orleans.Serialization.Codecs.DoubleCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 2U)\n                {\n                    instance.FloatProp = global::Orleans.Serialization.Codecs.FloatCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 3U)\n                {\n                    instance.LongProp = global::Orleans.Serialization.Codecs.Int64Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 4U)\n                {\n                    instance.BoolProp = global::Orleans.Serialization.Codecs.BoolCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 5U)\n                {\n                    instance.ByteProp = global::Orleans.Serialization.Codecs.ByteCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 6U)\n                {\n                    instance.ShortProp = global::Orleans.Serialization.Codecs.Int16Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 7U)\n                {\n                    instance.CharProp = global::Orleans.Serialization.Codecs.CharCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 8U)\n                {\n                    instance.UIntProp = global::Orleans.Serialization.Codecs.UInt32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 9U)\n                {\n                    instance.ULongProp = global::Orleans.Serialization.Codecs.UInt64Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 10U)\n                {\n                    instance.UShortProp = global::Orleans.Serialization.Codecs.UInt16Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 11U)\n                {\n                    instance.SByteProp = global::Orleans.Serialization.Codecs.SByteCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 12U)\n                {\n                    instance.DecimalProp = global::Orleans.Serialization.Codecs.DecimalCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 13U)\n                {\n                    instance.DateTimeProp = global::Orleans.Serialization.Codecs.DateTimeCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 14U)\n                {\n                    instance.DateTimeOffsetProp = global::Orleans.Serialization.Codecs.DateTimeOffsetCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 15U)\n                {\n                    instance.TimeSpanProp = global::Orleans.Serialization.Codecs.TimeSpanCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 16U)\n                {\n                    instance.GuidProp = global::Orleans.Serialization.Codecs.GuidCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 17U)\n                {\n                    instance.IntArrayProp = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoData>\n    {\n        private readonly global::Orleans.Serialization.Codecs.ArrayCopier<int> _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData DeepCopy(global::TestProject.DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.ArrayCopier<int>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoData input, global::TestProject.DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.IntProp = input.IntProp;\n            output.DoubleProp = input.DoubleProp;\n            output.FloatProp = input.FloatProp;\n            output.LongProp = input.LongProp;\n            output.BoolProp = input.BoolProp;\n            output.ByteProp = input.ByteProp;\n            output.ShortProp = input.ShortProp;\n            output.CharProp = input.CharProp;\n            output.UIntProp = input.UIntProp;\n            output.ULongProp = input.ULongProp;\n            output.UShortProp = input.UShortProp;\n            output.SByteProp = input.SByteProp;\n            output.DecimalProp = input.DecimalProp;\n            output.DateTimeProp = input.DateTimeProp;\n            output.DateTimeOffsetProp = input.DateTimeOffsetProp;\n            output.TimeSpanProp = input.TimeSpanProp;\n            output.GuidProp = input.GuidProp;\n            output.IntArrayProp = _copier0.DeepCopy(input.IntArrayProp, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData>\n    {\n        public global::TestProject.DemoData Create() => new global::TestProject.DemoData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassReferenceProperties.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoData);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoData, string> setField2 = (global::System.Action<global::TestProject.DemoData, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoData), \"<RequiredStringPropInitOnly>k__BackingField\");\n        public Codec_DemoData(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.NullableStringProp);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.StringProp);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.RequiredStringProp);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.RequiredStringPropInitOnly);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.NullableStringProp = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.StringProp = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 2U)\n                {\n                    instance.RequiredStringProp = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 3U)\n                {\n                    setField2(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoData>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoData, string> setField2 = (global::System.Action<global::TestProject.DemoData, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoData), \"<RequiredStringPropInitOnly>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoData DeepCopy(global::TestProject.DemoData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoData))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoData(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoData> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoData input, global::TestProject.DemoData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.NullableStringProp = input.NullableStringProp;\n            output.StringProp = input.StringProp;\n            output.RequiredStringProp = input.RequiredStringProp;\n            setField2(output, input.RequiredStringPropInitOnly);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoData));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithConstructorParameters.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataWithCtorParams : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataWithCtorParams>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataWithCtorParams>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataWithCtorParams);GenericDemoDataWithCtorParams\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithCtorParams> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataWithCtorParams, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithCtorParams), \"<IntValue>k__BackingField\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithCtorParams, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithCtorParams), \"<Value>k__BackingField\");\n        public Codec_DemoDataWithCtorParams(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithCtorParams> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataWithCtorParams instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 1U, instance.IntValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataWithCtorParams instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField1(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataWithCtorParams @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataWithCtorParams))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithCtorParams ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataWithCtorParams, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataWithCtorParams>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataWithCtorParams : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataWithCtorParams>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataWithCtorParams>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithCtorParams> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataWithCtorParams, int> setField0 = (global::System.Action<global::TestProject.DemoDataWithCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithCtorParams), \"<IntValue>k__BackingField\");\n        private static readonly global::System.Action<global::TestProject.DemoDataWithCtorParams, string> setField1 = (global::System.Action<global::TestProject.DemoDataWithCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataWithCtorParams), \"<Value>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataWithCtorParams DeepCopy(global::TestProject.DemoDataWithCtorParams original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataWithCtorParams existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataWithCtorParams))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoDataWithCtorParams(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataWithCtorParams> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataWithCtorParams input, global::TestProject.DemoDataWithCtorParams output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField1(output, input.Value);\n            setField0(output, input.IntValue);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataWithCtorParams));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataWithCtorParams));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithFieldAndNoSetters.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ExternalType : global::Orleans.Serialization.Codecs.IFieldCodec<global::ExternalType>, global::Orleans.Serialization.Serializers.IBaseCodec<global::ExternalType>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::ExternalType);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::ExternalType> _activator;\n        private static readonly global::System.Func<global::ExternalType, int> getField0 = (global::System.Func<global::ExternalType, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::ExternalType), \"Amount\");\n        private static readonly global::System.Action<global::ExternalType, int> setField0 = (global::System.Action<global::ExternalType, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::ExternalType), \"Amount\");\n        public Codec_ExternalType(global::Orleans.Serialization.Activators.IActivator<global::ExternalType> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::ExternalType instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, getField0(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::ExternalType instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::ExternalType @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::ExternalType))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::ExternalType ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::ExternalType, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::ExternalType>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ExternalType : global::Orleans.Serialization.Cloning.IDeepCopier<global::ExternalType>, global::Orleans.Serialization.Cloning.IBaseCopier<global::ExternalType>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::ExternalType> _activator;\n        private static readonly global::System.Func<global::ExternalType, int> getField0 = (global::System.Func<global::ExternalType, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::ExternalType), \"Amount\");\n        private static readonly global::System.Action<global::ExternalType, int> setField0 = (global::System.Action<global::ExternalType, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::ExternalType), \"Amount\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::ExternalType DeepCopy(global::ExternalType original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::ExternalType existing))\n                return existing;\n            if (original.GetType() != typeof(global::ExternalType))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_ExternalType(global::Orleans.Serialization.Activators.IActivator<global::ExternalType> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::ExternalType input, global::ExternalType output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, getField0(input));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ExternalType : global::Orleans.Serialization.Activators.IActivator<global::ExternalType>\n    {\n        private readonly int _arg0;\n        public Activator_ExternalType(int arg0)\n        {\n            _arg0 = OrleansGeneratedCodeHelper.UnwrapService(this, arg0);\n        }\n\n        public global::ExternalType Create() => new global::ExternalType(_arg0);\n    }\n}\n\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.Codec_ExternalType));\n            config.Copiers.Add(typeof(OrleansCodeGen.Copier_ExternalType));\n            config.Activators.Add(typeof(OrleansCodeGen.Activator_ExternalType));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateMethodSerializersAnnotation.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::IMyGrain), \"6D39E404\")]\n    public sealed class Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::IMyGrain _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::IMyGrain), \"SayHello\", null, new[] { typeof(string) });\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"SayHello\";\n        public override string GetInterfaceName() => \"IMyGrain\";\n        public override string GetActivityName() => \"IMyGrain/SayHello\";\n        public override global::System.Type GetInterfaceType() => typeof(global::IMyGrain);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::IMyGrain)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.SayHello(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IMyGrain : global::Orleans.Runtime.GrainReference, global::IMyGrain\n    {\n        public Proxy_IMyGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::IMyGrain.SayHello(string arg0)\n        {\n            var request = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IMyGrain_GrainReference_6D39E404 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 DeepCopy(OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n}\n\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.Codec_Invokable_IMyGrain_GrainReference_6D39E404));\n            config.Copiers.Add(typeof(OrleansCodeGen.Copier_Invokable_IMyGrain_GrainReference_6D39E404));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.Proxy_IMyGrain));\n            config.Interfaces.Add(typeof(global::IMyGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::IMyGrain));\n            n3.Add(\"6D39E404\", typeof(OrleansCodeGen.Invokable_IMyGrain_GrainReference_6D39E404));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_MyCustomEnum : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.MyCustomEnum>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.MyCustomEnum);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.MyCustomEnum @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, fieldIdDelta, expectedType, (int)@value, _codecFieldType);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyCustomEnum ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            return (global::TestProject.MyCustomEnum)global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ClassWithImplicitFieldIds : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.ClassWithImplicitFieldIds>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.ClassWithImplicitFieldIds>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.ClassWithImplicitFieldIds);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.MyCustomEnum);\n        private readonly OrleansCodeGen.TestProject.Codec_MyCustomEnum _codec0;\n        public Codec_ClassWithImplicitFieldIds(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_MyCustomEnum>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.ClassWithImplicitFieldIds instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 19816600U, _type0, instance.EnumValue);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1774218397U, instance.StringValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.ClassWithImplicitFieldIds instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 19816600U)\n                {\n                    instance.EnumValue = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1794034997U)\n                {\n                    instance.StringValue = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id++;\n                }\n\n                reader.ConsumeUnknownField(ref header);\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.ClassWithImplicitFieldIds @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.ClassWithImplicitFieldIds))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ClassWithImplicitFieldIds ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.ClassWithImplicitFieldIds, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.ClassWithImplicitFieldIds();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.ClassWithImplicitFieldIds>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ClassWithImplicitFieldIds : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.ClassWithImplicitFieldIds>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.ClassWithImplicitFieldIds>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ClassWithImplicitFieldIds DeepCopy(global::TestProject.ClassWithImplicitFieldIds original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            return original is null || original.GetType() == typeof(global::TestProject.ClassWithImplicitFieldIds) ? original : context.DeepCopy(original);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.ClassWithImplicitFieldIds input, global::TestProject.ClassWithImplicitFieldIds output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.EnumValue = input.EnumValue;\n            output.StringValue = input.StringValue;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ClassWithImplicitFieldIds : global::Orleans.Serialization.Activators.IActivator<global::TestProject.ClassWithImplicitFieldIds>\n    {\n        public global::TestProject.ClassWithImplicitFieldIds Create() => new global::TestProject.ClassWithImplicitFieldIds();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_MyCustomEnum));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_ClassWithImplicitFieldIds));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_ClassWithImplicitFieldIds));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ClassWithImplicitFieldIds));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithInterfaceConstructorParameter.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_InterfaceCtorParam : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.InterfaceCtorParam>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.InterfaceCtorParam>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.InterfaceCtorParam);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.InterfaceCtorParam> _activator;\n        private readonly global::System.Type _type0 = typeof(global::TestProject.IMyInterface);\n        private readonly global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.IMyInterface> _codec0;\n        private static readonly global::System.Func<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface> getField0 = (global::System.Func<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.InterfaceCtorParam), \"_iface\");\n        private static readonly global::System.Action<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface> setField0 = (global::System.Action<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.InterfaceCtorParam), \"_iface\");\n        public Codec_InterfaceCtorParam(global::Orleans.Serialization.Activators.IActivator<global::TestProject.InterfaceCtorParam> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.IMyInterface>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.InterfaceCtorParam instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, getField0(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.InterfaceCtorParam instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, _codec0.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.InterfaceCtorParam @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.InterfaceCtorParam))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.InterfaceCtorParam ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.InterfaceCtorParam, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.InterfaceCtorParam>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_InterfaceCtorParam : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.InterfaceCtorParam>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.InterfaceCtorParam>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.InterfaceCtorParam> _activator;\n        private readonly global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.IMyInterface> _copier0;\n        private static readonly global::System.Func<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface> getField0 = (global::System.Func<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.InterfaceCtorParam), \"_iface\");\n        private static readonly global::System.Action<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface> setField0 = (global::System.Action<global::TestProject.InterfaceCtorParam, global::TestProject.IMyInterface>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.InterfaceCtorParam), \"_iface\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.InterfaceCtorParam DeepCopy(global::TestProject.InterfaceCtorParam original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.InterfaceCtorParam existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.InterfaceCtorParam))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_InterfaceCtorParam(global::Orleans.Serialization.Activators.IActivator<global::TestProject.InterfaceCtorParam> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.IMyInterface>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.InterfaceCtorParam input, global::TestProject.InterfaceCtorParam output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, _copier0.DeepCopy(getField0(input), context));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_InterfaceCtorParam));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_InterfaceCtorParam));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithNoPublicConstructors.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_NoPublicCtor : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.NoPublicCtor>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.NoPublicCtor>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.NoPublicCtor);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.NoPublicCtor> _activator;\n        public Codec_NoPublicCtor(global::Orleans.Serialization.Activators.IActivator<global::TestProject.NoPublicCtor> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.NoPublicCtor instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.NoPublicCtor instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.NoPublicCtor @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.NoPublicCtor))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.NoPublicCtor ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.NoPublicCtor, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.NoPublicCtor>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_NoPublicCtor : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.NoPublicCtor>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.NoPublicCtor>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.NoPublicCtor> _activator;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.NoPublicCtor DeepCopy(global::TestProject.NoPublicCtor original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.NoPublicCtor existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.NoPublicCtor))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_NoPublicCtor(global::Orleans.Serialization.Activators.IActivator<global::TestProject.NoPublicCtor> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.NoPublicCtor input, global::TestProject.NoPublicCtor output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_NoPublicCtor));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_NoPublicCtor));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithOptionalConstructorParameters.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_OptionalCtorParams : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.OptionalCtorParams>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.OptionalCtorParams>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.OptionalCtorParams);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.OptionalCtorParams> _activator;\n        private static readonly global::System.Func<global::TestProject.OptionalCtorParams, int> getField0 = (global::System.Func<global::TestProject.OptionalCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.OptionalCtorParams), \"_x\");\n        private static readonly global::System.Action<global::TestProject.OptionalCtorParams, int> setField0 = (global::System.Action<global::TestProject.OptionalCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.OptionalCtorParams), \"_x\");\n        private static readonly global::System.Func<global::TestProject.OptionalCtorParams, string> getField1 = (global::System.Func<global::TestProject.OptionalCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.OptionalCtorParams), \"_y\");\n        private static readonly global::System.Action<global::TestProject.OptionalCtorParams, string> setField1 = (global::System.Action<global::TestProject.OptionalCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.OptionalCtorParams), \"_y\");\n        public Codec_OptionalCtorParams(global::Orleans.Serialization.Activators.IActivator<global::TestProject.OptionalCtorParams> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.OptionalCtorParams instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, getField0(instance));\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, getField1(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.OptionalCtorParams instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    setField1(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.OptionalCtorParams @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.OptionalCtorParams))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.OptionalCtorParams ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.OptionalCtorParams, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.OptionalCtorParams>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_OptionalCtorParams : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.OptionalCtorParams>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.OptionalCtorParams>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.OptionalCtorParams> _activator;\n        private static readonly global::System.Func<global::TestProject.OptionalCtorParams, int> getField0 = (global::System.Func<global::TestProject.OptionalCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.OptionalCtorParams), \"_x\");\n        private static readonly global::System.Action<global::TestProject.OptionalCtorParams, int> setField0 = (global::System.Action<global::TestProject.OptionalCtorParams, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.OptionalCtorParams), \"_x\");\n        private static readonly global::System.Func<global::TestProject.OptionalCtorParams, string> getField1 = (global::System.Func<global::TestProject.OptionalCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.OptionalCtorParams), \"_y\");\n        private static readonly global::System.Action<global::TestProject.OptionalCtorParams, string> setField1 = (global::System.Action<global::TestProject.OptionalCtorParams, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.OptionalCtorParams), \"_y\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.OptionalCtorParams DeepCopy(global::TestProject.OptionalCtorParams original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.OptionalCtorParams existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.OptionalCtorParams))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_OptionalCtorParams(global::Orleans.Serialization.Activators.IActivator<global::TestProject.OptionalCtorParams> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.OptionalCtorParams input, global::TestProject.OptionalCtorParams output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, getField0(input));\n            setField1(output, getField1(input));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_OptionalCtorParams));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_OptionalCtorParams));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_MyServiceConsumer : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.MyServiceConsumer>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.MyServiceConsumer>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.MyServiceConsumer);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyServiceConsumer> _activator;\n        public Codec_MyServiceConsumer(global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyServiceConsumer> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.MyServiceConsumer instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Name);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.MyServiceConsumer instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Name = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.MyServiceConsumer @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.MyServiceConsumer))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyServiceConsumer ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.MyServiceConsumer, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.MyServiceConsumer>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_MyServiceConsumer : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.MyServiceConsumer>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.MyServiceConsumer>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyServiceConsumer> _activator;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyServiceConsumer DeepCopy(global::TestProject.MyServiceConsumer original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.MyServiceConsumer existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.MyServiceConsumer))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_MyServiceConsumer(global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyServiceConsumer> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.MyServiceConsumer input, global::TestProject.MyServiceConsumer output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Name = input.Name;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_RootType : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.RootType>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.RootType>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.RootType);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.MyServiceConsumer);\n        private readonly OrleansCodeGen.TestProject.Codec_MyServiceConsumer _codec0;\n        public Codec_RootType(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_MyServiceConsumer>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.RootType instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, instance.Consumer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.RootType instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Consumer = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.RootType @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.RootType))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.RootType ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.RootType, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.RootType();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.RootType>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_RootType : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.RootType>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.RootType>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_MyServiceConsumer _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.RootType DeepCopy(global::TestProject.RootType original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.RootType existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.RootType))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.RootType();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_RootType(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_MyServiceConsumer>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.RootType input, global::TestProject.RootType output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Consumer = _copier0.DeepCopy(input.Consumer, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_RootType : global::Orleans.Serialization.Activators.IActivator<global::TestProject.RootType>\n    {\n        public global::TestProject.RootType Create() => new global::TestProject.RootType();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_MyServiceConsumer));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_RootType));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_MyServiceConsumer));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_RootType));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_RootType));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ClassWithGeneratedActivatorConstructor : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.ClassWithGeneratedActivatorConstructor>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.ClassWithGeneratedActivatorConstructor>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.ClassWithGeneratedActivatorConstructor);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.ClassWithGeneratedActivatorConstructor instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.Value);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.Name);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.ClassWithGeneratedActivatorConstructor instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.Name = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.ClassWithGeneratedActivatorConstructor @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.ClassWithGeneratedActivatorConstructor))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ClassWithGeneratedActivatorConstructor ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.ClassWithGeneratedActivatorConstructor, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.ClassWithGeneratedActivatorConstructor();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.ClassWithGeneratedActivatorConstructor>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ClassWithGeneratedActivatorConstructor : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.ClassWithGeneratedActivatorConstructor>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.ClassWithGeneratedActivatorConstructor>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ClassWithGeneratedActivatorConstructor DeepCopy(global::TestProject.ClassWithGeneratedActivatorConstructor original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.ClassWithGeneratedActivatorConstructor existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.ClassWithGeneratedActivatorConstructor))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.ClassWithGeneratedActivatorConstructor();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.ClassWithGeneratedActivatorConstructor input, global::TestProject.ClassWithGeneratedActivatorConstructor output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n            output.Name = input.Name;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ClassWithGeneratedActivatorConstructor : global::Orleans.Serialization.Activators.IActivator<global::TestProject.ClassWithGeneratedActivatorConstructor>\n    {\n        public global::TestProject.ClassWithGeneratedActivatorConstructor Create() => new global::TestProject.ClassWithGeneratedActivatorConstructor();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_ClassWithGeneratedActivatorConstructor));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_ClassWithGeneratedActivatorConstructor));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ClassWithGeneratedActivatorConstructor));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_MyCompoundTypeAliasBaseClass : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.MyCompoundTypeAliasBaseClass>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.MyCompoundTypeAliasBaseClass>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.MyCompoundTypeAliasBaseClass);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.MyCompoundTypeAliasBaseClass instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.BaseValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.MyCompoundTypeAliasBaseClass instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.BaseValue = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.MyCompoundTypeAliasBaseClass @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.MyCompoundTypeAliasBaseClass))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyCompoundTypeAliasBaseClass ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.MyCompoundTypeAliasBaseClass, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.MyCompoundTypeAliasBaseClass();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.MyCompoundTypeAliasBaseClass>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_MyCompoundTypeAliasBaseClass : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.MyCompoundTypeAliasBaseClass>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.MyCompoundTypeAliasBaseClass>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyCompoundTypeAliasBaseClass DeepCopy(global::TestProject.MyCompoundTypeAliasBaseClass original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.MyCompoundTypeAliasBaseClass existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.MyCompoundTypeAliasBaseClass))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.MyCompoundTypeAliasBaseClass();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.MyCompoundTypeAliasBaseClass input, global::TestProject.MyCompoundTypeAliasBaseClass output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.BaseValue = input.BaseValue;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_MyCompoundTypeAliasBaseClass : global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyCompoundTypeAliasBaseClass>\n    {\n        public global::TestProject.MyCompoundTypeAliasBaseClass Create() => new global::TestProject.MyCompoundTypeAliasBaseClass();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_MyCompoundTypeAliasClass : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.MyCompoundTypeAliasClass>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.MyCompoundTypeAliasClass>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.MyCompoundTypeAliasClass);\n        private readonly OrleansCodeGen.TestProject.Codec_MyCompoundTypeAliasBaseClass _baseTypeSerializer;\n        public Codec_MyCompoundTypeAliasClass(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _baseTypeSerializer = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_MyCompoundTypeAliasBaseClass>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.MyCompoundTypeAliasClass instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Name);\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 1U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.MyCompoundTypeAliasClass instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Name = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.MyCompoundTypeAliasClass @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.MyCompoundTypeAliasClass))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyCompoundTypeAliasClass ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.MyCompoundTypeAliasClass, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.MyCompoundTypeAliasClass();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.MyCompoundTypeAliasClass>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_MyCompoundTypeAliasClass : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.MyCompoundTypeAliasClass>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.MyCompoundTypeAliasClass>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_MyCompoundTypeAliasBaseClass _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.MyCompoundTypeAliasClass DeepCopy(global::TestProject.MyCompoundTypeAliasClass original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.MyCompoundTypeAliasClass existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.MyCompoundTypeAliasClass))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.MyCompoundTypeAliasClass();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_MyCompoundTypeAliasClass(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _baseTypeCopier = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_MyCompoundTypeAliasBaseClass>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.MyCompoundTypeAliasClass input, global::TestProject.MyCompoundTypeAliasClass output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n            output.Name = input.Name;\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_MyCompoundTypeAliasClass : global::Orleans.Serialization.Activators.IActivator<global::TestProject.MyCompoundTypeAliasClass>\n    {\n        public global::TestProject.MyCompoundTypeAliasClass Create() => new global::TestProject.MyCompoundTypeAliasClass();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_MyCompoundTypeAliasBaseClass));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_MyCompoundTypeAliasClass));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_MyCompoundTypeAliasBaseClass));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_MyCompoundTypeAliasClass));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_MyCompoundTypeAliasBaseClass));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_MyCompoundTypeAliasClass));\n            config.WellKnownTypeAliases.Add(\"_custom_type_alias_\", typeof(global::TestProject.MyTypeAliasClass));\n            var n1 = config.CompoundTypeAliases.Add(\"xx_test_xx\");\n            var n2 = n1.Add(typeof(global::TestProject.MyTypeAliasClass));\n            var n3 = n2.Add(typeof( int ));\n            n3.Add(\"1\", typeof(global::TestProject.MyCompoundTypeAliasClass));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GenericData<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GenericData<T>>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GenericData<T>>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GenericData<T>);\n        private readonly global::System.Type _type0 = typeof(T);\n        private readonly global::Orleans.Serialization.Codecs.IFieldCodec<T> _codec0;\n        public Codec_GenericData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.IFieldCodec<T>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GenericData<T> instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, instance.Value);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.Description);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GenericData<T> instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.Description = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GenericData<T> @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GenericData<T>))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GenericData<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GenericData<T>, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.GenericData<T>();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GenericData<T>>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GenericData<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GenericData<T>>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GenericData<T>>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IDeepCopier<T> _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GenericData<T> DeepCopy(global::TestProject.GenericData<T> original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GenericData<T> existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GenericData<T>))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.GenericData<T>();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GenericData(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Cloning.IDeepCopier<T>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GenericData<T> input, global::TestProject.GenericData<T> output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = _copier0.DeepCopy(input.Value, context);\n            output.Description = input.Description;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_GenericData<T> : global::Orleans.Serialization.Activators.IActivator<global::TestProject.GenericData<T>>\n    {\n        public global::TestProject.GenericData<T> Create() => new global::TestProject.GenericData<T>();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ConcreteUsage : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.ConcreteUsage>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.ConcreteUsage>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.ConcreteUsage);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.GenericData<int>);\n        private readonly OrleansCodeGen.TestProject.Codec_GenericData<int> _codec0;\n        private readonly global::System.Type _type1 = typeof(global::TestProject.GenericData<string>);\n        private readonly OrleansCodeGen.TestProject.Codec_GenericData<string> _codec1;\n        public Codec_ConcreteUsage(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_GenericData<int>>(this, codecProvider);\n            _codec1 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_GenericData<string>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.ConcreteUsage instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, instance.IntData);\n            _codec1.WriteField(ref writer, 1U, _type1, instance.StringData);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.ConcreteUsage instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.IntData = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.StringData = _codec1.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.ConcreteUsage @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.ConcreteUsage))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ConcreteUsage ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.ConcreteUsage, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.ConcreteUsage();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.ConcreteUsage>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ConcreteUsage : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.ConcreteUsage>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.ConcreteUsage>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_GenericData<int> _copier0;\n        private readonly OrleansCodeGen.TestProject.Copier_GenericData<string> _copier1;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ConcreteUsage DeepCopy(global::TestProject.ConcreteUsage original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.ConcreteUsage existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.ConcreteUsage))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.ConcreteUsage();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_ConcreteUsage(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_GenericData<int>>(this, codecProvider);\n            _copier1 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_GenericData<string>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.ConcreteUsage input, global::TestProject.ConcreteUsage output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.IntData = _copier0.DeepCopy(input.IntData, context);\n            output.StringData = _copier1.DeepCopy(input.StringData, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ConcreteUsage : global::Orleans.Serialization.Activators.IActivator<global::TestProject.ConcreteUsage>\n    {\n        public global::TestProject.ConcreteUsage Create() => new global::TestProject.ConcreteUsage();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GenericData<>));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_ConcreteUsage));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GenericData<>));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_ConcreteUsage));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GenericData<>));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ConcreteUsage));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GenericWithCtor<T> : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GenericWithCtor<T>>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GenericWithCtor<T>>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GenericWithCtor<T>);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.GenericWithCtor<T>> _activator;\n        private readonly global::System.Type _type0 = typeof(T);\n        private readonly global::Orleans.Serialization.Codecs.IFieldCodec<T> _codec0;\n        private static readonly global::System.Func<global::TestProject.GenericWithCtor<T>, int> getField0 = (global::System.Func<global::TestProject.GenericWithCtor<T>, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.GenericWithCtor<T>), \"_id\");\n        private static readonly global::System.Action<global::TestProject.GenericWithCtor<T>, int> setField0 = (global::System.Action<global::TestProject.GenericWithCtor<T>, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.GenericWithCtor<T>), \"_id\");\n        private static readonly global::System.Func<global::TestProject.GenericWithCtor<T>, T> getField1 = (global::System.Func<global::TestProject.GenericWithCtor<T>, T>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.GenericWithCtor<T>), \"_value\");\n        private static readonly global::System.Action<global::TestProject.GenericWithCtor<T>, T> setField1 = (global::System.Action<global::TestProject.GenericWithCtor<T>, T>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.GenericWithCtor<T>), \"_value\");\n        public Codec_GenericWithCtor(global::Orleans.Serialization.Activators.IActivator<global::TestProject.GenericWithCtor<T>> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n            _codec0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Codecs.IFieldCodec<T>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GenericWithCtor<T> instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, getField1(instance));\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 1U, getField0(instance));\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GenericWithCtor<T> instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    setField1(instance, _codec0.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    setField0(instance, global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header));\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GenericWithCtor<T> @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GenericWithCtor<T>))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GenericWithCtor<T> ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GenericWithCtor<T>, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GenericWithCtor<T>>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GenericWithCtor<T> : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GenericWithCtor<T>>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GenericWithCtor<T>>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.GenericWithCtor<T>> _activator;\n        private readonly global::Orleans.Serialization.Cloning.IDeepCopier<T> _copier0;\n        private static readonly global::System.Func<global::TestProject.GenericWithCtor<T>, int> getField0 = (global::System.Func<global::TestProject.GenericWithCtor<T>, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.GenericWithCtor<T>), \"_id\");\n        private static readonly global::System.Action<global::TestProject.GenericWithCtor<T>, int> setField0 = (global::System.Action<global::TestProject.GenericWithCtor<T>, int>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.GenericWithCtor<T>), \"_id\");\n        private static readonly global::System.Func<global::TestProject.GenericWithCtor<T>, T> getField1 = (global::System.Func<global::TestProject.GenericWithCtor<T>, T>)global::Orleans.Serialization.Utilities.FieldAccessor.GetGetter(typeof(global::TestProject.GenericWithCtor<T>), \"_value\");\n        private static readonly global::System.Action<global::TestProject.GenericWithCtor<T>, T> setField1 = (global::System.Action<global::TestProject.GenericWithCtor<T>, T>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.GenericWithCtor<T>), \"_value\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GenericWithCtor<T> DeepCopy(global::TestProject.GenericWithCtor<T> original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GenericWithCtor<T> existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GenericWithCtor<T>))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GenericWithCtor(global::Orleans.Serialization.Activators.IActivator<global::TestProject.GenericWithCtor<T>> _activator, global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n            _copier0 = OrleansGeneratedCodeHelper.GetService<global::Orleans.Serialization.Cloning.IDeepCopier<T>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GenericWithCtor<T> input, global::TestProject.GenericWithCtor<T> output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField1(output, _copier0.DeepCopy(getField1(input), context));\n            setField0(output, getField0(input));\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_UsesGenericWithCtor : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.UsesGenericWithCtor>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.UsesGenericWithCtor>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.UsesGenericWithCtor);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.GenericWithCtor<string>);\n        private readonly OrleansCodeGen.TestProject.Codec_GenericWithCtor<string> _codec0;\n        public Codec_UsesGenericWithCtor(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_GenericWithCtor<string>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.UsesGenericWithCtor instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _codec0.WriteField(ref writer, 0U, _type0, instance.StringGen);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.UsesGenericWithCtor instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.StringGen = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.UsesGenericWithCtor @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.UsesGenericWithCtor))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.UsesGenericWithCtor ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.UsesGenericWithCtor, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.UsesGenericWithCtor();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.UsesGenericWithCtor>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_UsesGenericWithCtor : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.UsesGenericWithCtor>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.UsesGenericWithCtor>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_GenericWithCtor<string> _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.UsesGenericWithCtor DeepCopy(global::TestProject.UsesGenericWithCtor original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.UsesGenericWithCtor existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.UsesGenericWithCtor))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.UsesGenericWithCtor();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_UsesGenericWithCtor(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_GenericWithCtor<string>>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.UsesGenericWithCtor input, global::TestProject.UsesGenericWithCtor output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.StringGen = _copier0.DeepCopy(input.StringGen, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_UsesGenericWithCtor : global::Orleans.Serialization.Activators.IActivator<global::TestProject.UsesGenericWithCtor>\n    {\n        public global::TestProject.UsesGenericWithCtor Create() => new global::TestProject.UsesGenericWithCtor();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GenericWithCtor<>));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_UsesGenericWithCtor));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GenericWithCtor<>));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_UsesGenericWithCtor));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_UsesGenericWithCtor));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IComplexGrain), \"67FE5808\")]\n    public sealed class Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Runtime.TaskRequest<global::TestProject.ComplexData>\n    {\n        public int arg0;\n        public string arg1;\n        public global::TestProject.ComplexData arg2;\n        public global::System.Threading.CancellationToken arg3;\n        global::TestProject.IComplexGrain _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IComplexGrain), \"ProcessData\", null, new[] { typeof(int), typeof(string), typeof(global::TestProject.ComplexData), typeof(global::System.Threading.CancellationToken) });\n        global::System.Threading.CancellationTokenSource _cts;\n        public override int GetArgumentCount() => 4;\n        public override string GetMethodName() => \"ProcessData\";\n        public override string GetInterfaceName() => \"TestProject.IComplexGrain\";\n        public override string GetActivityName() => \"IComplexGrain/ProcessData\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IComplexGrain);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder)\n        {\n            _target = (global::TestProject.IComplexGrain)holder.GetTarget();\n            _cts = new();\n            arg3 = _cts.Token;\n        }\n\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            arg1 = default;\n            arg2 = default;\n            arg3 = default;\n            _target = default;\n            _cts?.Dispose();\n            _cts = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                case 1:\n                    return arg1;\n                case 2:\n                    return arg2;\n                case 3:\n                    return arg3;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 3);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (int)value;\n                    return;\n                case 1:\n                    arg1 = (string)value;\n                    return;\n                case 2:\n                    arg2 = (global::TestProject.ComplexData)value;\n                    return;\n                case 3:\n                    arg3 = (global::System.Threading.CancellationToken)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 3);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<global::TestProject.ComplexData> InvokeInner() => _target.ProcessData(arg0, arg1, arg2, arg3);\n        public override global::System.Threading.CancellationToken GetCancellationToken() => arg3;\n        public override bool TryCancel()\n        {\n            if (_cts is { } cts)\n            {\n                cts.Cancel(false);\n                return true;\n            }\n\n            return false;\n        }\n\n        public override bool IsCancellable => true;\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IComplexGrain : global::Orleans.Runtime.GrainReference, global::TestProject.IComplexGrain\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_ComplexData _copier0;\n        public Proxy_IComplexGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_ComplexData>(this, CodecProvider);\n        }\n\n        global::System.Threading.Tasks.Task<global::TestProject.ComplexData> global::TestProject.IComplexGrain.ProcessData(int arg0, string arg1, global::TestProject.ComplexData arg2, global::System.Threading.CancellationToken arg3)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808();\n            request.arg0 = arg0;\n            request.arg1 = arg1;\n            using var copyContext = base.CopyContextPool.GetContext();\n            request.arg2 = _copier0.DeepCopy(arg2, copyContext);\n            request.arg3 = arg3;\n            return base.InvokeAsync<global::TestProject.ComplexData>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ComplexData : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.ComplexData>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.ComplexData>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.ComplexData);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.ComplexData instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.IntValue);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.StringValue);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.ComplexData instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.IntValue = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.StringValue = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.ComplexData @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.ComplexData))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ComplexData ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.ComplexData, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.ComplexData();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.ComplexData>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ComplexData : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.ComplexData>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.ComplexData>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ComplexData DeepCopy(global::TestProject.ComplexData original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.ComplexData existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.ComplexData))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.ComplexData();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.ComplexData input, global::TestProject.ComplexData output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.IntValue = input.IntValue;\n            output.StringValue = input.StringValue;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ComplexData : global::Orleans.Serialization.Activators.IActivator<global::TestProject.ComplexData>\n    {\n        public global::TestProject.ComplexData Create() => new global::TestProject.ComplexData();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808);\n        private readonly global::System.Type _type0 = typeof(global::TestProject.ComplexData);\n        private readonly OrleansCodeGen.TestProject.Codec_ComplexData _codec0;\n        public Codec_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _codec0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Codec_ComplexData>(this, codecProvider);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.Int32Codec.WriteField(ref writer, 0U, instance.arg0);\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 1U, instance.arg1);\n            _codec0.WriteField(ref writer, 1U, _type0, instance.arg2);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.Int32Codec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 1U)\n                {\n                    instance.arg1 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                }\n\n                if (id == 2U)\n                {\n                    instance.arg2 = _codec0.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IComplexGrain_GrainReference_67FE5808 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808>\n    {\n        private readonly OrleansCodeGen.TestProject.Copier_ComplexData _copier0;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 DeepCopy(OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808();\n            result.arg0 = original.arg0;\n            result.arg1 = original.arg1;\n            result.arg2 = _copier0.DeepCopy(original.arg2, context);\n            result.arg3 = original.arg3;\n            return result;\n        }\n\n        public Copier_Invokable_IComplexGrain_GrainReference_67FE5808(global::Orleans.Serialization.Serializers.ICodecProvider codecProvider)\n        {\n            _copier0 = OrleansGeneratedCodeHelper.GetService<OrleansCodeGen.TestProject.Copier_ComplexData>(this, codecProvider);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_ComplexGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.ComplexGrain>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.ComplexGrain>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.ComplexGrain);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_ComplexGrain(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.ComplexGrain instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.ComplexGrain instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.ComplexGrain @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.ComplexGrain))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ComplexGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.ComplexGrain, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.ComplexGrain();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.ComplexGrain>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_ComplexGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.ComplexGrain>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.ComplexGrain>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.ComplexGrain DeepCopy(global::TestProject.ComplexGrain original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.ComplexGrain existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.ComplexGrain))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.ComplexGrain();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_ComplexGrain(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.ComplexGrain input, global::TestProject.ComplexGrain output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_ComplexGrain : global::Orleans.Serialization.Activators.IActivator<global::TestProject.ComplexGrain>\n    {\n        public global::TestProject.ComplexGrain Create() => new global::TestProject.ComplexGrain();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_ComplexData));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IComplexGrain_GrainReference_67FE5808));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_ComplexGrain));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_ComplexData));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IComplexGrain_GrainReference_67FE5808));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_ComplexGrain));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IComplexGrain));\n            config.Interfaces.Add(typeof(global::TestProject.IComplexGrain));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.ComplexGrain));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ComplexData));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_ComplexGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IComplexGrain));\n            n3.Add(\"67FE5808\", typeof(OrleansCodeGen.TestProject.Invokable_IComplexGrain_GrainReference_67FE5808));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithInvokableBaseType.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IHelloGrain), \"5336307F\")]\n    public sealed class Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::TestProject.IHelloGrain _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IHelloGrain), \"SayHello\", null, new[] { typeof(string) });\n        public Invokable_IHelloGrain_GrainReference_5336307F() : base()\n        {\n            SetLoggingOptions(\"Hello\");\n        }\n\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"SayHello\";\n        public override string GetInterfaceName() => \"TestProject.IHelloGrain\";\n        public override string GetActivityName() => \"IHelloGrain/SayHello\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IHelloGrain);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IHelloGrain)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.SayHello(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IHelloGrain : global::Orleans.Runtime.GrainReference, global::TestProject.IHelloGrain\n    {\n        public Proxy_IHelloGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IHelloGrain.SayHello(string arg0)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IHelloGrain_GrainReference_5336307F : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F DeepCopy(OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_HelloGrain : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.HelloGrain>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.HelloGrain>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.HelloGrain);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_HelloGrain(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.HelloGrain instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.HelloGrain instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.HelloGrain @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.HelloGrain))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.HelloGrain ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.HelloGrain, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.HelloGrain();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.HelloGrain>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_HelloGrain : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.HelloGrain>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.HelloGrain>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.HelloGrain DeepCopy(global::TestProject.HelloGrain original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.HelloGrain existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.HelloGrain))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.HelloGrain();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_HelloGrain(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.HelloGrain input, global::TestProject.HelloGrain output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_HelloGrain : global::Orleans.Serialization.Activators.IActivator<global::TestProject.HelloGrain>\n    {\n        public global::TestProject.HelloGrain Create() => new global::TestProject.HelloGrain();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IHelloGrain_GrainReference_5336307F));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_HelloGrain));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IHelloGrain_GrainReference_5336307F));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_HelloGrain));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IHelloGrain));\n            config.Interfaces.Add(typeof(global::TestProject.IHelloGrain));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.HelloGrain));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_HelloGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IHelloGrain));\n            n3.Add(\"5336307F\", typeof(OrleansCodeGen.TestProject.Invokable_IHelloGrain_GrainReference_5336307F));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainMethodAnnotatedWithResponseTimeout.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IResponseTimeoutGrain), \"6BE752C8\")]\n    public sealed class Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::TestProject.IResponseTimeoutGrain _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IResponseTimeoutGrain), \"LongRunningMethod\", null, new[] { typeof(string) });\n        private static readonly global::System.TimeSpan _responseTimeoutValue = global::System.TimeSpan.FromTicks(100000000L);\n        public override global::System.TimeSpan? GetDefaultResponseTimeout() => _responseTimeoutValue;\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"LongRunningMethod\";\n        public override string GetInterfaceName() => \"TestProject.IResponseTimeoutGrain\";\n        public override string GetActivityName() => \"IResponseTimeoutGrain/LongRunningMethod\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IResponseTimeoutGrain);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IResponseTimeoutGrain)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.LongRunningMethod(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IResponseTimeoutGrain : global::Orleans.Runtime.GrainReference, global::TestProject.IResponseTimeoutGrain\n    {\n        public Proxy_IResponseTimeoutGrain(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IResponseTimeoutGrain.LongRunningMethod(string arg0)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 DeepCopy(OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IResponseTimeoutGrain));\n            config.Interfaces.Add(typeof(global::TestProject.IResponseTimeoutGrain));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.ResponseTimeoutGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IResponseTimeoutGrain));\n            n3.Add(\"6BE752C8\", typeof(OrleansCodeGen.TestProject.Invokable_IResponseTimeoutGrain_GrainReference_6BE752C8));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithDifferentKeyTypes.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IMyGrainWithGuidKey), \"8F0FEC0E\")]\n    public sealed class Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Runtime.TaskRequest<global::System.Guid>\n    {\n        global::TestProject.IMyGrainWithGuidKey _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithGuidKey), \"GetGuidValue\", null, null);\n        public override string GetMethodName() => \"GetGuidValue\";\n        public override string GetInterfaceName() => \"TestProject.IMyGrainWithGuidKey\";\n        public override string GetActivityName() => \"IMyGrainWithGuidKey/GetGuidValue\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IMyGrainWithGuidKey);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IMyGrainWithGuidKey)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            _target = default;\n        }\n\n        protected override global::System.Threading.Tasks.Task<global::System.Guid> InvokeInner() => _target.GetGuidValue();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IMyGrainWithGuidKey : global::Orleans.Runtime.GrainReference, global::TestProject.IMyGrainWithGuidKey\n    {\n        public Proxy_IMyGrainWithGuidKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<global::System.Guid> global::TestProject.IMyGrainWithGuidKey.GetGuidValue()\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E();\n            return base.InvokeAsync<global::System.Guid>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IMyGrainWithStringKey), \"43570316\")]\n    public sealed class Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        global::TestProject.IMyGrainWithStringKey _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithStringKey), \"GetStringKey\", null, null);\n        public override string GetMethodName() => \"GetStringKey\";\n        public override string GetInterfaceName() => \"TestProject.IMyGrainWithStringKey\";\n        public override string GetActivityName() => \"IMyGrainWithStringKey/GetStringKey\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IMyGrainWithStringKey);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IMyGrainWithStringKey)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            _target = default;\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.GetStringKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IMyGrainWithStringKey : global::Orleans.Runtime.GrainReference, global::TestProject.IMyGrainWithStringKey\n    {\n        public Proxy_IMyGrainWithStringKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IMyGrainWithStringKey.GetStringKey()\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316();\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IMyGrainWithGuidCompoundKey), \"A9FEF7AF\")]\n    public sealed class Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Runtime.TaskRequest<global::System.Tuple<global::System.Guid, string>>\n    {\n        global::TestProject.IMyGrainWithGuidCompoundKey _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithGuidCompoundKey), \"GetGuidAndStringKey\", null, null);\n        public override string GetMethodName() => \"GetGuidAndStringKey\";\n        public override string GetInterfaceName() => \"TestProject.IMyGrainWithGuidCompoundKey\";\n        public override string GetActivityName() => \"IMyGrainWithGuidCompoundKey/GetGuidAndStringKey\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IMyGrainWithGuidCompoundKey);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IMyGrainWithGuidCompoundKey)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            _target = default;\n        }\n\n        protected override global::System.Threading.Tasks.Task<global::System.Tuple<global::System.Guid, string>> InvokeInner() => _target.GetGuidAndStringKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IMyGrainWithGuidCompoundKey : global::Orleans.Runtime.GrainReference, global::TestProject.IMyGrainWithGuidCompoundKey\n    {\n        public Proxy_IMyGrainWithGuidCompoundKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<global::System.Tuple<global::System.Guid, string>> global::TestProject.IMyGrainWithGuidCompoundKey.GetGuidAndStringKey()\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF();\n            return base.InvokeAsync<global::System.Tuple<global::System.Guid, string>>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IMyGrainWithIntegerCompoundKey), \"9814021A\")]\n    public sealed class Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Runtime.TaskRequest<global::System.Tuple<long, string>>\n    {\n        global::TestProject.IMyGrainWithIntegerCompoundKey _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IMyGrainWithIntegerCompoundKey), \"GetIntegerAndStringKey\", null, null);\n        public override string GetMethodName() => \"GetIntegerAndStringKey\";\n        public override string GetInterfaceName() => \"TestProject.IMyGrainWithIntegerCompoundKey\";\n        public override string GetActivityName() => \"IMyGrainWithIntegerCompoundKey/GetIntegerAndStringKey\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IMyGrainWithIntegerCompoundKey);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IMyGrainWithIntegerCompoundKey)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            _target = default;\n        }\n\n        protected override global::System.Threading.Tasks.Task<global::System.Tuple<long, string>> InvokeInner() => _target.GetIntegerAndStringKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IMyGrainWithIntegerCompoundKey : global::Orleans.Runtime.GrainReference, global::TestProject.IMyGrainWithIntegerCompoundKey\n    {\n        public Proxy_IMyGrainWithIntegerCompoundKey(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<global::System.Tuple<long, string>> global::TestProject.IMyGrainWithIntegerCompoundKey.GetIntegerAndStringKey()\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A();\n            return base.InvokeAsync<global::System.Tuple<long, string>>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E instance)\n        {\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E();\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GrainWithGuidKey : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GrainWithGuidKey>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GrainWithGuidKey>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GrainWithGuidKey);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_GrainWithGuidKey(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GrainWithGuidKey instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GrainWithGuidKey instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GrainWithGuidKey @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GrainWithGuidKey))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithGuidKey ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GrainWithGuidKey, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.GrainWithGuidKey();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GrainWithGuidKey>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GrainWithGuidKey : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GrainWithGuidKey>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GrainWithGuidKey>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithGuidKey DeepCopy(global::TestProject.GrainWithGuidKey original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GrainWithGuidKey existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GrainWithGuidKey))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.GrainWithGuidKey();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GrainWithGuidKey(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GrainWithGuidKey input, global::TestProject.GrainWithGuidKey output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_GrainWithGuidKey : global::Orleans.Serialization.Activators.IActivator<global::TestProject.GrainWithGuidKey>\n    {\n        public global::TestProject.GrainWithGuidKey Create() => new global::TestProject.GrainWithGuidKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 instance)\n        {\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IMyGrainWithStringKey_GrainReference_43570316 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316();\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GrainWithStringKey : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GrainWithStringKey>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GrainWithStringKey>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GrainWithStringKey);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_GrainWithStringKey(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GrainWithStringKey instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GrainWithStringKey instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GrainWithStringKey @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GrainWithStringKey))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithStringKey ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GrainWithStringKey, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.GrainWithStringKey();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GrainWithStringKey>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GrainWithStringKey : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GrainWithStringKey>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GrainWithStringKey>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithStringKey DeepCopy(global::TestProject.GrainWithStringKey original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GrainWithStringKey existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GrainWithStringKey))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.GrainWithStringKey();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GrainWithStringKey(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GrainWithStringKey input, global::TestProject.GrainWithStringKey output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_GrainWithStringKey : global::Orleans.Serialization.Activators.IActivator<global::TestProject.GrainWithStringKey>\n    {\n        public global::TestProject.GrainWithStringKey Create() => new global::TestProject.GrainWithStringKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF instance)\n        {\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF();\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GrainWithGuidCompoundKey : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GrainWithGuidCompoundKey>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GrainWithGuidCompoundKey>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GrainWithGuidCompoundKey);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_GrainWithGuidCompoundKey(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GrainWithGuidCompoundKey instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GrainWithGuidCompoundKey instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GrainWithGuidCompoundKey @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GrainWithGuidCompoundKey))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithGuidCompoundKey ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GrainWithGuidCompoundKey, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.GrainWithGuidCompoundKey();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GrainWithGuidCompoundKey>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GrainWithGuidCompoundKey : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GrainWithGuidCompoundKey>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GrainWithGuidCompoundKey>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithGuidCompoundKey DeepCopy(global::TestProject.GrainWithGuidCompoundKey original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GrainWithGuidCompoundKey existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GrainWithGuidCompoundKey))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.GrainWithGuidCompoundKey();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GrainWithGuidCompoundKey(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GrainWithGuidCompoundKey input, global::TestProject.GrainWithGuidCompoundKey output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_GrainWithGuidCompoundKey : global::Orleans.Serialization.Activators.IActivator<global::TestProject.GrainWithGuidCompoundKey>\n    {\n        public global::TestProject.GrainWithGuidCompoundKey Create() => new global::TestProject.GrainWithGuidCompoundKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A instance)\n        {\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A DeepCopy(OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A();\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_GrainWithIntegerCompoundKey : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.GrainWithIntegerCompoundKey>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.GrainWithIntegerCompoundKey>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.GrainWithIntegerCompoundKey);\n        private readonly global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer;\n        public Codec_GrainWithIntegerCompoundKey(global::Orleans.Serialization.Serializers.IBaseCodec<global::Orleans.Grain> _baseTypeSerializer)\n        {\n            this._baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeSerializer);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.GrainWithIntegerCompoundKey instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            _baseTypeSerializer.Serialize(ref writer, instance);\n            writer.WriteEndBase();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.GrainWithIntegerCompoundKey instance)\n        {\n            _baseTypeSerializer.Deserialize(ref reader, instance);\n            reader.ConsumeEndBaseOrEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.GrainWithIntegerCompoundKey @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.GrainWithIntegerCompoundKey))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithIntegerCompoundKey ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.GrainWithIntegerCompoundKey, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.GrainWithIntegerCompoundKey();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.GrainWithIntegerCompoundKey>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_GrainWithIntegerCompoundKey : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.GrainWithIntegerCompoundKey>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.GrainWithIntegerCompoundKey>\n    {\n        private readonly global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier;\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.GrainWithIntegerCompoundKey DeepCopy(global::TestProject.GrainWithIntegerCompoundKey original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.GrainWithIntegerCompoundKey existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.GrainWithIntegerCompoundKey))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.GrainWithIntegerCompoundKey();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_GrainWithIntegerCompoundKey(global::Orleans.Serialization.Cloning.IBaseCopier<global::Orleans.Grain> _baseTypeCopier)\n        {\n            this._baseTypeCopier = OrleansGeneratedCodeHelper.UnwrapService(this, _baseTypeCopier);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.GrainWithIntegerCompoundKey input, global::TestProject.GrainWithIntegerCompoundKey output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            _baseTypeCopier.DeepCopy(input, output, context);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_GrainWithIntegerCompoundKey : global::Orleans.Serialization.Activators.IActivator<global::TestProject.GrainWithIntegerCompoundKey>\n    {\n        public global::TestProject.GrainWithIntegerCompoundKey Create() => new global::TestProject.GrainWithIntegerCompoundKey();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GrainWithGuidKey));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IMyGrainWithStringKey_GrainReference_43570316));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GrainWithStringKey));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GrainWithGuidCompoundKey));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_GrainWithIntegerCompoundKey));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GrainWithGuidKey));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IMyGrainWithStringKey_GrainReference_43570316));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GrainWithStringKey));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GrainWithGuidCompoundKey));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_GrainWithIntegerCompoundKey));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IMyGrainWithGuidKey));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IMyGrainWithStringKey));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IMyGrainWithGuidCompoundKey));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IMyGrainWithIntegerCompoundKey));\n            config.Interfaces.Add(typeof(global::TestProject.IMyGrainWithGuidKey));\n            config.Interfaces.Add(typeof(global::TestProject.IMyGrainWithStringKey));\n            config.Interfaces.Add(typeof(global::TestProject.IMyGrainWithGuidCompoundKey));\n            config.Interfaces.Add(typeof(global::TestProject.IMyGrainWithIntegerCompoundKey));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithGuidKey));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithStringKey));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithGuidCompoundKey));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.GrainWithIntegerCompoundKey));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithGuidKey));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithStringKey));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithGuidCompoundKey));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_GrainWithIntegerCompoundKey));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IMyGrainWithGuidKey));\n            n3.Add(\"8F0FEC0E\", typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidKey_GrainReference_8F0FEC0E));\n            var n5 = n2.Add(typeof(global::TestProject.IMyGrainWithStringKey));\n            n5.Add(\"43570316\", typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithStringKey_GrainReference_43570316));\n            var n7 = n2.Add(typeof(global::TestProject.IMyGrainWithGuidCompoundKey));\n            n7.Add(\"A9FEF7AF\", typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithGuidCompoundKey_GrainReference_A9FEF7AF));\n            var n9 = n2.Add(typeof(global::TestProject.IMyGrainWithIntegerCompoundKey));\n            n9.Add(\"9814021A\", typeof(OrleansCodeGen.TestProject.Invokable_IMyGrainWithIntegerCompoundKey_GrainReference_9814021A));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainWithMultipleInterfaces.verified.cs",
    "content": "#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IGrainA), \"11405B98\")]\n    public sealed class Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::TestProject.IGrainA _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IGrainA), \"MethodA\", null, new[] { typeof(string) });\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"MethodA\";\n        public override string GetInterfaceName() => \"TestProject.IGrainA\";\n        public override string GetActivityName() => \"IGrainA/MethodA\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IGrainA);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IGrainA)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.MethodA(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IGrainA : global::Orleans.Runtime.GrainReference, global::TestProject.IGrainA\n    {\n        public Proxy_IGrainA(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IGrainA.MethodA(string arg0)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    [global::Orleans.CompoundTypeAliasAttribute(\"inv\", typeof(global::Orleans.Runtime.GrainReference), typeof(global::TestProject.IGrainB), \"6B5D7809\")]\n    public sealed class Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Runtime.TaskRequest<string>\n    {\n        public string arg0;\n        global::TestProject.IGrainB _target;\n        private static readonly global::System.Reflection.MethodInfo MethodBackingField = OrleansGeneratedCodeHelper.GetMethodInfoOrDefault(typeof(global::TestProject.IGrainB), \"MethodB\", null, new[] { typeof(string) });\n        public override int GetArgumentCount() => 1;\n        public override string GetMethodName() => \"MethodB\";\n        public override string GetInterfaceName() => \"TestProject.IGrainB\";\n        public override string GetActivityName() => \"IGrainB/MethodB\";\n        public override global::System.Type GetInterfaceType() => typeof(global::TestProject.IGrainB);\n        public override global::System.Reflection.MethodInfo GetMethod() => MethodBackingField;\n        public override void SetTarget(global::Orleans.Serialization.Invocation.ITargetHolder holder) => _target = (global::TestProject.IGrainB)holder.GetTarget();\n        public override object GetTarget() => _target;\n        public override void Dispose()\n        {\n            arg0 = default;\n            _target = default;\n        }\n\n        public override object GetArgument(int index)\n        {\n            switch (index)\n            {\n                case 0:\n                    return arg0;\n                default:\n                    return OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n            }\n        }\n\n        public override void SetArgument(int index, object value)\n        {\n            switch (index)\n            {\n                case 0:\n                    arg0 = (string)value;\n                    return;\n                default:\n                    OrleansGeneratedCodeHelper.InvokableThrowArgumentOutOfRange(index, 0);\n                    return;\n            }\n        }\n\n        protected override global::System.Threading.Tasks.Task<string> InvokeInner() => _target.MethodB(arg0);\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Proxy_IGrainB : global::Orleans.Runtime.GrainReference, global::TestProject.IGrainB\n    {\n        public Proxy_IGrainB(global::Orleans.Runtime.GrainReferenceShared arg0, global::Orleans.Runtime.IdSpan arg1) : base(arg0, arg1)\n        {\n        }\n\n        global::System.Threading.Tasks.Task<string> global::TestProject.IGrainB.MethodB(string arg0)\n        {\n            var request = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809();\n            request.arg0 = arg0;\n            return base.InvokeAsync<string>(request).AsTask();\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IGrainA_GrainReference_11405B98 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 DeepCopy(OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Serialization.Codecs.IFieldCodec<OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.arg0);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.arg0 = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null)\n            {\n                ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                return;\n            }\n\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            var result = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809();\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_Invokable_IGrainB_GrainReference_6B5D7809 : global::Orleans.Serialization.Cloning.IDeepCopier<OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 DeepCopy(OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809 original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            var result = new OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809();\n            result.arg0 = original.arg0;\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IGrainA_GrainReference_11405B98));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_Invokable_IGrainB_GrainReference_6B5D7809));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IGrainA_GrainReference_11405B98));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_Invokable_IGrainB_GrainReference_6B5D7809));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IGrainA));\n            config.InterfaceProxies.Add(typeof(OrleansCodeGen.TestProject.Proxy_IGrainB));\n            config.Interfaces.Add(typeof(global::TestProject.IGrainA));\n            config.Interfaces.Add(typeof(global::TestProject.IGrainB));\n            config.InterfaceImplementations.Add(typeof(global::TestProject.RealGrain));\n            var n1 = config.CompoundTypeAliases.Add(\"inv\");\n            var n2 = n1.Add(typeof(global::Orleans.Runtime.GrainReference));\n            var n3 = n2.Add(typeof(global::TestProject.IGrainA));\n            n3.Add(\"11405B98\", typeof(OrleansCodeGen.TestProject.Invokable_IGrainA_GrainReference_11405B98));\n            var n5 = n2.Add(typeof(global::TestProject.IGrainB));\n            n5.Add(\"6B5D7809\", typeof(OrleansCodeGen.TestProject.Invokable_IGrainB_GrainReference_6B5D7809));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataRecordStruct : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataRecordStruct>, global::Orleans.Serialization.Serializers.IValueSerializer<global::TestProject.DemoDataRecordStruct>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataRecordStruct);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, scoped ref global::TestProject.DemoDataRecordStruct instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            writer.WriteEndBase();\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, scoped ref global::TestProject.DemoDataRecordStruct instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            {\n                reader.ReadFieldHeader(ref header);\n                reader.ConsumeEndBaseOrEndObject(ref header);\n            }\n\n            id = 0U;\n            if (header.IsEndBaseFields)\n                while (true)\n                {\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                    if (id == 0U)\n                    {\n                        instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                        reader.ReadFieldHeader(ref header);\n                    }\n\n                    reader.ConsumeEndBaseOrEndObject(ref header);\n                    break;\n                }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataRecordStruct @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            ReferenceCodec.MarkValueField(writer.Session);\n            writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n            Serialize(ref writer, ref @value);\n            writer.WriteEndObject();\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataRecordStruct ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            field.EnsureWireTypeTagDelimited();\n            var result = default(global::TestProject.DemoDataRecordStruct);\n            ReferenceCodec.MarkValueField(reader.Session);\n            Deserialize(ref reader, ref result);\n            return result;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataRecordClass : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataRecordClass>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataRecordClass>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataRecordClass);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecordClass> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataRecordClass, string> setField0 = (global::System.Action<global::TestProject.DemoDataRecordClass, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataRecordClass), \"<Value>k__BackingField\");\n        public Codec_DemoDataRecordClass(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecordClass> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataRecordClass instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            writer.WriteEndBase();\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataRecordClass instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            {\n                reader.ReadFieldHeader(ref header);\n                reader.ConsumeEndBaseOrEndObject(ref header);\n            }\n\n            id = 0U;\n            if (header.IsEndBaseFields)\n                while (true)\n                {\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                    if (id == 0U)\n                    {\n                        setField0(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                        reader.ReadFieldHeader(ref header);\n                    }\n\n                    reader.ConsumeEndBaseOrEndObject(ref header);\n                    break;\n                }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataRecordClass @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataRecordClass))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataRecordClass ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataRecordClass, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataRecordClass>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataRecordClass : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataRecordClass>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataRecordClass>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecordClass> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataRecordClass, string> setField0 = (global::System.Action<global::TestProject.DemoDataRecordClass, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataRecordClass), \"<Value>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataRecordClass DeepCopy(global::TestProject.DemoDataRecordClass original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataRecordClass existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataRecordClass))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoDataRecordClass(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecordClass> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataRecordClass input, global::TestProject.DemoDataRecordClass output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, input.Value);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoDataRecord : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoDataRecord>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoDataRecord>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoDataRecord);\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecord> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataRecord, string> setField0 = (global::System.Action<global::TestProject.DemoDataRecord, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataRecord), \"<Value>k__BackingField\");\n        public Codec_DemoDataRecord(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecord> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoDataRecord instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            writer.WriteEndBase();\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoDataRecord instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            {\n                reader.ReadFieldHeader(ref header);\n                reader.ConsumeEndBaseOrEndObject(ref header);\n            }\n\n            id = 0U;\n            if (header.IsEndBaseFields)\n                while (true)\n                {\n                    reader.ReadFieldHeader(ref header);\n                    if (header.IsEndBaseOrEndObject)\n                        break;\n                    id += header.FieldIdDelta;\n                    if (id == 0U)\n                    {\n                        setField0(instance, global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header));\n                        reader.ReadFieldHeader(ref header);\n                    }\n\n                    reader.ConsumeEndBaseOrEndObject(ref header);\n                    break;\n                }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoDataRecord @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoDataRecord))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataRecord ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoDataRecord, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = _activator.Create();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoDataRecord>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoDataRecord : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoDataRecord>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoDataRecord>\n    {\n        private readonly global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecord> _activator;\n        private static readonly global::System.Action<global::TestProject.DemoDataRecord, string> setField0 = (global::System.Action<global::TestProject.DemoDataRecord, string>)global::Orleans.Serialization.Utilities.FieldAccessor.GetReferenceSetter(typeof(global::TestProject.DemoDataRecord), \"<Value>k__BackingField\");\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoDataRecord DeepCopy(global::TestProject.DemoDataRecord original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoDataRecord existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoDataRecord))\n                return context.DeepCopy(original);\n            var result = _activator.Create();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        public Copier_DemoDataRecord(global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoDataRecord> _activator)\n        {\n            this._activator = OrleansGeneratedCodeHelper.UnwrapService(this, _activator);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoDataRecord input, global::TestProject.DemoDataRecord output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            setField0(output, input.Value);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataRecordStruct));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataRecordClass));\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoDataRecord));\n            config.Copiers.Add(typeof(global::Orleans.Serialization.Cloning.ShallowCopier<global::TestProject.DemoDataRecordStruct>));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataRecordClass));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoDataRecord));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoClass : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoClass>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoClass>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoClass);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoClass instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            uint previousFieldId = 0U;\n            if (instance.Value is object)\n            {\n                global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U - previousFieldId, instance.Value);\n                previousFieldId = 0U;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoClass instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoClass @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoClass))\n            {\n                if (ReferenceCodec.TryWriteReferenceField(ref writer, fieldIdDelta, expectedType, @value))\n                    return;\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoClass ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoClass, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoClass();\n                ReferenceCodec.RecordObject(reader.Session, result);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoClass>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoClass : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoClass>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoClass>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoClass DeepCopy(global::TestProject.DemoClass original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (context.TryGetCopy(original, out global::TestProject.DemoClass existing))\n                return existing;\n            if (original.GetType() != typeof(global::TestProject.DemoClass))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoClass();\n            context.RecordCopy(original, result);\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoClass input, global::TestProject.DemoClass output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoClass : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoClass>\n    {\n        public global::TestProject.DemoClass Create() => new global::TestProject.DemoClass();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoClass));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoClass));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoClass));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSerializerTransparentAnnotation.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Codec_DemoClass : global::Orleans.Serialization.Codecs.IFieldCodec<global::TestProject.DemoClass>, global::Orleans.Serialization.Serializers.IBaseCodec<global::TestProject.DemoClass>\n    {\n        private readonly global::System.Type _codecFieldType = typeof(global::TestProject.DemoClass);\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Serialize<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, global::TestProject.DemoClass instance)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            global::Orleans.Serialization.Codecs.StringCodec.WriteField(ref writer, 0U, instance.Value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void Deserialize<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::TestProject.DemoClass instance)\n        {\n            uint id = 0U;\n            global::Orleans.Serialization.WireProtocol.Field header = default;\n            while (true)\n            {\n                reader.ReadFieldHeader(ref header);\n                if (header.IsEndBaseOrEndObject)\n                    break;\n                id += header.FieldIdDelta;\n                if (id == 0U)\n                {\n                    instance.Value = global::Orleans.Serialization.Codecs.StringCodec.ReadValue(ref reader, header);\n                    reader.ReadFieldHeader(ref header);\n                }\n\n                reader.ConsumeEndBaseOrEndObject(ref header);\n                break;\n            }\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void WriteField<TBufferWriter>(ref global::Orleans.Serialization.Buffers.Writer<TBufferWriter> writer, uint fieldIdDelta, global::System.Type expectedType, global::TestProject.DemoClass @value)\n            where TBufferWriter : global::System.Buffers.IBufferWriter<byte>\n        {\n            if (@value is null || @value.GetType() == typeof(global::TestProject.DemoClass))\n            {\n                if (@value is null)\n                {\n                    ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta);\n                    return;\n                }\n\n                ReferenceCodec.MarkValueField(writer.Session);\n                writer.WriteStartObject(fieldIdDelta, expectedType, _codecFieldType);\n                Serialize(ref writer, @value);\n                writer.WriteEndObject();\n            }\n            else\n                writer.SerializeUnexpectedType(fieldIdDelta, expectedType, @value);\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoClass ReadValue<TReaderInput>(ref global::Orleans.Serialization.Buffers.Reader<TReaderInput> reader, global::Orleans.Serialization.WireProtocol.Field field)\n        {\n            if (field.IsReference)\n                return ReferenceCodec.ReadReference<global::TestProject.DemoClass, TReaderInput>(ref reader, field);\n            field.EnsureWireTypeTagDelimited();\n            global::System.Type valueType = field.FieldType;\n            if (valueType is null || valueType == _codecFieldType)\n            {\n                var result = new global::TestProject.DemoClass();\n                ReferenceCodec.MarkValueField(reader.Session);\n                Deserialize(ref reader, result);\n                return result;\n            }\n\n            return reader.DeserializeUnexpectedType<TReaderInput, global::TestProject.DemoClass>(ref field);\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    public sealed class Copier_DemoClass : global::Orleans.Serialization.Cloning.IDeepCopier<global::TestProject.DemoClass>, global::Orleans.Serialization.Cloning.IBaseCopier<global::TestProject.DemoClass>\n    {\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public global::TestProject.DemoClass DeepCopy(global::TestProject.DemoClass original, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            if (original is null)\n                return null;\n            if (original.GetType() != typeof(global::TestProject.DemoClass))\n                return context.DeepCopy(original);\n            var result = new global::TestProject.DemoClass();\n            DeepCopy(original, result, context);\n            return result;\n        }\n\n        [global::System.Runtime.CompilerServices.MethodImplAttribute(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public void DeepCopy(global::TestProject.DemoClass input, global::TestProject.DemoClass output, global::Orleans.Serialization.Cloning.CopyContext context)\n        {\n            output.Value = input.Value;\n        }\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Activator_DemoClass : global::Orleans.Serialization.Activators.IActivator<global::TestProject.DemoClass>\n    {\n        public global::TestProject.DemoClass Create() => new global::TestProject.DemoClass();\n    }\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Serializers.Add(typeof(OrleansCodeGen.TestProject.Codec_DemoClass));\n            config.Copiers.Add(typeof(OrleansCodeGen.TestProject.Copier_DemoClass));\n            config.Activators.Add(typeof(OrleansCodeGen.TestProject.Activator_DemoClass));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithUseActivatorAnnotation.verified.cs",
    "content": "﻿#pragma warning disable CS1591, RS0016, RS0041\n[assembly: global::Orleans.ApplicationPartAttribute(\"TestProject\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core.Abstractions\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Serialization\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Core\")]\n[assembly: global::Orleans.ApplicationPartAttribute(\"Orleans.Runtime\")]\n[assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.TestProject.Metadata_TestProject))]\nnamespace OrleansCodeGen.TestProject\n{\n    using global::Orleans.Serialization.Codecs;\n    using global::Orleans.Serialization.GeneratedCodeHelpers;\n\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"OrleansCodeGen\", \"10.0.0.0\"), global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute]\n    internal sealed class Metadata_TestProject : global::Orleans.Serialization.Configuration.TypeManifestProviderBase\n    {\n        protected override void ConfigureInner(global::Orleans.Serialization.Configuration.TypeManifestOptions config)\n        {\n            config.Activators.Add(typeof(global::TestProject.DemoClassActivator));\n        }\n    }\n}\n#pragma warning restore CS1591, RS0016, RS0041\n"
  },
  {
    "path": "test/Orleans.Connections.Security.Tests/CertificateCreator.cs",
    "content": "using System.Security.Cryptography.X509Certificates;\nusing System.Security.Cryptography;\n\nnamespace Orleans.Connections.Security.Tests\n{\n    internal static class TestCertificateHelper\n    {\n        // See http://oid-info.com/get/1.3.6.1.5.5.7.3.1\n        // Indicates that a certificate can be used as a TLS server certificate\n        public const string ServerAuthenticationOid = \"1.3.6.1.5.5.7.3.1\";\n\n        // See http://oid-info.com/get/1.3.6.1.5.5.7.3.2\n        // Indicates that a certificate can be used as a TLS client certificate\n        public const string ClientAuthenticationOid = \"1.3.6.1.5.5.7.3.2\";\n\n        private const X509KeyUsageFlags KeyUsageFlags = X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.KeyAgreement;\n\n        public static X509Certificate2 CreateSelfSignedCertificate(string subjectName, string[] extendedKeyUsageOids = null)\n        {\n            using var rsa = RSA.Create(2048);\n            var request = new CertificateRequest($\"CN={subjectName}\", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);\n\n            request.CertificateExtensions.Add(\n                new X509BasicConstraintsExtension(false, false, 0, true));\n\n            request.CertificateExtensions.Add(\n                new X509SubjectKeyIdentifierExtension(request.PublicKey, false));\n\n            request.CertificateExtensions.Add(new X509KeyUsageExtension(KeyUsageFlags, false));\n\n            if (extendedKeyUsageOids != null && extendedKeyUsageOids.Length > 0)\n            {\n                var extendedKeyUsages = new OidCollection();\n                foreach (var oid in extendedKeyUsageOids)\n                {\n                    extendedKeyUsages.Add(new Oid(oid));\n                }\n                var extension = new X509EnhancedKeyUsageExtension(extendedKeyUsages, false);\n                request.CertificateExtensions.Add(extension);\n            }\n\n            var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(10)), DateTimeOffset.UtcNow.AddYears(5));\n\n            return certificate;\n        }\n\n        public static string ConvertToBase64(X509Certificate2 certificate)\n        {\n            return Convert.ToBase64String(certificate.Export(X509ContentType.Pfx, \"testing-only\"));\n        }\n\n        public static X509Certificate2 ConvertFromBase64(string encodedCertificate)\n        {\n            var rawData = Convert.FromBase64String(encodedCertificate);\n#if NET10_0_OR_GREATER\n            return X509CertificateLoader.LoadPkcs12(rawData, \"testing-only\");\n#else\n#pragma warning disable SYSLIB0057\n            return new X509Certificate2(rawData, \"testing-only\");\n#pragma warning restore SYSLIB0057\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Connections.Security.Tests/Orleans.Connections.Security.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Connections.Security\\Orleans.Connections.Security.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Orleans.Connections.Security.Tests/TlsConnectionTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace Orleans.Connections.Security.Tests\n{\n    /// <summary>\n    /// Tests for TLS (Transport Layer Security) support in Orleans connections.\n    /// \n    /// Orleans supports TLS encryption for:\n    /// - Client-to-silo connections (gateway connections)\n    /// - Silo-to-silo connections (membership protocol)\n    /// \n    /// Key features tested:\n    /// - Certificate creation and encoding/decoding\n    /// - Mutual TLS authentication (mTLS) with client certificates\n    /// - Different certificate validation modes\n    /// - End-to-end encrypted communication\n    /// \n    /// TLS is essential for:\n    /// - Securing Orleans deployments in untrusted networks\n    /// - Meeting compliance requirements (HIPAA, PCI-DSS, etc.)\n    /// - Preventing man-in-the-middle attacks\n    /// - Authenticating clients and silos\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class TlsConnectionTests\n    {\n        private const string CertificateSubjectName = \"fakedomain.faketld\";\n        private const string CertificateConfigKey = \"certificate\";\n        private const string ClientCertificateModeKey = \"CertificateMode\";\n\n        /// <summary>\n        /// Tests the certificate utility functions for creating self-signed certificates.\n        /// Verifies that certificates can be:\n        /// - Created with specific OIDs (Object Identifiers) for client/server authentication\n        /// - Encoded to Base64 for configuration storage\n        /// - Decoded back to the original certificate\n        /// </summary>\n        [Fact]\n        public void CanCreateCertificates()\n        {\n            var original = TestCertificateHelper.CreateSelfSignedCertificate(\n                CertificateSubjectName,\n                new[] { TestCertificateHelper.ClientAuthenticationOid, TestCertificateHelper.ServerAuthenticationOid });\n            var encoded = TestCertificateHelper.ConvertToBase64(original);\n            var decoded = TestCertificateHelper.ConvertFromBase64(encoded);\n            Assert.Equal(original, decoded);\n        }\n        \n        /// <summary>\n        /// Configures TLS for Orleans clients in the test cluster.\n        /// Sets up:\n        /// - Client certificate for mutual TLS\n        /// - SSL protocols (TLS 1.2)\n        /// - Certificate validation policies\n        /// - Target host name for certificate validation\n        /// </summary>\n        private class TlsClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                var encodedCertificate = configuration[CertificateConfigKey];\n                var localCertificate = TestCertificateHelper.ConvertFromBase64(encodedCertificate);\n\n                var certificateModeString = configuration[ClientCertificateModeKey];\n                var certificateMode = (RemoteCertificateMode)Enum.Parse(typeof(RemoteCertificateMode), certificateModeString);\n\n                clientBuilder.UseTls(options =>\n                {\n                    // Use TLS 1.2 for secure communication\n                    options.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;\n                    // Allow any certificate for testing (in production, validate properly)\n                    options.AllowAnyRemoteCertificate();\n                    // Client's certificate for mutual TLS\n                    options.LocalCertificate = localCertificate;\n                    // Require server to present a certificate\n                    options.RemoteCertificateMode = RemoteCertificateMode.RequireCertificate;\n                    // Configure whether server requires client certificate\n                    options.ClientCertificateMode = certificateMode;\n                    // Set target host for certificate validation\n                    options.OnAuthenticateAsClient = (connection, sslOptions) =>\n                    {\n                        sslOptions.TargetHost = CertificateSubjectName;\n                    };\n                });\n            }\n        }\n\n        /// <summary>\n        /// Configures TLS for Orleans silos in the test cluster.\n        /// Sets up:\n        /// - Server certificate for TLS\n        /// - Client certificate requirements\n        /// - SSL protocol versions\n        /// - Certificate validation policies\n        /// </summary>\n        private class TlsServerConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var config = hostBuilder.GetConfiguration();\n                var encodedCertificate = config[CertificateConfigKey];\n                var localCertificate = TestCertificateHelper.ConvertFromBase64(encodedCertificate);\n\n                var certificateModeString = config[ClientCertificateModeKey];\n                var certificateMode = (RemoteCertificateMode)Enum.Parse(typeof(RemoteCertificateMode), certificateModeString);\n\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseTls(localCertificate, options =>\n                    {\n                        // Use TLS 1.2 for secure communication\n                        options.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;\n                        // Allow any certificate for testing (in production, validate properly)\n                        options.AllowAnyRemoteCertificate();\n                        // Allow but don't require remote certificates (for silo-to-silo)\n                        options.RemoteCertificateMode = RemoteCertificateMode.AllowCertificate;\n                        // Configure client certificate requirements based on test parameters\n                        options.ClientCertificateMode = certificateMode;\n                        // Set target host when acting as client (silo-to-silo connections)\n                        options.OnAuthenticateAsClient = (connection, sslOptions) =>\n                        {\n                            sslOptions.TargetHost = CertificateSubjectName;\n                        };\n                    });\n                });\n            }\n        }\n\n        /// <summary>\n        /// End-to-end test of TLS communication with various certificate configurations.\n        /// Tests different combinations of:\n        /// - Certificate OIDs (null, server-only, or both client and server authentication)\n        /// - Certificate modes (NoCertificate, AllowCertificate, RequireCertificate)\n        /// \n        /// Verifies that:\n        /// - TLS connections are established successfully\n        /// - Grain calls work over encrypted connections\n        /// - Different authentication modes are properly enforced\n        /// - Data integrity is maintained (echo test)\n        /// </summary>\n        [Theory]\n        [InlineData(null, RemoteCertificateMode.AllowCertificate)]\n        [InlineData(null, RemoteCertificateMode.NoCertificate)]\n        [InlineData(new[] { TestCertificateHelper.ServerAuthenticationOid }, RemoteCertificateMode.AllowCertificate)]\n        [InlineData(new[] { TestCertificateHelper.ServerAuthenticationOid }, RemoteCertificateMode.NoCertificate)]\n        [InlineData(new[] { TestCertificateHelper.ClientAuthenticationOid, TestCertificateHelper.ServerAuthenticationOid }, RemoteCertificateMode.NoCertificate)]\n        [InlineData(new[] { TestCertificateHelper.ClientAuthenticationOid, TestCertificateHelper.ServerAuthenticationOid }, RemoteCertificateMode.AllowCertificate)]\n        [InlineData(new[] { TestCertificateHelper.ClientAuthenticationOid, TestCertificateHelper.ServerAuthenticationOid }, RemoteCertificateMode.RequireCertificate)]\n        public async Task TlsEndToEnd(string[] oids, RemoteCertificateMode certificateMode)\n        {\n            TestCluster testCluster = default;\n            try\n            {\n                var builder = new TestClusterBuilder()\n                    .AddSiloBuilderConfigurator<TlsServerConfigurator>()\n                    .AddClientBuilderConfigurator<TlsClientConfigurator>();\n\n                // Create a self-signed certificate with specified OIDs\n                var certificate = TestCertificateHelper.CreateSelfSignedCertificate(\n                    CertificateSubjectName, oids);\n                \n                // Pass certificate through configuration (simulates real deployment)\n                var encodedCertificate = TestCertificateHelper.ConvertToBase64(certificate);\n                builder.Properties[CertificateConfigKey] = encodedCertificate;\n                builder.Properties[ClientCertificateModeKey] = certificateMode.ToString();\n\n                testCluster = builder.Build();\n                await testCluster.DeployAsync();\n\n                var client = testCluster.Client;\n\n                // Test that grain calls work over TLS-encrypted connections\n                var grain = client.GetGrain<IPingGrain>(\"pingu\");\n                var expected = \"secret chit chat\";\n                var actual = await grain.Echo(expected);\n                Assert.Equal(expected, actual);\n            }\n            finally\n            {\n                if (testCluster != null)\n                {\n                    await testCluster.StopAllSilosAsync();\n                    testCluster.Dispose();\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Simple test grain interface for verifying TLS connections.\n    /// The echo method ensures data integrity over encrypted connections.\n    /// </summary>\n    public interface IPingGrain : IGrainWithStringKey\n    {\n        Task<string> Echo(string value);\n    }\n\n    /// <summary>\n    /// Test grain implementation that echoes back the input.\n    /// Used to verify that data is correctly transmitted over TLS connections.\n    /// </summary>\n    public class PingGrain : Grain, IPingGrain\n    {\n        public Task<string> Echo(string value) => Task.FromResult(value);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Async_AsyncExecutorWithRetriesTests.cs",
    "content": "using System.Globalization;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Xunit;\nusing Xunit.Abstractions;\n\n// ReSharper disable ConvertToLambdaExpression\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// Tests for the AsyncExecutorWithRetries utility class, which provides resilient asynchronous execution with retry logic.\n    /// This class tests Orleans' internal retry mechanism for handling transient failures in asynchronous operations.\n    /// The AsyncExecutorWithRetries is used throughout Orleans for reliable execution of operations that may fail temporarily.\n    /// </summary>\n    public class Async_AsyncExecutorWithRetriesTests\n    {\n        private readonly ITestOutputHelper output;\n\n        public Async_AsyncExecutorWithRetriesTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests that AsyncExecutorWithRetries retries a failing function until it succeeds, \n        /// and verifies that it fails when max retries are exceeded.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Async_AsyncExecutorWithRetriesTest_1()\n        {\n            int counter = 0;\n            Func<int, Task<int>> myFunc = ((int funcCounter) =>\n            {\n                // ReSharper disable AccessToModifiedClosure\n                Assert.Equal(counter, funcCounter);\n                this.output.WriteLine(\"Running for {0} time.\", counter);\n                counter++;\n                if (counter == 5)\n                    return Task.FromResult(28);\n                else\n                    throw new ArgumentException(\"Wrong arg!\");\n                // ReSharper restore AccessToModifiedClosure\n            });\n            Func<Exception, int, bool> errorFilter = ((Exception exc, int i) =>\n            {\n                return true;\n            });\n\n            Task<int> promise = AsyncExecutorWithRetries.ExecuteWithRetries(myFunc, 10, 10, null, errorFilter);\n            int value = await promise;\n            this.output.WriteLine(\"Value is {0}.\", value);\n            counter = 0;\n            try\n            {\n                promise = AsyncExecutorWithRetries.ExecuteWithRetries(myFunc, 3, 3, null, errorFilter);\n                value = await promise;\n                this.output.WriteLine(\"Value is {0}.\", value);\n            }\n            catch (Exception)\n            {\n                return;\n            }\n            Assert.Fail(\"Should have thrown\");\n        }\n\n        /// <summary>\n        /// Tests the success filter functionality, where retries continue until a success condition is met.\n        /// Verifies that execution stops when the success filter returns true.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Async_AsyncExecutorWithRetriesTest_2()\n        {\n            int counter = 0;\n            const int countLimit = 5;\n            Func<int, Task<int>> myFunc = ((int funcCounter) =>\n            {\n// ReSharper disable AccessToModifiedClosure\n                Assert.Equal(counter, funcCounter);\n                this.output.WriteLine(\"Running for {0} time.\", counter);\n                return Task.FromResult(++counter);\n// ReSharper restore AccessToModifiedClosure\n            });\n            Func<int, int, bool> successFilter = ((int count, int i) => count != countLimit);\n\n            int maxRetries = 10;\n            int expectedRetries = countLimit;\n            Task<int> promise = AsyncExecutorWithRetries.ExecuteWithRetries(myFunc, maxRetries, maxRetries, successFilter, null, Timeout.InfiniteTimeSpan);\n            int value = await promise;\n            this.output.WriteLine(\"Value={0} Counter={1} ExpectedRetries={2}\", value, counter, expectedRetries);\n            Assert.Equal(expectedRetries, value); // \"Returned value\"\n            Assert.Equal(counter, value); // \"Counter == Returned value\"\n\n            counter = 0;\n            maxRetries = 3;\n            expectedRetries = maxRetries;\n            promise = AsyncExecutorWithRetries.ExecuteWithRetries(myFunc, maxRetries, maxRetries, successFilter, null);\n            value = await promise;\n            this.output.WriteLine(\"Value={0} Counter={1} ExpectedRetries={2}\", value, counter, expectedRetries);\n            Assert.Equal(expectedRetries, value); // \"Returned value\"\n            Assert.Equal(counter, value); // \"Counter == Returned value\"\n        }\n\n        /// <summary>\n        /// Tests successful execution without any errors, verifying that the error filter is not invoked\n        /// when the function succeeds on the first attempt.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Async_AsyncExecutorWithRetriesTest_4()\n        {\n            int counter = 0;\n            int lastIteration = 0;\n            Func<int, Task<int>> myFunc = ((int funcCounter) =>\n            {\n                lastIteration = funcCounter;\n                Assert.Equal(counter, funcCounter);\n                this.output.WriteLine(\"Running for {0} time.\", counter);\n                return Task.FromResult(++counter);\n            });\n            Func<Exception, int, bool> errorFilter = ((Exception exc, int i) =>\n            {\n                Assert.Equal(lastIteration, i);\n                Assert.Fail(\"Should not be called\");\n                return true;\n            });\n\n            int maxRetries = 5;\n            Task<int> promise = AsyncExecutorWithRetries.ExecuteWithRetries(\n                myFunc, \n                maxRetries, \n                errorFilter,\n                default,\n                new FixedBackoff(TimeSpan.FromSeconds(1)));\n\n            int value = await promise;\n            this.output.WriteLine(\"Value={0} Counter={1} ExpectedRetries={2}\", value, counter, 0);\n            Assert.Equal(counter, value);\n            Assert.Equal(1, counter);\n        }\n\n        /// <summary>\n        /// Tests error filter behavior when it returns true (retry), false (stop), or throws an exception.\n        /// Verifies that the executor respects the error filter's decision on whether to continue retrying.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Async_AsyncExecutorWithRetriesTest_5()\n        {\n            int counter = 0;\n            int lastIteration = 0;\n            Func<int, Task<int>> myFunc = ((int funcCounter) =>\n            {\n                lastIteration = funcCounter;\n                Assert.Equal(counter, funcCounter);\n                this.output.WriteLine(\"Running FUNC for {0} time.\", counter);\n                ++counter;\n                throw new ArgumentException(counter.ToString(CultureInfo.InvariantCulture));\n            });\n            Func<Exception, int, bool> errorFilter = ((Exception exc, int i) =>\n            {\n                this.output.WriteLine(\"Running ERROR FILTER for {0} time.\", i);\n                Assert.Equal(lastIteration, i);\n                if (i==0 || i==1)\n                    return true;\n                else if (i == 2)\n                    throw exc;\n                else\n                    return false;\n            });\n\n            int maxRetries = 5;\n            Task<int> promise = AsyncExecutorWithRetries.ExecuteWithRetries(\n                myFunc,\n                maxRetries,\n                errorFilter,\n                default,\n                new FixedBackoff(TimeSpan.FromSeconds(1)));\n            try\n            {\n                int value = await promise;\n                Assert.Fail(\"Should have thrown\");\n            }\n            catch (Exception exc)\n            {\n                Exception baseExc = exc.GetBaseException();\n                Assert.Equal(typeof(ArgumentException), baseExc.GetType());\n                this.output.WriteLine(\"baseExc.GetType()={0} Counter={1}\", baseExc.GetType(), counter);\n                Assert.Equal(3, counter); // \"Counter == Returned value\"\n            }\n        }\n    }\n}\n\n// ReSharper restore ConvertToLambdaExpression\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Caching/ConcurrentLruSoakTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Reflection;\nusing AwesomeAssertions;\nusing Orleans.Caching;\nusing Orleans.Caching.Internal;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Caching;\n\n/// <summary>\n/// Stress tests for the ConcurrentLruCache to verify thread-safety and consistency under high concurrent load.\n/// These \"soak tests\" run intensive multi-threaded operations to detect race conditions, deadlocks, and data corruption\n/// that might not be caught by regular unit tests. The cache must maintain consistency of its multi-generation structure\n/// even under extreme concurrent access patterns.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic sealed class ConcurrentLruCacheSoakTests\n{\n    private readonly ITestOutputHelper testOutputHelper;\n    private const int HotCap = 3;\n    private const int WarmCap = 3;\n    private const int ColdCap = 3;\n\n    private const int Capacity = HotCap + WarmCap + ColdCap;\n\n    private ConcurrentLruCache<int, string> lru = new ConcurrentLruCache<int, string>(Capacity, EqualityComparer<int>.Default);\n\n    public ConcurrentLruCacheSoakTests(ITestOutputHelper testOutputHelper)\n    {\n        this.testOutputHelper = testOutputHelper;\n    }\n\n    /// <summary>\n    /// Tests concurrent GetOrAdd operations to ensure the cache maintains consistency under heavy read/write load.\n    /// Verifies that the cache size remains within bounds and internal structures remain valid.\n    /// </summary>\n    [Fact]\n    public async Task WhenSoakConcurrentGetCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    lru.GetOrAdd(i + 1, i => i.ToString());\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            // allow +/- 1 variance for capacity\n            lru.Count.Should().BeInRange(7, 10);\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetWithArgCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    // use the arg overload\n                    lru.GetOrAdd(i + 1, (i, s) => i.ToString(), \"Foo\");\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            // allow +/- 1 variance for capacity\n            lru.Count.Should().BeInRange(7, 10);\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetAndRemoveCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    lru.TryRemove(i + 1);\n                    lru.GetOrAdd(i + 1, i => i.ToString());\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetAndRemoveKvpCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    lru.TryRemove(new KeyValuePair<int, string>(i + 1, (i + 1).ToString()));\n                    lru.GetOrAdd(i + 1, i => i.ToString());\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetAndUpdateCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    lru.TryUpdate(i + 1, i.ToString());\n                    lru.GetOrAdd(i + 1, i => i.ToString());\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetAndAddCacheEndsInConsistentState()\n    {\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                for (var i = 0; i < 100000; i++)\n                {\n                    lru.AddOrUpdate(i + 1, i.ToString());\n                    lru.GetOrAdd(i + 1, i => i.ToString());\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n            RunIntegrityCheck();\n        }\n    }\n\n    [Fact]\n    public async Task WhenSoakConcurrentGetAndUpdateValueTypeCacheEndsInConsistentState()\n    {\n        var lruVT = new ConcurrentLruCache<int, Guid>(Capacity, EqualityComparer<int>.Default);\n\n        for (var i = 0; i < 10; i++)\n        {\n            await Threaded.Run(4, () =>\n            {\n                var b = new byte[8];\n                for (var i = 0; i < 100000; i++)\n                {\n                    lruVT.TryUpdate(i + 1, new Guid(i, 0, 0, b));\n                    lruVT.GetOrAdd(i + 1, x => new Guid(x, 0, 0, b));\n                }\n            });\n\n            testOutputHelper.WriteLine($\"{lruVT.HotCount} {lruVT.WarmCount} {lruVT.ColdCount}\");\n            testOutputHelper.WriteLine(string.Join(\" \", lruVT.Keys));\n\n            ConcurrentLruCacheIntegrityChecker.Validate(lruVT);\n        }\n    }\n\n    [Fact]\n    public async Task WhenAddingCacheSizeItemsNothingIsEvicted()\n    {\n        const int size = 1024;\n\n        var cache = new ConcurrentLruCache<int, int>(size);\n\n        await Threaded.Run(4, () =>\n        {\n            for (var i = 0; i < size; i++)\n            {\n                cache.GetOrAdd(i, k => k);\n            }\n        });\n\n        cache.Metrics.Evicted.Should().Be(0);\n    }\n\n    [Fact]\n    public async Task WhenConcurrentUpdateAndRemoveKvp()\n    {\n        var tcs = new TaskCompletionSource<int>();\n\n        var removal = Task.Run(() =>\n        {\n            while (!tcs.Task.IsCompleted)\n            {\n                lru.TryRemove(new KeyValuePair<int, string>(5, \"x\"));\n            }\n        });\n\n        for (var i = 0; i < 100_000; i++)\n        {\n            lru.AddOrUpdate(5, \"a\");\n            lru.TryGet(5, out _).Should().BeTrue(\"key 'a' should not be deleted\");\n            lru.AddOrUpdate(5, \"x\");\n        }\n\n        tcs.SetResult(int.MaxValue);\n\n        await removal;\n    }\n\n    [Theory]\n    [Repeat(10)]\n    public async Task WhenConcurrentGetAndClearCacheEndsInConsistentState(int iteration)\n    {\n        await Threaded.Run(4, r =>\n        {\n            for (var i = 0; i < 100000; i++)\n            {\n                // clear 6,250 times per 1_000_000 iters\n                if (r == 0 && (i & 15) == 15)\n                {\n                    lru.Clear();\n                }\n\n                lru.GetOrAdd(i + 1, i => i.ToString());\n            }\n        });\n\n        testOutputHelper.WriteLine($\"{iteration} {lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n        testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n        RunIntegrityCheck();\n    }\n\n    [Theory]\n    [Repeat(10)]\n    public async Task WhenConcurrentGetAndClearDuringWarmupCacheEndsInConsistentState(int iteration)\n    {\n        await Threaded.Run(4, r =>\n        {\n            for (var i = 0; i < 100000; i++)\n            {\n                // clear 25,000 times per 1_000_000 iters\n                // capacity is 9, so we will try to clear before warmup is done\n                if (r == 0 && (i & 3) == 3)\n                {\n                    lru.Clear();\n                }\n\n                lru.GetOrAdd(i + 1, i => i.ToString());\n            }\n        });\n\n        testOutputHelper.WriteLine($\"{iteration} {lru.HotCount} {lru.WarmCount} {lru.ColdCount}\");\n        testOutputHelper.WriteLine(string.Join(\" \", lru.Keys));\n\n        RunIntegrityCheck();\n    }\n\n    // This test will run forever if there is a live lock.\n    // Since the cache bookkeeping has some overhead, it is harder to provoke\n    // spinning inside the reader thread compared to LruItemSoakTests.DetectTornStruct.\n    [Theory]\n    [Repeat(10)]\n    public async Task WhenValueIsBigStructNoLiveLock(int _)\n    {\n        using var source = new CancellationTokenSource();\n        var started = new TaskCompletionSource<bool>();\n        var cache = new ConcurrentLruCache<int, Guid>(Capacity, EqualityComparer<int>.Default);\n\n        var setTask = Task.Run(() => Setter(cache, source.Token, started));\n        await started.Task;\n        Checker(cache, source);\n\n        await setTask;\n    }\n\n    private void Setter(ConcurrentLruCache<int, Guid> cache, CancellationToken cancelToken, TaskCompletionSource<bool> started)\n    {\n        started.SetResult(true);\n\n        while (true)\n        {\n            cache.AddOrUpdate(1, Guid.NewGuid());\n            cache.AddOrUpdate(1, Guid.NewGuid());\n\n            if (cancelToken.IsCancellationRequested)\n            {\n                return;\n            }\n        }\n    }\n\n    private void Checker(ConcurrentLruCache<int, Guid> cache, CancellationTokenSource source)\n    {\n        for (var count = 0; count < 100_000; ++count)\n        {\n            cache.TryGet(1, out _);\n        }\n\n        source.Cancel();\n    }\n\n    private void RunIntegrityCheck() => ConcurrentLruCacheIntegrityChecker.Validate(lru);\n\n    private static class ConcurrentLruCacheIntegrityChecker\n    {\n        public static void Validate<K, V>(ConcurrentLruCache<K, V> cache)\n        {\n            ConcurrentLruCache<K, V>.ITestAccessor testAccessor = cache;\n            // queue counters must be consistent with queues\n            testAccessor.HotQueue.Count.Should().Be(cache.HotCount, \"hot queue has a corrupted count\");\n            testAccessor.WarmQueue.Count.Should().Be(cache.WarmCount, \"warm queue has a corrupted count\");\n            testAccessor.ColdQueue.Count.Should().Be(cache.ColdCount, \"cold queue has a corrupted count\");\n\n            // cache contents must be consistent with queued items\n            ValidateQueue(testAccessor.HotQueue, \"hot\");\n            ValidateQueue(testAccessor.WarmQueue, \"warm\");\n            ValidateQueue(testAccessor.ColdQueue, \"cold\");\n\n            // cache must be within capacity\n            cache.Count.Should().BeLessThanOrEqualTo(cache.Capacity + 1, \"capacity out of valid range\");\n\n            void ValidateQueue(ConcurrentQueue<ConcurrentLruCache<K, V>.LruItem> queue, string queueName)\n            {\n                foreach (var item in queue)\n                {\n                    if (item.WasRemoved)\n                    {\n                        // It is possible for the queues to contain 2 (or more) instances of the same key/item. One that was removed,\n                        // and one that was added after the other was removed.\n                        // In this case, the dictionary may contain the value only if the queues contain an entry for that key marked as WasRemoved == false.\n                        if (testAccessor.Dictionary.TryGetValue(item.Key, out var value))\n                        {\n                            testAccessor.HotQueue.Union(testAccessor.WarmQueue).Union(testAccessor.ColdQueue)\n                                .Any(i => i.Key.Equals(item.Key) && !i.WasRemoved)\n                                .Should().BeTrue($\"{queueName} removed item {item.Key} was not removed\");\n                        }\n                    }\n                    else\n                    {\n                        testAccessor.Dictionary.TryGetValue(item.Key, out var value).Should().BeTrue($\"{queueName} item {item.Key} was not present\");\n                    }\n                }\n            }\n        }\n    }\n\n    private sealed class RepeatAttribute : Xunit.Sdk.DataAttribute\n    {\n        private readonly int _count;\n\n        public RepeatAttribute(int count)\n        {\n            if (count < 1)\n            {\n                throw new ArgumentOutOfRangeException(\n                    paramName: nameof(count),\n                    message: \"Repeat count must be greater than 0.\"\n                    );\n            }\n\n            _count = count;\n        }\n\n        public override IEnumerable<object[]> GetData(System.Reflection.MethodInfo testMethod)\n        {\n            foreach (var iterationNumber in Enumerable.Range(start: 1, count: _count))\n            {\n                yield return new object[] { iterationNumber };\n            }\n        }\n    }\n\n    private class Threaded\n    {\n        public static Task Run(int threadCount, Action action)\n        {\n            return Run(threadCount, i => action());\n        }\n\n        public static async Task Run(int threadCount, Action<int> action)\n        {\n            var tasks = new Task[threadCount];\n            ManualResetEvent mre = new ManualResetEvent(false);\n\n            for (int i = 0; i < threadCount; i++)\n            {\n                int run = i; \n                tasks[i] = Task.Run(() =>\n                {\n                    mre.WaitOne();\n                    action(run);\n                });\n            }\n\n            mre.Set();\n\n            await Task.WhenAll(tasks);\n        }\n\n        public static Task RunAsync(int threadCount, Func<Task> action)\n        {\n            return Run(threadCount, i => action());\n        }\n\n        public static async Task RunAsync(int threadCount, Func<int, Task> action)\n        {\n            var tasks = new Task[threadCount];\n            ManualResetEvent mre = new ManualResetEvent(false);\n\n            for (int i = 0; i < threadCount; i++)\n            {\n                int run = i;\n                tasks[i] = Task.Run(async () =>\n                {\n                    mre.WaitOne();\n                    await action(run);\n                });\n            }\n\n            mre.Set();\n\n            await Task.WhenAll(tasks);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Caching/ConcurrentLruTests.cs",
    "content": "using AwesomeAssertions;\nusing System.Collections;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Caching;\nusing Orleans.Caching.Internal;\n\nnamespace NonSilo.Tests.Caching;\n\n/// <summary>\n/// Tests for the ConcurrentLruCache, which is a thread-safe LRU (Least Recently Used) cache implementation used in Orleans.\n/// This cache is designed with a multi-generation architecture (Hot, Warm, Cold) to efficiently manage frequently accessed items.\n/// It's used throughout Orleans for caching grain directory entries, grain references, and other frequently accessed data.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class ConcurrentLruTests(ITestOutputHelper testOutputHelper)\n{\n    private readonly ITestOutputHelper _testOutputHelper = testOutputHelper;\n    private const int Capacity = 100;\n    private readonly CapacityPartition _capacityPartition = new(Capacity);\n    private int HotCap => _capacityPartition.Hot;\n    private int WarmCap => _capacityPartition.Warm;\n    private int ColdCap => _capacityPartition.Cold;\n\n    private readonly ConcurrentLruCache<int, string> _lru = new(Capacity);\n    private readonly ValueFactory _valueFactory = new();\n\n    private static ConcurrentLruCache<int, string>.ITestAccessor GetTestAccessor(ConcurrentLruCache<int, string> lru) => lru;\n\n    /// <summary>\n    /// Verifies that the cache requires a minimum capacity of 3 to support its multi-generation architecture.\n    /// </summary>\n    [Fact]\n    public void WhenCapacityIsLessThan3CtorThrows()\n    {\n        Action constructor = () => { var x = new ConcurrentLruCache<int, string>(2, EqualityComparer<int>.Default); };\n\n        constructor.Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Fact]\n    public void WhenCapacityIs4HotHasCapacity1AndColdHasCapacity1()\n    {\n        var lru = new ConcurrentLruCache<int, int>(4, EqualityComparer<int>.Default);\n\n        for (var i = 0; i < 5; i++)\n        {\n            lru.GetOrAdd(i, x => x);\n        }\n\n        lru.HotCount.Should().Be(1);\n        lru.ColdCount.Should().Be(1);\n        lru.Capacity.Should().Be(4);\n    }\n\n    [Fact]\n    public void WhenCapacityIs10HotHasCapacity1AndWarmHasCapacity8AndColdHasCapacity1()\n    {\n        var lru = new ConcurrentLruCache<int, int>(10, EqualityComparer<int>.Default);\n\n        for (var i = 0; i < lru.Capacity; i++)\n        {\n            lru.GetOrAdd(i, x => x);\n        }\n\n        lru.HotCount.Should().Be(1);\n        lru.WarmCount.Should().Be(8);\n        lru.ColdCount.Should().Be(1);\n        lru.Capacity.Should().Be(10);\n    }\n\n    [Fact]\n    public void ConstructAddAndRetrieveWithDefaultCtorReturnsValue()\n    {\n        var x = new ConcurrentLruCache<int, int>(3);\n\n        x.GetOrAdd(1, k => k).Should().Be(1);\n    }\n\n    /// <summary>\n    /// Tests that the cache correctly tracks the count of items when new entries are added.\n    /// </summary>\n    [Fact]\n    public void WhenItemIsAddedCountIsCorrect()\n    {\n        _lru.Count.Should().Be(0);\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.Count.Should().Be(1);\n    }\n\n    [Fact]\n    public void WhenItemsAddedKeysContainsTheKeys()\n    {\n        _lru.Count.Should().Be(0);\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n        _lru.Keys.Should().BeEquivalentTo(new[] { 1, 2 });\n    }\n\n    [Fact]\n    public void WhenItemsAddedGenericEnumerateContainsKvps()\n    {\n        _lru.Count.Should().Be(0);\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n        _lru.Should().BeEquivalentTo(new[] { new KeyValuePair<int, string>(1, \"1\"), new KeyValuePair<int, string>(2, \"2\") });\n    }\n\n    [Fact]\n    public void WhenItemsAddedEnumerateContainsKvps()\n    {\n        _lru.Count.Should().Be(0);\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n\n        var enumerable = (IEnumerable)_lru;\n        enumerable.Should().BeEquivalentTo(new[] { new KeyValuePair<int, string>(1, \"1\"), new KeyValuePair<int, string>(2, \"2\") });\n    }\n\n    [Fact]\n    public void FromColdWarmupFillsWarmQueue()\n    {\n        FillCache();\n\n        _lru.Count.Should().Be(Capacity);\n    }\n\n    [Fact]\n    public void WhenItemExistsTryGetReturnsValueAndTrue()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        var result = _lru.TryGet(1, out var value);\n\n        result.Should().Be(true);\n        value.Should().Be(\"1\");\n    }\n\n    [Fact]\n    public void WhenItemDoesNotExistTryGetReturnsNullAndFalse()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        var result = _lru.TryGet(2, out var value);\n\n        result.Should().Be(false);\n        value.Should().BeNull();\n    }\n\n    [Fact]\n    public void WhenItemIsAddedThenRetrievedMetricHitRatioIsHalf()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        var result = _lru.TryGet(1, out var value);\n\n        _lru.Metrics.HitRatio.Should().Be(0.5);\n    }\n\n    [Fact]\n    public void WhenItemIsAddedThenRetrievedTotalIs2()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        var result = _lru.TryGet(1, out var value);\n\n        _lru.Metrics.Total.Should().Be(2);\n    }\n\n    [Fact]\n    public void WhenRefToMetricsIsCapturedResultIsCorrect()\n    {\n        // this detects the case where the struct is copied. If the internal Data class\n        // doesn't work, this test fails.\n        var m = _lru.Metrics;\n\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        var result = _lru.TryGet(1, out var value);\n\n        m.HitRatio.Should().Be(0.5);\n    }\n\n    [Fact]\n    public void WhenKeyIsRequestedItIsCreatedAndCached()\n    {\n        var result1 = _lru.GetOrAdd(1, _valueFactory.Create);\n        var result2 = _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _valueFactory.TimesCalled.Should().Be(1);\n        result1.Should().Be(result2);\n    }\n\n    [Fact]\n    public void WhenKeyIsRequestedWithArgItIsCreatedAndCached()\n    {\n        var result1 = _lru.GetOrAdd(1, _valueFactory.Create, \"x\");\n        var result2 = _lru.GetOrAdd(1, _valueFactory.Create, \"y\");\n\n        _valueFactory.TimesCalled.Should().Be(1);\n        result1.Should().Be(result2);\n    }\n\n    [Fact]\n    public void WhenDifferentKeysAreRequestedValueIsCreatedForEach()\n    {\n        var result1 = _lru.GetOrAdd(1, _valueFactory.Create);\n        var result2 = _lru.GetOrAdd(2, _valueFactory.Create);\n\n        _valueFactory.TimesCalled.Should().Be(2);\n\n        result1.Should().Be(\"1\");\n        result2.Should().Be(\"2\");\n    }\n\n    [Fact]\n    public void WhenValuesAreNotReadAndMoreKeysRequestedThanCapacityCountDoesNotIncrease()\n    {\n        FillCache();\n\n        var result = _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.Count.Should().Be(Capacity);\n        _valueFactory.TimesCalled.Should().Be(Capacity + 1);\n    }\n\n    [Fact]\n    public void WhenValuesAreReadAndMoreKeysRequestedThanCapacityCountIsBounded()\n    {\n        for (var i = 0; i < Capacity + 1; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n\n            // touch items already cached when they are still in hot\n            if (i > 0)\n            {\n                _lru.GetOrAdd(i - 1, _valueFactory.Create);\n            }\n        }\n\n        _lru.Count.Should().Be(Capacity);\n        _valueFactory.TimesCalled.Should().Be(Capacity + 1);\n    }\n\n    [Fact]\n    public void WhenKeysAreContinuouslyRequestedInTheOrderTheyAreAddedCountIsBounded()\n    {\n        for (var i = 0; i < Capacity + 10; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n\n            // Touch all items already cached in hot, warm and cold.\n            // This is worst case scenario, since we touch them in the exact order they\n            // were added.\n            for (var j = 0; j < i; j++)\n            {\n                _lru.GetOrAdd(j, _valueFactory.Create);\n            }\n\n            _testOutputHelper.WriteLine($\"Total: {_lru.Count} Hot: {_lru.HotCount} Warm: {_lru.WarmCount} Cold: {_lru.ColdCount}\");\n            _lru.Count.Should().BeLessThanOrEqualTo(Capacity + 1);\n        }\n    }\n\n    [Fact]\n    public void WhenKeysAreContinuouslyRequestedInTheOrderTheyAreAddedCountIsBounded2()\n    {\n        var lru = new ConcurrentLruCache<int, string>(128, EqualityComparer<int>.Default);\n\n        for (var i = 0; i < 128 + 10; i++)\n        {\n            lru.GetOrAdd(i, _valueFactory.Create);\n\n            // Touch all items already cached in hot, warm and cold.\n            // This is worst case scenario, since we touch them in the exact order they\n            // were added.\n            for (var j = 0; j < i; j++)\n            {\n                lru.GetOrAdd(j, _valueFactory.Create);\n            }\n\n            lru.Count.Should().BeLessThanOrEqualTo(128 + 1, $\"Total: {lru.Count} Hot: {lru.HotCount} Warm: {lru.WarmCount} Cold: {lru.ColdCount}\");\n        }\n    }\n\n    /// <summary>\n    /// Tests the multi-generation eviction policy: items not accessed in the Hot generation are demoted to Cold.\n    /// This tests the cache's ability to distinguish between frequently and infrequently accessed items.\n    /// </summary>\n    [Fact]\n    public void WhenValueIsNotTouchedAndExpiresFromHotValueIsBumpedToCold()\n    {\n        FillCache();\n\n        // Insert a value, making it hot\n        Touch(0);\n\n        // Insert more values, demoting it to cold\n        GetOrAddRangeInclusive(1, Capacity - 1);\n\n        IsInCache(0); // Value should be cold\n\n        GetOrAddRangeInclusive(Capacity, Capacity + 1);\n\n        // Value should have been evicted\n        _lru.TryGet(0, out var value).Should().BeFalse();\n    }\n\n    private bool IsInCache(int key) => _lru.Keys.Contains(key);\n\n    private void Touch(int key)\n    {\n        _lru.GetOrAdd(key, _valueFactory.Create);\n    }\n\n    private void GetOrAddRangeInclusive(int start, int end)\n    {\n        if (start <= end)\n        {\n            for (var i = start; i <= end; i++)\n            {\n                Touch(i);\n            }\n        }\n        else\n        {\n            for (var i = start; i >= end; i--)\n            {\n                Touch(i);\n            }\n        }\n    }\n\n    private void AddOrUpdateRangeInclusive(int start, int end)\n    {\n        if (start <= end)\n        {\n            for (var i = start; i <= end; i++)\n            {\n                _lru.AddOrUpdate(i, _valueFactory.Create(i));\n            }\n        }\n        else\n        {\n            for (var i = start; i >= end; i--)\n            {\n                _lru.AddOrUpdate(i, _valueFactory.Create(i));\n            }\n        }\n    }\n\n    [Fact]\n    public void WhenValueIsTouchedAndExpiresFromHotValueIsBumpedToWarm()\n    {\n        FillCache();\n\n        // Promote to hot\n        Touch(0);\n        Touch(0);\n\n        GetOrAddRangeInclusive(1, 9);\n\n        _lru.TryGet(0, out var value).Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenValueIsTouchedAndExpiresFromColdItIsBumpedToWarm()\n    {\n        FillCache();\n\n        _lru.GetOrAdd(0, _valueFactory.Create);\n\n        IsInCache(0).Should().BeTrue();\n\n\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n        _lru.GetOrAdd(3, _valueFactory.Create); // push 0 to cold (not touched in hot)\n\n        IsInCache(0).Should().BeTrue();\n\n        _lru.GetOrAdd(0, _valueFactory.Create); // Touch 0 in cold\n\n        IsInCache(0).Should().BeTrue();\n\n        GetOrAddRangeInclusive(4, 9);\n        _lru.GetOrAdd(4, _valueFactory.Create); // fully cycle cold, this will evict 0 if it is not moved to warm\n        _lru.GetOrAdd(5, _valueFactory.Create);\n        _lru.GetOrAdd(6, _valueFactory.Create);\n        _lru.GetOrAdd(7, _valueFactory.Create);\n        _lru.GetOrAdd(8, _valueFactory.Create);\n        _lru.GetOrAdd(9, _valueFactory.Create);\n\n        _lru.TryGet(0, out var value).Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenValueIsNotTouchedAndExpiresFromColdItIsRemoved()\n    {\n        FillCache();\n\n        _lru.GetOrAdd(0, _valueFactory.Create);\n\n        AddOrUpdateRangeInclusive(1, Capacity);\n\n        _lru.TryGet(0, out var value).Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenValueIsNotTouchedAndExpiresFromWarmValueIsBumpedToCold()\n    {\n        FillCache();\n\n        // Insert hot\n        Touch(0);\n\n        // Touch it again so that it will be promoted to 'warm'\n        Touch(0);\n\n        GetOrAddRangeInclusive(1, Capacity - 1);\n\n        IsInCache(0).Should().BeTrue();\n\n        // Touch more values to have it evicted.\n        for (var i = 1; i < 1 + Capacity; i++)\n        {\n            Touch(i);\n            Touch(i);\n        }\n\n        _lru.TryGet(0, out var value).Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenValueIsTouchedAndExpiresFromWarmValueIsBumpedBackIntoWarm()\n    {\n        FillCache();\n\n        _lru.GetOrAdd(0, _valueFactory.Create);\n        _lru.GetOrAdd(0, _valueFactory.Create); // Touch 0 in hot, it will promote to warm\n\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n        _lru.GetOrAdd(3, _valueFactory.Create); // push 0 to warm\n\n        // touch next 3 values, so they will promote to warm\n        _lru.GetOrAdd(4, _valueFactory.Create); _lru.GetOrAdd(4, _valueFactory.Create);\n        _lru.GetOrAdd(5, _valueFactory.Create); _lru.GetOrAdd(5, _valueFactory.Create);\n        _lru.GetOrAdd(6, _valueFactory.Create); _lru.GetOrAdd(6, _valueFactory.Create);\n\n        // push 4,5,6 to warm, 0 to cold\n        _lru.GetOrAdd(7, _valueFactory.Create);\n        _lru.GetOrAdd(8, _valueFactory.Create);\n        _lru.GetOrAdd(9, _valueFactory.Create);\n\n        // Touch 0\n        _lru.TryGet(0, out var value).Should().BeTrue();\n\n        // push 7,8,9 to cold, cycle 0 back to warm\n        _lru.GetOrAdd(10, _valueFactory.Create);\n        _lru.GetOrAdd(11, _valueFactory.Create);\n        _lru.GetOrAdd(12, _valueFactory.Create);\n\n        _lru.TryGet(0, out value).Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenValueExpiresItIsDisposed()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n        var disposableValueFactory = new DisposableValueFactory();\n\n        for (var i = 0; i < 7; i++)\n        {\n            lruOfDisposable.GetOrAdd(i, disposableValueFactory.Create);\n        }\n\n        disposableValueFactory.Items[0].IsDisposed.Should().BeTrue();\n\n        disposableValueFactory.Items[1].IsDisposed.Should().BeFalse();\n        disposableValueFactory.Items[2].IsDisposed.Should().BeFalse();\n        disposableValueFactory.Items[3].IsDisposed.Should().BeFalse();\n        disposableValueFactory.Items[4].IsDisposed.Should().BeFalse();\n        disposableValueFactory.Items[5].IsDisposed.Should().BeFalse();\n        disposableValueFactory.Items[6].IsDisposed.Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenAddingNullValueCanBeAddedAndRemoved()\n    {\n        _lru.GetOrAdd(1, _ => null).Should().BeNull();\n        _lru.AddOrUpdate(1, null);\n        _lru.TryRemove(1).Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenValuesAreEvictedEvictionMetricCountsEvicted()\n    {\n        FillCache();\n\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.Metrics.Evicted.Should().Be(1);\n    }\n\n    [Fact]\n    public void WhenKeyExistsTryRemoveRemovesItemAndReturnsTrue()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryRemove(1).Should().BeTrue();\n        _lru.TryGet(1, out var value).Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenKeyExistsTryRemoveReturnsValue()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryRemove(1, out var value).Should().BeTrue();\n        value.Should().Be(\"1\");\n    }\n\n    [Fact]\n    public void WhenItemIsRemovedItIsDisposed()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n        var disposableValueFactory = new DisposableValueFactory();\n\n        lruOfDisposable.GetOrAdd(1, disposableValueFactory.Create);\n        lruOfDisposable.TryRemove(1);\n\n        disposableValueFactory.Items[1].IsDisposed.Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenItemRemovedFromHotDuringWarmupItIsEagerlyCycledOut()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryRemove(1);\n        Print();                                    // Hot [1] Warm [] Cold []\n\n        _lru.GetOrAdd(1, _valueFactory.Create);\n        _lru.GetOrAdd(2, _valueFactory.Create);\n        _lru.GetOrAdd(3, _valueFactory.Create);\n        Print();                                    // Hot [1,2,3] Warm [] Cold []\n\n        _lru.WarmCount.Should().Be(0);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenItemRemovedFromHotAfterWarmupItIsEagerlyCycledOut()\n    {\n        for (var i = 0; i < _lru.Capacity; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n        }\n\n        _lru.Metrics.Evicted.Should().Be(0);\n\n        _lru.GetOrAdd(-1, _valueFactory.Create);\n\n        _lru.TryRemove(-1);\n\n        // fully cycle hot, which is 3 items\n        foreach (var item in Enumerable.Range(1000, HotCap))\n        {\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        // without eager eviction as -1 is purged from hot, a 4th item will pushed out since hot queue is full\n        _lru.Metrics.Evicted.Should().Be(HotCap);\n    }\n\n    [Fact]\n    public void WhenItemRemovedFromWarmDuringWarmupItIsEagerlyCycledOut()\n    {\n        foreach (var item in Enumerable.Range(1, HotCap))\n        {\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        _lru.TryRemove(1);\n\n        foreach (var item in Enumerable.Range(1000, HotCap))\n        {\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        // Items are cycled from Hot to Warm, since Warm is not yet filled.\n        // The previously removed item is skipped.\n        _lru.WarmCount.Should().Be(HotCap - 1);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n\n    [Fact]\n    public void WhenItemRemovedFromWarmAfterWarmupItIsEagerlyCycledOut()\n    {\n        for (var i = 0; i < _lru.Capacity; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n        }\n\n        Print();                                    // Hot [6,7,8] Warm [1,2,3] Cold [0,4,5]\n        _lru.Metrics.Evicted.Should().Be(0);\n\n        _lru.TryRemove(1);\n\n        _lru.GetOrAdd(6, _valueFactory.Create); // 6 -> W\n        _lru.GetOrAdd(9, _valueFactory.Create);\n\n        Print();                                    // Hot [7,8,9] Warm [2,3,6] Cold [0,4,5]\n\n        _lru.Metrics.Evicted.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenItemRemovedFromColdAfterWarmupItIsEagerlyCycledOut()\n    {\n        for (var i = 0; i < _lru.Capacity; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n        }\n\n        Print();                                    // Hot [6,7,8] Warm [1,2,3] Cold [0,4,5]\n        _lru.Metrics.Evicted.Should().Be(0);\n\n        _lru.GetOrAdd(0, _valueFactory.Create);\n        _lru.TryRemove(0);\n\n        _lru.GetOrAdd(9, _valueFactory.Create);\n\n        Print();                                    // Hot [7,8,9] Warm [1,2,3] Cold [4,5,6]\n\n        _lru.Metrics.Evicted.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenKeyDoesNotExistTryRemoveReturnsFalse()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryRemove(2).Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenItemsAreRemovedTrimRemovesDeletedItemsFromQueues()\n    {\n        for (var i = 0; i < _lru.Capacity; i++)\n        {\n            _lru.GetOrAdd(i, _valueFactory.Create);\n        }\n\n        _lru.TryRemove(0);\n        _lru.TryRemove(1);\n        _lru.TryRemove(6);\n\n        _lru.Trim(1);\n\n        _lru.HotCount.Should().Be(HotCap);\n        _lru.WarmCount.Should().Be(WarmCap);\n        _lru.ColdCount.Should().Be(ColdCap - 1);\n    }\n\n    [Fact]\n    public void WhenRepeatedlyAddingAndRemovingSameValueLruRemainsInConsistentState()\n    {\n        for (var i = 0; i < Capacity; i++)\n        {\n            // Because TryRemove leaves the item in the queue, when it is eventually removed\n            // from the cold queue, it should not remove the newly created value.\n            _lru.GetOrAdd(1, _valueFactory.Create);\n            _lru.TryGet(1, out var value).Should().BeTrue();\n            _lru.TryRemove(1);\n        }\n    }\n\n    [Fact]\n    public void WhenKeyExistsTryUpdateUpdatesValueAndReturnsTrue()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryUpdate(1, \"2\").Should().BeTrue();\n\n        _lru.TryGet(1, out var value);\n        value.Should().Be(\"2\");\n    }\n\n    [Fact]\n    public void WhenKeyExistsTryUpdateDisposesOldValue()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n        var disposableValueFactory = new DisposableValueFactory();\n        var newValue = new DisposableItem();\n\n        lruOfDisposable.GetOrAdd(1, disposableValueFactory.Create);\n        lruOfDisposable.TryUpdate(1, newValue);\n\n        disposableValueFactory.Items[1].IsDisposed.Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenKeyDoesNotExistTryUpdateReturnsFalse()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryUpdate(2, \"3\").Should().BeFalse();\n    }\n\n    // backcompat: remove conditional compile\n#if NETCOREAPP3_0_OR_GREATER\n    [Fact]\n    public void WhenKeyExistsTryUpdateIncrementsUpdateCount()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryUpdate(1, \"2\").Should().BeTrue();\n\n        _lru.Metrics.Updated.Should().Be(1);\n    }\n\n    [Fact]\n    public void WhenKeyDoesNotExistTryUpdateDoesNotIncrementCounter()\n    {\n        _lru.GetOrAdd(1, _valueFactory.Create);\n\n        _lru.TryUpdate(2, \"3\").Should().BeFalse();\n\n        _lru.Metrics.Updated.Should().Be(0);\n    }\n#endif\n    [Fact]\n    public void WhenKeyDoesNotExistAddOrUpdateAddsNewItem()\n    {\n        _lru.AddOrUpdate(1, \"1\");\n\n        _lru.TryGet(1, out var value).Should().BeTrue();\n        value.Should().Be(\"1\");\n    }\n\n    [Fact]\n    public void WhenKeyExistsAddOrUpdateUpdatesExistingItem()\n    {\n        _lru.AddOrUpdate(1, \"1\");\n        _lru.AddOrUpdate(1, \"2\");\n\n        _lru.TryGet(1, out var value).Should().BeTrue();\n        value.Should().Be(\"2\");\n    }\n\n    [Fact]\n    public void WhenKeyExistsAddOrUpdateGuidUpdatesExistingItem()\n    {\n        var lru2 = new ConcurrentLruCache<int, Guid>(Capacity, EqualityComparer<int>.Default);\n\n        var b = new byte[8];\n        lru2.AddOrUpdate(1, new Guid(1, 0, 0, b));\n        lru2.AddOrUpdate(1, new Guid(2, 0, 0, b));\n\n        lru2.TryGet(1, out var value).Should().BeTrue();\n        value.Should().Be(new Guid(2, 0, 0, b));\n    }\n\n    [Fact]\n    public void WhenKeyExistsAddOrUpdateDisposesOldValue()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n        var disposableValueFactory = new DisposableValueFactory();\n        var newValue = new DisposableItem();\n\n        lruOfDisposable.GetOrAdd(1, disposableValueFactory.Create);\n        lruOfDisposable.AddOrUpdate(1, newValue);\n\n        disposableValueFactory.Items[1].IsDisposed.Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenKeyDoesNotExistAddOrUpdateMaintainsLruOrder()\n    {\n        AddOrUpdateRangeInclusive(1, Capacity + 1);\n\n        _lru.HotCount.Should().Be(HotCap);\n        _lru.WarmCount.Should().Be(WarmCap);\n        _lru.TryGet(0, out _).Should().BeFalse();\n    }\n\n    [Fact]\n    public void WhenCacheIsEmptyClearIsNoOp()\n    {\n        _lru.Clear();\n        _lru.Count.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenItemsExistClearRemovesAllItems()\n    {\n        _lru.AddOrUpdate(1, \"1\");\n        _lru.AddOrUpdate(2, \"2\");\n\n        _lru.Clear();\n\n        _lru.Count.Should().Be(0);\n\n        // verify queues are purged\n        _lru.HotCount.Should().Be(0);\n        _lru.WarmCount.Should().Be(0);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n    // This is a special case:\n    // Cycle 1: hot => warm\n    // Cycle 2: warm => warm\n    // Cycle 3: warm => cold\n    // Cycle 4: cold => remove\n    // Cycle 5: cold => remove\n    [Fact]\n    public void WhenCacheIsSize3ItemsExistAndItemsAccessedClearRemovesAllItems()\n    {\n        var lru = new ConcurrentLruCache<int, string>(3);\n\n        lru.AddOrUpdate(1, \"1\");\n        lru.AddOrUpdate(2, \"1\");\n\n        lru.TryGet(1, out _);\n        lru.TryGet(2, out _);\n\n        lru.Clear();\n\n        lru.Count.Should().Be(0);\n    }\n\n    [Theory]\n    [InlineData(1)]\n    [InlineData(2)]\n    [InlineData(3)]\n    [InlineData(4)]\n    [InlineData(5)]\n    [InlineData(6)]\n    [InlineData(7)]\n    [InlineData(8)]\n    [InlineData(9)]\n    [InlineData(10)]\n    public void WhenItemsExistAndItemsAccessedClearRemovesAllItems(int itemCount)\n    {\n        // By default capacity is 9. Test all possible states of touched items\n        // in the cache.\n\n        for (var i = 0; i < itemCount; i++)\n        {\n            _lru.AddOrUpdate(i, \"1\");\n        }\n\n        // touch n items\n        for (var i = 0; i < itemCount; i++)\n        {\n            _lru.TryGet(i, out _);\n        }\n\n        _lru.Clear();\n\n        _testOutputHelper.WriteLine(\"LRU \" + string.Join(\" \", _lru.Keys));\n\n        _lru.Count.Should().Be(0);\n\n        // verify queues are purged\n        _lru.HotCount.Should().Be(0);\n        _lru.WarmCount.Should().Be(0);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenWarmThenClearedIsWarmIsReset()\n    {\n        for (var i = 0; i < Capacity; i++)\n        {\n            Touch(i);\n        }\n\n        var testAccessor = GetTestAccessor(_lru);\n        testAccessor.IsWarm.Should().BeTrue();\n\n        _lru.Clear();\n        _lru.Count.Should().Be(0);\n        testAccessor.IsWarm.Should().BeFalse();\n\n        for (var i = 0; i < Capacity; i++)\n        {\n            Touch(i);\n        }\n\n        testAccessor.IsWarm.Should().BeTrue();\n        _lru.Count.Should().Be(_lru.Capacity);\n    }\n\n    [Fact]\n    public void WhenWarmThenTrimIsWarmIsReset()\n    {\n        GetOrAddRangeInclusive(1, Capacity);\n\n        var testAccessor = GetTestAccessor(_lru);\n        testAccessor.IsWarm.Should().BeTrue();\n        _lru.Trim(Capacity / 2);\n\n        testAccessor.IsWarm.Should().BeFalse();\n        _lru.Count.Should().Be(Capacity / 2);\n\n        for (var i = 0; i < Capacity; i++)\n        {\n            Touch(i);\n        }\n\n        testAccessor.IsWarm.Should().BeTrue();\n        _lru.Count.Should().Be(_lru.Capacity);\n    }\n\n    /// <summary>\n    /// Verifies that the cache properly disposes IDisposable items when they are removed via Clear().\n    /// This is important for preventing resource leaks when caching disposable objects.\n    /// </summary>\n    [Fact]\n    public void WhenItemsAreDisposableClearDisposesItemsOnRemove()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n\n        var items = Enumerable.Range(1, 4).Select(i => new DisposableItem()).ToList();\n\n        for (var i = 0; i < 4; i++)\n        {\n            lruOfDisposable.AddOrUpdate(i, items[i]);\n        }\n\n        lruOfDisposable.Clear();\n\n        items.All(i => i.IsDisposed == true).Should().BeTrue();\n    }\n\n    [Fact]\n    public void WhenTrimCountIsZeroThrows()\n    {\n        _lru.Invoking(l => _lru.Trim(0)).Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Fact]\n    public void WhenTrimCountIsMoreThanCapacityThrows()\n    {\n        _lru.Invoking(l => _lru.Trim(HotCap + WarmCap + ColdCap + 1)).Should().Throw<ArgumentOutOfRangeException>();\n    }\n\n    [Theory]\n    [InlineData(10)]\n    [InlineData(20)]\n    [InlineData(30)]\n    [InlineData(40)]\n    [InlineData(50)]\n    [InlineData(60)]\n    [InlineData(70)]\n    [InlineData(80)]\n    [InlineData(90)]\n    public void WhenColdItemsExistTrimRemovesExpectedItemCount(int trimCount)\n    {\n        FillCache();\n\n        // Warm items\n        var warmItems = Enumerable.Range(1, WarmCap).ToArray();\n        foreach (var item in warmItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        // Cold items (added but untouched)\n        var coldItems = Enumerable.Range(1000, ColdCap).ToArray();\n        foreach (var item in coldItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n        }\n\n        // Hot Items (evict the previous hot items to cold)\n        var hotItems = Enumerable.Range(2000, HotCap).ToArray();\n        foreach (var item in hotItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n        }\n\n        _lru.Trim(trimCount);\n\n        int[] expected = [\n            .. warmItems.Skip(Math.Max(0, trimCount - coldItems.Length)),\n            .. hotItems,\n            .. coldItems.Skip(trimCount)];\n        _lru.Keys.Order().Should().BeEquivalentTo(expected.Order());\n    }\n\n    [Theory]\n    [InlineData(1, new[] { 6, 5, 4, 3, 2 })]\n    [InlineData(2, new[] { 6, 5, 4, 3 })]\n    [InlineData(3, new[] { 6, 5, 4 })]\n    [InlineData(4, new[] { 6, 5 })]\n    [InlineData(5, new[] { 6 })]\n    [InlineData(6, new int[] { })]\n    [InlineData(7, new int[] { })]\n    [InlineData(8, new int[] { })]\n    [InlineData(9, new int[] { })]\n    public void WhenHotAndWarmItemsExistTrimRemovesExpectedItemCount(int itemCount, int[] expected)\n    {\n        // initial state:\n        // Hot = 6, 5, 4\n        // Warm = 3, 2, 1\n        // Cold = -\n        _lru.AddOrUpdate(1, \"1\");\n        _lru.AddOrUpdate(2, \"2\");\n        _lru.AddOrUpdate(3, \"3\");\n        _lru.GetOrAdd(1, i => i.ToString());\n        _lru.GetOrAdd(2, i => i.ToString());\n        _lru.GetOrAdd(3, i => i.ToString());\n\n        _lru.AddOrUpdate(4, \"4\");\n        _lru.AddOrUpdate(5, \"5\");\n        _lru.AddOrUpdate(6, \"6\");\n\n        _lru.Trim(itemCount);\n\n        _lru.Keys.Should().BeEquivalentTo(expected);\n    }\n\n    [Theory]\n    [InlineData(1, new[] { 3, 2 })]\n    [InlineData(2, new[] { 3 })]\n    [InlineData(3, new int[] { })]\n    [InlineData(4, new int[] { })]\n    [InlineData(5, new int[] { })]\n    [InlineData(6, new int[] { })]\n    [InlineData(7, new int[] { })]\n    [InlineData(8, new int[] { })]\n    [InlineData(9, new int[] { })]\n    public void WhenHotItemsExistTrimRemovesExpectedItemCount(int itemCount, int[] expected)\n    {\n        // initial state:\n        // Hot = 3, 2, 1\n        // Warm = -\n        // Cold = -\n        _lru.AddOrUpdate(1, \"1\");\n        _lru.AddOrUpdate(2, \"2\");\n        _lru.AddOrUpdate(3, \"3\");\n\n        _lru.Trim(itemCount);\n\n        _lru.Keys.Should().BeEquivalentTo(expected);\n    }\n\n    [Theory]\n    [InlineData(10)]\n    [InlineData(20)]\n    [InlineData(30)]\n    [InlineData(40)]\n    [InlineData(50)]\n    [InlineData(60)]\n    [InlineData(70)]\n    [InlineData(80)]\n    public void WhenColdItemsAreTouchedTrimRemovesExpectedItemCount(int trimCount)\n    {\n        FillCache();\n\n        // Warm items\n        var warmItems = Enumerable.Range(1, WarmCap).ToArray();\n        foreach (var item in warmItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        // Cold items (added but untouched)\n        var coldItems = Enumerable.Range(1000, ColdCap).ToArray();\n        foreach (var item in coldItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n        }\n\n        // Hot Items (evict the previous hot items to cold)\n        var hotItems = Enumerable.Range(2000, HotCap).ToArray();\n        foreach (var item in hotItems)\n        {\n            _lru.AddOrUpdate(item, item.ToString());\n        }\n\n        // Touch cold items to promote them to warm\n        foreach (var item in coldItems)\n        {\n            _lru.GetOrAdd(item, _valueFactory.Create);\n        }\n\n        _lru.Trim(trimCount);\n\n        int[] expected = [\n            .. warmItems.Skip(Math.Max(0, trimCount)),\n            .. hotItems,\n            .. coldItems];\n        _lru.Keys.Order().Should().BeEquivalentTo(expected.Order());\n        _testOutputHelper.WriteLine(\"LRU \" + string.Join(\" \", _lru.Keys));\n        _testOutputHelper.WriteLine(\"exp \" + string.Join(\" \", expected));\n\n        _lru.Keys.Should().BeEquivalentTo(expected);\n    }\n\n    [Theory]\n    [InlineData(1)]\n    [InlineData(2)]\n    [InlineData(3)]\n    [InlineData(4)]\n    [InlineData(5)]\n    [InlineData(6)]\n    [InlineData(7)]\n    [InlineData(8)]\n    [InlineData(9)]\n    [InlineData(10)]\n    public void WhenItemsExistAndItemsAccessedTrimRemovesAllItems(int itemCount)\n    {\n        // By default capacity is 9. Test all possible states of touched items\n        // in the cache.\n\n        for (var i = 0; i < itemCount; i++)\n        {\n            _lru.AddOrUpdate(i, \"1\");\n        }\n\n        // touch n items\n        for (var i = 0; i < itemCount; i++)\n        {\n            _lru.TryGet(i, out _);\n        }\n\n        _lru.Trim(Math.Min(itemCount, _lru.Capacity));\n\n        _testOutputHelper.WriteLine(\"LRU \" + string.Join(\" \", _lru.Keys));\n\n        _lru.Count.Should().Be(0);\n\n        // verify queues are purged\n        _lru.HotCount.Should().Be(0);\n        _lru.WarmCount.Should().Be(0);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n    [Theory]\n    [InlineData(1)]\n    [InlineData(2)]\n    [InlineData(3)]\n    [InlineData(4)]\n    [InlineData(5)]\n    [InlineData(6)]\n    [InlineData(7)]\n    [InlineData(8)]\n    [InlineData(9)]\n    [InlineData(10)]\n    public void WhenItemsRemovedClearRemovesAllItems(int itemCount)\n    {\n        for (var i = 0; i < itemCount; i++)\n        {\n            _lru.AddOrUpdate(i, \"1\");\n        }\n\n        // this leaves an item in the queue but not the dictionary\n        _lru.TryRemove(0, out _);\n\n        _lru.Clear();\n\n        _testOutputHelper.WriteLine(\"LRU \" + string.Join(\" \", _lru.Keys));\n\n        _lru.Count.Should().Be(0);\n\n        // verify queues are purged\n        _lru.HotCount.Should().Be(0);\n        _lru.WarmCount.Should().Be(0);\n        _lru.ColdCount.Should().Be(0);\n    }\n\n    [Fact]\n    public void WhenItemsAreDisposableTrimDisposesItems()\n    {\n        var lruOfDisposable = new ConcurrentLruCache<int, DisposableItem>(6, EqualityComparer<int>.Default);\n\n        var items = Enumerable.Range(1, 4).Select(i => new DisposableItem()).ToList();\n\n        for (var i = 0; i < 4; i++)\n        {\n            lruOfDisposable.AddOrUpdate(i, items[i]);\n        }\n\n        lruOfDisposable.Trim(2);\n\n        items[0].IsDisposed.Should().BeTrue();\n        items[1].IsDisposed.Should().BeTrue();\n        items[2].IsDisposed.Should().BeFalse();\n        items[3].IsDisposed.Should().BeFalse();\n    }\n\n    private void FillCache() => GetOrAddRangeInclusive(-1, -Capacity);\n\n    private void Print()\n    {\n#if DEBUG\n        _testOutputHelper.WriteLine(_lru.FormatLruString());\n#endif\n    }\n\n    private class ValueFactory\n    {\n        public int TimesCalled;\n\n        public string Create(int key)\n        {\n            TimesCalled++;\n            return key.ToString();\n        }\n\n        public string Create<TArg>(int key, TArg arg)\n        {\n            TimesCalled++;\n            return $\"{key}{arg}\";\n        }\n\n        public Task<string> CreateAsync(int key)\n        {\n            TimesCalled++;\n            return Task.FromResult(key.ToString());\n        }\n\n        public Task<string> CreateAsync<TArg>(int key, TArg arg)\n        {\n            TimesCalled++;\n            return Task.FromResult($\"{key}{arg}\");\n        }\n    }\n\n    private class DisposableItem : IDisposable\n    {\n        public bool IsDisposed { get; private set; }\n\n        public void Dispose()\n        {\n            IsDisposed = true;\n        }\n    }\n\n    private class DisposableValueFactory\n    {\n        public Dictionary<int, DisposableItem> Items { get; } = [];\n\n        public DisposableItem Create(int key)\n        {\n            var item = new DisposableItem();\n            Items.Add(key, item);\n            return item;\n        }\n\n        public Task<DisposableItem> CreateAsync(int key)\n        {\n            var item = new DisposableItem();\n            Items.Add(key, item);\n            return Task.FromResult(item);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ClientBuilderTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Hosting;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Xunit;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// A no-op implementation of IGatewayListProvider used for testing client configuration\n    /// without requiring actual gateway connectivity.\n    /// </summary>\n    public class NoOpGatewaylistProvider : IGatewayListProvider\n    {\n        public TimeSpan MaxStaleness => throw new NotImplementedException();\n\n        public bool IsUpdatable => throw new NotImplementedException();\n\n        public Task<IList<Uri>> GetGateways()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task InitializeGatewayListProvider()\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    /// <summary>\n    /// Tests for the Orleans ClientBuilder, which is responsible for configuring and building Orleans client instances.\n    /// These tests verify client configuration validation, service registration, and proper initialization of client components\n    /// without requiring a full Orleans cluster.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    [TestCategory(\"ClientBuilder\")]\n    public class ClientBuilderTests\n    {\n        /// <summary>\n        /// Tests that a client cannot be created without specifying a ClusterId and a ServiceId.\n        /// </summary>\n        [Fact]\n        public void ClientBuilder_ClusterOptionsTest()\n        {\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                var host = new HostBuilder()\n                    .UseOrleansClient((ctx, clientBuilder) =>\n                    {\n                        clientBuilder.Configure<ClusterOptions>(options =>\n                        {\n                            options.ClusterId = null;\n                            options.ServiceId = null;\n                        });\n\n                        clientBuilder.ConfigureServices(services =>\n                            services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                    })\n                    .Build();\n\n                _ = host.Services.GetRequiredService<IClusterClient>();\n            });\n\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                var host = new HostBuilder()\n                    .UseOrleansClient((ctx, clientBuilder) =>\n                    {\n                        clientBuilder.Configure<ClusterOptions>(options =>\n                        {\n                            options.ClusterId = \"someClusterId\";\n                            options.ServiceId = null;\n                        });\n\n                        clientBuilder.ConfigureServices(services =>\n                            services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                    })\n                    .Build();\n\n                _ = host.Services.GetRequiredService<IClusterClient>();\n            });\n\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                var host = new HostBuilder()\n                    .UseOrleansClient((ctx, clientBuilder) =>\n                    {\n                        clientBuilder.Configure<ClusterOptions>(options =>\n                        {\n                            options.ClusterId = null;\n                            options.ServiceId = \"someServiceId\";\n                        });\n\n                        clientBuilder.ConfigureServices(services =>\n                            services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                    })\n                    .Build();\n\n                _ = host.Services.GetRequiredService<IClusterClient>();\n            });\n\n            var host = new HostBuilder()\n                .UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder.Configure<ClusterOptions>(options =>\n                    {\n                        options.ClusterId = \"someClusterId\";\n                        options.ServiceId = \"someServiceId\";\n                    });\n\n                    clientBuilder.ConfigureServices(services => services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                })\n                .Build();\n\n            var client = host.Services.GetRequiredService<IClusterClient>();\n            Assert.NotNull(client);\n        }\n\n        /// <summary>\n        /// Tests that a client can be created without specifying configuration.\n        /// </summary>\n        [Fact]\n        public void ClientBuilder_NoSpecifiedConfigurationTest()\n        {\n            var hostBuilder = new HostBuilder()\n                .UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder.ConfigureServices(services => services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                })\n                .ConfigureServices(RemoveConfigValidators);\n\n            var host = hostBuilder.Build();\n\n            var client = host.Services.GetRequiredService<IClusterClient>();\n            Assert.NotNull(client);\n        }\n\n        /// <summary>\n        /// Verifies that the client throws an exception during startup if no grain interfaces are registered.\n        /// This ensures that clients have at least one grain interface to communicate with.\n        /// </summary>\n        [Fact]\n        public void ClientBuilder_ThrowsDuringStartupIfNoGrainInterfacesAdded()\n        {\n            // Add only an assembly with generated serializers but no grain interfaces\n            var hostBuilder = new HostBuilder()\n                .UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder\n                        .UseLocalhostClustering()\n                        .Configure<GrainTypeOptions>(options =>\n                        {\n                            options.Interfaces.Clear();\n                        });\n                })\n                .ConfigureServices(services => services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n\n            var host = hostBuilder.Build();\n\n            Assert.Throws<OrleansConfigurationException>(() => _ = host.Services.GetRequiredService<IClusterClient>());\n        }\n\n        /// <summary>\n        /// Tests that the <see cref=\"IClientBuilder.ConfigureServices\"/> delegate works as expected.\n        /// </summary>\n        [Fact]\n        public void ClientBuilder_ServiceProviderTest()\n        {\n            var hostBuilder = new HostBuilder()\n                .UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder.ConfigureServices(services => services.AddSingleton<IGatewayListProvider, NoOpGatewaylistProvider>());\n                })\n                .ConfigureServices(RemoveConfigValidators);\n\n            Assert.Throws<ArgumentNullException>(() => hostBuilder.ConfigureServices(null));\n\n            var registeredFirst = new int[1];\n\n            var one = new MyService { Id = 1 };\n            hostBuilder.ConfigureServices(\n                services =>\n                {\n                    Interlocked.CompareExchange(ref registeredFirst[0], 1, 0);\n                    services.AddSingleton(one);\n                });\n\n            var two = new MyService { Id = 2 };\n            hostBuilder.ConfigureServices(\n                services =>\n                {\n                    Interlocked.CompareExchange(ref registeredFirst[0], 2, 0);\n                    services.AddSingleton(two);\n                });\n\n            var host = hostBuilder.Build();\n\n            var client = host.Services.GetRequiredService<IClusterClient>();\n            var services = client.ServiceProvider.GetServices<MyService>()?.ToList();\n            Assert.NotNull(services);\n\n            // Both services should be registered.\n            Assert.Equal(2, services.Count);\n            Assert.NotNull(services.Find(svc => svc.Id == 1));\n            Assert.NotNull(services.Find(svc => svc.Id == 2));\n\n            // Service 1 should have been registered first - the pipeline order should be preserved.\n            Assert.Equal(1, registeredFirst[0]);\n\n            // The last registered service should be provided by default.\n            Assert.Equal(2, client.ServiceProvider.GetRequiredService<MyService>().Id);\n        }\n\n        /// <summary>\n        /// Tests that attempting to configure both a silo and a client in the same host throws an exception.\n        /// Orleans requires separate hosts for silos and clients.\n        /// </summary>\n        [Fact]\n        public void ClientBuilderThrowsDuringStartupIfSiloBuildersAdded()\n        {\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                _ = new HostBuilder()\n                    .UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder.UseLocalhostClustering();\n                    })\n                    .UseOrleansClient((ctx, clientBuilder) =>\n                    {\n                        clientBuilder.UseLocalhostClustering();\n                    });\n            });\n        }\n\n        /// <summary>\n        /// Tests that attempting to configure both a silo and a client using the Host.CreateApplicationBuilder API throws an exception.\n        /// This verifies that the same restriction applies to the modern hosting API.\n        /// </summary>\n        [Fact]\n        public void ClientBuilderWithHotApplicationBuilderThrowsDuringStartupIfSiloBuildersAdded()\n        {\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                _ = Host.CreateApplicationBuilder()\n                    .UseOrleans(siloBuilder =>\n                    {\n                        siloBuilder.UseLocalhostClustering();\n                    })\n                    .UseOrleansClient(clientBuilder =>\n                    {\n                        clientBuilder.UseLocalhostClustering();\n                    });\n            });\n        }\n\n        private static void RemoveConfigValidators(IServiceCollection services)\n        {\n            var validators = services.Where(descriptor => descriptor.ServiceType == typeof(IConfigurationValidator)).ToList();\n            foreach (var validator in validators) services.Remove(validator);\n        }\n\n        private class MyService\n        {\n            public int Id { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/CollectionFixtures.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// Defines the test collection for DefaultCluster tests in NonSilo.Tests.\n    /// This collection ensures all tests share the same cluster instance for better performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines the test collection for TestEnvironmentFixture.\n    /// This collection provides shared test environment setup across multiple test classes.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ConfigTests.cs",
    "content": "using System.Net;\nusing System.Net.Sockets;\nusing Orleans.Runtime.Configuration;\nusing Xunit;\nusing Xunit.Abstractions;\n\n// ReSharper disable RedundantTypeArgumentsOfMethod\n// ReSharper disable CheckNamespace\n// ReSharper disable ConvertToConstant.Local\n\nnamespace UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans configuration utilities, particularly the security features for handling sensitive connection strings.\n    /// These tests verify that Orleans properly redacts sensitive information from configuration strings for logging and diagnostics.\n    /// </summary>\n    public class ConfigTests\n    {\n        private readonly ITestOutputHelper output;\n\n        public ConfigTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests that Azure Storage connection strings have their account keys properly redacted.\n        /// This prevents sensitive authentication information from being exposed in logs.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\")]\n        public void Config_AzureConnectionInfo()\n        {\n            string azureConnectionStringInput =\n                @\"DefaultEndpointsProtocol=https;AccountName=test;AccountKey=q-SOMEKEY-==\";\n            output.WriteLine(\"Input = \" + azureConnectionStringInput);\n            string azureConnectionString = ConfigUtilities.RedactConnectionStringInfo(azureConnectionStringInput);\n            output.WriteLine(\"Output = \" + azureConnectionString);\n            Assert.True(azureConnectionString.EndsWith(\"AccountKey=<--SNIP-->\", StringComparison.InvariantCultureIgnoreCase),\n                \"Removed account key info from Azure connection string \" + azureConnectionString);\n        }\n\n        /// <summary>\n        /// Tests that SQL Server connection strings have their passwords properly redacted.\n        /// This ensures database credentials are not exposed in logs or error messages.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\")]\n        public void Config_AdoNetConnectionInfo()\n        {\n            string sqlConnectionStringInput =\n                @\"Server=myServerName\\myInstanceName;Database=myDataBase;User Id=myUsername;Password=myPassword\";\n            output.WriteLine(\"Input = \" + sqlConnectionStringInput);\n            string sqlConnectionString = ConfigUtilities.RedactConnectionStringInfo(sqlConnectionStringInput);\n            output.WriteLine(\"Output = \" + sqlConnectionString);\n            Assert.True(sqlConnectionString.EndsWith(\"Password=<--SNIP-->\", StringComparison.InvariantCultureIgnoreCase),\n                \"Removed password info from SqlServer connection string \" + sqlConnectionString);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\")]\n        public void Config_LocalIPAddressFallback_UsesIPv4Loopback()\n        {\n            var result = ConfigUtilities.ResolveLocalIPAddress(Array.Empty<IPAddress>(), AddressFamily.InterNetwork, interfaceName: null);\n            Assert.Equal(IPAddress.Loopback, result);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\")]\n        public void Config_LocalIPAddressFallback_UsesIPv6Loopback()\n        {\n            var result = ConfigUtilities.ResolveLocalIPAddress(Array.Empty<IPAddress>(), AddressFamily.InterNetworkV6, interfaceName: null);\n            Assert.Equal(IPAddress.IPv6Loopback, result);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\")]\n        public void Config_LocalIPAddressFallback_ThrowsForExplicitInterface()\n        {\n            Assert.Throws<Orleans.Runtime.OrleansException>(() => ConfigUtilities.ResolveLocalIPAddress(Array.Empty<IPAddress>(), AddressFamily.InterNetwork, \"en0\"));\n        }\n    }\n}\n\n// ReSharper restore ConvertToConstant.Local\n// ReSharper restore RedundantTypeArgumentsOfMethod\n// ReSharper restore CheckNamespace\n"
  },
  {
    "path": "test/Orleans.Core.Tests/DebuggerHelperTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests debugger helper functionality in Orleans.\n    /// Orleans provides debugging utilities that allow developers to inspect grain instances\n    /// during debugging sessions. This is useful for troubleshooting grain state and behavior\n    /// in development environments. The debugger helper provides access to the actual grain\n    /// instance behind the grain reference proxy.\n    /// </summary>\n    public class DebuggerHelperTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public DebuggerHelperTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests the ability to get the actual grain instance for debugging purposes.\n        /// Verifies that the OrleansDebuggerHelper can retrieve the concrete grain implementation\n        /// from within the grain itself. This is useful for inspecting private state during debugging.\n        /// Note: This functionality should only be used in development/debugging scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DebuggerHelper_GetGrainInstance()\n        {\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid()).Cast<IDebuggerHelperTestGrain>();\n            await grain.OrleansDebuggerHelper_GetGrainInstance_Test();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/CachedGrainLocatorTests.cs",
    "content": "// Ignore Spelling: Locator\n\nusing System.Collections.Immutable;\nusing System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing NSubstitute.ReceivedExtensions;\nusing Orleans.Configuration;\nusing Orleans.GrainDirectory;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Hosting;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.Directory\n{\n    /// <summary>\n    /// Tests for the CachedGrainLocator, which is Orleans' primary mechanism for locating grain activations across the cluster.\n    /// The locator maintains a local cache of grain locations to minimize directory lookups and improve performance.\n    /// It handles registration, lookup, and cleanup of grain activations while maintaining consistency with the distributed directory.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Directory\")]\n    public class CachedGrainLocatorTests\n    {\n        private readonly LoggerFactory loggerFactory;\n        private readonly SiloLifecycleSubject lifecycle;\n        private readonly IOptions<GrainDirectoryOptions> grainDirectoryOptions;\n        private readonly IGrainDirectory grainDirectory;\n        private readonly GrainDirectoryResolver grainDirectoryResolver;\n        private readonly MockClusterMembershipService mockMembershipService;\n        private readonly CachedGrainLocator grainLocator;\n\n        public CachedGrainLocatorTests(ITestOutputHelper output)\n        {\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(output) });\n            this.lifecycle = new SiloLifecycleSubject(this.loggerFactory.CreateLogger<SiloLifecycleSubject>());\n\n            this.grainDirectory = Substitute.For<IGrainDirectory>();\n            var services = new ServiceCollection()\n                .AddGrainDirectory(GrainDirectoryAttribute.DEFAULT_GRAIN_DIRECTORY, (sp, name) => this.grainDirectory)\n                .BuildServiceProvider();\n\n            this.grainDirectoryResolver = new GrainDirectoryResolver(\n                services,\n                new GrainPropertiesResolver(new NoOpClusterManifestProvider()),\n                Array.Empty<IGrainDirectoryResolver>());\n            this.mockMembershipService = new MockClusterMembershipService();\n\n            grainDirectoryOptions = Options.Create(new GrainDirectoryOptions());\n            this.grainLocator = new CachedGrainLocator(\n                services,\n                this.grainDirectoryResolver, \n                this.mockMembershipService.Target,\n                grainDirectoryOptions);\n\n            this.grainLocator.Participate(this.lifecycle);\n        }\n\n        // TODO\n        //[Fact]\n        //public void ConvertActivationAddressToGrainAddress()\n        //{\n        //    var expected = GenerateActivationAddress();\n        //    var grainAddress = expected.ToGrainAddress();\n        //    Assert.Equal(expected, grainAddress.ToActivationAddress());\n        //}\n\n        /// <summary>\n        /// Tests basic registration of a grain activation when no prior registration exists.\n        /// Verifies that the activation is registered in the directory and cached locally.\n        /// </summary>\n        [Fact]\n        public async Task RegisterWhenNoOtherEntryExists()\n        {\n            var silo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(silo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expected = GenerateGrainAddress(silo);\n\n            this.grainDirectory.Register(expected, previousAddress: null).Returns(expected);\n\n            var actual = await this.grainLocator.Register(expected, previousAddress: null);\n            Assert.Equal(expected, actual);\n            await this.grainDirectory.Received(1).Register(expected, previousAddress: null);\n\n            // Now should be in cache\n            Assert.True(this.grainLocator.TryLookupInCache(expected.GrainId, out var result));\n            Assert.NotNull(result);\n            Assert.Equal(expected, result);\n        }\n\n        [Fact]\n        public async Task RegisterWhenOtherEntryExists()\n        {\n            var expectedSilo = GenerateSiloAddress();\n            var otherSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n            var otherAddr = GenerateGrainAddress(otherSilo);\n\n            this.grainDirectory.Register(otherAddr, previousAddress: null).Returns(expectedAddr);\n\n            var actual = await this.grainLocator.Register(otherAddr, previousAddress: null);\n            Assert.Equal(expectedAddr, actual);\n            await this.grainDirectory.Received(1).Register(otherAddr, previousAddress: null);\n\n            // Now should be in cache\n            Assert.True(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out var result));\n            Assert.NotNull(result);\n            Assert.Equal(expectedAddr, result);\n        }\n\n        [Fact]\n        public async Task RegisterWhenOtherEntryExistsAndPreviousAddressMatches()\n        {\n            var silo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(silo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var existing = GenerateGrainAddress(silo);\n            var replacement = new GrainAddress\n            {\n                ActivationId = ActivationId.NewId(),\n                SiloAddress = GenerateSiloAddress(),\n                GrainId = existing.GrainId,\n                MembershipVersion = existing.MembershipVersion\n            };\n\n            this.grainDirectory.Register(replacement, previousAddress: null).Returns(existing);\n\n            var actual = await this.grainLocator.Register(replacement, previousAddress: null);\n            Assert.Equal(existing, actual);\n            await this.grainDirectory.Received(1).Register(replacement, previousAddress: null);\n            this.grainDirectory.ClearReceivedCalls();\n\n            this.grainDirectory.Register(replacement, previousAddress: existing).Returns(replacement);\n            actual = await this.grainLocator.Register(replacement, previousAddress: existing);\n            await this.grainDirectory.Received(1).Register(replacement, previousAddress: existing);\n            Assert.Equal(replacement, actual);\n\n            // Now should be in cache\n            Assert.True(this.grainLocator.TryLookupInCache(replacement.GrainId, out var result));\n            Assert.NotNull(result);\n            Assert.Equal(replacement, result);\n        }\n\n        [Fact]\n        public async Task RegisterWhenOtherEntryExistsAndPreviousAddressDoesNotMatch()\n        {\n            var silo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(silo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var existing = GenerateGrainAddress(silo);\n            var nonMatching = new GrainAddress\n            {\n                ActivationId = ActivationId.NewId(),\n                SiloAddress = GenerateSiloAddress(),\n                GrainId = existing.GrainId,\n                MembershipVersion = existing.MembershipVersion\n            };\n            var replacement = new GrainAddress\n            {\n                ActivationId = ActivationId.NewId(),\n                SiloAddress = GenerateSiloAddress(),\n                GrainId = existing.GrainId,\n                MembershipVersion = existing.MembershipVersion\n            };\n\n            this.grainDirectory.Register(replacement, previousAddress: null).Returns(existing);\n\n            var actual = await this.grainLocator.Register(replacement, previousAddress: null);\n            Assert.Equal(existing, actual);\n            await this.grainDirectory.Received(1).Register(replacement, previousAddress: null);\n            this.grainDirectory.ClearReceivedCalls();\n\n            this.grainDirectory.Register(replacement, previousAddress: nonMatching).Returns(existing);\n            actual = await this.grainLocator.Register(replacement, previousAddress: nonMatching);\n            await this.grainDirectory.Received(1).Register(replacement, previousAddress: nonMatching);\n            Assert.Equal(existing, actual);\n\n            // Cache should contain original address\n            Assert.True(this.grainLocator.TryLookupInCache(replacement.GrainId, out var result));\n            Assert.NotNull(result);\n            Assert.Equal(existing, result);\n        }\n\n        [Fact]\n        public async Task RegisterWhenOtherEntryExistsButSiloIsDead()\n        {\n            var expectedSilo = GenerateSiloAddress();\n            var outdatedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            this.mockMembershipService.UpdateSiloStatus(outdatedSilo, SiloStatus.Dead, \"old\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n            var outdatedAddr = GenerateGrainAddress(outdatedSilo);\n\n            // First returns the outdated entry, then the new one\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(outdatedAddr, expectedAddr);\n\n            var actual = await this.grainLocator.Register(expectedAddr, previousAddress: null);\n            Assert.Equal(expectedAddr, actual);\n            await this.grainDirectory.Received(2).Register(expectedAddr, previousAddress: null);\n            await this.grainDirectory.Received(1).Unregister(outdatedAddr);\n\n            // Now should be in cache\n            Assert.True(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out var result));\n            Assert.NotNull(result);\n            Assert.Equal(expectedAddr, result);\n\n            await this.lifecycle.OnStop();\n        }\n\n        [Fact]\n        public async Task LookupPopulateTheCache()\n        {\n            var expectedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var grainAddress = GenerateGrainAddress(expectedSilo);\n\n            this.grainDirectory.Lookup(grainAddress.GrainId).Returns(grainAddress);\n\n            // Cache should be empty\n            Assert.False(this.grainLocator.TryLookupInCache(grainAddress.GrainId, out _));\n\n            // Do a remote lookup\n            var result = await this.grainLocator.Lookup(grainAddress.GrainId);\n            Assert.NotNull(result);\n            Assert.Equal(grainAddress, result);\n\n            // Now cache should be populated\n            Assert.True(this.grainLocator.TryLookupInCache(grainAddress.GrainId, out var cachedValue));\n            Assert.NotNull(cachedValue);\n            Assert.Equal(grainAddress, cachedValue);\n        }\n\n        [Fact]\n        public async Task LookupWhenEntryExistsButSiloIsDead()\n        {\n            var outdatedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(outdatedSilo, SiloStatus.Dead, \"old\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var outdatedAddr = GenerateGrainAddress(outdatedSilo);\n\n            this.grainDirectory.Lookup(outdatedAddr.GrainId).Returns(outdatedAddr);\n\n            var actual = await this.grainLocator.Lookup(outdatedAddr.GrainId);\n            Assert.Null(actual);\n\n            await this.grainDirectory.Received(1).Lookup(outdatedAddr.GrainId);\n            await this.grainDirectory.Received(1).Unregister(outdatedAddr);\n            Assert.False(this.grainLocator.TryLookupInCache(outdatedAddr.GrainId, out _));\n\n            await this.lifecycle.OnStop();\n        }\n\n        [Fact]\n        public async Task LocalLookupWhenEntryExistsButSiloIsDead()\n        {\n            var outdatedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(outdatedSilo, SiloStatus.Dead, \"old\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var outdatedAddr = GenerateGrainAddress(outdatedSilo);\n\n            this.grainDirectory.Lookup(outdatedAddr.GrainId).Returns(outdatedAddr);\n            Assert.False(this.grainLocator.TryLookupInCache(outdatedAddr.GrainId, out _));\n\n            // Local lookup should never call the directory\n            await this.grainDirectory.DidNotReceive().Lookup(outdatedAddr.GrainId);\n            await this.grainDirectory.DidNotReceive().Unregister(outdatedAddr);\n\n            await this.lifecycle.OnStop();\n        }\n\n        /// <summary>\n        /// Tests that the locator properly cleans up cached entries when a silo dies.\n        /// This is critical for preventing requests from being sent to dead silos.\n        /// </summary>\n        [Fact]\n        public async Task CleanupWhenSiloIsDead()\n        {\n            var expectedSilo = GenerateSiloAddress();\n            var outdatedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            this.mockMembershipService.UpdateSiloStatus(outdatedSilo, SiloStatus.Active, \"old\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n            var outdatedAddr = GenerateGrainAddress(outdatedSilo);\n\n            // Register two entries\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(expectedAddr);\n            this.grainDirectory.Register(outdatedAddr, previousAddress: null).Returns(outdatedAddr);\n\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n            await this.grainLocator.Register(outdatedAddr, previousAddress: null);\n\n            // Simulate a dead silo\n            this.mockMembershipService.UpdateSiloStatus(outdatedAddr.SiloAddress, SiloStatus.Dead, \"old\");\n\n            // Wait a bit for the update to be processed\n            await WaitUntilClusterChangePropagated();\n\n            // Cleanup function from grain directory should have been called\n            await this.grainDirectory\n                .Received(1)\n                .UnregisterSilos(Arg.Is<List<SiloAddress>>(list => list.Count == 1 && list.Contains(outdatedAddr.SiloAddress)));\n\n            // Cache should have been cleaned\n            Assert.False(this.grainLocator.TryLookupInCache(outdatedAddr.GrainId, out var unused1));\n            Assert.True(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out var unused2));\n\n            var result = await this.grainLocator.Lookup(expectedAddr.GrainId);\n            Assert.NotNull(result);\n            Assert.Equal(expectedAddr, result);\n\n            await this.lifecycle.OnStop();\n        }\n\n        [Fact]\n        public async Task UnregisterCallDirectoryAndCleanCache()\n        {\n            var expectedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(expectedAddr);\n\n            // Register to populate cache\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n\n            // Unregister and check if cache was cleaned\n            await this.grainLocator.Unregister(expectedAddr, UnregistrationCause.Force);\n            Assert.False(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n        }\n\n        [Fact]\n        public async Task UnregisterRemovesFromCacheFirst()\n        {            \n            var expectedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n\n            // Give up control then Run forever\n            this.grainDirectory.Unregister(expectedAddr).Returns(async (t) => { await Task.Yield();  while (true) { } });\n\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(expectedAddr);\n\n            // Register to populate cache\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n\n            // Unregister and check if cache was cleaned\n            _ = this.grainLocator.Unregister(expectedAddr, UnregistrationCause.Force);\n            Assert.False(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n        }\n\n        [Fact]\n        public async Task UnregisterRacesWithLookupSameId()\n        {\n            var expectedSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n\n            ManualResetEvent mre = new ManualResetEvent(false);\n\n            // Give up control then Run forever\n            this.grainDirectory.Unregister(expectedAddr).Returns(async (t) =>\n            {\n                await Task.Yield();\n                mre.WaitOne();\n            });\n\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(expectedAddr);\n\n            // Register to populate cache\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n\n            // Unregister and check if cache was cleaned\n            Task t = this.grainLocator.Unregister(expectedAddr, UnregistrationCause.Force);\n            Assert.False(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n\n            // Add back to cache simulating a race from lookup\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n            Assert.True(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n\n            // Ensure when Unregister finishes if the race occured on the same id that it was removed\n            mre.Set();\n            await t;\n            Assert.False(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n        }\n\n        [Fact]\n        public async Task UnregisterRacesWithLookupDifferentId()\n        {\n            var expectedSilo = GenerateSiloAddress();\n            var secondSilo = GenerateSiloAddress();\n\n            // Setup membership service\n            this.mockMembershipService.UpdateSiloStatus(expectedSilo, SiloStatus.Active, \"exp\");\n            this.mockMembershipService.UpdateSiloStatus(secondSilo, SiloStatus.Active, \"exp\");\n            await this.lifecycle.OnStart();\n            await WaitUntilClusterChangePropagated();\n\n            var expectedAddr = GenerateGrainAddress(expectedSilo);\n            var secondAddr = GenerateGrainAddress(secondSilo);\n\n            ManualResetEvent mre = new ManualResetEvent(false);\n\n            // Give up control then Run forever\n            this.grainDirectory.Unregister(expectedAddr).Returns(async (t) =>\n            {\n                await Task.Yield();\n                mre.WaitOne();\n            });\n\n            this.grainDirectory.Register(expectedAddr, previousAddress: null).Returns(expectedAddr);\n            this.grainDirectory.Register(secondAddr, previousAddress: null).Returns(secondAddr);\n\n            // Register to populate cache\n            await this.grainLocator.Register(expectedAddr, previousAddress: null);\n\n            // Unregister and check if cache was cleaned\n            Task t = this.grainLocator.Unregister(expectedAddr, UnregistrationCause.Force);\n            Assert.False(this.grainLocator.TryLookupInCache(expectedAddr.GrainId, out _));\n\n            // Add back to cache simulating a race from lookup\n            await this.grainLocator.Register(secondAddr, previousAddress: null);\n            Assert.True(this.grainLocator.TryLookupInCache(secondAddr.GrainId, out _));\n\n            // Ensure when Unregister finishes if the race occured on the same id that it was removed\n            mre.Set();\n            await t;\n            Assert.True(this.grainLocator.TryLookupInCache(secondAddr.GrainId, out _));\n        }\n\n        private GrainAddress GenerateGrainAddress(SiloAddress siloAddress = null)\n        {\n            return new GrainAddress\n            {\n                GrainId = GrainId.Create(GrainType.Create(\"test\"), GrainIdKeyExtensions.CreateGuidKey(Guid.NewGuid())),\n                ActivationId = ActivationId.NewId(),\n                SiloAddress = siloAddress ?? GenerateSiloAddress(),\n                MembershipVersion = this.mockMembershipService.CurrentVersion,\n            };\n        }\n\n        private int generation = 0;\n        private SiloAddress GenerateSiloAddress() => SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), ++generation);\n\n        private async Task WaitUntilClusterChangePropagated()\n        {\n            await Until(() => this.mockMembershipService.CurrentVersion == ((CachedGrainLocator.ITestAccessor)this.grainLocator).LastMembershipVersion);\n        }\n\n        private static async Task Until(Func<bool> condition)\n        {\n            var maxTimeout = 40_000;\n            while (!condition() && (maxTimeout -= 10) > 0) await Task.Delay(10);\n            Assert.True(maxTimeout > 0);\n        }\n\n        private class NoOpClusterManifestProvider : IClusterManifestProvider\n        {\n            public ClusterManifest Current => new ClusterManifest(\n                MajorMinorVersion.Zero,\n                ImmutableDictionary<SiloAddress, GrainManifest>.Empty);\n\n            public IAsyncEnumerable<ClusterManifest> Updates => this.GetUpdates();\n\n            public GrainManifest LocalGrainManifest { get; } = new GrainManifest(ImmutableDictionary<GrainType, GrainProperties>.Empty, ImmutableDictionary<GrainInterfaceType, GrainInterfaceProperties>.Empty);\n\n            private async IAsyncEnumerable<ClusterManifest> GetUpdates()\n            {\n                yield return this.Current;\n                await Task.Delay(100);\n                yield break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/ClientDirectoryTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Collections.Immutable;\nusing System.Threading.Channels;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing NonSilo.Tests.Utilities;\nusing NSubstitute;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.Scheduler;\nusing UnitTests.Directory;\nusing Xunit;\n\nnamespace NonSilo.Tests.Directory\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Directory\")]\n    public class ClientDirectoryTests\n    {\n        private readonly ILocalSiloDetails _localSiloDetails;\n        private readonly SiloAddress _localSilo;\n        private readonly IOptions<SiloMessagingOptions> _messagingOptions;\n        private readonly ILoggerFactory _loggerFactory;\n        private readonly SiloLifecycleSubject _lifecycle;\n        private readonly List<DelegateAsyncTimer> _timers;\n        private readonly Channel<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)> _timerCalls;\n        private readonly DelegateAsyncTimerFactory _timerFactory;\n        private readonly MockClusterMembershipService _clusterMembershipService;\n        private readonly IInternalGrainFactory _grainFactory;\n        private readonly ClientDirectory _directory;\n        private readonly ClientDirectory.TestAccessor _testAccessor;\n        private readonly IConnectedClientCollection _connectedClientCollection;\n        private readonly ConcurrentDictionary<SiloAddress, IRemoteClientDirectory> _remoteDirectories = new ConcurrentDictionary<SiloAddress, IRemoteClientDirectory>();\n        private long _expectedConnectedClientsVersion;\n\n        public ClientDirectoryTests()\n        {\n            _connectedClientCollection = Substitute.For<IConnectedClientCollection>();\n            _connectedClientCollection.GetConnectedClientIds().ReturnsForAnyArgs(_ => new List<GrainId>());\n\n            _localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            _localSilo = Silo(\"127.0.0.1:100@100\");\n            _localSiloDetails.SiloAddress.Returns(_localSilo);\n            _localSiloDetails.DnsHostName.Returns(\"MyServer11\");\n            _localSiloDetails.Name.Returns(Guid.NewGuid().ToString(\"N\"));\n\n            _messagingOptions = Options.Create(new SiloMessagingOptions());\n            _loggerFactory = NullLoggerFactory.Instance;\n            _lifecycle = new SiloLifecycleSubject(_loggerFactory.CreateLogger<SiloLifecycleSubject>());\n            _timers = new List<DelegateAsyncTimer>();\n            _timerCalls = Channel.CreateUnbounded<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n            _timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            _timerCalls.Writer.TryWrite((overridePeriod, task));\n                            return task.Task;\n                        });\n                    _timers.Add(t);\n                    return t;\n                });\n\n            _clusterMembershipService = new MockClusterMembershipService();\n            _clusterMembershipService.UpdateSiloStatus(_localSilo, SiloStatus.Active, \"local-silo\");\n\n            _grainFactory = Substitute.For<IInternalGrainFactory>();\n            _grainFactory.GetSystemTarget<IRemoteClientDirectory>(default, default)\n                .ReturnsForAnyArgs(info => _remoteDirectories.GetOrAdd(info.ArgAt<SiloAddress>(1), k => Substitute.For<IRemoteClientDirectory>()));\n            var systemTargetShared = new SystemTargetShared(\n                runtimeClient: null!,\n                localSiloDetails: _localSiloDetails,\n                loggerFactory: _loggerFactory,\n                schedulingOptions: Options.Create(new SchedulingOptions()),\n                grainReferenceActivator: null,\n                timerRegistry: null,\n                activations: new ActivationDirectory());\n\n            _directory = new ClientDirectory(\n                grainFactory: _grainFactory,\n                siloDetails: _localSiloDetails,\n                messagingOptions: _messagingOptions,\n                loggerFactory: _loggerFactory,\n                clusterMembershipService: _clusterMembershipService,\n                timerFactory: _timerFactory,\n                connectedClients: _connectedClientCollection,\n                shared: systemTargetShared);\n            _testAccessor = new ClientDirectory.TestAccessor(_directory);\n\n            // Disable automatic publishing to simplify testing.\n            _testAccessor.SchedulePublishUpdate = () => { };\n        }\n\n        /// <summary>\n        /// Tests for the basic functionality of <see cref=\"ClientDirectory.TryLocalLookup(GrainId, out List{ActivationAddress})>)\"/>\n        /// </summary>\n        [Fact]\n        public void TryLocalLookupTests()\n        {\n            // Unknown clients don't exist locally.\n            var fakeClientId = Client(\"mr. snrub\");\n            Assert.False(_directory.TryLocalLookup(fakeClientId, out var lookupResult));\n            Assert.Null(lookupResult);\n\n            var hostedClientId = HostedClient.CreateHostedClientGrainId(_localSilo).GrainId;\n            Assert.True(_directory.TryLocalLookup(hostedClientId, out lookupResult));\n            Assert.NotNull(lookupResult);\n            var singleResult = Assert.Single(lookupResult);\n            Assert.Equal(Gateway.GetClientActivationAddress(hostedClientId, _localSilo), singleResult);\n\n            // Add the client and check that it's added successfully.\n            var clientsVersion = SetLocalClients(new List<GrainId> { fakeClientId });\n            Assert.True(_directory.TryLocalLookup(fakeClientId, out lookupResult));\n            Assert.NotNull(lookupResult);\n            singleResult = Assert.Single(lookupResult);\n            Assert.Equal(Gateway.GetClientActivationAddress(fakeClientId, _localSilo), singleResult);\n            Assert.Equal(clientsVersion, _testAccessor.ObservedConnectedClientsVersion);\n\n            // Remove the client and check that it's no longer found.\n            clientsVersion = SetLocalClients(new List<GrainId>(0));\n            Assert.False(_directory.TryLocalLookup(fakeClientId, out lookupResult));\n            Assert.Null(lookupResult);\n            Assert.Equal(clientsVersion, _testAccessor.ObservedConnectedClientsVersion);\n\n            // Add a new silo and ensure that its hosted client is immediately visible.\n            var remoteSilo = Silo(\"127.0.0.1:222@100\");\n            var hostedClientId2 = HostedClient.CreateHostedClientGrainId(remoteSilo).GrainId;\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo, SiloStatus.Active, \"remoteSilo\");\n            Assert.True(_directory.TryLocalLookup(hostedClientId2, out lookupResult));\n            Assert.NotNull(lookupResult);\n            Assert.Equal(Gateway.GetClientActivationAddress(hostedClientId2, remoteSilo), Assert.Single(lookupResult));\n        }\n\n        /// <summary>\n        /// Tests for the basic functionality of <see cref=\"ClientDirectory.Lookup(GrainId)\"/>\n        /// </summary>\n        [Fact]\n        public async Task LocalLookupTests()\n        {\n            // Unknown clients don't exist locally\n            var fakeClientId = Client(\"mr. snrub\");\n            var lookupResult = await _directory.Lookup(fakeClientId);\n            Assert.Empty(lookupResult);\n\n            var hostedClientId = HostedClient.CreateHostedClientGrainId(_localSilo).GrainId;\n            lookupResult = await _directory.Lookup(hostedClientId);\n            Assert.NotNull(lookupResult);\n            var singleResult = Assert.Single(lookupResult);\n            Assert.Equal(Gateway.GetClientActivationAddress(hostedClientId, _localSilo), singleResult);\n\n            // Add the client and check that it's added successfully\n            var clientsVersion = SetLocalClients(new List<GrainId> { fakeClientId });\n            lookupResult = await _directory.Lookup(fakeClientId);\n            Assert.NotNull(lookupResult);\n            singleResult = Assert.Single(lookupResult);\n            Assert.Equal(Gateway.GetClientActivationAddress(fakeClientId, _localSilo), singleResult);\n            Assert.Equal(clientsVersion, _testAccessor.ObservedConnectedClientsVersion);\n\n            // Remove the client and check that it's no longer found\n            clientsVersion = SetLocalClients(new List<GrainId>(0));\n            lookupResult = await _directory.Lookup(fakeClientId);\n            Assert.Empty(lookupResult);\n            Assert.Equal(clientsVersion, _testAccessor.ObservedConnectedClientsVersion);\n        }\n\n        /// <summary>\n        /// Tests that <see cref=\"ClientDirectory.Lookup(GrainId)\"/> will successfully reach out to a remote silo to perform lookups of client routes\n        /// whent hey are not available locally. Additionally, that any other returned routes are stored locally so that subsequent lookups are not\n        /// needed.\n        /// </summary>\n        [Fact]\n        public async Task RemoteLookupSuccessTests()\n        {\n            var remoteClientId = Client(\"remote1\");\n            var remoteClientId2 = Client(\"remote2\");\n            var remoteSilo = Silo(\"127.0.0.1:222@100\");\n\n            // Verify that a silo will ask a remote silo \n            _clusterMembershipService.UpdateSiloStatus(remoteSilo, SiloStatus.Active, \"remoteSilo\");\n            var remoteDirectory = _remoteDirectories.GetOrAdd(remoteSilo, Substitute.For<IRemoteClientDirectory>());\n            remoteDirectory.GetClientRoutes(default).ReturnsForAnyArgs(info =>\n            {\n                var versionVector = info.ArgAt<ImmutableDictionary<SiloAddress, long>>(0);\n                Assert.NotNull(versionVector);\n                Assert.True(versionVector.TryGetValue(_localSilo, out var localSiloVersion));\n                Assert.Equal(2, localSiloVersion);\n\n                Assert.True(versionVector.TryGetValue(remoteSilo, out var remoteSiloVersion));\n                Assert.Equal(0, remoteSiloVersion);\n\n                var result = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId>, long)>();\n                result[remoteSilo] = (ImmutableHashSet.CreateRange(new[] { remoteClientId, remoteClientId2 }), 2);\n                return Task.FromResult(result.ToImmutable());\n            });\n\n            var resultTask = _directory.Lookup(remoteClientId);\n            var result = Assert.Single(await resultTask);\n            Assert.Equal(Gateway.GetClientActivationAddress(remoteClientId, remoteSilo), result);\n\n            // In finding the first client, the silo should have learned about the other client\n            resultTask = _directory.Lookup(remoteClientId2);\n            result = Assert.Single(await resultTask);\n            Assert.Equal(Gateway.GetClientActivationAddress(remoteClientId2, remoteSilo), result);\n\n            // The remote silo should not have been queried a second time.\n            _ = remoteDirectory.Received(1).GetClientRoutes(Arg.Any<ImmutableDictionary<SiloAddress, long>>());\n\n            // Signal that the remote silo is shutting down. Both clients should disappear along with it.\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo, SiloStatus.ShuttingDown, \"remoteSilo\");\n            resultTask = _directory.Lookup(remoteClientId);\n            Assert.Empty(await resultTask);\n            resultTask = _directory.Lookup(remoteClientId2);\n            Assert.Empty(await resultTask);\n\n            // Since there are no other directories, no additional remote calls should have been made.\n            _ = remoteDirectory.Received(1).GetClientRoutes(Arg.Any<ImmutableDictionary<SiloAddress, long>>());\n        }\n\n        /// <summary>\n        /// Tests that <see cref=\"ClientDirectory.Lookup(GrainId)\"/> will continue despite failure reaching out to a remote silo.\n        /// </summary>\n        [Fact]\n        public async Task RemoteLookupFailureTests()\n        {\n            var remoteClientId = Client(\"remote1\");\n            var remoteClientId2 = Client(\"remote2\");\n            var remoteSilo = Silo(\"127.0.0.1:222@100\");\n            var remoteSilo2 = Silo(\"127.0.0.1:333@100\");\n\n            var numTimesToThrow = new[] { 1 };\n            IRemoteClientDirectory CreateRemoteDirectory()\n            {\n                var remoteDirectory = Substitute.For<IRemoteClientDirectory>();\n                remoteDirectory.GetClientRoutes(default).ReturnsForAnyArgs(info =>\n                {\n                    if (numTimesToThrow[0]-- > 0)\n                    {\n                        throw new TimeoutException(\"Unable\");\n                    }\n\n                    var result = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId>, long)>();\n                    result[remoteSilo] = (ImmutableHashSet.CreateRange(new[] { remoteClientId, remoteClientId2 }), 2);\n                    return Task.FromResult(result.ToImmutable());\n                });\n\n                return remoteDirectory;\n            }\n\n            _remoteDirectories.GetOrAdd(remoteSilo, CreateRemoteDirectory());\n            _remoteDirectories.GetOrAdd(remoteSilo2, CreateRemoteDirectory());\n\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo, SiloStatus.Active, \"remoteSilo\");\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo2, SiloStatus.Active, \"remoteSilo2\");\n\n            // Verify that a silo will ask a remote silo even after a failure\n            var resultTask = _directory.Lookup(remoteClientId);\n            var result = Assert.Single(await resultTask);\n            Assert.Equal(Gateway.GetClientActivationAddress(remoteClientId, remoteSilo), result);\n\n            // The silo should have made two calls: one failure and one successful call.\n            // Each call should have landed on a different silo.\n            foreach (var remoteDirectory in _remoteDirectories.Values)\n            {\n                _ = remoteDirectory.Received(1).GetClientRoutes(Arg.Any<ImmutableDictionary<SiloAddress, long>>());\n            }\n        }\n\n        [Fact]\n        public async Task PublishChangesSuccessTests()\n        {\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n            _testAccessor.SchedulePublishUpdate = () => _testAccessor.PublishUpdates().GetAwaiter().GetResult();\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n\n            var remoteClientId = Client(\"remote1\");\n            var remoteClientId2 = Client(\"remote2\");\n            var remoteSilo = Silo(\"127.0.0.1:222@100\");\n            var remoteSilo2 = Silo(\"127.0.0.1:333@100\");\n\n            var totalUpdateCalls = new[] { 0 };\n            var calledSilos = new List<SiloAddress>();\n            SiloAddress GetOtherRemoteSilo(SiloAddress silo) => silo.Equals(remoteSilo) ? remoteSilo2 : remoteSilo;\n            IRemoteClientDirectory CreateRemoteDirectory(SiloAddress silo)\n            {\n                var otherRemoteSilo = GetOtherRemoteSilo(silo);\n\n                var remoteDirectory = Substitute.For<IRemoteClientDirectory>();\n                remoteDirectory.GetClientRoutes(default).ReturnsForAnyArgs(info =>\n                {\n                    var result = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId>, long)>();\n                    result[silo] = (ImmutableHashSet.CreateRange(new[] { remoteClientId }), 2);\n                    return Task.FromResult(result.ToImmutable());\n                });\n\n                remoteDirectory.OnUpdateClientRoutes(default).ReturnsForAnyArgs(info =>\n                {\n                    calledSilos.Add(silo);\n                    var callNumber = ++totalUpdateCalls[0];\n                    var update = info.ArgAt<ImmutableDictionary<SiloAddress, (ImmutableHashSet<GrainId> ConnectedClients, long Version)>>(0);\n\n                    if (callNumber == 1)\n                    {\n                        Assert.True(update.TryGetValue(otherRemoteSilo, out var siloUpdate));\n                        Assert.Contains(remoteClientId2, siloUpdate.ConnectedClients);\n                    }\n                    else if (callNumber == 2)\n                    {\n                        // There should only be one silo in this update since the other remote silo is dead and this silo already has its own latest state.\n                        Assert.Single(update);\n                        Assert.True(update.TryGetValue(_localSilo, out var siloUpdate));\n                        Assert.Equal(3, siloUpdate.ConnectedClients.Count);\n                    }\n                    else\n                    {\n                        throw new InvalidOperationException(\"Unexpected call\");\n                    }\n\n                    return Task.CompletedTask;\n                });\n\n                return remoteDirectory;\n            }\n\n            _remoteDirectories.GetOrAdd(remoteSilo, CreateRemoteDirectory);\n            _remoteDirectories.GetOrAdd(remoteSilo2, CreateRemoteDirectory);\n\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo, SiloStatus.Active, \"remoteSilo\");\n            _clusterMembershipService.UpdateSiloStatus(remoteSilo2, SiloStatus.Active, \"remoteSilo2\");\n\n            var builder = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId>, long)>();\n            builder[remoteSilo] = (ImmutableHashSet.CreateRange(new[] { remoteClientId, remoteClientId2 }), 3);\n            builder[remoteSilo2] = (ImmutableHashSet.CreateRange(new[] { remoteClientId, remoteClientId2 }), 3);\n            await _directory.OnUpdateClientRoutes(builder.ToImmutable());\n            Assert.Equal(1, totalUpdateCalls[0]);\n\n            var oldSuccessor = calledSilos.Last();\n            _clusterMembershipService.UpdateSiloStatus(oldSuccessor, SiloStatus.Dead, \"blah\");\n            var newSuccessor = GetOtherRemoteSilo(oldSuccessor);\n            totalUpdateCalls[0] = 0;\n\n            // Add clients locally and see that they are propagated to the new successor.\n            SetLocalClients(new List<GrainId> { remoteClientId, remoteClientId2 });\n            builder = ImmutableDictionary.CreateBuilder<SiloAddress, (ImmutableHashSet<GrainId>, long)>();\n            builder[oldSuccessor] = (ImmutableHashSet.CreateRange(new[] { remoteClientId2 }), 4);\n            await _directory.OnUpdateClientRoutes(builder.ToImmutable());\n            Assert.Equal(1, totalUpdateCalls[0]);\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static GrainId Client(string id) => ClientGrainId.Create(id).GrainId;\n\n        private long SetLocalClients(List<GrainId> clients)\n        {\n            var clientCollectionVersion = ++_expectedConnectedClientsVersion;\n            _connectedClientCollection.GetConnectedClientIds().ReturnsForAnyArgs(_ => clients);\n            _connectedClientCollection.Version.ReturnsForAnyArgs(_ => clientCollectionVersion);\n            return clientCollectionVersion;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/DhtGrainLocatorTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Logging;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing TestExtensions;\nusing UnitTests.SchedulerTests;\nusing UnitTests.TesterInternal;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.Directory\n{\n    /// <summary>\n    /// Tests for distributed hash table grain locator functionality including grain unregistration and batch operations.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Directory\")]\n    public class DhtGrainLocatorTests\n    {\n        private readonly DhtGrainLocator target;\n        private readonly MockLocalGrainDirectory localGrainDirectory;\n        private readonly ITestOutputHelper output;\n        private readonly LoggerFactory loggerFactory;\n        private readonly UnitTestSchedulingContext rootContext;\n\n        public DhtGrainLocatorTests(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(output) });\n            this.rootContext = UnitTestSchedulingContext.Create(loggerFactory);\n            this.localGrainDirectory = new MockLocalGrainDirectory(\n                TimeSpan.FromMilliseconds(100),\n                TimeSpan.FromMilliseconds(200));\n            this.target = new DhtGrainLocator(this.localGrainDirectory, this.rootContext);\n        }\n\n        [Fact]\n        public async Task SingleDeactivation()\n        {\n            foreach (var cause in (UnregistrationCause[]) Enum.GetValues(typeof(UnregistrationCause)))\n             {\n                var activationAddress = GenerateActivationAddress();\n\n                await this.target.Unregister(activationAddress, cause);\n\n                Assert.Single(this.localGrainDirectory.UnregistrationReceived);\n                Assert.Equal(cause, this.localGrainDirectory.UnregistrationReceived[0].cause);\n                Assert.Equal(activationAddress, this.localGrainDirectory.UnregistrationReceived[0].activationAddress);\n\n                this.localGrainDirectory.Reset();\n            }\n        }\n\n        [Fact]\n        public async Task MultipleDeactivations()\n        {\n            foreach (var cause in (UnregistrationCause[])Enum.GetValues(typeof(UnregistrationCause)))\n            {\n                var batchn = 100;\n                var addresses = new List<GrainAddress>();\n                var tasks = new List<Task>();\n\n                for (var i = 0; i < batchn; i++)\n                {\n                    addresses.Add(GenerateActivationAddress());\n                }\n\n                foreach (var addr in addresses)\n                {\n                    tasks.Add(this.target.Unregister(addr, cause));\n                }\n\n                await Task.WhenAll(tasks);\n\n                Assert.True(batchn > this.localGrainDirectory.UnregistrationCounter);\n\n                Assert.All(this.localGrainDirectory.UnregistrationReceived, item => Assert.Equal(cause, item.cause));\n                Assert.Equal(addresses, this.localGrainDirectory.UnregistrationReceived.Select(item => item.activationAddress));\n\n                this.localGrainDirectory.Reset();\n            }\n        }\n\n        [Fact]\n        public async Task MultipleMixedDeactivations()\n        {\n            var batchn = 12;\n            var addresses = new List<GrainAddress>();\n            var tasks = new List<Task>();\n\n            var map = new Dictionary<GrainAddress, UnregistrationCause>();\n\n            foreach (var cause in (UnregistrationCause[])Enum.GetValues(typeof(UnregistrationCause)))\n            {\n                for (var i = 0; i < batchn; i++)\n                {\n                    var addr = GenerateActivationAddress();\n                    addresses.Add(addr);\n                    map.Add(addr, cause);\n                    tasks.Add(this.target.Unregister(addr, cause));\n                }\n            }\n\n            await Task.WhenAll(tasks);\n\n            Assert.All(this.localGrainDirectory.UnregistrationReceived, item => Assert.Equal(map[item.activationAddress], item.cause));\n            Assert.Equal(addresses.ToHashSet(), this.localGrainDirectory.UnregistrationReceived.Select(item => item.activationAddress).ToHashSet());\n\n            this.localGrainDirectory.Reset();\n        }\n\n        private int generation = 0;\n        private GrainAddress GenerateActivationAddress()\n        {\n            var grainId = LegacyGrainId.GetGrainIdForTesting(Guid.NewGuid());\n            var siloAddr = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), ++generation);\n\n            return GrainAddress.NewActivationAddress(siloAddr, grainId);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/DirectoryMembershipSnapshotTests.cs",
    "content": "using System.Collections.Immutable;\nusing Orleans.Runtime.GrainDirectory;\nusing CsCheck;\nusing Xunit;\nusing Orleans.Configuration;\n\nnamespace NonSilo.Tests.Directory;\n\n/// <summary>\n/// Tests for directory membership snapshot functionality including range ownership and ring coverage validation.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic sealed class DirectoryMembershipSnapshotTests\n{\n    private static readonly Gen<ClusterMembershipSnapshot> GenClusterMembershipSnapshot = Gen.Select(Gen.UInt, Gen.Enum<SiloStatus>(), (hash, status) => (hash, status))\n        .Array[Gen.Int[1, 30]].Select((tuple) =>\n    {\n        var dict = ImmutableDictionary.CreateBuilder<SiloAddress, ClusterMember>();\n        var port = 1;\n        foreach (var item in tuple)\n        {\n            var (hash, status) = item;\n            var addr = SiloAddress.New(new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, port++), (int)hash);\n            dict.Add(addr, new ClusterMember(addr, status, $\"Silo_{hash}\"));\n        }\n\n        return new ClusterMembershipSnapshot(dict.ToImmutable(), new(1));\n    });\n\n    private static readonly Gen<DirectoryMembershipSnapshot> GenDirectoryMembershipSnapshot =\n        GenClusterMembershipSnapshot.SelectMany(snapshot => Gen.UInt.Array[ConsistentRingOptions.DEFAULT_NUM_VIRTUAL_RING_BUCKETS].Array[snapshot.Members.Count].Select(hashes => \n    {\n        var i = 0;\n        return new DirectoryMembershipSnapshot(snapshot, null!, (_, _) => hashes[i++]);\n    }));\n\n    [Fact]\n    public void GetOwnerTest()\n    {\n        // As long as the cluster has at least one member, we should be able to find an owner.\n        Gen.Select(GenDirectoryMembershipSnapshot, Gen.UInt)\n            .Sample((snapshot, hash) => Assert.Equal(snapshot.Members.Length > 0, snapshot.TryGetOwner(hash, out var owner, out _)));\n    }\n\n    [Fact]\n    public void MembersDoNotIntersectTest()\n    {\n        // Member ranges should not intersect.\n        GenDirectoryMembershipSnapshot.Where(s => s.Members.Length > 0)\n            .Sample(snapshot =>\n            {\n                foreach (var range in snapshot.RangeOwners)\n                {\n                    foreach (var otherRange in snapshot.RangeOwners)\n                    {\n                        if (range == otherRange)\n                        {\n                            continue;\n                        }\n\n                        Assert.False(range.Range.Intersects(otherRange.Range));\n                    }\n                }\n            });\n    }\n\n    [Fact]\n    public void ViewCoversRingTest()\n    {\n        // The union of all member ranges should cover the entire ring.\n        GenDirectoryMembershipSnapshot.Where(s => s.Members.Length > 0)\n            .Sample(snapshot =>\n            {\n                uint sum = 0;\n                var allRanges = new List<RingRange>();\n                foreach (var member in snapshot.Members)\n                {\n                    Assert.Equal(snapshot.GetMemberRanges(member).Sum(range => range.Size), snapshot.GetMemberRangesByPartition(member).Sum(range => range.Size));\n                    foreach (var range in snapshot.GetMemberRanges(member))\n                    {\n                        allRanges.Add(range);\n                        sum += range.Size;\n                    }\n                }\n\n\n                Assert.Equal(uint.MaxValue, sum);\n\n                var allRangesCollection = RingRangeCollection.Create(allRanges);\n\n                Assert.Equal(uint.MaxValue, allRangesCollection.Size);\n                Assert.Equal(100f, allRangesCollection.SizePercent);\n                Assert.False(allRangesCollection.IsEmpty);\n                Assert.False(allRangesCollection.IsDefault);\n                Assert.True(allRangesCollection.IsFull);\n            });\n    }\n\n    [Fact]\n    public void MemberRangesCoverRingTest()\n    {\n        // The union of all member ranges should cover the entire ring.\n        GenDirectoryMembershipSnapshot.Where(s => s.Members.Length > 0)\n            .Sample(snapshot =>\n            {\n                uint sum = 0;\n                var allRanges = new List<RingRange>();\n                foreach (var member in snapshot.Members)\n                {\n                    foreach (var range in snapshot.GetMemberRangesByPartition(member))\n                    {\n                        allRanges.Add(range);\n                        sum += range.Size;\n                    }\n                }\n\n                Assert.Equal(uint.MaxValue, sum);\n                var allRangesCollection = RingRangeCollection.Create(allRanges);\n                Assert.Equal(uint.MaxValue, allRangesCollection.Size);\n                Assert.Equal(100f, allRangesCollection.SizePercent);\n                Assert.False(allRangesCollection.IsEmpty);\n                Assert.False(allRangesCollection.IsDefault);\n                Assert.True(allRangesCollection.IsFull);\n            });\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/GrainDirectoryResolverTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing Orleans;\nusing Orleans.GrainDirectory;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Runtime.GrainDirectory;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces.Directories;\nusing UnitTests.Grains.Directories;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Directory\n{\n    /// <summary>\n    /// Tests for grain directory resolver functionality including custom directory resolution and directory listing.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Directory\")]\n    public class GrainDirectoryResolverTests\n    {\n        private readonly IGrainDirectory azureDirectory = Substitute.For<IGrainDirectory>();\n        private readonly IGrainDirectory otherDirectory = Substitute.For<IGrainDirectory>();\n        private readonly IGrainDirectory againAnotherDirectory = Substitute.For<IGrainDirectory>();\n        private readonly IHost host;\n        private readonly GrainDirectoryResolver target;\n\n        public GrainDirectoryResolverTests(ITestOutputHelper output)\n        {\n            this.azureDirectory = Substitute.For<IGrainDirectory>();\n\n            var hostBuilder = new HostBuilder();\n            hostBuilder.UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder\n                    .AddGrainDirectory(CustomDirectoryGrain.DIRECTORY, (sp, nameof) => this.azureDirectory)\n                    .AddGrainDirectory(\"OtherDirectory\", (sp, nameof) => this.otherDirectory)\n                    .AddGrainDirectory(\"AgainAnotherDirectory\", (sp, nameof) => this.againAnotherDirectory)\n                    .ConfigureLogging(builder => builder.AddProvider(new XunitLoggerProvider(output)))\n                    .UseLocalhostClustering();\n            });\n\n            this.host = hostBuilder.Build();\n\n            this.target = host.Services.GetRequiredService<GrainDirectoryResolver>();\n        }\n\n        [Fact]\n        public void UserProvidedDirectory()\n        {\n            var grainId = host.Services.GetRequiredService<IGrainFactory>().GetGrain<ICustomDirectoryGrain>(Guid.NewGuid()).GetGrainId();\n            Assert.Same(this.azureDirectory, this.target.Resolve(grainId.Type));\n        }\n\n        [Fact]\n        public void DefaultDhtDirectory()\n        {\n            Assert.Null(this.target.Resolve(GrainType.Create(DefaultDirectoryGrain.DIRECTORY)));\n        }\n\n        [Fact]\n        public void ListAllDirectories()\n        {\n            \n            var expected = new[] { this.azureDirectory, this.otherDirectory, this.againAnotherDirectory };\n            Assert.Equal(expected, this.target.Directories.ToArray());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/GrainLocatorResolverTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.VisualStudio.TestPlatform.Utilities;\nusing NSubstitute;\nusing Orleans.GrainDirectory;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Hosting;\nusing TestExtensions;\nusing UnitTests.Grains.Directories;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Directory\n{\n    /// <summary>\n    /// Tests for grain locator resolver functionality including DHT, cached, and client grain locator resolution.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Directory\")]\n    public class GrainLocatorResolverTests\n    {\n        private readonly IGrainDirectory customDirectory;\n        private readonly IHost host;\n        private readonly GrainLocatorResolver target;\n\n        public GrainLocatorResolverTests(ITestOutputHelper output)\n        {\n            this.customDirectory = Substitute.For<IGrainDirectory>();\n\n            var hostBuilder = new HostBuilder();\n            hostBuilder.UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder\n                    .ConfigureServices(svc => svc.AddSingleton(Substitute.For<DhtGrainLocator>(null, null)))\n                    .ConfigureServices(svc => svc.AddGrainDirectory(CustomDirectoryGrain.DIRECTORY, (sp, nameof) => this.customDirectory))\n                    .ConfigureLogging(builder => builder.AddProvider(new XunitLoggerProvider(output)))\n                    .UseLocalhostClustering();\n            });\n            this.host = hostBuilder.Build();\n\n            this.target = this.host.Services.GetRequiredService<GrainLocatorResolver>();\n        }\n\n        [Fact]\n        public void ReturnsDhtGrainLocatorWhenUsingDhtDirectory()\n        {\n            var grainLocator = this.host.Services.GetRequiredService<DhtGrainLocator>();\n            Assert.Same(grainLocator, target.GetGrainLocator(GrainType.Create(DefaultDirectoryGrain.DIRECTORY)));\n        }\n\n        [Fact]\n        public void ReturnsCachedGrainLocatorWhenUsingCustomDirectory()\n        {\n            var grainLocator = this.host.Services.GetRequiredService<CachedGrainLocator>();\n            Assert.Same(grainLocator, target.GetGrainLocator(GrainType.Create(CustomDirectoryGrain.DIRECTORY)));\n        }\n\n        [Fact]\n        public void ReturnsClientGrainLocatorWhenUsingClient()\n        {\n            var grainLocator = this.host.Services.GetRequiredService<ClientGrainLocator>();\n            Assert.Same(grainLocator, target.GetGrainLocator(ClientGrainId.Create(\"client\").GrainId.Type));\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/MockClusterMembershipService.cs",
    "content": "using System.Collections.Immutable;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Utilities;\n\nnamespace UnitTests.Directory\n{\n    internal class MockClusterMembershipService : IClusterMembershipService\n    {\n        private long version = 0;\n        private readonly Dictionary<SiloAddress, (SiloStatus Status, string Name)> statuses;\n        private ClusterMembershipSnapshot snapshot;\n        private readonly AsyncEnumerable<ClusterMembershipSnapshot> updates;\n\n        ClusterMembershipSnapshot IClusterMembershipService.CurrentSnapshot => this.snapshot;\n\n        public MembershipVersion CurrentVersion => this.snapshot.Version;\n\n        IAsyncEnumerable<ClusterMembershipSnapshot> IClusterMembershipService.MembershipUpdates => this.updates;\n\n        public IClusterMembershipService Target => this;\n\n        public MockClusterMembershipService(Dictionary<SiloAddress, (SiloStatus Status, string Name)> initialStatuses = null)\n        {\n            this.statuses = initialStatuses ?? new Dictionary<SiloAddress, (SiloStatus Status, string Name)>();\n            this.snapshot = ToSnapshot(this.statuses, ++version);\n            this.updates = new AsyncEnumerable<ClusterMembershipSnapshot>(\n                initialValue: this.snapshot,\n                updateValidator: (previous, proposed) => proposed.Version > previous.Version,\n                onPublished: update => Interlocked.Exchange(ref this.snapshot, update));\n        }\n\n        public void UpdateSiloStatus(SiloAddress siloAddress, SiloStatus siloStatus, string name)\n        {\n            this.statuses[siloAddress] = (siloStatus, name);\n            this.updates.Publish(ToSnapshot(this.statuses, ++version));\n        }\n\n        internal static ClusterMembershipSnapshot ToSnapshot(Dictionary<SiloAddress, (SiloStatus Status, string Name)> statuses, long version)\n        {\n            var dictBuilder = ImmutableDictionary.CreateBuilder<SiloAddress, ClusterMember>();\n            foreach (var kvp in statuses)\n                dictBuilder.Add(kvp.Key, new ClusterMember(kvp.Key, kvp.Value.Status, kvp.Value.Name));\n\n            return new ClusterMembershipSnapshot(dictBuilder.ToImmutable(), new MembershipVersion(version));\n        }\n\n        public ValueTask Refresh(MembershipVersion minimumVersion = default, CancellationToken cancellationToken = default) => new ValueTask();\n\n        public Task<bool> TryKill(SiloAddress siloAddress) => throw new NotImplementedException();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/MockLocalGrainDirectory.cs",
    "content": "using Orleans.GrainDirectory;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\n\nnamespace UnitTests.Directory\n{\n    internal class MockLocalGrainDirectory : ILocalGrainDirectory\n    {\n        private readonly TimeSpan singleOperationDelay;\n        private readonly TimeSpan batchOperationDelay;\n\n        public List<(GrainAddress activationAddress, UnregistrationCause cause)> UnregistrationReceived { get; private set; }\n\n        public int UnregistrationCounter { get; private set; }\n\n        public MockLocalGrainDirectory(TimeSpan singleOperationDelay, TimeSpan batchOperationDelay)\n        {\n            Reset();\n            this.singleOperationDelay = singleOperationDelay;\n            this.batchOperationDelay = batchOperationDelay;\n        }\n\n        public void Reset()\n        {\n            this.UnregistrationCounter = 0;\n            this.UnregistrationReceived = new List<(GrainAddress activationAddress, UnregistrationCause cause)>();\n        }\n\n        public async Task UnregisterAsync(GrainAddress address, UnregistrationCause cause, int hopCount = 0)\n        {\n            this.UnregistrationCounter++;\n            await Task.Delay(singleOperationDelay);\n            this.UnregistrationReceived.Add((address, cause));\n        }\n\n        public async Task UnregisterManyAsync(List<GrainAddress> addresses, UnregistrationCause cause, int hopCount = 0)\n        {\n            this.UnregistrationCounter++;\n            await Task.Delay(batchOperationDelay);\n            foreach(var addr in addresses)\n            {\n                this.UnregistrationReceived.Add((addr, cause));\n            }\n        }\n\n        #region Not Implemented\n        public RemoteGrainDirectory RemoteGrainDirectory => throw new NotImplementedException();\n\n        public RemoteGrainDirectory CacheValidator => throw new NotImplementedException();\n\n        public Task DeleteGrainAsync(GrainId grainId, int hopCount = 0)\n        {\n            throw new NotImplementedException();\n        }\n\n        public GrainAddress GetLocalCacheData(GrainId grain)\n        {\n            throw new NotImplementedException();\n        }\n\n        public AddressAndTag GetLocalDirectoryData(GrainId grain)\n        {\n            throw new NotImplementedException();\n        }\n\n        public SiloAddress GetPrimaryForGrain(GrainId grain)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void InvalidateCacheEntry(GrainAddress activation)\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool IsSiloInCluster(SiloAddress silo)\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool LocalLookup(GrainId grain, out AddressAndTag addresses)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<AddressAndTag> LookupAsync(GrainId grainId, int hopCount = 0)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<AddressAndTag> RegisterAsync(GrainAddress address, int hopCount = 0)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<AddressAndTag> RegisterAsync(GrainAddress address, GrainAddress previousAddress, int hopCount = 0)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void SetSiloRemovedCatalogCallback(Action<ILocalGrainDirectory, SiloAddress, SiloStatus> catalogOnSiloRemoved)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void Start()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task StopAsync()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task UnregisterAfterNonexistingActivation(GrainAddress address, SiloAddress origin)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void AddOrUpdateCacheEntry(GrainId grainId, SiloAddress siloAddress) => throw new NotImplementedException();\n\n        public void InvalidateCacheEntry(GrainId grainId) => throw new NotImplementedException();\n        public bool TryCachedLookup(GrainId grainId, out GrainAddress address) => throw new NotImplementedException();\n        #endregion\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/RingRangeCollectionTests.cs",
    "content": "using System.Collections.Immutable;\nusing Orleans.Runtime.GrainDirectory;\nusing CsCheck;\nusing Xunit;\n\nnamespace NonSilo.Tests.Directory;\n\n/// <summary>\n/// Tests for ring range collection operations including containment, intersection, and difference calculations.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic sealed class RingRangeCollectionTests\n{\n    private static readonly Gen<RingRangeCollection> GenRingRangeCollection = Gen.Int[0, 100].SelectMany(count => Gen.Select(Gen.UInt, Gen.Bool, static (boundary, included) => (boundary, included)).Array[count].Select(elements =>\n    {\n        var arr = ImmutableArray.CreateBuilder<RingRange>(elements.Length);\n        for (var i = 1; i < arr.Count;)\n        {\n            var prev = elements[i - 1];\n            var (boundary, included) = elements[i];\n            if (!included)\n            {\n                continue;\n            }\n\n            arr.Add(RingRange.Create(prev.boundary, boundary));\n        }\n\n        return RingRangeCollection.Create(arr);\n    }));\n\n    [Fact]\n    public void Contains()\n    {\n        Gen.Select(GenRingRangeCollection, Gen.UInt).Sample((ranges, point) =>\n        {\n            var doesContain = ranges.Ranges.Any(r => r.Contains(point));\n            Assert.Equal(doesContain, ranges.Contains(point));\n        });\n    }\n\n    [Fact]\n    public void Intersects()\n    {\n        GenRingRangeCollection.Sample(ranges =>\n        {\n            foreach (var range in ranges.Ranges)\n            {\n                Assert.True(ranges.Intersects(range));\n            }\n        });\n    }\n\n    [Fact]\n    public void Difference()\n    {\n        var ringWithUpdates = GenRingRangeCollection.SelectMany(original => Gen.Float[0f, 1f].Array[original.Ranges.Length].Select(diffs =>\n        {\n            // Increase or decrease the end of each range by some amount.\n            var arr = ImmutableArray.CreateBuilder<RingRange>(original.Ranges.Length);\n            for (var i = 0; i < diffs.Length; i++)\n            {\n                var orig = original.Ranges[i];\n                var next = original.Ranges[(i + 1) % original.Ranges.Length];\n                var maxPossibleLength = RingRange.Create(orig.Start, next.Start).Size;\n                var newEnd = orig.Start + maxPossibleLength * diffs[i];\n                arr.Add(RingRange.Create(orig.Start, (uint)Math.Clamp(orig.End + diffs[i], orig.Start + 1, next.Start)));\n            }\n\n            return (original, RingRangeCollection.Create(arr));\n        }));\n\n        ringWithUpdates.Sample((original, updated) =>\n        {\n            var additions = updated.Difference(original);\n            \n            foreach (var addition in additions)\n            {\n                Assert.True(updated.Intersects(addition));\n                Assert.False(original.Intersects(addition));\n            }\n\n            var removals = updated.Difference(original);\n            \n            foreach (var removal in removals)\n            {\n                Assert.False(updated.Intersects(removal));\n                Assert.True(original.Intersects(removal));\n            }\n        });\n    }\n\n    [Fact]\n    public void ContainsTest()\n    {\n        Gen.Select(GenRingRangeCollection, Gen.UInt).Sample((collection, point) =>\n        {\n            var allRanges = collection.Ranges.ToList();\n            var expectedContains = allRanges.Any(r => r.Contains(point));\n            Assert.Equal(expectedContains, collection.Contains(point));\n            var numContains = collection.Count(r => r.Contains(point));\n            Assert.Equal(expectedContains ? 1 : 0, numContains);\n        });\n    }\n\n    [Fact]\n    public void ContainsWrappedTest()\n    {\n        var ranges = new RingRange[]\n        {\n            RingRange.Create(0x10930012, 0x179C5AD4),\n            RingRange.Create(0x287844C7, 0x2B5DCCCB),\n            RingRange.Create(0x32AC80C2, 0x36F72978),\n            RingRange.Create(0x6F5C3AAC, 0x7776E202),\n            RingRange.Create(0x7D2B02F3, 0x7DF52810),\n            RingRange.Create(0xA18205D1, 0xA3A44031),\n            RingRange.Create(0xA847CD39, 0xAD6C28D0),\n            RingRange.Create(0xAF60D42F, 0xB278D2BE),\n            RingRange.Create(0xBB8EA837, 0xC61DA5E1),\n            RingRange.Create(0xF08C2237, 0xF3030A5A)\n        }.ToImmutableArray();\n        var collection = new RingRangeCollection(ranges);\n        uint point = 0x16F4037C;\n        Assert.True(ranges[0].Contains(point));\n        Assert.True(collection.Contains(point));\n\n        // Just outside the last range.\n        point = 0xF3030A5A + 1;\n        Assert.False(ranges[^1].Contains(point));\n        Assert.False(collection.Contains(point));\n\n        // Just inside the last range.\n        point = 0xF3030A5A;\n        Assert.True(ranges[^1].Contains(point));\n        Assert.True(collection.Contains(point));\n\n        // Between ranges.\n        point = 0xF08C2237 - 1;\n        Assert.False(collection.Contains(point));\n\n        // In an interior range.\n        point = 0x7D2B02F3 + 1;\n        Assert.True(collection.Contains(point));\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Directory/RingRangeTests.cs",
    "content": "using Orleans.Runtime.GrainDirectory;\nusing CsCheck;\nusing Xunit;\n\nnamespace NonSilo.Tests.Directory;\n\n/// <summary>\n/// Tests for ring range operations including difference, complement, intersection, and containment logic.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic sealed class RingRangeTests\n{\n    internal static Gen<RingRange> GenRingRange => Gen.Select(Gen.UInt, Gen.UInt, RingRange.Create);\n\n    [Fact]\n    public void RingRangeDifference_EquallyDividedRange()\n    {\n        var previous = RingRange.Empty;\n        var current = CreateEquallyDividedRange(2, 0);\n        Assert.Empty(current.Difference(current));\n\n        Assert.Equal(current, Assert.Single(current.Difference(previous)));\n        Assert.Empty(previous.Difference(current));\n\n        var firstHalf = CreateEquallyDividedRange(2, 0);\n        var secondHalf = CreateEquallyDividedRange(2, 1);\n\n        Assert.Equal(firstHalf, Assert.Single(firstHalf.Difference(secondHalf)));\n        Assert.Equal(secondHalf, Assert.Single(secondHalf.Difference(firstHalf)));\n    }\n\n    [Fact]\n    public void ComplementDoesNotIntersect()\n    {\n        GenRingRange.Where(range => !range.IsEmpty && !range.IsFull)\n            .Sample((sample) =>\n            {\n                var inverse = sample.Complement();\n                Assert.False(sample.Intersects(inverse));\n                Assert.Empty(sample.Intersections(inverse));\n                Assert.False(sample.Contains(inverse.End));\n                var difference = Assert.Single(sample.Difference(inverse));\n                Assert.Equal(sample, difference);\n                var inverseDifference = Assert.Single(inverse.Difference(sample));\n                Assert.Equal(inverse, inverseDifference);\n            });\n    }\n\n    [Fact]\n    public void ComplementComplementIsEqual()\n    {\n        GenRingRange\n            .Sample((sample) =>\n            {\n                var inverse = sample.Complement();\n                var inverseInverse = inverse.Complement();\n                Assert.True(sample.Equals(inverseInverse));\n            });\n    }\n\n    [Fact]\n    public void RingRangeDifference_HolePunch()\n    {\n        var first = CreateEquallyDividedRange(8, 0);\n        var second = CreateEquallyDividedRange(8, 1);\n        var third = CreateEquallyDividedRange(8, 2);\n        var fullRange = RingRange.Create(first.Start, third.End);\n\n        var midPunch = fullRange.Difference(second);\n        Assert.Equal(2, midPunch.Count());\n        Assert.Equal(first, midPunch.First());\n        Assert.Equal(third, midPunch.Last());\n    }\n\n    [Fact]\n    public void RingRangeDifference_Empty()\n    {\n        var current = RingRange.Create(0x33333334, 0x66666667);\n        var result = current.Difference(RingRange.Empty);\n        Assert.Equal(current, Assert.Single(result));\n    }\n\n    [Fact]\n    public void RingRangeDifference_Empty_Two()\n    {\n        var current = RingRange.Create(0x33333334, 0x66666667);\n        var previous = RingRange.Create(uint.MaxValue - 1, 1);\n        var result = Assert.Single(current.Difference(previous));\n        Assert.Equal(current, result);\n        Assert.Equal(previous, Assert.Single(previous.Difference(current)));\n    }\n\n    [Fact]\n    public void RingRangeIntersection()\n    {\n        Assert.Empty(RingRange.Empty.Difference(RingRange.Empty));\n\n        Assert.Empty(RingRange.Full.Difference(RingRange.Full));\n\n        Assert.Equal(RingRange.Full, Assert.Single(RingRange.Full.Difference(RingRange.Empty)));\n\n        Assert.Empty(RingRange.Empty.Difference(RingRange.Full));\n    }\n\n    [Fact]\n    public void RingRangeContains()\n    {\n        Assert.False(RingRange.Empty.Contains(0));\n        Assert.False(RingRange.Empty.Contains(1));\n        Assert.False(RingRange.Empty.Contains(uint.MaxValue));\n        Assert.False(RingRange.Empty.Contains(uint.MaxValue / 2));\n\n        Assert.True(RingRange.Full.Contains(0));\n        Assert.True(RingRange.Full.Contains(1));\n        Assert.True(RingRange.Full.Contains(uint.MaxValue));\n        Assert.True(RingRange.Full.Contains(uint.MaxValue / 2));\n\n        var wrapped = RingRange.Create(uint.MaxValue - 10, 10);\n        Assert.True(wrapped.Contains(0));\n        Assert.True(wrapped.Contains(1));\n        Assert.True(wrapped.Contains(uint.MaxValue));\n        Assert.False(wrapped.Contains(uint.MaxValue / 2));\n    }\n\n    [InlineData(1)]\n    [InlineData(2)]\n    [InlineData(3)]\n    [InlineData(17)]\n    [InlineData(33)]\n    [Theory]\n    public void EqualRangeInvariants(int count)\n    {\n        var sum = 0ul;\n        var previous = RingRange.Empty;\n        for (var i = 0; i < count; i++)\n        {\n            var range = CreateEquallyDividedRange(count, i);\n            Assert.False(previous.Intersects(range));\n            sum += range.Size;\n            previous = range;\n        }\n\n        Assert.Equal(uint.MaxValue, sum);\n    }\n\n    private static RingRange CreateEquallyDividedRange(int count, int index)\n    {\n        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, count, nameof(index));\n        ArgumentOutOfRangeException.ThrowIfLessThan(count, 1);\n        return Core((uint)count, (uint)index);\n        static RingRange Core(uint count, uint index)\n        {\n            ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, count, nameof(index));\n\n            if (count == 1 && index == 0)\n            {\n                return RingRange.Full;\n            }\n\n            var rangeSize = (ulong)uint.MaxValue + 1;\n            var portion = rangeSize / count;\n            var remainder = rangeSize - portion * count;\n            var start = 0u;\n            for (var i = 0; i < count; i++)\n            {\n                // (Start, End]\n                var end = unchecked((uint)(start + portion));\n\n                if (remainder > 0)\n                {\n                    end++;\n                    remainder--;\n                }\n\n                if (i == index)\n                {\n                    return RingRange.Create(start, end);\n                }\n\n                start = end;\n            }\n\n            throw new ArgumentException(null, nameof(index));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/DurableJobs/DurableJobReceiverExtensionTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing NSubstitute;\nusing Orleans.DurableJobs;\nusing Orleans.Runtime;\nusing Xunit;\n\nnamespace NonSilo.Tests.ScheduledJobs;\n\n[TestCategory(\"DurableJobs\")]\npublic class DurableJobReceiverExtensionTests\n{\n    [Fact]\n    public async Task HandleDurableJobAsync_WhenExecutionTaskIsCanceled_PropagatesCancellation()\n    {\n        var handler = Substitute.For<IDurableJobHandler>();\n        handler.ExecuteJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(Task.FromCanceled(new CancellationToken(canceled: true)));\n\n        var extension = CreateExtension(handler);\n        var context = CreateJobContext(\"run-1\");\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => extension.HandleDurableJobAsync(context, CancellationToken.None));\n    }\n\n    [Fact]\n    public async Task HandleDurableJobAsync_WhenTokenIsCanceledButExecutionIsStillRunning_RemainsPending()\n    {\n        var executionTask = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n        var handler = Substitute.For<IDurableJobHandler>();\n        handler.ExecuteJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(executionTask.Task);\n\n        var extension = CreateExtension(handler);\n        var context = CreateJobContext(\"run-1\");\n        using var cts = new CancellationTokenSource();\n        cts.Cancel();\n\n        var first = await extension.HandleDurableJobAsync(context, cts.Token);\n        var second = await extension.HandleDurableJobAsync(context, cts.Token);\n\n        Assert.True(first.IsPending);\n        Assert.True(second.IsPending);\n        await handler.Received(1).ExecuteJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>());\n\n        executionTask.SetResult(true);\n    }\n\n    [Fact]\n    public void DurableJobRunResult_Failed_ThrowsForNullException()\n    {\n        Assert.Throws<ArgumentNullException>(() => DurableJobRunResult.Failed(null!));\n    }\n\n    private static DurableJobReceiverExtension CreateExtension(IDurableJobHandler handler)\n    {\n        var grainContext = Substitute.For<IGrainContext>();\n        grainContext.GrainInstance.Returns(handler);\n        grainContext.GrainId.Returns(GrainId.Create(\"test\", \"grain-1\"));\n        return new DurableJobReceiverExtension(grainContext, NullLogger<DurableJobReceiverExtension>.Instance);\n    }\n\n    private static IJobRunContext CreateJobContext(string runId)\n    {\n        var context = Substitute.For<IJobRunContext>();\n        context.RunId.Returns(runId);\n        context.DequeueCount.Returns(1);\n        context.Job.Returns(new DurableJob\n        {\n            Id = \"job-1\",\n            Name = \"job-1\",\n            DueTime = DateTimeOffset.UtcNow,\n            TargetGrainId = GrainId.Create(\"test\", \"grain-1\"),\n            ShardId = \"shard-1\"\n        });\n\n        return context;\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.Core.Tests/DurableJobs/InMemoryJobQueueTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.DurableJobs;\nusing Orleans.Runtime;\nusing NSubstitute;\nusing Xunit;\n\nnamespace NonSilo.Tests.DurableJobs;\n\n[TestCategory(\"DurableJobs\")]\npublic class InMemoryJobQueueTests\n{\n    [Fact]\n    public void Enqueue_AddsJobToQueue()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddSeconds(1));\n\n        queue.Enqueue(job, 0);\n\n        Assert.Equal(1, queue.Count);\n    }\n\n    [Fact]\n    public void Enqueue_MultipleJobs_IncreasesCount()\n    {\n        var queue = new InMemoryJobQueue();\n        var job1 = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddSeconds(1));\n        var job2 = CreateJob(\"job2\", DateTimeOffset.UtcNow.AddSeconds(2));\n        var job3 = CreateJob(\"job3\", DateTimeOffset.UtcNow.AddSeconds(3));\n\n        queue.Enqueue(job1, 0);\n        queue.Enqueue(job2, 0);\n        queue.Enqueue(job3, 0);\n\n        Assert.Equal(3, queue.Count);\n    }\n\n    [Fact]\n    public void Enqueue_AfterMarkAsComplete_ThrowsInvalidOperationException()\n    {\n        var queue = new InMemoryJobQueue();\n        queue.MarkAsComplete();\n\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddSeconds(1));\n\n        Assert.Throws<InvalidOperationException>(() => queue.Enqueue(job, 0));\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_ReturnsJobsInDueTimeOrder()\n    {\n        var queue = new InMemoryJobQueue();\n        var now = DateTimeOffset.UtcNow;\n        var job1 = CreateJob(\"job1\", now.AddMilliseconds(-100));\n        var job2 = CreateJob(\"job2\", now.AddMilliseconds(-50));\n\n        queue.Enqueue(job1, 0);\n        queue.Enqueue(job2, 0);\n        queue.MarkAsComplete();\n\n        var results = new List<IJobRunContext>();\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            results.Add(context);\n            if (results.Count >= 2) break;\n        }\n\n        Assert.Equal(2, results.Count);\n        Assert.Equal(\"job1\", results[0].Job.Name);\n        Assert.Equal(\"job2\", results[1].Job.Name);\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_IncrementsDequeueCount()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddMilliseconds(-100));\n\n        queue.Enqueue(job, 0);\n        queue.MarkAsComplete();\n\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            Assert.Equal(1, context.DequeueCount);\n            break;\n        }\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_WithInitialDequeueCount_IncrementsCorrectly()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddMilliseconds(-100));\n\n        queue.Enqueue(job, 3);\n        queue.MarkAsComplete();\n\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            Assert.Equal(4, context.DequeueCount);\n            break;\n        }\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_WaitsForDueTime()\n    {\n        var queue = new InMemoryJobQueue();\n        var futureTime = DateTimeOffset.UtcNow.AddSeconds(2);\n        var job = CreateJob(\"job1\", futureTime);\n\n        queue.Enqueue(job, 0);\n        queue.MarkAsComplete();\n\n        var startTime = DateTimeOffset.UtcNow;\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            var elapsed = DateTimeOffset.UtcNow - startTime;\n            Assert.True(elapsed.TotalSeconds >= 1.5, $\"Job was dequeued too early. Elapsed: {elapsed.TotalSeconds}s\");\n            break;\n        }\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_CompletesWhenQueueIsMarkedComplete()\n    {\n        var queue = new InMemoryJobQueue();\n        queue.MarkAsComplete();\n\n        var count = 0;\n        await foreach (var _ in queue.WithCancellation(CancellationToken.None))\n        {\n            count++;\n        }\n\n        Assert.Equal(0, count);\n    }\n\n    [Fact]\n    public void CancelJob_RemovesJobFromQueue()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddSeconds(5));\n\n        queue.Enqueue(job, 0);\n        var removed = queue.CancelJob(\"job1\");\n\n        Assert.True(removed);\n        Assert.Equal(0, queue.Count);\n    }\n\n    [Fact]\n    public async Task CancelJob_PreventsJobFromBeingDequeued()\n    {\n        var queue = new InMemoryJobQueue();\n        var job1 = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddMilliseconds(-100));\n        var job2 = CreateJob(\"job2\", DateTimeOffset.UtcNow.AddMilliseconds(-50));\n\n        queue.Enqueue(job1, 0);\n        queue.Enqueue(job2, 0);\n        queue.CancelJob(\"job1\");\n        queue.MarkAsComplete();\n\n        var results = new List<string>();\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            results.Add(context.Job.Id);\n            if (results.Count >= 1) break;\n        }\n\n        Assert.Single(results);\n        Assert.Equal(\"job2\", results[0]);\n    }\n\n    [Fact]\n    public void CancelJob_NonExistentJob_DoesNotThrow()\n    {\n        var queue = new InMemoryJobQueue();\n\n        var removed = queue.CancelJob(\"non-existent-job\");\n\n        Assert.False(removed);\n        Assert.Equal(0, queue.Count);\n    }\n\n    [Fact]\n    public void RetryJobLater_MovesJobToNewDueTime()\n    {\n        var queue = new InMemoryJobQueue();\n        var originalDueTime = DateTimeOffset.UtcNow.AddSeconds(1);\n        var job = CreateJob(\"job1\", originalDueTime);\n\n        queue.Enqueue(job, 0);\n\n        var context = CreateJobContext(job, \"run1\", 1);\n        var newDueTime = DateTimeOffset.UtcNow.AddSeconds(10);\n\n        queue.RetryJobLater(context, newDueTime);\n\n        Assert.Equal(1, queue.Count);\n    }\n\n    [Fact]\n    public async Task RetryJobLater_PreservesDequeueCount()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddMilliseconds(-100));\n\n        queue.Enqueue(job, 5);\n\n        var context = CreateJobContext(job, \"run1\", 5);\n        var newDueTime = DateTimeOffset.UtcNow.AddMilliseconds(-50);\n\n        queue.RetryJobLater(context, newDueTime);\n        queue.MarkAsComplete();\n\n        await foreach (var newContext in queue.WithCancellation(CancellationToken.None))\n        {\n            Assert.Equal(6, newContext.DequeueCount);\n            Assert.Equal(\"job1\", newContext.Job.Id);\n            break;\n        }\n    }\n\n    [Fact]\n    public void RetryJobLater_NonExistentJob_DoesNotThrow()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddSeconds(1));\n        var context = CreateJobContext(job, \"run1\", 1);\n\n        queue.RetryJobLater(context, DateTimeOffset.UtcNow.AddSeconds(10));\n\n        Assert.Equal(0, queue.Count);\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_RespectsEmptyBuckets()\n    {\n        var queue = new InMemoryJobQueue();\n        var dueTime = DateTimeOffset.UtcNow.AddMilliseconds(-100);\n        var job1 = CreateJob(\"job1\", dueTime);\n        var job2 = CreateJob(\"job2\", dueTime);\n\n        queue.Enqueue(job1, 0);\n        queue.Enqueue(job2, 0);\n        queue.CancelJob(\"job1\");\n        queue.CancelJob(\"job2\");\n        queue.MarkAsComplete();\n\n        var results = new List<IJobRunContext>();\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            results.Add(context);\n            if (results.Count >= 2) break;\n        }\n\n        Assert.Empty(results);\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_HandlesMultipleDueTimes()\n    {\n        var queue = new InMemoryJobQueue();\n        var now = DateTimeOffset.UtcNow;\n        var job1 = CreateJob(\"job1\", now.AddSeconds(-5));\n        var job2 = CreateJob(\"job2\", now.AddSeconds(-3));\n        var job3 = CreateJob(\"job3\", now.AddSeconds(-1));\n\n        queue.Enqueue(job1, 0);\n        queue.Enqueue(job2, 0);\n        queue.Enqueue(job3, 0);\n        queue.MarkAsComplete();\n\n        var results = new List<string>();\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            results.Add(context.Job.Name);\n            if (results.Count >= 3) break;\n        }\n\n        Assert.Equal(3, results.Count);\n        Assert.Equal(\"job1\", results[0]);\n        Assert.Equal(\"job2\", results[1]);\n        Assert.Equal(\"job3\", results[2]);\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_GeneratesUniqueRunIds()\n    {\n        var queue = new InMemoryJobQueue();\n        var job = CreateJob(\"job1\", DateTimeOffset.UtcNow.AddMilliseconds(-100));\n\n        queue.Enqueue(job, 0);\n        queue.MarkAsComplete();\n\n        var runIds = new List<string>();\n        await foreach (var context in queue.WithCancellation(CancellationToken.None))\n        {\n            runIds.Add(context.RunId);\n            Assert.False(string.IsNullOrEmpty(context.RunId));\n            break;\n        }\n\n        Assert.Single(runIds);\n    }\n\n    [Fact]\n    public async Task GetAsyncEnumerator_CancellationToken_StopsEnumeration()\n    {\n        var queue = new InMemoryJobQueue();\n        var cts = new CancellationTokenSource();\n\n        cts.Cancel();\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>\n        {\n            await foreach (var _ in queue.WithCancellation(cts.Token))\n            {\n            }\n        });\n    }\n\n    private static DurableJob CreateJob(string id, DateTimeOffset dueTime)\n    {\n        return new DurableJob\n        {\n            Id = id,\n            Name = id,\n            DueTime = dueTime,\n            TargetGrainId = GrainId.Create(\"test\", id),\n            ShardId = \"shard1\",\n            Metadata = null\n        };\n    }\n\n    private static IJobRunContext CreateJobContext(DurableJob job, string runId, int dequeueCount)\n    {\n        var context = Substitute.For<IJobRunContext>();\n        context.Job.Returns(job);\n        context.RunId.Returns(runId);\n        context.DequeueCount.Returns(dequeueCount);\n        return context;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/DurableJobs/InMemoryJobShardManagerTests.cs",
    "content": "#nullable enable\n\nusing System.Collections.Immutable;\nusing System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.DurableJobs;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing NSubstitute;\nusing Xunit;\n\nnamespace NonSilo.Tests.DurableJobs;\n\n[TestCategory(\"DurableJobs\")]\npublic class InMemoryJobShardManagerTests : IAsyncLifetime\n{\n    private static readonly SiloAddress Silo1 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 1);\n    private static readonly SiloAddress Silo2 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5002), 2);\n    private static readonly SiloAddress Silo3 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5003), 3);\n    private static readonly SiloAddress Silo4 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5004), 4);\n\n    public Task InitializeAsync() => InMemoryJobShardManager.ClearAllShardsAsync();\n\n    public Task DisposeAsync() => InMemoryJobShardManager.ClearAllShardsAsync();\n\n    [Fact]\n    public async Task CreateShardAsync_CreatesShardOwnedBySilo()\n    {\n        var manager = new InMemoryJobShardManager(Silo1);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var shard = await manager.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        Assert.NotNull(shard);\n        Assert.Equal(minDueTime, shard.StartTime);\n        Assert.Equal(maxDueTime, shard.EndTime);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_ReturnsOwnedShards()\n    {\n        var manager = new InMemoryJobShardManager(Silo1);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var createdShard = await manager.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n        var assignedShards = await manager.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        Assert.Single(assignedShards);\n        Assert.Equal(createdShard.Id, assignedShards[0].Id);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_OrphanedShard_IsAssignedWithoutIncrementingAdoptedCount()\n    {\n        // Silo1 creates a shard and gracefully releases it\n        var manager1 = new InMemoryJobShardManager(Silo1);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var shard = await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n        \n        // Schedule a job so the shard isn't deleted on unregister\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"test\", \"grain1\"), JobName = \"TestJob\", DueTime = minDueTime.AddMinutes(30), Metadata = null }, CancellationToken.None);\n        \n        // Gracefully unregister (sets owner to null)\n        await manager1.UnregisterShardAsync(shard, CancellationToken.None);\n\n        // Silo2 picks up the orphaned shard\n        var manager2 = new InMemoryJobShardManager(Silo2);\n        var assignedShards = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        Assert.Single(assignedShards);\n        Assert.Equal(shard.Id, assignedShards[0].Id);\n\n        var ownershipInfo = await InMemoryJobShardManager.GetOwnershipInfoAsync(shard.Id);\n        Assert.True(ownershipInfo.HasValue);\n        Assert.Equal(Silo2.ToString(), ownershipInfo.Value.Owner);\n        Assert.Equal(0, ownershipInfo.Value.AdoptedCount);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_AdoptedFromDeadSilo_IncrementsAdoptedCount()\n    {\n        // Setup membership service that reports Silo1 as dead\n        var membershipService = CreateMembershipService(deadSilos: [Silo1]);\n\n        // Silo1 creates a shard (simulating it was created before death)\n        var manager1 = new InMemoryJobShardManager(Silo1, membershipService);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var shard = await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        // Silo2 adopts the shard from dead Silo1\n        var manager2 = new InMemoryJobShardManager(Silo2, membershipService, maxAdoptedCount: 3);\n        var assignedShards = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        // Shard should be assigned (adopted count = 1, under threshold)\n        Assert.Single(assignedShards);\n        Assert.Equal(shard.Id, assignedShards[0].Id);\n\n        var ownershipInfo = await InMemoryJobShardManager.GetOwnershipInfoAsync(shard.Id);\n        Assert.True(ownershipInfo.HasValue);\n        Assert.Equal(Silo2.ToString(), ownershipInfo.Value.Owner);\n        Assert.Equal(1, ownershipInfo.Value.AdoptedCount);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_PoisonedShard_IsNotAssigned()\n    {\n        // Setup membership service\n        var membershipService = Substitute.For<IClusterMembershipService>();\n        var snapshot = CreateMembershipSnapshot(deadSilos: [Silo1, Silo2, Silo3]);\n        membershipService.CurrentSnapshot.Returns(snapshot);\n\n        // Silo1 creates a shard\n        var manager1 = new InMemoryJobShardManager(Silo1, membershipService, maxAdoptedCount: 2);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        // Silo2 adopts from dead Silo1 (adopted count = 1)\n        var manager2 = new InMemoryJobShardManager(Silo2, membershipService, maxAdoptedCount: 2);\n        var shards2 = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n        Assert.Single(shards2);\n\n        // Silo3 adopts from dead Silo2 (adopted count = 2)\n        var manager3 = new InMemoryJobShardManager(Silo3, membershipService, maxAdoptedCount: 2);\n        var shards3 = await manager3.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n        Assert.Single(shards3);\n\n        // Silo4 tries to adopt from dead Silo3 (adopted count would be 3, exceeds max of 2)\n        var manager4 = new InMemoryJobShardManager(Silo4, membershipService, maxAdoptedCount: 2);\n        var shards4 = await manager4.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        // Shard is poisoned and should not be assigned\n        Assert.Empty(shards4);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_MaxAdoptedCountOfZero_NeverAssignsAdoptedShards()\n    {\n        // Setup membership service that reports Silo1 as dead\n        var membershipService = CreateMembershipService(deadSilos: [Silo1]);\n\n        // Silo1 creates a shard\n        var manager1 = new InMemoryJobShardManager(Silo1, membershipService, maxAdoptedCount: 0);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        // Silo2 tries to adopt from dead Silo1 with maxAdoptedCount=0\n        var manager2 = new InMemoryJobShardManager(Silo2, membershipService, maxAdoptedCount: 0);\n        var assignedShards = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        // Shard should not be assigned (adopted count would be 1, exceeds max of 0)\n        Assert.Empty(assignedShards);\n    }\n\n    [Fact]\n    public async Task UseInMemoryDurableJobs_ConfiguredMaxAdoptedCount_IsApplied()\n    {\n        var membershipService = CreateMembershipService(deadSilos: [Silo2]);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var ownerManager = new InMemoryJobShardManager(Silo2, membershipService, maxAdoptedCount: 3);\n        await ownerManager.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        var localSiloDetails = Substitute.For<ILocalSiloDetails>();\n        localSiloDetails.SiloAddress.Returns(Silo1);\n\n        var services = new ServiceCollection();\n        services.AddSingleton(localSiloDetails);\n        services.AddSingleton(membershipService);\n        services.Configure<DurableJobsOptions>(options => options.MaxAdoptedCount = 0);\n        services.UseInMemoryDurableJobs();\n\n        using var serviceProvider = services.BuildServiceProvider();\n        var manager = serviceProvider.GetRequiredService<InMemoryJobShardManager>();\n\n        var assignedShards = await manager.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n        Assert.Empty(assignedShards);\n    }\n\n    [Fact]\n    public async Task AssignJobShardsAsync_ShardFromActiveSilo_IsNotAssigned()\n    {\n        // Setup membership service that reports Silo1 as active\n        var membershipService = CreateMembershipService(activeSilos: [Silo1]);\n\n        // Silo1 creates a shard\n        var manager1 = new InMemoryJobShardManager(Silo1, membershipService);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n\n        // Silo2 tries to get shards - should not get Silo1's shard since Silo1 is active\n        var manager2 = new InMemoryJobShardManager(Silo2, membershipService);\n        var assignedShards = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n\n        Assert.Empty(assignedShards);\n    }\n\n    [Fact]\n    public async Task UnregisterShardAsync_WithNoJobsRemaining_RemovesShard()\n    {\n        var manager = new InMemoryJobShardManager(Silo1);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var shard = await manager.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n        \n        // Unregister with no jobs\n        await manager.UnregisterShardAsync(shard, CancellationToken.None);\n\n        // Shard should be removed, not reassignable\n        var assignedShards = await manager.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n        Assert.Empty(assignedShards);\n    }\n\n    [Fact]\n    public async Task UnregisterShardAsync_WithJobsRemaining_MarksShardAsOrphaned()\n    {\n        var manager1 = new InMemoryJobShardManager(Silo1);\n        var minDueTime = DateTimeOffset.UtcNow;\n        var maxDueTime = minDueTime.AddHours(1);\n\n        var shard = await manager1.CreateShardAsync(minDueTime, maxDueTime, new Dictionary<string, string>(), CancellationToken.None);\n        \n        // Add a job\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"test\", \"grain1\"), JobName = \"TestJob\", DueTime = minDueTime.AddMinutes(30), Metadata = null }, CancellationToken.None);\n        \n        // Unregister with jobs remaining\n        await manager1.UnregisterShardAsync(shard, CancellationToken.None);\n\n        // Shard should be orphaned and available for another silo\n        var manager2 = new InMemoryJobShardManager(Silo2);\n        var assignedShards = await manager2.AssignJobShardsAsync(maxDueTime, CancellationToken.None);\n        Assert.Single(assignedShards);\n    }\n\n    private static IClusterMembershipService CreateMembershipService(\n        SiloAddress[]? activeSilos = null,\n        SiloAddress[]? deadSilos = null)\n    {\n        var membershipService = Substitute.For<IClusterMembershipService>();\n        var snapshot = CreateMembershipSnapshot(activeSilos, deadSilos);\n        membershipService.CurrentSnapshot.Returns(snapshot);\n        return membershipService;\n    }\n\n    private static ClusterMembershipSnapshot CreateMembershipSnapshot(\n        SiloAddress[]? activeSilos = null,\n        SiloAddress[]? deadSilos = null)\n    {\n        var builder = ImmutableDictionary.CreateBuilder<SiloAddress, ClusterMember>();\n\n        if (activeSilos is not null)\n        {\n            foreach (var silo in activeSilos)\n            {\n                builder[silo] = new ClusterMember(silo, SiloStatus.Active, silo.ToString());\n            }\n        }\n\n        if (deadSilos is not null)\n        {\n            foreach (var silo in deadSilos)\n            {\n                builder[silo] = new ClusterMember(silo, SiloStatus.Dead, silo.ToString());\n            }\n        }\n\n        return new ClusterMembershipSnapshot(builder.ToImmutable(), new MembershipVersion(1));\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/DurableJobs/ShardExecutorTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing Orleans.DurableJobs;\nusing Orleans.Runtime.Messaging;\nusing System.Runtime.CompilerServices;\nusing Xunit;\n\nnamespace NonSilo.Tests.ScheduledJobs;\n\n[TestCategory(\"DurableJobs\")]\npublic class ShardExecutorTests\n{\n    [Fact]\n    public async Task RunShardAsync_WhenNotOverloaded_ProcessesJobsWithoutDelay()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(3);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        ConfigureGrainFactoryToTrackCompletions(grainFactory, completedJobs);\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify all jobs were processed and removed from the shard\n        Assert.Equal(3, completedJobs.Count);\n        Assert.Contains(\"job-0\", completedJobs);\n        Assert.Contains(\"job-1\", completedJobs);\n        Assert.Contains(\"job-2\", completedJobs);\n\n        await shard.Received(3).RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenOverloaded_PausesAndRetriesWithBackoffDelay()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10, overloadBackoffDelay: TimeSpan.FromMilliseconds(50));\n        var overloadDetector = Substitute.For<IOverloadDetector>();\n        var jobs = CreateJobs(2);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        ConfigureGrainFactoryToTrackCompletions(grainFactory, completedJobs);\n\n        // Simulate system being overloaded initially, then clearing after 3 checks\n        var checkCount = 0;\n        overloadDetector.IsOverloaded.Returns(_ =>\n        {\n            checkCount++;\n            return checkCount <= 3;\n        });\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Jobs should complete successfully after overload clears, and detector should be checked multiple times\n        Assert.Equal(2, completedJobs.Count);\n        Assert.True(checkCount > 3, $\"Expected multiple overload checks, got {checkCount}\");\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenOverloadTransitionsDuringProcessing_HandlesStateChanges()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10, overloadBackoffDelay: TimeSpan.FromMilliseconds(10));\n        var overloadDetector = Substitute.For<IOverloadDetector>();\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        ConfigureGrainFactoryToTrackCompletions(grainFactory, completedJobs);\n\n        // Jobs arrive gradually to allow overload state to toggle during processing\n        var shard = CreateJobShardWithDelayedYield(5, TimeSpan.FromMilliseconds(10));\n\n        // Alternate overload state with each check: overloaded, not overloaded, overloaded...\n        var checkCount = 0;\n        overloadDetector.IsOverloaded.Returns(_ =>\n        {\n            checkCount++;\n            return checkCount % 2 == 1;\n        });\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // All jobs should complete despite the toggling overload state\n        Assert.Equal(5, completedJobs.Count);\n        for (int i = 0; i < 5; i++)\n        {\n            Assert.Contains($\"job-{i}\", completedJobs);\n        }\n    }\n\n    [Fact]\n    public async Task RunShardAsync_RespectsMaxConcurrentJobsPerSilo_WhileCheckingOverload()\n    {\n        var maxConcurrent = 3;\n        var options = CreateOptions(maxConcurrentJobs: maxConcurrent);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var currentConcurrent = 0;\n        var maxObservedConcurrent = 0;\n        var concurrentLock = new object();\n\n        var jobs = CreateJobs(10);\n        var shard = CreateJobShard(jobs);\n        \n        // Track the maximum concurrent job execution count\n        ConfigureGrainFactoryWithSlowJobExecution(grainFactory, async () =>\n        {\n            lock (concurrentLock)\n            {\n                currentConcurrent++;\n                if (currentConcurrent > maxObservedConcurrent)\n                {\n                    maxObservedConcurrent = currentConcurrent;\n                }\n            }\n\n            await Task.Delay(50);\n\n            lock (concurrentLock)\n            {\n                currentConcurrent--;\n            }\n        });\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify concurrency limit was respected while jobs executed in parallel\n        Assert.True(maxObservedConcurrent <= maxConcurrent, \n            $\"Max concurrent jobs was {maxObservedConcurrent}, but limit was {maxConcurrent}\");\n        Assert.True(maxObservedConcurrent > 1, \n            \"Expected some concurrent execution\");\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenCancelledDuringOverloadBackoff_CancelsCleanly()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10, overloadBackoffDelay: TimeSpan.FromSeconds(10));\n        var overloadDetector = CreateOverloadDetector(isOverloaded: true);\n        var jobs = CreateJobs(5);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        ConfigureGrainFactoryToTrackCompletions(grainFactory, completedJobs);\n\n        // Cancel shortly after starting, while executor is waiting for overload to clear\n        var cts = new CancellationTokenSource();\n        cts.CancelAfter(TimeSpan.FromMilliseconds(100));\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>\n        {\n            await executor.RunShardAsync(shard, cts.Token);\n        });\n\n        // No jobs should have executed since cancellation occurred during backoff wait\n        Assert.Empty(completedJobs);\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenJobFailsDuringOverload_ContinuesOverloadChecking()\n    {\n        var options = CreateOptions(\n            maxConcurrentJobs: 10,\n            overloadBackoffDelay: TimeSpan.FromMilliseconds(10),\n            shouldRetry: (context, ex) => DateTimeOffset.UtcNow.AddSeconds(1)\n        );\n        var overloadDetector = Substitute.For<IOverloadDetector>();\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var jobs = CreateJobs(3);\n        var shard = CreateJobShard(jobs);\n\n        var completedJobs = new List<string>();\n        var failedJobs = new List<string>();\n        var jobExecutionCount = 0;\n\n        // Periodically report overload to test interaction with job failures\n        var checkCount = 0;\n        overloadDetector.IsOverloaded.Returns(_ =>\n        {\n            checkCount++;\n            return checkCount % 3 == 1;\n        });\n\n        // First job fails, remaining jobs succeed\n        ConfigureGrainFactoryWithSelectiveFailures(grainFactory, completedJobs, failedJobs, ref jobExecutionCount);\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Failed job should be scheduled for retry, successful jobs should be removed\n        Assert.Equal(2, completedJobs.Count);\n        Assert.Single(failedJobs);\n        \n        await shard.Received(1).RetryJobLaterAsync(\n            Arg.Any<IJobRunContext>(),\n            Arg.Any<DateTimeOffset>(),\n            Arg.Any<CancellationToken>());\n        \n        await shard.Received(2).RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WaitsForShardStartTime_BeforeProcessing()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(1);\n        var futureStartTime = DateTimeOffset.UtcNow.AddMilliseconds(200);\n        var shard = CreateJobShard(jobs, startTime: futureStartTime);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        ConfigureGrainFactoryToTrackCompletions(grainFactory, completedJobs);\n\n        var startTime = DateTimeOffset.UtcNow;\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify executor waited for shard start time before processing\n        var elapsed = DateTimeOffset.UtcNow - startTime;\n        Assert.True(elapsed.TotalMilliseconds >= 150, \n            $\"Expected to wait for shard start time, but elapsed only {elapsed.TotalMilliseconds}ms\");\n        Assert.Single(completedJobs);\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WaitsForAllJobsToComplete_BeforeReturning()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 5);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(5);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var completedJobs = new List<string>();\n        var runningJobs = 0;\n        var lockObj = new object();\n\n        // Simulate slow job execution to ensure some run concurrently\n        ConfigureGrainFactoryWithSlowJobExecution(grainFactory, async () =>\n        {\n            lock (lockObj) { runningJobs++; }\n            await Task.Delay(100);\n            lock (lockObj) \n            { \n                runningJobs--;\n                completedJobs.Add($\"job-{completedJobs.Count}\");\n            }\n        });\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify all jobs completed before RunShardAsync returned\n        Assert.Equal(0, runningJobs);\n        Assert.Equal(5, completedJobs.Count);\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenJobReturnsPollAfter_EntersPollingLoopUntilCompletion()\n    {\n        var options = CreateOptions(maxConcurrentJobs: 10);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(1);\n        var shard = CreateJobShard(jobs);\n        \n        var (grainFactory, callBox) = CreateGrainFactoryWithPollingBehavior();\n        \n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify HandleDurableJobAsync was called 4 times (1 initial + 3 polls)\n        Assert.Equal(4, callBox.Value);\n        \n        // Verify job was removed after completion\n        await shard.Received(1).RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenJobReturnsPollAfterThenFails_HandlesFailureCorrectly()\n    {\n        var options = CreateOptions(\n            maxConcurrentJobs: 10,\n            shouldRetry: (context, ex) => DateTimeOffset.UtcNow.AddSeconds(1)\n        );\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(1);\n        var shard = CreateJobShard(jobs);\n        \n        var (grainFactory, callBox) = CreateGrainFactoryWithPollingThenFailure();\n        \n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Verify HandleDurableJobAsync was called 4 times (1 initial + 2 PollAfter + 1 Failed)\n        Assert.Equal(4, callBox.Value);\n        \n        // Verify job was scheduled for retry (not removed)\n        await shard.Received(1).RetryJobLaterAsync(\n            Arg.Any<IJobRunContext>(),\n            Arg.Any<DateTimeOffset>(),\n            Arg.Any<CancellationToken>());\n        \n        await shard.DidNotReceive().RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenRetryPersistenceFails_ReleasesConcurrencyAndContinuesProcessing()\n    {\n        var options = CreateOptions(\n            maxConcurrentJobs: 1,\n            shouldRetry: (context, ex) => DateTimeOffset.UtcNow.AddSeconds(1)\n        );\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(2);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactory();\n        var completedJobs = new List<string>();\n        var failedJobs = new List<string>();\n        var jobExecutionCount = 0;\n        ConfigureGrainFactoryWithSelectiveFailures(grainFactory, completedJobs, failedJobs, ref jobExecutionCount);\n\n        shard.RetryJobLaterAsync(\n            Arg.Any<IJobRunContext>(),\n            Arg.Any<DateTimeOffset>(),\n            Arg.Any<CancellationToken>())\n            .Returns(Task.FromException(new InvalidOperationException(\"Simulated retry persistence failure\")));\n\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));\n        await executor.RunShardAsync(shard, cts.Token);\n\n        Assert.Single(failedJobs);\n        Assert.Single(completedJobs);\n        await shard.Received(1).RetryJobLaterAsync(Arg.Any<IJobRunContext>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>());\n        await shard.Received(1).RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WhenExecutionIsCanceled_DoesNotRetryOrRemove()\n    {\n        var options = CreateOptions(\n            maxConcurrentJobs: 10,\n            shouldRetry: (context, ex) => DateTimeOffset.UtcNow.AddSeconds(1)\n        );\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var jobs = CreateJobs(1);\n        var shard = CreateJobShard(jobs);\n        var grainFactory = CreateGrainFactoryWithCanceledExecution();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => executor.RunShardAsync(shard, cts.Token));\n\n        await shard.DidNotReceive().RetryJobLaterAsync(Arg.Any<IJobRunContext>(), Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>());\n        await shard.DidNotReceive().RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>());\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WithSlowStart_GraduallyIncreasesConcurrency()\n    {\n        var initialConcurrency = 2;\n        var maxConcurrency = 16;\n        var options = CreateOptions(\n            maxConcurrentJobs: maxConcurrency,\n            concurrencySlowStartEnabled: true,\n            slowStartInitialConcurrency: initialConcurrency,\n            slowStartInterval: TimeSpan.FromMilliseconds(100));\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var currentConcurrent = 0;\n        var maxObservedConcurrent = 0;\n        var concurrentLock = new object();\n        var releaseJobs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        var concurrencyIncreased = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        // Enough jobs to exercise the slow start ramp-up\n        var jobs = CreateJobs(20);\n        var shard = CreateJobShard(jobs);\n\n        ConfigureGrainFactoryWithSlowJobExecution(grainFactory, async () =>\n        {\n            lock (concurrentLock)\n            {\n                currentConcurrent++;\n                if (currentConcurrent > maxObservedConcurrent)\n                {\n                    maxObservedConcurrent = currentConcurrent;\n                    if (maxObservedConcurrent > initialConcurrency)\n                    {\n                        concurrencyIncreased.TrySetResult();\n                    }\n                }\n            }\n\n            await releaseJobs.Task;\n\n            lock (concurrentLock)\n            {\n                currentConcurrent--;\n            }\n        });\n\n        var runTask = executor.RunShardAsync(shard, CancellationToken.None);\n        try\n        {\n            var completedTask = await Task.WhenAny(concurrencyIncreased.Task, Task.Delay(TimeSpan.FromSeconds(10)));\n            Assert.Same(concurrencyIncreased.Task, completedTask);\n        }\n        finally\n        {\n            releaseJobs.TrySetResult();\n            await runTask;\n        }\n\n        // Slow start should limit initial concurrency, then ramp up\n        Assert.True(maxObservedConcurrent <= maxConcurrency,\n            $\"Max concurrent jobs was {maxObservedConcurrent}, but limit was {maxConcurrency}\");\n        Assert.True(maxObservedConcurrent > initialConcurrency,\n            $\"Expected concurrency to increase beyond initial {initialConcurrency}, but max observed was {maxObservedConcurrent}\");\n    }\n\n    [Fact]\n    public async Task RunShardAsync_WithSlowStartDisabled_UsesFullConcurrencyImmediately()\n    {\n        var maxConcurrency = 5;\n        var options = CreateOptions(\n            maxConcurrentJobs: maxConcurrency,\n            concurrencySlowStartEnabled: false);\n        var overloadDetector = CreateOverloadDetector(isOverloaded: false);\n        var grainFactory = CreateGrainFactory();\n        var executor = new ShardExecutor(grainFactory, options, overloadDetector, NullLogger<ShardExecutor>.Instance);\n\n        var currentConcurrent = 0;\n        var maxObservedConcurrent = 0;\n        var concurrentLock = new object();\n\n        var jobs = CreateJobs(10);\n        var shard = CreateJobShard(jobs);\n\n        ConfigureGrainFactoryWithSlowJobExecution(grainFactory, async () =>\n        {\n            lock (concurrentLock)\n            {\n                currentConcurrent++;\n                if (currentConcurrent > maxObservedConcurrent)\n                {\n                    maxObservedConcurrent = currentConcurrent;\n                }\n            }\n\n            await Task.Delay(100);\n\n            lock (concurrentLock)\n            {\n                currentConcurrent--;\n            }\n        });\n\n        await executor.RunShardAsync(shard, CancellationToken.None);\n\n        // Without slow start, all concurrency slots should be available immediately\n        Assert.True(maxObservedConcurrent <= maxConcurrency,\n            $\"Max concurrent jobs was {maxObservedConcurrent}, but limit was {maxConcurrency}\");\n        Assert.Equal(maxConcurrency, maxObservedConcurrent);\n    }\n\n    [Fact]\n    public void ValidateConfiguration_WithSlowStartDisabled_AllowsNonPositiveInitialConcurrency()\n    {\n        var options = Options.Create(new DurableJobsOptions\n        {\n            ConcurrencySlowStartEnabled = false,\n            SlowStartInitialConcurrency = 0\n        });\n        var validator = new Orleans.Hosting.DurableJobsOptionsValidator(\n            NullLogger<Orleans.Hosting.DurableJobsOptionsValidator>.Instance,\n            options);\n\n        validator.ValidateConfiguration();\n    }\n\n    // Helper methods\n\n    private static IOptions<DurableJobsOptions> CreateOptions(\n        int maxConcurrentJobs = 10,\n        TimeSpan? overloadBackoffDelay = null,\n        Func<IJobRunContext, Exception, DateTimeOffset?> shouldRetry = null,\n        bool concurrencySlowStartEnabled = false,\n        int? slowStartInitialConcurrency = null,\n        TimeSpan? slowStartInterval = null)\n    {\n        var options = new DurableJobsOptions\n        {\n            MaxConcurrentJobsPerSilo = maxConcurrentJobs,\n            OverloadBackoffDelay = overloadBackoffDelay ?? TimeSpan.FromMilliseconds(100),\n            ShouldRetry = shouldRetry ?? ((_, _) => null), // Default: no retry\n            ConcurrencySlowStartEnabled = concurrencySlowStartEnabled,\n            SlowStartInitialConcurrency = slowStartInitialConcurrency ?? Environment.ProcessorCount,\n            SlowStartInterval = slowStartInterval ?? TimeSpan.FromSeconds(10)\n        };\n        return Options.Create(options);\n    }\n\n    private static IOverloadDetector CreateOverloadDetector(bool isOverloaded)\n    {\n        var detector = Substitute.For<IOverloadDetector>();\n        detector.IsOverloaded.Returns(isOverloaded);\n        return detector;\n    }\n\n    private static List<DurableJob> CreateJobs(int count, DateTimeOffset? dueTime = null)\n    {\n        var jobs = new List<DurableJob>();\n        var baseDueTime = dueTime ?? DateTimeOffset.UtcNow.AddMilliseconds(-100);\n        \n        for (int i = 0; i < count; i++)\n        {\n            jobs.Add(new DurableJob\n            {\n                Id = $\"job-{i}\",\n                Name = $\"job-{i}\",\n                DueTime = baseDueTime.AddMilliseconds(i * 10),\n                TargetGrainId = GrainId.Create(\"test\", $\"grain-{i}\"),\n                ShardId = \"shard-1\",\n                Metadata = null\n            });\n        }\n        \n        return jobs;\n    }\n\n    private static IJobShard CreateJobShard(\n        List<DurableJob> jobs, \n        DateTimeOffset? startTime = null,\n        DateTimeOffset? endTime = null)\n    {\n        var shard = Substitute.For<IJobShard>();\n        shard.Id.Returns(\"shard-1\");\n        shard.StartTime.Returns(startTime ?? DateTimeOffset.UtcNow.AddMinutes(-10));\n        shard.EndTime.Returns(endTime ?? DateTimeOffset.UtcNow.AddMinutes(10));\n\n        shard.ConsumeDurableJobsAsync().Returns(callInfo => CreateJobContexts(jobs));\n\n        shard.RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>())\n            .Returns(Task.FromResult(true));\n\n        return shard;\n    }\n\n    private static IJobShard CreateJobShardWithDelayedYield(int jobCount, TimeSpan yieldDelay)\n    {\n        var jobs = CreateJobs(jobCount);\n        var shard = Substitute.For<IJobShard>();\n        shard.Id.Returns(\"shard-1\");\n        shard.StartTime.Returns(DateTimeOffset.UtcNow.AddMinutes(-10));\n        shard.EndTime.Returns(DateTimeOffset.UtcNow.AddMinutes(10));\n\n        shard.ConsumeDurableJobsAsync().Returns(callInfo => CreateJobContextsWithDelay(jobs, yieldDelay));\n\n        shard.RemoveJobAsync(Arg.Any<string>(), Arg.Any<CancellationToken>())\n            .Returns(Task.FromResult(true));\n\n        return shard;\n    }\n\n    private static async IAsyncEnumerable<IJobRunContext> CreateJobContexts(List<DurableJob> jobs)\n    {\n        foreach (var job in jobs)\n        {\n            var context = Substitute.For<IJobRunContext>();\n            context.Job.Returns(job);\n            context.RunId.Returns(Guid.NewGuid().ToString());\n            context.DequeueCount.Returns(1);\n            yield return context;\n        }\n        \n        await Task.CompletedTask;\n    }\n\n    private static async IAsyncEnumerable<IJobRunContext> CreateJobContextsWithDelay(\n        List<DurableJob> jobs, \n        TimeSpan delay)\n    {\n        foreach (var job in jobs)\n        {\n            await Task.Delay(delay);\n            \n            var context = Substitute.For<IJobRunContext>();\n            context.Job.Returns(job);\n            context.RunId.Returns(Guid.NewGuid().ToString());\n            context.DequeueCount.Returns(1);\n            yield return context;\n        }\n    }\n\n    private static IInternalGrainFactory CreateGrainFactory()\n    {\n        var factory = Substitute.For<IInternalGrainFactory>();\n        \n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(DurableJobRunResult.Completed);\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n        \n        return factory;\n    }\n\n    private static void ConfigureGrainFactoryToTrackCompletions(\n        IInternalGrainFactory factory, \n        List<string> completedJobs)\n    {\n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(callInfo =>\n            {\n                var context = callInfo.ArgAt<IJobRunContext>(0);\n                lock (completedJobs)\n                {\n                    completedJobs.Add(context.Job.Id);\n                }\n                return Task.FromResult(DurableJobRunResult.Completed);\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n    }\n\n    private static void ConfigureGrainFactoryWithSlowJobExecution(\n        IInternalGrainFactory factory,\n        Func<Task> executionAction)\n    {\n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(async callInfo =>\n            {\n                await executionAction();\n                return DurableJobRunResult.Completed;\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n    }\n\n    private static void ConfigureGrainFactoryWithSelectiveFailures(\n        IInternalGrainFactory factory,\n        List<string> completedJobs,\n        List<string> failedJobs,\n        ref int jobExecutionCount)\n    {\n        var executionCount = jobExecutionCount;\n        \n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(callInfo =>\n            {\n                var context = callInfo.ArgAt<IJobRunContext>(0);\n                var currentExecution = Interlocked.Increment(ref executionCount);\n                \n                // First job fails\n                if (currentExecution == 1)\n                {\n                    lock (failedJobs)\n                    {\n                        failedJobs.Add(context.Job.Id);\n                    }\n                    var exception = new InvalidOperationException(\"Simulated job failure\");\n                    return Task.FromResult(DurableJobRunResult.Failed(exception));\n                }\n                \n                // Other jobs succeed\n                lock (completedJobs)\n                {\n                    completedJobs.Add(context.Job.Id);\n                }\n                return Task.FromResult(DurableJobRunResult.Completed);\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n\n        jobExecutionCount = executionCount;\n    }\n\n    private static IInternalGrainFactory CreateGrainFactoryWithCanceledExecution()\n    {\n        var factory = Substitute.For<IInternalGrainFactory>();\n\n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(Task.FromCanceled<DurableJobRunResult>(new CancellationToken(canceled: true)));\n\n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n\n        return factory;\n    }\n\n    private static (IInternalGrainFactory, StrongBox<int>) CreateGrainFactoryWithPollingBehavior()\n    {\n        var factory = Substitute.For<IInternalGrainFactory>();\n        var callBox = new StrongBox<int>(0);\n        \n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        \n        // First 3 calls return PollAfter, 4th returns Completed\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(callInfo =>\n            {\n                var currentCall = Interlocked.Increment(ref callBox.Value);\n                if (currentCall < 4)\n                {\n                    return Task.FromResult(DurableJobRunResult.PollAfter(TimeSpan.FromMilliseconds(10)));\n                }\n                return Task.FromResult(DurableJobRunResult.Completed);\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n        \n        return (factory, callBox);\n    }\n\n    private static (IInternalGrainFactory, StrongBox<int>) CreateGrainFactoryWithPollingThenFailure()\n    {\n        var factory = Substitute.For<IInternalGrainFactory>();\n        var callBox = new StrongBox<int>(0);\n        \n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        \n        // First 3 calls return PollAfter, 4th returns Failed\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(callInfo =>\n            {\n                var currentCall = Interlocked.Increment(ref callBox.Value);\n                if (currentCall < 4)\n                {\n                    return Task.FromResult(DurableJobRunResult.PollAfter(TimeSpan.FromMilliseconds(10)));\n                }\n                var exception = new InvalidOperationException(\"Job failed after polling\");\n                return Task.FromResult(DurableJobRunResult.Failed(exception));\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n        \n        return (factory, callBox);\n    }\n\n    private static (IInternalGrainFactory, StrongBox<int>) CreateGrainFactoryWithTimedPolling(\n        int pollDelayMs,\n        List<DateTimeOffset> pollTimestamps)\n    {\n        var factory = Substitute.For<IInternalGrainFactory>();\n        var callBox = new StrongBox<int>(0);\n        \n        var extension = Substitute.For<IDurableJobReceiverExtension>();\n        \n        // First 3 calls return PollAfter (recording timestamps after the initial call), 4th returns Completed\n        extension.HandleDurableJobAsync(Arg.Any<IJobRunContext>(), Arg.Any<CancellationToken>())\n            .Returns(callInfo =>\n            {\n                var currentCall = Interlocked.Increment(ref callBox.Value);\n                if (currentCall > 1)\n                {\n                    lock (pollTimestamps)\n                    {\n                        pollTimestamps.Add(DateTimeOffset.UtcNow);\n                    }\n                }\n                \n                if (currentCall < 4)\n                {\n                    return Task.FromResult(DurableJobRunResult.PollAfter(TimeSpan.FromMilliseconds(pollDelayMs)));\n                }\n                return Task.FromResult(DurableJobRunResult.Completed);\n            });\n        \n        factory.GetGrain<IDurableJobReceiverExtension>(Arg.Any<GrainId>()).Returns(extension);\n        \n        return (factory, callBox);\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.Core.Tests/General/CounterAggregatorGroupTests.cs",
    "content": "using Orleans.Runtime;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General;\n\n/// <summary>\n/// Tests for the CounterAggregatorGroup, which is part of Orleans' instrumentation and metrics infrastructure.\n/// This component aggregates counter values from multiple sources and is used throughout Orleans for collecting\n/// performance metrics such as message counts, activation counts, and other operational statistics.\n/// </summary>\npublic class CounterAggregatorGroupTests\n{\n    private readonly ITestOutputHelper _output;\n    public CounterAggregatorGroupTests(ITestOutputHelper output)\n    {\n        this._output = output;\n    }\n\n    /// <summary>\n    /// Verifies that the aggregator group caches aggregator instances to avoid creating duplicates\n    /// for the same metric name and tags combination.\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"Aggregators\")]\n    public void ValidateAggregatorCache()\n    {\n        var group = new CounterAggregatorGroup();\n\n        var aggregator1 = group.FindOrCreate(new(\"foo\", \"bar\"));\n        var aggregator2 = group.FindOrCreate(new(\"foo\", \"bar\"));\n\n        Assert.Same(aggregator1, aggregator2);\n        Assert.Single(group.Aggregators);\n    }\n\n    /// <summary>\n    /// Tests the collection mechanism that retrieves aggregated metric values from all counters in the group.\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"Aggregators\")]\n    public void Collect()\n    {\n        var group = new CounterAggregatorGroup();\n\n        var aggregator1 = group.FindOrCreate(new(\"foo\", \"bar1\"));\n        var aggregator2 = group.FindOrCreate(new(\"foo\", \"bar2\"));\n\n        aggregator1.Add(1);\n        aggregator1.Add(2);\n        aggregator2.Add(2);\n        aggregator2.Add(3);\n\n        var measurements = group.Collect().ToList();\n        Assert.Equal(2, measurements.Count);\n        Assert.Equal(3, measurements.Single(m => m.Tags[0].Value is \"bar1\").Value);\n        Assert.Equal(5, measurements.Single(m => m.Tags[0].Value is \"bar2\").Value);\n    }\n\n    /// <summary>\n    /// Stress test to verify thread-safety of the counter aggregator under high concurrent load.\n    /// This ensures metrics collection remains accurate in Orleans' multi-threaded runtime environment.\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"Aggregators\")]\n    public void TestMultithreadedCorrectness()\n    {\n        int numOfIterations = 1000000;\n\n        var group = new CounterAggregatorGroup();\n        var counterCount = Environment.ProcessorCount;\n\n        Parallel.For(0, Environment.ProcessorCount, j =>\n        {\n            for (int i = 0; i < counterCount; i++)\n            {\n                var aggregator = group.FindOrCreate(new(\"test\", i));\n\n                for (int k = 0; k < numOfIterations; k++)\n                {\n                    aggregator.Add(i);\n                }\n            }\n        });\n\n        var measurements = group.Collect().OrderBy(m => m.Tags[0].Value).ToList();\n        foreach (var measurement in measurements)\n        {\n            var i = (int)measurement.Tags[0].Value;\n            _output.WriteLine(\"{0} {1}\", i, measurement.Value);\n            Assert.Equal(i * Environment.ProcessorCount * numOfIterations, measurement.Value);\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/General/HistogramAggregatorTests.cs",
    "content": "using Orleans.Runtime;\nusing Xunit;\n\nnamespace UnitTests.General;\n\n/// <summary>\n/// Tests for histogram aggregator functionality including bucket collection and value distribution.\n/// </summary>\npublic class HistogramAggregatorTests\n{\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"Aggregators\")]\n    public void CollectBuckets()\n    {\n        var bounds = new long[] { 1, 3, 5, 8, 13 };\n        var aggregator = new HistogramAggregator(bounds, new[] { new KeyValuePair<string, object>(\"foo\", \"bar\") }, bound => new(\"le\", bound));\n        aggregator.Record(0);\n        aggregator.Record(2);\n        aggregator.Record(5);\n        aggregator.Record(7);\n        aggregator.Record(10);\n        aggregator.Record(11);\n        aggregator.Record(13);\n        aggregator.Record(15);\n        aggregator.Record(20);\n        aggregator.Record(100);\n        var buckets = aggregator.CollectBuckets().ToArray();\n        for(int i = 0; i < bounds.Length; i++)\n        {\n            Assert.Equal(\"foo\", buckets[i].Tags[0].Key);\n            Assert.Equal(\"bar\", buckets[i].Tags[0].Value);\n            Assert.Equal(\"le\", buckets[0].Tags[^1].Key);\n            Assert.Equal(bounds[i], buckets[i].Tags[^1].Value);\n        }\n        Assert.Equal(long.MaxValue, buckets.Last().Tags[^1].Value);\n        Assert.Equal(1, buckets[0].Value);\n        Assert.Equal(1, buckets[1].Value);\n        Assert.Equal(1, buckets[2].Value);\n        Assert.Equal(1, buckets[3].Value);\n        Assert.Equal(3, buckets[4].Value);\n        Assert.Equal(3, buckets[5].Value);\n    }\n}"
  },
  {
    "path": "test/Orleans.Core.Tests/General/Identifiertests.cs",
    "content": "using System.Net;\nusing System.Text.Json;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.GrainReferences;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for various Orleans identifier types including GrainId, UniqueKey, SiloAddress, and related functionality.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class IdentifierTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture environment;\n        private static Random random => Random.Shared;\n\n        private class A { }\n\n        private class B : A { }\n        \n        public IdentifierTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.environment = fixture;\n        }\n\n        /// <summary>\n        /// Verifies that GrainId.GetUniformHashCode returns a stable value.\n        /// </summary>\n        [Fact]\n        public void GrainIdUniformHashCodeIsStable()\n        {\n            var id = GrainId.Create(\"type\", \"key\");\n            var hashCode = id.GetUniformHashCode();\n            Assert.Equal(831806783u, hashCode);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueKeyKeyExtGrainCategoryDisallowsNullKeyExtension()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            UniqueKey.NewKey(Guid.NewGuid(), category: UniqueKey.Category.KeyExtGrain, keyExt: null));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueKeyKeyExtGrainCategoryDisallowsEmptyKeyExtension()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            UniqueKey.NewKey(Guid.NewGuid(), category: UniqueKey.Category.KeyExtGrain, keyExt: \"\"));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueKeyKeyExtGrainCategoryDisallowsWhiteSpaceKeyExtension()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            UniqueKey.NewKey(Guid.NewGuid(), category: UniqueKey.Category.KeyExtGrain, keyExt: \" \\t\\n\\r\"));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void ParsingUniqueKeyStringificationShouldReproduceAnIdenticalObject()\n        {\n            UniqueKey expected1 = UniqueKey.NewKey(Guid.NewGuid());\n            string str1 = expected1.ToHexString();\n            UniqueKey actual1 = UniqueKey.Parse(str1.AsSpan());\n            Assert.Equal(expected1, actual1); // UniqueKey.ToString() and UniqueKey.Parse() failed to reproduce an identical object (case 1).\n\n            string kx3 = \"case 3\";\n            UniqueKey expected3 = UniqueKey.NewKey(Guid.NewGuid(), category: UniqueKey.Category.KeyExtGrain, keyExt: kx3);\n            string str3 = expected3.ToHexString();\n            UniqueKey actual3 = UniqueKey.Parse(str3.AsSpan());\n            Assert.Equal(expected3, actual3); // UniqueKey.ToString() and UniqueKey.Parse() failed to reproduce an identical object (case 3).\n\n            long pk = random.Next();\n            UniqueKey expected4 = UniqueKey.NewKey(pk);\n            string str4 = expected4.ToHexString();\n            UniqueKey actual4 = UniqueKey.Parse(str4.AsSpan());\n            Assert.Equal(expected4, actual4); // UniqueKey.ToString() and UniqueKey.Parse() failed to reproduce an identical object (case 4).\n\n            pk = random.Next();\n            string kx5 = \"case 5\";\n            UniqueKey expected5 = UniqueKey.NewKey(pk, category: UniqueKey.Category.KeyExtGrain, keyExt: kx5);\n            string str5 = expected5.ToHexString();\n            UniqueKey actual5 = UniqueKey.Parse(str5.AsSpan());\n            Assert.Equal(expected5, actual5); // UniqueKey.ToString() and UniqueKey.Parse() failed to reproduce an identical object (case 5).\n        }\n\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void GrainIdShouldEncodeAndDecodePrimaryKeyGuidCorrectly()\n        {\n            const int repeat = 100;\n            for (int i = 0; i < repeat; ++i)\n            {\n                Guid expected = Guid.NewGuid();\n                GrainId grainId = GrainId.Create(GrainType.Create(\"foo\"), GrainIdKeyExtensions.CreateGuidKey(expected));\n                Guid actual = grainId.GetGuidKey();\n                Assert.Equal(expected, actual); // Failed to encode and decode grain id\n            }\n        }\n\n        /// <summary>\n        /// Tests GrainId serialization and deserialization through printable string representation.\n        /// </summary>\n        [Theory, TestCategory(\"SlowBVT\"), TestCategory(\"Identifiers\")]\n        [MemberData(nameof(TestGrainIds))]\n        public void GrainId_ToFromPrintableString(GrainId grainId)\n        {\n            string str = grainId.ToString();\n            var roundTripped = GrainId.Parse(str);\n\n            Assert.Equal(grainId, roundTripped);\n        }\n\n        [Theory, TestCategory(\"SlowBVT\"), TestCategory(\"Identifiers\")]\n        [MemberData(nameof(TestGrainIds))]\n        public void GrainId_TryParseFromPrintableString(GrainId grainId)\n        {\n            string str = grainId.ToString();\n            var success = GrainId.TryParse(str, out var roundTripped);\n\n            Assert.True(success);\n            Assert.Equal(grainId, roundTripped);\n        }\n\n        /// <summary>\n        /// Tests GrainId JSON serialization and deserialization round-trip.\n        /// </summary>\n        [Theory, TestCategory(\"SlowBVT\"), TestCategory(\"Identifiers\")]\n        [MemberData(nameof(TestGrainIds))]\n        public void GrainId_RoundTripJsonConverter(GrainId grainId)\n        {\n            var serialized = JsonSerializer.Serialize(grainId);\n            var deserialized = JsonSerializer.Deserialize<GrainId>(serialized);\n\n            Assert.Equal(grainId, deserialized);\n        }\n\n        public static TheoryData<GrainId> TestGrainIds\n        {\n            get\n            {\n                var td = new TheoryData<GrainId>();\n                var grainType = GrainType.Create(\"test\");\n                var guid = Guid.NewGuid();\n                var integer = Random.Shared.NextInt64();\n\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateGuidKey(guid)));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateGuidKey(guid, \"Guid-ExtKey-1\")));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateGuidKey(guid, (string)null)));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateIntegerKey(integer)));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateIntegerKey(integer, \"Long-ExtKey-2\")));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateIntegerKey(integer, (string)null)));\n                td.Add(GrainId.Create(grainType, GrainIdKeyExtensions.CreateIntegerKey(UniqueKey.NewKey(integer).PrimaryKeyToLong(), \"Long-ExtKey-2\")));\n\n                return td;\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueTypeCodeDataShouldStore32BitsOfInformation()\n        {\n            const int expected = unchecked((int)0xfabccbaf);\n            var uk = UniqueKey.NewKey(0, UniqueKey.Category.None, expected);\n            var actual = uk.BaseTypeCode;\n\n            Assert.Equal(expected, actual);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueKeysShouldPreserveTheirPrimaryKeyValueIfItIsGuid()\n        {\n            const int all32Bits = unchecked((int)0xffffffff);\n            var expectedKey1 = Guid.NewGuid();\n            const string expectedKeyExt1 = \"1\";\n            var uk1 = UniqueKey.NewKey(expectedKey1, UniqueKey.Category.KeyExtGrain, all32Bits, expectedKeyExt1);\n            string actualKeyExt1;\n            var actualKey1 = uk1.PrimaryKeyToGuid(out actualKeyExt1);\n            Assert.Equal(expectedKey1, actualKey1); //\"UniqueKey objects should preserve the value of their primary key (Guid case #1).\");\n            Assert.Equal(expectedKeyExt1, actualKeyExt1); //\"UniqueKey objects should preserve the value of their key extension (Guid case #1).\");\n\n            var expectedKey2 = Guid.NewGuid();\n            const string expectedKeyExt2 = \"2\";\n            var uk2 = UniqueKey.NewKey(expectedKey2, UniqueKey.Category.KeyExtGrain, all32Bits, expectedKeyExt2);\n            string actualKeyExt2;\n            var actualKey2 = uk2.PrimaryKeyToGuid(out actualKeyExt2);\n            Assert.Equal(expectedKey2, actualKey2); // \"UniqueKey objects should preserve the value of their primary key (Guid case #2).\");\n            Assert.Equal(expectedKeyExt2, actualKeyExt2); // \"UniqueKey objects should preserve the value of their key extension (Guid case #2).\");\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void UniqueKeysShouldPreserveTheirPrimaryKeyValueIfItIsLong()\n        {\n            const int all32Bits = unchecked((int)0xffffffff);\n\n            var n1 = random.Next();\n            var n2 = random.Next();\n            const string expectedKeyExt = \"1\";\n            var expectedKey = unchecked((long)((((ulong)((uint)n1)) << 32) | ((uint)n2)));\n            var uk = UniqueKey.NewKey(expectedKey, UniqueKey.Category.KeyExtGrain, all32Bits, expectedKeyExt);\n\n            string actualKeyExt;\n            var actualKey = uk.PrimaryKeyToLong(out actualKeyExt);\n\n            Assert.Equal(expectedKey, actualKey); // \"UniqueKey objects should preserve the value of their primary key (long case).\");\n            Assert.Equal(expectedKeyExt, actualKeyExt); // \"UniqueKey objects should preserve the value of their key extension (long case).\");\n        }\n\n        /// <summary>\n        /// Tests GrainId interning functionality to ensure identical IDs reference the same object.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void ID_Interning_GrainID()\n        {\n            Guid guid = new Guid();\n            GrainId gid1 = LegacyGrainId.FromParsableString(guid.ToString(\"B\"));\n            GrainId gid2 = LegacyGrainId.FromParsableString(guid.ToString(\"N\"));\n            Assert.Equal(gid1, gid2); // Should be equal GrainId's\n\n            // Round-trip through Serializer\n            GrainId gid3 = this.environment.Serializer.Deserialize<GrainId>(environment.Serializer.SerializeToArray(gid1));\n            Assert.Equal(gid1, gid3); // Should be equal GrainId's\n            Assert.Equal(gid2, gid3); // Should be equal GrainId's\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void ID_Interning_string_equals()\n        {\n            using var interner = new Interner<string, string>();\n            const string str = \"1\";\n            string r1 = interner.FindOrCreate(\"1\", _ => str);\n            string r2 = interner.FindOrCreate(\"1\", _ => null); // Should always be found\n\n            Assert.Equal(r1, r2); // 1: Objects should be equal\n            Assert.Same(r1, r2); // 2: Objects should be same / intern'ed\n\n            // Round-trip through Serializer\n            string r3 = this.environment.Serializer.Deserialize<string>(environment.Serializer.SerializeToArray(r1));\n\n            Assert.Equal(r1, r3); // 3: Should be equal\n            Assert.Equal(r2, r3); // 4: Should be equal\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void ID_Intern_FindOrCreate_derived_class()\n        {\n            using var interner = new Interner<int, A>();\n            var obj1 = new A();\n            var obj2 = new B();\n            var obj3 = new B();\n\n            var r1 = interner.FindOrCreate(1, _ => obj1);\n            Assert.Equal(obj1, r1); // Objects should be equal\n            Assert.Same(obj1, r1); // Objects should be same / intern'ed\n\n            var r2 = interner.FindOrCreate(2, _ => obj2);\n            Assert.Equal(obj2, r2); // Objects should be equal\n            Assert.Same(obj2, r2); // Objects should be same / intern'ed\n\n            // FindOrCreate should not replace instances of same class\n            var r3 = interner.FindOrCreate(2, _ => obj3);\n            Assert.Same(obj2, r3); // FindOrCreate should return previous object\n            Assert.NotSame(obj3, r3); // FindOrCreate should not replace previous object of same class\n\n            // FindOrCreate should not replace cached instances with instances of most derived class\n            var r4 = interner.FindOrCreate(1, _ => obj2);\n            Assert.Same(obj1, r4); // FindOrCreate return previously cached object\n            Assert.NotSame(obj2, r4); // FindOrCreate should not replace previously cached object\n\n            // FindOrCreate should not replace cached instances with instances of less derived class\n            var r5 = interner.FindOrCreate(2, _ => obj1);\n            Assert.NotSame(obj1, r5); // FindOrCreate should not replace previously cached object\n            Assert.Same(obj2, r5); // FindOrCreate return previously cached object\n        }\n\n        /// <summary>\n        /// Tests SiloAddress interning to ensure identical addresses reference the same object.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void Interning_SiloAddress()\n        {\n            //string addrStr1 = \"1.2.3.4@11111@1\";\n            SiloAddress a1 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 1111), 12345);\n            SiloAddress a2 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 1111), 12345);\n            Assert.Equal(a1, a2); // Should be equal SiloAddress's\n            Assert.Same(a1, a2); // Should be same / intern'ed SiloAddress object\n\n            // Round-trip through Serializer\n            SiloAddress a3 = this.environment.Serializer.Deserialize<SiloAddress>(environment.Serializer.SerializeToArray(a1));\n            Assert.Equal(a1, a3); // Should be equal SiloAddress's\n            Assert.Equal(a2, a3); // Should be equal SiloAddress's\n            Assert.Same(a1, a3); // Should be same / intern'ed SiloAddress object\n            Assert.Same(a2, a3); // Should be same / intern'ed SiloAddress object\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void Interning_SiloAddress2()\n        {\n            SiloAddress a1 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 1111), 12345);\n            SiloAddress a2 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 2222), 12345);\n            Assert.NotEqual(a1, a2); // Should not be equal SiloAddress's\n            Assert.NotSame(a1, a2); // Should not be same / intern'ed SiloAddress object\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void Interning_SiloAddress_Serialization()\n        {\n            SiloAddress a1 = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 1111), 12345);\n\n            // Round-trip through Serializer\n            SiloAddress a3 = this.environment.Serializer.Deserialize<SiloAddress>(environment.Serializer.SerializeToArray(a1));\n            Assert.Equal(a1, a3); // Should be equal SiloAddress's\n            Assert.Same(a1, a3); // Should be same / intern'ed SiloAddress object\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\")]\n        public void SiloAddress_ToFrom_ParsableString()\n        {\n            SiloAddress address1 = SiloAddressUtils.NewLocalSiloAddress(12345);\n\n            string addressStr1 = address1.ToParsableString();\n            SiloAddress addressObj1 = SiloAddress.FromParsableString(addressStr1);\n\n            output.WriteLine(\"Convert -- From: {0} Got result string: '{1}' object: {2}\",\n                address1, addressStr1, addressObj1);\n\n            Assert.Equal(address1, addressObj1); // SiloAddress equal after To-From-ParsableString\n\n            //const string addressStr2 = \"127.0.0.1-11111-144611139\";\n            const string addressStr2 = \"127.0.0.1:11111@144611139\";\n            SiloAddress addressObj2 = SiloAddress.FromParsableString(addressStr2);\n            string addressStr2Out = addressObj2.ToParsableString();\n\n            output.WriteLine(\"Convert -- From: {0} Got result string: '{1}' object: {2}\",\n                addressStr2, addressStr2Out, addressObj2);\n\n            Assert.Equal(addressStr2, addressStr2Out); // SiloAddress equal after From-To-ParsableString\n        }\n        /// <summary>\n        /// Tests GrainReference creation, serialization, and round-trip operations.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Identifiers\"), TestCategory(\"GrainReference\")]\n        public void GrainReference_Test1()\n        {\n            Guid guid = Guid.NewGuid();\n            GrainId regularGrainId = LegacyGrainId.GetGrainIdForTesting(guid);\n            GrainReference grainRef = (GrainReference)this.environment.InternalGrainFactory.GetGrain(regularGrainId);\n            TestGrainReference(grainRef);\n\n            grainRef = (GrainReference)this.environment.InternalGrainFactory.GetGrain(regularGrainId);\n            TestGrainReference(grainRef);\n        }\n\n        private void TestGrainReference(GrainReference grainRef)\n        {\n            GrainReference roundTripped = RoundTripGrainReferenceToKey(grainRef);\n            Assert.Equal(grainRef, roundTripped); // GrainReference.ToKeyString\n\n            roundTripped = this.environment.Serializer.Deserialize<GrainReference>(environment.Serializer.SerializeToArray(grainRef));\n            Assert.Equal(grainRef, roundTripped); // GrainReference.OrleansSerializer\n        }\n\n        private GrainReference RoundTripGrainReferenceToKey(GrainReference input)\n        {\n            string str = input.GrainId.ToString();\n            GrainReference output = this.environment.Services.GetRequiredService<GrainReferenceActivator>().CreateReference(GrainId.Parse(str), default);\n            return output;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/General/RequestContextTestsNonSiloRequired.cs",
    "content": "using System.Globalization;\nusing Orleans;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing Xunit;\nusing Tester;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for request context functionality including multi-threading, activity ID propagation, and import/export operations.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class RequestContextTests_Local : IDisposable\n    {\n        private readonly Dictionary<string, object> headers = new Dictionary<string, object>();\n\n\n        private readonly TestEnvironmentFixture fixture;\n\n        public RequestContextTests_Local(TestEnvironmentFixture fixture)\n        {\n            this.fixture = fixture;\n            RequestContext.Clear();\n            headers.Clear();\n        }\n\n        public void Dispose()\n        {\n            TestCleanup();\n        }\n\n        private void TestCleanup()\n        {\n            RequestContextTestUtils.ClearActivityId();\n            RequestContext.Clear();\n            headers.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_MultiThreads_ExportToMessage()\n        {\n            const int NumLoops = 50;\n            string id = \"key\" + Random.Shared.Next();\n\n            Message msg = new Message();\n            Task[] promises = new Task[NumLoops];\n            ManualResetEventSlim flag = new ManualResetEventSlim(false);\n            for (int i = 0; i < NumLoops; i++)\n            {\n                string key = id + \"-\" + i;\n                RequestContext.Set(key, i);\n                promises[i] = Task.Run(() =>\n                {\n                    flag.Wait();\n                    msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n                });\n                flag.Set();\n                Thread.Sleep(1);\n                RequestContext.Remove(key);\n            }\n            await Task.WhenAll(promises);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public void RequestContext_ActivityId_ExportToMessage()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n            Guid nullActivityId = Guid.Empty;\n\n            Message msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)\n                {\n                    headers.Add(kvp.Key, kvp.Value);\n                };\n            Assert.False(headers.ContainsKey(RequestContext.CALL_CHAIN_REENTRANCY_HEADER), \"ActivityId should not be be present \" + headers.ToStrings(separator: \",\"));\n            TestCleanup();\n\n            RequestContext.ReentrancyId = activityId;\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)\n                {\n                    headers.Add(kvp.Key, kvp.Value);\n                };\n            Assert.True(headers.ContainsKey(RequestContext.CALL_CHAIN_REENTRANCY_HEADER), \"ActivityId #1 should be present \" + headers.ToStrings(separator: \",\"));\n            object result = headers[RequestContext.CALL_CHAIN_REENTRANCY_HEADER];\n            Assert.NotNull(result);// ActivityId #1 should not be null\n            Assert.Equal(activityId, result);  // \"E2E ActivityId #1 not propagated correctly\"\n            Assert.Equal(activityId, RequestContextTestUtils.GetActivityId());  // \"Original E2E ActivityId #1 should not have changed\"\n            TestCleanup();\n\n            RequestContextTestUtils.SetActivityId(nullActivityId);\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)\n                {\n                    headers.Add(kvp.Key, kvp.Value);\n                };\n            Assert.False(headers.ContainsKey(RequestContext.CALL_CHAIN_REENTRANCY_HEADER), \"Null ActivityId should not be present \" + headers.ToStrings(separator: \",\"));\n            TestCleanup();\n\n            RequestContextTestUtils.SetActivityId(activityId2);\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            foreach (var kvp in msg.RequestContextData)\n            {\n                headers.Add(kvp.Key, kvp.Value);\n            };\n            Assert.True(headers.ContainsKey(RequestContext.CALL_CHAIN_REENTRANCY_HEADER), \"ActivityId #2 should be present \" + headers.ToStrings(separator: \",\"));\n            result = headers[RequestContext.CALL_CHAIN_REENTRANCY_HEADER];\n            Assert.NotNull(result); // ActivityId #2 should not be null\n            Assert.Equal(activityId2, result);  // \"E2E ActivityId #2 not propagated correctly\"\n\n            Assert.Equal(activityId2, RequestContextTestUtils.GetActivityId());  // \"Original E2E ActivityId #2 should not have changed\"\n            TestCleanup();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public void RequestContext_ActivityId_ExportImport()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n            Guid nullActivityId = Guid.Empty;\n\n            Message msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            RequestContext.Clear();\n            RequestContextExtensions.Import(msg.RequestContextData);\n            var actId = RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER);\n            Assert.Null(actId);\n            TestCleanup();\n\n            RequestContextTestUtils.SetActivityId(activityId);\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            RequestContext.Clear();\n            RequestContextExtensions.Import(msg.RequestContextData);\n            actId = RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER);\n            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)\n                {\n                    headers.Add(kvp.Key, kvp.Value);\n                };\n            Assert.NotNull(actId); // \"ActivityId #1 should be present \" + headers.ToStrings(separator: \",\")\n            object result = headers[RequestContext.CALL_CHAIN_REENTRANCY_HEADER];\n            Assert.NotNull(result);// \"ActivityId #1 should not be null\"\n            Assert.Equal(activityId, result);  // \"E2E ActivityId #1 not propagated correctly\"\n            Assert.Equal(activityId, RequestContextTestUtils.GetActivityId());  // \"Original E2E ActivityId #1 should not have changed\"\n            TestCleanup();\n\n            RequestContextTestUtils.SetActivityId(nullActivityId);\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            RequestContext.Clear();\n            RequestContextExtensions.Import(msg.RequestContextData);\n            actId = RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER);\n            Assert.Null(actId);\n            TestCleanup();\n\n            RequestContextTestUtils.SetActivityId(activityId2);\n            msg = new Message();\n            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.DeepCopier);\n            RequestContext.Clear();\n            RequestContextExtensions.Import(msg.RequestContextData);\n            actId = RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER);\n            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)\n                {\n                    headers.Add(kvp.Key, kvp.Value);\n                };\n            Assert.NotNull(actId); // \"ActivityId #2 should be present \" + headers.ToStrings(separator: \",\")\n            result = headers[RequestContext.CALL_CHAIN_REENTRANCY_HEADER];\n            Assert.NotNull(result); // \"ActivityId #2 should not be null\"\n            Assert.Equal(activityId2, result);// \"E2E ActivityId #2 not propagated correctly\n\n            Assert.Equal(activityId2, RequestContextTestUtils.GetActivityId()); // \"Original E2E ActivityId #2 should not have changed\"\n            TestCleanup();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_CrossThread()\n        {\n            const int NumLoops = 1000;\n\n            string name1 = \"Name\" + Random.Shared.Next();\n            string data1 = \"Main\";\n\n            RequestContext.Set(name1, data1);\n            Assert.Equal(data1, RequestContext.Get(name1));  // \"RC.GetData-Main\"\n\n            Task[] promises = new Task[NumLoops];\n            for (int i = 0; i < NumLoops; i++)\n            {\n                string str = i.ToString(CultureInfo.InvariantCulture);\n                promises[i] = Task.Run(async () =>\n                {\n                    await Task.Delay(5);\n                    Assert.Equal(data1, RequestContext.Get(name1));  // \"RC.GetData-Task.Run-0\"\n                    await Task.Delay(5);\n                    // Set New value\n                    RequestContext.Set(name1, str);\n                    Assert.Equal(str, RequestContext.Get(name1));  // \"RC.GetData-Task.Run-1-\" + str\n                    await Task.Delay(5);\n                    Assert.Equal(str, RequestContext.Get(name1));  // \"RC.GetData-Task.Run-2-\" + str\n                    await Task.Delay(5);\n                    Assert.Equal(str, RequestContext.Get(name1));  // \"RC.GetData-Task.Run-3-\" + str\n                });\n            }\n            await Task.WhenAll(promises);\n            Assert.Equal(data1, RequestContext.Get(name1));  // \"RC.GetData-Main-Final\"\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/General/RingTests_Standalone.cs",
    "content": "using System.Collections.Immutable;\nusing System.Net;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Runtime;\nusing Orleans.Runtime.ConsistentRing;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    public class RingTests_Standalone\n    {\n        private const int count = 5;\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void RingStandalone_Basic()\n        {\n            Dictionary<SiloAddress, ConsistentRingProvider> rings = CreateServers(count);\n            rings = Combine(rings, rings);\n            VerifyRing(rings);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void RingStandalone_Failures()\n        {\n            TestChurn(new int[] { 0 }, new int[] { });    // 1 failure in the beginning\n            TestChurn(new int[] { 0, 1 }, new int[] { }); // 2 failures in the beginning\n\n            TestChurn(new int[] { count - 1 }, new int[] { });            // 1 failure at the end\n            TestChurn(new int[] { count - 1, count - 2 }, new int[] { }); // 2 failures at the end\n\n            TestChurn(new int[] { count / 2 }, new int[] { });                // 1 failure in the middle\n            TestChurn(new int[] { count / 2, 1 + count / 2 }, new int[] { }); // 2 failures in the middle\n\n            TestChurn(new int[] { 1, count - 2 }, new int[] { }); // 2 failures at some distance\n            TestChurn(new int[] { 0, count - 1 }, new int[] { }); // 2 failures at some distance\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void RingStandalone_Joins()\n        {\n            TestChurn(new int[] { }, new int[] { 0 });     // 1 join in the beginning\n            TestChurn(new int[] { }, new int[] { 0, 1 });  // 2 joins in the beginning\n\n            TestChurn(new int[] { }, new int[] { count - 1 });             // 1 join at the end\n            TestChurn(new int[] { }, new int[] { count - 1, count - 2 });  // 2 joins at the end\n\n            TestChurn(new int[] { }, new int[] { count / 2 });                 // 1 join in the middle\n            TestChurn(new int[] { }, new int[] { count / 2, 1 + count / 2 });  // 2 joins in the middle\n\n            TestChurn(new int[] { }, new int[] { 1, count - 2 });  // 2 joins at some distance\n            TestChurn(new int[] { }, new int[] { 0, count - 1 });  // 2 joins at some distance\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void RingStandalone_Mixed()\n        {\n            TestChurn(new int[] { 0 }, new int[] { 1 });     // FJ in the beginning\n            TestChurn(new int[] { 1 }, new int[] { 0 });     // JF in the beginning\n\n            TestChurn(new int[] { count - 2 }, new int[] { count - 1 });     // FJ at the end\n            TestChurn(new int[] { count - 1 }, new int[] { count - 2 });     // JF at the end\n\n            TestChurn(new int[] { count / 2 }, new int[] { 1 + count / 2 });     // FJ in the middle\n            TestChurn(new int[] { 1 + count / 2 }, new int[] { count / 2 });     // JF in the middle\n\n            TestChurn(new int[] { 0 }, new int[] { count - 1 });     // F first, J at the end\n            TestChurn(new int[] { count - 1 }, new int[] { 0 });     // F last, J at the beginning\n\n        }\n\n        private void TestChurn(int[] indexesFails, int[] indexesJoins)\n        {\n            Dictionary<SiloAddress, ConsistentRingProvider> rings, holder = new Dictionary<SiloAddress, ConsistentRingProvider>();\n            List<SiloAddress> sortedServers, fail = new List<SiloAddress>();\n\n            rings = CreateServers(count);\n\n            sortedServers = rings.Keys.ToList();\n            sortedServers.Sort(CompareSiloAddressesByHash);\n            // failures\n            foreach (int i in indexesFails)\n            {\n                fail.Add(sortedServers[i]);\n            }\n            // joins\n            foreach (int i in indexesJoins)\n            {\n                holder.Add(sortedServers[i], rings[sortedServers[i]]);\n                rings.Remove(sortedServers[i]);\n            }\n            rings = Combine(rings, rings);\n            RemoveServers(rings, fail);     // fail nodes\n            rings = Combine(rings, holder); // join the new nodes\n            VerifyRing(rings);\n        }\n\n        private static Dictionary<SiloAddress, ConsistentRingProvider> CreateServers(int n)\n        {\n            Dictionary<SiloAddress, ConsistentRingProvider> rings = new Dictionary<SiloAddress, ConsistentRingProvider>();\n\n            for (int i = 1; i <= n; i++)\n            {\n                SiloAddress addr = SiloAddressUtils.NewLocalSiloAddress(i);\n                rings.Add(addr, new ConsistentRingProvider(addr, NullLoggerFactory.Instance, new FakeSiloStatusOracle()));\n            }\n            return rings;\n        }\n\n        private static Dictionary<SiloAddress, ConsistentRingProvider> Combine(Dictionary<SiloAddress, ConsistentRingProvider> set1, Dictionary<SiloAddress, ConsistentRingProvider> set2)\n        {\n            // tell set1 about every node in set2\n            foreach (ConsistentRingProvider crp in set1.Values)\n            {\n                foreach (ConsistentRingProvider other in set2.Values)\n                {\n                    if (!crp.MyAddress.Equals(other.MyAddress))\n                    {\n                        other.AddServer(crp.MyAddress);\n                    }\n                }\n            }\n\n            // tell set2 about every node in set1 ... even if set1 and set2 overlap, ConsistentRingProvider should be able to handle\n            foreach (ConsistentRingProvider crp in set2.Values)\n            {\n                foreach (ConsistentRingProvider other in set1.Values)\n                {\n                    if (!crp.MyAddress.Equals(other.MyAddress))\n                    {\n                        other.AddServer(crp.MyAddress);\n                    }\n                }\n            }\n\n            // tell set2 about every node in set2 ... note that set1 already knows about nodes in set1\n            foreach (ConsistentRingProvider crp in set2.Values)\n            {\n                foreach (ConsistentRingProvider other in set2.Values)\n                {\n                    if (!crp.MyAddress.Equals(other.MyAddress))\n                    {\n                        other.AddServer(crp.MyAddress);\n                    }\n                }\n            }\n\n            // merge the sets\n            return set1.Union(set2).ToDictionary(pair => pair.Key, pair => pair.Value);\n        }\n\n        private void RemoveServers(Dictionary<SiloAddress, ConsistentRingProvider> rings, List<SiloAddress> remove)\n        {\n            foreach (SiloAddress addr in remove)\n            {\n                rings.Remove(addr);\n            }\n\n            // tell every node about the failed nodes\n            foreach (ConsistentRingProvider crp in rings.Values)\n            {\n                foreach (SiloAddress addr in remove)\n                {\n                    crp.RemoveServer(addr);\n                }\n            }\n        }\n\n        private void VerifyRing(Dictionary<SiloAddress, ConsistentRingProvider> rings)\n        {\n            RangeBreakable fullring = new RangeBreakable();\n\n            foreach (ConsistentRingProvider r in rings.Values)\n            {\n                // see if there is no overlap between the responsibilities of two nodes\n                Assert.True(fullring.Remove(r.GetMyRange()), string.Format(\"Couldn't find & break range {0} in {1}. Some other node already claimed responsibility.\", r.GetMyRange(), fullring));\n            }\n            Assert.True(fullring.NumRanges == 0, string.Format(\"Range not completely covered. Uncovered ranges: {0}\", fullring));\n        }\n\n        /// <summary>\n        /// Compare SiloAddress-es based on their consistent hash code\n        /// </summary>\n        /// <param name=\"x\"></param>\n        /// <param name=\"y\"></param>\n        /// <returns></returns>\n        private static int CompareSiloAddressesByHash(SiloAddress x, SiloAddress y)\n        {\n            if (x == null)\n            {\n                return y == null ? 0 : -1;\n            }\n            else\n            {\n                if (y == null)\n                {\n                    return 1;\n                }\n                else\n                {\n                    // real comparison is here\n                    return x.GetConsistentHashCode().CompareTo(y.GetConsistentHashCode());\n                }\n            }\n        }\n    }\n\n    internal sealed class FakeSiloStatusOracle : ISiloStatusOracle\n    {\n        private readonly Dictionary<SiloAddress, SiloStatus> _content = [];\n        private readonly HashSet<ISiloStatusListener> _subscribers = [];\n\n        public FakeSiloStatusOracle()\n        {\n            SiloAddress = SiloAddress.New(IPAddress.Loopback, Random.Shared.Next(2000, 40_000), SiloAddress.AllocateNewGeneration());\n            _content[SiloAddress] = SiloStatus.Active;\n        }\n\n        public SiloStatus CurrentStatus => SiloStatus.Active;\n\n        public string SiloName => \"TestSilo\";\n\n        public SiloAddress SiloAddress { get; }\n\n        public SiloStatus GetApproximateSiloStatus(SiloAddress siloAddress)\n        {\n            if (_content.TryGetValue(siloAddress, out var status))\n            {\n                return status;\n            }\n            return SiloStatus.None;\n        }\n\n        public Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false)\n        {\n            return onlyActive\n                ? new Dictionary<SiloAddress, SiloStatus>(_content.Where(kvp => kvp.Value == SiloStatus.Active))\n                : new Dictionary<SiloAddress, SiloStatus>(_content);\n        }\n\n        public void SetSiloStatus(SiloAddress siloAddress, SiloStatus status)\n        {\n            _content[siloAddress] = status;\n            foreach (var subscriber in _subscribers)\n            {\n                subscriber.SiloStatusChangeNotification(siloAddress, status);\n            }\n        }\n\n        public bool IsDeadSilo(SiloAddress silo) => GetApproximateSiloStatus(silo) == SiloStatus.Dead;\n\n        public bool IsFunctionalDirectory(SiloAddress siloAddress) => !GetApproximateSiloStatus(siloAddress).IsTerminating();\n\n        public bool SubscribeToSiloStatusEvents(ISiloStatusListener observer) => _subscribers.Add(observer);\n\n        public bool TryGetSiloName(SiloAddress siloAddress, out string siloName)\n        {\n            siloName = \"TestSilo\";\n            return true;\n        }\n\n        public bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener observer) => _subscribers.Remove(observer);\n        public ImmutableArray<SiloAddress> GetActiveSilos() => [.. GetApproximateSiloStatuses(onlyActive: true).Keys];\n    }\n\n    internal class RangeBreakable\n    {\n        private List<SingleRange> ranges { get; set; }\n        internal int NumRanges { get { return ranges.Count; } }\n\n        public RangeBreakable()\n        {\n            ranges = new List<SingleRange>(1);\n            ranges.Add(RangeFactory.CreateFullRange() as SingleRange);\n        }\n\n        public bool Remove(IRingRange range)\n        {\n            bool wholerange = true;\n            foreach (var s in RangeFactory.GetSubRanges(range))\n            {\n                bool found = false;\n                foreach (var m in ranges)\n                {\n                    if (m.Begin == m.End) // treat full range as special case\n                    {\n                        found = true;\n                        ranges.Remove(m);\n                        if (s.Begin != s.End) // if s is full range as well, then end of story ... whole range is covered\n                        {\n                            ranges.Add(RangeFactory.CreateRange(s.End, s.Begin) as SingleRange);\n                        }\n                        break;\n                    }\n\n                    if (m.InRange(s.Begin + 1) && m.InRange(s.End)) // s cant overlap two singleranges\n                    {\n                        found = true;\n                        ranges.Remove(m);\n                        if (s.Begin != m.Begin)\n                        {\n                            ranges.Add(RangeFactory.CreateRange(m.Begin, s.Begin) as SingleRange);\n                        }\n                        if (s.End != m.End)\n                        {\n                            ranges.Add(RangeFactory.CreateRange(s.End, m.End) as SingleRange);\n                        }\n                        break;\n                    }\n                }\n                wholerange = wholerange && found;\n            }\n            return wholerange;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/General/UtilsTests.cs",
    "content": "using System.Net;\nusing Orleans.Runtime;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.UtilsTests\n{\n    /// <summary>\n    /// Tests for utility functions including gateway URI conversion for IPv4 and IPv6 addresses.\n    /// </summary>\n    [TestCategory(\"Utils\")]\n    public class UtilsTests\n    {\n        private readonly ITestOutputHelper output;\n\n\n        public UtilsTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public void ToGatewayUriTest()\n        {\n            var ipv4 = new IPEndPoint(IPAddress.Any, 11111);\n            var uri = ipv4.ToGatewayUri();\n            Assert.Equal(\"gwy.tcp://0.0.0.0:11111/0\", uri.ToString());\n\n            var ipv4silo = SiloAddress.New(ipv4, 100);\n            uri = ipv4silo.ToGatewayUri();\n            Assert.Equal(\"gwy.tcp://0.0.0.0:11111/100\", uri.ToString());\n\n            var ipv6 = new IPEndPoint(IPAddress.IPv6Any, 11111);\n            uri = ipv6.ToGatewayUri();\n            Assert.Equal(\"gwy.tcp://[::]:11111/0\", uri.ToString());\n\n            var ipv6silo = SiloAddress.New(ipv6, 100);\n            uri = ipv6silo.ToGatewayUri();\n            Assert.Equal(\"gwy.tcp://[::]:11111/100\", uri.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/IdSpanTests.cs",
    "content": "using Orleans.Runtime;\nusing Xunit;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// Tests for IdSpan, a primitive type for identities representing a sequence of bytes.\n    /// Validates equality, hash code consistency, and proper handling of null vs empty arrays.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class IdSpanTests\n    {\n        /// <summary>\n        /// Tests that IdSpan.Create(string.Empty) and default(IdSpan) are NOT equal.\n        /// They should have different internal states (empty array vs null) and should not be considered equal.\n        /// </summary>\n        [Fact]\n        public void IdSpan_CreateEmptyString_NotEqualToDefault()\n        {\n            IdSpan createdFromEmptyString = IdSpan.Create(string.Empty);\n            IdSpan defaultIdSpan = default;\n\n            Assert.NotEqual(createdFromEmptyString, defaultIdSpan);\n            Assert.False(createdFromEmptyString.Equals(defaultIdSpan));\n            Assert.False(createdFromEmptyString == defaultIdSpan);\n            Assert.True(createdFromEmptyString != defaultIdSpan);\n        }\n\n        /// <summary>\n        /// Tests that hash codes are consistent with equality.\n        /// If two IdSpans are equal, they must have the same hash code.\n        /// </summary>\n        [Fact]\n        public void IdSpan_HashCode_ConsistentWithEquality()\n        {\n            IdSpan id1 = IdSpan.Create(\"test\");\n            IdSpan id2 = IdSpan.Create(\"test\");\n            IdSpan id3 = IdSpan.Create(\"different\");\n\n            // Equal objects must have equal hash codes\n            Assert.Equal(id1, id2);\n            Assert.Equal(id1.GetHashCode(), id2.GetHashCode());\n\n            // Not equal objects may have different hash codes (not required but expected)\n            Assert.NotEqual(id1, id3);\n        }\n\n        /// <summary>\n        /// Tests that default IdSpan has expected properties.\n        /// </summary>\n        [Fact]\n        public void IdSpan_Default_HasExpectedProperties()\n        {\n            IdSpan defaultIdSpan = default;\n\n            Assert.True(defaultIdSpan.IsDefault);\n            Assert.Equal(0, defaultIdSpan.GetHashCode());\n            Assert.Equal(\"\", defaultIdSpan.ToString());\n        }\n\n        /// <summary>\n        /// Tests that IdSpan created from empty string has expected properties.\n        /// </summary>\n        [Fact]\n        public void IdSpan_CreateEmptyString_HasExpectedProperties()\n        {\n            IdSpan emptyStringIdSpan = IdSpan.Create(string.Empty);\n\n            Assert.True(emptyStringIdSpan.IsDefault);\n            Assert.Equal(\"\", emptyStringIdSpan.ToString());\n            // Hash code should be computed from empty byte array, not 0\n            Assert.NotEqual(0, emptyStringIdSpan.GetHashCode());\n        }\n\n        /// <summary>\n        /// Tests that IdSpans with same content are equal.\n        /// </summary>\n        [Fact]\n        public void IdSpan_SameContent_AreEqual()\n        {\n            IdSpan id1 = IdSpan.Create(\"test123\");\n            IdSpan id2 = IdSpan.Create(\"test123\");\n\n            Assert.Equal(id1, id2);\n            Assert.True(id1 == id2);\n            Assert.False(id1 != id2);\n            Assert.Equal(id1.GetHashCode(), id2.GetHashCode());\n        }\n\n        /// <summary>\n        /// Tests that IdSpans with different content are not equal.\n        /// </summary>\n        [Fact]\n        public void IdSpan_DifferentContent_AreNotEqual()\n        {\n            IdSpan id1 = IdSpan.Create(\"test1\");\n            IdSpan id2 = IdSpan.Create(\"test2\");\n\n            Assert.NotEqual(id1, id2);\n            Assert.False(id1 == id2);\n            Assert.True(id1 != id2);\n        }\n\n        /// <summary>\n        /// Tests CompareTo behavior with null and empty arrays.\n        /// </summary>\n        [Fact]\n        public void IdSpan_CompareTo_HandlesNullAndEmpty()\n        {\n            IdSpan defaultIdSpan = default;\n            IdSpan emptyStringIdSpan = IdSpan.Create(string.Empty);\n            IdSpan normalIdSpan = IdSpan.Create(\"test\");\n\n            // Default (null) should compare differently than empty string\n            Assert.NotEqual(0, defaultIdSpan.CompareTo(emptyStringIdSpan));\n            Assert.NotEqual(0, emptyStringIdSpan.CompareTo(defaultIdSpan));\n            \n            // Both should be less than a normal span\n            Assert.True(defaultIdSpan.CompareTo(normalIdSpan) < 0);\n            Assert.True(emptyStringIdSpan.CompareTo(normalIdSpan) < 0);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Lease/GoldenPathInMemoryLeaseProviderTests.cs",
    "content": "using Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Runtime.Development;\nusing TestExtensions;\nusing TestExtensions.Runners;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests for the in-memory lease provider implementation following the golden path test patterns.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Lease\")]\n    public class GoldenPathInMemoryLeaseProviderTests : GoldenPathLeaseProviderTestRunner, IClassFixture<GoldenPathInMemoryLeaseProviderTests.Fixture>\n    {\n        public GoldenPathInMemoryLeaseProviderTests(Fixture fixture, ITestOutputHelper output)\n            : base(new InMemoryLeaseProvider(fixture.GrainFactory), output)\n        {\n        }\n\n        public class Fixture : BaseTestClusterFixture\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ManagementAgentTests.cs",
    "content": "﻿\nusing Orleans.Runtime;\nusing Xunit;\n\nnamespace UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans management and monitoring components, particularly the SystemStatus enumeration.\n    /// SystemStatus is used throughout Orleans to track the lifecycle state of silos and other runtime components.\n    /// </summary>\n    public class ManagementAgentTests\n    {\n        /// <summary>\n        /// Tests the equality implementation of SystemStatus values to ensure proper comparison behavior.\n        /// This is important for state management and monitoring throughout the Orleans runtime.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Management\")]\n        public void SystemStatusEquals()\n        {\n            SystemStatus same1 = SystemStatus.Terminated;\n            SystemStatus same2 = SystemStatus.Terminated;\n            SystemStatus other = SystemStatus.Stopping;\n\n            CheckEquals(same1, same2);\n            CheckNotEquals(same1, other);\n            CheckNotEquals(same2, other);\n        }\n\n        //[Fact]\n        //public void CheckEventChannelEnvSetup()\n        //{\n        //    bool found = ManagementBusConnector.CheckEventChannelEnvSetup();\n        //    Console.WriteLine(\"CheckEventChannelEnvSetup=\" + found);\n        //}\n\n        private static void CheckEquals(object obj, object other)\n        {\n            Assert.NotNull(obj);\n            Assert.NotNull(other);\n            Assert.Equal(obj, other);\n            Assert.Equal(other, obj);\n            Assert.Equal(obj.GetHashCode(), other.GetHashCode());\n            Assert.True(obj.Equals(other));\n            Assert.True(other.Equals(obj));\n            Assert.True(obj == other);\n            Assert.True(other == obj);\n            Assert.False(obj != other);\n            Assert.False(other != obj);\n        }\n\n        private static void CheckNotEquals(object obj, object other)\n        {\n            Assert.NotNull(obj);\n            Assert.NotNull(other);\n            Assert.NotEqual(obj, other);\n            Assert.NotEqual(other, obj);\n            Assert.NotEqual(obj.GetHashCode(), other.GetHashCode());\n            Assert.False(obj.Equals(other));\n            Assert.False(other.Equals(obj));\n            Assert.False(obj == other);\n            Assert.False(other == obj);\n            Assert.True(obj != other);\n            Assert.True(other != obj);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/ClusterHealthMonitorTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NonSilo.Tests.Utilities;\nusing NSubstitute;\nusing Orleans.Configuration;\nusing Orleans.Runtime.MembershipService;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for Orleans' cluster health monitoring system, which is responsible for detecting failed silos\n    /// and maintaining cluster membership consistency. The health monitor performs periodic probes of other silos\n    /// and uses voting mechanisms to declare silos as dead, preventing split-brain scenarios in the distributed system.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class ClusterHealthMonitorTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly LoggerFactory loggerFactory;\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly SiloAddress localSilo;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly IMembershipGossiper membershipGossiper;\n        private readonly SiloLifecycleSubject lifecycle;\n        private readonly List<DelegateAsyncTimer> timers;\n        private readonly ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)> timerCalls;\n        private readonly DelegateAsyncTimerFactory timerFactory;\n        private readonly ILocalSiloHealthMonitor localSiloHealthMonitor;\n        private readonly InMemoryMembershipTable membershipTable;\n        private readonly IRemoteSiloProber prober;\n\n        public ClusterHealthMonitorTests(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(this.output) });\n\n            this.localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            this.localSilo = Silo(\"127.0.0.1:100@100\");\n            this.localSiloDetails.SiloAddress.Returns(this.localSilo);\n            this.localSiloDetails.DnsHostName.Returns(\"MyServer11\");\n            this.localSiloDetails.Name.Returns(Guid.NewGuid().ToString(\"N\"));\n\n            this.fatalErrorHandler = Substitute.For<IFatalErrorHandler>();\n            this.membershipGossiper = Substitute.For<IMembershipGossiper>();\n            this.lifecycle = new SiloLifecycleSubject(this.loggerFactory.CreateLogger<SiloLifecycleSubject>());\n            this.timers = new List<DelegateAsyncTimer>();\n            this.timerCalls = new ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n            this.timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            this.timerCalls.Enqueue((overridePeriod, task));\n                            return task.Task;\n                        });\n                    this.timers.Add(t);\n                    return t;\n                });\n\n            this.localSiloHealthMonitor = Substitute.For<ILocalSiloHealthMonitor>();\n            this.localSiloHealthMonitor.GetLocalHealthDegradationScore(default).ReturnsForAnyArgs(0);\n\n            this.prober = Substitute.For<IRemoteSiloProber>();\n            this.membershipTable = new InMemoryMembershipTable(new TableVersion(1, \"1\"));\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_BasicScenario()\n        {\n            await ClusterHealthMonitor_BasicScenario_Runner(enableIndirectProbes: true, numVotesForDeathDeclaration: 2);\n        }\n\n        /// <summary>\n        /// Tests that when silos are stale, they are monitored by all other silos.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_MonitorAllStaleSilos()\n        {\n            await ClusterHealthMonitor_BasicScenario_Runner(enableIndirectProbes: true, numVotesForDeathDeclaration: 2, otherSilosAreStale: true);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with indirect probes disabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_NoIndirectProbes()\n        {\n            await ClusterHealthMonitor_BasicScenario_Runner(enableIndirectProbes: false, numVotesForDeathDeclaration: 2);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with indirect probes disabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_ThreeVotesNeededToKill()\n        {\n            await ClusterHealthMonitor_BasicScenario_Runner(enableIndirectProbes: true, numVotesForDeathDeclaration: 3);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with indirect probes disabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_OneVoteNeededToKill()\n        {\n            await ClusterHealthMonitor_BasicScenario_Runner(enableIndirectProbes: false, numVotesForDeathDeclaration: 1);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with EvictWhenMaxJoinAttemptTimeExceeded enabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_SilosWithStaleCreatedOrJoiningState_OneVoteNeededToKill()\n        {\n            await ClusterHealthMonitor_StaleJoinOrCreatedSilos_Runner(evictWhenMaxJoinAttemptTimeExceeded: true, numVotesForDeathDeclaration: 1);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with EvictWhenMaxJoinAttemptTimeExceeded enabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_SilosWithStaleCreatedOrJoiningState_TwoVotesNeededToKill()\n        {\n            await ClusterHealthMonitor_StaleJoinOrCreatedSilos_Runner(evictWhenMaxJoinAttemptTimeExceeded: true, numVotesForDeathDeclaration: 2);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with EvictWhenMaxJoinAttemptTimeExceeded enabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_SilosWithStaleCreatedOrJoiningState_ThreeVotesNeededToKill()\n        {\n            await ClusterHealthMonitor_StaleJoinOrCreatedSilos_Runner(evictWhenMaxJoinAttemptTimeExceeded: true, numVotesForDeathDeclaration: 3);\n        }\n\n        /// <summary>\n        /// Tests basic operation of <see cref=\"ClusterHealthMonitor\"/> and <see cref=\"SiloHealthMonitor\"/>, but with EvictWhenMaxJoinAttemptTimeExceeded enabled.\n        /// </summary>\n        [Fact]\n        public async Task ClusterHealthMonitor_SilosWithStaleCreatedOrJoiningState_Disabled()\n        {\n            await ClusterHealthMonitor_StaleJoinOrCreatedSilos_Runner(evictWhenMaxJoinAttemptTimeExceeded: false, numVotesForDeathDeclaration: 3);\n        }\n\n        private async Task ClusterHealthMonitor_BasicScenario_Runner(bool enableIndirectProbes, int? numVotesForDeathDeclaration = default, bool otherSilosAreStale = false)\n        {\n            var now = DateTimeOffset.UtcNow;\n            var clusterMembershipOptions = new ClusterMembershipOptions\n            {\n                EnableIndirectProbes = enableIndirectProbes,\n                NumProbedSilos = 3,\n            };\n\n            if (numVotesForDeathDeclaration.HasValue)\n            {\n                clusterMembershipOptions.NumVotesForDeathDeclaration = numVotesForDeathDeclaration.Value;\n            }\n\n            var testRig = CreateClusterHealthMonitorTestRig(clusterMembershipOptions);\n            var probeCalls = new ConcurrentQueue<(SiloAddress Target, int ProbeNumber, bool IsIndirect)>();\n            this.prober.Probe(default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(0), info.ArgAt<int>(1), false));\n                return Task.CompletedTask;\n            });\n            this.prober.ProbeIndirectly(default, default, default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(1), info.ArgAt<int>(3), true));\n                return Task.FromResult(new IndirectProbeResponse\n                {\n                    IntermediaryHealthScore = 0,\n                    ProbeResponseTime = TimeSpan.FromMilliseconds(1),\n                    Succeeded = true\n                });\n            });\n\n            await this.lifecycle.OnStart();\n            Assert.Empty(testRig.TestAccessor.MonitoredSilos);\n\n            var iAmAliveTime = otherSilosAreStale ? now.Subtract(TimeSpan.FromHours(1)) : now;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.200:100@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:200@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:300@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:400@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:500@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:600@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:700@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:800@100\"), SiloStatus.Active, iAmAliveTime),\n                Entry(Silo(\"127.0.0.200:900@100\"), SiloStatus.Active, iAmAliveTime)\n            };\n\n            var lastVersion = testRig.TestAccessor.ObservedVersion;\n\n            // Add the new silos\n            var table = await this.membershipTable.ReadAll();\n            foreach (var entry in otherSilos)\n            {\n                table = await this.membershipTable.ReadAll();\n                Assert.True(await this.membershipTable.InsertRow(entry, table.Version.Next()));\n            }\n\n            await testRig.Manager.Refresh();\n\n            await Until(() => testRig.TestAccessor.ObservedVersion > lastVersion);\n            lastVersion = testRig.TestAccessor.ObservedVersion;\n\n            // No silos should be monitored by this silo until it becomes active.\n            Assert.Empty(testRig.TestAccessor.MonitoredSilos);\n\n            await testRig.Manager.UpdateStatus(SiloStatus.Active);\n\n            await Until(() => testRig.TestAccessor.ObservedVersion > lastVersion);\n            lastVersion = testRig.TestAccessor.ObservedVersion;\n\n            // Now that this silo is active, it should be monitoring some fraction of the other active silos\n            await Until(() => testRig.TestAccessor.MonitoredSilos.Count > 0);\n            Assert.NotEmpty(this.timers);\n            Assert.DoesNotContain(testRig.TestAccessor.MonitoredSilos, s => s.Key.Equals(this.localSilo));\n            var expectedNumProbedSilos = otherSilosAreStale ? otherSilos.Length : clusterMembershipOptions.NumProbedSilos;\n            Assert.Equal(expectedNumProbedSilos, testRig.TestAccessor.MonitoredSilos.Count);\n            Assert.All(testRig.TestAccessor.MonitoredSilos, m => m.Key.Equals(m.Value.TargetSiloAddress));\n            Assert.Empty(probeCalls);\n\n            // Check that those silos are actually being probed periodically\n            await UntilEqual(expectedNumProbedSilos, () =>\n            {\n                if (this.timerCalls.TryDequeue(out var timer))\n                {\n                    timer.Completion.TrySetResult(true);\n                }\n\n                return probeCalls.Count;\n            });\n            Assert.Equal(expectedNumProbedSilos, probeCalls.Count);\n            while (probeCalls.TryDequeue(out var call)) Assert.Contains(testRig.TestAccessor.MonitoredSilos, k => k.Key.Equals(call.Item1));\n\n            var monitoredSilos = testRig.TestAccessor.MonitoredSilos.Values.ToList();\n            foreach (var siloMonitor in monitoredSilos)\n            {\n                Assert.Equal(0, ((SiloHealthMonitor.ITestAccessor)siloMonitor).MissedProbes);\n            }\n\n            // Make the probes fail.\n            this.prober.Probe(default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(0), info.ArgAt<int>(1), true));\n                return Task.FromException(new Exception(\"no\"));\n            });\n            this.prober.ProbeIndirectly(default, default, default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(1), info.ArgAt<int>(3), true));\n                return Task.FromResult(new IndirectProbeResponse\n                {\n                    FailureMessage = \"We failed the probe on purpose, as a joke\",\n                    IntermediaryHealthScore = 0,\n                    ProbeResponseTime = TimeSpan.FromSeconds(1),\n                    Succeeded = false\n                });\n            });\n\n            // The above call to specify the probe behaviour also enqueued a value, so clear it here.\n            while (probeCalls.TryDequeue(out _)) ;\n\n            for (var expectedMissedProbes = 1; expectedMissedProbes <= clusterMembershipOptions.NumMissedProbesLimit; expectedMissedProbes++)\n            {\n                this.membershipTable.ClearCalls();\n\n                // Wait for probes to be fired\n                await UntilEqual(expectedNumProbedSilos, () =>\n                {\n                    if (this.timerCalls.TryDequeue(out var timer))\n                    {\n                        timer.Completion.TrySetResult(true);\n                    }\n\n                    return probeCalls.Count;\n                });\n\n                while (probeCalls.TryDequeue(out var call)) ;\n\n                testRig.Manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n                // Check that probes match the expected missed probes\n                table = await this.membershipTable.ReadAll();\n                foreach (var siloMonitor in monitoredSilos)\n                {\n                    Assert.Equal(expectedMissedProbes, ((SiloHealthMonitor.ITestAccessor)siloMonitor).MissedProbes);\n\n                    var entry = table.Members.Single(m => m.Item1.SiloAddress.Equals(siloMonitor.TargetSiloAddress)).Item1;\n                    var votes = entry.GetFreshVotes(now.UtcDateTime, clusterMembershipOptions.DeathVoteExpirationTimeout);\n                    if (expectedMissedProbes < clusterMembershipOptions.NumMissedProbesLimit)\n                    {\n                        Assert.Empty(votes);\n                    }\n                    else\n                    {\n                        // After a certain number of failures, a vote should be added to the table.\n                        Assert.Contains(votes, vote => vote.Item1.Equals(localSiloDetails.SiloAddress));\n                        if (clusterMembershipOptions.NumVotesForDeathDeclaration <= 2 && enableIndirectProbes || numVotesForDeathDeclaration == 1)\n                        {\n                            Assert.Equal(SiloStatus.Dead, entry.Status);\n                        }\n                    }\n                }\n            }\n\n            if (enableIndirectProbes && numVotesForDeathDeclaration <= 2 || numVotesForDeathDeclaration == 1)\n            {\n                table = await this.membershipTable.ReadAll();\n                Assert.Equal(expectedNumProbedSilos, table.Members.Count(m => m.Item1.Status == SiloStatus.Dead));\n\n                // There is no more to test here, since all of the monitored silos have been killed.\n                return;\n            }\n\n            await testRig.Manager.Refresh();\n\n            // Make the probes succeed again.\n            this.prober.Probe(default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(0), info.ArgAt<int>(1), false));\n                return Task.CompletedTask;\n            });\n            this.prober.ProbeIndirectly(default, default, default, default).ReturnsForAnyArgs(info =>\n            {\n                probeCalls.Enqueue((info.ArgAt<SiloAddress>(1), info.ArgAt<int>(3), true));\n                return Task.FromResult(new IndirectProbeResponse\n                {\n                    IntermediaryHealthScore = 0,\n                    ProbeResponseTime = TimeSpan.FromMilliseconds(1),\n                    Succeeded = true\n                });\n            });\n\n            // The above call to specify the probe behaviour also enqueued a value, so clear it here.\n            while (probeCalls.TryDequeue(out _)) ;\n\n            // Wait for probes to be fired\n            this.output.WriteLine($\"Firing probes for silos: {string.Join(\", \", testRig.TestAccessor.MonitoredSilos.Keys)}\");\n            var probesReceived = new HashSet<SiloAddress>();\n            await UntilEqual(testRig.TestAccessor.MonitoredSilos.Count, () =>\n            {\n                if (this.timerCalls.TryDequeue(out var timer))\n                {\n                    timer.Completion.TrySetResult(true);\n                }\n\n                while (probeCalls.TryDequeue(out var call))\n                {\n                    probesReceived.Add(call.Target);\n                }\n\n                return probesReceived.Count;\n            });\n\n            foreach (var siloMonitor in testRig.TestAccessor.MonitoredSilos.Values)\n            {\n                this.output.WriteLine($\"Checking missed probes on {siloMonitor.TargetSiloAddress}: {((SiloHealthMonitor.ITestAccessor)siloMonitor).MissedProbes}\");\n                Assert.Equal(0, ((SiloHealthMonitor.ITestAccessor)siloMonitor).MissedProbes);\n            }\n\n            await StopLifecycle();\n        }\n\n        private async Task ClusterHealthMonitor_StaleJoinOrCreatedSilos_Runner(bool evictWhenMaxJoinAttemptTimeExceeded = true, int? numVotesForDeathDeclaration = default)\n        {\n            var now = DateTimeOffset.UtcNow;\n            var clusterMembershipOptions = new ClusterMembershipOptions\n            {\n                EvictWhenMaxJoinAttemptTimeExceeded = evictWhenMaxJoinAttemptTimeExceeded\n            };\n\n            if (numVotesForDeathDeclaration.HasValue)\n            {\n                clusterMembershipOptions.NumVotesForDeathDeclaration = numVotesForDeathDeclaration.Value;\n            }\n\n            var testRig = CreateClusterHealthMonitorTestRig(clusterMembershipOptions);\n\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.200:100@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:300@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:400@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:500@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:600@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:700@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:800@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.200:900@100\"), SiloStatus.Active, now)\n            };\n\n            var joiningSilo = \"127.0.0.200:111@100\";\n            var createdSilo = \"127.0.0.200:112@100\";\n\n            // default MaxJoinAttemptTime is 5 minutes, setting it to 6 minutes ago will make sure they are flagged immediately\n            var staleCreatedOrJoiningSilos = new[]\n            {\n                Entry(Silo(joiningSilo), SiloStatus.Joining, DateTime.UtcNow.AddMinutes(-6)),\n                Entry(Silo(createdSilo), SiloStatus.Created, DateTime.UtcNow.AddMinutes(-6)),\n            };\n\n            otherSilos = [.. otherSilos, .. staleCreatedOrJoiningSilos];\n\n            var lastVersion = testRig.TestAccessor.ObservedVersion;\n\n            // Add the new silos\n            var table = await this.membershipTable.ReadAll();\n            foreach (var entry in otherSilos)\n            {\n                table = await this.membershipTable.ReadAll();\n                Assert.True(await this.membershipTable.InsertRow(entry, table.Version.Next()));\n            }\n\n            table = await this.membershipTable.ReadAll();\n            var joiningEntry = GetEntryFromTable(table, joiningSilo);\n            var createdEntry = GetEntryFromTable(table, createdSilo);\n\n            Assert.NotNull(joiningEntry);\n            Assert.NotNull(createdEntry);\n\n            Assert.Equal(expected: SiloStatus.Joining, actual: joiningEntry.Item1.Status);\n            Assert.Equal(expected: SiloStatus.Created, actual: createdEntry.Item1.Status);\n\n            // We are going to add numVotesForDeathDeclaration - 1 votes to the created or joining silos\n            var totalRequiredVotes = clusterMembershipOptions.NumVotesForDeathDeclaration;\n\n            var votesNeeded = totalRequiredVotes - 1;\n\n            // the joining and created silos should not be declared dead until the required number of votes.\n            while (votesNeeded > 0)\n            {\n                table = await this.membershipTable.ReadAll();\n                joiningEntry = GetEntryFromTable(table, joiningSilo);\n                joiningEntry.Item1.AddSuspector(otherSilos[0].SiloAddress, DateTime.UtcNow);\n                Assert.True(await this.membershipTable.UpdateRow(joiningEntry.Item1, joiningEntry.Item2, table.Version.Next()));\n\n                table = await this.membershipTable.ReadAll();\n                createdEntry = GetEntryFromTable(table, createdSilo);\n                createdEntry.Item1.AddSuspector(otherSilos[0].SiloAddress, DateTime.UtcNow);\n                Assert.True(await this.membershipTable.UpdateRow(createdEntry.Item1, createdEntry.Item2, table.Version.Next()));\n\n                votesNeeded--;\n            }\n\n            table = await this.membershipTable.ReadAll();\n            joiningEntry = GetEntryFromTable(table, joiningSilo);\n            createdEntry = GetEntryFromTable(table, createdSilo);\n\n            // Suspect time will be null if numVotesForDeathDeclaration == 1\n            if (totalRequiredVotes > 1 && evictWhenMaxJoinAttemptTimeExceeded)\n            {\n                Assert.Equal(totalRequiredVotes - 1, joiningEntry.Item1.SuspectTimes.Count);\n                Assert.Equal(totalRequiredVotes - 1, createdEntry.Item1.SuspectTimes.Count);\n            }\n\n            // now we start the lifecycle and let the local silo add the final vote.\n            await this.lifecycle.OnStart();\n\n            await testRig.Manager.Refresh();\n\n            testRig.Manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            await Until(() => testRig.TestAccessor.ObservedVersion > lastVersion);\n            \n            lastVersion = testRig.TestAccessor.ObservedVersion;\n\n            table = await this.membershipTable.ReadAll();\n            joiningEntry = GetEntryFromTable(table, joiningSilo);\n            createdEntry = GetEntryFromTable(table, createdSilo);\n\n            var expectedVotes = totalRequiredVotes == 1\n                ? 2\n                : totalRequiredVotes;\n\n            expectedVotes = evictWhenMaxJoinAttemptTimeExceeded\n                ? totalRequiredVotes\n                : totalRequiredVotes - 1;\n\n            Assert.True(expectedVotes <= joiningEntry.Item1.SuspectTimes.Count);\n            Assert.True(expectedVotes <= createdEntry.Item1.SuspectTimes.Count);\n\n            Assert.Equal(expected: evictWhenMaxJoinAttemptTimeExceeded ? SiloStatus.Dead : SiloStatus.Joining, actual: joiningEntry.Item1.Status);\n            Assert.Equal(expected: evictWhenMaxJoinAttemptTimeExceeded ? SiloStatus.Dead : SiloStatus.Created, actual: createdEntry.Item1.Status);\n\n            await StopLifecycle();\n\n            static Tuple<MembershipEntry, string> GetEntryFromTable(MembershipTableData table, string siloAddress)\n            {\n                return table.Members.FirstOrDefault(entry => entry.Item1.SiloAddress.ToParsableString() == siloAddress);\n            }\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static MembershipEntry Entry(SiloAddress address, SiloStatus status, DateTimeOffset startTime = default) => new MembershipEntry { SiloAddress = address, Status = status, StartTime = startTime.UtcDateTime, IAmAliveTime = startTime.UtcDateTime };\n\n        private static async Task UntilEqual<T>(T expected, Func<T> getActual)\n        {\n            var maxTimeout = 40_000;\n            var equalityComparer = EqualityComparer<T>.Default;\n            var actual = getActual();\n            while (!equalityComparer.Equals(expected, actual) && (maxTimeout -= 10) > 0)\n            {\n                await Task.Delay(10);\n                actual = getActual();\n            }\n\n            Assert.Equal(expected, actual);\n            Assert.True(maxTimeout > 0);\n        }\n\n        private static async Task Until(Func<bool> condition)\n        {\n            var maxTimeout = 40_000;\n            while (!condition() && (maxTimeout -= 10) > 0) await Task.Delay(10);\n            Assert.True(maxTimeout > 0);\n        }\n\n        private async Task StopLifecycle(CancellationToken cancellation = default)\n        {\n            var stopped = this.lifecycle.OnStop(cancellation);\n\n            while (!stopped.IsCompleted)\n            {\n                while (this.timerCalls.TryDequeue(out var call)) call.Completion.TrySetResult(false);\n                await Task.Delay(15);\n            }\n\n            await stopped;\n        }\n\n        private class ClusterHealthMonitorTestRig(\n            MembershipTableManager manager,\n            IOptionsMonitor<ClusterMembershipOptions> optionsMonitor,\n            ClusterHealthMonitor.ITestAccessor testAccessor)\n        {\n            public readonly MembershipTableManager Manager = manager;\n            public readonly IOptionsMonitor<ClusterMembershipOptions> OptionsMonitor = optionsMonitor;\n            public readonly ClusterHealthMonitor.ITestAccessor TestAccessor = testAccessor;\n        }\n\n        private ClusterHealthMonitorTestRig CreateClusterHealthMonitorTestRig(ClusterMembershipOptions clusterMembershipOptions)\n        {\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(clusterMembershipOptions),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                this.lifecycle);\n\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n\n            var optionsMonitor = Substitute.For<IOptionsMonitor<ClusterMembershipOptions>>();\n            optionsMonitor.CurrentValue.ReturnsForAnyArgs(clusterMembershipOptions);\n\n            var monitor = new ClusterHealthMonitor(\n                this.localSiloDetails,\n                manager,\n                this.loggerFactory.CreateLogger<ClusterHealthMonitor>(),\n                optionsMonitor,\n                this.fatalErrorHandler,\n                null);\n\n            ((ILifecycleParticipant<ISiloLifecycle>)monitor).Participate(this.lifecycle);\n\n            var testAccessor = (ClusterHealthMonitor.ITestAccessor)monitor;\n            testAccessor.CreateMonitor = s => new SiloHealthMonitor(\n                s,\n                testAccessor.OnProbeResult,\n                optionsMonitor,\n                this.loggerFactory,\n                this.prober,\n                this.timerFactory,\n                this.localSiloHealthMonitor,\n                manager,\n                this.localSiloDetails);\n\n            return new(\n                manager: manager,\n                optionsMonitor: optionsMonitor,\n                testAccessor: testAccessor);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/InMemoryMembershipTable.cs",
    "content": "using Orleans.Runtime;\nusing Orleans;\nusing System.Collections.Immutable;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// An in-memory implementation of <see cref=\"IMembershipTable\"/> for testing purposes.\n    /// </summary>\n    public class InMemoryMembershipTable : IMembershipTable\n    {\n        private readonly object tableLock = new object();\n        private readonly List<(string, object)> calls = new List<(string, object)>();\n        private ImmutableList<(MembershipEntry, string)> entries = ImmutableList<(MembershipEntry, string)>.Empty;\n\n        public InMemoryMembershipTable() { }\n\n        public InMemoryMembershipTable(TableVersion version, params MembershipEntry[] entries)\n        {\n            var builder = ImmutableList.CreateBuilder<(MembershipEntry, string)>();\n            foreach (var entry in entries)\n            {\n                builder.Add((entry, version.VersionEtag));\n            }\n\n            this.Version = version;\n            this.entries = builder.ToImmutable();\n        }\n\n        public List<(string Method, object Arguments)> Calls\n        {\n            get\n            {\n                lock (this.tableLock) return new List<(string, object)>(this.calls);\n            }\n        }\n\n        public Action OnReadAll { get; set; }\n        public TableVersion Version { get; set; } = new TableVersion(0, \"0\");\n\n        public void ClearCalls()\n        {\n            lock (this.tableLock) this.calls.Clear();\n        }\n\n        public void Reset()\n        {\n            lock (this.tableLock)\n            {\n                this.entries = ImmutableList<(MembershipEntry, string)>.Empty;\n                this.Version = this.Version.Next();\n            }\n        }\n\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(CleanupDefunctSiloEntries), beforeDate));\n                var newEntries = ImmutableList.CreateBuilder<(MembershipEntry, string)>();\n                foreach (var (entry, etag) in this.entries)\n                {\n                    if (entry.Status == SiloStatus.Dead\n                        && new DateTime(Math.Max(entry.IAmAliveTime.Ticks, entry.StartTime.Ticks), DateTimeKind.Utc) < beforeDate)\n                    {\n                        continue;\n                    }\n\n                    newEntries.Add((entry, etag));\n                }\n\n                this.entries = newEntries.ToImmutable();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task DeleteMembershipTableEntries(string clusterId)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(DeleteMembershipTableEntries), clusterId));\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(InitializeMembershipTable), tryInitTableVersion));\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(InsertRow), (entry, tableVersion)));\n                this.ValidateVersion(tableVersion);\n\n                if (this.entries.Exists(e => e.Item1.SiloAddress.Equals(entry.SiloAddress)))\n                {\n                    return Task.FromResult(false);\n                }\n\n                this.Version = new TableVersion(tableVersion.Version, tableVersion.Version.ToString());\n                this.entries = this.entries.Add((entry, this.Version.VersionEtag));\n\n                return Task.FromResult(true);\n            }\n        }\n\n        public Task<MembershipTableData> ReadAll()\n        {\n            this.OnReadAll?.Invoke();\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(ReadAll), null));\n                var result = new MembershipTableData(\n                    this.entries.Select(e => Tuple.Create(e.Item1, e.Item2)).ToList(),\n                    this.Version);\n                return Task.FromResult(result);\n            }\n        }\n\n        public Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(ReadRow), key));\n                var result = new MembershipTableData(\n                    this.entries.Where(e => e.Item1.SiloAddress.Equals(key)).Select(e => Tuple.Create(e.Item1, e.Item2)).ToList(),\n                    this.Version);\n                return Task.FromResult(result);\n            }\n        }\n\n        public Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(UpdateIAmAlive), entry));\n                var existingEntry = this.entries.Single(e => e.Item1.SiloAddress.Equals(entry.SiloAddress));\n                var replacement = existingEntry.Item1.Copy();\n                replacement.IAmAliveTime = entry.IAmAliveTime;\n                this.entries = this.entries.Replace(existingEntry, (replacement, Guid.NewGuid().ToString()));\n                return Task.CompletedTask;\n            }\n        }\n\n        public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            lock (this.tableLock)\n            {\n                this.calls.Add((nameof(UpdateRow), (entry, etag, tableVersion)));\n                this.ValidateVersion(tableVersion);\n                var existingEntry = this.entries.Find(e => e.Item1.SiloAddress.Equals(entry.SiloAddress));\n                if (existingEntry.Item1 is null) return Task.FromResult(false);\n\n                if (!etag.Equals(existingEntry.Item2))\n                {\n                    throw new InvalidOperationException($\"Mismatching row etag. Required: {existingEntry.Item2}, Provided: {etag}\");\n                }\n\n                this.Version = new TableVersion(tableVersion.Version, tableVersion.Version.ToString());\n                this.entries = this.entries.Replace(existingEntry, (entry, this.Version.VersionEtag));\n                return Task.FromResult(true);\n            }\n        }\n\n        private void ValidateVersion(TableVersion tableVersion)\n        {\n            lock (this.tableLock)\n            {\n                if (this.Version.VersionEtag != tableVersion.VersionEtag)\n                {\n                    throw new InvalidOperationException(\"Etag mismatch\");\n                }\n\n                if (this.Version.Version >= tableVersion.Version)\n                {\n                    throw new InvalidOperationException(\"Version must increase on update\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/MembershipAgentTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NonSilo.Tests.Utilities;\nusing NSubstitute;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for membership agent functionality including lifecycle stages, IAmAlive updates, and connectivity validation.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class MembershipAgentTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly LoggerFactory loggerFactory;\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly SiloAddress localSilo;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly IMembershipGossiper membershipGossiper;\n        private readonly SiloLifecycleSubject lifecycle;\n        private readonly List<DelegateAsyncTimer> timers;\n        private readonly ConcurrentDictionary<string, ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>> timerCalls;\n        private readonly DelegateAsyncTimerFactory timerFactory;\n        private readonly InMemoryMembershipTable membershipTable;\n        private readonly IOptions<ClusterMembershipOptions> clusterMembershipOptions;\n        private readonly MembershipTableManager manager;\n        private readonly ClusterHealthMonitor clusterHealthMonitor;\n        private readonly IRemoteSiloProber remoteSiloProber;\n        private readonly Func<SiloHealthMonitor, SiloHealthMonitor.ProbeResult, Task> onProbeResult;\n        private readonly MembershipAgent agent;\n        private readonly ILocalSiloHealthMonitor localSiloHealthMonitor;\n        private readonly IOptionsMonitor<ClusterMembershipOptions> optionsMonitor;\n\n        public MembershipAgentTests(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(this.output) });\n\n            this.localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            this.localSilo = SiloAddress.FromParsableString(\"127.0.0.1:100@100\");\n            this.localSiloDetails.SiloAddress.Returns(this.localSilo);\n            this.localSiloDetails.DnsHostName.Returns(\"MyServer11\");\n            this.localSiloDetails.Name.Returns(Guid.NewGuid().ToString(\"N\"));\n\n            this.fatalErrorHandler = Substitute.For<IFatalErrorHandler>();\n            this.fatalErrorHandler.IsUnexpected(default).ReturnsForAnyArgs(true);\n            this.membershipGossiper = Substitute.For<IMembershipGossiper>();\n            this.lifecycle = new SiloLifecycleSubject(this.loggerFactory.CreateLogger<SiloLifecycleSubject>());\n            this.timers = new List<DelegateAsyncTimer>();\n            this.timerCalls = new ConcurrentDictionary<string, ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>>();\n            this.timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var queue = this.timerCalls.GetOrAdd(name, n => new ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>());\n                            var task = new TaskCompletionSource<bool>();\n                            queue.Enqueue((overridePeriod, task));\n                            return task.Task;\n                        });\n                    this.timers.Add(t);\n                    return t;\n                });\n\n            this.membershipTable = new InMemoryMembershipTable(new TableVersion(1, \"1\"));\n            this.clusterMembershipOptions = Options.Create(new ClusterMembershipOptions() { MaxJoinAttemptTime = TimeSpan.FromSeconds(45) });\n            this.manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)this.manager).Participate(this.lifecycle);\n\n            this.optionsMonitor = Substitute.For<IOptionsMonitor<ClusterMembershipOptions>>();\n            this.optionsMonitor.CurrentValue.ReturnsForAnyArgs(this.clusterMembershipOptions.Value);\n            this.clusterHealthMonitor = new ClusterHealthMonitor(\n                this.localSiloDetails,\n                this.manager,\n                this.loggerFactory.CreateLogger<ClusterHealthMonitor>(),\n                optionsMonitor,\n                this.fatalErrorHandler,\n                null);\n            ((ILifecycleParticipant<ISiloLifecycle>)this.clusterHealthMonitor).Participate(this.lifecycle);\n\n            this.remoteSiloProber = Substitute.For<IRemoteSiloProber>();\n            remoteSiloProber.Probe(default, default).ReturnsForAnyArgs(Task.CompletedTask);\n\n            this.localSiloHealthMonitor = Substitute.For<ILocalSiloHealthMonitor>();\n            this.localSiloHealthMonitor.GetLocalHealthDegradationScore(default).ReturnsForAnyArgs(0);\n\n            this.onProbeResult = (Func<SiloHealthMonitor, SiloHealthMonitor.ProbeResult, Task>)((siloHealthMonitor, probeResult) => Task.CompletedTask);\n\n            this.agent = new MembershipAgent(\n                this.manager,\n                this.localSiloDetails,\n                this.fatalErrorHandler,\n                this.clusterMembershipOptions,\n                this.loggerFactory.CreateLogger<MembershipAgent>(),\n                this.timerFactory,\n                this.remoteSiloProber);\n            ((ILifecycleParticipant<ISiloLifecycle>)this.agent).Participate(this.lifecycle);\n        }\n\n        [Fact]\n        public async Task MembershipAgent_LifecycleStages_GracefulShutdown()\n        {\n            var levels = new ConcurrentDictionary<int, SiloStatus>();\n            Func<CancellationToken, Task> Callback(int level) => ct =>\n            {\n                levels[level] = this.manager.CurrentStatus;\n                return Task.CompletedTask;\n            };\n            Task NoOp(CancellationToken ct) => Task.CompletedTask;\n            foreach (var l in new[] {\n                ServiceLifecycleStage.RuntimeInitialize,\n                ServiceLifecycleStage.AfterRuntimeGrainServices,\n                ServiceLifecycleStage.BecomeActive})\n            {\n                // After start\n                this.lifecycle.Subscribe(\n                \"x\",\n                l + 1,\n                Callback(l + 1),\n                NoOp);\n\n                // After stop\n                this.lifecycle.Subscribe(\n                \"x\",\n                l - 1,\n                NoOp,\n                Callback(l - 1));\n            }\n\n            await this.lifecycle.OnStart();\n            Assert.Equal(SiloStatus.Created, levels[ServiceLifecycleStage.RuntimeInitialize + 1]);\n            Assert.Equal(SiloStatus.Joining, levels[ServiceLifecycleStage.AfterRuntimeGrainServices + 1]);\n            Assert.Equal(SiloStatus.Active, levels[ServiceLifecycleStage.BecomeActive + 1]);\n\n            await StopLifecycle();\n\n            Assert.Equal(SiloStatus.ShuttingDown, levels[ServiceLifecycleStage.BecomeActive - 1]);\n            Assert.Equal(SiloStatus.ShuttingDown, levels[ServiceLifecycleStage.AfterRuntimeGrainServices - 1]);\n            Assert.Equal(SiloStatus.Dead, levels[ServiceLifecycleStage.RuntimeInitialize - 1]);\n        }\n\n        [Fact]\n        public async Task MembershipAgent_LifecycleStages_UngracefulShutdown()\n        {\n            var levels = new ConcurrentDictionary<int, SiloStatus>();\n            Func<CancellationToken, Task> Callback(int level) => ct =>\n            {\n                levels[level] = this.manager.CurrentStatus;\n                return Task.CompletedTask;\n            };\n            Task NoOp(CancellationToken ct) => Task.CompletedTask;\n            foreach (var l in new[] {\n                ServiceLifecycleStage.RuntimeInitialize,\n                ServiceLifecycleStage.AfterRuntimeGrainServices,\n                ServiceLifecycleStage.BecomeActive})\n            {\n                // After start\n                this.lifecycle.Subscribe(\n                \"x\",\n                l + 1,\n                Callback(l + 1),\n                NoOp);\n\n                // After stop\n                this.lifecycle.Subscribe(\n                \"x\",\n                l - 1,\n                NoOp,\n                Callback(l - 1));\n            }\n\n            await this.lifecycle.OnStart();\n            Assert.Equal(SiloStatus.Created, levels[ServiceLifecycleStage.RuntimeInitialize + 1]);\n            Assert.Equal(SiloStatus.Joining, levels[ServiceLifecycleStage.AfterRuntimeGrainServices + 1]);\n            Assert.Equal(SiloStatus.Active, levels[ServiceLifecycleStage.BecomeActive + 1]);\n\n            using var cancellation = new CancellationTokenSource();\n            cancellation.Cancel();\n            await StopLifecycle(cancellation.Token);\n\n            Assert.Equal(SiloStatus.Stopping, levels[ServiceLifecycleStage.BecomeActive - 1]);\n            Assert.Equal(SiloStatus.Stopping, levels[ServiceLifecycleStage.AfterRuntimeGrainServices - 1]);\n            Assert.Equal(SiloStatus.Dead, levels[ServiceLifecycleStage.RuntimeInitialize - 1]);\n        }\n\n        [Fact]\n        public async Task MembershipAgent_UpdateIAmAlive()\n        {\n            await this.lifecycle.OnStart();\n            await Until(() => this.timerCalls.ContainsKey(\"UpdateIAmAlive\"));\n\n            var updateCounter = 0;\n            var testAccessor = (MembershipAgent.ITestAccessor)this.agent;\n            testAccessor.OnUpdateIAmAlive = () => ++updateCounter;\n\n            (TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion) timer = (default, default);\n            while (!this.timerCalls[\"UpdateIAmAlive\"].TryDequeue(out timer)) await Task.Delay(1);\n            timer.Completion.TrySetResult(true);\n            await Until(() => updateCounter == 1);\n\n            testAccessor.OnUpdateIAmAlive = () => { ++updateCounter; throw new Exception(\"no\"); };\n\n            while (!this.timerCalls[\"UpdateIAmAlive\"].TryDequeue(out timer)) await Task.Delay(1);\n            timer.Completion.TrySetResult(true);\n            Assert.False(timer.DelayOverride.HasValue);\n            await Until(() => updateCounter == 2);\n\n            testAccessor.OnUpdateIAmAlive = () => ++updateCounter;\n\n            while (!this.timerCalls[\"UpdateIAmAlive\"].TryDequeue(out timer)) await Task.Delay(1);\n            Assert.True(timer.DelayOverride.HasValue);\n            timer.Completion.TrySetResult(true);\n            await Until(() => updateCounter == 3);\n            Assert.Equal(3, updateCounter);\n\n            // When something goes horribly awry (eg, the timer throws an exception), the silo should fault.\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n            while (!this.timerCalls[\"UpdateIAmAlive\"].TryDequeue(out timer)) await Task.Delay(1);\n            timer.Completion.TrySetException(new Exception(\"no\"));\n            Assert.False(timer.DelayOverride.HasValue);\n            await Until(() => this.fatalErrorHandler.ReceivedCalls().Any());\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n\n            // Stop & cancel all timers.\n            await StopLifecycle();\n        }\n\n        [Fact]\n        public async Task MembershipAgent_LifecycleStages_ValidateInitialConnectivity_Success()\n        {\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.200:100@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:200@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:300@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:400@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:500@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:600@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:700@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:800@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:900@100\"), SiloStatus.Active)\n            };\n\n            // Add the new silos\n            foreach (var entry in otherSilos)\n            {\n                var table = await this.membershipTable.ReadAll();\n                Assert.True(await this.membershipTable.InsertRow(entry, table.Version.Next()));\n            }\n\n            Task onProbeResult(SiloHealthMonitor siloHealthMonitor, SiloHealthMonitor.ProbeResult probeResult) => Task.CompletedTask;\n\n            var clusterHealthMonitorTestAccessor = (ClusterHealthMonitor.ITestAccessor)this.clusterHealthMonitor;\n            clusterHealthMonitorTestAccessor.CreateMonitor = silo => new SiloHealthMonitor(\n                silo,\n                onProbeResult,\n                this.optionsMonitor,\n                this.loggerFactory,\n                remoteSiloProber,\n                this.timerFactory,\n                this.localSiloHealthMonitor,\n                manager,\n                this.localSiloDetails);\n            var started = this.lifecycle.OnStart();\n\n            await Until(() => remoteSiloProber.ReceivedCalls().Count() >= otherSilos.Length);\n\n\n            await Until(() => started.IsCompleted);\n            await started;\n\n            await StopLifecycle();\n        }\n\n        [Fact]\n        public async Task MembershipAgent_LifecycleStages_ValidateInitialConnectivity_Failure()\n        {\n            this.timerFactory.CreateDelegate = (period, name) => new DelegateAsyncTimer(_ => Task.FromResult(false));\n\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.200:100@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:200@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:300@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:400@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:500@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:600@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:700@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:800@100\"), SiloStatus.Active),\n                Entry(Silo(\"127.0.0.200:900@100\"), SiloStatus.Active)\n            };\n\n            // Add the new silos\n            foreach (var entry in otherSilos)\n            {\n                var table = await this.membershipTable.ReadAll();\n                Assert.True(await this.membershipTable.InsertRow(entry, table.Version.Next()));\n            }\n\n            this.remoteSiloProber.Probe(default, default).ReturnsForAnyArgs(Task.FromException(new Exception(\"no\")));\n\n            var dateTimeIndex = 0;\n            var dateTimes = new DateTime[] { DateTime.UtcNow, DateTime.UtcNow.AddMinutes(1) };\n            var membershipAgentTestAccessor = ((MembershipAgent.ITestAccessor)this.agent).GetDateTime = () => dateTimes[dateTimeIndex++];\n\n            var clusterHealthMonitorTestAccessor = (ClusterHealthMonitor.ITestAccessor)this.clusterHealthMonitor;\n            clusterHealthMonitorTestAccessor.CreateMonitor = silo => new SiloHealthMonitor(\n                silo,\n                this.onProbeResult,\n                this.optionsMonitor,\n                this.loggerFactory,\n                this.remoteSiloProber,\n                this.timerFactory,\n                this.localSiloHealthMonitor,\n                manager,\n                this.localSiloDetails);\n            var started = this.lifecycle.OnStart();\n\n            await Until(() => this.remoteSiloProber.ReceivedCalls().Count() >= otherSilos.Length);\n            await Until(() => started.IsCompleted);\n\n            // Startup should have faulted.\n            Assert.True(started.IsFaulted);\n\n            await StopLifecycle();\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static MembershipEntry Entry(SiloAddress address, SiloStatus status) => new MembershipEntry { SiloAddress = address, Status = status, StartTime = DateTime.UtcNow, IAmAliveTime = DateTime.UtcNow };\n\n        private static async Task Until(Func<bool> condition)\n        {\n            var maxTimeout = 40_000;\n            while (!condition() && (maxTimeout -= 10) >= 0) await Task.Delay(10);\n            Assert.True(maxTimeout > 0);\n        }\n\n        private async Task StopLifecycle(CancellationToken cancellation = default)\n        {\n            var stopped = this.lifecycle.OnStop(cancellation);\n\n            while (!stopped.IsCompleted)\n            {\n                foreach (var pair in this.timerCalls) while (pair.Value.TryDequeue(out var call)) call.Completion.TrySetResult(false);\n                await Task.Delay(15);\n            }\n\n            await stopped;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/MembershipTableCleanupAgentTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NonSilo.Tests.Utilities;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.MembershipService;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for membership table cleanup agent functionality including enabled/disabled scenarios and defunct silo cleanup.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class MembershipTableCleanupAgentTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly LoggerFactory loggerFactory;\n\n        public MembershipTableCleanupAgentTests(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(this.output) });\n        }\n\n        [Fact]\n        public async Task MembershipTableCleanupAgent_Enabled_BasicScenario()\n        {\n            await this.BasicScenario(enabled: true);\n        }\n\n        [Fact]\n        public async Task MembershipTableCleanupAgent_Disabled_BasicScenario()\n        {\n            await this.BasicScenario(enabled: false);\n        }\n\n        private async Task BasicScenario(bool enabled)\n        {\n            var options = new ClusterMembershipOptions { DefunctSiloCleanupPeriod = enabled ? new TimeSpan?(TimeSpan.FromMinutes(90)) : null, DefunctSiloExpiration = TimeSpan.FromDays(1) };\n            var timers = new List<DelegateAsyncTimer>();\n            var timerCalls = new ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n            var timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    Assert.Equal(options.DefunctSiloCleanupPeriod.Value, period);\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            timerCalls.Enqueue((overridePeriod, task));\n                            return task.Task;\n                        });\n                    timers.Add(t);\n                    return t;\n                });\n\n            var table = new InMemoryMembershipTable();\n            var cleanupAgent = new MembershipTableCleanupAgent(\n                Options.Create(options),\n                table,\n                this.loggerFactory.CreateLogger<MembershipTableCleanupAgent>(),\n                timerFactory);\n            var lifecycle = new SiloLifecycleSubject(this.loggerFactory.CreateLogger<SiloLifecycleSubject>());\n            ((ILifecycleParticipant<ISiloLifecycle>)cleanupAgent).Participate(lifecycle);\n\n            await lifecycle.OnStart();\n            Assert.DoesNotContain(table.Calls, c => c.Method.Equals(nameof(IMembershipTable.CleanupDefunctSiloEntries)));\n\n            if (enabled) await Until(() => timerCalls.Count > 0);\n\n            Assert.Equal(enabled, timerCalls.TryDequeue(out var timer));\n            timer.Completion?.TrySetResult(true);\n\n            var stopped = lifecycle.OnStop();\n            if (enabled) await Until(() => timerCalls.Count > 0);\n            while (timerCalls.TryDequeue(out timer)) timer.Completion.TrySetResult(false);\n            if (enabled)\n            {\n                Assert.Contains(table.Calls, c => c.Method.Equals(nameof(IMembershipTable.CleanupDefunctSiloEntries)));\n            }\n            else\n            {\n                Assert.DoesNotContain(table.Calls, c => c.Method.Equals(nameof(IMembershipTable.CleanupDefunctSiloEntries)));\n            }\n\n            while (!stopped.IsCompleted)\n            {\n                while (timerCalls.TryDequeue(out var call)) call.Completion.TrySetResult(false);\n                await Task.Delay(15);\n            }\n\n            await stopped;\n        }\n\n        private static async Task Until(Func<bool> condition)\n        {\n            var maxTimeout = 40_000;\n            while (!condition() && (maxTimeout -= 10) > 0) await Task.Delay(10);\n            Assert.True(maxTimeout > 0);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/MembershipTableManagerTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime.MembershipService;\nusing Xunit;\nusing NSubstitute;\nusing Orleans.Runtime;\nusing Orleans;\nusing Xunit.Abstractions;\nusing TestExtensions;\nusing System.Collections.Concurrent;\nusing NonSilo.Tests.Utilities;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for <see cref=\"MembershipTableManager\"/>\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class MembershipTableManagerTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly LoggerFactory loggerFactory;\n        private readonly ILocalSiloDetails localSiloDetails;\n        private readonly SiloAddress localSilo;\n        private readonly IFatalErrorHandler fatalErrorHandler;\n        private readonly IMembershipGossiper membershipGossiper;\n        private readonly SiloLifecycleSubject lifecycle;\n\n        public MembershipTableManagerTests(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(this.output) });\n\n            this.localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            this.localSilo = Silo(\"127.0.0.1:100@100\");\n            this.localSiloDetails.SiloAddress.Returns(this.localSilo);\n            this.localSiloDetails.DnsHostName.Returns(\"MyServer11\");\n            this.localSiloDetails.Name.Returns(Guid.NewGuid().ToString(\"N\"));\n\n            this.fatalErrorHandler = Substitute.For<IFatalErrorHandler>();\n            this.fatalErrorHandler.IsUnexpected(default).ReturnsForAnyArgs(true);\n            this.membershipGossiper = Substitute.For<IMembershipGossiper>();\n            this.lifecycle = new SiloLifecycleSubject(this.loggerFactory.CreateLogger<SiloLifecycleSubject>());\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior around silo startup for a fresh cluster.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_NewCluster()\n        {\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"));\n            await this.BasicScenarioTest(membershipTable, gracefulShutdown: true);\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior around silo startup when there is an\n        /// existing cluster.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_ExistingCluster()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.ShuttingDown, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Joining, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            await this.BasicScenarioTest(membershipTable, gracefulShutdown: false);\n        }\n\n        private async Task BasicScenarioTest(InMemoryMembershipTable membershipTable, bool gracefulShutdown = true)\n        {\n            var timers = new List<DelegateAsyncTimer>();\n            var timerCalls = new BlockingCollection<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n\n            var timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var timer = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            timerCalls.Add((overridePeriod, task));\n                            return task.Task;\n                        });\n                    timers.Add(timer);\n                    return timer;\n                });\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: timerFactory,\n                this.lifecycle);\n\n            // Validate that the initial snapshot is valid and contains the local silo.\n            var initialSnapshot = manager.MembershipTableSnapshot;\n            Assert.NotNull(initialSnapshot);\n            Assert.NotNull(initialSnapshot.Entries);\n            var localSiloEntry = initialSnapshot.Entries[this.localSilo];\n            Assert.Equal(SiloStatus.Created, localSiloEntry.Status);\n            Assert.Equal(this.localSiloDetails.Name, localSiloEntry.SiloName);\n            Assert.Equal(this.localSiloDetails.DnsHostName, localSiloEntry.HostName);\n            Assert.Equal(SiloStatus.Created, manager.CurrentStatus);\n\n            Assert.NotNull(manager.MembershipTableUpdates);\n            var changes = manager.MembershipTableUpdates;\n            var currentEnumerator = changes.GetAsyncEnumerator();\n            Assert.True(currentEnumerator.MoveNextAsync().Result);\n            Assert.Equal(currentEnumerator.Current.Version, manager.MembershipTableSnapshot.Version);\n            Assert.Empty(membershipTable.Calls);\n\n            // All of these checks were performed before any lifecycle methods have a chance to run.\n            // This is in order to verify that a service accessing membership in its constructor will\n            // see the correct results regardless of initialization order.\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n\n            await this.lifecycle.OnStart();\n\n            var calls = membershipTable.Calls;\n            Assert.NotEmpty(calls);\n            Assert.True(calls.Count >= 2);\n            Assert.Equal(nameof(IMembershipTable.InitializeMembershipTable), calls[0].Method);\n            Assert.Equal(nameof(IMembershipTable.ReadAll), calls[1].Method);\n\n            // During initialization, a first read from the table will be performed, transitioning\n            // membership to a valid version.currentEnumerator = changes.GetAsyncEnumerator();\n            currentEnumerator = changes.GetAsyncEnumerator();\n            Assert.True(currentEnumerator.MoveNextAsync().Result);\n            var update1 = currentEnumerator.Current;\n\n            // Transition to joining.\n            this.membershipGossiper.ClearReceivedCalls();\n            await manager.UpdateStatus(SiloStatus.Joining);\n            await this.membershipGossiper.ReceivedWithAnyArgs().GossipToRemoteSilos(default, default, default, default);\n            Assert.Equal(SiloStatus.Joining, manager.CurrentStatus);\n            localSiloEntry = manager.MembershipTableSnapshot.Entries[this.localSilo];\n            Assert.Equal(SiloStatus.Joining, localSiloEntry.Status);\n\n            // An update should have been issued.\n            currentEnumerator = changes.GetAsyncEnumerator();\n            Assert.True(currentEnumerator.MoveNextAsync().Result);\n            Assert.NotEqual(update1.Version, manager.MembershipTableSnapshot.Version);\n\n            var update2 = currentEnumerator.Current;\n            Assert.Equal(update2.Version, manager.MembershipTableSnapshot.Version);\n            var entry = Assert.Single(update2.Entries, e => e.Key.Equals(this.localSilo));\n            Assert.Equal(this.localSilo, entry.Key);\n            Assert.Equal(this.localSilo, entry.Value.SiloAddress);\n            Assert.Equal(SiloStatus.Joining, entry.Value.Status);\n\n            calls = membershipTable.Calls.Skip(2).ToList();\n            Assert.NotEmpty(calls);\n            Assert.Contains(calls, call => call.Method.Equals(nameof(IMembershipTable.InsertRow)));\n            Assert.Contains(calls, call => call.Method.Equals(nameof(IMembershipTable.ReadAll)));\n\n            {\n                // Check that a timer is being requested and that after it expires a call to\n                // refresh the membership table is made.\n                using var cts = new CancellationTokenSource();\n                cts.CancelAfter(TimeSpan.FromSeconds(10));\n                var (_, completion) = timerCalls.Take(cts.Token);\n                membershipTable.ClearCalls();\n                completion.TrySetResult(true);\n                while (membershipTable.Calls.Count == 0) await Task.Delay(10);\n                Assert.Contains(membershipTable.Calls, c => c.Method.Equals(nameof(IMembershipTable.ReadAll)));\n            }\n\n            var shutdownCts = new CancellationTokenSource();\n            if (!gracefulShutdown) shutdownCts.Cancel();\n            Assert.Equal(0, timers.First().DisposedCounter);\n            var stopped = this.lifecycle.OnStop(shutdownCts.Token);\n\n            // Complete any timers that were waiting.\n            while (timerCalls.TryTake(out var t))\n            {\n                t.Completion.TrySetResult(false);\n            }\n\n            await stopped;\n            Assert.Equal(1, timers.First().DisposedCounter);\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior around silo startup when there is an\n        /// existing cluster and this silo has been restarted (there is an existing entry with an\n        /// older generation).\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_Restarted()\n        {\n            var now = DateTimeOffset.UtcNow;\n\n            // The table includes a predecessor which is still marked as active\n            // This can happen if a node restarts quickly.\n            var predecessor = Entry(Silo(\"127.0.0.1:100@1\"), SiloStatus.Active, now);\n\n            var otherSilos = new[]\n            {\n                predecessor,\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.ShuttingDown, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Joining, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                this.lifecycle);\n\n            // Validate that the initial snapshot is valid and contains the local silo.\n            var snapshot = manager.MembershipTableSnapshot;\n            Assert.NotNull(snapshot);\n            Assert.NotNull(snapshot.Entries);\n            var localSiloEntry = snapshot.Entries[this.localSilo];\n            Assert.Equal(SiloStatus.Created, localSiloEntry.Status);\n            Assert.Equal(this.localSiloDetails.Name, localSiloEntry.SiloName);\n            Assert.Equal(this.localSiloDetails.DnsHostName, localSiloEntry.HostName);\n            Assert.Equal(SiloStatus.Created, manager.CurrentStatus);\n\n            Assert.NotNull(manager.MembershipTableUpdates);\n            var membershipUpdates = manager.MembershipTableUpdates.GetAsyncEnumerator();\n            Assert.True(await membershipUpdates.MoveNextAsync());\n            var firstSnapshot = membershipUpdates.Current;\n            Assert.Equal(firstSnapshot.Version, manager.MembershipTableSnapshot.Version);\n            Assert.Empty(membershipTable.Calls);\n\n            // All of these checks were performed before any lifecycle methods have a chance to run.\n            // This is in order to verify that a service accessing membership in its constructor will\n            // see the correct results regardless of initialization order.\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n\n            await this.lifecycle.OnStart();\n\n            var calls = membershipTable.Calls;\n            Assert.NotEmpty(calls);\n            Assert.True(calls.Count >= 2);\n            Assert.Equal(nameof(IMembershipTable.InitializeMembershipTable), calls[0].Method);\n            Assert.Contains(calls, call => call.Method.Equals(nameof(IMembershipTable.ReadAll)));\n            \n            // During initialization, a first read from the table will be performed, transitioning\n            // membership to a valid version.Assert.True(membershipUpdates.MoveNextAsync().Result);\n            Assert.True(await membershipUpdates.MoveNextAsync());\n            var update1 = membershipUpdates.Current;\n\n            // Transition to joining.\n            await manager.UpdateStatus(SiloStatus.Joining);\n            snapshot = manager.MembershipTableSnapshot;\n            Assert.Equal(SiloStatus.Joining, manager.CurrentStatus);\n            Assert.Equal(SiloStatus.Joining, snapshot.Entries[localSilo].Status);\n\n            Assert.True(await membershipUpdates.MoveNextAsync());\n            Assert.True(await membershipUpdates.MoveNextAsync());\n            Assert.Equal(membershipUpdates.Current.Version, manager.MembershipTableSnapshot.Version);\n\n            // The predecessor should have been marked dead during startup.\n            Assert.Equal(SiloStatus.Active, update1.GetSiloStatus(predecessor.SiloAddress));\n            var latest = membershipUpdates.Current;\n            Assert.Equal(SiloStatus.Dead, latest.GetSiloStatus(predecessor.SiloAddress));\n\n            var entry = Assert.Single(latest.Entries, e => e.Key.Equals(this.localSilo));\n            Assert.Equal(this.localSilo, entry.Key);\n            Assert.Equal(this.localSilo, entry.Value.SiloAddress);\n            Assert.Equal(SiloStatus.Joining, entry.Value.Status);\n\n            calls = membershipTable.Calls.Skip(2).ToList();\n            Assert.NotEmpty(calls);\n            Assert.Contains(calls, call => call.Method.Equals(nameof(IMembershipTable.InsertRow)));\n            Assert.Contains(calls, call => call.Method.Equals(nameof(IMembershipTable.ReadAll)));\n\n            await this.lifecycle.OnStop();\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior around silo startup when there is an\n        /// existing cluster and this silo has already been superseded by a newer iteration.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_Superseded()\n        {\n            var now = DateTimeOffset.UtcNow;\n\n            // The table includes a successor to this silo.\n            var successor = Entry(Silo(\"127.0.0.1:100@200\"), SiloStatus.Active, now);\n\n            var otherSilos = new[]\n            {\n                successor,\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.ShuttingDown, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Joining, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                this.lifecycle);\n\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n\n            await this.lifecycle.OnStart();\n\n            // Silo should kill itself during the joining phase\n            await manager.UpdateStatus(SiloStatus.Joining);\n\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n\n            await this.lifecycle.OnStop();\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior around silo startup when there is an\n        /// existing cluster and this silo has already been declared dead.\n        /// Note that this should never happen in the way tested here - the silo should not be known\n        /// to other silos before it starts up. Still, the case is covered by the manager.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_AlreadyDeclaredDead()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(this.localSilo, SiloStatus.Dead, now),\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.ShuttingDown, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Joining, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                this.lifecycle);\n\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n\n            await this.lifecycle.OnStart();\n\n            // Silo should kill itself during the joining phase\n            await manager.UpdateStatus(SiloStatus.Joining);\n\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n\n            var cts = new CancellationTokenSource();\n            cts.Cancel();\n            await this.lifecycle.OnStop(cts.Token);\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> behavior when there is an\n        /// existing cluster and this silo is declared dead some time after updating its status to joining.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_DeclaredDead_AfterJoining()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now)\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n\n            // Silo should kill itself during the joining phase\n            await manager.UpdateStatus(SiloStatus.Joining);\n\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n\n            // Mark the silo as dead\n            while (true)\n            {\n                var table = await membershipTable.ReadAll();\n                var row = table.Members.Single(e => e.Item1.SiloAddress.Equals(this.localSilo));\n                var entry = row.Item1.WithStatus(SiloStatus.Dead);\n                if (await membershipTable.UpdateRow(entry, row.Item2, table.Version.Next())) break;\n            }\n\n            // Refresh silo status and check that it determines it's dead.\n            await manager.Refresh();\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n\n            await this.lifecycle.OnStop();\n        }\n\n        /// <summary>\n        /// Try to suspect another silo of failing but discover that this silo has failed.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_TrySuspectOrKill_ButIAmKill()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            await manager.UpdateStatus(SiloStatus.Active);\n\n            // Mark the silo as dead\n            while (true)\n            {\n                var table = await membershipTable.ReadAll();\n                var row = table.Members.Single(e => e.Item1.SiloAddress.Equals(this.localSilo));\n                var entry = row.Item1.WithStatus(SiloStatus.Dead);\n                if (await membershipTable.UpdateRow(entry, row.Item2, table.Version.Next())) break;\n            }\n\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n            await manager.TryToSuspectOrKill(otherSilos.First().SiloAddress);\n            manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n        }\n\n        /// <summary>\n        /// Try to suspect another silo of failing but discover that it is already dead.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_TrySuspectOrKill_AlreadyDead()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            await manager.UpdateStatus(SiloStatus.Active);\n\n            var victim = otherSilos.Last().SiloAddress;\n            await manager.TryToSuspectOrKill(victim);\n            Assert.Equal(SiloStatus.Dead, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n        }\n\n        /// <summary>\n        /// Declare a silo dead in a small, 2-silo cluster, requiring one vote ((2 + 1) / 2 = 1).\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_TrySuspectOrKill_DeclareDead_SmallCluster()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            await manager.UpdateStatus(SiloStatus.Active);\n\n            var victim = otherSilos.First().SiloAddress;\n            await manager.TryToSuspectOrKill(victim);\n            manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            Assert.Equal(SiloStatus.Dead, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n        }\n\n        /// <summary>\n        /// Declare a silo dead in a larger cluster, requiring 2 votes (per configuration), but where our clock is several minutes out of sync with others in the cluster.\n        /// The purpose is to check that logic is consistent across a cluster even if clocks are wildly out of sync.\n        /// This is especially relevant when it comes to vote counting.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_TrySuspectOrKill_ClocksNotSynchronized()\n        {\n            var now = DateTime.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:600@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:700@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:800@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:900@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var clusterMembershipOptions = new ClusterMembershipOptions();\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(clusterMembershipOptions),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n\n            // Rig the local clock.\n            manager.GetDateTimeUtcNow = () => now;\n\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            await manager.UpdateStatus(SiloStatus.Active);\n\n            // Add some suspect times. The time difference between them is larger than the recency window (DeathVoteExpirationTimeout),\n            // so only one of the votes will be considered fresh, even though both will be in the future from the perspective\n            // of the local silo.\n            var victim = otherSilos.First().SiloAddress;\n            while (true)\n            {\n                var table = await membershipTable.ReadAll();\n                var row = table.Members.Single(e => e.Item1.SiloAddress.Equals(victim));\n                var entry = row.Item1.Copy();\n                entry.SuspectTimes?.Clear();\n\n                // Twice the recency window into the future (from the local silo's perspective). This will be the benchmark against which\n                // other votes are compared.\n                // If the logic for counting fresh votes is faulty, this plus the vote below should have resulted in an eviction, and\n                // therefore the local silo will crash, declaring that there is a bug.\n                entry.AddSuspector(otherSilos[2].SiloAddress, now.Add(clusterMembershipOptions.DeathVoteExpirationTimeout.Multiply(2)));\n\n                // Half the recency window into the past (from the local silo's perspective) and therefore within the recency window from\n                // the local silo's perspective.\n                // If the logic for counting fresh votes is faulty, this plus the local silo's vote should be enough to evict the victim.\n                entry.AddSuspector(otherSilos[4].SiloAddress, now.Subtract(clusterMembershipOptions.DeathVoteExpirationTimeout.Divide(2)));\n                if (await membershipTable.UpdateRow(entry, row.Item2, table.Version.Next())) break;\n            }\n\n            // Check that:\n            //   a) Adding our vote changes nothing, since our clock is too far behind\n            //   b) The silo is not mistakenly declared dead, since the difference between the two votes is larger than DeathVoteExpirationTimeout.\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n            await manager.TryToSuspectOrKill(victim);\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n\n            // The victim should be alive as no second vote fell within the recency window of the latest vote.\n            await manager.Refresh();\n            Assert.Equal(SiloStatus.Active, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n        }\n\n        /// <summary>\n        /// Declare a silo dead in a larger cluster, requiring 2 votes (per configuration).\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_TrySuspectOrKill_DeclareDead_LargerCluster()\n        {\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:300@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:400@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:500@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:600@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:700@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:800@100\"), SiloStatus.Active, now),\n                Entry(Silo(\"127.0.0.1:900@100\"), SiloStatus.Dead, now),\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(this.loggerFactory),\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            await manager.UpdateStatus(SiloStatus.Active);\n\n            // Multiple votes from the same node should not result in the node being declared dead.\n            var victim = otherSilos.First().SiloAddress;\n            await manager.TryToSuspectOrKill(victim);\n            await manager.TryToSuspectOrKill(victim);\n            await manager.TryToSuspectOrKill(victim);\n            manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            Assert.Equal(SiloStatus.Active, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n\n            // Manually remove our vote and add another silo's vote so we can be the one to kill the silo.\n            while (true)\n            {\n                var table = await membershipTable.ReadAll();\n                var row = table.Members.Single(e => e.Item1.SiloAddress.Equals(victim));\n                var entry = row.Item1.Copy();\n                entry.SuspectTimes?.Clear();\n                entry.AddSuspector(otherSilos[2].SiloAddress, DateTime.UtcNow);\n                if (await membershipTable.UpdateRow(entry, row.Item2, table.Version.Next())) break;\n            }\n\n            await manager.TryToSuspectOrKill(victim);\n            manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            Assert.Equal(SiloStatus.Dead, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n\n            // One down, one to go. Now overshoot votes and kill ourselves instead (due to internal error).\n            victim = otherSilos[1].SiloAddress;\n            while (true)\n            {\n                var table = await membershipTable.ReadAll();\n                var row = table.Members.Single(e => e.Item1.SiloAddress.Equals(victim));\n                var entry = row.Item1.Copy();\n                entry.SuspectTimes?.Clear();\n                entry.AddSuspector(otherSilos[2].SiloAddress, DateTime.UtcNow);\n                entry.AddSuspector(otherSilos[3].SiloAddress, DateTime.UtcNow);\n                entry.AddSuspector(otherSilos[4].SiloAddress, DateTime.UtcNow);\n                if (await membershipTable.UpdateRow(entry, row.Item2, table.Version.Next())) break;\n            }\n\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n            await manager.TryToSuspectOrKill(victim);\n            manager.TestingSuspectOrKillIdle.WaitOne(TimeSpan.FromSeconds(45));\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n\n            // We killed ourselves and should not have marked the other silo as dead.\n            await manager.Refresh();\n            Assert.Equal(SiloStatus.Active, manager.MembershipTableSnapshot.GetSiloStatus(victim));\n        }\n\n        /// <summary>\n        /// Tests <see cref=\"MembershipTableManager\"/> table refresh behavior.\n        /// </summary>\n        [Fact]\n        public async Task MembershipTableManager_Refresh()\n        {\n            var timers = new List<DelegateAsyncTimer>();\n            var timerCalls = new ConcurrentQueue<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n            var timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            timerCalls.Enqueue((overridePeriod, task));\n                            return task.Task;\n                        });\n                    timers.Add(t);\n                    return t;\n                });\n\n            var now = DateTimeOffset.UtcNow;\n            var otherSilos = new[]\n            {\n                Entry(Silo(\"127.0.0.1:200@100\"), SiloStatus.Active, now)\n            };\n            var membershipTable = new InMemoryMembershipTable(new TableVersion(123, \"123\"), otherSilos);\n\n            var manager = new MembershipTableManager(\n                localSiloDetails: this.localSiloDetails,\n                clusterMembershipOptions: Options.Create(new ClusterMembershipOptions()),\n                membershipTable: membershipTable,\n                fatalErrorHandler: this.fatalErrorHandler,\n                gossiper: this.membershipGossiper,\n                log: this.loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: timerFactory,\n                siloLifecycle: this.lifecycle);\n            ((ILifecycleParticipant<ISiloLifecycle>)manager).Participate(this.lifecycle);\n            await this.lifecycle.OnStart();\n            \n            // Test that retries occur after an exception.\n            (TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion) timer = (default, default);\n            while (!timerCalls.TryDequeue(out timer)) await Task.Delay(1);\n            var counter = 0;\n            membershipTable.OnReadAll = () => { if (counter++ == 0) throw new Exception(\"no\"); };\n            timer.Completion.TrySetResult(true);\n            this.fatalErrorHandler.DidNotReceiveWithAnyArgs().OnFatalException(default, default, default);\n\n            // A shorter delay should be provided after a transient failure.\n            while (!timerCalls.TryDequeue(out timer)) await Task.Delay(10);\n            membershipTable.OnReadAll = null;\n            Assert.True(timer.DelayOverride.HasValue);\n            timer.Completion.TrySetResult(true);\n\n            // The standard delay should be used thereafter.\n            while (!timerCalls.TryDequeue(out timer)) await Task.Delay(10);\n            Assert.False(timer.DelayOverride.HasValue);\n            timer.Completion.TrySetResult(true);\n\n            // If for some reason the timer itself fails (or something else), the silo should crash\n            while (!timerCalls.TryDequeue(out timer)) await Task.Delay(10);\n            timer.Completion.TrySetException(new Exception(\"no again\"));\n            this.fatalErrorHandler.ReceivedWithAnyArgs().OnFatalException(default, default, default);\n            Assert.False(timerCalls.TryDequeue(out timer));\n            await this.lifecycle.OnStop();\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static MembershipEntry Entry(SiloAddress address, SiloStatus status, DateTimeOffset iAmAliveTime)\n        {\n            return new MembershipEntry { SiloAddress = address, Status = status, IAmAliveTime =  iAmAliveTime.UtcDateTime, StartTime = iAmAliveTime.UtcDateTime };\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/MembershipTableSnapshotTests.cs",
    "content": "using AwesomeAssertions.Common;\nusing Orleans;\nusing Orleans.Runtime;\nusing Xunit;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for membership table snapshot functionality including silo status retrieval and IAmAliveTime preservation.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class MembershipTableSnapshotTests\n    {\n        [Fact]\n        public void MembershipTableSnapshot_GetSiloStatus_JoiningSilo()\n        {\n            var silo = Silo(\"127.0.0.1:100@1\");\n\n            // The table is empty\n            var localSiloEntry = Entry(silo, SiloStatus.Joining);\n            var snapshot = AddOrUpdateEntry(MembershipTableSnapshot.Create(Table()), localSiloEntry);\n\n            Assert.Equal(localSiloEntry.Status, snapshot.GetSiloStatus(silo));\n            Assert.Equal(silo, snapshot.Entries[silo].SiloAddress);\n            Assert.Equal(localSiloEntry.Status, snapshot.Entries[silo].Status);\n            Assert.Contains(snapshot.Entries, e => e.Key.Equals(silo) && e.Value.Status == localSiloEntry.Status);\n        }\n\n        [Fact]\n        public void MembershipTableSnapshot_GetSiloStatus_StoppingSilo()\n        {\n            var silo = Silo(\"127.0.0.1:100@1\");\n\n            // Check that the Silo status in the entry directly provided to the\n            // constructor overrides the value in the table.\n            var localSiloEntry = Entry(silo, SiloStatus.Stopping);\n            var snapshot = AddOrUpdateEntry(MembershipTableSnapshot.Create(\n                Table(\n                    Entry(silo, SiloStatus.Active),\n                    Entry(Silo(\"127.0.0.1:200@1\"), SiloStatus.Active))),\n                localSiloEntry);\n            \n            Assert.Equal(localSiloEntry.Status, snapshot.GetSiloStatus(silo));\n            Assert.Equal(silo, snapshot.Entries[silo].SiloAddress);\n            Assert.Equal(localSiloEntry.Status, snapshot.Entries[silo].Status);\n            Assert.Contains(snapshot.Entries, e => e.Key.Equals(silo) && e.Value.Status == localSiloEntry.Status);\n        }\n\n        [Fact]\n        public void MembershipTableSnapshot_GetSiloStatus_UnknownSilo()\n        {\n            var knownSilo = Silo(\"127.0.0.1:100@1\");\n            var unknownSilo = Silo(\"127.0.0.1:101@1\");\n\n            var knownSiloEntry = Entry(knownSilo, SiloStatus.Active);\n            var snapshot = AddOrUpdateEntry(MembershipTableSnapshot.Create(Table(knownSiloEntry)), knownSiloEntry);\n\n            Assert.Equal(SiloStatus.None, snapshot.GetSiloStatus(unknownSilo));\n        }\n\n        [Fact]\n        public void MembershipTableSnapshot_CreateUpdatePreservesIAmAliveTime()\n        {\n            var originalSilo = Silo(\"127.0.0.1:100@1\");\n            var earlierDate = new DateTimeOffset(new DateTime(2025, 1, 30, 12, 30, 45, DateTimeKind.Utc));\n            var laterDate = earlierDate.AddDays(1);\n\n            // Merging a later snapshot with an earlier date with an older snapshot with a later date should preserve the later date.\n            {\n                var originalSnapshot = MembershipTableSnapshot.Create(Table(Entry(originalSilo, SiloStatus.Active, laterDate)));\n                var newSnapshot = MembershipTableSnapshot.Update(originalSnapshot, Table(Entry(originalSilo, SiloStatus.Active, earlierDate)));\n\n                var iAmAliveTime = newSnapshot.Entries[originalSilo].IAmAliveTime;\n                Assert.Equal(laterDate, iAmAliveTime);\n            }\n\n            // Now do the same thing, but using a snapshot instead of a table\n            {\n                var originalSnapshot = MembershipTableSnapshot.Create(Table(Entry(originalSilo, SiloStatus.Active, laterDate)));\n                var newSnapshot = MembershipTableSnapshot.Update(originalSnapshot, MembershipTableSnapshot.Create(Table(Entry(originalSilo, SiloStatus.Active, earlierDate))));\n\n                var iAmAliveTime = newSnapshot.Entries[originalSilo].IAmAliveTime;\n                Assert.Equal(laterDate, iAmAliveTime);\n            }\n        }\n\n        [Fact]\n        public void MembershipTableSnapshot_GetSiloStatus_UnknownSilo_KnownSuccessor()\n        {\n            var unknownSilo = Silo(\"127.0.0.1:100@1\");\n            var knownSuccessor = Silo(\"127.0.0.1:100@2\");\n\n            var knownSiloEntry = Entry(knownSuccessor, SiloStatus.Active);\n            var snapshot = AddOrUpdateEntry(MembershipTableSnapshot.Create(Table(knownSiloEntry)), knownSiloEntry);\n\n            Assert.Equal(SiloStatus.Dead, snapshot.GetSiloStatus(unknownSilo));\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static MembershipEntry Entry(SiloAddress address, SiloStatus status, DateTimeOffset iAmAliveTime = default)\n        {\n            return new MembershipEntry { SiloAddress = address, Status = status, IAmAliveTime = iAmAliveTime.UtcDateTime };\n        }\n\n        private static MembershipTableData Table(params MembershipEntry[] entries)\n        {\n            var entryList = entries.Select(e => Tuple.Create(e, \"test\")).ToList();\n            return new MembershipTableData(entryList, new TableVersion(12, \"test\"));\n        }\n\n        private static MembershipTableSnapshot AddOrUpdateEntry(MembershipTableSnapshot table, MembershipEntry localSiloEntry)\n        {\n            if (table is null) throw new ArgumentNullException(nameof(table));\n\n            var entries = table.Entries.ToBuilder();\n\n            if (entries.TryGetValue(localSiloEntry.SiloAddress, out var existing))\n            {\n                entries[localSiloEntry.SiloAddress] = existing.WithStatus(localSiloEntry.Status);\n            }\n            else\n            {\n                entries[localSiloEntry.SiloAddress] = localSiloEntry;\n            }\n\n            return new MembershipTableSnapshot(table.Version, entries.ToImmutable());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Membership/SiloHealthMonitorTests.cs",
    "content": "using System.Threading.Channels;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NonSilo.Tests.Utilities;\nusing NSubstitute;\nusing NSubstitute.ExceptionExtensions;\nusing Orleans.Configuration;\nusing Orleans.Runtime.MembershipService;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Orleans.Runtime.MembershipService.SiloHealthMonitor;\n\nnamespace NonSilo.Tests.Membership\n{\n    /// <summary>\n    /// Tests for silo health monitoring including direct/indirect probing, failure detection, and stale silo handling.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Membership\")]\n    public class SiloHealthMonitorTests\n    {\n        private readonly ITestOutputHelper _output;\n        private readonly LoggerFactory _loggerFactory;\n        private readonly ILocalSiloDetails _localSiloDetails;\n        private readonly SiloAddress _localSilo;\n        private readonly List<DelegateAsyncTimer> _timers;\n        private readonly Channel<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)> _timerCalls;\n        private readonly DelegateAsyncTimerFactory _timerFactory;\n        private readonly ILocalSiloHealthMonitor _localSiloHealthMonitor;\n        private readonly IRemoteSiloProber _prober;\n        private readonly MembershipTableManager _membershipService;\n        private readonly ClusterMembershipOptions _clusterMembershipOptions;\n        private readonly IOptionsMonitor<ClusterMembershipOptions> _optionsMonitor;\n        private readonly Channel<ProbeResult> _probeResults;\n        private readonly SiloHealthMonitor _monitor;\n        private readonly SiloAddress _targetSilo;\n        private readonly InMemoryMembershipTable _membershipTable;\n\n        public SiloHealthMonitorTests(ITestOutputHelper output)\n        {\n            _output = output;\n            _loggerFactory = new LoggerFactory(new[] { new XunitLoggerProvider(_output) });\n\n            _localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            _localSilo = Silo(\"127.0.0.1:100@100\");\n            _localSiloDetails.SiloAddress.Returns(_localSilo);\n            _localSiloDetails.DnsHostName.Returns(\"MyServer11\");\n            _localSiloDetails.Name.Returns(Guid.NewGuid().ToString(\"N\"));\n\n            _timers = new List<DelegateAsyncTimer>();\n            _timerCalls = Channel.CreateUnbounded<(TimeSpan? DelayOverride, TaskCompletionSource<bool> Completion)>();\n            _timerFactory = new DelegateAsyncTimerFactory(\n                (period, name) =>\n                {\n                    var t = new DelegateAsyncTimer(\n                        overridePeriod =>\n                        {\n                            var task = new TaskCompletionSource<bool>();\n                            _timerCalls.Writer.TryWrite((overridePeriod, task));\n                            return task.Task;\n                        });\n                    _timers.Add(t);\n                    return t;\n                });\n\n            _localSiloHealthMonitor = Substitute.For<ILocalSiloHealthMonitor>();\n            _localSiloHealthMonitor.GetLocalHealthDegradationScore(default).ReturnsForAnyArgs(0);\n\n            _prober = Substitute.For<IRemoteSiloProber>();\n\n            _clusterMembershipOptions = new ClusterMembershipOptions();\n            _optionsMonitor = Substitute.For<IOptionsMonitor<ClusterMembershipOptions>>();\n            _optionsMonitor.CurrentValue.ReturnsForAnyArgs(info => _clusterMembershipOptions);\n\n            var fatalErrorHandler = Substitute.For<IFatalErrorHandler>();\n            var membershipGossiper = Substitute.For<IMembershipGossiper>();\n            var lifecycle = new SiloLifecycleSubject(_loggerFactory.CreateLogger<SiloLifecycleSubject>());\n\n            _targetSilo = Silo(\"127.0.0.200:100@100\");\n            _membershipTable = new(new TableVersion(0, \"0\"), Entry(_localSilo, SiloStatus.Active), Entry(_targetSilo, SiloStatus.Active));\n            _membershipService = new MembershipTableManager(\n                localSiloDetails: _localSiloDetails,\n                clusterMembershipOptions: Options.Create(_clusterMembershipOptions),\n                membershipTable: _membershipTable,\n                fatalErrorHandler: fatalErrorHandler,\n                gossiper: membershipGossiper,\n                log: _loggerFactory.CreateLogger<MembershipTableManager>(),\n                timerFactory: new AsyncTimerFactory(_loggerFactory),\n                lifecycle);\n\n            _probeResults = Channel.CreateBounded<ProbeResult>(new BoundedChannelOptions(1) { FullMode = BoundedChannelFullMode.Wait });\n            Task onProbeResult(SiloHealthMonitor mon, ProbeResult res) => _probeResults.Writer.WriteAsync(res).AsTask();\n\n            _monitor = new SiloHealthMonitor(\n                _targetSilo,\n                onProbeResult,\n                _optionsMonitor,\n                _loggerFactory,\n                _prober,\n                _timerFactory,\n                _localSiloHealthMonitor,\n                _membershipService,\n                _localSiloDetails);\n        }\n\n        private async Task Shutdown()\n        {\n            var stopTask = _monitor.StopAsync(CancellationToken.None);\n\n            Task.Run(async () =>\n            {\n                while (!stopTask.IsCompleted && await _timerCalls.Reader.WaitToReadAsync())\n                {\n                    while (_timerCalls.Reader.TryRead(out var timerCall))\n                    {\n                        timerCall.Completion.TrySetResult(false);\n                    }\n                }\n            }).Ignore();\n\n            await stopTask;\n            _timerCalls.Writer.TryComplete();\n        }\n\n        [Fact]\n        public async Task SiloHealthMonitor_SuccessfulProbe()\n        {\n            _prober.Probe(default, default).ReturnsForAnyArgs(Task.CompletedTask);\n            _prober.ProbeIndirectly(default, default, default, default).ThrowsAsyncForAnyArgs(new InvalidOperationException(\"No\"));\n\n            _monitor.Start();\n\n            // Let a timer complete\n            var timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            // Check the resulting probe result.\n            var probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Succeeded, probeResult.Status);\n            Assert.Equal(0, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            await Shutdown();\n        }\n\n        [Fact]\n        public async Task SiloHealthMonitor_FailedProbe_Timeout()\n        {\n            _clusterMembershipOptions.ProbeTimeout = TimeSpan.FromSeconds(2);\n\n            _prober.Probe(default, default, default).ReturnsForAnyArgs(info => Task.Delay(TimeSpan.FromSeconds(30)));\n            _prober.ProbeIndirectly(default, default, default, default).ThrowsAsyncForAnyArgs(new InvalidOperationException(\"No\"));\n            _monitor.Start();\n\n            // Let a timer complete\n            var timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            var probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(1, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            await Shutdown();\n        }\n\n        [Fact]\n        public async Task SiloHealthMonitor_FailedProbe_Exception()\n        {\n            _clusterMembershipOptions.ProbeTimeout = TimeSpan.FromSeconds(2);\n\n            _prober.Probe(default, default).ThrowsAsyncForAnyArgs(new Exception(\"nope\"));\n            _prober.ProbeIndirectly(default, default, default, default).ThrowsAsyncForAnyArgs(new InvalidOperationException(\"No\"));\n            _monitor.Start();\n\n            // Let a timer complete\n            var timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            // Throw directly, instead of timing out the probe\n            _prober.WhenForAnyArgs(s => s.Probe(default, default)).Throw(new Exception(\"nope\"));\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            var probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(1, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            await Shutdown();\n        }\n\n        [Fact]\n        public async Task SiloHealthMonitor_Indirect_FailedProbe()\n        {\n            _clusterMembershipOptions.ProbeTimeout = TimeSpan.FromSeconds(2);\n            _clusterMembershipOptions.EnableIndirectProbes = true;\n\n            _prober.Probe(default, default).ThrowsAsyncForAnyArgs(info => new Exception(\"nonono!\"));\n            _prober.ProbeIndirectly(default, default, default, default).ReturnsForAnyArgs(new IndirectProbeResponse\n            {\n                FailureMessage = \"fail\",\n                IntermediaryHealthScore = 0,\n                ProbeResponseTime = TimeSpan.FromSeconds(1),\n                Succeeded = false\n            });\n            _monitor.Start();\n\n            // Let a timer complete\n            var timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            var probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(1, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            var otherSilo = Silo(\"127.0.0.1:1234@1234\");\n            await _membershipTable.InsertRow(Entry(_monitor.TargetSiloAddress, SiloStatus.Active), _membershipTable.Version.Next());\n            await _membershipTable.InsertRow(Entry(otherSilo, SiloStatus.Joining), _membershipTable.Version.Next());\n            await _membershipService.Refresh();\n\n            // There is only one other active silo (the target silo), so an indirect probe cannot be performed.\n            probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(2, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            // Make the other silo active so that there is an intermediary to use for an indirect probe.\n            var etag = (await _membershipTable.ReadAll()).Members.Where(kv => kv.Item1.SiloAddress.Equals(otherSilo)).Single().Item2;\n            await _membershipTable.UpdateRow(Entry(otherSilo, SiloStatus.Active, iAmAliveTime: DateTime.UtcNow), etag, _membershipTable.Version.Next());\n            await _membershipService.Refresh();\n\n            _prober.ClearReceivedCalls();\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            // Since there is another active silo, an indirect probe will be performed.\n            probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(3, probeResult.FailedProbeCount);\n            Assert.False(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            // Ensure that the correct intermediary was selected.\n            var probeCall = _prober.ReceivedCalls().Single();\n            var args = probeCall.GetArguments();\n            var intermediary = Assert.IsType<SiloAddress>(args[0]);\n            Assert.Equal(otherSilo, intermediary);\n\n            // Ensure that negative results from unhealthy intermediaries are not considered.\n            _prober.ProbeIndirectly(default, default, default, default).ReturnsForAnyArgs(new IndirectProbeResponse\n            {\n                FailureMessage = \"fail\",\n                IntermediaryHealthScore = 1,\n                ProbeResponseTime = TimeSpan.FromSeconds(1),\n                Succeeded = false\n            });\n\n            _prober.ClearReceivedCalls();\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            // The number of failed probes should not be incremented, the status should be \"unknown\", and the health score should be 1.\n            probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Unknown, probeResult.Status);\n            Assert.Equal(3, probeResult.FailedProbeCount);\n            Assert.False(probeResult.IsDirectProbe);\n            Assert.Equal(1, probeResult.IntermediaryHealthDegradationScore);\n\n            // Ensure that the correct intermediary was selected.\n            probeCall = _prober.ReceivedCalls().Single();\n            args = probeCall.GetArguments();\n            intermediary = Assert.IsType<SiloAddress>(args[0]);\n            Assert.Equal(otherSilo, intermediary);\n\n            // After seeing that the chosen intermediary is unhealthy, a subsequent probe should be\n            // performed directly (since there are no other silos to use as an intermediary).\n            _prober.ClearReceivedCalls();\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n\n            probeResult = await _probeResults.Reader.ReadAsync();\n            Assert.Equal(ProbeResultStatus.Failed, probeResult.Status);\n            Assert.Equal(4, probeResult.FailedProbeCount);\n            Assert.True(probeResult.IsDirectProbe);\n            Assert.Equal(0, probeResult.IntermediaryHealthDegradationScore);\n\n            // Ensure that it was the target that was probed directly.\n            probeCall = _prober.ReceivedCalls().Single();\n            args = probeCall.GetArguments();\n            var target = Assert.IsType<SiloAddress>(args[0]);\n            Assert.Equal(_monitor.TargetSiloAddress, target);\n\n            await Shutdown();\n        }\n\n        [Fact]\n        public async Task SiloHealthMonitor_IndirectProbe_SkipsStaleSilo()\n        {\n            _clusterMembershipOptions.EnableIndirectProbes = true;\n            _clusterMembershipOptions.ProbeTimeout = TimeSpan.FromSeconds(2);\n\n            // Make direct probes fail.\n            _prober.Probe(default, default).ThrowsAsyncForAnyArgs(new Exception(\"Direct probe failing.\"));\n\n            // Start the monitor and trigger one timer cycle for a direct-probe attempt (which fails).\n            _monitor.Start();\n            var timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n            var firstProbeResult = await _probeResults.Reader.ReadAsync();\n            Assert.True(firstProbeResult.IsDirectProbe);\n            Assert.Equal(ProbeResultStatus.Failed, firstProbeResult.Status);\n\n            // Now add a 'stale' silo and a 'fresh' silo (both Active).\n            // This occurs after the first failed direct probe, matching the approach used in the test above.\n            var staleSilo = Silo(\"127.0.0.1:3333@3333\");\n            await _membershipTable.InsertRow(\n                Entry(staleSilo, SiloStatus.Active, DateTime.UtcNow - TimeSpan.FromMinutes(30)),\n                _membershipTable.Version.Next());\n            _prober.ClearReceivedCalls();\n\n            // Trigger another timer cycle which will now attempt an indirect probe.\n            timerCall = await _timerCalls.Reader.ReadAsync();\n            timerCall.Completion.TrySetResult(true);\n            var probeResult = await _probeResults.Reader.ReadAsync();\n\n            // Verify that this time the probe is direct since it skipped the stale intermediary silos.\n            Assert.True(probeResult.IsDirectProbe);\n            var call = _prober.ReceivedCalls().LastOrDefault();\n            var args = call?.GetArguments();\n            var probedSilo = Assert.IsType<SiloAddress>(args?[0]);\n            Assert.Equal(_targetSilo, probedSilo);\n            Assert.Equal(_targetSilo, _monitor.TargetSiloAddress);\n\n            await Shutdown();\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n\n        private static MembershipEntry Entry(SiloAddress address, SiloStatus status, DateTimeOffset iAmAliveTime = default) => new()\n        {\n            SiloAddress = address,\n            Status = status,\n            StartTime = iAmAliveTime.UtcDateTime,\n            IAmAliveTime = iAmAliveTime.UtcDateTime\n        };\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ObserverManagerTests.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Utilities;\nusing Xunit;\n\nnamespace NonSilo.Tests;\n\n[TestCategory(\"BVT\")]\npublic sealed class ObserverManagerTests\n{\n    [Fact]\n    public async Task CollectionModified()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Using predicate for an easier simulation of inserting item while enumerating.\n        bool Predicate(int observer)\n        {\n            if (observer == 5)\n            {\n                observerManager.Subscribe(11, 1);\n            }\n\n            return true;\n        }\n\n        Task NotificationAsync(int observer) => Task.CompletedTask;\n\n        var ex = await Record.ExceptionAsync(() => observerManager.Notify(NotificationAsync, Predicate));\n\n        Assert.Null(ex);\n    }\n\n    [Fact]\n    public async Task SubscribeDuringNotify_ObserversAreUpdatedImmediately()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new List<int>();\n        var newlyAddedObserverNotified = false;\n\n        // Subscribe some initial observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        async Task NotificationAsync(int observer)\n        {\n            notifiedObservers.Add(observer);\n\n            // Add a new observer during notification of the first observer.\n            if (observer == 0)\n            {\n                observerManager.Subscribe(100, 100);\n\n                // Verify that the newly added observer is immediately visible in the collection.\n                Assert.Contains(100, observerManager.Observers.Values);\n            }\n\n            // Check if we're processing the newly added observer.\n            if (observer == 100)\n            {\n                newlyAddedObserverNotified = true;\n            }\n\n            await Task.CompletedTask;\n        }\n\n        await observerManager.Notify(NotificationAsync);\n\n        // Only the original observers should have been notified, not the one added during notification.\n        Assert.Equal(5, notifiedObservers.Count);\n\n        // The newly added observer was not notified.\n        Assert.DoesNotContain(100, notifiedObservers);\n        Assert.False(newlyAddedObserverNotified);\n    }\n\n    [Fact]\n    public async Task UnsubscribeDuringNotify_ObserversAreUpdatedImmediately()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new List<int>();\n        var unsubscribedObserverNotified = false;\n\n        // Subscribe some initial observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        async Task NotificationAsync(int observer)\n        {\n            notifiedObservers.Add(observer);\n\n            // Unsubscribe an observer during notification of the first observer.\n            if (observer == 0)\n            {\n                observerManager.Unsubscribe(3);\n\n                // Verify that the unsubscribed observer is immediately removed from the collection.\n                Assert.DoesNotContain(3, observerManager.Observers.Values);\n            }\n\n            // Check if we're processing the unsubscribed observer.\n            if (observer == 3)\n            {\n                unsubscribedObserverNotified = true;\n            }\n\n            await Task.CompletedTask;\n        }\n\n        await observerManager.Notify(NotificationAsync);\n\n        // Even though we unsubscribed during iteration, the snapshot still contains the original observers.\n        // All original observers were notified due to snapshot.\n        Assert.Equal(5, notifiedObservers.Count);\n        // Observer 3 was notified because it was in the snapshot.\n        Assert.True(unsubscribedObserverNotified);\n        // But it's no longer in the collection after notification completed.\n        Assert.Equal(4, observerManager.Count);\n    }\n\n    [Fact]\n    public void SyncNotify_SubscribeAndUnsubscribe_WorksCorrectly()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new List<int>();\n\n        // Subscribe some initial observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        void Notification(int observer)\n        {\n            notifiedObservers.Add(observer);\n\n            // Add new observers and remove existing ones during notification.\n            if (observer == 0)\n            {\n                observerManager.Subscribe(100, 100);\n                observerManager.Unsubscribe(3);\n            }\n        }\n\n        observerManager.Notify(Notification);\n\n        // All original observers were notified.\n        Assert.Equal(5, notifiedObservers.Count);\n        // Observer 3 was notified because it was in the snapshot.\n        Assert.Contains(3, notifiedObservers);\n        // New observer wasn't in the original snapshot.\n        Assert.DoesNotContain(100, notifiedObservers);\n        // 5 original - 1 removed + 1 added = 5 total.\n        Assert.Equal(5, observerManager.Count);\n    }\n\n    [Fact]\n    public async Task ExceptionInNotificationCallback_RemovesObserver()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe some observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        async Task NotificationAsync(int observer)\n        {\n            // Throw exception for specific observer.\n            if (observer == 2)\n            {\n                throw new InvalidOperationException(\"Test exception\");\n            }\n\n            await Task.CompletedTask;\n        }\n\n        await observerManager.Notify(NotificationAsync);\n\n        // One observer should be removed.\n        Assert.Equal(4, observerManager.Count);\n        // Observer 2 should be removed due to exception.\n        Assert.DoesNotContain(2, observerManager.Observers.Values);\n    }\n\n    [Fact]\n    public void SyncNotify_ExceptionInNotificationCallback_RemovesObserver()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe some observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        void Notification(int observer)\n        {\n            // Throw exception for specific observer.\n            if (observer == 2)\n            {\n                throw new InvalidOperationException(\"Test exception\");\n            }\n        }\n\n        observerManager.Notify(Notification);\n\n        // One observer should be removed.\n        Assert.Equal(4, observerManager.Count);\n        // Observer 2 should be removed due to exception.\n        Assert.DoesNotContain(2, observerManager.Observers.Values);\n    }\n\n    [Fact]\n    public async Task ExpiredObservers_AreRemovedDuringNotify()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromMinutes(30), NullLogger.Instance);\n        var currentTime = DateTime.UtcNow;\n        var notifiedObservers = new List<int>();\n\n        // Mock GetDateTime to control time.\n        observerManager.GetDateTime = () => currentTime;\n\n        // Subscribe some observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Move some observers into the past to make them expire.\n        // Advance time by 1 hour.\n        currentTime = DateTime.UtcNow.AddHours(1);\n\n        // Notification function that tracks which observers were called.\n        async Task NotificationAsync(int observer)\n        {\n            notifiedObservers.Add(observer);\n            await Task.CompletedTask;\n        }\n\n        await observerManager.Notify(NotificationAsync);\n\n        // No observers should be notified as all are expired.\n        Assert.Empty(notifiedObservers);\n        // All observers should be removed due to expiration.\n        Assert.Equal(0, observerManager.Count);\n    }\n\n    [Fact]\n    public void ClearExpired_RemovesOnlyExpiredObservers()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromMinutes(30), NullLogger.Instance);\n        var startTime = DateTime.UtcNow;\n\n        // Mock GetDateTime to control time.\n        observerManager.GetDateTime = () => startTime;\n\n        // Subscribe some observers.\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Update last seen time for half of the observers.\n        var halfTime = startTime.AddMinutes(25);\n        observerManager.GetDateTime = () => halfTime;\n\n        for (var i = 5; i < 10; i++)\n        {\n            // This refreshes the LastSeen time.\n            observerManager.Subscribe(i, i);\n        }\n\n        // Advance time to expire only the first half.\n        observerManager.GetDateTime = () => startTime.AddMinutes(35);\n\n        observerManager.ClearExpired();\n\n         // Half should be removed due to expiration.\n        Assert.Equal(5, observerManager.Count);\n        for (var i = 0; i < 5; i++)\n        {\n             // First half should be removed.\n            Assert.DoesNotContain(i, observerManager.Observers.Values);\n        }\n\n        for (var i = 5; i < 10; i++)\n        {\n            // Second half should remain.\n            Assert.Contains(i, observerManager.Observers.Values);\n        }\n    }\n\n    [Fact]\n    public void Clear_RemovesAllObservers()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe some observers.\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Verify initial count.\n        Assert.Equal(10, observerManager.Count);\n\n        observerManager.Clear();\n\n        Assert.Equal(0, observerManager.Count);\n        Assert.Empty(observerManager.Observers);\n    }\n\n    [Fact]\n    public async Task CanModifyObserversConcurrently()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var scheduler = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 1);\n        const int observerCount = 100;\n\n        // Task 1: Subscribe observers.\n        var task1 = Task.Factory.StartNew(() =>\n        {\n            for (var i = 0; i < observerCount; i++)\n            {\n                observerManager.Subscribe(i, i);\n            }\n        },\n        CancellationToken.None,\n        TaskCreationOptions.RunContinuationsAsynchronously,\n        scheduler.ConcurrentScheduler);\n\n        // Task 2: Also subscribe same observers (to test update scenario).\n        var task2 = Task.Factory.StartNew(() =>\n        {\n            for (var i = 0; i < observerCount; i++)\n            {\n                // Different value to test updates.\n                observerManager.Subscribe(i, i * 10);\n            }\n        },\n        CancellationToken.None,\n        TaskCreationOptions.RunContinuationsAsynchronously,\n        scheduler.ConcurrentScheduler);\n\n        // Wait for both tasks to complete.\n        await Task.WhenAll(task1, task2);\n\n        Assert.Equal(observerCount, observerManager.Count);\n\n        // Now run notification on a different thread while modifying on main thread.\n        var notifiedCount = 0;\n        var tcs = new TaskCompletionSource();\n        var startedTcs = new TaskCompletionSource();\n        var notifyTask = Task.Factory.StartNew(async () =>\n        {\n            await observerManager.Notify(async observer =>\n            {\n                startedTcs.TrySetResult();\n                await tcs.Task;\n                Interlocked.Increment(ref notifiedCount);\n            });\n        },\n        CancellationToken.None,\n        TaskCreationOptions.RunContinuationsAsynchronously,\n        scheduler.ConcurrentScheduler).Unwrap();\n        await startedTcs.Task;\n\n        // Simultaneously modify the collection.\n        for (var i = observerCount; i < observerCount + 50; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        tcs.TrySetResult();\n        await notifyTask;\n\n        // We should have notified exactly observerCount observers\n        // (those that were present when the snapshot was created).\n        Assert.Equal(observerCount, notifiedCount);\n        Assert.Equal(observerCount + 50, observerManager.Count);\n    }\n\n    [Fact]\n    public void PredicateFiltersObserversToNotify()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new List<int>();\n\n        // Subscribe some observers.\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        bool EvenNumberPredicate(int observer) => observer % 2 == 0;\n\n        void Notification(int observer)\n        {\n            notifiedObservers.Add(observer);\n        }\n\n        observerManager.Notify(Notification, EvenNumberPredicate);\n\n        // Only even observers should be notified.\n        Assert.Equal(5, notifiedObservers.Count);\n        // All notified observers should be even.\n        Assert.All(notifiedObservers, observer => Assert.True(observer % 2 == 0));\n    }\n\n    [Fact]\n    public async Task AsyncPredicateFiltersObserversToNotify()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new List<int>();\n\n        // Subscribe some observers.\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        bool OddNumberPredicate(int observer) => observer % 2 == 1;\n\n        async Task NotificationAsync(int observer)\n        {\n            notifiedObservers.Add(observer);\n            await Task.CompletedTask;\n        }\n\n        await observerManager.Notify(NotificationAsync, OddNumberPredicate);\n\n        // Only odd observers should be notified.\n        Assert.Equal(5, notifiedObservers.Count);\n        // All notified observers should be odd.\n        Assert.All(notifiedObservers, observer => Assert.True(observer % 2 == 1));\n    }\n\n    [Fact]\n    public void EnumeratorWorksCorrectly()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe some observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        var enumeratedObservers = new List<int>();\n        foreach (var observer in observerManager)\n        {\n            enumeratedObservers.Add(observer);\n        }\n\n        Assert.Equal(5, enumeratedObservers.Count);\n        Assert.Equal(Enumerable.Range(0, 5), enumeratedObservers.OrderBy(x => x));\n    }\n\n    [Fact]\n    public void SubscribingExistingObserver_UpdatesLastSeenTime()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromMinutes(30), NullLogger.Instance);\n        var startTime = DateTime.UtcNow;\n\n        // Mock GetDateTime to control time.\n        observerManager.GetDateTime = () => startTime;\n\n        // Subscribe initial observer.\n        observerManager.Subscribe(1, 42);\n\n        // Advance time to near expiration but not quite.\n        var laterTime = startTime.AddMinutes(25);\n        observerManager.GetDateTime = () => laterTime;\n\n        // Update the subscription (same ID, same observer value).\n        observerManager.Subscribe(1, 42);\n\n        // Advance time to past the original subscription time + expiration.\n        var expirationCheckTime = startTime.AddMinutes(35);\n        observerManager.GetDateTime = () => expirationCheckTime;\n\n        var notified = false;\n        observerManager.Notify(observer => notified = true);\n\n        // Observer should still be active due to the refresh.\n        Assert.True(notified);\n        Assert.Equal(1, observerManager.Count);\n    }\n\n    [Fact]\n    public void SubscribingExistingObserver_UpdatesObserverValue()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe initial observer.\n        observerManager.Subscribe(1, 100);\n\n        // Update the subscription (same ID, different observer value).\n        observerManager.Subscribe(1, 200);\n\n        var observedValue = 0;\n        observerManager.Notify(observer => observedValue = observer);\n\n        // Should get the updated value.\n        Assert.Equal(200, observedValue);\n    }\n\n    [Fact]\n    public void SetExpirationDuration_AffectsExpiration()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var startTime = DateTime.UtcNow;\n\n        // Mock GetDateTime to control time.\n        observerManager.GetDateTime = () => startTime;\n\n        // Subscribe some observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Change expiration to a shorter duration after subscribing.\n        observerManager.ExpirationDuration = TimeSpan.FromMinutes(30);\n\n        // Advance time to between the old and new expiration durations.\n        // Past 30min, but before 1hr.\n        var laterTime = startTime.AddMinutes(45);\n        observerManager.GetDateTime = () => laterTime;\n\n        var notifiedObservers = new List<int>();\n        observerManager.Notify(observer => notifiedObservers.Add(observer));\n\n        // No observers should be notified due to expiration.\n        Assert.Empty(notifiedObservers);\n        // All observers should be removed.\n        Assert.Equal(0, observerManager.Count);\n    }\n\n    [Fact]\n    public async Task ClearDuringNotification_WorksCorrectly()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n        var notifiedObservers = new ConcurrentBag<int>();\n\n        // Subscribe some observers.\n        for (var i = 0; i < 10; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        // Start notification.\n        var notifyStartedTcs = new TaskCompletionSource();\n        var notifyTask = Task.Run(() =>\n        {\n            observerManager.Notify(observer =>\n            {\n                notifyStartedTcs.TrySetResult();\n                notifiedObservers.Add(observer);\n            });\n        });\n\n        // Clear while notification is happening.\n        await notifyStartedTcs.Task;\n        observerManager.Clear();\n\n        // Wait for notification to complete.\n        await notifyTask;\n\n        // Assert - We should still have notified all the original observers in the snapshot.\n        Assert.Equal(10, notifiedObservers.Count);\n\n        // But the collection should now be empty.\n        Assert.Equal(0, observerManager.Count);\n        Assert.Empty(observerManager.Observers);\n    }\n\n    [Fact]\n    public void ModifyDuringEnumeration_WorksWithoutExceptions()\n    {\n        var observerManager = new ObserverManager<int, int>(TimeSpan.FromHours(1), NullLogger.Instance);\n\n        // Subscribe some initial observers.\n        for (var i = 0; i < 5; i++)\n        {\n            observerManager.Subscribe(i, i);\n        }\n\n        var enumeratedObservers = new List<int>();\n        var newObserversAdded = new List<int>();\n        var removedObserver = -1;\n\n        // Enumerate using foreach which uses GetEnumerator under the hood.\n        foreach (var observer in observerManager)\n        {\n            enumeratedObservers.Add(observer);\n\n            // Add and remove observers during enumeration.\n            if (observer == 2)\n            {\n                // Add new observers.\n                for (var i = 10; i < 15; i++)\n                {\n                    observerManager.Subscribe(i, i);\n                    newObserversAdded.Add(i);\n                }\n\n                // Remove an observer.\n                observerManager.Unsubscribe(4);\n                removedObserver = 4;\n\n                // Verify immediate visibility in the collection (but not in the enumeration).\n                Assert.DoesNotContain(4, observerManager.Observers.Values);\n                foreach (var newObserver in newObserversAdded)\n                {\n                    Assert.Contains(newObserver, observerManager.Observers.Values);\n                }\n            }\n        }\n\n        // Original enumeration should complete with all original observers.\n        Assert.Equal(5, enumeratedObservers.Count);\n        // Even though we removed it during enumeration.\n        Assert.Contains(removedObserver, enumeratedObservers);\n\n        // Verify final collection state.\n        // 5 original - 1 removed + 5 added = 9 total.\n        Assert.Equal(9, observerManager.Count);\n        Assert.DoesNotContain(removedObserver, observerManager);\n        foreach (var newObserver in newObserversAdded)\n        {\n            Assert.Contains(newObserver, observerManager);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Orleans.Core.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Streaming.EventHubs\\Orleans.Streaming.EventHubs.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.NewtonsoftJson\\Orleans.Serialization.NewtonsoftJson.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Orleans.Serialization.SystemTextJson\\Orleans.Serialization.SystemTextJson.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Serializers\\Orleans.Serialization.Protobuf\\Orleans.Serialization.Protobuf.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.TimeProvider.Testing\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"NSubstitute\" />\n    <PackageReference Include=\"NSubstitute.Analyzers.CSharp\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"CsCheck\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Include=\"*.xml\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/AsyncSerialExecutorTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Orleans;\nusing Orleans.Internal;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.OrleansRuntime\n{\n    /// <summary>\n    /// Tests for async serial executor functionality including sequential task execution and concurrency validation.\n    /// </summary>\n    public class AsyncSerialExecutorTests\n    {\n        public ITestOutputHelper output;\n        public int operationsInProgress;\n\n        public AsyncSerialExecutorTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Async\")]\n        public async Task AsyncSerialExecutorTests_Small()\n        {\n            AsyncSerialExecutor executor = new AsyncSerialExecutor();\n            List<Task> tasks = new List<Task>();\n            operationsInProgress = 0;\n\n            tasks.Add(executor.AddNext(() => Operation(1)));\n            tasks.Add(executor.AddNext(() => Operation(2)));\n            tasks.Add(executor.AddNext(() => Operation(3)));\n\n            await Task.WhenAll(tasks);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Async\")]\n        public async Task AsyncSerialExecutorTests_SerialSubmit()\n        {\n            AsyncSerialExecutor executor = new AsyncSerialExecutor();\n            List<Task> tasks = new List<Task>();\n            for (int i = 0; i < 10; i++)\n            {\n                int capture = i;\n                output.WriteLine(\"Submitting Task {0}.\", capture);\n                tasks.Add(executor.AddNext(() => Operation(capture)));\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Async\")]\n        public async Task AsyncSerialExecutorTests_ParallelSubmit()\n        {\n            AsyncSerialExecutor executor = new AsyncSerialExecutor();\n            ConcurrentStack<Task> tasks = new ConcurrentStack<Task>();\n            List<Task> enqueueTasks = new List<Task>();\n            for (int i = 0; i < 10; i++)\n            {\n                int capture = i;\n                enqueueTasks.Add(\n                    Task.Run(() =>\n                    {\n                        output.WriteLine(\"Submitting Task {0}.\", capture);\n                        tasks.Push(executor.AddNext(() => Operation(capture)));\n                    }));\n            }\n            await Task.WhenAll(enqueueTasks);\n            await Task.WhenAll(tasks);\n        }\n\n        private async Task Operation(int opNumber)\n        {\n            if (operationsInProgress > 0) Assert.Fail($\"1: Operation {opNumber} found {operationsInProgress} operationsInProgress.\");\n            operationsInProgress++;\n            var delay = RandomTimeSpan.Next(TimeSpan.FromSeconds(2));\n\n            output.WriteLine(\"Task {0} Staring\", opNumber);\n            await Task.Delay(delay);\n            if (operationsInProgress != 1) Assert.Fail($\"2: Operation {opNumber} found {operationsInProgress} operationsInProgress.\");\n\n            output.WriteLine(\"Task {0} after first delay\", opNumber);\n            await Task.Delay(delay);\n            if (operationsInProgress != 1) Assert.Fail($\"3: Operation {opNumber} found {operationsInProgress} operationsInProgress.\");\n\n            operationsInProgress--;\n            output.WriteLine(\"Task {0} Done\", opNumber);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/ExceptionsTests.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.Serialization;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime\n{\n    /// <summary>\n    /// Tests for Orleans exception serialization and round-trip testing.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class ExceptionsTests\n    {\n        private readonly TestEnvironmentFixture fixture;\n\n        public ExceptionsTests(TestEnvironmentFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_Exception_Orleans()\n        {\n            var original = new SiloUnavailableException(\"Some message\");\n            var output = this.fixture.Serializer.RoundTripSerializationForTesting(original);\n\n            Assert.Equal(original.Message, output.Message);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/Streams/BestFitBalancerTests.cs",
    "content": "using Orleans.Streams;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for best-fit balancer algorithm including resource distribution across buckets and ordering invariance.\n    /// </summary>\n    public class BestFitBalancerTests\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseMoreResourcesThanBucketsTest()\n        {\n            const int resourceCount = 99;\n            const int bucketCount = 10;\n            var idealBalance = (int)Math.Floor((double) (resourceCount)/bucketCount);\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseMoreResourcesThanBuckets2Test()\n        {\n            const int resourceCount = 100;\n            const int bucketCount = 30;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseLessResourcesThanBucketsTest()\n        {\n            const int bucketCount = 99;\n            const int resourceCount = 10;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseLessResourcesThanBuckets2Test()\n        {\n            const int bucketCount = 100;\n            const int resourceCount = 30;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseResourcesMatchBucketsTest()\n        {\n            const int bucketCount = 100;\n            const int resourceCount = 100;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseResourcesDevisibleByBucketsTest()\n        {\n            const int resourceCount = 100;\n            const int bucketCount = 10;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void IdealCaseRangedTest()\n        {\n            const int MaxResourceCount = 20;\n            const int MaxBucketCount = 20;\n\n            for (int resourceCount = 1; resourceCount <= MaxResourceCount; resourceCount++)\n            {\n                for (int bucketCount = 1; bucketCount <= MaxBucketCount; bucketCount++)\n                {\n                    var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n                    List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n                    List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n                    var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n                    Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n                    ValidateBalance(buckets, resources, balancerResults, idealBalance);\n                }\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void HalfBucketsActiveTest()\n        {\n            const int resourceCount = 99;\n            const int bucketCount = 10;\n            const int activeBucketCount = bucketCount/2;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / activeBucketCount);\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            List<int> activeBuckets = buckets.Take(activeBucketCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(activeBuckets);\n            ValidateBalance(activeBuckets, resources, balancerResults, idealBalance);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void OrderIrrelevantTest()\n        {\n            const int resourceCount = 99;\n            const int bucketCount = 10;\n            var idealBalance = (int)Math.Floor((double)(resourceCount) / bucketCount);\n            List<int> resources = Enumerable.Range(0, resourceCount).ToList();\n            List<int> buckets = Enumerable.Range(0, bucketCount).ToList();\n            var resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResults = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResults, idealBalance);\n\n            // reverse inputs\n            resources.Reverse();\n            buckets.Reverse();\n            resourceBalancer = new BestFitBalancer<int, int>(buckets, resources);\n            Dictionary<int, List<int>> balancerResultsFromReversedInputs = resourceBalancer.GetDistribution(buckets);\n            ValidateBalance(buckets, resources, balancerResultsFromReversedInputs, idealBalance);\n\n            Assert.True(balancerResults.Keys.SequenceEqual(balancerResultsFromReversedInputs.Keys), \"Bucket order\");\n            foreach (int bucket in balancerResults.Keys)\n            {\n                Assert.True(balancerResults[bucket].SequenceEqual(balancerResultsFromReversedInputs[bucket]), \"Resource order\");\n            }\n        }\n\n        private static void ValidateBalance(List<int> buckets, List<int> resources, Dictionary<int, List<int>> balancerResults, int idealBalance)\n        {\n            var resultBuckets = new List<int>();\n            var resultResources = new List<int>();\n            foreach (KeyValuePair<int, List<int>> kvp in balancerResults)\n            {\n                Assert.False(resultBuckets.Contains(kvp.Key), \"Duplicate bucket found.\");\n                Assert.True(buckets.Contains(kvp.Key), \"Unknown bucket found.\");\n                resultBuckets.Add(kvp.Key);\n                kvp.Value.ForEach(resource =>\n                {\n                    Assert.False(resultResources.Contains(resource), \"Duplicate resource found.\");\n                    Assert.True(resources.Contains(resource), \"Unknown resource found.\");\n                    resultResources.Add(resource);\n                });\n                Assert.True(idealBalance <= kvp.Value.Count, \"Balance not ideal\");\n                Assert.True(idealBalance + 1 >= kvp.Value.Count, \"Balance not ideal\");\n            }\n            Assert.Equal(buckets.Count, resultBuckets.Count);  // \"bucket counts do not match\"\n            Assert.Equal(resources.Count, resultResources.Count);  // \"resource counts do not match\"\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/Streams/ResourceSelectorTestRunner.cs",
    "content": "﻿using Xunit.Abstractions;\nusing Xunit;\nusing Orleans.Streams;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    public abstract class ResourceSelectorTestRunner\n    {\n        private readonly ITestOutputHelper output;\n\n        protected ResourceSelectorTestRunner(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        internal void NextSelectionWillGoThroughEveryResourceIfExistingSelectionEmpty(List<string> resources, IResourceSelector<string> resourceSelector)\n        {\n            Assert.Equal(resources.Distinct().Count(), resources.Count);\n            resources.Sort();\n            List<string> selected = resourceSelector.NextSelection(resources.Count, new List<string>());\n            Assert.Equal(resources.Count, selected.Count);\n            selected = selected.Distinct().ToList();\n            selected.Sort();\n            Assert.Equal(resources.Count, selected.Count);\n            for (int i=0; i<selected.Count; i++)\n            {\n                Assert.Equal(resources[i], selected[i]);\n            }\n        }\n\n        internal void NextSelectionWontGoInfinitely(List<string> resources, IResourceSelector<string> resourceSelector)\n        {\n            Assert.Equal(resources.Distinct().Count(), resources.Count);\n            resources.Sort();\n            List<string> selected = resourceSelector.NextSelection(int.MaxValue, new List<string>());\n            Assert.Equal(resources.Count, selected.Count);\n            selected = selected.Distinct().ToList();\n            selected.Sort();\n            Assert.Equal(resources.Count, selected.Count);\n            for (int i = 0; i < selected.Count; i++)\n            {\n                Assert.Equal(resources[i], selected[i]);\n            }\n        }\n\n        internal void NextSelectionWontReSelectExistingSelections(List<string> resources, IResourceSelector<string> resourceSelector)\n        {\n            Assert.Equal(resources.Distinct().Count(), resources.Count);\n            for (int selectCount = 0; selectCount < resources.Count; selectCount++)\n            {\n                for (int excludeCount = 0; excludeCount < resources.Count; excludeCount++)\n                {\n                    List<string> excluded = resourceSelector.NextSelection(excludeCount, new List<string>());\n                    Assert.Equal(excludeCount, excluded.Count);\n                    excluded = excluded.Distinct().ToList();\n                    Assert.Equal(excludeCount, excluded.Count);\n\n                    List<string> selected = resourceSelector.NextSelection(selectCount, excluded);\n                    int expectedCount = Math.Min(selectCount, resources.Count - excludeCount);\n                    Assert.Equal(expectedCount, selected.Count);\n                    selected = selected.Distinct().ToList();\n                    Assert.Equal(expectedCount, selected.Count);\n                    for (int i = 0; i < selected.Count; i++)\n                    {\n                        Assert.DoesNotContain(selected[i], excluded);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/Streams/RoundRobinSelectorTests.cs",
    "content": "using Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Streams;\nusing System.Data;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for round-robin resource selector including selection distribution and duplicate handling.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class RoundRobinSelectorTests : ResourceSelectorTestRunner\n    {\n        private const int ResourceCount = 10;\n        private readonly IResourceSelector<string> resourceSelector;\n        private readonly List<string> resources;\n\n        public RoundRobinSelectorTests(ITestOutputHelper output) : base(output)\n        {\n            this.resources = Enumerable.Range(0, ResourceCount).Select(i => $\"resource_{i}\").ToList();\n            this.resourceSelector = new RoundRobinSelector<string>(this.resources);\n        }\n\n        [Fact]\n        public void NextSelectionWillGoThroughEveryResourceIfExistingSelectionEmptyTest()\n        {\n            base.NextSelectionWillGoThroughEveryResourceIfExistingSelectionEmpty(resources, resourceSelector);\n        }\n\n        [Fact]\n        public void NextSelectionWontGoInfinitelyTest()\n        {\n            base.NextSelectionWontGoInfinitely(resources, resourceSelector);\n        }\n\n        [Fact]\n        public void NextSelectionWontReSelectExistingSelectionsTest()\n        {\n            base.NextSelectionWontReSelectExistingSelections(resources, resourceSelector);\n        }\n\n        [Fact]\n        public void NextSelectionWontReSelectExistingSelectionsWithDuplicatesTest()\n        {\n            var duplicateResources = new List<string>(this.resources);\n            duplicateResources.AddRange(this.resources);\n            var resourceSelectorWithDuplicates = new RoundRobinSelector<string>(duplicateResources);\n            base.NextSelectionWontReSelectExistingSelections(this.resources, resourceSelectorWithDuplicates);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/OrleansRuntime/Streams/SubscriptionMarkerTests.cs",
    "content": "using Orleans.Streams;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for subscription marker functionality including implicit and explicit subscription marking.\n    /// </summary>\n    public class SubscriptionMarkerTests\n    {\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Nightly\"), TestCategory(\"Streaming\")]\n        public void MarkAsImplicitSubscriptionTest()\n        {\n            Guid guid = Guid.Empty;\n\n            Assert.False(SubscriptionMarker.IsImplicitSubscription(guid));\n\n            Guid markedGuid = SubscriptionMarker.MarkAsImplictSubscriptionId(guid);\n\n            Assert.True(SubscriptionMarker.IsImplicitSubscription(markedGuid));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Nightly\"), TestCategory(\"Streaming\")]\n        public void MarkAsExplicitSubscriptionTest()\n        {\n            byte[] guidBytes = Enumerable.Range(0, 16).Select(i => (byte)0xff).ToArray();\n            var guid = new Guid(guidBytes);\n\n            Assert.True(SubscriptionMarker.IsImplicitSubscription(guid));\n\n            Guid markedGuid = SubscriptionMarker.MarkAsExplicitSubscriptionId(guid);\n\n            Assert.False(SubscriptionMarker.IsImplicitSubscription(markedGuid));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ProviderErrorMessageTests.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Hosting;\nusing Xunit;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// Tests for provider error messages to ensure they include helpful information about known/registered providers.\n    /// These tests verify that when a provider is not found, the error message includes a list of available providers\n    /// for the specified kind (e.g., Clustering, GrainStorage, etc.) to help users diagnose configuration issues.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    [TestCategory(\"Providers\")]\n    public class ProviderErrorMessageTests\n    {\n        /// <summary>\n        /// Tests that client builder includes known providers in error message when a provider is not found.\n        /// Verifies that the error message contains both the standard message and a list of known providers\n        /// for the specified kind when an invalid provider type is requested.\n        /// </summary>\n        [Fact]\n        public void ClientBuilder_IncludesKnownProvidersInErrorMessage()\n        {\n            var configDict = new Dictionary<string, string?>\n            {\n                { \"Orleans:ClusterId\", \"test-cluster\" },\n                { \"Orleans:ServiceId\", \"test-service\" },\n                { \"Orleans:Clustering:ProviderType\", \"NonExistentProvider\" }\n            };\n\n            var exception = Assert.Throws<InvalidOperationException>(() =>\n            {\n                _ = new HostBuilder()\n                    .ConfigureAppConfiguration(configBuilder =>\n                    {\n                        configBuilder.AddInMemoryCollection(configDict);\n                    })\n                    .UseOrleansClient(_ => { })\n                    .Build();\n            });\n\n            // Verify the error message contains the provider name that was not found\n            Assert.Contains(\"Could not find Clustering provider named 'NonExistentProvider'\", exception.Message);\n\n            // Verify the error message includes information about known providers\n            // The exact list will depend on what providers are registered, but the message should contain \"Known Clustering providers:\"\n            // if there are any registered Clustering providers\n            Assert.Contains(\"This can indicate that either the 'Microsoft.Orleans.Sdk' or the provider's package are not referenced\", exception.Message);\n        }\n\n        /// <summary>\n        /// Tests that silo builder includes known providers in error message when a provider is not found.\n        /// Verifies that the error message contains both the standard message and a list of known providers\n        /// for the specified kind when an invalid provider type is requested.\n        /// </summary>\n        [Fact]\n        public void SiloBuilder_IncludesKnownProvidersInErrorMessage()\n        {\n            var configDict = new Dictionary<string, string?>\n            {\n                { \"Orleans:ClusterId\", \"test-cluster\" },\n                { \"Orleans:ServiceId\", \"test-service\" },\n                { \"Orleans:Clustering:ProviderType\", \"NonExistentProvider\" }\n            };\n\n            var exception = Assert.Throws<InvalidOperationException>(() =>\n            {\n                _ = new HostBuilder()\n                    .ConfigureAppConfiguration(configBuilder =>\n                    {\n                        configBuilder.AddInMemoryCollection(configDict);\n                    })\n                    .UseOrleans(_ => { })\n                    .Build();\n            });\n\n            // Verify the error message contains the provider name that was not found\n            Assert.Contains(\"Could not find Clustering provider named 'NonExistentProvider'\", exception.Message);\n\n            // Verify the error message includes information about known providers\n            Assert.Contains(\"This can indicate that either the 'Microsoft.Orleans.Sdk' or the provider's package are not referenced\", exception.Message);\n        }\n\n        /// <summary>\n        /// Tests that error message for GrainStorage provider includes known providers.\n        /// Verifies that when an invalid GrainStorage provider is specified, the error message\n        /// includes helpful information about available GrainStorage providers.\n        /// </summary>\n        [Fact]\n        public void SiloBuilder_IncludesKnownGrainStorageProvidersInErrorMessage()\n        {\n            var configDict = new Dictionary<string, string?>\n            {\n                { \"Orleans:ClusterId\", \"test-cluster\" },\n                { \"Orleans:ServiceId\", \"test-service\" },\n                { \"Orleans:GrainStorage:MyStorage:ProviderType\", \"InvalidStorageProvider\" }\n            };\n\n            var exception = Assert.Throws<InvalidOperationException>(() =>\n            {\n                _ = new HostBuilder()\n                    .ConfigureAppConfiguration(configBuilder =>\n                    {\n                        configBuilder.AddInMemoryCollection(configDict);\n                    })\n                    .UseOrleans(siloBuilder =>\n                    {\n                        siloBuilder.UseLocalhostClustering();\n                    })\n                    .Build();\n            });\n\n            // Verify the error message contains the provider name that was not found\n            Assert.Contains(\"Could not find GrainStorage provider named 'InvalidStorageProvider'\", exception.Message);\n\n            // Verify the error message includes information about known providers\n            Assert.Contains(\"This can indicate that either the 'Microsoft.Orleans.Sdk' or the provider's package are not referenced\", exception.Message);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Runtime/ActivationCollectorTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Microsoft.Extensions.Time.Testing;\nusing NSubstitute;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Statistics;\nusing TestGrains;\nusing Xunit;\n\nnamespace UnitTests.Runtime\n{\n    /// <summary>\n    /// Tests for activation collector functionality including ticket generation from timestamps.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Runtime\")]\n    public class ActivationCollectorTests\n    {\n        private readonly FakeTimeProvider timeProvider;\n        private readonly ActivationCollector collector;\n\n        public ActivationCollectorTests()\n        {\n            var grainCollectionOptions = Options.Create(new GrainCollectionOptions());\n            var logger = NullLogger<ActivationCollector>.Instance;\n\n            this.timeProvider = new FakeTimeProvider(DateTimeOffset.Parse(\"2025-01-01T00:00:00.000+00:00\"));\n            this.collector = new ActivationCollector(timeProvider, grainCollectionOptions, logger, new EnvironmentStatisticsProvider());\n        }\n\n        [Theory, TestCategory(\"Activation\")]\n        [InlineData(\"2025-01-01T00:00:00\", \"2025-01-01T00:00:00\")]\n        [InlineData(\"2025-01-01T00:00:01\", \"2025-01-01T00:01:00\")]\n        [InlineData(\"2025-01-01T00:00:59\", \"2025-01-01T00:01:00\")]\n        [InlineData(\"2025-01-01T00:01:01\", \"2025-01-01T00:02:00\")]\n        public void MakeTicketFromDateTime(string timestampString, string expectedTicketString)\n        {\n            var timestamp = DateTime.Parse(timestampString);\n            var expectedTicket = DateTime.Parse(expectedTicketString);\n\n            var actualTicket = collector.MakeTicketFromDateTime(timestamp);\n\n            Assert.Equal(expectedTicket, actualTicket);\n        }\n\n        [Fact, TestCategory(\"Activation\")]\n        public void MakeTicketFromDateTime_MaxValue()\n        {\n            var expectedTicket = DateTime.MaxValue;\n\n            var actualTicket = collector.MakeTicketFromDateTime(DateTime.MaxValue);\n\n            Assert.Equal(expectedTicket, actualTicket);\n        }\n\n        [Fact, TestCategory(\"Activation\")]\n        public void MakeTicketFromDateTime_Invalid_BeforeNextTicket()\n        {\n            var timestamp = this.timeProvider.GetUtcNow().AddMinutes(-5).UtcDateTime;\n\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var ticket = collector.MakeTicketFromDateTime(timestamp);\n            });\n        }\n\n        [Theory, TestCategory(\"MemoryBasedDeactivations\")]\n        [InlineData(80.0, 70.0, 1000, 150, 100, true, 82)] // Over threshold, need to deactivate\n        [InlineData(80.0, 70.0, 1000, 250, 100, false, 0)] // Below threshold, no deactivation\n        [InlineData(80.0, 70.0, 1000, 100, 200, true, 155)] // More activations, smaller per-activation size\n        [InlineData(80.0, 70.0, 1000, 800, 100, false, 0)] // Well below threshold\n        [InlineData(80.0, 70.0, 1000, 50,  10,  true, 7)] // Few activations, large per-activation size\n        public void IsMemoryOverloaded_WorksAsExpected(\n            double memoryLoadThreshold,\n            double targetMemoryLoad,\n            long maxMemoryMb,\n            long availableMemoryMb,\n            int activationCount,\n            bool expectedOverloaded,\n            int expectedActivationsTarget)\n        {\n            var grainCollectionOptions = Options.Create(new GrainCollectionOptions\n            {\n                MemoryUsageLimitPercentage = memoryLoadThreshold,\n                MemoryUsageTargetPercentage = targetMemoryLoad\n            });\n\n            // Calculate usedMemory and set rawAvailableMemoryBytes as per new logic\n            long usedMemoryBytes = maxMemoryMb - availableMemoryMb;\n            long rawAvailableMemoryBytes = availableMemoryMb;\n            long maxMemoryBytes = maxMemoryMb;\n\n            var statsProvider = Substitute.For<IEnvironmentStatisticsProvider>();\n            statsProvider.GetEnvironmentStatistics().Returns(\n                new EnvironmentStatistics(\n                    cpuUsagePercentage: 0,\n                    rawCpuUsagePercentage: 0,\n                    memoryUsageBytes: usedMemoryBytes,\n                    rawMemoryUsageBytes: usedMemoryBytes,\n                    availableMemoryBytes: rawAvailableMemoryBytes,\n                    rawAvailableMemoryBytes: rawAvailableMemoryBytes,\n                    maximumAvailableMemoryBytes: maxMemoryBytes\n                )\n            );\n\n            var logger = NullLogger<ActivationCollector>.Instance;\n            var timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);\n\n            var collector = new ActivationCollector(\n                timeProvider,\n                grainCollectionOptions,\n                logger,\n                statsProvider\n            );\n\n            collector._activationCount = activationCount;\n            var overloaded = collector.IsMemoryOverloaded(out var surplusActivations);\n\n            Assert.Equal(expectedOverloaded, overloaded);\n            if (overloaded)\n            {\n                Assert.Equal(expectedActivationsTarget, activationCount - surplusActivations);\n            }\n        }\n\n        [Fact]\n        public async Task DeactivateInDueTimeOrder_OnlyOldestAndEligibleAreDeactivated()\n        {\n            var grainCollectionOptions = Options.Create(new GrainCollectionOptions());\n\n            var logger = NullLogger<ActivationCollector>.Instance;\n            var statsProvider = Substitute.For<IEnvironmentStatisticsProvider>();\n            var timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);\n\n            var collector = new ActivationCollector(timeProvider, grainCollectionOptions, logger, statsProvider);\n            var timer = Substitute.For<IAsyncTimer>();\n            timer.NextTick().Returns(Task.FromResult(false));\n            var timerFactory = Substitute.For<IAsyncTimerFactory>();\n            timerFactory.Create(Arg.Any<TimeSpan>(), Arg.Any<string>()).Returns(timer);\n\n            var wsLogger = NullLogger<ActivationWorkingSet>.Instance;\n            var workingSet = new ActivationWorkingSet(timerFactory, wsLogger, new[] { collector });\n\n            var activation1 = PrepareActivation(1, collector);\n            var activation2 = PrepareActivation(1, collector);\n            var activation3 = PrepareActivation(1, collector);\n\n            activation1.IsCandidateForRemoval(Arg.Any<bool>()).Returns(true);\n            activation2.IsCandidateForRemoval(Arg.Any<bool>()).Returns(true);\n            activation3.IsCandidateForRemoval(Arg.Any<bool>()).Returns(true);\n\n            workingSet.OnActivated(activation1);\n            workingSet.OnActivated(activation2);\n            workingSet.OnActivated(activation3);\n\n            await collector.DeactivateInDueTimeOrder(2, CancellationToken.None);\n\n            Assert.Equal(1, collector._activationCount);\n        }\n\n        [Fact]\n        public async Task DeactivateInDueTimeOrder_ConcurrentModification_ShouldNotThrow()\n        {\n            var grainCollectionOptions = Options.Create(new GrainCollectionOptions());\n\n            var logger = NullLogger<ActivationCollector>.Instance;\n            var statsProvider = Substitute.For<IEnvironmentStatisticsProvider>();\n            var timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);\n\n            var collector = new ActivationCollector(timeProvider, grainCollectionOptions, logger, statsProvider);\n            var timer = Substitute.For<IAsyncTimer>();\n            timer.NextTick().Returns(Task.FromResult(false));\n            var timerFactory = Substitute.For<IAsyncTimerFactory>();\n            timerFactory.Create(Arg.Any<TimeSpan>(), Arg.Any<string>()).Returns(timer);\n\n            var wsLogger = NullLogger<ActivationWorkingSet>.Instance;\n            var workingSet = new ActivationWorkingSet(timerFactory, wsLogger, new[] { collector });\n\n            var totalActivations = 500;\n            var activations = new List<IActivationWorkingSetMember>();\n\n            for (var i = 0; i < totalActivations; i++)\n            {\n                var collectionAgeLimit = TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(i * 1);\n\n                var activation = PrepareActivation(collectionAgeLimit, collector);\n\n                activation.IsCandidateForRemoval(Arg.Any<bool>()).Returns(true);\n                var activationMember = activation;\n                activations.Add(activationMember);\n                workingSet.OnActivated(activationMember);\n            }\n\n            // Now we have 500 buckets. Let's trigger the race condition.\n            var exceptions = new ConcurrentBag<Exception>();\n            var cts = new CancellationTokenSource();\n\n            // Task 1: Aggressively ADD new activations (creates NEW buckets in the dictionary)\n            var addTask = Task.Run(async () =>\n            {\n                int addCount = 0;\n                while (!cts.Token.IsCancellationRequested && addCount < 200)\n                {\n                    // Add 10 activations at a time with random collection ages\n                    for (int i = 0; i < 10; i++)\n                    {\n                        var activation = PrepareActivation(501 + Random.Shared.Next(200), collector);\n                        activation.IsCandidateForRemoval(Arg.Any<bool>()).Returns(true);\n\n                        workingSet.OnActivated(activation);\n                        addCount++;\n                    }\n\n                    await Task.Yield();\n                }\n            });\n\n            // Task 2: Aggressively REMOVE activations (empties buckets, causing REMOVAL from dictionary)\n            var removeTask = Task.Run(async () =>\n            {\n                int removeCount = 0;\n                while (!cts.Token.IsCancellationRequested && removeCount < 200)\n                {\n                    // Remove 10 activations at a time\n                    for (int i = 0; i < 10 && activations.Count > 100; i++)\n                    {\n                        var activation = activations[Random.Shared.Next(activations.Count)] as ICollectibleGrainContext;\n\n                        // TryCancelCollection removes the activation from its bucket\n                        // If the bucket becomes empty, it gets removed from the dictionary!\n                        if (collector.TryCancelCollection(activation))\n                        {\n                            removeCount++;\n                        }\n                    }\n\n                    await Task.Yield();\n                }\n            });\n\n            // Task 3: Run DeactivateInDueTimeOrder MANY times concurrently\n            // This is where OrderBy enumerates buckets and can race with add/remove\n            var deactivateTasks = Enumerable.Range(0, 20).Select(_ => Task.Run(async () =>\n            {\n                for (int i = 0; i < 100; i++)\n                {\n                    try\n                    {\n                        // Deactivation iterates through the buckets, and if code is not resilient for concurrent modification,\n                        // it will blow up with some form of collection modification exception.                        \n                        await collector.DeactivateInDueTimeOrder(50, CancellationToken.None);\n                        await Task.Delay(1);\n                    }\n                    catch (Exception ex)\n                    {\n                        exceptions.Add(ex);\n                    }\n                }\n            })).ToArray();\n\n            // Wait for all deactivation attempts\n            await Task.WhenAll(deactivateTasks);\n\n            // Stop background modifications\n            cts.Cancel();\n            await Task.WhenAll(addTask, removeTask);\n\n            // Verify no exceptions occurred during deactivation\n            Assert.Empty(exceptions);\n        }\n\n        private IActivationWorkingSetMember PrepareActivation(int collectionAgeLimitMinutes, ActivationCollector collector)\n            => PrepareActivation(TimeSpan.FromMinutes(collectionAgeLimitMinutes), collector);\n\n        private IActivationWorkingSetMember PrepareActivation(TimeSpan collectionAgeLimit, ActivationCollector collector)\n        {\n            var activation = Substitute.For<ICollectibleGrainContext, IActivationWorkingSetMember>();\n            activation.CollectionAgeLimit.Returns(collectionAgeLimit);\n            activation.IsValid.Returns(true);\n            activation.IsExemptFromCollection.Returns(false);\n            activation.IsInactive.Returns(true);\n            activation.Deactivated.Returns(Task.CompletedTask).AndDoes(_ => { Interlocked.Decrement(ref collector._activationCount); });\n\n            return (IActivationWorkingSetMember)activation;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Runtime/ActivationCountPlacementDirectorTests.cs",
    "content": "using System;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.Statistics;\nusing Xunit;\n\nnamespace UnitTests.Runtime\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Placement\")]\n    public class ActivationCountPlacementDirectorTests\n    {\n        [Fact]\n        public async Task OnAddActivation_WhenCacheIsEmptyAndLocalSiloIsIncompatible_PlacesOnCompatibleSilo()\n        {\n            var localSilo = Silo(\"127.0.0.1:100@1\");\n            var compatibleSilo = Silo(\"127.0.0.1:101@1\");\n            var director = CreateDirector(localSilo);\n            var placementContext = Substitute.For<IPlacementContext>();\n            placementContext.GetCompatibleSilos(Arg.Any<PlacementTarget>()).Returns([compatibleSilo]);\n\n            var result = await director.OnAddActivation(strategy: null!, target: default, placementContext);\n\n            Assert.Equal(compatibleSilo, result);\n        }\n\n        [Fact]\n        public async Task OnAddActivation_WhenCacheIsEmptyAndLocalSiloIsCompatible_PlacesLocally()\n        {\n            var localSilo = Silo(\"127.0.0.1:100@1\");\n            var compatibleSilo = Silo(\"127.0.0.1:101@1\");\n            var director = CreateDirector(localSilo);\n            var placementContext = Substitute.For<IPlacementContext>();\n            placementContext.GetCompatibleSilos(Arg.Any<PlacementTarget>()).Returns([compatibleSilo, localSilo]);\n\n            var result = await director.OnAddActivation(strategy: null!, target: default, placementContext);\n\n            Assert.Equal(localSilo, result);\n        }\n\n        [Fact]\n        public async Task OnAddActivation_WhenSomeCompatibleSilosHaveNoStats_PrefersSilosWithStats()\n        {\n            var localSilo = Silo(\"127.0.0.1:100@1\");\n            var siloWithStats = Silo(\"127.0.0.1:101@1\");\n            var siloWithoutStats = Silo(\"127.0.0.1:102@1\");\n            var director = CreateDirector(localSilo);\n            var placementContext = CreatePlacementContext(siloWithStats, siloWithoutStats);\n            director.SiloStatisticsChangeNotification(siloWithStats, CreateSiloRuntimeStatistics(overloaded: false, recentlyUsedActivationCount: 10));\n\n            var result = await director.OnAddActivation(strategy: null!, target: default, placementContext);\n\n            Assert.Equal(siloWithStats, result);\n        }\n\n        [Fact]\n        public async Task OnAddActivation_WhenAllCompatibleSilosWithStatsAreOverloaded_Throws()\n        {\n            var localSilo = Silo(\"127.0.0.1:100@1\");\n            var overloadedSilo1 = Silo(\"127.0.0.1:101@1\");\n            var overloadedSilo2 = Silo(\"127.0.0.1:102@1\");\n            var director = CreateDirector(localSilo);\n            var placementContext = CreatePlacementContext(overloadedSilo1, overloadedSilo2);\n            director.SiloStatisticsChangeNotification(overloadedSilo1, CreateSiloRuntimeStatistics(overloaded: true));\n            director.SiloStatisticsChangeNotification(overloadedSilo2, CreateSiloRuntimeStatistics(overloaded: true));\n\n            await Assert.ThrowsAsync<SiloUnavailableException>(() => director.OnAddActivation(strategy: null!, target: default, placementContext));\n        }\n\n        [Fact]\n        public async Task OnAddActivation_WhenSilosWithStatsAreOverloadedAndWithoutStatsExist_FallsBackToWithoutStats()\n        {\n            var localSilo = Silo(\"127.0.0.1:100@1\");\n            var overloadedSilo = Silo(\"127.0.0.1:101@1\");\n            var siloWithoutStats = Silo(\"127.0.0.1:102@1\");\n            var director = CreateDirector(localSilo);\n            var placementContext = CreatePlacementContext(overloadedSilo, siloWithoutStats);\n            director.SiloStatisticsChangeNotification(overloadedSilo, CreateSiloRuntimeStatistics(overloaded: true));\n\n            var result = await director.OnAddActivation(strategy: null!, target: default, placementContext);\n\n            Assert.Equal(siloWithoutStats, result);\n        }\n\n        private static ActivationCountPlacementDirector CreateDirector(SiloAddress localSilo)\n        {\n            var localSiloDetails = Substitute.For<ILocalSiloDetails>();\n            localSiloDetails.SiloAddress.Returns(localSilo);\n\n            return new ActivationCountPlacementDirector(\n                localSiloDetails,\n                deploymentLoadPublisher: null!,\n                Options.Create(new ActivationCountBasedPlacementOptions()));\n        }\n\n        private static IPlacementContext CreatePlacementContext(params SiloAddress[] compatibleSilos)\n        {\n            var placementContext = Substitute.For<IPlacementContext>();\n            placementContext.GetCompatibleSilos(Arg.Any<PlacementTarget>()).Returns(compatibleSilos);\n            return placementContext;\n        }\n\n        private static SiloRuntimeStatistics CreateSiloRuntimeStatistics(bool overloaded, int recentlyUsedActivationCount = 0)\n        {\n            var environmentStatisticsProvider = Substitute.For<IEnvironmentStatisticsProvider>();\n            var maxMemoryBytes = 1000L;\n            var memoryUsageBytes = overloaded ? 950L : 100L;\n            var availableMemoryBytes = maxMemoryBytes - memoryUsageBytes;\n            var cpuUsagePercentage = overloaded ? 100f : 0f;\n\n            environmentStatisticsProvider.GetEnvironmentStatistics().Returns(\n                new EnvironmentStatistics(\n                    cpuUsagePercentage: cpuUsagePercentage,\n                    rawCpuUsagePercentage: cpuUsagePercentage,\n                    memoryUsageBytes: memoryUsageBytes,\n                    rawMemoryUsageBytes: memoryUsageBytes,\n                    availableMemoryBytes: availableMemoryBytes,\n                    rawAvailableMemoryBytes: availableMemoryBytes,\n                    maximumAvailableMemoryBytes: maxMemoryBytes));\n\n            return new SiloRuntimeStatistics(\n                activationCount: 0,\n                recentlyUsedActivationCount: recentlyUsedActivationCount,\n                environmentStatisticsProvider,\n                Options.Create(new LoadSheddingOptions { LoadSheddingEnabled = overloaded }),\n                DateTime.UtcNow);\n        }\n\n        private static SiloAddress Silo(string value) => SiloAddress.FromParsableString(value);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/RuntimeTypeNameFormatterTests.cs",
    "content": "using System.Collections.Specialized;\nusing Orleans.Serialization.TypeSystem;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// Tests for the Orleans RuntimeTypeNameFormatter, which is responsible for formatting and parsing .NET type names\n    /// in a way that is recoverable and consistent across different environments. This is crucial for Orleans' serialization\n    /// system and type resolution when communicating between silos and clients.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class RuntimeTypeNameFormatterTests\n    {\n        public interface IMyBaseType<T> { }\n        public interface IMyArrayType<T> : IMyBaseType <T[]> { }\n        private readonly ITestOutputHelper _output;\n        private readonly List<Type> _types = new()\n            {\n                typeof(NameValueCollection),\n                typeof(int),\n                typeof(int[]),\n                typeof(int*[]),\n                typeof(int[]),\n                typeof(List<>),\n                typeof(List<int>),\n                typeof(List<int*[]>),\n                typeof(Inner<int[,,]>.InnerInner<string, List<int>>.Bottom[,]),\n                typeof(Inner<>.InnerInner<,>.Bottom),\n                typeof(RuntimeTypeNameFormatterTests),\n                typeof(TestGrainInterfaces.CircularStateTestState),\n                typeof(int).MakeByRefType(),\n                typeof(Inner<int[]>.InnerInner<string, List<int>>.Bottom[,])\n                    .MakePointerType()\n                    .MakePointerType()\n                    .MakeArrayType(10)\n                    .MakeByRefType(),\n                typeof(NameValueCollection)\n            };\n\n        public RuntimeTypeNameFormatterTests(ITestOutputHelper output)\n        {\n            _output = output;\n            _types.Add(typeof(List<>).MakeGenericType(typeof(Inner<int>.Middle).MakeArrayType()));\n            _types.Add(typeof(List<>).MakeGenericType(typeof(Inner<>.Middle).MakeArrayType()));\n            typeof(IMyArrayType<>).MakeGenericType(typeof(Inner<>.Middle)).GetInterfaces().ToList().ForEach(_types.Add);\n            typeof(IMyArrayType<>).GetInterfaces().ToList().ForEach(_types.Add);\n        }\n\n        /// <summary>\n        /// Tests that various strings formatted with <see cref=\"RuntimeTypeNameFormatter\"/> can be loaded using <see cref=\"Type.GetType(string)\"/>.\n        /// </summary>\n        [Fact]\n        public void FormattedTypeNamesAreRecoverable()\n        {\n            var resolver = new CachedTypeResolver();\n            foreach (var type in _types)\n            {\n                if (string.IsNullOrWhiteSpace(type.FullName)) continue;\n                var formatted = RuntimeTypeNameFormatter.Format(type);\n                _output.WriteLine($\"Full Name: {type.FullName}\");\n                _output.WriteLine($\"Formatted: {formatted}\");\n                var isRecoverable = resolver.TryResolveType(formatted, out var resolved) && resolved == type;\n                var resolvedFormatted = resolved is not null ? RuntimeTypeNameFormatter.Format(resolved) : \"null\";\n                Assert.True(isRecoverable, $\"Type.GetType(\\\"{formatted}\\\") must be equal to the original type. Got: {resolvedFormatted}\");\n            }\n        }\n\n        /// <summary>\n        /// Tests that various strings parsed by <see cref=\"RuntimeTypeNameParser\"/> are reformatted identically to their input, when the input was produced by <see cref=\"RuntimeTypeNameFormatter\"/>.\n        /// </summary>\n        [Fact]\n        public void ParsedTypeNamesAreIdenticalToFormattedNames()\n        {\n            foreach (var type in _types)\n            {\n                var formatted = RuntimeTypeNameFormatter.Format(type);\n                var parsed = RuntimeTypeNameParser.Parse(formatted);\n                _output.WriteLine($\"Type.FullName: {type.FullName}\");\n                _output.WriteLine($\"Formatted    : {formatted}\");\n                _output.WriteLine($\"Parsed       : {parsed}\");\n                Assert.Equal(formatted, parsed.Format());\n\n                var reparsed = RuntimeTypeNameParser.Parse(parsed.Format());\n                _output.WriteLine($\"Reparsed     : {reparsed}\");\n                Assert.Equal(formatted, reparsed.Format());\n            }\n        }\n\n        /// <summary>\n        /// Tests that parsing invalid type names produces descriptive error messages with position indicators.\n        /// This helps developers debug type resolution issues in Orleans serialization.\n        /// </summary>\n        [Fact]\n        public void InvalidNamesThrowDescriptiveErrorMessage()\n        {\n            var input = \"MalformedName[`\";\n            var exception = Assert.Throws<InvalidOperationException>(() => RuntimeTypeNameParser.Parse(input));\n            _output.WriteLine(exception.Message);\n            Assert.Contains(input, exception.Message);\n            Assert.Contains(\"^\", exception.Message); // Position indicator\n        }\n        \n        public class Inner<T>\n        {\n            public class Middle { }\n            public class InnerInner<U, V>\n            {\n                public class Bottom { }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/SchedulerTests/OrleansTaskSchedulerAdvancedTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Internal;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.SchedulerTests\n{\n    /// <summary>\n    /// Advanced tests for Orleans task scheduler functionality.\n    /// </summary>\n    public class OrleansTaskSchedulerAdvancedTests(ITestOutputHelper output) : IDisposable\n    {\n        private static readonly TimeSpan WaitTimeout = TimeSpan.FromSeconds(10);\n        private readonly ILoggerFactory _loggerFactory = OrleansTaskSchedulerBasicTests.InitSchedulerLogging();\n\n        public void Dispose()\n        {\n            _loggerFactory.Dispose();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_Test()\n        {\n            var n = 0;\n            var insideTask = false;\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            output.WriteLine(\"Running Main in Context=\" + RuntimeContext.Current);\n            var tasksTask = new TaskCompletionSource<List<Task>>();\n            var gates = new SemaphoreSlim[10];\n            for (var i = 0; i < 10; i++)\n            {\n                gates[i] = new SemaphoreSlim(0, 1);\n            }\n\n            context.Scheduler.QueueAction(() =>\n                {\n                    var tasks = new List<Task>(10);\n                    for (var i = 0; i < 10; i++)\n                    {\n                        var taskNum = i;\n                        tasks.Add(Task.Factory.StartNew(() =>\n                        {\n                            output.WriteLine(\"Starting \" + taskNum + \" in Context=\" + RuntimeContext.Current);\n                            Assert.False(insideTask, $\"Starting new task when I am already inside task of iteration {n}\");\n                            insideTask = true;\n\n                            // Exacerbate the chance of a data race in the event that two of these tasks run concurrently.\n                            var k = n;\n                            gates[taskNum].Wait();\n                            n = k + 1;\n\n                            insideTask = false;\n                        },\n                        CancellationToken.None,\n                        TaskCreationOptions.None,\n                        TaskScheduler.Current));\n                    }\n                    tasksTask.SetResult(tasks);\n\n                    // Release all gates in sequence to ensure sequential execution\n                    for (var i = 0; i < 10; i++)\n                    {\n                        gates[i].Release();\n                    }\n                });\n\n            await Task.WhenAll(await tasksTask.Task);\n\n            // N should be 10, because all tasks should execute serially\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(10, n);  // \"Work items executed concurrently\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_WaitTest()\n        {\n            var n = 0;\n            var insideTask = false;\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            var result = new TaskCompletionSource<bool>();\n            var gate = new SemaphoreSlim(0, 1);\n\n            context.Scheduler.QueueAction(() =>\n                {\n                    var task1 = Task.Factory.StartNew(() =>\n                    {\n                        output.WriteLine(\"Starting 1\");\n                        Assert.False(insideTask, $\"Starting new task when I am already inside task of iteration {n}\");\n                        insideTask = true;\n                        output.WriteLine(\"===> 1a\");\n                        gate.Wait();\n                        n = n + 3;\n                        output.WriteLine(\"===> 1b\");\n                        insideTask = false;\n                    });\n                    var task2 = Task.Factory.StartNew(() =>\n                    {\n                        output.WriteLine(\"Starting 2\");\n                        Assert.False(insideTask, $\"Starting new task when I am already inside task of iteration {n}\");\n                        insideTask = true;\n                        output.WriteLine(\"===> 2a\");\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                        task1.Wait();\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                        output.WriteLine(\"===> 2b\");\n                        n = n * 5;\n                        output.WriteLine(\"===> 2c\");\n                        insideTask = false;\n                        result.SetResult(true);\n                    });\n                    task1.Ignore();\n                    task2.Ignore();\n\n                    // Release the gate to allow task1 to complete\n                    gate.Release();\n                });\n\n            var timeoutLimit = TimeSpan.FromMilliseconds(3000);\n            try\n            {\n                await result.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(15, n);  // \"Work items executed out of order\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_Turn_Execution_Order()\n        {\n            // Can we add a unit test that basicaly checks that any turn is indeed run till completion before any other turn?\n            // For example, you have a  long running main turn and in the middle it spawns a lot of short CWs (on Done promise) and StartNew.\n            // You test that no CW/StartNew runs until the main turn is fully done. And run in stress.\n\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            var result1 = new TaskCompletionSource<bool>();\n            var result2 = new TaskCompletionSource<bool>();\n            var mainTurnGate = new TaskCompletionSource<bool>();\n            var mainDone = false;\n            var stageNum1 = 0;\n            var stageNum2 = 0;\n\n            context.Scheduler.QueueAction(() =>\n            {\n                mainDone = false;\n                stageNum1 = stageNum2 = 0;\n\n                var task1 = Task.Factory.StartNew(() => SubProcess1(11));\n                var task2 = task1.ContinueWith((_) => SubProcess1(12));\n                var task3 = task2.ContinueWith((_) => SubProcess1(13));\n                var task4 = task3.ContinueWith((_) => { SubProcess1(14); result1.SetResult(true); });\n                task4.Ignore();\n\n                var task21 = Task.CompletedTask.ContinueWith((_) => SubProcess2(21));\n                var task22 = task21.ContinueWith((_) => { SubProcess2(22); result2.SetResult(true); });\n                task22.Ignore();\n\n                // Wait for the gate to ensure ordering\n                mainTurnGate.Task.Wait();\n                mainDone = true;\n            });\n\n            // Release the gate to allow main turn to complete\n            mainTurnGate.SetResult(true);\n\n            try { await result1.Task.WaitAsync(WaitTimeout); }\n            catch (TimeoutException) { Assert.Fail(\"Timeout-1\"); }\n            try { await result2.Task.WaitAsync(WaitTimeout); }\n            catch (TimeoutException) { Assert.Fail(\"Timeout-2\"); }\n\n            Assert.NotEqual(0, stageNum1); // \"Work items did not get executed-1\"\n            Assert.NotEqual(0, stageNum2);  // \"Work items did not get executed-2\"\n            Assert.Equal(14, stageNum1);  // \"Work items executed out of order-1\"\n            Assert.Equal(22, stageNum2);  // \"Work items executed out of order-2\"\n\n            void SubProcess1(int n)\n            {\n                var msg = string.Format(\"1-{0} MainDone={1} inside Task {2}\", n, mainDone, Task.CurrentId);\n                output.WriteLine(\"1 ===> \" + msg);\n                Assert.True(mainDone, msg + \" -- Main turn should be finished\");\n                stageNum1 = n;\n            }\n\n            void SubProcess2(int n)\n            {\n                var msg = string.Format(\"2-{0} MainDone={1} inside Task {2}\", n, mainDone, Task.CurrentId);\n                output.WriteLine(\"2 ===> \" + msg);\n                Assert.True(mainDone, msg + \" -- Main turn should be finished\");\n                stageNum2 = n;\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_Stopped_WorkItemGroup()\n        {\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            void CheckScheduler(object state)\n            {\n                Assert.IsType<string>(state);\n                Assert.Equal(\"some state\", state as string);\n                Assert.IsType<ActivationTaskScheduler>(TaskScheduler.Current);\n            }\n\n            Task<Task> ScheduleTask() => Task.Factory.StartNew(\n                state =>\n                {\n                    CheckScheduler(state);\n\n                    return Task.Factory.StartNew(\n                        async s =>\n                        {\n                            CheckScheduler(s);\n                            await Task.Delay(50);\n                            CheckScheduler(s);\n                        },\n                        state, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current).Unwrap();\n                },\n                \"some state\",\n                CancellationToken.None,\n                TaskCreationOptions.DenyChildAttach,\n                context.WorkItemGroup.TaskScheduler);\n\n            // Check that the WorkItemGroup is functioning.\n            await await ScheduleTask();\n\n            var taskAfterStopped = ScheduleTask();\n            var resultTask = await Task.WhenAny(taskAfterStopped, Task.Delay(WaitTimeout));\n            Assert.Same(taskAfterStopped, resultTask);\n\n            await await taskAfterStopped;\n\n            // Wait for the WorkItemGroup to upgrade the warning to an error and try again.\n            // This delay is based upon SchedulingOptions.StoppedActivationWarningInterval.\n            await Task.Delay(TimeSpan.FromMilliseconds(300));\n\n            taskAfterStopped = ScheduleTask();\n            resultTask = await Task.WhenAny(taskAfterStopped, Task.Delay(WaitTimeout));\n            Assert.Same(taskAfterStopped, resultTask);\n\n            await await taskAfterStopped;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_Task_Turn_Execution_Order()\n        {\n            // A unit test that checks that any turn is indeed run till completion before any other turn?\n            // For example, you have a long running main turn and in the middle it spawns a lot of short CWs (on Done promise) and StartNew.\n            // You test that no CW/StartNew runs until the main turn is fully done. And run in stress.\n\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n            var activationScheduler = context.WorkItemGroup.TaskScheduler;\n\n            var mainDone = false;\n            var stageNum1 = 0;\n            var stageNum2 = 0;\n\n            var result1 = new TaskCompletionSource<bool>();\n            var result2 = new TaskCompletionSource<bool>();\n            var wrapperGate = new TaskCompletionSource<bool>();\n            var mainTurnGate = new TaskCompletionSource<bool>();\n\n            Task wrapper = null;\n            Task finalTask1 = null;\n            Task finalPromise2 = null;\n            var wrapperCreated = new TaskCompletionSource<Task>();\n\n            context.Scheduler.QueueAction(() =>\n            {\n                Log(1, \"Outer ClosureWorkItem \" + Task.CurrentId + \" starting\");\n                Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #0\"\n\n                Log(2, \"Starting wrapper Task\");\n                wrapper = Task.Factory.StartNew(() =>\n                {\n                    Log(3, \"Inside wrapper Task Id=\" + Task.CurrentId);\n                    Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #1\"\n\n                    // Execution chain #1\n                    Log(4, \"Wrapper Task Id=\" + Task.CurrentId + \" creating Task chain\");\n                    var task1 = Task.Factory.StartNew(() =>\n                    {\n                        Log(5, \"#11 Inside sub-Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #11\"\n                        SubProcess1(11);\n                    });\n                    var task2 = task1.ContinueWith((Task task) =>\n                    {\n                        Log(6, \"#12 Inside continuation Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #12\"\n                        if (task.IsFaulted) throw task.Exception.Flatten();\n                        SubProcess1(12);\n                    });\n                    var task3 = task2.ContinueWith(task =>\n                    {\n                        Log(7, \"#13 Inside continuation Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #13\"\n                        if (task.IsFaulted) throw task.Exception.Flatten();\n                        SubProcess1(13);\n                    });\n                    finalTask1 = task3.ContinueWith(task =>\n                    {\n                        Log(8, \"#14 Inside final continuation Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #14\"\n                        if (task.IsFaulted) throw task.Exception.Flatten();\n                        SubProcess1(14);\n                        result1.SetResult(true);\n                    });\n\n                    // Execution chain #2\n                    Log(9, \"Wrapper Task \" + Task.CurrentId + \" creating AC chain\");\n                    var promise2 = Task.Factory.StartNew(() =>\n                    {\n                        Log(10, \"#21 Inside sub-Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #21\"\n                        SubProcess2(21);\n                    });\n                    finalPromise2 = promise2.ContinueWith((_) =>\n                    {\n                        Log(11, \"#22 Inside final continuation Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #22\"\n                        SubProcess2(22);\n                        result2.SetResult(true);\n                    });\n                    finalPromise2.Ignore();\n\n                    Log(12, \"Wrapper Task Id=\" + Task.CurrentId + \" waiting for gate\");\n                    wrapperGate.Task.Wait();\n\n                    Log(13, \"Wrapper Task Id=\" + Task.CurrentId + \" finished\");\n\n                    void SubProcess1(int n)\n                    {\n                        var msg = string.Format(\"1-{0} MainDone={1} inside Task {2}\", n, mainDone, Task.CurrentId);\n                        output.WriteLine(\"1 ===> \" + msg);\n                        Assert.True(mainDone, msg + \" -- Main turn should be finished\");\n                        stageNum1 = n;\n                    }\n\n                    void SubProcess2(int n)\n                    {\n                        var msg = string.Format(\"2-{0} MainDone={1} inside Task {2}\", n, mainDone, Task.CurrentId);\n                        output.WriteLine(\"2 ===> \" + msg);\n                        Assert.True(mainDone, msg + \" -- Main turn should be finished\");\n                        stageNum2 = n;\n                    }\n                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);\n\n                wrapperCreated.SetResult(wrapper);\n\n                Log(14, \"Outer ClosureWorkItem Task Id=\" + Task.CurrentId + \" waiting for gate\");\n                mainTurnGate.Task.Wait();\n                Log(15, \"Outer ClosureWorkItem Task Id=\" + Task.CurrentId + \" continuing\");\n\n                Log(16, \"Finished Outer ClosureWorkItem Task Id=\" + wrapper.Id);\n                mainDone = true;\n            });\n\n            Log(17, \"Waiting for ClosureWorkItem to spawn wrapper Task\");\n            wrapper = await wrapperCreated.Task.WaitAsync(WaitTimeout);\n            Assert.NotNull(wrapper); // Wrapper Task was not created\n\n            // Release gates to allow execution to proceed\n            wrapperGate.SetResult(true);\n            mainTurnGate.SetResult(true);\n\n            Log(18, \"Waiting for wrapper Task Id=\" + wrapper.Id + \" to complete\");\n            await wrapper.WaitAsync(WaitTimeout);\n            Assert.False(wrapper.IsFaulted, \"Wrapper Task faulted: \" + wrapper.Exception);\n            Assert.True(wrapper.IsCompleted, \"Wrapper Task should be completed\");\n\n            Log(20, \"Waiting for TaskWorkItem to complete\");\n            // Wait for mainDone using a reasonable timeout\n            for (var i = 0; i < 100 && !mainDone; i++)\n            {\n                await Task.Delay(10);\n            }\n            Log(21, \"Done waiting for TaskWorkItem to complete MainDone=\" + mainDone);\n            Assert.True(mainDone, \"Main Task should be completed\");\n            Assert.NotNull(finalTask1); // Task chain #1 not created\n            Assert.NotNull(finalPromise2); // Task chain #2 not created\n\n            Log(22, \"Waiting for final task #1 to complete\");\n            await finalTask1.WaitAsync(WaitTimeout);\n            Assert.False(finalTask1.IsFaulted, \"Final Task faulted: \" + finalTask1.Exception);\n            Assert.True(finalTask1.IsCompleted, \"Final Task completed\");\n            Assert.True(await result1.Task, \"Timeout-1\");\n\n            Log(24, \"Waiting for final promise #2 to complete\");\n            await finalPromise2.WaitAsync(WaitTimeout);\n            Log(25, \"Done waiting for final promise #2\");\n            Assert.False(finalPromise2.IsFaulted, \"Final Task faulted: \" + finalPromise2.Exception);\n            Assert.True(finalPromise2.IsCompleted, \"Final Task completed\");\n            Assert.True(await result2.Task, \"Timeout-2\");\n\n            Assert.NotEqual(0, stageNum1);  // \"Work items did not get executed-1\"\n            Assert.Equal(14, stageNum1);  // \"Work items executed out of order-1\"\n            Assert.NotEqual(0, stageNum2);  // \"Work items did not get executed-2\"\n            Assert.Equal(22, stageNum2);  // \"Work items executed out of order-2\"\n\n\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_Current_TaskScheduler()\n        {\n            UnitTestSchedulingContext context = UnitTestSchedulingContext.Create(_loggerFactory);\n            var activationScheduler = context.WorkItemGroup.TaskScheduler;\n\n            var mainDone = false;\n            var stageNum1 = 0;\n\n            var result = new TaskCompletionSource<bool>();\n            var wrapperGate = new TaskCompletionSource<bool>();\n            var mainTurnGate = new TaskCompletionSource<bool>();\n\n            Task wrapper = null;\n            Task finalPromise = null;\n            var wrapperCreated = new TaskCompletionSource<Task>();\n\n            context.Scheduler.QueueAction(() =>\n            {\n                Log(1, \"Outer ClosureWorkItem \" + Task.CurrentId + \" starting\");\n                Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #0\"\n\n                Log(2, \"Starting wrapper Task\");\n                wrapper = Task.Factory.StartNew(() =>\n                {\n                    Log(3, \"Inside wrapper Task Id=\" + Task.CurrentId);\n                    Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #1\"\n\n                    Log(4, \"Wrapper Task \" + Task.CurrentId + \" creating AC chain\");\n                    var promise1 = Task.Factory.StartNew(() =>\n                    {\n                        Log(5, \"#1 Inside AC Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #1\"\n                        SubProcess1(1);\n                    });\n                    var promise2 = promise1.ContinueWith((_) =>\n                    {\n                        Log(6, \"#2 Inside AC Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #2\"\n                        SubProcess1(2);\n                    });\n                    finalPromise = promise2.ContinueWith((_) =>\n                    {\n                        Log(7, \"#3 Inside final AC Task Id=\" + Task.CurrentId);\n                        Assert.Equal(activationScheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #3\"\n                        SubProcess1(3);\n                        result.SetResult(true);\n                    });\n                    finalPromise.Ignore();\n\n                    Log(8, \"Wrapper Task Id=\" + Task.CurrentId + \" waiting for gate\");\n                    wrapperGate.Task.Wait();\n\n                    Log(9, \"Wrapper Task Id=\" + Task.CurrentId + \" finished\");\n\n                    void SubProcess1(int n)\n                    {\n                        var msg = string.Format(\"1-{0} MainDone={1} inside Task {2}\", n, mainDone, Task.CurrentId);\n                        output.WriteLine(\"1 ===> \" + msg);\n                        Assert.True(mainDone, msg + \" -- Main turn should be finished\");\n                        stageNum1 = n;\n                    }\n                });\n\n                wrapperCreated.SetResult(wrapper);\n\n                Log(10, \"Outer ClosureWorkItem Task Id=\" + Task.CurrentId + \" waiting for gate\");\n                mainTurnGate.Task.Wait();\n                Log(11, \"Outer ClosureWorkItem Task Id=\" + Task.CurrentId + \" continuing\");\n\n                Log(12, \"Finished Outer TaskWorkItem Task Id=\" + wrapper.Id);\n                mainDone = true;\n            });\n\n            Log(13, \"Waiting for ClosureWorkItem to spawn wrapper Task\");\n            wrapper = await wrapperCreated.Task.WaitAsync(WaitTimeout);\n            Assert.NotNull(wrapper); // Wrapper Task was not created\n\n            // Release gates to allow execution to proceed\n            wrapperGate.SetResult(true);\n            mainTurnGate.SetResult(true);\n\n            Log(14, \"Waiting for wrapper Task Id=\" + wrapper.Id + \" to complete\");\n            await wrapper.WaitAsync(WaitTimeout);\n            Assert.False(wrapper.IsFaulted, \"Wrapper Task faulted: \" + wrapper.Exception);\n            Assert.True(wrapper.IsCompleted, \"Wrapper Task should be completed\");\n\n            Log(16, \"Waiting for TaskWorkItem to complete\");\n            // Wait for mainDone using a reasonable timeout\n            for (var i = 0; i < 100 && !mainDone; i++)\n            {\n                await Task.Delay(10);\n            }\n            Log(17, \"Done waiting for TaskWorkItem to complete MainDone=\" + mainDone);\n            Assert.True(mainDone, \"Main Task should be completed\");\n            Assert.NotNull(finalPromise); // AC chain not created\n\n            Log(18, \"Waiting for final AC promise to complete\");\n            await finalPromise.WaitAsync(WaitTimeout);\n            Log(19, \"Done waiting for final promise\");\n            Assert.False(finalPromise.IsFaulted, \"Final AC faulted: \" + finalPromise.Exception);\n            Assert.True(finalPromise.IsCompleted, \"Final AC completed\");\n            Assert.True(await result.Task, \"Timeout-1\");\n\n            Assert.NotEqual(0, stageNum1);  // \"Work items did not get executed-1\"\n            Assert.Equal(3, stageNum1);  // \"Work items executed out of order-1\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_ContinueWith_1_Test()\n        {\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            var result = new TaskCompletionSource<bool>();\n            var gate = new SemaphoreSlim(0, 1);\n            var n = 0;\n            // ReSharper disable AccessToModifiedClosure\n            context.Scheduler.QueueAction(() =>\n            {\n                var task1 = Task.Factory.StartNew(() => { output.WriteLine(\"===> 1a\"); gate.Wait(); n = n + 3; output.WriteLine(\"===> 1b\"); });\n                var task2 = task1.ContinueWith((_) => { n = n * 5; output.WriteLine(\"===> 2\"); });\n                var task3 = task2.ContinueWith((_) => { n = n / 5; output.WriteLine(\"===> 3\"); });\n                var task4 = task3.ContinueWith((_) => { n = n - 2; output.WriteLine(\"===> 4\"); result.SetResult(true); });\n                task4.Ignore();\n\n                // Release the gate to allow task1 to complete\n                gate.Release();\n            });\n            // ReSharper restore AccessToModifiedClosure\n\n            await result.Task.WaitAsync(WaitTimeout);\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(1, n);  // \"Work items executed out of order\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Sched_Task_JoinAll()\n        {\n            var result = new TaskCompletionSource<bool>();\n            var n = 0;\n            Task<int>[] tasks = null;\n            var gates = new SemaphoreSlim[4];\n            for (var i = 0; i < 4; i++)\n            {\n                gates[i] = new SemaphoreSlim(0, 1);\n            }\n\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            context.Scheduler.QueueAction(() =>\n            {\n                var task1 = Task<int>.Factory.StartNew(() => { output.WriteLine(\"===> 1a\"); gates[0].Wait(); n = n + 3; output.WriteLine(\"===> 1b\"); return 1; });\n                var task2 = Task<int>.Factory.StartNew(() => { output.WriteLine(\"===> 2a\"); gates[1].Wait(); n = n + 3; output.WriteLine(\"===> 2b\"); return 2; });\n                var task3 = Task<int>.Factory.StartNew(() => { output.WriteLine(\"===> 3a\"); gates[2].Wait(); n = n + 3; output.WriteLine(\"===> 3b\"); return 3; });\n                var task4 = Task<int>.Factory.StartNew(() => { output.WriteLine(\"===> 4a\"); gates[3].Wait(); n = n + 3; output.WriteLine(\"===> 4b\"); return 4; });\n                tasks = new Task<int>[] { task1, task2, task3, task4 };\n                result.SetResult(true);\n\n                // Release all gates in sequence\n                for (var i = 0; i < 4; i++)\n                {\n                    gates[i].Release();\n                }\n            });\n\n            await result.Task.WaitAsync(WaitTimeout); // Wait for main (one that creates tasks) work item to finish.\n\n            var promise = Task<int[]>.Factory.ContinueWhenAll(tasks, (res) =>\n            {\n                List<int> output = new List<int>();\n                var taskNum = 1;\n                foreach (var t in tasks)\n                {\n                    Assert.True(t.IsCompleted, \"Sub-Task completed\");\n                    Assert.False(t.IsFaulted, \"Sub-Task faulted: \" + t.Exception);\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                    var val = t.Result;\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                    Assert.Equal(taskNum, val);  // \"Value returned by Task \" + taskNum\n                    output.Add(val);\n                    taskNum++;\n                }\n                var results = output.ToArray();\n                return results;\n            });\n\n            await promise.WaitAsync(WaitTimeout);\n\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(12, n);  // \"Not all work items executed\"\n            var ms = stopwatch.ElapsedMilliseconds;\n            // Since we removed sleeps, execution should be much faster - just verify it completed\n            Assert.True(ms < 8000, \"Wait time too long: \" + ms);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_AC_ContinueWith_2_OrleansSched()\n        {\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n            var workItemGroup = context.WorkItemGroup;\n\n            var result1 = new TaskCompletionSource<bool>();\n            var result2 = new TaskCompletionSource<bool>();\n            var failed1 = false;\n            var failed2 = false;\n            var gate = new SemaphoreSlim(0, 1);\n\n            var task1 = Task.Factory.StartNew(\n                () => { output.WriteLine(\"===> 1a\"); gate.Wait(); throw new ArgumentException(); },\n                CancellationToken.None,\n                TaskCreationOptions.RunContinuationsAsynchronously,\n                workItemGroup.TaskScheduler);\n\n            var task2 = task1.ContinueWith((Task t) =>\n            {\n                if (!t.IsFaulted) output.WriteLine(\"===> 2\");\n                else\n                {\n                    output.WriteLine(\"===> 3\");\n                    failed1 = true;\n                    result1.SetResult(true);\n                }\n            },\n            workItemGroup.TaskScheduler);\n            var task3 = task1.ContinueWith((Task t) =>\n            {\n                if (!t.IsFaulted) output.WriteLine(\"===> 4\");\n                else\n                {\n                    output.WriteLine(\"===> 5\");\n                    failed2 = true;\n                    result2.SetResult(true);\n                }\n            },\n            workItemGroup.TaskScheduler);\n\n            task1.Ignore();\n            task2.Ignore();\n            task3.Ignore();\n\n            // Release the gate to allow task1 to throw\n            gate.Release();\n\n            await result1.Task.WaitAsync(WaitTimeout);\n            await result2.Task.WaitAsync(WaitTimeout);\n            Assert.True(failed1);  // \"First ContinueWith did not fire error handler.\"\n            Assert.True(failed2);  // \"Second ContinueWith did not fire error handler.\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_Task_SchedulingContext()\n        {\n            var context = UnitTestSchedulingContext.Create(_loggerFactory);\n\n            var result = new TaskCompletionSource<bool>();\n            Task endOfChain = null;\n            var n = 0;\n            var gate = new SemaphoreSlim(0, 1);\n\n            Task wrapper = new Task(() =>\n            {\n                CheckRuntimeContext(context);\n\n                // ReSharper disable AccessToModifiedClosure\n                var task1 = Task.Factory.StartNew(() =>\n                {\n                    output.WriteLine(\"===> 1a \");\n                    CheckRuntimeContext(context);\n                    gate.Wait();\n                    n = n + 3;\n                    output.WriteLine(\"===> 1b\");\n                    CheckRuntimeContext(context);\n                });\n                var task2 = task1.ContinueWith(task =>\n                {\n                    output.WriteLine(\"===> 2\");\n                    CheckRuntimeContext(context);\n                    n = n * 5;\n                });\n                var task3 = task2.ContinueWith(task =>\n                {\n                    output.WriteLine(\"===> 3\");\n                    n = n / 5;\n                    CheckRuntimeContext(context);\n                });\n                var task4 = task3.ContinueWith(task =>\n                {\n                    output.WriteLine(\"===> 4\");\n                    n = n - 2;\n                    result.SetResult(true);\n                    CheckRuntimeContext(context);\n                });\n                // ReSharper restore AccessToModifiedClosure\n                endOfChain = task4.ContinueWith(task =>\n                {\n                    output.WriteLine(\"Done Faulted={0}\", task.IsFaulted);\n                    CheckRuntimeContext(context);\n                    Assert.False(task.IsFaulted, \"Faulted with Exception=\" + task.Exception);\n                });\n\n                // Release the gate to allow task1 to complete\n                gate.Release();\n            });\n            wrapper.Start(context.WorkItemGroup.TaskScheduler);\n            await wrapper.WaitAsync(WaitTimeout);\n\n            Assert.False(wrapper.IsFaulted, \"Wrapper Task Faulted with Exception=\" + wrapper.Exception);\n            Assert.True(wrapper.IsCompleted, \"Wrapper Task completed\");\n            await result.Task.WaitAsync(WaitTimeout);\n            Assert.NotNull(endOfChain); // End of chain Task created successfully\n            Assert.False(endOfChain.IsFaulted, \"Task chain Faulted with Exception=\" + endOfChain.Exception);\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(1, n);  // \"Work items executed out of order\"\n        }\n\n        private void Log(int level, string what)\n        {\n            output.WriteLine(\"#{0} - {1} -- Thread={2} Worker={3} TaskScheduler.Current={4}\",\n                level, what,\n                Environment.CurrentManagedThreadId,\n                Thread.CurrentThread.Name,\n                TaskScheduler.Current);\n        }\n\n        private static void CheckRuntimeContext(IGrainContext context)\n        {\n            Assert.NotNull(RuntimeContext.Current); // Runtime context should not be null\n            Assert.NotNull(RuntimeContext.Current); // Activation context should not be null\n            Assert.Equal(context, RuntimeContext.Current);  // \"Activation context\"\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/SchedulerTests/OrleansTaskSchedulerAdvancedTests_Set2.cs",
    "content": "using System.Diagnostics;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Time.Testing;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Scheduler;\nusing Orleans.Runtime.TestHooks;\nusing Orleans.Statistics;\nusing TestExtensions;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.SchedulerTests\n{\n    /// <summary>\n    /// Second set of advanced tests for Orleans task scheduler.\n    /// </summary>\n    public class OrleansTaskSchedulerAdvancedTests_Set2 : IDisposable\n    {\n        private static readonly object Lockable = new object();\n        private static readonly int WaitFactor = Debugger.IsAttached ? 100 : 1;\n        private readonly ITestOutputHelper output;\n        private readonly UnitTestSchedulingContext context;\n        private readonly WorkItemGroup workItemGroup;\n        private readonly ActivationTaskScheduler scheduler;\n        private readonly IEnvironmentStatisticsProvider environmentStatisticsProvider;\n        private readonly ILoggerFactory loggerFactory;\n        public OrleansTaskSchedulerAdvancedTests_Set2(ITestOutputHelper output)\n        {\n            this.output = output;\n            this.loggerFactory = OrleansTaskSchedulerBasicTests.InitSchedulerLogging();\n            this.context = UnitTestSchedulingContext.Create(loggerFactory);\n            this.workItemGroup = context.WorkItemGroup;\n            this.scheduler = workItemGroup.TaskScheduler;\n            this.environmentStatisticsProvider = new TestHooksEnvironmentStatisticsProvider();\n        }\n\n        public void Dispose()\n        {\n            this.loggerFactory.Dispose();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_SimpleFifoTest()\n        {\n            // This is not a great test because there's a 50/50 shot that it will work even if the scheduling\n            // is completely and thoroughly broken and both closures are executed \"simultaneously\"\n\n            int n = 0;\n            var gate = new SemaphoreSlim(0, 1);\n            // ReSharper disable AccessToModifiedClosure\n            var task1 = new Task(() => { gate.Wait(); n = n + 5; });\n            Task task2 = new Task(() => { n = n * 3; });\n            // ReSharper restore AccessToModifiedClosure\n\n            task1.Start(scheduler);\n            task2.Start(scheduler);\n\n            // Release gate to allow task1 to proceed\n            gate.Release();\n\n            await task1;\n            await task2;\n\n            // N should be 15, because the two tasks should execute in order\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(15, n);  // \"Work items executed out of order\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_NewTask_ContinueWith_Wrapped()\n        {\n            Task<Task> wrapped = new Task<Task>(() =>\n            {\n                this.output.WriteLine(\"#0 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                    SynchronizationContext.Current, TaskScheduler.Current);\n\n                Task t0 = new Task(() =>\n                {\n                    this.output.WriteLine(\"#1 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                        SynchronizationContext.Current, TaskScheduler.Current);\n                    Assert.Equal(scheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #1\"\n                });\n                Task t1 = t0.ContinueWith(task =>\n                {\n                    Assert.False(task.IsFaulted, \"Task #1 Faulted=\" + task.Exception);\n\n                    this.output.WriteLine(\"#2 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                        SynchronizationContext.Current, TaskScheduler.Current);\n                    Assert.Equal(scheduler, TaskScheduler.Current);  // \"TaskScheduler.Current #2\"\n                });\n                t0.Start(scheduler);\n                return t1;\n            });\n            wrapped.Start(scheduler);\n            await wrapped.Unwrap().WaitAsync(TimeSpan.FromSeconds(10));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_SubTaskExecutionSequencing()\n        {\n            LogContext(\"Main-task \" + Task.CurrentId);\n\n            int n = 0;\n\n            var finished = new TaskCompletionSource();\n            int numCompleted = 0;\n            var gates = new SemaphoreSlim[10];\n            for (int i = 0; i < 10; i++)\n            {\n                gates[i] = new SemaphoreSlim(0, 1);\n            }\n\n            void action()\n            {\n                LogContext(\"WorkItem-task \" + Task.CurrentId);\n\n                for (int i = 0; i < 10; i++)\n                {\n                    int taskIndex = i;\n                    int id = -1;\n                    Task.Factory.StartNew(() =>\n                    {\n                        id = Task.CurrentId.HasValue ? (int)Task.CurrentId : -1;\n\n                        // ReSharper disable AccessToModifiedClosure\n                        LogContext(\"Sub-task \" + id + \" n=\" + n);\n                        int k = n;\n                        this.output.WriteLine(\"Sub-task \" + id + \" waiting for gate\");\n                        gates[taskIndex].Wait();\n                        this.output.WriteLine(\"Sub-task \" + id + \" awake\");\n                        n = k + 1;\n                        // ReSharper restore AccessToModifiedClosure\n                    })\n                    .ContinueWith(tsk =>\n                    {\n                        LogContext(\"Sub-task \" + id + \"-ContinueWith\");\n\n                        this.output.WriteLine(\"Sub-task \" + id + \" Done\");\n                        if (Interlocked.Increment(ref numCompleted) == 10)\n                        {\n                            finished.SetResult();\n                        }\n                    });\n                }\n\n                // Release all gates in sequence to ensure sequential execution\n                for (int i = 0; i < 10; i++)\n                {\n                    gates[i].Release();\n                }\n            }\n\n            Task t = new Task(action);\n\n            t.Start(scheduler);\n\n            // Wait for completion\n            this.output.WriteLine(\"Main-task waiting\");\n            await finished.Task;\n            this.output.WriteLine(\"Main-task done\");\n\n            // N should be 10, because all tasks should execute serially\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(10, n);  // \"Work items executed concurrently\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_ContinueWith_1_Test()\n        {\n            var result = new TaskCompletionSource<bool>();\n            int n = 0;\n            var gate = new SemaphoreSlim(0, 1);\n\n            Task wrapper = new Task(() =>\n            {\n                // ReSharper disable AccessToModifiedClosure\n                Task task1 = Task.Factory.StartNew(() => { this.output.WriteLine(\"===> 1a\"); gate.Wait(); n = n + 3; this.output.WriteLine(\"===> 1b\"); });\n                Task task2 = task1.ContinueWith(task => { n = n * 5; this.output.WriteLine(\"===> 2\"); });\n                Task task3 = task2.ContinueWith(task => { n = n / 5; this.output.WriteLine(\"===> 3\"); });\n                Task task4 = task3.ContinueWith(task => { n = n - 2; this.output.WriteLine(\"===> 4\"); result.SetResult(true); });\n                // ReSharper restore AccessToModifiedClosure\n                task4.ContinueWith(task =>\n                {\n                    this.output.WriteLine(\"Done Faulted={0}\", task.IsFaulted);\n                    Assert.False(task.IsFaulted, \"Faulted with Exception=\" + task.Exception);\n                });\n\n                // Release gate to allow task1 to complete\n                gate.Release();\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await result.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(1, n);  // \"Work items executed out of order\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_WhenAny()\n        {\n            ManualResetEvent pause1 = new ManualResetEvent(false);\n            ManualResetEvent pause2 = new ManualResetEvent(false);\n            var finish = new TaskCompletionSource<bool>();\n            Task<int> task1 = null;\n            Task<int> task2 = null;\n            Task join = null;\n            Task wrapper = new Task(() =>\n            {\n                task1 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-1 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);  // \"TaskScheduler.Current=\" + TaskScheduler.Current\n                    pause1.WaitOne();\n                    this.output.WriteLine(\"Task-1 Done\");\n                    return 1;\n                });\n                task2 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-2 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    pause2.WaitOne();\n                    this.output.WriteLine(\"Task-2 Done\");\n                    return 2;\n                });\n\n                join = Task.WhenAny(task1, task2, Task.Delay(TimeSpan.FromSeconds(2)));\n\n                finish.SetResult(true);\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await finish.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            pause1.Set();\n            await join;\n            Assert.True(join.IsCompleted && !join.IsFaulted, \"Join Status \" + join.Status);\n            Assert.False(task1.IsFaulted, \"Task-1 Faulted \" + task1.Exception);\n            Assert.False(task2.IsFaulted, \"Task-2 Faulted \" + task2.Exception);\n            Assert.True(task1.IsCompleted || task2.IsCompleted, \"Task-1 Status = \" + task1.Status + \" Task-2 Status = \" + task2.Status);\n            pause2.Set();\n            task2.Ignore();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_WhenAny_Timeout()\n        {\n            ManualResetEvent pause1 = new ManualResetEvent(false);\n            ManualResetEvent pause2 = new ManualResetEvent(false);\n            var finish = new TaskCompletionSource<bool>();\n            var fakeTimeProvider = new FakeTimeProvider();\n            Task<int> task1 = null;\n            Task<int> task2 = null;\n            Task join = null;\n            Task wrapper = new Task(() =>\n            {\n                task1 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-1 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    pause1.WaitOne();\n                    this.output.WriteLine(\"Task-1 Done\");\n                    return 1;\n                });\n                task2 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-2 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    pause2.WaitOne();\n                    this.output.WriteLine(\"Task-2 Done\");\n                    return 2;\n                });\n\n                join = Task.WhenAny(task1, task2, Task.Delay(TimeSpan.FromSeconds(2), fakeTimeProvider));\n\n                finish.SetResult(true);\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await finish.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            // Advance time to trigger the delay timeout\n            fakeTimeProvider.Advance(TimeSpan.FromSeconds(2));\n\n            Assert.NotNull(join);\n            await join;\n            Assert.True(join.IsCompleted && !join.IsFaulted, \"Join Status \" + join.Status);\n            Assert.False(task1.IsFaulted, \"Task-1 Faulted \" + task1.Exception);\n            Assert.False(task1.IsCompleted, \"Task-1 Status \" + task1.Status);\n            Assert.False(task2.IsFaulted, \"Task-2 Faulted \" + task2.Exception);\n            Assert.False(task2.IsCompleted, \"Task-2 Status \" + task2.Status);\n            pause1.Set();\n            task1.Ignore();\n            pause2.Set();\n            task2.Ignore();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_WhenAny_Busy_Timeout()\n        {\n            var pause1 = new TaskCompletionSource<bool>();\n            var pause2 = new TaskCompletionSource<bool>();\n            var finish = new TaskCompletionSource<bool>();\n            var fakeTimeProvider = new FakeTimeProvider();\n            Task<int> task1 = null;\n            Task<int> task2 = null;\n            Task join = null;\n            Task wrapper = new Task(() =>\n            {\n                task1 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-1 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    int num1 = 1;\n                    pause1.Task.Wait();\n                    this.output.WriteLine(\"Task-1 Done\");\n                    return num1;\n                });\n                task2 = Task<int>.Factory.StartNew(() =>\n                {\n                    this.output.WriteLine(\"Task-2 Started\");\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    int num2 = 2;\n                    pause2.Task.Wait();\n                    this.output.WriteLine(\"Task-2 Done\");\n                    return num2;\n                });\n\n                var delayTask = Task.Delay(TimeSpan.FromSeconds(2), fakeTimeProvider);\n\n                // Advance time immediately to trigger the delay\n                fakeTimeProvider.Advance(TimeSpan.FromSeconds(2));\n\n                join = Task.WhenAny(task1, task2, delayTask);\n\n                finish.SetResult(true);\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await finish.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            Assert.NotNull(join); // Joined promise assigned\n            await join;\n            Assert.True(join.IsCompleted && !join.IsFaulted, \"Join Status \" + join.Status);\n            Assert.False(task1.IsFaulted, \"Task-1 Faulted \" + task1.Exception);\n            Assert.False(task1.IsCompleted, \"Task-1 Status \" + task1.Status);\n            Assert.False(task2.IsFaulted, \"Task-2 Faulted \" + task2.Exception);\n            Assert.False(task2.IsCompleted, \"Task-2 Status \" + task2.Status);\n        }\n\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Task_Run()\n        {\n            ManualResetEvent pause1 = new ManualResetEvent(false);\n            ManualResetEvent pause2 = new ManualResetEvent(false);\n            var finish = new TaskCompletionSource<bool>();\n            Task<int> task1 = null;\n            Task<int> task2 = null;\n            Task join = null;\n            Task wrapper = new Task(() =>\n            {\n                task1 = Task.Run(() =>\n                {\n                    this.output.WriteLine(\"Task-1 Started\");\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    pause1.WaitOne();\n                    this.output.WriteLine(\"Task-1 Done\");\n                    return 1;\n                });\n                task2 = Task.Run(() =>\n                {\n                    this.output.WriteLine(\"Task-2 Started\");\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    pause2.WaitOne();\n                    this.output.WriteLine(\"Task-2 Done\");\n                    return 2;\n                });\n\n                join = Task.WhenAll(task1, task2).ContinueWith(t =>\n                {\n                    this.output.WriteLine(\"Join Started\");\n                    if (t.IsFaulted) throw t.Exception;\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    this.output.WriteLine(\"Join Done\");\n                });\n\n                finish.SetResult(true);\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await finish.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            pause1.Set();\n            pause2.Set();\n            Assert.NotNull(join); // Joined promise assigned\n            await join;\n            Assert.True(join.IsCompleted && !join.IsFaulted, \"Join Status \" + join);\n            Assert.True(task1.IsCompleted && !task1.IsFaulted, \"Task-1 Status \" + task1);\n            Assert.True(task2.IsCompleted && !task2.IsFaulted, \"Task-2 Status \" + task2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Task_Run_Delay()\n        {\n            ManualResetEvent pause1 = new ManualResetEvent(false);\n            ManualResetEvent pause2 = new ManualResetEvent(false);\n            var finish = new TaskCompletionSource<bool>();\n            Task<int> task1 = null;\n            Task<int> task2 = null;\n            Task join = null;\n            Task wrapper = new Task(() =>\n            {\n                task1 = Task.Run(() =>\n                {\n                    this.output.WriteLine(\"Task-1 Started\");\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    Task.Delay(1);\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    pause1.WaitOne();\n                    this.output.WriteLine(\"Task-1 Done\");\n                    return 1;\n                });\n                task2 = Task.Run(() =>\n                {\n                    this.output.WriteLine(\"Task-2 Started\");\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    Task.Delay(1);\n                    Assert.NotEqual(scheduler, TaskScheduler.Current);\n                    pause2.WaitOne();\n                    this.output.WriteLine(\"Task-2 Done\");\n                    return 2;\n                });\n\n                join = Task.WhenAll(task1, task2).ContinueWith(t =>\n                {\n                    this.output.WriteLine(\"Join Started\");\n                    if (t.IsFaulted) throw t.Exception;\n                    Assert.Equal(scheduler, TaskScheduler.Current);\n                    this.output.WriteLine(\"Join Done\");\n                });\n\n                finish.SetResult(true);\n            });\n            wrapper.Start(scheduler);\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await finish.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n\n            pause1.Set();\n            pause2.Set();\n            Assert.NotNull(join); // Joined promise assigned\n            await join;\n            Assert.True(join.IsCompleted && !join.IsFaulted, \"Join Status \" + join);\n            Assert.True(task1.IsCompleted && !task1.IsFaulted, \"Task-1 Status \" + task1);\n            Assert.True(task2.IsCompleted && !task2.IsFaulted, \"Task-2 Status \" + task2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Task_Delay()\n        {\n            Task<Task> wrapper = new Task<Task>(async () =>\n            {\n                Assert.Equal(scheduler, TaskScheduler.Current);\n                await DoDelay(1);\n                Assert.Equal(scheduler, TaskScheduler.Current);\n                await DoDelay(2);\n                Assert.Equal(scheduler, TaskScheduler.Current);\n            });\n            wrapper.Start(scheduler);\n\n            await wrapper.Unwrap();\n        }\n\n        private async Task DoDelay(int i)\n        {\n            try\n            {\n                this.output.WriteLine(\"Before Task.Delay #{0} TaskScheduler.Current={1}\", i, TaskScheduler.Current);\n                await Task.Delay(1);\n                this.output.WriteLine(\"After Task.Delay #{0} TaskScheduler.Current={1}\", i, TaskScheduler.Current);\n            }\n            catch (ObjectDisposedException)\n            {\n                // Ignore any problems with ObjectDisposedException if console output stream has already been closed\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Turn_Execution_Order_Loop()\n        {\n            const int NumChains = 10;\n            const int ChainLength = 3;\n            // Can we add a unit test that basicaly checks that any turn is indeed run till completion before any other turn?\n            // For example, you have a long running main turn and in the middle it spawns a lot of short CWs (on Done promise) and StartNew.\n            // You test that no CW/StartNew runs until the main turn is fully done. And run in stress.\n\n            var resultHandles = new TaskCompletionSource<bool>[NumChains];\n            Task[] taskChains = new Task[NumChains];\n            Task[] taskChainEnds = new Task[NumChains];\n            bool[] executingChain = new bool[NumChains];\n            int[] stageComplete = new int[NumChains];\n            int executingGlobal = -1;\n            var gates = new ManualResetEventSlim[NumChains];\n\n            for (int i = 0; i < NumChains; i++)\n            {\n                gates[i] = new ManualResetEventSlim(false);\n                int chainNum = i; // Capture\n                resultHandles[chainNum] = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n                Task task = taskChains[chainNum] = new Task(() =>\n                {\n                    const int taskNum = 0;\n                    try\n                    {\n                        Assert.Equal(-1, executingGlobal);  // \"Detected unexpected other execution in chain \" + chainNum + \" Task \" + taskNum\n                        Assert.False(executingChain[chainNum], \"Detected unexpected other execution on chain \" + chainNum + \" Task \" + taskNum);\n\n                        executingGlobal = chainNum;\n                        executingChain[chainNum] = true;\n\n                        gates[chainNum].Wait();\n                    }\n                    finally\n                    {\n                        stageComplete[chainNum] = taskNum;\n                        executingChain[chainNum] = false;\n                        executingGlobal = -1;\n                    }\n                });\n                for (int j = 1; j < ChainLength; j++)\n                {\n                    int taskNum = j; // Capture\n                    task = task.ContinueWith(t =>\n                    {\n                        if (t.IsFaulted) throw t.Exception;\n                        this.output.WriteLine(\"Inside Chain {0} Task {1}\", chainNum, taskNum);\n                        try\n                        {\n                            Assert.Equal(-1, executingGlobal);  // \"Detected unexpected other execution in chain \" + chainNum + \" Task \" + taskNum\n                            Assert.False(executingChain[chainNum], \"Detected unexpected other execution on chain \" + chainNum + \" Task \" + taskNum);\n                            Assert.Equal(taskNum - 1, stageComplete[chainNum]);  // \"Detected unexpected execution stage on chain \" + chainNum + \" Task \" + taskNum\n\n                            executingGlobal = chainNum;\n                            executingChain[chainNum] = true;\n\n                            gates[chainNum].Wait();\n                        }\n                        finally\n                        {\n                            stageComplete[chainNum] = taskNum;\n                            executingChain[chainNum] = false;\n                            executingGlobal = -1;\n                        }\n                    }, scheduler);\n                }\n                taskChainEnds[chainNum] = task.ContinueWith(t =>\n                {\n                    if (t.IsFaulted) throw t.Exception;\n                    this.output.WriteLine(\"Inside Chain {0} Final Task\", chainNum);\n                    resultHandles[chainNum].SetResult(true);\n                }, scheduler);\n            }\n\n            for (int i = 0; i < NumChains; i++)\n            {\n                taskChains[i].Start(scheduler);\n            }\n\n            // Set all gates to allow execution to proceed\n            for (int i = 0; i < NumChains; i++)\n            {\n                gates[i].Set();\n            }\n\n            for (int i = 0; i < NumChains; i++)\n            {\n                TimeSpan waitCheckTime = TimeSpan.FromMilliseconds(1_500 * ChainLength * NumChains * WaitFactor);\n\n                try\n                {\n                    await resultHandles[i].Task.WaitAsync(waitCheckTime);\n                }\n                catch (TimeoutException)\n                {\n                    Assert.Fail(\"Result did not arrive before timeout \" + waitCheckTime);\n                }\n\n                bool ok = await resultHandles[i].Task;\n\n                try\n                {\n                    // since resultHandle being complete doesn't directly imply that the final chain was completed (there's a chance for a race condition), give a small chance for it to complete.\n                    await taskChainEnds[i].WaitAsync(TimeSpan.FromMilliseconds(10));\n                }\n                catch (TimeoutException)\n                {\n                    Assert.Fail($\"Task chain end {i} should complete very shortly after after its resultHandle\");\n                }\n\n                Assert.True(taskChainEnds[i].IsCompleted, \"Task chain \" + i + \" should be completed\");\n                Assert.False(taskChainEnds[i].IsFaulted, \"Task chain \" + i + \" should not be Faulted: \" + taskChainEnds[i].Exception);\n                Assert.Equal(ChainLength - 1, stageComplete[i]);  // \"Task chain \" + i + \" should have completed all stages\"\n                Assert.True(ok, \"Successfully waited for ResultHandle for Task chain \" + i);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Test1()\n        {\n            await Run_ActivationSched_Test1(scheduler, false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task ActivationSched_Test1_Bounce()\n        {\n            await Run_ActivationSched_Test1(scheduler, true);\n        }\n\n        internal async Task Run_ActivationSched_Test1(TaskScheduler scheduler, bool bounceToThreadPool)\n        {\n            var grainId = LegacyGrainId.GetGrainId(0, Guid.NewGuid());\n            var silo = new MockSiloDetails\n            {\n                SiloAddress = SiloAddressUtils.NewLocalSiloAddress(23)\n            };\n            var grain = new NonReentrantStressGrainWithoutState();\n\n            await Task.Factory.StartNew(() => grain.OnActivateAsync(CancellationToken.None), CancellationToken.None, TaskCreationOptions.None, scheduler).Unwrap();\n\n            Task wrapped = null;\n            var wrapperDone = new TaskCompletionSource<bool>();\n            var wrappedDone = new TaskCompletionSource<bool>();\n            Task<Task> wrapper = new Task<Task>(() =>\n            {\n                this.output.WriteLine(\"#0 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                    SynchronizationContext.Current, TaskScheduler.Current);\n\n                Task t1 = grain.Test1();\n\n                void wrappedDoneAction() { wrappedDone.SetResult(true); }\n\n                if (bounceToThreadPool)\n                {\n                    wrapped = t1.ContinueWith(_ => wrappedDoneAction(),\n                        CancellationToken.None,\n                        TaskContinuationOptions.ExecuteSynchronously,\n                        TaskScheduler.Default);\n                }\n                else\n                {\n                    wrapped = t1.ContinueWith(_ => wrappedDoneAction());\n                }\n                wrapperDone.SetResult(true);\n                return wrapped;\n            });\n            wrapper.Start(scheduler);\n            await wrapper;\n\n            var timeoutLimit = TimeSpan.FromSeconds(10);\n            try\n            {\n                await wrapperDone.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n            bool done = wrapperDone.Task.Result;\n\n            Assert.True(done, \"Wrapper Task finished\");\n            Assert.True(wrapper.IsCompleted, \"Wrapper Task completed\");\n\n            //done = wrapped.Wait(TimeSpan.FromSeconds(12));\n            //Assert.True(done, \"Wrapped Task not timeout\");\n            await wrapped;\n            try\n            {\n                await wrappedDone.Task.WaitAsync(timeoutLimit);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail(\"Result did not arrive before timeout \" + timeoutLimit);\n            }\n            done = wrappedDone.Task.Result;\n            Assert.True(done, \"Wrapped Task should be finished\");\n            Assert.True(wrapped.IsCompleted, \"Wrapped Task completed\");\n        }\n\n        private void LogContext(string what)\n        {\n            lock (Lockable)\n            {\n                this.output.WriteLine(\n                    \"{0}\\n\"\n                    + \" TaskScheduler.Current={1}\\n\"\n                    + \" Task.Factory.Scheduler={2}\\n\"\n                    + \" SynchronizationContext.Current={3}\",\n                    what,\n                    (TaskScheduler.Current == null ? \"null\" : TaskScheduler.Current.ToString()),\n                    (Task.Factory.Scheduler == null ? \"null\" : Task.Factory.Scheduler.ToString()),\n                    (SynchronizationContext.Current == null ? \"null\" : SynchronizationContext.Current.ToString())\n                );\n\n                //var st = new StackTrace();\n                //output.WriteLine(st.ToString());\n            }\n        }\n\n        private class MockSiloDetails : ILocalSiloDetails\n        {\n            public string DnsHostName { get; }\n            public SiloAddress SiloAddress { get; set; }\n            public SiloAddress GatewayAddress { get; }\n            public string Name { get; set; } = Guid.NewGuid().ToString();\n            public string ClusterId { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/SchedulerTests/OrleansTaskSchedulerBasicTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Scheduler;\nusing UnitTests.TesterInternal;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost.Utils;\n\n// ReSharper disable ConvertToConstant.Local\n\nnamespace UnitTests.SchedulerTests\n{\n    /// <summary>\n    /// Test implementation of IGrainContext for unit testing the Orleans task scheduler without requiring a full grain activation.\n    /// </summary>\n    internal class UnitTestSchedulingContext : IGrainContext, IDisposable\n    {\n        public static UnitTestSchedulingContext Create(ILoggerFactory loggerFactory)\n        {\n            var result = new UnitTestSchedulingContext();\n            result.WorkItemGroup = SchedulingHelper.CreateWorkItemGroupForTesting(result, loggerFactory);\n            return result;\n        }\n\n        private UnitTestSchedulingContext() { }\n\n        public WorkItemGroup WorkItemGroup { get; private set; }\n\n        public GrainReference GrainReference => throw new NotImplementedException();\n\n        public GrainId GrainId => throw new NotImplementedException();\n\n        public IAddressable GrainInstance => throw new NotImplementedException();\n\n        public ActivationId ActivationId => throw new NotImplementedException();\n\n        public GrainAddress Address => throw new NotImplementedException();\n\n        public IServiceProvider ActivationServices => throw new NotImplementedException();\n\n        public IDictionary<object, object> Items => throw new NotImplementedException();\n\n        public IGrainLifecycle ObservableLifecycle => throw new NotImplementedException();\n\n        public IWorkItemScheduler Scheduler => WorkItemGroup;\n\n        public bool IsExemptFromCollection => throw new NotImplementedException();\n\n        public PlacementStrategy PlacementStrategy => throw new NotImplementedException();\n\n        object IGrainContext.GrainInstance => throw new NotImplementedException();\n\n        public void Activate(Dictionary<string, object> requestContext, CancellationToken cancellationToken) => throw new NotImplementedException();\n        public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken) { }\n        public Task Deactivated => Task.CompletedTask;\n        public void Dispose() => (Scheduler as IDisposable)?.Dispose();\n        public object GetComponent(Type componentType) => throw new NotImplementedException();\n        public object GetTarget() => throw new NotImplementedException();\n        public void ReceiveMessage(object message) => throw new NotImplementedException();\n\n        public void SetComponent<TComponent>(TComponent value) where TComponent : class => throw new NotImplementedException();\n\n        bool IEquatable<IGrainContext>.Equals(IGrainContext other) => ReferenceEquals(this, other);\n        void IGrainContext.Rehydrate(IRehydrationContext context) => throw new NotImplementedException();\n        void IGrainContext.Migrate(Dictionary<string, object> requestContext, CancellationToken cancellationToken) => throw new NotImplementedException();\n    }\n\n    /// <summary>\n    /// Basic tests for the Orleans task scheduler, which is the core component responsible for scheduling grain work items.\n    /// The scheduler ensures single-threaded execution semantics for grains while efficiently utilizing thread pool resources.\n    /// These tests verify fundamental scheduling operations without requiring a full Orleans runtime.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Scheduler\")]\n    public class OrleansTaskSchedulerBasicTests : IDisposable\n    {\n        private static readonly object Lockable = new();\n        private readonly ITestOutputHelper _output;\n        private readonly UnitTestSchedulingContext _rootContext;\n        private readonly ILoggerFactory _loggerFactory;\n        public OrleansTaskSchedulerBasicTests(ITestOutputHelper output)\n        {\n            _output = output;\n            SynchronizationContext.SetSynchronizationContext(null);\n            _loggerFactory = InitSchedulerLogging();\n            _rootContext = UnitTestSchedulingContext.Create(_loggerFactory);\n        }\n\n        public void Dispose()\n        {\n            SynchronizationContext.SetSynchronizationContext(null);\n        }\n\n        /// <summary>\n        /// Tests that tasks can be scheduled and executed on the Orleans activation task scheduler.\n        /// Verifies basic task execution flow in the grain's single-threaded execution context.\n        /// </summary>\n        [Fact, TestCategory(\"AsynchronyPrimitives\")]\n        public async Task Async_Task_Start_ActivationTaskScheduler()\n        {\n            var expected = 2;\n            var done = false;\n            var t = new Task<int>(() => { done = true; return expected; });\n            _rootContext.Scheduler.QueueTask(t);\n\n            var received = await t;\n            Assert.True(t.IsCompleted, \"Task should have completed\");\n            Assert.False(t.IsFaulted, \"Task should not thrown exception: \" + t.Exception);\n            Assert.True(done, \"Task should be done\");\n            Assert.Equal(expected, received);\n        }\n\n        [Fact]\n        public async Task Sched_SimpleFifoTest()\n        {\n            // This is not a great test because there's a 50/50 shot that it will work even if the scheduling\n            // is completely and thoroughly broken and both closures are executed \"simultaneously\"\n\n            var n = 0;\n            var completed = new TaskCompletionSource<bool>();\n            // ReSharper disable AccessToModifiedClosure\n            void item1() { n = n + 5; }\n            void item2() { n = n * 3; completed.SetResult(true); }\n            // ReSharper restore AccessToModifiedClosure\n            _rootContext.Scheduler.QueueAction(item1);\n            _rootContext.Scheduler.QueueAction(item2);\n\n            // Wait for completion\n            await completed.Task.WaitAsync(TimeSpan.FromSeconds(5));\n\n            // N should be 15, because the two tasks should execute in order\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(15, n);\n            _output.WriteLine(\"Test executed OK.\");\n        }\n\n        [Fact]\n        public async Task Sched_Task_TplFifoTest()\n        {\n            // This is not a great test because there's a 50/50 shot that it will work even if the scheduling\n            // is completely and thoroughly broken and both closures are executed \"simultaneously\"\n\n            var n = 0;\n            var gate = new SemaphoreSlim(0, 1);\n\n            // ReSharper disable AccessToModifiedClosure\n            var task1 = new Task(() => { gate.Wait(); n = n + 5; });\n            var task2 = new Task(() => { n = n * 3; });\n            // ReSharper restore AccessToModifiedClosure\n\n            _rootContext.Scheduler.QueueTask(task1);\n            _rootContext.Scheduler.QueueTask(task2);\n\n            // Release task1 to proceed\n            gate.Release();\n\n            await Task.WhenAll(task1, task2).WaitAsync(TimeSpan.FromSeconds(5));\n\n            // N should be 15, because the two tasks should execute in order\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(15, n);\n        }\n\n        [Fact]\n        public async Task Sched_Task_ClosureWorkItem_Wait()\n        {\n            const int NumTasks = 10;\n            var workItemCompletionTimeout = TimeSpan.FromSeconds(10);\n\n            var flags = new ManualResetEvent[NumTasks];\n            for (var i = 0; i < NumTasks; i++)\n            {\n                flags[i] = new ManualResetEvent(false);\n            }\n\n            var tasks = new Task[NumTasks];\n            for (var i = 0; i < NumTasks; i++)\n            {\n                var taskNum = i; // Capture\n                tasks[i] = new Task(() => { _output.WriteLine(\"Inside Task-\" + taskNum); flags[taskNum].WaitOne(); });\n            }\n\n            var workItems = new Task[NumTasks];\n            for (var i = 0; i < NumTasks; i++)\n            {\n                var taskNum = i; // Capture\n                workItems[i] = _rootContext.QueueAction(taskIndex =>\n                {\n                    _output.WriteLine(\"Inside ClosureWorkItem-\" + taskIndex);\n                    tasks[taskIndex].Start(TaskScheduler.Default);\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                    tasks[taskIndex].Wait();\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                }, taskNum);\n            }\n\n            foreach (var flag in flags) flag.Set();\n            await Task.WhenAll(workItems).WaitAsync(workItemCompletionTimeout);\n\n\n            for (var i = 0; i < tasks.Length; i++)\n            {\n                Assert.False(tasks[i].IsFaulted, \"Task.IsFaulted-\" + i + \" Exception=\" + tasks[i].Exception);\n                Assert.True(tasks[i].IsCompleted, \"Task.IsCompleted-\" + i);\n            }\n        }\n\n        [Fact]\n        public async Task Sched_Task_TaskWorkItem_CurrentScheduler()\n        {\n            var result0 = new TaskCompletionSource<bool>();\n            var result1 = new TaskCompletionSource<bool>();\n\n            Task t1 = null;\n            _rootContext.Scheduler.QueueAction(() =>\n            {\n                try\n                {\n                    _output.WriteLine(\"#0 - TaskWorkItem - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                        SynchronizationContext.Current, TaskScheduler.Current);\n                    var taskScheduler = ((WorkItemGroup)_rootContext.Scheduler).TaskScheduler;\n                    Assert.Equal(taskScheduler, TaskScheduler.Current); //\n\n                    t1 = new Task(() =>\n                    {\n                        _output.WriteLine(\"#1 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                            SynchronizationContext.Current, TaskScheduler.Current);\n                        var taskScheduler = ((WorkItemGroup)_rootContext.Scheduler).TaskScheduler;  // \"TaskScheduler.Current #1\"\n                        Assert.Equal(taskScheduler, TaskScheduler.Current); //\n                        result1.SetResult(true);\n                    });\n                    t1.Start();\n\n                    result0.SetResult(true);\n                }\n                catch (Exception exc)\n                {\n                    result0.SetException(exc);\n                }\n            });\n\n            await result0.Task.WaitAsync(TimeSpan.FromMinutes(1));\n            Assert.True(result0.Task.Exception == null, \"Task-0 should not throw exception: \" + result0.Task.Exception);\n            Assert.True(await result0.Task, \"Task-0 completed\");\n\n            Assert.NotNull(t1); // Task-1 started\n            await result1.Task.WaitAsync(TimeSpan.FromMinutes(1));\n            // give a minimum extra chance to yield after result0 has been set, as it might not have finished the t1 task\n            await t1.WaitAsync(TimeSpan.FromMilliseconds(1));\n\n            Assert.True(t1.IsCompleted, \"Task-1 completed\");\n            Assert.False(t1.IsFaulted, \"Task-1 faulted: \" + t1.Exception);\n            Assert.True(await result1.Task, \"Task-1 completed\");\n        }\n\n        [Fact]\n        public async Task Sched_Task_SubTaskExecutionSequencing()\n        {\n            LogContext(\"Main-task \" + Task.CurrentId);\n\n            var n = 0;\n            var finished = new TaskCompletionSource<int>();\n            var numCompleted = new[] {0};\n            var gates = new SemaphoreSlim[10];\n            for (var i = 0; i < 10; i++)\n            {\n                gates[i] = new SemaphoreSlim(0, 1);\n            }\n\n            void closure()\n            {\n                LogContext(\"ClosureWorkItem-task \" + Task.CurrentId);\n\n                for (var i = 0; i < 10; i++)\n                {\n                    var taskIndex = i;\n                    var id = -1;\n                    void action()\n                    {\n                        id = Task.CurrentId.HasValue ? (int)Task.CurrentId : -1;\n\n                        // ReSharper disable AccessToModifiedClosure\n                        LogContext(\"Sub-task \" + id + \" n=\" + n);\n\n                        var k = n;\n                        _output.WriteLine(\"Sub-task \" + id + \" waiting for gate\");\n                        gates[taskIndex].Wait();\n                        _output.WriteLine(\"Sub-task \" + id + \" proceeding\");\n                        n = k + 1;\n                        // ReSharper restore AccessToModifiedClosure\n                    }\n                    Task.Factory.StartNew(action).ContinueWith(tsk =>\n                    {\n                        LogContext(\"Sub-task \" + id + \"-ContinueWith\");\n\n                        _output.WriteLine(\"Sub-task \" + id + \" Done\");\n                        if (Interlocked.Increment(ref numCompleted[0]) == 10)\n                        {\n                            finished.SetResult(0);\n                        }\n                    });\n                }\n\n                // Release all gates in sequence to ensure sequential execution\n                for (var i = 0; i < 10; i++)\n                {\n                    gates[i].Release();\n                }\n            }\n\n            _rootContext.Scheduler.QueueAction(closure);\n\n            // Wait for completion\n            _output.WriteLine(\"Main-task waiting\");\n            await finished.Task.WaitAsync(TimeSpan.FromSeconds(10));\n            _output.WriteLine(\"Main-task done\");\n\n            // N should be 10, because all tasks should execute serially\n            Assert.True(n != 0, \"Work items did not get executed\");\n            Assert.Equal(10, n);  // \"Work items executed concurrently\"\n        }\n\n        [Fact]\n        public async Task Sched_AC_RequestContext_StartNew_ContinueWith()\n        {\n            const string key = \"A\";\n            var val = Random.Shared.Next();\n            RequestContext.Set(key, val);\n\n            _output.WriteLine(\"Initial - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                SynchronizationContext.Current, TaskScheduler.Current);\n\n            Assert.Equal(val, RequestContext.Get(key));  // \"RequestContext.Get Initial\"\n\n            Task t0 = Task.Factory.StartNew(async () =>\n            {\n                _output.WriteLine(\"#0 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                    SynchronizationContext.Current, TaskScheduler.Current);\n\n                Assert.Equal(val, RequestContext.Get(key));  // \"RequestContext.Get #0\"\n\n                Task t1 = Task.Factory.StartNew(() =>\n                {\n                    _output.WriteLine(\"#1 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                        SynchronizationContext.Current, TaskScheduler.Current);\n                    Assert.Equal(val, RequestContext.Get(key));  // \"RequestContext.Get #1\"\n                });\n                Task t2 = t1.ContinueWith((_) =>\n                {\n                    _output.WriteLine(\"#2 - new Task - SynchronizationContext.Current={0} TaskScheduler.Current={1}\",\n                        SynchronizationContext.Current, TaskScheduler.Current);\n                    Assert.Equal(val, RequestContext.Get(key));  // \"RequestContext.Get #2\"\n                });\n                await t2.WaitAsync(TimeSpan.FromSeconds(5));\n            }).Unwrap();\n            await t0.WaitAsync(TimeSpan.FromSeconds(10));\n            Assert.True(t0.IsCompleted, \"Task #0 FAULTED=\" + t0.Exception);\n        }\n\n        [Fact]\n        public async Task RequestContextProtectedInQueuedTasksTest()\n        {\n            var key = Guid.NewGuid().ToString();\n            var value = Guid.NewGuid().ToString();\n\n            // Caller RequestContext is protected from clear within QueueTask\n            RequestContext.Set(key, value);\n            await _rootContext.QueueTask(() => AsyncCheckClearRequestContext(key));\n            Assert.Equal(value, (string)RequestContext.Get(key));\n\n            // Caller RequestContext is protected from clear within QueueTask even if work is not actually asynchronous.\n            await _rootContext.QueueTask(() => NonAsyncCheckClearRequestContext(key));\n            Assert.Equal(value, (string)RequestContext.Get(key));\n\n            // Caller RequestContext is protected from clear when work is asynchronous.\n            async Task asyncCheckClearRequestContext()\n            {\n                RequestContext.Clear();\n                Assert.Null(RequestContext.Get(key));\n                await Task.Delay(TimeSpan.Zero);\n            }\n            await asyncCheckClearRequestContext();\n            Assert.Equal(value, (string)RequestContext.Get(key));\n\n            // Caller RequestContext is NOT protected from clear when work is not asynchronous.\n            Task nonAsyncCheckClearRequestContext()\n            {\n                RequestContext.Clear();\n                Assert.Null(RequestContext.Get(key));\n                return Task.CompletedTask;\n            }\n            await nonAsyncCheckClearRequestContext();\n            Assert.Null(RequestContext.Get(key));\n\n            static async Task AsyncCheckClearRequestContext(string key)\n            {\n                Assert.Null(RequestContext.Get(key));\n                await Task.Delay(TimeSpan.Zero);\n            }\n\n            static Task NonAsyncCheckClearRequestContext(string key)\n            {\n                Assert.Null(RequestContext.Get(key));\n                return Task.CompletedTask;\n            }\n        }\n\n        private void LogContext(string what)\n        {\n            lock (Lockable)\n            {\n                _output.WriteLine(\n                    \"{0}\\n\"\n                    + \" TaskScheduler.Current={1}\\n\"\n                    + \" Task.Factory.Scheduler={2}\\n\"\n                    + \" SynchronizationContext.Current={3}\\n\"\n                    + \" Orleans-RuntimeContext.Current={4}\",\n                    what,\n                    (TaskScheduler.Current == null ? \"null\" : TaskScheduler.Current.ToString()),\n                    (Task.Factory.Scheduler == null ? \"null\" : Task.Factory.Scheduler.ToString()),\n                    (SynchronizationContext.Current == null ? \"null\" : SynchronizationContext.Current.ToString()),\n                    (RuntimeContext.Current == null ? \"null\" : RuntimeContext.Current.ToString())\n                );\n\n                //var st = new StackTrace();\n                //output.WriteLine(\"Backtrace: \" + st);\n            }\n        }\n\n        internal static ILoggerFactory InitSchedulerLogging()\n        {\n            var filters = new LoggerFilterOptions();\n            filters.AddFilter(\"Scheduler\", LogLevel.Trace);\n            filters.AddFilter(\"Scheduler.WorkerPoolThread\", LogLevel.Trace);\n            var loggerFactory = TestingUtils.CreateDefaultLoggerFactory(TestingUtils.CreateTraceFileName(\"Silo\", DateTime.UtcNow.ToString(\"yyyyMMdd_hhmmss\")), filters);\n            return loggerFactory;\n        }\n    }\n}\n\n// ReSharper restore ConvertToConstant.Local\n"
  },
  {
    "path": "test/Orleans.Core.Tests/SchedulerTests/STSchedulerLongTurnTest.cs",
    "content": "using System.Diagnostics;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.SchedulerTests\n{\n    /// <summary>\n    /// Tests Orleans scheduler behavior with long-running grain operations to ensure they don't cause timeouts or queue blocking.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class STSchedulerLongTurnTest : HostedTestClusterEnsureDefaultStarted\n    {\n        public STSchedulerLongTurnTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Scheduler\")]\n        public async Task Sched_LongTurnTest()\n        {\n            // With two silos, there should be 16 threads.\n            // We'll create way more grains than that to make sure we swamp the thread pools\n            var grains = new List<IErrorGrain>();\n            var grainFullName = typeof(ErrorGrain).FullName;\n            for (int i = 0; i < 100; i++)\n            {\n                grains.Add(this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName));\n            }\n\n            // Send a bunch of do-nothing requests just to get the grains activated\n            var promises = grains.Select(grain => grain.Dispose());\n            await Task.WhenAll(promises);\n\n\n            // Now start a timer, and then queue up a bunch of long (sleeping) requests\n            var timer = new Stopwatch();\n            timer.Start();\n\n            promises = grains.Select(grain => grain.LongMethod(12));\n            try\n            {\n                await Task.WhenAll(promises);\n            }\n            catch (Exception ex)\n            {\n                if (ex.GetBaseException() is TimeoutException)\n                {\n                    Assert.Fail(\"Long turns queued up and caused a timeout\");\n                }\n                else\n                {\n                    throw;\n                }\n            }\n            timer.Stop();\n\n            Assert.True(timer.Elapsed.TotalSeconds < 40, \"Long turns queued up and caused an extended runtime\");\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Core.Tests/SchedulingHelper.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Scheduler;\n\nnamespace UnitTests.TesterInternal\n{\n    public class SchedulingHelper\n    {\n        internal static WorkItemGroup CreateWorkItemGroupForTesting(\n            IGrainContext context,\n            ILoggerFactory loggerFactory)\n        {\n            ArgumentNullException.ThrowIfNull(context);\n            ArgumentNullException.ThrowIfNull(loggerFactory);\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddLogging();\n            services.AddSingleton(loggerFactory);\n            services.Configure<SchedulingOptions>(options =>\n            {\n                options.DelayWarningThreshold = TimeSpan.FromMilliseconds(100);\n                options.ActivationSchedulingQuantum = TimeSpan.FromMilliseconds(100);\n                options.TurnWarningLengthThreshold = TimeSpan.FromMilliseconds(100);\n                options.StoppedActivationWarningInterval = TimeSpan.FromMilliseconds(200);\n            });\n\n            var s = services.BuildServiceProvider();\n            var result = new WorkItemGroup(\n                context,\n                s.GetRequiredService<ILogger<WorkItemGroup>>(),\n                s.GetRequiredService<ILogger<ActivationTaskScheduler>>(),\n                s.GetRequiredService<IOptions<SchedulingOptions>>());\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Serialization/BuiltInSerializerTests.cs",
    "content": "using System.Collections.ObjectModel;\nusing Orleans.Concurrency;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Streaming.EventHubs;\nusing Orleans.Streams;\nusing TestExtensions;\nusing TestGrainInterfaces;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\n// ReSharper disable NotAccessedVariable\n\nnamespace UnitTests.Serialization\n{\n    /// <summary>\n    /// Tests for Orleans' built-in serializers, which handle serialization of common .NET types and Orleans-specific types.\n    /// These serializers are crucial for grain communication, state persistence, and streaming. The tests verify that\n    /// Orleans can correctly serialize and deserialize various data structures used throughout the framework.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection), TestCategory(\"Serialization\")]\n    public class BuiltInSerializerTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture environment;\n\n        public BuiltInSerializerTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.environment = fixture;\n        }\n\n        /// <summary>\n        /// Verifies that Orleans internal types have appropriate serializers registered.\n        /// This is essential for proper functioning of Orleans' internal messaging and state management.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\")]\n        public void InternalSerializableTypesHaveSerializers()\n        {\n            Assert.True(\n                environment.Serializer.CanSerialize<int>(),\n                $\"Should be able to serialize internal type {nameof(Int32)}.\");\n            Assert.True(\n                environment.Serializer.CanSerialize(typeof(List<int>)),\n                $\"Should be able to serialize internal type {nameof(List<int>)}.\");\n            Assert.True(\n                environment.Serializer.CanSerialize(typeof(PubSubGrainState)),\n                $\"Should be able to serialize internal type {nameof(PubSubGrainState)}.\");\n            Assert.True(\n                environment.Serializer.CanSerialize(typeof(EventHubBatchContainer)),\n                $\"Should be able to serialize internal type {nameof(EventHubBatchContainer)}.\");\n            Assert.True(\n                environment.Serializer.CanSerialize(typeof(EventHubSequenceTokenV2)),\n                $\"Should be able to serialize internal type {nameof(EventHubSequenceTokenV2)}.\");\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\")]\n        public void ValueTupleTypesHasSerializer()\n        {\n            Assert.True(\n                environment.Serializer.CanSerialize(typeof(ValueTuple<int, AddressAndTag>)),\n                $\"Should be able to serialize internal type {nameof(ValueTuple<int, AddressAndTag>)}.\");\n        }\n\n        /// <summary>\n        /// Tests that the default (non-fallback) serializer can handle complex classes.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public void Serialize_ComplexAccessibleClass()\n        {\n            var expected = new AnotherConcreteClass\n            {\n                Int = 89,\n                AnotherString = Guid.NewGuid().ToString(),\n                NonSerializedInt = 39,\n                Enum = SomeAbstractClass.SomeEnum.Something,\n            };\n\n            expected.Classes = new SomeAbstractClass[]\n            {\n                expected,\n                new AnotherConcreteClass\n                {\n                    AnotherString = \"hi\",\n                    Interfaces = new List<ISomeInterface> { expected }\n                }\n            };\n            expected.Interfaces = new List<ISomeInterface>\n            {\n                expected.Classes[1]\n            };\n            expected.SetObsoleteInt(38);\n\n            var actual = (AnotherConcreteClass)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, expected);\n\n            Assert.Equal(expected.Int, actual.Int);\n            Assert.Equal(expected.Enum, actual.Enum);\n            Assert.Equal(expected.AnotherString, actual.AnotherString);\n            Assert.Equal(expected.Classes.Length, actual.Classes.Length);\n            Assert.Equal(expected.Classes[1].Interfaces[0].Int, actual.Classes[1].Interfaces[0].Int);\n            Assert.Equal(expected.Interfaces[0].Int, actual.Interfaces[0].Int);\n            Assert.Equal(actual.Interfaces[0], actual.Classes[1]);\n            Assert.NotEqual(expected.NonSerializedInt, actual.NonSerializedInt);\n            Assert.Equal(0, actual.NonSerializedInt);\n            Assert.Equal(expected.GetObsoleteInt(), actual.GetObsoleteInt());\n            Assert.Null(actual.SomeGrainReference);\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public void Serialize_Type()\n        {\n\n            // Test serialization of Type.\n            var expected = typeof(int);\n            var actual = (Type)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, expected);\n            Assert.Equal(expected.AssemblyQualifiedName, actual.AssemblyQualifiedName);\n\n            // Test serialization of RuntimeType.\n            expected = 8.GetType();\n            actual = (Type)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, expected);\n            Assert.Equal(expected.AssemblyQualifiedName, actual.AssemblyQualifiedName);\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public void Serialize_ComplexStruct()\n        {\n\n            // Test struct serialization.\n            var expected = new SomeStruct(10) { Id = Guid.NewGuid(), PublicValue = 6, ValueWithPrivateGetter = 7 };\n            expected.SetValueWithPrivateSetter(8);\n            expected.SetPrivateValue(9);\n            var actual = (SomeStruct)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, expected);\n            Assert.Equal(expected.Id, actual.Id);\n            Assert.Equal(expected.ReadonlyField, actual.ReadonlyField);\n            Assert.Equal(expected.PublicValue, actual.PublicValue);\n            Assert.Equal(expected.ValueWithPrivateSetter, actual.ValueWithPrivateSetter);\n            Assert.Null(actual.SomeGrainReference);\n            Assert.Equal(expected.GetPrivateValue(), actual.GetPrivateValue());\n            Assert.Equal(expected.GetValueWithPrivateGetter(), actual.GetValueWithPrivateGetter());\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_EmptyList()\n        {\n            var list = new List<int>();\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, list, false);\n            Assert.IsAssignableFrom<List<int>>(deserialized);  //Empty list of integers copied as wrong type\"\n            ValidateList(list, (List<int>)deserialized, \"int (empty, copy)\");\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, list);\n            Assert.IsAssignableFrom<List<int>>(deserialized); //Empty list of integers full serialization loop as wrong type\n            ValidateList(list, (List<int>)deserialized, \"int (empty)\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_BasicDictionaries()\n        {\n\n            Dictionary<string, string> source1 = new Dictionary<string, string>();\n            source1[\"Hello\"] = \"Yes\";\n            source1[\"Goodbye\"] = \"No\";\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateDictionary<string, string>(source1, deserialized, \"string/string\");\n\n            Dictionary<int, DateTime> source2 = new Dictionary<int, DateTime>();\n            source2[3] = DateTime.Now;\n            source2[27] = DateTime.Now.AddHours(2);\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source2);\n            ValidateDictionary<int, DateTime>(source2, deserialized, \"int/date\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_ReadOnlyDictionary()\n        {\n            Dictionary<string, string> source1 = new Dictionary<string, string>();\n            source1[\"Hello\"] = \"Yes\";\n            source1[\"Goodbye\"] = \"No\";\n            var readOnlySource1 = new ReadOnlyDictionary<string, string>(source1);\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, readOnlySource1);\n            ValidateReadOnlyDictionary(readOnlySource1, deserialized, \"string/string\");\n\n            Dictionary<int, DateTime> source2 = new Dictionary<int, DateTime>();\n            source2[3] = DateTime.Now;\n            source2[27] = DateTime.Now.AddHours(2);\n            var readOnlySource2 = new ReadOnlyDictionary<int, DateTime>(source2);\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, readOnlySource2);\n            ValidateReadOnlyDictionary(readOnlySource2, deserialized, \"int/date\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_DictionaryWithComparer()\n        {\n            Dictionary<string, string> source1 = new Dictionary<string, string>(new CaseInsensitiveStringEquality());\n            source1[\"Hello\"] = \"Yes\";\n            source1[\"Goodbye\"] = \"No\";\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateDictionary<string, string>(source1, deserialized, \"case-insensitive string/string\");\n            Dictionary<string, string> result1 = deserialized as Dictionary<string, string>;\n            Assert.Equal(source1[\"Hello\"], result1[\"hElLo\"]); //Round trip for case insensitive string/string dictionary lost the custom comparer\n\n            Dictionary<int, DateTime> source2 = new Dictionary<int, DateTime>(new Mod5IntegerComparer());\n            source2[3] = DateTime.Now;\n            source2[27] = DateTime.Now.AddHours(2);\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source2);\n            ValidateDictionary<int, DateTime>(source2, deserialized, \"int/date\");\n            Dictionary<int, DateTime> result2 = (Dictionary<int, DateTime>)deserialized;\n            Assert.Equal<DateTime>(source2[3], result2[13]);  //Round trip for case insensitive int/DateTime dictionary lost the custom comparer\"\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_SortedDictionaryWithComparer()\n        {\n            var source1 = new SortedDictionary<string, string>(new CaseInsensitiveStringComparer());\n            source1[\"Hello\"] = \"Yes\";\n            source1[\"Goodbye\"] = \"No\";\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateSortedDictionary<string, string>(source1, deserialized, \"string/string\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_SortedListWithComparer()\n        {\n            var source1 = new SortedList<string, string>(new CaseInsensitiveStringComparer());\n            source1[\"Hello\"] = \"Yes\";\n            source1[\"Goodbye\"] = \"No\";\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateSortedList<string, string>(source1, deserialized, \"string/string\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_HashSetWithComparer()\n        {\n            var source1 = new HashSet<string>(new CaseInsensitiveStringEquality());\n            source1.Add(\"one\");\n            source1.Add(\"two\");\n            source1.Add(\"three\");\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            Assert.IsAssignableFrom(source1.GetType(), deserialized); //Type is wrong after round-trip of string hash set with comparer\n            var result = deserialized as HashSet<string>;\n            Assert.Equal(source1.Count, result.Count); //Count is wrong after round-trip of string hash set with comparer\n#pragma warning disable xUnit2017 // Do not use Contains() to check if a value exists in a collection\n            foreach (var key in source1)\n            {\n                Assert.True(result.Contains(key)); //key is missing after round-trip of string hash set with comparer\n            }\n            Assert.True(result.Contains(\"One\")); //Comparer is wrong after round-trip of string hash set with comparer\n#pragma warning restore xUnit2017 // Do not use Contains() to check if a value exists in a collection\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_Stack()\n        {\n            var source1 = new Stack<string>();\n            source1.Push(\"one\");\n            source1.Push(\"two\");\n            source1.Push(\"three\");\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            Assert.IsAssignableFrom(source1.GetType(), deserialized); //Type is wrong after round-trip of string stack\n            var result = deserialized as Stack<string>;\n            Assert.Equal(source1.Count, result.Count); //Count is wrong after round-trip of string stack\n\n            var srcIter = source1.GetEnumerator();\n            var resIter = result.GetEnumerator();\n            while (srcIter.MoveNext() && resIter.MoveNext())\n            {\n                Assert.Equal(srcIter.Current, resIter.Current); //Data is wrong after round-trip of string stack\n            }\n        }\n\n        /// <summary>\n        /// Tests that the <see cref=\"IOnDeserialized\"/> callback is invoked after deserialization.\n        /// </summary>\n        /// <param name=\"serializerToUse\"></param>\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_TypeWithOnDeserializedHook()\n        {\n            var input = new TypeWithOnDeserializedHook\n            {\n                Int = 5\n            };\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, input);\n            var result = Assert.IsType<TypeWithOnDeserializedHook>(deserialized);\n            Assert.Equal(input.Int, result.Int);\n            Assert.Null(input.Context);\n            Assert.NotNull(result.Context);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_SortedSetWithComparer()\n        {\n            var source1 = new SortedSet<string>(new CaseInsensitiveStringComparer());\n            source1.Add(\"one\");\n            source1.Add(\"two\");\n            source1.Add(\"three\");\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            Assert.IsAssignableFrom(source1.GetType(), deserialized); //Type is wrong after round-trip of string sorted set with comparer\n            var result = (SortedSet<string>)deserialized;\n            Assert.Equal(source1.Count, result.Count); //Count is wrong after round-trip of string sorted set with comparer\n#pragma warning disable xUnit2017 // Do not use Contains() to check if a value exists in a collection\n            foreach (var key in source1)\n            {\n                Assert.True(result.Contains(key)); //key is missing after round-trip of string sorted set with comparer\n            }\n            Assert.True(result.Contains(\"One\")); //Comparer is wrong after round-trip of string sorted set with comparer\n#pragma warning restore xUnit2017 // Do not use Contains() to check if a value exists in a collection\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_Array()\n        {\n            var source1 = new int[] { 1, 3, 5 };\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateArray<int>(source1, deserialized, \"int\");\n\n            var source2 = new string[] { \"hello\", \"goodbye\", \"yes\", \"no\", \"\", \"I don't know\" };\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source2);\n            ValidateArray<string>(source2, deserialized, \"string\");\n\n            var source3 = new sbyte[] { 1, 3, 5 };\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source3);\n            ValidateArray<sbyte>(source3, deserialized, \"sbyte\");\n\n            var source4 = new byte[] { 1, 3, 5 };\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source4);\n            ValidateArray<byte>(source4, deserialized, \"byte\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_ArrayOfArrays()\n        {\n            var source1 = new[] { new[] { 1, 3, 5 }, new[] { 10, 20, 30 }, new[] { 17, 13, 11, 7, 5, 3, 2 } };\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source1);\n            ValidateArrayOfArrays(source1, deserialized, \"int\");\n\n            var source2 = new[] { new[] { \"hello\", \"goodbye\", \"yes\", \"no\", \"\", \"I don't know\" }, new[] { \"yes\" } };\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source2);\n            ValidateArrayOfArrays(source2, deserialized, \"string\");\n\n            var source3 = new HashSet<string>[3][];\n            source3[0] = new HashSet<string>[2];\n            source3[1] = new HashSet<string>[3];\n            source3[2] = new HashSet<string>[1];\n            source3[0][0] = new HashSet<string>();\n            source3[0][1] = new HashSet<string>();\n            source3[1][0] = new HashSet<string>();\n            source3[1][1] = null;\n            source3[1][2] = new HashSet<string>();\n            source3[2][0] = new HashSet<string>();\n            source3[0][0].Add(\"this\");\n            source3[0][0].Add(\"that\");\n            source3[1][0].Add(\"the other\");\n            source3[1][2].Add(\"and another\");\n            source3[2][0].Add(\"but not yet another\");\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source3);\n            var result = Assert.IsAssignableFrom<HashSet<string>[][]>(deserialized); //Array of arrays of hash sets type is wrong on deserialization\n            Assert.Equal(3, result.Length); //Outer array size wrong on array of array of sets\n            Assert.Equal(2, result[0][0].Count); //Inner set size wrong on array of array of sets, element 0,0\n            Assert.Empty(result[0][1]); //Inner set size wrong on array of array of sets, element 0,1\n            Assert.Single(result[1][0]); //Inner set size wrong on array of array of sets, element 1,0\n            Assert.Null(result[1][1]); //Inner set not null on array of array of sets, element 1, 1\n            Assert.Single(result[1][2]); //Inner set size wrong on array of array of sets, element 1,2\n            Assert.Single(result[2][0]); //Inner set size wrong on array of array of sets, element 2,0\n\n            var source4 = new GrainReference[3][];\n            source4[0] = new GrainReference[2];\n            source4[1] = new GrainReference[3];\n            source4[2] = new GrainReference[1];\n            source4[0][0] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            source4[0][1] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            source4[1][0] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            source4[1][1] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            source4[1][2] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            source4[2][0] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source4);\n            ValidateArrayOfArrays(source4, deserialized, \"grain reference\");\n\n            var source5 = new GrainReference[32][];\n            for (int i = 0; i < source5.Length; i++)\n            {\n                source5[i] = new GrainReference[64];\n                for (int j = 0; j < source5[i].Length; j++)\n                {\n                    source5[i][j] = (GrainReference)environment.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n                }\n            }\n            deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source5);\n            ValidateArrayOfArrays(source5, deserialized, \"grain reference (large)\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_ArrayOfArrayOfArrays()\n        {\n            var source1 = new[] { new[] { 1, 3, 5 }, new[] { 10, 20, 30 }, new[] { 17, 13, 11, 7, 5, 3, 2 } };\n            var source2 = new[] { new[] { 1, 3 }, new[] { 10, 20 }, new[] { 17, 13, 11, 7, 5 } };\n            var source3 = new[] { new[] { 1, 3, 5 }, new[] { 10, 20, 30 } };\n            var source = new[] { source1, source2, source3 };\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, source);\n            ValidateArrayOfArrayOfArrays(source, deserialized, \"int\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_ReadOnlyCollection()\n        {\n            var source1 = new List<string> { \"Yes\", \"No\" };\n            var collection = new ReadOnlyCollection<string>(source1);\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, collection);\n            ValidateReadOnlyCollectionList(collection, deserialized, \"string/string\");\n        }\n\n        private class BanningTypeResolver : TypeResolver\n        {\n            private readonly CachedTypeResolver _resolver = new CachedTypeResolver();\n            private readonly HashSet<Type> _blockedTypes;\n\n            public BanningTypeResolver(params Type[] blockedTypes)\n            {\n                _blockedTypes = new HashSet<Type>();\n                foreach (var type in blockedTypes ?? Array.Empty<Type>())\n                {\n                    _blockedTypes.Add(type);\n                }\n            }\n\n            public override Type ResolveType(string name)\n            {\n                var result = _resolver.ResolveType(name);\n                if (_blockedTypes.Contains(result))\n                {\n                    result = null;\n                }\n\n                return result;\n            }\n\n            public override bool TryResolveType(string name, out Type type)\n            {\n                if (_resolver.TryResolveType(name, out type))\n                {\n                    if (_blockedTypes.Contains(type))\n                    {\n                        type = null;\n                        return false;\n                    }\n\n                    return true;\n                }\n\n                return false;\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_ObjectIdentity()\n        {\n            var val = new List<string> { \"first\", \"second\" };\n\n            var val2 = new List<string> { \"first\", \"second\" };\n\n            var source = new Dictionary<string, List<string>>();\n            source[\"one\"] = val;\n            source[\"two\"] = val;\n            source[\"three\"] = val2;\n            Assert.Same(source[\"one\"], source[\"two\"]); //Object identity lost before round trip of string/list dict!!!\n\n            var deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  source);\n            var result = Assert.IsAssignableFrom<Dictionary<string, List<string>>>(deserialized); //Type is wrong after round-trip of string/list dict\n            Assert.Equal(source.Count, result.Count); //Count is wrong after round-trip of string/list dict\n\n            List<string> list1;\n            List<string> list2;\n            List<string> list3;\n            Assert.True(result.TryGetValue(\"one\", out list1)); //Key 'one' not found after round trip of string/list dict\n            Assert.True(result.TryGetValue(\"two\", out list2)); //Key 'two' not found after round trip of string/list dict\n            Assert.True(result.TryGetValue(\"three\", out list3)); //Key 'three' not found after round trip of string/list dict\n\n            ValidateList<string>(val, list1, \"string\");\n            ValidateList<string>(val, list2, \"string\");\n            ValidateList<string>(val2, list3, \"string\");\n\n            Assert.Same(list1, list2); //Object identity lost after round trip of string/list dict\n            Assert.NotSame(list2, list3); //Object identity gained after round trip of string/list dict\n            Assert.NotSame(list1, list3); //Object identity gained after round trip of string/list dict\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_Unrecognized()\n        {\n            var test1 = new Unrecognized { A = 3, B = 27 };\n            var raw = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, test1, false);\n            var result = Assert.IsAssignableFrom<Unrecognized>(raw); //Type is wrong after deep copy of unrecognized\n            Assert.Equal(3, result.A);  //Property A is wrong after deep copy of unrecognized\"\n            Assert.Equal(27, result.B);  //Property B is wrong after deep copy of unrecognized\"\n\n            var test2 = new Unrecognized[3];\n            for (int i = 0; i < 3; i++)\n            {\n                test2[i] = new Unrecognized { A = i, B = 2 * i };\n            }\n            raw = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier, test2);\n            Assert.IsAssignableFrom<Unrecognized[]>(raw); //Type is wrong after round trip of array of unrecognized\n            var result2 = (Unrecognized[])raw;\n            Assert.Equal(3, result2.Length); //Array length is wrong after round trip of array of unrecognized\n            for (int j = 0; j < 3; j++)\n            {\n                Assert.Equal(j, result2[j].A); //Property A at index \" + j + \"is wrong after round trip of array of unrecognized\n                Assert.Equal(2 * j, result2[j].B); //Property B at index \" + j + \"is wrong after round trip of array of unrecognized\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_Immutable()\n        {\n            var test1 = new ImmutableType(3, 27);\n            var raw = environment.DeepCopier.Copy<object>(test1);\n            Assert.IsAssignableFrom<ImmutableType>(raw); //Type is wrong after deep copy of [Immutable] type\n            Assert.Same(test1, raw); //Deep copy of [Immutable] object made a copy instead of just copying the pointer\n\n            var test2list = new List<int>();\n            for (int i = 0; i < 3; i++)\n            {\n                test2list.Add(i);\n            }\n            var test2 = new Immutable<List<int>>(test2list);\n            raw = environment.DeepCopier.Copy<object>(test2);\n            Assert.IsAssignableFrom<Immutable<List<int>>>(raw); //Type is wrong after round trip of array of Immutable<>\n            Assert.Same(test2.Value, ((Immutable<List<int>>)raw).Value); //Deep copy of Immutable<> object made a copy instead of just copying the pointer\n\n            var test3 = new EmbeddedImmutable(\"test\", 1, 2, 3, 4);\n            raw = environment.DeepCopier.Copy<object>(test3);\n            Assert.IsAssignableFrom<EmbeddedImmutable>(raw); //Type is wrong after deep copy of type containing an Immutable<> field\n            Assert.Same(test3.B.Value, ((EmbeddedImmutable)raw).B.Value); //Deep copy of embedded [Immutable] object made a copy instead of just copying the pointer\n\n            var test4 = new ClassWithEmbeddedImmutable { Immutable = new byte[] { 1 }, Mutable = new byte[] { 2 } };\n            raw = environment.DeepCopier.Copy<object>(test4);\n            Assert.IsAssignableFrom<ClassWithEmbeddedImmutable>(raw); //Type is wrong after deep copy of type containing an Immutable<> field\n            Assert.Same(test4.Immutable, ((ClassWithEmbeddedImmutable)raw).Immutable); //Deep copy of embedded [Immutable] object made a copy instead of just copying the pointer\n            Assert.NotSame(test4.Mutable, ((ClassWithEmbeddedImmutable)raw).Mutable);\n\n            var test5 = new StructWithEmbeddedImmutable { Immutable = new byte[] { 1 }, Mutable = new byte[] { 2 } };\n            raw = environment.DeepCopier.Copy<object>(test5);\n            Assert.IsAssignableFrom<StructWithEmbeddedImmutable>(raw); //Type is wrong after deep copy of type containing an Immutable<> field\n            Assert.Same(test5.Immutable, ((StructWithEmbeddedImmutable)raw).Immutable); //Deep copy of embedded [Immutable] object made a copy instead of just copying the pointer\n            Assert.NotSame(test5.Mutable, ((StructWithEmbeddedImmutable)raw).Mutable);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_GrainReference()\n        {\n            GrainId grainId = LegacyGrainId.NewId();\n            GrainReference input = (GrainReference)environment.InternalGrainFactory.GetGrain(grainId);\n\n            object deserialized = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  input);\n\n            var grainRef = Assert.IsAssignableFrom<GrainReference>(deserialized); //GrainReference copied as wrong type\n            Assert.Equal(grainId, grainRef.GrainId); //GrainId different after copy\n            Assert.Equal(input, grainRef); //Wrong contents after round-trip of input\n        }\n\n        internal bool AreByteArraysAreEqual(byte[] array1, byte[] array2)\n        {\n            if (array1.Length != array2.Length)\n                return false;\n\n            for (int i = 0; i < array1.Length; i++)\n            {\n                if (array1[i] != array2[i])\n                    return false;\n            }\n\n            return true;\n        }\n\n        internal static object OrleansSerializationLoop(Serializer serializer, DeepCopier copier, object input, bool includeWire = true)\n        {\n            var copy = copier.Copy(input);\n            if (includeWire)\n            {\n                copy = serializer.RoundTripSerializationForTesting(copy);\n            }\n            return copy;\n        }\n\n        private void ValidateDictionary<K, V>(Dictionary<K, V> source, object deserialized, string type)\n        {\n            var result = Assert.IsAssignableFrom<Dictionary<K, V>>(deserialized); //Type is wrong after round-trip of dict\n            ValidateDictionaryContent(source, result, type);\n        }\n\n        private void ValidateDictionaryContent<K, V>(IDictionary<K, V> source, IDictionary<K, V> result, string type)\n        {\n            Assert.Equal(source.Count, result.Count);  //Count is wrong after round-trip of \" + type + \" dict\"\n            foreach (var pair in source)\n            {\n                Assert.True(result.ContainsKey(pair.Key), \"Key \" + pair.Key.ToString() + \" is missing after round-trip of \" + type + \" dict\");\n                Assert.Equal<V>(pair.Value, result[pair.Key]); //Key has wrong value after round-trip\n            }\n        }\n\n        private void ValidateReadOnlyDictionary<K, V>(ReadOnlyDictionary<K, V> source, object deserialized, string type)\n        {\n            var result = Assert.IsAssignableFrom<ReadOnlyDictionary<K, V>>(deserialized); //Type is wrong after round-trip\n            ValidateDictionaryContent(source, result, type);\n        }\n\n        private void ValidateSortedDictionary<K, V>(SortedDictionary<K, V> source, object deserialized, string type)\n        {\n            Assert.IsAssignableFrom<SortedDictionary<K, V>>(deserialized);\n            SortedDictionary<K, V> result = deserialized as SortedDictionary<K, V>;\n            Assert.Equal(source.Count, result.Count); //Count is wrong after round-trip of \" + type + \" sorted dict\n            foreach (var pair in source)\n            {\n                Assert.True(result.ContainsKey(pair.Key)); //Key \" + pair.Key.ToString() + \" is missing after round-trip of \" + type + \" sorted dict\n                Assert.Equal<V>(pair.Value, result[pair.Key]); //Key \" + pair.Key.ToString() + \" has wrong value after round-trip of \" + type + \" sorted dict\n            }\n\n            var sourceKeys = source.Keys.GetEnumerator();\n            var resultKeys = result.Keys.GetEnumerator();\n            while (sourceKeys.MoveNext() && resultKeys.MoveNext())\n            {\n                Assert.Equal<K>(sourceKeys.Current, resultKeys.Current); //Keys out of order after round-trip of \" + type + \" sorted dict\n            }\n        }\n\n        private void ValidateSortedList<K, V>(SortedList<K, V> source, object deserialized, string type)\n        {\n            Assert.IsAssignableFrom<SortedList<K, V>>(deserialized);\n            SortedList<K, V> result = deserialized as SortedList<K, V>;\n            Assert.Equal(source.Count, result.Count);  //Count is wrong after round-trip of \" + type + \" sorted list\"\n            foreach (var pair in source)\n            {\n                Assert.True(result.ContainsKey(pair.Key)); //Key \" + pair.Key.ToString() + \" is missing after round-trip of \" + type + \" sorted list\n                Assert.Equal<V>(pair.Value, result[pair.Key]); //Key \" + pair.Key.ToString() + \" has wrong value after round-trip of \" + type + \" sorted list\n            }\n\n            var sourceKeys = source.Keys.GetEnumerator();\n            var resultKeys = result.Keys.GetEnumerator();\n            while (sourceKeys.MoveNext() && resultKeys.MoveNext())\n            {\n                Assert.Equal<K>(sourceKeys.Current, resultKeys.Current); //Keys out of order after round-trip of \" + type + \" sorted list\n            }\n        }\n\n        private void ValidateReadOnlyCollectionList<T>(ReadOnlyCollection<T> expected, object deserialized, string type)\n        {\n            Assert.IsAssignableFrom<ReadOnlyCollection<T>>(deserialized); //Type is wrong after round-trip of \" + type + \" array\n            ValidateList(expected, deserialized as IList<T>, type);\n        }\n\n        private void ValidateList<T>(IList<T> expected, IList<T> result, string type)\n        {\n            Assert.Equal(expected.Count, result.Count);\n            for (int i = 0; i < expected.Count; i++)\n            {\n                Assert.Equal<T>(expected[i], result[i]); //Item \" + i + \" is wrong after round trip of \" + type + \" list\n            }\n        }\n\n        private void ValidateArray<T>(T[] expected, object deserialized, string type)\n        {\n            var result = Assert.IsAssignableFrom<T[]>(deserialized);\n            Assert.Equal(expected.Length, result.Length);  //Length is wrong after round-trip of \" + type + \" array\"\n            for (int i = 0; i < expected.Length; i++)\n            {\n                Assert.Equal<T>(expected[i], result[i]);  //Item \" + i + \" is wrong after round trip of \" + type + \" array\"\n            }\n        }\n\n        private void ValidateArrayOfArrays<T>(T[][] expected, object deserialized, string type)\n        {\n            var result = Assert.IsAssignableFrom<T[][]>(deserialized);  //Type is wrong after round-trip of \" + type + \" array of arrays\"\n            Assert.Equal(expected.Length, result.Length);  //Length is wrong after round-trip of \" + type + \" array of arrays\"\n            for (int i = 0; i < expected.Length; i++)\n            {\n                ValidateArray<T>(expected[i], result[i], \"Array of \" + type + \"[\" + i + \"] \");\n            }\n        }\n\n        private void ValidateArrayOfArrayOfArrays<T>(T[][][] expected, object deserialized, string type)\n        {\n            var result = Assert.IsAssignableFrom<T[][][]>(deserialized);  //Type is wrong after round-trip of \" + type + \" array of arrays\"\n            Assert.Equal(expected.Length, result.Length);  //Length is wrong after round-trip of \" + type + \" array of arrays\"\n            for (int i = 0; i < expected.Length; i++)\n            {\n                ValidateArrayOfArrays<T>(expected[i], result[i], \"Array of \" + type + \"[\" + i + \"][]\");\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_CircularReference()\n        {\n            var c1 = new CircularTest1();\n            var c2 = new CircularTest2();\n            c2.CircularTest1List.Add(c1);\n            c1.CircularTest2 = c2;\n\n            var deserialized = (CircularTest1)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  c1);\n            Assert.Equal(c1.CircularTest2.CircularTest1List.Count, deserialized.CircularTest2.CircularTest1List.Count);\n            Assert.Same(deserialized, deserialized.CircularTest2.CircularTest1List[0]);\n\n            deserialized = (CircularTest1)OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  c1, true);\n            Assert.Equal(c1.CircularTest2.CircularTest1List.Count, deserialized.CircularTest2.CircularTest1List.Count);\n            Assert.Same(deserialized, deserialized.CircularTest2.CircularTest1List[0]);\n        }\n        \n        [Fact, TestCategory(\"Functional\")]\n        public void Serialize_Enums()\n        {\n            var result = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  IntEnum.Value2);\n            var typedResult = Assert.IsType<IntEnum>(result);\n            Assert.Equal(IntEnum.Value2, typedResult);\n\n            var result2 = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  UShortEnum.Value3);\n            var typedResult2 = Assert.IsType<UShortEnum>(result2);\n            Assert.Equal(UShortEnum.Value3, typedResult2);\n\n            var test = new ClassWithEnumTestData { EnumValue = TestEnum.Third, Enemy = CampaignEnemyTestType.Enemy3 };\n            var result3 = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  test);\n            var typedResult3 = Assert.IsType<ClassWithEnumTestData>(result3);\n\n            Assert.Equal(TestEnum.Third, typedResult3.EnumValue);\n            Assert.Equal(CampaignEnemyTestType.Enemy3, typedResult3.Enemy);\n\n            var result4 = OrleansSerializationLoop(environment.Serializer, environment.DeepCopier,  CampaignEnemyType.Enemy3);\n            var typedResult4 = Assert.IsType<CampaignEnemyType>(result4);\n            Assert.Equal(CampaignEnemyType.Enemy3, typedResult4);\n        }\n    }\n}\n\n// ReSharper restore NotAccessedVariable"
  },
  {
    "path": "test/Orleans.Core.Tests/Serialization/ExternalCodecTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing System.Reflection;\nusing TestExtensions;\nusing Xunit;\nusing System.Text;\nusing Microsoft.Extensions.Hosting;\nusing Newtonsoft.Json;\n\nusing Orleans.Serialization;\nusing Orleans.Runtime;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Streaming.EventHubs;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Metadata;\n\nnamespace UnitTests.Serialization\n{\n    [TestCategory(\"Serialization\"), TestCategory(\"BVT\")]\n    public class ExternalCodecTests\n    {\n        private readonly SerializationTestEnvironment environment;\n\n        public ExternalCodecTests()\n        {\n            this.environment = SerializationTestEnvironment.InitializeWithDefaults(\n                builder =>\n                    builder.ConfigureServices(services =>\n                        services.AddSerializer(serializerBuilder =>\n                        {\n                            serializerBuilder.AddNewtonsoftJsonSerializer(type => type.GetCustomAttribute<JsonTypeAttribute>() is not null);\n                        })));\n        }\n\n        [Fact]\n        public void NewtonsoftJsonCodec_ExternalSerializer_Client()\n        {\n            TestSerializationRoundTrip(this.environment.Serializer);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonCodec_ExternalSerializer_Silo()\n        {\n            var silo = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                    .Configure<ClusterOptions>(o => o.ClusterId = o.ServiceId = \"s\")\n                    .UseLocalhostClustering()\n                    .ConfigureServices(services =>\n                        services.AddSerializer(serializerBuilder =>\n                        {\n                            serializerBuilder.AddNewtonsoftJsonSerializer(type => type.GetCustomAttribute<JsonTypeAttribute>() is not null);\n                        }));\n                })\n                .Build();\n            var serializer = silo.Services.GetRequiredService<Serializer>();\n            TestSerializationRoundTrip(serializer);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonCodec_CanModifySerializerSettings()\n        {\n            var silo = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                    .Configure<ClusterOptions>(o => o.ClusterId = o.ServiceId = \"s\")\n                    .Configure<OrleansJsonSerializerOptions>(options => options.JsonSerializerSettings.DefaultValueHandling = DefaultValueHandling.Include)\n                    .UseLocalhostClustering();\n                })\n                .Build();\n            var serializer = silo.Services.GetRequiredService<OrleansJsonSerializer>();\n            var data = new JsonPoco();\n            var serialized = serializer.Serialize(data, typeof(JsonPoco));\n            Assert.Contains(\"some_flag\", serialized);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonCodec_DoesNotSerializeFrameworkTypes()\n        {\n            var silo = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.Services.AddSerializer(serializerBuilder => serializerBuilder.AddNewtonsoftJsonSerializer(type =>\n                        {\n                            Assert.Fail($\"Custom type filter should not be consulted for any type in this test, but it was used for type {type}.\");\n                            return true;\n                        }));\n                    siloBuilder.UseLocalhostClustering();\n                })\n                .Build();\n            var services = silo.Services;\n            var serializer = services.GetRequiredService<Serializer>();\n            var generatedGrainReferenceType = services.GetRequiredService<IOptions<TypeManifestOptions>>().Value\n                .InterfaceProxies.First(i => ! i.IsGenericType && i.Assembly.GetCustomAttribute<FrameworkPartAttribute>() is null);\n            var codecProvider = services.GetRequiredService<CodecProvider>();\n            foreach (var type in new[] { typeof(SiloAddress), typeof(GrainReference), typeof(EventHubBatchContainer), generatedGrainReferenceType })\n            {\n                var codec = codecProvider.GetCodec(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(codec);\n\n                var copier = codecProvider.GetDeepCopier(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(copier);\n            }\n        }\n\n        [Fact]\n        public void SystemTextJsonCodec_DoesNotSerializeFrameworkTypes()\n        {\n            var silo = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.Services.AddSerializer(serializerBuilder => serializerBuilder.AddJsonSerializer(type =>\n                        {\n                            Assert.Fail($\"Custom type filter should not be consulted for any type in this test, but it was used for type {type}.\");\n                            return true;\n                        }));\n                    siloBuilder.UseLocalhostClustering();\n                })\n                .Build();\n            var services = silo.Services;\n            var serializer = services.GetRequiredService<Serializer>();\n            var generatedGrainReferenceType = services.GetRequiredService<IOptions<TypeManifestOptions>>().Value\n                .InterfaceProxies.First(i => ! i.IsGenericType && i.Assembly.GetCustomAttribute<FrameworkPartAttribute>() is null);\n            var codecProvider = services.GetRequiredService<CodecProvider>();\n            foreach (var type in new[] { typeof(SiloAddress), typeof(GrainReference), typeof(EventHubBatchContainer), generatedGrainReferenceType })\n            {\n                var codec = codecProvider.GetCodec(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(codec);\n\n                var copier = codecProvider.GetDeepCopier(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(copier);\n            }\n        }\n\n        [Fact]\n        public void ProtocolBuffersCodec_DoesNotSerializeFrameworkTypes()\n        {\n            var silo = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.Services.AddSerializer(serializerBuilder => serializerBuilder.AddProtobufSerializer(type =>\n                        {\n                            Assert.Fail($\"Custom type filter should not be consulted for any type in this test, but it was used for type {type}.\");\n                            return true;\n                        },\n                        type =>\n                        {\n                            Assert.Fail($\"Custom type filter should not be consulted for any type in this test, but it was used for type {type}.\");\n                            return true;\n                        }));\n                    siloBuilder.UseLocalhostClustering();\n                })\n                .Build();\n            var services = silo.Services;\n            var serializer = services.GetRequiredService<Serializer>();\n            var generatedGrainReferenceType = services.GetRequiredService<IOptions<TypeManifestOptions>>().Value\n                .InterfaceProxies.First(i => ! i.IsGenericType && i.Assembly.GetCustomAttribute<FrameworkPartAttribute>() is null);\n            var codecProvider = services.GetRequiredService<CodecProvider>();\n            foreach (var type in new[] { typeof(SiloAddress), typeof(GrainReference), typeof(EventHubBatchContainer), generatedGrainReferenceType })\n            {\n                var codec = codecProvider.GetCodec(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(codec);\n\n                var copier = codecProvider.GetDeepCopier(type);\n                Assert.IsNotType<NewtonsoftJsonCodec>(copier);\n            }\n        }\n\n        private static void TestSerializationRoundTrip(Serializer serializer)\n        {\n            var data = new JsonPoco { Prop = \"some data\" };\n            var serialized = serializer.SerializeToArray(data);\n            var subSequence = Encoding.UTF8.GetBytes(\"crazy_name\");\n\n            // The serialized data should have our custom [JsonProperty] name, 'crazy_name', in it.\n            Assert.Contains(ToString(subSequence), ToString(serialized));\n\n            var deserialized = serializer.Deserialize<JsonPoco>(serialized);\n\n            Assert.Equal(data.Prop, deserialized.Prop);\n        }\n\n        private static string ToString(byte[] bytes)\n        {\n            var result = new StringBuilder(bytes.Length * 2);\n            foreach (var b in bytes)\n            {\n                result.Append($\"{b:x2}\");\n            }\n\n            var str = result.ToString();\n            return str;\n        }\n\n        /// <summary>\n        /// Use a custom attribute to distinguish types which should be serialized using the JSON codec.\n        /// </summary>\n        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\n        internal class JsonTypeAttribute : Attribute\n        {\n        }\n\n        [JsonType]\n        public class JsonPoco\n        {\n            [JsonProperty(\"crazy_name\")]\n            public string Prop { get; set; }\n\n            [JsonProperty(\"some_flag\")]\n            public bool Flag { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Core.Tests/Serialization/MessageSerializerTests.cs",
    "content": "using System.Buffers;\nusing System.Buffers.Binary;\nusing System.IO.Pipelines;\nusing System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.CodeGeneration;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Session;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.Serialization\n{\n    /// <summary>\n    /// Tests for Orleans message serialization functionality.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class MessageSerializerTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n        private readonly MessageFactory messageFactory;\n        private readonly MessageSerializer messageSerializer;\n        private readonly SerializerSessionPool _serializerSessionPool;\n        private readonly IFieldCodec<GrainAddress> _grainAddressCodec;\n\n        public MessageSerializerTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            this.messageFactory = this.fixture.Services.GetRequiredService<MessageFactory>();\n            this.messageSerializer = this.fixture.Services.GetRequiredService<MessageSerializer>();\n            _serializerSessionPool = fixture.Services.GetRequiredService<SerializerSessionPool>();\n            _grainAddressCodec = fixture.Services.GetRequiredService<IFieldCodec<GrainAddress>>();\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task MessageTest_TtlUpdatedOnAccess()\n        {\n            var message = this.messageFactory.CreateMessage(null, InvokeMethodOptions.None);\n\n            message.TimeToLive = TimeSpan.FromSeconds(1);\n            await Task.Delay(TimeSpan.FromMilliseconds(500));\n            Assert.InRange(message.TimeToLive.Value, TimeSpan.FromMilliseconds(-1000), TimeSpan.FromMilliseconds(900));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public async Task MessageTest_TtlUpdatedOnSerialization()\n        {\n            var message = this.messageFactory.CreateMessage(null, InvokeMethodOptions.None);\n\n            message.TimeToLive = TimeSpan.FromSeconds(1);\n            await Task.Delay(TimeSpan.FromMilliseconds(500));\n            var deserializedMessage = RoundTripMessage(message);\n\n            Assert.NotNull(deserializedMessage.TimeToLive);\n            Assert.InRange(message.TimeToLive.Value, TimeSpan.FromMilliseconds(-1000), TimeSpan.FromMilliseconds(900));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public void Message_SerializeHeaderTooBig()\n        {\n            try\n            {\n                // Create a ridiculously big RequestContext\n                var maxHeaderSize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageHeaderSize;\n                RequestContext.Set(\"big_object\", new byte[maxHeaderSize + 1]);\n\n                var message = this.messageFactory.CreateMessage(null, InvokeMethodOptions.None);\n\n                var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 0));\n                var writer = pipe.Writer;\n                Assert.Throws<InvalidMessageFrameException>(() => this.messageSerializer.Write(writer, message));\n            }\n            finally\n            {\n                RequestContext.Clear();\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public void Message_SerializeBodyTooBig()\n        {\n            var maxBodySize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageBodySize;\n\n            // Create a request with a ridiculously big argument\n            var arg = new byte[maxBodySize + 1];\n            var request = new[] { arg };\n            var message = this.messageFactory.CreateMessage(request, InvokeMethodOptions.None);\n\n            var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 0));\n            var writer = pipe.Writer;\n            Assert.Throws<InvalidMessageFrameException>(() => this.messageSerializer.Write(writer, message));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public void Message_DeserializeHeaderTooBig()\n        {\n            var maxHeaderSize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageHeaderSize;\n            var maxBodySize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageBodySize;\n\n            DeserializeFakeMessage(maxHeaderSize + 1, maxBodySize - 1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Serialization\")]\n        public void Message_DeserializeBodyTooBig()\n        {\n            var maxHeaderSize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageHeaderSize;\n            var maxBodySize = this.fixture.Services.GetService<IOptions<SiloMessagingOptions>>().Value.MaxMessageBodySize;\n\n            DeserializeFakeMessage(maxHeaderSize - 1, maxBodySize + 1);\n        }\n\n        private void DeserializeFakeMessage(int headerSize, int bodySize)\n        {\n            var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 0));\n            var writer = pipe.Writer;\n\n            Span<byte> lengthFields = stackalloc byte[8];\n            BinaryPrimitives.WriteInt32LittleEndian(lengthFields, headerSize);\n            BinaryPrimitives.WriteInt32LittleEndian(lengthFields[4..], bodySize);\n            writer.Write(lengthFields);\n            writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n\n            pipe.Reader.TryRead(out var readResult);\n            var reader = readResult.Buffer;\n            Assert.Throws<InvalidMessageFrameException>(() => this.messageSerializer.TryRead(ref reader, out var message));\n        }\n\n        private Message RoundTripMessage(Message message)\n        {\n            var pipe = new Pipe(new PipeOptions(pauseWriterThreshold: 0));\n            var writer = pipe.Writer;\n            this.messageSerializer.Write(writer, message);\n            writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n\n            pipe.Reader.TryRead(out var readResult);\n            var reader = readResult.Buffer;\n            var (requiredBytes, _, _) = this.messageSerializer.TryRead(ref reader, out var deserializedMessage);\n            Assert.Equal(0, requiredBytes);\n            return deserializedMessage;\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public void MessageTest_CacheInvalidationHeader_RoundTripCompatibility()\n        {\n            var newSilo = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 55555), 55555);\n\n            var oldActivations = new List<GrainAddress>\n            {\n                GrainAddress.NewActivationAddress(SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 11111), 111111), GrainId.Create(\"test\", \"1\")),\n                GrainAddress.NewActivationAddress(SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 22222), 222222), GrainId.Create(\"test\", \"2\")),\n                new() { SiloAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 33333), 33333), GrainId = GrainId.Create(\"test\", \"3\") },\n            };\n\n            var newActivations = new List<GrainAddress>\n            {\n                GrainAddress.NewActivationAddress(newSilo, GrainId.Create(\"test\", \"1\")),\n                GrainAddress.NewActivationAddress(newSilo, GrainId.Create(\"test\", \"2\")),\n                new() { SiloAddress = newSilo, GrainId = GrainId.Create(\"test\", \"3\") },\n            };\n\n            var newUpdates = oldActivations.Zip(newActivations).Select(x => new GrainAddressCacheUpdate(x.First, x.Second)).ToList();\n\n            // Old to new\n            {\n                using var writer1Session = _serializerSessionPool.GetSession();\n                var writer = Writer.CreatePooled(writer1Session);\n                var stub = new MessageSerializerBackwardsCompatibilityStub(_grainAddressCodec);\n                var fromOld = oldActivations.ToList();\n                stub.WriteCacheInvalidationHeaders(ref writer, fromOld);\n                writer.Commit();\n\n                using var reader1Session = _serializerSessionPool.GetSession();\n                var reader = Reader.Create(writer.Output.AsReadOnlySequence(), reader1Session);\n                var toNew = messageSerializer.ReadCacheInvalidationHeaders(ref reader);\n                Assert.NotNull(toNew);\n                Assert.Equal(fromOld.Count, toNew.Count);\n                for (var i = 0; i < fromOld.Count; i++)\n                {\n                    // Only the invalid grain address can be represented.\n                    Assert.Equal(fromOld[i], toNew[i].InvalidGrainAddress);\n                    Assert.Null(toNew[i].ValidGrainAddress);\n                }\n\n                writer.Dispose();\n            }\n\n            // New to new\n            {\n                using var writer1Session = _serializerSessionPool.GetSession();\n                var writer = Writer.CreatePooled(writer1Session);\n                var fromNew = newUpdates.ToList();\n                var message = new Message { CacheInvalidationHeader = fromNew };\n                messageSerializer.WriteCacheInvalidationHeaders(ref writer, message);\n                writer.Commit();\n\n                using var reader1Session = _serializerSessionPool.GetSession();\n                var reader = Reader.Create(writer.Output.AsReadOnlySequence(), reader1Session);\n                var toNew = messageSerializer.ReadCacheInvalidationHeaders(ref reader);\n                Assert.NotNull(toNew);\n                Assert.Equal(fromNew.Count, toNew.Count);\n                for (var i = 0; i < fromNew.Count; i++)\n                {\n                    // Full fidelity is expected\n                    Assert.Equal(fromNew[i].InvalidGrainAddress, toNew[i].InvalidGrainAddress);\n                    Assert.Equal(fromNew[i].ValidGrainAddress, toNew[i].ValidGrainAddress);\n                }\n\n                writer.Dispose();\n            }\n\n            // New to old\n            {\n                using var writer1Session = _serializerSessionPool.GetSession();\n                var writer = Writer.CreatePooled(writer1Session);\n                var fromNew = newUpdates.ToList();\n                var message = new Message { CacheInvalidationHeader = fromNew };\n                messageSerializer.WriteCacheInvalidationHeaders(ref writer, message);\n                writer.Commit();\n\n                using var reader1Session = _serializerSessionPool.GetSession();\n                var reader = Reader.Create(writer.Output.AsReadOnlySequence(), reader1Session);\n                var stub = new MessageSerializerBackwardsCompatibilityStub(_grainAddressCodec);\n                var toOld = stub.ReadCacheInvalidationHeaders(ref reader);\n                Assert.NotNull(toOld);\n                Assert.Equal(fromNew.Count, toOld.Count);\n                for (var i = 0; i < fromNew.Count; i++)\n                {\n                    // Only the invalid grain address can be represented.\n                    Assert.Equal(fromNew[i].InvalidGrainAddress, toOld[i]);\n                }\n\n                writer.Dispose();\n            }\n        }\n\n        private class MessageSerializerBackwardsCompatibilityStub\n        {\n            private readonly IFieldCodec<GrainAddress> _grainAddressCodec;\n\n            public MessageSerializerBackwardsCompatibilityStub(IFieldCodec<GrainAddress> grainAddressCodec)\n            {\n                _grainAddressCodec = grainAddressCodec;\n            }\n            \n            internal List<GrainAddress> ReadCacheInvalidationHeaders<TInput>(ref Reader<TInput> reader)\n            {\n                var n = (int)reader.ReadVarUInt32();\n                if (n > 0)\n                {\n                    var list = new List<GrainAddress>(n);\n                    for (int i = 0; i < n; i++)\n                    {\n                        list.Add(_grainAddressCodec.ReadValue(ref reader, reader.ReadFieldHeader()));\n                    }\n\n                    return list;\n                }\n\n                return new List<GrainAddress>();\n            }\n\n            internal void WriteCacheInvalidationHeaders<TBufferWriter>(ref Writer<TBufferWriter> writer, List<GrainAddress> value) where TBufferWriter : IBufferWriter<byte>\n            {\n                writer.WriteVarUInt32((uint)value.Count);\n                foreach (var entry in value)\n                {\n                    _grainAddressCodec.WriteField(ref writer, 0, typeof(GrainAddress), entry);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Serialization/SerializationTests.DifferentTypes.cs",
    "content": "using System.Globalization;\nusing Orleans.Serialization;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.Serialization\n{\n    /// <summary>\n    /// Summary description for SerializationTests\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class SerializationTestsDifferentTypes\n    {\n        private readonly TestEnvironmentFixture fixture;\n\n        public SerializationTestsDifferentTypes(TestEnvironmentFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_DateTime()\n        {\n            // Local Kind\n            DateTime inputLocal = DateTime.Now;\n\n            DateTime outputLocal = this.fixture.Serializer.RoundTripSerializationForTesting(inputLocal);\n            Assert.Equal(inputLocal.ToString(CultureInfo.InvariantCulture), outputLocal.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputLocal.Kind, outputLocal.Kind);\n\n            // UTC Kind\n            DateTime inputUtc = DateTime.UtcNow;\n\n            DateTime outputUtc = this.fixture.Serializer.RoundTripSerializationForTesting(inputUtc);\n            Assert.Equal(inputUtc.ToString(CultureInfo.InvariantCulture), outputUtc.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputUtc.Kind, outputUtc.Kind);\n\n            // Unspecified Kind\n            DateTime inputUnspecified = new DateTime(0x08d27e2c0cc7dfb9);\n\n            DateTime outputUnspecified = this.fixture.Serializer.RoundTripSerializationForTesting(inputUnspecified);\n            Assert.Equal(inputUnspecified.ToString(CultureInfo.InvariantCulture), outputUnspecified.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputUnspecified.Kind, outputUnspecified.Kind);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_DateTimeOffset()\n        {\n            // Local Kind\n            DateTime inputLocalDateTime = DateTime.Now;\n            DateTimeOffset inputLocal = new DateTimeOffset(inputLocalDateTime);\n\n            DateTimeOffset outputLocal = this.fixture.Serializer.RoundTripSerializationForTesting(inputLocal);\n            Assert.Equal(inputLocal, outputLocal);\n            Assert.Equal(\n                inputLocal.ToString(CultureInfo.InvariantCulture),\n                outputLocal.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputLocal.DateTime.Kind, outputLocal.DateTime.Kind);\n\n            // UTC Kind\n            DateTime inputUtcDateTime = DateTime.UtcNow;\n            DateTimeOffset inputUtc = new DateTimeOffset(inputUtcDateTime);\n\n            DateTimeOffset outputUtc = this.fixture.Serializer.RoundTripSerializationForTesting(inputUtc);\n            Assert.Equal(inputUtc, outputUtc);\n            Assert.Equal(\n                inputUtc.ToString(CultureInfo.InvariantCulture),\n                outputUtc.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputUtc.DateTime.Kind, outputUtc.DateTime.Kind);\n\n            // Unspecified Kind\n            DateTime inputUnspecifiedDateTime = new DateTime(0x08d27e2c0cc7dfb9);\n            DateTimeOffset inputUnspecified = new DateTimeOffset(inputUnspecifiedDateTime);\n\n            DateTimeOffset outputUnspecified = this.fixture.Serializer.Deserialize<DateTimeOffset>(this.fixture.Serializer.SerializeToArray(inputUnspecified));\n            Assert.Equal(inputUnspecified, outputUnspecified);\n            Assert.Equal(\n                inputUnspecified.ToString(CultureInfo.InvariantCulture),\n                outputUnspecified.ToString(CultureInfo.InvariantCulture));\n            Assert.Equal(inputUnspecified.DateTime.Kind, outputUnspecified.DateTime.Kind);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_RecursiveSerialization()\n        {\n            TestTypeA input = new TestTypeA();\n            input.Collection = new HashSet<TestTypeA>();\n            input.Collection.Add(input);\n            _ = this.fixture.Serializer.RoundTripSerializationForTesting(input);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_CultureInfo()\n        {\n            var input = new List<CultureInfo> { CultureInfo.GetCultureInfo(\"en\"), CultureInfo.GetCultureInfo(\"de\") };\n\n            foreach (var cultureInfo in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(cultureInfo);\n                Assert.Equal(cultureInfo, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_CultureInfoList()\n        {\n            var input = new List<CultureInfo> { CultureInfo.GetCultureInfo(\"en\"), CultureInfo.GetCultureInfo(\"de\") };\n\n            var output = this.fixture.Serializer.RoundTripSerializationForTesting(input);\n            Assert.True(input.SequenceEqual(output));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple()\n        {\n            var input = new List<ValueTuple<int>> { ValueTuple.Create(1), ValueTuple.Create(100) };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple2()\n        {\n            var input = new List<ValueTuple<int, int>> { ValueTuple.Create(1, 2), ValueTuple.Create(100, 200) };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple3()\n        {\n            var input = new List<ValueTuple<int, int, int>>\n            {\n                ValueTuple.Create(1, 2, 3),\n                ValueTuple.Create(100, 200, 300)\n            };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple4()\n        {\n            var input = new List<ValueTuple<int, int, int, int>>\n            {\n                ValueTuple.Create(1, 2, 3, 4),\n                ValueTuple.Create(100, 200, 300, 400)\n            };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple5()\n        {\n            var input = new List<ValueTuple<int, int, int, int, int>>\n            {\n                ValueTuple.Create(1, 2, 3, 4, 5),\n                ValueTuple.Create(100, 200, 300, 400, 500)\n            };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple6()\n        {\n            var input = new List<ValueTuple<int, int, int, int, int, int>>\n            {\n                ValueTuple.Create(1, 2, 3, 4, 5, 6),\n                ValueTuple.Create(100, 200, 300, 400, 500, 600)\n            };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple7()\n        {\n            var input = new List<ValueTuple<int, int, int, int, int, int, int>>\n            {\n                ValueTuple.Create(1, 2, 3, 4, 5, 6, 7),\n                ValueTuple.Create(100, 200, 300, 400, 500, 600, 700)\n            };\n\n            foreach (var valueTuple in input)\n            {\n                var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n                Assert.Equal(valueTuple, output);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ValueTuple8()\n        {\n            var valueTuple = ValueTuple.Create(1, 2, 3, 4, 5, 6, 7, 8);\n            var output = this.fixture.Serializer.RoundTripSerializationForTesting(valueTuple);\n            Assert.Equal(valueTuple, output);\n        }\n    }\n\n    public static class SerializerExtensions\n    {\n        public static T RoundTripSerializationForTesting<T>(this Serializer serializer, T value) => serializer.Deserialize<T>(serializer.SerializeToArray(value));\n    }\n}"
  },
  {
    "path": "test/Orleans.Core.Tests/Serialization/SerializationTests.ImmutableCollections.cs",
    "content": "using System.Collections.Immutable;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.Serialization\n{\n    /// <summary>\n    /// Tests for serialization of immutable collections.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class SerializationTestsImmutableCollections\n    {\n        private readonly TestEnvironmentFixture fixture;\n\n        public SerializationTestsImmutableCollections(TestEnvironmentFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        private void RoundTripCollectionSerializationTest<T>(IEnumerable<T> input)\n        {\n            var output = this.fixture.Serializer.RoundTripSerializationForTesting(input);\n            Assert.Equal(input,output);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_Dictionary()\n        {\n            var original = ImmutableDictionary.CreateBuilder<string, string>();\n            original.Add(\"a\",\"b\");\n            original.Add(\"c\",\"d\");\n            var dict = original.ToImmutable();\n            \n            RoundTripCollectionSerializationTest(dict);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_Array()\n        {\n            var original = ImmutableArray.Create(\"1\",\"2\",\"3\");\n            RoundTripCollectionSerializationTest(original);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_ArrayDefault()\n        {\n            var input = default(ImmutableArray<int>);\n            var output = this.fixture.Serializer.RoundTripSerializationForTesting(input);\n            Assert.Equal(input.IsDefault, output.IsDefault);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_HashSet()\n        {\n            var original = ImmutableHashSet.Create(\"1\", \"2\", \"3\");\n            RoundTripCollectionSerializationTest(original);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_List()\n        {\n            var original = ImmutableList.Create(\"1\", \"2\", \"3\");\n            RoundTripCollectionSerializationTest(original);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_Queue()\n        {\n            var original = ImmutableQueue.Create(\"1\", \"2\", \"3\");\n            RoundTripCollectionSerializationTest(original);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_SortedSet()\n        {\n            var original = ImmutableSortedSet.Create(\"1\", \"2\", \"3\");\n            RoundTripCollectionSerializationTest(original);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ImmutableCollections\"), TestCategory(\"Serialization\")]\n        public void SerializationTests_ImmutableCollections_SortedDictionary()\n        {\n            var original = ImmutableSortedDictionary.CreateBuilder<string, string>();\n            original.Add(\"a\", \"b\");\n            original.Add(\"c\", \"d\");\n            var dict = original.ToImmutable();\n\n            RoundTripCollectionSerializationTest(dict);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/ServiceLifecycleTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.Logging;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\n#nullable enable\n\nnamespace NonSilo.Tests;\n\n[TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\npublic class ServiceLifecycleTests\n{\n    private readonly ServiceLifecycle<ISiloLifecycle> _lifecycle;\n    private readonly CancelableSiloLifecycleSubject _subject;\n    private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n\n    public ServiceLifecycleTests(ITestOutputHelper output)\n    {\n        var factory = new LoggerFactory([new XunitLoggerProvider(output)]);\n\n        _subject = new CancelableSiloLifecycleSubject(factory.CreateLogger<SiloLifecycleSubject>());\n        _lifecycle = new ServiceLifecycle<ISiloLifecycle>(factory.CreateLogger<ServiceLifecycle<ISiloLifecycle>>());\n\n        _lifecycle.Participate(_subject);\n    }\n\n    private static (Task<object?> Task, IDisposable Registration) RegisterCallback(\n        IServiceLifecycleStage stage,\n        Action<object?, CancellationToken>? action = null,\n        object? state = null,\n        bool terminateOnError = true)\n    {\n        var tcs = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);\n    \n        var registration = stage.Register((s, ct) =>\n        {\n            try\n            {\n                action?.Invoke(s, ct);\n                tcs.TrySetResult(s);\n            }\n            catch (Exception ex)\n            {\n                // We set the exception on the TCS so the test can inspect the specific failure of this callback.\n                tcs.TrySetException(ex);\n    \n                // We rethrow so the LifecycleSubject behaves according to TerminateOnError.\n                throw;\n            }\n            return Task.CompletedTask;\n        }, state, terminateOnError);\n    \n        return (tcs.Task, registration);\n    }\n\n    [Fact]\n    public async Task BasicCallbackExecution()\n    {\n        var callbackState = \"test-state\";\n\n        var (task, _) = RegisterCallback(_lifecycle.Started, (state, ct) => { }, callbackState);\n\n        await _subject.OnStart();\n\n        var result = await task.WaitAsync(Timeout);\n        Assert.Equal(callbackState, result);\n    }\n\n    [Fact]\n    public async Task Stage_WaitAsync()\n    {\n        var waitTask = _lifecycle.Started.WaitAsync();\n\n        Assert.False(waitTask.IsCompleted);\n\n        await _subject.OnStart();\n        await waitTask.WaitAsync(Timeout);\n    }\n\n    [Fact]\n    public async Task Stage_WaitAsync_Cancellation()\n    {\n        var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n\n        using var cts = new CancellationTokenSource();\n\n        // We register a blocking callback to keep the stage in a \"running\" state.\n        // This forces WaitAsync to actually block, allowing us to verify that cancelling\n        // the token interrupts the wait as expected.\n\n        _lifecycle.Started.Register((_, _) => tcs.Task);\n\n        var startTask = _subject.OnStart();\n        var waitTask = _lifecycle.Started.WaitAsync(cts.Token);\n\n        Assert.False(waitTask.IsCompleted, \"WaitAsync should be paused waiting for the stage to complete\");\n\n        await cts.CancelAsync();\n        await Assert.ThrowsAsync<TaskCanceledException>(() => waitTask);\n\n        tcs.SetResult();\n\n        await startTask;\n    }\n\n    [Fact]\n    public async Task Stage_NotifyCompleted_IsIdempotent()\n    {\n        var stage = new ServiceLifecycleNotificationStage(Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance, \"Started\");\n        var gate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);\n        var executionCount = 0;\n\n        stage.Register(async (_, _) =>\n        {\n            Interlocked.Increment(ref executionCount);\n            await gate.Task;\n        }, state: null, terminateOnError: true);\n\n        var first = stage.NotifyCompleted(CancellationToken.None);\n        var second = stage.NotifyCompleted(CancellationToken.None);\n\n        Assert.False(second.IsCompleted);\n\n        gate.SetResult();\n        await Task.WhenAll(first, second).WaitAsync(Timeout);\n\n        await stage.NotifyCompleted(CancellationToken.None).WaitAsync(Timeout);\n\n        Assert.Equal(1, executionCount);\n    }\n\n    [Fact]\n    public async Task CallbackDisposal_PreventsExecution()\n    {\n        var (task, registration) = RegisterCallback(_lifecycle.Stopping);\n\n        registration.Dispose();\n\n        await _subject.OnStart();\n        await _subject.OnStop();\n\n        Assert.False(task.IsCompleted);\n    }\n\n    [Fact]\n    public async Task CancellationToken_TriggeredOnStageCompletion()\n    {\n        var tcs = new TaskCompletionSource();\n\n        using var registration = _lifecycle.Stopping.Token.Register(tcs.SetResult);\n\n        await _subject.OnStart();\n        await _subject.OnStop();\n\n        await tcs.Task.WaitAsync(Timeout);\n    }\n\n    [Fact]\n    public async Task ErrorHandling_TerminateOnErrorFalse()\n    {\n        var (task, _) = RegisterCallback(\n        _lifecycle.Started,\n        (state, ct) => throw new InvalidOperationException(\"Test\"),\n        terminateOnError: false);\n\n        await _subject.OnStart();\n\n        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => task.WaitAsync(Timeout));\n        Assert.Equal(\"Test\", ex.Message);\n    }\n\n    [Fact]\n    public async Task ErrorHandling_TerminateOnErrorTrue()\n    {\n        var (task, _) = RegisterCallback(\n            _lifecycle.Started,\n            (state, ct) => throw new InvalidOperationException(\"Test\"),\n            terminateOnError: true);\n\n        var startTask = _subject.OnStart();\n\n        // This ensures the callback actually executed and we aren't just catching the lifecycle aborting.\n        var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => task.WaitAsync(Timeout));\n        Assert.Equal(\"Test\", ex.Message);\n\n        // Now verify the lifecycle start failed as expected.\n        await Assert.ThrowsAsync<InvalidOperationException>(() => startTask);\n    }\n\n    [Fact]\n    public async Task ErrorHandling_TerminateOnErrorTrue_MultipleFailures()\n    {\n        var (task1, _) = RegisterCallback(\n            _lifecycle.Started,\n            (_, _) => throw new InvalidOperationException(\"first\"),\n            terminateOnError: true);\n\n        var (task2, _) = RegisterCallback(\n            _lifecycle.Started,\n            (_, _) => throw new ArgumentException(\"second\"),\n            terminateOnError: true);\n\n        var startTask = _subject.OnStart();\n\n        // We swallow the start exception initially so we can inspect the individual tasks.\n        try\n        {\n            await startTask;\n        }\n        catch\n        {\n            // Ignore\n        }\n\n        // Now we wait for both TCS signals to complete (rather 'fail') before asserting.\n        // This prevents racing between the OnStart exception propagation and the TCS setting.\n\n        try { await task1.WaitAsync(Timeout); } catch { }\n        try { await task2.WaitAsync(Timeout); } catch { }\n\n        await Assert.ThrowsAsync<InvalidOperationException>(() => task1);\n        await Assert.ThrowsAsync<ArgumentException>(() => task2);\n    }\n\n    [Fact]\n    public async Task LateRegistration_ExecutedImmediately()\n    {\n        await _subject.OnStart();\n        await _subject.OnStop();\n\n        // Registering after stage completes should run immediately\n        var (task, _) = RegisterCallback(_lifecycle.Stopping);\n\n        await task.WaitAsync(TimeSpan.FromSeconds(1));\n    }\n\n    [Fact]\n    public async Task ConcurrentCallbacks_RegistrationSafe()\n    {\n        const int Count = 50;\n\n        var startSignal = new ManualResetEventSlim(false);\n        var tasks = new Task[Count];\n        var executionCount = 0;\n\n        for (var i = 0; i < Count; i++)\n        {\n            tasks[i] = Task.Run(() =>\n            {\n                startSignal.Wait();\n                RegisterCallback(_lifecycle.Started, (_, _) => Interlocked.Increment(ref executionCount));\n            });\n        }\n\n        startSignal.Set();\n\n        await Task.WhenAll(tasks);\n        await _subject.OnStart();\n\n        Assert.Equal(Count, executionCount);\n    }\n\n    [Fact]\n    public async Task MultipleStages_ExecuteInOrder()\n    {\n        var executionOrder = new ConcurrentQueue<string>();\n\n        RegisterCallback(_lifecycle.Started, (_, _) => executionOrder.Enqueue(\"Started\"));\n        RegisterCallback(_lifecycle.Stopping, (_, _) => executionOrder.Enqueue(\"Stopping\"));\n\n        // We capture the stopped task to wait on it specifically.\n        var (stoppedTask, _) = RegisterCallback(_lifecycle.Stopped, (_, _) => executionOrder.Enqueue(\"Stopped\"));\n\n        await _subject.OnStart();\n        await _subject.OnStop();\n        await stoppedTask.WaitAsync(Timeout);\n\n        var order = executionOrder.ToArray();\n\n        Assert.Equal(3, order.Length);\n        Assert.Equal(\"Started\", order[0]);\n        Assert.Equal(\"Stopping\", order[1]);\n        Assert.Equal(\"Stopped\", order[2]);\n    }\n\n    [Fact]\n    public async Task BackgroundWorker_StopsOnCancellation()\n    {\n        var workerExited = new TaskCompletionSource();\n        var token = _lifecycle.Stopping.Token;\n\n        _ = Task.Run(async () =>\n        {\n            try\n            {\n                await Task.Delay(System.Threading.Timeout.InfiniteTimeSpan, token);\n            }\n            catch (OperationCanceledException)\n            {\n                workerExited.SetResult();\n            }\n        });\n\n        await _subject.OnStart();\n        await _subject.OnStop();\n\n        await workerExited.Task.WaitAsync(Timeout);\n    }\n\n    [Fact]\n    public async Task Lifecycle_CancellationToken_PassedToCallback()\n    {\n        var tcs = new TaskCompletionSource<bool>();\n\n        // We manually register here because the logic is specific to CT handling inside the callback\n        // and returns a Task result different from the standard flow.\n        _lifecycle.Started.Register(async (state, ct) =>\n        {\n            try\n            {\n                await Task.Delay(System.Threading.Timeout.InfiniteTimeSpan, ct);\n            }\n            catch (OperationCanceledException)\n            {\n                tcs.SetResult(true);\n            }\n        });\n\n        var startTask = _subject.OnStart();\n\n        await _subject.CancelStartAsync();\n\n        try\n        {\n            await startTask;\n        }\n        catch (OperationCanceledException)\n        {\n\n        }\n\n        var tokenWasCancelled = await tcs.Task.WaitAsync(Timeout);\n        Assert.True(tokenWasCancelled);\n    }\n\n    /// <summary>\n    /// A simple cancelable version of the real subject to test for cancellations.\n    /// </summary>\n    public class CancelableSiloLifecycleSubject(ILogger<SiloLifecycleSubject> logger) : SiloLifecycleSubject(logger)\n    {\n        private readonly CancellationTokenSource _cts = new();\n\n        public override Task OnStart(CancellationToken cancellationToken = default)\n        {\n            var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cts.Token);\n            return base.OnStart(linkedCts.Token);\n        }\n\n        public Task CancelStartAsync()\n        {\n            _cts.Cancel();\n            return Task.CompletedTask;\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.Core.Tests/SiloBuilderTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.Configuration.Validators;\nusing Orleans.Hosting;\nusing Orleans.Runtime;\nusing Orleans.Statistics;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace NonSilo.Tests\n{\n    /// <summary>\n    /// A no-op implementation of IMembershipTable used for testing silo configuration\n    /// without requiring actual membership table infrastructure.\n    /// </summary>\n    public class NoOpMembershipTable : IMembershipTable\n    {\n        public Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task DeleteMembershipTableEntries(string clusterId)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task InitializeMembershipTable(bool tryInitTableVersion)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)\n        {\n            return Task.FromResult(true);\n        }\n\n        public Task<MembershipTableData> ReadAll()\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<MembershipTableData> ReadRow(SiloAddress key)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task UpdateIAmAlive(MembershipEntry entry)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion)\n        {\n            return Task.FromResult(true);\n        }\n    }\n\n    /// <summary>\n    /// Tests for the Orleans SiloBuilder, which is responsible for configuring and building Orleans silo instances.\n    /// These tests verify configuration validation, service registration, and proper initialization of silo components\n    /// without requiring a full Orleans cluster. Silos are the primary hosting units for grains in Orleans.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    [TestCategory(\"Hosting\")]\n    public class SiloBuilderTests\n    {\n        /// <summary>\n        /// Tests basic silo builder configuration, verifying that a silo can be successfully built\n        /// with localhost clustering and required configuration options.\n        /// </summary>\n        [Fact]\n        public void SiloBuilderTest()\n        {\n            var host = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .UseLocalhostClustering()\n                        .Configure<ClusterOptions>(options => options.ClusterId = \"someClusterId\")\n                        .Configure<EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback);\n                })\n                .UseDefaultServiceProvider((context, options) =>\n                {\n                    options.ValidateScopes = true;\n                    options.ValidateOnBuild = true;\n                })\n                .Build();\n\n            var clusterClient = host.Services.GetRequiredService<IClusterClient>();\n        }\n\n        /// <summary>\n        /// Grain's CollectionAgeLimit must be > 0 minutes.\n        /// </summary>\n        [Fact]\n        public async Task SiloBuilder_GrainCollectionOptionsForZeroSecondsAgeLimitTest()\n        {\n            await Assert.ThrowsAsync<OrleansConfigurationException>(async () =>\n            {\n                await new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .Configure<ClusterOptions>(options => { options.ClusterId = \"GrainCollectionClusterId\"; options.ServiceId = \"GrainCollectionServiceId\"; })\n                        .Configure<EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback)\n                        .ConfigureServices(services => services.AddSingleton<IMembershipTable, NoOpMembershipTable>())\n                        .Configure<GrainCollectionOptions>(options => options\n                                    .ClassSpecificCollectionAge\n                                    .Add(typeof(CollectionSpecificAgeLimitForZeroSecondsActivationGcTestGrain).FullName, TimeSpan.Zero));\n                }).RunConsoleAsync();\n            });\n        }\n\n        /// <summary>\n        /// ClusterMembershipOptions.NumProbedSilos must be greater than ClusterMembershipOptions.NumVotesForDeathDeclaration.\n        /// </summary>\n        [Fact]\n        public async Task SiloBuilder_ClusterMembershipOptionsValidators()\n        {\n            await Assert.ThrowsAsync<OrleansConfigurationException>(async () =>\n            {\n                await new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .UseLocalhostClustering()\n                        .Configure<ClusterMembershipOptions>(options => { options.NumVotesForDeathDeclaration = 10; options.NumProbedSilos = 1; });\n                }).RunConsoleAsync();\n            });\n\n            await Assert.ThrowsAsync<OrleansConfigurationException>(async () =>\n            {\n                await new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .UseLocalhostClustering()\n                        .Configure<ClusterMembershipOptions>(options => { options.NumVotesForDeathDeclaration = 0; });\n                }).RunConsoleAsync();\n            });\n        }\n\n        /// <summary>\n        /// Ensures <see cref=\"LoadSheddingValidator\"/> fails when LoadSheddingLimit greater than 100.\n        /// </summary>\n        [Fact]\n        public async Task SiloBuilder_LoadSheddingValidatorAbove100ShouldFail()\n        {\n            await Assert.ThrowsAsync<OrleansConfigurationException>(async () =>\n            {\n                await new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .UseLocalhostClustering()\n                        .Configure<ClusterOptions>(options => options.ClusterId = \"someClusterId\")\n                        .Configure<EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback)\n                        .ConfigureServices(services => services.AddSingleton<IMembershipTable, NoOpMembershipTable>())\n                        .Configure<LoadSheddingOptions>(options =>\n                        {\n                            options.LoadSheddingEnabled = true;\n                            options.CpuThreshold = 101;\n                        });\n                }).RunConsoleAsync();\n            });\n        }\n\n        /// <summary>\n        /// Tests that a silo cannot start without any grain classes or interfaces registered.\n        /// This ensures silos have actual work to perform before they can be started.\n        /// </summary>\n        [Fact]\n        public async Task SiloBuilderThrowsDuringStartupIfNoGrainsAdded()\n        {\n            using var host = new HostBuilder()\n                .UseOrleans((ctx, siloBuilder) =>\n                {\n                    // Add only an assembly with generated serializers but no grain interfaces or grain classes\n                    siloBuilder.UseLocalhostClustering()\n                    .Configure<GrainTypeOptions>(options =>\n                    {\n                        options.Classes.Clear();\n                        options.Interfaces.Clear();\n                    });\n                }).Build();\n\n            await Assert.ThrowsAsync<OrleansConfigurationException>(() => host.StartAsync());\n        }\n\n        /// <summary>\n        /// Tests that attempting to configure both a client and a silo in the same host throws an exception.\n        /// Orleans requires separate hosts for silos and clients.\n        /// </summary>\n        [Fact]\n        public void SiloBuilderThrowsDuringStartupIfClientBuildersAdded()\n        {\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                _ = new HostBuilder()\n                    .UseOrleansClient((ctx, clientBuilder) =>\n                    {\n                        clientBuilder.UseLocalhostClustering();\n                    })\n                    .UseOrleans((ctx, siloBuilder) =>\n                    {\n                        siloBuilder.UseLocalhostClustering();\n                    });\n            });\n        }\n\n        /// <summary>\n        /// Tests that attempting to configure both a client and a silo using the Host.CreateApplicationBuilder API throws an exception.\n        /// This verifies that the same restriction applies to the modern hosting API.\n        /// </summary>\n        [Fact]\n        public void SiloBuilderWithHotApplicationBuilderThrowsDuringStartupIfClientBuildersAdded()\n        {\n            Assert.Throws<OrleansConfigurationException>(() =>\n            {\n                _ = Host.CreateApplicationBuilder()\n                    .UseOrleansClient(clientBuilder =>\n                    {\n                        clientBuilder.UseLocalhostClustering();\n                    })\n                    .UseOrleans(siloBuilder =>\n                    {\n                        siloBuilder.UseLocalhostClustering();\n                    });\n            });\n        }\n\n        private class MyService\n        {\n            public int Id { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Utilities/DelegateAsyncTimer.cs",
    "content": "using Orleans.Runtime;\n\nnamespace NonSilo.Tests.Utilities\n{\n    internal class DelegateAsyncTimer : IAsyncTimer\n    {\n        private readonly Func<TimeSpan?, Task<bool>> nextTick;\n\n        public DelegateAsyncTimer(Func<TimeSpan?, Task<bool>> nextTick)\n        {\n            this.nextTick = nextTick;\n        }\n\n        public int DisposedCounter { get; private set; }\n\n        public Task<bool> NextTick(TimeSpan? overrideDelay = null) => this.nextTick(overrideDelay);\n\n        public bool CheckHealth(DateTime lastCheckTime, out string reason)\n        {\n            reason = default;\n            return true;\n        }\n\n        public void Dispose() => ++this.DisposedCounter;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Core.Tests/Utilities/DelegateAsyncTimerFactory.cs",
    "content": "using Orleans.Runtime;\n\nnamespace NonSilo.Tests.Utilities\n{\n    internal class DelegateAsyncTimerFactory : IAsyncTimerFactory\n    {\n        public DelegateAsyncTimerFactory(Func<TimeSpan, string, IAsyncTimer> create)\n        {\n            this.CreateDelegate = create;\n        }\n\n        public Func<TimeSpan, string, IAsyncTimer> CreateDelegate { get; set; }\n\n        public IAsyncTimer Create(TimeSpan period, string name) => this.CreateDelegate(period, name);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/GenericGrain.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Dashboard;\nusing Orleans.Dashboard.Metrics;\n\nnamespace TestGrains\n{\n    public interface IGenericGrain<T> : IGrainWithStringKey\n    {\n        Task<T> Echo(T value);\n\n        Task<T> EchoNoProfiling(T value);\n    }\n\n    internal class GenericGrain<T> : Grain, IGenericGrain<T>\n    {\n        private readonly IGrainProfiler profiler;\n\n        public GenericGrain(IGrainProfiler profiler)\n        {\n            this.profiler = profiler;\n        }\n\n        public Task<T> Echo(T value)\n        {\n            return Task.FromResult(value);\n        }\n\n        [NoProfiling]\n        public async Task<T> EchoNoProfiling(T value)\n        {\n            await profiler.TrackAsync<GenericGrain<T>>(() => Task.Delay(1000));\n\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/Orleans.Dashboard.TestGrains.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n\t  <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Core\\Orleans.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Dashboard\\Orleans.Dashboard\\Orleans.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Dashboard\\Orleans.Dashboard.Abstractions\\Orleans.Dashboard.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestCalls.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans;\n\nnamespace TestGrains\n{\n    public static class TestCalls\n    {\n        public static Task Run(IGrainFactory client, CancellationToken cancellationToken)\n        {\n            return Task.Run(async () =>\n            {\n                var messageGrain = client.GetGrain<ITestMessageBasedGrain>(42);\n\n                await messageGrain.Receive(\"string\");\n                await messageGrain.ReceiveVoid(DateTime.UtcNow);\n                await messageGrain.Notify(null);\n\n                var genericGrain = client.GetGrain<ITestGenericGrain<string, int>>(\"test\");\n\n                await genericGrain.TestT(\"string\");\n                await genericGrain.TestU(1);\n                await genericGrain.TestTU(\"string\", 1);\n\n                var random = new Random();\n\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    try\n                    {\n                        var testGrain = client.GetGrain<ITestGrain>(random.Next(500));\n\n                        await Task.Delay(2000);\n\n                        await testGrain.ExampleMethod1();\n                        await testGrain.ExampleMethod2();\n\n                        var genericClient = client.GetGrain<IGenericGrain<string>>(\"foo\");\n\n                        await genericClient.Echo(\"hello world\");\n\n                        await genericClient.EchoNoProfiling(\"hello world\");\n                    }\n                    catch\n                    {\n                        // Grain might throw exception to test error rate.\n                    }\n                }\n            });\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestGenericGrain.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Orleans;\n\nnamespace TestGrains\n{\n    public interface ITestGenericGrain<T, U> : IGrainWithStringKey\n    {\n        Task<T> TestT(T value);\n\n        Task<U> TestU(U value);\n\n        Task<T> TestTU(T value1, U value2);\n    }\n\n    public class TestGenericGrain<T, U> : Grain, ITestGenericGrain<T, U>\n    {\n        public Task<T> TestT(T value)\n        {\n            return Task.FromResult(value);\n        }\n\n        public Task<T> TestTU(T value1, U value2)\n        {\n            return Task.FromResult(value1);\n        }\n\n        public Task<U> TestU(U value)\n        {\n            return Task.FromResult(value);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestGrain.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\n\nnamespace TestGrains\n{\n    public interface ITestGrain : IGrainWithIntegerKey\n    {\n        Task ExampleMethod1();\n\n        Task ExampleMethod2();\n    }\n\n    public class TestGrain : Grain, ITestGrain, IRemindable\n    {\n        private readonly Random random = new();\n\n        public async Task ExampleMethod1()\n        {\n            await Task.Delay(random.Next(100));\n        }\n\n        public Task ExampleMethod2()\n        {\n            if (random.Next(100) > 50)\n            {\n                throw new Exception();\n            }\n\n            return Task.CompletedTask;\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await this.RegisterOrUpdateReminder(\"Frequent\", TimeSpan.Zero, TimeSpan.FromMinutes(1));\n            await this.RegisterOrUpdateReminder(\"Daily\", TimeSpan.Zero, TimeSpan.FromDays(1));\n            await this.RegisterOrUpdateReminder(\"Weekly\", TimeSpan.Zero, TimeSpan.FromDays(7));\n        }\n\n        public Task ReceiveReminder(string reminderName, TickStatus status)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestGrainsHostedService.cs",
    "content": "﻿using Microsoft.Extensions.Hosting;\nusing Orleans;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace TestGrains\n{\n    public class TestGrainsHostedService : IHostedService\n    {\n        private readonly IGrainFactory grainFactory;\n        private readonly CancellationTokenSource stop = new();\n\n        public TestGrainsHostedService(IGrainFactory grainFactory)\n        {\n            this.grainFactory = grainFactory;\n        }\n\n        public Task StartAsync(CancellationToken cancellationToken)\n        {\n            TestCalls.Run(grainFactory, stop.Token);\n\n            return Task.CompletedTask;\n        }\n\n        public Task StopAsync(CancellationToken cancellationToken)\n        {\n            stop.Cancel();\n\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestMessageBasedGrain.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Orleans;\n\nnamespace TestGrains\n{\n    public interface ITestMessageBasedGrain : IGrainWithIntegerKey\n    {\n        Task<object> Receive(object message);\n\n        Task ReceiveVoid(object message);\n\n        Task Notify(object message);\n    }\n\n    public class TestMessageBasedGrain : Grain, ITestMessageBasedGrain\n    {\n        public Task<object> Receive(object message)\n        {\n            return Task.FromResult((object) null);\n        }\n\n        public Task ReceiveVoid(object message)\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task Notify(object message)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestStateCompoundKeyGrain.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Orleans;\n\nnamespace TestGrains\n{\n    public interface ITestStateCompoundKeyGrain : IGrainWithIntegerCompoundKey\n    {\n        Task<InMemoryCounterState> GetState();\n    }\n\n    public class TestStateCompoundKeyGrain : Grain, ITestStateCompoundKeyGrain\n    {\n        private readonly Random _random = new();\n        private readonly InMemoryCounterState _state;\n\n        public TestStateCompoundKeyGrain()\n        {\n            _state = new InMemoryCounterState()\n            {\n                Counter = _random.Next(100),\n                ActivatedDateTime = DateTime.UtcNow\n            };\n        }\n\n        public Task<InMemoryCounterState> GetState()\n        {\n            return Task.FromResult(_state);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestStateGrain.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.Runtime;\n\nnamespace TestGrains\n{\n    public interface ITestStateGrain : IGrainWithIntegerKey\n    {\n        Task<CounterState> GetCounterState();\n        Task WriteCounterState(CounterState state);\n    }\n\n    public class TestStateGrain : Grain, ITestStateGrain\n    {\n        private readonly Random random = new();\n\n        private readonly IPersistentState<CounterState> _counter;\n\n        public TestStateGrain(\n            [PersistentState(\"counter\")]IPersistentState <CounterState> counter)\n        {\n            _counter = counter;\n        }\n\n        public Task<CounterState> GetCounterState()\n        {\n            return Task.FromResult(_counter.State);\n        }\n\n        public async Task WriteCounterState(CounterState state)\n        {\n            _counter.State = state;\n            await _counter.WriteStateAsync();\n        }\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            await base.OnActivateAsync(cancellationToken);\n            _counter.State.Counter = random.Next(100);\n            _counter.State.CurrentDateTime = DateTime.UtcNow;\n            await _counter.WriteStateAsync();\n        }\n    }\n\n    [GenerateSerializer]\n    public class CounterState\n    {\n        [Id(0)]\n        public int Counter { get; set; }\n        [Id(1)]\n        public DateTime CurrentDateTime { get; set; }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.TestGrains/TestStateInMemoryGrain.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Orleans;\n\nnamespace TestGrains\n{\n    public interface ITestStateInMemoryGrain : IGrainWithIntegerKey\n    {\n        Task<InMemoryCounterState> GetState();\n    }\n\n    public class TestStateInMemoryGrain : Grain, ITestStateInMemoryGrain\n    {\n        private readonly Random _random = new();\n        private readonly InMemoryCounterState _state;\n\n        public TestStateInMemoryGrain()\n        {\n            _state = new InMemoryCounterState()\n            {\n                Counter = _random.Next(100),\n                ActivatedDateTime = DateTime.UtcNow\n            };\n        }\n\n        public Task<InMemoryCounterState> GetState()\n        {\n            return Task.FromResult(_state);\n        }\n    }\n\n    [GenerateSerializer]\n    public class InMemoryCounterState\n    {\n        [Id(0)]\n        public int Counter { get; set; }\n        [Id(1)]\n        public DateTime ActivatedDateTime { get; set; }\n    }\n}"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/EmbeddedAssetTests.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Http.HttpResults;\nusing Orleans.Dashboard;\nusing Xunit;\n\nnamespace UnitTests\n{\n    public class EmbeddedAssetTests\n    {\n        private static readonly Assembly DashboardAssembly = typeof(DashboardOptions).Assembly;\n        private const string ResourcePrefix = \"Orleans.Dashboard.wwwroot.\";\n\n        [Fact]\n        public void Assembly_ContainsEmbeddedResources()\n        {\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n\n            Assert.NotEmpty(resourceNames);\n        }\n\n        [Fact]\n        public void Assembly_ContainsIndexHtml()\n        {\n            var resourceName = $\"{ResourcePrefix}index.html\";\n\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n\n            Assert.Contains(resourceName, resourceNames);\n        }\n\n        [Fact]\n        public void Assembly_ContainsIndexCss()\n        {\n            var resourceName = $\"{ResourcePrefix}index.css\";\n\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n\n            Assert.Contains(resourceName, resourceNames);\n        }\n\n        [Fact]\n        public void Assembly_ContainsIndexJs()\n        {\n            var resourceName = $\"{ResourcePrefix}index.min.js\";\n\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n\n            Assert.Contains(resourceName, resourceNames);\n        }\n\n        [Fact]\n        public void Assembly_ContainsFavicon()\n        {\n            var resourceName = $\"{ResourcePrefix}favicon.ico\";\n\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n\n            Assert.Contains(resourceName, resourceNames);\n        }\n\n        [Fact]\n        public void Assembly_ContainsFontFiles()\n        {\n            var resourceNames = DashboardAssembly.GetManifestResourceNames();\n            var fontResources = resourceNames.Where(n => n.StartsWith($\"{ResourcePrefix}fonts.\", StringComparison.Ordinal));\n\n            Assert.NotEmpty(fontResources);\n        }\n\n        [Fact]\n        public void IndexHtml_IsNotEmpty()\n        {\n            var resourceName = $\"{ResourcePrefix}index.html\";\n\n            using var stream = DashboardAssembly.GetManifestResourceStream(resourceName);\n\n            Assert.NotNull(stream);\n            Assert.True(stream.Length > 0, \"index.html should not be empty\");\n        }\n\n        [Fact]\n        public void IndexCss_IsNotEmpty()\n        {\n            var resourceName = $\"{ResourcePrefix}index.css\";\n\n            using var stream = DashboardAssembly.GetManifestResourceStream(resourceName);\n\n            Assert.NotNull(stream);\n            Assert.True(stream.Length > 0, \"index.css should not be empty\");\n        }\n\n        [Fact]\n        public void IndexJs_IsNotEmpty()\n        {\n            var resourceName = $\"{ResourcePrefix}index.min.js\";\n\n            using var stream = DashboardAssembly.GetManifestResourceStream(resourceName);\n\n            Assert.NotNull(stream);\n            Assert.True(stream.Length > 0, \"index.min.js should not be empty\");\n        }\n\n        [Fact]\n        public void IndexHtml_ContainsExpectedContent()\n        {\n            var resourceName = $\"{ResourcePrefix}index.html\";\n\n            using var stream = DashboardAssembly.GetManifestResourceStream(resourceName);\n            using var reader = new System.IO.StreamReader(stream!);\n            var content = reader.ReadToEnd();\n\n            Assert.Contains(\"<!DOCTYPE html>\", content, StringComparison.OrdinalIgnoreCase);\n            Assert.Contains(\"Orleans Dashboard\", content);\n            Assert.Contains(\"index.min.js\", content);\n            Assert.Contains(\"index.css\", content);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_CanBeInstantiated()\n        {\n            // This tests that the EmbeddedAssetProvider can load all resources\n            // without throwing exceptions during construction\n            var provider = new EmbeddedAssetProvider();\n\n            Assert.NotNull(provider);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_ServesIndexHtml()\n        {\n            var provider = new EmbeddedAssetProvider();\n            var httpContext = new DefaultHttpContext();\n\n            var result = provider.ServeAsset(\"index.html\", httpContext);\n\n            // Result should not be NotFound - it should be a file result\n            Assert.IsNotType<NotFound>(result);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_ServesIndexCss()\n        {\n            var provider = new EmbeddedAssetProvider();\n            var httpContext = new DefaultHttpContext();\n\n            var result = provider.ServeAsset(\"index.css\", httpContext);\n\n            Assert.IsNotType<NotFound>(result);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_ServesIndexJs()\n        {\n            var provider = new EmbeddedAssetProvider();\n            var httpContext = new DefaultHttpContext();\n\n            var result = provider.ServeAsset(\"index.min.js\", httpContext);\n\n            Assert.IsNotType<NotFound>(result);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_ServesFontFiles()\n        {\n            var provider = new EmbeddedAssetProvider();\n            var httpContext = new DefaultHttpContext();\n            var assembly = typeof(EmbeddedAssetProvider).GetTypeInfo().Assembly;\n            var fontResourceName = assembly\n                .GetManifestResourceNames()\n                .FirstOrDefault(name =>\n                    name.EndsWith(\".woff2\", StringComparison.Ordinal) ||\n                    name.EndsWith(\".woff\", StringComparison.Ordinal));\n\n            Assert.NotNull(fontResourceName);\n\n            var resourcePrefix = typeof(EmbeddedAssetProvider).Namespace + \".\";\n            var assetName = fontResourceName.StartsWith(resourcePrefix, StringComparison.Ordinal)\n                ? fontResourceName.Substring(resourcePrefix.Length)\n                : fontResourceName;\n\n            var result = provider.ServeAsset(assetName, httpContext);\n            Assert.IsNotType<NotFound>(result);\n        }\n\n        [Fact]\n        public void EmbeddedAssetProvider_ReturnsNotFoundForMissingAsset()\n        {\n            var provider = new EmbeddedAssetProvider();\n            var httpContext = new DefaultHttpContext();\n\n            var result = provider.ServeAsset(\"nonexistent.file\", httpContext);\n\n            Assert.IsType<NotFound>(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/GrainStateTests.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\nusing Orleans.Dashboard;\nusing Orleans.TestingHost;\nusing TestGrains;\nusing Orleans.Hosting;\nusing Microsoft.Extensions.Hosting;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Dashboard.Implementation.Helpers;\nusing Orleans.Dashboard.Core;\n\nnamespace UnitTests\n{\n    public class GrainStateTests : IDisposable\n    {\n        private readonly TestCluster _cluster;\n        public GrainStateTests()\n        {\n            var builder = new TestClusterBuilder();\n            builder.AddSiloBuilderConfigurator<TestSiloConfigurations>();\n            _cluster = builder.Build();\n            _cluster.Deploy();\n        }\n\n        public void Dispose()\n        {\n            _cluster.StopAllSilos();\n        }\n\n        [Fact]\n        public async Task TestGetGrainsTypes()\n        {\n            var dashboardGrain = _cluster.GrainFactory.GetGrain<IDashboardGrain>(1);\n            var types = await dashboardGrain.GetGrainTypes();\n\n            Assert.Contains(\"TestGrains.TestStateInMemoryGrain\", types.Value);\n        }\n\n        [Fact]\n        public async Task TestWithGetStateMethod()\n        {\n            var dashboardGrain = _cluster.GrainFactory.GetGrain<IDashboardGrain>(1);\n            var stateGrain = _cluster.GrainFactory.GetGrain<ITestStateInMemoryGrain>(123);\n\n            var immutableState = await dashboardGrain.GetGrainState(\"123\", \"TestGrains.TestStateInMemoryGrain\");\n\n            dynamic state = JObject.Parse(immutableState.Value);\n\n            var stateFromGrain = await stateGrain.GetState();\n            int counter = state.GetState.Counter;\n            Assert.Equal(stateFromGrain.Counter, counter);\n        }\n\n        [Fact]\n        public async Task TestWithIStorageField()\n        {\n            var dashboardGrain = _cluster.GrainFactory.GetGrain<IDashboardGrain>(1);\n            var stateGrain = _cluster.GrainFactory.GetGrain<ITestStateGrain>(123);\n            await stateGrain.WriteCounterState(new CounterState\n            {\n                Counter = 5,\n                CurrentDateTime = DateTime.UtcNow\n            });\n            var immutableState = await dashboardGrain.GetGrainState(\"123\", \"TestGrains.TestStateGrain\");\n\n            dynamic state = JObject.Parse(immutableState.Value);\n\n            var stateFromGrain = await stateGrain.GetCounterState();\n            int counter = state.GetCounterState.Counter;\n            Assert.Equal(stateFromGrain.Counter, counter);\n        }\n\n\n        public class TestSiloConfigurations : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder.UseInMemoryReminderService();\n                siloBuilder.AddMemoryGrainStorageAsDefault();\n\n                siloBuilder.Services.AddOrleansDashboardForSiloCore();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/Orleans.Dashboard.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Dashboard\\Orleans.Dashboard\\Orleans.Dashboard.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"..\\Orleans.Dashboard.TestGrains\\Orleans.Dashboard.TestGrains.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Service Include=\"{82a7f48d-3b50-4b1e-b82e-3ada8210c358}\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/RingBufferTests.cs",
    "content": "using Orleans.Dashboard.Metrics.History;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace UnitTests\n{\n    public class RingBufferTests\n    {\n        [Fact]\n        public void Should_create_empty_buffer()\n        {\n            var buffer = new RingBuffer<int>(10);\n\n            Assert.Empty(ToList(buffer));\n        }\n\n        [Fact]\n        public void Should_add_item_to_buffer_until_capacity_reached()\n        {\n            var buffer = new RingBuffer<int>(10);\n\n            for (var i = 0; i < 10; i++)\n            {\n                buffer.Add(i);\n\n                Assert.Equal(Enumerable.Range(0, i + 1).ToArray(), ToList(buffer).ToArray());\n            }\n        }\n\n        [Fact]\n        public void Should_add_item_over_capacity()\n        {\n            var buffer = new RingBuffer<int>(10);\n\n            for (var i = 0; i < 100; i++)\n            {\n                buffer.Add(i);\n\n                Assert.Equal(Enumerable.Range(0, i + 1).TakeLast(10).ToArray(), ToList(buffer).ToArray());\n            }\n        }\n\n        private static List<T> ToList<T>(RingBuffer<T> buffer)\n        {\n            var result = new List<T>(); \n\n            for (var i = 0; i < buffer.Count; i++)\n            {\n                result.Add(buffer[i]);\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/TraceHistoryTests.cs",
    "content": "using Orleans.Dashboard.Metrics.History;\nusing Orleans.Dashboard.Model;\nusing System;\nusing System.Linq;\nusing Xunit;\n\nnamespace UnitTests;\n\npublic class TraceHistoryTests\n{\n    private readonly DateTime _startTime = DateTime.UtcNow;\n    private int _seconds;\n\n    private void Add(ITraceHistory history, int count)\n    {\n        for (var i = 0; i < count; i++)\n        {\n            history.Add(_startTime.AddSeconds(_seconds), \"SILO1\", new[]\n            {\n                new SiloGrainTraceEntry \n                {\n                    Grain = \"GRAIN1\",\n                    Method = \"METHOD1\",\n                    Count = 1,\n                    ExceptionCount = 0,\n                    ElapsedTime = 10\n                }\n            });\n\n            history.Add(_startTime.AddSeconds(_seconds), \"SILO2\", new[]\n            {\n                new SiloGrainTraceEntry \n                {\n                    Grain = \"GRAIN1\",\n                    Method = \"METHOD1\",\n                    Count = 100,\n                    ExceptionCount = 10,\n                    ElapsedTime = 200\n                }\n            });\n\n            _seconds++;\n        }\n    }\n\n    private ITraceHistory CreateHistory() => new TraceHistory(100);\n\n    [Fact]\n    public void TestTraceHistoryIsLimitedTo100()\n    {\n        var history = CreateHistory();\n\n        // Seed with 100 values\n        Add(history, 100);\n\n        // check there are 100 values in the results\n        var grainTraceDictionary = history.QueryAll();\n\n        Assert.Equal(100, grainTraceDictionary.Keys.Count);\n\n        // Add another 10 values\n        Add(history, 10);\n\n        var grainTraceDictionary2 = history.QueryAll();\n\n        Assert.Equal(100, grainTraceDictionary2.Keys.Count);\n    }\n\n    [Fact]\n    public void TestTraceHistoryQueryAll()\n    {\n        var history = CreateHistory();\n\n        Add(history, 100);\n\n        var silo1History = history.QuerySilo(\"SILO1\");\n\n        Assert.Equal(100, silo1History.Keys.Count);\n    }\n\n    [Fact]\n    public void TestTraceHistoryQueryGrain()\n    {\n        var history = CreateHistory();\n\n        Add(history, 100);\n\n        var grainDictionary = history.QueryGrain(\"GRAIN1\");\n\n        Assert.Single(grainDictionary.Keys);\n        Assert.Equal(\"GRAIN1.METHOD1\", grainDictionary.Keys.First());\n        Assert.Equal(100, grainDictionary[\"GRAIN1.METHOD1\"].Keys.Count);\n    }\n\n    [Fact]\n    public void TestTraceHistoryGroupByGrainAndSilo()\n    {\n        var history = CreateHistory();\n\n        Add(history, 100);\n\n        var traceAggregate = history.GroupByGrainAndSilo().ToList();\n\n        Assert.Equal(2, traceAggregate.Count);\n\n        var silo1Aggregate = traceAggregate.FirstOrDefault(x => x.SiloAddress == \"SILO1\");\n\n        Assert.Equal(\"SILO1\", silo1Aggregate.SiloAddress);\n        Assert.Equal(\"GRAIN1\", silo1Aggregate.Grain);\n        Assert.Equal(100, silo1Aggregate.Count);\n        Assert.Equal(0, silo1Aggregate.ExceptionCount);\n        Assert.Equal(1000, silo1Aggregate.ElapsedTime);\n\n        var silo2Aggregate = traceAggregate.FirstOrDefault(x => x.SiloAddress == \"SILO2\");\n\n        Assert.Equal(\"SILO2\", silo2Aggregate.SiloAddress);\n        Assert.Equal(\"GRAIN1\", silo2Aggregate.Grain);\n        Assert.Equal(100 * 100, silo2Aggregate.Count);\n        Assert.Equal(10 * 100, silo2Aggregate.ExceptionCount);\n        Assert.Equal(200 * 100, silo2Aggregate.ElapsedTime);\n    }\n\n\n    [Fact]\n    public void TestTraceHistoryTopGrainMethods()\n    {\n        var history = CreateHistory();\n\n        Add(history, 100);\n\n        var results = history.AggregateByGrainMethod().ToList();\n        var result = results.First();\n\n        Assert.Single(results);\n        Assert.Equal(100 + (100 * 100), result.Count);\n        Assert.Equal(10 * 100, result.ExceptionCount);\n        Assert.Equal(1000 + (200 * 100), result.ElapsedTime);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Dashboard.Tests/Orleans.Dashboard.UnitTests/TypeFormatterTests.cs",
    "content": "using Orleans.Dashboard.Metrics.TypeFormatting;\nusing Xunit;\n\nnamespace UnitTests\n{\n    public class TypeFormatterTests\n    {\n        [Fact]\n        public void TestSimpleType()\n        {\n            var example = \"System.String\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\"String\", name);\n        }\n\n        [Fact]\n        public void TestCustomType()\n        {\n            var example = \"ExecuteAsync(CreateApp)\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\"ExecuteAsync(CreateApp)\", name);\n        }\n\n        [Fact]\n        public void TestFriendlyNameForStrings()\n        {\n            var example = \"TestGrains.GenericGrain`1[[System.String,mscorlib]]\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\"TestGrains.GenericGrain<String>\", name);\n        }\n\n        [Fact]\n        public void TestGenericWithMultipleTs()\n        {\n            var example = \"TestGrains.IGenericGrain`1[[System.Tuple`2[[string],[int]]]]\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\"TestGrains.IGenericGrain<Tuple<string, int>>\", name);\n        }\n\n        [Fact]\n        public void TestGenericGrainWithMultipleTs()\n        {\n            var example = \"TestGrains.ITestGenericGrain`2[[string],[int]]\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\"TestGrains.ITestGenericGrain<string, int>\", name);\n        }\n\n        [Fact]\n        public void TestGenericGrainWithFsType()\n        {\n            var example = \".Program.Progress\";\n\n            var name = TypeFormatter.Parse(example);\n\n            Assert.Equal(\".Program.Progress\", name);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/AsyncEnumerableGrainCallTests.cs",
    "content": "#nullable enable\nusing System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests;\n\n/// <summary>\n/// Tests support for grain methods which return <see cref=\"IAsyncEnumerable{T}\"/>.\n/// These tests verify Orleans' ability to handle streaming results from grain methods,\n/// including batching, error handling, cancellation, and proper resource cleanup.\n/// Orleans uses a grain extension mechanism to manage the lifecycle of async enumerators\n/// across the distributed system.\n/// </summary>\npublic class AsyncEnumerableGrainCallTests : HostedTestClusterEnsureDefaultStarted\n{\n    public AsyncEnumerableGrainCallTests(DefaultClusterFixture fixture) : base(fixture)\n    {\n    }\n\n    /// <summary>\n    /// Tests basic async enumerable functionality where a grain produces values that are consumed by the client.\n    /// Verifies that values are correctly transmitted and the enumerator is properly disposed after use.\n    /// This demonstrates Orleans' support for streaming data from grains without keeping all data in memory.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 5))\n            {\n                await Task.Delay(200);\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Complete();\n        });\n\n        var values = new List<string>();\n        await foreach (var entry in grain.GetValues())\n        {\n            values.Add(entry);\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(5, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests preemptive cancellation of async enumerable streams before any values are yielded.\n    /// Verifies that when a CancellationToken is cancelled before the enumeration starts yielding values,\n    /// the operation properly throws OperationCanceledException and no values are returned.\n    /// This test ensures Orleans handles early cancellation gracefully in distributed streaming scenarios.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_CancelBeforeYield()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        // Set up cancellation tokens - one for test timeout, one for the grain call\n        using var testCts = new CancellationTokenSource(TimeSpan.FromSeconds(35));\n        using var callCts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n\n        // Task to cancel the enumeration after it starts but before it yields\n        var enumerationStartedTask = Task.Run(async () =>\n        {\n            await grain.WaitForCall(callId); // Wait for enumeration to begin\n            callCts.Cancel(); // Cancel before any values are yielded\n        });\n\n        try\n        {\n            // Start enumeration with a slow grain method and un-cancelled token\n            await foreach (var entry in grain.SleepyEnumerable(callId, TimeSpan.FromSeconds(25), callCts.Token))\n            {\n                Assert.Fail(\"Should have thrown due to cancellation before yielding any values.\");\n            }\n\n            Assert.Fail(\"Enumeration should not have completed without an exception.\");\n        }\n        catch (OperationCanceledException)\n        {\n            // Verify the cancellation token was indeed cancelled\n            Assert.True(callCts.Token.IsCancellationRequested);\n        }\n\n        await enumerationStartedTask;\n\n        // Wait for the grain to record the cancellation\n        while (true)\n        {\n            var canceledCalls = await grain.GetCanceledCalls();\n            if (canceledCalls.Contains(callId))\n            {\n                break;\n            }\n\n            await Task.Delay(TimeSpan.FromMilliseconds(10));\n            if (testCts.IsCancellationRequested)\n            {\n                Assert.Fail(\"Test timed out waiting for cancellation to be recorded.\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Tests error handling in async enumerable streams when an exception is thrown during enumeration.\n    /// Verifies that exceptions are properly propagated to the client and resources are cleaned up.\n    /// The errorIndex parameter determines when the error occurs, testing both immediate and delayed errors.\n    /// The waitAfterYield parameter tests error handling with and without async delays after yielding values.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    [InlineData(0, false)]\n    [InlineData(0, true)]\n    [InlineData(1, false)]\n    [InlineData(1, true)]\n    [InlineData(9, false)]\n    [InlineData(9, true)]\n    [InlineData(10, false)]\n    [InlineData(10, true)]\n    [InlineData(11, false)]\n    [InlineData(11, true)]\n    public async Task ObservableGrain_AsyncEnumerable_Throws(int errorIndex, bool waitAfterYield)\n    {\n        const string ErrorMessage = \"This is my error!\";\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var values = new List<int>();\n        try\n        {\n            await foreach (var entry in grain.GetValuesWithError(errorIndex, waitAfterYield, ErrorMessage).WithBatchSize(10))\n            {\n                values.Add(entry);\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n        }\n        catch (InvalidOperationException iox)\n        {\n            Assert.Equal(ErrorMessage, iox.Message);\n        }\n\n        Assert.Equal(errorIndex, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests cancellation handling in async enumerable streams when the grain cancels the enumeration.\n    /// Verifies that OperationCanceledException is properly propagated and resources are cleaned up.\n    /// This tests Orleans' ability to handle cooperative cancellation in distributed streaming scenarios.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    [InlineData(0, false)]\n    [InlineData(0, true)]\n    [InlineData(1, false)]\n    [InlineData(1, true)]\n    [InlineData(9, false)]\n    [InlineData(9, true)]\n    [InlineData(10, false)]\n    [InlineData(10, true)]\n    [InlineData(11, false)]\n    [InlineData(11, true)]\n    public async Task ObservableGrain_AsyncEnumerable_Cancellation(int errorIndex, bool waitAfterYield)\n    {\n        // This special error message is interpreted to indicate that cancellation\n        // should occur when the index is reached.\n        const string ErrorMessage = \"cancel\";\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var values = new List<int>();\n        try\n        {\n            await foreach (var entry in grain.GetValuesWithError(errorIndex, waitAfterYield, ErrorMessage).WithBatchSize(10))\n            {\n                values.Add(entry);\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n        }\n        catch (OperationCanceledException oce)\n        {\n            var expectedMessage = new OperationCanceledException().Message;\n            Assert.Equal(expectedMessage, oce.Message);\n        }\n\n        Assert.Equal(errorIndex, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests client-side cancellation of async enumerable streams using CancellationToken.\n    /// Verifies that cancellation requests from the client are properly handled, including:\n    /// - Preemptive cancellation (before enumeration starts)\n    /// - Mid-stream cancellation (during enumeration)\n    /// - Proper cleanup and disposal of server-side resources\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    [InlineData(0, false)]\n    [InlineData(0, true)]\n    [InlineData(1, false)]\n    [InlineData(1, true)]\n    [InlineData(9, false)]\n    [InlineData(9, true)]\n    [InlineData(10, false)]\n    [InlineData(10, true)]\n    [InlineData(11, false)]\n    [InlineData(11, true)]\n    public async Task ObservableGrain_AsyncEnumerable_CancellationToken(int errorIndex, bool waitAfterYield)\n    {\n        const string ErrorMessage = \"Throwing!\";\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var values = new List<int>();\n        try\n        {\n            using var cts = new CancellationTokenSource();\n            if (errorIndex == 0)\n            {\n                cts.Cancel();\n            }\n\n            await foreach (var entry in grain.GetValuesWithError(int.MaxValue, waitAfterYield, ErrorMessage, cts.Token).WithBatchSize(10))\n            {\n                values.Add(entry);\n                if (values.Count == errorIndex)\n                {\n                    cts.Cancel();\n                }\n\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n        }\n        catch (OperationCanceledException oce)\n        {\n            var expectedMessage = new OperationCanceledException().Message;\n            Assert.Equal(expectedMessage, oce.Message);\n        }\n\n        Assert.Equal(errorIndex, values.Count);\n\n        if (errorIndex == 0)\n        {\n            // Check that the enumerator was not disposed since it was cancelled preemptively and therefore no call should have been made.\n            var grainCalls = await grain.GetIncomingCalls();\n            Assert.DoesNotContain(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration)));\n            Assert.DoesNotContain(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.DisposeAsync)));\n        }\n        if (errorIndex > 0)\n        {\n            // Check that the enumerator is disposed, but only if it was not cancelled preemptively.\n            var grainCalls = await grain.GetIncomingCalls();\n            Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration)));\n            Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.DisposeAsync)));\n        }\n    }\n\n    /// <summary>\n    /// Tests client-side cancellation using the WithCancellation extension method.\n    /// Similar to CancellationToken test but uses the extension method approach for cancellation.\n    /// Verifies that the WithCancellation extension properly integrates with Orleans' async enumerable support.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    [InlineData(0, false)]\n    [InlineData(0, true)]\n    [InlineData(1, false)]\n    [InlineData(1, true)]\n    [InlineData(9, false)]\n    [InlineData(9, true)]\n    [InlineData(10, false)]\n    [InlineData(10, true)]\n    [InlineData(11, false)]\n    [InlineData(11, true)]\n    public async Task ObservableGrain_AsyncEnumerable_CancellationToken_WithCancellationExtension(int errorIndex, bool waitAfterYield)\n    {\n        const string ErrorMessage = \"Throwing!\";\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var values = new List<int>();\n        try\n        {\n            using var cts = new CancellationTokenSource();\n            if (errorIndex == 0)\n            {\n                cts.Cancel();\n            }\n\n            await foreach (var entry in grain.GetValuesWithError(int.MaxValue, waitAfterYield, ErrorMessage).WithBatchSize(10).WithCancellation(cts.Token))\n            {\n                values.Add(entry);\n                if (values.Count == errorIndex)\n                {\n                    cts.Cancel();\n                }\n\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n        }\n        catch (OperationCanceledException oce)\n        {\n            var expectedMessage = new OperationCanceledException().Message;\n            Assert.Equal(expectedMessage, oce.Message);\n        }\n\n        Assert.Equal(errorIndex, values.Count);\n\n        if (errorIndex == 0)\n        {\n            // Check that the enumerator was not disposed since it was cancelled preemptively and therefore no call should have been made.\n            var grainCalls = await grain.GetIncomingCalls();\n            Assert.DoesNotContain(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration)));\n            Assert.DoesNotContain(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.DisposeAsync)));\n        }\n        if (errorIndex > 0)\n        {\n            // Check that the enumerator is disposed, but only if it was not cancelled preemptively.\n            var grainCalls = await grain.GetIncomingCalls();\n            Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration)));\n            Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.DisposeAsync)));\n        }\n    }\n\n    /// <summary>\n    /// Tests batching optimization for async enumerable streams.\n    /// Verifies that Orleans automatically batches multiple values to reduce network round-trips.\n    /// This optimization is crucial for performance when streaming many small values.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_Batch()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        foreach (var value in Enumerable.Range(0, 50))\n        {\n            await grain.OnNext(value.ToString());\n        }\n\n        await grain.Complete();\n\n        var values = new List<string>();\n        await foreach (var entry in grain.GetValues())\n        {\n            values.Add(entry);\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(50, values.Count);\n\n        var grainCalls = await grain.GetIncomingCalls();\n        var moveNextCallCount = grainCalls.Count(element =>\n            element.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension))\n            && (element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.MoveNext)) || element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration))));\n        Assert.True(moveNextCallCount < values.Count);\n\n        // Check that the enumerator is disposed\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests custom batch size configuration for async enumerable streams.\n    /// Verifies that the WithBatchSize extension method correctly controls the number of items per batch.\n    /// This allows clients to tune the trade-off between latency and throughput.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_SplitBatch()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        foreach (var value in Enumerable.Range(0, 50))\n        {\n            await grain.OnNext(value.ToString());\n        }\n\n        await grain.Complete();\n\n        var values = new List<string>();\n        await foreach (var entry in grain.GetValues().WithBatchSize(25))\n        {\n            values.Add(entry);\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(50, values.Count);\n\n        var grainCalls = await grain.GetIncomingCalls();\n        var moveNextCallCount = grainCalls.Count(element =>\n            element.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension))\n            && (element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.MoveNext)) || element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration))));\n        Assert.True(moveNextCallCount < values.Count);\n\n        // Check that the enumerator is disposed\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests disabling batching by setting batch size to 1.\n    /// Verifies that each value results in a separate network call when batching is disabled.\n    /// This mode provides lowest latency but highest overhead for streaming scenarios.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_NoBatching()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        foreach (var value in Enumerable.Range(0, 50))\n        {\n            await grain.OnNext(value.ToString());\n        }\n\n        await grain.Complete();\n\n        var values = new List<string>();\n        await foreach (var entry in grain.GetValues().WithBatchSize(1))\n        {\n            values.Add(entry);\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(50, values.Count);\n\n        var grainCalls = await grain.GetIncomingCalls();\n        var moveNextCallCount = grainCalls.Count(element =>\n            element.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension))\n            && (element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.MoveNext)) || element.MethodName.Contains(nameof(IAsyncEnumerableGrainExtension.StartEnumeration))));\n\n        // One call for every value and one final call to complete the enumeration\n        Assert.Equal(values.Count + 1, moveNextCallCount);\n\n        // Check that the enumerator is disposed\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests cancellation during active enumeration.\n    /// Verifies that cancelling mid-stream properly stops enumeration and cleans up resources.\n    /// This simulates real-world scenarios where clients need to stop consuming data early.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_WithCancellation()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 5))\n            {\n                await Task.Delay(200);\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Complete();\n        });\n\n        var values = new List<string>();\n        using var cts = new CancellationTokenSource();\n        try\n        {\n            await foreach (var entry in grain.GetValues().WithCancellation(cts.Token))\n            {\n                values.Add(entry);\n                if (values.Count == 3)\n                {\n                    cts.Cancel();\n                }\n\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n\n            Assert.Fail(\"Expected an exception to be thrown\");\n        }\n        catch (OperationCanceledException)\n        {\n            // Expected\n        }\n\n        Assert.Equal(3, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests async enumerable behavior with a slow-producing grain.\n    /// Verifies that the client can stop consuming before all values are produced.\n    /// This tests Orleans' ability to handle backpressure and early termination in streaming scenarios.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_SlowProducer()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 5))\n            {\n                await Task.Delay(2000);\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Complete();\n        });\n\n        var values = new List<string>();\n        await foreach (var entry in grain.GetValues())\n        {\n            values.Add(entry);\n            if (values.Count == 2)\n            {\n                break;\n            }\n\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(2, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests async enumerable behavior with a slow-consuming client.\n    /// Verifies that the enumerator is not prematurely cleaned up when the client consumes slowly.\n    /// Uses diagnostic listeners to monitor the cleanup timer behavior.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_SlowConsumer()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var cleanupInterval = TimeSpan.FromMilliseconds(1_000);\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n        using var listener = new AsyncEnumerableGrainExtensionListener(grain.GetGrainId(), cleanupInterval);\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 3))\n            {\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Complete();\n        });\n\n        var values = new List<string>();\n        var cleanupCountBeforeMoveNext = listener.CleanupCount;\n        await foreach (var entry in grain.GetValues().WithBatchSize(1))\n        {\n            values.Add(entry);\n\n            // Wait for one cleanup cycle before reading the next value.\n            // Track the count captured before the corresponding MoveNext call to avoid waiting\n            // for a second cycle if cleanup happens right after MoveNext completes.\n            while (listener.CleanupCount == cleanupCountBeforeMoveNext)\n            {\n                await Task.Delay(cleanupInterval / 10, cts.Token);\n            }\n\n            cleanupCountBeforeMoveNext = listener.CleanupCount;\n            Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n        }\n\n        Assert.Equal(3, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests enumerator eviction when a client consumes too slowly.\n    /// Verifies that Orleans properly cleans up abandoned enumerators after a timeout period.\n    /// This prevents resource leaks when clients fail to complete enumeration.\n    /// The test ensures proper error handling when trying to continue after eviction.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_SlowConsumer_Evicted()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var cleanupInterval = TimeSpan.FromMilliseconds(1_000);\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n        using var listener = new AsyncEnumerableGrainExtensionListener(grain.GetGrainId(), cleanupInterval);\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 5))\n            {\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Complete();\n        });\n\n        var values = new List<string>();\n        try\n        {\n            await foreach (var entry in grain.GetValues().WithBatchSize(1))\n            {\n                values.Add(entry);\n\n                // After the 3rd iteration, sleep for longer than the cleanup duration\n                // and wait for the enumerator to be cleaned up.\n                if (values.Count >= 3)\n                {\n                    var initialCleanupCount = listener.CleanupCount;\n                    while (listener.CleanupCount < initialCleanupCount + 2)\n                    {\n                        await Task.Delay(cleanupInterval, cts.Token);\n                    }\n                }\n\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n\n            Assert.Fail(\"Expected an exception to be thrown\");\n        }\n        catch (EnumerationAbortedException ex)\n        {\n            Assert.Contains(\"the remote target does not have a record of this enumerator\", ex.Message);\n        }\n\n        Assert.Equal(3, values.Count);\n\n        // Check that the enumerator is disposed\n        var grainCalls = await grain.GetIncomingCalls();\n        Assert.Contains(grainCalls, c => c.InterfaceName.Contains(nameof(IAsyncEnumerableGrainExtension)) && c.MethodName.Contains(nameof(IAsyncDisposable.DisposeAsync)));\n    }\n\n    /// <summary>\n    /// Tests async enumerable behavior when the grain is deactivated during enumeration.\n    /// Verifies that grain deactivation properly terminates active enumerations with an appropriate error.\n    /// This ensures clean shutdown and prevents hanging clients when grains are deactivated.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Observable\")]\n    public async Task ObservableGrain_AsyncEnumerable_Deactivate()\n    {\n        var grain = GrainFactory.GetGrain<IObservableGrain>(Guid.NewGuid());\n\n        var producer = Task.Run(async () =>\n        {\n            foreach (var value in Enumerable.Range(0, 2))\n            {\n                await Task.Delay(200);\n                await grain.OnNext(value.ToString());\n            }\n\n            await grain.Deactivate();\n        });\n\n        var values = new List<string>();\n        await Assert.ThrowsAsync<EnumerationAbortedException>(async () =>\n        {\n            await foreach (var entry in grain.GetValues())\n            {\n                values.Add(entry);\n                Logger.LogInformation(\"ObservableGrain_AsyncEnumerable: {Entry}\", entry);\n            }\n        });\n\n        Assert.Equal(2, values.Count);\n    }\n\n    /// <summary>\n    /// Diagnostic listener for monitoring AsyncEnumerableGrainExtension behavior during tests.\n    /// This helper class allows tests to observe internal cleanup operations and verify\n    /// that enumerators are properly managed according to their lifecycle requirements.\n    /// </summary>\n    private sealed class AsyncEnumerableGrainExtensionListener : IObserver<KeyValuePair<string, object?>>, IObserver<DiagnosticListener>, IDisposable\n    {\n        private readonly IDisposable _allListenersSubscription;\n        private readonly GrainId _targetGrainId;\n        private readonly TimeSpan _enumeratorCleanupInterval;\n        private IDisposable? _instanceSubscription;\n\n        public AsyncEnumerableGrainExtensionListener(GrainId targetGrainId, TimeSpan enumeratorCleanupInterval)\n        {\n            _allListenersSubscription = DiagnosticListener.AllListeners.Subscribe(this);\n            _targetGrainId = targetGrainId;\n            _enumeratorCleanupInterval = enumeratorCleanupInterval;\n        }\n\n        public int CleanupCount { get; private set; }\n\n        void IObserver<KeyValuePair<string, object?>>.OnCompleted()\n        {\n            _instanceSubscription?.Dispose();\n        }\n\n        void IObserver<KeyValuePair<string, object?>>.OnError(Exception error)\n        {\n        }\n\n        void IObserver<KeyValuePair<string, object?>>.OnNext(KeyValuePair<string, object?> value)\n        {\n            var extension = (AsyncEnumerableGrainExtension)value.Value!;\n            if (extension.GrainContext.GrainId != _targetGrainId)\n            {\n                return;\n            }\n\n            if (value.Key == \"OnAsyncEnumeratorGrainExtensionCreated\")\n            {\n                extension.Timer.Change(_enumeratorCleanupInterval, _enumeratorCleanupInterval);\n            }\n\n            if (value.Key == \"OnEnumeratorCleanupCompleted\")\n            {\n                ++CleanupCount;\n            }\n        }\n\n        void IObserver<DiagnosticListener>.OnCompleted() { }\n        void IObserver<DiagnosticListener>.OnError(Exception error) { }\n        void IObserver<DiagnosticListener>.OnNext(DiagnosticListener value)\n        {\n            if (value.Name == \"Orleans.Runtime.AsyncEnumerableGrainExtension\")\n            {\n                _instanceSubscription = value.Subscribe(this);\n            }\n        }\n\n        public void Dispose()\n        {\n            _allListenersSubscription.Dispose();\n            _instanceSubscription?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/BasicActivationTests.cs",
    "content": "using System.Globalization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests fundamental grain activation and lifecycle behaviors in Orleans.\n    /// These tests verify core functionality including:\n    /// - Grain activation and identity management\n    /// - State persistence across activations\n    /// - Error handling during activation\n    /// - Support for different key types (long, Guid, ulong)\n    /// - Request context propagation\n    /// Orleans uses an activation model where grains are activated on-demand and can be deactivated when idle.\n    /// </summary>\n    public class BasicActivationTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public BasicActivationTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        private TimeSpan GetResponseTimeout() => this.Client.ServiceProvider.GetRequiredService<OutsideRuntimeClient>().GetResponseTimeout();\n        private void SetResponseTimeout(TimeSpan value) => this.Client.ServiceProvider.GetRequiredService<OutsideRuntimeClient>().SetResponseTimeout(value);\n\n        /// <summary>\n        /// Tests basic grain activation with long keys and state updates.\n        /// Verifies that:\n        /// - Grains are properly activated when accessed\n        /// - State changes persist within the same activation\n        /// - Multiple grain references to the same identity share the same activation\n        /// This demonstrates Orleans' virtual actor model where grains exist logically even when not activated.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_ActivateAndUpdate()\n        {\n            long g1Key = GetRandomGrainId();\n            long g2Key = GetRandomGrainId();\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(g1Key);\n            ITestGrain g2 = this.GrainFactory.GetGrain<ITestGrain>(g2Key);\n            Assert.Equal(g1Key, g1.GetPrimaryKeyLong());\n            Assert.Equal(g1Key, await g1.GetKey());\n            Assert.Equal(g1Key.ToString(), await g1.GetLabel());\n            Assert.Equal(g2Key, await g2.GetKey());\n            Assert.Equal(g2Key.ToString(), await g2.GetLabel());\n\n            await g1.SetLabel(\"one\");\n            Assert.Equal(\"one\", await g1.GetLabel());\n            Assert.Equal(g2Key.ToString(), await g2.GetLabel());\n\n            ITestGrain g1a = this.GrainFactory.GetGrain<ITestGrain>(g1Key);\n            Assert.Equal(\"one\", await g1a.GetLabel());\n        }\n\n        /// <summary>\n        /// Tests grain activation using Guid keys instead of long keys.\n        /// Verifies that the grain system properly handles Guid-based grain identities.\n        /// GUIDs are commonly used for grain keys when natural numeric identifiers don't exist.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_Guid_ActivateAndUpdate()\n        {\n            Guid guid1 = Guid.NewGuid();\n            Guid guid2 = Guid.NewGuid();\n\n            IGuidTestGrain g1 = this.GrainFactory.GetGrain<IGuidTestGrain>(guid1);\n            IGuidTestGrain g2 = this.GrainFactory.GetGrain<IGuidTestGrain>(guid2);\n            Assert.Equal(guid1, g1.GetPrimaryKey());\n            Assert.Equal(guid1, await g1.GetKey());\n            Assert.Equal(guid1.ToString(), await g1.GetLabel());\n            Assert.Equal(guid2, await g2.GetKey());\n            Assert.Equal(guid2.ToString(), await g2.GetLabel());\n\n            await g1.SetLabel(\"one\");\n            Assert.Equal(\"one\", await g1.GetLabel());\n            Assert.Equal(guid2.ToString(), await g2.GetLabel());\n\n            IGuidTestGrain g1a = this.GrainFactory.GetGrain<IGuidTestGrain>(guid1);\n            Assert.Equal(\"one\", await g1a.GetLabel());\n        }\n\n        /// <summary>\n        /// Tests error handling when grain activation fails due to invalid parameters.\n        /// Verifies that grains can enforce constraints during activation (e.g., rejecting certain key values).\n        /// This demonstrates Orleans' ability to fail fast when grain invariants are violated.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"ErrorHandling\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_Fail()\n        {\n            bool failed;\n            long key = 0;\n            try\n            {\n                // Key values of -2 are not allowed in this case\n                ITestGrain fail = this.GrainFactory.GetGrain<ITestGrain>(-2);\n                key = await fail.GetKey();\n                failed = false;\n            }\n            catch (ArgumentException)\n            {\n                failed = true;\n            }\n\n            if (!failed) Assert.Fail(\"Should have failed, but instead returned \" + key);\n        }\n\n        /// <summary>\n        /// Tests error handling when multiple concurrent requests fail during grain activation.\n        /// Verifies that Orleans properly handles burst failures without resource leaks or deadlocks.\n        /// All concurrent requests should receive the same activation failure.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"ErrorHandling\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_BurstFail()\n        {\n            bool failed;\n            long key = 0;\n            var tasks = new List<Task>();\n            try\n            {\n                // Key values of -2 are not allowed in this case\n                var fail = this.GrainFactory.GetGrain<ITestGrainLongOnActivateAsync>(-2);\n                for (int i = 0; i < 10000; i++)\n                {\n                    tasks.Add(fail.GetKey());\n                }\n                failed = false;\n                await Task.WhenAll(tasks);\n            }\n            catch (Exception)\n            {\n                failed = true;\n                foreach (var t in tasks)\n                {\n                    Assert.Equal(typeof(ArgumentException), t.Exception.InnerException.GetType());\n                }\n            }\n\n            if (!failed) Assert.Fail(\"Should have failed, but instead returned \" + key);\n        }\n\n        /// <summary>\n        /// Tests grain activation with ulong.MaxValue cast to long (results in -1).\n        /// Verifies proper handling of edge cases in numeric grain keys.\n        /// This ensures the grain system correctly handles the full range of long values.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_ULong_MaxValue()\n        {\n            ulong key1AsUlong = ulong.MaxValue; // == -1L\n            long key1 = (long)key1AsUlong;\n\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(key1);\n            Assert.Equal(key1, g1.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, await g1.GetKey());\n            Assert.Equal(key1.ToString(CultureInfo.InvariantCulture), await g1.GetLabel());\n\n            await g1.SetLabel(\"MaxValue\");\n            Assert.Equal(\"MaxValue\", await g1.GetLabel());\n\n            ITestGrain g1a = this.GrainFactory.GetGrain<ITestGrain>((long)key1AsUlong);\n            Assert.Equal(\"MaxValue\", await g1a.GetLabel());\n            Assert.Equal(key1, g1a.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, await g1a.GetKey());\n        }\n\n        /// <summary>\n        /// Tests grain activation with ulong.MinValue (0) cast to long.\n        /// Verifies proper handling of zero as a grain key.\n        /// Zero is a valid grain key and should work like any other numeric identifier.\n        /// </summary>\n        [Fact, TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_ULong_MinValue()\n        {\n            ulong key1AsUlong = ulong.MinValue; // == zero\n            long key1 = (long)key1AsUlong;\n\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(key1);\n            Assert.Equal(key1, g1.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, await g1.GetKey());\n            Assert.Equal(key1.ToString(CultureInfo.InvariantCulture), await g1.GetLabel());\n\n            await g1.SetLabel(\"MinValue\");\n            Assert.Equal(\"MinValue\", await g1.GetLabel());\n\n            ITestGrain g1a = this.GrainFactory.GetGrain<ITestGrain>((long)key1AsUlong);\n            Assert.Equal(\"MinValue\", await g1a.GetLabel());\n            Assert.Equal(key1, g1a.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, await g1a.GetKey());\n        }\n\n        /// <summary>\n        /// Tests grain activation with int.MaxValue as the grain key.\n        /// Verifies proper handling of large positive grain keys.\n        /// This ensures no overflow or precision issues with large numeric identifiers.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_Long_MaxValue()\n        {\n            long key1 = int.MaxValue;\n            ulong key1AsUlong = (ulong)key1;\n\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(key1);\n            Assert.Equal(key1, g1.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, await g1.GetKey());\n            Assert.Equal(key1.ToString(CultureInfo.InvariantCulture), await g1.GetLabel());\n\n            await g1.SetLabel(\"MaxValue\");\n            Assert.Equal(\"MaxValue\", await g1.GetLabel());\n\n            ITestGrain g1a = this.GrainFactory.GetGrain<ITestGrain>((long)key1AsUlong);\n            Assert.Equal(\"MaxValue\", await g1a.GetLabel());\n            Assert.Equal(key1, g1a.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, await g1a.GetKey());\n        }\n\n        /// <summary>\n        /// Tests grain activation with long.MinValue as the grain key.\n        /// Verifies proper handling of the most negative possible grain key.\n        /// This ensures the grain system handles the full range of signed long values.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_Long_MinValue()\n        {\n            long key1 = long.MinValue;\n            ulong key1AsUlong = (ulong)key1;\n\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(key1);\n            Assert.Equal((long)key1AsUlong, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, g1.GetPrimaryKeyLong());\n            Assert.Equal(key1, await g1.GetKey());\n            Assert.Equal(key1.ToString(CultureInfo.InvariantCulture), await g1.GetLabel());\n\n            await g1.SetLabel(\"MinValue\");\n            Assert.Equal(\"MinValue\", await g1.GetLabel());\n\n            ITestGrain g1a = this.GrainFactory.GetGrain<ITestGrain>((long)key1AsUlong);\n            Assert.Equal(\"MinValue\", await g1a.GetLabel());\n            Assert.Equal(key1, g1a.GetPrimaryKeyLong());\n            Assert.Equal((long)key1AsUlong, await g1a.GetKey());\n        }\n\n        /// <summary>\n        /// Tests grain activation when grains implement multiple interfaces.\n        /// Verifies that grains can return references to other grains through various collection types.\n        /// This demonstrates Orleans' support for complex grain interface hierarchies.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task BasicActivation_MultipleGrainInterfaces()\n        {\n            ITestGrain simple = this.GrainFactory.GetGrain<ITestGrain>(GetRandomGrainId());\n\n            await simple.GetMultipleGrainInterfaces_List();\n            this.Logger.LogInformation(\"GetMultipleGrainInterfaces_List() worked\");\n\n            await simple.GetMultipleGrainInterfaces_Array();\n\n            this.Logger.LogInformation(\"GetMultipleGrainInterfaces_Array() worked\");\n        }\n\n        /// <summary>\n        /// Tests recovery after message timeout in reentrant grains.\n        /// Verifies that:\n        /// - Grains can recover from expired messages in their queues\n        /// - Subsequent valid requests succeed after timeouts\n        /// - The system properly cleans up expired messages\n        /// This tests Orleans' resilience to transient failures and timeout conditions.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"ActivateDeactivate\"),\n         TestCategory(\"Reentrancy\")]\n        public async Task BasicActivation_Reentrant_RecoveryAfterExpiredMessage()\n        {\n            List<Task> promises = new List<Task>();\n            TimeSpan prevTimeout = this.GetResponseTimeout();\n            try\n            {\n                // set short response time and ask to do long operation, to trigger expired msgs in the silo queues.\n                TimeSpan shortTimeout = TimeSpan.FromMilliseconds(1000);\n                this.SetResponseTimeout(shortTimeout);\n\n                ITestGrain grain = this.GrainFactory.GetGrain<ITestGrain>(GetRandomGrainId());\n                int num = 10;\n                for (long i = 0; i < num; i++)\n                {\n                    Task task = grain.DoLongAction(\n                        TimeSpan.FromMilliseconds(shortTimeout.TotalMilliseconds * 3),\n                        \"A_\" + i);\n                    promises.Add(task);\n                }\n                try\n                {\n                    await Task.WhenAll(promises);\n                }\n                catch (Exception)\n                {\n                    this.Logger.LogInformation(\"Done with stress iteration.\");\n                }\n\n                // wait a bit to make sure expired msgs in the silo is trigered.\n                Thread.Sleep(TimeSpan.FromSeconds(10));\n\n                // set the regular response time back, expect msgs ot succeed.\n                this.SetResponseTimeout(prevTimeout);\n                \n                this.Logger.LogInformation(\"About to send a next legit request that should succeed.\");\n                await grain.DoLongAction(TimeSpan.FromMilliseconds(1), \"B_\" + 0);\n                this.Logger.LogInformation(\"The request succeeded.\");\n            }\n            finally\n            {\n                // set the regular response time back, expect msgs ot succeed.\n                this.SetResponseTimeout(prevTimeout);\n            }\n        }\n\n        /// <summary>\n        /// Tests request context propagation from client to grain.\n        /// Verifies that Orleans properly flows ambient context (like trace IDs or user context)\n        /// from the client through to grain method executions.\n        /// Request context is essential for distributed tracing and multi-tenancy scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"RequestContext\"), TestCategory(\"GetGrain\")]\n        public async Task BasicActivation_TestRequestContext()\n        {\n            ITestGrain g1 = this.GrainFactory.GetGrain<ITestGrain>(GetRandomGrainId());\n            Task<Tuple<string, string>> promise1 = g1.TestRequestContext();\n            Tuple<string, string> requestContext = await promise1;\n            this.Logger.LogInformation(\"Request Context is: {RequestContext}\", requestContext);\n            Assert.NotNull(requestContext.Item2);\n            Assert.NotNull(requestContext.Item1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ClientAddressableTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests client-addressable objects in Orleans, which allow grains to call back to client-side objects.\n    /// This feature enables bidirectional communication where grains can invoke methods on objects hosted in the client.\n    /// Key scenarios include:\n    /// - Observer patterns where grains notify clients of events\n    /// - Client-side callbacks for long-running operations\n    /// - Polling patterns where grains pull data from clients\n    /// Client-addressable objects must be registered with the runtime and have a limited lifetime.\n    /// </summary>\n    public class ClientAddressableTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private object anchor;\n        private readonly IRuntimeClient runtimeClient;\n\n        /// <summary>\n        /// Test implementation of a client-side object that can be called by grains.\n        /// Demonstrates various patterns including:\n        /// - Successful method execution (OnHappyPath)\n        /// - Error propagation (OnSadPath)\n        /// - Thread-safe state management (OnSerialStress)\n        /// - Concurrent access handling (OnParallelStress)\n        /// </summary>\n        private class MyPseudoGrain : IClientAddressableTestClientObject\n        {\n            private int counter = 0;\n            private readonly List<int> numbers = new List<int>();\n\n            public Task<string> OnHappyPath(string message)\n            {\n                if (string.IsNullOrEmpty(message))\n                    throw new ArgumentException(\"target\");\n                else\n                    return Task.FromResult(message);\n            }\n\n            public Task OnSadPath(string message)\n            {\n                if (string.IsNullOrEmpty(message))\n                    throw new ArgumentException(\"target\");\n                else\n                    throw new ApplicationException(message);\n            }\n\n            public Task<int> OnSerialStress(int n)\n            {\n                Assert.Equal(this.counter, n);\n                ++this.counter;\n                return Task.FromResult(10000 + n);\n            }\n\n            public Task<int> OnParallelStress(int n)\n            {\n                this.numbers.Add(n);\n                return Task.FromResult(10000 + n);\n            }\n\n            public void VerifyNumbers(int iterationCount)\n            {\n                Assert.Equal(iterationCount, this.numbers.Count);\n                this.numbers.Sort();\n                for (var i = 0; i < this.numbers.Count; ++i)\n                    Assert.Equal(i, this.numbers[i]);\n            }\n        }\n\n        /// <summary>\n        /// Test implementation of a client-side producer that grains can poll for data.\n        /// Demonstrates the pull model where grains actively request data from clients.\n        /// </summary>\n        private class MyProducer : IClientAddressableTestProducer\n        {\n            private int counter = 0;\n\n            public Task<int> Poll()\n            {\n                ++this.counter;\n                return Task.FromResult(this.counter);\n            }\n        }\n\n        public ClientAddressableTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n            this.runtimeClient = this.HostedCluster.ServiceProvider.GetRequiredService<IRuntimeClient>();\n        }\n\n        /// <summary>\n        /// Tests successful grain-to-client method invocation.\n        /// Verifies that:\n        /// - Client objects can be registered and referenced by grains\n        /// - Grains can successfully invoke methods on client objects\n        /// - Return values are properly marshaled back to the grain\n        /// - Object references can be properly cleaned up\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ClientAddressable\")]\n        public async Task TestClientAddressableHappyPath()\n        {\n            var myOb = new MyPseudoGrain();\n            this.anchor = myOb;\n            var myRef = ((IInternalGrainFactory)this.GrainFactory).CreateObjectReference<IClientAddressableTestClientObject>(myOb);\n            var proxy = this.GrainFactory.GetGrain<IClientAddressableTestGrain>(GetRandomGrainId());\n            const string expected = \"o hai!\";\n            await proxy.SetTarget(myRef);\n            var actual = await proxy.HappyPath(expected);\n            Assert.Equal(expected, actual);\n\n            this.runtimeClient.DeleteObjectReference(myRef);\n        }\n\n        /// <summary>\n        /// Tests error propagation from client objects back to grains.\n        /// Verifies that exceptions thrown in client-side methods are properly\n        /// serialized and re-thrown in the calling grain, maintaining the error message.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ClientAddressable\")]\n        public async Task TestClientAddressableSadPath()\n        {\n            const string message = \"o hai!\";\n\n            var myOb = new MyPseudoGrain();\n            this.anchor = myOb;\n            var myRef = ((IInternalGrainFactory)this.GrainFactory).CreateObjectReference<IClientAddressableTestClientObject>(myOb);\n            var proxy = this.GrainFactory.GetGrain<IClientAddressableTestGrain>(GetRandomGrainId());\n            await proxy.SetTarget(myRef);\n\n            await Assert.ThrowsAsync<ApplicationException>(() =>\n                proxy.SadPath(message)\n            );\n\n            this.runtimeClient.DeleteObjectReference(myRef);\n        }\n\n        /// <summary>\n        /// Tests the pull pattern where grains request data from client objects.\n        /// Verifies that:\n        /// - Client producer objects can be shared between grains via a rendezvous grain\n        /// - Consumer grains can pull data from client-side producers\n        /// - State is maintained correctly in the client object across calls\n        /// This pattern is useful for scenarios where clients generate data that grains consume.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ClientAddressable\")]\n        public async Task GrainShouldSuccessfullyPullFromClientObject()\n        {\n            var myOb = new MyProducer();\n            this.anchor = myOb;\n            var myRef = ((IInternalGrainFactory)this.GrainFactory).CreateObjectReference<IClientAddressableTestProducer>(myOb);\n            var rendez = this.GrainFactory.GetGrain<IClientAddressableTestRendezvousGrain>(0);\n            var consumer = this.GrainFactory.GetGrain<IClientAddressableTestConsumer>(0);\n\n            await rendez.SetProducer(myRef);\n            await consumer.Setup();\n            var n = await consumer.PollProducer();\n            Assert.Equal(1, n);\n\n            this.runtimeClient.DeleteObjectReference(myRef);\n        }\n\n        /// <summary>\n        /// Stress tests serial execution of many client object invocations.\n        /// Verifies that:\n        /// - Client objects maintain correct state across many sequential calls\n        /// - Orleans properly serializes access to client objects\n        /// - No race conditions occur in the serial execution model\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ClientAddressable\")]\n        public async Task MicroClientAddressableSerialStressTest()\n        {\n            const int iterationCount = 1000;\n\n            var myOb = new MyPseudoGrain();\n            this.anchor = myOb;\n            var myRef = ((IInternalGrainFactory)this.GrainFactory).CreateObjectReference<IClientAddressableTestClientObject>(myOb);\n            var proxy = this.GrainFactory.GetGrain<IClientAddressableTestGrain>(GetRandomGrainId());\n            await proxy.SetTarget(myRef);\n            await proxy.MicroSerialStressTest(iterationCount);\n\n            this.runtimeClient.DeleteObjectReference(myRef);\n        }\n\n        /// <summary>\n        /// Stress tests parallel execution of many client object invocations.\n        /// Verifies that:\n        /// - Client objects can handle concurrent access from grains\n        /// - All parallel invocations are processed without data loss\n        /// - Thread-safety is maintained in the client object\n        /// This tests Orleans' ability to handle high-throughput client callbacks.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ClientAddressable\")]\n        public async Task MicroClientAddressableParallelStressTest()\n        {\n            const int iterationCount = 1000;\n\n            var myOb = new MyPseudoGrain();\n            this.anchor = myOb;\n            var myRef = ((IInternalGrainFactory)this.GrainFactory).CreateObjectReference<IClientAddressableTestClientObject>(myOb);\n            var proxy = this.GrainFactory.GetGrain<IClientAddressableTestGrain>(GetRandomGrainId());\n            await proxy.SetTarget(myRef);\n            await proxy.MicroParallelStressTest(iterationCount);\n\n            this.runtimeClient.DeleteObjectReference(myRef);\n\n            myOb.VerifyNumbers(iterationCount);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/CodeGenTests/CodeGeneratorTests_KnownAssemblyAttribute.cs",
    "content": "using Microsoft.FSharp.Core;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Unit tests for grains implementing generic interfaces\n    /// </summary>\n    public class KnownAssemblyAttributeTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public KnownAssemblyAttributeTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        private async Task SiloSerializerExists(Type t)\n        {\n            var id = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<ISerializerPresenceTest>(id);\n            var serializerExists = await grain.SerializerExistsForType(t);\n            Assert.True(serializerExists);\n        }\n\n        private void ClientSerializerExists(Type t)\n        {\n            Assert.True(this.HostedCluster.GetSerializer().CanSerialize(t));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public async Task Silo_Serializer_Exists_for_Type_In_Grain_Assembly()\n        {\n            await SiloSerializerExists(typeof(UnitTests.Grains.SimpleGrainState));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public void Client_Serializer_Exists_for_Type_In_Grain_Assembly()\n        {\n            ClientSerializerExists(typeof(UnitTests.Grains.SimpleGrainState));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public async Task Silo_Serializer_Exists_for_Type_In_Known_Assembly()\n        {\n            await SiloSerializerExists(typeof(FSharpOption<int>));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public void Client_Serializer_Exists_for_Type_In_Known_Assembly()\n        {\n            ClientSerializerExists(typeof(FSharpOption<int>));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public async Task Silo_Serializer_Exists_for_Type_In_Grain_Assembly_containing_KnownAssemblyAttribute()\n        {\n            await SiloSerializerExists(typeof(UnitTests.FSharpTypes.SingleCaseDU));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"CodeGen\"), TestCategory(\"Serialization\")]\n        public void Client_Serializer_Exists_for_Type_In_Grain_Assembly_containing_KnownAssemblyAttribute()\n        {\n            ClientSerializerExists(typeof(UnitTests.FSharpTypes.SingleCaseDU));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/CodeGenTests/GeneratorGrainTest.cs",
    "content": "using System.Text;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace Tester.CodeGenTests\n{\n    /// <summary>\n    /// Summary description for GrainClientTest\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"CodeGen\")]\n    public class GeneratorGrainTest : HostedTestClusterEnsureDefaultStarted\n    {\n        public GeneratorGrainTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        [Fact]\n        public async Task GeneratorGrainControlFlow()\n        {\n            var grainName = typeof(GeneratorTestGrain).FullName;\n            IGeneratorTestGrain grain = this.GrainFactory.GetGrain<IGeneratorTestGrain>(GetRandomGrainId(), grainName);\n\n            bool isNull = await grain.StringIsNullOrEmpty();\n            Assert.True(isNull);\n\n            await grain.StringSet(\"Begin\");\n\n            isNull = await grain.StringIsNullOrEmpty();\n            Assert.False(isNull);\n\n            MemberVariables members = await grain.GetMemberVariables();\n            Assert.Equal(\"Begin\", members.stringVar);\n\n            ASCIIEncoding encoding = new ASCIIEncoding();\n            byte[] bytes = encoding.GetBytes(\"ByteBegin\");\n            string str = \"StringBegin\";\n            MemberVariables memberVariables = new MemberVariables(bytes, str, ReturnCode.Fail);\n\n            await grain.SetMemberVariables(memberVariables);\n\n            members = await grain.GetMemberVariables();\n            ASCIIEncoding enc = new ASCIIEncoding();\n\n            Assert.Equal(\"ByteBegin\", enc.GetString(members.byteArray));\n            Assert.Equal(\"StringBegin\", members.stringVar);\n            Assert.Equal(ReturnCode.Fail, members.code);\n        }\n\n        [Fact]\n        public async Task GeneratorDerivedGrain1ControlFlow()\n        {\n            IGeneratorTestDerivedGrain1 grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n\n            bool isNull = await grain.StringIsNullOrEmpty();\n            Assert.True(isNull);\n\n            await grain.StringSet(\"Begin\");\n\n            isNull = await grain.StringIsNullOrEmpty();\n            Assert.False(isNull);\n\n            MemberVariables members = await grain.GetMemberVariables();\n            Assert.Equal(\"Begin\", members.stringVar);\n\n            ASCIIEncoding encoding = new ASCIIEncoding();\n            byte[] bytes = encoding.GetBytes(\"ByteBegin\");\n            string str = \"StringBegin\";\n            MemberVariables memberVariables = new MemberVariables(bytes, str, ReturnCode.Fail);\n\n            await grain.SetMemberVariables(memberVariables);\n\n            members = await grain.GetMemberVariables();\n            ASCIIEncoding enc = new ASCIIEncoding();\n\n            Assert.Equal(\"ByteBegin\", enc.GetString(members.byteArray));\n            Assert.Equal(\"StringBegin\", members.stringVar);\n            Assert.Equal(ReturnCode.Fail, members.code);\n        }\n\n        [Fact]\n        public async Task GeneratorDerivedGrain2ControlFlow()\n        {\n            var grainName = typeof(GeneratorTestDerivedGrain2).FullName;\n            IGeneratorTestDerivedGrain2 grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain2>(GetRandomGrainId(), grainName);\n\n            bool boolPromise = await grain.StringIsNullOrEmpty();\n            Assert.True(boolPromise);\n\n            await grain.StringSet(\"Begin\");\n\n            boolPromise = await grain.StringIsNullOrEmpty();\n            Assert.False(boolPromise);\n\n            MemberVariables members = await grain.GetMemberVariables();\n            Assert.Equal(\"Begin\", members.stringVar);\n\n            ASCIIEncoding encoding = new ASCIIEncoding();\n            byte[] bytes = encoding.GetBytes(\"ByteBegin\");\n            string str = \"StringBegin\";\n            MemberVariables memberVariables = new MemberVariables(bytes, str, ReturnCode.Fail);\n\n            await grain.SetMemberVariables(memberVariables);\n\n            members = await grain.GetMemberVariables();\n            ASCIIEncoding enc = new ASCIIEncoding();\n\n            Assert.Equal(\"ByteBegin\", enc.GetString(members.byteArray));\n            Assert.Equal(\"StringBegin\", members.stringVar);\n            Assert.Equal(ReturnCode.Fail, members.code);\n\n            string strPromise = await grain.StringConcat(\"Begin\", \"Cont\", \"End\");\n            Assert.Equal(\"BeginContEnd\", strPromise);\n        }\n\n        [Fact]\n        public async Task GeneratorDerivedDerivedGrainControlFlow()\n        {\n            IGeneratorTestDerivedDerivedGrain grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedDerivedGrain>(GetRandomGrainId());\n\n            bool isNull = await grain.StringIsNullOrEmpty();\n            Assert.True(isNull);\n\n            await grain.StringSet(\"Begin\");\n\n            isNull = await grain.StringIsNullOrEmpty();\n            Assert.False(isNull);\n\n            MemberVariables members = await grain.GetMemberVariables();\n            Assert.Equal(\"Begin\", members.stringVar);\n\n            ReplaceArguments arguments = new ReplaceArguments(\"Begin\", \"End\");\n            string strPromise = await grain.StringReplace(arguments);\n            Assert.Equal(\"End\", strPromise);\n\n            strPromise = await grain.StringConcat(\"Begin\", \"Cont\", \"End\");\n            Assert.Equal(\"BeginContEnd\", strPromise);\n\n            string[] strArray = { \"Begin\", \"Cont\", \"Cont\", \"End\" };\n            strPromise = await grain.StringNConcat(strArray);\n            Assert.Equal(\"BeginContContEnd\", strPromise);\n\n            ASCIIEncoding encoding = new ASCIIEncoding();\n            byte[] bytes = encoding.GetBytes(\"ByteBegin\");\n            string str = \"StringBegin\";\n            MemberVariables memberVariables = new MemberVariables(bytes, str, ReturnCode.Fail);\n\n            await grain.SetMemberVariables(memberVariables);\n\n            members = await grain.GetMemberVariables();\n\n            ASCIIEncoding enc = new ASCIIEncoding();\n\n            Assert.Equal(\"ByteBegin\", enc.GetString(members.byteArray));\n            Assert.Equal(\"StringBegin\", members.stringVar);\n            Assert.Equal(ReturnCode.Fail, members.code);\n        }\n\n        [Fact]\n        public async Task CodeGenDerivedFromCSharpInterfaceInDifferentAssembly()\n        {\n            var grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedFromCSharpInterfaceInExternalAssemblyGrain>(Guid.NewGuid());\n            var input = 1;\n            var output = await grain.Echo(input);\n            Assert.Equal(input, output);\n        }\n\n        [Fact]\n        public async Task GrainWithGenericMethods()\n        {\n            var grain = this.GrainFactory.GetGrain<IGrainWithGenericMethods>(Guid.NewGuid());\n            Assert.Equal(\"default string\", await grain.Default());\n            Assert.Equal(-8, await grain.RoundTrip(8));\n            Assert.Equal(new[] { typeof(IGrain), typeof(string), typeof(DateTime) }, await grain.GetTypesExplicit<IGrain, string, DateTime>());\n            Assert.Equal(new[] { typeof(IGrain), typeof(string), typeof(DateTime) }, await grain.GetTypesInferred((IGrain)grain, default(string), default(DateTime)));\n            Assert.Equal(new[] { typeof(IGrain), typeof(string) }, await grain.GetTypesInferred(default(IGrain), default(string), 0));\n            var now = DateTime.Now;\n            Assert.Equal(now, await grain.RoundTrip(now));\n            Assert.Equal(default, await grain.Default<DateTime>());\n\n            Assert.Equal(grain, await grain.Constraints(grain));\n        }\n\n        [Fact]\n        public async Task GenericGrainWithGenericMethods()\n        {\n            var grain = this.GrainFactory.GetGrain<IGenericGrainWithGenericMethods<int>>(Guid.NewGuid());\n\n            // The non-generic version of the method returns default(T).\n            Assert.Equal(0, await grain.Method(888));\n\n            // The generic version of the method returns the value provided.\n            var now = DateTime.Now;\n            Assert.Equal(now, await grain.Method(now));\n        }\n\n        [Fact]\n        public async Task GrainObserverWithGenericMethods()\n        {\n            var localObject = new ObserverWithGenericMethods();\n\n            var grain = this.GrainFactory.GetGrain<IGrainWithGenericMethods>(Guid.NewGuid());\n            var observer = this.GrainFactory.CreateObjectReference<IGrainObserverWithGenericMethods>(localObject);\n            await grain.SetValueOnObserver(observer, \"ToastedEnchiladas\");\n            Assert.Equal(\"ToastedEnchiladas\", await localObject.ValueTask);\n        }\n\n        [Fact]\n        public async Task GrainWithValueTaskMethod()\n        {\n            var grain = this.GrainFactory.GetGrain<IGrainWithGenericMethods>(Guid.NewGuid());\n            Assert.Equal(1, await grain.ValueTaskMethod(true));\n            Assert.Equal(2, await grain.ValueTaskMethod(false));\n        }\n\n        private class ObserverWithGenericMethods : IGrainObserverWithGenericMethods\n        {\n            private readonly TaskCompletionSource<object> valueCompletion = new TaskCompletionSource<object>();\n\n            public Task<object> ValueTask => this.valueCompletion.Task;\n\n            public void SetValue<T>(T value)\n            {\n                this.valueCompletion.SetResult(value);\n            }\n        }\n\n        [Fact, TestCategory(\"FSharp\")]\n        public async Task CodeGenDerivedFromFSharpInterfaceInDifferentAssembly()\n        {\n            var grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedFromFSharpInterfaceInExternalAssemblyGrain>(Guid.NewGuid());\n            var input = 1;\n            var output = await grain.Echo(input);\n            Assert.Equal(input, output);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/CodeGenTests/IRuntimeCodeGenGrain.cs",
    "content": "// ReSharper disable InconsistentNaming\nnamespace Tester.CodeGenTests\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Linq;\n    using System.Threading.Tasks;\n    using Orleans;\n    using Orleans.Providers;\n\n    // Regression test for explicit interface method implementations https://github.com/dotnet/orleans/issues/8991\n    public interface IExplicitInterfaceMethodImplementationTestGenericBase<in T>\n    {\n        Task M(T arg);\n    }\n\n    public interface IExplicitInterfaceMethodImplementationTestBase : IExplicitInterfaceMethodImplementationTestGenericBase<object>;\n\n    public interface IExplicitInterfaceMethodImplementationTestDerived : IExplicitInterfaceMethodImplementationTestBase, IExplicitInterfaceMethodImplementationTestGenericBase<string>\n    {\n        Task IExplicitInterfaceMethodImplementationTestGenericBase<object>.M(object obj) => M(obj);\n    }\n\n    public interface IExplicitInterfaceMethodImplementationTestImplementation : IExplicitInterfaceMethodImplementationTestDerived, IGrainWithGuidKey;\n\n    public class ExplicitInterfaceMethodImplementationTestGrain : Grain, IExplicitInterfaceMethodImplementationTestImplementation\n    {\n        public Task M(string arg)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    // End regression test for https://github.com/dotnet/orleans/issues/8991\n\n    public interface IGrainWithNonPublicMethods : IGrainWithGuidKey\n    {\n        internal class P1;\n        internal Task M1(P1 arg);\n\n        //protected class P2;\n        //protected Task M2(P2 arg);\n\n        internal protected class P3;\n        internal protected Task M3(P3 arg);\n\n        //private protected class P4;\n        //private protected Task M4(P4 arg);\n    }\n\n    public interface IGrainWithGenericMethods : IGrainWithGuidKey\n    {\n        Task<Type[]> GetTypesExplicit<T, U, V>();\n        Task<Type[]> GetTypesInferred<T, U, V>(T t, U u, V v);\n        Task<Type[]> GetTypesInferred<T, U>(T t, U u, int v);\n        Task<T> RoundTrip<T>(T val);\n        Task<int> RoundTrip(int val);\n        Task<T> Default<T>();\n        Task<string> Default();\n        Task<TGrain> Constraints<TGrain>(TGrain grain) where TGrain : IGrain;\n        Task SetValueOnObserver<T>(IGrainObserverWithGenericMethods observer, T value);\n        ValueTask<int> ValueTaskMethod(bool useCache);\n    }\n\n    public interface IGrainObserverWithGenericMethods : IGrainObserver\n    {\n        void SetValue<T>(T value);\n    }\n\n    public class GrainWithGenericMethods : Grain, IGrainWithGenericMethods\n    {\n        private object state;\n\n        public Task<Type[]> GetTypesExplicit<T, U, V>()\n        {\n            return Task.FromResult(new[] {typeof(T), typeof(U), typeof(V)});\n        }\n\n        public Task<Type[]> GetTypesInferred<T, U, V>(T t, U u, V v)\n        {\n            return Task.FromResult(new[] { typeof(T), typeof(U), typeof(V) });\n        }\n\n        public Task<Type[]> GetTypesInferred<T, U>(T t, U u, int v)\n        {\n            return Task.FromResult(new[] { typeof(T), typeof(U) });\n        }\n\n        public Task<T> RoundTrip<T>(T val)\n        {\n            return Task.FromResult(val);\n        }\n\n        public Task<int> RoundTrip(int val)\n        {\n            return Task.FromResult(-val);\n        }\n\n        public Task<T> Default<T>()\n        {\n            return Task.FromResult(default(T));\n        }\n\n        public Task<string> Default()\n        {\n            return Task.FromResult(\"default string\");\n        }\n\n        public Task<TGrain> Constraints<TGrain>(TGrain grain) where TGrain : IGrain\n        {\n            return Task.FromResult(grain);\n        }\n\n        public void SetValue<T>(T value)\n        {\n            this.state = value;\n        }\n\n        public Task<T> GetValue<T>() => Task.FromResult((T) this.state);\n\n        public Task SetValueOnObserver<T>(IGrainObserverWithGenericMethods observer, T value)\n        {\n            observer.SetValue<T>(value);\n            return Task.FromResult(0);\n        }\n\n        public ValueTask<int> ValueTaskMethod(bool useCache)\n        {\n            if (useCache)\n            {\n                return new ValueTask<int>(1);\n            }\n\n            return new ValueTask<int>(Task.FromResult(2));\n        }\n    }\n\n    public interface IGenericGrainWithGenericMethods<T> : IGrainWithGuidKey\n    {\n        Task<T> Method(T value);\n#pragma warning disable 693\n        Task<T> Method<T>(T value);\n#pragma warning restore 693\n    }\n\n    public class GrainWithGenericMethods<T> : Grain, IGenericGrainWithGenericMethods<T>\n    {\n        public Task<T> Method(T value) => Task.FromResult(default(T));\n\n#pragma warning disable 693\n        public Task<T> Method<T>(T value) => Task.FromResult(value);\n#pragma warning restore 693\n    }\n\n    [StorageProvider(ProviderName = \"MemoryStore\")]\n    public class RuntimeGenericGrain : Grain<GenericGrainState<@event>>, IRuntimeCodeGenGrain<@event>\n    {\n        public Task<@event> SetState(@event value)\n        {\n            this.State.@event = value;\n            return Task.FromResult(this.State.@event);\n        }\n\n        public Task<@event> @static()\n        {\n            return Task.FromResult(this.State.@event);\n        }\n    }\n\n    public interface IRuntimeCodeGenGrain<T> : IGrainWithGuidKey\n    {\n        /// <summary>\n        /// Sets and returns the grain's state.\n        /// </summary>\n        /// <param name=\"value\">The new state.</param>\n        /// <returns>The current state.</returns>\n        Task<T> SetState(T value);\n\n        /// <summary>\n        /// Tests that code generation correctly handles methods with reserved keyword identifiers.\n        /// </summary>\n        /// <returns>The current state's event.</returns>\n        Task<@event> @static();\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericGrainState<T>\n    {\n        [Id(0)]\n        public T @event { get; set; }\n    }\n\n    /// <summary>\n    /// A class designed to test that code generation correctly handles reserved keywords.\n    /// </summary>\n    [GenerateSerializer]\n    public class @event : IEquatable<@event>\n    {\n        private static readonly IEqualityComparer<@event> EventComparerInstance = new EventEqualityComparer();\n\n        public enum @enum\n        {\n            @async,\n            @int,\n        }\n\n        /// <summary>\n        /// A public field.\n        /// </summary>\n        [Id(0)]\n        public Guid Id;\n\n        /// <summary>\n        /// A private field.\n        /// </summary>\n        [Id(1)]\n        private Guid privateId;\n\n        /// <summary>\n        /// A property with a reserved keyword type and identifier.\n        /// </summary>\n        [Id(2)]\n        public @event @public { get; set; }\n\n        /// <summary>\n        /// Gets or sets the enum.\n        /// </summary>\n        [Id(3)]\n        public @enum Enum { get; set; }\n\n        /// <summary>\n        /// A property with a reserved keyword generic type and identifier.\n        /// </summary>\n        [Id(4)]\n        public List<@event> @if { get; set; }\n\n        public static IEqualityComparer<@event> EventComparer\n        {\n            get\n            {\n                return EventComparerInstance;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the private id.\n        /// </summary>\n        // ReSharper disable once ConvertToAutoProperty\n        public Guid PrivateId\n        {\n            get\n            {\n                return this.privateId;\n            }\n\n            set\n            {\n                this.privateId = value;\n            }\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj))\n            {\n                return false;\n            }\n            if (ReferenceEquals(this, obj))\n            {\n                return true;\n            }\n            if (obj.GetType() != this.GetType())\n            {\n                return false;\n            }\n\n            return this.Equals((@event)obj);\n        }\n\n        public override int GetHashCode() => HashCode.Combine(@if, @public, privateId, Id, Enum);\n\n        public bool Equals(@event other)\n        {\n            if (ReferenceEquals(null, other))\n            {\n                return false;\n            }\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n            if (this.@if != other.@if)\n            {\n                if (this.@if != null && !this.@if.SequenceEqual(other.@if, EventComparer))\n                {\n                    return false;\n                }\n            }\n\n            if (!Equals(this.@public, other.@public))\n            {\n                if (this.@public != null && !this.@public.Equals(other.@public))\n                {\n                    return false;\n                }\n            }\n\n            return this.privateId.Equals(other.privateId) && this.Id.Equals(other.Id) && this.Enum == other.Enum;\n        }\n\n        private sealed class EventEqualityComparer : IEqualityComparer<@event>\n        {\n            public bool Equals(@event x, @event y)\n            {\n                return x.Equals(y);\n            }\n\n            public int GetHashCode(@event obj)\n            {\n                return obj.GetHashCode();\n            }\n        }\n    }\n\n    [GenerateSerializer]\n    public class NestedGeneric<T>\n    {\n        [Id(0)]\n        public Nested Payload { get; set; }\n\n        [GenerateSerializer]\n        public class Nested\n        {\n            [Id(0)]\n            public T Value { get; set; }\n        }\n    }\n\n    [GenerateSerializer]\n    public class NestedConstructedGeneric\n    {\n        [Id(0)]\n        public Nested<int> Payload { get; set; }\n\n        [GenerateSerializer]\n        public class Nested<T>\n        {\n            [Id(0)]\n            public T Value { get; set; }\n        }\n    }\n\n    public interface INestedGenericGrain : IGrainWithGuidKey\n    {\n        Task<int> Do(NestedGeneric<int> value);\n        Task<int> Do(NestedConstructedGeneric value);\n    }\n\n    /// <summary>\n    /// Tests that nested classes do not fail code generation.\n    /// </summary>\n    public class NestedGenericGrain : Grain,  INestedGenericGrain\n    {\n        public Task<int> Do(NestedGeneric<int> value)\n        {\n            return Task.FromResult(value.Payload.Value);\n        }\n\n        public Task<int> Do(NestedConstructedGeneric value)\n        {\n            return Task.FromResult(value.Payload.Value);\n        }\n    }\n\n    public interface IGrainWithStaticMembers : IGrainWithGuidKey\n    {\n        public static int StaticMethodWithNonAsyncReturnType(int a) => 0;\n        public static virtual int StaticVirtualMethodWithNonAsyncReturnType(int a) => 0;\n        public static int StaticProperty => 0;\n        public static virtual int StaticVirtualProperty => 0;\n        public static int StaticMethodWithOutAndVarParams(out int a, ref int b) { a = 0; return 0; }\n        public static virtual int StaticVirtualMethodWithOutAndVarParams(out int a, ref int b) { a = 0; return 0; }\n    }\n\n    public class GrainWithStaticMembers : Grain, IGrainWithStaticMembers\n    { }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Defines the test collection for DefaultCluster tests.\n    /// This collection ensures all tests share the same cluster instance for better performance.\n    /// Tests in this collection run sequentially to avoid conflicts.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines the test collection for TestEnvironmentFixture.\n    /// This collection provides shared test environment setup across multiple test classes.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ConcreteStateClassTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests grain state persistence using concrete state classes.\n    /// Verifies that grain state survives deactivation and reactivation cycles.\n    /// Orleans supports automatic state persistence where grain state is:\n    /// - Loaded when the grain activates\n    /// - Saved when state changes (or on demand)\n    /// - Preserved across grain deactivations\n    /// This enables grains to maintain durable state without explicit database code.\n    /// </summary>\n    public class StateClassTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly Random rand = new Random();\n\n        public StateClassTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests basic state persistence functionality.\n        /// Verifies that grain state persists across deactivation/reactivation cycles.\n        /// The test:\n        /// 1. Sets a value in grain state\n        /// 2. Deactivates the grain\n        /// 3. Reactivates the grain (gets new version/activation)\n        /// 4. Verifies the state value was preserved\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task StateClassTests_StateClass()\n        {\n            await StateClassTests_Test(\"UnitTests.Grains.SimplePersistentGrain\");\n        }\n\n        /// <summary>\n        /// Helper method that performs the actual state persistence test.\n        /// Demonstrates that:\n        /// - Each grain activation gets a unique version identifier\n        /// - State changes survive grain deactivation\n        /// - New activations load the previously persisted state\n        /// </summary>\n        private async Task StateClassTests_Test(string grainClass)\n        {\n            var grain = this.GrainFactory.GetGrain<ISimplePersistentGrain>(GetRandomGrainId(), grainClass);\n            var originalVersion = await grain.GetVersion();\n            await grain.SetA(98, true); // deactivate grain after setting A\n\n            var newVersion = await grain.GetVersion(); // get a new version from the new activation\n            Assert.NotEqual(originalVersion, newVersion);\n            var a = await grain.GetA();\n            Assert.Equal(98, a); // value of A survive deactivation and reactivation of the grain\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/DeactivationTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests grain deactivation and reactivation behaviors in Orleans.\n    /// Grain deactivation is a key part of Orleans' resource management:\n    /// - Grains can be explicitly deactivated or automatically deactivated when idle\n    /// - Deactivation releases memory and other resources\n    /// - Reactivation occurs transparently when a deactivated grain is called again\n    /// - State is preserved across deactivation/reactivation cycles\n    /// These tests verify the performance and correctness of this mechanism.\n    /// </summary>\n    public class DeactivationTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public DeactivationTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests the timing of grain deactivation and reactivation.\n        /// Verifies that:\n        /// - Explicit deactivation followed by reactivation completes quickly (under 1 second)\n        /// - The grain gets a new activation (new version) after deactivation\n        /// - State is preserved across the deactivation/reactivation cycle\n        /// This ensures Orleans can efficiently manage grain lifecycle without significant overhead.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DeactivateReactivateTiming()\n        {\n            var x = GetRandomGrainId();\n            var grain = this.GrainFactory.GetGrain<ISimplePersistentGrain>(x);\n            var originalVersion = await grain.GetVersion();\n\n            var sw = Stopwatch.StartNew();\n\n            await grain.SetA(99, true); // deactivate grain after setting A value\n            var newVersion = await grain.GetVersion(); // get a new version from the new activation\n            Assert.NotEqual(originalVersion, newVersion);\n\n            sw.Stop();\n\n            Assert.True(sw.ElapsedMilliseconds < 1000);\n            this.Logger.LogInformation(\"Took {ElapsedMilliseconds}ms to deactivate and reactivate the grain\", sw.ElapsedMilliseconds);\n\n            var a = await grain.GetA();\n            Assert.Equal(99, a); // value of A survive deactivation and reactivation of the grain\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/EchoTaskGrainTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests basic grain communication patterns using Echo grains.\n    /// Echo grains are simple test grains that return or process the input they receive.\n    /// These tests verify fundamental Orleans features:\n    /// - Basic request/response communication\n    /// - Error propagation from grains to clients\n    /// - Timeout handling and recovery\n    /// - Cross-silo communication\n    /// - Async/await patterns in grain methods\n    /// - Nullable type handling across grain boundaries\n    /// </summary>\n    public class EchoTaskGrainTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly TimeSpan timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(10) : TimeSpan.FromSeconds(10);\n        private const string expectedEcho = \"Hello from EchoGrain\";\n        private const string expectedEchoError = \"Error from EchoGrain\";\n\n        public static readonly TimeSpan Epsilon = TimeSpan.FromSeconds(1);\n\n        public EchoTaskGrainTests(DefaultClusterFixture fixture)\n            : base(fixture)\n        {\n            if (HostedCluster.SecondarySilos.Count == 0)\n            {\n                HostedCluster.StartAdditionalSilo();\n                HostedCluster.WaitForLivenessToStabilizeAsync().Wait();\n            }\n        }\n\n        /// <summary>\n        /// Tests basic grain reference creation.\n        /// Verifies that grain references can be obtained without activation.\n        /// Getting a grain reference is a local operation that doesn't communicate with the cluster.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public void EchoGrain_GetGrain()\n        {\n            _ = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n        }\n\n        /// <summary>\n        /// Tests basic grain method invocation with string echo.\n        /// Verifies that:\n        /// - Grain activation occurs on first call\n        /// - Method parameters are correctly marshaled to the grain\n        /// - Return values are correctly marshaled back to the client\n        /// This is the most fundamental test of grain communication.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_Echo()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"CreateGrain took {Elapsed}\", clock.Elapsed);\n\n            clock.Restart();\n            string received = await grain.EchoAsync(expectedEcho);\n            this.Logger.LogInformation(\"EchoGrain.Echo took {Elapsed}\", clock.Elapsed);\n\n            Assert.Equal(expectedEcho, received);\n        }\n\n        /// <summary>\n        /// Tests exception propagation from grain to client.\n        /// Verifies that exceptions thrown in grain methods are:\n        /// - Serialized and sent back to the client\n        /// - Wrapped in appropriate exception types\n        /// - Contain the original error message\n        /// This ensures proper error handling in distributed scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_EchoError()\n        {\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n\n            Task<string> promise = grain.EchoErrorAsync(expectedEchoError);\n            await promise.ContinueWith(t =>\n            {\n                if (!t.IsFaulted) Assert.True(false); // EchoError should not have completed successfully\n\n                Exception exc = t.Exception;\n                while (exc is AggregateException) exc = exc.InnerException;\n                string received = exc.Message;\n                Assert.Equal(expectedEchoError, received);\n            }).WaitAsync(timeout);\n        }\n\n        /// <summary>\n        /// Tests timeout handling using ContinueWith pattern.\n        /// Verifies that:\n        /// - Long-running grain methods timeout according to configuration\n        /// - TimeoutException is properly thrown\n        /// - Timeout occurs within expected time bounds\n        /// This tests Orleans' ability to prevent hung calls from blocking indefinitely.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Echo\"), TestCategory(\"Timeout\")]\n        public async Task EchoGrain_Timeout_ContinueWith()\n        {\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n\n            TimeSpan delay5 = TimeSpan.FromSeconds(30); // grain call timeout (set in config)\n            TimeSpan delay45 = TimeSpan.FromSeconds(45);\n            TimeSpan delay60 = TimeSpan.FromSeconds(60);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            Task<int> promise = grain.BlockingCallTimeoutNoResponseTimeoutOverrideAsync(delay60);\n            await promise.ContinueWith(\n                t =>\n                {\n                    if (!t.IsFaulted) Assert.Fail(\"BlockingCallTimeout should not have completed successfully\");\n\n                    Exception exc = t.Exception;\n                    while (exc is AggregateException) exc = exc.InnerException;\n                    Assert.IsAssignableFrom<TimeoutException>(exc);\n                }).WaitAsync(delay45);\n            sw.Stop();\n            Assert.True(TimeIsLonger(sw.Elapsed, delay5), $\"Elapsed time out of range: {sw.Elapsed}\");\n            Assert.True(TimeIsShorter(sw.Elapsed, delay60), $\"Elapsed time out of range: {sw.Elapsed}\");\n        }\n\n        /// <summary>\n        /// Tests timeout handling using async/await pattern.\n        /// Similar to Timeout_ContinueWith but using modern async/await syntax.\n        /// Verifies proper timeout behavior with await-based error handling.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_Timeout_Await()\n        {\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n\n            TimeSpan delay5 = TimeSpan.FromSeconds(5);\n            TimeSpan delay25 = TimeSpan.FromSeconds(25);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            try\n            {\n                int res = await grain.BlockingCallTimeoutAsync(delay25);\n                Assert.Fail($\"BlockingCallTimeout should not have completed successfully, but returned {res}\");\n            }\n            catch (Exception exc)\n            {\n                while (exc is AggregateException) exc = exc.InnerException;\n                Assert.IsAssignableFrom<TimeoutException>(exc);\n            }\n            sw.Stop();\n            Assert.True(TimeIsLonger(sw.Elapsed, delay5), $\"Elapsed time out of range: {sw.Elapsed}\");\n            Assert.True(TimeIsShorter(sw.Elapsed, delay25), $\"Elapsed time out of range: {sw.Elapsed}\");\n        }\n\n        /// <summary>\n        /// Tests timeout handling when using Task.Result (blocking wait).\n        /// Verifies that timeouts work correctly even when using synchronous waiting patterns.\n        /// Note: This pattern is generally discouraged but needs to work for compatibility.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Echo\"), TestCategory(\"Timeout\")]\n        public async Task EchoGrain_Timeout_Result()\n        {\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n\n            TimeSpan delay5 = TimeSpan.FromSeconds(5);\n            TimeSpan delay25 = TimeSpan.FromSeconds(25);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            try\n            {\n                // Note that this method purposely uses Task.Result.\n                int res = await Task.Run(() =>\n                {\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                    return grain.BlockingCallTimeoutAsync(delay25).Result;\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                });\n\n                Assert.Fail($\"BlockingCallTimeout should not have completed successfully, but returned {res}\");\n            }\n            catch (Exception exc)\n            {\n                while (exc is AggregateException) exc = exc.InnerException;\n                Assert.IsAssignableFrom<TimeoutException>(exc);\n            }\n            sw.Stop();\n            Assert.True(TimeIsLonger(sw.Elapsed, delay5), $\"Elapsed time out of range: {sw.Elapsed}\");\n            Assert.True(TimeIsShorter(sw.Elapsed, delay25), $\"Elapsed time out of range: {sw.Elapsed}\");\n        }\n\n        /// <summary>\n        /// Tests grain state persistence across multiple calls.\n        /// Verifies that:\n        /// - Grains can maintain state between calls\n        /// - State is updated correctly for both successful and error cases\n        /// - The last value (or error message) is retrievable\n        /// This demonstrates basic stateful grain behavior.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_LastEcho()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"CreateGrain took {Elapsed}\", clock.Elapsed);\n\n            clock.Restart();\n            string received = await grain.EchoAsync(expectedEcho);\n            this.Logger.LogInformation(\"EchoGrain.Echo took {Elapsed}\", clock.Elapsed);\n\n            Assert.Equal(expectedEcho, received);\n\n            clock.Start();\n\n            received = await grain.GetLastEchoAsync();\n            this.Logger.LogInformation(\"EchoGrain.LastEcho took {Elapsed}\", clock.Elapsed);\n\n            Assert.Equal(expectedEcho, received); // LastEcho-Echo\n\n            Task<string> promise = grain.EchoErrorAsync(expectedEchoError);\n            await promise.ContinueWith(t =>\n            {\n                if (!t.IsFaulted) Assert.True(false); // EchoError should not have completed successfully\n\n                Exception exc = t.Exception;\n                while (exc is AggregateException) exc = exc.InnerException;\n                string received = exc.Message;\n                Assert.Equal(expectedEchoError, received);\n            }).WaitAsync(timeout);\n\n            clock.Restart();\n            received = await grain.GetLastEchoAsync();\n            this.Logger.LogInformation(\"EchoGrain.LastEcho-Error took {Elapsed}\", clock.Elapsed);\n\n            Assert.Equal(expectedEchoError, received); // LastEcho-Error\n        }\n\n        /// <summary>\n        /// Tests basic grain liveness check (ping).\n        /// Verifies that grains can respond to simple parameterless calls.\n        /// Ping operations are useful for health checks and keeping grains activated.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_Ping()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            string what = \"CreateGrain\";\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            what = \"EchoGrain.Ping\";\n            clock.Restart();\n\n            await grain.PingAsync().WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n        }\n\n        /// <summary>\n        /// Tests grain's ability to ping its local silo.\n        /// Verifies intra-silo communication where a grain communicates with its hosting silo.\n        /// This pattern is useful for silo-level health checks and diagnostics.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_PingSilo_Local()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            string what = \"CreateGrain\";\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            what = \"EchoGrain.PingLocalSilo\";\n            clock.Restart();\n            await grain.PingLocalSiloAsync().WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n        }\n\n        /// <summary>\n        /// Tests grain's ability to ping specific remote silos.\n        /// Verifies cross-silo communication where a grain can target specific silos.\n        /// This demonstrates Orleans' ability to route messages to specific cluster nodes.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_PingSilo_Remote()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            string what = \"CreateGrain\";\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            SiloAddress silo1 = HostedCluster.Primary.SiloAddress;\n            SiloAddress silo2 = HostedCluster.SecondarySilos[0].SiloAddress;\n\n            what = \"EchoGrain.PingRemoteSilo[1]\";\n            clock.Restart();\n            await grain.PingRemoteSiloAsync(silo1).WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            what = \"EchoGrain.PingRemoteSilo[2]\";\n            clock.Restart();\n            await grain.PingRemoteSiloAsync(silo2).WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n        }\n\n        /// <summary>\n        /// Tests grain's ability to ping any other silo in the cluster.\n        /// Verifies that grains can discover and communicate with other silos dynamically.\n        /// This is useful for distributed health checks and cluster topology awareness.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_PingSilo_OtherSilo()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            string what = \"CreateGrain\";\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            what = \"EchoGrain.PingOtherSilo\";\n            clock.Restart();\n            await grain.PingOtherSiloAsync().WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n        }\n\n        /// <summary>\n        /// Tests grain's ability to interact with cluster membership.\n        /// Verifies that grains can query and use membership information to communicate\n        /// with other cluster members. This demonstrates Orleans' membership awareness.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_PingSilo_OtherSilo_Membership()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            string what = \"CreateGrain\";\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoTaskGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n\n            what = \"EchoGrain.PingOtherSiloMembership\";\n            clock.Restart();\n            await grain.PingClusterMemberAsync().WaitAsync(timeout);\n            this.Logger.LogInformation(\"{What} took {Elapsed}\", what, clock.Elapsed);\n        }\n\n        /// <summary>\n        /// Tests various async/await patterns in non-reentrant grains.\n        /// Verifies that blocking grains correctly handle:\n        /// - Direct async method calls\n        /// - Chained async calls (grain calling grain)\n        /// - Different Task-based return patterns\n        /// Non-reentrant grains process one message at a time.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoTaskGrain_Await()\n        {\n            IBlockingEchoTaskGrain g = this.GrainFactory.GetGrain<IBlockingEchoTaskGrain>(GetRandomGrainId());\n\n            string received = await g.Echo(expectedEcho);\n            Assert.Equal(expectedEcho, received); // Echo\n\n            received = await g.CallMethodAV_Await(expectedEcho);\n            Assert.Equal(expectedEcho, received); // CallMethodAV_Await\n\n            received = await g.CallMethodTask_Await(expectedEcho);\n            Assert.Equal(expectedEcho, received); // CallMethodTask_Await\n        }\n\n        /// <summary>\n        /// Tests various async/await patterns in reentrant grains.\n        /// Similar to EchoTaskGrain_Await but with reentrant grains that can process\n        /// multiple messages concurrently. This verifies Orleans' reentrancy support.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoTaskGrain_Await_Reentrant()\n        {\n            IReentrantBlockingEchoTaskGrain g = this.GrainFactory.GetGrain<IReentrantBlockingEchoTaskGrain>(GetRandomGrainId());\n\n            string received = await g.Echo(expectedEcho);\n            Assert.Equal(expectedEcho, received); // Echo\n\n            received = await g.CallMethodAV_Await(expectedEcho);\n            Assert.Equal(expectedEcho, received); // CallMethodAV_Await\n\n            received = await g.CallMethodTask_Await(expectedEcho);\n            Assert.Equal(expectedEcho, received); // CallMethodTask_Await\n        }\n\n        /// <summary>\n        /// Tests nullable type handling across grain boundaries.\n        /// Verifies that:\n        /// - Nullable values are correctly serialized when non-null\n        /// - Null values are properly handled and returned as null\n        /// This ensures Orleans correctly handles .NET nullable value types.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Echo\")]\n        public async Task EchoGrain_EchoNullable()\n        {\n            Stopwatch clock = new Stopwatch();\n\n            clock.Start();\n            var grain = this.GrainFactory.GetGrain<IEchoGrain>(Guid.NewGuid());\n            this.Logger.LogInformation(\"CreateGrain took {Elapsed}\", clock.Elapsed);\n\n            clock.Restart();\n            var now = DateTime.Now;\n            var received = await grain.EchoNullable(now);\n            this.Logger.LogInformation(\"EchoGrain.EchoNullable took {Elapsed}\", clock.Elapsed);\n\n            Assert.Equal(now, received);\n\n            clock.Restart();\n            received = await grain.EchoNullable(null);\n            this.Logger.LogInformation(\"EchoGrain.EchoNullable took {Elapsed}\", clock.Elapsed);\n            Assert.Null(received);\n        }\n\n        // ---------- Utility methods ----------\n\n        private bool TimeIsLonger(TimeSpan time, TimeSpan limit)\n        {\n            this.Logger.LogInformation(\"Compare TimeIsLonger: Actual={Time} Limit={Limit} Epsilon={Epsilon}\", time, limit, Epsilon);\n            return time >= (limit - Epsilon);\n        }\n\n        private bool TimeIsShorter(TimeSpan time, TimeSpan limit)\n        {\n            this.Logger.LogInformation(\"Compare TimeIsShorter: Actual={Time} Limit={Limit} Epsilon={Epsilon}\", time, limit, Epsilon);\n            return time <= (limit + Epsilon);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ErrorGrainTest.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Internal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests error handling and exception propagation in Orleans.\n    /// These tests verify Orleans' robust error handling capabilities including:\n    /// - Exception serialization and propagation across process boundaries\n    /// - Handling of synchronous and asynchronous errors\n    /// - Timeout behavior and recovery\n    /// - Stress testing with multiple concurrent failing operations\n    /// - Various grain communication patterns under error conditions\n    /// Orleans ensures that errors in grains don't crash the system and are properly communicated to callers.\n    /// </summary>\n    public class ErrorGrainTest : HostedTestClusterEnsureDefaultStarted\n    {\n        private static readonly TimeSpan timeout = TimeSpan.FromSeconds(10);\n        private readonly ITestOutputHelper output;\n\n        public ErrorGrainTest(ITestOutputHelper output, DefaultClusterFixture fixture) : base(fixture)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests basic grain reference creation for error testing grains.\n        /// Verifies that error grain references can be obtained and basic methods can be called.\n        /// This establishes the baseline for error handling tests.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\")]\n        public async Task ErrorGrain_GetGrain()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n            _ = await grain.GetA();\n        }\n\n        /// <summary>\n        /// Tests error handling for locally thrown exceptions (not in Orleans grains).\n        /// Verifies that standard .NET exception handling works as expected for comparison\n        /// with distributed error handling in Orleans.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\")]\n        public async Task ErrorHandlingLocalError()\n        {\n            LocalErrorGrain localGrain = new LocalErrorGrain();\n            \n            Task<int> intPromise = localGrain.GetAxBError();\n            try\n            {\n                await intPromise;\n                Assert.Fail(\"Should not have executed\");\n            }\n            catch (Exception exc2)\n            {\n                Assert.Equal(exc2.GetBaseException().Message, (new Exception(\"GetAxBError-Exception\")).Message);\n            }\n\n            Assert.True(intPromise.Status == TaskStatus.Faulted);                \n        }\n\n        /// <summary>\n        /// Tests that grain methods that throw exceptions properly fail their returned Tasks.\n        /// Verifies that:\n        /// - Exceptions in grain methods cause the Task to enter Faulted state\n        /// - The exception can be retrieved from the Task\n        /// - Multiple awaits on the same failed Task consistently throw the same exception\n        /// This ensures reliable error propagation in distributed calls.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\")]\n        public async Task ErrorHandlingGrainError1()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n\n            Task<int> intPromise = grain.GetAxBError();\n            try\n            {\n                await intPromise;\n                Assert.Fail(\"Should have thrown\");\n            }\n            catch (Exception)\n            {\n                Assert.True(intPromise.Status == TaskStatus.Faulted);\n            }\n\n            try\n            {\n                await intPromise;\n                Assert.Fail(\"Should have thrown\");\n            }\n            catch (Exception exc2)\n            {\n                Assert.True(intPromise.Status == TaskStatus.Faulted);\n                Assert.Equal((new Exception(\"GetAxBError-Exception\")).Message, exc2.GetBaseException().Message);\n            }\n\n            Assert.True(intPromise.Status == TaskStatus.Faulted);\n        }\n\n        /// <summary>\n        /// Tests behavior of long-running grain methods without errors.\n        /// Verifies that:\n        /// - Tasks for long-running operations don't complete prematurely\n        /// - The Task eventually completes successfully\n        /// - Timing assertions ensure proper async behavior\n        /// This establishes baseline behavior for comparison with timeout scenarios.\n        /// </summary>\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/9558\"), TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\")]\n        public async Task ErrorHandlingTimedMethod()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n\n            Task promise = grain.LongMethod(2000);\n\n            // there is a race in the test here. If run in debugger, the invocation can actually finish OK\n            Stopwatch stopwatch = Stopwatch.StartNew();\n\n            await Task.Delay(1000);\n            Assert.False(promise.IsCompleted, \"The task shouldn't have completed yet.\");\n\n            // these asserts depend on timing issues and will be wrong for the sync version of OrleansTask\n            Assert.True(stopwatch.ElapsedMilliseconds >= 900, $\"Waited less than 900ms: ({stopwatch.ElapsedMilliseconds}ms)\"); // check that we waited at least 0.9 second\n            Assert.True(stopwatch.ElapsedMilliseconds <= 1300, $\"Waited longer than 1300ms: ({stopwatch.ElapsedMilliseconds}ms)\");\n\n            await promise; // just wait for the server side grain invocation to finish\n            \n            Assert.True(promise.Status == TaskStatus.RanToCompletion);\n        }\n\n        /// <summary>\n        /// Tests behavior of long-running grain methods that eventually throw exceptions.\n        /// Verifies that:\n        /// - Tasks don't complete until the actual error occurs\n        /// - The exception is properly propagated when the method completes\n        /// - Timing ensures the error happens after the expected delay\n        /// This tests Orleans' handling of delayed failures.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\")]\n        public async Task ErrorHandlingTimedMethodWithError()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n\n            Task task = grain.LongMethodWithError(2000);\n            // Removed flaky assertion about task completion due to potential race condition.\n            await Assert.ThrowsAsync<Exception>(async () => await task);\n            Assert.True(task.Status == TaskStatus.Faulted);\n        }\n\n        /// <summary>\n        /// Stress tests Orleans with many concurrent delayed grain calls.\n        /// Verifies that:\n        /// - The system can handle hundreds of concurrent grain calls\n        /// - All calls complete successfully without deadlocks\n        /// - Orleans properly manages resources under load\n        /// This tests the scalability of Orleans' message handling and scheduling.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ErrorHandling\"), TestCategory(\"Stress\")]\n        public async Task StressHandlingMultipleDelayedRequests()\n        {\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId());\n            bool once = true;\n            List<Task> tasks = new List<Task>();\n            for (int i = 0; i < 500; i++)\n            {\n                Task promise = grain.DelayMethod(1);\n                tasks.Add(promise);\n                if (once)\n                {\n                    once = false;\n                    await promise;\n                }\n\n            }\n            await Task.WhenAll(tasks).WaitAsync(TimeSpan.FromSeconds(20));\n        }\n\n        /// <summary>\n        /// Tests passing collections of grain references as method arguments.\n        /// Verifies that Orleans correctly serializes and deserializes complex types\n        /// containing grain references. This is important for scenarios where grains\n        /// need to coordinate with multiple other grains.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ErrorHandling\"), TestCategory(\"GrainReference\")]\n        public async Task ArgumentTypes_ListOfGrainReferences()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            List<IErrorGrain> list = new List<IErrorGrain>();\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n            list.Add(this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName));\n            list.Add(this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName));\n            await grain.AddChildren(list).WaitAsync(timeout);\n        }\n\n        /// <summary>\n        /// Tests Orleans' delayed execution capabilities.\n        /// Verifies that grains can schedule delayed operations and that these\n        /// operations execute correctly after the specified delay.\n        /// This tests Orleans' internal timer and scheduling mechanisms.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"AsynchronyPrimitives\"), TestCategory(\"ErrorHandling\")]\n        public async Task AC_DelayedExecutor_2()\n        {\n            var grainFullName = typeof(ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainFullName);\n            Task<bool> promise = grain.ExecuteDelayed(TimeSpan.FromMilliseconds(2000));\n            bool result = await promise;\n            Assert.True(result);\n        }\n\n        /// <summary>\n        /// Tests async method patterns in simple grains.\n        /// Verifies that grains correctly handle async methods for setting and getting state.\n        /// This demonstrates Orleans' support for modern async/await patterns in grain implementations.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"SimpleGrain\")]\n        public async Task SimpleGrain_AsyncMethods()\n        {\n            ISimpleGrainWithAsyncMethods grain = this.GrainFactory.GetGrain<ISimpleGrainWithAsyncMethods>(GetRandomGrainId());\n            Task setPromise = grain.SetA_Async(10);\n            await setPromise;\n\n            setPromise = grain.SetB_Async(30);\n            await setPromise;\n\n            var value = await grain.GetAxB_Async();\n            Assert.Equal(300, value);\n        }\n\n        /// <summary>\n        /// Tests promise forwarding where one grain forwards a call to another grain.\n        /// Verifies that Orleans correctly handles chained grain calls where the result\n        /// of one grain call is directly returned by another grain.\n        /// This pattern is common in grain orchestration scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"SimpleGrain\")]\n        public async Task SimpleGrain_PromiseForward()\n        {\n            ISimpleGrain forwardGrain = this.GrainFactory.GetGrain<IPromiseForwardGrain>(GetRandomGrainId());\n            Task<int> promise = forwardGrain.GetAxB(5, 6);\n            int result = await promise;\n            Assert.Equal(30, result);\n        }\n\n        /// <summary>\n        /// Tests GUID-based grain ID distribution and hashing.\n        /// Verifies that different GUID patterns produce well-distributed hash codes\n        /// for grain placement. This is important for load balancing across silos.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"SimpleGrain\")]\n        public void SimpleGrain_GuidDistribution()\n        {\n            int n = 0x1111;\n            CreateGR(n, 1);\n            CreateGR(n + 1, 1);\n            CreateGR(n + 2, 1);\n            CreateGR(n + 3, 1);\n            CreateGR(n + 4, 1);\n\n            Logger.LogInformation(\"================\");\n\n            CreateGR(n, 2);\n            CreateGR(n + 1, 2);\n            CreateGR(n + 2, 2);\n            CreateGR(n + 3, 2);\n            CreateGR(n + 4, 2);\n\n            Logger.LogInformation(\"DONE.\");\n        }\n\n        /// <summary>\n        /// Helper method to create grain references with specific GUID patterns.\n        /// Used to test hash code distribution for different GUID formats.\n        /// </summary>\n        private void CreateGR(int n, int type)\n        {\n            Guid guid;\n            if (type == 1)\n            {\n                guid = Guid.Parse(string.Format(\"00000000-0000-0000-0000-{0:X12}\", n));\n            }\n            else\n            {\n                guid = Guid.Parse(string.Format(\"{0:X8}-0000-0000-0000-000000000000\", n));\n            }\n            IEchoGrain grain = this.GrainFactory.GetGrain<IEchoGrain>(guid);\n            GrainId grainId = ((GrainReference)grain.AsReference<IEchoGrain>()).GrainId;\n            output.WriteLine(\"Guid = {0}, Guid.HashCode = x{1:X8}, GrainId.HashCode = x{2:X8}, GrainId.UniformHashCode = x{3:X8}\", guid, guid.GetHashCode(), grainId.GetHashCode(), grainId.GetUniformHashCode());\n        }\n\n        /// <summary>\n        /// Tests observer disconnection scenarios.\n        /// Verifies behavior when client observers are disconnected from grains.\n        /// This tests Orleans' observer pattern implementation for event notifications.\n        /// </summary>\n        [Fact, TestCategory(\"Revisit\"), TestCategory(\"Observers\")]\n        public void ObserverTest_Disconnect()\n        {\n            ObserverTest_DisconnectRunner(false);\n        }\n\n        /// <summary>\n        /// Tests observer disconnection with multiple subscriptions.\n        /// Verifies behavior when the same observer is subscribed multiple times\n        /// and then disconnected. This tests edge cases in observer management.\n        /// </summary>\n        [Fact, TestCategory(\"Revisit\"), TestCategory(\"Observers\")]\n        public void ObserverTest_Disconnect2()\n        {\n            ObserverTest_DisconnectRunner(true);\n        }\n\n        /// <summary>\n        /// Helper method for testing observer disconnection scenarios.\n        /// The observeTwice parameter controls whether to test single or double subscription.\n        /// Note: This test appears to be commented out for manual debugging scenarios.\n        /// </summary>\n        private void ObserverTest_DisconnectRunner(bool observeTwice)\n        {\n            // this is for manual repro & validation in the debugger\n            // wait to send event because it takes 60s to drop client grain\n            //var simple1 = SimpleGrainTests.GetSimpleGrain();\n            //var simple2 = SimpleGrainFactory.Cast(Domain.Current.Create(typeof(ISimpleGrain).FullName,\n            //    new Dictionary<string, object> { { \"EventDelay\", 70000 } }));\n            //var result = new ResultHandle();\n            //var callback = new SimpleGrainObserver((a, b, r) =>\n            //{\n            //    r.Done = (a == 10);\n            //    output.WriteLine(\"Received observer callback: A={0} B={1} Done={2}\", a, b, r.Done);\n            //}, result);\n            //var observer = SimpleGrainObserverFactory.CreateObjectReference(callback);\n            //if (observeTwice)\n            //{\n            //    simple1.Subscribe(observer).Wait();\n            //    simple1.SetB(1).Wait(); // send a message to the observer to get it in the cache\n            //}\n            //simple2.Subscribe(observer).Wait();\n            //simple2.SetA(10).Wait();\n            //Thread.Sleep(2000);\n            //Client.Uninitialize();\n            //var timeout80sec = TimeSpan.FromSeconds(80);\n            //Assert.False(result.WaitForFinished(timeout80sec), \"WaitforFinished Timeout=\" + timeout80sec);\n            //// prevent silo from shutting down right away\n            //Thread.Sleep(Debugger.IsAttached ? TimeSpan.FromMinutes(2) : TimeSpan.FromSeconds(5));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ExternalTypesTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans' ability to handle types defined outside of the grain interface and implementation assemblies.\n    /// Verifies that the serialization system correctly handles external types (like enums) passed as parameters to grain methods.\n    /// </summary>\n    public class ExternalTypesTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public ExternalTypesTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests that grains can successfully receive and process enum types defined in external assemblies.\n        /// This validates Orleans' type system's ability to serialize/deserialize types not directly referenced\n        /// in the grain interface assembly, which is important for supporting shared domain models.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public async Task ExternalTypesTest_GrainWithEnumExternalTypeParam()\n        {\n            var grainWithEnumTypeParam = this.GrainFactory.GetGrain<IExternalTypeGrain>(0);\n            await grainWithEnumTypeParam.GetEnumModel();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/FSharpGrainTests.cs",
    "content": "using Microsoft.FSharp.Core;\nusing TestExtensions;\nusing UnitTests.FSharpTypes;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans' interoperability with F# types and grains.\n    /// Validates that Orleans can correctly serialize/deserialize F# constructs like records, options, and discriminated unions,\n    /// ensuring proper cross-language support within the .NET ecosystem.\n    /// </summary>\n    public class FSharpGrainTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public FSharpGrainTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        private async Task PingTest<T>(T input)\n        {\n            var id = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGeneric1Argument<T>>(id, \"UnitTests.Grains.Generic1ArgumentGrain\");\n            var output = await grain.Ping(input);\n            Assert.Equal(input, output);\n        }\n\n        /// <summary>\n        /// Tests basic generic grain functionality with primitive F# types.\n        /// Validates that generic grains can handle simple type parameters when called from C#.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\")]\n        public async Task FSharpGrains_Ping()\n        {\n            await PingTest<int>(1);\n        }\n\n        /// <summary>\n        /// Tests serialization of basic F# record types.\n        /// Validates that Orleans can properly serialize/deserialize F# records containing primitive values.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_Record_ofInt()\n        {\n            await PingTest<UnitTests.FSharpTypes.Record>(UnitTests.FSharpTypes.Record.ofInt(1));\n        }\n\n        /// <summary>\n        /// Tests F# record serialization without Orleans attributes.\n        /// This test demonstrates Orleans' ability to handle F# records even when they lack\n        /// explicit Serializable and Immutable attributes, validating attribute-free serialization.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_Record_ofIntOption_Some_WithNoAttributes()\n        {\n            await PingTest<RecordOfIntOptionWithNoAttributes>(RecordOfIntOptionWithNoAttributes.ofInt(1));\n        }\n\n        /// <summary>\n        /// Tests F# record serialization with explicit Orleans attributes.\n        /// Validates that F# records containing option types (Some case) can be properly serialized\n        /// when decorated with Serializable and Immutable attributes.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_Record_ofIntOption_Some()\n        {\n            await PingTest<RecordOfIntOption>(RecordOfIntOption.ofInt(1));\n        }\n\n        /// <summary>\n        /// Tests F# record serialization with None option values.\n        /// Validates Orleans' handling of F# option types in the None case, ensuring proper null handling.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_Record_ofIntOption_None()\n        {\n            await PingTest<RecordOfIntOption>(RecordOfIntOption.Empty);\n        }\n\n        /// <summary>\n        /// Tests serialization of generic F# record types.\n        /// Validates that Orleans can handle F# records with type parameters, testing the combination\n        /// of F# generics and Orleans' serialization system.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_GenericRecord_ofInt()\n        {\n            var input = GenericRecord<int>.ofT(0);\n            await PingTest<GenericRecord<int>>(input);\n        }\n\n        /// <summary>\n        /// Tests serialization of generic F# records containing option types (Some case).\n        /// This complex scenario validates Orleans' ability to handle nested F# type constructs:\n        /// generic records containing option types with values.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_GenericRecord_ofIntOption_Some()\n        {\n            var input = GenericRecord<FSharpOption<int>>.ofT(FSharpOption<int>.Some(0));\n            await PingTest<GenericRecord<FSharpOption<int>>>(input);\n        }\n\n        /// <summary>\n        /// Tests serialization of generic F# records containing option types (None case).\n        /// Validates proper handling of null values within generic F# record structures.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_GenericRecord_ofIntOption_None()\n        {\n            var input = GenericRecord<FSharpOption<int>>.ofT(FSharpOption<int>.None);\n            await PingTest<GenericRecord<FSharpOption<int>>>(input);\n        }\n\n        /// <summary>\n        /// Tests direct serialization of F# option types (Some case).\n        /// Validates that Orleans can handle F#'s built-in option type when it contains a value.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_IntOption_Some()\n        {\n            var input = FSharpOption<int>.Some(10);\n            await PingTest<FSharpOption<int>>(input);\n        }\n\n        /// <summary>\n        /// Tests direct serialization of F# option types (None case).\n        /// Validates that Orleans correctly handles F#'s None value, which represents the absence of a value.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Generics\"), TestCategory(\"FSharp\"), TestCategory(\"Serialization\")]\n        public async Task FSharpGrains_Ping_IntOption_None()\n        {\n            var input = FSharpOption<int>.None;\n            await PingTest<FSharpOption<int>>(input);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GenericGrainTests.cs",
    "content": "using System.Globalization;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing TestGrainInterfaces;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Comprehensive tests for Orleans' support of generic grains and interfaces.\n    /// Validates that Orleans can correctly handle grain classes and interfaces with type parameters,\n    /// including complex scenarios like multiple type parameters, inheritance hierarchies, type constraints,\n    /// and proper grain activation/routing based on generic type arguments.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Generics\")]\n    public class GenericGrainTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private static int grainId = 0;\n\n        public GenericGrainTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        public TGrainInterface GetGrain<TGrainInterface>(long i) where TGrainInterface : IGrainWithIntegerKey\n        {\n            return this.GrainFactory.GetGrain<TGrainInterface>(i);\n        }\n\n        public TGrainInterface GetGrain<TGrainInterface>() where TGrainInterface : IGrainWithIntegerKey\n        {\n            return this.GrainFactory.GetGrain<TGrainInterface>(GetRandomGrainId());\n        }\n\n        /// <summary>\n        /// Tests that Orleans can instantiate multiple concrete grain types implementing different\n        /// specializations of the same generic interface. Validates that type-specific grain\n        /// implementations are correctly resolved and activated based on generic type arguments.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceGetGrain()\n        {\n            var grainOfIntFloat1 = GetGrain<IGenericGrain<int, float>>();\n            var grainOfIntFloat2 = GetGrain<IGenericGrain<int, float>>();\n            var grainOfFloatString = GetGrain<IGenericGrain<float, string>>();\n\n            await grainOfIntFloat1.SetT(123);\n            await grainOfIntFloat2.SetT(456);\n            await grainOfFloatString.SetT(789.0f);\n\n            var floatResult1 = await grainOfIntFloat1.MapT2U();\n            var floatResult2 = await grainOfIntFloat2.MapT2U();\n            var stringResult = await grainOfFloatString.MapT2U();\n\n            Assert.Equal(123f, floatResult1);\n            Assert.Equal(456f, floatResult2);\n            Assert.Equal(\"789\", stringResult);\n        }\n\n        /// <summary>\n        /// Validates grain identity preservation: multiple GetGrain calls with the same ID\n        /// return references to the same grain activation. This ensures Orleans' single-activation\n        /// guarantee holds for generic grains.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceMultiplicity()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<IGenericGrain<int, float>>(grainId);\n            await grainRef1.SetT(123);\n\n            var grainRef2 = GetGrain<IGenericGrain<int, float>>(grainId);\n            var floatResult = await grainRef2.MapT2U();\n\n            Assert.Equal(123f, floatResult);\n        }\n\n        /// <summary>\n        /// Tests Orleans' ability to instantiate generic grain specializations with various type arguments.\n        /// Uses theory-based testing to validate that generic grains work correctly with different\n        /// primitive types (float, string), demonstrating type parameter flexibility.\n        /// </summary>\n        [Theory]\n        [InlineData(1.2f)]\n        [InlineData(3.4f)]\n        [InlineData(\"5.6\")]\n        public async Task GenericGrainTests_SimpleGenericGrainGetGrain<T>(T setValue)\n        {\n\n            var grain = GetGrain<ISimpleGenericGrain<T>>();\n\n            await grain.Set(setValue);\n\n            // generic grain implementation does not change the set value:\n            await grain.Transform();\n\n            T result = await grain.Get();\n\n            Assert.Equal(setValue, result);\n        }\n\n        /// <summary>\n        /// Tests generic grains with array type parameters.\n        /// Validates that Orleans can handle complex type arguments like arrays in generic grain interfaces.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_SimpleGenericGrainGetGrain_ArrayTypeParameter()\n        {\n            var grain = GetGrain<ISimpleGenericGrain<int[]>>();\n\n            var expected = new[] { 1, 2, 3 };\n            await grain.Set(expected);\n\n            // generic grain implementation does not change the set value:\n            await grain.Transform();\n\n            var result = await grain.Get();\n\n            Assert.Equal(expected, result);\n        }\n\n        /// <summary>\n        /// Tests generic grains that work with arrays through inheritance.\n        /// Validates Orleans' handling of generic grains that register and manage array-based state.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_GenericGrainInheritingArray()\n        {\n            var grain = GetGrain<IGenericArrayRegisterGrain<int>>();\n\n            var expected = new[] { 1, 2, 3 };\n            await grain.Set(expected);\n\n            var result = await grain.Get();\n\n            Assert.Equal(expected, result);\n        }\n\n        /// <summary>\n        /// Tests grains implementing generic interfaces with nested generic type parameters.\n        /// Validates Orleans' ability to handle complex generic scenarios like List<T> as a type argument.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_GenericInterfaceWithGenericParametersGetGrain()\n        {\n\n            var grain = GetGrain<ISimpleGenericGrain<List<float>>>();\n            var list = new List<float>();\n            list.Add(0.1f);\n            await grain.Set(list);\n\n            var result = await grain.Get();\n\n            Assert.Single(result);\n            Assert.Equal(0.1f, result[0]);\n        }\n\n\n        /// <summary>\n        /// Validates that multiple GetGrain calls for the same generic grain type and ID\n        /// return the same activation. Ensures Orleans' single-activation semantics apply to generic grains.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_SimpleGenericGrainMultiplicity()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<ISimpleGenericGrain<float>>(grainId);\n            await grainRef1.Set(1.2f);\n            await grainRef1.Transform();  // NOP for generic grain class\n\n            var grainRef2 = GetGrain<ISimpleGenericGrain<float>>(grainId);\n            var floatResult = await grainRef2.Get();\n\n            Assert.Equal(1.2f, floatResult);\n        }\n\n        /// <summary>\n        /// Tests Orleans' type resolution preference rules: when both a concrete implementation\n        /// and a generic implementation exist for a generic interface, Orleans should prefer\n        /// the more specific concrete implementation. This validates proper type matching precedence.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericInterface()\n        {\n            var grainOfDouble1 = GetGrain<ISimpleGenericGrain<double>>();\n            var grainOfDouble2 = GetGrain<ISimpleGenericGrain<double>>();\n\n            await grainOfDouble1.Set(1.0);\n            await grainOfDouble2.Set(2.0);\n\n            // concrete implementation (SpecializedSimpleGenericGrain) doubles the set value:\n            await grainOfDouble1.Transform();\n            await grainOfDouble2.Transform();\n\n            var result1 = await grainOfDouble1.Get();\n            var result2 = await grainOfDouble2.Get();\n\n            Assert.Equal(2.0, result1);\n            Assert.Equal(4.0, result2);\n        }\n\n        /// <summary>\n        /// Validates activation identity when Orleans prefers concrete implementations.\n        /// Ensures that the preference for concrete implementations doesn't break\n        /// the single-activation guarantee.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericInterfaceMultiplicity()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<ISimpleGenericGrain<double>>(grainId);\n            await grainRef1.Set(1.0);\n            await grainRef1.Transform();  // SpecializedSimpleGenericGrain doubles the value for generic grain class\n\n            // a second reference with the same id points to the same grain:\n            var grainRef2 = GetGrain<ISimpleGenericGrain<double>>(grainId);\n            await grainRef2.Transform();\n            var floatResult = await grainRef2.Get();\n\n            Assert.Equal(4.0f, floatResult);\n        }\n\n        /// <summary>\n        /// Tests grains implementing multiple generic interfaces.\n        /// Validates that Orleans correctly handles grains with complex interface hierarchies\n        /// involving multiple generic interfaces.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesGetGrain()\n        {\n            var grain1 = GetGrain<ISimpleGenericGrain<int>>();\n            var grain2 = GetGrain<ISimpleGenericGrain<int>>();\n\n            await grain1.Set(1);\n            await grain2.Set(2);\n\n            // ConcreteGrainWith2GenericInterfaces multiplies the set value by 10:\n            await grain1.Transform();\n            await grain2.Transform();\n\n            var result1 = await grain1.Get();\n            var result2 = await grain2.Get();\n\n            Assert.Equal(10, result1);\n            Assert.Equal(20, result2);\n        }\n\n        /// <summary>\n        /// Validates single-activation semantics for grains with multiple interfaces.\n        /// Tests that repeated GetGrain calls with the same interface return the same activation\n        /// even when the grain implements multiple interfaces.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMultiplicity1()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<ISimpleGenericGrain<int>>(grainId);\n            await grainRef1.Set(1);\n\n            // ConcreteGrainWith2GenericInterfaces multiplies the set value by 10:\n            await grainRef1.Transform();\n\n            //A second reference to the interface will point to the same grain\n            var grainRef2 = GetGrain<ISimpleGenericGrain<int>>(grainId);\n            await grainRef2.Transform();\n            var floatResult = await grainRef2.Get();\n\n            Assert.Equal(100, floatResult);\n        }\n\n        /// <summary>\n        /// Tests grain identity across different interface references.\n        /// Validates that accessing the same grain through different interfaces it implements\n        /// still references the same underlying activation, maintaining state consistency.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMultiplicity2()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<ISimpleGenericGrain<int>>(grainId);\n            await grainRef1.Set(1);\n            await grainRef1.Transform();  // ConcreteGrainWith2GenericInterfaces multiplies the set value by 10:\n\n            // A second reference to a different interface implemented by ConcreteGrainWith2GenericInterfaces\n            // will reference the same grain:\n            var grainRef2 = GetGrain<IGenericGrain<int, string>>(grainId);\n            // ConcreteGrainWith2GenericInterfaces returns a string representation of the current value multiplied by 10:\n            var floatResult = await grainRef2.MapT2U();\n\n            Assert.Equal(\"100\", floatResult);\n        }\n\n        /// <summary>\n        /// Tests that grains can use the grain factory to create references to other generic grains.\n        /// Validates that grain factory operations work correctly within grain code for generic types.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainTests_UseGenericFactoryInsideGrain()\n        {\n            var grainId = GetRandomGrainId();\n\n            var grainRef1 = GetGrain<ISimpleGenericGrain<string>>(grainId);\n            await grainRef1.Set(\"JustString\");\n            await grainRef1.CompareGrainReferences(grainRef1);\n        }\n\n\n        [Fact]\n        public async Task Generic_SimpleGrain_GetGrain()\n        {\n            var grain = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n            await grain.GetA();\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrainControlFlow()\n        {\n            var a = Random.Shared.Next(100);\n            var b = a + 1;\n            var expected = a + \"x\" + b;\n\n            var grain = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n\n            await grain.SetA(a);\n\n            await grain.SetB(b);\n\n            Task<string> stringPromise = grain.GetAxB();\n            Assert.Equal(expected, await stringPromise);\n        }\n\n        [Fact]\n        public void Generic_SimpleGrainControlFlow_Blocking()\n        {\n            var a = Random.Shared.Next(100);\n            var b = a + 1;\n            var expected = a + \"x\" + b;\n\n            var grain = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n\n            // explicitly use .Wait() and .Result to make sure the client does not deadlock in these cases.\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n            grain.SetA(a).Wait();\n\n            grain.SetB(b).Wait();\n\n            Task<string> stringPromise = grain.GetAxB();\n            Assert.Equal(expected, stringPromise.Result);\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrainDataFlow()\n        {\n            var a = Random.Shared.Next(100);\n            var b = a + 1;\n            var expected = a + \"x\" + b;\n\n            var grain = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n\n            var setAPromise = grain.SetA(a);\n            var setBPromise = grain.SetB(b);\n            var stringPromise = Task.WhenAll(setAPromise, setBPromise).ContinueWith((_) => grain.GetAxB()).Unwrap();\n\n            var x = await stringPromise;\n            Assert.Equal(expected, x);\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrain2_GetGrain()\n        {\n            var g1 = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n            var g2 = this.GrainFactory.GetGrain<ISimpleGenericGrainU<int>>(grainId++);\n            var g3 = this.GrainFactory.GetGrain<ISimpleGenericGrain2<int, int>>(grainId++);\n            await g1.GetA();\n            await g2.GetA();\n            await g3.GetA();\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrainGenericParameterWithMultipleArguments_GetGrain()\n        {\n            var g1 = this.GrainFactory.GetGrain<ISimpleGenericGrain1<Dictionary<int, int>>>(GetRandomGrainId());\n            await g1.GetA();\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrainControlFlow2_GetAB()\n        {\n            var a = Random.Shared.Next(100);\n            var b = a + 1;\n            var expected = a + \"x\" + b;\n\n            var g1 = this.GrainFactory.GetGrain<ISimpleGenericGrain1<int>>(grainId++);\n            var g2 = this.GrainFactory.GetGrain<ISimpleGenericGrainU<int>>(grainId++);\n            var g3 = this.GrainFactory.GetGrain<ISimpleGenericGrain2<int, int>>(grainId++);\n\n            string r1 = await g1.GetAxB(a, b);\n            string r2 = await g2.GetAxB(a, b);\n            string r3 = await g3.GetAxB(a, b);\n            Assert.Equal(expected, r1);\n            Assert.Equal(expected, r2);\n            Assert.Equal(expected, r3);\n        }\n\n        [Fact]\n        public async Task Generic_SimpleGrainControlFlow3()\n        {\n            ISimpleGenericGrain2<int, float> g = this.GrainFactory.GetGrain<ISimpleGenericGrain2<int, float>>(grainId++);\n            await g.SetA(3);\n            await g.SetB(1.25f);\n            Assert.Equal(\"3x1.25\", await g.GetAxB());\n        }\n\n        [Fact]\n        public async Task Generic_BasicGrainControlFlow()\n        {\n            IBasicGenericGrain<int, float> g = this.GrainFactory.GetGrain<IBasicGenericGrain<int, float>>(0);\n            await g.SetA(3);\n            await g.SetB(1.25f);\n            Assert.Equal(\"3x1.25\", await g.GetAxB());\n        }\n\n        [Fact]\n        public async Task GrainWithListFields()\n        {\n            string a = Random.Shared.Next(100).ToString(CultureInfo.InvariantCulture);\n            string b = Random.Shared.Next(100).ToString(CultureInfo.InvariantCulture);\n\n            var g1 = this.GrainFactory.GetGrain<IGrainWithListFields>(grainId++);\n\n            var p1 = g1.AddItem(a);\n            var p2 = g1.AddItem(b);\n            await Task.WhenAll(p1, p2);\n\n            var r1 = await g1.GetItems();\n\n            Assert.True(\n                (a == r1[0] && b == r1[1]) || (b == r1[0] && a == r1[1]), // Message ordering was not necessarily preserved.\n                string.Format(\"Result: r[0]={0}, r[1]={1}\", r1[0], r1[1]));\n        }\n\n        [Fact]\n        public async Task Generic_GrainWithListFields()\n        {\n            int a = Random.Shared.Next(100);\n            int b = Random.Shared.Next(100);\n\n\n            var g1 = this.GrainFactory.GetGrain<IGenericGrainWithListFields<int>>(grainId++);\n\n            var p1 = g1.AddItem(a);\n            var p2 = g1.AddItem(b);\n            await Task.WhenAll(p1, p2);\n\n            var r1 = await g1.GetItems();\n\n            Assert.True(\n                (a == r1[0] && b == r1[1]) || (b == r1[0] && a == r1[1]), // Message ordering was not necessarily preserved.\n                string.Format(\"Result: r[0]={0}, r[1]={1}\", r1[0], r1[1]));\n        }\n\n        [Fact]\n        public async Task Generic_GrainWithNoProperties_ControlFlow()\n        {\n            int a = Random.Shared.Next(100);\n            int b = Random.Shared.Next(100);\n            string expected = a + \"x\" + b;\n\n            var g1 = this.GrainFactory.GetGrain<IGenericGrainWithNoProperties<int>>(grainId++);\n\n            string r1 = await g1.GetAxB(a, b);\n            Assert.Equal(expected, r1);\n        }\n\n        [Fact]\n        public async Task GrainWithNoProperties_ControlFlow()\n        {\n            int a = Random.Shared.Next(100);\n            int b = Random.Shared.Next(100);\n            string expected = a + \"x\" + b;\n\n            long grainId = GetRandomGrainId();\n            var g1 = this.GrainFactory.GetGrain<IGrainWithNoProperties>(grainId);\n\n            string r1 = await g1.GetAxB(a, b);\n            Assert.Equal(expected, r1);\n        }\n\n        [Fact]\n        public async Task Generic_ReaderWriterGrain1()\n        {\n            int a = Random.Shared.Next(100);\n            var g = this.GrainFactory.GetGrain<IGenericReaderWriterGrain1<int>>(grainId++);\n            await g.SetValue(a);\n            var res = await g.GetValue();\n            Assert.Equal(a, res);\n        }\n\n        [Fact]\n        public async Task Generic_ReaderWriterGrain2()\n        {\n            int a = Random.Shared.Next(100);\n            string b = \"bbbbb\";\n\n            var g = this.GrainFactory.GetGrain<IGenericReaderWriterGrain2<int, string>>(grainId++);\n            await g.SetValue1(a);\n            await g.SetValue2(b);\n            var r1 = await g.GetValue1();\n            Assert.Equal(a, r1);\n            var r2 = await g.GetValue2();\n            Assert.Equal(b, r2);\n        }\n\n        [Fact]\n        public async Task Generic_ReaderWriterGrain3()\n        {\n            int a = Random.Shared.Next(100);\n            string b = \"bbbbb\";\n            double c = 3.145;\n\n            var g = this.GrainFactory.GetGrain<IGenericReaderWriterGrain3<int, string, double>>(grainId++);\n            await g.SetValue1(a);\n            await g.SetValue2(b);\n            await g.SetValue3(c);\n            var r1 = await g.GetValue1();\n            Assert.Equal(a, r1);\n            var r2 = await g.GetValue2();\n            Assert.Equal(b, r2);\n            var r3 = await g.GetValue3();\n            Assert.Equal(c, r3);\n        }\n\n        /// <summary>\n        /// Tests generic grains with non-primitive type arguments like Guid and byte arrays.\n        /// Validates that Orleans correctly differentiates grain activations based on complex\n        /// generic type arguments, ensuring proper type-based routing.\n        /// </summary>\n        [Fact]\n        public async Task Generic_Non_Primitive_Type_Argument()\n        {\n            IEchoHubGrain<Guid, string> g1 = this.GrainFactory.GetGrain<IEchoHubGrain<Guid, string>>(1);\n            IEchoHubGrain<Guid, int> g2 = this.GrainFactory.GetGrain<IEchoHubGrain<Guid, int>>(1);\n            IEchoHubGrain<Guid, byte[]> g3 = this.GrainFactory.GetGrain<IEchoHubGrain<Guid, byte[]>>(1);\n\n            Assert.NotEqual((GrainReference)g1, (GrainReference)g2);\n            Assert.NotEqual((GrainReference)g1, (GrainReference)g3);\n            Assert.NotEqual((GrainReference)g2, (GrainReference)g3);\n\n            await g1.Foo(Guid.Empty, \"\", 1);\n            await g2.Foo(Guid.Empty, 0, 2);\n            await g3.Foo(Guid.Empty, new byte[] { }, 3);\n\n            Assert.Equal(1, await g1.GetX());\n            Assert.Equal(2, await g2.GetX());\n            Assert.Equal(3m, await g3.GetX());\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_1()\n        {\n            const string msg1 = \"Hello from EchoGenericChainGrain-1\";\n\n            IEchoGenericChainGrain<string> g1 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g1.Echo(msg1);\n            Assert.Equal(msg1, received);\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_2()\n        {\n            const string msg2 = \"Hello from EchoGenericChainGrain-2\";\n\n            IEchoGenericChainGrain<string> g2 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g2.Echo2(msg2);\n            Assert.Equal(msg2, received);\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_3()\n        {\n            const string msg3 = \"Hello from EchoGenericChainGrain-3\";\n\n            IEchoGenericChainGrain<string> g3 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g3.Echo3(msg3);\n            Assert.Equal(msg3, received);\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_4()\n        {\n            const string msg4 = \"Hello from EchoGenericChainGrain-4\";\n\n            var g4 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g4.Echo4(msg4);\n            Assert.Equal(msg4, received);\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_5()\n        {\n            const string msg5 = \"Hello from EchoGenericChainGrain-5\";\n\n            var g5 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g5.Echo5(msg5);\n            Assert.Equal(msg5, received);\n        }\n\n        [Fact]\n        public async Task Generic_Echo_Chain_6()\n        {\n            const string msg6 = \"Hello from EchoGenericChainGrain-6\";\n\n            var g6 = this.GrainFactory.GetGrain<IEchoGenericChainGrain<string>>(GetRandomGrainId());\n\n            string received = await g6.Echo6(msg6);\n            Assert.Equal(msg6, received);\n        }\n\n\n        [Fact]\n        public async Task Generic_1Argument_GenericCallOnly()\n        {\n            var grain = this.GrainFactory.GetGrain<IGeneric1Argument<string>>(Guid.NewGuid(), \"UnitTests.Grains.Generic1ArgumentGrain\");\n            var s1 = Guid.NewGuid().ToString();\n            var s2 = await grain.Ping(s1);\n            Assert.Equal(s1, s2);\n        }\n\n        [Fact]\n        public void Generic_1Argument_NonGenericCallFirst()\n        {\n            Assert.Throws<ArgumentException>(() => this.GrainFactory.GetGrain<INonGenericBase>(Guid.NewGuid(), \"UnitTests.Grains.Generic1ArgumentGrain\"));\n        }\n\n        [Fact]\n        public async Task Generic_1Argument_GenericCallFirst()\n        {\n            var id = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGeneric1Argument<string>>(id, \"UnitTests.Grains.Generic1ArgumentGrain\");\n            var s1 = Guid.NewGuid().ToString();\n            var s2 = await grain.Ping(s1);\n            Assert.Equal(s1, s2);\n            Assert.Throws<ArgumentException>(() => this.GrainFactory.GetGrain<INonGenericBase>(id, \"UnitTests.Grains.Generic1ArgumentGrain\"));\n        }\n\n        /// <summary>\n        /// Validates that grains with different generic type arguments create independent activations.\n        /// This is crucial for ensuring that IDbGrain<int> and IDbGrain<string> are treated as\n        /// completely separate grain types with independent state.\n        /// </summary>\n        [Fact]\n        public async Task DifferentTypeArgsProduceIndependentActivations()\n        {\n            var grain1 = this.GrainFactory.GetGrain<IDbGrain<int>>(0);\n            await grain1.SetValue(123);\n\n            var grain2 = this.GrainFactory.GetGrain<IDbGrain<string>>(0);\n            var v = await grain2.GetValue();\n            Assert.Null(v);\n        }\n\n        /// <summary>\n        /// Tests generic grains making calls to themselves.\n        /// Validates that self-referential calls work correctly in generic grain contexts.\n        /// </summary>\n        [Fact, TestCategory(\"Echo\")]\n        public async Task Generic_PingSelf()\n        {\n            var id = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(id);\n            var s1 = Guid.NewGuid().ToString();\n            var s2 = await grain.PingSelf(s1);\n            Assert.Equal(s1, s2);\n        }\n\n        /// <summary>\n        /// Tests generic grains making calls to other generic grains of the same type.\n        /// Validates grain-to-grain communication for generic grain types.\n        /// </summary>\n        [Fact, TestCategory(\"Echo\")]\n        public async Task Generic_PingOther()\n        {\n            var id = Guid.NewGuid();\n            var targetId = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(id);\n            var target = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(targetId);\n            var s1 = Guid.NewGuid().ToString();\n            var s2 = await grain.PingOther(target, s1);\n            Assert.Equal(s1, s2);\n        }\n\n        /// <summary>\n        /// Tests complex call chains where a generic grain calls itself through another grain.\n        /// Validates that grain references remain valid when passed between generic grains.\n        /// </summary>\n        [Fact, TestCategory(\"Echo\")]\n        public async Task Generic_PingSelfThroughOther()\n        {\n            var id = Guid.NewGuid();\n            var targetId = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(id);\n            var target = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(targetId);\n            var s1 = Guid.NewGuid().ToString();\n            var s2 = await grain.PingSelfThroughOther(target, s1);\n            Assert.Equal(s1, s2);\n        }\n\n        /// <summary>\n        /// Tests scheduled operations and deactivation for generic grains.\n        /// Validates that Orleans' activation lifecycle management works correctly with generic grains,\n        /// including delayed operations and explicit deactivation.\n        /// </summary>\n        [Fact, TestCategory(\"ActivateDeactivate\")]\n        public async Task Generic_ScheduleDelayedPingAndDeactivate()\n        {\n            var id = Guid.NewGuid();\n            var targetId = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(id);\n            var target = this.GrainFactory.GetGrain<IGenericPingSelf<string>>(targetId);\n            var s1 = Guid.NewGuid().ToString();\n            await grain.ScheduleDelayedPingToSelfAndDeactivate(target, s1, TimeSpan.FromSeconds(5));\n            string s2 = null;\n            await TestingUtils.WaitUntilAsync(\n                async lastTry =>\n                {\n                    s2 = await grain.GetLastValue();\n                    if (s2 == s1)\n                    {\n                        return true;\n                    }\n\n                    if (lastTry)\n                    {\n                        Assert.Fail($\"Expected delayed ping to set value '{s1}', but saw '{s2 ?? \"null\"}'.\");\n                    }\n\n                    return false;\n                },\n                timeout: TimeSpan.FromSeconds(30),\n                delayOnFail: TimeSpan.FromMilliseconds(200));\n            Assert.Equal(s1, s2);\n        }\n\n        /// <summary>\n        /// Tests serialization of generic grains with circular references in their state.\n        /// Validates that Orleans' serialization system can handle complex object graphs\n        /// in generic grain contexts without infinite loops.\n        /// </summary>\n        [Fact, TestCategory(\"Serialization\")]\n        public async Task SerializationTests_Generic_CircularReferenceTest()\n        {\n            var grainId = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<ICircularStateTestGrain>(primaryKey: grainId, keyExtension: grainId.ToString(\"N\"));\n            _ = await grain.GetState();\n        }\n\n        /// <summary>\n        /// Tests generic grains with type constraints (where T : class, new(), etc.).\n        /// Validates that Orleans correctly enforces and works with C# generic type constraints,\n        /// including unmanaged constraints and reference type constraints.\n        /// </summary>\n        [Fact]\n        public async Task Generic_GrainWithTypeConstraints()\n        {\n            var grainId = Guid.NewGuid().ToString();\n            var grain = this.GrainFactory.GetGrain<IGenericGrainWithConstraints<List<int>, int, string>>(grainId);\n            var result = await grain.GetCount();\n            Assert.Equal(0, result);\n            await grain.Add(42);\n            result = await grain.GetCount();\n            Assert.Equal(1, result);\n\n            var unmanagedGrain = this.GrainFactory.GetGrain<IUnmanagedArgGrain<DateTime>>(Guid.NewGuid());\n            {\n                var echoInput = DateTime.UtcNow;\n                var echoOutput = await unmanagedGrain.Echo(echoInput);\n                Assert.Equal(echoInput, echoOutput);\n                echoOutput = await unmanagedGrain.EchoValue(echoInput);\n                Assert.Equal(echoInput, echoOutput);\n            }\n            {\n                var echoInput = \"hello\";\n                var echoOutput = await unmanagedGrain.EchoNonNullable(echoInput);\n                Assert.Equal(echoInput, echoOutput);\n                echoOutput = await unmanagedGrain.EchoReference(echoInput);\n                Assert.Equal(echoInput, echoOutput);\n            }\n        }\n\n        /// <summary>\n        /// Tests generic grains with value type state persistence.\n        /// Validates that Orleans' persistence system correctly handles value types (structs)\n        /// as grain state in generic grain contexts.\n        /// </summary>\n        [Fact, TestCategory(\"Persistence\")]\n        public async Task Generic_GrainWithValueTypeState()\n        {\n            Guid id = Guid.NewGuid();\n            var grain = this.GrainFactory.GetGrain<IValueTypeTestGrain>(id);\n\n            var initial = await grain.GetStateData();\n            Assert.Equal(new ValueTypeTestData(0), initial);\n\n            var expectedValue = new ValueTypeTestData(42);\n\n            await grain.SetStateData(expectedValue);\n\n            Assert.Equal(expectedValue, await grain.GetStateData());\n        }\n\n        /// <summary>\n        /// Tests casting non-generic grain references to generic interfaces after activation.\n        /// Validates Orleans' support for late-bound interface discovery on already-activated grains.\n        /// </summary>\n        [Fact, TestCategory(\"Cast\")]\n        public async Task Generic_CastToGenericInterfaceAfterActivation()\n        {\n            var grain = this.GrainFactory.GetGrain<INonGenericCastableGrain>(Guid.NewGuid());\n            await grain.DoSomething(); //activates original grain type here\n\n            var castRef = grain.AsReference<ISomeGenericGrain<string>>();\n\n            var result = await castRef.Hello();\n\n            Assert.Equal(\"Hello!\", result);\n        }\n\n        /// <summary>\n        /// Tests casting to generic interfaces with different type arguments before activation.\n        /// Validates that Orleans can handle interface casts that involve different generic\n        /// type specializations before the grain is activated.\n        /// </summary>\n        [Fact, TestCategory(\"Cast\")]\n        public async Task Generic_CastToDifferentlyConcretizedGenericInterfaceBeforeActivation()\n        {\n            var grain = this.GrainFactory.GetGrain<INonGenericCastableGrain>(Guid.NewGuid());\n\n            var castRef = grain.AsReference<IIndependentlyConcretizedGenericGrain<string>>();\n\n            var result = await castRef.Hello();\n\n            Assert.Equal(\"Hello!\", result);\n        }\n\n        /// <summary>\n        /// Tests casting between independently concretized generic interfaces.\n        /// Validates Orleans' ability to handle complex interface hierarchies where interfaces\n        /// are specialized independently of the grain's generic parameters.\n        /// </summary>\n        [Fact, TestCategory(\"Cast\")]\n        public async Task Generic_CastToDifferentlyConcretizedInterfaceBeforeActivation()\n        {\n            var grain = this.GrainFactory.GetGrain<INonGenericCastableGrain>(Guid.NewGuid());\n\n            var castRef = grain.AsReference<IIndependentlyConcretizedGrain>();\n\n            var result = await castRef.Hello();\n\n            Assert.Equal(\"Hello!\", result);\n        }\n\n        /// <summary>\n        /// Tests casting from generic to non-generic interfaces.\n        /// Validates that Orleans supports interface casts that cross the generic/non-generic boundary.\n        /// </summary>\n        [Fact, TestCategory(\"Cast\")]\n        public async Task Generic_CastGenericInterfaceToNonGenericInterfaceBeforeActivation()\n        {\n            var grain = this.GrainFactory.GetGrain<IGenericCastableGrain<string>>(Guid.NewGuid());\n\n            var castRef = grain.AsReference<INonGenericCastGrain>();\n\n            var result = await castRef.Hello();\n\n            Assert.Equal(\"Hello!\", result);\n        }\n\n        /// <summary>\n        /// Tests that generic grains can have generic state with different type parameters.\n        /// Validates that the type parameters for Grain<TState> don't need to match the grain's\n        /// own type parameters, allowing flexible state modeling in generic grain implementations.\n        /// </summary>\n        [Fact]\n        public async Task GenericGrainStateParameterMismatchTest()\n        {\n            var grain = this.GrainFactory.GetGrain<IGenericGrainWithGenericState<int, List<Guid>, string>>(Guid.NewGuid());\n            var result = await grain.GetStateType();\n            Assert.Equal(typeof(List<Guid>), result);\n        }\n    }\n\n    namespace Generic.EdgeCases\n    {\n        using UnitTests.GrainInterfaces.Generic.EdgeCases;\n        using UnitTests.Grains.Generic.EdgeCases;\n\n        /// <summary>\n        /// Tests for edge cases in Orleans' generic grain type system.\n        /// Validates complex scenarios including partial type specialization, repeated type parameters,\n        /// rearranged generic arguments, type parameter constraints in inheritance hierarchies,\n        /// and advanced type inference scenarios that push the boundaries of the generic type resolver.\n        /// </summary>\n        [TestCategory(\"BVT\"), TestCategory(\"Generics\")]\n        public class GenericEdgeCaseTests : HostedTestClusterEnsureDefaultStarted\n        {\n            public GenericEdgeCaseTests(DefaultClusterFixture fixture) : base(fixture)\n            {\n            }\n\n            private static async Task<Type[]> GetConcreteGenArgs(IBasicGrain @this)\n            {\n                var genArgTypeNames = await @this.ConcreteGenArgTypeNames();\n                return genArgTypeNames.Select(Type.GetType).ToArray();\n            }\n\n            /// <summary>\n            /// Tests partial specialization of generic grain types.\n            /// Validates Orleans' ability to handle grains that partially specify generic parameters,\n            /// leaving some to be inferred from the interface implementation.\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_PartiallySpecifyingGenericGrainFulfilsInterface()\n            {\n                var grain = this.GrainFactory.GetGrain<IGrainWithTwoGenArgs<string, int>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) }));\n            }\n\n            /// <summary>\n            /// Tests grains that reuse the same generic parameter multiple times.\n            /// Validates handling of scenarios where a single type parameter appears\n            /// multiple times in the grain's interface hierarchy.\n            /// Note: Currently unsupported - fails with too many generic arguments.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_GenericGrainCanReuseOwnGenArgRepeatedly()\n            {\n                // Resolves correctly but can't be activated: too many gen args supplied for concrete class\n                var grain = this.GrainFactory.GetGrain<IGrainReceivingRepeatedGenArgs<int, int>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) }));\n            }\n\n            /// <summary>\n            /// Tests casting with partially specified generic interfaces.\n            /// Validates that interfaces with partial generic specialization can be\n            /// cast to their fully specified counterparts.\n            /// </summary>\n            [Fact]\n            public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable()\n            {\n                var grain = this.GrainFactory.GetGrain<IPartiallySpecifyingInterface<string>>(Guid.NewGuid());\n                await grain.Hello();\n                var castRef = grain.AsReference<IGrainWithTwoGenArgs<string, int>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests casting with partial generic specialization before activation.\n            /// Validates that the casting mechanism works correctly even when the grain\n            /// hasn't been activated yet.\n            /// </summary>\n            [Fact]\n            public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable_Activating()\n            {\n                var grain = this.GrainFactory.GetGrain<IPartiallySpecifyingInterface<string>>(Guid.NewGuid());\n                var castRef = grain.AsReference<IGrainWithTwoGenArgs<string, int>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n\n            /// <summary>\n            /// Tests resolution of generic arguments that are both repeated and rearranged.\n            /// Validates complex type parameter mapping where arguments appear multiple times\n            /// in different positions.\n            /// Note: Currently unsupported - type inference fails.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_RepeatedRearrangedGenArgsResolved()\n            {\n                // Again resolves to the correct generic type definition, but fails on activation as too many args\n                // gen args aren't being properly inferred from matched concrete type\n                var grain = this.GrainFactory.GetGrain<IReceivingRepeatedGenArgsAmongstOthers<int, string, int>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(string), typeof(int) }));\n            }\n\n            /// <summary>\n            /// Tests type resolution with repeated generic arguments across interfaces.\n            /// Validates that Orleans correctly handles scenarios where the same type parameter\n            /// is used multiple times across different interfaces in the hierarchy.\n            /// </summary>\n            [Fact]\n            public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInTypeResolution()\n            {\n                var grain = this.GrainFactory.GetGrain<IReceivingRepeatedGenArgsFromOtherInterface<bool, bool, bool>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(Enumerable.Empty<Type>()));\n            }\n\n            /// <summary>\n            /// Tests casting between interfaces with repeated generic arguments.\n            /// Validates that grains can be cast between interfaces that use the same\n            /// type parameter multiple times in their definitions.\n            /// </summary>\n            [Fact]\n            public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting()\n            {\n                var grain = this.GrainFactory.GetGrain<IReceivingRepeatedGenArgsFromOtherInterface<bool, bool, bool>>(Guid.NewGuid());\n                await grain.Hello();\n                var castRef = grain.AsReference<ISpecifyingGenArgsRepeatedlyToParentInterface<bool>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests casting with repeated generic arguments before activation.\n            /// Validates pre-activation casting behavior for complex generic hierarchies\n            /// with repeated type parameters.\n            /// </summary>\n            [Fact]\n            public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting_Activating()\n            {\n                var grain = this.GrainFactory.GetGrain<IReceivingRepeatedGenArgsFromOtherInterface<bool, bool, bool>>(Guid.NewGuid());\n                var castRef = grain.AsReference<ISpecifyingGenArgsRepeatedlyToParentInterface<bool>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests resolution of rearranged generic arguments.\n            /// Validates that Orleans can handle interfaces where generic parameters\n            /// appear in different orders than in the grain implementation.\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_RearrangedGenArgsOfCorrectArityAreResolved()\n            {\n                var grain = this.GrainFactory.GetGrain<IReceivingRearrangedGenArgs<int, long>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(long), typeof(int) }));\n            }\n\n            /// <summary>\n            /// Tests casting between interfaces with rearranged generic arguments.\n            /// Validates that casting works when generic parameters are in different\n            /// positions but the total count matches.\n            /// </summary>\n            [Fact]\n            public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable()\n            {\n                var grain = this.GrainFactory.GetGrain<ISpecifyingRearrangedGenArgsToParentInterface<int, long>>(Guid.NewGuid());\n                await grain.Hello();\n                var castRef = grain.AsReference<IReceivingRearrangedGenArgsViaCast<long, int>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests pre-activation casting with rearranged generic arguments.\n            /// Validates that parameter rearrangement doesn't break casting before\n            /// the grain is activated.\n            /// </summary>\n            [Fact]\n            public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable_Activating()\n            {\n                var grain = this.GrainFactory.GetGrain<ISpecifyingRearrangedGenArgsToParentInterface<int, long>>(Guid.NewGuid());\n                var castRef = grain.AsReference<IReceivingRearrangedGenArgsViaCast<long, int>>();\n                var response = await castRef.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            public interface IFullySpecifiedGenericInterface<T> : IBasicGrain\n            { }\n\n            public interface IDerivedFromMultipleSpecializationsOfSameInterface : IFullySpecifiedGenericInterface<int>, IFullySpecifiedGenericInterface<long>\n            { }\n\n            public class GrainFulfillingMultipleSpecializationsOfSameInterfaceViaIntermediate : BasicGrain, IDerivedFromMultipleSpecializationsOfSameInterface\n            { }\n\n            /// <summary>\n            /// Tests casting between multiple specializations of the same generic interface.\n            /// Validates that a grain implementing multiple concrete versions of a generic\n            /// interface can be cast between those specializations.\n            /// </summary>\n            [Fact]\n            public async Task CastingBetweenFullySpecifiedGenericInterfaces()\n            {\n                var grain = this.GrainFactory.GetGrain<IDerivedFromMultipleSpecializationsOfSameInterface>(Guid.NewGuid());\n                await grain.Hello();\n                var castRef = grain.AsReference<IFullySpecifiedGenericInterface<int>>();\n                await castRef.Hello();\n                var castRef2 = castRef.AsReference<IFullySpecifiedGenericInterface<long>>();\n                await castRef2.Hello();\n            }\n\n            /// <summary>\n            /// Tests casting to interfaces with unrelated generic parameters.\n            /// Validates that grains can be cast to interfaces whose generic parameters\n            /// have no relationship to the grain's concrete type arguments.\n            /// </summary>\n            [Fact]\n            public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs()\n            {\n                var grain = this.GrainFactory.GetGrain<IArbitraryInterface<int, long>>(Guid.NewGuid());\n                await grain.Hello();\n                _ = grain.AsReference<IInterfaceUnrelatedToConcreteGenArgs<float>>();\n                var response = await grain.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n\n            /// <summary>\n            /// Tests pre-activation casting to unrelated generic interfaces.\n            /// Validates that casting to interfaces with independent generic parameters\n            /// works before grain activation.\n            /// </summary>\n            [Fact]\n            public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs_Activating()\n            {\n                var grain = this.GrainFactory.GetGrain<IArbitraryInterface<int, long>>(Guid.NewGuid());\n                _ = grain.AsReference<IInterfaceUnrelatedToConcreteGenArgs<float>>();\n                var response = await grain.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests further specialization of already-generic type arguments.\n            /// Validates handling of nested generics like List<T> where T itself is\n            /// a type parameter to be resolved.\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_GenArgsCanBeFurtherSpecialized()\n            {\n                var grain = this.GrainFactory.GetGrain<IInterfaceTakingFurtherSpecializedGenArg<List<int>>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) }));\n            }\n\n            /// <summary>\n            /// Tests specialization of generic parameters into array types.\n            /// Validates that Orleans can handle scenarios where generic parameters\n            /// are specialized as array types (T[]).\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_GenArgsCanBeFurtherSpecializedIntoArrays()\n            {\n                var grain = this.GrainFactory.GetGrain<IInterfaceTakingFurtherSpecializedGenArg<long[]>>(Guid.NewGuid());\n                var concreteGenArgs = await GetConcreteGenArgs(grain);\n                Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(long) }));\n            }\n\n            /// <summary>\n            /// Tests casting between interfaces with nested generic specializations.\n            /// Validates casting when interfaces use complex generic types like List<T>\n            /// with different but compatible specializations.\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs()\n            {\n                var grain = this.GrainFactory.GetGrain<IAnotherReceivingFurtherSpecializedGenArg<List<int>>>(Guid.NewGuid());\n                await grain.Hello();\n                _ = grain.AsReference<IYetOneMoreReceivingFurtherSpecializedGenArg<int[]>>();\n                var response = await grain.Hello();\n                Assert.Equal(\"Hello!\", response);\n            }\n\n            /// <summary>\n            /// Tests pre-activation casting with nested generic specializations.\n            /// Validates that complex generic casting scenarios work before grain activation.\n            /// Note: Currently unsupported feature.\n            /// </summary>\n            [Fact(Skip = \"Currently unsupported\")]\n            public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs_Activating()\n            {\n                var grain = this.GrainFactory.GetGrain<IAnotherReceivingFurtherSpecializedGenArg<List<int>>>(Guid.NewGuid());\n                _ = grain.AsReference<IYetOneMoreReceivingFurtherSpecializedGenArg<int[]>>();\n\n                var response = await grain.Hello();\n\n                Assert.Equal(\"Hello!\", response);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GrainActivateDeactivateTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.ActivationsLifeCycleTests\n{\n    /// <summary>\n    /// Tests for Orleans grain activation and deactivation lifecycle.\n    /// Validates that grains properly execute OnActivateAsync and OnDeactivateAsync methods,\n    /// handle activation failures, support reactivation after deactivation, and manage\n    /// complex scenarios like deactivation during activation or with long-running operations.\n    /// </summary>\n    public class GrainActivateDeactivateTests : HostedTestClusterEnsureDefaultStarted, IDisposable\n    {\n        private readonly IActivateDeactivateWatcherGrain watcher;\n\n        public GrainActivateDeactivateTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n            watcher = this.GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(0);\n            watcher.Clear().Wait();\n        }\n\n        public virtual void Dispose()\n        {\n            watcher.Clear().Wait();\n        }\n\n        /// <summary>\n        /// Tests basic grain reference creation for the watcher grain.\n        /// Validates that the test infrastructure's watcher grain can be properly instantiated.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"GetGrain\")]\n        public async Task WatcherGrain_GetGrain()\n        {\n            IActivateDeactivateWatcherGrain grain = this.GrainFactory.GetGrain<IActivateDeactivateWatcherGrain>(1);\n            await grain.Clear();\n        }\n\n        /// <summary>\n        /// Tests basic grain activation lifecycle.\n        /// Validates that OnActivateAsync is called exactly once when a grain is first accessed.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Activate_Simple()\n        {\n            int id = Random.Shared.Next();\n            ISimpleActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ISimpleActivateDeactivateTestGrain>(id);\n\n            string activation = await grain.DoSomething();\n\n            await CheckNumActivateDeactivateCalls(1, 0, activation, \"After activation\");\n        }\n\n        /// <summary>\n        /// Tests basic grain deactivation lifecycle.\n        /// Validates that OnDeactivateAsync is called when a grain is explicitly deactivated,\n        /// and that both activation and deactivation hooks are called exactly once.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Deactivate_Simple()\n        {\n            int id = Random.Shared.Next();\n            ISimpleActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ISimpleActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation, \"After deactivation\");\n        }\n\n        /// <summary>\n        /// Tests grain reactivation after deactivation.\n        /// Validates that a new activation is created when accessing a deactivated grain,\n        /// with OnActivateAsync called again for the new activation.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Reactivate_Simple()\n        {\n            int id = Random.Shared.Next();\n            ISimpleActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ISimpleActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation, \"After deactivation\");\n\n            // Reactivate\n            string activation2 = await grain.DoSomething();\n\n            Assert.NotEqual(activation, activation2); // New activation created after re-activate\n            await CheckNumActivateDeactivateCalls(2, 1, new[] { activation, activation2 }, \"After reactivation\");\n        }\n\n        /// <summary>\n        /// Tests activation with tail call optimization patterns.\n        /// Validates that grains using tail calls in their activation logic properly execute OnActivateAsync.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Activate_TailCall()\n        {\n            int id = Random.Shared.Next();\n            ITailCallActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ITailCallActivateDeactivateTestGrain>(id);\n\n            string activation = await grain.DoSomething();\n\n            await CheckNumActivateDeactivateCalls(1, 0, activation, \"After activation\");\n        }\n\n        /// <summary>\n        /// Tests deactivation with tail call optimization patterns.\n        /// Validates proper lifecycle management for grains using tail call patterns.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Deactivate_TailCall()\n        {\n            int id = Random.Shared.Next();\n            ITailCallActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ITailCallActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation, \"After deactivation\");\n        }\n\n        /// <summary>\n        /// Tests reactivation for grains using tail call patterns.\n        /// Validates that tail call grains can be properly deactivated and reactivated.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Reactivate_TailCall()\n        {\n            int id = Random.Shared.Next();\n            ITailCallActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ITailCallActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation, \"After deactivation\");\n\n            // Reactivate\n            string activation2 = await grain.DoSomething();\n\n            Assert.NotEqual(activation, activation2); // New activation created after re-activate\n            await CheckNumActivateDeactivateCalls(2, 1, new[] { activation, activation2 }, \"After reactivation\");\n        }\n\n        /// <summary>\n        /// Tests deactivation of grains with long-running operations.\n        /// Validates that grains with reentrant long-running tasks can be properly deactivated\n        /// and that a new activation is created on subsequent access.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\"), TestCategory(\"Reentrancy\")]\n        public async Task LongRunning_Deactivate()\n        {\n            int id = Random.Shared.Next();\n            ILongRunningActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ILongRunningActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n\n            await CheckNumActivateDeactivateCalls(1, 0, activation, \"Before deactivation\");\n\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation, \"After deactivation\");\n\n            // Reactivate\n            string activation2 = await grain.DoSomething();\n\n            Assert.NotEqual(activation, activation2); // New activation created after re-activate;\n\n            await CheckNumActivateDeactivateCalls(2, 1, new[] { activation, activation2 }, \"After reactivation\");\n        }\n\n        /// <summary>\n        /// Tests handling of exceptions thrown during grain activation.\n        /// Validates that exceptions in OnActivateAsync are properly propagated to the caller\n        /// and that the grain fails to activate.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task BadActivate_Await()\n        {\n            try\n            {\n                int id = Random.Shared.Next();\n                IBadActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<IBadActivateDeactivateTestGrain>(id);\n\n                await grain.ThrowSomething();\n\n                Assert.Fail(\"Expected ThrowSomething call to fail as unable to Activate grain\");\n            }\n            catch (ApplicationException exc)\n            {\n                Assert.Contains(\"Application-OnActivateAsync\", exc.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that grain methods fail when activation throws an exception.\n        /// Validates that all grain method calls fail appropriately when OnActivateAsync fails.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task BadActivate_GetValue()\n        {\n            try\n            {\n                int id = Random.Shared.Next();\n                IBadActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<IBadActivateDeactivateTestGrain>(id);\n\n                long key = await grain.GetKey();\n\n                Assert.Fail(\"Expected ThrowSomething call to fail as unable to Activate grain, but returned \" + key);\n            }\n            catch (ApplicationException exc)\n            {\n                Assert.Contains(\"Application-OnActivateAsync\", exc.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests activation failure propagation through grain-to-grain calls.\n        /// Validates that activation exceptions are properly propagated when a grain\n        /// is activated indirectly through another grain's method call.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task BadActivate_Await_ViaOtherGrain()\n        {\n            try\n            {\n                int id = Random.Shared.Next();\n                ICreateGrainReferenceTestGrain grain = this.GrainFactory.GetGrain<ICreateGrainReferenceTestGrain>(id);\n\n                await grain.ForwardCall(this.GrainFactory.GetGrain<IBadActivateDeactivateTestGrain>(id));\n\n                Assert.Fail(\"Expected ThrowSomething call to fail as unable to Activate grain\");\n            }\n            catch (ApplicationException exc)\n            {\n                Assert.Contains(\"Application-OnActivateAsync\", exc.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests handling of exceptions thrown in grain constructors.\n        /// Validates that constructor failures are properly handled and don't result in\n        /// invalid operation exceptions, ensuring clean failure semantics.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Constructor_Bad_Await()\n        {\n            try\n            {\n                int id = Random.Shared.Next();\n                IBadConstructorTestGrain grain = this.GrainFactory.GetGrain<IBadConstructorTestGrain>(id);\n\n                await grain.DoSomething();\n\n                Assert.Fail(\"Expected ThrowSomething call to fail as unable to Activate grain\");\n            }\n            catch (TimeoutException te)\n            {\n                Console.WriteLine(\"Received timeout: \" + te);\n                throw; // Fail test\n            }\n            catch (Exception exc)\n            {\n                AssertIsNotInvalidOperationException(exc, \"Constructor\");\n            }\n        }\n\n        /// <summary>\n        /// Tests that grains can create grain references in their constructors.\n        /// Validates that grain reference creation is allowed during grain construction phase.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task Constructor_CreateGrainReference()\n        {\n            int id = Random.Shared.Next();\n            ICreateGrainReferenceTestGrain grain = this.GrainFactory.GetGrain<ICreateGrainReferenceTestGrain>(id);\n\n            string activation = await grain.DoSomething();\n            Assert.NotNull(activation);\n        }\n\n        /// <summary>\n        /// Tests deactivation of grains using Task-based activation patterns.\n        /// Validates proper lifecycle management for grains with Task Action activation logic.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task TaskAction_Deactivate()\n        {\n            int id = Random.Shared.Next();\n            ITaskActionActivateDeactivateTestGrain grain = this.GrainFactory.GetGrain<ITaskActionActivateDeactivateTestGrain>(id);\n\n            // Activate\n            string activation = await grain.DoSomething();\n\n            // Deactivate\n            await grain.DoDeactivate();\n            Thread.Sleep(TimeSpan.FromSeconds(2)); // Allow some time for deactivate to happen\n\n            await CheckNumActivateDeactivateCalls(1, 1, activation.ToString());\n        }\n\n        /// <summary>\n        /// Tests the scenario where a grain attempts to deactivate during activation.\n        /// Validates that Orleans properly handles and rejects this invalid state transition,\n        /// preventing race conditions in the activation lifecycle.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivateDeactivate\")]\n        public async Task DeactivateOnIdleWhileActivate()\n        {\n            int id = Random.Shared.Next();\n            IDeactivatingWhileActivatingTestGrain grain = this.GrainFactory.GetGrain<IDeactivatingWhileActivatingTestGrain>(id);\n\n            try\n            {\n                string activation = await grain.DoSomething();\n                Assert.Fail(\"Should have thrown.\");\n            }\n            catch (OrleansMessageRejectionException exc)\n            {\n                this.Logger.LogInformation(exc, \"Thrown as expected\");\n                Assert.True(\n                    exc.Message.Contains(\"Forwarding failed\"),\n                    \"Did not get expected exception message returned: \" + exc.Message);\n            }  \n        }\n\n        private async Task CheckNumActivateDeactivateCalls(\n            int expectedActivateCalls,\n            int expectedDeactivateCalls,\n            string forActivation,\n            string when = null)\n        {\n            await CheckNumActivateDeactivateCalls(\n                expectedActivateCalls,\n                expectedDeactivateCalls,\n                new string[] { forActivation },\n                when )\n            ;\n        }\n\n        private async Task CheckNumActivateDeactivateCalls(\n            int expectedActivateCalls, \n            int expectedDeactivateCalls,\n            string[] forActivations,\n            string when = null)\n        {\n            string[] activateCalls = await watcher.GetActivateCalls();\n            Assert.Equal(expectedActivateCalls, activateCalls.Length);\n\n            string[] deactivateCalls = await watcher.GetDeactivateCalls();\n            Assert.Equal(expectedDeactivateCalls, deactivateCalls.Length);\n\n            for (int i = 0; i < expectedActivateCalls; i++)\n            {\n                Assert.Equal(forActivations[i], activateCalls[i]);\n            }\n\n            for (int i = 0; i < expectedDeactivateCalls; i++)\n            {\n                Assert.Equal(forActivations[i], deactivateCalls[i]);\n            }\n        }\n\n        private static void AssertIsNotInvalidOperationException(Exception thrownException, string expectedMessageSubstring)\n        {\n            Console.WriteLine(\"Received exception: \" + thrownException);\n            Exception e = thrownException.GetBaseException();\n            Console.WriteLine(\"Nested exception type: \" + e.GetType().FullName);\n            Console.WriteLine(\"Nested exception message: \" + e.Message);\n\n            Assert.IsAssignableFrom<Exception>(e);\n            Assert.False(e is InvalidOperationException);\n            Assert.True(e.Message.Contains(expectedMessageSubstring), \"Did not get expected exception message returned: \" + e.Message);\n\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GrainFactoryTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests for Orleans' grain factory and grain type resolution mechanisms.\n    /// Validates how the grain factory resolves grain implementations from interfaces,\n    /// handles ambiguous type mappings, supports grain class prefixes and full names,\n    /// and manages inheritance hierarchies in grain type resolution.\n    /// </summary>\n    public class GrainFactoryTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public GrainFactoryTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests that ambiguous grain type resolution throws an exception.\n        /// When multiple grain implementations exist for an interface without explicit resolution,\n        /// Orleans should throw an ArgumentException to prevent undefined behavior.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public void GetGrain_Ambiguous()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId());\n            });\n        }\n\n        /// <summary>\n        /// Tests grain resolution when a default implementation is specified.\n        /// Validates that Orleans correctly uses the default grain implementation\n        /// when multiple implementations exist but one is marked as default.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_Ambiguous_WithDefault()\n        {\n            var g = this.GrainFactory.GetGrain<IBase4>(GetRandomGrainId());\n            Assert.False(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests grain resolution using fully qualified type names.\n        /// Validates that specifying the full grain class name correctly resolves\n        /// to the intended implementation when ambiguity exists.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_WithFullName()\n        {\n            var grainFullName = typeof(BaseGrain).FullName;\n            var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId(), grainFullName);\n            Assert.True(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests grain resolution using grain class name prefixes.\n        /// Validates that Orleans can resolve grains using partial type names (prefixes)\n        /// as a convenience feature for grain identification.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_WithPrefix()\n        {\n            var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId(), BaseGrain.GrainPrefix);\n            Assert.True(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests that ambiguous grain prefixes throw an exception.\n        /// When a prefix matches multiple grain implementations, Orleans should\n        /// throw an ArgumentException to prevent ambiguous resolution.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public void GetGrain_AmbiguousPrefix()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId(), \"UnitTests.Grains\");\n            });\n        }\n\n        /// <summary>\n        /// Tests that non-existent grain prefixes throw an exception.\n        /// Validates proper error handling when attempting to resolve grains\n        /// with prefixes that don't match any registered implementations.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public void GetGrain_WrongPrefix()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId(), \"Foo\");\n            });\n        }\n\n        /// <summary>\n        /// Tests grain resolution for derived grain interfaces without prefixes.\n        /// Validates that Orleans correctly resolves grain implementations that\n        /// implement derived interfaces in inheritance hierarchies.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_Derived_NoPrefix()\n        {\n            var g = this.GrainFactory.GetGrain<IDerivedFromBase>(GetRandomGrainId());\n            Assert.False(await g.Foo());\n            Assert.True(await g.Bar());\n        }\n\n        /// <summary>\n        /// Tests grain resolution for derived grains using full type names.\n        /// Validates explicit resolution of derived grain implementations\n        /// when specified by their complete type name.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_Derived_WithFullName()\n        {\n            var grainFullName = typeof(DerivedFromBaseGrain).FullName;\n            var g = this.GrainFactory.GetGrain<IDerivedFromBase>(GetRandomGrainId(), grainFullName);\n            Assert.False(await g.Foo());\n            Assert.True(await g.Bar());\n        }\n\n        /// <summary>\n        /// Tests accessing derived grain implementations through base interfaces.\n        /// Validates that a derived grain can be accessed through its base interface\n        /// when explicitly specified by full name, supporting polymorphic grain usage.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_Derived_WithFullName_FromBase()\n        {\n            var grainFullName = typeof(DerivedFromBaseGrain).FullName;\n            var g = this.GrainFactory.GetGrain<IBase>(GetRandomGrainId(), grainFullName);\n            Assert.False(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests grain resolution for derived grains using prefixes.\n        /// Validates that prefix-based resolution works correctly with\n        /// grain inheritance hierarchies.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_Derived_WithPrefix()\n        {\n            var g = this.GrainFactory.GetGrain<IDerivedFromBase>(GetRandomGrainId(), \"UnitTests.Grains\");\n            Assert.False(await g.Foo());\n            Assert.True(await g.Bar());\n        }\n\n        /// <summary>\n        /// Tests error handling for invalid prefixes with derived grains.\n        /// Validates that incorrect prefixes throw appropriate exceptions\n        /// even in inheritance scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public void GetGrain_Derived_WithWrongPrefix()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var g = this.GrainFactory.GetGrain<IDerivedFromBase>(GetRandomGrainId(), \"Foo\");\n            });\n        }\n\n        /// <summary>\n        /// Tests automatic grain resolution when only one implementation exists.\n        /// Validates that Orleans can automatically resolve the single implementation\n        /// of an interface without requiring prefixes or full names.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_OneImplementation_NoPrefix()\n        {\n            var g = this.GrainFactory.GetGrain<IBase1>(GetRandomGrainId());\n            Assert.False(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests explicit grain resolution for single implementations.\n        /// Validates that full type names work correctly even when automatic\n        /// resolution would suffice (single implementation scenario).\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_OneImplementation_Prefix()\n        {\n            var grainFullName = typeof(BaseGrain1).FullName;\n            var g = this.GrainFactory.GetGrain<IBase1>(GetRandomGrainId(), grainFullName);\n            Assert.False(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests grains implementing multiple unrelated interfaces.\n        /// Validates that Orleans correctly handles grains that implement multiple\n        /// independent interfaces, allowing access through any implemented interface.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrain_MultipleUnrelatedInterfaces()\n        {\n            var g1 = this.GrainFactory.GetGrain<IBase3>(GetRandomGrainId());\n            Assert.False(await g1.Foo());\n            var g2 = this.GrainFactory.GetGrain<IBase2>(GetRandomGrainId());\n            Assert.True(await g2.Bar());\n        }\n\n        /// <summary>\n        /// Tests grain creation with string-based keys.\n        /// Validates that the grain factory correctly handles grains identified\n        /// by string keys rather than integer or GUID keys.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetStringGrain()\n        {\n            var g = this.GrainFactory.GetGrain<IStringGrain>(Guid.NewGuid().ToString());\n            Assert.True(await g.Foo());\n        }\n\n        /// <summary>\n        /// Tests grain creation with GUID-based keys.\n        /// Validates that the grain factory correctly handles grains identified\n        /// by GUID keys, supporting different grain key type scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGuidGrain()\n        {\n            var g = this.GrainFactory.GetGrain<IGuidGrain>(Guid.NewGuid());\n            Assert.True(await g.Foo());\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrainIdSpanGeneric()\n        {\n            var g = GrainFactory.GetGrain<IDerivedFromBase>(GrainIdKeyExtensions.CreateIntegerKey(0));\n            await g.Foo();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrainIdSpan()\n        {\n            var g = GrainFactory.GetGrain(typeof(IDerivedFromBase), GrainIdKeyExtensions.CreateIntegerKey(0));\n            await g.AsReference<IBase>().Foo();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrainIdSpanGenericPrefix()\n        {\n            var g = GrainFactory.GetGrain<IBase>(GrainIdKeyExtensions.CreateIntegerKey(0), BaseGrain.GrainPrefix);\n            await g.Foo();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Factory\"), TestCategory(\"GetGrain\")]\n        public async Task GetGrainIdSpanPrefix()\n        {\n            var g = GrainFactory.GetGrain(typeof(IBase), GrainIdKeyExtensions.CreateIntegerKey(0), BaseGrain.GrainPrefix);\n            await g.AsReference<IBase>().Foo();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GrainInterfaceHierarchyTests.cs",
    "content": "using TestExtensions;\nusing TestGrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests for Orleans' support of grain interface inheritance hierarchies.\n    /// Validates that grains can properly implement interfaces that extend other interfaces,\n    /// support multiple inheritance paths, and correctly expose methods from all levels\n    /// of the interface hierarchy.\n    /// </summary>\n    public class GrainInterfaceHierarchyTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public GrainInterfaceHierarchyTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        private T GetHierarchyGrain<T>() where T : IDoSomething, IGrainWithIntegerKey\n        {\n            return GrainFactory.GetGrain<T>(GetRandomGrainId());\n        }\n\n        /// <summary>\n        /// Tests a grain implementing a simple interface hierarchy.\n        /// Validates basic interface inheritance where a grain implements an interface\n        /// that extends a base interface.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingGrainEmptyTest()\n        {\n            IDoSomethingEmptyGrain doSomething = GetHierarchyGrain<IDoSomethingEmptyGrain>();\n            Assert.Equal(\"DoSomethingEmptyGrain\", await doSomething.DoIt());\n        }\n\n        /// <summary>\n        /// Tests a grain implementing an extended interface hierarchy.\n        /// Validates that grains can implement interfaces that add additional methods\n        /// to their base interface, exposing both sets of functionality.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingGrainEmptyWithMoreTest()\n        {\n            IDoSomethingEmptyWithMoreGrain doSomething = GetHierarchyGrain<IDoSomethingEmptyWithMoreGrain>();\n            Assert.Equal(\"DoSomethingEmptyWithMoreGrain\", await doSomething.DoIt());\n            Assert.Equal(\"DoSomethingEmptyWithMoreGrain\", await doSomething.DoMore());\n        }\n\n        /// <summary>\n        /// Tests a grain implementing an interface with multiple method extensions.\n        /// Validates proper method resolution when interfaces extend base interfaces\n        /// with additional functionality.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingWithMoreEmptyGrainTest()\n        {\n            IDoSomethingWithMoreEmptyGrain doSomething = GetHierarchyGrain<IDoSomethingWithMoreEmptyGrain>();\n            Assert.Equal(\"DoSomethingWithMoreEmptyGrain\", await doSomething.DoIt());\n            Assert.Equal(\"DoSomethingWithMoreEmptyGrain\", await doSomething.DoMore());\n        }\n\n        /// <summary>\n        /// Tests a grain with a different interface extension pattern.\n        /// Validates that grains correctly implement alternative method sets\n        /// when extending base interfaces.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingWithMoreGrainTest()\n        {\n            IDoSomethingWithMoreGrain doSomething = GetHierarchyGrain<IDoSomethingWithMoreGrain>();\n            Assert.Equal(\"DoSomethingWithMoreGrain\", await doSomething.DoIt());\n            Assert.Equal(\"DoSomethingWithMoreGrain\", await doSomething.DoThat());\n        }\n\n        /// <summary>\n        /// Tests a grain implementing multiple interface inheritance paths.\n        /// Validates that grains can implement complex interface hierarchies where\n        /// multiple interfaces are combined, exposing all inherited methods.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingCombinedGrainTest()\n        {\n            IDoSomethingCombinedGrain doSomething = GetHierarchyGrain<IDoSomethingCombinedGrain>();\n            Assert.Equal(\"DoSomethingCombinedGrain\", await doSomething.DoIt());\n            Assert.Equal(\"DoSomethingCombinedGrain\", await doSomething.DoMore());\n            Assert.Equal(\"DoSomethingCombinedGrain\", await doSomething.DoThat());\n        }\n\n        /// <summary>\n        /// Tests state management across different interface hierarchy implementations.\n        /// Validates that grains with different interface hierarchies maintain independent\n        /// state and that state operations work correctly through inherited interfaces.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DoSomethingValidateSingleGrainTest()\n        {\n            var doSomethingEmptyGrain = GetHierarchyGrain<IDoSomethingEmptyGrain>();\n            var doSomethingEmptyWithMoreGrain = GetHierarchyGrain<IDoSomethingEmptyWithMoreGrain>();\n            var doSomethingWithMoreEmptyGrain = GetHierarchyGrain<IDoSomethingWithMoreEmptyGrain>();\n            var doSomethingWithMoreGrain = GetHierarchyGrain<IDoSomethingWithMoreGrain>();\n            var doSomethingCombinedGrain = GetHierarchyGrain<IDoSomethingCombinedGrain>();\n\n            await doSomethingEmptyGrain.SetA(10);\n            await doSomethingEmptyWithMoreGrain.SetA(10);\n            await doSomethingWithMoreEmptyGrain.SetA(10);\n            await doSomethingWithMoreGrain.SetA(10);\n            await doSomethingWithMoreGrain.SetB(10);\n            await doSomethingCombinedGrain.SetA(10);\n            await doSomethingCombinedGrain.SetB(10);\n            await doSomethingCombinedGrain.SetC(10);\n\n            await doSomethingEmptyGrain.IncrementA();\n            await doSomethingEmptyWithMoreGrain.IncrementA();\n            await doSomethingWithMoreEmptyGrain.IncrementA();\n            await doSomethingWithMoreGrain.IncrementA();\n            await doSomethingWithMoreGrain.IncrementB();\n            await doSomethingCombinedGrain.IncrementA();\n            await doSomethingCombinedGrain.IncrementB();\n            await doSomethingCombinedGrain.IncrementC();\n\n            Assert.Equal(11, await doSomethingEmptyGrain.GetA());\n            Assert.Equal(11, await doSomethingEmptyWithMoreGrain.GetA());\n            Assert.Equal(11, await doSomethingWithMoreEmptyGrain.GetA());\n            Assert.Equal(11, await doSomethingWithMoreGrain.GetA());\n            Assert.Equal(11, await doSomethingWithMoreGrain.GetB());\n            Assert.Equal(11, await doSomethingCombinedGrain.GetA());\n            Assert.Equal(11, await doSomethingCombinedGrain.GetB());\n            Assert.Equal(11, await doSomethingCombinedGrain.GetC());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GrainReferenceCastTests.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    using Microsoft.Extensions.DependencyInjection;\n\n    /// <summary>\n    /// Tests for Orleans' grain reference casting capabilities.\n    /// Validates that grain references can be safely cast between compatible interfaces,\n    /// including upcasting to base interfaces, casting between multiple implemented interfaces,\n    /// and proper error handling for invalid casts. Tests both pre- and post-activation scenarios.\n    /// </summary>\n    public class GrainReferenceCastTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly IInternalGrainFactory internalGrainFactory;\n\n        public GrainReferenceCastTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n            var client = this.HostedCluster.Client;\n            this.internalGrainFactory = client.ServiceProvider.GetRequiredService<IInternalGrainFactory>();\n        }\n\n        /// <summary>\n        /// Tests basic grain reference casting to the same interface type.\n        /// Validates that casting a grain reference to its own interface type works correctly\n        /// and returns a reference that is assignable to the expected type.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastGrainRefCastFromMyType()\n        {\n            GrainReference grain = (GrainReference)this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), SimpleGrain.SimpleGrainNamePrefix);\n            GrainReference cast = (GrainReference)grain.AsReference<ISimpleGrain>();\n            Assert.IsAssignableFrom(grain.GetType(), cast);\n            Assert.IsAssignableFrom<ISimpleGrain>(cast);\n        }\n\n        /// <summary>\n        /// Tests casting between multiple interfaces implemented by the same grain.\n        /// Validates that a grain implementing multiple interfaces can be cast between\n        /// those interfaces while maintaining proper type relationships.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastGrainRefCastFromMyTypePolymorphic()\n        {\n            IAddressable grain = this.GrainFactory.GetGrain<IMultifacetTestGrain>(0);\n            Assert.IsAssignableFrom<IMultifacetWriter>(grain);\n            Assert.IsAssignableFrom<IMultifacetReader>(grain);\n\n            IAddressable cast = grain.AsReference<IMultifacetReader>();\n            Assert.IsAssignableFrom(grain.GetType(), cast);\n            Assert.IsAssignableFrom<IMultifacetWriter>(cast);\n            Assert.IsAssignableFrom<IMultifacetReader>(grain);\n\n            IAddressable cast2 = grain.AsReference<IMultifacetWriter>();\n            Assert.IsAssignableFrom(grain.GetType(), cast2);\n            Assert.IsAssignableFrom<IMultifacetReader>(cast2);\n            Assert.IsAssignableFrom<IMultifacetWriter>(grain);\n        }\n\n        /// <summary>\n        /// Tests casting between reader and writer interfaces on a multifaceted grain.\n        /// Validates that grains implementing multiple related interfaces can be accessed\n        /// through different interface views while maintaining state consistency.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task CastMultifacetRWReference()\n        {\n            int newValue = 3;\n\n            IMultifacetWriter writer = this.GrainFactory.GetGrain<IMultifacetWriter>(1);\n            // No Wait in this test case\n\n            IMultifacetReader reader = writer.AsReference<IMultifacetReader>();\n\n            await writer.SetValue(newValue);\n\n            Task<int> readAsync = reader.GetValue();\n            int result = await readAsync;\n\n            Assert.Equal(newValue, result);\n        }\n\n        /// <summary>\n        /// Tests casting between interfaces with explicit grain resolution.\n        /// Validates interface casting behavior when the grain reference is resolved\n        /// before casting, ensuring proper interface compatibility checks.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task CastMultifacetRWReferenceWaitForResolve()\n        {\n            int newValue = 4;\n\n            IMultifacetWriter writer = this.GrainFactory.GetGrain<IMultifacetWriter>(2);\n            \n            IMultifacetReader reader = writer.AsReference<IMultifacetReader>();\n            \n            await writer.SetValue(newValue);\n\n            int result = await reader.GetValue();\n\n            Assert.Equal(newValue, result);\n        }\n\n        /// <summary>\n        /// Tests that invalid cast attempts throw appropriate exceptions.\n        /// Validates that attempting to cast a grain reference to a non-grain type\n        /// (like bool) results in an ArgumentException.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastFailInternalCastFromBadType()\n        {\n            var grain = this.GrainFactory.GetGrain<ISimpleGrain>(\n                Random.Shared.Next(),\n                SimpleGrain.SimpleGrainNamePrefix);\n\n            // Attempting to cast a grain to a non-grain type should fail.\n            Assert.Throws<ArgumentException>(() => this.internalGrainFactory.Cast(grain, typeof(bool)));\n        }\n\n        /// <summary>\n        /// Tests internal casting mechanism for same-type casts.\n        /// Validates that casting a grain to its own interface type is optimized\n        /// as a no-op, returning the same reference object.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastInternalCastFromMyType()\n        {\n            GrainReference grain = (GrainReference)this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), SimpleGrain.SimpleGrainNamePrefix);\n            \n            // This cast should be a no-op, since the interface matches the initial reference's exactly.\n            IAddressable cast = grain.Cast<ISimpleGrain>();\n\n            Assert.Same(grain, cast);\n            Assert.IsAssignableFrom<ISimpleGrain>(cast);\n        }\n\n        /// <summary>\n        /// Tests upcasting from derived to base grain interfaces.\n        /// Validates that grain references can be cast from derived interfaces\n        /// to their base interfaces, following normal inheritance rules.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastInternalCastUpFromChild()\n        {\n            GrainReference grain = (GrainReference)this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n            \n            // This cast should be a no-op, since the interface is implemented by the initial reference's interface.\n            IAddressable cast = grain.Cast<IGeneratorTestGrain>();\n\n            Assert.Same(grain, cast);\n            Assert.IsAssignableFrom<IGeneratorTestGrain>(cast);\n        }\n\n        /// <summary>\n        /// Tests grain reference upcasting through AsReference method.\n        /// Validates that derived grain references can be upcast to base interfaces\n        /// using the AsReference API while maintaining type compatibility.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastGrainRefUpCastFromChild()\n        {\n            GrainReference grain = (GrainReference) this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n            GrainReference cast = (GrainReference) grain.AsReference<IGeneratorTestGrain>();\n            Assert.IsAssignableFrom<IGeneratorTestDerivedGrain1>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestGrain>(cast);\n        }\n\n        /// <summary>\n        /// Tests that side-casting between sibling interfaces fails after grain resolution.\n        /// Validates that attempting to cast between unrelated interfaces (siblings in\n        /// the hierarchy) throws InvalidCastException when the grain is already resolved.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task FailSideCastAfterResolve()\n        {\n            IGeneratorTestDerivedGrain1 grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n            Assert.True(await grain.StringIsNullOrEmpty());\n\n            IGeneratorTestDerivedGrain2 cast = grain.AsReference<IGeneratorTestDerivedGrain2>();\n            \n            await Assert.ThrowsAsync<InvalidCastException>(() => cast.StringConcat(\"a\", \"b\", \"c\"));\n        }\n\n        /// <summary>\n        /// Tests that operations fail after invalid side-cast attempts.\n        /// Validates that calling methods on an incorrectly cast grain reference\n        /// throws InvalidCastException when the actual grain doesn't implement the interface.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task FailOperationAfterSideCast()\n        {\n            IGeneratorTestDerivedGrain1 grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n\n            // Cast works optimistically when the grain reference is not already resolved\n            IGeneratorTestDerivedGrain2 cast = grain.AsReference<IGeneratorTestDerivedGrain2>();\n\n            // Operation fails when grain reference is completely resolved\n            await Assert.ThrowsAsync<InvalidCastException>(() => cast.StringConcat(\"a\", \"b\", \"c\"));\n        }\n\n        /// <summary>\n        /// Tests complex casting scenarios with continuation chains.\n        /// Validates that invalid casts fail appropriately in async continuation contexts,\n        /// while valid operations on common interfaces continue to work.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task FailSideCastAfterContinueWith()\n        {\n            var grain = GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n            IGeneratorTestDerivedGrain2 cast = null;\n            var av = grain.StringIsNullOrEmpty();\n            var av2 = av.ContinueWith(t => Assert.True(t.Result))\n                .ContinueWith(\n                    t =>\n                    {\n                        Assert.False(t.IsFaulted);\n\n                        // Casting is always allowed, so this should succeed.\n                        cast = grain.AsReference<IGeneratorTestDerivedGrain2>();\n                    })\n                .ContinueWith(\n                    t =>\n                    {\n                        // Call a method which the grain does not implement, resulting in a cast failure.\n                        Assert.True(t.IsCompletedSuccessfully);\n                        return cast.StringConcat(\"a\", \"b\", \"c\");\n                    })\n                .Unwrap()\n                .ContinueWith(\n                    t =>\n                    {\n                        // Call a method on the common interface, which the grain implements.\n                        // This should not throw.\n                        Assert.True(t.IsFaulted);\n                        return cast.StringIsNullOrEmpty();\n                    })\n                .Unwrap();\n\n            // Ensure that the last task did not throw.\n            var av2Result = await av2;\n            Assert.True(av2Result);\n        }\n\n        /// <summary>\n        /// Tests upcasting through multiple levels of interface inheritance.\n        /// Validates that grain references can be cast from grandchild interfaces\n        /// to both parent and grandparent interfaces, with proper type checking\n        /// to prevent invalid cross-hierarchy casts.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastGrainRefUpCastFromGrandchild()\n        {\n            GrainReference cast;\n            GrainReference grain = (GrainReference)this.GrainFactory.GetGrain<IGeneratorTestDerivedDerivedGrain>(GetRandomGrainId());\n  \n            // Parent\n            cast = (GrainReference) grain.AsReference<IGeneratorTestDerivedGrain2>();\n            Assert.IsAssignableFrom<IGeneratorTestDerivedDerivedGrain>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestDerivedGrain2>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestGrain>(cast);\n            \n            // Cross-cast outside the inheritance hierarchy should not work\n            Assert.False(cast is IGeneratorTestDerivedGrain1);\n\n            // Grandparent\n            cast = (GrainReference) grain.AsReference<IGeneratorTestGrain>();\n            Assert.IsAssignableFrom<IGeneratorTestDerivedDerivedGrain>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestGrain>(cast);\n\n            // Cross-cast outside the inheritance hierarchy should not work\n            Assert.False(cast is IGeneratorTestDerivedGrain1);\n        }\n\n        /// <summary>\n        /// Tests upcasting from deeply nested derived interfaces.\n        /// Validates proper type relationships when casting from interfaces\n        /// that are multiple levels deep in the inheritance hierarchy.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void CastGrainRefUpCastFromDerivedDerivedChild()\n        {\n            GrainReference grain = (GrainReference) this.GrainFactory.GetGrain<IGeneratorTestDerivedDerivedGrain>(GetRandomGrainId());\n            GrainReference cast = (GrainReference) grain.AsReference<IGeneratorTestDerivedGrain2>();\n            Assert.IsAssignableFrom<IGeneratorTestDerivedDerivedGrain>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestDerivedGrain2>(cast);\n            Assert.IsAssignableFrom<IGeneratorTestGrain>(cast);\n            Assert.False(cast is IGeneratorTestDerivedGrain1);\n        }\n\n        /// <summary>\n        /// Tests async operations on self-cast grain references.\n        /// Validates that grain method calls work correctly after casting\n        /// a grain reference to its own interface type.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task CastAsyncGrainRefCastFromSelf()\n        {\n            IAddressable grain = this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), SimpleGrain.SimpleGrainNamePrefix);\n            ISimpleGrain cast = grain.AsReference<ISimpleGrain>();\n\n            Task<int> successfulCallPromise = cast.GetA();\n            await successfulCallPromise;\n            Assert.Equal(TaskStatus.RanToCompletion, successfulCallPromise.Status);\n        }\n\n        // todo: implement white box access\n#if TODO\n        [Fact]\n        public void CastAsyncGrainRefUpCastFromChild()\n        {\n            // GeneratorTestDerivedGrain1Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedGrain2Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedDerivedGrainReference derives from GeneratorTestDerivedGrain2Reference\n\n            //GrainReference grain = GeneratorTestDerivedGrain1Reference.GetGrain(GetRandomGrainId());\n            var lookupPromise = GrainReference.CreateGrain(\n                \"\",\n                \"GeneratorTestGrain.GeneratorTestDerivedGrain1\" );\n            GrainReference grain = new GrainReference(lookupPromise);\n\n            GrainReference cast = (GrainReference) GeneratorTestGrainFactory.Cast(grain);\n            Assert.NotNull(cast);\n            //Assert.Same(typeof(IGeneratorTestGrain), cast.GetType());\n\n            if (!cast.IsResolved)\n            {\n                cast.Wait(100);  // Resolve the grain reference\n            }\n\n            Assert.True(cast.IsResolved);\n            Assert.True(grain.IsResolved);\n        }\n\n        [Fact]\n        public void CastAsyncGrainRefUpCastFromGrandchild()\n        {\n            // GeneratorTestDerivedGrain1Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedGrain2Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedDerivedGrainReference derives from GeneratorTestDerivedGrain2Reference\n\n            //GrainReference grain = GeneratorTestDerivedDerivedGrainReference.GetGrain(GetRandomGrainId());\n            var lookupPromise = GrainReference.CreateGrain(\n                \"\", \n                \"GeneratorTestGrain.GeneratorTestDerivedDerivedGrain\"\n            );\n            GrainReference grain = new GrainReference(lookupPromise);\n\n            GrainReference cast = (GrainReference) GeneratorTestGrainFactory.Cast(grain);\n            Assert.NotNull(cast);\n            //Assert.Same(typeof(IGeneratorTestGrain), cast.GetType());\n\n            if (!cast.IsResolved)\n            {\n                cast.Wait(100);  // Resolve the grain reference\n            }\n\n            Assert.True(cast.IsResolved);\n            Assert.True(grain.IsResolved);\n        }\n\n        [Fact]\n        [ExpectedExceptionAttribute(typeof(InvalidCastException))]\n        public void CastAsyncGrainRefFailSideCastToPeer()\n        {\n            // GeneratorTestDerivedGrain1Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedGrain2Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedDerivedGrainReference derives from GeneratorTestDerivedGrain2Reference\n\n            //GrainReference grain = GeneratorTestDerivedGrain1Reference.GetGrain(GetRandomGrainId());\n            var lookupPromise = GrainReference.CreateGrain(\n                \"\", \n                \"GeneratorTestGrain.GeneratorTestDerivedGrain1\"\n            );\n            GrainReference grain = new GrainReference(lookupPromise);\n\n            GrainReference cast = (GrainReference) GeneratorTestDerivedGrain2Factory.Cast(grain);\n            if (!cast.IsResolved)\n            {\n                cast.Wait(100);  // Resolve the grain reference\n            }\n\n            Assert.True(false, \"Exception should have been raised\");\n        }\n\n        [Fact]\n        [ExpectedExceptionAttribute(typeof(InvalidCastException))]\n        public void CastAsyncGrainRefFailDownCastToChild()\n        {\n            // GeneratorTestDerivedGrain1Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedGrain2Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedDerivedGrainReference derives from GeneratorTestDerivedGrain2Reference\n\n            //GrainReference grain = GeneratorTestGrainReference.GetGrain(GetRandomGrainId());\n            var lookupPromise = GrainReference.CreateGrain(\n                \"\", \n                \"GeneratorTestGrain.GeneratorTestGrain\");\n            GrainReference grain = new GrainReference(lookupPromise);\n\n            GrainReference cast = (GrainReference) GeneratorTestDerivedGrain1Factory.Cast(grain);\n            if (!cast.IsResolved)\n            {\n                cast.Wait(100);  // Resolve the grain reference\n            }\n\n            Assert.True(false, \"Exception should have been raised\");\n        }\n\n        [Fact]\n        [ExpectedExceptionAttribute(typeof(InvalidCastException))]\n        public void CastAsyncGrainRefFailDownCastToGrandchild()\n        {\n            // GeneratorTestDerivedGrain1Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedGrain2Reference derives from GeneratorTestGrainReference\n            // GeneratorTestDerivedDerivedGrainReference derives from GeneratorTestDerivedGrain2Reference\n\n            //GrainReference grain = GeneratorTestGrainReference.GetGrain(GetRandomGrainId());\n            var lookupPromise = GrainReference.CreateGrain(\n                \"\", \n                \"GeneratorTestGrain.GeneratorTestGrain\");\n            GrainReference grain = new GrainReference(lookupPromise);\n\n            GrainReference cast = (GrainReference) GeneratorTestDerivedDerivedGrainFactory.Cast(grain);\n            if (!cast.IsResolved)\n            {\n                cast.Wait(100);  // Resolve the grain reference\n            }\n\n            Assert.True(false, \"Exception should have been raised\");\n        }\n#endif\n        /// <summary>\n        /// Tests calling methods inherited from base interfaces after casting.\n        /// Validates that methods defined in base interfaces remain accessible\n        /// when working with derived grain references and after casting operations.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task CastCallMethodInheritedFromBaseClass()\n        {\n            Task<bool> isNullStr;\n\n            IGeneratorTestDerivedGrain1 grain = this.GrainFactory.GetGrain<IGeneratorTestDerivedGrain1>(GetRandomGrainId());\n            isNullStr = grain.StringIsNullOrEmpty();\n            Assert.True(await isNullStr, \"Value should be null initially\");\n\n            isNullStr = grain.StringSet(\"a\").ContinueWith((_) => grain.StringIsNullOrEmpty()).Unwrap();\n            Assert.False(await isNullStr, \"Value should not be null after SetString(a)\");\n\n            isNullStr = grain.StringSet(null).ContinueWith((_) => grain.StringIsNullOrEmpty()).Unwrap();\n            Assert.True(await isNullStr, \"Value should be null after SetString(null)\");\n\n            IGeneratorTestGrain cast = grain.AsReference<IGeneratorTestGrain>();\n            isNullStr = cast.StringSet(\"b\").ContinueWith((_) => grain.StringIsNullOrEmpty()).Unwrap();\n            Assert.False(await isNullStr, \"Value should not be null after cast.SetString(b)\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/GrainReferenceTest.cs",
    "content": "using Newtonsoft.Json;\nusing Orleans.Concurrency;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    public interface IFooGrain : IGrain { }\n\n    [GrainType(\"foo`1\")]\n    [StatelessWorker]\n    public class FooGrain : Grain, IFooGrain { }\n\n    /// <summary>\n    /// Tests for Orleans grain reference functionality.\n    /// Validates grain reference equality, comparison, serialization (including JSON),\n    /// passing grain references between grains, handling null references,\n    /// and proper hash code generation for distributed systems.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"GrainReference\")]\n    public class GrainReferenceTest : HostedTestClusterEnsureDefaultStarted\n    {\n        public GrainReferenceTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests that grain references produce consistent uniform hash codes.\n        /// Validates that the hash code generation is deterministic and stable,\n        /// which is crucial for consistent grain placement and routing in the cluster.\n        /// </summary>\n        [Fact]\n        public void GrainReferenceComparison_ShouldProduceUniformHashCode()\n        {\n            var simpleGrain = this.GrainFactory.GetGrain<ISimpleGrain>(1234L, UnitTests.Grains.SimpleGrain.SimpleGrainNamePrefix);\n            var r = simpleGrain as GrainReference;\n            Assert.NotNull(r);\n\n            // Hey there stranger. So the test failed here?\n            // It's probably because the way hash codes are generated for the GrainReference\n            // have changed. If you are sure the new code is repeatable, then it's fine to\n            // update the expected value here. Good luck, friend.\n            Assert.Equal(3643965955u, r.GetUniformHashCode());\n        }\n\n        /// <summary>\n        /// Tests grain reference equality and comparison operators.\n        /// Validates that different grain references are properly distinguished\n        /// using equality operators, Equals method, and inequality checks.\n        /// </summary>\n        [Fact]\n        public void GrainReferenceComparison_DifferentReference()\n        {\n            ISimpleGrain ref1 = this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), UnitTests.Grains.SimpleGrain.SimpleGrainNamePrefix);\n            ISimpleGrain ref2 = this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), UnitTests.Grains.SimpleGrain.SimpleGrainNamePrefix);\n            Assert.True(ref1 != ref2);\n            Assert.True(ref2 != ref1);\n            Assert.False(ref1 == ref2);\n            Assert.False(ref2 == ref1);\n            Assert.False(ref1.Equals(ref2));\n            Assert.False(ref2.Equals(ref1));\n        }\n\n        /// <summary>\n        /// Tests passing grain's own reference (this) to another grain.\n        /// Validates that grains can pass references to themselves as method parameters,\n        /// enabling callback patterns and grain interconnections.\n        /// </summary>\n        [Fact]\n        public async Task GrainReference_Pass_this()\n        {\n            IChainedGrain g1 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n            IChainedGrain g2 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n\n            await g1.PassThis(g2);\n        }\n\n        /// <summary>\n        /// Tests passing grain references within nested data structures.\n        /// Validates that grain references embedded in complex objects are properly\n        /// serialized and maintain their identity when passed between grains.\n        /// </summary>\n        [Fact]\n        public async Task GrainReference_Pass_this_Nested()\n        {\n            IChainedGrain g1 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n            IChainedGrain g2 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n\n            await g1.PassThisNested(new ChainGrainHolder { Next = g2 });\n        }\n\n        /// <summary>\n        /// Tests passing null grain references between grains.\n        /// Validates that null references are properly handled in both direct\n        /// parameter passing and when embedded in data structures.\n        /// </summary>\n        [Fact]\n        public async Task GrainReference_Pass_Null()\n        {\n            IChainedGrain g1 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n            IChainedGrain g2 = this.GrainFactory.GetGrain<IChainedGrain>(GetRandomGrainId());\n\n            // g1 will pass a null reference to g2\n            await g1.PassNullNested(new ChainGrainHolder { Next = g2 });\n            Assert.Null(await g2.GetNext());\n            await g1.PassNull(g2);\n            Assert.Null(await g2.GetNext());\n        }\n\n        /// <summary>\n        /// Tests JSON serialization of grain references.\n        /// Validates that grain references can be serialized to JSON and deserialized\n        /// back while maintaining their identity and functionality.\n        /// </summary>\n        [Fact, TestCategory(\"Serialization\"), TestCategory(\"JSON\")]\n        public void GrainReference_Json_Serialization()\n        {\n            int id = Random.Shared.Next();\n            TestGrainReferenceSerialization(id, true);\n        }\n\n        /// <summary>\n        /// Tests JSON serialization of grain references within complex objects.\n        /// Validates that grain references nested in data structures are properly\n        /// serialized/deserialized and remain functional after round-trip.\n        /// </summary>\n        [Fact, TestCategory(\"Serialization\"), TestCategory(\"JSON\")]\n        public async Task GrainReference_Json_Serialization_Nested()\n        {\n            var settings = OrleansJsonSerializerSettings.GetDefaultSerializerSettings(this.HostedCluster.Client.ServiceProvider);\n\n            var grain = HostedCluster.GrainFactory.GetGrain<ISimpleGrain>(GetRandomGrainId());\n            await grain.SetA(56820);\n            var input = new GenericGrainReferenceHolder\n            {\n                Reference = grain as GrainReference\n            };\n\n            var json = JsonConvert.SerializeObject(input, settings);\n            var output = JsonConvert.DeserializeObject<GenericGrainReferenceHolder>(json, settings);\n\n            Assert.Equal(input.Reference, output.Reference);\n            var reference = output.Reference;\n            Assert.Equal(56820, await ((ISimpleGrain)reference).GetA());\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class GenericGrainReferenceHolder\n        {\n            [JsonProperty]\n            [Id(0)]\n            public GrainReference Reference { get; set; }\n        }\n\n        /// <summary>\n        /// Tests JSON serialization of unresolved grain references.\n        /// Validates that grain references can be serialized even before they are\n        /// resolved (activated), maintaining lazy resolution semantics.\n        /// </summary>\n        [Fact, TestCategory(\"Serialization\"), TestCategory(\"JSON\")]\n        public void GrainReference_Json_Serialization_Unresolved()\n        {\n            int id = Random.Shared.Next();\n            TestGrainReferenceSerialization(id, false);\n        }\n\n        /// <summary>\n        /// Tests grain reference interning for system grains.\n        /// Validates that multiple requests for the same grain return the same\n        /// reference object (interning), optimizing memory usage.\n        /// Note: Currently skipped as grain reference interning is not implemented.\n        /// </summary>\n        [Fact(Skip = \"GrainReference interning is not currently implemented.\"), TestCategory(\"Serialization\"), TestCategory(\"Interner\")]\n        public void GrainReference_Interning_Sys_StoreGrain()\n        {\n            var g1 = (GrainReference)this.GrainFactory.GetGrain<IMemoryStorageGrain>(0);\n            var g2 = (GrainReference)this.GrainFactory.GetGrain<IMemoryStorageGrain>(0);\n            Assert.Equal(g1, g2); // Should be equal GrainReferences.\n            Assert.Same(g1, g2); // Should be same / interned GrainReference object\n\n            // Round-trip through Serializer\n            var g3 = this.HostedCluster.RoundTripSerializationForTesting(g1);\n            Assert.Equal(g3, g1);\n            Assert.Equal(g3, g2);\n            Assert.Same(g3, g1);\n            Assert.Same(g3, g2);\n        }\n\n        private void TestGrainReferenceSerialization(int id, bool resolveBeforeSerialize)\n        {\n            // Make sure grain references serialize well through .NET serializer.\n            var grain = this.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), UnitTests.Grains.SimpleGrain.SimpleGrainNamePrefix);\n\n            if (resolveBeforeSerialize)\n            {\n                grain.SetA(id).Wait(); //  Resolve GR\n            }\n\n            // Serialize + Deserialize through Json serializer\n            var other = NewtonsoftJsonSerializeRoundtrip(grain);\n\n            if (!resolveBeforeSerialize)\n            {\n                grain.SetA(id).Wait(); //  Resolve GR\n            }\n\n            Assert.IsAssignableFrom(grain.GetType(), other);\n            Assert.NotNull(other);\n            Assert.Equal(grain,  other);  // \"Deserialized grain reference equality is preserved\"\n            int res = other.GetA().Result;\n            Assert.Equal(id,  res);  // \"Returned values from call to deserialized grain reference\"\n        }\n\n        private T NewtonsoftJsonSerializeRoundtrip<T>(T obj)\n        {\n            var settings = OrleansJsonSerializerSettings.GetDefaultSerializerSettings(this.HostedCluster.Client.ServiceProvider);\n            // http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_JsonConvert.htm\n            string json = JsonConvert.SerializeObject(obj, settings);\n            object other = JsonConvert.DeserializeObject(json, typeof(T), settings);\n            return (T)other;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/HostedClientTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Concurrency;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Metadata;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing Tester.CodeGenTests;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for hosted client functionality in Orleans.\n    /// A hosted client is an Orleans client that runs within the same process as the silo,\n    /// enabling in-process communication between application code and grains.\n    /// This pattern is common in ASP.NET Core applications hosting Orleans.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"HostedClient\")]\n    public class HostedClientTests : IClassFixture<HostedClientTests.Fixture>\n    {\n        private readonly TimeSpan _timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(10);\n        private readonly IHost _host;\n\n        public class Fixture : IAsyncLifetime\n        {\n            private readonly TestClusterPortAllocator portAllocator;\n            public IHost Host { get; private set; }\n\n            public Fixture()\n            {\n                portAllocator = new TestClusterPortAllocator();\n            }\n\n            public async Task InitializeAsync()\n            {\n                var (siloPort, gatewayPort) = portAllocator.AllocateConsecutivePortPairs(1);\n                Host = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder()\n                    .UseOrleans(siloBuilder =>\n                    {\n                        siloBuilder\n                            .UseLocalhostClustering(siloPort, gatewayPort)\n                            .Configure<ClusterOptions>(options =>\n                            {\n                                options.ClusterId = Guid.NewGuid().ToString();\n                                options.ServiceId = Guid.NewGuid().ToString();\n                            })\n                            .ConfigureLogging(logging => logging.AddDebug())\n                            .AddMemoryGrainStorage(\"PubSubStore\")\n                            .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(\"MemStream\");\n                    })\n                    .Build();\n                await Host.StartAsync();\n            }\n\n            public async Task DisposeAsync()\n            {\n                try\n                {\n                    await Host.StopAsync();\n                }\n                finally\n                {\n                    Host.Dispose();\n                    portAllocator.Dispose();\n                }\n            }\n        }\n\n        public HostedClientTests(Fixture fixture)\n        {\n            _host = fixture.Host;\n        }\n\n        /// <summary>\n        /// Tests basic grain invocation from a hosted client.\n        /// Verifies that an in-process client can successfully communicate with grains\n        /// running in the same process, demonstrating the core hosted client pattern.\n        /// </summary>\n        [Fact]\n        public async Task HostedClient_GrainCallTest()\n        {\n            var client = _host.Services.GetRequiredService<IClusterClient>();\n\n            var grain = client.GetGrain<ISimpleGrain>(65);\n            await grain.SetA(23);\n            var val = await grain.GetA();\n            Assert.Equal(23, val);\n        }\n\n        /// <summary>\n        /// Tests timeout behavior for grain calls from a hosted client.\n        /// Verifies that response timeouts are properly enforced and that\n        /// the runtime correctly tracks running requests during timeout scenarios.\n        /// This ensures reliability when grains become unresponsive.\n        /// </summary>\n        [Fact]\n        public async Task HostedClient_TimeoutTest()\n        {\n            var client = _host.Services.GetRequiredService<IClusterClient>();\n            var runtimeClient = _host.Services.GetRequiredService<IRuntimeClient>();\n            var typeResolver = _host.Services.GetRequiredService<GrainInterfaceTypeResolver>();\n\n            var stuckGrainType = typeResolver.GetGrainInterfaceType(typeof(IStuckGrain));\n            var initialTimeout = runtimeClient.GetResponseTimeout();\n\n            var timeout = TimeSpan.FromSeconds(1);\n            var maxTimeout = timeout.Multiply(3.5);\n\n            try\n            {\n                runtimeClient.SetResponseTimeout(timeout);\n                var stopwatch = Stopwatch.StartNew();\n\n                var assertionTask = Assert.ThrowsAsync<TimeoutException>(\n                        async () =>\n                        {\n                            var grain = client.GetGrain<IStuckGrain>(Guid.NewGuid());\n                            await grain.RunForever();\n                        })\n                    .WaitAsync(maxTimeout);\n\n                Assert.Equal(expected: 1, actual: runtimeClient.GetRunningRequestsCount(stuckGrainType));\n\n                await assertionTask;\n                stopwatch.Stop();\n\n                Assert.Equal(expected: 0, actual: runtimeClient.GetRunningRequestsCount(stuckGrainType));\n\n                Assert.True(stopwatch.Elapsed >= timeout, $\"Waited less than {timeout}. Waited {stopwatch.Elapsed}\");\n                Assert.True(stopwatch.Elapsed <= maxTimeout, $\"Waited longer than {maxTimeout}. Waited {stopwatch.Elapsed}\");\n                stopwatch.Stop();\n            }\n            finally\n            {\n                runtimeClient.SetResponseTimeout(initialTimeout);\n            }\n        }\n\n        /// <summary>\n        /// Tests reference equality semantics for objects passed through grain calls.\n        /// Verifies that immutable objects (strings, grain references) maintain reference equality,\n        /// while mutable objects (arrays) are copied. Also demonstrates the Immutable<T> wrapper\n        /// for preserving reference equality of mutable objects when needed.\n        /// </summary>\n        [Fact]\n        public async Task HostedClient_ReferenceEquality_GrainCallTest()\n        {\n            var client = _host.Services.GetRequiredService<IClusterClient>();\n            var grain = client.GetGrain<IGrainWithGenericMethods>(Guid.NewGuid());\n\n            // Strings are immutable.\n            object expected = new string('*', 5);\n            var actual = await grain.RoundTrip(expected);\n            Assert.Same(expected, actual);\n\n            // Grain references are immutable.\n            actual = await grain.RoundTrip(grain);\n            Assert.Same(grain, actual);\n\n            // Arrays are not immutable, so a copy is expected.\n            var collection = new int[] { 1, 3, 9 };\n            actual = await grain.RoundTrip(collection);\n            Assert.NotSame(expected, actual);\n\n            // Immutable<T> should round-trip without any copying.\n            var expectedImmutable = new Immutable<int[]>(collection);\n            var actualImmutable = await grain.RoundTrip(expectedImmutable);\n            Assert.Same(expectedImmutable.Value, actualImmutable.Value);\n        }\n\n        /// <summary>\n        /// Tests the observer pattern from a hosted client.\n        /// Demonstrates how clients can register observer objects to receive\n        /// notifications from grains, enabling push-based communication patterns.\n        /// Verifies that callbacks are properly invoked with the correct context.\n        /// </summary>\n        [Fact]\n        public async Task HostedClient_ObserverTest()\n        {\n            var client = _host.Services.GetRequiredService<IClusterClient>();\n\n            var handle = new AsyncResultHandle();\n\n            var callbackCounter = new int[1];\n            var callbacksReceived = new bool[2];\n\n            var grain = client.GetGrain<ISimpleObserverableGrain>(0);\n            var observer = new ObserverTests.SimpleGrainObserver(\n                (a, b, result) =>\n                {\n                    Assert.Null(RuntimeContext.Current);\n                    callbackCounter[0]++;\n\n                    if (a == 3 && b == 0)\n                        callbacksReceived[0] = true;\n                    else if (a == 3 && b == 2)\n                        callbacksReceived[1] = true;\n                    else\n                        throw new ArgumentOutOfRangeException(\"Unexpected callback with values: a=\" + a + \",b=\" + b);\n\n                    if (callbackCounter[0] == 1)\n                    {\n                        // Allow for callbacks occurring in any order\n                        Assert.True(callbacksReceived[0] || callbacksReceived[1]);\n                    }\n                    else if (callbackCounter[0] == 2)\n                    {\n                        Assert.True(callbacksReceived[0] && callbacksReceived[1]);\n                        result.Done = true;\n                    }\n                    else\n                    {\n                        Assert.True(false);\n                    }\n                },\n                handle,\n                client.ServiceProvider.GetRequiredService<ILogger<ISimpleGrainObserver>>());\n            var reference = client.CreateObjectReference<ISimpleGrainObserver>(observer);\n            await grain.Subscribe(reference);\n            await grain.SetA(3);\n            await grain.SetB(2);\n\n            Assert.True(await handle.WaitForFinished(_timeout));\n\n            client.DeleteObjectReference<ISimpleGrainObserver>(reference);\n            Assert.NotNull(observer);\n        }\n\n        /// <summary>\n        /// Tests streaming functionality from a hosted client.\n        /// Verifies that clients can subscribe to Orleans streams and receive\n        /// messages published to those streams, demonstrating the streaming\n        /// abstraction for event-driven communication patterns.\n        /// </summary>\n        [Fact]\n        public async Task HostedClient_StreamTest()\n        {\n            var client = _host.Services.GetRequiredService<IClusterClient>();\n\n            var handle = new AsyncResultHandle();\n            var vals = new List<int>();\n            var stream0 = client.GetStreamProvider(\"MemStream\").GetStream<int>(\"hi\", Guid.Empty);\n            await stream0.SubscribeAsync(\n                (val, token) =>\n                {\n                    vals.Add(val);\n                    if (vals.Count >= 2) handle.Done = true;\n                    return Task.CompletedTask;\n                });\n            var stream = client.GetStreamProvider(\"MemStream\").GetStream<int>(\"hi\", Guid.Empty);\n            await stream.OnNextAsync(1);\n            await stream.OnNextAsync(409);\n            Assert.True(await handle.WaitForFinished(_timeout));\n            Assert.Equal(new[] { 1, 409 }, vals);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/InMemoryDurableJobsTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Tester.DurableJobs;\nusing TestExtensions;\nusing Xunit;\n\nnamespace DefaultCluster.Tests;\n\npublic class InMemoryDurableJobsTests : HostedTestClusterEnsureDefaultStarted\n{\n    private readonly DurableJobTestsRunner _runner;\n\n    public InMemoryDurableJobsTests(DefaultClusterFixture fixture) : base(fixture)\n    {\n        _runner = new DurableJobTestsRunner(this.GrainFactory);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task DurableJobGrain()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DurableJobGrain(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task JobExecutionOrder()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobExecutionOrder(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task PastDueTime()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.PastDueTime(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task JobWithMetadata()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobWithMetadata(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task MultipleGrains()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.MultipleGrains(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task DuplicateJobNames()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DuplicateJobNames(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task CancelNonExistentJob()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.CancelNonExistentJob(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task CancelAlreadyExecutedJob()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.CancelAlreadyExecutedJob(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task ConcurrentScheduling()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ConcurrentScheduling(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task JobPropertiesVerification()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobPropertiesVerification(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task DequeueCount()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.DequeueCount(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task ScheduleJobOnAnotherGrain()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ScheduleJobOnAnotherGrain(cts.Token);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\n    public async Task JobRetry()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobRetry(cts.Token);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/KeyExtensionTests.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans grain key extensions functionality.\n    /// Key extensions allow grains to have compound keys by combining a primary key\n    /// (GUID, long, or string) with a string extension. This enables scenarios like\n    /// multi-tenancy where the same grain type can have different instances per tenant.\n    /// </summary>\n    public class KeyExtensionTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public KeyExtensionTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Verifies that grains with the same base primary key but different key extensions\n        /// are treated as distinct grain instances with separate activations.\n        /// This is fundamental for multi-tenancy and partitioning scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public async Task PrimaryKeyExtensionsShouldDifferentiateGrainsUsingTheSameBasePrimaryKey()\n        {\n            var baseKey = Guid.NewGuid();\n\n            const string kx1 = \"1\";\n            const string kx2 = \"2\";\n\n            var grain1 = this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, kx1, null);\n            var grainId1 = await grain1.GetGrainReference();\n            var activationId1 = await grain1.GetActivationId();\n\n            var grain2 = this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, kx2, null);\n            var grainId2 = await grain2.GetGrainReference();\n            var activationId2 = await grain2.GetActivationId();\n\n            Assert.NotEqual(grainId1, grainId2); // Mismatched key extensions should differentiate an identical base primary key.\n            Assert.NotEqual(activationId1, activationId2); // Mismatched key extensions should differentiate an identical base primary key.\n        }\n\n        /// <summary>\n        /// Verifies that grains with different base primary keys are distinct\n        /// even when they share the same key extension value.\n        /// Ensures proper isolation between different grain instances.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public async Task PrimaryKeyExtensionsShouldDifferentiateGrainsUsingDifferentBaseKeys()\n        {\n            var baseKey1 = Guid.NewGuid();\n            var baseKey2 = Guid.NewGuid();\n\n            const string kx = \"1\";\n\n            var grain1 = this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey1, kx, null);\n            var grainId1 = await grain1.GetGrainReference();\n            var activationId1 = await grain1.GetActivationId();\n\n            var grain2 = this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey2, kx, null);\n            var grainId2 = await grain2.GetGrainReference();\n            var activationId2 = await grain2.GetActivationId();\n\n            Assert.NotEqual(grainId1, grainId2); // Mismatched base keys should differentiate between identical extended keys.\n            Assert.NotEqual(activationId1, activationId2); // Mismatched base keys should differentiate between identical extended keys.\n        }\n\n        /// <summary>\n        /// Verifies that empty string key extensions are not allowed.\n        /// This prevents accidental grain identity confusion and ensures\n        /// meaningful key extensions when used.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public void EmptyKeyExtensionsAreDisallowed()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var baseKey = Guid.NewGuid();\n\n                this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, \"\", null);\n            });\n        }\n\n        /// <summary>\n        /// Verifies that whitespace-only key extensions are not allowed.\n        /// This ensures key extensions contain meaningful identifiers\n        /// and prevents subtle bugs from invisible characters.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public void WhiteSpaceKeyExtensionsAreDisallowed()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                var baseKey = Guid.NewGuid();\n\n                this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, \" \\t\\n\\r\", null);\n            });\n        }\n\n        /// <summary>\n        /// Verifies that null key extensions are not allowed.\n        /// Enforces that key extensions must be explicitly provided\n        /// when using the extended grain factory methods.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public void NullKeyExtensionsAreDisallowed()\n        {\n            Assert.Throws<ArgumentNullException>(() =>\n            {\n                var baseKey = Guid.NewGuid();\n\n                this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, null, null);\n            });\n        }\n\n        /// <summary>\n        /// Verifies that key extensions can exceed 127 bytes in length.\n        /// This ensures the system can handle long identifiers such as\n        /// file paths, URLs, or other extended identifiers without artificial limits.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public async Task PrimaryKeyExtensionsShouldPermitStringsLongerThan127BytesLong()\n        {\n            var baseKey = Guid.NewGuid();\n\n            string kx1 = new string('\\\\', 300);\n\n            var localGrainRef = this.GrainFactory.GetGrain<IKeyExtensionTestGrain>(baseKey, kx1, null);\n            var remoteGrainRef = await localGrainRef.GetGrainReference();\n\n            Assert.Equal(localGrainRef, remoteGrainRef); // Mismatched grain ID.\n        }\n\n        /// <summary>\n        /// Tests retrieving the primary key string from a grain reference.\n        /// Verifies that string-keyed grains can have their keys extracted\n        /// from grain references for diagnostic or routing purposes.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"PrimaryKeyExtension\")]\n        public void GetPrimaryKeyStringOnGrainReference()\n        {\n            const string key = \"foo\";\n\n            var grain = this.GrainFactory.GetGrain<IStringGrain>(key);\n            var key2 = ((GrainReference) grain).GetPrimaryKeyString();\n\n            Assert.Equal(key, key2); // Unexpected key was returned.\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/LifecycleObserverCreationTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for creating grain observers during lifecycle participation.\n    /// This validates that grain observers can be created during silo lifecycle stages,\n    /// which previously failed because lifecycle events were executed on a SystemTarget\n    /// (grain context), preventing CreateObjectReference from working.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Lifecycle\"), TestCategory(\"Observer\")]\n    public class LifecycleObserverCreationTests\n    {\n        /// <summary>\n        /// Tests that grain observers can be created during lifecycle participation.\n        /// This validates the fix for the issue where CreateObjectReference would fail\n        /// with \"Cannot create a local object reference from a grain\" when called during\n        /// lifecycle events, because those events were previously scheduled on a SystemTarget.\n        /// </summary>\n        [Fact]\n        public async Task LifecycleParticipant_CanCreateGrainObserver()\n        {\n            var observerCreated = false;\n            var grainCalled = false;\n\n            // Create a test cluster with a lifecycle participant that creates an observer\n            var builder = new InProcessTestClusterBuilder();\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.ConfigureServices(services =>\n                {\n                    services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>>(serviceProvider =>\n                        new TestLifecycleParticipant(\n                            serviceProvider.GetRequiredService<IGrainFactory>(),\n                            () => observerCreated = true,\n                            () => grainCalled = true));\n                });\n            });\n\n            var cluster = builder.Build();\n            await cluster.DeployAsync();\n\n            try\n            {\n                // Verify the observer was created during lifecycle participation\n                Assert.True(observerCreated, \"Observer should have been created during lifecycle participation\");\n                \n                // Verify that a grain call was successfully made during lifecycle participation\n                Assert.True(grainCalled, \"Grain should have been called during lifecycle participation\");\n                \n                // Also verify the cluster is operational by calling a grain after startup\n                var grain = cluster.Client.GetGrain<ISimpleGrain>(42);\n                await grain.SetA(100);\n                var value = await grain.GetA();\n                Assert.Equal(100, value);\n            }\n            finally\n            {\n                await cluster.DisposeAsync();\n            }\n        }\n\n        /// <summary>\n        /// Lifecycle participant that creates a grain observer during the Active stage.\n        /// This simulates the issue scenario where a hosted service or lifecycle participant\n        /// needs to create grain observers during silo startup.\n        /// </summary>\n        private class TestLifecycleParticipant : ILifecycleParticipant<ISiloLifecycle>\n        {\n            private readonly IGrainFactory _grainFactory;\n            private readonly Action _onObserverCreated;\n            private readonly Action _onGrainCalled;\n\n            public TestLifecycleParticipant(IGrainFactory grainFactory, Action onObserverCreated, Action onGrainCalled)\n            {\n                _grainFactory = grainFactory;\n                _onObserverCreated = onObserverCreated;\n                _onGrainCalled = onGrainCalled;\n            }\n\n            public void Participate(ISiloLifecycle lifecycle)\n            {\n                lifecycle.Subscribe(\n                    nameof(TestLifecycleParticipant),\n                    ServiceLifecycleStage.Active,\n                    OnStart,\n                    OnStop);\n            }\n\n            private async Task OnStart(CancellationToken ct)\n            {\n                // This is the critical test - creating a grain observer during lifecycle participation\n                // should work now that lifecycle events run via Task.Run instead of on a SystemTarget\n                var observer = new TestObserver();\n                var reference = _grainFactory.CreateObjectReference<ISimpleGrainObserver>(observer);\n                \n                // Verify the reference was created successfully\n                Assert.NotNull(reference);\n                _onObserverCreated();\n                \n                // Also test that we can make grain calls during lifecycle participation\n                var grain = _grainFactory.GetGrain<ISimpleGrain>(123);\n                await grain.SetA(50);\n                var value = await grain.GetA();\n                Assert.Equal(50, value);\n                _onGrainCalled();\n                \n                // Clean up\n                _grainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n            }\n\n            private Task OnStop(CancellationToken ct)\n            {\n                return Task.CompletedTask;\n            }\n        }\n\n        /// <summary>\n        /// Simple observer implementation for testing.\n        /// </summary>\n        private class TestObserver : ISimpleGrainObserver\n        {\n            public void StateChanged(int a, int b)\n            {\n                // No-op for testing\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/LocalActivationStatusCheckerTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests;\n\n/// <summary>\n/// Tests for ILocalActivationStatusChecker functionality.\n/// Validates that the activation status checker correctly identifies locally activated grains\n/// from both silo and client perspectives.\n/// </summary>\npublic class LocalActivationStatusCheckerTests(DefaultClusterFixture fixture) : HostedTestClusterEnsureDefaultStarted(fixture)\n{\n    /// <summary>\n    /// Tests that IsLocallyActivated returns true for a grain that has been activated on the local silo.\n    /// Verifies that after calling a grain method (which activates the grain), the silo-side\n    /// ILocalActivationStatusChecker correctly identifies the grain as locally activated.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\")]\n    public async Task ShouldReturnTrueForLocallyActivatedGrain()\n    {\n        // Get a grain reference and activate it by calling a method\n        var grain = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n        await grain.SetA(42);\n\n        // The grain should be locally activated on exactly one silo\n        var grainId = grain.GetGrainId();\n        Assert.Single(HostedCluster.Silos, silo => IsLocallyActivated(silo, grainId));\n\n        static bool IsLocallyActivated(SiloHandle silo, GrainId grainId)\n        {\n            var siloHandle = (InProcessSiloHandle)silo;\n            var checker = siloHandle.ServiceProvider.GetRequiredService<ILocalActivationStatusChecker>();\n            return checker.IsLocallyActivated(grainId);\n        }\n    }\n\n    /// <summary>\n    /// Tests that IsLocallyActivated returns false for a grain that has not been activated.\n    /// Verifies that a grain reference that has been created but never invoked is not\n    /// considered locally activated.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\")]\n    public void ShouldReturnFalseForNonActivatedGrain()\n    {\n        // Get a grain reference but don't activate it\n        var grain = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n\n        // The grain should not be locally activated on any silo\n        var grainId = grain.GetGrainId();\n        Assert.DoesNotContain(HostedCluster.Silos, silo => IsLocallyActivated(silo, grainId));\n\n        static bool IsLocallyActivated(SiloHandle silo, GrainId grainId)\n        {\n            var siloHandle = (InProcessSiloHandle)silo;\n            var checker = siloHandle.ServiceProvider.GetRequiredService<ILocalActivationStatusChecker>();\n            return checker.IsLocallyActivated(grainId);\n        }\n    }\n\n    /// <summary>\n    /// Tests that IsLocallyActivated returns false for different grain identities.\n    /// Verifies that activating one grain does not affect the activation status of another grain.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\")]\n    public async Task ShouldReturnFalseForDifferentGrainIdentity()\n    {\n        // Activate one grain\n        var grain1 = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n        await grain1.SetA(42);\n\n        // Get a different grain reference (different identity)\n        var grain2 = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n\n        // The second grain should not be locally activated on any silo\n        var grainId2 = grain2.GetGrainId();\n        Assert.DoesNotContain(HostedCluster.Silos, silo => IsLocallyActivated(silo, grainId2));\n\n        static bool IsLocallyActivated(SiloHandle silo, GrainId grainId)\n        {\n            var siloHandle = (InProcessSiloHandle)silo;\n            var checker = siloHandle.ServiceProvider.GetRequiredService<ILocalActivationStatusChecker>();\n            return checker.IsLocallyActivated(grainId);\n        }\n    }\n\n    /// <summary>\n    /// Tests that the client-side ILocalActivationStatusChecker always returns false.\n    /// Clients do not host grain activations, so IsLocallyActivated should always return false\n    /// regardless of whether a grain has been invoked or not.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\")]\n    public async Task ClientShouldAlwaysReturnFalseForIsLocallyActivated()\n    {\n        // Get a grain reference and activate it\n        var grain = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n        await grain.SetA(42);\n\n        // Get the client-side activation checker\n        var clientChecker = Client.ServiceProvider.GetRequiredService<ILocalActivationStatusChecker>();\n        var isLocalOnClient = clientChecker.IsLocallyActivated(grain.GetGrainId());\n\n        // Client should always return false\n        Assert.False(isLocalOnClient, \"Client should always return false for IsLocallyActivated\");\n    }\n\n    /// <summary>\n    /// Tests that the client-side checker returns false even for non-activated grains.\n    /// Verifies consistent behavior regardless of grain activation state.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\")]\n    public void ClientShouldReturnFalseForNonActivatedGrain()\n    {\n        // Get a grain reference without activating it\n        var grain = GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.NextInt64());\n\n        // Get the client-side activation checker\n        var clientChecker = Client.ServiceProvider.GetRequiredService<ILocalActivationStatusChecker>();\n        var isLocalOnClient = clientChecker.IsLocallyActivated(grain.GetGrainId());\n\n        // Client should return false\n        Assert.False(isLocalOnClient, \"Client should return false for non-activated grain\");\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/LocalErrorGrain.cs",
    "content": "﻿namespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Test grain implementation used for error handling tests.\n    /// This grain simulates various error conditions to test exception propagation and timeout scenarios.\n    /// Not a real Orleans grain - used as a local mock for testing error cases.\n    /// </summary>\n    internal class LocalErrorGrain\n    {\n        private int m_a = 0;\n        private int m_b = 0;\n\n        public LocalErrorGrain() { }\n\n        public Task SetA(int a)\n        {\n            m_a = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(int b)\n        {\n            m_b = b;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetAxB()\n        {\n            return Task.FromResult(m_a * m_b);\n        }\n\n        public async Task<int> GetAxBError()\n        {\n            await Task.CompletedTask;\n            throw new Exception(\"GetAxBError-Exception\");\n        }\n\n        public Task LongMethod(int waitTime)\n        {\n            Thread.Sleep(waitTime);\n            return Task.CompletedTask;\n        }\n\n        public async Task LongMethodWithError(int waitTime)\n        {\n            Thread.Sleep(waitTime);\n            await Task.CompletedTask;\n            throw new Exception(\"LongMethodWithError(\" + waitTime + \")\");\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ManagementGrainTests.cs",
    "content": "using Orleans.Concurrency;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime\n{\n    /// <summary>\n    /// Tests for the Orleans Management Grain functionality.\n    /// The Management Grain is a system grain that provides cluster management operations\n    /// such as querying grain activation information, collecting statistics, and\n    /// performing administrative tasks across the Orleans cluster.\n    /// </summary>\n    public class ManagementGrainTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public ManagementGrainTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests querying grain activation addresses through the management grain.\n        /// Verifies that:\n        /// - Non-activated grains return null addresses\n        /// - Activated grains return valid addresses that remain stable\n        /// - Stateless worker grains throw appropriate exceptions (no single activation)\n        /// This functionality is crucial for diagnostics and monitoring grain placement.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task GetActivationAddressTest()\n        {\n            var managementGrain = this.Fixture.Client.GetGrain<IManagementGrain>(0);\n            var grain1 = this.Fixture.Client.GetGrain<IDumbGrain>(Guid.NewGuid());\n            var grain2 = this.Fixture.Client.GetGrain<IDumbGrain>(Guid.NewGuid());\n\n            var grain1Address = await managementGrain.GetActivationAddress(grain1);\n            Assert.Null(grain1Address);\n\n            await grain1.DoNothing();\n            grain1Address = await managementGrain.GetActivationAddress(grain1);\n            Assert.NotNull(grain1Address);\n            var grain2Address = await managementGrain.GetActivationAddress(grain2);\n            Assert.Null(grain2Address);\n\n            await grain2.DoNothing();\n            var grain1Address2 = await managementGrain.GetActivationAddress(grain1);\n            Assert.NotNull(grain1Address2);\n            Assert.True(grain1Address.Equals(grain1Address2));\n\n            var worker = this.Fixture.Client.GetGrain<IDumbWorker>(0);\n            await Assert.ThrowsAnyAsync<InvalidOperationException>(async () => await managementGrain.GetActivationAddress(worker));\n        }\n    }\n\n    /// <summary>\n    /// Test interface for a stateless worker grain.\n    /// Used to verify that management operations handle stateless workers correctly.\n    /// </summary>\n    public interface IDumbWorker : IGrainWithIntegerKey\n    {\n        Task DoNothing();\n    }\n\n    /// <summary>\n    /// Test implementation of a stateless worker grain.\n    /// Stateless workers can have multiple activations and don't have a single address,\n    /// which makes them special cases for management operations.\n    /// </summary>\n    [StatelessWorker(1)]\n    public class DumbWorker : Grain, IDumbWorker\n    {\n        public Task DoNothing() => Task.CompletedTask;\n    }\n\n    /// <summary>\n    /// Test interface for a regular stateful grain.\n    /// Used to verify normal grain activation address queries.\n    /// </summary>\n    public interface IDumbGrain : IGrainWithGuidKey\n    {\n        Task DoNothing();\n    }\n\n    /// <summary>\n    /// Test implementation of a regular stateful grain.\n    /// Regular grains have a single activation at any time,\n    /// making their addresses queryable through management operations.\n    /// </summary>\n    public class DumbGrain : Grain, IDumbGrain\n    {\n        public Task DoNothing() => Task.CompletedTask;\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/MemoryStorageProviderTests.cs",
    "content": "using Orleans.Storage;\nusing Orleans.Storage.Internal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.StorageTests\n{\n    /// <summary>\n    /// Tests for the Orleans Memory Storage Provider.\n    /// The memory storage provider stores grain state in memory (non-persistent)\n    /// and is typically used for development, testing, and scenarios where\n    /// state persistence across restarts is not required.\n    /// </summary>\n    [TestCategory(\"Storage\"), TestCategory(\"MemoryStore\")]\n    public class MemoryStorageProviderTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public MemoryStorageProviderTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests that grains can restore their initial state from storage.\n        /// Verifies the basic contract that grain state is loaded during activation\n        /// and that the storage provider properly initializes state objects.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task MemoryStorageProvider_RestoreStateTest()\n        {\n            var grainWithState = this.GrainFactory.GetGrain<IInitialStateGrain>(0);\n            Assert.NotNull(await grainWithState.GetNames());\n        }\n\n        /// <summary>\n        /// Tests handling of null state values in the storage provider.\n        /// Verifies that grains can store and retrieve null state without errors,\n        /// and can transition between null and non-null state values.\n        /// This is important for optional state scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task MemoryStorageProvider_NullState()\n        {\n            var grainWithState = this.GrainFactory.GetGrain<INullStateGrain>(0);\n            Assert.NotNull(await grainWithState.GetState());\n\n            await grainWithState.SetStateAndDeactivate(null);\n            await grainWithState.SetStateAndDeactivate(new NullableState { Name = \"Thrall\" });\n        }\n\n        /// <summary>\n        /// Tests basic write and read operations for grain state.\n        /// Verifies that state changes are properly persisted in memory\n        /// and can be retrieved, demonstrating the fundamental storage\n        /// provider contract for state management.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task MemoryStorageProvider_WriteReadStateTest()\n        {\n            var grainWithState = this.GrainFactory.GetGrain<IInitialStateGrain>(0);\n\n            List<string> names = await grainWithState.GetNames();\n            Assert.NotNull(names);\n            Assert.Empty(names);\n\n            // first write\n            await grainWithState.AddName(\"Bob\");\n            names = await grainWithState.GetNames();\n            Assert.NotNull(names);\n            Assert.Single(names);\n            Assert.Equal(\"Bob\", names[0]);\n\n            // secodn write\n            await grainWithState.AddName(\"Alice\");\n            names = await grainWithState.GetNames();\n            Assert.NotNull(names);\n            Assert.Equal(2, names.Count);\n            Assert.Equal(\"Bob\", names[0]);\n            Assert.Equal(\"Alice\", names[1]);\n        }\n\n        /// <summary>\n        /// Tests ETag (entity tag) enforcement in the memory storage provider.\n        /// ETags provide optimistic concurrency control by ensuring updates only succeed\n        /// if the state hasn't changed since it was read. This test verifies:\n        /// - Null ETags work for initial writes\n        /// - Mismatched ETags cause appropriate exceptions\n        /// - Correct ETags allow updates\n        /// - Deleted state requires null ETags for new writes\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task MemoryStorageGrainEnforcesEtagsTest()\n        {\n            var memoryStorageGrain = this.GrainFactory.GetGrain<IMemoryStorageGrain>(Random.Shared.Next());\n\n            // Delete grain state from empty grain, should be safe.\n            await memoryStorageGrain.DeleteStateAsync<object>(\"grainStoreKey\", \"eTag\");\n\n            // Read grain state from empty grain, should be safe, but return nothing.\n            var grainState = await memoryStorageGrain.ReadStateAsync<object>(\"grainStoreKey\");\n            Assert.Null(grainState);\n\n            // write state with etag, when there is nothing in storage.  Most storage should fail this, but memory storage should succeed.\n            await memoryStorageGrain.WriteStateAsync(\"grainId\", TestGrainState.CreateRandom());\n\n            // write new state with null etag\n            string newEtag = await memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(null));\n            Assert.NotNull(newEtag);\n\n            // try to write new state with null etag;\n            var ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(null)));\n\n            // try to write new state with different etag;\n            ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(newEtag + \"a\")));\n\n            // Write new state with good etag;\n            string latestEtag = await memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(newEtag));\n            Assert.NotNull(latestEtag);\n\n            // try delete state with null etag\n            ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.DeleteStateAsync<object>(\"id\", null));\n\n            // try delete state with wrong etag\n            ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.DeleteStateAsync<object>(\"id\", latestEtag + \"a\"));\n\n            // delete state\n            await memoryStorageGrain.DeleteStateAsync<object>(\"id\", latestEtag);\n\n            // Read grain deleted grain state, should be safe, but return nothing.\n            grainState = await memoryStorageGrain.ReadStateAsync<object>(\"id\");\n            Assert.Null(grainState);\n\n            // try delete already deleted grain state\n            ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.DeleteStateAsync<object>(\"id\", latestEtag));\n\n            // try to write state to deleted state.\n            ex = await Assert.ThrowsAsync<MemoryStorageEtagMismatchException>(() => memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(latestEtag)));\n\n            // Make sure we can write new state to a deleted state\n            await memoryStorageGrain.WriteStateAsync(\"id\", TestGrainState.CreateWithEtag(null));\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class TestGrainState : IGrainState<object>\n        {\n            public static IGrainState<object> CreateRandom()\n            {\n                return new TestGrainState\n                {\n                    State = Random.Shared.Next(),\n                    ETag = Random.Shared.Next().ToString()\n                };\n            }\n\n            public static IGrainState<object> CreateWithEtag(string eTag)\n            {\n                return new TestGrainState\n                {\n                    State = Random.Shared.Next(),\n                    ETag = eTag\n                };\n            }\n\n            [Id(0)]\n            public object State { get; set; }\n\n            [Id(1)]\n            public string ETag { get; set; }\n\n            [Id(2)]\n            public bool RecordExists { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/Migration/MigrationTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Core.Internal;\nusing Orleans.Placement;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    public class MigrationTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public MigrationTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests that grain migration works for a simple grain which directly implements <see cref=\"IGrainMigrationParticipant\"/>.\n        /// The test does not specify an alternative location for the grain to migrate to, but spins until it selects an alternative on its own.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task BasicGrainMigrationTest()\n        {\n            for (var i = 1; i < 100; ++i)\n            {\n                var grain = GrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n                var expectedState = Random.Shared.Next();\n                var originalAddress = await grain.GetGrainAddress();\n                GrainAddress newAddress;\n                do\n                {\n                    // Trigger migration without setting a placement hint, so the grain placement provider will be\n                    // free to select any location including the existing one.\n                    await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n                    await grain.SetState(expectedState);\n                    newAddress = await grain.GetGrainAddress();\n                } while (originalAddress == newAddress);\n\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n            }\n        }\n\n        /// <summary>\n        /// Tests that migration can be initiated from within the grain's <see cref=\"IGrainBase.OnDeactivateAsync(DeactivationReason, CancellationToken)\"/> implementation.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task InitiateMigrationFromOnDeactivateAsyncTest()\n        {\n            for (var i = 1; i < 100; ++i)\n            {\n                var grain = GrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n                var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalHost);\n\n                // Trigger deactivation and tell the grain that it should migrate to the target host on deactivation.\n                await grain.MigrateDuringDeactivation(targetHost);\n\n                GrainAddress newAddress;\n                do\n                {\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                var newHost = newAddress.SiloAddress;\n                Assert.Equal(targetHost, newHost);\n\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n            }\n        }\n\n        /// <summary>\n        /// Tests that grain migration works for a simple grain which directly implements <see cref=\"IGrainMigrationParticipant\"/>.\n        /// The test specifies an alternative location for the grain to migrate to and asserts that it migrates to that location.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DirectedGrainMigrationTest()\n        {\n            for (var i = 1; i < 100; ++i)\n            {\n                var grain = GrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n                var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalHost);\n\n                // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                GrainAddress newAddress;\n                do\n                {\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                var newHost = newAddress.SiloAddress;\n                Assert.Equal(targetHost, newHost);\n\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n            }\n        }\n\n        /// <summary>\n        /// Tests that multiple grains can be migrated simultaneously.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task MultiGrainDirectedMigrationTest()\n        {\n            var baseId = GetRandomGrainId();\n            for (var i = 1; i < 100; ++i)\n            {\n                var a = GrainFactory.GetGrain<IMigrationTestGrain>(baseId + 2 * i);\n                var expectedState = Random.Shared.Next();\n                await a.SetState(expectedState);\n                var originalAddressA = await a.GetGrainAddress();\n                var originalHostA = originalAddressA.SiloAddress;\n\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, originalHostA);\n                var b = GrainFactory.GetGrain<IMigrationTestGrain>(baseId + 1 + 2 * i);\n                await b.SetState(expectedState);\n                var originalAddressB = await b.GetGrainAddress();\n                Assert.Equal(originalHostA, originalAddressB.SiloAddress);\n\n                var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalHostA);\n\n                // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                var migrateA = a.Cast<IGrainManagementExtension>().MigrateOnIdle();\n                var migrateB = b.Cast<IGrainManagementExtension>().MigrateOnIdle();\n                await migrateA;\n                await migrateB;\n\n                while (true)\n                {\n                    var newAddress = await a.GetGrainAddress();\n                    if (newAddress.ActivationId != originalAddressA.ActivationId)\n                    {\n                        Assert.Equal(targetHost, newAddress.SiloAddress);\n                        break;\n                    }\n                }\n\n                while (true)\n                {\n                    var newAddress = await b.GetGrainAddress();\n                    if (newAddress.ActivationId != originalAddressB.ActivationId)\n                    {\n                        Assert.Equal(targetHost, newAddress.SiloAddress);\n                        break;\n                    }\n                }\n\n                Assert.Equal(expectedState, await a.GetState());\n                Assert.Equal(expectedState, await b.GetState());\n            }\n        }\n\n        /// <summary>\n        /// Tests that grain migration works for a simple grain which uses <see cref=\"Grain{TGrainState}\"/> for state.\n        /// The test specifies an alternative location for the grain to migrate to and asserts that it migrates to that location.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DirectedGrainMigrationTest_GrainOfT()\n        {\n            for (var i = 1; i < 100; ++i)\n            {\n                var grain = GrainFactory.GetGrain<IMigrationTestGrain_GrainOfT>(GetRandomGrainId());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n                var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalHost);\n\n                // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                GrainAddress newAddress;\n                do\n                {\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                var newHost = newAddress.SiloAddress;\n                Assert.Equal(targetHost, newHost);\n\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n            }\n        }\n\n        /// <summary>\n        /// Tests that grain migration works for a simple grain which uses <see cref=\"IPersistentState{TState}\"/> for state.\n        /// The test specifies an alternative location for the grain to migrate to and asserts that it migrates to that location.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task DirectedGrainMigrationTest_IPersistentStateOfT()\n        {\n            for (var i = 1; i < 100; ++i)\n            {\n                var grain = GrainFactory.GetGrain<IMigrationTestGrain_IPersistentStateOfT>(GetRandomGrainId());\n                var expectedStateA = Random.Shared.Next();\n                var expectedStateB = Random.Shared.Next();\n                await grain.SetState(expectedStateA, expectedStateB);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n                var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalHost);\n\n                // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                GrainAddress newAddress;\n                do\n                {\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                var newHost = newAddress.SiloAddress;\n                Assert.Equal(targetHost, newHost);\n\n                var (actualA, actualB) = await grain.GetState();\n                Assert.Equal(expectedStateA, actualA);\n                Assert.Equal(expectedStateB, actualB);\n            }\n        }\n\n        /// <summary>\n        /// When grain dehydration fails, the grain should be deactivated but will not retain migration state.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task FailDehydrationTest()\n        {\n            using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));\n            var grain = GrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n            var expectedState = Random.Shared.Next();\n            await grain.SetState(expectedState);\n            var originalAddress = await grain.GetGrainAddress();\n            var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalAddress.SiloAddress);\n\n            // Wait for membership to stabilize and for cluster manifests to be propagated.\n            // We do this by repeatedly trying to activate a grain on the target silo.\n            var primaryGrainFactory = ((InProcessSiloHandle)Fixture.HostedCluster.Primary).ServiceProvider.GetRequiredService<IGrainFactory>();\n            SiloAddress grainOnOtherSiloAddr;\n            do\n            {\n                cts.Token.ThrowIfCancellationRequested();\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                var grainOnOtherSilo = primaryGrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n                var addr = await grainOnOtherSilo.GetGrainAddress();\n                grainOnOtherSiloAddr = addr.SiloAddress;\n                await Task.Delay(100);\n            } while (!targetHost.Equals(grainOnOtherSiloAddr));\n\n            // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n            // Also, tell the grain to fail to dehydrate (by stuffing some data into the request context which tells it to throw)\n            RequestContext.Set(\"fail_dehydrate\", true);\n            RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n            await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n            // The grain should have lost its state during the failed migration.\n            var newState = await grain.GetState();\n            Assert.NotEqual(expectedState, newState);\n\n            var newAddress = await grain.GetGrainAddress();\n            Assert.Equal(targetHost, newAddress.SiloAddress);\n        }\n\n        /// <summary>\n        /// When grain rehydration fails, the grain should be deactivated but will not retain migration state.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task FailRehydrationTest()\n        {\n            var grain = GrainFactory.GetGrain<IMigrationTestGrain>(GetRandomGrainId());\n            var expectedState = Random.Shared.Next();\n            await grain.SetState(expectedState);\n            var originalAddress = await grain.GetGrainAddress();\n            var targetHost = Fixture.HostedCluster.GetActiveSilos().Select(s => s.SiloAddress).First(address => address != originalAddress.SiloAddress);\n\n            // Trigger migration, setting a placement hint to coerce the placement director to use the target silo\n            // Also, tell the grain to fail to rehydrate (by stuffing some data into the rehydration context which tells it to throw)\n            RequestContext.Set(\"fail_rehydrate\", true);\n            RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n            await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n            var newAddress = await grain.GetGrainAddress();\n            Assert.Equal(targetHost, newAddress.SiloAddress);\n\n            // The grain should have lost its state during the failed migration.\n            var newState = await grain.GetState();\n            Assert.NotEqual(expectedState, newState);\n        }\n    }\n\n    public interface IMigrationTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask<GrainAddress> GetGrainAddress();\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n        ValueTask MigrateDuringDeactivation(SiloAddress targetHost);\n    }\n\n    // Use random placement because this is used to test undirected migration.\n    [RandomPlacement]\n    public class MigrationTestGrain : Grain, IMigrationTestGrain, IGrainMigrationParticipant\n    {\n        private int _state;\n        private SiloAddress _migrateDuringDeactivationTargetHost;\n        public ValueTask<int> GetState() => new(_state);\n\n        public ValueTask SetState(int state)\n        {\n            _state = state;\n            return default;\n        }\n\n        public void OnDehydrate(IDehydrationContext migrationContext)\n        {\n            if (RequestContext.Get(\"fail_rehydrate\") is true)\n            {\n                migrationContext.TryAddValue(\"fail_rehydrate\", true);\n            }\n\n            if (RequestContext.Get(\"fail_dehydrate\") is true)\n            {\n                throw new InvalidOperationException(\"Failing to dehydrate on-command\");\n            }\n\n            migrationContext.TryAddValue(\"state\", _state);\n\n        }\n\n        public void OnRehydrate(IRehydrationContext migrationContext)\n        {\n            if (migrationContext.TryGetValue(\"fail_rehydrate\", out bool fail) && fail)\n            {\n                throw new InvalidOperationException(\"Failing to rehydrate on-command\");\n            }\n\n            migrationContext.TryGetValue(\"state\", out _state);\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n\n        public ValueTask MigrateDuringDeactivation(SiloAddress targetHost)\n        {\n            _migrateDuringDeactivationTargetHost = targetHost;\n            this.DeactivateOnIdle();\n            return ValueTask.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            if (reason.ReasonCode is DeactivationReasonCode.ApplicationRequested && _migrateDuringDeactivationTargetHost is not null)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, _migrateDuringDeactivationTargetHost);\n                this.MigrateOnIdle();\n            }\n\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n    public interface IMigrationTestGrain_GrainOfT : IGrainWithIntegerKey\n    {\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n        ValueTask<GrainAddress> GetGrainAddress();\n    }\n\n    public class MigrationTestGrainWithMemoryStorage : Grain<MyMigrationStateClass>, IMigrationTestGrain_GrainOfT\n    {\n        public ValueTask<int> GetState() => new(State.Value);\n\n        public ValueTask SetState(int state)\n        {\n            State.Value = state;\n            return default;\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n\n    [GenerateSerializer]\n    public class MyMigrationStateClass\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    public interface IMigrationTestGrain_IPersistentStateOfT : IGrainWithIntegerKey\n    {\n        ValueTask SetState(int a, int b);\n        ValueTask<(int A, int B)> GetState();\n        ValueTask<GrainAddress> GetGrainAddress();\n    }\n\n    public class MigrationTestGrainWithInjectedMemoryStorage : Grain, IMigrationTestGrain_IPersistentStateOfT\n    {\n        private readonly IPersistentState<MyMigrationStateClass> _stateA;\n        private readonly IPersistentState<MyMigrationStateClass> _stateB;\n\n        public MigrationTestGrainWithInjectedMemoryStorage(\n            [PersistentState(\"a\")] IPersistentState<MyMigrationStateClass> stateA,\n            [PersistentState(\"b\")] IPersistentState<MyMigrationStateClass> stateB)\n        {\n            _stateA = stateA;\n            _stateB = stateB;\n        }\n\n        public ValueTask<(int A, int B)> GetState() => new((_stateA.State.Value, _stateB.State.Value));\n\n        public ValueTask SetState(int a, int b)\n        {\n            _stateA.State.Value = a;\n            _stateB.State.Value = b;\n            return default;\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/MultifacetGrainTest.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for multifaceted grain functionality in Orleans.\n    /// Multifaceted grains can implement multiple interfaces and be accessed\n    /// through different interface references using AsReference<T>().\n    /// This enables grains to expose different APIs to different consumers\n    /// while maintaining a single grain instance.\n    /// </summary>\n    //using ValueUpdateEventArgs = MultifacetGrainClient.ValueUpdateEventArgs;\n    public class MultifacetGrainTest : HostedTestClusterEnsureDefaultStarted\n    {\n        private IMultifacetWriter writer;\n        private IMultifacetReader reader;\n\n        //int eventCounter;\n        private const int EXPECTED_NUMBER_OF_EVENTS = 4;\n        private readonly TimeSpan timeout = TimeSpan.FromSeconds(5);\n\n        public MultifacetGrainTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests accessing a grain through different interface facets.\n        /// Verifies that a grain implementing multiple interfaces (writer and reader)\n        /// can be accessed through either interface using AsReference<T>(),\n        /// and that both references operate on the same underlying grain state.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Cast\")]\n        public async Task RWReferences()\n        {\n            writer = this.GrainFactory.GetGrain<IMultifacetWriter>(GetRandomGrainId());\n            reader = writer.AsReference<IMultifacetReader>();\n\n            int x = 1234;\n            await writer.SetValue(x).WaitAsync(timeout);\n            int y = await reader.GetValue();\n            Assert.Equal(x, y);\n        }\n\n        /// <summary>\n        /// Verifies that invalid interface casts throw appropriate exceptions.\n        /// Tests that attempting to cast a grain reference to an interface\n        /// it doesn't implement results in an InvalidCastException,\n        /// ensuring type safety in the multifacet pattern.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public void RWReferencesInvalidCastException()\n        {\n            Assert.Throws<InvalidCastException>(() =>\n            {\n                reader = this.GrainFactory.GetGrain<IMultifacetReader>(GetRandomGrainId());\n                writer = (IMultifacetWriter)reader;\n            });\n        }\n\n        /// <summary>\n        /// Tests factory methods that return different facets of a grain.\n        /// Verifies that factory grains can create and return references\n        /// to different interfaces of the same grain, enabling patterns\n        /// where grain creation logic returns appropriate interfaces to callers.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task MultifacetFactory()\n        {\n            IMultifacetFactoryTestGrain factory = this.GrainFactory.GetGrain<IMultifacetFactoryTestGrain>(GetRandomGrainId());\n            IMultifacetTestGrain grain = this.GrainFactory.GetGrain<IMultifacetTestGrain>(GetRandomGrainId());\n            IMultifacetWriter writer = await factory.GetWriter(grain /*\"MultifacetFactory\"*/);\n            IMultifacetReader reader = await factory.GetReader(grain /*\"MultifacetFactory\"*/);\n            await writer.SetValue(5);\n            int v = await reader.GetValue();\n            Assert.Equal(5, v);\n\n        }\n\n        /// <summary>\n        /// Tests passing grain interface references as method arguments.\n        /// Verifies that different interface facets of a grain can be passed\n        /// to and stored by other grains, and that these references remain\n        /// valid and operate on the same underlying grain instance.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Multifacet_InterfacesAsArguments()\n        {\n            IMultifacetFactoryTestGrain factory = this.GrainFactory.GetGrain<IMultifacetFactoryTestGrain>(GetRandomGrainId());\n            IMultifacetTestGrain grain = this.GrainFactory.GetGrain<IMultifacetTestGrain>(GetRandomGrainId());\n            await factory.SetReader(grain);\n            await factory.SetWriter(grain);\n            IMultifacetWriter writer = await factory.GetWriter();\n            IMultifacetReader reader = await factory.GetReader();\n            await writer.SetValue(10);\n            int v = await reader.GetValue();\n            Assert.Equal(10, v);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ObserverTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for the Orleans Observer pattern implementation.\n    /// Observers enable grains to send notifications to clients or other grains\n    /// through callback interfaces. This is Orleans' mechanism for push-based\n    /// communication, allowing grains to notify interested parties of state changes\n    /// or events without polling. Observers are weakly referenced to prevent\n    /// memory leaks and support automatic cleanup.\n    /// </summary>\n    public class ObserverTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly TimeSpan timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(10);\n        private int callbackCounter;\n        private readonly bool[] callbacksReceived = new bool[2];\n\n        // we keep the observer objects as instance variables to prevent them from\n        // being garbage collected prematurely (the runtime stores them as weak references).\n        private SimpleGrainObserver observer1;\n        private SimpleGrainObserver observer2;\n\n        public ObserverTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        private void TestInitialize()\n        {\n            callbackCounter = 0;\n            callbacksReceived[0] = false;\n            callbacksReceived[1] = false;\n\n            observer1 = null;\n            observer2 = null;\n        }\n\n        private ISimpleObserverableGrain GetGrain()\n        {\n            return this.GrainFactory.GetGrain<ISimpleObserverableGrain>(GetRandomGrainId());\n        }\n\n        /// <summary>\n        /// Tests basic observer notification functionality.\n        /// Verifies that a grain can notify registered observers of state changes,\n        /// that multiple notifications are delivered correctly, and that the\n        /// observer callback context is properly maintained.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ObserverTest_SimpleNotification()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_SimpleNotification_Callback, result, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(this.observer1);\n            await grain.Subscribe(reference);\n            await grain.SetA(3);\n            await grain.SetB(2);\n\n            Assert.True(await result.WaitForFinished(timeout));\n\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n        }\n\n        /// <summary>\n        /// Tests observer notifications using generated factory methods.\n        /// Similar to SimpleNotification test but uses the generated factory pattern\n        /// to create observer references, verifying both approaches work identically.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ObserverTest_SimpleNotification_GeneratedFactory()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_SimpleNotification_Callback, result, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            await grain.Subscribe(reference);\n            await grain.SetA(3);\n            await grain.SetB(2);\n\n            Assert.True(await result.WaitForFinished(timeout));\n\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n        }\n\n        private void ObserverTest_SimpleNotification_Callback(int a, int b, AsyncResultHandle result)\n        {\n            callbackCounter++;\n            this.Logger.LogInformation(\"Invoking ObserverTest_SimpleNotification_Callback for {CallbackCounter} time with a = {A} and b = {B}\", this.callbackCounter, a, b);\n\n            if (a == 3 && b == 0)\n                callbacksReceived[0] = true;\n            else if (a == 3 && b == 2)\n                callbacksReceived[1] = true;\n            else\n                throw new ArgumentOutOfRangeException(\"Unexpected callback with values: a=\" + a + \",b=\" + b);\n\n            if (callbackCounter == 1)\n            {\n                // Allow for callbacks occurring in any order\n                Assert.True(callbacksReceived[0] || callbacksReceived[1]);\n            }\n            else if (callbackCounter == 2)\n            {\n                Assert.True(callbacksReceived[0] && callbacksReceived[1]);\n                result.Done = true;\n            }\n            else\n            {\n                Assert.True(false);\n            }\n        }\n\n        /// <summary>\n        /// Tests that subscribing the same observer reference twice is prevented.\n        /// Verifies that Orleans detects and rejects duplicate subscriptions\n        /// to prevent duplicate notifications and maintain subscription integrity.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task ObserverTest_DoubleSubscriptionSameReference()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_DoubleSubscriptionSameReference_Callback, result, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            await grain.Subscribe(reference);\n            await grain.SetA(1); // Use grain\n            try\n            {\n                await grain.Subscribe(reference);\n            }\n            catch (TimeoutException)\n            {\n                throw;\n            }\n            catch (Exception exc)\n            {\n                Exception baseException = exc.GetBaseException();\n                this.Logger.LogInformation(baseException, \"Received exception\");\n                Assert.IsAssignableFrom<OrleansException>(baseException);\n                if (!baseException.Message.StartsWith(\"Cannot subscribe already subscribed observer\"))\n                {\n                    Assert.Fail(\"Unexpected exception message: \" + baseException);\n                }\n            }\n\n            await grain.SetA(2); // Use grain\n\n            Assert.False(await result.WaitForFinished(timeout), $\"Should timeout waiting {timeout} for SetA(2)\");\n\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n        }\n\n        private void ObserverTest_DoubleSubscriptionSameReference_Callback(int a, int b, AsyncResultHandle result)\n        {\n            callbackCounter++;\n            this.Logger.LogInformation(\"Invoking ObserverTest_DoubleSubscriptionSameReference_Callback for {CallbackCounter} time with a={A} and b={B}\", this.callbackCounter, a, b);\n            Assert.True(callbackCounter <= 2, \"Callback has been called more times than was expected \" + callbackCounter);\n            if (callbackCounter == 2)\n            {\n                result.Continue = true;\n            }\n        }\n\n        /// <summary>\n        /// Tests the subscribe/unsubscribe lifecycle for observers.\n        /// Verifies that observers receive notifications after subscribing,\n        /// stop receiving them after unsubscribing, and that the unsubscribe\n        /// operation properly cleans up the subscription.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task ObserverTest_SubscribeUnsubscribe()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_SubscribeUnsubscribe_Callback, result, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            await grain.Subscribe(reference);\n            await grain.SetA(5);\n            Assert.True(await result.WaitForContinue(timeout), $\"Should not timeout waiting {timeout} for SetA\");\n\n            await grain.Unsubscribe(reference);\n            await grain.SetB(3);\n\n            Assert.False(await result.WaitForFinished(timeout), $\"Should timeout waiting {timeout} for SetB\");\n\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n        }\n\n        private void ObserverTest_SubscribeUnsubscribe_Callback(int a, int b, AsyncResultHandle result)\n        {\n            callbackCounter++;\n            this.Logger.LogInformation(\"Invoking ObserverTest_SubscribeUnsubscribe_Callback for {CallbackCounter} time with a = {A} and b = {B}\", this.callbackCounter, a, b);\n            Assert.True(callbackCounter < 2, \"Callback has been called more times than was expected.\");\n\n            Assert.Equal(5, a);\n            Assert.Equal(0, b);\n\n            result.Continue = true;\n        }\n\n\n        /// <summary>\n        /// Tests unsubscribing an observer that was never subscribed.\n        /// Verifies that attempting to unsubscribe a non-existent subscription\n        /// is handled gracefully without causing system errors.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ObserverTest_Unsubscribe()\n        {\n            TestInitialize();\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(null, null, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            try\n            {\n                await grain.Unsubscribe(reference);\n\n                this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n            }\n            catch (TimeoutException)\n            {\n                throw;\n            }\n            catch (Exception exc)\n            {\n                Exception baseException = exc.GetBaseException();\n                if (!(baseException is OrleansException))\n                    Assert.True(false);\n            }\n        }\n\n        /// <summary>\n        /// Tests multiple different observers subscribing to the same grain.\n        /// Verifies that a grain can maintain multiple observer subscriptions\n        /// and correctly notify all registered observers of state changes.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ObserverTest_DoubleSubscriptionDifferentReferences()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_DoubleSubscriptionDifferentReferences_Callback, result, this.Logger);\n            ISimpleGrainObserver reference1 = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            this.observer2 = new SimpleGrainObserver(this.ObserverTest_DoubleSubscriptionDifferentReferences_Callback, result, this.Logger);\n            ISimpleGrainObserver reference2 = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer2);\n            await grain.Subscribe(reference1);\n            await grain.Subscribe(reference2);\n            grain.SetA(6).Ignore();\n\n            Assert.True(await result.WaitForFinished(timeout), $\"Should not timeout waiting {timeout} for SetA\");\n\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference1);\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference2);\n        }\n\n        private void ObserverTest_DoubleSubscriptionDifferentReferences_Callback(int a, int b, AsyncResultHandle result)\n        {\n            callbackCounter++;\n            this.Logger.LogInformation(\"Invoking ObserverTest_DoubleSubscriptionDifferentReferences_Callback for {CallbackCounter} time with a = {A} and b = {B}\", this.callbackCounter, a, b);\n            Assert.True(callbackCounter < 3, \"Callback has been called more times than was expected.\");\n\n            Assert.Equal(6, a);\n            Assert.Equal(0, b);\n\n            if (callbackCounter == 2)\n                result.Done = true;\n        }\n\n        /// <summary>\n        /// Tests that deleting an observer reference stops notifications.\n        /// Verifies that when an observer reference is deleted using\n        /// DeleteObjectReference, the grain can no longer send notifications\n        /// to that observer, demonstrating automatic cleanup behavior.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task ObserverTest_DeleteObject()\n        {\n            TestInitialize();\n            var result = new AsyncResultHandle();\n\n            ISimpleObserverableGrain grain = GetGrain();\n            this.observer1 = new SimpleGrainObserver(this.ObserverTest_DeleteObject_Callback, result, this.Logger);\n            ISimpleGrainObserver reference = this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer1);\n            await grain.Subscribe(reference);\n            await grain.SetA(5);\n            Assert.True(await result.WaitForContinue(timeout), $\"Should not timeout waiting {timeout} for SetA\");\n            this.GrainFactory.DeleteObjectReference<ISimpleGrainObserver>(reference);\n            await grain.SetB(3);\n\n            Assert.False(await result.WaitForFinished(timeout), $\"Should timeout waiting {timeout} for SetB\");\n        }\n\n        private void ObserverTest_DeleteObject_Callback(int a, int b, AsyncResultHandle result)\n        {\n            callbackCounter++;\n            this.Logger.LogInformation(\"Invoking ObserverTest_DeleteObject_Callback for {CallbackCounter} time with a = {A} and b = {B}\", this.callbackCounter, a, b);\n            Assert.True(callbackCounter < 2, \"Callback has been called more times than was expected.\");\n\n            Assert.Equal(5, a);\n            Assert.Equal(0, b);\n\n            result.Continue = true;\n        }\n\n        /// <summary>\n        /// Verifies that only grain references can be used as observers.\n        /// Tests that attempting to subscribe a regular object (not created via\n        /// CreateObjectReference) throws an appropriate exception, enforcing\n        /// the requirement that observers must be grain references.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ObserverTest_SubscriberMustBeGrainReference()\n        {\n            TestInitialize();\n            await Assert.ThrowsAsync<NotSupportedException>(async () =>\n            {\n                var result = new AsyncResultHandle();\n\n                ISimpleObserverableGrain grain = this.GetGrain();\n                this.observer1 = new SimpleGrainObserver(this.ObserverTest_SimpleNotification_Callback, result, this.Logger);\n                ISimpleGrainObserver reference = this.observer1;\n                // Should be: this.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(obj);\n                await grain.Subscribe(reference);\n                // Not reached\n            });\n        }\n\n        /// <summary>\n        /// Tests that CreateObjectReference validates its arguments correctly.\n        /// Verifies that attempting to create object references from invalid types\n        /// (like Grain classes or existing grain references) throws appropriate\n        /// exceptions, ensuring type safety in the observer pattern.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public void ObserverTest_CreateObjectReference_ThrowsForInvalidArgumentTypes()\n        {\n            TestInitialize();\n\n            // Attempt to create an object reference to a Grain class.\n            Assert.Throws<ArgumentException>(() => this.Client.CreateObjectReference<ISimpleGrainObserver>(new DummyObserverGrain()));\n\n            // Attempt to create an object reference to an existing GrainReference.\n            var observer = new DummyObserver();\n            var reference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);\n            Assert.Throws<ArgumentException>(() => this.Client.CreateObjectReference<ISimpleGrainObserver>(reference));\n        }\n\n        public class DummyObserverGrain : Grain, ISimpleGrainObserver\n        {\n            public void StateChanged(int a, int b) { }\n        }\n\n        public class DummyObserver : ISimpleGrainObserver\n        {\n            public void StateChanged(int a, int b) { }\n        }\n\n        internal class SimpleGrainObserver : ISimpleGrainObserver\n        {\n            private readonly Action<int, int, AsyncResultHandle> action;\n            private readonly AsyncResultHandle result;\n\n            private readonly ILogger logger;\n\n            public SimpleGrainObserver(Action<int, int, AsyncResultHandle> action, AsyncResultHandle result, ILogger logger)\n            {\n                this.action = action;\n                this.result = result;\n                this.logger = logger;\n            }\n\n            public void StateChanged(int a, int b)\n            {\n                this.logger.LogDebug(\"SimpleGrainObserver.StateChanged a={A} b={B}\", a, b);\n                action?.Invoke(a, b, result);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/OneWayCallTests.cs",
    "content": "using Orleans.Internal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans one-way method calls.\n    /// One-way methods are grain methods that return immediately to the caller\n    /// without waiting for the method execution to complete. This fire-and-forget\n    /// pattern is useful for notifications, logging, and other scenarios where\n    /// the caller doesn't need confirmation of completion or results.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"OneWay\")]\n    public class OneWayCallTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public OneWayCallTests(DefaultClusterFixture fixture) : base(fixture) { }\n\n        /// <summary>\n        /// Tests that one-way methods return synchronously when called from a client.\n        /// Verifies that:\n        /// - The Task/ValueTask completes immediately without waiting for execution\n        /// - The method still executes on the grain (observable via side effects)\n        /// - Exceptions in one-way methods don't propagate to the caller\n        /// </summary>\n        [Fact]\n        public async Task OneWayMethodsReturnSynchronously_ViaClient()\n        {\n            var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n\n            var observer = new SimpleGrainObserver();\n            var task = grain.Notify(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));\n            Assert.True(task.Status == TaskStatus.RanToCompletion, \"Task should be synchronously completed.\");\n            await observer.ReceivedValue.WaitAsync(TimeSpan.FromSeconds(10));\n            var count = await grain.GetCount();\n            Assert.Equal(1, count);\n\n            // This should not throw.\n            task = grain.ThrowsOneWay();\n            Assert.True(task.Status == TaskStatus.RanToCompletion, \"Task should be synchronously completed.\");\n        }\n\n        /// <summary>\n        /// Tests that one-way methods return synchronously when called from another grain.\n        /// Verifies that grain-to-grain one-way calls also complete immediately,\n        /// allowing the calling grain to continue processing without blocking\n        /// on the target grain's execution.\n        /// </summary>\n        [Fact]\n        public async Task OneWayMethodReturnSynchronously_ViaGrain()\n        {\n            var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n            var otherGrain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n\n            var observer = new SimpleGrainObserver();\n            var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);\n            var completedSynchronously = await grain.NotifyOtherGrain(otherGrain, observerReference);\n            Assert.True(completedSynchronously, \"Task should be synchronously completed.\");\n            await observer.ReceivedValue.WaitAsync(TimeSpan.FromSeconds(10));\n            var count = await otherGrain.GetCount();\n            Assert.Equal(1, count);\n        }\n\n        /// <summary>\n        /// Tests one-way methods that return ValueTask instead of Task.\n        /// Verifies that ValueTask-based one-way methods behave identically\n        /// to Task-based ones, completing synchronously while still executing\n        /// the method logic asynchronously on the target grain.\n        /// </summary>\n        [Fact]\n        public async Task OneWayMethodsReturnSynchronously_ViaClient_ValueTask()\n        {\n            var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n\n            var observer = new SimpleGrainObserver();\n            var task = grain.NotifyValueTask(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));\n            Assert.True(task.IsCompleted, \"ValueTask should be synchronously completed.\");\n            await observer.ReceivedValue.WaitAsync(TimeSpan.FromSeconds(10));\n            var count = await grain.GetCount();\n            Assert.Equal(1, count);\n\n            // This should not throw.\n            task = grain.ThrowsOneWayValueTask();\n            Assert.True(task.IsCompleted, \"Task should be synchronously completed.\");\n        }\n\n        /// <summary>\n        /// Tests ValueTask-based one-way methods called from another grain.\n        /// Ensures that the ValueTask variant of one-way methods maintains\n        /// the same fire-and-forget semantics in grain-to-grain communication.\n        /// </summary>\n        [Fact]\n        public async Task OneWayMethodReturnSynchronously_ViaGrain_ValueTask()\n        {\n            var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n            var otherGrain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n\n            var observer = new SimpleGrainObserver();\n            var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);\n            var completedSynchronously = await grain.NotifyOtherGrainValueTask(otherGrain, observerReference);\n            Assert.True(completedSynchronously, \"Task should be synchronously completed.\");\n            await observer.ReceivedValue.WaitAsync(TimeSpan.FromSeconds(10));\n            var count = await otherGrain.GetCount();\n            Assert.Equal(1, count);\n        }\n\n        private class SimpleGrainObserver : ISimpleGrainObserver\n        {\n            private readonly TaskCompletionSource<int> completion = new TaskCompletionSource<int>();\n            public Task ReceivedValue => this.completion.Task;\n            public void StateChanged(int a, int b)\n            {\n                this.completion.SetResult(b);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/Orleans.DefaultCluster.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"NodaTime\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.FSharp\\Orleans.Serialization.FSharp.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.DurableJobs.Tests\\Orleans.DurableJobs.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrainInterfaces\\TestGrainInterfaces.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrains\\TestGrains.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.CodeGenerator.Tests\\Orleans.CodeGenerator.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/PolymorphicInterfaceTest.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for polymorphic grain interfaces in Orleans.\n    /// Demonstrates how grains can implement multiple interfaces with inheritance\n    /// hierarchies, and how grain references can be cast between compatible interfaces.\n    /// This enables object-oriented patterns where grains expose different levels\n    /// of functionality through interface inheritance.\n    /// </summary>\n    public class PolymorphicInterfaceTest : HostedTestClusterEnsureDefaultStarted\n    {\n        public PolymorphicInterfaceTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests basic polymorphic interface method calls.\n        /// Verifies that a grain implementing interface IA can be accessed\n        /// through that interface and all methods are properly dispatched.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic_SimpleTest()\n        {\n            var grainFullName = typeof(PolymorphicTestGrain).FullName;\n            IA IARef = this.GrainFactory.GetGrain<IA>(GetRandomGrainId(), grainFullName);\n            Assert.Equal(\"A1\", await IARef.A1Method());\n            Assert.Equal(\"A2\", await IARef.A2Method());\n            Assert.Equal(\"A3\", await IARef.A3Method());\n        }\n\n        /// <summary>\n        /// Tests upcasting grain references through interface inheritance hierarchies.\n        /// Verifies that a grain reference can be cast to any interface in its\n        /// inheritance chain and that methods from all interfaces remain accessible\n        /// after casting. Demonstrates interface covariance in grain references.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic_UpCastTest()\n        {\n            var grainFullName = typeof(PolymorphicTestGrain).FullName;\n            IC ICRef = this.GrainFactory.GetGrain<IC>(GetRandomGrainId(), grainFullName);\n            IA IARef = ICRef; // cast to polymorphic interface\n            Assert.Equal(\"A1\", await IARef.A1Method());\n            Assert.Equal(\"A2\", await IARef.A2Method());\n            Assert.Equal(\"A3\", await IARef.A3Method());\n\n            IB IBRef = ICRef; // cast to polymorphic interface\n            Assert.Equal(\"B1\", await IBRef.B1Method());\n            Assert.Equal(\"B2\", await IBRef.B2Method());\n            Assert.Equal(\"B3\", await IBRef.B3Method());\n\n            IF IFRef = this.GrainFactory.GetGrain<IF>(GetRandomGrainId(), grainFullName);\n\n            Assert.Equal(\"F1\", await IFRef.F1Method());\n            Assert.Equal(\"F2\", await IFRef.F2Method());\n            Assert.Equal(\"F3\", await IFRef.F3Method());\n\n            IE IERef = IFRef; // cast to polymorphic interface\n            Assert.Equal(\"E1\", await IERef.E1Method());\n            Assert.Equal(\"E2\", await IERef.E2Method());\n            Assert.Equal(\"E3\", await IERef.E3Method());\n            \n        }\n\n        /// <summary>\n        /// Tests factory methods that return polymorphic grain references.\n        /// Verifies that grain factory can create grains using one interface type\n        /// but return them as a different compatible interface type,\n        /// enabling factory patterns with interface abstraction.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic_FactoryMethods()\n        {\n            var grainFullName = typeof(PolymorphicTestGrain).FullName;\n            IC ICRef = this.GrainFactory.GetGrain<IF>(GetRandomGrainId(), grainFullName); // FRef factory method returns a polymorphic reference to ICRef\n            Assert.Equal(\"B2\", await ICRef.B2Method());\n\n            IA IARef = this.GrainFactory.GetGrain<ID>(GetRandomGrainId(), grainFullName); // DRef factory method returns a polymorphic reference to IARef\n            Assert.Equal(\"A1\", await IARef.A1Method());\n        }\n\n        /// <summary>\n        /// Tests a service-style grain that implements multiple interfaces.\n        /// Verifies that a single grain can expose multiple sets of functionality\n        /// through different interfaces, similar to a service exposing multiple contracts.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic_ServiceType()\n        {\n            var grainFullName = typeof(ServiceType).FullName;\n            IServiceType serviceRef = this.GrainFactory.GetGrain<IServiceType>(GetRandomGrainId(), grainFullName);\n            Assert.Equal(\"A1\", await serviceRef.A1Method());\n            Assert.Equal(\"A2\", await serviceRef.A2Method());\n            Assert.Equal(\"A3\", await serviceRef.A3Method());\n            Assert.Equal(\"B1\", await serviceRef.B1Method());\n            Assert.Equal(\"B2\", await serviceRef.B2Method());\n            Assert.Equal(\"B3\", await serviceRef.B3Method());\n        }\n\n        /// <summary>\n        /// Tests resolution of ambiguous methods in diamond inheritance scenarios.\n        /// When multiple interfaces define the same method signature, verifies that\n        /// casting to specific interfaces correctly resolves which implementation\n        /// is called, following C# interface inheritance rules.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic_InheritedMethodAmbiguity()\n        {\n            // Tests interface inheritance hierarchies which involve duplicate method names, requiring casting to resolve the ambiguity.\n            var grainFullName = typeof(ServiceType).FullName;\n            var serviceRef = this.GrainFactory.GetGrain<IServiceType>(GetRandomGrainId(), grainFullName);\n            var ia = (IA)serviceRef;\n            var ib = (IB)serviceRef;\n            var ic = (IC)serviceRef;\n            Assert.Equal(\"IA\", await ia.CommonMethod());\n            Assert.Equal(\"IB\", await ib.CommonMethod());\n            Assert.Equal(\"IC\", await ic.CommonMethod());\n        }\n\n        /// <summary>\n        /// Comprehensive test for complex polymorphic grain scenarios.\n        /// Tests a derived service type that implements multiple interface hierarchies,\n        /// verifying that:\n        /// - All interfaces in the inheritance chain are accessible\n        /// - Cross-casting between unrelated interfaces works when supported\n        /// - Derived interface methods are available alongside base methods\n        /// This consolidates all polymorphic grain reference use cases.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cast\")]\n        public async Task Polymorphic__DerivedServiceType()\n        {\n            var grainFullName = typeof(DerivedServiceType).FullName;\n            IDerivedServiceType derivedRef = this.GrainFactory.GetGrain<IDerivedServiceType>(GetRandomGrainId(), grainFullName);\n\n            IA IARef = derivedRef;\n            Assert.Equal(\"A1\", await IARef.A1Method());\n            Assert.Equal(\"A2\", await IARef.A2Method());\n            Assert.Equal(\"A3\", await IARef.A3Method());\n\n\n            IB IBRef = (IB)IARef; // this could result in an invalid cast exception but it shoudn't because we have a priori knowledge that DerivedServiceType implements the interface\n            Assert.Equal(\"B1\", await IBRef.B1Method());\n            Assert.Equal(\"B2\", await IBRef.B2Method());\n            Assert.Equal(\"B3\", await IBRef.B3Method());\n\n            IF IFRef = (IF)IBRef;\n            Assert.Equal(\"F1\", await IFRef.F1Method());\n            Assert.Equal(\"F2\", await IFRef.F2Method());\n            Assert.Equal(\"F3\", await IFRef.F3Method());\n\n            IE IERef = (IE)IFRef;\n            Assert.Equal(\"E1\", await IERef.E1Method());\n            Assert.Equal(\"E2\", await IERef.E2Method());\n            Assert.Equal(\"E3\", await IERef.E3Method());\n\n            IH IHRef = derivedRef;\n            Assert.Equal(\"H1\", await IHRef.H1Method());\n            Assert.Equal(\"H2\", await IHRef.H2Method());\n            Assert.Equal(\"H3\", await IHRef.H3Method());\n\n            IServiceType serviceTypeRef = derivedRef; // upcast the pointer reference\n            Assert.Equal(\"ServiceTypeMethod1\", await serviceTypeRef.ServiceTypeMethod1());\n            Assert.Equal(\"ServiceTypeMethod2\", await serviceTypeRef.ServiceTypeMethod2());\n            Assert.Equal(\"ServiceTypeMethod3\", await serviceTypeRef.ServiceTypeMethod3());\n\n            Assert.Equal(\"DerivedServiceTypeMethod1\", await derivedRef.DerivedServiceTypeMethod1());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ProviderTests.cs",
    "content": "using Xunit;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests for Orleans providers and grain extensions.\n    /// Providers are pluggable components that extend grain functionality,\n    /// while grain extensions allow grains to expose additional interfaces\n    /// that can be dynamically installed. This enables modular grain design\n    /// where optional functionality can be added as needed.\n    /// </summary>\n    public class ProviderTests : OrleansTestingBase, IClassFixture<ProviderTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public ProviderTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<Configurator>();\n            }\n\n            private class Configurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddGrainExtension<IAutoExtension, AutoExtension>();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Tests grain extension installation and invocation.\n        /// Verifies that:\n        /// - Calling uninstalled extensions throws GrainExtensionNotInstalledException\n        /// - Extensions can be dynamically installed on grains\n        /// - Installed extensions can be invoked through their interfaces\n        /// This demonstrates the dynamic nature of grain extensions.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Providers\")]\n        public async Task Providers_TestExtensions()\n        {\n            IExtensionTestGrain grain = this.fixture.GrainFactory.GetGrain<IExtensionTestGrain>(GetRandomGrainId());\n            ITestExtension extension = grain.AsReference<ITestExtension>();\n            bool exceptionThrown = true;\n\n            try\n            {\n                var p1 = extension.CheckExtension_1();\n                await p1;\n                exceptionThrown = false;\n            }\n            catch (GrainExtensionNotInstalledException)\n            {\n                // This is the expected behavior\n            }\n            catch (AggregateException ex)\n            {\n                var baseEx = ex.GetBaseException();\n                if (baseEx is GrainExtensionNotInstalledException)\n                {\n                    // This is also the expected behavior\n                }\n                else\n                {\n                    Assert.Fail(\"Incorrect exception thrown when an unimplemented method is invoked: \" + baseEx);\n                }\n            }\n            catch (Exception ex1)\n            {\n                Assert.Fail(\"Incorrect exception thrown when an unimplemented method is invoked: \" + ex1);\n            }\n\n            if (!exceptionThrown)\n            {\n                Assert.Fail(\"Expected exception not thrown when no extension configured\");\n            }\n\n            var p2 = grain.InstallExtension(\"test\");\n            await p2;\n\n            try\n            {\n                var p1 = extension.CheckExtension_1();\n                await p1;\n                Assert.Equal(\"test\", await p1);\n            }\n            catch (Exception exc)\n            {\n                Assert.Fail(\"Unexpected exception thrown when extension is configured. Exc = \" + exc);\n            }\n\n            try\n            {\n                var p1 = extension.CheckExtension_2();\n                await p1;\n                Assert.Equal(\"23\", await p1);\n            }\n            catch (Exception exc)\n            {\n                Assert.Fail(\"Unexpected exception thrown when extension is configured. Exc = \" + exc);\n            }\n        }\n\n        /// <summary>\n        /// Tests activating a non-generic extension on a generic grain interface.\n        /// Verifies that when a generic grain has a non-generic extension,\n        /// the grain can be activated through the extension reference without\n        /// issues, demonstrating extension compatibility with generic grains.\n        /// </summary>\n        [Fact, TestCategory(\"Providers\"), TestCategory(\"BVT\"), TestCategory(\"Cast\"), TestCategory(\"Generics\")]\n        public async Task Providers_ActivateNonGenericExtensionOfGenericInterface()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGenericGrainWithNonGenericExtension<int>>(GetRandomGrainId());\n            var extension = grain.AsReference<ISimpleExtension>(); //generic base grain not yet activated - virt refs only\n\n            try\n            {\n                var res = await extension.CheckExtension_1(); //now activation occurs, but with non-generic reference\n            }\n            catch (Exception ex)\n            {\n                Assert.Fail(\"No exception should have been thrown. Ex: \" + ex.Message);\n            }\n\n            Assert.True(true);\n        }\n\n        /// <summary>\n        /// Tests referencing a non-generic extension after generic grain activation.\n        /// Verifies that after a generic grain is activated normally,\n        /// its non-generic extension can still be obtained and invoked,\n        /// ensuring extensions work correctly with already-activated generic grains.\n        /// </summary>\n        [Fact, TestCategory(\"Providers\"), TestCategory(\"BVT\"), TestCategory(\"Cast\"), TestCategory(\"Generics\")]\n        public async Task Providers_ReferenceNonGenericExtensionOfGenericInterface() {\n            var grain = this.fixture.GrainFactory.GetGrain<IGenericGrainWithNonGenericExtension<int>>(GetRandomGrainId());\n            await grain.DoSomething(); //original generic grain activates here\n\n            var extension = grain.AsReference<ISimpleExtension>();\n            try {\n                var res = await extension.CheckExtension_1();\n            }\n            catch(Exception ex) {\n                Assert.Fail(\"No exception should have been thrown. Ex: \" + ex.Message);\n            }\n\n            Assert.True(true);\n        }\n\n        /// <summary>\n        /// Tests automatic installation of grain extensions.\n        /// Verifies that extensions configured with AddGrainExtension are\n        /// automatically available on grains without manual installation,\n        /// while non-configured extensions still require explicit installation.\n        /// This demonstrates the auto-wiring capability for common extensions.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Providers\")]\n        public async Task Providers_AutoInstallExtensionTest()\n        {\n            INoOpTestGrain grain = this.fixture.GrainFactory.GetGrain<INoOpTestGrain>(GetRandomGrainId());\n            ISimpleExtension uninstalled = grain.AsReference<ISimpleExtension>();\n            IAutoExtension autoInstalled = grain.AsReference<IAutoExtension>();\n            await Assert.ThrowsAsync<GrainExtensionNotInstalledException>(() => uninstalled.CheckExtension_1());\n            await autoInstalled.CheckExtension();\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/ReminderTest.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests for Orleans Reminders functionality.\n    /// Reminders are a durable scheduling mechanism that persist across grain\n    /// deactivations and cluster restarts. Unlike timers (which are grain-local\n    /// and transient), reminders are stored in external storage and will\n    /// reliably trigger grain methods at specified intervals, making them\n    /// ideal for periodic background tasks that must survive failures.\n    /// </summary>\n    public class ReminderTest : HostedTestClusterEnsureDefaultStarted\n    {\n        public ReminderTest(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests basic reminder operations: checking existence, adding, and removing.\n        /// Verifies that:\n        /// - Non-existent reminders return false for existence checks\n        /// - Reminders can be successfully registered with a grain\n        /// - Registered reminders can be detected via existence checks\n        /// - Reminders can be removed and no longer exist afterwards\n        /// This demonstrates the fundamental CRUD operations for reminders.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Reminders\")]\n        public async Task SimpleGrainGetGrain()\n        {\n            IReminderTestGrain grain = this.GrainFactory.GetGrain<IReminderTestGrain>(GetRandomGrainId());\n            bool notExists = await grain.IsReminderExists(\"not exists\");\n            Assert.False(notExists);\n\n            await grain.AddReminder(\"dummy\");\n            Assert.True(await grain.IsReminderExists(\"dummy\"));\n\n            await grain.RemoveReminder(\"dummy\");\n            Assert.False(await grain.IsReminderExists(\"dummy\"));\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/RequestContextTest.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTDefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans Request Context functionality.\n    /// Request Context allows flowing ambient data (like correlation IDs, user context,\n    /// or request metadata) along with grain calls without explicitly passing it as\n    /// parameters. This is Orleans' equivalent of thread-local storage or async-local\n    /// storage, but designed for distributed calls across grains and silos.\n    /// </summary>\n    public class RequestContextTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public RequestContextTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests request context flowing from caller to callee.\n        /// Verifies that data set in RequestContext before a grain call\n        /// is available within the grain method execution, demonstrating\n        /// the automatic propagation of ambient context across grain boundaries.\n        /// This is useful for correlation IDs, authentication tokens, etc.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContextCallerToCalleeFlow()\n        {\n            var grain = this.GrainFactory.GetGrain<ISimplePersistentGrain>(Random.Shared.Next());\n            // Set context to send to the grain\n            RequestContext.Set(\"GrainInfo\", 10);\n            // This grain method reads the context and returns it\n            var infoFromGrain = await grain.GetRequestContext();\n            Assert.NotNull(infoFromGrain);\n            Assert.True((int)infoFromGrain == 10);\n\n            Assert.Contains(\"GrainInfo\", RequestContext.Keys);\n        }\n\n        /// <summary>\n        /// Tests request context flowing from callee back to caller.\n        /// Would verify that data set in RequestContext within a grain method\n        /// is available to the caller after the call completes.\n        /// NOTE: This test is currently skipped as the feature may not be fully supported.\n        /// Request context typically flows one-way (caller to callee) for isolation.\n        /// </summary>\n        [Fact(Skip = \"Was failing before (just masked as a Pass), needs fixing or removing\"), TestCategory(\"RequestContext\"), TestCategory(\"Functional\")]\n        public async Task RequestContextCalleeToCallerFlow()\n        {\n            var grain = this.GrainFactory.GetGrain<ISimplePersistentGrain>(Random.Shared.Next());\n            // This method in the grain does RequestContext.Set\n            await grain.SetRequestContext(15);\n            // Read the info set in the grain\n            var infoFromGrain = RequestContext.Get(\"GrainInfo\");\n            Assert.NotNull(infoFromGrain);\n            Assert.True((int)infoFromGrain == 15);\n\n            Assert.Contains(\"GrainInfo\", RequestContext.Keys);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/SerializationTests/JsonSerializerTests.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests;\n\n/// <summary>\n/// Tests System.Text.Json serialization of Orleans types including GrainId with various collection types.\n/// </summary>\n[TestCategory(\"Serialization\"), TestCategory(\"BVT\")]\npublic class JsonSerializerTests : HostedTestClusterEnsureDefaultStarted\n{\n    public JsonSerializerTests(DefaultClusterFixture fixture) : base(fixture)\n    {\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n    public void Serialization_GrainId_RoundTrip()\n    {\n        var grainId = GrainId.Create(\"type\", \"key\");\n        var copy = HostedCluster.RoundTripSystemTextJsonSerialization(grainId);\n\n        Assert.IsAssignableFrom<GrainId>(copy);\n        Assert.Equal(grainId, copy);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n    public void Serialization_WithGrainIdType_RoundTrip()\n    {\n        var grainId = GrainId.Create(\"type\", \"key\");\n        WithGrainIdType data = new(grainId);\n\n        var copy = HostedCluster.RoundTripSystemTextJsonSerialization(data);\n\n        Assert.IsAssignableFrom<WithGrainIdType>(copy);\n        Assert.Equal(grainId, copy.GrainId);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n    public void Serialization_WithGrainIdMapType_RoundTrip()\n    {\n        var grainId1 = GrainId.Create(\"type1\", \"key1\");\n        var grainId2 = GrainId.Create(\"type2\", \"key2\");\n\n        var map = new Dictionary<GrainId, int>();\n        map.Add(grainId1, 1);\n        map.Add(grainId2, 2);\n\n        WithGrainIdMapType data = new(map);\n\n        var copy = HostedCluster.RoundTripSystemTextJsonSerialization(data);\n\n        Assert.IsAssignableFrom<WithGrainIdMapType>(copy);\n        Assert.Equal(map, copy.Map);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n    public void Serialization_WithGrainIdConcurrentDictionaryType_RoundTrip()\n    {\n        var grainId = GrainId.Create(\"type\", \"key\");\n        var map = new ConcurrentDictionary<GrainId, int>();\n        map.TryAdd(grainId, 1);\n\n        WithGrainIdMapType data = new(map);\n\n        var copy = HostedCluster.RoundTripSystemTextJsonSerialization(data);\n\n        Assert.IsAssignableFrom<WithGrainIdMapType>(copy);\n        Assert.Equal(map, copy.Map);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n    public void Serialization_WithGrainIdHashSetType_RoundTrip()\n    {\n        var grainId = GrainId.Create(\"type\", \"key\");\n        var set = new HashSet<GrainId>();\n        set.Add(grainId);\n\n        WithGrainIdSetType data = new(set);\n\n        var copy = HostedCluster.RoundTripSystemTextJsonSerialization(data);\n\n        Assert.IsAssignableFrom<WithGrainIdSetType>(copy);\n        Assert.Equal(set, copy.Set);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/SerializationTests/RoundTripSerializerTests.cs",
    "content": "using System.Threading.Tasks;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.SerializerTests\n{\n    /// <summary>\n    /// Tests serialization round-trip for various data types including records, enums, and inherited generics.\n    /// </summary>\n    [TestCategory(\"Serialization\"), TestCategory(\"BVT\")]\n    public class RoundTripSerializerTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public RoundTripSerializerTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        [Fact]\n        public async Task Serialize_TestMethodResultRecord()\n        {\n            var grain = this.GrainFactory.GetGrain<IRoundtripSerializationGrain>(GetRandomGrainId());\n            RetVal retVal = await grain.GetRetValForParamVal(new ParamVal(42));\n            Assert.Equal(42, retVal.Value);\n        }\n\n        [Fact]\n        public async Task Serialize_TestMethodResultEnum()\n        {\n            var grain = this.GrainFactory.GetGrain<IRoundtripSerializationGrain>(GetRandomGrainId());\n            CampaignEnemyTestType result = await grain.GetEnemyType();\n            Assert.Equal(CampaignEnemyTestType.Enemy2, result); //Enum return value wasn't transmitted properly\n        }\n\n        [Fact]\n        public async Task Serialize_TestMethodResultWithInheritedClosedGeneric()\n        {\n            var grain = this.GrainFactory.GetGrain<IRoundtripSerializationGrain>(GetRandomGrainId());\n            object result = await grain.GetClosedGenericValue();\n            Assert.NotNull(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/SerializationTests/SerializationTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Tests deep copy and serialization round-trip for complex types including value types and types with custom activators.\n    /// </summary>\n    public class SerializationTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public SerializationTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_LargeTestData()\n        {\n            var data = new LargeTestData\n                           {\n                               Description =\n                                   \"This is a test. This is only a test. In the event of a real execution, this would contain actual data.\",\n                               EnumValue = TestEnum.First\n                           };\n            data.SetBit(13);\n            data.SetEnemy(17, CampaignEnemyTestType.Enemy1);\n\n            object obj = HostedCluster.DeepCopy(data);\n            Assert.IsAssignableFrom<LargeTestData>(obj);\n\n            object copy = HostedCluster.RoundTripSerializationForTesting(obj);\n            Assert.IsAssignableFrom<LargeTestData>(copy);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_ValueType_Phase1()\n        {\n            ValueTypeTestData data = new ValueTypeTestData(4);\n\n            object obj = HostedCluster.DeepCopy(data);\n\n            Assert.IsAssignableFrom<ValueTypeTestData>(obj);\n            Assert.Equal(4, ((ValueTypeTestData)obj).Value);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_ValueType_Phase2()\n        {\n            ValueTypeTestData data = new ValueTypeTestData(4);\n\n            object copy = HostedCluster.RoundTripSerializationForTesting(data);\n\n            Assert.IsAssignableFrom<ValueTypeTestData>(copy);\n            Assert.Equal(4, ((ValueTypeTestData)copy).Value);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_DefaultActivatorValueTypeWithRequiredField_Phase1()\n        {\n            DefaultActivatorValueTypeWithRequiredField data = new(4);\n\n            object obj = HostedCluster.DeepCopy(data);\n\n            Assert.IsAssignableFrom<DefaultActivatorValueTypeWithRequiredField>(obj);\n            Assert.Equal(4, ((DefaultActivatorValueTypeWithRequiredField)obj).Value);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_DefaultActivatorValueTypeWithRequiredField_Phase2()\n        {\n            DefaultActivatorValueTypeWithRequiredField data = new(4);\n\n            object copy = HostedCluster.RoundTripSerializationForTesting(data);\n\n            Assert.IsAssignableFrom<DefaultActivatorValueTypeWithRequiredField>(copy);\n            Assert.Equal(4, ((DefaultActivatorValueTypeWithRequiredField)copy).Value);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_DefaultActivatorValueTypeWithUseActivator_Phase1()\n        {\n            DefaultActivatorValueTypeWithUseActivator data = new();\n\n            object obj = HostedCluster.DeepCopy(data);\n\n            Assert.IsAssignableFrom<DefaultActivatorValueTypeWithUseActivator>(obj);\n            Assert.Equal(4, ((DefaultActivatorValueTypeWithUseActivator)obj).Value);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Serialization\")]\n        public void Serialization_DefaultActivatorValueTypeWithUseActivator_Phase2()\n        {\n            DefaultActivatorValueTypeWithUseActivator data = new();\n\n            object copy = HostedCluster.RoundTripSerializationForTesting(data);\n\n            Assert.IsAssignableFrom<DefaultActivatorValueTypeWithUseActivator>(copy);\n            Assert.Equal(4, ((DefaultActivatorValueTypeWithUseActivator)copy).Value);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/SiloRoleBasedPlacementDirectorTests.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for silo role-based placement strategy in Orleans.\n    /// This placement strategy allows grains to be placed on specific silos\n    /// based on silo roles/names. This is useful for scenarios requiring\n    /// grain affinity to specific infrastructure (e.g., grains that need\n    /// access to local resources or should run on specialized hardware).\n    /// </summary>\n    public class SiloRoleBasedPlacementDirectorTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public SiloRoleBasedPlacementDirectorTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests placement failure when the requested silo role doesn't exist.\n        /// Verifies that attempting to place a grain on a non-existent silo role\n        /// throws an appropriate exception, ensuring the system fails fast\n        /// when misconfigured rather than silently placing grains incorrectly.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\")]\n        public async Task SiloRoleBasedPlacementDirector_CantFindSilo()\n        {\n            var grain = this.GrainFactory.GetGrain<ISiloRoleBasedPlacementGrain>(\"Sibyl.Silo\");\n            await Assert.ThrowsAsync<OrleansException>(() => grain.Ping());\n        }\n\n        /// <summary>\n        /// Tests successful placement on a silo with the requested role.\n        /// Verifies that grains configured for role-based placement are\n        /// correctly activated on silos matching the specified role,\n        /// demonstrating the basic functionality of targeted placement.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\")]\n        public async Task SiloRoleBasedPlacementDirector_CanFindSilo()\n        {\n            var grain = this.GrainFactory.GetGrain<ISiloRoleBasedPlacementGrain>(\"testhost\");\n            bool result = await grain.Ping();\n            Assert.True(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/SimpleGrainTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Basic tests for simple grain functionality in Orleans.\n    /// These tests verify fundamental grain operations including activation,\n    /// method invocation, state management, and basic control flow.\n    /// SimpleGrain represents the most basic grain pattern with getter/setter\n    /// methods and demonstrates core Orleans programming model concepts.\n    /// </summary>\n    public class SimpleGrainTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public SimpleGrainTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        public ISimpleGrain GetSimpleGrain()\n        {\n            return this.GrainFactory.GetGrain<ISimpleGrain>(GetRandomGrainId(), SimpleGrain.SimpleGrainNamePrefix);\n        }\n\n        /// <summary>\n        /// Tests basic grain activation and method invocation.\n        /// Verifies that a grain can be obtained from the factory and\n        /// that methods can be successfully called on it, demonstrating\n        /// the fundamental grain lifecycle and RPC mechanism.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task SimpleGrainGetGrain()\n        {\n            ISimpleGrain grain = GetSimpleGrain();\n            _ = await grain.GetAxB();\n        }\n\n        /// <summary>\n        /// Tests sequential grain method calls and state persistence.\n        /// Verifies that grain state is maintained between calls by\n        /// setting values through separate method calls and then\n        /// computing a result based on the persisted state.\n        /// Demonstrates grain activation persistence within a session.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task SimpleGrainControlFlow()\n        {\n            ISimpleGrain grain = GetSimpleGrain();\n            \n            Task setPromise = grain.SetA(2);\n            await setPromise;\n\n            setPromise = grain.SetB(3);\n            await setPromise;\n\n            Task<int> intPromise = grain.GetAxB();\n            Assert.Equal(6, await intPromise);\n        }\n\n        /// <summary>\n        /// Tests concurrent grain method calls and data consistency.\n        /// Verifies that multiple method calls can be issued concurrently\n        /// (using Task.WhenAll) and that the grain properly handles\n        /// concurrent operations while maintaining state consistency.\n        /// Demonstrates Orleans' turn-based concurrency model.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task SimpleGrainDataFlow()\n        {\n            ISimpleGrain grain = GetSimpleGrain();\n\n            Task setAPromise = grain.SetA(3);\n            Task setBPromise = grain.SetB(4);\n            await Task.WhenAll(setAPromise, setBPromise);\n            var x = await grain.GetAxB();\n\n            Assert.Equal(12, x);\n        }\n\n        /// <summary>\n        /// Tests grain activation with multiple constructors.\n        /// Would verify that grains with multiple constructors activate\n        /// using the default (parameterless) constructor.\n        /// NOTE: Currently skipped as grains with multiple constructors\n        /// require explicit registration in the current Orleans version.\n        /// </summary>\n        [Fact(Skip = \"Grains with multiple constructors are not supported without being explicitly registered.\")]\n        [TestCategory(\"BVT\")]\n        public async Task GettingGrainWithMultipleConstructorsActivesViaDefaultConstructor()\n        {\n            ISimpleGrain grain = this.GrainFactory.GetGrain<ISimpleGrain>(GetRandomGrainId(), grainClassNamePrefix: MultipleConstructorsSimpleGrain.MultipleConstructorsSimpleGrainPrefix);\n\n            var actual = await grain.GetA();\n            Assert.Equal(MultipleConstructorsSimpleGrain.ValueUsedByParameterlessConstructor, actual);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/StatelessWorkerTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace DefaultCluster.Tests.General\n{\n    /// <summary>\n    /// Tests for Orleans Stateless Worker grains.\n    /// Stateless workers are a special grain type that can have multiple activations\n    /// per silo for parallel processing. They're ideal for functional operations\n    /// that don't maintain state between calls. The [StatelessWorker] attribute\n    /// controls the maximum number of local activations, enabling horizontal\n    /// scaling within a silo for CPU-bound or I/O-bound operations.\n    /// </summary>\n    public class StatelessWorkerTests : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly int ExpectedMaxLocalActivations = StatelessWorkerGrain.MaxLocalWorkers; // System.Environment.ProcessorCount;\n        private readonly ITestOutputHelper output;\n\n        public StatelessWorkerTests(DefaultClusterFixture fixture, ITestOutputHelper output) : base(fixture)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests stateless worker behavior when constructor throws an exception.\n        /// Verifies that construction failures are properly reported to callers\n        /// and that the system remains stable even when workers fail to instantiate.\n        /// This ensures robust error handling for worker initialization.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorkerThrowExceptionConstructor()\n        {\n            var grain = this.GrainFactory.GetGrain<IStatelessWorkerExceptionGrain>(0);\n\n            for (int i = 0; i < 5; i++)\n            {\n                var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => grain.Ping());\n                Assert.Contains(\"Failed to create an instance of grain type\", ex.Message);\n                var iex = Assert.IsType<Exception>(ex.InnerException);\n                Assert.Equal(\"oops\", iex.Message);\n            }\n        }\n\n        /// <summary>\n        /// Verifies that stateless worker activations respect the maximum limit per silo.\n        /// Tests that when multiple concurrent requests are made to a stateless worker,\n        /// the number of local activations doesn't exceed the configured maximum.\n        /// This ensures the [StatelessWorker(maxLocalWorkers)] attribute is enforced,\n        /// preventing resource exhaustion from unlimited parallelism.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorkerActivationsPerSiloDoNotExceedMaxLocalWorkersCount()\n        {\n            var gatewayOptions = this.Fixture.Client.ServiceProvider.GetRequiredService<IOptions<StaticGatewayListProviderOptions>>();\n            var gatewaysCount = gatewayOptions.Value.Gateways.Count;\n            // do extra calls to trigger activation of ExpectedMaxLocalActivations local activations\n            int numberOfCalls = ExpectedMaxLocalActivations * 3 * gatewaysCount;\n\n            IStatelessWorkerGrain grain = this.GrainFactory.GetGrain<IStatelessWorkerGrain>(GetRandomGrainId());\n            List<Task> promises = new List<Task>();\n\n            // warmup\n            for (int i = 0; i < gatewaysCount; i++)\n                promises.Add(grain.LongCall());\n            await Task.WhenAll(promises);\n\n            await Task.Delay(2000);\n\n            promises.Clear();\n            var stopwatch = Stopwatch.StartNew();\n\n            for (int i = 0; i < numberOfCalls; i++)\n                promises.Add(grain.LongCall());\n            await Task.WhenAll(promises);\n\n            stopwatch.Stop();\n\n            promises.Clear();\n\n            var statsTasks = new List<Task<Tuple<Guid, string, List<Tuple<DateTime, DateTime>>>>>();\n            for (int i = 0; i < numberOfCalls; i++)\n                statsTasks.Add(grain.GetCallStats());  // gather stats\n            await Task.WhenAll(statsTasks);\n\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n            var responsesPerSilo = statsTasks.Select(t => t.Result).GroupBy(s => s.Item2);\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n            foreach (var siloGroup in responsesPerSilo)\n            {\n                var silo = siloGroup.Key;\n\n                HashSet<Guid> activations = new HashSet<Guid>();\n\n                foreach (var response in siloGroup)\n                {\n                    if (activations.Contains(response.Item1))\n                        continue; // duplicate response from the same activation\n\n                    activations.Add(response.Item1);\n\n                    output.WriteLine($\"Silo {silo} with {activations.Count} activations: Activation {response.Item1}\");\n                    int count = 1;\n                    foreach (Tuple<DateTime, DateTime> call in response.Item3)\n                        output.WriteLine($\"\\t{count++}: {LogFormatter.PrintDate(call.Item1)} - {LogFormatter.PrintDate(call.Item2)}\");\n                }\n\n                Assert.True(activations.Count <= ExpectedMaxLocalActivations, $\"activations.Count = {activations.Count} in silo {silo} but expected no more than {ExpectedMaxLocalActivations}\");\n            }\n        }\n\n        /// <summary>\n        /// Tests system stability under high concurrency with limited worker activations.\n        /// Verifies that when concurrent invocations significantly exceed the local\n        /// worker limit, the system handles message forwarding correctly without\n        /// failures. This addresses issue #6795 regarding excessive message forwards\n        /// under high concurrency.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task ManyConcurrentInvocationsOnActivationLimitedStatelessWorkerDoesNotFail()\n        {\n            // Issue #6795: significantly more concurrent invocations than the local worker limit results in too many\n            // message forwards. When the issue occurs, this test will throw an exception.\n\n            // We are trying to trigger a race condition and need more than 1 attempt to reliably reproduce the issue.\n            for (var attempt = 0; attempt < 100; attempt++)\n            {\n                var grain = this.GrainFactory.GetGrain<IStatelessWorkerGrain>(attempt);\n                await Task.WhenAll(Enumerable.Range(0, 10).Select(_ => grain.DummyCall()));\n            }\n        }\n\n        /// <summary>\n        /// Tests stateless worker behavior in multi-silo deployments.\n        /// Verifies that rapid concurrent activations across multiple silos\n        /// don't cause forwarding failures. This ensures load distribution\n        /// works correctly when workers are spread across the cluster.\n        /// NOTE: Currently skipped due to a known issue with forwarding.\n        /// </summary>\n        [SkippableFact(Skip = \"Skipping test for now, since there seems to be a bug\"), TestCategory(\"Functional\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorkerFastActivationsDontFailInMultiSiloDeployment()\n        {\n            var gatewayOptions = this.Fixture.Client.ServiceProvider.GetRequiredService<IOptions<StaticGatewayListProviderOptions>>();\n            var gatewaysCount = gatewayOptions.Value.Gateways.Count;\n\n            if (gatewaysCount < 2)\n            {\n                throw new SkipException(\"This test was created to run with more than 1 gateway. 2 is the default at the time of this writing\");\n            }\n\n            // do extra calls to trigger activation of ExpectedMaxLocalActivations local activations\n            int numberOfCalls = ExpectedMaxLocalActivations * 3 * gatewaysCount;\n\n            IStatelessWorkerGrain grain = this.GrainFactory.GetGrain<IStatelessWorkerGrain>(GetRandomGrainId());\n            List<Task> promises = new List<Task>();\n\n            for (int i = 0; i < numberOfCalls; i++)\n                promises.Add(grain.LongCall());\n            await Task.WhenAll(promises);\n\n            // Calls should not have thrown ForwardingFailed exceptions.\n        }\n\n        /// <summary>\n        /// Tests that stateless workers can use [MayInterleave] for specific methods.\n        /// Verifies that methods marked with MayInterleave can process concurrently\n        /// even within a single activation, allowing fine-grained concurrency control\n        /// for stateless workers beyond the default turn-based model.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorker_DoesNotThrow_IfMarkedWithMayInterleave()\n        {\n            var grain = GrainFactory.GetGrain<IStatelessWorkerWithMayInterleaveGrain>(0);\n            var observer = new CallbackObserver();\n            var reference = GrainFactory.CreateObjectReference<ICallbackGrainObserver>(observer);\n            var task = grain.GoFast(reference);\n            await observer.OnCallback.WaitAsync(TimeSpan.FromSeconds(10));\n            observer.Signal();\n            await task;\n        }\n\n        /// <summary>\n        /// Tests that MayInterleave predicates are properly evaluated for stateless workers.\n        /// Verifies that when the MayInterleave predicate returns false, calls are\n        /// not interleaved and execute sequentially, maintaining Orleans' turn-based\n        /// concurrency for those specific calls even in stateless workers.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorker_ShouldNotInterleaveCalls_IfMayInterleavePredicatedDoesntMatch()\n        {\n            var grain = GrainFactory.GetGrain<IStatelessWorkerWithMayInterleaveGrain>(0);\n\n            List<CallbackObserver> callbacks = [new(), new(), new()];\n            var callbackReferences = callbacks.Select(c => GrainFactory.CreateObjectReference<ICallbackGrainObserver>(c)).ToList();\n            List<Task> completions = [grain.GoSlow(callbackReferences[0]), grain.GoSlow(callbackReferences[1]), grain.GoSlow(callbackReferences[2])];\n            var callbackSignals = callbacks.Select(c => c.OnCallback).ToList();\n\n            var triggered = await Task.WhenAny(callbackSignals).WaitAsync(TimeSpan.FromSeconds(10));\n            callbackSignals.Remove(triggered);\n            await Assert.ThrowsAsync<TimeoutException>(async () => await Task.WhenAny(callbackSignals).WaitAsync(TimeSpan.FromSeconds(5)));\n            callbacks.ForEach(c => c.Signal());\n            await Task.WhenAll(completions).WaitAsync(TimeSpan.FromSeconds(10));\n        }\n\n        /// <summary>\n        /// Tests that MayInterleave allows concurrent execution when predicate matches.\n        /// Verifies that when the MayInterleave predicate returns true, multiple calls\n        /// can execute concurrently within the same stateless worker activation,\n        /// enabling maximum parallelism for suitable operations.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"StatelessWorker\")]\n        public async Task StatelessWorker_ShouldInterleaveCalls_IfMayInterleavePredicatedMatches()\n        {\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));\n            var grain = GrainFactory.GetGrain<IStatelessWorkerWithMayInterleaveGrain>(0);\n\n            List<CallbackObserver> callbacks = [new(), new(), new()];\n            var callbackReferences = callbacks.Select(c => GrainFactory.CreateObjectReference<ICallbackGrainObserver>(c)).ToList();\n            var completion = Task.WhenAll(grain.GoFast(callbackReferences[0]), grain.GoFast(callbackReferences[1]), grain.GoFast(callbackReferences[2]));\n\n            // Wait for all callbacks to be triggered simultaneously, giving up if they don't signal before the timeout.\n            await Task.WhenAll(callbacks.Select(c => c.OnCallback)).WaitAsync(cts.Token);\n            callbacks.ForEach(c => c.Signal());\n\n            await completion;\n        }\n\n        private sealed class CallbackObserver : ICallbackGrainObserver\n        {\n            private readonly TaskCompletionSource _waitAsyncTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n            private readonly TaskCompletionSource _wasCalledTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n            public void Signal() => _waitAsyncTcs.TrySetResult();\n            public Task OnCallback => _wasCalledTcs.Task;\n            async Task ICallbackGrainObserver.WaitAsync()\n            {\n                _wasCalledTcs.TrySetResult();\n                await _waitAsyncTcs.Task;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DefaultCluster.Tests/TimerOrleansTest.cs",
    "content": "using System.Diagnostics;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace DefaultCluster.Tests.TimerTests\n{\n    /// <summary>\n    /// Tests for Orleans Timer functionality.\n    /// Timers provide grain-local, non-durable periodic callbacks. Unlike reminders,\n    /// timers are active only while a grain is activated and don't persist across\n    /// deactivations. They're ideal for short-lived periodic tasks, polling,\n    /// timeouts, and other scenarios where persistence isn't required.\n    /// Timers are more efficient than reminders for high-frequency operations.\n    /// </summary>\n    public class TimerOrleansTest : HostedTestClusterEnsureDefaultStarted\n    {\n        private readonly ITestOutputHelper output;\n\n        public TimerOrleansTest(ITestOutputHelper output, DefaultClusterFixture fixture)\n            : base(fixture)\n        {\n            this.output = output;\n        }\n\n        private static async Task<int> WaitForCounterAtLeast(Func<Task<int>> getCounter, int minimumValue, TimeSpan timeout, TimeSpan delay)\n        {\n            var last = 0;\n            await TestingUtils.WaitUntilAsync(\n                async lastTry =>\n                {\n                    last = await getCounter();\n                    if (last >= minimumValue)\n                    {\n                        return true;\n                    }\n\n                    if (lastTry)\n                    {\n                        Assert.Fail($\"Counter did not reach {minimumValue} within {timeout}. Last value: {last}\");\n                    }\n\n                    return false;\n                },\n                timeout,\n                delay);\n\n            return last;\n        }\n\n        /// <summary>\n        /// Tests basic timer functionality including start and stop operations.\n        /// Verifies that timers tick at expected intervals, can be stopped,\n        /// and that stopping a timer prevents further ticks. This demonstrates\n        /// the fundamental timer lifecycle within a grain activation.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Basic()\n        {\n            for (int i = 0; i < 10; i++)\n            {\n                var grain = GrainFactory.GetGrain<ITimerGrain>(GetRandomGrainId());\n                var period = await grain.GetTimerPeriod();\n                var timeout = period.Multiply(50);\n                var last = await WaitForCounterAtLeast(grain.GetCounter, 10, timeout, period);\n\n                output.WriteLine(\"value = \" + last);\n                Assert.True(last >= 10 & last <= 12, last.ToString());\n\n                await grain.StopDefaultTimer();\n                await Task.Delay(period.Multiply(2));\n                var curr = await grain.GetCounter();\n                Assert.True(curr == last || curr == last + 1, \"curr == last || curr == last + 1\");\n            }\n        }\n\n        /// <summary>\n        /// Tests multiple grains with timers running in parallel.\n        /// Verifies that each grain maintains its own independent timer\n        /// and that timers across different grain activations don't interfere\n        /// with each other, demonstrating timer isolation per grain.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Parallel()\n        {\n            TimeSpan period = TimeSpan.Zero;\n            List<ITimerGrain> grains = new List<ITimerGrain>();\n            for (int i = 0; i < 10; i++)\n            {\n                ITimerGrain grain = GrainFactory.GetGrain<ITimerGrain>(GetRandomGrainId());\n                grains.Add(grain);\n                period = await grain.GetTimerPeriod(); // activate grains\n            }\n\n            var tasks = new List<Task>(grains.Count);\n            for (int i = 0; i < grains.Count; i++)\n            {\n                ITimerGrain grain = grains[i];\n                tasks.Add(\n                    Task.Run(\n                        async () =>\n                        {\n                            int last = await grain.GetCounter();\n                            var stopwatch = Stopwatch.StartNew();\n                            var timeout = period.Multiply(50);\n                            while (stopwatch.Elapsed < timeout && last < 10)\n                            {\n                                await Task.Delay(period.Divide(2));\n                                last = await grain.GetCounter();\n                            }\n\n                            output.WriteLine(\"value = \" + last);\n                            Assert.True(last >= 10 && last <= 12, \"last >= 10 && last <= 12\");\n                        }));\n            }\n\n            await Task.WhenAll(tasks);\n            for (int i = 0; i < grains.Count; i++)\n            {\n                ITimerGrain grain = grains[i];\n                await grain.StopDefaultTimer();\n            }\n        }\n\n        /// <summary>\n        /// Tests timer behavior across grain deactivation and reactivation.\n        /// Verifies that timers don't persist across grain lifecycle - when a grain\n        /// is deactivated and reactivated, timers start fresh. This demonstrates\n        /// the non-durable nature of timers compared to reminders.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Migration()\n        {\n            ITimerGrain grain = GrainFactory.GetGrain<ITimerGrain>(GetRandomGrainId());\n            TimeSpan period = await grain.GetTimerPeriod();\n\n            // Ensure that the grain works as it should.\n            var last = await grain.GetCounter();\n            var stopwatch = Stopwatch.StartNew();\n            var timeout = period.Multiply(50);\n            while (stopwatch.Elapsed < timeout && last < 10)\n            {\n                await Task.Delay(period.Divide(2));\n                last = await grain.GetCounter();\n            }\n\n            last = await grain.GetCounter();\n            output.WriteLine(\"value = \" + last);\n\n            // Restart the grain.\n            await grain.Deactivate();\n            stopwatch.Restart();\n            last = await grain.GetCounter();\n            Assert.True(last == 0, \"Restarted grains should have zero ticks. Actual: \" + last);\n            period = await grain.GetTimerPeriod();\n\n            // Poke the grain and ensure it still works as it should.\n            while (stopwatch.Elapsed < timeout && last < 10)\n            {\n                await Task.Delay(period.Divide(2));\n                last = await grain.GetCounter();\n            }\n\n            last = await grain.GetCounter();\n            stopwatch.Stop();\n\n            int maximalNumTicks = (int)Math.Round(stopwatch.Elapsed.Divide(period), MidpointRounding.ToPositiveInfinity);\n            Assert.True(\n                last <= maximalNumTicks,\n                $\"Assert: last <= maximalNumTicks. Actual: last = {last}, maximalNumTicks = {maximalNumTicks}\");\n\n            output.WriteLine(\n                \"Total Elapsed time = \" + (stopwatch.Elapsed.TotalSeconds) + \" sec. Expected Ticks = \" + maximalNumTicks +\n                \". Actual ticks = \" + last);\n        }\n\n        /// <summary>\n        /// Tests timers that make asynchronous grain calls in their callbacks.\n        /// Verifies that timer callbacks can perform grain-to-grain communication\n        /// and that exceptions in timer callbacks are captured and don't crash\n        /// the grain. Important for timer-based orchestration patterns.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task AsyncTimerTest_GrainCall()\n        {\n            const string testName = \"AsyncTimerTest_GrainCall\";\n            TimeSpan delay = TimeSpan.FromSeconds(5);\n            TimeSpan wait = delay.Multiply(2);\n\n            ITimerCallGrain grain = null;\n\n            Exception error = null;\n            try\n            {\n                grain = GrainFactory.GetGrain<ITimerCallGrain>(GetRandomGrainId());\n\n                await grain.StartTimer(testName, delay);\n\n                await Task.Delay(wait);\n\n                int tickCount = await grain.GetTickCount();\n                Assert.Equal(1, tickCount);\n\n                Exception err = await grain.GetException();\n                Assert.Null(err); // Should be no exceptions during timer callback\n            }\n            catch (Exception exc)\n            {\n                output.WriteLine(exc);\n                error = exc;\n            }\n\n            try\n            {\n                if (grain != null) await grain.StopTimer(testName);\n            }\n            catch (Exception exc)\n            {\n                // Ignore\n                output.WriteLine(\"Ignoring exception from StopTimer : {0}\", exc);\n            }\n\n            if (error != null)\n            {\n                Assert.Fail($\"Test {testName} failed with error {error}\");\n            }\n        }\n\n        /// <summary>\n        /// Tests all timer creation overloads and their behavior.\n        /// Verifies that different timer registration methods (with/without state,\n        /// different period specifications) work correctly and that all timer\n        /// variants execute their callbacks as expected.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task GrainTimer_TestAllOverloads()\n        {\n            var grain = GrainFactory.GetGrain<ITimerRequestGrain>(GetRandomGrainId());\n\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n            var numTimers = await grain.TestAllTimerOverloads();\n            while (true)\n            {\n                var completedTimers = await grain.PollCompletedTimers().WaitAsync(cts.Token);\n                if (completedTimers == numTimers)\n                {\n                    break;\n                }\n\n                await Task.Delay(TimeSpan.FromMilliseconds(50), cts.Token);\n            }\n\n            await grain.TestCompletedTimerResults();\n        }\n\n        /// <summary>\n        /// Tests that timers can safely dispose themselves from their own callbacks.\n        /// Verifies that self-disposal doesn't cause deadlocks or exceptions,\n        /// which is important for one-shot timer patterns or timers that\n        /// need to cancel themselves based on conditions.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task GrainTimer_DisposeFromCallback()\n        {\n            // Schedule a timer which disposes itself from its own callback.\n            var grain = GrainFactory.GetGrain<ITimerCallGrain>(GetRandomGrainId());\n            await grain.RunSelfDisposingTimer();\n\n            var pocoGrain = GrainFactory.GetGrain<IPocoTimerCallGrain>(GetRandomGrainId());\n            await pocoGrain.RunSelfDisposingTimer();\n        }\n\n        /// <summary>\n        /// Tests timer behavior in non-reentrant grains.\n        /// Verifies that multiple timers in a non-reentrant grain respect\n        /// the grain's concurrency constraints - timer callbacks don't overlap\n        /// and are serialized with other grain methods, maintaining the\n        /// single-threaded execution model.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task NonReentrantGrainTimer_Test()\n        {\n            const string testName = \"NonReentrantGrainTimer_Test\";\n            var delay = TimeSpan.FromSeconds(5);\n            var wait = delay.Multiply(2);\n\n            var grain = GrainFactory.GetGrain<INonReentrantTimerCallGrain>(GetRandomGrainId());\n\n            // Schedule multiple timers with the same delay\n            await grain.StartTimer(testName, delay);\n            await grain.StartTimer($\"{testName}_1\", delay);\n            await grain.StartTimer($\"{testName}_2\", delay);\n\n            // Invoke some non-interleaving methods.\n            var externalTicks = 0;\n            var stopwatch = Stopwatch.StartNew();\n            while (stopwatch.Elapsed < wait)\n            {\n                await grain.ExternalTick(\"external\");\n                externalTicks++;\n            }\n\n            var tickCount = await grain.GetTickCount();\n\n            Assert.Equal(3 + externalTicks, tickCount);\n\n            var err = await grain.GetException();\n            Assert.Null(err); // Should be no exceptions during timer callback\n\n            await grain.StopTimer(testName);\n            await grain.StopTimer($\"{testName}_1\");\n            await grain.StopTimer($\"{testName}_2\");\n        }\n\n        /// <summary>\n        /// Tests changing timer periods and due times after creation.\n        /// Verifies that timer.Change() correctly updates timing parameters,\n        /// handles edge cases (infinite, zero, negative values), and that\n        /// timers can be safely modified from within their own callbacks.\n        /// Essential for adaptive timing scenarios.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task GrainTimer_Change()\n        {\n            const string testName = nameof(GrainTimer_Change);\n            TimeSpan delay = TimeSpan.FromSeconds(5);\n            TimeSpan wait = delay.Multiply(2);\n\n            var grain = GrainFactory.GetGrain<ITimerCallGrain>(GetRandomGrainId());\n\n            await grain.StartTimer(testName, delay);\n\n            await Task.Delay(wait);\n\n            int tickCount = await grain.GetTickCount();\n            Assert.Equal(1, tickCount);\n\n            await grain.RestartTimer(testName, delay);\n\n            await Task.Delay(wait);\n\n            tickCount = await grain.GetTickCount();\n            Assert.Equal(2, tickCount);\n\n            // Infinite timeouts should be valid.\n            await grain.RestartTimer(testName, Timeout.InfiniteTimeSpan);\n            await grain.RestartTimer(testName, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);\n\n            // Zero and sub-ms timeouts should be valid (rounded up to 1ms)\n            await grain.RestartTimer(testName, TimeSpan.Zero);\n            await grain.RestartTimer(testName, TimeSpan.FromMicroseconds(10));\n            await grain.RestartTimer(testName, TimeSpan.Zero, TimeSpan.Zero);\n            await grain.RestartTimer(testName, TimeSpan.FromMicroseconds(10), TimeSpan.FromMicroseconds(10));\n            await grain.RestartTimer(testName, TimeSpan.FromMilliseconds(-0.4));\n            await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(-0.5));\n\n            // Invalid values\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(-5)));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.MaxValue));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(-5)));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.MaxValue));\n\n            Exception err = await grain.GetException();\n            Assert.Null(err); // Should be no exceptions during timer callback\n\n            // Valid operations called from within a timer: updating the period and disposing the timer.\n            var grain2 = GrainFactory.GetGrain<ITimerCallGrain>(GetRandomGrainId());\n            await grain2.StartTimer(testName, delay, \"update_period\");\n            await Task.Delay(wait);\n            Assert.Null(await grain2.GetException()); // Should be no exceptions during timer callback\n            Assert.Equal(1, await grain2.GetTickCount());\n\n            var grain3 = GrainFactory.GetGrain<ITimerCallGrain>(GetRandomGrainId());\n            await grain3.StartTimer(testName, delay, \"dispose_timer\");\n            var grain3Timeout = wait.Multiply(2);\n            var grain3Stopwatch = Stopwatch.StartNew();\n            var grain3TickCount = await grain3.GetTickCount();\n            while (grain3Stopwatch.Elapsed < grain3Timeout && grain3TickCount < 1)\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(200));\n                grain3TickCount = await grain3.GetTickCount();\n            }\n\n            Assert.Null(await grain3.GetException()); // Should be no exceptions during timer callback\n            Assert.Equal(1, grain3TickCount);\n\n            await grain.StopTimer(testName);\n        }\n\n        /// <summary>\n        /// Tests basic timer functionality with POCO (Plain Old CLR Object) grains.\n        /// Verifies that timers work identically with POCO grains as with\n        /// traditional Grain-derived classes, demonstrating that the timer\n        /// infrastructure is independent of the grain implementation style.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Basic_Poco()\n        {\n            for (int i = 0; i < 10; i++)\n            {\n                var grain = GrainFactory.GetGrain<IPocoTimerGrain>(GetRandomGrainId());\n                var period = await grain.GetTimerPeriod();\n                var timeout = period.Multiply(50);\n                var last = await WaitForCounterAtLeast(grain.GetCounter, 10, timeout, period);\n\n                output.WriteLine(\"value = \" + last);\n                Assert.True(last >= 10 & last <= 12, last.ToString());\n\n                await grain.StopDefaultTimer();\n                await Task.Delay(period.Multiply(2));\n                var curr = await grain.GetCounter();\n                Assert.True(curr == last || curr == last + 1, \"curr == last || curr == last + 1\");\n            }\n        }\n\n        /// <summary>\n        /// Tests parallel timer execution across multiple POCO grain instances.\n        /// Verifies that POCO grains maintain timer isolation just like\n        /// traditional grains, with each instance having independent timers\n        /// that don't interfere with each other.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Parallel_Poco()\n        {\n            TimeSpan period = TimeSpan.Zero;\n            List<IPocoTimerGrain> grains = new List<IPocoTimerGrain>();\n            for (int i = 0; i < 10; i++)\n            {\n                IPocoTimerGrain grain = GrainFactory.GetGrain<IPocoTimerGrain>(GetRandomGrainId());\n                grains.Add(grain);\n                period = await grain.GetTimerPeriod(); // activate grains\n            }\n\n            var tasks = new List<Task>(grains.Count);\n            for (int i = 0; i < grains.Count; i++)\n            {\n                IPocoTimerGrain grain = grains[i];\n                tasks.Add(\n                    Task.Run(\n                        async () =>\n                        {\n                            int last = await grain.GetCounter();\n                            var stopwatch = Stopwatch.StartNew();\n                            var timeout = period.Multiply(50);\n                            while (stopwatch.Elapsed < timeout && last < 10)\n                            {\n                                await Task.Delay(period.Divide(2));\n                                last = await grain.GetCounter();\n                            }\n\n                            output.WriteLine(\"value = \" + last);\n                            Assert.True(last >= 10 && last <= 12, \"last >= 10 && last <= 12\");\n                        }));\n            }\n\n            await Task.WhenAll(tasks);\n            for (int i = 0; i < grains.Count; i++)\n            {\n                IPocoTimerGrain grain = grains[i];\n                await grain.StopDefaultTimer();\n            }\n        }\n\n        /// <summary>\n        /// Tests timer behavior across POCO grain deactivation/reactivation.\n        /// Verifies that POCO grains exhibit the same non-persistent timer\n        /// behavior as traditional grains - timers are lost on deactivation\n        /// and start fresh on reactivation.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task TimerOrleansTest_Migration_Poco()\n        {\n            IPocoTimerGrain grain = GrainFactory.GetGrain<IPocoTimerGrain>(GetRandomGrainId());\n            TimeSpan period = await grain.GetTimerPeriod();\n\n            // Ensure that the grain works as it should.\n            var last = await grain.GetCounter();\n            var stopwatch = Stopwatch.StartNew();\n            var timeout = period.Multiply(50);\n            while (stopwatch.Elapsed < timeout && last < 10)\n            {\n                await Task.Delay(period.Divide(2));\n                last = await grain.GetCounter();\n            }\n\n            last = await grain.GetCounter();\n            output.WriteLine(\"value = \" + last);\n\n            // Restart the grain.\n            await grain.Deactivate();\n            stopwatch.Restart();\n            last = await grain.GetCounter();\n            Assert.True(last == 0, \"Restarted grains should have zero ticks. Actual: \" + last);\n            period = await grain.GetTimerPeriod();\n\n            // Poke the grain and ensure it still works as it should.\n            while (stopwatch.Elapsed < timeout && last < 10)\n            {\n                await Task.Delay(period.Divide(2));\n                last = await grain.GetCounter();\n            }\n\n            last = await grain.GetCounter();\n            stopwatch.Stop();\n\n            int maximalNumTicks = (int)Math.Round(stopwatch.Elapsed.Divide(period), MidpointRounding.ToPositiveInfinity);\n            Assert.True(\n                last <= maximalNumTicks,\n                $\"Assert: last <= maximalNumTicks. Actual: last = {last}, maximalNumTicks = {maximalNumTicks}\");\n\n            output.WriteLine(\n                \"Total Elapsed time = \" + (stopwatch.Elapsed.TotalSeconds) + \" sec. Expected Ticks = \" + maximalNumTicks +\n                \". Actual ticks = \" + last);\n        }\n\n        /// <summary>\n        /// Tests asynchronous grain calls from POCO grain timer callbacks.\n        /// Verifies that POCO grain timers can perform async operations\n        /// including grain-to-grain calls, with proper exception handling\n        /// in the timer callback context.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task AsyncTimerTest_GrainCall_Poco()\n        {\n            const string testName = \"AsyncTimerTest_GrainCall\";\n            TimeSpan delay = TimeSpan.FromSeconds(5);\n            TimeSpan wait = delay.Multiply(2);\n\n            IPocoTimerCallGrain grain = null;\n\n            Exception error = null;\n            try\n            {\n                grain = GrainFactory.GetGrain<IPocoTimerCallGrain>(GetRandomGrainId());\n\n                await grain.StartTimer(testName, delay);\n\n                await Task.Delay(wait);\n\n                int tickCount = await grain.GetTickCount();\n                Assert.Equal(1, tickCount);\n\n                Exception err = await grain.GetException();\n                Assert.Null(err); // Should be no exceptions during timer callback\n            }\n            catch (Exception exc)\n            {\n                output.WriteLine(exc);\n                error = exc;\n            }\n\n            try\n            {\n                if (grain != null) await grain.StopTimer(testName);\n            }\n            catch (Exception exc)\n            {\n                // Ignore\n                output.WriteLine(\"Ignoring exception from StopTimer : {0}\", exc);\n            }\n\n            if (error != null)\n            {\n                Assert.Fail($\"Test {testName} failed with error {error}\");\n            }\n        }\n\n        /// <summary>\n        /// Tests all timer registration overloads with POCO grains.\n        /// Ensures that POCO grains support the full range of timer\n        /// registration methods, maintaining API compatibility with\n        /// traditional grain implementations.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Timers\")]\n        public async Task GrainTimer_TestAllOverloads_Poco()\n        {\n            var grain = GrainFactory.GetGrain<IPocoTimerRequestGrain>(GetRandomGrainId());\n\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n            var numTimers = await grain.TestAllTimerOverloads();\n            while (true)\n            {\n                var completedTimers = await grain.PollCompletedTimers().WaitAsync(cts.Token);\n                if (completedTimers == numTimers)\n                {\n                    break;\n                }\n\n                await Task.Delay(TimeSpan.FromMilliseconds(50), cts.Token);\n            }\n\n            await grain.TestCompletedTimerResults();\n        }\n\n        /// <summary>\n        /// Tests timer concurrency constraints in non-reentrant POCO grains.\n        /// Verifies that POCO grains respect reentrancy settings, ensuring\n        /// timer callbacks are properly serialized in non-reentrant grains\n        /// regardless of the grain implementation style.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task NonReentrantGrainTimer_Test_Poco()\n        {\n            const string testName = \"NonReentrantGrainTimer_Test\";\n            var delay = TimeSpan.FromSeconds(5);\n            var wait = delay.Multiply(2);\n\n            var grain = GrainFactory.GetGrain<IPocoNonReentrantTimerCallGrain>(GetRandomGrainId());\n\n            // Schedule multiple timers with the same delay\n            await grain.StartTimer(testName, delay);\n            await grain.StartTimer($\"{testName}_1\", delay);\n            await grain.StartTimer($\"{testName}_2\", delay);\n\n            // Invoke some non-interleaving methods.\n            var externalTicks = 0;\n            var stopwatch = Stopwatch.StartNew();\n            while (stopwatch.Elapsed < wait)\n            {\n                await grain.ExternalTick(\"external\");\n                externalTicks++;\n            }\n\n            var tickCount = await grain.GetTickCount();\n\n            Assert.Equal(3 + externalTicks, tickCount);\n\n            var err = await grain.GetException();\n            Assert.Null(err); // Should be no exceptions during timer callback\n\n            await grain.StopTimer(testName);\n            await grain.StopTimer($\"{testName}_1\");\n            await grain.StopTimer($\"{testName}_2\");\n        }\n\n        /// <summary>\n        /// Tests dynamic timer period changes in POCO grains.\n        /// Verifies that POCO grain timers support runtime modifications\n        /// of timing parameters through the Change method, including\n        /// edge cases and callback-initiated changes.\n        /// </summary>\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task GrainTimer_Change_Poco()\n        {\n            const string testName = nameof(GrainTimer_Change);\n            TimeSpan delay = TimeSpan.FromSeconds(5);\n            TimeSpan wait = delay.Multiply(2);\n\n            var grain = GrainFactory.GetGrain<IPocoTimerCallGrain>(GetRandomGrainId());\n\n            await grain.StartTimer(testName, delay);\n\n            await Task.Delay(wait);\n\n            int tickCount = await grain.GetTickCount();\n            Assert.Equal(1, tickCount);\n\n            await grain.RestartTimer(testName, delay);\n\n            await Task.Delay(wait);\n\n            tickCount = await grain.GetTickCount();\n            Assert.Equal(2, tickCount);\n\n            // Infinite timeouts should be valid.\n            await grain.RestartTimer(testName, Timeout.InfiniteTimeSpan);\n            await grain.RestartTimer(testName, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);\n\n            // Zero and sub-ms timeouts should be valid (rounded up to 1ms)\n            await grain.RestartTimer(testName, TimeSpan.Zero);\n            await grain.RestartTimer(testName, TimeSpan.FromMicroseconds(10));\n            await grain.RestartTimer(testName, TimeSpan.Zero, TimeSpan.Zero);\n            await grain.RestartTimer(testName, TimeSpan.FromMicroseconds(10), TimeSpan.FromMicroseconds(10));\n            await grain.RestartTimer(testName, TimeSpan.FromMilliseconds(-0.4));\n            await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(-0.5));\n\n            // Invalid values\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(-5)));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.MaxValue));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(-5)));\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await grain.RestartTimer(testName, TimeSpan.FromSeconds(1), TimeSpan.MaxValue));\n\n            Exception err = await grain.GetException();\n            Assert.Null(err); // Should be no exceptions during timer callback\n\n            // Valid operations called from within a timer: updating the period and disposing the timer.\n            var grain2 = GrainFactory.GetGrain<IPocoTimerCallGrain>(GetRandomGrainId());\n            await grain2.StartTimer(testName, delay, \"update_period\");\n            await Task.Delay(wait);\n            Assert.Null(await grain2.GetException()); // Should be no exceptions during timer callback\n            Assert.Equal(1, await grain2.GetTickCount());\n\n            var grain3 = GrainFactory.GetGrain<IPocoTimerCallGrain>(GetRandomGrainId());\n            await grain3.StartTimer(testName, delay, \"dispose_timer\");\n            await Task.Delay(wait);\n            Assert.Null(await grain3.GetException()); // Should be no exceptions during timer callback\n            Assert.Equal(1, await grain3.GetTickCount());\n\n            await grain.StopTimer(testName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/Autofac/DependencyInjectionGrainTestsUsingAutofac.cs",
    "content": "using Autofac.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace DependencyInjection.Tests.Autofac\n{\n// Autofac doesn't support keyed service yet\n#if false\n    /// <summary>\n    /// Tests dependency injection functionality using Autofac as the DI container for Orleans grains.\n    /// </summary>\n    [TestCategory(\"DI\"), TestCategory(\"Functional\")]\n    public class DependencyInjectionGrainTestsUsingAutofac : DependencyInjectionGrainTestRunner, IClassFixture<DependencyInjectionGrainTestsUsingAutofac.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfiguratorConfiguringAutofac>();\n            }\n            //configure to use Autofac as DI container\n            private class SiloBuilderConfiguratorConfiguringAutofac : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory());\n                }\n            }\n        }\n\n        public DependencyInjectionGrainTestsUsingAutofac(Fixture fixture)\n            : base(fixture)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Tests that Orleans silos can start successfully when configured to use Autofac as the DI container.\n    /// </summary>\n    [TestCategory(\"DI\"), TestCategory(\"Functional\")]\n    public class DependencyInjectionSiloStartsUsingAutofac : IClassFixture<DependencyInjectionSiloStartsUsingAutofac.Fixture>\n    {\n        private readonly BaseTestClusterFixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.GatewayPerSilo = false;\n                builder.Options.InitialSilosCount = 2;\n                builder.AddSiloBuilderConfigurator<HostBuilderConfigurator>();\n            }\n\n            //configure to use Autofac as DI container\n            private class HostBuilderConfigurator : IHostConfigurator\n            {\n                public void Configure(IHostBuilder hostBuilder)\n                {\n                    hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory());\n                }\n            }\n\n            private class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder siloBuilder)\n                {\n                }\n            }\n        }\n\n        public DependencyInjectionSiloStartsUsingAutofac(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact]\n        public async Task ClusterStart()\n        {\n            var grain = this.fixture.Client.GetGrain<ISimpleGrain>(0);\n            await grain.IncrementA();\n        }\n    }\n#endif\n}\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/DefaultServiceProvider/DependencyInjectionGrainTestsUsingDefaultServiceProvider.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace DependencyInjection.Tests.DefaultServiceProvider\n{\n    /// <summary>\n    /// Tests dependency injection functionality using the default Microsoft DI container.\n    /// Inherits all test cases from DependencyInjectionGrainTestRunner to verify\n    /// that the default ServiceProvider implementation works correctly with Orleans.\n    /// </summary>\n    [TestCategory(\"DI\"), TestCategory(\"Functional\")]\n    public class DependencyInjectionGrainTestsUsingDefaultServiceProvider : DependencyInjectionGrainTestRunner, IClassFixture<DependencyInjectionGrainTestsUsingDefaultServiceProvider.Fixture>\n    {\n        /// <summary>\n        /// Test fixture that configures a single-silo cluster with the default DI container.\n        /// </summary>\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n            }\n        }\n\n        public DependencyInjectionGrainTestsUsingDefaultServiceProvider(Fixture fixture)\n            : base(fixture)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/DependencyInjectionGrainTestsRunner.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace DependencyInjection.Tests\n{\n    /// <summary>\n    /// Test runner for Orleans dependency injection integration tests.\n    /// \n    /// Orleans integrates with Microsoft.Extensions.DependencyInjection to support:\n    /// - Constructor injection in grains\n    /// - Scoped services (one instance per grain activation)\n    /// - Singleton services (shared across all grains)\n    /// - Integration with third-party DI containers\n    /// \n    /// Key concepts tested:\n    /// - Grain constructors can have dependencies injected\n    /// - Each grain activation gets its own scope\n    /// - IGrainFactory and IGrainActivationContext are automatically available\n    /// - Generic grains can have dependencies based on their type parameters\n    /// - Explicit grain registrations in DI are NOT supported by design\n    /// \n    /// This abstract base class contains the core test logic, while concrete\n    /// implementations test different DI container integrations.\n    /// </summary>\n    public abstract class DependencyInjectionGrainTestRunner : OrleansTestingBase\n    {\n        private readonly BaseTestClusterFixture fixture;\n\n        /// <summary>\n        /// Configures services for dependency injection tests.\n        /// This is in the base test runner because all DI tests need these services,\n        /// while different ServiceProviderFactory setups are in concrete test classes.\n        /// </summary>\n        protected class TestSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.ConfigureServices(services =>\n                {\n                    services.AddSingleton<IReducer<string, Reducer1Action>>(x => new Reducer1());\n                    services.AddSingleton<IReducer<int, Reducer2Action>>(x => new Reducer2());\n                    services.AddSingleton<IInjectedService, InjectedService>();\n                    services.AddScoped<IInjectedScopedService, InjectedScopedService>();\n\n                    // Explicitly register a grain class to test that it will NOT use this registration.\n                    // Orleans creates grains through its own activation system, not DI container.\n                    // This registration is here to verify that Orleans ignores it and fails\n                    // when trying to create the grain (missing constructor parameters).\n                    services.AddTransient(\n                        sp => new ExplicitlyRegisteredSimpleDIGrain(\n                            sp.GetRequiredService<IInjectedService>(),\n                            \"some value\",\n                            5));\n                });\n            }\n        }\n\n        public DependencyInjectionGrainTestRunner(BaseTestClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Basic test that grains can be activated with constructor dependencies.\n        /// This verifies the fundamental DI integration is working.\n        /// </summary>\n        [Fact]\n        public async Task CanGetGrainWithInjectedDependencies()\n        {\n            IDIGrainWithInjectedServices grain = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            var _ = await grain.GetLongValue();\n        }\n\n        /// <summary>\n        /// Tests that IGrainFactory is automatically available for injection.\n        /// IGrainFactory is a framework service that allows grains to create other grains.\n        /// Note: Don't register your own IGrainFactory - Orleans provides this automatically.\n        /// </summary>\n        [Fact]\n        public async Task CanGetGrainWithInjectedGrainFactory()\n        {\n            // please don't inject your implementation of IGrainFactory to DI container in Startup Class, \n            // since we are currently not supporting replacing IGrainFactory \n            IDIGrainWithInjectedServices grain = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            _ = await grain.GetGrainFactoryId();\n        }\n\n        /// <summary>\n        /// Verifies that singleton services are shared across all grain activations.\n        /// The same instance should be injected into different grains.\n        /// </summary>\n        [Fact]\n        public async Task CanResolveSingletonDependencies()\n        {\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            var grain2 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n\n            // the injected service will return the same value only if it's the same instance\n            Assert.Equal(\n                await grain1.GetInjectedSingletonServiceValue(), \n                await grain2.GetInjectedSingletonServiceValue());\n\n            await grain1.DoDeactivate();\n            await grain2.DoDeactivate();\n        }\n\n        /// <summary>\n        /// Verifies that scoped services create unique instances per grain activation.\n        /// Each grain should get its own instance of scoped services.\n        /// This is crucial for services that maintain per-grain state.\n        /// </summary>\n        [Fact]\n        public async Task CanResolveScopedDependencies()\n        {\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            var grain2 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n\n            // the injected service will only return a different value if it's a different instance\n            Assert.NotEqual(\n                await grain1.GetInjectedScopedServiceValue(),\n                await grain2.GetInjectedScopedServiceValue());\n\n            await grain1.DoDeactivate();\n            await grain2.DoDeactivate();\n        }\n\n        /// <summary>\n        /// Tests that IGrainActivationContext is available as a scoped service.\n        /// Each grain activation has its own context with grain-specific information\n        /// like GrainId, which should be accessible through DI.\n        /// </summary>\n        [Fact]\n        public async Task CanResolveScopedGrainActivationContext()\n        {\n            long id1 = GetRandomGrainId();\n            long id2 = GetRandomGrainId();\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(id1);\n            var grain2 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(id2);\n\n            // the injected service will only return a different value if it's a different instance\n            Assert.Contains(id1.ToString(\"X\"), await grain1.GetStringValue());\n            Assert.Contains(id2.ToString(\"X\"), await grain2.GetStringValue());\n\n            await grain1.DoDeactivate();\n            await grain2.DoDeactivate();\n        }\n\n        /// <summary>\n        /// Verifies that scoped services are thread-safe within a grain activation.\n        /// Multiple concurrent calls to the same grain should use the same\n        /// scoped service instances, as grains process requests sequentially.\n        /// </summary>\n        [Fact]\n        public async Task ScopedDependenciesAreThreadSafe()\n        {\n            const int parallelCalls = 10;\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n\n            var calls =\n                Enumerable.Range(0, parallelCalls)\n                    .Select(i => grain1.GetInjectedScopedServiceValue())\n                    .ToList();\n\n            await Task.WhenAll(calls);\n            string expected = await calls[0];\n            foreach (var callTask in calls)\n            {\n                Assert.Equal(expected, await callTask);\n            }\n\n            await grain1.DoDeactivate();\n        }\n\n        /// <summary>\n        /// Tests that grains can access the DI container through IServiceProvider.\n        /// Services resolved directly from the provider should match those\n        /// injected through the constructor for the same grain activation.\n        /// </summary>\n        [Fact]\n        public async Task CanResolveSameDependenciesViaServiceProvider()\n        {\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            var grain2 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n\n            await grain1.AssertCanResolveSameServiceInstances();\n            await grain2.AssertCanResolveSameServiceInstances();\n\n            await grain1.DoDeactivate();\n            await grain2.DoDeactivate();\n        }\n\n        /// <summary>\n        /// Verifies that IGrainFactory is registered as a singleton.\n        /// All grains in the silo should receive the same IGrainFactory instance.\n        /// </summary>\n        [Fact]\n        public async Task CanResolveSingletonGrainFactory()\n        {\n            var grain1 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n            var grain2 = this.fixture.GrainFactory.GetGrain<IDIGrainWithInjectedServices>(GetRandomGrainId());\n\n            // the injected grain factory will return the same value only if it's the same instance,\n            Assert.Equal(\n                await grain1.GetGrainFactoryId(),\n                await grain2.GetGrainFactoryId());\n        }\n\n        /// <summary>\n        /// Tests that explicitly registered grain classes in DI are ignored.\n        /// Orleans must create grains through its activation system, not DI,\n        /// to ensure proper lifecycle management and distributed behavior.\n        /// This test verifies that the explicit registration is not used.\n        /// </summary>\n        [Fact]\n        public async Task CannotGetExplictlyRegisteredGrain()\n        {\n            ISimpleDIGrain grain = this.fixture.GrainFactory.GetGrain<ISimpleDIGrain>(GetRandomGrainId(), grainClassNamePrefix: \"UnitTests.Grains.ExplicitlyRegistered\");\n            var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => grain.GetLongValue());\n            var innerException = Assert.IsType<InvalidOperationException>(exception.InnerException);\n            Assert.Contains(\"Unable to resolve service for type 'System.String' while attempting to activate 'UnitTests.Grains.ExplicitlyRegisteredSimpleDIGrain'\", innerException.Message);\n        }\n\n        /// <summary>\n        /// Tests that generic grains can have dependencies injected based on their type parameters.\n        /// For example, IReducer<TState, TAction> can be resolved differently for different\n        /// TState/TAction combinations, allowing type-safe dependency injection.\n        /// </summary>\n        [Fact]\n        public async Task CanUseGenericArgumentsInConstructor()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IReducerGameGrain<string, Reducer1Action>>(\"reducer1\");\n            Assert.NotNull(await grain.Go(\"378\", new Reducer1Action()));\n            var grain2 = this.fixture.GrainFactory.GetGrain<IReducerGameGrain<int, Reducer2Action>>(\"reducer1\");\n            Assert.NotEqual(0, await grain2.Go(378, new Reducer2Action()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/Orleans.DependencyInjection.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Autofac.Extensions.DependencyInjection\" />\n    <PackageReference Include=\"StructureMap.Microsoft.DependencyInjection\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestGrains\\TestGrains.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.DependencyInjection.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/DurableJobs/DurableJobTestsRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans;\nusing Orleans.DurableJobs;\nusing Xunit;\nusing UnitTests.GrainInterfaces;\n\nnamespace Tester.DurableJobs;\n\n/// <summary>\n/// Contains the test logic for durable jobs that can be run against different providers.\n/// This class is provider-agnostic and can be reused by test classes for InMemory, Azure, and other providers.\n/// </summary>\npublic class DurableJobTestsRunner\n{\n    private readonly IGrainFactory _grainFactory;\n\n    public DurableJobTestsRunner(IGrainFactory grainFactory)\n    {\n        _grainFactory = grainFactory;\n    }\n\n    public async Task DurableJobGrain(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-job-grain\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(5);\n        var job1 = await grain.ScheduleJobAsync(\"TestJob\", dueTime).WaitAsync(cancellationToken);\n        Assert.NotNull(job1);\n        Assert.Equal(\"TestJob\", job1.Name);\n        Assert.Equal(dueTime, job1.DueTime);\n        var job2 = await grain.ScheduleJobAsync(\"TestJob2\", dueTime).WaitAsync(cancellationToken);\n        var job3 = await grain.ScheduleJobAsync(\"TestJob3\", dueTime.AddSeconds(4)).WaitAsync(cancellationToken);\n        var job4 = await grain.ScheduleJobAsync(\"TestJob4\", dueTime).WaitAsync(cancellationToken);\n        var job5 = await grain.ScheduleJobAsync(\"TestJob5\", dueTime.AddSeconds(1)).WaitAsync(cancellationToken);\n        var canceledJob = await grain.ScheduleJobAsync(\"CanceledJob\", dueTime.AddSeconds(2)).WaitAsync(cancellationToken);\n        Assert.True(await grain.TryCancelJobAsync(canceledJob).WaitAsync(cancellationToken));\n        // Wait for the job to run\n        foreach (var job in new[] { job1, job2, job3, job4, job5 })\n        {\n            try\n            {\n                await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n            }\n            catch (TimeoutException)\n            {\n                Assert.Fail($\"The durable job {job.Name} did not run within the expected time.\");\n            }\n        }\n        // Verify the canceled job did not run\n        Assert.False(await grain.HasJobRan(canceledJob.Id).WaitAsync(cancellationToken));\n    }\n\n    public async Task JobExecutionOrder(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-execution-order\");\n        var baseTime = DateTimeOffset.UtcNow.AddSeconds(2);\n\n        var job1 = await grain.ScheduleJobAsync(\"FirstJob\", baseTime).WaitAsync(cancellationToken);\n        var job2 = await grain.ScheduleJobAsync(\"SecondJob\", baseTime.AddSeconds(2)).WaitAsync(cancellationToken);\n        var job3 = await grain.ScheduleJobAsync(\"ThirdJob\", baseTime.AddSeconds(4)).WaitAsync(cancellationToken);\n\n        await grain.WaitForJobToRun(job1.Id).WaitAsync(cancellationToken);\n        await grain.WaitForJobToRun(job2.Id).WaitAsync(cancellationToken);\n        await grain.WaitForJobToRun(job3.Id).WaitAsync(cancellationToken);\n\n        var time1 = await grain.GetJobExecutionTime(job1.Id).WaitAsync(cancellationToken);\n        var time2 = await grain.GetJobExecutionTime(job2.Id).WaitAsync(cancellationToken);\n        var time3 = await grain.GetJobExecutionTime(job3.Id).WaitAsync(cancellationToken);\n\n        Assert.True(time1 < time2, $\"Job1 executed at {time1}, Job2 at {time2}\");\n        Assert.True(time2 < time3, $\"Job2 executed at {time2}, Job3 at {time3}\");\n    }\n\n    public async Task PastDueTime(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-past-due\");\n        var pastTime = DateTimeOffset.UtcNow.AddSeconds(-5);\n\n        var job = await grain.ScheduleJobAsync(\"PastDueJob\", pastTime).WaitAsync(cancellationToken);\n        Assert.NotNull(job);\n\n        await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n        Assert.True(await grain.HasJobRan(job.Id).WaitAsync(cancellationToken));\n    }\n\n    public async Task JobWithMetadata(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-metadata\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n        var metadata = new Dictionary<string, string>\n        {\n            [\"UserId\"] = \"user123\",\n            [\"Action\"] = \"SendEmail\",\n            [\"Priority\"] = \"High\"\n        };\n\n        var job = await grain.ScheduleJobAsync(\"MetadataJob\", dueTime, metadata).WaitAsync(cancellationToken);\n        Assert.NotNull(job);\n        Assert.NotNull(job.Metadata);\n        Assert.Equal(3, job.Metadata.Count);\n        Assert.Equal(\"user123\", job.Metadata[\"UserId\"]);\n        Assert.Equal(\"SendEmail\", job.Metadata[\"Action\"]);\n        Assert.Equal(\"High\", job.Metadata[\"Priority\"]);\n\n        await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n\n        var context = await grain.GetJobRun(job.Id).WaitAsync(cancellationToken);\n        Assert.NotNull(context);\n        Assert.NotNull(context.Job.Metadata);\n        Assert.Equal(\"user123\", context.Job.Metadata[\"UserId\"]);\n    }\n\n    public async Task MultipleGrains(CancellationToken cancellationToken)\n    {\n        var grain1 = _grainFactory.GetGrain<IDurableJobGrain>(\"test-grain-1\");\n        var grain2 = _grainFactory.GetGrain<IDurableJobGrain>(\"test-grain-2\");\n        var grain3 = _grainFactory.GetGrain<IDurableJobGrain>(\"test-grain-3\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n\n        var job1 = await grain1.ScheduleJobAsync(\"Job1\", dueTime).WaitAsync(cancellationToken);\n        var job2 = await grain2.ScheduleJobAsync(\"Job2\", dueTime).WaitAsync(cancellationToken);\n        var job3 = await grain3.ScheduleJobAsync(\"Job3\", dueTime).WaitAsync(cancellationToken);\n\n        await grain1.WaitForJobToRun(job1.Id).WaitAsync(cancellationToken);\n        await grain2.WaitForJobToRun(job2.Id).WaitAsync(cancellationToken);\n        await grain3.WaitForJobToRun(job3.Id).WaitAsync(cancellationToken);\n\n        Assert.True(await grain1.HasJobRan(job1.Id).WaitAsync(cancellationToken));\n        Assert.True(await grain2.HasJobRan(job2.Id).WaitAsync(cancellationToken));\n        Assert.True(await grain3.HasJobRan(job3.Id).WaitAsync(cancellationToken));\n\n        Assert.False(await grain1.HasJobRan(job2.Id).WaitAsync(cancellationToken));\n        Assert.False(await grain2.HasJobRan(job3.Id).WaitAsync(cancellationToken));\n        Assert.False(await grain3.HasJobRan(job1.Id).WaitAsync(cancellationToken));\n    }\n\n    public async Task DuplicateJobNames(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-duplicate-names\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n\n        var job1 = await grain.ScheduleJobAsync(\"SameName\", dueTime).WaitAsync(cancellationToken);\n        var job2 = await grain.ScheduleJobAsync(\"SameName\", dueTime.AddSeconds(1)).WaitAsync(cancellationToken);\n        var job3 = await grain.ScheduleJobAsync(\"SameName\", dueTime.AddSeconds(2)).WaitAsync(cancellationToken);\n\n        Assert.NotEqual(job1.Id, job2.Id);\n        Assert.NotEqual(job2.Id, job3.Id);\n        Assert.NotEqual(job1.Id, job3.Id);\n\n        Assert.Equal(\"SameName\", job1.Name);\n        Assert.Equal(\"SameName\", job2.Name);\n        Assert.Equal(\"SameName\", job3.Name);\n\n        await grain.WaitForJobToRun(job1.Id).WaitAsync(cancellationToken);\n        await grain.WaitForJobToRun(job2.Id).WaitAsync(cancellationToken);\n        await grain.WaitForJobToRun(job3.Id).WaitAsync(cancellationToken);\n\n        Assert.True(await grain.HasJobRan(job1.Id).WaitAsync(cancellationToken));\n        Assert.True(await grain.HasJobRan(job2.Id).WaitAsync(cancellationToken));\n        Assert.True(await grain.HasJobRan(job3.Id).WaitAsync(cancellationToken));\n    }\n\n    public async Task CancelNonExistentJob(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-cancel-nonexistent\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(10);\n\n        var job = await grain.ScheduleJobAsync(\"RealJob\", dueTime).WaitAsync(cancellationToken);\n        \n        var fakeJob = new DurableJob\n        {\n            Id = \"non-existent-id\",\n            Name = \"FakeJob\",\n            DueTime = dueTime,\n            ShardId = job.ShardId,\n            TargetGrainId = job.TargetGrainId\n        };\n\n        var cancelResult = await grain.TryCancelJobAsync(fakeJob).WaitAsync(cancellationToken);\n        Assert.False(cancelResult);\n\n        await Task.Delay(100, cancellationToken);\n        Assert.False(await grain.HasJobRan(fakeJob.Id).WaitAsync(cancellationToken));\n    }\n\n    public async Task CancelAlreadyExecutedJob(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-cancel-executed\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(2);\n\n        var job = await grain.ScheduleJobAsync(\"QuickJob\", dueTime).WaitAsync(cancellationToken);\n\n        await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n        Assert.True(await grain.HasJobRan(job.Id).WaitAsync(cancellationToken));\n\n        var cancelResult = await grain.TryCancelJobAsync(job).WaitAsync(cancellationToken);\n        Assert.False(cancelResult);\n    }\n\n    public async Task ConcurrentScheduling(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-concurrent\");\n        var baseTime = DateTimeOffset.UtcNow.AddSeconds(5);\n        var jobCount = 20;\n\n        var scheduleTasks = new List<Task<DurableJob>>();\n        for (int i = 0; i < jobCount; i++)\n        {\n            scheduleTasks.Add(grain.ScheduleJobAsync($\"ConcurrentJob{i}\", baseTime.AddMilliseconds(i * 100)));\n        }\n\n        var jobs = await Task.WhenAll(scheduleTasks).WaitAsync(cancellationToken);\n\n        Assert.Equal(jobCount, jobs.Length);\n        Assert.Equal(jobCount, jobs.Select(j => j.Id).Distinct().Count());\n\n        var waitTasks = jobs.Select(j => grain.WaitForJobToRun(j.Id));\n        await Task.WhenAll(waitTasks).WaitAsync(cancellationToken);\n\n        foreach (var job in jobs)\n        {\n            Assert.True(await grain.HasJobRan(job.Id).WaitAsync(cancellationToken), $\"Job {job.Name} did not run\");\n        }\n    }\n\n    public async Task JobPropertiesVerification(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-properties\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n        var metadata = new Dictionary<string, string> { [\"Key\"] = \"Value\" };\n\n        var job = await grain.ScheduleJobAsync(\"PropertyTestJob\", dueTime, metadata).WaitAsync(cancellationToken);\n\n        Assert.NotNull(job.Id);\n        Assert.NotEmpty(job.Id);\n        Assert.Equal(\"PropertyTestJob\", job.Name);\n        Assert.Equal(dueTime, job.DueTime);\n        Assert.NotNull(job.ShardId);\n        Assert.NotEmpty(job.ShardId);\n        Assert.NotNull(job.Metadata);\n        Assert.Single(job.Metadata);\n\n        await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n\n        var context = await grain.GetJobRun(job.Id).WaitAsync(cancellationToken);\n        Assert.NotNull(context);\n        Assert.Equal(job.Id, context.Job.Id);\n        Assert.Equal(job.Name, context.Job.Name);\n        Assert.NotNull(context.RunId);\n        Assert.NotEmpty(context.RunId);\n    }\n\n    public async Task DequeueCount(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IDurableJobGrain>(\"test-dequeue-count\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n\n        var job = await grain.ScheduleJobAsync(\"DequeueTestJob\", dueTime).WaitAsync(cancellationToken);\n\n        await grain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n\n        var context = await grain.GetJobRun(job.Id).WaitAsync(cancellationToken);\n        Assert.NotNull(context);\n        Assert.Equal(1, context.DequeueCount);\n    }\n\n    public async Task ScheduleJobOnAnotherGrain(CancellationToken cancellationToken)\n    {\n        var schedulerGrain = _grainFactory.GetGrain<ISchedulerGrain>(\"scheduler-grain\");\n        var targetGrain = _grainFactory.GetGrain<IDurableJobGrain>(\"target-grain\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(3);\n\n        var job = await schedulerGrain.ScheduleJobOnAnotherGrainAsync(\"target-grain\", \"CrossGrainJob\", dueTime).WaitAsync(cancellationToken);\n\n        Assert.NotNull(job);\n        Assert.Equal(\"CrossGrainJob\", job.Name);\n        Assert.Equal(dueTime, job.DueTime);\n\n        await targetGrain.WaitForJobToRun(job.Id).WaitAsync(cancellationToken);\n\n        Assert.True(await targetGrain.HasJobRan(job.Id).WaitAsync(cancellationToken));\n\n        var context = await targetGrain.GetJobRun(job.Id).WaitAsync(cancellationToken);\n        Assert.NotNull(context);\n        Assert.Equal(job.Id, context.Job.Id);\n        Assert.Equal(\"CrossGrainJob\", context.Job.Name);\n    }\n\n    public async Task JobRetry(CancellationToken cancellationToken)\n    {\n        var grain = _grainFactory.GetGrain<IRetryTestGrain>(\"retry-test-grain\");\n        var dueTime = DateTimeOffset.UtcNow.AddSeconds(2);\n        var metadata = new Dictionary<string, string>\n        {\n            [\"FailUntilAttempt\"] = \"3\"\n        };\n\n        var job = await grain.ScheduleJobAsync(\"RetryJob\", dueTime, metadata).WaitAsync(cancellationToken);\n\n        Assert.NotNull(job);\n        Assert.Equal(\"RetryJob\", job.Name);\n        Assert.NotNull(job.Metadata);\n        Assert.Equal(\"3\", job.Metadata[\"FailUntilAttempt\"]);\n\n        // Wait for the job to eventually succeed (with retries)\n        // Default retry policy: retry up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s)\n        // We expect 3 attempts: fail at DequeueCount=1, fail at DequeueCount=2, succeed at DequeueCount=3\n        // Total time: ~2s (initial) + 1s (first retry delay) + 2s (second retry delay) = ~5s\n        await grain.WaitForJobToSucceed(job.Id).WaitAsync(cancellationToken);\n\n        Assert.True(await grain.HasJobSucceeded(job.Id).WaitAsync(cancellationToken));\n\n        var attemptCount = await grain.GetJobExecutionAttemptCount(job.Id).WaitAsync(cancellationToken);\n        Assert.Equal(3, attemptCount);\n\n        var dequeueCountHistory = await grain.GetJobDequeueCountHistory(job.Id).WaitAsync(cancellationToken);\n        Assert.Equal(3, dequeueCountHistory.Count);\n        Assert.Equal(1, dequeueCountHistory[0]);\n        Assert.Equal(2, dequeueCountHistory[1]);\n        Assert.Equal(3, dequeueCountHistory[2]);\n\n        var finalContext = await grain.GetFinalJobRun(job.Id).WaitAsync(cancellationToken);\n        Assert.NotNull(finalContext);\n        Assert.Equal(3, finalContext.DequeueCount);\n        Assert.Equal(job.Id, finalContext.Job.Id);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/DurableJobs/IJobShardManagerTestFixture.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\n\nnamespace Tester.DurableJobs;\n\n/// <summary>\n/// Defines the contract for provider-specific test fixtures used by <see cref=\"JobShardManagerTestsRunner\"/>.\n/// Each provider implementation (Azure, InMemory, etc.) should implement this interface to provide\n/// the necessary infrastructure for running shared job shard manager tests.\n/// </summary>\npublic interface IJobShardManagerTestFixture : IAsyncDisposable\n{\n    /// <summary>\n    /// Creates a new <see cref=\"JobShardManager\"/> instance for the specified silo.\n    /// </summary>\n    /// <param name=\"localSiloDetails\">The local silo details.</param>\n    /// <param name=\"membershipService\">The cluster membership service for the manager.</param>\n    /// <returns>A configured job shard manager instance.</returns>\n    JobShardManager CreateManager(ILocalSiloDetails localSiloDetails, IClusterMembershipService membershipService);\n}\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/DurableJobs/InMemoryJobShardManagerTestFixture.cs",
    "content": "using System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\n\nnamespace Tester.DurableJobs;\n\n/// <summary>\n/// InMemory implementation of <see cref=\"IJobShardManagerTestFixture\"/>.\n/// Provides the infrastructure needed to run shared job shard manager tests against the InMemory provider.\n/// </summary>\ninternal sealed class InMemoryJobShardManagerTestFixture : IJobShardManagerTestFixture\n{\n    private readonly int _maxAdoptedCount;\n\n    public InMemoryJobShardManagerTestFixture(int maxAdoptedCount = 3)\n    {\n        _maxAdoptedCount = maxAdoptedCount;\n        // Clear any state from previous tests\n        InMemoryJobShardManager.ClearAllShardsAsync().GetAwaiter().GetResult();\n    }\n\n    public JobShardManager CreateManager(ILocalSiloDetails localSiloDetails, IClusterMembershipService membershipService)\n    {\n        return new InMemoryJobShardManager(localSiloDetails.SiloAddress, membershipService, _maxAdoptedCount);\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        // Clear state after tests\n        await InMemoryJobShardManager.ClearAllShardsAsync();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/DurableJobs/InMemoryJobShardManagerTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Tester.DurableJobs;\n\n/// <summary>\n/// Tests for <see cref=\"InMemoryJobShardManager\"/> using the <see cref=\"JobShardManagerTestsRunner\"/>.\n/// These tests verify shard lifecycle management, ownership, and failover semantics for the InMemory provider.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"DurableJobs\")]\npublic class InMemoryJobShardManagerTests : IAsyncLifetime\n{\n    private readonly InMemoryJobShardManagerTestFixture _fixture;\n    private readonly JobShardManagerTestsRunner _runner;\n\n    public InMemoryJobShardManagerTests()\n    {\n        _fixture = new InMemoryJobShardManagerTestFixture();\n        _runner = new JobShardManagerTestsRunner(_fixture);\n    }\n\n    public Task InitializeAsync() => Task.CompletedTask;\n\n    public Task DisposeAsync() => _fixture.DisposeAsync().AsTask();\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_ShardCreationAndAssignment()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardCreationAndAssignment(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_ReadFrozenShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ReadFrozenShard(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_LiveShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.LiveShard(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_JobMetadata()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobMetadata(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_ConcurrentShardAssignment_OwnershipConflicts()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ConcurrentShardAssignment_OwnershipConflicts(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_ShardMetadataMerge()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardMetadataMerge(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_StopProcessingShard()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.StopProcessingShard(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_RetryJobLater()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.RetryJobLater(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_JobCancellation()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.JobCancellation(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_ShardRegistrationRetry_IdCollisions()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.ShardRegistrationRetry_IdCollisions(cts.Token);\n    }\n\n    [SkippableFact]\n    public async Task InMemoryJobShardManager_UnregisterShard_WithJobsRemaining()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n        await _runner.UnregisterShard_WithJobsRemaining(cts.Token);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/DurableJobs/JobShardManagerTestsRunner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Orleans.Runtime;\nusing Orleans.DurableJobs;\nusing Xunit;\n\nnamespace Tester.DurableJobs;\n\n/// <summary>\n/// Contains provider-agnostic test logic for job shard managers that can be run against different providers.\n/// This class is similar to <see cref=\"DurableJobTestsRunner\"/> but operates at the infrastructure layer,\n/// testing shard lifecycle management, ownership, and failover semantics.\n/// </summary>\npublic class JobShardManagerTestsRunner\n{\n    private readonly IJobShardManagerTestFixture _fixture;\n    private readonly IDictionary<string, string> _testMetadata;\n    private readonly InMemoryClusterMembershipService _membershipService;\n\n    public JobShardManagerTestsRunner(IJobShardManagerTestFixture fixture)\n    {\n        _fixture = fixture;\n        _testMetadata = new Dictionary<string, string>\n        {\n            { \"CreatedBy\", \"UnitTest\" },\n            { \"Purpose\", \"Testing\" }\n        };\n        _membershipService = new InMemoryClusterMembershipService();\n    }\n\n    /// <summary>\n    /// Sets the status of a silo in the cluster membership service.\n    /// </summary>\n    private void SetSiloStatus(SiloAddress siloAddress, SiloStatus status)\n    {\n        _membershipService.SetSiloStatus(siloAddress, status);\n    }\n\n    /// <summary>\n    /// Creates a job shard manager for the given silo address.\n    /// </summary>\n    private JobShardManager CreateManager(SiloAddress siloAddress)\n    {\n        var localSiloDetails = new TestLocalSiloDetails(siloAddress);\n        return _fixture.CreateManager(localSiloDetails, _membershipService);\n    }\n\n    /// <summary>\n    /// Tests basic shard creation and assignment workflow.\n    /// Verifies that shards are created with unique IDs and correctly assigned to their creator silo.\n    /// </summary>\n    public async Task ShardCreationAndAssignment(CancellationToken cancellationToken)\n    {\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTimeOffset.UtcNow;\n        var maxDate = date.AddHours(1);\n\n        // Register multiple shards and ensure they are distinct\n        // two of them have the same time range\n        var shard1 = await silo1Manager.CreateShardAsync(date, maxDate, _testMetadata, cancellationToken);\n        var shard2 = await silo1Manager.CreateShardAsync(date, maxDate, _testMetadata, cancellationToken);\n        var shard3 = await silo1Manager.CreateShardAsync(date.AddHours(2), maxDate, _testMetadata, cancellationToken);\n\n        Assert.Distinct([shard1.Id, shard2.Id, shard3.Id]);\n\n        // All shards are now assigned to the creator silo\n        var assignedShards = await silo1Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(3), cancellationToken);\n        Assert.Equal(3, assignedShards.Count);\n        Assert.Contains(shard1.Id, assignedShards.Select(s => s.Id));\n        Assert.Contains(shard2.Id, assignedShards.Select(s => s.Id));\n        Assert.Contains(shard3.Id, assignedShards.Select(s => s.Id));\n        var emptyShards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(3), cancellationToken);\n        Assert.Empty(emptyShards);\n\n        // Mark the local silo as dead\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Now we can take over all three shards\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(3), cancellationToken);\n        Assert.Equal(3, shards.Count);\n        Assert.Contains(shard1.Id, shards.Select(s => s.Id));\n        Assert.Contains(shard2.Id, shards.Select(s => s.Id));\n        Assert.Contains(shard3.Id, shards.Select(s => s.Id));\n\n        // Register another silo\n        var silo3Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5002), 0);\n        SetSiloStatus(silo3Address, SiloStatus.Active);\n        var silo3Manager = CreateManager(silo3Address);\n\n        // No unassigned shards\n        Assert.Empty(await silo3Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken));\n    }\n\n    /// <summary>\n    /// Tests reading and consuming jobs from a shard after ownership transfer.\n    /// Verifies that jobs are preserved during failover and can be consumed by the new owner.\n    /// </summary>\n    public async Task ReadFrozenShard(CancellationToken cancellationToken)\n    {\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTime.UtcNow;\n        var shard1 = await silo1Manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n\n        // Schedule some jobs\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = date.AddSeconds(1), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job3\", DueTime = date.AddSeconds(3), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = date.AddSeconds(2), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job4\", DueTime = date.AddSeconds(4), Metadata = null }, cancellationToken);\n\n        // Mark the silo1 as dead, and create a new incarnation\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Take over the shard\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        shard1 = shards[0];\n\n        var counter = 1;\n        await foreach (var jobCtx in shard1.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            Assert.Equal($\"job{counter}\", jobCtx.Job.Name);\n            await shard1.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n            counter++;\n        }\n        Assert.Equal(5, counter);\n        await silo2Manager.UnregisterShardAsync(shard1, cancellationToken);\n\n        // No unassigned shards\n        Assert.Empty(await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken));\n    }\n\n    /// <summary>\n    /// Tests consuming jobs from a live shard (one that continues to accept new jobs).\n    /// Verifies job scheduling, consumption, and cancellation during processing.\n    /// </summary>\n    public async Task LiveShard(CancellationToken cancellationToken)\n    {\n        var startTime = DateTime.UtcNow;\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard1 = await manager.CreateShardAsync(date, date.AddYears(1), _testMetadata, cancellationToken);\n\n        // Schedule some jobs\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job0\", DueTime = startTime.AddSeconds(1), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job2\", DueTime = startTime.AddSeconds(3), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job1\", DueTime = startTime.AddSeconds(2), Metadata = null }, cancellationToken);\n        var lastJob = await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job3\", DueTime = startTime.AddSeconds(4), Metadata = null }, cancellationToken);\n        var jobToCancel = await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job4\", DueTime = startTime.AddSeconds(5), Metadata = null }, cancellationToken);\n\n        var counter = 0;\n        await shard1.MarkAsCompleteAsync(cancellationToken);\n        await shard1.RemoveJobAsync(jobToCancel.Id, cancellationToken);\n        await foreach (var jobCtx in shard1.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            Assert.Equal($\"job{counter}\", jobCtx.Job.Name);\n            await shard1.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n            counter++;\n        }\n        Assert.Equal(4, counter);\n        Assert.True(lastJob.DueTime <= DateTimeOffset.UtcNow);\n        await manager.UnregisterShardAsync(shard1, cancellationToken);\n\n        // No unassigned shards\n        Assert.Empty(await manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken));\n    }\n\n    /// <summary>\n    /// Tests job metadata persistence and retrieval across shard ownership transfer.\n    /// </summary>\n    public async Task JobMetadata(CancellationToken cancellationToken)\n    {\n        // Initialize 2 silos with two managers\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTime.UtcNow;\n        var shard = await silo1Manager.CreateShardAsync(date, date.AddYears(1), _testMetadata, cancellationToken);\n\n        // Schedule jobs with different metadata on a single shard\n        var jobMetadata1 = new Dictionary<string, string>\n        {\n            { \"Priority\", \"High\" },\n            { \"Category\", \"Payment\" },\n            { \"RequestId\", \"12345\" }\n        };\n        var jobMetadata2 = new Dictionary<string, string>\n        {\n            { \"Priority\", \"Low\" },\n            { \"Category\", \"Notification\" }\n        };\n\n        var job1 = await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddSeconds(1), Metadata = jobMetadata1 }, cancellationToken);\n        var job2 = await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = DateTime.UtcNow.AddSeconds(2), Metadata = jobMetadata2 }, cancellationToken);\n        var job3 = await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target3\"), JobName = \"job3\", DueTime = DateTime.UtcNow.AddSeconds(3), Metadata = null }, cancellationToken);\n\n        // Verify metadata is set on the durable jobs\n        Assert.Equal(jobMetadata1, job1.Metadata);\n        Assert.Equal(jobMetadata2, job2.Metadata);\n        Assert.Null(job3.Metadata);\n\n        // Mark the silo owning the shard as dead\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Take over the shard with the other silo\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        shard = shards[0];\n\n        // Consume jobs and verify metadata is preserved\n        var consumedJobs = new List<DurableJob>();\n        await foreach (var jobCtx in shard.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job);\n            await shard.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(3, consumedJobs.Count);\n        \n        var consumedJob1 = consumedJobs.First(j => j.Name == \"job1\");\n        var consumedJob2 = consumedJobs.First(j => j.Name == \"job2\");\n        var consumedJob3 = consumedJobs.First(j => j.Name == \"job3\");\n\n        Assert.Equal(jobMetadata1, consumedJob1.Metadata);\n        Assert.Equal(jobMetadata2, consumedJob2.Metadata);\n        Assert.Null(consumedJob3.Metadata);\n\n        await silo2Manager.UnregisterShardAsync(shard, cancellationToken);\n    }\n\n    /// <summary>\n    /// Tests concurrent shard assignment to verify that only one silo can claim ownership of an orphaned shard.\n    /// </summary>\n    public async Task ConcurrentShardAssignment_OwnershipConflicts(CancellationToken cancellationToken)\n    {\n        // Initialize 3 silos with 3 managers\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n        var silo3Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5002), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        SetSiloStatus(silo3Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n        var silo3Manager = CreateManager(silo3Address);\n\n        var date = DateTime.UtcNow;\n\n        // Create two shards on the first silo\n        var shard1 = await silo1Manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n        var shard2 = await silo1Manager.CreateShardAsync(date, date.AddHours(2), _testMetadata, cancellationToken);\n\n        // Mark the first silo as dead\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Concurrently try to assign shards from silo2 and silo3\n        var assignTask2 = silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(3), cancellationToken);\n        var assignTask3 = silo3Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(3), cancellationToken);\n\n        await Task.WhenAll(assignTask2, assignTask3);\n\n        var shards2 = await assignTask2;\n        var shards3 = await assignTask3;\n\n        // Verify that only one silo was able to assign each shard (no duplicates)\n        var totalAssignments = shards2.Count + shards3.Count;\n        Assert.Equal(2, totalAssignments);\n\n        var allAssignedShardIds = shards2.Select(s => s.Id).Concat(shards3.Select(s => s.Id)).ToList();\n        Assert.Contains(shard1.Id, allAssignedShardIds);\n        Assert.Contains(shard2.Id, allAssignedShardIds);\n        Assert.Equal(2, allAssignedShardIds.Distinct().Count());\n    }\n\n    /// <summary>\n    /// Tests that shard metadata is correctly preserved and merged during ownership transfers.\n    /// </summary>\n    public async Task ShardMetadataMerge(CancellationToken cancellationToken)\n    {\n        // Initialize 2 silos with 2 managers\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTime.UtcNow;\n\n        // Create a shard on silo1 with some metadata, then update the metadata and verify it is merged correctly\n        var customMetadata = new Dictionary<string, string>\n        {\n            { \"Environment\", \"Production\" },\n            { \"TenantId\", \"tenant-123\" }\n        };\n\n        var shard = await silo1Manager.CreateShardAsync(date, date.AddHours(1), customMetadata, cancellationToken);\n        Assert.NotNull(shard.Metadata);\n        Assert.All(customMetadata, kvp =>\n        {\n            Assert.True(shard.Metadata.ContainsKey(kvp.Key));\n            Assert.Equal(kvp.Value, shard.Metadata[kvp.Key]);\n        });\n\n        // Schedule a job to ensure shard persistence\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddSeconds(5), Metadata = null }, cancellationToken);\n\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Take over the shard from silo2 and verify the metadata is preserved\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        shard = shards[0];\n\n        Assert.NotNull(shard.Metadata);\n        Assert.All(customMetadata, kvp =>\n        {\n            Assert.True(shard.Metadata.ContainsKey(kvp.Key));\n            Assert.Equal(kvp.Value, shard.Metadata[kvp.Key]);\n        });\n    }\n\n    /// <summary>\n    /// Tests stopping shard processing and verifying jobs remain for reassignment.\n    /// </summary>\n    public async Task StopProcessingShard(CancellationToken cancellationToken)\n    {\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n        var shard1 = await manager.CreateShardAsync(date, date.AddYears(1), _testMetadata, cancellationToken);\n\n        // Schedule some jobs\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddSeconds(5), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job3\", DueTime = DateTime.UtcNow.AddSeconds(10), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = DateTime.UtcNow.AddSeconds(6), Metadata = null }, cancellationToken);\n        await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job4\", DueTime = DateTime.UtcNow.AddSeconds(15), Metadata = null }, cancellationToken);\n\n        var counter = 1;\n        await foreach (var jobCtx in shard1.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            Assert.Equal($\"job{counter}\", jobCtx.Job.Name);\n            if (counter == 2)\n                break;\n            await shard1.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n            counter++;\n        }\n        Assert.Equal(2, counter);\n        await manager.UnregisterShardAsync(shard1, cancellationToken);\n\n        var shards = await manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        Assert.Equal(shard1.Id, shards[0].Id);\n    }\n\n    /// <summary>\n    /// Tests retrying a job with a new due time.\n    /// </summary>\n    public async Task RetryJobLater(CancellationToken cancellationToken)\n    {\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n        var manager = CreateManager(localAddress);\n        var date = DateTime.UtcNow;\n        var shard1 = await manager.CreateShardAsync(date, date.AddYears(1), _testMetadata, cancellationToken);\n\n        // Schedule a job\n        var job = await shard1.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddSeconds(1), Metadata = null }, cancellationToken);\n        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(40));\n        await foreach (var jobCtx in shard1.ConsumeDurableJobsAsync().WithCancellation(cts.Token))\n        {\n            Assert.Equal(\"job1\", jobCtx.Job.Name);\n            var newDueTime = DateTimeOffset.UtcNow.AddSeconds(1);\n            await shard1.RetryJobLaterAsync(jobCtx, newDueTime, cancellationToken);\n            break;\n        }\n\n        // Consume again\n        await foreach (var jobCtx in shard1.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            Assert.Equal(\"job1\", jobCtx.Job.Name);\n            Assert.NotEqual(job.DueTime, jobCtx.Job.DueTime);\n            await shard1.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n            break;\n        }\n        await manager.UnregisterShardAsync(shard1, cancellationToken);\n    }\n    \n\n    /// <summary>\n    /// Tests job cancellation before and during processing.\n    /// </summary>\n    public async Task JobCancellation(CancellationToken cancellationToken)\n    {\n        // Initialize 2 silos with two managers\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTime.UtcNow;\n        var shard = await silo1Manager.CreateShardAsync(date, date.AddYears(1), _testMetadata, cancellationToken);\n\n        // Schedule multiple jobs in a single shard\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddMilliseconds(500), Metadata = null }, cancellationToken);\n        var job2 = await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = DateTime.UtcNow.AddMilliseconds(1000), Metadata = null }, cancellationToken);\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target3\"), JobName = \"job3\", DueTime = DateTime.UtcNow.AddMilliseconds(1500), Metadata = null }, cancellationToken);\n        var job4 = await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target4\"), JobName = \"job4\", DueTime = DateTime.UtcNow.AddMilliseconds(2000), Metadata = null }, cancellationToken);\n\n        // Cancel job2 before processing starts\n        await shard.RemoveJobAsync(job2.Id, cancellationToken);\n\n        // Start consuming jobs\n        var consumedJobs = new List<string>();\n\n        await foreach (var jobCtx in shard.ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n\n            // Cancel job4 during processing (after job1 is consumed)\n            if (jobCtx.Job.Name == \"job1\")\n            {\n                await shard.RemoveJobAsync(job4.Id, cancellationToken);\n            }\n\n            await shard.RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n\n            if (consumedJobs.Count >= 2)\n            {\n                break;\n            }\n        }\n\n        // Verify that only job1 and job3 were consumed (job2 was cancelled before consumption, job4 was cancelled during)\n        Assert.Equal(2, consumedJobs.Count);\n        Assert.Contains(\"job1\", consumedJobs);\n        Assert.Contains(\"job3\", consumedJobs);\n        Assert.DoesNotContain(\"job2\", consumedJobs);\n        Assert.DoesNotContain(\"job4\", consumedJobs);\n\n        // Mark the shard owner silo as dead and reassign to verify cancelled jobs are not in storage\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        shard = shards[0];\n\n        var hasJobs = false;\n        using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n        cts.CancelAfter(TimeSpan.FromSeconds(5));\n        await foreach (var jobCtx in shard.ConsumeDurableJobsAsync().WithCancellation(cts.Token))\n        {\n            hasJobs = true;\n            break;\n        }\n\n        Assert.False(hasJobs);\n        await silo2Manager.UnregisterShardAsync(shard, cancellationToken);\n    }\n\n    /// <summary>\n    /// Tests that multiple shard registrations with the same time range produce unique IDs.\n    /// </summary>\n    public async Task ShardRegistrationRetry_IdCollisions(CancellationToken cancellationToken)\n    {\n        var localAddress = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        SetSiloStatus(localAddress, SiloStatus.Active);\n\n        var manager = CreateManager(localAddress);\n\n        var date = DateTime.UtcNow;\n\n        var shard1 = await manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n        var shard2 = await manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n        var shard3 = await manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n\n        Assert.Distinct([shard1.Id, shard2.Id, shard3.Id]);\n    }\n\n    /// <summary>\n    /// Tests that unregistering a shard with remaining jobs preserves the shard for reassignment.\n    /// </summary>\n    public async Task UnregisterShard_WithJobsRemaining(CancellationToken cancellationToken)\n    {\n        // Initialize 2 silos with 2 managers\n        var silo1Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5000), 0);\n        var silo2Address = SiloAddress.New(new IPEndPoint(IPAddress.Loopback, 5001), 0);\n\n        SetSiloStatus(silo1Address, SiloStatus.Active);\n        SetSiloStatus(silo2Address, SiloStatus.Active);\n        var silo1Manager = CreateManager(silo1Address);\n        var silo2Manager = CreateManager(silo2Address);\n\n        var date = DateTime.UtcNow;\n        var shard = await silo1Manager.CreateShardAsync(date, date.AddHours(1), _testMetadata, cancellationToken);\n\n        // Create a shard on silo1, schedule some jobs, then unregister the shard\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target1\"), JobName = \"job1\", DueTime = DateTime.UtcNow.AddSeconds(1), Metadata = null }, cancellationToken);\n        await shard.TryScheduleJobAsync(new ScheduleJobRequest { Target = GrainId.Create(\"type\", \"target2\"), JobName = \"job2\", DueTime = DateTime.UtcNow.AddSeconds(2), Metadata = null }, cancellationToken);\n\n        await silo1Manager.UnregisterShardAsync(shard, cancellationToken);\n\n        // The shard should NOT have been deleted since there were jobs remaining\n        SetSiloStatus(silo1Address, SiloStatus.Dead);\n\n        // Take over the shard from silo2 and consume the jobs\n        var shards = await silo2Manager.AssignJobShardsAsync(DateTime.UtcNow.AddHours(1), cancellationToken);\n        Assert.Single(shards);\n        Assert.Equal(shard.Id, shards[0].Id);\n\n        var consumedJobs = new List<string>();\n        await foreach (var jobCtx in shards[0].ConsumeDurableJobsAsync().WithCancellation(cancellationToken))\n        {\n            consumedJobs.Add(jobCtx.Job.Name);\n            await shards[0].RemoveJobAsync(jobCtx.Job.Id, cancellationToken);\n        }\n\n        Assert.Equal(2, consumedJobs.Count);\n        Assert.Contains(\"job1\", consumedJobs);\n        Assert.Contains(\"job2\", consumedJobs);\n        await silo2Manager.UnregisterShardAsync(shards[0], cancellationToken);\n    }\n\n    /// <summary>\n    /// Simple implementation of <see cref=\"ILocalSiloDetails\"/> for testing.\n    /// </summary>\n    private sealed class TestLocalSiloDetails : ILocalSiloDetails\n    {\n        public TestLocalSiloDetails(SiloAddress siloAddress)\n        {\n            SiloAddress = siloAddress;\n        }\n\n        public string Name => SiloAddress.ToString();\n\n        public string ClusterId => \"TestCluster\";\n\n        public string DnsHostName => SiloAddress.ToString();\n\n        public SiloAddress SiloAddress { get; }\n\n        public SiloAddress GatewayAddress => SiloAddress;\n    }\n\n    /// <summary>\n    /// Simple in-memory implementation of <see cref=\"IClusterMembershipService\"/> for testing.\n    /// </summary>\n    private sealed class InMemoryClusterMembershipService : IClusterMembershipService\n    {\n        private readonly Dictionary<SiloAddress, ClusterMember> _silos = new();\n        private int _version = 0;\n\n        public ClusterMembershipSnapshot CurrentSnapshot => \n            new ClusterMembershipSnapshot(_silos.ToImmutableDictionary(), new MembershipVersion(_version));\n\n        public IAsyncEnumerable<ClusterMembershipSnapshot> MembershipUpdates => throw new NotImplementedException();\n\n        public void SetSiloStatus(SiloAddress address, SiloStatus status)\n        {\n            _silos[address] = new ClusterMember(address, status, address.ToParsableString());\n            _version++;\n        }\n\n        public ValueTask Refresh(MembershipVersion minimumVersion = default, CancellationToken cancellationToken = default) => \n            ValueTask.CompletedTask;\n\n        public Task<bool> TryKill(SiloAddress siloAddress) => throw new NotImplementedException();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.DurableJobs.Tests/Orleans.DurableJobs.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/AccountGrainTests.cs",
    "content": "using TestGrainInterfaces;\nusing Xunit;\nusing Assert = Xunit.Assert;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Tests for event-sourced account grain functionality including balance operations and transaction logging.\n    /// </summary>\n    public class AccountGrainTests : IClassFixture<EventSourcingClusterFixture>\n    {\n        private readonly EventSourcingClusterFixture fixture;\n\n        public AccountGrainTests(EventSourcingClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        private static async Task TestSequence(IAccountGrain account, bool hasLogStored)\n        {\n            Assert.Equal(0u, await account.Balance());\n\n            var initialdepositguid = Guid.NewGuid();\n            await account.Deposit(100, initialdepositguid, \"initial deposit\");\n\n            Assert.Equal(100u, await account.Balance());\n\n            var firstwithdrawalguid = Guid.NewGuid();\n            var success = await account.Withdraw(70, firstwithdrawalguid, \"first withdrawal\");\n\n            Assert.True(success);\n            Assert.Equal(30u, await account.Balance());\n\n            var secondwithdrawalguid = Guid.NewGuid();\n            success = await account.Withdraw(70, secondwithdrawalguid, \"second withdrawal\");\n\n            Assert.False(success);\n            Assert.Equal(30u, await account.Balance());\n\n            if (hasLogStored)\n            {\n                // check the transaction log\n                var log = await account.GetTransactionLog();\n\n                Assert.Equal(2, log.Count());\n                Assert.Equal(initialdepositguid, log[0].Guid);\n                Assert.Equal(\"initial deposit\", log[0].Description);\n                Assert.Equal(firstwithdrawalguid, log[1].Guid);\n                Assert.Equal(\"first withdrawal\", log[1].Description);\n                Assert.True(log[0].IssueTime < log[1].IssueTime);\n            }\n            else\n            {\n                await Assert.ThrowsAsync<NotSupportedException>(async () => await account.GetTransactionLog());\n            }\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/5605\"), TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task AccountWithLog()\n        {\n            var account = this.fixture.GrainFactory.GetGrain<IAccountGrain>($\"Account-{Guid.NewGuid()}\", \"TestGrains.AccountGrain\");\n            await TestSequence(account, true);\n        }\n\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task AccountWithoutLog()\n        {\n            var account = this.fixture.GrainFactory.GetGrain<IAccountGrain>($\"Account-{Guid.NewGuid()}\", \"TestGrains.AccountGrain_PersistStateOnly\");\n            await TestSequence(account, false);\n        }\n\n    }\n}"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/ChatGrainTests.cs",
    "content": "using TestGrainInterfaces;\nusing Xunit;\nusing Assert = Xunit.Assert;\nusing System.Xml.Linq;\nusing TestGrains;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Tests for event-sourced chat grain functionality including post creation, editing, deletion, and truncation.\n    /// </summary>\n    public class ChatGrainTests : IClassFixture<EventSourcingClusterFixture>\n    {\n        private readonly EventSourcingClusterFixture fixture;\n\n        public ChatGrainTests(EventSourcingClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task Init()\n        {\n            var chat = this.fixture.GrainFactory.GetGrain<IChatGrain>($\"Chatroom-{Guid.NewGuid()}\");\n\n            var content = (await chat.GetChat()).ToString();\n\n            var expectedprefix = $\"<!--This chat room was created by TestGrains.ChatGrain-->{Environment.NewLine}<root>{Environment.NewLine}  <created>\";\n            var expectedsuffix = $\"</created>{Environment.NewLine}  <posts />{Environment.NewLine}</root>\";\n \n            Assert.StartsWith(expectedprefix, content);\n            Assert.EndsWith(expectedsuffix, content);\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task PostThenDelete()\n        {\n            var chat = this.fixture.GrainFactory.GetGrain<IChatGrain>($\"Chatroom-{Guid.NewGuid()}\");\n            var guid = Guid.NewGuid();\n\n            await chat.Post(guid, \"Famous Athlete\", \"I am retiring\");\n\n            {\n                var content = (await chat.GetChat()).ToString();\n                var doc = XDocument.Load(new StringReader(content));\n                var container = doc.GetPostsContainer();\n                Assert.Single(container.Elements(\"post\"));\n            }\n\n            await chat.Delete(guid);\n\n            {\n                var content = (await chat.GetChat()).ToString();\n                var doc = XDocument.Load(new StringReader(content));\n                var container = doc.GetPostsContainer();\n                Assert.Empty(container.Elements(\"post\"));\n            }\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task PostThenEdit()\n        {\n            var chat = this.fixture.GrainFactory.GetGrain<IChatGrain>($\"Chatroom-{Guid.NewGuid()}\");\n            var guid = Guid.NewGuid();\n\n            await chat.Post(Guid.NewGuid(), \"asdf\", \"asdf\");\n            await chat.Post(guid, \"Famous Athlete\", \"I am retiring\");\n            await chat.Post(Guid.NewGuid(), \"456\", \"456\");\n\n            {\n                var content = (await chat.GetChat()).ToString();\n                var doc = XDocument.Load(new StringReader(content));\n                var container = doc.GetPostsContainer();\n                Assert.Equal(3, container.Elements(\"post\").Count());\n            }\n\n            await chat.Edit(guid, \"I am not retiring\");\n\n            {\n                var content = (await chat.GetChat()).ToString();\n                var doc = XDocument.Load(new StringReader(content));\n                var container = doc.GetPostsContainer();\n                Assert.Equal(3, container.Elements(\"post\").Count());\n                var post = doc.FindPost(guid.ToString());\n                Assert.Equal(\"I am not retiring\", post.Element(\"text\").Value);\n            }\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task Truncate()\n        {\n            var chat = this.fixture.GrainFactory.GetGrain<IChatGrain>($\"Chatroom-{Guid.NewGuid()}\");\n\n            for (int i = 0; i < ChatFormat.MaxNumPosts + 10; i++)\n                await chat.Post(Guid.NewGuid(), i.ToString(), i.ToString());\n\n            {\n                var content = (await chat.GetChat()).ToString();\n                var doc = XDocument.Load(new StringReader(content));\n                var container = doc.GetPostsContainer();\n                Assert.Equal(ChatFormat.MaxNumPosts, container.Elements(\"post\").Count());\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/CountersGrainPerfTests.cs",
    "content": "using TestGrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Xunit.Sdk;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Performance tests for event-sourced counters grain comparing different synchronization and reentrancy strategies.\n    /// </summary>\n    [TestCaseOrderer(\"Tester.EventSourcingTests.SimplePriorityOrderer\", \"Tester\")]\n    public partial class CountersGrainTests\n    {\n\n        // you can look at the time taken by each of the tests below\n        // to get a rough idea on how the synchronization choices, and the configuration parameters,\n        // and the consistency provider, affect throughput\n\n        // To run these perf tests from within visual studio, first type\n        // \"CountersGrainTests.Perf\" in the search box, and then \"Run All\"\n        // This will run the warmup and then all tests, in the same test cluster. Afterwards it reports\n        // approximate time taken for each. It's not really a test, just an\n        // illustration of how JournaledGrain performance can vary with the choices made.\n\n        // what you should see is:\n        // - the conservative approach (confirm each update, disallow reentrancy) is slow.\n        // - confirming at end only, instead of after each update, is fast.\n        // - allowing reentrancy, while still confirming after each update, is also fast.\n\n        private const int iterations = 800;\n\n        [Fact, RunThisFirst, TestCategory(\"EventSourcing\")]\n        public Task Perf_Warmup()\n        {\n            // call reset on each grain to ensure everything is loaded and primed\n            return Task.WhenAll(\n                this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_NonReentrant\").Reset(true),\n                this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_Reentrant\").Reset(true),\n                this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_NonReentrant\").Reset(true),\n                this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_Reentrant\").Reset(true)\n            );\n        }\n\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmEachUpdate_MemoryStateStore_NonReentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_NonReentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, true);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmAtEndOnly_MemoryStateStore_NonReentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_NonReentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, false);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmEachUpdate_MemoryLogStore_NonReentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_NonReentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, true);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmAtEndOnly_MemoryLogStore_NonReentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_NonReentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, false);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmEachUpdate_MemoryStateStore_Reentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_Reentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, true);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmAtEndOnly_MemoryStateStore_Reentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_StateStore_Reentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, false);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmEachUpdate_MemoryLogStore_Reentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_Reentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, true);\n        }\n        [Fact, TestCategory(\"EventSourcing\")]\n        public async Task Perf_ConfirmAtEndOnly_MemoryLogStore_Reentrant()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(0, \"TestGrains.CountersGrain_LogStore_Reentrant\");\n            await ConcurrentIncrementsRunner(grain, iterations, false);\n        }\n\n\n    }\n\n    internal class RunThisFirstAttribute : Attribute\n    {\n    }\n\n    public class SimplePriorityOrderer : ITestCaseOrderer\n    {\n        private readonly string attrname = typeof(RunThisFirstAttribute).AssemblyQualifiedName;\n\n        private bool HasRunThisFirstAttribute(ITestCase testcase)\n        {\n            return testcase.TestMethod.Method.GetCustomAttributes(attrname).Any();\n        }\n\n        public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase\n        {\n            // return all tests with RunThisFirst attribute\n            foreach (var tc in testCases.Where(tc => HasRunThisFirstAttribute(tc)))\n                yield return tc;\n\n            // return all other tests\n            foreach (var tc in testCases.Where(tc => !HasRunThisFirstAttribute(tc)))\n                yield return tc;\n        }\n    }\n\n}"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/CountersGrainTests.cs",
    "content": "using TestGrainInterfaces;\nusing Xunit;\nusing Assert = Xunit.Assert;\nusing Orleans.Runtime;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Tests for event-sourced counters grain functionality including concurrent increments and state management.\n    /// </summary>\n    public partial class CountersGrainTests : IClassFixture<EventSourcingClusterFixture>\n    {\n        private readonly EventSourcingClusterFixture fixture;\n\n        public CountersGrainTests(EventSourcingClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task Record()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(GrainId.Create(\"simple-counters-grain\", \"0\"));\n\n            var currentstate = await grain.GetTentativeState();\n            Assert.NotNull(currentstate);\n            Assert.Empty(currentstate);\n\n            await grain.Add(\"Alice\", 1, false);\n            await grain.Add(\"Alice\", 1, false);\n            await grain.Add(\"Alice\", 1, false);\n\n            // all three updates should be visible in the tentative count (even if not confirmed yet)\n            Assert.Equal(3, await grain.GetTentativeCount(\"Alice\"));\n\n            // reset all counters to zero, and wait for confirmation\n            await grain.Reset(true);\n\n            Assert.Empty((await grain.GetTentativeState()));\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task ConcurrentIncrements()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ICountersGrain>(GrainId.Create(\"simple-counters-grain\", \"0\"));\n            await ConcurrentIncrementsRunner(grain, 50, false);\n        }\n\n        private static readonly string[] keys = { \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\" };\n        private static string RandomKey() { return keys[Random.Shared.Next(keys.Length)]; }\n\n\n        private static async Task ConcurrentIncrementsRunner(ICountersGrain grain, int count, bool wait_for_confirmation_on_each)\n        {\n            // increment (count) times, on random keys, concurrently\n            var tasks = new List<Task>();\n            for (int i = 0; i < count; i++)\n                tasks.Add(grain.Add(RandomKey(), 1, wait_for_confirmation_on_each));\n            await Task.WhenAll(tasks);\n\n            // check that the tentative state shows all increments\n            Assert.Equal(count, (await grain.GetTentativeState()).Aggregate(0, (c, kvp) => c + kvp.Value));\n\n            // if we did not wait for confirmation on each event, wait now\n            if (!wait_for_confirmation_on_each)\n                await grain.ConfirmAllPreviouslyRaisedEvents();\n\n            // check that the confirmed state shows all the increments\n            Assert.Equal(count, (await grain.GetConfirmedState()).Aggregate(0, (c, kvp) => c + kvp.Value));\n\n            // reset all counters\n            await grain.Reset(true);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/EventSourcingClusterFixture.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.EventSourcing.CustomStorage;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing TestExtensions;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// We use a special fixture for event sourcing tests \n    /// so we can add the required log consistency providers, and \n    /// do more tracing\n    /// </summary>\n    public class EventSourcingClusterFixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<TestSiloConfigurator>();\n        }\n\n        private class TestSiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                // we use a slowed-down memory storage provider\n                hostBuilder\n                    .AddLogStorageBasedLogConsistencyProvider(\"LogStorage\")\n                    .AddStateStorageBasedLogConsistencyProvider(\"StateStorage\")\n                    .AddCustomStorageBasedLogConsistencyProvider(\"CustomStoragePrimaryCluster\")\n                    .ConfigureLogging(builder =>\n                    {\n                        builder.AddFilter(typeof(MemoryGrainStorage).FullName, LogLevel.Debug);\n                        builder.AddFilter(typeof(LogConsistencyProvider).Namespace, LogLevel.Debug);\n                    })\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"AzureStore\")\n                    .AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddFaultInjectionMemoryStorage(\"SlowMemoryStore\", options=>options.NumStorageGrains = 10, faultyOptions => faultyOptions.Latency = TimeSpan.FromMilliseconds(15));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/LogTestGrainClearTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Orleans.Storage;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Assert = Xunit.Assert;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Integration tests for clear-log behavior on non-Azure log test grain configurations.\n    /// </summary>\n    public class LogTestGrainClearTests : IClassFixture<EventSourcingClusterFixture>\n    {\n        private readonly EventSourcingClusterFixture fixture;\n\n        public LogTestGrainClearTests(EventSourcingClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Theory, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        [InlineData(\"TestGrains.LogTestGrainDefaultStorage\", 721001L)]\n        [InlineData(\"TestGrains.LogTestGrainSharedLogStorage\", 721002L)]\n        [InlineData(\"TestGrains.LogTestGrainCustomStoragePrimaryCluster\", 721003L)]\n        public async Task ClearLog_ResetDropsTentativeAndAllowsFurtherWrites(string grainClass, long grainId)\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILogTestGrain>(grainId, grainClass);\n\n            await grain.Clear();\n            await grain.SetAGlobal(10);\n            Assert.Equal(10, await grain.GetAGlobal());\n            Assert.Equal(1, await grain.GetConfirmedVersion());\n\n            await grain.SetALocal(99);\n            await grain.SetBLocal(77);\n            var tentativeBeforeClear = await grain.GetBothLocal();\n            Assert.Equal(99, tentativeBeforeClear.A);\n            Assert.Equal(77, tentativeBeforeClear.B);\n\n            await grain.Clear();\n            Assert.Equal(0, await grain.GetConfirmedVersion());\n\n            var confirmedAfterClear = await grain.GetBothGlobal();\n            Assert.Equal(0, confirmedAfterClear.A);\n            Assert.Equal(0, confirmedAfterClear.B);\n\n            var tentativeAfterClear = await grain.GetBothLocal();\n            Assert.Equal(0, tentativeAfterClear.A);\n            Assert.Equal(0, tentativeAfterClear.B);\n\n            await grain.SetAGlobal(41);\n            await grain.IncrementAGlobal();\n            Assert.Equal(42, await grain.GetAGlobal());\n            Assert.Equal(2, await grain.GetConfirmedVersion());\n\n            await grain.Clear();\n            var exceptions = await RunConcurrentOperationsAroundClear(grain);\n            Assert.DoesNotContain(exceptions, static ex => ex is InconsistentStateException);\n            Assert.Empty(exceptions);\n\n            await grain.Clear();\n            await grain.SetAGlobal(7);\n            Assert.Equal(7, await grain.GetAGlobal());\n            Assert.Equal(1, await grain.GetConfirmedVersion());\n        }\n\n        private static async Task<List<Exception>> RunConcurrentOperationsAroundClear(ILogTestGrain grain)\n        {\n            var gate = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);\n            var exceptions = new List<Exception>();\n            var syncLock = new object();\n\n            Task Run(Func<Task> operation)\n            {\n                return Task.Run(async () =>\n                {\n                    await gate.Task;\n                    try\n                    {\n                        await operation();\n                    }\n                    catch (Exception exception)\n                    {\n                        lock (syncLock)\n                        {\n                            exceptions.Add(exception);\n                        }\n                    }\n                });\n            }\n\n            var operations = new[]\n            {\n                Run(() => grain.SetALocal(1)),\n                Run(() => grain.SetAGlobal(2)),\n                Run(() => grain.IncrementAGlobal()),\n                Run(() => grain.Clear()),\n                Run(() => grain.SetAGlobal(3)),\n                Run(async () => _ = await grain.GetAGlobal()),\n            };\n\n            gate.SetResult(true);\n            await Task.WhenAll(operations);\n            return exceptions;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/EventSourcingTests/PersonGrainTests.cs",
    "content": "﻿using TestGrainInterfaces;\nusing Xunit;\nusing Assert = Xunit.Assert;\n\nnamespace Tester.EventSourcingTests\n{\n    /// <summary>\n    /// Tests for journaled person grain functionality including birth registration, marriage events, and state transitions.\n    /// </summary>\n    public class PersonGrainTests : IClassFixture<EventSourcingClusterFixture>\n    {\n        private readonly EventSourcingClusterFixture fixture;\n\n        public PersonGrainTests(EventSourcingClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task JournaledGrainTests_Activate()\n        {\n            var grainWithState = this.fixture.GrainFactory.GetGrain<IPersonGrain>(Guid.Empty);\n\n            Assert.NotNull(await grainWithState.GetTentativePersonalAttributes());\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task JournaledGrainTests_Persist()\n        {\n            var grainWithState = this.fixture.GrainFactory.GetGrain<IPersonGrain>(Guid.Empty);\n\n            await grainWithState.RegisterBirth(new PersonAttributes { FirstName = \"Luke\", LastName = \"Skywalker\", Gender = GenderType.Male });\n\n            var attributes = await grainWithState.GetTentativePersonalAttributes();\n\n            Assert.NotNull(attributes);\n            Assert.Equal(\"Luke\", attributes.FirstName);\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task JournaledGrainTests_AppendMoreEvents()\n        {\n            var leia = this.fixture.GrainFactory.GetGrain<IPersonGrain>(Guid.NewGuid());\n            await leia.RegisterBirth(new PersonAttributes { FirstName = \"Leia\", LastName = \"Organa\", Gender = GenderType.Female });\n\n            var han = this.fixture.GrainFactory.GetGrain<IPersonGrain>(Guid.NewGuid());\n            await han.RegisterBirth(new PersonAttributes { FirstName = \"Han\", LastName = \"Solo\", Gender = GenderType.Male });\n\n            await leia.Marry(han);\n\n            var attributes = await leia.GetTentativePersonalAttributes();\n            Assert.NotNull(attributes);\n            Assert.Equal(\"Leia\", attributes.FirstName);\n            Assert.Equal(\"Solo\", attributes.LastName);\n        }\n\n        [Fact, TestCategory(\"EventSourcing\"), TestCategory(\"Functional\")]\n        public async Task JournaledGrainTests_TentativeConfirmedState()\n        {\n            var leia = this.fixture.GrainFactory.GetGrain<IPersonGrain>(Guid.NewGuid());\n\n            // the whole test has to run inside the grain, otherwise the interleaving of \n            // the individual steps is nondeterministic\n            await leia.RunTentativeConfirmedStateTest();\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.EventSourcing.Tests/Orleans.EventSourcing.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.GrainDirectory.Tests/GrainDirectory/DistributedGrainDirectoryTests.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.GrainDirectory;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.TestingHost;\nusing Tester.Directories;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.GrainDirectory;\n\n[TestCategory(\"BVT\"), TestCategory(\"Directory\")]\npublic sealed class DefaultGrainDirectoryTests(DefaultClusterFixture fixture, ITestOutputHelper output)\n    : GrainDirectoryTests<IGrainDirectory>(output), IClassFixture<DefaultClusterFixture>\n{\n    private readonly TestCluster _testCluster = fixture.HostedCluster;\n    private InProcessSiloHandle Primary => (InProcessSiloHandle)_testCluster.Primary;\n\n    protected override IGrainDirectory CreateGrainDirectory() =>\n        Primary.SiloHost.Services.GetRequiredService<GrainDirectoryResolver>().DefaultGrainDirectory;\n}\n"
  },
  {
    "path": "test/Orleans.GrainDirectory.Tests/GrainDirectory/GrainDirectoryResilienceTests.cs",
    "content": "#nullable enable\nusing System.Diagnostics;\nusing System.Globalization;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.GrainDirectory;\n\ninternal interface IMyDirectoryTestGrain : IGrainWithIntegerKey\n{\n    ValueTask Ping();\n}\n\n[CollectionAgeLimit(Minutes = 1.01)]\ninternal class MyDirectoryTestGrain : Grain, IMyDirectoryTestGrain\n{\n    public ValueTask Ping() => default;\n}\n\n[TestCategory(\"Stress\"), TestCategory(\"Directory\")]\npublic sealed class GrainDirectoryResilienceTests\n{\n    /// <summary>\n    /// Cluster chaos test: tests directory functionality & integrity while starting/stopping/killing silos frequently.\n    /// </summary>\n    /// <returns></returns>\n    [Fact]\n    public async Task ElasticChaos()\n    {\n        var testClusterBuilder = new TestClusterBuilder(1);\n        testClusterBuilder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        var testCluster = testClusterBuilder.Build();\n        await testCluster.DeployAsync();\n        var log = testCluster.ServiceProvider.GetRequiredService<ILogger<GrainDirectoryResilienceTests>>();\n        log.LogInformation(\"ServiceId: '{ServiceId}'\", testCluster.Options.ServiceId);\n        log.LogInformation(\"ClusterId: '{ClusterId}'.\", testCluster.Options.ClusterId);\n\n        var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));\n        var reconfigurationTimer = CoarseStopwatch.StartNew();\n        var upperLimit = 10;\n        var lowerLimit = 1; // Membership is kept on the primary, so we can't go below 1\n        var target = upperLimit;\n        var idBase = 0L;\n        var client = ((InProcessSiloHandle)testCluster.Primary).SiloHost.Services.GetRequiredService<IGrainFactory>();\n        const int CallsPerIteration = 100;\n        var loadTask = Task.Run(async () =>\n        {\n            while (!cts.IsCancellationRequested)\n            {\n                var time = Stopwatch.StartNew();\n                var tasks = Enumerable.Range(0, CallsPerIteration).Select(i => client.GetGrain<IMyDirectoryTestGrain>(idBase + i).Ping().AsTask()).ToList();\n                var workTask = Task.WhenAll(tasks);\n                \n                try\n                {\n                    await workTask;\n                }\n                catch (SiloUnavailableException sue)\n                {\n                    log.LogInformation(sue, \"Swallowed transient exception.\");\n                }\n                catch (OrleansMessageRejectionException omre)\n                {\n                   log.LogInformation(omre, \"Swallowed rejection.\");\n                }\n                catch (Exception exception)\n                {\n                    log.LogError(exception, \"Unhandled exception.\");\n                    throw;\n                }\n\n                idBase += CallsPerIteration;\n            }\n        });\n\n        var chaosTask = Task.Run(async () =>\n        {\n            var clusterOperation = Task.CompletedTask;\n            while (!cts.IsCancellationRequested)\n            {\n                try\n                {\n                    var remaining = TimeSpan.FromSeconds(10) - reconfigurationTimer.Elapsed;\n                    if (remaining <= TimeSpan.Zero)\n                    {\n                        reconfigurationTimer.Restart();\n                        await clusterOperation;\n\n                        // Check integrity\n                        var integrityChecks = new List<Task>();\n                        foreach (var silo in testCluster.Silos)\n                        {\n                            var address = silo.SiloAddress;\n                            for (var partitionIndex = 0; partitionIndex < DirectoryMembershipSnapshot.PartitionsPerSilo; partitionIndex++)\n                            {\n                                var replica = ((IInternalGrainFactory)client).GetSystemTarget<IGrainDirectoryTestHooks>(GrainDirectoryPartition.CreateGrainId(address, partitionIndex).GrainId);\n                                integrityChecks.Add(replica.CheckIntegrityAsync().AsTask());\n                            }\n                        }\n\n                        await Task.WhenAll(integrityChecks);\n                        foreach (var task in integrityChecks)\n                        {\n                            await task;\n                        }\n\n                        clusterOperation = Task.Run(async () =>\n                        {\n                            var currentCount = testCluster.Silos.Count;\n\n                            if (currentCount > target)\n                            {\n                                // Stop or kill a random silo, but not the primary (since that hosts cluster membership)\n                                var victim = testCluster.SecondarySilos[Random.Shared.Next(testCluster.SecondarySilos.Count)];\n                                if (currentCount % 2 == 0)\n                                {\n                                    log.LogInformation(\"Stopping '{Silo}'.\", victim.SiloAddress);\n                                    await testCluster.StopSiloAsync(victim);\n                                    log.LogInformation(\"Stopped '{Silo}'.\", victim.SiloAddress);\n                                }\n                                else\n                                {\n                                    log.LogInformation(\"Killing '{Silo}'.\", victim.SiloAddress);\n                                    await testCluster.KillSiloAsync(victim);\n                                    log.LogInformation(\"Killed '{Silo}'.\", victim.SiloAddress);\n                                }\n                            }\n                            else if (currentCount < target)\n                            {\n                                log.LogInformation(\"Starting new silo.\");\n                                var result = await testCluster.StartAdditionalSiloAsync();\n                                log.LogInformation(\"Started '{Silo}'.\", result.SiloAddress);\n                            }\n\n                            if (currentCount <= lowerLimit)\n                            {\n                                target = upperLimit;\n                            }\n                            else if (currentCount >= upperLimit)\n                            {\n                                target = lowerLimit;\n                            }\n                        });\n                    }\n                    else\n                    {\n                        await Task.Delay(remaining);\n                    }\n                }\n                catch (Exception exception)\n                {\n                    log.LogInformation(exception, \"Ignoring chaos exception.\");\n                }\n            }\n        });\n\n        await await Task.WhenAny(loadTask, chaosTask);\n        cts.Cancel();\n        await Task.WhenAll(loadTask, chaosTask);\n        await testCluster.StopAllSilosAsync();\n        await testCluster.DisposeAsync();\n    }\n\n    private class SiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder siloBuilder)\n        {\n            siloBuilder.Configure<SiloMessagingOptions>(o => o.ResponseTimeout = o.SystemResponseTimeout = TimeSpan.FromMinutes(2));\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n            siloBuilder.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.GrainDirectory.Tests/Orleans.GrainDirectory.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/DurableDictionaryTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Tests for DurableDictionary, a persistent dictionary implementation that uses Orleans' journaling\n/// infrastructure to maintain state across grain activations and system restarts.\n/// \n/// DurableDictionary is part of Orleans' event sourcing capabilities, providing a dictionary\n/// data structure that automatically persists all operations (add, update, remove) to a\n/// durable log. This ensures that the dictionary state can be recovered after failures.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class DurableDictionaryTests : StateMachineTestBase\n{\n    /// <summary>\n    /// Tests basic dictionary operations including add, update, remove, and indexer access.\n    /// Verifies that the DurableDictionary behaves like a standard dictionary while\n    /// persisting state changes through the state machine manager.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_BasicOperations_Test()\n    {\n        // Arrange - Create a durable dictionary with string keys and int values\n        // The dictionary requires codecs for serializing keys and values to the journal\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var keyCodec = CodecProvider.GetCodec<string>();\n        var valueCodec = CodecProvider.GetCodec<int>();\n        var dictionary = new DurableDictionary<string, int>(\"testDict\", sut.Manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Add items to the dictionary\n        // Each operation is journaled but not persisted until WriteStateAsync is called\n        dictionary.Add(\"one\", 1);\n        dictionary.Add(\"two\", 2);\n        dictionary.Add(\"three\", 3);\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(3, dictionary.Count);\n        Assert.Equal(1, dictionary[\"one\"]);\n        Assert.Equal(2, dictionary[\"two\"]);\n        Assert.Equal(3, dictionary[\"three\"]);\n        \n        // Act - Update item\n        dictionary[\"two\"] = 22;\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(22, dictionary[\"two\"]);\n        \n        // Act - Remove item\n        var removed = dictionary.Remove(\"three\");\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.True(removed);\n        Assert.Equal(2, dictionary.Count);\n        Assert.False(dictionary.ContainsKey(\"three\"));\n    }\n    \n    /// <summary>\n    /// Tests that dictionary state is correctly persisted and can be recovered.\n    /// Creates a dictionary, adds items, then creates a new dictionary instance\n    /// using the same storage to verify state recovery.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_Persistence_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var keyCodec = CodecProvider.GetCodec<string>();\n        var valueCodec = CodecProvider.GetCodec<int>();\n        var dictionary1 = new DurableDictionary<string, int>(\"testDict\", sut.Manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Add items and persist\n        dictionary1.Add(\"one\", 1);\n        dictionary1.Add(\"two\", 2);\n        dictionary1.Add(\"three\", 3);\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n        \n        // Create a new manager with the same storage to simulate recovery after restart\n        // This tests the journaling system's ability to replay operations and restore state\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var dictionary2 = new DurableDictionary<string, int>(\"testDict\", sut2.Manager, keyCodec, valueCodec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n        \n        // Assert - Dictionary should be recovered\n        Assert.Equal(3, dictionary2.Count);\n        Assert.Equal(1, dictionary2[\"one\"]);\n        Assert.Equal(2, dictionary2[\"two\"]);\n        Assert.Equal(3, dictionary2[\"three\"]);\n    }\n    \n    /// <summary>\n    /// Tests that the dictionary correctly handles complex key types.\n    /// Verifies that custom key objects with multiple properties are properly\n    /// serialized, stored, and used for lookups.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_ComplexKeys_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var keyCodec = CodecProvider.GetCodec<TestKey>();\n        var valueCodec = CodecProvider.GetCodec<string>();\n        var dictionary = new DurableDictionary<TestKey, string>(\"complexDict\", manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act\n        var key1 = new TestKey { Id = 1, Name = \"Key1\" };\n        var key2 = new TestKey { Id = 2, Name = \"Key2\" };\n        \n        dictionary.Add(key1, \"Value1\");\n        dictionary.Add(key2, \"Value2\");\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(2, dictionary.Count);\n        Assert.Equal(\"Value1\", dictionary[key1]);\n        Assert.Equal(\"Value2\", dictionary[key2]);\n    }\n    \n    /// <summary>\n    /// Tests that the dictionary correctly handles complex value types.\n    /// Verifies that custom objects with multiple properties can be stored\n    /// and retrieved, and that mutations to retrieved objects are persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_ComplexValues_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var keyCodec = CodecProvider.GetCodec<string>();\n        var valueCodec = CodecProvider.GetCodec<TestPerson>();\n        var dictionary = new DurableDictionary<string, TestPerson>(\"peopleDict\", manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act\n        var person1 = new TestPerson { Id = 1, Name = \"John\", Age = 30 };\n        var person2 = new TestPerson { Id = 2, Name = \"Jane\", Age = 25 };\n        \n        dictionary.Add(\"person1\", person1);\n        dictionary.Add(\"person2\", person2);\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(2, dictionary.Count);\n        Assert.Equal(\"John\", dictionary[\"person1\"].Name);\n        Assert.Equal(25, dictionary[\"person2\"].Age);\n        \n        // Act - Update\n        dictionary[\"person1\"].Age = 31;\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(31, dictionary[\"person1\"].Age);\n    }\n    \n    /// <summary>\n    /// Tests the Clear operation which removes all items from the dictionary.\n    /// Verifies that the clear operation is properly journaled and persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_Clear_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var keyCodec = CodecProvider.GetCodec<string>();\n        var valueCodec = CodecProvider.GetCodec<int>();\n        var dictionary = new DurableDictionary<string, int>(\"clearDict\", manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        dictionary.Add(\"one\", 1);\n        dictionary.Add(\"two\", 2);\n        dictionary.Add(\"three\", 3);\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act - Clear\n        dictionary.Clear();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Empty(dictionary);\n    }\n    \n    /// <summary>\n    /// Tests enumeration capabilities of the durable dictionary.\n    /// Verifies that the dictionary supports standard enumeration patterns\n    /// and provides access to Keys and Values collections.\n    /// </summary>\n    [Fact]\n    public async Task DurableDictionary_Enumeration_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var keyCodec = CodecProvider.GetCodec<string>();\n        var valueCodec = CodecProvider.GetCodec<int>();\n        var dictionary = new DurableDictionary<string, int>(\"enumDict\", manager, keyCodec, valueCodec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        var expectedPairs = new Dictionary<string, int>\n        {\n            { \"one\", 1 },\n            { \"two\", 2 },\n            { \"three\", 3 }\n        };\n        \n        foreach (var pair in expectedPairs)\n        {\n            dictionary.Add(pair.Key, pair.Value);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act & Assert - Test enumeration\n        var actualPairs = dictionary.ToDictionary(kv => kv.Key, kv => kv.Value);\n        Assert.Equal(expectedPairs, actualPairs);\n        \n        // Test Keys and Values collections\n        Assert.Equal(expectedPairs.Keys, dictionary.Keys);\n        Assert.Equal(expectedPairs.Values, dictionary.Values);\n    }\n}\n\n/// <summary>\n/// Test key type used to verify that complex keys with multiple properties\n/// can be used in durable dictionaries. The GenerateSerializer attribute ensures\n/// Orleans can serialize this type for journaling.\n/// </summary>\n[GenerateSerializer]\npublic record class TestKey\n{\n    [Id(0)]\n    public int Id { get; set; }\n    [Id(1)]\n    public string? Name { get; set; }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/DurableGrainTests.cs",
    "content": "using Orleans.Core.Internal;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Integration tests for DurableGrain functionality in Orleans.\n/// \n/// DurableGrain is a base class that provides automatic state persistence using Orleans' journaling\n/// infrastructure. It ensures that grain state survives grain deactivations, node failures, and\n/// system restarts by journaling all state modifications to a durable log.\n/// \n/// These tests verify:\n/// - State persistence across grain activations\n/// - Support for complex types and collections\n/// - Multiple durable collections in a single grain\n/// - Large state handling\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class DurableGrainTests(IntegrationTestFixture fixture) : IClassFixture<IntegrationTestFixture>\n{\n    private IGrainFactory Client => fixture.Client;\n\n    /// <summary>\n    /// Tests basic state persistence for a durable grain.\n    /// Verifies that simple state properties (string and int) are correctly\n    /// persisted and recovered after grain deactivation.\n    /// </summary>\n    [Fact]\n    public async Task DurableGrain_State_Persistence_Test()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestDurableGrain>(Guid.NewGuid());\n\n        // Act - Set state properties and persist\n        await grain.SetTestValues(\"Test Name\", 42);\n\n        // Assert\n        Assert.Equal(\"Test Name\", await grain.GetName());\n        Assert.Equal(42, await grain.GetCounter());\n\n        // Force deactivation and get a new reference\n        // This simulates grain failure or node restart scenarios\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - State should be recovered\n        Assert.Equal(\"Test Name\", await grain.GetName());\n        Assert.Equal(42, await grain.GetCounter());\n    }\n\n    /// <summary>\n    /// Tests that state updates are properly journaled and persisted.\n    /// Verifies that the latest state values are recovered after deactivation,\n    /// not the initial values.\n    /// </summary>\n    [Fact]\n    public async Task DurableGrain_Update_State_Test()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestDurableGrain>(Guid.NewGuid());\n\n        // Act - Set state and persist\n        await grain.SetTestValues(\"Initial Name\", 10);\n\n        // Update state and persist again\n        await grain.SetTestValues(\"Updated Name\", 20);\n\n        // Assert\n        Assert.Equal(\"Updated Name\", await grain.GetName());\n        Assert.Equal(20, await grain.GetCounter());\n\n        // Force deactivation and get a new reference\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n\n        // Assert - Updated state should be recovered\n        Assert.Equal(\"Updated Name\", await grain.GetName());\n        Assert.Equal(20, await grain.GetCounter());\n    }\n\n    /// <summary>\n    /// Tests persistence of complex types including custom objects and collections.\n    /// Verifies that Orleans' serialization correctly handles nested objects\n    /// and collections in durable grain state.\n    /// </summary>\n    [Fact]\n    public async Task DurableGrain_Complex_Types_Test()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestDurableGrainWithComplexState>(Guid.NewGuid());\n\n        // Act - Set complex state and persist\n        var person = new TestPerson { Id = 1, Name = \"John Doe\", Age = 30 };\n        var items = new List<string> { \"Item1\", \"Item2\", \"Item3\" };\n        await grain.SetTestValues(person, items);\n\n        // Assert\n        var retrievedPerson = await grain.GetPerson();\n        var retrievedItems = await grain.GetItems();\n\n        Assert.Equal(\"John Doe\", retrievedPerson.Name);\n        Assert.Equal(3, retrievedItems.Count);\n\n        // Force deactivation and get a new reference\n        // This simulates grain failure or node restart scenarios\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - Complex state should be recovered\n        retrievedPerson = await grain.GetPerson();\n        retrievedItems = await grain.GetItems();\n\n        Assert.NotNull(retrievedPerson);\n        Assert.Equal(1, retrievedPerson.Id);\n        Assert.Equal(\"John Doe\", retrievedPerson.Name);\n        Assert.Equal(30, retrievedPerson.Age);\n\n        Assert.Equal(3, retrievedItems.Count);\n        Assert.Equal(\"Item1\", retrievedItems[0]);\n        Assert.Equal(\"Item2\", retrievedItems[1]);\n        Assert.Equal(\"Item3\", retrievedItems[2]);\n    }\n\n    /// <summary>\n    /// Tests a grain that uses multiple durable collections simultaneously.\n    /// Verifies that DurableDictionary, DurableList, DurableQueue, and DurableSet\n    /// can coexist in a single grain and maintain their state independently.\n    /// </summary>\n    [Fact]\n    public async Task DurableGrain_Multiple_Collections_Test()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestMultiCollectionGrain>(Guid.NewGuid());\n\n        // Act - Populate collections and persist\n        await grain.AddToDictionary(\"key1\", 1);\n        await grain.AddToDictionary(\"key2\", 2);\n        await grain.AddToList(\"item1\");\n        await grain.AddToList(\"item2\");\n        await grain.AddToQueue(100);\n        await grain.AddToQueue(200);\n        await grain.AddToSet(\"set1\");\n        await grain.AddToSet(\"set2\");\n\n        // Assert\n        Assert.Equal(2, await grain.GetDictionaryCount());\n        Assert.Equal(2, await grain.GetListCount());\n        Assert.Equal(2, await grain.GetQueueCount());\n        Assert.Equal(2, await grain.GetSetCount());\n\n        // Force deactivation and get a new reference\n        // This simulates grain failure or node restart scenarios\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - All collections should be recovered\n        Assert.Equal(2, await grain.GetDictionaryCount());\n        Assert.Equal(1, await grain.GetDictionaryValue(\"key1\"));\n        Assert.Equal(2, await grain.GetDictionaryValue(\"key2\"));\n\n        Assert.Equal(2, await grain.GetListCount());\n        Assert.Equal(\"item1\", await grain.GetListItem(0));\n        Assert.Equal(\"item2\", await grain.GetListItem(1));\n\n        Assert.Equal(2, await grain.GetQueueCount());\n        Assert.Equal(100, await grain.PeekQueueItem());\n\n        Assert.Equal(2, await grain.GetSetCount());\n        Assert.True(await grain.ContainsSetItem(\"set1\"));\n        Assert.True(await grain.ContainsSetItem(\"set2\"));\n    }\n\n    /// <summary>\n    /// Tests complex state modification scenarios including updates and removals.\n    /// Verifies that all modification operations (add, update, remove) are properly\n    /// journaled and the final state is correctly recovered.\n    /// </summary>\n    [Fact]\n    public async Task DurableGrain_State_Modifications_Test()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestMultiCollectionGrain>(Guid.NewGuid());\n\n        // Act - Populate initial state and persist\n        await grain.AddToDictionary(\"key1\", 1);\n        await grain.AddToList(\"item1\");\n        await grain.AddToQueue(100);\n        await grain.AddToSet(\"set1\");\n\n        // Modify state and persist again\n        await grain.AddToDictionary(\"key2\", 2);\n        await grain.AddToDictionary(\"key1\", 10); // Update via interface method\n        await grain.AddToList(\"item2\");\n        await grain.AddToQueue(200);\n        await grain.AddToSet(\"set2\");\n\n        // Assert\n        Assert.Equal(2, await grain.GetDictionaryCount());\n        Assert.Equal(10, await grain.GetDictionaryValue(\"key1\"));\n        Assert.Equal(2, await grain.GetListCount());\n        Assert.Equal(2, await grain.GetQueueCount());\n        Assert.Equal(2, await grain.GetSetCount());\n\n        // Force deactivation and get a new reference\n        // This simulates grain failure or node restart scenarios\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - Modified state should be recovered\n        Assert.Equal(2, await grain.GetDictionaryCount());\n        Assert.Equal(10, await grain.GetDictionaryValue(\"key1\"));\n        Assert.Equal(2, await grain.GetDictionaryValue(\"key2\"));\n\n        Assert.Equal(2, await grain.GetListCount());\n        Assert.Equal(\"item1\", await grain.GetListItem(0));\n        Assert.Equal(\"item2\", await grain.GetListItem(1));\n\n        // Further modify the state\n        await grain.RemoveFromDictionary(\"key1\");\n        await grain.RemoveListItemAt(0);\n        await grain.DequeueItem();\n        await grain.RemoveFromSet(\"set1\");\n\n        // Assert the modifications\n        Assert.Equal(1, await grain.GetDictionaryCount());\n        Assert.Equal(1, await grain.GetListCount());\n        Assert.Equal(1, await grain.GetQueueCount());\n        Assert.Equal(1, await grain.GetSetCount());\n    }\n\n    /// <summary>\n    /// Tests grain state persistence using a different grain interface.\n    /// This test provides an additional verification of the durability mechanism\n    /// using a simpler grain interface.\n    /// </summary>\n    [Fact]\n    public async Task Grain_State_Should_Persist_Between_Activations()\n    {\n        // Arrange - Get a reference to a grain\n        var grain = Client.GetGrain<ITestDurableGrainInterface>(Guid.NewGuid());\n\n        // Act - Set the grain state\n        await grain.SetValues(\"Test Name\", 42);\n        var initialState = await grain.GetValues();\n\n        // Deactivate the grain forcefully\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Get the values from the grain (which will be reactivated)\n        var newState = await grain.GetValues();\n\n        // Assert\n        Assert.Equal(initialState.Name, newState.Name);\n        Assert.Equal(initialState.Counter, newState.Counter);\n    }\n\n    /// <summary>\n    /// Comprehensive test for multiple collection operations and persistence.\n    /// Tests add, remove, and query operations on all collection types,\n    /// verifying state consistency across multiple deactivation cycles.\n    /// </summary>\n    [Fact]\n    public async Task Grain_Should_Handle_Multiple_Collections()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestMultiCollectionGrain>(Guid.NewGuid());\n\n        // Act - Add items to collections\n        await grain.AddToDictionary(\"key1\", 1);\n        await grain.AddToDictionary(\"key2\", 2);\n\n        await grain.AddToList(\"item1\");\n        await grain.AddToList(\"item2\");\n\n        await grain.AddToQueue(100);\n        await grain.AddToQueue(200);\n\n        await grain.AddToSet(\"set1\");\n        await grain.AddToSet(\"set2\");\n        await grain.AddToSet(\"set1\"); // Duplicate, should be ignored\n\n        // Assert - Check counts\n        Assert.Equal(2, await grain.GetDictionaryCount());\n        Assert.Equal(2, await grain.GetListCount());\n        Assert.Equal(2, await grain.GetQueueCount());\n        Assert.Equal(2, await grain.GetSetCount());\n\n        // Deactivate the grain forcefully\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - Check values after reactivation\n        Assert.Equal(1, await grain.GetDictionaryValue(\"key1\"));\n        Assert.Equal(2, await grain.GetDictionaryValue(\"key2\"));\n        Assert.Equal(\"item1\", await grain.GetListItem(0));\n        Assert.Equal(\"item2\", await grain.GetListItem(1));\n        Assert.Equal(100, await grain.PeekQueueItem());\n        Assert.True(await grain.ContainsSetItem(\"set1\"));\n        Assert.True(await grain.ContainsSetItem(\"set2\"));\n\n        // Act - Modify collections\n        await grain.RemoveFromDictionary(\"key1\");\n        await grain.RemoveListItemAt(0);\n        await grain.DequeueItem();\n        await grain.RemoveFromSet(\"set1\");\n\n        // Assert - Check counts after modifications\n        Assert.Equal(1, await grain.GetDictionaryCount());\n        Assert.Equal(1, await grain.GetListCount());\n        Assert.Equal(1, await grain.GetQueueCount());\n        Assert.Equal(1, await grain.GetSetCount());\n\n        // Deactivate the grain again\n        idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - Check values after second reactivation\n        Assert.Equal(1, await grain.GetDictionaryCount());\n        Assert.Equal(1, await grain.GetListCount());\n        Assert.Equal(1, await grain.GetQueueCount());\n        Assert.Equal(1, await grain.GetSetCount());\n        Assert.Equal(2, await grain.GetDictionaryValue(\"key2\"));\n        Assert.Equal(\"item2\", await grain.GetListItem(0));\n        Assert.Equal(200, await grain.PeekQueueItem());\n        Assert.True(await grain.ContainsSetItem(\"set2\"));\n    }\n\n    /// <summary>\n    /// Stress test for large state handling in durable grains.\n    /// Verifies that the journaling system can handle grains with thousands\n    /// of state entries without performance degradation or data loss.\n    /// </summary>\n    [Fact]\n    public async Task Grain_Should_Handle_Large_State()\n    {\n        // Arrange\n        var grain = Client.GetGrain<ITestMultiCollectionGrain>(Guid.NewGuid());\n\n        // Act - Add many items\n        const int itemCount = 1000;\n        for (int i = 0; i < itemCount; i++)\n        {\n            await grain.AddToDictionary($\"key{i}\", i);\n            if (i < 100) // Add fewer items to other collections to keep test runtime reasonable\n            {\n                await grain.AddToList($\"item{i}\");\n                await grain.AddToQueue(i);\n                await grain.AddToSet($\"set{i}\");\n            }\n        }\n\n        // Assert - Check counts\n        Assert.Equal(itemCount, await grain.GetDictionaryCount());\n        Assert.Equal(100, await grain.GetListCount());\n        Assert.Equal(100, await grain.GetQueueCount());\n        Assert.Equal(100, await grain.GetSetCount());\n\n        // Deactivate the grain forcefully\n        var idBefore = await grain.GetActivationId();\n        await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n        Assert.NotEqual(idBefore, await grain.GetActivationId());\n\n        // Assert - Check random values after reactivation\n        for (int i = 0; i < 10; i++)\n        {\n            var randomIndex = new Random().Next(0, itemCount - 1);\n            Assert.Equal(randomIndex, await grain.GetDictionaryValue($\"key{randomIndex}\"));\n\n            if (randomIndex < 100)\n            {\n                Assert.Equal($\"item{randomIndex}\", await grain.GetListItem(randomIndex));\n                Assert.True(await grain.ContainsSetItem($\"set{randomIndex}\"));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/DurableQueueTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Tests for DurableQueue, a persistent FIFO queue implementation that uses Orleans' journaling\n/// infrastructure to maintain state across grain activations and system restarts.\n/// \n/// DurableQueue provides standard queue operations (Enqueue, Dequeue, Peek) while ensuring\n/// all operations are journaled for durability. This is particularly useful for implementing\n/// reliable message processing patterns in Orleans grains.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class DurableQueueTests : StateMachineTestBase\n{\n    /// <summary>\n    /// Tests basic queue operations: Enqueue, Dequeue, Peek, and Count.\n    /// Verifies FIFO ordering and that operations are correctly persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_BasicOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var queue = new DurableQueue<string>(\"testQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Enqueue items\n        queue.Enqueue(\"one\");\n        queue.Enqueue(\"two\");\n        queue.Enqueue(\"three\");\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(3, queue.Count);\n        \n        // Act - Peek at the front of the queue\n        var peeked = queue.Peek();\n        \n        // Assert - Peek returns the first item without removing it\n        Assert.Equal(\"one\", peeked);\n        Assert.Equal(3, queue.Count);\n        \n        // Act - Dequeue\n        var dequeued1 = queue.Dequeue();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(\"one\", dequeued1);\n        Assert.Equal(2, queue.Count);\n        \n        // Act - Dequeue again\n        var dequeued2 = queue.Dequeue();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(\"two\", dequeued2);\n        Assert.Single(queue);\n        \n        // Act - Dequeue last item\n        var dequeued3 = queue.Dequeue();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(\"three\", dequeued3);\n        Assert.Empty(queue);\n    }\n    \n    /// <summary>\n    /// Tests that queue state is correctly persisted and recovered.\n    /// Creates a queue, adds items, then recreates the queue from the same\n    /// storage to verify state recovery.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_Persistence_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var codec = CodecProvider.GetCodec<string>();\n        var queue1 = new DurableQueue<string>(\"testQueue\", sut.Manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Enqueue items and persist\n        queue1.Enqueue(\"one\");\n        queue1.Enqueue(\"two\");\n        queue1.Enqueue(\"three\");\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n        \n        // Create a new manager with the same storage\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var queue2 = new DurableQueue<string>(\"testQueue\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - Queue should be recovered\n        Assert.Equal(3, queue2.Count);\n        Assert.Equal(\"one\", queue2.Peek());\n        \n        // Act - Dequeue from recovered queue\n        var dequeued = queue2.Dequeue();\n        await sut2.Manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(\"one\", dequeued);\n        Assert.Equal(2, queue2.Count);\n    }\n    \n    /// <summary>\n    /// Tests that the queue correctly handles complex value types.\n    /// Verifies that custom objects are properly serialized and deserialized\n    /// when enqueued and dequeued.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_ComplexValues_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<TestPerson>();\n        var queue = new DurableQueue<TestPerson>(\"personQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act\n        var person1 = new TestPerson { Id = 1, Name = \"John\", Age = 30 };\n        var person2 = new TestPerson { Id = 2, Name = \"Jane\", Age = 25 };\n        \n        queue.Enqueue(person1);\n        queue.Enqueue(person2);\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(2, queue.Count);\n        var peeked = queue.Peek();\n        Assert.Equal(\"John\", peeked.Name);\n        \n        // Act - Dequeue\n        var dequeued = queue.Dequeue();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Single(queue);\n        Assert.Equal(\"John\", dequeued.Name);\n        Assert.Equal(30, dequeued.Age);\n    }\n    \n    /// <summary>\n    /// Tests the Clear operation which removes all items from the queue.\n    /// Verifies that the clear operation is properly journaled.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_Clear_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var queue = new DurableQueue<string>(\"clearQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        queue.Enqueue(\"one\");\n        queue.Enqueue(\"two\");\n        queue.Enqueue(\"three\");\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act - Clear\n        queue.Clear();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Empty(queue);\n        Assert.Empty(queue);\n    }\n    \n    /// <summary>\n    /// Tests edge cases for operations on an empty queue.\n    /// Verifies that Peek and Dequeue throw appropriate exceptions\n    /// when the queue is empty.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_EmptyQueueOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var queue = new DurableQueue<string>(\"emptyQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Empty(queue);\n        \n        // Act & Assert - Peek and Dequeue on empty queue should throw\n        Assert.Throws<InvalidOperationException>(() => queue.Peek());\n        Assert.Throws<InvalidOperationException>(() => queue.Dequeue());\n    }\n    \n    /// <summary>\n    /// Tests queue enumeration capabilities.\n    /// Verifies that the queue supports standard enumeration patterns\n    /// and returns items in FIFO order.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_Enumeration_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var queue = new DurableQueue<string>(\"enumQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        var expectedItems = new List<string> { \"one\", \"two\", \"three\" };\n        \n        foreach (var item in expectedItems)\n        {\n            queue.Enqueue(item);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act\n        var actualItems = queue.ToList();\n        \n        // Assert - Items should be in same order as enqueued\n        Assert.Equal(expectedItems, actualItems);\n    }\n    \n    /// <summary>\n    /// Stress test for queue performance with large numbers of items.\n    /// Tests that the journaling system can handle thousands of queue operations\n    /// and correctly recover the entire queue state.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_LargeNumberOfOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var queue = new DurableQueue<int>(\"largeQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Enqueue many items\n        const int itemCount = 1000;\n        for (int i = 0; i < itemCount; i++)\n        {\n            queue.Enqueue(i);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(itemCount, queue.Count);\n        Assert.Equal(0, queue.Peek());\n        \n        // Create a new manager with the same storage to test recovery\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var queue2 = new DurableQueue<int>(\"largeQueue\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n        \n        // Assert - Large queue is correctly recovered\n        Assert.Equal(itemCount, queue2.Count);\n        \n        // Act - Dequeue all items and verify order\n        for (int i = 0; i < itemCount; i++)\n        {\n            var item = queue2.Dequeue();\n            Assert.Equal(i, item);\n        }\n        \n        await sut2.Manager.WriteStateAsync(CancellationToken.None);\n        Assert.Empty(queue2);\n    }\n    \n    /// <summary>\n    /// Tests complex queue operation patterns with interleaved enqueue/dequeue operations.\n    /// Simulates real-world usage where items are added and removed in batches,\n    /// verifying that the queue maintains correct ordering and state.\n    /// </summary>\n    [Fact]\n    public async Task DurableQueue_Concurrent_EnqueueDequeue_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var queue = new DurableQueue<int>(\"concurrentQueue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Simulate a queue with concurrent operations\n        const int batchSize = 100;\n        \n        // First batch: add 100 items\n        for (int i = 0; i < batchSize; i++)\n        {\n            queue.Enqueue(i);\n        }\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Remove 50 items\n        for (int i = 0; i < batchSize / 2; i++)\n        {\n            queue.Dequeue();\n        }\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Add another 100 items\n        for (int i = batchSize; i < batchSize * 2; i++)\n        {\n            queue.Enqueue(i);\n        }\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(batchSize + batchSize / 2, queue.Count); // Should have 150 items\n        \n        // Create a new manager with the same storage to test recovery\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var queue2 = new DurableQueue<int>(\"concurrentQueue\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n        \n        // Assert - Queue should be recovered with correct state and ordering\n        Assert.Equal(batchSize + batchSize / 2, queue2.Count);\n        \n        // First values should be the second half of first batch\n        for (int i = batchSize / 2; i < batchSize; i++)\n        {\n            var item = queue2.Dequeue();\n            Assert.Equal(i, item);\n        }\n        \n        // Then we should get the second batch\n        for (int i = batchSize; i < batchSize * 2; i++)\n        {\n            var item = queue2.Dequeue();\n            Assert.Equal(i, item);\n        }\n        \n        await sut2.Manager.WriteStateAsync(CancellationToken.None);\n        Assert.Empty(queue2);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/DurableSetTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Tests for DurableSet, a persistent set implementation that uses Orleans' journaling\n/// infrastructure to maintain unique collections across grain activations and system restarts.\n/// \n/// DurableSet provides standard set operations (Add, Remove, Contains) while ensuring\n/// uniqueness of elements and durability through journaling. This is useful for maintaining\n/// collections of unique identifiers, tags, or other distinct values in Orleans grains.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class DurableSetTests : StateMachineTestBase\n{\n    /// <summary>\n    /// Tests basic set operations: Add, Remove, and uniqueness constraint.\n    /// Verifies that duplicates are not added and that operations are persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_BasicOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var set = new DurableSet<string>(\"testSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Add items\n        bool added1 = set.Add(\"one\");\n        bool added2 = set.Add(\"two\");\n        bool added3 = set.Add(\"three\");\n        bool duplicateAdded = set.Add(\"one\"); // Adding duplicate\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.True(added1);\n        Assert.True(added2);\n        Assert.True(added3);\n        Assert.False(duplicateAdded); // Should not add duplicates\n        Assert.Equal(3, set.Count);\n        Assert.Equal([\"one\", \"two\", \"three\"], set);\n        \n        // Act - Remove item\n        bool removed = set.Remove(\"two\");\n        bool removedNonExisting = set.Remove(\"four\"); // Remove non-existing\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.True(removed);\n        Assert.False(removedNonExisting);\n        Assert.Equal(2, set.Count);\n        Assert.Equal([\"one\", \"three\"], set);\n    }\n    \n    /// <summary>\n    /// Tests that set state is correctly persisted and recovered.\n    /// Creates a set, adds items, then recreates the set from the same\n    /// storage to verify state recovery.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_Persistence_Test()\n    {\n        // First manager and set\n        var sut = CreateTestSystem();\n        var codec = CodecProvider.GetCodec<string>();\n        var set1 = new DurableSet<string>(\"testSet\", sut.Manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Add items and persist\n        set1.Add(\"one\");\n        set1.Add(\"two\");\n        set1.Add(\"three\");\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n\n        // Create a new manager with the same storage\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var set2 = new DurableSet<string>(\"testSet\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - Set should be recovered\n        Assert.Equal(3, set2.Count);\n        Assert.Equal([\"one\", \"two\", \"three\"], set2);\n    }\n    \n    /// <summary>\n    /// Tests that the set correctly handles complex value types.\n    /// Verifies that custom objects with proper equality implementations\n    /// maintain uniqueness in the set.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_ComplexValues_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<TestPerson>();\n        var set = new DurableSet<TestPerson>(\"personSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act\n        var person1 = new TestPerson { Id = 1, Name = \"John\", Age = 30 };\n        var person2 = new TestPerson { Id = 2, Name = \"Jane\", Age = 25 };\n        var person3 = new TestPerson { Id = 1, Name = \"John\", Age = 30 }; // Same as person1\n        \n        set.Add(person1);\n        set.Add(person2);\n        bool duplicateAdded = set.Add(person3); // Should not add duplicate when overriding Equals\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.False(duplicateAdded);\n        Assert.Equal(2, set.Count);\n        Assert.Equal([person1, person2], set);\n    }\n    \n    /// <summary>\n    /// Tests the Clear operation which removes all items from the set.\n    /// Verifies that the clear operation is properly journaled.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_Clear_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var set = new DurableSet<string>(\"clearSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        set.Add(\"one\");\n        set.Add(\"two\");\n        set.Add(\"three\");\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act - Clear\n        set.Clear();\n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Empty(set);\n    }\n    \n    /// <summary>\n    /// Tests set enumeration capabilities.\n    /// Verifies that the set supports standard enumeration patterns\n    /// and can be converted to other collection types.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_Enumeration_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var set = new DurableSet<string>(\"enumSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add items\n        var expectedItems = new HashSet<string> { \"one\", \"two\", \"three\" };\n        \n        foreach (var item in expectedItems)\n        {\n            set.Add(item);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act\n        var actualItems = set.ToHashSet();\n        \n        // Assert\n        Assert.Equal(expectedItems, actualItems);\n    }\n    \n    /// <summary>\n    /// Stress test for set performance with large numbers of items.\n    /// Tests that the journaling system can handle thousands of unique items\n    /// and correctly enforce uniqueness constraints.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_LargeNumberOfItems_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var set = new DurableSet<int>(\"largeSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Act - Add many items\n        const int itemCount = 1000;\n        for (int i = 0; i < itemCount; i++)\n        {\n            set.Add(i);\n        }\n        \n        // Add some duplicates which should be ignored\n        for (int i = 0; i < 100; i++)\n        {\n            set.Add(i);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert\n        Assert.Equal(itemCount, set.Count);\n\n        // Create a new manager with the same storage to test recovery\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var set2 = new DurableSet<int>(\"largeSet\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n        \n        // Assert - Large set is correctly recovered\n        Assert.Equal(itemCount, set2.Count);\n        for (int i = 0; i < itemCount; i++)\n        {\n            Assert.Contains(i, (IReadOnlySet<int>)set2);\n        }\n    }\n    \n    /// <summary>\n    /// Tests mathematical set operations using durable sets.\n    /// Demonstrates how to perform intersection, union, and difference\n    /// operations using the enumeration capabilities of durable sets.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_SetOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var set1 = new DurableSet<int>(\"set1\", manager, codec, SessionPool);\n        var set2 = new DurableSet<int>(\"set2\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Populate set1 with even numbers from 0 to 10\n        for (int i = 0; i <= 10; i += 2)\n        {\n            set1.Add(i);\n        }\n        \n        // Populate set2 with numbers from 5 to 15\n        for (int i = 5; i <= 15; i++)\n        {\n            set2.Add(i);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act & Assert - Set operations\n        var set1HashSet = set1.ToHashSet();\n        var set2HashSet = set2.ToHashSet();\n        \n        // Intersection\n        var intersection = new HashSet<int>(set1HashSet);\n        intersection.IntersectWith(set2HashSet);\n        Assert.Equal(new HashSet<int> { 6, 8, 10 }, intersection);\n        \n        // Union\n        var union = new HashSet<int>(set1HashSet);\n        union.UnionWith(set2HashSet);\n        Assert.Equal(new HashSet<int> { 0, 2, 4, 6, 8, 10, 5, 7, 9, 11, 12, 13, 14, 15 }, union);\n        \n        // Difference (set1 - set2)\n        var difference = new HashSet<int>(set1HashSet);\n        difference.ExceptWith(set2HashSet);\n        Assert.Equal(new HashSet<int> { 0, 2, 4 }, difference);\n    }\n    \n    /// <summary>\n    /// Tests selective removal of multiple items from a set.\n    /// Demonstrates how to remove a subset of items and verify\n    /// that the remaining items are correctly persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableSet_ExceptWith_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var set = new DurableSet<int>(\"exceptSet\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n        \n        // Add numbers from 0 to 9\n        for (int i = 0; i < 10; i++)\n        {\n            set.Add(i);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Act - Remove even numbers\n        var evens = new List<int>();\n        for (int i = 0; i < 10; i += 2)\n        {\n            evens.Add(i);\n        }\n        \n        foreach (var even in evens)\n        {\n            set.Remove(even);\n        }\n        \n        await manager.WriteStateAsync(CancellationToken.None);\n        \n        // Assert - Should only contain odd numbers\n        Assert.Equal(5, set.Count);\n        for (int i = 1; i < 10; i += 2)\n        {\n            Assert.Contains(i, (IReadOnlySet<int>)set);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/DurableValueTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Tests for DurableValue, a simple persistent value wrapper that uses Orleans' journaling\n/// infrastructure to maintain a single value across grain activations and system restarts.\n/// \n/// DurableValue is the simplest durable data structure, providing a way to persist\n/// a single value of any type. It's useful for grain state properties that need\n/// durability without the complexity of collections.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class DurableValueTests : StateMachineTestBase\n{\n    /// <summary>\n    /// Tests basic value operations: setting and updating values.\n    /// Verifies that value changes are properly journaled and persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableValue_BasicOperations_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string>();\n        var durableValue = new DurableValue<string>(\"testValue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Set initial value\n        durableValue.Value = \"Hello World\";\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Equal(\"Hello World\", durableValue.Value);\n\n        // Act - Update value\n        durableValue.Value = \"Updated Value\";\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Equal(\"Updated Value\", durableValue.Value);\n    }\n\n    /// <summary>\n    /// Tests that value state is correctly persisted and recovered.\n    /// Creates a DurableValue, sets a value, then recreates it from the same\n    /// storage to verify state recovery.\n    /// </summary>\n    [Fact]\n    public async Task DurableValue_Persistence_Test()\n    {\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n        var durableValue = new DurableValue<int>(\"counter\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Modify and persist\n        durableValue.Value = 42;\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n\n        // Create a new manager with the same storage\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var durableValue2 = new DurableValue<int>(\"counter\", sut2.Manager, codec, SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - Value should be recovered\n        Assert.Equal(42, durableValue2.Value);\n    }\n\n    /// <summary>\n    /// Tests handling of null values in DurableValue.\n    /// Verifies that null values are properly persisted and can be\n    /// distinguished from uninitialized state.\n    /// </summary>\n    [Fact]\n    public async Task DurableValue_NullValue_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<string?>();\n        var durableValue = new DurableValue<string?>(\"nullableValue\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Set to null\n        durableValue.Value = null;\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Null(durableValue.Value);\n\n        // Act - Update to non-null\n        durableValue.Value = \"Not null anymore\";\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Equal(\"Not null anymore\", durableValue.Value);\n\n        // Act - Update back to null\n        durableValue.Value = null;\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Null(durableValue.Value);\n    }\n\n    /// <summary>\n    /// Tests that DurableValue correctly handles complex value types.\n    /// Verifies that custom objects are properly serialized and that\n    /// mutations to properties of the stored object are persisted.\n    /// </summary>\n    [Fact]\n    public async Task DurableValue_ComplexType_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<TestPerson>();\n        var durableValue = new DurableValue<TestPerson>(\"person\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act\n        var person = new TestPerson { Id = 1, Name = \"John Doe\", Age = 30 };\n        durableValue.Value = person;\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.NotNull(durableValue.Value);\n        Assert.Equal(1, durableValue.Value.Id);\n        Assert.Equal(\"John Doe\", durableValue.Value.Name);\n        Assert.Equal(30, durableValue.Value.Age);\n\n        // Act - Update property\n        durableValue.Value.Age = 31;\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert\n        Assert.Equal(31, durableValue.Value.Age);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/Grains.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Journaling.Tests;\n\n[GenerateSerializer]\npublic sealed record TestDurableGrainState(string Name, int Counter);\n\npublic class TestDurableGrain(\n    [FromKeyedServices(\"state\")] IPersistentState<TestDurableGrainState> state) : DurableGrain, ITestDurableGrain\n{\n    private readonly Guid _activationId = Guid.NewGuid();\n    public Task<string> GetName() => Task.FromResult(state.State.Name);\n    public Task<int> GetCounter() => Task.FromResult(state.State.Counter);\n\n    public async Task SetTestValues(string name, int counter)\n    {\n        state.State = new(name, counter);\n        await WriteStateAsync();\n    }\n\n    public Task<Guid> GetActivationId() => Task.FromResult(_activationId);\n}\n\npublic class TestDurableGrainWithComplexState(\n    [FromKeyedServices(\"person\")] IDurableValue<TestPerson> person,\n    [FromKeyedServices(\"list\")] IDurableList<string> list) : DurableGrain, ITestDurableGrainWithComplexState\n{\n    private readonly Guid _activationId = Guid.NewGuid();\n    private readonly IDurableValue<TestPerson> _person = person;\n    private readonly IDurableList<string> _list = list;\n\n    public Task<TestPerson> GetPerson() => Task.FromResult(_person.Value ?? new TestPerson());\n    public Task<IReadOnlyList<string>> GetItems() => Task.FromResult<IReadOnlyList<string>>(_list.AsReadOnly());\n\n    public async Task SetTestValues(TestPerson person, List<string> items)\n    {\n        _person.Value = person;\n        _list.Clear();\n        _list.AddRange(items);\n        await WriteStateAsync();\n    }\n\n    public Task<Guid> GetActivationId() => Task.FromResult(_activationId);\n}\n\npublic interface ITestDurableGrain : IGrainWithGuidKey\n{\n    Task<Guid> GetActivationId();\n    Task SetTestValues(string name, int counter);\n    Task<string> GetName();\n    Task<int> GetCounter();\n}\n\npublic interface ITestDurableGrainWithComplexState : IGrainWithGuidKey\n{\n    Task<Guid> GetActivationId();\n    Task SetTestValues(TestPerson person, List<string> items);\n    Task<TestPerson> GetPerson();\n    Task<IReadOnlyList<string>> GetItems();\n}\n\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/ITestDurableGrainInterface.cs",
    "content": "namespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Interface for the test durable grain\n/// </summary>\npublic interface ITestDurableGrainInterface : IGrainWithGuidKey\n{\n    Task<Guid> GetActivationId();\n    Task SetValues(string name, int counter);\n    Task<(string Name, int Counter)> GetValues();\n}"
  },
  {
    "path": "test/Orleans.Journaling.Tests/ITestMultiCollectionGrain.cs",
    "content": "namespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Interface for the test multi-collection grain\n/// </summary>\npublic interface ITestMultiCollectionGrain : IGrainWithGuidKey\n{\n    Task<Guid> GetActivationId();\n\n    // Dictionary operations\n    Task AddToDictionary(string key, int value);\n    Task RemoveFromDictionary(string key);\n    Task<int> GetDictionaryValue(string key);\n    Task<int> GetDictionaryCount();\n\n    // List operations\n    Task AddToList(string item);\n    Task RemoveListItemAt(int index);\n    Task<string> GetListItem(int index);\n    Task<int> GetListCount();\n\n    // Queue operations\n    Task AddToQueue(int item);\n    Task<int> DequeueItem();\n    Task<int> PeekQueueItem();\n    Task<int> GetQueueCount();\n\n    // Set operations\n    Task AddToSet(string item);\n    Task RemoveFromSet(string item);\n    Task<bool> ContainsSetItem(string item);\n    Task<int> GetSetCount();\n}"
  },
  {
    "path": "test/Orleans.Journaling.Tests/IntegrationTestFixture.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Base class for journaling tests with common setup using InProcessTestCluster\n/// </summary>\npublic class IntegrationTestFixture : IAsyncLifetime\n{\n    public InProcessTestCluster Cluster { get; }\n    public IClusterClient Client => Cluster.Client;\n\n    public IntegrationTestFixture()\n    {\n        var builder = new InProcessTestClusterBuilder();\n        var storageProvider = new VolatileStateMachineStorageProvider();\n        builder.ConfigureSilo((options, siloBuilder) =>\n        {\n            siloBuilder.AddStateMachineStorage();\n            siloBuilder.Services.AddSingleton<IStateMachineStorageProvider>(storageProvider);\n        });\n        ConfigureTestCluster(builder);\n        Cluster = builder.Build();\n    }\n\n    protected virtual void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n    {\n    }\n\n    public virtual async Task InitializeAsync()\n    {\n        await Cluster.DeployAsync();\n    }\n\n    public virtual async Task DisposeAsync()\n    {\n        if (Cluster != null)\n        {\n            await Cluster.DisposeAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/JournalingAzureStorageTestConfiguration.cs",
    "content": "using TestExtensions;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\ninternal static class JournalingAzureStorageTestConfiguration\n{\n    public static void CheckPreconditionsOrThrow()\n    {\n        if (TestDefaultConfiguration.UseAadAuthentication)\n        {\n            Skip.If(string.IsNullOrEmpty(TestDefaultConfiguration.DataBlobUri.ToString()), \"DataBlobUri is not set. Skipping test.\");\n        }\n        else\n        {\n            Skip.If(string.IsNullOrEmpty(TestDefaultConfiguration.DataConnectionString), \"DataConnectionString is not set. Skipping test.\");\n        }\n    }\n\n    public static AzureAppendBlobStateMachineStorageOptions ConfigureTestDefaults(this AzureAppendBlobStateMachineStorageOptions options)\n    {\n        if (TestDefaultConfiguration.UseAadAuthentication)\n        {\n            options.ConfigureBlobServiceClient(TestDefaultConfiguration.DataBlobUri, TestDefaultConfiguration.TokenCredential);\n        }\n        else\n        {\n            options.ConfigureBlobServiceClient(TestDefaultConfiguration.DataConnectionString);\n        }\n\n        return options;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/LogSegmentTests.cs",
    "content": "using Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Specialized;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration.Internal;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n[TestCategory(\"AzureStorage\"), TestCategory(\"Functional\")]\npublic sealed class AzureStorageLogSegmentTests : LogSegmentTests\n{\n    public AzureStorageLogSegmentTests()\n    {\n        JournalingAzureStorageTestConfiguration.CheckPreconditionsOrThrow();\n    }\n\n    protected override void ConfigureServices(IServiceCollection services)\n    {\n        services.Configure<AzureAppendBlobStateMachineStorageOptions>(options => JournalingAzureStorageTestConfiguration.ConfigureTestDefaults(options));\n        services.AddSingleton<AzureAppendBlobStateMachineStorageProvider>();\n        services.AddFromExisting<IStateMachineStorageProvider, AzureAppendBlobStateMachineStorageProvider>();\n        services.AddFromExisting<ILifecycleParticipant<ISiloLifecycle>, AzureAppendBlobStateMachineStorageProvider>();\n    }\n}\n\npublic sealed class InMemoryLogSegmentTests : LogSegmentTests\n{\n    protected override void ConfigureServices(IServiceCollection services)\n    {\n        services.AddSingleton<IStateMachineStorageProvider, VolatileStateMachineStorageProvider>();\n    }\n}\n\n/// <summary>\n/// Base class for testing <see cref=\"IStateMachineStorageProvider\"/> implementations.\n/// Derived classes must implement <see cref=\"ConfigureServices\"/> to register the specific storage provider.\n/// This class provides a suite of common tests for validating the behavior of <see cref=\"DurableList{T}\"/>\n/// against different storage backends.\n/// </summary>\npublic abstract class LogSegmentTests : IAsyncLifetime\n{\n    private IServiceProvider _serviceProvider = null!;\n    private SiloLifecycleSubject? _siloLifecycle;\n    private IStateMachineStorageProvider _storageProvider = null!;\n    private static readonly IOptions<StateMachineManagerOptions> ManagerOptions = Options.Create(new StateMachineManagerOptions());\n\n    public virtual async Task InitializeAsync()\n    {\n        var services = new ServiceCollection();\n        services.AddSerializer();\n        services.AddLogging();\n        ConfigureServices(services);\n        _serviceProvider = services.BuildServiceProvider();\n        _siloLifecycle = new SiloLifecycleSubject(_serviceProvider.GetRequiredService<ILogger<SiloLifecycleSubject>>());\n        _storageProvider = _serviceProvider.GetRequiredService<IStateMachineStorageProvider>();\n        var participants = _serviceProvider.GetServices<ILifecycleParticipant<ISiloLifecycle>>();\n        foreach (var participant in participants)\n        {\n            participant.Participate(_siloLifecycle);\n        }\n\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));\n        await _siloLifecycle.OnStart(cts.Token);\n    }\n\n    public async Task DisposeAsync()\n    {\n        if (_siloLifecycle is not null)\n        {\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));\n            await _siloLifecycle.OnStop(cts.Token);\n        }\n    }\n\n    protected abstract void ConfigureServices(IServiceCollection services);\n\n    private (StateMachineManager Manager, DurableList<T> List, IStateMachineStorage Storage) CreateTestComponents<T>(string listName, GrainId grainId)\n    {\n        var sessionPool = _serviceProvider.GetRequiredService<SerializerSessionPool>();\n        var codecProvider = _serviceProvider.GetRequiredService<ICodecProvider>();\n        var grainContext = new TestGrainContext(grainId); // Use provided GrainId\n        var storage = _storageProvider.Create(grainContext);\n        var manager = new StateMachineManager(storage, _serviceProvider.GetRequiredService<ILogger<StateMachineManager>>(), ManagerOptions, sessionPool, TimeProvider.System);\n        var list = new DurableList<T>(listName, manager, codecProvider.GetCodec<T>(), sessionPool);\n        return (manager, list, storage);\n    }\n\n    /// <summary>\n    /// Tests basic Add, Update (by index), and RemoveAt operations.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_BasicOperations_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var grainId = GrainId.Create(\"test-grain\", $\"basicList-{Guid.NewGuid()}\"); // Unique ID for this test run\n        var (manager, list, _) = CreateTestComponents<string>(\"basicList\", grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        list.Add(\"one\");\n        list.Add(\"two\");\n        list.Add(\"three\");\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Equal(3, list.Count);\n        Assert.Equal(\"one\", list[0]);\n        Assert.Equal(\"two\", list[1]);\n        Assert.Equal(\"three\", list[2]);\n\n        list[1] = \"updated\";\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Equal(\"updated\", list[1]);\n\n        list.RemoveAt(0);\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"updated\", list[0]);\n        Assert.Equal(\"three\", list[1]);\n    }\n\n    /// <summary>\n    /// Tests that list state is correctly persisted and can be recovered by a new instance.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_Persistence_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var listName = \"persistenceList\";\n        var grainId = GrainId.Create(\"test-grain\", $\"{listName}-{Guid.NewGuid()}\"); // Consistent GrainId for recovery\n        var (manager1, list1, storage) = CreateTestComponents<string>(listName, grainId);\n        await manager1.InitializeAsync(cts.Token);\n\n        list1.Add(\"one\");\n        list1.Add(\"two\");\n        list1.Add(\"three\");\n        await manager1.WriteStateAsync(cts.Token);\n\n        var sessionPool = _serviceProvider.GetRequiredService<SerializerSessionPool>();\n        var codecProvider = _serviceProvider.GetRequiredService<ICodecProvider>();\n        var manager2 = new StateMachineManager(storage, _serviceProvider.GetRequiredService<ILogger<StateMachineManager>>(), ManagerOptions, sessionPool, TimeProvider.System);\n        var list2 = new DurableList<string>(listName, manager2, codecProvider.GetCodec<string>(), sessionPool);\n        await manager2.InitializeAsync(cts.Token);\n\n        Assert.Equal(3, list2.Count);\n        Assert.Equal(\"one\", list2[0]);\n        Assert.Equal(\"two\", list2[1]);\n        Assert.Equal(\"three\", list2[2]);\n    }\n\n    /// <summary>\n    /// Tests storing and retrieving complex objects, including updates to mutable properties.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_ComplexValues_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var listName = \"personList\";\n        var grainId = GrainId.Create(\"test-grain\", $\"{listName}-{Guid.NewGuid()}\"); // Consistent GrainId for recovery\n        var (manager, list, _) = CreateTestComponents<TestPerson>(listName, grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        var person1 = new TestPerson { Id = 1, Name = \"John\", Age = 30 };\n        var person2 = new TestPerson { Id = 2, Name = \"Jane\", Age = 25 };\n\n        list.Add(person1);\n        list.Add(person2);\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"John\", list[0].Name);\n        Assert.Equal(25, list[1].Age);\n\n        list[0] = list[0] with { Age = 31 };\n        await manager.WriteStateAsync(cts.Token);\n\n        // Re-read to confirm persistence of the change\n        var (manager2, list2, _) = CreateTestComponents<TestPerson>(listName, grainId); // Use same GrainId to reload\n        await manager2.InitializeAsync(cts.Token);\n        Assert.Equal(31, list2[0].Age);\n    }\n\n    /// <summary>\n    /// Tests the Clear operation and its persistence.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_Clear_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var listName = \"clearList\";\n        var grainId = GrainId.Create(\"test-grain\", $\"{listName}-{Guid.NewGuid()}\"); // Consistent GrainId for recovery\n        var (manager, list, _) = CreateTestComponents<string>(listName, grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        list.Add(\"one\");\n        list.Add(\"two\");\n        list.Add(\"three\");\n        await manager.WriteStateAsync(cts.Token);\n\n        list.Clear();\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Empty(list);\n\n        // Verify persistence of Clear\n        var (manager2, list2, _) = CreateTestComponents<string>(listName, grainId); // Use same GrainId to reload\n        await manager2.InitializeAsync(cts.Token);\n        Assert.Empty(list2);\n    }\n\n    /// <summary>\n    /// Tests the Contains method and Remove (by value) operation.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_Contains_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var grainId = GrainId.Create(\"test-grain\", $\"containsList-{Guid.NewGuid()}\"); // Unique ID for this test run\n        var (manager, list, _) = CreateTestComponents<string>(\"containsList\", grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        list.Add(\"one\");\n        list.Add(\"two\");\n        list.Add(\"three\");\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Contains(\"two\", list);\n        Assert.DoesNotContain(\"four\", list);\n\n        list.Remove(\"two\");\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.DoesNotContain(\"two\", list);\n    }\n\n    /// <summary>\n    /// Tests Insert and Remove (by value) operations.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_InsertAndRemove_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var grainId = GrainId.Create(\"test-grain\", $\"insertList-{Guid.NewGuid()}\"); // Unique ID for this test run\n        var (manager, list, _) = CreateTestComponents<string>(\"insertList\", grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        list.Add(\"one\");\n        list.Add(\"three\");\n        await manager.WriteStateAsync(cts.Token);\n\n        list.Insert(1, \"two\");\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.Equal(3, list.Count);\n        Assert.Equal(\"one\", list[0]);\n        Assert.Equal(\"two\", list[1]);\n        Assert.Equal(\"three\", list[2]);\n\n        bool removed = list.Remove(\"two\");\n        await manager.WriteStateAsync(cts.Token);\n\n        Assert.True(removed);\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"one\", list[0]);\n        Assert.Equal(\"three\", list[1]);\n    }\n\n    /// <summary>\n    /// Tests list enumeration using ToList() (which relies on GetEnumerator).\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_Enumeration_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n        var grainId = GrainId.Create(\"test-grain\", $\"enumList-{Guid.NewGuid()}\"); // Unique ID for this test run\n        var (manager, list, _) = CreateTestComponents<string>(\"enumList\", grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        var expectedItems = new List<string> { \"one\", \"two\", \"three\" };\n\n        foreach (var item in expectedItems)\n        {\n            list.Add(item);\n        }\n\n        await manager.WriteStateAsync(cts.Token);\n\n        var actualItems = list.ToList();\n\n        Assert.Equal(expectedItems, actualItems);\n    }\n\n    /// <summary>\n    /// Tests behavior with a larger number of operations (add, update) and multiple writes,\n    /// potentially triggering snapshotting behavior in the storage provider. Also tests recovery.\n    /// </summary>\n    [SkippableFact]\n    public async Task DurableList_LargeNumberOfOperations_And_Snapshot_Test()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); // Increased timeout\n        var listName = \"largeList\";\n        var grainId = GrainId.Create(\"test-grain\", $\"{listName}-{Guid.NewGuid()}\"); // Consistent GrainId for recovery\n        var (manager, list, storage) = CreateTestComponents<int>(listName, grainId);\n        await manager.InitializeAsync(cts.Token);\n\n        const int itemCount = 100; // Reduced for faster testing, increase if needed\n        for (int i = 0; i < itemCount; i++)\n        {\n            list.Add(i);\n        }\n\n        // Write multiple times to potentially trigger snapshotting\n        for (int j = 0; j < 5; ++j)\n        {\n            await manager.WriteStateAsync(cts.Token);\n        }\n\n        Assert.Equal(itemCount, list.Count);\n\n        for (int i = 0; i < itemCount; i += 2)\n        {\n            list[i] = list[i] * 2;\n        }\n\n        // Write multiple times again\n        for (int j = 0; j < 5; ++j)\n        {\n            await manager.WriteStateAsync(cts.Token);\n        }\n\n        for (int i = 0; i < itemCount; i++)\n        {\n            if (i % 2 == 0) Assert.Equal(i * 2, list[i]);\n            else Assert.Equal(i, list[i]);\n        }\n\n        // Test recovery (potentially from snapshot)\n        var sessionPool = _serviceProvider.GetRequiredService<SerializerSessionPool>();\n        var codecProvider = _serviceProvider.GetRequiredService<ICodecProvider>();\n        var manager2 = new StateMachineManager(storage, _serviceProvider.GetRequiredService<ILogger<StateMachineManager>>(), ManagerOptions, sessionPool, TimeProvider.System);// Reuses the storage object linked via grainId\n        var list2 = new DurableList<int>(listName, manager2, codecProvider.GetCodec<int>(), sessionPool);\n        await manager2.InitializeAsync(cts.Token);\n\n        Assert.Equal(itemCount, list2.Count);\n        for (int i = 0; i < itemCount; i++)\n        {\n            if (i % 2 == 0) Assert.Equal(i * 2, list2[i]);\n            else Assert.Equal(i, list2[i]);\n        }\n    }\n\n    // Keep TestGrainContext and add TestPerson record needed for one of the tests\n    [GenerateSerializer, Immutable]\n    internal sealed record TestPerson\n    {\n        [Id(0)]\n        public int Id { get; init; }\n        [Id(1)]\n        public string Name { get; init; } = \"\";\n        [Id(2)]\n        public int Age { get; init; }\n    }\n\n    internal sealed class TestGrainContext(GrainId grainId) : IGrainContext\n    {\n        public GrainReference GrainReference => throw new NotImplementedException();\n        public GrainId GrainId => grainId;\n        public object? GrainInstance  => throw new NotImplementedException();\n        public ActivationId ActivationId  => throw new NotImplementedException();\n        public GrainAddress Address  => throw new NotImplementedException();\n        public IServiceProvider ActivationServices  => throw new NotImplementedException();\n        public IGrainLifecycle ObservableLifecycle  => throw new NotImplementedException();\n        public IWorkItemScheduler Scheduler  => throw new NotImplementedException();\n        public Task Deactivated  => throw new NotImplementedException();\n\n        public void Activate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken = default) => throw new NotImplementedException();\n        public void Deactivate(DeactivationReason deactivationReason, CancellationToken cancellationToken = default) => throw new NotImplementedException();\n        public bool Equals(IGrainContext? other) => throw new NotImplementedException();\n        public TComponent? GetComponent<TComponent>() where TComponent : class => throw new NotImplementedException();\n        public object? GetComponent(Type componentType) => throw new NotImplementedException();\n        public TTarget? GetTarget<TTarget>() where TTarget : class => throw new NotImplementedException();\n        public object? GetTarget() => throw new NotImplementedException();\n        public void Migrate(Dictionary<string, object>? requestContext, CancellationToken cancellationToken = default) => throw new NotImplementedException();\n        public void ReceiveMessage(object message) => throw new NotImplementedException();\n        public void Rehydrate(IRehydrationContext context) => throw new NotImplementedException();\n        public void SetComponent<TComponent>(TComponent? value) where TComponent : class => throw new NotImplementedException();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/Orleans.Journaling.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);ORLEANSEXP005</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Microsoft.Extensions.TimeProvider.Testing\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Journaling\\Orleans.Journaling.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Server\\Orleans.Server.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Journaling.AzureStorage\\Orleans.Journaling.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Extensions\\Orleans.Azure.Tests\\Orleans.Azure.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/StateMachineManagerTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Time.Testing;\nusing Xunit;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Tests for StateMachineManager, the core component of Orleans' journaling infrastructure.\n/// \n/// StateMachineManager coordinates multiple durable data structures (DurableDictionary, DurableList, etc.)\n/// within a single grain, ensuring that all state changes are atomically journaled and can be\n/// recovered together. It manages the lifecycle of state machines, handles persistence through\n/// WriteStateAsync calls, and ensures consistent recovery after failures.\n/// </summary>\n[TestCategory(\"BVT\")]\npublic class StateMachineManagerTests : StateMachineTestBase\n{\n    /// <summary>\n    /// Tests the registration and basic operation of multiple state machines.\n    /// Verifies that different types of durable collections can be registered\n    /// with the manager and operate independently.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_RegisterStateMachine_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var codec = CodecProvider.GetCodec<int>();\n\n        // Act - Register state machines\n        var dictionary = new DurableDictionary<string, int>(\"dict1\", manager, CodecProvider.GetCodec<string>(), codec, SessionPool);\n        var list = new DurableList<string>(\"list1\", manager, CodecProvider.GetCodec<string>(), SessionPool);\n        var queue = new DurableQueue<int>(\"queue1\", manager, codec, SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Add some data\n        dictionary.Add(\"key1\", 1);\n        list.Add(\"item1\");\n        queue.Enqueue(42);\n\n        // Write state\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert - Data is correctly stored\n        Assert.Equal(1, dictionary[\"key1\"]);\n        Assert.Equal(\"item1\", list[0]);\n        Assert.Equal(42, queue.Peek());\n    }\n\n    /// <summary>\n    /// Tests that all registered state machines are correctly recovered together.\n    /// Verifies that the manager maintains consistency across multiple collections\n    /// during recovery from persisted state.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_StateRecovery_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n\n        // Create and populate state machines\n        var dictionary = new DurableDictionary<string, int>(\"dict1\", sut.Manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        var list = new DurableList<string>(\"list1\", sut.Manager, CodecProvider.GetCodec<string>(), SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        dictionary.Add(\"key1\", 1);\n        dictionary.Add(\"key2\", 2);\n        list.Add(\"item1\");\n        list.Add(\"item2\");\n\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n\n        // Act - Create new manager with same storage\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var recoveredDict = new DurableDictionary<string, int>(\"dict1\", sut2.Manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        var recoveredList = new DurableList<string>(\"list1\", sut2.Manager, CodecProvider.GetCodec<string>(), SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - State should be recovered\n        Assert.Equal(2, recoveredDict.Count);\n        Assert.Equal(1, recoveredDict[\"key1\"]);\n        Assert.Equal(2, recoveredDict[\"key2\"]);\n\n        Assert.Equal(2, recoveredList.Count);\n        Assert.Equal(\"item1\", recoveredList[0]);\n        Assert.Equal(\"item2\", recoveredList[1]);\n    }\n\n    /// <summary>\n    /// Tests multiple WriteStateAsync calls with operations in between.\n    /// Verifies that each WriteStateAsync creates a consistent checkpoint\n    /// and that the final state is correctly recovered.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_MultipleWriteStates_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var dictionary = new DurableDictionary<string, int>(\"dict1\", sut.Manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Multiple operations with WriteState in between\n        dictionary.Add(\"key1\", 1);\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        dictionary.Add(\"key2\", 2);\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        dictionary[\"key1\"] = 10;\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        dictionary.Remove(\"key2\");\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert - Final state is correct\n        Assert.Single(dictionary);\n        Assert.Equal(10, dictionary[\"key1\"]);\n        Assert.False(dictionary.ContainsKey(\"key2\"));\n\n        // Create new manager to verify recovery\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var recoveredDict = new DurableDictionary<string, int>(\"dict1\", sut2.Manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - Recovery should have final state\n        Assert.Single(recoveredDict);\n        Assert.Equal(10, recoveredDict[\"key1\"]);\n        Assert.False(recoveredDict.ContainsKey(\"key2\"));\n    }\n\n    /// <summary>\n    /// Tests managing multiple state machines of different types simultaneously.\n    /// Verifies that the manager correctly handles diverse data structures\n    /// (dictionaries with different key/value types, lists, values) in a single grain.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_MultipleStateMachines_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n\n        // Create multiple state machines with different types\n        var intDict = new DurableDictionary<int, string>(\"intDict\", manager, CodecProvider.GetCodec<int>(), CodecProvider.GetCodec<string>(), SessionPool);\n        var stringList = new DurableList<string>(\"stringList\", manager, CodecProvider.GetCodec<string>(), SessionPool);\n        var personValue = new DurableValue<TestPerson>(\"personValue\", manager, CodecProvider.GetCodec<TestPerson>(), SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Populate all state machines\n        intDict.Add(1, \"one\");\n        intDict.Add(2, \"two\");\n\n        stringList.Add(\"item1\");\n        stringList.Add(\"item2\");\n\n        personValue.Value = new TestPerson { Id = 100, Name = \"Test Person\", Age = 30 };\n\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert - All should have correct values\n        Assert.Equal(2, intDict.Count);\n        Assert.Equal(\"one\", intDict[1]);\n\n        Assert.Equal(2, stringList.Count);\n        Assert.Equal(\"item1\", stringList[0]);\n\n        Assert.NotNull(personValue.Value);\n        Assert.Equal(100, personValue.Value.Id);\n        Assert.Equal(\"Test Person\", personValue.Value.Name);\n\n        // Create new manager to verify recovery of multiple state machines\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var recoveredIntDict = new DurableDictionary<int, string>(\"intDict\", sut2.Manager, CodecProvider.GetCodec<int>(), CodecProvider.GetCodec<string>(), SessionPool);\n        var recoveredStringList = new DurableList<string>(\"stringList\", sut2.Manager, CodecProvider.GetCodec<string>(), SessionPool);\n        var recoveredPersonValue = new DurableValue<TestPerson>(\"personValue\", sut2.Manager, CodecProvider.GetCodec<TestPerson>(), SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - All should be recovered with correct values\n        Assert.Equal(2, recoveredIntDict.Count);\n        Assert.Equal(\"one\", recoveredIntDict[1]);\n\n        Assert.Equal(2, recoveredStringList.Count);\n        Assert.Equal(\"item1\", recoveredStringList[0]);\n\n        Assert.NotNull(recoveredPersonValue.Value);\n        Assert.Equal(100, recoveredPersonValue.Value.Id);\n        Assert.Equal(\"Test Person\", recoveredPersonValue.Value.Name);\n    }\n\n    /// <summary>\n    /// Tests that multiple state machines can operate independently without interference.\n    /// Verifies namespace isolation between different state machines with similar keys.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_Concurrency_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var manager = sut.Manager;\n        var dict1 = new DurableDictionary<string, int>(\"dict1\", manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        var dict2 = new DurableDictionary<string, int>(\"dict2\", manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Simulate concurrent operations on different state machines\n        dict1.Add(\"key1\", 1);\n        dict2.Add(\"key1\", 100);\n\n        dict1.Add(\"key2\", 2);\n        dict2.Add(\"key2\", 200);\n\n        await manager.WriteStateAsync(CancellationToken.None);\n\n        // Assert - Both state machines should have their correct values\n        Assert.Equal(2, dict1.Count);\n        Assert.Equal(2, dict2.Count);\n\n        Assert.Equal(1, dict1[\"key1\"]);\n        Assert.Equal(100, dict2[\"key1\"]);\n\n        Assert.Equal(2, dict1[\"key2\"]);\n        Assert.Equal(200, dict2[\"key2\"]);\n    }\n\n    /// <summary>\n    /// Stress test for state recovery with large amounts of data.\n    /// Verifies that the journaling system can handle and recover state machines\n    /// containing thousands of entries without data loss or corruption.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_LargeStateRecovery_Test()\n    {\n        // Arrange\n        var sut = CreateTestSystem();\n        var largeDict = new DurableDictionary<int, string>(\"largeDict\", sut.Manager, CodecProvider.GetCodec<int>(), CodecProvider.GetCodec<string>(), SessionPool);\n        await sut.Lifecycle.OnStart();\n\n        // Act - Add many items\n        const int itemCount = 1000;\n        for (int i = 0; i < itemCount; i++)\n        {\n            largeDict.Add(i, $\"Value {i}\");\n        }\n\n        await sut.Manager.WriteStateAsync(CancellationToken.None);\n\n        // Create new manager for recovery\n        var sut2 = CreateTestSystem(storage: sut.Storage);\n        var recoveredDict = new DurableDictionary<int, string>(\"largeDict\", sut2.Manager, CodecProvider.GetCodec<int>(), CodecProvider.GetCodec<string>(), SessionPool);\n        await sut2.Lifecycle.OnStart();\n\n        // Assert - All items should be recovered\n        Assert.Equal(itemCount, recoveredDict.Count);\n        for (int i = 0; i < itemCount; i++)\n        {\n            Assert.Equal($\"Value {i}\", recoveredDict[i]);\n        }\n    }\n\n    /// <summary>\n    /// Tests the full lifecycle of a retired state machine. It is preserved and also reintroduced through an\n    /// early compaction, but purged eventually after its grace period expires on later compactions.\n    /// </summary>\n    [Fact]\n    public async Task StateMachineManager_AutoRetiringStateMachines()\n    {\n        const string DictToKeepKey = \"dictToKeep\";\n        const string DictToRetireKey = \"dictToRetire\";\n\n        var period = ManagerOptions.RetirementGracePeriod;\n        var timeProvider = new FakeTimeProvider(DateTime.UtcNow);\n        var storage = CreateStorage();\n\n        // -------------- STEP 1 --------------\n\n        // We begin with 2 dictionaries, one of which we will retire by means of not registering it in the manager.\n        // This would be in the real-world developers removing it from the grain's ctor as a dependency.\n        var sut1 = CreateTestSystem(storage, timeProvider);\n        var dictToKeep1 = CreateTestMachine(DictToKeepKey, sut1.Manager);\n        var dictToRetire2 = CreateTestMachine(DictToRetireKey, sut1.Manager);\n\n        await sut1.Lifecycle.OnStart();\n\n        dictToKeep1.Add(\"a\", 1);\n        dictToRetire2.Add(\"b\", 1);\n\n        await sut1.Manager.WriteStateAsync(CancellationToken.None);\n\n        // -------------- STEP 2 --------------\n\n        // This time, we only register the dictionary we want to keep, this marks dictToRetire as retired.\n        var sut2 = CreateTestSystem(storage, timeProvider);\n        var dictToKeep2 = CreateTestMachine(DictToKeepKey, sut2.Manager);\n\n        await sut2.Lifecycle.OnStart();\n        \n        // The manager should have recovered the state for dictToKeep,\n        // and created a DurableNothing placeholder for dictToRetire (we cant test for it at this point). \n        Assert.Equal(1, dictToKeep2[\"a\"]);\n\n        // We advance time by half the grace period to see if we can save it from purging.\n        timeProvider.Advance(period / 2);\n\n        await TriggerCompaction(sut2.Manager, dictToKeep2);\n\n        // -------------- STEP 3 --------------\n\n        // Verify that the retired dictionary was NOT purged by this compaction, as only half the time has passed.\n        var sut3 = CreateTestSystem(storage, timeProvider);\n        var dictToKeep3 = CreateTestMachine(DictToKeepKey, sut3.Manager);\n        var dictToRetire3 = CreateTestMachine(DictToRetireKey, sut3.Manager);\n\n        await sut3.Lifecycle.OnStart();\n\n        Assert.Equal(10, dictToKeep3[\"a\"]);\n\n        // The fact this entry [\"b\", 1] exists proves that the state of dictToRetire was preserved, even though we did not register it in step 2.\n        Assert.Equal(1, dictToRetire3[\"b\"]);\n\n        // By advancing time by another half-period we cover the full period. But since we have re-introduced dictToRetire, we should have un-retired it.\n        // This is similar to step 2, but there we avoided purging due to time not being due, whereas here we avoid purging due to re-registration.\n        timeProvider.Advance(period / 2);\n\n        await TriggerCompaction(sut3.Manager, dictToKeep3);\n\n        // -------------- STEP 4 --------------\n\n        // Because of re-registration is step 3 (to test it was not purged), this means dictToRetire has been removed from the tracker.\n        // Again as in step 2, we only register the dictionary we want to keep, this marks dictToRetire as retired.\n        var sut4 = CreateTestSystem(storage, timeProvider);\n        var dictToKeep4 = CreateTestMachine(DictToKeepKey, sut4.Manager);\n\n        await sut4.Lifecycle.OnStart();\n\n        // The manager should have recovered the state for dictToKeep.\n        // It should have created a DurableNothing placeholder for dictToRetire, but we can not test for that.\n\n\n        // This time we advance time to cover the full period. Note that this is necessary because a side effect of step 3\n        // was that dictToRetire was removed from the tracker (since it came back), so just triggering a compaction won't cut it\n        // as time to retire will essentially be reset to \"now\".\n        timeProvider.Advance(period);\n\n        // This compaction should finally purge it.\n        await TriggerCompaction(sut4.Manager, dictToKeep4);\n\n        // -------------- STEP 5 --------------\n\n        // At this point, the manager has performed a snapshot, so it should have purged the dictToRetire data.\n        // By registering both dictionaries again, we should see what state remains after the snapshot.\n        var sut5 = CreateTestSystem(storage, timeProvider);\n        var dictToKeep5 = CreateTestMachine(DictToKeepKey, sut5.Manager);\n        var dictToRetire5 = CreateTestMachine(DictToRetireKey, sut5.Manager);\n\n        await sut5.Lifecycle.OnStart();\n        Assert.Equal(10, dictToKeep5[\"a\"]);\n\n        // The retired dictionary should now be empty because its state was purged during the compaction.\n        // Note that this is a new version of dictToRetire, since the original was removed. Idea here is\n        // that if we can register a new dictToRetire (with the same key), it means that the machine itself\n        // has been removed but also the data, otherwise a previous machine would have had at least one\n        // entry i.e. [\"b\", 1].\n\n        Assert.Empty(dictToRetire5);\n\n        // Note: The retirement of state machines has the nice benefit of being able to reuse machine names.\n\n        DurableDictionary<string, int> CreateTestMachine(string key, IStateMachineManager manager) =>\n            new(key, manager, CodecProvider.GetCodec<string>(), CodecProvider.GetCodec<int>(), SessionPool);\n\n        static async Task TriggerCompaction(IStateMachineManager manager, DurableDictionary<string, int> dict)\n        {\n            for (var i = 0; i < 11; i++)\n            {\n                dict[\"a\"] = i;\n                await manager.WriteStateAsync(CancellationToken.None);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/StateMachineTestBase.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.Time.Testing;\n\nnamespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Base class for journaling tests with common setup\n/// </summary>\npublic abstract class StateMachineTestBase\n{\n    protected readonly ServiceProvider ServiceProvider;\n    protected readonly SerializerSessionPool SessionPool;\n    protected readonly ICodecProvider CodecProvider;\n    protected readonly ILoggerFactory LoggerFactory;\n    protected readonly StateMachineManagerOptions ManagerOptions = new();\n\n    protected StateMachineTestBase()\n    {\n        var services = new ServiceCollection();\n\n        services.AddSerializer();\n        services.AddLogging(builder => builder.AddConsole());\n\n        ServiceProvider = services.BuildServiceProvider();\n        SessionPool = ServiceProvider.GetRequiredService<SerializerSessionPool>();\n        CodecProvider = ServiceProvider.GetRequiredService<ICodecProvider>();\n        LoggerFactory = ServiceProvider.GetRequiredService<ILoggerFactory>();\n    }\n\n    /// <summary>\n    /// Creates an in-memory storage for testing\n    /// </summary>\n    protected virtual IStateMachineStorage CreateStorage()\n    {\n        return new VolatileStateMachineStorage();\n    }\n\n    /// <summary>\n    /// Creates a state machine manager with in-memory storage\n    /// </summary>\n    internal (IStateMachineManager Manager, IStateMachineStorage Storage, ILifecycleSubject Lifecycle)\n        CreateTestSystem(IStateMachineStorage? storage = null, TimeProvider? provider = null)\n    {\n        storage ??= CreateStorage();\n        provider ??= TimeProvider.System;\n\n        var logger = LoggerFactory.CreateLogger<StateMachineManager>();\n        var manager = new StateMachineManager(storage, logger, Options.Create(ManagerOptions), SessionPool, provider);\n        var lifecycle = new GrainLifecycle(LoggerFactory.CreateLogger<GrainLifecycle>());\n        (manager as ILifecycleParticipant<IGrainLifecycle>)?.Participate(lifecycle);\n        return (manager, storage, lifecycle);\n    }\n\n    private class GrainLifecycle(ILogger logger) : LifecycleSubject(logger), IGrainLifecycle\n    {\n        private static readonly ImmutableDictionary<int, string> StageNames = GetStageNames(typeof(GrainLifecycleStage));\n\n        public void AddMigrationParticipant(IGrainMigrationParticipant participant) { }\n        public void RemoveMigrationParticipant(IGrainMigrationParticipant participant) { }\n\n        protected override string GetStageName(int stage)\n        {\n            if (StageNames.TryGetValue(stage, out var result)) return result;\n            return base.GetStageName(stage);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/TestDurableGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Journaling.Tests;\n\npublic class DurableValueTestGrain(\n    [FromKeyedServices(\"name\")] IDurableValue<string> name,\n    [FromKeyedServices(\"counter\")] IDurableValue<int> counter) : DurableGrain, ITestDurableGrainInterface\n{\n    private readonly Guid _activationId = Guid.NewGuid();\n    private readonly IDurableValue<string> _name = name;\n    private readonly IDurableValue<int> _counter = counter;\n\n    public Task SetValues(string name, int counter)\n    {\n        _name.Value = name;\n        _counter.Value = counter;\n        return WriteStateAsync().AsTask();\n    }\n\n    public Task<(string Name, int Counter)> GetValues() => Task.FromResult((_name.Value!, _counter.Value!));\n\n    public Task<Guid> GetActivationId() => Task.FromResult(_activationId);\n}"
  },
  {
    "path": "test/Orleans.Journaling.Tests/TestMultiCollectionGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Orleans.Journaling.Tests;\n\npublic class TestMultiCollectionGrain(\n    [FromKeyedServices(\"dictionary\")] IDurableDictionary<string, int> dictionary,\n    [FromKeyedServices(\"list\")] IDurableList<string> list,\n    [FromKeyedServices(\"queue\")] IDurableQueue<int> queue,\n    [FromKeyedServices(\"set\")] IDurableSet<string> set) : DurableGrain, ITestMultiCollectionGrain\n{\n    private readonly Guid _activationId = Guid.NewGuid();\n\n    // Dictionary operations\n    public async Task AddToDictionary(string key, int value)\n    {\n        dictionary[key] = value;\n        await WriteStateAsync();\n    }\n\n    public async Task RemoveFromDictionary(string key)\n    {\n        dictionary.Remove(key);\n        await WriteStateAsync();\n    }\n\n    public async Task<int> GetDictionaryValue(string key)\n    {\n        return await Task.FromResult(dictionary[key]);\n    }\n\n    public async Task<int> GetDictionaryCount()\n    {\n        return await Task.FromResult(dictionary.Count);\n    }\n\n    // List operations\n    public async Task AddToList(string item)\n    {\n        list.Add(item);\n        await WriteStateAsync();\n    }\n\n    public async Task RemoveListItemAt(int index)\n    {\n        list.RemoveAt(index);\n        await WriteStateAsync();\n    }\n\n    public async Task<string> GetListItem(int index)\n    {\n        return await Task.FromResult(list[index]);\n    }\n\n    public async Task<int> GetListCount()\n    {\n        return await Task.FromResult(list.Count);\n    }\n\n    // Queue operations\n    public async Task AddToQueue(int item)\n    {\n        queue.Enqueue(item);\n        await WriteStateAsync();\n    }\n\n    public async Task<int> DequeueItem()\n    {\n        var item = queue.Dequeue();\n        return await Task.FromResult(item);\n    }\n\n    public async Task<int> PeekQueueItem()\n    {\n        return await Task.FromResult(queue.Peek());\n    }\n\n    public async Task<int> GetQueueCount()\n    {\n        return await Task.FromResult(queue.Count);\n    }\n\n    // Set operations\n    public async Task AddToSet(string item)\n    {\n        set.Add(item);\n        await WriteStateAsync();\n    }\n\n    public async Task RemoveFromSet(string item)\n    {\n        set.Remove(item);\n        await WriteStateAsync();\n    }\n\n    public async Task<bool> ContainsSetItem(string item)\n    {\n        return await Task.FromResult(set.Contains(item));\n    }\n\n    public async Task<int> GetSetCount()\n    {\n        return await Task.FromResult(set.Count);\n    }\n\n    public Task<Guid> GetActivationId() => Task.FromResult(_activationId);\n}\n"
  },
  {
    "path": "test/Orleans.Journaling.Tests/TestPerson.cs",
    "content": "namespace Orleans.Journaling.Tests;\n\n/// <summary>\n/// Test class used for complex object serialization testing\n/// </summary>\n[GenerateSerializer]\npublic record class TestPerson\n{\n    [Id(0)]\n    public int Id { get; set; }\n    [Id(1)]\n    public string? Name { get; set; }\n    [Id(2)]\n    public int Age { get; set; }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/ControlRebalancerTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Placement.Rebalancing;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\n/// <summary>\n/// Tests for controlling the activation rebalancer, including suspend/resume operations and report subscription.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRebalancing\")]\npublic class ControlRebalancerTests(RebalancerFixture fixture, ITestOutputHelper output)\n    : RebalancingTestBase<RebalancerFixture>(fixture, output), IClassFixture<RebalancerFixture>\n{\n    [Fact]\n    public async Task Rebalancer_Should_Be_Controllable_And_Report_To_Listeners()\n    {\n        var serviceProvider = Cluster.GetSiloServiceProvider();\n        var rebalancer = serviceProvider.GetRequiredService<IActivationRebalancer>();\n        var report = await rebalancer.GetRebalancingReport();\n        var host = report.Host;\n\n        Assert.Equal(RebalancerStatus.Executing, report.Status);\n        Assert.Null(report.SuspensionDuration);\n        Assert.NotEqual(SiloAddress.Zero, host);\n\n        // Publish-Subscribe\n        var listener = new Listener();\n        rebalancer.SubscribeToReports(listener);\n        Assert.False(listener.Report.HasValue);\n\n        await rebalancer.ResumeRebalancing();\n        Assert.True(listener.Report.HasValue);\n        Assert.Equal(RebalancerStatus.Executing, listener.Report.Value.Status);\n        Assert.Equal(host, listener.Report.Value.Host);\n\n        await rebalancer.SuspendRebalancing();\n        Assert.Equal(RebalancerStatus.Suspended, listener.Report.Value.Status);\n        Assert.True(listener.Report.Value.SuspensionDuration.HasValue);\n        Assert.Equal(host, listener.Report.Value.Host);\n\n        rebalancer.UnsubscribeFromReports(listener);\n        await rebalancer.ResumeRebalancing();\n        while (report.Status == RebalancerStatus.Suspended)\n        {\n            report = await rebalancer.GetRebalancingReport(true);\n            await Task.Delay(100);\n        }\n        // Its actually resumed, but here its still suspended since we unsubscribed\n        Assert.Equal(RebalancerStatus.Suspended, listener.Report.Value.Status); \n\n        // Request-Reply\n        var duration = TimeSpan.FromSeconds(5);\n        await rebalancer.SuspendRebalancing(duration); // Suspend for some time\n        while (report.Status == RebalancerStatus.Executing)\n        {\n            report = await rebalancer.GetRebalancingReport(true);\n            await Task.Delay(100);\n        }\n\n        Assert.True(report.SuspensionDuration.HasValue);\n        // Must be less than the time it was told to be suspended\n        Assert.True(report.SuspensionDuration.Value < duration); \n        Assert.Equal(host, report.Host);\n\n        while (report.Status == RebalancerStatus.Suspended)\n        {\n            report = await rebalancer.GetRebalancingReport(true);\n            await Task.Delay(100);\n        }\n\n        report = await rebalancer.GetRebalancingReport(true);\n        Assert.False(report.SuspensionDuration.HasValue);\n        Assert.Equal(host, report.Host);\n\n        await rebalancer.SuspendRebalancing(); // Suspend indefinitely\n        while (report.Status == RebalancerStatus.Executing)\n        {\n            report = await rebalancer.GetRebalancingReport(true);\n            await Task.Delay(100);\n        }\n        report = await rebalancer.GetRebalancingReport(true);\n        Assert.True(report.SuspensionDuration.HasValue);\n        Assert.Equal(host, report.Host);\n    }\n\n    private class Listener : IActivationRebalancerReportListener\n    {\n        public RebalancingReport? Report { get; private set; }\n        public void OnReport(RebalancingReport report) => Report = report;\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/DynamicRebalancingTests.cs",
    "content": "using Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\n/// <summary>\n/// Tests for dynamic activation rebalancing while new activations are being created.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRebalancing\")]\npublic class DynamicRebalancingTests(RebalancerFixture fixture, ITestOutputHelper output)\n    : RebalancingTestBase<RebalancerFixture>(fixture, output), IClassFixture<RebalancerFixture>\n{\n    [Fact]\n    public async Task Should_Move_Activations_From_Silo1_And_Silo3_To_Silo2_And_Silo4_While_New_Activations_Are_Created()\n    {\n        var tasks = new List<Task>();\n\n        AddTestActivations(tasks, Silo1, 300);\n        AddTestActivations(tasks, Silo2, 30);\n        AddTestActivations(tasks, Silo3, 180);\n        AddTestActivations(tasks, Silo4, 100);\n\n        await Task.WhenAll(tasks);\n\n        var stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n        var initialSilo1Activations = GetActivationCount(stats, Silo1);\n        var initialSilo2Activations = GetActivationCount(stats, Silo2);\n        var initialSilo3Activations = GetActivationCount(stats, Silo3);\n        var initialSilo4Activations = GetActivationCount(stats, Silo4);\n\n        OutputHelper.WriteLine(\n           $\"Pre-rebalancing activations:\\n\" +\n           $\"Silo1: {initialSilo1Activations}\\n\" +\n           $\"Silo2: {initialSilo2Activations}\\n\" +\n           $\"Silo3: {initialSilo3Activations}\\n\" +\n           $\"Silo4: {initialSilo4Activations}\\n\");\n\n        var silo1Activations = initialSilo1Activations;\n        var silo2Activations = initialSilo2Activations;\n        var silo3Activations = initialSilo3Activations;\n        var silo4Activations = initialSilo4Activations;\n\n        const int extraActivationsSilo1 = 30;\n        const int extraActivationsSilo2 = 3;\n        const int extraActivationsSilo3 = 18;\n        const int extraActivationsSilo4 = 10;\n\n        var index = 0;\n        var extraRounds = 0;\n\n        while (index < 5)\n        {\n            await Task.Delay(RebalancerFixture.SessionCyclePeriod);\n\n            if (index % 2 == 0)\n            {\n                tasks.Clear();\n\n                // add an extra 1/10 of the initial activation count for each silo\n                AddTestActivations(tasks, Silo1, extraActivationsSilo1);\n                AddTestActivations(tasks, Silo2, extraActivationsSilo2);\n                AddTestActivations(tasks, Silo3, extraActivationsSilo3);\n                AddTestActivations(tasks, Silo4, extraActivationsSilo4);\n\n                await Task.WhenAll(tasks);\n\n                OutputHelper.WriteLine(\n                   $\"Added extra activations on cycle {index + 1}:\\n\" +\n                   $\"Silo1: {extraActivationsSilo1}\\n\" +\n                   $\"Silo2: {extraActivationsSilo2}\\n\" +\n                   $\"Silo3: {extraActivationsSilo3}\\n\" +\n                   $\"Silo4: {extraActivationsSilo4}\\n\");\n\n                extraRounds++;\n            }\n\n            stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n            silo1Activations = GetActivationCount(stats, Silo1);\n            silo2Activations = GetActivationCount(stats, Silo2);\n            silo3Activations = GetActivationCount(stats, Silo3);\n            silo4Activations = GetActivationCount(stats, Silo4);\n\n            index++;\n        }\n\n        var finalSilo1Activations = initialSilo1Activations + extraRounds * extraActivationsSilo1;\n        var finalSilo2Activations = initialSilo2Activations + extraRounds * extraActivationsSilo2;\n        var finalSilo3Activations = initialSilo3Activations + extraRounds * extraActivationsSilo3;\n        var finalSilo4Activations = initialSilo4Activations + extraRounds * extraActivationsSilo4;\n\n        Assert.True(silo1Activations < finalSilo1Activations,\n            $\"Did not expect Silo1 to have more activations than what it started + added afterwards: \" +\n            $\"[{finalSilo1Activations} -> {silo1Activations}]\");\n\n        Assert.True(silo2Activations > finalSilo2Activations,\n            $\"Did not expect Silo2 to have less activations than what it started + added afterwards: \" +\n            $\"[{finalSilo2Activations} -> {silo2Activations}]\");\n\n        Assert.True(silo3Activations < finalSilo3Activations,\n            $\"Did not expect Silo3 to have more activations than what it started + added afterwards: \" +\n            $\"[{finalSilo3Activations} -> {silo3Activations}]\");\n\n        Assert.True(silo4Activations > finalSilo4Activations,\n            \"Did not expect Silo4 to have less activations than what it started + added afterwards: \" +\n            $\"[{finalSilo4Activations} -> {silo4Activations}]\");\n\n        var preVariance = CalculateVariance([finalSilo1Activations, finalSilo2Activations, finalSilo3Activations, finalSilo4Activations]);\n        var postVariance = CalculateVariance([silo1Activations, silo2Activations, silo3Activations, silo4Activations]);\n\n        OutputHelper.WriteLine(\n            $\"Post-rebalancing activations ({index} cycles):\\n\" +\n            $\"Silo1: {silo1Activations} | Expected without rebalancing: {finalSilo1Activations}\\n\" +\n            $\"Silo2: {silo2Activations} | Expected without rebalancing: {finalSilo2Activations}\\n\" +\n            $\"Silo3: {silo3Activations} | Expected without rebalancing: {finalSilo3Activations}\\n\" +\n            $\"Silo4: {silo4Activations} | Expected without rebalancing: {finalSilo4Activations}\\n\" +\n            $\"Variance: {postVariance} | Expected without rebalancing: {preVariance}\");\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/RebalancerFixture.cs",
    "content": "﻿using TestExtensions;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\npublic class RebalancerFixture : BaseInProcessTestClusterFixture\n{\n    public static readonly TimeSpan RebalancerDueTime = TimeSpan.FromSeconds(5);\n    public static readonly TimeSpan SessionCyclePeriod = TimeSpan.FromSeconds(3);\n\n    protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n    {\n        builder.Options.InitialSilosCount = 4;\n        builder.Options.UseRealEnvironmentStatistics = true;\n        builder.ConfigureSilo((options, siloBuilder)\n#pragma warning disable ORLEANSEXP002\n            => siloBuilder\n                .Configure<SiloMessagingOptions>(o =>\n                {\n                    o.AssumeHomogenousSilosForTesting = true;\n                    o.ClientGatewayShutdownNotificationTimeout = default;\n                })\n                .Configure<ActivationRebalancerOptions>(o =>\n                {\n                    o.RebalancerDueTime = RebalancerDueTime;\n                    o.SessionCyclePeriod = SessionCyclePeriod;\n                })\n                .AddActivationRebalancer());\n#pragma warning restore ORLEANSEXP002\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/RebalancingOptionsTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Xunit;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\n/// <summary>\n/// Tests for activation rebalancer configuration options validation.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRebalancing\")]\npublic class RebalancingOptionsTests\n{\n    [Fact]\n    public void ConstantsShouldNotChange()\n    {\n        Assert.Equal(TimeSpan.FromSeconds(60), ActivationRebalancerOptions.DEFAULT_REBALANCER_DUE_TIME);\n        Assert.Equal(TimeSpan.FromSeconds(15), ActivationRebalancerOptions.DEFAULT_SESSION_CYCLE_PERIOD);\n        Assert.Equal(3, ActivationRebalancerOptions.DEFAULT_MAX_STAGNANT_CYCLES);\n        Assert.Equal(0.0001d, ActivationRebalancerOptions.DEFAULT_ENTROPY_QUANTUM);\n        Assert.Equal(0.0001d, ActivationRebalancerOptions.DEFAULT_ALLOWED_ENTROPY_DEVIATION);\n        Assert.Equal(0.1d, ActivationRebalancerOptions.DEFAULT_CYCLE_NUMBER_WEIGHT);\n        Assert.Equal(0.1d, ActivationRebalancerOptions.DEFAULT_SILO_NUMBER_WEIGHT);\n        Assert.Equal(0.1d, ActivationRebalancerOptions.MAX_SCALED_ENTROPY_DEVIATION);\n        Assert.Equal(10_000, ActivationRebalancerOptions.DEFAULT_SCALED_ENTROPY_DEVIATION_ACTIVATION_THRESHOLD);\n        Assert.Equal(int.MaxValue, ActivationRebalancerOptions.DEFAULT_ACTIVATION_MIGRATION_COUNT_LIMIT);\n        Assert.True(ActivationRebalancerOptions.DEFAULT_SCALE_ALLOWED_ENTROPY_DEVIATION);\n    }\n\n    [Theory]\n    [InlineData(1000, 1, 0, 0.2, 0.2, 0, -0.1, 0, 999)]\n    [InlineData(2000, 2, -1, 0.05, 0.05, 0.5, 1.1, 10, 500)]\n    [InlineData(1000, 1, 2, 0, 0.05, 0.5, 0.5, 10, 999)]    \n    [InlineData(1000, 1, 2, 0.05, 0, 0.5, 0.5, 10, 999)]    \n    [InlineData(1000, 1, 2, 0.05, 0.05, -0.1, 0.5, 10, 999)]\n    [InlineData(1000, 1, 2, 0.05, 0.05, 0.5, 1.1, 10, 999)] \n    [InlineData(1000, 1, 2, 0.05, 0.05, 0.5, 0.5, 0, 999)]  \n    [InlineData(1000, 1, 2, 0.05, 0.05, 0.5, 0.5, 10, 999)] \n\n    public void InvalidOptionsShouldThrow(\n        int sessionCyclePeriodMilliseconds,\n        int publisherRefreshTimeSeconds,\n        int maxStagnantCycles,\n        double entropyQuantum,\n        double allowedEntropyDeviation,\n        double cycleNumberWeight,\n        double siloNumberWeight,\n        int activationMigrationCountLimit,\n        int scaledEntropyDeviationActivationThreshold)\n    {\n        var publisherOptions = new DeploymentLoadPublisherOptions\n        {\n            DeploymentLoadPublisherRefreshTime = TimeSpan.FromSeconds(publisherRefreshTimeSeconds)\n        };\n\n        var options = new ActivationRebalancerOptions\n        {\n            SessionCyclePeriod = TimeSpan.FromMilliseconds(sessionCyclePeriodMilliseconds),\n            MaxStagnantCycles = maxStagnantCycles,\n            EntropyQuantum = entropyQuantum,\n            AllowedEntropyDeviation = allowedEntropyDeviation,\n            CycleNumberWeight = cycleNumberWeight,\n            SiloNumberWeight = siloNumberWeight,\n            ActivationMigrationCountLimit = activationMigrationCountLimit,\n            ScaledEntropyDeviationActivationThreshold = scaledEntropyDeviationActivationThreshold\n        };\n\n        var validator = new ActivationRebalancerOptionsValidator(Options.Create(options), Options.Create(publisherOptions));\n        Assert.Throws<OrleansConfigurationException>(validator.ValidateConfiguration);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/RebalancingTestBase.cs",
    "content": "using TestExtensions;\nusing Xunit.Abstractions;\nusing Orleans.TestingHost;\nusing Orleans.Runtime.Placement;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\npublic abstract class RebalancingTestBase<TFixture>\n    where TFixture : BaseInProcessTestClusterFixture\n{\n    protected InProcessTestCluster Cluster { get; }\n\n    protected SiloAddress Silo1 { get; }\n    protected SiloAddress Silo2 { get; }\n    protected SiloAddress Silo3 { get; }\n    protected SiloAddress Silo4 { get; }\n\n    internal ITestOutputHelper OutputHelper { get; }\n    internal IInternalGrainFactory GrainFactory { get; }\n    internal IManagementGrain MgmtGrain { get; }\n\n    protected RebalancingTestBase(TFixture fixture, ITestOutputHelper output)\n    {\n        var silos = fixture.HostedCluster.GetActiveSilos().Select(h => h.SiloAddress).OrderBy(s => s).ToArray();\n\n        Silo1 = silos[0];\n        Silo2 = silos[1];\n        Silo3 = silos[2];\n        Silo4 = silos[3];\n\n        Cluster = fixture.HostedCluster;\n        OutputHelper = output;\n        GrainFactory = (IInternalGrainFactory)fixture.HostedCluster.Client;\n        MgmtGrain = GrainFactory.GetGrain<IManagementGrain>(0);\n    }\n\n    protected static int GetActivationCount(DetailedGrainStatistic[] stats, SiloAddress silo) =>\n        stats.Count(x => x.SiloAddress.Equals(silo));\n\n    protected void AddTestActivations(List<Task> tasks, SiloAddress silo, int count)\n    {\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, silo);\n        for (var i = 0; i < count; i++)\n        {\n            tasks.Add(GrainFactory.GetGrain<IRebalancingTestGrain>(Guid.NewGuid()).Ping());\n        }\n    }\n\n    protected static int CalculateVariance(int[] values)\n    {\n        var mean = values.Average();\n        var sumSqrtDiff = values.Select(x => (x - mean) * (x - mean)).Sum();\n        var variance = sumSqrtDiff / (values.Length - 1);\n\n        return (int)variance;\n    }\n\n    public async Task InitializeAsync()\n    {\n        await GrainFactory\n            .GetGrain<IManagementGrain>(0)\n            .ForceActivationCollection(TimeSpan.Zero);\n    }\n}\n\npublic interface IRebalancingTestGrain : IGrainWithGuidKey\n{\n    Task Ping();\n}\n\npublic class RebalancingTestGrain : Grain, IRebalancingTestGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/StatePreservationRebalancingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Configuration;\nusing Orleans.Core.Internal;\nusing Orleans.Placement.Rebalancing;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\nusing SPFixture = UnitTests.ActivationRebalancingTests.StatePreservationRebalancingTests.StatePreservationFixture;\n\n#nullable enable\n\nnamespace UnitTests.ActivationRebalancingTests;\n\n/// <summary>\n/// Tests for activation rebalancing with state preservation when the hosting silo dies.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRebalancing\")]\npublic class StatePreservationRebalancingTests(SPFixture fixture, ITestOutputHelper output)\n    : RebalancingTestBase<SPFixture>(fixture, output), IClassFixture<SPFixture>\n{\n    private const string ErrorMessage =\n        \"The rebalancer was not found in any of the 4 silos. \" +\n        \"Either you have added more silos and not updated this code, \" +\n        \"or there is a bug in the rebalancer or monitor\";\n\n    [Fact]\n    public async Task Should_Migrate_And_Preserve_State_When_Hosting_Silo_Dies()\n    {\n        var tasks = new List<Task>();\n\n        // Move the rebalancer to the first secondary silo, since we will stop it later and we cannot stop\n        // the primary in this test setup.\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Cluster.Silos[1].SiloAddress);\n        await Cluster.Client.GetGrain<IActivationRebalancerWorker>(0).Cast<IGrainManagementExtension>().MigrateOnIdle();\n        RequestContext.Remove(IPlacementDirector.PlacementHintKey);\n\n        AddTestActivations(tasks, Silo1, 300);\n        AddTestActivations(tasks, Silo2, 30);\n        AddTestActivations(tasks, Silo3, 180);\n        AddTestActivations(tasks, Silo4, 100);\n\n        await Task.WhenAll(tasks);\n\n        var stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n        var initialSilo1Activations = GetActivationCount(stats, Silo1);\n        var initialSilo2Activations = GetActivationCount(stats, Silo2);\n        var initialSilo3Activations = GetActivationCount(stats, Silo3);\n        var initialSilo4Activations = GetActivationCount(stats, Silo4);\n\n        OutputHelper.WriteLine(\n           $\"Pre-rebalancing activations:\\n\" +\n           $\"Silo1: {initialSilo1Activations}\\n\" +\n           $\"Silo2: {initialSilo2Activations}\\n\" +\n           $\"Silo3: {initialSilo3Activations}\\n\" +\n           $\"Silo4: {initialSilo4Activations}\\n\");\n\n        var silo1Activations = initialSilo1Activations;\n        var silo2Activations = initialSilo2Activations;\n        var silo3Activations = initialSilo3Activations;\n        var silo4Activations = initialSilo4Activations;\n\n        var rebalancerHostNum = 0;\n        var index = 0;\n\n        while (index < 6)\n        {\n            if (index == 3)\n            {\n                (var rebalancerHost, rebalancerHostNum) = await FindRebalancerHost(Silo1);\n\n                OutputHelper.WriteLine($\"Cycle {index}: Now stopping Silo{rebalancerHostNum}, which is the host of the rebalancer\\n\");\n\n                Assert.NotEqual(rebalancerHost, Cluster.Silos[0].SiloAddress);\n                await Cluster.StopSiloAsync(Cluster.Silos.First(x => x.SiloAddress.Equals(rebalancerHost)));\n            }\n\n            await Task.Delay(SPFixture.SessionCyclePeriod);\n            stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n            silo1Activations = GetActivationCount(stats, Silo1);\n            silo2Activations = GetActivationCount(stats, Silo2);\n            silo3Activations = GetActivationCount(stats, Silo3);\n            silo4Activations = GetActivationCount(stats, Silo4);\n\n            index++;\n        }\n\n        if (rebalancerHostNum == 1)\n        {\n            Assert.True(silo2Activations > initialSilo2Activations,\n                $\"Did not expect Silo2 to have less activations than what it started with: \" +\n                $\"[{initialSilo2Activations} -> {silo2Activations}]\");\n\n            Assert.True(silo3Activations < initialSilo3Activations,\n                $\"Did not expect Silo3 to have more activations than what it started with: \" +\n                $\"[{initialSilo3Activations} -> {silo3Activations}]\");\n        }\n        else if (rebalancerHostNum == 2)\n        {\n            Assert.True(silo3Activations < initialSilo3Activations,\n                $\"Did not expect Silo3 to have more activations than what it started with: \" +\n                $\"[{initialSilo3Activations} -> {silo3Activations}]\");\n\n            Assert.True(silo4Activations > initialSilo4Activations,\n                $\"Did not expect Silo4 to have less activations than what it started with: \" +\n                $\"[{initialSilo4Activations} -> {silo4Activations}]\");\n        }\n        else if (rebalancerHostNum == 3)\n        {\n            Assert.True(silo1Activations < initialSilo1Activations,\n                $\"Did not expect Silo1 to have more activations than what it started with: \" +\n                $\"[{initialSilo1Activations} -> {silo1Activations}]\");\n\n            Assert.True(silo2Activations > initialSilo2Activations,\n                $\"Did not expect Silo2 to have less activations than what it started with: \" +\n                $\"[{initialSilo2Activations} -> {silo2Activations}]\");\n        }\n        else if (rebalancerHostNum == 4)\n        {\n            Assert.True(silo1Activations < initialSilo1Activations,\n                $\"Did not expect Silo1 to have more activations than what it started with: \" +\n                $\"[{initialSilo1Activations} -> {silo1Activations}]\");\n\n            Assert.True(silo2Activations > initialSilo2Activations,\n                $\"Did not expect Silo2 to have less activations than what it started with: \" +\n                $\"[{initialSilo2Activations} -> {silo2Activations}]\");\n        }\n\n        OutputHelper.WriteLine(\n            $\"Post-rebalancing activations ({index} cycles):\\n\" +\n            $\"Silo1: {(rebalancerHostNum == 1 ? \"DEAD\" : silo1Activations)}\\n\" +\n            $\"Silo2: {(rebalancerHostNum == 2 ? \"DEAD\" : silo2Activations)}\\n\" +\n            $\"Silo3: {(rebalancerHostNum == 3 ? \"DEAD\" : silo3Activations)}\\n\" +\n            $\"Silo4: {(rebalancerHostNum == 4 ? \"DEAD\" : silo4Activations)}\\n\");\n\n        (_, rebalancerHostNum) = await FindRebalancerHost(rebalancerHostNum switch\n        {\n            1 => Silo2,\n            2 => Silo3,\n            3 => Silo4,\n            4 => Silo1,\n            _ => throw new InvalidOperationException(ErrorMessage)\n        });\n\n        OutputHelper.WriteLine($\"The rebalancer is hosted by Silo{rebalancerHostNum} now\");\n    }\n\n    private async Task<(SiloAddress, int)> FindRebalancerHost(SiloAddress target)\n    {\n        var host = (await GrainFactory\n            .GetSystemTarget<IActivationRebalancerMonitor>(\n             Constants.ActivationRebalancerMonitorType, target)\n            .GetRebalancingReport(true))\n            .Host;\n\n        if (host.Equals(Silo1))\n        {\n            return new(host, 1);\n        }\n\n        if (host.Equals(Silo2))\n        {\n            return new(host, 2);\n        }\n\n        if (host.Equals(Silo3))\n        {\n            return new(host, 3);\n        }\n\n        if (host.Equals(Silo4))\n        {\n            return new(host, 4);\n        }\n\n        Assert.Fail(ErrorMessage);\n        return new(SiloAddress.Zero, 0);\n    }\n\n    public class StatePreservationFixture : BaseInProcessTestClusterFixture\n    {\n        public static readonly TimeSpan RebalancerDueTime = TimeSpan.FromSeconds(5);\n        public static readonly TimeSpan SessionCyclePeriod = TimeSpan.FromSeconds(3);\n\n        protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.Options.UseRealEnvironmentStatistics = true;\n            builder.ConfigureSilo((options, siloBuilder)\n#pragma warning disable ORLEANSEXP002\n                => siloBuilder\n                    .Configure<SiloMessagingOptions>(o =>\n                    {\n                        o.ResponseTimeoutWithDebugger = TimeSpan.FromMinutes(1);\n                        o.AssumeHomogenousSilosForTesting = true;\n                        o.ClientGatewayShutdownNotificationTimeout = default;\n                    })\n                    .Configure<ActivationRebalancerOptions>(o =>\n                    {\n                        o.RebalancerDueTime = RebalancerDueTime;\n                        o.SessionCyclePeriod = SessionCyclePeriod;\n                    })\n                    .AddActivationRebalancer());\n#pragma warning restore ORLEANSEXP002\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRebalancingTests/StaticRebalancingTests.cs",
    "content": "using Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.ActivationRebalancingTests;\n\n/// <summary>\n/// Tests for static activation rebalancing without adding new activations during the process.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRebalancing\")]\npublic class StaticRebalancingTests(RebalancerFixture fixture, ITestOutputHelper output)\n    : RebalancingTestBase<RebalancerFixture>(fixture, output), IClassFixture<RebalancerFixture>\n{ \n    [Fact]\n    public async Task Should_Move_Activations_From_Silo1_And_Silo3_To_Silo2_And_Silo4()\n    {\n        var tasks = new List<Task>();\n\n        AddTestActivations(tasks, Silo1, 300);\n        AddTestActivations(tasks, Silo2, 30);\n        AddTestActivations(tasks, Silo3, 180);\n        AddTestActivations(tasks, Silo4, 100);\n\n        await Task.WhenAll(tasks);\n\n        var stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n        var initialSilo1Activations = GetActivationCount(stats, Silo1);\n        var initialSilo2Activations = GetActivationCount(stats, Silo2);\n        var initialSilo3Activations = GetActivationCount(stats, Silo3);\n        var initialSilo4Activations = GetActivationCount(stats, Silo4);\n\n        OutputHelper.WriteLine(\n           $\"Pre-rebalancing activations:\\n\" +\n           $\"Silo1: {initialSilo1Activations}\\n\" +\n           $\"Silo2: {initialSilo2Activations}\\n\" +\n           $\"Silo3: {initialSilo3Activations}\\n\" +\n           $\"Silo4: {initialSilo4Activations}\\n\");\n\n        var silo1Activations = initialSilo1Activations;\n        var silo2Activations = initialSilo2Activations;\n        var silo3Activations = initialSilo3Activations;\n        var silo4Activations = initialSilo4Activations;\n\n        var index = 0;\n        while (index < 3)\n        {\n            await Task.Delay(RebalancerFixture.SessionCyclePeriod);\n            stats = await MgmtGrain.GetDetailedGrainStatistics();\n\n            silo1Activations = GetActivationCount(stats, Silo1);\n            silo2Activations = GetActivationCount(stats, Silo2);\n            silo3Activations = GetActivationCount(stats, Silo3);\n            silo4Activations = GetActivationCount(stats, Silo4);\n\n            index++;\n        }\n\n        Assert.True(silo1Activations < initialSilo1Activations,\n            $\"Did not expect Silo1 to have more activations than what it started with: \" +\n            $\"[{initialSilo1Activations} -> {silo1Activations}]\");\n\n        Assert.True(silo2Activations > initialSilo2Activations,\n            $\"Did not expect Silo2 to have less activations than what it started with: \" +\n            $\"[{initialSilo2Activations} -> {silo2Activations}]\");\n\n        Assert.True(silo3Activations < initialSilo3Activations,\n            $\"Did not expect Silo3 to have more activations than what it started with: \" +\n            $\"[{initialSilo3Activations} -> {silo3Activations}]\");\n\n        Assert.True(silo4Activations > initialSilo4Activations,\n            \"Did not expect Silo4 to have less activations than what it started with: \" +\n            $\"[{initialSilo4Activations} -> {silo4Activations}]\");\n\n        var preVariance = CalculateVariance([initialSilo1Activations, initialSilo2Activations, initialSilo3Activations, initialSilo4Activations]);\n        var postVariance = CalculateVariance([silo1Activations, silo2Activations, silo3Activations, silo4Activations]);\n        \n        OutputHelper.WriteLine(\n            $\"Post-rebalancing activations ({index} cycles):\\n\" +\n            $\"Silo1: {silo1Activations}\\n\" +\n            $\"Silo2: {silo2Activations}\\n\" +\n            $\"Silo3: {silo3Activations}\\n\" +\n            $\"Silo4: {silo4Activations}\\n\" +\n            $\"Variance: {postVariance} | Expected without rebalancing: {preVariance}\");\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/BlockedBloomFilterTests.cs",
    "content": "using Orleans.Runtime.Placement.Repartitioning;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n#nullable enable\n\npublic class BlockedBloomFilterTests\n{\n    private readonly GrainId _grainId = GrainId.Create(\"test\", \"key\");\n\n    [Fact]\n    public void AddAndCheck()\n    {\n        var filter = new BlockedBloomFilter(100, 0.01);\n\n        filter.Add(_grainId);\n\n        Assert.True(filter.Contains(_grainId));\n    }\n\n    [Fact]\n    public void DoesNotContainSome()\n    {\n        var filter = new BlockedBloomFilter(100, 0.01);\n        Assert.False(filter.Contains(_grainId));\n    }\n}\n\npublic class AnchoredGrainsFilterTests\n{\n    private readonly GrainId _grainId = GrainId.Create(\"test\", \"key\");\n\n    private static AnchoredGrainsFilter CreateFilter(int generations = 2) => new(100, 0.01, generations);\n\n    [Fact]\n    public void AddAndCheck()\n    {\n        var filter = CreateFilter();\n\n        filter.Add(_grainId);\n\n        Assert.True(filter.Contains(_grainId));\n    }\n\n    [Fact]\n    public void Rotate_RetainsGrains_AfterFirstCycle()\n    {\n        var filter = CreateFilter();\n\n        filter.Add(_grainId);\n        filter.Rotate(); // Gen 0 -> Gen 1\n\n        Assert.True(filter.Contains(_grainId));\n    }\n\n    [Fact]\n    public void Rotate_DropsGrains_AfterAllCycles_2Gen()\n    {\n        var filter = CreateFilter(generations: 2);\n        filter.Add(_grainId);\n\n        filter.Rotate(); // Gen 0 -> Gen 1\n        Assert.True(filter.Contains(_grainId));\n\n        filter.Rotate(); // Gen 1 -> Gone\n        Assert.False(filter.Contains(_grainId));\n    }\n\n    [Fact]\n    public void Rotate_DropsGrains_AfterAllCycles_3Gen()\n    {\n        var filter = CreateFilter(generations: 3);\n        filter.Add(_grainId);\n\n        filter.Rotate(); // Gen 0 -> Gen 1\n        Assert.True(filter.Contains(_grainId));\n\n        filter.Rotate(); // Gen 1 -> Gen 2\n        Assert.True(filter.Contains(_grainId));\n\n        filter.Rotate(); // Gen 2 -> Gone\n        Assert.False(filter.Contains(_grainId));\n    }\n\n    [Fact]\n    public void ContinuousActivity_KeepsGrainsAnchored()\n    {\n        var filter = CreateFilter(generations: 3);\n\n        foreach (var _ in Enumerable.Range(0, 10))\n        {\n            filter.Add(_grainId); // A hot grain\n            filter.Rotate();\n            Assert.True(filter.Contains(_grainId));\n        }\n    }\n\n    [Fact]\n    public void Reset_ClearsAllFilters()\n    {\n        var filter = CreateFilter(generations: 3);\n\n        filter.Add(_grainId);\n        filter.Reset();\n\n        Assert.False(filter.Contains(_grainId)); // None of the filters should contain it.\n    }\n\n    [Fact]\n    public void Rotate_CalledManyTimes_DoesNotThrowOutOfBounds()\n    {\n        var filter = CreateFilter(generations: 3);\n\n        var exception = Record.Exception(() =>\n        {\n            for (var i = 0; i < 100; i++)\n            {\n                filter.Rotate();\n            }\n        });\n\n        Assert.Null(exception);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/CustomToleranceTests.cs",
    "content": "using System.ComponentModel;\nusing System.Diagnostics;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Placement;\nusing Orleans.Placement.Repartitioning;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n// Scenarios can be seen visually here: https://github.com/dotnet/orleans/pull/8877\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRepartitioning\"), Category(\"BVT\")]\npublic class CustomToleranceTests(CustomToleranceTests.Fixture fixture, ITestOutputHelper output) : RepartitioningTestBase<CustomToleranceTests.Fixture>(fixture), IClassFixture<CustomToleranceTests.Fixture>\n{\n    [Fact]\n    public async Task Should_ConvertAllRemoteCalls_ToLocalCalls_WhileRespectingTolerance()\n    {\n        using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));\n        await AdjustActivationCountOffsets();\n\n        var e1 = GrainFactory.GetGrain<IE>(1);\n        var e2 = GrainFactory.GetGrain<IE>(2);\n        var e3 = GrainFactory.GetGrain<IE>(3);\n\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n\n        await e1.FirstPing(Silo2);\n        await e2.FirstPing(Silo2);\n        await e3.FirstPing(Silo2);\n\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo2);\n        var x = GrainFactory.GetGrain<IX>(0);\n        await x.Ping();\n\n        var i = 0;\n        while (i < 3)\n        {\n            await e1.Ping();\n            await e2.Ping();\n            await e3.Ping();\n            await x.Ping();\n            i++;\n        }\n\n        var f1 = GrainFactory.GetGrain<IF>(1);\n        var f2 = GrainFactory.GetGrain<IF>(2);\n        var f3 = GrainFactory.GetGrain<IF>(3);\n\n        var e1_host = await e1.GetAddress();\n        var e2_host = await e2.GetAddress();\n        var e3_host = await e3.GetAddress();\n\n        var f1_host = await f1.GetAddress();\n        var f2_host = await f2.GetAddress();\n        var f3_host = await f3.GetAddress();\n\n        Assert.Equal(Silo1, e1_host);\n        Assert.Equal(Silo1, e2_host);\n        Assert.Equal(Silo1, e3_host);\n\n        Assert.Equal(Silo2, f1_host);\n        Assert.Equal(Silo2, f2_host);\n        Assert.Equal(Silo2, f3_host);\n\n        Assert.Equal(Silo2, await x.GetAddress()); // X remains in silo 2\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n\n        // At this point the layout is like follows:\n\n        // S1: E1-F1, E3-F3, sys.svc.clustering.dev, rest (default activations, present in both silos)\n        // S2: E2-F2, X, rest (default activations, present in both silos)\n\n        // Tolerance <= 2, and if we ignore defaults once, sys.svc.clustering.dev, and X (which is used to counter-balance sys.svc.clustering.dev)\n        // we end up with a total of 4 activations in silo1, and 2 in silo 2, which means the tolerance has been respected, and all remote calls have\n        // been converted to local calls.\n\n        await Test();\n\n        // To make sure, we trigger 's1_rebalancer' again, which should yield to no further migrations.\n        i = 0;\n        while (i < 3)\n        {\n            await e1.Ping();\n            await e2.Ping();\n            await e3.Ping();\n            await x.Ping();\n            i++;\n        }\n\n        await LogEdgesAsync(Silo1Repartitioner);\n        await LogEdgesAsync(Silo2Repartitioner);\n        await Silo1Repartitioner.TriggerExchangeRequest();\n        await Test();\n\n        // To make extra sure, we now trigger 's2_rebalancer', which again should yield to no further migrations.\n        i = 0;\n        while (i < 3)\n        {\n            await e1.Ping();\n            await e2.Ping();\n            await e3.Ping();\n            await x.Ping();\n            i++;\n        }\n\n        await Silo2Repartitioner.TriggerExchangeRequest();\n\n        await Test();\n\n        async Task Test()\n        {\n            e1_host = await e1.GetAddress();\n            e2_host = await e2.GetAddress();\n            e3_host = await e3.GetAddress();\n\n            f1_host = await f1.GetAddress();\n            f2_host = await f2.GetAddress();\n            f3_host = await f3.GetAddress();\n\n            // Check that each grain is collocated with its pair\n            Assert.Equal(f1_host, e1_host);\n            Assert.Equal(f2_host, e2_host);\n            Assert.Equal(f3_host, e3_host);\n\n            var locations = new SiloAddress[] { e1_host, e2_host, e3_host };\n            Assert.False(locations.All(h => h.Equals(Silo1)), \"Grains should not all be located on silo 1.\");\n            Assert.False(locations.All(h => h.Equals(Silo2)), \"Grains should not all be located on silo 2.\");\n\n            Assert.Equal(Silo2, await x.GetAddress()); // X remains in silo 2\n        }\n    }\n\n    private async Task LogEdgesAsync(IActivationRepartitionerSystemTarget repartitioner)\n    {\n        var edgeCounts = await repartitioner.GetGrainCallFrequencies();\n        output.WriteLine($\"{repartitioner.GetGrainId()} call frequencies:\");\n        foreach (var (edge, freq) in edgeCounts)\n        {\n            output.WriteLine($\"\\t{edge} x {freq}\");\n        }\n    }\n\n    public interface IE : IGrainWithIntegerKey\n    {\n        Task FirstPing(SiloAddress silo2);\n        Task Ping();\n        Task<SiloAddress> GetAddress();\n    }\n\n    public interface IF : IGrainWithIntegerKey\n    {\n        Task Ping();\n        Task<SiloAddress> GetAddress();\n    }\n\n    public interface IX : IGrainWithIntegerKey\n    {\n        Task Ping();\n        Task<SiloAddress> GetAddress();\n    }\n\n    public class E : Grain, IE\n    {\n        public async Task FirstPing(SiloAddress silo2)\n        {\n            RequestContext.Set(IPlacementDirector.PlacementHintKey, silo2);\n            await GrainFactory.GetGrain<IF>(this.GetPrimaryKeyLong()).Ping();\n        }\n\n        public Task Ping() => GrainFactory.GetGrain<IF>(this.GetPrimaryKeyLong()).Ping();\n        public Task<SiloAddress> GetAddress() => Task.FromResult(GrainContext.Address.SiloAddress);\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<E>>().LogInformation(\"Activating {GrainId} on silo {SiloAddress}\", this.GrainId, this.Runtime.SiloAddress);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<E>>().LogInformation(\"Deactivating {GrainId} on silo {SiloAddress}. Reason: {Reason}\", this.GrainId, this.Runtime.SiloAddress, reason);\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n    public class F : Grain, IF\n    {\n        public Task Ping() => Task.CompletedTask;\n\n        public Task<SiloAddress> GetAddress() => Task.FromResult(GrainContext.Address.SiloAddress);\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<F>>().LogInformation(\"Activating {GrainId} on silo {SiloAddress}\", this.GrainId, this.Runtime.SiloAddress);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<F>>().LogInformation(\"Deactivating {GrainId} on silo {SiloAddress}. Reason: {Reason}\", this.GrainId, this.Runtime.SiloAddress, reason);\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n    /// <summary>\n    /// This is simply to achieve initial balance between the 2 silos, as by default the primary\n    /// will have 1 more activation than the secondary. That activations is 'sys.svc.clustering.dev'\n    /// </summary>\n    [Immovable(ImmovableKind.Repartitioner)]\n    public class X : Grain, IX\n    {\n        public Task Ping() => Task.CompletedTask;\n        public Task<SiloAddress> GetAddress() => Task.FromResult(GrainContext.Address.SiloAddress);\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<X>>().LogInformation(\"Activating {GrainId} on silo {SiloAddress}\", this.GrainId, this.Runtime.SiloAddress);\n            return base.OnActivateAsync(cancellationToken);\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            ServiceProvider.GetRequiredService<ILogger<X>>().LogInformation(\"Deactivating {GrainId} on silo {SiloAddress}. Reason: {Reason}\", this.GrainId, this.Runtime.SiloAddress, reason);\n            return base.OnDeactivateAsync(reason, cancellationToken);\n        }\n    }\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 2;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                => hostBuilder\n                    .Configure<SiloMessagingOptions>(o =>\n                    {\n                        o.AssumeHomogenousSilosForTesting = true;\n                        o.ClientGatewayShutdownNotificationTimeout = default;\n                    })\n                    .Configure<ActivationRepartitionerOptions>(o =>\n                    {\n                        // Make these so that the timers practically never fire! We will invoke the protocol manually.\n                        o.MinRoundPeriod = TimeSpan.FromSeconds(299);\n                        o.MaxRoundPeriod = TimeSpan.FromSeconds(300);\n                        // Make this zero, so we can invoke the protocol more than once without needing to put a delay in the tests. \n                        o.RecoveryPeriod = TimeSpan.Zero;\n\n                        // To remove the remote possibility of false positives caused by the probabilistic filtering in tests.\n                        o.AnchoringFilterEnabled = false;\n                    })\n                    .AddActivationRepartitioner<HardLimitRule>()\n                    .ConfigureLogging(logging => logging.AddFilter(\"Orleans.Runtime.Placement.Repartitioning\", LogLevel.Trace))\n                    .ConfigureServices(service => service.AddSingleton<IRepartitionerMessageFilter, TestMessageFilter>());\n#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n        }\n\n        private class HardLimitRule : IImbalanceToleranceRule\n        {\n            public bool IsSatisfiedBy(uint imbalance) => imbalance <= 2;\n        }\n\n        private class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<GatewayOptions>(o => o.PreferredGatewayIndex = 0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/DefaultToleranceTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Placement;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n/// <summary>\n/// Tests for default tolerance scenarios in activation repartitioning, including grain movement and placement decisions.\n/// </summary>\n// Scenarious can be seen visually here: https://github.com/dotnet/orleans/pull/8877\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRepartitioning\")]\npublic class DefaultToleranceTests(DefaultToleranceTests.Fixture fixture) : RepartitioningTestBase<DefaultToleranceTests.Fixture>(fixture), IClassFixture<DefaultToleranceTests.Fixture>\n{\n    [Fact]\n    public async Task A_ShouldMoveToSilo2__B_And_C_ShouldStayOnSilo2()\n    {\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n\n        var scenario = Scenario._1;\n        var a = GrainFactory.GetGrain<IA>($\"a{scenario}\");\n        await a.FirstPing(scenario, Silo1, Silo2);\n\n        var i = 0;\n        while (i < 3)\n        {\n            await a.Ping(scenario);\n            i++;\n        }\n\n        var b = GrainFactory.GetGrain<IB>($\"b{scenario}\");\n        var c = GrainFactory.GetGrain<IC>($\"c{scenario}\");\n\n        var a_host = await a.GetAddress();\n        var b_host = await b.GetAddress();\n        var c_host = await c.GetAddress();\n\n        Assert.Equal(Silo1, a_host);\n        Assert.Equal(Silo2, b_host);\n        Assert.Equal(Silo2, c_host);\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n\n        do\n        {\n            a_host = await a.GetAddress();\n        }\n        while (a_host == Silo1);\n\n        // refresh\n        a_host = await a.GetAddress();\n        b_host = await b.GetAddress();\n        c_host = await c.GetAddress();\n\n        Assert.Equal(Silo2, a_host);  // A is now in silo 2\n        Assert.Equal(Silo2, b_host);\n        Assert.Equal(Silo2, c_host);\n\n        await ResetCounters();\n    }\n\n    [Fact]\n    public async Task C_ShouldMoveToSilo1__A_And_B_ShouldStayOnSilo1()\n    {\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n\n        var scenario = Scenario._2;\n        var a = GrainFactory.GetGrain<IA>($\"a{scenario}\");\n        var b = GrainFactory.GetGrain<IB>($\"b{scenario}\");\n\n        await a.FirstPing(scenario, Silo1, Silo2);\n        await b.Ping(scenario);\n\n        var i = 0;\n        while (i < 3)\n        {\n            await a.Ping(scenario);\n            await b.Ping(scenario);\n            i++;\n        }\n\n        var c = GrainFactory.GetGrain<IC>($\"c{scenario}\");\n\n        var a_host = await a.GetAddress();\n        var b_host = await b.GetAddress();\n        var c_host = await c.GetAddress();\n\n        Assert.Equal(Silo1, a_host);\n        Assert.Equal(Silo1, b_host);\n        Assert.Equal(Silo2, c_host);\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n\n        do\n        {\n            c_host = await c.GetAddress();\n        }\n        while (c_host == Silo2);\n\n        // refresh\n        a_host = await a.GetAddress();\n        b_host = await b.GetAddress();\n        c_host = await c.GetAddress();\n\n        Assert.Equal(Silo1, a_host);\n        Assert.Equal(Silo1, b_host);\n        Assert.Equal(Silo1, c_host);  // C is now in silo 1\n\n        await ResetCounters();\n    }\n\n    [Fact]\n    public async Task Immovable_C_ShouldStayOnSilo2__A_And_B_ShouldMoveToSilo2()\n    {\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n\n        var scenario = Scenario._3;\n        var a = GrainFactory.GetGrain<IA>($\"a{scenario}\");\n        var b = GrainFactory.GetGrain<IB>($\"b{scenario}\");\n\n        await a.FirstPing(scenario, Silo1, Silo2);\n        await b.Ping(scenario);\n\n        var i = 0;\n        while (i < 3)\n        {\n            await a.Ping(scenario);\n            await b.Ping(scenario);\n            i++;\n        }\n\n        var c = GrainFactory.GetGrain<ICImmovable>($\"c{scenario}\");\n\n        var a_host = await a.GetAddress();\n        var b_host = await b.GetAddress();\n        var c_host = await c.GetAddress();\n\n        Assert.Equal(Silo1, a_host);\n        Assert.Equal(Silo1, b_host);\n        Assert.Equal(Silo2, c_host);\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n\n        do\n        {\n            a_host = await a.GetAddress();\n            b_host = await b.GetAddress();\n        }\n        while (a_host == Silo1 || b_host == Silo1);\n\n        // refresh\n        a_host = await a.GetAddress();\n        b_host = await b.GetAddress();\n        c_host = await c.GetAddress();\n\n        Assert.Equal(Silo2, a_host);  // A is now in silo 2\n        Assert.Equal(Silo2, b_host);  // B is now in silo 2\n        Assert.Equal(Silo2, c_host);  // C is still in silo 2\n\n        await ResetCounters();\n    }\n\n    [Fact]\n    public async Task A_ShouldMoveToSilo2_Or_C_ShouldMoveToSilo1__B_And_D_ShouldStayOnTheirSilos()\n    {\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n\n        var scenario = Scenario._4;\n        var a = GrainFactory.GetGrain<IA>($\"a{scenario}\");\n\n        await a.FirstPing(scenario, Silo1, Silo2);\n\n        var i = 0;\n        while (i < 3)\n        {\n            await a.Ping(scenario);\n            i++;\n        }\n\n        var b = GrainFactory.GetGrain<IB>($\"b{scenario}\");\n        var c = GrainFactory.GetGrain<IC>($\"c{scenario}\");\n        var d = GrainFactory.GetGrain<ID>($\"d{scenario}\");\n\n        var a_host = await a.GetAddress();\n        var b_host = await b.GetAddress();\n        var c_host = await c.GetAddress();\n        var d_host = await d.GetAddress();\n\n        Assert.Equal(Silo1, a_host);\n        Assert.Equal(Silo1, b_host);\n        Assert.Equal(Silo2, c_host);\n        Assert.Equal(Silo2, d_host);\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n\n        do\n        {\n            a_host = await a.GetAddress();\n            c_host = await c.GetAddress();\n        }\n        while (a_host == Silo1 && c_host == Silo2);\n\n        // refresh\n        a_host = await a.GetAddress();\n        b_host = await b.GetAddress();\n        c_host = await c.GetAddress();\n        d_host = await d.GetAddress();\n\n        // A can go to Silo 2, or C can come to Silo 1, both are valid, so we need to check for both.\n        if (a_host == Silo2 && c_host == Silo2)\n        {\n            Assert.Equal(Silo2, a_host);  // A is now in silo 2\n            Assert.Equal(Silo1, b_host);\n            Assert.Equal(Silo2, c_host);\n            Assert.Equal(Silo2, d_host);\n\n            return;\n        }\n\n        if (a_host == Silo1 && c_host == Silo1)\n        {\n            Assert.Equal(Silo1, a_host);\n            Assert.Equal(Silo1, b_host);\n            Assert.Equal(Silo1, c_host);  // C is now in silo 1\n            Assert.Equal(Silo2, d_host);\n\n            return;\n        }\n\n        await ResetCounters();\n    }\n\n    [SkippableFact]\n    public async Task Receivers_ShouldMoveCloseTo_PullingAgent()\n    {\n        var sp1 = GrainFactory.GetGrain<ISP>(\"s1\");\n        var sp2 = GrainFactory.GetGrain<ISP>(\"s2\");\n        var sp3 = GrainFactory.GetGrain<ISP>(\"s3\");\n\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo1);\n        await sp1.FirstPing();\n        await sp2.FirstPing();\n\n        RequestContext.Set(IPlacementDirector.PlacementHintKey, Silo2);\n        await sp3.FirstPing();\n\n        var i = 0;\n        while (i < 3)\n        {\n            await sp1.StreamPing();\n            await sp2.StreamPing();\n            await sp3.StreamPing();\n            i++;\n        }\n\n        var sr1 = GrainFactory.GetGrain<ISR>(\"s1\");\n        var sr2 = GrainFactory.GetGrain<ISR>(\"s2\");\n        var sr3 = GrainFactory.GetGrain<ISR>(\"s3\");\n\n        var sr1_GotHit = false;\n        var sr2_GotHit = false;\n        var sr3_GotHit = false;\n\n        while (!sr1_GotHit || !sr2_GotHit || !sr3_GotHit)\n        {\n            sr1_GotHit = await sr1.GotStreamHit();\n            sr2_GotHit = await sr2.GotStreamHit();\n            sr3_GotHit = await sr3.GotStreamHit();\n        }\n\n        var sr1_host = await sr1.GetAddress();\n        var sr2_host = await sr2.GetAddress();\n        var sr3_host = await sr3.GetAddress();\n\n        Assert.Equal(Silo1, sr1_host);\n        Assert.Equal(Silo1, sr2_host);\n        Assert.Equal(Silo2, sr3_host);\n\n        await Silo1Repartitioner.TriggerExchangeRequest();\n        await Task.Delay(100); // leave some breathing room - may not be enough though, thats why this test is skippable\n\n        var allowedDuration = TimeSpan.FromSeconds(3);\n        Stopwatch stopwatch = new();\n        stopwatch.Start();\n\n        do\n        {\n            sr1_host = await sr1.GetAddress();\n            sr2_host = await sr2.GetAddress();\n\n            Skip.If(stopwatch.Elapsed > allowedDuration);\n        }\n        while (sr1_host == Silo1 || sr2_host == Silo1);\n\n        // refresh\n        sr1_host = await sr1.GetAddress();\n        sr2_host = await sr2.GetAddress();\n        sr3_host = await sr3.GetAddress();\n\n        Assert.Equal(Silo2, sr1_host);  // SR1 is now in silo 2, as there is 1 pulling agent (which is moved to silo 2 by the streaming runtime)\n        Assert.Equal(Silo2, sr2_host);  // SR2 is now in silo 2, as there is 1 pulling agent (which is moved to silo 2 by the streaming runtime)\n        Assert.Equal(Silo2, sr3_host);\n\n        await ResetCounters();\n    }\n\n    public enum Scenario { _1, _2, _3, _4 }\n\n    public interface IBase : IGrainWithStringKey\n    {\n        Task Ping(Scenario scenario);\n        Task<SiloAddress> GetAddress();\n    }\n    public interface IA : IBase\n    {\n        Task FirstPing(Scenario scenario, SiloAddress silo1, SiloAddress silo2);\n    }\n    public interface IB : IBase { }\n    public interface IC : IBase\n    {\n        Task Ping(Scenario scenario, SiloAddress silo2);\n    }\n    public interface ICImmovable : IBase { }\n    public interface ID : IBase { }\n    public interface ISP : IGrainWithStringKey\n    {\n        Task FirstPing();\n        Task StreamPing();\n        Task<SiloAddress> GetAddress();\n    }\n    public interface ISR : IGrainWithStringKey\n    {\n        Task Ping();\n        Task<bool> GotStreamHit();\n        Task<SiloAddress> GetAddress();\n    }\n\n    public abstract class GrainBase : Grain\n    {\n        public Task<SiloAddress> GetAddress() => Task.FromResult(GrainContext.Address.SiloAddress);\n    }\n\n    public class A : GrainBase, IA\n    {\n        private SiloAddress _silo1;\n        private SiloAddress _silo2;\n\n        public async Task FirstPing(Scenario scenario, SiloAddress silo1, SiloAddress silo2)\n        {\n            _silo1 = silo1;\n            _silo2 = silo2;\n\n            switch (scenario)\n            {\n                case Scenario._1:\n                    {\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, _silo2);\n\n                        await GrainFactory.GetGrain<IB>($\"b{scenario}\").Ping(scenario);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._2:\n                    {\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, _silo2);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._3:\n                    {\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, _silo2);\n                        await GrainFactory.GetGrain<ICImmovable>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._4:\n                    {\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, _silo1);\n                        await GrainFactory.GetGrain<IB>($\"b{scenario}\").Ping(scenario);\n\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, _silo2);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario, _silo2);\n                    }\n                    break;\n                default: throw new NotSupportedException();\n            }\n        }\n\n        public async Task Ping(Scenario scenario)\n        {\n            switch (scenario)\n            {\n                case Scenario._1:\n                    {\n                        await GrainFactory.GetGrain<IB>($\"b{scenario}\").Ping(scenario);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._2:\n                    {\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._3:\n                    {\n                        await GrainFactory.GetGrain<ICImmovable>($\"c{scenario}\").Ping(scenario);\n                    }\n                    break;\n                case Scenario._4:\n                    {\n                        await GrainFactory.GetGrain<IB>($\"b{scenario}\").Ping(scenario);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario);\n                        await GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario, _silo2);\n                    }\n                    break;\n                default: throw new NotSupportedException();\n            }\n        }\n    }\n\n    public class B : GrainBase, IB\n    {\n        public Task Ping(Scenario scenario) =>\n            scenario switch\n            {\n                Scenario._1 => Task.CompletedTask,\n                Scenario._2 => GrainFactory.GetGrain<IC>($\"c{scenario}\").Ping(scenario),\n                Scenario._3 => GrainFactory.GetGrain<ICImmovable>($\"c{scenario}\").Ping(scenario),\n                Scenario._4 => Task.CompletedTask,\n                _ => throw new NotSupportedException(),\n            };\n    }\n\n    public class C : GrainBase, IC\n    {\n        public Task Ping(Scenario scenario) =>\n            scenario switch\n            {\n                Scenario._1 => GrainFactory.GetGrain<IB>($\"b{scenario}\").Ping(scenario),\n                Scenario._2 => Task.CompletedTask,\n                Scenario._3 => Task.CompletedTask,\n                Scenario._4 => Task.CompletedTask,\n                _ => throw new NotSupportedException(),\n            };\n\n        public async Task Ping(Scenario scenario, SiloAddress silo2)\n        {\n            switch (scenario)\n            {\n                case Scenario._4:\n                    {\n                        RequestContext.Set(IPlacementDirector.PlacementHintKey, silo2);\n                        await GrainFactory.GetGrain<ID>($\"d{scenario}\").Ping(scenario);\n                    }\n                    break;\n                default: throw new NotSupportedException();\n            }\n        }\n    }\n\n    [Immovable(ImmovableKind.Repartitioner)]\n    public class CImmovable : GrainBase, ICImmovable\n    {\n        public Task Ping(Scenario scenario) =>\n            scenario switch\n            {\n                Scenario._3 => Task.CompletedTask,\n                _ => throw new NotSupportedException(),\n            };\n    }\n\n    public class D : GrainBase, ID\n    {\n        public Task Ping(Scenario scenario) =>\n            scenario switch\n            {\n                Scenario._4 => Task.CompletedTask,\n                _ => throw new NotSupportedException(),\n            };\n    }\n\n    [Immovable(ImmovableKind.Repartitioner)]\n    public class SP : GrainBase, ISP\n    {\n        // We are just 'Immovable' on this type, because we just want it to push messages to the stream,\n        // as for some reason pushing to a stream via the cluster client isnt invoking the consumer grains.\n\n        private IAsyncStream<int> _stream;\n\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            _stream = this.GetStreamProvider(Fixture.StreamProviderName)\n                .GetStream<int>(StreamId.Create(Fixture.StreamNamespaceName, this.GetPrimaryKeyString()));\n\n            return Task.CompletedTask;\n        }\n\n        public Task FirstPing() => GrainFactory.GetGrain<ISR>(this.GetPrimaryKeyString()).Ping();\n        public Task StreamPing() => _stream.OnNextAsync(Random.Shared.Next());\n    }\n\n    [ImplicitStreamSubscription(Fixture.StreamNamespaceName)]\n    public class SR : GrainBase, ISR\n    {\n        private bool _streamHit = false;\n\n        public override async Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            var sp = this.GetStreamProvider(Fixture.StreamProviderName)\n                .GetStream<int>(StreamId.Create(Fixture.StreamNamespaceName, this.GetPrimaryKeyString()));\n\n            await sp.SubscribeAsync((_, _) =>\n             {\n                 _streamHit = true;\n                 return Task.CompletedTask;\n             });\n        }\n\n        public Task Ping() => Task.CompletedTask;\n        public Task<bool> GotStreamHit() => Task.FromResult(_streamHit);\n    }\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        public const string StreamProviderName = \"arsp\";\n        public const string StreamNamespaceName = \"arns\";\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 2;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n#pragma warning disable ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                => hostBuilder\n                    .Configure<SiloMessagingOptions>(o =>\n                    {\n                        o.AssumeHomogenousSilosForTesting = true;\n                        o.ClientGatewayShutdownNotificationTimeout = default;\n                    })\n                    .Configure<ActivationRepartitionerOptions>(o =>\n                    {\n                        // Make these so that the timers practically never fire! We will invoke the protocol manually.\n                        o.MinRoundPeriod = TimeSpan.FromSeconds(299);\n                        o.MaxRoundPeriod = TimeSpan.FromSeconds(300);\n                        // Make this practically zero, so we can invoke the protocol more than once without needing to put a delay in the tests. \n                        o.RecoveryPeriod = TimeSpan.FromMilliseconds(1);\n                    })\n                    .AddMemoryStreams(StreamProviderName, c =>\n                    {\n                        c.ConfigurePartitioning(1);\n                        c.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    })\n                    .AddActivationRepartitioner()\n                    .ConfigureServices(service => service.AddSingleton<IRepartitionerMessageFilter, TestMessageFilter>());\n#pragma warning restore ORLEANSEXP001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/FrequencyFilterTests.cs",
    "content": "using System.Text;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\npublic class FrequencyFilterTests\n{\n    [Fact]\n    public void GetExpectedTopK()\n    {\n        const int NumSamples = 10_000;\n        var sink = new UlongFrequentItemCollection(100);\n        var random = new Random();\n        var distribution = new ZipfRejectionSampler(random, 1000, 0.5);\n        for (var i = 0; i < NumSamples; i++)\n        {\n            var sample = (ulong)distribution.Sample();\n            sink.Add(new TestKey(sample));\n\n            if (i == 4 * NumSamples / 5)\n            {\n                sink.Remove(new TestKey(3));\n            }\n        }\n\n        var allCounters = sink.Elements.ToList();\n        allCounters.Sort((left, right) => right.Count.CompareTo(left.Count));\n        var sb = new StringBuilder();\n        foreach (var (key, count, error) in allCounters)\n        {\n            if (error == 0)\n            {\n                sb.AppendLine($\"{key.Key,3}: {count}\");\n            }\n            else\n            {\n                sb.AppendLine($\"{key.Key,3}: {count} ε{error}\");\n            }\n        }\n\n        var result = sb.ToString();\n        Assert.NotEmpty(result);\n    }\n\n    public readonly struct TestKey(ulong key) \n    {\n        private static ulong _nextKey;\n        public static TestKey GetNext() => new(_nextKey++);\n        public readonly ulong Key = key;\n\n        public override string ToString() => $\"[{Key}]\";\n    }\n\n    private sealed class UlongFrequentItemCollection(int capacity) : FrequentItemCollection<ulong, TestKey>(capacity)\n    {\n        protected override ulong GetKey(in TestKey element) => element.Key;\n        public void Remove(in TestKey element) => RemoveCore(GetKey(element));\n    }\n\n    /// <summary>\n    /// Generates an approximate Zipf distribution. Previous method was 20x faster than MathNet.Numerics, but could only generate 250 samples/sec.\n    /// This approximate method can generate > 1,000,000 samples/sec.\n    /// </summary>\n    public class FastZipf\n    {\n        private static readonly Random SeededPrng = new(42);\n\n        /// <summary>\n        /// Generate a zipf distribution.\n        /// </summary>\n        /// <param name=\"random\">The random number generator to use.</param>\n        /// <param name=\"sampleCount\">The number of samples.</param>\n        /// <param name=\"skew\">The skew. s=0 is a uniform distribution. As s increases, high-rank items become rapidly more likely than the rare low-ranked items.</param>\n        /// <param name=\"cardinality\">N: the cardinality. The total number of items.</param>\n        /// <returns>A zipf distribution.</returns>\n        public static long[] Generate(Random random, int sampleCount, double skew, int cardinality)\n        {\n            var sampler = new ZipfRejectionSampler(random, cardinality, skew);\n\n            var samples = new long[sampleCount];\n            for (var i = 0; i < sampleCount; i++)\n            {\n                samples[i] = sampler.Sample();\n            }\n\n            return samples;\n        }\n\n        /// <summary>\n        /// Generate a zipf distribution.\n        /// </summary>\n        /// <param name=\"sampleCount\">The number of samples.</param>\n        /// <param name=\"skew\">The skew. s=0 is a uniform distribution. As s increases, high-rank items become rapidly more likely than the rare low-ranked items.</param>\n        /// <param name=\"cardinality\">N: the cardinality. The total number of items.</param>\n        /// <returns>A zipf distribution.</returns>\n        public static long[] Generate(int sampleCount, double skew, int cardinality) => Generate(SeededPrng, sampleCount, skew, cardinality);\n    }\n\n    // https://jasoncrease.medium.com/rejection-sampling-the-zipf-distribution-6b359792cffa\n    public class ZipfRejectionSampler\n    {\n        private readonly Random _rand;\n        private readonly double _skew;\n        private readonly double _t;\n\n        public ZipfRejectionSampler(Random random, long cardinality, double skew)\n        {\n            _rand = random;\n            _skew = skew;\n            _t = (Math.Pow(cardinality, 1 - skew) - skew) / (1 - skew);\n        }\n\n        public long Sample()\n        {\n            while (true)\n            {\n                var invB = bInvCdf(_rand.NextDouble());\n                var sampleX = (long)(invB + 1);\n                var yRand = _rand.NextDouble();\n                var ratioTop = Math.Pow(sampleX, -_skew);\n                var ratioBottom = sampleX <= 1 ? 1 / _t : Math.Pow(invB, -_skew) / _t;\n                var rat = ratioTop / (ratioBottom * _t);\n\n                if (yRand < rat)\n                {\n                    return sampleX;\n                }\n            }\n        }\n        private double bInvCdf(double p)\n        {\n            return p * _t switch\n            {\n                <= 1 => p * _t,\n                _ => Math.Pow(p * _t * (1 - _skew) + _skew, 1 / (1 - _skew))\n            };\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/FrequentEdgeCounterTests.cs",
    "content": "using Orleans.Placement.Repartitioning;\nusing Orleans.Runtime.Placement.Repartitioning;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n[Alias(\"UnitTests.ActivationRepartitioningTests.IMyPartitionableGrain\")]\npublic interface IMyPartitionableGrain : IGrainWithStringKey\n{\n    [Alias(\"GetValue\")]\n    Task<T> GetValue<T>();\n\n    [Alias(\"GetValue1\")]\n    Task<T> GetValue<T, H>();\n}\n\n[Alias(\"UnitTests.ActivationRepartitioningTests.IMyGrain`1\")]\npublic interface IMyActiveBalancingGrain<T> : IGrainWithStringKey\n{\n    Task<T> GetValue();\n}\n\n/// <summary>\n/// Tests for the frequent edge counter used to track communication patterns in activation repartitioning.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRepartitioning\")]\npublic class FrequentEdgeCounterTests\n{\n    private static readonly GrainId Id_A = GrainId.Create(\"A\", Guid.NewGuid().ToString());\n    private static readonly GrainId Id_B = GrainId.Create(\"B\", Guid.NewGuid().ToString());\n    private static readonly GrainId Id_C = GrainId.Create(\"C\", Guid.NewGuid().ToString());\n    private static readonly GrainId Id_D = GrainId.Create(\"D\", Guid.NewGuid().ToString());\n    private static readonly GrainId Id_E = GrainId.Create(\"E\", Guid.NewGuid().ToString());\n    private static readonly GrainId Id_F = GrainId.Create(\"F\", Guid.NewGuid().ToString());\n\n    [Fact]\n    public void Add_ShouldIncrementCounter_WhenEdgeIsAdded()\n    {\n        var sink = new FrequentEdgeCounter(capacity: 10);\n        var edge = new Edge(new(Id_A, SiloAddress.Zero, true), new(Id_B, SiloAddress.Zero, true));\n\n        sink.Add(edge);\n\n        var counters = sink.Elements.ToList();\n\n        Assert.Single(counters);\n        Assert.Equal(1u, counters[0].Count);\n        Assert.Equal(edge, counters[0].Element);\n    }\n\n    [Fact]\n    public void Add_ShouldUpdateExistingCounter_WhenSameEdgeIsAddedAgain()\n    {\n        var sink = new FrequentEdgeCounter(capacity: 10);\n        var edge = new Edge(new(Id_A, SiloAddress.Zero, true), new(Id_B, SiloAddress.Zero, true));\n\n        sink.Add(edge);\n        sink.Add(edge);\n\n        var counters = sink.Elements.ToList();\n\n        Assert.Single(counters);\n        Assert.Equal(2u, counters[0].Count);\n        Assert.Equal(edge, counters[0].Element);\n    }\n\n    [Fact]\n    public void Add_ShouldRemoveMinCounter_WhenCapacityIsReached()\n    {\n        var sink = new FrequentEdgeCounter(capacity: 2);\n\n        var edge1 = new Edge(new(Id_A, SiloAddress.Zero, true), new(Id_B, SiloAddress.Zero, true));\n        var edge2 = new Edge(new(Id_C, SiloAddress.Zero, true), new(Id_D, SiloAddress.Zero, true));\n\n        sink.Add(edge1);\n        sink.Add(edge1);\n        sink.Add(edge2);\n\n        Assert.Equal(2, sink.Count);\n\n        var edge3 = new Edge(new(Id_E, SiloAddress.Zero, true), new(Id_F, SiloAddress.Zero, true));\n        sink.Add(edge3);  // should remove the minimum counter (edge2) since capacity is 2\n\n        var counters = sink.Elements.ToList();\n\n        Assert.Equal(2, counters.Count);\n        Assert.DoesNotContain(counters, c => c.Element == edge2);\n    }\n\n    [Fact]\n    public void Remove_ShouldRemoveCounter_WhenEdgeIsRemoved()\n    {\n        var sink = new FrequentEdgeCounter(capacity: 10);\n        var edge = new Edge(new(Id_A, SiloAddress.Zero, true), new(Id_B, SiloAddress.Zero, true));\n\n        sink.Add(edge);\n        sink.Remove(edge);\n\n        Assert.Empty(sink.Elements);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/MaxHeapTests.cs",
    "content": "using Orleans.Runtime.Placement.Repartitioning;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n/// <summary>\n/// Tests for the max heap data structure used in activation repartitioning algorithms.\n/// </summary>\npublic sealed class MaxHeapTests\n{\n    public class MyHeapElement(int value) : IHeapElement<MyHeapElement>\n    {\n        public int Value { get; set; } = value;\n\n        public int HeapIndex { get; set; } = -1;\n\n        public int CompareTo(MyHeapElement other) => Value.CompareTo(other.Value);\n        public override string ToString() => $\"{Value} @ {HeapIndex}\";\n    }\n\n    [Fact]\n    public void HeapPropertyIsMaintained()\n    {\n        var edges = new MyHeapElement[100];\n        for (int i = 0; i < edges.Length; i++)\n        {\n            edges[i] = new MyHeapElement(i);\n        }\n\n        Random.Shared.Shuffle(edges);\n        var heap = new MaxHeap<MyHeapElement>([.. edges]);\n        Assert.Equal(100, heap.Count);\n        Assert.Equal(99, heap.Peek().Value);\n        Assert.Equal(99, heap.Peek().Value);\n        Assert.Equal(99, heap.Pop().Value);\n        Assert.Equal(98, heap.Pop().Value);\n        Assert.Equal(98, heap.Count);\n        Assert.Equal(98, heap.UnorderedElements.Count());\n\n        var unorderedElements = heap.UnorderedElements.ToArray();\n        var edge = unorderedElements[Random.Shared.Next(unorderedElements.Length)];\n        edge.Value = 2000;\n        heap.OnIncreaseElementPriority(edge);\n        Assert.Equal(2000, heap.Peek().Value);\n\n        // Randomly re-assign priorities to edges\n        var newScore = 100;\n        var elements = heap.UnorderedElements.ToArray();\n        Random.Shared.Shuffle(elements);\n        foreach (var element in elements)\n        {\n            var originalValue = element.Value;\n            element.Value = newScore--;\n            if (element.Value > originalValue)\n            {\n                heap.OnIncreaseElementPriority(element);\n            }\n            else\n            {\n                heap.OnDecreaseElementPriority(element);\n            }\n        }\n\n        Assert.Equal(98, heap.UnorderedElements.Count());\n        var allElements = new List<MyHeapElement>();\n        while (heap.Count > 0)\n        {\n            allElements.Add(heap.Pop());\n        }\n\n        Assert.Equal(98, allElements.Count);\n\n        var copy = allElements.ToList();\n        copy.Sort((a, b) => b.Value.CompareTo(a.Value));\n        var expected = string.Join(\", \", Enumerable.Range(0, 98).Select(i => 100 - i));\n        var actual = string.Join(\", \", allElements.Select(c => c.Value));\n        Assert.Equal(expected, actual);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/OptionsTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Configuration;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n/// <summary>\n/// Tests for activation repartitioner configuration options validation.\n/// </summary>\n[TestCategory(\"Functional\"), TestCategory(\"ActivationRepartitioning\")]\npublic class OptionsTests\n{\n    [Fact]\n    public void ConstantsShouldNotChange()\n    {\n        Assert.True(ActivationRepartitionerOptions.DEFAULT_ANCHORING_FILTER_ENABLED);\n        Assert.Equal(0.01d, ActivationRepartitionerOptions.DEFAULT_PROBABILISTIC_FILTERING_MAX_ALLOWED_ERROR);\n        Assert.Equal(10_000, ActivationRepartitionerOptions.DEFAULT_MAX_EDGE_COUNT);\n        Assert.Equal(TimeSpan.FromMinutes(1), ActivationRepartitionerOptions.DEFAULT_MINUMUM_ROUND_PERIOD);\n        Assert.Equal(TimeSpan.FromMinutes(2), ActivationRepartitionerOptions.DEFAULT_MAXIMUM_ROUND_PERIOD);\n        Assert.Equal(TimeSpan.FromMinutes(1), ActivationRepartitionerOptions.DEFAULT_RECOVERY_PERIOD);\n    }\n\n    [Theory]\n    [InlineData(0, 1, 1, 1, 1, 0.01d)]\n    [InlineData(1, 0, 1, 1, 1, 0.01d)]\n    [InlineData(1, 1, 0, 1, 1, 0.01d)]\n    [InlineData(1, 1, 1, 0, 1, 0.01d)]\n    [InlineData(1, 1, 1, 1, -1, 0.01d)]\n    [InlineData(1, 1, 2, 1, 1, 0.01d)]\n    [InlineData(1, 1, 2, 1, 2, 0.01d)]\n    [InlineData(1, 1, 2, 1, 2, 0.1d)]\n    public void InvalidOptionsShouldThrow(\n        int topHeaviestCommunicationLinks,\n        int maxUnprocessedEdges,\n        int minRebalancingPeriodMinutes,\n        int maxRebalancingPeriodMinutes,\n        int recoveryPeriodMinutes,\n        double probabilisticFilteringMaxAllowedErrorRate)\n    {\n        var options = new ActivationRepartitionerOptions\n        {\n            MaxEdgeCount = topHeaviestCommunicationLinks,\n            MinRoundPeriod = TimeSpan.FromMinutes(minRebalancingPeriodMinutes),\n            MaxRoundPeriod = TimeSpan.FromMinutes(maxRebalancingPeriodMinutes),\n            RecoveryPeriod = TimeSpan.FromMinutes(recoveryPeriodMinutes),\n            MaxUnprocessedEdges = maxUnprocessedEdges,\n            ProbabilisticFilteringMaxAllowedErrorRate = probabilisticFilteringMaxAllowedErrorRate\n        };\n\n        var validator = new ActivationRepartitionerOptionsValidator(Options.Create(options));\n        Assert.Throws<OrleansConfigurationException>(validator.ValidateConfiguration);\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/RepartitioningTestBase.cs",
    "content": "using Orleans.Placement.Repartitioning;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\npublic abstract class RepartitioningTestBase<TFixture> : IAsyncLifetime where TFixture : BaseTestClusterFixture, new()\n{\n    private readonly TFixture _fixture;\n\n    internal IInternalGrainFactory GrainFactory => _fixture.HostedCluster.InternalGrainFactory;\n    internal IActivationRepartitionerSystemTarget Silo1Repartitioner { get; }\n    internal IActivationRepartitionerSystemTarget Silo2Repartitioner { get; }\n    protected SiloAddress Silo1 { get; }\n    protected SiloAddress Silo2 { get; }\n\n    public RepartitioningTestBase(TFixture fixture)\n    {\n        _fixture = fixture;\n\n        var silos = _fixture.HostedCluster.GetActiveSilos().Select(h => h.SiloAddress).OrderBy(s => s).ToArray();\n        Silo1 = silos[0];\n        Silo2 = silos[1];\n\n        Silo1Repartitioner = IActivationRepartitionerSystemTarget.GetReference(GrainFactory, Silo1);\n        Silo2Repartitioner = IActivationRepartitionerSystemTarget.GetReference(GrainFactory, Silo2);\n    }\n\n    public virtual async Task InitializeAsync()\n    {\n        await GrainFactory.GetGrain<IManagementGrain>(0).ForceActivationCollection(TimeSpan.FromSeconds(0));\n        await ResetCounters();\n        await AdjustActivationCountOffsets();\n    }\n\n    public virtual Task DisposeAsync()\n    {\n        return Task.CompletedTask;\n    }\n\n    public async ValueTask ResetCounters()\n    {\n        await Silo1Repartitioner.ResetCounters();\n        await Silo2Repartitioner.ResetCounters();\n    }\n\n    public async Task AdjustActivationCountOffsets()\n    {\n        // Account for imbalances in the initial activation counts.\n        Dictionary<SiloAddress, int> counts = [];\n        int max = 0;\n        foreach (var silo in (IEnumerable<SiloHandle>)_fixture.HostedCluster.Silos)\n        {\n            var sysTarget = GrainFactory.GetSystemTarget<IActivationRepartitionerSystemTarget>(Constants.ActivationRepartitionerType, silo.SiloAddress);\n            var count = counts[silo.SiloAddress] = await sysTarget.GetActivationCount();\n            max = Math.Max(max, count);\n        }\n\n        foreach (var silo in (IEnumerable<SiloHandle>)_fixture.HostedCluster.Silos)\n        {\n            var sysTarget = GrainFactory.GetSystemTarget<IActivationRepartitionerSystemTarget>(Constants.ActivationRepartitionerType, silo.SiloAddress);\n            var myCount = counts[silo.SiloAddress];\n            await sysTarget.SetActivationCountOffset(max - myCount);\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/ActivationRepartitioningTests/TestMessageFilter.cs",
    "content": "using Orleans.Runtime.Placement;\nusing Orleans.Runtime.Placement.Repartitioning;\n\nnamespace UnitTests.ActivationRepartitioningTests;\n\n/// <summary>\n/// Ignores client messages to make testing easier\n/// </summary>\ninternal sealed class TestMessageFilter(GrainMigratabilityChecker checker) : IRepartitionerMessageFilter\n{\n    private readonly RepartitionerMessageFilter _messageFilter = new(checker);\n\n    public bool IsAcceptable(Message message, out bool isSenderMigratable, out bool isTargetMigratable) =>\n        _messageFilter.IsAcceptable(message, out isSenderMigratable, out isTargetMigratable) &&\n        !message.SendingGrain.IsClient() && !message.TargetGrain.IsClient();\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/General/ElasticPlacementTest.cs",
    "content": "using System.Net;\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    [TestCategory(\"Elasticity\"), TestCategory(\"Placement\")]\n    public class ElasticPlacementTests : TestClusterPerTest\n    {\n        private readonly List<IActivationCountBasedPlacementTestGrain> grains = new List<IActivationCountBasedPlacementTestGrain>();\n        private const int leavy = 300;\n        private const int perSilo = 1000;\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddMemoryGrainStorageAsDefault()\n                    .Configure<LoadSheddingOptions>(options => options.LoadSheddingEnabled = true);\n            }\n        }\n\n        /// <summary>\n        /// Test placement behaviour for newly added silos. The grain placement strategy should favor them\n        /// until they reach a similar load as the other silos.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4008\"), TestCategory(\"Functional\")]\n        public async Task ElasticityTest_CatchingUp()\n        {\n\n            logger.LogInformation(\"\\n\\n\\n----- Phase 1 -----\\n\\n\");\n            AddTestGrains(perSilo).Wait();\n            AddTestGrains(perSilo).Wait();\n\n            var activationCounts = await GetPerSiloActivationCounts();\n            LogCounts(activationCounts);\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            AssertIsInRange(activationCounts[this.HostedCluster.Primary], perSilo, leavy);\n            AssertIsInRange(activationCounts[this.HostedCluster.SecondarySilos.First()], perSilo, leavy);\n\n            SiloHandle silo3 = this.HostedCluster.StartAdditionalSilo();\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            logger.LogInformation(\"\\n\\n\\n----- Phase 2 -----\\n\\n\");\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            activationCounts = await GetPerSiloActivationCounts();\n            LogCounts(activationCounts);\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            double expected = (6.0 * perSilo) / 3.0;\n            AssertIsInRange(activationCounts[this.HostedCluster.Primary], expected, leavy);\n            AssertIsInRange(activationCounts[this.HostedCluster.SecondarySilos.First()], expected, leavy);\n            AssertIsInRange(activationCounts[silo3], expected, leavy);\n\n            logger.LogInformation(\"\\n\\n\\n----- Phase 3 -----\\n\\n\");\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            activationCounts = await GetPerSiloActivationCounts();\n            LogCounts(activationCounts);\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            expected = (9.0 * perSilo) / 3.0;\n            AssertIsInRange(activationCounts[this.HostedCluster.Primary], expected, leavy);\n            AssertIsInRange(activationCounts[this.HostedCluster.SecondarySilos.First()], expected, leavy);\n            AssertIsInRange(activationCounts[silo3], expected, leavy);\n\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            logger.LogInformation(\"Test finished OK. Expected per silo = {Expected}\", expected);\n        }\n\n        /// <summary>\n        /// This evaluates the how the placement strategy behaves once silos are stopped: The strategy should\n        /// balance the activations from the stopped silo evenly among the remaining silos.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4008\"), TestCategory(\"Functional\")]\n        public async Task ElasticityTest_StoppingSilos()\n        {\n            List<SiloHandle> runtimes = await this.HostedCluster.StartAdditionalSilosAsync(2);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            int stopLeavy = leavy;\n\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n            await AddTestGrains(perSilo);\n\n            var activationCounts = await GetPerSiloActivationCounts();\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            LogCounts(activationCounts);\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            AssertIsInRange(activationCounts[this.HostedCluster.Primary], perSilo, stopLeavy);\n            AssertIsInRange(activationCounts[this.HostedCluster.SecondarySilos.First()], perSilo, stopLeavy);\n            AssertIsInRange(activationCounts[runtimes[0]], perSilo, stopLeavy);\n            AssertIsInRange(activationCounts[runtimes[1]], perSilo, stopLeavy);\n\n            await this.HostedCluster.StopSiloAsync(runtimes[0]);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            await InvokeAllGrains();\n\n            activationCounts = await GetPerSiloActivationCounts();\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            LogCounts(activationCounts);\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            double expected = perSilo * 1.33;\n            AssertIsInRange(activationCounts[this.HostedCluster.Primary], expected, stopLeavy);\n            AssertIsInRange(activationCounts[this.HostedCluster.SecondarySilos.First()], expected, stopLeavy);\n            AssertIsInRange(activationCounts[runtimes[1]], expected, stopLeavy);\n\n            logger.LogInformation(\"-----------------------------------------------------------------\");\n            logger.LogInformation(\"Test finished OK. Expected per silo = {Expected}\", expected);\n        }\n\n        /// <summary>\n        /// Do not place activation in case all silos are at 100 CPU utilization.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4008\"), TestCategory(\"Functional\")]\n        public async Task ElasticityTest_AllSilosCPUTooHigh()\n        {\n            var taintedGrainPrimary = await GetGrainAtSilo(this.HostedCluster.Primary.SiloAddress);\n            var taintedGrainSecondary = await GetGrainAtSilo(this.HostedCluster.SecondarySilos.First().SiloAddress);\n\n            await taintedGrainPrimary.EnableOverloadDetection(false);\n            await taintedGrainSecondary.EnableOverloadDetection(false);\n\n            await taintedGrainPrimary.LatchCpuUsage(100.0f);\n            await taintedGrainSecondary.LatchCpuUsage(100.0f);\n\n            await Assert.ThrowsAsync<OrleansException>(() =>\n                this.AddTestGrains(1));\n        }\n\n        /// <summary>\n        /// Do not place activation in case all silos are at 100 CPU utilization or have overloaded flag set.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4008\"), TestCategory(\"Functional\")]\n        public async Task ElasticityTest_AllSilosOverloaded()\n        {\n            var taintedGrainPrimary = await GetGrainAtSilo(this.HostedCluster.Primary.SiloAddress);\n            var taintedGrainSecondary = await GetGrainAtSilo(this.HostedCluster.SecondarySilos.First().SiloAddress);\n\n            await taintedGrainPrimary.LatchCpuUsage(100.0f);\n            await taintedGrainSecondary.LatchOverloaded();\n\n            // OrleansException or GateWayTooBusyException\n            var exception = await Assert.ThrowsAnyAsync<Exception>(() =>\n                this.AddTestGrains(1));\n\n            Assert.True(exception is OrleansException || exception is GatewayTooBusyException);\n        }\n\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task LoadAwareGrainShouldNotAttemptToCreateActivationsOnOverloadedSilo()\n        {\n            await ElasticityGrainPlacementTest(\n                g =>\n                    g.LatchOverloaded(),\n                g =>\n                    g.UnlatchOverloaded(),\n                \"LoadAwareGrainShouldNotAttemptToCreateActivationsOnOverloadedSilo\",\n                \"A grain instantiated with the load-aware placement strategy should not attempt to create activations on an overloaded silo.\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task LoadAwareGrainShouldNotAttemptToCreateActivationsOnBusySilos()\n        {\n            // a CPU usage of 100% will disqualify a silo from getting new grains.\n            await ElasticityGrainPlacementTest(\n                g =>\n                    g.LatchCpuUsage(100.0f),\n                g =>\n                    g.UnlatchCpuUsage(),\n                \"LoadAwareGrainShouldNotAttemptToCreateActivationsOnBusySilos\",\n                \"A grain instantiated with the load-aware placement strategy should not attempt to create activations on a busy silo.\");\n        }\n\n\n        private async Task<IPlacementTestGrain> GetGrainAtSilo(SiloAddress silo)\n        {\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, silo);\n                IPlacementTestGrain grain = this.GrainFactory.GetGrain<IRandomPlacementTestGrain>(Guid.NewGuid());\n                SiloAddress address = await grain.GetLocation();\n                if (address.Equals(silo))\n                    return grain;\n            }\n        }\n\n        private static void AssertIsInRange(int actual, double expected, int leavy)\n        {\n            Assert.True(expected - leavy <= actual && actual <= expected + leavy,\n                string.Format(\"Expecting a value in the range between {0} and {1}, but instead got {2} outside the range.\",\n                    expected - leavy, expected + leavy, actual));\n        }\n\n\n        private async Task ElasticityGrainPlacementTest(\n            Func<IPlacementTestGrain, Task> taint,\n            Func<IPlacementTestGrain, Task> restore,\n            string name,\n            string assertMsg)\n        {\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            logger.LogInformation(\"********************** Starting the test {Name} ******************************\", name);\n            var taintedSilo = this.HostedCluster.StartAdditionalSilo();\n\n            const long sampleSize = 10;\n\n            var taintedGrain = await GetGrainAtSilo(taintedSilo.SiloAddress);\n\n            var testGrains =\n                Enumerable.Range(0, (int)sampleSize).\n                Select(\n                    n =>\n                        this.GrainFactory.GetGrain<IActivationCountBasedPlacementTestGrain>(Guid.NewGuid()));\n\n            // make the grain's silo undesirable for new grains.\n            taint(taintedGrain).Wait();\n            List<IPEndPoint> actual;\n            try\n            {\n                actual =\n                    testGrains.Select(\n                        g =>\n                            g.GetEndpoint().Result).ToList();\n            }\n            finally\n            {\n                // i don't know if this necessary but to be safe, i'll restore the silo's desirability.\n                logger.LogInformation(\"********************** Finalizing the test {Name} ******************************\", name);\n                restore(taintedGrain).Wait();\n            }\n\n            var unexpected = taintedSilo.SiloAddress.Endpoint;\n            Assert.True(\n                actual.All(\n                    i =>\n                        !i.Equals(unexpected)),\n                assertMsg);\n        }\n\n        private Task AddTestGrains(int amount)\n        {\n            var promises = new List<Task>();\n            for (var i = 0; i < amount; i++)\n            {\n                IActivationCountBasedPlacementTestGrain grain = this.GrainFactory.GetGrain<IActivationCountBasedPlacementTestGrain>(Guid.NewGuid());\n                this.grains.Add(grain);\n                // Make sure we activate grain:\n                promises.Add(grain.Nop());\n            }\n            return Task.WhenAll(promises);\n        }\n\n        private Task InvokeAllGrains()\n        {\n            var promises = new List<Task>();\n            foreach (var grain in grains)\n            {\n                promises.Add(grain.Nop());\n            }\n            return Task.WhenAll(promises);\n        }\n\n        private async Task<Dictionary<SiloHandle, int>> GetPerSiloActivationCounts()\n        {\n            string fullTypeName = \"UnitTests.Grains.ActivationCountBasedPlacementTestGrain\";\n\n            IManagementGrain mgmtGrain = this.GrainFactory.GetGrain<IManagementGrain>(0);\n            SimpleGrainStatistic[] stats = await mgmtGrain.GetSimpleGrainStatistics();\n\n            return this.HostedCluster.GetActiveSilos()\n                .ToDictionary(\n                    s => s,\n                    s => stats\n                        .Where(stat => stat.SiloAddress.Equals(s.SiloAddress) && stat.GrainType == fullTypeName)\n                        .Select(stat => stat.ActivationCount).SingleOrDefault());\n        }\n\n        private void LogCounts(Dictionary<SiloHandle, int> activationCounts)\n        {\n            var sb = new StringBuilder();\n            foreach (var silo in this.HostedCluster.GetActiveSilos())\n            {\n                int count;\n                activationCounts.TryGetValue(silo, out count);\n                sb.AppendLine($\"{silo.Name}.ActivationCount = {count}\");\n            }\n            logger.LogInformation(\"{Message}\", sb.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/General/GrainPlacementClusterChangeTests.cs",
    "content": "﻿using System.Net;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for grain placement behavior when cluster topology changes.\n    /// </summary>\n    public sealed class GrainPlacementClusterChangeTests(ITestOutputHelper output) : TestClusterPerTest\n    {\n        [Theory]\n        [InlineData(\"Primary\")]\n        [InlineData(\"Secondary\")]\n        [TestCategory(\"BVT\"), TestCategory(\"Placement\")]\n        public async Task PreferLocalPlacementGrain_ShouldMigrateWhenHostSiloKilled(string value)\n        {\n            foreach (SiloHandle silo in HostedCluster.GetActiveSilos())\n            {\n                output.WriteLine(\n                    \"Silo {0} : Address = {1} Proxy gateway: {2}\",\n                    silo.Name, silo.SiloAddress, silo.GatewayAddress);\n            }\n\n            IPEndPoint targetSilo;\n            if (value == \"Primary\")\n            {\n                targetSilo = HostedCluster.Primary.SiloAddress.Endpoint;\n            }\n            else\n            {\n                targetSilo = HostedCluster.SecondarySilos.First().SiloAddress.Endpoint;\n            }\n\n            Guid proxyKey;\n            IRandomPlacementTestGrain proxy;\n            IPEndPoint expected;\n            do\n            {\n                proxyKey = Guid.NewGuid();\n                proxy = GrainFactory.GetGrain<IRandomPlacementTestGrain>(proxyKey);\n                expected = await proxy.GetEndpoint();\n            } while (!targetSilo.Equals(expected));\n            output.WriteLine(\"Proxy grain was originally located on silo {0}\", expected);\n\n            Guid grainKey = proxyKey;\n            await proxy.StartPreferLocalGrain(grainKey);\n            IPreferLocalPlacementTestGrain grain = GrainFactory.GetGrain<IPreferLocalPlacementTestGrain>(grainKey);\n            IPEndPoint actual = await grain.GetEndpoint();\n            output.WriteLine(\"PreferLocalPlacement grain was originally located on silo {0}\", actual);\n            Assert.Equal(expected, actual);  // \"PreferLocalPlacement strategy should create activations on the local silo.\"\n\n            SiloHandle siloToKill = HostedCluster.GetActiveSilos().First(s => s.SiloAddress.Endpoint.Equals(expected));\n            output.WriteLine(\"Killing silo {0} hosting locally placed grain\", siloToKill);\n            await HostedCluster.StopSiloAsync(siloToKill);\n\n            IPEndPoint newActual = await grain.GetEndpoint();\n            output.WriteLine(\"PreferLocalPlacement grain was recreated on silo {0}\", newActual);\n            Assert.NotEqual(expected, newActual);  // \"PreferLocalPlacement strategy should recreate activations on other silo if local fails.\"\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/General/GrainPlacementTests.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for various grain placement strategies including random, prefer local, and stateless worker placement.\n    /// </summary>\n    public class GrainPlacementTests(DefaultClusterFixture fixture) : IClassFixture<DefaultClusterFixture>\n    {\n        private readonly DefaultClusterFixture _fixture = fixture;\n\n        [Fact, TestCategory(\"Placement\"), TestCategory(\"Functional\")]\n        public async Task VerifyDefaultPlacement()\n        {\n            var actual = await _fixture.GrainFactory.GetGrain<IDefaultPlacementGrain>(Random.Shared.Next()).GetDefaultPlacement();\n            Assert.IsType<ResourceOptimizedPlacement>(actual);\n        }\n\n        [Fact, TestCategory(\"Placement\"), TestCategory(\"Functional\")]\n        public async Task RandomlyPlacedGrainShouldPlaceActivationsRandomly()\n        {\n            var grains =\n                Enumerable.Range(0, 20).\n                Select(\n                    n =>\n                        _fixture.GrainFactory.GetGrain<IRandomPlacementTestGrain>(Guid.NewGuid()));\n            List<string> places = new();\n            foreach (var grain in grains)\n            {\n                places.Add(await grain.GetRuntimeInstanceId());\n            }\n\n            // consider: it seems like we should check that we get close to a 50/50 split for placement.\n            var groups = places.GroupBy(s => s);\n            Assert.True(groups.Count() > 1,\n                \"Grains should be on different silos, but they are on \" + Utils.EnumerableToString(places)); // will randomly fail one in a million times if RNG is good :-)\n        }\n\n        //[Fact, TestCategory(\"Placement\"), TestCategory(\"Functional\")]\n        //public void PreferLocalPlacedGrainShouldPlaceActivationsLocally_OneHop()\n        //{\n        //    HostedCluster.WaitForLivenessToStabilize();\n        //    logger.Info(\"********************** Starting the test PreferLocalPlacedGrainShouldPlaceActivationsLocally ******************************\");\n        //    TestSilosStarted(2);\n\n        //    int numGrains = 20;\n        //    var preferLocalGrain =\n        //        Enumerable.Range(0, numGrains).\n        //            Select(\n        //                n =>\n        //                    PreferLocalPlacementTestGrainFactory.GetGrain((long)n)).ToList();\n        //    var preferLocalGrainPlaces = preferLocalGrain.Select(g => g.GetRuntimeInstanceId().Result).ToList();\n\n        //    // check that every \"prefer local grain\" was placed on the same silo with its requesting random grain\n        //    foreach (int key in Enumerable.Range(0, numGrains))\n        //    {\n        //        string preferLocal = preferLocalGrainPlaces.ElementAt(key);\n        //        logger.Info(preferLocal);\n        //    }\n        //}\n\n        [Fact, TestCategory(\"Placement\"), TestCategory(\"Functional\")]\n        public async Task PreferLocalPlacedGrainShouldPlaceActivationsLocally_TwoHops()\n        {\n            int numGrains = 20;\n            var randomGrains =\n                Enumerable.Range(0, numGrains).\n                    Select(\n                        n =>\n                            _fixture.GrainFactory.GetGrain<IRandomPlacementTestGrain>(Guid.NewGuid())).ToList();\n            var randomGrainPlaces = new List<string>();\n            foreach (var grain in randomGrains)\n            {\n                randomGrainPlaces.Add(await grain.GetRuntimeInstanceId());\n            }\n\n            var preferLocalGrainKeys = new List<Guid>();\n            foreach (var grain in randomGrains)\n            {\n                preferLocalGrainKeys.Add(await grain.StartPreferLocalGrain(grain.GetPrimaryKey()));\n            }\n\n            var preferLocalGrainPlaces = new List<string>();\n            foreach (var key in preferLocalGrainKeys)\n            {\n                preferLocalGrainPlaces.Add(await _fixture.GrainFactory.GetGrain<IPreferLocalPlacementTestGrain>(key).GetRuntimeInstanceId());\n            }\n\n            // check that every \"prefer local grain\" was placed on the same silo with its requesting random grain\n            foreach(int key in Enumerable.Range(0, numGrains))\n            {\n                string random = randomGrainPlaces.ElementAt(key);\n                string preferLocal = preferLocalGrainPlaces.ElementAt(key);\n                Assert.Equal(random, preferLocal);  //\"Grains should be on the same silos, but they are on \" + random + \" and \" + preferLocal\n            }\n        }\n\n        private static async Task<List<string>> CollectActivationIds(IPlacementTestGrain grain, int sampleSize)\n        {\n            var tasks = new List<Task<string>>(sampleSize);\n            for (var i = 0; i < sampleSize; ++i)\n            {\n                tasks.Add(grain.GetActivationId());\n            }\n\n            await Task.WhenAll(tasks);\n            return tasks.Select(t => t.Result).ToList();\n        }\n\n        private static async Task<int> ActivationCount(IPlacementTestGrain grain, int sampleSize)\n        {\n            var activations = await CollectActivationIds(grain, sampleSize);\n            return activations.Distinct().Count();\n        }\n\n        [Fact, TestCategory(\"Placement\"), TestCategory(\"BVT\")]\n        public async Task StatelessWorkerShouldCreateSpecifiedActivationCount()\n        {\n            {\n                // note: this amount should agree with both the specified minimum and maximum in the StatelessWorkerPlacement attribute\n                // associated with ILocalPlacementTestGrain.\n                const int expected = 1;\n                var grain = _fixture.GrainFactory.GetGrain<IStatelessWorkerPlacementTestGrain>(Guid.NewGuid());\n                int actual = await ActivationCount(grain, expected * 50);\n                Assert.True(actual <= expected, $\"Created more activations than the specified limit: {actual} > {expected}.\");\n            }\n\n            {\n                const int expected = 2;\n                var grain = _fixture.GrainFactory.GetGrain<IOtherStatelessWorkerPlacementTestGrain>(Guid.NewGuid());\n                int actual = await ActivationCount(grain, expected * 50);\n                Assert.True(actual <= expected, $\"Created more activations than the specified limit: {actual} > {expected}.\");\n\n            }\n        }\n\n        [Fact, TestCategory(\"Placement\"), TestCategory(\"Functional\")]\n        public async Task StatelessWorkerGrainShouldCreateActivationsOnLocalSilo()\n        {\n            const int sampleSize = 5;\n            var placement = new StatelessWorkerPlacement(sampleSize);\n            var proxy = _fixture.GrainFactory.GetGrain<IRandomPlacementTestGrain>(Guid.NewGuid());\n            await proxy.StartLocalGrains(new List<Guid> { Guid.Empty });\n            var expected = await proxy.GetEndpoint();\n            // locally placed grains are multi-activation and stateless. this means that we have to sample the value of\n            // the result, rather than simply ask for it once in order to get a consensus of the result.\n            var actual = await proxy.SampleLocalGrainEndpoint(Guid.Empty, sampleSize);\n            Assert.True(actual.All(expected.Equals),\n                \"A grain instantiated with the local placement strategy should create activations on the local silo.\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/General/LoadSheddingTest.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Messaging;\nusing Orleans.Runtime.TestHooks;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for load shedding functionality when the gateway is overloaded.\n    /// </summary>\n    // if we parallelize tests, each test should run in isolation \n    public class LoadSheddingTest : OrleansTestingBase, IClassFixture<LoadSheddingTest.Fixture>\n    {\n        private readonly Fixture fixture;\n        private readonly TestHooksEnvironmentStatisticsProvider _environmentStatistics;\n        private readonly OverloadDetector _overloadDetector;\n        private const int CpuThreshold = 98;\n\n        public class Fixture : BaseInProcessTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.ConfigureSilo((options, hostBuilder) =>\n                hostBuilder.AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddMemoryGrainStorageAsDefault()\n                    .Configure<LoadSheddingOptions>(options =>\n                    {\n                        options.LoadSheddingEnabled = true;\n                        options.CpuThreshold = CpuThreshold;\n                    }));\n            }\n        }\n\n        public LoadSheddingTest(Fixture fixture)\n        {\n            this.fixture = fixture;\n            _environmentStatistics = fixture.HostedCluster.Silos[0].ServiceProvider.GetRequiredService<TestHooksEnvironmentStatisticsProvider>();\n            _overloadDetector = fixture.HostedCluster.Silos[0].ServiceProvider.GetRequiredService<OverloadDetector>();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"LoadShedding\")]\n        public async Task LoadSheddingBasic()\n        {\n            try\n            {\n                ISimpleGrain grain = this.fixture.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), SimpleGrain.SimpleGrainNamePrefix);\n                LatchIsOverloaded(true);\n\n                // Do not accept message in overloaded state\n                await Assert.ThrowsAsync<GatewayTooBusyException>(() => grain.SetA(5));\n            }\n            finally\n            {\n                UnlatchIsOverloaded();\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"LoadShedding\")]\n        public async Task LoadSheddingComplex()\n        {\n            try\n            {\n                ISimpleGrain grain = this.fixture.GrainFactory.GetGrain<ISimpleGrain>(Random.Shared.Next(), SimpleGrain.SimpleGrainNamePrefix);\n\n                this.fixture.Logger.LogInformation(\"Acquired grain reference\");\n\n                LatchIsOverloaded(false);\n\n                await grain.SetA(1);\n                this.fixture.Logger.LogInformation(\"First set succeeded\");\n\n                LatchIsOverloaded(true);\n\n                // Do not accept message in overloaded state\n                await Assert.ThrowsAsync<GatewayTooBusyException>(() => grain.SetA(2));\n\n                this.fixture.Logger.LogInformation(\"Second set was shed\");\n\n                LatchIsOverloaded(false);\n\n                // Simple request after overload is cleared should succeed\n                await grain.SetA(4);\n                this.fixture.Logger.LogInformation(\"Third set succeeded\");\n            }\n            finally\n            {\n                UnlatchIsOverloaded();\n            }\n        }\n\n        private void LatchIsOverloaded(bool isOverloaded)\n        {\n            var cpuUsage = isOverloaded ? CpuThreshold + 1 : CpuThreshold - 1;\n            var previousStats = _environmentStatistics.GetEnvironmentStatistics();\n            _environmentStatistics.LatchHardwareStatistics(new(\n                cpuUsagePercentage: cpuUsage,\n                rawCpuUsagePercentage: cpuUsage,\n                memoryUsageBytes: previousStats.FilteredMemoryUsageBytes,\n                rawMemoryUsageBytes: previousStats.RawMemoryUsageBytes,\n                availableMemoryBytes: previousStats.FilteredAvailableMemoryBytes,\n                rawAvailableMemoryBytes: previousStats.RawAvailableMemoryBytes,\n                maximumAvailableMemoryBytes: previousStats.MaximumAvailableMemoryBytes));\n            _overloadDetector.ForceRefresh();\n        }\n\n        private void UnlatchIsOverloaded()\n        {\n            _environmentStatistics.UnlatchHardwareStatistics();\n            _overloadDetector.ForceRefresh();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/General/ResourceOptimizedPlacementOptionsTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Xunit;\n\nnamespace UnitTests.General;\n\n/// <summary>\n/// Tests for resource optimized placement configuration options validation.\n/// </summary>\npublic sealed class ResourceOptimizedPlacementOptionsTests\n{\n    [Fact, TestCategory(\"PlacementOptions\"), TestCategory(\"BVT\")]\n    public void ConstantsShouldNotChange()\n    {\n        Assert.Equal(40, ResourceOptimizedPlacementOptions.DEFAULT_CPU_USAGE_WEIGHT);\n        Assert.Equal(20, ResourceOptimizedPlacementOptions.DEFAULT_MEMORY_USAGE_WEIGHT);\n        Assert.Equal(20, ResourceOptimizedPlacementOptions.DEFAULT_AVAILABLE_MEMORY_WEIGHT);\n        Assert.Equal(5, ResourceOptimizedPlacementOptions.DEFAULT_MAX_AVAILABLE_MEMORY_WEIGHT);\n        Assert.Equal(15, ResourceOptimizedPlacementOptions.DEFAULT_ACTIVATION_COUNT_WEIGHT);\n    }\n\n    [Fact, TestCategory(\"PlacementOptions\"), TestCategory(\"BVT\")]\n    public void DefaultShouldEqualConstants()\n    {\n        var options = new ResourceOptimizedPlacementOptions();\n        Assert.Equal(ResourceOptimizedPlacementOptions.DEFAULT_CPU_USAGE_WEIGHT, options.CpuUsageWeight);\n        Assert.Equal(ResourceOptimizedPlacementOptions.DEFAULT_MEMORY_USAGE_WEIGHT, options.MemoryUsageWeight);\n        Assert.Equal(ResourceOptimizedPlacementOptions.DEFAULT_AVAILABLE_MEMORY_WEIGHT, options.AvailableMemoryWeight);\n        Assert.Equal(ResourceOptimizedPlacementOptions.DEFAULT_MAX_AVAILABLE_MEMORY_WEIGHT, options.MaxAvailableMemoryWeight);\n        Assert.Equal(ResourceOptimizedPlacementOptions.DEFAULT_ACTIVATION_COUNT_WEIGHT, options.ActivationCountWeight);\n    }\n\n    [Theory, TestCategory(\"PlacementOptions\"), TestCategory(\"BVT\")]\n    [InlineData(-10, 0, 0, 0, 0, 0)]\n    [InlineData(101, 0, 0, 0, 0, 0)]\n    [InlineData(0, -10, 0, 0, 0, 0)]\n    [InlineData(0, 101, 0, 0, 0, 0)]\n    [InlineData(0, 0, -10, 0, 0, 0)]\n    [InlineData(0, 0, 101, 0, 0, 0)]\n    [InlineData(0, 0, 0, -10, 0, 0)]\n    [InlineData(0, 0, 0, 101, 0, 0)]\n    [InlineData(0, 0, 0, 0, -10, 0)]\n    [InlineData(0, 0, 0, 0, 101, 0)]\n    [InlineData(0, 0, 0, 0, 0, -10)]\n    [InlineData(0, 0, 0, 0, 0, 101)]\n    public void InvalidWeightsShouldThrow(int cpuUsage, int memUsage, int memAvailable, int maxMemAvailable, int activationCount, int prefMargin)\n    {\n        var options = Options.Create(new ResourceOptimizedPlacementOptions\n        {\n            CpuUsageWeight = cpuUsage,\n            MemoryUsageWeight = memUsage,\n            AvailableMemoryWeight = memAvailable,\n            MaxAvailableMemoryWeight = maxMemAvailable,\n            LocalSiloPreferenceMargin = prefMargin,\n            ActivationCountWeight = activationCount\n        });\n\n        var validator = new ResourceOptimizedPlacementOptionsValidator(options);\n        Assert.Throws<OrleansConfigurationException>(validator.ValidateConfiguration);\n    }\n\n    [Theory, TestCategory(\"PlacementOptions\"), TestCategory(\"BVT\")]\n    [InlineData(10, 0, 0, 0, 0, 10)]\n    [InlineData(100, 0, 0, 0, 0, 10)]\n    [InlineData(10, 10, 0, 0, 0, 0)]\n    [InlineData(10, 100, 0, 0, 0, 0)]\n    [InlineData(10, 0, 10, 0, 0, 0)]\n    [InlineData(10, 0, 100, 0, 0, 0)]\n    [InlineData(10, 0, 0, 10, 0, 0)]\n    [InlineData(10, 0, 0, 100, 0, 0)]\n    [InlineData(10, 0, 0, 0, 10, 0)]\n    [InlineData(10, 0, 0, 0, 100, 0)]\n    [InlineData(10, 0, 0, 0, 0, 100)]\n    public void ValidWeightsShouldNotThrow(int cpuUsage, int memUsage, int memAvailable, int maxMemAvailable, int activationCount, int prefMargin)\n    {\n        var options = Options.Create(new ResourceOptimizedPlacementOptions\n        {\n            CpuUsageWeight = cpuUsage,\n            MemoryUsageWeight = memUsage,\n            AvailableMemoryWeight = memAvailable,\n            MaxAvailableMemoryWeight = maxMemAvailable,\n            LocalSiloPreferenceMargin = prefMargin,\n            ActivationCountWeight = activationCount\n        });\n\n        var validator = new ResourceOptimizedPlacementOptionsValidator(options);\n        validator.ValidateConfiguration();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/Orleans.Placement.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"CsCheck\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/GrainPlacementFilterTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Placement;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace UnitTests.PlacementFilterTests;\n\n/// <summary>\n/// Tests for grain placement filter registration, ordering, and execution.\n/// </summary>\n[TestCategory(\"Placement\"), TestCategory(\"Filters\")]\npublic class GrainPlacementFilterTests(GrainPlacementFilterTests.Fixture fixture) : IClassFixture<GrainPlacementFilterTests.Fixture>\n{\n    public static Dictionary<string, List<string>> FilterScratchpad = [];\n    private static Random random = new();\n\n    public class Fixture : IAsyncLifetime\n    {\n        public InProcessTestCluster Cluster { get; private set; }\n        public async Task DisposeAsync()\n        {\n            if (Cluster is { } cluster)\n            {\n                await cluster.DisposeAsync();\n            }\n        }\n\n        public async Task InitializeAsync()\n        {\n            var builder = new InProcessTestClusterBuilder(3);\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.Services.AddPlacementFilter<TestPlacementFilterStrategy, TestPlacementFilterDirector>(ServiceLifetime.Singleton);\n                siloBuilder.Services.AddPlacementFilter<OrderAPlacementFilterStrategy, OrderAPlacementFilterDirector>(ServiceLifetime.Singleton);\n                siloBuilder.Services.AddPlacementFilter<OrderBPlacementFilterStrategy, OrderBPlacementFilterDirector>(ServiceLifetime.Singleton);\n            });\n\n            Cluster = builder.Build();\n            await Cluster.DeployAsync();\n            await Cluster.WaitForLivenessToStabilizeAsync();\n        }\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_GrainWithoutFilterCanBeCalled()\n    {\n        var managementGrain = fixture.Cluster.Client.GetGrain<IManagementGrain>(0);\n        var silos = await managementGrain.GetHosts(true);\n        Assert.NotNull(silos);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_FilterIsTriggered()\n    {\n        var triggered = false;\n        var task = Task.Run(async () =>\n        {\n            triggered = await TestPlacementFilterDirector.Triggered.WaitAsync(TimeSpan.FromSeconds(1));\n        });\n        var localOnlyGrain = fixture.Cluster.Client.GetGrain<ITestFilteredGrain>(0);\n        await localOnlyGrain.Ping();\n        await task;\n        Assert.True(triggered);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_OrderAB12()\n    {\n        var primaryKey = random.Next();\n        var testGrain = fixture.Cluster.Client.GetGrain<ITestAB12FilteredGrain>(primaryKey);\n        await testGrain.Ping();\n        var list = FilterScratchpad.GetValueOrAddNew(testGrain.GetGrainId().Type.ToString());\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"A\", list[0]);\n        Assert.Equal(\"B\", list[1]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_OrderAB21()\n    {\n        var primaryKey = random.Next();\n        var testGrain = fixture.Cluster.Client.GetGrain<ITestAB21FilteredGrain>(primaryKey);\n        await testGrain.Ping();\n        var list = FilterScratchpad.GetValueOrAddNew(testGrain.GetGrainId().Type.ToString());\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"B\", list[0]);\n        Assert.Equal(\"A\", list[1]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_OrderBA12()\n    {\n        var primaryKey = random.Next();\n        var testGrain = fixture.Cluster.Client.GetGrain<ITestBA12FilteredGrain>(primaryKey);\n        await testGrain.Ping();\n        var list = FilterScratchpad.GetValueOrAddNew(testGrain.GetGrainId().Type.ToString());\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"B\", list[0]);\n        Assert.Equal(\"A\", list[1]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_OrderBA21()\n    {\n        var primaryKey = random.Next();\n        var testGrain = fixture.Cluster.Client.GetGrain<ITestBA21FilteredGrain>(primaryKey);\n        await testGrain.Ping();\n\n        var list = FilterScratchpad.GetValueOrAddNew(testGrain.GetGrainId().Type.ToString());\n        Assert.Equal(2, list.Count);\n        Assert.Equal(\"A\", list[0]);\n        Assert.Equal(\"B\", list[1]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_DuplicateOrder()\n    {\n        var primaryKey = random.Next();\n        var testGrain = fixture.Cluster.Client.GetGrain<ITestDuplicateOrderFilteredGrain>(primaryKey);\n        await Assert.ThrowsAsync<InvalidOperationException>(async () =>\n        {\n            await testGrain.Ping();\n        }); \n    }\n}\n\n[TestPlacementFilter(order: 1)]\npublic class TestFilteredGrain : Grain, ITestFilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestFilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n\npublic class TestPlacementFilterAttribute(int order) : PlacementFilterAttribute(new TestPlacementFilterStrategy(order));\n\npublic class TestPlacementFilterStrategy(int order) : PlacementFilterStrategy(order)\n{\n    public TestPlacementFilterStrategy() : this(0)\n    {\n    }\n}\n\npublic class TestPlacementFilterDirector() : IPlacementFilterDirector\n{\n    public static SemaphoreSlim Triggered { get; } = new(0);\n\n    public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n    {\n        Triggered.Release(1);\n        return silos;\n    }\n}\n\n\n\npublic class OrderAPlacementFilterAttribute(int order) : PlacementFilterAttribute(new OrderAPlacementFilterStrategy(order));\n\npublic class OrderAPlacementFilterStrategy(int order) : PlacementFilterStrategy(order)\n{\n    public OrderAPlacementFilterStrategy() : this(0)\n    {\n    }\n}\n\npublic class OrderAPlacementFilterDirector : IPlacementFilterDirector\n{\n    public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n    {\n        var dict = GrainPlacementFilterTests.FilterScratchpad;\n        var list = dict.GetValueOrAddNew(target.GrainIdentity.Type.ToString());\n        list.Add(\"A\");\n        return silos;\n    }\n}\n\n\npublic class OrderBPlacementFilterAttribute(int order) : PlacementFilterAttribute(new OrderBPlacementFilterStrategy(order));\n\npublic class OrderBPlacementFilterStrategy(int order) : PlacementFilterStrategy(order)\n{\n\n    public OrderBPlacementFilterStrategy() : this(0)\n    {\n    }\n}\n\npublic class OrderBPlacementFilterDirector() : IPlacementFilterDirector\n{\n    public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n    {\n        var dict = GrainPlacementFilterTests.FilterScratchpad;\n        var list = dict.GetValueOrAddNew(target.GrainIdentity.Type.ToString());\n        list.Add(\"B\");\n        return silos;\n    }\n}\n\n[OrderAPlacementFilter(order: 1)]\n[OrderBPlacementFilter(order: 2)]\npublic class TestAB12FilteredGrain : Grain, ITestAB12FilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestAB12FilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n\n[OrderAPlacementFilter(order: 2)]\n[OrderBPlacementFilter(order: 1)]\npublic class TestAB21FilteredGrain : Grain, ITestAB21FilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestAB21FilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n\n[OrderBPlacementFilter(order: 1)]\n[OrderAPlacementFilter(order: 2)]\npublic class TestBA12FilteredGrain : Grain, ITestBA12FilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestBA12FilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n\n\n[OrderBPlacementFilter(order: 2)]\n[OrderAPlacementFilter(order: 1)]\npublic class TestBA121FilteredGrain : Grain, ITestBA21FilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestBA21FilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n\n\n\n[OrderBPlacementFilter(order: 2)]\n[OrderAPlacementFilter(order: 2)]\npublic class TestDuplicateOrderFilteredGrain : Grain, ITestDuplicateOrderFilteredGrain\n{\n    public Task Ping() => Task.CompletedTask;\n}\n\npublic interface ITestDuplicateOrderFilteredGrain : IGrainWithIntegerKey\n{\n    Task Ping();\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/PreferredMatchSiloMetadataPlacementFilterDirectorTests.cs",
    "content": "using System.Net;\nusing Orleans.Metadata;\nusing Orleans.Placement;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\nusing Orleans.Runtime.Placement;\nusing Orleans.Runtime.Placement.Filtering;\nusing Xunit;\n\nnamespace UnitTests.PlacementFilterTests;\n\n/// <summary>\n/// Tests for preferred match silo metadata placement filter director behavior.\n/// </summary>\n[TestCategory(\"Placement\"), TestCategory(\"Filters\"), TestCategory(\"SiloMetadata\")]\npublic class PreferredMatchSiloMetadataPlacementFilterDirectorTests\n{\n    [Fact, TestCategory(\"Functional\")]\n    public void CanBeCreated()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var director = new PreferredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                { testLocalSiloAddress, SiloMetadata.Empty }\n            }));\n        Assert.NotNull(director);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void CanBeCalled()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var director = new PreferredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testLocalSiloAddress, SiloMetadata.Empty}\n            }));\n        var result = director.Filter(new PreferredMatchSiloMetadataPlacementFilterStrategy(), default,\n            new List<SiloAddress>() { testLocalSiloAddress }\n        ).ToList();\n        Assert.NotNull(result);\n        Assert.NotEmpty(result);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void FiltersToAllWhenNoEntry()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var siloMetadata = new SiloMetadata();\n        siloMetadata.AddMetadata(\"metadata.key\", \"something\");\n        var director = new PreferredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress, SiloMetadata.Empty},\n                {testLocalSiloAddress, siloMetadata},\n            }));\n        var result = director.Filter(new PreferredMatchSiloMetadataPlacementFilterStrategy([\"metadata.key\"], 1, 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress }).ToList();\n        Assert.NotEmpty(result);\n    }\n\n\n    [Theory, TestCategory(\"Functional\")]\n    [InlineData(1, 3, \"no.match\")]\n    [InlineData(2, 3, \"no.match\")]\n    [InlineData( 1, 1, \"one.match\")]\n    [InlineData( 2, 3, \"one.match\")]\n    [InlineData( 1, 2, \"two.match\")]\n    [InlineData( 2, 2, \"two.match\")]\n    [InlineData( 3, 3, \"two.match\")]\n    [InlineData( 1, 3, \"all.match\")]\n    [InlineData( 2, 3, \"all.match\")]\n\n    public void FiltersOnSingleMetadata(int minCandidates, int expectedCount, string key)\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress1 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var testOtherSiloAddress2 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1002, 1);\n        var testOtherSiloAddress3 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1003, 1);\n        var localSiloMetadata = new SiloMetadata();\n        localSiloMetadata.AddMetadata(\"all.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"one.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"two.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"no.match\", \"match\");\n        var otherSiloMetadata1 = new SiloMetadata();\n        otherSiloMetadata1.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"one.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"two.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"no.match\", \"nomatch\");\n        var otherSiloMetadata2 = new SiloMetadata();\n        otherSiloMetadata2.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata2.AddMetadata(\"one.match\", \"nomatch\");\n        otherSiloMetadata2.AddMetadata(\"two.match\", \"match\");\n        otherSiloMetadata2.AddMetadata(\"no.match\", \"nomatch\");\n        var otherSiloMetadata3 = new SiloMetadata();\n        otherSiloMetadata3.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata3.AddMetadata(\"one.match\", \"nomatch\");\n        otherSiloMetadata3.AddMetadata(\"two.match\", \"nomatch\");\n        otherSiloMetadata3.AddMetadata(\"no.match\", \"nomatch\");\n        var director = new PreferredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress1, otherSiloMetadata1},\n                {testOtherSiloAddress2, otherSiloMetadata2},\n                {testOtherSiloAddress3, otherSiloMetadata3},\n                {testLocalSiloAddress, localSiloMetadata},\n            }));\n        var result = director.Filter(new PreferredMatchSiloMetadataPlacementFilterStrategy([key], minCandidates, 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress1, testOtherSiloAddress2, testOtherSiloAddress3 }).ToList();\n        Assert.NotEmpty(result);\n        Assert.Equal(expectedCount, result.Count);\n    }\n\n    [Theory, TestCategory(\"Functional\")]\n    [InlineData(1, 3, \"no.match\", \"all.match\")]\n    [InlineData(1, 1, \"no.match\", \"one.match\", \"two.match\")]\n    [InlineData(2, 2, \"no.match\", \"one.match\", \"two.match\")]\n    [InlineData(3, 3, \"no.match\", \"one.match\", \"two.match\")]\n    [InlineData(1, 3, \"all.match\", \"no.match\")]\n    [InlineData(1, 1, \"one.match\", \"all.match\")]\n    [InlineData(2, 3, \"one.match\", \"all.match\")]\n    [InlineData(1, 1, \"no.match\", \"one.match\", \"all.match\")]\n    [InlineData(2, 3, \"no.match\", \"one.match\", \"all.match\")]\n\n    public void FiltersOnMultipleMetadata(int minCandidates, int expectedCount, params string[] keys)\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress1 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var testOtherSiloAddress2 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1002, 1);\n        var testOtherSiloAddress3 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1003, 1);\n        var localSiloMetadata = new SiloMetadata();\n        localSiloMetadata.AddMetadata(\"all.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"one.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"two.match\", \"match\");\n        localSiloMetadata.AddMetadata(\"no.match\", \"match\");\n        var otherSiloMetadata1 = new SiloMetadata();\n        otherSiloMetadata1.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"one.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"two.match\", \"match\");\n        otherSiloMetadata1.AddMetadata(\"no.match\", \"not.match\");\n        var otherSiloMetadata2 = new SiloMetadata();\n        otherSiloMetadata2.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata2.AddMetadata(\"one.match\", \"nomatch\");\n        otherSiloMetadata2.AddMetadata(\"two.match\", \"match\");\n        otherSiloMetadata2.AddMetadata(\"no.match\", \"not.match\");\n        var otherSiloMetadata3 = new SiloMetadata();\n        otherSiloMetadata3.AddMetadata(\"all.match\", \"match\");\n        otherSiloMetadata3.AddMetadata(\"one.match\", \"not.match\");\n        otherSiloMetadata3.AddMetadata(\"two.match\", \"not.match\");\n        otherSiloMetadata3.AddMetadata(\"no.match\", \"not.match\");\n        var director = new PreferredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress1, otherSiloMetadata1},\n                {testOtherSiloAddress2, otherSiloMetadata2},\n                {testOtherSiloAddress3, otherSiloMetadata3},\n                {testLocalSiloAddress, localSiloMetadata},\n            }));\n        var result = director.Filter(new PreferredMatchSiloMetadataPlacementFilterStrategy(keys, minCandidates, 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress1, testOtherSiloAddress2, testOtherSiloAddress3 }).ToList();\n        Assert.NotEmpty(result);\n        Assert.Equal(expectedCount, result.Count);\n    }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/RequiredMatchSiloMetadataPlacementFilterDirectorTests.cs",
    "content": "using System.Net;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\nusing Orleans.Runtime.Placement.Filtering;\nusing Xunit;\n\nnamespace UnitTests.PlacementFilterTests;\n\n/// <summary>\n/// Tests for required match silo metadata placement filter director behavior.\n/// </summary>\n[TestCategory(\"Placement\"), TestCategory(\"Filters\"), TestCategory(\"SiloMetadata\")]\npublic class RequiredMatchSiloMetadataPlacementFilterDirectorTests\n{\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_CanBeCreated()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testLocalSiloAddress, SiloMetadata.Empty}\n            }));\n        Assert.NotNull(director);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_CanBeCalled()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testLocalSiloAddress, SiloMetadata.Empty}\n            }));\n        var result = director.Filter(new RequiredMatchSiloMetadataPlacementFilterStrategy(), default,\n            new List<SiloAddress>() { testLocalSiloAddress }\n        ).ToList();\n        Assert.NotNull(result);\n        Assert.NotEmpty(result);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_FiltersToNothingWhenNoEntry()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var siloMetadata = new SiloMetadata();\n        siloMetadata.AddMetadata(\"metadata.key\", \"something\");\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress, SiloMetadata.Empty},\n                {testLocalSiloAddress, siloMetadata},\n            }));\n        var result = director.Filter(new RequiredMatchSiloMetadataPlacementFilterStrategy([\"metadata.key\"], 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress }).ToList();\n        Assert.Empty(result);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_FiltersToNothingWhenDifferentValue()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var localSiloMetadata = new SiloMetadata();\n        localSiloMetadata.AddMetadata(\"metadata.key\", \"local\");\n        var otherSiloMetadata = new SiloMetadata();\n        otherSiloMetadata.AddMetadata(\"metadata.key\", \"other\");\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress, otherSiloMetadata},\n                {testLocalSiloAddress, localSiloMetadata},\n            }));\n        var result = director.Filter(new RequiredMatchSiloMetadataPlacementFilterStrategy([\"metadata.key\"], 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress }).ToList();\n        Assert.Empty(result);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_FiltersToSiloWhenMatching()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var localSiloMetadata = new SiloMetadata();\n        localSiloMetadata.AddMetadata(\"metadata.key\", \"same\");\n        var otherSiloMetadata = new SiloMetadata();\n        otherSiloMetadata.AddMetadata(\"metadata.key\", \"same\");\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress, otherSiloMetadata},\n                {testLocalSiloAddress, localSiloMetadata},\n            }));\n        var result = director.Filter(new RequiredMatchSiloMetadataPlacementFilterStrategy([\"metadata.key\"], 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress }).ToList();\n        Assert.NotEmpty(result);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void RequiredMatchSiloMetadataPlacementFilterDirector_FiltersToMultipleSilosWhenMatching()\n    {\n        var testLocalSiloAddress = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1000, 1);\n        var testOtherSiloAddress1 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1001, 1);\n        var testOtherSiloAddress2 = SiloAddress.New(IPAddress.Parse(\"1.1.1.1\"), 1002, 1);\n        var localSiloMetadata = new SiloMetadata();\n        localSiloMetadata.AddMetadata(\"metadata.key\", \"same\");\n        var otherSiloMetadata1 = new SiloMetadata();\n        otherSiloMetadata1.AddMetadata(\"metadata.key\", \"same\");\n        var otherSiloMetadata2 = new SiloMetadata();\n        otherSiloMetadata2.AddMetadata(\"metadata.key\", \"same\");\n        var director = new RequiredMatchSiloMetadataPlacementFilterDirector(\n            new TestLocalSiloDetails(\"name\", \"clusterId\", \"dnsHostName\",\n                testLocalSiloAddress,\n                testLocalSiloAddress),\n            new TestSiloMetadataCache(new Dictionary<SiloAddress, SiloMetadata>()\n            {\n                {testOtherSiloAddress1, otherSiloMetadata1},\n                {testOtherSiloAddress2, otherSiloMetadata2},\n                {testLocalSiloAddress, localSiloMetadata},\n            }));\n        var result = director.Filter(new RequiredMatchSiloMetadataPlacementFilterStrategy([\"metadata.key\"], 0), default,\n            new List<SiloAddress>() { testOtherSiloAddress1, testOtherSiloAddress2 }).ToList();\n        Assert.NotEmpty(result);\n        Assert.Equal(2, result.Count);\n    }\n\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/SiloMetadataPlacementFilterTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Placement;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\nusing Orleans.Runtime.Placement.Filtering;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace UnitTests.PlacementFilterTests;\n\n[TestCategory(\"Placement\"), TestCategory(\"Filters\"), TestCategory(\"SiloMetadata\")]\npublic class SiloMetadataPlacementFilterTests(SiloMetadataPlacementFilterTests.Fixture fixture) : IClassFixture<SiloMetadataPlacementFilterTests.Fixture>\n{\n    public class Fixture : IAsyncLifetime\n    {\n        public InProcessTestCluster Cluster { get; private set; }\n        public async Task DisposeAsync()\n        {\n            if (Cluster is { } cluster)\n            {\n                await cluster.DisposeAsync();\n            }\n        }\n\n        public async Task InitializeAsync()\n        {\n            var builder = new InProcessTestClusterBuilder(3);\n            builder.ConfigureSilo((options, siloBuilder) => siloBuilder.UseSiloMetadata(new Dictionary<string, string>\n            {\n                {\"first\", \"1\"},\n                {\"second\", \"2\"},\n                {\"third\", \"3\"},\n                {\"unique\", Guid.NewGuid().ToString()}\n            }));\n\n            Cluster = builder.Build();\n            await Cluster.DeployAsync();\n            await Cluster.WaitForLivenessToStabilizeAsync();\n        }\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_GrainWithoutFilterCanBeCalled()\n    {\n        var managementGrain = fixture.Cluster.Client.GetGrain<IManagementGrain>(0);\n        var silos = await managementGrain.GetHosts(true);\n        Assert.NotNull(silos);\n    }\n\n    /// <summary>\n    /// Unique silo metadata is set up to be different for each silo, so this will require that placement happens on the calling silo.\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_RequiredFilterCanBeCalled()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IUniqueRequiredMatchFilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                Assert.Equal(hostedClusterSilo.SiloAddress, hostingSilo);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Unique silo metadata is set up to be different for each silo, so this will require that placement happens on the calling silo because it is the only one that matches.\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_PreferredFilterCanBeCalled()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IPreferredMatchFilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                Assert.Equal(hostedClusterSilo.SiloAddress, hostingSilo);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Unique silo metadata is set up to be different for each silo, so this will still place on any of the two silos since just the matching silos (just the one) is not enough to make the minimum desired candidates.\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_PreferredMin2FilterCanBeCalled()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            var dict = new Dictionary<SiloAddress, int>();\n            foreach (var clusterSilo in fixture.Cluster.Silos)\n            {\n                dict[clusterSilo.SiloAddress] = 0;\n            }\n\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IPreferredMatchMin2FilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                dict[hostingSilo] = dict.TryGetValue(hostingSilo, out var count) ? count + 1 : 1;\n            }\n\n            foreach (var kv in dict)\n            {\n                Assert.True(kv.Value >= 1, $\"Silo {kv.Key} did not host at least 1 grain\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Unique silo metadata is set up to be different for each silo, so this will still place on any of the two silos since just the matching silos (just the one) is not enough to make the minimum desired candidates.\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_PreferredMultipleFilterCanBeCalled()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            var dict = new Dictionary<SiloAddress, int>();\n            foreach (var clusterSilo in fixture.Cluster.Silos)\n            {\n                dict[clusterSilo.SiloAddress] = 0;\n            }\n\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IPreferredMatchMultipleFilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                dict[hostingSilo] = dict.TryGetValue(hostingSilo, out var count) ? count + 1 : 1;\n            }\n\n            foreach (var kv in dict)\n            {\n                Assert.True(kv.Value >= 1, $\"Silo {kv.Key} did not host at least 1 grain\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Unique silo metadata is set up to be different for each silo, so this will still place on any of the two silos since just the matching silos (just the one) is not enough to make the minimum desired candidates.\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_PreferredMin2FilterCanBeCalledWithLargerCluster()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            var dict = new Dictionary<SiloAddress, int>();\n            foreach (var clusterSilo in fixture.Cluster.Silos)\n            {\n                dict[clusterSilo.SiloAddress] = 0;\n            }\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IPreferredMatchMin2FilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                dict[hostingSilo] = dict.TryGetValue(hostingSilo, out var count) ? count + 1 : 1;\n            }\n\n            foreach (var kv in dict)\n            {\n                Assert.True(kv.Value >= 1, $\"Silo {kv.Key} did not host at least 1 grain\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// If no metadata key is defined then it should fall back to matching all silos\n    /// </summary>\n    /// <returns></returns>\n    [Fact, TestCategory(\"Functional\")]\n    public async Task PlacementFilter_PreferredNoMetadataFilterCanBeCalled()\n    {\n        var id = 0;\n        foreach (var hostedClusterSilo in fixture.Cluster.Silos)\n        {\n            var dict = new Dictionary<SiloAddress, int>();\n            foreach (var clusterSilo in fixture.Cluster.Silos)\n            {\n                dict[clusterSilo.SiloAddress] = 0;\n            }\n            for (var i = 0; i < 50; i++)\n            {\n                ++id;\n                var firstSp = fixture.Cluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n                var firstSiloMetadataCache = firstSp.GetRequiredService<IClusterClient>();\n                var managementGrain = firstSiloMetadataCache.GetGrain<IPreferredMatchNoMetadataFilteredGrain>(id);\n                var hostingSilo = await managementGrain.GetHostingSilo();\n                Assert.NotNull(hostingSilo);\n                dict[hostingSilo] = dict.TryGetValue(hostingSilo, out var count) ? count + 1 : 1;\n            }\n\n            foreach (var kv in dict)\n            {\n                Assert.True(kv.Value >= 1, $\"Silo {kv.Key} did not host at least 1 grain\");\n            }\n        }\n    }\n}\n\npublic interface IUniqueRequiredMatchFilteredGrain : IGrainWithIntegerKey\n{\n    Task<SiloAddress> GetHostingSilo();\n}\n\n#pragma warning disable ORLEANSEXP004\n[RequiredMatchSiloMetadataPlacementFilter([\"unique\"]), RandomPlacement]\n#pragma warning restore ORLEANSEXP004\npublic class UniqueRequiredMatchFilteredGrain(ILocalSiloDetails localSiloDetails) : Grain, IUniqueRequiredMatchFilteredGrain\n{\n    public Task<SiloAddress> GetHostingSilo() => Task.FromResult(localSiloDetails.SiloAddress);\n}\npublic interface IPreferredMatchFilteredGrain : IGrainWithIntegerKey\n{\n    Task<SiloAddress> GetHostingSilo();\n}\n\n#pragma warning disable ORLEANSEXP004\n[PreferredMatchSiloMetadataPlacementFilter([\"unique\"], 1), RandomPlacement]\n#pragma warning restore ORLEANSEXP004\npublic class PreferredMatchFilteredGrain(ILocalSiloDetails localSiloDetails) : Grain, IPreferredMatchFilteredGrain\n{\n    public Task<SiloAddress> GetHostingSilo() => Task.FromResult(localSiloDetails.SiloAddress);\n}\n\n\npublic interface IPreferredMatchMin2FilteredGrain : IGrainWithIntegerKey\n{\n    Task<SiloAddress> GetHostingSilo();\n}\n\n#pragma warning disable ORLEANSEXP004\n[PreferredMatchSiloMetadataPlacementFilter([\"unique\"]), RandomPlacement]\n#pragma warning restore ORLEANSEXP004\npublic class PreferredMatchMinTwoFilteredGrain(ILocalSiloDetails localSiloDetails) : Grain, IPreferredMatchMin2FilteredGrain\n{\n    public Task<SiloAddress> GetHostingSilo() => Task.FromResult(localSiloDetails.SiloAddress);\n}\n\npublic interface IPreferredMatchMultipleFilteredGrain : IGrainWithIntegerKey\n{\n    Task<SiloAddress> GetHostingSilo();\n}\n\n#pragma warning disable ORLEANSEXP004\n[PreferredMatchSiloMetadataPlacementFilter([\"unique\", \"other\"], 2), RandomPlacement]\n#pragma warning restore ORLEANSEXP004\npublic class PreferredMatchMultipleFilteredGrain(ILocalSiloDetails localSiloDetails) : Grain, IPreferredMatchMultipleFilteredGrain\n{\n    public Task<SiloAddress> GetHostingSilo() => Task.FromResult(localSiloDetails.SiloAddress);\n}\n\n#pragma warning disable ORLEANSEXP004\n[PreferredMatchSiloMetadataPlacementFilter([\"not.there\"]), RandomPlacement]\n#pragma warning restore ORLEANSEXP004\npublic class PreferredMatchNoMetadataFilteredGrain(ILocalSiloDetails localSiloDetails) : Grain, IPreferredMatchNoMetadataFilteredGrain\n{\n    public Task<SiloAddress> GetHostingSilo() => Task.FromResult(localSiloDetails.SiloAddress);\n}\n\npublic interface IPreferredMatchNoMetadataFilteredGrain : IGrainWithIntegerKey\n{\n    Task<SiloAddress> GetHostingSilo();\n}\n"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/TestLocalSiloDetails.cs",
    "content": "namespace UnitTests.PlacementFilterTests;\n\ninternal class TestLocalSiloDetails : ILocalSiloDetails\n{\n    public TestLocalSiloDetails(string name, string clusterId, string dnsHostName, SiloAddress siloAddress, SiloAddress gatewayAddress)\n    {\n        Name = name;\n        ClusterId = clusterId;\n        DnsHostName = dnsHostName;\n        SiloAddress = siloAddress;\n        GatewayAddress = gatewayAddress;\n    }\n\n    public string Name { get; }\n    public string ClusterId { get; }\n    public string DnsHostName { get; }\n    public SiloAddress SiloAddress { get; }\n    public SiloAddress GatewayAddress { get; }\n}"
  },
  {
    "path": "test/Orleans.Placement.Tests/PlacementFilterTests/TestSiloMetadataCache.cs",
    "content": "using Orleans.Runtime.MembershipService.SiloMetadata;\n\nnamespace UnitTests.PlacementFilterTests;\n\ninternal class TestSiloMetadataCache : ISiloMetadataCache\n{\n    private readonly Dictionary<SiloAddress, SiloMetadata> _metadata;\n\n    public TestSiloMetadataCache(Dictionary<SiloAddress, SiloMetadata> metadata)\n    {\n        _metadata = metadata;\n    }\n\n    public SiloMetadata GetSiloMetadata(SiloAddress siloAddress) => _metadata.GetValueOrDefault(siloAddress) ?? SiloMetadata.Empty;\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ActivationsLifeCycleTests/ActivationCollectorTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.TestingHost;\nusing Tester;\nusing TestExtensions;\nusing UnitTestGrains;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.ActivationsLifeCycleTests\n{\n    /// <summary>\n    /// Tests for the activation collector that manages grain activation lifecycle and garbage collection.\n    /// </summary>\n    public class ActivationCollectorTests : OrleansTestingBase, IAsyncLifetime\n    {\n        private static readonly TimeSpan DEFAULT_COLLECTION_QUANTUM = TimeSpan.FromSeconds(10);\n        private static readonly TimeSpan DEFAULT_IDLE_TIMEOUT = DEFAULT_COLLECTION_QUANTUM + TimeSpan.FromSeconds(1);\n        private static readonly TimeSpan WAIT_TIME = DEFAULT_IDLE_TIMEOUT.Multiply(3.0);\n\n        private TestCluster testCluster;\n\n        private ILogger logger;\n\n        private async Task Initialize(TimeSpan collectionAgeLimit, TimeSpan quantum)\n        {\n            var builder = new TestClusterBuilder(1);\n            builder.Properties[\"CollectionQuantum\"] = quantum.ToString();\n            builder.Properties[\"DefaultCollectionAgeLimit\"] = collectionAgeLimit.ToString();\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            testCluster = builder.Build();\n            await testCluster.DeployAsync();\n            this.logger = this.testCluster.Client.ServiceProvider.GetRequiredService<ILogger<ActivationCollectorTests>>();\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var config = hostBuilder.GetConfiguration();\n                var collectionAgeLimit = TimeSpan.Parse(config[\"DefaultCollectionAgeLimit\"]);\n                var quantum = TimeSpan.Parse(config[\"CollectionQuantum\"]);\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder\n                        .ConfigureServices(services => services.Where(s => s.ServiceType == typeof(IConfigurationValidator)).ToList().ForEach(s => services.Remove(s)));\n                    siloBuilder.Configure<GrainCollectionOptions>(options =>\n                    {\n                        options.CollectionAge = collectionAgeLimit;\n                        options.CollectionQuantum = quantum;\n                        options.ClassSpecificCollectionAge = new Dictionary<string, TimeSpan>\n                        {\n                            [typeof(IdleActivationGcTestGrain2).FullName] = DEFAULT_IDLE_TIMEOUT,\n                            [typeof(BusyActivationGcTestGrain2).FullName] = DEFAULT_IDLE_TIMEOUT,\n                            [typeof(CollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain).FullName] = TimeSpan.FromSeconds(12),\n                        };\n                    });\n                });\n            }\n        }\n\n\n        Task IAsyncLifetime.InitializeAsync() => Task.CompletedTask;\n\n        private async Task Initialize(TimeSpan collectionAgeLimit)\n        {\n            await Initialize(collectionAgeLimit, DEFAULT_COLLECTION_QUANTUM);\n        }\n\n        public async Task DisposeAsync()\n        {\n            if (testCluster is null) return;\n\n            try\n            {\n                await testCluster.StopAllSilosAsync();\n            }\n            finally\n            {\n                await testCluster.DisposeAsync();\n                testCluster = null;\n            }\n        }\n\n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorForceCollection()\n        {\n            await Initialize(DEFAULT_IDLE_TIMEOUT);\n\n            const int grainCount = 1000;\n            var fullGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain1));\n\n            List<Task> tasks = new List<Task>();\n            logger.LogInformation(\"ActivationCollectorForceCollection: activating {Count} grains.\", grainCount);\n            for (var i = 0; i < grainCount; ++i)\n            {\n                IIdleActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain1>(Guid.NewGuid());\n                tasks.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks);\n\n            await Task.Delay(TimeSpan.FromSeconds(5));\n\n            var grain = this.testCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            await grain.ForceActivationCollection(TimeSpan.FromSeconds(4));\n\n            int activationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(0, activationsNotCollected);\n\n            await grain.ForceActivationCollection(TimeSpan.FromSeconds(4));\n        }\n\n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldCollectIdleActivations()\n        {\n            await Initialize(DEFAULT_IDLE_TIMEOUT);\n\n            const int grainCount = 1000;\n            var fullGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain1));\n\n            List<Task> tasks = new List<Task>();\n            logger.LogInformation(\"IdleActivationCollectorShouldCollectIdleActivations: activating {Count} grains.\", grainCount);\n            for (var i = 0; i < grainCount; ++i)\n            {\n                IIdleActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain1>(Guid.NewGuid());\n                tasks.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(grainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"IdleActivationCollectorShouldCollectIdleActivations: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(WAIT_TIME);\n\n            int activationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(0, activationsNotCollected);\n        }   \n\n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldNotCollectBusyActivations()\n        {\n            await Initialize(DEFAULT_IDLE_TIMEOUT);\n\n            const int idleGrainCount = 500;\n            const int busyGrainCount = 500;\n            var idleGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain1));\n            var busyGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(BusyActivationGcTestGrain1));\n\n            List<Task> tasks0 = new List<Task>();\n            List<IBusyActivationGcTestGrain1> busyGrains = new List<IBusyActivationGcTestGrain1>();\n            logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivations: activating {Count} busy grains.\", busyGrainCount);\n            for (var i = 0; i < busyGrainCount; ++i)\n            {\n                IBusyActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IBusyActivationGcTestGrain1>(Guid.NewGuid());\n                busyGrains.Add(g);\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n            bool[] quit = new bool[]{ false };\n            async Task busyWorker()\n            {\n                logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivations: busyWorker started\");\n                List<Task> tasks1 = new List<Task>();\n                while (!quit[0])\n                {\n                    foreach (var g in busyGrains)\n                        tasks1.Add(g.Nop());\n                    await Task.WhenAll(tasks1);\n                }\n            }\n            Task.Run(busyWorker).Ignore();\n\n            logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivations: activating {Count} idle grains.\", idleGrainCount);\n            tasks0.Clear();\n            for (var i = 0; i < idleGrainCount; ++i)\n            {\n                IIdleActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain1>(Guid.NewGuid());\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName) + await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(idleGrainCount + busyGrainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"ActivationCollectorShouldNotCollectBusyActivations: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(WAIT_TIME);\n\n            // we should have only collected grains from the idle category (IdleActivationGcTestGrain1).\n            int idleActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName);\n            int busyActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(0, idleActivationsNotCollected);\n            Assert.Equal(busyGrainCount, busyActivationsNotCollected);\n\n            quit[0] = true;\n        }          \n        \n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ManualCollectionShouldNotCollectBusyActivations()\n        {\n            await Initialize(DEFAULT_IDLE_TIMEOUT);\n\n            TimeSpan shortIdleTimeout = TimeSpan.FromSeconds(1);\n            const int idleGrainCount = 500;\n            const int busyGrainCount = 500;\n            var idleGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain1));\n            var busyGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(BusyActivationGcTestGrain1));\n\n            List<Task> tasks0 = new List<Task>();\n            List<IBusyActivationGcTestGrain1> busyGrains = new List<IBusyActivationGcTestGrain1>();\n            logger.LogInformation(\"ManualCollectionShouldNotCollectBusyActivations: activating {Count} busy grains.\", busyGrainCount);\n            for (var i = 0; i < busyGrainCount; ++i)\n            {\n                IBusyActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IBusyActivationGcTestGrain1>(Guid.NewGuid());\n                busyGrains.Add(g);\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n            bool[] quit = new bool[]{ false };\n            async Task busyWorker()\n            {\n                logger.LogInformation(\"ManualCollectionShouldNotCollectBusyActivations: busyWorker started\");\n                List<Task> tasks1 = new List<Task>();\n                while (!quit[0])\n                {\n                    foreach (var g in busyGrains)\n                        tasks1.Add(g.Nop());\n                    await Task.WhenAll(tasks1);\n                }\n            }\n            Task.Run(busyWorker).Ignore();\n\n            logger.LogInformation(\"ManualCollectionShouldNotCollectBusyActivations: activating {Count} idle grains.\", idleGrainCount);\n            tasks0.Clear();\n            for (var i = 0; i < idleGrainCount; ++i)\n            {\n                IIdleActivationGcTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain1>(Guid.NewGuid());\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName) + await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(idleGrainCount + busyGrainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"ManualCollectionShouldNotCollectBusyActivations: grains activated; waiting {TotalSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                shortIdleTimeout.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(shortIdleTimeout);\n\n            TimeSpan everything = TimeSpan.FromMinutes(10);\n            logger.LogInformation(\"ManualCollectionShouldNotCollectBusyActivations: triggering manual collection (timespan is {TotalSeconds} sec).\",  everything.TotalSeconds);\n            IManagementGrain mgmtGrain = this.testCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n            await mgmtGrain.ForceActivationCollection(everything);\n\n\n            logger.LogInformation(\n                \"ManualCollectionShouldNotCollectBusyActivations: waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(WAIT_TIME);\n\n            // we should have only collected grains from the idle category (IdleActivationGcTestGrain).\n            int idleActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName);\n            int busyActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(0, idleActivationsNotCollected);\n            Assert.Equal(busyGrainCount, busyActivationsNotCollected);\n\n            quit[0] = true;\n        }    \n        \n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldCollectIdleActivationsSpecifiedInPerTypeConfiguration()\n        {\n            //make sure default value won't cause activation collection during wait time\n            var defaultCollectionAgeLimit = WAIT_TIME.Multiply(2);\n            await Initialize(defaultCollectionAgeLimit);\n\n            const int grainCount = 1000;\n            var fullGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain2));\n\n            List<Task> tasks = new List<Task>();\n            logger.LogInformation(\"ActivationCollectorShouldCollectIdleActivationsSpecifiedInPerTypeConfiguration: activating {Count} grains.\", grainCount);\n            for (var i = 0; i < grainCount; ++i)\n            {\n                IIdleActivationGcTestGrain2 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain2>(Guid.NewGuid());\n                tasks.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(grainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"ActivationCollectorShouldCollectIdleActivationsSpecifiedInPerTypeConfiguration: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(WAIT_TIME);\n\n            int activationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(0, activationsNotCollected);\n        }   \n\n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldNotCollectBusyActivationsSpecifiedInPerTypeConfiguration()\n        {\n            //make sure default value won't cause activation collection during wait time\n            var defaultCollectionAgeLimit = WAIT_TIME.Multiply(2);\n            await Initialize(defaultCollectionAgeLimit);\n\n            const int idleGrainCount = 500;\n            const int busyGrainCount = 500;\n            var idleGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(IdleActivationGcTestGrain2));\n            var busyGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(BusyActivationGcTestGrain2));\n\n            List<Task> tasks0 = new List<Task>();\n            List<IBusyActivationGcTestGrain2> busyGrains = new List<IBusyActivationGcTestGrain2>();\n            logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivationsSpecifiedInPerTypeConfiguration: activating {Count} busy grains.\", busyGrainCount);\n            for (var i = 0; i < busyGrainCount; ++i)\n            {\n                IBusyActivationGcTestGrain2 g = this.testCluster.GrainFactory.GetGrain<IBusyActivationGcTestGrain2>(Guid.NewGuid());\n                busyGrains.Add(g);\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n            bool[] quit = new bool[]{ false };\n            async Task busyWorker()\n            {\n                logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivationsSpecifiedInPerTypeConfiguration: busyWorker started\");\n                List<Task> tasks1 = new List<Task>();\n                while (!quit[0])\n                {\n                    foreach (var g in busyGrains)\n                        tasks1.Add(g.Nop());\n                    await Task.WhenAll(tasks1);\n                }\n            }\n            Task.Run(busyWorker).Ignore();\n\n            logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyActivationsSpecifiedInPerTypeConfiguration: activating {Count} idle grains.\", idleGrainCount);\n            tasks0.Clear();\n            for (var i = 0; i < idleGrainCount; ++i)\n            {\n                IIdleActivationGcTestGrain2 g = this.testCluster.GrainFactory.GetGrain<IIdleActivationGcTestGrain2>(Guid.NewGuid());\n                tasks0.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks0);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName) + await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(idleGrainCount + busyGrainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"IdleActivationCollectorShouldNotCollectBusyActivations: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTime} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            await Task.Delay(WAIT_TIME);\n\n            // we should have only collected grains from the idle category (IdleActivationGcTestGrain2).\n            int idleActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, idleGrainTypeName);\n            int busyActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, busyGrainTypeName);\n            Assert.Equal(0, idleActivationsNotCollected);\n            Assert.Equal(busyGrainCount, busyActivationsNotCollected);\n\n            quit[0] = true;\n        } \n  \n        [Fact(Skip = \"Flaky test. Needs to be investigated.\"), TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldNotCollectBusyStatelessWorkers()\n        {\n            await Initialize(DEFAULT_IDLE_TIMEOUT);\n\n            // the purpose of this test is to determine whether idle stateless worker activations are properly identified by the activation collector.\n            // in this test, we:\n            //\n            //   1. setup the test.\n            //   2. activate a set of grains by sending a burst of messages to each one. the purpose of the burst is to ensure that multiple activations are used. \n            //   3. verify that multiple activations for each grain have been created.\n            //   4. periodically send a message to each grain, ensuring that only one activation remains busy. each time we check the activation id and compare it against the activation id returned by the previous grain call. initially, these may not be identical but as the other activations become idle and are collected, there will be only one activation servicing these calls.\n            //   5. wait long enough for idle activations to be collected.\n            //   6. verify that only one activation is still active per grain.\n            //   7. ensure that test steps 2-6 are repeatable.\n\n            const int grainCount = 1;\n            var grainTypeName = RuntimeTypeNameFormatter.Format(typeof(StatelessWorkerActivationCollectorTestGrain1));\n            const int burstLength = 1000;\n\n            List<Task> tasks0 = new List<Task>();\n            List<IStatelessWorkerActivationCollectorTestGrain1> grains = new List<IStatelessWorkerActivationCollectorTestGrain1>();\n            for (var i = 0; i < grainCount; ++i)\n            {\n                IStatelessWorkerActivationCollectorTestGrain1 g = this.testCluster.GrainFactory.GetGrain<IStatelessWorkerActivationCollectorTestGrain1>(Guid.NewGuid());\n                grains.Add(g);\n            }\n\n\n            bool[] quit = new bool[] { false };\n            bool[] matched = new bool[grainCount];\n            string[] activationIds = new string[grainCount];\n            async Task workFunc(int index)\n            {\n                // (part of) 4. periodically send a message to each grain...\n\n                // take a grain and call Delay to keep it busy.\n                IStatelessWorkerActivationCollectorTestGrain1 g = grains[index];\n                await g.Delay(DEFAULT_IDLE_TIMEOUT.Divide(2));\n                // identify the activation and record whether it matches the activation ID last reported. it probably won't match in the beginning but should always converge on a match as other activations get collected.\n                string aid = await g.IdentifyActivation();\n                logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyStatelessWorkers: identified {Activation}\", aid);\n                matched[index] = aid == activationIds[index];\n                activationIds[index] = aid;\n            }\n            async Task workerFunc()\n            {\n                // (part of) 4. periodically send a message to each grain...\n                logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyStatelessWorkers: busyWorker started\");\n\n                List<Task> tasks1 = new List<Task>();\n                while (!quit[0])\n                {\n                    for (int index = 0; index < grains.Count; ++index)\n                    {\n                        if (quit[0])\n                        {\n                            break;\n                        }\n\n                        tasks1.Add(workFunc(index));\n                    }\n                    await Task.WhenAll(tasks1);\n                }\n            }\n\n            // setup (1) ends here.\n\n            for (int i = 0; i < 2; ++i)\n            {\n                // 2. activate a set of grains... \n                this.logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyStatelessWorkers: activating {Count} stateless worker grains (run #{RunNumber}).\", grainCount, i);\n                foreach (var g in grains)\n                {\n                    for (int j = 0; j < burstLength; ++j)\n                    {\n                        // having the activation delay will ensure that one activation cannot serve all requests that we send to it, making it so that additional activations will be created.\n                        tasks0.Add(g.Delay(TimeSpan.FromMilliseconds(10)));\n                    }\n                }\n                await Task.WhenAll(tasks0);\n\n\n                // 3. verify that multiple activations for each grain have been created.\n                int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, grainTypeName);\n                Assert.True(activationsCreated > grainCount, $\"more than {grainCount} activations should have been created; got {activationsCreated} instead\");\n\n                // 4. periodically send a message to each grain...\n                this.logger.LogInformation(\"ActivationCollectorShouldNotCollectBusyStatelessWorkers: grains activated; sending heartbeat to {Count} stateless worker grains.\", grainCount);\n                Task workerTask = Task.Run(workerFunc);\n\n                // 5. wait long enough for idle activations to be collected.\n                this.logger.LogInformation(\n                    \"ActivationCollectorShouldNotCollectBusyStatelessWorkers: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTimeout} sec).\",\n                    WAIT_TIME.TotalSeconds,\n                    DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n                await Task.Delay(WAIT_TIME);\n\n                // 6. verify that only one activation is still active per grain.\n                int busyActivationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, grainTypeName);\n\n                // signal that the worker task should stop and wait for it to finish.\n                quit[0] = true;\n                await workerTask;\n                quit[0] = false;\n\n                Assert.Equal(grainCount, busyActivationsNotCollected);\n\n                // verify that we matched activation ids in the final iteration of step 4's loop.\n                for (int index = 0; index < grains.Count; ++index)\n                {\n                    Assert.True(matched[index], string.Format(\"activation ID of final subsequent heartbeats did not match for grain {0}\", grains[index]));\n                }\n            }\n        }\n\n        [Fact, TestCategory(\"ActivationCollector\"), TestCategory(\"Functional\")]\n        public async Task ActivationCollectorShouldCollectByCollectionSpecificAgeLimitForTwelveSeconds()\n        {\n            var waitTime = TimeSpan.FromSeconds(30);\n            var defaultCollectionAge = waitTime.Multiply(2);\n            //make sure defaultCollectionAge value won't cause activation collection in wait time\n            await Initialize(defaultCollectionAge);\n\n            const int grainCount = 1000;\n\n            // CollectionAgeLimit = 12 seconds\n            var fullGrainTypeName = RuntimeTypeNameFormatter.Format(typeof(CollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain));\n\n            List<Task> tasks = new List<Task>();\n            logger.LogInformation(\"ActivationCollectorShouldCollectByCollectionSpecificAgeLimit: activating {GrainCount} grains.\", grainCount);\n            for (var i = 0; i < grainCount; ++i)\n            {\n                ICollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain g = this.testCluster.GrainFactory.GetGrain<ICollectionSpecificAgeLimitForTenSecondsActivationGcTestGrain>(Guid.NewGuid());\n                tasks.Add(g.Nop());\n            }\n            await Task.WhenAll(tasks);\n\n            int activationsCreated = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(grainCount, activationsCreated);\n\n            logger.LogInformation(\n                \"ActivationCollectorShouldCollectByCollectionSpecificAgeLimit: grains activated; waiting {WaitSeconds} sec (activation GC idle timeout is {DefaultIdleTimeout} sec).\",\n                WAIT_TIME.TotalSeconds,\n                DEFAULT_IDLE_TIMEOUT.TotalSeconds);\n            \n            // Some time is required for GC to collect all of the Grains)\n            await Task.Delay(waitTime);\n\n            int activationsNotCollected = await TestUtils.GetActivationCount(this.testCluster.GrainFactory, fullGrainTypeName);\n            Assert.Equal(0, activationsNotCollected);\n        }\n\n        [Fact, TestCategory(\"SlowBVT\"), TestCategory(\"Timers\")]\n        public async Task NonReentrantGrainTimer_NoKeepAlive_Test()\n        {\n            await Initialize(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1));\n\n            const string testName = \"NonReentrantGrainTimer_NoKeepAlive_Test\";\n\n            var grain = this.testCluster.GrainFactory.GetGrain<INonReentrantTimerCallGrain>(GetRandomGrainId());\n\n            // Schedule a timer to fire at the 30s mark which will not extend the grain's lifetime.\n            await grain.StartTimer(testName, TimeSpan.FromSeconds(30), keepAlive: false);\n            await Task.Delay(TimeSpan.FromSeconds(7));\n\n            var tickCount = await grain.GetTickCount();\n\n            // The grain should have been deactivated.\n            Assert.Equal(0, tickCount);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ActivationsLifeCycleTests/DeactivateOnIdleTests.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.TestHelper;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Internal;\nusing Orleans.Configuration;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace UnitTests.ActivationsLifeCycleTests\n{\n    /// <summary>\n    /// Tests for grain deactivation on idle behavior and related stress scenarios.\n    /// </summary>\n    [TestCategory(\"ActivationCollector\")]\n    public class DeactivateOnIdleTests : OrleansTestingBase, IDisposable\n    {\n        private readonly ITestOutputHelper output;\n        private TestCluster testCluster;\n\n        public DeactivateOnIdleTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        private void Initialize(TestClusterBuilder builder = null)\n        {\n            if (builder == null)\n            {\n                builder = new TestClusterBuilder(1);\n            }\n\n            testCluster = builder.Build();\n            testCluster.Deploy();\n        }\n        \n        public void Dispose()\n        {\n            try\n            {\n                testCluster?.StopAllSilos();\n            }\n            finally\n            {\n                testCluster?.Dispose();\n                testCluster = null;\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdleTestInside_Basic()\n        {\n            Initialize();\n\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1);\n            var b = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(2);\n            await a.SetOther(b);\n            await a.GetOtherAge(); // prime a's routing cache\n            await b.DeactivateSelf();\n            Thread.Sleep(5000);\n            var age = await a.GetOtherAge().WaitAsync(TimeSpan.FromMilliseconds(2000));\n            Assert.True(age.TotalMilliseconds < 2000, \"Should be newly activated grain\");\n        }\n\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task DeactivateOnIdleTest_Stress_1()\n        {\n            Initialize();\n\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1);\n            await a.GetAge();\n            await a.DeactivateSelf();\n            for (int i = 0; i < 30; i++)\n            {\n                await a.GetAge();\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdleTest_Stress_2_NonReentrant()\n        {\n            Initialize();\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1, \"UnitTests.Grains.CollectionTestGrain\");\n            await a.IncrCounter();\n\n            Task t1 = Task.Run(async () =>\n            {\n                List<Task> tasks = new List<Task>();\n                for (int i = 0; i < 100; i++)\n                {\n                    tasks.Add(a.IncrCounter());\n                }\n                await Task.WhenAll(tasks);\n            });\n\n            await Task.Delay(1);\n            Task t2 = a.DeactivateSelf();\n            await Task.WhenAll(t1, t2);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdleTest_Stress_3_Reentrant()\n        {\n            Initialize();\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1, \"UnitTests.Grains.ReentrantCollectionTestGrain\");\n            await a.IncrCounter();\n\n            Task t1 = Task.Run(async () =>\n            {\n                List<Task> tasks = new List<Task>();\n                for (int i = 0; i < 100; i++)\n                {\n                    tasks.Add(a.IncrCounter());\n                }\n                await Task.WhenAll(tasks);\n            });\n\n            await Task.Delay(TimeSpan.FromMilliseconds(1));\n            Task t2 = a.DeactivateSelf();\n            await Task.WhenAll(t1, t2);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdleTest_Stress_4_Timer()\n        {\n            Initialize();\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1, \"UnitTests.Grains.ReentrantCollectionTestGrain\");\n            for (int i = 0; i < 10; i++)\n            {\n                await a.StartTimer(TimeSpan.FromMilliseconds(5), TimeSpan.FromMilliseconds(100));\n            }\n            await a.DeactivateSelf();\n            await a.IncrCounter();\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdleTest_Stress_5()\n        {\n            Initialize();\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1);\n            await a.IncrCounter();\n\n            Task t1 = Task.Run(async () =>\n            {\n                List<Task> tasks = new List<Task>();\n                for (int i = 0; i < 100; i++)\n                {\n                    tasks.Add(a.IncrCounter());\n                }\n                await Task.WhenAll(tasks);\n            });\n            Task t2 = Task.Run(async () =>\n            {\n                List<Task> tasks = new List<Task>();\n                for (int i = 0; i < 1; i++)\n                {\n                    await Task.Delay(1);\n                    tasks.Add(a.DeactivateSelf());\n                }\n                await Task.WhenAll(tasks);\n            });\n            await Task.WhenAll(t1, t2);\n        }\n\n        [Fact, TestCategory(\"Stress\")]\n        public async Task DeactivateOnIdleTest_Stress_11()\n        {\n            Initialize();\n            var a = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(1);\n            List<Task> tasks = new List<Task>();\n            for (int i = 0; i < 100; i++)\n            {\n                tasks.Add(a.IncrCounter());\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdle_NonExistentActivation_1()\n        {\n            await DeactivateOnIdle_NonExistentActivation_Runner(0);\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task DeactivateOnIdle_NonExistentActivation_2()\n        {\n            await DeactivateOnIdle_NonExistentActivation_Runner(1);\n        }\n\n        public class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<StaticGatewayListProviderOptions>(options => { options.Gateways = options.Gateways.Take(1).ToList(); });\n            }\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                var cfg = hostBuilder.GetConfiguration();\n                var maxForwardCount = int.Parse(cfg[\"MaxForwardCount\"]);\n                hostBuilder.ConfigureServices(services =>\n                {\n                    services.Configure<SiloMessagingOptions>(options => options.MaxForwardCount = maxForwardCount);\n                });\n            }\n        }\n\n        private async Task DeactivateOnIdle_NonExistentActivation_Runner(int forwardCount)\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            builder.Properties[\"MaxForwardCount\"] = forwardCount.ToString();\n            Initialize(builder);\n\n            ICollectionTestGrain grain = await PickGrainInNonPrimary();\n\n            output.WriteLine(\"About to make a 1st GetAge() call.\");\n            TimeSpan age = await grain.GetAge();\n            output.WriteLine(age.ToString());\n\n            await grain.DeactivateSelf();\n            await Task.Delay(3000);\n\n            var thrownException = await Record.ExceptionAsync(() => grain.GetAge());\n            Assert.Null(thrownException);\n            output.WriteLine(\"\\nThe 1st call after DeactivateSelf has NOT thrown any exception as expected, since forwardCount is {0}.\\n\", forwardCount);\n        }\n\n        private async Task<ICollectionTestGrain> PickGrainInNonPrimary()\n        {\n            for (int i = 0; i < 500; i++)\n            {\n                if (i % 30 == 29) await Task.Delay(1000); // give some extra time to stabilize if it can't find a suitable grain\n\n                // Create grain such that:\n                // Its directory owner is not the Gateway silo. This way Gateway will use its directory cache.\n                // Its activation is located on the non Gateway silo as well.\n                ICollectionTestGrain grain = this.testCluster.GrainFactory.GetGrain<ICollectionTestGrain>(i);\n                GrainId grainId = ((GrainReference)await grain.GetGrainReference()).GrainId;\n                SiloAddress primaryForGrain = (await TestUtils.GetDetailedGrainReport(this.testCluster.InternalGrainFactory, grainId, this.testCluster.Primary)).PrimaryForGrain;\n                if (primaryForGrain.Equals(this.testCluster.Primary.SiloAddress))\n                {\n                    continue;\n                }\n                string siloHostingActivation = await grain.GetRuntimeInstanceId();\n                if (this.testCluster.Primary.SiloAddress.ToString().Equals(siloHostingActivation))\n                {\n                    continue;\n                }\n                this.output.WriteLine(\"\\nCreated grain with key {0} whose primary directory owner is silo {1} and which was activated on silo {2}\\n\", i, primaryForGrain.ToString(), siloHostingActivation);\n                return grain;\n            }\n\n            Assert.True(testCluster.GetActiveSilos().Count() > 1, \"This logic requires at least 1 non-primary active silo\");\n            Assert.Fail(\"Could not find a grain that activates on a non-primary silo, and has the partition be also managed by a non-primary silo\");\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/CancellationTests/SystemTargetCancellationTokenTests.cs",
    "content": "#nullable enable\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CancellationTests;\n\n/// <summary>\n/// Tests for SystemTarget CancellationToken functionality with acknowledgement waiting enabled.\n/// </summary>\npublic sealed class SystemTargetCancellationTokenTests_WaitForAcknowledgement(SystemTargetCancellationTokenTests_WaitForAcknowledgement.Fixture fixture)\n    : SystemTargetCancellationTokenTests(fixture), IClassFixture<SystemTargetCancellationTokenTests_WaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        public override bool WaitForCancellationAcknowledgement => true;\n    }\n}\n\n/// <summary>\n/// Tests for SystemTarget CancellationToken functionality with acknowledgement waiting disabled.\n/// </summary>\npublic sealed class SystemTargetCancellationTokenTests_NoWaitForAcknowledgement(SystemTargetCancellationTokenTests_NoWaitForAcknowledgement.Fixture fixture)\n    : SystemTargetCancellationTokenTests(fixture), IClassFixture<SystemTargetCancellationTokenTests_NoWaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        public override bool WaitForCancellationAcknowledgement => false;\n    }\n}\n\n/// <summary>\n/// Base class for testing CancellationToken propagation and handling for SystemTargets.\n/// Note: All SystemTarget calls are interleaving by default - they execute immediately\n/// without queueing, unlike regular grain calls.\n/// </summary>\npublic abstract class SystemTargetCancellationTokenTests(SystemTargetCancellationTokenTests.FixtureBase fixture)\n{\n    /// <summary>\n    /// The grain type for the cancellation test system target.\n    /// </summary>\n    public static readonly GrainType CancellationTestSystemTargetType = SystemTargetGrainId.CreateGrainType(\"cancellation-test-target\");\n\n    public abstract class FixtureBase : BaseInProcessTestClusterFixture\n    {\n        public abstract bool WaitForCancellationAcknowledgement { get; }\n\n        protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n        {\n            base.ConfigureTestCluster(builder);\n            builder.ConfigureHost(hostBuilder => hostBuilder.Logging.SetMinimumLevel(LogLevel.Debug));\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.Configure<SiloMessagingOptions>(opts =>\n                {\n                    opts.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n\n                // Register the CancellationTestSystemTarget as a lifecycle participant\n                siloBuilder.Services.AddSingleton<CancellationTestSystemTarget>();\n                siloBuilder.Services.AddSingleton<ILifecycleParticipant<ISiloLifecycle>>(sp => sp.GetRequiredService<CancellationTestSystemTarget>());\n            });\n\n            builder.ConfigureClient(clientBuilder =>\n            {\n                clientBuilder.Configure<ClientMessagingOptions>(opts =>\n                {\n                    opts.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n            });\n        }\n\n        /// <summary>\n        /// Gets a reference to the CancellationTestSystemTarget on the specified silo.\n        /// </summary>\n        public ICancellationTestSystemTarget GetSystemTarget(SiloAddress siloAddress)\n        {\n            return ((IInternalGrainFactory)GrainFactory).GetSystemTarget<ICancellationTestSystemTarget>(CancellationTestSystemTargetType, siloAddress);\n        }\n    }\n\n    public bool WaitForCancellationAcknowledgement => fixture.WaitForCancellationAcknowledgement;\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task SystemTargetTaskCancellation(int delay)\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var task = systemTarget.LongWait(cts.Token, TimeSpan.FromSeconds(10), callId);\n        cts.CancelAfter(delay);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(systemTarget, callId);\n        }\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task MultipleSystemTargetsTaskCancellation(int delay)\n    {\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var systemTargets = fixture.HostedCluster.Silos\n            .Select(s => fixture.GetSystemTarget(s.SiloAddress))\n            .ToList();\n\n        var tasks = systemTargets.Select(st =>\n            Assert.ThrowsAnyAsync<OperationCanceledException>(() =>\n                st.LongWait(cts.Token, TimeSpan.FromSeconds(10), callId)))\n            .ToList();\n\n        cts.CancelAfter(delay);\n        await Task.WhenAll(tasks);\n        if (delay > 0)\n        {\n            foreach (var st in systemTargets)\n            {\n                await WaitForCallCancellation(st, callId);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Tests multiple concurrent cancellations on the same SystemTarget.\n    /// Since all SystemTarget calls are interleaving, they all run concurrently.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task SystemTargetMultipleConcurrentCancellations(int delay)\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        var callIds = Enumerable.Range(0, 5).Select(_ => Guid.NewGuid()).ToArray();\n        var tasks = callIds\n            .Select(async callId =>\n            {\n                using var cts = new CancellationTokenSource();\n                // All these calls run concurrently since SystemTarget calls are interleaving\n                var task = systemTarget.LongWait(cts.Token, TimeSpan.FromSeconds(10), callId);\n                cts.CancelAfter(delay);\n                await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n            })\n            .ToList();\n\n        await Task.WhenAll(tasks);\n        if (delay > 0)\n        {\n            foreach (var callId in callIds)\n            {\n                await WaitForCallCancellation(systemTarget, callId);\n            }\n        }\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task TokenPassingWithoutCancellation_NoExceptionShouldBeThrown()\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        using var cts = new CancellationTokenSource();\n        try\n        {\n            await systemTarget.LongWait(cts.Token, TimeSpan.FromMilliseconds(1), Guid.Empty);\n        }\n        catch (Exception ex)\n        {\n            Assert.Fail(\"Expected no exception, but got: \" + ex.Message);\n        }\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task PreCancelledTokenPassing()\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        using var cts = new CancellationTokenSource();\n        await cts.CancelAsync();\n\n        // Expect an OperationCanceledException to be thrown as the token is already cancelled\n        Assert.Throws<OperationCanceledException>(() =>\n            systemTarget.LongWait(cts.Token, TimeSpan.FromSeconds(10), Guid.Empty).Ignore());\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksExecutionContext()\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var task = systemTarget.CancellationTokenCallbackResolve(cts.Token, callId);\n        cts.CancelAfter(TimeSpan.FromMilliseconds(100));\n\n        if (WaitForCancellationAcknowledgement)\n        {\n            var result = await task;\n            Assert.True(result);\n        }\n        else\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        }\n\n        await WaitForCallCancellation(systemTarget, callId);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksTaskSchedulerContext()\n    {\n        var silos = fixture.HostedCluster.Silos.ToArray();\n        var sourceTarget = fixture.GetSystemTarget(silos[0].SiloAddress);\n        var destinationTarget = fixture.GetSystemTarget(silos.Length > 1 ? silos[1].SiloAddress : silos[0].SiloAddress);\n\n        var callId = Guid.NewGuid();\n        var task = sourceTarget.CallOtherCancellationTokenCallbackResolve(destinationTarget, callId);\n\n        if (WaitForCancellationAcknowledgement)\n        {\n            var result = await task;\n            Assert.True(result);\n        }\n        else\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        }\n\n        await WaitForCallCancellation(destinationTarget, callId);\n    }\n\n    [Fact, TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksThrow_ExceptionDoesNotPropagate()\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        systemTarget.CancellationTokenCallbackThrow(cts.Token, callId).Ignore();\n        // Cancellation is a cooperative mechanism, so we don't expect the exception to propagate\n        cts.CancelAfter(100);\n        await WaitForCallCancellation(systemTarget, callId);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InSiloCancellation(int delay)\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        await CancellationTestCore(siloAddress, siloAddress, delay);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InterSiloCancellation(int delay)\n    {\n        var silos = fixture.HostedCluster.Silos.ToArray();\n        if (silos.Length < 2)\n        {\n            // Skip test if there's only one silo\n            return;\n        }\n\n        await CancellationTestCore(silos[0].SiloAddress, silos[1].SiloAddress, delay);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InterSiloClientCancellationTokenPassing(int delay)\n    {\n        var silos = fixture.HostedCluster.Silos.ToArray();\n        if (silos.Length < 2)\n        {\n            // Skip test if there's only one silo\n            return;\n        }\n\n        await ClientCancellationTokenPassing(delay, silos[0].SiloAddress, silos[1].SiloAddress);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InSiloClientCancellationTokenPassing(int delay)\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        await ClientCancellationTokenPassing(delay, siloAddress, siloAddress);\n    }\n\n    private async Task ClientCancellationTokenPassing(int delay, SiloAddress sourceAddress, SiloAddress targetAddress)\n    {\n        var sourceTarget = fixture.GetSystemTarget(sourceAddress);\n        var target = fixture.GetSystemTarget(targetAddress);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var task = sourceTarget.CallOtherLongRunningTask(target, cts.Token, TimeSpan.FromSeconds(10), callId);\n        cts.CancelAfter(delay);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(target, callId);\n        }\n    }\n\n    private async Task CancellationTestCore(SiloAddress sourceAddress, SiloAddress targetAddress, int delay)\n    {\n        var sourceTarget = fixture.GetSystemTarget(sourceAddress);\n        var target = fixture.GetSystemTarget(targetAddress);\n\n        var callId = Guid.NewGuid();\n        var task = sourceTarget.CallOtherLongRunningTaskWithLocalCancellation(target, TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(delay), callId);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(target, callId);\n        }\n    }\n\n    private static async Task WaitForCallCancellation(ICancellationTestSystemTarget systemTarget, Guid callId)\n    {\n        var (wasCancelled, error) = await systemTarget.WaitForCancellation(callId, TimeSpan.FromSeconds(30));\n        if (!wasCancelled)\n        {\n            Assert.Fail($\"Did not encounter the expected call id {callId}\");\n        }\n\n        if (error is not null)\n        {\n            throw new Exception(\"Expected no error, but found an error\", error);\n        }\n    }\n\n    /// <summary>\n    /// Tests that multiple concurrent requests can each be cancelled independently.\n    /// Since all SystemTarget calls are interleaving, they all execute concurrently.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task MultipleConcurrentSystemTargetRequestsCancellation()\n    {\n        var siloAddress = fixture.HostedCluster.Silos.First().SiloAddress;\n        var systemTarget = fixture.GetSystemTarget(siloAddress);\n\n        // Start multiple concurrent requests (all SystemTarget calls are interleaving)\n        using var cts1 = new CancellationTokenSource();\n        using var cts2 = new CancellationTokenSource();\n        using var cts3 = new CancellationTokenSource();\n\n        var callId1 = Guid.NewGuid();\n        var callId2 = Guid.NewGuid();\n        var callId3 = Guid.NewGuid();\n\n        var task1 = systemTarget.LongWait(cts1.Token, TimeSpan.FromSeconds(10), callId1);\n        var task2 = systemTarget.LongWait(cts2.Token, TimeSpan.FromSeconds(10), callId2);\n        var task3 = systemTarget.LongWait(cts3.Token, TimeSpan.FromSeconds(10), callId3);\n\n        // Wait for all to be running\n        await Task.Delay(100);\n\n        // Cancel only the second request\n        await cts2.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task2);\n        await WaitForCallCancellation(systemTarget, callId2);\n\n        // First and third should still be running, cancel them\n        await cts1.CancelAsync();\n        await cts3.CancelAsync();\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task1);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task3);\n\n        await WaitForCallCancellation(systemTarget, callId1);\n        await WaitForCallCancellation(systemTarget, callId3);\n    }\n}\n\n/// <summary>\n/// A SystemTarget implementation for testing CancellationToken functionality.\n/// Note: All SystemTarget calls are interleaving - they execute immediately without queueing.\n/// </summary>\ninternal sealed class CancellationTestSystemTarget : SystemTarget, ICancellationTestSystemTarget, ILifecycleParticipant<ISiloLifecycle>\n{\n    private readonly ConcurrentDictionary<Guid, (TaskCompletionSource<bool> Tcs, Exception? Error)> _cancelledCalls = new();\n    private readonly ILocalSiloDetails _localSiloDetails;\n\n    public CancellationTestSystemTarget(\n        ILocalSiloDetails localSiloDetails,\n        SystemTargetShared shared)\n        : base(SystemTargetCancellationTokenTests.CancellationTestSystemTargetType, shared)\n    {\n        _localSiloDetails = localSiloDetails;\n        // Register with the activation directory so it can receive messages\n        shared.ActivationDirectory.RecordNewTarget(this);\n    }\n\n    void ILifecycleParticipant<ISiloLifecycle>.Participate(ISiloLifecycle lifecycle)\n    {\n        // No lifecycle registration needed - we register in the constructor\n    }\n\n    /// <inheritdoc />\n    public Task<string> GetRuntimeInstanceId()\n    {\n        return Task.FromResult(_localSiloDetails.SiloAddress.ToString());\n    }\n\n    /// <inheritdoc />\n    public async Task LongWait(CancellationToken cancellationToken, TimeSpan delay, Guid callId)\n    {\n        try\n        {\n            await Task.Delay(delay, cancellationToken);\n        }\n        catch (OperationCanceledException)\n        {\n            RecordCancellation(callId, null);\n            throw;\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task CallOtherLongRunningTask(ICancellationTestSystemTarget target, CancellationToken cancellationToken, TimeSpan delay, Guid callId)\n    {\n        await target.LongWait(cancellationToken, delay, callId);\n    }\n\n    /// <inheritdoc />\n    public async Task CallOtherLongRunningTaskWithLocalCancellation(ICancellationTestSystemTarget target, TimeSpan delay, TimeSpan delayBeforeCancel, Guid callId)\n    {\n        using var cts = new CancellationTokenSource();\n        var task = target.LongWait(cts.Token, delay, callId);\n        cts.CancelAfter(delayBeforeCancel);\n        await task;\n    }\n\n    /// <inheritdoc />\n    public Task<bool> CancellationTokenCallbackResolve(CancellationToken cancellationToken, Guid callId)\n    {\n        var tcs = new TaskCompletionSource<bool>();\n        var orleansTs = TaskScheduler.Current;\n        cancellationToken.Register(() =>\n        {\n            if (TaskScheduler.Current != orleansTs)\n            {\n                var exception = new Exception(\"Callback executed on wrong thread\");\n                RecordCancellation(callId, exception);\n                tcs.SetException(exception);\n            }\n            else\n            {\n                RecordCancellation(callId, null);\n                tcs.SetResult(true);\n            }\n        });\n\n        return tcs.Task;\n    }\n\n    /// <inheritdoc />\n    public async Task<bool> CallOtherCancellationTokenCallbackResolve(ICancellationTestSystemTarget target, Guid callId)\n    {\n        using var cts = new CancellationTokenSource();\n        var task = target.CancellationTokenCallbackResolve(cts.Token, callId);\n        cts.CancelAfter(300);\n        return await task;\n    }\n\n    /// <inheritdoc />\n    public async Task CancellationTokenCallbackThrow(CancellationToken cancellationToken, Guid callId)\n    {\n        cancellationToken.Register(() =>\n        {\n            RecordCancellation(callId, null);\n            throw new InvalidOperationException(\"From cancellation token callback\");\n        });\n\n        await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);\n    }\n\n    /// <inheritdoc />\n    public Task<bool> WasCallCancelled(Guid callId)\n    {\n        return Task.FromResult(_cancelledCalls.ContainsKey(callId));\n    }\n\n    /// <inheritdoc />\n    public async Task<(bool WasCancelled, Exception? Error)> WaitForCancellation(Guid callId, TimeSpan timeout)\n    {\n        var entry = _cancelledCalls.GetOrAdd(callId, _ => (new TaskCompletionSource<bool>(), null));\n\n        try\n        {\n            using var cts = new CancellationTokenSource(timeout);\n            await entry.Tcs.Task.WaitAsync(cts.Token);\n            return (true, _cancelledCalls.TryGetValue(callId, out var result) ? result.Error : null);\n        }\n        catch (OperationCanceledException)\n        {\n            return (false, null);\n        }\n    }\n\n    private readonly object _cancelledCallsLock = new();\n\n    private void RecordCancellation(Guid callId, Exception? error)\n    {\n        var entry = _cancelledCalls.GetOrAdd(callId, _ => (new TaskCompletionSource<bool>(), error));\n        if (error is not null)\n        {\n            lock (_cancelledCallsLock)\n            {\n                // Re-check inside the lock to ensure atomicity\n                var currentEntry = _cancelledCalls.GetOrAdd(callId, _ => (entry.Tcs, error));\n                if (currentEntry.Error is null)\n                {\n                    _cancelledCalls[callId] = (entry.Tcs, error);\n                }\n            }\n        }\n\n        entry.Tcs.TrySetResult(true);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace UnitTests\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n    \n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides internal Orleans test environment setup for unit and integration tests.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ConcurrencyTests.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.ConcurrencyTests\n{\n    /// <summary>\n    /// Tests for Orleans grain concurrency features and read-only methods.\n    /// \n    /// Orleans provides several concurrency models for grains:\n    /// - Default: Turn-based concurrency (one request at a time)\n    /// - [ReadOnly]: Methods can execute concurrently with other methods\n    /// - [AlwaysInterleave]: All methods can interleave\n    /// - [Reentrant]: Grain can process new requests while awaiting\n    /// \n    /// These tests focus on [ReadOnly] methods, which allow multiple read operations\n    /// to execute concurrently while maintaining data safety. This is crucial for:\n    /// - Improving throughput for read-heavy workloads\n    /// - Reducing latency when multiple clients read the same data\n    /// - Maintaining grain state consistency\n    /// </summary>\n    public class ConcurrencyTests : OrleansTestingBase, IClassFixture<ConcurrencyTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n        }\n\n        public ConcurrencyTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Tests that methods marked with [ReadOnly] can execute concurrently.\n        /// Sends 5 concurrent requests to a ReadOnly method and verifies they\n        /// all complete successfully without being serialized.\n        /// If these methods were not concurrent, they would execute sequentially,\n        /// taking much longer to complete.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ReadOnly\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task ConcurrencyTest_ReadOnly()\n        {\n            IConcurrentGrain first = this.fixture.GrainFactory.GetGrain<IConcurrentGrain>(GetRandomGrainId());\n            await first.Initialize(0);\n\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < 5; i++)\n            {\n                Task p = first.A();\n                promises.Add(p);\n            }\n            await Task.WhenAll(promises);\n        }\n\n        /// <summary>\n        /// Stress test for concurrent execution with collection return values.\n        /// Verifies that:\n        /// - Multiple concurrent calls can safely return collections\n        /// - Orleans properly handles deep copying of return values\n        /// - No data corruption occurs under high concurrency (2000 iterations × 20 concurrent calls)\n        /// \n        /// This test is important because returning mutable collections from concurrent\n        /// methods could lead to race conditions if not properly handled by the runtime.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ReadOnly\"), TestCategory(\"AsynchronyPrimitives\")]\n        public async Task ConcurrencyTest_ModifyReturnList()\n        {\n            IConcurrentGrain grain = this.fixture.GrainFactory.GetGrain<IConcurrentGrain>(GetRandomGrainId());\n\n            Task<List<int>>[] ll = new Task<List<int>>[20];\n            for (int i = 0; i < 2000; i++)\n            {\n                for (int j = 0; j < ll.Length; j++)\n                    ll[j] = grain.ModifyReturnList_Test();\n\n                await Task.WhenAll(ll);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ConnectionStringFixture.cs",
    "content": "using Xunit;\n\nnamespace UnitTests\n{\n    public class ConnectionStringFixture\n    {\n        private Lazy<Task<string>> connectionStringLazy;\n\n        public void InitializeConnectionStringAccessor(Func<Task<string>> connectionStringAccessor)\n        {\n            Interlocked.CompareExchange(ref this.connectionStringLazy,\n                new Lazy<Task<string>>(connectionStringAccessor, LazyThreadSafetyMode.ExecutionAndPublication), null);\n        }\n\n        public string ConnectionString\n        {\n            get\n            {\n                if (this.connectionStringLazy == null)\n                {\n                    throw new InvalidOperationException(\n                        $\"{nameof(InitializeConnectionStringAccessor)} was not called before accessing the connection string\");\n                }\n\n                var connString = this.connectionStringLazy.Value.GetAwaiter().GetResult();\n                if (connString != null)\n                {\n                    return connString;\n                }\n\n                throw new SkipException(\"Environment is not correctly set up to run these tests. Connection string is empty.\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ErrorInjectionStorageProvider.cs",
    "content": "using System.Runtime.Serialization;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Serialization;\n\nnamespace UnitTests.StorageTests\n{\n    [Serializable]\n    public enum ErrorInjectionPoint\n    {\n        Unknown = 0,\n        None = 1,\n        BeforeRead = 2,\n        AfterRead = 3,\n        BeforeWrite = 4,\n        AfterWrite = 5\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public struct ErrorInjectionBehavior\n    {\n        public static readonly ErrorInjectionBehavior None = new ErrorInjectionBehavior { ErrorInjectionPoint = ErrorInjectionPoint.None };\n\n        [Id(0)]\n        public Type ExceptionType { get; set; }\n        [Id(1)]\n        public ErrorInjectionPoint ErrorInjectionPoint { get; set; }\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class StorageProviderInjectedError : OrleansException\n    {\n        [Id(0)]\n        private readonly ErrorInjectionPoint errorInjectionPoint;\n\n        public StorageProviderInjectedError(ErrorInjectionPoint errorPoint)\n        {\n            errorInjectionPoint = errorPoint;\n        }\n\n        public StorageProviderInjectedError()\n        {\n            errorInjectionPoint = ErrorInjectionPoint.Unknown;\n        }\n\n        public override string Message\n        {\n            get\n            {\n                return \"ErrorInjectionPoint=\" + Enum.GetName(typeof(ErrorInjectionPoint), errorInjectionPoint);\n            }\n        }\n\n        [Obsolete]\n        protected StorageProviderInjectedError(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n        }\n\n        protected StorageProviderInjectedError(string message) : base(message)\n        {\n        }\n\n        protected StorageProviderInjectedError(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n\n    public class ErrorInjectionStorageProvider : MockStorageProvider, IControllable\n    {\n        private readonly ILogger logger;\n\n        public ErrorInjectionStorageProvider(\n            ILogger<ErrorInjectionStorageProvider> logger,\n            ILoggerFactory loggerFactory,\n            DeepCopier copier) : base(loggerFactory, copier)\n        {\n            this.logger = logger;\n            SetErrorInjection(ErrorInjectionBehavior.None);\n        }\n\n        public static async Task SetErrorInjection(string providerName, ErrorInjectionBehavior errorInjectionBehavior, IGrainFactory grainFactory)\n        {\n            IManagementGrain mgmtGrain = grainFactory.GetGrain<IManagementGrain>(0);\n            await mgmtGrain.SendControlCommandToProvider<ErrorInjectionStorageProvider>(\n                providerName, \n                (int)Commands.SetErrorInjection,\n                errorInjectionBehavior);\n        }\n\n        public ErrorInjectionBehavior ErrorInjection { get; private set; }\n\n        internal static bool DoInjectErrors = true;\n\n        public void SetErrorInjection(ErrorInjectionBehavior errorInject)\n        {\n            ErrorInjection = errorInject;\n            logger.LogInformation(\"Set ErrorInjection to {ErrorInjection}\", ErrorInjection);\n        }\n        \n        public async override Task Close()\n        {\n            logger.LogInformation(\"Close ErrorInjection={ErrorInjection}\", ErrorInjection);\n            try\n            {\n                SetErrorInjection(ErrorInjectionBehavior.None);\n                await base.Close();\n            }\n            catch (Exception exc)\n            {\n                logger.LogError(exc, \"Unexpected error during Close\");\n                throw;\n            }\n        }\n\n        public async override Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            logger.LogInformation( \"ReadStateAsync for {GrainType} {GrainId} ErrorInjection={ErrorInjection}\", grainType, grainId, ErrorInjection);\n            try\n            {\n                ThrowIfMatches(ErrorInjectionPoint.BeforeRead);\n                await base.ReadStateAsync(grainType, grainId, grainState);\n                ThrowIfMatches(ErrorInjectionPoint.AfterRead);\n            }\n            catch (Exception exc)\n            {\n                logger.LogWarning(exc, \"Injected error during ReadStateAsync for {GrainType} {GrainId}\", grainType, grainId);\n                throw;\n            }\n        }\n\n        public async override Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            logger.LogInformation(\"WriteStateAsync for {GrainType} {GrainReference} ErrorInjection={ErrorInjection}\", grainType, grainId, ErrorInjection);\n            try\n            {\n                ThrowIfMatches(ErrorInjectionPoint.BeforeWrite);\n                await base.WriteStateAsync(grainType, grainId, grainState);\n                ThrowIfMatches(ErrorInjectionPoint.AfterWrite);\n            }\n            catch (Exception exc)\n            {\n                logger.LogWarning(exc, \"Injected error during WriteStateAsync for {GrainType} {GrainId}\", grainType, grainId);\n                throw;\n            }\n        }\n\n        private void ThrowIfMatches(ErrorInjectionPoint executingPoint)\n        {\n            if (DoInjectErrors && ErrorInjection.ErrorInjectionPoint == executingPoint)\n            {\n                if (ErrorInjection.ExceptionType == null || ErrorInjection.ExceptionType == typeof(StorageProviderInjectedError))\n                {\n                    throw new StorageProviderInjectedError(ErrorInjection.ErrorInjectionPoint);\n                }\n                else\n                {\n                    throw ((Exception)Activator.CreateInstance(ErrorInjection.ExceptionType));\n                }\n            }\n        }\n\n        /// <summary>\n        /// A function to execute a control command.\n        /// </summary>\n        /// <param name=\"command\">A serial number of the command.</param>\n        /// <param name=\"arg\">An opaque command argument</param>\n        public override Task<object> ExecuteCommand(int command, object arg)\n        { \n            switch ((Commands)command)\n            {\n                case Commands.SetErrorInjection:\n                    SetErrorInjection((ErrorInjectionBehavior)arg);\n                    return Task.FromResult<object>(true);\n                default:\n                    return base.ExecuteCommand(command, arg);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/GatewaySelectionTest.cs",
    "content": "//#define USE_SQL_SERVER\nusing System.Net;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.Internal;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.MessageCenterTests\n{\n    /// <summary>\n    /// Tests for Orleans gateway selection and load balancing mechanisms.\n    /// \n    /// Gateways are the entry points for client connections to an Orleans cluster.\n    /// Each silo can act as a gateway, and clients need to:\n    /// - Discover available gateways (via IGatewayListProvider)\n    /// - Select which gateway to connect to\n    /// - Handle gateway failures by switching to another gateway\n    /// \n    /// The GatewayManager implements a round-robin selection strategy to distribute\n    /// client connections evenly across available gateways. This is critical for:\n    /// - Load balancing client connections\n    /// - Avoiding gateway overload\n    /// - Providing high availability for client access\n    /// \n    /// These tests verify that gateway selection distributes load evenly.\n    /// </summary>\n    public class GatewaySelectionTest\n    {\n        protected readonly ITestOutputHelper output;\n\n        protected static readonly List<Uri> gatewayAddressUris = new[]\n        {\n            new Uri(\"gwy.tcp://127.0.0.1:1/0\"),\n            new Uri(\"gwy.tcp://127.0.0.1:2/0\"),\n            new Uri(\"gwy.tcp://127.0.0.1:3/0\"),\n            new Uri(\"gwy.tcp://127.0.0.1:4/0\")\n        }.ToList();\n        \n        public GatewaySelectionTest(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests that the gateway manager properly distributes connections\n        /// across available gateways using round-robin selection.\n        /// Verifies even distribution across 4 test gateways.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Gateway\")]\n        public async Task GatewaySelection()\n        {\n            var listProvider = new TestListProvider(gatewayAddressUris);\n            await Test_GatewaySelection(listProvider);\n        }\n\n        /// <summary>\n        /// Core test logic for gateway selection distribution.\n        /// Simulates 2300 gateway selections and verifies they are evenly distributed.\n        /// </summary>\n        protected async Task Test_GatewaySelection(IGatewayListProvider listProvider)\n        {\n            IList<Uri> gatewayUris = await listProvider.GetGateways();\n            Assert.True(gatewayUris.Count > 0, $\"Found some gateways. Data = {Utils.EnumerableToString(gatewayUris)}\");\n\n            var gatewayEndpoints = gatewayUris.Select(uri =>\n            {\n                return new IPEndPoint(IPAddress.Parse(uri.Host), uri.Port);\n            }).ToList();\n\n            // Create and start the gateway manager with our test gateway list\n            var gatewayManager = new GatewayManager(Options.Create(new GatewayOptions()), listProvider, NullLoggerFactory.Instance, null, TimeProvider.System);\n            await gatewayManager.StartAsync(CancellationToken.None);\n\n            var counts = new int[4];  // Track selections per gateway\n\n            // Simulate 2300 gateway selections to test distribution\n            for (int i = 0; i < 2300; i++)\n            {\n                var ip = gatewayManager.GetLiveGateway();\n                Assert.NotNull(ip);\n                var addr = ip.Endpoint.Address;\n                Assert.Equal(IPAddress.Loopback, addr);  // \"Incorrect IP address returned for gateway\"\n                Assert.True((0 < ip.Endpoint.Port) && (ip.Endpoint.Port < 5), \"Incorrect IP port returned for gateway\");\n                counts[ip.Endpoint.Port - 1]++;  // Count selections per gateway\n            }\n\n            // Historical note: The gateway manager used to select randomly based on load,\n            // but now uses round-robin for more predictable distribution.\n            // The commented assertions show the old expected distribution patterns.\n\n            // With round-robin selection, we expect exactly even distribution\n            // 2300 selections / 4 gateways = 575 per gateway\n            int low = 2300 / 4;\n            int up = 2300 / 4;\n            Assert.True((low <= counts[0]) && (counts[0] <= up), \"Gateway selection is incorrectly skewed. \" + counts[0]);\n            Assert.True((low <= counts[1]) && (counts[1] <= up), \"Gateway selection is incorrectly skewed. \" + counts[1]);\n            Assert.True((low <= counts[2]) && (counts[2] <= up), \"Gateway selection is incorrectly skewed. \" + counts[2]);\n            Assert.True((low <= counts[3]) && (counts[3] <= up), \"Gateway selection is incorrectly skewed. \" + counts[3]);\n        }\n\n        /// <summary>\n        /// Test implementation of IGatewayListProvider that returns a fixed list of gateways.\n        /// In production, this interface is implemented by membership providers\n        /// (Azure Table, SQL, ZooKeeper, etc.) to dynamically discover available gateways.\n        /// </summary>\n        private class TestListProvider : IGatewayListProvider\n        {\n            private readonly IList<Uri> list;\n\n            public TestListProvider(List<Uri> gatewayUris)\n            {\n                list = gatewayUris;\n            }\n\n            public Task<IList<Uri>> GetGateways()\n            {\n                return Task.FromResult(list);\n            }\n\n            public TimeSpan MaxStaleness\n            {\n                get { return TimeSpan.FromMinutes(1); }\n            }\n\n            public bool IsUpdatable\n            {\n                get { return false; }\n            }\n            public Task InitializeGatewayListProvider()\n            {\n                return Task.CompletedTask;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/General/ConsistentRingProviderTests_Silo.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ReminderService;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.TestHelper;\nusing Xunit;\nusing Xunit.Sdk;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for the consistent ring provider's behavior during silo failures and joins.\n    /// </summary>\n    public class ConsistentRingProviderTests_Silo : TestClusterPerTest\n    {\n        private const int numAdditionalSilos = 3;\n        private readonly TimeSpan failureTimeout = TimeSpan.FromSeconds(30);\n        private readonly TimeSpan endWait = TimeSpan.FromMinutes(5);\n\n        private enum Fail { First, Random, Last }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<Configurator>();\n            builder.AddClientBuilderConfigurator<Configurator>();\n        }\n\n        private class Configurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddMemoryGrainStorage(\"MemoryStore\")\n                    .AddMemoryGrainStorageAsDefault()\n                    .UseInMemoryReminderService();\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<GatewayOptions>(\n                    options => options.GatewayListRefreshPeriod = TimeSpan.FromMilliseconds(100));\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_Basic()\n        {\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            await VerificationScenario(0);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1F_Random()\n        {\n            await FailureTest(Fail.Random, 1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1F_Beginning()\n        {\n            await FailureTest(Fail.First, 1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1F_End()\n        {\n            await FailureTest(Fail.Last, 1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_2F_Random()\n        {\n            await FailureTest(Fail.Random, 2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_2F_Beginning()\n        {\n            await FailureTest(Fail.First, 2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_2F_End()\n        {\n            await FailureTest(Fail.Last, 2);\n        }\n\n        private async Task FailureTest(Fail failCode, int numOfFailures)\n        {\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            List<SiloHandle> failures = await getSilosToFail(failCode, numOfFailures);\n            foreach (SiloHandle fail in failures) // verify before failure\n            {\n                await VerificationScenario(PickKey(fail.SiloAddress)); // fail.SiloAddress.GetConsistentHashCode());\n            }\n\n            logger.LogInformation(\n                \"FailureTest {FailureCount}, Code {FailureCode}, Stopping silos: {SiloAddresses}\",\n                numOfFailures,\n                failCode,\n                Utils.EnumerableToString(failures, handle => handle.SiloAddress.ToString()));\n            List<uint> keysToTest = new List<uint>();\n            foreach (SiloHandle fail in failures) // verify before failure\n            {\n                keysToTest.Add(PickKey(fail.SiloAddress)); //fail.SiloAddress.GetConsistentHashCode());\n                await this.HostedCluster.StopSiloAsync(fail);\n            }\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            await AssertEventually(async () =>\n            {\n                foreach (var key in keysToTest) // verify after failure\n                {\n                    await VerificationScenario(key);\n                }\n            }, failureTimeout);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1J()\n        {\n            await JoinTest(1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_2J()\n        {\n            await JoinTest(2);\n        }\n\n        private async Task JoinTest(int numOfJoins)\n        {\n            logger.LogInformation(\"JoinTest {NumOfJoins}\", numOfJoins);\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos - numOfJoins);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            List<SiloHandle> silos = await this.HostedCluster.StartAdditionalSilosAsync(numOfJoins);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            foreach (SiloHandle sh in silos)\n            {\n                await VerificationScenario(PickKey(sh.SiloAddress));\n            }\n            Thread.Sleep(TimeSpan.FromSeconds(15));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1F1J()\n        {\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            List<SiloHandle> failures = await getSilosToFail(Fail.Random, 1);\n            uint keyToCheck = PickKey(failures[0].SiloAddress);// failures[0].SiloAddress.GetConsistentHashCode();\n            List<SiloHandle> joins = null;\n\n            // kill a silo and join a new one in parallel\n            logger.LogInformation(\"Killing silo {SiloAddress} and joining a silo\", failures[0].SiloAddress);\n\n            var tasks = new Task[2]\n            {\n                Task.Factory.StartNew(() => this.HostedCluster.StopSiloAsync(failures[0])),\n                this.HostedCluster.StartAdditionalSilosAsync(1).ContinueWith(t => joins = t.GetAwaiter().GetResult())\n            };\n            await Task.WhenAll(tasks).WaitAsync(endWait);\n\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            await AssertEventually(async () =>\n            {\n                await VerificationScenario(keyToCheck); // verify failed silo's key\n                await VerificationScenario(PickKey(joins[0].SiloAddress)); // verify newly joined silo's key\n            }, failureTimeout);\n        }\n\n        // failing the secondary in this scenario exposed the bug in DomainGrain ... so, we keep it as a separate test than Ring_1F1J\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Ring\")]\n        public async Task Ring_1Fsec1J()\n        {\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n            //List<SiloHandle> failures = getSilosToFail(Fail.Random, 1);\n            SiloHandle fail = this.HostedCluster.SecondarySilos.First();\n            uint keyToCheck = PickKey(fail.SiloAddress); //fail.SiloAddress.GetConsistentHashCode();\n            List<SiloHandle> joins = null;\n\n            // kill a silo and join a new one in parallel\n            logger.LogInformation(\"Killing secondary silo {SiloAddress} and joining a silo\", fail.SiloAddress);\n            var tasks = new Task[2]\n            {\n                Task.Factory.StartNew(() => this.HostedCluster.StopSiloAsync(fail)),\n                this.HostedCluster.StartAdditionalSilosAsync(1).ContinueWith(t => joins = t.GetAwaiter().GetResult())\n            };\n            await Task.WhenAll(tasks).WaitAsync(endWait);\n\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            await AssertEventually(async () =>\n            {\n                await VerificationScenario(keyToCheck); // verify failed silo's key\n                await VerificationScenario(PickKey(joins[0].SiloAddress));\n            }, failureTimeout);\n        }\n\n        private uint PickKey(SiloAddress responsibleSilo)\n        {\n            int iteration = 10000;\n            var testHooks = this.Client.GetTestHooks(this.HostedCluster.Primary);\n            for (int i = 0; i < iteration; i++)\n            {\n                double next = Random.Shared.NextDouble();\n                uint randomKey = (uint)((double)RangeFactory.RING_SIZE * next);\n                SiloAddress s = testHooks.GetConsistentRingPrimaryTargetSilo(randomKey).Result;\n                if (responsibleSilo.Equals(s))\n                    return randomKey;\n            }\n            throw new Exception(string.Format(\"Could not pick a key that silo {0} will be responsible for. Primary.Ring = \\n{1}\",\n                responsibleSilo, testHooks.GetConsistentRingProviderDiagnosticInfo().Result));\n        }\n\n        private async Task VerificationScenario(uint testKey)\n        {\n            // setup\n            List<SiloAddress> silos = new List<SiloAddress>();\n\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos())\n            {\n                long hash = siloHandle.SiloAddress.GetConsistentHashCode();\n                int index = silos.FindLastIndex(siloAddr => siloAddr.GetConsistentHashCode() < hash) + 1;\n                silos.Insert(index, siloHandle.SiloAddress);\n            }\n\n            // verify parameter key\n            await VerifyKey(testKey, silos);\n            // verify some other keys as well, apart from the parameter key            \n            // some random keys\n            for (int i = 0; i < 3; i++)\n            {\n                await VerifyKey((uint)Random.Shared.Next(), silos);\n            }\n            // lowest key\n            uint lowest = (uint)(silos.First().GetConsistentHashCode() - 1);\n            await VerifyKey(lowest, silos);\n            // highest key\n            uint highest = (uint)(silos.Last().GetConsistentHashCode() + 1);\n            await VerifyKey(lowest, silos);\n        }\n\n        private async Task VerifyKey(uint key, List<SiloAddress> silos)\n        {\n            var testHooks = this.Client.GetTestHooks(this.HostedCluster.Primary);\n            SiloAddress truth = testHooks.GetConsistentRingPrimaryTargetSilo(key).Result; //expected;\n            //if (truth == null) // if the truth isn't passed, we compute it here\n            //{\n            //    truth = silos.Find(siloAddr => (key <= siloAddr.GetConsistentHashCode()));\n            //    if (truth == null)\n            //    {\n            //        truth = silos.First();\n            //    }\n            //}\n\n            // lookup for 'key' should return 'truth' on all silos\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos()) // do this for each silo\n            {\n                testHooks = this.Client.GetTestHooks(siloHandle);\n                SiloAddress s = await testHooks.GetConsistentRingPrimaryTargetSilo((uint)key);\n                Assert.Equal(truth, s);\n            }\n        }\n\n        private async Task<List<SiloHandle>> getSilosToFail(Fail fail, int numOfFailures)\n        {\n            List<SiloHandle> failures = new List<SiloHandle>();\n            int count = 0;\n\n            // Figure out the primary directory partition and the silo hosting the ReminderTableGrain.\n            var tableGrain = this.GrainFactory.GetGrain<IReminderTableGrain>(InMemoryReminderTable.ReminderTableGrainId);\n            var tableGrainId = ((GrainReference)tableGrain).GrainId;\n\n            // Ping the grain to make sure it is active.\n            await tableGrain.ReadRows(tableGrainId);\n\n            SiloAddress reminderTableGrainPrimaryDirectoryAddress = (await TestUtils.GetDetailedGrainReport(this.HostedCluster.InternalGrainFactory, tableGrainId, this.HostedCluster.Primary)).PrimaryForGrain;\n            // ask a detailed report from the directory partition owner, and get the activation addresses\n            var address = (await TestUtils.GetDetailedGrainReport(this.HostedCluster.InternalGrainFactory, tableGrainId, this.HostedCluster.GetSiloForAddress(reminderTableGrainPrimaryDirectoryAddress))).LocalDirectoryActivationAddress;\n            GrainAddress reminderGrainActivation = address;\n\n            SortedList<int, SiloHandle> ids = new SortedList<int, SiloHandle>();\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos())\n            {\n                SiloAddress siloAddress = siloHandle.SiloAddress;\n                if (siloAddress.Equals(this.HostedCluster.Primary.SiloAddress))\n                {\n                    continue;\n                }\n                // Don't fail primary directory partition and the silo hosting the ReminderTableGrain.\n                if (siloAddress.Equals(reminderTableGrainPrimaryDirectoryAddress) || siloAddress.Equals(reminderGrainActivation.SiloAddress))\n                {\n                    continue;\n                }\n                ids.Add(siloHandle.SiloAddress.GetConsistentHashCode(), siloHandle);\n            }\n\n            int index;\n            // we should not fail the primary!\n            // we can't guarantee semantics of 'Fail' if it evalutes to the primary's address\n            switch (fail)\n            {\n                case Fail.First:\n                    index = 0;\n                    while (count++ < numOfFailures)\n                    {\n                        while (failures.Contains(ids.Values[index]))\n                        {\n                            index++;\n                        }\n                        failures.Add(ids.Values[index]);\n                    }\n                    break;\n                case Fail.Last:\n                    index = ids.Count - 1;\n                    while (count++ < numOfFailures)\n                    {\n                        while (failures.Contains(ids.Values[index]))\n                        {\n                            index--;\n                        }\n                        failures.Add(ids.Values[index]);\n                    }\n                    break;\n                case Fail.Random:\n                default:\n                    while (count++ < numOfFailures)\n                    {\n                        SiloHandle r = ids.Values[Random.Shared.Next(ids.Count)];\n                        while (failures.Contains(r))\n                        {\n                            r = ids.Values[Random.Shared.Next(ids.Count)];\n                        }\n                        failures.Add(r);\n                    }\n                    break;\n            }\n            return failures;\n        }\n\n        // for debugging only\n        private void printSilos(string msg)\n        {\n            SortedList<int, SiloAddress> ids = new SortedList<int, SiloAddress>(numAdditionalSilos + 2);\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos())\n            {\n                ids.Add(siloHandle.SiloAddress.GetConsistentHashCode(), siloHandle.SiloAddress);\n            }\n            logger.LogInformation(\"{Message} list of silos: \", msg);\n            foreach (var id in ids.Keys.ToList())\n            {\n                logger.LogInformation(\"{From} -> {To}\", ids[id], id);\n            }\n        }\n\n        private static async Task AssertEventually(Func<Task> assertion, TimeSpan timeout)\n        {\n            await AssertEventually(assertion, timeout, TimeSpan.FromMilliseconds(500));\n        }\n\n        private static async Task AssertEventually(Func<Task> assertion, TimeSpan timeout, TimeSpan delayBetweenIterations)\n        {\n            var sw = Stopwatch.StartNew();\n\n            while (true)\n            {\n                try\n                {\n                    await assertion();\n                    return;\n                }\n                catch (XunitException)\n                {\n                    if (sw.ElapsedMilliseconds > timeout.TotalMilliseconds)\n                    {\n                        throw;\n                    }\n                }\n\n                if (delayBetweenIterations > TimeSpan.Zero)\n                {\n                    Thread.Sleep(delayBetweenIterations);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/General/RequestContextTest.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Tester;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for request context propagation across grain calls and activities.\n    /// </summary>\n    public class RequestContextTests_Silo : OrleansTestingBase, IClassFixture<RequestContextTests_Silo.Fixture>, IDisposable\n    {\n        private readonly ITestOutputHelper output;\n        private readonly Fixture fixture;\n        private readonly OutsideRuntimeClient runtimeClient;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n            }\n        }\n\n        public RequestContextTests_Silo(ITestOutputHelper output, Fixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n            this.runtimeClient = this.fixture.Client.ServiceProvider.GetRequiredService<OutsideRuntimeClient>();\n\n            RequestContextTestUtils.ClearActivityId();\n            RequestContext.Clear();\n        }\n        \n        public void Dispose()\n        {\n            RequestContextTestUtils.ClearActivityId();\n            RequestContext.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_Simple()\n        {\n            Guid activityId = Guid.NewGuid();\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            RequestContextTestUtils.SetActivityId(activityId);\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(activityId,  result);  // \"E2E ActivityId not propagated correctly\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_AC_Test1()\n        {\n            long id = GetRandomGrainId();\n            const string key = \"TraceId\";\n            string val = \"TraceValue-\" + id;\n            string val2 = val + \"-2\";\n\n            var grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(id);\n\n            RequestContext.Set(key, val);\n            var result = await grain.TraceIdEcho();\n            Assert.Equal(val,  result);  // \"Immediate RequestContext echo was not correct\"\n\n            RequestContext.Set(key, val2);\n            result = await grain.TraceIdDoubleEcho();\n            Assert.Equal(val2,  result);  // \"Transitive RequestContext echo was not correct\"\n\n            RequestContext.Set(key, val);\n            result = await grain.TraceIdDelayedEcho1();\n            Assert.Equal(val,  result); // \"Delayed (StartNew) RequestContext echo was not correct\");\n\n            RequestContext.Set(key, val2);\n            result = await grain.TraceIdDelayedEcho2();\n            Assert.Equal(val2,  result); // \"Delayed (ContinueWith) RequestContext echo was not correct\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_Task_Test1()\n        {\n            long id = GetRandomGrainId();\n            const string key = \"TraceId\";\n            string val = \"TraceValue-\" + id;\n            string val2 = val + \"-2\";\n\n            var grain = this.fixture.GrainFactory.GetGrain<IRequestContextTaskGrain>(id);\n\n            RequestContext.Set(key, val);\n            var result = await grain.TraceIdEcho();\n            Assert.Equal(val,  result);  // \"Immediate RequestContext echo was not correct\"\n\n            RequestContext.Set(key, val2);\n            result = await grain.TraceIdDoubleEcho();\n            Assert.Equal(val2,  result);  // \"Transitive RequestContext echo was not correct\"\n\n            RequestContext.Set(key, val);\n            result = await grain.TraceIdDelayedEcho1();\n            Assert.Equal(val,  result); // \"Delayed (StartNew) RequestContext echo was not correct\");\n\n            RequestContext.Set(key, val2);\n            result = await grain.TraceIdDelayedEcho2();\n            Assert.Equal(val2,  result); // \"Delayed (ContinueWith) RequestContext echo was not correct\");\n\n            RequestContext.Set(key, val);\n            result = await grain.TraceIdDelayedEchoAwait();\n            Assert.Equal(val,  result); // \"Delayed (Await) RequestContext echo was not correct\");\n\n            // Expected behaviour is this won't work, because Task.Run by design does not use Orleans task scheduler\n            //RequestContext.Set(key, val2);\n            //result = await grain.TraceIdDelayedEchoTaskRun();\n            //Assert.Equal(val2,  result); // \"Delayed (Task.Run) RequestContext echo was not correct\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_Task_TestRequestContext()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IRequestContextTaskGrain>(1);\n            Tuple<string, string> requestContext = await grain.TestRequestContext();\n            this.fixture.Logger.LogInformation(\"Request Context is: {RequestContext}\", requestContext);\n            Assert.Equal(\"binks\",  requestContext.Item1);  // \"Item1=\" + requestContext.Item1\n            Assert.Equal(\"binks\",  requestContext.Item2);  // \"Item2=\" + requestContext.Item2\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_RC_Set_E2E()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n            Guid nullActivityId = Guid.Empty;\n\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            RequestContext.Set(RequestContext.CALL_CHAIN_REENTRANCY_HEADER, activityId);\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(activityId,  result);  // \"E2E ActivityId not propagated correctly\"\n            RequestContext.Clear();\n\n            RequestContext.Set(RequestContext.CALL_CHAIN_REENTRANCY_HEADER, nullActivityId);\n            result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            RequestContext.Clear();\n\n            RequestContext.Set(RequestContext.CALL_CHAIN_REENTRANCY_HEADER, activityId2);\n            result = await grain.E2EActivityId();\n            Assert.Equal(activityId2,  result);  // \"E2E ActivityId 2 not propagated correctly\"\n            RequestContext.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_CM_E2E()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n            Guid nullActivityId = Guid.Empty;\n\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            RequestContext.ReentrancyId = activityId;\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(activityId, result);  // \"E2E ActivityId not propagated correctly\"\n            RequestContext.Clear();\n\n            RequestContext.ReentrancyId = nullActivityId;\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            for (int i = 0; i < Environment.ProcessorCount; i++)\n            {\n                result = await grain.E2EActivityId();\n                Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            }\n            RequestContext.Clear();\n\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            RequestContext.ReentrancyId = activityId2;\n            result = await grain.E2EActivityId();\n            Assert.Equal(activityId2,  result);  // \"E2E ActivityId 2 not propagated correctly\"\n            RequestContext.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_CM_E2E_ViaProxy()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n            Guid nullActivityId = Guid.Empty;\n\n            IRequestContextProxyGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextProxyGrain>(GetRandomGrainId());\n\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            RequestContext.ReentrancyId = activityId;\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(activityId,  result);  // \"E2E ActivityId not propagated correctly\"\n            RequestContext.Clear();\n\n            RequestContext.ReentrancyId = nullActivityId;\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            for (int i = 0; i < Environment.ProcessorCount; i++)\n            {\n                result = await grain.E2EActivityId();\n                Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            }\n            RequestContext.Clear();\n\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            RequestContext.ReentrancyId = activityId2;\n            result = await grain.E2EActivityId();\n            Assert.Equal(activityId2,  result);  // \"E2E ActivityId 2 not propagated correctly\"\n            RequestContext.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_RC_None_E2E()\n        {\n            Guid nullActivityId = Guid.Empty;\n\n            RequestContext.Clear();\n\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"E2E ActivityId should not exist\"\n\n            result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            RequestContext.Clear();\n\n            result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"E2E ActivityId 2 should not exist\"\n            Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));  // \"No ActivityId context should be set\"\n\n            for (int i = 0; i < Environment.ProcessorCount; i++)\n            {\n                Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));  // \"No ActivityId context should be set\"\n\n                result = await grain.E2EActivityId();\n\n                Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n\n                RequestContext.Clear();\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_CM_None_E2E()\n        {\n            Guid nullActivityId = Guid.Empty;\n\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"E2E ActivityId should not exist\"\n\n            RequestContextTestUtils.SetActivityId(nullActivityId);\n           Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            RequestContext.Clear();\n\n            RequestContextTestUtils.SetActivityId(nullActivityId);\n           Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            for (int i = 0; i < Environment.ProcessorCount; i++)\n            {\n                result = await grain.E2EActivityId();\n                Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            }\n            RequestContext.Clear();\n            RequestContextTestUtils.SetActivityId(nullActivityId);\n           Assert.Null(RequestContext.Get(RequestContext.CALL_CHAIN_REENTRANCY_HEADER));\n            result = await grain.E2EActivityId();\n            Assert.Equal(nullActivityId,  result);  // \"Null ActivityId propagated E2E incorrectly\"\n            RequestContext.Clear();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task RequestContext_ActivityId_CM_DynamicChange_Client()\n        {\n            Guid activityId = Guid.NewGuid();\n            Guid activityId2 = Guid.NewGuid();\n\n            IRequestContextTestGrain grain = this.fixture.GrainFactory.GetGrain<IRequestContextTestGrain>(GetRandomGrainId());\n\n            RequestContext.ReentrancyId = activityId;\n            Guid result = await grain.E2EActivityId();\n            Assert.Equal(activityId,  result);  // \"E2E ActivityId #1 not propagated correctly\"\n            RequestContext.Clear();\n\n            using (RequestContext.SuppressCallChainReentrancy())\n            {\n                result = await grain.E2EActivityId();\n                Assert.Equal(Guid.Empty, result);  // \"E2E ActivityId #2 not not have been propagated\"\n                RequestContext.Clear();\n            }\n\n            RequestContext.ReentrancyId = activityId2;\n            result = await grain.E2EActivityId();\n            Assert.Equal(activityId2,  result);  // \"E2E ActivityId #2 should have been propagated\"\n            RequestContext.Clear();\n\n            RequestContext.ReentrancyId = activityId;\n            result = await grain.E2EActivityId();\n            Assert.Equal(activityId,  result);  // \"E2E ActivityId #1 not propagated correctly after #2\"\n            RequestContext.Clear();\n        }\n    }\n\n    internal class RequestContextGrainObserver : ISimpleGrainObserver\n    {\n        private readonly ITestOutputHelper output;\n        private readonly Action<int, int, object> action;\n        private readonly object result;\n\n        public RequestContextGrainObserver(ITestOutputHelper output, Action<int, int, object> action, object result)\n        {\n            this.output = output;\n            this.action = action;\n            this.result = result;\n        }\n\n        public void StateChanged(int a, int b)\n        {\n            output.WriteLine(\"RequestContextGrainObserver.StateChanged a={0} b={1}\", a, b);\n            this.action?.Invoke(a, b, this.result);\n        }\n    }\n\n    public class Halo_RequestContextTests : OrleansTestingBase\n    {\n        private readonly ITestOutputHelper output;\n\n        public Halo_RequestContextTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task Halo_RequestContextShouldBeMaintainedWhenThreadHoppingOccurs()\n        {\n            int numTasks = 20;\n            Task[] tasks = new Task[numTasks];\n\n            for (int i = 0; i < numTasks; i++)\n            {\n                var closureInt = i;\n                async Task func() { await ContextTester(closureInt); }\n                tasks[i] = Task.Run(func);\n            }\n\n            await Task.WhenAll(tasks);\n        }\n\n        private async Task ContextTester(int i)\n        {\n            RequestContext.Set(\"threadId\", i);\n            int contextId = (int)(RequestContext.Get(\"threadId\") ?? -1);\n            output.WriteLine(\"ExplicitId={0}, ContextId={2}, ManagedThreadId={1}\", i, Environment.CurrentManagedThreadId, contextId);\n            await FrameworkContextVerification(i).ConfigureAwait(false);\n        }\n\n        private async Task FrameworkContextVerification(int id)\n        {\n            for (int i = 0; i < 10; i++)\n            {\n                await Task.Delay(10);\n                int contextId = (int)(RequestContext.Get(\"threadId\") ?? -1);\n                output.WriteLine(\"Inner, in loop {0}, Explicit Id={2}, ContextId={3}, ManagedThreadId={1}\", i, Environment.CurrentManagedThreadId, id, contextId);\n                Assert.Equal(id, contextId);\n            }\n        }\n    }\n\n    public class Halo_CallContextTests : OrleansTestingBase\n    {\n        private readonly ITestOutputHelper output;\n\n        private readonly AsyncLocal<int> threadId = new AsyncLocal<int>();\n\n        public Halo_CallContextTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"RequestContext\")]\n        public async Task Halo_LogicalCallContextShouldBeMaintainedWhenThreadHoppingOccurs()\n        {\n            int numTasks = 20;\n            Task[] tasks = new Task[numTasks];\n\n            for (int i = 0; i < numTasks; i++)\n            {\n                var closureInt = i;\n                async Task func() { await ContextTester(closureInt); }\n                tasks[i] = Task.Run(func);\n            }\n\n            await Task.WhenAll(tasks);\n        }\n\n        private async Task ContextTester(int i)\n        {\n            threadId.Value = i;\n            int contextId = threadId.Value;\n            output.WriteLine(\"ExplicitId={0}, ContextId={2}, ManagedThreadId={1}\", i, Environment.CurrentManagedThreadId, contextId);\n            await FrameworkContextVerification(i).ConfigureAwait(false);\n        }\n\n        private async Task FrameworkContextVerification(int id)\n        {\n            for (int i = 0; i < 10; i++)\n            {\n                await Task.Delay(10);\n                int contextId = threadId.Value;\n                output.WriteLine(\"Inner, in loop {0}, Explicit Id={2}, ContextId={3}, ManagedThreadId={1}\", i, Environment.CurrentManagedThreadId, id, contextId);\n                Assert.Equal(id, contextId);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/GeoClusterTests/BasicLogTestGrainTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing Xunit;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing TestExtensions;\nusing Tester;\n\nusing Orleans.Configuration;\nusing Azure.Data.Tables;\nusing Azure.Identity;\n\nnamespace Tests.GeoClusterTests\n{\n    /// <summary>\n    /// Tests for log-based consistency providers with different storage configurations.\n    /// </summary>\n    [TestCategory(\"GeoCluster\"), TestCategory(\"Functional\")]\n    public class BasicLogTestGrainTests : IClassFixture<BasicLogTestGrainTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private readonly Random random;\n\n        public class Fixture : BaseAzureTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            }\n\n            private class SiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddStateStorageBasedLogConsistencyProvider()\n                        .AddLogStorageBasedLogConsistencyProvider()\n                        .AddCustomStorageBasedLogConsistencyProvider(\"CustomStorage\")\n                        .AddCustomStorageBasedLogConsistencyProvider(\"CustomStoragePrimaryCluster\", \"A\")\n                        .AddAzureTableGrainStorageAsDefault(builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                        {\n                            options.TableServiceClient = GetTableServiceClient();\n                        }))\n                        .AddAzureTableGrainStorage(\"AzureStore\", builder => builder.Configure<IOptions<ClusterOptions>>((options, silo) =>\n                        {\n                            options.TableServiceClient = GetTableServiceClient();\n                        }))\n                        .AddMemoryGrainStorage(\"MemoryStore\"); \n                }\n\n                private static TableServiceClient GetTableServiceClient()\n                {\n                    return TestDefaultConfiguration.UseAadAuthentication\n                        ? new(TestDefaultConfiguration.TableEndpoint, TestDefaultConfiguration.TokenCredential)\n                        : new(TestDefaultConfiguration.DataConnectionString);\n                }\n            }\n        }\n        \n        public BasicLogTestGrainTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            fixture.EnsurePreconditionsMet();\n            this.random = new Random();\n        }\n\n        [SkippableFact]\n        public async Task DefaultStorage()\n        {\n            await DoBasicLogTestGrainTest(\"TestGrains.LogTestGrainDefaultStorage\");\n        }\n        [SkippableFact]\n        public async Task MemoryStorage()\n        {\n            await DoBasicLogTestGrainTest(\"TestGrains.LogTestGrainMemoryStorage\");\n        }\n        [SkippableFact]\n        public async Task SharedStorage()\n        {\n            await DoBasicLogTestGrainTest(\"TestGrains.LogTestGrainSharedStateStorage\");\n        }\n        [SkippableFact]\n        public async Task SharedLogStorage()\n        {\n            await DoBasicLogTestGrainTest(\"TestGrains.LogTestGrainSharedLogStorage\");\n        }\n        [SkippableFact]\n        public async Task CustomStorage()\n        {\n            await DoBasicLogTestGrainTest(\"TestGrains.LogTestGrainCustomStorage\");\n        }\n\n        private int GetRandom()\n        {\n            lock (random)\n                return random.Next();\n        }\n\n\n        private async Task DoBasicLogTestGrainTest(string grainClass, int phases = 100)\n        {\n            await ThreeCheckers(grainClass, phases);\n        }\n\n        private async Task ThreeCheckers(string grainClass, int phases)\n        {\n            // Global \n            async Task checker1()\n            {\n                int x = GetRandom();\n                var grain = this.fixture.GrainFactory.GetGrain<ILogTestGrain>(x, grainClass);\n                await grain.SetAGlobal(x);\n                int a = await grain.GetAGlobal();\n                Assert.Equal(x, a); // value of A survive grain call\n                Assert.Equal(1, await grain.GetConfirmedVersion());\n            }\n\n            // Local\n            async Task checker2()\n            {\n                int x = GetRandom();\n                var grain = this.fixture.GrainFactory.GetGrain<ILogTestGrain>(x, grainClass);\n                Assert.Equal(0, await grain.GetConfirmedVersion());\n                await grain.SetALocal(x);\n                int a = await grain.GetALocal();\n                Assert.Equal(x, a); // value of A survive grain call\n            }\n\n            // Local then Global\n            async Task checker3()\n            {\n                // Local then Global\n                int x = GetRandom();\n                var grain = this.fixture.GrainFactory.GetGrain<ILogTestGrain>(x, grainClass);\n                await grain.SetALocal(x);\n                int a = await grain.GetAGlobal();\n                Assert.Equal(x, a);\n                Assert.Equal(1, await grain.GetConfirmedVersion());\n            }\n\n            // test them in sequence\n            await checker1();\n            await checker2();\n            await checker3();\n\n            // test (phases) instances of each checker, all in parallel\n            var tasks = new List<Task>();\n            for (int i = 0; i < phases; i++)\n            {\n                tasks.Add(checker1());\n                tasks.Add(checker2());\n                tasks.Add(checker3());\n            }\n            await Task.WhenAll(tasks);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/GrainDirectoryPartitionTests.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Xunit;\n\nnamespace UnitTests;\n\n/// <summary>\n/// Tests for the Orleans grain directory partition functionality.\n/// \n/// The grain directory is a distributed data structure that maps grain identities\n/// to their current activation locations (silo addresses). Key concepts:\n/// \n/// - Single activation constraint: Each grain ID should have at most one activation\n/// - Directory partitioning: The directory is partitioned across silos for scalability\n/// - Silo death handling: Dead silo entries must be cleaned up to allow new activations\n/// - Race condition handling: Concurrent activation requests must be properly synchronized\n/// \n/// These tests verify critical scenarios:\n/// - Overriding entries pointing to dead silos\n/// - Preventing duplicate activations on live silos\n/// - Conditional updates using previousAddress parameter\n/// - Filtering out entries for dead silos during lookups\n/// \n/// This is essential for maintaining Orleans' single activation guarantee.\n/// </summary>\n[TestCategory(\"BVT\"), TestCategory(\"GrainDirectory\")]\npublic class GrainDirectoryPartitionTests\n{\n    private readonly LocalGrainDirectoryPartition _target;\n    private readonly MockSiloStatusOracle _siloStatusOracle;\n    private static readonly SiloAddress LocalSiloAddress =  SiloAddress.FromParsableString(\"127.0.0.1:11111@123\");\n    private static readonly SiloAddress OtherSiloAddress =  SiloAddress.FromParsableString(\"127.0.0.2:11111@456\");\n\n    public GrainDirectoryPartitionTests()\n    {\n        _siloStatusOracle = new MockSiloStatusOracle();\n        _target = new LocalGrainDirectoryPartition(\n            _siloStatusOracle,\n            Options.Create(new GrainDirectoryOptions()),\n            new LoggerFactory());\n    }\n\n    /// <summary>\n    /// Tests that directory entries pointing to dead silos can be overridden.\n    /// When a silo dies, its grain activations become invalid. The directory\n    /// must allow new activations to replace these dead entries to maintain\n    /// availability. This is crucial for recovery after silo failures.\n    /// </summary>\n    [Fact]\n    public void OverrideDeadEntryTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Active);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var firstGrainAddress = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n\n        // Insert valid entry, pointing to valid silo\n        var firstRegister = _target.AddSingleActivation(firstGrainAddress, previousAddress: null);\n        Assert.Equal(firstGrainAddress, firstRegister.Address);\n\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Dead);\n\n        // Previous entry is now pointing to a dead silo, it should be possible to override it now\n        var secondGrainAddress = GrainAddress.NewActivationAddress(LocalSiloAddress, grainId);\n        var secondRegister = _target.AddSingleActivation(secondGrainAddress, previousAddress: null);\n        Assert.Equal(secondGrainAddress, secondRegister.Address);\n    }\n\n    /// <summary>\n    /// Verifies that the directory rejects attempts to register activations\n    /// on silos that are already known to be dead. This prevents creating\n    /// entries that would immediately be invalid, avoiding unnecessary\n    /// cleanup work and potential race conditions.\n    /// </summary>\n    [Fact]\n    public void DoNotInsertInvalidEntryTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Dead);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var grainAddress = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n\n        // Insert invalid entry, pointing to dead silo\n       Assert.Throws<OrleansException>(() => _target.AddSingleActivation(grainAddress, previousAddress: null));\n    }\n\n    /// <summary>\n    /// Tests the single activation guarantee by ensuring valid entries\n    /// cannot be overridden by new activation attempts. This prevents\n    /// duplicate activations when multiple silos try to activate the\n    /// same grain concurrently.\n    /// </summary>\n    [Fact]\n    public void DoNotOverrideValidEntryTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Active);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var grainAddress = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n\n        // Insert valid entry, pointing to valid silo\n        var register = _target.AddSingleActivation(grainAddress, previousAddress: null);\n        Assert.Equal(grainAddress, register.Address);\n\n        // Previous entry is still valid, it should not be possible to override it\n        var newGrainAddress = GrainAddress.NewActivationAddress(LocalSiloAddress, grainId);\n        var newRegister = _target.AddSingleActivation(newGrainAddress, previousAddress: null);\n        Assert.Equal(grainAddress, newRegister.Address);\n    }\n\n    /// <summary>\n    /// Tests conditional update functionality using the previousAddress parameter.\n    /// This allows explicit handoff scenarios where an activation is intentionally\n    /// moved from one silo to another, but only if the current state matches\n    /// expectations (optimistic concurrency control).\n    /// </summary>\n    [Fact]\n    public void OverrideValidEntryIfMatchesTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Active);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var grainAddress = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n\n        // Insert valid entry, pointing to valid silo\n        var register = _target.AddSingleActivation(grainAddress, previousAddress: null);\n        Assert.Equal(grainAddress, register.Address);\n\n        // Previous entry is still valid, but it should be possible to override it we provide it as the \"previousAddress\" to the AddSingleActivation call.\n        var newGrainAddress = GrainAddress.NewActivationAddress(LocalSiloAddress, grainId);\n        var newRegister = _target.AddSingleActivation(newGrainAddress, previousAddress: grainAddress);\n        Assert.Equal(newGrainAddress, newRegister.Address);\n    }\n\n    /// <summary>\n    /// Verifies that conditional updates fail when the previousAddress doesn't\n    /// match the current entry. This prevents race conditions where the directory\n    /// state changed between read and update operations, ensuring consistency\n    /// in distributed scenarios.\n    /// </summary>\n    [Fact]\n    public void DoNotOverrideValidEntryIfNoMatchTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Active);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var grainAddress = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n        var nonMatchingAddress = new GrainAddress\n        {\n            GrainId = grainAddress.GrainId,\n            ActivationId = ActivationId.NewId(),\n            SiloAddress = OtherSiloAddress,\n            MembershipVersion = new MembershipVersion(grainAddress.MembershipVersion.Value + 1),\n        };\n\n        // Insert valid entry, pointing to valid silo\n        var register = _target.AddSingleActivation(grainAddress, previousAddress: null);\n        Assert.Equal(grainAddress, register.Address);\n\n        // Previous entry is still valid and we provided a non-matching previousAddress, so the existing value should not be overridden.\n        var newGrainAddress = GrainAddress.NewActivationAddress(LocalSiloAddress, grainId);\n        var newRegister = _target.AddSingleActivation(newGrainAddress, previousAddress: nonMatchingAddress);\n        Assert.Equal(grainAddress, newRegister.Address);\n    }\n\n    /// <summary>\n    /// Tests that lookups filter out entries pointing to dead silos.\n    /// Even if the directory contains stale entries, lookups should\n    /// return null rather than invalid addresses, allowing the caller\n    /// to create a new activation on a healthy silo.\n    /// </summary>\n    [Fact]\n    public void DoNotReturnInvalidEntryTest()\n    {\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Active);\n\n        var grainId = GrainId.Create(\"testGrain\", \"myKey\");\n        var grainAddress1 = GrainAddress.NewActivationAddress(OtherSiloAddress, grainId);\n\n        // Insert valid entry, pointing to valid silo\n        var register1 = _target.AddSingleActivation(grainAddress1, previousAddress: null);\n        Assert.Equal(grainAddress1, register1.Address);\n\n        _siloStatusOracle.SetSiloStatus(OtherSiloAddress, SiloStatus.Dead);\n\n        // Previous entry is no longer still valid, it should not be returned\n        var lookup = _target.LookUpActivation(grainId);\n        Assert.Null(lookup.Address);\n    }\n\n    /// <summary>\n    /// Mock implementation of ISiloStatusOracle for testing.\n    /// The silo status oracle provides membership information about\n    /// which silos are alive, dead, or in other states. The grain\n    /// directory uses this to validate entries and make placement decisions.\n    /// </summary>\n    private class MockSiloStatusOracle : ISiloStatusOracle\n    {\n        private readonly Dictionary<SiloAddress, SiloStatus> _content = new();\n\n        public MockSiloStatusOracle(SiloAddress siloAddress = null)\n        {\n            SiloAddress = siloAddress ?? LocalSiloAddress;\n            _content[SiloAddress] = SiloStatus.Active;\n        }\n\n        public SiloStatus CurrentStatus => SiloStatus.Active;\n\n        public string SiloName => \"TestSilo\";\n\n        public SiloAddress SiloAddress { get; }\n\n        public SiloStatus GetApproximateSiloStatus(SiloAddress siloAddress)\n        {\n            if (_content.TryGetValue(siloAddress, out var status))\n            {\n                return status;\n            }\n            return SiloStatus.None;\n        }\n\n        public Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false)\n        {\n            return onlyActive\n                ? new Dictionary<SiloAddress, SiloStatus>(_content.Where(kvp => kvp.Value == SiloStatus.Active))\n                : new Dictionary<SiloAddress, SiloStatus>(_content);\n        }\n\n        public ImmutableArray<SiloAddress> GetActiveSilos() => _content.Keys.ToImmutableArray();\n\n        public void SetSiloStatus(SiloAddress siloAddress, SiloStatus status) => _content[siloAddress] = status;\n\n        public bool IsDeadSilo(SiloAddress silo) => GetApproximateSiloStatus(silo) == SiloStatus.Dead;\n\n        public bool IsFunctionalDirectory(SiloAddress siloAddress) => !GetApproximateSiloStatus(siloAddress).IsTerminating();\n\n        #region Not Implemented\n        public bool SubscribeToSiloStatusEvents(ISiloStatusListener observer) => throw new NotImplementedException();\n\n        public bool TryGetSiloName(SiloAddress siloAddress, out string siloName) => throw new NotImplementedException();\n\n        public bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener observer) => throw new NotImplementedException();\n        #endregion\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/GrainLocatorActivationResiliencyTests.cs",
    "content": "using System.Diagnostics;\nusing System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\n\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests\n{\n    /// <summary>\n    /// Tests that grain activation can recover from invalid grain directory entries.\n    /// \n    /// The grain directory can contain stale or \"poison\" entries that point to\n    /// non-existent activations. This can happen due to:\n    /// - Silo crashes before cleaning up directory entries\n    /// - Network partitions causing inconsistent state\n    /// - Race conditions during activation/deactivation\n    /// \n    /// Orleans must be resilient to these scenarios by:\n    /// - Detecting invalid entries during activation\n    /// - Retrying registration with proper previousRegistration parameter\n    /// - Forwarding calls to the correct silo based on directory entries\n    /// \n    /// These tests verify Orleans can recover from poison directory entries\n    /// and maintain the single activation constraint.\n    /// </summary>\n    public class GrainLocatorActivationResiliencyTests : HostedTestClusterEnsureDefaultStarted\n    {\n        public GrainLocatorActivationResiliencyTests(DefaultClusterFixture fixture) : base(fixture)\n        {\n        }\n\n        /// <summary>\n        /// Tests recovery when the grain directory contains an invalid entry pointing\n        /// to the same silo where activation will occur.\n        /// \n        /// Scenario:\n        /// 1. Insert a \"poison\" directory entry pointing to a non-existent activation on the primary silo\n        /// 2. Attempt to activate the grain on the same silo\n        /// 3. The activation should detect the invalid entry (same silo, different activation ID)\n        /// 4. Retry registration with the poison entry as previousRegistration to update it\n        /// \n        /// This tests the local silo's ability to self-heal invalid directory state.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ReactivateGrainWithPoisonGrainDirectoryEntry_LocalSilo()\n        {\n            var primarySilo = (InProcessSiloHandle)Fixture.HostedCluster.Primary;\n            var primarySiloAddress = primarySilo.SiloAddress;\n            var grain = GrainFactory.GetGrain<IGuidTestGrain>(Guid.NewGuid());\n\n            // Create a poison directory entry:\n            // - Points to the correct silo (primary)\n            // - But with a fake activation ID that doesn't exist\n            // This simulates a stale entry from a crashed/deactivated grain\n            var grainLocator = primarySilo.SiloHost.Services.GetRequiredService<GrainLocator>();\n            var badAddress = GrainAddress.GetAddress(primarySiloAddress, grain.GetGrainId(), ActivationId.NewId());\n            await grainLocator.Register(badAddress, previousRegistration: null);\n\n            {\n                // Force placement on the primary silo using placement hint\n                // Despite the poison entry, the grain should successfully activate\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, primarySiloAddress);\n                var silo = await grain.GetSiloAddress();\n                Assert.Equal(primarySiloAddress, silo);\n            }\n        }\n        \n        /// <summary>\n        /// Tests recovery when activation is attempted on a different silo than the poison entry.\n        /// \n        /// Scenario:\n        /// 1. Insert poison entry pointing to primary silo\n        /// 2. Attempt to activate on secondary silo\n        /// 3. Secondary silo sees the directory entry and forwards the call to primary\n        /// 4. Primary silo detects invalid entry and updates it during activation\n        /// \n        /// This tests cross-silo coordination and forwarding behavior when dealing\n        /// with invalid directory entries, ensuring calls reach the right silo.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ReactivateGrainWithPoisonGrainDirectoryEntry_RemoteSilo()\n        {\n            var primarySilo = (InProcessSiloHandle)Fixture.HostedCluster.Primary;\n            var secondarySiloAddress = Fixture.HostedCluster.SecondarySilos.First().SiloAddress;\n            var primarySiloAddress = primarySilo.SiloAddress;\n            var grain = GrainFactory.GetGrain<IGuidTestGrain>(Guid.NewGuid());\n\n            // Create poison entry pointing to primary silo with fake activation ID\n            // This tests the forwarding mechanism: secondary silo will see this entry\n            // and forward the request to primary, where recovery will occur\n            var grainLocator = primarySilo.SiloHost.Services.GetRequiredService<GrainLocator>();\n            var badAddress = GrainAddress.GetAddress(primarySiloAddress, grain.GetGrainId(), ActivationId.NewId());\n            await grainLocator.Register(badAddress, previousRegistration: null);\n\n            {\n                // Attempt placement on secondary silo, but the directory entry\n                // will cause forwarding to primary silo. This verifies:\n                // 1. Secondary recognizes it shouldn't activate due to existing entry\n                // 2. Call is forwarded to primary based on directory\n                // 3. Primary recovers from poison entry and activates successfully\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, secondarySiloAddress);\n                var silo = await grain.GetSiloAddress();\n                Assert.Equal(primarySiloAddress, silo);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/GrainStateContainingGrainReferences.cs",
    "content": "﻿using Orleans.Runtime;\n\nnamespace TesterInternal\n{\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class GrainStateContainingGrainReferences\n    {\n        [Orleans.Id(0)]\n        public IAddressable Grain { get; set; }\n        [Orleans.Id(1)]\n        public List<IAddressable> GrainList { get; set; }\n        [Orleans.Id(2)]\n        public Dictionary<string, IAddressable> GrainDict { get; set; }\n\n        public GrainStateContainingGrainReferences()\n        {\n            GrainList = new List<IAddressable>();\n            GrainDict = new Dictionary<string, IAddressable>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/LivenessTests/ConsistentRingProviderTests.cs",
    "content": "using System.Collections.Immutable;\nusing System.Net;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Configuration;\nusing Orleans.Runtime.ConsistentRing;\nusing Orleans.Streams;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.LivenessTests\n{\n    /// <summary>\n    /// Tests for consistent ring hash provider functionality and virtual buckets distribution.\n    /// </summary>\n    public class ConsistentRingProviderTests(ITestOutputHelper output)\n    {\n        private readonly ITestOutputHelper _output = output;\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Liveness\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void ConsistentRingProvider_Test1()\n        {\n            SiloAddress silo1 = SiloAddressUtils.NewLocalSiloAddress(0);\n            ConsistentRingProvider ring = new ConsistentRingProvider(silo1, NullLoggerFactory.Instance, new FakeSiloStatusOracle());\n            _output.WriteLine(\"Silo1 range: {0}. The whole ring is: {1}\", ring.GetMyRange(), ring.ToString());\n\n            ring.AddServer(SiloAddressUtils.NewLocalSiloAddress(1));\n            _output.WriteLine(\"Silo1 range: {0}. The whole ring is: {1}\", ring.GetMyRange(), ring.ToString());\n\n            ring.AddServer(SiloAddressUtils.NewLocalSiloAddress(2));\n            _output.WriteLine(\"Silo1 range: {0}. The whole ring is: {1}\", ring.GetMyRange(), ring.ToString());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Liveness\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void ConsistentRingProvider_Test2()\n        {\n            SiloAddress silo1 = SiloAddressUtils.NewLocalSiloAddress(0);\n            VirtualBucketsRingProvider ring = new VirtualBucketsRingProvider(silo1, NullLoggerFactory.Instance, 30, new FakeSiloStatusOracle());\n            _output.WriteLine(\"\\n\\n*** Silo1 range: {0}.\\n*** The whole ring with 1 silo is:\\n{1}\\n\\n\", ring.GetMyRange(), ring.ToString());\n\n            for (int i = 1; i <= 10; i++)\n            {\n                ring.SiloStatusChangeNotification(SiloAddressUtils.NewLocalSiloAddress(i), SiloStatus.Active);\n                _output.WriteLine(\"\\n\\n*** Silo1 range: {0}.\\n*** The whole ring with {1} silos is:\\n{2}\\n\\n\", ring.GetMyRange(), i + 1, ring.ToString());\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Liveness\"), TestCategory(\"Ring\"), TestCategory(\"RingStandalone\")]\n        public void ConsistentRingProvider_Test3()\n        {\n            int NUM_SILOS = 100;\n            double NUM_QUEUES = 10024.0;\n            int NUM_AGENTS = 4;\n\n            Random random = new Random();\n            SiloAddress silo1 = SiloAddressUtils.NewLocalSiloAddress(random.Next(100000));\n            VirtualBucketsRingProvider ring = new VirtualBucketsRingProvider(silo1, NullLoggerFactory.Instance, 50, new FakeSiloStatusOracle());\n\n            for (int i = 1; i <= NUM_SILOS - 1; i++)\n            {\n                ring.SiloStatusChangeNotification(SiloAddressUtils.NewLocalSiloAddress(random.Next(100000)), SiloStatus.Active);\n            }\n\n            var siloRanges = ring.GetRanges();\n            var sortedSiloRanges = siloRanges.ToList();\n            sortedSiloRanges.Sort((t1, t2) => t1.Item2.RangePercentage().CompareTo(t2.Item2.RangePercentage()));\n\n            var allAgentRanges = new List<(SiloAddress, List<IRingRangeInternal>)>();\n            foreach (var siloRange in siloRanges)\n            {\n                List<IRingRangeInternal> agentRanges = new List<IRingRangeInternal>();\n                for (int i = 0; i < NUM_AGENTS; i++)\n                {\n                    IRingRangeInternal agentRange = (IRingRangeInternal)RangeFactory.GetEquallyDividedSubRange(siloRange.Value, NUM_AGENTS, i);\n                    agentRanges.Add(agentRange);\n                }\n                allAgentRanges.Add((siloRange.Key, agentRanges));\n            }\n\n            Dictionary<SiloAddress, List<int>> queueHistogram = GetQueueHistogram(allAgentRanges, (int)NUM_QUEUES);\n            string str = Utils.EnumerableToString(sortedSiloRanges,\n                tuple => string.Format(\"Silo {0} -> Range {1:0.000}%, {2} queues: {3}\",\n                    tuple.Item1,\n                    tuple.Item2.RangePercentage(),\n                    queueHistogram[tuple.Item1].Sum(),\n                    Utils.EnumerableToString(queueHistogram[tuple.Item1])), \"\\n\");\n\n            _output.WriteLine(\"\\n\\n*** The whole ring with {0} silos is:\\n{1}\\n\\n\", NUM_SILOS, str);\n\n            _output.WriteLine(\"Total number of queues is: {0}\", queueHistogram.Values.Sum(list => list.Sum()));\n            _output.WriteLine(\"Expected average range per silo is: {0:0.00}%, expected #queues per silo is: {1:0.00}, expected #queues per agent is: {2:0.000}.\",\n                100.0 / NUM_SILOS, NUM_QUEUES / NUM_SILOS, NUM_QUEUES / (NUM_SILOS * NUM_AGENTS));\n            _output.WriteLine(\"Min #queues per silo is: {0}, Max #queues per silo is: {1}.\",\n                queueHistogram.Values.Min(list => list.Sum()), queueHistogram.Values.Max(list => list.Sum()));\n        }\n\n        private static Dictionary<SiloAddress, List<int>> GetQueueHistogram(List<(SiloAddress Key, List<IRingRangeInternal> Value)> siloRanges, int totalNumQueues)\n        {\n            var options = new HashRingStreamQueueMapperOptions();\n            options.TotalQueueCount = totalNumQueues;\n            HashRingBasedStreamQueueMapper queueMapper = new HashRingBasedStreamQueueMapper(options, \"AzureQueues\");\n            _ = queueMapper.GetAllQueues();\n\n            Dictionary<SiloAddress, List<int>> queueHistogram = new Dictionary<SiloAddress, List<int>>();\n            foreach (var siloRange in siloRanges)\n            {\n                List<int> agentRanges = new List<int>();\n                foreach (IRingRangeInternal agentRange in siloRange.Value)\n                {\n                    int numQueues = queueMapper.GetQueuesForRange(agentRange).Count();\n                    agentRanges.Add(numQueues);\n                }\n                agentRanges.Sort();\n                queueHistogram.Add(siloRange.Key, agentRanges);\n            }\n            //queueHistogram.Sort((t1, t2) => t1.Item2.CompareTo(t2.Item2));\n            return queueHistogram;\n        }\n\n        internal sealed class FakeSiloStatusOracle : ISiloStatusOracle\n        {\n            private readonly Dictionary<SiloAddress, SiloStatus> _content = [];\n            private readonly HashSet<ISiloStatusListener> _subscribers = [];\n\n            public FakeSiloStatusOracle()\n            {\n                SiloAddress = SiloAddress.New(IPAddress.Loopback, Random.Shared.Next(2000, 40_000), SiloAddress.AllocateNewGeneration());\n                _content[SiloAddress] = SiloStatus.Active;\n            }\n\n            public SiloStatus CurrentStatus => SiloStatus.Active;\n\n            public string SiloName => \"TestSilo\";\n\n            public SiloAddress SiloAddress { get; }\n\n            public SiloStatus GetApproximateSiloStatus(SiloAddress siloAddress)\n            {\n                if (_content.TryGetValue(siloAddress, out var status))\n                {\n                    return status;\n                }\n                return SiloStatus.None;\n            }\n\n            public Dictionary<SiloAddress, SiloStatus> GetApproximateSiloStatuses(bool onlyActive = false)\n            {\n                return onlyActive\n                    ? new Dictionary<SiloAddress, SiloStatus>(_content.Where(kvp => kvp.Value == SiloStatus.Active))\n                    : new Dictionary<SiloAddress, SiloStatus>(_content);\n            }\n\n            public void SetSiloStatus(SiloAddress siloAddress, SiloStatus status)\n            {\n                _content[siloAddress] = status;\n                foreach (var subscriber in _subscribers)\n                {\n                    subscriber.SiloStatusChangeNotification(siloAddress, status);\n                }\n            }\n\n            public bool IsDeadSilo(SiloAddress silo) => GetApproximateSiloStatus(silo) == SiloStatus.Dead;\n\n            public bool IsFunctionalDirectory(SiloAddress siloAddress) => !GetApproximateSiloStatus(siloAddress).IsTerminating();\n\n            public bool SubscribeToSiloStatusEvents(ISiloStatusListener observer) => _subscribers.Add(observer);\n\n            public bool TryGetSiloName(SiloAddress siloAddress, out string siloName)\n            {\n                siloName = \"TestSilo\";\n                return true;\n            }\n\n            public bool UnSubscribeFromSiloStatusEvents(ISiloStatusListener observer) => _subscribers.Remove(observer);\n            public ImmutableArray<SiloAddress> GetActiveSilos() => [.. GetApproximateSiloStatuses(onlyActive: true).Keys];\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MembershipTests/ClientIdPartitionDataRebuildTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.TestHelper;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests for client directory partition reconstruction after silo failures.\n    /// </summary>\n    public class ClientIdPartitionDataRebuildTests : IDisposable\n    {\n        internal class Observer : ISimpleGrainObserver\n        {\n            private readonly SemaphoreSlim semaphore = new SemaphoreSlim(0);\n            private int lastA;\n            private int lastB;\n\n            public void StateChanged(int a, int b)\n            {\n                this.lastA = a;\n                this.lastB = b;\n                this.semaphore.Release();\n            }\n\n            public async Task WaitForNotification(int expectedA, int expectedB, TimeSpan timeout)\n            {\n                Assert.True(await this.semaphore.WaitAsync(timeout), \"No notification received\");\n                Assert.Equal(expectedA, this.lastA);\n                Assert.Equal(expectedB, this.lastB);\n            }\n        }\n\n        private readonly ITestOutputHelper output;\n\n        private TestCluster hostedCluster;\n\n        public ClientIdPartitionDataRebuildTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [Fact(Skip = \"Not reliable in PR build, skipping for now\")]\n        //[SkippableFact(typeof(SiloUnavailableException)), TestCategory(\"Functional\")]\n        public async Task ReconstructClientIdPartitionTest_Observer()\n        {\n            // Ensure the client entry is on Silo2 partition and get a grain that live on Silo3\n            var grain = await SetupTestAndPickGrain<ISimpleObserverableGrain>(g => g.GetRuntimeInstanceId());\n            var observer = new Observer();\n            var reference = this.hostedCluster.GrainFactory.CreateObjectReference<ISimpleGrainObserver>(observer);\n\n            await grain.Subscribe(reference);\n\n            // Test first notification\n            await grain.SetA(10);\n            await observer.WaitForNotification(10, 0, TimeSpan.FromSeconds(10));\n\n            // Kill the silo that hold directory client entry\n            await this.hostedCluster.SecondarySilos[0].StopSiloAsync(stopGracefully: false);\n            await Task.Delay(5000);\n\n            // Second notification should work since the directory was \"rebuilt\" when\n            // silos in cluster detected the dead one\n            await grain.SetB(20);\n            await observer.WaitForNotification(10, 20, TimeSpan.FromSeconds(10));\n        }\n\n        [Fact(Skip = \"Not reliable in PR build, skipping for now\")]\n        //[SkippableFact(typeof(SiloUnavailableException)), TestCategory(\"Functional\")]\n        public async Task ReconstructClientIdPartitionTest_Request()\n        {\n            // Ensure the client entry is on Silo2 partition and get a grain that live on Silo2\n            var grain = await SetupTestAndPickGrain<ITestGrain>(g => g.GetRuntimeInstanceId());\n\n            // Launch a long task and kill the silo that hold directory client entry\n            var promise = grain.DoLongAction(TimeSpan.FromSeconds(10), \"LongAction\");\n            await this.hostedCluster.SecondarySilos[0].StopSiloAsync(stopGracefully: false);\n\n            // It should work since the directory was \"rebuilt\" when\n            // silos in cluster detected the dead one\n            await promise;\n        }\n\n        private async Task<T> SetupTestAndPickGrain<T>(Func<T, Task<string>> getRuntimeInstanceId) where T : class, IGrainWithIntegerKey\n        {\n            // Ensure the client entry is on Silo2 partition\n            GrainId clientId = default;\n            CreateAndDeployTestCluster();\n            for (var i = 0; i < 100; i++)\n            {\n                if (this.hostedCluster.Client == null)\n                {\n                    await this.hostedCluster.InitializeClientAsync();\n                }\n\n                var client = this.hostedCluster.ServiceProvider.GetRequiredService<OutsideRuntimeClient>();\n                clientId = client.CurrentActivationAddress.GrainId;\n                var report = await TestUtils.GetDetailedGrainReport(this.hostedCluster.InternalGrainFactory, clientId, hostedCluster.Primary);\n                if (this.hostedCluster.SecondarySilos[0].SiloAddress.Equals(report.PrimaryForGrain))\n                {\n                    break;\n                }\n                clientId = default;\n                await this.hostedCluster.KillClientAsync();\n            }\n            Assert.False(clientId.IsDefault);\n\n            // Ensure grain is activated on Silo3\n            T grain = null;\n            for (var i = 0; i < 100; i++)\n            {\n                grain = this.hostedCluster.GrainFactory.GetGrain<T>(i);\n                var instanceId = await getRuntimeInstanceId(grain);\n                if (instanceId.Contains(hostedCluster.SecondarySilos[1].SiloAddress.Endpoint.ToString()))\n                {\n                    break;\n                }\n                grain = null;\n            }\n            Assert.NotNull(grain);\n\n            return grain;\n        }\n\n        private void CreateAndDeployTestCluster()\n        {\n            var builder = new TestClusterBuilder(3);\n\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n            this.hostedCluster = builder.Build();\n            this.hostedCluster.Deploy();\n        }\n\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.Configure<ClusterMembershipOptions>(options =>\n                {\n                    options.NumMissedProbesLimit = 1;\n                    options.ProbeTimeout = TimeSpan.FromMilliseconds(500);\n                    options.NumVotesForDeathDeclaration = 1;\n                });\n\n                hostBuilder.Configure<GrainDirectoryOptions>(options => options.CacheSize = 0);\n            }\n        }\n\n        public class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<GatewayOptions>(options => options.PreferredGatewayIndex = 0);\n            }\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                hostedCluster?.StopAllSilos();\n            }\n            finally\n            {\n                hostedCluster?.Dispose();\n                hostedCluster = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MembershipTests/MembershipTableTestsBase.cs",
    "content": "using System.Net;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing Xunit;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\n\nnamespace UnitTests.MembershipTests\n{\n    internal static class SiloInstanceTableTestConstants\n    {\n        internal static readonly TimeSpan Timeout = TimeSpan.FromMinutes(1);\n\n        internal static readonly bool DeleteEntriesAfterTest = true; // false; // Set to false for Debug mode\n\n        internal static readonly string INSTANCE_STATUS_CREATED = SiloStatus.Created.ToString();  //\"Created\";\n        internal static readonly string INSTANCE_STATUS_ACTIVE = SiloStatus.Active.ToString();    //\"Active\";\n        internal static readonly string INSTANCE_STATUS_DEAD = SiloStatus.Dead.ToString();        //\"Dead\";\n    }\n\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public abstract class MembershipTableTestsBase : IDisposable, IClassFixture<ConnectionStringFixture>\n    {\n        private readonly TestEnvironmentFixture environment;\n        private static readonly string hostName = Dns.GetHostName();\n        private readonly ILogger logger;\n        private readonly IMembershipTable membershipTable;\n        private readonly IGatewayListProvider gatewayListProvider;\n        protected readonly string clusterId;\n        protected readonly string connectionString;\n        protected ILoggerFactory loggerFactory;\n        protected IOptions<SiloOptions> siloOptions;\n        protected IOptions<ClusterOptions> _clusterOptions;\n        protected const string testDatabaseName = \"OrleansMembershipTest\";//for relational storage\n        protected readonly IOptions<GatewayOptions> _gatewayOptions;\n\n        private static int generation;\n\n        protected MembershipTableTestsBase(ConnectionStringFixture fixture, TestEnvironmentFixture environment, LoggerFilterOptions filters)\n        {\n            this.environment = environment;\n            loggerFactory = TestingUtils.CreateDefaultLoggerFactory($\"{this.GetType()}.log\", filters);\n            logger = loggerFactory.CreateLogger(this.GetType().FullName);\n\n            this.clusterId = \"test-\" + Guid.NewGuid();\n\n            logger.LogInformation(\"ClusterId={ClusterId}\", this.clusterId);\n\n            fixture.InitializeConnectionStringAccessor(GetConnectionString);\n            this.connectionString = fixture.ConnectionString;\n            if (string.IsNullOrEmpty(this.connectionString))\n            {\n                throw new SkipException(\"No connection string configured\");\n            }\n            this._clusterOptions = Options.Create(new ClusterOptions { ClusterId = this.clusterId });\n            var adoVariant = GetAdoInvariant();\n\n            membershipTable = CreateMembershipTable(logger);\n            membershipTable.InitializeMembershipTable(true).WaitAsync(TimeSpan.FromMinutes(1)).Wait();\n\n            this._gatewayOptions = Options.Create(new GatewayOptions());\n            gatewayListProvider = CreateGatewayListProvider(logger);\n            gatewayListProvider.InitializeGatewayListProvider().WaitAsync(TimeSpan.FromMinutes(1)).Wait();\n        }\n\n        public IGrainFactory GrainFactory => this.environment.GrainFactory;\n\n        public IServiceProvider Services => this.environment.Services;\n\n        public void Dispose()\n        {\n            if (membershipTable != null && SiloInstanceTableTestConstants.DeleteEntriesAfterTest)\n            {\n                membershipTable.DeleteMembershipTableEntries(this.clusterId).Wait();\n            }\n            this.loggerFactory.Dispose();\n        }\n\n        protected abstract IGatewayListProvider CreateGatewayListProvider(ILogger logger);\n        protected abstract IMembershipTable CreateMembershipTable(ILogger logger);\n        protected abstract Task<string> GetConnectionString();\n\n        protected virtual string GetAdoInvariant()\n        {\n            return null;\n        }\n\n        protected async Task MembershipTable_GetGateways()\n        {\n            var membershipEntries = Enumerable.Range(0, 10).Select(i => CreateMembershipEntryForTest()).ToArray();\n\n            membershipEntries[3].Status = SiloStatus.Active;\n            membershipEntries[3].ProxyPort = 0;\n            membershipEntries[5].Status = SiloStatus.Active;\n            membershipEntries[9].Status = SiloStatus.Active;\n\n            var data = await membershipTable.ReadAll();\n            Assert.NotNull(data);\n            Assert.Empty(data.Members);\n\n            var version = data.Version;\n            foreach (var membershipEntry in membershipEntries)\n            {\n                Assert.True(await membershipTable.InsertRow(membershipEntry, version.Next()));\n                version = (await membershipTable.ReadRow(membershipEntry.SiloAddress)).Version;\n            }\n\n            var gateways = await gatewayListProvider.GetGateways();\n\n            var entries = new List<string>(gateways.Select(g => g.ToString()));\n\n            // only members with a non-zero Gateway port\n            Assert.DoesNotContain(membershipEntries[3].SiloAddress.ToGatewayUri().ToString(), entries);\n\n            // only Active members\n            Assert.Contains(membershipEntries[5].SiloAddress.ToGatewayUri().ToString(), entries);\n            Assert.Contains(membershipEntries[9].SiloAddress.ToGatewayUri().ToString(), entries);\n            Assert.Equal(2, entries.Count);\n        }\n\n        protected async Task MembershipTable_ReadAll_EmptyTable()\n        {\n            var data = await membershipTable.ReadAll();\n            Assert.NotNull(data);\n\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Empty(data.Members);\n            Assert.NotNull(data.Version.VersionEtag);\n            Assert.Equal(0, data.Version.Version);\n        }\n\n        protected async Task MembershipTable_InsertRow(bool extendedProtocol = true)\n        {\n            var membershipEntry = CreateMembershipEntryForTest();\n\n            var data = await membershipTable.ReadAll();\n            Assert.NotNull(data);\n            Assert.Empty(data.Members);\n\n            TableVersion nextTableVersion = data.Version.Next();\n\n            bool ok = await membershipTable.InsertRow(membershipEntry, nextTableVersion);\n            Assert.True(ok, \"InsertRow failed\");\n\n            data = await membershipTable.ReadAll();\n\n            if (extendedProtocol)\n                Assert.Equal(1, data.Version.Version);\n\n            Assert.Single(data.Members);\n        }\n\n        protected async Task MembershipTable_ReadRow_Insert_Read(bool extendedProtocol = true)\n        {\n            MembershipTableData data = await membershipTable.ReadAll();\n\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Empty(data.Members);\n\n            TableVersion newTableVersion = data.Version.Next();\n\n            MembershipEntry newEntry = CreateMembershipEntryForTest();\n            bool ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n\n            Assert.True(ok, \"InsertRow failed\");\n\n            ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n            Assert.False(ok, \"InsertRow should have failed - same entry, old table version\");\n\n            if (extendedProtocol)\n            {\n                ok = await membershipTable.InsertRow(CreateMembershipEntryForTest(), newTableVersion);\n                Assert.False(ok, \"InsertRow should have failed - new entry, old table version\");\n            }\n\n            data = await membershipTable.ReadAll();\n\n            if (extendedProtocol)\n                Assert.Equal(1, data.Version.Version);\n\n            TableVersion nextTableVersion = data.Version.Next();\n\n            ok = await membershipTable.InsertRow(newEntry, nextTableVersion);\n            Assert.False(ok, \"InsertRow should have failed - duplicate entry\");\n\n            data = await membershipTable.ReadAll();\n\n            Assert.Single(data.Members);\n\n            data = await membershipTable.ReadRow(newEntry.SiloAddress);\n            if (extendedProtocol)\n                Assert.Equal(newTableVersion.Version, data.Version.Version);\n\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Single(data.Members);\n            Assert.NotNull(data.Version.VersionEtag);\n            if (extendedProtocol)\n            {\n                Assert.NotEqual(newTableVersion.VersionEtag, data.Version.VersionEtag);\n                Assert.Equal(newTableVersion.Version, data.Version.Version);\n            }\n            var membershipEntry = data.Members[0].Item1;\n            string eTag = data.Members[0].Item2;\n            logger.LogInformation(\"Membership.ReadRow returned MembershipEntry ETag={ETag} Entry={Entry}\", eTag, membershipEntry);\n\n            Assert.NotNull(eTag);\n            Assert.NotNull(membershipEntry);\n        }\n\n        protected async Task MembershipTable_ReadAll_Insert_ReadAll(bool extendedProtocol = true)\n        {\n            MembershipTableData data = await membershipTable.ReadAll();\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Empty(data.Members);\n\n            TableVersion newTableVersion = data.Version.Next();\n\n            MembershipEntry newEntry = CreateMembershipEntryForTest();\n            bool ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n\n            Assert.True(ok, \"InsertRow failed\");\n\n            data = await membershipTable.ReadAll();\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Single(data.Members);\n            Assert.NotNull(data.Version.VersionEtag);\n\n            if (extendedProtocol)\n            {\n                Assert.NotEqual(newTableVersion.VersionEtag, data.Version.VersionEtag);\n                Assert.Equal(newTableVersion.Version, data.Version.Version);\n            }\n\n            var membershipEntry = data.Members[0].Item1;\n            string eTag = data.Members[0].Item2;\n            logger.LogInformation(\"Membership.ReadAll returned MembershipEntry ETag={ETag} Entry={Entry}\", eTag, membershipEntry);\n\n            Assert.NotNull(eTag);\n            Assert.NotNull(membershipEntry);\n        }\n\n        protected async Task MembershipTable_UpdateRow(bool extendedProtocol = true)\n        {\n            var tableData = await membershipTable.ReadAll();\n            Assert.NotNull(tableData.Version);\n\n            Assert.Equal(0, tableData.Version.Version);\n            Assert.Empty(tableData.Members);\n\n            for (int i = 1; i < 10; i++)\n            {\n                var siloEntry = CreateMembershipEntryForTest();\n\n                siloEntry.SuspectTimes =\n                    new List<Tuple<SiloAddress, DateTime>>\n                    {\n                        new Tuple<SiloAddress, DateTime>(CreateSiloAddressForTest(), GetUtcNowWithSecondsResolution().AddSeconds(1)),\n                        new Tuple<SiloAddress, DateTime>(CreateSiloAddressForTest(), GetUtcNowWithSecondsResolution().AddSeconds(2))\n                    };\n\n                TableVersion tableVersion = tableData.Version.Next();\n\n                logger.LogInformation(\"Calling InsertRow with Entry = {Entry} TableVersion = {TableVersion}\", siloEntry, tableVersion);\n                bool ok = await membershipTable.InsertRow(siloEntry, tableVersion);\n\n                Assert.True(ok, \"InsertRow failed\");\n\n                tableData = await membershipTable.ReadAll();\n\n                var etagBefore = tableData.TryGet(siloEntry.SiloAddress)?.Item2;\n\n                Assert.NotNull(etagBefore);\n\n                if (extendedProtocol)\n                {\n                    logger.LogInformation(\n                        \"Calling UpdateRow with Entry = {Entry} correct eTag = {ETag} old version={TableVersion}\",\n                        siloEntry,\n                        etagBefore,\n                        tableVersion?.ToString() ?? \"null\");\n                    ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n                    Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n                    tableData = await membershipTable.ReadAll();\n                }\n\n                tableVersion = tableData.Version.Next();\n\n                logger.LogInformation(\n                    \"Calling UpdateRow with Entry = {Entry} correct eTag = {ETag} correct version={TableVersion}\",\n                    siloEntry,\n                    etagBefore,\n                    tableVersion?.ToString() ?? \"null\");\n\n                ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n\n                Assert.True(ok, $\"UpdateRow failed - Table Data = {tableData}\");\n\n                logger.LogInformation(\n                    \"Calling UpdateRow with Entry = {Entry} old eTag = {ETag} old version={TableVersion}\",\n                    siloEntry,\n                    etagBefore,\n                    tableVersion?.ToString() ?? \"null\");\n                ok = await membershipTable.UpdateRow(siloEntry, etagBefore, tableVersion);\n                Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n\n                tableData = await membershipTable.ReadAll();\n\n                var tuple = tableData.TryGet(siloEntry.SiloAddress);\n\n                Assert.Equal(tuple.Item1.ToFullString(), siloEntry.ToFullString());\n\n                var etagAfter = tuple.Item2;\n\n                if (extendedProtocol)\n                {\n                    logger.LogInformation(\n                        \"Calling UpdateRow with Entry = {Entry} correct eTag = {ETag} old version={TableVersion}\",\n                        siloEntry,\n                        etagAfter,\n                        tableVersion?.ToString() ?? \"null\");\n\n                    ok = await membershipTable.UpdateRow(siloEntry, etagAfter, tableVersion);\n\n                    Assert.False(ok, $\"row update should have failed - Table Data = {tableData}\");\n                }\n\n                tableData = await membershipTable.ReadAll();\n\n                etagBefore = etagAfter;\n\n                etagAfter = tableData.TryGet(siloEntry.SiloAddress)?.Item2;\n\n                Assert.Equal(etagBefore, etagAfter);\n                Assert.NotNull(tableData.Version);\n                if (extendedProtocol)\n                    Assert.Equal(tableVersion.Version, tableData.Version.Version);\n\n                Assert.Equal(i, tableData.Members.Count);\n            }\n        }\n\n        protected async Task MembershipTable_UpdateRowInParallel(bool extendedProtocol = true)\n        {\n            var tableData = await membershipTable.ReadAll();\n\n            var data = CreateMembershipEntryForTest();\n\n            TableVersion newTableVer = tableData.Version.Next();\n\n            var insertions = Task.WhenAll(Enumerable.Range(1, 20).Select(async i => { try { return await membershipTable.InsertRow(data, newTableVer); } catch { return false; } }));\n\n            Assert.True((await insertions).Single(x => x), \"InsertRow failed\");\n\n            await Task.WhenAll(Enumerable.Range(1, 19).Select(async i =>\n            {\n                var done = false;\n                do\n                {\n                    var updatedTableData = await membershipTable.ReadAll();\n                    var updatedRow = updatedTableData.TryGet(data.SiloAddress);\n\n                    await Task.Delay(10);\n                    if (updatedRow is null) continue;\n\n                    TableVersion tableVersion = updatedTableData.Version.Next();\n                    try\n                    {\n                        done = await membershipTable.UpdateRow(updatedRow.Item1, updatedRow.Item2, tableVersion);\n                    }\n                    catch\n                    {\n                        done = false;\n                    }\n                } while (!done);\n            })).WaitAsync(TimeSpan.FromSeconds(30));\n\n\n            tableData = await membershipTable.ReadAll();\n            Assert.NotNull(tableData.Version);\n\n            if (extendedProtocol)\n                Assert.Equal(20, tableData.Version.Version);\n\n            Assert.Single(tableData.Members);\n        }\n\n        protected async Task MembershipTable_UpdateIAmAlive(bool extendedProtocol = true)\n        {\n            MembershipTableData tableData = await membershipTable.ReadAll();\n\n            TableVersion newTableVersion = tableData.Version.Next();\n            MembershipEntry newEntry = CreateMembershipEntryForTest();\n            bool ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n            Assert.True(ok);\n\n            var amAliveTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));\n\n            // This mimics the arguments MembershipOracle.OnIAmAliveUpdateInTableTimer passes in\n            var entry = new MembershipEntry\n            {\n                SiloAddress = newEntry.SiloAddress,\n                IAmAliveTime = amAliveTime\n            };\n\n            await membershipTable.UpdateIAmAlive(entry);\n\n            tableData = await membershipTable.ReadAll();\n            var member = tableData.Members.First(e => e.Item1.SiloAddress.Equals(newEntry.SiloAddress));\n\n            // compare that the value is close to what we passed in, but not exactly, as the underlying store can set its own precision settings\n            // (ie: in SQL Server this is defined as datetime2(3), so we don't expect precision to account for less than 0.001s values)\n            Assert.True((amAliveTime - member.Item1.IAmAliveTime).Duration() < TimeSpan.FromSeconds(2), (amAliveTime - member.Item1.IAmAliveTime).Duration().ToString());\n            Assert.Equal(newTableVersion.Version, tableData.Version.Version);\n        }\n\n        protected async Task MembershipTable_CleanupDefunctSiloEntries(bool extendedProtocol = true)\n        {\n            MembershipTableData data = await membershipTable.ReadAll();\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Empty(data.Members);\n\n            TableVersion newTableVersion = data.Version.Next();\n\n            var oldEntryDead = CreateMembershipEntryForTest();\n            oldEntryDead.IAmAliveTime = oldEntryDead.IAmAliveTime.AddDays(-10);\n            oldEntryDead.StartTime = oldEntryDead.StartTime.AddDays(-10);\n            oldEntryDead.Status = SiloStatus.Dead;\n            bool ok = await membershipTable.InsertRow(oldEntryDead, newTableVersion);\n            var table = await membershipTable.ReadAll();\n\n            Assert.True(ok, \"InsertRow Dead failed\");\n\n            newTableVersion = table.Version.Next();\n            var oldEntryJoining = CreateMembershipEntryForTest();\n            oldEntryJoining.IAmAliveTime = oldEntryJoining.IAmAliveTime.AddDays(-10);\n            oldEntryJoining.StartTime = oldEntryJoining.StartTime.AddDays(-10);\n            oldEntryJoining.Status = SiloStatus.Joining;\n            ok = await membershipTable.InsertRow(oldEntryJoining, newTableVersion);\n            table = await membershipTable.ReadAll();\n\n            Assert.True(ok, \"InsertRow Joining failed\");\n\n            newTableVersion = table.Version.Next();\n            var  newEntry = CreateMembershipEntryForTest();\n            ok = await membershipTable.InsertRow(newEntry, newTableVersion);\n\n            Assert.True(ok, \"InsertRow failed\");\n\n            data = await membershipTable.ReadAll();\n            newTableVersion = data.Version.Next();\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Equal(3, data.Members.Count);\n\n            // Every status other than Active should get cleared out if old\n            foreach (var siloStatus in Enum.GetValues<SiloStatus>())\n            {\n                var oldEntry = CreateMembershipEntryForTest();\n                oldEntry.IAmAliveTime = oldEntry.IAmAliveTime.AddDays(-10);\n                oldEntry.StartTime = oldEntry.StartTime.AddDays(-10);\n                oldEntry.Status = siloStatus;\n                ok = await membershipTable.InsertRow(oldEntry, newTableVersion);\n                table = await membershipTable.ReadAll();\n\n                Assert.True(ok, \"InsertRow failed\");\n\n                newTableVersion = table.Version.Next();\n            }\n\n            await membershipTable.CleanupDefunctSiloEntries(oldEntryDead.IAmAliveTime.AddDays(3));\n\n            data = await membershipTable.ReadAll();\n            logger.LogInformation(\"Membership.ReadAll returned TableVersion={TableVersion} Data={Data}\", data.Version, data);\n\n            Assert.Equal(2, data.Members.Count);\n        }\n\n        // Utility methods\n        private static MembershipEntry CreateMembershipEntryForTest()\n        {\n            SiloAddress siloAddress = CreateSiloAddressForTest();\n\n            var membershipEntry = new MembershipEntry\n            {\n                SiloAddress = siloAddress,\n                HostName = hostName,\n                SiloName = \"TestSiloName\",\n                Status = SiloStatus.Joining,\n                ProxyPort = siloAddress.Endpoint.Port,\n                StartTime = GetUtcNowWithSecondsResolution(),\n                IAmAliveTime = GetUtcNowWithSecondsResolution()\n            };\n\n            return membershipEntry;\n        }\n\n        private static DateTime GetUtcNowWithSecondsResolution()\n        {\n            var now = DateTime.UtcNow;\n            return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, DateTimeKind.Utc);\n        }\n\n        private static SiloAddress CreateSiloAddressForTest()\n        {\n            var siloAddress = SiloAddressUtils.NewLocalSiloAddress(Interlocked.Increment(ref generation));\n            siloAddress.Endpoint.Port = 12345;\n            return siloAddress;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MemoryGrainStorageTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing TestExtensions.Runners;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests;\n\n/// <summary>\n/// Tests for the in-memory grain storage provider.\n/// \n/// Memory storage provider characteristics:\n/// - Stores grain state in memory only (non-durable)\n/// - State is lost when silo restarts\n/// - Useful for development, testing, and caching scenarios\n/// - Supports all standard persistence operations (Read, Write, Clear)\n/// - Multiple named instances can be configured\n/// \n/// These tests verify that memory storage correctly implements the\n/// IGrainStorage interface and handles all persistence operations,\n/// even though the storage is not durable across restarts.\n/// \n/// The tests inherit from GrainPersistenceTestsRunner which provides\n/// a comprehensive suite of persistence behavior tests.\n/// </summary>\n[TestCategory(\"Persistence\"), TestCategory(\"Memory\")]\npublic class MemoryGrainStorageTests : GrainPersistenceTestsRunner, IClassFixture<MemoryGrainStorageTests.Fixture>\n{\n    public class Fixture : BaseTestClusterFixture\n    {\n        private class StorageSiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                // Configure multiple named memory storage providers\n                // Grains can specify which provider to use via [StorageProvider] attribute\n                hostBuilder.AddMemoryGrainStorage(\"GrainStorageForTest\")\n                .AddMemoryGrainStorage(\"test1\")\n                .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<StorageSiloBuilderConfigurator>();\n        }\n    }\n\n    public MemoryGrainStorageTests(ITestOutputHelper output, Fixture fixture) : base(output, fixture)\n    {\n        fixture.EnsurePreconditionsMet();\n        // Memory storage is not durable - state is lost on restart\n        // This flag tells the base test runner to skip durability tests\n        IsDurableStorage = false;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MessageScheduling/AllowCallChainReentrancyTests.cs",
    "content": "using TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for allowed call chain reentrancy scenarios on non-reentrant grains.\n    /// </summary>\n    public class AllowCallChainReentrancyTests : OrleansTestingBase, IClassFixture<AllowCallChainReentrancyTests.Fixture>\n    {\n        private const int NumIterations = 30;\n        private readonly CallChainReentrancyTestHelper _testHelper;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n        }\n\n        public AllowCallChainReentrancyTests(ITestOutputHelper output, Fixture fixture)\n        {\n            if (output == null) throw new ArgumentNullException(nameof(output));\n\n            _testHelper = new CallChainReentrancyTestHelper\n            {\n                Fixture = fixture,\n                NumIterations = NumIterations\n            };\n        }\n\n        // 1) Allowed reentrancy A, A\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task DeadlockDetection_1()\n        {\n            await _testHelper.CallChainReentrancy_1();\n        }\n\n        // 2) Allowed reentrancy on non-reentrant grains A, B, A\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_2()\n        {\n            await _testHelper.CallChainReentrancy_2();\n        }\n\n        // 3) Allowed reentrancy X, A, X, A\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_3()\n        {\n            await _testHelper.CallChainReentrancy_3();\n        }\n\n        // 4) No Deadlock X, X\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_4()\n        {\n            await _testHelper.CallChainReentrancy_4();\n        }\n\n        // 5) No Deadlock X, A, X\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_5()\n        {\n            await _testHelper.CallChainReentrancy_5();\n        }\n\n        // 6) Allowed reentrancy on non-reentrant grains A, B, C, A\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_6()\n        {\n            await _testHelper.CallChainReentrancy_6();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Deadlock\")]\n        public async Task CallChainReentrancy_WithSuppression()\n        {\n            await _testHelper.CallChainReentrancy_WithSuppression();\n        }\n    }\n} \n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MessageScheduling/CallChainReentrancyTestHelper.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Threading.Channels;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    public class CallChainReentrancyTestHelper\n    {\n        public BaseTestClusterFixture Fixture { get; set; }\n        public int NumIterations { get; set; }\n\n        // 2 silos, loop across all cases (to force all grains to be local and remote):\n        //      Non Reentrant A, B, C\n        //      Reentrant X\n        // 1) No Deadlock A, A\n        // 2) No Deadlock A, B, A\n        // 3) No Deadlock X, A, X, A\n        // 4) No Deadlock X, X\n        // 5) No Deadlock X, A, X\n        // 6) No Deadlock A, B, C, A\n\n        // 1) Allowed reentrancy A, A\n        public async Task CallChainReentrancy_1()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockNonReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId, true),\n                    (grainId, true)\n                };\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        // 2) Allowed reentrancy on non-reentrant grains A, B, A\n        public async Task CallChainReentrancy_2()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockNonReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId, true),\n                    (grainId + 100, true),\n                    (grainId, true)\n                };\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        // 3) Allowed reentrancy X, A, X, A\n        public async Task CallChainReentrancy_3()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId + 1000, false),\n                    (grainId, true),\n                    (grainId + 1000, false),\n                    (grainId, true)\n                };\n\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        // 4) No Deadlock X, X\n        public async Task CallChainReentrancy_4()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId + 1000, false),\n                    (grainId + 1000, false)\n                };\n\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        // 5) No Deadlock X, A, X\n        public async Task CallChainReentrancy_5()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId + 1000, false),\n                    (grainId, true),\n                    (grainId + 1000, false)\n                };\n\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        // 6) Allowed reentrancy on non-reentrant grains only when using full chain reentrancy A, B, C, A\n        public async Task CallChainReentrancy_6()\n        {\n            long baseGrainId = Random.Shared.Next();\n            for (var i = 0; i < NumIterations; i++)\n            {\n                var grainId = baseGrainId + i;\n                var firstGrain = Fixture.GrainFactory.GetGrain<IDeadlockNonReentrantGrain>(grainId);\n                var callChain = new List<(long GrainId, bool Blocking)>\n                {\n                    (grainId, true),\n                    (grainId + 100, true),\n                    (grainId + 200, true),\n                    (grainId, true)\n                };\n                await firstGrain.CallNext_1(callChain, 1);\n            }\n        }\n\n        /// <summary>\n        /// Suppresses call chain reentrancy within a reentrant call chain, to ensure that the subsequent call chain is not reentrant.\n        /// </summary>\n        public async Task CallChainReentrancy_WithSuppression()\n        {\n            using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2));\n\n            var aId = $\"A-{Random.Shared.Next()}\";\n            var bId = $\"B-{Random.Shared.Next()}\";\n            var a = Fixture.GrainFactory.GetGrain<ICallChainReentrancyGrain>(aId);\n\n            var chain = new List<(string, ReentrancyCallType)>\n            {\n                // 1. a->a: Start a new call chain, allowing reentrancy back into 'a'\n                (aId, ReentrancyCallType.AllowCallChainReentrancy),\n\n                // 2. a->b: Wont allow reentrancy into 'b', since 'b' has not excxplicitly requested it.\n                (bId, ReentrancyCallType.Regular),\n\n                // 3. b->a: Ensure that reentrancy into 'a' is allowed.\n                (aId, ReentrancyCallType.Regular),\n\n                // 4. a->b: Suppress call chain reentrancy from 'a' to 'b'. The call to 'b' should block (until we explicitly unblock it later), since 'b' is waiting already.\n                (bId, ReentrancyCallType.SuppressCallChainReentrancy),\n            };\n\n            var observer = new CallChainObserver();\n            var observerRef = Fixture.GrainFactory.CreateObjectReference<ICallChainObserver>(observer);\n\n            var aTask = a.CallChain(observerRef, chain, 0, cts.Token);\n\n            // Wait for 'a' to receive the call from 'b'\n            await observer.WaitForOperationAsync(CallChainOperation.Enter, aId, 3, cts.Token);\n\n            // Tell 'a' to stop waiting for 'b to return, allowing the final call (step 4) to enter 'b' and complete the call chain.\n            await a.UnblockWaiters(cts.Token);\n\n            await aTask;\n\n            // Wait for 'b' to complete its final call\n            await observer.WaitForOperationAsync(CallChainOperation.Exit, bId, 4, cts.Token);\n        }\n\n        public enum CallChainOperation\n        {\n            Enter,\n            Exit,\n        }\n\n        public class CallChainObserver : ICallChainObserver\n        {\n            private readonly Channel<(CallChainOperation Operation, string Grain, int CallIndex)> _operations = Channel.CreateUnbounded<(CallChainOperation Operation, string Grain, int CallIndex)>();\n            private readonly ConcurrentBag<(CallChainOperation Operation, string Grain, int CallIndex)> _allOperations = new();\n\n            public async Task OnEnter(string grain, int callIndex)\n            {\n                await _operations.Writer.WriteAsync((CallChainOperation.Enter, grain, callIndex));\n            }\n\n            public async Task OnExit(string grain, int callIndex)\n            {\n                await _operations.Writer.WriteAsync((CallChainOperation.Exit, grain, callIndex));\n            }\n\n            public async Task WaitForOperationAsync(CallChainOperation operationType, string grain, int callIndex, CancellationToken cancellationToken = default)\n            {\n                // First check if we've already seen this operation\n                if (_allOperations.Any(op => op.Operation == operationType && op.Grain.Equals(grain) && op.CallIndex == callIndex))\n                {\n                    return;\n                }\n\n                var operations = _operations.Reader;\n                while (await operations.WaitToReadAsync(cancellationToken))\n                {\n                    Assert.True(operations.TryRead(out var operation));\n                    _allOperations.Add(operation);\n\n                    if (operation.Operation == operationType && operation.Grain.Equals(grain) && operation.CallIndex == callIndex)\n                    {\n                        return;\n                    }\n\n                    // Check if we've passed the expected call index\n                    if (operation.CallIndex > callIndex)\n                    {\n                        break;\n                    }\n                }\n\n                Assert.Fail($\"Expected to find operation ({operationType}, {grain}, {callIndex}) in {string.Join(\", \", _allOperations.Select(op => $\"({op.Operation}, {op.Grain}, {op.CallIndex})\"))}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MessageScheduling/DisabledCallChainReentrancyTestRunner.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Microsoft.Extensions.Logging;\n\nnamespace UnitTests\n{\n    public class DisabledCallChainReentrancyTestRunner\n    {\n        private readonly IGrainFactory grainFactory;\n        private readonly ILogger logger;\n\n        public DisabledCallChainReentrancyTestRunner(IGrainFactory grainFactory, ILogger logger)\n        {\n            this.grainFactory = grainFactory;\n            this.logger = logger;\n        }\n\n        public void NonReentrantGrain(bool performDeadlockDetection)\n        {\n            INonReentrantGrain nonreentrant = this.grainFactory.GetGrain<INonReentrantGrain>(OrleansTestingBase.GetRandomGrainId());\n            nonreentrant.SetSelf(nonreentrant).Wait();\n            bool timeout = false;\n            bool deadlock = false;\n            try\n            {\n                timeout = !nonreentrant.Two().Wait(2000);\n            }\n            catch (Exception exc)\n            {\n                Assert.Fail(string.Format(\"Unexpected exception {0}: {1}\", exc.Message, exc.StackTrace));\n            }\n            if (performDeadlockDetection)\n            {\n                Assert.True(deadlock, \"Non-reentrant grain should deadlock\");\n            }\n            else\n            {\n                Assert.True(timeout, \"Non-reentrant grain should timeout\");\n            }\n            this.logger.LogInformation(\"Reentrancy NonReentrantGrain Test finished OK.\");\n        }\n\n        public void NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateReturnsFalse(bool performDeadlockDetection)\n        {\n            var grain = this.grainFactory.GetGrain<IMayInterleaveStaticPredicateGrain>(OrleansTestingBase.GetRandomGrainId());\n            grain.SetSelf(grain).Wait();\n            bool timeout = false;\n            bool deadlock = false;\n            try\n            {\n                timeout = !grain.Two().Wait(2000);\n            }\n            catch (Exception exc)\n            {\n                Assert.Fail(string.Format(\"Unexpected exception {0}: {1}\", exc.Message, exc.StackTrace));\n            }\n            if (performDeadlockDetection)\n            {\n                Assert.True(deadlock, \"Non-reentrant grain should deadlock when MayInterleave predicate returns false\");\n            }\n            else\n            {\n                Assert.True(timeout, \"Non-reentrant grain should timeout when MayInterleave predicate returns false\");\n            }\n            this.logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleavePredicate_WhenPredicateReturnsFalse Test finished OK.\");\n        }\n\n        public void NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsFalse(bool performDeadlockDetection)\n        {\n            var grain = this.grainFactory.GetGrain<IMayInterleaveInstancedPredicateGrain>(OrleansTestingBase.GetRandomGrainId());\n            grain.SetSelf(grain).Wait();\n            bool timeout = false;\n            bool deadlock = false;\n            try\n            {\n                timeout = !grain.Two().Wait(2000);\n            }\n            catch (Exception exc)\n            {\n                Assert.Fail(string.Format(\"Unexpected exception {0}: {1}\", exc.Message, exc.StackTrace));\n            }\n            if (performDeadlockDetection)\n            {\n                Assert.True(deadlock, \"Non-reentrant grain should deadlock when MayInterleave predicate returns false\");\n            }\n            else\n            {\n                Assert.True(timeout, \"Non-reentrant grain should timeout when MayInterleave predicate returns false\");\n            }\n            this.logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsFalse Test finished OK.\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MessageScheduling/DisabledCallChainReentrancyTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for disabled call chain reentrancy behavior on non-reentrant grains.\n    /// </summary>\n    public class DisabledCallChainReentrancyTests : OrleansTestingBase, IClassFixture<DisabledCallChainReentrancyTests.Fixture>\n    {\n        private readonly DisabledCallChainReentrancyTestRunner runner;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<ReentrancyTestsSiloBuilderConfigurator>();\n            }\n        }\n\n        public DisabledCallChainReentrancyTests(Fixture fixture)\n        {\n            this.runner = new DisabledCallChainReentrancyTestRunner(fixture.GrainFactory, fixture.Logger);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public void NonReentrantGrain()\n        {\n            this.runner.NonReentrantGrain(false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public void NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateReturnsFalse()\n        {\n            this.runner.NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateReturnsFalse(false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public void NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsFalse()\n        {\n            this.runner.NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsFalse(false);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/MessageScheduling/ReentrancyTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests\n{\n    internal class ReentrancyTestsSiloBuilderConfigurator : ISiloConfigurator\n    {\n        public void Configure(ISiloBuilder hostBuilder)\n        {\n            hostBuilder\n                .AddMemoryGrainStorage(\"MemoryStore\")\n                .AddMemoryGrainStorage(\"PubSubStore\")\n                .AddMemoryGrainStorageAsDefault();\n        }\n    }\n\n    /// <summary>\n    /// Tests for grain reentrancy, MayInterleave predicates, and fan-out scenarios.\n    /// </summary>\n    public class ReentrancyTests : OrleansTestingBase, IClassFixture<ReentrancyTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<ReentrancyTestsSiloBuilderConfigurator>();\n            }\n        }\n\n        private readonly ITestOutputHelper output;\n        private readonly Fixture fixture;\n\n        public ReentrancyTests(ITestOutputHelper output, Fixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n        }\n\n        // See https://github.com/dotnet/orleans/pull/5086\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task CorrelationId_Bug()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IFirstGrain>(Guid.NewGuid());\n            await grain.Start(Guid.NewGuid(), Guid.NewGuid());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task ReentrantGrain()\n        {\n            var reentrant = this.fixture.GrainFactory.GetGrain<IReentrantGrain>(GetRandomGrainId());\n            await reentrant.SetSelf(reentrant);\n\n            // Should reenter\n            await reentrant.Two().WaitAsync(TimeSpan.FromSeconds(5));\n            this.fixture.Logger.LogInformation(\"Reentrancy ReentrantGrain Test finished OK.\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateReturnsTrue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMayInterleaveStaticPredicateGrain>(GetRandomGrainId());\n            await grain.SetSelf(grain);\n\n            // Should reenter since predicate should return true.\n            await grain.TwoReentrant().WaitAsync(TimeSpan.FromSeconds(5));\n            this.fixture.Logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateReturnsTrue Test finished OK.\");\n        }\n\n        [Theory, TestCategory(\"Functional\"), TestCategory(\"Reentrancy\")]\n        [InlineData(true)]\n        [InlineData(false)]\n        public async Task MayInterleavePredicate_AllowsInterleaving(bool mayInterleaveFirst)\n        {\n            // Create a unique grain per run\n            var grainKey = $\"grain-{mayInterleaveFirst}\";\n            var grain = this.fixture.GrainFactory.GetGrain<ICallOrderingGrain>(grainKey);\n\n            Task first = mayInterleaveFirst ? grain.MethodA() : grain.MethodB();\n            await Task.Delay(250); // Stagger second call\n            Task second = mayInterleaveFirst ? grain.MethodB() : grain.MethodA();\n\n            await Task.Delay(500); // Let both methods reach entry point\n\n            await grain.Unblock();\n            await Task.WhenAll(first, second);\n\n            var log = await grain.GetLog();\n\n            Assert.Contains(\"enter:A\", log);\n            Assert.Contains(\"enter:B\", log);\n            Assert.Contains(\"exit:A\", log);\n            Assert.Contains(\"exit:B\", log);\n\n            var firstExit = log.FindIndex(x => x.StartsWith(\"exit\"));\n            Assert.True(firstExit >= 2, $\"Expected both methods to enter before exiting. Log: {string.Join(\", \", log)}\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateThrows()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMayInterleaveStaticPredicateGrain>(GetRandomGrainId());\n            await grain.SetSelf(grain);\n            try\n            {\n                await grain.Exceptional().WaitAsync(TimeSpan.FromSeconds(2));\n            }\n            catch (Exception ex)\n            {\n                Assert.IsType<ApplicationException>(ex);\n                Assert.True(ex.Message == \"boom\",\n                    \"Should fail with Orleans runtime exception having all of necessary details\");\n            }\n            this.fixture.Logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleaveStaticPredicate_WhenPredicateThrows Test finished OK.\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsTrue()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMayInterleaveInstancedPredicateGrain>(GetRandomGrainId());\n            await grain.SetSelf(grain);\n\n            // Grain should reenter when MayInterleave predicate returns true\n            await grain.TwoReentrant().WaitAsync(TimeSpan.FromSeconds(2));\n            this.fixture.Logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateReturnsTrue Test finished OK.\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateThrows()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMayInterleaveInstancedPredicateGrain>(GetRandomGrainId());\n            await grain.SetSelf(grain);\n            try\n            {\n                await grain.Exceptional().WaitAsync(TimeSpan.FromSeconds(2));\n            }\n            catch (Exception ex)\n            {\n                Assert.IsType<ApplicationException>(ex);\n                Assert.True(ex.Message == \"boom\",\n                    \"Should fail with Orleans runtime exception having all of necessary details\");\n            }\n            this.fixture.Logger.LogInformation(\"Reentrancy NonReentrantGrain_WithMayInterleaveInstancedPredicate_WhenPredicateThrows Test finished OK.\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task Reentrancy_Deadlock_1()\n        {\n            List<Task> done = new List<Task>();\n            var grain1 = this.fixture.GrainFactory.GetGrain<IReentrantSelfManagedGrain>(1);\n            await grain1.SetDestination(2);\n            done.Add(grain1.Ping(15));\n\n            var grain2 = this.fixture.GrainFactory.GetGrain<IReentrantSelfManagedGrain>(2);\n            await grain2.SetDestination(1);\n            done.Add(grain2.Ping(15));\n\n            await Task.WhenAll(done);\n            this.fixture.Logger.LogInformation(\"ReentrancyTest_Deadlock_1 OK - no deadlock.\");\n        }\n\n        // TODO: [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        [Fact(Skip = \"Ignore\"), TestCategory(\"Failures\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task Reentrancy_Deadlock_2()\n        {\n            List<Task> done = new List<Task>();\n            var grain1 = this.fixture.GrainFactory.GetGrain<INonReentrantSelfManagedGrain>(1);\n            await grain1.SetDestination(2);\n\n            var grain2 = this.fixture.GrainFactory.GetGrain<INonReentrantSelfManagedGrain>(2);\n            await grain2.SetDestination(1);\n\n            this.fixture.Logger.LogInformation(\"ReentrancyTest_Deadlock_2 is about to call grain1.Ping()\");\n            done.Add(grain1.Ping(15));\n            this.fixture.Logger.LogInformation(\"ReentrancyTest_Deadlock_2 is about to call grain2.Ping()\");\n            done.Add(grain2.Ping(15));\n\n            await Task.WhenAll(done);\n            this.fixture.Logger.LogInformation(\"ReentrancyTest_Deadlock_2 OK - no deadlock.\");\n        }\n\n        [Fact, TestCategory(\"Failures\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        private async Task NonReentrantFanOut()\n        {\n            var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<int>>(Guid.NewGuid());\n            var target = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<int>>(Guid.NewGuid());\n            await grain.CallOtherLongRunningTask(target, 2, TimeSpan.FromSeconds(1));\n            await Assert.ThrowsAsync<TimeoutException>(\n                () => target.FanOutOtherLongRunningTask(grain, 2, TimeSpan.FromSeconds(10), 5));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_Reentrant()\n        {\n            await Do_FanOut_Task_Join(0, false, false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_NonReentrant()\n        {\n            await Do_FanOut_Task_Join(0, true, false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_Reentrant_Chain()\n        {\n            await Do_FanOut_Task_Join(0, false, true);\n        }\n\n        // TODO: [Fact, TestCategory(\"BVT\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        [Fact(Skip =\"Ignore\"), TestCategory(\"Failures\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_NonReentrant_Chain()\n        {\n            await Do_FanOut_Task_Join(0, true, true);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_Reentrant()\n        {\n            await Do_FanOut_AC_Join(0, false, false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_NonReentrant()\n        {\n            await Do_FanOut_AC_Join(0, true, false);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_Reentrant_Chain()\n        {\n            await Do_FanOut_AC_Join(0, false, true);\n        }\n\n        [TestCategory(\"MultithreadingFailures\")]\n        // TODO: [TestCategory(\"Functional\")]\n        [Fact(Skip =\"Ignore\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_NonReentrant_Chain()\n        {\n            await Do_FanOut_AC_Join(0, true, true);\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_Stress_Reentrant()\n        {\n            const int numLoops = 5;\n            const int blockSize = 10;\n            TimeSpan timeout = TimeSpan.FromSeconds(40);\n            await Do_FanOut_Stress(numLoops, blockSize, timeout, false, false);\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_Task_Stress_NonReentrant()\n        {\n            const int numLoops = 5;\n            const int blockSize = 10;\n            TimeSpan timeout = TimeSpan.FromSeconds(40);\n            await Do_FanOut_Stress(numLoops, blockSize, timeout, true, false);\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_Stress_Reentrant()\n        {\n            const int numLoops = 5;\n            const int blockSize = 10;\n            TimeSpan timeout = TimeSpan.FromSeconds(40);\n            await Do_FanOut_Stress(numLoops, blockSize, timeout, false, true);\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"Functional\"), TestCategory(\"Tasks\"), TestCategory(\"Reentrancy\")]\n        public async Task FanOut_AC_Stress_NonReentrant()\n        {\n            const int numLoops = 5;\n            const int blockSize = 10;\n            TimeSpan timeout = TimeSpan.FromSeconds(40);\n            await Do_FanOut_Stress(numLoops, blockSize, timeout, true, true);\n        }\n\n        // ---------- Utility methods ----------\n\n        private async Task Do_FanOut_Task_Join(int offset, bool doNonReentrant, bool doCallChain)\n        {\n            const int num = 10;\n            int id = Random.Shared.Next();\n            if (doNonReentrant)\n            {\n                IFanOutGrain grain = this.fixture.GrainFactory.GetGrain<IFanOutGrain>(id);\n                if (doCallChain)\n                {\n                    await grain.FanOutNonReentrant_Chain(offset*num, num);\n                }\n                else\n                {\n                    await grain.FanOutNonReentrant(offset * num, num);\n                }\n            }\n            else\n            {\n                IFanOutGrain grain = this.fixture.GrainFactory.GetGrain<IFanOutGrain>(id);\n                if (doCallChain)\n                {\n                    await grain.FanOutReentrant_Chain(offset*num, num);\n                }\n                else\n                {\n                    await grain.FanOutReentrant(offset * num, num);\n                }\n            }\n        }\n\n        private async Task Do_FanOut_AC_Join(int offset, bool doNonReentrant, bool doCallChain)\n        {\n            const int num = 10;\n            int id = Random.Shared.Next();\n            if (doNonReentrant)\n            {\n                IFanOutACGrain grain = this.fixture.GrainFactory.GetGrain<IFanOutACGrain>(id);\n                if (doCallChain)\n                {\n                    await grain.FanOutACNonReentrant_Chain(offset * num, num);\n                }\n                else\n                {\n                    await grain.FanOutACNonReentrant(offset * num, num);\n                }\n            }\n            else\n            {\n                IFanOutACGrain grain = this.fixture.GrainFactory.GetGrain<IFanOutACGrain>(id);\n                if (doCallChain)\n                {\n                    await grain.FanOutACReentrant_Chain(offset * num, num);\n                }\n                else\n                {\n                    await grain.FanOutACReentrant(offset * num, num);\n                }\n            }\n        }\n\n        private readonly TimeSpan MaxStressExecutionTime = TimeSpan.FromMinutes(2);\n\n        private async Task Do_FanOut_Stress(int numLoops, int blockSize, TimeSpan timeout,\n            bool doNonReentrant, bool doAC)\n        {\n            Stopwatch totalTime = Stopwatch.StartNew();\n            List<Task> promises = new List<Task>();\n            for (int i = 0; i < numLoops; i++)\n            {\n                output.WriteLine(\"Start loop {0}\", i);\n                Stopwatch loopClock = Stopwatch.StartNew();\n                for (int j = 0; j < blockSize; j++)\n                {\n                    int offset = j;\n                    output.WriteLine(\"Start inner loop {0}\", j);\n                    Stopwatch innerClock = Stopwatch.StartNew();\n                    Task promise = Task.Run(() =>\n                    {\n                        return doAC ? Do_FanOut_AC_Join(offset, doNonReentrant, false)\n                                    : Do_FanOut_Task_Join(offset, doNonReentrant, false);\n                    });\n                    promises.Add(promise);\n                    output.WriteLine(\"Inner loop {0} - Created Tasks. Elapsed={1}\", j, innerClock.Elapsed);\n                    await Task.WhenAll(promises).WaitAsync(timeout);\n                    output.WriteLine(\"Inner loop {0} - Finished Join. Elapsed={1}\", j, innerClock.Elapsed);\n                    promises.Clear();\n                }\n                output.WriteLine(\"End loop {0} Elapsed={1}\", i, loopClock.Elapsed);\n            }\n            TimeSpan elapsed = totalTime.Elapsed;\n            Assert.True(elapsed < MaxStressExecutionTime, $\"Stress test execution took too long: {elapsed}\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/Orleans.Runtime.Internal.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"CsCheck\" />\n    <PackageReference Include=\"Azure.Identity\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Persistence.AzureStorage\\Orleans.Persistence.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"GoogleUtils.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Cosmos.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.NATS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/OrleansRuntime/StuckGrainTests.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing Orleans.Internal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Orleans.Runtime;\nusing UnitTests.Grains;\n\nnamespace UnitTests.StuckGrainTests\n{\n    /// <summary>\n    /// Summary description for PersistenceTest\n    /// </summary>\n    public class StuckGrainTests : OrleansTestingBase, IClassFixture<StuckGrainTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n            }\n\n            private class SiloHostConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.Configure<GrainCollectionOptions>(options =>\n                    {\n                        options.CollectionAge = TimeSpan.FromSeconds(2);\n                        options.CollectionQuantum = TimeSpan.FromSeconds(1);\n\n                        options.ActivationTimeout = TimeSpan.FromSeconds(2);\n                        options.DeactivationTimeout = TimeSpan.FromSeconds(2);\n                    });\n\n                    hostBuilder.Configure<SiloMessagingOptions>(options =>\n                    {\n                        options.MaxRequestProcessingTime = TimeSpan.FromSeconds(3);\n                    });\n                }\n            }\n        }\n\n        public StuckGrainTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCollection\")]\n        public async Task StuckGrainTest_Basic()\n        {\n            var id = Guid.NewGuid();\n            var stuckGrain = this.fixture.GrainFactory.GetGrain<IStuckGrain>(id);\n            var task = stuckGrain.RunForever();\n\n            // Should timeout\n            await Assert.ThrowsAsync<TimeoutException>(() => task.WaitAsync(TimeSpan.FromSeconds(1)));\n\n            var cleaner = this.fixture.GrainFactory.GetGrain<IStuckCleanGrain>(id);\n            await cleaner.Release(id);\n\n            // Should complete now\n            await task.WaitAsync(TimeSpan.FromSeconds(1));\n\n            // wait for activation collection\n            await Task.Delay(TimeSpan.FromSeconds(6));\n\n            Assert.False(await cleaner.IsActivated(id), \"Grain activation is supposed be garbage collected, but it is still running.\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCollection\")]\n        public async Task StuckGrainTest_StuckDetectionAndForward()\n        {\n            var id = Guid.NewGuid();\n            var stuckGrain = this.fixture.GrainFactory.GetGrain<IStuckGrain>(id);\n            var task = stuckGrain.RunForever();\n\n            // Should timeout\n            await Assert.ThrowsAsync<TimeoutException>(() => task.WaitAsync(TimeSpan.FromSeconds(1)));\n\n            var calls = new Task[3];\n            for (var i = 0; i < calls.Length; i++)\n            {\n                var call = stuckGrain.NonBlockingCall();\n                calls[i] = call;\n                await Task.WhenAny(call, Task.Delay(TimeSpan.FromMilliseconds(500)));\n            }\n\n            // Wait so the first task will reach with DefaultCollectionAge timeout\n            await Task.Delay(TimeSpan.FromSeconds(3));\n\n            // No issue on this one\n            await stuckGrain.NonBlockingCall();\n\n            // All otherwise stuck calls should have been forwarded to a new activation.\n            await Task.WhenAll(calls).WaitAsync(TimeSpan.FromSeconds(10));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCollection\")]\n        public async Task StuckGrainTest_StuckDetectionOnDeactivation()\n        {\n            var id = Guid.NewGuid();\n            var stuckGrain = this.fixture.GrainFactory.GetGrain<IStuckGrain>(id);\n            await stuckGrain.BlockingDeactivation();\n\n            await StuckGrain.WaitForDeactivationStart(stuckGrain.GetGrainId());\n\n            for (var i = 0; i < 3; i++)\n            {\n                var call = stuckGrain.NonBlockingCall();\n                await Task.WhenAny(call, Task.Delay(TimeSpan.FromMilliseconds(500)));\n            }\n\n            await TestingUtils.WaitUntilAsync(\n                async lastTry =>\n                {\n                    var count = await stuckGrain.GetNonBlockingCallCounter();\n                    if (lastTry)\n                    {\n                        Assert.Equal(3, count);\n                    }\n\n                    return count == 3;\n                },\n                TimeSpan.FromSeconds(10),\n                TimeSpan.FromMilliseconds(200));\n\n            // No issue on this one\n            await stuckGrain.NonBlockingCall();\n\n            // All 4 otherwise stuck calls should have been forwarded to a new activation\n            Assert.Equal(4, await stuckGrain.GetNonBlockingCallCounter());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCollection\")]\n        public async Task StuckGrainTest_StuckDetectionOnActivation()\n        {\n            var id = Guid.NewGuid();\n            var stuckGrain = this.fixture.GrainFactory.GetGrain<IStuckGrain>(id);\n\n            // The cancellation token passed to OnActivateAsync should become cancelled and this will cause activation to fail.\n            RequestContext.Set(\"block_activation_seconds\", 30);\n            await Assert.ThrowsAsync<TaskCanceledException>(() => stuckGrain.NonBlockingCall());\n\n            // Check to see that it did try to activate.\n            RequestContext.Clear();\n            var unstuckGrain = this.fixture.GrainFactory.GetGrain<IStuckGrain>(Guid.NewGuid());\n            await unstuckGrain.NonBlockingCall();\n\n            var activationAttempted = await unstuckGrain.DidActivationTryToStart(stuckGrain.GetGrainId());\n            Assert.True(activationAttempted);\n\n            // Now that activation is not blocked (we cleared the request context value which told it to block), let's check that our previously stuck grain works.\n            await stuckGrain.NonBlockingCall();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/Properties/AssemblyInfo.cs",
    "content": "// Disable XUnit concurrency limit\n[assembly: Xunit.CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/ReadMe.md",
    "content": "# TesterInternal Project\n\nThis project is for **white-box** testing of the Orleans runtime, \nincluding testing of internal Orleans runtime APIs.\n\nThis project has 'friend' access to the internal API surface of the Orleans runtime.\n\nThe following projects use `[InternalsVisibleTo]` assembly attributes to grant internal access privilege to this test project:\n\n- `Orleans.dll`\n- `OrleansRuntime.dll`\n- `OrleansAzureUtils.dll`\n\nThis project may contains a mixture of unit and system tests, including starting test silos.\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/RemindersTest/ReminderTableTestsBase.cs",
    "content": "using Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.MembershipTests;\nusing Xunit;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.TestingHost.Utils;\n\nnamespace UnitTests.RemindersTest\n{\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public abstract class ReminderTableTestsBase : IAsyncLifetime, IClassFixture<ConnectionStringFixture>\n    {\n        protected readonly TestEnvironmentFixture ClusterFixture;\n        private readonly ILogger logger;\n\n        private readonly IReminderTable remindersTable;\n        protected ILoggerFactory loggerFactory;\n        protected IOptions<ClusterOptions> clusterOptions;\n\n        protected ConnectionStringFixture connectionStringFixture;\n\n        protected const string testDatabaseName = \"OrleansReminderTest\";//for relational storage\n\n        protected ReminderTableTestsBase(ConnectionStringFixture fixture, TestEnvironmentFixture clusterFixture, LoggerFilterOptions filters)\n        {\n            this.connectionStringFixture = fixture;\n            fixture.InitializeConnectionStringAccessor(GetConnectionString);\n            loggerFactory = TestingUtils.CreateDefaultLoggerFactory($\"{this.GetType()}.log\", filters);\n            this.ClusterFixture = clusterFixture;\n            logger = loggerFactory.CreateLogger<ReminderTableTestsBase>();\n            var serviceId = Guid.NewGuid().ToString() + \"/foo\";\n            var clusterId = \"test-\" + serviceId + \"/foo2\";\n\n            logger.LogInformation(\"ClusterId={ClusterId}\", clusterId);\n            this.clusterOptions = Options.Create(new ClusterOptions { ClusterId = clusterId, ServiceId = serviceId });\n\n            this.remindersTable = this.CreateRemindersTable();\n        }\n\n        public virtual async Task InitializeAsync()\n        {\n            using var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(1));\n            await this.remindersTable.StartAsync(cancellation.Token);\n        }\n\n        public virtual async Task DisposeAsync()\n        {\n            if (remindersTable != null && SiloInstanceTableTestConstants.DeleteEntriesAfterTest)\n            {\n                await remindersTable.TestOnlyClearTable();\n            }\n        }\n\n        protected abstract IReminderTable CreateRemindersTable();\n        protected abstract Task<string> GetConnectionString();\n\n        protected virtual string GetAdoInvariant()\n        {\n            return null;\n        }\n\n        protected async Task RemindersParallelUpsert()\n        {\n            var upserts = await Task.WhenAll(Enumerable.Range(0, 5).Select(i =>\n            {\n                var reminder = CreateReminder(MakeTestGrainReference(), i.ToString());\n                return Task.WhenAll(Enumerable.Range(1, 5).Select(j =>\n                {\n                    return RetryHelper.RetryOnExceptionAsync(5, RetryOperation.Sigmoid, async () =>\n                    {\n                        return await remindersTable.UpsertRow(reminder);\n                    });\n                }));\n            }));\n            Assert.DoesNotContain(upserts, i => i.Distinct().Count() != 5);\n        }\n\n        protected async Task ReminderSimple()\n        {\n            var reminder = CreateReminder(MakeTestGrainReference(), \"foo/bar\\\\#b_a_z?\");\n            await remindersTable.UpsertRow(reminder);\n\n            var readReminder = await remindersTable.ReadRow(reminder.GrainId, reminder.ReminderName);\n\n            string etagTemp = reminder.ETag = readReminder.ETag;\n\n            Assert.Equal(readReminder.ETag, reminder.ETag);\n            Assert.Equal(readReminder.GrainId, reminder.GrainId);\n            Assert.Equal(readReminder.Period, reminder.Period);\n            Assert.Equal(readReminder.ReminderName, reminder.ReminderName);\n            Assert.Equal(readReminder.StartAt, reminder.StartAt);\n            Assert.NotNull(etagTemp);\n\n            reminder.ETag = await remindersTable.UpsertRow(reminder);\n\n            var removeRowRes = await remindersTable.RemoveRow(reminder.GrainId, reminder.ReminderName, etagTemp);\n            Assert.False(removeRowRes, \"should have failed. Etag is wrong\");\n            removeRowRes = await remindersTable.RemoveRow(reminder.GrainId, \"bla\", reminder.ETag);\n            Assert.False(removeRowRes, \"should have failed. reminder name is wrong\");\n            removeRowRes = await remindersTable.RemoveRow(reminder.GrainId, reminder.ReminderName, reminder.ETag);\n            Assert.True(removeRowRes, \"should have succeeded. Etag is right\");\n            removeRowRes = await remindersTable.RemoveRow(reminder.GrainId, reminder.ReminderName, reminder.ETag);\n            Assert.False(removeRowRes, \"should have failed. reminder shouldn't exist\");\n        }\n\n        protected async Task RemindersRange(int iterations = 1000)\n        {\n            await Task.WhenAll(Enumerable.Range(1, iterations).Select(async i =>\n            {\n                var grainRef = MakeTestGrainReference();\n\n                await RetryHelper.RetryOnExceptionAsync(10, RetryOperation.Sigmoid, async () =>\n                {\n                    await remindersTable.UpsertRow(CreateReminder(grainRef, i.ToString()));\n                    return 0;\n                });\n            }));\n\n            var rows = await remindersTable.ReadRows(0, uint.MaxValue);\n\n            Assert.Equal(rows.Reminders.Count, iterations);\n\n            rows = await remindersTable.ReadRows(0, 0);\n\n            Assert.Equal(rows.Reminders.Count, iterations);\n\n            var remindersHashes = rows.Reminders.Select(r => r.GrainId.GetUniformHashCode()).ToArray();\n\n            await Task.WhenAll(Enumerable.Range(0, iterations).Select(i =>\n            {\n                return TestRemindersHashInterval(remindersTable,\n                    (uint)Random.Shared.Next(int.MinValue, int.MaxValue),\n                    (uint)Random.Shared.Next(int.MinValue, int.MaxValue),\n                    remindersHashes);\n            }));\n        }\n\n        private async Task TestRemindersHashInterval(IReminderTable reminderTable, uint beginHash, uint endHash,\n            uint[] remindersHashes)\n        {\n            var rowsTask = reminderTable.ReadRows(beginHash, endHash);\n            var expectedHashes = beginHash < endHash\n                ? remindersHashes.Where(r => r > beginHash && r <= endHash)\n                : remindersHashes.Where(r => r > beginHash || r <= endHash);\n\n            HashSet<uint> expectedSet = new HashSet<uint>(expectedHashes);\n            var returnedHashes = (await rowsTask).Reminders.Select(r => r.GrainId.GetUniformHashCode());\n            var returnedSet = new HashSet<uint>(returnedHashes);\n\n            Assert.True(returnedSet.SetEquals(expectedSet));\n        }\n\n        private static ReminderEntry CreateReminder(GrainId grainId, string reminderName)\n        {\n            var now = DateTime.UtcNow;\n            now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);\n            return new ReminderEntry\n            {\n                GrainId = grainId,\n                Period = TimeSpan.FromMinutes(1),\n                StartAt = now,\n                ReminderName = reminderName\n            };\n        }\n\n        private static GrainId MakeTestGrainReference() => LegacyGrainId.GetGrainId(12345, Guid.NewGuid(), \"foo/bar\\\\#baz?\");\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/RetryHelper.cs",
    "content": "using System.Diagnostics;\n\nnamespace UnitTests\n{\n    /// <summary>\n    /// Predetermined retry operation, used with <see cref=\"RetryHelper\"/>.\n    /// </summary>\n    /// <remarks>A very crude system for current tests.</remarks>\n    public static class RetryOperation\n    {\n        /// <summary>\n        /// Produces sigmoid shaped delay curve.\n        /// </summary>\n        /// <param name=\"retryAttempt\">The current retry attempt.</param>\n        /// <returns>Delay for the next attempt to retry.</returns>\n        /// <remarks>This function has not received deep scrutiny.</remarks>\n        public static TimeSpan Sigmoid(int retryAttempt)\n        {\n            const int MaxDurationInSeconds = 50;\n            return TimeSpan.FromMilliseconds(Convert.ToInt32(Math.Round((1 / (1 + Math.Exp(-retryAttempt + 3))) * MaxDurationInSeconds)) * 1000);\n        }\n\n\n        /// <summary>\n        /// Produces a linear delay curve in increments of 10 ms.\n        /// </summary>\n        /// <param name=\"retryAttempt\">The current retry attempt.</param>\n        /// <remarks>This function has not received deep scrutiny.</remarks>\n        public static TimeSpan LinearWithTenMilliseconds(int retryAttempt)\n        {\n            return TimeSpan.FromMilliseconds(retryAttempt * 10);\n        }\n    }\n\n\n    /// <summary>\n    /// A simple retry helper to make testing more robust.\n    /// </summary>\n    internal static class RetryHelper\n    {\n        /// <summary>\n        /// A scaffolding function to retry operations according to parameters.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type of the function to retry.</typeparam>\n        /// <param name=\"maxAttempts\">Maximum number of retry attempts.</param>\n        /// <param name=\"retryFunction\">The function taking the current retry parameter that provides the time to wait for next attempt.</param>\n        /// <param name=\"operation\">The operation to retry.</param>\n        /// <param name=\"cancellation\">The cancellation token.</param>\n        /// <returns>The result of the retry.</returns>\n        internal static async Task<TResult> RetryOnExceptionAsync<TResult>(int maxAttempts, Func<int, TimeSpan> retryFunction, Func<Task<TResult>> operation, CancellationToken cancellation = default)\n        {\n            const int MinAttempts = 1;\n            if(maxAttempts <= MinAttempts)\n            {\n                throw new ArgumentOutOfRangeException(nameof(maxAttempts), $\"The count of {maxAttempts} needs to be at least {MinAttempts}.\");\n            }\n\n            if(operation == null)\n            {\n                throw new ArgumentNullException(nameof(operation));\n            }\n\n            var attempts = 0;\n            while(true)\n            {\n                try\n                {\n                    cancellation.ThrowIfCancellationRequested();\n\n                    attempts++;\n                    return await operation().ConfigureAwait(false);\n                }\n                catch(Exception ex)\n                {\n                    if(attempts == maxAttempts)\n                    {\n                        throw;\n                    }\n\n                    Trace.WriteLine(ex);\n                    await Task.Delay(retryFunction(attempts), cancellation).ConfigureAwait(false);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/SiloMetadataTests/SiloMetadataTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime.MembershipService.SiloMetadata;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace UnitTests.SiloMetadataTests;\n\n/// <summary>\n/// Tests for silo metadata configuration, retrieval, and synchronization across cluster.\n/// </summary>\n[TestCategory(\"SiloMetadata\")]\npublic class SiloMetadataTests(SiloMetadataTests.Fixture fixture) : IClassFixture<SiloMetadataTests.Fixture>\n{\n    private static readonly List<KeyValuePair<string, string>> Metadata =\n        [\n            new(\"Orleans:Metadata:first\", \"1\"),\n            new(\"Orleans:Metadata:second\", \"2\"),\n            new(\"Orleans:Metadata:third\", \"3\")\n        ];\n\n    public class Fixture : IAsyncLifetime\n    {\n        public InProcessTestCluster Cluster { get; private set; }\n        public async Task DisposeAsync()\n        {\n            if (Cluster is { } cluster)\n            {\n                await cluster.DisposeAsync();\n            }\n        }\n\n        public async Task InitializeAsync()\n        {\n            var builder = new InProcessTestClusterBuilder(3);\n            builder.ConfigureSiloHost((options, hostBuilder) =>\n            {\n                hostBuilder.Configuration.AddInMemoryCollection(Metadata);\n            });\n\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder\n                .UseSiloMetadata()\n                .UseSiloMetadata(new Dictionary<string, string>\n                {\n                    {\"host.id\", Guid.NewGuid().ToString()}\n                });\n            });\n\n            Cluster = builder.Build();\n            await Cluster.DeployAsync();\n            await Cluster.WaitForLivenessToStabilizeAsync();\n        }\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void SiloMetadata_FromConfiguration_CanBeSetAndRead()\n    {\n        fixture.Cluster.AssertAllSiloMetadataMatchesOnAllSilos(Metadata.Select(kv => kv.Key.Split(':').Last()).ToArray());\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void SiloMetadata_HasConfiguredValues()\n    {\n        var first = fixture.Cluster.Silos.First();\n        var firstSp = fixture.Cluster.GetSiloServiceProvider(first.SiloAddress);\n        var firstSiloMetadataCache = firstSp.GetRequiredService<ISiloMetadataCache>();\n        var metadata = firstSiloMetadataCache.GetSiloMetadata(first.SiloAddress);\n        Assert.NotNull(metadata);\n        Assert.NotNull(metadata.Metadata);\n        Assert.True(metadata.Metadata.Count >= Metadata.Count);\n        foreach (var kv in Metadata)\n        {\n            Assert.Equal(kv.Value, metadata.Metadata[kv.Key.Split(':').Last()]);\n        }\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void SiloMetadata_CanBeSetAndRead()\n    {\n        fixture.Cluster.AssertAllSiloMetadataMatchesOnAllSilos([\"host.id\"]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task SiloMetadata_NewSilosHaveMetadata()\n    {\n        await fixture.Cluster.StartAdditionalSiloAsync();\n        await fixture.Cluster.WaitForLivenessToStabilizeAsync();\n        fixture.Cluster.AssertAllSiloMetadataMatchesOnAllSilos([\"host.id\"]);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public async Task SiloMetadata_RemovedSiloHasNoMetadata()\n    {\n        fixture.Cluster.AssertAllSiloMetadataMatchesOnAllSilos([\"host.id\"]);\n        var first = fixture.Cluster.Silos.First();\n        var firstSp = fixture.Cluster.GetSiloServiceProvider(first.SiloAddress);\n        var firstSiloMetadataCache = firstSp.GetRequiredService<ISiloMetadataCache>();\n\n        var second = fixture.Cluster.Silos.Skip(1).First();\n        var metadata = firstSiloMetadataCache.GetSiloMetadata(second.SiloAddress);\n        Assert.NotNull(metadata);\n        Assert.NotEmpty(metadata.Metadata);\n\n        await fixture.Cluster.StopSiloAsync(second);\n        metadata = firstSiloMetadataCache.GetSiloMetadata(second.SiloAddress);\n        Assert.NotNull(metadata);\n        Assert.Empty(metadata.Metadata);\n    }\n\n    [Fact, TestCategory(\"Functional\")]\n    public void SiloMetadata_BadSiloAddressHasNoMetadata()\n    {\n        var first = fixture.Cluster.Silos.First();\n        var firstSp = fixture.Cluster.GetSiloServiceProvider(first.SiloAddress);\n        var firstSiloMetadataCache = firstSp.GetRequiredService<ISiloMetadataCache>();\n        var metadata = firstSiloMetadataCache.GetSiloMetadata(SiloAddress.Zero);\n        Assert.NotNull(metadata);\n        Assert.Empty(metadata.Metadata);\n    }\n}\n\npublic static class SiloMetadataTestExtensions\n{\n    public static void AssertAllSiloMetadataMatchesOnAllSilos(this InProcessTestCluster hostedCluster, string[] expectedKeys)\n    {\n        var exampleSiloMetadata = new Dictionary<SiloAddress, SiloMetadata>();\n        var first = hostedCluster.Silos.First();\n        var firstSp = hostedCluster.GetSiloServiceProvider(first.SiloAddress);\n        var firstSiloMetadataCache = firstSp.GetRequiredService<ISiloMetadataCache>();\n        foreach (var otherSilo in hostedCluster.Silos)\n        {\n            var metadata = firstSiloMetadataCache.GetSiloMetadata(otherSilo.SiloAddress);\n            Assert.NotNull(metadata);\n            Assert.NotNull(metadata.Metadata);\n            foreach (var expectedKey in expectedKeys)\n            {\n                Assert.True(metadata.Metadata.ContainsKey(expectedKey));\n            }\n            exampleSiloMetadata.Add(otherSilo.SiloAddress, metadata);\n        }\n\n        foreach (var hostedClusterSilo in hostedCluster.Silos.Skip(1))\n        {\n            var sp = hostedCluster.GetSiloServiceProvider(hostedClusterSilo.SiloAddress);\n            var siloMetadataCache = sp.GetRequiredService<ISiloMetadataCache>();\n            var remoteMetadata = new Dictionary<SiloAddress, SiloMetadata>();\n            foreach (var otherSilo in hostedCluster.Silos)\n            {\n                var metadata = siloMetadataCache.GetSiloMetadata(otherSilo.SiloAddress);\n                Assert.NotNull(metadata);\n                Assert.NotNull(metadata.Metadata);\n                foreach (var expectedKey in expectedKeys)\n                {\n                    Assert.True(metadata.Metadata.ContainsKey(expectedKey));\n                }\n                remoteMetadata.Add(otherSilo.SiloAddress, metadata);\n            }\n\n            //Assert that the two dictionaries have the same keys and the values for those keys are the same\n            Assert.Equal(exampleSiloMetadata.Count, remoteMetadata.Count);\n            foreach (var kvp in exampleSiloMetadata)\n            {\n                Assert.Equal(kvp.Value.Metadata.Count, remoteMetadata[kvp.Key].Metadata.Count);\n                foreach (var kvp2 in kvp.Value.Metadata)\n                {\n                    Assert.True(remoteMetadata[kvp.Key].Metadata.TryGetValue(kvp2.Key, out var value),\n                        $\"Key '{kvp2.Key}' not found in actual dictionary.\");\n                    Assert.Equal(kvp2.Value, value);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/CommonStorageTests.cs",
    "content": "using System.Globalization;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing UnitTests.StorageTests.Relational.TestDataSets;\nusing Xunit;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// The storage tests with assertions that should hold for any back-end.\n    /// </summary>\n    /// <remarks>\n    /// This is not in an inheritance hierarchy to allow for cleaner separation for any framework\n    /// code and even testing the tests. The tests use unique news (Guids) so the storage doesn't\n    /// need to be cleaned until all the storage tests have been run.\n    /// </remarks>\n    internal class CommonStorageTests\n    {\n        public CommonStorageTests(IGrainStorage storage) => Storage = storage ?? throw new ArgumentNullException(nameof(storage));\n\n        /// <summary>\n        /// The storage provider under test.\n        /// </summary>\n        public IGrainStorage Storage { get; }\n\n        /// <summary>\n        /// Creates a new grain and a grain reference pair.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <param name=\"version\">The initial version of the state.</param>\n        /// <returns>A grain reference and a state pair.</returns>\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Style\", \"IDE0022\")]\n        internal (GrainId GrainId, GrainState<TestState1> GrainState)  GetTestReferenceAndState(long grainId, string version)\n        {\n            var id = GrainId.Create(GrainType.Create(\"my-grain-type\"), GrainIdKeyExtensions.CreateIntegerKey(grainId));\n            var grainState = new GrainState<TestState1> { State = new TestState1(), ETag = version };\n            return (id, grainState);\n        }\n\n        /// <summary>\n        /// Creates a new grain and a grain reference pair.\n        /// </summary>\n        /// <param name=\"grainId\">The grain ID.</param>\n        /// <param name=\"version\">The initial version of the state.</param>\n        /// <returns>A grain reference and a state pair.</returns>\n        internal (GrainId GrainId, GrainState<TestState1> GrainState) GetTestReferenceAndState(string grainId, string version)\n        {\n            var id = GrainId.Create(\"my-grain-type\", grainId);\n            var grainState = new GrainState<TestState1> { State = new TestState1(), ETag = version };\n            return (id, grainState);\n        }\n\n        /// <summary>\n        /// Writes a known inconsistent state to the storage and asserts an exception will be thrown.\n        /// </summary>\n        /// <returns></returns>\n        internal async Task PersistenceStorage_Relational_WriteReadIdCyrillic()\n        {\n            var grainTypeName = GrainTypeGenerator.GetGrainType<Guid>();\n            var grainReference = this.GetTestReferenceAndState(0, null);\n            var grainState = grainReference.GrainState;\n            await Storage.WriteStateAsync(grainTypeName, grainReference.GrainId, grainState).ConfigureAwait(false);\n            var storedGrainState = new GrainState<TestState1> { State = new TestState1() };\n            await Storage.ReadStateAsync(grainTypeName, grainReference.GrainId, storedGrainState).ConfigureAwait(false);\n\n            Assert.Equal(grainState.ETag, storedGrainState.ETag);\n            Assert.Equal(grainState.State, storedGrainState.State);\n        }\n\n        /// <summary>\n        /// Writes to storage and tries to re-write the same state with NULL as ETag, as if the\n        /// grain was just created.\n        /// </summary>\n        /// <returns>\n        /// The <see cref=\"InconsistentStateException\"/> thrown by the provider. This can be further\n        /// inspected by the storage specific asserts.\n        /// </returns>\n        internal async Task<InconsistentStateException> PersistenceStorage_WriteDuplicateFailsWithInconsistentStateException()\n        {\n            //A grain with a random ID will be arranged to the database. Then its state is set to null to simulate the fact\n            //it is like a second activation after a one that has succeeded to write.\n            string grainTypeName = GrainTypeGenerator.GetGrainType<Guid>();\n            var (grainId, grainState) = this.GetTestReferenceAndState(RandomUtilities.GetRandom<long>(), null);\n\n            await Store_WriteRead(grainTypeName, grainId, grainState).ConfigureAwait(false);\n            grainState.ETag = null;\n            var exception = await Record.ExceptionAsync(() => Store_WriteRead(grainTypeName, grainId, grainState)).ConfigureAwait(false);\n\n            Assert.NotNull(exception);\n            Assert.IsType<InconsistentStateException>(exception);\n\n            return (InconsistentStateException)exception;\n        }\n\n        /// <summary>\n        /// Writes a known inconsistent state to the storage and asserts an exception will be thrown.\n        /// </summary>\n        /// <returns>\n        /// The <see cref=\"InconsistentStateException\"/> thrown by the provider. This can be further\n        /// inspected by the storage specific asserts.\n        /// </returns>\n        internal async Task<InconsistentStateException> PersistenceStorage_WriteInconsistentFailsWithInconsistentStateException()\n        {\n            //Some version not expected to be in the storage for this type and ID.\n            var inconsistentStateVersion = RandomUtilities.GetRandom<int>().ToString(CultureInfo.InvariantCulture);\n\n            var inconsistentState = this.GetTestReferenceAndState(RandomUtilities.GetRandom<long>(), inconsistentStateVersion);\n            string grainTypeName = GrainTypeGenerator.GetGrainType<Guid>();\n            var exception = await Record.ExceptionAsync(() => Store_WriteRead(grainTypeName, inconsistentState.GrainId, inconsistentState.GrainState)).ConfigureAwait(false);\n\n            Assert.NotNull(exception);\n            Assert.IsType<InconsistentStateException>(exception);\n\n            return (InconsistentStateException)exception;\n        }\n\n        internal async Task PersistenceStorage_WriteReadWriteReadStatesInParallel(string prefix = nameof(this.PersistenceStorage_WriteReadWriteReadStatesInParallel), int countOfGrains = 100)\n        {\n            //As data is written and read the Version numbers (ETags) are as checked for correctness (they change).\n            //Additionally the Store_WriteRead tests does its validation.\n            var grainTypeName = GrainTypeGenerator.GetGrainType<Guid>();\n            int StartOfRange = 33900;\n            int CountOfRange = countOfGrains;\n\n            //Since the version is NULL, storage provider tries to insert this data\n            //as new state. If there is already data with this class, the writing fails\n            //and the storage provider throws. Essentially it means either this range\n            //is ill chosen or the test failed due to another problem.\n            var grainStates = Enumerable.Range(StartOfRange, CountOfRange).Select(i => GetTestReferenceAndState($\"{prefix}-{Guid.NewGuid():N}-{i}\", null)).ToList();\n\n            // Avoid parallelization of the first write to not stress out the system with deadlocks\n            // on INSERT\n            foreach (var grainData in grainStates)\n            {\n                //A sanity checker that the first version really has null as its state. Then it is stored\n                //to the database and a new version is acquired.\n                var firstVersion = grainData.GrainState.ETag;\n                Assert.Null(firstVersion);\n\n                await Store_WriteRead(grainTypeName, grainData.GrainId, grainData.GrainState).ConfigureAwait(false);\n                var secondVersion = grainData.GrainState.ETag;\n                Assert.NotEqual(firstVersion, secondVersion);\n            };\n\n            int MaxNumberOfThreads = Environment.ProcessorCount * 3;\n            // The purpose of Parallel.ForEachAsync is to ensure the storage provider will be tested from\n            // multiple threads concurrently, as would happen in running system also. Nevertheless\n            // limit the degree of parallelization (concurrent threads) to avoid unnecessarily\n            // starving and growing the thread pool (which is very slow) if a few threads coupled\n            // with parallelization via tasks can force most concurrency scenarios.\n\n            await Parallel.ForEachAsync(grainStates, new ParallelOptions { MaxDegreeOfParallelism = MaxNumberOfThreads }, async (grainData, ct) =>\n            {\n                // This loop writes the state consecutive times to the database to make sure its\n                // version is updated appropriately.\n                for (int k = 0; k < 10; ++k)\n                {\n                    var versionBefore = grainData.GrainState.ETag;\n                    await RetryHelper.RetryOnExceptionAsync(5, RetryOperation.Sigmoid, async () =>\n                    {\n                        await Store_WriteRead(grainTypeName, grainData.GrainId, grainData.GrainState);\n                        return 0;\n                    });\n\n                    var versionAfter = grainData.GrainState.ETag;\n                    Assert.NotEqual(versionBefore, versionAfter);\n                }\n            });\n        }\n\n        /// <summary>\n        /// Writes to storage, clears and reads back and asserts both the version and the state.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"grainTypeName\">The type of the grain.</param>\n        /// <param name=\"grainReference\">The grain reference as would be given by Orleans.</param>\n        /// <param name=\"grainState\">The grain state the grain would hold and Orleans pass.</param>\n        /// <returns></returns>\n        internal async Task Store_WriteClearRead<T>(string grainTypeName, GrainId grainId, GrainState<T> grainState) where T : new()\n        {\n            //A legal situation for clearing has to be arranged by writing a state to the storage before\n            //clearing it. Writing and clearing both change the ETag, so they should differ.\n            await Storage.WriteStateAsync(grainTypeName, grainId, grainState);\n            var writtenStateVersion = grainState.ETag;\n            var recordExitsAfterWriting = grainState.RecordExists;\n            Assert.True(recordExitsAfterWriting);\n\n            await Storage.ClearStateAsync(grainTypeName, grainId, grainState).ConfigureAwait(false);\n            var clearedStateVersion = grainState.ETag;\n            Assert.NotEqual(writtenStateVersion, clearedStateVersion);\n\n            var recordExitsAfterClearing = grainState.RecordExists;\n            Assert.False(recordExitsAfterClearing);\n\n            var storedGrainState = new GrainState<T> { State = new T(), ETag = clearedStateVersion };\n            await Storage.WriteStateAsync(grainTypeName, grainId, storedGrainState).ConfigureAwait(false);\n            Assert.Equal(storedGrainState.State, Activator.CreateInstance<T>());\n            Assert.True(storedGrainState.RecordExists);\n        }\n\n        /// <summary>\n        /// Writes to storage, reads back and asserts both the version and the state.\n        /// </summary>\n        /// <typeparam name=\"T\">The grain state type.</typeparam>\n        /// <param name=\"grainTypeName\">The type of the grain.</param>\n        /// <param name=\"grainReference\">The grain reference as would be given by Orleans.</param>\n        /// <param name=\"grainState\">The grain state the grain would hold and Orleans pass.</param>\n        /// <returns></returns>\n        internal async Task Store_WriteRead<T>(string grainTypeName, GrainId grainId, GrainState<T> grainState) where T : new()\n        {\n            await Storage.WriteStateAsync(grainTypeName, grainId, grainState).ConfigureAwait(false);\n            var storedGrainState = new GrainState<T> { State = new T() };\n            await Storage.ReadStateAsync(grainTypeName, grainId, storedGrainState).ConfigureAwait(false);\n\n            Assert.Equal(grainState.ETag, storedGrainState.ETag);\n            Assert.Equal(grainState.State, storedGrainState.State);\n            Assert.True(storedGrainState.RecordExists);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/CommonStorageUtilities.cs",
    "content": "using Xunit;\n\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Common utilities to be used while testing storage providers.\n    /// </summary>\n    public static class CommonStorageUtilities\n    {\n        /// <summary>\n        /// Asserts certain information is present in the <see cref=\"Orleans.Storage.InconsistentStateException\"/>.\n        /// </summary>\n        /// <param name=\"exceptionMessage\">The exception message to assert.</param>\n        public static void AssertRelationalInconsistentExceptionMessage(string exceptionMessage)\n        {\n            Assert.Contains(\"ServiceId=\", exceptionMessage);\n            Assert.Contains(\"ProviderName=\", exceptionMessage);\n            Assert.Contains(\"GrainType=\", exceptionMessage);\n            Assert.Contains(\"GrainId=\", exceptionMessage);\n            Assert.Contains(\"ETag=\", exceptionMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/HierarchicalKeyStoreTests.cs",
    "content": "using System.Globalization;\nusing Orleans.Storage;\nusing Xunit;\n\nnamespace UnitTests.StorageTests\n{\n    /// <summary>\n    /// Tests for hierarchical key-value store operations including multi-key storage.\n    /// </summary>\n    public class HierarchicalKeyStoreTests : IClassFixture<HierarchicalKeyStoreTests.Fixture>\n    {\n        public class Fixture\n        {\n            public Fixture()\n            {\n            }\n        }\n\n        private const string KeyName1 = \"Key1\";\n        private const string KeyName2 = \"Key2\";\n        private const string KeyName3 = \"Key3\";\n        private const string ValueName1 = \"Value1\";\n        private const string ValueName2 = \"Value2\";\n        private const string ValueName3 = \"Value3\";\n\n        private static int _keyCounter = 1;\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_MakeKey()\n        {\n            //string testName = TestContext.TestName;\n\n            var keys = new[]\n            {\n                Tuple.Create(\"One\", \"1\"),\n                Tuple.Create(\"Two\", \"2\")\n            }.ToList();\n\n            string keyStr = HierarchicalKeyStore.MakeStoreKey(keys);\n            Assert.Equal(\"One=1+Two=2\", keyStr); // Output from MakeStoreKey\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_1Key_Read_Write()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n\n            var keys = new[]\n            {\n                Tuple.Create(KeyName1, key1.ToString(CultureInfo.InvariantCulture))\n            }.ToList();\n\n            var data = new Dictionary<string, object>();\n            data.Add(ValueName1, testName);\n\n            var store = new HierarchicalKeyStore(1);\n            _ = store.WriteRow(keys, data, null);\n\n            var result = store.ReadRow(keys);\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_2Key_Read_Write()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n\n            var keys = new[]\n            {\n                Tuple.Create(KeyName1, key1.ToString(CultureInfo.InvariantCulture)),\n                Tuple.Create(KeyName2, key2.ToString(CultureInfo.InvariantCulture))\n            }.ToList();\n\n            var data = new Dictionary<string, object>();\n            data.Add(ValueName1, testName);\n\n            var store = new HierarchicalKeyStore(2);\n            _ = store.WriteRow(keys, data, null);\n\n            var result = store.ReadRow(keys);\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_3Key_Read_Write()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n            int key3 = _keyCounter++;\n\n            var keys = new[]\n            {\n                Tuple.Create(KeyName1, key1.ToString(CultureInfo.InvariantCulture)),\n                Tuple.Create(KeyName2, key2.ToString(CultureInfo.InvariantCulture)),\n                Tuple.Create(KeyName3, key3.ToString(CultureInfo.InvariantCulture))\n            }.ToList();\n\n            var data = new Dictionary<string, object>();\n            data[ValueName1] = testName + 1;\n            data[ValueName2] = testName + 2;\n            data[ValueName3] = testName + 3;\n\n            var store = new HierarchicalKeyStore(3);\n            _ = store.WriteRow(keys, data, null);\n\n            var result = store.ReadRow(keys);\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_Write2()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n\n            List<Tuple<string, string>> keys = MakeKeys(key1, key2);\n\n            var data = new Dictionary<string, object>();\n            data[ValueName1] = testName;\n\n            var store = new HierarchicalKeyStore(keys.Count);\n\n            // Write #1\n            string eTag = store.WriteRow(keys, data, null);\n\n            data[ValueName1] = \"One\";\n            data[ValueName2] = \"Two\";\n            data[ValueName3] = \"Three\";\n\n            // Write #2\n            _ = store.WriteRow(keys, data, eTag);\n\n            var result = store.ReadRow(keys);\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_DeleteRow()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n            int key3 = _keyCounter++;\n            int key4 = _keyCounter++;\n\n            List<Tuple<string, string>> keys1 = MakeKeys(key1, key2);\n            List<Tuple<string, string>> keys2 = MakeKeys(key3, key4);\n\n            var data = new Dictionary<string, object>();\n            data[ValueName1] = testName;\n\n            var store = new HierarchicalKeyStore(keys1.Count);\n\n            // Write #1\n            string eTag = store.WriteRow(keys1, data, null);\n\n            data[ValueName1] = \"One\";\n            data[ValueName2] = \"Two\";\n            data[ValueName3] = \"Three\";\n\n            // Write #2\n            string newEtag = store.WriteRow(keys2, data, eTag);\n\n            store.DeleteRow(keys1, newEtag);\n\n            var result = store.ReadRow(keys1);\n\n            Assert.NotNull(result); // Should not be Null result after DeleteRow\n            Assert.Empty(result); // No data after DeleteRow\n\n            result = store.ReadRow(keys2);\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_Read_PartialKey()\n        {\n            string testName = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n\n            List<Tuple<string, string>> keys = MakeKeys(key1, key2);\n\n            var data = new Dictionary<string, object>();\n            data[ValueName1] = testName + 1;\n            data[ValueName2] = testName + 2;\n            data[ValueName3] = testName + 3;\n\n            var store = new HierarchicalKeyStore(keys.Count);\n            _ = store.WriteRow(keys, data, null);\n\n            var readKeys = new List<Tuple<string, string>>();\n            readKeys.Add(keys.First());\n\n            var results = store.ReadMultiRow(readKeys);\n\n            Assert.NotNull(results); // Null results\n            Assert.Single(results); // Number of results\n\n            var result = results.First();\n\n            Assert.NotNull(result); // Null result\n            foreach (string valueName in data.Keys)\n            {\n                Assert.Equal(data[valueName], result[valueName]);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"MemoryStore\")]\n        public void HKS_KeyNotFound()\n        {\n            _ = Guid.NewGuid().ToString(); //TestContext.TestName;\n\n            int key1 = _keyCounter++;\n            int key2 = _keyCounter++;\n\n            List<Tuple<string, string>> keys = MakeKeys(key1, key2);\n\n            var store = new HierarchicalKeyStore(keys.Count);\n\n            var result = store.ReadRow(keys);\n\n            Assert.NotNull(result); // Null result\n            Assert.Empty(result); // No data\n        }\n\n        // Utility methods\n\n        private List<Tuple<string, string>> MakeKeys(int key1, int key2)\n        {\n            var keys = new[]\n            {\n                Tuple.Create(KeyName1, key1.ToString(CultureInfo.InvariantCulture)),\n                Tuple.Create(KeyName2, key2.ToString(CultureInfo.InvariantCulture))\n            }.ToList();\n            return keys;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/LocalStoreTests.cs",
    "content": "using System.Diagnostics;\nusing System.Text;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing TestExtensions;\nusing UnitTests.Persistence;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.StorageTests\n{\n    [Serializable]\n    public enum ProviderType\n    {\n        AzureTable,\n        Memory,\n        Mock,\n        File,\n        AdoNet\n    }\n    \n    /// <summary>\n    /// Tests for local data store operations including read, write, and delete functionality.\n    /// </summary>\n    [Collection(TestEnvironmentFixture.DefaultCollection)]\n    public class LocalStoreTests\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TestEnvironmentFixture fixture;\n\n        public LocalStoreTests(ITestOutputHelper output, TestEnvironmentFixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public void Store_Read()\n        {\n            string name = Guid.NewGuid().ToString();//TestContext.TestName;\n\n            ILocalDataStore store = new HierarchicalKeyStore(2);\n\n            GrainReference reference = (GrainReference)this.fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            TestStoreGrainState state = new TestStoreGrainState();\n            var stateProperties = AsDictionary(state);\n            var keys = GetKeys(name, reference);\n            store.WriteRow(keys, stateProperties, null);\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            var data = store.ReadRow(keys);\n            TimeSpan readTime = sw.Elapsed;\n            output.WriteLine(\"{0} - Read time = {1}\", store.GetType().FullName, readTime);\n            Assert.Equal(state.A,  data[\"A\"]);  // \"A\"\n            Assert.Equal(state.B,  data[\"B\"]);  // \"B\"\n            Assert.Equal(state.C,  data[\"C\"]);  // \"C\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public void Store_WriteRead()\n        {\n            string name = Guid.NewGuid().ToString();//TestContext.TestName;\n\n            ILocalDataStore store = new HierarchicalKeyStore(2);\n\n            GrainReference reference = (GrainReference)fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            var state = TestStoreGrainState.NewRandomState();\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            var keys = GetKeys(name, reference);\n            var stateProperties = AsDictionary(state.State);\n            store.WriteRow(keys, stateProperties, state.ETag);\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n            var data = store.ReadRow(keys);\n            TimeSpan readTime = sw.Elapsed;\n            output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.Equal(state.State.A,  data[\"A\"]);  // \"A\"\n            Assert.Equal(state.State.B,  data[\"B\"]);  // \"B\"\n            Assert.Equal(state.State.C,  data[\"C\"]);  // \"C\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public void Store_Delete()\n        {\n            string name = Guid.NewGuid().ToString();//TestContext.TestName;\n\n            ILocalDataStore store = new HierarchicalKeyStore(2);\n\n            GrainReference reference = (GrainReference)this.fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            var data = TestStoreGrainState.NewRandomState();\n\n            output.WriteLine(\"Using store = {0}\", store.GetType().FullName);\n            Stopwatch sw = new Stopwatch();\n\n            var keys = GetKeys(name, reference);\n\n            sw.Restart();\n            string eTag = store.WriteRow(keys, AsDictionary(data.State), null);\n            output.WriteLine(\"Write returned Etag={0} after {1} {2}\", eTag, sw.Elapsed, StorageProviderUtils.PrintOneWrite(keys, data, eTag));\n\n            sw.Restart();\n            var storedData = store.ReadRow(keys);\n            output.WriteLine(\"Read returned {0} after {1}\", StorageProviderUtils.PrintOneWrite(keys, storedData, eTag), sw.Elapsed);\n            Assert.NotNull(data); // Should get some data from Read\n\n            sw.Restart();\n            bool ok = store.DeleteRow(keys, eTag);\n            Assert.True(ok, $\"Row deleted OK after {sw.Elapsed}. Etag={eTag} Keys={StorageProviderUtils.PrintKeys(keys)}\");\n\n            sw.Restart();\n            storedData = store.ReadRow(keys); // Try to re-read after delete\n            output.WriteLine(\"Re-Read took {0} and returned {1}\", sw.Elapsed, StorageProviderUtils.PrintData(storedData));\n            Assert.NotNull(data); // Should not get null data from Re-Read\n            Assert.True(storedData.Count == 0, $\"Should get no data from Re-Read but got: {StorageProviderUtils.PrintData(storedData)}\");\n\n            sw.Restart();\n            const string oldEtag = null;\n            eTag = store.WriteRow(keys, storedData, oldEtag);\n            output.WriteLine(\"Write for Keys={0} Etag={1} Data={2} returned New Etag={3} after {4}\",\n                StorageProviderUtils.PrintKeys(keys), oldEtag, StorageProviderUtils.PrintData(storedData),\n                eTag, sw.Elapsed);\n\n            sw.Restart();\n            ok = store.DeleteRow(keys, eTag);\n            Assert.True(ok, $\"Row deleted OK after {sw.Elapsed}. Etag={eTag} Keys={StorageProviderUtils.PrintKeys(keys)}\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public void Store_ReadMulti()\n        {\n            string name = Guid.NewGuid().ToString();//TestContext.TestName;\n\n            ILocalDataStore store = new HierarchicalKeyStore(2);\n\n            // Write #1\n            IList<Tuple<string, string>> keys = new[]\n            {\n                Tuple.Create(\"GrainType\", name),\n                Tuple.Create(\"GrainId\", \"1\")\n            }.ToList();\n            var grainState = TestStoreGrainState.NewRandomState();\n            var state = grainState.State;\n            state.A = name;\n            store.WriteRow(keys, AsDictionary(state), grainState.ETag);\n\n            // Write #2\n            keys = new[]\n            {\n                Tuple.Create(\"GrainType\", name),\n                Tuple.Create(\"GrainId\", \"2\")\n            }.ToList();\n            grainState = TestStoreGrainState.NewRandomState();\n            state = grainState.State;\n            state.A = name;\n            store.WriteRow(keys, AsDictionary(state), grainState.ETag);\n\n            // Multi Read\n            keys = new[]\n            {\n                Tuple.Create(\"GrainType\", name)\n            }.ToList();\n\n            var results = store.ReadMultiRow(keys);\n\n            Assert.Equal(2,  results.Count);  // \"Count\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public void GrainState_Store_WriteRead()\n        {\n            string name = Guid.NewGuid().ToString();//TestContext.TestName;\n\n            ILocalDataStore store = new HierarchicalKeyStore(2);\n\n            GrainReference reference = (GrainReference)this.fixture.InternalGrainFactory.GetGrain(LegacyGrainId.NewId());\n            var grainState = TestStoreGrainState.NewRandomState();\n            var state = grainState.State;\n            Stopwatch sw = new Stopwatch();\n            sw.Start();\n            IList<Tuple<string, string>> keys = new[]\n            {\n                Tuple.Create(\"GrainType\", name),\n                Tuple.Create(\"GrainId\", reference.GrainId.ToString())\n            }.ToList();\n            store.WriteRow(keys, AsDictionary(state), grainState.ETag);\n            TimeSpan writeTime = sw.Elapsed;\n            sw.Restart();\n            var data = store.ReadRow(keys);\n            TimeSpan readTime = sw.Elapsed;\n            output.WriteLine(\"{0} - Write time = {1} Read time = {2}\", store.GetType().FullName, writeTime, readTime);\n            Assert.Equal(state.A,  data[\"A\"]);  // \"A\"\n            Assert.Equal(state.B,  data[\"B\"]);  // \"B\"\n            Assert.Equal(state.C,  data[\"C\"]);  // \"C\"\n        }\n\n        // ---------- Utility methods ----------\n\n        private static IList<Tuple<string, string>> GetKeys(string grainTypeName, GrainReference grain)\n        {\n            var keys = new[]\n            {\n                Tuple.Create(\"GrainType\", grainTypeName),\n                Tuple.Create(\"GrainId\", grain.GrainId.ToString())\n            };\n            return keys.ToList();\n        }\n\n        private static Dictionary<string, object> AsDictionary(object state)\n        {\n            return state.GetType().GetProperties()\n                .Select(v => new KeyValuePair<string, object>(v.Name, v.GetValue(state)))\n                .ToDictionary(pair => pair.Key, pair => pair.Value);\n        }\n    }\n\n    internal static class StorageProviderUtils\n    {\n        public static string PrintKeys(IEnumerable<Tuple<string, string>> keys)\n        {\n            return Utils.EnumerableToString(keys,\n                keyTuple => string.Format(\"Key:{0}={1}\", keyTuple.Item1, keyTuple.Item2 ?? \"null\"));\n        }\n\n        public static string PrintData(object data)\n        {\n            if (data == null)\n            {\n                return \"[ ]\";\n            }\n\n            return data.ToString();\n        }\n\n        public static string PrintOneWrite(\n            IEnumerable<Tuple<string, string>> keys,\n            object data,\n            string eTag)\n        {\n            var sb = new StringBuilder();\n            sb.Append(\"Keys=\").Append(PrintKeys(keys));\n            sb.Append(\" Data=\").Append(PrintData(data));\n            sb.Append(\" Etag=\").Append(eTag ?? \"null\");\n            return sb.ToString();\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/PersistenceGrainTests.cs",
    "content": "//#define REREAD_STATE_AFTER_WRITE_FAILED\n\nusing System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Internal;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing TesterInternal;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\n// ReSharper disable RedundantAssignment\n// ReSharper disable UnusedVariable\n// ReSharper disable InconsistentNaming\n\nnamespace UnitTests.StorageTests\n{\n    /// <summary>\n    /// PersistenceGrainTests - Run with only local unit test silo -- no external dependency on Azure storage\n    /// </summary>\n    public class PersistenceGrainTests_Local : OrleansTestingBase, IClassFixture<PersistenceGrainTests_Local.Fixture>, IDisposable, IAsyncLifetime\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n\n            private class SiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddMemoryGrainStorage(\"MemoryStore\");\n                    hostBuilder.AddTestStorageProvider(MockStorageProviderName1, (sp, name) => ActivatorUtilities.CreateInstance<MockStorageProvider>(sp, name));\n                    hostBuilder.AddTestStorageProvider(MockStorageProviderName2, (sp, name) => ActivatorUtilities.CreateInstance<MockStorageProvider>(sp, name));\n                    hostBuilder.AddTestStorageProvider(MockStorageProviderNameLowerCase, (sp, name) => ActivatorUtilities.CreateInstance<MockStorageProvider>(sp, name));\n                    hostBuilder.AddTestStorageProvider(ErrorInjectorProviderName, (sp, name) => ActivatorUtilities.CreateInstance<ErrorInjectionStorageProvider>(sp));\n\n                    hostBuilder.Services.AddSingleton<OrleansGrainStorageSerializer>();\n                    hostBuilder.AddMemoryGrainStorage(\"OrleansSerializerMemoryStore\", (OptionsBuilder<MemoryGrainStorageOptions> optionsBuilder) =>\n                        optionsBuilder.Configure<OrleansGrainStorageSerializer>((options, serializer) => options.GrainStorageSerializer = serializer));\n                }\n            }\n        }\n\n        private const string DefaultGrainStateName = \"state\";\n        private const string MockStorageProviderName1 = \"test1\";\n        private const string MockStorageProviderName2 = \"test2\";\n        private const string MockStorageProviderNameLowerCase = \"lowercase\";\n        private const string ErrorInjectorProviderName = \"ErrorInjector\";\n        private readonly ITestOutputHelper output;\n\n        protected TestCluster HostedCluster { get; }\n\n        public PersistenceGrainTests_Local(ITestOutputHelper output, Fixture fixture)\n        {\n            this.output = output;\n            HostedCluster = fixture.HostedCluster;\n            ResetMockStorageProvidersHistory();\n        }\n\n        public async Task InitializeAsync()\n        {\n            await SetErrorInjection(ErrorInjectorProviderName, ErrorInjectionPoint.None);\n        }\n\n        public async Task DisposeAsync()\n        {\n            await SetErrorInjection(ErrorInjectorProviderName, ErrorInjectionPoint.None);\n        }\n\n        public void Dispose()\n        {\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Silo_StorageProvider_Name_Missing()\n        {\n            List<SiloHandle> silos = this.HostedCluster.GetActiveSilos().ToList();\n            var silo = silos.First();\n            const string providerName = \"NotPresent\";\n            Assert.False(await this.HostedCluster.Client.GetTestHooks(silo).HasStorageProvider(providerName),\n                    $\"Provider {providerName} on silo {silo.Name} should not be registered\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_CheckStateInit()\n        {\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n            bool ok = await grain.CheckStateInit();\n            Assert.True(ok, \"CheckStateInit OK\");\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_CheckStorageProvider()\n        {\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n            string providerType = await grain.CheckProviderType();\n            Assert.Equal(typeof(MockStorageProvider).FullName, providerType); // StorageProvider provider type\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Init()\n        {\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n            await grain.DoSomething();\n\n            //request InitCount on providers on all silos in this cluster\n            IManagementGrain mgmtGrain = this.HostedCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n            object[] replies = await mgmtGrain.SendControlCommandToProvider<MockStorageProvider>(\n               MockStorageProviderName1, (int)MockStorageProvider.Commands.InitCount, null);\n\n            Assert.Contains(1, replies); // StorageProvider #Init\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Activate_StoredValue()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(guid);\n\n            // Store initial value in storage\n            int initialValue = 567;\n            SetStoredValue<MockStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", initialValue);\n\n            int readValue = await grain.GetValue();\n            Assert.Equal(initialValue, readValue); // Read previously stored value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Generics\")]\n        public async Task Persistence_Grain_Activate_StoredValue_Generic()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n\n            var grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGenericGrain<int>>(guid);\n\n            // Store initial value in storage\n            int initialValue = 567;\n            SetStoredValue<MockStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", initialValue);\n\n            int readValue = await grain.GetValue();\n            Assert.Equal(initialValue, readValue); // Read previously stored value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Activate_Error()\n        {\n            const string providerName = ErrorInjectorProviderName;\n            string grainType = typeof(PersistenceProviderErrorGrain).FullName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(guid);\n\n            // Store initial value in storage\n            int initialValue = 567;\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, grainType, grain, \"Field1\", initialValue);\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeRead);\n\n            await Assert.ThrowsAsync<StorageProviderInjectedError>(() =>\n                grain.GetValue());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Read()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n\n            await grain.DoSomething();\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Write()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n\n            await grain.DoWrite(1);\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(1, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await grain.DoWrite(2);\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(2, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(2, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_ReRead()\n        {\n            const string providerName = MockStorageProviderName1;\n\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(guid);\n\n            await grain.DoSomething();\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n            SetStoredValue<MockStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", 42);\n\n            await grain.DoRead();\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(2, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            Assert.Equal(42, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public async Task MemoryStore_Read_Write()\n        {\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n            IMemoryStorageTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IMemoryStorageTestGrain>(guid);\n\n            int val = await grain.GetValue();\n\n            Assert.Equal(0, val); // Initial value\n\n            await grain.DoWrite(1);\n            val = await grain.GetValue();\n            Assert.Equal(1, val); // Value after Write-1\n\n            await grain.DoWrite(2);\n            val = await grain.GetValue();\n            Assert.Equal(2, val); // Value after Write-2\n\n            val = await grain.DoRead();\n\n            Assert.Equal(2, val); // Value after Re-Read\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public async Task MemoryStore_Delete()\n        {\n            Guid id = Guid.NewGuid();\n            var grain = this.HostedCluster.GrainFactory.GetGrain<IMemoryStorageTestGrain>(id);\n            await grain.DoWrite(1);\n            await grain.DoDelete();\n            int val = await grain.GetValue(); // Should this throw instead?\n            Assert.Equal(0, val); // Value after Delete\n            await grain.DoWrite(2);\n            val = await grain.GetValue();\n            Assert.Equal(2, val); // Value after Delete + New Write\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"CorePerf\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public async Task MemoryStore_Stress_Read()\n        {\n            const int numIterations = 10000;\n\n            Stopwatch sw = Stopwatch.StartNew();\n\n            Task<int>[] promises = new Task<int>[numIterations];\n            for (int i = 0; i < numIterations; i++)\n            {\n                IMemoryStorageTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IMemoryStorageTestGrain>(Guid.NewGuid());\n                int idx = i; // Capture\n                async Task<int> asyncFunc()\n                {\n                    await grain.DoWrite(idx);\n                    return await grain.DoRead();\n                }\n                promises[i] = Task.Run(asyncFunc);\n            }\n            await Task.WhenAll(promises);\n\n            TimeSpan elapsed = sw.Elapsed;\n            double tps = (numIterations * 2) / elapsed.TotalSeconds; // One Read and one Write per iteration\n            output.WriteLine(\"{0} Completed Read-Write operations in {1} at {2} TPS\",  numIterations, elapsed, tps);\n\n            for (int i = 0; i < numIterations; i++)\n            {\n                int expectedVal = i;\n                Assert.Equal(expectedVal,  await promises[i]);  //  \"Returned value - Read @ #\" + i\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Write()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n\n            await grain.DoWrite(1);\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(1, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await grain.DoWrite(2);\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(2, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(2, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Delete()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n\n            await grain.DoWrite(1);\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            int initialReadCount = providerState.ProviderStateForTest.ReadCount;\n            int initialWriteCount = providerState.ProviderStateForTest.WriteCount;\n            int initialDeleteCount = providerState.ProviderStateForTest.DeleteCount;\n\n            await grain.DoDelete();\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(initialDeleteCount + 1, providerState.ProviderStateForTest.DeleteCount); // StorageProvider #Deletes\n            Assert.Null(providerState.LastStoredGrainState); // Store-AfterDelete-Empty\n\n            int val = await grain.GetValue(); // Returns current in-memory null data without re-read.\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName); // update state\n            Assert.Equal(0, val); // Value after Delete\n            Assert.Equal(initialReadCount, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n\n            await grain.DoWrite(2);\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName); // update state\n            Assert.Equal(initialReadCount, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(initialWriteCount + 1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(2, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Read_Error()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceErrorGrain>(id);\n            _ = await grain.GetValue();\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            try\n            {\n                await grain.DoReadError(true);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                Exception e = ae.GetBaseException();\n                if (e is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw e;\n                }\n            }\n\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            try\n            {\n                await grain.DoReadError(false);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                Exception e = ae.GetBaseException();\n                if (e is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw e;\n                }\n            }\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(2, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_Write_Error()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceErrorGrain>(id);\n\n            await grain.DoWrite(1);\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(1, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await grain.DoWrite(2);\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(2, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(2, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            try\n            {\n                await grain.DoWriteError(3, true);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                if (ae.GetBaseException() is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw;\n                }\n            }\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName); // update provider state\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(2, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(2, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            try\n            {\n                await grain.DoWriteError(4, false);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                if (ae.GetBaseException() is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw;\n                }\n            }\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(3, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            Assert.Equal(4, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_ReRead_Error()\n        {\n            const string providerName = \"test1\";\n\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n            IPersistenceErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceErrorGrain>(guid);\n            _ = await grain.GetValue();\n\n            var providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n\n            Assert.Equal(1, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes\n\n            SetStoredValue<MockStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", 42);\n\n            await grain.DoRead();\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(2, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(0, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            Assert.Equal(42, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await grain.DoWrite(43);\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(2, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            Assert.Equal(43, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            try\n            {\n                await grain.DoReadError(true);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                if (ae.GetBaseException() is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw;\n                }\n            }\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(2, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            Assert.Equal(43, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            try\n            {\n                await grain.DoReadError(false);\n            }\n            catch (ApplicationException)\n            {\n                // Expected error\n            }\n            catch (AggregateException ae)\n            {\n                if (ae.GetBaseException() is ApplicationException)\n                {\n                    // Expected error\n                }\n                else\n                {\n                    throw;\n                }\n            }\n            providerState = GetStateForStorageProviderInUse<MockStorageProvider>(providerName);\n            Assert.Equal(3, providerState.ProviderStateForTest.ReadCount); // StorageProvider #Reads-2\n            Assert.Equal(1, providerState.ProviderStateForTest.WriteCount); // StorageProvider #Writes-2\n\n            Assert.Equal(43, providerState.LastStoredGrainState.Field1); // Store-Field1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_BeforeRead()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(guid);\n\n            var val = await grain.GetValue(); // Activate grain\n            int expectedVal = 42;\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n            val = await grain.DoRead();\n\n            Assert.Equal(expectedVal, val); // Returned value\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeRead);\n\n            await CheckStorageProviderErrors(grain.DoRead);\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_AfterRead()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(guid);\n\n            var val = await grain.GetValue(); // Activate grain\n            int expectedVal = 52;\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n\n            val = await grain.DoRead();\n\n            Assert.Equal(expectedVal, val); // Returned value\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.AfterRead);\n            await CheckStorageProviderErrors(grain.DoRead);\n\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n\n            int newVal = 53;\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", newVal);\n\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n\n            await grain.DoRead(); // Force re-read\n            expectedVal = newVal;\n\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_BeforeWrite()\n        {\n            Guid id = Guid.NewGuid();\n            string providerName = ErrorInjectorProviderName;\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(id);\n\n            var val = await grain.GetValue();\n\n            int expectedVal = 62;\n            await grain.DoWrite(expectedVal);\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            const int attemptedVal3 = 63;\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeWrite);\n            await CheckStorageProviderErrors(() => grain.DoWrite(attemptedVal3));\n\n            // Stored value unchanged\n            providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            val = await grain.GetValue();\n            // Stored value unchanged\n            providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n#if REREAD_STATE_AFTER_WRITE_FAILED\n            Assert.Equal(expectedVal, val); // Last value written successfully\n#else\n            Assert.Equal(attemptedVal3, val); // Last value attempted to be written is still in memory\n#endif\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_InconsistentStateException_DeactivatesGrain()\n        {\n            Guid id = Guid.NewGuid();\n            string providerName = ErrorInjectorProviderName;\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(id);\n\n            var val = await grain.GetValue();\n\n            int expectedVal = 62;\n            var originalActivationId = await grain.GetActivationId();\n            await grain.DoWrite(expectedVal);\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            const int attemptedVal3 = 63;\n            await SetErrorInjection(providerName, new ErrorInjectionBehavior\n            {\n                ErrorInjectionPoint = ErrorInjectionPoint.BeforeWrite,\n                ExceptionType = typeof(InconsistentStateException)\n            });\n            await CheckStorageProviderErrors(() => grain.DoWrite(attemptedVal3), typeof(InconsistentStateException));\n\n            // Stored value unchanged\n            providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n            Assert.NotEqual(originalActivationId, await grain.GetActivationId());\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            val = await grain.GetValue();\n            // Stored value unchanged\n            providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            // The value should not have changed.\n            Assert.Equal(expectedVal, val);\n        }\n\n        /// <summary>\n        /// Tests that deactivations caused by an <see cref=\"InconsistentStateException\"/> only affect the grain which\n        /// the exception originated from.\n        /// </summary>\n        /// <returns></returns>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_InconsistentStateException_DeactivatesOnlyCurrentGrain()\n        {\n            var target = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(Guid.NewGuid());\n            var proxy = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorProxyGrain>(Guid.NewGuid());\n\n            // Record the original activation ids.\n            var targetActivationId = await target.GetActivationId();\n            var proxyActivationId = await proxy.GetActivationId();\n\n            // Cause an inconsistent state exception.\n            await SetErrorInjection(ErrorInjectorProviderName, new ErrorInjectionBehavior\n            {\n                ErrorInjectionPoint = ErrorInjectionPoint.BeforeWrite,\n                ExceptionType = typeof(InconsistentStateException)\n            });\n            await CheckStorageProviderErrors(() => proxy.DoWrite(63, target), typeof(InconsistentStateException));\n\n            // The target should have been deactivated by the exception.\n            Assert.NotEqual(targetActivationId, await target.GetActivationId());\n\n            // The grain which called the target grain should not have been deactivated.\n            Assert.Equal(proxyActivationId, await proxy.GetActivationId());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_AfterWrite()\n        {\n            Guid id = Guid.NewGuid();\n            string providerName = ErrorInjectorProviderName;\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(id);\n\n            var val = await grain.GetValue();\n\n            int expectedVal = 82;\n            await grain.DoWrite(expectedVal);\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            const int attemptedVal4 = 83;\n            await SetErrorInjection(providerName, ErrorInjectionPoint.AfterWrite);\n            await CheckStorageProviderErrors(() => grain.DoWrite(attemptedVal4));\n\n            // Stored value has changed\n            expectedVal = attemptedVal4;\n            providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_BeforeReRead()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(guid);\n\n            var val = await grain.GetValue();\n            int expectedVal = 72;\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n            val = await grain.DoRead();\n            Assert.Equal(expectedVal, val); // Returned value\n\n            expectedVal = 73;\n            await grain.DoWrite(expectedVal);\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeRead);\n            await CheckStorageProviderErrors(grain.DoRead);\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Error_AfterReRead()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n            IPersistenceProviderErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceProviderErrorGrain>(guid);\n\n            var val = await grain.GetValue();\n\n            int expectedVal = 92;\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n            val = await grain.DoRead();\n            Assert.Equal(expectedVal, val); // Returned value\n\n            expectedVal = 93;\n            await grain.DoWrite(expectedVal);\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n\n            expectedVal = 94;\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n            await SetErrorInjection(providerName, ErrorInjectionPoint.AfterRead);\n            await CheckStorageProviderErrors(grain.DoRead);\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Error_Handled_Read()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n            IPersistenceUserHandledErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceUserHandledErrorGrain>(guid);\n            _ = await grain.GetValue(); // Activate grain\n            int expectedVal = 42;\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n\n            var val = await grain.DoRead(false);\n\n            Assert.Equal(expectedVal, val); // Returned value\n\n            int newVal = expectedVal + 1;\n\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", newVal);\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeRead);\n            val = await grain.DoRead(true);\n            Assert.Equal(expectedVal, val); // Returned value\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            expectedVal = newVal;\n\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", newVal);\n            val = await grain.DoRead(false);\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Error_Handled_Write()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            _ = guid.ToString(\"N\");\n            IPersistenceUserHandledErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceUserHandledErrorGrain>(guid);\n            _ = await grain.GetValue(); // Activate grain\n            int expectedVal = 42;\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n\n            var val = await grain.DoRead(false);\n\n            Assert.Equal(expectedVal, val); // Returned value\n\n            int newVal = expectedVal + 1;\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeWrite);\n            await grain.DoWrite(newVal, true);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n\n            expectedVal = newVal;\n            await grain.DoWrite(newVal, false);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Error_NotHandled_Write()\n        {\n            string providerName = ErrorInjectorProviderName;\n            Guid guid = Guid.NewGuid();\n            string id = guid.ToString(\"N\");\n            IPersistenceUserHandledErrorGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceUserHandledErrorGrain>(guid);\n\n            var val = await grain.GetValue(); // Activate grain\n            int expectedVal = 42;\n\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n            SetStoredValue<ErrorInjectionStorageProvider>(providerName, DefaultGrainStateName, grain, \"Field1\", expectedVal);\n            val = await grain.DoRead(false);\n\n            Assert.Equal(expectedVal, val); // Returned value after read\n\n            int newVal = expectedVal + 1;\n            await SetErrorInjection(providerName, ErrorInjectionPoint.BeforeWrite);\n            await CheckStorageProviderErrors(() => grain.DoWrite(newVal, false));\n\n            val = await grain.GetValue();\n            // Stored value unchanged\n            var providerState = GetStateForStorageProviderInUse<ErrorInjectionStorageProvider>(providerName);\n            Assert.Equal(expectedVal, providerState.LastStoredGrainState.Field1); // Store-Field1\n#if REREAD_STATE_AFTER_WRITE_FAILED\n            Assert.Equal(expectedVal, val); // After failed write: Last value written successfully\n#else\n            Assert.Equal(newVal, val); // After failed write: Last value attempted to be written is still in memory\n#endif\n            await SetErrorInjection(providerName, ErrorInjectionPoint.None);\n\n            expectedVal = newVal;\n            await grain.DoWrite(newVal, false);\n            val = await grain.GetValue();\n            Assert.Equal(expectedVal, val); // Returned value after good write\n        }\n\n        [Fact, TestCategory(\"Stress\"), TestCategory(\"CorePerf\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Provider_Loop_Read()\n        {\n            const int numIterations = 100;\n\n            Task<int>[] promises = new Task<int>[numIterations];\n            for (int i = 0; i < numIterations; i++)\n            {\n                int expectedVal = i;\n                IPersistenceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceTestGrain>(Guid.NewGuid());\n                Guid guid = grain.GetPrimaryKey();\n                _ = guid.ToString(\"N\");\n\n                SetStoredValue<MockStorageProvider>(MockStorageProviderName1, DefaultGrainStateName, grain, \"Field1\", expectedVal); // Update state data behind grain\n                promises[i] = grain.DoRead();\n            }\n            await Task.WhenAll(promises);\n\n            for (int i = 0; i < numIterations; i++)\n            {\n                int expectedVal = i;\n                Assert.Equal(expectedVal,  await promises[i]);  //  \"Returned value - Read @ #\" + i\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_BadProvider()\n        {\n            IBadProviderTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IBadProviderTestGrain>(Guid.NewGuid());\n            var oex = await Assert.ThrowsAsync<BadProviderConfigException>(() => grain.DoSomething());\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public void OrleansException_BadProvider()\n        {\n            string msg1 = \"BadProvider\";\n            string msg2 = \"Wrapper\";\n            string msg3 = \"Aggregate\";\n\n            var bpce = new BadProviderConfigException(msg1);\n            var oe = new OrleansException(msg2, bpce);\n            var ae = new AggregateException(msg3, oe);\n\n            Assert.NotNull(ae.InnerException); // AggregateException.InnerException should not be null\n            Assert.IsAssignableFrom<OrleansException>(ae.InnerException);\n            Exception exc = ae.InnerException;\n            Assert.NotNull(exc.InnerException); // OrleansException.InnerException should not be null\n            Assert.IsAssignableFrom<BadProviderConfigException>(exc.InnerException);\n\n            exc = ae.GetBaseException();\n            Assert.NotNull(exc.InnerException); // BaseException.InnerException should not be null\n            Assert.IsAssignableFrom<BadProviderConfigException>(exc.InnerException);\n\n            Assert.StartsWith(msg3,  ae.Message);  //  \"AggregateException.Message should be '{0}'\", msg3\n            Assert.Equal(msg2,  exc.Message);  //  \"OrleansException.Message should be '{0}'\", msg2\n            Assert.Equal(msg1,  exc.InnerException.Message);  //  \"InnerException.Message should be '{0}'\", msg1\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"MemoryStore\")]\n        public async Task MemoryStore_UserGrain_Read_Write()\n        {\n            Guid id = Guid.NewGuid();\n            IUser grain = this.HostedCluster.GrainFactory.GetGrain<IUser>(id);\n\n            string name = id.ToString();\n\n            await grain.SetName(name);\n\n            string readName = await grain.GetName();\n\n            Assert.Equal(name, readName); // Read back previously set name\n\n            Guid id1 = Guid.NewGuid();\n            Guid id2 = Guid.NewGuid();\n            string name1 = id1.ToString();\n            string name2 = id2.ToString();\n            IUser friend1 = this.HostedCluster.GrainFactory.GetGrain<IUser>(id1);\n            IUser friend2 = this.HostedCluster.GrainFactory.GetGrain<IUser>(id2);\n            await friend1.SetName(name1);\n            await friend2.SetName(name2);\n\n            var readName1 = await friend1.GetName();\n            var readName2 = await friend2.GetName();\n\n            Assert.Equal(name1, readName1); // Friend #1 Name\n            Assert.Equal(name2, readName2); // Friend #2 Name\n\n            await grain.AddFriend(friend1);\n            await grain.AddFriend(friend2);\n\n            var friends = await grain.GetFriends();\n            Assert.Equal(2, friends.Count); // Number of friends\n            Assert.Equal(name1, await friends[0].GetName()); // GetFriends - Friend #1 Name\n            Assert.Equal(name2, await friends[1].GetName()); // GetFriends - Friend #2 Name\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_Grain_NoState()\n        {\n            const string providerName = MockStorageProviderName1;\n            Guid id = Guid.NewGuid();\n            IPersistenceNoStateTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IPersistenceNoStateTestGrain>(id);\n\n            await grain.DoSomething();\n\n            Assert.True(HasStorageProvider(providerName));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Serialization\")]\n        public void Serialize_GrainState_DeepCopy()\n        {\n            // NOTE: This test requires Silo to be running & Client init so that grain references can be resolved before serialization.\n            IUser[] grains = new IUser[3];\n            grains[0] = this.HostedCluster.GrainFactory.GetGrain<IUser>(Guid.NewGuid());\n            grains[1] = this.HostedCluster.GrainFactory.GetGrain<IUser>(Guid.NewGuid());\n            grains[2] = this.HostedCluster.GrainFactory.GetGrain<IUser>(Guid.NewGuid());\n\n            GrainStateContainingGrainReferences initialState = new GrainStateContainingGrainReferences();\n            foreach (var g in grains)\n            {\n                initialState.GrainList.Add(g);\n                initialState.GrainDict.Add(g.GetPrimaryKey().ToString(), g);\n            }\n\n            var copy = (GrainStateContainingGrainReferences)this.HostedCluster.DeepCopy(initialState);\n            Assert.NotSame(initialState.GrainDict, copy.GrainDict); // Dictionary\n            Assert.NotSame(initialState.GrainList, copy.GrainList); // List\n        }\n\n        [Fact, TestCategory(\"Persistence\"), TestCategory(\"Serialization\"), TestCategory(\"CorePerf\"), TestCategory(\"Stress\")]\n        public async Task Serialize_GrainState_DeepCopy_Stress()\n        {\n            int num = 100;\n            int loops = num * 100;\n            GrainStateContainingGrainReferences[] states = new GrainStateContainingGrainReferences[num];\n            for (int i = 0; i < num; i++)\n            {\n                IUser grain = this.HostedCluster.GrainFactory.GetGrain<IUser>(Guid.NewGuid());\n                states[i] = new GrainStateContainingGrainReferences();\n                states[i].GrainList.Add(grain);\n                states[i].GrainDict.Add(grain.GetPrimaryKey().ToString(), grain);\n            }\n\n            List<Task> tasks = new List<Task>();\n            for (int i = 0; i < loops; i++)\n            {\n                int idx = Random.Shared.Next(num);\n                tasks.Add(Task.Run(() => { var copy = this.HostedCluster.DeepCopy(states[idx]); }));\n                tasks.Add(Task.Run(() => { var other = this.HostedCluster.RoundTripSerializationForTesting(states[idx]); }));\n            }\n            await Task.WhenAll(tasks);\n\n            //Task copyTask = Task.Run(() =>\n            //{\n            //    for (int i = 0; i < loops; i++)\n            //    {\n            //        int idx = random.Next(num);\n            //        var copy = states[idx].DeepCopy();\n            //    }\n            //});\n            //Task serializeTask = Task.Run(() =>\n            //{\n            //    for (int i = 0; i < loops; i++)\n            //    {\n            //        int idx = random.Next(num);\n            //        var other = SerializationManager.RoundTripSerializationForTesting(states[idx]);\n            //    }\n            //});\n            //await Task.WhenAll(copyTask, serializeTask);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Scheduler\"), TestCategory(\"Reentrancy\")]\n        public async Task ReentrentGrainWithState()\n        {\n            Guid id1 = Guid.NewGuid();\n            Guid id2 = Guid.NewGuid();\n            IReentrentGrainWithState grain1 = this.HostedCluster.GrainFactory.GetGrain<IReentrentGrainWithState>(id1);\n            IReentrentGrainWithState grain2 = this.HostedCluster.GrainFactory.GetGrain<IReentrentGrainWithState>(id2);\n            await Task.WhenAll(grain1.Setup(grain2), grain2.Setup(grain1));\n\n            Task t11 = grain1.Test1();\n            Task t12 = grain1.Test2();\n            Task t21 = grain2.Test1();\n            Task t22 = grain2.Test2();\n            await Task.WhenAll(t11, t12, t21, t22);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Scheduler\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrentStressGrainWithoutState()\n        {\n            Guid id1 = Guid.NewGuid();\n            INonReentrantStressGrainWithoutState grain1 = this.HostedCluster.GrainFactory.GetGrain<INonReentrantStressGrainWithoutState>(id1);\n            await grain1.Test1();\n        }\n\n        private const bool DoStart = true; // Task.Delay tests fail (Timeout) unless True\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Scheduler\"), TestCategory(\"Reentrancy\")]\n        public async Task ReentrentGrain_Task_Delay()\n        {\n            Guid id1 = Guid.NewGuid();\n            IReentrentGrainWithState grain1 = this.HostedCluster.GrainFactory.GetGrain<IReentrentGrainWithState>(id1);\n\n            await grain1.Task_Delay(DoStart);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Scheduler\"), TestCategory(\"Reentrancy\")]\n        public async Task NonReentrentGrain_Task_Delay()\n        {\n            Guid id1 = Guid.NewGuid();\n            INonReentrantStressGrainWithoutState grain1 = this.HostedCluster.GrainFactory.GetGrain<INonReentrantStressGrainWithoutState>(id1);\n\n            await grain1.Task_Delay(DoStart);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\"), TestCategory(\"Scheduler\"), TestCategory(\"Reentrancy\")]\n        public async Task StateInheritanceTest()\n        {\n            Guid id1 = Guid.NewGuid();\n            IStateInheritanceTestGrain grain = this.HostedCluster.GrainFactory.GetGrain<IStateInheritanceTestGrain>(id1);\n\n            await grain.SetValue(1);\n            int val = await grain.GetValue();\n            Assert.Equal(1, val);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task SurrogatePersistence_TypeWithoutPublicConstructor_Read()\n        {\n            ISurrogateStateForTypeWithoutPublicConstructorGrain<ExternalTypeWithoutPublicConstructor> grain = HostedCluster.GrainFactory\n                .GetGrain<ISurrogateStateForTypeWithoutPublicConstructorGrain<ExternalTypeWithoutPublicConstructor>>(Guid.NewGuid());\n            ExternalTypeWithoutPublicConstructor instance = ExternalTypeWithoutPublicConstructor.Create(1, 2);\n\n            await grain.SetState(instance);\n            ExternalTypeWithoutPublicConstructor val = await grain.GetState();\n\n            Assert.Equal(1, val.Field1);\n            Assert.Equal(2, val.Field2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Persistence\")]\n        public async Task Persistence_RecordTypeWithoutPublicParameterlessConstructor_Read()\n        {\n            IRecordTypeWithoutPublicParameterlessConstructorGrain<RecordTypeWithoutPublicParameterlessConstructor> grain = HostedCluster.GrainFactory\n                .GetGrain<IRecordTypeWithoutPublicParameterlessConstructorGrain<RecordTypeWithoutPublicParameterlessConstructor>>(Guid.NewGuid());\n            RecordTypeWithoutPublicParameterlessConstructor instance = new RecordTypeWithoutPublicParameterlessConstructor(1);\n\n            await grain.SetState(instance);\n            RecordTypeWithoutPublicParameterlessConstructor val = await grain.GetState();\n\n            Assert.Equal(1, val.Field);\n        }\n\n        // ---------- Utility functions ----------\n        private void SetStoredValue<T>(string providerName, string grainType, IGrain grain, string fieldName, int newValue) where T : IControllable\n        {\n            IManagementGrain mgmtGrain = this.HostedCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n            // set up SetVal func args\n            var args = new MockStorageProvider.SetValueArgs\n            {\n                Val = newValue,\n                Name = \"Field1\",\n                GrainType = grainType,\n                GrainId = grain.GetGrainId(),\n                StateType = typeof(PersistenceTestGrainState)\n            };\n            mgmtGrain.SendControlCommandToProvider<T>(\n                providerName, (int)MockStorageProvider.Commands.SetValue, args).Wait();\n        }\n\n        private async Task SetErrorInjection(string providerName, ErrorInjectionPoint errorInjectionPoint)\n        {\n            await SetErrorInjection(providerName, new ErrorInjectionBehavior { ErrorInjectionPoint = errorInjectionPoint });\n        }\n\n        private async Task SetErrorInjection(string providerName, ErrorInjectionBehavior errorInjectionBehavior)\n        {\n            await ErrorInjectionStorageProvider.SetErrorInjection(providerName, errorInjectionBehavior, this.HostedCluster.GrainFactory);\n        }\n\n        private async Task CheckStorageProviderErrors(Func<Task> taskFunc, Type expectedException = null)\n        {\n            StackTrace at = new StackTrace();\n            TimeSpan timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(15);\n            try\n            {\n                await taskFunc().WaitAsync(timeout);\n\n                if (ErrorInjectionStorageProvider.DoInjectErrors)\n                {\n                    string msg = \"StorageProviderInjectedError exception should have been thrown \" + at;\n                    output.WriteLine(\"Assertion failed: {0}\", msg);\n                    Assert.Fail(msg);\n                }\n            }\n            catch (Exception e)\n            {\n                output.WriteLine(\"Exception caught: {0}\", e);\n                var baseException = e.GetBaseException();\n                if (baseException is OrleansException && baseException.InnerException != null)\n                {\n                    baseException = baseException.InnerException;\n                }\n\n                Assert.IsAssignableFrom(expectedException ?? typeof(StorageProviderInjectedError), baseException);\n                //if (exc is StorageProviderInjectedError)\n                //{\n                //     //Expected error\n                //}\n                //else\n                //{\n                //    output.WriteLine(\"Unexpected exception: {0}\", exc);\n                //    Assert.True(false, exc.ToString());\n                //}\n            }\n        }\n        private bool HasStorageProvider(string providerName)\n        {\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos())\n            {\n                if (this.HostedCluster.Client.GetTestHooks(siloHandle).HasStorageProvider(providerName).Result)\n                {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        private ProviderState GetStateForStorageProviderInUse<T>(string providerName, bool okNull = false) where T : IControllable\n        {\n            ProviderState providerState = new ProviderState();\n            IManagementGrain mgmtGrain = this.HostedCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n            object[] replies = mgmtGrain.SendControlCommandToProvider<T>(\n               providerName, (int)MockStorageProvider.Commands.GetProvideState, null).Result;\n            object[] replies2 = mgmtGrain.SendControlCommandToProvider<T>(\n                              providerName, (int)MockStorageProvider.Commands.GetLastState, null).Result;\n            for(int i = 0; i < replies.Length; i++)\n            {\n                MockStorageProvider.StateForTest state = (MockStorageProvider.StateForTest)replies[i];\n                PersistenceTestGrainState grainState = (PersistenceTestGrainState)replies2[i];\n                if (state.ReadCount > 0)\n                {\n                    providerState.ProviderStateForTest = state;\n                    providerState.LastStoredGrainState = grainState;\n                    return providerState;\n                }\n            }\n\n            return providerState;\n        }\n\n        private class ProviderState\n        {\n            public MockStorageProvider.StateForTest ProviderStateForTest { get; set; }\n            public PersistenceTestGrainState LastStoredGrainState { get; set; }\n        }\n\n        private void ResetMockStorageProvidersHistory()\n        {\n            var mockStorageProviders = new[] { MockStorageProviderName1, MockStorageProviderName2, MockStorageProviderNameLowerCase };\n            foreach (var siloHandle in this.HostedCluster.GetActiveSilos().ToList())\n            {\n                foreach (var providerName in mockStorageProviders)\n                {\n                    if (!this.HostedCluster.Client.GetTestHooks(siloHandle).HasStorageProvider(providerName).Result) continue;\n                    IManagementGrain mgmtGrain = this.HostedCluster.GrainFactory.GetGrain<IManagementGrain>(0);\n                    _ = mgmtGrain.SendControlCommandToProvider<MockStorageProvider>(\n                       providerName, (int)MockStorageProvider.Commands.ResetHistory, null).Result;\n                }\n            }\n        }\n    }\n}\n\n// ReSharper restore RedundantAssignment\n// ReSharper restore UnusedVariable\n// ReSharper restore InconsistentNaming\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/RandomUtilities.cs",
    "content": "using System.Text;\nusing Orleans.Runtime;\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Utility function to provide random values to some tests.\n    /// </summary>\n    public static class RandomUtilities\n    {\n        /// <summary>\n        /// This type code is consistent with Orleans.Runtime.Category.Grain = 3, used also like\n        /// \"public Category IdCategory { get { return GetCategory(TypeCodeData); } }\".\n        /// Note that 0L would likely do also.\n        /// </summary>\n        public const long NormalGrainTypeCode = 3L;\n\n        /// <summary>\n        /// This type code is consistent with Orleans.Runtime.Category.Grain = 6, used also like\n        /// \"public Category IdCategory { get { return GetCategory(TypeCodeData); } }\".\n        /// Note that 0L would likely do also.\n        /// </summary>\n        public const long KeyExtensionGrainTypeCode = 6L;\n\n        /// <summary>\n        /// A list of random generators being used. This list is read-only after construction.\n        /// </summary>\n        /// <remarks>The state, basically the <see cref=\"Range{T}\"/> object isn't used currently.</remarks>\n        private static Dictionary<Type, object> RandomGenerators { get; } = new Dictionary<Type, object>\n        {\n            [typeof(Guid)] = new Func<object, Guid>(_ => Guid.NewGuid()),\n            [typeof(int)] = new Func<object, int>(_ => Random.Shared.Next()),\n            [typeof(long)] = new Func<object, long>(_=> Random.Shared.NextInt64()),\n            [typeof(string)] = new Func<object, string>(symbolSet =>\n            {\n                var count = ((Tuple<Range<long>, SymbolSet>)symbolSet).Item1.Start;\n                var symbols = ((Tuple<Range<long>, SymbolSet>)symbolSet).Item2;\n                var builder = new StringBuilder();\n                for(long i = 0; i < count; ++i)\n                {\n                    var symbolRange = symbols.SetRanges[Random.Shared.Next(symbols.SetRanges.Count)];\n                    builder.Append((char)Random.Shared.Next(symbolRange.Start, symbolRange.End));\n                }\n\n                return builder.ToString();\n            })\n        };\n\n        /// <summary>\n        /// Get a random value of the given type.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns>Random value of the given type.</returns>\n        /// <exception cref=\"ArgumentException\"/>.\n        public static T GetRandom<T>(Range<long> range = null)\n        {\n            object randomGenerator;\n            if(RandomGenerators.TryGetValue(typeof(T), out randomGenerator))\n            {\n                //If this a string type, some symbol set from which to draw the symbols needs to given\n                //and a special kind of a parameter constructed.\n                if((typeof(T) == typeof(string)))\n                {\n                    const long SymbolsDefaultCount = 15;\n                    var symbols = new SymbolSet(SymbolSet.Latin1);\n                    return ((Func<object, T>)randomGenerator)(Tuple.Create(range ?? new Range<long>(SymbolsDefaultCount, SymbolsDefaultCount), symbols));\n                }\n\n                return ((Func<object, T>)randomGenerator)(null);\n            }\n\n            throw new ArgumentException(typeof(T).Name);\n        }\n\n        /// <summary>\n        /// Get random symbols.\n        /// </summary>\n        /// <param name=\"symbolSet\">The set of symbols from which the random characters are drawn from.</param>\n        /// <param name=\"count\">The count of random symbols.</param>\n        /// <returns>A random string.</returns>\n        /// <exception cref=\"ArgumentNullException\"/>.\n        /// <exception cref=\"ArgumentOutOfRangeException\"/>.\n        public static string GetRandomCharacters(SymbolSet symbolSet, long count)\n        {\n            if(symbolSet == null)\n            {\n                throw new ArgumentNullException(nameof(symbolSet));\n            }\n\n            if(count < 1)\n            {\n                throw new ArgumentOutOfRangeException(nameof(count), \"The count news to be more than zero.\");\n            }\n\n            object randomGenerator = RandomGenerators[typeof(string)];\n            return ((Func<object, string>)randomGenerator)(Tuple.Create(new Range<long>(count, count), symbolSet));\n        }\n\n        /// <summary>\n        /// Get a random grain ID.\n        /// </summary>\n        /// <typeparam name=\"TGrainKey\">The grain key type.</typeparam>\n        /// <typeparam name=\"TGrainGeneric\">The type of the generic part of a grain.</typeparam>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"symbolSet\">symbolset to use.</param>\n        /// <param name=\"symbolCount\">number of symbols to take from symbol set.</param>\n        /// <returns>Random value of the given type.</returns>\n        /// <exception cref=\"ArgumentException\"/>.\n        internal static GrainId GetRandomGrainId<TGrainKey, TGrainGeneric>(SymbolSet symbolSet, long symbolCount = 15)\n        {\n            if (symbolSet == null)\n            {\n                throw new ArgumentNullException(nameof(symbolSet));\n            }\n\n            if (typeof(TGrainKey) == typeof(string))\n            {\n                var grainId = GetRandomCharacters(symbolSet, symbolCount);\n                return LegacyGrainId.FromParsableString(LegacyGrainId.GetGrainId(NormalGrainTypeCode, grainId).ToParsableString());\n            }\n\n            throw new ArgumentException(typeof(TGrainKey).Name);\n        }\n\n        /// <summary>\n        /// Get a random grain ID.\n        /// </summary>\n        /// <param name=\"keyExtension\">The grain extension key.</param>\n        /// \n        /// <returns>Random value of the given type.</returns>\n        /// <exception cref=\"ArgumentException\"/>.\n        internal static GrainId GetRandomGrainId<T>(bool keyExtension = false)\n        {\n            //If this a string type, some symbol set from which to draw the symbols needs to given\n            //and a special kind of a parameter constructed.\n            const long SymbolsDefaultCount = 15;\n            var symbolSet = new SymbolSet(SymbolSet.Latin1);\n\n            if (typeof(T)== typeof(Guid))\n            {\n                var extension = keyExtension ? GetRandomCharacters(symbolSet, SymbolsDefaultCount) : null;\n                return LegacyGrainId.GetGrainId(UniqueKey.NewKey(Guid.NewGuid(), keyExtension ? UniqueKey.Category.KeyExtGrain : UniqueKey.Category.Grain, keyExtension ? KeyExtensionGrainTypeCode : NormalGrainTypeCode, extension));\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                var extension = keyExtension ? GetRandomCharacters(symbolSet, SymbolsDefaultCount) : null;\n                return LegacyGrainId.GetGrainId(UniqueKey.NewKey(Random.Shared.NextInt64(), keyExtension ? UniqueKey.Category.KeyExtGrain : UniqueKey.Category.Grain, keyExtension ? KeyExtensionGrainTypeCode : NormalGrainTypeCode, extension));\n            }\n\n            if (typeof(T) == typeof(string))\n            {\n                var grainId = GetRandomCharacters(symbolSet, SymbolsDefaultCount);\n                return LegacyGrainId.GetGrainId(NormalGrainTypeCode, grainId);\n            }\n\n            throw new ArgumentException(typeof(T).Name);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/Range.cs",
    "content": "﻿using System.Diagnostics;\n\n\nnamespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Implements the concept of a contiguous range.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the range.</typeparam>\n    /// <remarks>A rudimentary implementation.</remarks>\n    [DebuggerDisplay(\"Start = {Start}, End = {End}\")]\n    public sealed class Range<T>: IEquatable<Range<T>>\n    {\n        /// <summary>\n        /// The start of a contiguous range.\n        /// </summary>\n        public T Start { get; }\n\n        /// <summary>\n        /// The end of a contiguous range.\n        /// </summary>\n        public T End { get; }\n\n        /// <summary>\n        /// Constructor.\n        /// </summary>\n        /// <param name=\"start\">The start of the range.</param>\n        /// <param name=\"end\">The end of the range.</param>\n        /// <param name=\"comparer\">The range comparer.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\"/>.\n        public Range(T start, T end, IComparer<T> comparer = null)\n        {\n            var comp = comparer == null ? Comparer<T>.Default : comparer;\n            if(comp.Compare(end, start) < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(end), end, $\"The relation min ({start}) <= max ({end}) must hold.\");\n            }\n\n            Start = start;\n            End = end;\n        }\n\n\n        public override bool Equals(object obj)\n        {\n            if(!(obj is Range<T>)) return false;\n            Range<T> other = (Range<T>)obj;\n\n            return Equals(other);\n        }\n\n\n        public bool Equals(Range<T> other)\n        {\n            return Start.Equals(other.Start) && End.Equals(other.End);\n        }\n\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                var comparer = EqualityComparer<T>.Default;\n                int hash = 17;\n                hash = hash * 23 + comparer.GetHashCode(Start);\n                hash = hash * 23 + comparer.GetHashCode(End);\n\n                return hash;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/StorageProviders/BaseJSONStorageProvider.cs",
    "content": "//*********************************************************\n//    Copyright (c) Microsoft. All rights reserved.\n//    \n//    Apache 2.0 License\n//    \n//    You may obtain a copy of the License at\n//    http://www.apache.org/licenses/LICENSE-2.0\n//    \n//    Unless required by applicable law or agreed to in writing, software \n//    distributed under the License is distributed on an \"AS IS\" BASIS, \n//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or \n//    implied. See the License for the specific language governing \n//    permissions and limitations under the License.\n//\n//*********************************************************\n\nusing Newtonsoft.Json;\nusing Orleans.Runtime;\nusing Orleans.Storage;\n\nnamespace Samples.StorageProviders\n{\n    /// <summary>\n    /// Base class for JSON-based grain storage providers.\n    /// </summary>\n    public abstract class BaseJSONStorageProvider : IGrainStorage\n    {\n        /// <summary>\n        /// Storage provider name\n        /// </summary>\n        public string Name { get; protected set; }\n\n        /// <summary>\n        /// Data manager instance\n        /// </summary>\n        /// <remarks>The data manager is responsible for reading and writing JSON strings.</remarks>\n        protected IJSONStateDataManager DataManager { get; set; }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        protected BaseJSONStorageProvider()\n        {\n        }\n\n        /// <summary>\n        /// Closes the storage provider during silo shutdown.\n        /// </summary>\n        /// <returns>Completion promise for this operation.</returns>\n        public Task Close()\n        {\n            if (DataManager != null)\n                DataManager.Dispose();\n            DataManager = null;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Reads persisted state from the backing store and deserializes it into the target\n        /// grain state object.\n        /// </summary>\n        /// <param name=\"grainType\">A string holding the name of the grain class.</param>\n        /// <param name=\"grainReference\">Represents the long-lived identity of the grain.</param>\n        /// <param name=\"grainState\">A reference to an object to hold the persisted state of the grain.</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (DataManager == null) throw new ArgumentException(\"DataManager property not initialized\");\n            var entityData = await DataManager.Read(grainState.GetType().Name, grainId.ToString());\n            if (entityData != null)\n            {\n                ConvertFromStorageFormat(grainState, entityData);\n                grainState.RecordExists = true;\n            }\n        }\n\n        /// <summary>\n        /// Writes the persisted state from a grain state object into its backing store.\n        /// </summary>\n        /// <param name=\"grainType\">A string holding the name of the grain class.</param>\n        /// <param name=\"grainReference\">Represents the long-lived identity of the grain.</param>\n        /// <param name=\"grainState\">A reference to an object holding the persisted state of the grain.</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (DataManager == null) throw new ArgumentException(\"DataManager property not initialized\");\n            var entityData = ConvertToStorageFormat(grainState);\n            grainState.RecordExists = true;\n            return DataManager.Write(grainState.GetType().Name, grainId.ToString(), entityData);\n        }\n\n        /// <summary>\n        /// Removes grain state from its backing store, if found.\n        /// </summary>\n        /// <param name=\"grainType\">A string holding the name of the grain class.</param>\n        /// <param name=\"grainReference\">Represents the long-lived identity of the grain.</param>\n        /// <param name=\"grainState\">An object holding the persisted state of the grain.</param>\n        /// <returns></returns>\n        public Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            if (DataManager == null) throw new ArgumentException(\"DataManager property not initialized\");\n            DataManager.Delete(grainState.GetType().Name, grainId.ToString());\n            grainState.RecordExists = false;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Serializes from a grain instance to a JSON document.\n        /// </summary>\n        /// <param name=\"grainState\">Grain state to be converted into JSON storage format.</param>\n        /// <remarks>\n        /// See:\n        /// http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx\n        /// for more on the JSON serializer.\n        /// </remarks>\n        protected static string ConvertToStorageFormat<T>(IGrainState<T> grainState)\n        {\n            return JsonConvert.SerializeObject(grainState.State);\n        }\n\n        /// <summary>\n        /// Constructs a grain state instance by deserializing a JSON document.\n        /// </summary>\n        /// <param name=\"grainState\">Grain state to be populated for storage.</param>\n        /// <param name=\"entityData\">JSON storage format representation of the grain state.</param>\n        protected static void ConvertFromStorageFormat<T>(IGrainState<T> grainState, string entityData)\n        {\n            var data = JsonConvert.DeserializeObject<T>(entityData);\n            grainState.State = data;\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/StorageProviders/FileStorageProvider.cs",
    "content": "//*********************************************************\n//    Copyright (c) Microsoft. All rights reserved.\n//    \n//    Apache 2.0 License\n//    \n//    You may obtain a copy of the License at\n//    http://www.apache.org/licenses/LICENSE-2.0\n//    \n//    Unless required by applicable law or agreed to in writing, software \n//    distributed under the License is distributed on an \"AS IS\" BASIS, \n//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or \n//    implied. See the License for the specific language governing \n//    permissions and limitations under the License.\n//\n//*********************************************************\n\nnamespace Samples.StorageProviders\n{\n    /// <summary>\n    /// Orleans storage provider implementation for file-backed stores.\n    /// </summary>\n    /// <remarks>\n    /// The storage provider should be included in a deployment by adding this line to the Orleans server configuration file:\n    /// \n    ///     <Provider Type=\"Samples.StorageProviders.OrleansFileStorage\" Name=\"FileStore\" RooDirectory=\"SOME FILE PATH\" />\n    ///\n    /// and this line to any grain that uses it:\n    /// \n    ///     [Orleans.Providers.StorageProvider(ProviderName = \"FileStore\")]\n    /// \n    /// The name 'FileStore' is an arbitrary choice.\n    /// \n    /// Note that unless the root directory path is a network path available to all silos in a deployment, grain state\n    /// will not transport from one silo to another.\n    /// </remarks>\n    public class OrleansFileStorage : BaseJSONStorageProvider\n    {\n        public OrleansFileStorage(string rootDirectory)\n        {\n            this.RootDirectory = rootDirectory;\n            if (string.IsNullOrWhiteSpace(RootDirectory)) throw new ArgumentException(\"RootDirectory property not set\");\n            DataManager = new GrainStateFileDataManager(RootDirectory);\n        }\n\n        /// <summary>\n        /// The directory path, relative to the host of the silo. Set from\n        /// configuration data during initialization.\n        /// </summary>\n        public string RootDirectory { get; set; }\n    }\n\n    /// <summary>\n    /// Interfaces with the file system.\n    /// </summary>\n    internal class GrainStateFileDataManager : IJSONStateDataManager \n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"storageDirectory\">A path relative to the silo host process' working directory.</param>\n        public GrainStateFileDataManager(string storageDirectory)\n        {\n            directory = new DirectoryInfo(storageDirectory);\n            if (!directory.Exists)\n                directory.Create();\n        }\n\n        /// <summary>\n        /// Deletes a file representing a grain state object.\n        /// </summary>\n        /// <param name=\"collectionName\">The type of the grain state object.</param>\n        /// <param name=\"key\">The grain id string.</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public Task Delete(string collectionName, string key)\n        {\n            FileInfo fileInfo = GetStorageFilePath(collectionName, key);\n\n            if (fileInfo.Exists)\n                fileInfo.Delete();\n\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Reads a file representing a grain state object.\n        /// </summary>\n        /// <param name=\"collectionName\">The type of the grain state object.</param>\n        /// <param name=\"key\">The grain id string.</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task<string> Read(string collectionName, string key)\n        {\n            FileInfo fileInfo = GetStorageFilePath(collectionName, key);\n\n            if (!fileInfo.Exists)\n                return null;\n\n            using (var stream = fileInfo.OpenText())\n            {\n                return await stream.ReadToEndAsync();\n            }\n        }\n\n        /// <summary>\n        /// Writes a file representing a grain state object.\n        /// </summary>\n        /// <param name=\"collectionName\">The type of the grain state object.</param>\n        /// <param name=\"key\">The grain id string.</param>\n        /// <param name=\"entityData\">The grain state data to be stored./</param>\n        /// <returns>Completion promise for this operation.</returns>\n        public async Task Write(string collectionName, string key, string entityData)\n        {\n            FileInfo fileInfo = GetStorageFilePath(collectionName, key);\n\n            using (var stream = new StreamWriter(fileInfo.Open(FileMode.Create, FileAccess.Write)))\n            {\n                await stream.WriteAsync(entityData);\n            }\n        }\n\n        public void Dispose()\n        {\n        }\n\n        /// <summary>\n        /// Returns the file path for storing that data with these keys.\n        /// </summary>\n        /// <param name=\"collectionName\">The type of the grain state object.</param>\n        /// <param name=\"key\">The grain id string.</param>\n        /// <returns>File info for this storage data file.</returns>\n        private FileInfo GetStorageFilePath(string collectionName, string key)\n        {\n            string fileName = (key + \".\" + collectionName).Replace('/', '_');\n            string path = Path.Combine(directory.FullName, fileName);\n            return new FileInfo(path);\n        }\n\n        private readonly DirectoryInfo directory;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/StorageProviders/IJSONStateDataManager.cs",
    "content": "﻿//*********************************************************\n//    Copyright (c) Microsoft. All rights reserved.\n//    \n//    Apache 2.0 License\n//    \n//    You may obtain a copy of the License at\n//    http://www.apache.org/licenses/LICENSE-2.0\n//    \n//    Unless required by applicable law or agreed to in writing, software \n//    distributed under the License is distributed on an \"AS IS\" BASIS, \n//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or \n//    implied. See the License for the specific language governing \n//    permissions and limitations under the License.\n//\n//*********************************************************\n\nnamespace Samples.StorageProviders\n{\n    /// <summary>\n    /// Defines the interface for the lower level of JSON storage providers, i.e.\n    /// the part that writes JSON strings to the underlying storage. The higher level\n    /// maps between grain state data and JSON.\n    /// </summary>\n    /// <remarks>\n    /// Having this interface allows most of the serialization-level logic\n    /// to be implemented in a base class of the storage providers.\n    /// </remarks>\n    public interface IJSONStateDataManager : IDisposable\n    {\n        /// <summary>\n        /// Deletes the grain state associated with a given key from the collection\n        /// </summary>\n        /// <param name=\"collectionName\">The name of a collection, such as a type name</param>\n        /// <param name=\"key\">The primary key of the object to delete</param>\n        System.Threading.Tasks.Task Delete(string collectionName, string key);\n\n        /// <summary>\n        /// Reads grain state from storage.\n        /// </summary>\n        /// <param name=\"collectionName\">The name of a collection, such as a type name.</param>\n        /// <param name=\"key\">The primary key of the object to read.</param>\n        /// <returns>A string containing a JSON representation of the entity, if it exists; null otherwise.</returns>\n        System.Threading.Tasks.Task<string> Read(string collectionName, string key);\n\n        /// <summary>\n        /// Writes grain state to storage.\n        /// </summary>\n        /// <param name=\"collectionName\">The name of a collection, such as a type name.</param>\n        /// <param name=\"key\">The primary key of the object to write.</param>\n        /// <param name=\"entityData\">A string containing a JSON representation of the entity.</param>\n        System.Threading.Tasks.Task Write(string collectionName, string key, string entityData);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/SymbolSet.cs",
    "content": "namespace UnitTests.StorageTests.Relational\n{\n    /// <summary>\n    /// Embodies a set of character encoding ranges.\n    /// </summary>\n    /// <remarks>Contains some sets of symbols used to create character encodings. See for more at https://en.wikipedia.org/wiki/Character_encoding.</remarks>\n    public class SymbolSet\n    {\n        /// <summary>\n        /// Latin-1 with characters only (no punctuation, numbers etc.).\n        /// </summary>\n        public static IList<Range<int>> Latin1 { get; } = new List<Range<int>>(new[]\n        {\n            new Range<int>(0x0041, 0x005A),\n            new Range<int>(0x0061, 0x007A),\n            new Range<int>(0x00C0, 0x00D6),\n            new Range<int>(0x00D8, 0x00F6),\n            new Range<int>(0x00F8, 0x00FF),\n        });\n\n        /// <summary>\n        /// Cyrillic character set.\n        /// </summary>\n        public static IList<Range<int>> Cyrillic { get; } = new List<Range<int>>(new[] { new Range<int>(0x0400, 0x04FF) });\n\n        /// <summary>\n        /// Hebrew character set.\n        /// </summary>\n        public static IList<Range<int>> Hebrew { get; } = new List<Range<int>>(new[] { new Range<int>(0x05D0, 0x05EA) });\n\n        /// <summary>\n        /// Unicode emoticons.\n        /// </summary>\n        public static IList<Range<int>> Emoticons { get; } = new List<Range<int>>(new[] { new Range<int>(0x1F600, 0x1F64F) });\n\n        /// <summary>\n        /// Dingbats characters.\n        /// </summary>\n        public static IList<Range<int>> Dingbats { get; } = new List<Range<int>>(new[] { new Range<int>(0x2700, 0x27BF) });\n\n        /// <summary>\n        /// The set of symbols as defined by this set.\n        /// </summary>\n        public IList<Range<int>> SetRanges { get; }\n\n        /// <summary>\n        /// A constructor.\n        /// </summary>\n        /// <param name=\"setRanges\">A set of symbol ranges to collect the symbols in this collection.</param>\n        public SymbolSet(IEnumerable<Range<int>> setRanges)\n        {\n            if(setRanges == null)\n            {\n                throw new ArgumentNullException(nameof(setRanges));\n            }\n\n            SetRanges = new List<Range<int>>(setRanges);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/GrainTypeGenerator.cs",
    "content": "namespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    public static class GrainTypeGenerator\n    {\n        /// <summary>\n        /// A sentinel value for when a generic parameter isn't used and applied to some function call.\n        /// </summary>\n        private class NotApplicable { };\n\n        public interface ITestGrainWithIntegerKey: IGrainWithIntegerKey { }\n\n        public interface ITestGrainGenericWithIntegerKey<T>: IGrainWithIntegerKey { }\n\n        public class TestGrainWithIntegerKey: Grain, ITestGrainWithIntegerKey { }\n\n        public class TestGrainGenericWithIntegerKey<T>: Grain, ITestGrainGenericWithIntegerKey<T> { }\n\n        public interface ITestGrainWithGuidKey: IGrainWithGuidKey { }\n\n        public interface ITestGrainGenericWithGuidKey<T>: IGrainWithGuidKey { }\n\n        public class TestGrainWithGuidKey: Grain, ITestGrainWithGuidKey { }\n\n        public class TestGrainGenericWithGuidKey<T>: Grain, ITestGrainGenericWithGuidKey<T> { }\n\n        public interface ITestGrainWithStringKey: IGrainWithStringKey { }\n\n        public interface ITestGrainGenericWithStringKey<T>: IGrainWithStringKey { }\n\n        public class TestGrainWithStringKey: Grain, ITestGrainWithStringKey { }\n\n        public class TestGrainGenericWithStringKey<T>: Grain, ITestGrainGenericWithStringKey<T> { }\n\n        private static Dictionary<Type, Func<Type, Type, Type>> GrainTypeSwitch { get; } = new Dictionary<Type, Func<Type, Type, Type>>\n        {\n            [typeof(Guid)] = (grainType, stateType) =>\n            {\n                if(grainType == typeof(NotApplicable))\n                {\n                    return typeof(TestGrainWithGuidKey);\n                }\n                return typeof(TestGrainGenericWithGuidKey<double>);\n            },\n            [typeof(long)] = (grainType, stateType) =>\n            {\n                if(grainType == typeof(NotApplicable))\n                {\n                    return typeof(TestGrainWithIntegerKey);\n                }\n                return typeof(TestGrainGenericWithIntegerKey<double>);\n            },\n            [typeof(string)] = (grainType, stateType) =>\n            {\n                if(grainType == typeof(NotApplicable))\n                {\n                    return typeof(TestGrainWithStringKey);\n                }\n                return typeof(TestGrainGenericWithStringKey<double>);\n            }\n        };\n\n\n        public static string GetGrainType<TGrainKey>()\n        {\n            return GetGrainType<TGrainKey, NotApplicable>();\n        }\n\n// Orleans.Storage.AdoNetStorageProvider cannot be resolved, because the containing assembly is not referenced since not needed.\n#pragma warning disable 1574\n        /// <summary>\n        /// Returns a grain type name.\n        /// </summary>\n        /// <typeparam name=\"TGrainKey\">Used to choose the key type interface.</typeparam>\n        /// <typeparam name=\"TGrain\">Used to choose the type of grain.</typeparam>\n        /// <returns>The class in typeof(T).AssemblyQualifiedName form.</returns>\n        /// <remarks> ASSUMES Orleans give <em>grainType</em> parameters in this form to <see cref=\"Orleans.Storage.IStorageProvider\"/> interface implementing functions.\n        /// In <see cref=\"Orleans.Storage.AdoNetStorageProvider\"/> private function <em>ExtractClassBaseType</em> relies this is in this form. Should be fixed\n        /// if/when this is changed in Orleans.\n        /// </remarks>\n#pragma warning restore 1574\n        public static string GetGrainType<TGrainKey, TGrain>()\n        {\n            Func<Type, Type, Type> func;\n            if(GrainTypeSwitch.TryGetValue(typeof(TGrainKey), out func))\n            {\n                return (func(typeof(TGrainKey), typeof(TGrain))).AssemblyQualifiedName;\n            }\n\n            throw new ArgumentException(typeof(TGrainKey).Name);\n\n        }\n    }\n}\n\n#pragma warning restore ORLEANS0102\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/StorageDataSet2CyrillicIdsAndGrainNames.cs",
    "content": "using System.Collections;\nusing Orleans.Runtime;\n\nnamespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    /// <summary>\n    /// A data set for grains with Cyrillic letters and IDs.\n    /// </summary>\n    /// <typeparam name=\"TStateData\">The type of <see cref=\"TestStateGeneric1{T}\"/>.</typeparam>\n    internal class StorageDataSet2CyrillicIdsAndGrainNames<TStateData>: IEnumerable<object[]>\n    {\n        private const int NumCases = 3;\n\n        /// <summary>\n        /// The symbol set this data set uses.\n        /// </summary>\n        private static SymbolSet Symbols { get; } = new SymbolSet(SymbolSet.Cyrillic);\n\n        /// <summary>\n        /// The length of random string drawn form <see cref=\"Symbols\"/>.\n        /// </summary>\n        private const long StringLength = 15L;\n        \n        public static (string, GrainId, GrainState<TestStateGeneric1<TStateData>>) GetTestData(int testNum) => testNum switch\n        {\n            0 => (\n                GrainTypeGenerator.GetGrainType<string>(),\n                RandomUtilities.GetRandomGrainId<string, int>(Symbols, StringLength),\n                new GrainState<TestStateGeneric1<TStateData>>\n                {\n                    State = new TestStateGeneric1<TStateData>\n                    {\n                        SomeData = RandomUtilities.GetRandom<TStateData>(),\n                        A = \"Data1\",\n                        B = 1,\n                        C = 4\n                    }\n                }),\n            1 => (\n                GrainTypeGenerator.GetGrainType<string>(),\n                RandomUtilities.GetRandomGrainId<string, int>(Symbols, StringLength),\n                new GrainState<TestStateGeneric1<TStateData>>\n                {\n                    State = new TestStateGeneric1<TStateData>\n                    {\n                        SomeData = RandomUtilities.GetRandom<TStateData>(),\n                        A = \"Data2\",\n                        B = 2,\n                        C = 5\n                    }\n                }),\n            2 => (\n                GrainTypeGenerator.GetGrainType<string>(),\n                RandomUtilities.GetRandomGrainId<string, int>(Symbols, StringLength),\n                new GrainState<TestStateGeneric1<TStateData>>\n                {\n                    State = new TestStateGeneric1<TStateData>\n                    {\n                        SomeData = RandomUtilities.GetRandom<TStateData>(),\n                        A = \"Data3\",\n                        B = 3,\n                        C = 6\n                    }\n                }),\n            _ => throw new IndexOutOfRangeException()\n        };\n\n        public IEnumerator<object[]> GetEnumerator() => Enumerable.Range(0, NumCases).Select(n => new object[] { n }).GetEnumerator();\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/StorageDataSetGeneric.cs",
    "content": "using System.Collections;\nusing Orleans.Runtime;\n\nnamespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    internal sealed class StorageDataSetGeneric<TGrainKey, TStateData> : IEnumerable<object[]>\n    {\n        private const int NumCases = 3;\n\n        public static (string, GrainId, GrainState<TestStateGeneric1<TStateData>>) GetTestData(int testNum) => testNum switch\n        {\n            0 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(), A = \"Data1\", B = 1, C = 4 } }),\n            1 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(), A = \"Data2\", B = 2, C = 5 } }),\n            2 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(), A = \"Data3\", B = 3, C = 6 } }),\n            _ => throw new IndexOutOfRangeException()\n        };\n\n        public IEnumerator<object[]> GetEnumerator() => Enumerable.Range(0, NumCases).Select(n => new object[] { n }).GetEnumerator();\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/StorageDataSetPlain.cs",
    "content": "using System.Collections;\nusing Orleans.Runtime;\n\nnamespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    /// <summary>\n    /// A set of simple test data set wit and without extension keys.\n    /// </summary>\n    /// <typeparam name=\"TGrainKey\">The grain type (integer, guid or string)</typeparam>.\n    internal sealed class StorageDataSetPlain<TGrainKey>: IEnumerable<object[]>\n    {\n        private const int NumCases = 3;\n\n        /// <summary>\n        /// The symbol set this data set uses.\n        /// </summary>\n        private static SymbolSet Symbols { get; } = new SymbolSet(SymbolSet.Latin1);\n\n        /// <summary>\n        /// The length of random string drawn form <see cref=\"Symbols\"/>.\n        /// </summary>\n        private const long StringLength = 15L;\n\n        public static (string, GrainId, GrainState<TestState1>) GetTestData(int testNum) => testNum switch\n        {\n            0 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestState1> { State = new TestState1 { A = RandomUtilities.GetRandomCharacters(Symbols, StringLength), B = 1, C = 4 } }),\n            1 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(true),\n                new GrainState<TestState1> { State = new TestState1 { A = RandomUtilities.GetRandomCharacters(Symbols, StringLength), B = 2, C = 5 } }),\n            2 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(true),\n                new GrainState<TestState1> { State = new TestState1 { A = RandomUtilities.GetRandomCharacters(Symbols, StringLength), B = 3, C = 6 } }),\n            _ => throw new IndexOutOfRangeException(),\n\n        };\n\n        public IEnumerator<object[]> GetEnumerator() => Enumerable.Range(0, NumCases).Select(n => new object[] { n }).GetEnumerator();\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/StorageDateSetGenericHuge.cs",
    "content": "using Orleans.Runtime;\nusing System.Collections;\n\nnamespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    internal sealed class StorageDataSetGenericHuge<TGrainKey, TStateData> : IEnumerable<object[]>\n    {\n        private const int NumCases = 3;\n        private static Range<long> CountOfCharacters { get; } = new Range<long>(1000000, 1000000);\n\n        public static (string, GrainId, GrainState<TestStateGeneric1<TStateData>>) GetTestData(int testNum) => testNum switch\n        {\n            0 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(CountOfCharacters), A = \"Data1\", B = 1, C = 4 } }),\n            1 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(CountOfCharacters), A = \"Data2\", B = 2, C = 5 } }),\n            2 => (\n                GrainTypeGenerator.GetGrainType<TGrainKey>(),\n                RandomUtilities.GetRandomGrainId<TGrainKey>(),\n                new GrainState<TestStateGeneric1<TStateData>> { State = new TestStateGeneric1<TStateData> { SomeData = RandomUtilities.GetRandom<TStateData>(CountOfCharacters), A = \"Data3\", B = 3, C = 6 } }),\n            _ => throw new IndexOutOfRangeException(),\n        };\n\n        public IEnumerator<object[]> GetEnumerator() => Enumerable.Range(0, NumCases).Select(n => new object[] { n }).GetEnumerator();\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/TestState1.cs",
    "content": "﻿namespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    /// <summary>\n    /// A state used to test if saving, reading and clearing of the storage functions as expected.\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class TestState1: IEquatable<TestState1>\n    {\n        [Orleans.Id(0)]\n        public string A { get; set; }\n\n        [Orleans.Id(1)]\n        public int B { get; set; }\n\n        [Orleans.Id(2)]\n        public long C { get; set; }\n\n        public override bool Equals(object obj)\n        {\n            return Equals(obj as TestState1);\n        }\n\n\n        public bool Equals(TestState1 other)\n        {\n            if(ReferenceEquals(other, null))\n            {\n                return false;\n            }\n\n            return EqualityComparer<string>.Default.Equals(A, other.A) && B.Equals(other.B) && C.Equals(other.C);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                int hash = 17;\n                hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(A);\n                hash = hash * 23 + B.GetHashCode();\n                hash = hash * 23 + C.GetHashCode();\n\n                return hash;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/StorageTests/TestDataSets/TestStateGeneric1.cs",
    "content": "﻿namespace UnitTests.StorageTests.Relational.TestDataSets\n{\n    /// <summary>\n    /// A generic state used to test if saving, reading and clearing of the storage functions as expected.\n    /// </summary>\n    [Serializable]\n    [Orleans.GenerateSerializer]\n    public class TestStateGeneric1<T>: IEquatable<TestStateGeneric1<T>>\n    {\n        [Orleans.Id(0)]\n        public T SomeData { get; set; }\n\n        [Orleans.Id(1)]\n        public string A { get; set; }\n\n        [Orleans.Id(2)]\n        public int B { get; set; }\n\n        [Orleans.Id(3)]\n        public long C { get; set; }\n\n\n        public override bool Equals(object obj)\n        {\n            return Equals(obj as TestStateGeneric1<T>);\n        }\n\n\n        public bool Equals(TestStateGeneric1<T> other)\n        {\n            if(ReferenceEquals(other, null))\n            {\n                return false;\n            }\n\n            return EqualityComparer<T>.Default.Equals(SomeData, other.SomeData)\n                && EqualityComparer<string>.Default.Equals(A, other.A)\n                && B.Equals(other.B)\n                && C.Equals(other.C);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                int hash = 17;\n                hash = hash * 23 + EqualityComparer<T>.Default.GetHashCode(SomeData);\n                hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(A);\n                hash = hash * 23 + B.GetHashCode();\n                hash = hash * 23 + C.GetHashCode();\n\n                return hash;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TestRunners/GrainPersistenceTestRunner.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing Tester;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace TestExtensions.Runners;\n\npublic abstract class GrainPersistenceTestsRunner : OrleansTestingBase\n{\n    private readonly ITestOutputHelper output;\n    private readonly string grainNamespace;\n    private readonly BaseTestClusterFixture fixture;\n    protected readonly ILogger logger;\n    protected TestCluster HostedCluster { get; private set; }\n    private static readonly double timingFactor = TestUtils.CalibrateTimings();\n    private const int LoopIterations_Grain = 1000;\n    private const int BatchSize = 100;\n    private const int MaxReadTime = 200;\n    private const int MaxWriteTime = 2000;\n\n    protected GrainPersistenceTestsRunner(ITestOutputHelper output, BaseTestClusterFixture fixture, string grainNamespace = \"UnitTests.Grains\")\n    {\n        this.output = output;\n        this.fixture = fixture;\n        this.grainNamespace = grainNamespace;\n        logger = fixture.Logger;\n        HostedCluster = fixture.HostedCluster;\n    }\n\n    protected bool DeleteStateOnClear { get; init; }\n    protected bool IsDurableStorage { get; init; } = true;\n    protected bool DistinguishesGenericGrainTypeParameters { get; init; } = true;\n\n    protected TimeSpan PerformanceTestTimeout { get; init; } = TimeSpan.FromSeconds(90);\n\n    public IGrainFactory GrainFactory => fixture.GrainFactory;\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task ClearStateAsync_Before_WriteStateAsync()\n    {\n        var grain = GrainFactory.GetGrain<IGrainStorageTestGrain>(Guid.NewGuid(), grainNamespace);\n\n        await grain.DoDelete();\n\n        var state = await grain.GetStateAsync();\n        Assert.False(state.RecordExists);\n        Assert.NotNull(state.State);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_GrainStorage_Delete()\n    {\n        var grain = GrainFactory.GetGrain<IGrainStorageTestGrain>(Guid.NewGuid(), grainNamespace);\n\n        await grain.DoWrite(1);\n        var state = await grain.GetStateAsync();\n        Assert.True(state.RecordExists);\n        Assert.NotNull(state.ETag);\n        Assert.NotNull(state.State);\n\n        await grain.DoDelete();\n\n        state = await grain.GetStateAsync();\n        Assert.False(state.RecordExists);\n        if (DeleteStateOnClear)\n        {\n            Assert.Null(state.ETag);\n        }\n\n        Assert.NotNull(state.State);\n\n        var val = await grain.GetValue(); // Should this throw instead?\n        Assert.Equal(0, val);  // \"Value after Delete\"\n\n        await grain.DoWrite(2);\n\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Delete + New Write\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_GrainStorage_Read()\n    {\n        var id = Guid.NewGuid();\n        var grain = GrainFactory.GetGrain<IGrainStorageTestGrain>(id, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        var state = await grain.GetStateAsync();\n        Assert.False(state.RecordExists);\n        Assert.NotNull(state.State);\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_GuidKey_GrainStorage_Read_Write()\n    {\n        var id = Guid.NewGuid();\n        var grain = GrainFactory.GetGrain<IGrainStorageTestGrain>(id, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain.DoWrite(1);\n        val = await grain.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(2);\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_LongKey_GrainStorage_Read_Write()\n    {\n        long id = Random.Shared.Next();\n        var grain = GrainFactory.GetGrain<IGrainStorageTestGrain_LongKey>(id, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain.DoWrite(1);\n        val = await grain.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(2);\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_LongKeyExtended_GrainStorage_Read_Write()\n    {\n        long id = Random.Shared.Next();\n        var extKey = Random.Shared.Next().ToString(CultureInfo.InvariantCulture);\n\n        var\n            grain = GrainFactory.GetGrain<IGrainStorageTestGrain_LongExtendedKey>(id, extKey, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain.DoWrite(1);\n        val = await grain.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(2);\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n        Assert.Equal(2, val);  // \"Value after DoRead\"\n\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n\n        var extKeyValue = await grain.GetExtendedKeyValue();\n        Assert.Equal(extKey, extKeyValue);  // \"Extended Key\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_GuidKeyExtended_GrainStorage_Read_Write()\n    {\n        var id = Guid.NewGuid();\n        var extKey = Random.Shared.Next().ToString(CultureInfo.InvariantCulture);\n\n        var\n            grain = GrainFactory.GetGrain<IGrainStorageTestGrain_GuidExtendedKey>(id, extKey, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain.DoWrite(1);\n        val = await grain.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(2);\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n        Assert.Equal(2, val);  // \"Value after DoRead\"\n\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n\n        var extKeyValue = await grain.GetExtendedKeyValue();\n        Assert.Equal(extKey, extKeyValue);  // \"Extended Key\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_Generic_GrainStorage_Read_Write()\n    {\n        long id = Random.Shared.Next();\n\n        var grain = GrainFactory.GetGrain<IGrainStorageGenericGrain<int>>(id, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain.DoWrite(1);\n        val = await grain.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(2);\n        val = await grain.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_NestedGeneric_GrainStorage_Read_Write()\n    {\n        long id = Random.Shared.Next();\n\n        var grain = GrainFactory.GetGrain<IGrainStorageGenericGrain<List<int>>>(id, grainNamespace);\n\n        var val = await grain.GetValue();\n\n        Assert.Null(val);  // \"Initial value\"\n\n        await grain.DoWrite(new List<int> { 1 });\n        val = await grain.GetValue();\n        Assert.Equal(new List<int> { 1 }, val);  // \"Value after Write-1\"\n\n        await grain.DoWrite(new List<int> { 1, 2 });\n        val = await grain.GetValue();\n        Assert.Equal(new List<int> { 1, 2 }, val);  // \"Value after Write-2\"\n\n        val = await grain.DoRead();\n\n        Assert.Equal(new List<int> { 1, 2 }, val);  // \"Value after Re-Read\"\n    }\n\n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_Generic_GrainStorage_DiffTypes()\n    {\n        if (!DistinguishesGenericGrainTypeParameters)\n        {\n            throw new SkipException(\"This provider does not support distinguishing grains in storage by their generic type parameters.\");\n        }\n\n        long id1 = Random.Shared.Next();\n        var id2 = id1;\n        var id3 = id1;\n\n        var grain1 = GrainFactory.GetGrain<IGrainStorageGenericGrain<int>>(id1, grainNamespace);\n\n        var grain2 = GrainFactory.GetGrain<IGrainStorageGenericGrain<string>>(id2, grainNamespace);\n\n        var grain3 = GrainFactory.GetGrain<IGrainStorageGenericGrain<double>>(id3, grainNamespace);\n\n        var val1 = await grain1.GetValue();\n        Assert.Equal(0, val1);  // \"Initial value - 1\"\n\n        var val2 = await grain2.GetValue();\n        Assert.Null(val2);  // \"Initial value - 2\"\n\n        var val3 = await grain3.GetValue();\n        Assert.Equal(0.0, val3);  // \"Initial value - 3\"\n\n        var expected1 = 1;\n        await grain1.DoWrite(expected1);\n        val1 = await grain1.GetValue();\n        Assert.Equal(expected1, val1);  // \"Value after Write#1 - 1\"\n\n        var expected2 = \"Three\";\n        await grain2.DoWrite(expected2);\n        val2 = await grain2.GetValue();\n        Assert.Equal(expected2, val2);  // \"Value after Write#1 - 2\"\n\n        var expected3 = 5.1;\n        await grain3.DoWrite(expected3);\n        val3 = await grain3.GetValue();\n        Assert.Equal(expected3, val3);  // \"Value after Write#1 - 3\"\n\n        val1 = await grain1.GetValue();\n        Assert.Equal(expected1, val1);  // \"Value before Write#2 - 1\"\n        expected1 = 2;\n        await grain1.DoWrite(expected1);\n        val1 = await grain1.GetValue();\n        Assert.Equal(expected1, val1);  // \"Value after Write#2 - 1\"\n        val1 = await grain1.DoRead();\n        Assert.Equal(expected1, val1);  // \"Value after Re-Read - 1\"\n\n        val2 = await grain2.GetValue();\n        Assert.Equal(expected2, val2);  // \"Value before Write#2 - 2\"\n        expected2 = \"Four\";\n        await grain2.DoWrite(expected2);\n        val2 = await grain2.GetValue();\n        Assert.Equal(expected2, val2);  // \"Value after Write#2 - 2\"\n        val2 = await grain2.DoRead();\n        Assert.Equal(expected2, val2);  // \"Value after Re-Read - 2\"\n\n        val3 = await grain3.GetValue();\n        Assert.Equal(expected3, val3);  // \"Value before Write#2 - 3\"\n        expected3 = 6.2;\n        await grain3.DoWrite(expected3);\n        val3 = await grain3.GetValue();\n        Assert.Equal(expected3, val3);  // \"Value after Write#2 - 3\"\n        val3 = await grain3.DoRead();\n        Assert.Equal(expected3, val3);  // \"Value after Re-Read - 3\"\n    }\n    \n    [SkippableFact, TestCategory(\"Functional\")]\n    public async Task Grain_GrainStorage_SiloRestart()\n    {\n        if (!IsDurableStorage) \n        {\n            throw new SkipException(\"This provider does not persist state, so cannot survive a silo restart.\");\n        }\n\n        var initialServiceId = fixture.GetClientServiceId();\n\n        output.WriteLine(\"ClusterId={0} ServiceId={1}\", HostedCluster.Options.ClusterId, initialServiceId);\n\n        var id1 = Guid.NewGuid();\n        var grain1 = GrainFactory.GetGrain<IGrainStorageTestGrain>(id1, grainNamespace);\n        var id2 = Guid.NewGuid();\n        var grain2 = GrainFactory.GetGrain<IGrainStorageTestGrain>(id2, grainNamespace);\n\n        var val = await grain1.GetValue();\n        Assert.Equal(0, val);  // \"Initial value\"\n\n        await grain1.DoWrite(1);\n\n        await grain2.DoWrite(1);\n\n        val = await grain1.GetValue();\n        Assert.Equal(1, val);\n        val = await grain2.GetValue();\n        Assert.Equal(1, val);\n\n        await grain2.DoDelete();\n\n        var serviceId = await GrainFactory.GetGrain<IServiceIdGrain>(Guid.Empty).GetServiceId();\n        Assert.Equal(initialServiceId, serviceId);  // \"ServiceId same before restart.\"\n\n        output.WriteLine(\"About to reset Silos\");\n        foreach (var silo in HostedCluster.GetActiveSilos().ToList())\n        {\n            await HostedCluster.RestartSiloAsync(silo);\n        }\n\n        await HostedCluster.InitializeClientAsync();\n\n        output.WriteLine(\"Silos restarted\");\n\n        serviceId = await GrainFactory.GetGrain<IServiceIdGrain>(Guid.Empty).GetServiceId();\n        grain1 = GrainFactory.GetGrain<IGrainStorageTestGrain>(id1, grainNamespace);\n        grain2 = GrainFactory.GetGrain<IGrainStorageTestGrain>(id2, grainNamespace);\n        output.WriteLine(\"ClusterId={0} ServiceId={1}\", HostedCluster.Options.ClusterId, serviceId);\n        Assert.Equal(initialServiceId, serviceId);  // \"ServiceId same after restart.\"\n\n        val = await grain1.GetValue();\n        Assert.Equal(1, val);  // \"Value after Write-1\"\n\n        val = await grain2.GetValue();\n        Assert.Equal(0, val);  // State should be cleared.\n\n        await grain1.DoWrite(2);\n        val = await grain1.GetValue();\n        Assert.Equal(2, val);  // \"Value after Write-2\"\n\n        val = await grain1.DoRead();\n\n        Assert.Equal(2, val);  // \"Value after Re-Read\"\n    }\n\n    [SkippableFact, TestCategory(\"CorePerf\"), TestCategory(\"Performance\"), TestCategory(\"Stress\")]\n    public async Task Persistence_Perf_Activate()\n    {\n        const string testName = \"Persistence_Perf_Activate\";\n        int n = LoopIterations_Grain;\n        TimeSpan target = TimeSpan.FromMilliseconds(MaxReadTime * n);\n\n        // Timings for Activate\n        await RunPerfTest(n, testName, target,\n            grainNoState => grainNoState.PingAsync(),\n            grainMemory => grainMemory.DoSomething(),\n            grainMemoryStore => grainMemoryStore.GetValue(),\n            grainAzureStore => grainAzureStore.GetValue());\n    }\n\n    [SkippableFact, TestCategory(\"CorePerf\"), TestCategory(\"Performance\"), TestCategory(\"Stress\")]\n    public async Task Persistence_Perf_Write()\n    {\n        const string testName = \"Persistence_Perf_Write\";\n        int n = LoopIterations_Grain;\n        TimeSpan target = TimeSpan.FromMilliseconds(MaxWriteTime * n);\n\n        // Timings for Write\n        await RunPerfTest(n, testName, target,\n            grainNoState => grainNoState.EchoAsync(testName),\n            grainMemory => grainMemory.DoWrite(n),\n            grainMemoryStore => grainMemoryStore.DoWrite(n),\n            grainAzureStore => grainAzureStore.DoWrite(n));\n    }\n\n    [SkippableFact, TestCategory(\"CorePerf\"), TestCategory(\"Performance\"), TestCategory(\"Stress\")]\n    public async Task Persistence_Perf_Write_Reread()\n    {\n        const string testName = \"Persistence_Perf_Write_Read\";\n        int n = LoopIterations_Grain;\n        TimeSpan target = TimeSpan.FromMilliseconds(MaxWriteTime * n);\n\n        // Timings for Write\n        await RunPerfTest(n, testName + \"--Write\", target,\n            grainNoState => grainNoState.EchoAsync(testName),\n            grainMemory => grainMemory.DoWrite(n),\n            grainMemoryStore => grainMemoryStore.DoWrite(n),\n            grainAzureStore => grainAzureStore.DoWrite(n));\n\n        // Timings for Activate\n        await RunPerfTest(n, testName + \"--ReRead\", target,\n            grainNoState => grainNoState.GetLastEchoAsync(),\n            grainMemory => grainMemory.DoRead(),\n            grainMemoryStore => grainMemoryStore.DoRead(),\n            grainAzureStore => grainAzureStore.DoRead());\n    }\n\n    protected async Task Persistence_Silo_StorageProvider(string providerName)\n    {\n        List<SiloHandle> silos = this.HostedCluster.GetActiveSilos().ToList();\n        foreach (var silo in silos)\n        {\n            var isPresent = await this.HostedCluster.Client.GetTestHooks(silo).HasStorageProvider(providerName);\n            Assert.True(isPresent, $\"No storage provider found: {providerName}\");\n        }\n    }\n\n    // ---------- Utility functions ----------\n\n    private async Task RunPerfTest(int n, string testName, TimeSpan target,\n        Func<IEchoTaskGrain, Task> actionNoState,\n        Func<IPersistenceTestGrain, Task> actionMemory,\n        Func<IMemoryStorageTestGrain, Task> actionMemoryStore,\n        Func<IGrainStorageTestGrain, Task> actionAzureTable)\n    {\n        IEchoTaskGrain[] noStateGrains = new IEchoTaskGrain[n];\n        IPersistenceTestGrain[] memoryGrains = new IPersistenceTestGrain[n];\n        IGrainStorageTestGrain[] azureStoreGrains = new IGrainStorageTestGrain[n];\n        IMemoryStorageTestGrain[] memoryStoreGrains = new IMemoryStorageTestGrain[n];\n\n        for (int i = 0; i < n; i++)\n        {\n            Guid id = Guid.NewGuid();\n            noStateGrains[i] = this.GrainFactory.GetGrain<IEchoTaskGrain>(id);\n            memoryGrains[i] = this.GrainFactory.GetGrain<IPersistenceTestGrain>(id);\n            azureStoreGrains[i] = this.GrainFactory.GetGrain<IGrainStorageTestGrain>(id);\n            memoryStoreGrains[i] = this.GrainFactory.GetGrain<IMemoryStorageTestGrain>(id);\n        }\n\n        TimeSpan baseline, elapsed;\n\n        elapsed = baseline = await TestUtils.TimeRunAsync(n, TimeSpan.Zero, testName + \" (No state)\",\n            () => RunIterations(testName, n, i => actionNoState(noStateGrains[i])));\n\n        elapsed = await TestUtils.TimeRunAsync(n, baseline, testName + \" (Local Memory Store)\",\n            () => RunIterations(testName, n, i => actionMemory(memoryGrains[i])));\n\n        elapsed = await TestUtils.TimeRunAsync(n, baseline, testName + \" (Dev Store Grain Store)\",\n            () => RunIterations(testName, n, i => actionMemoryStore(memoryStoreGrains[i])));\n\n        elapsed = await TestUtils.TimeRunAsync(n, baseline, testName + \" (Azure Table Store)\",\n            () => RunIterations(testName, n, i => actionAzureTable(azureStoreGrains[i])));\n\n        if (elapsed > target.Multiply(timingFactor))\n        {\n            string msg = string.Format(\"{0}: Elapsed time {1} exceeds target time {2}\", testName, elapsed, target);\n\n            if (elapsed > target.Multiply(2.0 * timingFactor))\n            {\n                Assert.Fail(msg);\n            }\n            else\n            {\n                throw new SkipException(msg);\n            }\n        }\n    }\n\n    private async Task RunIterations(string testName, int n, Func<int, Task> action)\n    {\n        List<Task> promises = new List<Task>();\n        Stopwatch sw = Stopwatch.StartNew();\n        // Fire off requests in batches\n        for (int i = 0; i < n; i++)\n        {\n            var promise = action(i);\n            promises.Add(promise);\n            if ((i % BatchSize) == 0 && i > 0)\n            {\n                await Task.WhenAll([.. promises]).WaitAsync(PerformanceTestTimeout);\n                promises.Clear();\n                //output.WriteLine(\"{0} has done {1} iterations  in {2} at {3} RPS\",\n                //                  testName, i, sw.Elapsed, i / sw.Elapsed.TotalSeconds);\n            }\n        }\n\n        await Task.WhenAll([.. promises]).WaitAsync(PerformanceTestTimeout);\n        sw.Stop();\n        output.WriteLine(\"{0} completed. Did {1} iterations in {2} at {3} RPS\",\n                          testName, n, sw.Elapsed, n / sw.Elapsed.TotalSeconds);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TestStoreGrainState.cs",
    "content": "using System.Globalization;\n\nnamespace UnitTests.Persistence\n{\n    [Serializable]\n    [GenerateSerializer]\n    public class TestStoreGrainState\n    {\n        [Id(0)]\n        public string A { get; set; }\n        [Id(1)]\n        public int B { get; set; }\n        [Id(2)]\n        public long C { get; set; }\n\n        internal static GrainState<TestStoreGrainState> NewRandomState(int? aPropertyLength = null)\n        {\n            return new GrainState<TestStoreGrainState>\n            {\n                State = new TestStoreGrainState\n                {\n                    A = aPropertyLength == null\n                        ? Random.Shared.Next().ToString(CultureInfo.InvariantCulture)\n                        : GenerateRandomDigitString(aPropertyLength.Value),\n                    B = Random.Shared.Next(),\n                    C = Random.Shared.Next()\n                }\n            };\n        }\n\n        private static string GenerateRandomDigitString(int stringLength)\n        {\n            var characters = new char[stringLength];\n            for (var i = 0; i < stringLength; ++i)\n            {\n                characters[i] = (char)Random.Shared.Next('0', '9' + 1);\n            }\n            return new string(characters);\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TestUtils.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.TestingHost;\n\nnamespace UnitTests.TestHelper\n{\n    public static class TestUtils\n    {\n        /// <summary>Gets a detailed grain report from a specified silo</summary>\n        /// <param name=\"grainFactory\">The grain factory.</param>\n        /// <param name=\"grainId\">The grain id we are requesting information from</param>\n        /// <param name=\"siloHandle\">The target silo that should provide this information from it's cache</param>\n        internal static Task<DetailedGrainReport> GetDetailedGrainReport(IInternalGrainFactory grainFactory, GrainId grainId, SiloHandle siloHandle)\n        {\n            // Use the siloAddress here, not the gateway address, since we may be targeting a silo on which we are not \n            // connected to the gateway\n            var siloControl = grainFactory.GetSystemTarget<ISiloControl>(Constants.SiloControlType, siloHandle.SiloAddress);\n            return siloControl.GetDetailedGrainReport(grainId);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TimeoutTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Metadata;\nusing Orleans.Runtime;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans timeout mechanisms and request cancellation.\n    /// \n    /// Orleans implements timeouts to prevent indefinite waiting on grain calls:\n    /// - Each grain call has a configurable response timeout\n    /// - If a grain method doesn't complete within the timeout, a TimeoutException is thrown\n    /// - The original request continues executing on the silo (not cancelled)\n    /// - Subsequent calls to a busy grain may be dropped to prevent queue buildup\n    /// \n    /// These tests verify:\n    /// - Timeout exceptions are thrown at the appropriate time\n    /// - Request tracking is properly cleaned up after timeouts\n    /// - Call dropping behavior for overloaded grains\n    /// \n    /// Note: These tests modify global timeout settings, so they should run in isolation.\n    /// </summary>\n    public class TimeoutTests : HostedTestClusterEnsureDefaultStarted, IDisposable\n    {\n        private readonly ITestOutputHelper output;\n        private readonly TimeSpan originalTimeout;\n        private readonly IRuntimeClient runtimeClient;\n        private readonly GrainInterfaceTypeResolver typeResolver;\n\n        public TimeoutTests(ITestOutputHelper output, DefaultClusterFixture fixture) : base(fixture)\n        {\n            this.output = output;\n            this.runtimeClient = this.HostedCluster.ServiceProvider.GetRequiredService<IRuntimeClient>();\n            // Save original timeout to restore it after tests\n            originalTimeout = this.runtimeClient.GetResponseTimeout();\n            this.typeResolver = this.HostedCluster.ServiceProvider.GetRequiredService<GrainInterfaceTypeResolver>();\n        }\n\n        public virtual void Dispose()\n        {\n            // Restore original timeout to avoid affecting other tests\n            this.runtimeClient.SetResponseTimeout(originalTimeout);\n        }\n\n        /// <summary>\n        /// Tests that grain calls timeout correctly when the method takes longer than the response timeout.\n        /// Verifies:\n        /// - TimeoutException is thrown after the configured timeout period\n        /// - The timeout occurs within expected bounds (not too early, not too late)\n        /// - Request tracking is cleaned up (no lingering requests)\n        /// - Re-awaiting the same task fails immediately\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Timeout\")]\n        public async Task Timeout_LongMethod()\n        {\n            bool finished = false;\n            var grainName = typeof (ErrorGrain).FullName;\n            IErrorGrain grain = this.GrainFactory.GetGrain<IErrorGrain>(GetRandomGrainId(), grainName);\n            var errorGrainType = this.typeResolver.GetGrainInterfaceType(typeof(IErrorGrain));\n            // Set a 1-second timeout for this test\n            TimeSpan timeout = TimeSpan.FromMilliseconds(1000);\n            this.runtimeClient.SetResponseTimeout(timeout);\n\n            // Call a method that takes 4x longer than the timeout\n            Task promise = grain.LongMethod((int)timeout.Multiply(4).TotalMilliseconds);\n            //promise = grain.LongMethodWithError(2000);\n\n            // Note: There's a potential race condition in debugger where the call might complete\n            // Measure how long we wait for the timeout\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n            try\n            {\n                await promise.WaitAsync(timeout.Multiply(3));\n                finished = true;\n                Assert.Fail(\"Should have thrown\");\n            }\n            catch (Exception exc)\n            {\n                stopwatch.Stop();\n                Exception baseExc = exc.GetBaseException();\n                if (!(baseExc is TimeoutException))\n                {\n                    Assert.Fail(\"Should not have got here \" + exc);\n                }\n            }\n            output.WriteLine(\"Waited for \" + stopwatch.Elapsed);\n            Assert.True(!finished);\n            // Verify timeout occurred within expected bounds (90% to 350% of configured timeout)\n            Assert.True(stopwatch.Elapsed >= timeout.Multiply(0.9), \"Waited less than \" + timeout.Multiply(0.9) + \". Waited \" + stopwatch.Elapsed);\n            Assert.True(stopwatch.Elapsed <= timeout.Multiply(3.5), \"Waited longer than \" + timeout.Multiply(3.5) + \". Waited \" + stopwatch.Elapsed);\n            Assert.True(promise.Status == TaskStatus.Faulted);\n\n            // Verify request tracking is cleaned up - no requests should be pending\n            Assert.Equal(expected: 0, actual: this.runtimeClient.GetRunningRequestsCount(errorGrainType));\n\n            // Re-awaiting a timed-out task should fail immediately\n            try\n            {\n                stopwatch = new Stopwatch();\n                await promise;\n                Assert.Fail(\"Should have thrown\");\n            }\n            catch (Exception exc)\n            {\n                stopwatch.Stop();\n                Exception baseExc = exc.GetBaseException();\n                if (!(baseExc is TimeoutException))\n                {\n                    Assert.Fail(\"Should not have got here \" + exc);\n                }\n            }\n            Assert.True(stopwatch.Elapsed <= timeout.Multiply(0.1), \"Waited longer than \" + timeout.Multiply(0.1) + \". Waited \" + stopwatch.Elapsed);\n            Assert.True(promise.Status == TaskStatus.Faulted);\n        }\n\n        /// <summary>\n        /// Tests call dropping behavior when a grain is overloaded.\n        /// When a grain is busy processing a long-running request and the client times out,\n        /// subsequent calls to the same activation may be dropped to prevent queue buildup.\n        /// \n        /// Scenario:\n        /// 1. First call takes longer than timeout - client gets TimeoutException\n        /// 2. Second call arrives while first is still running - should be dropped\n        /// 3. Verify only the first call actually executed on the grain\n        /// \n        /// Currently skipped due to issue #3995.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/3995\"), TestCategory(\"SlowBVT\")]\n        public async Task CallThatShouldHaveBeenDroppedNotExecutedTest()\n        {\n            var responseTimeout = TimeSpan.FromSeconds(2);\n            this.runtimeClient.SetResponseTimeout(responseTimeout);\n\n            var target = Client.GetGrain<ILongRunningTaskGrain<int>>(Guid.NewGuid());\n\n            // First call: Takes 5 seconds but client times out after 2 seconds\n            var delay = TimeSpan.FromSeconds(5);\n            var firstCall = target.LongRunningTask(1, responseTimeout + delay);\n            await Task.Delay(TimeSpan.FromMilliseconds(100));\n            // Second call: Should be dropped because grain is still busy with first call\n            var secondCall = target.LongRunningTask(2, TimeSpan.Zero);\n\n            try\n            {\n                await Assert.ThrowsAsync<TimeoutException>(() => firstCall);\n                await Assert.ThrowsAsync<TimeoutException>(() => secondCall);\n            }\n            catch\n            {\n                output.WriteLine(firstCall.IsFaulted ? $\"firstCall: faulted\" : $\"firstCall: {firstCall.Result}\");\n                output.WriteLine(secondCall.IsFaulted ? $\"secondCall: faulted\" : $\"secondCall: {secondCall.Result}\");\n                throw;\n            }\n\n            // Wait for first call to complete on the silo\n            await Task.Delay(delay);\n\n            // Verify only the first call executed (value = 1), second call was dropped\n            Assert.Equal(1, await target.GetLastValue());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TimerTests/ReminderTests_Base.cs",
    "content": "//#define USE_SQL_SERVER\n\nusing System.Text;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Internal;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable UnusedVariable\n\nnamespace UnitTests.TimerTests\n{\n    /// <summary>\n    /// Base class for reminder tests providing common test operations and utilities.\n    /// </summary>\n    public class ReminderTests_Base : OrleansTestingBase, IDisposable\n    {\n        protected TestCluster HostedCluster { get; private set; }\n        internal static readonly TimeSpan LEEWAY = TimeSpan.FromMilliseconds(500); // the experiment shouldnt be that long that the sums of leeways exceeds a period\n        internal static readonly TimeSpan ENDWAIT = TimeSpan.FromMinutes(5);\n\n        internal const string DR = \"DEFAULT_REMINDER\";\n        internal const string R1 = \"REMINDER_1\";\n        internal const string R2 = \"REMINDER_2\";\n\n        protected const long retries = 3;\n\n        protected const long failAfter = 2; // NOTE: match this sleep with 'failCheckAfter' used in PerGrainFailureTest() so you dont try to get counter immediately after failure as new activation may not have the reminder statistics\n        protected const long failCheckAfter = 6; // safe value: 9\n\n        protected ILogger log;\n\n        public ReminderTests_Base(BaseTestClusterFixture fixture)\n        {\n            HostedCluster = fixture.HostedCluster;\n            GrainFactory = fixture.GrainFactory;\n\n            var filters = new LoggerFilterOptions();\n#if DEBUG\n            filters.AddFilter(\"Storage\", LogLevel.Trace);\n            filters.AddFilter(\"Reminder\", LogLevel.Trace);\n#endif\n\n            log = TestingUtils.CreateDefaultLoggerFactory(TestingUtils.CreateTraceFileName(\"client\", DateTime.Now.ToString(\"yyyyMMdd_hhmmss\")), filters).CreateLogger<ReminderTests_Base>();\n        }\n\n        public IGrainFactory GrainFactory { get; }\n\n        public void Dispose()\n        {\n            // ReminderTable.Clear() cannot be called from a non-Orleans thread,\n            // so we must proxy the call through a grain.\n            var controlProxy = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            controlProxy.EraseReminderTable().WaitAsync(TestConstants.InitTimeout).Wait();\n        }\n\n        public async Task Test_Reminders_Basic_StopByRef()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            IGrainReminder r1 = await grain.StartReminder(DR);\n            IGrainReminder r2 = await grain.StartReminder(DR);\n            try\n            {\n                // First handle should now be out of date once the seconf handle to the same reminder was obtained\n                await grain.StopReminder(r1);\n                Assert.Fail(\"Removed reminder1, which shouldn't be possible.\");\n            }\n            catch (Exception exc)\n            {\n                log.LogInformation(exc, \"Couldn't remove {Reminder}, as expected.\", r1);\n            }\n\n            await grain.StopReminder(r2);\n            log.LogInformation(\"Removed reminder2 successfully\");\n\n            // trying to see if readreminder works\n            _ = await grain.StartReminder(DR);\n            _ = await grain.StartReminder(DR);\n            _ = await grain.StartReminder(DR);\n            _ = await grain.StartReminder(DR);\n\n            IGrainReminder r = await grain.GetReminderObject(DR);\n            await grain.StopReminder(r);\n            log.LogInformation(\"Removed got reminder successfully\");\n        }\n\n        public async Task Test_Reminders_Basic_ListOps()\n        {\n            Guid id = Guid.NewGuid();\n            log.LogInformation(\"Start Grain Id = {GrainId}\", id);\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(id);\n            const int count = 5;\n            Task<IGrainReminder>[] startReminderTasks = new Task<IGrainReminder>[count];\n            for (int i = 0; i < count; i++)\n            {\n                startReminderTasks[i] = grain.StartReminder(DR + \"_\" + i);\n                log.LogInformation(\"Started {ReminderName}_{ReminderNumber}\", DR, i);\n            }\n\n            await Task.WhenAll(startReminderTasks);\n            // do comparison on strings\n            List<string> registered = (from reminder in startReminderTasks select reminder.Result.ReminderName).ToList();\n\n            log.LogInformation(\"Waited\");\n\n            List<IGrainReminder> remindersList = await grain.GetRemindersList();\n            List<string> fetched = (from reminder in remindersList select reminder.ReminderName).ToList();\n\n            foreach (var remRegistered in registered)\n            {\n                Assert.True(fetched.Remove(remRegistered), $\"Couldn't get reminder {remRegistered}. \" +\n                                                           $\"Registered list: {Utils.EnumerableToString(registered)}, \" +\n                                                           $\"fetched list: {Utils.EnumerableToString(remindersList, r => r.ReminderName)}\");\n            }\n            Assert.True(fetched.Count == 0, $\"More than registered reminders. Extra: {Utils.EnumerableToString(fetched)}\");\n\n            // do some time tests as well\n            log.LogInformation(\"Time tests\");\n            TimeSpan period = await grain.GetReminderPeriod(DR);\n            await Task.Delay((period + LEEWAY).Multiply(2)); // giving some leeway, including leeway in each period to minimize flakiness\n            for (int i = 0; i < count; i++)\n            {\n                long curr = await grain.GetCounter(DR + \"_\" + i);\n                Assert.Equal(2, curr);\n            }\n        }\n\n        public async Task Test_Reminders_1J_MultiGrainMultiReminders()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g2 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g3 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g4 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            IReminderTestGrain2 g5 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            TimeSpan period = await g1.GetReminderPeriod(DR);\n\n            Task<bool>[] tasks =\n            {\n                Task.Run(() => this.PerGrainMultiReminderTestChurn(g1)),\n                Task.Run(() => this.PerGrainMultiReminderTestChurn(g2)),\n                Task.Run(() => this.PerGrainMultiReminderTestChurn(g3)),\n                Task.Run(() => this.PerGrainMultiReminderTestChurn(g4)),\n                Task.Run(() => this.PerGrainMultiReminderTestChurn(g5)),\n            };\n\n            await Task.Delay(period.Multiply(5));\n\n            // start another silo ... although it will take it a while before it stabilizes\n            log.LogInformation(\"Starting another silo\");\n            await this.HostedCluster.StartAdditionalSilosAsync(1, true);\n\n            //Block until all tasks complete.\n            await Task.WhenAll(tasks).WaitAsync(ENDWAIT);\n        }\n\n        public async Task Test_Reminders_ReminderNotFound()\n        {\n            IReminderTestGrain2 g1 = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n\n            // request a reminder that does not exist\n            IGrainReminder reminder = await g1.GetReminderObject(\"blarg\");\n            Assert.Null(reminder);\n        }\n\n        internal async Task<bool> PerGrainMultiReminderTestChurn(IReminderTestGrain2 g)\n        {\n            // for churn cases, we do execute start and stop reminders with retries as we don't have the queue-ing \n            // functionality implemented on the LocalReminderService yet\n            TimeSpan period = await g.GetReminderPeriod(DR);\n            this.log.LogInformation(\"PerGrainMultiReminderTestChurn Period={Period} Grain={Grain}\", period, g);\n\n            // Start Default Reminder\n            //g.StartReminder(DR, file + \"_\" + DR).Wait();\n            await ExecuteWithRetries(g.StartReminder, DR);\n            TimeSpan sleepFor = period.Multiply(2);\n            await Task.Delay(sleepFor);\n            // Start R1\n            //g.StartReminder(R1, file + \"_\" + R1).Wait();\n            await ExecuteWithRetries(g.StartReminder, R1);\n            sleepFor = period.Multiply(2);\n            await Task.Delay(sleepFor);\n            // Start R2\n            //g.StartReminder(R2, file + \"_\" + R2).Wait();\n            await ExecuteWithRetries(g.StartReminder, R2);\n            sleepFor = period.Multiply(2);\n            await Task.Delay(sleepFor);\n\n            sleepFor = period.Multiply(1);\n            await Task.Delay(sleepFor);\n\n            // Stop R1\n            //g.StopReminder(R1).Wait();\n            await ExecuteWithRetriesStop(g.StopReminder, R1);\n            sleepFor = period.Multiply(2);\n            await Task.Delay(sleepFor);\n            // Stop R2\n            //g.StopReminder(R2).Wait();\n            await ExecuteWithRetriesStop(g.StopReminder, R2);\n            sleepFor = period.Multiply(1);\n            await Task.Delay(sleepFor);\n\n            // Stop Default reminder\n            //g.StopReminder(DR).Wait();\n            await ExecuteWithRetriesStop(g.StopReminder, DR);\n            sleepFor = period.Multiply(1) + LEEWAY; // giving some leeway\n            await Task.Delay(sleepFor);\n\n            long last = await g.GetCounter(R1);\n            AssertIsInRange(last, 4, 6, g, R1, sleepFor);\n\n            last = await g.GetCounter(R2);\n            AssertIsInRange(last, 4, 6, g, R2, sleepFor);\n\n            last = await g.GetCounter(DR);\n            AssertIsInRange(last, 9, 10, g, DR, sleepFor);\n\n            return true;\n        }\n\n        protected async Task<bool> PerGrainFailureTest(IReminderTestGrain2 grain)\n        {\n            TimeSpan period = await grain.GetReminderPeriod(DR);\n\n            this.log.LogInformation(\"PerGrainFailureTest Period={Period} Grain={Grain}\", period, grain);\n\n            await grain.StartReminder(DR);\n            TimeSpan sleepFor = period.Multiply(failCheckAfter) + LEEWAY; // giving some leeway\n            await Task.Delay(sleepFor);\n            long last = await grain.GetCounter(DR);\n            AssertIsInRange(last, failCheckAfter - 1, failCheckAfter + 1, grain, DR, sleepFor);\n\n            await grain.StopReminder(DR);\n            sleepFor = period.Multiply(2) + LEEWAY; // giving some leeway\n            await Task.Delay(sleepFor);\n            long curr = await grain.GetCounter(DR);\n\n            AssertIsInRange(curr, last, last + 1, grain, DR, sleepFor);\n\n            return true;\n        }\n\n        protected async Task<bool> PerGrainMultiReminderTest(IReminderTestGrain2 g)\n        {\n            var (dueTime, period) = await g.GetReminderDueTimeAndPeriod(DR);\n\n            this.log.LogInformation(\"PerGrainMultiReminderTest Period={Period} Grain={Grain}\", period, g);\n\n            // Each reminder is started 2 periods after the previous reminder\n            // once all reminders have been started, stop them every 2 periods\n            // except the default reminder, which we stop after 3 periods instead\n            // just to test and break the symmetry\n\n            // Start Default Reminder\n            await g.StartReminder(DR);\n            TimeSpan sleepFor = dueTime + period;\n            await Task.Delay(sleepFor);\n            var reminders = await g.GetReminderStates();\n            var (min, max) = GetExpectedRange(1);\n            AssertIsInRange(reminders[DR].Fired.Count, min, max, g, DR, sleepFor);\n\n            // Start R1\n            await g.StartReminder(R1);\n            await Task.Delay(sleepFor);\n            reminders = await g.GetReminderStates();\n            (min, max) = GetExpectedRange(1);\n            AssertIsInRange(reminders[R1].Fired.Count, min, max, g, R1, sleepFor);\n\n            // Start R2\n            await g.StartReminder(R2);\n            await Task.Delay(sleepFor);\n            reminders = await g.GetReminderStates();\n            (min, max) = GetExpectedRange(2);\n            AssertIsInRange(reminders[R1].Fired.Count, min, max, g, R1, sleepFor);\n            (min, max) = GetExpectedRange(1);\n            AssertIsInRange(reminders[R2].Fired.Count, min, max, g, R2, sleepFor);\n            (min, max) = GetExpectedRange(3);\n            AssertIsInRange(reminders[DR].Fired.Count, min, max, g, DR, sleepFor);\n\n            // Stop R1\n            await g.StopReminder(R1);\n            await Task.Delay(sleepFor);\n            reminders = await g.GetReminderStates();\n            (min, max) = GetExpectedRange(2);\n            AssertIsInRange(reminders[R1].Fired.Count, min, max, g, R1, sleepFor);\n            AssertIsInRange(reminders[R2].Fired.Count, min, max, g, R2, sleepFor);\n            (min, max) = GetExpectedRange(4);\n            AssertIsInRange(reminders[DR].Fired.Count, min, max, g, DR, sleepFor);\n\n            // Stop R2\n            await g.StopReminder(R2);\n            await Task.Delay(sleepFor);\n            reminders = await g.GetReminderStates();\n            (min, max) = GetExpectedRange(2);\n            AssertIsInRange(reminders[R1].Fired.Count, min, max, g, R1, sleepFor);\n            AssertIsInRange(reminders[R2].Fired.Count, min, max, g, R2, sleepFor);\n            (min, max) = GetExpectedRange(5);\n            AssertIsInRange(reminders[DR].Fired.Count, min, max, g, DR, sleepFor);\n\n            // Stop Default reminder\n            await g.StopReminder(DR);\n            await Task.Delay(sleepFor);\n            reminders = await g.GetReminderStates();\n            (min, max) = GetExpectedRange(2);\n            AssertIsInRange(reminders[R1].Fired.Count, min, max, g, R1, sleepFor);\n            AssertIsInRange(reminders[R2].Fired.Count, min, max, g, R2, sleepFor);\n            (min, max) = GetExpectedRange(5);\n            AssertIsInRange(reminders[DR].Fired.Count, min, max, g, DR, sleepFor);\n\n            return true;\n\n            (int MinFires, int MaxFires) GetExpectedRange(int numPeriods)\n            {\n                var minExpected = ((sleepFor - LEEWAY) * numPeriods - dueTime) / period;\n                var maxExpected = ((sleepFor + LEEWAY) * numPeriods - dueTime) / period;\n                return ((int)Math.Floor(minExpected), (int)Math.Ceiling(maxExpected));\n            }\n        }\n\n        protected async Task<bool> PerCopyGrainFailureTest(IReminderTestCopyGrain grain)\n        {\n            TimeSpan period = await grain.GetReminderPeriod(DR);\n\n            this.log.LogInformation(\"PerCopyGrainFailureTest Period={Period} Grain={Grain}\", period, grain);\n\n            await grain.StartReminder(DR);\n            await Task.Delay(period.Multiply(failCheckAfter) + LEEWAY); // giving some leeway\n            long last = await grain.GetCounter(DR);\n            Assert.Equal(failCheckAfter, last);  // \"{0} CopyGrain {1} Reminder {2}\" // Time(), grain.GetPrimaryKey(), DR);\n\n            await grain.StopReminder(DR);\n            await Task.Delay(period.Multiply(2) + LEEWAY); // giving some leeway\n            long curr = await grain.GetCounter(DR);\n            Assert.Equal(last, curr); // \"{0} CopyGrain {1} Reminder {2}\", Time(), grain.GetPrimaryKey(), DR);\n\n            return true;\n        }\n\n        protected static string Time()\n        {\n            return DateTime.UtcNow.ToString(\"hh:mm:ss.fff\");\n        }\n\n        protected void AssertIsInRange(long val, long lowerLimit, long upperLimit, IGrain grain, string reminderName, TimeSpan sleepFor)\n        {\n            StringBuilder sb = new StringBuilder();\n            sb.AppendFormat(\"Grain: {0} Grain PrimaryKey: {1}, Reminder: {2}, SleepFor: {3} Time now: {4}\",\n                grain, grain.GetPrimaryKey(), reminderName, sleepFor, Time());\n            sb.AppendFormat(\n                \" -- Expecting value in the range between {0} and {1}, and got value {2}.\",\n                lowerLimit, upperLimit, val);\n            this.log.LogInformation(\"{Message}\", sb.ToString());\n\n            bool tickCountIsInsideRange = lowerLimit <= val && val <= upperLimit;\n\n            if (!tickCountIsInsideRange)\n            {\n                Assert.True(tickCountIsInsideRange, $\"AssertIsInRange: {sb}  -- WHICH IS OUTSIDE RANGE.\");\n            }\n        }\n\n        protected async Task ExecuteWithRetries(Func<string, TimeSpan?, bool, Task> function, string reminderName, TimeSpan? period = null, bool validate = false)\n        {\n            for (long i = 1; i <= retries; i++)\n            {\n                try\n                {\n                    await function(reminderName, period, validate).WaitAsync(TestConstants.InitTimeout);\n                    return; // success ... no need to retry\n                }\n                catch (AggregateException aggEx)\n                {\n                    foreach (var exception in aggEx.InnerExceptions)\n                    {\n                        await HandleError(exception, i);\n                    }\n                }\n                catch (ReminderException exc)\n                {\n                    await HandleError(exc, i);\n                }\n            }\n\n            // execute one last time and bubble up errors if any\n            await function(reminderName, period, validate).WaitAsync(TestConstants.InitTimeout);\n        }\n\n        // Func<> doesnt take optional parameters, thats why we need a separate method\n        protected async Task ExecuteWithRetriesStop(Func<string, Task> function, string reminderName)\n        {\n            for (long i = 1; i <= retries; i++)\n            {\n                try\n                {\n                    await function(reminderName).WaitAsync(TestConstants.InitTimeout);\n                    return; // success ... no need to retry\n                }\n                catch (Exception exception)\n                {\n                    await HandleError(exception, i);\n                }\n            }\n\n            // execute one last time and bubble up errors if any\n            await function(reminderName).WaitAsync(TestConstants.InitTimeout);\n        }\n\n        private async Task<bool> HandleError(Exception ex, long i)\n        {\n            if (ex is AggregateException)\n            {\n                ex = ((AggregateException)ex).Flatten().InnerException;\n            }\n\n            if (ex is ReminderException)\n            {\n                this.log.LogInformation(ex, \"Retryable operation failed on attempt {Attempt}\", i);\n                await Task.Delay(TimeSpan.FromMilliseconds(10)); // sleep a bit before retrying\n                return true;\n            }\n\n            return false;\n        }\n    }\n}\n// ReSharper restore InconsistentNaming\n// ReSharper restore UnusedVariable\n"
  },
  {
    "path": "test/Orleans.Runtime.Internal.Tests/TimerTests/ReminderTests_TableGrain.cs",
    "content": "//#define USE_SQL_SERVER\n\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Orleans.Internal;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable UnusedVariable\n\nnamespace UnitTests.TimerTests\n{\n    /// <summary>\n    /// Tests for grain-based reminder functionality using in-memory reminder service as table storage.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Reminders\")]\n    public class ReminderTests_TableGrain : ReminderTests_Base, IClassFixture<ReminderTests_TableGrain.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n\n            private class SiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddMemoryGrainStorageAsDefault()\n                        .AddReminders()\n                        .UseInMemoryReminderService();\n                }\n            }\n        }\n\n        public ReminderTests_TableGrain(Fixture fixture) : base(fixture)\n        {\n            // ReminderTable.Clear() cannot be called from a non-Orleans thread,\n            // so we must proxy the call through a grain.\n            var controlProxy = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            controlProxy.EraseReminderTable().WaitAsync(TestConstants.InitTimeout).Wait();\n        }\n\n        // Basic tests\n\n        /// <summary>\n        /// Tests basic reminder operations including stopping reminders by reference.\n        /// </summary>\n        [Fact]\n        public async Task Rem_Grain_Basic_StopByRef()\n        {\n            await Test_Reminders_Basic_StopByRef();\n        }\n\n        /// <summary>\n        /// Tests basic reminder list operations including creation and retrieval.\n        /// </summary>\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/9555\")]\n        public async Task Rem_Grain_Basic_ListOps()\n        {\n            await Test_Reminders_Basic_ListOps();\n        }\n\n        /// <summary>\n        /// Tests handling of multiple reminders per grain.\n        /// </summary>\n        [Fact]\n        public async Task Rem_Grain_MultipleReminders()\n        {\n            IReminderTestGrain2 grain = this.GrainFactory.GetGrain<IReminderTestGrain2>(Guid.NewGuid());\n            await PerGrainMultiReminderTest(grain);\n        }\n\n        // Single join tests ... multi grain, multi reminders\n\n        /// <summary>\n        /// Tests single join scenario with multiple grains and multiple reminders.\n        /// </summary>\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4318\")]\n        public async Task Rem_Grain_1J_MultiGrainMultiReminders()\n        {\n            await Test_Reminders_1J_MultiGrainMultiReminders();\n        }\n\n        /// <summary>\n        /// Tests handling of reminder not found scenarios.\n        /// </summary>\n        [Fact]\n        public async Task Rem_Grain_ReminderNotFounds()\n        {\n            await Test_Reminders_ReminderNotFound();\n        }\n    }\n}\n// ReSharper restore InconsistentNaming\n// ReSharper restore UnusedVariable\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ActivationTracingTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Text;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Core.Internal;\nusing Orleans.Diagnostics;\nusing Orleans.Placement;\nusing Orleans.Runtime.Placement;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Failing test demonstrating missing activation tracing spans.\n    /// Expects an activation Activity to be created on first grain activation.\n    /// </summary>\n    [Collection(\"ActivationTracing\")]\n    public class ActivationTracingTests : OrleansTestingBase, IClassFixture<ActivationTracingTests.Fixture>\n    {\n        private static readonly ConcurrentBag<Activity> Started = new();\n\n        static ActivationTracingTests()\n        {\n            var listener = new ActivityListener\n            {\n                ShouldListenTo = src => src.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        || src.Name == ActivitySources.LifecycleActivitySourceName\n                                        || src.Name == ActivitySources.StorageActivitySourceName,\n                Sample = (ref _) => ActivitySamplingResult.AllData,\n                SampleUsingParentId = (ref _) => ActivitySamplingResult.AllData,\n                ActivityStarted = activity => Started.Add(activity),\n            };\n            ActivitySource.AddActivityListener(listener);\n        }\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 2; // Need 2 silos for migration tests\n                builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n                builder.AddSiloBuilderConfigurator<SiloCfg>();\n                builder.AddClientBuilderConfigurator<ClientCfg>();\n            }\n\n            private class SiloCfg : ISiloConfigurator\n            {\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates.\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddActivityPropagation()\n                        .AddDistributedGrainDirectory()\n                        .AddMemoryGrainStorageAsDefault()\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddIncomingGrainCallFilter<DeactivateAfterDisposeAsyncFilter>();\n                    hostBuilder.Services.AddPlacementFilter<TracingTestPlacementFilterStrategy, TracingTestPlacementFilterDirector>(ServiceLifetime.Singleton);\n                    hostBuilder.Services.AddPlacementFilter<SecondTracingTestPlacementFilterStrategy, SecondTracingTestPlacementFilterDirector>(ServiceLifetime.Singleton);\n                }\n#pragma warning restore ORLEANSEXP003\n            }\n\n            private class ClientCfg : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddActivityPropagation();\n                }\n            }\n        }\n\n        private readonly Fixture _fixture;\n        private readonly ITestOutputHelper _output;\n\n        public ActivationTracingTests(Fixture fixture, ITestOutputHelper output)\n        {\n            _fixture = fixture;\n            _output = output;\n        }\n\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationSpanIsCreatedOnFirstCall()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IActivityGrain>(Random.Shared.Next());\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Expect at least one activation-related activity\n                var activationActivities = Started.Where(a => a.Source.Name == ActivitySources.LifecycleActivitySourceName).ToList();\n                Assert.True(activationActivities.Count > 0, \"Expected activation tracing activity to be created, but none were observed.\");\n\n                // Verify all expected spans are present and properly parented under test-parent\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Find the placement span - should be parented to the grain call which is parented to test-parent\n                var placementSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.PlaceGrain);\n                Assert.NotNull(placementSpan);\n                Assert.Equal(testParentTraceId, placementSpan.TraceId.ToString());\n\n                // Find the placement filter span - should share the same trace ID as test-parent\n                var placementFilterSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.FilterPlacementCandidates);\n                Assert.Null(placementFilterSpan);\n\n                // Find the activation span - should be parented to the grain call which is parented to test-parent\n                var activationSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n                Assert.NotNull(activationSpan);\n                Assert.Equal(testParentTraceId, activationSpan.TraceId.ToString());\n\n                // Find the OnActivateAsync span - should be parented to the activation span\n                var onActivateSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.OnActivate);\n                Assert.Null(onActivateSpan);\n\n                // Find the directory register span - should be parented to activation span\n                var directoryRegisterSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.RegisterDirectoryEntry);\n                Assert.NotNull(directoryRegisterSpan);\n                Assert.Equal(testParentTraceId, directoryRegisterSpan.TraceId.ToString());\n                Assert.Equal(activationSpan.SpanId.ToString(), directoryRegisterSpan.ParentSpanId.ToString());\n            }\n            finally\n            {\n                parent.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationSpanIncludesFilter()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-filter\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IFilteredActivityGrain>(Random.Shared.Next());\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Expect at least one activation-related activity\n                var activationActivities = Started.Where(a => a.Source.Name == ActivitySources.LifecycleActivitySourceName).ToList();\n                Assert.True(activationActivities.Count > 0, \"Expected activation tracing activity to be created, but none were observed.\");\n\n                // Verify all expected spans are present and properly parented under test-parent\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Find the placement span - should be parented to the grain call which is parented to test-parent\n                var placementSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.PlaceGrain);\n                Assert.NotNull(placementSpan);\n                Assert.Equal(testParentTraceId, placementSpan.TraceId.ToString());\n\n                // Find the placement filter span - should share the same trace ID as test-parent\n                var placementFilterSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.FilterPlacementCandidates);\n                Assert.NotNull(placementFilterSpan);\n                Assert.Equal(testParentTraceId, placementFilterSpan.TraceId.ToString());\n                Assert.Equal(\"TracingTestPlacementFilterStrategy\", placementFilterSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.placement.filter.type\").Value);\n\n                // Find the activation span - should be parented to the grain call which is parented to test-parent\n                var activationSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n                Assert.NotNull(activationSpan);\n                Assert.Equal(testParentTraceId, activationSpan.TraceId.ToString());\n\n                // Find the OnActivateAsync span - should be parented to the activation span\n                var onActivateSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.OnActivate);\n                Assert.NotNull(onActivateSpan);\n                Assert.Equal(testParentTraceId, onActivateSpan.TraceId.ToString());\n                Assert.Equal(activationSpan.SpanId.ToString(), onActivateSpan.ParentSpanId.ToString());\n\n                // Find the directory register span - should be parented to activation span\n                var directoryRegisterSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.RegisterDirectoryEntry);\n                Assert.NotNull(directoryRegisterSpan);\n                Assert.Equal(testParentTraceId, directoryRegisterSpan.TraceId.ToString());\n                Assert.Equal(activationSpan.SpanId.ToString(), directoryRegisterSpan.ParentSpanId.ToString());\n            }\n            finally\n            {\n                parent.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationSpanIncludesMultipleFilters()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-multi-filter\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IMultiFilteredActivityGrain>(Random.Shared.Next());\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Verify all expected spans are present and properly parented under test-parent\n                var testParentTraceId = parent.TraceId.ToString();\n                var testParentSpanId = parent.SpanId.ToString();\n\n                // Find the placement span\n                var placementSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.PlaceGrain);\n                Assert.NotNull(placementSpan);\n                Assert.Equal(testParentTraceId, placementSpan.TraceId.ToString());\n\n                // Find ALL placement filter spans - should be 2 (one for each filter)\n                var placementFilterSpans = Started\n                    .Where(a => a.OperationName == ActivityNames.FilterPlacementCandidates)\n                    .OrderBy(a => a.StartTimeUtc)\n                    .ToList();\n                Assert.Equal(2, placementFilterSpans.Count);\n\n                // Both filter spans should share the same trace ID as test-parent\n                foreach (var filterSpan in placementFilterSpans)\n                {\n                    Assert.Equal(testParentTraceId, filterSpan.TraceId.ToString());\n                    // Each filter span should be parented directly to the PlaceGrain span\n                    Assert.Equal(placementSpan.SpanId.ToString(), filterSpan.ParentSpanId.ToString());\n                }\n\n                // Verify that both filters were executed\n                var filterTypes = placementFilterSpans\n                    .Select(span => span.Tags.FirstOrDefault(t => t.Key == \"orleans.placement.filter.type\").Value)\n                    .ToHashSet();\n                Assert.Contains(\"TracingTestPlacementFilterStrategy\", filterTypes);\n                Assert.Contains(\"SecondTracingTestPlacementFilterStrategy\", filterTypes);\n            }\n            finally\n            {\n                parent.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task PersistentStateReadSpanIsCreatedDuringActivation()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-storage\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IPersistentStateActivityGrain>(Random.Shared.Next());\n                // First call should force activation which triggers state read\n                _ = await grain.GetActivityId();\n\n                // Expect at least one activation-related activity\n                var activationActivities = Started.Where(a => a.Source.Name == ActivitySources.LifecycleActivitySourceName).ToList();\n                Assert.True(activationActivities.Count > 0, \"Expected activation tracing activity to be created, but none were observed.\");\n\n                // Verify all expected spans are present and properly parented under test-parent\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Find the activation span - should be parented to the grain call which is parented to test-parent\n                var activationSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain && a.Tags.First(kv => kv.Key == \"orleans.grain.type\").Value == \"persistentstateactivity\");\n                Assert.NotNull(activationSpan);\n                Assert.Equal(testParentTraceId, activationSpan.TraceId.ToString());\n\n                // Find the storage read span - should share the same trace ID as test-parent\n                var storageReadSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.StorageRead);\n                Assert.NotNull(storageReadSpan);\n                Assert.Equal(testParentTraceId, storageReadSpan.TraceId.ToString());\n\n                // Verify storage read span has expected tags\n                Assert.Equal(\"MemoryGrainStorage\", storageReadSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.storage.provider\").Value);\n                Assert.Equal(\"state\", storageReadSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.storage.state.name\").Value);\n                Assert.Equal(\"PersistentStateActivityGrainState\", storageReadSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.storage.state.type\").Value);\n\n                // Verify the grain ID tag is present\n                var grainIdTag = storageReadSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value;\n                Assert.NotNull(grainIdTag);\n            }\n            finally\n            {\n                parent.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that dehydrate and rehydrate spans are created during grain migration.\n        /// Verifies that the migration process creates proper tracing spans for both\n        /// dehydration (on the source silo) and rehydration (on the target silo).\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task MigrationSpansAreCreatedDuringGrainMigration()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-migration\");\n            parent?.Start();\n            try\n            {\n                // Create a grain and set some state\n                var grain = _fixture.GrainFactory.GetGrain<IMigrationTracingTestGrain>(Random.Shared.Next());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Trigger migration with a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Verify the state was preserved (this also waits for migration to complete)\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Verify dehydrate span was created\n                var dehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationDehydrate).ToList();\n                Assert.True(dehydrateSpans.Count > 0, \"Expected at least one dehydrate span to be created during migration\");\n\n                var dehydrateSpan = dehydrateSpans.First();\n                Assert.NotNull(dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.NotNull(dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.silo.id\").Value);\n                Assert.NotNull(dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.activation.id\").Value);\n                // Verify target silo tag is present\n                Assert.Equal(targetHost.ToString(), dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.migration.target.silo\").Value);\n                // Verify dehydrate span is parented to the migration request trace\n                Assert.Equal(testParentTraceId, dehydrateSpan.TraceId.ToString());\n\n                // Verify rehydrate span was created on the target silo\n                var rehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationRehydrate).ToList();\n                Assert.True(rehydrateSpans.Count > 0, \"Expected at least one rehydrate span to be created during migration\");\n\n                var rehydrateSpan = rehydrateSpans.First();\n                Assert.NotNull(rehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.NotNull(rehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.silo.id\").Value);\n                Assert.NotNull(rehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.activation.id\").Value);\n                // Verify the rehydrate span has the previous registration tag\n                Assert.NotNull(rehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.rehydrate.previousRegistration\").Value);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that FilterPlacementCandidates spans are properly parented under a PlaceGrain span\n        /// when migration triggers placement via PlaceGrainAsync.\n        /// This covers the code path where PlaceGrainAsync (not the PlacementWorker message path)\n        /// calls a placement director which calls GetCompatibleSilos with filters.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task MigrationPlacementFilterSpanIsParentedUnderPlaceGrainSpan()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-migration-filter\");\n            parent?.Start();\n            try\n            {\n                // Create a grain that has both a placement filter and migration support\n                var grain = _fixture.GrainFactory.GetGrain<IMigrationFilterTracingTestGrain>(Random.Shared.Next());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Clear activities to focus on migration placement\n                Started.Clear();\n\n                // Trigger migration with a placement hint\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Verify the state was preserved (this also waits for migration to complete)\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Find the PlaceGrain span created during migration's PlaceGrainAsync call\n                var placementSpans = Started.Where(a => a.OperationName == ActivityNames.PlaceGrain).ToList();\n                Assert.True(placementSpans.Count > 0, \"Expected at least one PlaceGrain span during migration\");\n\n                var placementSpan = placementSpans.First();\n                Assert.Equal(testParentTraceId, placementSpan.TraceId.ToString());\n\n                // Find the FilterPlacementCandidates span - should share the same trace ID\n                var filterSpans = Started.Where(a => a.OperationName == ActivityNames.FilterPlacementCandidates).ToList();\n                Assert.True(filterSpans.Count > 0, \"Expected at least one FilterPlacementCandidates span during migration with filter\");\n\n                var filterSpan = filterSpans.First();\n                Assert.Equal(testParentTraceId, filterSpan.TraceId.ToString());\n                Assert.Equal(\"TracingTestPlacementFilterStrategy\", filterSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.placement.filter.type\").Value);\n\n                // The filter span should be a child of the PlaceGrain span\n                Assert.Equal(placementSpan.SpanId.ToString(), filterSpan.ParentSpanId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that dehydrate and rehydrate spans are created during migration of a grain with persistent state.\n        /// Verifies that IPersistentState participates in migration and creates proper tracing spans.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task MigrationSpansAreCreatedForGrainWithPersistentState()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-migration-persistent\");\n            parent?.Start();\n            try\n            {\n                // Create a grain with persistent state and set some state\n                var grain = _fixture.GrainFactory.GetGrain<IMigrationPersistentStateTracingTestGrain>(Random.Shared.Next());\n                var expectedStateA = Random.Shared.Next();\n                var expectedStateB = Random.Shared.Next();\n                await grain.SetState(expectedStateA, expectedStateB);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Trigger migration with a placement hint\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Wait for migration to complete\n                GrainAddress newAddress;\n                do\n                {\n                    await Task.Delay(100);\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                // Verify the grain migrated to the target silo\n                Assert.Equal(targetHost, newAddress.SiloAddress);\n\n                // Verify the state was preserved\n                var (actualA, actualB) = await grain.GetState();\n                Assert.Equal(expectedStateA, actualA);\n                Assert.Equal(expectedStateB, actualB);\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                // Verify dehydrate span was NOT created (grain doesn't implement IGrainMigrationParticipant)\n                var dehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationDehydrate).ToList();\n                Assert.True(dehydrateSpans.Count == 0, $\"Expected no dehydrate spans for grain without IGrainMigrationParticipant, but found {dehydrateSpans.Count}\");\n\n                // Verify rehydrate span was NOT created\n                var rehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationRehydrate).ToList();\n                Assert.True(rehydrateSpans.Count == 0, $\"Expected no rehydrate spans for grain without IGrainMigrationParticipant, but found {rehydrateSpans.Count}\");\n\n                // Verify storage read span was NOT created during rehydration (state is transferred via migration context)\n                // Note: Storage read should NOT happen during migration - the state is transferred in-memory\n                var storageReadSpansAfterMigration = Started.Where(a => a.OperationName == ActivityNames.StorageRead).ToList();\n                // During migration, storage should not be read because state is transferred via dehydration context\n                // The storage read only happens on fresh activation, not on rehydration\n\n                Assert.Equal(2, storageReadSpansAfterMigration.Count);\n            }\n            finally\n            {\n                parent.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that dehydrate and rehydrate spans are NOT created during migration of a grain\n        /// that does not implement IGrainMigrationParticipant.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task DehydrateAndRehydrateSpansAreNotCreatedForGrainWithoutMigrationParticipant()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-no-migration-participant\");\n            parent?.Start();\n            try\n            {\n                // Create a grain that doesn't implement IGrainMigrationParticipant\n                var grain = _fixture.GrainFactory.GetGrain<ISimpleMigrationTracingTestGrain>(Random.Shared.Next());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Trigger migration with a placement hint to coerce the placement director to use the target silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Make a call to ensure grain is activated on target silo\n                // Note: State won't be preserved since grain doesn't participate in migration\n                _ = await grain.GetState();\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                // Verify dehydrate span was NOT created (grain doesn't implement IGrainMigrationParticipant)\n                var dehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationDehydrate).ToList();\n                Assert.True(dehydrateSpans.Count == 0, $\"Expected no dehydrate spans for grain without IGrainMigrationParticipant, but found {dehydrateSpans.Count}\");\n\n                // Verify rehydrate span was NOT created\n                var rehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationRehydrate).ToList();\n                Assert.True(rehydrateSpans.Count == 0, $\"Expected no rehydrate spans for grain without IGrainMigrationParticipant, but found {rehydrateSpans.Count}\");\n\n                // Verify that activation span WAS created (the grain was still activated on the new silo)\n                var activationSpans = Started.Where(a => a.OperationName == ActivityNames.ActivateGrain).ToList();\n                Assert.True(activationSpans.Count > 0, \"Expected at least one activation span for the migrated grain\");\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that appropriate tracing spans are created for IAsyncEnumerable grain calls with multiple elements.\n        /// Verifies that:\n        /// 1. A session span is created with the original method name (GetActivityDataStream)\n        /// 2. StartEnumeration, MoveNext, and DisposeAsync spans are nested under the session span\n        /// 3. All spans share the same trace context\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task AsyncEnumerableSpansAreCreatedForMultipleElements()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-async-enumerable\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IAsyncEnumerableActivityGrain>(Random.Shared.Next());\n                const int elementCount = 5;\n\n                var values = new List<ActivityData>();\n                await foreach (var entry in grain.GetActivityDataStream(elementCount).WithBatchSize(1))\n                {\n                    values.Add(entry);\n                }\n\n                // Verify we received all elements\n                Assert.Equal(elementCount, values.Count);\n\n                // Verify all expected spans are present and properly parented under test-parent\n                var testParentTraceId = parent.TraceId.ToString();\n                var testParentSpanId = parent.SpanId.ToString();\n\n                // Find all activities with the ApplicationGrainActivitySourceName\n                var applicationSpans = Started.Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName).ToList();\n\n                // Find the session span (the logical method call span)\n                // This should have the method name from the grain interface (e.g., \"IAsyncEnumerableActivityGrain/GetActivityDataStream\")\n                var sessionSpans = applicationSpans.Where(a => a.OperationName.Contains(\"GetActivityDataStream\")).ToList();\n                Assert.True(sessionSpans.Count >= 1, \"Expected at least one session span with GetActivityDataStream operation name\");\n\n                var sessionSpan = sessionSpans.First();\n                Assert.Equal(testParentTraceId, sessionSpan.TraceId.ToString());\n                Assert.Equal(testParentSpanId, sessionSpan.ParentSpanId.ToString());\n\n                // Verify the session span has the request ID tag\n                var requestIdTag = sessionSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.async_enumerable.request_id\").Value;\n                Assert.NotNull(requestIdTag);\n\n                var sessionSpanId = sessionSpan.SpanId.ToString();\n\n                // Find all spans (including runtime spans) to verify parenting\n                var allSpans = Started.ToList();\n\n                // Find the StartEnumeration span - should be nested under the session span (in RuntimeActivitySourceName)\n                // Filter to only client-side spans (those directly parented to the session span)\n                var startEnumerationSpans = allSpans\n                    .Where(a => a.OperationName.Contains(\"StartEnumeration\") && a.ParentSpanId.ToString() == sessionSpanId)\n                    .ToList();\n                Assert.True(startEnumerationSpans.Count >= 1, \"Expected at least one StartEnumeration span parented to session span\");\n\n                var startEnumerationSpan = startEnumerationSpans.First();\n                Assert.Equal(testParentTraceId, startEnumerationSpan.TraceId.ToString());\n\n                // Find MoveNext spans - should be nested under the session span (in RuntimeActivitySourceName)\n                // Filter to only client-side spans (those directly parented to the session span)\n                var moveNextSpans = allSpans\n                    .Where(a => a.OperationName.Contains(\"MoveNext\") && a.ParentSpanId.ToString() == sessionSpanId)\n                    .ToList();\n                Assert.True(moveNextSpans.Count >= 1, $\"Expected at least one MoveNext span parented to session span, found {moveNextSpans.Count}\");\n\n                // All client-side MoveNext spans should share the same trace ID\n                foreach (var moveNextSpan in moveNextSpans)\n                {\n                    Assert.Equal(testParentTraceId, moveNextSpan.TraceId.ToString());\n                }\n\n                // Find DisposeAsync span - should be nested under the session span (in RuntimeActivitySourceName)\n                // Filter to only client-side spans (those directly parented to the session span)\n                var disposeSpans = allSpans\n                    .Where(a => a.OperationName.Contains(\"DisposeAsync\") && a.ParentSpanId.ToString() == sessionSpanId)\n                    .ToList();\n                Assert.True(disposeSpans.Count >= 1, \"Expected at least one DisposeAsync span parented to session span\");\n\n                var disposeSpan = disposeSpans.First();\n                Assert.Equal(testParentTraceId, disposeSpan.TraceId.ToString());\n\n                // Verify each ActivityData received has activity information\n                // (verifying trace context was propagated into the grain during enumeration)\n                foreach (var activityData in values)\n                {\n                    Assert.NotNull(activityData);\n                    Assert.NotNull(activityData.Id);\n                }\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is created when a grain is deactivated via DeactivateOnIdle.\n        /// Verifies that the span has proper tags including grain ID, type, silo ID, and deactivation reason.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsCreatedOnDeactivateOnIdle()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-deactivate\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationTracingTestGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Trigger deactivation - capture the trace ID before clearing\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation\n                await grain.TriggerDeactivation();\n\n                // Wait for deactivation to complete - make a call to ensure grain is reactivated (which confirms deactivation happened)\n                await Task.Delay(500);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the span has expected tags\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.type\").Value);\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.silo.id\").Value);\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.activation.id\").Value);\n\n                // Verify deactivation reason tag\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"ApplicationRequested\", deactivationReasonTag);\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                // This confirms the activity context was propagated from the TriggerDeactivation call\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span captures state writes performed during deactivation.\n        /// Verifies that storage operations during OnDeactivateAsync are properly traced.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIncludesStorageWriteDuringDeactivation()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-deactivate-storage\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationWithWorkTracingTestGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation\n                await grain.TriggerDeactivation();\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                var wasDeactivated = await grain.WasDeactivated();\n                Assert.True(wasDeactivated, \"Expected grain to have been deactivated\");\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                // Find storage write span - should have been created during OnDeactivateAsync\n                var storageWriteSpans = Started.Where(a => a.OperationName == ActivityNames.StorageWrite).ToList();\n                Assert.True(storageWriteSpans.Count > 0, \"Expected at least one storage write span to be created during OnDeactivateAsync\");\n\n                var storageWriteSpan = storageWriteSpans.First();\n                Assert.Equal(\"MemoryGrainStorage\", storageWriteSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.storage.provider\").Value);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span captures exceptions thrown during deactivation.\n        /// Verifies that the span's error status is set and the exception event is recorded.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanCapturesExceptionDuringDeactivation()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-deactivate-exception\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationWithExceptionTracingTestGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation (grain throws exception in OnDeactivateAsync)\n                await grain.TriggerDeactivation();\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the span captured the error\n                Assert.Equal(ActivityStatusCode.Error, onDeactivateSpan.Status);\n\n                // Verify the span captured the error\n                Assert.Equal(\"on-deactivate-failed\", onDeactivateSpan.StatusDescription);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is created during migration and precedes the dehydration span.\n        /// Verifies the correct ordering: OnDeactivateAsync -> Dehydrate during migration.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanPrecedesDehydrateDuringMigration()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-deactivate-migrate\");\n            parent?.Start();\n            try\n            {\n                // Create a grain and set some state\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationMigrationTracingTestGrain>(Random.Shared.Next());\n                var expectedState = Random.Shared.Next();\n                await grain.SetState(expectedState);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Clear activities to focus on deactivation/migration\n                Started.Clear();\n\n                // Trigger migration with a placement hint\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Wait for migration to complete\n                GrainAddress newAddress;\n                do\n                {\n                    await Task.Delay(100);\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                // Verify the state was preserved\n                var newState = await grain.GetState();\n                Assert.Equal(expectedState, newState);\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span during migration\");\n\n                // Find the dehydrate span\n                var dehydrateSpans = Started.Where(a => a.OperationName == ActivityNames.ActivationDehydrate).ToList();\n                Assert.True(dehydrateSpans.Count > 0, \"Expected at least one dehydrate span during migration\");\n\n                // Verify OnDeactivate started before Dehydrate (as per the FinishDeactivating flow)\n                var onDeactivateSpan = onDeactivateSpans.First();\n                var dehydrateSpan = dehydrateSpans.First();\n\n                Assert.True(onDeactivateSpan.StartTimeUtc <= dehydrateSpan.StartTimeUtc,\n                    \"OnDeactivateAsync should start before or at the same time as Dehydrate\");\n\n                // Verify both spans have proper tags\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.Contains(\"Migrating\", onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value);\n\n                Assert.NotNull(dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.Equal(targetHost.ToString(), dehydrateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.migration.target.silo\").Value);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is NOT created for grains that don't implement IGrainBase.\n        /// Verifies that only grains with OnDeactivateAsync implementation get the span.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsNotCreatedForNonGrainBaseGrain()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-no-deactivate\");\n            parent?.Start();\n            try\n            {\n                // Use a simple grain that doesn't override OnDeactivateAsync (IActivityGrain/ActivityGrain)\n                var grain = _fixture.GrainFactory.GetGrain<IActivityGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation via IGrainManagementExtension\n                await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation\n                _ = await grain.GetActivityId();\n\n                // For grains that don't inherit from Grain (which implements IGrainBase), \n                // OnDeactivateAsync won't be called, so no span should be created\n                // Note: ActivityGrain doesn't inherit from Grain, it implements IActivityGrain directly\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n\n                // ActivityGrain doesn't implement IGrainBase, so no OnDeactivate span should be created\n                Assert.True(onDeactivateSpans.Count == 0,\n                    $\"Expected no OnDeactivate spans for grain not implementing IGrainBase, but found {onDeactivateSpans.Count}\");\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span properly inherits the trace context from the triggering call.\n        /// Verifies that when deactivation is triggered, the OnDeactivate span has the same TraceId as the request.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanInheritsTraceContextFromTriggeringCall()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-trace-context\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationTracingTestGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // Trigger deactivation - this call's activity context should be propagated to OnDeactivate\n                await grain.TriggerDeactivation();\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                // This confirms trace context propagation works correctly\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is created during IAsyncEnumerable method execution when the grain calls DeactivateOnIdle.\n        /// Verifies that the OnDeactivate span is properly parented to the method call (session) span.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsParentedToAsyncEnumerableMethodCall()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-async-enum-deactivate\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IAsyncEnumerableDeactivationGrain>(Random.Shared.Next());\n                var testParentTraceId = parent.TraceId.ToString();\n                const int elementCount = 3;\n\n                var values = new List<int>();\n                await foreach (var value in grain.GetValuesAndDeactivate(elementCount).WithBatchSize(1))\n                {\n                    values.Add(value);\n                }\n\n                // Verify we received all elements\n                Assert.Equal(elementCount, values.Count);\n\n                // Wait for deactivation to complete\n                await Task.Delay(1000);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                _ = await grain.GetActivityId();\n\n                // Find the session span (the logical method call span)\n                var sessionSpans = Started\n                    .Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                               && a.OperationName.Contains(\"GetValuesAndDeactivate\"))\n                    .ToList();\n                Assert.True(sessionSpans.Count >= 1, \"Expected at least one session span with GetValuesAndDeactivate operation name\");\n\n                var sessionSpan = sessionSpans.First();\n                Assert.Equal(testParentTraceId, sessionSpan.TraceId.ToString());\n                var sessionSpanId = sessionSpan.SpanId.ToString();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during enumeration\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n\n                // Verify the OnDeactivate span is parented to the session span\n                // Note: The OnDeactivate might be a descendant (not direct child) of the session span,\n                // but it should be in the same trace\n                Assert.Equal(sessionSpan.TraceId, onDeactivateSpan.TraceId);\n\n                // Verify deactivation reason tag\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"ApplicationRequested\", deactivationReasonTag);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span captures proper deactivation reason for different deactivation scenarios.\n        /// Verifies that the deactivation reason tag reflects the actual reason for deactivation.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanHasCorrectReasonTagForMigration()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-reason-migration\");\n            parent?.Start();\n            try\n            {\n                // Create a grain and set some state\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationMigrationTracingTestGrain>(Random.Shared.Next());\n                var testParentTraceId = parent.TraceId.ToString();\n                await grain.SetState(42);\n                var originalAddress = await grain.GetGrainAddress();\n                var originalHost = originalAddress.SiloAddress;\n\n                // Find a different silo to migrate to\n                var targetHost = _fixture.HostedCluster.GetActiveSilos()\n                    .Select(s => s.SiloAddress)\n                    .First(address => address != originalHost);\n\n                // Clear activities to focus on deactivation/migration\n                Started.Clear();\n\n                // Trigger migration\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetHost);\n                await grain.Cast<IGrainManagementExtension>().MigrateOnIdle();\n\n                // Wait for migration to complete\n                GrainAddress newAddress;\n                do\n                {\n                    await Task.Delay(100);\n                    newAddress = await grain.GetGrainAddress();\n                } while (newAddress.ActivationId == originalAddress.ActivationId);\n\n                // Give some time for all activities to complete\n                await Task.Delay(500);\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span during migration\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the deactivation reason tag indicates migration\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"Migrating\", deactivationReasonTag);\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is created when a grain throws InconsistentStateException\n        /// and gets deactivated with ApplicationError reason.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsCreatedForInconsistentStateException()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-inconsistent-state\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IInconsistentStateDeactivationGrain>(Random.Shared.Next());\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // This call will throw InconsistentStateException and trigger deactivation\n                try\n                {\n                    await grain.ThrowInconsistentStateException();\n                }\n                catch (InconsistentStateException)\n                {\n                    // Expected\n                }\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the span has expected tags\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.type\").Value);\n\n                // Verify deactivation reason tag indicates ApplicationError\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"ApplicationError\", deactivationReasonTag);\n\n                // Verify the OnDeactivate span has a valid trace ID\n                // Note: The trace ID may or may not match our parent activity depending on timing,\n                // but it should be valid and propagated from somewhere in the call chain\n                Assert.NotEqual(default(ActivityTraceId).ToString(), onDeactivateSpan.TraceId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is NOT created when a grain fails during activation (PreviousState != Valid).\n        /// The OnDeactivate span should only be created when the grain was previously in Valid state.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsNotCreatedForActivationFailure()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-activation-failure\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IActivationFailureDeactivationGrain>(Random.Shared.Next());\n\n                // Clear activities to focus on activation/deactivation\n                Started.Clear();\n\n                // First call should trigger activation which will fail\n                try\n                {\n                    await grain.GetActivityId();\n                }\n                catch\n                {\n                    // Expected - activation fails\n                }\n\n                // Wait for any deactivation to complete\n                await Task.Delay(5000);\n\n                // Find the OnDeactivate span - should NOT exist because the grain was never in Valid state\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count == 0,\n                    $\"Expected no OnDeactivate spans for grain that failed during activation, but found {onDeactivateSpans.Count}\");\n\n                // Verify the activation span was created\n                var activationSpans = Started.Where(a => a.OperationName == ActivityNames.ActivateGrain).ToList();\n                Assert.True(activationSpans.Count > 0, \"Expected at least one activation span\");\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that OnDeactivateAsync span is created when a grain deactivates itself using GrainContext.Deactivate.\n        /// This tests the programmatic deactivation path within the grain.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanIsCreatedForGrainContextDeactivate()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-grain-context-deactivate\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IGrainContextDeactivationGrain>(Random.Shared.Next());\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation using GrainContext.Deactivate with custom reason\n                await grain.DeactivateWithCustomReason(\"Custom deactivation reason for testing\");\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the span has expected tags\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.id\").Value);\n                Assert.NotNull(onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.grain.type\").Value);\n\n                // Verify deactivation reason tag indicates ApplicationRequested with custom message\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"ApplicationRequested\", deactivationReasonTag);\n                Assert.Contains(\"Custom deactivation reason for testing\", deactivationReasonTag);\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that the OnDeactivate span properly captures the activity context when deactivation\n        /// is triggered externally via IGrainManagementExtension.DeactivateOnIdle.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task OnDeactivateSpanHasCorrectParentWhenTriggeredExternally()\n        {\n            Started.Clear();\n\n            using var parent = ActivitySources.ApplicationGrainSource.StartActivity(\"test-parent-external-deactivate\");\n            parent?.Start();\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<IDeactivationTracingTestGrain>(Random.Shared.Next());\n                var testParentTraceId = parent.TraceId.ToString();\n\n                // First call should force activation\n                _ = await grain.GetActivityId();\n\n                // Clear activities to focus on deactivation\n                Started.Clear();\n\n                // Trigger deactivation externally via IGrainManagementExtension\n                await grain.Cast<IGrainManagementExtension>().DeactivateOnIdle();\n\n                // Wait for deactivation to complete\n                await Task.Delay(500);\n\n                // Make another call to force a new activation (confirming the previous one was deactivated)\n                _ = await grain.GetActivityId();\n\n                // Find the OnDeactivate span\n                var onDeactivateSpans = Started.Where(a => a.OperationName == ActivityNames.OnDeactivate).ToList();\n                Assert.True(onDeactivateSpans.Count > 0, \"Expected at least one OnDeactivate span to be created during deactivation\");\n\n                var onDeactivateSpan = onDeactivateSpans.First();\n\n                // Verify the OnDeactivate span shares the same trace ID as the parent activity\n                // This confirms the activity context was propagated from the DeactivateOnIdle call\n                Assert.Equal(testParentTraceId, onDeactivateSpan.TraceId.ToString());\n\n                // Verify deactivation reason tag\n                var deactivationReasonTag = onDeactivateSpan.Tags.FirstOrDefault(t => t.Key == \"orleans.deactivation.reason\").Value;\n                Assert.NotNull(deactivationReasonTag);\n                Assert.Contains(\"ApplicationRequested\", deactivationReasonTag);\n            }\n            finally\n            {\n                parent?.Stop();\n                AssertNoApplicationSpansParentedByRuntimeSpans();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Asserts that no spans from ApplicationGrainActivitySourceName have parents from RuntimeActivitySourceName.\n        /// This ensures that if only ApplicationGrainActivitySourceName has been added (without RuntimeActivitySourceName),\n        /// there won't be any hanging traces put at root because of missing RuntimeActivitySourceName spans\n        /// that would otherwise propagate the trace context.\n        /// </summary>\n        private void AssertNoApplicationSpansParentedByRuntimeSpans()\n        {\n            var activities = Started.ToList();\n            var activityById = activities\n                .Where(a => a.Id is not null)\n                .ToDictionary(a => a.Id!);\n\n            var applicationSpans = activities\n                .Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName)\n                .ToList();\n\n            var violations = new List<(Activity Child, Activity Parent)>();\n\n            foreach (var appSpan in applicationSpans)\n            {\n                if (appSpan.ParentId is not null && activityById.TryGetValue(appSpan.ParentId, out var parentActivity))\n                {\n                    if (parentActivity.Source.Name == ActivitySources.RuntimeActivitySourceName)\n                    {\n                        violations.Add((appSpan, parentActivity));\n                    }\n                }\n            }\n\n            if (violations.Count > 0)\n            {\n                var sb = new StringBuilder();\n                sb.AppendLine($\"Found {violations.Count} ApplicationGrainActivitySourceName span(s) with RuntimeActivitySourceName parent(s):\");\n                foreach (var (child, violationParent) in violations)\n                {\n                    sb.AppendLine($\"  - Application span '{child.OperationName}' (Id: {child.Id}) has Runtime parent '{violationParent.OperationName}' (Id: {violationParent.Id})\");\n                }\n                Assert.Fail(sb.ToString());\n            }\n        }\n\n        private void PrintActivityDiagnostics()\n        {\n            var activities = Started.ToList();\n            if (activities.Count == 0)\n            {\n                _output.WriteLine(\"No activities captured.\");\n                return;\n            }\n\n            var sb = new StringBuilder();\n            sb.AppendLine();\n            sb.AppendLine(\"╔══════════════════════════════════════════════════════════════════════════════╗\");\n            sb.AppendLine(\"║                         CAPTURED ACTIVITIES DIAGNOSTIC                       ║\");\n            sb.AppendLine(\"╠══════════════════════════════════════════════════════════════════════════════╣\");\n            sb.AppendLine($\"║ Total Activities: {activities.Count,-59}║\");\n            sb.AppendLine(\"╚══════════════════════════════════════════════════════════════════════════════╝\");\n            sb.AppendLine();\n\n            // Group by source\n            var bySource = activities.GroupBy(a => a.Source.Name).OrderBy(g => g.Key);\n\n            foreach (var sourceGroup in bySource)\n            {\n                sb.AppendLine($\"┌─ Source: {sourceGroup.Key}\");\n                sb.AppendLine(\"│\");\n\n                var sourceActivities = sourceGroup.OrderBy(a => a.StartTimeUtc).ToList();\n                for (int i = 0; i < sourceActivities.Count; i++)\n                {\n                    var activity = sourceActivities[i];\n                    var isLast = i == sourceActivities.Count - 1;\n                    var prefix = isLast ? \"└──\" : \"├──\";\n                    var continuePrefix = isLast ? \"   \" : \"│  \";\n\n                    sb.AppendLine($\"│ {prefix} [{activity.OperationName}]\");\n                    sb.AppendLine($\"│ {continuePrefix}   ID: {activity.Id ?? \"(null)\"}\");\n\n                    if (activity.ParentId is not null)\n                    {\n                        sb.AppendLine($\"│ {continuePrefix}   Parent: {activity.ParentId}\");\n                    }\n                    else\n                    {\n                        sb.AppendLine($\"│ {continuePrefix}   Parent: (root)\");\n                    }\n\n                    sb.AppendLine($\"│ {continuePrefix}   Duration: {activity.Duration.TotalMilliseconds:F2}ms\");\n                    sb.AppendLine($\"│ {continuePrefix}   Status: {activity.Status}\");\n\n                    var tags = activity.Tags.ToList();\n                    if (tags.Count > 0)\n                    {\n                        sb.AppendLine($\"│ {continuePrefix}   Tags:\");\n                        foreach (var tag in tags)\n                        {\n                            sb.AppendLine($\"│ {continuePrefix}     • {tag.Key}: {tag.Value}\");\n                        }\n                    }\n\n                    sb.AppendLine(\"│\");\n                }\n\n                sb.AppendLine();\n            }\n\n            // Print hierarchy view\n            sb.AppendLine(\"═══════════════════════════════════════════════════════════════════════════════\");\n            sb.AppendLine(\"                              ACTIVITY HIERARCHY                               \");\n            sb.AppendLine(\"═══════════════════════════════════════════════════════════════════════════════\");\n            sb.AppendLine();\n\n            var activityById = activities.Where(a => a.Id is not null).ToDictionary(a => a.Id!);\n            var roots = activities.Where(a => a.ParentId is null || !activityById.ContainsKey(a.ParentId)).ToList();\n\n            foreach (var root in roots.OrderBy(a => a.StartTimeUtc))\n            {\n                PrintActivityTree(sb, root, activityById, activities, \"\", true);\n            }\n\n            _output.WriteLine(sb.ToString());\n        }\n\n        private static void PrintActivityTree(\n            StringBuilder sb,\n            Activity activity,\n            Dictionary<string, Activity> activityById,\n            List<Activity> allActivities,\n            string indent,\n            bool isLast)\n        {\n            var marker = isLast ? \"└── \" : \"├── \";\n            var durationStr = activity.Duration.TotalMilliseconds > 0\n                ? $\" ({activity.Duration.TotalMilliseconds:F2}ms)\"\n                : \"\";\n\n            sb.AppendLine($\"{indent}{marker}[{activity.Source.Name}] {activity.OperationName}{durationStr}\");\n\n            var children = allActivities\n                .Where(a => a.ParentId == activity.Id)\n                .OrderBy(a => a.StartTimeUtc)\n                .ToList();\n\n            var childIndent = indent + (isLast ? \"    \" : \"│   \");\n\n            for (int i = 0; i < children.Count; i++)\n            {\n                PrintActivityTree(sb, children[i], activityById, allActivities, childIndent, i == children.Count - 1);\n            }\n        }\n    }\n\n    #region Test Grains for Deactivation Tracing\n\n    /// <summary>\n    /// Test grain interface for basic deactivation tracing tests.\n    /// </summary>\n    public interface IDeactivationTracingTestGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task TriggerDeactivation();\n    }\n\n    /// <summary>\n    /// Test grain implementation for basic deactivation tracing tests.\n    /// Implements a simple OnDeactivateAsync to verify the span is created.\n    /// </summary>\n    public class DeactivationTracingTestGrain : Grain, IDeactivationTracingTestGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public Task TriggerDeactivation()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // Simple deactivation logic to ensure OnDeactivateAsync is called\n            return Task.CompletedTask;\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface for deactivation tracing with work in OnDeactivateAsync.\n    /// </summary>\n    public interface IDeactivationWithWorkTracingTestGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task TriggerDeactivation();\n        Task<bool> WasDeactivated();\n    }\n\n    /// <summary>\n    /// Test grain state for tracking deactivation.\n    /// </summary>\n    [GenerateSerializer]\n    public class DeactivationWorkState\n    {\n        [Id(0)]\n        public bool WasDeactivated { get; set; }\n\n        [Id(1)]\n        public string DeactivationReason { get; set; }\n    }\n\n    /// <summary>\n    /// Test grain implementation that performs work during OnDeactivateAsync.\n    /// Uses persistent state to track that deactivation occurred.\n    /// </summary>\n    public class DeactivationWithWorkTracingTestGrain : Grain, IDeactivationWithWorkTracingTestGrain\n    {\n        private readonly IPersistentState<DeactivationWorkState> _state;\n\n        public DeactivationWithWorkTracingTestGrain(\n            [PersistentState(\"deactivationState\")] IPersistentState<DeactivationWorkState> state)\n        {\n            _state = state;\n        }\n\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public Task TriggerDeactivation()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> WasDeactivated() => Task.FromResult(_state.State.WasDeactivated);\n\n        public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // Perform work during deactivation - write state\n            _state.State.WasDeactivated = true;\n            _state.State.DeactivationReason = reason.ToString();\n            await _state.WriteStateAsync();\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface for deactivation tracing with exception in OnDeactivateAsync.\n    /// </summary>\n    public interface IDeactivationWithExceptionTracingTestGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task TriggerDeactivation();\n    }\n\n    /// <summary>\n    /// Test grain implementation that throws an exception during OnDeactivateAsync.\n    /// Used to verify that the OnDeactivate span captures errors correctly.\n    /// </summary>\n    public class DeactivationWithExceptionTracingTestGrain : Grain, IDeactivationWithExceptionTracingTestGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public Task TriggerDeactivation()\n        {\n            this.DeactivateOnIdle();\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            throw new InvalidOperationException(\"Simulated error during deactivation\");\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface for deactivation tracing with migration participant.\n    /// </summary>\n    public interface IDeactivationMigrationTracingTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask<GrainAddress> GetGrainAddress();\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n        ValueTask TriggerDeactivation();\n    }\n\n    /// <summary>\n    /// Test grain implementation that implements IGrainMigrationParticipant for deactivation tracing.\n    /// Used to verify OnDeactivate span is created before dehydration during migration.\n    /// </summary>\n    [RandomPlacement]\n    public class DeactivationMigrationTracingTestGrain : Grain, IDeactivationMigrationTracingTestGrain, IGrainMigrationParticipant\n    {\n        private int _state;\n        private bool _onDeactivateCalled;\n\n        public ValueTask<int> GetState() => new(_state);\n\n        public ValueTask SetState(int state)\n        {\n            _state = state;\n            return default;\n        }\n\n        public ValueTask TriggerDeactivation()\n        {\n            this.DeactivateOnIdle();\n            return default;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            _onDeactivateCalled = true;\n            return Task.CompletedTask;\n        }\n\n        public void OnDehydrate(IDehydrationContext migrationContext)\n        {\n            migrationContext.TryAddValue(\"state\", _state);\n            migrationContext.TryAddValue(\"onDeactivateCalled\", _onDeactivateCalled);\n        }\n\n        public void OnRehydrate(IRehydrationContext migrationContext)\n        {\n            migrationContext.TryGetValue(\"state\", out _state);\n            migrationContext.TryGetValue(\"onDeactivateCalled\", out _onDeactivateCalled);\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n\n    /// <summary>\n    /// Test grain interface for InconsistentStateException deactivation tracing tests.\n    /// </summary>\n    public interface IInconsistentStateDeactivationGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task ThrowInconsistentStateException();\n    }\n\n    /// <summary>\n    /// Test grain implementation that throws InconsistentStateException.\n    /// Used to verify OnDeactivate span is created with ApplicationError reason.\n    /// </summary>\n    public class InconsistentStateDeactivationGrain : Grain, IInconsistentStateDeactivationGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public Task ThrowInconsistentStateException()\n        {\n            throw new InconsistentStateException(\"Simulated inconsistent state for testing deactivation tracing\")\n            {\n                IsSourceActivation = true\n            };\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // Simple deactivation logic\n            return Task.CompletedTask;\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface for activation failure deactivation tracing tests.\n    /// </summary>\n    public interface IActivationFailureDeactivationGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n    }\n\n    /// <summary>\n    /// Test grain implementation that fails during activation.\n    /// Used to verify OnDeactivate span is NOT created when PreviousState != Valid.\n    /// </summary>\n    public class ActivationFailureDeactivationGrain : Grain, IActivationFailureDeactivationGrain\n    {\n        public ActivationFailureDeactivationGrain()\n        {\n            // Throw exception in constructor to fail activation\n            throw new InvalidOperationException(\"Simulated activation failure for testing deactivation tracing\");\n        }\n\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // This should never be called since activation fails\n            return Task.CompletedTask;\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface for GrainContext.Deactivate deactivation tracing tests.\n    /// </summary>\n    public interface IGrainContextDeactivationGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task DeactivateWithCustomReason(string reason);\n    }\n\n    /// <summary>\n    /// Test grain implementation that uses GrainContext.Deactivate with custom reason.\n    /// Used to verify OnDeactivate span is created with the custom reason.\n    /// </summary>\n    public class GrainContextDeactivationGrain : Grain, IGrainContextDeactivationGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public Task DeactivateWithCustomReason(string reason)\n        {\n            GrainContext.Deactivate(new DeactivationReason(DeactivationReasonCode.ApplicationRequested, reason));\n            return Task.CompletedTask;\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // Simple deactivation logic\n            return Task.CompletedTask;\n        }\n    }\n\n    #endregion\n\n    #region Test Placement Filter for Tracing\n\n    /// <summary>\n    /// Test placement filter attribute for tracing tests.\n    /// </summary>\n    public class TracingTestPlacementFilterAttribute() : PlacementFilterAttribute(new TracingTestPlacementFilterStrategy());\n\n    /// <summary>\n    /// Test placement filter strategy for tracing tests.\n    /// </summary>\n    public class TracingTestPlacementFilterStrategy() : PlacementFilterStrategy(order: 1)\n    {\n    }\n\n    /// <summary>\n    /// Test placement filter director that simply passes through all silos.\n    /// </summary>\n    public class TracingTestPlacementFilterDirector : IPlacementFilterDirector\n    {\n        public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n        {\n            return silos;\n        }\n    }\n\n    /// <summary>\n    /// Second test placement filter attribute for tracing tests with multiple filters.\n    /// </summary>\n    public class SecondTracingTestPlacementFilterAttribute() : PlacementFilterAttribute(new SecondTracingTestPlacementFilterStrategy());\n\n    /// <summary>\n    /// Second test placement filter strategy for tracing tests with multiple filters.\n    /// </summary>\n    public class SecondTracingTestPlacementFilterStrategy() : PlacementFilterStrategy(order: 2)\n    {\n    }\n\n    /// <summary>\n    /// Second test placement filter director that simply passes through all silos.\n    /// </summary>\n    public class SecondTracingTestPlacementFilterDirector : IPlacementFilterDirector\n    {\n        public IEnumerable<SiloAddress> Filter(PlacementFilterStrategy filterStrategy, PlacementTarget target, IEnumerable<SiloAddress> silos)\n        {\n            return silos;\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface with a placement filter for tracing tests.\n    /// </summary>\n    public interface IFilteredActivityGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n    }\n\n    /// <summary>\n    /// Test grain implementation with a placement filter for tracing tests.\n    /// </summary>\n    [TracingTestPlacementFilter]\n    public class FilteredActivityGrain : Grain, IFilteredActivityGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            var result = new ActivityData()\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            };\n\n            return Task.FromResult(result);\n        }\n    }\n\n    /// <summary>\n    /// Test grain interface with multiple placement filters for tracing tests.\n    /// </summary>\n    public interface IMultiFilteredActivityGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n    }\n\n    /// <summary>\n    /// Test grain implementation with multiple placement filters for tracing tests.\n    /// </summary>\n    [TracingTestPlacementFilter]\n    [SecondTracingTestPlacementFilter]\n    public class MultiFilteredActivityGrain : Grain, IMultiFilteredActivityGrain\n    {\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            var result = new ActivityData()\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            };\n\n            return Task.FromResult(result);\n        }\n    }\n\n    #endregion\n\n    #region Test Grain with Persistent State for tracing\n\n    /// <summary>\n    /// Test grain interface with persistent state for tracing tests.\n    /// </summary>\n    public interface IPersistentStateActivityGrain : IGrainWithIntegerKey\n    {\n        Task<ActivityData> GetActivityId();\n        Task<int> GetStateValue();\n    }\n\n    /// <summary>\n    /// Test grain state for persistent state tracing tests.\n    /// </summary>\n    [GenerateSerializer]\n    public class PersistentStateActivityGrainState\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    /// <summary>\n    /// Test grain implementation with persistent state for tracing tests.\n    /// </summary>\n    [TracingTestPlacementFilter]\n    public class PersistentStateActivityGrain : Grain, IPersistentStateActivityGrain\n    {\n        private readonly IPersistentState<PersistentStateActivityGrainState> _state;\n\n        public PersistentStateActivityGrain(\n            [PersistentState(\"state\")] IPersistentState<PersistentStateActivityGrainState> state)\n        {\n            _state = state;\n        }\n\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            var result = new ActivityData()\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            };\n\n            return Task.FromResult(result);\n        }\n\n        public Task<int> GetStateValue()\n        {\n            return Task.FromResult(_state.State.Value);\n        }\n    }\n\n    #endregion\n\n    #region Test Grain for Migration Tracing\n\n    /// <summary>\n    /// Test grain interface for migration tracing tests.\n    /// </summary>\n    public interface IMigrationTracingTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask<GrainAddress> GetGrainAddress();\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n    }\n\n    /// <summary>\n    /// Test grain state for migration tracing tests.\n    /// </summary>\n    [GenerateSerializer]\n    public class MigrationTracingTestGrainState\n    {\n        [Id(0)]\n        public int Value { get; set; }\n    }\n\n    /// <summary>\n    /// Test grain implementation for migration tracing tests.\n    /// Implements IGrainMigrationParticipant to participate in migration.\n    /// Uses RandomPlacement to allow migration to different silos.\n    /// </summary>\n    [RandomPlacement]\n    public class MigrationTracingTestGrain : Grain, IMigrationTracingTestGrain, IGrainMigrationParticipant\n    {\n        private int _state;\n\n        public ValueTask<int> GetState() => new(_state);\n\n        public ValueTask SetState(int state)\n        {\n            _state = state;\n            return default;\n        }\n\n        public void OnDehydrate(IDehydrationContext migrationContext)\n        {\n            migrationContext.TryAddValue(\"state\", _state);\n        }\n\n        public void OnRehydrate(IRehydrationContext migrationContext)\n        {\n            migrationContext.TryGetValue(\"state\", out _state);\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n\n    /// <summary>\n    /// Test grain interface for migration tracing tests without IGrainMigrationParticipant.\n    /// </summary>\n\n    /// <summary>\n    /// Test grain interface for migration tracing tests with a placement filter.\n    /// </summary>\n    public interface IMigrationFilterTracingTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask<GrainAddress> GetGrainAddress();\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n    }\n\n    /// <summary>\n    /// Test grain implementation for migration tracing tests with a placement filter.\n    /// Combines IGrainMigrationParticipant and a placement filter to verify that\n    /// FilterPlacementCandidates spans are properly parented under PlaceGrain during migration.\n    /// </summary>\n    [RandomPlacement]\n    [TracingTestPlacementFilter]\n    public class MigrationFilterTracingTestGrain : Grain, IMigrationFilterTracingTestGrain, IGrainMigrationParticipant\n    {\n        private int _state;\n\n        public ValueTask<int> GetState() => new(_state);\n\n        public ValueTask SetState(int state)\n        {\n            _state = state;\n            return default;\n        }\n\n        public void OnDehydrate(IDehydrationContext migrationContext)\n        {\n            migrationContext.TryAddValue(\"state\", _state);\n        }\n\n        public void OnRehydrate(IRehydrationContext migrationContext)\n        {\n            migrationContext.TryGetValue(\"state\", out _state);\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n    public interface ISimpleMigrationTracingTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask<GrainAddress> GetGrainAddress();\n        ValueTask SetState(int state);\n        ValueTask<int> GetState();\n    }\n\n    /// <summary>\n    /// Test grain implementation for migration tracing tests that does NOT implement IGrainMigrationParticipant.\n    /// Uses RandomPlacement to allow migration to different silos.\n    /// This grain will lose its state during migration since it doesn't participate in dehydration/rehydration.\n    /// </summary>\n    [RandomPlacement]\n    public class SimpleMigrationTracingTestGrain : Grain, ISimpleMigrationTracingTestGrain\n    {\n        private int _state;\n\n        public ValueTask<int> GetState() => new(_state);\n\n        public ValueTask SetState(int state)\n        {\n            _state = state;\n            return default;\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n\n    /// <summary>\n    /// Test grain interface with persistent state for migration tracing tests.\n    /// </summary>\n    public interface IMigrationPersistentStateTracingTestGrain : IGrainWithIntegerKey\n    {\n        ValueTask SetState(int a, int b);\n        ValueTask<(int A, int B)> GetState();\n        ValueTask<GrainAddress> GetGrainAddress();\n    }\n\n    /// <summary>\n    /// Test grain implementation with IPersistentState for migration tracing tests.\n    /// Uses RandomPlacement to allow migration to different silos.\n    /// </summary>\n    [RandomPlacement]\n    public class MigrationPersistentStateTracingTestGrain : Grain, IMigrationPersistentStateTracingTestGrain\n    {\n        private readonly IPersistentState<MigrationTracingTestGrainState> _stateA;\n        private readonly IPersistentState<MigrationTracingTestGrainState> _stateB;\n\n        public MigrationPersistentStateTracingTestGrain(\n            [PersistentState(\"a\")] IPersistentState<MigrationTracingTestGrainState> stateA,\n            [PersistentState(\"b\")] IPersistentState<MigrationTracingTestGrainState> stateB)\n        {\n            _stateA = stateA;\n            _stateB = stateB;\n        }\n\n        public ValueTask<(int A, int B)> GetState() => new((_stateA.State.Value, _stateB.State.Value));\n\n        public ValueTask SetState(int a, int b)\n        {\n            _stateA.State.Value = a;\n            _stateB.State.Value = b;\n            return default;\n        }\n\n        public ValueTask<GrainAddress> GetGrainAddress() => new(GrainContext.Address);\n    }\n\n    #endregion\n\n    #region Test Grain for IAsyncEnumerable with Deactivation\n\n    /// <summary>\n    /// Test grain interface for IAsyncEnumerable deactivation tracing tests.\n    /// </summary>\n    public interface IAsyncEnumerableDeactivationGrain : IGrainWithIntegerKey\n    {\n        IAsyncEnumerable<int> GetValuesAndDeactivate(int count);\n        Task<ActivityData> GetActivityId();\n    }\n\n    /// <summary>\n    /// Grain call filter that triggers deactivation after DisposeAsync is called on an async enumerable.\n    /// This ensures deactivation happens after the enumeration is fully complete.\n    /// </summary>\n    public class DeactivateAfterDisposeAsyncFilter : IIncomingGrainCallFilter\n    {\n        public async Task Invoke(IIncomingGrainCallContext context)\n        {\n            await context.Invoke();\n\n            // Check if this is the DisposeAsync call for async enumerable\n            if (context.InterfaceMethod?.Name == \"DisposeAsync\" &&\n                context.InterfaceMethod.DeclaringType?.FullName == \"Orleans.Runtime.IAsyncEnumerableGrainExtension\")\n            {\n                // Trigger deactivation on the grain\n                if (context.Grain is Grain grain)\n                {\n                    grain.DeactivateOnIdle();\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Test grain implementation that yields values via IAsyncEnumerable and then deactivates after DisposeAsync.\n    /// Uses a grain call filter to trigger deactivation after the async enumerable is disposed.\n    /// </summary>\n    public class AsyncEnumerableDeactivationGrain : Grain, IAsyncEnumerableDeactivationGrain\n    {\n        public async IAsyncEnumerable<int> GetValuesAndDeactivate(int count)\n        {\n            for (int i = 0; i < count; i++)\n            {\n                await Task.Delay(10); // Small delay to simulate work\n                yield return i;\n            }\n        }\n\n        public Task<ActivityData> GetActivityId()\n        {\n            var activity = Activity.Current;\n            if (activity is null)\n            {\n                return Task.FromResult(default(ActivityData));\n            }\n\n            return Task.FromResult(new ActivityData\n            {\n                Id = activity.Id,\n                TraceState = activity.TraceStateString,\n                Baggage = activity.Baggage.ToList(),\n            });\n        }\n\n        public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)\n        {\n            // Simple deactivation logic to ensure OnDeactivateAsync is called\n            return Task.CompletedTask;\n        }\n    }\n\n    #endregion\n\n    #region Trace Context Propagation Tests\n\n    /// <summary>\n    /// Test grain interface for verifying trace context propagation from client to grain.\n    /// Returns detailed trace information to verify the server received the correct trace context.\n    /// </summary>\n    public interface ITraceContextPropagationGrain : IGrainWithIntegerKey\n    {\n        /// <summary>\n        /// Returns detailed trace information from the server-side Activity.Current.\n        /// This allows the test to verify that trace context was properly propagated.\n        /// </summary>\n        Task<TraceContextInfo> GetTraceContextInfo();\n\n        /// <summary>\n        /// Makes a call to another grain and returns both the local and nested trace context.\n        /// Used to verify trace context propagation across grain-to-grain calls.\n        /// </summary>\n        Task<(TraceContextInfo Local, TraceContextInfo Nested)> GetNestedTraceContextInfo();\n    }\n\n    /// <summary>\n    /// Detailed trace context information returned from grain calls.\n    /// </summary>\n    [GenerateSerializer]\n    public class TraceContextInfo\n    {\n        [Id(0)]\n        public string ActivityId { get; set; }\n\n        [Id(1)]\n        public string TraceId { get; set; }\n\n        [Id(2)]\n        public string SpanId { get; set; }\n\n        [Id(3)]\n        public string ParentSpanId { get; set; }\n\n        [Id(4)]\n        public string ParentId { get; set; }\n\n        [Id(5)]\n        public string OperationName { get; set; }\n\n        [Id(6)]\n        public string TraceParentFromRequestContext { get; set; }\n\n        [Id(7)]\n        public bool HasActivity { get; set; }\n\n        [Id(8)]\n        public ActivityKind Kind { get; set; }\n\n        [Id(9)]\n        public bool IsRemote { get; set; }\n    }\n\n    /// <summary>\n    /// Test grain implementation for verifying trace context propagation.\n    /// </summary>\n    public class TraceContextPropagationGrain : Grain, ITraceContextPropagationGrain\n    {\n        public Task<TraceContextInfo> GetTraceContextInfo()\n        {\n            var activity = Activity.Current;\n            var traceParent = RequestContext.Get(\"traceparent\") as string;\n\n            return Task.FromResult(new TraceContextInfo\n            {\n                HasActivity = activity is not null,\n                ActivityId = activity?.Id,\n                TraceId = activity?.TraceId.ToString(),\n                SpanId = activity?.SpanId.ToString(),\n                ParentSpanId = activity?.ParentSpanId.ToString(),\n                ParentId = activity?.ParentId,\n                OperationName = activity?.OperationName,\n                Kind = activity?.Kind ?? ActivityKind.Internal,\n                IsRemote = activity?.HasRemoteParent ?? false,\n                TraceParentFromRequestContext = traceParent\n            });\n        }\n\n        public async Task<(TraceContextInfo Local, TraceContextInfo Nested)> GetNestedTraceContextInfo()\n        {\n            var localInfo = await GetTraceContextInfo();\n\n            // Make a nested call to another grain\n            var nestedGrain = GrainFactory.GetGrain<ITraceContextPropagationGrain>(this.GetPrimaryKeyLong() + 1);\n            var nestedInfo = await nestedGrain.GetTraceContextInfo();\n\n            return (localInfo, nestedInfo);\n        }\n    }\n\n    #endregion\n\n    /// <summary>\n    /// Tests specifically for verifying trace context propagation between client and grain server.\n    /// These tests expose issues where the server-side span starts a new trace instead of continuing the client's trace.\n    /// </summary>\n    [Collection(\"ActivationTracing\")]\n    public class GrainCallTraceContextPropagationTests : OrleansTestingBase, IClassFixture<ActivationTracingTests.Fixture>\n    {\n        private static readonly ConcurrentBag<Activity> Started = new();\n\n        static GrainCallTraceContextPropagationTests()\n        {\n            var listener = new ActivityListener\n            {\n                ShouldListenTo = src => src.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        || src.Name == ActivitySources.LifecycleActivitySourceName\n                                        || src.Name == ActivitySources.StorageActivitySourceName,\n                Sample = (ref _) => ActivitySamplingResult.AllData,\n                SampleUsingParentId = (ref _) => ActivitySamplingResult.AllData,\n                ActivityStarted = activity => Started.Add(activity),\n            };\n            ActivitySource.AddActivityListener(listener);\n        }\n\n        private readonly ActivationTracingTests.Fixture _fixture;\n        private readonly ITestOutputHelper _output;\n\n        public GrainCallTraceContextPropagationTests(ActivationTracingTests.Fixture fixture, ITestOutputHelper output)\n        {\n            _fixture = fixture;\n            _output = output;\n        }\n\n        /// <summary>\n        /// CRITICAL TEST: Verifies that the server-side grain call activity has the same TraceId as the client.\n        /// This test fails if trace context propagation is broken - the server will start a new trace instead\n        /// of continuing the client's trace.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ServerSideGrainCallSharesSameTraceIdAsClient()\n        {\n            Started.Clear();\n\n            // Start a parent activity on the client side\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-parent-activity\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n            var clientSpanId = clientActivity.SpanId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n            _output.WriteLine($\"Client SpanId: {clientSpanId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n\n                // This call should propagate the trace context to the server\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n                _output.WriteLine($\"Server SpanId: {serverTraceInfo.SpanId}\");\n                _output.WriteLine($\"Server ParentSpanId: {serverTraceInfo.ParentSpanId}\");\n                _output.WriteLine($\"Server ParentId: {serverTraceInfo.ParentId}\");\n                _output.WriteLine($\"Server OperationName: {serverTraceInfo.OperationName}\");\n                _output.WriteLine($\"Server Kind: {serverTraceInfo.Kind}\");\n                _output.WriteLine($\"Server IsRemote: {serverTraceInfo.IsRemote}\");\n                _output.WriteLine($\"Server TraceParentFromRequestContext: {serverTraceInfo.TraceParentFromRequestContext}\");\n\n                // CRITICAL ASSERTION: Server must have an activity\n                Assert.True(serverTraceInfo.HasActivity, \"Server-side grain call should have an Activity.Current\");\n\n                // CRITICAL ASSERTION: Server TraceId must match client TraceId\n                // If this fails, trace context propagation is broken!\n                Assert.Equal(clientTraceId, serverTraceInfo.TraceId);\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that the server-side activity is a Server kind and has a remote parent.\n        /// This confirms proper W3C trace context handling.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ServerSideActivityHasCorrectKindAndRemoteParent()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-activity-kind-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server Kind: {serverTraceInfo.Kind}\");\n                _output.WriteLine($\"Server IsRemote: {serverTraceInfo.IsRemote}\");\n\n                Assert.True(serverTraceInfo.HasActivity, \"Server-side grain call should have an Activity.Current\");\n\n                // Server-side activity should be of kind Server\n                Assert.Equal(ActivityKind.Server, serverTraceInfo.Kind);\n\n                // Server-side activity should have a remote parent (propagated from client)\n                Assert.True(serverTraceInfo.IsRemote, \"Server-side activity should have HasRemoteParent=true\");\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies trace context propagation across nested grain-to-grain calls.\n        /// All calls in the chain should share the same TraceId.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task NestedGrainCallsShareSameTraceId()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-nested-calls-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var (localInfo, nestedInfo) = await grain.GetNestedTraceContextInfo();\n\n                _output.WriteLine($\"First Grain TraceId: {localInfo.TraceId}\");\n                _output.WriteLine($\"Nested Grain TraceId: {nestedInfo.TraceId}\");\n\n                // Both grains should have activities\n                Assert.True(localInfo.HasActivity, \"First grain should have an Activity.Current\");\n                Assert.True(nestedInfo.HasActivity, \"Nested grain should have an Activity.Current\");\n\n                // CRITICAL: All calls should share the same TraceId\n                Assert.Equal(clientTraceId, localInfo.TraceId);\n                Assert.Equal(clientTraceId, nestedInfo.TraceId);\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that traceparent header is properly set in RequestContext when making grain calls.\n        /// This tests the outgoing filter's injection of trace context.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceParentIsSetInRequestContext()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-traceparent-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server TraceParentFromRequestContext: {serverTraceInfo.TraceParentFromRequestContext}\");\n\n                // traceparent header should be present in RequestContext\n                Assert.NotNull(serverTraceInfo.TraceParentFromRequestContext);\n                Assert.NotEmpty(serverTraceInfo.TraceParentFromRequestContext);\n\n                // traceparent should contain the client's TraceId\n                Assert.Contains(clientTraceId, serverTraceInfo.TraceParentFromRequestContext);\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that the client-side outgoing span and server-side incoming span are properly linked.\n        /// The server span's parent should be the client's outgoing span.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ClientAndServerSpansAreProperlyLinked()\n        {\n            Started.Clear();\n\n            using var clientParentActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-linking-test\");\n            clientParentActivity?.Start();\n\n            Assert.NotNull(clientParentActivity);\n            var clientTraceId = clientParentActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client Parent TraceId: {clientTraceId}\");\n            _output.WriteLine($\"Client Parent SpanId: {clientParentActivity.SpanId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                _ = await grain.GetTraceContextInfo();\n\n                // Find the client-side outgoing span (should be a child of our test activity)\n                var clientOutgoingSpan = Started\n                    .Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                               && a.Kind == ActivityKind.Client\n                               && a.OperationName.Contains(\"GetTraceContextInfo\"))\n                    .FirstOrDefault();\n\n                // Find the server-side incoming span\n                var serverIncomingSpan = Started\n                    .Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                               && a.Kind == ActivityKind.Server\n                               && a.OperationName.Contains(\"GetTraceContextInfo\"))\n                    .FirstOrDefault();\n\n                _output.WriteLine($\"Client Outgoing Span: {clientOutgoingSpan?.Id ?? \"(not found)\"}\");\n                _output.WriteLine($\"Server Incoming Span: {serverIncomingSpan?.Id ?? \"(not found)\"}\");\n\n                Assert.NotNull(clientOutgoingSpan);\n                Assert.NotNull(serverIncomingSpan);\n\n                // Both should share the same TraceId\n                Assert.Equal(clientTraceId, clientOutgoingSpan.TraceId.ToString());\n                Assert.Equal(clientTraceId, serverIncomingSpan.TraceId.ToString());\n\n                // Client outgoing span should be parented to our test activity\n                Assert.Equal(clientParentActivity.SpanId.ToString(), clientOutgoingSpan.ParentSpanId.ToString());\n\n                // Server span's parent should be the client outgoing span\n                Assert.Equal(clientOutgoingSpan.SpanId.ToString(), serverIncomingSpan.ParentSpanId.ToString());\n            }\n            finally\n            {\n                clientParentActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that trace context is properly propagated even when the client has no active activity.\n        /// The server should still create its own trace in this case.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ServerCreatesOwnTraceWhenClientHasNoActivity()\n        {\n            Started.Clear();\n\n            // Ensure no activity is current on the client\n            var previousActivity = Activity.Current;\n            Activity.Current = null;\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n\n                // Server should still create an activity (starting a new trace)\n                Assert.True(serverTraceInfo.HasActivity, \"Server should create an activity even when client has none\");\n                Assert.NotNull(serverTraceInfo.TraceId);\n                Assert.NotEmpty(serverTraceInfo.TraceId);\n            }\n            finally\n            {\n                Activity.Current = previousActivity;\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that multiple concurrent grain calls from the same client activity\n        /// all share the same TraceId.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ConcurrentGrainCallsShareSameTraceId()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-concurrent-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                var tasks = Enumerable.Range(0, 5)\n                    .Select(i => _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next()).GetTraceContextInfo())\n                    .ToList();\n\n                var results = await Task.WhenAll(tasks);\n\n                foreach (var (result, index) in results.Select((r, i) => (r, i)))\n                {\n                    _output.WriteLine($\"Grain {index} TraceId: {result.TraceId}\");\n\n                    Assert.True(result.HasActivity, $\"Grain {index} should have an Activity.Current\");\n                    Assert.Equal(clientTraceId, result.TraceId);\n                }\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// EDGE CASE: Tests trace context propagation when the traceparent header contains an unexpected format.\n        /// The server should handle malformed headers gracefully and still create an activity.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ServerHandlesMalformedTraceParentGracefully()\n        {\n            Started.Clear();\n\n            // Manually set an invalid traceparent in RequestContext\n            RequestContext.Set(\"traceparent\", \"invalid-traceparent-value\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n                _output.WriteLine($\"Server TraceParentFromRequestContext: {serverTraceInfo.TraceParentFromRequestContext}\");\n\n                // Server should still have an activity (creating a new trace)\n                Assert.True(serverTraceInfo.HasActivity, \"Server should create an activity even with malformed traceparent\");\n                Assert.NotNull(serverTraceInfo.TraceId);\n            }\n            finally\n            {\n                RequestContext.Clear();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that the traceparent in RequestContext reflects the client's outgoing span,\n        /// not the original parent activity. This verifies proper span creation on the client side.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceParentReflectsClientOutgoingSpan()\n        {\n            Started.Clear();\n\n            using var clientParentActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-traceparent-reflection-test\");\n            clientParentActivity?.Start();\n\n            Assert.NotNull(clientParentActivity);\n            var clientTraceId = clientParentActivity.TraceId.ToString();\n            var clientParentSpanId = clientParentActivity.SpanId.ToString();\n\n            _output.WriteLine($\"Client Parent TraceId: {clientTraceId}\");\n            _output.WriteLine($\"Client Parent SpanId: {clientParentSpanId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server TraceParentFromRequestContext: {serverTraceInfo.TraceParentFromRequestContext}\");\n                _output.WriteLine($\"Server ParentSpanId: {serverTraceInfo.ParentSpanId}\");\n\n                Assert.NotNull(serverTraceInfo.TraceParentFromRequestContext);\n\n                // The traceparent should contain the TraceId\n                Assert.Contains(clientTraceId, serverTraceInfo.TraceParentFromRequestContext);\n\n                // The server's parent span ID should NOT be the original client parent span ID\n                // It should be the span ID of the client's outgoing call span\n                // (This is because the client creates a new span for the outgoing call)\n                Assert.NotEqual(clientParentSpanId, serverTraceInfo.ParentSpanId);\n\n                // Find the client outgoing span\n                var clientOutgoingSpan = Started\n                    .FirstOrDefault(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        && a.Kind == ActivityKind.Client\n                                        && a.OperationName.Contains(\"GetTraceContextInfo\"));\n\n                Assert.NotNull(clientOutgoingSpan);\n\n                // The server's parent span ID should match the client outgoing span ID\n                Assert.Equal(clientOutgoingSpan.SpanId.ToString(), serverTraceInfo.ParentSpanId);\n\n                // The traceparent should contain the client outgoing span ID\n                Assert.Contains(clientOutgoingSpan.SpanId.ToString(), serverTraceInfo.TraceParentFromRequestContext);\n            }\n            finally\n            {\n                clientParentActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests trace context propagation when making calls from within a grain's OnActivateAsync.\n        /// This is a common edge case where activation might not have a proper trace context.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceContextIsPropagatedDuringActivation()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-activation-context-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                // Make a call that triggers activation\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server TraceId (during activation): {serverTraceInfo.TraceId}\");\n\n                // Verify the trace ID matches\n                Assert.Equal(clientTraceId, serverTraceInfo.TraceId);\n\n                // Find the activation span\n                var activationSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"Activation Span TraceId: {activationSpan.TraceId}\");\n                    // The activation span should also share the same trace ID\n                    Assert.Equal(clientTraceId, activationSpan.TraceId.ToString());\n                }\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests that tracestate header is properly propagated along with traceparent.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceStateIsPropagatedWithTraceParent()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-tracestate-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n\n            // Set a tracestate on the client activity\n            clientActivity.TraceStateString = \"vendor1=value1,vendor2=value2\";\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                // Find the server span\n                var serverSpan = Started\n                    .FirstOrDefault(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        && a.Kind == ActivityKind.Server\n                                        && a.OperationName.Contains(\"GetTraceContextInfo\"));\n\n                _output.WriteLine($\"Server Span TraceState: {serverSpan?.TraceStateString ?? \"(null)\"}\");\n\n                // The tracestate should be propagated to the server\n                // Note: This test may need adjustment based on how Orleans handles tracestate\n                if (serverSpan is not null && !string.IsNullOrEmpty(serverSpan.TraceStateString))\n                {\n                    Assert.Contains(\"vendor1\", serverSpan.TraceStateString);\n                }\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// CRITICAL TEST: Verifies that when a grain call triggers activation, the activation span\n        /// shares the same TraceId as the grain call and is properly linked in the trace.\n        /// \n        /// This test reproduces the production issue where the activation span starts a new trace\n        /// instead of being part of the incoming grain call's trace.\n        /// \n        /// Expected trace structure:\n        ///   client-parent-activity\n        ///     └── ITraceContextPropagationGrain/GetTraceContextInfo (Client, outgoing)\n        ///           └── ITraceContextPropagationGrain/GetTraceContextInfo (Server, incoming) \n        ///                 └── activate grain (should be linked to this trace!)\n        ///                       ├── register directory entry\n        ///                       └── execute OnActivateAsync\n        /// \n        /// Bug scenario (what we're testing for):\n        ///   activate grain (NEW TRACE - disconnected from client!)  <-- THIS IS THE BUG\n        ///     ├── register directory entry\n        ///     └── execute OnActivateAsync\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationSpanSharesTraceIdWithTriggeringGrainCall()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-activation-trace-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                // Use a unique grain ID to ensure we trigger a new activation\n                var uniqueGrainId = Random.Shared.Next();\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(uniqueGrainId);\n\n                // This call will trigger activation since it's a new grain\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n\n                // Find the activation span\n                var activationSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n\n                _output.WriteLine($\"Activation Span found: {activationSpan is not null}\");\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"Activation Span TraceId: {activationSpan.TraceId}\");\n                    _output.WriteLine($\"Activation Span ParentSpanId: {activationSpan.ParentSpanId}\");\n                    _output.WriteLine($\"Activation Span ParentId: {activationSpan.ParentId}\");\n                }\n\n                // CRITICAL ASSERTION: Activation span must exist\n                Assert.NotNull(activationSpan);\n\n                // CRITICAL ASSERTION: Activation span must share the same TraceId as the client\n                // If this fails, the activation is starting a new trace instead of being part\n                // of the incoming grain call's trace!\n                Assert.Equal(clientTraceId, activationSpan.TraceId.ToString());\n\n                // CRITICAL ASSERTION: Activation span should have a parent (not be a root span)\n                // In the bug scenario, the activation span has no parent and starts a new trace\n                Assert.False(\n                    string.IsNullOrEmpty(activationSpan.ParentId),\n                    \"Activation span should have a parent! If this fails, the activation is starting a new trace.\");\n\n                // Verify the grain call span also shares the same trace ID\n                Assert.Equal(clientTraceId, serverTraceInfo.TraceId);\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Verifies that when activation is triggered by a grain call, the entire trace hierarchy is correct:\n        /// 1. Client outgoing span\n        /// 2. Server incoming grain call span (parented to client outgoing)\n        /// 3. Activation span (should share trace context with the grain call)\n        /// 4. OnActivateAsync span (parented to activation span)\n        /// \n        /// This test checks the full hierarchy to ensure no span is disconnected.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task FullTraceHierarchyIsCorrectWhenActivationTriggeredByGrainCall()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-hierarchy-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n            var clientSpanId = clientActivity.SpanId.ToString();\n\n            _output.WriteLine($\"=== TEST START ===\");\n            _output.WriteLine($\"Client Activity TraceId: {clientTraceId}\");\n            _output.WriteLine($\"Client Activity SpanId: {clientSpanId}\");\n\n            try\n            {\n                // Use a grain type that has OnActivateAsync to ensure we get all spans\n                var grain = _fixture.GrainFactory.GetGrain<IFilteredActivityGrain>(Random.Shared.Next());\n                _ = await grain.GetActivityId();\n\n                _output.WriteLine($\"\\n=== SPAN ANALYSIS ===\");\n\n                // 1. Find client outgoing span\n                var clientOutgoingSpan = Started\n                    .FirstOrDefault(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        && a.Kind == ActivityKind.Client\n                                        && a.OperationName.Contains(\"GetActivityId\"));\n\n                _output.WriteLine($\"\\n1. Client Outgoing Span:\");\n                if (clientOutgoingSpan is not null)\n                {\n                    _output.WriteLine($\"   TraceId: {clientOutgoingSpan.TraceId}\");\n                    _output.WriteLine($\"   SpanId: {clientOutgoingSpan.SpanId}\");\n                    _output.WriteLine($\"   ParentSpanId: {clientOutgoingSpan.ParentSpanId}\");\n                    _output.WriteLine($\"   ParentId: {clientOutgoingSpan.ParentId}\");\n                }\n                else\n                {\n                    _output.WriteLine($\"   NOT FOUND!\");\n                }\n\n                // 2. Find server incoming span\n                var serverIncomingSpan = Started\n                    .FirstOrDefault(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        && a.Kind == ActivityKind.Server\n                                        && a.OperationName.Contains(\"GetActivityId\"));\n\n                _output.WriteLine($\"\\n2. Server Incoming Span:\");\n                if (serverIncomingSpan is not null)\n                {\n                    _output.WriteLine($\"   TraceId: {serverIncomingSpan.TraceId}\");\n                    _output.WriteLine($\"   SpanId: {serverIncomingSpan.SpanId}\");\n                    _output.WriteLine($\"   ParentSpanId: {serverIncomingSpan.ParentSpanId}\");\n                    _output.WriteLine($\"   ParentId: {serverIncomingSpan.ParentId}\");\n                }\n                else\n                {\n                    _output.WriteLine($\"   NOT FOUND!\");\n                }\n\n                // 3. Find activation span\n                var activationSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n\n                _output.WriteLine($\"\\n3. Activation Span:\");\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"   TraceId: {activationSpan.TraceId}\");\n                    _output.WriteLine($\"   SpanId: {activationSpan.SpanId}\");\n                    _output.WriteLine($\"   ParentSpanId: {activationSpan.ParentSpanId}\");\n                    _output.WriteLine($\"   ParentId: {activationSpan.ParentId ?? \"(null - ROOT SPAN!)\"}\");\n                }\n                else\n                {\n                    _output.WriteLine($\"   NOT FOUND!\");\n                }\n\n                // 4. Find OnActivateAsync span\n                var onActivateSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.OnActivate);\n\n                _output.WriteLine($\"\\n4. OnActivateAsync Span:\");\n                if (onActivateSpan is not null)\n                {\n                    _output.WriteLine($\"   TraceId: {onActivateSpan.TraceId}\");\n                    _output.WriteLine($\"   SpanId: {onActivateSpan.SpanId}\");\n                    _output.WriteLine($\"   ParentSpanId: {onActivateSpan.ParentSpanId}\");\n                    _output.WriteLine($\"   ParentId: {onActivateSpan.ParentId}\");\n                }\n                else\n                {\n                    _output.WriteLine($\"   NOT FOUND (grain may not implement IGrainBase)\");\n                }\n\n                // ASSERTIONS\n                _output.WriteLine($\"\\n=== ASSERTIONS ===\");\n\n                // All spans should share the same TraceId\n                Assert.NotNull(clientOutgoingSpan);\n                Assert.NotNull(serverIncomingSpan);\n                Assert.NotNull(activationSpan);\n\n                _output.WriteLine($\"Checking all spans share TraceId {clientTraceId}...\");\n\n                Assert.Equal(clientTraceId, clientOutgoingSpan.TraceId.ToString());\n                _output.WriteLine($\"  ✓ Client outgoing span has correct TraceId\");\n\n                Assert.Equal(clientTraceId, serverIncomingSpan.TraceId.ToString());\n                _output.WriteLine($\"  ✓ Server incoming span has correct TraceId\");\n\n                // THIS IS THE CRITICAL CHECK - activation span must share the trace ID!\n                Assert.Equal(clientTraceId, activationSpan.TraceId.ToString());\n                _output.WriteLine($\"  ✓ Activation span has correct TraceId\");\n\n                // Client outgoing span should be parented to our test activity\n                Assert.Equal(clientSpanId, clientOutgoingSpan.ParentSpanId.ToString());\n                _output.WriteLine($\"  ✓ Client outgoing span is parented to test activity\");\n\n                // Server incoming span should be parented to client outgoing span\n                Assert.Equal(clientOutgoingSpan.SpanId.ToString(), serverIncomingSpan.ParentSpanId.ToString());\n                _output.WriteLine($\"  ✓ Server incoming span is parented to client outgoing span\");\n\n                // Activation span should have a parent (not be a root span)\n                Assert.False(\n                    string.IsNullOrEmpty(activationSpan.ParentId),\n                    \"Activation span should not be a root span! This indicates broken trace context propagation.\");\n                _output.WriteLine($\"  ✓ Activation span has a parent (not a root span)\");\n\n                if (onActivateSpan is not null)\n                {\n                    Assert.Equal(clientTraceId, onActivateSpan.TraceId.ToString());\n                    _output.WriteLine($\"  ✓ OnActivateAsync span has correct TraceId\");\n\n                    Assert.Equal(activationSpan.SpanId.ToString(), onActivateSpan.ParentSpanId.ToString());\n                    _output.WriteLine($\"  ✓ OnActivateAsync span is parented to activation span\");\n                }\n\n                _output.WriteLine($\"\\n=== ALL CHECKS PASSED ===\");\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Diagnostic test that checks if the traceparent is properly present in the message's\n        /// RequestContextData when it reaches the server. This helps diagnose production issues\n        /// where trace context might not be propagating.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task DiagnoseTraceContextInRequestContextData()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-diagnostic-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine($\"=== DIAGNOSTIC TEST ===\");\n            _output.WriteLine($\"Client Activity TraceId: {clientTraceId}\");\n            _output.WriteLine($\"Client Activity SpanId: {clientActivity.SpanId}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"\\n=== Server-side RequestContext Analysis ===\");\n                _output.WriteLine($\"TraceParent from RequestContext: {serverTraceInfo.TraceParentFromRequestContext ?? \"(NULL or MISSING!)\"}\");\n                _output.WriteLine($\"Server Activity TraceId: {serverTraceInfo.TraceId ?? \"(NULL!)\"}\");\n                _output.WriteLine($\"Server Activity ParentSpanId: {serverTraceInfo.ParentSpanId ?? \"(NULL!)\"}\");\n                _output.WriteLine($\"Server Activity HasRemoteParent: {serverTraceInfo.IsRemote}\");\n\n                // DIAGNOSTIC ASSERTIONS\n                if (string.IsNullOrEmpty(serverTraceInfo.TraceParentFromRequestContext))\n                {\n                    _output.WriteLine(\"\\n⚠️ WARNING: traceparent is NOT present in RequestContext!\");\n                    _output.WriteLine(\"This would cause activation spans to start a new trace.\");\n                    _output.WriteLine(\"Check that AddActivityPropagation() is called on both client and silo.\");\n                }\n                else\n                {\n                    _output.WriteLine($\"\\n✓ traceparent IS present in RequestContext\");\n\n                    // Parse and validate the traceparent format\n                    var parts = serverTraceInfo.TraceParentFromRequestContext.Split('-');\n                    if (parts.Length >= 3)\n                    {\n                        var version = parts[0];\n                        var traceId = parts[1];\n                        var parentId = parts[2];\n\n                        _output.WriteLine($\"  Version: {version}\");\n                        _output.WriteLine($\"  TraceId: {traceId}\");\n                        _output.WriteLine($\"  ParentSpanId: {parentId}\");\n\n                        Assert.Equal(clientTraceId, traceId);\n                        _output.WriteLine($\"  ✓ TraceId matches client's TraceId\");\n                    }\n                }\n\n                // The traceparent should be present\n                Assert.NotNull(serverTraceInfo.TraceParentFromRequestContext);\n                Assert.NotEmpty(serverTraceInfo.TraceParentFromRequestContext);\n                Assert.Contains(clientTraceId, serverTraceInfo.TraceParentFromRequestContext);\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// CRITICAL TEST: Simulates a scenario where the calling code has no active Activity.\n        /// In this case, the ActivityPropagationOutgoingGrainCallFilter's StartActivity will return null\n        /// (because there's no parent activity and potentially no listener), and no traceparent will be injected.\n        /// \n        /// This test verifies that when a grain call is made without an active Activity,\n        /// the activation span will NOT have a parent and will start a new trace.\n        /// \n        /// This reproduces the production issue where:\n        /// - `activate grain` span has empty parentSpanId\n        /// - The trace appears disconnected from the originating call\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationStartsNewTraceWhenCallerHasNoActivity()\n        {\n            Started.Clear();\n\n            // Ensure no Activity is current\n            var previousActivity = Activity.Current;\n            Activity.Current = null;\n\n            try\n            {\n                _output.WriteLine(\"=== TEST: Calling grain with NO Activity.Current ===\");\n                _output.WriteLine($\"Activity.Current before call: {Activity.Current?.Id ?? \"(null)\"}\");\n\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"\\n=== Server Response ===\");\n                _output.WriteLine($\"Server TraceParent from RequestContext: {serverTraceInfo.TraceParentFromRequestContext ?? \"(NULL - this is the bug!)\"}\");\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n\n                // Find the activation span\n                var activationSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n\n                _output.WriteLine($\"\\n=== Activation Span Analysis ===\");\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"Activation Span TraceId: {activationSpan.TraceId}\");\n                    _output.WriteLine($\"Activation Span ParentId: {activationSpan.ParentId ?? \"(NULL - ROOT SPAN!)\"}\");\n                    _output.WriteLine($\"Activation Span ParentSpanId: {activationSpan.ParentSpanId}\");\n\n                    // When there's no caller activity, the activation span should have no parent\n                    // This is the scenario that matches the production trace\n                    if (string.IsNullOrEmpty(activationSpan.ParentId))\n                    {\n                        _output.WriteLine(\"\\n⚠️ EXPECTED BEHAVIOR: Activation span is a ROOT span (no parent)\");\n                        _output.WriteLine(\"This matches the production issue where activate grain has empty parentSpanId\");\n                    }\n                }\n                else\n                {\n                    _output.WriteLine(\"Activation span NOT FOUND\");\n                }\n\n                // Document the expected behavior: without a caller activity, traceparent won't be in RequestContext\n                // and the activation will start a new trace\n                if (string.IsNullOrEmpty(serverTraceInfo.TraceParentFromRequestContext))\n                {\n                    _output.WriteLine(\"\\n✓ CONFIRMED: traceparent is NOT in RequestContext when caller has no Activity\");\n                    _output.WriteLine(\"This causes the activation span to start a new trace (no parent)\");\n                }\n            }\n            finally\n            {\n                Activity.Current = previousActivity;\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Tests what happens when a grain call is made from within another grain that has no activity context.\n        /// This simulates scenarios like:\n        /// - Grain timers triggering calls\n        /// - Reminder callbacks making grain calls\n        /// - Stream subscription handlers\n        /// - Background processing in grains\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task GrainToGrainCallWithoutActivityContext()\n        {\n            Started.Clear();\n\n            // First, activate a grain that will make a nested call\n            // We start with an activity to ensure the first grain is activated with proper context\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"setup-activity\");\n            clientActivity?.Start();\n\n            var callerGrain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n            \n            // First call to ensure the grain is activated\n            _ = await callerGrain.GetTraceContextInfo();\n            \n            clientActivity?.Stop();\n            Activity.Current = null;\n            Started.Clear();\n\n            _output.WriteLine(\"=== TEST: Grain-to-grain call with no ambient activity ===\");\n\n            try\n            {\n                // Now make another call - the grain is already activated\n                // But if this call triggers a nested call within the grain, \n                // and there's no Activity.Current, the nested call won't have trace context\n                var result = await callerGrain.GetNestedTraceContextInfo();\n\n                _output.WriteLine($\"Caller grain TraceId: {result.Local.TraceId}\");\n                _output.WriteLine($\"Nested grain TraceId: {result.Nested.TraceId}\");\n\n                // Both should have activities (server creates one even without traceparent)\n                Assert.True(result.Local.HasActivity);\n                Assert.True(result.Nested.HasActivity);\n\n                // But they should share the same trace because grain-to-grain calls preserve context\n                Assert.Equal(result.Local.TraceId, result.Nested.TraceId);\n            }\n            finally\n            {\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// CRITICAL TEST: This test reproduces the exact production issue where:\n        /// - OpenTelemetry is configured to listen to Microsoft.Orleans.Lifecycle (for activation spans)\n        /// - But NOT listening to Microsoft.Orleans.Application (for grain call spans)\n        /// \n        /// When this happens:\n        /// 1. Client makes a grain call\n        /// 2. ActivityPropagationOutgoingGrainCallFilter tries to start an activity on ApplicationGrainSource\n        /// 3. StartActivity returns NULL because there's no listener for that source\n        /// 4. No traceparent is injected into RequestContext\n        /// 5. Server receives message with no traceparent\n        /// 6. Catalog.GetOrCreateActivation starts activation span with no parent\n        /// 7. The activation span becomes a ROOT span (disconnected from the original trace)\n        /// \n        /// Expected trace in production (BUG):\n        ///   activate grain (NO PARENT - starts new trace!)\n        ///     ├── register directory entry\n        ///     └── execute OnActivateAsync\n        /// \n        /// This test verifies that if Application source isn't being sampled,\n        /// the activation span will have no parent.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task ActivationSpanHasNoParentWhenApplicationSourceNotSampled()\n        {\n            // This test documents the expected behavior when only Lifecycle source is sampled\n            // In our test fixture, we DO sample Application source, so this test verifies correct behavior\n            // In production, if Application source is NOT sampled, the activation will be a root span\n            \n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"client-sampling-test\");\n            clientActivity?.Start();\n\n            _output.WriteLine(\"=== TEST: Verifying sampling behavior ===\");\n            _output.WriteLine($\"Client Activity created: {clientActivity is not null}\");\n            _output.WriteLine($\"Client Activity ID: {clientActivity?.Id}\");\n\n            if (clientActivity is null)\n            {\n                _output.WriteLine(\"\\n⚠️ CLIENT ACTIVITY IS NULL!\");\n                _output.WriteLine(\"This means Microsoft.Orleans.Application source is NOT being sampled.\");\n                _output.WriteLine(\"The ActivityPropagationOutgoingGrainCallFilter will NOT inject traceparent.\");\n                _output.WriteLine(\"This causes activation spans to start new traces (no parent).\");\n            }\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"\\n=== Results ===\");\n                _output.WriteLine($\"Server has traceparent in RequestContext: {!string.IsNullOrEmpty(serverTraceInfo.TraceParentFromRequestContext)}\");\n                _output.WriteLine($\"Server TraceParent: {serverTraceInfo.TraceParentFromRequestContext ?? \"(NULL)\"}\");\n\n                // Find spans by source\n                var applicationSpans = Started.Where(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName).ToList();\n                var lifecycleSpans = Started.Where(a => a.Source.Name == ActivitySources.LifecycleActivitySourceName).ToList();\n\n                _output.WriteLine($\"\\n=== Spans by Source ===\");\n                _output.WriteLine($\"Microsoft.Orleans.Application spans: {applicationSpans.Count}\");\n                foreach (var span in applicationSpans)\n                {\n                    _output.WriteLine($\"  - {span.OperationName} (Kind: {span.Kind})\");\n                }\n                _output.WriteLine($\"Microsoft.Orleans.Lifecycle spans: {lifecycleSpans.Count}\");\n                foreach (var span in lifecycleSpans)\n                {\n                    _output.WriteLine($\"  - {span.OperationName} (ParentId: {span.ParentId ?? \"NULL - ROOT\"})\");\n                }\n\n                // Find the client outgoing span\n                var clientOutgoingSpan = Started\n                    .FirstOrDefault(a => a.Source.Name == ActivitySources.ApplicationGrainActivitySourceName\n                                        && a.Kind == ActivityKind.Client);\n\n                _output.WriteLine($\"\\n=== Key Finding ===\");\n                if (clientOutgoingSpan is null && applicationSpans.Count == 0)\n                {\n                    _output.WriteLine(\"⚠️ No Application source spans found!\");\n                    _output.WriteLine(\"If this happens in production (no listener for Application source),\");\n                    _output.WriteLine(\"the activation span will have no parent.\");\n                }\n\n                // In our test environment, Application source IS sampled, so we should have spans\n                Assert.NotNull(clientActivity);\n                Assert.True(applicationSpans.Count > 0, \n                    \"Application source spans should exist. In production, verify Microsoft.Orleans.Application is in your TracerProvider sources.\");\n            }\n            finally\n            {\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// Diagnostic test that checks if all Orleans ActivitySources are being properly sampled.\n        /// Run this to verify your OpenTelemetry configuration includes all necessary sources.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task DiagnoseActivitySourceSampling()\n        {\n            Started.Clear();\n\n            _output.WriteLine(\"=== Checking ActivitySource Sampling ===\\n\");\n\n            // Test each Orleans ActivitySource\n            var sourcesToTest = new[]\n            {\n                (ActivitySources.ApplicationGrainSource, \"Microsoft.Orleans.Application\"),\n                (ActivitySources.RuntimeGrainSource, \"Microsoft.Orleans.Runtime\"),\n                (ActivitySources.LifecycleGrainSource, \"Microsoft.Orleans.Lifecycle\"),\n                (ActivitySources.StorageGrainSource, \"Microsoft.Orleans.Storage\"),\n            };\n\n            foreach (var (source, name) in sourcesToTest)\n            {\n                var testActivity = source.StartActivity($\"test-{name}\", ActivityKind.Internal);\n                var isSampled = testActivity is not null;\n                _output.WriteLine($\"{name}: {(isSampled ? \"✓ SAMPLED\" : \"✗ NOT SAMPLED\")}\");\n                testActivity?.Stop();\n            }\n\n            _output.WriteLine(\"\\n=== Implications ===\");\n            _output.WriteLine(\"For proper trace propagation, you need to sample:\");\n            _output.WriteLine(\"  - Microsoft.Orleans.Application (for grain call spans)\");\n            _output.WriteLine(\"  - Microsoft.Orleans.Lifecycle (for activation/deactivation spans)\");\n            _output.WriteLine(\"\\nIf Application is NOT sampled but Lifecycle IS:\");\n            _output.WriteLine(\"  - Grain call spans won't be created\");\n            _output.WriteLine(\"  - traceparent won't be injected into messages\");\n            _output.WriteLine(\"  - Activation spans will start new traces (no parent)\");\n\n            // Make an actual grain call to verify end-to-end\n            _output.WriteLine(\"\\n=== End-to-End Test ===\");\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"e2e-test\");\n            if (clientActivity is null)\n            {\n                _output.WriteLine(\"⚠️ Could not create client activity - Application source not sampled!\");\n            }\n            else\n            {\n                clientActivity.Start();\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var info = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"Server received traceparent: {!string.IsNullOrEmpty(info.TraceParentFromRequestContext)}\");\n                \n                var activationSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"Activation span has parent: {!string.IsNullOrEmpty(activationSpan.ParentId)}\");\n                    if (string.IsNullOrEmpty(activationSpan.ParentId))\n                    {\n                        _output.WriteLine(\"⚠️ BUG: Activation span is a root span!\");\n                    }\n                }\n\n                clientActivity.Stop();\n            }\n\n            PrintActivityDiagnostics();\n        }\n\n        /// <summary>\n        /// CRITICAL TEST: Simulates a call from an ASP.NET HTTP request handler.\n        /// In production, grain calls often originate from HTTP endpoints where:\n        /// 1. ASP.NET creates an HTTP activity (e.g., \"GET /api/users/{id}\")\n        /// 2. The controller calls a grain\n        /// 3. Orleans should propagate the HTTP trace context to the grain\n        /// \n        /// This test verifies that if Activity.Current exists (from HTTP/ASP.NET),\n        /// Orleans properly propagates it to the grain call and activation spans.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceContextPropagatedFromHttpActivityToGrainCall()\n        {\n            Started.Clear();\n\n            // Simulate an ASP.NET HTTP activity (different source than Orleans)\n            using var httpActivitySource = new ActivitySource(\"Microsoft.AspNetCore\", \"1.0.0\");\n            var httpListener = new ActivityListener\n            {\n                ShouldListenTo = src => src.Name == \"Microsoft.AspNetCore\",\n                Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllDataAndRecorded,\n            };\n            ActivitySource.AddActivityListener(httpListener);\n\n            using var httpActivity = httpActivitySource.StartActivity(\"GET /api/users/{id}\", ActivityKind.Server);\n            httpActivity?.Start();\n\n            Assert.NotNull(httpActivity);\n            var httpTraceId = httpActivity.TraceId.ToString();\n\n            _output.WriteLine(\"=== TEST: HTTP to Grain call trace propagation ===\");\n            _output.WriteLine($\"HTTP Activity TraceId: {httpTraceId}\");\n            _output.WriteLine($\"HTTP Activity SpanId: {httpActivity.SpanId}\");\n            _output.WriteLine($\"Activity.Current: {Activity.Current?.Id}\");\n\n            try\n            {\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"\\n=== Server Response ===\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n                _output.WriteLine($\"Server TraceParent: {serverTraceInfo.TraceParentFromRequestContext ?? \"(NULL)\"}\");\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n\n                // Find the activation span\n                var activationSpan = Started\n                    .FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n\n                _output.WriteLine($\"\\n=== Activation Span ===\");\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"TraceId: {activationSpan.TraceId}\");\n                    _output.WriteLine($\"ParentId: {activationSpan.ParentId ?? \"(NULL - ROOT!)\"}\");\n                }\n\n                // Server should have the same TraceId as the HTTP activity\n                Assert.Equal(httpTraceId, serverTraceInfo.TraceId);\n\n                // Activation span should also share the same TraceId\n                if (activationSpan is not null)\n                {\n                    Assert.Equal(httpTraceId, activationSpan.TraceId.ToString());\n                    Assert.False(string.IsNullOrEmpty(activationSpan.ParentId), \n                        \"Activation span should have a parent when called from HTTP activity\");\n                }\n            }\n            finally\n            {\n                httpActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// DIAGNOSTIC TEST: Forces grain activation on a specific (different) silo to test cross-silo\n        /// trace context propagation. This simulates production scenarios where the placement\n        /// director places the grain on a different silo than the one receiving the initial call.\n        /// \n        /// In production with AddDistributedGrainDirectory():\n        /// 1. Client sends call to Silo A\n        /// 2. Placement decides grain should be on Silo B\n        /// 3. Message is forwarded to Silo B\n        /// 4. Silo B creates the activation\n        /// \n        /// The question: Is trace context preserved through this forwarding?\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceContextPreservedWhenGrainPlacedOnDifferentSilo()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"cross-silo-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            _output.WriteLine(\"=== TEST: Cross-silo grain activation ===\");\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            // Get the silos\n            var silos = _fixture.HostedCluster.GetActiveSilos().ToList();\n            _output.WriteLine($\"Active silos: {silos.Count}\");\n            foreach (var silo in silos)\n            {\n                _output.WriteLine($\"  - {silo.SiloAddress}\");\n            }\n\n            if (silos.Count < 2)\n            {\n                _output.WriteLine(\"⚠️ Need at least 2 silos for this test\");\n                return;\n            }\n\n            try\n            {\n                // Use placement hint to force grain onto a specific silo\n                var targetSilo = silos[1].SiloAddress; // Use second silo\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, targetSilo);\n                _output.WriteLine($\"Placement hint set to: {targetSilo}\");\n\n                // This grain uses RandomPlacement, so the hint should work\n                var grain = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                var serverTraceInfo = await grain.GetTraceContextInfo();\n\n                _output.WriteLine($\"\\n=== Results ===\");\n                _output.WriteLine($\"Server TraceId: {serverTraceInfo.TraceId}\");\n                _output.WriteLine($\"Server TraceParent: {serverTraceInfo.TraceParentFromRequestContext ?? \"(NULL!)\"}\");\n                _output.WriteLine($\"Server HasActivity: {serverTraceInfo.HasActivity}\");\n\n                // Find the activation span\n                var activationSpan = Started.FirstOrDefault(a => a.OperationName == ActivityNames.ActivateGrain);\n                if (activationSpan is not null)\n                {\n                    _output.WriteLine($\"\\nActivation Span:\");\n                    _output.WriteLine($\"  TraceId: {activationSpan.TraceId}\");\n                    _output.WriteLine($\"  ParentId: {activationSpan.ParentId ?? \"(NULL - ROOT!)\"}\");\n                    _output.WriteLine($\"  HasRemoteParent: {activationSpan.HasRemoteParent}\");\n                }\n\n                // CRITICAL: Even with cross-silo placement, trace should be preserved\n                Assert.Equal(clientTraceId, serverTraceInfo.TraceId);\n                \n                if (activationSpan is not null)\n                {\n                    Assert.Equal(clientTraceId, activationSpan.TraceId.ToString());\n                    Assert.False(string.IsNullOrEmpty(activationSpan.ParentId),\n                        \"Activation span should have a parent even with cross-silo placement\");\n                }\n            }\n            finally\n            {\n                RequestContext.Clear();\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        /// <summary>\n        /// DIAGNOSTIC TEST: Tests trace context when a grain-to-grain call crosses silo boundaries.\n        /// This is common in production where Grain A on Silo 1 calls Grain B on Silo 2.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task TraceContextPreservedInCrossSiloGrainToGrainCall()\n        {\n            Started.Clear();\n\n            using var clientActivity = ActivitySources.ApplicationGrainSource.StartActivity(\"cross-silo-g2g-test\");\n            clientActivity?.Start();\n\n            Assert.NotNull(clientActivity);\n            var clientTraceId = clientActivity.TraceId.ToString();\n\n            var silos = _fixture.HostedCluster.GetActiveSilos().ToList();\n            if (silos.Count < 2)\n            {\n                _output.WriteLine(\"⚠️ Need at least 2 silos for this test\");\n                return;\n            }\n\n            _output.WriteLine(\"=== TEST: Cross-silo grain-to-grain call ===\");\n            _output.WriteLine($\"Client TraceId: {clientTraceId}\");\n\n            try\n            {\n                // Place first grain on silo 1\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, silos[0].SiloAddress);\n                var grain1 = _fixture.GrainFactory.GetGrain<ITraceContextPropagationGrain>(Random.Shared.Next());\n                _ = await grain1.GetTraceContextInfo(); // Activate on silo 1\n                RequestContext.Clear();\n\n                // Now make a nested call - the nested grain should go to silo 2\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, silos[1].SiloAddress);\n                var (local, nested) = await grain1.GetNestedTraceContextInfo();\n                RequestContext.Clear();\n\n                _output.WriteLine($\"\\n=== Results ===\");\n                _output.WriteLine($\"Local grain TraceId: {local.TraceId}\");\n                _output.WriteLine($\"Nested grain TraceId: {nested.TraceId}\");\n                _output.WriteLine($\"Nested grain HasRemoteParent: {nested.IsRemote}\");\n\n                // Both should share same trace ID\n                Assert.Equal(clientTraceId, local.TraceId);\n                Assert.Equal(clientTraceId, nested.TraceId);\n            }\n            finally\n            {\n                RequestContext.Clear();\n                clientActivity?.Stop();\n                PrintActivityDiagnostics();\n            }\n        }\n\n        private void PrintActivityDiagnostics()\n        {\n            var activities = Started.ToList();\n            if (activities.Count == 0)\n            {\n                _output.WriteLine(\"No activities captured.\");\n                return;\n            }\n\n            var sb = new StringBuilder();\n            sb.AppendLine();\n            sb.AppendLine(\"=== CAPTURED ACTIVITIES ===\");\n            sb.AppendLine($\"Total: {activities.Count}\");\n            sb.AppendLine();\n\n            foreach (var activity in activities.OrderBy(a => a.StartTimeUtc))\n            {\n                sb.AppendLine($\"[{activity.Source.Name}] {activity.OperationName}\");\n                sb.AppendLine($\"  ID: {activity.Id}\");\n                sb.AppendLine($\"  TraceId: {activity.TraceId}\");\n                sb.AppendLine($\"  SpanId: {activity.SpanId}\");\n                sb.AppendLine($\"  ParentSpanId: {activity.ParentSpanId}\");\n                sb.AppendLine($\"  ParentId: {activity.ParentId}\");\n                sb.AppendLine($\"  Kind: {activity.Kind}\");\n                sb.AppendLine($\"  HasRemoteParent: {activity.HasRemoteParent}\");\n                sb.AppendLine();\n            }\n\n            _output.WriteLine(sb.ToString());\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ActivityPropagationTests.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Diagnostics;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for distributed tracing and activity propagation across Orleans grain calls.\n    ///\n    /// Orleans supports distributed tracing through .NET's Activity API, which is compatible with OpenTelemetry.\n    /// These tests verify that:\n    /// - Activity context (trace ID, span ID, trace state) is properly propagated from client to grain\n    /// - Both W3C and Hierarchical activity ID formats are supported\n    /// - Baggage items (key-value pairs) are correctly transmitted across grain boundaries\n    /// - Activity propagation works correctly both from external clients and between grains\n    ///\n    /// The ActivityPropagationGrainCallFilter is responsible for creating child activities for grain calls\n    /// and ensuring proper context propagation throughout the distributed system.\n    /// </summary>\n    public class ActivityPropagationTests : OrleansTestingBase, IClassFixture<ActivityPropagationTests.Fixture>\n    {\n        private static readonly ActivityListener Listener;\n\n        static ActivityPropagationTests()\n        {\n            // Configure an ActivityListener to monitor grain call activities\n            // This listener specifically targets activities created by Orleans for grain calls\n            Listener = new()\n            {\n                ShouldListenTo = p => p.Name == ActivitySources.ApplicationGrainActivitySourceName,\n                Sample = Sample,\n                SampleUsingParentId = SampleUsingParentId,\n            };\n\n            static ActivitySamplingResult Sample(ref ActivityCreationOptions<ActivityContext> options)\n            {\n                // Accessing TraceId during sampling is important to ensure the Activity system\n                // properly initializes the trace context. This reproduces a specific scenario\n                // where SetParentId might not work correctly if TraceId isn't accessed.\n                var _ = options.TraceId;\n                return ActivitySamplingResult.PropagationData;\n            };\n\n            static ActivitySamplingResult SampleUsingParentId(ref ActivityCreationOptions<string> options)\n            {\n                //Trace id has to be accessed in sample to reproduce the scenario when SetParentId does not work\n                var _ = options.TraceId;\n                return ActivitySamplingResult.PropagationData;\n            };\n        }\n\n        /// <summary>\n        /// Test fixture that configures an Orleans cluster with activity propagation enabled.\n        /// Both the silo and client are configured to support distributed tracing.\n        /// </summary>\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n                builder.AddSiloBuilderConfigurator<SiloInvokerTestSiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<ClientConfigurator>();\n            }\n\n            private class SiloInvokerTestSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder) =>\n                    hostBuilder\n                        // Enable activity propagation on the silo to support distributed tracing\n                        .AddActivityPropagation()\n                        // Configure memory storage providers for testing\n                        .AddMemoryGrainStorageAsDefault()\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n            }\n\n            private class ClientConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) =>\n                    clientBuilder\n                        // Enable activity propagation on the client to participate in distributed traces\n                        .AddActivityPropagation();\n            }\n        }\n\n        private readonly ActivityIdFormat _defaultIdFormat;\n        private readonly Fixture _fixture;\n\n        public ActivityPropagationTests(Fixture fixture)\n        {\n            _defaultIdFormat = Activity.DefaultIdFormat;\n            this._fixture = fixture;\n            ActivitySource.AddActivityListener(Listener);\n        }\n\n        /// <summary>\n        /// Tests that grain calls create new activities when no parent activity exists.\n        /// Verifies both W3C (standard format) and Hierarchical (legacy .NET format) activity ID formats.\n        /// When no parent activity is present, Orleans creates a new root activity for the grain call.\n        /// </summary>\n        [Theory]\n        [InlineData(ActivityIdFormat.W3C)]\n        [InlineData(ActivityIdFormat.Hierarchical)]\n        [TestCategory(\"BVT\")]\n        public async Task WithoutParentActivity(ActivityIdFormat idFormat)\n        {\n            Activity.DefaultIdFormat = idFormat;\n\n            await Test(_fixture.GrainFactory);\n            await Test(_fixture.Client);\n\n            static async Task Test(IGrainFactory grainFactory)\n            {\n                var grain = grainFactory.GetGrain<IActivityGrain>(Random.Shared.Next());\n\n                var result = await grain.GetActivityId();\n\n                Assert.NotNull(result);\n                Assert.NotEmpty(result.Id);\n                Assert.Null(result.TraceState);\n            }\n        }\n\n        /// <summary>\n        /// Tests activity propagation with W3C format when a parent activity exists.\n        /// Verifies that:\n        /// - The trace ID from the parent activity is preserved in the grain\n        /// - Trace state (vendor-specific tracing data) is correctly propagated\n        /// - Baggage items (contextual key-value pairs) are transmitted to the grain\n        /// This ensures distributed traces can span across client-to-grain boundaries.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task WithParentActivity_W3C()\n        {\n            Activity.DefaultIdFormat = ActivityIdFormat.W3C;\n\n            var activity = new Activity(\"SomeName\")\n            {\n#if NET10_0_OR_GREATER\n                // In .NET 10+, the W3C propagator enforces strict W3C trace state format (key=value)\n                TraceStateString = \"vendor=value\"\n#else\n                // Pre-.NET 10 legacy propagator accepts any string format\n                TraceStateString = \"traceState\"\n#endif\n            };\n            activity.AddBaggage(\"foo\", \"bar\");\n            activity.Start();\n\n            try\n            {\n                await Test(_fixture.GrainFactory);\n                await Test(_fixture.Client);\n            }\n            finally\n            {\n                activity.Stop();\n            }\n\n            async Task Test(IGrainFactory grainFactory)\n            {\n                var grain = grainFactory.GetGrain<IActivityGrain>(Random.Shared.Next());\n\n                var result = await grain.GetActivityId();\n\n                Assert.NotNull(result);\n                Assert.NotNull(result.Id);\n                Assert.Contains(activity.TraceId.ToHexString(), result.Id); // ensure, that trace id is persisted.\n                Assert.Equal(activity.TraceStateString, result.TraceState);\n                Assert.Equal(activity.Baggage, result.Baggage);\n            }\n        }\n\n        /// <summary>\n        /// Tests activity propagation with Hierarchical format (legacy .NET format).\n        /// Verifies that:\n        /// - The grain's activity ID is a child of the parent activity (starts with parent ID)\n        /// - Baggage items are correctly propagated\n        /// Note: Hierarchical format doesn't support trace state like W3C format does.\n        /// In .NET 10+, the default W3C propagator doesn't support Hierarchical format,\n        /// so the test expectations are adjusted accordingly.\n        /// </summary>\n        [Fact]\n        [TestCategory(\"BVT\")]\n        public async Task WithParentActivity_Hierarchical()\n        {\n            Activity.DefaultIdFormat = ActivityIdFormat.Hierarchical;\n\n            var activity = new Activity(\"SomeName\");\n            activity.AddBaggage(\"foo\", \"bar\");\n            activity.Start();\n\n            try\n            {\n                await Test(_fixture.GrainFactory);\n                await Test(_fixture.Client);\n            }\n            finally\n            {\n                activity.Stop();\n            }\n\n            async Task Test(IGrainFactory grainFactory)\n            {\n                var grain = grainFactory.GetGrain<IActivityGrain>(Random.Shared.Next());\n\n                var result = await grain.GetActivityId();\n\n                Assert.NotNull(result);\n                Assert.NotNull(result.Id);\n#if NET10_0_OR_GREATER\n                // In .NET 10+, the default W3C propagator doesn't support Hierarchical format.\n                // It cannot inject Hierarchical activities, so the grain creates a new root activity.\n                // Neither ID hierarchy nor baggage is propagated with Hierarchical format.\n#else\n                // Pre-.NET 10: Legacy propagator supports Hierarchical format\n                Assert.StartsWith(activity.Id, result.Id);\n                Assert.Equal(activity.Baggage, result.Baggage);\n#endif\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/CancellationTests/CancellationTokenTests.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CancellationTests;\n\n/// <summary>\n/// Tests for CancellationToken functionality with acknowledgement waiting enabled.\n/// </summary>\npublic sealed class CancellationTokenTests_WaitForAcknowledgement(CancellationTokenTests_WaitForAcknowledgement.Fixture fixture) : CancellationTokenTests(fixture), IClassFixture<CancellationTokenTests_WaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        // Wait for callees to acknowledge cancellation.\n        public override bool WaitForCancellationAcknowledgement => true;\n    }\n}\n\n/// <summary>\n/// Tests for CancellationToken functionality with acknowledgement waiting disabled.\n/// </summary>\npublic sealed class CancellationTokenTests_NoWaitForAcknowledgement(CancellationTokenTests_NoWaitForAcknowledgement.Fixture fixture) : CancellationTokenTests(fixture), IClassFixture<CancellationTokenTests_NoWaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        // Do not wait for callees to acknowledge cancellation.\n        public override bool WaitForCancellationAcknowledgement => false;\n    }\n}\n\n/// <summary>\n/// Base class for testing CancellationToken propagation and handling across grain calls.\n/// </summary>\npublic abstract class CancellationTokenTests(CancellationTokenTests.FixtureBase fixture)\n{\n    public abstract class FixtureBase : BaseInProcessTestClusterFixture\n    {\n        public abstract bool WaitForCancellationAcknowledgement { get; }\n        protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n        {\n            base.ConfigureTestCluster(builder);\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.Configure<SiloMessagingOptions>(options =>\n                {\n                    options.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n            });\n\n            builder.ConfigureClient(clientBuilder =>\n            {\n                clientBuilder.Configure<ClientMessagingOptions>(options =>\n                {\n                    options.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n            });\n        }\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task GrainTaskCancellation(int delay)\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.LongWait(cts.Token, TimeSpan.FromSeconds(10), callId);\n        cts.CancelAfter(delay);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(grain, callId);\n        }\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task MultipleGrainsTaskCancellation(int delay)\n    {\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grains = Enumerable.Range(0, 5).Select(_ => fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid())).ToList();\n        var grainTasks = grains.Select(grain =>\n            Assert.ThrowsAnyAsync<OperationCanceledException>(() =>\n                grain.LongWaitInterleaving(cts.Token, TimeSpan.FromSeconds(10), callId)))\n            .ToList();\n        cts.CancelAfter(delay);\n        await Task.WhenAll(grainTasks);\n        if (delay > 0)\n        {\n            foreach (var grain in grains)\n            {\n                await WaitForCallCancellation(grain, callId);\n            }\n        }\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task GrainTaskMultipleCancellations(int delay)\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        var callIds = Enumerable.Range(0, 5).Select(_ => Guid.NewGuid()).ToArray();\n        var grainTasks = callIds\n            .Select(async callId =>\n            {\n                using var cts = new CancellationTokenSource();\n                var task = grain.LongWaitInterleaving(cts.Token, TimeSpan.FromSeconds(10), callId);\n                cts.CancelAfter(delay);\n                await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n            })\n            .ToList();\n        await Task.WhenAll(grainTasks);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(grain, callIds);\n        }\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task TokenPassingWithoutCancellation_NoExceptionShouldBeThrown()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        try\n        {\n            await grain.LongWait(cts.Token, TimeSpan.FromMilliseconds(1), Guid.Empty);\n        }\n        catch (Exception ex)\n        {\n            Assert.Fail(\"Expected no exception, but got: \" + ex.Message);\n        }\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task PreCancelledTokenPassing()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        await cts.CancelAsync();\n\n        // Except a OperationCanceledException to be thrown as the token is already cancelled\n        Assert.Throws<OperationCanceledException>(() => grain.LongWait(cts.Token, TimeSpan.FromSeconds(10), Guid.Empty).Ignore());\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksExecutionContext()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.CancellationTokenCallbackResolve(cts.Token, callId);\n        cts.CancelAfter(TimeSpan.FromMilliseconds(100));\n        if (fixture.WaitForCancellationAcknowledgement)\n        {\n            var result = await grainTask;\n            Assert.True(result);\n        }\n        else\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        }\n\n        await WaitForCallCancellation(grain, callId);\n    }\n\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksTaskSchedulerContext()\n    {\n        var grains = await GetGrains<bool>(false);\n\n        var callId = Guid.NewGuid();\n        var grainTask = grains.Item1.CallOtherCancellationTokenCallbackResolve(grains.Item2, callId);\n        if (fixture.WaitForCancellationAcknowledgement)\n        {\n            var result = await grainTask;\n            Assert.True(result);\n        }\n        else\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        }\n\n        await WaitForCallCancellation(grains.Item2, callId);\n    }\n\n    [Fact, TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksThrow_ExceptionDoesNotPropagate()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        grain.CancellationTokenCallbackThrow(cts.Token, callId).Ignore();\n        // Cancellation is a cooperative mechanism, so we don't expect the exception to propagate\n        cts.CancelAfter(100);\n        await WaitForCallCancellation(grain, callId);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InSiloCancellation(int delay)\n    {\n        await CancellationTestCore(false, delay);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InterSiloCancellation(int delay)\n    {\n        await CancellationTestCore(true, delay);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InterSiloClientCancellationTokenPassing(int delay)\n    {\n        await ClientCancellationTokenPassing(delay, true);\n    }\n\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InSiloClientCancellationTokenPassing(int delay)\n    {\n        await ClientCancellationTokenPassing(delay, false);\n    }\n\n    private async Task ClientCancellationTokenPassing(int delay, bool interSilo)\n    {\n        var grains = await GetGrains<bool>(interSilo);\n        var grain = grains.Item1;\n        var target = grains.Item2;\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.CallOtherLongRunningTask(target, cts.Token, TimeSpan.FromSeconds(10), callId);\n        cts.CancelAfter(delay);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(target, callId);\n        }\n    }\n\n    private async Task CancellationTestCore(bool interSilo, int delay)\n    {\n        var grains = await GetGrains<bool>(interSilo);\n        var grain = grains.Item1;\n        var target = grains.Item2;\n        var callId = Guid.NewGuid();\n        var grainTask = grain.CallOtherLongRunningTaskWithLocalCancellation(target, TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(delay), callId);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(target, callId);\n        }\n    }\n\n    private async Task<Tuple<ILongRunningTaskGrain<T1>, ILongRunningTaskGrain<T1>>> GetGrains<T1>(bool placeOnDifferentSilos = true)\n    {\n        var attemptNumber = 0;\n        var attemptLimit = 50;\n        ILongRunningTaskGrain<T1> grain, target;\n        string instanceId, targetInstanceId;\n        do\n        {\n            if (attemptNumber > 0)\n            {\n                if (attemptNumber >= attemptLimit)\n                {\n                    throw new Exception(\"Could not make requested grains placement\");\n                }\n\n                await Task.Delay(500);\n            }\n\n            ++attemptNumber;\n            var firstSilo = fixture.HostedCluster.Silos.First().SiloAddress;\n            RequestContext.Set(IPlacementDirector.PlacementHintKey, firstSilo);\n            grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<T1>>(Guid.NewGuid());\n            instanceId = await grain.GetRuntimeInstanceId();\n\n            if (placeOnDifferentSilos)\n            {\n                var secondSilo = fixture.HostedCluster.Silos.Skip(1).First().SiloAddress;\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, secondSilo);\n            }\n\n            target = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<T1>>(Guid.NewGuid());\n            targetInstanceId = await target.GetRuntimeInstanceId();\n            RequestContext.Clear();\n        } while (placeOnDifferentSilos && instanceId.Equals(targetInstanceId) || !placeOnDifferentSilos && !instanceId.Equals(targetInstanceId));\n\n        return new Tuple<ILongRunningTaskGrain<T1>, ILongRunningTaskGrain<T1>>(grain, target);\n    }\n\n    private async Task WaitForCallCancellation<T>(ILongRunningTaskGrain<T> grain, Guid callId)\n    {\n        using var cts = new CancellationTokenSource();\n        cts.CancelAfter(TimeSpan.FromSeconds(300));\n        await foreach (var (cancelledCallId, error) in grain.WatchCancellations(cts.Token))\n        {\n            if (cancelledCallId == callId)\n            {\n                if (error is not null)\n                {\n                    throw new Exception(\"Expected no error, but found an error\", error);\n                }\n\n                return;\n            }\n        }\n\n        Assert.Fail(\"Did not encounter the expected call id\");\n    }\n\n    private async Task WaitForCallCancellation<T>(ILongRunningTaskGrain<T> grain, Guid[] callIds)\n    {\n        using var cts = new CancellationTokenSource();\n        var targetIds = new HashSet<Guid>(callIds);\n        cts.CancelAfter(TimeSpan.FromSeconds(300));\n        await foreach (var (cancelledCallId, error) in grain.WatchCancellations(cts.Token))\n        {\n            if (targetIds.Remove(cancelledCallId))\n            {\n                if (error is not null)\n                {\n                    throw new Exception(\"Expected no error, but found an error\", error);\n                }\n\n                if (targetIds.Count == 0)\n                {\n                    return;\n                }\n            }\n        }\n\n        Assert.Fail(\"Did not encounter the expected call id\");\n    }\n\n    /// <summary>\n    /// Tests that a running interleaving grain operation can be cancelled via CancellationToken.\n    /// Interleaving requests run concurrently without queueing and should also be cancellable.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(300)]\n    public async Task InterleavingGrainTaskCancellation(int delay)\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.LongWaitInterleaving(cts.Token, TimeSpan.FromSeconds(10), callId);\n        cts.CancelAfter(delay);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (delay > 0)\n        {\n            await WaitForCallCancellation(grain, callId);\n        }\n    }\n\n    /// <summary>\n    /// Tests that an interleaving request can be cancelled while a regular request is also running.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancelInterleavingWhileRegularGrainRequestRunning()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n\n        // Start a regular (non-interleaving) long-running request\n        using var regularCts = new CancellationTokenSource();\n        var regularCallId = Guid.NewGuid();\n        var regularTask = grain.LongWait(regularCts.Token, TimeSpan.FromSeconds(30), regularCallId);\n\n        // Wait for the regular request to start\n        await Task.Delay(100);\n\n        // Start an interleaving request (this should run concurrently)\n        using var interleavingCts = new CancellationTokenSource();\n        var interleavingCallId = Guid.NewGuid();\n        var interleavingTask = grain.LongWaitInterleaving(interleavingCts.Token, TimeSpan.FromSeconds(10), interleavingCallId);\n\n        // Wait a bit for the interleaving request to start\n        await Task.Delay(100);\n\n        // Cancel the interleaving request\n        await interleavingCts.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => interleavingTask);\n        await WaitForCallCancellation(grain, interleavingCallId);\n\n        // Clean up - cancel the regular request\n        await regularCts.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => regularTask);\n    }\n\n    /// <summary>\n    /// Tests that multiple concurrent interleaving requests can each be cancelled independently.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task MultipleInterleavingGrainRequestsCancellation()\n    {\n        var grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n\n        // Start multiple interleaving requests concurrently\n        using var cts1 = new CancellationTokenSource();\n        using var cts2 = new CancellationTokenSource();\n        using var cts3 = new CancellationTokenSource();\n\n        var callId1 = Guid.NewGuid();\n        var callId2 = Guid.NewGuid();\n        var callId3 = Guid.NewGuid();\n\n        var task1 = grain.LongWaitInterleaving(cts1.Token, TimeSpan.FromSeconds(10), callId1);\n        var task2 = grain.LongWaitInterleaving(cts2.Token, TimeSpan.FromSeconds(10), callId2);\n        var task3 = grain.LongWaitInterleaving(cts3.Token, TimeSpan.FromSeconds(10), callId3);\n\n        // Wait for all to be running\n        await Task.Delay(100);\n\n        // Cancel only the second request\n        await cts2.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task2);\n        await WaitForCallCancellation(grain, callId2);\n\n        // First and third should still be running, cancel them\n        await cts1.CancelAsync();\n        await cts3.CancelAsync();\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task1);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task3);\n\n        await WaitForCallCancellation(grain, [callId1, callId3]);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/CancellationTests/GrainCancellationTokenTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CancellationTests\n{\n    /// <summary>\n    /// Tests for GrainCancellationToken functionality including task cancellation and token callbacks.\n    /// </summary>\n    public class GrainCancellationTokenTests : OrleansTestingBase, IClassFixture<GrainCancellationTokenTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                base.ConfigureTestCluster(builder);\n                builder.AddSiloBuilderConfigurator<SiloConfig>();\n            }\n\n            private class SiloConfig : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder siloBuilder)\n                {\n                    siloBuilder.ConfigureLogging(logging => logging.AddDebug());\n                }\n            }\n        }\n\n        public GrainCancellationTokenTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task GrainTaskCancellation(int delay)\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            using var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            var grainTask = grain.LongWaitGrainCancellation(cts.Token, TimeSpan.FromSeconds(10), callId);\n            await Task.Delay(TimeSpan.FromMilliseconds(delay));\n            await cts.Cancel();\n            await Assert.ThrowsAsync<TaskCanceledException>(() => grainTask);\n            await WaitForCallCancellation(grain, callId);\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task MultipleGrainsTaskCancellation(int delay)\n        {\n            using var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            var grains = Enumerable.Range(0, 5).Select(_ => this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid())).ToList();\n            var grainTasks = grains\n                .Select(grain => Assert.ThrowsAsync<TaskCanceledException>(() => grain\n                            .LongWaitGrainCancellationInterleaving(cts.Token, TimeSpan.FromSeconds(10), callId))).ToList();\n            await Task.Delay(TimeSpan.FromMilliseconds(delay));\n            await cts.Cancel();\n            await Task.WhenAll(grainTasks);\n            if (delay > 0)\n            {\n                foreach (var grain in grains)\n                {\n                    await WaitForCallCancellation(grain, callId);\n                }\n            }\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task GrainTaskMultipleCancellations(int delay)\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            var callIds = Enumerable.Range(0, 5).Select(_ => Guid.NewGuid()).ToArray();\n            var grainTasks = callIds\n                .Select(async callId =>\n                {\n                    using var cts = new GrainCancellationTokenSource();\n                    var task = grain.LongWaitGrainCancellationInterleaving(cts.Token, TimeSpan.FromSeconds(10), callId);\n                    await Task.WhenAny(task, Task.Delay(TimeSpan.FromMilliseconds(delay)));\n                    await cts.Cancel();\n                    try\n                    {\n                        await task;\n                        Assert.Fail(\"Expected TaskCancelledException, but message completed\");\n                    }\n                    catch (TaskCanceledException) { }\n                })\n                .ToList();\n            await Task.WhenAll(grainTasks);\n            if (delay > 0)\n            {\n                await WaitForCallCancellation(grain, callIds);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        public async Task TokenPassingWithoutCancellation_NoExceptionShouldBeThrown()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            using var cts = new GrainCancellationTokenSource();\n            try\n            {\n                await grain.LongWaitGrainCancellation(cts.Token, TimeSpan.FromMilliseconds(1), Guid.Empty);\n            }\n            catch (Exception ex)\n            {\n                Assert.Fail(\"Expected no exception, but got: \" + ex.Message);\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        public async Task PreCancelledTokenPassing()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            using var cts = new GrainCancellationTokenSource();\n            await cts.Cancel();\n            var callId = Guid.NewGuid();\n            var grainTask = grain.LongWaitGrainCancellation(cts.Token, TimeSpan.FromSeconds(10), callId);\n            await Assert.ThrowsAsync<TaskCanceledException>(() => grainTask);\n            await WaitForCallCancellation(grain, callId);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        public async Task CancellationTokenCallbacksExecutionContext()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            using var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            var grainTask = grain.GrainCancellationTokenCallbackResolve(cts.Token, callId);\n            await Task.Delay(TimeSpan.FromMilliseconds(100));\n            await cts.Cancel();\n            var result = await grainTask;\n            Assert.True(result);\n            await WaitForCallCancellation(grain, callId);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        public async Task CancellationTokenCallbacksTaskSchedulerContext()\n        {\n            var grains = await GetGrains<bool>(false);\n\n            using var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            var grainTask = grains.Item1.CallOtherGrainCancellationTokenCallbackResolve(grains.Item2, callId);\n            await cts.Cancel();\n            var result = await grainTask;\n            Assert.True(result);\n            await WaitForCallCancellation(grains.Item2, callId);\n        }\n\n        [Fact, TestCategory(\"Cancellation\")]\n        public async Task CancellationTokenCallbacksThrow_ExceptionShouldBePropagated()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n            using var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            grain.GrainCancellationTokenCallbackThrow(cts.Token, callId).Ignore();\n            await Task.Delay(TimeSpan.FromMilliseconds(100));\n            try\n            {\n                await cts.Cancel();\n            }\n            catch (AggregateException ex)\n            {\n                Assert.True(ex.InnerException is InvalidOperationException, \"Exception thrown has wrong type\");\n                return;\n            }\n\n            Assert.Fail(\"No exception was thrown\");\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task InSiloGrainCancellation(int delay)\n        {\n            await GrainGrainCancellation(false, delay);\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task InterSiloGrainCancellation(int delay)\n        {\n            await GrainGrainCancellation(true, delay);\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task InterSiloClientCancellationTokenPassing(int delay)\n        {\n            await ClientGrainGrainTokenPassing(delay, true);\n        }\n\n        [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n        [InlineData(0)]\n        [InlineData(10)]\n        [InlineData(300)]\n        public async Task InSiloClientCancellationTokenPassing(int delay)\n        {\n            await ClientGrainGrainTokenPassing(delay, false);\n        }\n\n        private async Task ClientGrainGrainTokenPassing(int delay, bool interSilo)\n        {\n            var grains = await GetGrains<bool>(interSilo);\n            var grain = grains.Item1;\n            var target = grains.Item2;\n            var cts = new GrainCancellationTokenSource();\n            var callId = Guid.NewGuid();\n            var grainTask = grain.CallOtherLongRunningTaskGrainCancellation(target, cts.Token, TimeSpan.FromSeconds(10), callId);\n            await Task.Delay(TimeSpan.FromMilliseconds(delay));\n            await cts.Cancel();\n            await Assert.ThrowsAsync<TaskCanceledException>(() => grainTask);\n            if (delay > 0)\n            {\n                await WaitForCallCancellation(grains.Item2, callId);\n            }\n        }\n\n        private async Task GrainGrainCancellation(bool interSilo, int delay)\n        {\n            var grains = await GetGrains<bool>(interSilo);\n            var grain = grains.Item1;\n            var target = grains.Item2;\n            var callId = Guid.NewGuid();\n            var grainTask = grain.CallOtherLongRunningTaskWithLocalGrainCancellationToken(target, TimeSpan.FromSeconds(10), TimeSpan.FromMilliseconds(delay), callId);\n            await Assert.ThrowsAsync<TaskCanceledException>(() => grainTask);\n            if (delay > 0)\n            {\n                await WaitForCallCancellation(grains.Item2, callId);\n            }\n        }\n\n    private async Task<Tuple<ILongRunningTaskGrain<T1>, ILongRunningTaskGrain<T1>>> GetGrains<T1>(bool placeOnDifferentSilos = true)\n    {\n        var attemptNumber = 0;\n        var attemptLimit = 50;\n        ILongRunningTaskGrain<T1> grain, target;\n        string instanceId, targetInstanceId;\n        do\n        {\n            if (attemptNumber > 0)\n            {\n                if (attemptNumber >= attemptLimit)\n                {\n                    throw new Exception(\"Could not make requested grains placement\");\n                }\n\n                await Task.Delay(500);\n            }\n\n            ++attemptNumber;\n            var firstSilo = fixture.HostedCluster.Silos.First().SiloAddress;\n            RequestContext.Set(IPlacementDirector.PlacementHintKey, firstSilo);\n            grain = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<T1>>(Guid.NewGuid());\n            instanceId = await grain.GetRuntimeInstanceId();\n\n            if (placeOnDifferentSilos)\n            {\n                var secondSilo = fixture.HostedCluster.Silos.Skip(1).First().SiloAddress;\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, secondSilo);\n            }\n\n            target = fixture.GrainFactory.GetGrain<ILongRunningTaskGrain<T1>>(Guid.NewGuid());\n            targetInstanceId = await target.GetRuntimeInstanceId();\n            RequestContext.Clear();\n        } while (placeOnDifferentSilos && instanceId.Equals(targetInstanceId) || !placeOnDifferentSilos && !instanceId.Equals(targetInstanceId));\n\n        return new Tuple<ILongRunningTaskGrain<T1>, ILongRunningTaskGrain<T1>>(grain, target);\n    }\n\n        private async Task WaitForCallCancellation<T>(ILongRunningTaskGrain<T> grain, Guid callId)\n        {\n            using var cts = new CancellationTokenSource();\n            cts.CancelAfter(TimeSpan.FromSeconds(30));\n            await foreach (var (cancelledCallId, error) in grain.WatchCancellations(cts.Token))\n            {\n                if (cancelledCallId == callId)\n                {\n                    if (error is not null)\n                    {\n                        throw new Exception(\"Expected no error, but found an error\", error);\n                    }\n\n                    return;\n                }\n            }\n\n            Assert.Fail(\"Did not encounter the expected call id\");\n        }\n\n        private async Task WaitForCallCancellation<T>(ILongRunningTaskGrain<T> grain, Guid[] callIds)\n        {\n            using var cts = new CancellationTokenSource();\n            var targetIds = new HashSet<Guid>(callIds);\n            cts.CancelAfter(TimeSpan.FromSeconds(300));\n            await foreach (var (cancelledCallId, error) in grain.WatchCancellations(cts.Token))\n            {\n                if (targetIds.Remove(cancelledCallId))\n                {\n                    if (error is not null)\n                    {\n                        throw new Exception(\"Expected no error, but found an error\", error);\n                    }\n\n                    if (targetIds.Count == 0)\n                    {\n                        return;\n                    }\n                }\n            }\n\n            Assert.Fail(\"Did not encounter the expected call id\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/CancellationTests/ObserverCancellationTokenTests.cs",
    "content": "#nullable enable\nusing System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CancellationTests;\n\n/// <summary>\n/// Tests for Observer CancellationToken functionality with acknowledgement waiting enabled.\n/// </summary>\npublic sealed class ObserverCancellationTokenTests_WaitForAcknowledgement(ObserverCancellationTokenTests_WaitForAcknowledgement.Fixture fixture)\n    : ObserverCancellationTokenTests(fixture), IClassFixture<ObserverCancellationTokenTests_WaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        public override bool WaitForCancellationAcknowledgement => true;\n    }\n}\n\n/// <summary>\n/// Tests for Observer CancellationToken functionality with acknowledgement waiting disabled.\n/// </summary>\npublic sealed class ObserverCancellationTokenTests_NoWaitForAcknowledgement(ObserverCancellationTokenTests_NoWaitForAcknowledgement.Fixture fixture)\n    : ObserverCancellationTokenTests(fixture), IClassFixture<ObserverCancellationTokenTests_NoWaitForAcknowledgement.Fixture>\n{\n    public sealed class Fixture : FixtureBase\n    {\n        public override bool WaitForCancellationAcknowledgement => false;\n    }\n}\n\n/// <summary>\n/// Base class for testing CancellationToken propagation and handling for observers (local objects).\n/// </summary>\npublic abstract class ObserverCancellationTokenTests(ObserverCancellationTokenTests.FixtureBase fixture)\n{\n    public abstract class FixtureBase : BaseInProcessTestClusterFixture\n    {\n        public abstract bool WaitForCancellationAcknowledgement { get; }\n\n        protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n        {\n            base.ConfigureTestCluster(builder);\n            builder.ConfigureHost(hostBuilder => hostBuilder.Logging.SetMinimumLevel(LogLevel.Debug));\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.Configure<SiloMessagingOptions>(options =>\n                {\n                    options.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n            });\n\n            builder.ConfigureClient(clientBuilder =>\n            {\n                clientBuilder.Configure<ClientMessagingOptions>(options =>\n                {\n                    options.WaitForCancellationAcknowledgement = WaitForCancellationAcknowledgement;\n                });\n            });\n        }\n    }\n\n    /// <summary>\n    /// Tests that a running observer operation can be cancelled via CancellationToken.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(true)]\n    [InlineData(false)]\n    public async Task ObserverTaskCancellation(bool cancelImmediately)\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.NotifyLongWait(TimeSpan.FromSeconds(10), callId, cts.Token);\n\n        if (cancelImmediately)\n        {\n            await cts.CancelAsync();\n        }\n        else\n        {\n            await observer.WaitForCallToStart(callId);\n            await cts.CancelAsync();\n        }\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (!cancelImmediately)\n        {\n            await observer.WaitForCancellation(callId);\n        }\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that a pre-cancelled token is properly handled when calling an observer.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task PreCancelledTokenPassing()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        using var cts = new CancellationTokenSource();\n        await cts.CancelAsync();\n\n        // Expect an OperationCanceledException to be thrown as the token is already cancelled\n        Assert.Throws<OperationCanceledException>(() =>\n            grain.NotifyLongWait(TimeSpan.FromSeconds(10), Guid.Empty, cts.Token).Ignore());\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that passing a CancellationToken without cancellation does not throw.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task TokenPassingWithoutCancellation_NoExceptionShouldBeThrown()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        using var cts = new CancellationTokenSource();\n        try\n        {\n            await grain.NotifyLongWait(TimeSpan.FromMilliseconds(1), Guid.Empty, cts.Token);\n        }\n        catch (Exception ex)\n        {\n            Assert.Fail(\"Expected no exception, but got: \" + ex.Message);\n        }\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that cancellation token callbacks execute in the correct execution context for observers.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancellationTokenCallbacksExecutionContext()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.NotifyCancellationTokenCallbackResolve(callId, cts.Token);\n\n        await observer.WaitForCallToStart(callId);\n        await cts.CancelAsync();\n\n        if (fixture.WaitForCancellationAcknowledgement)\n        {\n            var result = await grainTask;\n            Assert.True(result);\n        }\n        else\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        }\n\n        await observer.WaitForCancellation(callId);\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests cancellation when multiple observers are subscribed and all receive cancellation.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(true)]\n    [InlineData(false)]\n    public async Task MultipleObserversCancellation(bool cancelImmediately)\n    {\n        // Create multiple grains each with an observer\n        using var cts = new CancellationTokenSource();\n        var grains = new List<(IObserverWithCancellationGrain Grain, LongRunningObserver Observer, ILongRunningObserver Reference, Guid CallId)>();\n\n        for (int i = 0; i < 5; i++)\n        {\n            var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n            var observer = new LongRunningObserver();\n            var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n            await grain.Subscribe(reference);\n            grains.Add((grain, observer, reference, Guid.NewGuid()));\n        }\n\n        var notifyTasks = grains\n            .Select(g => g.Grain.NotifyLongWait(TimeSpan.FromSeconds(10), g.CallId, cts.Token))\n            .ToList();\n\n        if (cancelImmediately)\n        {\n            await cts.CancelAsync();\n        }\n        else\n        {\n            await Task.WhenAll(grains.Select(g => g.Observer.WaitForCallToStart(g.CallId)));\n            await cts.CancelAsync();\n        }\n\n        foreach (var task in notifyTasks)\n        {\n            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task);\n        }\n\n        if (!cancelImmediately)\n        {\n            for (int i = 0; i < grains.Count; i++)\n            {\n                await grains[i].Observer.WaitForCancellation(grains[i].CallId);\n            }\n        }\n\n        foreach (var g in grains)\n        {\n            await g.Grain.Unsubscribe(g.Reference);\n        }\n        foreach (var g in grains)\n        {\n            fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(g.Reference);\n        }\n    }\n\n    /// <summary>\n    /// Tests that cancellation of a waiting (queued) request in an observer is handled correctly.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancelWaitingRequest()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        // Start a long-running request that will block the observer\n        using var blockingCts = new CancellationTokenSource();\n        var blockingCallId = Guid.NewGuid();\n        var blockingTask = grain.NotifyLongWait(TimeSpan.FromSeconds(30), blockingCallId, blockingCts.Token);\n\n        // Wait for the blocking request to start\n        await observer.WaitForCallToStart(blockingCallId);\n\n        // Start another request that will be queued\n        using var queuedCts = new CancellationTokenSource();\n        var queuedCallId = Guid.NewGuid();\n        var queuedTask = grain.NotifyLongWait(TimeSpan.FromSeconds(10), queuedCallId, queuedCts.Token);\n\n        // Cancel the queued request\n        await queuedCts.CancelAsync();\n\n        // The queued task should throw OperationCanceledException\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => queuedTask);\n\n        // Cancel the blocking request to clean up\n        await blockingCts.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => blockingTask);\n        await observer.WaitForCancellation(blockingCallId);\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that a running interleaving observer operation can be cancelled via CancellationToken.\n    /// Interleaving requests run concurrently without queueing and should also be cancellable.\n    /// </summary>\n    [Theory, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    [InlineData(true)]\n    [InlineData(false)]\n    public async Task InterleavingObserverTaskCancellation(bool cancelImmediately)\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        using var cts = new CancellationTokenSource();\n        var callId = Guid.NewGuid();\n        var grainTask = grain.NotifyInterleavingLongWait(TimeSpan.FromSeconds(10), callId, cts.Token);\n\n        if (cancelImmediately)\n        {\n            await cts.CancelAsync();\n        }\n        else\n        {\n            await observer.WaitForCallToStart(callId);\n            await cts.CancelAsync();\n        }\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => grainTask);\n        if (!cancelImmediately)\n        {\n            await observer.WaitForCancellation(callId);\n        }\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that multiple concurrent interleaving requests can each be cancelled independently.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task MultipleInterleavingRequestsCancellation()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        // Start multiple interleaving requests concurrently\n        using var cts1 = new CancellationTokenSource();\n        using var cts2 = new CancellationTokenSource();\n        using var cts3 = new CancellationTokenSource();\n\n        var callId1 = Guid.NewGuid();\n        var callId2 = Guid.NewGuid();\n        var callId3 = Guid.NewGuid();\n\n        var task1 = grain.NotifyInterleavingLongWait(TimeSpan.FromSeconds(10), callId1, cts1.Token);\n        var task2 = grain.NotifyInterleavingLongWait(TimeSpan.FromSeconds(10), callId2, cts2.Token);\n        var task3 = grain.NotifyInterleavingLongWait(TimeSpan.FromSeconds(10), callId3, cts3.Token);\n\n        // Wait for all to be running\n        await Task.WhenAll(\n            observer.WaitForCallToStart(callId1),\n            observer.WaitForCallToStart(callId2),\n            observer.WaitForCallToStart(callId3));\n\n        // Cancel only the second request\n        await cts2.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task2);\n        await observer.WaitForCancellation(callId2);\n\n        // First and third should still be running, cancel them\n        await cts1.CancelAsync();\n        await cts3.CancelAsync();\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task1);\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => task3);\n\n        await observer.WaitForCancellation(callId1);\n        await observer.WaitForCancellation(callId3);\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Tests that an interleaving request can be cancelled while a regular request is also running.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"Cancellation\")]\n    public async Task CancelInterleavingWhileRegularRequestRunning()\n    {\n        var grain = fixture.GrainFactory.GetGrain<IObserverWithCancellationGrain>(Guid.NewGuid());\n        var observer = new LongRunningObserver();\n        var reference = fixture.GrainFactory.CreateObjectReference<ILongRunningObserver>(observer);\n        await grain.Subscribe(reference);\n\n        // Start a regular (non-interleaving) long-running request\n        using var regularCts = new CancellationTokenSource();\n        var regularCallId = Guid.NewGuid();\n        var regularTask = grain.NotifyLongWait(TimeSpan.FromSeconds(30), regularCallId, regularCts.Token);\n\n        // Wait for the regular request to start\n        await observer.WaitForCallToStart(regularCallId);\n\n        // Start an interleaving request (this should run concurrently)\n        using var interleavingCts = new CancellationTokenSource();\n        var interleavingCallId = Guid.NewGuid();\n        var interleavingTask = grain.NotifyInterleavingLongWait(TimeSpan.FromSeconds(10), interleavingCallId, interleavingCts.Token);\n\n        // Wait for the interleaving request to start\n        await observer.WaitForCallToStart(interleavingCallId);\n\n        // Cancel the interleaving request\n        await interleavingCts.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => interleavingTask);\n        await observer.WaitForCancellation(interleavingCallId);\n\n        // Clean up - cancel the regular request\n        await regularCts.CancelAsync();\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(() => regularTask);\n        await observer.WaitForCancellation(regularCallId);\n\n        await grain.Unsubscribe(reference);\n        fixture.GrainFactory.DeleteObjectReference<ILongRunningObserver>(reference);\n    }\n\n    /// <summary>\n    /// Client-side observer implementation for testing long-running operations with cancellation.\n    /// </summary>\n    private sealed class LongRunningObserver : ILongRunningObserver\n    {\n        private readonly ConcurrentDictionary<Guid, TaskCompletionSource> _callStartedTcs = new();\n        private readonly ConcurrentDictionary<Guid, TaskCompletionSource> _callCancelledTcs = new();\n\n        /// <inheritdoc />\n        public async Task LongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken)\n        {\n            var startedTcs = _callStartedTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            var cancelledTcs = _callCancelledTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n\n            startedTcs.TrySetResult();\n\n            try\n            {\n                await Task.Delay(delay, cancellationToken);\n            }\n            catch (OperationCanceledException)\n            {\n                cancelledTcs.TrySetResult();\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public Task<bool> CancellationTokenCallbackResolve(Guid callId, CancellationToken cancellationToken)\n        {\n            var startedTcs = _callStartedTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            var cancelledTcs = _callCancelledTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            var resultTcs = new TaskCompletionSource<bool>();\n\n            startedTcs.TrySetResult();\n\n            cancellationToken.Register(() =>\n            {\n                cancelledTcs.TrySetResult();\n                resultTcs.TrySetResult(true);\n            });\n\n            return resultTcs.Task;\n        }\n\n        /// <inheritdoc />\n        public async Task InterleavingLongWait(TimeSpan delay, Guid callId, CancellationToken cancellationToken)\n        {\n            var startedTcs = _callStartedTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            var cancelledTcs = _callCancelledTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n\n            startedTcs.TrySetResult();\n\n            try\n            {\n                await Task.Delay(delay, cancellationToken);\n            }\n            catch (OperationCanceledException)\n            {\n                cancelledTcs.TrySetResult();\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Waits for a call to start.\n        /// </summary>\n        public Task WaitForCallToStart(Guid callId)\n        {\n            var tcs = _callStartedTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            return tcs.Task.WaitAsync(TimeSpan.FromSeconds(30));\n        }\n\n        /// <summary>\n        /// Waits for a call to be cancelled.\n        /// </summary>\n        public Task WaitForCancellation(Guid callId)\n        {\n            var tcs = _callCancelledTcs.GetOrAdd(callId, _ => new TaskCompletionSource());\n            return tcs.Task.WaitAsync(TimeSpan.FromSeconds(30));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/ClientConnectionEventTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester;\n\n/// <summary>\n/// Tests for client connection events including cluster disconnection and gateway count changes.\n/// </summary>\npublic class ClientConnectionEventTests\n{\n    [Fact, TestCategory(\"SlowBVT\")]\n    public async Task EventSendWhenDisconnectedFromCluster()\n    {\n        var tcs = new TaskCompletionSource();\n        var builder = new InProcessTestClusterBuilder();\n        builder.ConfigureClient(c =>\n        {\n            c.Configure<GatewayOptions>(o => o.GatewayListRefreshPeriod = TimeSpan.FromSeconds(0.5));\n            c.AddClusterConnectionLostHandler((sender, args) => tcs.TrySetResult());\n        });\n        await using var cluster = builder.Build();\n        await cluster.DeployAsync();\n\n        // Burst lot of call, to be sure that we are connected to all silos\n        for (int i = 0; i < 100; i++)\n        {\n            var grain = cluster.Client.GetGrain<ITestGrain>(i);\n            await grain.SetLabel(i.ToString());\n        }\n\n        await cluster.StopAllSilosAsync();\n        await tcs.Task.WaitAsync(TimeSpan.FromSeconds(10));\n    }\n\n    [Fact, TestCategory(\"SlowBVT\")]\n    public async Task GatewayChangedEventSentOnDisconnectAndReconnect()\n    {\n        var regainedGatewayTcs = new TaskCompletionSource();\n        var lostGatewayTcs = new TaskCompletionSource();\n        var builder = new InProcessTestClusterBuilder();\n        builder.ConfigureClient(c =>\n        {\n            c.Configure<GatewayOptions>(o => o.GatewayListRefreshPeriod = TimeSpan.FromSeconds(0.5));\n            c.AddGatewayCountChangedHandler((sender, args) =>\n            {\n                if (args.NumberOfConnectedGateways == 1)\n                {\n                    lostGatewayTcs.TrySetResult();\n                }\n                if (args.NumberOfConnectedGateways == 2)\n                {\n                    regainedGatewayTcs.TrySetResult();\n                }\n            });\n        });\n        await using var cluster = builder.Build();\n        await cluster.DeployAsync();\n\n        var silo = cluster.Silos[0];\n        await silo.StopSiloAsync(true);\n\n        await lostGatewayTcs.Task.WaitAsync(TimeSpan.FromSeconds(20));\n\n        await cluster.RestartStoppedSecondarySiloAsync(silo.Name);\n\n        // Clients need prodding to reconnect.\n        var remainingAttempts = 90;\n        bool reconnected;\n        do\n        {\n            cluster.Client.GetGrain<ITestGrain>(Guid.NewGuid().GetHashCode()).SetLabel(\"test\").Ignore();\n            await regainedGatewayTcs.Task.WaitAsync(TimeSpan.FromSeconds(1)).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.SuppressThrowing);\n            reconnected = regainedGatewayTcs.Task.IsCompleted;\n        } while (!reconnected && --remainingAttempts > 0);\n\n        Assert.True(reconnected, \"Failed to reconnect to restarted gateway.\");\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/ClientConnectionRegisteredServiceEventTests.cs",
    "content": "using System.Collections.Immutable;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester\n{\n    /// <summary>\n    /// Tests for client connection events using registered service event notification patterns.\n    /// </summary>\n    public class ClientConnectionRegisteredServiceEventTests : TestClusterPerTest\n    {\n        private EventNotifier<EventArgs> clusterConnectionLostNotifier;\n\n        private EventNotifier<GatewayCountChangedEventArgs> gatewayCountChangedNotifier;\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            this.clusterConnectionLostNotifier = this.HostedCluster.ServiceProvider.GetRequiredService<EventNotifier<EventArgs>>();\n            this.gatewayCountChangedNotifier = this.HostedCluster.ServiceProvider.GetRequiredService<EventNotifier<GatewayCountChangedEventArgs>>();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddClientBuilderConfigurator<Configurator>();\n        }\n\n        public class EventNotifier<TEventArgs>\n        {\n            private ImmutableList<Action<TEventArgs>> subscribers = ImmutableList<Action<TEventArgs>>.Empty;\n\n            public void Subscribe(Action<TEventArgs> action) => ImmutableInterlocked.Update(ref this.subscribers, (subs, sub) => subs.Add(sub), action);\n\n            public void Unsubscribe(Action<TEventArgs> action) =>\n                ImmutableInterlocked.Update(ref this.subscribers, (subs, sub) => subs.Remove(sub), action);\n\n            public void Notify(TEventArgs arg)\n            {\n                foreach (var sub in this.subscribers)\n                {\n                    sub(arg);\n                }\n            }\n        }\n\n        public class Configurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                var clusterConnectionLostNotifier = new EventNotifier<EventArgs>();\n                var gatewayConnectionCountNotifier = new EventNotifier<GatewayCountChangedEventArgs>();\n\n                clientBuilder.ConfigureServices(s => s.AddSingleton(clusterConnectionLostNotifier));\n                clientBuilder.ConfigureServices(s => s.AddSingleton(gatewayConnectionCountNotifier));\n                clientBuilder.Configure<GatewayOptions>(options => options.GatewayListRefreshPeriod = TimeSpan.FromSeconds(1));\n                clientBuilder.AddClusterConnectionLostHandler((s, e) => clusterConnectionLostNotifier.Notify(e));\n                clientBuilder.AddGatewayCountChangedHandler((s, e) => gatewayConnectionCountNotifier.Notify(e));\n            }\n        }\n\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task EventSendWhenDisconnectedFromCluster()\n        {\n            var runtime = this.HostedCluster.ServiceProvider.GetRequiredService<OutsideRuntimeClient>();\n\n            var semaphore = new SemaphoreSlim(0, 1);\n            void ReleaseSemaphoreAction(EventArgs args) => semaphore.Release();\n\n            this.clusterConnectionLostNotifier.Subscribe(ReleaseSemaphoreAction);\n\n            try\n            {\n                // Burst lot of call, to be sure that we are connected to all silos\n                for (int i = 0; i < 100; i++)\n                {\n                    var grain = GrainFactory.GetGrain<ITestGrain>(i);\n                    await grain.SetLabel(i.ToString());\n                }\n\n                await this.HostedCluster.StopAllSilosAsync();\n\n                Assert.True(await semaphore.WaitAsync(TimeSpan.FromSeconds(10)));\n            }\n            finally\n            {\n                this.clusterConnectionLostNotifier.Unsubscribe(ReleaseSemaphoreAction);\n            }\n        }\n\n        [Fact, TestCategory(\"SlowBVT\")]\n        public async Task GatewayChangedEventSentOnDisconnectAndReconnect()\n        {\n            var regainedGatewaySemaphore = new SemaphoreSlim(0, 1);\n            var lostGatewaySemaphore = new SemaphoreSlim(0, 1);\n\n            void ReleaseGatewaySemaphoreAction(GatewayCountChangedEventArgs args)\n            {\n                if (args.NumberOfConnectedGateways == 1)\n                {\n                    lostGatewaySemaphore.Release();\n                }\n                if (args.NumberOfConnectedGateways == 2)\n                {\n                    regainedGatewaySemaphore.Release();\n                }\n            }\n\n            this.gatewayCountChangedNotifier.Subscribe(ReleaseGatewaySemaphoreAction);\n\n            try\n            {\n                var silo = this.HostedCluster.SecondarySilos[0];\n                await silo.StopSiloAsync(true);\n\n                Assert.True(await lostGatewaySemaphore.WaitAsync(TimeSpan.FromSeconds(20)));\n\n                await this.HostedCluster.RestartStoppedSecondarySiloAsync(silo.Name);\n\n                // Clients need prodding to reconnect.\n                var remainingAttempts = 90;\n                bool reconnected;\n                do\n                {\n                    this.Client.GetGrain<ITestGrain>(Guid.NewGuid().GetHashCode()).SetLabel(\"test\").Ignore();\n                    reconnected = await regainedGatewaySemaphore.WaitAsync(TimeSpan.FromSeconds(1));\n                } while (!reconnected && --remainingAttempts > 0);\n\n                Assert.True(reconnected, \"Failed to reconnect to restarted gateway.\");\n            }\n            finally\n            {\n                this.gatewayCountChangedNotifier.Unsubscribe(ReleaseGatewaySemaphoreAction);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/ClusterClientTests.cs",
    "content": "using System.Collections.ObjectModel;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.ClientConnectionTests\n{\n    [TestCategory(\"Functional\")]\n    public class ClusterClientTests : TestClusterPerTest\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n        }\n\n        /// <summary>\n        /// Ensures that ClusterClient.Connect can be retried.\n        /// </summary>\n        [Fact]\n        public async Task ConnectIsRetryableTest()\n        {\n            var gateways = await this.HostedCluster.Client.ServiceProvider.GetRequiredService<IGatewayListProvider>().GetGateways();\n            var gwEndpoint = gateways.First();\n\n            // Create a client with no gateway endpoint and then add a gateway endpoint when the client fails to connect.\n            var gatewayProvider = new MockGatewayListProvider();\n            var exceptions = new List<Exception>();\n\n            Task<bool> RetryFunc(Exception exception, CancellationToken cancellationToken)\n            {\n                Assert.IsType<SiloUnavailableException>(exception);\n                exceptions.Add(exception);\n                gatewayProvider.Gateways = new List<Uri> { gwEndpoint }.AsReadOnly();\n                return Task.FromResult(true);\n            }\n\n            using var host = new HostBuilder().UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder\n                        .Configure<ClusterOptions>(options =>\n                        {\n                            var existingClientOptions = this.HostedCluster.ServiceProvider\n                                .GetRequiredService<IOptions<ClusterOptions>>().Value;\n                            options.ClusterId = existingClientOptions.ClusterId;\n                            options.ServiceId = existingClientOptions.ServiceId;\n                        })\n                        .ConfigureServices(services => services.AddSingleton<IGatewayListProvider>(gatewayProvider))\n                        .UseConnectionRetryFilter(RetryFunc);\n                })\n                .Build();\n\n            var client = host.Services.GetRequiredService<IClusterClient>();\n\n            await host.StartAsync();\n            Assert.Single(exceptions);\n            await host.StopAsync();\n        }\n\n        public class MockGatewayListProvider : IGatewayListProvider\n        {\n            public ReadOnlyCollection<Uri> Gateways { get; set; } = new ReadOnlyCollection<Uri>(new List<Uri>());\n\n            public Task InitializeGatewayListProvider() => Task.CompletedTask;\n\n            public Task<IList<Uri>> GetGateways() => Task.FromResult<IList<Uri>>(this.Gateways);\n\n            public TimeSpan MaxStaleness => TimeSpan.FromSeconds(30);\n\n            public bool IsUpdatable => true;\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/GatewayConnectionTests.cs",
    "content": "using System.Net;\nusing System.Net.Sockets;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Runtime.Messaging;\n\nnamespace Tester\n{\n    public class TestGatewayManager : IGatewayListProvider\n    {\n        public TimeSpan MaxStaleness => TimeSpan.FromSeconds(1);\n\n        public bool IsUpdatable => true;\n\n        public IList<Uri> Gateways { get; }\n\n        public TestGatewayManager()\n        {\n            Gateways = new List<Uri>();\n        }\n\n        public Task InitializeGatewayListProvider()\n        {\n            return Task.CompletedTask;\n        }\n\n        public Task<IList<Uri>> GetGateways()\n        {\n            return Task.FromResult(Gateways);\n        }\n    }\n\n    /// <summary>\n    /// Tests for gateway connection handling including reconnection behavior and cluster mismatch scenarios.\n    /// </summary>\n    public class GatewayConnectionTests : TestClusterPerTest\n    {\n        private OutsideRuntimeClient runtimeClient;\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.UseTestClusterMembership = false;\n            builder.Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n            builder.Options.InitialSilosCount = 1;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                hostBuilder.UseOrleans((ctx, siloBuilder) =>\n                {\n                    siloBuilder.UseLocalhostClustering();\n                });\n\n                hostBuilder.ConfigureServices((context, services) =>\n                {\n                    var cfg = context.Configuration;\n                    var siloPort = int.Parse(cfg[nameof(TestClusterOptions.BaseSiloPort)]);\n                    var gatewayPort = int.Parse(cfg[nameof(TestClusterOptions.BaseGatewayPort)]);\n                    services.Configure<EndpointOptions>(options =>\n                    {\n                        options.SiloPort = siloPort;\n                        options.GatewayPort = gatewayPort;\n                    });\n                });\n            }\n        }\n\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                var basePort = int.Parse(configuration[nameof(TestClusterOptions.BaseGatewayPort)]);\n                var primaryGw = new IPEndPoint(IPAddress.Loopback, basePort).ToGatewayUri();\n                clientBuilder.Configure<GatewayOptions>(options =>\n                {\n                    options.GatewayListRefreshPeriod = TimeSpan.FromMilliseconds(100);\n                });\n                clientBuilder.ConfigureServices(services =>\n                {\n                    services.AddSingleton(sp =>\n                    {\n                        var gateway = new TestGatewayManager();\n                        gateway.Gateways.Add(primaryGw);\n                        return gateway;\n                    });\n                    services.AddFromExisting<IGatewayListProvider, TestGatewayManager>();\n                });\n            }\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            this.runtimeClient = this.Client.ServiceProvider.GetRequiredService<OutsideRuntimeClient>();\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task NoReconnectionToGatewayNotReturnedByManager()\n        {\n            // Use a timeout shorter than OpenConnectionTimeout (5s) so that calls to\n            // the fake gateway produce a TimeoutException, but long enough that\n            // legitimate grain calls on slow CI machines don't spuriously timeout.\n            this.runtimeClient.SetResponseTimeout(TimeSpan.FromSeconds(3));\n\n            var connectionCount = 0;\n            var timeoutCount = 0;\n\n            // Fake Gateway\n            var gateways = await this.HostedCluster.Client.ServiceProvider.GetRequiredService<IGatewayListProvider>().GetGateways();\n            var port = gateways.First().Port + 2;\n            var endpoint = new IPEndPoint(IPAddress.Loopback, port);\n            var evt = new SocketAsyncEventArgs();\n            var gatewayManager = this.runtimeClient.ServiceProvider.GetService<TestGatewayManager>();\n            evt.Completed += (sender, args) =>\n            {\n                connectionCount++;\n                gatewayManager.Gateways.Remove(endpoint.ToGatewayUri());\n            };\n\n            // Add the fake gateway and wait the refresh from the client\n            gatewayManager.Gateways.Add(endpoint.ToGatewayUri());\n            await Task.Delay(200);\n\n            using (var socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))\n            {\n                // Start the fake gw\n                socket.Bind(endpoint);\n                socket.Listen(1);\n                socket.AcceptAsync(evt);\n\n                // Make a bunch of calls\n                for (var i = 0; i < 100; i++)\n                {\n                    try\n                    {\n                        var g = this.Client.GetGrain<ISimpleGrain>(i);\n                        await g.SetA(i);\n                    }\n                    catch (TimeoutException)\n                    {\n                        timeoutCount++;\n                    }\n                }\n                socket.Close();\n            }\n\n            // Check that we only connected once to the fake GW\n            Assert.Equal(1, connectionCount);\n            Assert.True(timeoutCount >= 1, $\"Expected at least 1 timeout but got {timeoutCount}\");\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ConnectionFromDifferentClusterIsRejected()\n        {\n            // Arange\n            var gateways = await this.HostedCluster.Client.ServiceProvider.GetRequiredService<IGatewayListProvider>().GetGateways();\n            var gwEndpoint  = gateways.First().ToIPEndPoint();\n            var exceptions = new List<Exception>();\n\n            Task<bool> RetryFunc(Exception exception, CancellationToken cancellationToken)\n            {\n                Assert.IsType<ConnectionFailedException>(exception);\n                exceptions.Add(exception);\n                return Task.FromResult(false);\n            }\n\n            // Close current client connection\n            await this.HostedCluster.StopClusterClientAsync();\n            var hostBuilder = new HostBuilder().UseOrleansClient(\n                (ctx, clientBuilder) =>\n                {\n                    clientBuilder.Configure<ClientMessagingOptions>(\n                        options => { options.ResponseTimeoutWithDebugger = TimeSpan.FromSeconds(10); });\n                    clientBuilder.Configure<ClusterOptions>(\n                        options =>\n                        {\n                            options.ClusterId = \"myClusterId\";\n                        })\n                        .UseStaticClustering(gwEndpoint)\n                        .UseConnectionRetryFilter(RetryFunc);\n                    ;\n                });\n            var host = hostBuilder.Build();\n            var exception = await Assert.ThrowsAsync<ConnectionFailedException>(async () => await host.StartAsync());\n            Assert.Contains(\"Unable to connect to\", exception.Message);\n            await host.StopAsync();\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/InvalidPreambleConnectionTests.cs",
    "content": "using System.Net.Sockets;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Messaging;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.ClientConnectionTests\n{\n    /// <summary>\n    /// Tests for handling invalid connection preambles sent to gateway endpoints.\n    /// </summary>\n    public class InvalidPreambleConnectionTests : TestClusterPerTest\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ShouldCloseConnectionWhenClientSendsInvalidPreambleSize()\n        {\n            var gateways = await this.HostedCluster.Client.ServiceProvider.GetRequiredService<IGatewayListProvider>().GetGateways();\n            var gwEndpoint = gateways.First().ToIPEndPoint();\n\n            using var socket = new Socket(gwEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);\n\n            // Set receive timeout to avoid hanging indefinitely\n            socket.ReceiveTimeout = 25_000;\n\n            await socket.ConnectAsync(gwEndpoint);\n\n            // Send invalid preamble size (exceeds MaxPreambleLength of 1024 from ConnectionPreambleHelper)\n            int invalidSize = 99999;\n            await socket.SendAsync(BitConverter.GetBytes(invalidSize), SocketFlags.None);\n\n            // Try to read from the socket to detect closure\n            // When the server closes the connection, Receive will return 0 bytes or throw\n            var buffer = new byte[1];\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n\n            try\n            {\n                var bytesReceived = await socket.ReceiveAsync(buffer, SocketFlags.None, cts.Token);\n\n                // If we receive 0 bytes, the connection was gracefully closed by the server\n                Assert.Equal(0, bytesReceived);\n            }\n            catch (SocketException ex) when (ex.SocketErrorCode is SocketError.ConnectionReset or SocketError.ConnectionAborted)\n            {\n                // Connection was forcibly closed - this is also acceptable\n            }\n            catch (OperationCanceledException)\n            {\n                Assert.Fail(\"Server did not close the connection within the timeout period\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ClientConnectionTests/StallConnectionTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing System.Diagnostics;\nusing System.Net.Sockets;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.ClientConnectionTests\n{\n    /// <summary>\n    /// Tests for handling stalled connections to gateways and silos during client reconnection and cluster joins.\n    /// </summary>\n    public class StallConnectionTests : TestClusterPerTest\n    {\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10);\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.ConnectionTransport = ConnectionTransportType.TcpSocket;\n            builder.Options.InitialSilosCount = 1;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n        }\n\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.Configure<ConnectionOptions>(options => options.OpenConnectionTimeout = Timeout);\n            }\n        }\n\n        public class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<ClientMessagingOptions>(options => options.ResponseTimeout = Timeout);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ConnectToGwAfterStallConnectionOpened()\n        {\n            Socket stalledSocket;\n            var gwEndpoint = this.HostedCluster.Primary.GatewayAddress.Endpoint;\n\n            // Close current client connection\n            await this.Client.ServiceProvider.GetRequiredService<IHost>().StopAsync();\n\n            // Stall connection to GW\n            using (stalledSocket = new Socket(gwEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))\n            {\n                await stalledSocket.ConnectAsync(gwEndpoint);\n\n                // Try to reconnect to GW\n                var stopwatch = Stopwatch.StartNew();\n                await this.HostedCluster.InitializeClientAsync();\n                stopwatch.Stop();\n\n                // Check that we were able to connect before the first connection timeout\n                Assert.True(stopwatch.Elapsed < Timeout);\n\n                stalledSocket.Disconnect(true);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task SiloJoinAfterStallConnectionOpened()\n        {\n            Socket stalledSocket;\n            var siloEndpoint = this.HostedCluster.Primary.SiloAddress.Endpoint;\n\n            // Stall connection to GW\n            using (stalledSocket = new Socket(siloEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))\n            {\n                await stalledSocket.ConnectAsync(siloEndpoint);\n\n                // Try to add a new silo in the cluster\n                this.HostedCluster.StartAdditionalSilo();\n\n                // Wait for the silo to join the cluster\n                Assert.True(await WaitForClusterSize(2));\n\n                stalledSocket.Disconnect(true);\n            }\n        }\n\n        private async Task<bool> WaitForClusterSize(int expectedSize)\n        {\n            var mgmtGrain = this.Client.GetGrain<IManagementGrain>(0);\n            var timeout = TestCluster.GetLivenessStabilizationTime(new Orleans.Configuration.ClusterMembershipOptions());\n            var stopWatch = Stopwatch.StartNew();\n            do\n            {\n                var hosts = await mgmtGrain.GetHosts();\n                if (hosts.Count == expectedSize)\n                {\n                    stopWatch.Stop();\n                    return true;\n                }\n                await Task.Delay(500);\n            }\n            while (stopWatch.Elapsed < timeout);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/CollectionFixtures.cs",
    "content": "﻿using TestExtensions;\nusing Xunit;\n\nnamespace Tester\n{\n    // Assembly collections must be defined once in each assembly\n    \n    /// <summary>\n    /// Defines a test collection for tests that require a default Orleans cluster setup.\n    /// Tests in this collection share a single cluster instance for improved performance.\n    /// </summary>\n    [CollectionDefinition(\"DefaultCluster\")]\n    public class DefaultClusterTestCollection : ICollectionFixture<DefaultClusterFixture> { }\n\n    /// <summary>\n    /// Defines a test collection for tests that require shared test environment configuration.\n    /// Provides core Orleans test environment setup and resources.\n    /// </summary>\n    [CollectionDefinition(TestEnvironmentFixture.DefaultCollection)]\n    public class TestEnvironmentFixtureCollection : ICollectionFixture<TestEnvironmentFixture> { }\n\n    /// <summary>\n    /// Base test cluster fixture for Azure-based integration tests.\n    /// Ensures Azure Storage connectivity is available before running tests.\n    /// </summary>\n    public abstract class BaseAzureTestClusterFixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForAzureStorage();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Directories/GrainDirectoryTests.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.Logging;\nusing Orleans.GrainDirectory;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.Directories;\n\n// Base tests for custom Grain Directory\npublic abstract class GrainDirectoryTests<TGrainDirectory> where TGrainDirectory : IGrainDirectory\n{\n    protected readonly ILoggerFactory loggerFactory;\n    private TGrainDirectory? _directory;\n\n    protected GrainDirectoryTests(ITestOutputHelper testOutput)\n    {\n        this.loggerFactory = new LoggerFactory();\n        this.loggerFactory.AddProvider(new XunitLoggerProvider(testOutput));\n    }\n\n    protected TGrainDirectory GrainDirectory => _directory ??= CreateGrainDirectory();\n\n    protected abstract TGrainDirectory CreateGrainDirectory();\n\n    [SkippableFact]\n    public async Task RegisterLookupUnregisterLookup()\n    {\n        var expected = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = GrainId.Parse(\"user/somerandomuser_\" + Guid.NewGuid().ToString(\"N\")),\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        Assert.Equal(expected, await GrainDirectory.Register(expected, null));\n\n        Assert.Equal(expected, await GrainDirectory.Lookup(expected.GrainId));\n\n        await GrainDirectory.Unregister(expected);\n\n        Assert.Null(await GrainDirectory.Lookup(expected.GrainId));\n    }\n\n    [SkippableFact]\n    public async Task DoNotOverwriteEntry()\n    {\n        var expected = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = GrainId.Parse(\"user/somerandomuser_\" + Guid.NewGuid().ToString(\"N\")),\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        var differentActivation = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = expected.GrainId,\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        var differentSilo = new GrainAddress\n        {\n            ActivationId = expected.ActivationId,\n            GrainId = expected.GrainId,\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.14:1000@4583\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        Assert.Equal(expected, await GrainDirectory.Register(expected, null));\n        Assert.Equal(expected, await GrainDirectory.Register(differentActivation, null));\n        Assert.Equal(expected, await GrainDirectory.Register(differentSilo, null));\n\n        Assert.Equal(expected, await GrainDirectory.Lookup(expected.GrainId));\n    }\n\n    /// <summary>\n    /// Overwrite an existing entry if the register call includes a matching \"previousAddress\" parameter.\n    /// </summary>\n    [SkippableFact]\n    public async Task OverwriteEntryIfMatch()\n    {\n        var initial = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = GrainId.Parse(\"user/somerandomuser_\" + Guid.NewGuid().ToString(\"N\")),\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        var differentActivation = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = initial.GrainId,\n            SiloAddress = initial.SiloAddress,\n            MembershipVersion = initial.MembershipVersion\n        };\n\n        var differentSilo = new GrainAddress\n        {\n            ActivationId = initial.ActivationId,\n            GrainId = initial.GrainId,\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.14:1000@4583\"),\n            MembershipVersion = initial.MembershipVersion\n        };\n\n        // Success, no registration exists, so the previous address is ignored.\n        Assert.Equal(initial, await GrainDirectory.Register(initial, differentSilo));\n\n        // Success, the previous address matches the existing registration.\n        Assert.Equal(differentActivation, await GrainDirectory.Register(differentActivation, initial));\n\n        // Failure, the previous address does not match the existing registration.\n        Assert.Equal(differentActivation, await GrainDirectory.Register(differentSilo, initial));\n\n        Assert.Equal(differentActivation, await GrainDirectory.Lookup(initial.GrainId));\n    }\n\n    [SkippableFact]\n    public async Task DoNotDeleteDifferentActivationIdEntry()\n    {\n        var expected = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = GrainId.Parse(\"user/somerandomuser_\" + Guid.NewGuid().ToString(\"N\")),\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        var otherEntry = new GrainAddress\n        {\n            ActivationId = ActivationId.NewId(),\n            GrainId = expected.GrainId,\n            SiloAddress = SiloAddress.FromParsableString(\"10.0.23.12:1000@5678\"),\n            MembershipVersion = new MembershipVersion(51)\n        };\n\n        Assert.Equal(expected, await GrainDirectory.Register(expected, null));\n        await GrainDirectory.Unregister(otherEntry);\n        Assert.Equal(expected, await GrainDirectory.Lookup(expected.GrainId));\n    }\n\n    [SkippableFact]\n    public async Task LookupNotFound()\n    {\n        Assert.Null(await GrainDirectory.Lookup(GrainId.Parse(\"user/somerandomuser_\" + Guid.NewGuid().ToString(\"N\"))));\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Directories/MultipleGrainDirectoriesTests.cs",
    "content": "using Orleans.Internal;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces.Directories;\nusing Xunit;\n\nnamespace Tester.Directories\n{\n    /// <summary>\n    /// Base class for testing multiple grain directory implementations across cluster silos.\n    /// </summary>\n    public abstract class MultipleGrainDirectoriesTests : TestClusterPerTest\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 2;\n        }\n\n        [SkippableFact, TestCategory(\"Directory\"), TestCategory(\"Functional\")]\n        public async Task PingGrain()\n        {\n            var grainOnPrimary = await GetGrainOnPrimary().WaitAsync(TimeSpan.FromSeconds(5));\n            var grainOnSecondary = await GetGrainOnSecondary().WaitAsync(TimeSpan.FromSeconds(5));\n\n            // Setup\n            var primaryCounter = await grainOnPrimary.Ping();\n            var secondaryCounter = await grainOnSecondary.Ping();\n\n            // Each silo see the activation on the other silo\n            Assert.Equal(++primaryCounter, await grainOnSecondary.ProxyPing(grainOnPrimary));\n            Assert.Equal(++secondaryCounter, await grainOnPrimary.ProxyPing(grainOnSecondary));\n\n            await Task.Delay(5000);\n\n            // Shutdown the secondary silo\n            await this.HostedCluster.StopSecondarySilosAsync();\n\n            // Activation on the primary silo should still be there, another activation should be\n            // created for the other one\n            Assert.Equal(++primaryCounter, await grainOnPrimary.Ping());\n            Assert.Equal(1, await grainOnSecondary.Ping());\n        }\n\n        private async Task<ICustomDirectoryGrain> GetGrainOnPrimary()\n        {\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, HostedCluster.Primary.SiloAddress);\n                var grain = this.GrainFactory.GetGrain<ICustomDirectoryGrain>(Guid.NewGuid());\n                var instanceId = await grain.GetRuntimeInstanceId();\n                if (instanceId.Contains(HostedCluster.Primary.SiloAddress.Endpoint.ToString()))\n                    return grain;\n            }\n        }\n\n        private async Task<ICustomDirectoryGrain> GetGrainOnSecondary()\n        {\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, HostedCluster.SecondarySilos[0].SiloAddress);\n                var grain = this.GrainFactory.GetGrain<ICustomDirectoryGrain>(Guid.NewGuid());\n                var instanceId = await grain.GetRuntimeInstanceId();\n                if (instanceId.Contains(HostedCluster.SecondarySilos[0].SiloAddress.Endpoint.ToString()))\n                    return grain;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/DuplicateActivationsTests.cs",
    "content": "using Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CatalogTests\n{\n    /// <summary>\n    /// Tests the Orleans catalog's ability to prevent duplicate grain activations under high concurrency.\n    /// \n    /// Orleans guarantees single activation semantics - each grain ID should have at most one activation\n    /// in the cluster at any time. This test stress-tests this guarantee by having multiple runner grains\n    /// simultaneously make calls to the same set of target grains.\n    /// \n    /// The catalog is responsible for ensuring that concurrent activation requests for the same grain\n    /// don't result in multiple activations within a single silo.\n    /// </summary>\n    public class DuplicateActivationsTests : IClassFixture<DuplicateActivationsTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n        }\n\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                // Increase response timeout to accommodate the high load during stress testing\n                // This prevents timeouts that could interfere with duplicate activation detection\n                hostBuilder.Configure<SiloMessagingOptions>(options => options.ResponseTimeout = TimeSpan.FromMinutes(1));\n            }\n        }\n\n\n        public DuplicateActivationsTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Stress test for duplicate activation prevention.\n        /// Creates 100 runner grains that each make 100 calls to 10 target grains.\n        /// This generates 10,000 concurrent requests to just 10 grains, creating\n        /// extreme contention that tests the catalog's synchronization mechanisms.\n        /// \n        /// If duplicate activations occur, the target grains will detect this and throw exceptions.\n        /// The test passes only if all calls complete without any duplicate activation errors.\n        /// </summary>\n        [Fact, TestCategory(\"Catalog\"), TestCategory(\"Functional\")]\n        public async Task DuplicateActivations()\n        {\n            const int nRunnerGrains = 100;    // Number of grains making concurrent calls\n            const int nTargetGrain = 10;      // Number of target grains (high contention)\n            const int startingKey = 1000;     // Starting grain ID for target grains\n            const int nCallsToEach = 100;     // Calls each runner makes to each target\n\n            var runnerGrains = new ICatalogTestGrain[nRunnerGrains];\n\n            // Phase 1: Initialize all runner grains\n            // Using negative IDs for runners to avoid collision with target grain IDs\n            var promises = new List<Task>(nRunnerGrains);\n            for (int i = 0; i < nRunnerGrains; i++)\n            {\n                runnerGrains[i] = this.fixture.GrainFactory.GetGrain<ICatalogTestGrain>(-i);\n                promises.Add(runnerGrains[i].Initialize());\n            }\n\n            await Task.WhenAll(promises);\n            promises.Clear();\n\n            // Phase 2: All runners simultaneously blast calls to the same target grains\n            // This creates massive concurrent activation pressure on the catalog\n            for (int i = 0; i < nRunnerGrains; i++)\n            {\n                promises.Add(runnerGrains[i].BlastCallNewGrains(nTargetGrain, startingKey, nCallsToEach));\n            }\n\n            // If any duplicate activations occur, the grains will detect and report them\n            await Task.WhenAll(promises);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ExceptionPropagationTests.cs",
    "content": "using TestExtensions;\n\nusing UnitTests.GrainInterfaces;\n\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Comprehensive tests for exception propagation across Orleans' distributed system boundaries.\n    /// \n    /// Orleans must correctly propagate exceptions from grains back to callers, preserving:\n    /// - Original exception types and messages\n    /// - Stack traces from the remote grain (critical for debugging distributed systems)\n    /// - AggregateException structure (not unwrapped)\n    /// - Task cancellation semantics\n    /// \n    /// These tests also verify exception propagation during serialization/deserialization failures,\n    /// which can occur at multiple points:\n    /// - Client -> Grain (request/response)\n    /// - Grain -> Client (callbacks)\n    /// - Grain -> Grain (cross-silo calls)\n    /// \n    /// Proper exception handling is crucial for debugging and maintaining distributed applications.\n    /// </summary>\n    public class ExceptionPropagationTests : OrleansTestingBase, IClassFixture<ExceptionPropagationTests.Fixture>\n    {\n        private const int TestIterations = 3;\n        private readonly ITestOutputHelper output;\n        private readonly Fixture fixture;\n        private readonly IMessageSerializationGrain exceptionGrain;\n        private readonly MessageSerializationClientObject clientObject = new MessageSerializationClientObject();\n        private readonly IMessageSerializationClientObject clientObjectRef;\n\n        public ExceptionPropagationTests(ITestOutputHelper output, Fixture fixture)\n        {\n            this.output = output;\n            this.fixture = fixture;\n\n            var grainFactory = (IInternalGrainFactory)this.fixture.GrainFactory;\n            this.exceptionGrain = grainFactory.GetGrain<IMessageSerializationGrain>(GetRandomGrainId());\n            this.clientObjectRef = grainFactory.CreateObjectReference<IMessageSerializationClientObject>(this.clientObject);\n        }\n\n        public class Fixture : BaseTestClusterFixture\n        {\n        }\n\n        /// <summary>\n        /// Verifies that different exception types thrown by grains are correctly\n        /// propagated to the calling client with their original type and message intact.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ExceptionsPropagatedFromGrainToClient()\n        {\n            var grain = this.fixture.Client.GetGrain<IExceptionGrain>(0);\n\n            var invalidOperationException = await Assert.ThrowsAsync<InvalidOperationException>(() => grain.ThrowsInvalidOperationException());\n            Assert.Equal(\"Test exception\", invalidOperationException.Message);\n\n            var nullReferenceException = await Assert.ThrowsAsync<NullReferenceException>(() => grain.ThrowsNullReferenceException());\n            Assert.Equal(\"null null null\", nullReferenceException.Message);\n        }\n\n        /// <summary>\n        /// Basic test ensuring that exceptions thrown in grain methods\n        /// are propagated back to the caller as the same exception type.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task BasicExceptionPropagation()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var exception = await Assert.ThrowsAsync<InvalidOperationException>(\n                () => grain.ThrowsInvalidOperationException());\n\n            output.WriteLine(exception.ToString());\n            Assert.Equal(\"Test exception\", exception.Message);\n        }\n\n        /// <summary>\n        /// Critical test verifying that remote stack traces are preserved in propagated exceptions.\n        /// When debugging distributed systems, it's essential to see where the exception originated\n        /// in the remote grain, not just where it was received in the client.\n        /// Uses .Wait() to get the raw AggregateException without any async state machine modifications.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ExceptionContainsOriginalStackTrace()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n\n            // Explicitly using .Wait() instead of await the task to avoid any modification of the inner exception\n            var originalException = await Task.Run(() => {\n                try\n                {\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                    grain.ThrowsInvalidOperationException().Wait();\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                    return null;\n                }\n                catch (Exception exception)\n                {\n                    return exception;\n                }\n            });\n            var aggEx = Assert.IsType<AggregateException>(originalException);\n\n            var exception = aggEx.InnerException;\n            output.WriteLine(exception.ToString());\n            Assert.IsAssignableFrom<InvalidOperationException>(exception);\n            Assert.Equal(\"Test exception\", exception.Message);\n            Assert.Contains(\"ThrowsInvalidOperationException\", exception.StackTrace);\n        }\n\n        /// <summary>\n        /// Verifies that even when using async/await (which rethrows exceptions),\n        /// the original remote stack trace is still preserved in the exception.\n        /// This is important for maintaining debuggability in async code.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ExceptionContainsOriginalStackTraceWhenRethrowingLocally()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            try\n            {\n                // Use await to force the exception to be rethrown and validate that the remote stack trace is still present\n                await grain.ThrowsInvalidOperationException();\n                Assert.Fail(\"should have thrown\");\n            }\n            catch (InvalidOperationException exception)\n            {\n                output.WriteLine(exception.ToString());\n                Assert.IsAssignableFrom<InvalidOperationException>(exception);\n                Assert.Equal(\"Test exception\", exception.Message);\n                Assert.Contains(\"ThrowsInvalidOperationException\", exception.StackTrace);\n            }\n        }\n\n        /// <summary>\n        /// Ensures that AggregateExceptions thrown by grains are NOT unwrapped during propagation.\n        /// This preserves the original exception structure, which may be important for error handling\n        /// logic that expects specific exception hierarchies.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ExceptionPropagationDoesNotUnwrapAggregateExceptions()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var exception = await Assert.ThrowsAsync<AggregateException>(\n                () => grain.ThrowsAggregateExceptionWrappingInvalidOperationException());\n\n            var nestedEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\"Test exception\", nestedEx.Message);\n        }\n\n        /// <summary>\n        /// Tests that nested AggregateExceptions maintain their structure during propagation.\n        /// Orleans does not flatten the exception hierarchy, preserving the original nesting\n        /// that may have semantic meaning in the application.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task ExceptionPropagationDoesNoFlattenAggregateExceptions()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var exception = await Assert.ThrowsAsync<AggregateException>(\n                () => grain.ThrowsNestedAggregateExceptionsWrappingInvalidOperationException());\n\n            var nestedAggEx = Assert.IsAssignableFrom<AggregateException>(exception.InnerException);\n            var doubleNestedEx = Assert.IsAssignableFrom<InvalidOperationException>(nestedAggEx.InnerException);\n            Assert.Equal(\"Test exception\", doubleNestedEx.Message);\n        }\n\n        /// <summary>\n        /// Verifies that task cancellation is properly propagated as TaskCanceledException.\n        /// This is important for cooperative cancellation patterns in distributed systems.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task TaskCancelationPropagation()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            await Assert.ThrowsAsync<TaskCanceledException>(\n                () => grain.Canceled());\n        }\n\n        /// <summary>\n        /// Tests exception propagation through grain-to-grain calls.\n        /// When grain A calls grain B, and grain B throws an exception,\n        /// the exception should propagate back through grain A to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task GrainForwardingExceptionPropagation()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var otherGrainId = GetRandomGrainId();\n            var exception = await Assert.ThrowsAsync<InvalidOperationException>(\n                () => grain.GrainCallToThrowsInvalidOperationException(otherGrainId));\n\n            Assert.Equal(\"Test exception\", exception.Message);\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task GrainForwardingExceptionPropagationDoesNotUnwrapAggregateExceptions()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var otherGrainId = GetRandomGrainId();\n            var exception = await Assert.ThrowsAsync<AggregateException>(\n                () => grain.GrainCallToThrowsAggregateExceptionWrappingInvalidOperationException(otherGrainId));\n\n            var nestedEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\"Test exception\", nestedEx.Message);\n        }\n\n        /// <summary>\n        /// Ensures that exceptions thrown synchronously in grain methods (before any await)\n        /// still result in a faulted Task rather than throwing synchronously to the caller.\n        /// This maintains consistent async behavior regardless of where exceptions occur.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task SynchronousExceptionThrownShouldResultInFaultedTask()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n\n            // start the grain call but don't await it nor wrap in try/catch, to make sure it doesn't throw synchronously\n            var grainCallTask = grain.ThrowsSynchronousInvalidOperationException();\n\n            var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => grainCallTask);\n\n            Assert.Equal(\"Test exception\", exception.Message);\n\n            var grainCallTask2 = grain.ThrowsSynchronousInvalidOperationException();\n            var exception2 = await Assert.ThrowsAsync<InvalidOperationException>(() => grainCallTask2);\n            Assert.Equal(\"Test exception\", exception2.Message);\n        }\n\n        /// <summary>\n        /// Tests that when a Task is faulted with multiple exceptions, all exceptions\n        /// are propagated in the AggregateException, not just the first one.\n        /// This is currently skipped pending implementation of issue #1378.\n        /// </summary>\n        [Fact(Skip = \"Implementation of issue #1378 is still pending\"), TestCategory(\"BVT\")]\n        public async Task ExceptionPropagationForwardsEntireAggregateException()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n            var grainCall = grain.ThrowsMultipleExceptionsAggregatedInFaultedTask();\n\n            var originalException = await Task.Run(() =>\n            {\n                try\n                {\n#pragma warning disable xUnit1031 // Do not use blocking task operations in test method\n                    // use Wait() so that we get the entire AggregateException ('await' would just catch the first inner exception)\n                    // Do not use Assert.Throws to avoid any tampering of the AggregateException itself from the test framework\n                    grainCall.Wait();\n#pragma warning restore xUnit1031 // Do not use blocking task operations in test method\n                    return null;\n                }\n                catch (Exception exception)\n                {\n                    return exception;\n                }\n            });\n            var exception = Assert.IsType<AggregateException>(originalException);\n\n            output.WriteLine(exception.ToString());\n\n            // make sure that all exceptions in the task are present, and not just the first one.\n            Assert.Equal(2, exception.InnerExceptions.Count);\n            var firstEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerExceptions[0]);\n            Assert.Equal(\"Test exception 1\", firstEx.Message);\n            var secondEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerExceptions[1]);\n            Assert.Equal(\"Test exception 2\", secondEx.Message);\n        }\n\n        [Fact, TestCategory(\"BVT\")]\n        public async Task SynchronousAggregateExceptionThrownShouldResultInFaultedTaskWithOriginalAggregateExceptionUnmodifiedAsInnerException()\n        {\n            IExceptionGrain grain = this.fixture.GrainFactory.GetGrain<IExceptionGrain>(GetRandomGrainId());\n\n            // start the grain call but don't await it nor wrap in try/catch, to make sure it doesn't throw synchronously\n            var grainCallTask = grain.ThrowsSynchronousAggregateExceptionWithMultipleInnerExceptions();\n\n            // assert that the faulted task has an inner exception of type AggregateException, which should be our original exception\n            var exception = await Assert.ThrowsAsync<AggregateException>(() => grainCallTask);\n\n            Assert.StartsWith(\"Test AggregateException message\", exception.Message);\n\n            // make sure that all exceptions in the task are present, and not just the first one.\n            Assert.Equal(2, exception.InnerExceptions.Count);\n            var firstEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerExceptions[0]);\n            Assert.Equal(\"Test exception 1\", firstEx.Message);\n            var secondEx = Assert.IsAssignableFrom<InvalidOperationException>(exception.InnerExceptions[1]);\n            Assert.Equal(\"Test exception 2\", secondEx.Message);\n        }\n\n        /// <summary>\n        /// Tests exception propagation when a client cannot deserialize a request from a grain.\n        /// This scenario occurs when a grain makes a callback to a client observer, but the\n        /// request contains types that cannot be deserialized on the client side.\n        /// The serialization failure should be detected and propagated back to the grain.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsClient_Request_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUndeserializableToClient(this.clientObjectRef));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a client cannot serialize a response to a grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsClient_Response_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.GetUnserializableFromClient(this.clientObjectRef));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot deserialize a response from a client, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsClient_Response_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.GetUndeserializableFromClient(this.clientObjectRef));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot serialize a request to a client, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsClient_Request_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUnserializableToClient(this.clientObjectRef));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests exception propagation for grain-to-grain calls when deserialization fails.\n        /// This can happen in cross-silo scenarios where grains have incompatible type versions\n        /// or when using custom serializers that fail. The exception should propagate back\n        /// through the call chain to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsGrain_Request_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUndeserializableToOtherSilo());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot serialize a request to another grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsGrain_Request_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUnserializableToOtherSilo());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot serialize a response to another grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsGrain_Response_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.GetUnserializableFromOtherSilo());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot deserialize a response from another grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_GrainCallsGrain_Response_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.GetUndeserializableFromOtherSilo());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests the most common serialization failure scenario: client sends a request\n        /// that the grain cannot deserialize. This validates that Orleans properly detects\n        /// the failure and sends an appropriate exception back to the client rather than\n        /// silently failing or hanging.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_ClientCallsGrain_Request_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUndeserializable(new UndeserializableType(32)));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a client cannot serialize a request to a grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_ClientCallsGrain_Request_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<NotSupportedException>(() => exceptionGrain.SendUnserializable(new UnserializableType()));\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a grain cannot serialize a response to a client, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_ClientCallsGrain_Response_Serialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<Exception>(() => exceptionGrain.GetUnserializable());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        /// <summary>\n        /// Tests that when a client cannot deserialize a response from a grain, an exception is promptly propagated back to the original caller.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Messaging\"), TestCategory(\"Serialization\")]\n        public async Task ExceptionPropagation_ClientCallsGrain_Response_Deserialization_Failure()\n        {\n            for (var i = 0; i < TestIterations; i++)\n            {\n                var exception = await Assert.ThrowsAnyAsync<Exception>(() => exceptionGrain.GetUndeserializable());\n                Assert.Contains(UndeserializableType.FailureMessage, exception.Message);\n            }\n        }\n\n        private class MessageSerializationClientObject : IMessageSerializationClientObject\n        {\n            public Task SendUndeserializable(UndeserializableType input) => Task.FromResult(input);\n            public Task SendUnserializable(UnserializableType input) => Task.FromResult(input);\n            public Task<UnserializableType> GetUnserializable() => Task.FromResult(new UnserializableType());\n            public Task<UndeserializableType> GetUndeserializable() => Task.FromResult(new UndeserializableType(35));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Forwarding/ShutdownSiloTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Orleans.Configuration;\nusing System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Azure.Data.Tables;\nusing Azure.Identity;\nusing Orleans.Runtime.Placement;\n\nnamespace Tester.Forwarding\n{\n    /// <summary>\n    /// Tests for silo shutdown scenarios including request forwarding, timer handling, and stuck activations.\n    /// </summary>\n    public class ShutdownSiloTests : TestClusterPerTest\n    {\n        public const int NumberOfSilos = 2;\n\n        public static readonly TimeSpan DeactivationTimeout = TimeSpan.FromSeconds(10);\n        internal class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .Configure<GrainCollectionOptions>(options =>\n                    {\n                        options.DeactivationTimeout = DeactivationTimeout;\n                    })\n                    .UseAzureStorageClustering(options => options.TableServiceClient = GetTableServiceClient())\n                    .ConfigureServices(services => services.AddSingleton<PlacementStrategy, ActivationCountBasedPlacement>())\n                    .Configure<ClusterMembershipOptions>(options =>\n                    {\n                        options.NumMissedProbesLimit = 1;\n                        options.NumVotesForDeathDeclaration = 1;\n                    });\n            }\n\n            private static TableServiceClient GetTableServiceClient()\n            {\n                return TestDefaultConfiguration.UseAadAuthentication\n                    ? new(TestDefaultConfiguration.TableEndpoint, TestDefaultConfiguration.TokenCredential)\n                    : new(TestDefaultConfiguration.DataConnectionString);\n            }\n        }\n\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForAzureStorage();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = NumberOfSilos;\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        }\n\n        public ShutdownSiloTests()\n        {\n            this.EnsurePreconditionsMet();\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/6423\"), TestCategory(\"Forward\"), TestCategory(\"Functional\")]\n        public async Task SiloGracefulShutdown_ForwardPendingRequest()\n        {\n            var grain = await GetLongRunningTaskGrainOnSecondary<bool>();\n\n            var tasks = new List<Task<string>>();\n            for (int i = 0; i < 100; i++)\n            {\n                tasks.Add(grain.GetRuntimeInstanceIdWithDelay(TimeSpan.FromMilliseconds(50)));\n            }\n\n            // Shutdown the silo where the grain is\n            await Task.Delay(500);\n            await HostedCluster.StopSiloAsync(HostedCluster.SecondarySilos.First());\n\n            var results = await Task.WhenAll(tasks);\n            Assert.Equal(results[99], HostedCluster.Primary.SiloAddress.ToString());\n        }\n\n        [SkippableFact, TestCategory(\"GracefulShutdown\"), TestCategory(\"Functional\")]\n        public async Task SiloGracefulShutdown_PendingRequestTimers()\n        {\n            var grain = await GetTimerRequestGrainOnSecondary();\n\n            var promise = grain.StartAndWaitTimerTick(TimeSpan.FromSeconds(10));\n\n            await Task.Delay(500);\n            await HostedCluster.StopSiloAsync(HostedCluster.SecondarySilos.First());\n\n            await promise;\n        }\n\n        [SkippableFact, TestCategory(\"GracefulShutdown\"), TestCategory(\"Functional\")]\n        public async Task SiloGracefulShutdown_StuckTimers()\n        {\n            var grain = await GetTimerRequestGrainOnSecondary();\n\n            await grain.StartStuckTimer(TimeSpan.Zero);\n\n            await Task.Delay(TimeSpan.FromSeconds(1));\n            var stopwatch = Stopwatch.StartNew();\n            await HostedCluster.StopSiloAsync(HostedCluster.SecondarySilos.First());\n            stopwatch.Stop();\n\n            Assert.True(stopwatch.Elapsed > DeactivationTimeout);\n        }\n\n        [SkippableFact, TestCategory(\"GracefulShutdown\"), TestCategory(\"Functional\")]\n        public async Task SiloGracefulShutdown_StuckActivation()\n        {\n            var grain = await GetTimerRequestGrainOnSecondary();\n            _ = grain.StartAndWaitTimerTick(TimeSpan.FromMinutes(2));\n\n            await Task.Delay(500);\n            var stopwatch = Stopwatch.StartNew();\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n            await HostedCluster.SecondarySilos.First().StopSiloAsync(cts.Token);\n            stopwatch.Stop();\n            Assert.True(stopwatch.Elapsed < TimeSpan.FromMinutes(1));\n        }\n\n        private async Task<ILongRunningTaskGrain<T>> GetLongRunningTaskGrainOnSecondary<T>()\n        {\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, HostedCluster.SecondarySilos[0].SiloAddress);\n                var grain = GrainFactory.GetGrain<ILongRunningTaskGrain<T>>(Guid.NewGuid());\n                var instanceId = await grain.GetRuntimeInstanceId();\n                if (instanceId.Contains(HostedCluster.SecondarySilos[0].SiloAddress.Endpoint.ToString()))\n                {\n                    return grain;\n                }\n            }\n        }\n\n        private async Task<ITimerRequestGrain> GetTimerRequestGrainOnSecondary()\n        {\n            var i = 0;\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, HostedCluster.SecondarySilos[0].SiloAddress);\n                var grain = GrainFactory.GetGrain<ITimerRequestGrain>(i++);\n                var instanceId = await grain.GetRuntimeInstanceId();\n                if (instanceId.Contains(HostedCluster.SecondarySilos[0].SiloAddress.Endpoint.ToString()))\n                {\n                    return grain;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/GrainActivatorTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Orleans.Metadata;\n\nnamespace UnitTests.General\n{\n    /// <summary>\n    /// Tests for custom grain activators, which allow complete control over grain instantiation and disposal.\n    /// \n    /// Orleans uses IGrainActivator to create and destroy grain instances. By default, it uses\n    /// dependency injection, but applications can provide custom activators for scenarios like:\n    /// - Object pooling for expensive grain instances\n    /// - Custom initialization logic that can't be done in constructors\n    /// - Integration with third-party DI containers\n    /// - Specialized cleanup during grain deactivation\n    /// \n    /// This test demonstrates implementing a custom activator that bypasses DI entirely\n    /// and tracks the number of disposed instances.\n    /// </summary>\n    [TestCategory(\"DI\")]\n    public class GrainActivatorTests : OrleansTestingBase, IClassFixture<GrainActivatorTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n            }\n\n            private class TestSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.ConfigureServices(services =>\n                    {\n                        // Register our custom grain activator as a grain type component configurator\n                        // This allows it to selectively apply to specific grain types\n                        services.AddSingleton<IConfigureGrainTypeComponents, HardcodedGrainActivator>();\n                    });\n                }\n            }\n        }\n\n        public GrainActivatorTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Verifies that custom grain activators can create grain instances without using DI.\n        /// The custom activator injects a hardcoded value that proves it was used instead\n        /// of the default DI-based activation.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task CanUseCustomGrainActivatorToCreateGrains()\n        {\n            ISimpleDIGrain grain = this.fixture.GrainFactory.GetGrain<ISimpleDIGrain>(GetRandomGrainId(), grainClassNamePrefix: \"UnitTests.Grains.ExplicitlyRegistered\");\n            var actual = await grain.GetStringValue();\n            Assert.Equal(HardcodedGrainActivator.HardcodedValue, actual);\n        }\n\n        /// <summary>\n        /// Tests that custom grain activators receive disposal notifications when grains are deactivated.\n        /// This is critical for resource cleanup scenarios like returning objects to pools,\n        /// closing connections, or updating metrics. The test verifies the disposal count\n        /// increases after explicit deactivation.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\")]\n        public async Task CanUseCustomGrainActivatorToReleaseGrains()\n        {\n            ISimpleDIGrain grain1 = this.fixture.GrainFactory.GetGrain<ISimpleDIGrain>(GetRandomGrainId(), grainClassNamePrefix: \"UnitTests.Grains.ExplicitlyRegistered\");\n            long initialReleasedInstances = await grain1.GetLongValue();\n\n            ISimpleDIGrain grain2 = this.fixture.GrainFactory.GetGrain<ISimpleDIGrain>(GetRandomGrainId(), grainClassNamePrefix: \"UnitTests.Grains.ExplicitlyRegistered\");\n            long secondReleasedInstances = await grain2.GetLongValue();\n\n            Assert.Equal(initialReleasedInstances, secondReleasedInstances);\n\n            await grain1.DoDeactivate();\n            await Task.Delay(250);\n\n            ISimpleDIGrain grain3 = this.fixture.GrainFactory.GetGrain<ISimpleDIGrain>(GetRandomGrainId(), grainClassNamePrefix: \"UnitTests.Grains.ExplicitlyRegistered\");\n            long finalReleasedInstances = await grain3.GetLongValue();\n            Assert.Equal(initialReleasedInstances + 1, finalReleasedInstances);\n        }\n\n        /// <summary>\n        /// Custom grain activator that bypasses dependency injection entirely.\n        /// Implements both IGrainActivator (for creation/disposal) and IConfigureGrainTypeComponents\n        /// (to register itself for specific grain types). This demonstrates how to:\n        /// - Create grains with custom logic instead of DI\n        /// - Track lifecycle events like disposal\n        /// - Selectively apply to specific grain types using the grain class map\n        /// </summary>\n        private class HardcodedGrainActivator : IGrainActivator, IConfigureGrainTypeComponents\n        {\n            public const string HardcodedValue = \"Hardcoded Test Value\";\n            private readonly GrainClassMap _grainClassMap;\n            private int _released;  // Tracks number of disposed grain instances\n\n            public HardcodedGrainActivator(GrainClassMap grainClassMap)\n            {\n                _grainClassMap = grainClassMap;\n            }\n\n            public void Configure(GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared)\n            {\n                // Selectively register this activator only for ExplicitlyRegisteredSimpleDIGrain types\n                // Other grain types will continue using the default DI-based activator\n                if (_grainClassMap.TryGetGrainClass(grainType, out var grainClass) && grainClass.IsAssignableFrom(typeof(ExplicitlyRegisteredSimpleDIGrain)))\n                {\n                    shared.SetComponent<IGrainActivator>(this);\n                }\n            }\n\n            public object CreateInstance(IGrainContext context)\n            {\n                // Custom instantiation logic - creates grain with hardcoded dependencies\n                // In real scenarios, this could get objects from a pool, perform complex\n                // initialization, or integrate with external systems\n                return new ExplicitlyRegisteredSimpleDIGrain(new InjectedService(NullLoggerFactory.Instance), HardcodedValue, _released);\n            }\n\n            public ValueTask DisposeInstance(IGrainContext context, object instance)\n            {\n                // Called when grain is deactivated - perfect for cleanup, returning to pools,\n                // or updating metrics. The count allows tests to verify disposal happened.\n                ++_released;\n                return default;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/GrainCallFilterTests.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Orleans.Providers;\nusing System.Diagnostics;\n\nnamespace UnitTests.General\n{\n    internal interface IMyRegularInterface\n    {\n        [Alias(\"Set\")]\n        ValueTask SetExtensionValue(int value);\n\n        [Alias(\"Get\")]\n        ValueTask<int> GetExtensionValue();\n    }\n\n    internal interface IMyOtherInterface\n    {\n        [Alias(\"Set\")]\n        ValueTask SetExtensionValue(int value);\n\n        [Alias(\"Get\")]\n        ValueTask<int> GetExtensionValue();\n    }\n\n    internal interface IMyGrainExtension : IGrainExtension, IMyRegularInterface, IMyOtherInterface\n    {\n    }\n\n    internal sealed class MyGrainExtension : IMyGrainExtension\n    {\n        private int _value;\n\n        ValueTask<int> IMyRegularInterface.GetExtensionValue() => new(_value);\n\n        public ValueTask SetExtensionValue(int value)\n        {\n            _value = value;\n            return default;\n        }\n\n        ValueTask<int> IMyOtherInterface.GetExtensionValue() => new(100 + _value);\n    }\n\n    /// <summary>\n    /// Comprehensive tests for Orleans grain call filters (interceptors).\n    /// \n    /// Grain call filters provide AOP-style interception of grain method calls, enabling:\n    /// - Cross-cutting concerns (logging, monitoring, security)\n    /// - Request/response manipulation\n    /// - Retry logic and error handling\n    /// - Method call metrics and tracing\n    /// \n    /// Orleans supports both incoming filters (executed on the target grain/silo) and\n    /// outgoing filters (executed on the calling grain/client). Filters can be registered:\n    /// - System-wide (all grains)\n    /// - Per-grain-type\n    /// \n    /// These tests verify filter execution order, context propagation, exception handling,\n    /// and integration with various Orleans features like streaming and observers.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"GrainCallFilter\")]\n    public class GrainCallFilterTests : OrleansTestingBase, IClassFixture<GrainCallFilterTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n                builder.AddSiloBuilderConfigurator<SiloInvokerTestSiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<ClientConfigurator>();\n            }\n\n            private class SiloInvokerTestSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddGrainExtension<IMyGrainExtension, MyGrainExtension>()\n                        // System-wide incoming filter - executes for ALL grain calls on this silo\n                        .AddIncomingGrainCallFilter(context =>\n                        {\n                            Assert.NotNull(context);\n                            Assert.NotNull(context.InterfaceMethod);\n                            Assert.NotNull(context.Grain);\n                            Assert.NotNull(context.ImplementationMethod);\n                            Assert.NotNull(context.TargetContext);\n                            Assert.NotEmpty(context.InterfaceName);\n                            Assert.NotEmpty(context.MethodName);\n                            Assert.False(context.TargetId.IsDefault);\n                            Assert.False(context.InterfaceType.IsDefault);\n\n                            // Test 1: Verify RequestContext propagation through filters\n                            // Each filter adds a digit to build up \"1234\"\n                            if (string.Equals(context.InterfaceMethod.Name, nameof(IGrainCallFilterTestGrain.GetRequestContext)))\n                            {\n                                if (RequestContext.Get(GrainCallFilterTestConstants.Key) != null) throw new InvalidOperationException();\n                                RequestContext.Set(GrainCallFilterTestConstants.Key, \"1\");\n                            }\n\n                            // Test 2: Verify behavior when filter doesn't call context.Invoke()\n                            // This should result in an InvalidOperationException for the caller\n                            if (string.Equals(context.InterfaceMethod.Name, nameof(IGrainCallFilterTestGrain.SystemWideCallFilterMarker)))\n                            {\n                                // explicitly do not continue calling Invoke\n                                return Task.CompletedTask;\n                            }\n\n                            // Test 3: Demonstrate request manipulation - negate the value\n                            // This shows filters can modify method arguments before execution\n                            if (string.Equals(context.InterfaceMethod.Name, nameof(IMyGrainExtension.SetExtensionValue)))\n                            {\n                                context.Request.SetArgument(0, (int)context.Request.GetArgument(0) * -1);\n                            }\n\n                            return context.Invoke();\n                        })\n                        .AddIncomingGrainCallFilter<GrainCallFilterWithDependencies>()\n                        // System-wide outgoing filter - executes when this silo calls other grains\n                        .AddOutgoingGrainCallFilter(async ctx =>\n                        {\n                            // Modify outgoing Echo calls by doubling the string argument\n                            if (ctx.InterfaceMethod?.Name == \"Echo\")\n                            {\n                                // Concatenate the input to itself.\n                                var orig = (string)ctx.Request.GetArgument(0);\n                                ctx.Request.SetArgument(0, orig + orig);\n                            }\n\n                            if (string.Equals(ctx.InterfaceMethod?.Name, nameof(IMethodInterceptionGrain.SystemWideCallFilterMarker)))\n                            {\n                                // explicitly do not continue calling Invoke\n                                return;\n                            }\n\n                            await ctx.Invoke();\n                        })\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(\"SMSProvider\")\n                        .AddMemoryGrainStorageAsDefault()\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n            private class ClientConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder\n                        .AddIncomingGrainCallFilter(context =>\n                        {\n                            Assert.NotNull(context);\n                            Assert.NotNull(context.InterfaceMethod);\n                            Assert.NotNull(context.Grain);\n                            Assert.NotNull(context.ImplementationMethod);\n                            Assert.NotNull(context.TargetContext);\n                            Assert.NotEmpty(context.InterfaceName);\n                            Assert.NotEmpty(context.MethodName);\n                            Assert.False(context.TargetId.IsDefault);\n                            Assert.False(context.InterfaceType.IsDefault);\n\n                            if (string.Equals(context.InterfaceMethod.Name, nameof(IGrainCallFilterTestGrainObserver.GetRequestContext)))\n                            {\n                                if (RequestContext.Get(GrainCallFilterTestConstants.Key) != null) throw new InvalidOperationException();\n                                RequestContext.Set(GrainCallFilterTestConstants.Key, \"1\");\n                            }\n\n                            if (string.Equals(context.InterfaceMethod.Name, nameof(IGrainCallFilterTestGrainObserver.SystemWideCallFilterMarker)))\n                            {\n                                // explicitly do not continue calling Invoke\n                                return Task.CompletedTask;\n                            }\n\n                            return context.Invoke();\n                        })\n                        .AddIncomingGrainCallFilter<GrainCallFilterWithDependencies>()\n                        .AddOutgoingGrainCallFilter(RetryCertainCalls)\n                        .AddOutgoingGrainCallFilter(async context =>\n                        {\n                            Assert.NotNull(context);\n                            Assert.NotNull(context.InterfaceMethod);\n                            Assert.NotNull(context.Grain);\n                            Assert.NotEmpty(context.InterfaceName);\n                            Assert.NotEmpty(context.MethodName);\n                            Assert.False(context.TargetId.IsDefault);\n                            Assert.False(context.InterfaceType.IsDefault);\n                            if (context.InterfaceMethod?.DeclaringType == typeof(IOutgoingMethodInterceptionGrain)\n                                && context.InterfaceMethod?.Name == nameof(IOutgoingMethodInterceptionGrain.EchoViaOtherGrain))\n                            {\n                                context.Request.SetArgument(1, ((string)context.Request.GetArgument(1)).ToUpperInvariant());\n                            }\n\n                            await context.Invoke();\n\n                            if (context.InterfaceMethod?.DeclaringType == typeof(IOutgoingMethodInterceptionGrain)\n                                && context.InterfaceMethod?.Name == nameof(IOutgoingMethodInterceptionGrain.EchoViaOtherGrain))\n                            {\n                                var result = (Dictionary<string, object>)context.Result;\n                                result[\"orig\"] = result[\"result\"];\n                                result[\"result\"] = \"intercepted!\";\n                            }\n                        })\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(\"SMSProvider\");\n\n                    // Demonstrates retry logic in outgoing filters\n                    // This filter retries failed calls by modifying the argument\n                    static async Task RetryCertainCalls(IOutgoingGrainCallContext ctx)\n                    {\n                        var attemptsRemaining = 2;\n\n                        while (attemptsRemaining > 0)\n                        {\n                            try\n                            {\n                                await ctx.Invoke();\n                                return;\n                            }\n                            catch (ArgumentOutOfRangeException) when (attemptsRemaining > 1 && ctx.Grain is IOutgoingMethodInterceptionGrain)\n                            {\n                                // Retry by decrementing the problematic value\n                                if (string.Equals(ctx.InterfaceMethod?.Name, nameof(IOutgoingMethodInterceptionGrain.ThrowIfGreaterThanZero)) && ctx.Request.GetArgument(0) is int value)\n                                {\n                                    ctx.Request.SetArgument(0, value - 1);\n                                }\n\n                                --attemptsRemaining;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Demonstrates that grain call filters can use dependency injection.\n        /// This filter receives IGrainFactory through constructor injection,\n        /// showing that filters are full participants in the DI container.\n        /// </summary>\n        [SuppressMessage(\"ReSharper\", \"NotAccessedField.Local\")]\n        public class GrainCallFilterWithDependencies(IGrainFactory grainFactory) : IIncomingGrainCallFilter\n        {\n            public Task Invoke(IIncomingGrainCallContext context)\n            {\n                Assert.NotNull(grainFactory);\n                // Continue building the RequestContext value: \"1\" -> \"12\"\n                if (string.Equals(context.ImplementationMethod?.Name, nameof(IGrainCallFilterTestGrain.GetRequestContext)))\n                {\n                    if (RequestContext.Get(GrainCallFilterTestConstants.Key) is string value)\n                    {\n                        RequestContext.Set(GrainCallFilterTestConstants.Key, value + '2');\n                    }\n                }\n\n                return context.Invoke();\n            }\n        }\n\n        private readonly Fixture fixture;\n\n        public GrainCallFilterTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n        \n        /// <summary>\n        /// Tests the complete outgoing filter pipeline with request/response manipulation.\n        /// Verifies that:\n        /// 1. Client outgoing filter converts argument to uppercase: ab -> AB\n        /// 2. Grain1 outgoing filter doubles the string: AB -> ABAB\n        /// 3. Grain2 incoming filter reverses it: ABAB -> BABA\n        /// 4. Response is intercepted and modified on the way back\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Outgoing_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IOutgoingMethodInterceptionGrain>(Random.Shared.Next());\n            var grain2 = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n\n            // This grain method reads the context and returns it\n            var result = await grain.EchoViaOtherGrain(grain2, \"ab\");\n\n            // Original arg should have been:\n            // 1. Converted to upper case on the way out of the client: ab -> AB.\n            // 2. Doubled on the way out of grain1: AB -> ABAB.\n            // 3. Reversed on the way in to grain2: ABAB -> BABA.\n            Assert.Equal(\"BABA\", result[\"orig\"] as string);\n            Assert.NotNull(result[\"result\"]);\n            Assert.Equal(\"intercepted!\", result[\"result\"]);\n        }\n\n        /// <summary>\n        /// Verifies the execution order of multiple incoming grain call filters.\n        /// The RequestContext should accumulate values in order: \"1\" -> \"12\" -> \"123\" -> \"1234\"\n        /// where each digit is added by a different filter in the pipeline.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_Order_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGrainCallFilterTestGrain>(Random.Shared.Next());\n\n            // This grain method reads the context and returns it\n            var context = await grain.GetRequestContext();\n            Assert.NotNull(context);\n            Assert.Equal(\"1234\", context);\n        }\n        \n        /// <summary>\n        /// Tests that grain call filters are properly invoked for streaming scenarios.\n        /// When a grain receives stream events, the incoming filters should still execute,\n        /// allowing for stream event manipulation or monitoring.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_Stream_Test()\n        {\n            var streamProvider = this.fixture.Client.GetStreamProvider(\"SMSProvider\");\n            var id = Guid.NewGuid();\n            var stream = streamProvider.GetStream<int>(\"InterceptedStream\", id);\n            var grain = this.fixture.GrainFactory.GetGrain<IStreamInterceptionGrain>(id);\n\n            // The intercepted grain should double the value passed to the stream.\n            const int testValue = 43;\n            await stream.OnNextAsync(testValue);\n            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));\n            int actual = 0;\n            while (!cts.IsCancellationRequested)\n            {\n                actual = await grain.GetLastStreamValue();\n                if (actual != 0) break;\n            }\n            \n            Assert.Equal(testValue * 2, actual);\n        }\n\n        /// <summary>\n        /// Demonstrates retry logic in incoming filters.\n        /// The filter modifies the failing argument value to make the call succeed.\n        /// Shows how filters can implement resilience patterns.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_Retry_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGrainCallFilterTestGrain>(0);\n\n            var result = await grain.ThrowIfGreaterThanZero(1);\n            Assert.Equal(\"Thanks for nothing\", result);\n\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => grain.ThrowIfGreaterThanZero(2));\n        }\n\n        /// <summary>\n        /// Tests that an incoming call filter works with HashSet.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_HashSet_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGrainCallFilterTestGrain>(0);\n\n            var result = await grain.SumSet(new HashSet<int> { 1, 2, 3 });\n            Assert.Equal(6, result);\n        }\n\n        /// <summary>\n        /// Tests that an outgoing call filter can retry calls.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Outgoing_Retry_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IOutgoingMethodInterceptionGrain>(0);\n\n            var result = await grain.ThrowIfGreaterThanZero(1);\n            Assert.Equal(\"Thanks for nothing\", result);\n\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => grain.ThrowIfGreaterThanZero(2));\n        }\n\n        /// <summary>\n        /// Tests grain-specific filters.\n        /// These filters only execute for specific grain types, not system-wide.\n        /// Demonstrates:\n        /// - Method interception with custom logic\n        /// - Selective filtering (some methods not intercepted)\n        /// - Access to implementation method info\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_GrainLevel_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(0);\n            var result = await grain.One();\n            Assert.Equal(\"intercepted one with no args\", result);\n\n            result = await grain.Echo(\"stao erom tae\");\n            Assert.Equal(\"eat more oats\", result);// Grain interceptors should receive the MethodInfo of the implementation, not the interface.\n\n            result = await grain.NotIntercepted();\n            Assert.Equal(\"not intercepted\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n        }\n\n        /// <summary>\n        /// Verifies that grain call filters work correctly with generic grain types.\n        /// Generic grains pose special challenges for reflection-based systems,\n        /// so this ensures filters can properly intercept calls to generic grain methods.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_GenericGrain_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGenericMethodInterceptionGrain<int>>(0);\n            var result = await grain.GetInputAsString(679);\n            Assert.Contains(\"Hah!\", result);\n            Assert.Contains(\"679\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n        }\n        \n        /// <summary>\n        /// Tests filters on grains which implement multiple of the same generic interface.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_ConstructedGenericInheritance_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ITrickyMethodInterceptionGrain>(0);\n\n            var result = await grain.GetInputAsString(\"2014-12-19T14:32:50Z\");\n            Assert.Contains(\"Hah!\", result);\n            Assert.Contains(\"2014-12-19T14:32:50Z\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n\n            var bestNumber = await grain.GetBestNumber();\n            Assert.Equal(38, bestNumber);\n\n            result = await grain.GetInputAsString(true);\n            Assert.Contains(true.ToString(CultureInfo.InvariantCulture), result);\n        }\n\n        /// <summary>\n        /// Demonstrates exception handling in grain call filters.\n        /// Filters can catch exceptions from grain methods and:\n        /// - Transform them into different responses\n        /// - Log and rethrow\n        /// - Convert to domain-specific exceptions\n        /// This test shows converting an exception into a success response.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_ExceptionHandling_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n\n            // This grain method throws, but the exception should be handled by one of the filters and converted\n            // into a specific message.\n            var result = await grain.Throw();\n            Assert.NotNull(result);\n            Assert.Equal(\"EXCEPTION! Oi!\", result);\n        }\n\n        /// <summary>\n        /// Tests that grain call filters can throw exceptions.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_FilterThrows_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n            \n            var exception = await Assert.ThrowsAsync<MethodInterceptionGrain.MyDomainSpecificException>(() => grain.FilterThrows());\n            Assert.NotNull(exception);\n            Assert.Equal(\"Filter THROW!\", exception.Message);\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter sets an incorrect result type for <see cref=\"Orleans.IGrainCallContext.Result\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_SetIncorrectResultType_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n\n            // This grain method throws, but the exception should be handled by one of the filters and converted\n            // into a specific message.\n            await Assert.ThrowsAsync<InvalidCastException>(() => grain.IncorrectResultType());\n        }\n\n        /// <summary>\n        /// Tests that grain call filters properly intercept calls to grain extensions.\n        /// Grain extensions are a way to add additional interfaces to existing grains.\n        /// This verifies that filters work correctly even when methods are called\n        /// through extension interfaces rather than the primary grain interface.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_GrainExtension()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n            var extension = grain.AsReference<IMyGrainExtension>();\n\n            await ((IMyRegularInterface)extension).SetExtensionValue(42);\n            var result = await ((IMyRegularInterface)extension).GetExtensionValue();\n            Assert.Equal(-42, result);\n\n            result = await ((IMyOtherInterface)extension).GetExtensionValue();\n            Assert.Equal(100-42, result);\n        }\n\n        /// <summary>\n        /// Verifies correct method resolution when grains implement generic interfaces.\n        /// Tests complex inheritance scenarios where:\n        /// - A grain implements multiple generic interfaces\n        /// - Methods have the same name across interfaces\n        /// - The filter must correctly identify which interface method was called\n        /// This is critical for filters that need to apply interface-specific logic.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_GenericInterface_ConcreteGrain_Test()\n        {\n            var id = Random.Shared.Next();\n            var hungry = this.fixture.GrainFactory.GetGrain<IHungryGrain<Apple>>(id);\n            var caterpillar = this.fixture.GrainFactory.GetGrain<ICaterpillarGrain>(id);\n            var omnivore = this.fixture.GrainFactory.GetGrain<IOmnivoreGrain>(id);\n\n            RequestContext.Set(\"tag\", \"hungry-eat\");\n            await hungry.Eat(new Apple());\n            await ((IHungryGrain<Apple>)caterpillar).Eat(new Apple());\n\n            RequestContext.Set(\"tag\", \"omnivore-eat\");\n            await omnivore.Eat(\"string\");\n            await ((IOmnivoreGrain)caterpillar).Eat(\"string\");\n\n            RequestContext.Set(\"tag\", \"caterpillar-eat\");\n            await caterpillar.Eat(\"string\");\n\n            RequestContext.Set(\"tag\", \"hungry-eatwith\");\n            await caterpillar.EatWith(new Apple(), \"butter\");\n            await hungry.EatWith(new Apple(), \"butter\");\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter does not call <see cref=\"IGrainCallContext.Invoke\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_SystemWideDoesNotCallContextInvoke_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGrainCallFilterTestGrain>(Random.Shared.Next());\n\n            // The call filter doesn't continue the Invoke chain, but the error state should be thrown as an\n            // InvalidOperationException, not an NullReferenceException.\n            await Assert.ThrowsAsync<InvalidOperationException>(() => grain.SystemWideCallFilterMarker());\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter does not call <see cref=\"IGrainCallContext.Invoke\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_GrainSpecificDoesNotCallContextInvoke_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IGrainCallFilterTestGrain>(Random.Shared.Next());\n\n            // The call filter doesn't continue the Invoke chain, but the error state should be thrown as an\n            // InvalidOperationException, not an NullReferenceException.\n            await Assert.ThrowsAsync<InvalidOperationException>(() => grain.GrainSpecificCallFilterMarker());\n        }\n\n        /// <summary>\n        /// Tests that if an outgoing grain call filter does not call <see cref=\"IGrainCallContext.Invoke\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Outgoing_SystemWideDoesNotCallContextInvoke_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(Random.Shared.Next());\n\n            // The call filter doesn't continue the Invoke chain, but the error state should be thrown as an\n            // InvalidOperationException, not an NullReferenceException.\n            await Assert.ThrowsAsync<InvalidOperationException>(() => grain.SystemWideCallFilterMarker());\n        }\n\n        /// <summary>\n        /// Ensures that grain call filters are invoked around method calls in the correct order.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_Order_Test()\n        {\n            var observer = new GrainCallFilterTestGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGrainCallFilterTestGrainObserver>(observer);\n\n            // This grain method reads the context and returns it\n            var context = await grain.GetRequestContext();\n            Assert.NotNull(context);\n            Assert.Equal(\"1234\", context);\n        }\n\n        /// <summary>\n        /// Tests that an incoming call filter can retry calls to an observer.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_Retry_Test()\n        {\n            var observer = new GrainCallFilterTestGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGrainCallFilterTestGrainObserver>(observer);\n\n            var result = await grain.ThrowIfGreaterThanZero(1);\n            Assert.Equal(\"Thanks for nothing\", result);\n\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => grain.ThrowIfGreaterThanZero(2));\n        }\n\n        /// <summary>\n        /// Tests that an incoming call filter works on an observer with HashSet.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_HashSet_Test()\n        {\n            var observer = new GrainCallFilterTestGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGrainCallFilterTestGrainObserver>(observer);\n\n            var result = await grain.SumSet(new HashSet<int> { 1, 2, 3 });\n            Assert.Equal(6, result);\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter does not call <see cref=\"IGrainCallContext.Invoke\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_SystemWideDoesNotCallContextInvoke_Test()\n        {\n            var observer = new GrainCallFilterTestGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGrainCallFilterTestGrainObserver>(observer);\n\n            // The call filter doesn't continue the Invoke chain, but the error state should be thrown as an\n            // InvalidOperationException, not an NullReferenceException.\n            await Assert.ThrowsAsync<InvalidOperationException>(() => grain.SystemWideCallFilterMarker());\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter does not call <see cref=\"IGrainCallContext.Invoke\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_GrainSpecificDoesNotCallContextInvoke_Test()\n        {\n            var observer = new GrainCallFilterTestGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGrainCallFilterTestGrainObserver>(observer);\n\n            // The call filter doesn't continue the Invoke chain, but the error state should be thrown as an\n            // InvalidOperationException, not an NullReferenceException.\n            await Assert.ThrowsAsync<InvalidOperationException>(() => grain.GrainSpecificCallFilterMarker());\n        }\n\n        /// <summary>\n        /// Tests filters on just the grain level.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_GrainLevel_Test()\n        {\n            var observer = new MethodInterceptionGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IMethodInterceptionGrainObserver>(observer);\n            var result = await grain.One();\n            Assert.Equal(\"intercepted one with no args\", result);\n\n            result = await grain.Echo(\"stao erom tae\");\n            Assert.Equal(\"eat more oats\", result);// Grain interceptors should receive the MethodInfo of the implementation, not the interface.\n\n            result = await grain.NotIntercepted();\n            Assert.Equal(\"not intercepted\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n        }\n\n        /// <summary>\n        /// Tests filters on generic grains.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_GenericGrain_Test()\n        {\n            var observer = new GenericMethodInterceptionGrainObserver<int>();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IGenericMethodInterceptionGrainObserver<int>>(observer);\n            var result = await grain.GetInputAsString(679);\n            Assert.Contains(\"Hah!\", result);\n            Assert.Contains(\"679\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n        }\n        \n        /// <summary>\n        /// Tests filters on grains which implement multiple of the same generic interface.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_ConstructedGenericInheritance_Test()\n        {\n            var observer = new TrickyInterceptionGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<ITrickyMethodInterceptionGrainObserver>(observer);\n\n            var result = await grain.GetInputAsString(\"2014-12-19T14:32:50Z\");\n            Assert.Contains(\"Hah!\", result);\n            Assert.Contains(\"2014-12-19T14:32:50Z\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n\n            var bestNumber = await grain.GetBestNumber();\n            Assert.Equal(38, bestNumber);\n\n            result = await grain.GetInputAsString(true);\n            Assert.Contains(true.ToString(CultureInfo.InvariantCulture), result);\n        }\n\n        /// <summary>\n        /// Tests that grain call filters can handle exceptions.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_ExceptionHandling_Test()\n        {\n            var observer = new MethodInterceptionGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IMethodInterceptionGrainObserver>(observer);\n\n            // This grain method throws, but the exception should be handled by one of the filters and converted\n            // into a specific message.\n            var result = await grain.Throw();\n            Assert.NotNull(result);\n            Assert.Equal(\"EXCEPTION! Oi!\", result);\n        }\n\n        /// <summary>\n        /// Tests that grain call filters can throw exceptions.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_FilterThrows_Test()\n        {\n            var observer = new MethodInterceptionGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IMethodInterceptionGrainObserver>(observer);\n            \n            var exception = await Assert.ThrowsAsync<MethodInterceptionGrainObserver.MyDomainSpecificException>(() => grain.FilterThrows());\n            Assert.NotNull(exception);\n            Assert.Equal(\"Filter THROW!\", exception.Message);\n        }\n\n        /// <summary>\n        /// Tests that if a grain call filter sets an incorrect result type for <see cref=\"Orleans.IGrainCallContext.Result\"/>,\n        /// an exception is thrown on the caller.\n        /// </summary>\n        [Fact]\n        public async Task Observer_GrainCallFilter_Incoming_SetIncorrectResultType_Test()\n        {\n            var observer = new MethodInterceptionGrainObserver();\n            var grain = this.fixture.GrainFactory.CreateObjectReference<IMethodInterceptionGrainObserver>(observer);\n\n            // This grain method throws, but the exception should be handled by one of the filters and converted\n            // into a specific message.\n            await Assert.ThrowsAsync<InvalidCastException>(() => grain.IncorrectResultType());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/GrainLevelCallFilterTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    [TestCategory(\"BVT\"), TestCategory(\"GrainLevelCallFilter\")]\n    public class GrainLevelCallFilterTests : OrleansTestingBase, IClassFixture<GrainLevelCallFilterTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            }\n        }\n\n        private readonly Fixture fixture;\n\n        public GrainLevelCallFilterTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Tests filters on just the grain level when there are no global grain call filters\n        /// </summary>\n        [Fact]\n        public async Task GrainCallFilter_Incoming_GrainLevel_Without_Global_Filter_Test()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<IMethodInterceptionGrain>(0);\n            var result = await grain.One();\n            Assert.Equal(\"intercepted one with no args\", result);\n\n            result = await grain.Echo(\"stao erom tae\");\n            Assert.Equal(\"eat more oats\", result);// Grain interceptors should receive the MethodInfo of the implementation, not the interface.\n\n            result = await grain.NotIntercepted();\n            Assert.Equal(\"not intercepted\", result);\n\n            result = await grain.SayHello();\n            Assert.Equal(\"Hello\", result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/GrainServiceTests/GrainServiceTests.cs",
    "content": "using Xunit;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\n\nnamespace Tester\n{\n    /// <summary>\n    /// Tests for grain service functionality including service invocation, lifecycle, and extensions.\n    /// </summary>\n    public class GrainServiceTests : OrleansTestingBase, IClassFixture<GrainServiceTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 1;\n                builder.AddSiloBuilderConfigurator<GrainServiceSiloBuilderConfigurator>();\n            }\n\n            private class GrainServiceSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddTestGrainService(\"abc\").AddGrainExtension<IEchoExtension, EchoExtension>();\n                }\n            }\n        }\n\n        public GrainServiceTests(Fixture fixture)\n        {\n            this.GrainFactory = fixture.GrainFactory;\n        }\n\n        public IGrainFactory GrainFactory { get; set; }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"GrainServices\")]\n        public async Task SimpleInvokeGrainService()\n        {\n            IGrainServiceTestGrain grain = this.GrainFactory.GetGrain<IGrainServiceTestGrain>(0);\n            var grainId = await grain.GetHelloWorldUsingCustomService();\n            Assert.Equal(\"Hello World from Test Grain Service\", grainId);\n            var prop = await grain.GetServiceConfigProperty();\n            Assert.Equal(\"abc\", prop);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"GrainServices\")]\n        public async Task GrainServiceWasStarted()\n        {\n            IGrainServiceTestGrain grain = GrainFactory.GetGrain<IGrainServiceTestGrain>(0);\n            var prop = await grain.CallHasStarted();\n            Assert.True(prop);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"GrainServices\")]\n        public async Task GrainServiceWasStartedInBackground()\n        {\n            IGrainServiceTestGrain grain = GrainFactory.GetGrain<IGrainServiceTestGrain>(0);\n            var prop = await grain.CallHasStartedInBackground();\n            Assert.True(prop);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"GrainServices\")]\n        public async Task GrainServiceWasInit()\n        {\n            IGrainServiceTestGrain grain = GrainFactory.GetGrain<IGrainServiceTestGrain>(0);\n            var prop = await grain.CallHasInit();\n            Assert.True(prop);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"GrainServices\")]\n        public async Task GrainServiceExtensionTest()\n        {\n            IGrainServiceTestGrain grain = GrainFactory.GetGrain<IGrainServiceTestGrain>(0);\n            var what = await grain.EchoViaExtension(\"what\");\n            Assert.Equal(\"what\", what);\n        }\n\n        public class EchoExtension : IEchoExtension\n        {\n            public Task<string> Echo(string what)\n            {\n                return Task.FromResult(what);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/GrainServiceTests/TestGrainService.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Services;\nusing UnitTests.GrainInterfaces;\n\nnamespace Tester\n{\n    public class TestGrainServiceClient : GrainServiceClient<ITestGrainService>, ITestGrainServiceClient\n    {\n        public TestGrainServiceClient(IServiceProvider serviceProvider) : base(serviceProvider)\n        {\n        }\n\n        public Task<string> GetHelloWorldUsingCustomService()\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).GetHelloWorldUsingCustomService(CurrentGrainReference);\n        }\n\n        public Task<bool> HasStarted()\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).HasStarted();\n        }\n\n        public Task<bool> HasStartedInBackground()\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).HasStartedInBackground();\n        }\n\n        public Task<bool> HasInit()\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).HasInit();\n        }\n\n        public Task<string> GetServiceConfigProperty()\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).GetServiceConfigProperty();\n        }\n\n        public Task<string> EchoViaExtension(string what)\n        {\n            return GetGrainService(CurrentGrainReference.GrainId).AsReference<IEchoExtension>().Echo(what);\n        }\n    }\n\n    public sealed class TestGrainService : GrainService, ITestGrainService\n    {\n        private readonly TestGrainServiceOptions config;\n\n        public TestGrainService(GrainId id, Silo silo, ILoggerFactory loggerFactory, IOptions<TestGrainServiceOptions> options) : base(id, silo, loggerFactory)\n        {\n            this.config = options.Value;\n        }\n\n        private bool started = false;\n        private bool startedInBackground = false;\n        private bool init = false;\n\n        public async override Task Init(IServiceProvider serviceProvider)\n        {\n            await base.Init(serviceProvider);\n            init = true;\n        }\n\n        public override Task Start()\n        {\n            started = true;\n            return base.Start();\n        }\n\n        public Task<string> GetHelloWorldUsingCustomService(GrainReference reference)\n        {\n            return Task.FromResult(\"Hello World from Test Grain Service\");\n        }\n\n        protected override Task StartInBackground()\n        {\n            startedInBackground = true;\n            return Task.CompletedTask;\n        }\n\n        public Task<bool> HasStarted()\n        {\n            return Task.FromResult(started);\n        }\n\n        public Task<bool> HasStartedInBackground()\n        {\n            return Task.FromResult(startedInBackground);\n        }\n\n        public Task<bool> HasInit()\n        {\n            return Task.FromResult(init);\n        }\n\n        public Task<string> GetServiceConfigProperty()\n        {\n            return Task.FromResult(config.ConfigProperty);\n        }\n    }\n\n    public static class TestGrainServicesSiloBuilderExtensions\n    {\n        public static ISiloBuilder AddTestGrainService(this ISiloBuilder builder, string configProperty)\n        {\n            return builder.AddGrainService<TestGrainService>()\n                .ConfigureServices(services => services\n                    .AddSingleton<ITestGrainServiceClient, TestGrainServiceClient>()\n                    .AddOptions<TestGrainServiceOptions>().Configure(o => o.ConfigProperty = configProperty));\n        }\n    }\n\n    public class TestGrainServiceOptions\n    {\n        public string ConfigProperty { get; set; }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/HeterogeneousSilosTests/HeterogeneousTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace Tester.HeterogeneousSilosTests\n{\n    /// <summary>\n    /// Tests for heterogeneous silo configurations including grain type exclusion and type resolution merging.\n    /// </summary>\n    [TestCategory(\"Functional\")]\n    public class HeterogeneousTests : OrleansTestingBase, IDisposable, IAsyncLifetime\n    {\n        private static readonly TimeSpan ClientRefreshDelay = TimeSpan.FromSeconds(1);\n        private static readonly TimeSpan RefreshInterval = TimeSpan.FromMilliseconds(200);\n        private TestCluster cluster;\n\n        private void SetupAndDeployCluster(Type defaultPlacementStrategy, params Type[] blackListedTypes)\n        {\n            cluster?.StopAllSilos();\n            var builder = new TestClusterBuilder(1);\n            builder.Properties[\"DefaultPlacementStrategy\"] = RuntimeTypeNameFormatter.Format(defaultPlacementStrategy);\n            builder.Properties[\"BlockedGrainTypes\"] = string.Join(\"|\", blackListedTypes.Select(t => RuntimeTypeNameFormatter.Format(t)));\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n            cluster = builder.Build();\n            cluster.Deploy();\n        }\n\n        public class SiloConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                hostBuilder.ConfigureServices(services =>\n                {\n                    services.Configure<SiloMessagingOptions>(options => options.AssumeHomogenousSilosForTesting = false);\n                    services.Configure<TypeManagementOptions>(options => options.TypeMapRefreshInterval = RefreshInterval);\n                    services.AddOptions<GrainTypeOptions>().Configure((GrainTypeOptions options, IOptions<SiloOptions> siloOptions) =>\n                    {\n                        var cfg = hostBuilder.GetConfiguration();\n\n                        // The blocklist is only intended for the primary silo in these tests.\n                        if (string.Equals(siloOptions.Value.SiloName, Silo.PrimarySiloName))\n                        {\n                            var typeNames = cfg[\"BlockedGrainTypes\"].Split('|').ToList();\n                            foreach (var typeName in typeNames)\n                            {\n                                var type = Type.GetType(typeName);\n                                options.Classes.Remove(type);\n                            }\n                        }\n                    });\n\n                    var defaultPlacementStrategy = Type.GetType(hostBuilder.GetConfiguration()[\"DefaultPlacementStrategy\"]);\n                    services.AddSingleton(typeof(PlacementStrategy), defaultPlacementStrategy);\n                });\n            }\n        }\n\n        public class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<TypeManagementOptions>(options => options.TypeMapRefreshInterval = ClientRefreshDelay);\n            }\n        }\n\n        public void Dispose()\n        {\n            cluster?.Dispose();\n            cluster = null;\n        }\n\n        [Fact]\n        public void GrainExcludedTest()\n        {\n            SetupAndDeployCluster(typeof(RandomPlacement), typeof(TestGrain));\n\n            // Should fail\n            var exception = Assert.Throws<ArgumentException>(() => this.cluster.GrainFactory.GetGrain<ITestGrain>(0));\n            Assert.Contains(\"Could not find an implementation for interface\", exception.Message);\n\n            // Should not fail\n            this.cluster.GrainFactory.GetGrain<ISimpleGrainWithAsyncMethods>(0);\n        }\n\n\n        [Fact]\n        public async Task MergeGrainResolverTests()\n        {\n            await MergeGrainResolverTestsImpl<ITestGrain>(typeof(RandomPlacement), true, this.CallITestGrainMethod, typeof(TestGrain));\n            await MergeGrainResolverTestsImpl<ITestGrain>(typeof(PreferLocalPlacement), true, this.CallITestGrainMethod, typeof(TestGrain));\n            // TODO Check ActivationCountBasedPlacement in tests\n            //await MergeGrainResolverTestsImpl(\"ActivationCountBasedPlacement\", typeof(TestGrain));\n        }\n\n        [Fact]\n        public async Task MergeGrainResolverWithClientRefreshTests()\n        {\n            await MergeGrainResolverTestsImpl<ITestGrain>(typeof(RandomPlacement), false, this.CallITestGrainMethod, typeof(TestGrain));\n            await MergeGrainResolverTestsImpl<ITestGrain>(typeof(PreferLocalPlacement), false, this.CallITestGrainMethod, typeof(TestGrain));\n            // TODO Check ActivationCountBasedPlacement in tests\n            //await MergeGrainResolverTestsImpl(\"ActivationCountBasedPlacement\", typeof(TestGrain));\n        }\n\n        [Fact]\n        public async Task StatelessWorkerPlacementTests()\n        {\n            await MergeGrainResolverTestsImpl<IStatelessWorkerGrain>(typeof(RandomPlacement), true, this.CallIStatelessWorkerGrainMethod, typeof(StatelessWorkerGrain));\n            await MergeGrainResolverTestsImpl<IStatelessWorkerGrain>(typeof(PreferLocalPlacement), true, this.CallIStatelessWorkerGrainMethod, typeof(StatelessWorkerGrain));\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/9560\")]\n        public async Task StatelessWorkerPlacementWithClientRefreshTests()\n        {\n            await MergeGrainResolverTestsImpl<IStatelessWorkerGrain>(typeof(RandomPlacement), false, this.CallIStatelessWorkerGrainMethod, typeof(StatelessWorkerGrain));\n            await MergeGrainResolverTestsImpl<IStatelessWorkerGrain>(typeof(PreferLocalPlacement), false, this.CallIStatelessWorkerGrainMethod, typeof(StatelessWorkerGrain));\n        }\n\n        private async Task CallITestGrainMethod(IGrain grain)\n        {\n            var g = grain.Cast<ITestGrain>();\n            await g.SetLabel(\"Hello world\");\n        }\n\n        private async Task CallIStatelessWorkerGrainMethod(IGrain grain)\n        {\n            var g = grain.Cast<IStatelessWorkerGrain>();\n            await g.GetCallStats();\n        }\n\n        private async Task MergeGrainResolverTestsImpl<T>(Type defaultPlacementStrategy, bool restartClient, Func<IGrain, Task> func, params Type[] blackListedTypes)\n            where T : IGrainWithIntegerKey\n        {\n            SetupAndDeployCluster(defaultPlacementStrategy, blackListedTypes);\n\n            var delayTimeout = RefreshInterval.Add(RefreshInterval);\n\n            // Should fail\n            var exception = Assert.Throws<ArgumentException>(() => this.cluster.GrainFactory.GetGrain<T>(0));\n            Assert.Contains(\"Could not find an implementation for interface\", exception.Message);\n\n            // Start a new silo with TestGrain\n            await cluster.StartAdditionalSiloAsync();\n            await Task.Delay(delayTimeout);\n\n            if (restartClient)\n            {\n                // Disconnect/Reconnect the client\n                await cluster.StopClusterClientAsync();\n                await cluster.InitializeClientAsync();\n            }\n            else\n            {\n                await Task.Delay(ClientRefreshDelay.Multiply(3));\n            }\n\n            for (var i = 0; i < 5; i++)\n            {\n                // Success\n                var g = this.cluster.GrainFactory.GetGrain<T>(i);\n                await func(g);\n            }\n\n            // Stop the latest silos\n            await cluster.StopSecondarySilosAsync();\n            await Task.Delay(delayTimeout);\n\n            if (restartClient)\n            {\n                // Disconnect/Reconnect the client\n                await cluster.StopClusterClientAsync();\n                await cluster.InitializeClientAsync();\n            }\n            else\n            {\n                await Task.Delay(ClientRefreshDelay.Multiply(3));\n            }\n\n            // Should fail\n            exception = Assert.Throws<ArgumentException>(() => this.cluster.GrainFactory.GetGrain<T>(0));\n            Assert.Contains(\"Could not find an implementation for interface\", exception.Message);\n        }\n\n        public Task InitializeAsync()\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task DisposeAsync()\n        {\n            try\n            {\n                if (this.cluster is TestCluster c)\n                {\n                    await c.StopAllSilosAsync();\n                }\n            }\n            finally\n            {\n                this.cluster?.Dispose();\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/HeterogeneousSilosTests/UpgradeTests/RuntimeStrategyChangeTests.cs",
    "content": "using Orleans.Metadata;\nusing Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\nusing TestVersionGrainInterfaces;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Tester.HeterogeneousSilosTests.UpgradeTests\n{\n    /// <summary>\n    /// Tests for runtime changes to versioning strategies including compatibility and selector strategy modifications.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class RuntimeStrategyChangeTests : UpgradeTestsBase\n    {\n        protected override Type VersionSelectorStrategy => typeof(LatestVersion);\n        protected override Type CompatibilityStrategy => typeof(AllVersionsCompatible);\n\n        [Fact]\n        public async Task ChangeCompatibilityStrategy()\n        {\n            await StartSiloV1();\n            var resolver = this.Client.ServiceProvider.GetService<GrainInterfaceTypeResolver>();\n            var ifaceId = resolver.GetGrainInterfaceType(typeof(IVersionUpgradeTestGrain));\n\n            var grainV1 = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            Assert.Equal(1, await grainV1.GetVersion());\n\n            await StartSiloV2();\n\n            var grainV2 = Client.GetGrain<IVersionUpgradeTestGrain>(1);\n            Assert.Equal(2, await grainV2.GetVersion());\n\n            // Current policy \"AllVersionsCompatible\" -> no downgrade\n            Assert.Equal(2, await grainV1.ProxyGetVersion(grainV2));\n            Assert.Equal(2, await grainV2.GetVersion());\n            Assert.Equal(1, await grainV1.GetVersion());\n\n            await ManagementGrain.SetCompatibilityStrategy(ifaceId, StrictVersionCompatible.Singleton);\n\n            // Current policy \"StrictVersionCompatible\" -> Downgrade mandatory\n            Assert.Equal(1, await grainV1.ProxyGetVersion(grainV2));\n            Assert.Equal(1, await grainV2.GetVersion());\n            Assert.Equal(1, await grainV1.GetVersion());\n\n            // Since this client is V1, only V1 should be activated, even with the \"LatestVersion\" rule\n            for (var i = 2; i < 102; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n            \n            // Fallback to AllVersionsCompatible\n            await ManagementGrain.SetCompatibilityStrategy(ifaceId, null);\n\n            // Now we should activate only v2\n            for (var i = 102; i < 202; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(2, await grain.GetVersion());\n            }\n        }\n\n        [Fact]\n        public async Task ChangeVersionSelectorStrategy()\n        {\n            await StartSiloV1();\n            var resolver = this.Client.ServiceProvider.GetService<GrainInterfaceTypeResolver>();\n            var ifaceId = resolver.GetGrainInterfaceType(typeof(IVersionUpgradeTestGrain));\n\n            // Only V1 exists\n            var grainV1 = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            Assert.Equal(1, await grainV1.GetVersion());\n\n            await StartSiloV2();\n\n            // Don't touch to V1\n            Assert.Equal(1, await grainV1.GetVersion());\n            // But only activate V2\n            for (int i = 1; i < 101; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(2, await grain.GetVersion());\n            }\n\n            await ManagementGrain.SetSelectorStrategy(ifaceId, MinimumVersion.Singleton);\n\n            // Don't touch to existing activation\n            Assert.Equal(1, await grainV1.GetVersion());\n            for (int i = 1; i < 101; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(2, await grain.GetVersion());\n            }\n            // But only activate V1\n            for (int i = 101; i < 201; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n        }\n\n        [Fact]\n        public async Task ChangeDefaultVersionCompatibilityStrategy()\n        {\n            Assert.Equal(typeof(AllVersionsCompatible), CompatibilityStrategy);\n\n            await StartSiloV1();\n\n            // Only V1 exists\n            var grainV1 = new IVersionUpgradeTestGrain[2];\n            grainV1[0] = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            grainV1[1] = Client.GetGrain<IVersionUpgradeTestGrain>(1);\n            Assert.Equal(1, await grainV1[0].GetVersion());\n            Assert.Equal(1, await grainV1[1].GetVersion());\n\n            // Change default to backward compatible\n            await ManagementGrain.SetCompatibilityStrategy(BackwardCompatible.Singleton);\n\n            await StartSiloV2();\n\n            var grainV2 = Client.GetGrain<IVersionUpgradeTestGrain>(2);\n            Assert.Equal(2, await grainV2.GetVersion());\n\n            // Should provoke \"upgrade\"\n            Assert.Equal(2, await grainV2.ProxyGetVersion(grainV1[0]));\n            Assert.Equal(2, await grainV1[0].GetVersion());\n\n            // Change default to backward compatible\n            await ManagementGrain.SetCompatibilityStrategy(null);\n\n            // Should not provoke upgrade\n            Assert.Equal(1, await grainV2.ProxyGetVersion(grainV1[1]));\n            Assert.Equal(1, await grainV1[1].GetVersion());\n        }\n\n        [Fact]\n        public async Task ChangeDefaultVersionSelectorStrategy()\n        {\n            Assert.Equal(typeof(LatestVersion), VersionSelectorStrategy);\n\n            await StartSiloV1();\n\n            // Only V1 exists\n            var grainV1 = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            Assert.Equal(1, await grainV1.GetVersion());\n\n            await StartSiloV2();\n\n            // Change default to minimum version\n            await ManagementGrain.SetSelectorStrategy(MinimumVersion.Singleton);\n\n            // But only activate V1\n            for (int i = 0; i < 100; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n\n            // Change default to latest version\n            await ManagementGrain.SetSelectorStrategy(null);\n\n            // Don't touch to existing activation\n            for (int i = 0; i < 100; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n            // But only activate V2\n            for (int i = 100; i < 200; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(2, await grain.GetVersion());\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/HeterogeneousSilosTests/UpgradeTests/UpgradeTests.cs",
    "content": "using Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\nusing TestVersionGrainInterfaces;\nusing Xunit;\n\nnamespace Tester.HeterogeneousSilosTests.UpgradeTests\n{\n    /// <summary>\n    /// Tests for minimum version selector strategy ensuring v1 grains are always activated.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class MinimumVersionTests : UpgradeTestsBase\n    {\n        protected override Type VersionSelectorStrategy => typeof(MinimumVersion);\n        protected override Type CompatibilityStrategy => typeof(BackwardCompatible);\n        \n        [Fact]\n        public Task AlwaysCreateActivationWithMinimumVersion()\n        {\n            // Even after v2 silo is deployed, we should only activate v1 grains\n            return Step1_StartV1Silo_Step2_StartV2Silo_Step3_StopV2Silo(step2Version: 1);\n        }\n    }\n\n    /// <summary>\n    /// Tests for latest version selector strategy with backward compatibility and grain upgrades.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class LatestVersionTests : UpgradeTestsBase\n    {\n        protected override Type VersionSelectorStrategy => typeof(LatestVersion);\n        protected override Type CompatibilityStrategy => typeof(BackwardCompatible);\n\n        [Fact]\n        public Task AlwaysCreateActivationWithLatestVersion()\n        {\n            // After v2 is deployed, we should always activate v2 grains\n            return Step1_StartV1Silo_Step2_StartV2Silo_Step3_StopV2Silo(step2Version: 2);\n        }\n\n        [Fact]\n        public Task UpgradeProxyCallNoPendingRequest()\n        {\n            // v2 -> v1 call should provoke grain activation upgrade.\n            // The grain is inactive when receiving the message\n            return ProxyCallNoPendingRequest(expectedVersion: 2);\n        }\n\n        [Fact]\n        public Task UpgradeProxyCallWithPendingRequest()\n        {\n            // v2 -> v1 call should provoke grain activation upgrade\n            // The grain is already processing a request when receiving the message\n            return ProxyCallWithPendingRequest(expectedVersion: 2);\n        }\n    }\n\n    /// <summary>\n    /// Tests for all versions compatible strategy preventing automatic grain upgrades.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class AllVersionsCompatibleTests : UpgradeTestsBase\n    {\n        protected override Type VersionSelectorStrategy => typeof(LatestVersion);\n        protected override Type CompatibilityStrategy => typeof(AllVersionsCompatible);\n\n        [Fact]\n        public Task DoNotUpgradeProxyCallNoPendingRequest()\n        {\n            // v2 -> v1 call should provoke grain activation upgrade because they are compatible\n            // The grain is inactive when receiving the message\n            return ProxyCallNoPendingRequest(expectedVersion: 1);\n        }\n\n        [Fact]\n        public Task DoNotUpgradeProxyCallWithPendingRequest()\n        {\n            // v2 -> v1 call should provoke grain activation upgrade because they are compatible\n            // The grain is already processing a request when receiving the message\n            return ProxyCallWithPendingRequest(expectedVersion: 1);\n        }\n    }\n\n    /// <summary>\n    /// Tests for random compatible version selection strategy distributing activations across versions.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class RandomCompatibleVersionTests : UpgradeTestsBase\n    {\n        protected override Type VersionSelectorStrategy => typeof(AllCompatibleVersions);\n        protected override Type CompatibilityStrategy => typeof(AllVersionsCompatible);\n\n        [Fact]\n        public async Task CreateActivationWithBothVersion()\n        {\n            const float numberOfGrains = 300;\n\n            await StartSiloV1();\n            await StartSiloV2();\n\n            var versionCounter = new int[2];\n\n            // We should create v1 and v2 activations\n\n            for (var i = 0; i < numberOfGrains; i++)\n            {\n                var v = await Client.GetGrain<IVersionUpgradeTestGrain>(i).GetVersion();\n                versionCounter[v - 1]++;\n            }\n\n            // 99.95% chance of success\n            Assert.InRange(versionCounter[0]/numberOfGrains, 0.35, 0.65);\n            Assert.InRange(versionCounter[1]/numberOfGrains, 0.35, 0.65);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/HeterogeneousSilosTests/UpgradeTests/UpgradeTestsBase.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Configuration.Memory;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing System.Runtime.InteropServices;\nusing TestExtensions;\nusing TestVersionGrainInterfaces;\nusing TestVersionGrains;\nusing Xunit;\n\nnamespace Tester.HeterogeneousSilosTests.UpgradeTests\n{\n    public abstract class UpgradeTestsBase : IDisposable, IAsyncLifetime\n    {\n        private static readonly TimeSpan RefreshInterval = TimeSpan.FromMilliseconds(200);\n\n        private TimeSpan waitDelay;\n\n        protected IClusterClient Client => this.cluster.Client;\n        protected IManagementGrain ManagementGrain => this.cluster.Client.GetGrain<IManagementGrain>(0);\n#if DEBUG\n        private const string BuildConfiguration = \"Debug\";\n#else\n        private const string BuildConfiguration = \"Release\";\n#endif\n        private const string CommonParentDirectory = \"test\";\n        private const string BinDirectory = \"bin\";\n        private const string VersionsProjectDirectory = \"Grains\";\n        private const string GrainsV1ProjectName = \"TestVersionGrains\";\n        private const string GrainsV2ProjectName = \"TestVersionGrains2\";\n        private static readonly string VersionTestBinaryName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? \"TestVersionGrains.exe\" : \"TestVersionGrains\";\n        private readonly FileInfo assemblyGrainsV1;\n        private readonly FileInfo assemblyGrainsV2;\n\n        private readonly List<SiloHandle> deployedSilos = new List<SiloHandle>();\n        private int siloIdx = 0;\n        private TestClusterBuilder builder;\n        private TestCluster cluster;\n\n        protected abstract Type VersionSelectorStrategy { get; }\n\n        protected abstract Type CompatibilityStrategy { get; }\n\n        protected virtual short SiloCount => 2;\n\n        protected UpgradeTestsBase()\n        {\n            var testDirectory = new DirectoryInfo(GetType().Assembly.Location);\n\n            while (string.Compare(testDirectory.Name, CommonParentDirectory, StringComparison.OrdinalIgnoreCase) != 0 || testDirectory.Parent == null)\n            {\n                testDirectory = testDirectory.Parent;\n            }\n\n            if (testDirectory.Parent == null)\n            {\n                throw new InvalidOperationException($\"Cannot locate 'test' directory starting from '{GetType().Assembly.Location}'\");\n            }\n\n            assemblyGrainsV1 = GetVersionTestDirectory(testDirectory, GrainsV1ProjectName);\n            assemblyGrainsV2 = GetVersionTestDirectory(testDirectory, GrainsV2ProjectName);\n        }\n\n        private static FileInfo GetVersionTestDirectory(DirectoryInfo testDirectory, string directoryName)\n        {\n            var projectDirectory = Path.Combine(testDirectory.FullName, VersionsProjectDirectory, directoryName, BinDirectory);\n\n            var directories = Directory.GetDirectories(projectDirectory, BuildConfiguration, SearchOption.AllDirectories);\n\n            if (directories.Length != 1)\n            {\n                throw new InvalidOperationException($\"Number of directories found for pattern: '{BuildConfiguration}' under {testDirectory.FullName}: {directories.Length}\");\n            }\n\n            var directory = directories[0];\n            var files = Directory.GetFiles(directory, VersionTestBinaryName, SearchOption.AllDirectories)\n                .Where(f => !f.Contains(Path.DirectorySeparatorChar + \"ref\" + Path.DirectorySeparatorChar))\n                .Where(f => f.Contains(\"publish\"))\n                .Where(f => f.Contains($\"net{Environment.Version.Major}.{Environment.Version.Minor}\"))\n                .ToArray();\n\n            if (files.Length != 1)\n            {\n                throw new InvalidOperationException($\"Found {files.Length} files found for pattern: '{VersionTestBinaryName}' under {directory}: {string.Join(\", \", files)}\");\n            }\n\n            return new FileInfo(files[0]);\n        }\n\n        protected async Task Step1_StartV1Silo_Step2_StartV2Silo_Step3_StopV2Silo(int step2Version)\n        {\n            const int numberOfGrains = 100;\n\n            await StartSiloV1();\n\n            // Only V1 exist for now\n            for (var i = 0; i < numberOfGrains; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n\n            // Start a new silo with V2\n            var siloV2 = await StartSiloV2();\n\n            for (var i = 0; i < numberOfGrains; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n\n            for (var i = numberOfGrains; i < numberOfGrains * 2; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(step2Version, await grain.GetVersion());\n            }\n\n            // Stop the V2 silo\n            await StopSilo(siloV2);\n\n            // Now all activation should be V1\n            for (var i = 0; i < numberOfGrains * 3; i++)\n            {\n                var grain = Client.GetGrain<IVersionUpgradeTestGrain>(i);\n                Assert.Equal(1, await grain.GetVersion());\n            }\n        }\n\n        protected async Task ProxyCallNoPendingRequest(int expectedVersion)\n        {\n            await StartSiloV1();\n\n            // Only V1 exist for now\n            var grain0 = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            Assert.Equal(1, await grain0.GetVersion());\n\n            await StartSiloV2();\n\n            // New activation should be V2\n            var grain1 = Client.GetGrain<IVersionUpgradeTestGrain>(1);\n            Assert.Equal(2, await grain1.GetVersion());\n            Assert.Equal(1, await grain0.GetVersion());\n\n            Assert.Equal(expectedVersion, await grain1.ProxyGetVersion(grain0));\n            Assert.Equal(expectedVersion, await grain0.GetVersion());\n        }\n\n        protected async Task ProxyCallWithPendingRequest(int expectedVersion)\n        {\n            await StartSiloV1();\n\n            // Only V1 exist for now\n            var grain0 = Client.GetGrain<IVersionUpgradeTestGrain>(0);\n            Assert.Equal(1, await grain0.GetVersion());\n\n            // Start a new silo with V2\n            await StartSiloV2();\n\n            // New activation should be V2\n            var grain1 = Client.GetGrain<IVersionUpgradeTestGrain>(1);\n            Assert.Equal(2, await grain1.GetVersion());\n\n            var waitingTask = grain0.LongRunningTask(TimeSpan.FromSeconds(5));\n            var callBeforeUpgrade = grain0.GetVersion();\n            await Task.Delay(100); // Make sure requests are not sent out of order\n            var callProvokingUpgrade = grain1.ProxyGetVersion(grain0);\n\n            await waitingTask;\n            Assert.Equal(1, await callBeforeUpgrade);\n            Assert.Equal(expectedVersion, await callProvokingUpgrade);\n        }\n\n        protected async Task<SiloHandle> StartSiloV1()\n        {\n            var handle = await StartSilo(assemblyGrainsV1);\n            await Task.Delay(waitDelay);\n            return handle;\n        }\n\n        protected async Task<SiloHandle> StartSiloV2()\n        {\n            var handle = await StartSilo(assemblyGrainsV2);\n            await Task.Delay(waitDelay);\n            return handle;\n        }\n\n        private async Task<SiloHandle> StartSilo(FileInfo grainAssembly)\n        {\n            SiloHandle silo;\n            if (this.siloIdx == 0)\n            {\n                // Setup configuration\n                this.builder = new TestClusterBuilder(1);\n                builder.CreateSiloAsync = StandaloneSiloHandle.Create;\n                TestDefaultConfiguration.ConfigureTestCluster(this.builder);\n                builder.AddSiloBuilderConfigurator<VersionGrainsSiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<VersionGrainsClientConfigurator>();\n                builder.Properties[nameof(SiloCount)] = this.SiloCount.ToString();\n                builder.Properties[nameof(RefreshInterval)] = RefreshInterval.ToString();\n                builder.Properties[nameof(VersionSelectorStrategy)] = this.VersionSelectorStrategy.Name;\n                builder.Properties[nameof(CompatibilityStrategy)] = this.CompatibilityStrategy.Name;\n                builder.Properties[\"GrainAssembly\"] = grainAssembly.FullName;\n                builder.Properties[StandaloneSiloHandle.ExecutablePathConfigKey] = grainAssembly.FullName;\n                waitDelay = TestCluster.GetLivenessStabilizationTime(new ClusterMembershipOptions(), didKill: false);\n\n                this.cluster = builder.Build();\n                await this.cluster.DeployAsync();\n                silo = this.cluster.Primary;\n            }\n            else\n            {\n                var configBuilder = new ConfigurationBuilder();\n                foreach (var source in cluster.ConfigurationSources) configBuilder.Add(source);\n                var testClusterOptions = new TestClusterOptions();\n                configBuilder.Build().Bind(testClusterOptions);\n\n                // Override the root directory.\n                var sources = new IConfigurationSource[]\n                {\n                    new MemoryConfigurationSource\n                    {\n                        InitialData = new Dictionary<string, string>\n                        {\n                            [StandaloneSiloHandle.ExecutablePathConfigKey] = grainAssembly.FullName\n                        }\n                    }\n                };\n\n                silo = await TestCluster.StartSiloAsync(cluster, siloIdx, testClusterOptions, sources);\n            }\n\n            this.deployedSilos.Add(silo);\n            this.siloIdx++;\n\n            return silo;\n        }\n\n        protected async Task StopSilo(SiloHandle handle)\n        {\n            await handle?.StopSiloAsync(true);\n            this.deployedSilos.Remove(handle);\n            await Task.Delay(waitDelay);\n        }\n\n        public void Dispose()\n        {\n            try\n            {\n                if (deployedSilos.Count == 0) return;\n\n                var primarySilo = this.deployedSilos[0];\n                foreach (var silo in this.deployedSilos.Skip(1))\n                {\n                    silo.Dispose();\n                }\n                primarySilo.Dispose();\n            }\n            finally\n            {\n                this.cluster?.Dispose();\n            }\n        }\n\n        public Task InitializeAsync()\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task DisposeAsync()\n        {\n            if (deployedSilos.Count == 0) return;\n\n            var primarySilo = this.deployedSilos[0];\n            foreach (var silo in this.deployedSilos.Skip(1))\n            {\n                await silo.DisposeAsync();\n            }\n\n            await primarySilo.DisposeAsync();\n            if (Client is { })\n            {\n                await cluster.StopClusterClientAsync();\n            }\n        }\n\n        public class VersionGrainsClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<GatewayOptions>(options => options.PreferredGatewayIndex = 0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/HeterogeneousSilosTests/UpgradeTests/VersionPlacementTests.cs",
    "content": "using Orleans.Versions.Compatibility;\nusing Orleans.Versions.Selector;\nusing TestVersionGrainInterfaces;\nusing Xunit;\n\nnamespace Tester.HeterogeneousSilosTests.UpgradeTests\n{\n    /// <summary>\n    /// Tests grain placement behavior during version upgrades when using AllCompatibleVersions selector and AllVersionsCompatible compatibility strategy.\n    /// </summary>\n    [TestCategory(\"Versioning\"), TestCategory(\"ExcludeXAML\"), TestCategory(\"SlowBVT\")]\n    public class VersionPlacementTests : UpgradeTestsBase\n    {\n        protected override short SiloCount => 3;\n\n        protected override Type VersionSelectorStrategy => typeof(AllCompatibleVersions);\n        protected override Type CompatibilityStrategy => typeof(AllVersionsCompatible);\n\n        [Fact]\n        public async Task ActivateDominantVersion()\n        {\n            await StartSiloV1();\n\n            var grain0 = Client.GetGrain<IVersionPlacementTestGrain>(0);\n            Assert.Equal(1, await grain0.GetVersion());\n\n            await StartSiloV2();\n\n            for (var i = 1; i < 101; i++)\n            {\n                var grain1 = Client.GetGrain<IVersionPlacementTestGrain>(i);\n                Assert.Equal(1, await grain1.GetVersion());\n            }\n\n            await StartSiloV2();\n\n            for (var i = 101; i < 201; i++)\n            {\n                var grain2 = Client.GetGrain<IVersionPlacementTestGrain>(i);\n                Assert.Equal(2, await grain2.GetVersion());\n            }\n\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/JsonNodeGrainTests.cs",
    "content": "using System;\nusing System.Text.Json.Nodes;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans;\nusing Orleans.Hosting;\nusing Orleans.Serialization;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace DefaultCluster.Tests\n{\n    /// <summary>\n    /// Grain interface for testing JsonNode serialization through Orleans grain calls.\n    /// This interface reproduces the scenario from GitHub issue #9568 where JsonNode parameters\n    /// are used in grain methods, which can receive JsonValue instances at runtime.\n    /// </summary>\n    public interface IJsonNodeTestGrain : IGrainWithIntegerKey\n    {\n        Task<JsonNode> ProcessJsonNode(JsonNode node);\n        Task<string> GetJsonString(JsonNode node);\n    }\n\n    /// <summary>\n    /// Implementation of the JsonNode test grain.\n    /// Provides methods to test serialization and deserialization of JsonNode instances\n    /// through grain method calls, ensuring the fix for issue #9568 works in a distributed context.\n    /// </summary>\n    public class JsonNodeTestGrain : Grain, IJsonNodeTestGrain\n    {\n        public Task<JsonNode> ProcessJsonNode(JsonNode node)\n        {\n            // Simply return the node - serialization should handle it\n            return Task.FromResult(node);\n        }\n\n        public Task<string> GetJsonString(JsonNode node)\n        {\n            // Convert to string to verify we received the correct data\n            return Task.FromResult(node?.ToJsonString() ?? \"null\");\n        }\n    }\n\n    /// <summary>\n    /// Test fixture that configures an in-process Orleans cluster with JSON serialization support.\n    /// Sets up both silo and client to use the JsonCodec for System.Text.Json types.\n    /// </summary>\n    public class JsonNodeGrainTestFixture : BaseInProcessTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n        {\n            base.ConfigureTestCluster(builder);\n\n            // Configure JSON serialization\n            builder.ConfigureSilo((options, siloBuilder) =>\n            {\n                siloBuilder.Services.AddSerializer(serializerBuilder =>\n                {\n                    serializerBuilder.AddJsonSerializer(_ => false);\n                });\n            });\n\n            builder.ConfigureClient(clientBuilder =>\n            {\n                clientBuilder.Services.AddSerializer(serializerBuilder =>\n                {\n                    serializerBuilder.AddJsonSerializer(_ => false);\n                });\n            });\n        }\n    }\n\n    /// <summary>\n    /// Integration tests for JsonNode serialization in Orleans grains.\n    /// These tests verify that the fix for GitHub issue #9568 works correctly when JsonNode types\n    /// are passed through grain method calls, particularly when JsonValue is passed to a JsonNode parameter.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class JsonNodeGrainTests : IClassFixture<JsonNodeGrainTestFixture>\n    {\n        private readonly JsonNodeGrainTestFixture _fixture;\n        private readonly ITestOutputHelper _output;\n\n        public JsonNodeGrainTests(JsonNodeGrainTestFixture fixture, ITestOutputHelper output)\n        {\n            _fixture = fixture;\n            _output = output;\n        }\n\n        /// <summary>\n        /// Reproduces GitHub issue #9568: Tests that a grain method with JsonNode parameter can receive JsonValue.\n        /// This test verifies the core fix where JsonValue (a derived type) is passed to a method expecting JsonNode (base type).\n        /// Previously this would throw InvalidCastException during deserialization.\n        /// </summary>\n        [Fact]\n        public async Task GrainCanProcessJsonValue_AsJsonNode()\n        {\n            // When a grain method has a JsonNode parameter but receives a JsonValue\n            var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(1);\n\n            // Create a JsonValue (which is a subtype of JsonNode)\n            JsonNode jsonNode = JsonValue.Create(1);\n\n            // This should not throw InvalidCastException\n            var result = await grain.ProcessJsonNode(jsonNode);\n\n            // Verify the result\n            Assert.NotNull(result);\n            Assert.Equal(1, result.GetValue<int>());\n        }\n\n        /// <summary>\n        /// Tests that grains can process all JsonNode subtypes (JsonValue, JsonArray, JsonObject).\n        /// Verifies that each type maintains its structure and values through grain method calls.\n        /// </summary>\n        [Fact]\n        public async Task GrainCanProcessVariousJsonNodeTypes()\n        {\n            var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(2);\n\n            // Test JsonValue with int\n            JsonNode intValue = JsonValue.Create(42);\n            var intResult = await grain.ProcessJsonNode(intValue);\n            Assert.Equal(42, intResult.GetValue<int>());\n\n            // Test JsonValue with string\n            JsonNode stringValue = JsonValue.Create(\"hello\");\n            var stringResult = await grain.ProcessJsonNode(stringValue);\n            Assert.Equal(\"hello\", stringResult.GetValue<string>());\n\n            // Test JsonValue with bool\n            JsonNode boolValue = JsonValue.Create(true);\n            var boolResult = await grain.ProcessJsonNode(boolValue);\n            Assert.True(boolResult.GetValue<bool>());\n\n            // Test JsonArray\n            JsonNode arrayValue = new JsonArray { 1, 2, 3 };\n            var arrayResult = await grain.ProcessJsonNode(arrayValue);\n            Assert.IsType<JsonArray>(arrayResult);\n            Assert.Equal(3, ((JsonArray)arrayResult).Count);\n\n            // Test JsonObject\n            JsonNode objectValue = new JsonObject { [\"key\"] = \"value\", [\"number\"] = 123 };\n            var objectResult = await grain.ProcessJsonNode(objectValue);\n            Assert.IsType<JsonObject>(objectResult);\n            Assert.Equal(\"value\", objectResult[\"key\"]!.GetValue<string>());\n            Assert.Equal(123, objectResult[\"number\"]!.GetValue<int>());\n        }\n\n        /// <summary>\n        /// Tests grain processing of complex nested JSON structures.\n        /// Verifies that deeply nested objects containing mixed JsonNode types are correctly\n        /// serialized and deserialized through grain calls.\n        /// </summary>\n        [Fact]\n        public async Task GrainCanProcessComplexJsonStructure()\n        {\n            var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(3);\n\n            // Create a complex nested structure\n            var complexNode = new JsonObject\n            {\n                [\"simpleValue\"] = JsonValue.Create(123),\n                [\"arrayWithValues\"] = new JsonArray\n                {\n                    JsonValue.Create(\"first\"),\n                    JsonValue.Create(456),\n                    JsonValue.Create(false)\n                },\n                [\"nestedObject\"] = new JsonObject\n                {\n                    [\"deepValue\"] = JsonValue.Create(3.14159),\n                    [\"deepArray\"] = new JsonArray { JsonValue.Create(true), null }\n                }\n            };\n\n            // Process through grain\n            var result = await grain.ProcessJsonNode(complexNode);\n\n            // Verify structure is preserved\n            Assert.NotNull(result);\n            Assert.Equal(123, result[\"simpleValue\"]!.GetValue<int>());\n\n            var array = result[\"arrayWithValues\"] as JsonArray;\n            Assert.NotNull(array);\n            Assert.Equal(\"first\", array![0]!.GetValue<string>());\n            Assert.Equal(456, array[1]!.GetValue<int>());\n            Assert.False(array[2]!.GetValue<bool>());\n\n            var nested = result[\"nestedObject\"] as JsonObject;\n            Assert.NotNull(nested);\n            Assert.Equal(3.14159, nested![\"deepValue\"]!.GetValue<double>(), 5);\n        }\n\n        /// <summary>\n        /// Tests that JsonNode instances can be converted to strings within grain methods.\n        /// Verifies that the grain receives valid JsonNode instances that can be manipulated.\n        /// </summary>\n        [Fact]\n        public async Task GrainCanConvertJsonNodeToString()\n        {\n            var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(4);\n\n            // Test with JsonValue\n            JsonNode valueNode = JsonValue.Create(42);\n            var valueString = await grain.GetJsonString(valueNode);\n            Assert.Equal(\"42\", valueString);\n\n            // Test with JsonObject\n            JsonNode objectNode = new JsonObject { [\"test\"] = \"value\" };\n            var objectString = await grain.GetJsonString(objectNode);\n            Assert.Contains(\"\\\"test\\\":\\\"value\\\"\", objectString);\n\n            // Test with JsonArray\n            JsonNode arrayNode = new JsonArray { 1, 2, 3 };\n            var arrayString = await grain.GetJsonString(arrayNode);\n            Assert.Equal(\"[1,2,3]\", arrayString);\n        }\n\n        /// <summary>\n        /// Tests that grain methods correctly handle null JsonNode parameters.\n        /// Ensures that null values are properly serialized and don't cause exceptions.\n        /// </summary>\n        [Fact]\n        public async Task GrainHandlesNullJsonNode()\n        {\n            var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(5);\n\n            JsonNode nullNode = null;\n            var result = await grain.ProcessJsonNode(nullNode);\n            Assert.Null(result);\n\n            var stringResult = await grain.GetJsonString(nullNode);\n            Assert.Equal(\"null\", stringResult);\n        }\n\n        /// <summary>\n        /// Tests thread safety and correctness with concurrent grain calls using JsonNode parameters.\n        /// Verifies that multiple simultaneous grain calls with different JsonNode values don't interfere with each other.\n        /// </summary>\n        [Fact]\n        public async Task MultipleConcurrentGrainCallsWithJsonNodes()\n        {\n            // Test concurrent calls to ensure thread safety\n            var tasks = new Task[10];\n\n            for (int i = 0; i < 10; i++)\n            {\n                var grainId = i + 100;\n                var value = i * 10;\n                tasks[i] = Task.Run(async () =>\n                {\n                    var grain = _fixture.GrainFactory.GetGrain<IJsonNodeTestGrain>(grainId);\n                    JsonNode node = JsonValue.Create(value);\n                    var result = await grain.ProcessJsonNode(node);\n                    Assert.Equal(value, result.GetValue<int>());\n                });\n            }\n\n            await Task.WhenAll(tasks);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Lifecycle/LifecycleTests.cs",
    "content": "using Microsoft.Extensions.Logging.Abstractions;\nusing Xunit;\n\nnamespace Tester\n{\n    public class LifecycleTests\n    {\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\n        public async Task FullLifecycleTest()\n        {\n            const int observersPerStage = 2;\n            Dictionary<TestStages, int> observerCountByStage = new Dictionary<TestStages, int>();\n            foreach (TestStages stage in Enum.GetValues(typeof(TestStages)))\n            {\n                observerCountByStage[stage] = observersPerStage;\n            }\n            Dictionary<TestStages, List<Observer>> observersByStage = await RunLifecycle(observerCountByStage, null, null);\n\n            Assert.Equal(observerCountByStage.Count, observersByStage.Count);\n            foreach (KeyValuePair<TestStages,List<Observer>> kvp in observersByStage)\n            {\n                Assert.Equal(observerCountByStage[kvp.Key], kvp.Value.Count);\n                Assert.True(kvp.Value.All(o => o.Started));\n                Assert.True(kvp.Value.All(o => o.Stopped));\n                Assert.True(kvp.Value.All(o => !o.FailedOnStart));\n                Assert.True(kvp.Value.All(o => !o.FailedOnStop));\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\n        public async Task FailOnStartOnEachStageLifecycleTest()\n        {\n            const int observersPerStage = 2;\n            Dictionary<TestStages, int> observerCountByStage = new Dictionary<TestStages, int>();\n            foreach (TestStages stage in Enum.GetValues(typeof(TestStages)))\n            {\n                observerCountByStage[stage] = observersPerStage;\n            }\n\n            foreach (TestStages stage in Enum.GetValues(typeof(TestStages)))\n            {\n                Dictionary<TestStages, List<Observer>> observersByStage = await RunLifecycle(observerCountByStage, stage, null);\n\n                Assert.Equal(observerCountByStage.Count, observersByStage.Count);\n                foreach (KeyValuePair<TestStages, List<Observer>> kvp in observersByStage)\n                {\n                    Assert.Equal(observerCountByStage[kvp.Key], kvp.Value.Count);\n                    if (kvp.Key < stage)\n                    {\n                        Assert.True(kvp.Value.All(o => o.Started));\n                        Assert.True(kvp.Value.All(o => o.Stopped));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStart));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStop));\n                    } else if (kvp.Key == stage)\n                    {\n                        Assert.True(kvp.Value.All(o => o.Started));\n                        Assert.True(kvp.Value.All(o => o.Stopped));\n                        Assert.True(kvp.Value.All(o => o.FailedOnStart));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStop));\n                    } else if (kvp.Key > stage)\n                    {\n                        Assert.True(kvp.Value.All(o => !o.Started));\n                        Assert.True(kvp.Value.All(o => !o.Stopped));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStart));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStop));\n                    }\n                }\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\n        public async Task FailOnStopOnEachStageLifecycleTest()\n        {\n            const int observersPerStage = 2;\n            Dictionary<TestStages, int> observerCountByStage = new Dictionary<TestStages, int>();\n            foreach (TestStages stage in Enum.GetValues(typeof(TestStages)))\n            {\n                observerCountByStage[stage] = observersPerStage;\n            }\n\n            foreach (TestStages stage in Enum.GetValues(typeof(TestStages)))\n            {\n                Dictionary<TestStages, List<Observer>> observersByStage = await RunLifecycle(observerCountByStage, null, stage);\n\n                Assert.Equal(observerCountByStage.Count, observersByStage.Count);\n                foreach (KeyValuePair<TestStages, List<Observer>> kvp in observersByStage)\n                {\n                    Assert.Equal(observerCountByStage[kvp.Key], kvp.Value.Count);\n                    if (kvp.Key != stage)\n                    {\n                        Assert.True(kvp.Value.All(o => o.Started));\n                        Assert.True(kvp.Value.All(o => o.Stopped));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStart));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStop));\n                    }\n                    else if (kvp.Key == stage)\n                    {\n                        Assert.True(kvp.Value.All(o => o.Started));\n                        Assert.True(kvp.Value.All(o => o.Stopped));\n                        Assert.True(kvp.Value.All(o => !o.FailedOnStart));\n                        Assert.True(kvp.Value.All(o => o.FailedOnStop));\n                    }\n                }\n            }\n        }\n\n        private class TestLifecycleSubject : LifecycleSubject\n        {\n            public TestLifecycleSubject() : base(NullLogger.Instance)\n            {\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\n        public async Task MultiStageObserverLifecycleTest()\n        {\n            var lifecycle = new TestLifecycleSubject();\n            var multiStageObserver = new MultiStageObserver();\n            multiStageObserver.Participate(lifecycle);\n            await lifecycle.OnStart();\n            await lifecycle.OnStop();\n            Assert.Equal(4, multiStageObserver.Started.Count);\n            Assert.Equal(4, multiStageObserver.Stopped.Count);\n            Assert.True(multiStageObserver.Started.Values.All(o => o));\n            Assert.True(multiStageObserver.Stopped.Values.All(o => o));\n        }\n\n        private static async Task<Dictionary<TestStages,List<Observer>>> RunLifecycle(Dictionary<TestStages,int> observerCountByStage, TestStages? failOnStart, TestStages? failOnStop)\n        {\n            // setup lifecycle observers\n            var observersByStage = new Dictionary<TestStages, List<Observer>>();\n            var lifecycle = new TestLifecycleSubject();\n            foreach (KeyValuePair<TestStages, int> kvp in observerCountByStage)\n            {\n                List<Observer> observers = Enumerable\n                    .Range(0, kvp.Value)\n                    .Select(i => new Observer(failOnStart.HasValue && kvp.Key == failOnStart, failOnStop.HasValue && kvp.Key == failOnStop))\n                    .ToList();\n                observersByStage[kvp.Key] = observers;\n                observers.ForEach(o => lifecycle.Subscribe((int)kvp.Key, o));\n            }\n\n            // run lifecycle\n            if (failOnStart.HasValue)\n            {\n                await Assert.ThrowsAsync<Exception>(() => lifecycle.OnStart());\n            }\n            else\n            {\n                await lifecycle.OnStart();\n            }\n            await lifecycle.OnStop();\n\n            // return results\n            return observersByStage;\n        }\n\n        private enum TestStages\n        {\n            Down,\n            Initialize,\n            Configure,\n            Run,\n        }\n\n        private class Observer : ILifecycleObserver\n        {\n            private readonly bool failOnStart;\n            private readonly bool failOnStop;\n\n            public bool Started { get; private set; }\n            public bool Stopped { get; private set; }\n            public bool FailedOnStart { get; private set; }\n            public bool FailedOnStop { get; private set; }\n\n            public Observer(bool failOnStart, bool failOnStop)\n            {\n                this.failOnStart = failOnStart;\n                this.failOnStop = failOnStop;\n            }\n\n            public Task OnStart(CancellationToken ct)\n            {\n                this.Started = true;\n                this.FailedOnStart = this.failOnStart;\n                if (this.failOnStart) throw new Exception(\"failOnStart\");\n                return Task.CompletedTask;\n            }\n\n            public Task OnStop(CancellationToken ct)\n            {\n                this.Stopped = true;\n                this.FailedOnStop = this.failOnStop;\n                if (this.failOnStop) throw new Exception(\"failOnStop\");\n                return Task.CompletedTask;\n            }\n        }\n\n        /// <summary>\n        /// Single component which takes action at multiple stages of the lifecycle (most common expected pattern)\n        /// </summary>\n        private class MultiStageObserver : ILifecycleParticipant<ILifecycleObservable>\n        {\n            public Dictionary<TestStages,bool> Started { get; } = new Dictionary<TestStages, bool>(); \n            public Dictionary<TestStages, bool> Stopped { get; } = new Dictionary<TestStages, bool>();\n\n\n            private Task OnStartStage(TestStages stage)\n            {\n                this.Started[stage] = true;\n                return Task.CompletedTask;\n            }\n\n            private Task OnStopStage(TestStages stage)\n            {\n                this.Stopped[stage] = true;\n                return Task.CompletedTask;\n            }\n\n            public void Participate(ILifecycleObservable lifecycle)\n            {\n                lifecycle.Subscribe<MultiStageObserver>((int)TestStages.Down, ct => OnStartStage(TestStages.Down), ct => OnStopStage(TestStages.Down));\n                lifecycle.Subscribe<MultiStageObserver>((int)TestStages.Initialize, ct => OnStartStage(TestStages.Initialize), ct => OnStopStage(TestStages.Initialize));\n                lifecycle.Subscribe<MultiStageObserver>((int)TestStages.Configure, ct => OnStartStage(TestStages.Configure), ct => OnStopStage(TestStages.Configure));\n                lifecycle.Subscribe<MultiStageObserver>((int)TestStages.Run, ct => OnStartStage(TestStages.Run), ct => OnStopStage(TestStages.Run));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/LocalhostSiloTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Internal;\nusing Orleans.TestingHost;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester\n{\n    /// <summary>\n    /// Tests for localhost clustering mode, designed for local development and testing.\n    /// \n    /// UseLocalhostClustering configures Orleans to run on localhost without external dependencies\n    /// like Azure Storage or SQL Server. This mode:\n    /// - Uses in-memory membership provider\n    /// - Configures silos to communicate via localhost\n    /// - Supports both single-silo and multi-silo configurations\n    /// - Ideal for unit tests, development, and debugging\n    /// \n    /// These tests verify that localhost clustering works correctly for both single-silo\n    /// and multi-silo scenarios, ensuring developers can easily run Orleans locally.\n    /// </summary>\n    [TestCategory(\"Functional\")]\n    public class LocalhostClusterTests\n    {\n        /// <summary>\n        /// Tests localhost clustering with a single silo.\n        /// Verifies:\n        /// - Silo can start with localhost clustering\n        /// - Client can connect using localhost clustering\n        /// - Basic grain calls work in this configuration\n        /// This is the simplest Orleans setup for local development.\n        /// </summary>\n        [Fact]\n        public async Task LocalhostSiloTest()\n        {\n            using var portAllocator = new TestClusterPortAllocator();\n            var (siloPort, gatewayPort) = portAllocator.AllocateConsecutivePortPairs(1);\n            // Configure a single silo with localhost clustering\n            // siloPort: for silo-to-silo communication (not used in single silo)\n            // gatewayPort: for client-to-silo communication\n            var host = new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder.AddMemoryGrainStorage(\"MemoryStore\")\n                .UseLocalhostClustering(siloPort, gatewayPort);\n            }).Build();\n\n            // Configure client to connect to the localhost silo\n            var clientHost = new HostBuilder().UseOrleansClient((ctx, clientBuilder) =>\n            {\n                clientBuilder.UseLocalhostClustering(gatewayPort);\n            }).Build();\n\n            var client = clientHost.Services.GetRequiredService<IClusterClient>();\n\n            try\n            {\n                await host.StartAsync();\n                await clientHost.StartAsync();\n                var grain = client.GetGrain<IEchoGrain>(Guid.NewGuid());\n                var result = await grain.Echo(\"test\");\n                Assert.Equal(\"test\", result);\n            }\n            finally\n            {\n                await OrleansTaskExtentions.SafeExecute(() => host.StopAsync());\n                await OrleansTaskExtentions.SafeExecute(() => clientHost.StopAsync());\n                Utils.SafeExecute(() => host.Dispose());\n                Utils.SafeExecute(() => clientHost.Dispose());\n            }\n        }\n\n        /// <summary>\n        /// Tests localhost clustering with multiple silos forming a cluster.\n        /// Verifies:\n        /// - Multiple silos can form a cluster on localhost\n        /// - Silos discover each other through the primary silo endpoint\n        /// - Client can connect to multiple gateways for high availability\n        /// - Distributed grain directory works in multi-silo setup\n        /// This demonstrates a more realistic local development scenario.\n        /// </summary>\n        [Fact]\n        public async Task LocalhostClusterTest()\n        {\n            using var portAllocator = new TestClusterPortAllocator();\n            var (baseSiloPort, baseGatewayPort) = portAllocator.AllocateConsecutivePortPairs(2);\n            // Silo 1: Primary silo that others will connect to\n            var silo1 = new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder\n                .AddMemoryGrainStorage(\"MemoryStore\")\n                .UseLocalhostClustering(baseSiloPort, baseGatewayPort);\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                // Distributed grain directory allows grain activations across multiple silos\n                siloBuilder.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n            }).Build();\n\n            // Silo 2: Secondary silo that connects to the primary\n            // Note the third parameter: primary silo endpoint for cluster discovery\n            var silo2 = new HostBuilder().UseOrleans((ctx, siloBuilder) =>\n            {\n                siloBuilder\n                .AddMemoryGrainStorage(\"MemoryStore\")\n                .UseLocalhostClustering(baseSiloPort + 1, baseGatewayPort + 1, new IPEndPoint(IPAddress.Loopback, baseSiloPort));\n#pragma warning disable ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n                siloBuilder.AddDistributedGrainDirectory();\n#pragma warning restore ORLEANSEXP003 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n            }).Build();\n\n            // Client configured with multiple gateway ports for load balancing/failover\n            var clientHost = new HostBuilder().UseOrleansClient((ctx, clientBuilder) =>\n            {\n                clientBuilder.UseLocalhostClustering([baseGatewayPort, baseGatewayPort + 1]);\n            }).Build();\n\n            var client = clientHost.Services.GetRequiredService<IClusterClient>();\n\n            try\n            {\n                await silo1.StartAsync();\n                await silo2.StartAsync();\n                await clientHost.StartAsync();\n\n                var grain = client.GetGrain<IEchoGrain>(Guid.NewGuid());\n                var result = await grain.Echo(\"test\");\n                Assert.Equal(\"test\", result);\n            }\n            finally\n            {\n                using var cancelled = new CancellationTokenSource();\n                cancelled.Cancel();\n                await Utils.SafeExecuteAsync(clientHost.StopAsync(cancelled.Token));\n                await Utils.SafeExecuteAsync(silo2.StopAsync(cancelled.Token));\n                await Utils.SafeExecuteAsync(silo1.StopAsync(cancelled.Token));\n                Utils.SafeExecute(() => clientHost.Dispose());\n                Utils.SafeExecute(() => silo2.Dispose());\n                Utils.SafeExecute(() => silo1.Dispose());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/LogFomatterTests.cs",
    "content": "using System.Collections.Concurrent;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Xunit;\n\nnamespace Tester\n{\n    /// <summary>\n    /// Tests for custom option formatters and formatter resolution, including support for named options and redaction of sensitive data.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class LogFomatterTests\n    {\n        [Fact]\n        public void CanResolveFormatter()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptions>(options => options.IntField = 1);\n            services.ConfigureFormatter<TestOptions, TestOptionsFormatter>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptions>);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void CanResolveGenericFormatter()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptions>(options => options.IntField = 1);\n            services.ConfigureFormatter<TestOptions>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptions>);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void GenericFormatterRedact()\n        {\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptionsWithSecrets>(options => {\n                options.Data = \"Hello\";\n                // [SuppressMessage(\"Microsoft.Security\", \"CS002:SecretInNextLine\", Justification=\"Not a secret\")]\n                options.Password = \"v3ryS3cur3!!!\";\n                options.SomeConnectionString = \"DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=someKey;EndpointSuffix=core.windows.net\";\n            });\n            services.ConfigureFormatter<TestOptionsWithSecrets>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptionsWithSecrets>);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Contains(\"Hello\", actual.ToString());\n            Assert.Contains(\"Password: REDACTED\", actual.ToString());\n            Assert.Contains(\"SomeConnectionString: DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=<--SNIP-->\", actual.ToString());\n        }\n\n        [Fact]\n        public void GenericFormatterWithListAndDictionary()\n        {\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptionsWithListAndDictionary>(options => {\n                options.SomeDictionary.Add(\"Account1\", \"Key1\");\n                options.SomeDictionary.Add(\"Account2\", \"Key2\");\n                options.SomeDictionary.Add(\"Account3\", \"Key3\");\n                options.SomeList.Add(10);\n                options.SomeList.Add(11);\n            });\n            services.ConfigureFormatter<TestOptionsWithListAndDictionary>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptionsWithListAndDictionary>);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            var txt = actual.ToString();\n            Assert.Contains(\"SomeList.0: 10\", actual.ToString());\n            Assert.Contains(\"SomeList.1: 11\", actual.ToString());\n            Assert.Contains(\"SomeDictionary.Account1: Key1\", actual.ToString());\n            Assert.Contains(\"SomeDictionary.Account2: Key2\", actual.ToString());\n            Assert.Contains(\"SomeDictionary.Account3: Key3\", actual.ToString());\n            Assert.Contains(\"NullList:\", actual.ToString());\n            Assert.Contains(\"NullDictionary:\", actual.ToString());\n        }\n\n        [Fact]\n        public void FormatterConfiguredTwiceDoesNotLeadToDuplicatedFormatter()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptions>(options => options.IntField = 1);\n            services.ConfigureFormatter<TestOptions, TestOptionsFormatter2>();\n            //the formatter configured second time will override the first one in DI and\n            //DI will end up with two formatter for the same option\n            services.ConfigureFormatter<TestOptions, TestOptionsFormatter>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            // only one options formater and it points to the right one\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptions>);\n            // when resolving singe type specific formatter, we get the right one\n            var logFormatter = servicesProvider.GetService<IOptionFormatter<TestOptions>>();\n            Assert.True(logFormatter is TestOptionsFormatter);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void CustomFormatterOverridesDefaultFormatter_PreRegistration()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptions>(options => options.IntField = 1);\n            // pre register overrides\n            services.ConfigureFormatter<TestOptions, TestOptionsFormatter>();\n            // default\n            services.TryConfigureFormatter<TestOptions, TestOptionsFormatter2>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptions>);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void CustomFormatterOverridesDefaultFormatter_PostRegistration()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.Configure<TestOptions>(options => options.IntField = 1);\n            // default\n            services.TryConfigureFormatter<TestOptions, TestOptionsFormatter2>();\n            // post register overrides\n            services.ConfigureFormatter<TestOptions, TestOptionsFormatter>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Single(logFormatters);\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.First() is IOptionFormatter<TestOptions>);\n            // when resolving singe type specific formatter, we get the right one\n            var logFormatter = servicesProvider.GetService<IOptionFormatter<TestOptions>>();\n            Assert.True(logFormatter is TestOptionsFormatter);\n            // ensure logging output is as expected\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void NamedFormatterGoldenPath()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildNamedOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            services.ConfigureFormatterResolver<TestOptions, TestOptionsFormatter.Resolver>();\n            Enumerable\n                .Range(1, 3)\n                .ToList()\n                .ForEach(i =>\n                {\n                    string name = i.ToString();\n                    services.Configure<TestOptions>(name, (options => options.IntField = i));\n                    services.ConfigureNamedOptionForLogging<TestOptions>(name);\n                });\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Equal(3, logFormatters.Count());\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(1) is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(2) is TestOptionsFormatter);\n            var logFormatter = servicesProvider.GetService<IOptionFormatterResolver<TestOptions>>();\n            Assert.True(logFormatter is TestOptionsFormatter.Resolver);\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void NamedGenericFormatterGoldenPath()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildNamedOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton(typeof(IOptionFormatter<>), typeof(DefaultOptionsFormatter<>));\n            services.AddSingleton(typeof(IOptionFormatterResolver<>), typeof(DefaultOptionsFormatterResolver<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            Enumerable\n                .Range(1, 3)\n                .ToList()\n                .ForEach(i =>\n                {\n                    string name = i.ToString();\n                    services.Configure<TestOptions>(name, (options => options.IntField = i));\n                    services.ConfigureNamedOptionForLogging<TestOptions>(name);\n                });\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Equal(3, logFormatters.Count());\n            var logFormatter = servicesProvider.GetService<IOptionFormatterResolver<TestOptions>>();\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void CustomFormatterResolverOverridesDefaultFormatter_PreRegistration()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildNamedOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            // pre register overrides\n            services.ConfigureFormatterResolver<TestOptions, TestOptionsFormatter.Resolver>();\n            // configure options\n            Enumerable\n                .Range(1, 3)\n                .ToList()\n                .ForEach(i =>\n                {\n                    string name = i.ToString();\n                    services.Configure<TestOptions>(name, (options => options.IntField = i));\n                    services.ConfigureNamedOptionForLogging<TestOptions>(name);\n                });\n            // default\n            services.TryConfigureFormatterResolver<TestOptions, TestOptionsFormatter2.Resolver>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Equal(3, logFormatters.Count());\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(1) is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(2) is TestOptionsFormatter);\n            var logFormatter = servicesProvider.GetService<IOptionFormatterResolver<TestOptions>>();\n            Assert.True(logFormatter is TestOptionsFormatter.Resolver);\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        [Fact]\n        public void CustomFormatterResolverOverridesDefaultFormatter_PostRegistration()\n        {\n            // expected output\n            TestLoggerFactory expected = BuildNamedOptionsExpectedResult();\n\n            // actual output\n            var services = new ServiceCollection();\n            services.AddOptions();\n            services.AddSingleton<TestLoggerFactory>();\n            services.AddSingleton<ILoggerFactory>(sp => sp.GetRequiredService<TestLoggerFactory>());\n            services.AddSingleton(typeof(ILogger<>), typeof(TestLogger<>));\n            services.AddSingleton<OptionsLogger, TestOptionsLogger>();\n            // defaults\n            services.TryConfigureFormatterResolver<TestOptions, TestOptionsFormatter2.Resolver>();\n            // configure options\n            Enumerable\n                .Range(1, 3)\n                .ToList()\n                .ForEach(i =>\n                {\n                    string name = i.ToString();\n                    services.Configure<TestOptions>(name, (options => options.IntField = i));\n                    services.ConfigureNamedOptionForLogging<TestOptions>(name);\n                });\n            // post register overrides\n            services.ConfigureFormatterResolver<TestOptions, TestOptionsFormatter.Resolver>();\n            var servicesProvider = services.BuildServiceProvider();\n            servicesProvider.GetRequiredService<OptionsLogger>().LogOptions();\n\n            var logFormatters = servicesProvider.GetServices<IOptionFormatter>();\n            Assert.Equal(3, logFormatters.Count());\n            Assert.True(logFormatters.First() is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(1) is TestOptionsFormatter);\n            Assert.True(logFormatters.ElementAt(2) is TestOptionsFormatter);\n            var logFormatter = servicesProvider.GetService<IOptionFormatterResolver<TestOptions>>();\n            Assert.True(logFormatter is TestOptionsFormatter.Resolver);\n            var actual = servicesProvider.GetRequiredService<TestLoggerFactory>();\n            Assert.Equal(expected.ToString(), actual.ToString());\n        }\n\n        private static TestLoggerFactory BuildOptionsExpectedResult()\n        {\n            var services = new ServiceCollection();\n            var testOptions = new TestOptions\n            {\n                IntField = 1\n            };\n            var expected = new TestLoggerFactory();\n            var formatter = new TestOptionsFormatter(Options.Create(testOptions));\n            var optionsLogger = new TestOptionsLogger(expected.CreateLogger<TestOptionsLogger>(), services.BuildServiceProvider());\n            optionsLogger.LogOption(formatter);\n            return expected;\n        }\n\n        private static TestLoggerFactory BuildNamedOptionsExpectedResult()\n        {\n            var services = new ServiceCollection();\n            IOptionFormatter[] formatters = Enumerable\n                .Range(1, 3)\n                .Select(i =>  TestOptionsFormatter.CreateNamed(i.ToString(), Options.Create(new TestOptions { IntField = i })))\n                .ToArray<IOptionFormatter>();\n            var expected = new TestLoggerFactory();\n            var optionsLogger = new TestOptionsLogger(expected.CreateLogger<TestOptionsLogger>(), services.BuildServiceProvider());\n            optionsLogger.LogOptions(formatters);\n            return expected;\n        }\n\n        private class TestOptionsWithSecrets\n        {\n            [Redact()]\n            public string Password { get; set; }\n\n            public string Data { get; set; }\n\n            [RedactConnectionString()]\n            public string SomeConnectionString { get; set; }\n        }\n\n        private class TestOptions\n        {\n            public int IntField { get; set; } = 0;\n        }\n\n        private class TestOptionsWithListAndDictionary\n        {\n            public List<int> SomeList { get; set; } = new List<int>();\n\n            public Dictionary<string, string> SomeDictionary { get; set; } = new Dictionary<string, string>();\n\n            public List<int> NullList { get; set; } = null;\n\n            public Dictionary<string, string> NullDictionary { get; set; } = null;\n        }\n\n        private class TestOptionsFormatter2 : IOptionFormatter<TestOptions>\n        {\n            public string Name { get; private set; }\n\n            private readonly TestOptions options;\n            public TestOptionsFormatter2(IOptions<TestOptions> options)\n            {\n                this.options = options.Value;\n                this.Name = nameof(TestOptions);\n            }\n\n            public static TestOptionsFormatter2 CreateNamed(string name, IOptions<TestOptions> options)\n            {\n                var result = new TestOptionsFormatter2(options);\n                // different format\n                result.Name = $\"{nameof(TestOptions)}+{name}\";\n                return result;\n            }\n\n            public IEnumerable<string> Format()\n            {\n                return new List<string>()\n                {\n                    // different format\n                    OptionFormattingUtilities.Format(nameof(options.IntField), options.IntField, \"{0}=>{1}\")\n                };\n            }\n\n            public class Resolver : IOptionFormatterResolver<TestOptions>\n            {\n                private readonly IOptionsMonitor<TestOptions> optionsMonitor;\n                public Resolver(IOptionsMonitor<TestOptions> optionsMonitor)\n                {\n                    this.optionsMonitor = optionsMonitor;\n                }\n\n                public IOptionFormatter<TestOptions> Resolve(string name)\n                {\n                    return TestOptionsFormatter2.CreateNamed(name, Options.Create(this.optionsMonitor.Get(name)));\n                }\n            }\n        }\n\n        private class TestOptionsFormatter : IOptionFormatter<TestOptions>\n        {\n            public string Name { get; private set; }\n\n            private readonly TestOptions options;\n            public TestOptionsFormatter(IOptions<TestOptions> options)\n            {\n                this.options = options.Value;\n                this.Name = typeof(TestOptions).FullName;\n            }\n\n            public static TestOptionsFormatter CreateNamed(string name, IOptions<TestOptions> options)\n            {\n                var result = new TestOptionsFormatter(options);\n                result.Name = $\"{typeof(TestOptions).FullName}-{name}\";\n                return result;\n            }\n\n            public IEnumerable<string> Format()\n            {\n                return new List<string>()\n                {\n                    OptionFormattingUtilities.Format(nameof(options.IntField), options.IntField)\n                };\n            }\n\n            public class Resolver : IOptionFormatterResolver<TestOptions>\n            {\n                private readonly IOptionsMonitor<TestOptions> optionsMonitor;\n                public Resolver(IOptionsMonitor<TestOptions> optionsMonitor)\n                {\n                    this.optionsMonitor = optionsMonitor;\n                }\n\n                public IOptionFormatter<TestOptions> Resolve(string name)\n                {\n                    return TestOptionsFormatter.CreateNamed(name, Options.Create(this.optionsMonitor.Get(name)));\n                }\n            }\n        }\n\n        private class TestLoggerFactory : ILoggerFactory\n        {\n            private readonly ConcurrentDictionary<string, Logger> loggers = new ConcurrentDictionary<string, Logger>();\n\n            public void AddProvider(ILoggerProvider provider)\n            {\n                throw new NotImplementedException();\n            }\n\n            public ILogger CreateLogger(string categoryName)\n            {\n                return this.loggers.GetOrAdd(categoryName, new Logger());\n            }\n\n            public void Dispose()\n            {\n            }\n\n            public override string ToString()\n            {\n                return string.Join(\":\", this.loggers.Select(kvp => $\"{kvp.Key} =\\n{kvp.Value.ToString()}\\n\"));\n            }\n\n            private class Logger : ILogger\n            {\n                private readonly List<string> entries = new List<string>();\n\n                public IDisposable BeginScope<TState>(TState state)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public override string ToString()\n                {\n                    return string.Join(\";\", this.entries);\n                }\n\n                public bool IsEnabled(LogLevel logLevel)\n                {\n                    return true;\n                }\n\n                public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n                {\n                    entries.Add(formatter(state, exception));\n                }\n            }\n        }\n\n        private class TestLogger<T> : ILogger<T>\n        {\n            private readonly ILogger<T> logger;\n\n            public TestLogger(ILoggerFactory loggerFactory)\n            {\n                this.logger = loggerFactory.CreateLogger<T>();\n            }\n\n            public IDisposable BeginScope<TState>(TState state)\n            {\n                return logger.BeginScope<TState>(state);\n            }\n\n            public bool IsEnabled(LogLevel logLevel)\n            {\n                return logger.IsEnabled(logLevel);\n            }\n\n            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n            {\n                logger.Log<TState>(logLevel, eventId, state, exception, formatter);\n            }\n        }\n\n\n        private class TestOptionsLogger : OptionsLogger\n        {\n            public TestOptionsLogger(ILogger<TestOptionsLogger> logger, IServiceProvider services)\n                : base(logger, services)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ManagementGrainTests.cs",
    "content": "using System.Text;\nusing Orleans.Runtime;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\nusing Xunit.Abstractions;\n\n// ReSharper disable ConvertToConstant.Local\n\nnamespace UnitTests.Management\n{\n    /// <summary>\n    /// Tests for the Orleans Management Grain, which provides runtime statistics and cluster management.\n    /// \n    /// The Management Grain (IManagementGrain) is a system grain that provides:\n    /// - Cluster topology information (active silos, their status)\n    /// - Grain activation statistics (counts per type, per silo)\n    /// - Runtime metrics and diagnostics\n    /// \n    /// These capabilities are essential for:\n    /// - Monitoring cluster health\n    /// - Debugging activation distribution\n    /// - Building management dashboards\n    /// - Implementing custom placement strategies based on current load\n    /// </summary>\n    public class ManagementGrainTests :  OrleansTestingBase, IClassFixture<ManagementGrainTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private readonly ITestOutputHelper output;\n        private readonly IManagementGrain mgmtGrain;\n\n        public ManagementGrainTests(Fixture fixture, ITestOutputHelper output)\n        {\n            this.fixture = fixture;\n            this.output = output;\n            mgmtGrain = this.fixture.Client.GetGrain<IManagementGrain>(0);\n        }\n\n        private TestCluster HostedCluster => this.fixture.HostedCluster;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                // The ActivationCount tests rely on CounterStatistic, which is a shared static value, so isolation\n                // between silos is obtained using external processes. This ensures each silo maintains independent\n                // statistics rather than sharing them through static fields in the same process.\n                builder.CreateSiloAsync = StandaloneSiloHandle.CreateForAssembly(this.GetType().Assembly);\n                builder.Properties[\"GrainAssembly\"] = $\"{typeof(SimpleGrain).Assembly}\";\n            }\n        }\n\n        /// <summary>\n        /// Tests retrieval of cluster topology information.\n        /// GetHosts returns all active silos in the cluster with their current status.\n        /// This is fundamental for understanding cluster composition and health.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Management\")]\n        public async Task GetHosts()\n        {\n            if (HostedCluster.SecondarySilos.Count == 0)\n            {\n                await HostedCluster.StartAdditionalSiloAsync();\n                await HostedCluster.WaitForLivenessToStabilizeAsync();\n            }\n\n            var numberOfActiveSilos = 1 + HostedCluster.SecondarySilos.Count; // Primary + secondaries\n            Dictionary<SiloAddress, SiloStatus> siloStatuses = await mgmtGrain.GetHosts(true);\n            Assert.NotNull(siloStatuses);\n            Assert.Equal(numberOfActiveSilos, siloStatuses.Count);\n        }\n\n        /// <summary>\n        /// Tests retrieval of detailed host information including additional metadata.\n        /// GetDetailedHosts provides more comprehensive information about each silo,\n        /// useful for detailed diagnostics and monitoring dashboards.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Management\")]\n        public async Task GetDetailedHosts()\n        {\n            if (HostedCluster.SecondarySilos.Count == 0)\n            {\n                await HostedCluster.StartAdditionalSiloAsync();\n                await HostedCluster.WaitForLivenessToStabilizeAsync();\n            }\n\n            var numberOfActiveSilos = 1 + HostedCluster.SecondarySilos.Count; // Primary + secondaries\n            var siloStatuses = await mgmtGrain.GetDetailedHosts(true);\n            Assert.NotNull(siloStatuses);\n            Assert.Equal(numberOfActiveSilos, siloStatuses.Length);\n        }\n\n\n        /// <summary>\n        /// Tests basic grain statistics retrieval.\n        /// Verifies that:\n        /// - Statistics are returned for active grain types\n        /// - Grain type names are properly formatted (without 'Activation' suffix)\n        /// This data is crucial for understanding what grains are active in the cluster.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Management\")]\n        public void GetSimpleGrainStatistics()\n        {\n            SimpleGrainStatistic[] stats = this.GetSimpleGrainStatisticsRunner(\"Initial\");\n            Assert.True(stats.Length > 0, \"Got some grain statistics: \" + stats.Length);\n            foreach (var s in stats)\n            {\n                Assert.False(s.GrainType.EndsWith(\"Activation\"), \"Grain type name should not end with 'Activation' - \" + s.GrainType);\n            }\n        }\n\n        /// <summary>\n        /// Tests that activation counts are correctly tracked for SimpleGrain.\n        /// Verifies that:\n        /// - Creating a new grain activation increments the count\n        /// - Statistics accurately reflect the number of active grains\n        /// This is essential for load monitoring and placement decisions.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Management\")]\n        public async Task GetSimpleGrainStatistics_ActivationCounts()\n        {\n            await RunGetStatisticsTest<ISimpleGrain, SimpleGrain>(g => g.GetA());\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Management\")]\n        public async Task GetTestGrainStatistics_ActivationCounts()\n        {\n            await RunGetStatisticsTest<ITestGrain, TestGrain>(g => g.GetKey());\n        }\n\n        /// <summary>\n        /// Generic test helper that verifies activation counting for any grain type.\n        /// Process:\n        /// 1. Get initial statistics and count existing activations\n        /// 2. Create and activate a new grain by calling a method\n        /// 3. Verify the activation count increased by exactly 1\n        /// This ensures the management grain correctly tracks grain lifecycle events.\n        /// </summary>\n        private async Task RunGetStatisticsTest<TGrainInterface, TGrain>(Func<TGrainInterface, Task> callGrainMethodAction)\n            where TGrainInterface : IGrainWithIntegerKey\n            where TGrain : TGrainInterface\n        {\n            SimpleGrainStatistic[] stats = this.GetSimpleGrainStatisticsRunner(\"Before Create\");\n            Assert.True(stats.Length > 0, \"Got some grain statistics: \" + stats.Length);\n\n            string grainType = RuntimeTypeNameFormatter.Format(typeof(TGrain));\n            int initialStatisticsCount = stats.Count(s => s.GrainType == grainType);\n            int initialActivationsCount = stats.Where(s => s.GrainType == grainType).Sum(s => s.ActivationCount);\n            var grain1 = this.fixture.Client.GetGrain<TGrainInterface>(Random.Shared.Next());\n            await callGrainMethodAction(grain1); // Call grain method to ensure activation\n            stats = this.GetSimpleGrainStatisticsRunner(\"After Invoke\");\n            Assert.True(stats.Count(s => s.GrainType == grainType) >= initialStatisticsCount, \"Activation counter now exists for grain: \" + grainType);\n            int expectedActivationsCount = initialActivationsCount + 1;\n            int actualActivationsCount = stats.Where(s => s.GrainType == grainType).Sum(s => s.ActivationCount);\n            Assert.Equal(expectedActivationsCount, actualActivationsCount);\n        }\n\n        private SimpleGrainStatistic[] GetSimpleGrainStatisticsRunner(string when)\n        {\n            SimpleGrainStatistic[] stats = mgmtGrain.GetSimpleGrainStatistics(null).Result;\n            StringBuilder sb = new StringBuilder();\n            foreach (var s in stats) sb.AppendLine().Append(s);\n            sb.AppendLine();\n            output.WriteLine(\"Grain statistics returned by Orleans Management Grain - \" + when + \" : \" + sb);\n            return stats;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/MembershipTests/LivenessTests.cs",
    "content": "using System.Globalization;\nusing System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Base class for testing silo liveness detection and membership management during silo failures and restarts.\n    /// </summary>\n    public abstract class LivenessTestsBase : TestClusterPerTest\n    {\n        private readonly ITestOutputHelper output;\n        private const int numAdditionalSilos = 1;\n        private const int numGrains = 20;\n\n        public LivenessTestsBase(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        protected async Task Do_Liveness_OracleTest_1()\n        {\n            output.WriteLine(\"ClusterId= {0}\", this.HostedCluster.Options.ClusterId);\n\n            SiloHandle silo3 = await this.HostedCluster.StartAdditionalSiloAsync();\n\n            IManagementGrain mgmtGrain = this.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            Dictionary<SiloAddress, SiloStatus> statuses = await mgmtGrain.GetHosts(false);\n            foreach (var pair in statuses)\n            {\n                output.WriteLine(\"       ######## Silo {0}, status: {1}\", pair.Key, pair.Value);\n                Assert.Equal(SiloStatus.Active, pair.Value);\n            }\n            Assert.Equal(3, statuses.Count);\n\n            IPEndPoint address = silo3.SiloAddress.Endpoint;\n            output.WriteLine(\"About to stop {0}\", address);\n            await this.HostedCluster.StopSiloAsync(silo3);\n\n            // TODO: Should we be allowing time for changes to percolate?\n\n            output.WriteLine(\"----------------\");\n\n            statuses = await mgmtGrain.GetHosts(false);\n            foreach (var pair in statuses)\n            {\n                output.WriteLine(\"       ######## Silo {0}, status: {1}\", pair.Key, pair.Value);\n                IPEndPoint silo = pair.Key.Endpoint;\n                if (silo.Equals(address))\n                {\n                    Assert.True(pair.Value == SiloStatus.ShuttingDown\n                        || pair.Value == SiloStatus.Stopping\n                        || pair.Value == SiloStatus.Dead,\n                        string.Format(\"SiloStatus for {0} should now be ShuttingDown or Stopping or Dead instead of {1}\", silo, pair.Value));\n                }\n                else\n                {\n                    Assert.Equal(SiloStatus.Active, pair.Value);\n                }\n            }\n        }\n\n        protected async Task Do_Liveness_OracleTest_2(int silo2Kill, bool restart = true, bool startTimers = false)\n        {\n            await this.HostedCluster.StartAdditionalSilosAsync(numAdditionalSilos);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            for (int i = 0; i < numGrains; i++)\n            {\n                await SendTraffic(i + 1, startTimers);\n            }\n\n            SiloHandle silo2KillHandle = this.HostedCluster.Silos[silo2Kill];\n\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to kill {Endpoint}\\n\\n\\n\", silo2KillHandle.SiloAddress.Endpoint);\n\n            if (restart)\n                await this.HostedCluster.RestartSiloAsync(silo2KillHandle);\n            else\n                await this.HostedCluster.KillSiloAsync(silo2KillHandle);\n\n            bool didKill = !restart;\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync(didKill);\n\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to start sending msg to grain again\\n\\n\\n\");\n\n            for (int i = 0; i < numGrains; i++)\n            {\n                await SendTraffic(i + 1);\n            }\n\n            for (int i = numGrains; i < 2 * numGrains; i++)\n            {\n                await SendTraffic(i + 1);\n            }\n            logger.LogInformation(\"======================================================\");\n        }\n\n        protected async Task Do_Liveness_OracleTest_3()\n        {\n            var moreSilos = await this.HostedCluster.StartAdditionalSilosAsync(1);\n            await this.HostedCluster.WaitForLivenessToStabilizeAsync();\n\n            await TestTraffic();\n\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to stop a first silo.\\n\\n\\n\");\n            var siloToStop = this.HostedCluster.SecondarySilos[0];\n            await this.HostedCluster.StopSiloAsync(siloToStop);\n\n            await TestTraffic();\n\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to re-start a first silo.\\n\\n\\n\");\n            \n            await this.HostedCluster.RestartStoppedSecondarySiloAsync(siloToStop.Name);\n\n            await TestTraffic();\n\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to stop a second silo.\\n\\n\\n\");\n            await this.HostedCluster.StopSiloAsync(moreSilos[0]);\n\n            await TestTraffic();\n\n            logger.LogInformation(\"======================================================\");\n        }\n\n        private async Task TestTraffic()\n        {\n            logger.LogInformation(\"\\n\\n\\n\\nAbout to start sending msg to grain again.\\n\\n\\n\");\n            // same grains\n            for (int i = 0; i < numGrains; i++)\n            {\n                await SendTraffic(i + 1);\n            }\n            // new random grains\n            for (int i = 0; i < numGrains; i++)\n            {\n                await SendTraffic(Random.Shared.Next(10000));\n            }\n        }\n\n        private async Task SendTraffic(long key, bool startTimers = false)\n        {\n            try\n            {\n                ILivenessTestGrain grain = this.GrainFactory.GetGrain<ILivenessTestGrain>(key);\n                Assert.Equal(key, grain.GetPrimaryKeyLong());\n                Assert.Equal(key.ToString(CultureInfo.InvariantCulture), await grain.GetLabel());\n                await LogGrainIdentity(logger, grain);\n                if (startTimers)\n                {\n                    await grain.StartTimer();\n                }\n            }\n            catch (Exception exc)\n            {\n                logger.LogInformation(exc, \"Exception making grain call\");\n                throw;\n            }\n        }\n\n        private async Task LogGrainIdentity(ILogger logger, ILivenessTestGrain grain)\n        {\n            logger.LogInformation(\"Grain {Grain}, activation {Activation} on {Host}\",\n                await grain.GetGrainReference(),\n                await grain.GetUniqueId(),\n                await grain.GetRuntimeInstanceId());\n        }\n    }\n\n    /// <summary>\n    /// Tests silo liveness detection using membership grain with specific gateway preferences.\n    /// </summary>\n    public class LivenessTests_MembershipGrain : LivenessTestsBase\n    {\n        public LivenessTests_MembershipGrain(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddClientBuilderConfigurator<ClientConfigurator>();\n        }\n\n        public class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.Configure<GatewayOptions>(options => options.PreferredGatewayIndex = 1);\n            }\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Membership\")]\n        public async Task Liveness_Grain_1()\n        {\n            await Do_Liveness_OracleTest_1();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Membership\")]\n        public async Task Liveness_Grain_2_Restart_GW()\n        {\n            await Do_Liveness_OracleTest_2(1);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Membership\")]\n        public async Task Liveness_Grain_3_Restart_Silo_1()\n        {\n            await Do_Liveness_OracleTest_2(2);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Membership\")]\n        public async Task Liveness_Grain_4_Kill_Silo_1_With_Timers()\n        {\n            await Do_Liveness_OracleTest_2(2, false, true);\n        }\n\n        //[Fact, TestCategory(\"Functional\"), TestCategory(\"Membership\")]\n        /*public async Task Liveness_Grain_5_ShutdownRestartZeroLoss()\n        {\n            await Do_Liveness_OracleTest_3();\n        }*/\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/MembershipTests/SilosStopTests.cs",
    "content": "using System.Net;\nusing Microsoft.Extensions.Configuration;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.MembershipTests\n{\n    /// <summary>\n    /// Tests handling of ungraceful silo shutdowns and their impact on outstanding grain requests.\n    /// </summary>\n    public class SilosStopTests : TestClusterPerTest\n    {\n        private class BuilderConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .Configure<ClusterMembershipOptions>(options =>\n                    {\n                        options.NumMissedProbesLimit = 1;\n                        options.NumVotesForDeathDeclaration = 1;\n                        options.TableRefreshTimeout = TimeSpan.FromSeconds(2);\n                    })\n                    .Configure<SiloMessagingOptions>(options => options.AssumeHomogenousSilosForTesting = true);\n            }\n\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                var clusterOptions = configuration.GetTestClusterOptions();\n                clientBuilder.UseStaticClustering(new IPEndPoint(IPAddress.Loopback, clusterOptions.BaseGatewayPort));\n            }\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddClientBuilderConfigurator<BuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<BuilderConfigurator>();\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Liveness\")]\n        public async Task SiloUngracefulShutdown_OutstandingRequestsBreak()\n        {\n            var grain = await GetGrainOnTargetSilo(HostedCluster.Primary);\n            Assert.NotNull(grain);\n            var target = await GetGrainOnTargetSilo(HostedCluster.SecondarySilos[0]);\n            Assert.NotNull(target);\n\n            var promise = grain.CallOtherLongRunningTask(target, true, TimeSpan.FromSeconds(7));\n\n            await Task.Delay(500);\n            await HostedCluster.KillSiloAsync(HostedCluster.SecondarySilos[0]);\n\n            await Assert.ThrowsAsync<SiloUnavailableException>(() => promise);\n        }\n\n        private async Task<ILongRunningTaskGrain<bool>> GetGrainOnTargetSilo(SiloHandle siloHandle)\n        {\n            const int maxRetry = 10;\n            for (int i = 0; i < maxRetry; i++)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, siloHandle.SiloAddress);\n                var grain = GrainFactory.GetGrain<ILongRunningTaskGrain<bool>>(Guid.NewGuid());\n                var instanceId = await grain.GetRuntimeInstanceId();\n                if (instanceId.Contains(siloHandle.SiloAddress.Endpoint.ToString()))\n                    return grain;\n                await Task.Delay(100);\n            }\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/MinimalReminderTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.CatalogTests\n{\n    /// <summary>\n    /// Tests reminder functionality with minimal interval configuration (100ms) using in-memory reminder service.\n    /// </summary>\n    public class MinimalReminderTests : IClassFixture<MinimalReminderTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloConfiguration>();\n            }\n        }\n\n        public class SiloConfiguration : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder)\n            {\n                siloBuilder.Configure<ReminderOptions>(options =>\n                        options.MinimumReminderPeriod = TimeSpan.FromMilliseconds(100))\n                    .UseInMemoryReminderService();\n            }\n        }\n\n        public MinimalReminderTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"Catalog\"), TestCategory(\"Functional\")]\n        public async Task MinimalReminderInterval()\n        {\n            var grainGuid = Guid.NewGuid();\n            const string reminderName = \"minimal_reminder\";\n\n            var reminderGrain = this.fixture.GrainFactory.GetGrain<IReminderTestGrain2>(grainGuid);\n            _ = await reminderGrain.StartReminder(reminderName, TimeSpan.FromMilliseconds(100), true);\n\n            var r = await reminderGrain.GetReminderObject(reminderName);\n            await reminderGrain.StopReminder(r);\n\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/OneWayDeactivationTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Configuration.Internal;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.General\n{\n    [TestCategory(\"BVT\"), TestCategory(\"OneWay\")]\n    public class OneWayDeactivationTests : OrleansTestingBase, IClassFixture<OneWayDeactivationTests.Fixture>\n    {\n        private readonly Fixture _fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 3;\n                builder.AddSiloBuilderConfigurator<SiloConfiguration>();\n            }\n        }\n\n        public class SiloConfiguration : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder siloBuilder) => siloBuilder.ConfigureServices(services =>\n                {\n                    services.Configure<GrainDirectoryOptions>(options =>\n                    {\n                        options.CachingStrategy = GrainDirectoryOptions.CachingStrategyType.Custom;\n                    });\n\n                    services.AddSingleton<TestDirectoryCache>();\n                    services.AddFromExisting<IGrainDirectoryCache, TestDirectoryCache>();\n                });\n        }\n\n        public OneWayDeactivationTests(Fixture fixture)\n        {\n            _fixture = fixture;\n        }\n\n        /// <summary>\n        /// Tests that calling [OneWay] methods on an activation which no longer exists triggers a cache invalidation.\n        /// Subsequent calls should reactivate the grain.\n        /// </summary>\n        [Fact]\n        public async Task OneWay_Deactivation_CacheInvalidated()\n        {\n            var directoryCache = ((InProcessSiloHandle)_fixture.HostedCluster.Primary).SiloHost.Services.GetRequiredService<TestDirectoryCache>();\n            IOneWayGrain grainToCallFrom;\n            while (true)\n            {\n                RequestContext.Set(IPlacementDirector.PlacementHintKey, _fixture.HostedCluster.Primary.SiloAddress);\n                grainToCallFrom = _fixture.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());\n                var grainHost = await grainToCallFrom.GetSiloAddress();\n                if (grainHost.Equals(_fixture.HostedCluster.Primary.SiloAddress))\n                {\n                    break;\n                }\n            }\n\n            // Activate the grain & record its address.\n            RequestContext.Remove(IPlacementDirector.PlacementHintKey);\n            var grainToDeactivate = await grainToCallFrom.GetOtherGrain();\n            var initialActivationId = await grainToDeactivate.GetActivationId();\n            var grainId = grainToDeactivate.GetGrainId();\n            var activationAddress = directoryCache.Operations\n                .OfType<TestDirectoryCache.CacheOperation.AddOrUpdate>()\n                .Last(op => op.Value.GrainId.Equals(grainId))\n                .Value;\n            await grainToDeactivate.Deactivate();\n            await grainToCallFrom.SignalSelfViaOther();\n            var (count, finalActivationId) = await grainToCallFrom.WaitForSignal();\n            Assert.Equal(1, count);\n            Assert.NotEqual(initialActivationId, finalActivationId);\n\n            // Test that cache was updated.\n            // We don't know what the whole activation address should be, but we do know\n            // that some entry should be successfully updated for the provided grain id.\n            var newActivationAddress = directoryCache.Operations\n                .OfType<TestDirectoryCache.CacheOperation.AddOrUpdate>()\n                .Last(op => op.Value.GrainId.Equals(grainId))\n                .Value;\n            Assert.NotNull(newActivationAddress);\n\n            directoryCache.Operations.Clear();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Orleans.Runtime.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OutputType>Exe</OutputType>\n    <GenerateProgramFile>false</GenerateProgramFile>\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Microsoft.Extensions.Diagnostics.Testing\" />\n    <PackageReference Include=\"Azure.Identity\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Clustering.AzureStorage\\Orleans.Clustering.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.GrainDirectory.AzureStorage\\Orleans.GrainDirectory.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestInternalGrains\\TestInternalGrains.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestVersionGrains\\TestVersionGrains.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Grains\\TestFSharp\\TestFSharp.fsproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Reminders\\Orleans.Reminders.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Sdk\\Orleans.Sdk.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.SystemTextJson\\Orleans.Serialization.SystemTextJson.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.BroadcastChannel\\Orleans.BroadcastChannel.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Placement/CustomPlacementTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Placement;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Orleans.Configuration;\n\nnamespace Tester.CustomPlacementTests\n{\n    /// <summary>\n    /// Tests custom grain placement strategies including fixed silo placement, exclusion-based placement, and hash-based placement.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Placement\")]\n    public class CustomPlacementTests : OrleansTestingBase, IClassFixture<CustomPlacementTests.Fixture>\n    {\n        private const short nSilos = 3;\n        private readonly Fixture fixture;\n        private readonly string[] silos;\n        private readonly SiloAddress[] siloAddresses;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = nSilos;\n                builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n            }\n\n            private class TestSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.Configure<SiloMessagingOptions>(options => options.AssumeHomogenousSilosForTesting = true);\n                    hostBuilder.ConfigureServices(ConfigureServices);\n                }\n            }\n\n            private static void ConfigureServices(IServiceCollection services)\n            {\n                services.AddPlacementDirector<TestCustomPlacementStrategy, TestPlacementStrategyFixedSiloDirector>();\n            }\n        }\n\n        public CustomPlacementTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n\n            // sort silo IDs into an array\n            this.silos = fixture.HostedCluster.GetActiveSilos().OrderBy(s => s.SiloAddress).Select(h => h.SiloAddress.ToString()).ToArray();\n            this.siloAddresses = fixture.HostedCluster.GetActiveSilos().Select(h => h.SiloAddress).OrderBy(s => s).ToArray();\n        }\n\n        [Fact]\n        public async Task CustomPlacement_FixedSilo()\n        {\n            const int nGrains = 100;\n\n            Task<string>[] tasks = new Task<string>[nGrains];\n            for (int i = 0; i < nGrains; i++)\n            {\n                var g = this.fixture.GrainFactory.GetGrain<ICustomPlacementTestGrain>(Guid.NewGuid(),\n                    \"UnitTests.Grains.CustomPlacement_FixedSiloGrain\");\n                tasks[i] = g.GetRuntimeInstanceId();\n            }\n\n            await Task.WhenAll(tasks);\n\n            var silo = await tasks[0];\n            Assert.Equal(silos[silos.Length-2], silo);\n\n            for (int i = 1; i < nGrains; i++)\n            {\n                Assert.Equal(silo, await tasks[i]);\n            }\n        }\n\n        [Fact]\n        public async Task CustomPlacement_ExcludeOne()\n        {\n            const int nGrains = 100;\n\n            Task<string>[] tasks = new Task<string>[nGrains];\n            for (int i = 0; i < nGrains; i++)\n            {\n                var g = this.fixture.GrainFactory.GetGrain<ICustomPlacementTestGrain>(Guid.NewGuid(),\n                    \"UnitTests.Grains.CustomPlacement_ExcludeOneGrain\");\n                tasks[i] = g.GetRuntimeInstanceId();\n            }\n\n            await Task.WhenAll(tasks);\n            var excludedSilo = silos[1];\n\n            for (int i = 1; i < nGrains; i++)\n            {\n                Assert.NotEqual(excludedSilo, await tasks[i]);\n            }\n        }\n\n        [Fact]\n        public async Task CustomPlacement_RequestContextBased()\n        {\n            const int nGrains = 100;\n            var targetSilo = silos.Length - 1; // Always target the last one\n\n            Task<string>[] tasks = new Task<string>[nGrains];\n            for (int i = 0; i < nGrains; i++)\n            {\n                RequestContext.Set(TestPlacementStrategyFixedSiloDirector.TARGET_SILO_INDEX, targetSilo);\n                var g = this.fixture.GrainFactory.GetGrain<ICustomPlacementTestGrain>(Guid.NewGuid(),\n                    \"UnitTests.Grains.CustomPlacement_RequestContextBased\");\n                tasks[i] = g.GetRuntimeInstanceId();\n                RequestContext.Clear();\n            }\n\n            await Task.WhenAll(tasks);\n\n            for (int i = 1; i < nGrains; i++)\n            {\n                Assert.Equal(silos[targetSilo], await tasks[i]);\n            }\n        }\n\n        [Fact]\n        public async Task HashBasedPlacement()\n        {\n            const int nGrains = 100;\n\n            Task<SiloAddress>[] tasks = new Task<SiloAddress>[nGrains];\n            List<GrainId> grains = new List<GrainId>();\n            for (int i = 0; i < nGrains; i++)\n            {\n                var g = this.fixture.GrainFactory.GetGrain<IHashBasedPlacementGrain>(Guid.NewGuid(),\n                    \"UnitTests.Grains.HashBasedBasedPlacementGrain\");\n                grains.Add(g.GetGrainId());\n                tasks[i] = g.GetSiloAddress();\n            }\n\n            await Task.WhenAll(tasks);\n\n            for (int i = 0; i < nGrains; i++)\n            {\n                var hash = (int) (grains[i].GetUniformHashCode() & 0x7fffffff);\n                Assert.Equal(siloAddresses[hash % silos.Length], await tasks[i]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Program.cs",
    "content": "using Orleans.TestingHost;\n\nnamespace Tester\n{\n    public static class Program \n    {\n        public static async Task Main(string[] args) => await StandaloneSiloHost.Main(args);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Properties/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/Properties/IsExternalInit.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/ReadMe.md",
    "content": "# Tester Project\n\nThis project is for **black-box** testing of the Orleans runtime.\n\nThis project only has access to the public API surface of the Orleans runtime, so all test code executes as normal user-level code.\n\nThis project may contains a mixture of unit and system tests, including starting test silos.\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StartupTaskTests.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\n\nusing TestExtensions;\n\nusing UnitTests.GrainInterfaces;\n\nusing Xunit;\n\nnamespace DefaultCluster.Tests\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Lifecycle\")]\n    public class StartupTaskTests : IClassFixture<StartupTaskTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n                builder.AddSiloBuilderConfigurator<StartupTaskSiloConfigurator>();\n            }\n\n            private class StartupTaskSiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddStartupTask<CallGrainStartupTask>();\n                    hostBuilder.AddStartupTask(\n                        async (services, cancellation) =>\n                        {\n                            var grainFactory = services.GetRequiredService<IGrainFactory>();\n                            var grain = grainFactory.GetGrain<ISimpleGrain>(1);\n                            await grain.SetA(888);\n                        });\n                }\n            }\n        }\n\n        public class CallGrainStartupTask : IStartupTask\n        {\n            private readonly IGrainFactory grainFactory;\n\n            public CallGrainStartupTask(IGrainFactory grainFactory)\n            {\n                this.grainFactory = grainFactory;\n            }\n\n            public async Task Execute(CancellationToken cancellationToken)\n            {\n                var grain = this.grainFactory.GetGrain<ISimpleGrain>(2);\n                await grain.SetA(777);\n            }\n        }\n\n        private readonly Fixture fixture;\n\n        public StartupTaskTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        /// <summary>\n        /// Ensures that startup tasks can call grains.\n        /// </summary>\n        [Fact]\n        public async Task StartupTaskCanCallGrains()\n        {\n            var grain = this.fixture.GrainFactory.GetGrain<ISimpleGrain>(1);\n            var value = await grain.GetA();\n            Assert.Equal(888, value);\n\n            grain = this.fixture.GrainFactory.GetGrain<ISimpleGrain>(2);\n            value = await grain.GetA();\n            Assert.Equal(777, value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StatelessWorkerActivationTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.General;\n\n/// <summary>\n/// Tests for stateless worker grain activation and scaling behavior.\n/// \n/// Stateless worker grains are a special type of grain marked with [StatelessWorker] attribute that:\n/// - Can have multiple activations on the same silo (up to MaxLocalWorkers limit)\n/// - Are automatically scaled based on load\n/// - Don't maintain state between calls\n/// - Are ideal for CPU-intensive or I/O-bound operations that can be parallelized\n/// \n/// These tests verify:\n/// - Single activation behavior when load is low\n/// - Automatic scaling up to MaxLocalWorkers under concurrent load\n/// - Proper cleanup when activations are deactivated\n/// </summary>\npublic class StatelessWorkerActivationTests : IClassFixture<StatelessWorkerActivationTests.Fixture>\n{\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 1;\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n        }\n\n        private class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                // Shared state service used by test grains to track activation counts\n                hostBuilder.Services.AddSingleton<StatelessWorkerScalingGrainSharedState>();\n            }\n        }\n    }\n\n    private readonly Fixture _fixture;\n\n    public StatelessWorkerActivationTests(Fixture fixture)\n    {\n        _fixture = fixture;\n    }\n\n    /// <summary>\n    /// Verifies that a stateless worker grain maintains a single activation\n    /// when requests are sequential (no concurrent load).\n    /// This demonstrates that Orleans doesn't unnecessarily create multiple\n    /// activations when they're not needed.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"StatelessWorker\")]\n    public async Task SingleWorkerInvocationUnderLoad()\n    {\n        var workerGrain = _fixture.GrainFactory.GetGrain<IStatelessWorkerScalingGrain>(0);\n        var managementGrain = _fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n        var grainReference = (GrainReference)workerGrain;\n\n        for (var i = 0; i < 100; i++)\n        {\n            await workerGrain.GetActivationCount();\n            await Until(async () => 1 == await managementGrain.GetGrainActivationCount(grainReference), 5_000);\n        }\n    }\n\n    /// <summary>\n    /// Tests automatic scaling of stateless worker activations under concurrent load.\n    /// \n    /// Process:\n    /// 1. Start with single activation\n    /// 2. Create concurrent requests that block (using Wait())\n    /// 3. Orleans detects blocked activations and creates new ones\n    /// 4. Scaling continues up to MaxLocalWorkers (4 in this test)\n    /// \n    /// This demonstrates Orleans' ability to automatically scale stateless\n    /// workers based on actual load, not just request count.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"StatelessWorker\")]\n    public async Task MultipleWorkerInvocationUnderLoad()\n    {\n        const int MaxLocalWorkers = 4;  // Maximum activations per silo\n        var waiters = new List<Task>();  // Track blocking calls\n        var worker = _fixture.GrainFactory.GetGrain<IStatelessWorkerScalingGrain>(1);\n\n        // Initially, only one activation exists\n        var activationCount = await worker.GetActivationCount();\n        Assert.Equal(1, activationCount);\n\n        // First blocking call triggers creation of second activation\n        waiters.Add(worker.Wait());\n        await Until(async () => 2 == await worker.GetActivationCount());\n        activationCount = await worker.GetActivationCount();\n        Assert.Equal(2, activationCount);\n\n        waiters.Add(worker.Wait());\n        await Until(async () => 3 == await worker.GetActivationCount());\n        activationCount = await worker.GetActivationCount();\n        Assert.Equal(3, activationCount);\n\n        waiters.Add(worker.Wait());\n        await Until(async () => 4 == await worker.GetActivationCount());\n        activationCount = await worker.GetActivationCount();\n        Assert.Equal(4, activationCount);\n\n        var waitingCount = await worker.GetWaitingCount();\n        Assert.Equal(3, waitingCount);\n\n        for (var i = 0; i < MaxLocalWorkers; i++)\n        {\n            waiters.Add(worker.Wait());\n        }\n\n        await Until(async () => MaxLocalWorkers == await worker.GetActivationCount());\n        await Until(async () => MaxLocalWorkers == await worker.GetWaitingCount());\n        activationCount = await worker.GetActivationCount();\n        Assert.Equal(MaxLocalWorkers, activationCount);\n        waitingCount = await worker.GetWaitingCount();\n        Assert.Equal(MaxLocalWorkers, waitingCount);\n\n        // Release all the waiting workers to clean up\n        for (var i = 0; i < waiters.Count; i++)\n        {\n            await worker.Release();\n        }\n\n        // Ensure all blocking calls complete properly\n        await Task.WhenAll(waiters);\n    }\n\n    /// <summary>\n    /// Tests that stateless worker activations are properly cleaned up from the catalog\n    /// when deactivated. This is important for:\n    /// - Preventing memory leaks\n    /// - Ensuring accurate activation counts\n    /// - Verifying the grain directory properly tracks stateless workers\n    /// \n    /// Uses management grain to force activation collection and verify cleanup.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"StatelessWorker\")]\n    public async Task CatalogCleanupOnDeactivation()\n    {\n        var workerGrain = _fixture.GrainFactory.GetGrain<IStatelessWorkerGrain>(0);\n        var mgmt = _fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n        \n        var numActivations = await mgmt.GetGrainActivationCount((GrainReference)workerGrain);\n        Assert.Equal(0, numActivations);\n        \n        // Activate grain with a dummy call\n        await workerGrain.DummyCall();\n        \n        numActivations = await mgmt.GetGrainActivationCount((GrainReference)workerGrain);\n        Assert.Equal(1, numActivations);\n        \n        // Force immediate activation collection to trigger deactivation\n        // TimeSpan.Zero means collect all idle activations immediately\n        await mgmt.ForceActivationCollection(TimeSpan.Zero);\n        \n        // The activation count for the stateless worker grain should become 0 again\n        await Until(\n            async () => await mgmt.GetGrainActivationCount((GrainReference)workerGrain) == 0,\n            5_000\n        );\n    }\n\n    /// <summary>\n    /// Helper method to wait for an async condition to become true.\n    /// Used to handle eventual consistency in activation creation/destruction.\n    /// </summary>\n    private static async Task Until(Func<Task<bool>> condition, int maxTimeout = 40_000)\n    {\n        while (!await condition() && (maxTimeout -= 10) > 0) await Task.Delay(10);\n        Assert.True(maxTimeout > 0);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Abstractions/ExampleStorageAttribute.cs",
    "content": "﻿namespace Tester.StorageFacet.Abstractions\n{\n    [AttributeUsage(AttributeTargets.Parameter)]\n    public class ExampleStorageAttribute : Attribute, IFacetMetadata, IExampleStorageConfig\n    {\n        public string StorageProviderName { get; }\n\n        public string StateName { get; }\n\n        public ExampleStorageAttribute(string storageProviderName = null, string stateName = null)\n        {\n            this.StorageProviderName = storageProviderName;\n            this.StateName = stateName;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Abstractions/IExampleStorage.cs",
    "content": "﻿namespace Tester.StorageFacet.Abstractions\n{\n    /// <summary>\n    /// Primary storage feature interface.\n    ///  This is the actual functionality the users need.\n    /// </summary>\n    /// <typeparam name=\"TState\"></typeparam>\n    public interface IExampleStorage<TState>\n    {\n        TState State { get; set; }\n\n        Task Save();\n\n        // Test calls - used to verify facet wiring works\n        string Name { get; }\n        string GetExtendedInfo();\n    }\n\n    /// <summary>\n    /// Feature configuration information which application layer can provide to the\n    ///  feature per instance (by grain type if using attributes).\n    /// </summary>\n    public interface IExampleStorageConfig\n    {\n        string StateName { get; }\n    }\n\n    /// <summary>\n    /// Feature configuration utility class\n    /// </summary>\n    public class ExampleStorageConfig : IExampleStorageConfig\n    {\n        public ExampleStorageConfig(string stateName)\n        {\n            this.StateName = stateName;\n        }\n\n        public string StateName { get; }\n    }\n\n    /// <summary>\n    /// Creates a storage feature from a configuration\n    /// </summary>\n    public interface IExampleStorageFactory\n    {\n        IExampleStorage<TState> Create<TState>(IExampleStorageConfig config);\n    }\n\n    /// <summary>\n    /// Creates a storage feature by name from a configuration\n    /// </summary>\n    public interface INamedExampleStorageFactory\n    {\n        IExampleStorage<TState> Create<TState>(string name, IExampleStorageConfig config);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Implementations/BlobExampleStorage.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester.StorageFacet.Implementations\n{\n    public class BlobExampleStorage<TState> : IExampleStorage<TState>\n    {\n        private IExampleStorageConfig config;\n\n        public string Name => this.config.StateName;\n        public TState State { get; set; }\n\n        public Task Save()\n        {\n            return Task.CompletedTask;\n        }\n\n        public string GetExtendedInfo()\n        {\n            return $\"Blob:{this.Name}, StateType:{typeof(TState).Name}\";\n        }\n\n        public void Configure(IExampleStorageConfig cfg)\n        {\n            this.config = cfg;\n        }\n    }\n\n    public class BlobExampleStorageFactory : IExampleStorageFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n        public BlobExampleStorageFactory(IGrainContextAccessor contextAccessor)\n        {\n            this.contextAccessor = contextAccessor;\n        }\n\n        public IExampleStorage<TState> Create<TState>(IExampleStorageConfig config)\n        {\n            var storage = this.contextAccessor.GrainContext.ActivationServices.GetRequiredService<BlobExampleStorage<TState>>();\n            storage.Configure(config);\n            return storage;\n        }\n    }\n\n    public static class BlobExampleStorageExtensions\n    {\n        public static void UseBlobExampleStorage(this ISiloBuilder builder, string name)\n        {\n            builder.ConfigureServices(services =>\n            {\n                services.AddKeyedTransient<IExampleStorageFactory, BlobExampleStorageFactory>(name);\n                services.AddTransient(typeof(BlobExampleStorage<>));\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Implementations/TableExampleStorage.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester.StorageFacet.Implementations\n{\n    public class TableExampleStorage<TState> : IExampleStorage<TState>, ILifecycleParticipant<IGrainLifecycle>\n    {\n        private IExampleStorageConfig config;\n        private bool activateCalled;\n\n        public string Name => this.config.StateName;\n        public TState State { get; set; }\n\n        public Task Save()\n        {\n            return Task.CompletedTask;\n        }\n\n        public string GetExtendedInfo()\n        {\n            return $\"Table:{this.Name}-ActivateCalled:{this.activateCalled}, StateType:{typeof(TState).Name}\";\n        }\n\n        public Task LoadState(CancellationToken ct)\n        {\n            this.activateCalled = true;\n            return Task.CompletedTask;\n        }\n\n        public void Participate(IGrainLifecycle lifecycle)\n        {\n            lifecycle.Subscribe(OptionFormattingUtilities.Name<TableExampleStorage<TState>>(this.Name), GrainLifecycleStage.SetupState, LoadState);\n        }\n\n        public void Configure(IExampleStorageConfig cfg)\n        {\n            this.config = cfg;\n        }\n    }\n\n    public class TableExampleStorageFactory : IExampleStorageFactory\n    {\n        private readonly IGrainContextAccessor contextAccessor;\n        public TableExampleStorageFactory(IGrainContextAccessor context)\n        {\n            this.contextAccessor = context;\n        }\n\n        public IExampleStorage<TState> Create<TState>(IExampleStorageConfig config)\n        {\n            var context = this.contextAccessor.GrainContext;\n            var storage = context.ActivationServices.GetRequiredService<TableExampleStorage<TState>>();\n            storage.Configure(config);\n            storage.Participate(context.ObservableLifecycle);\n            return storage;\n        }\n    }\n\n    public static class TableExampleStorageExtensions\n    {\n        public static void UseTableExampleStorage(this ISiloBuilder builder, string name)\n        {\n            builder.ConfigureServices(services =>\n            {\n                services.AddKeyedTransient<IExampleStorageFactory, TableExampleStorageFactory>(name);\n                services.AddTransient(typeof(TableExampleStorage<>));\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Infrastructure/ExampleStorageAttributeMapper.cs",
    "content": "﻿using System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester.StorageFacet.Infrastructure\n{\n    public class ExampleStorageAttributeMapper : IAttributeToFactoryMapper<ExampleStorageAttribute>\n    {\n        private static readonly MethodInfo create = typeof(INamedExampleStorageFactory).GetMethod(\"Create\");\n\n        public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, ExampleStorageAttribute attribute)\n        {\n            IExampleStorageConfig config = attribute;\n            // set state name to parameter name, if not already specified\n            if (string.IsNullOrEmpty(config.StateName))\n            {\n                config = new ExampleStorageConfig(parameter.Name);\n            }\n            // use generic type args to define collection type.\n            MethodInfo genericCreate = create.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());\n            object[] args = new object[] {attribute.StorageProviderName, config};\n            return context => Create(context, genericCreate, args);\n        }\n\n        private object Create(IGrainContext context, MethodInfo genericCreate, object[] args)\n        {\n            INamedExampleStorageFactory factory = context.ActivationServices.GetRequiredService<INamedExampleStorageFactory>();\n            return genericCreate.Invoke(factory, args);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Infrastructure/ExampleStorageExtensions.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester.StorageFacet.Infrastructure\n{\n    public static class ExampleStorageExtensions\n    {\n        public static void UseExampleStorage(this ISiloBuilder builder)\n        {\n            builder.ConfigureServices(services =>\n            {\n                // storage feature factory infrastructure\n                services.AddTransient<INamedExampleStorageFactory, NamedExampleStorageFactory>();\n\n                // storage feature facet attribute mapper\n                services.AddSingleton(typeof(IAttributeToFactoryMapper<ExampleStorageAttribute>), typeof(ExampleStorageAttributeMapper));\n            });\n        }\n\n        public static void UseAsDefaultExampleStorage<TFactoryType>(this ISiloBuilder builder)\n            where TFactoryType : class, IExampleStorageFactory\n        {\n            builder.ConfigureServices(services =>\n            {\n                services.AddTransient<IExampleStorageFactory, TFactoryType>();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/Feature.Infrastructure/NamedExampleStorageFactory.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester.StorageFacet.Infrastructure\n{\n    public class NamedExampleStorageFactory : INamedExampleStorageFactory\n    {\n        private readonly IServiceProvider services;\n\n        public NamedExampleStorageFactory(IServiceProvider services)\n        {\n            this.services = services;\n        }\n\n        public IExampleStorage<TState> Create<TState>(string name, IExampleStorageConfig cfg)\n        {\n            IExampleStorageFactory factory = string.IsNullOrEmpty(name)\n                ? this.services.GetService<IExampleStorageFactory>()\n                : this.services.GetKeyedService<IExampleStorageFactory>(name);\n            if (factory != null) return factory.Create<TState>(cfg);\n            throw new InvalidOperationException($\"Storage feature with name {name} not found.\");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/StorageFacetGrain.cs",
    "content": "﻿// Note that for a feature exposed to a grain as a facet, only it's abstractions should be necessary.\nusing Tester.StorageFacet.Abstractions;\n\nnamespace Tester\n{\n    public interface IStorageFacetGrain : IGrainWithIntegerKey\n    {\n        Task<string[]> GetNames();\n        Task<string[]> GetExtendedInfo();\n    }\n\n    public class StorageFacetGrain : Grain, IStorageFacetGrain\n    {\n        private readonly IExampleStorage<string> first;\n        private readonly IExampleStorage<string> second;\n\n        public StorageFacetGrain(\n            [ExampleStorage(\"Blob\", \"FirstState\")] IExampleStorage<string> first,\n            [ExampleStorage(\"Table\")] IExampleStorage<string> second)\n        {\n            this.first = first;\n            this.second = second;\n        }\n\n        public Task<string[]> GetNames()\n        {\n            return Task.FromResult(new[] { this.first.Name, this.second.Name });\n        }\n\n        public Task<string[]> GetExtendedInfo()\n        {\n            return Task.FromResult(new[] { this.first.GetExtendedInfo(), this.second.GetExtendedInfo() });\n        }\n    }\n\n    public interface IStorageFactoryGrain : IStorageFacetGrain\n    {\n    }\n    public class StorageFactoryGrain : Grain, IStorageFactoryGrain\n    {\n        private readonly IExampleStorage<string> first;\n        private readonly IExampleStorage<string> second;\n\n        public StorageFactoryGrain(\n            INamedExampleStorageFactory namedExampleStorageFactory)\n        {\n            this.first = namedExampleStorageFactory.Create<string>(\"Blob\", new ExampleStorageConfig(\"FirstState\"));\n            this.second = namedExampleStorageFactory.Create<string>(\"Table\", new ExampleStorageConfig(\"second\"));\n        }\n\n        public Task<string[]> GetNames()\n        {\n            return Task.FromResult(new[] { this.first.Name, this.second.Name });\n        }\n\n        public Task<string[]> GetExtendedInfo()\n        {\n            return Task.FromResult(new[] { this.first.GetExtendedInfo(), this.second.GetExtendedInfo() });\n        }\n    }\n\n    public interface IStorageDefaultFactoryGrain : IStorageFacetGrain\n    {\n    }\n\n    public class StorageDefaultFactoryGrain : Grain, IStorageDefaultFactoryGrain\n    {\n        private readonly IExampleStorage<string> first;\n        private readonly IExampleStorage<string> second;\n\n        public StorageDefaultFactoryGrain(\n            IExampleStorageFactory ExampleStorageFactory)\n        {\n            this.first = ExampleStorageFactory.Create<string>(new ExampleStorageConfig(\"FirstState\"));\n            this.second = ExampleStorageFactory.Create<string>(new ExampleStorageConfig(\"second\"));\n        }\n\n        public Task<string[]> GetNames()\n        {\n            return Task.FromResult(new[] { this.first.Name, this.second.Name });\n        }\n\n        public Task<string[]> GetExtendedInfo()\n        {\n            return Task.FromResult(new[] { this.first.GetExtendedInfo(), this.second.GetExtendedInfo() });\n        }\n    }\n\n    public interface IStorageDefaultFacetGrain : IStorageFacetGrain\n    {\n    }\n\n    public class StorageDefaultFacetGrain : Grain, IStorageDefaultFacetGrain\n    {\n        private readonly IExampleStorage<string> first;\n        private readonly IExampleStorage<string> second;\n\n        public StorageDefaultFacetGrain(\n            [ExampleStorage(stateName: \"FirstState\")] IExampleStorage<string> first,\n            [ExampleStorage] IExampleStorage<string> second)\n        {\n            this.first = first;\n            this.second = second;\n        }\n\n        public Task<string[]> GetNames()\n        {\n            return Task.FromResult(new[] { this.first.Name, this.second.Name });\n        }\n\n        public Task<string[]> GetExtendedInfo()\n        {\n            return Task.FromResult(new[] { this.first.GetExtendedInfo(), this.second.GetExtendedInfo() });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/StorageFacet/StorageFacetTests.cs",
    "content": "using TestExtensions;\nusing Xunit;\nusing Orleans.TestingHost;\nusing Tester.StorageFacet.Infrastructure;\nusing Tester.StorageFacet.Implementations;\n\nnamespace Tester\n{\n    /// <summary>\n    /// Tests storage facet infrastructure with multiple storage implementations (Blob and Table) demonstrating extensible storage patterns.\n    /// </summary>\n    public class StorageFacetTests : IClassFixture<StorageFacetTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestSiloBuilderConfigurator>();\n            }\n\n            private class TestSiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    // Setup storage feature infrastructure.\n                    // - Setup infrastructure.\n                    // - Set default feature implementation - optional\n\n                    // Setup infrastructure\n                    hostBuilder.UseExampleStorage();\n                    // Default storage feature factory - optional\n                    hostBuilder.UseAsDefaultExampleStorage<TableExampleStorageFactory>();\n\n                    // Service will need to add types they want to use to collection\n                    // - Call extension functions from each implementation assembly to register it's classes.\n\n                    // Blob - from blob extension assembly\n                    hostBuilder.UseBlobExampleStorage(\"Blob\");\n                    // Table - from table extension assembly\n                    hostBuilder.UseTableExampleStorage(\"Table\");\n                    // Blarg - from blarg extension assembly\n                    //builder.UseBlargExampleStorage(\"Blarg\");\n                }\n            }\n        }\n\n        public StorageFacetTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Facet\")]\n        public Task ExampleStorageFacetHappyPath()\n        {\n            return ExampleStorageHappyPath<IStorageFacetGrain>();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Facet\")]\n        public Task ExampleStorageFactoryHappyPath()\n        {\n            return ExampleStorageHappyPath<IStorageFactoryGrain>();\n        }\n\n        private async Task ExampleStorageHappyPath<TGrainInterface>()\n            where TGrainInterface : IStorageFacetGrain\n        {\n            IStorageFacetGrain grain = this.fixture.GrainFactory.GetGrain<TGrainInterface>(0);\n            string[] names = await grain.GetNames();\n            string[] info = await grain.GetExtendedInfo();\n            Assert.Equal(2, names.Length);\n            Assert.Equal(\"FirstState\", names[0]);\n            Assert.Equal(\"second\", names[1]);\n            Assert.Equal(2, info.Length);\n            Assert.Equal(\"Blob:FirstState, StateType:String\", info[0]);\n            Assert.Equal(\"Table:second-ActivateCalled:True, StateType:String\", info[1]);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Facet\")]\n        public Task ExampleStorageFacetDefaultPath()\n        {\n            return ExampleStorageDefaultPath<IStorageDefaultFacetGrain>();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Facet\")]\n        public Task ExampleStorageFactoryDefaultPath()\n        {\n            return ExampleStorageDefaultPath<IStorageDefaultFactoryGrain>();\n        }\n\n        private async Task ExampleStorageDefaultPath<TGrainInterface>()\n            where TGrainInterface : IStorageFacetGrain\n        {\n            IStorageFacetGrain grain = this.fixture.GrainFactory.GetGrain<TGrainInterface>(0);\n            string[] names = await grain.GetNames();\n            string[] info = await grain.GetExtendedInfo();\n            Assert.Equal(2, names.Length);\n            Assert.Equal(\"FirstState\", names[0]);\n            Assert.Equal(\"second\", names[1]);\n            Assert.Equal(2, info.Length);\n            Assert.Equal(\"Table:FirstState-ActivateCalled:True, StateType:String\", info[0]);\n            Assert.Equal(\"Table:second-ActivateCalled:True, StateType:String\", info[1]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Runtime.Tests/TestDirectoryCache.cs",
    "content": "using System.Collections.Concurrent;\nusing Orleans.Configuration;\nusing Orleans.Runtime;\nusing Orleans.Runtime.GrainDirectory;\n\nnamespace UnitTests.General\n{\n    public class TestDirectoryCache : IGrainDirectoryCache\n    {\n        public TestDirectoryCache(IServiceProvider serviceProvider)\n        {\n            var options = new GrainDirectoryOptions();\n            InnerCache = GrainDirectoryCacheFactory.CreateGrainDirectoryCache(serviceProvider, options);\n        }\n\n        public IGrainDirectoryCache InnerCache { get; }\n\n        public ConcurrentQueue<CacheOperation> Operations { get; } = new();\n\n        public IEnumerable<(GrainAddress ActivationAddress, int Version)> KeyValues => InnerCache.KeyValues;\n\n        public void AddOrUpdate(GrainAddress value, int version)\n        {\n            InnerCache.AddOrUpdate(value, version);\n            Operations.Enqueue(new CacheOperation.AddOrUpdate(value, version));\n        }\n\n        public void Clear()\n        {\n            InnerCache.Clear();\n            Operations.Enqueue(new CacheOperation.Clear());\n        }\n\n        public bool LookUp(GrainId key, out GrainAddress result, out int version)\n        {\n            var exists = InnerCache.LookUp(key, out result, out version);\n            Operations.Enqueue(new CacheOperation.Lookup(key, (exists, result, version)));\n            return exists;\n        }\n\n        public bool Remove(GrainId key)\n        {\n            var exists = InnerCache.Remove(key);\n            Operations.Enqueue(new CacheOperation.Remove(key, exists));\n            return exists;\n        }\n\n        /// <summary>\n        /// Removes an entry from the cache given its key\n        /// </summary>\n        /// <param name=\"key\">key to remove</param>\n        /// <returns>True if the entry was in the cache and the removal was successful</returns>\n        public bool Remove(GrainAddress key)\n        {\n            var exists = InnerCache.Remove(key);\n            Operations.Enqueue(new CacheOperation.RemoveActivation(key, exists));\n            return exists;\n        }\n\n        public record CacheOperation()\n        {\n            public record RemoveActivation(GrainAddress Key, bool Result) : CacheOperation;\n            public record Remove(GrainId Key, bool Result) : CacheOperation;\n            public record Lookup(GrainId Key, (bool Exists, GrainAddress Address, int Version) Result) : CacheOperation;\n            public record AddOrUpdate(GrainAddress Value, int Version) : CacheOperation;\n            public record Clear() : CacheOperation;\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/TransportTests/TransportTestsBase.cs",
    "content": "using TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester.TransportTests;\n\npublic abstract class TransportTestsBase\n{\n    private readonly BaseTestClusterFixture _fixture;\n\n    protected TransportTestsBase(BaseTestClusterFixture fixture)\n    {\n        _fixture = fixture;\n        Assert.True(fixture.HostedCluster.Silos.Count >= 2);\n    }\n\n    [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Transport\")]\n    public async Task SimplePing()\n    {\n        var grain = _fixture.Client.GetGrain<IGenericPingSelf<int>>(Guid.NewGuid());\n        var value = await grain.Ping(10);\n        Assert.Equal(10, value);\n    }\n\n    [SkippableFact, TestCategory(\"BVT\"), TestCategory(\"Transport\")]\n    public async Task ProxyPing()\n    {\n        var grain1 = _fixture.Client.GetGrain<IGenericPingSelf<int>>(Guid.NewGuid());\n        for (var i = 0; i < 10; i++)\n        {\n            var grain2 = _fixture.Client.GetGrain<IGenericPingSelf<int>>(Guid.NewGuid());\n            var value = await grain1.PingOther(grain2, i);\n            Assert.Equal(i, value);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Runtime.Tests/TransportTests/UnixSocketTransportTests.cs",
    "content": "using System.Net.Sockets;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace Tester.TransportTests;\n\n/// <summary>\n/// Tests for Orleans cluster communication using Unix domain socket transport.\n/// </summary>\npublic class UnixSocketTransportTests : TransportTestsBase, IClassFixture<UnixSocketTransportTests.Fixture>\n{\n    public UnixSocketTransportTests(Fixture fixture) : base(fixture)\n    {\n    }\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow()\n        {\n            try\n            {\n                var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);\n            }\n            catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)\n            {\n                throw new SkipException(\"Unix socket not supported\", ex);\n            }\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.ConnectionTransport = ConnectionTransportType.UnixSocket;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <LangVersion>latest</LangVersion>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\"/>\n    <PackageReference Include=\"FSharp.Core\"/>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src/Orleans.Serialization.FSharp/Orleans.Serialization.FSharp.csproj\"/>\n    <ProjectReference Include=\"$(SourceRoot)test/TestInfrastructure/TestExtensions/TestExtensions.csproj\"/>\n    <ProjectReference Include=\"$(SourceRoot)test/Grains/TestFSharp/TestFSharp.fsproj\"/>\n    <ProjectReference Include=\"$(SourceRoot)test/Grains/TestFSharpGrainInterfaces/TestFSharpGrainInterfaces.csproj\"/>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Include=\"SerializationTests.fs\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "test/Orleans.Serialization.FSharp.Tests/SerializationTests.fs",
    "content": "﻿namespace TestFSharpSerialization\n\nopen TestExtensions\nopen UnitTests.FSharpTypes\nopen Xunit\n\n[<CollectionDefinition(\"DefaultCluster\")>]\ntype DefaultClusterTestCollection() = interface ICollectionFixture<DefaultClusterFixture>;\n\n/// <summary>\n/// Tests for Orleans' F# language support in serialization.\n/// \n/// Orleans provides first-class support for F# types including:\n/// - Discriminated unions (both enum-style and data-carrying)\n/// - F# records with structural equality\n/// - Recursive discriminated unions\n/// - Generic discriminated unions\n/// - Option types and other F# core types\n/// - Unit type\n/// \n/// The F# serialization support ensures:\n/// - Proper handling of F# type system features\n/// - Preservation of structural equality semantics\n/// - Efficient encoding of discriminated union cases\n/// - Support for F# collections (lists, sets, maps)\n/// \n/// This enables F# developers to use Orleans with idiomatic F# code,\n/// leveraging functional programming patterns while maintaining\n/// full compatibility with Orleans' distributed computing model.\n/// </summary>\ntype FSharpSerializationTests(fixture: DefaultClusterFixture) =\n    inherit HostedTestClusterEnsureDefaultStarted(fixture)\n\n    let cluster = fixture.HostedCluster\n\n    /// <summary>\n    /// Tests serialization of F# unit type, which represents \"no value\" and is commonly\n    /// used in F# for side-effect-only operations.\n    /// </summary>\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_Unit () =\n        let roundtripped = cluster.RoundTripSerializationForTesting ()\n        let copy = cluster.DeepCopy ()\n        Assert.Equal((), roundtripped)\n        Assert.Equal((), copy)\n\n    /// <summary>\n    /// Tests enum-style discriminated unions (DUs without data), which are similar\n    /// to C# enums but with F# type safety and pattern matching support.\n    /// </summary>\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_EnumStyleDU () =\n        let case1 = EnumStyleDU.Case1\n        let case2 = EnumStyleDU.Case2\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_MixCaseDU () =\n        let case1 = MixCaseDU.Case1\n        let case2 = MixCaseDU.Case2 \"Case2\"\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    /// <summary>\n    /// Tests recursive discriminated unions, which can contain references to themselves,\n    /// commonly used for tree structures and recursive data types in F#.\n    /// </summary>\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_RecursiveDU () =\n        let case1 = RecursiveDU.Case1\n        let case2 = RecursiveDU.Case2 (RecursiveDU.Case2 RecursiveDU.Case1)\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_GenericDU () =\n        let case1String = GenericDU.Case1 \"string\"\n        let case1Int = GenericDU.Case1 99\n        let case1Case2 = GenericDU.Case1 GenericDU.Case2\n        let case2 = GenericDU.Case2\n\n        let roundtrippedCase1String = cluster.RoundTripSerializationForTesting case1String\n        let roundtrippedCase1Int = cluster.RoundTripSerializationForTesting case1Int\n        let roundtrippedCase1Case2 = cluster.RoundTripSerializationForTesting case1Case2\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1String = cluster.DeepCopy case1String\n        let copyCase1Int = cluster.DeepCopy case1Int\n        let copyCase1Case2 = cluster.DeepCopy case1Case2\n        let copyCase2 = cluster.DeepCopy case2\n        Assert.Equal(case1String, roundtrippedCase1String)\n        Assert.Equal(case1Int, roundtrippedCase1Int)\n        Assert.Equal(case1Case2, roundtrippedCase1Case2)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1String, copyCase1String)\n        Assert.Equal(case1Int, copyCase1Int)\n        Assert.Equal(case1Case2, copyCase1Case2)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_SingleCaseDiscriminatedUnion () =\n        let du = SingleCaseDU.Case1 1\n        let roundtripped = cluster.RoundTripSerializationForTesting du\n        let copy = cluster.DeepCopy du\n        Assert.Equal(du, roundtripped)\n        Assert.Equal(du, copy)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_NamedFieldsSingleCaseDiscriminatedUnion () =\n        let du = NamedFieldsSingleCaseDU.Case1 \"str\"\n        let roundtripped = cluster.RoundTripSerializationForTesting du\n        let copy = cluster.DeepCopy du\n        Assert.Equal(du, roundtripped)\n        Assert.Equal(du, copy)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_DoubleCaseDiscriminatedUnion () =\n        let case1 = DoubleCaseDU.Case1 \"case 1\"\n        let case2 = DoubleCaseDU.Case2 2\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_NamedFieldsDoubleCaseDiscriminatedUnion () =\n        let case1 = NamedFieldsDoubleCaseDU.Case1 (\"case 1\", 123)\n        let case2 = NamedFieldsDoubleCaseDU.Case2 \"case 2\"\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_TripleCaseDiscriminatedUnion () =\n        let case1 = TripleCaseDU.Case1 \"case 1\"\n        let case2 = TripleCaseDU.Case2 2\n        let case3 = TripleCaseDU.Case3 'a'\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        let copyCase3 = cluster.DeepCopy case3\n\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case3, roundtrippedCase3)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n        Assert.Equal(case3, copyCase3)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_NamedFieldsTripleCaseDiscriminatedUnion () =\n        let case1 = NamedFieldsTripleCaseDU.Case1 \"case 1\"\n        let case2 = NamedFieldsTripleCaseDU.Case2 (\"case 2\", 123uy)\n        let case3 = NamedFieldsTripleCaseDU.Case3 (\"one\", \"two\", 3)\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        let copyCase3 = cluster.DeepCopy case3\n\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case3, roundtrippedCase3)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n        Assert.Equal(case3, copyCase3)\n\n    [<Fact>]\n    [<TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_QuadrupleCaseDiscriminatedUnion () =\n        let case1 = QuadrupleCaseDU.Case1 \"case 1\"\n        let case2 = QuadrupleCaseDU.Case2 2\n        let case3 = QuadrupleCaseDU.Case3 'a'\n        let case4 = QuadrupleCaseDU.Case4 1uy\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3\n        let roundtrippedCase4 = cluster.RoundTripSerializationForTesting case4\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        let copyCase3 = cluster.DeepCopy case3\n        let copyCase4 = cluster.DeepCopy case4\n\n        Assert.Equal(case1, roundtrippedCase1);\n        Assert.Equal(case2, roundtrippedCase2);\n        Assert.Equal(case3, roundtrippedCase3);\n        Assert.Equal(case4, roundtrippedCase4);\n        Assert.Equal(case1, copyCase1);\n        Assert.Equal(case2, copyCase2);\n        Assert.Equal(case3, copyCase3);\n        Assert.Equal(case4, copyCase4)\n\n    [<Fact>]\n    [<TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_QuintupleCaseDiscriminatedUnion () =\n        let case1 = QuintupleCaseDU.Case1\n        let case2 = QuintupleCaseDU.Case2 (2, \"some string\")\n        let case3 = QuintupleCaseDU.Case3\n        let case4 = QuintupleCaseDU.Case4 (1uy, 2L)\n        let case5 = QuintupleCaseDU.Case5 \"case 5\"\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3\n        let roundtrippedCase4 = cluster.RoundTripSerializationForTesting case4\n        let roundtrippedCase5 = cluster.RoundTripSerializationForTesting case5\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        let copyCase3 = cluster.DeepCopy case3\n        let copyCase4 = cluster.DeepCopy case4\n        let copyCase5 = cluster.DeepCopy case5\n\n        Assert.Equal(case1, roundtrippedCase1);\n        Assert.Equal(case2, roundtrippedCase2);\n        Assert.Equal(case3, roundtrippedCase3);\n        Assert.Equal(case4, roundtrippedCase4);\n        Assert.Equal(case5, roundtrippedCase5);\n        Assert.Equal(case1, copyCase1);\n        Assert.Equal(case2, copyCase2);\n        Assert.Equal(case3, copyCase3);\n        Assert.Equal(case4, copyCase4)\n        Assert.Equal(case5, copyCase5)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_PrivateConstructorDiscriminatedUnion () =\n        let du = PrivateConstructorDU.SomeValue\n        let roundtripped = cluster.RoundTripSerializationForTesting du\n        let copy = cluster.DeepCopy du\n        Assert.Equal(du, roundtripped)\n        Assert.Equal(du, copy)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_PrivateConstructorDoubleCaseDiscriminatedUnion () =\n        let case1 = PrivateConstructorDoubleCaseDU.One\n        let case2 = PrivateConstructorDoubleCaseDU.Two\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n\n        Assert.Equal(case1, roundtrippedCase1)\n        Assert.Equal(case2, roundtrippedCase2)\n        Assert.Equal(case1, copyCase1)\n        Assert.Equal(case2, copyCase2)\n\n    [<Fact>]\n    [<TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_Mutually_Recursive_DU () =\n        let mutually_case1 = DUMutually.Case1 1\n        let mutually_case2_case1 = DUMutually.Case2 (DURecursive.Case1 (DUMutually.Case1 2))\n        let mutually_case2_case2 =\n            DUMutually.Case2 (DURecursive.Case2 (DURecursive.Case1 (DUMutually.Case1 3), DUMutually.Case2 (DURecursive.Case1 (DUMutually.Case1 1337))))\n\n        let roundtripped_mutually_case1 = cluster.RoundTripSerializationForTesting mutually_case1\n        let roundtripped_mutually_case2_case1 = cluster.RoundTripSerializationForTesting mutually_case2_case1\n        let roundtripped_mutually_case2_case2 = cluster.RoundTripSerializationForTesting mutually_case2_case2\n        let copy_mutually_case1 = cluster.DeepCopy mutually_case1\n        let copy_mutually_case2_case1 = cluster.DeepCopy mutually_case2_case1\n        let copy_mutually_case2_case2 = cluster.DeepCopy mutually_case2_case2\n\n        Assert.Equal(mutually_case1, roundtripped_mutually_case1)\n        Assert.Equal(mutually_case2_case1, roundtripped_mutually_case2_case1)\n        Assert.Equal(mutually_case2_case2, roundtripped_mutually_case2_case2)\n        Assert.Equal(mutually_case1, copy_mutually_case1)\n        Assert.Equal(mutually_case2_case1, copy_mutually_case2_case1)\n        Assert.Equal(mutually_case2_case2, copy_mutually_case2_case2)\n\n    [<Fact; TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_SingleCaseStructDiscriminatedUnion () =\n        let du = SingleCaseStructDU.Case \"string\"\n        let roundtripped = cluster.RoundTripSerializationForTesting du\n        let copy = cluster.DeepCopy du\n        Assert.Equal(du, roundtripped)\n        Assert.Equal(du, copy)\n\n    [<Fact>]\n    [<TestCategory(\"BVT\"); TestCategory(\"Serialization\")>]\n    let Serialization_Roundtrip_FSharp_MulticaseStructDiscriminatedUnion () =\n        let case1 = MulticaseStructDU.Case1 \"case 1\"\n        let case2 = MulticaseStructDU.Case2 \"case 2\"\n        let case3 = MulticaseStructDU.Case3 123\n        let case4 = MulticaseStructDU.Case4\n        let case5 = MulticaseStructDU.Case5 123L\n\n        let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1\n        let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2\n        let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3\n        let roundtrippedCase4 = cluster.RoundTripSerializationForTesting case4\n        let roundtrippedCase5 = cluster.RoundTripSerializationForTesting case5\n        let copyCase1 = cluster.DeepCopy case1\n        let copyCase2 = cluster.DeepCopy case2\n        let copyCase3 = cluster.DeepCopy case3\n        let copyCase4 = cluster.DeepCopy case4\n        let copyCase5 = cluster.DeepCopy case5\n\n        Assert.Equal(case1, roundtrippedCase1);\n        Assert.Equal(case2, roundtrippedCase2);\n        Assert.Equal(case3, roundtrippedCase3);\n        Assert.Equal(case4, roundtrippedCase4);\n        Assert.Equal(case5, roundtrippedCase5);\n        Assert.Equal(case1, copyCase1);\n        Assert.Equal(case2, copyCase2);\n        Assert.Equal(case3, copyCase3);\n        Assert.Equal(case4, copyCase4)\n        Assert.Equal(case5, copyCase5)\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ArcBufferWriterTests.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Orleans.Serialization.Buffers;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for the ArcBufferWriter class, which provides a high-performance buffer writer implementation\n/// for Orleans' serialization system. ArcBufferWriter is a specialized buffer writer that manages\n/// memory in pages and supports atomic reference counting (ARC) for efficient memory management.\n/// \n/// Orleans' serialization approach emphasizes:\n/// - Zero-copy operations where possible through buffer slicing\n/// - Efficient memory pooling to reduce GC pressure\n/// - Reference counting for safe concurrent access\n/// - Support for streaming scenarios with incremental writes and reads\n/// </summary>\n[Trait(\"Category\", \"BVT\")]\npublic class ArcBufferWriterTests\n{\n    private const int PageSize = ArcBufferWriter.MinimumPageSize;\n#if NET6_0_OR_GREATER\n    private readonly Random _random = Random.Shared;\n#else\n    private readonly Random _random = new Random();\n#endif\n\n    /// <summary>\n    /// Verifies that writing data larger than a single page results in correct multi-page buffer management and correct data retrieval.\n    /// </summary>\n    [Fact]\n    public void MultiPageBuffer_CorrectlyHandlesLargeWritesAndRetrieval()\n    {\n        using var bufferWriter = new ArcBufferWriter();\n        var randomData = new byte[PageSize * 3];\n        _random.NextBytes(randomData);\n        int[] writeSizes = [1, 52, 125, 4096];\n        var i = 0;\n        while (bufferWriter.Length < randomData.Length)\n        {\n            var writeSize = Math.Min(randomData.Length - bufferWriter.Length, writeSizes[i++ % writeSizes.Length]);\n            bufferWriter.Write(randomData);\n        }\n\n        {\n            using var wholeBuffer = bufferWriter.PeekSlice(randomData.Length);\n            Assert.Equal(3, wholeBuffer.Pages.Count());\n            Assert.Equal(3, wholeBuffer.PageSegments.Count());\n            Assert.Equal(3, wholeBuffer.MemorySegments.Count());\n            Assert.Equal(3, wholeBuffer.ArraySegments.Count());\n            Assert.Equal(randomData, wholeBuffer.AsReadOnlySequence().ToArray());\n\n            {\n                using var newWriter = new ArcBufferWriter();\n                newWriter.Write(wholeBuffer.AsReadOnlySequence());\n\n                Span<byte> headerBytes = stackalloc byte[8];\n                var result = newWriter.Peek(in headerBytes);\n                Assert.True(result.Length >= headerBytes.Length);\n                Assert.Equal(randomData[0..headerBytes.Length], result[..headerBytes.Length].ToArray());\n                var copiedData = new byte[newWriter.Length];\n                newWriter.Peek(copiedData);\n                newWriter.AdvanceReader(copiedData.Length);\n                Assert.Equal(0, newWriter.Length);\n                Assert.Equal(randomData, copiedData);\n            }\n\n            var spanCount = 0;\n            foreach (var span in wholeBuffer.SpanSegments)\n            {\n                Assert.Equal(PageSize, span.Length);\n                var spanArray = span.ToArray();\n                Assert.Equal(spanArray, wholeBuffer.ArraySegments.Skip(spanCount).Take(1).Single().ToArray());\n                Assert.Equal(spanArray, wholeBuffer.MemorySegments.Skip(spanCount).Take(1).Single().ToArray());\n                Assert.Equal(spanArray, wholeBuffer.PageSegments.Skip(spanCount).Take(1).Single().Span.ToArray());\n                Assert.Equal(spanArray, wholeBuffer.PageSegments.Skip(spanCount).Take(1).Single().Memory.ToArray());\n                Assert.Equal(spanArray, wholeBuffer.PageSegments.Skip(spanCount).Take(1).Single().ArraySegment.ToArray());\n                Assert.Equal(spanArray, wholeBuffer.AsReadOnlySequence().Slice(spanCount * PageSize, PageSize).ToArray());\n                ++spanCount;\n            }\n\n            Assert.Equal(3, spanCount);\n        }\n\n        Assert.Equal(randomData.Length, bufferWriter.Length);\n\n        {\n            using var peeked = bufferWriter.PeekSlice(3000);\n            using var slice = bufferWriter.ConsumeSlice(3000);\n            var sliceArray = slice.ToArray();\n            Assert.Equal(randomData.AsSpan(0, 3000).ToArray(), sliceArray);\n            Assert.Equal(sliceArray, peeked.ToArray());\n            Assert.Equal(sliceArray, peeked.AsReadOnlySequence().ToArray());\n\n            Assert.Equal(randomData.Length - sliceArray.Length, bufferWriter.Length);\n        }\n\n        {\n            using var peeked = bufferWriter.PeekSlice(3000);\n            using var slice = bufferWriter.ConsumeSlice(3000);\n            var sliceArray = slice.ToArray();\n            Assert.Equal(randomData.AsSpan(3000, 3000).ToArray(), sliceArray);\n            Assert.Equal(sliceArray, peeked.ToArray());\n            Assert.Equal(sliceArray, slice.AsReadOnlySequence().ToArray());\n\n            Assert.Equal(randomData.Length - sliceArray.Length * 2, bufferWriter.Length);\n        }\n\n        Assert.Equal(randomData.Length - 6000, bufferWriter.Length);\n    }\n\n    /// <summary>\n    /// Verifies that page reference counts and versions are managed correctly as slices are consumed and disposed.\n    /// </summary>\n    [Fact]\n    public void PageBufferManagement_TracksReferenceCountsAndVersions()\n    {\n        var bufferWriter = new ArcBufferWriter();\n        var randomData = new byte[PageSize * 12];\n        _random.NextBytes(randomData);\n        bufferWriter.Write(randomData);\n\n        var peeked = bufferWriter.PeekSlice(randomData.Length);\n        var pages = peeked.Pages.ToList();\n        peeked.Dispose();\n\n        var expected = pages.Select((p, i) => (p.Version, p.ReferenceCount)).ToList();\n        CheckPages(pages, expected);\n\n        var slice = bufferWriter.ConsumeSlice(PageSize - 1);\n        slice.Dispose();\n\n        CheckPages(pages, expected);\n\n        slice = bufferWriter.ConsumeSlice(1);\n        CheckPages(pages, expected);\n        slice.Dispose();\n\n        expected[0] = (expected[0].Version + 1, 0);\n        CheckPages(pages, expected);\n\n        slice = bufferWriter.ConsumeSlice(PageSize);\n        CheckPages(pages, expected);\n        slice.Dispose();\n\n        expected[1] = (expected[1].Version + 1, 0);\n        CheckPages(pages, expected);\n\n        slice = bufferWriter.ConsumeSlice(PageSize + 1);\n        expected[3] = (expected[3].Version, expected[3].ReferenceCount + 1);\n        CheckPages(pages, expected);\n        slice.Dispose();\n\n        expected[2] = (expected[2].Version + 1, 0);\n        expected[3] = (expected[3].Version, expected[3].ReferenceCount - 1);\n        CheckPages(pages, expected);\n\n        Assert.Equal(randomData.Length - 1 - PageSize * 3, bufferWriter.Length);\n\n        bufferWriter.Dispose();\n        expected = expected.Take(3).Concat(expected.Skip(3).Select(e => (e.Version + 1, 0))).ToList();\n        CheckPages(pages, expected);\n\n        Assert.Throws<ObjectDisposedException>(() => bufferWriter.Length);\n\n        static void CheckPages(List<ArcBufferPage> pages, List<(int Version, int ReferenceCount)> expectedValues)\n        {\n            var index = 0;\n            foreach (var page in pages)\n            {\n                var expected = expectedValues[index];\n                CheckPage(page, expected.Version, expected.ReferenceCount);\n                ++index;\n            }\n        }\n\n        static void CheckPage(ArcBufferPage page, int expectedVersion, int expectedRefCount)\n        {\n            Assert.Equal(expectedVersion, page.Version);\n            Assert.Equal(expectedRefCount, page.ReferenceCount);\n        }\n    }\n\n    /// <summary>\n    /// Verifies that ReplenishBuffers provides correct buffer segments for socket-like reads and that all pages are eventually freed.\n    /// </summary>\n    [Fact]\n    public void ReplenishBuffers_ProvidesSegmentsAndFreesPages()\n    {\n        var bufferWriter = new ArcBufferWriter();\n        var randomData = new byte[PageSize * 16];\n        _random.NextBytes(randomData);\n        bufferWriter.Write([0]);\n        var pages = new List<ArcBufferPage>();\n        var firstSlice = bufferWriter.ConsumeSlice(1);\n        var firstPage = firstSlice.Pages.First();\n        firstSlice.Dispose();\n\n        var buffers = new List<ArraySegment<byte>>(capacity: 16);\n        var consumed = new List<ArcBuffer>();\n        int[] socketReadSizes = [256, 4096, 76, 12805, 4096, 26, 8094, 12345, 1, 0, 12345];\n        int[] messageReadSizes = [8, 1020, 8, 902, 8, 1203, 8, 8045, 0, 12034, 8, 1101, 8, 4096];\n        var messageReadIndex = 0;\n\n        ReadOnlySpan<byte> socket = randomData;\n        foreach (var readSize in socketReadSizes)\n        {\n            bufferWriter.ReplenishBuffers(buffers);\n\n            // Simulate reading from a socket.\n            Read(ref socket, readSize, buffers);\n            MaintainBufferList(buffers, readSize);\n            bufferWriter.AdvanceWriter(readSize);\n\n            // Add the newly allocated pages to the list for test assertion purposes.\n            using (var peeked = bufferWriter.PeekSlice(bufferWriter.Length))\n            {\n                pages.AddRange(peeked.Pages.Where(p => !pages.Contains(p)));\n            }\n\n            // Simulate consuming the socket data.\n            while (bufferWriter.Length > messageReadSizes[messageReadIndex % messageReadSizes.Length])\n            {\n                consumed.Add(bufferWriter.ConsumeSlice(messageReadSizes[messageReadIndex++ % messageReadSizes.Length]));\n            }\n        }\n\n        consumed.Add(bufferWriter.ConsumeSlice(bufferWriter.Length));\n\n        var totalReadSize = socketReadSizes.Sum();\n        Assert.Equal(totalReadSize, consumed.Sum(c => c.Length));\n        var consumedData = new byte[totalReadSize];\n        var consumerSpan = consumedData.AsSpan();\n        foreach (var buffer in consumed)\n        {\n            buffer.CopyTo(consumerSpan);\n            consumerSpan = consumerSpan[buffer.Length..];\n        }\n\n        Assert.Equal(randomData[..totalReadSize], consumedData);\n        foreach (var buffer in consumed)\n        {\n            buffer.Dispose();\n        }\n\n        bufferWriter.Dispose();\n\n        // Check that all pages were freed.\n        foreach (var page in pages)\n        {\n            Assert.Equal(0, page.ReferenceCount);\n        }\n\n        static void MaintainBufferList(List<ArraySegment<byte>> buffers, int readSize)\n        {\n            while (readSize > 0)\n            {\n                if (buffers[0].Count <= readSize)\n                {\n                    // Consume the buffer completely.\n                    readSize -= buffers[0].Count;\n                    buffers.RemoveAt(0);\n                }\n                else\n                {\n                    // Consume the buffer partially.\n                    buffers[0] = new(buffers[0].Array, buffers[0].Offset + readSize, buffers[0].Count - readSize);\n                    break;\n                }\n            }\n        }\n\n        static void Read(ref ReadOnlySpan<byte> socket, int readSize, List<ArraySegment<byte>> buffers)\n        {\n            var payload = socket[..readSize];\n            socket = socket[readSize..];\n            var bufferIndex = 0;\n            while (!payload.IsEmpty)\n            {\n                var output = buffers[bufferIndex];\n                var amount = Math.Min(output.Count, payload.Length);\n                payload[..amount].CopyTo(output);\n                payload = payload[amount..];\n                ++bufferIndex;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Verifies that writing a buffer of a given size results in the correct reported length.\n    /// </summary>\n    [Fact]\n    public void WriteBuffer_UpdatesLengthCorrectly()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = new byte[1024];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        // Assert\n        Assert.Equal(data.Length, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that peeking at a slice returns the correct data without consuming it.\n    /// </summary>\n    [Fact]\n    public void PeekSlice_ReturnsCorrectDataWithoutConsuming()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = new byte[1024];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        using var peeked = buffer.PeekSlice(512);\n        // Assert\n        Assert.Equal(data.AsSpan(0, 512).ToArray(), peeked.ToArray());\n    }\n\n    /// <summary>\n    /// Verifies that consuming a slice returns the correct data and updates the buffer length.\n    /// </summary>\n    [Fact]\n    public void ConsumeSlice_ReturnsCorrectDataAndUpdatesLength()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = new byte[1024];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        using var slice = buffer.ConsumeSlice(512);\n        using var subSlice = slice.Slice(256, 256);\n        // Assert\n        Assert.Equal(data.AsSpan(0, 512).ToArray(), slice.ToArray());\n        Assert.Equal(data.AsSpan(256, 256).ToArray(), subSlice.ToArray());\n        Assert.Equal(data.Length - slice.Length, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that using a slice after it has been unpinned throws an exception.\n    /// </summary>\n    [Fact]\n    public void UseAfterFree_ThrowsException()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = new byte[1024];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        var slice = buffer.ConsumeSlice(512);\n        slice.Unpin();\n\n        // Assert\n        Assert.Throws<InvalidOperationException>(() => slice.ToArray());\n    }\n\n    /// <summary>\n    /// Verifies that double unpinning a slice throws, and that buffer can be reset and disposed safely.\n    /// </summary>\n    [Fact]\n    public void DoubleFree_ThrowsAndBufferCanBeResetAndDisposed()\n    {\n        var buffer = new ArcBufferWriter();\n        var data = new byte[1024];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        var slice = buffer.ConsumeSlice(512);\n        slice.Unpin();\n\n        // Assert\n        Assert.Throws<InvalidOperationException>(() => slice.Unpin());\n\n        Assert.Equal(512, buffer.Length);\n        buffer.Reset();\n        Assert.Equal(0, buffer.Length);\n\n        buffer.Dispose();\n    }\n\n    /// <summary>\n    /// Verifies that a new buffer is empty.\n    /// </summary>\n    [Fact]\n    public void NewBuffer_IsEmpty()\n    {\n        using var buffer = new ArcBufferWriter();\n        // Assert\n        Assert.Equal(0, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that writing an empty buffer does not change the buffer length.\n    /// </summary>\n    [Fact]\n    public void WriteEmptyBuffer_DoesNotChangeLength()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = Array.Empty<byte>();\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        // Assert\n        Assert.Equal(0, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that peeking at an empty buffer returns empty segments and throws when peeking past end.\n    /// </summary>\n    [Fact]\n    public void PeekEmptyBuffer_ReturnsEmptyAndThrowsOnOverflow()\n    {\n        using var buffer = new ArcBufferWriter();\n        using var peeked = buffer.PeekSlice(0);\n        using var subSlice = peeked.Slice(0, 0);\n        Assert.Empty(peeked.Pages);\n        Assert.Empty(peeked.PageSegments);\n        Assert.Empty(peeked.ArraySegments);\n        Assert.Empty(peeked.MemorySegments);\n\n        Assert.Empty(subSlice.Pages);\n        Assert.Empty(subSlice.PageSegments);\n        Assert.Empty(subSlice.ArraySegments);\n        Assert.Empty(subSlice.MemorySegments);\n\n        // Assert\n        Assert.Equal(0, peeked.Length);\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.PeekSlice(1));\n    }\n\n    /// <summary>\n    /// Verifies that consuming an empty buffer returns empty segments and throws when consuming past end.\n    /// </summary>\n    [Fact]\n    public void ConsumeEmptyBuffer_ReturnsEmptyAndThrowsOnOverflow()\n    {\n        using var buffer = new ArcBufferWriter();\n        using var slice = buffer.ConsumeSlice(0);\n        using var subSlice = slice.Slice(0, 0);\n        Assert.Empty(slice.Pages);\n        Assert.Empty(slice.PageSegments);\n        Assert.Empty(slice.ArraySegments);\n        Assert.Empty(slice.MemorySegments);\n        Assert.Equal(0, slice.AsReadOnlySequence().Length);\n\n        Assert.Empty(subSlice.Pages);\n        Assert.Empty(subSlice.PageSegments);\n        Assert.Empty(subSlice.ArraySegments);\n        Assert.Empty(subSlice.MemorySegments);\n        Assert.Equal(0, subSlice.AsReadOnlySequence().Length);\n\n        // Assert\n        Assert.Equal(0, slice.Length);\n        Assert.Equal(0, buffer.Length);\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.PeekSlice(1));\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.ConsumeSlice(1));\n    }\n\n    /// <summary>\n    /// Verifies that disposing a slice after consuming a full page increments the page version.\n    /// </summary>\n    [Fact]\n    public void DisposeSliceAfterFullPageConsumption_IncrementsPageVersion()\n    {\n        using var bufferWriter = new ArcBufferWriter();\n        var data = new byte[ArcBufferPagePool.MinimumPageSize + 1];\n        _random.NextBytes(data);\n        bufferWriter.Write(data);\n\n        // Consuming the slice will cause the writer to release (unpin) those pages.\n        // Since we write more than one page (MinimumPageSize), we should have at least two pages.\n        // The write head will sit on the second page, leaving the first free to be consumed.\n        var slice = bufferWriter.ConsumeSlice(ArcBufferPagePool.MinimumPageSize);\n        var pages = new List<ArcBufferPage>(slice.Pages);\n\n        var initialVersions = pages.Select(p => p.Version).ToList();\n        slice.Dispose();\n\n        // Assert\n        foreach (var page in pages.Zip(initialVersions))\n        {\n            // Check that the versions have been incremented.\n            Assert.True(page.First.Version > page.Second);\n        }\n    }\n\n    /// <summary>\n    /// Verifies that after writing and then advancing the read head, the page version is incremented as expected.\n    /// </summary>\n    [Fact]\n    public void PageVersionIncrementAfterWriteAndReadHeadAdvance()\n    {\n        using var bufferWriter = new ArcBufferWriter();\n        var data = new byte[ArcBufferPagePool.MinimumPageSize];\n        _random.NextBytes(data);\n        bufferWriter.Write(data);\n\n        // Since we write exactly one page (MinimumPageSize), we should have exactly one page.\n        // The write head will sit on the first page, preventing it from being unpinned.\n        var slice = bufferWriter.ConsumeSlice(ArcBufferPagePool.MinimumPageSize);\n        var pages = new List<ArcBufferPage>(slice.Pages);\n\n        var initialVersions = pages.Select(p => p.Version).ToList();\n        slice.Dispose();\n\n        // Assert\n        foreach (var page in pages.Zip(initialVersions))\n        {\n            // Check that the versions have NOT been incremented.\n            Assert.False(page.First.Version > page.Second);\n        }\n\n        // Write one more byte, moving the write head to the second page.\n        bufferWriter.Write([0]);\n\n        // Advance the read head to trigger unpinning and version increment.\n        bufferWriter.AdvanceReader(1);\n\n        // Assert\n        foreach (var page in pages.Zip(initialVersions))\n        {\n            // Check that the versions have NOT been incremented.\n            Assert.True(page.First.Version > page.Second);\n        }\n    }\n\n    /// <summary>\n    /// Verifies that all operations throw ObjectDisposedException after the buffer is disposed.\n    /// </summary>\n    [Fact]\n    public void DisposedBuffer_ThrowsOnAllOperations()\n    {\n        var buffer = new ArcBufferWriter();\n        buffer.Dispose();\n        Assert.Throws<ObjectDisposedException>(() => buffer.GetMemory(1));\n        Assert.Throws<ObjectDisposedException>(() => buffer.GetSpan(1));\n        Assert.Throws<ObjectDisposedException>(() => buffer.Write(new byte[1]));\n        Assert.Throws<ObjectDisposedException>(() => buffer.PeekSlice(0));\n        Assert.Throws<ObjectDisposedException>(() => buffer.ConsumeSlice(0));\n        Assert.Throws<ObjectDisposedException>(() => buffer.AdvanceWriter(1));\n        Assert.Throws<ObjectDisposedException>(() => buffer.AdvanceReader(0));\n        Assert.Throws<ObjectDisposedException>(() => buffer.Reset());\n        Assert.Throws<ObjectDisposedException>(() => buffer.ReplenishBuffers(new List<ArraySegment<byte>>(1)));\n    }\n\n    /// <summary>\n    /// Verifies that double-disposing an ArcBuffer slice is safe and does not throw.\n    /// </summary>\n    [Fact]\n    public void DoubleDisposeArcBuffer_IsSafe()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var slice = buffer.PeekSlice(10);\n        slice.Dispose();\n        // Should not throw\n        slice.Dispose();\n    }\n\n    /// <summary>\n    /// Verifies that resetting a disposed buffer throws ObjectDisposedException.\n    /// </summary>\n    [Fact]\n    public void ResetAfterDispose_Throws()\n    {\n        var buffer = new ArcBufferWriter();\n        buffer.Dispose();\n        Assert.Throws<ObjectDisposedException>(() => buffer.Reset());\n    }\n\n    /// <summary>\n    /// Verifies that advancing the writer by a negative value throws ArgumentOutOfRangeException.\n    /// </summary>\n    [Fact]\n    public void AdvanceWriterNegative_Throws()\n    {\n        using var buffer = new ArcBufferWriter();\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.AdvanceWriter(-1));\n    }\n\n    /// <summary>\n    /// Verifies that advancing the reader by a negative or too-large value throws ArgumentOutOfRangeException.\n    /// </summary>\n    [Fact]\n    public void AdvanceReaderNegativeOrTooLarge_Throws()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[10]);\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.PeekSlice(11));\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.ConsumeSlice(11));\n    }\n\n    /// <summary>\n    /// Verifies that calling Reset() after writing data spanning several pages returns all pages to the pool and empties the buffer.\n    /// </summary>\n    [Fact]\n    public void ResetReleasesAllPages_EmptiesBuffer()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[ArcBufferPagePool.MinimumPageSize * 3]);\n        buffer.Reset();\n        Assert.Equal(0, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that calling Dispose() multiple times on ArcBufferWriter is safe.\n    /// </summary>\n    [Fact]\n    public void DisposeMultipleTimes_IsSafe()\n    {\n        var buffer = new ArcBufferWriter();\n        buffer.Dispose();\n        buffer.Dispose();\n    }\n\n    /// <summary>\n    /// Verifies that writing or getting memory/span after Dispose() throws ObjectDisposedException.\n    /// </summary>\n    [Fact]\n    public void WriteAfterDispose_Throws()\n    {\n        var buffer = new ArcBufferWriter();\n        buffer.Dispose();\n        Assert.Throws<ObjectDisposedException>(() => buffer.Write(new byte[1]));\n        Assert.Throws<ObjectDisposedException>(() => buffer.GetMemory(1));\n        Assert.Throws<ObjectDisposedException>(() => buffer.GetSpan(1));\n    }\n\n    /// <summary>\n    /// Verifies that pinning and unpinning a page multiple times only returns it to the pool when the reference count reaches zero.\n    /// </summary>\n    [Fact]\n    public void PinUnpinReferenceCounting_WorksCorrectly()\n    {\n        var page = new ArcBufferPage(ArcBufferPagePool.MinimumPageSize);\n        int token = page.Version;\n        page.Pin(token);\n        page.Pin(token);\n        Assert.Equal(2, page.ReferenceCount);\n        page.Unpin(token);\n        Assert.Equal(1, page.ReferenceCount);\n        page.Unpin(token);\n        Assert.Equal(0, page.ReferenceCount);\n    }\n\n    /// <summary>\n    /// Verifies that unpinning a page with an incorrect version token throws InvalidOperationException.\n    /// </summary>\n    [Fact]\n    public void UnpinWithInvalidToken_Throws()\n    {\n        var page = new ArcBufferPage(ArcBufferPagePool.MinimumPageSize);\n        int token = page.Version;\n        page.Pin(token);\n        Assert.Throws<InvalidOperationException>(() => page.Unpin(token + 1));\n    }\n\n    /// <summary>\n    /// Verifies that CheckValidity throws if the reference count is zero or negative.\n    /// </summary>\n    [Fact]\n    public void CheckValidityWithInvalidRefCount_Throws()\n    {\n        var page = new ArcBufferPage(ArcBufferPagePool.MinimumPageSize);\n        int token = page.Version;\n        Assert.Throws<InvalidOperationException>(() => page.CheckValidity(token));\n    }\n\n    /// <summary>\n    /// Verifies that disposing a slice does not affect the original buffer.\n    /// </summary>\n    [Fact]\n    public void SliceDispose_DoesNotAffectOriginalBuffer()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var slice = buffer.PeekSlice(50);\n        slice.Dispose();\n        Assert.Equal(100, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that UnsafeSlice does not increment the reference count.\n    /// </summary>\n    [Fact]\n    public void UnsafeSlice_DoesNotPinPages()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var slice = buffer.PeekSlice(100);\n        var page = slice.First;\n        int before = page.ReferenceCount;\n        var unsafeSlice = slice.UnsafeSlice(10, 10);\n        Assert.Equal(before, unsafeSlice.First.ReferenceCount);\n    }\n\n    /// <summary>\n    /// Verifies that copying to a span that is too small throws.\n    /// </summary>\n    [Fact]\n    public void CopyToWithInsufficientDestination_Throws()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var slice = buffer.PeekSlice(100);\n        var dest = new byte[50];\n        Assert.Throws<ArgumentException>(() => slice.CopyTo(dest.AsSpan()));\n    }\n\n    /// <summary>\n    /// Verifies that consuming more bytes than available throws.\n    /// </summary>\n    [Fact]\n    public void ConsumeMoreThanAvailable_Throws()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[10]);\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.ConsumeSlice(20));\n    }\n\n    /// <summary>\n    /// Verifies that Skip() advances the read head.\n    /// </summary>\n    [Fact]\n    public void SkipAdvancesReadHead_WorksCorrectly()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var reader = new ArcBufferReader(buffer);\n        reader.Skip(50);\n        Assert.Equal(50, reader.Length);\n    }\n\n    /// <summary>\n    /// Verifies that large pages are reused by the pool.\n    /// </summary>\n    [Fact]\n    public void LargePageReuse_Works()\n    {\n        var pool = ArcBufferPagePool.Shared;\n        var page1 = pool.Rent(ArcBufferPagePool.MinimumPageSize * 4);\n        int version1 = page1.Version;\n        page1.Pin(version1); // Pin the page\n        page1.Unpin(version1); // Return to pool\n        var page2 = pool.Rent(ArcBufferPagePool.MinimumPageSize * 4);\n        Assert.True(page2.Version > version1 || page2 != page1);\n    }\n\n    /// <summary>\n    /// Verifies that minimum size pages are reused by the pool.\n    /// </summary>\n    [Fact]\n    public void MinimumPageReuse_Works()\n    {\n        var pool = ArcBufferPagePool.Shared;\n        var page1 = pool.Rent();\n        int version1 = page1.Version;\n        page1.Pin(version1); // Pin the page\n        page1.Unpin(version1); // Return to pool\n        var page2 = pool.Rent();\n        Assert.True(page2.Version > version1 || page2 != page1);\n    }\n\n    /// <summary>\n    /// Verifies boundary values for slicing, peeking, and consuming.\n    /// </summary>\n    [Fact]\n    public void BoundaryValue_SlicePeekConsume()\n    {\n        using var buffer = new ArcBufferWriter();\n        var data = new byte[PageSize * 2];\n        _random.NextBytes(data);\n        buffer.Write(data);\n\n        // Slice at start\n        using (var s = buffer.PeekSlice(0))\n        {\n            Assert.Equal(0, s.Length);\n        }\n        using (var s = buffer.PeekSlice(1))\n        {\n            Assert.Equal(data[0], s.ToArray()[0]);\n        }\n        using (var s = buffer.PeekSlice(data.Length))\n        {\n            Assert.Equal(data, s.ToArray());\n        }\n\n        // Slice at page boundary\n        using (var s = buffer.PeekSlice(PageSize))\n        {\n            Assert.Equal(data.Take(PageSize).ToArray(), s.ToArray());\n        }\n        using (var s = buffer.PeekSlice(PageSize + 1))\n        {\n            Assert.Equal(data.Take(PageSize + 1).ToArray(), s.ToArray());\n        }\n\n        // Consume at boundaries\n        using (var s = buffer.ConsumeSlice(0))\n        {\n            Assert.Equal(0, s.Length);\n        }\n        using (var s = buffer.ConsumeSlice(1))\n        {\n            Assert.Equal(data[0], s.ToArray()[0]);\n        }\n        using (var s = buffer.ConsumeSlice(PageSize - 1))\n        {\n            Assert.Equal(data.Skip(1).Take(PageSize - 1).ToArray(), s.ToArray());\n        }\n        using (var s = buffer.ConsumeSlice(PageSize))\n        {\n            Assert.Equal(data.Skip(PageSize).Take(PageSize).ToArray(), s.ToArray());\n        }\n    }\n\n    /// <summary>\n    /// Verifies that double-free and use-after-free are guarded.\n    /// </summary>\n    [Fact]\n    public void DoubleFree_And_UseAfterFree_Guards()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[100]);\n        var slice = buffer.PeekSlice(50);\n        slice.Dispose();\n        // Double dispose is safe\n        slice.Dispose();\n        // Unpin after dispose throws\n        Assert.Throws<InvalidOperationException>(() => slice.Unpin());\n        // Use after dispose throws\n        Assert.Throws<InvalidOperationException>(() => slice.ToArray());\n    }\n\n    /// <summary>\n    /// Verifies that memory is not leaked (reference count returns to zero) after all slices are disposed.\n    /// </summary>\n    [Fact]\n    public void NoMemoryLeak_ReferenceCountReturnsToZero()\n    {\n        var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[PageSize * 2]);\n        var slices = new List<ArcBuffer>();\n        for (int i = 0; i < 10; i++)\n        {\n            slices.Add(buffer.PeekSlice(PageSize));\n        }\n        var pages = slices[0].Pages.ToList();\n        foreach (var s in slices)\n        {\n            s.Dispose();\n        }\n        foreach (var p in pages)\n        {\n            Assert.Equal(1, p.ReferenceCount); // Only the buffer's own pin remains\n        }\n        buffer.Dispose();\n        foreach (var p in pages)\n        {\n            Assert.Equal(0, p.ReferenceCount);\n        }\n    }\n\n    /// <summary>\n    /// Verifies that slicing and peeking with zero-length and full-length works for empty and full buffers.\n    /// </summary>\n    [Fact]\n    public void EmptyAndFullBuffer_SlicePeek()\n    {\n        using var buffer = new ArcBufferWriter();\n        using (var s = buffer.PeekSlice(0))\n        {\n            Assert.Equal(0, s.Length);\n        }\n        buffer.Write(new byte[PageSize]);\n        using (var s = buffer.PeekSlice(PageSize))\n        {\n            Assert.Equal(PageSize, s.Length);\n        }\n        using (var s = buffer.ConsumeSlice(PageSize))\n        {\n            Assert.Equal(PageSize, s.Length);\n        }\n        Assert.Equal(0, buffer.Length);\n    }\n\n    /// <summary>\n    /// Verifies that slicing at the very end of the buffer returns an empty slice.\n    /// </summary>\n    [Fact]\n    public void SliceAtEnd_ReturnsEmpty()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[10]);\n        buffer.ConsumeSlice(10).Dispose();\n        using (var s = buffer.PeekSlice(0))\n        {\n            Assert.Equal(0, s.Length);\n        }\n        Assert.Throws<ArgumentOutOfRangeException>(() => buffer.PeekSlice(1));\n    }\n\n    /// <summary>\n    /// Verifies that pin/unpin on different slices to the same page does not leak memory.\n    /// </summary>\n    [Fact]\n    public void MultipleSlices_SamePage_NoLeak()\n    {\n        using var buffer = new ArcBufferWriter();\n        buffer.Write(new byte[PageSize]);\n        var s1 = buffer.PeekSlice(PageSize / 2);\n        var s2 = buffer.PeekSlice(PageSize / 2);\n        var page = s1.First;\n        Assert.True(page.ReferenceCount >= 2);\n        s1.Dispose();\n        Assert.True(page.ReferenceCount >= 1);\n        s2.Dispose();\n        Assert.Equal(1, page.ReferenceCount); // Only buffer's own pin remains\n        buffer.Dispose();\n        Assert.Equal(0, page.ReferenceCount);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Buffers/Adaptors/PooledBufferStreamTests.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Linq;\nusing Microsoft.Extensions;\nusing Microsoft.Extensions.ObjectPool;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Xunit;\n\nnamespace Orleans.Serialization.Buffers.Adaptors.UnitTests;\n\n/// <summary>\n/// Unit tests for the PooledBufferStream constructor.\n/// </summary>\n[Category(\"BVT\")]\npublic class PooledBufferStreamTests\n{\n    /// <summary>\n    /// Verifies that the parameterless constructor initializes a new instance with a length of zero \n    /// and appropriate stream capabilities.\n    /// </summary>\n    [Fact]\n    public void Constructor_Parameterless_InitializesWithZeroLengthAndValidCapabilities()\n    {\n        // Arrange & Act\n        using var stream = new PooledBufferStream();\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n        Assert.True(stream.CanRead);\n        Assert.True(stream.CanSeek);\n        Assert.True(stream.CanWrite);\n        // Verify default Position is 0\n        Assert.Equal(0, stream.Position);\n    }\n\n    /// <summary>\n    /// Verifies that the constructor with a minAllocationSize parameter initializes a new instance \n    /// with a length of zero and appropriate stream capabilities.\n    /// Tests various edge cases for the minAllocationSize parameter.\n    /// </summary>\n    /// <param name=\"minAllocationSize\">The minimum allocation size passed to the constructor.</param>\n    [Theory]\n    [InlineData(-1)]\n    [InlineData(0)]\n    [InlineData(1)]\n    [InlineData(4096)]\n    [InlineData(int.MaxValue)]\n    public void Constructor_WithMinAllocationSize_InitializesWithZeroLengthAndValidCapabilities(int minAllocationSize)\n    {\n        // Arrange & Act\n        using var stream = new PooledBufferStream(minAllocationSize);\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n        Assert.True(stream.CanRead);\n        Assert.True(stream.CanSeek);\n        Assert.True(stream.CanWrite);\n        // Verify default Position is 0\n        Assert.Equal(0, stream.Position);\n    }\n\n    /// <summary>\n    /// Verifies that the PooledBufferStream constructor initializes the Length property to zero,\n    /// regardless of the provided minAllocationSize parameter value.\n    /// Test cases include negative, zero, positive, int.MaxValue, and int.MinValue values.\n    /// </summary>\n    /// <param name=\"minAllocationSize\">The minimum allocation size used to initialize the stream.</param>\n    [Theory]\n    [InlineData(-1)]\n    [InlineData(0)]\n    [InlineData(1)]\n    [InlineData(100)]\n    [InlineData(int.MaxValue)]\n    [InlineData(int.MinValue)]\n    public void Constructor_WithMinAllocationValues_LengthIsZero(int minAllocationSize)\n    {\n        // Arrange & Act\n        using var stream = new PooledBufferStream(minAllocationSize);\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n    }\n\n    /// <summary>\n    /// Verifies that the default PooledBufferStream constructor initializes the Length property to zero.\n    /// </summary>\n    [Fact]\n    public void DefaultConstructor_LengthIsZero()\n    {\n        // Arrange & Act\n        using var stream = new PooledBufferStream();\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n    }\n\n    /// <summary>\n    /// Verifies that calling Rent returns a non-null instance of PooledBufferStream with an initial length of zero.\n    /// This test parameterizes the number of times Rent is called to ensure consistent behavior regardless of call count.\n    /// </summary>\n    /// <param name=\"rentCount\">The number of times to invoke Rent.</param>\n    [Theory]\n    [InlineData(1)]\n    [InlineData(5)]\n    [InlineData(10)]\n    public void Rent_MultipleTimes_ReturnsValidInstance(int rentCount)\n    {\n        // Arrange\n        var instances = new List<PooledBufferStream>();\n\n        // Act\n        for (int i = 0; i < rentCount; i++)\n        {\n            var instance = PooledBufferStream.Rent();\n            instances.Add(instance);\n        }\n\n        // Assert\n        Assert.Equal(rentCount, instances.Count);\n        foreach (var instance in instances)\n        {\n            Assert.NotNull(instance);\n            // Verify that the Length property is zero for a freshly rented stream.\n            Assert.Equal(0, instance.Length);\n        }\n    }\n\n    /// <summary>\n    /// Tests that returning a valid stream recycles it by ensuring that a subsequently rented instance is the same as the returned one.\n    /// </summary>\n    [Fact]\n    public void Return_ValidStream_RecyclesObject()\n    {\n        // Arrange\n        using var stream = PooledBufferStream.Rent();\n        // Modify state to simulate usage.\n        stream.Position = 100;\n\n        // Act\n        PooledBufferStream.Return(stream);\n        var recycledStream = PooledBufferStream.Rent();\n\n        // Assert\n        // Expect the same instance to be recycled.\n        Assert.True(Object.ReferenceEquals(stream, recycledStream), \"The recycled stream instance should be the same as the one returned.\");\n\n        // Cleanup: Return the stream again to avoid affecting other tests.\n        PooledBufferStream.Return(recycledStream);\n    }\n\n    /// <summary>\n    /// Tests that passing a null stream to Return throws an exception.\n    /// </summary>\n    [Fact]\n    public void Return_NullStream_ThrowsException()\n    {\n        // Arrange & Act & Assert\n        Assert.Throws<ArgumentNullException>(() => PooledBufferStream.Return(null));\n    }\n\n    /// <summary>\n    /// Verifies that a newly created PooledBufferStream has a Length of zero, regardless of the specified minAllocationSize.\n    /// </summary>\n    /// <param name=\"minAllocationSize\">The minimum allocation size to use when constructing the stream.</param>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(4096)]\n    [InlineData(100)]\n    [InlineData(-1)]\n    public void Length_OnNewStream_ReturnsZero(int minAllocationSize)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream(minAllocationSize);\n\n        // Act\n        long length = stream.Length;\n\n        // Assert\n        Assert.Equal(0L, length);\n    }\n\n    /// <summary>\n    /// Tests that ToArray returns an empty array when no data has been written to the stream.\n    /// </summary>\n    [Fact]\n    public void ToArray_EmptyStream_ReturnsEmptyArray()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act\n        byte[] result = stream.ToArray();\n\n        // Assert\n        Assert.NotNull(result);\n        Assert.Empty(result);\n    }\n\n    /// <summary>\n    /// Verifies that the CopyTo method correctly writes all segments to the provided writer.\n    /// </summary>\n    [Theory]\n    [InlineData(new byte[] { 1, 2, 3, 4 })]\n    [InlineData(new byte[] { 10, 20, 30 })]\n    public void CopyTo_ValidSegments_CopiesDataCorrectly(byte[] expectedData)\n    {\n        using var stream = new PooledBufferStream();\n        stream.Write(expectedData);\n\n        var output = new byte[expectedData.Length];\n        var writer = Writer.Create(output, session: null);\n\n        stream.CopyTo(ref writer);\n\n        Assert.Equal(expectedData, output);\n    }\n\n    /// <summary>\n    /// Verifies that the CopyTo method correctly writes all segments to the provided writer for larger buffers.\n    /// Tests with buffers larger than 5kb to ensure multi-segment functionality works properly.\n    /// </summary>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(1)]\n    [InlineData(1 * 1024)]\n    [InlineData(4 * 1024 - 1)]\n    [InlineData(4 * 1024)]\n    [InlineData(4 * 1024 + 1)]\n    [InlineData(5 * 1024)]\n    [InlineData(8 * 1024)]\n    public void CopyTo_LargeBuffers_CopiesDataCorrectly(int bufferSize)\n    {\n        using var stream = new PooledBufferStream();\n        var expectedData = GenerateTestData(bufferSize);\n        stream.Write(expectedData, 0, expectedData.Length);\n\n        var output = new byte[expectedData.Length];\n        var writer = Writer.Create(output, session: null);\n\n        stream.CopyTo(ref writer);\n\n        Assert.True(expectedData.SequenceEqual(output));\n    }\n\n    /// <summary>\n    /// Verifies that calling Reset on a fresh instance results in a Length of zero.\n    /// </summary>\n    [Fact]\n    public void Reset_FreshInstance_LengthIsZero()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act\n        stream.Reset();\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n    }\n\n    /// <summary>\n    /// Verifies that after writing data to the stream, calling Reset resets the stream length to zero.\n    /// Tests multiple scenarios using different write counts.\n    /// </summary>\n    /// <param name=\"writeCount\">The number of bytes to write to the stream.</param>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(1024)]\n    public void Reset_AfterWrite_LengthResetToZero(int writeCount)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        var buffer = new byte[writeCount];\n        // Populate the buffer with some dummy data if needed.\n        for (int i = 0; i < writeCount; i++)\n        {\n            buffer[i] = (byte)(i % 256);\n        }\n\n        // Act\n        stream.Write(buffer, 0, writeCount);\n        // Depending on implementation, Length may or may not reflect the exact number of written bytes.\n        // Calling Reset should clear any written data and reset Length.\n        stream.Reset();\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n    }\n\n    /// <summary>\n    /// Verifies that calling Reset resets the Position property to zero.\n    /// This is important when recycling streams from the pool to ensure the position\n    /// doesn't carry over from previous usage.\n    /// </summary>\n    /// <param name=\"initialPosition\">The initial position to set before calling Reset.</param>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(10)]\n    [InlineData(100)]\n    [InlineData(1024)]\n    public void Reset_WithPosition_ResetsPositionToZero(int initialPosition)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        stream.SetLength(2000); // Set length large enough to accommodate position\n        stream.Position = initialPosition;\n\n        // Act\n        stream.Reset();\n\n        // Assert\n        Assert.Equal(0, stream.Position);\n        Assert.Equal(0, stream.Length);\n    }\n\n    /// <summary>\n    /// Verifies that RentReadOnlySequence returns a correct ReadOnlySequence for various data lengths.\n    /// When no data has been written, an empty sequence is returned; otherwise, the sequence matches the written data.\n    /// </summary>\n    /// <param name=\"dataLength\">The length of the test data to write to the stream.</param>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(100)]\n    [InlineData(4096)]\n    [InlineData(5000)]\n    public void RentReadOnlySequence_VariousDataLengths_ReturnsExpectedSequence(int dataLength)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        byte[] expectedData = GenerateTestData(dataLength);\n        if (dataLength > 0)\n        {\n            stream.Write(expectedData, 0, expectedData.Length);\n        }\n\n        // Act\n        ReadOnlySequence<byte> sequence = stream.RentReadOnlySequence();\n\n        // Assert\n        if (dataLength == 0)\n        {\n            Assert.Equal(0, sequence.Length);\n        }\n        else\n        {\n            byte[] actualData = sequence.ToArray();\n            Assert.Equal(expectedData.Length, actualData.Length);\n            Assert.True(expectedData.SequenceEqual(actualData));\n        }\n\n        stream.ReturnReadOnlySequence(sequence);\n    }\n\n    /// <summary>\n    /// Generates deterministic test data of a specified length.\n    /// </summary>\n    /// <param name=\"length\">The length of the data to generate.</param>\n    /// <returns>A byte array filled with sequential values modulo 256.</returns>\n    private static byte[] GenerateTestData(int length)\n    {\n        byte[] data = new byte[length];\n        for (int i = 0; i < length; i++)\n        {\n            data[i] = (byte)(i % 256);\n        }\n        return data;\n    }\n\n    /// <summary>\n    /// Verifies that ReturnReadOnlySequence performs no action when the sequence's start does not return a BufferSegment.\n    /// In this test, we create a dummy ReadOnlySequenceSegment<byte> that returns an object not of type BufferSegment.\n    /// Expected outcome: No exception is thrown.\n    /// </summary>\n    [Theory]\n    [InlineData(0)]\n    [InlineData(100)]\n    public void ReturnReadOnlySequence_StartNotBufferSegment_DoesNotThrow(int dummyValue)\n    {\n        // Arrange\n        var dummySegment = new DummyReadOnlySequenceSegment(dummyValue);\n        // Create a ReadOnlySequence using the dummy segment.\n        var sequence = new ReadOnlySequence<byte>(dummySegment, 0, dummySegment, dummySegment.Memory.Length);\n        using var stream = new PooledBufferStream();\n\n        // Act & Assert (should not throw)\n        stream.ReturnReadOnlySequence(in sequence);\n    }\n\n    /// <summary>\n    /// Verifies that ReturnReadOnlySequence returns the BufferSegment chain to the pool.\n    /// Tests that each segment in a multi-segment chain is properly returned to the pool\n    /// and can be reused for subsequent operations.\n    /// </summary>\n    [Fact]\n    public void ReturnReadOnlySequence_ValidBufferSegmentChain_CallsPoolReturnForEachSegment()\n    {\n        using var stream = new PooledBufferStream();\n        \n        // Write data that will span multiple segments to create a chain\n        var dataSize = 10000; // Large enough to span multiple segments\n        var testData = GenerateTestData(dataSize);\n        stream.Write(testData, 0, testData.Length);\n\n        // Rent the ReadOnlySequence to get the BufferSegment chain\n        var sequence = stream.RentReadOnlySequence();\n\n        // Verify we have a multi-segment chain\n        Assert.True(sequence.Length > 0);\n        \n        // Count the number of segments in the chain before returning\n        var segmentCount = CountSegmentsInChain(sequence);\n        Assert.True(segmentCount > 1, \"Test requires multiple segments to verify chain handling\");\n\n        // Get fresh segments from the pool to verify they're different before returning\n        var freshSegments = new List<PooledBufferStream.BufferSegment>();\n        for (int i = 0; i < segmentCount; i++)\n        {\n            freshSegments.Add(PooledBufferStream.BufferSegment.Pool.Get());\n        }\n\n        // Return the fresh segments to avoid affecting the test\n        foreach (var segment in freshSegments)\n        {\n            PooledBufferStream.BufferSegment.Pool.Return(segment);\n        }\n\n        // Return the sequence - this should return all segments in the chain to the pool\n        stream.ReturnReadOnlySequence(sequence);\n\n        // Verify that segments are returned to the pool by getting new ones\n        // and checking they're the same instances (indicating they were recycled)\n        var recycledSegments = new List<PooledBufferStream.BufferSegment>();\n        for (int i = 0; i < segmentCount; i++)\n        {\n            recycledSegments.Add(PooledBufferStream.BufferSegment.Pool.Get());\n        }\n\n        // The recycled segments should be reset and ready for reuse\n        foreach (var segment in recycledSegments)\n        {\n            Assert.True(segment.Memory.IsEmpty, \"Recycled segment should have empty memory\");\n            Assert.Equal(0, segment.RunningIndex);\n            Assert.Null(segment.Next);\n        }\n\n        // Clean up by returning the segments back to the pool\n        foreach (var segment in recycledSegments)\n        {\n            PooledBufferStream.BufferSegment.Pool.Return(segment);\n        }\n    }\n\n    /// <summary>\n    /// Counts the number of segments in a ReadOnlySequence chain.\n    /// </summary>\n    /// <param name=\"sequence\">The sequence to count segments for.</param>\n    /// <returns>The number of segments in the chain.</returns>\n    private static int CountSegmentsInChain(ReadOnlySequence<byte> sequence)\n    {\n        if (sequence.IsSingleSegment)\n        {\n            return 1;\n        }\n\n        var count = 0;\n        var position = sequence.Start;\n        while (sequence.TryGet(ref position, out var memory))\n        {\n            count++;\n            if (position.Equals(sequence.End))\n            {\n                break;\n            }\n        }\n\n        return count;\n    }\n\n    /// <summary>\n    /// A dummy implementation of ReadOnlySequenceSegment<byte> used to simulate a segment whose GetObject does not return a BufferSegment.\n    /// </summary>\n    private class DummyReadOnlySequenceSegment : ReadOnlySequenceSegment<byte>\n    {\n        private readonly int _dummyValue;\n\n        public DummyReadOnlySequenceSegment(int dummyValue)\n        {\n            _dummyValue = dummyValue;\n            // Initialize Memory with an empty array for simplicity.\n            Memory = new byte[0];\n        }\n\n    }\n\n    /// <summary>\n    /// Tests that the CanRead property returns true.\n    /// This test verifies that a newly instantiated PooledBufferStream correctly reports that it can be read.\n    /// </summary>\n    [Fact]\n    public void CanRead_Property_ReturnsTrue()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act\n        bool canRead = stream.CanRead;\n\n        // Assert\n        Assert.True(canRead);\n    }\n\n    /// <summary>\n    /// Tests that the CanSeek property returns true.\n    /// </summary>\n    [Fact]\n    public void CanSeek_Property_ReturnsTrue()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act\n        bool result = stream.CanSeek;\n\n        // Assert\n        Assert.True(result);\n    }\n\n    /// <summary>\n    /// Tests that the CanWrite property returns true regardless of the constructor used.\n    /// </summary>\n    /// <param name=\"useNonDefaultConstructor\">Boolean flag to test both default and parameterized constructors.</param>\n    [Theory]\n    [InlineData(false)]\n    [InlineData(true)]\n    public void CanWrite_Property_ReturnsTrue(bool useNonDefaultConstructor)\n    {\n        // Arrange\n        using var stream = useNonDefaultConstructor ? new PooledBufferStream(1024) : new PooledBufferStream();\n\n        // Act\n        bool canWrite = stream.CanWrite;\n\n        // Assert\n        Assert.True(canWrite);\n    }\n\n    /// <summary>\n    /// Tests valid Seek scenarios with a preset stream length.\n    /// For Begin: newPosition equals the offset.\n    /// For Current: newPosition equals Position plus offset.\n    /// For End: newPosition equals Length minus offset.\n    /// </summary>\n    /// <param name=\"offset\">The offset parameter for Seek.</param>\n    /// <param name=\"origin\">The SeekOrigin used in Seek.</param>\n    /// <param name=\"expectedPosition\">The expected new position after seeking.</param>\n    [Theory]\n    [InlineData(30, SeekOrigin.Begin, 30)]\n    [InlineData(20, SeekOrigin.Current, 30)]\n    [InlineData(10, SeekOrigin.End, 90)]\n    public void Seek_ValidScenarios_ExpectedPosition(long offset, SeekOrigin origin, long expectedPosition)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        stream.SetLength(100);\n        if (origin == SeekOrigin.Current)\n        {\n            stream.Position = 10;\n        }\n\n        // Act\n        long result = stream.Seek(offset, origin);\n\n        // Assert\n        Assert.Equal(expectedPosition, result);\n        Assert.Equal(expectedPosition, stream.Position);\n    }\n\n    /// <summary>\n    /// Tests valid Seek scenarios on a stream with default length (0).\n    /// For Begin and Current with offset 0, the operation should succeed.\n    /// </summary>\n    [Theory]\n    [InlineData(0, SeekOrigin.Begin, 0)]\n    [InlineData(0, SeekOrigin.Current, 0)]\n    public void Seek_ZeroOffsetOnEmptyStream_ReturnsZero(long offset, SeekOrigin origin, long expectedPosition)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act\n        long result = stream.Seek(offset, origin);\n\n        // Assert\n        Assert.Equal(expectedPosition, result);\n        Assert.Equal(expectedPosition, stream.Position);\n    }\n\n    /// <summary>\n    /// Tests Seek scenarios that are expected to throw InvalidOperationException \n    /// when the resulting position is out of bounds.\n    /// </summary>\n    /// <param name=\"offset\">The offset parameter for Seek.</param>\n    /// <param name=\"origin\">The SeekOrigin used in Seek.</param>\n    /// <param name=\"expectedMessage\">The expected exception message.</param>\n    [Theory]\n    // For Begin: negative offset.\n    [InlineData(-1, SeekOrigin.Begin, \"Attempted to seek past beginning of stream\")]\n    // For Current: result becomes negative.\n    [InlineData(-11, SeekOrigin.Current, \"Attempted to seek past beginning of stream\")]\n    // For End: offset greater than Length results in negative newPosition.\n    [InlineData(101, SeekOrigin.End, \"Attempted to seek past beginning of stream\")]\n    // For Begin: offset greater than Length.\n    [InlineData(101, SeekOrigin.Begin, \"Attempted to seek past end of stream\")]\n    // For Current: result exceeds Length.\n    [InlineData(91, SeekOrigin.Current, \"Attempted to seek past end of stream\")]\n    // For End: negative offset causes newPosition to exceed Length.\n    [InlineData(-1, SeekOrigin.End, \"Attempted to seek past end of stream\")]\n    public void Seek_OutOfBounds_ThrowsInvalidOperationException(long offset, SeekOrigin origin, string expectedMessage)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        stream.SetLength(100);\n        if (origin == SeekOrigin.Current)\n        {\n            stream.Position = 10;\n        }\n\n        // Act & Assert\n        var ex = Assert.Throws<InvalidOperationException>(() => stream.Seek(offset, origin));\n        Assert.Equal(expectedMessage, ex.Message);\n    }\n\n    /// <summary>\n    /// Tests that an invalid SeekOrigin value causes an ArgumentOutOfRangeException.\n    /// </summary>\n    [Fact]\n    public void Seek_InvalidOrigin_ThrowsArgumentOutOfRangeException()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act & Assert\n        Assert.Throws<ArgumentOutOfRangeException>(() => stream.Seek(0, (SeekOrigin)999));\n    }\n\n    /// <summary>\n    /// Verifies that calling Read on an empty stream (with no data written) returns zero.\n    /// </summary>\n    [Fact]\n    public void Read_WithEmptyStream_ReturnsZero()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        var buffer = new byte[10];\n\n        // Act\n        int bytesRead = stream.Read(buffer, 0, buffer.Length);\n\n        // Assert\n        Assert.Equal(0, bytesRead);\n    }\n\n    /// <summary>\n    /// Verifies that calling Read with a null buffer throws an ArgumentNullException.\n    /// </summary>\n    [Fact]\n    public void Read_NullBuffer_ThrowsArgumentNullException()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n\n        // Act & Assert\n        Assert.Throws<ArgumentNullException>(() => stream.Read(null, 0, 5));\n    }\n\n    /// <summary>\n    /// Verifies that calling Read with an invalid offset or count throws an ArgumentOutOfRangeException.\n    /// </summary>\n    /// <param name=\"offset\">The offset to use when reading.</param>\n    /// <param name=\"count\">The count to use when reading.</param>\n    [Theory]\n    [InlineData(-1, 5)]\n    [InlineData(2, 100)]\n    public void Read_InvalidOffsetOrCount_ThrowsArgumentOutOfRangeException(int offset, int count)\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        var buffer = new byte[10];\n\n        // Act & Assert\n        Assert.Throws<ArgumentOutOfRangeException>(() => stream.Read(buffer, offset, count));\n    }\n\n    /// <summary>\n    /// Verifies that calling SetLength with a value equal to the current Length does not modify the stream state.\n    /// This test sets an initial non-zero length then calls SetLength with the same value.\n    /// </summary>\n    [Fact]\n    public void SetLength_ValueEqualsCurrentLength_DoesNotChangeState()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        stream.Position = 200;\n        stream.SetLength(500);\n        long originalLength = stream.Length;\n        long originalPosition = stream.Position;\n\n        // Act\n        stream.SetLength(500);\n\n        // Assert\n        Assert.Equal(originalLength, stream.Length);\n        Assert.Equal(originalPosition, stream.Position);\n    }\n\n    /// <summary>\n    /// Verifies that calling SetLength on an empty or non-empty stream updates the Length and adjusts Position accordingly.\n    /// This test covers scenarios including growth and truncation.\n    /// </summary>\n    /// <param name=\"initialPosition\">The initial Position set on the stream.</param>\n    /// <param name=\"initialSetLength\">The first SetLength call to establish a non-empty state.</param>\n    /// <param name=\"newSetLength\">The second SetLength call to update the length.</param>\n    /// <param name=\"expectedPosition\">The expected Position after updating the length.</param>\n    /// <param name=\"expectedLength\">The expected Length after updating the length.</param>\n    [Theory]\n    [InlineData(100, 500, 500, 100, 500)]   // Equality case on non-empty stream.\n    [InlineData(600, 500, 1000, 500, 1000)]  // Growth case: initial length 500 grows to 1000.\n    [InlineData(800, 1000, 500, 500, 500)]   // Truncate case: initial length 1000 truncates to 500.\n    public void SetLength_Scenarios_UpdatesLengthAndPosition(int initialPosition, int initialSetLength, int newSetLength, int expectedPosition, int expectedLength)\n    {\n        // Arrange\n        using var stream = new MemoryStream();\n        stream.Position = initialPosition;\n        stream.SetLength(initialSetLength);\n\n        // Act\n        stream.SetLength(newSetLength);\n\n        // Assert\n        Assert.Equal(expectedLength, stream.Length);\n        Assert.Equal(expectedPosition, stream.Position);\n    }\n\n    /// <summary>\n    /// Verifies that calling SetLength with 0 on an empty stream maintains Length and Position at 0.\n    /// </summary>\n    [Fact]\n    public void SetLength_ZeroOnEmpty_DoesNotChangeState()\n    {\n        // Arrange\n        using var stream = new PooledBufferStream();\n        stream.Position = 0;\n\n        // Act\n        stream.SetLength(0);\n\n        // Assert\n        Assert.Equal(0, stream.Length);\n        Assert.Equal(0, stream.Position);\n    }\n\n    /// <summary>\n    /// Provides invalid parameter combinations for testing Write method exceptions.\n    /// Each object array contains: buffer, offset, count, and expected exception type.\n    /// </summary>\n    public static IEnumerable<object[]> InvalidWriteParameters\n    {\n        get\n        {\n            yield return new object[] { null, 0, 1, typeof(ArgumentNullException) };\n            yield return new object[] { new byte[5], -1, 3, typeof(ArgumentOutOfRangeException) };\n            yield return new object[] { new byte[5], 2, -1, typeof(ArgumentOutOfRangeException) };\n            yield return new object[] { new byte[5], 3, 3, typeof(ArgumentOutOfRangeException) };\n        }\n    }\n\n    /// <summary>\n    /// Tests that Write throws the appropriate exceptions when provided with invalid parameters.\n    /// </summary>\n    /// <param name=\"buffer\">The input byte array (may be null).</param>\n    /// <param name=\"offset\">The starting offset in the array.</param>\n    /// <param name=\"count\">The number of bytes to write.</param>\n    /// <param name=\"expectedException\">The expected type of exception.</param>\n    [Theory]\n    [MemberData(nameof(InvalidWriteParameters))]\n    public void Write_InvalidParameters_ThrowsException(byte[] buffer, int offset, int count, Type expectedException)\n    {\n        using var stream = new PooledBufferStream();\n        Assert.Throws(expectedException, () => stream.Write(buffer, offset, count));\n    }\n\n    /// <summary>\n    /// Tests that calling Write with a zero count does not modify the stream's position.\n    /// </summary>\n    [Fact]\n    public void Write_ZeroCount_DoesNothing()\n    {\n        using var stream = new PooledBufferStream();\n        long initialPosition = stream.Position;\n        byte[] data = new byte[10];\n        stream.Write(data, 0, 0);\n        Assert.Equal(initialPosition, stream.Position);\n    }\n\n    /// <summary>\n    /// Tests that Write correctly appends data to the stream.\n    /// Verifies that written data can be retrieved via ToArray() and that the stream's Position advances appropriately.\n    /// </summary>\n    /// <param name=\"inputLength\">The length of data to write.</param>\n    [Theory]\n    [InlineData(1)]\n    [InlineData(10)]\n    [InlineData(4096)]\n    public void Write_ValidInput_AppendsData(int inputLength)\n    {\n        using var stream = new PooledBufferStream();\n        byte[] data = new byte[inputLength];\n        for (int i = 0; i < inputLength; i++)\n        {\n            data[i] = (byte)(i % 256);\n        }\n        long initialPosition = stream.Position;\n        \n        stream.Write(data, 0, data.Length);\n        \n        // Verify that the data has been correctly appended\n        byte[] writtenData = stream.ToArray();\n        Assert.Equal(data, writtenData);\n        \n        // Verify that the stream length matches the written data length\n        Assert.Equal(inputLength, stream.Length);\n        \n        // Verify that the position has advanced correctly\n        Assert.Equal(initialPosition + inputLength, stream.Position);\n    }\n\n    /// <summary>\n    /// Verifies that the Flush method performs no operation and does not throw any exceptions.\n    /// </summary>\n    [Fact]\n    public void Flush_NoData_DoesNotThrowException()\n    {\n        // Arrange: Create a new instance of PooledBufferStream.\n        using var stream = new PooledBufferStream();\n\n        // Act & Assert: Calling Flush should not throw an exception.\n        var exception = Record.Exception(() => stream.Flush());\n        Assert.Null(exception);\n    }\n}\n\n/// <summary>\n/// Unit tests for the BufferSegment class.\n/// </summary>\npublic class BufferSegmentTests\n{\n    /// <summary>\n    /// Provides test data for the Initialize method.\n    /// Each test case includes a byte array and a corresponding runningIndex value.\n    /// </summary>\n    public static IEnumerable<object[]> GetInitializeTestData()\n    {\n        yield return new object[] { new byte[0], 0L };\n        yield return new object[] { new byte[] { 1, 2, 3 }, 123L };\n        yield return new object[] { new byte[] { 255 }, -1L };\n        yield return new object[] { new byte[] { 0, 0, 0, 0, 1 }, long.MaxValue };\n        yield return new object[] { new byte[] { 10, 20, 30, 40, 50 }, long.MinValue };\n    }\n\n    /// <summary>\n    /// Verifies that the Initialize method sets the Memory and RunningIndex properties correctly.\n    /// Tests various edge cases including empty arrays, typical values, and boundary numeric values.\n    /// </summary>\n    /// <param name=\"inputData\">Byte array to be set into the Memory property.</param>\n    /// <param name=\"runningIndex\">The runningIndex value to be assigned.</param>\n    [Theory]\n    [MemberData(nameof(GetInitializeTestData))]\n    public void Initialize_ValidInput_PropertiesSetCorrectly(byte[] inputData, long runningIndex)\n    {\n        // Arrange\n        ReadOnlyMemory<byte> readOnlyMemory = new ReadOnlyMemory<byte>(inputData);\n        var bufferSegment = new PooledBufferStream.BufferSegment();\n\n        // Act\n        bufferSegment.Initialize(readOnlyMemory, runningIndex);\n\n        // Assert\n        Assert.Equal(readOnlyMemory.ToArray(), bufferSegment.Memory.ToArray());\n        Assert.Equal(runningIndex, bufferSegment.RunningIndex);\n    }\n\n    /// <summary>\n    /// Verifies that calling SetNext with a valid BufferSegment correctly sets the Next property.\n    /// </summary>\n    [Fact]\n    public void SetNext_ValidBufferSegment_SetsNextProperty()\n    {\n        // Arrange\n        var segment = new PooledBufferStream.BufferSegment();\n        var nextSegment = new PooledBufferStream.BufferSegment();\n\n        // Act\n        segment.SetNext(nextSegment);\n\n        // Assert\n        Assert.Equal(nextSegment, segment.Next);\n    }\n\n    /// <summary>\n    /// Verifies that calling SetNext more than once correctly overwrites the Next property.\n    /// </summary>\n    [Fact]\n    public void SetNext_OverwriteExistingNext_SetsNextPropertyToNewValue()\n    {\n        // Arrange\n        var segment = new PooledBufferStream.BufferSegment();\n        var firstNextSegment = new PooledBufferStream.BufferSegment();\n        var secondNextSegment = new PooledBufferStream.BufferSegment();\n\n        // Act\n        segment.SetNext(firstNextSegment);\n        segment.SetNext(secondNextSegment);\n\n        // Assert\n        Assert.Equal(secondNextSegment, segment.Next);\n    }\n\n    /// <summary>\n    /// Verifies that the SegmentPoolPolicy.Create method creates a new BufferSegment instance.\n    /// This test calls BufferSegment.Pool.Get() which internally uses the SegmentPoolPolicy.Create method.\n    /// Expected: A non-null BufferSegment instance is returned.\n    /// </summary>\n    [Fact]\n    public void SegmentPoolPolicy_Create_ReturnsNewBufferSegment()\n    {\n        // Act\n        PooledBufferStream.BufferSegment segment = PooledBufferStream.BufferSegment.Pool.Get();\n\n        // Assert\n        Assert.NotNull(segment);\n        Assert.IsType<PooledBufferStream.BufferSegment>(segment);\n        PooledBufferStream.BufferSegment.Pool.Return(segment);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs",
    "content": "using CsCheck;\n#if NET8_0_OR_GREATER\nusing Orleans;\nusing Orleans.CodeGeneration;\n#endif\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TestKit;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.FSharp.Core;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Collections.ObjectModel;\nusing System.Collections.Specialized;\nusing System.Linq;\nusing System.Net;\nusing System.Numerics;\n#if NET8_0_OR_GREATER\nusing System.Xml.Linq;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Serialization;\n#endif\nusing Xunit;\nusing Microsoft.FSharp.Collections;\nusing Xunit.Abstractions;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Configuration;\nusing System.Reflection;\nusing System.CodeDom.Compiler;\nusing System.Collections;\nusing Orleans.Serialization.Invocation;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    internal static class CsCheckAdaptor\n    {\n        public static Action<Action<TValue>> ToValueProvider<TValue>(this Gen<TValue> gen) => value => gen.Sample(value);\n    }\n\n    [GenerateSerializer]\n    public enum MyEnum : short\n    {\n        None,\n        One,\n        Two\n    }\n\n    /// <summary>\n    /// Tests for Orleans' built-in codecs for primitive and common .NET types.\n    /// Orleans provides optimized serialization codecs for commonly used types including:\n    /// - Primitive types (int, bool, etc.)\n    /// - Common .NET types (DateTime, Guid, Version, etc.)\n    /// - Collection types (List, Dictionary, arrays, etc.)\n    /// - Nullable types\n    /// - Enums\n    ///\n    /// These codecs are designed for:\n    /// - High performance with minimal allocations\n    /// - Compact binary representation\n    /// - Version tolerance (forward/backward compatibility)\n    /// - Cross-language support where applicable\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class CodecTestTests\n    {\n        [Fact]\n        public void EveryCodecHasTests()\n        {\n            var services = new ServiceCollection().AddSerializer().BuildServiceProvider();\n            var serializerOptions = services.GetRequiredService<IOptions<TypeManifestOptions>>();\n            var typesWithCodecs = new HashSet<Type>();\n            var typesWithCopiers = new HashSet<Type>();\n            foreach (var codec in serializerOptions.Value.Serializers)\n            {\n                if (codec.IsAbstract || codec.GetCustomAttribute<GeneratedCodeAttribute>() is not null)\n                {\n                    continue;\n                }\n\n                foreach (var iface in codec.GetInterfaces())\n                {\n                    if (!iface.IsGenericType)\n                    {\n                        continue;\n                    }\n\n                    var gtd = iface.GetGenericTypeDefinition();\n                    if (gtd == typeof(IFieldCodec<>) && iface.GenericTypeArguments[0] is { IsArray: false })\n                    {\n                        var typeArg = iface.GenericTypeArguments[0] switch\n                        {\n                            { IsGenericType: true } gt => gt.GetGenericTypeDefinition(),\n                            { } t => t,\n                        };\n                        typesWithCodecs.Add(typeArg);\n                    }\n\n                    if (gtd == typeof(IDeepCopier<>) && iface.GenericTypeArguments[0] is { IsArray: false })\n                    {\n                        var typeArg = iface.GenericTypeArguments[0] switch\n                        {\n                            { IsGenericType: true } gt => gt.GetGenericTypeDefinition(),\n                            { } t => t,\n                        };\n                        typesWithCopiers.Add(typeArg);\n                    }\n                }\n            }\n\n            var typesWithCodecTests = new HashSet<Type>();\n            var typesWithCopierTests = new HashSet<Type>();\n            foreach (var type in typeof(CodecTestTests).Assembly.GetTypes())\n            {\n                if (type.BaseType is not { IsGenericType: true } baseType)\n                {\n                    continue;\n                }\n\n                var genericTypeDefinition = baseType.GetGenericTypeDefinition();\n                if (genericTypeDefinition == typeof(FieldCodecTester<,>))\n                {\n                    var typeArg = baseType.GenericTypeArguments[0] switch\n                    {\n                        { IsGenericType: true } gt => gt.GetGenericTypeDefinition(),\n                        { } t => t,\n                    };\n\n                    typesWithCodecTests.Add(typeArg);\n                }\n                else if (genericTypeDefinition == typeof(CopierTester<,>))\n                {\n                    var typeArg = baseType.GenericTypeArguments[0] switch\n                    {\n                        { IsGenericType: true } gt => gt.GetGenericTypeDefinition(),\n                        { } t => t,\n                    };\n\n                    typesWithCopierTests.Add(typeArg);\n                }\n            }\n\n            var excludedTypes = new HashSet<Type>();\n            TryAddExcludedType(excludedTypes, \"UnitTests.GrainInterfaces.UnserializableType, TestGrainInterfaces\");\n            TryAddExcludedType(excludedTypes, \"UnitTests.GrainInterfaces.UndeserializableType, TestGrainInterfaces\");\n\n            var typesWithoutCodecTests = typesWithCodecs.Except(typesWithCodecTests).Except(excludedTypes).ToArray();\n            if (typesWithoutCodecTests.Length > 0)\n            {\n                Assert.Fail($\"Missing codec tests for \\n * {string.Join(\"\\n * \", typesWithoutCodecTests.Select(t => t.ToString()))}\");\n            }\n\n            var typesWithoutCopierTests = typesWithCopiers.Except(typesWithCopierTests).Except(excludedTypes).ToArray();\n            if (typesWithoutCopierTests.Length > 0)\n            {\n                Assert.Fail($\"Missing copier tests for \\n * {string.Join(\"\\n * \", typesWithoutCopierTests.Select(t => t.ToString()))}\");\n            }\n\n            static void TryAddExcludedType(HashSet<Type> excluded, string typeName)\n            {\n                if (Type.GetType(typeName) is { } type)\n                {\n                    excluded.Add(type);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Tests enum serialization and deserialization.\n    /// Enums in Orleans are serialized efficiently as their underlying type values,\n    /// ensuring compact representation and support for undefined enum values.\n    /// </summary>\n    public class EnumTests(ITestOutputHelper output) : FieldCodecTester<MyEnum, IFieldCodec<MyEnum>>(output)\n    {\n        protected override IFieldCodec<MyEnum> CreateCodec() => ServiceProvider.GetRequiredService<ICodecProvider>().GetCodec<MyEnum>();\n        protected override MyEnum CreateValue() => (MyEnum)Random.Next((int)MyEnum.None, (int)MyEnum.Two);\n        protected override MyEnum[] TestValues => [MyEnum.None, MyEnum.One, MyEnum.Two, (MyEnum)(-1), (MyEnum)10_000];\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.Services.RemoveAll(typeof(IFieldCodec<MyEnum>));\n        }\n\n        protected override Action<Action<MyEnum>> ValueProvider => Gen.Int.Select(v => (MyEnum)v).ToValueProvider();\n    }\n\n    public class EnumCopierTests(ITestOutputHelper output) : CopierTester<MyEnum, IDeepCopier<MyEnum>>(output)\n    {\n        protected override IDeepCopier<MyEnum> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<MyEnum>();\n        protected override MyEnum CreateValue() => (MyEnum)Random.Next((int)MyEnum.None, (int)MyEnum.Two);\n        protected override MyEnum[] TestValues => [MyEnum.None, MyEnum.One, MyEnum.Two, (MyEnum)(-1), (MyEnum)10_000];\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.Services.RemoveAll(typeof(IFieldCodec<MyEnum>));\n        }\n\n        protected override Action<Action<MyEnum>> ValueProvider => Gen.Int.Select(v => (MyEnum)v).ToValueProvider();\n    }\n\n    public class DateTimeKindTests(ITestOutputHelper output) : FieldCodecTester<DateTimeKind, IFieldCodec<DateTimeKind>>(output)\n    {\n        protected override IFieldCodec<DateTimeKind> CreateCodec() => ServiceProvider.GetRequiredService<ICodecProvider>().GetCodec<DateTimeKind>();\n        protected override DateTimeKind CreateValue() => (DateTimeKind)Random.Next((int)DateTimeKind.Unspecified, (int)DateTimeKind.Local + 1);\n        protected override DateTimeKind[] TestValues => [DateTimeKind.Utc, DateTimeKind.Unspecified, (DateTimeKind)(-1), (DateTimeKind)10_000];\n\n        protected override Action<Action<DateTimeKind>> ValueProvider => Gen.Int.Select(v => (DateTimeKind)v).ToValueProvider();\n    }\n\n    public class DateTimeKindCopierTests(ITestOutputHelper output) : CopierTester<DateTimeKind, IDeepCopier<DateTimeKind>>(output)\n    {\n        protected override IDeepCopier<DateTimeKind> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<DateTimeKind>();\n        protected override DateTimeKind CreateValue() => (DateTimeKind)Random.Next((int)DateTimeKind.Unspecified, (int)DateTimeKind.Local + 1);\n        protected override DateTimeKind[] TestValues => [DateTimeKind.Utc, DateTimeKind.Local, (DateTimeKind)(-1), (DateTimeKind)10_000];\n\n        protected override Action<Action<DateTimeKind>> ValueProvider => Gen.Int.Select(v => (DateTimeKind)v).ToValueProvider();\n    }\n\n    public class DayOfWeekTests(ITestOutputHelper output) : FieldCodecTester<DayOfWeek, IFieldCodec<DayOfWeek>>(output)\n    {\n        protected override IFieldCodec<DayOfWeek> CreateCodec() => ServiceProvider.GetRequiredService<ICodecProvider>().GetCodec<DayOfWeek>();\n        protected override DayOfWeek CreateValue() => (DayOfWeek)Random.Next((int)DayOfWeek.Sunday, (int)DayOfWeek.Saturday + 1);\n        protected override DayOfWeek[] TestValues => [DayOfWeek.Monday, DayOfWeek.Sunday, (DayOfWeek)(-1), (DayOfWeek)10_000];\n\n        protected override Action<Action<DayOfWeek>> ValueProvider => Gen.Int.Select(v => (DayOfWeek)v).ToValueProvider();\n    }\n\n    public class DayOfWeekCopierTests(ITestOutputHelper output) : CopierTester<DayOfWeek, IDeepCopier<DayOfWeek>>(output)\n    {\n        protected override IDeepCopier<DayOfWeek> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<DayOfWeek>();\n        protected override DayOfWeek CreateValue() => (DayOfWeek)Random.Next((int)DayOfWeek.Sunday, (int)DayOfWeek.Saturday);\n        protected override DayOfWeek[] TestValues => [DayOfWeek.Monday, DayOfWeek.Sunday, (DayOfWeek)(-1), (DayOfWeek)10_000];\n\n        protected override Action<Action<DayOfWeek>> ValueProvider => Gen.Int.Select(v => (DayOfWeek)v).ToValueProvider();\n    }\n\n    public class NullableIntTests(ITestOutputHelper output) : FieldCodecTester<int?, IFieldCodec<int?>>(output)\n    {\n        protected override IFieldCodec<int?> CreateCodec() => ServiceProvider.GetRequiredService<ICodecProvider>().GetCodec<int?>();\n        protected override int? CreateValue() => TestValues[Random.Next(TestValues.Length)];\n        protected override int?[] TestValues => [null, 1, 2, -3];\n    }\n\n    public class NullableIntCopierTests(ITestOutputHelper output) : CopierTester<int?, IDeepCopier<int?>>(output)\n    {\n        protected override IDeepCopier<int?> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<int?>();\n        protected override int? CreateValue() => TestValues[Random.Next(TestValues.Length)];\n        protected override int?[] TestValues => [null, 1, 2, -3];\n    }\n\n    public class DateTimeTests(ITestOutputHelper output) : FieldCodecTester<DateTime, DateTimeCodec>(output)\n    {\n        protected override DateTime CreateValue() => DateTime.UtcNow;\n        protected override DateTime[] TestValues => [DateTime.MinValue, DateTime.MaxValue, new DateTime(1970, 1, 1, 0, 0, 0)];\n        protected override Action<Action<DateTime>> ValueProvider => Gen.DateTime.ToValueProvider();\n    }\n\n    public class DateTimeCopierTests(ITestOutputHelper output) : CopierTester<DateTime, IDeepCopier<DateTime>>(output)\n    {\n        protected override DateTime CreateValue() => DateTime.UtcNow;\n        protected override DateTime[] TestValues => [DateTime.MinValue, DateTime.MaxValue, new DateTime(1970, 1, 1, 0, 0, 0)];\n        protected override Action<Action<DateTime>> ValueProvider => Gen.DateTime.ToValueProvider();\n    }\n\n#if NET6_0_OR_GREATER\n    public class DateOnlyTests(ITestOutputHelper output) : FieldCodecTester<DateOnly, DateOnlyCodec>(output)\n    {\n        protected override DateOnly CreateValue() => DateOnly.FromDateTime(DateTime.UtcNow);\n        protected override DateOnly[] TestValues => [DateOnly.MinValue, DateOnly.MaxValue, new DateOnly(1970, 1, 1), CreateValue()];\n        protected override Action<Action<DateOnly>> ValueProvider => assert => Gen.Date.Sample(dt => assert(DateOnly.FromDateTime(dt)));\n    }\n\n    public class TimeOnlyTests(ITestOutputHelper output) : FieldCodecTester<TimeOnly, TimeOnlyCodec>(output)\n    {\n        protected override TimeOnly CreateValue() => TimeOnly.FromDateTime(DateTime.UtcNow);\n        protected override TimeOnly[] TestValues => [TimeOnly.MinValue, TimeOnly.MaxValue, TimeOnly.FromTimeSpan(TimeSpan.Zero), CreateValue()];\n        protected override Action<Action<TimeOnly>> ValueProvider => assert => Gen.Date.Sample(dt => assert(TimeOnly.FromDateTime(dt)));\n    }\n\n    public class DateOnlyCopierTests(ITestOutputHelper output) : CopierTester<DateOnly, IDeepCopier<DateOnly>>(output)\n    {\n        protected override DateOnly CreateValue() => DateOnly.FromDateTime(DateTime.UtcNow);\n        protected override DateOnly[] TestValues => [DateOnly.MinValue, DateOnly.MaxValue, new DateOnly(1970, 1, 1), CreateValue()];\n        protected override Action<Action<DateOnly>> ValueProvider => assert => Gen.Date.Sample(dt => assert(DateOnly.FromDateTime(dt)));\n    }\n\n    public class TimeOnlyCopierTests(ITestOutputHelper output) : CopierTester<TimeOnly, IDeepCopier<TimeOnly>>(output)\n    {\n        protected override TimeOnly CreateValue() => TimeOnly.FromDateTime(DateTime.UtcNow);\n        protected override TimeOnly[] TestValues => [TimeOnly.MinValue, TimeOnly.MaxValue, TimeOnly.FromTimeSpan(TimeSpan.Zero), CreateValue()];\n        protected override Action<Action<TimeOnly>> ValueProvider => assert => Gen.Date.Sample(dt => assert(TimeOnly.FromDateTime(dt)));\n    }\n#endif\n\n    public class TimeSpanTests(ITestOutputHelper output) : FieldCodecTester<TimeSpan, TimeSpanCodec>(output)\n    {\n        protected override TimeSpan CreateValue() => TimeSpan.FromMilliseconds(Guid.NewGuid().GetHashCode());\n        protected override TimeSpan[] TestValues => [TimeSpan.MinValue, TimeSpan.MaxValue, TimeSpan.Zero, TimeSpan.FromSeconds(12345)];\n        protected override Action<Action<TimeSpan>> ValueProvider => Gen.TimeSpan.ToValueProvider();\n    }\n\n    public class TimeSpanCopierTests(ITestOutputHelper output) : CopierTester<TimeSpan, IDeepCopier<TimeSpan>>(output)\n    {\n        protected override TimeSpan CreateValue() => TimeSpan.FromMilliseconds(Guid.NewGuid().GetHashCode());\n        protected override TimeSpan[] TestValues => [TimeSpan.MinValue, TimeSpan.MaxValue, TimeSpan.Zero, TimeSpan.FromSeconds(12345)];\n        protected override Action<Action<TimeSpan>> ValueProvider => Gen.TimeSpan.ToValueProvider();\n    }\n\n    public class DateTimeOffsetTests(ITestOutputHelper output) : FieldCodecTester<DateTimeOffset, DateTimeOffsetCodec>(output)\n    {\n        protected override DateTimeOffset CreateValue() => DateTime.UtcNow;\n        protected override DateTimeOffset[] TestValues =>\n        [\n            DateTimeOffset.MinValue,\n            DateTimeOffset.MaxValue,\n            new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(11.5)),\n            new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(-11.5)),\n        ];\n\n        protected override Action<Action<DateTimeOffset>> ValueProvider => Gen.DateTimeOffset.ToValueProvider();\n    }\n\n    public class DateTimeOffsetCopierTests(ITestOutputHelper output) : CopierTester<DateTimeOffset, IDeepCopier<DateTimeOffset>>(output)\n    {\n        protected override DateTimeOffset CreateValue() => DateTime.UtcNow;\n        protected override DateTimeOffset[] TestValues =>\n        [\n            DateTimeOffset.MinValue,\n            DateTimeOffset.MaxValue,\n            new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(11.5)),\n            new DateTimeOffset(new DateTime(1970, 1, 1, 0, 0, 0), TimeSpan.FromHours(-11.5)),\n        ];\n\n        protected override Action<Action<DateTimeOffset>> ValueProvider => Gen.DateTimeOffset.ToValueProvider();\n    }\n\n    public class VersionTests(ITestOutputHelper output) : FieldCodecTester<Version, VersionCodec>(output)\n    {\n        protected override Version CreateValue() => new();\n        protected override Version[] TestValues =>\n        [\n            new Version(),\n            new Version(1, 2),\n            new Version(1, 2, 3),\n            new Version(1, 2, 3, 4),\n            new Version(\"1.2\"),\n            new Version(\"1.2.3\"),\n            new Version(\"1.2.3.4\")\n        ];\n\n        protected override bool Equals(Version left, Version right) => left == right && (left is null || left.GetHashCode() == right.GetHashCode());\n    }\n\n    public class VersionCopierTests(ITestOutputHelper output) : CopierTester<Version, IDeepCopier<Version>>(output)\n    {\n        protected override Version CreateValue() => new();\n        protected override Version[] TestValues =>\n        [\n            new Version(),\n            new Version(1, 2),\n            new Version(1, 2, 3),\n            new Version(1, 2, 3, 4),\n            new Version(\"1.2\"),\n            new Version(\"1.2.3\"),\n            new Version(\"1.2.3.4\")\n        ];\n\n        protected override bool Equals(Version left, Version right) => left == right && (left is null || left.GetHashCode() == right.GetHashCode());\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class BitVector32Tests(ITestOutputHelper output) : FieldCodecTester<BitVector32, BitVector32Codec>(output)\n    {\n        protected override BitVector32 CreateValue() => new(Random.Next());\n\n        protected override BitVector32[] TestValues =>\n        [\n            new BitVector32(0),\n            new BitVector32(100),\n            new BitVector32(-100),\n            CreateValue(),\n            CreateValue(),\n            CreateValue()\n        ];\n\n        protected override bool Equals(BitVector32 left, BitVector32 right) => left.Equals(right) && left.GetHashCode() == right.GetHashCode();\n    }\n\n    public class BitVector32CopierTests(ITestOutputHelper output) : CopierTester<BitVector32, IDeepCopier<BitVector32>>(output)\n    {\n        protected override BitVector32 CreateValue() => new(Random.Next());\n\n        protected override BitVector32[] TestValues =>\n        [\n            new BitVector32(0),\n            new BitVector32(100),\n            new BitVector32(-100),\n            CreateValue(),\n            CreateValue(),\n            CreateValue()\n        ];\n\n        protected override bool Equals(BitVector32 left, BitVector32 right) => left.Equals(right) && left.GetHashCode() == right.GetHashCode();\n    }\n\n    public class KeyValuePairTests(ITestOutputHelper output) : FieldCodecTester<KeyValuePair<string, string>, KeyValuePairCodec<string, string>>(output)\n    {\n        protected override KeyValuePair<string, string> CreateValue() => KeyValuePair.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override KeyValuePair<string, string>[] TestValues =>\n        [\n            default,\n            KeyValuePair.Create<string, string>(null, null),\n            KeyValuePair.Create<string, string>(string.Empty, \"foo\"),\n            KeyValuePair.Create<string, string>(\"foo\", \"bar\"),\n            KeyValuePair.Create<string, string>(\"foo\", \"foo\"),\n        ];\n    }\n\n    public class KeyValuePairCopierTests(ITestOutputHelper output) : CopierTester<KeyValuePair<string, string>, KeyValuePairCopier<string, string>>(output)\n    {\n        protected override KeyValuePair<string, string> CreateValue() => KeyValuePair.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override KeyValuePair<string, string>[] TestValues =>\n        [\n            default,\n            KeyValuePair.Create<string, string>(null, null),\n            KeyValuePair.Create<string, string>(string.Empty, \"foo\"),\n            KeyValuePair.Create<string, string>(\"foo\", \"bar\"),\n            KeyValuePair.Create<string, string>(\"foo\", \"foo\"),\n        ];\n    }\n\n    public class Tuple1Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string>, TupleCodec<string>>(output)\n    {\n        protected override Tuple<string> CreateValue() => Tuple.Create(Guid.NewGuid().ToString());\n\n        protected override Tuple<string>[] TestValues =>\n        [\n            null,\n            Tuple.Create<string>(null),\n            Tuple.Create<string>(string.Empty),\n            Tuple.Create<string>(\"foobar\")\n        ];\n    }\n\n    public class Tuple1CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string>, TupleCopier<string>>(output)\n    {\n        protected override Tuple<string> CreateValue() => Tuple.Create(Guid.NewGuid().ToString());\n\n        protected override Tuple<string>[] TestValues =>\n        [\n            null,\n            Tuple.Create<string>(null),\n            Tuple.Create<string>(string.Empty),\n            Tuple.Create<string>(\"foobar\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple2Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string>, TupleCodec<string, string>>(output)\n    {\n        protected override Tuple<string, string> CreateValue() => Tuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create<string, string>(null, null),\n            Tuple.Create<string, string>(string.Empty, \"foo\"),\n            Tuple.Create<string, string>(\"foo\", \"bar\"),\n            Tuple.Create<string, string>(\"foo\", \"foo\"),\n        ];\n    }\n\n    public class Tuple2CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string>, TupleCopier<string, string>>(output)\n    {\n        protected override Tuple<string, string> CreateValue() => Tuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create<string, string>(null, null),\n            Tuple.Create<string, string>(string.Empty, \"foo\"),\n            Tuple.Create<string, string>(\"foo\", \"bar\"),\n            Tuple.Create<string, string>(\"foo\", \"foo\"),\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple3Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string, string>, TupleCodec<string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class Tuple3CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string, string>, TupleCopier<string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple4Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string, string, string>, TupleCodec<string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class Tuple4CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string, string, string>, TupleCopier<string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple5Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string, string, string, string>, TupleCodec<string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty,string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class Tuple5CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string, string, string, string>, TupleCopier<string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty,string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple6Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string,string, string, string, string>, TupleCodec<string, string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class Tuple6CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string,string, string, string, string>, TupleCopier<string, string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple7Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string, string, string, string, string, string>, TupleCodec<string, string, string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class Tuple7CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string, string, string, string, string, string>, TupleCopier<string, string, string, string, string, string, string>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string, string> CreateValue() => Tuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override Tuple<string, string, string, string, string, string, string>[] TestValues =>\n        [\n            null,\n            Tuple.Create(default(string), default(string), default(string), default(string), default(string), default(string), default(string)),\n            Tuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            Tuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\"),\n            Tuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class Tuple8Tests(ITestOutputHelper output) : FieldCodecTester<Tuple<string, string, string, string, string, string, string, Tuple<string>>, TupleCodec<string, string, string, string, string, string, string, Tuple<string>>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string, string, Tuple<string>> CreateValue() => new(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            new Tuple<string>(Guid.NewGuid().ToString()));\n\n        protected override Tuple<string, string, string, string, string, string, string, Tuple<string>>[] TestValues =>\n        [\n            null,\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(default, default, default, default, default, default, default, new Tuple<string>(default)),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\", Tuple.Create(\"foo\")),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\", Tuple.Create(\"8\")),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", Tuple.Create(\"foo\"))\n        ];\n    }\n\n    public class Tuple8CopierTests(ITestOutputHelper output) : CopierTester<Tuple<string, string, string, string, string, string, string, Tuple<string>>, TupleCopier<string, string, string, string, string, string, string, Tuple<string>>>(output)\n    {\n        protected override Tuple<string, string, string, string, string, string, string, Tuple<string>> CreateValue() => new(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            new Tuple<string>(Guid.NewGuid().ToString()));\n\n        protected override Tuple<string, string, string, string, string, string, string, Tuple<string>>[] TestValues =>\n        [\n            null,\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(default, default, default, default, default, default, default, new Tuple<string>(default)),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\", Tuple.Create(\"foo\")),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\", Tuple.Create(\"8\")),\n            new Tuple<string, string, string, string, string, string, string, Tuple<string>>(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", Tuple.Create(\"foo\"))\n        ];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class ValueTupleTests(ITestOutputHelper output) : FieldCodecTester<ValueTuple, ValueTupleCodec>(output)\n    {\n        protected override ValueTuple CreateValue() => default;\n\n        protected override ValueTuple[] TestValues => [ default ];\n    }\n\n    public class ValueTupleCopierTests(ITestOutputHelper output) : CopierTester<ValueTuple, ValueTupleCopier>(output)\n    {\n        protected override ValueTuple CreateValue() => default;\n\n        protected override ValueTuple[] TestValues => [ default ];\n    }\n\n    public class ValueTuple1Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string>, ValueTupleCodec<string>>(output)\n    {\n        protected override ValueTuple<string> CreateValue() => ValueTuple.Create(Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create<string>(null),\n            ValueTuple.Create<string>(string.Empty),\n            ValueTuple.Create<string>(\"foobar\")\n        ];\n    }\n\n    public class ValueTuple1CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string>, ValueTupleCopier<string>>(output)\n    {\n        protected override ValueTuple<string> CreateValue() => ValueTuple.Create(Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create<string>(null),\n            ValueTuple.Create<string>(string.Empty),\n            ValueTuple.Create<string>(\"foobar\")\n        ];\n    }\n\n    public class ValueTuple2Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string>, ValueTupleCodec<string, string>>(output)\n    {\n        protected override ValueTuple<string, string> CreateValue() => ValueTuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create<string, string>(null, null),\n            ValueTuple.Create<string, string>(string.Empty, \"foo\"),\n            ValueTuple.Create<string, string>(\"foo\", \"bar\"),\n            ValueTuple.Create<string, string>(\"foo\", \"foo\"),\n        ];\n    }\n\n    public class ValueTuple2CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string>, ValueTupleCopier<string, string>>(output)\n    {\n        protected override ValueTuple<string, string> CreateValue() => ValueTuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create<string, string>(null, null),\n            ValueTuple.Create<string, string>(string.Empty, \"foo\"),\n            ValueTuple.Create<string, string>(\"foo\", \"bar\"),\n            ValueTuple.Create<string, string>(\"foo\", \"foo\"),\n        ];\n    }\n\n    public class ValueTuple3Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string, string>, ValueTupleCodec<string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple3CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string, string>, ValueTupleCopier<string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple4Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string, string, string>, ValueTupleCodec<string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple4CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string, string, string>, ValueTupleCopier<string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple5Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string, string, string, string>, ValueTupleCodec<string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty,string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple5CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string, string, string, string>, ValueTupleCopier<string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty,string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple6Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string,string, string, string, string>, ValueTupleCodec<string, string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple6CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string,string, string, string, string>, ValueTupleCopier<string, string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple7Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string, string, string, string, string, string>, ValueTupleCodec<string, string, string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple7opierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string, string, string, string, string, string>, ValueTupleCopier<string, string, string, string, string, string, string>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string, string> CreateValue() => ValueTuple.Create(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString());\n\n        protected override ValueTuple<string, string, string, string, string, string, string>[] TestValues =>\n        [\n            default,\n            ValueTuple.Create(default(string), default(string), default(string), default(string), default(string), default(string), default(string)),\n            ValueTuple.Create(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\"),\n            ValueTuple.Create(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\"),\n            ValueTuple.Create(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\")\n        ];\n    }\n\n    public class ValueTuple8Tests(ITestOutputHelper output) : FieldCodecTester<ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>, ValueTupleCodec<string, string, string, string, string, string, string, ValueTuple<string>>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>> CreateValue() => new(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            ValueTuple.Create(Guid.NewGuid().ToString()));\n\n        protected override ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>[] TestValues =>\n        [\n            default,\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(default, default, default, default, default, default, default, ValueTuple.Create(default(string))),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\", ValueTuple.Create(\"foo\")),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\", ValueTuple.Create(\"8\")),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", ValueTuple.Create(\"foo\"))\n        ];\n    }\n\n    public class ValueTuple8CopierTests(ITestOutputHelper output) : CopierTester<ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>, ValueTupleCopier<string, string, string, string, string, string, string, ValueTuple<string>>>(output)\n    {\n        protected override ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>> CreateValue() => new(\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            Guid.NewGuid().ToString(),\n            ValueTuple.Create(Guid.NewGuid().ToString()));\n\n        protected override ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>[] TestValues =>\n        [\n            default,\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(default, default, default, default, default, default, default, ValueTuple.Create(default(string))),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, \"foo\", ValueTuple.Create(\"foo\")),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(\"foo\", \"bar\", \"baz\", \"4\", \"5\", \"6\", \"7\", ValueTuple.Create(\"8\")),\n            new ValueTuple<string, string, string, string, string, string, string, ValueTuple<string>>(\"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", \"foo\", ValueTuple.Create(\"foo\"))\n        ];\n    }\n\n    public class BoolCodecTests(ITestOutputHelper output) : FieldCodecTester<bool, BoolCodec>(output)\n    {\n        protected override bool CreateValue() => true;\n        protected override bool Equals(bool left, bool right) => left == right;\n        protected override bool[] TestValues => [false, true];\n    }\n\n    public class BoolCopierTests(ITestOutputHelper output) : CopierTester<bool, IDeepCopier<bool>>(output)\n    {\n        protected override bool CreateValue() => true;\n        protected override bool Equals(bool left, bool right) => left == right;\n        protected override bool[] TestValues => [false, true];\n    }\n\n    public class StringCodecTests(ITestOutputHelper output) : FieldCodecTester<string, StringCodec>(output)\n    {\n        protected override string CreateValue() => Guid.NewGuid().ToString();\n        protected override bool Equals(string left, string right) => StringComparer.Ordinal.Equals(left, right);\n        protected override string[] TestValues => [null, string.Empty, new string('*', 6), new string('x', 4097), \"Hello, World!\"];\n    }\n\n    public class StringCopierTests(ITestOutputHelper output) : CopierTester<string, IDeepCopier<string>>(output)\n    {\n        protected override string CreateValue() => Guid.NewGuid().ToString();\n        protected override bool Equals(string left, string right) => StringComparer.Ordinal.Equals(left, right);\n        protected override string[] TestValues => [null, string.Empty, new string('*', 6), new string('x', 4097), \"Hello, World!\"];\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class ObjectCodecTests(ITestOutputHelper output) : FieldCodecTester<object, ObjectCodec>(output)\n    {\n        protected override object CreateValue() => new();\n        protected override bool Equals(object left, object right) => ReferenceEquals(left, right) || typeof(object) == left?.GetType() && typeof(object) == right?.GetType();\n        protected override object[] TestValues => [null, new object()];\n    }\n\n    public class ObjectCopierTests(ITestOutputHelper output) : CopierTester<object, ObjectCopier>(output)\n    {\n        protected override object CreateValue() => new();\n        protected override bool Equals(object left, object right) => ReferenceEquals(left, right) || typeof(object) == left?.GetType() && typeof(object) == right?.GetType();\n        protected override object[] TestValues => [null, new object()];\n        protected override bool IsImmutable => true;\n    }\n\n    public class BitArrayCodecTests(ITestOutputHelper output) : FieldCodecTester<BitArray, BitArrayCodec>(output)\n    {\n        protected override BitArray CreateValue() => new BitArray(Guid.NewGuid().ToByteArray());\n\n        protected override bool Equals(BitArray left, BitArray right) => ReferenceEquals(left, right) || left.Length == right.Length && Enumerable.Range(0, left.Length).All(i => left[i] == right[i]);\n\n        protected override BitArray[] TestValues =>\n        [\n            null,\n            new BitArray(0, false),\n            new BitArray(Enumerable.Range(0, Random.Next(4097)).Select(b => unchecked((byte)b)).ToArray()),\n            CreateValue(),\n        ];\n    }\n\n    public class BitArrayCopierTests(ITestOutputHelper output) : CopierTester<BitArray, BitArrayCopier>(output)\n    {\n        protected override BitArray CreateValue() => new BitArray(Guid.NewGuid().ToByteArray());\n\n        protected override bool Equals(BitArray left, BitArray right) => ReferenceEquals(left, right) || left.Length == right.Length && Enumerable.Range(0, left.Length).All(i => left[i] == right[i]);\n\n        protected override BitArray[] TestValues =>\n        [\n            null,\n            new BitArray(0, false),\n            new BitArray(Enumerable.Range(0, Random.Next(4097)).Select(b => unchecked((byte)b)).ToArray()),\n            CreateValue(),\n        ];\n    }\n\n    public class ByteArrayCodecTests(ITestOutputHelper output) : FieldCodecTester<byte[], ByteArrayCodec>(output)\n    {\n        protected override byte[] CreateValue() => Guid.NewGuid().ToByteArray();\n\n        protected override bool Equals(byte[] left, byte[] right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n\n        protected override byte[][] TestValues =>\n        [\n            null,\n            Array.Empty<byte>(),\n            Enumerable.Range(0, 4097).Select(b => unchecked((byte)b)).ToArray(), CreateValue(),\n        ];\n    }\n\n    public class ByteArrayCopierTests(ITestOutputHelper output) : CopierTester<byte[], ByteArrayCopier>(output)\n    {\n        protected override byte[] CreateValue() => Guid.NewGuid().ToByteArray();\n\n        protected override bool Equals(byte[] left, byte[] right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n\n        protected override byte[][] TestValues =>\n        [\n            null,\n            Array.Empty<byte>(),\n            Enumerable.Range(0, 4097).Select(b => unchecked((byte)b)).ToArray(), CreateValue(),\n        ];\n    }\n\n    public class MemoryCodecTests(ITestOutputHelper output) : FieldCodecTester<Memory<int>, MemoryCodec<int>>(output)\n    {\n        protected override Memory<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new Memory<int>(array, start, len);\n        }\n\n        protected override bool Equals(Memory<int> left, Memory<int> right) => left.Span.SequenceEqual(right.Span);\n        protected override Memory<int>[] TestValues => [default, new Memory<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class MemoryCopierTests(ITestOutputHelper output) : CopierTester<Memory<int>, MemoryCopier<int>>(output)\n    {\n        protected override Memory<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new Memory<int>(array, start, len);\n        }\n\n        protected override bool Equals(Memory<int> left, Memory<int> right) => left.Span.SequenceEqual(right.Span);\n        protected override Memory<int>[] TestValues => [default, new Memory<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ReadOnlyMemoryCodecTests(ITestOutputHelper output) : FieldCodecTester<ReadOnlyMemory<int>, ReadOnlyMemoryCodec<int>>(output)\n    {\n        protected override ReadOnlyMemory<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new ReadOnlyMemory<int>(array, start, len);\n        }\n\n        protected override bool Equals(ReadOnlyMemory<int> left, ReadOnlyMemory<int> right) => left.Span.SequenceEqual(right.Span);\n        protected override ReadOnlyMemory<int>[] TestValues => [default, new ReadOnlyMemory<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ReadOnlyMemoryCopierTests(ITestOutputHelper output) : CopierTester<ReadOnlyMemory<int>, ReadOnlyMemoryCopier<int>>(output)\n    {\n        protected override ReadOnlyMemory<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new ReadOnlyMemory<int>(array, start, len);\n        }\n\n        protected override bool Equals(ReadOnlyMemory<int> left, ReadOnlyMemory<int> right) => left.Span.SequenceEqual(right.Span);\n        protected override ReadOnlyMemory<int>[] TestValues => [default, new ReadOnlyMemory<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArraySegmentCodecTests(ITestOutputHelper output) : FieldCodecTester<ArraySegment<int>, ArraySegmentCodec<int>>(output)\n    {\n        protected override ArraySegment<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new ArraySegment<int>(array, start, len);\n        }\n\n        protected override bool Equals(ArraySegment<int> left, ArraySegment<int> right) => left.SequenceEqual(right);\n        protected override ArraySegment<int>[] TestValues => [default, new ArraySegment<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArraySegmentCopierTests(ITestOutputHelper output) : CopierTester<ArraySegment<int>, ArraySegmentCopier<int>>(output)\n    {\n        protected override ArraySegment<int> CreateValue()\n        {\n            var array = Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n            var start = Random.Next(array.Length);\n            var len = Random.Next(array.Length - start);\n            return new ArraySegment<int>(array, start, len);\n        }\n\n        protected override bool Equals(ArraySegment<int> left, ArraySegment<int> right) => left.SequenceEqual(right);\n        protected override ArraySegment<int>[] TestValues => [default, new ArraySegment<int>([], 0, 0), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArrayCodecTests(ITestOutputHelper output) : FieldCodecTester<int[], ArrayCodec<int>>(output)\n    {\n        protected override int[] CreateValue() => Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n        protected override bool Equals(int[] left, int[] right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override int[][] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArrayCopierTests(ITestOutputHelper output) : CopierTester<int[], ArrayCopier<int>>(output)\n    {\n        protected override int[] CreateValue() => Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToArray();\n        protected override bool Equals(int[] left, int[] right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override int[][] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableArrayCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableArray<int>, ImmutableArrayCodec<int>>(output)\n    {\n        protected override ImmutableArray<int> CreateValue() => Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToImmutableArray();\n        protected override bool Equals(ImmutableArray<int> left, ImmutableArray<int> right) => (left.IsDefault && right.IsDefault) || left.SequenceEqual(right);\n        protected override ImmutableArray<int>[] TestValues => [default, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableArrayCopierTests(ITestOutputHelper output) : CopierTester<ImmutableArray<int>, ImmutableArrayCopier<int>>(output)\n    {\n        protected override ImmutableArray<int> CreateValue() => Enumerable.Range(0, Random.Next(120) + 50).Select(_ => Guid.NewGuid().GetHashCode()).ToImmutableArray();\n        protected override bool Equals(ImmutableArray<int> left, ImmutableArray<int> right) => (left.IsDefault && right.IsDefault) || left.SequenceEqual(right);\n        protected override ImmutableArray<int>[] TestValues => [default, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class PooledBufferCodecTests(ITestOutputHelper output) : FieldCodecTester<PooledBuffer, PooledBufferCodec>(output)\n    {\n        protected override PooledBuffer CreateValue()\n        {\n            var result = new PooledBuffer();\n            var len = 1 + Random.Next(5765);\n            var remaining = len;\n            while (remaining > 0)\n            {\n                var chunk = result.GetSpan(0);\n                var buf = chunk[..Math.Min(chunk.Length, remaining)];\n                Random.NextBytes(buf);\n                remaining -= buf.Length;\n                result.Advance(buf.Length);\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(PooledBuffer left, PooledBuffer right) => left.ToArray().SequenceEqual(right.ToArray());\n        protected override PooledBuffer[] TestValues => [default, CreateValue(), CreateValue(), CreateValue()];\n        protected override PooledBuffer GetWriteCopy(PooledBuffer input)\n        {\n            var result = new PooledBuffer();\n            result.Write(input.ToArray());\n            return result;\n        }\n    }\n\n    public class PooledBufferCopierTests(ITestOutputHelper output) : CopierTester<PooledBuffer, PooledBufferCopier>(output)\n    {\n        protected override bool IsImmutable => true;\n\n        protected override bool IsPooled => true;\n\n        protected override PooledBuffer CreateValue()\n        {\n            var result = new PooledBuffer();\n            var len = Random.Next(8765);\n            var remaining = len;\n            while (remaining > 0)\n            {\n                var chunk = result.GetSpan(0);\n                var chunkLen = Math.Min(chunk.Length, remaining);\n                var buf = chunk[..chunkLen];\n                Random.NextBytes(buf);\n                remaining -= buf.Length;\n                result.Advance(buf.Length);\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(PooledBuffer left, PooledBuffer right) => left.ToArray().SequenceEqual(right.ToArray());\n        protected override PooledBuffer[] TestValues => [default, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n#if NET7_0_OR_GREATER\n    public class UInt128CodecTests(ITestOutputHelper output) : FieldCodecTester<UInt128, UInt128Codec>(output)\n    {\n        protected override UInt128 CreateValue() => new (unchecked((ulong)Random.NextInt64()), unchecked((ulong)Random.NextInt64()));\n\n        protected override UInt128[] TestValues =>\n        [\n            0,\n            1,\n            (UInt128)byte.MaxValue - 1,\n            byte.MaxValue,\n            (UInt128)byte.MaxValue + 1,\n            (UInt128)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (UInt128)ushort.MaxValue + 1,\n            (UInt128)uint.MaxValue - 1,\n            uint.MaxValue,\n            (UInt128)uint.MaxValue + 1,\n            UInt128.MaxValue,\n        ];\n\n        protected override Action<Action<UInt128>> ValueProvider => assert => Gen.ULong.Select(Gen.ULong).Sample(value => assert(new (value.Item1, value.Item2)));\n    }\n\n    public class UInt128CopierTests(ITestOutputHelper output) : CopierTester<UInt128, IDeepCopier<UInt128>>(output)\n    {\n        protected override UInt128 CreateValue() => new (unchecked((ulong)Random.NextInt64()), unchecked((ulong)Random.NextInt64()));\n\n        protected override UInt128[] TestValues =>\n        [\n            0,\n            1,\n            (UInt128)byte.MaxValue - 1,\n            byte.MaxValue,\n            (UInt128)byte.MaxValue + 1,\n            (UInt128)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (UInt128)ushort.MaxValue + 1,\n            (UInt128)uint.MaxValue - 1,\n            uint.MaxValue,\n            (UInt128)uint.MaxValue + 1,\n            UInt128.MaxValue,\n        ];\n\n        protected override Action<Action<UInt128>> ValueProvider => assert => Gen.ULong.Select(Gen.ULong).Sample(value => assert(new (value.Item1, value.Item2)));\n    }\n#endif\n\n    public class BigIntegerCodecTests(ITestOutputHelper output) : FieldCodecTester<BigInteger, BigIntegerCodec>(output)\n    {\n        // New behavior in .NET 9: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/9.0/biginteger-limit#new-behavior\n        protected override int[] MaxSegmentSizes => [(2^31)-1];\n\n        protected override BigInteger CreateValue()\n        {\n            var bytes = new byte[Random.Next(1, 100)];\n            Random.NextBytes(bytes);\n            return new BigInteger(bytes);\n        }\n\n        protected override BigInteger[] TestValues =>\n        [\n            BigInteger.Zero,\n            BigInteger.One,\n            BigInteger.MinusOne,\n            new BigInteger(byte.MaxValue),\n            new BigInteger(byte.MaxValue) + 1,\n            new BigInteger(ushort.MaxValue),\n            new BigInteger(ushort.MaxValue) + 1,\n            new BigInteger(uint.MaxValue),\n            new BigInteger(uint.MaxValue) + 1,\n            new BigInteger(ulong.MaxValue),\n            new BigInteger(ulong.MaxValue) + 1,\n#if NET7_0_OR_GREATER\n            (BigInteger)Int128.MaxValue,\n            (BigInteger)Int128.MaxValue + 1,\n            (BigInteger)UInt128.MaxValue,\n            (BigInteger)UInt128.MaxValue + 1,\n            -(BigInteger)Int128.MaxValue,\n            -(BigInteger)UInt128.MaxValue,\n#endif\n            -new BigInteger(byte.MaxValue),\n            -new BigInteger(ushort.MaxValue),\n            -new BigInteger(uint.MaxValue),\n            -new BigInteger(ulong.MaxValue),\n            BigInteger.Parse(\"123456789012345678901234567890123456789012345678901234567890\"),\n            BigInteger.Parse(\"-123456789012345678901234567890123456789012345678901234567890\"),\n        ];\n\n        protected override Action<Action<BigInteger>> ValueProvider => assert =>\n        {\n            Gen.Byte.Array.Sample(bytes =>\n            {\n                if (bytes.Length > 0)\n                {\n                    assert(new BigInteger(bytes));\n                }\n            });\n        };\n    }\n\n    public class BigIntegerCopierTests(ITestOutputHelper output) : CopierTester<BigInteger, ShallowCopier<BigInteger>>(output)\n    {\n        protected override bool IsImmutable => true;\n\n        protected override BigInteger CreateValue()\n        {\n            var bytes = new byte[Random.Next(1, 100)];\n            Random.NextBytes(bytes);\n            return new BigInteger(bytes);\n        }\n\n        protected override BigInteger[] TestValues =>\n        [\n            BigInteger.Zero,\n            BigInteger.One,\n            BigInteger.MinusOne,\n            new BigInteger(byte.MaxValue),\n            new BigInteger(byte.MaxValue) + 1,\n            new BigInteger(ushort.MaxValue),\n            new BigInteger(ushort.MaxValue) + 1,\n            new BigInteger(uint.MaxValue),\n            new BigInteger(uint.MaxValue) + 1,\n            new BigInteger(ulong.MaxValue),\n            new BigInteger(ulong.MaxValue) + 1,\n#if NET7_0_OR_GREATER\n            (BigInteger)Int128.MaxValue,\n            (BigInteger)Int128.MaxValue + 1,\n            (BigInteger)UInt128.MaxValue,\n            (BigInteger)UInt128.MaxValue + 1,\n#endif\n            -new BigInteger(byte.MaxValue),\n            -new BigInteger(ushort.MaxValue),\n            -new BigInteger(uint.MaxValue),\n            -new BigInteger(ulong.MaxValue),\n#if NET7_0_OR_GREATER\n            -(BigInteger)Int128.MaxValue,\n            -(BigInteger)UInt128.MaxValue,\n#endif\n            BigInteger.Parse(\"123456789012345678901234567890123456789012345678901234567890\"),\n            BigInteger.Parse(\"-123456789012345678901234567890123456789012345678901234567890\"),\n        ];\n\n        protected override Action<Action<BigInteger>> ValueProvider => assert =>\n        {\n            Gen.Byte.Array.Sample(bytes =>\n            {\n                if (bytes.Length > 0)\n                {\n                    assert(new BigInteger(bytes));\n                }\n            });\n        };\n    }\n\n    public class UInt64CodecTests(ITestOutputHelper output) : FieldCodecTester<ulong, UInt64Codec>(output)\n    {\n        protected override ulong CreateValue()\n        {\n            var msb = (ulong)Guid.NewGuid().GetHashCode() << 32;\n            var lsb = (ulong)Guid.NewGuid().GetHashCode();\n            return msb | lsb;\n        }\n\n        protected override ulong[] TestValues => new ulong[]\n        {\n            0,\n            1,\n            (ulong)byte.MaxValue - 1,\n            byte.MaxValue,\n            (ulong)byte.MaxValue + 1,\n            (ulong)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (ulong)ushort.MaxValue + 1,\n            (ulong)uint.MaxValue - 1,\n            uint.MaxValue,\n            (ulong)uint.MaxValue + 1,\n            ulong.MaxValue,\n        }\n        .Concat(Enumerable.Range(1, 63).Select(i => 1ul << i))\n        .ToArray();\n\n\n        protected override Action<Action<ulong>> ValueProvider => Gen.ULong.ToValueProvider();\n    }\n\n    public class UInt64CopierTests(ITestOutputHelper output) : CopierTester<ulong, IDeepCopier<ulong>>(output)\n    {\n        protected override ulong CreateValue()\n        {\n            var msb = (ulong)Guid.NewGuid().GetHashCode() << 32;\n            var lsb = (ulong)Guid.NewGuid().GetHashCode();\n            return msb | lsb;\n        }\n\n        protected override ulong[] TestValues =>\n        [\n            0,\n            1,\n            (ulong)byte.MaxValue - 1,\n            byte.MaxValue,\n            (ulong)byte.MaxValue + 1,\n            (ulong)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (ulong)ushort.MaxValue + 1,\n            (ulong)uint.MaxValue - 1,\n            uint.MaxValue,\n            (ulong)uint.MaxValue + 1,\n            ulong.MaxValue,\n        ];\n\n        protected override Action<Action<ulong>> ValueProvider => Gen.ULong.ToValueProvider();\n    }\n\n    public class UInt32CodecTests(ITestOutputHelper output) : FieldCodecTester<uint, UInt32Codec>(output)\n    {\n        protected override uint CreateValue() => (uint)Guid.NewGuid().GetHashCode();\n\n        protected override uint[] TestValues => new uint[]\n        {\n            0,\n            1,\n            (uint)byte.MaxValue - 1,\n            byte.MaxValue,\n            (uint)byte.MaxValue + 1,\n            (uint)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (uint)ushort.MaxValue + 1,\n            uint.MaxValue,\n        }\n        .Concat(Enumerable.Range(1, 31).Select(i => 1u << i))\n        .ToArray();\n\n        protected override Action<Action<uint>> ValueProvider => Gen.UInt.ToValueProvider();\n    }\n\n    public class UInt32CopierTests(ITestOutputHelper output) : CopierTester<uint, IDeepCopier<uint>>(output)\n    {\n        protected override uint CreateValue() => (uint)Guid.NewGuid().GetHashCode();\n\n        protected override uint[] TestValues =>\n        [\n            0,\n            1,\n            (uint)byte.MaxValue - 1,\n            byte.MaxValue,\n            (uint)byte.MaxValue + 1,\n            (uint)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (uint)ushort.MaxValue + 1,\n            uint.MaxValue,\n        ];\n\n        protected override Action<Action<uint>> ValueProvider => Gen.UInt.ToValueProvider();\n    }\n\n    public class UInt16CodecTests(ITestOutputHelper output) : FieldCodecTester<ushort, UInt16Codec>(output)\n    {\n        protected override ushort CreateValue() => (ushort)Guid.NewGuid().GetHashCode();\n        protected override ushort[] TestValues =>\n        [\n            0,\n            1,\n            byte.MaxValue - 1,\n            byte.MaxValue,\n            byte.MaxValue + 1,\n            ushort.MaxValue - 1,\n            ushort.MaxValue,\n        ];\n\n        protected override Action<Action<ushort>> ValueProvider => Gen.UShort.ToValueProvider();\n    }\n\n    public class UInt16CopierTests(ITestOutputHelper output) : CopierTester<ushort, IDeepCopier<ushort>>(output)\n    {\n        protected override ushort CreateValue() => (ushort)Guid.NewGuid().GetHashCode();\n        protected override ushort[] TestValues =>\n        [\n            0,\n            1,\n            byte.MaxValue - 1,\n            byte.MaxValue,\n            byte.MaxValue + 1,\n            ushort.MaxValue - 1,\n            ushort.MaxValue,\n        ];\n\n        protected override Action<Action<ushort>> ValueProvider => Gen.UShort.ToValueProvider();\n    }\n\n    public class ByteCodecTests(ITestOutputHelper output) : FieldCodecTester<byte, ByteCodec>(output)\n    {\n        protected override byte CreateValue() => (byte)Guid.NewGuid().GetHashCode();\n        protected override byte[] TestValues => [0, 1, byte.MaxValue - 1, byte.MaxValue];\n\n        protected override Action<Action<byte>> ValueProvider => Gen.Byte.ToValueProvider();\n    }\n\n    public class ByteCopierTests(ITestOutputHelper output) : CopierTester<byte, IDeepCopier<byte>>(output)\n    {\n        protected override byte CreateValue() => (byte)Guid.NewGuid().GetHashCode();\n        protected override byte[] TestValues => [0, 1, byte.MaxValue - 1, byte.MaxValue];\n\n        protected override Action<Action<byte>> ValueProvider => Gen.Byte.ToValueProvider();\n    }\n\n#if NET7_0_OR_GREATER\n    public class Int128CodecTests(ITestOutputHelper output) : FieldCodecTester<Int128, Int128Codec>(output)\n    {\n        protected override Int128 CreateValue() => new (unchecked((ulong)Random.NextInt64()), unchecked((ulong)Random.NextInt64()));\n\n        protected override Int128[] TestValues =>\n        [\n            0,\n            1,\n            (Int128)byte.MaxValue - 1,\n            byte.MaxValue,\n            (Int128)byte.MaxValue + 1,\n            (Int128)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (Int128)ushort.MaxValue + 1,\n            (Int128)uint.MaxValue - 1,\n            uint.MaxValue,\n            (Int128)uint.MaxValue + 1,\n            Int128.MaxValue,\n        ];\n\n        protected override Action<Action<Int128>> ValueProvider => assert => Gen.ULong.Select(Gen.ULong).Sample(value => assert(new (value.Item1, value.Item2)));\n    }\n\n    public class Int128CopierTests(ITestOutputHelper output) : CopierTester<Int128, IDeepCopier<Int128>>(output)\n    {\n        protected override Int128 CreateValue() => new Int128(unchecked((ulong)Random.NextInt64()), unchecked((ulong)Random.NextInt64()));\n\n        protected override Int128[] TestValues =>\n        [\n            0,\n            1,\n            (Int128)byte.MaxValue - 1,\n            byte.MaxValue,\n            (Int128)byte.MaxValue + 1,\n            (Int128)ushort.MaxValue - 1,\n            ushort.MaxValue,\n            (Int128)ushort.MaxValue + 1,\n            (Int128)uint.MaxValue - 1,\n            uint.MaxValue,\n            (Int128)uint.MaxValue + 1,\n            Int128.MaxValue,\n        ];\n\n        protected override Action<Action<Int128>> ValueProvider => assert => Gen.ULong.Select(Gen.ULong).Sample(value => assert(new (value.Item1, value.Item2)));\n    }\n#endif\n\n    public class Int64CodecTests(ITestOutputHelper output) : FieldCodecTester<long, Int64Codec>(output)\n    {\n        protected override long CreateValue()\n        {\n            var msb = (ulong)Guid.NewGuid().GetHashCode() << 32;\n            var lsb = (ulong)Guid.NewGuid().GetHashCode();\n            return (long)(msb | lsb);\n        }\n\n        protected override long[] TestValues =>\n        [\n            long.MinValue,\n            -1,\n            0,\n            1,\n            (long)sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            (long)sbyte.MaxValue + 1,\n            (long)short.MaxValue - 1,\n            short.MaxValue,\n            (long)short.MaxValue + 1,\n            (long)int.MaxValue - 1,\n            int.MaxValue,\n            (long)int.MaxValue + 1,\n            long.MaxValue,\n        ];\n\n        protected override Action<Action<long>> ValueProvider => Gen.Long.ToValueProvider();\n    }\n\n    public class Int64CopierTests(ITestOutputHelper output) : CopierTester<long, IDeepCopier<long>>(output)\n    {\n        protected override long CreateValue()\n        {\n            var msb = (ulong)Guid.NewGuid().GetHashCode() << 32;\n            var lsb = (ulong)Guid.NewGuid().GetHashCode();\n            return (long)(msb | lsb);\n        }\n\n        protected override long[] TestValues =>\n        [\n            long.MinValue,\n            -1,\n            0,\n            1,\n            (long)sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            (long)sbyte.MaxValue + 1,\n            (long)short.MaxValue - 1,\n            short.MaxValue,\n            (long)short.MaxValue + 1,\n            (long)int.MaxValue - 1,\n            int.MaxValue,\n            (long)int.MaxValue + 1,\n            long.MaxValue,\n        ];\n\n        protected override Action<Action<long>> ValueProvider => Gen.Long.ToValueProvider();\n    }\n\n    public class Int32CodecTests(ITestOutputHelper output) : FieldCodecTester<int, Int32Codec>(output)\n    {\n        protected override int CreateValue() => Guid.NewGuid().GetHashCode();\n\n        protected override int[] TestValues =>\n        [\n            int.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            sbyte.MaxValue + 1,\n            short.MaxValue - 1,\n            short.MaxValue,\n            short.MaxValue + 1,\n            int.MaxValue - 1,\n            int.MaxValue,\n        ];\n\n        protected override Action<Action<int>> ValueProvider => Gen.Int.ToValueProvider();\n\n        [Fact]\n        public void CanRoundTripViaSerializer_WriteReadByteByByte()\n        {\n            var serializer = ServiceProvider.GetRequiredService<Serializer<int>>();\n\n            foreach (var original in TestValues)\n            {\n                var buffer = new TestMultiSegmentBufferWriter(maxAllocationSize: 8);\n\n                using var writerSession = SessionPool.GetSession();\n                var writer = Writer.Create(buffer, writerSession);\n                for (var i = 0; i < 5; i++)\n                {\n                    serializer.Serialize(original, ref writer);\n                }\n\n                writer.Commit();\n                using var readerSession = SessionPool.GetSession();\n                var reader = Reader.Create(buffer.GetReadOnlySequence(maxSegmentSize: 1), readerSession);\n                for (var i = 0; i < 5; i++)\n                {\n                    var deserialized = serializer.Deserialize(ref reader);\n\n                    Assert.True(Equals(original, deserialized), $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                }\n            }\n        }\n    }\n\n    public class Int32CopierTests(ITestOutputHelper output) : CopierTester<int, IDeepCopier<int>>(output)\n    {\n        protected override int CreateValue() => Guid.NewGuid().GetHashCode();\n\n        protected override int[] TestValues =>\n        [\n            int.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            sbyte.MaxValue + 1,\n            short.MaxValue - 1,\n            short.MaxValue,\n            short.MaxValue + 1,\n            int.MaxValue - 1,\n            int.MaxValue,\n        ];\n\n        protected override Action<Action<int>> ValueProvider => Gen.Int.ToValueProvider();\n    }\n\n    public class Int16CodecTests(ITestOutputHelper output) : FieldCodecTester<short, Int16Codec>(output)\n    {\n        protected override short CreateValue() => (short)Guid.NewGuid().GetHashCode();\n\n        protected override short[] TestValues =>\n        [\n            short.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            sbyte.MaxValue + 1,\n            short.MaxValue - 1,\n            short.MaxValue\n        ];\n\n        protected override Action<Action<short>> ValueProvider => Gen.Short.ToValueProvider();\n    }\n\n    public class Int16CopierTests(ITestOutputHelper output) : CopierTester<short, IDeepCopier<short>>(output)\n    {\n        protected override short CreateValue() => (short)Guid.NewGuid().GetHashCode();\n\n        protected override short[] TestValues =>\n        [\n            short.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue,\n            sbyte.MaxValue + 1,\n            short.MaxValue - 1,\n            short.MaxValue\n        ];\n\n        protected override Action<Action<short>> ValueProvider => Gen.Short.ToValueProvider();\n    }\n\n    public class SByteCodecTests(ITestOutputHelper output) : FieldCodecTester<sbyte, SByteCodec>(output)\n    {\n        protected override sbyte CreateValue() => (sbyte)Guid.NewGuid().GetHashCode();\n\n        protected override sbyte[] TestValues =>\n        [\n            sbyte.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue\n        ];\n\n        protected override Action<Action<sbyte>> ValueProvider => Gen.SByte.ToValueProvider();\n    }\n\n    public class SByteCopierTests(ITestOutputHelper output) : CopierTester<sbyte, IDeepCopier<sbyte>>(output)\n    {\n        protected override sbyte CreateValue() => (sbyte)Guid.NewGuid().GetHashCode();\n\n        protected override sbyte[] TestValues =>\n        [\n            sbyte.MinValue,\n            -1,\n            0,\n            1,\n            sbyte.MaxValue - 1,\n            sbyte.MaxValue\n        ];\n\n        protected override Action<Action<sbyte>> ValueProvider => Gen.SByte.ToValueProvider();\n    }\n\n    public class CharCodecTests(ITestOutputHelper output) : FieldCodecTester<char, CharCodec>(output)\n    {\n        private int _createValueCount;\n\n        protected override char CreateValue() => (char)('!' + _createValueCount++ % ('~' - '!'));\n        protected override char[] TestValues =>\n        [\n            (char)0,\n            (char)1,\n            (char)(byte.MaxValue - 1),\n            (char)byte.MaxValue,\n            (char)(byte.MaxValue + 1),\n            (char)(ushort.MaxValue - 1),\n            (char)ushort.MaxValue,\n        ];\n\n        protected override Action<Action<char>> ValueProvider => Gen.Char.ToValueProvider();\n    }\n\n    public class CharCopierTests(ITestOutputHelper output) : CopierTester<char, IDeepCopier<char>>(output)\n    {\n        private int _createValueCount;\n\n        protected override char CreateValue() => (char)('!' + _createValueCount++ % ('~' - '!'));\n        protected override char[] TestValues =>\n        [\n            (char)0,\n            (char)1,\n            (char)(byte.MaxValue - 1),\n            (char)byte.MaxValue,\n            (char)(byte.MaxValue + 1),\n            (char)(ushort.MaxValue - 1),\n            (char)ushort.MaxValue,\n        ];\n\n        protected override Action<Action<char>> ValueProvider => Gen.Char.ToValueProvider();\n    }\n\n    public class GuidCodecTests(ITestOutputHelper output) : FieldCodecTester<Guid, GuidCodec>(output)\n    {\n        protected override Guid CreateValue() => Guid.NewGuid();\n        protected override Guid[] TestValues =>\n        [\n            Guid.Empty,\n            Guid.Parse(\"4DEBD074-5DBB-45F6-ACB7-ED97D2AEE02F\"),\n            Guid.Parse(\"FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF\")\n        ];\n\n        protected override Action<Action<Guid>> ValueProvider => Gen.Guid.ToValueProvider();\n    }\n\n    public class GuidCopierTests(ITestOutputHelper output) : CopierTester<Guid, IDeepCopier<Guid>>(output)\n    {\n        protected override Guid CreateValue() => Guid.NewGuid();\n        protected override Guid[] TestValues =>\n        [\n            Guid.Empty,\n            Guid.Parse(\"4DEBD074-5DBB-45F6-ACB7-ED97D2AEE02F\"),\n            Guid.Parse(\"FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF\")\n        ];\n\n        protected override Action<Action<Guid>> ValueProvider => Gen.Guid.ToValueProvider();\n    }\n\n    public class TypeCodecTests(ITestOutputHelper output) : FieldCodecTester<Type, TypeSerializerCodec>(output)\n    {\n        private readonly Type[] _values =\n        [\n            null,\n            typeof(Dictionary<Guid, List<string>>),\n            typeof(Type).MakeByRefType(),\n            typeof(Guid),\n            typeof(int).MakePointerType(),\n            typeof(string[]),\n            typeof(string[,]),\n            typeof(string[,]).MakePointerType(),\n            typeof(string[,]).MakeByRefType(),\n            typeof(Dictionary<,>),\n            typeof(List<>),\n            typeof(string)\n        ];\n\n        private int _valueIndex;\n\n        protected override Type CreateValue() => _values[_valueIndex++ % _values.Length];\n        protected override Type[] TestValues => _values;\n    }\n\n    public class TypeCopierTests(ITestOutputHelper output) : CopierTester<Type, IDeepCopier<Type>>(output)\n    {\n        private readonly Type[] _values =\n        [\n            null,\n            typeof(Dictionary<Guid, List<string>>),\n            typeof(Type).MakeByRefType(),\n            typeof(Guid),\n            typeof(int).MakePointerType(),\n            typeof(string[]),\n            typeof(string[,]),\n            typeof(string[,]).MakePointerType(),\n            typeof(string[,]).MakeByRefType(),\n            typeof(Dictionary<,>),\n            typeof(List<>),\n            typeof(string)\n        ];\n\n        private int _valueIndex;\n\n        protected override Type CreateValue() => _values[_valueIndex++ % _values.Length];\n        protected override Type[] TestValues => _values;\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class FloatCodecTests(ITestOutputHelper output) : FieldCodecTester<float, FloatCodec>(output)\n    {\n        protected override float CreateValue() => float.MaxValue * (float)Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override float[] TestValues => [float.MinValue, 0, 1.0f, float.MaxValue];\n\n        protected override Action<Action<float>> ValueProvider => Gen.Float.ToValueProvider();\n    }\n\n    public class FloatCopierTests(ITestOutputHelper output) : CopierTester<float, IDeepCopier<float>>(output)\n    {\n        protected override float CreateValue() => float.MaxValue * (float)Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override float[] TestValues => [float.MinValue, 0, 1.0f, float.MaxValue];\n\n        protected override Action<Action<float>> ValueProvider => Gen.Float.ToValueProvider();\n    }\n\n#if NET5_0_OR_GREATER\n    public class HalfCodecTests(ITestOutputHelper output) : FieldCodecTester<Half, HalfCodec>(output)\n    {\n        protected override Half CreateValue() => (Half)BitConverter.UInt16BitsToHalf((ushort)Random.Next(ushort.MinValue, ushort.MaxValue));\n        protected override Half[] TestValues => [Half.MinValue, (Half)0, (Half)1.0f, Half.Tau, Half.E, Half.Epsilon, Half.MaxValue];\n\n        protected override Action<Action<Half>> ValueProvider => assert => Gen.UShort.Sample(value => assert(BitConverter.UInt16BitsToHalf(value)));\n    }\n\n    public class HalfCopierTests(ITestOutputHelper output) : CopierTester<Half, IDeepCopier<Half>>(output)\n    {\n        protected override Half CreateValue() => (Half)BitConverter.UInt16BitsToHalf((ushort)Random.Next(ushort.MinValue, ushort.MaxValue));\n        protected override Half[] TestValues => [Half.MinValue, (Half)0, (Half)1.0f, Half.Tau, Half.E, Half.Epsilon, Half.MaxValue];\n\n        protected override Action<Action<Half>> ValueProvider => assert => Gen.UShort.Sample(value => assert(BitConverter.UInt16BitsToHalf(value)));\n    }\n#endif\n\n    public class DoubleCodecTests(ITestOutputHelper output) : FieldCodecTester<double, DoubleCodec>(output)\n    {\n        protected override double CreateValue() => double.MaxValue * Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override double[] TestValues => [double.MinValue, 0, 1.0, double.MaxValue];\n\n        protected override Action<Action<double>> ValueProvider => Gen.Double.ToValueProvider();\n    }\n\n    public class DoubleCopierTests(ITestOutputHelper output) : CopierTester<double, IDeepCopier<double>>(output)\n    {\n        protected override double CreateValue() => double.MaxValue * Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override double[] TestValues => [double.MinValue, 0, 1.0, double.MaxValue];\n\n        protected override Action<Action<double>> ValueProvider => Gen.Double.ToValueProvider();\n    }\n\n    public class DecimalCodecTests(ITestOutputHelper output) : FieldCodecTester<decimal, DecimalCodec>(output)\n    {\n        protected override decimal CreateValue() => decimal.MaxValue * (decimal)Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override decimal[] TestValues => [decimal.MinValue, 0, 1.0M, decimal.MaxValue];\n        protected override Action<Action<decimal>> ValueProvider => Gen.Decimal.ToValueProvider();\n    }\n\n    public class DecimalCopierTests(ITestOutputHelper output) : CopierTester<decimal, IDeepCopier<decimal>>(output)\n    {\n        protected override decimal CreateValue() => decimal.MaxValue * (decimal)Random.NextDouble() * Math.Sign(Guid.NewGuid().GetHashCode());\n        protected override decimal[] TestValues => [decimal.MinValue, 0, 1.0M, decimal.MaxValue];\n        protected override Action<Action<decimal>> ValueProvider => Gen.Decimal.ToValueProvider();\n    }\n\n    public class ListCodecTests(ITestOutputHelper output) : FieldCodecTester<List<int>, ListCodec<int>>(output)\n    {\n        protected override List<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(List<int> left, List<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override List<int>[] TestValues => [null, new List<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    [GenerateSerializer]\n    public class TypeWithListBase : List<int>\n    {\n        public TypeWithListBase() : this(true) { }\n        public TypeWithListBase(bool addDefaultValue)\n        {\n            if (addDefaultValue)\n            {\n                this.Add(42);\n            }\n        }\n\n        [Id(0)]\n        public int OtherProperty { get; set; }\n\n        public override string ToString() => $\"[OtherProperty: {OtherProperty}, Values: [{string.Join(\", \", this)}]]\";\n    }\n\n    public class ListBaseCodecTests(ITestOutputHelper output) : FieldCodecTester<TypeWithListBase, IFieldCodec<TypeWithListBase>>(output)\n    {\n        private static TypeWithListBase AddValues(TypeWithListBase value)\n        {\n            value.Add(1);\n            value.Add(2);\n            value.Add(3);\n            return value;\n        }\n\n        protected override TypeWithListBase[] TestValues => [null, new(), new(addDefaultValue: false), new() { 15 }, AddValues(new() { OtherProperty = 123 })];\n\n        protected override TypeWithListBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n        protected override bool Equals(TypeWithListBase left, TypeWithListBase right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.OtherProperty == right.OtherProperty;\n    }\n\n    public class ListBaseCopierTests(ITestOutputHelper output) : CopierTester<TypeWithListBase, IDeepCopier<TypeWithListBase>>(output)\n    {\n        private static TypeWithListBase AddValues(TypeWithListBase value)\n        {\n            value.Add(1);\n            value.Add(2);\n            value.Add(3);\n            return value;\n        }\n\n        protected override TypeWithListBase[] TestValues => [null, new(), new(addDefaultValue: false), new() { 15 }, AddValues(new() { OtherProperty = 123 })];\n\n        protected override TypeWithListBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n        protected override bool Equals(TypeWithListBase left, TypeWithListBase right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.OtherProperty == right.OtherProperty;\n    }\n\n    public class ListCopierTests(ITestOutputHelper output) : CopierTester<List<int>, ListCopier<int>>(output)\n    {\n        protected override List<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(List<int> left, List<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override List<int>[] TestValues => [null, new List<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableListCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableList<int>, ImmutableListCodec<int>>(output)\n    {\n        protected override ImmutableList<int> CreateValue()\n        {\n            var result = ImmutableList.CreateBuilder<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override bool Equals(ImmutableList<int> left, ImmutableList<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableList<int>[] TestValues => [null, ImmutableList<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableListCopierTests(ITestOutputHelper output) : CopierTester<ImmutableList<int>, ImmutableListCopier<int>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override ImmutableList<int> CreateValue()\n        {\n            var result = ImmutableList.CreateBuilder<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override bool Equals(ImmutableList<int> left, ImmutableList<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableList<int>[] TestValues => [null, ImmutableList<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class SortedListCodecTests(ITestOutputHelper output) : FieldCodecTester<SortedList<int, string>, SortedListCodec<int, string>>(output)\n    {\n        protected override SortedList<int, string> CreateValue()\n        {\n            var result = new SortedList<int, string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val, val.ToString());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(SortedList<int, string> left, SortedList<int, string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override SortedList<int, string>[] TestValues => [null, new SortedList<int, string>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class SortedListCopierTests(ITestOutputHelper output) : CopierTester<SortedList<int, string>, SortedListCopier<int, string>>(output)\n    {\n        protected override SortedList<int, string> CreateValue()\n        {\n            var result = new SortedList<int, string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val, val.ToString());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(SortedList<int, string> left, SortedList<int, string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override SortedList<int, string>[] TestValues => [null, new SortedList<int, string>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class SortedSetCodecTests(ITestOutputHelper output) : FieldCodecTester<SortedSet<int>, SortedSetCodec<int>>(output)\n    {\n        protected override SortedSet<int> CreateValue()\n        {\n            var result = new SortedSet<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val);\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(SortedSet<int> left, SortedSet<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override SortedSet<int>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class SortedSetCopierTests(ITestOutputHelper output) : CopierTester<SortedSet<int>, SortedSetCopier<int>>(output)\n    {\n        protected override SortedSet<int> CreateValue()\n        {\n            var result = new SortedSet<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val);\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(SortedSet<int> left, SortedSet<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override SortedSet<int>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableSortedSetCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableSortedSet<int>, ImmutableSortedSetCodec<int>>(output)\n    {\n        protected override ImmutableSortedSet<int> CreateValue()\n        {\n            var result = ImmutableSortedSet.CreateBuilder<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val);\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override bool Equals(ImmutableSortedSet<int> left, ImmutableSortedSet<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableSortedSet<int>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableSortedSetCopierTests(ITestOutputHelper output) : CopierTester<ImmutableSortedSet<int>, ImmutableSortedSetCopier<int>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override ImmutableSortedSet<int> CreateValue()\n        {\n            var result = ImmutableSortedSet.CreateBuilder<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var val = Random.Next();\n                result.Add(val);\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override bool Equals(ImmutableSortedSet<int> left, ImmutableSortedSet<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableSortedSet<int>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArrayListCodecTests(ITestOutputHelper output) : FieldCodecTester<ArrayList, ArrayListCodec>(output)\n    {\n        protected override ArrayList CreateValue()\n        {\n            var result = new ArrayList();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(ArrayList left, ArrayList right) => ReferenceEquals(left, right) || left.ToArray().SequenceEqual(right.ToArray());\n        protected override ArrayList[] TestValues => [null, new ArrayList(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ArrayListCopierTests(ITestOutputHelper output) : CopierTester<ArrayList, ArrayListCopier>(output)\n    {\n        protected override ArrayList CreateValue()\n        {\n            var result = new ArrayList();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(ArrayList left, ArrayList right) => ReferenceEquals(left, right) || left.ToArray().SequenceEqual(right.ToArray());\n        protected override ArrayList[] TestValues => [null, new ArrayList(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class CollectionCodecTests(ITestOutputHelper output) : FieldCodecTester<Collection<int>, CollectionCodec<int>>(output)\n    {\n        protected override Collection<int> CreateValue()\n        {\n            var result = new Collection<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Collection<int> left, Collection<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Collection<int>[] TestValues => [null, new Collection<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class CollectionCopierTests(ITestOutputHelper output) : CopierTester<Collection<int>, CollectionCopier<int>>(output)\n    {\n        protected override Collection<int> CreateValue()\n        {\n            var result = new Collection<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Collection<int> left, Collection<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Collection<int>[] TestValues => [null, new Collection<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    [GenerateSerializer]\n    public class TypeWithCollectionBase : Collection<int>\n    {\n        public TypeWithCollectionBase() : this(true) { }\n        public TypeWithCollectionBase(bool addDefaultValue)\n        {\n            if (addDefaultValue)\n            {\n                this.Add(42);\n            }\n        }\n\n        [Id(0)]\n        public int OtherProperty { get; set; }\n\n        public override string ToString() => $\"[OtherProperty: {OtherProperty}, Values: [{string.Join(\", \", this)}]]\";\n    }\n\n    public class CollectionBaseCodecTests(ITestOutputHelper output) : FieldCodecTester<TypeWithCollectionBase, IFieldCodec<TypeWithCollectionBase>>(output)\n    {\n        private static TypeWithCollectionBase AddValues(TypeWithCollectionBase value)\n        {\n            value.Add(1);\n            value.Add(2);\n            value.Add(3);\n            return value;\n        }\n\n        protected override TypeWithCollectionBase[] TestValues => [null, new(), new(addDefaultValue: false), new() { 15 }, AddValues(new() { OtherProperty = 123 })];\n\n        protected override TypeWithCollectionBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n        protected override bool Equals(TypeWithCollectionBase left, TypeWithCollectionBase right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.OtherProperty == right.OtherProperty;\n    }\n\n    public class CollectionBaseCopierTests(ITestOutputHelper output) : CopierTester<TypeWithCollectionBase, IDeepCopier<TypeWithCollectionBase>>(output)\n    {\n        private static TypeWithCollectionBase AddValues(TypeWithCollectionBase value)\n        {\n            value.Add(1);\n            value.Add(2);\n            value.Add(3);\n            return value;\n        }\n\n        protected override TypeWithCollectionBase[] TestValues => [null, new(), new(addDefaultValue: false), new() { 15 }, AddValues(new() { OtherProperty = 123 })];\n\n        protected override TypeWithCollectionBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n        protected override bool Equals(TypeWithCollectionBase left, TypeWithCollectionBase right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.OtherProperty == right.OtherProperty;\n    }\n\n    public class ReadOnlyCollectionCodecTests(ITestOutputHelper output) : FieldCodecTester<ReadOnlyCollection<int>, ReadOnlyCollectionCodec<int>>(output)\n    {\n        protected override ReadOnlyCollection<int> CreateValue()\n        {\n            var result = new Collection<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return new ReadOnlyCollection<int>(result);\n        }\n\n        protected override bool Equals(ReadOnlyCollection<int> left, ReadOnlyCollection<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ReadOnlyCollection<int>[] TestValues => [null, new ReadOnlyCollection<int>([]), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ReadOnlyCollectionCopierTests(ITestOutputHelper output) : CopierTester<ReadOnlyCollection<int>, ReadOnlyCollectionCopier<int>>(output)\n    {\n        protected override ReadOnlyCollection<int> CreateValue()\n        {\n            var result = new Collection<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return new ReadOnlyCollection<int>(result);\n        }\n\n        protected override bool Equals(ReadOnlyCollection<int> left, ReadOnlyCollection<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ReadOnlyCollection<int>[] TestValues => [null, new ReadOnlyCollection<int>([]), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class StackCodecTests(ITestOutputHelper output) : FieldCodecTester<Stack<int>, StackCodec<int>>(output)\n    {\n        protected override Stack<int> CreateValue()\n        {\n            var result = new Stack<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Push(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Stack<int> left, Stack<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Stack<int>[] TestValues => [null, new Stack<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class StackCopierTests(ITestOutputHelper output) : CopierTester<Stack<int>, StackCopier<int>>(output)\n    {\n        protected override Stack<int> CreateValue()\n        {\n            var result = new Stack<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Push(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Stack<int> left, Stack<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Stack<int>[] TestValues => [null, new Stack<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableStackCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableStack<int>, ImmutableStackCodec<int>>(output)\n    {\n        protected override ImmutableStack<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return ImmutableStack.CreateRange(result);\n        }\n\n        protected override bool Equals(ImmutableStack<int> left, ImmutableStack<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableStack<int>[] TestValues => [null, ImmutableStack<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableStackCopierTests(ITestOutputHelper output) : CopierTester<ImmutableStack<int>, ImmutableStackCopier<int>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override ImmutableStack<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return ImmutableStack.CreateRange(result);\n        }\n\n        protected override bool Equals(ImmutableStack<int> left, ImmutableStack<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableStack<int>[] TestValues => [null, ImmutableStack<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class QueueCodecTests(ITestOutputHelper output) : FieldCodecTester<Queue<int>, QueueCodec<int>>(output)\n    {\n        protected override Queue<int> CreateValue()\n        {\n            var result = new Queue<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Enqueue(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Queue<int> left, Queue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Queue<int>[] TestValues => [null, new Queue<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class QueueCopierTests(ITestOutputHelper output) : CopierTester<Queue<int>, QueueCopier<int>>(output)\n    {\n        protected override Queue<int> CreateValue()\n        {\n            var result = new Queue<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Enqueue(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(Queue<int> left, Queue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override Queue<int>[] TestValues => [null, new Queue<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ConcurrentQueueCodecTests(ITestOutputHelper output) : FieldCodecTester<ConcurrentQueue<int>, ConcurrentQueueCodec<int>>(output)\n    {\n        protected override ConcurrentQueue<int> CreateValue()\n        {\n            var result = new ConcurrentQueue<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Enqueue(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(ConcurrentQueue<int> left, ConcurrentQueue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ConcurrentQueue<int>[] TestValues => [null, new ConcurrentQueue<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ConcurrentQueueCopierTests(ITestOutputHelper output) : CopierTester<ConcurrentQueue<int>, ConcurrentQueueCopier<int>>(output)\n    {\n        protected override ConcurrentQueue<int> CreateValue()\n        {\n            var result = new ConcurrentQueue<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Enqueue(Random.Next());\n            }\n\n            return result;\n        }\n\n        protected override bool Equals(ConcurrentQueue<int> left, ConcurrentQueue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ConcurrentQueue<int>[] TestValues => [null, new ConcurrentQueue<int>(), CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableQueueCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableQueue<int>, ImmutableQueueCodec<int>>(output)\n    {\n        protected override ImmutableQueue<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return ImmutableQueue.CreateRange<int>(result);\n        }\n\n        protected override bool Equals(ImmutableQueue<int> left, ImmutableQueue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableQueue<int>[] TestValues => [null, ImmutableQueue<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class ImmutableQueueCopierTests(ITestOutputHelper output) : CopierTester<ImmutableQueue<int>, ImmutableQueueCopier<int>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override ImmutableQueue<int> CreateValue()\n        {\n            var result = new List<int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result.Add(Random.Next());\n            }\n\n            return ImmutableQueue.CreateRange<int>(result);\n        }\n\n        protected override bool Equals(ImmutableQueue<int> left, ImmutableQueue<int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n        protected override ImmutableQueue<int>[] TestValues => [null, ImmutableQueue<int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n    }\n\n    public class DictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<Dictionary<string, int>, DictionaryCodec<string, int>>(output)\n    {\n        protected override Dictionary<string, int> CreateValue()\n        {\n            var result = new Dictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override Dictionary<string, int>[] TestValues => [null, new Dictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(Dictionary<string, int> left, Dictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class DictionaryCopierTests(ITestOutputHelper output) : CopierTester<Dictionary<string, int>, DictionaryCopier<string, int>>(output)\n    {\n        protected override Dictionary<string, int> CreateValue()\n        {\n            var result = new Dictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override Dictionary<string, int>[] TestValues => [null, new Dictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(Dictionary<string, int> left, Dictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    [GenerateSerializer]\n    public class TypeWithDictionaryBase : Dictionary<string, int>\n    {\n        public TypeWithDictionaryBase() : this(true) { }\n        public TypeWithDictionaryBase(bool addDefaultValue, IEqualityComparer<string> comparer = null) : base(comparer)\n        {\n            if (addDefaultValue)\n            {\n                this[\"kEY\"] = 1;\n                this[\"key\"] = 2;\n                this[\"Key\"] = 3;\n            }\n        }\n\n        [Id(0)]\n        public int OtherProperty { get; set; }\n\n        public override string ToString() => $\"[OtherProperty: {OtherProperty}, Values: [{string.Join(\", \", this.Select(kvp => $\"[{kvp.Key}] = '{kvp.Value}'\"))}]]\";\n    }\n\n    public class DictionaryBaseCodecTests(ITestOutputHelper output) : FieldCodecTester<TypeWithDictionaryBase, IFieldCodec<TypeWithDictionaryBase>>(output)\n    {\n        protected override TypeWithDictionaryBase[] TestValues =>\n        [\n            null,\n            new(),\n            new(addDefaultValue: true, StringComparer.OrdinalIgnoreCase),\n            new(addDefaultValue: false),\n            new(addDefaultValue: true, comparer: StringComparer.Ordinal),\n            new() { [\"foo\"] = 15 },\n            new() { [\"foo\"] = 15, OtherProperty = 123 }\n        ];\n\n        protected override TypeWithDictionaryBase CreateValue() => new() { OtherProperty = Random.Next() };\n        protected override bool Equals(TypeWithDictionaryBase left, TypeWithDictionaryBase right) =>\n            ReferenceEquals(left, right)\n            || left.SequenceEqual(right)\n            && left.OtherProperty == right.OtherProperty\n            && left.Comparer?.GetType() == right.Comparer?.GetType();\n    }\n\n    public class DictionaryBaseCopierTests(ITestOutputHelper output) : CopierTester<TypeWithDictionaryBase, IDeepCopier<TypeWithDictionaryBase>>(output)\n    {\n        protected override TypeWithDictionaryBase[] TestValues => [null, new(), new(addDefaultValue: false), new() { [\"foo\"] = 15 }, new() { [\"foo\"] = 15, OtherProperty = 123 }];\n\n        protected override TypeWithDictionaryBase CreateValue() => new() { OtherProperty = Random.Next() };\n        protected override bool Equals(TypeWithDictionaryBase left, TypeWithDictionaryBase right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.OtherProperty == right.OtherProperty;\n    }\n\n    public class DictionaryWithComparerCodecTests(ITestOutputHelper output) : FieldCodecTester<Dictionary<string, int>, DictionaryCodec<string, int>>(output)\n    {\n        protected override int[] MaxSegmentSizes => [1024];\n        private int _nextComparer;\n        private readonly IEqualityComparer<string>[] _comparers =\n        [\n            new CaseInsensitiveEqualityComparer(),\n#if NETCOREAPP3_1_OR_GREATER\n            StringComparer.Ordinal,\n            StringComparer.OrdinalIgnoreCase,\n            EqualityComparer<string>.Default,\n#endif\n#if NET6_0_OR_GREATER\n            StringComparer.InvariantCulture,\n            StringComparer.InvariantCultureIgnoreCase,\n            StringComparer.CurrentCulture,\n            StringComparer.CurrentCultureIgnoreCase,\n#endif\n        ];\n\n        protected override Dictionary<string, int> CreateValue()\n        {\n            var eqComparer = _comparers[_nextComparer++ % _comparers.Length];\n            var result = new Dictionary<string, int>(eqComparer);\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                var key = Guid.NewGuid().ToString();\n                result[key.ToLowerInvariant()] = Random.Next();\n                result[key.ToUpperInvariant()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override Dictionary<string, int>[] TestValues => [\n            null,\n            new Dictionary<string, int>(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue(),\n            CreateValue()\n        ];\n\n        protected override bool Equals(Dictionary<string, int> left, Dictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n\n        [GenerateSerializer]\n        public class CaseInsensitiveEqualityComparer : IEqualityComparer<string>\n        {\n            public bool Equals(string left, string right)\n            {\n                if (left == null && right == null)\n                {\n                    return true;\n                }\n                else if (left == null || right == null)\n                {\n                    return false;\n                }\n                else if (left.ToUpper() == right.ToUpper())\n                {\n                    return true;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n\n            public int GetHashCode(string s) => s.ToUpper().GetHashCode();\n        }\n    }\n\n    public class DictionaryWithComparerCopierTests(ITestOutputHelper output) : CopierTester<Dictionary<string, int>, DictionaryCopier<string, int>>(output)\n    {\n        protected override Dictionary<string, int> CreateValue()\n        {\n            var eqComparer = new DictionaryWithComparerCodecTests.CaseInsensitiveEqualityComparer();\n            var result = new Dictionary<string, int>(eqComparer);\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override Dictionary<string, int>[] TestValues => [null, new Dictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(Dictionary<string, int> left, Dictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right) && left.Comparer?.GetType() == right.Comparer?.GetType();\n    }\n\n    public class ConcurrentDictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<ConcurrentDictionary<string, int>, ConcurrentDictionaryCodec<string, int>>(output)\n    {\n        protected override ConcurrentDictionary<string, int> CreateValue()\n        {\n            var result = new ConcurrentDictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override ConcurrentDictionary<string, int>[] TestValues => [null, new ConcurrentDictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(ConcurrentDictionary<string, int> left, ConcurrentDictionary<string, int> right)\n        {\n            // Order of the key-value pairs in the return value may not match the order of the key-value pairs in the surrogate\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n            else if (left.Keys.Count != right.Keys.Count)\n            {\n                return false;\n            }\n\n            foreach (string k in left.Keys)\n            {\n                if (!(right.ContainsKey(k) && left[k] == right[k]))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n\n    public class ConcurrentDictionaryCopierTests(ITestOutputHelper output) : CopierTester<ConcurrentDictionary<string, int>, ConcurrentDictionaryCopier<string, int>>(output)\n    {\n        protected override ConcurrentDictionary<string, int> CreateValue()\n        {\n            var result = new ConcurrentDictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override ConcurrentDictionary<string, int>[] TestValues => [null, new ConcurrentDictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(ConcurrentDictionary<string, int> left, ConcurrentDictionary<string, int> right)\n        {\n            // Order of the key-value pairs in the return value may not match the order of the key-value pairs in the surrogate\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n            else if (left.Keys.Count != right.Keys.Count)\n            {\n                return false;\n            }\n\n            foreach (string k in left.Keys)\n            {\n                if (!(right.ContainsKey(k) && left[k] == right[k]))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n\n    public class ReadOnlyDictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<ReadOnlyDictionary<string, int>, ReadOnlyDictionaryCodec<string, int>>(output)\n    {\n        protected override ReadOnlyDictionary<string, int> CreateValue()\n        {\n            var dict = new Dictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                dict[Random.Next().ToString()] = Random.Next();\n            }\n\n            return new ReadOnlyDictionary<string, int>(dict);\n        }\n\n        protected override ReadOnlyDictionary<string, int>[] TestValues => [null, new ReadOnlyDictionary<string, int>(new Dictionary<string, int>()), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ReadOnlyDictionary<string, int> left, ReadOnlyDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class ReadOnlyDictionaryCopierTests(ITestOutputHelper output) : CopierTester<ReadOnlyDictionary<string, int>, ReadOnlyDictionaryCopier<string, int>>(output)\n    {\n        protected override ReadOnlyDictionary<string, int> CreateValue()\n        {\n            var dict = new Dictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                dict[Random.Next().ToString()] = Random.Next();\n            }\n\n            return new ReadOnlyDictionary<string, int>(dict);\n        }\n\n        protected override ReadOnlyDictionary<string, int>[] TestValues => [null, new ReadOnlyDictionary<string, int>(new Dictionary<string, int>()), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ReadOnlyDictionary<string, int> left, ReadOnlyDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class ImmutableDictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableDictionary<string, int>, ImmutableDictionaryCodec<string, int>>(output)\n    {\n        protected override ImmutableDictionary<string, int> CreateValue()\n        {\n            var result = ImmutableDictionary.CreateBuilder<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override ImmutableDictionary<string, int>[] TestValues => [null, ImmutableDictionary<string, int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ImmutableDictionary<string, int> left, ImmutableDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class ImmutableDictionaryCopierTests(ITestOutputHelper output) : CopierTester<ImmutableDictionary<string, int>, ImmutableDictionaryCopier<string, int>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override ImmutableDictionary<string, int> CreateValue()\n        {\n            var result = ImmutableDictionary.CreateBuilder<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override ImmutableDictionary<string, int>[] TestValues => [null, ImmutableDictionary<string, int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ImmutableDictionary<string, int> left, ImmutableDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class SortedDictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<SortedDictionary<string, int>, SortedDictionaryCodec<string, int>>(output)\n    {\n        protected override SortedDictionary<string, int> CreateValue()\n        {\n            var result = new SortedDictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override SortedDictionary<string, int>[] TestValues => [null, new SortedDictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(SortedDictionary<string, int> left, SortedDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class SortedDictionaryCopierTests(ITestOutputHelper output) : CopierTester<SortedDictionary<string, int>, SortedDictionaryCopier<string, int>>(output)\n    {\n        protected override SortedDictionary<string, int> CreateValue()\n        {\n            var result = new SortedDictionary<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result;\n        }\n\n        protected override SortedDictionary<string, int>[] TestValues => [null, new SortedDictionary<string, int>(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(SortedDictionary<string, int> left, SortedDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class ImmutableSortedDictionaryCodecTests(ITestOutputHelper output) : FieldCodecTester<ImmutableSortedDictionary<string, int>, ImmutableSortedDictionaryCodec<string, int>>(output)\n    {\n        protected override ImmutableSortedDictionary<string, int> CreateValue()\n        {\n            var result = ImmutableSortedDictionary.CreateBuilder<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override ImmutableSortedDictionary<string, int>[] TestValues => [null, ImmutableSortedDictionary<string, int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ImmutableSortedDictionary<string, int> left, ImmutableSortedDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class ImmutableSortedDictionaryCopierTests(ITestOutputHelper output) : CopierTester<ImmutableSortedDictionary<string, int>, ImmutableSortedDictionaryCopier<string, int>>(output)\n    {\n        protected override bool IsImmutable => true;\n\n        protected override ImmutableSortedDictionary<string, int> CreateValue()\n        {\n            var result = ImmutableSortedDictionary.CreateBuilder<string, int>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next();\n            }\n\n            return result.ToImmutable();\n        }\n\n        protected override ImmutableSortedDictionary<string, int>[] TestValues => [null, ImmutableSortedDictionary<string, int>.Empty, CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(ImmutableSortedDictionary<string, int> left, ImmutableSortedDictionary<string, int> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class NameValueCollectionCodecTests(ITestOutputHelper output) : FieldCodecTester<NameValueCollection, NameValueCollectionCodec>(output)\n    {\n        protected override NameValueCollection CreateValue()\n        {\n            var result = new NameValueCollection();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next().ToString();\n            }\n\n            return result;\n        }\n\n        protected override NameValueCollection[] TestValues => [null, new NameValueCollection(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(NameValueCollection left, NameValueCollection right) => ReferenceEquals(left, right)\n            || (left.AllKeys.OrderBy(key => key).SequenceEqual(right.AllKeys.OrderBy(key => key)) && left.AllKeys.All(key => string.Equals(left[key], right[key], StringComparison.Ordinal)));\n    }\n\n    public class NameValueCollectionCopierTests(ITestOutputHelper output) : CopierTester<NameValueCollection, NameValueCollectionCopier>(output)\n    {\n        protected override NameValueCollection CreateValue()\n        {\n            var result = new NameValueCollection();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                result[Random.Next().ToString()] = Random.Next().ToString();\n            }\n\n            return result;\n        }\n\n        protected override NameValueCollection[] TestValues => [null, new NameValueCollection(), CreateValue(), CreateValue(), CreateValue()];\n        protected override bool Equals(NameValueCollection left, NameValueCollection right) => ReferenceEquals(left, right)\n            || (left.AllKeys.OrderBy(key => key).SequenceEqual(right.AllKeys.OrderBy(key => key)) && left.AllKeys.All(key => string.Equals(left[key], right[key], StringComparison.Ordinal)));\n    }\n\n    public class IPAddressTests(ITestOutputHelper output) : FieldCodecTester<IPAddress, IPAddressCodec>(output)\n    {\n        protected override int[] MaxSegmentSizes => [32];\n\n        protected override IPAddress[] TestValues => [null, IPAddress.Any, IPAddress.IPv6Any, IPAddress.IPv6Loopback, IPAddress.IPv6None, IPAddress.Loopback, IPAddress.Parse(\"123.123.10.3\"), CreateValue()];\n\n        protected override IPAddress CreateValue()\n        {\n            byte[] bytes;\n            if (Random.Next(1) == 0)\n            {\n                bytes = new byte[4];\n            }\n            else\n            {\n                bytes = new byte[16];\n            }\n            Random.NextBytes(bytes);\n            return new IPAddress(bytes);\n        }\n    }\n\n    public class IPAddressCopierTests(ITestOutputHelper output) : CopierTester<IPAddress, IDeepCopier<IPAddress>>(output)\n    {\n        protected override IPAddress[] TestValues => [null, IPAddress.Any, IPAddress.IPv6Any, IPAddress.IPv6Loopback, IPAddress.IPv6None, IPAddress.Loopback, IPAddress.Parse(\"123.123.10.3\"), CreateValue()];\n\n        protected override IPAddress CreateValue()\n        {\n            byte[] bytes;\n            if (Random.Next(1) == 0)\n            {\n                bytes = new byte[4];\n            }\n            else\n            {\n                bytes = new byte[16];\n            }\n            Random.NextBytes(bytes);\n            return new IPAddress(bytes);\n        }\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class IPEndPointTests(ITestOutputHelper output) : FieldCodecTester<IPEndPoint, IPEndPointCodec>(output)\n    {\n        protected override int[] MaxSegmentSizes => [32];\n\n        protected override IPEndPoint[] TestValues =>\n           [null,\n            new(IPAddress.Any, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6Any, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6Loopback, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6None, Random.Next(ushort.MaxValue)),\n            new(IPAddress.Loopback, Random.Next(ushort.MaxValue)),\n            new(IPAddress.Parse(\"123.123.10.3\"), Random.Next(ushort.MaxValue)),\n            CreateValue()];\n\n        protected override IPEndPoint CreateValue()\n        {\n            byte[] bytes;\n            if (Random.Next(1) == 0)\n            {\n                bytes = new byte[4];\n            }\n            else\n            {\n                bytes = new byte[16];\n            }\n            Random.NextBytes(bytes);\n            return new IPEndPoint(new IPAddress(bytes), Random.Next((int)ushort.MaxValue));\n        }\n    }\n\n    public class IPEndPointCopierTests(ITestOutputHelper output) : CopierTester<IPEndPoint, IDeepCopier<IPEndPoint>>(output)\n    {\n        protected override IPEndPoint[] TestValues =>\n           [null,\n            new(IPAddress.Any, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6Any, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6Loopback, Random.Next(ushort.MaxValue)),\n            new(IPAddress.IPv6None, Random.Next(ushort.MaxValue)),\n            new(IPAddress.Loopback, Random.Next(ushort.MaxValue)),\n            new(IPAddress.Parse(\"123.123.10.3\"), Random.Next(ushort.MaxValue)),\n            CreateValue()];\n\n        protected override IPEndPoint CreateValue()\n        {\n            byte[] bytes;\n            if (Random.Next(1) == 0)\n            {\n                bytes = new byte[4];\n            }\n            else\n            {\n                bytes = new byte[16];\n            }\n            Random.NextBytes(bytes);\n            return new IPEndPoint(new IPAddress(bytes), Random.Next((int)ushort.MaxValue));\n        }\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class HashSetTests(ITestOutputHelper output) : FieldCodecTester<HashSet<string>, HashSetCodec<string>>(output)\n    {\n        protected override HashSet<string> CreateValue()\n        {\n            var result = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = result.Add(Random.Next().ToString());\n            }\n\n            return result;\n        }\n\n        protected override HashSet<string>[] TestValues => [null, new HashSet<string>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(HashSet<string> left, HashSet<string> right) => ReferenceEquals(left, right) || left.SetEquals(right);\n    }\n\n    public class HashSetCopierTests(ITestOutputHelper output) : CopierTester<HashSet<string>, HashSetCopier<string>>(output)\n    {\n        protected override HashSet<string> CreateValue()\n        {\n            var result = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = result.Add(Random.Next().ToString());\n            }\n\n            return result;\n        }\n\n        protected override HashSet<string>[] TestValues => [null, new HashSet<string>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(HashSet<string> left, HashSet<string> right) => ReferenceEquals(left, right) || left.SetEquals(right);\n    }\n\n    [GenerateSerializer]\n    public class TypeWithHashSetBase : HashSet<string>\n    {\n        public TypeWithHashSetBase() : this(true) { }\n        public TypeWithHashSetBase(bool addDefaultValue, IEqualityComparer<string> comparer = null) : base(comparer)\n        {\n            if (addDefaultValue)\n            {\n                this.Add(\"key\");\n                this.Add(\"kEY\");\n                this.Add(\"Key\");\n                this.Add(\"KEY\");\n            }\n        }\n\n        [Id(0)]\n        public int OtherProperty { get; set; }\n\n        public override string ToString() => $\"[OtherProperty: {OtherProperty}, Values: [{string.Join(\", \", this)}]]\";\n    }\n\n    public class HashSetBaseCodecTests(ITestOutputHelper output) : FieldCodecTester<TypeWithHashSetBase, IFieldCodec<TypeWithHashSetBase>>(output)\n    {\n        private static TypeWithHashSetBase AddValues(TypeWithHashSetBase value)\n        {\n            value.Add(\"one\");\n            value.Add(\"ONE\");\n            value.Add(\"two\");\n            value.Add(\"three\");\n            return value;\n        }\n\n        protected override TypeWithHashSetBase[] TestValues =>\n        [\n            null,\n            new(),\n            new(addDefaultValue: true, StringComparer.OrdinalIgnoreCase),\n            new(addDefaultValue: false),\n            new(addDefaultValue: true, comparer: StringComparer.Ordinal),\n            new() { \"foo\" },\n            AddValues(new() { OtherProperty = 123 })\n        ];\n\n        protected override TypeWithHashSetBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n        protected override bool Equals(TypeWithHashSetBase left, TypeWithHashSetBase right) =>\n            ReferenceEquals(left, right)\n            || left.SequenceEqual(right)\n            && left.OtherProperty == right.OtherProperty\n            && left?.Comparer == right?.Comparer;\n    }\n\n    public class HashSetBaseCopierTests(ITestOutputHelper output) : CopierTester<TypeWithHashSetBase, IDeepCopier<TypeWithHashSetBase>>(output)\n    {\n        private static TypeWithHashSetBase AddValues(TypeWithHashSetBase value)\n        {\n            value.Add(\"one\");\n            value.Add(\"ONE\");\n            value.Add(\"two\");\n            value.Add(\"three\");\n            return value;\n        }\n\n        protected override TypeWithHashSetBase[] TestValues =>\n        [\n            null,\n            new(),\n            new(addDefaultValue: true, StringComparer.OrdinalIgnoreCase),\n            new(addDefaultValue: false),\n            new(addDefaultValue: true, comparer: StringComparer.Ordinal),\n            new() { \"foo\" },\n            AddValues(new() { OtherProperty = 123 })\n        ];\n\n        protected override TypeWithHashSetBase CreateValue() => AddValues(new() { OtherProperty = Random.Next() });\n\n        protected override bool Equals(TypeWithHashSetBase left, TypeWithHashSetBase right) =>\n            ReferenceEquals(left, right)\n            || left.SequenceEqual(right)\n            && left.OtherProperty == right.OtherProperty\n            && left?.Comparer == right?.Comparer;\n    }\n\n    public class ImmutableHashSetTests(ITestOutputHelper output) : FieldCodecTester<ImmutableHashSet<string>, ImmutableHashSetCodec<string>>(output)\n    {\n        protected override ImmutableHashSet<string> CreateValue()\n        {\n            var hashSet = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = hashSet.Add(Random.Next().ToString());\n            }\n\n            return hashSet.ToImmutableHashSet();\n        }\n\n        protected override ImmutableHashSet<string>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(ImmutableHashSet<string> left, ImmutableHashSet<string> right) => ReferenceEquals(left, right) || left.SetEquals(right);\n    }\n\n    public class ImmutableHashSetCopierTests(ITestOutputHelper output) : CopierTester<ImmutableHashSet<string>, ImmutableHashSetCopier<string>>(output)\n    {\n        protected override ImmutableHashSet<string> CreateValue()\n        {\n            var hashSet = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = hashSet.Add(Random.Next().ToString());\n            }\n\n            return hashSet.ToImmutableHashSet();\n        }\n\n        protected override ImmutableHashSet<string>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(ImmutableHashSet<string> left, ImmutableHashSet<string> right) => ReferenceEquals(left, right) || left.SetEquals(right);\n\n        protected override bool IsImmutable => true;\n    }\n\n    public sealed class ImmutableHashSetMutableCopierTests(ITestOutputHelper output) : CopierTester<ImmutableHashSet<object>, ImmutableHashSetCopier<object>>(output)\n    {\n        protected override ImmutableHashSet<object> CreateValue()\n        {\n            var hashSet = new HashSet<object>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = hashSet.Add(Random.Next());\n            }\n\n            return hashSet.ToImmutableHashSet();\n        }\n\n        protected override ImmutableHashSet<object>[] TestValues => [null, [], CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(ImmutableHashSet<object> left, ImmutableHashSet<object> right) => ReferenceEquals(left, right) || left.SetEquals(right);\n\n        protected override bool IsImmutable => false;\n    }\n\n    public class UriTests(ITestOutputHelper output) : FieldCodecTester<Uri, UriCodec>(output)\n    {\n        protected override int[] MaxSegmentSizes => [128];\n        protected override Uri CreateValue() => new Uri($\"http://www.{Guid.NewGuid()}.com/\");\n\n        protected override Uri[] TestValues => [null, CreateValue(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(Uri left, Uri right) => ReferenceEquals(left, right) || left == right;\n    }\n\n    public class UriCopierTests(ITestOutputHelper output) : CopierTester<Uri, IDeepCopier<Uri>>(output)\n    {\n        protected override Uri CreateValue() => new Uri($\"http://www.{Guid.NewGuid()}.com/\");\n\n        protected override Uri[] TestValues => [null, CreateValue(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(Uri left, Uri right) => ReferenceEquals(left, right) || left == right;\n\n        protected override bool IsImmutable => true;\n    }\n\n    public class FSharpUnitTests(ITestOutputHelper output) : FieldCodecTester<Unit, FSharpUnitCodec>(output)\n    {\n        protected override Unit CreateValue() => null;\n        protected override Unit[] TestValues => [null];\n    }\n\n    public class FSharpUnitCopierTests(ITestOutputHelper output) : CopierTester<Unit, FSharpUnitCopier>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override Unit CreateValue() => null;\n        protected override Unit[] TestValues => [null];\n    }\n\n    public class FSharpOptionTests(ITestOutputHelper output) : FieldCodecTester<FSharpOption<Guid>, FSharpOptionCodec<Guid>>(output)\n    {\n        protected override FSharpOption<Guid>[] TestValues => [null, FSharpOption<Guid>.None, FSharpOption<Guid>.Some(Guid.Empty), FSharpOption<Guid>.Some(Guid.NewGuid())];\n\n        protected override FSharpOption<Guid> CreateValue() => FSharpOption<Guid>.Some(Guid.NewGuid());\n    }\n\n    public class FSharpOptionCopierTests(ITestOutputHelper output) : CopierTester<FSharpOption<Guid>, FSharpOptionCopier<Guid>>(output)\n    {\n        protected override FSharpOption<Guid>[] TestValues => [null, FSharpOption<Guid>.None, FSharpOption<Guid>.Some(Guid.Empty), FSharpOption<Guid>.Some(Guid.NewGuid())];\n\n        protected override FSharpOption<Guid> CreateValue() => FSharpOption<Guid>.Some(Guid.NewGuid());\n\n        protected override bool Equals(FSharpOption<Guid> left, FSharpOption<Guid> right) => ReferenceEquals(left, right) || left.GetType() == right.GetType() && left.Value.Equals(right.Value);\n    }\n\n    public class FSharpOptionTests2(ITestOutputHelper output) : FieldCodecTester<FSharpOption<object>, FSharpOptionCodec<object>>(output)\n    {\n        protected override FSharpOption<object>[] TestValues => [null, FSharpOption<object>.Some(null), FSharpOption<object>.None, FSharpOption<object>.Some(Guid.Empty), FSharpOption<object>.Some(Guid.NewGuid())];\n\n        protected override FSharpOption<object> CreateValue() => FSharpOption<object>.Some(Guid.NewGuid());\n    }\n\n    public class FSharpRefTests(ITestOutputHelper output) : FieldCodecTester<FSharpRef<Guid>, FSharpRefCodec<Guid>>(output)\n    {\n        protected override FSharpRef<Guid>[] TestValues => [null, new FSharpRef<Guid>(default), new FSharpRef<Guid>(Guid.Empty), new FSharpRef<Guid>(Guid.NewGuid())];\n\n        protected override FSharpRef<Guid> CreateValue() => new(Guid.NewGuid());\n\n        protected override bool Equals(FSharpRef<Guid> left, FSharpRef<Guid> right) => ReferenceEquals(left, right) || EqualityComparer<Guid>.Default.Equals(left.Value, right.Value);\n    }\n\n    public class FSharpRefCopierTests(ITestOutputHelper output) : CopierTester<FSharpRef<Guid>, FSharpRefCopier<Guid>>(output)\n    {\n        protected override FSharpRef<Guid>[] TestValues => [null, new FSharpRef<Guid>(default), new FSharpRef<Guid>(Guid.Empty), new FSharpRef<Guid>(Guid.NewGuid())];\n\n        protected override FSharpRef<Guid> CreateValue() => new(Guid.NewGuid());\n\n        protected override bool Equals(FSharpRef<Guid> left, FSharpRef<Guid> right) => ReferenceEquals(left, right) || left.GetType() == right.GetType() && left.Value.Equals(right.Value);\n    }\n\n    public class FSharpValueOptionTests(ITestOutputHelper output) : FieldCodecTester<FSharpValueOption<Guid>, FSharpValueOptionCodec<Guid>>(output)\n    {\n        protected override FSharpValueOption<Guid>[] TestValues => [default, FSharpValueOption<Guid>.None, FSharpValueOption<Guid>.Some(Guid.Empty), FSharpValueOption<Guid>.Some(Guid.NewGuid())];\n\n        protected override FSharpValueOption<Guid> CreateValue() => FSharpValueOption<Guid>.Some(Guid.NewGuid());\n    }\n\n    public class FSharpValueOptionCopierTests(ITestOutputHelper output) : CopierTester<FSharpValueOption<Guid>, FSharpValueOptionCopier<Guid>>(output)\n    {\n        protected override FSharpValueOption<Guid>[] TestValues => [default, FSharpValueOption<Guid>.None, FSharpValueOption<Guid>.Some(Guid.Empty), FSharpValueOption<Guid>.Some(Guid.NewGuid())];\n\n        protected override FSharpValueOption<Guid> CreateValue() => FSharpValueOption<Guid>.Some(Guid.NewGuid());\n\n        protected override bool Equals(FSharpValueOption<Guid> left, FSharpValueOption<Guid> right) => left.IsNone && right.IsNone || left.IsSome && right.IsSome && left.Value.Equals(right.Value);\n    }\n\n    public class FSharpResultTests(ITestOutputHelper output) : FieldCodecTester<FSharpResult<int, Guid>, FSharpResultCodec<int, Guid>>(output)\n    {\n        protected override FSharpResult<int, Guid>[] TestValues => [FSharpResult<int, Guid>.NewOk(-1), FSharpResult<int, Guid>.NewError(Guid.NewGuid())];\n\n        protected override FSharpResult<int, Guid> CreateValue() => FSharpResult<int, Guid>.NewOk(0);\n    }\n\n    public class FSharpChoice2Tests(ITestOutputHelper output) : FieldCodecTester<FSharpChoice<int, Guid>, FSharpChoiceCodec<int, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid>[] TestValues => [FSharpChoice<int, Guid>.NewChoice1Of2(-1), FSharpChoice<int, Guid>.NewChoice2Of2(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid> CreateValue() => FSharpChoice<int, Guid>.NewChoice1Of2(0);\n    }\n\n    public class FSharpChoice2CopierTests(ITestOutputHelper output) : CopierTester<FSharpChoice<int, Guid>, FSharpChoiceCopier<int, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid>[] TestValues => [FSharpChoice<int, Guid>.NewChoice1Of2(-1), FSharpChoice<int, Guid>.NewChoice2Of2(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid> CreateValue() => FSharpChoice<int, Guid>.NewChoice1Of2(0);\n    }\n\n    public class FSharpChoice3Tests(ITestOutputHelper output) : FieldCodecTester<FSharpChoice<int, Guid, Guid>, FSharpChoiceCodec<int, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid>.NewChoice1Of3(-1), FSharpChoice<int, Guid, Guid>.NewChoice3Of3(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid>.NewChoice1Of3(0);\n    }\n\n    public class FSharpChoice3CopierTests(ITestOutputHelper output) : CopierTester<FSharpChoice<int, Guid, Guid>, FSharpChoiceCopier<int, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid>.NewChoice1Of3(-1), FSharpChoice<int, Guid, Guid>.NewChoice3Of3(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid>.NewChoice1Of3(0);\n    }\n\n    public class FSharpChoice4Tests(ITestOutputHelper output) : FieldCodecTester<FSharpChoice<int, Guid, Guid, Guid>, FSharpChoiceCodec<int, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid>.NewChoice1Of4(-1), FSharpChoice<int, Guid, Guid, Guid>.NewChoice4Of4(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid>.NewChoice1Of4(0);\n    }\n\n    public class FSharpChoice4CopierTests(ITestOutputHelper output) : CopierTester<FSharpChoice<int, Guid, Guid, Guid>, FSharpChoiceCopier<int, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid>.NewChoice1Of4(-1), FSharpChoice<int, Guid, Guid, Guid>.NewChoice4Of4(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid>.NewChoice1Of4(0);\n    }\n\n    public class FSharpChoice5Tests(ITestOutputHelper output) : FieldCodecTester<FSharpChoice<int, Guid, Guid, Guid, Guid>, FSharpChoiceCodec<int, Guid, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice1Of5(-1), FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice5Of5(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice1Of5(0);\n    }\n\n    public class FSharpChoice5CopierTests(ITestOutputHelper output) : CopierTester<FSharpChoice<int, Guid, Guid, Guid, Guid>, FSharpChoiceCopier<int, Guid, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice1Of5(-1), FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice5Of5(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid, Guid>.NewChoice1Of5(0);\n    }\n\n    public class FSharpChoice6Tests(ITestOutputHelper output) : FieldCodecTester<FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>, FSharpChoiceCodec<int, Guid, Guid, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice1Of6(-1), FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice6Of6(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice1Of6(0);\n    }\n\n    public class FSharpChoice6CopierTests(ITestOutputHelper output) : CopierTester<FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>, FSharpChoiceCopier<int, Guid, Guid, Guid, Guid, Guid>>(output)\n    {\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>[] TestValues => [FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice1Of6(-1), FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice6Of6(Guid.NewGuid())];\n\n        protected override FSharpChoice<int, Guid, Guid, Guid, Guid, Guid> CreateValue() => FSharpChoice<int, Guid, Guid, Guid, Guid, Guid>.NewChoice1Of6(0);\n    }\n\n    public class FSharpSetTests(ITestOutputHelper output) : FieldCodecTester<FSharpSet<string>, FSharpSetCodec<string>>(output)\n    {\n        protected override FSharpSet<string> CreateValue()\n        {\n            var hashSet = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = hashSet.Add(Random.Next().ToString());\n            }\n\n            return SetModule.OfSeq(hashSet);\n        }\n\n        protected override FSharpSet<string>[] TestValues => [null, SetModule.Empty<string>(), new FSharpSet<string>(Array.Empty<string>()), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpSet<string> left, FSharpSet<string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class FSharpSetCopierTests(ITestOutputHelper output) : CopierTester<FSharpSet<string>, FSharpSetCopier<string>>(output)\n    {\n        protected override FSharpSet<string> CreateValue()\n        {\n            var hashSet = new HashSet<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                _ = hashSet.Add(Random.Next().ToString());\n            }\n\n            return SetModule.OfSeq(hashSet);\n        }\n\n        protected override FSharpSet<string>[] TestValues => [null, SetModule.Empty<string>(), new FSharpSet<string>(Array.Empty<string>()), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpSet<string> left, FSharpSet<string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class FSharpMapTests(ITestOutputHelper output) : FieldCodecTester<FSharpMap<string, string>, FSharpMapCodec<string, string>>(output)\n    {\n        protected override int[] MaxSegmentSizes => [128];\n\n        protected override FSharpMap<string, string> CreateValue()\n        {\n            var collection = new List<Tuple<string, string>>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                collection.Add(Tuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()));\n            }\n\n            return MapModule.OfSeq(collection);\n        }\n\n        protected override FSharpMap<string, string>[] TestValues => [null, MapModule.Empty<string, string>(), new FSharpMap<string, string>(Array.Empty<Tuple<string, string>>()), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpMap<string, string> left, FSharpMap<string, string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class FSharpMapCopierTests(ITestOutputHelper output) : CopierTester<FSharpMap<string, string>, FSharpMapCopier<string, string>>(output)\n    {\n        protected override FSharpMap<string, string> CreateValue()\n        {\n            var collection = new List<Tuple<string, string>>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                collection.Add(Tuple.Create(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()));\n            }\n\n            return MapModule.OfSeq(collection);\n        }\n\n        protected override FSharpMap<string, string>[] TestValues => [null, MapModule.Empty<string, string>(), new FSharpMap<string, string>(Array.Empty<Tuple<string, string>>()), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpMap<string, string> left, FSharpMap<string, string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class FSharpListTests(ITestOutputHelper output) : FieldCodecTester<FSharpList<string>, FSharpListCodec<string>>(output)\n    {\n        protected override FSharpList<string> CreateValue()\n        {\n            var list = new List<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                list.Add(Random.Next().ToString());\n            }\n\n            return ListModule.OfSeq(list);\n        }\n\n        protected override FSharpList<string>[] TestValues => [null, ListModule.Empty<string>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpList<string> left, FSharpList<string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class FSharpListCopierTests(ITestOutputHelper output) : CopierTester<FSharpList<string>, FSharpListCopier<string>>(output)\n    {\n        protected override FSharpList<string> CreateValue()\n        {\n            var list = new List<string>();\n            var len = Random.Next(17);\n            for (var i = 0; i < len + 5; i++)\n            {\n                list.Add(Random.Next().ToString());\n            }\n\n            return ListModule.OfSeq(list);\n        }\n\n        protected override FSharpList<string>[] TestValues => [null, ListModule.Empty<string>(), CreateValue(), CreateValue(), CreateValue()];\n\n        protected override bool Equals(FSharpList<string> left, FSharpList<string> right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n    }\n\n    public class CultureInfoTests(ITestOutputHelper output) : FieldCodecTester<CultureInfo, CultureInfoCodec>(output)\n    {\n        protected override CultureInfo CreateValue() => TestValues[Random.Next(TestValues.Length)];\n\n        protected override CultureInfo[] TestValues => [null, CultureInfo.CurrentCulture, CultureInfo.InvariantCulture, CultureInfo.GetCultureInfo(\"en-us\"), CultureInfo.GetCultureInfo(\"mn-MN\")];\n\n        protected override bool Equals(CultureInfo left, CultureInfo right) => ReferenceEquals(left, right) || left.Equals(right);\n    }\n\n    public class CultureInfoCopierTests(ITestOutputHelper output) : CopierTester<CultureInfo, IDeepCopier<CultureInfo>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override CultureInfo CreateValue() => TestValues[Random.Next(TestValues.Length)];\n\n        protected override CultureInfo[] TestValues => [null, CultureInfo.CurrentCulture, CultureInfo.InvariantCulture, CultureInfo.GetCultureInfo(\"en-us\"), CultureInfo.GetCultureInfo(\"mn-MN\")];\n\n        protected override bool Equals(CultureInfo left, CultureInfo right) => ReferenceEquals(left, right) || left.Equals(right);\n    }\n\n    public class CompareInfoTests(ITestOutputHelper output) : FieldCodecTester<CompareInfo, CompareInfoCodec>(output)\n    {\n        protected override CompareInfo CreateValue() => TestValues[Random.Next(TestValues.Length)];\n\n        protected override CompareInfo[] TestValues => [null, CultureInfo.CurrentCulture.CompareInfo, CultureInfo.InvariantCulture.CompareInfo, CompareInfo.GetCompareInfo(\"en-us\"), CompareInfo.GetCompareInfo(\"mn-MN\")];\n\n        protected override bool Equals(CompareInfo left, CompareInfo right) => ReferenceEquals(left, right) || left.Equals(right);\n    }\n\n    public class CompareInfoCopierTests(ITestOutputHelper output) : CopierTester<CompareInfo, IDeepCopier<CompareInfo>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override CompareInfo CreateValue() => TestValues[Random.Next(TestValues.Length)];\n\n        protected override CompareInfo[] TestValues => [null, CultureInfo.CurrentCulture.CompareInfo, CultureInfo.InvariantCulture.CompareInfo, CompareInfo.GetCompareInfo(\"en-us\"), CompareInfo.GetCompareInfo(\"mn-MN\")];\n\n        protected override bool Equals(CompareInfo left, CompareInfo right) => ReferenceEquals(left, right) || left.Equals(right);\n    }\n\n    public class ResponseCodecTests(ITestOutputHelper output) : FieldCodecTester<Response, IFieldCodec<Response>>(output)\n    {\n        protected override Response CreateValue() => Response.FromResult(Guid.NewGuid());\n\n        protected override Response[] TestValues =>\n        [\n            default,\n            Response.FromResult(156),\n            Response.FromResult(\"hello\"),\n            Response.FromException(new Exception(\"uhoh\")),\n        ];\n\n        protected override bool Equals(Response left, Response right)\n        {\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left.Exception is not null)\n            {\n                if (right.Exception is null)\n                {\n                    return false;\n                }\n\n                return string.Equals(left.Exception.Message, right.Exception.Message, StringComparison.Ordinal);\n            }\n\n            if (left.Result is null && right.Result is null)\n            {\n                return true;\n            }\n            else if (left.Result is null || right.Result is null)\n            {\n                return false;\n            }\n\n            return Equals(left.Result, right.Result);\n        }\n    }\n\n    public class ResponseCopierTests(ITestOutputHelper output) : CopierTester<Response, IDeepCopier<Response>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override bool IsPooled => true;\n\n        protected override Response CreateValue() => Response.FromResult(Guid.NewGuid().ToString());\n\n        protected override Response[] TestValues =>\n        [\n            default,\n            Response.Completed,\n            Response.FromResult(156),\n            Response.FromResult(\"hello\"),\n            Response.FromException(new Exception(\"uhoh\")),\n        ];\n\n        protected override bool Equals(Response left, Response right)\n        {\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left.Exception is not null)\n            {\n                if (right.Exception is null)\n                {\n                    return false;\n                }\n\n                return string.Equals(left.Exception.Message, right.Exception.Message, StringComparison.Ordinal);\n            }\n\n            if (left.Result is null && right.Result is null)\n            {\n                return true;\n            }\n            else if (left.Result is null || right.Result is null)\n            {\n                return false;\n            }\n\n            return Equals(left.Result, right.Result);\n        }\n    }\n\n    public class Response1CodecTests(ITestOutputHelper output) : FieldCodecTester<Response<int>, IFieldCodec<Response<int>>>(output)\n    {\n        protected override Response<int> CreateValue() => (Response<int>)Response.FromResult(Random.Next());\n\n        protected override Response<int>[] TestValues =>\n        [\n            default,\n            (Response<int>)Response.FromResult(156),\n        ];\n\n        protected override bool Equals(Response<int> left, Response<int> right)\n        {\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left.Exception is not null)\n            {\n                if (right.Exception is null)\n                {\n                    return false;\n                }\n\n                return string.Equals(left.Exception.Message, right.Exception.Message, StringComparison.Ordinal);\n            }\n\n            if (left.Result is null && right.Result is null)\n            {\n                return true;\n            }\n            else if (left.Result is null || right.Result is null)\n            {\n                return false;\n            }\n\n            return Equals(left.Result, right.Result);\n        }\n    }\n\n    public class Response1CopierTests(ITestOutputHelper output) : CopierTester<Response<int>, IDeepCopier<Response<int>>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override bool IsPooled => true;\n\n        protected override Response<int> CreateValue() => (Response<int>)Response.FromResult(Random.Next());\n\n        protected override Response<int>[] TestValues =>\n        [\n            default,\n            (Response<int>)Response.FromResult(156),\n        ];\n\n        protected override bool Equals(Response<int> left, Response<int> right)\n        {\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left.Exception is not null)\n            {\n                if (right.Exception is null)\n                {\n                    return false;\n                }\n\n                return string.Equals(left.Exception.Message, right.Exception.Message, StringComparison.Ordinal);\n            }\n\n            if (left.Result is null && right.Result is null)\n            {\n                return true;\n            }\n            else if (left.Result is null || right.Result is null)\n            {\n                return false;\n            }\n\n            return Equals(left.Result, right.Result);\n        }\n    }\n\n    public class ExceptionCodecTests(ITestOutputHelper output) : FieldCodecTester<Exception, ExceptionCodec>(output)\n    {\n        protected override Exception[] TestValues => [null, new Exception(\"hi\"), CreateValue()];\n        protected override int[] MaxSegmentSizes => [8096];\n\n        protected override Exception CreateValue()\n        {\n            try\n            {\n                throw new InvalidOperationException(\"ExpectedException\");\n            }\n            catch (Exception ex)\n            {\n                return ex;\n            }\n        }\n\n        protected override bool Equals(Exception left, Exception right)\n        {\n            // Validation for exceptions is light. They are generally transformed in some fashion as they are serialized and deserialized.\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return string.Equals(left.Message, right.Message, StringComparison.Ordinal);\n        }\n    }\n\n    public class ExceptionCopierTests(ITestOutputHelper output) : CopierTester<Exception, IDeepCopier<Exception>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override Exception[] TestValues => [null, new Exception(\"hi\"), CreateValue()];\n\n        protected override Exception CreateValue()\n        {\n            try\n            {\n                throw new InvalidOperationException(\"ExpectedException\");\n            }\n            catch (Exception ex)\n            {\n                return ex;\n            }\n        }\n\n        protected override bool Equals(Exception left, Exception right)\n        {\n            // Validation for exceptions is light. They are generally transformed in some fashion as they are serialized and deserialized.\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return string.Equals(left.Message, right.Message, StringComparison.Ordinal);\n        }\n    }\n\n    public class AggregateExceptionCodecTests(ITestOutputHelper output) : FieldCodecTester<AggregateException, IFieldCodec<AggregateException>>(output)\n    {\n        protected override AggregateException[] TestValues => [null, new AggregateException(\"hi\"), CreateValue()];\n        protected override int[] MaxSegmentSizes => [8096];\n\n        protected override AggregateException CreateValue()\n        {\n            try\n            {\n                try\n                {\n                    throw new InvalidOperationException(\"ExpectedAggregateException\");\n                }\n                catch (Exception ex)\n                {\n                    throw new AggregateException(\"Aahh\", ex, new InvalidCastException(\"Boo!\"));\n                }\n            }\n            catch (AggregateException ag)\n            {\n                return ag;\n            }\n        }\n\n        protected override bool Equals(AggregateException left, AggregateException right)\n        {\n            // Validation for exceptions is light. They are generally transformed in some fashion as they are serialized and deserialized.\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return string.Equals(left.Message, right.Message, StringComparison.Ordinal);\n        }\n    }\n\n    public class AggregateExceptionCopierTests(ITestOutputHelper output) : CopierTester<AggregateException, IDeepCopier<AggregateException>>(output)\n    {\n        protected override bool IsImmutable => true;\n        protected override AggregateException[] TestValues => [null, new AggregateException(\"hi\"), CreateValue()];\n\n        protected override AggregateException CreateValue()\n        {\n            try\n            {\n                try\n                {\n                    throw new InvalidOperationException(\"ExpectedAggregateException\");\n                }\n                catch (Exception ex)\n                {\n                    throw new AggregateException(\"Aahh\", ex, new InvalidCastException(\"Boo!\"));\n                }\n            }\n            catch (AggregateException ag)\n            {\n                return ag;\n            }\n        }\n\n        protected override bool Equals(AggregateException left, AggregateException right)\n        {\n            // Validation for exceptions is light. They are generally transformed in some fashion as they are serialized and deserialized.\n            if (left is null && right is null)\n            {\n                return true;\n            }\n            else if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left.InnerExceptions.Count != right.InnerExceptions.Count)\n            {\n                return false;\n            }\n\n            foreach (var inner in left.InnerExceptions.Zip(right.InnerExceptions))\n            {\n                if (!string.Equals(inner.First.Message, inner.Second.Message, StringComparison.Ordinal))\n                {\n                    return false;\n                }\n            }\n\n            return string.Equals(left.Message, right.Message, StringComparison.Ordinal);\n        }\n    }\n\n    public class CancellationTokenCopierTests(ITestOutputHelper output) : CopierTester<CancellationToken, IDeepCopier<CancellationToken>>(output)\n    {\n        protected override CancellationToken CreateValue() => default;\n        protected override CancellationToken[] TestValues =>\n        [\n            new CancellationToken(),\n            new CancellationToken(true)\n        ];\n    }\n\n#if NET8_0_OR_GREATER\n    public class GrainCancellationTokenCodecTests(ITestOutputHelper output) : FieldCodecTester<GrainCancellationToken, IFieldCodec<GrainCancellationToken>>(output)\n    {\n        private static readonly PropertyInfo TokenIdProperty = typeof(GrainCancellationToken).GetProperty(\"Id\", BindingFlags.Instance | BindingFlags.NonPublic)\n            ?? throw new InvalidOperationException(\"Unable to locate GrainCancellationToken.Id property.\");\n\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            var runtimeInterfaceType = Type.GetType(\"Orleans.Runtime.IGrainCancellationTokenRuntime, Orleans.Core.Abstractions\")\n                ?? throw new InvalidOperationException(\"Unable to locate IGrainCancellationTokenRuntime.\");\n            var runtimeImplementationType = Type.GetType(\"Orleans.Runtime.GrainCancellationTokenRuntime, Orleans.Core\")\n                ?? throw new InvalidOperationException(\"Unable to locate GrainCancellationTokenRuntime.\");\n            var runtimeInstance = Activator.CreateInstance(runtimeImplementationType, nonPublic: true)\n                ?? throw new InvalidOperationException(\"Unable to create GrainCancellationTokenRuntime.\");\n\n            builder.Services.AddSingleton(runtimeInterfaceType, runtimeInstance);\n        }\n\n        protected override GrainCancellationToken CreateValue() => CreateToken(isCanceled: false);\n\n        protected override GrainCancellationToken[] TestValues =>\n        [\n            null,\n            CreateToken(isCanceled: false),\n            CreateToken(isCanceled: true),\n        ];\n\n        protected override bool Equals(GrainCancellationToken left, GrainCancellationToken right)\n        {\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n\n            if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return GetTokenId(left) == GetTokenId(right)\n                && left.CancellationToken.IsCancellationRequested == right.CancellationToken.IsCancellationRequested;\n        }\n\n        private static GrainCancellationToken CreateToken(bool isCanceled)\n        {\n            var source = new GrainCancellationTokenSource();\n            if (isCanceled)\n            {\n                source.Cancel().GetAwaiter().GetResult();\n            }\n\n            return source.Token;\n        }\n\n        private static Guid GetTokenId(GrainCancellationToken token)\n            => (Guid)TokenIdProperty.GetValue(token)!;\n    }\n\n    public class IdSpanCodecTests(ITestOutputHelper output) : FieldCodecTester<IdSpan, IdSpanCodec>(output)\n    {\n        protected override IdSpan CreateValue() => IdSpan.Create(Guid.NewGuid().ToString(\"N\"));\n\n        protected override IdSpan[] TestValues =>\n        [\n            default,\n            IdSpan.Create(\"alpha\"),\n            new IdSpan([1, 2, 3, 4]),\n            new IdSpan([10, 20, 30]),\n        ];\n    }\n\n    public class SiloAddressCodecTests(ITestOutputHelper output) : FieldCodecTester<SiloAddress, SiloAddressCodec>(output)\n    {\n        protected override int[] MaxSegmentSizes => [256];\n\n        protected override SiloAddress CreateValue()\n            => SiloAddress.New(IPAddress.Loopback, Random.Next(10240, 30240), Random.Next(1, 1000));\n\n        protected override SiloAddress[] TestValues =>\n        [\n            null,\n            SiloAddress.Zero,\n            SiloAddress.New(IPAddress.Loopback, 11111, 1),\n            SiloAddress.New(IPAddress.Parse(\"127.0.0.2\"), 22222, 2),\n        ];\n    }\n\n    public class IAddressableCodecTests(ITestOutputHelper output) : FieldCodecTester<IAddressable, IFieldCodec<IAddressable>>(output)\n    {\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.Services.AddSingleton<IGrainReferenceRuntime, TestGrainReferenceRuntime>();\n            builder.Services.AddSingleton<IGrainFactory, TestGrainFactory>();\n\n            var codecProviderType = Type.GetType(\"Orleans.Runtime.GrainReferenceCodecProvider, Orleans.Core.Abstractions\")\n                ?? throw new InvalidOperationException(\"Unable to locate GrainReferenceCodecProvider.\");\n            builder.Services.AddSingleton(typeof(ISpecializableCodec), codecProviderType);\n        }\n\n        protected override IAddressable CreateValue()\n        {\n            var grainId = GrainReferenceTestHelper.CreateGrainId();\n            return GrainReferenceTestHelper.CreateGrainReference(ServiceProvider, grainId, GrainReferenceTestHelper.InterfaceType);\n        }\n\n        protected override IAddressable[] TestValues =>\n        [\n            null,\n            CreateValue(),\n            CreateValue(),\n        ];\n\n        protected override bool Equals(IAddressable left, IAddressable right)\n        {\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n\n            if (left is null || right is null)\n            {\n                return false;\n            }\n\n            if (left is not GrainReference leftRef || right is not GrainReference rightRef)\n            {\n                return false;\n            }\n\n            return leftRef.GrainId == rightRef.GrainId && leftRef.InterfaceType == rightRef.InterfaceType;\n        }\n    }\n\n    public class XDocumentCodecTests(ITestOutputHelper output) : FieldCodecTester<XDocument, IFieldCodec<XDocument>>(output)\n    {\n        protected override int[] MaxSegmentSizes => [256];\n\n        protected override XDocument CreateValue() => CreateDocument();\n\n        protected override XDocument[] TestValues =>\n        [\n            null,\n            CreateDocument(),\n            CreateDocument(),\n        ];\n\n        protected override bool Equals(XDocument left, XDocument right)\n        {\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n\n            if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return XNode.DeepEquals(left, right);\n        }\n\n        private static XDocument CreateDocument()\n            => new(new XElement(\"root\", new XAttribute(\"id\", Guid.NewGuid()), new XElement(\"value\", Guid.NewGuid().ToString(\"N\"))));\n    }\n\n    public class XDocumentCopierTests(ITestOutputHelper output) : CopierTester<XDocument, IDeepCopier<XDocument>>(output)\n    {\n        protected override bool IsPooled => true;\n\n        protected override XDocument CreateValue() => CreateDocument();\n\n        protected override XDocument[] TestValues =>\n        [\n            CreateDocument(),\n            CreateDocument(),\n        ];\n\n        protected override bool Equals(XDocument left, XDocument right)\n        {\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n\n            if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return XNode.DeepEquals(left, right);\n        }\n\n        private static XDocument CreateDocument()\n            => new(new XElement(\"root\", new XAttribute(\"id\", Guid.NewGuid()), new XElement(\"value\", Guid.NewGuid().ToString(\"N\"))));\n    }\n\n    public class GrainReferenceCopierTests(ITestOutputHelper output) : CopierTester<GrainReference, IDeepCopier<GrainReference>>(output)\n    {\n        protected override bool IsImmutable => true;\n\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.Services.AddSingleton<IGrainReferenceRuntime, TestGrainReferenceRuntime>();\n        }\n\n        protected override GrainReference CreateValue()\n        {\n            var grainId = GrainReferenceTestHelper.CreateGrainId();\n            return GrainReferenceTestHelper.CreateGrainReference(ServiceProvider, grainId, GrainReferenceTestHelper.InterfaceType);\n        }\n\n        protected override GrainReference[] TestValues =>\n        [\n            null,\n            CreateValue(),\n            CreateValue(),\n        ];\n\n        protected override bool Equals(GrainReference left, GrainReference right)\n        {\n            if (ReferenceEquals(left, right))\n            {\n                return true;\n            }\n\n            if (left is null || right is null)\n            {\n                return false;\n            }\n\n            return left.GrainId == right.GrainId && left.InterfaceType == right.InterfaceType;\n        }\n    }\n\n    internal static class GrainReferenceTestHelper\n    {\n        private static readonly MethodInfo GrainReferenceFromGrainId = typeof(GrainReference).GetMethod(\"FromGrainId\", BindingFlags.Static | BindingFlags.NonPublic)\n            ?? throw new InvalidOperationException(\"Unable to locate GrainReference.FromGrainId.\");\n\n        internal static readonly GrainInterfaceType InterfaceType = GrainInterfaceType.Create(\"unit-tests\");\n\n        internal static GrainId CreateGrainId()\n            => GrainId.Create(GrainType.Create(\"unit-tests\"), IdSpan.Create(Guid.NewGuid().ToString(\"N\")));\n\n        internal static GrainReference CreateGrainReference(IServiceProvider serviceProvider, GrainId grainId, GrainInterfaceType interfaceType)\n        {\n            var runtime = serviceProvider.GetRequiredService<IGrainReferenceRuntime>();\n            var codecProvider = serviceProvider.GetRequiredService<CodecProvider>();\n            var copyContextPool = serviceProvider.GetRequiredService<CopyContextPool>();\n            var shared = new GrainReferenceShared(\n                grainId.Type,\n                interfaceType,\n                interfaceVersion: 0,\n                runtime,\n                InvokeMethodOptions.None,\n                codecProvider,\n                copyContextPool,\n                serviceProvider);\n            return (GrainReference)GrainReferenceFromGrainId.Invoke(null, new object[] { shared, grainId })!;\n        }\n    }\n\n    internal sealed class TestGrainReferenceRuntime : IGrainReferenceRuntime\n    {\n        public object Cast(IAddressable grain, Type interfaceType) => grain;\n\n        public ValueTask<T> InvokeMethodAsync<T>(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n            => throw new NotSupportedException(\"Grain invocations are not supported in codec tests.\");\n\n        public ValueTask InvokeMethodAsync(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n            => throw new NotSupportedException(\"Grain invocations are not supported in codec tests.\");\n\n        public void InvokeMethod(GrainReference reference, IInvokable request, InvokeMethodOptions options)\n            => throw new NotSupportedException(\"Grain invocations are not supported in codec tests.\");\n    }\n\n    internal sealed class TestGrainFactory(IServiceProvider serviceProvider) : IGrainFactory\n    {\n        private const string UnsupportedMessage = \"TestGrainFactory only supports GrainId-based lookups.\";\n        private readonly IServiceProvider _serviceProvider = serviceProvider;\n\n        public IAddressable GetGrain(GrainId grainId, GrainInterfaceType interfaceType)\n            => GrainReferenceTestHelper.CreateGrainReference(_serviceProvider, grainId, interfaceType);\n\n        public IAddressable GetGrain(GrainId grainId)\n            => GetGrain(grainId, GrainReferenceTestHelper.InterfaceType);\n\n        public TGrainInterface GetGrain<TGrainInterface>(GrainId grainId) where TGrainInterface : IAddressable\n            => (TGrainInterface)GetGrain(grainId, GrainReferenceTestHelper.InterfaceType);\n\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidKey\n            => ThrowUnsupported<TGrainInterface>();\n\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerKey\n            => ThrowUnsupported<TGrainInterface>();\n\n        public TGrainInterface GetGrain<TGrainInterface>(string primaryKey, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithStringKey\n            => ThrowUnsupported<TGrainInterface>();\n\n        public TGrainInterface GetGrain<TGrainInterface>(Guid primaryKey, string keyExtension, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithGuidCompoundKey\n            => ThrowUnsupported<TGrainInterface>();\n\n        public TGrainInterface GetGrain<TGrainInterface>(long primaryKey, string keyExtension, string grainClassNamePrefix = null) where TGrainInterface : IGrainWithIntegerCompoundKey\n            => ThrowUnsupported<TGrainInterface>();\n\n        public TGrainObserverInterface CreateObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver\n            => ThrowUnsupported<TGrainObserverInterface>();\n\n        public void DeleteObjectReference<TGrainObserverInterface>(IGrainObserver obj) where TGrainObserverInterface : IGrainObserver\n            => ThrowUnsupported();\n\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey)\n            => ThrowUnsupported<IGrain>();\n\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey)\n            => ThrowUnsupported<IGrain>();\n\n        public IGrain GetGrain(Type grainInterfaceType, string grainPrimaryKey)\n            => ThrowUnsupported<IGrain>();\n\n        public IGrain GetGrain(Type grainInterfaceType, Guid grainPrimaryKey, string keyExtension)\n            => ThrowUnsupported<IGrain>();\n\n        public IGrain GetGrain(Type grainInterfaceType, long grainPrimaryKey, string keyExtension)\n            => ThrowUnsupported<IGrain>();\n\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey, string grainClassNamePrefix)\n            => ThrowUnsupported<IAddressable>();\n\n        public IAddressable GetGrain(Type interfaceType, IdSpan grainKey)\n            => ThrowUnsupported<IAddressable>();\n\n        private static T ThrowUnsupported<T>() => throw new NotSupportedException(UnsupportedMessage);\n\n        private static void ThrowUnsupported() => throw new NotSupportedException(UnsupportedMessage);\n    }\n#endif\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ConverterTests.cs",
    "content": "using System;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.TestKit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for the converter-based serialization mechanism in Orleans.\n/// \n/// Converters allow Orleans to serialize types from external libraries that cannot be modified\n/// to add Orleans serialization attributes. This is achieved through surrogate types that:\n/// - Act as intermediaries for serialization\n/// - Convert between the foreign type and a serializable representation\n/// - Support both reference types and value types\n/// - Allow serialization of derived types from foreign libraries\n/// \n/// This approach enables Orleans to maintain its high-performance serialization while\n/// integrating with third-party libraries and legacy code.\n/// </summary>\npublic class ConverterCodecTests : FieldCodecTester<MyForeignLibraryType, IFieldCodec<MyForeignLibraryType>>\n{\n    public ConverterCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MyForeignLibraryType CreateValue() => new(12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(MyForeignLibraryType left, MyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override MyForeignLibraryType[] TestValues => new MyForeignLibraryType[] { null, CreateValue() };\n}\n\npublic class ConverterCopierTests : CopierTester<MyForeignLibraryType, IDeepCopier<MyForeignLibraryType>>\n{\n    public ConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MyForeignLibraryType CreateValue() => new(12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(MyForeignLibraryType left, MyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override MyForeignLibraryType[] TestValues => new MyForeignLibraryType[] { null, CreateValue() };\n}\n\npublic class WrappedConverterCodecTests : FieldCodecTester<WrapsMyForeignLibraryType, IFieldCodec<WrapsMyForeignLibraryType>>\n{\n    public WrappedConverterCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override WrapsMyForeignLibraryType CreateValue() => new() { IntValue = 12, ForeignValue = new MyForeignLibraryType(12, \"hi\", DateTimeOffset.Now), OtherIntValue = 7468249 };\n    protected override bool Equals(WrapsMyForeignLibraryType left, WrapsMyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override WrapsMyForeignLibraryType[] TestValues => new WrapsMyForeignLibraryType[] { default, CreateValue() };\n}\n\npublic class WrappedConverterCopierTests : CopierTester<WrapsMyForeignLibraryType, IDeepCopier<WrapsMyForeignLibraryType>>\n{\n    public WrappedConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override WrapsMyForeignLibraryType CreateValue() => new() { IntValue = 12, ForeignValue = new MyForeignLibraryType(12, \"hi\", DateTimeOffset.Now), OtherIntValue = 7468249 };\n    protected override bool Equals(WrapsMyForeignLibraryType left, WrapsMyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override WrapsMyForeignLibraryType[] TestValues => new WrapsMyForeignLibraryType[] { default, CreateValue() };\n}\n\npublic class StructConverterCodecTests : ValueTypeFieldCodecTester<MyForeignLibraryValueType, IFieldCodec<MyForeignLibraryValueType>>\n{\n    public StructConverterCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MyForeignLibraryValueType CreateValue() => new(12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(MyForeignLibraryValueType left, MyForeignLibraryValueType right) => left.Equals(right);\n    protected override MyForeignLibraryValueType[] TestValues => new MyForeignLibraryValueType[] { default, CreateValue() };\n}\n\npublic class StructConverterCopierTests : CopierTester<MyForeignLibraryValueType, IDeepCopier<MyForeignLibraryValueType>>\n{\n    public StructConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MyForeignLibraryValueType CreateValue() => new(12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(MyForeignLibraryValueType left, MyForeignLibraryValueType right) => left.Equals(right);\n    protected override MyForeignLibraryValueType[] TestValues => new MyForeignLibraryValueType[] { default, CreateValue() };\n}\n\npublic class WrappedStructConverterCodecTests : ValueTypeFieldCodecTester<WrapsMyForeignLibraryValueType, IFieldCodec<WrapsMyForeignLibraryValueType>>\n{\n    public WrappedStructConverterCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override WrapsMyForeignLibraryValueType CreateValue() => new() { IntValue = 12, ForeignValue = new MyForeignLibraryValueType(12, \"hi\", DateTimeOffset.Now), OtherIntValue = 7468249 };\n    protected override bool Equals(WrapsMyForeignLibraryValueType left, WrapsMyForeignLibraryValueType right) => left.Equals(right);\n    protected override WrapsMyForeignLibraryValueType[] TestValues => new WrapsMyForeignLibraryValueType[] { default, CreateValue() };\n}\n\npublic class WrappedStructConverterCopierTests : CopierTester<WrapsMyForeignLibraryValueType, IDeepCopier<WrapsMyForeignLibraryValueType>>\n{\n    public WrappedStructConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override WrapsMyForeignLibraryValueType CreateValue() => new() { IntValue = 12, ForeignValue = new MyForeignLibraryValueType(12, \"hi\", DateTimeOffset.Now), OtherIntValue = 7468249 };\n    protected override bool Equals(WrapsMyForeignLibraryValueType left, WrapsMyForeignLibraryValueType right) => left.Equals(right);\n    protected override WrapsMyForeignLibraryValueType[] TestValues => new WrapsMyForeignLibraryValueType[] { default, CreateValue() };\n}\n\npublic class DerivedConverterCodecTests : FieldCodecTester<DerivedFromMyForeignLibraryType, IFieldCodec<DerivedFromMyForeignLibraryType>>\n{\n    public DerivedConverterCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override DerivedFromMyForeignLibraryType CreateValue() => new(658, 12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(DerivedFromMyForeignLibraryType left, DerivedFromMyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override DerivedFromMyForeignLibraryType[] TestValues => new DerivedFromMyForeignLibraryType[] { null, CreateValue() };\n}\n\npublic class DerivedConverterCopierTests : CopierTester<DerivedFromMyForeignLibraryType, IDeepCopier<DerivedFromMyForeignLibraryType>>\n{\n    public DerivedConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override DerivedFromMyForeignLibraryType CreateValue() => new(658, 12, \"hi\", DateTimeOffset.Now);\n    protected override bool Equals(DerivedFromMyForeignLibraryType left, DerivedFromMyForeignLibraryType right) => ReferenceEquals(left, right) || left.Equals(right);\n    protected override DerivedFromMyForeignLibraryType[] TestValues => new DerivedFromMyForeignLibraryType[] { null, CreateValue() };\n}\n\n\npublic class CombinedConverterCopierTests : CopierTester<MyFirstForeignLibraryType, IDeepCopier<MyFirstForeignLibraryType>>\n{\n    public CombinedConverterCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MyFirstForeignLibraryType CreateValue() => new() { Num = 12, String = \"hi\", DateTimeOffset = DateTimeOffset.Now };\n    protected override bool Equals(MyFirstForeignLibraryType left, MyFirstForeignLibraryType right) => left.Equals(right);\n    protected override MyFirstForeignLibraryType[] TestValues => new MyFirstForeignLibraryType[] { CreateValue() };\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/GeneratedSerializerTests.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.IO.Pipelines;\nusing Xunit;\nusing System.Linq;\nusing UnitTests.SerializerExternalModels;\nusing Orleans;\n\n[assembly: GenerateCodeForDeclaringAssembly(typeof(Person2ExternalStruct))]\n#if NET6_0_OR_GREATER\n[assembly: GenerateCodeForDeclaringAssembly(typeof(Person2External))]\n#endif\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for Orleans' code-generated serializers.\n/// \n/// Orleans uses source generators to create high-performance serializers at compile time for types\n/// marked with [GenerateSerializer]. The generated serializers provide:\n/// - Zero-allocation serialization for common scenarios\n/// - Support for complex object graphs with circular references\n/// - Version tolerance through field-based serialization\n/// - Efficient handling of inheritance hierarchies\n/// - Support for records, classes, and structs\n/// - Integration with external types through assembly-level attributes\n/// \n/// The generated code follows Orleans' serialization protocol which ensures:\n/// - Backward and forward compatibility\n/// - Minimal wire format overhead\n/// - Support for schema evolution\n/// </summary>\n[Trait(\"Category\", \"BVT\")]\npublic class GeneratedSerializerTests : IDisposable\n{\n    private readonly ServiceProvider _serviceProvider;\n    private readonly CodecProvider _codecProvider;\n    private readonly SerializerSessionPool _sessionPool;\n    private readonly Serializer _serializer;\n    private readonly DeepCopier _deepCopier;\n\n    public GeneratedSerializerTests()\n    {\n        _serviceProvider = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        _codecProvider = _serviceProvider.GetRequiredService<CodecProvider>();\n        _sessionPool = _serviceProvider.GetRequiredService<SerializerSessionPool>();\n        _serializer = _serviceProvider.GetRequiredService<Serializer>();\n        _deepCopier = _serviceProvider.GetRequiredService<DeepCopier>();\n    }\n\n    /// <summary>\n    /// Verifies that generated serializers correctly handle basic class serialization,\n    /// including fields, properties, and polymorphic object references.\n    /// </summary>\n    [Fact]\n    public void GeneratedSerializersRoundTripThroughCodec()\n    {\n        var original = new SomeClassWithSerializers { IntField = 2, IntProperty = 30, OtherObject = MyCustomEnum.Two };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntField, result.IntField);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        var otherObj = Assert.IsType<MyCustomEnum>(result.OtherObject);\n        Assert.Equal(MyCustomEnum.Two, otherObj);\n    }\n\n    /// <summary>\n    /// Verifies that C# records are properly serialized and deserialized,\n    /// maintaining both primary constructor parameters and additional properties.\n    /// Records are fully supported in Orleans serialization.\n    /// </summary>\n    [Fact]\n    public void GeneratedRecordSerializersRoundTripThroughCodec()\n    {\n        var original = new Person(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n    }\n\n    [Fact]\n    public void AutoGeneratedPublicPropertyIdsTest()\n    {\n        var r = new Random();\n        var original = new PocoWithAutogeneratedIds\n        {\n            A = r.Next(),\n            B = r.Next(),\n            C = r.Next(),\n            D = r.Next(),\n            E = r.Next(),\n            F = r.Next(),\n            G = r.Next(),\n            H = r.Next(),\n            I = r.Next(),\n            J = r.Next(),\n            K = r.Next(),\n        };\n        var result = RoundTripThroughCodec(original);\n        Assert.Equal(original, result);\n    }\n\n    /// <summary>\n    /// Tests serialization of circular references and recursive data structures.\n    /// Orleans correctly handles object graphs with cycles, preserving reference equality\n    /// after deserialization to maintain object graph integrity.\n    /// </summary>\n    [Fact]\n    public void RecursiveTypeSerializersRoundTripThroughSerializer()\n    {\n        var original = new RecursiveClass { IntProperty = 30 };\n        original.RecursiveProperty = original;\n        var result = (RecursiveClass)RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.NotNull(result.RecursiveProperty);\n        Assert.Same(result, result.RecursiveProperty);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n    }\n\n    [Fact]\n    public void RecursiveTypeSerializersRoundTripThroughCodec()\n    {\n        var original = new RecursiveClass { IntProperty = 30 };\n        original.RecursiveProperty = original;\n        var result = RoundTripThroughCodec(original);\n\n        Assert.NotNull(result.RecursiveProperty);\n        Assert.Same(result, result.RecursiveProperty);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n    }\n\n    [Fact]\n    public void GeneratedRecordWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var original = new Person2(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n    }\n\n    [Fact]\n    public void GeneratedLibExternalRecordStructWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var original = new Person2ExternalStruct(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n    }\n\n#if NET6_0_OR_GREATER\n    [Fact]\n    public void GeneratedLibExternalRecordWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var original = new Person2External(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n    }\n\n    [Fact]\n    public void GeneratedLibExternalGenericRecordStructWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var originalInner = new Person2External(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var original = new GenericPersonExternalStruct<Person2External>(originalInner, \"harry\")\n        {\n            BodyParam = originalInner,\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.CtorParam, result.CtorParam);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.BodyParam, result.BodyParam);\n        Assert.Equal(original.StarSign, result.StarSign);\n        Assert.Same(result.CtorParam, result.BodyParam);\n    }\n\n    [Fact]\n    public void GeneratedReadonlyLibExternalGenericRecordStructWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var originalInner = new Person2External(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var original = new ReadonlyGenericPersonExternalStruct<Person2External>(originalInner, \"harry\")\n        {\n            BodyParam = originalInner,\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.CtorParam, result.CtorParam);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.BodyParam, result.BodyParam);\n        Assert.Equal(original.StarSign, result.StarSign);\n        Assert.Same(result.CtorParam, result.BodyParam);\n    }\n#endif\n\n#if NET9_0_OR_GREATER\n    [Fact]\n    public void GeneratedLibExternalGenericRecordWithPCtorSerializersRoundTripThroughCodec()\n    {\n        var originalInner = new Person2External(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var original = new GenericPersonExternal<Person2External>(originalInner, \"harry\")\n        {\n            BodyParam = originalInner,\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.CtorParam, result.CtorParam);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.BodyParam, result.BodyParam);\n        Assert.Equal(original.StarSign, result.StarSign);\n        Assert.Same(result.CtorParam, result.BodyParam);\n    }\n#endif\n\n#if NET6_0_OR_GREATER\n    [Fact]\n    public void RequiredMembersAreSupported()\n    {\n        var original = new ClassWithRequiredMembers\n        {\n            IntProperty = 1,\n            StringField = \"foo\",\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringField, result.StringField);\n\n        var subOriginal = new SubClassWithRequiredMembersInBase\n        {\n            IntProperty = 1,\n            StringField = \"foo\",\n        };\n\n        var subResult = RoundTripThroughCodec(subOriginal);\n\n        Assert.Equal(subOriginal.IntProperty, subResult.IntProperty);\n        Assert.Equal(subOriginal.StringField, subResult.StringField);\n    }\n#endif\n\n    [Fact]\n    public void GeneratedRecordWithExcludedPCtorSerializersRoundTripThroughCodec()\n    {\n        var original = new Person3(2, \"harry\")\n        {\n            FavouriteColor = \"redborine\",\n            StarSign = \"Aquaricorn\"\n        };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(default, result.Age);\n        Assert.Equal(default, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n    }\n\n    [Fact]\n    public void GeneratedRecordWithExclusiveCtorSerializersRoundTripThroughCodec()\n    {\n        var original = new Person4(2, \"harry\");\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n    }\n\n    /// <summary>\n    /// Tests that a record type can be serialized bitwise identically to a regular (non-record) class with the same layout.\n    /// </summary>\n    [Fact]\n    public void RecordSerializedAsRegularClass()\n    {\n        var original = new Person5(2, \"harry\") { FavouriteColor = \"redborine\", StarSign = \"Aquaricorn\" };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.Age, result.Age);\n        Assert.Equal(original.Name, result.Name);\n        Assert.Equal(original.FavouriteColor, result.FavouriteColor);\n        Assert.Equal(original.StarSign, result.StarSign);\n\n        // Note that this only works because we are serializing each object using the \"expected type\" optimization and\n        // therefore omitting the concrete type names.\n        var originalAsArray = _serializer.SerializeToArray(original);\n        var classVersion = new Person5_Class { Age = 2,  Name = \"harry\", FavouriteColor = \"redborine\", StarSign = \"Aquaricorn\" };\n        var classAsArray = _serializer.SerializeToArray(classVersion);\n        Assert.Equal(originalAsArray, classAsArray);\n    }\n\n    [Fact]\n    public void GeneratedSerializersRoundTripThroughSerializer()\n    {\n        var original = new SomeClassWithSerializers { IntField = 2, IntProperty = 30 };\n        var result = (SomeClassWithSerializers)RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.Equal(original.IntField, result.IntField);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n    }\n\n    [Fact]\n    public void GeneratedSerializersRoundTripThroughSerializer_ImmutableClass()\n    {\n        var original = new ImmutableClass(30, 2, 88, 99);\n        var result = (ImmutableClass)RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.Equal(original.GetIntField(), result.GetIntField());\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(0, result.UnmarkedField);\n        Assert.Equal(0, result.UnmarkedProperty);\n    }\n\n    [Fact]\n    public void GeneratedSerializersRoundTripThroughSerializer_ImmutableStruct()\n    {\n        var original = new ImmutableStruct(30, 2);\n         var result = (ImmutableStruct)RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.Equal(original.GetIntField(), result.GetIntField());\n        Assert.Equal(original.IntProperty, result.IntProperty);\n    }\n\n    [Fact]\n    public void UnmarkedFieldsAreNotSerialized()\n    {\n        var original = new SomeClassWithSerializers { IntField = 2, IntProperty = 30, UnmarkedField = 12, UnmarkedProperty = 47 };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.NotEqual(original.UnmarkedField, result.UnmarkedField);\n        Assert.NotEqual(original.UnmarkedProperty, result.UnmarkedProperty);\n    }\n\n    [Fact]\n    public void GenericPocosCanRoundTrip()\n    {\n        var original = new GenericPoco<string>\n        {\n            ArrayField = new[] { \"a\", \"bb\", \"ccc\" },\n            Field = Guid.NewGuid().ToString(\"N\")\n        };\n        var result = (GenericPoco<string>)RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n\n        Assert.Equal(original.ArrayField, result.ArrayField);\n        Assert.Equal(original.Field, result.Field);\n        Assert.Contains(\"gpoco`1\", formattedBitStream);\n    }\n\n    [Fact]\n    public void NestedGenericPocoWithTypeAlias()\n    {\n        var original = new GenericPoco<GenericPoco<string>>\n        {\n            Field = new GenericPoco<string>\n            {\n                Field = Guid.NewGuid().ToString(\"N\")\n            }\n        };\n\n        RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n        Assert.Contains(\"gpoco`1[[gpoco`1[[string]]]]\", formattedBitStream);\n    }\n\n    [Fact]\n    public void GenericArityAliasTest()\n    {\n        {\n            var original = new Outer<int>.InnerGen<string>();\n            RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n        }\n\n        {\n            var original = new Outer<int>.InnerNonGen();\n            RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n        }\n    }\n\n    [Fact]\n    public void ArraysAreSupported()\n    {\n        var original = new[] { \"a\", \"bb\", \"ccc\" };\n        var result = (string[])RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.Equal(original, result);\n    }\n\n    [Fact]\n    public void ArraysPocoRoundTrip()\n    {\n        var original = new ArrayPoco<int>\n        {\n            Array = new[] { 1, 2, 3 },\n            Dim2 = new int[,] { { 1 }, { 2 } },\n            Dim3 = new int[,,] { { { 2 } } },\n            Dim4 = new int[,,,] { { { { 4 } } } },\n            Dim32 = new int[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,] { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { 809 } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } },\n            Jagged = new int[][] { new int[] { 909 } }\n        };\n        var result = (ArrayPoco<int>)RoundTripThroughUntypedSerializer(original, out _);\n\n        Assert.Equal(JsonConvert.SerializeObject(original), JsonConvert.SerializeObject(result));\n    }\n\n    [Fact]\n    public void MultiDimensionalArraysAreSupported()\n    {\n        var array2d = new string[,] { { \"1\", \"2\", \"3\" }, { \"4\", \"5\", \"6\" }, { \"7\", \"8\", \"9\" } };\n        var result2d = (string[,])RoundTripThroughUntypedSerializer(array2d, out _);\n\n        Assert.Equal(array2d, result2d);\n        var array3d = new string[,,]\n        {\n            { { \"b\", \"b\", \"4\" }, { \"a\", \"g\", \"a\" }, { \"a\", \"g\", \"p\" } },\n            { { \"g\", \"r\", \"g\" }, { \"1\", \"3\", \"a\" }, { \"l\", \"k\", \"a\" } },\n            { { \"z\", \"b\", \"g\" }, { \"5\", \"7\", \"a\" }, { \"5\", \"n\", \"0\" } }\n        };\n        var result3d = (string[,,])RoundTripThroughUntypedSerializer(array3d, out _);\n\n        Assert.Equal(array3d, result3d);\n    }\n\n    [Fact]\n    public void SystemCollectionsRoundTrip()\n    {\n        var concurrentQueueField = new ConcurrentQueue<int>();\n        concurrentQueueField.Enqueue(4);\n\n        var concurrentQueueProperty = new ConcurrentQueue<int>();\n        concurrentQueueProperty.Enqueue(5);\n        concurrentQueueProperty.Enqueue(6);\n\n        var concurrentDictField = new ConcurrentDictionary<string, int>();\n        _ = concurrentDictField.TryAdd(\"nine\", 9);\n\n        var concurrentDictProperty = new ConcurrentDictionary<string, int>();\n        _ = concurrentDictProperty.TryAdd(\"ten\", 10);\n        _ = concurrentDictProperty.TryAdd(\"eleven\", 11);\n\n        var original = new SystemCollectionsClass\n        {\n            hashSetField = new HashSet<string> { \"one\" },\n            HashSetProperty = new HashSet<string> { \"two\", \"three\" },\n            concurrentQueueField = concurrentQueueField,\n            ConcurrentQueueProperty = concurrentQueueProperty,\n            concurrentDictField = concurrentDictField,\n            ConcurrentDictProperty = concurrentDictProperty\n        };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.hashSetField, result.hashSetField);\n        Assert.Equal(original.HashSetProperty, result.HashSetProperty);\n\n        Assert.Equal(original.concurrentQueueField, result.concurrentQueueField);\n        Assert.Equal(original.ConcurrentQueueProperty, result.ConcurrentQueueProperty);\n\n        // Order of the key-value pairs in the return value may not match the order of the key-value pairs in the surrogate\n        Assert.Equal(original.concurrentDictField[\"nine\"], result.concurrentDictField[\"nine\"]);\n        Assert.Equal(original.ConcurrentDictProperty[\"ten\"], result.ConcurrentDictProperty[\"ten\"]);\n        Assert.Equal(original.ConcurrentDictProperty[\"eleven\"], result.ConcurrentDictProperty[\"eleven\"]);\n    }\n\n    [Fact]\n    public void ClassWithLargeCollectionAndUriRoundTrip()\n    {\n        var largeCollection = new List<string>(200);\n        for (int i = 0; i < 200; i++)\n        {\n            largeCollection.Add(i.ToString());\n        }\n\n        var original = new ClassWithLargeCollectionAndUri\n        {\n            LargeCollection = largeCollection,\n            Uri = new($\"http://www.{Guid.NewGuid()}.com/\")\n        };\n\n        var result = RoundTripThroughCodec(original);\n        Assert.Equal(original.Uri, result.Uri);\n    }\n\n    [Fact]\n    public void ClassWithManualSerializablePropertyRoundTrip()\n    {\n        var original = new ClassWithManualSerializableProperty\n        {\n            GuidProperty = Guid.NewGuid(),\n        };\n\n        var result = RoundTripThroughCodec(original);\n        Assert.Equal(original.GuidProperty, result.GuidProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n\n        var guidValue = Guid.NewGuid();\n        original.StringProperty = guidValue.ToString(\"N\");\n        result = RoundTripThroughCodec(original);\n\n        Assert.Equal(guidValue, result.GuidProperty);\n        Assert.Equal(original.GuidProperty, result.GuidProperty);\n\n        Assert.Equal(guidValue.ToString(\"N\"), result.StringProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n\n        original.StringProperty = \"bananas\";\n        result = RoundTripThroughCodec(original);\n\n        Assert.Equal(default, result.GuidProperty);\n        Assert.Equal(original.GuidProperty, result.GuidProperty);\n        Assert.Equal(\"bananas\", result.StringProperty);\n    }\n\n    [Fact]\n    public void ImmutableClassWithImplicitFieldIdsRoundTrip()\n    {\n        var original = new ClassWithImplicitFieldIds(\"apples\", MyCustomEnum.One);\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.StringValue, result.StringValue);\n        Assert.Equal(original.EnumValue, result.EnumValue);\n    }\n\n    [Fact]\n    public void CopyImmutableAndSealedTypes()\n    {\n        DoTest<MyImmutableSub, MyImmutableBase>(new MyImmutableSub { BaseValue = 1, SubValue = 2 });\n        DoTest<MyMutableSub, MyImmutableBase>(new MyMutableSub { BaseValue = 1, SubValue = 2 });\n        DoTest<MySealedSub, MyMutableBase>(new MySealedSub { BaseValue = 1, SubValue = 2 });\n        DoTest<MySealedImmutableSub, MyMutableBase>(new MySealedImmutableSub { BaseValue = 1, SubValue = 2 });\n        DoTest<MyUnsealedImmutableSub, MyMutableBase>(new MyUnsealedImmutableSub { BaseValue = 1, SubValue = 2 });\n\n        void DoTest<T, TBase>(T original) where T : TBase, IMySub\n        {\n            var res1 = Copy(original);\n            Assert.Equal(original.BaseValue, res1.BaseValue);\n            Assert.Equal(original.SubValue, res1.SubValue);\n\n            var res2 = Assert.IsType<T>(Copy<object>(original));\n            Assert.Equal(original.BaseValue, res2.BaseValue);\n            Assert.Equal(original.SubValue, res2.SubValue);\n\n            var res3 = Assert.IsType<T>(Copy<TBase>(original));\n            Assert.Equal(original.BaseValue, res3.BaseValue);\n            Assert.Equal(original.SubValue, res3.SubValue);\n        }\n    }\n\n    [Fact]\n    public void DuplicateReferencesSerializeTargetJustOnce()\n    {\n        var sharedObject = new MyValue(1);\n        var original = new object[] { sharedObject, sharedObject };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original, result);\n        Assert.Same(result[0], result[1]);\n    }\n\n    [Fact]\n    public void DuplicateReferencesSerializeTargetMultipleTimesWhenSuppressReferenceTrackingEnabled()\n    {\n        var sharedObject = new MySuppressReferenceTrackingValue(1);\n        var original = new object[] { sharedObject, sharedObject };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original, result);\n        Assert.NotSame(result[0], result[1]);\n    }\n\n    [Fact]\n    public void DuplicateReferencesToAnyExceptionTypesSerializeTargetMultipleTimes()\n    {\n        var sharedException = new MyCustomException(\"Something bad\");\n        var original = new Exception[] { sharedException, sharedException };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.NotSame(result[0], result[1]);\n    }\n\n    [Fact]\n    public void DuplicateReferencesToExceptionTypeWithSurrogateSerializeTargetMultipleTimes()\n    {\n        var sharedException = new MyCustomForeignException(1);\n        var original = new Exception[] { sharedException, sharedException };\n\n        var result = RoundTripThroughCodec(original);\n\n        Assert.NotSame(result[0], result[1]);\n    }\n\n    [Fact]\n    public void TypeReferencesAreEncodedOnce()\n    {\n        var original = new object[] { new MyValue(1), new MyValue(2), new MyValue(3) };\n        var result = (object[])RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n\n        Assert.Equal(original, result);\n        Assert.Contains(\"SchemaType: Referenced RuntimeType: MyValue\", formattedBitStream);\n    }\n\n    [Fact]\n    public void TypeCodecDoesNotUpdateTypeReferences()\n    {\n        var original = new ClassWithTypeFields { Type1 = typeof(MyValue), UntypedValue = new MyValue(42), Type2 = typeof(MyValue) };\n        var result = (ClassWithTypeFields)RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n\n        Assert.Equal(original.Type1, result.Type1);\n        Assert.Equal(original.UntypedValue, result.UntypedValue);\n        Assert.Equal(original.Type2, result.Type2);\n\n        Assert.Contains(\"[#4 LengthPrefixed Id: 1 SchemaType: Expected]\", formattedBitStream); // Type1\n        Assert.Contains(\"[#5 TagDelimited Id: 2 SchemaType: Encoded RuntimeType: MyValue\", formattedBitStream); // UntypedValue\n        Assert.Contains(\"[#7 Reference Id: 3 SchemaType: Expected\", formattedBitStream); // Type2\n    }\n\n    [Fact]\n    public void TypeCodecConsumesTypeReferences()\n    {\n        var original = new ClassWithTypeFields { UntypedValue = new MyValue(42), Type2 = typeof(MyValue) };\n        var result = (ClassWithTypeFields)RoundTripThroughUntypedSerializer(original, out var formattedBitStream);\n\n        Assert.Equal(original.Type1, result.Type1);\n        Assert.Equal(original.UntypedValue, result.UntypedValue);\n        Assert.Equal(original.Type2, result.Type2);\n\n        Assert.Contains(\"[#2 Reference Id: 1 SchemaType: Expected Reference: 0]\", formattedBitStream); // Type1\n        Assert.Contains(\"[#3 TagDelimited Id: 2 SchemaType: Encoded RuntimeType: MyValue\", formattedBitStream); // UntypedValue\n        Assert.Contains(\"[#5 TagDelimited Id: 3 SchemaType: Expected]\", formattedBitStream); // Type2\n        Assert.Contains(\"[#7 VarInt Id: 2 SchemaType: Expected] Value: 2\", formattedBitStream); // type reference from Type2 field pointing to the encoded field type of UntypedValue\n    }\n\n    [Fact]\n    public void TypeDerivedFromList()\n    {\n        var original = new SerializableClassWithCompiledBase { IntProperty = 30 };\n        original.Add(1);\n        original.Add(200);\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.True(original.SequenceEqual(result));\n    }\n\n    [Fact]\n    public void TypeDerivedFromDictionary()\n    {\n        var original = new DerivedFromDictionary<string, int>(StringComparer.OrdinalIgnoreCase)\n        {\n            { \"a\", 1 },\n            { \"b\", 2 },\n        };\n        original.IntProperty = Guid.NewGuid().GetHashCode();\n\n        var result = RoundTripThroughCodec(original);\n        Assert.Equal(original.Count, result.Count);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n\n        // Set a duplicate key, differing by case, to check that the equality comparer has been set correctly.\n        result[\"A\"] = 1;\n        result[\"a\"] = 1;\n\n        Assert.True(original.SequenceEqual(result));\n    }\n\n    public void Dispose() => _serviceProvider?.Dispose();\n\n    private T RoundTripThroughCodec<T>(T original)\n    {\n        T result;\n        var pipe = new Pipe();\n        using (var readerSession = _sessionPool.GetSession())\n        using (var writeSession = _sessionPool.GetSession())\n        {\n            var writer = Writer.Create(pipe.Writer, writeSession);\n            var codec = _codecProvider.GetCodec<T>();\n            codec.WriteField(\n                ref writer,\n                0,\n                null,\n                original);\n            writer.Commit();\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n\n            var previousPos = reader.Position;\n            var initialHeader = reader.ReadFieldHeader();\n            Assert.True(reader.Position > previousPos);\n\n            result = codec.ReadValue(ref reader, initialHeader);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n        }\n\n        return result;\n    }\n\n    private T Copy<T>(T original)\n    {\n        var copier = _serviceProvider.GetRequiredService<DeepCopier<T>>();\n        return copier.Copy(original);\n    }\n\n    private object RoundTripThroughUntypedSerializer(object original, out string formattedBitStream)\n    {\n        var pipe = new Pipe();\n        object result;\n        using (var readerSession = _sessionPool.GetSession())\n        using (var writeSession = _sessionPool.GetSession())\n        {\n            var writer = Writer.Create(pipe.Writer, writeSession);\n            var serializer = _serviceProvider.GetService<Serializer<object>>();\n            serializer.Serialize(original, ref writer);\n\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n\n            using var analyzerSession = _sessionPool.GetSession();\n            formattedBitStream = BitStreamFormatter.Format(readResult.Buffer, analyzerSession);\n\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n\n            result = serializer.Deserialize(ref reader);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/GenericBaseClassTest.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    [GenerateSerializer]\n    abstract class Base<T>;\n\n    class Derived : Base<int>;\n\n    /// <summary>\n    /// Tests for serialization behavior with generic base classes.\n    /// \n    /// Orleans requires that serializable types are explicitly marked with [GenerateSerializer].\n    /// When a base class is generic and marked for serialization, derived classes that close\n    /// the generic type parameters do not automatically inherit serialization capability\n    /// unless they are also marked with [GenerateSerializer].\n    /// \n    /// This test verifies that the serializer correctly identifies which types can be serialized\n    /// based on explicit attribute marking rather than inheritance.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class GenericBaseClassTest\n    {\n        private readonly ServiceProvider _services;\n        private readonly Serializer _serializer;\n        public GenericBaseClassTest()\n        {\n            _services = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            _serializer = _services.GetRequiredService<Serializer>();\n        }\n\n        [Fact]\n        public void DerivedNoGeneric()\n        {\n            Assert.False(_serializer.CanSerialize(typeof(Derived)));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ISerializableTests.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.TypeSystem;\nusing Orleans.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.IO.Pipelines;\nusing System.Runtime.Serialization;\nusing System.Runtime.Serialization.Formatters.Binary;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' support of the .NET ISerializable interface.\n    /// \n    /// Orleans provides compatibility with types that implement ISerializable for custom serialization,\n    /// which is important for:\n    /// - Integrating with legacy .NET types\n    /// - Supporting types that require custom serialization logic\n    /// - Maintaining compatibility with existing serialization patterns\n    /// \n    /// The DotNetSerializableCodec handles ISerializable types by:\n    /// - Respecting serialization callbacks (OnSerializing, OnSerialized, etc.)\n    /// - Supporting streaming contexts\n    /// - Handling serialization constructors\n    /// - Providing fallback serialization for types without Orleans-specific serializers\n    /// \n    /// Note: While supported for compatibility, Orleans' native serialization is preferred\n    /// for better performance and version tolerance.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\"), Trait(\"Category\", \"ISerializable\")]\n    public class ISerializableTests\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly SerializerSessionPool _sessionPool;\n        private readonly Serializer<object> _serializer;\n        private readonly ITestOutputHelper _log;\n\n        public ISerializableTests(ITestOutputHelper log)\n        {\n            var services = new ServiceCollection();\n            _ = services.AddSerializer();\n            services.RemoveAll(typeof(TypeResolver));\n            services.AddSingleton<TypeResolver>(sp => new BanningTypeResolver(typeof(UnserializableConformingException), typeof(UnserializableNonConformingException)));\n            services.AddSingleton<IGeneralizedCodec, DotNetSerializableCodec>();\n\n            _serviceProvider = services.BuildServiceProvider();\n            _sessionPool = _serviceProvider.GetService<SerializerSessionPool>();\n            _serializer = _serviceProvider.GetRequiredService<Serializer<object>>();\n            _log = log;\n        }\n\n        private object SerializationLoop(object original)\n        {\n            var pipe = new Pipe();\n\n            using var writerSession = _sessionPool.GetSession();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n            _serializer.Serialize(original, ref writer);\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            {\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var output = BitStreamFormatter.Format(ref reader);\n                _log.WriteLine(output);\n            }\n\n            {\n                using var readerSession = _sessionPool.GetSession();\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var deserialized = _serializer.Deserialize(ref reader);\n                pipe.Reader.AdvanceTo(readResult.Buffer.End);\n                pipe.Reader.Complete();\n\n                //Assert.True(Equals(original, deserialized), $\"Deserialized value \\\"{deserialized}\\\" must equal original value \\\"{original}\\\"\");\n                Assert.Equal(writer.Position, reader.Position);\n                Assert.Equal(writerSession.ReferencedObjects.CurrentReferenceId, readerSession.ReferencedObjects.CurrentReferenceId);\n                return deserialized;\n            }\n        }\n\n        /// <summary>\n        /// Tests that <see cref=\"DotNetSerializableCodec\"/> can correctly serialize objects.\n        /// </summary>\n        [Fact]\n        public void ISerializableObjectWithCallbacks()\n        {\n            var input = new SimpleISerializableObject\n            {\n                Payload = \"pyjamas\"\n            };\n\n            // Verify that our behavior conforms to our expected behavior.\n            var result = (SimpleISerializableObject)SerializationLoop(input);\n            Assert.Equal(\n                new[]\n                {\n                    \"default_ctor\",\n                    \"serializing\",\n                    \"serialized\"\n                },\n                input.History);\n            Assert.Equal(3, input.Contexts.Count);\n\n            Assert.Equal(\n                new[]\n                {\n                    \"deserializing\",\n                    \"serialization_ctor\",\n                    \"deserialized\",\n                    \"deserialization\"\n                },\n                result.History);\n            Assert.Equal(input.Payload, result.Payload, StringComparer.Ordinal);\n            Assert.Equal(3, result.Contexts.Count);\n        }\n\n        /// <summary>\n        /// Tests that <see cref=\"DotNetSerializableCodec\"/> can correctly serialize structs.\n        /// </summary>\n        [Fact]\n        public void ISerializableStructWithCallbacks()\n        {\n            var input = new SimpleISerializableStruct\n            {\n                Payload = \"pyjamas\"\n            };\n\n            // Verify that our behavior conforms to our expected behavior.\n            var result = (SimpleISerializableStruct)SerializationLoop(input);\n            Assert.Equal(\n                new[]\n                {\n                    \"serialization_ctor\",\n                    \"deserialized\",\n                    \"deserialization\"\n                },\n                result.History);\n            Assert.Equal(input.Payload, result.Payload, StringComparer.Ordinal);\n            Assert.Equal(2, result.Contexts.Count);\n        }\n\n        private class BaseException : Exception\n        {\n            public BaseException() { }\n\n            public BaseException(string message, Exception innerException) : base(message, innerException) { }\n#if NET8_0_OR_GREATER\n            [Obsolete]\n#endif\n            protected BaseException(SerializationInfo info, StreamingContext context) : base(info, context)\n            {\n                BaseField = (SimpleISerializableObject)info.GetValue(\"BaseField\", typeof(SimpleISerializableObject));\n            }\n\n            public SimpleISerializableObject BaseField { get; set; }\n\n#if NET8_0_OR_GREATER\n            [Obsolete]\n#endif\n            public override void GetObjectData(SerializationInfo info, StreamingContext context)\n            {\n                base.GetObjectData(info, context);\n                info.AddValue(\"BaseField\", BaseField, typeof(SimpleISerializableObject));\n            }\n        }\n\n        [Serializable]\n        private class UnserializableConformingException : BaseException\n        {\n            public string SubClassField { get; set; }\n            public object SomeObject { get; set; }\n\n            public UnserializableConformingException(string message, Exception innerException) : base(message, innerException) { }\n\n#if NET8_0_OR_GREATER\n            [Obsolete]\n#endif\n            protected UnserializableConformingException(SerializationInfo info, StreamingContext context) : base(info, context)\n            {\n                SubClassField = info.GetString(\"SubClassField\");\n                SomeObject = info.GetValue(\"SomeObject\", typeof(object));\n            }\n\n#if NET8_0_OR_GREATER\n            [Obsolete]\n#endif\n            public override void GetObjectData(SerializationInfo info, StreamingContext context)\n            {\n                base.GetObjectData(info, context);\n                info.AddValue(\"SubClassField\", SubClassField);\n                info.AddValue(\"SomeObject\", SomeObject, typeof(object));\n            }\n        }\n\n        public class UnserializableNonConformingException : Exception\n        {\n            public UnserializableNonConformingException(string message) : base(message)\n            { }\n        }\n\n        private class BanningTypeResolver : TypeResolver\n        {\n            private readonly TypeResolver _resolver = new CachedTypeResolver();\n            private readonly HashSet<Type> _blockedTypes;\n\n            public BanningTypeResolver(params Type[] blockedTypes)\n            {\n                _blockedTypes = new HashSet<Type>();\n                foreach (var type in blockedTypes ?? Array.Empty<Type>())\n                {\n                    _blockedTypes.Add(type);\n                }\n            }\n\n            public override Type ResolveType(string name)\n            {\n                var result = _resolver.ResolveType(name);\n                if (_blockedTypes.Contains(result))\n                {\n                    result = null;\n                }\n\n                return result;\n            }\n\n            public override bool TryResolveType(string name, out Type type)\n            {\n                if (_resolver.TryResolveType(name, out type))\n                {\n                    if (_blockedTypes.Contains(type))\n                    {\n                        type = null;\n                        return false;\n                    }\n\n                    return true;\n                }\n\n                return false;\n            }\n        }\n\n        [Fact]\n        public void Serialize_UnserializableException()\n        {\n            const string message = \"This is a test message\";\n\n            var serializer = _serviceProvider.GetRequiredService<Serializer>();\n\n            // Throw the exception so that stack trace is populated\n            Exception source = Assert.Throws<UnserializableNonConformingException>((Action)(() =>\n            {\n                throw new UnserializableNonConformingException(message);\n            }));\n\n            var serialized = serializer.SerializeToArray(source);\n            using var formatterSession = _sessionPool.GetSession();\n            var formatted = BitStreamFormatter.Format(serialized, formatterSession);\n\n            object deserialized = serializer.Deserialize<Exception>(serialized);\n\n            // Type is wrong after round trip of unserializable exception\n            var result = Assert.IsAssignableFrom<UnavailableExceptionFallbackException>(deserialized);\n\n            // Exception message is correct after round trip of unserializable exception\n            Assert.Contains(message, result.Message);\n            Assert.Equal(RuntimeTypeNameFormatter.Format(source.GetType()), result.ExceptionType);\n\n            // Throw the exception so that stack trace is populated\n            source = Assert.Throws<UnserializableConformingException>((Action)(() =>\n            {\n                Exception inner;\n                try\n                {\n                    throw new InvalidOperationException(\"invalid\");\n                }\n                catch (Exception exception)\n                {\n                    inner = exception;\n                }\n\n                throw new UnserializableConformingException(message, inner)\n                {\n                    SomeObject = new object(),\n                    SubClassField = \"hoppo\",\n                    BaseField = new SimpleISerializableObject() { Payload = \"payload\" }\n                };\n            }));\n            deserialized = serializer.Deserialize<Exception>(serializer.SerializeToArray(source));\n\n            // Type is wrong after round trip of unserializable exception\n            result = Assert.IsAssignableFrom<UnavailableExceptionFallbackException>(deserialized);\n\n            // Exception message is correct after round trip of unserializable exception\n            Assert.Contains(message, result.Message);\n            Assert.Equal(RuntimeTypeNameFormatter.Format(source.GetType()), result.ExceptionType);\n\n            var inner = Assert.IsType<InvalidOperationException>(result.InnerException);\n            Assert.Equal(\"invalid\", inner.Message);\n\n            Assert.True(result.Properties.ContainsKey(\"SomeObject\"));\n            var baseField = Assert.IsType<SimpleISerializableObject>(result.Properties[\"BaseField\"]);\n            Assert.Equal(\"payload\", baseField.Payload);\n        }\n\n        [Serializable]\n        public class SimpleISerializableObject : ISerializable, IDeserializationCallback\n        {\n            private List<string> _history;\n            private List<StreamingContext> _contexts;\n\n            public SimpleISerializableObject()\n            {\n                History.Add(\"default_ctor\");\n            }\n\n            public SimpleISerializableObject(SerializationInfo info, StreamingContext context)\n            {\n                History.Add(\"serialization_ctor\");\n                Contexts.Add(context);\n                Payload = info.GetString(nameof(Payload));\n            }\n\n            public List<string> History => _history ??= new List<string>();\n            public List<StreamingContext> Contexts => _contexts ??= new List<StreamingContext>();\n\n            public string Payload { get; set; }\n\n            public void GetObjectData(SerializationInfo info, StreamingContext context)\n            {\n                Contexts.Add(context);\n                info.AddValue(nameof(Payload), Payload);\n            }\n\n            [OnSerializing]\n            internal void OnSerializingMethod(StreamingContext context)\n            {\n                History.Add(\"serializing\");\n                Contexts.Add(context);\n            }\n\n            [OnSerialized]\n            internal void OnSerializedMethod(StreamingContext context)\n            {\n                History.Add(\"serialized\");\n                Contexts.Add(context);\n            }\n\n            [OnDeserializing]\n            internal void OnDeserializingMethod(StreamingContext context)\n            {\n                History.Add(\"deserializing\");\n                Contexts.Add(context);\n            }\n\n            [OnDeserialized]\n            internal void OnDeserializedMethod(StreamingContext context)\n            {\n                History.Add(\"deserialized\");\n                Contexts.Add(context);\n            }\n\n            void IDeserializationCallback.OnDeserialization(object sender) => History.Add(\"deserialization\");\n        }\n\n        [Serializable]\n        public struct SimpleISerializableStruct : ISerializable, IDeserializationCallback\n        {\n            private List<string> _history;\n            private List<StreamingContext> _contexts;\n\n            public SimpleISerializableStruct(SerializationInfo info, StreamingContext context)\n            {\n                _history = null;\n                _contexts = null;\n                Payload = info.GetString(nameof(Payload));\n                History.Add(\"serialization_ctor\");\n                Contexts.Add(context);\n            }\n\n            public List<string> History => _history ??= new List<string>();\n            public List<StreamingContext> Contexts => _contexts ??= new List<StreamingContext>();\n\n            public string Payload { get; set; }\n\n            public void GetObjectData(SerializationInfo info, StreamingContext context)\n            {\n                Contexts.Add(context);\n                info.AddValue(nameof(Payload), Payload);\n            }\n\n            [OnSerializing]\n            internal void OnSerializingMethod(StreamingContext context)\n            {\n                History.Add(\"serializing\");\n                Contexts.Add(context);\n            }\n\n            [OnSerialized]\n            internal void OnSerializedMethod(StreamingContext context)\n            {\n                History.Add(\"serialized\");\n                Contexts.Add(context);\n            }\n\n            [OnDeserializing]\n            internal void OnDeserializingMethod(StreamingContext context)\n            {\n                History.Add(\"deserializing\");\n                Contexts.Add(context);\n            }\n\n            [OnDeserialized]\n            internal void OnDeserializedMethod(StreamingContext context)\n            {\n                History.Add(\"deserialized\");\n                Contexts.Add(context);\n            }\n\n            void IDeserializationCallback.OnDeserialization(object sender) => History.Add(\"deserialization\");\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/InvokableTestInterfaces.cs",
    "content": "using Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.UnitTests;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\npublic interface IHasNoNamespace : IMyInvokableBaseType \n{\n}\n\nnamespace Orleans.Serialization.UnitTests\n{\n    [Alias(\"_my_proxy_base_\")]\n    [DefaultInvokableBaseType(typeof(ValueTask<>), typeof(UnitTestRequest<>))]\n    [DefaultInvokableBaseType(typeof(ValueTask), typeof(UnitTestRequest))]\n    [DefaultInvokableBaseType(typeof(Task<>), typeof(UnitTestTaskRequest<>))]\n    [DefaultInvokableBaseType(typeof(Task), typeof(UnitTestTaskRequest))]\n    [DefaultInvokableBaseType(typeof(void), typeof(UnitTestVoidRequest))]\n    public abstract class MyInvokableProxyBase\n    {\n        public Action<IInvokable> OnInvoke { get; set; }\n\n        protected MyInvokableProxyBase(CopyContextPool copyContextPool, CodecProvider codecProvider)\n        {\n            CopyContextPool = copyContextPool;\n            CodecProvider = codecProvider;\n        }\n\n        protected TInvokable GetInvokable<TInvokable>() where TInvokable : class, IInvokable, new() => InvokablePool.Get<TInvokable>();\n\n        protected ValueTask<T> InvokeAsync<T>(IInvokable body)\n        {\n            OnInvoke?.Invoke(body);\n            return default;\n        }\n\n        protected ValueTask InvokeAsync(IInvokable body)\n        {\n            OnInvoke?.Invoke(body);\n            return default;\n        }\n\n        protected CopyContextPool CopyContextPool { get; }\n\n        protected CodecProvider CodecProvider { get; }\n    }\n\n    [Alias(\"groan\")]\n    [DefaultInvokableBaseType(typeof(ValueTask<>), typeof(UnitTestRequest<>))]\n    [DefaultInvokableBaseType(typeof(ValueTask), typeof(UnitTestRequest))]\n    [DefaultInvokableBaseType(typeof(Task<>), typeof(UnitTestTaskRequest<>))]\n    [DefaultInvokableBaseType(typeof(Task), typeof(UnitTestTaskRequest))]\n    [DefaultInvokableBaseType(typeof(void), typeof(UnitTestVoidRequest))]\n    public abstract class AltInvokableProxyBase\n    {\n        protected TInvokable GetInvokable<TInvokable>() where TInvokable : class, IInvokable, new() => InvokablePool.Get<TInvokable>();\n\n        protected ValueTask<T> InvokeAsync<T>(IInvokable body) => default;\n\n        protected ValueTask InvokeAsync(IInvokable body) => default;\n\n        protected CopyContextPool CopyContextPool { get; }\n\n        protected CodecProvider CodecProvider { get; }\n    }\n\n    [Alias(\"my_interface\")]\n    [GenerateMethodSerializers(typeof(MyInvokableProxyBase))]\n    public interface IMyInvokableBaseType\n    {\n    }\n\n    [Alias(\"_proxy_alias_test_\")]\n    [GenerateMethodSerializers(typeof(MyInvokableProxyBase))]\n    public interface IProxyAliasTestGrain\n    {\n        [Id(125)]\n        ValueTask Method();\n\n        [Alias(\"Method\")]\n        ValueTask Method(int a);\n\n        [Alias(\"StringMethod\")]\n        ValueTask Method(string a);\n\n        [Alias(\"MyOtherMethod\")]\n        ValueTask OtherMethod();\n    }\n\n    [Alias(\"test.IGenericProxyAliasTestGrain`3\"), GenerateMethodSerializers(typeof(MyInvokableProxyBase))]\n    public interface IGenericProxyAliasTestGrain<T, U, V>\n    {\n        [Id(777)]\n        ValueTask Method<W, X, Y>();\n    }\n\n    public interface IG2<T1, T2> : IMyInvokableBaseType \n    { }\n\n    public class HalfOpenGrain1<T> : IG2<T, int>\n    { }\n    public class HalfOpenGrain2<T> : IG2<int, T>\n    { }\n\n    public class OpenGeneric<T2, T1> : IG2<T2, T1>\n    { }\n\n    public class ClosedGeneric : IG2<Dummy1, Dummy2>\n    { }\n\n    public class ClosedGenericWithManyInterfaces : IG2<Dummy1, Dummy2>, IG2<Dummy2, Dummy1>\n    { }\n\n    public class Dummy1 { }\n\n    public class Dummy2 { }\n\n    public interface IG<T> : IMyInvokableBaseType \n    {\n    }\n\n    public class G1<T1, T2, T3, T4> : Root<T1>.IA<T2, T3, T4>\n    {\n    }\n\n    public class Root<TRoot>\n    {\n        public interface IA<T1, T2, T3> : IMyInvokableBaseType \n        {\n\n        }\n\n        public class G<T1, T2, T3> : IG<IA<T1, T2, T3>>\n        {\n        }\n    }\n\n    public interface IGrainWithGenericMethods : IMyInvokableBaseType \n    {\n        Task<Type[]> GetTypesExplicit<T, U, V>();\n        Task<Type[]> GetTypesInferred<T, U, V>(T t, U u, V v);\n        Task<Type[]> GetTypesInferred<T, U>(T t, U u, int v);\n        Task<T> RoundTrip<T>(T val);\n        Task<int> RoundTrip(int val);\n        Task<T> Default<T>();\n        Task<string> Default();\n        Task<TGrain> Constraints<TGrain>(TGrain grain) where TGrain : IMyInvokableBaseType;\n        ValueTask<int> ValueTaskMethod(bool useCache);\n    }\n\n    public class GrainWithGenericMethods : IGrainWithGenericMethods\n    {\n        private object state;\n\n        public Task<Type[]> GetTypesExplicit<T, U, V>()\n        {\n            return Task.FromResult(new[] {typeof(T), typeof(U), typeof(V)});\n        }\n\n        public Task<Type[]> GetTypesInferred<T, U, V>(T t, U u, V v)\n        {\n            return Task.FromResult(new[] { typeof(T), typeof(U), typeof(V) });\n        }\n\n        public Task<Type[]> GetTypesInferred<T, U>(T t, U u, int v)\n        {\n            return Task.FromResult(new[] { typeof(T), typeof(U) });\n        }\n\n        public Task<T> RoundTrip<T>(T val)\n        {\n            return Task.FromResult(val);\n        }\n\n        public Task<int> RoundTrip(int val)\n        {\n            return Task.FromResult(-val);\n        }\n\n        public Task<T> Default<T>()\n        {\n            return Task.FromResult(default(T));\n        }\n\n        public Task<string> Default()\n        {\n            return Task.FromResult(\"default string\");\n        }\n\n        public Task<TGrain> Constraints<TGrain>(TGrain grain) where TGrain : IMyInvokableBaseType \n        {\n            return Task.FromResult(grain);\n        }\n\n        public void SetValue<T>(T value)\n        {\n            this.state = value;\n        }\n\n        public Task<T> GetValue<T>() => Task.FromResult((T) this.state);\n\n        public ValueTask<int> ValueTaskMethod(bool useCache)\n        {\n            if (useCache)\n            {\n                return new ValueTask<int>(1);\n            }\n\n            return new ValueTask<int>(Task.FromResult(2));\n        }\n    }\n\n    public interface IGenericGrainWithGenericMethods<T> : IMyInvokableBaseType \n    {\n        Task<T> Method(T value);\n#pragma warning disable 693\n        Task<T> Method<T>(T value);\n#pragma warning restore 693\n    }\n\n    public interface IRuntimeCodeGenGrain<T> : IMyInvokableBaseType\n    {\n        /// <summary>\n        /// Sets and returns the grain's state.\n        /// </summary>\n        /// <param name=\"value\">The new state.</param>\n        /// <returns>The current state.</returns>\n        Task<T> SetState(T value);\n\n        /// <summary>\n        /// Tests that code generation correctly handles methods with reserved keyword identifiers.\n        /// </summary>\n        /// <returns>The current state's event.</returns>\n        Task<@event> @static();\n    }\n\n    [Serializable]\n    [GenerateSerializer]\n    public class GenericGrainState<T>\n    {\n        [Id(1)]\n        public T @event { get; set; }\n    }\n\n    /// <summary>\n    /// A class designed to test that code generation correctly handles reserved keywords.\n    /// </summary>\n    [GenerateSerializer]\n    public class @event : IEquatable<@event>\n    {\n        private static readonly IEqualityComparer<@event> EventComparerInstance = new EventEqualityComparer();\n\n        public enum @enum\n        {\n            @async,\n            @int,\n        }\n\n        /// <summary>\n        /// A public field.\n        /// </summary>\n        [Id(0)]\n        public Guid Id;\n\n        /// <summary>\n        /// A private field.\n        /// </summary>\n        [Id(1)]\n        private Guid privateId;\n\n        /// <summary>\n        /// A property with a reserved keyword type and identifier.\n        /// </summary>\n        [Id(2)]\n        public @event @public { get; set; }\n\n        /// <summary>\n        /// Gets or sets the enum.\n        /// </summary>\n        [Id(3)]\n        public @enum Enum { get; set; }\n\n        /// <summary>\n        /// A property with a reserved keyword generic type and identifier.\n        /// </summary>\n        [Id(4)]\n        public List<@event> @if { get; set; }\n\n        public static IEqualityComparer<@event> EventComparer\n        {\n            get\n            {\n                return EventComparerInstance;\n            }\n        }\n\n        /// <summary>\n        /// Gets or sets the private id.\n        /// </summary>\n        // ReSharper disable once ConvertToAutoProperty\n        public Guid PrivateId\n        {\n            get\n            {\n                return this.privateId;\n            }\n\n            set\n            {\n                this.privateId = value;\n            }\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj))\n            {\n                return false;\n            }\n            if (ReferenceEquals(this, obj))\n            {\n                return true;\n            }\n            if (obj.GetType() != this.GetType())\n            {\n                return false;\n            }\n\n            return this.Equals((@event)obj);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                var hashCode = (this.@if != null ? this.@if.GetHashCode() : 0);\n                hashCode = (hashCode * 397) ^ (this.@public != null ? this.@public.GetHashCode() : 0);\n                hashCode = (hashCode * 397) ^ this.privateId.GetHashCode();\n                hashCode = (hashCode * 397) ^ this.Id.GetHashCode();\n                return hashCode;\n            }\n        }\n\n        public bool Equals(@event other)\n        {\n            if (ReferenceEquals(null, other))\n            {\n                return false;\n            }\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n            if (this.@if != other.@if)\n            {\n                if (this.@if != null && !this.@if.SequenceEqual(other.@if, EventComparer))\n                {\n                    return false;\n                }\n            }\n\n            if (!Equals(this.@public, other.@public))\n            {\n                if (this.@public != null && !this.@public.Equals(other.@public))\n                {\n                    return false;\n                }\n            }\n\n            return this.privateId.Equals(other.privateId) && this.Id.Equals(other.Id) && this.Enum == other.Enum;\n        }\n\n        private sealed class EventEqualityComparer : IEqualityComparer<@event>\n        {\n            public bool Equals(@event x, @event y)\n            {\n                return x.Equals(y);\n            }\n\n            public int GetHashCode(@event obj)\n            {\n                return obj.GetHashCode();\n            }\n        }\n    }\n\n    [GenerateSerializer]\n    public class NestedGeneric<T>\n    {\n        [Id(0)]\n        public Nested Payload { get; set; }\n\n        [GenerateSerializer]\n        public class Nested\n        {\n            [Id(0)]\n            public T Value { get; set; }\n        }\n    }\n\n    [GenerateSerializer]\n    public class NestedConstructedGeneric\n    {\n        [Id(0)]\n        public Nested<int> Payload { get; set; }\n\n        [GenerateSerializer]\n        public class Nested<T>\n        {\n            [Id(0)]\n            public T Value { get; set; }\n        }\n    }\n\n    public interface INestedGenericGrain : IMyInvokableBaseType \n    {\n        Task<int> Do(NestedGeneric<int> value);\n        Task<int> Do(NestedConstructedGeneric value);\n    }\n\n    /// <summary>\n    /// Tests that nested classes do not fail code generation.\n    /// </summary>\n    public class NestedGenericGrain : INestedGenericGrain\n    {\n        public Task<int> Do(NestedGeneric<int> value)\n        {\n            return Task.FromResult(value.Payload.Value);\n        }\n\n        public Task<int> Do(NestedConstructedGeneric value)\n        {\n            return Task.FromResult(value.Payload.Value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ManualVersionToleranceTests.cs",
    "content": "using Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.GeneratedCodeHelpers;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.Session;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Buffers;\nusing System.IO.Pipelines;\nusing System.Text;\nusing Xunit;\nusing Xunit.Abstractions;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' version tolerance capabilities in serialization.\n    /// \n    /// Version tolerance is a critical feature of Orleans that allows:\n    /// - Adding new fields to types without breaking existing serialized data\n    /// - Removing fields gracefully (old data with removed fields can still be deserialized)\n    /// - Changing type hierarchies while maintaining compatibility\n    /// - Rolling upgrades in distributed systems without downtime\n    /// \n    /// Orleans achieves version tolerance through:\n    /// - Field-based serialization (not order-dependent)\n    /// - Explicit field IDs that remain stable across versions\n    /// - Graceful handling of unknown fields during deserialization\n    /// - Support for schema evolution patterns\n    /// </summary>\n    public class ManualVersionToleranceTests\n    {\n        private const string TestString = \"hello, Orleans.Serialization\";\n        private readonly ITestOutputHelper _log;\n        private readonly IServiceProvider _serviceProvider;\n        private readonly CodecProvider _codecProvider;\n        private readonly IFieldCodec<SubType> _serializer;\n        private readonly ServiceCollection _serviceCollection;\n\n        public ManualVersionToleranceTests(ITestOutputHelper log)\n        {\n            _log = log;\n            var serviceCollection = new ServiceCollection();\n            _serviceCollection = serviceCollection;\n            _ = _serviceCollection.AddSerializer(builder =>\n              {\n                  _ = builder.Configure(configuration =>\n                    {\n                        _ = configuration.Serializers.Add(typeof(SubTypeSerializer));\n                        _ = configuration.Serializers.Add(typeof(BaseTypeSerializer));\n                        _ = configuration.Serializers.Add(typeof(ObjectWithNewFieldTypeSerializer));\n                        _ = configuration.Serializers.Add(typeof(ObjectWithoutNewFieldTypeSerializer));\n\n                        // Intentionally remove the generated serializer for these type. It will be added back during tests.\n                        configuration.Serializers.RemoveWhere(s => typeof(IFieldCodec<ObjectWithNewField>).IsAssignableFrom(s));\n                        configuration.Serializers.RemoveWhere(s => typeof(IFieldCodec<ObjectWithoutNewField>).IsAssignableFrom(s));\n                    });\n              });\n\n            _serviceProvider = _serviceCollection.BuildServiceProvider();\n\n            _codecProvider = _serviceProvider.GetRequiredService<CodecProvider>();\n            _serializer = _codecProvider.GetCodec<SubType>();\n        }\n\n        [Fact]\n        public void VersionTolerance_RoundTrip_Tests()\n        {\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = \"HOHOHO\",\n                    AddedLaterString = TestString,\n                    String = null,\n                    Int = 1,\n                    Ref = TestString\n                });\n\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = \"base\",\n                    String = \"sub\",\n                    Int = 2,\n                });\n\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = \"base\",\n                    String = \"sub\",\n                    Int = int.MinValue,\n                });\n\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = TestString,\n                    String = TestString,\n                    Int = 10\n                });\n\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = TestString,\n                    String = null,\n                    Int = 1\n                });\n\n            RoundTripTest(\n                new SubType\n                {\n                    BaseTypeString = TestString,\n                    String = null,\n                    Int = 1\n                });\n\n            TestSkip(\n                new SubType\n                {\n                    BaseTypeString = TestString,\n                    String = null,\n                    Int = 1\n                });\n\n            var self = new SubType\n            {\n                BaseTypeString = \"HOHOHO\",\n                AddedLaterString = TestString,\n                String = null,\n                Int = 1\n            };\n            self.Ref = self;\n            RoundTripTest(self, assertRef: false);\n\n            self.Ref = Guid.NewGuid();\n            RoundTripTest(self, assertRef: false);\n        }\n\n        private SerializerSession GetSession() => _serviceProvider.GetRequiredService<SerializerSessionPool>().GetSession();\n\n        private void RoundTripTest(SubType expected, bool assertRef = true)\n        {\n            using var writerSession = GetSession();\n            var pipe = new Pipe();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n\n            _serializer.WriteField(ref writer, 0, typeof(SubType), expected);\n            writer.Commit();\n\n            _log.WriteLine($\"Size: {writer.Position} bytes.\");\n            _log.WriteLine($\"Wrote References:\\n{GetWriteReferenceTable(writerSession)}\");\n\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            pipe.Writer.Complete();\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSesssion = GetSession();\n            var reader = Reader.Create(readResult.Buffer, readerSesssion);\n            var initialHeader = reader.ReadFieldHeader();\n\n            _log.WriteLine(\"Header:\");\n            _log.WriteLine(initialHeader.ToString());\n\n            var actual = _serializer.ReadValue(ref reader, initialHeader);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n\n            _log.WriteLine($\"Expect: {expected}\\nActual: {actual}\");\n\n            Assert.Equal(expected.BaseTypeString, actual.BaseTypeString);\n            Assert.Null(actual.AddedLaterString); // The deserializer isn't 'aware' of this field which was added later - version tolerance.\n            Assert.Equal(expected.String, actual.String);\n            Assert.Equal(expected.Int, actual.Int);\n            if (assertRef)\n            {\n                Assert.Equal(expected.Ref, actual.Ref);\n            }\n            Assert.Equal(writer.Position, reader.Position);\n            Assert.Equal(writer.Session.ReferencedObjects.CurrentReferenceId, reader.Session.ReferencedObjects.CurrentReferenceId);\n\n            var references = GetReadReferenceTable(reader.Session);\n            _log.WriteLine($\"Read references:\\n{references}\");\n        }\n\n        private void TestSkip(SubType expected)\n        {\n            using var writerSession = GetSession();\n            var pipe = new Pipe();\n            var writer = Writer.Create(pipe.Writer, writerSession);\n\n            _serializer.WriteField(ref writer, 0, typeof(SubType), expected);\n            writer.Commit();\n\n            _ = pipe.Writer.FlushAsync().AsTask().GetAwaiter().GetResult();\n            var objectWithNewFieldSerializer = _codecProvider.GetCodec<ObjectWithNewField>();\n            var objectWithoutNewFieldSerializer = _codecProvider.GetCodec<ObjectWithoutNewField>();\n            pipe.Writer.Complete();\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = GetSession();\n            var reader = Reader.Create(readResult.Buffer, readerSession);\n            var initialHeader = reader.ReadFieldHeader();\n            var skipCodec = new SkipFieldCodec();\n            _ = skipCodec.ReadValue(ref reader, initialHeader);\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n            Assert.Equal(writer.Session.ReferencedObjects.CurrentReferenceId, reader.Session.ReferencedObjects.CurrentReferenceId);\n            _log.WriteLine($\"Skipped {reader.Position} bytes.\");\n        }\n\n        private static StringBuilder GetReadReferenceTable(SerializerSession session)\n        {\n            var table = session.ReferencedObjects.CopyReferenceTable();\n            var references = new StringBuilder();\n            foreach (var entry in table)\n            {\n                _ = references.AppendLine($\"\\t[{entry.Key}] {entry.Value}\");\n            }\n            return references;\n        }\n\n        private static StringBuilder GetWriteReferenceTable(SerializerSession session)\n        {\n            var table = session.ReferencedObjects.CopyIdTable();\n            var references = new StringBuilder();\n            foreach (var entry in table)\n            {\n                _ = references.AppendLine($\"\\t[{entry.Value}] {entry.Key}\");\n            }\n            return references;\n        }\n\n        [Fact]\n        public async Task ObjectWithNewFieldTest()\n        {\n            var expected = new ObjectWithNewField(\"blah\", newField: \"this field will not be manually serialized -- the binary will not have it!\");\n            var pipe = new Pipe();\n\n            // Using manual serializer that ignores ObjectWithNewField.NewField\n            // not serializing NewField to simulate a binary that's created from a previous version of the object\n            var objectWithNewFieldSerializer = _codecProvider.GetCodec<ObjectWithNewField>();\n            var objectWithoutNewFieldSerializer = _codecProvider.GetCodec<ObjectWithoutNewField>();\n            _ = Assert.IsType<ConcreteTypeSerializer<ObjectWithNewField, ObjectWithNewFieldTypeSerializer>>(objectWithNewFieldSerializer);\n\n            var (writerPosition, writerCurrentReferenceId) = WriteToPipe();\n            (int WriterPosition, uint CurrentReferenceId) WriteToPipe()\n            {\n                using var writerSession = GetSession();\n                var writer = Writer.Create(pipe.Writer, writerSession);\n                objectWithNewFieldSerializer.WriteField(ref writer, 0, typeof(ObjectWithNewField), expected);\n                writer.Commit();\n\n                _log.WriteLine($\"Size: {writer.Position} bytes.\");\n                _log.WriteLine($\"Wrote References:\\n{GetWriteReferenceTable(writerSession)}\");\n                return (writer.Position, writer.Session.ReferencedObjects.CurrentReferenceId);\n            }\n\n            _ = await pipe.Writer.FlushAsync();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = GetSession();\n            var (actual, readerPosition, readerCurrentReferenceId) = ReadValue();\n            (ObjectWithNewField Value, long ReaderPosition, uint CurrentReferenceId) ReadValue()\n            {\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var initialHeader = reader.ReadFieldHeader();\n\n                _log.WriteLine(\"Header:\");\n                _log.WriteLine(initialHeader.ToString());\n\n                GetGeneratedSerializer(out objectWithNewFieldSerializer);\n                Assert.IsNotType<ConcreteTypeSerializer<ObjectWithNewField, ObjectWithNewFieldTypeSerializer>>(objectWithNewFieldSerializer);\n\n                // using Generated Deserializer, which is capable of deserializing NewField \n                var value = objectWithNewFieldSerializer.ReadValue(ref reader, initialHeader);\n                return (value, reader.Position, reader.Session.ReferencedObjects.CurrentReferenceId);\n            }\n\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n\n            _log.WriteLine($\"Expect: {expected}\\nActual: {actual}\");\n\n            Assert.Equal(expected.Blah, actual.Blah);\n            objectWithNewFieldSerializer = _codecProvider.GetCodec<ObjectWithNewField>();\n            objectWithoutNewFieldSerializer = _codecProvider.GetCodec<ObjectWithoutNewField>();\n            Assert.Null(actual.NewField); // Null, since it should not be in the binary\n            Assert.Equal(expected.Version, actual.Version);\n            Assert.Equal(writerPosition, readerPosition);\n            Assert.Equal(writerCurrentReferenceId, readerCurrentReferenceId);\n\n            var references = GetReadReferenceTable(readerSession);\n            _log.WriteLine($\"Read references:\\n{references}\");\n        }\n\n        [Fact]\n        public async Task ObjectWithoutNewFieldTest()\n        {\n            var expected = new ObjectWithoutNewField(\"blah\");\n\n            using var writerSession = GetSession();\n            var pipe = new Pipe();\n\n            var objectWithNewFieldSerializer = _codecProvider.GetCodec<ObjectWithNewField>();\n            var objectWithoutNewFieldSerializer = _codecProvider.GetCodec<ObjectWithoutNewField>();\n            // Using a manual serializer that writes a new field\n            // serializing a new field to simulate a binary that created from a newer version of the object\n            _ = Assert.IsType<ConcreteTypeSerializer<ObjectWithoutNewField, ObjectWithoutNewFieldTypeSerializer>>(objectWithoutNewFieldSerializer);\n\n            var (writerPosition, writerCurrentReferenceId) = WriteToPipe();\n            (int WriterPosition, uint CurrentReferenceId) WriteToPipe()\n            {\n                var writer = Writer.Create(pipe.Writer, writerSession);\n                objectWithoutNewFieldSerializer.WriteField(ref writer, 0, typeof(ObjectWithoutNewField), expected);\n                writer.Commit();\n\n                _log.WriteLine($\"Size: {writer.Position} bytes.\");\n                _log.WriteLine($\"Wrote References:\\n{GetWriteReferenceTable(writerSession)}\");\n                return (writer.Position, writer.Session.ReferencedObjects.CurrentReferenceId);\n            }\n\n            _ = await pipe.Writer.FlushAsync();\n            pipe.Writer.Complete();\n\n            _ = pipe.Reader.TryRead(out var readResult);\n            using var readerSession = GetSession();\n\n            var (actual, readerPosition, readerCurrentReferenceId) = ReadValue();\n            (ObjectWithoutNewField Value, long ReaderPosition, uint CurrentReferenceId) ReadValue()\n            {\n                var reader = Reader.Create(readResult.Buffer, readerSession);\n                var initialHeader = reader.ReadFieldHeader();\n\n                _log.WriteLine(\"Header:\");\n                _log.WriteLine(initialHeader.ToString());\n\n                GetGeneratedSerializer(out objectWithoutNewFieldSerializer);\n                Assert.IsNotType<ConcreteTypeSerializer<ObjectWithoutNewField, ObjectWithoutNewFieldTypeSerializer>>(objectWithoutNewFieldSerializer);\n\n                // using Generated Deserializer, which is not able to deserialize the new field that was serialized\n                var value = objectWithoutNewFieldSerializer.ReadValue(ref reader, initialHeader);\n                return (value, reader.Position, reader.Session.ReferencedObjects.CurrentReferenceId);\n            }\n\n            pipe.Reader.AdvanceTo(readResult.Buffer.End);\n            pipe.Reader.Complete();\n\n            _log.WriteLine($\"Expect: {expected}\\nActual: {actual}\");\n\n            Assert.Equal(expected.Blah, actual.Blah);\n            Assert.Equal(expected.Version, actual.Version);\n            Assert.Equal(writerPosition, readerPosition);\n            Assert.Equal(writerCurrentReferenceId, readerCurrentReferenceId);\n\n            var references = GetReadReferenceTable(readerSession);\n            _log.WriteLine($\"Read references:\\n{references}\");\n        }\n\n        private static void GetGeneratedSerializer<T>(out IFieldCodec<T> serializer)\n        {\n            var services = new ServiceCollection().AddSerializer();\n            var serviceProvider = services.BuildServiceProvider();\n            var codecProvider = serviceProvider.GetRequiredService<CodecProvider>();\n            serializer = codecProvider.GetCodec<T>();\n        }\n\n        [GenerateSerializer]\n        public class ObjectWithNewField\n        {\n            [Id(0)]\n            public string Blah { get; set; }\n            [Id(1)]\n            public object NewField { get; set; }\n            [Id(2)]\n            public int Version { get; set; }\n\n            public ObjectWithNewField(string blah, object newField)\n            {\n                Blah = blah;\n                NewField = newField;\n                Version = 2;\n            }\n\n            public override string ToString() => $\"{nameof(Blah)}: {Blah}; {nameof(NewField)}: {NewField}; {nameof(Version)}: {Version}\";\n        }\n\n        public class ObjectWithNewFieldTypeSerializer : IBaseCodec<ObjectWithNewField>\n        {\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, ObjectWithNewField obj) where TBufferWriter : IBufferWriter<byte>\n            {\n                // not serializing newField to simulate a binary that's created from a previous version of the object\n                StringCodec.WriteField(ref writer, 0, obj.Blah);\n                Int32Codec.WriteField(ref writer, 2, obj.Version);\n            }\n\n            // using a generated deserializer for deserialization\n            public void Deserialize<TInput>(ref Reader<TInput> reader, ObjectWithNewField obj)\n            {\n            }\n        }\n\n        [GenerateSerializer]\n        public class ObjectWithoutNewField\n        {\n            [Id(0)]\n            public string Blah { get; set; }\n            [Id(1)]\n            public int Version { get; set; }\n\n            public ObjectWithoutNewField(string blah)\n            {\n                Blah = blah;\n                Version = 1;\n            }\n\n            public override string ToString() => $\"{nameof(Blah)}: {Blah}; {nameof(Version)}: {Version}\";\n        }\n\n        public class ObjectWithoutNewFieldTypeSerializer : IBaseCodec<ObjectWithoutNewField>\n        {\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, ObjectWithoutNewField obj) where TBufferWriter : IBufferWriter<byte>\n            {\n                StringCodec.WriteField(ref writer, 0, obj.Blah);\n                Int32Codec.WriteField(ref writer, 1, obj.Version);\n                // serializing a new field to simulate a binary that's created from a newer version of the object\n                ObjectCodec.WriteField(ref writer, 6, \"I will be stuck in binary limbo! (I shouldn't be part of the deserialized object)\");\n            }\n\n            // using a generated deserializer for deserialization\n            public void Deserialize<TInput>(ref Reader<TInput> reader, ObjectWithoutNewField obj)\n            {\n            }\n        }\n\n        /// <summary>\n        /// NOTE: The serializer for this type is HAND-ROLLED. See <see cref=\"BaseTypeSerializer\" />\n        /// </summary>\n        public class BaseType : IEquatable<BaseType>\n        {\n            public string BaseTypeString { get; set; }\n            public string AddedLaterString { get; set; }\n\n            public bool Equals(BaseType other) => other is not null\n                    && string.Equals(BaseTypeString, other.BaseTypeString, StringComparison.Ordinal)\n                    && string.Equals(AddedLaterString, other.AddedLaterString, StringComparison.Ordinal);\n\n            public override bool Equals(object obj) => obj is BaseType baseType && Equals(baseType);\n\n            public override int GetHashCode() => HashCode.Combine(BaseTypeString, AddedLaterString);\n\n            public override string ToString() => $\"{nameof(BaseTypeString)}: {BaseTypeString}\";\n        }\n\n        /// <summary>\n        /// NOTE: The serializer for this type is HAND-ROLLED. See <see cref=\"SubTypeSerializer\" />\n        /// </summary>\n        public class SubType : BaseType, IEquatable<SubType>\n        {\n            // 0\n            public string String { get; set; }\n\n            // 1\n            public int Int { get; set; }\n\n            // 3\n            public object Ref { get; set; }\n\n            public bool Equals(SubType other)\n            {\n                if (other is null)\n                {\n                    return false;\n                }\n\n                return\n                    base.Equals(other)\n                    && string.Equals(String, other.String, StringComparison.Ordinal)\n                    && Int == other.Int\n                    && (ReferenceEquals(Ref, other.Ref) || Ref.Equals(other.Ref));\n            }\n\n            public override string ToString()\n            {\n                string refString = Ref == this ? \"[this]\" : $\"[{Ref?.ToString() ?? \"null\"}]\";\n                return $\"{base.ToString()}, {nameof(String)}: {String}, {nameof(Int)}: {Int}, Ref: {refString}\";\n            }\n\n            public override bool Equals(object obj) => obj is SubType subType && Equals(subType);\n\n            public override int GetHashCode()\n            {\n                // Avoid stack overflows with this one weird trick.\n                if (ReferenceEquals(Ref, this))\n                {\n                    return HashCode.Combine(base.GetHashCode(), String, Int);\n                }\n\n                return HashCode.Combine(base.GetHashCode(), String, Int, Ref);\n            }\n        }\n\n        public class SubTypeSerializer : IBaseCodec<SubType>\n        {\n            private readonly IBaseCodec<BaseType> _baseTypeSerializer;\n            private readonly IFieldCodec<string> _stringCodec;\n            private readonly IFieldCodec<int> _intCodec;\n            private readonly IFieldCodec<object> _objectCodec;\n\n            public SubTypeSerializer(IBaseCodec<BaseType> baseTypeSerializer, IFieldCodec<string> stringCodec, IFieldCodec<int> intCodec, IFieldCodec<object> objectCodec)\n            {\n                _baseTypeSerializer = OrleansGeneratedCodeHelper.UnwrapService(this, baseTypeSerializer);\n                _stringCodec = OrleansGeneratedCodeHelper.UnwrapService(this, stringCodec);\n                _intCodec = OrleansGeneratedCodeHelper.UnwrapService(this, intCodec);\n                _objectCodec = OrleansGeneratedCodeHelper.UnwrapService(this, objectCodec);\n            }\n\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, SubType obj) where TBufferWriter : IBufferWriter<byte>\n            {\n                _baseTypeSerializer.Serialize(ref writer, obj);\n                writer.WriteEndBase(); // the base object is complete.\n\n                _stringCodec.WriteField(ref writer, 0, typeof(string), obj.String);\n                _intCodec.WriteField(ref writer, 1, typeof(int), obj.Int);\n                _objectCodec.WriteField(ref writer, 1, typeof(object), obj.Ref);\n                _intCodec.WriteField(ref writer, 1, typeof(int), obj.Int);\n                _intCodec.WriteField(ref writer, 409, typeof(int), obj.Int);\n                /*writer.WriteFieldHeader(session, 1025, typeof(Guid), Guid.Empty.GetType(), WireType.Fixed128);\n                writer.WriteFieldHeader(session, 1020, typeof(object), typeof(Program), WireType.Reference);*/\n            }\n\n            public void Deserialize<TInput>(ref Reader<TInput> reader, SubType obj)\n            {\n                uint fieldId = 0;\n                _baseTypeSerializer.Deserialize(ref reader, obj);\n                while (true)\n                {\n                    var header = reader.ReadFieldHeader();\n                    if (header.IsEndBaseOrEndObject)\n                    {\n                        break;\n                    }\n\n                    fieldId += header.FieldIdDelta;\n                    switch (fieldId)\n                    {\n                        case 0:\n                            obj.String = _stringCodec.ReadValue(ref reader, header);\n                            break;\n                        case 1:\n                            obj.Int = _intCodec.ReadValue(ref reader, header);\n                            break;\n                        case 2:\n                            obj.Ref = _objectCodec.ReadValue(ref reader, header);\n                            break;\n                        default:\n                            reader.ConsumeUnknownField(header);\n                            break;\n                    }\n                }\n            }\n        }\n\n        public class BaseTypeSerializer : IBaseCodec<BaseType>\n        {\n            public void Serialize<TBufferWriter>(ref Writer<TBufferWriter> writer, BaseType obj) where TBufferWriter : IBufferWriter<byte>\n            {\n                StringCodec.WriteField(ref writer, 0, obj.BaseTypeString);\n                StringCodec.WriteField(ref writer, 234, obj.AddedLaterString);\n            }\n\n            public void Deserialize<TInput>(ref Reader<TInput> reader, BaseType obj)\n            {\n                uint fieldId = 0;\n                while (true)\n                {\n                    var header = reader.ReadFieldHeader();\n                    if (header.IsEndBaseOrEndObject)\n                    {\n                        break;\n                    }\n\n                    fieldId += header.FieldIdDelta;\n                    switch (fieldId)\n                    {\n                        case 0:\n                            obj.BaseTypeString = StringCodec.ReadValue(ref reader, header);\n                            break;\n                        default:\n                            reader.ConsumeUnknownField(header);\n                            break;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/MemoryPackSerializerTests.cs",
    "content": "#nullable enable\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TestKit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for Orleans' MemoryPack serialization support.\n/// \n/// MemoryPack is a binary serialization format that provides:\n/// - More compact representation than JSON\n/// - Faster serialization/deserialization than text formats\n/// - Cross-platform and cross-language support\n/// \n/// Orleans' MemoryPack integration:\n/// - Leverages the MemoryPack-CSharp library\n/// - Supports union types (discriminated unions)\n/// - Provides both serialization and deep copy functionality\n/// - Can be used for specific types while using Orleans' native format for others\n/// \n/// This is useful when:\n/// - Interoperating with systems that use MemoryPack\n/// - Requiring a compact binary format with broad language support\n/// - Needing better performance than JSON but more portability than Orleans' native format\n/// </summary>\n[Trait(\"Category\", \"BVT\")]\npublic class MemoryPackCodecTests : FieldCodecTester<MyMemoryPackClass?, IFieldCodec<MyMemoryPackClass?>>\n{\n    public MemoryPackCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMemoryPackSerializer();\n    }\n\n    protected override MyMemoryPackClass? CreateValue() => new() { IntProperty = 30, StringProperty = \"hello\", SubClass = new() { Id = Guid.NewGuid() } };\n\n    protected override MyMemoryPackClass?[] TestValues => new MyMemoryPackClass?[]\n    {\n        null,\n        new() { SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { Union = new MyMemoryPackUnionVariant1 { IntProperty = 1 } },\n        new() { Union = new MyMemoryPackUnionVariant2 { StringProperty = \"String\" } },\n    };\n\n    [Fact]\n    public void MemoryPackSerializerDeepCopyTyped()\n    {\n        var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier<MyMemoryPackClass>>();\n        var result = copier.Copy(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n        Assert.Equal(original.SubClass.Id, result.SubClass.Id);\n    }\n\n    [Fact]\n    public void MemoryPackSerializerDeepCopyUntyped()\n    {\n        var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n        var result = (MyMemoryPackClass)copier.Copy((object)original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n        Assert.Equal(original.SubClass.Id, result.SubClass.Id);\n    }\n\n    [Fact]\n    public void MemoryPackSerializerRoundTripThroughCodec()\n    {\n        var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n\n    [Fact]\n    public void MemoryPackSerializerRoundTripThroughUntypedSerializer()\n    {\n        var original = new MyMemoryPackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var untypedResult = RoundTripThroughUntypedSerializer(original, out _);\n\n        var result = Assert.IsType<MyMemoryPackClass>(untypedResult);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n}\n\n\n[Trait(\"Category\", \"BVT\")]\npublic class MemoryPackUnionCodecTests : FieldCodecTester<IMyMemoryPackUnion?, IFieldCodec<IMyMemoryPackUnion?>>\n{\n    public MemoryPackUnionCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMemoryPackSerializer();\n    }\n\n    protected override IMyMemoryPackUnion? CreateValue() => new MyMemoryPackUnionVariant1() { IntProperty = 30 };\n\n    protected override IMyMemoryPackUnion?[] TestValues => new IMyMemoryPackUnion?[]\n    {\n        null,\n        new MyMemoryPackUnionVariant1 { IntProperty = 1 },\n        new MyMemoryPackUnionVariant2 { StringProperty = \"String\" },\n    };\n}\n\n\n[Trait(\"Category\", \"BVT\")]\npublic class MemoryPackCodecCopierTests : CopierTester<MyMemoryPackClass?, IDeepCopier<MyMemoryPackClass?>>\n{\n    public MemoryPackCodecCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMemoryPackSerializer();\n    }\n    protected override IDeepCopier<MyMemoryPackClass?> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<MyMemoryPackClass?>();\n\n    protected override MyMemoryPackClass? CreateValue() => new() { IntProperty = 30, StringProperty = \"hello\", SubClass = new() { Id = Guid.NewGuid() } };\n\n    protected override MyMemoryPackClass?[] TestValues => new MyMemoryPackClass?[]\n    {\n        null,\n        new() { SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },\n    };\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/MessagePackSerializerTests.cs",
    "content": "#nullable enable\nusing System;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TestKit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for Orleans' MessagePack serialization support.\n/// \n/// MessagePack is a binary serialization format that provides:\n/// - More compact representation than JSON\n/// - Faster serialization/deserialization than text formats\n/// - Cross-platform and cross-language support\n/// \n/// Orleans' MessagePack integration:\n/// - Leverages the MessagePack-CSharp library\n/// - Supports union types (discriminated unions)\n/// - Provides both serialization and deep copy functionality\n/// - Can be used for specific types while using Orleans' native format for others\n/// \n/// This is useful when:\n/// - Interoperating with systems that use MessagePack\n/// - Requiring a compact binary format with broad language support\n/// - Needing better performance than JSON but more portability than Orleans' native format\n/// </summary>\n[Trait(\"Category\", \"BVT\")]\npublic class MessagePackCodecTests : FieldCodecTester<MyMessagePackClass?, IFieldCodec<MyMessagePackClass?>>\n{\n    public MessagePackCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMessagePackSerializer();\n    }\n\n    protected override MyMessagePackClass? CreateValue() => new() { IntProperty = 30, StringProperty = \"hello\", SubClass = new() { Id = Guid.NewGuid() } };\n\n    protected override MyMessagePackClass?[] TestValues => new MyMessagePackClass?[]\n    {\n        null,\n        new() { SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { Union = new MyMessagePackUnionVariant1 { IntProperty = 1 } },\n        new() { Union = new MyMessagePackUnionVariant2 { StringProperty = \"String\" } },\n    };\n\n    [Fact]\n    public void MessagePackSerializerDeepCopyTyped()\n    {\n        var original = new MyMessagePackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier<MyMessagePackClass>>();\n        var result = copier.Copy(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n        Assert.Equal(original.SubClass.Id, result.SubClass.Id);\n    }\n\n    [Fact]\n    public void MessagePackSerializerDeepCopyUntyped()\n    {\n        var original = new MyMessagePackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n        var result = (MyMessagePackClass)copier.Copy((object)original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n        Assert.Equal(original.SubClass.Id, result.SubClass.Id);\n    }\n\n    [Fact]\n    public void MessagePackSerializerRoundTripThroughCodec()\n    {\n        var original = new MyMessagePackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n\n    [Fact]\n    public void MessagePackSerializerRoundTripThroughUntypedSerializer()\n    {\n        var original = new MyMessagePackClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new() { Id = Guid.NewGuid() } };\n        var untypedResult = RoundTripThroughUntypedSerializer(original, out _);\n\n        var result = Assert.IsType<MyMessagePackClass>(untypedResult);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n}\n\n\n[Trait(\"Category\", \"BVT\")]\npublic class MessagePackUnionCodecTests : FieldCodecTester<IMyMessagePackUnion?, IFieldCodec<IMyMessagePackUnion?>>\n{\n    public MessagePackUnionCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMessagePackSerializer();\n    }\n\n    protected override IMyMessagePackUnion? CreateValue() => new MyMessagePackUnionVariant1() { IntProperty = 30 };\n\n    protected override IMyMessagePackUnion?[] TestValues => new IMyMessagePackUnion?[]\n    {\n        null,\n        new MyMessagePackUnionVariant1 { IntProperty = 1 },\n        new MyMessagePackUnionVariant2 { StringProperty = \"String\" },\n    };\n}\n\n\n[Trait(\"Category\", \"BVT\")]\npublic class MessagePackCodecCopierTests : CopierTester<MyMessagePackClass?, IDeepCopier<MyMessagePackClass?>>\n{\n    public MessagePackCodecCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddMessagePackSerializer();\n    }\n    protected override IDeepCopier<MyMessagePackClass?> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<MyMessagePackClass?>();\n\n    protected override MyMessagePackClass? CreateValue() => new() { IntProperty = 30, StringProperty = \"hello\", SubClass = new() { Id = Guid.NewGuid() } };\n\n    protected override MyMessagePackClass?[] TestValues => new MyMessagePackClass?[]\n    {\n        null,\n        new() { SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new() { Id = Guid.NewGuid() } },\n        new() { IntProperty = 150_000, StringProperty = new string('c', 6_000), SubClass = new() { Id = Guid.NewGuid() } },\n    };\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Models.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq.Expressions;\nusing System.Runtime.Serialization;\nusing System.Text.Json;\nusing System.Text.Json.Nodes;\nusing MemoryPack;\nusing MessagePack;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing Orleans;\n\n[Alias(\"test.person.alias\"), GenerateSerializer]\npublic record Person([property: Id(0)] int Age, [property: Id(1)] string Name)\n{\n    [Id(2)]\n    public string FavouriteColor { get; init; }\n\n    [Id(3)]\n    public string StarSign { get; init; }\n}\n\n[GenerateSerializer]\npublic record Person2(int Age, string Name)\n{\n    [Id(0)]\n    public string FavouriteColor { get; init; }\n\n    [Id(1)]\n    public string StarSign { get; init; }\n}\n\n[GenerateSerializer(IncludePrimaryConstructorParameters = false)]\npublic record Person3(int Age, string Name)\n{\n    [Id(0)]\n    public string FavouriteColor { get; init; }\n\n    [Id(1)]\n    public string StarSign { get; init; }\n}\n\n[GenerateSerializer]\npublic record Person4(int Age, string Name);\n\n[GenerateSerializer(IncludePrimaryConstructorParameters = false)]\npublic record Person5([property: Id(0)] int Age, [property: Id(1)] string Name)\n{\n    [Id(2)]\n    public string FavouriteColor { get; init; }\n\n    [Id(3)]\n    public string StarSign { get; init; }\n}\n\n[GenerateSerializer]\npublic class Person5_Class\n{\n    [Id(0)] public int Age { get; init; }\n    [Id(1)] public string Name { get; init; }\n    [Id(2)] public string FavouriteColor { get; init; }\n    [Id(3)] public string StarSign { get; init; }\n}\n\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\npublic sealed class MyJsonSerializableAttribute : Attribute\n{\n}\n\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]\npublic sealed class MyNewtonsoftJsonSerializableAttribute : Attribute\n{\n}\n\ninternal interface IMyBase\n{\n    MyValue BaseValue { get; set; }\n}\n\ninternal interface IMySub : IMyBase\n{\n    MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\npublic class MyValue : IEquatable<MyValue>\n{\n    [Id(0)]\n    public int Value { get; set; }\n\n    public MyValue(int value) => Value = value;\n\n    public static implicit operator int(MyValue value) => value.Value;\n    public static implicit operator MyValue(int value) => new(value);\n\n    public bool Equals(MyValue other)\n    {\n        return other is not null && Value == other.Value;\n    }\n\n    public override bool Equals(object obj)\n    {\n        return Equals(obj as MyValue);\n    }\n\n    public override int GetHashCode() => Value;\n}\n\n[GenerateSerializer]\n[Immutable]\npublic class MyImmutableBase : IMyBase\n{\n    [Id(0)]\n    public MyValue BaseValue { get; set; }\n}\n\n[GenerateSerializer]\npublic sealed class MyMutableSub : MyImmutableBase, IMySub\n{\n    [Id(0)]\n    public MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\n[Immutable]\npublic sealed class MyImmutableSub : MyImmutableBase, IMySub\n{\n    [Id(0)]\n    public MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\npublic class MyMutableBase : IMyBase\n{\n    [Id(0)]\n    public MyValue BaseValue { get; set; }\n}\n\n[GenerateSerializer]\npublic sealed class MySealedSub : MyMutableBase, IMySub\n{\n    [Id(0)]\n    public MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\n[Immutable]\npublic sealed class MySealedImmutableSub : MyMutableBase, IMySub\n{\n    [Id(0)]\n    public MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\n[Immutable]\npublic class MyUnsealedImmutableSub : MyMutableBase, IMySub\n{\n    [Id(0)]\n    public MyValue SubValue { get; set; }\n}\n\n[GenerateSerializer]\n[SuppressReferenceTracking]\npublic class MySuppressReferenceTrackingValue : MyValue\n{\n    public MySuppressReferenceTrackingValue(int value) : base(value)\n    {\n    }\n}\n\n[GenerateSerializer]\npublic class MyCustomException : Exception\n{\n    public MyCustomException() { }\n    public MyCustomException(string message) : base(message) { }\n    public MyCustomException(string message, Exception inner) : base(message, inner) { }\n#if NET8_0_OR_GREATER\n    [Obsolete]\n#endif\n    public MyCustomException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n\n    [Id(0)]\n    public int CustomInt;\n}\n\npublic class MyCustomForeignException : Exception\n{\n    public MyCustomForeignException(int customInt)\n    {\n        CustomInt = customInt;\n    }\n\n#if NET8_0_OR_GREATER\n    [Obsolete]\n#endif\n    public MyCustomForeignException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n\n    [Id(0)]\n    public int CustomInt;\n}\n\n[GenerateSerializer]\npublic struct MyCustomForeignExceptionSurrogate\n{\n    [Id(0)]\n    public int CustomInt { get; set; }\n\n    public MyCustomForeignExceptionSurrogate(int customInt)\n    {\n        CustomInt = customInt;\n    }\n}\n\n[RegisterConverter]\npublic sealed class MyCustomForeignExceptionSurrogateConverter : IConverter<MyCustomForeignException, MyCustomForeignExceptionSurrogate>\n{\n    public MyCustomForeignException ConvertFromSurrogate(in MyCustomForeignExceptionSurrogate surrogate) =>\n        new MyCustomForeignException(surrogate.CustomInt);\n\n    public MyCustomForeignExceptionSurrogate ConvertToSurrogate(in MyCustomForeignException value) =>\n        new MyCustomForeignExceptionSurrogate(value.CustomInt);\n}\n\n[GenerateSerializer]\n[SuppressMessage(\"Usage\", \"ORLEANS0004:Add missing serialization attributes\", Justification = \"Intentional for tests\")]\npublic class SomeClassWithSerializers\n{\n    [Id(0)]\n    public int IntProperty { get; set; }\n\n    [Id(1)] public int IntField;\n\n    public int UnmarkedField;\n\n    public int UnmarkedProperty { get; set; }\n\n    public override string ToString() => $\"{nameof(IntField)}: {IntField}, {nameof(IntProperty)}: {IntProperty}\";\n}\n\nnamespace Orleans.Serialization.UnitTests\n{\n    public class MyForeignLibraryType\n    {\n        public MyForeignLibraryType() { }\n\n        public MyForeignLibraryType(int num, string str, DateTimeOffset dto)\n        {\n            Num = num;\n            String = str;\n            DateTimeOffset = dto;\n        }\n\n        public int Num { get; set; }\n        public string String { get; set; }\n        public DateTimeOffset DateTimeOffset { get; set; }\n\n        public override bool Equals(object obj) =>\n            obj is MyForeignLibraryType type\n            && Num == type.Num\n            && string.Equals(String, type.String, StringComparison.Ordinal)\n            && DateTimeOffset.Equals(type.DateTimeOffset);\n\n        public override int GetHashCode() => HashCode.Combine(Num, String, DateTimeOffset);\n    }\n\n    [GenerateSerializer]\n    public struct MyForeignLibraryTypeSurrogate\n    {\n        [Id(0)]\n        public int Num { get; set; }\n\n        [Id(1)]\n        public string String { get; set; }\n\n        [Id(2)]\n        public DateTimeOffset DateTimeOffset { get; set; }\n    }\n\n    [RegisterConverter]\n    public sealed class MyForeignLibraryTypeSurrogateConverter : IConverter<MyForeignLibraryType, MyForeignLibraryTypeSurrogate>, IPopulator<MyForeignLibraryType, MyForeignLibraryTypeSurrogate>\n    {\n        public MyForeignLibraryType ConvertFromSurrogate(in MyForeignLibraryTypeSurrogate surrogate)\n            => new(surrogate.Num, surrogate.String, surrogate.DateTimeOffset);\n\n        public MyForeignLibraryTypeSurrogate ConvertToSurrogate(in MyForeignLibraryType value)\n            => new() { Num = value.Num, String = value.String, DateTimeOffset = value.DateTimeOffset };\n        public void Populate(in MyForeignLibraryTypeSurrogate surrogate, MyForeignLibraryType value)\n        {\n            value.Num = surrogate.Num;\n            value.String = surrogate.String;\n            value.DateTimeOffset = surrogate.DateTimeOffset;\n        }\n    }\n\n    [GenerateSerializer]\n    public class WrapsMyForeignLibraryType\n    {\n        [Id(0)]\n        public int IntValue { get; set; }\n\n        [Id(1)]\n        public MyForeignLibraryType ForeignValue { get; set; }\n\n        [Id(2)]\n        public int OtherIntValue { get; set; }\n\n        public override bool Equals(object obj) => obj is WrapsMyForeignLibraryType type && IntValue == type.IntValue && EqualityComparer<MyForeignLibraryType>.Default.Equals(ForeignValue, type.ForeignValue) && OtherIntValue == type.OtherIntValue;\n        public override int GetHashCode() => HashCode.Combine(IntValue, ForeignValue, OtherIntValue);\n    }\n\n    [GenerateSerializer]\n    public class DerivedFromMyForeignLibraryType : MyForeignLibraryType\n    {\n        public DerivedFromMyForeignLibraryType() { }\n        public DerivedFromMyForeignLibraryType(int intValue, int num, string str, DateTimeOffset dto) : base(num, str, dto)\n        {\n            IntValue = intValue;\n        }\n\n        [Id(0)]\n        public int IntValue { get; set; }\n\n        public override bool Equals(object obj) => obj is DerivedFromMyForeignLibraryType type && base.Equals(obj) && Num == type.Num && String == type.String && DateTimeOffset.Equals(type.DateTimeOffset) && IntValue == type.IntValue;\n        public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), Num, String, DateTimeOffset, IntValue);\n    }\n\n    public struct MyForeignLibraryValueType\n    {\n        public MyForeignLibraryValueType(int num, string str, DateTimeOffset dto)\n        {\n            Num = num;\n            String = str;\n            DateTimeOffset = dto;\n        }\n\n        public int Num { get; }\n        public string String { get; }\n        public DateTimeOffset DateTimeOffset { get; }\n\n        public override readonly bool Equals(object obj) =>\n            obj is MyForeignLibraryValueType type\n            && Num == type.Num\n            && string.Equals(String, type.String, StringComparison.Ordinal)\n            && DateTimeOffset.Equals(type.DateTimeOffset);\n\n        public override readonly int GetHashCode() => HashCode.Combine(Num, String, DateTimeOffset);\n    }\n\n    [GenerateSerializer]\n    public struct MyForeignLibraryValueTypeSurrogate\n    {\n        [Id(0)]\n        public int Num { get; set; }\n\n        [Id(1)]\n        public string String { get; set; }\n\n        [Id(2)]\n        public DateTimeOffset DateTimeOffset { get; set; }\n    }\n\n    [RegisterConverter]\n    public sealed class MyForeignLibraryValueTypeSurrogateConverter : IConverter<MyForeignLibraryValueType, MyForeignLibraryValueTypeSurrogate>\n    {\n        public MyForeignLibraryValueType ConvertFromSurrogate(in MyForeignLibraryValueTypeSurrogate surrogate)\n            => new(surrogate.Num, surrogate.String, surrogate.DateTimeOffset);\n\n        public MyForeignLibraryValueTypeSurrogate ConvertToSurrogate(in MyForeignLibraryValueType value)\n            => new() { Num = value.Num, String = value.String, DateTimeOffset = value.DateTimeOffset };\n    }\n\n    [GenerateSerializer]\n    public struct WrapsMyForeignLibraryValueType\n    {\n        [Id(0)]\n        public int IntValue { get; set; }\n\n        [Id(1)]\n        public MyForeignLibraryValueType ForeignValue { get; set; }\n\n        [Id(2)]\n        public int OtherIntValue { get; set; }\n\n        public override readonly bool Equals(object obj) => obj is WrapsMyForeignLibraryValueType type && IntValue == type.IntValue && EqualityComparer<MyForeignLibraryValueType>.Default.Equals(ForeignValue, type.ForeignValue) && OtherIntValue == type.OtherIntValue;\n        public override readonly int GetHashCode() => HashCode.Combine(IntValue, ForeignValue, OtherIntValue);\n    }\n\n    [GenerateSerializer]\n    public class MyNonJsonBaseClass : IEquatable<MyNonJsonBaseClass>\n    {\n        [Id(0)]\n        [JsonProperty]\n        public int IntProperty { get; set; }\n\n        public override string ToString() => $\"{nameof(IntProperty)}: {IntProperty}\";\n        public bool Equals(MyNonJsonBaseClass other) => other is not null && (ReferenceEquals(this, other) || other.IntProperty == IntProperty);\n        public override bool Equals(object obj) => Equals(obj as MyNonJsonBaseClass);\n        public override int GetHashCode() => HashCode.Combine(IntProperty);\n    }\n\n    [MyNewtonsoftJsonSerializable]\n    public class MyNewtonsoftJsonClass : MyNonJsonBaseClass, IEquatable<MyNewtonsoftJsonClass>\n    {\n        [JsonProperty]\n        public string SubTypeProperty { get; set; }\n\n        [JsonProperty]\n        public TestId Id { get; set; }\n\n        [JsonProperty]\n        public JArray JsonArray { get; set; } = new JArray(true, 42, \"hello\");\n\n        [JsonProperty]\n        public JObject JsonObject { get; set; } = new() { [\"foo\"] = \"bar\" };\n\n        public override string ToString() => $\"{nameof(SubTypeProperty)}: {SubTypeProperty}, {base.ToString()}\";\n        public bool Equals(MyNewtonsoftJsonClass other) => other is not null && base.Equals(other) && string.Equals(SubTypeProperty, other.SubTypeProperty, StringComparison.Ordinal) && EqualityComparer<TestId>.Default.Equals(Id, other.Id)\n            && string.Equals(JsonConvert.SerializeObject(JsonArray), JsonConvert.SerializeObject(other.JsonArray))\n            && string.Equals(JsonConvert.SerializeObject(JsonObject), JsonConvert.SerializeObject(other.JsonObject));\n        public override bool Equals(object obj) => Equals(obj as MyJsonClass);\n        public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SubTypeProperty);\n    }\n\n    [MyJsonSerializable]\n    public class MyJsonClass : MyNonJsonBaseClass, IEquatable<MyJsonClass>\n    {\n        [JsonProperty]\n        public string SubTypeProperty { get; set; }\n\n        [JsonProperty]\n        public TestId Id { get; set; }\n\n        [JsonProperty]\n        public JsonArray JsonArray { get; set; } = new JsonArray(true, 42, \"hello\");\n\n        [JsonProperty]\n        public JsonObject JsonObject { get; set; } = new() { [\"foo\"] = \"bar\" };\n\n        public override string ToString() => $\"{nameof(SubTypeProperty)}: {SubTypeProperty}, {base.ToString()}\";\n        public bool Equals(MyJsonClass other) => other is not null && base.Equals(other) && string.Equals(SubTypeProperty, other.SubTypeProperty, StringComparison.Ordinal) && EqualityComparer<TestId>.Default.Equals(Id, other.Id)\n            && string.Equals(System.Text.Json.JsonSerializer.Serialize(JsonArray), System.Text.Json.JsonSerializer.Serialize(other.JsonArray))\n            && string.Equals(System.Text.Json.JsonSerializer.Serialize(JsonObject), System.Text.Json.JsonSerializer.Serialize(other.JsonObject));\n        public override bool Equals(object obj) => Equals(obj as MyJsonClass);\n        public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SubTypeProperty);\n    }\n\n    [System.Text.Json.Serialization.JsonConverter(typeof(StronglyTypedIdJsonConverter<TestId, Guid>))]\n    public record TestId(Guid Id) : StronglyTypedId<Guid>(Id);\n\n    public abstract record StronglyTypedId<TValue>(TValue Value)\n        where TValue : notnull\n    {\n        public override string ToString() => Value.ToString() ?? typeof(TValue).ToString();\n    }\n\n    file class StronglyTypedIdJsonConverter<TStronglyTypedId, TValue> : System.Text.Json.Serialization.JsonConverter<TStronglyTypedId>\n        where TStronglyTypedId : StronglyTypedId<TValue>\n        where TValue : notnull\n    {\n        public override TStronglyTypedId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            if (reader.TokenType is JsonTokenType.Null)\n            {\n                return null;\n            }\n\n            var value = System.Text.Json.JsonSerializer.Deserialize<TValue>(ref reader, options);\n            var factory = StronglyTypedIdHelper.GetFactory<TValue>(typeToConvert);\n            return (TStronglyTypedId)factory(value);\n        }\n\n        public override void Write(Utf8JsonWriter writer, TStronglyTypedId value, JsonSerializerOptions options)\n        {\n            if (value is null)\n            {\n                writer.WriteNullValue();\n            }\n            else\n            {\n                System.Text.Json.JsonSerializer.Serialize(writer, value.Value, options);\n            }\n        }\n    }\n\n    file static class StronglyTypedIdHelper\n    {\n        private static readonly ConcurrentDictionary<Type, Delegate> StronglyTypedIdFactories = new();\n\n        public static Func<TValue, object> GetFactory<TValue>(Type stronglyTypedIdType)\n            where TValue : notnull\n        {\n            return (Func<TValue, object>)StronglyTypedIdFactories.GetOrAdd(\n                stronglyTypedIdType,\n                CreateFactory<TValue>);\n        }\n\n        private static Func<TValue, object> CreateFactory<TValue>(Type stronglyTypedIdType)\n            where TValue : notnull\n        {\n            if (!IsStronglyTypedId(stronglyTypedIdType))\n            {\n                throw new ArgumentException($\"Type '{stronglyTypedIdType}' is not a strongly-typed id type\", nameof(stronglyTypedIdType));\n            }\n\n            var ctor = stronglyTypedIdType.GetConstructor(new[] { typeof(TValue) });\n            if (ctor is null)\n            {\n                throw new ArgumentException($\"Type '{stronglyTypedIdType}' doesn't have a constructor with one parameter of type '{typeof(TValue)}'\", nameof(stronglyTypedIdType));\n            }\n\n            var param = Expression.Parameter(typeof(TValue), \"value\");\n            var body = Expression.New(ctor, param);\n            var lambda = Expression.Lambda<Func<TValue, object>>(body, param);\n            return lambda.Compile();\n        }\n\n        public static bool IsStronglyTypedId(Type type) => IsStronglyTypedId(type, out _);\n\n        public static bool IsStronglyTypedId(Type type, out Type idType)\n        {\n            if (type is null)\n            {\n                throw new ArgumentNullException(nameof(type));\n            }\n\n            if (type.BaseType is Type baseType &&\n                baseType.IsGenericType &&\n                baseType.GetGenericTypeDefinition() == typeof(StronglyTypedId<>))\n            {\n                idType = baseType.GetGenericArguments()[0];\n                return true;\n            }\n\n            idType = null;\n            return false;\n        }\n    }\n\n    [GenerateSerializer]\n    public enum MyCustomEnum\n    {\n        None,\n        One,\n        Two,\n        Three\n    }\n\n    [GenerateSerializer]\n    public class RecursiveClass\n    {\n        [Id(0)]\n        public int IntProperty { get; set; }\n\n        [Id(1)]\n        public RecursiveClass RecursiveProperty { get; set; }\n    }\n\n    [GenerateSerializer]\n    [Id(3201)]\n    public class SomeClassWithSerializers\n    {\n        [Id(0)]\n        public int IntProperty { get; set; }\n\n        [Id(1)] public int IntField;\n\n        [Id(2)]\n        public object OtherObject { get; set; }\n\n        [NonSerialized]\n        public int UnmarkedField;\n\n        [field: NonSerialized]\n        public int UnmarkedProperty { get; set; }\n\n        public override string ToString() => $\"{nameof(IntField)}: {IntField}, {nameof(IntProperty)}: {IntProperty}\";\n    }\n\n    [GenerateSerializer(GenerateFieldIds = GenerateFieldIds.PublicProperties)]\n    public class PocoWithAutogeneratedIds : IEquatable<PocoWithAutogeneratedIds>\n    {\n        public int A { get; set; }\n        public int B { get; set; }\n        public int C { get; set; }\n        public int D { get; set; }\n        public int E { get; set; }\n        public int F { get; set; }\n        public int G { get; set; }\n        public int H { get; set; }\n        public int I { get; set; }\n        public int J { get; set; }\n        public int K { get; set; }\n\n        public override bool Equals(object obj) => Equals(obj as PocoWithAutogeneratedIds);\n        public bool Equals(PocoWithAutogeneratedIds other) => other is not null\n            && A == other.A\n            && B == other.B\n            && C == other.C\n            && D == other.D\n            && E == other.E\n            && F == other.F\n            && G == other.G\n            && H == other.H\n            && I == other.I\n            && J == other.J\n            && K == other.K;\n\n        public override int GetHashCode()\n        {\n            var hash = new HashCode();\n            hash.Add(A);\n            hash.Add(B);\n            hash.Add(C);\n            hash.Add(D);\n            hash.Add(E);\n            hash.Add(F);\n            hash.Add(G);\n            hash.Add(H);\n            hash.Add(I);\n            hash.Add(J);\n            hash.Add(K);\n            return hash.ToHashCode();\n        }\n\n        public static bool operator ==(PocoWithAutogeneratedIds left, PocoWithAutogeneratedIds right) => EqualityComparer<PocoWithAutogeneratedIds>.Default.Equals(left, right);\n        public static bool operator !=(PocoWithAutogeneratedIds left, PocoWithAutogeneratedIds right) => !(left == right);\n    }\n\n    [GenerateSerializer]\n    [Alias(\"sercla1\")]\n    public class SerializableClassWithCompiledBase : List<int>\n    {\n        [Id(0)]\n        public int IntProperty { get; set; }\n    }\n\n#if NET6_0_OR_GREATER\n    [GenerateSerializer]\n    public class ClassWithRequiredMembers\n    {\n        [Id(0)]\n        public required int IntProperty { get; set; }\n\n        [Id(1)]\n        public required string StringField;\n    }\n\n    [GenerateSerializer]\n    public class SubClassWithRequiredMembersInBase : ClassWithRequiredMembers\n    {\n    }\n#endif\n\n    [GenerateSerializer]\n    public sealed class DerivedFromDictionary<TKey, TValue> : Dictionary<TKey, TValue>\n    {\n        public DerivedFromDictionary(IEqualityComparer<TKey> comparer) : base(comparer)\n        {\n        }\n\n        [Id(0)]\n        public int IntProperty { get; set; }\n    }\n\n    [GenerateSerializer]\n    [Alias(\"gpoco`1\")]\n    public class GenericPoco<T>\n    {\n        [Id(0)]\n        public T Field { get; set; }\n\n        [Id(1030)]\n        public T[] ArrayField { get; set; }\n    }\n\n    [GenerateSerializer]\n    [Alias(\"GenericPocoWithConstraint`2\")]\n    public class GenericPocoWithConstraint<TClass, TStruct>\n        : GenericPoco<TStruct> where TClass : List<int>, new() where TStruct : struct\n    {\n        [Id(0)]\n        public new TClass Field { get; set; }\n\n        [Id(999)]\n        public TStruct ValueField { get; set; }\n    }\n\n    public sealed class Outer<T>\n    {\n        [GenerateSerializer]\n        [Alias(\"Orleans.Serialization.UnitTests.Outer.InnerNonGen`1\")]\n        public class InnerNonGen\n        {\n        }\n\n        [GenerateSerializer]\n        [Alias(\"Orleans.Serialization.UnitTests.Outer.InnerGen`2\")]\n        public class InnerGen<U>\n        {\n        }\n    }\n\n    [GenerateSerializer]\n    public class ArrayPoco<T>\n    {\n        [Id(0)]\n        public T[] Array { get; set; }\n\n        [Id(1)]\n        public T[,] Dim2 { get; set; }\n\n        [Id(2)]\n        public T[,,] Dim3 { get; set; }\n\n        [Id(3)]\n        public T[,,,] Dim4 { get; set; }\n\n        [Id(4)]\n        public T[,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,] Dim32 { get; set; }\n\n        [Id(5)]\n        public T[][] Jagged { get; set; }\n    }\n\n    [GenerateSerializer]\n    [SuppressMessage(\"Usage\", \"ORLEANS0004:Add missing serialization attributes\", Justification = \"Intentional for tests\")]\n    public class ImmutableClass\n    {\n        public ImmutableClass(int intProperty, int intField, int unmarkedField, int unmarkedProperty)\n        {\n            IntProperty = intProperty;\n            _intField = intField;\n            UnmarkedField = unmarkedField;\n            UnmarkedProperty = unmarkedProperty;\n        }\n\n        [Id(0)]\n        public int IntProperty { get; }\n\n        [Id(1)] private readonly int _intField;\n\n        public int GetIntField() => _intField;\n\n        public readonly int UnmarkedField;\n\n        public int UnmarkedProperty { get; }\n\n        public override string ToString() => $\"{nameof(_intField)}: {_intField}, {nameof(IntProperty)}: {IntProperty}\";\n    }\n\n    [GenerateSerializer]\n    public struct ImmutableStruct\n    {\n        public ImmutableStruct(int intProperty, int intField)\n        {\n            IntProperty = intProperty;\n            _intField = intField;\n        }\n\n        [Id(0)]\n        public int IntProperty { get; }\n\n        [Id(1)] private readonly int _intField;\n        public readonly int GetIntField() => _intField;\n\n        public override readonly string ToString() => $\"{nameof(_intField)}: {_intField}, {nameof(IntProperty)}: {IntProperty}\";\n    }\n\n    [GenerateSerializer]\n    public class SystemCollectionsClass\n    {\n        [Id(0)]\n        public HashSet<string> hashSetField;\n\n        [Id(1)]\n        public HashSet<string> HashSetProperty { get; set; }\n\n        [Id(2)]\n        public ConcurrentQueue<int> concurrentQueueField;\n\n        [Id(3)]\n        public ConcurrentQueue<int> ConcurrentQueueProperty { get; set; }\n\n        [Id(4)]\n        public ConcurrentDictionary<string, int> concurrentDictField;\n\n        [Id(5)]\n        public ConcurrentDictionary<string, int> ConcurrentDictProperty { get; set; }\n    }\n\n    [GenerateSerializer]\n    public class ClassWithLargeCollectionAndUri\n    {\n        [Id(0)]\n        public List<string> LargeCollection;\n\n        [Id(1)]\n        public Uri Uri;\n    }\n\n    [GenerateSerializer]\n    public class ClassWithManualSerializableProperty\n    {\n        [NonSerialized]\n        private string _stringPropertyValue;\n\n        [Id(0)]\n        public Guid GuidProperty { get; set; }\n\n        [Id(1)]\n        public string StringProperty\n        {\n            get\n            {\n                return _stringPropertyValue ?? GuidProperty.ToString(\"N\");\n            }\n\n            set\n            {\n                _stringPropertyValue = value;\n                GuidProperty = Guid.TryParse(value, out var guidValue) ? guidValue : default;\n            }\n        }\n    }\n\n    [GenerateSerializer(GenerateFieldIds = GenerateFieldIds.PublicProperties), Immutable]\n    public class ClassWithImplicitFieldIds\n    {\n        public string StringValue { get; }\n        public MyCustomEnum EnumValue { get; }\n\n        public ClassWithImplicitFieldIds(string stringValue, MyCustomEnum enumValue)\n        {\n            StringValue = stringValue;\n            EnumValue = enumValue;\n        }\n\n        public override string ToString() => $\"{nameof(StringValue)}: {StringValue}, {nameof(EnumValue)}: {EnumValue}\";\n    }\n\n    [GenerateSerializer]\n    public sealed class ClassWithTypeFields\n    {\n        [Id(1)] public Type Type1;\n        [Id(2)] public object UntypedValue;\n        [Id(3)] public Type Type2;\n    }\n\n    public class MyFirstForeignLibraryType\n    {\n\n        public int Num { get; set; }\n        public string String { get; set; }\n        public DateTimeOffset DateTimeOffset { get; set; }\n\n        public override bool Equals(object obj) =>\n            obj is MyFirstForeignLibraryType type\n            && Num == type.Num\n            && string.Equals(String, type.String, StringComparison.Ordinal)\n            && DateTimeOffset.Equals(type.DateTimeOffset);\n\n        public override int GetHashCode() => HashCode.Combine(Num, String, DateTimeOffset);\n    }\n\n    public class MySecondForeignLibraryType\n    {\n        public string Name { get; set; }\n        public float Value { get; set; }\n        public DateTimeOffset Timestamp { get; set; }\n\n        public override bool Equals(object obj) =>\n            obj is MySecondForeignLibraryType type\n            && string.Equals(Name, type.Name, StringComparison.Ordinal)\n            && Value == type.Value\n            && Timestamp.Equals(type.Timestamp);\n\n        public override int GetHashCode() => HashCode.Combine(Name, Value, Timestamp);\n    }\n\n    [GenerateSerializer]\n    public struct MyFirstForeignLibraryTypeSurrogate\n    {\n        [Id(0)]\n        public int Num { get; set; }\n\n        [Id(1)]\n        public string String { get; set; }\n\n        [Id(2)]\n        public DateTimeOffset DateTimeOffset { get; set; }\n    }\n\n\n    [GenerateSerializer]\n    public struct MySecondForeignLibraryTypeSurrogate\n    {\n        [Id(0)]\n        public string Name { get; set; }\n\n        [Id(1)]\n        public float Value { get; set; }\n\n        [Id(2)]\n        public DateTimeOffset Timestamp { get; set; }\n    }\n\n    [RegisterConverter]\n    public sealed class MyCombinedForeignLibraryValueTypeSurrogateConverter :\n        IConverter<MyFirstForeignLibraryType, MyFirstForeignLibraryTypeSurrogate>,\n        IConverter<MySecondForeignLibraryType, MySecondForeignLibraryTypeSurrogate>\n    {\n        public MyFirstForeignLibraryType ConvertFromSurrogate(in MyFirstForeignLibraryTypeSurrogate surrogate)\n            => new() { Num = surrogate.Num, String = surrogate.String, DateTimeOffset = surrogate.DateTimeOffset };\n        public MyFirstForeignLibraryTypeSurrogate ConvertToSurrogate(in MyFirstForeignLibraryType value)\n            => new() { Num = value.Num, String = value.String, DateTimeOffset = value.DateTimeOffset };\n\n        public MySecondForeignLibraryType ConvertFromSurrogate(in MySecondForeignLibraryTypeSurrogate surrogate)\n            => new() { Name = surrogate.Name, Value = surrogate.Value, Timestamp = surrogate.Timestamp };\n        public MySecondForeignLibraryTypeSurrogate ConvertToSurrogate(in MySecondForeignLibraryType value)\n            => new() { Name = value.Name, Value = value.Value, Timestamp = value.Timestamp };\n    }\n\n    [MessagePackObject]\n    public sealed record MyMessagePackClass\n    {\n        [Key(0)]\n        public int IntProperty { get; init; }\n\n        [Key(1)]\n        public string StringProperty { get; init; }\n\n        [Key(2)]\n        public MyMessagePackSubClass SubClass { get; init; }\n\n        [Key(3)]\n        public IMyMessagePackUnion Union { get; init; }\n    }\n\n    [MessagePackObject]\n    public sealed record MyMessagePackSubClass\n    {\n        [Key(0)]\n        public Guid Id { get; init; }\n    }\n\n    [Union(0, typeof(MyMessagePackUnionVariant1))]\n    [Union(1, typeof(MyMessagePackUnionVariant2))]\n    public interface IMyMessagePackUnion\n    {\n    }\n\n    [MessagePackObject]\n    public sealed record MyMessagePackUnionVariant1 : IMyMessagePackUnion\n    {\n        [Key(0)]\n        public int IntProperty { get; init; }\n    }\n\n    [MessagePackObject]\n    public sealed record MyMessagePackUnionVariant2 : IMyMessagePackUnion\n    {\n        [Key(0)]\n        public string StringProperty { get; init; }\n    }\n\n    [MemoryPackable]\n    public partial record MyMemoryPackClass\n    {\n        public int IntProperty { get; init; }\n\n        public string StringProperty { get; init; }\n\n        public MyMemoryPackSubClass SubClass { get; init; }\n\n        public IMyMemoryPackUnion Union { get; init; }\n    }\n\n    [MemoryPackable]\n    public partial record MyMemoryPackSubClass\n    {\n        public Guid Id { get; init; }\n    }\n\n    [MemoryPackable]\n    [MemoryPackUnion(0, typeof(MyMemoryPackUnionVariant1))]\n    [MemoryPackUnion(1, typeof(MyMemoryPackUnionVariant2))]\n    public partial interface IMyMemoryPackUnion\n    {\n    }\n\n    [MemoryPackable]\n    public partial record MyMemoryPackUnionVariant1 : IMyMemoryPackUnion\n    {\n        public int IntProperty { get; init; }\n    }\n\n    [MemoryPackable]\n    public partial record MyMemoryPackUnionVariant2 : IMyMemoryPackUnion\n    {\n        public string StringProperty { get; init; }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/NewtonsoftJsonCodecTests.cs",
    "content": "using System.Reflection;\nusing Microsoft.Extensions.DependencyInjection;\nusing Newtonsoft.Json.Linq;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TestKit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' Newtonsoft.Json serialization support.\n    /// \n    /// Orleans provides integration with Newtonsoft.Json (Json.NET) for scenarios requiring:\n    /// - Compatibility with existing Newtonsoft.Json configurations\n    /// - Advanced JSON features not available in System.Text.Json\n    /// - Integration with systems already using Newtonsoft.Json\n    /// \n    /// The Newtonsoft.Json codec in Orleans:\n    /// - Supports all Json.NET features including custom converters\n    /// - Can be selectively applied using type predicates\n    /// - Provides both serialization and deep copy functionality\n    /// - Handles Json.NET specific types like JObject, JArray, etc.\n    /// \n    /// This integration is particularly useful when migrating existing systems\n    /// to Orleans that already have complex Newtonsoft.Json configurations.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class NewtonsoftJsonCodecTests : FieldCodecTester<MyNewtonsoftJsonClass, IFieldCodec<MyNewtonsoftJsonClass>>\n    {\n        public NewtonsoftJsonCodecTests(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.AddNewtonsoftJsonSerializer(isSupported: type => type.GetCustomAttribute<MyNewtonsoftJsonSerializableAttribute>(inherit: false) is not null);\n        }\n\n        protected override MyNewtonsoftJsonClass CreateValue() => new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hello\" };\n\n        protected override int[] MaxSegmentSizes => new[] { 840 };\n\n        protected override MyNewtonsoftJsonClass[] TestValues => new MyNewtonsoftJsonClass[]\n        {\n            null,\n            new MyNewtonsoftJsonClass(),\n            new MyNewtonsoftJsonClass() { IntProperty = 150, SubTypeProperty = new string('c', 20) },\n            new MyNewtonsoftJsonClass() { IntProperty = -150_000, SubTypeProperty = new string('c', 4097) },\n        };\n\n        [Fact]\n        public void NewtonsoftJsonDeepCopyTyped()\n        {\n            var original = new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hi\" };\n            var copier = ServiceProvider.GetRequiredService<DeepCopier<MyNewtonsoftJsonClass>>();\n            var result = copier.Copy(original);\n\n            Assert.Equal(original.IntProperty, result.IntProperty);\n            Assert.Equal(original.SubTypeProperty, result.SubTypeProperty);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonDeepCopyUntyped()\n        {\n            var original = new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hi\" };\n            var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n            var result = (MyNewtonsoftJsonClass)copier.Copy((object)original);\n\n            Assert.Equal(original.IntProperty, result.IntProperty);\n            Assert.Equal(original.SubTypeProperty, result.SubTypeProperty);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonRoundTripThroughCodec()\n        {\n            var original = new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hi\" };\n            var result = RoundTripThroughCodec(original);\n\n            Assert.Equal(original.IntProperty, result.IntProperty);\n            Assert.Equal(original.SubTypeProperty, result.SubTypeProperty);\n        }\n\n        [Fact]\n        public void NewtonsoftJsonRoundTripThroughUntypedSerializer()\n        {\n            var original = new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hi\" };\n            var untypedResult = RoundTripThroughUntypedSerializer(original, out _);\n\n            var result = Assert.IsType<MyNewtonsoftJsonClass>(untypedResult);\n            Assert.Equal(original.IntProperty, result.IntProperty);\n            Assert.Equal(original.SubTypeProperty, result.SubTypeProperty);\n        }\n\n        [Fact]\n        public void CanSerializeNativeJsonTypes()\n        {\n            var jsonArray = Newtonsoft.Json.JsonConvert.DeserializeObject<JArray>(\"[1, true, \\\"three\\\", {\\\"foo\\\": \\\"bar\\\"}]\");\n            var jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(\"{\\\"foo\\\": \\\"bar\\\"}\");\n            var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n\n            var deserializedArray = RoundTripThroughUntypedSerializer(jsonArray, out _);\n            Assert.Equal(Newtonsoft.Json.JsonConvert.SerializeObject(jsonArray), Newtonsoft.Json.JsonConvert.SerializeObject(deserializedArray));\n\n            var deserializedObject = RoundTripThroughUntypedSerializer(jsonObject, out _);\n            Assert.Equal(Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject), Newtonsoft.Json.JsonConvert.SerializeObject(deserializedObject));\n        }\n    }\n\n    [Trait(\"Category\", \"BVT\")]\n    public class NewtonsoftJsonCodecCopierTests : CopierTester<MyNewtonsoftJsonClass, IDeepCopier<MyNewtonsoftJsonClass>>\n    {\n        public NewtonsoftJsonCodecCopierTests(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override void Configure(ISerializerBuilder builder)\n        {\n            builder.AddNewtonsoftJsonSerializer(isSupported: type => type.GetCustomAttribute<MyNewtonsoftJsonSerializableAttribute>(inherit: false) is not null);\n        }\n\n        protected override IDeepCopier<MyNewtonsoftJsonClass> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<MyNewtonsoftJsonClass>();\n\n        protected override MyNewtonsoftJsonClass CreateValue() => new MyNewtonsoftJsonClass { IntProperty = 30, SubTypeProperty = \"hello\" };\n\n        protected override MyNewtonsoftJsonClass[] TestValues => new MyNewtonsoftJsonClass[]\n        {\n            null,\n            new MyNewtonsoftJsonClass(),\n            new MyNewtonsoftJsonClass() { IntProperty = 150, SubTypeProperty = new string('c', 20) },\n            new MyNewtonsoftJsonClass() { IntProperty = -150_000, SubTypeProperty = new string('c', 4097) },\n        };\n\n        [Fact]\n        public void CanCopyNativeJsonTypes()\n        {\n            var jsonArray = Newtonsoft.Json.JsonConvert.DeserializeObject<JArray>(\"[1, true, \\\"three\\\", {\\\"foo\\\": \\\"bar\\\"}]\");\n            var jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(\"{\\\"foo\\\": \\\"bar\\\"}\");\n            var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n\n            var deserializedArray = copier.Copy(jsonArray);\n            Assert.Equal(Newtonsoft.Json.JsonConvert.SerializeObject(jsonArray), Newtonsoft.Json.JsonConvert.SerializeObject(deserializedArray));\n\n            var deserializedObject = copier.Copy(jsonObject);\n            Assert.Equal(Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject), Newtonsoft.Json.JsonConvert.SerializeObject(deserializedObject));\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/NumericsWideningAndNarrowingTests.cs",
    "content": "#if NET7_0_OR_GREATER\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for numeric type conversion support in Orleans serialization.\n/// \n/// Orleans provides version-tolerant serialization for numeric types, allowing:\n/// - Widening conversions (e.g., int to long) without data loss\n/// - Narrowing conversions (e.g., long to int) with appropriate handling\n/// - Cross-version compatibility when numeric field types change\n/// \n/// This feature is crucial for:\n/// - Schema evolution where numeric precision requirements change\n/// - Gradual migrations of data types in distributed systems\n/// - Maintaining compatibility during rolling upgrades\n/// \n/// The serialization system automatically handles:\n/// - Conversions between signed/unsigned integers of different sizes\n/// - Floating-point precision changes\n/// - Safe conversions that preserve values within target type ranges\n/// - Appropriate handling of overflow/underflow scenarios\n/// </summary>\npublic class NumericsWideningAndNarrowingTests\n{\n    private readonly IServiceProvider _serviceProvider;\n    private readonly Serializer _serializer;\n\n    public NumericsWideningAndNarrowingTests()\n    {\n        var services = new ServiceCollection();\n        _ = services.AddSerializer();\n        _serviceProvider = services.BuildServiceProvider();\n        _serializer = _serviceProvider.GetRequiredService<Serializer>();\n    }\n\n    /// <summary>\n    /// Tests that unsigned integers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void UnsignedIntegerWideningAndNarrowingVersionToleranceTests()\n    {\n        ConversionRoundTrip<byte, ushort>();\n        ConversionRoundTrip<byte, uint>();\n        ConversionRoundTrip<byte, ulong>();\n        ConversionRoundTrip<byte, UInt128>();\n\n        ConversionRoundTrip<ushort, uint>();\n        ConversionRoundTrip<ushort, ulong>();\n        ConversionRoundTrip<ushort, UInt128>();\n\n        ConversionRoundTrip<uint, ulong>();\n        ConversionRoundTrip<uint, UInt128>();\n\n        ConversionRoundTrip<ulong, UInt128>();\n    }\n\n    /// <summary>\n    /// Tests that signed integers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void SignedIntegerWideningAndNarrowingVersionToleranceTests()\n    {\n        ConversionRoundTrip<sbyte, short>();\n        ConversionRoundTrip<sbyte, int>();\n        ConversionRoundTrip<sbyte, long>();\n        ConversionRoundTrip<sbyte, Int128>();\n\n        ConversionRoundTrip<short, int>();\n        ConversionRoundTrip<short, long>();\n        ConversionRoundTrip<short, Int128>();\n\n        ConversionRoundTrip<int, long>();\n        ConversionRoundTrip<int, Int128>();\n\n        ConversionRoundTrip<long, Int128>();\n    }\n\n    /// <summary>\n    /// Tests that floating point numbers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void FloatWideningAndNarrowingVersionToleranceTests()\n    {\n        FloatConversionRoundTrip<Half, decimal>();\n        FloatConversionRoundTrip<Half, float>();\n        FloatConversionRoundTrip<Half, double>();\n\n        FloatConversionRoundTrip<decimal, float>();\n        FloatConversionRoundTrip<decimal, double>();\n\n        FloatConversionRoundTrip<float, double>();\n    }\n\n    private void ConversionRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        WideningRoundTrip<N, W>();\n        NarrowingRoundTrip<N, W>();\n        NarrowingOverflow<N, W>();\n    }\n\n    private void FloatConversionRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        FloatWideningRoundTrip<N, W>();\n        FloatNarrowingRoundTrip<N, W>();\n        NarrowingOverflow<N, W>();\n    }\n\n    private void WideningRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        var two = N.MultiplicativeIdentity + N.MultiplicativeIdentity;\n        var values = new List<N>\n        {\n            N.MinValue,\n            default,\n            N.MaxValue / two,\n            N.MaxValue,\n        };\n\n        foreach (var value in values)\n        {\n            RoundTripValue<N, W>(value);\n        }\n    }\n\n    private void NarrowingRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        var two = N.MultiplicativeIdentity + N.MultiplicativeIdentity;\n        var values = (new N[]\n        {\n            N.MinValue,\n            default,\n            N.MaxValue / two,\n            N.MaxValue,\n        }).Select(W.CreateTruncating).ToList();\n\n        foreach (var value in values)\n        {\n            RoundTripValue<W, N>(value);\n        }\n    }\n\n    private void NarrowingOverflow<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        var values = W.Sign(W.MinValue) switch\n        {\n            -1 => new[] { W.MinValue, W.MaxValue },\n            _ => new[] { W.MaxValue }\n        };\n\n        foreach (var value in values)\n        {\n            Assert.Throws<OverflowException>(() => RoundTripValueDirectly<W, N>(value));\n            Assert.Throws<OverflowException>(() => RoundTripValueIndirectly<W, N>(value));\n        }\n    }\n\n    private void FloatWideningRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        var two = N.MultiplicativeIdentity + N.MultiplicativeIdentity;\n        var buffer = N.MaxValue / (two * two * two);\n        var values = new List<N>\n        {\n            N.MinValue + buffer,\n            N.MinValue / two,\n            default,\n            N.MaxValue / two,\n            N.MaxValue - buffer,\n        };\n\n        foreach (var value in values)\n        {\n            RoundTripValue<N, W>(value);\n        }\n    }\n\n    private void FloatNarrowingRoundTrip<N, W>()\n        where N : INumber<N>, IMinMaxValue<N>\n        where W : INumber<W>, IMinMaxValue<W>\n    {\n        var two = N.MultiplicativeIdentity + N.MultiplicativeIdentity;\n        var buffer = N.MaxValue / (two * two * two);\n        var values = new List<N>\n        {\n            N.MinValue + buffer,\n            N.MinValue / two,\n            default,\n            N.MaxValue / two,\n            N.MaxValue - buffer,\n        }.Select(W.CreateTruncating).ToList();\n\n        foreach (var value in values)\n        {\n            RoundTripValue<W, N>(value);\n        }\n    }\n\n    private void RoundTripValue<TLeft, TRight>(TLeft leftValue)\n        where TLeft : INumber<TLeft>, IMinMaxValue<TLeft>\n        where TRight : INumber<TRight>, IMinMaxValue<TRight>\n    {\n        RoundTripValueDirectly<TLeft, TRight>(leftValue);\n        RoundTripValueIndirectly<TLeft, TRight>(leftValue);\n    }\n\n    private void RoundTripValueDirectly<TLeft, TRight>(TLeft leftValue)\n        where TLeft : INumber<TLeft>, IMinMaxValue<TLeft>\n        where TRight : INumber<TRight>, IMinMaxValue<TRight>\n    {\n        // Round-trip the value, converting it along the way.\n        var payload = _serializer.SerializeToArray(leftValue);\n        var result = _serializer.Deserialize<TRight>(payload);\n\n        var asRight = TRight.CreateTruncating(leftValue);\n        Assert.Equal(asRight, result);\n\n        var asLeft = TLeft.CreateTruncating(result);\n        var expected = TLeft.CreateTruncating(TRight.CreateTruncating(leftValue));\n        Assert.Equal(expected, asLeft);\n    }\n\n    private void RoundTripValueIndirectly<TLeft, TRight>(TLeft leftValue)\n        where TLeft : INumber<TLeft>, IMinMaxValue<TLeft>\n        where TRight : INumber<TRight>, IMinMaxValue<TRight>\n    {\n        // Wrap the value and round-trip the wrapped value, converting it along the way.\n        var payload = _serializer.SerializeToArray(new ValueHolder<TLeft> { Value = leftValue });\n        var result = _serializer.Deserialize<ValueHolder<TRight>>(payload).Value;\n\n        var asRight = TRight.CreateTruncating(leftValue);\n        Assert.Equal(asRight, result);\n\n        var asLeft = TLeft.CreateTruncating(result);\n        var expected = TLeft.CreateTruncating(TRight.CreateTruncating(leftValue));\n        Assert.Equal(expected, asLeft);\n    }\n\n    [GenerateSerializer]\n    public sealed class ValueHolder<T>\n    {\n        [Id(0)]\n        public T Value;\n    }\n}\n#else\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Ensures that numeric fields (integers, floats, etc) can be widened and narrowed in a version tolerant manner.\n/// </summary>\npublic class NumericsWideningAndNarrowingTests\n{\n    private static readonly ByteNumber ByteType = new();\n    private static readonly ShortNumber ShortType = new();\n    private static readonly IntNumber IntType = new();\n    private static readonly LongNumber LongType = new();\n    private static readonly SByteNumber SByteType = new();\n    private static readonly UShortNumber UShortType = new();\n    private static readonly UIntNumber UIntType = new();\n    private static readonly ULongNumber ULongType = new();\n    private static readonly FloatNumber FloatType = new();\n    private static readonly DoubleNumber DoubleType = new();\n    private static readonly DecimalNumber DecimalType = new();\n#if NET5_0_OR_GREATER\n    private static readonly HalfNumber HalfType = new();\n#endif\n\n    private readonly IServiceProvider _serviceProvider;\n    private readonly Serializer _serializer;\n\n    public NumericsWideningAndNarrowingTests()\n    {\n        var services = new ServiceCollection();\n        _ = services.AddSerializer();\n        _serviceProvider = services.BuildServiceProvider();\n        _serializer = _serviceProvider.GetRequiredService<Serializer>();\n    }\n\n    /// <summary>\n    /// Tests that unsigned integers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void UnsignedIntegerWideningAndNarrowingVersionToleranceTests()\n    {\n        ConversionRoundTrip(ByteType, UShortType);\n        ConversionRoundTrip(ByteType, UIntType);\n        ConversionRoundTrip(ByteType, ULongType);\n\n        ConversionRoundTrip(UShortType, UIntType);\n        ConversionRoundTrip(UShortType, ULongType);\n\n        ConversionRoundTrip(UIntType, ULongType);\n    }\n\n    /// <summary>\n    /// Tests that signed integers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void SignedIntegerWideningAndNarrowingVersionToleranceTests()\n    {\n        ConversionRoundTrip(SByteType, ShortType);\n        ConversionRoundTrip(SByteType, IntType);\n        ConversionRoundTrip(SByteType, LongType);\n\n        ConversionRoundTrip(ShortType, IntType);\n        ConversionRoundTrip(ShortType, LongType);\n\n        ConversionRoundTrip(IntType, LongType);\n    }\n\n    /// <summary>\n    /// Tests that floating point numbers can be widened and narrowed and maintain compatibility.\n    /// </summary>\n    [Fact]\n    public void FloatWideningAndNarrowingVersionToleranceTests()\n    {\n#if NET5_0_OR_GREATER\n        FloatConversionRoundTrip(HalfType, DecimalType);\n        FloatConversionRoundTrip(HalfType, FloatType);\n        FloatConversionRoundTrip(HalfType, DoubleType);\n#endif\n\n        FloatConversionRoundTrip(DecimalType, FloatType);\n        FloatConversionRoundTrip(DecimalType, DoubleType);\n\n        FloatConversionRoundTrip(FloatType, DoubleType);\n    }\n\n    private void ConversionRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        WideningRoundTrip(n, w);\n        NarrowingRoundTrip(n, w);\n        NarrowingOverflow(n, w);\n    }\n\n    private void FloatConversionRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        FloatWideningRoundTrip(n, w);\n        FloatNarrowingRoundTrip(n, w);\n        NarrowingOverflow(n, w);\n    }\n\n    private void WideningRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        var two = n.Add(n.MultiplicativeIdentity, n.MultiplicativeIdentity);\n        var values = new List<N>\n        {\n            n.MinValue,\n            default,\n            n.Divide(n.MaxValue, two),\n            n.MaxValue,\n        };\n\n        foreach (var value in values)\n        {\n            RoundTripValue(value, n, w);\n        }\n    }\n\n    private void NarrowingRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        var two = n.Add(n.MultiplicativeIdentity, n.MultiplicativeIdentity);\n        var values = (new N[]\n        {\n            n.MinValue,\n            default,\n            n.Divide(n.MaxValue, two),\n            n.MaxValue,\n        }).Select(w.CreateTruncating).ToList();\n\n        foreach (var value in values)\n        {\n            RoundTripValue(value, w, n);\n        }\n    }\n\n    private void NarrowingOverflow<N, W>(INumber<N> n, INumber<W> w)\n    {\n        var values = w.Sign(w.MinValue) switch\n        {\n            -1 => new[] { w.MinValue, w.MaxValue },\n            _ => new[] { w.MaxValue }\n        };\n\n        foreach (var value in values)\n        {\n            Assert.Throws<OverflowException>(() => RoundTripValueDirectly(value, w, n));\n            Assert.Throws<OverflowException>(() => RoundTripValueIndirectly(value, w, n));\n        }\n    }\n\n    private void FloatWideningRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        var two = n.Add(n.MultiplicativeIdentity, n.MultiplicativeIdentity);\n        var buffer = n.Divide(n.Divide(n.Divide(n.MaxValue, two), two), two);\n        var values = new List<N>\n        {\n            n.Add(n.MinValue, buffer),\n            n.Divide(n.MinValue, two),\n            default,\n            n.Divide(n.MaxValue, two),\n            n.Subtract(n.MaxValue, buffer),\n        };\n\n        foreach (var value in values)\n        {\n            RoundTripValue(value, n, w);\n        }\n    }\n\n    private void FloatNarrowingRoundTrip<N, W>(INumber<N> n, INumber<W> w)\n    {\n        var two = n.Add(n.MultiplicativeIdentity, n.MultiplicativeIdentity);\n        var buffer = n.Divide(n.Divide(n.Divide(n.MaxValue, two), two), two);\n        var values = new List<N>\n        {\n            n.Add(n.MinValue, buffer),\n            n.Divide(n.MinValue, two),\n            default,\n            n.Divide(n.MaxValue, two),\n            n.Subtract(n.MaxValue, buffer),\n        }.Select(w.CreateTruncating).ToList();\n\n        foreach (var value in values)\n        {\n            RoundTripValue(value, w, n);\n        }\n    }\n\n    private void RoundTripValue<TLeft, TRight>(TLeft leftValue, INumber<TLeft> left, INumber<TRight> right)\n    {\n        RoundTripValueDirectly(leftValue, left, right);\n        RoundTripValueIndirectly(leftValue, left, right);\n    }\n\n    private void RoundTripValueDirectly<TLeft, TRight>(TLeft leftValue, INumber<TLeft> left, INumber<TRight> right)\n    {\n        // Round-trip the value, converting it along the way.\n        var payload = _serializer.SerializeToArray(leftValue);\n        var result = _serializer.Deserialize<TRight>(payload);\n\n        var asRight = right.CreateTruncating(leftValue);\n        Assert.Equal(asRight, result);\n\n        var asLeft = left.CreateTruncating(result);\n        var expected = left.CreateTruncating(right.CreateTruncating(leftValue));\n        Assert.Equal(expected, asLeft);\n    }\n\n    private void RoundTripValueIndirectly<TLeft, TRight>(TLeft leftValue, INumber<TLeft> left, INumber<TRight> right)\n    {\n        // Wrap the value and round-trip the wrapped value, converting it along the way.\n        var payload = _serializer.SerializeToArray(new ValueHolder<TLeft> { Value = leftValue });\n        var result = _serializer.Deserialize<ValueHolder<TRight>>(payload).Value;\n\n        var asRight = right.CreateTruncating(leftValue);\n        Assert.Equal(asRight, result);\n\n        var asLeft = left.CreateTruncating(result);\n        var expected = left.CreateTruncating(right.CreateTruncating(leftValue));\n        Assert.Equal(expected, asLeft);\n    }\n\n    [GenerateSerializer]\n    public sealed class ValueHolder<T>\n    {\n        [Id(0)]\n        public T Value;\n    }\n\n    public interface INumber<T>\n    {\n        public T MinValue { get; }\n        public T MaxValue { get; }\n        public T MultiplicativeIdentity { get; }\n        public int Sign(T value);\n        public T Add(T x, T y);\n        public T Subtract(T x, T y);\n        public T Divide(T x, T y);\n        public T CreateTruncating<TFrom>(TFrom from);\n    }\n\n    public sealed class ByteNumber : INumber<byte>\n    {\n        public byte MinValue => byte.MinValue;\n        public byte MaxValue => byte.MaxValue;\n        public byte MultiplicativeIdentity => 1;\n        public int Sign(byte value) => Math.Sign(value);\n\n        public byte Add(byte x, byte y) => (byte)(x + y);\n\n        public byte Subtract(byte x, byte y) => (byte)(x - y);\n\n        public byte Divide(byte x, byte y) => (byte)(x / y);\n\n        public byte CreateTruncating<TFrom>(TFrom from) => (byte)Convert.ChangeType(from, typeof(byte));\n    }\n\n    public sealed class UShortNumber : INumber<ushort>\n    {\n        public ushort MinValue => ushort.MinValue;\n        public ushort MaxValue => ushort.MaxValue;\n        public ushort MultiplicativeIdentity => 1;\n        public int Sign(ushort value) => 1;\n\n        public ushort Add(ushort x, ushort y) => (ushort)(x + y);\n\n        public ushort Subtract(ushort x, ushort y) => (ushort)(x - y);\n\n        public ushort Divide(ushort x, ushort y) => (ushort)(x / y);\n\n        public ushort CreateTruncating<TFrom>(TFrom from) => (ushort)Convert.ChangeType(from, typeof(ushort));\n    }\n\n    public sealed class UIntNumber : INumber<uint>\n    {\n        public uint MinValue => uint.MinValue;\n        public uint MaxValue => uint.MaxValue;\n        public uint MultiplicativeIdentity => 1;\n        public int Sign(uint value) => 1;\n\n        public uint Add(uint x, uint y) => x + y;\n\n        public uint Subtract(uint x, uint y) => x - y;\n\n        public uint Divide(uint x, uint y) => x / y;\n\n        public uint CreateTruncating<TFrom>(TFrom from) => (uint)Convert.ChangeType(from, typeof(uint));\n    }\n\n    public sealed class ULongNumber : INumber<ulong>\n    {\n        public ulong MinValue => ulong.MinValue;\n        public ulong MaxValue => ulong.MaxValue;\n        public ulong MultiplicativeIdentity => 1;\n        public int Sign(ulong value) => 1;\n\n        public ulong Add(ulong x, ulong y) => x + y;\n\n        public ulong Subtract(ulong x, ulong y) => x - y;\n\n        public ulong Divide(ulong x, ulong y) => x / y;\n\n        public ulong CreateTruncating<TFrom>(TFrom from) => (ulong)Convert.ChangeType(from, typeof(ulong));\n    }\n\n    public sealed class SByteNumber : INumber<sbyte>\n    {\n        public sbyte MinValue => sbyte.MinValue;\n        public sbyte MaxValue => sbyte.MaxValue;\n        public sbyte MultiplicativeIdentity => 1;\n        public int Sign(sbyte value) => Math.Sign(value);\n\n        public sbyte Add(sbyte x, sbyte y) => (sbyte)(x + y);\n\n        public sbyte Subtract(sbyte x, sbyte y) => (sbyte)(x - y);\n\n        public sbyte Divide(sbyte x, sbyte y) => (sbyte)(x / y);\n\n        public sbyte CreateTruncating<TFrom>(TFrom from) => (sbyte)Convert.ChangeType(from, typeof(sbyte));\n    }\n\n    public sealed class ShortNumber : INumber<short>\n    {\n        public short MinValue => short.MinValue;\n        public short MaxValue => short.MaxValue;\n        public short MultiplicativeIdentity => 1;\n        public int Sign(short value) => Math.Sign(value);\n\n        public short Add(short x, short y) => (short)(x + y);\n\n        public short Subtract(short x, short y) => (short)(x - y);\n\n        public short Divide(short x, short y) => (short)(x / y);\n\n        public short CreateTruncating<TFrom>(TFrom from) => (short)Convert.ChangeType(from, typeof(short));\n    }\n\n    public sealed class IntNumber : INumber<int>\n    {\n        public int MinValue => int.MinValue;\n        public int MaxValue => int.MaxValue;\n        public int MultiplicativeIdentity => 1;\n        public int Sign(int value) => Math.Sign(value);\n\n        public int Add(int x, int y) => x + y;\n\n        public int Subtract(int x, int y) => x - y;\n\n        public int Divide(int x, int y) => x / y;\n\n        public int CreateTruncating<TFrom>(TFrom from) => (int)Convert.ChangeType(from, typeof(int));\n    }\n\n    public sealed class LongNumber : INumber<long>\n    {\n        public long MinValue => long.MinValue;\n        public long MaxValue => long.MaxValue;\n        public long MultiplicativeIdentity => 1;\n        public int Sign(long value) => Math.Sign(value);\n\n        public long Add(long x, long y) => x + y;\n\n        public long Subtract(long x, long y) => x - y;\n\n        public long Divide(long x, long y) => x / y;\n\n        public long CreateTruncating<TFrom>(TFrom from) => (long)Convert.ChangeType(from, typeof(long));\n    }\n\n    public sealed class FloatNumber : INumber<float>\n    {\n        public float MinValue => float.MinValue;\n        public float MaxValue => float.MaxValue;\n        public float MultiplicativeIdentity => 1;\n        public int Sign(float value) => Math.Sign(value);\n\n        public float Add(float x, float y) => x + y;\n\n        public float Subtract(float x, float y) => x - y;\n\n        public float Divide(float x, float y) => x / y;\n\n        public float CreateTruncating<TFrom>(TFrom from) => (float)Convert.ChangeType(from, typeof(float));\n    }\n\n    public sealed class DoubleNumber : INumber<double>\n    {\n        public double MinValue => double.MinValue;\n        public double MaxValue => double.MaxValue;\n        public double MultiplicativeIdentity => 1;\n        public int Sign(double value) => Math.Sign(value);\n\n        public double Add(double x, double y) => x + y;\n\n        public double Subtract(double x, double y) => x - y;\n\n        public double Divide(double x, double y) => x / y;\n\n        public double CreateTruncating<TFrom>(TFrom from) => (double)Convert.ChangeType(from, typeof(double));\n    }\n\n    public sealed class DecimalNumber : INumber<decimal>\n    {\n        public decimal MinValue => decimal.MinValue;\n        public decimal MaxValue => decimal.MaxValue;\n        public decimal MultiplicativeIdentity => 1;\n        public int Sign(decimal value) => Math.Sign(value);\n\n        public decimal Add(decimal x, decimal y) => x + y;\n\n        public decimal Subtract(decimal x, decimal y) => x - y;\n\n        public decimal Divide(decimal x, decimal y) => x / y;\n\n        public decimal CreateTruncating<TFrom>(TFrom from) => (decimal)Convert.ChangeType(from, typeof(decimal));\n    }\n\n#if NET5_0_OR_GREATER\n    public sealed class HalfNumber : INumber<Half>\n    {\n        public Half MinValue => Half.MinValue;\n        public Half MaxValue => Half.MaxValue;\n        public Half MultiplicativeIdentity => 1;\n        public int Sign(Half value) => Math.Sign(value);\n\n        public Half Add(Half x, Half y) => x + y;\n\n        public Half Subtract(Half x, Half y) => x - y;\n\n        public Half Divide(Half x, Half y) => x / y;\n\n        public Half CreateTruncating<TFrom>(TFrom from) => (Half)Convert.ChangeType(from, typeof(Half));\n    }\n#endif\n}\n\n#endif"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsTestProject>true</IsTestProject>\n    <TargetFrameworks>$(TestTargetFrameworks);netcoreapp3.1</TargetFrameworks>\n    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <ImplicitUsings>disable</ImplicitUsings>\n    <SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"CsCheck\" />\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.core\" />\n    <PackageReference Include=\"xunit.extensibility.core\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Include=\"Newtonsoft.Json\" />\n    <PackageReference Include=\"FSharp.Core\" />\n    <PackageReference Include=\"Google.Protobuf\" />\n    <PackageReference Include=\"Grpc.Tools\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'netcoreapp3.1'\">\n    <PackageReference Update=\"CsCheck\" VersionOverride=\"2.14.1\"/>\n    <PackageReference Update=\"Microsoft.NET.Test.Sdk\" VersionOverride=\"17.11.1\"/>\n    <PackageReference Update=\"xunit.runner.visualstudio\" VersionOverride=\"2.4.5\"/>\n    <PackageReference Update=\"xunit\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.assert\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.core\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.extensibility.core\" VersionOverride=\"2.4.2\" />\n    <PackageReference Update=\"xunit.extensibility.execution\" VersionOverride=\"2.4.2\" />\n    <Compile Remove=\"SerializationTests.cs\" />\n    <Compile Remove=\"JsonSerializerTests.cs\" />\n    <Compile Remove=\"RoundTripSerializerTests.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.TestKit\\Orleans.Serialization.TestKit.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.FSharp\\Orleans.Serialization.FSharp.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization\\Orleans.Serialization.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.SystemTextJson\\Orleans.Serialization.SystemTextJson.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.NewtonsoftJson\\Orleans.Serialization.NewtonsoftJson.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.MemoryPack\\Orleans.Serialization.MemoryPack.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Serialization.MessagePack\\Orleans.Serialization.MessagePack.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Serializers\\Orleans.Serialization.Protobuf\\Orleans.Serialization.Protobuf.csproj\" />\n    <ProjectReference Include=\"..\\Misc\\TestSerializerExternalModels\\TestSerializerExternalModels.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Tests\\Orleans.Runtime.Tests.csproj\" Condition=\"'$(TargetFramework)' != 'netcoreapp3.1'\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"protobuf-model.proto\" GrpcServices=\"None\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/PolymorphismTests.cs",
    "content": "using Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing Xunit;\nusing Microsoft.Extensions.Options;\nusing System.Runtime.Serialization;\n\nnamespace Orleans.Serialization.UnitTests\n{\n\n    [GenerateSerializer]\n    public class CustomException : Exception\n    {\n        public CustomException() { }\n        public CustomException(string message) : base(message) { }\n        public CustomException(string message, Exception inner) : base(message, inner) { }\n\n#if NET8_0_OR_GREATER\n        [Obsolete]\n#endif\n        public CustomException(SerializationInfo info, StreamingContext context) : base(info, context) { }\n\n        [Id(0)]\n        public int CustomInt;\n    }\n\n    /// <summary>\n    /// Tests for Orleans' polymorphic serialization capabilities.\n    /// \n    /// Orleans fully supports polymorphic types, allowing:\n    /// - Serialization of base class references containing derived types\n    /// - Proper type preservation across serialization boundaries\n    /// - Interface and abstract class serialization\n    /// - Custom exception types with inheritance\n    /// \n    /// Key features tested:\n    /// - Type manifests for efficient type encoding\n    /// - Well-known type IDs for common types\n    /// - Inheritance hierarchy preservation\n    /// - Cross-version compatibility with type evolution\n    /// \n    /// This is essential for:\n    /// - Object-oriented designs with inheritance\n    /// - Plugin architectures with dynamic type loading\n    /// - Exception propagation across grain boundaries\n    /// - Flexible API designs with interface parameters\n    /// </summary>\n    public class PolymorphismTests\n    {\n        private readonly ServiceProvider _serviceProvider;\n\n        public PolymorphismTests()\n        {\n            _serviceProvider = new ServiceCollection().AddSerializer()\n                .AddSingleton<IConfigureOptions<TypeManifestOptions>, TypeConfigurationProvider>()\n                .BuildServiceProvider();\n        }\n\n        private class TypeConfigurationProvider : IConfigureOptions<TypeManifestOptions>\n        {\n            public void Configure(TypeManifestOptions configuration)\n            {\n                configuration.WellKnownTypeIds[1000] = typeof(SomeBaseClass);\n                configuration.WellKnownTypeIds[1001] = typeof(SomeSubClass);\n                configuration.WellKnownTypeIds[1002] = typeof(OtherSubClass);\n                configuration.WellKnownTypeIds[1003] = typeof(SomeSubClassChild);\n            }\n        }\n\n        [Fact]\n        public void ExceptionsAreSerializable()\n        {\n            Exception baseEx;\n            InvalidOperationException ioEx;\n            AggregateException aggregateException;\n            CustomException customException;\n            try\n            {\n                throw new InvalidOperationException(\"This is exceptional!\");\n            }\n            catch (InvalidOperationException ex)\n            {\n                ioEx = ex;\n                ioEx.Data.Add(\"Hi\", \"yes?\");\n                try\n                {\n                    throw new AggregateException(\"This is insane!\", ex);\n                }\n                catch (AggregateException ag)\n                {\n                    aggregateException = ag;\n                    try\n                    {\n                        throw new CustomException(\"it's customization time\") { CustomInt = 45 };\n                    }\n                    catch (CustomException ce)\n                    {\n                        customException = ce;\n                        try\n                        {\n                            throw new Exception(\"boring base exception\");\n                        }\n                        catch (Exception e)\n                        {\n                            baseEx = e;\n                            baseEx.Data.Add(\"Hi\", \"yes?\");\n                        }\n                    }\n                }\n            }\n\n            var result = RoundTripToExpectedType<Exception, InvalidOperationException>(ioEx);\n            Assert.Equal(ioEx.Message, result.Message);\n            Assert.Contains(ioEx.StackTrace, result.StackTrace);\n            Assert.Equal(ioEx.InnerException, result.InnerException);\n            Assert.NotNull(result.Data);\n            var data = result.Data;\n            Assert.True(data.Count == 1);\n            Assert.Equal(\"yes?\", data[\"Hi\"]);\n\n            var exCopy = DeepCopy(ioEx);\n            Assert.Equal(ioEx.Message, exCopy.Message);\n            Assert.Contains(ioEx.StackTrace, exCopy.StackTrace);\n            Assert.Equal(ioEx.InnerException, exCopy.InnerException);\n            Assert.NotNull(exCopy.Data);\n            var copyData = exCopy.Data;\n            Assert.True(copyData.Count == 1);\n            Assert.Equal(\"yes?\", copyData[\"Hi\"]);\n\n            var baseExResult = RoundTripToExpectedType<Exception, Exception>(baseEx);\n            Assert.Equal(baseEx.Message, baseExResult.Message);\n            Assert.Contains(baseEx.StackTrace, baseExResult.StackTrace);\n            Assert.Equal(baseEx.InnerException, baseExResult.InnerException);\n            Assert.NotNull(baseExResult.Data);\n            var baseExData = baseExResult.Data;\n            Assert.True(baseExData.Count == 1);\n            Assert.Equal(\"yes?\", baseExData[\"Hi\"]);\n\n            var baseExCopy = DeepCopy(baseEx);\n            Assert.Equal(baseEx.Message, baseExCopy.Message);\n            Assert.Contains(baseEx.StackTrace, baseExCopy.StackTrace);\n            Assert.Equal(baseEx.InnerException, baseExCopy.InnerException);\n            Assert.NotNull(baseExCopy.Data);\n            var baseExCopyData = baseExCopy.Data;\n            Assert.True(baseExCopyData.Count == 1);\n            Assert.Equal(\"yes?\", baseExCopyData[\"Hi\"]);\n\n            var agResult = RoundTripToExpectedType<Exception, AggregateException>(aggregateException);\n            Assert.Equal(aggregateException.Message, agResult.Message);\n            Assert.Contains(aggregateException.StackTrace, agResult.StackTrace);\n            var inner = Assert.IsType<InvalidOperationException>(agResult.InnerException);\n            Assert.Equal(ioEx.Message, inner.Message);\n\n            var agCopy = DeepCopy(aggregateException);\n            Assert.Equal(aggregateException.Message, agCopy.Message);\n            Assert.Contains(aggregateException.StackTrace, agCopy.StackTrace);\n            var agInner = Assert.IsType<InvalidOperationException>(agCopy.InnerException);\n            Assert.Equal(ioEx.Message, agInner.Message);\n\n            var ceResult = RoundTripToExpectedType<Exception, CustomException>(customException);\n            Assert.Equal(customException.Message, ceResult.Message);\n            Assert.Contains(customException.StackTrace, ceResult.StackTrace);\n            Assert.Equal(customException.CustomInt, ceResult.CustomInt);\n\n            var ceCopy = DeepCopy(customException);\n            Assert.Equal(customException.Message, ceCopy.Message);\n            Assert.Contains(customException.StackTrace, ceCopy.StackTrace);\n            Assert.Equal(customException.CustomInt, ceCopy.CustomInt);\n        }\n\n        [Fact]\n        public void GeneratedSerializersRoundTripThroughSerializer_Polymorphic()\n        {\n            var original = new SomeSubClass\n            { SbcString = \"Shaggy\", SbcInteger = 13, SscString = \"Zoinks!\", SscInteger = -1 };\n\n            var getSubClassSerializerResult = RoundTripToExpectedType<SomeSubClass, SomeSubClass>(original);\n            Assert.Equal(original.SscString, getSubClassSerializerResult.SscString);\n            Assert.Equal(original.SscInteger, getSubClassSerializerResult.SscInteger);\n\n            var getBaseClassSerializerResult = RoundTripToExpectedType<SomeBaseClass, SomeSubClass>(original);\n            Assert.Equal(original.SscString, getBaseClassSerializerResult.SscString);\n            Assert.Equal(original.SscInteger, getBaseClassSerializerResult.SscInteger);\n        }\n\n        [Fact]\n        public void GeneratedSerializersRoundTripThroughSerializer_PolymorphicMultiHierarchy()\n        {\n            var someSubClass = new SomeSubClass\n            { SbcString = \"Shaggy\", SbcInteger = 13, SscString = \"Zoinks!\", SscInteger = -1 };\n\n            var otherSubClass = new OtherSubClass\n            { SbcString = \"sbcs\", SbcInteger = 2000, OtherSubClassString = \"oscs\", OtherSubClassInt = 1000 };\n\n            var someSubClassChild = new SomeSubClassChild\n            { SbcString = \"a\", SbcInteger = 0, SscString = \"Zoinks!\", SscInteger = -1, SomeSubClassChildString = \"string!\", SomeSubClassChildInt = 5858 };\n\n            var someSubClassResult = RoundTripToExpectedType<SomeBaseClass, SomeSubClass>(someSubClass);\n            Assert.Equal(someSubClass.SscString, someSubClassResult.SscString);\n            Assert.Equal(someSubClass.SscInteger, someSubClassResult.SscInteger);\n            Assert.Equal(someSubClass.SbcString, someSubClassResult.SbcString);\n            Assert.Equal(someSubClass.SbcInteger, someSubClassResult.SbcInteger);\n\n            var otherSubClassResult = RoundTripToExpectedType<SomeBaseClass, OtherSubClass>(otherSubClass);\n            Assert.Equal(otherSubClass.OtherSubClassString, otherSubClassResult.OtherSubClassString);\n            Assert.Equal(otherSubClass.OtherSubClassInt, otherSubClassResult.OtherSubClassInt);\n            Assert.Equal(otherSubClass.SbcString, otherSubClassResult.SbcString);\n            Assert.Equal(otherSubClass.SbcInteger, otherSubClassResult.SbcInteger);\n\n            var someSubClassChildResult = RoundTripToExpectedType<SomeBaseClass, SomeSubClassChild>(someSubClassChild);\n            Assert.Equal(someSubClassChild.SomeSubClassChildString, someSubClassChildResult.SomeSubClassChildString);\n            Assert.Equal(someSubClassChild.SomeSubClassChildInt, someSubClassChildResult.SomeSubClassChildInt);\n            Assert.Equal(someSubClassChild.SscString, someSubClassChildResult.SscString);\n            Assert.Equal(someSubClassChild.SscInteger, someSubClassChildResult.SscInteger);\n            Assert.Equal(someSubClassChild.SbcString, someSubClassChildResult.SbcString);\n            Assert.Equal(someSubClassChild.SbcInteger, someSubClassChildResult.SbcInteger);\n        }\n\n        [Fact]\n        public void DeepCopyPolymorphicTypes()\n        {\n            var someBaseClass = new SomeBaseClass\n            { SbcString = \"Shaggy\", SbcInteger = 13 };\n\n            var someSubClass = new SomeSubClass\n            { SbcString = \"Shaggy\", SbcInteger = 13, SscString = \"Zoinks!\", SscInteger = -1 };\n\n            var otherSubClass = new OtherSubClass\n            { SbcString = \"sbcs\", SbcInteger = 2000, OtherSubClassString = \"oscs\", OtherSubClassInt = 1000 };\n\n            var someSubClassChild = new SomeSubClassChild\n            { SbcString = \"a\", SbcInteger = 0, SscString = \"Zoinks!\", SscInteger = -1, SomeSubClassChildString = \"string!\", SomeSubClassChildInt = 5858 };\n\n            var someBaseClassResult = DeepCopy(someBaseClass);\n            Assert.Equal(someBaseClass.SbcString, someBaseClassResult.SbcString);\n            Assert.Equal(someBaseClass.SbcInteger, someBaseClassResult.SbcInteger);\n\n            var someSubClassResult = DeepCopy(someSubClass);\n            Assert.Equal(someSubClass.SscString, someSubClassResult.SscString);\n            Assert.Equal(someSubClass.SscInteger, someSubClassResult.SscInteger);\n            Assert.Equal(someSubClass.SbcString, someSubClassResult.SbcString);\n            Assert.Equal(someSubClass.SbcInteger, someSubClassResult.SbcInteger);\n\n            var otherSubClassResult = DeepCopy(otherSubClass);\n            Assert.Equal(otherSubClass.OtherSubClassString, otherSubClassResult.OtherSubClassString);\n            Assert.Equal(otherSubClass.OtherSubClassInt, otherSubClassResult.OtherSubClassInt);\n            Assert.Equal(otherSubClass.SbcString, otherSubClassResult.SbcString);\n            Assert.Equal(otherSubClass.SbcInteger, otherSubClassResult.SbcInteger);\n\n            var someSubClassChildResult = DeepCopy(someSubClassChild);\n            Assert.Equal(someSubClassChild.SomeSubClassChildString, someSubClassChildResult.SomeSubClassChildString);\n            Assert.Equal(someSubClassChild.SomeSubClassChildInt, someSubClassChildResult.SomeSubClassChildInt);\n            Assert.Equal(someSubClassChild.SscString, someSubClassChildResult.SscString);\n            Assert.Equal(someSubClassChild.SscInteger, someSubClassChildResult.SscInteger);\n            Assert.Equal(someSubClassChild.SbcString, someSubClassChildResult.SbcString);\n            Assert.Equal(someSubClassChild.SbcInteger, someSubClassChildResult.SbcInteger);\n\n        }\n\n        private TActual RoundTripToExpectedType<TBase, TActual>(TActual original)\n            where TActual : TBase\n        {\n            var serializer = _serviceProvider.GetService<Serializer<TBase>>();\n            var array = serializer.SerializeToArray(original);\n\n            string formatted;\n            {\n                using var session = _serviceProvider.GetRequiredService<SerializerSessionPool>().GetSession();\n                formatted = BitStreamFormatter.Format(array, session);\n            }\n\n            return (TActual)serializer.Deserialize(array);\n        }\n\n        private T DeepCopy<T>(T original)\n        {\n            var deepCopier = _serviceProvider.GetService<DeepCopier<T>>();\n            return deepCopier.Copy(original);\n        }\n\n        [Id(1000)]\n        [GenerateSerializer]\n        public class SomeBaseClass\n        {\n            [Id(0)]\n            public string SbcString { get; set; }\n\n            [Id(1)]\n            public int SbcInteger { get; set; }\n        }\n\n        [Id(1001)]\n        [GenerateSerializer]\n        public class SomeSubClass : SomeBaseClass\n        {\n            [Id(0)]\n            public int SscInteger { get; set; }\n\n            [Id(1)]\n            public string SscString { get; set; }\n        }\n\n        [Id(1002)]\n        [GenerateSerializer]\n        public class OtherSubClass : SomeBaseClass\n        {\n            [Id(0)]\n            public int OtherSubClassInt { get; set; }\n\n            [Id(1)]\n            public string OtherSubClassString { get; set; }\n        }\n\n        [Id(1003)]\n        [GenerateSerializer]\n        public class SomeSubClassChild : SomeSubClass\n        {\n            [Id(0)]\n            public int SomeSubClassChildInt { get; set; }\n\n            [Id(1)]\n            public string SomeSubClassChildString { get; set; }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/PooledBufferTests.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Runtime.InteropServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Session;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' PooledBuffer implementation.\n    /// \n    /// PooledBuffer is a high-performance buffer management system that:\n    /// - Uses ArrayPool to minimize allocations and GC pressure\n    /// - Supports efficient slicing operations without copying\n    /// - Handles large data through segmented storage\n    /// - Provides zero-copy access to buffer contents\n    /// \n    /// Key features tested:\n    /// - Large buffer handling (multi-megabyte)\n    /// - Slicing operations at various offsets\n    /// - Memory safety and bounds checking\n    /// - Proper cleanup and return to pool\n    /// \n    /// This infrastructure is critical for Orleans' serialization performance,\n    /// especially when handling large object graphs or streaming scenarios.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public class PooledBufferTests\n    {\n        [Fact]\n        public void LargeBufferRoundTrip()\n        {\n            var random = new Random();\n            var buffer = new PooledBuffer();\n            var randomData = new byte[1024 * 1024 * 10];\n            random.NextBytes(randomData);\n            buffer.Write(randomData);\n\n            var slice4 = buffer.Slice(3000, 1500);\n            var sliceArray4 = slice4.ToArray();\n            Assert.True(randomData.AsSpan(3000, 1500).SequenceEqual(sliceArray4));\n\n            var slice = buffer.Slice();\n            var sliceArray = slice.ToArray();\n            Assert.True(randomData.AsSpan().SequenceEqual(sliceArray));\n\n            var slice3 = buffer.Slice(100, 1024);\n            var sliceArray3 = slice3.ToArray();\n            Assert.True(randomData.AsSpan(100, 1024).SequenceEqual(sliceArray3));\n\n            var slice2 = buffer.Slice(100);\n            var sliceArray2 = slice2.ToArray();\n            var slicedRandomData = randomData.AsSpan(100).ToArray();\n            Assert.True(slicedRandomData.AsSpan().SequenceEqual(sliceArray2));\n\n            var rosArray = new byte[randomData.Length];\n            buffer.AsReadOnlySequence().CopyTo(rosArray.AsSpan());\n            Assert.True(randomData.AsSpan().SequenceEqual(rosArray));\n\n            var spansArray = new byte[randomData.Length];\n            var spansArraySpan = spansArray.AsSpan();\n            foreach (var span in buffer.Slice())\n            {\n                span.CopyTo(spansArraySpan);\n                spansArraySpan = spansArraySpan[span.Length..];\n            }\n\n            Assert.True(randomData.AsSpan().SequenceEqual(spansArray));\n\n            buffer.Dispose();\n        }\n\n        [Fact]\n        public void LargeBufferRoundTrip_Single()\n        {\n            var random = new Random();\n            var buffer = new PooledBuffer();\n            var randomData = new byte[1024 * 1024 * 10];\n            random.NextBytes(randomData);\n            buffer.Write(randomData);\n\n            var contents = buffer.ToArray();\n            Assert.True(randomData.AsSpan().SequenceEqual(contents));\n\n            buffer.Dispose();\n        }\n\n        [Fact]\n        public void LargeBufferRoundTrip_ReaderWriter()\n        {\n            var random = new Random();\n            var randomData = new byte[1024 * 1024 * 10];\n            random.NextBytes(randomData);\n            var writer = Writer.Create(new PooledBuffer(), null);\n            writer.Write(randomData);\n            writer.Commit();\n\n            var slice = writer.Output.Slice();\n            var sliceReader = Reader.Create(slice, null);\n            var sliceArray = sliceReader.ReadBytes((uint)randomData.Length);\n            Assert.True(randomData.AsSpan().SequenceEqual(sliceArray));\n\n            var slice3 = writer.Output.Slice(100, 1024);\n            var reader3 = Reader.Create(slice3, null);\n            var result3 = reader3.ReadBytes((uint)slice3.Length);\n            Assert.True(randomData.AsSpan(100, 1024).SequenceEqual(result3));\n\n            var slice2 = writer.Output.Slice(100);\n            var reader2 = Reader.Create(slice2, null);\n            var result2 = reader2.ReadBytes((uint)slice2.Length);\n            Assert.True(randomData.AsSpan(100).SequenceEqual(result2));\n\n            var slice4 = writer.Output.Slice(3000, 1500);\n            var reader4 = Reader.Create(slice4, null);\n            var result4 = reader4.ReadBytes((uint)slice4.Length);\n            Assert.True(randomData.AsSpan(3000, 1500).SequenceEqual(result4));\n\n            var slice5 = writer.Output.Slice(4500, 125);\n            var reader5 = Reader.Create(slice5, null);\n            var result5 = reader5.ReadBytes((uint)slice5.Length);\n            Assert.True(randomData.AsSpan(4500, 125).SequenceEqual(result5));\n\n            var ros = writer.Output.AsReadOnlySequence();\n            var rosReader = Reader.Create(ros, null);\n            var rosArray = rosReader.ReadBytes((uint)randomData.Length);\n            Assert.True(randomData.AsSpan().SequenceEqual(rosArray));\n\n            writer.Dispose();\n        }\n\n        /// <summary>\n        /// Regression test for https://github.com/dotnet/orleans/issues/8503\n        /// </summary>\n        [Fact]\n        public void PooledBuffer_WriteTwice()\n        {\n            var serviceProvider = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            var pool = serviceProvider.GetRequiredService<SerializerSessionPool>();\n            var serializer = serviceProvider.GetRequiredService<Serializer>();\n            var obj = LargeObject.BuildRandom();\n\n            SerializeObject(pool, serializer, obj);\n            SerializeObject(pool, serializer, obj);\n\n            static void SerializeObject(SerializerSessionPool pool, Serializer serializer, LargeObject obj)\n            {\n                Writer<PooledBuffer> writer = default;\n                var session = pool.GetSession();\n                try\n                {\n                    writer = Writer.CreatePooled(session);\n                    serializer.Serialize(obj, ref writer);\n\n                    var sequence = writer.Output.AsReadOnlySequence();\n                    Assert.Equal(writer.Output.Length, sequence.Length);\n                }\n                finally\n                {\n                    writer.Dispose();\n                    session.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Tests that the serializer can correctly serialized <see cref=\"PooledBuffer\"/>.\n        /// </summary>\n        [Fact]\n        public void PooledBuffer_SerializerRoundTrip()\n        {\n            var serviceProvider = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            var serializer = serviceProvider.GetRequiredService<Serializer>();\n\n            var random = new Random();\n            for (var i = 0; i < 10; i++)\n            {\n                const int TargetLength = 8120;\n\n                // NOTE: The serializer is responsible for freeing the buffer provided to it, so we do not free this.\n                var buffer = new PooledBuffer();\n                while (buffer.Length < TargetLength)\n                {\n                    var span = buffer.GetSpan(TargetLength - buffer.Length);\n                    var writeLen = Math.Min(span.Length, TargetLength - buffer.Length);\n                    random.NextBytes(span[..writeLen]);\n                    buffer.Advance(writeLen);\n                }\n\n                var bytes = buffer.ToArray();\n                Assert.Equal(TargetLength, bytes.Length);\n\n                var result = serializer.Deserialize<PooledBuffer>(serializer.SerializeToArray(buffer));\n                Assert.Equal(TargetLength, result.Length);\n\n                var resultBytes = result.ToArray();\n                Assert.Equal(bytes, resultBytes);\n\n                // NOTE: we are responsible for disposing a buffer returned from deserialization.\n                result.Dispose();\n            }\n        }\n\n        /// <summary>\n        /// Tests that the serializer can correctly serialized <see cref=\"PooledBuffer\"/> when it's embedded in another structure.\n        /// </summary>\n        [Fact]\n        public void PooledBuffer_SerializerRoundTrip_Embedded()\n        {\n            var serviceProvider = new ServiceCollection()\n                .AddSerializer()\n                .BuildServiceProvider();\n            var serializer = serviceProvider.GetRequiredService<Serializer>();\n\n            var random = new Random();\n            for (var i = 0; i < 10; i++)\n            {\n                const int TargetLength = 8120;\n\n                // NOTE: The serializer is responsible for freeing the buffer provided to it, so we do not free this.\n                var buffer = new PooledBuffer();\n                while (buffer.Length < TargetLength)\n                {\n                    var span = buffer.GetSpan(TargetLength - buffer.Length);\n                    var writeLen = Math.Min(span.Length, TargetLength - buffer.Length);\n                    random.NextBytes(span[..writeLen]);\n                    buffer.Advance(writeLen);\n                }\n\n                var bytes = buffer.ToArray();\n                Assert.Equal(TargetLength, bytes.Length);\n\n                var embed = (Guid: Guid.NewGuid(), Buffer: buffer, Int: 42);\n                var result = serializer.Deserialize<(Guid Guid, PooledBuffer Buffer, int Int)>(serializer.SerializeToArray(embed));\n                Assert.Equal(embed.Guid, result.Guid);\n                Assert.Equal(embed.Int, result.Int);\n                var resultBuffer = result.Buffer;\n                Assert.Equal(TargetLength, resultBuffer.Length);\n\n                var resultBytes = resultBuffer.ToArray();\n                Assert.Equal(bytes, resultBytes);\n\n                // NOTE: we are responsible for disposing a buffer returned from deserialization.\n                resultBuffer.Dispose();\n            }\n        }\n\n        [GenerateSerializer]\n        public readonly record struct LargeObject(\n            [property: Id(0)] Guid Id,\n            [property: Id(1)] (Guid, Guid)[] Values)\n        {\n            public static LargeObject BuildRandom()\n            {\n                var id = Guid.NewGuid();\n                var values = new (Guid, Guid)[256];\n\n                for (var i = 0; i < values.Length; i++)\n                {\n                    values[i] = (Guid.NewGuid(), Guid.NewGuid());\n                }\n\n                return new(id, values);\n            }\n        }\n\n        /// <summary>\n        /// Ensures that BufferSlice's SpanEnumerator and MemoryEnumerator correctly handle non-zero offsets that cross segment boundaries.\n        /// This test exercises the offset math for enumerators when the slice starts partway through a segment and spans multiple segments.\n        /// </summary>\n        [Fact]\n        public void PooledBuffer_SliceEnumerators_OffsetCrossSegment_Correctness()\n        {\n            // Arrange: Write enough data to ensure multiple segments\n            var random = new Random(42);\n            var buffer = new PooledBuffer();\n            int totalLength = 16 * 1024; // 16KB, should span multiple segments (4KB min segment size)\n            var data = new byte[totalLength];\n            random.NextBytes(data);\n            buffer.Write(data);\n\n            // Pick an offset and length that will cross segment boundaries\n            int offset = 3500; // Not aligned to segment boundary\n            int length = 7000; // Crosses at least one segment boundary\n            var expected = data.AsSpan(offset, length).ToArray();\n\n            // Act & Assert: SpanEnumerator\n            var slice = buffer.Slice(offset, length);\n            var spanConcat = new byte[length];\n            int spanPos = 0;\n            foreach (var span in slice)\n            {\n                span.CopyTo(spanConcat.AsSpan(spanPos));\n                spanPos += span.Length;\n            }\n            Assert.Equal(length, spanPos);\n            Assert.Equal(expected, spanConcat);\n\n            // Act & Assert: MemoryEnumerator\n            var memConcat = new byte[length];\n            int memPos = 0;\n            foreach (var mem in slice.MemorySegments)\n            {\n                var span = mem.Span;\n                span.CopyTo(memConcat.AsSpan(memPos));\n                memPos += span.Length;\n            }\n            Assert.Equal(length, memPos);\n            Assert.Equal(expected, memConcat);\n\n            buffer.Dispose();\n        }\n\n        /// <summary>\n        /// Ensures that BufferSlice's SpanEnumerator and MemoryEnumerator exercise the code path where the enumerator's position is greater than zero.\n        /// This is achieved by using a slice offset that skips at least one full segment, so the enumerator must skip segments before yielding data.\n        /// The test validates that the enumerators return the correct data for such non-zero offsets.\n        /// </summary>\n        [Fact]\n        public void PooledBuffer_SliceEnumerators_OffsetAfterFirstSegment_CoversPositionGreaterThanZero()\n        {\n            // This test ensures that the BufferSlice enumerators exercise the branch where _position > 0\n            // by using a slice offset that skips at least one full segment. The correctness of the output\n            // validates that the offset math is correct for non-zero _position.\n            var random = new Random(123);\n            var buffer = new PooledBuffer();\n            int segmentSize = 4 * 1024; // MinimumBlockSize\n            int totalLength = segmentSize * 3; // 3 segments\n            var data = new byte[totalLength];\n            random.NextBytes(data);\n            buffer.Write(data);\n\n            // Pick an offset that is after the first segment\n            int offset = segmentSize + 123; // Offset into the second segment\n            int length = 1000; // Arbitrary length within the second segment\n            var expected = data.AsSpan(offset, length).ToArray();\n\n            // Act & Assert: SpanEnumerator\n            var slice = buffer.Slice(offset, length);\n            var spanConcat = new byte[length];\n            int spanPos = 0;\n            foreach (var span in slice)\n            {\n                span.CopyTo(spanConcat.AsSpan(spanPos));\n                spanPos += span.Length;\n            }\n            Assert.Equal(length, spanPos);\n            Assert.Equal(expected, spanConcat);\n\n            // Act & Assert: MemoryEnumerator\n            var memConcat = new byte[length];\n            int memPos = 0;\n            foreach (var mem in slice.MemorySegments)\n            {\n                var span = mem.Span;\n                span.CopyTo(memConcat.AsSpan(memPos));\n                memPos += span.Length;\n            }\n            Assert.Equal(length, memPos);\n            Assert.Equal(expected, memConcat);\n\n            buffer.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Properties/IsExternalInit.cs",
    "content": "namespace System.Runtime.CompilerServices\n{\n    internal static class IsExternalInit {}\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Properties/RequiredMemberAttribute.cs",
    "content": "﻿namespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]\n    internal sealed class RequiredMemberAttribute : Attribute { }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ProtobufSerializerTests.cs",
    "content": "#nullable enable\nusing System;\nusing System.Linq;\nusing Google.Protobuf;\nusing Google.Protobuf.Collections;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Serialization.Cloning;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.Serializers;\nusing Orleans.Serialization.TestKit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for Orleans' Protocol Buffers (protobuf) serialization support.\n/// \n/// Protocol Buffers is Google's language-neutral, platform-neutral serialization format that provides:\n/// - Compact binary encoding\n/// - Strong schema definition through .proto files\n/// - Excellent cross-language support\n/// - Forward and backward compatibility\n/// \n/// Orleans' protobuf integration:\n/// - Supports Google.Protobuf generated classes\n/// - Handles protobuf collections and nested messages\n/// - Provides both serialization and deep copy functionality\n/// - Integrates with Orleans' type system for polymorphism\n/// \n/// This integration is valuable when:\n/// - Interfacing with gRPC services\n/// - Sharing data with non-.NET systems\n/// - Requiring schema-first development\n/// - Needing highly optimized wire format\n/// </summary>\n[Trait(\"Category\", \"BVT\")]\npublic class ProtobufSerializerTests : FieldCodecTester<MyProtobufClass?, IFieldCodec<MyProtobufClass?>>\n{\n    public ProtobufSerializerTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddProtobufSerializer();\n    }\n\n    protected override MyProtobufClass? CreateValue() => new() { IntProperty = 30, StringProperty = \"hello\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n\n    protected override MyProtobufClass?[] TestValues => new MyProtobufClass?[]\n    {\n        null,\n        new () { SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n        new () { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n        new () { IntProperty = -150_000, StringProperty = new string('c', 6_000), SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n    };\n\n    [Fact]\n    public void ProtobufSerializerDeepCopyTyped()\n    {\n        var original = new MyProtobufClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier<MyProtobufClass>>();\n        var result = copier.Copy(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n\n    [Fact]\n    public void ProtobufSerializerDeepCopyUntyped()\n    {\n        var original = new MyProtobufClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n        var copier = ServiceProvider.GetRequiredService<DeepCopier>();\n        var result = (MyProtobufClass)copier.Copy((object)original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n\n    [Fact]\n    public void ProtobufSerializerRoundTripThroughCodec()\n    {\n        var original = new MyProtobufClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n        var result = RoundTripThroughCodec(original);\n\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n\n    [Fact]\n    public void ProtobufSerializerRoundTripThroughUntypedSerializer()\n    {\n        var original = new MyProtobufClass { IntProperty = 30, StringProperty = \"hi\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n        var untypedResult = RoundTripThroughUntypedSerializer(original, out _);\n\n        var result = Assert.IsType<MyProtobufClass>(untypedResult);\n        Assert.Equal(original.IntProperty, result.IntProperty);\n        Assert.Equal(original.StringProperty, result.StringProperty);\n    }\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class ProtobufCodecCopierTests : CopierTester<MyProtobufClass?, IDeepCopier<MyProtobufClass?>>\n{\n    public ProtobufCodecCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override void Configure(ISerializerBuilder builder)\n    {\n        builder.AddProtobufSerializer();\n    }\n    protected override IDeepCopier<MyProtobufClass?> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<MyProtobufClass?>();\n\n    protected override MyProtobufClass? CreateValue() => new MyProtobufClass { IntProperty = 30, StringProperty = \"hello\", SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } };\n\n    protected override MyProtobufClass?[] TestValues => new MyProtobufClass?[]\n    {\n        null,\n        new () { SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n        new () { IntProperty = 150, StringProperty = new string('c', 20), SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n        new () { IntProperty = -150_000, StringProperty = new string('c', 6_000), SubClass = new MyProtobufClass.Types.SubClass { Id = Guid.NewGuid().ToByteString() } },\n    };\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class ProtobufRepeatedFieldCodecTests : FieldCodecTester<RepeatedField<int>, RepeatedFieldCodec<int>>\n{\n    public ProtobufRepeatedFieldCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override RepeatedField<int> CreateValue()\n    {\n        var result = new RepeatedField<int>();\n        for (var i = 0; i < Random.Next(17) + 5; i++)\n        {\n            result.Add(Random.Next());\n        }\n\n        return result;\n    }\n\n    protected override bool Equals(RepeatedField<int> left, RepeatedField<int> right) => object.ReferenceEquals(left, right) || left.SequenceEqual(right);\n    protected override RepeatedField<int>[] TestValues => new[] { new RepeatedField<int>(), CreateValue(), CreateValue(), CreateValue() };\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class ProtobufRepeatedFieldCopierTests : CopierTester<RepeatedField<int>, IDeepCopier<RepeatedField<int>>>\n{\n    public ProtobufRepeatedFieldCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override IDeepCopier<RepeatedField<int>> CreateCopier() => ServiceProvider.GetRequiredService<ICodecProvider>().GetDeepCopier<RepeatedField<int>>();\n\n    protected override RepeatedField<int> CreateValue()\n    {\n        var result = new RepeatedField<int>();\n        for (var i = 0; i < Random.Next(17) + 5; i++)\n        {\n            result.Add(Random.Next());\n        }\n\n        return result;\n    }\n\n    protected override bool Equals(RepeatedField<int> left, RepeatedField<int> right) => object.ReferenceEquals(left, right) || left.SequenceEqual(right);\n    protected override RepeatedField<int>[] TestValues => new[] { new RepeatedField<int>(), CreateValue(), CreateValue(), CreateValue() };\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class MapFieldCodecTests : FieldCodecTester<MapField<string, int>, MapFieldCodec<string, int>>\n{\n    public MapFieldCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MapField<string, int> CreateValue()\n    {\n        var result = new MapField<string, int>();\n        for (var i = 0; i < Random.Next(17) + 5; i++)\n        {\n            result[Random.Next().ToString()] = Random.Next();\n        }\n\n        return result;\n    }\n\n    protected override MapField<string, int>[] TestValues => new[] { new MapField<string, int>(), CreateValue(), CreateValue(), CreateValue() };\n    protected override bool Equals(MapField<string, int> left, MapField<string, int> right) => object.ReferenceEquals(left, right) || left.SequenceEqual(right);\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class MapFieldCopierTests : CopierTester<MapField<string, int>, MapFieldCopier<string, int>>\n{\n    public MapFieldCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override MapField<string, int> CreateValue()\n    {\n        var result = new MapField<string, int>();\n        for (var i = 0; i < Random.Next(17) + 5; i++)\n        {\n            result[Random.Next().ToString()] = Random.Next();\n        }\n\n        return result;\n    }\n\n    protected override MapField<string, int>[] TestValues => new[] { new MapField<string, int>(), CreateValue(), CreateValue(), CreateValue() };\n    protected override bool Equals(MapField<string, int> left, MapField<string, int> right) => object.ReferenceEquals(left, right) || left.SequenceEqual(right);\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class ByteStringCodecTests : FieldCodecTester<ByteString, ByteStringCodec>\n{\n    public ByteStringCodecTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override ByteString CreateValue() => Guid.NewGuid().ToByteString();\n\n    protected override bool Equals(ByteString left, ByteString right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n\n    protected override ByteString[] TestValues => new[]\n    {\n        ByteString.Empty,\n        ByteString.CopyFrom(Enumerable.Range(0, 4097).Select(b => unchecked((byte)b)).ToArray()),\n        CreateValue()\n    };\n}\n\n[Trait(\"Category\", \"BVT\")]\npublic class ByteStringCopierTests : CopierTester<ByteString, ByteStringCopier>\n{\n    public ByteStringCopierTests(ITestOutputHelper output) : base(output)\n    {\n    }\n\n    protected override ByteString CreateValue() => Guid.NewGuid().ToByteString();\n\n    protected override bool Equals(ByteString left, ByteString right) => ReferenceEquals(left, right) || left.SequenceEqual(right);\n\n    protected override ByteString[] TestValues => new[]\n    {\n        ByteString.Empty,\n        ByteString.CopyFrom(Enumerable.Range(0, 4097).Select(b => unchecked((byte)b)).ToArray()),\n        CreateValue()\n    };\n}\n\npublic static class ProtobufGuidExtensions\n{\n    public static ByteString ToByteString(this Guid guid)\n    {\n        Span<byte> span = stackalloc byte[16];\n        guid.TryWriteBytes(span);\n        return ByteString.CopyFrom(span);\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/ReaderWriterTests.cs",
    "content": "using CsCheck;\nusing Orleans.Serialization.Buffers;\nusing Orleans.Serialization.Buffers.Adaptors;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.TestKit;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Buffers;\nusing System.Collections.Generic;\nusing System.IO;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Serialization.Codecs;\nusing Orleans.Serialization.WireProtocol;\nusing System.Runtime.InteropServices;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' low-level Reader and Writer implementations.\n    /// \n    /// These tests verify the fundamental building blocks of Orleans serialization:\n    /// - Binary encoding/decoding of primitive types\n    /// - Variable-length integer encoding (VarInt) for space efficiency\n    /// - Buffer management and pooling strategies\n    /// - Stream-based and memory-based I/O operations\n    /// \n    /// The Reader/Writer infrastructure provides:\n    /// - High-performance binary serialization primitives\n    /// - Zero-allocation patterns for common scenarios\n    /// - Support for various buffer types (streams, arrays, pipes)\n    /// - Efficient handling of large data through segmented buffers\n    /// \n    /// These components are critical for Orleans' wire protocol efficiency\n    /// and directly impact the performance of grain communication.\n    /// </summary>\n    [Trait(\"Category\", \"BVT\")]\n    public sealed class ReaderWriterPoolingStreamTest : ReaderWriterTestBase<Stream, PoolingStreamBufferWriter, ReaderInput>\n    {\n        public ReaderWriterPoolingStreamTest(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override Stream CreateBuffer() => new MemoryStream();\n        protected override Reader<ReaderInput> CreateReader(Stream buffer, SerializerSession session)\n        {\n            buffer.Position = 0;\n            return Reader.Create(buffer, session);\n        }\n\n        protected override Writer<PoolingStreamBufferWriter> CreateWriter(Stream buffer, SerializerSession session) => Writer.CreatePooled(buffer, session);\n        protected override Stream GetBuffer(Stream originalBuffer, PoolingStreamBufferWriter output) => originalBuffer;\n        protected override void DisposeBuffer(Stream buffer, PoolingStreamBufferWriter output)\n        {\n            output.Dispose();\n            buffer.Dispose();\n        }\n\n        [Fact]\n        public override void VarUInt32RoundTrip() => VarUInt32RoundTripTest();\n\n        [Fact]\n        public override void VarUInt64RoundTrip() => VarUInt64RoundTripTest();\n\n        [Fact]\n        public override void Int64RoundTrip() => Int64RoundTripTest();\n\n        [Fact]\n        public override void Int32RoundTrip() => Int32RoundTripTest();\n\n        [Fact]\n        public override void UInt64RoundTrip() => UInt64RoundTripTest();\n\n        [Fact]\n        public override void UInt32RoundTrip() => UInt32RoundTripTest();\n\n        [Fact]\n        protected override void ByteRoundTrip() => ByteRoundTripTest();\n    }\n\n    [Trait(\"Category\", \"BVT\")]\n    public sealed class ReaderWriterStreamTest : ReaderWriterTestBase<Stream, ArrayStreamBufferWriter, ReaderInput>\n    {\n        public ReaderWriterStreamTest(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override Stream CreateBuffer() => new MemoryStream();\n        protected override Reader<ReaderInput> CreateReader(Stream buffer, SerializerSession session)\n        {\n            buffer.Position = 0;\n            return Reader.Create(buffer, session);\n        }\n\n        protected override Writer<ArrayStreamBufferWriter> CreateWriter(Stream buffer, SerializerSession session) => Writer.Create(buffer, session);\n        protected override Stream GetBuffer(Stream originalBuffer, ArrayStreamBufferWriter output) => originalBuffer;\n        protected override void DisposeBuffer(Stream buffer, ArrayStreamBufferWriter output) => buffer.Dispose();\n\n        [Fact]\n        public override void VarUInt32RoundTrip() => VarUInt32RoundTripTest();\n\n        [Fact]\n        public override void VarUInt64RoundTrip() => VarUInt64RoundTripTest();\n\n        [Fact]\n        public override void Int64RoundTrip() => Int64RoundTripTest();\n\n        [Fact]\n        public override void Int32RoundTrip() => Int32RoundTripTest();\n\n        [Fact]\n        public override void UInt64RoundTrip() => UInt64RoundTripTest();\n\n        [Fact]\n        public override void UInt32RoundTrip() => UInt32RoundTripTest();\n\n        [Fact]\n        protected override void ByteRoundTrip() => ByteRoundTripTest();\n    }\n\n    [Trait(\"Category\", \"BVT\")]\n    public sealed class ReaderWriterMemoryStreamTest : ReaderWriterTestBase<MemoryStream, MemoryStreamBufferWriter, ReaderInput>\n    {\n        public ReaderWriterMemoryStreamTest(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override MemoryStream CreateBuffer() => new();\n        protected override Reader<ReaderInput> CreateReader(MemoryStream buffer, SerializerSession session)\n        {\n            buffer.Position = 0;\n            return Reader.Create(buffer, session);\n        }\n\n        protected override Writer<MemoryStreamBufferWriter> CreateWriter(MemoryStream buffer, SerializerSession session) => Writer.Create(buffer, session);\n        protected override MemoryStream GetBuffer(MemoryStream originalBuffer, MemoryStreamBufferWriter output) => originalBuffer;\n        protected override void DisposeBuffer(MemoryStream buffer, MemoryStreamBufferWriter output) => buffer.Dispose();\n\n        [Fact]\n        public override void VarUInt32RoundTrip() => VarUInt32RoundTripTest();\n\n        [Fact]\n        public override void VarUInt64RoundTrip() => VarUInt64RoundTripTest();\n\n        [Fact]\n        public override void Int64RoundTrip() => Int64RoundTripTest();\n\n        [Fact]\n        public override void Int32RoundTrip() => Int32RoundTripTest();\n\n        [Fact]\n        public override void UInt64RoundTrip() => UInt64RoundTripTest();\n\n        [Fact]\n        public override void UInt32RoundTrip() => UInt32RoundTripTest();\n\n        [Fact]\n        protected override void ByteRoundTrip() => ByteRoundTripTest();\n    }\n\n    [Trait(\"Category\", \"BVT\")]\n    public sealed class ReaderWriterSpanTest : ReaderWriterTestBase<byte[], SpanBufferWriter, SpanReaderInput>\n    {\n        public ReaderWriterSpanTest(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override byte[] CreateBuffer() => new byte[100];\n        protected override Reader<SpanReaderInput> CreateReader(byte[] buffer, SerializerSession session) => Reader.Create(buffer, session);\n        protected override Writer<SpanBufferWriter> CreateWriter(byte[] buffer, SerializerSession session) => Writer.Create(buffer, session);\n        protected override byte[] GetBuffer(byte[] originalBuffer, SpanBufferWriter output) => originalBuffer;\n        protected override void DisposeBuffer(byte[] buffer, SpanBufferWriter output)\n        {\n        }\n\n        [Fact]\n        public override void VarUInt32RoundTrip() => VarUInt32RoundTripTest();\n\n        [Fact]\n        public override void VarUInt64RoundTrip() => VarUInt64RoundTripTest();\n\n        [Fact]\n        public override void Int64RoundTrip() => Int64RoundTripTest();\n\n        [Fact]\n        public override void Int32RoundTrip() => Int32RoundTripTest();\n\n        [Fact]\n        public override void UInt64RoundTrip() => UInt64RoundTripTest();\n\n        [Fact]\n        public override void UInt32RoundTrip() => UInt32RoundTripTest();\n\n        [Fact]\n        protected override void ByteRoundTrip() => ByteRoundTripTest();\n    }\n\n    [Trait(\"Category\", \"BVT\")]\n    public sealed class ReaderWriterSegmentWriterTest : ReaderWriterTestBase<TestMultiSegmentBufferWriter, TestMultiSegmentBufferWriter, ReadOnlySequenceInput>\n    {\n        public ReaderWriterSegmentWriterTest(ITestOutputHelper output) : base(output)\n        {\n        }\n\n        protected override TestMultiSegmentBufferWriter CreateBuffer() => new(maxAllocationSize: 10);\n        protected override Reader<ReadOnlySequenceInput> CreateReader(TestMultiSegmentBufferWriter buffer, SerializerSession session) => Reader.Create(buffer.GetReadOnlySequence(maxSegmentSize: 8), session);\n        protected override Writer<TestMultiSegmentBufferWriter> CreateWriter(TestMultiSegmentBufferWriter buffer, SerializerSession session) => Writer.Create(buffer, session);\n        protected override TestMultiSegmentBufferWriter GetBuffer(TestMultiSegmentBufferWriter originalBuffer, TestMultiSegmentBufferWriter output) => output;\n        protected override void DisposeBuffer(TestMultiSegmentBufferWriter buffer, TestMultiSegmentBufferWriter output)\n        {\n        }\n\n        [Fact]\n        public override void VarUInt32RoundTrip() => VarUInt32RoundTripTest();\n\n        [Fact]\n        public override void VarUInt64RoundTrip() => VarUInt64RoundTripTest();\n\n        [Fact]\n        public override void Int64RoundTrip() => Int64RoundTripTest();\n\n        [Fact]\n        public override void Int32RoundTrip() => Int32RoundTripTest();\n\n        [Fact]\n        public override void UInt64RoundTrip() => UInt64RoundTripTest();\n\n        [Fact]\n        public override void UInt32RoundTrip() => UInt32RoundTripTest();\n\n        [Fact]\n        protected override void ByteRoundTrip() => ByteRoundTripTest();\n\n        [Fact]\n        public void SkipBufferEdge_ReadOnlySequence()\n        {\n            byte[] b = new byte[] { 25, 84, 101, 115, 116, 32, 97, 99, 99, 111, 117, 110 };\n            byte[] b2 = new byte[] { 116, 64, 0, 0, 0 };\n\n            var seq = ReadOnlySequenceHelper.CreateReadOnlySequence(b, b2);\n            using SerializerSession session = this.GetSession();\n            var reader = Reader.Create(seq, session);\n            SkipFieldExtension.SkipField(ref reader, new Field(new Tag((byte)WireType.LengthPrefixed)));\n\n            Assert.Equal(64, reader.ReadInt32());\n        }\n\n        [Fact]\n        public void SkipBufferEdge_BufferSlice()\n        {\n            byte[] b = new byte[] { 25, 84, 101, 115, 116, 32, 97, 99, 99, 111, 117, 110 };\n            byte[] b2 = new byte[] { 116, 64, 0, 0, 0 };\n\n            var buffer = new PooledBuffer();\n\n            // PooledBuffer / BufferSlice is more abstract than ReadOnlySequence, which is why we are relying on \n            // implementation details.\n            var buf = buffer.GetMemory(1);\n            Assert.True(MemoryMarshal.TryGetArray<byte>(buf, out var seg));\n            var offset = seg.Array.Length - b.Length;\n            buffer.Write(new byte[offset]);\n            buffer.Write(b);\n            buffer.Write(b2);\n            var slice = buffer.Slice(offset);\n\n            // Verify that the slices are what we expect.\n            var count = 0;\n            foreach (var s in slice)\n            {\n                if (count == 0)\n                {\n                    Assert.Equal(b, s.ToArray());\n                }\n                else\n                {\n                    Assert.Equal(b2, s.ToArray());\n                }\n\n                ++count;\n            }\n\n            Assert.Equal(2, count);\n\n            using SerializerSession session = this.GetSession();\n            var reader = Reader.Create(slice, session);\n            SkipFieldExtension.SkipField(ref reader, new Field(new Tag((byte)WireType.LengthPrefixed)));\n\n            Assert.Equal(64, reader.ReadInt32());\n            buffer.Dispose();\n        }\n    }\n\n    public abstract class ReaderWriterTestBase<TBuffer, TOutput, TInput> where TOutput : IBufferWriter<byte>\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly SerializerSessionPool _sessionPool;\n        private readonly ITestOutputHelper _testOutputHelper;\n\n        private delegate T ReadValue<T>(ref Reader<TInput> reader);\n        private delegate void WriteValue<T>(ref Writer<TOutput> writer, T value);\n\n        public ReaderWriterTestBase(ITestOutputHelper testOutputHelper)\n        {\n            var services = new ServiceCollection();\n            _ = services.AddSerializer();\n            _serviceProvider = services.BuildServiceProvider();\n            _sessionPool = _serviceProvider.GetService<SerializerSessionPool>();\n            _testOutputHelper = testOutputHelper;\n        }\n\n        protected SerializerSession GetSession() => _sessionPool.GetSession();\n        protected abstract TBuffer CreateBuffer();\n        protected abstract Reader<TInput> CreateReader(TBuffer buffer, SerializerSession session);\n        protected abstract Writer<TOutput> CreateWriter(TBuffer buffer, SerializerSession session);\n        protected abstract TBuffer GetBuffer(TBuffer originalBuffer, TOutput output);\n        protected abstract void DisposeBuffer(TBuffer buffer, TOutput output);\n\n        private Func<T, bool> CreateTestPredicate<T>(WriteValue<T> writeValue, ReadValue<T> readValue)\n        {\n            return Test;\n\n            bool Test(T expected)\n            {\n                var buffer = CreateBuffer();\n                using var writerSession = _sessionPool.GetSession();\n                var writer = CreateWriter(buffer, writerSession);\n                try\n                {\n                    for (int i = 0; i < 5; i++)\n                    {\n                        writeValue(ref writer, expected);\n                    }\n\n                    writer.Commit();\n                    using var readerSession = _sessionPool.GetSession();\n                    var readerBuffer = GetBuffer(buffer, writer.Output);\n                    var reader = CreateReader(readerBuffer, readerSession);\n\n                    for (int i = 0; i < 5; i++)\n                    {\n                        var actual = readValue(ref reader);\n                        if (!EqualityComparer<T>.Default.Equals(expected, actual))\n                        {\n                            _testOutputHelper.WriteLine(\n                                $\"Failure: Actual: \\\"{actual}\\\" (0x{actual:X}). Expected \\\"{expected}\\\" (0x{expected:X}). Iteration: {i}\");\n                            return false;\n                        }\n                    }\n\n                    return true;\n                }\n                finally\n                {\n                    var disposeBuffer = GetBuffer(buffer, writer.Output);\n                    DisposeBuffer(disposeBuffer, writer.Output);\n                }\n            }\n        }\n\n        public abstract void VarUInt32RoundTrip();\n        public abstract void VarUInt64RoundTrip();\n        public abstract void Int64RoundTrip();\n        public abstract void Int32RoundTrip();\n        public abstract void UInt64RoundTrip();\n        public abstract void UInt32RoundTrip();\n        protected abstract void ByteRoundTrip();\n\n        protected void VarUInt32RoundTripTest()\n        {\n            static uint Read(ref Reader<TInput> reader) => reader.ReadVarUInt32();\n            static void Write(ref Writer<TOutput> writer, uint expected) => writer.WriteVarUInt32(expected);\n\n            Gen.UInt.Sample(CreateTestPredicate(Write, Read));\n        }\n\n        protected void VarUInt64RoundTripTest()\n        {\n            static ulong Read(ref Reader<TInput> reader) => reader.ReadVarUInt64();\n            static void Write(ref Writer<TOutput> writer, ulong expected) => writer.WriteVarUInt64(expected);\n\n            Gen.ULong.Sample(CreateTestPredicate(Write, Read));\n        }\n\n        protected void Int64RoundTripTest()\n        {\n            static long Read(ref Reader<TInput> reader) => reader.ReadInt64();\n            static void Write(ref Writer<TOutput> writer, long expected) => writer.WriteInt64(expected);\n\n            Gen.Long.Sample(CreateTestPredicate(Write, Read));\n\n        }\n\n        protected void Int32RoundTripTest()\n        {\n            static int Read(ref Reader<TInput> reader) => reader.ReadInt32();\n            static void Write(ref Writer<TOutput> writer, int expected) => writer.WriteInt32(expected);\n\n            Gen.Int.Sample(CreateTestPredicate(Write, Read));\n        }\n\n        protected void UInt64RoundTripTest()\n        {\n            static ulong Read(ref Reader<TInput> reader) => reader.ReadUInt64();\n            static void Write(ref Writer<TOutput> writer, ulong expected) => writer.WriteUInt64(expected);\n\n            Gen.ULong.Sample(CreateTestPredicate(Write, Read));\n        }\n\n        protected void UInt32RoundTripTest()\n        {\n            static uint Read(ref Reader<TInput> reader) => reader.ReadUInt32();\n            static void Write(ref Writer<TOutput> writer, uint expected) => writer.WriteUInt32(expected);\n\n            Gen.UInt.Sample(CreateTestPredicate(Write, Read));\n        }\n\n        protected void ByteRoundTripTest()\n        {\n            static byte Read(ref Reader<TInput> reader) => reader.ReadByte();\n            static void Write(ref Writer<TOutput> writer, byte expected) => writer.WriteByte(expected);\n\n            Gen.Byte.Sample(CreateTestPredicate(Write, Read));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/RecordSerializationTests.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests;\n\n/// <summary>\n/// Tests for Orleans' support of C# record types.\n/// \n/// Records are first-class citizens in Orleans serialization, with full support for:\n/// - Primary constructor parameters\n/// - Init-only properties\n/// - Record inheritance hierarchies\n/// - Abstract record base types\n/// - Complex record structures with multiple inheritance levels\n/// \n/// Orleans handles records efficiently by:\n/// - Generating optimized serializers that understand record semantics\n/// - Preserving value equality semantics\n/// - Supporting both positional and nominal record syntax\n/// - Handling record structs (value type records)\n/// \n/// This support is crucial for modern C# applications that leverage records for:\n/// - Immutable data models\n/// - Domain-driven design with value objects\n/// - Functional programming patterns\n/// - Clean API contracts\n/// </summary>\npublic class RecordSerializationTests\n{\n    private readonly ServiceProvider _services;\n    private readonly Serializer _serializer;\n\n    public RecordSerializationTests()\n    {\n        _services = new ServiceCollection()\n            .AddSerializer()\n            .BuildServiceProvider();\n        _serializer = _services.GetRequiredService<Serializer>();\n    }\n\n    [Fact]\n    public void CanSerializeEmptyAbstractRecord()\n    {\n        var serializer = _services.GetRequiredService<Serializer<DerivedFromEmptyAbstractRecord>>();\n\n        var key = new DerivedFromEmptyAbstractRecord(\"Sample Foo\");\n        var bytes = serializer.SerializeToArray(key);\n        var newKey = serializer.Deserialize(bytes);\n\n        Assert.Equal(key, newKey);\n    }\n\n    [Fact]\n    public void CanSerializePopulatedAbstractRecord()\n    {\n        var serializer = _services.GetRequiredService<Serializer<DerivedFromNonEmptyAbstractRecord>>();\n\n        var key = new DerivedFromNonEmptyAbstractRecord(\"Sample Foo\");\n        var bytes = serializer.SerializeToArray(key);\n        var newKey = serializer.Deserialize(bytes);\n\n        Assert.Equal(key, newKey);\n    }\n\n    [Fact]\n    public void CanSerializeRecordsWithEmptyHierarchyLayers()\n    {\n        var serializer = _services.GetRequiredService<Serializer<RecordHierarchyDerived>>();\n\n        var expected = new RecordHierarchyDerived(Message: \"test\");\n        var bytes = serializer.SerializeToArray(expected);\n        var result = serializer.Deserialize(bytes);\n\n        Assert.Equal(expected, result);\n    }\n\n    [Fact]\n    public void CanSerializeRecordsInList()\n    {\n        var serializer = _services.GetRequiredService<Serializer>();\n        var expected = new List<DerivedFromNonEmptyAbstractRecord>\n        {\n            new DerivedFromNonEmptyAbstractRecord(\"foo\") { Bar = \"bar\" },\n            new DerivedFromNonEmptyAbstractRecord(\"foo2\") { Bar = \"bar2\" },\n        };\n        var bytes = serializer.SerializeToArray(expected);\n        var result = serializer.Deserialize<List<DerivedFromNonEmptyAbstractRecord>>(bytes);\n        Assert.Equal(expected.Count, result.Count);\n        Assert.Equal(expected[0], result[0]);\n        Assert.Equal(expected[1], result[1]);\n    }\n\n        [Fact]\n        public void Can_Roundtrip_WithListOfObject_Fruit()\n        {\n            var original = new FooWithListOfObject\n            {\n                Items = new List<object> { new FruitRecord(\"Banana\"), new FruitRecord(\"Mango\") },\n                Bar = new FooRecord(Guid.NewGuid())\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooWithListOfObject>(bytes);\n\n            Assert.NotNull(deserialized.Bar);\n            Assert.Equal(original.Bar, deserialized.Bar);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_With_Them_Apples()\n        {\n            var original = new TwoObjects\n            {\n                One = new AppleRecord(\"Golden Delicious\"),\n                Two = new AppleRecord(\"Granny Smith\")\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<TwoObjects>(bytes);\n\n            Assert.NotNull(deserialized.One);\n            Assert.NotNull(deserialized.Two);\n            Assert.Equal(original.One, deserialized.One);\n            Assert.Equal(original.Two, deserialized.Two);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_WithListOfObject_Apple()\n        {\n            var original = new FooWithListOfObject\n            {\n                Items = new List<object> { new AppleRecord(\"Golden Delicious\"), new AppleRecord(\"Granny Smith\") },\n                Bar = new FooRecord(Guid.NewGuid())\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooWithListOfObject>(bytes);\n\n            Assert.NotNull(deserialized.Items);\n            Assert.Equal(original.Items.Count, deserialized.Items.Count);\n            Assert.Equal(original.Items[0], deserialized.Items[0]);\n            Assert.Equal(original.Items[1], deserialized.Items[1]);\n\n            Assert.NotNull(deserialized.Bar);\n            Assert.Equal(original.Bar, deserialized.Bar);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_WithListOfFruit_Fruit()\n        {\n            var original = new FooWithListOfFruit()\n            {\n                Items = new List<FruitRecord> { new FruitRecord(\"Banana\"), new FruitRecord(\"Mango\") },\n                Bar = new FooRecord(Guid.NewGuid())\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooWithListOfFruit>(bytes);\n\n            Assert.NotNull(deserialized.Bar);\n            Assert.Equal(original.Bar, deserialized.Bar);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_WithListOfFruit_Apple()\n        {\n            var original = new FooWithListOfFruit()\n            {\n                Items = new List<FruitRecord> { new AppleRecord(\"Golden Delicious\"), new AppleRecord(\"Granny Smith\") },\n                Bar = new FooRecord(Guid.NewGuid())\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooWithListOfFruit>(bytes);\n\n            Assert.NotNull(deserialized.Bar);\n            Assert.Equal(original.Bar, deserialized.Bar);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_WithListOfApple_Apple()\n        {\n            var original = new FooWithListOfApple()\n            {\n                Items = new List<AppleRecord> { new AppleRecord(\"Golden Delicious\"), new AppleRecord(\"Granny Smith\") },\n                Bar = new FooRecord(Guid.NewGuid())\n            };\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooWithListOfApple>(bytes);\n\n            Assert.NotNull(deserialized.Bar);\n            Assert.Equal(original.Bar, deserialized.Bar);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_Fruit_Apple()\n        {\n            FruitRecord original = new AppleRecord(\"Golden Delicious\");\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FruitRecord>(bytes);\n\n            Assert.NotNull(deserialized);\n            Assert.Equal(original, deserialized);\n        }\n\n        [Fact]\n        public void Can_Roundtrip_Foo()\n        {\n            var original = new FooRecord(Guid.NewGuid());\n\n            var bytes = _serializer.SerializeToArray(original);\n\n            var deserialized = _serializer.Deserialize<FooRecord>(bytes);\n\n            Assert.NotNull(deserialized);\n            Assert.Equal(original, deserialized);\n        }\n\n    // TODO: This type should cause a build error because \"Bar\" is an init-only non-auto property but has an [Id(...)] attribute.\n    // It is suited for an diagnostic analyzer test, but the current implementation\n    // of the source generator does not support execution as an analyzer.\n    /*\n    [GenerateSerializer]\n    public record RecordWithInitOnlyManualProperty\n    {\n        private string _bar;\n\n        [Id(0)]\n        public string Bar\n        {\n            get => _bar;\n            init\n            {\n                _bar = value;\n                OnSetBar(_bar);\n            }\n        }\n\n        public RecordWithInitOnlyManualProperty(string bar)\n        {\n            _bar = bar;\n            OnSetBar(_bar);\n        }\n\n        private void OnSetBar(string bar)\n        {\n            // Ignore\n            _ = bar;\n        }\n    }\n    */\n}\n\n[GenerateSerializer]\npublic abstract record EmptyAbstractRecord\n{\n}\n\n[GenerateSerializer]\npublic record DerivedFromEmptyAbstractRecord : EmptyAbstractRecord\n{\n    [Id(0)]\n    public string Foo { get; init; }\n\n    public DerivedFromEmptyAbstractRecord(string foo)\n    {\n        Foo = foo;\n    }\n}\n\n[GenerateSerializer]\npublic abstract record NonEmptyAbstractRecord\n{\n    [Id(0)]\n    public string Bar { get; init; }\n\n    protected NonEmptyAbstractRecord()\n    {\n        Bar = \"bar\";\n    }\n}\n\n[GenerateSerializer]\npublic record DerivedFromNonEmptyAbstractRecord : NonEmptyAbstractRecord\n{\n    [Id(0)]\n    public string Foo { get; init; }\n\n    public DerivedFromNonEmptyAbstractRecord(string foo) : base()\n    {\n        Foo = foo;\n    }\n}\n\n[GenerateSerializer]\npublic record RecordHierarchyDerived([property: Id(1)] string Message) : RecordHierarchyMiddle\n{\n    public override string Type => \"Foo\";\n}\n\n[GenerateSerializer]\npublic abstract record RecordHierarchyMiddle : RecordHierarchyBase;\n\n[GenerateSerializer]\npublic abstract record RecordHierarchyBase\n{\n    public abstract string Type { get; }\n}\n\n[GenerateSerializer]\npublic class FooWithListOfObject\n{\n    [Id(1)]\n    public List<object>? Items { get; set; }\n\n    [Id(2)]\n    public FooRecord? Bar { get; set; }\n}\n\n[GenerateSerializer]\npublic class TwoObjects\n{\n    [Id(0)]\n    public object? One { get; set; }\n\n    [Id(1)]\n    public object? Two { get; set; }\n}\n\n[GenerateSerializer]\npublic class FooWithListOfFruit\n{\n    [Id(1)]\n    public List<FruitRecord>? Items { get; set; }\n\n    [Id(2)]\n    public FooRecord? Bar { get; set; }\n}\n\n[GenerateSerializer]\npublic class FooWithListOfApple\n{\n    [Id(1)]\n    public List<AppleRecord>? Items { get; set; }\n\n    [Id(2)]\n    public FooRecord? Bar { get; set; }\n}\n\n[GenerateSerializer]\npublic record FruitRecord(string Name);\n\n[GenerateSerializer]\npublic record AppleRecord(string Name) : FruitRecord(Name);\n\n[GenerateSerializer]\npublic record FooRecord([property: Id(0)] Guid Id);"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/Request.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Threading.Tasks;\n\nnamespace Orleans.Serialization.Invocation\n{\n    [GenerateSerializer]\n    public abstract class UnitTestRequestBase : IInvokable\n    {\n        public virtual int GetArgumentCount() => 0;\n        public abstract ValueTask<Response> Invoke();\n        public abstract object GetTarget();\n        public abstract void SetTarget(ITargetHolder holder);\n        public virtual object GetArgument(int index) => throw new ArgumentOutOfRangeException(message: \"The request has zero arguments\", null);\n        public virtual void SetArgument(int index, object value) => throw new ArgumentOutOfRangeException(message: \"The request has zero arguments\", null);\n        public abstract void Dispose();\n        public abstract string GetMethodName();\n        public abstract string GetInterfaceName();\n\n        public abstract string GetActivityName();\n        public abstract Type GetInterfaceType();\n\n        public abstract MethodInfo GetMethod();\n    }\n\n    [GenerateSerializer]\n    public abstract class UnitTestRequest : UnitTestRequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.FromResult<object>(null));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.FromResult<object>(null);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract ValueTask InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public abstract class UnitTestRequest<TResult> : UnitTestRequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.Result));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(ValueTask<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract ValueTask<TResult> InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public abstract class UnitTestTaskRequest<TResult> : UnitTestRequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                var status = resultTask.Status;\n                if (resultTask.IsCompleted)\n                {\n                    return new ValueTask<Response>(Response.FromResult(resultTask.GetAwaiter().GetResult()));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task<TResult> resultTask)\n        {\n            try\n            {\n                var result = await resultTask;\n                return Response.FromResult(result);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract Task<TResult> InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public abstract class UnitTestTaskRequest : UnitTestRequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                var resultTask = InvokeInner();\n                var status = resultTask.Status;\n                if (resultTask.IsCompleted)\n                {\n                    resultTask.GetAwaiter().GetResult();\n                    return new ValueTask<Response>(Response.FromResult<object>(null));\n                }\n\n                return CompleteInvokeAsync(resultTask);\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        private static async ValueTask<Response> CompleteInvokeAsync(Task resultTask)\n        {\n            try\n            {\n                await resultTask;\n                return Response.FromResult<object>(null);\n            }\n            catch (Exception exception)\n            {\n                return Response.FromException(exception);\n            }\n        }\n\n        // Generated\n        protected abstract Task InvokeInner();\n    }\n\n    [GenerateSerializer]\n    public abstract class UnitTestVoidRequest : UnitTestRequestBase\n    {\n        public sealed override ValueTask<Response> Invoke()\n        {\n            try\n            {\n                InvokeInner();\n                return new ValueTask<Response>(Response.FromResult<object>(null));\n            }\n            catch (Exception exception)\n            {\n                return new ValueTask<Response>(Response.FromException(exception));\n            }\n        }\n\n        // Generated\n        protected abstract void InvokeInner();\n    }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/TypeEncodingTests.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Orleans.Serialization.Configuration;\nusing Orleans.Serialization.Invocation;\nusing Orleans.Serialization.Session;\nusing Orleans.Serialization.Utilities;\nusing Xunit;\n\nnamespace Orleans.Serialization.UnitTests\n{\n    /// <summary>\n    /// Tests for Orleans' type encoding and type manifest system.\n    /// \n    /// Orleans uses an efficient type encoding system that:\n    /// - Maps types to compact identifiers for wire efficiency\n    /// - Supports type aliases for human-readable debugging\n    /// - Handles generic types with proper parameter encoding\n    /// - Manages compound types (generics with multiple parameters)\n    /// \n    /// Key features tested:\n    /// - Type alias resolution and encoding\n    /// - Generic type parameter serialization\n    /// - Interface proxy type generation and naming\n    /// - Type manifest configuration and well-known types\n    /// \n    /// The type encoding system is fundamental to Orleans' ability to:\n    /// - Minimize bandwidth usage through compact type representations\n    /// - Support debugging through readable type aliases\n    /// - Enable cross-version compatibility through stable type identifiers\n    /// - Provide efficient polymorphic serialization\n    /// </summary>\n    public class TypeEncodingTests\n    {\n        private readonly IServiceProvider _serviceProvider;\n        private readonly SerializerSessionPool _sessionPool;\n        private readonly Serializer _serializer;\n\n        public TypeEncodingTests()\n        {\n            var services = new ServiceCollection();\n            _ = services.AddSerializer();\n            _serviceProvider = services.BuildServiceProvider();\n            _sessionPool = _serviceProvider.GetRequiredService<SerializerSessionPool>();\n            _serializer = _serviceProvider.GetRequiredService<Serializer>();\n        }\n\n        [Fact]\n        public void CompoundTypeAliasesAreEncodedAsExpected()\n        {\n            var original = new MyCompoundTypeAliasClass\n            {\n                Name = \"TwinkleToes\",\n                Value = 112\n            };\n            var expectedString = \"(\\\"xx_test_xx\\\",[_custom_type_alias_],[int],\\\"1\\\")\";\n            var expectedEncoding = Encoding.UTF8.GetBytes(expectedString).AsSpan();\n            var (payload, bitStream) = SerializePayload(original);\n            Assert.True(payload.AsSpan().IndexOf(expectedEncoding) >= 0, $\"Expected to find string \\\"{expectedString}\\\" in bitstream (formatted: {bitStream})\");\n        }\n\n        [Fact]\n        public void GeneratedProxyClassesHaveExpectedCompoundTypeNames()\n        {\n            var configuration = _serviceProvider.GetRequiredService<IOptions<TypeManifestOptions>>().Value;\n            var generatedProxy = configuration.InterfaceProxies.Single(proxy => typeof(IProxyAliasTestGrain).IsAssignableFrom(proxy));\n            var instance = ActivatorUtilities.CreateInstance(_serviceProvider, generatedProxy);\n            var instanceAsBase = Assert.IsAssignableFrom<MyInvokableProxyBase>(instance);\n            var instanceAsInterface = Assert.IsAssignableFrom<IProxyAliasTestGrain>(instance);\n\n            var calls = new Queue<IInvokable>();\n            instanceAsBase.OnInvoke = body => calls.Enqueue(body);\n\n            {\n                var res = instanceAsInterface.Method();\n                Assert.True(res.IsCompletedSuccessfully);\n                var method = calls.Dequeue();\n                var (payload, bitStream) = SerializePayload(method);\n                var expectedString = \"(\\\"inv\\\",[_my_proxy_base_],[_proxy_alias_test_],\\\"125\\\")\";\n                var expectedEncoding = Encoding.UTF8.GetBytes(expectedString).AsSpan();\n                Assert.True(payload.AsSpan().IndexOf(expectedEncoding) >= 0, $\"Expected to find string \\\"{expectedString}\\\" in bitstream (formatted: {bitStream})\");\n            }\n\n            {\n                var res = instanceAsInterface.OtherMethod();\n                Assert.True(res.IsCompletedSuccessfully);\n                var method = calls.Dequeue();\n                var (payload, bitStream) = SerializePayload(method);\n                var expectedString = \"(\\\"inv\\\",[_my_proxy_base_],[_proxy_alias_test_],\\\"MyOtherMethod\\\")\";\n                var expectedEncoding = Encoding.UTF8.GetBytes(expectedString).AsSpan();\n                Assert.True(payload.AsSpan().IndexOf(expectedEncoding) >= 0, $\"Expected to find string \\\"{expectedString}\\\" in bitstream (formatted: {bitStream})\");\n            }\n        }\n\n        [Fact]\n        public void GeneratedProxyClassesHaveExpectedCompoundTypeNames_Generic()\n        {\n            var configuration = _serviceProvider.GetRequiredService<IOptions<TypeManifestOptions>>().Value;\n            var generatedProxy = configuration.InterfaceProxies.Single(proxy => proxy.GetInterfaces().Any(iface => iface.IsGenericType && typeof(IGenericProxyAliasTestGrain<,,>).IsAssignableFrom(iface.GetGenericTypeDefinition())));\n            var instance = ActivatorUtilities.CreateInstance(_serviceProvider, generatedProxy.MakeGenericType(typeof(int), typeof(string), typeof(double)));\n            var instanceAsBase = Assert.IsAssignableFrom<MyInvokableProxyBase>(instance);\n            var instanceAsInterface = Assert.IsAssignableFrom<IGenericProxyAliasTestGrain<int, string, double>>(instance);\n\n            var calls = new Queue<IInvokable>();\n            instanceAsBase.OnInvoke = body => calls.Enqueue(body);\n\n            var res = instanceAsInterface.Method<int, MyTypeAliasClass, int>();\n            Assert.True(res.IsCompletedSuccessfully);\n            var method = calls.Dequeue();\n            var (payload, bitStream) = SerializePayload(method);\n            var expectedString = \"(\\\"inv\\\",[_my_proxy_base_],[test.IGenericProxyAliasTestGrain`3],\\\"777\\\")`6[[int],[string],[double],[int],[_custom_type_alias_],[int]]\";\n            var expectedEncoding = Encoding.UTF8.GetBytes(expectedString).AsSpan();\n            Assert.True(payload.AsSpan().IndexOf(expectedEncoding) >= 0, $\"Expected to find string \\\"{expectedString}\\\" in bitstream (formatted: {bitStream})\");\n        }\n\n        private (byte[] Serialized, string FormattedBitStream) SerializePayload(object original)\n        {\n            var payload = _serializer.SerializeToArray<object>(original);\n            using var session = _sessionPool.GetSession();\n            var bitStream = BitStreamFormatter.Format(payload, session);\n            return (payload, bitStream);\n        }\n\n        [Fact]\n        public void AliasAttributeIsApplied()\n        {\n            var original = new Person(2, \"harry\");\n\n            var bytes = _serializer.SerializeToArray(original.GetType());\n            var resultType = _serializer.Deserialize<Type>(bytes);\n\n            var alias = original.GetType().GetCustomAttributes(false).OfType<AliasAttribute>().SingleOrDefault();\n            Assert.NotNull(alias);\n            Assert.NotNull(alias.Alias);\n            Assert.Equal(typeof(Person), resultType);\n            var expectedBytes = Encoding.UTF8.GetBytes(alias.Alias);\n            Assert.True(bytes.AsSpan().IndexOf(expectedBytes) >= 0);\n        }\n    }\n\n    [Alias(\"_custom_type_alias_\")]\n    public class MyTypeAliasClass\n    {\n    }\n\n    [GenerateSerializer]\n    public class MyCompoundTypeAliasBaseClass\n    {\n        [Id(0)]\n        public int BaseValue { get; set; }\n    }\n\n    [GenerateSerializer]\n    [CompoundTypeAlias(\"xx_test_xx\", typeof(MyTypeAliasClass), typeof(int), \"1\")]\n    public class MyCompoundTypeAliasClass : MyCompoundTypeAliasBaseClass\n    {\n        [Id(0)]\n        public string? Name { get; set; }\n\n        [Id(1)]\n        public int Value { get; set; }\n    }\n}"
  },
  {
    "path": "test/Orleans.Serialization.UnitTests/protobuf-model.proto",
    "content": "syntax = \"proto3\";\noption csharp_namespace = \"Orleans.Serialization.UnitTests\";\n\nmessage MyProtobufClass {\n    int32 int_property = 1;\n    string string_property = 2;\n    SubClass sub_class = 3;\n\n    message SubClass {\n        bytes id = 1;\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/Orleans.Streaming.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>UnitTests</RootNamespace>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Orleans.Runtime.Internal.Tests\\Orleans.Runtime.Internal.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.NATS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/OrleansRuntime/Streams/CachedMessageBlockTests.cs",
    "content": "using Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for cached message block functionality in streaming infrastructure.\n    /// </summary>\n    public class CachedMessageBlockTests\n    {\n        private const int TestBlockSize = 100;\n        private readonly Guid StreamGuid = Guid.NewGuid();\n\n        private class TestQueueMessage\n        {\n            public Guid StreamGuid { get; set; }\n            public EventSequenceTokenV2 SequenceToken { get; set; }\n        }\n\n        [GenerateSerializer]\n        public class TestBatchContainer : IBatchContainer\n        {\n            [Id(0)]\n            public StreamId StreamId { get; set; }\n\n            [Id(1)]\n            public StreamSequenceToken SequenceToken { get; set; }\n\n            public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n            {\n                throw new NotImplementedException();\n            }\n\n            public bool ImportRequestContext()\n            {\n                throw new NotImplementedException();\n            }\n        }\n\n        private class TestCacheDataAdapter : ICacheDataAdapter\n        {\n            public IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage)\n            {\n                return new TestBatchContainer()\n                {\n                    StreamId = cachedMessage.StreamId,\n                    SequenceToken = new EventSequenceToken(cachedMessage.SequenceNumber, cachedMessage.EventIndex)\n                };\n            }\n\n            public StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n            {\n                return new EventSequenceTokenV2(cachedMessage.SequenceNumber, cachedMessage.EventIndex);\n            }\n        }\n\n        private StreamPosition GetStreamPosition(TestQueueMessage queueMessage)\n        {\n            var streamId = StreamId.Create(null, queueMessage.StreamGuid);\n            StreamSequenceToken sequenceToken = queueMessage.SequenceToken;\n            return new StreamPosition(streamId, sequenceToken);\n        }\n\n        private CachedMessage QueueMessageToCachedMessage(TestQueueMessage queueMessage, DateTime dequeueTimeUtc)\n        {\n            StreamPosition streamPosition = GetStreamPosition(queueMessage);\n            return new CachedMessage\n            {\n                StreamId = streamPosition.StreamId,\n                SequenceNumber = queueMessage.SequenceToken.SequenceNumber,\n                EventIndex = queueMessage.SequenceToken.EventIndex,\n            };\n        }\n\n        private class MyTestPooled : IObjectPool<CachedMessageBlock>\n        {\n            public CachedMessageBlock Allocate()\n            {\n                return new CachedMessageBlock(TestBlockSize){Pool = this};\n            }\n\n            public void Free(CachedMessageBlock resource)\n            {\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void Add1Remove1Test()\n        {\n            IObjectPool<CachedMessageBlock> pool = new MyTestPooled();\n            ICacheDataAdapter dataAdapter = new TestCacheDataAdapter();\n            CachedMessageBlock block = pool.Allocate();\n\n            AddAndCheck(block, dataAdapter, 0, -1);\n            RemoveAndCheck(block, 0, 0);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void Add2Remove1UntilFull()\n        {\n            IObjectPool<CachedMessageBlock> pool = new MyTestPooled();\n            ICacheDataAdapter dataAdapter = new TestCacheDataAdapter();\n            CachedMessageBlock block = pool.Allocate();\n            int first = 0;\n            int last = -1;\n\n            while (block.HasCapacity)\n            {\n                // add message to end of block\n                AddAndCheck(block, dataAdapter, first, last);\n                last++;\n                if (!block.HasCapacity)\n                {\n                    continue;\n                }\n                // add message to end of block\n                AddAndCheck(block, dataAdapter, first, last);\n                last++;\n                // removed message from start of block\n                RemoveAndCheck(block, first, last);\n                first++;\n            }\n            Assert.Equal(TestBlockSize / 2, block.OldestMessageIndex);\n            Assert.Equal(TestBlockSize - 1, block.NewestMessageIndex);\n            Assert.False(block.IsEmpty);\n            Assert.False(block.HasCapacity);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void FirstMessageWithSequenceNumberTest()\n        {\n            IObjectPool<CachedMessageBlock> pool = new MyTestPooled();\n            ICacheDataAdapter dataAdapter = new TestCacheDataAdapter();\n            CachedMessageBlock block = pool.Allocate();\n            int last = -1;\n            int sequenceNumber = 0;\n\n            while (block.HasCapacity)\n            {\n                // add message to end of block\n                AddAndCheck(block, dataAdapter, 0, last, sequenceNumber);\n                last++;\n                sequenceNumber += 2;\n            }\n            Assert.Equal(block.OldestMessageIndex, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(0)));\n            Assert.Equal(block.OldestMessageIndex, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(1)));\n            Assert.Equal(block.NewestMessageIndex, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(sequenceNumber - 2)));\n            Assert.Equal(block.NewestMessageIndex - 1, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(sequenceNumber - 3)));\n            Assert.Equal(50, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(sequenceNumber / 2)));\n            Assert.Equal(50, block.GetIndexOfFirstMessageLessThanOrEqualTo(new EventSequenceTokenV2(sequenceNumber / 2 + 1)));\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void NextInStreamTest()\n        {\n            IObjectPool<CachedMessageBlock> pool = new MyTestPooled();\n            ICacheDataAdapter dataAdapter = new TestCacheDataAdapter();\n            CachedMessageBlock block = pool.Allocate();\n            int last = 0;\n            int sequenceNumber = 0;\n            // define 2 streams\n            var streams = new[] { new StreamIdentity(Guid.NewGuid(), null), new StreamIdentity(Guid.NewGuid(), null) };\n\n            // add both streams interleaved, until lock is full\n            while (block.HasCapacity)\n            {\n                var stream = streams[last%2];\n                var message = new TestQueueMessage\n                {\n                    StreamGuid = stream.Guid,\n                    SequenceToken = new EventSequenceTokenV2(sequenceNumber)\n                };\n\n                // add message to end of block\n                AddAndCheck(block, dataAdapter, message, 0, last - 1);\n                last++;\n                sequenceNumber += 2;\n            }\n\n            // get index of first stream\n            int streamIndex;\n            Assert.True(block.TryFindFirstMessage(StreamId.Create(streams[0]), dataAdapter, out streamIndex));\n            Assert.Equal(0, streamIndex);\n            Assert.Equal(0, block.GetSequenceToken(streamIndex, dataAdapter).SequenceNumber);\n\n            // find stream1 messages\n            int iteration = 1;\n            while (block.TryFindNextMessage(streamIndex + 1, StreamId.Create(streams[0]), dataAdapter, out streamIndex))\n            {\n                Assert.Equal(iteration * 2, streamIndex);\n                Assert.Equal(iteration * 4, block.GetSequenceToken(streamIndex, dataAdapter).SequenceNumber);\n                iteration++;\n            }\n\n            Assert.Equal(TestBlockSize / 2, iteration);\n\n            // get index of first stream\n            Assert.True(block.TryFindFirstMessage(StreamId.Create(streams[1]), dataAdapter, out streamIndex));\n            Assert.Equal(1, streamIndex);\n            Assert.Equal(2, block.GetSequenceToken(streamIndex, dataAdapter).SequenceNumber);\n\n            // find stream1 messages\n            iteration = 1;\n            while (block.TryFindNextMessage(streamIndex + 1, StreamId.Create(streams[1]), dataAdapter, out streamIndex))\n            {\n                Assert.Equal(iteration * 2 + 1, streamIndex);\n                Assert.Equal(iteration * 4 + 2, block.GetSequenceToken(streamIndex, dataAdapter).SequenceNumber);\n                iteration++;\n            }\n\n            Assert.Equal(TestBlockSize / 2, iteration);\n        }\n\n        private void AddAndCheck(CachedMessageBlock block, ICacheDataAdapter dataAdapter, int first, int last, int sequenceNumber = 1)\n        {\n            var message = new TestQueueMessage\n            {\n                StreamGuid = StreamGuid,\n                SequenceToken = new EventSequenceTokenV2(sequenceNumber)\n            };\n            AddAndCheck(block, dataAdapter, message, first, last);\n        }\n\n        private void AddAndCheck(CachedMessageBlock block, ICacheDataAdapter dataAdapter, TestQueueMessage message, int first, int last)\n        {\n            Assert.Equal(first, block.OldestMessageIndex);\n            Assert.Equal(last, block.NewestMessageIndex);\n            Assert.True(block.HasCapacity);\n\n            block.Add(QueueMessageToCachedMessage(message, DateTime.UtcNow));\n            last++;\n\n            Assert.Equal(first > last, block.IsEmpty);\n            Assert.Equal(last + 1 < TestBlockSize, block.HasCapacity);\n            Assert.Equal(first, block.OldestMessageIndex);\n            Assert.Equal(last, block.NewestMessageIndex);\n\n            Assert.True(block.GetSequenceToken(last, dataAdapter).Equals(message.SequenceToken));\n        }\n\n        private void RemoveAndCheck(CachedMessageBlock block, int first, int last)\n        {\n            Assert.Equal(first, block.OldestMessageIndex);\n            Assert.Equal(last, block.NewestMessageIndex);\n            Assert.False(block.IsEmpty);\n            Assert.Equal(last + 1 < TestBlockSize, block.HasCapacity);\n\n            Assert.True(block.Remove());\n\n            first++;\n            Assert.Equal(first > last, block.IsEmpty);\n            Assert.Equal(last + 1 < TestBlockSize, block.HasCapacity);\n            Assert.Equal(first, block.OldestMessageIndex);\n            Assert.Equal(last, block.NewestMessageIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/OrleansRuntime/Streams/FixedSizeBufferTests.cs",
    "content": "﻿using Orleans.Providers.Streams.Common;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for fixed size buffer pooling and segment allocation.\n    /// </summary>\n    public class FixedSizeBufferTests\n    {\n        private const int TestBlockSize = 100;\n\n        private class MyTestPooled : IObjectPool<FixedSizeBuffer>\n        {\n            public int Allocated { get; private set; }\n            public int Freed { get; private set; }\n\n            public FixedSizeBuffer Allocate()\n            {\n                Allocated++;\n                return new FixedSizeBuffer(TestBlockSize) {Pool = this};\n            }\n\n            public void Free(FixedSizeBuffer resource)\n            {\n                Freed++;\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void EmptyBlockGetSegmentTooLargeBvt()\n        {\n            IObjectPool<FixedSizeBuffer> pool = new MyTestPooled();\n            FixedSizeBuffer buffer = pool.Allocate();\n            ArraySegment<byte> segment;\n            Assert.False(buffer.TryGetSegment(TestBlockSize + 1, out segment), \"Should not be able to get segement that is bigger than block.\");\n            Assert.Null(segment.Array);\n            Assert.Equal(0, segment.Offset);\n#pragma warning disable xUnit2013 // Do not use equality check to check for collection size.\n            Assert.Equal(0, segment.Count);\n#pragma warning restore xUnit2013 // Do not use equality check to check for collection size.\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void EmptyBlockTryGetMaxSegmentBvt()\n        {\n            IObjectPool<FixedSizeBuffer> pool = new MyTestPooled();\n            FixedSizeBuffer buffer = pool.Allocate();\n            ArraySegment<byte> segment;\n            Assert.True(buffer.TryGetSegment(TestBlockSize, out segment), \"Should be able to get segement of block size.\");\n            Assert.NotNull(segment.Array);\n            Assert.Equal(0, segment.Offset);\n            Assert.Equal(TestBlockSize, segment.Count);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void FillBlockTestBvt()\n        {\n            IObjectPool<FixedSizeBuffer> pool = new MyTestPooled();\n            FixedSizeBuffer buffer = pool.Allocate();\n            ArraySegment<byte> segment;\n            for (int i = 0; i < TestBlockSize; i++)\n            {\n                Assert.True(buffer.TryGetSegment(1, out segment), string.Format(\"Should be able to get {0}th segement of size 1.\", i + 1));\n                Assert.Equal(i, segment.Offset);\n                Assert.Single(segment);\n            }\n            Assert.False(buffer.TryGetSegment(1, out segment), string.Format(\"Should be able to get {0}th segement of size 1.\", TestBlockSize + 1));\n            Assert.Null(segment.Array);\n            Assert.Equal(0, segment.Offset);\n#pragma warning disable xUnit2013 // Do not use equality check to check for collection size.\n            Assert.Equal(0, segment.Count);\n#pragma warning restore xUnit2013 // Do not use equality check to check for collection size.\n        }\n\n        private void MyTestPurge(IDisposable resource, FixedSizeBuffer actualBuffer)\n        {\n            Assert.Equal<object>(resource, actualBuffer);\n            resource.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/OrleansRuntime/Streams/ObjectPoolTests.cs",
    "content": "﻿using Orleans.Providers.Streams.Common;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    /// <summary>\n    /// Tests for object pool allocation, recycling, and resource management.\n    /// </summary>\n    public class ObjectPoolTests\n    {\n        private class Accumulator\n        {\n            public int CurrentlyAllocated { get; set; }\n            public int MaxAllocated { get; set; }\n\n        }\n        private class TestPooledResource : PooledResource<TestPooledResource>\n        {\n            private readonly Accumulator accumulator;\n\n            public int AllocationCount { get; private set; }\n\n            public TestPooledResource(Accumulator accumulator)\n            {\n                this.accumulator = accumulator;\n                this.accumulator.CurrentlyAllocated++;\n                this.accumulator.MaxAllocated = Math.Max(this.accumulator.MaxAllocated, this.accumulator.CurrentlyAllocated);\n            }\n\n            public override void OnResetState()\n            {\n                accumulator.CurrentlyAllocated--;\n                AllocationCount++;\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void Alloc1Free1Test()\n        {\n            var accumulator = new Accumulator();\n            IObjectPool<TestPooledResource> pool = new ObjectPool<TestPooledResource>(() => new TestPooledResource(accumulator));\n            // Allocate and free 10 items\n            for (int i = 0; i < 10; i++)\n            {\n                TestPooledResource resource = pool.Allocate();\n                resource.Dispose();\n            }\n            // only 1 at a time was ever allocated, so max allocated should be 1\n            Assert.Equal(1, accumulator.MaxAllocated);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void Alloc10Free1Test()\n        {\n            var accumulator = new Accumulator();\n            IObjectPool<TestPooledResource> pool = new ObjectPool<TestPooledResource>(() => new TestPooledResource(accumulator));\n\n            // Allocate 10 items\n            var resources = Enumerable.Range(0, 10).Select(i => pool.Allocate()) .ToList();\n\n            // free 10\n            resources.ForEach(r => r.Dispose());\n\n            // pool was pre-populated with 10, so max allocated should be 10\n            Assert.Equal(10, accumulator.MaxAllocated);\n\n            // Allocate and free 10 items\n            for (int i = 0; i < 10; i++)\n            {\n                TestPooledResource resource = pool.Allocate();\n                resource.Dispose();\n            }\n\n            // only 1 at a time was ever allocated, but pool was pre-populated with 10, so max allocated should be 10\n            Assert.Equal(10, accumulator.MaxAllocated);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void ReuseResourceTest()\n        {\n            const int WorkngSet = 20;\n            var accumulator = new Accumulator();\n            IObjectPool<TestPooledResource> pool = new ObjectPool<TestPooledResource>(() => new TestPooledResource(accumulator));\n\n            for (int i = 0; i < 5; i++)\n            {\n                // Allocate WorkngSet items\n                var resources = Enumerable.Range(0, WorkngSet).Select(v => pool.Allocate()).ToList();\n\n                resources.Reverse(); // reversing alloca to maintain order when disposed\n\n                // free WorkngSet\n                resources.ForEach(r => r.Dispose());\n\n                // pool was pre-populated with WorkngSet, so max allocated should be 10\n                Assert.Equal(WorkngSet, accumulator.MaxAllocated);\n\n                // Allocate and free 5 items\n                for (int j = 0; j < 5; j++)\n                {\n                    TestPooledResource resource = pool.Allocate();\n                    int expectedAllocationCount = (i*(5 + 1)) // allocations accumulated in previous loops\n                                                  + (j + 1); // allocations accumulated in this loop\n                    Assert.Equal(expectedAllocationCount, resource.AllocationCount);\n                    resource.Dispose();\n                }\n\n                // only 1 at a time was ever allocated, but pool was pre-populated with WorkngSet, so max allocated should be 10\n                Assert.Equal(WorkngSet, accumulator.MaxAllocated);\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/OrleansRuntime/Streams/PooledQueueCacheTests.cs",
    "content": "using System.Globalization;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Xunit;\n\nnamespace UnitTests.OrleansRuntime.Streams\n{\n    public class PooledQueueCacheTests\n    {\n        private const int PooledBufferCount = 8;\n        private const int PooledBufferSize = 1 << 10; // 1K\n        private const int MessageSize = 1 << 7; // 128\n        private const int MessagesPerBuffer = 8;\n        private const string TestStreamNamespace = \"blarg\";\n        \n        private class TestQueueMessage\n        {\n            private static readonly byte[] FixedMessage = new byte[MessageSize];\n            public StreamId StreamId;\n            public long SequenceNumber;\n            public readonly byte[] Data = FixedMessage;\n            public DateTime EnqueueTimeUtc = DateTime.UtcNow;\n        }\n\n        [GenerateSerializer]\n        public class TestBatchContainer : IBatchContainer\n        {\n            [Id(0)]\n            public StreamId StreamId { get; set; }\n\n            [Id(1)]\n            public StreamSequenceToken SequenceToken { get; set; }\n\n            [Id(2)]\n            public byte[] Data { get; set; }\n\n            public IEnumerable<Tuple<T, StreamSequenceToken>> GetEvents<T>()\n            {\n                throw new NotImplementedException();\n            }\n\n            public bool ImportRequestContext()\n            {\n                throw new NotImplementedException();\n            }\n        }\n\n\n        private class TestCacheDataAdapter : ICacheDataAdapter\n        {\n            public IBatchContainer GetBatchContainer(ref CachedMessage cachedMessage)\n            {\n                //Deserialize payload\n                int readOffset = 0;\n                ArraySegment<byte> payload = SegmentBuilder.ReadNextBytes(cachedMessage.Segment, ref readOffset);\n\n                return new TestBatchContainer\n                {\n                    StreamId =  cachedMessage.StreamId,\n                    SequenceToken = GetSequenceToken(ref cachedMessage),\n                    Data = payload.ToArray()\n                };\n            }\n\n            public StreamSequenceToken GetSequenceToken(ref CachedMessage cachedMessage)\n            {\n                return new EventSequenceTokenV2(cachedMessage.SequenceNumber);\n            }\n\n        }\n\n        private class CachedMessageConverter\n        {\n            private readonly IObjectPool<FixedSizeBuffer> bufferPool;\n            private readonly IEvictionStrategy evictionStrategy;\n            private FixedSizeBuffer currentBuffer;\n\n\n            public CachedMessageConverter(IObjectPool<FixedSizeBuffer> bufferPool, IEvictionStrategy evictionStrategy)\n            {\n                this.bufferPool = bufferPool;\n                this.evictionStrategy = evictionStrategy;\n            }\n\n            public CachedMessage ToCachedMessage(TestQueueMessage queueMessage, DateTime dequeueTimeUtc)\n            {\n                StreamPosition streamPosition = GetStreamPosition(queueMessage);\n                return new CachedMessage\n                {\n                    StreamId = streamPosition.StreamId,\n                    SequenceNumber = queueMessage.SequenceNumber,\n                    EnqueueTimeUtc = queueMessage.EnqueueTimeUtc,\n                    DequeueTimeUtc = dequeueTimeUtc,\n                    Segment = SerializeMessageIntoPooledSegment(queueMessage),\n                };\n            }\n\n            private StreamPosition GetStreamPosition(TestQueueMessage queueMessage)\n            {\n                StreamSequenceToken sequenceToken = new EventSequenceTokenV2(queueMessage.SequenceNumber);\n                return new StreamPosition(queueMessage.StreamId, sequenceToken);\n            }\n\n            private ArraySegment<byte> SerializeMessageIntoPooledSegment(TestQueueMessage queueMessage)\n            {\n                // serialize payload\n                int size = SegmentBuilder.CalculateAppendSize(queueMessage.Data);\n\n                // get segment from current block\n                ArraySegment<byte> segment;\n                if (currentBuffer == null || !currentBuffer.TryGetSegment(size, out segment))\n                {\n                    // no block or block full, get new block and try again\n                    currentBuffer = bufferPool.Allocate();\n                    //call EvictionStrategy's OnBlockAllocated method\n                    this.evictionStrategy.OnBlockAllocated(currentBuffer);\n                    // if this fails with clean block, then requested size is too big\n                    if (!currentBuffer.TryGetSegment(size, out segment))\n                    {\n                        string errmsg = string.Format(CultureInfo.InvariantCulture,\n                            \"Message size is too big. MessageSize: {0}\", size);\n                        throw new ArgumentOutOfRangeException(nameof(queueMessage), errmsg);\n                    }\n                }\n                // encode namespace, offset, partitionkey, properties and payload into segment\n                int writeOffset = 0;\n                SegmentBuilder.Append(segment, ref writeOffset, queueMessage.Data);\n                return segment;\n            }\n        }\n\n        /// <summary>\n        /// Fill the cache with 2 streams.\n        /// Get valid cursor to start of each stream.\n        /// Walk each cursor until there is no more data on each stream.\n        /// Alternate adding messages to cache and walking cursors.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void GoldenPathTest()\n        {\n            var bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(PooledBufferSize));\n            var dataAdapter = new TestCacheDataAdapter();\n            var cache = new PooledQueueCache(dataAdapter, NullLogger.Instance, null, null);\n            var evictionStrategy = new ChronologicalEvictionStrategy(NullLogger.Instance, new TimePurgePredicate(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10)), null, null);\n            evictionStrategy.PurgeObservable = cache;\n            var converter = new CachedMessageConverter(bufferPool, evictionStrategy);\n\n            RunGoldenPath(cache, converter, 111);\n        }\n\n        /// <summary>\n        /// Run normal golden path test, then purge the cache, and then run another golden path test.  \n        /// Goal is to make sure cache cleans up correctly when all data is purged.\n        /// </summary>\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void CacheDrainTest()\n        {\n            var bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(PooledBufferSize));\n            var dataAdapter = new TestCacheDataAdapter();\n            var cache = new PooledQueueCache(dataAdapter, NullLogger.Instance, null, null);\n            var evictionStrategy = new ChronologicalEvictionStrategy(NullLogger.Instance, new TimePurgePredicate(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10)), null, null);\n            evictionStrategy.PurgeObservable = cache;\n            var converter = new CachedMessageConverter(bufferPool, evictionStrategy);\n\n            int startSequenceNuber = 222;\n            startSequenceNuber = RunGoldenPath(cache, converter, startSequenceNuber);\n            RunGoldenPath(cache, converter, startSequenceNuber);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void AvoidCacheMissNotEmptyCache()\n        {\n            AvoidCacheMiss(false);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void AvoidCacheMissEmptyCache()\n        {\n            AvoidCacheMiss(true);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void AvoidCacheMissMultipleStreamsActive()\n        {\n            var bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(PooledBufferSize));\n            var dataAdapter = new TestCacheDataAdapter();\n            var cache = new PooledQueueCache(dataAdapter, NullLogger.Instance, null, null, TimeSpan.FromSeconds(30));\n            var evictionStrategy = new ChronologicalEvictionStrategy(NullLogger.Instance, new TimePurgePredicate(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)), null, null);\n            evictionStrategy.PurgeObservable = cache;\n            var converter = new CachedMessageConverter(bufferPool, evictionStrategy);\n\n            var seqNumber = 123;\n            var streamKey = Guid.NewGuid();\n            var stream = StreamId.Create(TestStreamNamespace, streamKey);\n\n            // Enqueue a message for our stream\n            var firstSequenceNumber = EnqueueMessage(streamKey);\n\n            // Enqueue a few other messages for other streams\n            EnqueueMessage(Guid.NewGuid());\n            EnqueueMessage(Guid.NewGuid());\n\n            // Consume the first event and see that the cursor has moved to last seen event (not matching our streamIdentity)\n            var cursor = cache.GetCursor(stream, new EventSequenceTokenV2(firstSequenceNumber));\n            Assert.True(cache.TryGetNextMessage(cursor, out var firstContainer));\n            Assert.False(cache.TryGetNextMessage(cursor, out _));\n\n            // Remove multiple events, including the one that the cursor is currently pointing to\n            cache.RemoveOldestMessage();\n            cache.RemoveOldestMessage();\n            cache.RemoveOldestMessage();\n\n            // Enqueue another message for stream\n            var lastSequenceNumber = EnqueueMessage(streamKey);\n\n            // Should be able to consume the event just pushed\n            Assert.True(cache.TryGetNextMessage(cursor, out var lastContainer));\n            Assert.Equal(stream, lastContainer.StreamId);\n            Assert.Equal(lastSequenceNumber, lastContainer.SequenceToken.SequenceNumber);\n\n            long EnqueueMessage(Guid streamId)\n            {\n                var now = DateTime.UtcNow;\n                var msg = new TestQueueMessage\n                {\n                    StreamId = StreamId.Create(TestStreamNamespace, streamId),\n                    SequenceNumber = seqNumber,\n                };\n                cache.Add(new List<CachedMessage>() { converter.ToCachedMessage(msg, now) }, now);\n                seqNumber++;\n                return msg.SequenceNumber;\n            }\n        }\n\n        private void AvoidCacheMiss(bool emptyCache)\n        {\n            var bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(PooledBufferSize));\n            var dataAdapter = new TestCacheDataAdapter();\n            var cache = new PooledQueueCache(dataAdapter, NullLogger.Instance, null, null, TimeSpan.FromSeconds(30));\n            var evictionStrategy = new ChronologicalEvictionStrategy(NullLogger.Instance, new TimePurgePredicate(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)), null, null);\n            evictionStrategy.PurgeObservable = cache;\n            var converter = new CachedMessageConverter(bufferPool, evictionStrategy);\n\n            var seqNumber = 123;\n            var stream = StreamId.Create(TestStreamNamespace, Guid.NewGuid());\n\n            // Enqueue a message for stream\n            var firstSequenceNumber = EnqueueMessage(stream);\n\n            // Consume first event\n            var cursor = cache.GetCursor(stream, new EventSequenceTokenV2(firstSequenceNumber));\n            Assert.True(cache.TryGetNextMessage(cursor, out var firstContainer));\n            Assert.Equal(stream, firstContainer.StreamId);\n            Assert.Equal(firstSequenceNumber, firstContainer.SequenceToken.SequenceNumber);\n\n            // Remove first message, that was consumed\n            cache.RemoveOldestMessage();\n\n            if (!emptyCache)\n            {\n                // Enqueue something not related to the stream\n                // so the cache isn't empty\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n                EnqueueMessage(StreamId.Create(TestStreamNamespace, Guid.NewGuid()));\n            }\n\n            // Enqueue another message for stream\n            var lastSequenceNumber = EnqueueMessage(stream);\n\n            // Should be able to consume the event just pushed\n            Assert.True(cache.TryGetNextMessage(cursor, out var lastContainer));\n            Assert.Equal(stream, lastContainer.StreamId);\n            Assert.Equal(lastSequenceNumber, lastContainer.SequenceToken.SequenceNumber);\n\n            long EnqueueMessage(StreamId streamId)\n            {\n                var now = DateTime.UtcNow;\n                var msg = new TestQueueMessage\n                {\n                    StreamId = streamId,\n                    SequenceNumber = seqNumber,\n                };\n                cache.Add(new List<CachedMessage>() { converter.ToCachedMessage(msg, now) }, now);\n                seqNumber++;\n                return msg.SequenceNumber;\n            }\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public void SimpleCacheMiss()\n        {\n            var bufferPool = new ObjectPool<FixedSizeBuffer>(() => new FixedSizeBuffer(PooledBufferSize));\n            var dataAdapter = new TestCacheDataAdapter();\n            var cache = new PooledQueueCache(dataAdapter, NullLogger.Instance, null, null, TimeSpan.FromSeconds(10));\n            var evictionStrategy = new ChronologicalEvictionStrategy(NullLogger.Instance, new TimePurgePredicate(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)), null, null);\n            evictionStrategy.PurgeObservable = cache;\n            var converter = new CachedMessageConverter(bufferPool, evictionStrategy);\n\n            var seqNumber = 123;\n            var streamKey = Guid.NewGuid();\n            var stream = StreamId.Create(TestStreamNamespace, streamKey);\n\n            var cursor = cache.GetCursor(stream, new EventSequenceTokenV2(seqNumber));\n            // Start by enqueuing a message for stream, followed bu another one destined for another one\n            EnqueueMessage(streamKey);\n            EnqueueMessage(Guid.NewGuid());\n            // Consume the stream, should be fine\n            Assert.True(cache.TryGetNextMessage(cursor, out _));\n            Assert.False(cache.TryGetNextMessage(cursor, out _));\n\n            // Enqueue a new batch\n            // First and last messages destined for stream, following messages\n            // destined for other streams\n            EnqueueMessage(streamKey);\n            for (var idx = 0; idx < 20; idx++)\n            {\n                EnqueueMessage(Guid.NewGuid());\n            }\n\n            // Remove first three messages from the cache\n            cache.RemoveOldestMessage(); // Destined for stream, consumed\n            cache.RemoveOldestMessage(); // Not destined for stream\n            cache.RemoveOldestMessage(); // Destined for stream, not consumed\n\n            // Enqueue a new message for stream\n            EnqueueMessage(streamKey);\n\n            // Should throw since we missed the second message destined for stream\n            Assert.Throws<QueueCacheMissException>(() => cache.TryGetNextMessage(cursor, out _));\n\n            long EnqueueMessage(Guid streamId)\n            {\n                var now = DateTime.UtcNow;\n                var msg = new TestQueueMessage\n                {\n                    StreamId = StreamId.Create(TestStreamNamespace, streamId),\n                    SequenceNumber = seqNumber,\n                };\n                cache.Add(new List<CachedMessage>() { converter.ToCachedMessage(msg, now) }, now);\n                seqNumber++;\n                return msg.SequenceNumber;\n            }\n        }\n\n        private int RunGoldenPath(PooledQueueCache cache, CachedMessageConverter converter, int startOfCache)\n        {\n            int sequenceNumber = startOfCache;\n            IBatchContainer batch;\n\n            var stream1 = StreamId.Create(TestStreamNamespace, Guid.NewGuid());\n            var stream2 = StreamId.Create(TestStreamNamespace, Guid.NewGuid());\n\n            // now add messages into cache newer than cursor\n            // Adding enough to fill the pool\n            List<TestQueueMessage> messages = Enumerable.Range(0, MessagesPerBuffer * PooledBufferCount)\n                .Select(i => new TestQueueMessage\n                {\n                    StreamId = i % 2 == 0 ? stream1 : stream2,\n                    SequenceNumber = sequenceNumber + i\n                })\n                .ToList();\n            DateTime utcNow = DateTime.UtcNow;\n            List<CachedMessage> cachedMessages = messages\n                .Select(m => converter.ToCachedMessage(m, utcNow))\n                .ToList();\n            cache.Add(cachedMessages, utcNow);\n            sequenceNumber += MessagesPerBuffer * PooledBufferCount;\n\n            // get cursor for stream1, walk all the events in the stream using the cursor\n            object stream1Cursor = cache.GetCursor(stream1, new EventSequenceTokenV2(startOfCache));\n            int stream1EventCount = 0;\n            while (cache.TryGetNextMessage(stream1Cursor, out batch))\n            {\n                Assert.NotNull(stream1Cursor);\n                Assert.NotNull(batch);\n                Assert.Equal(stream1, batch.StreamId);\n                Assert.NotNull(batch.SequenceToken);\n                stream1EventCount++;\n            }\n            Assert.Equal((sequenceNumber - startOfCache) / 2, stream1EventCount);\n\n            // get cursor for stream2, walk all the events in the stream using the cursor\n            object stream2Cursor = cache.GetCursor(stream2, new EventSequenceTokenV2(startOfCache));\n            int stream2EventCount = 0;\n            while (cache.TryGetNextMessage(stream2Cursor, out batch))\n            {\n                Assert.NotNull(stream2Cursor);\n                Assert.NotNull(batch);\n                Assert.Equal(stream2, batch.StreamId);\n                Assert.NotNull(batch.SequenceToken);\n                stream2EventCount++;\n            }\n            Assert.Equal((sequenceNumber - startOfCache) / 2, stream2EventCount);\n\n            // Add a blocks worth of events to the cache, then walk each cursor.  Do this enough times to fill the cache twice.\n            for (int j = 0; j < PooledBufferCount*2; j++)\n            {\n                List<TestQueueMessage> moreMessages = Enumerable.Range(0, MessagesPerBuffer)\n                .Select(i => new TestQueueMessage\n                {\n                    StreamId = i % 2 == 0 ? stream1 : stream2,\n                    SequenceNumber = sequenceNumber + i\n                })\n                .ToList();\n                utcNow = DateTime.UtcNow;\n                List<CachedMessage> moreCachedMessages = moreMessages\n                    .Select(m => converter.ToCachedMessage(m, utcNow))\n                    .ToList();\n                cache.Add(moreCachedMessages, utcNow);\n                sequenceNumber += MessagesPerBuffer;\n\n                // walk all the events in the stream using the cursor\n                while (cache.TryGetNextMessage(stream1Cursor, out batch))\n                {\n                    Assert.NotNull(stream1Cursor);\n                    Assert.NotNull(batch);\n                    Assert.Equal(stream1, batch.StreamId);\n                    Assert.NotNull(batch.SequenceToken);\n                    stream1EventCount++;\n                }\n                Assert.Equal((sequenceNumber - startOfCache) / 2, stream1EventCount);\n\n                // walk all the events in the stream using the cursor\n                while (cache.TryGetNextMessage(stream2Cursor, out batch))\n                {\n                    Assert.NotNull(stream2Cursor);\n                    Assert.NotNull(batch);\n                    Assert.Equal(stream2, batch.StreamId);\n                    Assert.NotNull(batch.SequenceToken);\n                    stream2EventCount++;\n                }\n                Assert.Equal((sequenceNumber - startOfCache) / 2, stream2EventCount);\n            }\n            return sequenceNumber;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/BroadcastChannels/BroadcastChannelTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.BroadcastChannel;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.Grains.BroadcastChannel;\nusing Xunit;\n\nnamespace Tester.StreamingTests.BroadcastChannel\n{\n    /// <summary>\n    /// Tests broadcast channel functionality including fire-and-forget and non-fire-and-forget delivery modes with multiple subscribers.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class BroadcastChannelTests : OrleansTestingBase, IClassFixture<BroadcastChannelTests.Fixture>\n    {\n        private const string ProviderName = \"BroadcastChannel\";\n        private const string ProviderNameNonFireAndForget = \"BroadcastChannelNonFireAndForget\";\n        private const int CallTimeoutMs = 500;\n        private readonly Fixture _fixture;\n        private IBroadcastChannelProvider _provider => _fixture.Client.GetBroadcastChannelProvider(ProviderName);\n        private IBroadcastChannelProvider _providerNonFireAndForget => _fixture.Client.GetBroadcastChannelProvider(ProviderNameNonFireAndForget);\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void CheckPreconditionsOrThrow()\n            {\n                base.CheckPreconditionsOrThrow();\n            }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddClientBuilderConfigurator<ClientConfigurator>();\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            }\n            public class SiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddBroadcastChannel(ProviderName);\n                    hostBuilder.AddBroadcastChannel(ProviderNameNonFireAndForget, options => options.FireAndForgetDelivery = false);\n                }\n            }\n            public class ClientConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddBroadcastChannel(ProviderName);\n                    clientBuilder.AddBroadcastChannel(ProviderNameNonFireAndForget, options => options.FireAndForgetDelivery = false);\n                }\n            }\n        }\n\n        public BroadcastChannelTests(Fixture fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n            _fixture = fixture;\n        }\n\n        [Fact]\n        public async Task ClientPublishSingleChannelTest() => await ClientPublishSingleChannelTestImpl(_provider);\n\n        [Fact]\n        public async Task ClientPublishSingleChannelMultipleConsumersTest() => await MultipleSubscribersChannelTestImpl(_provider);\n\n        [Fact]\n        public async Task ClientPublishMultipleChannelTest() => await ClientPublishMultipleChannelTestImpl(_provider);\n\n        [Fact]\n        public async Task MultipleSubscribersOneBadActorChannelTest() => await MultipleSubscribersOneBadActorChannelTestImpl(_provider);\n\n        [Fact]\n        public async Task NonFireAndForgetClientPublishSingleChannelTest() => await ClientPublishSingleChannelTestImpl(_providerNonFireAndForget, false);\n\n        [Fact]\n        public async Task NonFireAndForgetClientPublishMultipleChannelTest() => await ClientPublishMultipleChannelTestImpl(_providerNonFireAndForget);\n\n        [Fact]\n        public async Task NonFireAndForgetClientPublishSingleChannelMultipleConsumersTest() => await MultipleSubscribersChannelTestImpl(_providerNonFireAndForget, false);\n\n        [Fact]\n        public async Task NonFireAndForgetMultipleSubscribersOneBadActorChannelTest() => await MultipleSubscribersOneBadActorChannelTestImpl(_providerNonFireAndForget, false);\n\n        private async Task ClientPublishSingleChannelTestImpl(IBroadcastChannelProvider provider, bool fireAndForget = true)\n        {\n            var grainKey = Guid.NewGuid().ToString(\"N\");\n            var channelId = ChannelId.Create(\"some-namespace\", grainKey);\n            var stream = provider.GetChannelWriter<int>(channelId);\n\n            await stream.Publish(1);\n            await stream.Publish(2);\n            await stream.Publish(3);\n\n            var grain = _fixture.Client.GetGrain<ISimpleSubscriberGrain>(grainKey);\n            var values = await Get(() => grain.GetValues(channelId), 3);\n\n            Assert.Equal(3, values.Count);\n            if (fireAndForget)\n            {\n                Assert.Contains(1, values);\n                Assert.Contains(2, values);\n                Assert.Contains(3, values);\n            }\n            else\n            {\n                Assert.Equal(1, values[0]);\n                Assert.Equal(2, values[1]);\n                Assert.Equal(3, values[2]);\n            }\n        }\n\n        private async Task ClientPublishMultipleChannelTestImpl(IBroadcastChannelProvider provider)\n        {\n            var grainKey = Guid.NewGuid().ToString(\"N\");\n            var channels = new List<(ChannelId ChannelId, int ExpectedValue)>();\n\n            for (var i = 0; i < 10; i++)\n            {\n                var id = ChannelId.Create($\"some-namespace{i}\", grainKey);\n                var value = i + 50;\n\n                channels.Add((id, value));\n\n                await provider.GetChannelWriter<int>(id).Publish(value);\n            }\n\n            var grain = _fixture.Client.GetGrain<ISimpleSubscriberGrain>(grainKey);\n\n            foreach (var channel in channels)\n            {\n                var values = await Get(() => grain.GetValues(channel.ChannelId), 1);\n\n                Assert.Single(values);\n                Assert.Equal(channel.ExpectedValue, values[0]);\n            }\n        }\n\n        private async Task MultipleSubscribersChannelTestImpl(IBroadcastChannelProvider provider, bool fireAndForget = true)\n        {\n            var grainKey = Guid.NewGuid().ToString(\"N\");\n            var channelId = ChannelId.Create(\"multiple-namespaces-0\", grainKey);\n            var stream = provider.GetChannelWriter<int>(channelId);\n\n            await stream.Publish(1);\n            await stream.Publish(2);\n            await stream.Publish(3);\n\n            var grains = new ISubscriberGrain[]\n            {\n                _fixture.Client.GetGrain<ISimpleSubscriberGrain>(grainKey),\n                _fixture.Client.GetGrain<IRegexNamespaceSubscriberGrain>(grainKey)\n            };\n\n            foreach (var grain in grains)\n            {\n                var values = await Get(() => grain.GetValues(channelId), 3);\n\n                Assert.Equal(3, values.Count);\n                if (fireAndForget)\n                {\n                    Assert.Contains(1, values);\n                    Assert.Contains(2, values);\n                    Assert.Contains(3, values);\n                }\n                else\n                {\n                    Assert.Equal(1, values[0]);\n                    Assert.Equal(2, values[1]);\n                    Assert.Equal(3, values[2]);\n                } \n            }\n        }\n\n        private async Task MultipleSubscribersOneBadActorChannelTestImpl(IBroadcastChannelProvider provider, bool fireAndForget = true)\n        {\n            var grainKey = Guid.NewGuid().ToString(\"N\");\n            var channelId = ChannelId.Create(\"multiple-namespaces-0\", grainKey);\n            var stream = provider.GetChannelWriter<int>(channelId);\n\n            var badGrain = _fixture.Client.GetGrain<ISimpleSubscriberGrain>(grainKey);\n            var goodGrain = _fixture.Client.GetGrain<IRegexNamespaceSubscriberGrain>(grainKey);\n\n            await stream.Publish(1);\n            if (fireAndForget)\n            {\n                var values = await Get(() => badGrain.GetValues(channelId), 1);\n                Assert.Single(values);\n            }\n            await badGrain.ThrowsOnReceive(true);\n            if (fireAndForget)\n            {\n                await stream.Publish(2);\n                // Wait to be sure that published event reached the grain\n                var counter = 0;\n                using var cts = new CancellationTokenSource(CallTimeoutMs);\n                while (!cts.IsCancellationRequested)\n                {\n                    counter = await badGrain.GetOnPublishedCounter();\n                    if (counter == 2) break;\n                    await Task.Delay(10);\n                }\n                Assert.Equal(2, counter);\n            }\n            else\n            {\n                var ex = await Assert.ThrowsAsync<AggregateException>(() => stream.Publish(2));\n                Assert.Single(ex.InnerExceptions);\n            }\n            await badGrain.ThrowsOnReceive(false);\n            await stream.Publish(3);\n\n            var goodValues = await Get(() => goodGrain.GetValues(channelId), 3);\n\n            Assert.Equal(3, goodValues.Count);\n            if (fireAndForget)\n            {\n                Assert.Contains(1, goodValues);\n                Assert.Contains(2, goodValues);\n                Assert.Contains(3, goodValues);\n            }\n            else\n            {\n                Assert.Equal(1, goodValues[0]);\n                Assert.Equal(2, goodValues[1]);\n                Assert.Equal(3, goodValues[2]);\n            }\n\n            var badValues = await Get(() => badGrain.GetValues(channelId), 2);\n\n            Assert.Equal(2, badValues.Count);\n            if (fireAndForget)\n            {\n                Assert.Contains(1, badValues);\n                Assert.Contains(3, badValues);\n            }\n            else\n            {\n                Assert.Equal(1, badValues[0]);\n                Assert.Equal(3, badValues[1]);\n            }\n        }\n\n        private static async Task<List<T>> Get<T>(Func<Task<List<T>>> func, int expectedCount, int timeoutMs = CallTimeoutMs)\n        {\n            using var cts = new CancellationTokenSource(timeoutMs);\n            while (!cts.IsCancellationRequested)\n            {\n                try\n                {\n                    var values = await func();\n                    if (values.Count == expectedCount)\n                    {\n                        return values;\n                    }\n                    await Task.Delay(10);\n                }\n                catch (Exception)\n                {\n                    // Ignore\n                }\n            }\n            return await func();\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ClientStreamTestRunner.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.StreamingTests\n{\n    public class ClientStreamTestRunner\n    {\n        private static readonly Func<Task<int>> DefaultDeliveryFailureCount = () => Task.FromResult(0); \n        private static readonly TimeSpan _timeout = TimeSpan.FromMinutes(3);\n\n        private readonly TestCluster testHost;\n        public ClientStreamTestRunner(TestCluster testHost)\n        {\n            this.testHost = testHost;\n        }\n\n        public async Task StreamProducerOnDroppedClientTest(string streamProviderName, string streamNamespace)\n        {\n            const int eventsProduced = 10;\n            Guid streamGuid = Guid.NewGuid();\n\n            await ProduceEventsFromClient(streamProviderName, streamGuid, streamNamespace, eventsProduced);\n\n            // Hard kill client\n            await testHost.KillClientAsync();\n            \n            // make sure dead client has had time to drop\n            await Task.Delay(Constants.DEFAULT_CLIENT_DROP_TIMEOUT + TimeSpan.FromSeconds(5));\n\n            // initialize new client\n            await testHost.InitializeClientAsync();\n\n            // run test again.\n            await ProduceEventsFromClient(streamProviderName, streamGuid, streamNamespace, eventsProduced);\n        }\n\n        public async Task StreamConsumerOnDroppedClientTest(string streamProviderName, string streamNamespace, ITestOutputHelper output, Func<Task<int>> getDeliveryFailureCount = null, bool waitForRetryTimeouts = false)\n        {\n            getDeliveryFailureCount = getDeliveryFailureCount ?? DefaultDeliveryFailureCount;\n\n            Guid streamGuid = Guid.NewGuid();\n            int[] eventCount = {0};\n\n            // become stream consumers\n            await SubscribeToStream(streamProviderName, streamGuid, streamNamespace,\n                (e, t) => { eventCount[0]++; return Task.CompletedTask; });\n\n            // setup producer\n            var producer = this.testHost.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // produce some events\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            // check counts\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(() => Task.FromResult(eventCount[0]), producer.GetNumberProduced, lastTry), _timeout);\n\n            // Hard kill client\n            await testHost.KillClientAsync();\n\n            // make sure dead client has had time to drop\n            await Task.Delay(Constants.DEFAULT_CLIENT_DROP_TIMEOUT + TimeSpan.FromSeconds(5));\n\n            // initialize new client\n            await testHost.InitializeClientAsync();\n\n            eventCount[0] = 0;\n\n            // become stream consumers\n            await SubscribeToStream(streamProviderName, streamGuid, streamNamespace,\n                (e, t) => { eventCount[0]++; return Task.CompletedTask; });\n\n            // setup producer\n            producer = this.testHost.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // produce more events\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            // give strem retry policy time to fail\n            if (waitForRetryTimeouts)\n            {\n                await Task.Delay(TimeSpan.FromSeconds(90));\n            }\n\n            // check counts\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(() => Task.FromResult(eventCount[0]), producer.GetNumberProduced, lastTry), _timeout);\n            int deliveryFailureCount = await getDeliveryFailureCount();\n            Assert.Equal(0, deliveryFailureCount);\n        }\n\n        private Task SubscribeToStream(string streamProviderName, Guid streamGuid, string streamNamespace,\n            Func<int, StreamSequenceToken, Task> onNextAsync)\n        {\n            IStreamProvider streamProvider = this.testHost.Client.GetStreamProvider(streamProviderName);\n            IAsyncObservable<int> stream = streamProvider.GetStream<int>(streamNamespace, streamGuid);\n            return stream.SubscribeAsync(onNextAsync);\n        }\n\n        private async Task ProduceEventsFromClient(string streamProviderName, Guid streamGuid, string streamNamespace, int eventsProduced)\n        {\n            // get reference to a consumer\n            var consumer = this.testHost.GrainFactory.GetGrain<ISampleStreaming_ConsumerGrain>(Guid.NewGuid());\n\n            // subscribe\n            await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            // generate events\n            await GenerateEvents(streamProviderName, streamGuid, streamNamespace, eventsProduced);\n\n            // make sure all went well\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(() => consumer.GetNumberConsumed(), () => Task.FromResult(eventsProduced), lastTry), _timeout);\n        }\n\n        private async Task GenerateEvents(string streamProviderName, Guid streamGuid, string streamNamespace, int produceCount)\n        {\n            IStreamProvider streamProvider = this.testHost.Client.GetStreamProvider(streamProviderName);\n            IAsyncObserver<int> observer = streamProvider.GetStream<int>(streamNamespace, streamGuid);\n            for (int i = 0; i < produceCount; i++)\n            {\n                await observer.OnNextAsync(i);\n            }\n        }\n\n        private async Task<bool> CheckCounters(Func<Task<int>> getConsumed, Func<Task<int>> getProduced, bool assertIsTrue)\n        {\n            int eventsProduced = await getProduced();\n            int numConsumed = await getConsumed();\n            if (!assertIsTrue) return eventsProduced == numConsumed;\n            Assert.Equal(eventsProduced, numConsumed);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ControllableStreamGeneratorProviderTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing TestGrainInterfaces;\nusing TestGrains;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests for the controllable stream generator provider functionality, validating stream generation behavior and control commands.\n    /// </summary>\n    public class ControllableStreamGeneratorProviderTests : OrleansTestingBase, IClassFixture<ControllableStreamGeneratorProviderTests.Fixture>\n    {\n        private const int TotalQueueCount = 4;\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n            public static readonly string StreamProviderTypeName = typeof(PersistentStreamProvider).FullName;\n            public const string StreamNamespace = GeneratedEventCollectorGrain.StreamNamespace;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddPersistentStreams(StreamProviderName,\n                            GeneratorAdapterFactory.Create,\n                            b =>\n                            {\n                                b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                                b.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = TotalQueueCount));\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                            });\n                }\n            }\n        }\n\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n\n        public ControllableStreamGeneratorProviderTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n        \n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public async Task ValidateControllableGeneratedStreamsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ ValidateControllableGeneratedStreamsTest *********************************\");\n            await ValidateControllableGeneratedStreams();\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public async Task Validate2ControllableGeneratedStreamsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ Validate2ControllableGeneratedStreamsTest *********************************\");\n            await ValidateControllableGeneratedStreams();\n            await ValidateControllableGeneratedStreams();\n        }\n\n        private async Task ValidateControllableGeneratedStreams()\n        {\n            try\n            {\n                var generatorConfig = new SimpleGeneratorOptions\n                {\n                    StreamNamespace = Fixture.StreamNamespace,\n                    EventsInStream = 100\n                };\n\n                var mgmt = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n                object[] results = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(Fixture.StreamProviderName, (int)StreamGeneratorCommand.Configure, generatorConfig);\n                Assert.Equal(2, results.Length);\n                bool[] bResults = results.Cast<bool>().ToArray();\n\n                foreach (var controlCommandResult in bResults)\n                {\n                    Assert.True(controlCommandResult);\n                }\n\n                await TestingUtils.WaitUntilAsync(assertIsTrue => CheckCounters(generatorConfig, assertIsTrue), Timeout);\n            }\n            finally\n            {\n                var reporter = this.fixture.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n                reporter.Reset().Ignore();\n            }\n        }\n\n        private async Task<bool> CheckCounters(SimpleGeneratorOptions generatorConfig, bool assertIsTrue)\n        {\n            var reporter = this.fixture.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n\n            var report = await reporter.GetReport(GeneratedStreamTestConstants.StreamProviderName, GeneratedEventCollectorGrain.StreamNamespace);\n            if (assertIsTrue)\n            {\n                // one stream per queue\n                Assert.Equal(TotalQueueCount, report.Count); // stream count\n                foreach (int eventsPerStream in report.Values)\n                {\n                    Assert.Equal(generatorConfig.EventsInStream, eventsPerStream);\n                }\n            }\n            else if (TotalQueueCount != report.Count ||\n                     report.Values.Any(count => count != generatorConfig.EventsInStream))\n            {\n                return false;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ControllableStreamProviderTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Tester.TestStreamProviders.Controllable;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests for the controllable stream provider adapter, validating echo commands through adapter and factory interfaces.\n    /// </summary>\n    public class ControllableStreamProviderTests : OrleansTestingBase, IClassFixture<ControllableStreamProviderTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = \"ControllableTestStreamProvider\";\n            public readonly string StreamProviderTypeName = typeof(PersistentStreamProvider).FullName;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddPersistentStreams(\n                            StreamProviderName,\n                            ControllableTestAdapterFactory.Create,\n                            b=>\n                            {\n                                b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                            });\n                }\n            }\n        }\n\n        private readonly Fixture _fixture;\n\n        public ControllableStreamProviderTests(Fixture fixture)\n        {\n            _fixture = fixture;\n        }        \n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task ControllableAdapterEchoTest()\n        {\n            _fixture.Logger.LogInformation(\"************************ ControllableAdapterEchoTest *********************************\");\n            const string echoArg = \"blarg\";\n            await ControllableAdapterEchoTestRunner(ControllableTestStreamProviderCommands.AdapterEcho, echoArg);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task ControllableAdapterFactoryEchoTest()\n        {\n            _fixture.Logger.LogInformation(\"************************ ControllableAdapterFactoryEchoTest *********************************\");\n            const string echoArg = \"blarg\";\n            await ControllableAdapterEchoTestRunner(ControllableTestStreamProviderCommands.AdapterFactoryEcho, echoArg);\n        }\n\n        private async Task ControllableAdapterEchoTestRunner(ControllableTestStreamProviderCommands command, object echoArg)\n        {\n            _fixture.Logger.LogInformation(\"************************ ControllableAdapterEchoTest *********************************\");\n            var mgmt = _fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n\n            object[] results = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(Fixture.StreamProviderName, (int)command, echoArg);\n            Assert.Equal(2, results.Length);\n            Tuple<ControllableTestStreamProviderCommands, object>[] echos = results.Cast<Tuple<ControllableTestStreamProviderCommands, object>>().ToArray();\n            foreach (var echo in echos)\n            {\n                Assert.Equal(command, echo.Item1);\n                Assert.Equal(echoArg, echo.Item2);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/DeactivationTestRunner.cs",
    "content": "using Orleans.Streams;\nusing Orleans.Internal;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Orleans.Runtime;\nusing Orleans.Core.Internal;\n\nnamespace UnitTests.StreamingTests\n{\n    internal class DeactivationTestRunner\n    {\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10);\n        private readonly string streamProviderName;\n        private readonly IClusterClient client;\n\n        private class Counter\n        {\n            public int Value { get; private set; }\n\n            public Task Increment()\n            {\n                Value++;\n                return Task.CompletedTask;\n            }\n\n            public void Clear()\n            {\n                Value = 0;\n            }\n        }\n\n        public DeactivationTestRunner(string streamProviderName, IClusterClient client)\n        {\n            if (string.IsNullOrWhiteSpace(streamProviderName))\n            {\n                throw new ArgumentNullException(nameof(streamProviderName));\n            }\n\n            if (client == null) throw new ArgumentNullException(nameof(client));\n\n            this.streamProviderName = streamProviderName;\n            this.client = client;\n        }\n\n        public async Task DeactivationTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.client.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.client.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            // subscribe (PubSubRendezvousGrain will have one consumer)\n            StreamSubscriptionHandle<int> subscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            // produce one message (PubSubRendezvousGrain will have one consumer and one producer)\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n            await producer.Produce();\n\n            var count = await consumer.GetNumberConsumed();\n\n            var consumerGrainReceivedStreamMessage = count[subscriptionHandle].Item1 == 1;\n            Assert.True(consumerGrainReceivedStreamMessage);\n\n            // Deactivate all of the pub sub rendesvous grains\n            var rendesvousGrains = await client.GetGrain<IManagementGrain>(0).GetActiveGrains(GrainType.Create(\"pubsubrendezvous\"));\n            foreach (var grainId in rendesvousGrains)\n            {\n                var grain = client.GetGrain<IGrainManagementExtension>(grainId);\n                await grain.DeactivateOnIdle();\n            }\n\n            // deactivating PubSubRendezvousGrain and SampleStreaming_ProducerGrain during the same GC cycle causes a deadlock\n            // resume producing after the PubSubRendezvousGrain and the SampleStreaming_ProducerGrain grains have been deactivated:\n\n            // BecomeProducer is hung due to deactivation deadlock?\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName).WaitAsync(Timeout);\n\n            // Produce is hung due to deactivation deadlock?\n            await producer.Produce().WaitAsync(Timeout);\n\n            // consumer grain should continue to receive stream messages:\n            count = await consumer.GetNumberConsumed();\n\n            Assert.True(count[subscriptionHandle].Item1 == 2, \"Consumer did not receive stream messages after PubSubRendezvousGrain and SampleStreaming_ProducerGrain reactivation\");\n        }\n\n        public async Task DeactivationTest_ClientConsumer(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.client.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n\n            var count = new Counter();\n            // get stream and subscribe\n            IStreamProvider streamProvider = this.client.GetStreamProvider(streamProviderName);\n            var stream = streamProvider.GetStream<int>(streamNamespace, streamGuid);\n            StreamSubscriptionHandle<int> subscriptionHandle = await stream.SubscribeAsync((e, t) => count.Increment());\n\n            // produce one message (PubSubRendezvousGrain will have one consumer and one producer)\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n            await producer.Produce();\n\n            Assert.Equal(1, count.Value);\n\n            // Deactivate all of the pub sub rendesvous grains\n            var rendesvousGrains = await client.GetGrain<IManagementGrain>(0).GetActiveGrains(GrainType.Create(\"pubsubrendezvous\"));\n            foreach (var grainId in rendesvousGrains)\n            {\n                var grain = client.GetGrain<IGrainManagementExtension>(grainId);\n                await grain.DeactivateOnIdle();\n            }\n\n            // deactivating PubSubRendezvousGrain and SampleStreaming_ProducerGrain during the same GC cycle causes a deadlock\n            // resume producing after the PubSubRendezvousGrain and the SampleStreaming_ProducerGrain grains have been deactivated:\n\n            // BecomeProducer is hung due to deactivation deadlock?\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName).WaitAsync(Timeout);\n\n            // Produce is hung due to deactivation deadlock?\n            await producer.Produce().WaitAsync(Timeout);\n\n            Assert.Equal(2, count.Value); // Client consumer grain did not receive stream messages after PubSubRendezvousGrain and SampleStreaming_ProducerGrain reactivation\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/Filtering/StreamFilteringTestsBase.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams.Filtering;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Sdk;\n\nnamespace Tester.StreamingTests.Filtering\n{\n    public class CustomStreamFilter : IStreamFilter\n    {\n        private readonly ILogger<CustomStreamFilter> logger;\n\n        public CustomStreamFilter(ILogger<CustomStreamFilter> logger)\n        {\n            this.logger = logger;\n        }\n\n        public bool ShouldDeliver(StreamId streamId, object item, string filterData)\n        {\n            try\n            {\n                var result = ShouldDeliverImpl(streamId, item, filterData);\n                logger.LogInformation(\"Filter -> StreamId {StreamId}, Item: {Item}, FilterData: {FilterData} -> Result: {Result}\", streamId, item, filterData, result);\n\n                return result;\n            }\n            catch (Exception)\n            {\n                logger.LogInformation(\"Filter -> StreamId {StreamId}, Item: {Item}, FilterData: {FilterData} -> Result: exception\", streamId, item, filterData);\n                throw;\n            }\n        }\n\n        private bool ShouldDeliverImpl(StreamId streamId, object item, string filterData)\n        {\n            if (filterData.Equals(\"throw\"))\n                throw new Exception(\"throw\");\n\n            if (string.IsNullOrWhiteSpace(filterData))\n                return true;\n\n            if (filterData.Equals(\"even\"))\n            {\n                var value = (int)item;\n                return value % 2 == 0;\n            }\n\n            if (filterData.Equals(\"only3\"))\n            {\n                var value = (int)item;\n                return value == 3;\n            }\n\n            if (filterData.Equals(\"only7\"))\n            {\n                var value = (int)item;\n                return value == 7;\n            }\n\n            return true;\n        }\n    }\n\n    public abstract class StreamFilteringTestsBase : OrleansTestingBase\n    {\n        protected readonly BaseTestClusterFixture fixture;\n        private IClusterClient clusterClient => this.fixture.Client;\n        private CustomStreamFilter streamFilter => this.fixture.HostedCluster.ServiceProvider.GetKeyedService<IStreamFilter>(ProviderName) as CustomStreamFilter;\n\n        protected ILogger logger => fixture.Logger;\n\n        protected abstract string ProviderName { get; }\n\n        protected virtual TimeSpan WaitTime => TimeSpan.Zero;\n\n        protected StreamFilteringTestsBase(BaseTestClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        public virtual async Task IgnoreBadFilter()\n        {\n            EnsureStreamFilterIsRegistered();\n\n            const int numberOfEvents = 10;\n            var streamId = StreamId.Create(\"IgnoreBadFilter\", \"my-stream\");\n            var grain = this.clusterClient.GetGrain<IStreamingHistoryGrain>(\"IgnoreBadFilter\");\n\n            try\n            {\n                await grain.BecomeConsumer(streamId, ProviderName, \"throw\");\n\n                var stream = this.clusterClient.GetStreamProvider(ProviderName).GetStream<int>(streamId);\n\n                for (var i = 0; i < numberOfEvents; i++)\n                {\n                    await stream.OnNextAsync(i);\n                }\n\n                await Task.Delay(WaitTime);\n\n                var history = await grain.GetReceivedItems();\n\n                Assert.Equal(numberOfEvents, history.Count);\n                for (var i = 0; i < numberOfEvents; i++)\n                {\n                    Assert.Equal(i, history[i]);\n                }\n            }\n            finally\n            {\n                await grain.StopBeingConsumer();\n            }\n        }\n\n        public virtual async Task OnlyEvenItems()\n        {\n            EnsureStreamFilterIsRegistered();\n\n            const int numberOfEvents = 10;\n            var streamId = StreamId.Create(\"OnlyEvenItems\", \"my-stream\");\n            var grain = this.clusterClient.GetGrain<IStreamingHistoryGrain>(\"OnlyEvenItems\");\n\n            try\n            {\n                await grain.BecomeConsumer(streamId, ProviderName, \"even\");\n\n                var stream = this.clusterClient.GetStreamProvider(ProviderName).GetStream<int>(streamId);\n\n                for (var i = 0; i < numberOfEvents; i++)\n                {\n                    await stream.OnNextAsync(i);\n                }\n\n                await Task.Delay(WaitTime);\n\n                var history = await grain.GetReceivedItems();\n\n                var idx = 0;\n                for (var i = 0; i < numberOfEvents; i++)\n                {\n                    if (i % 2 == 0)\n                    {\n                        Assert.Equal(i, history[idx]);\n                        idx++;\n                    }\n                }\n            }\n            finally\n            {\n                await grain.StopBeingConsumer();\n            }\n        }\n\n        public virtual async Task MultipleSubscriptionsDifferentFilterData()\n        {\n            EnsureStreamFilterIsRegistered();\n\n            const int numberOfEvents = 10;\n            var streamId = StreamId.Create(\"MultipleSubscriptionsDifferentFilterData\", \"my-stream\");\n            var grain = this.clusterClient.GetGrain<IStreamingHistoryGrain>(\"MultipleSubscriptionsDifferentFilterData\");\n\n            try\n            {\n                await grain.BecomeConsumer(streamId, ProviderName, \"only3\");\n                await grain.BecomeConsumer(streamId, ProviderName, \"only7\");\n\n                var stream = this.clusterClient.GetStreamProvider(ProviderName).GetStream<int>(streamId);\n\n                for (var i = 0; i < numberOfEvents; i++)\n                {\n                    await stream.OnNextAsync(i);\n                }\n\n                await Task.Delay(WaitTime);\n\n                var history = await grain.GetReceivedItems();\n\n                Assert.Equal(2, history.Count);\n                Assert.Contains(3, history);\n                Assert.Contains(7, history);\n\n            }\n            finally\n            {\n                await grain.StopBeingConsumer();\n            }\n        }\n\n        private void EnsureStreamFilterIsRegistered()\n        {\n            if (this.streamFilter == null)\n            {\n                throw new XunitException(\"CustomStreamFilter not registered as a filter!\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/GeneratedStreamRecoveryTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing TestGrains;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests implicit subscription stream recovery scenarios with generated events, including transient and non-transient error handling.\n    /// </summary>\n    public class GeneratedImplicitSubscriptionStreamRecoveryTests : OrleansTestingBase, IClassFixture<GeneratedImplicitSubscriptionStreamRecoveryTests.Fixture>\n    {\n        private static readonly string StreamProviderTypeName = typeof(PersistentStreamProvider).FullName;\n        private const int TotalQueueCount = 4;\n        private readonly Fixture fixture;\n        private readonly ImplicitSubscritionRecoverableStreamTestRunner runner;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                         .AddMemoryGrainStorageAsDefault()\n                        .AddMemoryGrainStorage(\"MemoryStore\")\n                        .AddPersistentStreams(StreamProviderName,\n                            GeneratorAdapterFactory.Create,\n                            b =>\n                            {\n                                b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                                b.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = TotalQueueCount));\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                            });\n                }\n            }\n        }\n\n        public GeneratedImplicitSubscriptionStreamRecoveryTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            this.runner = new ImplicitSubscritionRecoverableStreamTestRunner(\n                this.fixture.GrainFactory,\n                Fixture.StreamProviderName);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task Recoverable100EventStreamsWithTransientErrorsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ Recoverable100EventStreamsWithTransientErrorsTest *********************************\");\n            await runner.Recoverable100EventStreamsWithTransientErrors(GenerateEvents,\n                ImplicitSubscription_TransientError_RecoverableStream_CollectorGrain.StreamNamespace,\n                TotalQueueCount,\n                100);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task Recoverable100EventStreamsWith1NonTransientErrorTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ Recoverable100EventStreamsWith1NonTransientErrorTest *********************************\");\n            await runner.Recoverable100EventStreamsWith1NonTransientError(GenerateEvents,\n                ImplicitSubscription_NonTransientError_RecoverableStream_CollectorGrain.StreamNamespace,\n                TotalQueueCount,\n                100);\n        }\n\n        private async Task GenerateEvents(string streamNamespace, int streamCount, int eventsInStream)\n        {\n            var generatorConfig = new SimpleGeneratorOptions\n            {\n                StreamNamespace = streamNamespace,\n                EventsInStream = eventsInStream\n            };\n\n            var mgmt = this.fixture.GrainFactory.GetGrain<IManagementGrain>(0);\n            object[] results = await mgmt.SendControlCommandToProvider<PersistentStreamProvider>(Fixture.StreamProviderName, (int)StreamGeneratorCommand.Configure, generatorConfig);\n            Assert.Equal(2, results.Length);\n            bool[] bResults = results.Cast<bool>().ToArray();\n            foreach (var result in bResults)\n            {\n                Assert.True(result, \"Control command result\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ImplicitSubscriptionKeyTypeGrainTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests implicit stream subscriptions with different grain key types, specifically testing long key type grain subscriptions.\n    /// </summary>\n    public sealed class ImplicitSubscriptionKeyTypeGrainTests : OrleansTestingBase, IClassFixture<ImplicitSubscriptionKeyTypeGrainTests.Fixture>\n    {\n        private readonly Fixture fixture;\n        private readonly IStreamProvider _streamProvider;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddMemoryGrainStorageAsDefault();\n\n                    hostBuilder.AddMemoryStreams(ImplicitStreamTestConstants.StreamProviderName)\n                        .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddMemoryStreams(ImplicitStreamTestConstants.StreamProviderName);\n                }\n            }\n        }\n\n        public ImplicitSubscriptionKeyTypeGrainTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            _streamProvider = fixture.Client.GetStreamProvider(ImplicitStreamTestConstants.StreamProviderName);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task LongKey()\n        {\n            long grainId = 13;\n            int value = 87;\n            IAsyncStream<int> stream = _streamProvider.GetStream<int>(nameof(IImplicitSubscriptionLongKeyGrain), grainId);\n\n            await stream.OnNextAsync(value);\n\n            var consumer = fixture.GrainFactory.GetGrain<IImplicitSubscriptionLongKeyGrain>(grainId);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckValue(consumer, value, lastTry), TimeSpan.FromSeconds(30));\n        }\n\n        private async Task<bool> CheckValue(IImplicitSubscriptionKeyTypeGrain consumer, int expectedValue, bool assertIsTrue)\n        {\n            int value = await consumer.GetValue();\n\n            if (assertIsTrue)\n            {\n                Assert.Equal(expectedValue, value);\n            }\n\n            if (expectedValue != value)\n            {\n                return false;\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ImplicitSubscritionRecoverableStreamTestRunner.cs",
    "content": "﻿using Orleans.TestingHost.Utils;\nusing TestGrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace Tester.StreamingTests\n{\n    public class ImplicitSubscritionRecoverableStreamTestRunner\n    {\n        private readonly IGrainFactory grainFactory;\n        private readonly string streamProviderName;\n\n        public ImplicitSubscritionRecoverableStreamTestRunner(IGrainFactory grainFactory, string streamProviderName)\n        {\n            this.grainFactory = grainFactory;\n            this.streamProviderName = streamProviderName;\n        }\n\n        public async Task Recoverable100EventStreamsWithTransientErrors(Func<string, int, int, Task> generateFn, string streamNamespace, int streamCount, int eventsInStream)\n        {\n            try\n            {\n                await generateFn(streamNamespace, streamCount, eventsInStream);\n                await TestingUtils.WaitUntilAsync(assertIsTrue => this.CheckCounters(streamNamespace, streamCount, eventsInStream, assertIsTrue), TimeSpan.FromSeconds(30));\n            }\n            finally\n            {\n                var reporter = this.grainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n                reporter.Reset().Ignore();\n            }\n        }\n\n        public async Task Recoverable100EventStreamsWith1NonTransientError(Func<string, int, int, Task> generateFn, string streamNamespace, int streamCount, int eventsInStream)\n        {\n            try\n            {\n                await generateFn(streamNamespace, streamCount, eventsInStream);\n                // should eventually skip the faulted event, so event count should be one (faulted event) less that number of events in stream.\n                await TestingUtils.WaitUntilAsync(assertIsTrue => this.CheckCounters(streamNamespace, streamCount, eventsInStream - 1, assertIsTrue), TimeSpan.FromSeconds(90));\n            }\n            finally\n            {\n                var reporter = this.grainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n                reporter.Reset().Ignore();\n            }\n        }\n\n        private async Task<bool> CheckCounters(string streamNamespace, int streamCount, int eventsInStream, bool assertIsTrue)\n        {\n            var reporter = grainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n\n            var report = await reporter.GetReport(streamProviderName, streamNamespace);\n            if (assertIsTrue)\n            {\n                // one stream per queue\n                Assert.Equal(streamCount, report.Count);\n                foreach (int eventsPerStream in report.Values)\n                {\n                    Assert.Equal(eventsInStream, eventsPerStream);\n                }\n            }\n            else if (streamCount != report.Count ||\n                     report.Values.Any(count => count != eventsInStream))\n            {\n                return false;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryProgrammaticSubcribeTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing Tester.StreamingTests;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests programmatic stream subscriptions using memory streams with multiple stream providers.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n    public class MemoryProgrammaticSubcribeTests : ProgrammaticSubscribeTestsRunner, IClassFixture<MemoryProgrammaticSubcribeTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<TestClusterConfigurator>();\n                builder.AddClientBuilderConfigurator<TestClusterConfigurator>();\n            }\n\n            private class TestClusterConfigurator : ISiloConfigurator, IClientBuilderConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    // Do use \"PubSubStore\" in this test\n\n                    hostBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName);\n                    hostBuilder.AddMemoryGrainStorage(StreamProviderName);\n\n                    hostBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName2);\n                    hostBuilder.AddMemoryGrainStorage(StreamProviderName2);\n                }\n\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder.AddStreaming();\n            }\n        }\n\n        public MemoryProgrammaticSubcribeTests(Fixture fixture) : base(fixture)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryStreamBatchingTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Providers;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests memory stream batching functionality with configured batch container size of 10 items.\n    /// </summary>\n    [TestCategory(\"BVT\")]\n    public class MemoryStreamBatchingTests : StreamBatchingTestRunner, IClassFixture<MemoryStreamBatchingTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            private const int partitionCount = 1;\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamBatchingTestConst.ProviderName, b =>\n                    {\n                        b.ConfigurePartitioning(partitionCount);\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder) => hostBuilder.AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamBatchingTestConst.ProviderName, b =>\n                    {\n                        b.ConfigurePartitioning(partitionCount);\n                        b.ConfigurePullingAgent(ob => ob.Configure(options => options.BatchContainerBatchSize = 10));\n                        b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                    });\n            }\n        }\n\n        public MemoryStreamBatchingTests(Fixture fixture, ITestOutputHelper output)\n            : base(fixture, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryStreamCacheMissTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing Xunit.Abstractions;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests memory stream cache miss scenarios with custom cache eviction settings and stream filters.\n    /// </summary>\n    [TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"StreamingCacheMiss\")]\n    public class MemoryStreamCacheMissTests : StreamingCacheMissTests\n    {\n        public MemoryStreamCacheMissTests(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        #region Configuration stuff\n\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b =>\n                    {\n                        b.ConfigureCacheEviction(ob => ob.Configure(options =>\n                        {\n                            options.DataMaxAgeInCache = TimeSpan.FromSeconds(5);\n                            options.DataMinTimeInCache = TimeSpan.FromSeconds(0);\n                        }));\n                    })\n                    .AddStreamFilter<CustomStreamFilter>(StreamProviderName);\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName);\n            }\n        }\n\n        #endregion\n\n\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryStreamProviderBatchedClientTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests for memory stream provider behavior with batched messages when clients are dropped from the cluster.\n    /// </summary>\n    public class MemoryStreamProviderBatchedClientTests : OrleansTestingBase, IClassFixture<MemoryStreamProviderBatchedClientTests.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = \"MemoryStreamProvider\";\n            public const string StreamNamespace = \"StreamNamespace\";\n            private const int partitionCount = 8;\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b => b\n                            .ConfigurePartitioning(partitionCount));\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder) =>\n                    hostBuilder\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(\n                        StreamProviderName,\n                        b => b.ConfigurePartitioning(partitionCount))\n                    .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n            }\n        }\n\n        private readonly ITestOutputHelper output = null;\n        private readonly ClientStreamTestRunner runner;\n\n        private readonly Fixture fixture;\n\n        public MemoryStreamProviderBatchedClientTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            runner = new ClientStreamTestRunner(fixture.HostedCluster);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task BatchedMemoryStreamProducerOnDroppedClientTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ BatchedMemoryStreamProducerOnDroppedClientTest *********************************\");\n            await runner.StreamProducerOnDroppedClientTest(Fixture.StreamProviderName, Fixture.StreamNamespace);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task BatchedMemoryStreamConsumerOnDroppedClientTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ BatchedMemoryStreamConsumerOnDroppedClientTest *********************************\");\n            await runner.StreamConsumerOnDroppedClientTest(Fixture.StreamProviderName, Fixture.StreamNamespace, output,\n                    null, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryStreamProviderClientTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests for client behavior with the MemoryStreamProvider.\n    /// \n    /// MemoryStreamProvider is an in-memory streaming provider useful for:\n    /// - Unit testing streaming scenarios without external dependencies\n    /// - Development and prototyping\n    /// - Scenarios where persistence is not required\n    /// \n    /// These tests focus on client disconnection scenarios to ensure\n    /// proper cleanup and recovery of stream producers and consumers.\n    /// </summary>\n    public class MemoryStreamProviderClientTests : OrleansTestingBase, IClassFixture<MemoryStreamProviderClientTests.Fixture>\n    {\n        /// <summary>\n        /// Test fixture that configures a cluster with MemoryStreamProvider.\n        /// Sets up both silo and client with the same stream provider configuration\n        /// to ensure proper communication.\n        /// </summary>\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = \"MemoryStreamProvider\";\n            public const string StreamNamespace = \"StreamNamespace\";\n            private const int partitionCount = 8;\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b=>b\n                    .ConfigurePartitioning(partitionCount));\n            }\n\n            /// <summary>\n            /// Configures silos with:\n            /// - Memory grain storage for PubSub subscriptions\n            /// - Memory stream provider with specified partition count\n            /// - Reduced client drop timeout for faster test execution\n            /// </summary>\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)=> hostBuilder.AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b=>b\n                    .ConfigurePartitioning(partitionCount))\n                    .Configure<SiloMessagingOptions>(options => options.ClientDropTimeout = TimeSpan.FromSeconds(5));\n            }\n        }\n\n        private readonly ITestOutputHelper output = null;\n        private readonly ClientStreamTestRunner runner;\n\n        private readonly Fixture fixture;\n\n        public MemoryStreamProviderClientTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            runner = new ClientStreamTestRunner(fixture.HostedCluster);\n        }\n\n        /// <summary>\n        /// Tests stream producer behavior when the client is dropped/disconnected.\n        /// Verifies that:\n        /// - Stream production stops when client disconnects\n        /// - No orphaned producers remain in the system\n        /// - Other clients/grains can still use the stream\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task MemoryStreamProducerOnDroppedClientTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ MemoryStreamProducerOnDroppedClientTest *********************************\");\n            await runner.StreamProducerOnDroppedClientTest(Fixture.StreamProviderName, Fixture.StreamNamespace);\n        }\n\n        /// <summary>\n        /// Tests stream consumer behavior when the client is dropped/disconnected.\n        /// Verifies that:\n        /// - Consumer subscriptions are properly cleaned up\n        /// - Messages are not lost when a consumer disconnects\n        /// - Rebalancing occurs to redistribute stream processing\n        /// </summary>\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task MemoryStreamConsumerOnDroppedClientTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ MemoryStreamConsumerOnDroppedClientTest *********************************\");\n            await runner.StreamConsumerOnDroppedClientTest(Fixture.StreamProviderName, Fixture.StreamNamespace, output,\n                    null, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MemoryStreamResumeTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests memory stream resume functionality with configurable stream inactivity periods and cache eviction settings.\n    /// </summary>\n    [TestCategory(\"SlowBVT\"), TestCategory(\"Streaming\"), TestCategory(\"StreamingResume\")]\n    public class MemoryStreamResumeTests : StreamingResumeTests\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n        }\n\n        #region Configuration stuff\n        private class MySiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b =>\n                    {\n                        b.ConfigurePullingAgent(ob => ob.Configure(options =>\n                        {\n                            options.StreamInactivityPeriod = StreamInactivityPeriod;\n                        }));\n                        b.ConfigureCacheEviction(ob => ob.Configure(options =>\n                        {\n                            options.MetadataMinTimeInCache = MetadataMinTimeInCache;\n                            options.DataMaxAgeInCache = DataMaxAgeInCache;\n                            options.DataMinTimeInCache = DataMinTimeInCache;\n                        }));\n                    });\n            }\n        }\n\n        private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName);\n            }\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/MultipleStreamsTestRunner.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing UnitTests.StreamingTests;\n\nnamespace UnitTests.Streaming\n{\n    public class MultipleStreamsTestRunner\n    {\n        public const string SMS_STREAM_PROVIDER_NAME = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n        public const string AQ_STREAM_PROVIDER_NAME = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30);\n\n        private readonly ILogger logger;\n        private readonly string streamProviderName;\n        private readonly int testNumber;\n        private readonly bool runFullTest;\n        private readonly IInternalClusterClient client;\n\n        internal MultipleStreamsTestRunner(IInternalClusterClient client, string streamProvider, int testNum = 0, bool fullTest = true)\n        {\n            this.client = client;\n            this.streamProviderName = streamProvider;\n            this.logger = (TestingUtils.CreateDefaultLoggerFactory($\"{this.GetType().Name}.log\")).CreateLogger<MultipleStreamsTestRunner>();\n            this.testNumber = testNum;\n            this.runFullTest = fullTest;\n        }\n\n        private void Heading(string testName)\n        {\n            logger.LogInformation(\"\\n\\n************************ {StreamProviderName}_{TestNumber}_{TestName} ********************************* \\n\\n\", streamProviderName, testNumber, testName);\n        }\n\n        public async Task StreamTest_MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains(Func<SiloHandle> startSiloFunc = null, Action<SiloHandle> stopSiloFunc = null)\n        {\n            Heading(\"MultipleStreams_ManyDifferent_ManyProducerGrainsManyConsumerGrains\");\n            List<SingleStreamTestRunner> runners = new List<SingleStreamTestRunner>();\n            List<Task> tasks = new List<Task>();\n            for (int i = 0; i < 10; i++)\n            {\n                runners.Add(new SingleStreamTestRunner(this.client, this.streamProviderName, i, runFullTest));\n            }\n            foreach (var runner in runners)\n            {\n                tasks.Add(runner.StreamTest_Create_OneProducerGrainOneConsumerGrain());\n            }\n            await Task.WhenAll(tasks);\n            tasks.Clear();\n\n            SiloHandle silo = null;\n            if (startSiloFunc != null)\n            {\n                silo = startSiloFunc();\n            }\n\n            foreach (var runner in runners)\n            {\n                tasks.Add(runner.BasicTestAsync(runFullTest));\n            }\n            await Task.WhenAll(tasks);\n            tasks.Clear();\n\n            if (stopSiloFunc != null)\n            {\n                logger.LogInformation(\"\\n\\n\\nAbout to stop silo {SiloAddress} \\n\\n\", silo.SiloAddress);\n\n                stopSiloFunc(silo);\n\n                foreach (var runner in runners)\n                {\n                    tasks.Add(runner.BasicTestAsync(runFullTest));\n                }\n                await Task.WhenAll(tasks);\n                tasks.Clear();\n            }\n\n            foreach (var runner in runners)\n            {\n                tasks.Add(runner.StopProxies());\n            }\n            await Task.WhenAll(tasks);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/PlugableQueueBalancerTests/LeaseBasedQueueBalancer.cs",
    "content": "using Orleans.Streams;\n\nnamespace Tester.StreamingTests\n{\n    //Dumb queue balancer only acquire leases once, never renew it, just for testing\n    public class LeaseBasedQueueBalancerForTest : IStreamQueueBalancer\n    {\n        private readonly string id;\n        private readonly ILeaseManagerGrain leaseManagerGrain;\n        private List<QueueId> ownedQueues;\n\n        public LeaseBasedQueueBalancerForTest(string name, IGrainFactory grainFactory)\n        {\n            this.leaseManagerGrain = grainFactory.GetGrain<ILeaseManagerGrain>(name);\n            this.id = $\"{name}-{Guid.NewGuid()}\";\n        }\n\n        public async Task Initialize(IStreamQueueMapper queueMapper)\n        {\n            await this.leaseManagerGrain.SetQueuesAsLeases(queueMapper.GetAllQueues());\n            await GetInitialLease();\n        }\n\n        public Task Shutdown()\n        {\n            return Task.CompletedTask;\n        }\n\n        public IEnumerable<QueueId> GetMyQueues()\n        {\n            return this.ownedQueues;\n        }\n\n        private async Task GetInitialLease()\n        {\n            var responsibilty = await this.leaseManagerGrain.GetLeaseResposibility();\n            this.ownedQueues = new List<QueueId>(responsibilty);\n            for(int i = 0; i < responsibilty; i++)\n            {\n                try\n                {\n                    this.ownedQueues.Add(await this.leaseManagerGrain.Acquire());\n                }\n                catch (KeyNotFoundException)\n                { }   \n            }\n            await this.leaseManagerGrain.RecordBalancerResponsibility(id.ToString(), this.ownedQueues.Count);\n        }\n\n        public bool SubscribeToQueueDistributionChangeEvents(IStreamQueueBalanceListener observer)\n        {\n            //no op operation\n            return true;\n        }\n\n        public bool UnSubscribeFromQueueDistributionChangeEvents(IStreamQueueBalanceListener observer)\n        {\n            //no op operation\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/PlugableQueueBalancerTests/LeaseManagerGrain.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Tester.StreamingTests\n{\n    //one lease manager grain per stream provider, so its key is stream provider name\n    public interface ILeaseManagerGrain : IGrainWithStringKey\n    {\n        Task<QueueId> Acquire();\n        Task<bool> Renew(QueueId leaseNumber);\n        Task Release(QueueId leaseNumber);\n        Task<int> GetLeaseResposibility();\n        Task SetQueuesAsLeases(IEnumerable<QueueId> queues);\n        //methods used in test asserts\n        Task RecordBalancerResponsibility(string balancerId, int ownedQueues);\n        Task<Dictionary<string, int>> GetResponsibilityMap();\n\n    }\n\n    public class LeaseManagerGrain : Grain, ILeaseManagerGrain\n    {\n        //queueId is the lease id here\n        private static readonly DateTime UnAssignedLeaseTime = DateTime.MinValue;\n        private Dictionary<QueueId, DateTime> queueLeaseToRenewTimeMap;\n        private ISiloStatusOracle siloStatusOracle;\n        public override Task OnActivateAsync(CancellationToken cancellationToken)\n        {\n            this.siloStatusOracle = base.ServiceProvider.GetRequiredService<ISiloStatusOracle>();\n            this.queueLeaseToRenewTimeMap = new Dictionary<QueueId, DateTime>();\n            this.responsibilityMap = new Dictionary<string, int>();\n            return Task.CompletedTask;\n        }\n        public Task<int> GetLeaseResposibility()\n        {\n            var siloCount = this.siloStatusOracle.GetApproximateSiloStatuses(onlyActive: true).Count;\n            var resposibity = this.queueLeaseToRenewTimeMap.Count / siloCount;\n            return Task.FromResult(resposibity);\n        }\n\n        public Task<QueueId> Acquire()\n        {\n            foreach (var lease in this.queueLeaseToRenewTimeMap)\n            {\n                //find the first unassigned lease and assign it\n                if (lease.Value.Equals(UnAssignedLeaseTime))\n                {\n                    this.queueLeaseToRenewTimeMap[lease.Key] = DateTime.UtcNow;\n                    return Task.FromResult(lease.Key);\n                }\n            }\n            throw new KeyNotFoundException(\"No more lease to acquire\");\n        }\n\n        public Task<bool> Renew(QueueId leaseNumber)\n        {\n            if (this.queueLeaseToRenewTimeMap.ContainsKey(leaseNumber))\n            {\n                this.queueLeaseToRenewTimeMap[leaseNumber] = DateTime.UtcNow;\n                return Task.FromResult(true);\n            }\n            return Task.FromResult(false);\n        }\n\n        public Task Release(QueueId leaseNumber)\n        {\n            if (this.queueLeaseToRenewTimeMap.ContainsKey(leaseNumber))\n                this.queueLeaseToRenewTimeMap[leaseNumber] = UnAssignedLeaseTime;\n            return Task.CompletedTask;\n        }\n\n        public Task SetQueuesAsLeases(IEnumerable<QueueId> queueIds)\n        {\n            //if already set up, return\n            if (this.queueLeaseToRenewTimeMap.Count > 0)\n                return Task.CompletedTask;\n            //set up initial lease map\n            foreach (var queueId in queueIds)\n            {\n                this.queueLeaseToRenewTimeMap.Add(queueId, UnAssignedLeaseTime);\n            }\n            return Task.CompletedTask;\n        }\n\n        //methods used in test asserts\n        private Dictionary<string, int> responsibilityMap;\n        public Task RecordBalancerResponsibility(string balancerId, int ownedQueues)\n        {\n            responsibilityMap[balancerId] = ownedQueues;\n            return Task.CompletedTask;\n        }\n\n        public Task<Dictionary<string, int>> GetResponsibilityMap()\n        {\n            return Task.FromResult(responsibilityMap);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/PlugableQueueBalancerTests/PluggableQueueBalancerTestBase.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Xunit;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\n\nnamespace Tester.StreamingTests\n{\n    public class PluggableQueueBalancerTestBase : OrleansTestingBase\n    {\n        private readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n        private static readonly Type QueueBalancerType = typeof(LeaseBasedQueueBalancerForTest);\n\n        public virtual async Task ShouldUseInjectedQueueBalancerAndBalanceCorrectly(BaseTestClusterFixture fixture, string streamProviderName, int siloCount, int totalQueueCount)\n        {\n            var leaseManager = fixture.GrainFactory.GetGrain<ILeaseManagerGrain>(streamProviderName);\n            var expectedResponsibilityPerBalancer = totalQueueCount / siloCount;\n            await TestingUtils.WaitUntilAsync(lastTry => CheckLeases(leaseManager, siloCount, expectedResponsibilityPerBalancer, lastTry), Timeout);\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.ConfigureServices(services => services.AddTransient<LeaseBasedQueueBalancerForTest>());\n            }\n        }\n\n        private async Task<bool> CheckLeases(ILeaseManagerGrain leaseManager, int siloCount, int expectedResponsibilityPerBalancer, bool lastTry)\n        {\n            Dictionary<string,int> responsibilityMap = await leaseManager.GetResponsibilityMap();\n            if(lastTry)\n            {\n                //there should be one StreamQueueBalancer per silo\n                Assert.Equal(responsibilityMap.Count, siloCount);\n                foreach (int responsibility in responsibilityMap.Values)\n                {\n                    Assert.Equal(expectedResponsibilityPerBalancer, responsibility);\n                }\n            }\n            return (responsibilityMap.Count == siloCount)\n                && (responsibilityMap.Values.All(responsibility => expectedResponsibilityPerBalancer == responsibility));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/PlugableQueueBalancerTests/PluggableQueueBalancerTestsWithMemoryStreamProvider.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Tester.StreamingTests.PlugableQueueBalancerTests\n{\n    /// <summary>\n    /// Tests for pluggable queue balancer functionality using memory stream provider with lease-based queue balancing.\n    /// </summary>\n    public class PluggableQueueBalancerTestsWithMemoryStreamProvider : PluggableQueueBalancerTestBase, IClassFixture<PluggableQueueBalancerTestsWithMemoryStreamProvider.Fixture>\n    {\n        private const string StreamProviderName = \"MemoryStreamProvider\";\n        private static readonly int totalQueueCount = 6;\n        private static readonly short siloCount = 2;\n\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = siloCount;\n                builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"PubSubStore\")\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(\n                            StreamProviderName,\n                            b=>\n                            {\n                                b.ConfigurePartitioning(totalQueueCount);\n                                b.ConfigurePartitionBalancing((s, n) => ActivatorUtilities.CreateInstance<LeaseBasedQueueBalancerForTest>(s, n));\n                            });\n                        \n                }\n            }\n            \n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder\n                        .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName);\n                }\n            }\n\n        }\n\n        public PluggableQueueBalancerTestsWithMemoryStreamProvider(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact(Skip = \"https://github.com/dotnet/orleans/issues/4317\"), TestCategory(\"BVT\")]\n        public Task PluggableQueueBalancerTest_ShouldUseInjectedQueueBalancerAndBalanceCorrectly()\n        {\n            return base.ShouldUseInjectedQueueBalancerAndBalanceCorrectly(this.fixture, StreamProviderName, siloCount, totalQueueCount);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ProgrammaticSubscribeTests/ProgrammaticSubscribeTestsRunner.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Streams.Core;\nusing TestExtensions;\nusing Xunit;\nusing UnitTests.GrainInterfaces;\nusing Orleans.TestingHost.Utils;\nusing UnitTests.Grains.ProgrammaticSubscribe;\n\nnamespace Tester.StreamingTests\n{\n    public abstract class ProgrammaticSubscribeTestsRunner \n    {\n        private readonly BaseTestClusterFixture fixture;\n        public const string StreamProviderName = \"StreamProvider1\";\n        public const string StreamProviderName2 = \"StreamProvider2\";\n        public ProgrammaticSubscribeTestsRunner(BaseTestClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [SkippableFact]\n        public async Task Programmatic_Subscribe_Provider_WithExplicitPubsub_TryGetStreamSubscrptionManager()\n        {\n            var subGrain = this.fixture.HostedCluster.GrainFactory.GetGrain<ISubscribeGrain>(Guid.NewGuid());\n            Assert.True(await subGrain.CanGetSubscriptionManager(StreamProviderName));\n        }\n        \n        [SkippableFact]\n        public async Task Programmatic_Subscribe_CanUseNullNamespace()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), null, StreamProviderName);\n            await subscriptionManager.AddSubscription<IPassive_ConsumerGrain>(streamId,\n                Guid.NewGuid());\n            var subscriptions = await subscriptionManager.GetSubscriptions(streamId);\n            await subscriptionManager.RemoveSubscription(streamId, subscriptions.First().SubscriptionId);\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_Subscribe()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscription for 10 consumer grains\n            var subscriptions = await subscriptionManager.SetupStreamingSubscriptionForStream<IPassive_ConsumerGrain>(streamId, 10);\n            var consumers = subscriptions.Select(sub => this.fixture.HostedCluster.GrainFactory.GetGrain<IPassive_ConsumerGrain>(sub.GrainId)).ToList();\n\n            var producer = this.fixture.HostedCluster.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            await producer.StartPeriodicProducing();\n\n            int numProduced = 0;\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer, lastTry), _timeout);\n            await producer.StopPeriodicProducing();\n            \n            var tasks = new List<Task>();\n            foreach (var consumer in consumers)\n            {\n                tasks.Add(TestingUtils.WaitUntilAsync(lastTry => CheckCounters(new List<ITypedProducerGrain> { producer }, \n                    consumer, lastTry, this.fixture.Logger), _timeout));\n            }\n            await Task.WhenAll(tasks);\n\n            //clean up test\n            tasks.Clear();\n            tasks = consumers.Select(consumer => consumer.StopConsuming()).ToList();\n            await Task.WhenAll(tasks);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5635\")]\n        public async Task StreamingTests_Consumer_Producer_UnSubscribe()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscription for consumer grains\n            var subscriptions = await subscriptionManager.SetupStreamingSubscriptionForStream<IPassive_ConsumerGrain>(streamId, 2);\n\n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            await producer.StartPeriodicProducing();\n\n            int numProduced = 0;\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer, lastTry), _timeout);\n            //the subscription to remove\n            var subscription = subscriptions[0];\n            // remove subscription\n            await subscriptionManager.RemoveSubscription(streamId, subscription.SubscriptionId);\n            var numProducedWhenUnSub = await producer.GetNumberProduced();\n            var consumerUnSub = this.fixture.GrainFactory.GetGrain<IPassive_ConsumerGrain>(subscription.GrainId);\n            var consumerNormal = this.fixture.GrainFactory.GetGrain<IPassive_ConsumerGrain>(subscriptions[1].GrainId);\n            //assert consumer grain's onAdd func got called.\n            Assert.True((await consumerUnSub.GetCountOfOnAddFuncCalled()) > 0);\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProducedWhenUnSub, producer, lastTry), _timeout);\n            await producer.StopPeriodicProducing();\n\n            //wait for consumers to finish consuming\n            await Task.Delay(TimeSpan.FromMilliseconds(2000));\n\n            //assert normal consumer consumed equal to produced\n            await TestingUtils.WaitUntilAsync(\n            lastTry =>CheckCounters(new List<ITypedProducerGrain> { producer }, consumerNormal, lastTry, this.fixture.Logger), _timeout);\n\n            //asert unsubscribed consumer consumed less than produced\n            numProduced = await producer.GetNumberProduced();\n            var numConsumed = await consumerUnSub.GetNumberConsumed();\n            Assert.True(numConsumed <= numProducedWhenUnSub);\n            Assert.True(numConsumed < numProduced);\n\n            // clean up test\n            await consumerNormal.StopConsuming();\n            await consumerUnSub.StopConsuming();\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_GetSubscriptions()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscriptions\n            var expectedSubscriptions = await subscriptionManager.SetupStreamingSubscriptionForStream<IPassive_ConsumerGrain>(streamId, 2);\n            var expectedSubscriptionIds = expectedSubscriptions.Select(sub => sub.SubscriptionId).ToSet();\n            var subscriptions = await subscriptionManager.GetSubscriptions(streamId);\n            var subscriptionIds = subscriptions.Select(sub => sub.SubscriptionId).ToSet();\n            Assert.True(expectedSubscriptionIds.SetEquals(subscriptionIds));\n\n             //remove one subscription\n            await subscriptionManager.RemoveSubscription(streamId, expectedSubscriptions[0].SubscriptionId);\n            expectedSubscriptions = expectedSubscriptions.GetRange(1, 1);\n            subscriptions = await subscriptionManager.GetSubscriptions(streamId);\n            expectedSubscriptionIds = expectedSubscriptions.Select(sub => sub.SubscriptionId).ToSet();\n            subscriptionIds = subscriptions.Select(sub => sub.SubscriptionId).ToSet();\n            Assert.True(expectedSubscriptionIds.SetEquals(subscriptionIds));\n\n            // clean up tests\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_ConsumerUnsubscribeOnAdd()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscriptions\n            await subscriptionManager.SetupStreamingSubscriptionForStream<IJerk_ConsumerGrain>(streamId, 10);\n            //producer start producing \n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingInt>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            await producer.StartPeriodicProducing();\n\n            int numProduced = 0;\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer, lastTry), _timeout);\n            await producer.StopPeriodicProducing();\n            //wait for consumers to react\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n\n            //get subscription count now, should be all removed/unsubscribed \n            var subscriptions = await subscriptionManager.GetSubscriptions(streamId);\n            Assert.True( subscriptions.Count<Orleans.Streams.Core.StreamSubscription>()== 0);\n            // clean up tests\n        }\n\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5650\")]\n        public async Task StreamingTests_Consumer_Producer_SubscribeToTwoStream_MessageWithPolymorphism()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscription for 10 consumer grains\n            var subscriptions = await subscriptionManager.SetupStreamingSubscriptionForStream<IPassive_ConsumerGrain>(streamId, 10);\n            var consumers = subscriptions.Select(sub => this.fixture.GrainFactory.GetGrain<IPassive_ConsumerGrain>(sub.GrainId)).ToList();\n\n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            await producer.StartPeriodicProducing();\n\n            int numProduced = 0;\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer, lastTry), _timeout);\n            // set up the new stream to subscribe, which produce strings\n            var streamId2 = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace2\", StreamProviderName);\n            var producer2 = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer2.BecomeProducer(streamId2.Guid, streamId2.Namespace, streamId2.ProviderName);\n\n            //register the consumer grain to second stream\n            var tasks = consumers.Select(consumer => subscriptionManager.AddSubscription<IPassive_ConsumerGrain>(streamId2, consumer.GetPrimaryKey())).ToList();\n            await Task.WhenAll(tasks);\n\n            await producer2.StartPeriodicProducing();\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer2, lastTry), _timeout);\n            await producer.StopPeriodicProducing();\n            await producer2.StopPeriodicProducing();\n\n            var tasks2 = new List<Task>();\n            foreach (var consumer in consumers)\n            {\n                tasks2.Add(TestingUtils.WaitUntilAsync(lastTry => CheckCounters(new List<ITypedProducerGrain> { producer, producer2 },\n                    consumer, lastTry, this.fixture.Logger), _timeout));\n            }\n            await Task.WhenAll(tasks);\n\n            //clean up test\n            tasks2.Clear();\n            tasks2 = consumers.Select(consumer => consumer.StopConsuming()).ToList();\n            await Task.WhenAll(tasks2);\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_SubscribeToStreamsHandledByDifferentStreamProvider()\n        {\n            var subscriptionManager = new SubscriptionManager(this.fixture.HostedCluster);\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace\", StreamProviderName);\n            //set up subscription for 10 consumer grains\n            var subscriptions = await subscriptionManager.SetupStreamingSubscriptionForStream<IPassive_ConsumerGrain>(streamId, 10);\n            var consumers = subscriptions.Select(sub => this.fixture.GrainFactory.GetGrain<IPassive_ConsumerGrain>(sub.GrainId)).ToList();\n\n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            await producer.StartPeriodicProducing();\n\n            int numProduced = 0;\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer, lastTry), _timeout);\n            // set up the new stream to subscribe, which produce strings\n            var streamId2 = new FullStreamIdentity(Guid.NewGuid(), \"EmptySpace2\", StreamProviderName2);\n            var producer2 = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer2.BecomeProducer(streamId2.Guid, streamId2.Namespace, streamId2.ProviderName);\n\n            //register the consumer grain to second stream\n            var tasks = consumers.Select(consumer => subscriptionManager.AddSubscription<IPassive_ConsumerGrain>(streamId2, consumer.GetPrimaryKey())).ToList();\n            await Task.WhenAll(tasks);\n\n            await producer2.StartPeriodicProducing();\n            await TestingUtils.WaitUntilAsync(lastTry => ProducerHasProducedSinceLastCheck(numProduced, producer2, lastTry), _timeout);\n            await producer.StopPeriodicProducing();\n            await producer2.StopPeriodicProducing();\n\n            var tasks2 = new List<Task>();\n            foreach (var consumer in consumers)\n            {\n                tasks2.Add(TestingUtils.WaitUntilAsync(lastTry => CheckCounters(new List<ITypedProducerGrain> { producer, producer2 },\n                    consumer, lastTry, this.fixture.Logger), _timeout));\n            }\n            await Task.WhenAll(tasks);\n\n            //clean up test\n            tasks2.Clear();\n            tasks2 = consumers.Select(consumer => consumer.StopConsuming()).ToList();\n            await Task.WhenAll(tasks2);\n        }\n\n        //test utilities and statics\n        private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30);\n       \n        public static async Task<bool> ProducerHasProducedSinceLastCheck(int numProducedLastTime, ITypedProducerGrain producer, bool assertIsTrue)\n        {\n            var numProduced = await producer.GetNumberProduced();\n            if (assertIsTrue)\n            {\n                throw new OrleansException($\"Producer has not produced since last check\");\n            }\n            else\n            {\n                return numProduced > numProducedLastTime;\n            }\n        }\n\n        public static async Task<bool> CheckCounters(List<ITypedProducerGrain> producers, IPassive_ConsumerGrain consumer, bool assertIsTrue, ILogger logger)\n        {\n            int numProduced = 0;\n            foreach (var p in producers)\n            {\n                numProduced += await p.GetNumberProduced();\n            }\n            var numConsumed = await consumer.GetNumberConsumed();\n            logger.LogInformation(\"CheckCounters: numProduced = {ProducedCount}, numConsumed = {ConsumedCount}\", numProduced, numConsumed);\n            if (assertIsTrue)\n            {\n                Assert.Equal(numProduced, numConsumed);\n                return true;\n            }\n            else\n            {\n                return numProduced == numConsumed;\n            }\n        }\n    }\n\n    public class SubscriptionManager\n    {\n        private readonly IGrainFactory grainFactory;\n        private readonly IServiceProvider serviceProvider;\n        private readonly IStreamSubscriptionManager subManager;\n        public SubscriptionManager(TestCluster cluster)\n        {\n            this.grainFactory = cluster.GrainFactory;\n            this.serviceProvider = cluster.ServiceProvider;\n            var admin = serviceProvider.GetRequiredService<IStreamSubscriptionManagerAdmin>();\n            this.subManager = admin.GetStreamSubscriptionManager(StreamSubscriptionManagerType.ExplicitSubscribeOnly);\n        }\n\n        public async Task<List<StreamSubscription>> SetupStreamingSubscriptionForStream<TGrainInterface>(FullStreamIdentity streamIdentity, int grainCount)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            var subscriptions = new List<StreamSubscription>();\n            while (grainCount > 0)\n            {\n                var grainId = Guid.NewGuid();\n                var grainRef = this.grainFactory.GetGrain<TGrainInterface>(grainId) as GrainReference;\n                subscriptions.Add(await subManager.AddSubscription(streamIdentity.ProviderName, streamIdentity, grainRef));\n                grainCount--;\n            }\n            return subscriptions;\n        }\n\n        public async Task<StreamSubscription> AddSubscription<TGrainInterface>(FullStreamIdentity streamId, Guid grainId)\n            where TGrainInterface : IGrainWithGuidKey\n        {\n            var grainRef = this.grainFactory.GetGrain<TGrainInterface>(grainId) as GrainReference;\n            var sub = await this.subManager\n                .AddSubscription(streamId.ProviderName, streamId, grainRef);\n            return sub;\n        }\n\n        public Task<IEnumerable<StreamSubscription>> GetSubscriptions(FullStreamIdentity streamIdentity)\n        {\n            return subManager.GetSubscriptions(streamIdentity.ProviderName, streamIdentity);\n        }\n\n        public async Task RemoveSubscription(FullStreamIdentity streamId, Guid subscriptionId)\n        {\n            await subManager.RemoveSubscription(streamId.ProviderName, streamId, subscriptionId);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/ProgrammaticSubscribeTests/SubscriptionObserverWithImplicitSubscribingTestRunner.cs",
    "content": "using Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing UnitTests.Grains.ProgrammaticSubscribe;\nusing Xunit;\n\nnamespace Tester.StreamingTests.ProgrammaticSubscribeTests\n{\n    public abstract class SubscriptionObserverWithImplicitSubscribingTestRunner : OrleansTestingBase\n    {\n        private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30);\n        //test utilities and statics\n        public static string StreamProviderName = \"StreamProvider1\";\n        public static string StreamProviderName2 = \"StreamProvider2\";\n        private readonly BaseTestClusterFixture fixture;\n        public SubscriptionObserverWithImplicitSubscribingTestRunner(BaseTestClusterFixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_ImplicitSubscribProvider_DontHaveSubscriptionManager()\n        {\n            var subGrain = this.fixture.GrainFactory.GetGrain<ISubscribeGrain>(Guid.NewGuid());\n            Assert.False(await subGrain.CanGetSubscriptionManager(StreamProviderName));\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_Subscribe()\n        {\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), ImplicitSubscribeGrain.StreamNameSpace, StreamProviderName);\n            var producer = this.fixture.HostedCluster.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            for (var i = 0; i< 10; i++)\n            {\n                await producer.Produce();\n            }\n\n            var implicitConsumer = this.fixture.HostedCluster.GrainFactory.GetGrain<IImplicitSubscribeGrain>(streamId.Guid);\n\n            await TestingUtils.WaitUntilAsync(lastTry => ProgrammaticSubscribeTestsRunner.CheckCounters(new List<ITypedProducerGrain> { producer },\n                    implicitConsumer, lastTry, this.fixture.Logger), _timeout);\n\n            //clean up test\n            await implicitConsumer.StopConsuming();\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_SubscribeToTwoStream_MessageWithPolymorphism()\n        {\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), ImplicitSubscribeGrain.StreamNameSpace, StreamProviderName);\n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            // set up the new stream with the same guid, but different namespace, so it would invoke the same consumer grain\n            var streamId2 = new FullStreamIdentity(streamId.Guid, ImplicitSubscribeGrain.StreamNameSpace2, StreamProviderName);\n            var producer2 = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer2.BecomeProducer(streamId2.Guid, streamId2.Namespace, streamId2.ProviderName);\n\n            // Produce 10 events in streamId, 8 on streamId2\n            for (var i = 0; i < 10; i++)\n            {\n                await producer.Produce();\n                if (i < 8)\n                {\n                    await producer2.Produce();\n                }\n            }\n\n            var implicitConsumer = this.fixture.HostedCluster.GrainFactory.GetGrain<IImplicitSubscribeGrain>(streamId.Guid);\n            await TestingUtils.WaitUntilAsync(lastTry => ProgrammaticSubscribeTestsRunner.CheckCounters(new List<ITypedProducerGrain> { producer, producer2 },\n                implicitConsumer, lastTry, this.fixture.Logger), _timeout);\n\n            //clean up test\n            await implicitConsumer.StopConsuming();\n        }\n\n        [SkippableFact]\n        public async Task StreamingTests_Consumer_Producer_SubscribeToStreamsHandledByDifferentStreamProvider()\n        {\n            var streamId = new FullStreamIdentity(Guid.NewGuid(), ImplicitSubscribeGrain.StreamNameSpace, StreamProviderName);\n\n            var producer = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId.Guid, streamId.Namespace, streamId.ProviderName);\n\n            // set up the new stream with the same guid, but different namespace, so it would invoke the same consumer grain\n            var streamId2 = new FullStreamIdentity(streamId.Guid, ImplicitSubscribeGrain.StreamNameSpace2, StreamProviderName2);\n            var producer2 = this.fixture.GrainFactory.GetGrain<ITypedProducerGrainProducingApple>(Guid.NewGuid());\n            await producer2.BecomeProducer(streamId2.Guid, streamId2.Namespace, streamId2.ProviderName);\n\n            // Produce 10 events in streamId, 8 on streamId2\n            for (var i = 0; i < 10; i++)\n            {\n                await producer.Produce();\n                if (i < 8)\n                {\n                    await producer2.Produce();\n                }\n            }\n\n            var implicitConsumer =\n                this.fixture.HostedCluster.GrainFactory.GetGrain<IImplicitSubscribeGrain>(streamId.Guid);\n            await TestingUtils.WaitUntilAsync(lastTry => ProgrammaticSubscribeTestsRunner.CheckCounters(new List<ITypedProducerGrain> { producer, producer2 },\n                implicitConsumer, lastTry, this.fixture.Logger), _timeout);\n\n            //clean up test\n            await implicitConsumer.StopConsuming();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/PubSubRendezvousGrainTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    public class PubSubRendezvousGrainTests : OrleansTestingBase, IClassFixture<PubSubRendezvousGrainTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n               builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n            }\n\n            public class SiloHostConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddFaultInjectionMemoryStorage(\"PubSubStore\")\n                        .Services.AddSiloStreaming();\n                }\n            }\n        }\n\n        public PubSubRendezvousGrainTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task RegisterConsumerFaultTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ RegisterConsumerFaultTest *********************************\");\n            var streamId = new QualifiedStreamId(\"ProviderName\", StreamId.Create(\"StreamNamespace\", Guid.NewGuid()));\n            var pubSubGrain = this.fixture.GrainFactory.GetGrain<IPubSubRendezvousGrain>(streamId.ToString());\n            var faultGrain = this.fixture.GrainFactory.GetGrain<IStorageFaultGrain>(nameof(PubSubRendezvousGrain));\n\n            // clean call, to make sure everything is happy and pubsub has state.\n            await pubSubGrain.RegisterConsumer(GuidId.GetGuidId(Guid.NewGuid()), streamId, default, null);\n            int consumers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(1, consumers);\n\n            // inject fault\n            await faultGrain.AddFaultOnWrite(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when registering a new consumer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.RegisterConsumer(GuidId.GetGuidId(Guid.NewGuid()), streamId, default, null));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.RegisterConsumer(GuidId.GetGuidId(Guid.NewGuid()), streamId, default, null);\n            consumers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(2, consumers);\n        }\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task UnregisterConsumerFaultTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ UnregisterConsumerFaultTest *********************************\");\n            var streamId = new QualifiedStreamId(\"ProviderName\", StreamId.Create(\"StreamNamespace\", Guid.NewGuid()));\n            var pubSubGrain = this.fixture.GrainFactory.GetGrain<IPubSubRendezvousGrain>(streamId.ToString());\n            var faultGrain = this.fixture.GrainFactory.GetGrain<IStorageFaultGrain>(nameof(PubSubRendezvousGrain));\n\n            // Add two consumers so when we remove the first it does a storage write, not a storage clear.\n            GuidId subscriptionId1 = GuidId.GetGuidId(Guid.NewGuid());\n            GuidId subscriptionId2 = GuidId.GetGuidId(Guid.NewGuid());\n            await pubSubGrain.RegisterConsumer(subscriptionId1, streamId, default, null);\n            await pubSubGrain.RegisterConsumer(subscriptionId2, streamId, default, null);\n            int consumers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(2, consumers);\n\n            // inject fault\n            await faultGrain.AddFaultOnWrite(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when unregistering a consumer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.UnregisterConsumer(subscriptionId1, streamId));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.UnregisterConsumer(subscriptionId1, streamId);\n            consumers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(1, consumers);\n\n            // inject clear fault, because removing last consumer should trigger a clear storage call.\n            await faultGrain.AddFaultOnClear(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when unregistering a consumer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.UnregisterConsumer(subscriptionId2, streamId));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.UnregisterConsumer(subscriptionId2, streamId);\n            consumers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(0, consumers);\n        }\n\n        /// <summary>\n        /// This test fails because the producer must be grain reference which is not implied by the IStreamProducerExtension in the producer management calls.\n        /// TODO: Fix rendezvous implementation.\n        /// </summary>\n        /// <returns></returns>\n        [Fact(Skip = \"This test fails because the producer must be grain reference which is not implied by the IStreamProducerExtension\"), TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task RegisterProducerFaultTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ RegisterProducerFaultTest *********************************\");\n            var streamId = new QualifiedStreamId(\"ProviderName\", StreamId.Create(\"StreamNamespace\", Guid.NewGuid()));\n            var pubSubGrain = this.fixture.GrainFactory.GetGrain<IPubSubRendezvousGrain>(streamId.ToString());\n            var faultGrain = this.fixture.GrainFactory.GetGrain<IStorageFaultGrain>(nameof(PubSubRendezvousGrain));\n\n            // clean call, to make sure everything is happy and pubsub has state.\n            await pubSubGrain.RegisterProducer(streamId, default);\n            int producers = await pubSubGrain.ProducerCount(streamId);\n            Assert.Equal(1, producers);\n\n            // inject fault\n            await faultGrain.AddFaultOnWrite(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when registering a new producer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.RegisterProducer(streamId, default));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.RegisterProducer(streamId, default);\n            producers = await pubSubGrain.ProducerCount(streamId);\n            Assert.Equal(2, producers);\n        }\n\n        /// <summary>\n        /// This test fails because the producer must be grain reference which is not implied by the IStreamProducerExtension in the producer management calls.\n        /// TODO: Fix rendezvous implementation.\n        /// </summary>\n        [Fact(Skip = \"This test fails because the producer must be grain reference which is not implied by the IStreamProducerExtension\"), TestCategory(\"BVT\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task UnregisterProducerFaultTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ UnregisterProducerFaultTest *********************************\");\n            var streamId = new QualifiedStreamId(\"ProviderName\", StreamId.Create(\"StreamNamespace\", Guid.NewGuid()));\n            var pubSubGrain = this.fixture.GrainFactory.GetGrain<IPubSubRendezvousGrain>(streamId.ToString());\n            var faultGrain = this.fixture.GrainFactory.GetGrain<IStorageFaultGrain>(nameof(PubSubRendezvousGrain));\n\n            IStreamProducerExtension firstProducer = new DummyStreamProducerExtension();\n            IStreamProducerExtension secondProducer = new DummyStreamProducerExtension();\n            // Add two producers so when we remove the first it does a storage write, not a storage clear.\n            await pubSubGrain.RegisterProducer(streamId, firstProducer.GetGrainId());\n            await pubSubGrain.RegisterProducer(streamId, secondProducer.GetGrainId());\n            int producers = await pubSubGrain.ProducerCount(streamId);\n            Assert.Equal(2, producers);\n\n            // inject fault\n            await faultGrain.AddFaultOnWrite(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when unregistering a producer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.UnregisterProducer(streamId, firstProducer.GetGrainId()));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.UnregisterProducer(streamId, firstProducer.GetGrainId());\n            producers = await pubSubGrain.ProducerCount(streamId);\n            Assert.Equal(1, producers);\n\n            // inject clear fault, because removing last producers should trigger a clear storage call.\n            await faultGrain.AddFaultOnClear(pubSubGrain.GetGrainId(), new ApplicationException(\"Write\"));\n\n            // expect exception when unregistering a consumer\n            await Assert.ThrowsAsync<OrleansException>(\n                    () => pubSubGrain.UnregisterProducer(streamId, secondProducer.GetGrainId()));\n\n            // pubsub grain should recover and still function\n            await pubSubGrain.UnregisterProducer(streamId, secondProducer.GetGrainId());\n            producers = await pubSubGrain.ConsumerCount(streamId);\n            Assert.Equal(0, producers);\n        }\n\n        [Serializable]\n        [Orleans.GenerateSerializer]\n        public class DummyStreamProducerExtension : IStreamProducerExtension\n        {\n            [Orleans.Id(0)]\n            private readonly Guid id;\n\n            public DummyStreamProducerExtension()\n            {\n                id = Guid.NewGuid();\n            }\n\n            public Task AddSubscriber(GuidId subscriptionId, QualifiedStreamId streamId, GrainId streamConsumer, string filterData)\n            {\n                return Task.CompletedTask;\n            }\n\n            public Task RemoveSubscriber(GuidId subscriptionId, QualifiedStreamId streamId)\n            {\n                return Task.CompletedTask;\n            }\n\n            public override bool Equals(object obj)\n            {\n                if (ReferenceEquals(null, obj)) return false;\n                if (ReferenceEquals(this, obj)) return true;\n                if (obj.GetType() != GetType()) return false;\n                return Equals((DummyStreamProducerExtension)obj);\n            }\n\n            public override int GetHashCode()\n            {\n                return id.GetHashCode();\n            }\n\n            private bool Equals(DummyStreamProducerExtension other)\n            {\n                return id.Equals(other.id);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/SampleStreamingTests.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Sample streaming tests demonstrating basic producer-consumer patterns in Orleans Streaming.\n    /// \n    /// These tests showcase fundamental streaming scenarios:\n    /// - Producer and consumer grain communication via streams\n    /// - Different subscription ordering (consumer-first vs producer-first)\n    /// - Inline vs async consumer processing\n    /// - Message delivery guarantees and counting\n    /// \n    /// These patterns form the foundation for more complex streaming applications\n    /// like real-time analytics, event processing, and pub-sub systems.\n    /// </summary>\n    public class SampleStreamingTests\n    {\n        private const string StreamNamespace = \"SampleStreamNamespace\";\n        private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30);\n\n        private readonly string streamProvider;\n        private readonly ILogger logger;\n        private readonly TestCluster cluster;\n\n        public SampleStreamingTests(string streamProvider, ILogger logger, TestCluster cluster)\n        {\n            this.streamProvider = streamProvider;\n            this.logger = logger;\n            this.cluster = cluster;\n        }\n\n        /// <summary>\n        /// Tests the scenario where a consumer subscribes before the producer starts.\n        /// This verifies that:\n        /// - Consumers can subscribe to streams that don't yet have producers\n        /// - Messages are delivered once the producer starts\n        /// - No messages are lost in the handoff\n        /// </summary>\n        public async Task StreamingTests_Consumer_Producer(Guid streamId)\n        {\n            // consumer joins first, producer later\n            var consumer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_ConsumerGrain>(Guid.NewGuid());\n            await consumer.BecomeConsumer(streamId, StreamNamespace, streamProvider);\n\n            var producer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId, StreamNamespace, streamProvider);\n\n            await producer.StartPeriodicProducing();\n\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, lastTry), _timeout);\n\n            await consumer.StopConsuming();\n        }\n\n        /// <summary>\n        /// Tests the scenario where a producer starts before any consumers subscribe.\n        /// This verifies that:\n        /// - Producers can send to streams without active consumers\n        /// - Late-joining consumers receive messages (depending on provider)\n        /// - The system handles dynamic subscription scenarios\n        /// </summary>\n        public async Task StreamingTests_Producer_Consumer(Guid streamId)\n        {\n            // producer joins first, consumer later\n            var producer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId, StreamNamespace, streamProvider);\n\n            var consumer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_ConsumerGrain>(Guid.NewGuid());\n            await consumer.BecomeConsumer(streamId, StreamNamespace, streamProvider);\n\n            await producer.StartPeriodicProducing();\n\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n\n            await producer.StopPeriodicProducing();\n            //int numProduced = await producer.NumberProduced;\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, lastTry), _timeout);\n\n            await consumer.StopConsuming();\n        }\n\n        /// <summary>\n        /// Tests streaming with an inline consumer that processes messages synchronously.\n        /// Inline consumers:\n        /// - Process messages in the same task context as delivery\n        /// - Can provide lower latency but may impact throughput\n        /// - Are useful for simple, fast message processing\n        /// </summary>\n        public async Task StreamingTests_Producer_InlineConsumer(Guid streamId)\n        {\n            // producer joins first, consumer later\n            var producer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(streamId, StreamNamespace, streamProvider);\n\n            var consumer = this.cluster.GrainFactory.GetGrain<ISampleStreaming_InlineConsumerGrain>(Guid.NewGuid());\n            await consumer.BecomeConsumer(streamId, StreamNamespace, streamProvider);\n\n            await producer.StartPeriodicProducing();\n\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n\n            await producer.StopPeriodicProducing();\n            //int numProduced = await producer.NumberProduced;\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, lastTry), _timeout);\n\n            await consumer.StopConsuming();\n        }\n\n        /// <summary>\n        /// Verifies that all produced messages were consumed.\n        /// This is a key validation for streaming tests to ensure:\n        /// - No messages were lost\n        /// - No duplicate deliveries occurred\n        /// - Producer and consumer are properly synchronized\n        /// </summary>\n        private async Task<bool> CheckCounters(ISampleStreaming_ProducerGrain producer, ISampleStreaming_ConsumerGrain consumer, bool assertIsTrue)\n        {\n            var numProduced = await producer.GetNumberProduced();\n            var numConsumed = await consumer.GetNumberConsumed();\n            this.logger.LogInformation(\"CheckCounters: numProduced = {ProducedCount}, numConsumed = {ConsumedCount}\", numProduced, numConsumed);\n            if (assertIsTrue)\n            {\n                Assert.Equal(numProduced, numConsumed);\n                return true;\n            }\n            else\n            {\n                return numProduced == numConsumed;\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/SingleStreamTestRunner.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost.Utils;\nusing Tester;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    public class SingleStreamTestRunner\n    {\n        public const string SMS_STREAM_PROVIDER_NAME = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n        public const string SMS_STREAM_PROVIDER_NAME_DO_NOT_OPTIMIZE_FOR_IMMUTABLE_DATA = \"SMSProviderDoNotOptimizeForImmutableData\";\n        public const string AQ_STREAM_PROVIDER_NAME = StreamTestsConstants.AZURE_QUEUE_STREAM_PROVIDER_NAME;\n        private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30);\n\n        private ProducerProxy producer;\n        private ConsumerProxy consumer;\n        private const int Many = 3;\n        private const int ItemCount = 10;\n        private readonly ILogger logger;\n        private readonly string streamProviderName;\n        private readonly int testNumber;\n        private readonly bool runFullTest;\n        private readonly IInternalClusterClient client;\n\n        internal SingleStreamTestRunner(IInternalClusterClient client, string streamProvider, int testNum = 0, bool fullTest = true)\n        {\n            this.client = client;\n            this.streamProviderName = streamProvider;\n            this.logger = TestingUtils.CreateDefaultLoggerFactory($\"{this.GetType().Name}.log\").CreateLogger<SingleStreamTestRunner>();\n            this.testNumber = testNum;\n            this.runFullTest = fullTest;\n        }\n\n        private void Heading(string testName)\n        {\n            logger.LogInformation(\"\\n\\n************************ {TestNumber} {StreamProviderName}_{TestName} ********************************* \\n\\n\", testNumber, streamProviderName, testName);\n        }\n\n        //------------------------ One to One ----------------------//\n        public async Task StreamTest_01_OneProducerGrainOneConsumerGrain()\n        {\n            Heading(\"StreamTest_01_ConsumerJoinsFirstProducerLater\");\n            Guid streamId = Guid.NewGuid();\n            // consumer joins first, producer later\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n\n            streamId = Guid.NewGuid();\n            // produce joins first, consumer later\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_02_OneProducerGrainOneConsumerClient()\n        {\n            Heading(\"StreamTest_02_OneProducerGrainOneConsumerClient\");\n            Guid streamId = Guid.NewGuid();\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n\n            streamId = Guid.NewGuid();\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_03_OneProducerClientOneConsumerGrain()\n        {\n            Heading(\"StreamTest_03_OneProducerClientOneConsumerGrain\");\n            Guid streamId = Guid.NewGuid();\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client);\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n\n            streamId = Guid.NewGuid();\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client);\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_04_OneProducerClientOneConsumerClient()\n        {\n            Heading(\"StreamTest_04_OneProducerClientOneConsumerClient\");\n            Guid streamId = Guid.NewGuid();\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client);\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n\n            streamId = Guid.NewGuid();\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client);\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        //------------------------ MANY to Many different grains ----------------------//\n\n        public async Task StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains()\n        {\n            Heading(\"StreamTest_05_ManyDifferent_ManyProducerGrainsManyConsumerGrains\");\n            Guid streamId = Guid.NewGuid();\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, null, Many);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, null, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients()\n        {\n            Heading(\"StreamTest_06_ManyDifferent_ManyProducerGrainManyConsumerClients\");\n            Guid streamId = Guid.NewGuid();\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client, Many);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, null, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains()\n        {\n            Heading(\"StreamTest_07_ManyDifferent_ManyProducerClientsManyConsumerGrains\");\n            Guid streamId = Guid.NewGuid();\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, null, Many);\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients()\n        {\n            Heading(\"StreamTest_08_ManyDifferent_ManyProducerClientsManyConsumerClients\");\n            Guid streamId = Guid.NewGuid();\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client, Many);\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        //------------------------ MANY to Many Same grains ----------------------//\n\n        public async Task StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains()\n        {\n            Heading(\"StreamTest_09_ManySame_ManyProducerGrainsManyConsumerGrains\");\n            Guid streamId = Guid.NewGuid();\n            Guid grain1 = Guid.NewGuid();\n            Guid grain2 = Guid.NewGuid();\n            Guid[] consumerGrainIds = new Guid[] { grain1, grain1, grain1 };\n            Guid[] producerGrainIds = new Guid[] { grain2, grain2, grain2 };\n            // producer joins first, consumer later\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, producerGrainIds);\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, consumerGrainIds);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains()\n        {\n            Heading(\"StreamTest_10_ManySame_ManyConsumerGrainsManyProducerGrains\");\n            Guid streamId = Guid.NewGuid();\n            Guid grain1 = Guid.NewGuid();\n            Guid grain2 = Guid.NewGuid();\n            Guid[] consumerGrainIds = new Guid[] { grain1, grain1, grain1 };\n            Guid[] producerGrainIds = new Guid[] { grain2, grain2, grain2 };\n            // consumer joins first, producer later\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, consumerGrainIds);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, producerGrainIds);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients()\n        {\n            Heading(\"StreamTest_11_ManySame_ManyProducerGrainsManyConsumerClients\");\n            Guid streamId = Guid.NewGuid();\n            Guid grain1 = Guid.NewGuid();\n            Guid[] producerGrainIds = new Guid[] { grain1, grain1, grain1, grain1 };\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, producerGrainIds);\n            consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, this.client, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains()\n        {\n            Heading(\"StreamTest_12_ManySame_ManyProducerClientsManyConsumerGrains\");\n            Guid streamId = Guid.NewGuid();\n            Guid grain1 = Guid.NewGuid();\n            Guid[] consumerGrainIds = new Guid[] { grain1, grain1, grain1 };\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, consumerGrainIds);\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, null, logger, this.client, Many);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        //------------------------ MANY to Many producer consumer same grain ----------------------//\n\n        public async Task StreamTest_13_SameGrain_ConsumerFirstProducerLater(bool useReentrantGrain)\n        {\n            Heading(\"StreamTest_13_SameGrain_ConsumerFirstProducerLater\");\n            Guid streamId = Guid.NewGuid();\n            int grain1 = Random.Shared.Next();\n            int[] grainIds = new int[] { grain1 };\n            // consumer joins first, producer later\n            this.consumer = await ConsumerProxy.NewProducerConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, grainIds, useReentrantGrain, this.client);\n            this.producer = await ProducerProxy.NewProducerConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, grainIds, useReentrantGrain, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        public async Task StreamTest_14_SameGrain_ProducerFirstConsumerLater(bool useReentrantGrain)\n        {\n            Heading(\"StreamTest_14_SameGrain_ProducerFirstConsumerLater\");\n            Guid streamId = Guid.NewGuid();\n            int grain1 = Random.Shared.Next();\n            int[] grainIds = new int[] { grain1 };\n            // produce joins first, consumer later\n            this.producer = await ProducerProxy.NewProducerConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, grainIds, useReentrantGrain, this.client);\n            this.consumer = await ConsumerProxy.NewProducerConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, grainIds, useReentrantGrain, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        //----------------------------------------------//\n\n        public async Task StreamTest_15_ConsumeAtProducersRequest()\n        {\n            Heading(\"StreamTest_15_ConsumeAtProducersRequest\");\n            Guid streamId = Guid.NewGuid();\n            // this reproduces a scenario was discovered to not work (deadlock) by the Halo team. the scenario is that\n            // where a producer calls a consumer, which subscribes to the calling producer.\n\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n            Guid consumerGrainId = await producer.AddNewConsumerGrain();\n\n            this.consumer = ConsumerProxy.NewConsumerGrainAsync_WithoutBecomeConsumer(consumerGrainId, this.logger, this.client);\n            await BasicTestAsync();\n            await StopProxies();\n        }\n\n        internal async Task StreamTest_Create_OneProducerGrainOneConsumerGrain()\n        {\n            Guid streamId = Guid.NewGuid();\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client);\n        }\n\n        public async Task StreamTest_16_Deactivation_OneProducerGrainOneConsumerGrain()\n        {\n            Heading(\"StreamTest_16_Deactivation_OneProducerGrainOneConsumerGrain\");\n            Guid streamId = Guid.NewGuid();\n            Guid[] consumerGrainIds = { Guid.NewGuid() };\n            Guid[] producerGrainIds = { Guid.NewGuid() };\n\n            // consumer joins first, producer later\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, consumerGrainIds);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, producerGrainIds);\n            await BasicTestAsync(false);\n            //await consumer.StopBeingConsumer();\n            await StopProxies();\n\n            await consumer.DeactivateOnIdle();\n            await producer.DeactivateOnIdle();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckGrainsDeactivated(null, consumer, false), _timeout);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckGrainsDeactivated(producer, null, false), _timeout);\n\n            logger.LogInformation(\"\\n\\n\\n*******************************************************************\\n\\n\\n\");\n\n            this.consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, this.streamProviderName, this.logger, this.client, consumerGrainIds);\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamId, this.streamProviderName, null, this.logger, this.client, producerGrainIds);\n\n            await BasicTestAsync(false);\n            await StopProxies();\n        }\n\n        //public async Task StreamTest_17_Persistence_OneProducerGrainOneConsumerGrain()\n        //{\n        //    Heading(\"StreamTest_17_Persistence_OneProducerGrainOneConsumerGrain\");\n        //    StreamId streamId = StreamId.NewRandomStreamId();\n        //    // consumer joins first, producer later\n        //    consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n        //    producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n        //    await BasicTestAsync(false);\n\n        //    await consumer.DeactivateOnIdle();\n        //    await producer.DeactivateOnIdle();\n\n        //    await UnitTestBase.WaitUntilAsync(() => CheckGrainsDeactivated(null, consumer, assertAreEqual: false), _timeout);\n        //    await UnitTestBase.WaitUntilAsync(() => CheckGrainsDeactivated(producer, null, assertAreEqual: false), _timeout);\n\n        //    logger.Info(\"*******************************************************************\");\n        //    //await BasicTestAsync(false);\n        //    //await StopProxies();\n        //}\n\n        public async Task StreamTest_19_ConsumerImplicitlySubscribedToProducerClient()\n        {\n            Heading(\"StreamTest_19_ConsumerImplicitlySubscribedToProducerClient\");\n            string consumerTypeName = typeof(Streaming_ImplicitlySubscribedConsumerGrain).FullName;\n            Guid streamGuid = Guid.NewGuid();\n            producer = await ProducerProxy.NewProducerClientObjectsAsync(streamGuid, streamProviderName, \"TestNamespace1\", logger, this.client);\n            this.consumer = ConsumerProxy.NewConsumerGrainAsync_WithoutBecomeConsumer(streamGuid, this.logger, this.client, consumerTypeName);\n\n            logger.LogInformation(\"\\n** Starting Test {TestNumber}.\\n\", testNumber);\n            var producerCount = await producer.ProducerCount;\n            logger.LogInformation(\"\\n** Test {TestNumber} BasicTestAsync: producerCount={ProducerCount}.\\n\", testNumber, producerCount);\n\n            async Task<bool> waitUntilFunc(bool lastTry) =>\n                    0 < await TestUtils.GetActivationCount(this.client, consumerTypeName) && await this.CheckCounters(this.producer, this.consumer, false);\n            await producer.ProduceSequentialSeries(ItemCount);\n            await TestingUtils.WaitUntilAsync(waitUntilFunc, _timeout);\n            await CheckCounters(producer, consumer);\n            await StopProxies();\n        }\n\n        public async Task StreamTest_20_ConsumerImplicitlySubscribedToProducerGrain()\n        {\n            Heading(\"StreamTest_20_ConsumerImplicitlySubscribedToProducerGrain\");\n            string consumerTypeName = typeof(Streaming_ImplicitlySubscribedConsumerGrain).FullName;\n            Guid streamGuid = Guid.NewGuid();\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamGuid, this.streamProviderName, \"TestNamespace1\", this.logger, this.client);\n            this.consumer = ConsumerProxy.NewConsumerGrainAsync_WithoutBecomeConsumer(streamGuid, this.logger, this.client, consumerTypeName);\n\n            logger.LogInformation(\"\\n** Starting Test {TestNumber}.\\n\", testNumber);\n            var producerCount = await producer.ProducerCount;\n            logger.LogInformation(\"\\n** Test {TestNumber} BasicTestAsync: producerCount={ProducerCount}.\\n\", testNumber, producerCount);\n\n            async Task<bool> waitUntilFunc(bool lastTry) =>\n                    0 < await TestUtils.GetActivationCount(this.client, consumerTypeName) && await this.CheckCounters(this.producer, this.consumer, false);\n            await producer.ProduceSequentialSeries(ItemCount);\n            await TestingUtils.WaitUntilAsync(waitUntilFunc, _timeout);\n            await CheckCounters(producer, consumer);\n            await StopProxies();\n        }\n\n        public async Task StreamTest_21_GenericConsumerImplicitlySubscribedToProducerGrain()\n        {\n            Heading(\"StreamTest_21_GenericConsumerImplicitlySubscribedToProducerGrain\");\n            //ToDo in migrate: the following consumer grain is not implemented in VSO and all tests depend on it fail.\n            string consumerTypeName = \"UnitTests.Grains.Streaming_ImplicitlySubscribedGenericConsumerGrain\";//typeof(Streaming_ImplicitlySubscribedGenericConsumerGrain).FullName;\n            Guid streamGuid = Guid.NewGuid();\n            this.producer = await ProducerProxy.NewProducerGrainsAsync(streamGuid, this.streamProviderName, \"TestNamespace1\", this.logger, this.client);\n            this.consumer = ConsumerProxy.NewConsumerGrainAsync_WithoutBecomeConsumer(streamGuid, this.logger, this.client, consumerTypeName);\n\n            logger.LogInformation(\"\\n** Starting Test {TestNumber}.\\n\", testNumber);\n            var producerCount = await producer.ProducerCount;\n            logger.LogInformation(\"\\n** Test {TestNumber} BasicTestAsync: producerCount={ProducerCount}.\\n\", testNumber, producerCount);\n\n            async Task<bool> waitUntilFunc(bool lastTry) =>\n                    0 < await TestUtils.GetActivationCount(this.client, consumerTypeName) && await this.CheckCounters(this.producer, this.consumer, false);\n            await producer.ProduceSequentialSeries(ItemCount);\n            await TestingUtils.WaitUntilAsync(waitUntilFunc, _timeout);\n            await CheckCounters(producer, consumer);\n            await StopProxies();\n        }\n\n        public async Task StreamTest_22_TestImmutabilityDuringStreaming()\n        {\n            Heading(\"StreamTest_22_TestImmutabilityDuringStreaming\");\n\n            IStreamingImmutabilityTestGrain itemProducer = this.client.GetGrain<IStreamingImmutabilityTestGrain>(Guid.NewGuid());\n            string producerSilo = await itemProducer.GetSiloIdentifier();\n\n            // Obtain consumer in silo of item producer\n            IStreamingImmutabilityTestGrain consumerSameSilo = null;\n            do\n            {\n                var itemConsumer = this.client.GetGrain<IStreamingImmutabilityTestGrain>(Guid.NewGuid());\n                var consumerSilo = await itemConsumer.GetSiloIdentifier();\n\n                if (consumerSilo == producerSilo)\n                    consumerSameSilo = itemConsumer;\n            } while (consumerSameSilo == null);\n\n            // Test behavior if immutability is enabled\n            await consumerSameSilo.SubscribeToStream(itemProducer.GetPrimaryKey(), SMS_STREAM_PROVIDER_NAME);\n\n            await itemProducer.SetTestObjectStringProperty(\"VALUE_IN_IMMUTABLE_STREAM\");\n            await itemProducer.SendTestObject(SMS_STREAM_PROVIDER_NAME);\n\n            Assert.Equal(\"VALUE_IN_IMMUTABLE_STREAM\", await consumerSameSilo.GetTestObjectStringProperty());\n\n            // Now violate immutability by updating the property in the consumer.\n            await consumerSameSilo.SetTestObjectStringProperty(\"ILLEGAL_CHANGE\");\n            Assert.Equal(\"ILLEGAL_CHANGE\", await itemProducer.GetTestObjectStringProperty());\n\n            await consumerSameSilo.UnsubscribeFromStream();\n\n            // Test behavior if immutability is disabled\n            itemProducer = this.client.GetGrain<IStreamingImmutabilityTestGrain>(Guid.NewGuid());\n\n            await consumerSameSilo.SubscribeToStream(itemProducer.GetPrimaryKey(), SMS_STREAM_PROVIDER_NAME_DO_NOT_OPTIMIZE_FOR_IMMUTABLE_DATA);\n\n            await itemProducer.SetTestObjectStringProperty(\"VALUE_IN_MUTABLE_STREAM\");\n            await itemProducer.SendTestObject(SMS_STREAM_PROVIDER_NAME_DO_NOT_OPTIMIZE_FOR_IMMUTABLE_DATA);\n\n            Assert.Equal(\"VALUE_IN_MUTABLE_STREAM\", await consumerSameSilo.GetTestObjectStringProperty());\n\n            // Modify the items property and check it has no impact\n            await consumerSameSilo.SetTestObjectStringProperty(\"ALLOWED_CHANGE\");\n            Assert.Equal(\"ALLOWED_CHANGE\", await consumerSameSilo.GetTestObjectStringProperty());\n            Assert.Equal(\"VALUE_IN_MUTABLE_STREAM\", await itemProducer.GetTestObjectStringProperty());\n\n            await consumerSameSilo.UnsubscribeFromStream();\n        }\n\n        //-----------------------------------------------------------------------------//\n\n        public async Task BasicTestAsync(bool fullTest = true)\n        {\n            logger.LogInformation(\"\\n** Starting Test {TestNumber} BasicTestAsync.\\n\", testNumber);\n            var producerCount = await producer.ProducerCount;\n            var consumerCount = await consumer.ConsumerCount;\n            logger.LogInformation(\n                \"\\n** Test {TestNumber} BasicTestAsync: producerCount={ProducerCount}, consumerCount={ConsumerCount}.\\n\",\n                testNumber,\n                producerCount,\n                consumerCount);\n\n            await producer.ProduceSequentialSeries(ItemCount);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, false), _timeout);\n            await CheckCounters(producer, consumer);\n            if (runFullTest)\n            {\n                await producer.ProduceParallelSeries(ItemCount);\n                await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, false), _timeout);\n                await CheckCounters(producer, consumer);\n           \n                await producer.ProducePeriodicSeries(ItemCount);\n                await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, false), _timeout);\n                await CheckCounters(producer, consumer);\n            }\n            await ValidatePubSub(producer.StreamId, producer.ProviderName);\n        }\n\n        public async Task StopProxies()\n        {\n            await producer.StopBeingProducer();\n            await AssertProducerCount(0, producer.ProviderName, producer.StreamIdGuid);\n            await consumer.StopBeingConsumer();\n        }\n\n        private async Task<bool> CheckCounters(ProducerProxy producer, ConsumerProxy consumer, bool assertAreEqual = true)\n        {\n            var consumerCount = await consumer.ConsumerCount;\n            Assert.NotEqual(0,  consumerCount);  // \"no consumers were detected.\"\n            _ = await producer.ProducerCount;\n            var numProduced = await producer.ExpectedItemsProduced;\n            var expectConsumed = numProduced * consumerCount;\n            var numConsumed = await consumer.ItemsConsumed;\n            logger.LogInformation(\n                \"Test {TestNumber} CheckCounters: numProduced = {NumProduced}, expectConsumed = {ExpectedConsumed}, numConsumed = {NumConsumed}\",\n                testNumber,\n                numProduced,\n                expectConsumed,\n                numConsumed);\n            if (assertAreEqual)\n            {\n                Assert.Equal(expectConsumed,  numConsumed); // String.Format(\"expectConsumed = {0}, numConsumed = {1}\", expectConsumed, numConsumed));\n                return true;\n            }\n            else\n            {\n                return expectConsumed == numConsumed;\n            }\n        }\n\n        private async Task AssertProducerCount(int expectedCount, string providerName, Guid streamIdGuid)\n        {\n            // currently, we only support checking the producer count on the SMS rendezvous grain.\n            if (providerName == SMS_STREAM_PROVIDER_NAME)\n            {\n                var streamId = StreamId.Create(StreamTestsConstants.DefaultStreamNamespace, streamIdGuid);\n                var actualCount = await StreamTestUtils.GetStreamPubSub(this.client).ProducerCount(new QualifiedStreamId(providerName, streamId));\n                logger.LogInformation(\n                    \"StreamingTestRunner.AssertProducerCount: expected={ExpectedCount} actual (SMSStreamRendezvousGrain.ProducerCount)={ActualCount} streamId={StreamId}\",\n                    expectedCount,\n                    actualCount,\n                    streamId);\n                Assert.Equal(expectedCount, actualCount);\n            }\n        }\n\n        private Task ValidatePubSub(StreamId streamId, string providerName)\n        {\n            var intStreamId = new QualifiedStreamId(providerName, streamId);\n            var rendez = this.client.GetGrain<IPubSubRendezvousGrain>(intStreamId.ToString());\n            return rendez.Validate();\n        }\n\n        private async Task<bool> CheckGrainsDeactivated(ProducerProxy producer, ConsumerProxy consumer, bool assertAreEqual = true)\n        {\n            var activationCount = 0;\n            string str = \"\";\n            if (producer != null)\n            {\n                str = \"Producer\";\n                activationCount = await producer.GetNumActivations(this.client);\n            }\n            else if (consumer != null)\n            {\n                str = \"Consumer\";\n                activationCount = await consumer.GetNumActivations(this.client);\n            }\n            var expectActivationCount = 0;\n            logger.LogInformation(\n                \"Test {TestNumber} CheckGrainsDeactivated: {Type}ActivationCount = {ActivationCount}, Expected{Type}ActivationCount = {ExpectActivationCount}\", \n                testNumber, \n                str, \n                activationCount, \n                str,\n                expectActivationCount);\n            if (assertAreEqual)\n            {\n                Assert.Equal(expectActivationCount,  activationCount); // String.Format(\"Expected{0}ActivationCount = {1}, {0}ActivationCount = {2}\", str, expectActivationCount, activationCount));\n            }\n            return expectActivationCount == activationCount;\n        }\n    }\n}\n\n//public async Task AQ_1_ConsumerJoinsFirstProducerLater()\n//{\n//    logger.Info(\"\\n\\n ************************ AQ_1_ConsumerJoinsFirstProducerLater ********************************* \\n\\n\");\n//    streamId = StreamId.NewRandomStreamId();\n//    streamProviderName = AQ_STREAM_PROVIDER_NAME;\n//    // consumer joins first, producer later\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//public async Task AQ_2_ProducerJoinsFirstConsumerLater()\n//{\n//    logger.Info(\"\\n\\n ************************ AQ_2_ProducerJoinsFirstConsumerLater ********************************* \\n\\n\");\n//    streamId = StreamId.NewRandomStreamId();\n//    streamProviderName = AQ_STREAM_PROVIDER_NAME;\n//    // produce joins first, consumer later\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n//public async Task StreamTest_2_ProducerJoinsFirstConsumerLater()\n//{\n//    logger.Info(\"\\n\\n ************************ StreamTest_2_ProducerJoinsFirstConsumerLater ********************************* \\n\\n\");\n//    streamId = Guid.NewGuid();\n//    streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    // produce joins first, consumer later\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n\n\n//[Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n//public async Task StreamTestProducerOnly()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    await TestGrainProducerOnlyAsync(streamId, this.streamProviderName);\n//}\n\n//[Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n//public void AQProducerOnly()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = AQ_STREAM_PROVIDER_NAME;\n//    TestGrainProducerOnlyAsync(streamId, this.streamProviderName).Wait();\n//}\n\n//private async Task TestGrainProducerOnlyAsync(Guid streamId, string streamProvider)\n//{\n//    // no consumers, one producer\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProvider, logger);\n\n//    await producer.ProduceSequentialSeries(0, ItemsPerSeries);\n//    var numProduced = await producer.NumberProduced;\n//    logger.Info(\"numProduced = \" + numProduced);\n//    Assert.Equal(numProduced, ItemsPerSeries);\n\n//    // note that the value returned from successive calls to Do...Production() methods is a cumulative total.\n//    await producer.ProduceParallelSeries(ItemsPerSeries, ItemsPerSeries);\n//    numProduced = await producer.NumberProduced;\n//    logger.Info(\"numProduced = \" + numProduced);\n//    Assert.Equal(numProduced, ItemsPerSeries * 2);\n//}\n\n\n////------------------------ MANY to One ----------------------//\n\n//[Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n//public async Task StreamTest_Many_5_ManyProducerGrainsOneConsumerGrain()\n//{\n//    logger.Info(\"\\n\\n ************************ StreamTest_6_ManyProducerGrainsOneConsumerGrain ********************************* \\n\\n\");\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger, Many);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n//public async Task StreamTest_Many6_OneProducerGrainManyConsumerGrains()\n//{\n//    logger.Info(\"\\n\\n ************************ StreamTest_7_OneProducerGrainManyConsumerGrains ********************************* \\n\\n\");\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger, Many);\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task StreamTest_Many_8_ManyProducerGrainsOneConsumerClient()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger);\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger, Many);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//// note: this test currently fails intermittently due to synchronization issues in the StreamTest provider. it has been \n//// removed from nightly builds until this has been addressed.\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task _StreamTestManyProducerClientsOneConsumerGrain()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger);\n//    var producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, logger, Many);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//// note: this test currently fails intermittently due to synchronization issues in the StreamTest provider. it has been \n//// removed from nightly builds until this has been addressed.\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task _StreamTestManyProducerClientsOneConsumerClient()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger);\n//    var producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, logger, Many);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task _StreamTestOneProducerGrainManyConsumerClients()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, Many);\n//    var producer = await ProducerProxy.NewProducerGrainsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task _StreamTestOneProducerClientManyConsumerGrains()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerGrainsAsync(streamId, streamProviderName, logger, Many);\n//    var producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n\n//[Fact, TestCategory(\"Streaming\")]\n//public async Task _StreamTestOneProducerClientManyConsumerClients()\n//{\n//    streamId = Guid.NewGuid();\n//    this.streamProviderName = StreamTest_STREAM_PROVIDER_NAME;\n//    var consumer = await ConsumerProxy.NewConsumerClientObjectsAsync(streamId, streamProviderName, logger, Many);\n//    var producer = await ProducerProxy.NewProducerClientObjectsAsync(streamId, streamProviderName, logger);\n//    await BasicTestAsync(producer, consumer);\n//}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StatelessWorkersStreamTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests for stream subscription behavior with stateless worker grains, verifying subscription restrictions.\n    /// </summary>\n    [TestCategory(\"Streaming\")]\n    public class StatelessWorkersStreamTests : OrleansTestingBase, IClassFixture<StatelessWorkersStreamTests.Fixture>\n    {\n        private readonly Fixture fixture;\n\n        private readonly ILogger logger;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n                builder.AddClientBuilderConfigurator<ClientConfiguretor>();\n            }\n\n            public class SiloConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProvider)\n                         .AddMemoryGrainStorage(\"PubSubStore\");\n                }\n            }\n\n            public class ClientConfiguretor : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n                {\n                    clientBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProvider);\n                }\n            }\n        }\n\n        private const string StreamProvider = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n\n        public StatelessWorkersStreamTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n            logger = this.fixture.Logger;\n        }\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task SubscribeToStream_FromStatelessWorker_Fail()\n        {\n            this.logger.LogInformation($\"************************ { nameof(SubscribeToStream_FromStatelessWorker_Fail) } *********************************\");\n            var runner = new StatelessWorkersStreamTestsRunner(StreamProvider, this.logger, this.fixture.HostedCluster);\n            await Assert.ThrowsAsync<InvalidOperationException>( () => runner.BecomeConsumer(Guid.NewGuid()));\n        }\n    }\n\n    /// <summary>\n    /// Test runner class for executing stateless worker stream tests with producer and consumer functionality.\n    /// </summary>\n    public class StatelessWorkersStreamTestsRunner\n    {\n        private const string StreamNamespace = \"SampleStreamNamespace\";\n\n        private readonly string streamProvider;\n        private readonly ILogger logger;\n        private readonly TestCluster cluster;\n\n        public StatelessWorkersStreamTestsRunner(string streamProvider, ILogger logger, TestCluster cluster)\n        {\n            this.streamProvider = streamProvider;\n            this.logger = logger;\n            this.cluster = cluster;\n        }\n\n        public async Task BecomeConsumer(Guid streamId)\n        {\n            var consumer = this.cluster.GrainFactory.GetGrain<IStatelessWorkerStreamConsumerGrain>(0);\n            await consumer.BecomeConsumer(streamId, streamProvider);\n        }\n\n        public async Task ProduceMessage(Guid streamId)\n        {\n            var producer = this.cluster.GrainFactory.GetGrain<IStatelessWorkerStreamProducerGrain>(0);\n            await producer.Produce(streamId, streamProvider, string.Empty);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamBatchingTestRunner.cs",
    "content": "using Orleans.Streams;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.StreamingTests\n{\n    public abstract class StreamBatchingTestRunner\n    {\n        protected readonly BaseTestClusterFixture fixture;\n        protected readonly ITestOutputHelper output;\n        private readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n\n        protected StreamBatchingTestRunner(BaseTestClusterFixture fixture, ITestOutputHelper output)\n        {\n            this.fixture = fixture;\n            this.output = output;\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5649\"), TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task SingleSendBatchConsume()\n        {\n            const int ExpectedConsumed = 30;\n            Guid streamGuid = Guid.NewGuid();\n\n            IStreamProvider provider = this.fixture.Client.GetStreamProvider(StreamBatchingTestConst.ProviderName);\n            IAsyncStream<string> stream = provider.GetStream<string>(StreamBatchingTestConst.BatchingNameSpace, streamGuid);\n            for(int i = 0; i< ExpectedConsumed; i++)\n            {\n                await stream.OnNextAsync(i.ToString());\n            }\n            var consumer = this.fixture.GrainFactory.GetGrain<IStreamBatchingTestConsumerGrain>(streamGuid);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(consumer, ExpectedConsumed, 2, lastTry), Timeout);\n        }\n\n        [SkippableFact, TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task BatchSendSingleConsume()\n        {\n            const int BatchesSent = 3;\n            const int ItemsPerBatch = 10;\n            const int ExpectedConsumed = BatchesSent * ItemsPerBatch;\n            Guid streamGuid = Guid.NewGuid();\n\n            IStreamProvider provider = this.fixture.Client.GetStreamProvider(StreamBatchingTestConst.ProviderName);\n            IAsyncStream<string> stream = provider.GetStream<string>(StreamBatchingTestConst.NonBatchingNameSpace, streamGuid);\n            for (int i = 0; i < BatchesSent; i++)\n            {\n                await stream.OnNextBatchAsync(Enumerable.Range(i, ItemsPerBatch).Select(v => v.ToString()));\n            }\n            var consumer = this.fixture.GrainFactory.GetGrain<IStreamBatchingTestConsumerGrain>(streamGuid);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(consumer, ExpectedConsumed, 1, lastTry), Timeout);\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/5632\"), TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task BatchSendBatchConsume()\n        {\n            const int BatchesSent = 3;\n            const int ItemsPerBatch = 10;\n            const int ExpectedConsumed = BatchesSent * ItemsPerBatch;\n            Guid streamGuid = Guid.NewGuid();\n\n            IStreamProvider provider = this.fixture.Client.GetStreamProvider(StreamBatchingTestConst.ProviderName);\n            IAsyncStream<string> stream = provider.GetStream<string>(StreamBatchingTestConst.BatchingNameSpace, streamGuid);\n            for (int i = 0; i < BatchesSent; i++)\n            {\n                await stream.OnNextBatchAsync(Enumerable.Range(i, ItemsPerBatch).Select(v => v.ToString()));\n            }\n            var consumer = this.fixture.GrainFactory.GetGrain<IStreamBatchingTestConsumerGrain>(streamGuid);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(consumer, ExpectedConsumed, ItemsPerBatch, lastTry), Timeout);\n        }\n\n        private async Task<bool> CheckCounters(IStreamBatchingTestConsumerGrain consumer, int expectedConsumed, int minBatchSize, bool assertIsTrue)\n        {\n            ConsumptionReport report = await consumer.GetConsumptionReport();\n            this.output.WriteLine($\"Report - Consumed: {report.Consumed}, MaxBatchSize: {report.MaxBatchSize}\");\n            if (assertIsTrue)\n            {\n                Assert.Equal(expectedConsumed, report.Consumed);\n                Assert.True(report.MaxBatchSize >= minBatchSize);\n                return true;\n            }\n            else\n            {\n                return report.Consumed == expectedConsumed && report.MaxBatchSize >= minBatchSize;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamGeneratorProviderTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.Providers.Streams.Generator;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing TestGrainInterfaces;\nusing TestGrains;\nusing UnitTests.Grains;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests for stream generator provider functionality, validating automatic stream generation and event delivery.\n    /// </summary>\n    public class StreamGeneratorProviderTests : OrleansTestingBase, IClassFixture<StreamGeneratorProviderTests.Fixture>\n    {\n        private const int TotalQueueCount = 4;\n        private readonly Fixture fixture;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = GeneratedStreamTestConstants.StreamProviderName;\n            public const string StreamNamespace = GeneratedEventCollectorGrain.StreamNamespace;\n\n            public readonly static SimpleGeneratorOptions GeneratorConfig = new SimpleGeneratorOptions\n            {\n                StreamNamespace = StreamNamespace,\n                EventsInStream = 100\n            };\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .ConfigureLogging(logging => logging.AddDebug())\n                        .ConfigureServices(services => services.AddKeyedSingleton<IStreamGeneratorConfig>(StreamProviderName, (s, n) => GeneratorConfig))\n                        .AddPersistentStreams(\n                            StreamProviderName,\n                            GeneratorAdapterFactory.Create,\n                            b =>\n                            {\n                                b.ConfigurePullingAgent(ob => ob.Configure(options => { options.BatchContainerBatchSize = 10; }));\n                                b.Configure<HashRingStreamQueueMapperOptions>(ob => ob.Configure(options => options.TotalQueueCount = TotalQueueCount));\n                                b.UseDynamicClusterConfigDeploymentBalancer();\n                                b.ConfigureStreamPubSub(StreamPubSubType.ImplicitOnly);\n                            });\n\n                }\n            }\n        }\n\n        public StreamGeneratorProviderTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n\n        [Fact, TestCategory(\"BVT\"), TestCategory(\"Streaming\")]\n        public async Task ValidateGeneratedStreamsTest()\n        {\n            this.fixture.Logger.LogInformation(\"************************ ValidateGeneratedStreamsTest *********************************\");\n            await TestingUtils.WaitUntilAsync(CheckCounters, Timeout);\n        }\n\n        private async Task<bool> CheckCounters(bool assertIsTrue)\n        {\n            var reporter = this.fixture.GrainFactory.GetGrain<IGeneratedEventReporterGrain>(GeneratedStreamTestConstants.ReporterId);\n\n            var report = await reporter.GetReport(Fixture.StreamProviderName, Fixture.StreamNamespace);\n            if (assertIsTrue)\n            {\n                // one stream per queue\n                Assert.Equal(TotalQueueCount, report.Count);\n                foreach (int eventsPerStream in report.Values)\n                {\n                    Assert.Equal(Fixture.GeneratorConfig.EventsInStream, eventsPerStream);\n                }\n            }\n            else if (TotalQueueCount != report.Count ||\n                     report.Values.Any(count => count != Fixture.GeneratorConfig.EventsInStream))\n            {\n                return false;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamProvidersTests.cs",
    "content": "using Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing UnitTests.StreamingTests;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Orleans.Runtime;\nusing UnitTests.StorageTests;\nusing Orleans.Storage;\nusing Orleans.Providers;\nusing Orleans.Internal;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace UnitTests.Streaming\n{\n    /// <summary>\n    /// Tests for stream provider configuration and error injection scenarios.\n    /// </summary>\n    public class StreamProvidersTests_ProviderConfigNotLoaded : IClassFixture<StreamProvidersTests_ProviderConfigNotLoaded.Fixture>\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            public string ServiceId { get; set; }\n\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                this.ServiceId = builder.Options.ServiceId;\n                builder.Options.InitialSilosCount = 4;\n                builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n            }\n\n            public class SiloHostConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder)\n                {\n                    hostBuilder\n                        .AddMemoryGrainStorage(\"MemoryStore\")\n                        .ConfigureServices(services =>\n                        {\n                            services.AddSingleton<ErrorInjectionStorageProvider>();\n                            services.AddKeyedSingleton<IGrainStorage, ErrorInjectionStorageProvider>(\"ErrorInjector\");\n                            services.AddKeyedSingleton<IControllable, ErrorInjectionStorageProvider>(\"ErrorInjector\");\n                        });\n                }\n            }\n        }\n\n        public static readonly string STREAM_PROVIDER_NAME = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n        private readonly ITestOutputHelper output;\n        private readonly Fixture fixture;\n        protected TestCluster HostedCluster => this.fixture.HostedCluster;\n\n        public StreamProvidersTests_ProviderConfigNotLoaded(ITestOutputHelper output, Fixture fixture)\n        {\n            this.fixture = fixture;\n            this.output = output;\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"Providers\")]\n        public async Task ProvidersTests_ConfigNotLoaded()\n        {\n            Guid streamId = Guid.NewGuid();\n            var grainFullName = typeof(Streaming_ConsumerGrain).FullName;\n            // consumer joins first, producer later\n            IStreaming_ConsumerGrain consumer = this.HostedCluster.GrainFactory.GetGrain<IStreaming_ConsumerGrain>(Guid.NewGuid(), grainFullName);\n            await Assert.ThrowsAsync<KeyNotFoundException>(() => consumer.BecomeConsumer(streamId, STREAM_PROVIDER_NAME, null));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\"), TestCategory(\"ServiceId\"), TestCategory(\"Providers\")]\n        public async Task ServiceId_ProviderRuntime()\n        {\n            var thisRunServiceId = this.fixture.ServiceId;\n\n            SiloHandle siloHandle = this.HostedCluster.GetActiveSilos().First();\n            var serviceId = await this.fixture.Client.GetTestHooks(siloHandle).GetServiceId();\n            Assert.Equal(thisRunServiceId, serviceId);  // \"ServiceId active in silo\"\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Config\"), TestCategory(\"ServiceId\")]\n        public async Task ServiceId_SiloRestart()\n        {\n            var configServiceId = this.fixture.GetClientServiceId();\n            output.WriteLine(\"ServiceId={0}\", this.fixture.ServiceId);\n\n            Assert.Equal(this.fixture.ServiceId, configServiceId);  // \"ServiceId in test config\"\n\n            output.WriteLine(\"About to reset Silos .....\");\n            output.WriteLine(\"Restarting Silos ...\");\n\n            foreach (var silo in this.HostedCluster.GetActiveSilos().ToList())\n            {\n                await this.HostedCluster.RestartSiloAsync(silo);\n            }\n\n            output.WriteLine(\"..... Silos restarted\");\n            \n            var activeSilos = this.HostedCluster.GetActiveSilos().ToArray();\n            Assert.True(activeSilos.Length > 0);\n\n            foreach (var siloHandle in activeSilos)\n            {\n                await AsyncExecutorWithRetries.ExecuteWithRetries(async _ =>\n                    {\n                        var serviceId = await this.fixture.Client.GetTestHooks(siloHandle).GetServiceId();\n                        Assert.Equal(this.fixture.ServiceId, serviceId); // \"ServiceId active in silo\"\n                    },\n                    30,\n                    (ex, i) => ex is OrleansException,\n                    TimeSpan.FromSeconds(60),\n                    new FixedBackoff(TimeSpan.FromSeconds(2)));\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamPubSubReliabilityTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Runtime.Hosting;\nusing Orleans.Storage;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.StorageTests;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    /// <summary>\n    /// Tests for stream pub/sub reliability with error injection in storage providers.\n    /// </summary>\n    public class StreamPubSubReliabilityTests : OrleansTestingBase, IClassFixture<StreamPubSubReliabilityTests.Fixture>, IAsyncLifetime\n    {\n        public class Fixture : BaseTestClusterFixture\n        {\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.InitialSilosCount = 4;\n                builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n                builder.AddClientBuilderConfigurator<ClientConfiguretor>();\n            }\n        }\n\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamTestsConstants.SMS_STREAM_PROVIDER_NAME)\n                    .AddMemoryGrainStorage(\"MemoryStore\", op => op.NumStorageGrains = 1)\n                    .ConfigureServices(services =>\n                    {\n                        services.AddSingleton<ErrorInjectionStorageProvider>();\n                        services.AddGrainStorage(PubSubStoreProviderName, (sp, name) => sp.GetRequiredService<ErrorInjectionStorageProvider>());\n                        services.AddKeyedSingleton<IControllable>(PubSubStoreProviderName, (sp, key) => sp.GetRequiredService<ErrorInjectionStorageProvider>());\n                    });\n            }\n        }\n        public class ClientConfiguretor : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamTestsConstants.SMS_STREAM_PROVIDER_NAME);\n            }\n        }\n\n        private const string PubSubStoreProviderName = \"PubSubStore\";\n\n        public IGrainFactory GrainFactory => _fixture.GrainFactory;\n\n        protected Guid StreamId;\n        protected string StreamProviderName;\n        protected string StreamNamespace;\n        protected TestCluster HostedCluster;\n        private readonly Fixture _fixture;\n\n        public StreamPubSubReliabilityTests(Fixture fixture)\n        {\n            StreamId = Guid.NewGuid();\n            StreamProviderName = StreamTestsConstants.SMS_STREAM_PROVIDER_NAME;\n            StreamNamespace = StreamTestsConstants.StreamLifecycleTestsNamespace;\n            this.HostedCluster = fixture.HostedCluster;\n            _fixture = fixture;\n        }\n\n        public async Task InitializeAsync()\n        {\n            await SetErrorInjection(PubSubStoreProviderName, ErrorInjectionPoint.None);\n        }\n\n        public Task DisposeAsync() => Task.CompletedTask;\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task PubSub_Store_Baseline()\n        {\n            await Test_PubSub_Stream(StreamProviderName, StreamId);\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task PubSub_Store_ReadError()\n        {\n            // Expected behaviour: Underlying error StorageProviderInjectedError returned to caller\n            //\n            // Actual behaviour: Rather cryptic error OrleansException returned, mentioning \n            //                   root cause problem \"Failed SetupActivationState\" in message text, \n            //                   but no more details or stack trace.\n\n            await SetErrorInjection(PubSubStoreProviderName, ErrorInjectionPoint.BeforeRead);\n\n            // TODO: expect StorageProviderInjectedError directly instead of OrleansException\n            await Assert.ThrowsAsync<StorageProviderInjectedError>(() =>\n                Test_PubSub_Stream(StreamProviderName, StreamId));\n        }\n\n        [Fact, TestCategory(\"Functional\"), TestCategory(\"Streaming\"), TestCategory(\"PubSub\")]\n        public async Task PubSub_Store_WriteError()\n        {\n            await SetErrorInjection(PubSubStoreProviderName, ErrorInjectionPoint.BeforeWrite);\n\n            var exception = await Assert.ThrowsAsync<StorageProviderInjectedError>(() =>\n                Test_PubSub_Stream(StreamProviderName, StreamId));\n        }\n\n        private async Task Test_PubSub_Stream(string streamProviderName, Guid streamId)\n        {\n            // Consumer\n            IStreamLifecycleConsumerGrain consumer = this.GrainFactory.GetGrain<IStreamLifecycleConsumerGrain>(Guid.NewGuid());\n            await consumer.BecomeConsumer(streamId, this.StreamNamespace, streamProviderName);\n\n            // Producer\n            IStreamLifecycleProducerGrain producer = this.GrainFactory.GetGrain<IStreamLifecycleProducerGrain>(Guid.NewGuid());\n            await producer.BecomeProducer(StreamId, this.StreamNamespace, streamProviderName);\n\n            await producer.SendItem(1);\n\n            int received1 = 0;\n            using var cts = new CancellationTokenSource(1000);\n            do\n            {\n                received1 = await consumer.GetReceivedCount();\n            } while (received1 <= 1 || !cts.IsCancellationRequested);\n\n            Assert.True(received1 > 1, $\"Received count for consumer {consumer} is too low = {received1}\");\n\n            // Unsubscribe\n            await consumer.ClearGrain();\n\n            // Send one more message\n            await producer.SendItem(2);\n\n            await Task.Delay(300);\n\n            int received2 = await consumer.GetReceivedCount();\n\n            Assert.Equal(0, received2);  // $\"Received count for consumer {consumer} is wrong = {received2}\"\n\n        }\n\n        private async Task SetErrorInjection(string providerName, ErrorInjectionPoint errorInjectionPoint)\n        {\n            await ErrorInjectionStorageProvider.SetErrorInjection(\n                providerName,\n                new ErrorInjectionBehavior { ErrorInjectionPoint = errorInjectionPoint },\n                this.HostedCluster.GrainFactory);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamTestHelperClasses.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing UnitTests.GrainInterfaces;\nusing UnitTests.Grains;\nusing UnitTests.TestHelper;\n\nnamespace UnitTests.StreamingTests\n{\n    public class Streaming_ConsumerClientObject : IAsyncObserver<StreamItem>, IStreaming_ConsumerGrain\n    {\n        private readonly IClusterClient client;\n        private readonly ConsumerObserver _consumer;\n        private string _providerToUse;\n\n        private Streaming_ConsumerClientObject(ILogger logger, IClusterClient client)\n        {\n            this.client = client;\n            _consumer = ConsumerObserver.NewObserver(logger);\n        }\n\n        public static Streaming_ConsumerClientObject NewObserver(ILogger logger, IClusterClient client)\n        {\n            return new Streaming_ConsumerClientObject(logger, client);\n        }\n\n        public Task OnNextAsync(StreamItem item, StreamSequenceToken token = null)\n        {\n            return _consumer.OnNextAsync(item, token);\n        }\n\n        public Task OnCompletedAsync()\n        {\n            return _consumer.OnCompletedAsync();\n        }\n\n        public Task OnErrorAsync(Exception ex)\n        {\n            return _consumer.OnErrorAsync(ex);\n        }\n\n        public Task BecomeConsumer(Guid streamId, string providerToUse)\n        {\n            _providerToUse = providerToUse;\n            return _consumer.BecomeConsumer(streamId, this.client.GetStreamProvider(providerToUse), null);\n        }\n        \n        public Task BecomeConsumer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _providerToUse = providerToUse;\n            return _consumer.BecomeConsumer(streamId, this.client.GetStreamProvider(providerToUse), streamNamespace);\n        }\n\n        public Task StopBeingConsumer()\n        {\n            return _consumer.StopBeingConsumer(this.client.GetStreamProvider(_providerToUse));\n        }\n\n        public Task<int> GetConsumerCount()\n        {\n            return _consumer.ConsumerCount;\n        }\n\n        public Task<int> GetItemsConsumed()\n        {\n            return _consumer.ItemsConsumed;\n        }\n\n        public Task DeactivateConsumerOnIdle()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    public class Streaming_ProducerClientObject : IStreaming_ProducerGrain\n    {\n        private readonly ProducerObserver producer;\n        private readonly IClusterClient client;\n        private Streaming_ProducerClientObject(ILogger logger, IClusterClient client)\n        {\n            this.client = client;\n            this.producer = ProducerObserver.NewObserver(logger, client);\n        }\n\n        public static Streaming_ProducerClientObject NewObserver(ILogger logger, IClusterClient client)\n        {\n            if (null == logger)\n                throw new ArgumentNullException(nameof(logger));\n            return new Streaming_ProducerClientObject(logger, client);\n        }\n\n        public Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            this.producer.BecomeProducer(streamId, this.client.GetStreamProvider(providerToUse), streamNamespace);\n            return Task.CompletedTask;\n        }\n\n        public Task ProduceSequentialSeries(int count)\n        {\n             return this.producer.ProduceSequentialSeries(count);\n        }\n\n        public Task ProduceParallelSeries(int count)\n        {\n             return this.producer.ProduceParallelSeries(count);\n        }\n\n        public Task<int> GetItemsProduced()\n        {\n            return this.producer.ItemsProduced;\n        }\n\n        public Task ProducePeriodicSeries(int count)\n        {\n            return this.producer.ProducePeriodicSeries(timerCallback =>\n                    {\n                        var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1));\n                        _ = Task.Run(async () =>\n                        {\n                            do\n                            {\n                                try\n                                {\n                                    await timerCallback(null);\n                                }\n                                catch\n                                {\n                                    // Ignore\n                                }\n                            } while (await timer.WaitForNextTickAsync());\n                        });\n                        return timer;\n                    }, count);\n        }\n\n        public Task<Guid> GetStreamId()\n        {\n            return this.producer.StreamId;\n        }\n\n        public Task<string> GetProviderName()\n        {\n            return Task.FromResult(this.producer.ProviderName);\n        }\n\n        public Task AddNewConsumerGrain(Guid consumerGrainId)\n        {\n            return this.producer.AddNewConsumerGrain(consumerGrainId);\n        }\n\n        public Task<int> GetExpectedItemsProduced()\n        {\n            return this.producer.ExpectedItemsProduced;\n        }\n\n        public Task<int> GetProducerCount()\n        {\n            return this.producer.ProducerCount;\n        }\n\n        public Task StopBeingProducer()\n        {\n            return this.producer.StopBeingProducer();\n        }\n\n        public Task VerifyFinished()\n        {\n            return this.producer.VerifyFinished();\n        }\n\n        public Task DeactivateProducerOnIdle()\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n    internal class ConsumerProxy\n    {\n        private readonly IStreaming_ConsumerGrain[] _targets;\n        private readonly ILogger _logger;\n        private readonly IInternalGrainFactory grainFactory;\n\n        private ConsumerProxy(IStreaming_ConsumerGrain[] targets, ILogger logger, IInternalGrainFactory grainFactory)\n        {\n            _targets = targets;\n            _logger = logger;\n            this.grainFactory = grainFactory;\n        }\n\n        private static async Task<ConsumerProxy> NewConsumerProxy(Guid streamId, string streamProvider, IStreaming_ConsumerGrain[] targets, ILogger logger, IInternalGrainFactory grainFactory)\n        {\n            if (targets == null)\n                throw new ArgumentNullException(nameof(targets));\n            if (targets.Length == 0)\n                throw new ArgumentException(\"caller must specify at least one target\");\n            if (string.IsNullOrWhiteSpace(streamProvider))\n                throw new ArgumentException(\"Stream provider name is either null or whitespace\", nameof(streamProvider));\n            if (logger == null)\n                throw new ArgumentNullException(nameof(logger));\n\n            ConsumerProxy newObj = new ConsumerProxy(targets, logger, grainFactory);\n            await newObj.BecomeConsumer(streamId, streamProvider);\n            return newObj;\n        }\n\n        public static Task<ConsumerProxy> NewConsumerGrainsAsync(Guid streamId, string streamProvider, ILogger logger, IInternalGrainFactory grainFactory, Guid[] grainIds = null, int grainCount = 1)\n        {\n            grainCount = grainIds != null ? grainIds.Length : grainCount;\n            if (grainCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(grainCount), \"The grain count must be at least one\");\n            logger.LogInformation(\"ConsumerProxy.NewConsumerGrainsAsync: multiplexing {GrainCount} consumer grains for stream {StreamId}.\", grainCount, streamId);\n            var grains = new IStreaming_ConsumerGrain[grainCount];\n            var dedup = new Dictionary<Guid, IStreaming_ConsumerGrain>();\n            var grainFullName = typeof(Streaming_ConsumerGrain).FullName;\n            for (var i = 0; i < grainCount; ++i)\n            {\n                if (grainIds != null)\n                {\n                    // we deduplicate the grain references to ensure that IEnumerable.Distinct() works as intended.\n                    if (dedup.ContainsKey(grainIds[i]))\n                        grains[i] = dedup[grainIds[i]];\n                    else\n                    {\n                        var gref = grainFactory.GetGrain<IStreaming_ConsumerGrain>(grainIds[i], grainFullName);\n                        grains[i] = gref;\n                        dedup[grainIds[i]] = gref;\n                    }\n                }\n                else\n                {\n                    grains[i] = grainFactory.GetGrain<IStreaming_ConsumerGrain>(Guid.NewGuid(), grainFullName);\n                }\n            }\n            return NewConsumerProxy(streamId, streamProvider, grains, logger, grainFactory);\n        }\n\n        public static Task<ConsumerProxy> NewProducerConsumerGrainsAsync(Guid streamId, string streamProvider, ILogger logger, int[] grainIds, bool useReentrantGrain, IInternalGrainFactory grainFactory)\n        {\n            int grainCount = grainIds.Length;\n            if (grainCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(grainIds), \"The grain count must be at least one\");\n            logger.LogInformation(\"ConsumerProxy.NewProducerConsumerGrainsAsync: multiplexing {GrainCount} consumer grains for stream {StreamId}.\", grainCount, streamId);\n            var grains = new IStreaming_ConsumerGrain[grainCount];\n            var dedup = new Dictionary<int, IStreaming_ConsumerGrain>();\n            for (var i = 0; i < grainCount; ++i)\n            {\n                    // we deduplicate the grain references to ensure that IEnumerable.Distinct() works as intended.\n                    if (dedup.ContainsKey(grainIds[i]))\n                        grains[i] = dedup[grainIds[i]];\n                    else\n                    {\n                        if (useReentrantGrain)\n                        {\n                            grains[i] = grainFactory.GetGrain<IStreaming_Reentrant_ProducerConsumerGrain>(grainIds[i]);\n                        }\n                        else\n                        {\n                            var grainFullName = typeof(Streaming_ProducerConsumerGrain).FullName;\n                            grains[i] = grainFactory.GetGrain<IStreaming_ProducerConsumerGrain>(grainIds[i], grainFullName);\n                        }\n                        dedup[grainIds[i]] = grains[i];\n                    }\n                    }\n            return NewConsumerProxy(streamId, streamProvider, grains, logger, grainFactory);\n        }\n\n        public static Task<ConsumerProxy> NewConsumerClientObjectsAsync(Guid streamId, string streamProvider, ILogger logger, IInternalClusterClient client, int consumerCount = 1)\n        {\n            if (consumerCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(consumerCount), \"argument must be 1 or greater\");\n            logger.LogInformation(\"ConsumerProxy.NewConsumerClientObjectsAsync: multiplexing {ConsumerCount} consumer client objects for stream {StreamId}.\", consumerCount, streamId);\n            var objs = new IStreaming_ConsumerGrain[consumerCount];\n            for (var i = 0; i < consumerCount; ++i)\n                objs[i] = Streaming_ConsumerClientObject.NewObserver(logger, client);\n            return NewConsumerProxy(streamId, streamProvider, objs, logger, client);\n        }\n\n        public static ConsumerProxy NewConsumerGrainAsync_WithoutBecomeConsumer(Guid consumerGrainId, ILogger logger, IInternalGrainFactory grainFactory, string grainClassName = \"\")\n        {\n            if (logger == null)\n                throw new ArgumentNullException(nameof(logger));\n\n            if (string.IsNullOrEmpty(grainClassName)) \n            {\n                grainClassName = typeof(Streaming_ConsumerGrain).FullName;\n            }\n\n            var grains = new IStreaming_ConsumerGrain[1];\n            grains[0] = grainFactory.GetGrain<IStreaming_ConsumerGrain>(consumerGrainId, grainClassName);\n            ConsumerProxy newObj = new ConsumerProxy(grains, logger, grainFactory);\n            return newObj;\n        }\n\n        private async Task BecomeConsumer(Guid streamId, string providerToUse)\n        {\n            List<Task> tasks = new List<Task>();\n            foreach (var target in _targets)\n            {\n                Task t = target.BecomeConsumer(streamId, providerToUse, null);\n                // Consider: remove this await, let the calls go in parallel. \n                // Have to do it for now to prevent multithreaded scheduler bug from happening.\n                // await t;\n                tasks.Add(t);\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        private async Task<int> GetItemsConsumed()\n        {\n            var tasks = _targets.Distinct().Select(t => t.GetItemsConsumed()).ToArray();\n            await Task.WhenAll(tasks);\n            return tasks.Sum(t => t.Result);\n        }\n\n        public Task<int> ItemsConsumed\n        {\n            get { return GetItemsConsumed(); }\n        }\n\n        private async Task<int> GetConsumerCount()\n        {\n            var tasks = _targets.Distinct().Select(p => p.GetConsumerCount()).ToArray();\n            await Task.WhenAll(tasks);\n            return tasks.Sum(t => t.Result);\n        }\n\n        public Task<int> ConsumerCount\n        {\n            get { return GetConsumerCount(); }\n        }        \n\n        public Task StopBeingConsumer()\n        {\n            var tasks = _targets.Distinct().Select(c => c.StopBeingConsumer()).ToArray();\n            return Task.WhenAll(tasks);\n        }\n\n        public async Task DeactivateOnIdle()\n        {\n            var tasks = _targets.Distinct().Select(t => t.DeactivateConsumerOnIdle()).ToArray();\n            await Task.WhenAll(tasks);\n        }\n\n        public Task<int> GetNumActivations(IInternalGrainFactory grainFactory)\n        {\n            return GetNumActivations(_targets.Distinct(), grainFactory);\n    }\n\n        public static async Task<int> GetNumActivations(IEnumerable<IGrain> targets, IInternalGrainFactory grainFactory)\n        {\n            var grainIds = targets.Distinct().Where(t => t is GrainReference).Select(t => ((GrainReference)t).GrainId).ToArray();\n            IManagementGrain systemManagement = grainFactory.GetGrain<IManagementGrain>(0);\n            var tasks = grainIds.Select(g => systemManagement.GetGrainActivationCount((GrainReference)grainFactory.GetGrain(g))).ToArray();\n            await Task.WhenAll(tasks);\n            return tasks.Sum(t => t.Result);\n        }\n    }\n\n    internal class ProducerProxy\n    {\n        private readonly IStreaming_ProducerGrain[] _targets;\n        private readonly ILogger _logger;\n        private readonly Guid _streamId;\n        private readonly string _providerName;\n        private readonly InterlockedFlag _cleanedUpFlag;\n\n        public Task<int> ExpectedItemsProduced\n        {\n            get { return GetExpectedItemsProduced(); }\n        }\n\n        public string ProviderName { get { return _providerName; } }\n\n        public Guid StreamIdGuid { get { return _streamId; } }\n\n        public StreamId StreamId { get; }\n\n        private ProducerProxy(IStreaming_ProducerGrain[] targets, Guid streamId, string providerName, ILogger logger)\n        {\n            _targets = targets;\n            _logger = logger;\n            _streamId = streamId;\n            _providerName = providerName;\n            _cleanedUpFlag = new InterlockedFlag();\n            StreamId = StreamId.Create(null, streamId);\n        }\n\n        private static async Task<ProducerProxy> NewProducerProxy(IStreaming_ProducerGrain[] targets, Guid streamId, string streamProvider, string streamNamespace, ILogger logger)\n        {\n            if (targets == null)\n                throw new ArgumentNullException(nameof(targets));\n            if (string.IsNullOrWhiteSpace(streamProvider))\n                throw new ArgumentException(\"Stream provider name is either null or whitespace\", nameof(streamProvider));\n            if (logger == null)\n                throw new ArgumentNullException(nameof(logger));\n\n            ProducerProxy newObj = new ProducerProxy(targets, streamId, streamProvider, logger);\n            await newObj.BecomeProducer(streamId, streamProvider, streamNamespace);\n            return newObj;\n        }\n\n        public static Task<ProducerProxy> NewProducerGrainsAsync(Guid streamId, string streamProvider, string streamNamespace, ILogger logger, IInternalGrainFactory grainFactory, Guid[] grainIds = null, int grainCount = 1)\n        {\n            grainCount = grainIds != null ? grainIds.Length : grainCount;\n            if (grainCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(grainCount), \"The grain count must be at least one\");\n            logger.LogInformation(\"ProducerProxy.NewProducerGrainsAsync: multiplexing {GrainCount} producer grains for stream {StreamId}.\", grainCount, streamId);\n            var grains = new IStreaming_ProducerGrain[grainCount];\n            var dedup = new Dictionary<Guid, IStreaming_ProducerGrain>();\n            var producerGrainFullName = typeof(Streaming_ProducerGrain).FullName;\n            for (var i = 0; i < grainCount; ++i)\n            {\n                if (grainIds != null)\n                {\n                    // we deduplicate the grain references to ensure that IEnumerable.Distinct() works as intended.\n                    if (dedup.ContainsKey(grainIds[i]))\n                        grains[i] = dedup[grainIds[i]];\n                    else\n                    {\n                        var gref = grainFactory.GetGrain<IStreaming_ProducerGrain>(grainIds[i], producerGrainFullName);\n                        grains[i] = gref;\n                        dedup[grainIds[i]] = gref;\n                    }\n                }\n                else\n                {\n                    grains[i] = grainFactory.GetGrain<IStreaming_ProducerGrain>(Guid.NewGuid(), producerGrainFullName);\n                }\n            }\n            return NewProducerProxy(grains, streamId, streamProvider, streamNamespace, logger);\n        }\n\n        public static Task<ProducerProxy> NewProducerConsumerGrainsAsync(Guid streamId, string streamProvider, ILogger logger, int[] grainIds, bool useReentrantGrain, IInternalGrainFactory grainFactory)\n        {\n            int grainCount = grainIds.Length;\n            if (grainCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(grainIds), \"The grain count must be at least one\");\n            logger.LogInformation(\"ConsumerProxy.NewProducerConsumerGrainsAsync: multiplexing {GrainCount} producer grains for stream {StreamId}.\", grainCount, streamId);\n            var grains = new IStreaming_ProducerGrain[grainCount];\n            var dedup = new Dictionary<int, IStreaming_ProducerGrain>();\n            for (var i = 0; i < grainCount; ++i)\n            {\n                    // we deduplicate the grain references to ensure that IEnumerable.Distinct() works as intended.\n                    if (dedup.ContainsKey(grainIds[i]))\n                        grains[i] = dedup[grainIds[i]];\n                    else\n                    {\n                        if (useReentrantGrain)\n                        {\n                            grains[i] = grainFactory.GetGrain<IStreaming_Reentrant_ProducerConsumerGrain>(grainIds[i]);\n                        }\n                        else\n                        {\n                            var grainFullName = typeof(Streaming_ProducerConsumerGrain).FullName;\n                            grains[i] = grainFactory.GetGrain<IStreaming_ProducerConsumerGrain>(grainIds[i], grainFullName);\n                        }\n                        dedup[grainIds[i]] = grains[i];\n                    }                    \n                }\n            return NewProducerProxy(grains, streamId, streamProvider, null, logger);\n        }\n\n        public static Task<ProducerProxy> NewProducerClientObjectsAsync(Guid streamId, string streamProvider,  string streamNamespace, ILogger logger, IClusterClient client, int producersCount = 1)\n        {            \n            if (producersCount < 1)\n                throw new ArgumentOutOfRangeException(nameof(producersCount), \"The producer count must be at least one\");\n            var producers = new IStreaming_ProducerGrain[producersCount];\n            for (var i = 0; i < producersCount; ++i)\n                producers[i] = Streaming_ProducerClientObject.NewObserver(logger, client);\n            logger.LogInformation(\"ProducerProxy.NewProducerClientObjectsAsync: multiplexing {ProducerCount} producer client objects for stream {StreamId}.\", producersCount, streamId);\n            return NewProducerProxy(producers, streamId, streamProvider, streamNamespace, logger);\n        }\n\n        private Task BecomeProducer(Guid streamId, string providerToUse, string streamNamespace)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            return Task.WhenAll(_targets.Select(\n                target => \n                    target.BecomeProducer(streamId, providerToUse, streamNamespace)).ToArray());\n        }\n\n        public async Task ProduceSequentialSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            foreach (var t in _targets.Distinct())\n                await t.ProduceSequentialSeries(count); \n        }\n            \n        public Task ProduceParallelSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            return Task.WhenAll(_targets.Distinct().Select(t => t.ProduceParallelSeries(count)).ToArray());\n        }\n\n        public Task ProducePeriodicSeries(int count)\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            return Task.WhenAll(_targets.Distinct().Select(t => t.ProducePeriodicSeries(count)).ToArray());\n        }\n\n        public async Task<Guid> AddNewConsumerGrain()\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            if (_targets.Length != 1)\n                throw new InvalidOperationException(\"This method is only supported for singular producer cases\");\n            // disabled temporarily.\n            // return _targets[0].AddNewConsumerGrain();\n            Guid consumerGrainId = Guid.NewGuid();\n            await _targets[0].AddNewConsumerGrain(consumerGrainId);\n            return consumerGrainId;\n        }\n\n        private async Task<int> GetExpectedItemsProduced()\n        {\n            _cleanedUpFlag.ThrowNotInitializedIfSet();\n\n            var tasks = _targets.Distinct().Select(t => t.GetExpectedItemsProduced()).ToArray();\n            await Task.WhenAll(tasks);\n            return tasks.Sum(t => t.Result);\n        }\n\n        private async Task<int> GetProducerCount()\n        {\n            var tasks = _targets.Distinct().Select(p => p.GetProducerCount()).ToArray();\n            await Task.WhenAll(tasks);\n            return tasks.Sum(t => t.Result);\n        }\n\n        public Task<int> ProducerCount\n        {\n            get\n            {\n                // This method is used by the test code to verify that the object has in fact been disposed properly,\n                // so we choose not to throw if the object has already been disposed.\n                return GetProducerCount();\n            }\n        }\n\n        public async Task StopBeingProducer()\n        {\n            if (!_cleanedUpFlag.TrySet())\n                return;\n                \n            var tasks = new List<Task>();\n            foreach (var i in _targets.Distinct())\n            {\n                tasks.Add(i.StopBeingProducer());\n            }\n            await Task.WhenAll(tasks);\n\n            tasks = new List<Task>();\n            foreach (var i in _targets.Distinct())\n            {\n                tasks.Add(i.VerifyFinished());\n            }\n            await Task.WhenAll(tasks);\n        }\n\n        public Task DeactivateOnIdle()\n        {\n            var tasks = _targets.Distinct().Select(t => t.DeactivateProducerOnIdle()).ToArray();\n            return Task.WhenAll(tasks);\n        }\n\n        public Task<int> GetNumActivations(IInternalGrainFactory grainFactory)\n        {\n            return ConsumerProxy.GetNumActivations(_targets.Distinct(), grainFactory);\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamTestUtils.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace UnitTests.StreamingTests\n{\n    internal class StreamTestUtils\n    {\n        public const string AZURE_QUEUE_STREAM_PROVIDER_NAME = \"AzureQueueProvider\";\n\n        internal static void LogStartTest(string testName, Guid streamId, string streamProviderName, ILogger logger, TestCluster siloHost)\n        {\n            SiloAddress primSilo = siloHost.Primary?.SiloAddress;\n            SiloAddress secSilo = siloHost.SecondarySilos.FirstOrDefault()?.SiloAddress;\n            logger.LogInformation(\n                \"\\n\\n**START********************** {TestName} ********************************* \\n\\n\"\n                + \"Running with initial silos Primary={PrimarySilo} Secondary={SecondarySilo} StreamId={StreamId} StreamProviderName={StreamProviderName} \\n\\n\",\n                testName,\n                primSilo,\n                secSilo,\n                streamId,\n                streamProviderName);\n        }\n\n        internal static void LogEndTest(string testName, ILogger logger)\n        {\n            logger.LogInformation(\"\\n\\n--END------------------------ {TestName} --------------------------------- \\n\\n\", testName);\n        }\n\n        internal static IStreamPubSub GetStreamPubSub(IInternalClusterClient client)\n        {\n            var runtime = client.ServiceProvider.GetRequiredService<IStreamProviderRuntime>();\n            return runtime.PubSub(StreamPubSubType.ExplicitGrainBasedAndImplicit);\n        }\n\n        internal static async Task CheckPubSubCounts(IInternalClusterClient client, ITestOutputHelper output, string when, int expectedPublisherCount, int expectedConsumerCount, Guid streamIdGuid, string streamProviderName, string streamNamespace)\n        {\n            var pubSub = GetStreamPubSub(client);\n            var streamId = new QualifiedStreamId(streamProviderName, StreamId.Create(streamNamespace, streamIdGuid));\n            var totalWait = TimeSpan.Zero;\n\n            int consumerCount;\n            while ((consumerCount = await pubSub.ConsumerCount(streamId)) != expectedConsumerCount)\n            {\n                await Task.Delay(1000);\n                totalWait += TimeSpan.FromMilliseconds(1000);\n                if (totalWait > TimeSpan.FromMilliseconds(5000))\n                {\n                    break;\n                }\n            }\n\n            Assert_AreEqual(output, expectedConsumerCount, consumerCount, \"{0} - ConsumerCount for stream {1} = {2}\",\n                when, streamId, consumerCount);\n\n            int publisherCount;\n            totalWait = TimeSpan.Zero;\n            while ((publisherCount = await pubSub.ProducerCount(streamId)) != expectedPublisherCount)\n            {\n                await Task.Delay(1000);\n                totalWait += TimeSpan.FromMilliseconds(1000);\n                if (totalWait > TimeSpan.FromMilliseconds(5000))\n                {\n                    break;\n                }\n            }\n\n            Assert_AreEqual(output, expectedPublisherCount, publisherCount, \"{0} - PublisherCount for stream {1} = {2}\",\n                when, streamId, publisherCount);\n        }\n\n        internal static void Assert_AreEqual(ITestOutputHelper output, int expected, int actual, string msg, params object[] args)\n        {\n            // expected == -1 means don't care / don't assert check value.\n            string prefix = expected == -1 ? \"Not-checked\" : actual == expected ? \"True\" : \"FALSE\";\n            string fmtMsg = string.Format(\"--> {0}: \", prefix) + string.Format(msg, args);\n            output.WriteLine(fmtMsg);\n            if (expected != -1)\n            {\n                Assert.Equal(expected, actual);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamingCacheMissTests.cs",
    "content": "using Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.Streams.Filtering;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests for stream caching behavior and cache miss scenarios.\n    /// \n    /// Orleans streaming providers use caching to improve performance by:\n    /// - Batching messages for delivery\n    /// - Avoiding repeated deserialization\n    /// - Enabling recovery from temporary failures\n    /// \n    /// These tests verify correct behavior when:\n    /// - Events are evicted from cache due to age or memory pressure\n    /// - Filtered events interact with cache eviction\n    /// - Multiple streams compete for cache space\n    /// </summary>\n    public abstract class StreamingCacheMissTests : TestClusterPerTest\n    {\n        protected static readonly TimeSpan DataMaxAgeInCache = TimeSpan.FromSeconds(5);\n        protected static readonly TimeSpan DataMinTimeInCache = TimeSpan.FromSeconds(0);\n        protected const string StreamProviderName = \"StreamingCacheMissTests\";\n\n        private readonly ITestOutputHelper output;\n\n        /// <summary>\n        /// Custom stream filter that only delivers messages where the first byte equals 1.\n        /// Used to test interaction between filtering and cache eviction - filtered\n        /// messages should not trigger grain activation or affect cache behavior.\n        /// </summary>\n        protected class CustomStreamFilter : IStreamFilter\n        {\n            public bool ShouldDeliver(StreamId streamId, object item, string filterData)\n            {\n                var data = item as byte[];\n                return data == default || data[0] == 1;\n            }\n        }\n\n        public StreamingCacheMissTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        /// <summary>\n        /// Tests that grains correctly handle events that were evicted from cache.\n        /// Scenario:\n        /// 1. Send an event that gets cached\n        /// 2. Wait for cache expiration and trigger eviction\n        /// 3. Send another event\n        /// Verifies that both events are delivered despite cache eviction.\n        /// </summary>\n        [SkippableFact]\n        public virtual async Task PreviousEventEvictedFromCacheTest()\n        {\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n\n            // Tested stream and corresponding grain\n            var key = Guid.NewGuid();\n            var stream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), key);\n            var grain = this.Client.GetGrain<IImplicitSubscriptionCounterGrain>(key);\n\n            // We need multiple streams, so at least another one will be handled by the same PullingAgent than \"stream\"\n            // This ensures cache pressure and increases likelihood of eviction\n            var otherStreams = new List<IAsyncStream<byte[]>>();\n            for (var i = 0; i < 20; i++)\n                otherStreams.Add(streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), Guid.NewGuid()));\n\n            // Data that will be sent to the grains\n            var interestingData = new byte[1024];\n            interestingData[0] = 1;\n\n            // Should be delivered\n            await stream.OnNextAsync(interestingData);\n\n            // Wait for cache expiration time to pass\n            // Then send events to other streams to trigger cache cleaning/eviction\n            await Task.Delay(TimeSpan.FromSeconds(6));\n            otherStreams.ForEach(s => s.OnNextAsync(interestingData));\n\n            // Should be delivered\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(5_000);\n\n            Assert.Equal(0, await grain.GetErrorCounter());\n            Assert.Equal(2, await grain.GetEventCounter());\n        }\n\n        /// <summary>\n        /// Tests cache eviction behavior with filtered events.\n        /// Verifies that:\n        /// - Filtered events don't prevent cache eviction\n        /// - Non-filtered events are still delivered after cache eviction\n        /// - Filter state doesn't interfere with cache management\n        /// </summary>\n        [SkippableFact]\n        public virtual async Task PreviousEventEvictedFromCacheWithFilterTest()\n        {\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n\n            // Tested stream and corresponding grain\n            var key = Guid.NewGuid();\n            var stream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), key);\n            var grain = this.Client.GetGrain<IImplicitSubscriptionCounterGrain>(key);\n\n            // We need multiple streams, so at least another one will be handled by the same PullingAgent than \"stream\"\n            // This ensures cache pressure and increases likelihood of eviction\n            var otherStreams = new List<IAsyncStream<byte[]>>();\n            for (var i = 0; i < 20; i++)\n                otherStreams.Add(streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), Guid.NewGuid()));\n\n            // Data that will always be filtered\n            var skippedData = new byte[1024];\n            skippedData[0] = 2;\n\n            // Data that will be sent to the grains\n            var interestingData = new byte[1024];\n            interestingData[0] = 1;\n\n            // Send filtered data that should not reach the grain\n            await stream.OnNextAsync(skippedData);\n\n            // Wait for cache expiration and trigger eviction with more filtered events\n            // This tests that filtered events in cache don't affect delivery guarantees\n            await Task.Delay(TimeSpan.FromSeconds(6));\n            otherStreams.ForEach(s => s.OnNextAsync(skippedData));\n\n            // Should be delivered\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(1000);\n\n            Assert.Equal(0, await grain.GetErrorCounter());\n            Assert.Equal(1, await grain.GetEventCounter());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/StreamingResumeTests.cs",
    "content": "using Orleans.Streams;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester.StreamingTests\n{\n    public abstract class StreamingResumeTests : TestClusterPerTest\n    {\n        protected static readonly TimeSpan StreamInactivityPeriod = TimeSpan.FromSeconds(5);\n        protected static readonly TimeSpan MetadataMinTimeInCache = StreamInactivityPeriod * 100;\n        protected static readonly TimeSpan DataMaxAgeInCache = StreamInactivityPeriod * 5;\n        protected static readonly TimeSpan DataMinTimeInCache = StreamInactivityPeriod * 4;\n\n        protected const string StreamProviderName = \"StreamingCacheMissTests\";\n\n        [SkippableFact]\n        public virtual async Task ResumeAfterInactivity()\n        {\n            await ResumeAfterInactivityImpl(false);\n        }\n\n        [SkippableFact]\n        public virtual async Task ResumeAfterInactivityNotInCache()\n        {\n            await ResumeAfterInactivityImpl(true);\n        }\n\n        protected virtual async Task ResumeAfterInactivityImpl(bool waitForCacheToFlush)\n        {\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n\n            // Tested stream and corresponding grain\n            var key = Guid.NewGuid();\n            var stream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), key);\n            var grain = this.Client.GetGrain<IImplicitSubscriptionCounterGrain>(key);\n\n            // Data that will be sent to the grains\n            var interestingData = new byte[1] { 1 };\n\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(1_000);\n\n            // Wait for the stream to become inactive\n            await Task.Delay(StreamInactivityPeriod.Multiply(3));\n\n            if (waitForCacheToFlush)\n            {\n                for (var i = 0; i < 5; i++)\n                {\n                    var otherStream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), Guid.NewGuid());\n                    await otherStream.OnNextAsync(interestingData);\n                }\n                // Wait a bit more for the cache to flush some events\n                await Task.Delay(StreamInactivityPeriod.Multiply(3));\n                for (var i = 0; i < 5; i++)\n                {\n                    var otherStream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), Guid.NewGuid());\n                    await otherStream.OnNextAsync(interestingData);\n                }\n            }\n\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(2_000);\n\n            Assert.Equal(0, await grain.GetErrorCounter());\n            Assert.Equal(2, await grain.GetEventCounter());\n        }\n\n        [SkippableFact]\n        public virtual async Task ResumeAfterDeactivation()\n        {\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n\n            // Tested stream and corresponding grain\n            var key = Guid.NewGuid();\n            var stream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), key);\n            var grain = this.Client.GetGrain<IImplicitSubscriptionCounterGrain>(key);\n\n            // Data that will be sent to the grains\n            var interestingData = new byte[1] { 1 };\n\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(1_000);\n\n            // Wait for the stream to become inactive\n            await Task.Delay(StreamInactivityPeriod.Multiply(3));\n            await grain.Deactivate();\n\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(2_000);\n\n            Assert.Equal(0, await grain.GetErrorCounter());\n            Assert.Equal(2, await grain.GetEventCounter());\n        }\n\n        [SkippableFact]\n        public virtual async Task ResumeAfterDeactivationActiveStream()\n        {\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n\n            // Tested stream and corresponding grain\n            var key = Guid.NewGuid();\n            var stream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), key);\n            var otherStream = streamProvider.GetStream<byte[]>(nameof(IImplicitSubscriptionCounterGrain), Guid.NewGuid());\n            var grain = this.Client.GetGrain<IImplicitSubscriptionCounterGrain>(key);\n            await grain.DeactivateOnEvent(true);\n\n            // Data that will be sent to the grains\n            var interestingData = new byte[1] { 1 };\n\n            await stream.OnNextAsync(interestingData);\n            // Push other data\n            await otherStream.OnNextAsync(interestingData);\n            await otherStream.OnNextAsync(interestingData);\n            await otherStream.OnNextAsync(interestingData);\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(1_000);\n\n            // Wait for the stream to become inactive\n            await Task.Delay(StreamInactivityPeriod.Multiply(3));\n            await grain.Deactivate();\n\n            await stream.OnNextAsync(interestingData);\n\n            await Task.Delay(2_000);\n\n            Assert.Equal(0, await grain.GetErrorCounter());\n            Assert.Equal(3, await grain.GetEventCounter());\n        }\n\n        [SkippableFact]\n        public virtual async Task ResumeAfterSlowSubscriber()\n        {\n            var key = Guid.NewGuid();\n            var streamProvider = this.Client.GetStreamProvider(StreamProviderName);\n            var stream = streamProvider.GetStream<byte[]>(\"FastSlowImplicitSubscriptionCounterGrain\", key);\n\n            var fastGrain = this.Client.GetGrain<IFastImplicitSubscriptionCounterGrain>(key);\n            var slowGrain = this.Client.GetGrain<ISlowImplicitSubscriptionCounterGrain>(key);\n\n            await stream.OnNextAsync([1]);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckFastCounter(1, lastTry), TimeSpan.FromSeconds(30));\n\n            await stream.OnNextAsync([2]);\n            await TestingUtils.WaitUntilAsync(lastTry => CheckFastCounter(2, lastTry), TimeSpan.FromSeconds(30));\n\n            async Task<bool> CheckFastCounter(int expected, bool lastTry)\n            {\n                var actual = await fastGrain.GetEventCounter();\n                if (lastTry)\n                {\n                    Assert.Equal(expected, actual);\n                }\n\n                return actual == expected;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/SubscriptionMultiplicityTestRunner.cs",
    "content": "using System.Diagnostics;\nusing System.Diagnostics.Metrics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Runtime;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace UnitTests.StreamingTests\n{\n    public class SubscriptionMultiplicityTestRunner\n    {\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n        private readonly string streamProviderName;\n        private readonly ILogger logger;\n        private readonly TestCluster testCluster;\n\n        public SubscriptionMultiplicityTestRunner(string streamProviderName, TestCluster testCluster)\n        {\n            if (string.IsNullOrWhiteSpace(streamProviderName))\n            {\n                throw new ArgumentNullException(nameof(streamProviderName));\n            }\n            this.streamProviderName = streamProviderName;\n            this.logger = testCluster.Client.ServiceProvider.GetRequiredService<ILogger<SubscriptionMultiplicityTestRunner>>();\n            this.testCluster = testCluster;\n        }\n\n        public async Task MultipleParallelSubscriptionTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            // setup two subscriptions\n            StreamSubscriptionHandle<int> firstSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n            StreamSubscriptionHandle<int> secondSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            // produce some messages\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            await RunFor(() => producer.Produce(), TimeSpan.FromSeconds(1));\n\n            // check\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 2, lastTry), Timeout);\n\n            // unsubscribe\n            await consumer.StopConsuming(firstSubscriptionHandle);\n            await consumer.StopConsuming(secondSubscriptionHandle);\n        }\n\n        public async Task MultipleLinearSubscriptionTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // setup one subscription and send messsages\n            StreamSubscriptionHandle<int> firstSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // clear counts\n            await consumer.ClearNumberConsumed();\n            await producer.ClearNumberProduced();\n            // remove first subscription and send messages\n            await consumer.StopConsuming(firstSubscriptionHandle);\n\n            // setup second subscription and send messages\n            StreamSubscriptionHandle<int> secondSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // remove second subscription\n            await consumer.StopConsuming(secondSubscriptionHandle);\n        }\n\n        public async Task MultipleSubscriptionTest_AddRemove(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // setup one subscription and send messsages\n            StreamSubscriptionHandle<int> firstSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // clear counts\n            await consumer.ClearNumberConsumed();\n            await producer.ClearNumberProduced();\n\n            // setup second subscription and send messages\n            StreamSubscriptionHandle<int> secondSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 2, lastTry), Timeout);\n\n            // clear counts\n            await consumer.ClearNumberConsumed();\n            await producer.ClearNumberProduced();\n\n            // remove first subscription and send messages\n            await consumer.StopConsuming(firstSubscriptionHandle);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // remove second subscription\n            await consumer.StopConsuming(secondSubscriptionHandle);\n        }\n\n        public async Task ResubscriptionTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // setup one subscription and send messsages\n            StreamSubscriptionHandle<int> firstSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // Resume\n            StreamSubscriptionHandle<int> resumeHandle = await consumer.Resume(firstSubscriptionHandle);\n\n            Assert.Equal(firstSubscriptionHandle, resumeHandle);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // remove subscription\n            await consumer.StopConsuming(resumeHandle);\n        }\n\n        public async Task ResubscriptionAfterDeactivationTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            // setup one subscription and send messsages\n            StreamSubscriptionHandle<int> firstSubscriptionHandle = await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // Deactivate grain\n            await consumer.Deactivate();\n\n            // make sure grain has time to deactivate.\n            await Task.Delay(TimeSpan.FromMilliseconds(100));\n\n            // clear producer counts\n            await producer.ClearNumberProduced();\n\n            // Resume\n            StreamSubscriptionHandle<int> resumeHandle = await consumer.Resume(firstSubscriptionHandle);\n\n            Assert.Equal(firstSubscriptionHandle, resumeHandle);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // remove subscription\n            await consumer.StopConsuming(resumeHandle);\n        }\n\n        public async Task ActiveSubscriptionTest(Guid streamGuid, string streamNamespace)\n        {\n            const int subscriptionCount = 10;\n\n            // get producer and consumer\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            // create expected subscriptions\n            IEnumerable<Task<StreamSubscriptionHandle<int>>> subscriptionTasks =\n                Enumerable.Range(0, subscriptionCount)\n                    .Select(async i => await consumer.BecomeConsumer(streamGuid, streamNamespace, streamProviderName));\n            List<StreamSubscriptionHandle<int>> expectedSubscriptions = (await Task.WhenAll(subscriptionTasks)).ToList();\n\n            // query actuall subscriptions\n            IList<StreamSubscriptionHandle<int>> actualSubscriptions = await consumer.GetAllSubscriptions(streamGuid, streamNamespace, streamProviderName);\n\n            // validate\n            Assert.Equal(subscriptionCount, actualSubscriptions.Count);\n            Assert.Equal(subscriptionCount, expectedSubscriptions.Count);\n            foreach (StreamSubscriptionHandle<int> subscription in actualSubscriptions)\n            {\n                Assert.True(expectedSubscriptions.Contains(subscription), \"Subscription Match\");\n            }\n\n            // unsubscribe from one of the subscriptions\n            StreamSubscriptionHandle<int> firstHandle = expectedSubscriptions.First();\n            await consumer.StopConsuming(firstHandle);\n            expectedSubscriptions.Remove(firstHandle);\n\n            // query actuall subscriptions again\n            actualSubscriptions = await consumer.GetAllSubscriptions(streamGuid, streamNamespace, streamProviderName);\n\n            // validate\n            Assert.Equal(subscriptionCount-1, actualSubscriptions.Count);\n            Assert.Equal(subscriptionCount-1, expectedSubscriptions.Count);\n            foreach (StreamSubscriptionHandle<int> subscription in actualSubscriptions)\n            {\n                Assert.True(expectedSubscriptions.Contains(subscription), \"Subscription Match\");\n            }\n\n            // unsubscribe from the rest of the subscriptions\n            await Task.WhenAll(expectedSubscriptions.Select(h => consumer.StopConsuming(h)));\n\n            // query actuall subscriptions again\n            actualSubscriptions = await consumer.GetAllSubscriptions(streamGuid, streamNamespace, streamProviderName);\n\n            // validate\n            Assert.Empty(actualSubscriptions);\n        }\n\n        public async Task TwoIntermitentStreamTest(Guid streamGuid)\n        {\n            const string streamNamespace1 = \"streamNamespace1\";\n            const string streamNamespace2 = \"streamNamespace2\";\n\n            // send events on first stream /////////////////////////////\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer.BecomeProducer(streamGuid, streamNamespace1, streamProviderName);\n\n            StreamSubscriptionHandle<int> handle = await consumer.BecomeConsumer(streamGuid, streamNamespace1, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            // send some events on second stream /////////////////////////////\n            var producer2 = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            var consumer2 = this.testCluster.GrainFactory.GetGrain<IMultipleSubscriptionConsumerGrain>(Guid.NewGuid());\n\n            await producer2.BecomeProducer(streamGuid, streamNamespace2, streamProviderName);\n\n            StreamSubscriptionHandle<int> handle2 = await consumer2.BecomeConsumer(streamGuid, streamNamespace2, streamProviderName);\n\n            await producer2.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer2.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer2, consumer2, 1, lastTry), Timeout);\n\n            // send some events on first stream again /////////////////////////////\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, consumer, 1, lastTry), Timeout);\n\n            await consumer.StopConsuming(handle);\n            await consumer2.StopConsuming(handle2);\n        }\n\n        public async Task SubscribeFromClientTest(Guid streamGuid, string streamNamespace)\n        {\n            // get producer and consumer\n            var producer = this.testCluster.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(Guid.NewGuid());\n            int eventCount = 0;\n\n            var provider = this.testCluster.Client.ServiceProvider.GetKeyedService<IStreamProvider>(streamProviderName);\n            var stream = provider.GetStream<int>(streamNamespace, streamGuid);\n            var handle = await stream.SubscribeAsync((e,t) =>\n            {\n                eventCount++;\n                return Task.CompletedTask;\n            });\n\n            // produce some messages\n            await producer.BecomeProducer(streamGuid, streamNamespace, streamProviderName);\n\n            await producer.StartPeriodicProducing();\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await producer.StopPeriodicProducing();\n\n            // check\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(producer, () => eventCount, lastTry), Timeout);\n\n            // unsubscribe\n            await handle.UnsubscribeAsync();\n        }\n\n        private async Task<bool> CheckCounters(ISampleStreaming_ProducerGrain producer, IMultipleSubscriptionConsumerGrain consumer, int consumerCount, bool assertIsTrue)\n        {\n            var numProduced = await producer.GetNumberProduced();\n            var numConsumed = await consumer.GetNumberConsumed();\n            if (assertIsTrue)\n            {\n                Assert.True(numConsumed.Values.All(v => v.Item2 == 0), \"Errors\");\n                Assert.True(numProduced > 0, \"Events were not produced\");\n                Assert.Equal(consumerCount, numConsumed.Count);\n                foreach (int consumed in numConsumed.Values.Select(v => v.Item1))\n                {\n                    Assert.Equal(numProduced, consumed);\n                }\n            }\n            else if (numProduced <= 0 || // no events produced?\n                     consumerCount != numConsumed.Count || // subscription counts are wrong?\n                     numConsumed.Values.Any(consumedCount => consumedCount.Item1 != numProduced) ||// consumed events don't match produced events for any subscription?\n                     numConsumed.Values.Any(v => v.Item2 != 0)) // stream errors\n            {\n                if (numProduced <= 0)\n                {\n                    logger.LogInformation(\"numProduced <= 0: Events were not produced\");\n                }\n                if (consumerCount != numConsumed.Count)\n                {\n                    logger.LogInformation(\n                        \"consumerCount != numConsumed.Count: Incorrect number of consumers. consumerCount = {ConsumerCount}, numConsumed.Count = {ConsumedCount}\",\n                        consumerCount,\n                        numConsumed.Count);\n                }\n                foreach (var consumed in numConsumed)\n                {\n                    if (numProduced != consumed.Value.Item1)\n                    {\n                        logger.LogInformation(\"numProduced != consumed: Produced and consumed counts do not match. numProduced = {ProducedCount}, consumed = {ConsumedCount}\",\n                            numProduced, consumed.Key.HandleId + \" -> \" + consumed.Value);\n                            //numProduced, Utils.DictionaryToString(numConsumed));\n                    }\n                }\n                return false;\n            }\n\n            logger.LogInformation(\n                \"All counts are equal. numProduced = {ProducedCount}, numConsumed = {ConsumedCount}\",\n                numProduced,\n                Utils.EnumerableToString(\n                    numConsumed,\n                    kvp => kvp.Key.HandleId.ToString() + \"->\" + kvp.Value.ToString()));\n            return true;\n        }\n\n        private async Task<bool> CheckCounters(ISampleStreaming_ProducerGrain producer, Func<int> eventCount, bool assertIsTrue)\n        {\n            var numProduced = await producer.GetNumberProduced();\n            var numConsumed = eventCount();\n            if (assertIsTrue)\n            {\n                Assert.True(numProduced > 0, \"Events were not produced\");\n                Assert.Equal(numProduced, numConsumed);\n            }\n            else if (numProduced <= 0 || // no events produced?\n                     numProduced != numConsumed)\n            {\n                if (numProduced <= 0)\n                {\n                    logger.LogInformation(\"numProduced <= 0: Events were not produced\");\n                }\n                if (numProduced != numConsumed)\n                {\n                    logger.LogInformation(\n                        \"numProduced != numConsumed: Produced and consumed counts do not match. numProduced = {ProducedCount}, consumed = {ConsumedCount}\",\n                        numProduced,\n                        numConsumed);\n                }\n                return false;\n            }\n\n            logger.LogInformation(\n                \"All counts are equal. numProduced = {ProducedCount}, numConsumed = {ConsumedCount}\",\n                numProduced,\n                numConsumed);\n            return true;\n        }\n\n        private async Task RunFor(Func<Task> func, TimeSpan duration)\n        {\n            var sw = Stopwatch.StartNew();\n            do\n            {\n                await func();\n            }\n            while (sw.Elapsed < duration);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/StreamingTests/SystemTargetRouteTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Providers;\nusing Orleans.Streams;\nusing Orleans.TestingHost;\nusing Orleans.TestingHost.Utils;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\n\nnamespace Tester.StreamingTests\n{\n    /// <summary>\n    /// Tests for persistent streaming over single gateway configurations, validating system target routing behavior.\n    /// </summary>\n    public class SystemTargetRouteTests : OrleansTestingBase, IClassFixture<SystemTargetRouteTests.Fixture>\n    {\n        private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);\n        private int eventsConsumed = 0;\n\n        public class Fixture : BaseTestClusterFixture\n        {\n            public const string StreamProviderName = \"MemoryStreamProvider\";\n            private const int partitionCount = 8;\n            protected override void ConfigureTestCluster(TestClusterBuilder builder)\n            {\n                builder.Options.GatewayPerSilo = false;\n                builder.AddSiloBuilderConfigurator<MySiloBuilderConfigurator>();\n                builder.AddClientBuilderConfigurator<MyClientBuilderConfigurator>();\n            }\n\n            private class MyClientBuilderConfigurator : IClientBuilderConfigurator\n            {\n                public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => clientBuilder\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b=>b\n                    .ConfigurePartitioning(partitionCount));\n            }\n\n            private class MySiloBuilderConfigurator : ISiloConfigurator\n            {\n                public void Configure(ISiloBuilder hostBuilder) => hostBuilder\n                    .AddMemoryGrainStorage(\"PubSubStore\")\n                    .AddMemoryStreams<DefaultMemoryMessageBodySerializer>(StreamProviderName, b=>b\n                    .ConfigurePartitioning(partitionCount));\n            }\n        }\n\n        private readonly Fixture fixture;\n\n        public SystemTargetRouteTests(Fixture fixture)\n        {\n            this.fixture = fixture;\n        }\n\n        [SkippableFact(Skip = \"https://github.com/dotnet/orleans/issues/4320\"), TestCategory(\"Functional\"), TestCategory(\"Streaming\")]\n        public async Task PersistentStreamingOverSingleGatewayTest()\n        {\n            const int streamCount = 100;\n\n            this.fixture.Logger.LogInformation(\"************************ PersistentStreamingOverSingleGatewayTest *********************************\");\n\n            // generate stream Id's\n            List<Guid> streamIds = Enumerable.Range(0, streamCount)\n                .Select(i => Guid.NewGuid())\n                .ToList();\n\n            // subscribe to all streams\n            foreach(Guid streamId in streamIds)\n            {\n                IStreamProvider streamProvider = this.fixture.Client.GetStreamProvider(Fixture.StreamProviderName);\n                IAsyncObservable<int> stream = streamProvider.GetStream<int>(streamId);\n                await stream.SubscribeAsync(OnNextAsync);\n            }\n\n            // create producer grains\n            List<ISampleStreaming_ProducerGrain> producers = streamIds\n                .Select(id => this.fixture.GrainFactory.GetGrain<ISampleStreaming_ProducerGrain>(id))\n                .ToList();\n\n            // become producers\n            await Task.WhenAll(Enumerable.Range(0, streamCount).Select(i => producers[i].BecomeProducer(streamIds[i], null, Fixture.StreamProviderName)));\n\n            // produce some events\n            await Task.WhenAll(Enumerable.Range(0, streamCount).Select(i => producers[i].StartPeriodicProducing()));\n            await Task.Delay(TimeSpan.FromMilliseconds(1000));\n            await Task.WhenAll(Enumerable.Range(0, streamCount).Select(i => producers[i].StopPeriodicProducing()));\n\n            int[] counts = await Task.WhenAll(Enumerable.Range(0, streamCount).Select(i => producers[i].GetNumberProduced()));\n\n            // make sure all went well\n            await TestingUtils.WaitUntilAsync(lastTry => CheckCounters(counts.Sum(), lastTry), Timeout);\n        }\n\n        private Task OnNextAsync(int e, StreamSequenceToken token)\n        {\n            Interlocked.Increment(ref this.eventsConsumed);\n            return Task.CompletedTask;\n        }\n\n        private Task<bool> CheckCounters(int eventsProduced, bool assertIsTrue)\n        {\n            int numConsumed = this.eventsConsumed;\n            if (!assertIsTrue) return Task.FromResult(eventsProduced == numConsumed);\n            Assert.Equal(eventsProduced, numConsumed);\n            return Task.FromResult(true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Orleans.Streaming.Tests/TestStreamProviders/Controllable/ControllableTestStreamProvider.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Configuration;\nusing Orleans.Providers;\nusing Orleans.Providers.Streams.Common;\nusing Orleans.Runtime;\nusing Orleans.Streams;\n\nnamespace Tester.TestStreamProviders.Controllable\n{\n    [GenerateSerializer]\n    public enum ControllableTestStreamProviderCommands\n    {\n        AdapterEcho = PersistentStreamProviderCommand.AdapterCommandStartRange + 1,\n        AdapterFactoryEcho = PersistentStreamProviderCommand.AdapterFactoryCommandStartRange + 1,\n    }\n\n    public class ControllableTestAdapterFactory : IQueueAdapter, IQueueAdapterFactory, IControllable\n    {\n        public string Name { get; private set; }\n\n        public Task QueueMessageBatchAsync<T>(StreamId streamId, IEnumerable<T> events, StreamSequenceToken token,\n            Dictionary<string, object> requestContext)\n        {\n            return Task.CompletedTask;\n        }\n\n        public IQueueAdapterReceiver CreateReceiver(QueueId queueId)\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool IsRewindable { get; private set; }\n        public StreamProviderDirection Direction { get; private set; }\n\n        public ControllableTestAdapterFactory(string name)\n        {\n            Name = name;\n        }\n\n        public Task<IQueueAdapter> CreateAdapter()\n        {\n            return Task.FromResult<IQueueAdapter>(this);\n        }\n\n        public IQueueAdapterCache GetQueueAdapterCache()\n        {\n            throw new NotImplementedException();\n        }\n\n        public IStreamQueueMapper GetStreamQueueMapper()\n        {\n            var options = new HashRingStreamQueueMapperOptions();\n            options.TotalQueueCount = 0;\n            return new HashRingBasedStreamQueueMapper(options, Name);\n        }\n\n        public Task<IStreamFailureHandler> GetDeliveryFailureHandler(QueueId queueId)\n        {\n            throw new NotImplementedException();\n        }\n\n        public Task<object> ExecuteCommand(int command, object arg)\n        {\n            switch ((ControllableTestStreamProviderCommands) command)\n            {\n                case ControllableTestStreamProviderCommands.AdapterEcho:\n                    return Task.FromResult<object>(Tuple.Create(ControllableTestStreamProviderCommands.AdapterEcho, arg));\n                case ControllableTestStreamProviderCommands.AdapterFactoryEcho:\n                    return Task.FromResult<object>(Tuple.Create(ControllableTestStreamProviderCommands.AdapterFactoryEcho, arg));\n            }\n            throw new ArgumentOutOfRangeException(nameof(command));\n        }\n\n        public static ControllableTestAdapterFactory Create(IServiceProvider services, string name)\n        {\n            var factory = ActivatorUtilities.CreateInstance<ControllableTestAdapterFactory>(services, name);\n            return factory;\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/Orleans.TestingHost.Tests/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <ThrowUnobservedTaskExceptions enabled=\"false\" />\n    <gcServer enabled=\"true\" />\n    <gcConcurrent enabled=\"true\" />\n  </runtime>\n</configuration>\n"
  },
  {
    "path": "test/TestInfrastructure/Orleans.TestingHost.Tests/Grains/SimpleGrain.cs",
    "content": "﻿namespace Orleans.TestingHost.Tests.Grains\n{\n    public interface ISimpleGrain : IGrainWithIntegerKey\n    {\n        Task SetA(int a);\n        Task SetB(int b);\n        Task IncrementA();\n        Task<int> GetAxB();\n        Task<int> GetAxB(int a, int b);\n        Task<int> GetA();\n    }\n\n    /// <summary>\n    /// A simple grain that allows to set two arguments and then multiply them.\n    /// </summary>\n    public class SimpleGrain : Grain, ISimpleGrain\n    {\n        protected int A { get; set; }\n        protected int B { get; set; }\n\n        public Task SetA(int a)\n        {\n            A = a;\n            return Task.CompletedTask;\n        }\n\n        public Task SetB(int b)\n        {\n            this.B = b;\n            return Task.CompletedTask;\n        }\n\n        public Task IncrementA()\n        {\n            A = A + 1;\n            return Task.CompletedTask;\n        }\n\n        public Task<int> GetAxB()\n        {\n            return Task.FromResult(A * B);\n        }\n\n        public Task<int> GetAxB(int a, int b)\n        {\n            return Task.FromResult(a * b);\n        }\n\n        public Task<int> GetA()\n        {\n            return Task.FromResult(A);\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/Orleans.TestingHost.Tests/Orleans.TestingHost.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/TestInfrastructure/Orleans.TestingHost.Tests/TestClusterTests.cs",
    "content": "using AwesomeAssertions;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.TestingHost.Tests.Grains;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.TestingHost.Tests\n{\n    /// <summary>\n    /// Tests for Orleans TestCluster functionality.\n    /// \n    /// TestCluster is Orleans' primary testing infrastructure component that provides an in-memory\n    /// cluster environment for integration testing. It allows developers to:\n    /// - Spin up multiple silos in a single process\n    /// - Test grain interactions and cluster behavior\n    /// - Verify distributed system scenarios without external dependencies\n    /// - Configure and customize the test environment\n    /// \n    /// These tests verify TestCluster initialization, configuration, and lifecycle management.\n    /// \n    /// Each T0-T9 class tests cluster initialization in isolation to ensure\n    /// no static state interference between tests.\n    /// </summary>\n    public class T0\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n        }\n    }\n\n    public class T1\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n        }\n    }\n\n    public class T2\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n        }\n    }\n\n    public class T3\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T4\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T5\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T6\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T7\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T8\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    public class T9\n    {\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            await using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n        }\n    }\n\n    /// <summary>\n    /// Tests for TestCluster configurator functionality.\n    /// Verifies that different types of configurators (Host, Client, ClientHost)\n    /// are properly invoked during cluster initialization.\n    /// </summary>\n    public class T10\n    {\n        private static bool _hostWasInvoked;\n        private static bool _clientWasInvoked;\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ClientBuilder_HostConfigurator() => await Test<HostConfigurator>(true, false);\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ClientBuilder_ClientHostConfigurator() => await Test<ClientHostConfigurator>(true, true);\n\n        [Fact, TestCategory(\"Functional\")]\n        public async Task ClientBuilder_ClientConfigurator() => await Test<ClientConfigurator>(false, true);\n\n        private static async Task Test<TConfigurator>(bool hostInvoked, bool clientInvoked)\n            where TConfigurator : new()\n        {\n            _hostWasInvoked = false;\n            _clientWasInvoked = false;\n\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.AddClientBuilderConfigurator<TConfigurator>();\n            using var testCluster = builder.Build();\n\n            await testCluster.DeployAsync();\n            await testCluster.StopAllSilosAsync();\n\n            _hostWasInvoked.Should().Be(hostInvoked);\n            _clientWasInvoked.Should().Be(clientInvoked);\n        }\n\n        /// <summary>\n        /// Test configurator that only configures the host.\n        /// Used to verify host-only configuration scenarios.\n        /// </summary>\n        private class HostConfigurator : IHostConfigurator\n        {\n            public void Configure(IHostBuilder hostBuilder) => _hostWasInvoked = true;\n        }\n\n        /// <summary>\n        /// Test configurator that configures both host and client.\n        /// Demonstrates how a single configurator can handle both aspects\n        /// of the test cluster setup.\n        /// </summary>\n        private class ClientHostConfigurator : IHostConfigurator, IClientBuilderConfigurator\n        {\n\n            public void Configure(IHostBuilder hostBuilder) => _hostWasInvoked = true;\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => _clientWasInvoked = true;\n        }\n\n        /// <summary>\n        /// Test configurator that only configures the client.\n        /// Used to verify client-only configuration scenarios.\n        /// </summary>\n        private class ClientConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => _clientWasInvoked = true;\n        }\n    }\n\n    /// <summary>\n    /// Main test class for TestCluster functionality.\n    /// Implements IAsyncLifetime to properly manage cluster lifecycle\n    /// and ensure cleanup after tests complete.\n    /// </summary>\n    public class TestClusterTests : IAsyncLifetime\n    {\n        private TestCluster _testCluster;\n\n        /// <summary>\n        /// Tests basic TestCluster initialization and grain communication.\n        /// Verifies that:\n        /// - A cluster with multiple silos can be created\n        /// - Grains can be activated and called\n        /// - State can be set and retrieved from grains\n        /// </summary>\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitialize()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.Options.ServiceId = Guid.NewGuid().ToString();\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            _testCluster = builder.Build();\n\n            await _testCluster.DeployAsync();\n\n            var grain = _testCluster.Client.GetGrain<ISimpleGrain>(1);\n\n            await grain.SetA(2);\n            Assert.Equal(2, await grain.GetA());\n        }\n\n        /// <summary>\n        /// Tests TestCluster initialization using legacy configuration approach.\n        /// Demonstrates how to use ISiloConfigurator for backwards compatibility\n        /// with older test configuration patterns.\n        /// </summary>\n        [Fact, TestCategory(\"Functional\")]\n        public async Task CanInitializeWithLegacyConfiguration()\n        {\n            var builder = new TestClusterBuilder(2);\n            builder.ConfigureHostConfiguration(TestDefaultConfiguration.ConfigureHostConfiguration);\n            builder.AddSiloBuilderConfigurator<SiloConfigurator>();\n            _testCluster = builder.Build();\n\n            await _testCluster.DeployAsync();\n\n            var grain = _testCluster.Client.GetGrain<ISimpleGrain>(1);\n\n            await grain.SetA(2);\n            Assert.Equal(2, await grain.GetA());\n        }\n\n        /// <summary>\n        /// Example silo configurator that adds memory grain storage.\n        /// Demonstrates how to customize silo configuration in tests\n        /// using the ISiloConfigurator interface.\n        /// </summary>\n        public class SiloConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.AddMemoryGrainStorageAsDefault();\n            }\n        }\n        \n        public Task InitializeAsync()\n        {\n            return Task.CompletedTask;\n        }\n\n        public async Task DisposeAsync()\n        {\n            if (_testCluster is not null)\n            {\n                await _testCluster.DisposeAsync();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/BaseClusterFixture.cs",
    "content": "using System.Runtime.ExceptionServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\n\nnamespace TestExtensions\n{\n    public abstract class BaseTestClusterFixture : Xunit.IAsyncLifetime\n    {\n        private readonly ExceptionDispatchInfo preconditionsException;\n\n        static BaseTestClusterFixture()\n        {\n            TestDefaultConfiguration.InitializeDefaults();\n        }\n\n        protected BaseTestClusterFixture()\n        {\n            try\n            {\n                CheckPreconditionsOrThrow();\n            }\n            catch (Exception ex)\n            {\n                this.preconditionsException = ExceptionDispatchInfo.Capture(ex);\n                return;\n            }\n        }\n\n        public void EnsurePreconditionsMet()\n        {\n            this.preconditionsException?.Throw();\n        }\n\n        protected virtual void CheckPreconditionsOrThrow() { }\n\n        protected virtual void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n        }\n\n        public TestCluster HostedCluster { get; private set; }\n\n        public IGrainFactory GrainFactory => this.HostedCluster?.GrainFactory;\n\n        public IClusterClient Client => this.HostedCluster?.Client;\n\n        public ILogger Logger { get; private set; }\n        \n        public string GetClientServiceId() => Client.ServiceProvider.GetRequiredService<IOptions<ClusterOptions>>().Value.ServiceId;\n\n        public virtual async Task InitializeAsync()\n        {\n            this.EnsurePreconditionsMet();\n            var builder = new TestClusterBuilder();\n            TestDefaultConfiguration.ConfigureTestCluster(builder);\n            this.ConfigureTestCluster(builder);\n\n            var testCluster = builder.Build();\n            if (testCluster.Primary == null)\n            {\n                await testCluster.DeployAsync().ConfigureAwait(false);\n            }\n\n            this.HostedCluster = testCluster;\n            this.Logger = this.Client.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Application\");\n        }\n\n        public virtual async Task DisposeAsync()\n        {\n            var cluster = this.HostedCluster;\n            if (cluster is null) return;\n\n            try\n            {\n                await cluster.StopAllSilosAsync().ConfigureAwait(false);\n            }\n            finally\n            {\n                await cluster.DisposeAsync().ConfigureAwait(false);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/BaseInProcessTestClusterFixture.cs",
    "content": "using System.Runtime.ExceptionServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\n\nnamespace TestExtensions;\n\npublic abstract class BaseInProcessTestClusterFixture : Xunit.IAsyncLifetime\n{\n    private readonly ExceptionDispatchInfo preconditionsException;\n\n    static BaseInProcessTestClusterFixture()\n    {\n        TestDefaultConfiguration.InitializeDefaults();\n    }\n\n    protected BaseInProcessTestClusterFixture()\n    {\n        try\n        {\n            CheckPreconditionsOrThrow();\n        }\n        catch (Exception ex)\n        {\n            preconditionsException = ExceptionDispatchInfo.Capture(ex);\n            return;\n        }\n    }\n\n    public void EnsurePreconditionsMet()\n    {\n        preconditionsException?.Throw();\n    }\n\n    protected virtual void CheckPreconditionsOrThrow() { }\n\n    protected virtual void ConfigureTestCluster(InProcessTestClusterBuilder builder)\n    {\n    }\n\n    public InProcessTestCluster HostedCluster { get; private set; }\n\n    public IGrainFactory GrainFactory => Client;\n\n    public IClusterClient Client => HostedCluster?.Client;\n\n    public ILogger Logger { get; private set; }\n\n    public string GetClientServiceId() => Client.ServiceProvider.GetRequiredService<IOptions<ClusterOptions>>().Value.ServiceId;\n\n    public virtual async Task InitializeAsync()\n    {\n        EnsurePreconditionsMet();\n        var builder = new InProcessTestClusterBuilder();\n        builder.ConfigureHost(hostBuilder => TestDefaultConfiguration.ConfigureHostConfiguration(hostBuilder.Configuration));\n        ConfigureTestCluster(builder);\n\n        var testCluster = builder.Build();\n        await testCluster.DeployAsync().ConfigureAwait(false);\n\n        HostedCluster = testCluster;\n        Logger = Client.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Application\");\n    }\n\n    public virtual async Task DisposeAsync()\n    {\n        var cluster = HostedCluster;\n        if (cluster is null) return;\n\n        try\n        {\n            await cluster.StopAllSilosAsync().ConfigureAwait(false);\n        }\n        finally\n        {\n            await cluster.DisposeAsync().ConfigureAwait(false);\n        }\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/DefaultClusterFixture.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\n\nnamespace TestExtensions\n{\n    public class DefaultClusterFixture : Xunit.IAsyncLifetime\n    {\n        static DefaultClusterFixture()\n        {\n            TestDefaultConfiguration.InitializeDefaults();\n        }\n\n        public TestCluster HostedCluster { get; private set; }\n\n        public IGrainFactory GrainFactory => this.HostedCluster?.GrainFactory;\n\n        public IClusterClient Client => this.HostedCluster?.Client;\n\n        public ILogger Logger { get; private set; }\n\n        public virtual async Task InitializeAsync()\n        {\n            var builder = new TestClusterBuilder();\n            TestDefaultConfiguration.ConfigureTestCluster(builder);\n            builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n\n            var testCluster = builder.Build();\n            if (testCluster.Primary == null)\n            {\n                await testCluster.DeployAsync().ConfigureAwait(false);\n            }\n\n            this.HostedCluster = testCluster;\n            this.Logger = this.Client.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Application\");\n        }\n\n        public virtual async Task DisposeAsync()\n        {\n            var cluster = this.HostedCluster;\n            if (cluster is null) return;\n\n            try\n            {\n                await cluster.StopAllSilosAsync().ConfigureAwait(false);\n            }\n            finally\n            {\n                await cluster.DisposeAsync().ConfigureAwait(false);\n            }\n        }\n\n        public class SiloHostConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .Configure<SiloMessagingOptions>(o => o.ClientGatewayShutdownNotificationTimeout = default)\n                    .UseInMemoryReminderService()\n                    .UseInMemoryDurableJobs()\n                    .AddMemoryGrainStorageAsDefault()\n                    .AddMemoryGrainStorage(\"MemoryStore\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/HierarchicalKeyStore.cs",
    "content": "using System.Diagnostics;\nusing System.Globalization;\nusing System.Text;\n\nnamespace Orleans.Storage\n{\n    internal class HierarchicalKeyStore : ILocalDataStore\n    {\n        public string Etag { get; private set; }\n\n        private const char KEY_VALUE_PAIR_SEPERATOR = '+';\n        private const char KEY_VALUE_SEPERATOR = '=';\n\n        private long lastETagCounter = 1;\n        [NonSerialized]\n        private readonly Dictionary<string, Dictionary<string, object>> dataTable = new();\n        private readonly int numKeyLayers;\n        private readonly object lockable = new object();\n\n        public HierarchicalKeyStore(int keyLayers)\n        {\n            numKeyLayers = keyLayers;\n        }\n\n        public string WriteRow(IList<Tuple<string, string>> keys, IDictionary<string, object> data, string eTag)\n        {\n            if (keys.Count > numKeyLayers)\n            {\n                var error = string.Format(\"Wrong number of keys supplied -- Expected count = {0} Received = {1}\", numKeyLayers, keys.Count);\n                Trace.TraceError(error);\n                throw new ArgumentOutOfRangeException(nameof(keys), keys.Count, error);\n            }\n\n            lock (lockable)\n            {\n                var storedData = GetDataStore(keys);\n\n                foreach (var kv in data)\n                    storedData[kv.Key] = kv.Value;\n\n                Etag = NewEtag();\n                return Etag;\n            }\n        }\n\n        public IDictionary<string, object> ReadRow(IList<Tuple<string, string>> keys)\n        {\n            if (keys.Count > numKeyLayers)\n            {\n                var error = string.Format(\"Not enough keys supplied -- Expected count = {0} Received = {1}\", numKeyLayers, keys.Count);\n                Trace.TraceError(error);\n                throw new ArgumentOutOfRangeException(nameof(keys), keys.Count, error);\n            }\n\n            lock (lockable)\n            {\n                return GetDataStore(keys);\n            }\n        }\n\n        public IList<IDictionary<string, object>> ReadMultiRow(IList<Tuple<string, string>> keys)\n        {\n            if (keys.Count > numKeyLayers)\n            {\n                throw new ArgumentOutOfRangeException(nameof(keys), keys.Count,\n                    string.Format(\"Too many key supplied -- Expected count = {0} Received = {1}\", numKeyLayers, keys.Count));\n            }\n\n            lock (lockable)\n            {\n                return FindDataStores(keys);\n            }\n        }\n\n        public bool DeleteRow(IList<Tuple<string, string>> keys, string eTag)\n        {\n            if (keys.Count > numKeyLayers)\n            {\n                throw new ArgumentOutOfRangeException(nameof(keys), keys.Count,\n                    string.Format(\"Not enough keys supplied -- Expected count = {0} Received = {1}\", numKeyLayers, keys.Count));\n            }\n\n            string keyStr = MakeStoreKey(keys);\n\n            lock (lockable)\n            {\n                // No change to Etag\n                return dataTable.Remove(keyStr);\n            }\n        }\n\n        public void Clear()\n        {\n            lock (lockable)\n            {\n                dataTable.Clear();\n            }\n        }\n\n        public string DumpData(bool printDump = true)\n        {\n            var sb = new StringBuilder();\n            lock (lockable)\n            {\n                foreach (var kv in dataTable)\n                {\n                    sb.AppendFormat(\"{0} => {1}\", kv.Key, kv.Value).AppendLine();\n                }\n            }\n            if (printDump)\n            {\n                Trace.TraceInformation(\"Dump {0} Etag={1} Data= {2}\", GetType(), Etag, sb);\n            }\n            return sb.ToString();\n        }\n\n        private Dictionary<string, object> GetDataStore(IList<Tuple<string, string>> keys)\n        {\n            string keyStr = MakeStoreKey(keys);\n\n            lock (lockable)\n            {\n                if (!dataTable.TryGetValue(keyStr, out var data))\n                {\n                    data = new Dictionary<string, object>(); // Empty data set\n                    dataTable[keyStr] = data;\n                }\n                return data;\n            }\n        }\n\n        private IList<IDictionary<string, object>> FindDataStores(IList<Tuple<string, string>> keys)\n        {\n            if (numKeyLayers == keys.Count)\n            {\n                return new[] { GetDataStore(keys) };\n            }\n\n            var results = new List<IDictionary<string, object>>();\n            string keyStr = MakeStoreKey(keys);\n\n            lock (lockable)\n            {\n                foreach (var kv in dataTable)\n                    if (kv.Key.StartsWith(keyStr, StringComparison.Ordinal))\n                        results.Add(kv.Value);\n            }\n            return results;\n        }\n\n        internal static string MakeStoreKey(IEnumerable<Tuple<string, string>> keys)\n        {\n            var sb = new StringBuilder();\n            bool first = true;\n            foreach (var keyPair in keys)\n            {\n                if (first)\n                    first = false;\n                else\n                    sb.Append(KEY_VALUE_PAIR_SEPERATOR);\n\n                sb.Append(keyPair.Item1).Append(KEY_VALUE_SEPERATOR).Append(keyPair.Item2);\n            }\n            return sb.ToString();\n        }\n\n        private string NewEtag()\n        {\n            return lastETagCounter++.ToString(CultureInfo.InvariantCulture);\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/HostedTestClusterBase.cs",
    "content": "using System.Text.Json;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Serialization;\nusing Orleans.TestingHost;\nusing Xunit;\n\nnamespace TestExtensions\n{\n    /// <summary>\n    /// Base class that ensures a silo cluster is started with the default configuration, and avoids restarting it if the previous test used the same default base.\n    /// </summary>\n    [Collection(\"DefaultCluster\")]\n    public abstract class HostedTestClusterEnsureDefaultStarted : OrleansTestingBase\n    {\n        protected DefaultClusterFixture Fixture { get; private set; }\n        protected TestCluster HostedCluster => this.Fixture.HostedCluster;\n\n        protected IGrainFactory GrainFactory => this.HostedCluster.GrainFactory;\n\n        protected IClusterClient Client => this.HostedCluster.Client;\n        protected ILogger Logger => this.Client.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Application\");\n\n        protected HostedTestClusterEnsureDefaultStarted(DefaultClusterFixture fixture)\n        {\n            this.Fixture = fixture;\n        }\n    }\n\n    public static class TestClusterExtensions\n    {\n        public static T RoundTripSystemTextJsonSerialization<T>(this TestCluster cluster, T value)\n        {\n            var serialized = JsonSerializer.Serialize<T>(value);\n            return JsonSerializer.Deserialize<T>(serialized);\n        }\n\n        public static T RoundTripSerializationForTesting<T>(this TestCluster cluster, T value)\n        {\n            var serializer = cluster.ServiceProvider.GetRequiredService<Serializer>();\n            return serializer.Deserialize<T>(serializer.SerializeToArray(value));\n        }\n\n        public static T DeepCopy<T>(this TestCluster cluster, T value)\n        {\n            var copier = cluster.ServiceProvider.GetRequiredService<DeepCopier>();\n            return copier.Copy(value);\n        }\n\n        public static Serializer GetSerializer(this TestCluster cluster)\n        {\n            return cluster.ServiceProvider.GetRequiredService<Serializer>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/ILocalDataStore.cs",
    "content": "namespace Orleans.Storage\n{\n    public interface ILocalDataStore\n    {\n        string Etag { get; }\n        string WriteRow(IList<Tuple<string, string>> keys, IDictionary<string, object> data, string eTag);\n        IDictionary<string, object> ReadRow(IList<Tuple<string, string>> keys);\n        IList<IDictionary<string, object>> ReadMultiRow(IList<Tuple<string, string>> keys);\n        bool DeleteRow(IList<Tuple<string, string>> keys, string eTag);\n        void Clear();\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/MockStorageProvider.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.Providers;\nusing Orleans.Runtime;\nusing Orleans.Serialization;\nusing Orleans.Storage;\nusing Microsoft.Extensions.Logging;\n\nnamespace UnitTests.StorageTests\n{\n    public static class SiloBuilderExtensions\n    {\n        public static ISiloBuilder AddTestStorageProvider<T>(this ISiloBuilder builder, string name) where T : IGrainStorage\n        {\n            return builder.AddTestStorageProvider(name, (sp, n) => ActivatorUtilities.CreateInstance<T>(sp));\n        }\n\n        public static ISiloBuilder AddTestStorageProvider<T>(this ISiloBuilder builder, string name, Func<IServiceProvider, string, T> createInstance) where T : IGrainStorage\n        {\n            return builder.ConfigureServices(services =>\n            {\n                services.AddKeyedSingleton<IGrainStorage>(name, (sp, n) => createInstance(sp, n as string));\n\n                if (typeof(ILifecycleParticipant<ISiloLifecycle>).IsAssignableFrom(typeof(T)))\n                {\n                    services.AddKeyedSingleton(name, (svc, n) => (ILifecycleParticipant<ISiloLifecycle>)svc.GetRequiredKeyedService<IGrainStorage>(name));\n                }\n\n                if (typeof(IControllable).IsAssignableFrom(typeof(T)))\n                {\n                    services.AddKeyedSingleton(name, (svc, n) => (IControllable)svc.GetRequiredKeyedService<IGrainStorage>(name));\n                }\n            });\n        }\n    }\n\n    [DebuggerDisplay(\"MockStorageProvider:{Name}\")]\n    public class MockStorageProvider : IControllable, IGrainStorage\n    {\n        public enum Commands\n        {\n            InitCount,\n            SetValue,\n            GetProvideState,\n            SetErrorInjection,\n            GetLastState,\n            ResetHistory\n        }\n        [Serializable]\n        [GenerateSerializer]\n        public class StateForTest \n        {\n            [Id(0)]\n            public int InitCount { get; set; }\n            [Id(1)]\n            public int CloseCount { get; set; }\n            [Id(2)]\n            public int ReadCount { get; set; }\n            [Id(3)]\n            public int WriteCount { get; set; }\n            [Id(4)]\n            public int DeleteCount { get; set; }\n        }\n\n        private static int _instanceNum;\n        private readonly int _id;\n        private readonly int initCount;\n        private int closeCount;\n        private int readCount;\n        private int writeCount;\n        private int deleteCount;\n        private readonly int numKeys;\n        private readonly DeepCopier copier;\n        private readonly ILocalDataStore StateStore;\n        private const string stateStoreKey = \"State\";\n        private readonly ILogger logger;\n        public string LastId { get; private set; }\n        public object LastState { get; private set; }\n\n        public string Name { get; private set; }\n\n        public MockStorageProvider(ILoggerFactory loggerFactory, DeepCopier copier)\n            : this(Guid.NewGuid().ToString(), 2, loggerFactory, copier)\n        { }\n\n        public MockStorageProvider(string name, ILoggerFactory loggerFactory, DeepCopier copier)\n            : this(name, 2, loggerFactory, copier)\n        { }\n\n        public MockStorageProvider(string name, int numKeys, ILoggerFactory loggerFactory, DeepCopier copier)\n        {\n            _id = ++_instanceNum;\n            this.numKeys = numKeys;\n            this.copier = copier;\n            this.Name = name;\n            this.logger = loggerFactory.CreateLogger($\"Storage.{this.GetType().Name}-{this._id}\");\n\n            logger.LogInformation(\"Init Name={Name}\", name);\n            Interlocked.Increment(ref initCount);\n\n            StateStore = new HierarchicalKeyStore(numKeys);\n\n            logger.LogInformation(\"Finished Init Name={Name}\", name);\n        }\n\n        public StateForTest GetProviderState()\n        {\n            var state = new StateForTest();\n            state.InitCount = initCount;\n            state.CloseCount = closeCount;\n            state.DeleteCount = deleteCount;\n            state.ReadCount = readCount;\n            state.WriteCount = writeCount;\n            return state;\n        }\n\n        [Serializable]\n        [GenerateSerializer]\n        public class SetValueArgs\n        {\n            [Id(0)]\n            public Type StateType { get; set; }\n            [Id(1)]\n            public string GrainType { get; set; }\n            [Id(2)]\n            public GrainId GrainId { get; set; }\n            [Id(3)]\n            public string Name { get; set; }\n            [Id(4)]\n            public object Val { get; set; }\n\n        }\n\n        public void SetValue(SetValueArgs args)\n        {\n            SetValue(args.StateType, args.GrainType, args.GrainId, args.Name, args.Val);\n        }\n\n        private void SetValue(Type stateType, string grainType, GrainId grainId, string name, object val)\n        {\n            lock (StateStore)\n            {\n                this.logger.LogInformation(\"Setting stored value {Name} for {GrainId} to {Value}\", name, grainId, val);\n                var keys = MakeGrainStateKeys(grainType, grainId);\n                var storedDict = StateStore.ReadRow(keys);\n                if (!storedDict.ContainsKey(stateStoreKey))\n                {\n                    storedDict[stateStoreKey] = Activator.CreateInstance(stateType);\n                } \n\n                var storedState = storedDict[stateStoreKey];\n                var field = storedState.GetType().GetProperty(name).GetSetMethod(true);\n                field.Invoke(storedState, new[] { val });\n                LastId = GetId(grainId);\n                LastState = storedState;\n            }\n        }\n\n        public object GetLastState()\n        {\n            return LastState;\n        }\n\n        public T GetLastState<T>()\n        {\n            return (T) LastState;\n        }\n\n        private object GetLastState<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            lock (StateStore)\n            {\n                var keys = MakeGrainStateKeys(grainType, grainId);\n                var storedStateRow = StateStore.ReadRow(keys);\n                if (!storedStateRow.ContainsKey(stateStoreKey))\n                {\n                    storedStateRow[stateStoreKey] = Activator.CreateInstance(grainState.State.GetType());\n                }\n\n                var storedState = storedStateRow[stateStoreKey];\n                LastId = GetId(grainId);\n                LastState = storedState;\n                return storedState;\n            }\n        }\n\n        public virtual Task Close()\n        {\n            logger.LogInformation(\"Close\");\n            Interlocked.Increment(ref closeCount);\n            StateStore.Clear();\n            return Task.CompletedTask;\n        }\n\n        public virtual Task ReadStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            logger.LogInformation(\"ReadStateAsync for {GrainType} {GrainId}\", grainType, grainId);\n            Interlocked.Increment(ref readCount);\n            lock (StateStore)\n            {\n                var storedState = GetLastState(grainType, grainId, grainState);\n                grainState.RecordExists = storedState != null;\n                grainState.State = (T)this.copier.Copy(storedState); // Read current state data\n            }\n            return Task.CompletedTask;\n        }\n\n        public virtual Task WriteStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            logger.LogInformation(\"WriteStateAsync for {GrainType} {GrainId}\", grainType, grainId);\n            Interlocked.Increment(ref writeCount);\n            lock (StateStore)\n            {\n                var storedState = this.copier.Copy(grainState.State); // Store current state data\n                var stateStore = new Dictionary<string, object> {{ stateStoreKey, storedState }};\n                StateStore.WriteRow(MakeGrainStateKeys(grainType, grainId), stateStore, grainState.ETag);\n\n                LastId = GetId(grainId);\n                LastState = storedState;\n                grainState.RecordExists = true;\n            }\n            return Task.CompletedTask;\n        }\n\n        public virtual Task ClearStateAsync<T>(string grainType, GrainId grainId, IGrainState<T> grainState)\n        {\n            logger.LogInformation(\"ClearStateAsync for {GrainType} {GrainId}\", grainType, grainId);\n            Interlocked.Increment(ref deleteCount);\n            var keys = MakeGrainStateKeys(grainType, grainId);\n            lock (StateStore)\n            {\n                StateStore.DeleteRow(keys, grainState.ETag);\n                LastId = GetId(grainId);\n                LastState = null;\n            }\n            grainState.RecordExists = false;\n            grainState.State = Activator.CreateInstance<T>();\n            return Task.CompletedTask;\n        }\n\n        private static string GetId(GrainId grainId) => grainId.ToString();\n\n        private static IList<Tuple<string, string>> MakeGrainStateKeys(string grainType, GrainId grainId)\n        {\n            return new[]\n            {\n                Tuple.Create(\"GrainType\", grainType),\n                Tuple.Create(\"GrainId\", GetId(grainId))\n            }.ToList();\n        }\n\n        public void ResetHistory()\n        {\n            // initCount = 0;\n            closeCount = readCount = writeCount = deleteCount = 0;\n            LastId = null;\n            LastState = null;\n        }\n\n        /// <summary>\n        /// A function to execute a control command.\n        /// </summary>\n        /// <param name=\"command\">A serial number of the command.</param>\n        /// <param name=\"arg\">An opaque command argument</param>\n        public virtual Task<object> ExecuteCommand(int command, object arg)\n        {\n            switch ((Commands)command)\n            {\n                case Commands.InitCount:\n                    return Task.FromResult<object>(initCount);\n                case Commands.SetValue:\n                    SetValue((SetValueArgs) arg);\n                    return Task.FromResult<object>(true); \n                case Commands.GetProvideState:\n                    return Task.FromResult<object>(GetProviderState());\n                case Commands.GetLastState:\n                    return Task.FromResult(GetLastState());\n                case Commands.ResetHistory:\n                    ResetHistory();\n                    return Task.FromResult<object>(true);\n                default:\n                    return Task.FromResult<object>(true); \n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/OrleansTestingBase.cs",
    "content": "namespace TestExtensions\n{\n    public abstract class OrleansTestingBase\n    {\n        public static long GetRandomGrainId() => Random.Shared.Next();\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/Runners/GoldenPathLeaseProviderTestRunner.cs",
    "content": "﻿using Xunit;\nusing Xunit.Abstractions;\nusing Orleans.LeaseProviders;\n\nnamespace TestExtensions.Runners\n{\n    public class GoldenPathLeaseProviderTestRunner\n    {\n        private const string LeaseCategory = \"TestLeaseCategory\";\n\n        private readonly ILeaseProvider leaseProvider;\n        private readonly ITestOutputHelper output;\n\n        protected GoldenPathLeaseProviderTestRunner(ILeaseProvider leaseProvider, ITestOutputHelper output)\n        {\n            this.leaseProvider = leaseProvider;\n            this.output = output;\n        }\n\n        [SkippableFact]\n        public async Task ProviderCanAcquireLeases()\n        {\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15)), new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15))\n            };\n            //acquire\n            AcquireLeaseResult[] results = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            for (int i = 0; i < results.Length; i++)\n            {\n                var result = results[i];\n                Assert.Equal(ResponseCode.OK, result.StatusCode);\n                Assert.NotNull(result.AcquiredLease);\n                Assert.Equal(leaseRequests[i].ResourceKey, result.AcquiredLease.ResourceKey);\n            };\n        }\n\n        [SkippableFact]\n        public async Task ProviderCanReleaseLeases()\n        {\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15)), new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15))\n            };\n            //acquire\n            var results = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            //release\n            await this.leaseProvider.Release(LeaseCategory, results.Select(result => result.AcquiredLease).ToArray());\n        }\n\n        [SkippableFact]\n        public async Task ProviderCanRenewLeases()\n        {\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15)), new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15))\n            };\n            //acquire\n            var acquireResults = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            //renew\n            var renewResults = await this.leaseProvider.Renew(LeaseCategory, acquireResults.Select(result => result.AcquiredLease).ToArray());\n            for (int i = 0; i < renewResults.Count(); i++)\n            {\n                var result = renewResults[i];\n                Assert.Equal(ResponseCode.OK, result.StatusCode);\n                Assert.NotNull(result.AcquiredLease);\n                Assert.Equal(leaseRequests[i].ResourceKey, result.AcquiredLease.ResourceKey);\n            };\n        }\n\n        [SkippableFact]\n        public async Task Provider_TryAcquireLeaseWhichBelongToOtherEntity_Return_LeaseNotAvailable()\n        {\n            var resourceId = Guid.NewGuid().ToString();\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(resourceId, TimeSpan.FromSeconds(15)), new LeaseRequest(resourceId, TimeSpan.FromSeconds(15))\n            };\n            //two entity tries to acquire lease on the same release\n            var results = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            //one attempt succeeded and one attemp failed\n            Assert.Contains(results, result => result.StatusCode == ResponseCode.OK);\n            Assert.Contains(results, result => result.StatusCode == ResponseCode.LeaseNotAvailable);\n        }\n\n        [SkippableFact]\n        public async Task Provider_TryRenewLeaseWithWrongToken_Return_InvalidToken()\n        {\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15)), new LeaseRequest(Guid.NewGuid().ToString(), TimeSpan.FromSeconds(15))\n            };\n            //acquire\n            var results = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            var acquiredLeaseWithWrongToken = results.Select(result => new AcquiredLease(result.AcquiredLease.ResourceKey, result.AcquiredLease.Duration, Guid.NewGuid().ToString(), result.AcquiredLease.StartTimeUtc));\n            //renew with wrong token\n            var renewResults = await this.leaseProvider.Renew(LeaseCategory, acquiredLeaseWithWrongToken.ToArray());\n            for (int i = 0; i < renewResults.Count(); i++)\n            {\n                LeaseRequest request = leaseRequests[i];\n                AcquireLeaseResult result = renewResults[i];\n                Assert.Equal(ResponseCode.InvalidToken, result.StatusCode);\n                Assert.Equal(request.ResourceKey, result.AcquiredLease.ResourceKey);\n            }\n        }\n\n        [SkippableFact]\n        public async Task Provider_LifeCycle_Acqurie_Renew_Release_ShouldBeAbleToAcquireLeaseOnTheSameResourceAfterRelease()\n        {\n            var resourceId = Guid.NewGuid().ToString();\n            var leaseRequests = new List<LeaseRequest>() {\n                new LeaseRequest(resourceId, TimeSpan.FromSeconds(15))\n            };\n\n            //acquire first time\n            var acquireResults1 = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            //renew\n            var renewResults = await this.leaseProvider.Renew(LeaseCategory, acquireResults1.Select(result => result.AcquiredLease).ToArray());\n            for (int i = 0; i < renewResults.Count(); i++)\n            {\n                var result = renewResults[i];\n                Assert.Equal(ResponseCode.OK, result.StatusCode);\n                Assert.NotNull(result.AcquiredLease);\n                Assert.Equal(leaseRequests[i].ResourceKey, result.AcquiredLease.ResourceKey);\n            }\n            //release\n            await this.leaseProvider.Release(LeaseCategory, renewResults.Select(result => result.AcquiredLease).ToArray());\n\n            //acquire second time, acquire lease on the same resource after their leases got released\n            var acquireResults2 = await this.leaseProvider.Acquire(LeaseCategory, leaseRequests.ToArray());\n            for (int i = 0; i < acquireResults2.Count(); i++)\n            {\n                var result = acquireResults2[i];\n                Assert.Equal(ResponseCode.OK, result.StatusCode);\n                Assert.NotNull(result.AcquiredLease);\n                Assert.Equal(leaseRequests[i].ResourceKey, result.AcquiredLease.ResourceKey);\n                //token in two leases should be different\n                Assert.NotEqual(acquireResults1[i].AcquiredLease.Token, result.AcquiredLease.Token);\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/SerializationTestEnvironment.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Orleans.Serialization;\n\nnamespace TestExtensions\n{\n    public class SerializationTestEnvironment : IDisposable\n    {\n        public SerializationTestEnvironment(Action<IClientBuilder> configureClientBuilder = null)\n        {\n            var host = new HostBuilder()\n                .UseOrleansClient((ctx, clientBuilder) =>\n                {\n                    clientBuilder.UseLocalhostClustering();\n                    configureClientBuilder?.Invoke(clientBuilder);\n                }).Build();\n\n            this.Client = host.Services.GetRequiredService<IClusterClient>();\n            this.RuntimeClient = this.Client.ServiceProvider.GetRequiredService<OutsideRuntimeClient>();\n            RuntimeClient.ConsumeServices();\n        }\n\n        public IClusterClient Client { get; set; }\n        \n        internal OutsideRuntimeClient RuntimeClient { get; set; }\n\n        public static SerializationTestEnvironment InitializeWithDefaults(Action<IClientBuilder> configureClientBuilder = null)\n        {\n            var result = new SerializationTestEnvironment(configureClientBuilder);\n            return result;\n        }\n        \n        public IGrainFactory GrainFactory => this.RuntimeClient.InternalGrainFactory;\n\n        internal IInternalGrainFactory InternalGrainFactory => this.RuntimeClient.InternalGrainFactory;\n\n        internal IServiceProvider Services => this.Client.ServiceProvider;\n\n        public DeepCopier DeepCopier => this.RuntimeClient.ServiceProvider.GetRequiredService<DeepCopier>();\n        public Serializer Serializer => RuntimeClient.ServiceProvider.GetRequiredService<Serializer>();\n        \n        public void Dispose()\n        {\n            this.RuntimeClient?.Dispose();\n        }\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/SiloAddressUtils.cs",
    "content": "﻿using Orleans.Runtime;\nusing System.Net;\n\nnamespace TestExtensions\n{\n    public static class SiloAddressUtils\n    {\n        private static readonly IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Loopback, 0);\n\n        public static SiloAddress NewLocalSiloAddress(int gen)\n        {\n            return SiloAddress.New(localEndpoint, gen);\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestCategory.cs",
    "content": "using Xunit.Abstractions;\nusing Xunit.Sdk;\n\n/// <summary>\n/// This is a replacement for the MSTest [TestCategoryAttribute] on xunit\n/// xunit does not have the concept of Category for tests and instead, the have [TraitAttribute(string key, string value)]\n/// If we replace the MSTest [TestCategoryAttribute] for the [Trait(\"Category\", \"BVT\")], we will surely fall at some time in cases \n/// where people will typo on the \"Category\" key part of the Trait. \n/// On order to achieve the same behaviour as on MSTest, a custom [TestCategory] was created \n/// to mimic the MSTest one and avoid replace it on every existing test. \n/// The tests can be filtered by xunit runners by usage of \"-trait\" on the command line with the expression like\n/// <code>-trait \"Category=BVT\"</code> for example that will only run the tests with [TestCategory(\"BVT\")] on it.\n/// More on Trait extensibility <see href=\"https://github.com/xunit/samples.xunit/tree/master/TraitExtensibility\" />\n/// </summary>\n\n[TraitDiscoverer(\"CategoryDiscoverer\", \"TestExtensions\")]\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\npublic class TestCategoryAttribute : Attribute, ITraitAttribute\n{\n    public TestCategoryAttribute(string category) { }\n}\n\npublic class CategoryDiscoverer : ITraitDiscoverer\n{\n    public CategoryDiscoverer(IMessageSink diagnosticMessageSink)\n    {\n    }\n\n    public IEnumerable<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)\n    {\n        var ctorArgs = traitAttribute.GetConstructorArguments().ToList();\n        yield return new KeyValuePair<string, string>(\"Category\", ctorArgs[0].ToString());\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestClusterPerTest.cs",
    "content": "using System.Runtime.ExceptionServices;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Orleans.TestingHost;\n\nnamespace TestExtensions\n{\n    public abstract class TestClusterPerTest : OrleansTestingBase, Xunit.IAsyncLifetime\n    {\n        private readonly ExceptionDispatchInfo preconditionsException;\n        static TestClusterPerTest()\n        {\n            TestDefaultConfiguration.InitializeDefaults();\n        }\n\n        protected TestCluster HostedCluster { get; private set; }\n\n        internal IInternalClusterClient InternalClient => (IInternalClusterClient)this.Client;\n\n        public IClusterClient Client => this.HostedCluster.Client;\n\n        protected IGrainFactory GrainFactory => this.Client;\n\n        protected ILogger Logger => this.logger;\n        protected ILogger logger;\n\n        protected TestClusterPerTest()\n        {\n            try\n            {\n                CheckPreconditionsOrThrow();\n            }\n            catch (Exception ex)\n            {\n                this.preconditionsException = ExceptionDispatchInfo.Capture(ex);\n                return;\n            }\n        }\n\n        public void EnsurePreconditionsMet()\n        {\n            this.preconditionsException?.Throw();\n        }\n\n        protected virtual void CheckPreconditionsOrThrow() { }\n\n        protected virtual void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n        }\n\n        public virtual async Task InitializeAsync()\n        {\n            var builder = new TestClusterBuilder();\n            TestDefaultConfiguration.ConfigureTestCluster(builder);\n            this.ConfigureTestCluster(builder);\n\n            var testCluster = builder.Build();\n            if (testCluster.Primary == null)\n            {\n                await testCluster.DeployAsync().ConfigureAwait(false);\n            }\n\n            this.HostedCluster = testCluster;\n            this.logger = this.Client.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger(\"Application\");\n        }\n\n        public virtual async Task DisposeAsync()\n        {\n            var cluster = this.HostedCluster;\n            if (cluster is null) return;\n\n            try\n            {\n                await cluster.StopAllSilosAsync().ConfigureAwait(false);\n            }\n            finally\n            {\n                await cluster.DisposeAsync().ConfigureAwait(false);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestConstants.cs",
    "content": "using System.Diagnostics;\n\nnamespace TestExtensions\n{\n    // used for test constants\n    internal static class TestConstants\n    {\n        public static readonly TimeSpan InitTimeout =\n            Debugger.IsAttached ? TimeSpan.FromMinutes(10) : TimeSpan.FromMinutes(1);\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestDefaultConfiguration.cs",
    "content": "using Azure.Core;\nusing Azure.Identity;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.Primitives;\nusing Orleans.TestingHost;\n\nnamespace TestExtensions\n{\n    public class TestDefaultConfiguration\n    {\n        private static readonly object LockObject = new object();\n        private static IConfiguration defaultConfiguration;\n\n        static TestDefaultConfiguration()\n        {\n            InitializeDefaults();\n        }\n\n        public static void InitializeDefaults()\n        {\n            lock (LockObject)\n            {\n                defaultConfiguration = BuildDefaultConfiguration();\n            }\n        }\n\n        public static bool UseAadAuthentication\n        {\n            get\n            {\n                bool.TryParse(defaultConfiguration[nameof(UseAadAuthentication)], out var value);\n                return value;\n            }\n        }\n\n        public static string CosmosDBAccountEndpoint => defaultConfiguration[nameof(CosmosDBAccountEndpoint)];\n        public static string CosmosDBAccountKey => defaultConfiguration[nameof(CosmosDBAccountKey)];\n        public static Uri TableEndpoint => new Uri(defaultConfiguration[nameof(TableEndpoint)]);\n        public static Uri DataBlobUri => new Uri(defaultConfiguration[nameof(DataBlobUri)]);\n        public static Uri DataQueueUri => new Uri(defaultConfiguration[nameof(DataQueueUri)]);\n        public static string DataConnectionString => defaultConfiguration[nameof(DataConnectionString)];\n        public static string EventHubConnectionString => defaultConfiguration[nameof(EventHubConnectionString)];\n        public static string EventHubFullyQualifiedNamespace => defaultConfiguration[nameof(EventHubFullyQualifiedNamespace)];\n        public static string ZooKeeperConnectionString => defaultConfiguration[nameof(ZooKeeperConnectionString)];\n        public static string ConsulConnectionString => defaultConfiguration[nameof(ConsulConnectionString)];\n        public static string RedisConnectionString => defaultConfiguration[nameof(RedisConnectionString)];\n        public static string PostgresConnectionString => defaultConfiguration[nameof(PostgresConnectionString)];\n        public static string MySqlConnectionString => defaultConfiguration[nameof(MySqlConnectionString)];\n        public static string MsSqlConnectionString => defaultConfiguration[nameof(MsSqlConnectionString)];\n        public static string DynamoDbService => defaultConfiguration[nameof(DynamoDbService)];\n        public static string DynamoDbAccessKey => defaultConfiguration[nameof(DynamoDbAccessKey)];\n        public static string DynamoDbSecretKey => defaultConfiguration[nameof(DynamoDbSecretKey)];\n        public static string SqsConnectionString => defaultConfiguration[nameof(SqsConnectionString)];\n        public static TokenCredential TokenCredential\n        {\n            get\n            {\n                var systemAccessToken = Environment.GetEnvironmentVariable(\"SYSTEM_ACCESSTOKEN\");\n                if (!string.IsNullOrEmpty(systemAccessToken))\n                {\n                    // If running in an AzDo pipeline with a SYSTEM_ACCESSTOKEN available, let's try to use AzurePipelinesCredential\n                    var tenantId = Environment.GetEnvironmentVariable(\"AZURE_TENANT_ID\");\n                    var clientId = Environment.GetEnvironmentVariable(\"AZURE_CLIENT_ID\");\n                    var serviceConnectionId = Environment.GetEnvironmentVariable(\"SERVICE_CONNECTION_ID\");\n                    return new AzurePipelinesCredential(tenantId, clientId, serviceConnectionId, systemAccessToken);\n                }\n                return new DefaultAzureCredential();\n            }\n        }\n\n        public static bool GetValue(string key, out string value)\n        {\n            value = defaultConfiguration.GetValue(key, default(string));\n\n            return value != null;\n        }\n\n        private static IConfiguration BuildDefaultConfiguration()\n        {\n            var builder = new ConfigurationBuilder();\n            ConfigureHostConfiguration(builder);\n\n            var config = builder.Build();\n            return config;\n        }\n\n        public static void ConfigureHostConfiguration(IConfigurationBuilder builder)\n        {\n            builder.AddInMemoryCollection(new Dictionary<string, string>\n            {\n                { nameof(ZooKeeperConnectionString), \"127.0.0.1:2181\" }\n            });\n            if (!TryAddJsonFileFromEnvironmentVariable(builder, \"ORLEANS_SECRETFILE\"))\n            {\n                TryAddJsonFileInAncestorFolder(builder, \"OrleansTestSecrets.json\");\n            }\n            builder.AddEnvironmentVariables(\"Orleans\");\n        }\n\n        /// <summary>\n        /// Hack, allowing PhysicalFileProvider to be serialized using json\n        /// </summary>\n        private class SerializablePhysicalFileProvider : IFileProvider\n        {\n            [NonSerialized]\n            private PhysicalFileProvider fileProvider;\n\n            public string Root { get; set; }\n\n            public IDirectoryContents GetDirectoryContents(string subpath)\n            {\n                return this.FileProvider().GetDirectoryContents(subpath);\n            }\n\n            public IFileInfo GetFileInfo(string subpath)\n            {\n                return this.FileProvider().GetFileInfo(subpath);\n            }\n\n            public IChangeToken Watch(string filter)\n            {\n                return this.FileProvider().Watch(filter);\n            }\n\n            private PhysicalFileProvider FileProvider()\n            {\n                return this.fileProvider ?? (this.fileProvider = new PhysicalFileProvider(this.Root));\n            }\n        }\n\n        /// <summary>Try to find a file with specified name up the folder hierarchy, as some of our CI environments are configured this way.</summary>\n        private static bool TryAddJsonFileInAncestorFolder(IConfigurationBuilder builder, string fileName)\n        {\n            // There might be some other out-of-the-box way of doing this though.\n            var currentDir = new DirectoryInfo(Directory.GetCurrentDirectory());\n            while (currentDir != null && currentDir.Exists)\n            {\n                string filePath = Path.Combine(currentDir.FullName, fileName);\n                if (File.Exists(filePath))\n                {\n                    builder.AddJsonFile(new SerializablePhysicalFileProvider { Root = currentDir.FullName }, fileName, false, false);\n                    return true;\n                }\n\n                currentDir = currentDir.Parent;\n            }\n            return false;\n        }\n\n        private static bool TryAddJsonFileFromEnvironmentVariable(IConfigurationBuilder builder, string envName)\n        {\n            var path = Environment.GetEnvironmentVariable(envName);\n            if (!string.IsNullOrWhiteSpace(path) && File.Exists(path))\n            {\n                builder.AddJsonFile(new SerializablePhysicalFileProvider { Root = Path.GetDirectoryName(path) }, Path.GetFileName(path), false, false);\n            }\n            return false;\n        }\n\n        public static void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.ConfigureHostConfiguration(ConfigureHostConfiguration);\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestEnvironmentFixture.cs",
    "content": "﻿namespace TestExtensions\n{\n    public class TestEnvironmentFixture : SerializationTestEnvironment\n    {\n        public const string DefaultCollection = \"DefaultTestEnvironment\";\n    }\n}"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestExtensions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit.assert\" />\n    <PackageReference Include=\"xunit.extensibility.core\" />\n    <PackageReference Include=\"xunit.extensibility.execution\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" />\n    <PackageReference Include=\"AwesomeAssertions\" />\n    <PackageReference Include=\"Azure.Identity\" />\n  </ItemGroup>\n  \n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"GoogleUtils.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AdoNet.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.AWS.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Azure.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Core.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Cosmos.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Redis.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Runtime.Internal.Tests\" />\n    <InternalsVisibleTo Include=\"Orleans.Streaming.NATS.Tests\" />\n  </ItemGroup>\n</Project>\n\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestOutputHelperExtensions.cs",
    "content": "﻿namespace Xunit.Abstractions\n{\n    public static class TestOutputHelperExtensions\n    {\n        public static void WriteLine(this ITestOutputHelper output, object value)\n        {\n            output.WriteLine(value.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/TestUtils.cs",
    "content": "using System.Diagnostics;\nusing System.Net;\nusing Orleans.Runtime;\nusing Orleans.TestingHost.Utils;\nusing Xunit;\nusing static TestExtensions.TestDefaultConfiguration;\n\nnamespace Tester\n{\n    public class TestUtils\n    {\n        public static long GetRandomGrainId() => Random.Shared.Next();\n\n        public static void CheckForAzureStorage()\n        {\n            if ((UseAadAuthentication && (TableEndpoint == null)) ||\n                (!UseAadAuthentication && string.IsNullOrWhiteSpace(DataConnectionString)))\n            {\n                throw new SkipException(\"No connection string found. Skipping\");\n            }\n\n            bool usingLocalWAS = string.Equals(DataConnectionString, \"UseDevelopmentStorage=true\", StringComparison.OrdinalIgnoreCase);\n\n            if (!usingLocalWAS)\n            {\n                // Tests are using Azure Cloud Storage, not local WAS emulator.\n                return;\n            }\n\n            //Starts the storage emulator if not started already and it exists (i.e. is installed).\n            if (!StorageEmulator.TryStart())\n            {\n                string errorMsg = \"Azure Storage Emulator could not be started.\";\n                Console.WriteLine(errorMsg);\n                throw new SkipException(errorMsg);\n            }\n        }\n\n        public static void CheckForEventHub()\n        {\n            if ((UseAadAuthentication && (EventHubFullyQualifiedNamespace == null)) ||\n                (!UseAadAuthentication && string.IsNullOrWhiteSpace(EventHubConnectionString)))\n            {\n                throw new SkipException(\"No connection string found. Skipping\");\n            }\n        }\n\n        public static void CheckForRedis()\n        {\n            if (string.IsNullOrWhiteSpace(RedisConnectionString))\n            {\n                throw new SkipException(\"No connection string found. Skipping\");\n            }\n        }\n\n        public static double CalibrateTimings()\n        {\n            const int NumLoops = 10000;\n            TimeSpan baseline = TimeSpan.FromTicks(80); // Baseline from jthelin03D\n            var sw = Stopwatch.StartNew();\n            for (int i = 0; i < NumLoops; i++)\n            {\n            }\n            sw.Stop();\n            double multiple = 1.0 * sw.ElapsedTicks / baseline.Ticks;\n            Console.WriteLine(\"CalibrateTimings: {0} [{1} Ticks] vs {2} [{3} Ticks] = x{4}\",\n                sw.Elapsed, sw.ElapsedTicks,\n                baseline, baseline.Ticks,\n                multiple);\n            return multiple > 1.0 ? multiple : 1.0;\n        }\n\n        public static async Task<TimeSpan> TimeRunAsync(int numIterations, TimeSpan baseline, string what, Func<Task> action)\n        {\n            var stopwatch = new Stopwatch();\n\n            long startMem = GC.GetTotalMemory(true);\n            stopwatch.Start();\n\n            await action();\n\n            stopwatch.Stop();\n            long stopMem = GC.GetTotalMemory(false);\n            long memUsed = stopMem - startMem;\n            TimeSpan duration = stopwatch.Elapsed;\n\n            string timeDeltaStr = \"\";\n            if (baseline > TimeSpan.Zero)\n            {\n                double delta = (duration - baseline).TotalMilliseconds / baseline.TotalMilliseconds;\n                timeDeltaStr = string.Format(\"-- Change = {0}%\", 100.0 * delta);\n            }\n            Console.WriteLine(\"Time for {0} loops doing {1} = {2} {3} Memory used={4}\", numIterations, what, duration, timeDeltaStr, memUsed);\n            return duration;\n        }\n\n        public static async Task<int> GetActivationCount(IGrainFactory grainFactory, string grainTypeName)\n        {\n            int result = 0;\n\n            IManagementGrain mgmtGrain = grainFactory.GetGrain<IManagementGrain>(0);\n            SimpleGrainStatistic[] stats = await mgmtGrain.GetSimpleGrainStatistics();\n            foreach (var stat in stats)\n            {\n                if (string.Equals(stat.GrainType, grainTypeName, StringComparison.Ordinal))\n                {\n                    result += stat.ActivationCount;\n                }\n            }\n            return result;\n        }\n    }\n\n    public static class RequestContextTestUtils\n    {\n        public static void SetActivityId(Guid id)\n        {\n            RequestContext.ReentrancyId = id;\n        }\n\n        public static Guid GetActivityId()\n        {\n            return RequestContext.ReentrancyId is Guid value ? value : Guid.Empty;\n        }\n\n        public static void ClearActivityId()\n        {\n            RequestContext.ReentrancyId = Guid.Empty;\n        }\n    }\n}\n"
  },
  {
    "path": "test/TestInfrastructure/TestExtensions/XunitLoggerProvider.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Xunit.Abstractions;\n\nnamespace TestExtensions\n{\n    public class XunitLoggerProvider : ILoggerProvider\n    {\n        private readonly ITestOutputHelper output;\n\n        public XunitLoggerProvider(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        public ILogger CreateLogger(string categoryName) => new XunitLogger(this.output, categoryName);\n\n        public void Dispose()\n        {\n        }\n\n        private class XunitLogger : ILogger, IDisposable\n        {\n            private readonly ITestOutputHelper output;\n            private readonly string category;\n\n            public XunitLogger(ITestOutputHelper output, string category)\n            {\n                this.output = output;\n                this.category = category;\n            }\n            \n            public IDisposable BeginScope<TState>(TState state) => this;\n\n            public void Dispose() { }\n\n            public bool IsEnabled(LogLevel logLevel) => true;\n\n            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n            {\n                this.output.WriteLine($\"{logLevel} [{this.category}.{eventId.Name ?? eventId.Id.ToString()}] {formatter(state, exception)}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/TesterInternal/ActivationsLifeCycleTests/ActivationCancellationTests.cs",
    "content": "#nullable enable\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Orleans.Configuration;\nusing Orleans.TestingHost;\nusing TestExtensions;\nusing UnitTests.GrainInterfaces;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace UnitTests.ActivationCancellationTests;\n\n/// <summary>\n/// Tests for activation cancellation logging behavior in Orleans.\n/// \n/// These tests verify that:\n/// 1. When activation is cancelled gracefully (OperationCanceledException or ObjectDisposedException\n///    thrown while cancellation token is cancelled), the exception is wrapped in ActivationCancelledException\n///    and logged at WARNING level (not ERROR level).\n/// 2. When non-cancellation exceptions occur, they are still logged at ERROR level as expected.\n/// \n/// The key code being tested is in ActivationData.cs:\n/// - catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested) → ActivationCancelledException → Warning log\n/// - catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested &amp;&amp; !timeout) → ActivationCancelledException → Warning log\n/// - catch (Exception) → Error log\n/// \n/// Plan / Pseudocode (inserted as comment for traceability):\n/// 1. Add two reusable assertion helpers:\n///    - AssertLogEventExists(logs, eventId) -> asserts that any log in 'logs' has EventId == eventId.\n///    - AssertLogEventNotExists(logs, eventId) -> asserts that no log in 'logs' has EventId == eventId.\n/// 2. Keep existing behavior: ensure OperationCanceledException scenario finds info logs with the cancelled-activate EventId.\n/// 3. Additionally assert that across error logs there is NOT an event with EventId == (int)ErrorCode.Catalog_ErrorCallingActivate.\n/// 4. Helpers include clear diagnostic messages listing captured EventIds for easier debugging.\n/// 5. Place helpers as private methods on the test class so they can be reused by other tests.\n///\n/// The code below implements these helpers and uses them in the OperationCanceledException test.\n/// </summary>\npublic class ActivationCancellationLoggingTests : OrleansTestingBase, IClassFixture<ActivationCancellationLoggingTests.Fixture>\n{\n    private readonly Fixture _fixture;\n    private readonly ITestOutputHelper _output;\n\n    public class Fixture : BaseTestClusterFixture\n    {\n        // Static so it can be accessed from the configurator\n        public static InMemoryLoggerProvider SharedLoggerProvider { get; } = new();\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 1;\n            builder.AddSiloBuilderConfigurator<SiloHostConfigurator>();\n        }\n\n        private class SiloHostConfigurator : ISiloConfigurator, IHostConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.Configure<GrainCollectionOptions>(options =>\n                {\n                    options.CollectionAge = TimeSpan.FromSeconds(10);\n                    options.CollectionQuantum = TimeSpan.FromSeconds(1);\n                    // Short activation timeout so we can test cancellation scenarios\n                    options.ActivationTimeout = TimeSpan.FromSeconds(2);\n                    options.DeactivationTimeout = TimeSpan.FromSeconds(2);\n                });\n\n                hostBuilder.Configure<SiloMessagingOptions>(options =>\n                {\n                    options.MaxRequestProcessingTime = TimeSpan.FromSeconds(5);\n                });\n            }\n\n            public void Configure(IHostBuilder hostBuilder)\n            {\n                hostBuilder.ConfigureServices(services =>\n                {\n                    services.AddSingleton<ILoggerProvider>(SharedLoggerProvider);\n                });\n            }\n        }\n    }\n\n    public ActivationCancellationLoggingTests(Fixture fixture, ITestOutputHelper output)\n    {\n        _fixture = fixture;\n        _output = output;\n        Fixture.SharedLoggerProvider.Clear();\n    }\n\n    private (IReadOnlyList<LogEntry> ErrorLogs, IReadOnlyList<LogEntry> WarningLogs, IReadOnlyList<LogEntry> InfoLogs) GetActivationLogs()\n    {\n        var logs = Fixture.SharedLoggerProvider.GetLogs();\n        \n        // Log all captured entries for debugging\n        _output.WriteLine($\"Total logs captured: {logs.Count}\");\n        foreach (var log in logs.Where(l => l.Level >= LogLevel.Warning))\n        {\n            _output.WriteLine($\"[{log.Level}] [{log.Category}] {log.Message}\");\n        }\n\n        // Look for activation-related logs \n        var activationLogs = logs.Where(l => \n            l.Category.Contains(\"Orleans.Grain\") || \n            l.Category.Contains(\"ActivationData\") ||\n            l.Message.Contains(\"Activation\", StringComparison.OrdinalIgnoreCase) ||\n            l.Message.Contains(\"activating\", StringComparison.OrdinalIgnoreCase)).ToList();\n\n        var errorLogs = activationLogs.Where(l => l.Level == LogLevel.Error).ToList();\n        var warningLogs = activationLogs.Where(l => l.Level == LogLevel.Warning).ToList();\n        var infoLogs = activationLogs.Where(l => l.Level == LogLevel.Information).ToList();\n\n        return (errorLogs, warningLogs, infoLogs);\n    }\n\n    // Reusable helper: assert that at least one log in 'logs' has the specified event id.\n    private static void AssertLogEventExists(IEnumerable<LogEntry> logs, int eventId)\n    {\n        var ids = logs.Select(l => l.EventId.Id).ToList();\n        Assert.True(ids.Any(id => id == eventId),\n            $\"Expected an information log with EventId {eventId} but it was not found. Captured EventIds: {string.Join(',', ids)}\");\n    }\n\n    // Reusable helper: assert that no log in 'logs' has the specified event id.\n    private static void AssertLogEventNotExists(IEnumerable<LogEntry> logs, int eventId)\n    {\n        var ids = logs.Select(l => l.EventId.Id).ToList();\n        Assert.False(ids.Any(id => id == eventId),\n            $\"Did not expect a log with EventId {eventId}, but it was found. Captured EventIds: {string.Join(',', ids)}\");\n    }\n\n    #region Cancellation Scenarios - Should NOT log ERROR\n\n    /// <summary>\n    /// When OperationCanceledException is thrown because the cancellation token was observed during activation,\n    /// it should be logged at WARNING level (not ERROR) because this is intentional cancellation behavior.\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCancellation\")]\n    public async Task OperationCanceledException_WhenCancellationTokenObserved_LogsInfoNotError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsOperationCancelledGrain>(Guid.NewGuid());\n\n        // Set a delay longer than the activation timeout (2 seconds) to trigger cancellation\n        RequestContext.Set(\"delay_activation_ms\", 5000);\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>\n        {\n            await grain.IsActivated().WaitAsync(TimeSpan.FromSeconds(5));\n        });\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, warningLogs, infoLogs) = GetActivationLogs();\n\n        Assert.Empty(errorLogs);\n        Assert.Empty(warningLogs);\n        Assert.NotEmpty(infoLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(infoLogs, (int)ErrorCode.Catalog_CancelledActivate);\n\n        // Also ensure across error logs there is NOT an event with EventId == (int)ErrorCode.Catalog_ErrorCallingActivate\n        AssertLogEventNotExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    /// <summary>\n    /// When ObjectDisposedException is thrown because services are disposed after cancellation,\n    /// it should be logged at WARNING level (not ERROR) because this is expected behavior during cancellation.\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCancellation\")]\n    public async Task ObjectDisposedException_WhenCancellationRequested_LogsWarningNotError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsObjectDisposedGrain>(Guid.NewGuid());\n\n        // Set a delay longer than the activation timeout to trigger cancellation\n        RequestContext.Set(\"delay_activation_ms\", 5000);\n\n        await Assert.ThrowsAnyAsync<ObjectDisposedException>(async () =>\n        {\n            await grain.IsActivated();\n        });\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, warningLogs, infoLogs) = GetActivationLogs();\n\n        Assert.Empty(errorLogs);\n        Assert.NotEmpty(warningLogs);\n\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(warningLogs, (int)ErrorCode.Catalog_DisposedObjectAccess);\n\n        // Also ensure across error logs there is NOT an event with EventId == (int)ErrorCode.Catalog_ErrorCallingActivate\n        AssertLogEventNotExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    /// <summary>\n    /// When TaskCanceledException (which inherits from OperationCanceledException) is thrown during cancellation,\n    /// it should be logged at INFO level (not ERROR).\n    /// </summary>\n    [Fact, TestCategory(\"Functional\"), TestCategory(\"ActivationCancellation\")]\n    public async Task TaskCanceledException_WhenCancellationRequested_LogsInfoNotError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsTaskCancelledGrain>(Guid.NewGuid());\n\n        RequestContext.Set(\"delay_activation_ms\", 5000);\n\n        await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>\n        {\n            await grain.IsActivated().WaitAsync(TimeSpan.FromSeconds(5));\n        });\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, warningLogs, infoLogs) = GetActivationLogs();\n\n        Assert.Empty(errorLogs);\n        Assert.Empty(warningLogs);\n        Assert.NotEmpty(infoLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(infoLogs, (int)ErrorCode.Catalog_CancelledActivate);\n\n        // Also ensure across error logs there is NOT an event with EventId == (int)ErrorCode.Catalog_ErrorCallingActivate\n        AssertLogEventNotExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    #endregion\n\n    #region Non-Cancellation Scenarios - SHOULD log ERROR\n\n    /// <summary>\n    /// When a generic exception (not related to cancellation) is thrown during activation,\n    /// it should be logged at ERROR level because this is an unexpected failure.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivationCancellation\")]\n    public async Task GenericException_DuringActivation_LogsError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsGenericExceptionGrain>(Guid.NewGuid());\n\n        RequestContext.Set(\"throw_exception\", true);\n\n        await Assert.ThrowsAsync<InvalidOperationException>(() => grain.IsActivated());\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, _, infoLogs) = GetActivationLogs();\n\n        Assert.NotEmpty(errorLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    /// <summary>\n    /// When ObjectDisposedException is thrown but the cancellation token was NOT cancelled,\n    /// it should be logged at ERROR level (the 'when' guard should NOT match).\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivationCancellation\")]\n    public async Task ObjectDisposedException_WhenNotCancelled_LogsError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsObjectDisposedUnconditionallyGrain>(Guid.NewGuid());\n\n        RequestContext.Set(\"throw_object_disposed\", true);\n\n        await Assert.ThrowsAsync<ObjectDisposedException>(() => grain.IsActivated());\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, _, infoLogs) = GetActivationLogs();\n\n        Assert.NotEmpty(errorLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    /// <summary>\n    /// When OperationCanceledException is thrown but the cancellation token was NOT cancelled,\n    /// it should be logged at ERROR level (the 'when' guard should NOT match).\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivationCancellation\")]\n    public async Task OperationCanceledException_WhenNotCancelled_LogsError()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_ThrowsOperationCancelledUnconditionallyGrain>(Guid.NewGuid());\n\n        RequestContext.Set(\"throw_operation_cancelled\", true);\n\n        await Assert.ThrowsAsync<OperationCanceledException>(() => grain.IsActivated());\n\n        RequestContext.Clear();\n\n        await Task.Delay(100);\n\n        var (errorLogs, _, infoLogs) = GetActivationLogs();\n\n        Assert.NotEmpty(errorLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventExists(errorLogs, (int)ErrorCode.Catalog_ErrorCallingActivate);\n    }\n\n    #endregion\n\n    #region Baseline Tests - Normal Operation\n\n    /// <summary>\n    /// Baseline test: Successful activation should not log any errors or warnings.\n    /// </summary>\n    [Fact, TestCategory(\"BVT\"), TestCategory(\"ActivationCancellation\")]\n    public async Task SuccessfulActivation_NoErrorOrWarningLogs()\n    {\n        Fixture.SharedLoggerProvider.Clear();\n        var grain = _fixture.GrainFactory.GetGrain<IActivationCancellation_SuccessfulActivationGrain>(Guid.NewGuid());\n\n        var isActivated = await grain.IsActivated();\n\n        await Task.Delay(100);\n\n        var (errorLogs, warningLogs, infoLogs) = GetActivationLogs();\n\n        Assert.True(isActivated);\n        Assert.Empty(errorLogs);\n        Assert.Empty(warningLogs);\n\n        // New assertion: ensure there is an info log with EventId == (int)ErrorCode.Catalog_CancelledActivate\n        AssertLogEventNotExists(infoLogs, (int)ErrorCode.Catalog_CancelledActivate);\n    }\n\n    #endregion\n}\n\npublic class InMemoryLoggerProvider : ILoggerProvider\n{\n    private readonly List<LogEntry> _logs = new();\n    private readonly object _lock = new();\n\n    public ILogger CreateLogger(string categoryName) => new InMemoryLogger(this, categoryName);\n\n    public void Dispose() { }\n\n    public void Clear()\n    {\n        lock (_lock)\n        {\n            _logs.Clear();\n        }\n    }\n\n    public IReadOnlyList<LogEntry> GetLogs()\n    {\n        lock (_lock)\n        {\n            return _logs.ToList();\n        }\n    }\n\n    internal void AddLog(LogEntry entry)\n    {\n        lock (_lock)\n        {\n            _logs.Add(entry);\n        }\n    }\n\n    private class InMemoryLogger(InMemoryLoggerProvider provider, string categoryName) : ILogger\n    {\n        public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;\n\n        public bool IsEnabled(LogLevel logLevel) => true;\n\n        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)\n        {\n            provider.AddLog(new LogEntry(categoryName, logLevel, eventId, formatter(state, exception), exception));\n        }\n    }\n}\n\npublic record LogEntry(string Category, LogLevel Level, EventId EventId, string Message, Exception? Exception);\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/AzureTransactionalStateStorageTests.cs",
    "content": "using Azure.Data.Tables;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Orleans.Transactions.Abstractions;\nusing Orleans.Transactions.AzureStorage;\nusing Orleans.Transactions.AzureStorage.Tests;\nusing Orleans.Transactions.TestKit.xUnit;\nusing Tester.AzureUtils;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.Azure.Tests\n{\n    public class TestState : IEquatable<TestState>\n    {\n        public int State { get; set; }\n\n        public bool Equals(TestState other)\n        {\n            return other == null?false:this.State.Equals(other.State);\n        }\n    }\n\n    /// <summary>\n    /// Tests for Azure Table Storage implementation of transactional state storage.\n    /// </summary>\n    public class AzureTransactionalStateStorageTests : TransactionalStateStorageTestRunnerxUnit<TestState>, IClassFixture<TestFixture>\n    {\n        private const string tableName = \"StateStorageTests\";\n        private const string partition = \"testpartition\";\n        public AzureTransactionalStateStorageTests(TestFixture fixture, ITestOutputHelper testOutput)\n            : base(() => StateStorageFactory(fixture), (seed) => new TestState() { State = seed }, fixture.GrainFactory, testOutput)\n        {\n        }\n\n        private static async Task<ITransactionalStateStorage<TestState>> StateStorageFactory(TestFixture fixture)\n        {\n            var table = await InitTableAsync(NullLogger.Instance);\n            var jsonSettings = TransactionalStateFactory.GetJsonSerializerSettings(fixture.HostedCluster.ServiceProvider);\n            var stateStorage = new AzureTableTransactionalStateStorage<TestState>(table, $\"{partition}{DateTime.UtcNow.Ticks}\", jsonSettings,\n                NullLoggerFactory.Instance.CreateLogger<AzureTableTransactionalStateStorage<TestState>>());\n            return stateStorage;\n        }\n\n        private static async Task<TableClient> InitTableAsync(ILogger logger)\n        {\n            try\n            {\n                var tableCreationClient = GetCloudTableCreationClient(logger);\n                TableClient tableRef = tableCreationClient.GetTableClient(tableName);\n                var tableItem = await tableRef.CreateIfNotExistsAsync();\n                var didCreate = tableItem is not null;\n\n                logger.LogInformation(\"{Verb} Azure storage table {TableName}\", didCreate ? \"Created\" : \"Attached to\", tableName);\n                return tableRef;\n            }\n            catch (Exception exc)\n            {\n                logger.LogError(exc, \"Could not initialize connection to storage table {TableName}\", tableName);\n                throw;\n            }\n        }\n\n        private static TableServiceClient GetCloudTableCreationClient(ILogger logger)\n        {\n            try\n            {\n                var creationClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n                return creationClient;\n            }\n            catch (Exception exc)\n            {\n                logger.LogError(exc, \"Error creating CloudTableCreationClient\");\n                throw;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/ConsistencySkewedClockTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction consistency with skewed clock scenarios using Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions-dev\")]\n    public class ConsistencySkewedClockTests : ConsistencyTransactionTestRunnerxUnit, IClassFixture<SkewedClockTestFixture>\n    {\n        public ConsistencySkewedClockTests(SkewedClockTestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n\n        protected override bool StorageAdaptorHasLimitedCommitSpace => true;\n        protected override bool StorageErrorInjectionActive => false;\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/ConsistencyTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction consistency behavior with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions-dev\")]\n    public class ConsistencyTests : ConsistencyTransactionTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public ConsistencyTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n\n        protected override bool StorageAdaptorHasLimitedCommitSpace => true;\n        protected override bool StorageErrorInjectionActive => false;\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/FaultInjection/ControlledInjection/TransactionFaultInjectionTests.cs",
    "content": "using Orleans.Transactions.AzureStorage.Tests;\nusing Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.Azure.Tests\n{\n    /// <summary>\n    /// Tests for transaction behavior under controlled fault injection scenarios with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TransactionFaultInjectionTests : ControlledFaultInjectionTransactionTestRunnerxUnit, IClassFixture<ControlledFaultInjectionTestFixture>\n    {\n        public TransactionFaultInjectionTests(ControlledFaultInjectionTestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/FaultInjection/RandomInjection/ConsistencyFaultInjectionTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction consistency with random fault injection using Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions-dev\")]\n    public class ConsistencyFaultInjectionTests: ConsistencyTransactionTestRunnerxUnit, IClassFixture<RandomFaultInjectedTestFixture>\n    {\n        public ConsistencyFaultInjectionTests(RandomFaultInjectedTestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        { }\n\n        protected override bool StorageAdaptorHasLimitedCommitSpace => true;\n        protected override bool StorageErrorInjectionActive => true;\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/GoldenPathTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction golden path scenarios with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class GoldenPathTests : GoldenPathTransactionTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public GoldenPathTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/GrainFaultTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction behavior under grain fault conditions with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class GrainFaultTests : GrainFaultTransactionTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public GrainFaultTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/Orleans.Transactions.Azure.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <RootNamespace>Orleans.Transactions.Azure.Tests</RootNamespace>\n    <AssemblyName>Orleans.Transactions.Azure.Tests</AssemblyName>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)test\\Transactions\\Orleans.Transactions.Tests\\Orleans.Transactions.Tests.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Clustering.AzureStorage\\Orleans.Clustering.AzureStorage.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Azure\\Orleans.Transactions.AzureStorage\\Orleans.Transactions.AzureStorage.csproj\" />\n    <ProjectReference Include=\"..\\..\\Extensions\\Orleans.Azure.Tests\\Orleans.Azure.Tests.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/SkewedClockGoldenPathTransactionTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction golden path scenarios with skewed clocks using Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class SkewedClockGoldenPathTransactionTests : GoldenPathTransactionTestRunnerxUnit, IClassFixture<SkewedClockTestFixture>\n    {\n        public SkewedClockGoldenPathTransactionTests(SkewedClockTestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TestFixture.cs",
    "content": "using Orleans.Runtime;\nusing Microsoft.Extensions.DependencyInjection;\nusing Orleans.TestingHost;\nusing Orleans.Transactions.TestKit;\nusing Orleans.Transactions.Tests;\nusing TestExtensions;\nusing Tester;\nusing Microsoft.Extensions.Configuration;\nusing Tester.AzureUtils;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    public class TestFixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForAzureStorage();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .ConfigureServices(services => services.AddKeyedSingleton<IRemoteCommitService, RemoteCommitService>(TransactionTestConstants.RemoteCommitService))\n                    .AddAzureTableTransactionalStateStorage(TransactionTestConstants.TransactionStore, options =>\n                    {\n                        options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n                    })\n                    .UseTransactions();\n            }\n        }\n\n        public class ClientBuilderConfigurator : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder\n                    .UseTransactions();\n            }\n        }\n    }\n\n    public class ControlledFaultInjectionTestFixture : BaseTestClusterFixture\n    {\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForAzureStorage();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddFaultInjectionAzureTableTransactionalStateStorage(TransactionTestConstants.TransactionStore, options =>\n                    {\n                        options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n                    })\n                    .UseControlledFaultInjectionTransactionState()\n                    .UseTransactions()\n                    .ConfigureServices(svc =>\n                    {\n                        svc.AddScoped<ITransactionFaultInjector, SimpleAzureStorageExceptionInjector>()\n                        .AddScoped<IControlledTransactionFaultInjector>(sp => sp.GetService<ITransactionFaultInjector>() as IControlledTransactionFaultInjector);\n                    });\n            }\n        }\n    }\n\n    public class SkewedClockTestFixture : TestFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SkewedClockConfigurator>();\n            base.ConfigureTestCluster(builder);\n        }\n    }\n\n\n    public class RandomFaultInjectedTestFixture : TestFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<TxSiloBuilderConfigurator>();\n            base.ConfigureTestCluster(builder);\n        }\n\n        public class TxSiloBuilderConfigurator : ISiloConfigurator\n        {\n            private static readonly double probability = 0.05;\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .AddFaultInjectionAzureTableTransactionalStateStorage(TransactionTestConstants.TransactionStore, options =>\n                    {\n                        options.TableServiceClient = AzureStorageOperationOptionsExtensions.GetTableServiceClient();\n                    })\n                    .UseTransactions()\n                    .ConfigureServices(services => services.AddSingleton<ITransactionFaultInjector>(sp => new RandomErrorInjector(probability)));\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TocFaultTransactionTests.cs",
    "content": "\nusing Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for Transfer of Coordination (TOC) fault scenarios with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TocFaultTransactionTests : TocFaultTransactionTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public TocFaultTransactionTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TocGoldenPathTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for Transfer of Coordination (TOC) golden path scenarios with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TocGoldenPathTests : TocGoldenPathTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public TocGoldenPathTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TransactionConcurrencyTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction concurrency behavior with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TransactionConcurrencyTests : TransactionConcurrencyTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public TransactionConcurrencyTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TransactionRecoveryTests.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Orleans.TestingHost;\nusing Orleans.Transactions.TestKit;\nusing Orleans.Transactions.TestKit.xUnit;\nusing Tester;\nusing Tester.AzureUtils;\nusing TestExtensions;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for transaction recovery after silo failures with Azure Storage clustering.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TransactionRecoveryTests : TestClusterPerTest\n    {\n        private TransactionRecoveryTestsRunnerxUnit testRunner;\n        private readonly ITestOutputHelper helper;\n\n        public TransactionRecoveryTests(ITestOutputHelper helper)\n        {\n            this.EnsurePreconditionsMet();\n            this.helper = helper;\n        }\n\n        public override async Task InitializeAsync()\n        {\n            await base.InitializeAsync();\n            this.testRunner = new TransactionRecoveryTestsRunnerxUnit(this.HostedCluster, helper);\n        }\n\n        protected override void CheckPreconditionsOrThrow()\n        {\n            base.CheckPreconditionsOrThrow();\n            TestUtils.CheckForAzureStorage();\n        }\n\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.Options.InitialSilosCount = 4;\n            builder.AddSiloBuilderConfigurator<TestFixture.SiloBuilderConfigurator>();\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfiguratorUsingAzureClustering>();\n            builder.AddClientBuilderConfigurator<ClientBuilderConfiguratorUsingAzureClustering>();\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, 30)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, 20)]\n        public Task TransactionWillRecoverAfterRandomSiloGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return this.testRunner.TransactionWillRecoverAfterRandomSiloGracefulShutdown(transactionTestGrainClassName, concurrent);\n        }\n\n        [SkippableTheory]\n        [InlineData(TransactionTestConstants.SingleStateTransactionalGrain, 30)]\n        [InlineData(TransactionTestConstants.DoubleStateTransactionalGrain, 20)]\n        public Task TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(string transactionTestGrainClassName, int concurrent)\n        {\n            return this.testRunner.TransactionWillRecoverAfterRandomSiloUnGracefulShutdown(transactionTestGrainClassName, concurrent);\n        }\n\n        private class SiloBuilderConfiguratorUsingAzureClustering : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder.UseAzureStorageClustering(options =>  options.ConfigureTestDefaults());\n            }\n        }\n\n        private class ClientBuilderConfiguratorUsingAzureClustering : IClientBuilderConfigurator\n        {\n            public void Configure(IConfiguration configuration, IClientBuilder clientBuilder)\n            {\n                clientBuilder.UseAzureStorageClustering(options => options.ConfigureTestDefaults());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Azure.Test/TransactionScopeTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nusing Orleans.Transactions.TestKit.xUnit;\n\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.AzureStorage.Tests\n{\n    /// <summary>\n    /// Tests for scoped transaction functionality with Azure Storage.\n    /// </summary>\n    [TestCategory(\"AzureStorage\"), TestCategory(\"Transactions\"), TestCategory(\"Functional\")]\n    public class TransactionScopeTests : ScopedTransactionsTestRunnerxUnit, IClassFixture<TestFixture>\n    {\n        public TransactionScopeTests(TestFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, fixture.HostedCluster.ServiceProvider.GetRequiredService<ITransactionClient>(), output)\n        {\n            fixture.EnsurePreconditionsMet();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/AssemblyInfo.cs",
    "content": "using Xunit;\n\n// Disable XUnit concurrency limit\n[assembly: CollectionBehavior(MaxParallelThreads = -1)]\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Disabled/DisabledTransactionsTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit;\nusing Xunit.Abstractions;\nusing TestExtensions;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for behavior when transactions are disabled.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class DisabledTransactionsTests : DisabledTransactionsTestRunnerxUnit, IClassFixture<DefaultClusterFixture>\n    {\n        public DisabledTransactionsTests(DefaultClusterFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/ConsistencySkewedClockTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for transaction consistency with skewed clock scenarios using in-memory storage.\n    /// </summary>\n    [TestCategory(\"Transactions-dev\")]\n    public class ConsistencySkewedClockTests : ConsistencyTransactionTestRunnerxUnit, IClassFixture<SkewedClockMemoryTransactionsFixture>\n    {\n        public ConsistencySkewedClockTests(SkewedClockMemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n\n        protected override bool StorageErrorInjectionActive => false;\n        protected override bool StorageAdaptorHasLimitedCommitSpace => false;\n\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/ConsistencyTests.cs",
    "content": "using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for transaction consistency behavior with in-memory storage.\n    /// </summary>\n    [TestCategory(\"Transactions-dev\")]\n    public class ConsistencyTests : ConsistencyTransactionTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public ConsistencyTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n\n        protected override bool StorageErrorInjectionActive => false;\n        protected override bool StorageAdaptorHasLimitedCommitSpace => false;\n\n    }\n\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/GoldenPathTransactionMemoryTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for transaction golden path scenarios with in-memory storage.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class GoldenPathTransactionMemoryTests : GoldenPathTransactionTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public GoldenPathTransactionMemoryTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/GrainFaultTransactionMemoryTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for transaction behavior under grain fault conditions with in-memory storage.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class GrainFaultTransactionMemoryTests : GrainFaultTransactionTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public GrainFaultTransactionMemoryTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/MemoryTransactionsFixture.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Orleans.Runtime;\nusing Orleans.TestingHost;\nusing Orleans.Transactions.TestKit;\nusing TestExtensions;\n\nnamespace Orleans.Transactions.Tests\n{\n    public class MemoryTransactionsFixture : BaseTestClusterFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();\n        }\n\n        public class SiloBuilderConfigurator : ISiloConfigurator\n        {\n            public void Configure(ISiloBuilder hostBuilder)\n            {\n                hostBuilder\n                    .ConfigureServices(services => services.AddKeyedSingleton<IRemoteCommitService, RemoteCommitService>(TransactionTestConstants.RemoteCommitService))\n                    .AddMemoryGrainStorage(TransactionTestConstants.TransactionStore)\n                    .UseTransactions();\n            }\n        }\n    }\n\n    public class SkewedClockMemoryTransactionsFixture : MemoryTransactionsFixture\n    {\n        protected override void ConfigureTestCluster(TestClusterBuilder builder)\n        {\n            builder.AddSiloBuilderConfigurator<SkewedClockConfigurator>();\n            base.ConfigureTestCluster(builder);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/SkewedClockGoldenPathTransactionMemoryTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    /// <summary>\n    /// Tests for transaction golden path scenarios with skewed clocks using in-memory storage.\n    /// </summary>\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class SkewedClockGoldenPathTransactionMemoryTests : GoldenPathTransactionTestRunnerxUnit, IClassFixture<SkewedClockMemoryTransactionsFixture>\n    {\n        public SkewedClockGoldenPathTransactionMemoryTests(SkewedClockMemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/TocFaultTransactionMemoryTests.cs",
    "content": "﻿\nusing Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class TocFaultTransactionMemoryTests : TocFaultTransactionTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public TocFaultTransactionMemoryTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/TocGoldenPathMemoryTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class TocGoldenPathTransactionMemoryTests : TocGoldenPathTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public TocGoldenPathTransactionMemoryTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/TransactionAttributionTest.cs",
    "content": "﻿using Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class TransactionAttributionTest : TransactionAttributionTestRunner, IClassFixture<MemoryTransactionsFixture>\n    {\n        public TransactionAttributionTest(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Memory/TransactionConcurrencyTests.cs",
    "content": "﻿using Orleans.Transactions.TestKit.xUnit;\nusing Xunit.Abstractions;\nusing Xunit;\n\nnamespace Orleans.Transactions.Tests\n{\n\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class TransactionConcurrencyTests : TransactionConcurrencyTestRunnerxUnit, IClassFixture<MemoryTransactionsFixture>\n    {\n        public TransactionConcurrencyTests(MemoryTransactionsFixture fixture, ITestOutputHelper output)\n            : base(fixture.GrainFactory, output)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Orleans.Transactions.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>\n    <OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"xunit\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.TestingHost\\Orleans.TestingHost.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)src\\Orleans.Transactions.TestKit.xUnit\\Orleans.Transactions.TestKit.xUnit.csproj\" />\n    <ProjectReference Include=\"$(SourceRoot)test\\TestInfrastructure\\TestExtensions\\TestExtensions.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/Runners/TransactionAttributionTestRunner.cs",
    "content": "﻿using Orleans.Transactions.TestKit;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Orleans.Transactions.Tests\n{\n    public abstract class TransactionAttributionTestRunner\n    {\n        protected readonly IGrainFactory grainFactory;\n        protected readonly ITestOutputHelper output;\n\n        protected TransactionAttributionTestRunner(IGrainFactory grainFactory, ITestOutputHelper output)\n        {\n            this.output = output;\n            this.grainFactory = grainFactory;\n        }\n\n        /// <summary>\n        /// Test all attributes that can be called from a non transactional call.  Ensure they all behave correctly.\n        /// These include:\n        /// No attribute - should have no transaction context\n        /// Suppress - should have no transaction context\n        /// CreateOrJoin - should have unique transaction context\n        /// Create - should have unique transaction context\n        /// Supported - should have no transaction context\n        /// NotAllowed - should have no transaction context\n        /// </summary>\n        [Fact]\n        public async Task AllSupportedAttributesFromOutsideTransactionTest()\n        {\n            ITransactionAttributionGrain top = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid());\n            List<ITransactionAttributionGrain>[] tiers = \n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid()),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Suppress),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Supported),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.NotAllowed)\n                    })\n            };\n\n            List<string>[] results = await top.GetNestedTransactionIds(0, tiers);\n            for(int i=0; i<results.Length; i++)\n            {\n                this.output.WriteLine($\"{i} => {string.Join(\",\", results[i])}\");\n            }\n\n            // make sure there are 2 tiers\n            Assert.Equal(2, results.Length);\n\n            // make sure top level call has no transactionId\n            List<string> topTransactionIds = results[0];\n            Assert.Single(topTransactionIds);\n            Assert.Null(topTransactionIds.First());\n\n            // check sub call transactionIds, should be null, null, guid1, guid2, null, null\n            List<string> subcallTransactionIds = results[1];\n            Assert.Equal(6, subcallTransactionIds.Count);\n\n            Assert.Null(subcallTransactionIds[0]); // no attribute\n\n            Assert.Null(subcallTransactionIds[1]); // Suppress attribute\n\n            Assert.NotNull(subcallTransactionIds[2]); // CreateOrJoin attribute\n\n            Assert.NotNull(subcallTransactionIds[3]); // Create new attribute\n            // make sure the transaction id's for the Required and RequiredNew calls differ\n            Assert.NotEqual(subcallTransactionIds[2], subcallTransactionIds[3]);\n\n            Assert.Null(subcallTransactionIds[4]); // Supported attribute\n\n            Assert.Null(subcallTransactionIds[5]); // NotAllowed attribute\n        }\n\n        /// <summary>\n        /// Test all attributes that can be called from within a transactional call.  Ensure they all behave correctly.\n        /// These include:\n        /// No attribute - should have no transaction context\n        /// Suppress - should have no transaction context\n        /// CreateOrJoin - should have same transaction context as parent\n        /// Create - should have unique transaction context\n        /// Join - should have same transaction context as parent\n        /// Supported - should have same transaction context as parent\n        /// </summary>\n        [Fact]\n        public async Task AllSupportedAttributesFromWithinTransactionTest()\n        {\n            ITransactionAttributionGrain top = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create);\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid()),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Suppress),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Join),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Supported)\n                    })\n            };\n\n            List<string>[] results = await top.GetNestedTransactionIds(0, tiers);\n            for (int i = 0; i < results.Length; i++)\n            {\n                this.output.WriteLine($\"{i} => {string.Join(\",\", results[i])}\");\n            }\n\n            // make sure there are 2 tiers\n            Assert.Equal(2, results.Length);\n\n            // make sure top level call has transactionId\n            List<string> topTransactionIds = results[0];\n            Assert.Single(topTransactionIds);\n            Assert.NotNull(topTransactionIds.First());\n\n            // check sub call transactionIds, should be null, null, guid1, guid2, where guid1 should match Id from top\n            List<string> subcallTransactionIds = results[1];\n            Assert.Equal(6, subcallTransactionIds.Count);\n\n            Assert.Null(subcallTransactionIds[0]); // no attribute\n\n            Assert.Null(subcallTransactionIds[1]); // Suppress supported attribute\n\n            Assert.NotNull(subcallTransactionIds[2]); // CreateOrJoin attribute\n            // make sure required attributed transactionId matches top\n            Assert.Equal(subcallTransactionIds[2], topTransactionIds.First());\n\n            Assert.NotNull(subcallTransactionIds[3]); // Create attribute\n            // make sure the transaction id's differ\n            Assert.NotEqual(subcallTransactionIds[2], subcallTransactionIds[3]);\n\n            Assert.NotNull(subcallTransactionIds[4]); // Join attribute\n            // make sure Join attributed transactionId matches top\n            Assert.Equal(subcallTransactionIds[4], topTransactionIds.First());\n\n            Assert.NotNull(subcallTransactionIds[5]); // Supported attribute\n            // make sure Supported attributed transactionId matches top\n            Assert.Equal(subcallTransactionIds[5], topTransactionIds.First());\n        }\n\n        [Fact]\n        public async Task CreateOrJoinTest()\n        {\n            ITransactionAttributionGrain top = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin);\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin),\n                    })\n            };\n\n            List<string>[] results = await top.GetNestedTransactionIds(0, tiers);\n            for (int i = 0; i < results.Length; i++)\n            {\n                this.output.WriteLine($\"{i} => {string.Join(\",\", results[i])}\");\n            }\n\n            // make sure there are 2 tiers\n            Assert.Equal(2, results.Length);\n\n            // make sure top level call has transactionId\n            List<string> topTransactionIds = results[0];\n            Assert.Single(topTransactionIds);\n            Assert.NotNull(topTransactionIds.First());\n\n            // check sub call transactionIds, should be null, null, guid1, guid1, where guid1 should match Id from top\n            List<string> subcallTransactionIds = results[1];\n            Assert.Equal(2, subcallTransactionIds.Count);\n            // make sure required attributed transactionId matches parent\n            Assert.Equal(subcallTransactionIds[0], topTransactionIds.First());\n            // make sure required attributed transactionId matches parent\n            Assert.Equal(subcallTransactionIds[1], topTransactionIds.First());\n        }\n\n        [Fact]\n        public async Task CreateTest()\n        {\n            ITransactionAttributionGrain top = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create);\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create),\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create),\n                    })\n            };\n\n            List<string>[] results = await top.GetNestedTransactionIds(0, tiers);\n            for (int i = 0; i < results.Length; i++)\n            {\n                this.output.WriteLine($\"{i} => {string.Join(\",\", results[i])}\");\n            }\n\n            // make sure there are 2 tiers\n            Assert.Equal(2, results.Length);\n\n            // make sure top level call has transactionId\n            List<string> topTransactionIds = results[0];\n            Assert.Single(topTransactionIds);\n            Assert.NotNull(topTransactionIds.First());\n\n            // check sub call transactionIds, should be null, null, guid1, guid2, where guid1 and guid2 should be different and not match top level transactionId\n            List<string> subcallTransactionIds = results[1];\n            Assert.Equal(2, subcallTransactionIds.Count);\n            // make sure RequiresNew attributed transactionId does not match parents\n            Assert.NotEqual(subcallTransactionIds[0], topTransactionIds.First());\n            // make sure RequiresNew attributed transactionId does not match parents\n            Assert.NotEqual(subcallTransactionIds[1], topTransactionIds.First());\n            // make sure the transaction id's differ\n            Assert.NotEqual(subcallTransactionIds[0], subcallTransactionIds[1]);\n        }\n\n        /// <summary>\n        /// Check to see that a transaction taken place in a call marked 'supported' can join the parent transaction\n        /// </summary>\n        /// <returns></returns>\n        [Fact]\n        public async Task SupportedTest()\n        {\n            ITransactionAttributionGrain top = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create);\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Supported),\n                    }),\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.CreateOrJoin),\n                    })\n            };\n\n            List<string>[] results = await top.GetNestedTransactionIds(0, tiers);\n            for (int i = 0; i < results.Length; i++)\n            {\n                this.output.WriteLine($\"{i} => {string.Join(\",\", results[i])}\");\n            }\n\n            // make sure there are 3 tiers\n            Assert.Equal(3, results.Length);\n\n            // make sure top level call has transactionId\n            List<string> topTransactionIds = results[0];\n            Assert.Single(topTransactionIds);\n            Assert.NotNull(topTransactionIds.First());\n\n            // check first tier call transactionIds, should be a guid which matches the parent\n            List<string> tier1callTransactionIds = results[1];\n            Assert.Single(tier1callTransactionIds);\n            // make sure Supported attributed transactionId matchs parents\n            Assert.Equal(tier1callTransactionIds[0], topTransactionIds.First());\n\n            // check second tier call transactionIds, should be a guid which matches the parent\n            List<string> tier2callTransactionIds = results[2];\n            Assert.Single(tier2callTransactionIds);\n            // make sure CreateOrJoin attributed transactionId matchs parents\n            Assert.Equal(tier2callTransactionIds[0], topTransactionIds.First());\n        }\n\n        [Fact]\n        public async Task JoinFailTest()\n        {\n            ITransactionAttributionGrain fail = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid());\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Join),\n                    })\n            };\n\n            await Assert.ThrowsAsync<NotSupportedException>(() => fail.GetNestedTransactionIds(0, tiers));\n        }\n\n        [Fact]\n        public async Task NotAllowedFailTest()\n        {\n            ITransactionAttributionGrain fail = this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.Create);\n            List<ITransactionAttributionGrain>[] tiers =\n            {\n                new List<ITransactionAttributionGrain>(new[] {\n                    this.grainFactory.GetTransactionAttributionGrain(Guid.NewGuid(), TransactionOption.NotAllowed),\n                    })\n            };\n\n            OrleansTransactionAbortedException exception = await Assert.ThrowsAsync<OrleansTransactionAbortedException>(() => fail.GetNestedTransactionIds(0, tiers));\n            Assert.IsType<NotSupportedException>(exception.InnerException);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Transactions/Orleans.Transactions.Tests/TransactionOverloadDetectorTests.cs",
    "content": "﻿using System.Diagnostics;\nusing Microsoft.Extensions.Options;\nusing Xunit.Abstractions;\nusing Xunit;\nusing Orleans.Transactions.Abstractions;\n\nnamespace Orleans.Transactions.Tests\n{\n    [TestCategory(\"BVT\"), TestCategory(\"Transactions\")]\n    public class TransactionOverloadDetectorTests\n    {\n        private readonly ITestOutputHelper output;\n\n        public TransactionOverloadDetectorTests(ITestOutputHelper output)\n        {\n            this.output = output;\n        }\n\n        [SkippableTheory]\n        [InlineData(60, TransactionRateLoadSheddingOptions.DEFAULT_LIMIT)]\n        [InlineData(60, TransactionRateLoadSheddingOptions.DEFAULT_LIMIT * 2)]\n        [InlineData(60, 1)]\n        public void RateLimitTest(int runTimeInSeconds, double limit)\n        {\n            TimeSpan runTime = TimeSpan.FromSeconds(runTimeInSeconds);\n            TransactionRateLoadSheddingOptions options = new TransactionRateLoadSheddingOptions { Enabled = true, Limit = limit };\n            ITransactionAgentStatistics statistics = new TransactionAgentStatistics();\n            ITransactionOverloadDetector detector = new TransactionOverloadDetector(statistics, Options.Create(options));\n            Stopwatch sw = Stopwatch.StartNew();\n            long total = 0;\n            while (sw.Elapsed < runTime)\n            {\n                total++;\n                if (!detector.IsOverloaded())\n                {\n                    statistics.TrackTransactionStarted();\n                }\n            }\n            sw.Stop();\n            double averageRate = (statistics.TransactionsStarted * 1000) / sw.ElapsedMilliseconds;\n            this.output.WriteLine($\"Average of {averageRate}, with target of {options.Limit}.  Performed {statistics.TransactionsStarted} transactions of a max of {total} in {sw.ElapsedMilliseconds}ms.\");\n            // check to make sure average rate is withing rate +- 10%\n            Assert.True(options.Limit * 0.9 <= averageRate);\n            Assert.True(options.Limit * 1.1 >= averageRate);\n        }\n    }\n}\n"
  },
  {
    "path": "test/xunit.runner.json",
    "content": "{\n  \"$schema\": \"https://xunit.net/schema/current/xunit.runner.schema.json\",\n  \"appDomain\": \"denied\",\n  \"diagnosticMessages\": true,\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false,\n  \"methodDisplay\": \"classAndMethod\",\n  \"shadowCopy\": false,\n  \"preEnumerateTheories\": true,\n  \"longRunningTestSeconds\": 120\n}\n"
  }
]